diff --git a/.gitattributes b/.gitattributes index dfe0770424..0269fab9cb 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,3 @@ # Auto detect text files and perform LF normalization * text=auto +*.sol linguist-language=Solidity diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 6076fe46a4..e2e25180a1 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,9 +1,16 @@ # Lines starting with '#' are comments. # Each line is a file pattern followed by one or more owners. -accounts/usbwallet @karalabe -consensus @karalabe -core/ @karalabe @holiman -eth/ @karalabe -mobile/ @karalabe -p2p/ @fjl @zsfelfoldi +accounts/usbwallet @karalabe +accounts/abi @gballet +consensus @karalabe +core/ @karalabe @holiman +eth/ @karalabe +les/ @zsfelfoldi +light/ @zsfelfoldi +mobile/ @karalabe +p2p/ @fjl @zsfelfoldi +p2p/simulations @zelig @nonsense @janos @justelad +p2p/protocols @zelig @nonsense @janos @justelad +p2p/testing @zelig @nonsense @janos @justelad +whisper/ @gballet @gluk256 diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index a332b815d0..f87996cdcb 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,16 +1,40 @@ +# Contributing + +Thank you for considering to help out with the source code! We welcome +contributions from anyone on the internet, and are grateful for even the +smallest of fixes! + +If you'd like to contribute to go-ethereum, please fork, fix, commit and send a +pull request for the maintainers to review and merge into the main code base. If +you wish to submit more complex changes though, please check up with the core +devs first on [our gitter channel](https://gitter.im/ethereum/go-ethereum) to +ensure those changes are in line with the general philosophy of the project +and/or get some early feedback which can make both your efforts much lighter as +well as our review and merge procedures quick and simple. + +## Coding guidelines + +Please make sure your contributions adhere to our coding guidelines: + + * Code must adhere to the official Go +[formatting](https://golang.org/doc/effective_go.html#formatting) guidelines +(i.e. uses [gofmt](https://golang.org/cmd/gofmt/)). + * Code must be documented adhering to the official Go +[commentary](https://golang.org/doc/effective_go.html#commentary) guidelines. + * Pull requests need to be based on and opened against the `master` branch. + * Commit messages should be prefixed with the package(s) they modify. + * E.g. "eth, rpc: make trace configs optional" + ## Can I have feature X -Before you do a feature request please check and make sure that it isn't possible -through some other means. The JavaScript enabled console is a powerful feature -in the right hands. Please check our [Bitchin' tricks](https://github.com/ethereum/go-ethereum/wiki/bitchin-tricks) wiki page for more info +Before you submit a feature request, please check and make sure that it isn't +possible through some other means. The JavaScript-enabled console is a powerful +feature in the right hands. Please check our +[Wiki page](https://github.com/ethereum/go-ethereum/wiki) for more info and help. -## Contributing +## Configuration, dependencies, and tests -If you'd like to contribute to go-ethereum please fork, fix, commit and -send a pull request. Commits which do not comply with the coding standards -are ignored (use gofmt!). - -See [Developers' Guide](https://github.com/ethereum/go-ethereum/wiki/Developers'-Guide) -for more details on configuring your environment, testing, and -dependency management. +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. diff --git a/.github/no-response.yml b/.github/no-response.yml new file mode 100644 index 0000000000..903d4ce85f --- /dev/null +++ b/.github/no-response.yml @@ -0,0 +1,11 @@ +# Number of days of inactivity before an Issue is closed for lack of response +daysUntilClose: 30 +# Label requiring a response +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 + to our request for more information from the original author. With only the + information that is currently in the issue, we don't have enough information + to take action. Please reach out if you have more relevant information or + answers to our questions so that we can investigate further. diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 0000000000..6d921cc795 --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,17 @@ +# Number of days of inactivity before an issue becomes stale +daysUntilStale: 366 +# Number of days of inactivity before a stale issue is closed +daysUntilClose: 42 +# Issues with these labels will never be considered stale +exemptLabels: + - pinned + - security +# Label to use when marking an issue as 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 + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. +# Comment to post when closing a stale issue. Set to `false` to disable +closeComment: false diff --git a/.gitignore b/.gitignore index 0763d8492c..3e0009e167 100644 --- a/.gitignore +++ b/.gitignore @@ -34,8 +34,14 @@ profile.cov # IdeaIDE .idea +# VS Code +.vscode + # dashboard /dashboard/assets/flow-typed /dashboard/assets/node_modules /dashboard/assets/stats.json /dashboard/assets/bundle.js +/dashboard/assets/package-lock.json + +**/yarn-error.log diff --git a/.mailmap b/.mailmap index d51c7b6093..cc4b871a3c 100644 --- a/.mailmap +++ b/.mailmap @@ -65,7 +65,8 @@ Enrique Fynn Vincent G -RJ Catalano +RJ Catalano +RJ Catalano Nchinda Nchinda @@ -109,3 +110,14 @@ Frank Wang Gary Rong Guillaume Nicolas + +Sorin Neacsu +Sorin Neacsu + +Valentin Wüstholz +Valentin Wüstholz + +Armin Braun + +Ernesto del Toro +Ernesto del Toro diff --git a/.travis.yml b/.travis.yml index ba62b87bf5..7d0777fee9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,51 +6,56 @@ matrix: - os: linux dist: trusty sudo: required - go: 1.7.x + go: 1.10.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 + - 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: linux dist: trusty sudo: required - go: 1.8.x + go: 1.11.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 + - go run build/ci.go test -coverage $TEST_PACKAGES # These are the latest Go versions. - os: linux dist: trusty sudo: required - go: 1.9.x + 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 + - go run build/ci.go test -coverage $TEST_PACKAGES - os: osx - go: 1.9.x + 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 - - brew update - - brew install caskroom/cask/brew-cask - - brew cask install osxfuse - go run build/ci.go install - - go run build/ci.go test -coverage + - go run build/ci.go test -coverage $TEST_PACKAGES # This builder only tests code linters on latest version of Go - os: linux dist: trusty - go: 1.9.x + go: 1.12.x env: - lint git: @@ -58,14 +63,13 @@ matrix: script: - go run build/ci.go lint - # This builder does the Ubuntu PPA and Linux Azure uploads - - os: linux + # This builder does the Ubuntu PPA upload + - if: repo = ethereum/go-ethereum AND type = push + os: linux dist: trusty - sudo: required - go: 1.9.x + go: 1.12.x env: - ubuntu-ppa - - azure-linux git: submodules: false # avoid cloning ethereum/tests addons: @@ -74,11 +78,29 @@ matrix: - devscripts - debhelper - dput - - gcc-multilib - fakeroot + - python-bzrlib + - python-paramiko + script: + - 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: repo = ethereum/go-ethereum AND type = push + os: linux + dist: trusty + sudo: required + go: 1.12.x + env: + - azure-linux + git: + submodules: false # avoid cloning ethereum/tests + addons: + apt: + packages: + - gcc-multilib script: # Build for the primary platforms that Trusty can manage - - go run build/ci.go debsrc -signer "Go Ethereum Linux Builder " -upload ppa:ethereum/ethereum - go run build/ci.go install - go run build/ci.go archive -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds - go run build/ci.go install -arch 386 @@ -98,11 +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 - - os: linux + - if: repo = ethereum/go-ethereum AND type = push + os: linux dist: trusty services: - docker - go: 1.9.x + go: 1.12.x env: - azure-linux-mips git: @@ -125,8 +148,9 @@ 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 - - os: linux - dist: precise # Needed for the android tools + - if: repo = ethereum/go-ethereum AND type = push + os: linux + dist: trusty addons: apt: packages: @@ -146,24 +170,24 @@ matrix: git: submodules: false # avoid cloning ethereum/tests before_install: - - curl https://storage.googleapis.com/golang/go1.9.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-r15c-linux-x86_64.zip -o android-ndk-r15c.zip - - unzip -q android-ndk-r15c.zip && rm android-ndk-r15c.zip - - mv android-ndk-r15c $HOME - - export ANDROID_NDK=$HOME/android-ndk-r15c + - 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 - - os: osx - go: 1.9.x + - if: repo = ethereum/go-ethereum AND type = push + os: osx + go: 1.12.x env: - azure-osx - azure-ios @@ -185,13 +209,15 @@ matrix: - xctool -version - xcrun simctl list + # Workaround for https://github.com/golang/go/issues/23749 + - export CGO_CFLAGS_ALLOW='-fmodules|-fblocks|-fobjc-arc' - 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 - - os: linux + - if: repo = ethereum/go-ethereum AND type = cron + os: linux dist: trusty - sudo: required - go: 1.9.x + go: 1.12.x env: - azure-purge git: @@ -199,9 +225,11 @@ matrix: script: - go run build/ci.go purge -store gethstore/builds -days 14 -notifications: - webhooks: - urls: - - https://webhooks.gitter.im/e/e09ccdce1048c5e03445 - on_success: change - on_failure: always + - 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 -v -timeout 20m -race ./swarm... diff --git a/AUTHORS b/AUTHORS index faa19d281c..609dc48c72 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,85 +1,174 @@ # This is the official list of go-ethereum authors for copyright purposes. +Afri Schoedon <5chdn@users.noreply.github.com> +Agustin Armellini Fischer +Airead +Alan Chen +Alejandro Isaza Ales Katona Alex Leverington +Alex Wu Alexandre Van de Sande +Ali Hajimirza +Anton Evangelatov +Arba Sasmoyo +Armani Ferrante +Armin Braun Aron Fischer Bas van Kervel Benjamin Brent +Benoit Verkindt +Bo +Bo Ye +Bob Glickstein Brian Schroeder Casey Detrio +Chase Wright Christoph Jentzsch Daniel A. Nagy +Daniel Sloof +Darrel Herbst +Dave Appleton Diego Siqueira +Dmitry Shulyak +Egon Elbre +Elias Naur Elliot Shepherd Enrique Fynn +Ernesto del Toro Ethan Buchman +Eugene Valeyev +Evangelos Pappas +Evgeny Danilenko <6655321@bk.ru> Fabian Vogelsteller +Fabio Barone Fabio Berger +FaceHo Felix Lange +Fiisio Frank Wang +Furkan KAMACI Gary Rong +George Ornbo Gregg Dourgarian +Guillaume Ballet Guillaume Nicolas Gustav Simonsson Hao Bryan Cheng Henning Diedrich Isidoro Ghezzi +Ivan Daniluk Jae Kwon Jamie Pitts +Janoš Guljaš Jason Carver +Jay Guo Jeff R. Allen Jeffrey Wilcke Jens Agerberg +Jia Chenhui +Jim McDonald +Joel Burget Jonathan Brown Joseph Chow Justin Clark-Casey Justin Drake Kenji Siu Kobi Gurkan +Konrad Feldmeier +Kurkó Mihály +Kyuntae Ethan Kim Lefteris Karapetsas Leif Jurvetson +Leo Shklovskii Lewis Marshall +Lio李欧 Louis Holbrook Luca Zeug +Magicking Maran Hidskes Marek Kotewicz +Mark Martin Holst Swende Matthew Di Ferrante Matthew Wampler-Doty +Maximilian Meister Micah Zoltu +Michael Ruminer +Miguel Mota +Miya Chen Nchinda Nchinda Nick Dodson Nick Johnson +Nicolas Guillaume +Noman +Oli Bye +Paul Litvak Paulo L F Casaretto +Paweł Bylica Peter Pratscher +Petr Mikusek Péter Szilágyi -RJ Catalano +RJ Catalano Ramesh Nair Ricardo Catalinas Jiménez +Ricardo Domingos +Richard Hart +Rob +Robert Zaremba +Russ Cox Rémy Roy +S. Matthew English Shintaro Kaneko +Sorin Neacsu Stein Dekker +Steve Waldman Steven Roose Taylor Gerring Thomas Bocek +Ti Zhou Tosh Camille -Valentin Wüstholz +Valentin Wüstholz Victor Farazdagi Victor Tran Viktor Trón Ville Sundell Vincent G Vitalik Buterin +Vitaly V Vivek Anand Vlad Gluhovsky Yohann Léon Yoichi Hirai +Yondon Fu +Zach Zahoor Mohamed +Zoe Nolan Zsolt Felföldi +am2rican5 +ayeowch +b00ris +bailantaotao +baizhenxuan +bloonfield +changhong +evgk +ferhat elmas holisticode +jtakalai ken10100147 ligi +mark.lin +necaremus +njupt-moon <1015041018@njupt.edu.cn> +nkbai +rhaps107 +slumber1122 +sunxiaojun2014 +terasum +tsarpaul xiekeyang +yoza ΞTHΞЯSPHΞЯΞ <{viktor.tron,nagydani,zsfelfoldi}@gmail.com> Максим Чусовлянов +Ralph Caraveo diff --git a/Dockerfile b/Dockerfile index f4396fcf28..4b205d6492 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build Geth in a stock Go builder container -FROM golang:1.9-alpine as builder +FROM golang:1.12-alpine as builder RUN apk add --no-cache make gcc musl-dev linux-headers @@ -12,5 +12,5 @@ FROM alpine:latest RUN apk add --no-cache ca-certificates COPY --from=builder /go-ethereum/build/bin/geth /usr/local/bin/ -EXPOSE 8545 8546 30303 30303/udp 30304/udp +EXPOSE 8545 8546 30303 30303/udp ENTRYPOINT ["geth"] diff --git a/Dockerfile.alltools b/Dockerfile.alltools index 79bf0f8d56..4a4a26f8bc 100644 --- a/Dockerfile.alltools +++ b/Dockerfile.alltools @@ -1,5 +1,5 @@ # Build Geth in a stock Go builder container -FROM golang:1.9-alpine as builder +FROM golang:1.12-alpine as builder RUN apk add --no-cache make gcc musl-dev linux-headers @@ -12,4 +12,4 @@ FROM alpine:latest RUN apk add --no-cache ca-certificates COPY --from=builder /go-ethereum/build/bin/* /usr/local/bin/ -EXPOSE 8545 8546 30303 30303/udp 30304/udp +EXPOSE 8545 8546 30303 30303/udp diff --git a/Makefile b/Makefile index 3922d6015b..966bf9cbba 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,11 @@ ios: test: all build/env.sh go run build/ci.go test +lint: ## Run linters. + build/env.sh go run build/ci.go lint + clean: + ./build/clean_go_build_cache.sh rm -fr build/_workspace/pkg/ $(GOBIN)/* # The devtools target installs tools required for 'go generate'. @@ -53,6 +57,9 @@ devtools: @type "solc" 2> /dev/null || echo 'Please install solc' @type "protoc" 2> /dev/null || echo 'Please install protoc' +swarm-devtools: + env GOBIN= go install ./cmd/swarm/mimegen + # Cross Compilation Targets (xgo) geth-cross: geth-linux geth-darwin geth-windows geth-android geth-ios diff --git a/README.md b/README.md index 61e36afec4..02a8775084 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,13 @@ ## Go Ethereum -Official golang implementation of the Ethereum protocol. +Official Golang implementation of the Ethereum protocol. [![API Reference]( https://camo.githubusercontent.com/915b7be44ada53c290eb157634330494ebe3e30a/68747470733a2f2f676f646f632e6f72672f6769746875622e636f6d2f676f6c616e672f6764646f3f7374617475732e737667 )](https://godoc.org/github.com/ethereum/go-ethereum) -[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ethereum/go-ethereum?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) +[![Go Report Card](https://goreportcard.com/badge/github.com/ethereum/go-ethereum)](https://goreportcard.com/report/github.com/ethereum/go-ethereum) +[![Travis](https://travis-ci.org/ethereum/go-ethereum.svg?branch=master)](https://travis-ci.org/ethereum/go-ethereum) +[![Discord](https://img.shields.io/badge/discord-join%20chat-blue.svg)](https://discord.gg/nthXNEv) Automated builds are available for stable releases and the unstable master branch. Binary archives are published at https://geth.ethereum.org/downloads/. @@ -16,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.9 or later) and a C compiler. You can install them using your favourite package manager. Once the dependencies are installed, run @@ -32,13 +34,13 @@ 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. | +| **`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. | | `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 https://swarm-guide.readthedocs.io for swarm documentation. | +| `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 @@ -56,23 +58,21 @@ the user doesn't care about years-old historical data, so we can fast-sync quick state of the network. To do so: ``` -$ geth --fast --cache=512 console +$ geth console ``` This command will: - * Start geth in fast sync mode (`--fast`), causing it to download more data in exchange for avoiding - processing the entire history of the Ethereum network, which is very CPU intensive. - * Bump the memory allowance of the database to 512MB (`--cache=512`), which can help significantly in - sync times especially for HDD users. This flag is optional and you can set it as high or as low as - you'd like, though we'd recommend the 512MB - 2GB range. + * Start geth in fast sync mode (default, can be changed with the `--syncmode` flag), causing it to + download more data in exchange for avoiding processing the entire history of the Ethereum network, + which is very CPU intensive. * Start up Geth's built-in interactive [JavaScript console](https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console), (via the trailing `console` subcommand) through which you can invoke all official [`web3` methods](https://github.com/ethereum/wiki/wiki/JavaScript-API) as well as Geth's own [management APIs](https://github.com/ethereum/go-ethereum/wiki/Management-APIs). - This too is optional and if you leave it out you can always attach to an already running Geth instance + 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 @@ -80,14 +80,13 @@ entire system. In other words, instead of attaching to the main network, you wan network with your node, which is fully equivalent to the main network, but with play-Ether only. ``` -$ geth --testnet --fast --cache=512 console +$ geth --testnet console ``` -The `--fast`, `--cache` flags and `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 @@ -102,6 +101,14 @@ over between the main network and test network, you should make sure to always u for play-money and real-money. Unless you manually move accounts, Geth will by default correctly 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. + +``` +$ geth --rinkeby console +``` + ### Configuration As an alternative to passing the numerous flags to the `geth` binary, you can also pass a configuration file via: @@ -125,20 +132,20 @@ One of the quickest ways to get Ethereum up and running on your machine is by us ``` docker run -d --name ethereum-node -v /Users/alice/ethereum:/root \ -p 8545:8545 -p 30303:30303 \ - ethereum/client-go --fast --cache=512 + ethereum/client-go ``` -This will start geth in fast sync mode with a DB memory allowance of 512MB just as the above command does. It will also create a persistent volume in your home directory for saving your blockchain as well as map the default ports. There is also an `alpine` tag available for a slim version of the image. +This will start geth in fast-sync mode with a DB memory allowance of 1GB just as the above command does. It will also create a persistent volume in your home directory for saving your blockchain as well as map the default ports. There is also an `alpine` tag available for a slim version of the image. 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 +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. @@ -161,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 @@ -234,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 @@ -257,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: @@ -291,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/VERSION b/VERSION deleted file mode 100644 index 27f9cd322b..0000000000 --- a/VERSION +++ /dev/null @@ -1 +0,0 @@ -1.8.0 diff --git a/accounts/abi/abi.go b/accounts/abi/abi.go index abcb403db2..ba1774c647 100644 --- a/accounts/abi/abi.go +++ b/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 @@ -82,7 +80,7 @@ func (abi ABI) Unpack(v interface{}, name string, output []byte) (err error) { // 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") + return fmt.Errorf("abi: improperly formatted output: %s - Bytes: [%+v]", string(output), output) } return method.Outputs.Unpack(v, output) } else if event, ok := abi.Events[name]; ok { @@ -136,11 +134,14 @@ func (abi *ABI) UnmarshalJSON(data []byte) error { // MethodById looks up a method by the 4-byte id // returns nil if none found -func (abi *ABI) MethodById(sigdata []byte) *Method { +func (abi *ABI) MethodById(sigdata []byte) (*Method, error) { + if len(sigdata) < 4 { + 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]) { - return &method + return &method, nil } } - return nil + return nil, fmt.Errorf("no method with id: %#x", sigdata[:4]) } diff --git a/accounts/abi/abi_test.go b/accounts/abi/abi_test.go index 2d43b631c2..b9444f9f0d 100644 --- a/accounts/abi/abi_test.go +++ b/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)) @@ -621,14 +648,16 @@ func TestBareEvents(t *testing.T) { // TestUnpackEvent is based on this contract: // contract T { // event received(address sender, uint amount, bytes memo); +// event receivedAddr(address sender); // function receive(bytes memo) external payable { // received(msg.sender, msg.value, memo); +// receivedAddr(msg.sender); // } // } // When receive("X") is called with sender 0x00... and value 1, it produces this tx receipt: // receipt{status=1 cgas=23949 bloom=00000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000040200000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 logs=[log: b6818c8064f645cd82d99b59a1a267d6d61117ef [75fd880d39c1daf53b6547ab6cb59451fc6452d27caa90e5b6649dd8293b9eed] 000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158 9ae378b6d4409eada347a5dc0c180f186cb62dc68fcc0f043425eb917335aa28 0 95d429d309bb9d753954195fe2d69bd140b4ae731b9b5b605c34323de162cf00 0]} func TestUnpackEvent(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"}]` + 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) @@ -644,17 +673,24 @@ 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 { + Sender common.Address + } + var receivedAddrEv ReceivedAddrEvent + err = abi.Unpack(&receivedAddrEv, "receivedAddr", data) + if err != nil { + t.Error(err) } } @@ -689,10 +725,23 @@ func TestABI_MethodById(t *testing.T) { } for name, m := range abi.Methods { a := fmt.Sprintf("%v", m) - b := fmt.Sprintf("%v", abi.MethodById(m.Id())) + m2, err := abi.MethodById(m.Id()) + if err != nil { + t.Fatalf("Failed to look up ABI method: %v", err) + } + b := fmt.Sprintf("%v", m2) if a != b { t.Errorf("Method %v (id %v) not 'findable' by id in ABI", name, common.ToHex(m.Id())) } } - + // Also test empty + if _, err := abi.MethodById([]byte{0x00}); err == nil { + t.Errorf("Expected error, too short to decode data") + } + if _, err := abi.MethodById([]byte{}); err == nil { + t.Errorf("Expected error, too short to decode data") + } + if _, err := abi.MethodById(nil); err == nil { + t.Errorf("Expected error, nil is short to decode data") + } } diff --git a/accounts/abi/argument.go b/accounts/abi/argument.go index 04ca6150ad..d0a6b035c6 100644 --- a/accounts/abi/argument.go +++ b/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 } @@ -67,6 +70,17 @@ func (arguments Arguments) LengthNonIndexed() int { return out } +// NonIndexed returns the arguments with indexed arguments filtered out +func (arguments Arguments) NonIndexed() Arguments { + var ret []Argument + for _, arg := range arguments { + if !arg.Indexed { + ret = append(ret, arg) + } + } + return ret +} + // isTuple returns true for non-atomic constructs, like (uint,uint) or uint[] func (arguments Arguments) isTuple() bool { return len(arguments) > 1 @@ -74,88 +88,145 @@ func (arguments Arguments) isTuple() bool { // Unpack performs the operation hexdata -> Go format func (arguments Arguments) Unpack(v interface{}, data []byte) error { - if arguments.isTuple() { - return arguments.unpackTuple(v, data) - } - return arguments.unpackAtomic(v, data) -} - -func (arguments Arguments) unpackTuple(v interface{}, output []byte) error { // make sure the passed value is arguments pointer - valueOf := reflect.ValueOf(v) - if reflect.Ptr != valueOf.Kind() { + if reflect.Ptr != reflect.ValueOf(v).Kind() { return fmt.Errorf("abi: Unpack(non-pointer %T)", v) } - - var ( - value = valueOf.Elem() - typ = value.Type() - kind = value.Kind() - ) - - if err := requireUnpackKind(value, typ, kind, arguments); err != nil { + marshalledValues, err := arguments.UnpackValues(data) + if err != nil { return err } - // If the output interface is a struct, make sure names don't collide - if kind == reflect.Struct { - exists := make(map[string]bool) - for _, arg := range arguments { - field := capitalise(arg.Name) - if field == "" { - return fmt.Errorf("abi: purely underscored output cannot unpack to struct") - } - if exists[field] { - return fmt.Errorf("abi: multiple outputs mapping to the same struct field '%s'", field) - } - exists[field] = true - } + if arguments.isTuple() { + return arguments.unpackTuple(v, marshalledValues) } - // `i` counts the nonindexed arguments. - // `j` counts the number of complex types. - // both `i` and `j` are used to to correctly compute `data` offset. + return arguments.unpackAtomic(v, marshalledValues[0]) +} - i, j := -1, 0 - for _, arg := range arguments { +// 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 ( + dstVal = reflect.ValueOf(dst).Elem() + srcVal = reflect.ValueOf(src) + ) - if arg.Indexed { - // can't read, continue - continue + if t.T != TupleTy && !((t.T == SliceTy || t.T == ArrayTy) && t.Elem.T == TupleTy) { + return set(dstVal, srcVal) + } + + 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()) } - i++ - marshalledValue, err := toGoType((i+j)*32, arg.Type, output) + fieldmap, err := mapArgNamesToStructFields(t.TupleRawNames, dstVal) if err != nil { return err } - - if arg.Type.T == ArrayTy { - // combined index ('i' + 'j') need to be adjusted only by size of array, thus - // we need to decrement 'j' because 'i' was incremented - j += arg.Type.Size - 1 + 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]) + } + if err := unpack(elem, field.Addr().Interface(), srcVal.Field(i).Interface()); err != nil { + return err + } } + 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 +} - reflectValue := reflect.ValueOf(marshalledValue) +// unpackAtomic unpacks ( hexdata -> go ) a single value +func (arguments Arguments) unpackAtomic(v interface{}, marshalledValues interface{}) error { + if arguments.LengthNonIndexed() == 0 { + return nil + } + argument := arguments.NonIndexed()[0] + elem := reflect.ValueOf(v).Elem() + 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) +} + +// 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 + } + + // 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: - name := capitalise(arg.Name) - for j := 0; j < typ.NumField(); j++ { - // TODO read tags: `abi:"fieldName"` - if typ.Field(j).Name == name { - if err := set(value.Field(j), reflectValue, arg); err != nil { - return err - } - } + 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, reflectValue); err != nil { + if err := requireAssignable(v, reflect.ValueOf(marshalledValues[i])); err != nil { return err } - - if err := set(v.Elem(), reflectValue, arg); err != nil { + if err := unpack(&arg.Type, v.Addr().Interface(), marshalledValues[i]); err != nil { return err } default: @@ -163,37 +234,55 @@ func (arguments Arguments) unpackTuple(v interface{}, output []byte) error { } } return nil + } -// unpackAtomic unpacks ( hexdata -> go ) a single value -func (arguments Arguments) unpackAtomic(v interface{}, output []byte) error { - // make sure the passed value is arguments pointer - valueOf := reflect.ValueOf(v) - if reflect.Ptr != valueOf.Kind() { - return fmt.Errorf("abi: Unpack(non-pointer %T)", v) +// UnpackValues can be used to unpack ABI-encoded hexdata according to the ABI-specification, +// without supplying a struct to unpack into. Instead, this method returns a list containing the +// values. An atomic argument will be a list with one element. +func (arguments Arguments) UnpackValues(data []byte) ([]interface{}, error) { + retval := make([]interface{}, 0, arguments.LengthNonIndexed()) + virtualArgs := 0 + for index, arg := range arguments.NonIndexed() { + marshalledValue, err := toGoType((index+virtualArgs)*32, arg.Type, data) + 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 + // 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(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 + } + retval = append(retval, marshalledValue) } - arg := arguments[0] - if arg.Indexed { - return fmt.Errorf("abi: attempting to unpack indexed variable into element.") - } - - value := valueOf.Elem() - - marshalledValue, err := toGoType(0, arg.Type, output) - if err != nil { - return err - } - return set(value, reflect.ValueOf(marshalledValue), arg) + return retval, nil } -// Unpack performs the operation Go format -> Hexdata +// PackValues performs the operation Go format -> Hexdata +// It is the semantic opposite of UnpackValues +func (arguments Arguments) PackValues(args []interface{}) ([]byte, error) { + return arguments.Pack(args...) +} + +// Pack performs the operation Go format -> Hexdata func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) { // Make sure arguments match up and pack them abiArgs := arguments if len(args) != len(abiArgs) { return nil, fmt.Errorf("argument count mismatch: %d for %d", len(args), len(abiArgs)) } - // variable input is the output appended at the end of packed // output. This is used for strings and bytes types input. var variableInput []byte @@ -201,13 +290,8 @@ 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 { input := abiArgs[i] @@ -216,15 +300,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 @@ -237,14 +319,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/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 1803d3f236..de81db1344 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -31,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/bloombits" + "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" @@ -64,11 +65,11 @@ type SimulatedBackend struct { // NewSimulatedBackend creates a new binding backend using a simulated blockchain // for testing purposes. -func NewSimulatedBackend(alloc core.GenesisAlloc) *SimulatedBackend { - database, _ := ethdb.NewMemDatabase() - genesis := core.Genesis{Config: params.AllEthashProtocolChanges, Alloc: alloc} +func NewSimulatedBackend(alloc core.GenesisAlloc, gasLimit uint64) *SimulatedBackend { + database := ethdb.NewMemDatabase() + genesis := core.Genesis{Config: params.AllEthashProtocolChanges, GasLimit: gasLimit, Alloc: alloc} genesis.MustCommit(database) - blockchain, _ := core.NewBlockChain(database, genesis.Config, ethash.NewFaker(), vm.Config{}) + blockchain, _ := core.NewBlockChain(database, nil, genesis.Config, ethash.NewFaker(), vm.Config{}, nil) backend := &SimulatedBackend{ database: database, @@ -102,8 +103,10 @@ func (b *SimulatedBackend) Rollback() { func (b *SimulatedBackend) rollback() { blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(int, *core.BlockGen) {}) + statedb, _ := b.blockchain.State() + b.pendingBlock = blocks[0] - b.pendingState, _ = state.New(b.pendingBlock.Root(), state.NewDatabase(b.database)) + b.pendingState, _ = state.New(b.pendingBlock.Root(), statedb.Database()) } // CodeAt returns the code associated with a certain account in the blockchain. @@ -157,10 +160,29 @@ func (b *SimulatedBackend) StorageAt(ctx context.Context, contract common.Addres // TransactionReceipt returns the receipt of a transaction. func (b *SimulatedBackend) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { - receipt, _, _, _ := core.GetReceipt(b.database, txHash) + receipt, _, _, _ := rawdb.ReadReceipt(b.database, txHash) 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() @@ -205,7 +227,7 @@ func (b *SimulatedBackend) PendingNonceAt(ctx context.Context, account common.Ad } // SuggestGasPrice implements ContractTransactor.SuggestGasPrice. Since the simulated -// chain doens't have miners, we just return a gas price of 1 for any call. +// chain doesn't have miners, we just return a gas price of 1 for any call. func (b *SimulatedBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error) { return big.NewInt(1), nil } @@ -305,12 +327,14 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) { for _, tx := range b.pendingBlock.Transactions() { - block.AddTx(tx) + block.AddTxWithChain(b.blockchain, tx) } - block.AddTx(tx) + block.AddTxWithChain(b.blockchain, tx) }) + statedb, _ := b.blockchain.State() + b.pendingBlock = blocks[0] - b.pendingState, _ = state.New(b.pendingBlock.Root(), state.NewDatabase(b.database)) + b.pendingState, _ = state.New(b.pendingBlock.Root(), statedb.Database()) return nil } @@ -319,18 +343,24 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa // // TODO(karalabe): Deprecate when the subscription one can return past data too. func (b *SimulatedBackend) FilterLogs(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) { - // Initialize unset filter boundaried to run from genesis to chain head - from := int64(0) - if query.FromBlock != nil { - from = query.FromBlock.Int64() + var filter *filters.Filter + if query.BlockHash != nil { + // Block filter requested, construct a single-shot filter + filter = filters.NewBlockFilter(&filterBackend{b.database, b.blockchain}, *query.BlockHash, query.Addresses, query.Topics) + } else { + // Initialize unset filter boundaried to run from genesis to chain head + from := int64(0) + if query.FromBlock != nil { + from = query.FromBlock.Int64() + } + to := int64(-1) + if query.ToBlock != nil { + to = query.ToBlock.Int64() + } + // Construct the range filter + filter = filters.NewRangeFilter(&filterBackend{b.database, b.blockchain}, from, to, query.Addresses, query.Topics) } - to := int64(-1) - if query.ToBlock != nil { - to = query.ToBlock.Int64() - } - // Construct and execute the filter - filter := filters.New(&filterBackend{b.database, b.blockchain}, from, to, query.Addresses, query.Topics) - + // Run the filter and return all the logs logs, err := filter.Logs(ctx) if err != nil { return nil, err @@ -386,8 +416,10 @@ func (b *SimulatedBackend) AdjustTime(adjustment time.Duration) error { } block.OffsetTime(int64(adjustment.Seconds())) }) + statedb, _ := b.blockchain.State() + b.pendingBlock = blocks[0] - b.pendingState, _ = state.New(b.pendingBlock.Root(), state.NewDatabase(b.database)) + b.pendingState, _ = state.New(b.pendingBlock.Root(), statedb.Database()) return nil } @@ -422,11 +454,36 @@ func (fb *filterBackend) HeaderByNumber(ctx context.Context, block rpc.BlockNumb } return fb.bc.GetHeaderByNumber(uint64(block.Int64())), nil } -func (fb *filterBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { - return core.GetBlockReceipts(fb.db, hash, core.GetBlockNumber(fb.db, hash)), nil + +func (fb *filterBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { + return fb.bc.GetHeaderByHash(hash), nil } -func (fb *filterBackend) SubscribeTxPreEvent(ch chan<- core.TxPreEvent) event.Subscription { +func (fb *filterBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { + number := rawdb.ReadHeaderNumber(fb.db, hash) + if number == nil { + return nil, nil + } + return rawdb.ReadReceipts(fb.db, hash, *number), nil +} + +func (fb *filterBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) { + number := rawdb.ReadHeaderNumber(fb.db, hash) + if number == nil { + return nil, nil + } + receipts := rawdb.ReadReceipts(fb.db, hash, *number) + if receipts == nil { + return nil, nil + } + logs := make([][]*types.Log, len(receipts)) + for i, receipt := range receipts { + logs[i] = receipt.Logs + } + return logs, nil +} + +func (fb *filterBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription { return event.NewSubscription(func(quit <-chan struct{}) error { <-quit return nil diff --git a/accounts/abi/bind/backends/simulated_test.go b/accounts/abi/bind/backends/simulated_test.go new file mode 100644 index 0000000000..bd75807d75 --- /dev/null +++ b/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/accounts/abi/bind/base.go b/accounts/abi/bind/base.go index 83ad1c8ae7..c37bdf11d5 100644 --- a/accounts/abi/bind/base.go +++ b/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/accounts/abi/bind/base_test.go b/accounts/abi/bind/base_test.go new file mode 100644 index 0000000000..02caf457a4 --- /dev/null +++ b/accounts/abi/bind/base_test.go @@ -0,0 +1,80 @@ +// 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 ( + "context" + "math/big" + "testing" + + 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" +) + +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") + } +} diff --git a/accounts/abi/bind/bind.go b/accounts/abi/bind/bind.go index e31b454812..5ee30d0249 100644 --- a/accounts/abi/bind/bind.go +++ b/accounts/abi/bind/bind.go @@ -23,13 +23,13 @@ package bind import ( "bytes" "fmt" + "go/format" "regexp" "strings" "text/template" "unicode" "github.com/ethereum/go-ethereum/accounts/abi" - "golang.org/x/tools/imports" ) // Lang is a target programming language selector to generate bindings for. @@ -145,9 +145,9 @@ func Bind(types []string, abis []string, bytecodes []string, pkg string, lang La if err := tmpl.Execute(buffer, data); err != nil { return "", err } - // For Go bindings pass the code through goimports to clean it up and double check + // For Go bindings pass the code through gofmt to clean it up if lang == LangGo { - code, err := imports.Process(".", buffer.Bytes(), nil) + code, err := format.Source(buffer.Bytes()) if err != nil { return "", fmt.Errorf("%v\n%s", err, buffer) } @@ -164,118 +164,147 @@ var bindType = map[Lang]func(kind abi.Type) string{ LangJava: bindTypeJava, } +// Helper function for the binding generators. +// It reads the unmatched characters after the inner type-match, +// (since the inner type is a prefix of the total type declaration), +// looks for valid arrays (possibly a dynamic one) wrapping the inner type, +// and returns the sizes of these arrays. +// +// Returned array sizes are in the same order as solidity signatures; inner array size first. +// Array sizes may also be "", indicating a dynamic array. +func wrapArray(stringKind string, innerLen int, innerMapping string) (string, []string) { + remainder := stringKind[innerLen:] + //find all the sizes + matches := regexp.MustCompile(`\[(\d*)\]`).FindAllStringSubmatch(remainder, -1) + parts := make([]string, 0, len(matches)) + for _, match := range matches { + //get group 1 from the regex match + parts = append(parts, match[1]) + } + return innerMapping, parts +} + +// Translates the array sizes to a Go-lang declaration of a (nested) array of the inner type. +// Simply returns the inner type if arraySizes is empty. +func arrayBindingGo(inner string, arraySizes []string) string { + out := "" + //prepend all array sizes, from outer (end arraySizes) to inner (start arraySizes) + for i := len(arraySizes) - 1; i >= 0; i-- { + out += "[" + arraySizes[i] + "]" + } + out += inner + return out +} + // bindTypeGo converts a Solidity type to a Go one. Since there is no clear mapping // from all Solidity types to Go ones (e.g. uint17), those that cannot be exactly // mapped will use an upscaled type (e.g. *big.Int). func bindTypeGo(kind abi.Type) string { stringKind := kind.String() + innerLen, innerMapping := bindUnnestedTypeGo(stringKind) + return arrayBindingGo(wrapArray(stringKind, innerLen, innerMapping)) +} + +// The inner function of bindTypeGo, this finds the inner type of stringKind. +// (Or just the type itself if it is not an array or slice) +// The length of the matched part is returned, with the translated type. +func bindUnnestedTypeGo(stringKind string) (int, string) { switch { case strings.HasPrefix(stringKind, "address"): - parts := regexp.MustCompile(`address(\[[0-9]*\])?`).FindStringSubmatch(stringKind) - if len(parts) != 2 { - return stringKind - } - return fmt.Sprintf("%scommon.Address", parts[1]) + return len("address"), "common.Address" case strings.HasPrefix(stringKind, "bytes"): - parts := regexp.MustCompile(`bytes([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(stringKind) - if len(parts) != 3 { - return stringKind - } - return fmt.Sprintf("%s[%s]byte", parts[2], parts[1]) + parts := regexp.MustCompile(`bytes([0-9]*)`).FindStringSubmatch(stringKind) + return len(parts[0]), fmt.Sprintf("[%s]byte", parts[1]) case strings.HasPrefix(stringKind, "int") || strings.HasPrefix(stringKind, "uint"): - parts := regexp.MustCompile(`(u)?int([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(stringKind) - if len(parts) != 4 { - return stringKind - } + parts := regexp.MustCompile(`(u)?int([0-9]*)`).FindStringSubmatch(stringKind) switch parts[2] { case "8", "16", "32", "64": - return fmt.Sprintf("%s%sint%s", parts[3], parts[1], parts[2]) + return len(parts[0]), fmt.Sprintf("%sint%s", parts[1], parts[2]) } - return fmt.Sprintf("%s*big.Int", parts[3]) + return len(parts[0]), "*big.Int" - case strings.HasPrefix(stringKind, "bool") || strings.HasPrefix(stringKind, "string"): - parts := regexp.MustCompile(`([a-z]+)(\[[0-9]*\])?`).FindStringSubmatch(stringKind) - if len(parts) != 3 { - return stringKind - } - return fmt.Sprintf("%s%s", parts[2], parts[1]) + case strings.HasPrefix(stringKind, "bool"): + return len("bool"), "bool" + + case strings.HasPrefix(stringKind, "string"): + return len("string"), "string" default: - return stringKind + return len(stringKind), stringKind } } +// Translates the array sizes to a Java declaration of a (nested) array of the inner type. +// Simply returns the inner type if arraySizes is empty. +func arrayBindingJava(inner string, arraySizes []string) string { + // Java array type declarations do not include the length. + return inner + strings.Repeat("[]", len(arraySizes)) +} + // bindTypeJava converts a Solidity type to a Java one. Since there is no clear mapping // from all Solidity types to Java ones (e.g. uint17), those that cannot be exactly // mapped will use an upscaled type (e.g. BigDecimal). func bindTypeJava(kind abi.Type) string { stringKind := kind.String() + innerLen, innerMapping := bindUnnestedTypeJava(stringKind) + return arrayBindingJava(wrapArray(stringKind, innerLen, innerMapping)) +} + +// The inner function of bindTypeJava, this finds the inner type of stringKind. +// (Or just the type itself if it is not an array or slice) +// The length of the matched part is returned, with the translated type. +func bindUnnestedTypeJava(stringKind string) (int, string) { switch { case strings.HasPrefix(stringKind, "address"): parts := regexp.MustCompile(`address(\[[0-9]*\])?`).FindStringSubmatch(stringKind) if len(parts) != 2 { - return stringKind + return len(stringKind), stringKind } if parts[1] == "" { - return fmt.Sprintf("Address") + return len("address"), "Address" } - return fmt.Sprintf("Addresses") + return len(parts[0]), "Addresses" case strings.HasPrefix(stringKind, "bytes"): - parts := regexp.MustCompile(`bytes([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(stringKind) - if len(parts) != 3 { - return stringKind + parts := regexp.MustCompile(`bytes([0-9]*)`).FindStringSubmatch(stringKind) + if len(parts) != 2 { + return len(stringKind), stringKind } - if parts[2] != "" { - return "byte[][]" - } - return "byte[]" + return len(parts[0]), "byte[]" case strings.HasPrefix(stringKind, "int") || strings.HasPrefix(stringKind, "uint"): - parts := regexp.MustCompile(`(u)?int([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(stringKind) - if len(parts) != 4 { - return stringKind + //Note that uint and int (without digits) are also matched, + // these are size 256, and will translate to BigInt (the default). + parts := regexp.MustCompile(`(u)?int([0-9]*)`).FindStringSubmatch(stringKind) + if len(parts) != 3 { + return len(stringKind), stringKind } - switch parts[2] { - case "8", "16", "32", "64": - if parts[1] == "" { - if parts[3] == "" { - return fmt.Sprintf("int%s", parts[2]) - } - return fmt.Sprintf("int%s[]", parts[2]) - } + + namedSize := map[string]string{ + "8": "byte", + "16": "short", + "32": "int", + "64": "long", + }[parts[2]] + + //default to BigInt + if namedSize == "" { + namedSize = "BigInt" } - if parts[3] == "" { - return fmt.Sprintf("BigInt") - } - return fmt.Sprintf("BigInts") + return len(parts[0]), namedSize case strings.HasPrefix(stringKind, "bool"): - parts := regexp.MustCompile(`bool(\[[0-9]*\])?`).FindStringSubmatch(stringKind) - if len(parts) != 2 { - return stringKind - } - if parts[1] == "" { - return fmt.Sprintf("bool") - } - return fmt.Sprintf("bool[]") + return len("bool"), "boolean" case strings.HasPrefix(stringKind, "string"): - parts := regexp.MustCompile(`string(\[[0-9]*\])?`).FindStringSubmatch(stringKind) - if len(parts) != 2 { - return stringKind - } - if parts[1] == "" { - return fmt.Sprintf("String") - } - return fmt.Sprintf("String[]") + return len("string"), "String" default: - return stringKind + return len(stringKind), stringKind } } @@ -325,11 +354,13 @@ func namedTypeJava(javaKind string, solKind abi.Type) string { return "String" case "string[]": return "Strings" - case "bool": + case "boolean": return "Bool" - case "bool[]": + case "boolean[]": return "Bools" - case "BigInt": + case "BigInt[]": + return "BigInts" + default: parts := regexp.MustCompile(`(u)?int([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(solKind.String()) if len(parts) != 4 { return javaKind @@ -344,33 +375,29 @@ func namedTypeJava(javaKind string, solKind abi.Type) string { default: return javaKind } - default: - return javaKind } } // 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 the first character of a string upper case, also removing any -// prefixing underscores from the variable names. +// 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 strings.ToUpper(input[:1]) + input[1:] + return abi.ToCamelCase(input) } -// decapitalise makes the first character of a string lower case. +// decapitalise makes a camel-case string which starts with a lower case character. func decapitalise(input string) string { - return strings.ToLower(input[:1]) + input[1:] + if len(input) == 0 { + return input + } + + 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/accounts/abi/bind/bind_test.go b/accounts/abi/bind/bind_test.go index c4838e6470..46e0b38d00 100644 --- a/accounts/abi/bind/bind_test.go +++ b/accounts/abi/bind/bind_test.go @@ -27,7 +27,6 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" - "golang.org/x/tools/imports" ) var bindTests = []struct { @@ -35,6 +34,7 @@ var bindTests = []struct { contract string bytecode string abi string + imports string tester string }{ // Test that the binding is available in combined and separate forms too @@ -43,6 +43,7 @@ var bindTests = []struct { `contract NilContract {}`, `606060405260068060106000396000f3606060405200`, `[]`, + `"github.com/ethereum/go-ethereum/common"`, ` if b, err := NewEmpty(common.Address{}, nil); b == nil || err != nil { t.Fatalf("combined binding (%v) nil or error (%v) not nil", b, nil) @@ -61,6 +62,7 @@ var bindTests = []struct { `https://ethereum.org/token`, `60606040526040516107fd3803806107fd83398101604052805160805160a05160c051929391820192909101600160a060020a0333166000908152600360209081526040822086905581548551838052601f6002600019610100600186161502019093169290920482018390047f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56390810193919290918801908390106100e857805160ff19168380011785555b506101189291505b8082111561017157600081556001016100b4565b50506002805460ff19168317905550505050610658806101a56000396000f35b828001600101855582156100ac579182015b828111156100ac5782518260005055916020019190600101906100fa565b50508060016000509080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061017557805160ff19168380011785555b506100c89291506100b4565b5090565b82800160010185558215610165579182015b8281111561016557825182600050559160200191906001019061018756606060405236156100775760e060020a600035046306fdde03811461007f57806323b872dd146100dc578063313ce5671461010e57806370a082311461011a57806395d89b4114610132578063a9059cbb1461018e578063cae9ca51146101bd578063dc3080f21461031c578063dd62ed3e14610341575b610365610002565b61036760008054602060026001831615610100026000190190921691909104601f810182900490910260809081016040526060828152929190828280156104eb5780601f106104c0576101008083540402835291602001916104eb565b6103d5600435602435604435600160a060020a038316600090815260036020526040812054829010156104f357610002565b6103e760025460ff1681565b6103d560043560036020526000908152604090205481565b610367600180546020600282841615610100026000190190921691909104601f810182900490910260809081016040526060828152929190828280156104eb5780601f106104c0576101008083540402835291602001916104eb565b610365600435602435600160a060020a033316600090815260036020526040902054819010156103f157610002565b60806020604435600481810135601f8101849004909302840160405260608381526103d5948235946024803595606494939101919081908382808284375094965050505050505060006000836004600050600033600160a060020a03168152602001908152602001600020600050600087600160a060020a031681526020019081526020016000206000508190555084905080600160a060020a0316638f4ffcb1338630876040518560e060020a0281526004018085600160a060020a0316815260200184815260200183600160a060020a03168152602001806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156102f25780820380516001836020036101000a031916815260200191505b50955050505050506000604051808303816000876161da5a03f11561000257505050509392505050565b6005602090815260043560009081526040808220909252602435815220546103d59081565b60046020818152903560009081526040808220909252602435815220546103d59081565b005b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156103c75780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b60408051918252519081900360200190f35b6060908152602090f35b600160a060020a03821660009081526040902054808201101561041357610002565b806003600050600033600160a060020a03168152602001908152602001600020600082828250540392505081905550806003600050600084600160a060020a0316815260200190815260200160002060008282825054019250508190555081600160a060020a031633600160a060020a03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a35050565b820191906000526020600020905b8154815290600101906020018083116104ce57829003601f168201915b505050505081565b600160a060020a03831681526040812054808301101561051257610002565b600160a060020a0380851680835260046020908152604080852033949094168086529382528085205492855260058252808520938552929052908220548301111561055c57610002565b816003600050600086600160a060020a03168152602001908152602001600020600082828250540392505081905550816003600050600085600160a060020a03168152602001908152602001600020600082828250540192505081905550816005600050600086600160a060020a03168152602001908152602001600020600050600033600160a060020a0316815260200190815260200160002060008282825054019250508190555082600160a060020a031633600160a060020a03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a3939250505056`, `[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"success","type":"bool"}],"type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"},{"name":"_extraData","type":"bytes"}],"name":"approveAndCall","outputs":[{"name":"success","type":"bool"}],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"spentAllowance","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"inputs":[{"name":"initialSupply","type":"uint256"},{"name":"tokenName","type":"string"},{"name":"decimalUnits","type":"uint8"},{"name":"tokenSymbol","type":"string"}],"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"}]`, + `"github.com/ethereum/go-ethereum/common"`, ` if b, err := NewToken(common.Address{}, nil); b == nil || err != nil { t.Fatalf("binding (%v) nil or error (%v) not nil", b, nil) @@ -72,6 +74,7 @@ var bindTests = []struct { `https://ethereum.org/crowdsale`, `606060408190526007805460ff1916905560a0806105a883396101006040529051608051915160c05160e05160008054600160a060020a03199081169095178155670de0b6b3a7640000958602600155603c9093024201600355930260045560058054909216909217905561052f90819061007990396000f36060604052361561006c5760e060020a600035046301cb3b20811461008257806329dcb0cf1461014457806338af3eed1461014d5780636e66f6e91461015f5780637a3a0e84146101715780637b3e5e7b1461017a578063a035b1fe14610183578063dc0d3dff1461018c575b61020060075460009060ff161561032357610002565b61020060035460009042106103205760025460015490106103cb576002548154600160a060020a0316908290606082818181858883f150915460025460408051600160a060020a039390931683526020830191909152818101869052517fe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf6945090819003909201919050a15b60405160008054600160a060020a039081169230909116319082818181858883f150506007805460ff1916600117905550505050565b6103a160035481565b6103ab600054600160a060020a031681565b6103ab600554600160a060020a031681565b6103a160015481565b6103a160025481565b6103a160045481565b6103be60043560068054829081101561000257506000526002027ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f8101547ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d409190910154600160a060020a03919091169082565b005b505050815481101561000257906000526020600020906002020160005060008201518160000160006101000a815481600160a060020a030219169083021790555060208201518160010160005055905050806002600082828250540192505081905550600560009054906101000a9004600160a060020a0316600160a060020a031663a9059cbb3360046000505484046040518360e060020a0281526004018083600160a060020a03168152602001828152602001925050506000604051808303816000876161da5a03f11561000257505060408051600160a060020a03331681526020810184905260018183015290517fe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf692509081900360600190a15b50565b5060a0604052336060908152346080819052600680546001810180835592939282908280158290116102025760020281600202836000526020600020918201910161020291905b8082111561039d57805473ffffffffffffffffffffffffffffffffffffffff19168155600060019190910190815561036a565b5090565b6060908152602090f35b600160a060020a03166060908152602090f35b6060918252608052604090f35b5b60065481101561010e576006805482908110156100025760009182526002027ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f0190600680549254600160a060020a0316928490811015610002576002027ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d40015460405190915082818181858883f19350505050507fe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf660066000508281548110156100025760008290526002027ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f01548154600160a060020a039190911691908490811015610002576002027ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d40015460408051600160a060020a0394909416845260208401919091526000838201525191829003606001919050a16001016103cc56`, `[{"constant":false,"inputs":[],"name":"checkGoalReached","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"deadline","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"beneficiary","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":true,"inputs":[],"name":"tokenReward","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":true,"inputs":[],"name":"fundingGoal","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"amountRaised","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"price","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"funders","outputs":[{"name":"addr","type":"address"},{"name":"amount","type":"uint256"}],"type":"function"},{"inputs":[{"name":"ifSuccessfulSendTo","type":"address"},{"name":"fundingGoalInEthers","type":"uint256"},{"name":"durationInMinutes","type":"uint256"},{"name":"etherCostOfEachToken","type":"uint256"},{"name":"addressOfTokenUsedAsReward","type":"address"}],"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"backer","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"isContribution","type":"bool"}],"name":"FundTransfer","type":"event"}]`, + `"github.com/ethereum/go-ethereum/common"`, ` if b, err := NewCrowdsale(common.Address{}, nil); b == nil || err != nil { t.Fatalf("binding (%v) nil or error (%v) not nil", b, nil) @@ -83,6 +86,7 @@ var bindTests = []struct { `https://ethereum.org/dao`, `606060405260405160808061145f833960e06040529051905160a05160c05160008054600160a060020a03191633179055600184815560028490556003839055600780549182018082558280158290116100b8576003028160030283600052602060002091820191016100b891906101c8565b50506060919091015160029190910155600160a060020a0381166000146100a65760008054600160a060020a031916821790555b505050506111f18061026e6000396000f35b505060408051608081018252600080825260208281018290528351908101845281815292820192909252426060820152600780549194509250811015610002579081527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6889050815181546020848101517401000000000000000000000000000000000000000002600160a060020a03199290921690921760a060020a60ff021916178255604083015180516001848101805460008281528690209195600293821615610100026000190190911692909204601f9081018390048201949192919091019083901061023e57805160ff19168380011785555b50610072929150610226565b5050600060028201556001015b8082111561023a578054600160a860020a031916815560018181018054600080835592600290821615610100026000190190911604601f81901061020c57506101bb565b601f0160209004906000526020600020908101906101bb91905b8082111561023a5760008155600101610226565b5090565b828001600101855582156101af579182015b828111156101af57825182600050559160200191906001019061025056606060405236156100b95760e060020a6000350463013cf08b81146100bb578063237e9492146101285780633910682114610281578063400e3949146102995780635daf08ca146102a257806369bd34361461032f5780638160f0b5146103385780638da5cb5b146103415780639644fcbd14610353578063aa02a90f146103be578063b1050da5146103c7578063bcca1fd3146104b5578063d3c0715b146104dc578063eceb29451461058d578063f2fde38b1461067b575b005b61069c6004356004805482908110156100025790600052602060002090600a02016000506005810154815460018301546003840154600485015460068601546007870154600160a060020a03959095169750929560020194919360ff828116946101009093041692919089565b60408051602060248035600481810135601f81018590048502860185019096528585526107759581359591946044949293909201918190840183828082843750949650505050505050600060006004600050848154811015610002575090527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19e600a8402908101547f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b909101904210806101e65750600481015460ff165b8061026757508060000160009054906101000a9004600160a060020a03168160010160005054846040518084600160a060020a0316606060020a0281526014018381526020018280519060200190808383829060006004602084601f0104600f02600301f15090500193505050506040518091039020816007016000505414155b8061027757506001546005820154105b1561109257610002565b61077560043560066020526000908152604090205481565b61077560055481565b61078760043560078054829081101561000257506000526003026000805160206111d18339815191528101547fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c68a820154600160a060020a0382169260a060020a90920460ff16917fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c689019084565b61077560025481565b61077560015481565b610830600054600160a060020a031681565b604080516020604435600481810135601f81018490048402850184019095528484526100b9948135946024803595939460649492939101918190840183828082843750949650505050505050600080548190600160a060020a03908116339091161461084d57610002565b61077560035481565b604080516020604435600481810135601f8101849004840285018401909552848452610775948135946024803595939460649492939101918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976084979196506024909101945090925082915084018382808284375094965050505050505033600160a060020a031660009081526006602052604081205481908114806104ab5750604081205460078054909190811015610002579082526003026000805160206111d1833981519152015460a060020a900460ff16155b15610ce557610002565b6100b960043560243560443560005433600160a060020a03908116911614610b1857610002565b604080516020604435600481810135601f810184900484028501840190955284845261077594813594602480359593946064949293910191819084018382808284375094965050505050505033600160a060020a031660009081526006602052604081205481908114806105835750604081205460078054909190811015610002579082526003026000805160206111d18339815191520181505460a060020a900460ff16155b15610f1d57610002565b604080516020606435600481810135601f81018490048402850184019095528484526107759481359460248035956044359560849492019190819084018382808284375094965050505050505060006000600460005086815481101561000257908252600a027f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01815090508484846040518084600160a060020a0316606060020a0281526014018381526020018280519060200190808383829060006004602084601f0104600f02600301f150905001935050505060405180910390208160070160005054149150610cdc565b6100b960043560005433600160a060020a03908116911614610f0857610002565b604051808a600160a060020a031681526020018981526020018060200188815260200187815260200186815260200185815260200184815260200183815260200182810382528981815460018160011615610100020316600290048152602001915080546001816001161561010002031660029004801561075e5780601f106107335761010080835404028352916020019161075e565b820191906000526020600020905b81548152906001019060200180831161074157829003601f168201915b50509a505050505050505050505060405180910390f35b60408051918252519081900360200190f35b60408051600160a060020a038616815260208101859052606081018390526080918101828152845460026001821615610100026000190190911604928201839052909160a08301908590801561081e5780601f106107f35761010080835404028352916020019161081e565b820191906000526020600020905b81548152906001019060200180831161080157829003601f168201915b50509550505050505060405180910390f35b60408051600160a060020a03929092168252519081900360200190f35b600160a060020a03851660009081526006602052604081205414156108a957604060002060078054918290556001820180825582801582901161095c5760030281600302836000526020600020918201910161095c9190610a4f565b600160a060020a03851660009081526006602052604090205460078054919350908390811015610002575060005250600381026000805160206111d183398151915201805474ff0000000000000000000000000000000000000000191660a060020a85021781555b60408051600160a060020a03871681526020810186905281517f27b022af4a8347100c7a041ce5ccf8e14d644ff05de696315196faae8cd50c9b929181900390910190a15050505050565b505050915081506080604051908101604052808681526020018581526020018481526020014281526020015060076000508381548110156100025790600052602060002090600302016000508151815460208481015160a060020a02600160a060020a03199290921690921774ff00000000000000000000000000000000000000001916178255604083015180516001848101805460008281528690209195600293821615610100026000190190911692909204601f90810183900482019491929190910190839010610ad357805160ff19168380011785555b50610b03929150610abb565b5050600060028201556001015b80821115610acf57805474ffffffffffffffffffffffffffffffffffffffffff1916815560018181018054600080835592600290821615610100026000190190911604601f819010610aa15750610a42565b601f016020900490600052602060002090810190610a4291905b80821115610acf5760008155600101610abb565b5090565b82800160010185558215610a36579182015b82811115610a36578251826000505591602001919060010190610ae5565b50506060919091015160029190910155610911565b600183905560028290556003819055604080518481526020810184905280820183905290517fa439d3fa452be5e0e1e24a8145e715f4fd8b9c08c96a42fd82a855a85e5d57de9181900360600190a1505050565b50508585846040518084600160a060020a0316606060020a0281526014018381526020018280519060200190808383829060006004602084601f0104600f02600301f150905001935050505060405180910390208160070160005081905550600260005054603c024201816003016000508190555060008160040160006101000a81548160ff0219169083021790555060008160040160016101000a81548160ff02191690830217905550600081600501600050819055507f646fec02522b41e7125cfc859a64fd4f4cefd5dc3b6237ca0abe251ded1fa881828787876040518085815260200184600160a060020a03168152602001838152602001806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f168015610cc45780820380516001836020036101000a031916815260200191505b509550505050505060405180910390a1600182016005555b50949350505050565b6004805460018101808355909190828015829011610d1c57600a0281600a028360005260206000209182019101610d1c9190610db8565b505060048054929450918491508110156100025790600052602060002090600a02016000508054600160a060020a031916871781556001818101879055855160028381018054600082815260209081902096975091959481161561010002600019011691909104601f90810182900484019391890190839010610ed857805160ff19168380011785555b50610b6c929150610abb565b50506001015b80821115610acf578054600160a060020a03191681556000600182810182905560028381018054848255909281161561010002600019011604601f819010610e9c57505b5060006003830181905560048301805461ffff191690556005830181905560068301819055600783018190556008830180548282559082526020909120610db2916002028101905b80821115610acf57805474ffffffffffffffffffffffffffffffffffffffffff1916815560018181018054600080835592600290821615610100026000190190911604601f819010610eba57505b5050600101610e44565b601f016020900490600052602060002090810190610dfc9190610abb565b601f016020900490600052602060002090810190610e929190610abb565b82800160010185558215610da6579182015b82811115610da6578251826000505591602001919060010190610eea565b60008054600160a060020a0319168217905550565b600480548690811015610002576000918252600a027f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01905033600160a060020a0316600090815260098201602052604090205490915060ff1660011415610f8457610002565b33600160a060020a031660009081526009820160205260409020805460ff1916600190811790915560058201805490910190558315610fcd576006810180546001019055610fda565b6006810180546000190190555b7fc34f869b7ff431b034b7b9aea9822dac189a685e0b015c7d1be3add3f89128e8858533866040518085815260200184815260200183600160a060020a03168152602001806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f16801561107a5780820380516001836020036101000a031916815260200191505b509550505050505060405180910390a1509392505050565b6006810154600354901315611158578060000160009054906101000a9004600160a060020a0316600160a060020a03168160010160005054670de0b6b3a76400000284604051808280519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156111225780820380516001836020036101000a031916815260200191505b5091505060006040518083038185876185025a03f15050505060048101805460ff191660011761ff00191661010017905561116d565b60048101805460ff191660011761ff00191690555b60068101546005820154600483015460408051888152602081019490945283810192909252610100900460ff166060830152517fd220b7272a8b6d0d7d6bcdace67b936a8f175e6d5c1b3ee438b72256b32ab3af9181900360800190a1509291505056a66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688`, `[{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"proposals","outputs":[{"name":"recipient","type":"address"},{"name":"amount","type":"uint256"},{"name":"description","type":"string"},{"name":"votingDeadline","type":"uint256"},{"name":"executed","type":"bool"},{"name":"proposalPassed","type":"bool"},{"name":"numberOfVotes","type":"uint256"},{"name":"currentResult","type":"int256"},{"name":"proposalHash","type":"bytes32"}],"type":"function"},{"constant":false,"inputs":[{"name":"proposalNumber","type":"uint256"},{"name":"transactionBytecode","type":"bytes"}],"name":"executeProposal","outputs":[{"name":"result","type":"int256"}],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"memberId","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"numProposals","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"members","outputs":[{"name":"member","type":"address"},{"name":"canVote","type":"bool"},{"name":"name","type":"string"},{"name":"memberSince","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"debatingPeriodInMinutes","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"minimumQuorum","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":false,"inputs":[{"name":"targetMember","type":"address"},{"name":"canVote","type":"bool"},{"name":"memberName","type":"string"}],"name":"changeMembership","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"majorityMargin","outputs":[{"name":"","type":"int256"}],"type":"function"},{"constant":false,"inputs":[{"name":"beneficiary","type":"address"},{"name":"etherAmount","type":"uint256"},{"name":"JobDescription","type":"string"},{"name":"transactionBytecode","type":"bytes"}],"name":"newProposal","outputs":[{"name":"proposalID","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"minimumQuorumForProposals","type":"uint256"},{"name":"minutesForDebate","type":"uint256"},{"name":"marginOfVotesForMajority","type":"int256"}],"name":"changeVotingRules","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"proposalNumber","type":"uint256"},{"name":"supportsProposal","type":"bool"},{"name":"justificationText","type":"string"}],"name":"vote","outputs":[{"name":"voteID","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[{"name":"proposalNumber","type":"uint256"},{"name":"beneficiary","type":"address"},{"name":"etherAmount","type":"uint256"},{"name":"transactionBytecode","type":"bytes"}],"name":"checkProposalCode","outputs":[{"name":"codeChecksOut","type":"bool"}],"type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"type":"function"},{"inputs":[{"name":"minimumQuorumForProposals","type":"uint256"},{"name":"minutesForDebate","type":"uint256"},{"name":"marginOfVotesForMajority","type":"int256"},{"name":"congressLeader","type":"address"}],"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"proposalID","type":"uint256"},{"indexed":false,"name":"recipient","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"description","type":"string"}],"name":"ProposalAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"proposalID","type":"uint256"},{"indexed":false,"name":"position","type":"bool"},{"indexed":false,"name":"voter","type":"address"},{"indexed":false,"name":"justification","type":"string"}],"name":"Voted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"proposalID","type":"uint256"},{"indexed":false,"name":"result","type":"int256"},{"indexed":false,"name":"quorum","type":"uint256"},{"indexed":false,"name":"active","type":"bool"}],"name":"ProposalTallied","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"member","type":"address"},{"indexed":false,"name":"isMember","type":"bool"}],"name":"MembershipChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"minimumQuorum","type":"uint256"},{"indexed":false,"name":"debatingPeriodInMinutes","type":"uint256"},{"indexed":false,"name":"majorityMargin","type":"int256"}],"name":"ChangeOfRules","type":"event"}]`, + `"github.com/ethereum/go-ethereum/common"`, ` if b, err := NewDAO(common.Address{}, nil); b == nil || err != nil { t.Fatalf("binding (%v) nil or error (%v) not nil", b, nil) @@ -102,6 +106,11 @@ var bindTests = []struct { {"type":"function","name":"mixedInputs","constant":true,"inputs":[{"name":"","type":"string"},{"name":"str","type":"string"}],"outputs":[]} ] `, + ` + "fmt" + + "github.com/ethereum/go-ethereum/common" + `, `if b, err := NewInputChecker(common.Address{}, nil); b == nil || err != nil { t.Fatalf("binding (%v) nil or error (%v) not nil", b, nil) } else if false { // Don't run, just compile and test types @@ -131,6 +140,11 @@ var bindTests = []struct { {"type":"function","name":"mixedOutputs","constant":true,"inputs":[],"outputs":[{"name":"","type":"string"},{"name":"str","type":"string"}]} ] `, + ` + "fmt" + + "github.com/ethereum/go-ethereum/common" + `, `if b, err := NewOutputChecker(common.Address{}, nil); b == nil || err != nil { t.Fatalf("binding (%v) nil or error (%v) not nil", b, nil) } else if false { // Don't run, just compile and test types @@ -160,6 +174,13 @@ var bindTests = []struct { {"type":"event","name":"dynamic","inputs":[{"name":"idxStr","type":"string","indexed":true},{"name":"idxDat","type":"bytes","indexed":true},{"name":"str","type":"string"},{"name":"dat","type":"bytes"}]} ] `, + ` + "fmt" + "math/big" + "reflect" + + "github.com/ethereum/go-ethereum/common" + `, `if e, err := NewEventChecker(common.Address{}, nil); e == nil || err != nil { t.Fatalf("binding (%v) nil or error (%v) not nil", e, nil) } else if false { // Don't run, just compile and test types @@ -225,11 +246,19 @@ var bindTests = []struct { `, `6060604052604051610328380380610328833981016040528051018060006000509080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10608d57805160ff19168380011785555b50607c9291505b8082111560ba57838155600101606b565b50505061026a806100be6000396000f35b828001600101855582156064579182015b828111156064578251826000505591602001919060010190609e565b509056606060405260e060020a60003504630d86a0e181146100315780636874e8091461008d578063d736c513146100ea575b005b610190600180546020600282841615610100026000190190921691909104601f810182900490910260809081016040526060828152929190828280156102295780601f106101fe57610100808354040283529160200191610229565b61019060008054602060026001831615610100026000190190921691909104601f810182900490910260809081016040526060828152929190828280156102295780601f106101fe57610100808354040283529160200191610229565b60206004803580820135601f81018490049093026080908101604052606084815261002f946024939192918401918190838280828437509496505050505050508060016000509080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061023157805160ff19168380011785555b506102619291505b808211156102665760008155830161017d565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156101f05780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b820191906000526020600020905b81548152906001019060200180831161020c57829003601f168201915b505050505081565b82800160010185558215610175579182015b82811115610175578251826000505591602001919060010190610243565b505050565b509056`, `[{"constant":true,"inputs":[],"name":"transactString","outputs":[{"name":"","type":"string"}],"type":"function"},{"constant":true,"inputs":[],"name":"deployString","outputs":[{"name":"","type":"string"}],"type":"function"},{"constant":false,"inputs":[{"name":"str","type":"string"}],"name":"transact","outputs":[],"type":"function"},{"inputs":[{"name":"str","type":"string"}],"type":"constructor"}]`, + ` + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/crypto" + `, ` // Generate a new random account and a funded simulator key, _ := crypto.GenerateKey() auth := bind.NewKeyedTransactor(key) - sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}) + sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000) // Deploy an interaction tester contract and call a transaction on it _, _, interactor, err := DeployInteractor(auth, sim, "Deploy string") @@ -266,11 +295,19 @@ var bindTests = []struct { `, `606060405260dc8060106000396000f3606060405260e060020a6000350463993a04b78114601a575b005b600060605260c0604052600260809081527f486900000000000000000000000000000000000000000000000000000000000060a05260017fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47060e0829052610100819052606060c0908152600261012081905281906101409060a09080838184600060046012f1505081517fffff000000000000000000000000000000000000000000000000000000000000169091525050604051610160819003945092505050f3`, `[{"constant":true,"inputs":[],"name":"getter","outputs":[{"name":"","type":"string"},{"name":"","type":"int256"},{"name":"","type":"bytes32"}],"type":"function"}]`, + ` + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/crypto" + `, ` // Generate a new random account and a funded simulator key, _ := crypto.GenerateKey() auth := bind.NewKeyedTransactor(key) - sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}) + sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000) // Deploy a tuple tester contract and execute a structured call on it _, _, getter, err := DeployGetter(auth, sim) @@ -298,11 +335,19 @@ var bindTests = []struct { `, `606060405260dc8060106000396000f3606060405260e060020a60003504633175aae28114601a575b005b600060605260c0604052600260809081527f486900000000000000000000000000000000000000000000000000000000000060a05260017fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47060e0829052610100819052606060c0908152600261012081905281906101409060a09080838184600060046012f1505081517fffff000000000000000000000000000000000000000000000000000000000000169091525050604051610160819003945092505050f3`, `[{"constant":true,"inputs":[],"name":"tuple","outputs":[{"name":"a","type":"string"},{"name":"b","type":"int256"},{"name":"c","type":"bytes32"}],"type":"function"}]`, + ` + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/crypto" + `, ` // Generate a new random account and a funded simulator key, _ := crypto.GenerateKey() auth := bind.NewKeyedTransactor(key) - sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}) + sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000) // Deploy a tuple tester contract and execute a structured call on it _, _, tupler, err := DeployTupler(auth, sim) @@ -340,11 +385,21 @@ var bindTests = []struct { `, `606060405261015c806100126000396000f3606060405260e060020a6000350463be1127a3811461003c578063d88becc014610092578063e15a3db71461003c578063f637e5891461003c575b005b604080516020600480358082013583810285810185019096528085526100ee959294602494909392850192829185019084908082843750949650505050505050604080516020810190915260009052805b919050565b604080516102e0818101909252610138916004916102e491839060179083908390808284375090955050505050506102e0604051908101604052806017905b60008152602001906001900390816100d15790505081905061008d565b60405180806020018281038252838181518152602001915080519060200190602002808383829060006004602084601f0104600f02600301f1509050019250505060405180910390f35b60405180826102e0808381846000600461015cf15090500191505060405180910390f3`, `[{"constant":true,"inputs":[{"name":"input","type":"address[]"}],"name":"echoAddresses","outputs":[{"name":"output","type":"address[]"}],"type":"function"},{"constant":true,"inputs":[{"name":"input","type":"uint24[23]"}],"name":"echoFancyInts","outputs":[{"name":"output","type":"uint24[23]"}],"type":"function"},{"constant":true,"inputs":[{"name":"input","type":"int256[]"}],"name":"echoInts","outputs":[{"name":"output","type":"int256[]"}],"type":"function"},{"constant":true,"inputs":[{"name":"input","type":"bool[]"}],"name":"echoBools","outputs":[{"name":"output","type":"bool[]"}],"type":"function"}]`, + ` + "math/big" + "reflect" + + "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/crypto" + `, ` // Generate a new random account and a funded simulator key, _ := crypto.GenerateKey() auth := bind.NewKeyedTransactor(key) - sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}) + sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000) // Deploy a slice tester contract and execute a n array call on it _, _, slicer, err := DeploySlicer(auth, sim) @@ -374,11 +429,19 @@ var bindTests = []struct { `, `6060604052606a8060106000396000f360606040523615601d5760e060020a6000350463fc9c8d3981146040575b605e6000805473ffffffffffffffffffffffffffffffffffffffff191633179055565b606060005473ffffffffffffffffffffffffffffffffffffffff1681565b005b6060908152602090f3`, `[{"constant":true,"inputs":[],"name":"caller","outputs":[{"name":"","type":"address"}],"type":"function"}]`, + ` + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/crypto" + `, ` // Generate a new random account and a funded simulator key, _ := crypto.GenerateKey() auth := bind.NewKeyedTransactor(key) - sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}) + sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000) // Deploy a default method invoker contract and execute its default method _, _, defaulter, err := DeployDefaulter(auth, sim) @@ -409,9 +472,14 @@ var bindTests = []struct { `, `6060604052609f8060106000396000f3606060405260e060020a6000350463f97a60058114601a575b005b600060605260c0604052600d60809081527f4920646f6e27742065786973740000000000000000000000000000000000000060a052602060c0908152600d60e081905281906101009060a09080838184600060046012f15050815172ffffffffffffffffffffffffffffffffffffff1916909152505060405161012081900392509050f3`, `[{"constant":true,"inputs":[],"name":"String","outputs":[{"name":"","type":"string"}],"type":"function"}]`, + ` + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" + "github.com/ethereum/go-ethereum/common" + `, ` // Create a simulator and wrap a non-deployed contract - sim := backends.NewSimulatedBackend(nil) + sim := backends.NewSimulatedBackend(nil, uint64(10000000000)) nonexistent, err := NewNonExistent(common.Address{}, sim) if err != nil { @@ -425,7 +493,7 @@ var bindTests = []struct { } `, }, - // Tests that gas estimation works for contracts with weird gas mechanics too. + // Tests that gas estimation works for contracts with weird gas mechanics too. { `FunkyGasPattern`, ` @@ -443,11 +511,19 @@ var bindTests = []struct { `, `606060405261021c806100126000396000f3606060405260e060020a600035046323fcf32a81146100265780634f28bf0e1461007b575b005b6040805160206004803580820135601f8101849004840285018401909552848452610024949193602493909291840191908190840183828082843750949650505050505050620186a05a101561014e57610002565b6100db60008054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281529291908301828280156102145780601f106101e957610100808354040283529160200191610214565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561013b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b505050565b8060006000509080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106101b557805160ff19168380011785555b506101499291505b808211156101e557600081556001016101a1565b82800160010185558215610199579182015b828111156101995782518260005055916020019190600101906101c7565b5090565b820191906000526020600020905b8154815290600101906020018083116101f757829003601f168201915b50505050508156`, `[{"constant":false,"inputs":[{"name":"value","type":"string"}],"name":"SetField","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"field","outputs":[{"name":"","type":"string"}],"type":"function"}]`, + ` + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/crypto" + `, ` // Generate a new random account and a funded simulator key, _ := crypto.GenerateKey() auth := bind.NewKeyedTransactor(key) - sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}) + sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000) // Deploy a funky gas pattern contract _, _, limiter, err := DeployFunkyGasPattern(auth, sim) @@ -478,11 +554,20 @@ var bindTests = []struct { } `, `6060604052346000575b6086806100176000396000f300606060405263ffffffff60e060020a60003504166349f8e98281146022575b6000565b34600057602c6055565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b335b905600a165627a7a72305820aef6b7685c0fa24ba6027e4870404a57df701473fe4107741805c19f5138417c0029`, `[{"constant":true,"inputs":[],"name":"callFrom","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"}]`, + ` + "math/big" + + "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/crypto" + `, ` // Generate a new random account and a funded simulator key, _ := crypto.GenerateKey() auth := bind.NewKeyedTransactor(key) - sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}) + sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000) // Deploy a sender tester contract and execute a structured call on it _, _, callfrom, err := DeployCallFrom(auth, sim) @@ -506,6 +591,7 @@ var bindTests = []struct { } `, }, + // Tests that methods and returns with underscores inside work correctly. { `Underscorer`, ` @@ -518,7 +604,7 @@ var bindTests = []struct { } function LowerUpperCollision() constant returns (int _res, int Res) { return (1, 2); - } + } function UpperLowerCollision() constant returns (int _Res, int res) { return (1, 2); } @@ -531,14 +617,26 @@ var bindTests = []struct { function AllPurelyUnderscoredOutput() constant returns (int _, int __) { return (1, 2); } + function _under_scored_func() constant returns (int _int) { + return 0; + } } - `, `6060604052341561000f57600080fd5b6103498061001e6000396000f300606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806303a592131461008857806367e6633d146100b85780639df484851461014d578063af7486ab1461017d578063b564b34d146101ad578063e02ab24d146101dd578063e409ca451461020d575b600080fd5b341561009357600080fd5b61009b61023d565b604051808381526020018281526020019250505060405180910390f35b34156100c357600080fd5b6100cb610252565b6040518083815260200180602001828103825283818151815260200191508051906020019080838360005b838110156101115780820151818401526020810190506100f6565b50505050905090810190601f16801561013e5780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b341561015857600080fd5b6101606102a0565b604051808381526020018281526020019250505060405180910390f35b341561018857600080fd5b6101906102b5565b604051808381526020018281526020019250505060405180910390f35b34156101b857600080fd5b6101c06102ca565b604051808381526020018281526020019250505060405180910390f35b34156101e857600080fd5b6101f06102df565b604051808381526020018281526020019250505060405180910390f35b341561021857600080fd5b6102206102f4565b604051808381526020018281526020019250505060405180910390f35b60008060016002819150809050915091509091565b600061025c610309565b61013a8090506040805190810160405280600281526020017f7069000000000000000000000000000000000000000000000000000000000000815250915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b6020604051908101604052806000815250905600a165627a7a72305820c11dcfa136fc7d182ee4d34f0b12d988496228f7e2d02d2b5376d996ca1743d00029`, - `[{"constant":true,"inputs":[],"name":"LowerUpperCollision","outputs":[{"name":"_res","type":"int256"},{"name":"Res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"UnderscoredOutput","outputs":[{"name":"_int","type":"int256"},{"name":"_string","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"PurelyUnderscoredOutput","outputs":[{"name":"_","type":"int256"},{"name":"res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"UpperLowerCollision","outputs":[{"name":"_Res","type":"int256"},{"name":"res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"AllPurelyUnderscoredOutput","outputs":[{"name":"_","type":"int256"},{"name":"__","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"UpperUpperCollision","outputs":[{"name":"_Res","type":"int256"},{"name":"Res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"LowerLowerCollision","outputs":[{"name":"_res","type":"int256"},{"name":"res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"}]`, + `, `6060604052341561000f57600080fd5b6103858061001e6000396000f30060606040526004361061008e576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806303a592131461009357806346546dbe146100c357806367e6633d146100ec5780639df4848514610181578063af7486ab146101b1578063b564b34d146101e1578063e02ab24d14610211578063e409ca4514610241575b600080fd5b341561009e57600080fd5b6100a6610271565b604051808381526020018281526020019250505060405180910390f35b34156100ce57600080fd5b6100d6610286565b6040518082815260200191505060405180910390f35b34156100f757600080fd5b6100ff61028e565b6040518083815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561014557808201518184015260208101905061012a565b50505050905090810190601f1680156101725780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b341561018c57600080fd5b6101946102dc565b604051808381526020018281526020019250505060405180910390f35b34156101bc57600080fd5b6101c46102f1565b604051808381526020018281526020019250505060405180910390f35b34156101ec57600080fd5b6101f4610306565b604051808381526020018281526020019250505060405180910390f35b341561021c57600080fd5b61022461031b565b604051808381526020018281526020019250505060405180910390f35b341561024c57600080fd5b610254610330565b604051808381526020018281526020019250505060405180910390f35b60008060016002819150809050915091509091565b600080905090565b6000610298610345565b61013a8090506040805190810160405280600281526020017f7069000000000000000000000000000000000000000000000000000000000000815250915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b6020604051908101604052806000815250905600a165627a7a72305820d1a53d9de9d1e3d55cb3dc591900b63c4f1ded79114f7b79b332684840e186a40029`, + `[{"constant":true,"inputs":[],"name":"LowerUpperCollision","outputs":[{"name":"_res","type":"int256"},{"name":"Res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_under_scored_func","outputs":[{"name":"_int","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"UnderscoredOutput","outputs":[{"name":"_int","type":"int256"},{"name":"_string","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"PurelyUnderscoredOutput","outputs":[{"name":"_","type":"int256"},{"name":"res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"UpperLowerCollision","outputs":[{"name":"_Res","type":"int256"},{"name":"res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"AllPurelyUnderscoredOutput","outputs":[{"name":"_","type":"int256"},{"name":"__","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"UpperUpperCollision","outputs":[{"name":"_Res","type":"int256"},{"name":"Res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"LowerLowerCollision","outputs":[{"name":"_res","type":"int256"},{"name":"res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"}]`, + ` + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/crypto" + `, ` // Generate a new random account and a funded simulator key, _ := crypto.GenerateKey() auth := bind.NewKeyedTransactor(key) - sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}) + sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000) // Deploy a underscorer tester contract and execute a structured call on it _, _, underscorer, err := DeployUnderscorer(auth, sim) @@ -562,6 +660,7 @@ var bindTests = []struct { a, b, _ = underscorer.UpperUpperCollision(nil) a, b, _ = underscorer.PurelyUnderscoredOutput(nil) a, b, _ = underscorer.AllPurelyUnderscoredOutput(nil) + a, _ = underscorer.UnderScoredFunc(nil) fmt.Println(a, b, err) `, @@ -603,11 +702,21 @@ var bindTests = []struct { `, `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"}]`, + ` + "math/big" + "time" + + "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/crypto" + `, ` // Generate a new random account and a funded simulator key, _ := crypto.GenerateKey() auth := bind.NewKeyedTransactor(key) - sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}) + sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000) // Deploy an eventer contract _, _, eventer, err := DeployEventer(auth, sim) @@ -737,6 +846,81 @@ var bindTests = []struct { } `, }, + { + `DeeplyNestedArray`, + ` + contract DeeplyNestedArray { + uint64[3][4][5] public deepUint64Array; + function storeDeepUintArray(uint64[3][4][5] arr) public { + deepUint64Array = arr; + } + function retrieveDeepArray() public view returns (uint64[3][4][5]) { + return deepUint64Array; + } + } + `, + `6060604052341561000f57600080fd5b6106438061001e6000396000f300606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063344248551461005c5780638ed4573a1461011457806398ed1856146101ab575b600080fd5b341561006757600080fd5b610112600480806107800190600580602002604051908101604052809291906000905b828210156101055783826101800201600480602002604051908101604052809291906000905b828210156100f25783826060020160038060200260405190810160405280929190826003602002808284378201915050505050815260200190600101906100b0565b505050508152602001906001019061008a565b5050505091905050610208565b005b341561011f57600080fd5b61012761021d565b604051808260056000925b8184101561019b578284602002015160046000925b8184101561018d5782846020020151600360200280838360005b8381101561017c578082015181840152602081019050610161565b505050509050019260010192610147565b925050509260010192610132565b9250505091505060405180910390f35b34156101b657600080fd5b6101de6004808035906020019091908035906020019091908035906020019091905050610309565b604051808267ffffffffffffffff1667ffffffffffffffff16815260200191505060405180910390f35b80600090600561021992919061035f565b5050565b6102256103b0565b6000600580602002604051908101604052809291906000905b8282101561030057838260040201600480602002604051908101604052809291906000905b828210156102ed578382016003806020026040519081016040528092919082600380156102d9576020028201916000905b82829054906101000a900467ffffffffffffffff1667ffffffffffffffff16815260200190600801906020826007010492830192600103820291508084116102945790505b505050505081526020019060010190610263565b505050508152602001906001019061023e565b50505050905090565b60008360058110151561031857fe5b600402018260048110151561032957fe5b018160038110151561033757fe5b6004918282040191900660080292509250509054906101000a900467ffffffffffffffff1681565b826005600402810192821561039f579160200282015b8281111561039e5782518290600461038e9291906103df565b5091602001919060040190610375565b5b5090506103ac919061042d565b5090565b610780604051908101604052806005905b6103c9610459565b8152602001906001900390816103c15790505090565b826004810192821561041c579160200282015b8281111561041b5782518290600361040b929190610488565b50916020019190600101906103f2565b5b5090506104299190610536565b5090565b61045691905b8082111561045257600081816104499190610562565b50600401610433565b5090565b90565b610180604051908101604052806004905b6104726105a7565b81526020019060019003908161046a5790505090565b82600380016004900481019282156105255791602002820160005b838211156104ef57835183826101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555092602001926008016020816007010492830192600103026104a3565b80156105235782816101000a81549067ffffffffffffffff02191690556008016020816007010492830192600103026104ef565b505b50905061053291906105d9565b5090565b61055f91905b8082111561055b57600081816105529190610610565b5060010161053c565b5090565b90565b50600081816105719190610610565b50600101600081816105839190610610565b50600101600081816105959190610610565b5060010160006105a59190610610565b565b6060604051908101604052806003905b600067ffffffffffffffff168152602001906001900390816105b75790505090565b61060d91905b8082111561060957600081816101000a81549067ffffffffffffffff0219169055506001016105df565b5090565b90565b50600090555600a165627a7a7230582087e5a43f6965ab6ef7a4ff056ab80ed78fd8c15cff57715a1bf34ec76a93661c0029`, + `[{"constant":false,"inputs":[{"name":"arr","type":"uint64[3][4][5]"}],"name":"storeDeepUintArray","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"retrieveDeepArray","outputs":[{"name":"","type":"uint64[3][4][5]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"uint256"}],"name":"deepUint64Array","outputs":[{"name":"","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"}]`, + ` + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/crypto" + `, + ` + // Generate a new random account and a funded simulator + key, _ := crypto.GenerateKey() + auth := bind.NewKeyedTransactor(key) + sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000) + + //deploy the test contract + _, _, testContract, err := DeployDeeplyNestedArray(auth, sim) + if err != nil { + t.Fatalf("Failed to deploy test contract: %v", err) + } + + // Finish deploy. + sim.Commit() + + //Create coordinate-filled array, for testing purposes. + testArr := [5][4][3]uint64{} + for i := 0; i < 5; i++ { + testArr[i] = [4][3]uint64{} + for j := 0; j < 4; j++ { + testArr[i][j] = [3]uint64{} + for k := 0; k < 3; k++ { + //pack the coordinates, each array value will be unique, and can be validated easily. + testArr[i][j][k] = uint64(i) << 16 | uint64(j) << 8 | uint64(k) + } + } + } + + if _, err := testContract.StoreDeepUintArray(&bind.TransactOpts{ + From: auth.From, + Signer: auth.Signer, + }, testArr); err != nil { + t.Fatalf("Failed to store nested array in test contract: %v", err) + } + + sim.Commit() + + retrievedArr, err := testContract.RetrieveDeepArray(&bind.CallOpts{ + From: auth.From, + Pending: false, + }) + if err != nil { + t.Fatalf("Failed to retrieve nested array from test contract: %v", err) + } + + //quick check to see if contents were copied + // (See accounts/abi/unpack_test.go for more extensive testing) + if retrievedArr[4][3][2] != testArr[4][3][2] { + t.Fatalf("Retrieved value does not match expected value! got: %d, expected: %d. %v", retrievedArr[4][3][2], testArr[4][3][2], err) + } + `, + }, } // Tests that packages generated by the binder can be successfully compiled and @@ -747,15 +931,6 @@ func TestBindings(t *testing.T) { if !common.FileExist(gocmd) { t.Skip("go sdk not found for testing") } - // Skip the test if the go-ethereum sources are symlinked (https://github.com/golang/go/issues/14845) - linkTestCode := fmt.Sprintf("package linktest\nfunc CheckSymlinks(){\nfmt.Println(backends.NewSimulatedBackend(nil))\n}") - linkTestDeps, err := imports.Process(os.TempDir(), []byte(linkTestCode), nil) - if err != nil { - t.Fatalf("failed check for goimports symlink bug: %v", err) - } - if !strings.Contains(string(linkTestDeps), "go-ethereum") { - t.Skip("symlinked environment doesn't support bind (https://github.com/golang/go/issues/14845)") - } // Create a temporary workspace for the test suite ws, err := ioutil.TempDir("", "") if err != nil { @@ -778,12 +953,19 @@ func TestBindings(t *testing.T) { t.Fatalf("test %d: failed to write binding: %v", i, err) } // Generate the test file with the injected test code - code := fmt.Sprintf("package bindtest\nimport \"testing\"\nfunc Test%s(t *testing.T){\n%s\n}", tt.name, tt.tester) - blob, err := imports.Process("", []byte(code), nil) - if err != nil { - t.Fatalf("test %d: failed to generate tests: %v", i, err) - } - if err := ioutil.WriteFile(filepath.Join(pkg, strings.ToLower(tt.name)+"_test.go"), blob, 0600); err != nil { + code := fmt.Sprintf(` + package bindtest + + import ( + "testing" + %s + ) + + func Test%s(t *testing.T) { + %s + } + `, tt.imports, tt.name, tt.tester) + if err := ioutil.WriteFile(filepath.Join(pkg, strings.ToLower(tt.name)+"_test.go"), []byte(code), 0600); err != nil { t.Fatalf("test %d: failed to write tests: %v", i, err) } } diff --git a/accounts/abi/bind/template.go b/accounts/abi/bind/template.go index 7202ee67a1..02d0258e0c 100644 --- a/accounts/abi/bind/template.go +++ b/accounts/abi/bind/template.go @@ -64,6 +64,30 @@ const tmplSourceGo = ` package {{.Package}} +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 +) + {{range $contract := .Contracts}} // {{.Type}}ABI is the input ABI used to generate the binding from. const {{.Type}}ABI = "{{.InputABI}}" diff --git a/accounts/abi/bind/util_test.go b/accounts/abi/bind/util_test.go index 49e6dc813a..8f4092971f 100644 --- a/accounts/abi/bind/util_test.go +++ b/accounts/abi/bind/util_test.go @@ -53,9 +53,11 @@ var waitDeployedTests = map[string]struct { func TestWaitDeployed(t *testing.T) { for name, test := range waitDeployedTests { - backend := backends.NewSimulatedBackend(core.GenesisAlloc{ - crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(10000000000)}, - }) + backend := backends.NewSimulatedBackend( + core.GenesisAlloc{ + crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(10000000000)}, + }, 10000000, + ) // Create the transaction. tx := types.NewContractCreation(0, big.NewInt(0), test.gas, big.NewInt(1), common.FromHex(test.code)) diff --git a/accounts/abi/event.go b/accounts/abi/event.go index 595f169f3a..9392c1990c 100644 --- a/accounts/abi/event.go +++ b/accounts/abi/event.go @@ -33,15 +33,15 @@ type Event struct { Inputs Arguments } -func (event Event) String() string { - inputs := make([]string, len(event.Inputs)) - for i, input := range event.Inputs { - inputs[i] = fmt.Sprintf("%v %v", input.Name, input.Type) +func (e Event) String() string { + inputs := make([]string, len(e.Inputs)) + for i, input := range e.Inputs { + 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("event %v(%v)", event.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/accounts/abi/event_test.go b/accounts/abi/event_test.go index cca61e433d..e735cceb88 100644 --- a/accounts/abi/event_test.go +++ b/accounts/abi/event_test.go @@ -58,12 +58,28 @@ var jsonEventPledge = []byte(`{ "type": "event" }`) +var jsonEventMixedCase = []byte(`{ + "anonymous": false, + "inputs": [{ + "indexed": false, "name": "value", "type": "uint256" + }, { + "indexed": false, "name": "_value", "type": "uint256" + }, { + "indexed": false, "name": "Value", "type": "uint256" + }], + "name": "MixedCase", + "type": "event" + }`) + // 1000000 var transferData1 = "00000000000000000000000000000000000000000000000000000000000f4240" // "0x00Ce0d46d924CC8437c806721496599FC3FFA268", 2218516807680, "usd" var pledgeData1 = "00000000000000000000000000ce0d46d924cc8437c806721496599fc3ffa2680000000000000000000000000000000000000000000000000000020489e800007573640000000000000000000000000000000000000000000000000000000000" +// 1000000,2218516807680,1000001 +var mixedCaseData1 = "00000000000000000000000000000000000000000000000000000000000f42400000000000000000000000000000000000000000000000000000020489e8000000000000000000000000000000000000000000000000000000000000000f4241" + func TestEventId(t *testing.T) { var table = []struct { definition string @@ -71,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)")), }, }, } @@ -95,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"}]}]` @@ -121,6 +170,27 @@ func TestEventTupleUnpack(t *testing.T) { Value *big.Int } + type EventTransferWithTag struct { + // this is valid because `value` is not exportable, + // so value is only unmarshalled into `Value1`. + value *big.Int + Value1 *big.Int `abi:"value"` + } + + type BadEventTransferWithSameFieldAndTag struct { + Value *big.Int + Value1 *big.Int `abi:"value"` + } + + type BadEventTransferWithDuplicatedTag struct { + Value1 *big.Int `abi:"value"` + Value2 *big.Int `abi:"value"` + } + + type BadEventTransferWithEmptyTag struct { + Value *big.Int `abi:""` + } + type EventPledge struct { Who common.Address Wad *big.Int @@ -133,9 +203,16 @@ func TestEventTupleUnpack(t *testing.T) { Currency [3]byte } + type EventMixedCase struct { + Value1 *big.Int `abi:"value"` + Value2 *big.Int `abi:"_value"` + Value3 *big.Int `abi:"Value"` + } + bigint := new(big.Int) bigintExpected := big.NewInt(1000000) bigintExpected2 := big.NewInt(2218516807680) + bigintExpected3 := big.NewInt(1000001) addr := common.HexToAddress("0x00Ce0d46d924CC8437c806721496599FC3FFA268") var testCases = []struct { data string @@ -158,6 +235,34 @@ func TestEventTupleUnpack(t *testing.T) { jsonEventTransfer, "", "Can unpack ERC20 Transfer event into slice", + }, { + transferData1, + &EventTransferWithTag{}, + &EventTransferWithTag{Value1: bigintExpected}, + jsonEventTransfer, + "", + "Can unpack ERC20 Transfer event into structure with abi: tag", + }, { + transferData1, + &BadEventTransferWithDuplicatedTag{}, + &BadEventTransferWithDuplicatedTag{}, + jsonEventTransfer, + "struct: abi tag in 'Value2' already mapped", + "Can not unpack ERC20 Transfer event with duplicated abi tag", + }, { + transferData1, + &BadEventTransferWithSameFieldAndTag{}, + &BadEventTransferWithSameFieldAndTag{}, + jsonEventTransfer, + "abi: multiple variables maps to the same abi field 'value'", + "Can not unpack ERC20 Transfer event with a field and a tag mapping to the same abi variable", + }, { + transferData1, + &BadEventTransferWithEmptyTag{}, + &BadEventTransferWithEmptyTag{}, + jsonEventTransfer, + "struct: abi tag in 'Value' is empty", + "Can not unpack ERC20 Transfer event with an empty tag", }, { pledgeData1, &EventPledge{}, @@ -216,6 +321,13 @@ func TestEventTupleUnpack(t *testing.T) { jsonEventPledge, "abi: cannot unmarshal tuple into map[string]interface {}", "Can not unpack Pledge event into map", + }, { + mixedCaseData1, + &EventMixedCase{}, + &EventMixedCase{Value1: bigintExpected, Value2: bigintExpected2, Value3: bigintExpected3}, + jsonEventMixedCase, + "", + "Can unpack abi variables with mixed case", }} for _, tc := range testCases { @@ -227,7 +339,7 @@ func TestEventTupleUnpack(t *testing.T) { assert.Nil(err, "Should be able to unpack event data.") assert.Equal(tc.expected, tc.dest, tc.name) } else { - assert.EqualError(err, tc.error) + assert.EqualError(err, tc.error, tc.name) } }) } diff --git a/accounts/abi/method.go b/accounts/abi/method.go index f434ffdbef..2d8d3d6589 100644 --- a/accounts/abi/method.go +++ b/accounts/abi/method.go @@ -47,10 +47,8 @@ type Method struct { // Please note that "int" is substitute for its canonical representation "int256" func (method Method) Sig() string { types := make([]string, len(method.Inputs)) - i := 0 - for _, input := range method.Inputs { + for i, input := range method.Inputs { types[i] = input.Type.String() - i++ } return fmt.Sprintf("%v(%v)", method.Name, strings.Join(types, ",")) } @@ -58,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/accounts/abi/method_test.go b/accounts/abi/method_test.go new file mode 100644 index 0000000000..a98f1cd31f --- /dev/null +++ b/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/accounts/abi/numbers.go b/accounts/abi/numbers.go index 9ad99f90d2..4d706846da 100644 --- a/accounts/abi/numbers.go +++ b/accounts/abi/numbers.go @@ -25,35 +25,20 @@ import ( ) var ( - big_t = reflect.TypeOf(&big.Int{}) - derefbig_t = reflect.TypeOf(big.Int{}) - uint8_t = reflect.TypeOf(uint8(0)) - uint16_t = reflect.TypeOf(uint16(0)) - uint32_t = reflect.TypeOf(uint32(0)) - uint64_t = reflect.TypeOf(uint64(0)) - int_t = reflect.TypeOf(int(0)) - int8_t = reflect.TypeOf(int8(0)) - int16_t = reflect.TypeOf(int16(0)) - int32_t = reflect.TypeOf(int32(0)) - int64_t = reflect.TypeOf(int64(0)) - address_t = reflect.TypeOf(common.Address{}) - int_ts = reflect.TypeOf([]int(nil)) - int8_ts = reflect.TypeOf([]int8(nil)) - int16_ts = reflect.TypeOf([]int16(nil)) - int32_ts = reflect.TypeOf([]int32(nil)) - int64_ts = reflect.TypeOf([]int64(nil)) + bigT = reflect.TypeOf(&big.Int{}) + derefbigT = reflect.TypeOf(big.Int{}) + uint8T = reflect.TypeOf(uint8(0)) + uint16T = reflect.TypeOf(uint16(0)) + uint32T = reflect.TypeOf(uint32(0)) + uint64T = reflect.TypeOf(uint64(0)) + int8T = reflect.TypeOf(int8(0)) + int16T = reflect.TypeOf(int16(0)) + int32T = reflect.TypeOf(int32(0)) + int64T = reflect.TypeOf(int64(0)) + addressT = reflect.TypeOf(common.Address{}) ) // U256 converts a big Int into a 256bit EVM number. func U256(n *big.Int) []byte { return math.PaddedBigBytes(math.U256(n), 32) } - -// checks whether the given reflect value is signed. This also works for slices with a number type -func isSigned(v reflect.Value) bool { - switch v.Type() { - case int_ts, int8_ts, int16_ts, int32_ts, int64_ts, int_t, int8_t, int16_t, int32_t, int64_t: - return true - } - return false -} diff --git a/accounts/abi/numbers_test.go b/accounts/abi/numbers_test.go index b9ff5aef17..d25a5abcb5 100644 --- a/accounts/abi/numbers_test.go +++ b/accounts/abi/numbers_test.go @@ -19,7 +19,6 @@ package abi import ( "bytes" "math/big" - "reflect" "testing" ) @@ -32,13 +31,3 @@ func TestNumberTypes(t *testing.T) { t.Errorf("expected %x got %x", ubytes, unsigned) } } - -func TestSigned(t *testing.T) { - if isSigned(reflect.ValueOf(uint(10))) { - t.Error("signed") - } - - if !isSigned(reflect.ValueOf(int(10))) { - t.Error("not signed") - } -} diff --git a/accounts/abi/pack_test.go b/accounts/abi/pack_test.go index 36401ee677..10cd3a3962 100644 --- a/accounts/abi/pack_test.go +++ b/accounts/abi/pack_test.go @@ -1,4 +1,4 @@ -// Copyright 2015 The go-ethereum Authors +// Copyright 2017 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 @@ -29,309 +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) } } } @@ -401,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/accounts/abi/reflect.go b/accounts/abi/reflect.go index 7a9cdacd54..ccc6a65932 100644 --- a/accounts/abi/reflect.go +++ b/accounts/abi/reflect.go @@ -19,12 +19,13 @@ package abi import ( "fmt" "reflect" + "strings" ) // indirect recursively dereferences the value until it either gets the value // or finds a big.Int func indirect(v reflect.Value) reflect.Value { - if v.Kind() == reflect.Ptr && v.Elem().Type() != derefbig_t { + if v.Kind() == reflect.Ptr && v.Elem().Type() != derefbigT { return indirect(v.Elem()) } return v @@ -36,26 +37,26 @@ func reflectIntKindAndType(unsigned bool, size int) (reflect.Kind, reflect.Type) switch size { case 8: if unsigned { - return reflect.Uint8, uint8_t + return reflect.Uint8, uint8T } - return reflect.Int8, int8_t + return reflect.Int8, int8T case 16: if unsigned { - return reflect.Uint16, uint16_t + return reflect.Uint16, uint16T } - return reflect.Int16, int16_t + return reflect.Int16, int16T case 32: if unsigned { - return reflect.Uint32, uint32_t + return reflect.Uint32, uint32T } - return reflect.Int32, int32_t + return reflect.Int32, int32T case 64: if unsigned { - return reflect.Uint64, uint64_t + return reflect.Uint64, uint64T } - return reflect.Int64, int64_t + return reflect.Int64, int64T } - return reflect.Ptr, big_t + return reflect.Ptr, bigT } // mustArrayToBytesSlice creates a new byte slice with the exact same size as value @@ -70,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 { @@ -110,3 +125,94 @@ func requireUnpackKind(v reflect.Value, t reflect.Type, k reflect.Kind, } return nil } + +// 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 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. +// 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) + struct2abi := make(map[string]string) + + // first round ~~~ + for i := 0; i < typ.NumField(); i++ { + structFieldName := typ.Field(i).Name + + // skip private struct fields. + 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 _, arg := range argNames { + if arg == tagName { + if abi2struct[arg] != "" { + return nil, fmt.Errorf("struct: abi tag in '%s' already mapped", structFieldName) + } + // pair them + 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 _, argName := range argNames { + + structFieldName := ToCamelCase(argName) + + if structFieldName == "" { + return nil, fmt.Errorf("abi: purely underscored output cannot unpack to struct") + } + + // this abi has already been paired, skip it... unless there exists another, yet unassigned + // 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[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'", argName) + } + continue + } + + // return an error if this struct field has already been paired. + if struct2abi[structFieldName] != "" { + return nil, fmt.Errorf("abi: multiple outputs mapping to the same struct field '%s'", structFieldName) + } + + if value.FieldByName(structFieldName).IsValid() { + // pair them + 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] = argName + } + } + return abi2struct, nil +} diff --git a/accounts/abi/reflect_test.go b/accounts/abi/reflect_test.go new file mode 100644 index 0000000000..c425e6e54b --- /dev/null +++ b/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/accounts/abi/type.go b/accounts/abi/type.go index a1f13ffa29..26151dbd3e 100644 --- a/accounts/abi/type.go +++ b/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,13 +105,21 @@ 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") } return typ, err } // parse the type and size of the abi-type. - parsedType := typeRegex.FindAllStringSubmatch(t, -1)[0] + matches := typeRegex.FindAllStringSubmatch(t, -1) + if len(matches) == 0 { + return Type{}, fmt.Errorf("invalid type '%v'", t) + } + parsedType := matches[0] + // varSize is the size of the variable var varSize int if len(parsedType[3]) > 0 { @@ -135,7 +151,7 @@ func NewType(t string) (typ Type, err error) { typ.Type = reflect.TypeOf(bool(false)) case "address": typ.Kind = reflect.Array - typ.Type = address_t + typ.Type = addressT typ.Size = 20 typ.T = AddressTy case "string": @@ -153,6 +169,40 @@ 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, + }) + 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 @@ -173,28 +223,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 @@ -202,3 +306,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/accounts/abi/type_test.go b/accounts/abi/type_test.go index e55af12939..7ef47330dc 100644 --- a/accounts/abi/type_test.go +++ b/accounts/abi/type_test.go @@ -32,72 +32,75 @@ 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: int8_t, Size: 8, T: IntTy, stringKind: "int8"}}, - {"int16", Type{Kind: reflect.Int16, Type: int16_t, Size: 16, T: IntTy, stringKind: "int16"}}, - {"int32", Type{Kind: reflect.Int32, Type: int32_t, Size: 32, T: IntTy, stringKind: "int32"}}, - {"int64", Type{Kind: reflect.Int64, Type: int64_t, Size: 64, T: IntTy, stringKind: "int64"}}, - {"int256", Type{Kind: reflect.Ptr, Type: big_t, Size: 256, T: IntTy, stringKind: "int256"}}, - {"int8[]", Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([]int8{}), Elem: &Type{Kind: reflect.Int8, Type: int8_t, 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: int8_t, 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: int16_t, 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: int16_t, 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: int32_t, 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: int32_t, 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: int64_t, 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: int64_t, 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: big_t, 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: big_t, Size: 256, T: IntTy, stringKind: "int256"}, stringKind: "int256[2]"}}, - {"uint8", Type{Kind: reflect.Uint8, Type: uint8_t, Size: 8, T: UintTy, stringKind: "uint8"}}, - {"uint16", Type{Kind: reflect.Uint16, Type: uint16_t, Size: 16, T: UintTy, stringKind: "uint16"}}, - {"uint32", Type{Kind: reflect.Uint32, Type: uint32_t, Size: 32, T: UintTy, stringKind: "uint32"}}, - {"uint64", Type{Kind: reflect.Uint64, Type: uint64_t, Size: 64, T: UintTy, stringKind: "uint64"}}, - {"uint256", Type{Kind: reflect.Ptr, Type: big_t, Size: 256, T: UintTy, stringKind: "uint256"}}, - {"uint8[]", Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([]uint8{}), Elem: &Type{Kind: reflect.Uint8, Type: uint8_t, 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: uint8_t, 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: uint16_t, 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: uint16_t, 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: uint32_t, 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: uint32_t, 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: uint64_t, 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: uint64_t, 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: big_t, 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: big_t, 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: address_t, Size: 20, T: AddressTy, stringKind: "address"}}, - {"address[]", Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([]common.Address{}), Elem: &Type{Kind: reflect.Array, Type: address_t, 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: address_t, 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 }{}), stringKind: "(int64)", + TupleElems: []*Type{{Kind: reflect.Int64, T: IntTy, Type: reflect.TypeOf(int64(0)), Size: 64, stringKind: "int64"}}, TupleRawNames: []string{"a"}}}, } 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,151 +112,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{}, ""}, + {"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/accounts/abi/unpack.go b/accounts/abi/unpack.go index 80efb3f7ea..8406b09c80 100644 --- a/accounts/abi/unpack.go +++ b/accounts/abi/unpack.go @@ -1,4 +1,4 @@ -// Copyright 2015 The go-ethereum Authors +// Copyright 2017 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 @@ -25,8 +25,17 @@ import ( "github.com/ethereum/go-ethereum/common" ) +var ( + maxUint256 = big.NewInt(0).Add( + big.NewInt(0).Exp(big.NewInt(2), big.NewInt(256), nil), + big.NewInt(-1)) + maxInt256 = big.NewInt(0).Add( + big.NewInt(0).Exp(big.NewInt(2), big.NewInt(255), nil), + big.NewInt(-1)) +) + // reads the integer based on its kind -func readInteger(kind reflect.Kind, b []byte) interface{} { +func readInteger(typ byte, kind reflect.Kind, b []byte) interface{} { switch kind { case reflect.Uint8: return b[len(b)-1] @@ -45,7 +54,20 @@ func readInteger(kind reflect.Kind, b []byte) interface{} { case reflect.Int64: return int64(binary.BigEndian.Uint64(b[len(b)-8:])) default: - return new(big.Int).SetBytes(b) + // the only case lefts for integer is int256/uint256. + // big.SetBytes can't tell if a number is negative, positive on itself. + // On EVM, if the returned number > max int256, it is negative. + ret := new(big.Int).SetBytes(b) + if typ == UintTy { + return ret + } + + if ret.Cmp(maxInt256) > 0 { + ret.Add(maxUint256, big.NewInt(0).Neg(ret)) + ret.Add(ret, big.NewInt(1)) + ret.Neg(ret) + } + return ret } } @@ -95,13 +117,15 @@ func readFixedBytes(t Type, word []byte) (interface{}, error) { // iteratively unpack elements func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error) { + if size < 0 { + return nil, fmt.Errorf("cannot marshal input to array, size is negative (%d)", size) + } if start+32*size > len(output) { return nil, fmt.Errorf("abi: cannot marshal in to go array: offset %d would go over slice boundary (len=%d)", len(output), start+32*size) } // this value will become our slice or our array, depending on the type var refSlice reflect.Value - slice := output[start : start+size*32] if t.T == SliceTy { // declare our slice @@ -113,15 +137,16 @@ func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error) return nil, fmt.Errorf("abi: invalid type in array/slice unpacking stage") } - for i, j := start, 0; j*32 < len(slice); i, j = i+32, j+1 { - // this corrects the arrangement so that we get all the underlying array values - if t.Elem.T == ArrayTy && j != 0 { - i = start + t.Elem.Size*32*j - } + // Arrays have packed elements, resulting in longer unpack steps. + // Slices have just 32 bytes per element (pointing to the contents). + 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 } + // append the item to our reflect slice refSlice.Index(j).Set(reflect.ValueOf(inter)) } @@ -130,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) { @@ -138,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 } @@ -154,14 +209,28 @@ 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.Kind, returnOutput), nil + return readInteger(t.T, t.Kind, returnOutput), nil case BoolTy: return readBool(returnOutput) case AddressTy: @@ -169,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: @@ -181,16 +250,46 @@ func toGoType(index int, t Type, output []byte) (interface{}, error) { // interprets a 32 byte slice as an offset and then determines which indice to look to decode the type. func lengthPrefixPointsTo(index int, output []byte) (start int, length int, err error) { - offset := int(binary.BigEndian.Uint64(output[index+24 : index+32])) - if offset+32 > len(output) { - return 0, 0, fmt.Errorf("abi: cannot marshal in to go slice: offset %d would go over slice boundary (len=%d)", len(output), offset+32) - } - length = int(binary.BigEndian.Uint64(output[offset+24 : offset+32])) - if offset+32+length > len(output) { - return 0, 0, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), offset+32+length) - } - start = offset + 32 + bigOffsetEnd := big.NewInt(0).SetBytes(output[index : index+32]) + bigOffsetEnd.Add(bigOffsetEnd, common.Big32) + outputLength := big.NewInt(int64(len(output))) - //fmt.Printf("LENGTH PREFIX INFO: \nsize: %v\noffset: %v\nstart: %v\n", length, offset, start) + if bigOffsetEnd.Cmp(outputLength) > 0 { + return 0, 0, fmt.Errorf("abi: cannot marshal in to go slice: offset %v would go over slice boundary (len=%v)", bigOffsetEnd, outputLength) + } + + if bigOffsetEnd.BitLen() > 63 { + return 0, 0, fmt.Errorf("abi offset larger than int64: %v", bigOffsetEnd) + } + + offsetEnd := int(bigOffsetEnd.Uint64()) + lengthBig := big.NewInt(0).SetBytes(output[offsetEnd-32 : offsetEnd]) + + totalSize := big.NewInt(0) + totalSize.Add(totalSize, bigOffsetEnd) + totalSize.Add(totalSize, lengthBig) + if totalSize.BitLen() > 63 { + return 0, 0, fmt.Errorf("abi length larger than int64: %v", totalSize) + } + + if totalSize.Cmp(outputLength) > 0 { + return 0, 0, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %v require %v", outputLength, totalSize) + } + start = int(bigOffsetEnd.Uint64()) + 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/accounts/abi/unpack_test.go b/accounts/abi/unpack_test.go index 4d7fe638c4..fa8a69d05c 100644 --- a/accounts/abi/unpack_test.go +++ b/accounts/abi/unpack_test.go @@ -1,4 +1,4 @@ -// Copyright 2015 The go-ethereum Authors +// Copyright 2017 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 @@ -56,6 +56,23 @@ var unpackTests = []unpackTest{ enc: "0000000000000000000000000000000000000000000000000000000000000001", want: true, }, + { + def: `[{ "type": "bool" }]`, + enc: "0000000000000000000000000000000000000000000000000000000000000000", + want: false, + }, + { + def: `[{ "type": "bool" }]`, + enc: "0000000000000000000000000000000000000000000000000001000000000001", + want: false, + err: "abi: improperly encoded boolean value", + }, + { + def: `[{ "type": "bool" }]`, + enc: "0000000000000000000000000000000000000000000000000000000000000003", + want: false, + err: "abi: improperly encoded boolean value", + }, { def: `[{"type": "uint32"}]`, enc: "0000000000000000000000000000000000000000000000000000000000000001", @@ -100,6 +117,11 @@ var unpackTests = []unpackTest{ enc: "0000000000000000000000000000000000000000000000000000000000000001", want: big.NewInt(1), }, + { + def: `[{"type": "int256"}]`, + enc: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + want: big.NewInt(-1), + }, { def: `[{"type": "address"}]`, enc: "0000000000000000000000000100000000000000000000000000000000000000", @@ -130,7 +152,7 @@ var unpackTests = []unpackTest{ { def: `[{"type": "bytes32"}]`, enc: "0100000000000000000000000000000000000000000000000000000000000000", - want: common.HexToHash("0100000000000000000000000000000000000000000000000000000000000000"), + want: [32]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}, }, { def: `[{"type": "function"}]`, @@ -151,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", @@ -161,7 +188,7 @@ var unpackTests = []unpackTest{ }, { def: `[{"type": "uint8[][2]"}]`, - enc: "000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001", + enc: "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001", want: [2][]uint8{{1}, {1}}, }, { @@ -169,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", @@ -189,6 +221,11 @@ var unpackTests = []unpackTest{ enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", want: [2]uint32{1, 2}, }, + { + def: `[{"type": "uint32[2][3][4]"}]`, + enc: "000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001300000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000015000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000018", + want: [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}}}, + }, { def: `[{"type": "uint64[]"}]`, enc: "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", @@ -209,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", @@ -268,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", @@ -332,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 @@ -359,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 { @@ -386,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}, @@ -435,6 +603,108 @@ 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 + // after such nested array argument should be read with the correct offset, + // so that it does not read content from the previous array argument. + const definition = `[{"name" : "multi", "outputs": [{"type": "uint64[3][2][4]"}, {"type": "uint64"}]}]` + abi, err := JSON(strings.NewReader(definition)) + if err != nil { + t.Fatal(err) + } + buff := new(bytes.Buffer) + // construct the test array, each 3 char element is joined with 61 '0' chars, + // to from the ((3 + 61) * 0.5) = 32 byte elements in the array. + buff.Write(common.Hex2Bytes(strings.Join([]string{ + "", //empty, to apply the 61-char separator to the first element as well. + "111", "112", "113", "121", "122", "123", + "211", "212", "213", "221", "222", "223", + "311", "312", "313", "321", "322", "323", + "411", "412", "413", "421", "422", "423", + }, "0000000000000000000000000000000000000000000000000000000000000"))) + buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000009876")) + + ret1, ret1Exp := new([4][2][3]uint64), [4][2][3]uint64{ + {{0x111, 0x112, 0x113}, {0x121, 0x122, 0x123}}, + {{0x211, 0x212, 0x213}, {0x221, 0x222, 0x223}}, + {{0x311, 0x312, 0x313}, {0x321, 0x322, 0x323}}, + {{0x411, 0x412, 0x413}, {0x421, 0x422, 0x423}}, + } + ret2, ret2Exp := new(uint64), uint64(0x9876) + if err := abi.Unpack(&[]interface{}{ret1, ret2}, "multi", buff.Bytes()); err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(*ret1, ret1Exp) { + t.Error("array result", *ret1, "!= Expected", ret1Exp) + } + if *ret2 != ret2Exp { + t.Error("int result", *ret2, "!= Expected", ret2Exp) + } +} + func TestUnmarshal(t *testing.T) { const definition = `[ { "name" : "int", "constant" : false, "outputs": [ { "type": "uint256" } ] }, @@ -683,3 +953,175 @@ func TestUnmarshal(t *testing.T) { t.Fatal("expected error:", err) } } + +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{ + { + def: `[{"type": "uint8[]"}]`, + enc: "0000000000000000000000000000000000000000000000000000000000000020" + // offset + "0000000000000000000000000000000000000000000000000000000000000003" + // num elems + "0000000000000000000000000000000000000000000000000000000000000001" + // elem 1 + "0000000000000000000000000000000000000000000000000000000000000002", // elem 2 + }, + { // Length larger than 64 bits + def: `[{"type": "uint8[]"}]`, + enc: "0000000000000000000000000000000000000000000000000000000000000020" + // offset + "00ffffffffffffffffffffffffffffffffffffffffffffff0000000000000002" + // num elems + "0000000000000000000000000000000000000000000000000000000000000001" + // elem 1 + "0000000000000000000000000000000000000000000000000000000000000002", // elem 2 + }, + { // Offset very large (over 64 bits) + def: `[{"type": "uint8[]"}]`, + enc: "00ffffffffffffffffffffffffffffffffffffffffffffff0000000000000020" + // offset + "0000000000000000000000000000000000000000000000000000000000000002" + // num elems + "0000000000000000000000000000000000000000000000000000000000000001" + // elem 1 + "0000000000000000000000000000000000000000000000000000000000000002", // elem 2 + }, + { // Offset very large (below 64 bits) + def: `[{"type": "uint8[]"}]`, + enc: "0000000000000000000000000000000000000000000000007ffffffffff00020" + // offset + "0000000000000000000000000000000000000000000000000000000000000002" + // num elems + "0000000000000000000000000000000000000000000000000000000000000001" + // elem 1 + "0000000000000000000000000000000000000000000000000000000000000002", // elem 2 + }, + { // Offset negative (as 64 bit) + def: `[{"type": "uint8[]"}]`, + enc: "000000000000000000000000000000000000000000000000f000000000000020" + // offset + "0000000000000000000000000000000000000000000000000000000000000002" + // num elems + "0000000000000000000000000000000000000000000000000000000000000001" + // elem 1 + "0000000000000000000000000000000000000000000000000000000000000002", // elem 2 + }, + + { // Negative length + def: `[{"type": "uint8[]"}]`, + enc: "0000000000000000000000000000000000000000000000000000000000000020" + // offset + "000000000000000000000000000000000000000000000000f000000000000002" + // num elems + "0000000000000000000000000000000000000000000000000000000000000001" + // elem 1 + "0000000000000000000000000000000000000000000000000000000000000002", // elem 2 + }, + { // Very large length + def: `[{"type": "uint8[]"}]`, + enc: "0000000000000000000000000000000000000000000000000000000000000020" + // offset + "0000000000000000000000000000000000000000000000007fffffffff000002" + // num elems + "0000000000000000000000000000000000000000000000000000000000000001" + // elem 1 + "0000000000000000000000000000000000000000000000000000000000000002", // elem 2 + }, + } + for i, test := range oomTests { + def := fmt.Sprintf(`[{ "name" : "method", "outputs": %s}]`, test.def) + abi, err := JSON(strings.NewReader(def)) + if err != nil { + t.Fatalf("invalid ABI definition %s: %v", def, err) + } + encb, err := hex.DecodeString(test.enc) + if err != nil { + t.Fatalf("invalid hex: %s" + test.enc) + } + _, err = abi.Methods["method"].Outputs.UnpackValues(encb) + if err == nil { + t.Fatalf("Expected error on malicious input, test %d", i) + } + } +} diff --git a/accounts/accounts.go b/accounts/accounts.go index 76951e1a42..a52aa425c8 100644 --- a/accounts/accounts.go +++ b/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. // @@ -106,25 +136,14 @@ type Wallet interface { // 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), + // a password to decrypt the account, or a PIN code to 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 SignTxWithPassphrase, or by other means (e.g. unlock // 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/accounts/accounts_test.go b/accounts/accounts_test.go new file mode 100644 index 0000000000..a49e3954ee --- /dev/null +++ b/accounts/accounts_test.go @@ -0,0 +1,32 @@ +// 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 accounts + +import ( + "bytes" + "testing" + + "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/accounts/external/backend.go b/accounts/external/backend.go new file mode 100644 index 0000000000..21a313b669 --- /dev/null +++ b/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/accounts/hd.go b/accounts/hd.go index 277f688e48..6ed6318078 100644 --- a/accounts/hd.go +++ b/accounts/hd.go @@ -30,8 +30,8 @@ import ( var DefaultRootDerivationPath = DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0} // DefaultBaseDerivationPath is the base path from which custom derivation endpoints -// are incremented. As such, the first account will be at m/44'/60'/0'/0, the second -// at m/44'/60'/0'/1, etc. +// are incremented. As such, the first account will be at m/44'/60'/0'/0/0, the second +// at m/44'/60'/0'/0/1, etc. var DefaultBaseDerivationPath = DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0, 0} // DefaultLedgerBaseDerivationPath is the base path from which custom derivation endpoints diff --git a/accounts/keystore/account_cache.go b/accounts/keystore/account_cache.go index 71f698ece7..8f660e282f 100644 --- a/accounts/keystore/account_cache.go +++ b/accounts/keystore/account_cache.go @@ -27,10 +27,10 @@ import ( "sync" "time" + mapset "github.com/deckarep/golang-set" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" - "gopkg.in/fatih/set.v0" ) // Minimum amount of time between cache reloads. This limit applies if the platform does @@ -79,7 +79,7 @@ func newAccountCache(keydir string) (*accountCache, chan struct{}) { keydir: keydir, byAddr: make(map[common.Address][]accounts.Account), notify: make(chan struct{}, 1), - fileC: fileCache{all: set.NewNonTS()}, + fileC: fileCache{all: mapset.NewThreadUnsafeSet()}, } ac.watcher = newWatcher(ac) return ac, ac.notify @@ -237,7 +237,7 @@ func (ac *accountCache) scanAccounts() error { log.Debug("Failed to reload keystore contents", "err", err) return err } - if creates.Size() == 0 && deletes.Size() == 0 && updates.Size() == 0 { + if creates.Cardinality() == 0 && deletes.Cardinality() == 0 && updates.Cardinality() == 0 { return nil } // Create a helper method to scan the contents of the key files @@ -265,22 +265,25 @@ 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 } // Process all the file diffs start := time.Now() - for _, p := range creates.List() { + for _, p := range creates.ToSlice() { if a := readAccount(p.(string)); a != nil { ac.add(*a) } } - for _, p := range deletes.List() { + for _, p := range deletes.ToSlice() { ac.deleteByFile(p.(string)) } - for _, p := range updates.List() { + for _, p := range updates.ToSlice() { path := p.(string) ac.deleteByFile(path) if a := readAccount(path); a != nil { diff --git a/accounts/keystore/file_cache.go b/accounts/keystore/file_cache.go index c91b7b7b61..73ff6ae9ee 100644 --- a/accounts/keystore/file_cache.go +++ b/accounts/keystore/file_cache.go @@ -24,20 +24,20 @@ import ( "sync" "time" + mapset "github.com/deckarep/golang-set" "github.com/ethereum/go-ethereum/log" - set "gopkg.in/fatih/set.v0" ) // fileCache is a cache of files seen during scan of keystore. type fileCache struct { - all *set.SetNonTS // Set of all files from the keystore folder - lastMod time.Time // Last time instance when a file was modified + all mapset.Set // Set of all files from the keystore folder + lastMod time.Time // Last time instance when a file was modified mu sync.RWMutex } // scan performs a new scan on the given directory, compares against the already // cached filenames, and returns file sets: creates, deletes, updates. -func (fc *fileCache) scan(keyDir string) (set.Interface, set.Interface, set.Interface, error) { +func (fc *fileCache) scan(keyDir string) (mapset.Set, mapset.Set, mapset.Set, error) { t0 := time.Now() // List all the failes from the keystore folder @@ -51,14 +51,14 @@ func (fc *fileCache) scan(keyDir string) (set.Interface, set.Interface, set.Inte defer fc.mu.Unlock() // Iterate all the files and gather their metadata - all := set.NewNonTS() - mods := set.NewNonTS() + all := mapset.NewThreadUnsafeSet() + mods := mapset.NewThreadUnsafeSet() var newLastMod time.Time for _, fi := range files { - // Skip any non-key files from the folder path := filepath.Join(keyDir, fi.Name()) - if skipKeyFile(fi) { + // Skip any non-key files from the folder + if nonKeyFile(fi) { log.Trace("Ignoring file on account scan", "path", path) continue } @@ -76,9 +76,9 @@ func (fc *fileCache) scan(keyDir string) (set.Interface, set.Interface, set.Inte t2 := time.Now() // Update the tracked files and return the three sets - deletes := set.Difference(fc.all, all) // Deletes = previous - current - creates := set.Difference(all, fc.all) // Creates = current - previous - updates := set.Difference(mods, creates) // Updates = modified - creates + deletes := fc.all.Difference(all) // Deletes = previous - current + creates := all.Difference(fc.all) // Creates = current - previous + updates := mods.Difference(creates) // Updates = modified - creates fc.all, fc.lastMod = all, newLastMod t3 := time.Now() @@ -88,8 +88,8 @@ func (fc *fileCache) scan(keyDir string) (set.Interface, set.Interface, set.Inte return creates, deletes, updates, nil } -// skipKeyFile ignores editor backups, hidden files and folders/symlinks. -func skipKeyFile(fi os.FileInfo) bool { +// nonKeyFile ignores editor backups, hidden files and folders/symlinks. +func nonKeyFile(fi os.FileInfo) bool { // Skip editor backups and UNIX-style hidden files. if strings.HasSuffix(fi.Name(), "~") || strings.HasPrefix(fi.Name(), ".") { return true diff --git a/accounts/keystore/key.go b/accounts/keystore/key.go index 211fa863d7..84d8df0c5a 100644 --- a/accounts/keystore/key.go +++ b/accounts/keystore/key.go @@ -66,19 +66,19 @@ type plainKeyJSON struct { type encryptedKeyJSONV3 struct { Address string `json:"address"` - Crypto cryptoJSON `json:"crypto"` + Crypto CryptoJSON `json:"crypto"` Id string `json:"id"` Version int `json:"version"` } type encryptedKeyJSONV1 struct { Address string `json:"address"` - Crypto cryptoJSON `json:"crypto"` + Crypto CryptoJSON `json:"crypto"` Id string `json:"id"` Version string `json:"version"` } -type cryptoJSON struct { +type CryptoJSON struct { Cipher string `json:"cipher"` CipherText string `json:"ciphertext"` CipherParams cipherparamsJSON `json:"cipherparams"` @@ -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 @@ -179,26 +182,34 @@ func storeNewKey(ks keyStore, rand io.Reader, auth string) (*Key, accounts.Accou return key, a, err } -func writeKeyFile(file string, content []byte) error { +func writeTemporaryKeyFile(file string, content []byte) (string, error) { // Create the keystore directory with appropriate permissions // in case it is not present yet. const dirPerm = 0700 if err := os.MkdirAll(filepath.Dir(file), dirPerm); err != nil { - return err + return "", err } // Atomic write: create a temporary hidden file first // then move it into place. TempFile assigns mode 0600. f, err := ioutil.TempFile(filepath.Dir(file), "."+filepath.Base(file)+".tmp") if err != nil { - return err + return "", err } if _, err := f.Write(content); err != nil { f.Close() os.Remove(f.Name()) - return err + return "", err } f.Close() - return os.Rename(f.Name(), file) + return f.Name(), nil +} + +func writeKeyFile(file string, content []byte) error { + name, err := writeTemporaryKeyFile(file, content) + if err != nil { + return err + } + return os.Rename(name, file) } // keyFileName implements the naming convention for keyfiles: @@ -216,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/accounts/keystore/keystore.go b/accounts/keystore/keystore.go index 80ccd37419..2918047ccd 100644 --- a/accounts/keystore/keystore.go +++ b/accounts/keystore/keystore.go @@ -50,7 +50,7 @@ var ( var KeyStoreType = reflect.TypeOf(&KeyStore{}) // KeyStoreScheme is the protocol scheme prefixing account and wallet URLs. -var KeyStoreScheme = "keystore" +const KeyStoreScheme = "keystore" // Maximum time between wallet refreshes (if filesystem notifications don't work). const walletRefreshCycle = 3 * time.Second @@ -78,7 +78,7 @@ type unlocked struct { // NewKeyStore creates a keystore for the given directory. func NewKeyStore(keydir string, scryptN, scryptP int) *KeyStore { keydir, _ = filepath.Abs(keydir) - ks := &KeyStore{storage: &keyStorePassphrase{keydir, scryptN, scryptP}} + ks := &KeyStore{storage: &keyStorePassphrase{keydir, scryptN, scryptP, false}} ks.init(keydir) return ks } diff --git a/accounts/keystore/keystore_passphrase.go b/accounts/keystore/passphrase.go similarity index 76% rename from accounts/keystore/keystore_passphrase.go rename to accounts/keystore/passphrase.go index eaec39f7df..a0b6cf5385 100644 --- a/accounts/keystore/keystore_passphrase.go +++ b/accounts/keystore/passphrase.go @@ -28,18 +28,19 @@ package keystore import ( "bytes" "crypto/aes" - crand "crypto/rand" + "crypto/rand" "crypto/sha256" "encoding/hex" "encoding/json" "fmt" + "io" "io/ioutil" + "os" "path/filepath" "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/randentropy" "github.com/pborman/uuid" "golang.org/x/crypto/pbkdf2" "golang.org/x/crypto/scrypt" @@ -72,6 +73,10 @@ type keyStorePassphrase struct { keysDirPath string scryptN int scryptP int + // skipKeyFileVerification disables the security-feature which does + // reads and decrypts any newly created keyfiles. This should be 'false' in all + // cases except tests -- setting this to 'true' is not recommended. + skipKeyFileVerification bool } func (ks keyStorePassphrase) GetKey(addr common.Address, filename, auth string) (*Key, error) { @@ -93,7 +98,7 @@ func (ks keyStorePassphrase) GetKey(addr common.Address, filename, auth string) // StoreKey generates a key, encrypts with 'auth' and stores in the given directory func StoreKey(dir, auth string, scryptN, scryptP int) (common.Address, error) { - _, a, err := storeNewKey(&keyStorePassphrase{dir, scryptN, scryptP}, crand.Reader, auth) + _, a, err := storeNewKey(&keyStorePassphrase{dir, scryptN, scryptP, false}, rand.Reader, auth) return a.Address, err } @@ -102,33 +107,54 @@ func (ks keyStorePassphrase) StoreKey(filename string, key *Key, auth string) er if err != nil { return err } - return writeKeyFile(filename, keyjson) + // Write into temporary file + tmpName, err := writeTemporaryKeyFile(filename, keyjson) + if err != nil { + return err + } + if !ks.skipKeyFileVerification { + // Verify that we can decrypt the file with the given password. + _, err = ks.GetKey(key.Address, tmpName, auth) + if err != nil { + msg := "An error was encountered when saving and verifying the keystore file. \n" + + "This indicates that the keystore is corrupted. \n" + + "The corrupted file is stored at \n%v\n" + + "Please file a ticket at:\n\n" + + "https://github.com/ethereum/go-ethereum/issues." + + "The error was : %s" + return fmt.Errorf(msg, tmpName, err) + } + } + return os.Rename(tmpName, filename) } func (ks keyStorePassphrase) JoinPath(filename string) string { if filepath.IsAbs(filename) { return filename - } else { - return filepath.Join(ks.keysDirPath, filename) } + return filepath.Join(ks.keysDirPath, filename) } -// EncryptKey encrypts a key using the specified scrypt parameters into a json -// blob that can be decrypted later on. -func EncryptKey(key *Key, auth string, scryptN, scryptP int) ([]byte, error) { - authArray := []byte(auth) - salt := randentropy.GetEntropyCSPRNG(32) - derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptR, scryptP, scryptDKLen) +// Encryptdata encrypts the data given as 'data' with the password 'auth'. +func EncryptDataV3(data, auth []byte, scryptN, scryptP int) (CryptoJSON, error) { + + salt := make([]byte, 32) + if _, err := io.ReadFull(rand.Reader, salt); err != nil { + panic("reading from crypto/rand failed: " + err.Error()) + } + derivedKey, err := scrypt.Key(auth, salt, scryptN, scryptR, scryptP, scryptDKLen) if err != nil { - return nil, err + return CryptoJSON{}, err } encryptKey := derivedKey[:16] - keyBytes := math.PaddedBigBytes(key.PrivateKey.D, 32) - iv := randentropy.GetEntropyCSPRNG(aes.BlockSize) // 16 - cipherText, err := aesCTRXOR(encryptKey, keyBytes, iv) + iv := make([]byte, aes.BlockSize) // 16 + if _, err := io.ReadFull(rand.Reader, iv); err != nil { + panic("reading from crypto/rand failed: " + err.Error()) + } + cipherText, err := aesCTRXOR(encryptKey, data, iv) if err != nil { - return nil, err + return CryptoJSON{}, err } mac := crypto.Keccak256(derivedKey[16:32], cipherText) @@ -138,12 +164,11 @@ func EncryptKey(key *Key, auth string, scryptN, scryptP int) ([]byte, error) { scryptParamsJSON["p"] = scryptP scryptParamsJSON["dklen"] = scryptDKLen scryptParamsJSON["salt"] = hex.EncodeToString(salt) - cipherParamsJSON := cipherparamsJSON{ IV: hex.EncodeToString(iv), } - cryptoStruct := cryptoJSON{ + cryptoStruct := CryptoJSON{ Cipher: "aes-128-ctr", CipherText: hex.EncodeToString(cipherText), CipherParams: cipherParamsJSON, @@ -151,6 +176,17 @@ func EncryptKey(key *Key, auth string, scryptN, scryptP int) ([]byte, error) { KDFParams: scryptParamsJSON, MAC: hex.EncodeToString(mac), } + return cryptoStruct, nil +} + +// EncryptKey encrypts a key using the specified scrypt parameters into a json +// blob that can be decrypted later on. +func EncryptKey(key *Key, auth string, scryptN, scryptP int) ([]byte, error) { + keyBytes := math.PaddedBigBytes(key.PrivateKey.D, 32) + cryptoStruct, err := EncryptDataV3(keyBytes, []byte(auth), scryptN, scryptP) + if err != nil { + return nil, err + } encryptedKeyJSONV3 := encryptedKeyJSONV3{ hex.EncodeToString(key.Address[:]), cryptoStruct, @@ -198,42 +234,48 @@ func DecryptKey(keyjson []byte, auth string) (*Key, error) { }, nil } -func decryptKeyV3(keyProtected *encryptedKeyJSONV3, auth string) (keyBytes []byte, keyId []byte, err error) { - if keyProtected.Version != version { - return nil, nil, fmt.Errorf("Version not supported: %v", keyProtected.Version) +func DecryptDataV3(cryptoJson CryptoJSON, auth string) ([]byte, error) { + if cryptoJson.Cipher != "aes-128-ctr" { + return nil, fmt.Errorf("Cipher not supported: %v", cryptoJson.Cipher) } - - if keyProtected.Crypto.Cipher != "aes-128-ctr" { - return nil, nil, fmt.Errorf("Cipher not supported: %v", keyProtected.Crypto.Cipher) - } - - keyId = uuid.Parse(keyProtected.Id) - mac, err := hex.DecodeString(keyProtected.Crypto.MAC) + mac, err := hex.DecodeString(cryptoJson.MAC) if err != nil { - return nil, nil, err + return nil, err } - iv, err := hex.DecodeString(keyProtected.Crypto.CipherParams.IV) + iv, err := hex.DecodeString(cryptoJson.CipherParams.IV) if err != nil { - return nil, nil, err + return nil, err } - cipherText, err := hex.DecodeString(keyProtected.Crypto.CipherText) + cipherText, err := hex.DecodeString(cryptoJson.CipherText) if err != nil { - return nil, nil, err + return nil, err } - derivedKey, err := getKDFKey(keyProtected.Crypto, auth) + derivedKey, err := getKDFKey(cryptoJson, auth) if err != nil { - return nil, nil, err + return nil, err } calculatedMAC := crypto.Keccak256(derivedKey[16:32], cipherText) if !bytes.Equal(calculatedMAC, mac) { - return nil, nil, ErrDecrypt + return nil, ErrDecrypt } plainText, err := aesCTRXOR(derivedKey[:16], cipherText, iv) + if err != nil { + return nil, err + } + return plainText, err +} + +func decryptKeyV3(keyProtected *encryptedKeyJSONV3, auth string) (keyBytes []byte, keyId []byte, err error) { + if keyProtected.Version != version { + return nil, nil, fmt.Errorf("Version not supported: %v", keyProtected.Version) + } + keyId = uuid.Parse(keyProtected.Id) + plainText, err := DecryptDataV3(keyProtected.Crypto, auth) if err != nil { return nil, nil, err } @@ -274,7 +316,7 @@ func decryptKeyV1(keyProtected *encryptedKeyJSONV1, auth string) (keyBytes []byt return plainText, keyId, err } -func getKDFKey(cryptoJSON cryptoJSON, auth string) ([]byte, error) { +func getKDFKey(cryptoJSON CryptoJSON, auth string) ([]byte, error) { authArray := []byte(auth) salt, err := hex.DecodeString(cryptoJSON.KDFParams["salt"].(string)) if err != nil { diff --git a/accounts/keystore/keystore_passphrase_test.go b/accounts/keystore/passphrase_test.go similarity index 100% rename from accounts/keystore/keystore_passphrase_test.go rename to accounts/keystore/passphrase_test.go diff --git a/accounts/keystore/keystore_plain.go b/accounts/keystore/plain.go similarity index 96% rename from accounts/keystore/keystore_plain.go rename to accounts/keystore/plain.go index b490ca72b8..f62a133ce1 100644 --- a/accounts/keystore/keystore_plain.go +++ b/accounts/keystore/plain.go @@ -56,7 +56,6 @@ func (ks keyStorePlain) StoreKey(filename string, key *Key, auth string) error { func (ks keyStorePlain) JoinPath(filename string) string { if filepath.IsAbs(filename) { return filename - } else { - return filepath.Join(ks.keysDirPath, filename) } + return filepath.Join(ks.keysDirPath, filename) } diff --git a/accounts/keystore/keystore_plain_test.go b/accounts/keystore/plain_test.go similarity index 99% rename from accounts/keystore/keystore_plain_test.go rename to accounts/keystore/plain_test.go index a1c3bc4b6c..32852a0add 100644 --- a/accounts/keystore/keystore_plain_test.go +++ b/accounts/keystore/plain_test.go @@ -37,7 +37,7 @@ func tmpKeyStoreIface(t *testing.T, encrypted bool) (dir string, ks keyStore) { t.Fatal(err) } if encrypted { - ks = &keyStorePassphrase{d, veryLightScryptN, veryLightScryptP} + ks = &keyStorePassphrase{d, veryLightScryptN, veryLightScryptP, true} } else { ks = &keyStorePlain{d} } @@ -191,7 +191,7 @@ func TestV1_1(t *testing.T) { func TestV1_2(t *testing.T) { t.Parallel() - ks := &keyStorePassphrase{"testdata/v1", LightScryptN, LightScryptP} + ks := &keyStorePassphrase{"testdata/v1", LightScryptN, LightScryptP, true} addr := common.HexToAddress("cb61d5a9c4896fb9658090b597ef0e7be6f7b67e") file := "testdata/v1/cb61d5a9c4896fb9658090b597ef0e7be6f7b67e/cb61d5a9c4896fb9658090b597ef0e7be6f7b67e" k, err := ks.GetKey(addr, file, "g") diff --git a/accounts/keystore/presale.go b/accounts/keystore/presale.go index 1554294e14..03055245f5 100644 --- a/accounts/keystore/presale.go +++ b/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/accounts/keystore/keystore_wallet.go b/accounts/keystore/wallet.go similarity index 77% rename from accounts/keystore/keystore_wallet.go rename to accounts/keystore/wallet.go index 758fdfe364..1b36b6dff5 100644 --- a/accounts/keystore/keystore_wallet.go +++ b/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/accounts/url.go b/accounts/url.go index 47f9d8ee4b..a5add10216 100644 --- a/accounts/url.go +++ b/accounts/url.go @@ -74,6 +74,22 @@ func (u URL) MarshalJSON() ([]byte, error) { return json.Marshal(u.String()) } +// UnmarshalJSON parses url. +func (u *URL) UnmarshalJSON(input []byte) error { + var textURL string + err := json.Unmarshal(input, &textURL) + if err != nil { + return err + } + url, err := parseURL(textURL) + if err != nil { + return err + } + u.Scheme = url.Scheme + u.Path = url.Path + return nil +} + // Cmp compares x and y and returns: // // -1 if x < y diff --git a/accounts/url_test.go b/accounts/url_test.go new file mode 100644 index 0000000000..8027728719 --- /dev/null +++ b/accounts/url_test.go @@ -0,0 +1,96 @@ +// Copyright 2017 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 accounts + +import ( + "testing" +) + +func TestURLParsing(t *testing.T) { + url, err := parseURL("https://ethereum.org") + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if url.Scheme != "https" { + t.Errorf("expected: %v, got: %v", "https", url.Scheme) + } + if url.Path != "ethereum.org" { + t.Errorf("expected: %v, got: %v", "ethereum.org", url.Path) + } + + _, err = parseURL("ethereum.org") + if err == nil { + t.Error("expected err, got: nil") + } +} + +func TestURLString(t *testing.T) { + url := URL{Scheme: "https", Path: "ethereum.org"} + if url.String() != "https://ethereum.org" { + t.Errorf("expected: %v, got: %v", "https://ethereum.org", url.String()) + } + + url = URL{Scheme: "", Path: "ethereum.org"} + if url.String() != "ethereum.org" { + t.Errorf("expected: %v, got: %v", "ethereum.org", url.String()) + } +} + +func TestURLMarshalJSON(t *testing.T) { + url := URL{Scheme: "https", Path: "ethereum.org"} + json, err := url.MarshalJSON() + if err != nil { + t.Errorf("unexpcted error: %v", err) + } + if string(json) != "\"https://ethereum.org\"" { + t.Errorf("expected: %v, got: %v", "\"https://ethereum.org\"", string(json)) + } +} + +func TestURLUnmarshalJSON(t *testing.T) { + url := &URL{} + err := url.UnmarshalJSON([]byte("\"https://ethereum.org\"")) + if err != nil { + t.Errorf("unexpcted error: %v", err) + } + if url.Scheme != "https" { + t.Errorf("expected: %v, got: %v", "https", url.Scheme) + } + if url.Path != "ethereum.org" { + t.Errorf("expected: %v, got: %v", "https", url.Path) + } +} + +func TestURLComparison(t *testing.T) { + tests := []struct { + urlA URL + urlB URL + expect int + }{ + {URL{"https", "ethereum.org"}, URL{"https", "ethereum.org"}, 0}, + {URL{"http", "ethereum.org"}, URL{"https", "ethereum.org"}, -1}, + {URL{"https", "ethereum.org/a"}, URL{"https", "ethereum.org"}, 1}, + {URL{"https", "abc.org"}, URL{"https", "ethereum.org"}, -1}, + } + + for i, tt := range tests { + result := tt.urlA.Cmp(tt.urlB) + if result != tt.expect { + t.Errorf("test %d: cmp mismatch: expected: %d, got: %d", i, tt.expect, result) + } + } +} diff --git a/accounts/usbwallet/hub.go b/accounts/usbwallet/hub.go index 61fc98ccc8..640320bc91 100644 --- a/accounts/usbwallet/hub.go +++ b/accounts/usbwallet/hub.go @@ -127,7 +127,7 @@ func (hub *Hub) refreshWallets() { // breaking the Ledger protocol if that is waiting for user confirmation. This // is a bug acknowledged at Ledger, but it won't be fixed on old devices so we // need to prevent concurrent comms ourselves. The more elegant solution would - // be to ditch enumeration in favor of hutplug events, but that don't work yet + // be to ditch enumeration in favor of hotplug events, but that don't work yet // on Windows so if we need to hack it anyway, this is more elegant for now. hub.commsLock.Lock() if hub.commsPend > 0 { // A confirmation is pending, don't refresh diff --git a/accounts/usbwallet/ledger.go b/accounts/usbwallet/ledger.go index f5def61d23..c30903b5b7 100644 --- a/accounts/usbwallet/ledger.go +++ b/accounts/usbwallet/ledger.go @@ -53,11 +53,9 @@ const ( ledgerOpGetConfiguration ledgerOpcode = 0x06 // Returns specific wallet application configuration ledgerP1DirectlyFetchAddress ledgerParam1 = 0x00 // Return address directly from the wallet - ledgerP1ConfirmFetchAddress ledgerParam1 = 0x01 // Require a user confirmation before returning the address ledgerP1InitTransactionData ledgerParam1 = 0x00 // First transaction data block for signing ledgerP1ContTransactionData ledgerParam1 = 0x80 // Subsequent transaction data block for signing ledgerP2DiscardAddressChainCode ledgerParam2 = 0x00 // Do not return the chain code along with the address - ledgerP2ReturnAddressChainCode ledgerParam2 = 0x01 // Require a user confirmation before returning the address ) // errLedgerReplyInvalidHeader is the error message returned by a Ledger data exchange @@ -259,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 } @@ -304,7 +304,7 @@ func (w *ledgerDriver) ledgerSign(derivationPath []uint32, tx *types.Transaction for i, component := range derivationPath { binary.BigEndian.PutUint32(path[1+4*i:], component) } - // Create the transaction RLP based on whether legacy or EIP155 signing was requeste + // Create the transaction RLP based on whether legacy or EIP155 signing was requested var ( txrlp []byte err error @@ -352,7 +352,7 @@ func (w *ledgerDriver) ledgerSign(derivationPath []uint32, tx *types.Transaction signer = new(types.HomesteadSigner) } else { signer = types.NewEIP155Signer(chainID) - signature[64] = signature[64] - byte(chainID.Uint64()*2+35) + signature[64] -= byte(chainID.Uint64()*2 + 35) } signed, err := tx.WithSignature(signer, signature) if err != nil { diff --git a/accounts/usbwallet/trezor.go b/accounts/usbwallet/trezor.go index b84a955992..d3e17aba10 100644 --- a/accounts/usbwallet/trezor.go +++ b/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 } @@ -221,7 +247,7 @@ func (w *trezorDriver) trezorSign(derivationPath []uint32, tx *types.Transaction signer = new(types.HomesteadSigner) } else { signer = types.NewEIP155Signer(chainID) - signature[64] = signature[64] - byte(chainID.Uint64()*2+35) + signature[64] -= byte(chainID.Uint64()*2 + 35) } // Inject the final signature into the transaction and sanity check the sender signed, err := tx.WithSignature(signer, signature) diff --git a/accounts/usbwallet/internal/trezor/messages.pb.go b/accounts/usbwallet/trezor/messages.pb.go similarity index 100% rename from accounts/usbwallet/internal/trezor/messages.pb.go rename to accounts/usbwallet/trezor/messages.pb.go diff --git a/accounts/usbwallet/internal/trezor/messages.proto b/accounts/usbwallet/trezor/messages.proto similarity index 100% rename from accounts/usbwallet/internal/trezor/messages.proto rename to accounts/usbwallet/trezor/messages.proto diff --git a/accounts/usbwallet/internal/trezor/trezor.go b/accounts/usbwallet/trezor/trezor.go similarity index 98% rename from accounts/usbwallet/internal/trezor/trezor.go rename to accounts/usbwallet/trezor/trezor.go index 8ae9e726e4..80cc75efc4 100644 --- a/accounts/usbwallet/internal/trezor/trezor.go +++ b/accounts/usbwallet/trezor/trezor.go @@ -36,7 +36,7 @@ func Type(msg proto.Message) uint16 { } // Name returns the friendly message type name of a specific protocol buffer -// type numbers. +// type number. func Name(kind uint16) string { name := MessageType_name[int32(kind)] if len(name) < 12 { diff --git a/accounts/usbwallet/internal/trezor/types.pb.go b/accounts/usbwallet/trezor/types.pb.go similarity index 100% rename from accounts/usbwallet/internal/trezor/types.pb.go rename to accounts/usbwallet/trezor/types.pb.go diff --git a/accounts/usbwallet/internal/trezor/types.proto b/accounts/usbwallet/trezor/types.proto similarity index 100% rename from accounts/usbwallet/internal/trezor/types.proto rename to accounts/usbwallet/trezor/types.proto diff --git a/accounts/usbwallet/wallet.go b/accounts/usbwallet/wallet.go index 8b3b5a5224..feab505c9b 100644 --- a/accounts/usbwallet/wallet.go +++ b/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" ) @@ -99,7 +100,7 @@ type wallet struct { // // As such, a hardware wallet needs two locks to function correctly. A state // lock can be used to protect the wallet's software-side internal state, which - // must not be held exlusively during hardware communication. A communication + // must not be held exclusively during hardware communication. A communication // lock can be used to achieve exclusive access to the device itself, this one // however should allow "skipping" waiting for operations that might want to // use the device, but can live without too (e.g. account self-derivation). @@ -495,12 +496,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 +567,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/appveyor.yml b/appveyor.yml index 99029f553d..515f3d9fbe 100644 --- a/appveyor.yml +++ b/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.9.2.windows-%GETH_ARCH%.zip - - 7z x go1.9.2.windows-%GETH_ARCH%.zip -y -oC:\ > NUL + - appveyor DownloadFile https://dl.google.com/go/go1.12.windows-%GETH_ARCH%.zip + - 7z x go1.12.windows-%GETH_ARCH%.zip -y -oC:\ > NUL - go version - gcc --version diff --git a/bmt/bmt.go b/bmt/bmt.go deleted file mode 100644 index 4b65b1d94a..0000000000 --- a/bmt/bmt.go +++ /dev/null @@ -1,561 +0,0 @@ -// Copyright 2017 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 bmt provides a binary merkle tree implementation -package bmt - -import ( - "fmt" - "hash" - "io" - "strings" - "sync" - "sync/atomic" -) - -/* -Binary Merkle Tree Hash is a hash function over arbitrary datachunks of limited size -It is defined as the root hash of the binary merkle tree built over fixed size segments -of the underlying chunk using any base hash function (e.g keccak 256 SHA3) - -It is used as the chunk hash function in swarm which in turn is the basis for the -128 branching swarm hash http://swarm-guide.readthedocs.io/en/latest/architecture.html#swarm-hash - -The BMT is optimal for providing compact inclusion proofs, i.e. prove that a -segment is a substring of a chunk starting at a particular offset -The size of the underlying segments is fixed at 32 bytes (called the resolution -of the BMT hash), the EVM word size to optimize for on-chain BMT verification -as well as the hash size optimal for inclusion proofs in the merkle tree of the swarm hash. - -Two implementations are provided: - -* RefHasher is optimized for code simplicity and meant as a reference implementation -* Hasher is optimized for speed taking advantage of concurrency with minimalistic - control structure to coordinate the concurrent routines - It implements the ChunkHash interface as well as the go standard hash.Hash interface - -*/ - -const ( - // DefaultSegmentCount is the maximum number of segments of the underlying chunk - DefaultSegmentCount = 128 // Should be equal to storage.DefaultBranches - // DefaultPoolSize is the maximum number of bmt trees used by the hashers, i.e, - // the maximum number of concurrent BMT hashing operations performed by the same hasher - DefaultPoolSize = 8 -) - -// BaseHasher is a hash.Hash constructor function used for the base hash of the BMT. -type BaseHasher func() hash.Hash - -// Hasher a reusable hasher for fixed maximum size chunks representing a BMT -// implements the hash.Hash interface -// reuse pool of Tree-s for amortised memory allocation and resource control -// supports order-agnostic concurrent segment writes -// as well as sequential read and write -// can not be called concurrently on more than one chunk -// can be further appended after Sum -// Reset gives back the Tree to the pool and guaranteed to leave -// the tree and itself in a state reusable for hashing a new chunk -type Hasher struct { - pool *TreePool // BMT resource pool - bmt *Tree // prebuilt BMT resource for flowcontrol and proofs - blocksize int // segment size (size of hash) also for hash.Hash - count int // segment count - size int // for hash.Hash same as hashsize - cur int // cursor position for righmost currently open chunk - segment []byte // the rightmost open segment (not complete) - depth int // index of last level - result chan []byte // result channel - hash []byte // to record the result - max int32 // max segments for SegmentWriter interface - blockLength []byte // The block length that needes to be added in Sum -} - -// New creates a reusable Hasher -// implements the hash.Hash interface -// pulls a new Tree from a resource pool for hashing each chunk -func New(p *TreePool) *Hasher { - return &Hasher{ - pool: p, - depth: depth(p.SegmentCount), - size: p.SegmentSize, - blocksize: p.SegmentSize, - count: p.SegmentCount, - result: make(chan []byte), - } -} - -// Node is a reuseable segment hasher representing a node in a BMT -// it allows for continued writes after a Sum -// and is left in completely reusable state after Reset -type Node struct { - level, index int // position of node for information/logging only - initial bool // first and last node - root bool // whether the node is root to a smaller BMT - isLeft bool // whether it is left side of the parent double segment - unbalanced bool // indicates if a node has only the left segment - parent *Node // BMT connections - state int32 // atomic increment impl concurrent boolean toggle - left, right []byte -} - -// NewNode constructor for segment hasher nodes in the BMT -func NewNode(level, index int, parent *Node) *Node { - return &Node{ - parent: parent, - level: level, - index: index, - initial: index == 0, - isLeft: index%2 == 0, - } -} - -// TreePool provides a pool of Trees used as resources by Hasher -// a Tree popped from the pool is guaranteed to have clean state -// for hashing a new chunk -// Hasher Reset releases the Tree to the pool -type TreePool struct { - lock sync.Mutex - c chan *Tree - hasher BaseHasher - SegmentSize int - SegmentCount int - Capacity int - count int -} - -// NewTreePool creates a Tree pool with hasher, segment size, segment count and capacity -// on GetTree it reuses free Trees or creates a new one if size is not reached -func NewTreePool(hasher BaseHasher, segmentCount, capacity int) *TreePool { - return &TreePool{ - c: make(chan *Tree, capacity), - hasher: hasher, - SegmentSize: hasher().Size(), - SegmentCount: segmentCount, - Capacity: capacity, - } -} - -// Drain drains the pool uptil it has no more than n resources -func (self *TreePool) Drain(n int) { - self.lock.Lock() - defer self.lock.Unlock() - for len(self.c) > n { - <-self.c - self.count-- - } -} - -// Reserve is blocking until it returns an available Tree -// it reuses free Trees or creates a new one if size is not reached -func (self *TreePool) Reserve() *Tree { - self.lock.Lock() - defer self.lock.Unlock() - var t *Tree - if self.count == self.Capacity { - return <-self.c - } - select { - case t = <-self.c: - default: - t = NewTree(self.hasher, self.SegmentSize, self.SegmentCount) - self.count++ - } - return t -} - -// Release gives back a Tree to the pool. -// This Tree is guaranteed to be in reusable state -// does not need locking -func (self *TreePool) Release(t *Tree) { - self.c <- t // can never fail but... -} - -// Tree is a reusable control structure representing a BMT -// organised in a binary tree -// Hasher uses a TreePool to pick one for each chunk hash -// the Tree is 'locked' while not in the pool -type Tree struct { - leaves []*Node -} - -// Draw draws the BMT (badly) -func (self *Tree) Draw(hash []byte, d int) string { - var left, right []string - var anc []*Node - for i, n := range self.leaves { - left = append(left, fmt.Sprintf("%v", hashstr(n.left))) - if i%2 == 0 { - anc = append(anc, n.parent) - } - right = append(right, fmt.Sprintf("%v", hashstr(n.right))) - } - anc = self.leaves - var hashes [][]string - for l := 0; len(anc) > 0; l++ { - var nodes []*Node - hash := []string{""} - for i, n := range anc { - hash = append(hash, fmt.Sprintf("%v|%v", hashstr(n.left), hashstr(n.right))) - if i%2 == 0 && n.parent != nil { - nodes = append(nodes, n.parent) - } - } - hash = append(hash, "") - hashes = append(hashes, hash) - anc = nodes - } - hashes = append(hashes, []string{"", fmt.Sprintf("%v", hashstr(hash)), ""}) - total := 60 - del := " " - var rows []string - for i := len(hashes) - 1; i >= 0; i-- { - var textlen int - hash := hashes[i] - for _, s := range hash { - textlen += len(s) - } - if total < textlen { - total = textlen + len(hash) - } - delsize := (total - textlen) / (len(hash) - 1) - if delsize > len(del) { - delsize = len(del) - } - row := fmt.Sprintf("%v: %v", len(hashes)-i-1, strings.Join(hash, del[:delsize])) - rows = append(rows, row) - - } - rows = append(rows, strings.Join(left, " ")) - rows = append(rows, strings.Join(right, " ")) - return strings.Join(rows, "\n") + "\n" -} - -// NewTree initialises the Tree by building up the nodes of a BMT -// segment size is stipulated to be the size of the hash -// segmentCount needs to be positive integer and does not need to be -// a power of two and can even be an odd number -// segmentSize * segmentCount determines the maximum chunk size -// hashed using the tree -func NewTree(hasher BaseHasher, segmentSize, segmentCount int) *Tree { - n := NewNode(0, 0, nil) - n.root = true - prevlevel := []*Node{n} - // iterate over levels and creates 2^level nodes - level := 1 - count := 2 - for d := 1; d <= depth(segmentCount); d++ { - nodes := make([]*Node, count) - for i := 0; i < len(nodes); i++ { - parent := prevlevel[i/2] - t := NewNode(level, i, parent) - nodes[i] = t - } - prevlevel = nodes - level++ - count *= 2 - } - // the datanode level is the nodes on the last level where - return &Tree{ - leaves: prevlevel, - } -} - -// methods needed by hash.Hash - -// Size returns the size -func (self *Hasher) Size() int { - return self.size -} - -// BlockSize returns the block size -func (self *Hasher) BlockSize() int { - return self.blocksize -} - -// Sum returns the hash of the buffer -// hash.Hash interface Sum method appends the byte slice to the underlying -// data before it calculates and returns the hash of the chunk -func (self *Hasher) Sum(b []byte) (r []byte) { - t := self.bmt - i := self.cur - n := t.leaves[i] - j := i - // must run strictly before all nodes calculate - // datanodes are guaranteed to have a parent - if len(self.segment) > self.size && i > 0 && n.parent != nil { - n = n.parent - } else { - i *= 2 - } - d := self.finalise(n, i) - self.writeSegment(j, self.segment, d) - c := <-self.result - self.releaseTree() - - // sha3(length + BMT(pure_chunk)) - if self.blockLength == nil { - return c - } - res := self.pool.hasher() - res.Reset() - res.Write(self.blockLength) - res.Write(c) - return res.Sum(nil) -} - -// Hasher implements the SwarmHash interface - -// Hash waits for the hasher result and returns it -// caller must call this on a BMT Hasher being written to -func (self *Hasher) Hash() []byte { - return <-self.result -} - -// Hasher implements the io.Writer interface - -// Write fills the buffer to hash -// with every full segment complete launches a hasher go routine -// that shoots up the BMT -func (self *Hasher) Write(b []byte) (int, error) { - l := len(b) - if l <= 0 { - return 0, nil - } - s := self.segment - i := self.cur - count := (self.count + 1) / 2 - need := self.count*self.size - self.cur*2*self.size - size := self.size - if need > size { - size *= 2 - } - if l < need { - need = l - } - // calculate missing bit to complete current open segment - rest := size - len(s) - if need < rest { - rest = need - } - s = append(s, b[:rest]...) - need -= rest - // read full segments and the last possibly partial segment - for need > 0 && i < count-1 { - // push all finished chunks we read - self.writeSegment(i, s, self.depth) - need -= size - if need < 0 { - size += need - } - s = b[rest : rest+size] - rest += size - i++ - } - self.segment = s - self.cur = i - // otherwise, we can assume len(s) == 0, so all buffer is read and chunk is not yet full - return l, nil -} - -// Hasher implements the io.ReaderFrom interface - -// ReadFrom reads from io.Reader and appends to the data to hash using Write -// it reads so that chunk to hash is maximum length or reader reaches EOF -// caller must Reset the hasher prior to call -func (self *Hasher) ReadFrom(r io.Reader) (m int64, err error) { - bufsize := self.size*self.count - self.size*self.cur - len(self.segment) - buf := make([]byte, bufsize) - var read int - for { - var n int - n, err = r.Read(buf) - read += n - if err == io.EOF || read == len(buf) { - hash := self.Sum(buf[:n]) - if read == len(buf) { - err = NewEOC(hash) - } - break - } - if err != nil { - break - } - n, err = self.Write(buf[:n]) - if err != nil { - break - } - } - return int64(read), err -} - -// Reset needs to be called before writing to the hasher -func (self *Hasher) Reset() { - self.getTree() - self.blockLength = nil -} - -// Hasher implements the SwarmHash interface - -// ResetWithLength needs to be called before writing to the hasher -// the argument is supposed to be the byte slice binary representation of -// the legth of the data subsumed under the hash -func (self *Hasher) ResetWithLength(l []byte) { - self.Reset() - self.blockLength = l - -} - -// Release gives back the Tree to the pool whereby it unlocks -// it resets tree, segment and index -func (self *Hasher) releaseTree() { - if self.bmt != nil { - n := self.bmt.leaves[self.cur] - for ; n != nil; n = n.parent { - n.unbalanced = false - if n.parent != nil { - n.root = false - } - } - self.pool.Release(self.bmt) - self.bmt = nil - - } - self.cur = 0 - self.segment = nil -} - -func (self *Hasher) writeSegment(i int, s []byte, d int) { - h := self.pool.hasher() - n := self.bmt.leaves[i] - - if len(s) > self.size && n.parent != nil { - go func() { - h.Reset() - h.Write(s) - s = h.Sum(nil) - - if n.root { - self.result <- s - return - } - self.run(n.parent, h, d, n.index, s) - }() - return - } - go self.run(n, h, d, i*2, s) -} - -func (self *Hasher) run(n *Node, h hash.Hash, d int, i int, s []byte) { - isLeft := i%2 == 0 - for { - if isLeft { - n.left = s - } else { - n.right = s - } - if !n.unbalanced && n.toggle() { - return - } - if !n.unbalanced || !isLeft || i == 0 && d == 0 { - h.Reset() - h.Write(n.left) - h.Write(n.right) - s = h.Sum(nil) - - } else { - s = append(n.left, n.right...) - } - - self.hash = s - if n.root { - self.result <- s - return - } - - isLeft = n.isLeft - n = n.parent - i++ - } -} - -// getTree obtains a BMT resource by reserving one from the pool -func (self *Hasher) getTree() *Tree { - if self.bmt != nil { - return self.bmt - } - t := self.pool.Reserve() - self.bmt = t - return t -} - -// atomic bool toggle implementing a concurrent reusable 2-state object -// atomic addint with %2 implements atomic bool toggle -// it returns true if the toggler just put it in the active/waiting state -func (self *Node) toggle() bool { - return atomic.AddInt32(&self.state, 1)%2 == 1 -} - -func hashstr(b []byte) string { - end := len(b) - if end > 4 { - end = 4 - } - return fmt.Sprintf("%x", b[:end]) -} - -func depth(n int) (d int) { - for l := (n - 1) / 2; l > 0; l /= 2 { - d++ - } - return d -} - -// finalise is following the zigzags on the tree belonging -// to the final datasegment -func (self *Hasher) finalise(n *Node, i int) (d int) { - isLeft := i%2 == 0 - for { - // when the final segment's path is going via left segments - // the incoming data is pushed to the parent upon pulling the left - // we do not need toogle the state since this condition is - // detectable - n.unbalanced = isLeft - n.right = nil - if n.initial { - n.root = true - return d - } - isLeft = n.isLeft - n = n.parent - d++ - } -} - -// EOC (end of chunk) implements the error interface -type EOC struct { - Hash []byte // read the hash of the chunk off the error -} - -// Error returns the error string -func (self *EOC) Error() string { - return fmt.Sprintf("hasher limit reached, chunk hash: %x", self.Hash) -} - -// NewEOC creates new end of chunk error with the hash -func NewEOC(hash []byte) *EOC { - return &EOC{hash} -} diff --git a/bmt/bmt_r.go b/bmt/bmt_r.go deleted file mode 100644 index 649093ee3a..0000000000 --- a/bmt/bmt_r.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2017 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 . - -// simple nonconcurrent reference implementation for hashsize segment based -// Binary Merkle tree hash on arbitrary but fixed maximum chunksize -// -// This implementation does not take advantage of any paralellisms and uses -// far more memory than necessary, but it is easy to see that it is correct. -// It can be used for generating test cases for optimized implementations. -// see testBMTHasherCorrectness function in bmt_test.go -package bmt - -import ( - "hash" -) - -// RefHasher is the non-optimized easy to read reference implementation of BMT -type RefHasher struct { - span int - section int - cap int - h hash.Hash -} - -// NewRefHasher returns a new RefHasher -func NewRefHasher(hasher BaseHasher, count int) *RefHasher { - h := hasher() - hashsize := h.Size() - maxsize := hashsize * count - c := 2 - for ; c < count; c *= 2 { - } - if c > 2 { - c /= 2 - } - return &RefHasher{ - section: 2 * hashsize, - span: c * hashsize, - cap: maxsize, - h: h, - } -} - -// Hash returns the BMT hash of the byte slice -// implements the SwarmHash interface -func (rh *RefHasher) Hash(d []byte) []byte { - if len(d) > rh.cap { - d = d[:rh.cap] - } - - return rh.hash(d, rh.span) -} - -func (rh *RefHasher) hash(d []byte, s int) []byte { - l := len(d) - left := d - var right []byte - if l > rh.section { - for ; s >= l; s /= 2 { - } - left = rh.hash(d[:s], s) - right = d[s:] - if l-s > rh.section/2 { - right = rh.hash(right, s) - } - } - defer rh.h.Reset() - rh.h.Write(left) - rh.h.Write(right) - h := rh.h.Sum(nil) - return h -} diff --git a/bmt/bmt_test.go b/bmt/bmt_test.go deleted file mode 100644 index 57df83060a..0000000000 --- a/bmt/bmt_test.go +++ /dev/null @@ -1,481 +0,0 @@ -// Copyright 2017 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 bmt - -import ( - "bytes" - crand "crypto/rand" - "fmt" - "hash" - "io" - "math/rand" - "sync" - "sync/atomic" - "testing" - "time" - - "github.com/ethereum/go-ethereum/crypto/sha3" -) - -const ( - maxproccnt = 8 -) - -// TestRefHasher tests that the RefHasher computes the expected BMT hash for -// all data lengths between 0 and 256 bytes -func TestRefHasher(t *testing.T) { - hashFunc := sha3.NewKeccak256 - - sha3 := func(data ...[]byte) []byte { - h := hashFunc() - for _, v := range data { - h.Write(v) - } - return h.Sum(nil) - } - - // the test struct is used to specify the expected BMT hash for data - // lengths between "from" and "to" - type test struct { - from int64 - to int64 - expected func([]byte) []byte - } - - var tests []*test - - // all lengths in [0,64] should be: - // - // sha3(data) - // - tests = append(tests, &test{ - from: 0, - to: 64, - expected: func(data []byte) []byte { - return sha3(data) - }, - }) - - // all lengths in [65,96] should be: - // - // sha3( - // sha3(data[:64]) - // data[64:] - // ) - // - tests = append(tests, &test{ - from: 65, - to: 96, - expected: func(data []byte) []byte { - return sha3(sha3(data[:64]), data[64:]) - }, - }) - - // all lengths in [97,128] should be: - // - // sha3( - // sha3(data[:64]) - // sha3(data[64:]) - // ) - // - tests = append(tests, &test{ - from: 97, - to: 128, - expected: func(data []byte) []byte { - return sha3(sha3(data[:64]), sha3(data[64:])) - }, - }) - - // all lengths in [129,160] should be: - // - // sha3( - // sha3( - // sha3(data[:64]) - // sha3(data[64:128]) - // ) - // data[128:] - // ) - // - tests = append(tests, &test{ - from: 129, - to: 160, - expected: func(data []byte) []byte { - return sha3(sha3(sha3(data[:64]), sha3(data[64:128])), data[128:]) - }, - }) - - // all lengths in [161,192] should be: - // - // sha3( - // sha3( - // sha3(data[:64]) - // sha3(data[64:128]) - // ) - // sha3(data[128:]) - // ) - // - tests = append(tests, &test{ - from: 161, - to: 192, - expected: func(data []byte) []byte { - return sha3(sha3(sha3(data[:64]), sha3(data[64:128])), sha3(data[128:])) - }, - }) - - // all lengths in [193,224] should be: - // - // sha3( - // sha3( - // sha3(data[:64]) - // sha3(data[64:128]) - // ) - // sha3( - // sha3(data[128:192]) - // data[192:] - // ) - // ) - // - tests = append(tests, &test{ - from: 193, - to: 224, - expected: func(data []byte) []byte { - return sha3(sha3(sha3(data[:64]), sha3(data[64:128])), sha3(sha3(data[128:192]), data[192:])) - }, - }) - - // all lengths in [225,256] should be: - // - // sha3( - // sha3( - // sha3(data[:64]) - // sha3(data[64:128]) - // ) - // sha3( - // sha3(data[128:192]) - // sha3(data[192:]) - // ) - // ) - // - tests = append(tests, &test{ - from: 225, - to: 256, - expected: func(data []byte) []byte { - return sha3(sha3(sha3(data[:64]), sha3(data[64:128])), sha3(sha3(data[128:192]), sha3(data[192:]))) - }, - }) - - // run the tests - for _, x := range tests { - for length := x.from; length <= x.to; length++ { - t.Run(fmt.Sprintf("%d_bytes", length), func(t *testing.T) { - data := make([]byte, length) - if _, err := io.ReadFull(crand.Reader, data); err != nil && err != io.EOF { - t.Fatal(err) - } - expected := x.expected(data) - actual := NewRefHasher(hashFunc, 128).Hash(data) - if !bytes.Equal(actual, expected) { - t.Fatalf("expected %x, got %x", expected, actual) - } - }) - } - } -} - -func testDataReader(l int) (r io.Reader) { - return io.LimitReader(crand.Reader, int64(l)) -} - -func TestHasherCorrectness(t *testing.T) { - err := testHasher(testBaseHasher) - if err != nil { - t.Fatal(err) - } -} - -func testHasher(f func(BaseHasher, []byte, int, int) error) error { - tdata := testDataReader(4128) - data := make([]byte, 4128) - tdata.Read(data) - hasher := sha3.NewKeccak256 - size := hasher().Size() - counts := []int{1, 2, 3, 4, 5, 8, 16, 32, 64, 128} - - var err error - for _, count := range counts { - max := count * size - incr := 1 - for n := 0; n <= max+incr; n += incr { - err = f(hasher, data, n, count) - if err != nil { - return err - } - } - } - return nil -} - -func TestHasherReuseWithoutRelease(t *testing.T) { - testHasherReuse(1, t) -} - -func TestHasherReuseWithRelease(t *testing.T) { - testHasherReuse(maxproccnt, t) -} - -func testHasherReuse(i int, t *testing.T) { - hasher := sha3.NewKeccak256 - pool := NewTreePool(hasher, 128, i) - defer pool.Drain(0) - bmt := New(pool) - - for i := 0; i < 500; i++ { - n := rand.Intn(4096) - tdata := testDataReader(n) - data := make([]byte, n) - tdata.Read(data) - - err := testHasherCorrectness(bmt, hasher, data, n, 128) - if err != nil { - t.Fatal(err) - } - } -} - -func TestHasherConcurrency(t *testing.T) { - hasher := sha3.NewKeccak256 - pool := NewTreePool(hasher, 128, maxproccnt) - defer pool.Drain(0) - wg := sync.WaitGroup{} - cycles := 100 - wg.Add(maxproccnt * cycles) - errc := make(chan error) - - for p := 0; p < maxproccnt; p++ { - for i := 0; i < cycles; i++ { - go func() { - bmt := New(pool) - n := rand.Intn(4096) - tdata := testDataReader(n) - data := make([]byte, n) - tdata.Read(data) - err := testHasherCorrectness(bmt, hasher, data, n, 128) - wg.Done() - if err != nil { - errc <- err - } - }() - } - } - go func() { - wg.Wait() - close(errc) - }() - var err error - select { - case <-time.NewTimer(5 * time.Second).C: - err = fmt.Errorf("timed out") - case err = <-errc: - } - if err != nil { - t.Fatal(err) - } -} - -func testBaseHasher(hasher BaseHasher, d []byte, n, count int) error { - pool := NewTreePool(hasher, count, 1) - defer pool.Drain(0) - bmt := New(pool) - return testHasherCorrectness(bmt, hasher, d, n, count) -} - -func testHasherCorrectness(bmt hash.Hash, hasher BaseHasher, d []byte, n, count int) (err error) { - data := d[:n] - rbmt := NewRefHasher(hasher, count) - exp := rbmt.Hash(data) - timeout := time.NewTimer(time.Second) - c := make(chan error) - - go func() { - bmt.Reset() - bmt.Write(data) - got := bmt.Sum(nil) - if !bytes.Equal(got, exp) { - c <- fmt.Errorf("wrong hash: expected %x, got %x", exp, got) - } - close(c) - }() - select { - case <-timeout.C: - err = fmt.Errorf("BMT hash calculation timed out") - case err = <-c: - } - return err -} - -func BenchmarkSHA3_4k(t *testing.B) { benchmarkSHA3(4096, t) } -func BenchmarkSHA3_2k(t *testing.B) { benchmarkSHA3(4096/2, t) } -func BenchmarkSHA3_1k(t *testing.B) { benchmarkSHA3(4096/4, t) } -func BenchmarkSHA3_512b(t *testing.B) { benchmarkSHA3(4096/8, t) } -func BenchmarkSHA3_256b(t *testing.B) { benchmarkSHA3(4096/16, t) } -func BenchmarkSHA3_128b(t *testing.B) { benchmarkSHA3(4096/32, t) } - -func BenchmarkBMTBaseline_4k(t *testing.B) { benchmarkBMTBaseline(4096, t) } -func BenchmarkBMTBaseline_2k(t *testing.B) { benchmarkBMTBaseline(4096/2, t) } -func BenchmarkBMTBaseline_1k(t *testing.B) { benchmarkBMTBaseline(4096/4, t) } -func BenchmarkBMTBaseline_512b(t *testing.B) { benchmarkBMTBaseline(4096/8, t) } -func BenchmarkBMTBaseline_256b(t *testing.B) { benchmarkBMTBaseline(4096/16, t) } -func BenchmarkBMTBaseline_128b(t *testing.B) { benchmarkBMTBaseline(4096/32, t) } - -func BenchmarkRefHasher_4k(t *testing.B) { benchmarkRefHasher(4096, t) } -func BenchmarkRefHasher_2k(t *testing.B) { benchmarkRefHasher(4096/2, t) } -func BenchmarkRefHasher_1k(t *testing.B) { benchmarkRefHasher(4096/4, t) } -func BenchmarkRefHasher_512b(t *testing.B) { benchmarkRefHasher(4096/8, t) } -func BenchmarkRefHasher_256b(t *testing.B) { benchmarkRefHasher(4096/16, t) } -func BenchmarkRefHasher_128b(t *testing.B) { benchmarkRefHasher(4096/32, t) } - -func BenchmarkHasher_4k(t *testing.B) { benchmarkHasher(4096, t) } -func BenchmarkHasher_2k(t *testing.B) { benchmarkHasher(4096/2, t) } -func BenchmarkHasher_1k(t *testing.B) { benchmarkHasher(4096/4, t) } -func BenchmarkHasher_512b(t *testing.B) { benchmarkHasher(4096/8, t) } -func BenchmarkHasher_256b(t *testing.B) { benchmarkHasher(4096/16, t) } -func BenchmarkHasher_128b(t *testing.B) { benchmarkHasher(4096/32, t) } - -func BenchmarkHasherNoReuse_4k(t *testing.B) { benchmarkHasherReuse(1, 4096, t) } -func BenchmarkHasherNoReuse_2k(t *testing.B) { benchmarkHasherReuse(1, 4096/2, t) } -func BenchmarkHasherNoReuse_1k(t *testing.B) { benchmarkHasherReuse(1, 4096/4, t) } -func BenchmarkHasherNoReuse_512b(t *testing.B) { benchmarkHasherReuse(1, 4096/8, t) } -func BenchmarkHasherNoReuse_256b(t *testing.B) { benchmarkHasherReuse(1, 4096/16, t) } -func BenchmarkHasherNoReuse_128b(t *testing.B) { benchmarkHasherReuse(1, 4096/32, t) } - -func BenchmarkHasherReuse_4k(t *testing.B) { benchmarkHasherReuse(16, 4096, t) } -func BenchmarkHasherReuse_2k(t *testing.B) { benchmarkHasherReuse(16, 4096/2, t) } -func BenchmarkHasherReuse_1k(t *testing.B) { benchmarkHasherReuse(16, 4096/4, t) } -func BenchmarkHasherReuse_512b(t *testing.B) { benchmarkHasherReuse(16, 4096/8, t) } -func BenchmarkHasherReuse_256b(t *testing.B) { benchmarkHasherReuse(16, 4096/16, t) } -func BenchmarkHasherReuse_128b(t *testing.B) { benchmarkHasherReuse(16, 4096/32, t) } - -// benchmarks the minimum hashing time for a balanced (for simplicity) BMT -// by doing count/segmentsize parallel hashings of 2*segmentsize bytes -// doing it on n maxproccnt each reusing the base hasher -// 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(n int, t *testing.B) { - tdata := testDataReader(64) - data := make([]byte, 64) - tdata.Read(data) - hasher := sha3.NewKeccak256 - - t.ReportAllocs() - t.ResetTimer() - for i := 0; i < t.N; i++ { - count := int32((n-1)/hasher().Size() + 1) - wg := sync.WaitGroup{} - wg.Add(maxproccnt) - var i int32 - for j := 0; j < maxproccnt; j++ { - go func() { - defer wg.Done() - h := hasher() - for atomic.AddInt32(&i, 1) < count { - h.Reset() - h.Write(data) - h.Sum(nil) - } - }() - } - wg.Wait() - } -} - -func benchmarkHasher(n int, t *testing.B) { - tdata := testDataReader(n) - data := make([]byte, n) - tdata.Read(data) - - size := 1 - hasher := sha3.NewKeccak256 - segmentCount := 128 - pool := NewTreePool(hasher, segmentCount, size) - bmt := New(pool) - - t.ReportAllocs() - t.ResetTimer() - for i := 0; i < t.N; i++ { - bmt.Reset() - bmt.Write(data) - bmt.Sum(nil) - } -} - -func benchmarkHasherReuse(poolsize, n int, t *testing.B) { - tdata := testDataReader(n) - data := make([]byte, n) - tdata.Read(data) - - hasher := sha3.NewKeccak256 - segmentCount := 128 - pool := NewTreePool(hasher, segmentCount, poolsize) - cycles := 200 - - t.ReportAllocs() - t.ResetTimer() - for i := 0; i < t.N; i++ { - wg := sync.WaitGroup{} - wg.Add(cycles) - for j := 0; j < cycles; j++ { - bmt := New(pool) - go func() { - defer wg.Done() - bmt.Reset() - bmt.Write(data) - bmt.Sum(nil) - }() - } - wg.Wait() - } -} - -func benchmarkSHA3(n int, t *testing.B) { - data := make([]byte, n) - tdata := testDataReader(n) - tdata.Read(data) - hasher := sha3.NewKeccak256 - h := hasher() - - t.ReportAllocs() - t.ResetTimer() - for i := 0; i < t.N; i++ { - h.Reset() - h.Write(data) - h.Sum(nil) - } -} - -func benchmarkRefHasher(n int, t *testing.B) { - data := make([]byte, n) - tdata := testDataReader(n) - tdata.Read(data) - hasher := sha3.NewKeccak256 - rbmt := NewRefHasher(hasher, 128) - - t.ReportAllocs() - t.ResetTimer() - for i := 0; i < t.N; i++ { - rbmt.Hash(data) - } -} diff --git a/build/ci-notes.md b/build/ci-notes.md index 78e9575c01..13e1fd2307 100644 --- a/build/ci-notes.md +++ b/build/ci-notes.md @@ -2,37 +2,39 @@ Tagged releases and develop branch commits are available as installable Debian packages for Ubuntu. Packages are built for the all Ubuntu versions which are supported by -Canonical: - -- Trusty Tahr (14.04 LTS) -- Xenial Xerus (16.04 LTS) -- Yakkety Yak (16.10) -- Zesty Zapus (17.04) +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.9, 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.9 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.9 devscripts debhelper + $ sudo apt-get install build-essential golang-1.11 devscripts debhelper python-bzrlib python-paramiko Create the source packages: diff --git a/build/ci.go b/build/ci.go index 1f98bb8438..f5553fd300 100644 --- a/build/ci.go +++ b/build/ci.go @@ -26,7 +26,7 @@ Available commands are: install [ -arch architecture ] [ -cc compiler ] [ packages... ] -- builds packages and executables test [ -coverage ] [ packages... ] -- runs the tests lint -- runs certain pre-selected linters - archive [ -arch architecture ] [ -type zip|tar ] [ -signer key-envvar ] [ -upload dest ] -- archives build artefacts + archive [ -arch architecture ] [ -type zip|tar ] [ -signer key-envvar ] [ -upload dest ] -- archives build artifacts importkeys -- imports signing keys from env debsrc [ -signer key-id ] [ -upload dest ] -- creates a debian source package nsis -- creates a Windows NSIS installer @@ -59,6 +59,8 @@ import ( "time" "github.com/ethereum/go-ethereum/internal/build" + "github.com/ethereum/go-ethereum/params" + sv "github.com/ethereum/go-ethereum/swarm/version" ) var ( @@ -77,51 +79,89 @@ var ( executablePath("geth"), executablePath("puppeth"), executablePath("rlpdump"), - executablePath("swarm"), executablePath("wnode"), + executablePath("clef"), + } + + // Files that end up in the swarm*.zip archive. + swarmArchiveFiles = []string{ + "COPYING", + executablePath("swarm"), } // A debian package is created for all executables listed here. debExecutables = []debExecutable{ { - Name: "abigen", + BinaryName: "abigen", Description: "Source code generator to convert Ethereum contract definitions into easy to use, compile-time type-safe Go packages.", }, { - Name: "bootnode", + BinaryName: "bootnode", Description: "Ethereum bootnode.", }, { - Name: "evm", + BinaryName: "evm", Description: "Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode.", }, { - Name: "geth", + BinaryName: "geth", Description: "Ethereum CLI client.", }, { - Name: "puppeth", + BinaryName: "puppeth", Description: "Ethereum private network manager.", }, { - Name: "rlpdump", + BinaryName: "rlpdump", Description: "Developer utility tool that prints RLP structures.", }, { - Name: "swarm", - Description: "Ethereum Swarm daemon and tools", - }, - { - Name: "wnode", + BinaryName: "wnode", Description: "Ethereum Whisper diagnostic tool", }, + { + BinaryName: "clef", + Description: "Ethereum account management tool.", + }, } + // A debian package is created for all executables listed here. + debSwarmExecutables = []debExecutable{ + { + BinaryName: "swarm", + PackageName: "ethereum-swarm", + Description: "Ethereum Swarm daemon and tools", + }, + } + + debEthereum = debPackage{ + Name: "ethereum", + Version: params.Version, + Executables: debExecutables, + } + + debSwarm = debPackage{ + Name: "ethereum-swarm", + Version: sv.Version, + Executables: debSwarmExecutables, + } + + // Debian meta packages to build and push to Ubuntu PPA + debPackages = []debPackage{ + debSwarm, + debEthereum, + } + + // Packages to be cross-compiled by the xgo command + allCrossCompiledArchiveFiles = append(allToolsArchiveFiles, swarmArchiveFiles...) + // Distros for which packages are created. // Note: vivid is unsupported because there is no golang-1.6 package for it. // Note: wily is unsupported because it was officially deprecated on lanchpad. // Note: yakkety is unsupported because it was officially deprecated on lanchpad. - debDistros = []string{"trusty", "xenial", "zesty", "artful"} + // 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", "disco"} ) var GOBIN, _ = filepath.Abs(filepath.Join("build", "bin")) @@ -181,13 +221,13 @@ func doInstall(cmdline []string) { // Check Go version. People regularly open issues about compilation // failure with outdated Go. This should save them the trouble. if !strings.Contains(runtime.Version(), "devel") { - // Figure out the minor version number since we can't textually compare (1.10 < 1.7) + // Figure out the minor version number since we can't textually compare (1.10 < 1.9) var minor int fmt.Sscanf(strings.TrimPrefix(runtime.Version(), "go1."), "%d", &minor) - if minor < 7 { + if minor < 9 { log.Println("You have Go version", runtime.Version()) - log.Println("go-ethereum requires at least Go version 1.7 and cannot") + log.Println("go-ethereum requires at least Go version 1.9 and cannot") log.Println("be compiled with an earlier version. Please upgrade your Go installation.") os.Exit(1) } @@ -261,16 +301,6 @@ func goTool(subcmd string, args ...string) *exec.Cmd { func goToolArch(arch string, cc string, subcmd string, args ...string) *exec.Cmd { cmd := build.GoTool(subcmd, args...) - if subcmd == "build" || subcmd == "install" || subcmd == "test" { - // Go CGO has a Windows linker error prior to 1.8 (https://github.com/golang/go/issues/8756). - // Work around issue by allowing multiple definitions for <1.8 builds. - var minor int - fmt.Sscanf(strings.TrimPrefix(runtime.Version(), "go1."), "%d", &minor) - - if runtime.GOOS == "windows" && minor < 8 { - cmd.Args = append(cmd.Args, []string{"-ldflags", "-extldflags -Wl,--allow-multiple-definition"}...) - } - } cmd.Env = []string{"GOPATH=" + build.GOPATH()} if arch == "" || arch == runtime.GOARCH { cmd.Env = append(cmd.Env, "GOBIN="+GOBIN) @@ -295,9 +325,7 @@ func goToolArch(arch string, cc string, subcmd string, args ...string) *exec.Cmd // "tests" also includes static analysis tools such as vet. func doTest(cmdline []string) { - var ( - coverage = flag.Bool("coverage", false, "Whether to record code coverage") - ) + coverage := flag.Bool("coverage", false, "Whether to record code coverage") flag.CommandLine.Parse(cmdline) env := build.Env() @@ -307,14 +335,11 @@ func doTest(cmdline []string) { } packages = build.ExpandPackagesNoVendor(packages) - // Run analysis tools before the tests. - build.MustRun(goTool("vet", packages...)) - // Run the actual tests. - gotest := goTool("test", buildFlags(env)...) // Test a single package at a time. CI builders are slow // and some tests run into timeouts under load. - gotest.Args = append(gotest.Args, "-p", "1") + gotest := goTool("test", buildFlags(env)...) + gotest.Args = append(gotest.Args, "-p", "1", "-timeout", "5m") if *coverage { gotest.Args = append(gotest.Args, "-covermode=atomic", "-cover") } @@ -338,7 +363,11 @@ func doLint(cmdline []string) { // Run fast linters batched together configs := []string{ "--vendor", + "--tests", + "--deadline=2m", "--disable-all", + "--enable=goimports", + "--enable=varcheck", "--enable=vet", "--enable=gofmt", "--enable=misspell", @@ -349,13 +378,12 @@ func doLint(cmdline []string) { // Run slow linters one by one for _, linter := range []string{"unconvert", "gosimple"} { - configs = []string{"--vendor", "--deadline=10m", "--disable-all", "--enable=" + linter} + configs = []string{"--vendor", "--tests", "--deadline=10m", "--disable-all", "--enable=" + linter} build.MustRunCommand(filepath.Join(GOBIN, "gometalinter.v2"), append(configs, packages...)...) } } // Release Packaging - func doArchive(cmdline []string) { var ( arch = flag.String("arch", runtime.GOARCH, "Architecture cross packaging") @@ -375,10 +403,14 @@ func doArchive(cmdline []string) { } var ( - env = build.Env() - base = archiveBasename(*arch, env) - geth = "geth-" + base + ext - alltools = "geth-alltools-" + base + ext + env = build.Env() + + basegeth = archiveBasename(*arch, params.ArchiveVersion(env.Commit)) + geth = "geth-" + basegeth + ext + alltools = "geth-alltools-" + basegeth + ext + + baseswarm = archiveBasename(*arch, sv.ArchiveVersion(env.Commit)) + swarm = "swarm-" + baseswarm + ext ) maybeSkipArchive(env) if err := build.WriteArchive(geth, gethArchiveFiles); err != nil { @@ -387,14 +419,17 @@ func doArchive(cmdline []string) { if err := build.WriteArchive(alltools, allToolsArchiveFiles); err != nil { log.Fatal(err) } - for _, archive := range []string{geth, alltools} { + if err := build.WriteArchive(swarm, swarmArchiveFiles); err != nil { + log.Fatal(err) + } + for _, archive := range []string{geth, alltools, swarm} { if err := archiveUpload(archive, *upload, *signer); err != nil { log.Fatal(err) } } } -func archiveBasename(arch string, env build.Environment) string { +func archiveBasename(arch string, archiveVersion string) string { platform := runtime.GOOS + "-" + arch if arch == "arm" { platform += os.Getenv("GOARM") @@ -405,28 +440,14 @@ func archiveBasename(arch string, env build.Environment) string { if arch == "ios" { platform = "ios-all" } - return platform + "-" + archiveVersion(env) -} - -func archiveVersion(env build.Environment) string { - version := build.VERSION() - if isUnstableBuild(env) { - version += "-unstable" - } - if env.Commit != "" { - version += "-" + env.Commit[:8] - } - return version + return platform + "-" + archiveVersion } 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 } } @@ -466,11 +487,11 @@ func maybeSkipArchive(env build.Environment) { } // Debian Packaging - 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() ) @@ -480,35 +501,69 @@ 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) } - // Create the packages. - for _, distro := range debDistros { - meta := newDebMetadata(distro, *signer, env, now) - pkgdir := stageDebianSource(*workdir, meta) - debuild := exec.Command("debuild", "-S", "-sa", "-us", "-uc") - debuild.Dir = pkgdir - build.MustRun(debuild) + // Create Debian packages and upload them + for _, pkg := range debPackages { + 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", "-d", "-Zxz") + debuild.Dir = pkgdir + build.MustRun(debuild) - changes := fmt.Sprintf("%s_%s_source.changes", meta.Name(), meta.VersionString()) - changes = filepath.Join(*workdir, changes) - if *signer != "" { - build.MustRunCommand("debsign", changes) - } - if *upload != "" { - build.MustRunCommand("dput", *upload, 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 != "" { + 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 != "" { @@ -529,9 +584,17 @@ func isUnstableBuild(env build.Environment) bool { return true } +type debPackage struct { + Name string // the name of the Debian package to produce, e.g. "ethereum", or "ethereum-swarm" + Version string // the clean version of the debPackage, e.g. 1.8.12 or 0.3.0, without any metadata + Executables []debExecutable // executables to be included in the package +} + type debMetadata struct { Env build.Environment + PackageName string + // go-ethereum version being built. Note that this // is not the debian package version. The package version // is constructed by VersionString. @@ -543,21 +606,33 @@ type debMetadata struct { } type debExecutable struct { - Name, Description string + PackageName string + BinaryName string + Description string } -func newDebMetadata(distro, author string, env build.Environment, t time.Time) debMetadata { +// Package returns the name of the package if present, or +// fallbacks to BinaryName +func (d debExecutable) Package() string { + if d.PackageName != "" { + return d.PackageName + } + return d.BinaryName +} + +func newDebMetadata(distro, author string, env build.Environment, t time.Time, name string, version string, exes []debExecutable) debMetadata { if author == "" { // No signing key, use default author. author = "Ethereum Builds " } return debMetadata{ + PackageName: name, Env: env, Author: author, Distro: distro, - Version: build.VERSION(), + Version: version, Time: t.Format(time.RFC1123Z), - Executables: debExecutables, + Executables: exes, } } @@ -565,9 +640,9 @@ func newDebMetadata(distro, author string, env build.Environment, t time.Time) d // on all executable packages. func (meta debMetadata) Name() string { if isUnstableBuild(meta.Env) { - return "ethereum-unstable" + return meta.PackageName + "-unstable" } - return "ethereum" + return meta.PackageName } // VersionString returns the debian version of the packages. @@ -594,9 +669,9 @@ func (meta debMetadata) ExeList() string { // ExeName returns the package name of an executable package. func (meta debMetadata) ExeName(exe debExecutable) string { if isUnstableBuild(meta.Env) { - return exe.Name + "-unstable" + return exe.Package() + "-unstable" } - return exe.Name + return exe.Package() } // ExeConflicts returns the content of the Conflicts field @@ -611,7 +686,7 @@ func (meta debMetadata) ExeConflicts(exe debExecutable) string { // be preferred and the conflicting files should be handled via // alternates. We might do this eventually but using a conflict is // easier now. - return "ethereum, " + exe.Name + return "ethereum, " + exe.Package() } return "" } @@ -628,24 +703,23 @@ func stageDebianSource(tmpdir string, meta debMetadata) (pkgdir string) { // Put the debian build files in place. debian := filepath.Join(pkgdir, "debian") - build.Render("build/deb.rules", filepath.Join(debian, "rules"), 0755, meta) - build.Render("build/deb.changelog", filepath.Join(debian, "changelog"), 0644, meta) - build.Render("build/deb.control", filepath.Join(debian, "control"), 0644, meta) - build.Render("build/deb.copyright", filepath.Join(debian, "copyright"), 0644, meta) + build.Render("build/deb/"+meta.PackageName+"/deb.rules", filepath.Join(debian, "rules"), 0755, meta) + build.Render("build/deb/"+meta.PackageName+"/deb.changelog", filepath.Join(debian, "changelog"), 0644, meta) + build.Render("build/deb/"+meta.PackageName+"/deb.control", filepath.Join(debian, "control"), 0644, meta) + build.Render("build/deb/"+meta.PackageName+"/deb.copyright", filepath.Join(debian, "copyright"), 0644, meta) build.RenderString("8\n", filepath.Join(debian, "compat"), 0644, meta) build.RenderString("3.0 (native)\n", filepath.Join(debian, "source/format"), 0644, meta) for _, exe := range meta.Executables { install := filepath.Join(debian, meta.ExeName(exe)+".install") docs := filepath.Join(debian, meta.ExeName(exe)+".docs") - build.Render("build/deb.install", install, 0644, exe) - build.Render("build/deb.docs", docs, 0644, exe) + build.Render("build/deb/"+meta.PackageName+"/deb.install", install, 0644, exe) + build.Render("build/deb/"+meta.PackageName+"/deb.docs", docs, 0644, exe) } return pkgdir } // Windows installer - func doWindowsInstaller(cmdline []string) { // Parse the flags and make skip installer generation on PRs var ( @@ -695,11 +769,11 @@ func doWindowsInstaller(cmdline []string) { // Build the installer. This assumes that all the needed files have been previously // built (don't mix building and packaging to keep cross compilation complexity to a // minimum). - version := strings.Split(build.VERSION(), ".") + version := strings.Split(params.Version, ".") if env.Commit != "" { version[2] += "-" + env.Commit[:8] } - installer, _ := filepath.Abs("geth-" + archiveBasename(*arch, env) + ".exe") + installer, _ := filepath.Abs("geth-" + archiveBasename(*arch, params.ArchiveVersion(env.Commit)) + ".exe") build.MustRunCommand("makensis.exe", "/DOUTPUTFILE="+installer, "/DMAJORVERSION="+version[0], @@ -731,13 +805,9 @@ 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")) - build.MustRun(gomobileTool("init", "--ndk", os.Getenv("ANDROID_NDK"))) - build.MustRun(gomobileTool("bind", "--target", "android", "--javapkg", "org.ethereum", "-v", "github.com/ethereum/go-ethereum/mobile")) + build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile", "golang.org/x/mobile/cmd/gobind")) + build.MustRun(gomobileTool("bind", "-ldflags", "-s -w", "--target", "android", "--javapkg", "org.ethereum", "-v", "github.com/ethereum/go-ethereum/mobile")) if *local { // If we're building locally, copy bundle to build dir and skip Maven @@ -751,7 +821,7 @@ func doAndroidArchive(cmdline []string) { maybeSkipArchive(env) // Sign and upload the archive to Azure - archive := "geth-" + archiveBasename("android", env) + ".aar" + archive := "geth-" + archiveBasename("android", params.ArchiveVersion(env.Commit)) + ".aar" os.Rename("geth.aar", archive) if err := archiveUpload(archive, *upload, *signer); err != nil { @@ -761,22 +831,22 @@ func doAndroidArchive(cmdline []string) { os.Rename(archive, meta.Package+".aar") if *signer != "" && *deploy != "" { // Import the signing key into the local GPG instance - if b64key := os.Getenv(*signer); b64key != "" { - key, err := base64.StdEncoding.DecodeString(b64key) - if err != nil { - log.Fatalf("invalid base64 %s", *signer) - } - gpg := exec.Command("gpg", "--import") - gpg.Stdin = bytes.NewReader(key) - build.MustRun(gpg) + 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) } // Upload the artifacts to Sonatype and/or Maven Central repo := *deploy + "/service/local/staging/deploy/maven2" if meta.Develop { repo = *deploy + "/content/repositories/snapshots" } - build.MustRunCommand("mvn", "gpg:sign-and-deploy-file", + build.MustRunCommand("mvn", "gpg:sign-and-deploy-file", "-e", "-X", "-settings=build/mvn.settings", "-Durl="+repo, "-DrepositoryId=ossrh", + "-Dgpg.keyname="+keyID, "-DpomFile="+meta.Package+".pom", "-Dfile="+meta.Package+".aar") } } @@ -786,9 +856,10 @@ func gomobileTool(subcmd string, args ...string) *exec.Cmd { cmd.Args = append(cmd.Args, args...) cmd.Env = []string{ "GOPATH=" + build.GOPATH(), + "PATH=" + GOBIN + string(os.PathListSeparator) + os.Getenv("PATH"), } for _, e := range os.Environ() { - if strings.HasPrefix(e, "GOPATH=") { + if strings.HasPrefix(e, "GOPATH=") || strings.HasPrefix(e, "PATH=") { continue } cmd.Env = append(cmd.Env, e) @@ -830,7 +901,7 @@ func newMavenMetadata(env build.Environment) mavenMetadata { } } // Render the version and package strings - version := build.VERSION() + version := params.Version if isUnstableBuild(env) { version += "-SNAPSHOT" } @@ -855,9 +926,9 @@ func doXCodeFramework(cmdline []string) { env := build.Env() // Build the iOS XCode framework - build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile")) + build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile", "golang.org/x/mobile/cmd/gobind")) build.MustRun(gomobileTool("init")) - bind := gomobileTool("bind", "--target", "ios", "--tags", "ios", "-v", "github.com/ethereum/go-ethereum/mobile") + bind := gomobileTool("bind", "-ldflags", "-s -w", "--target", "ios", "--tags", "ios", "-v", "github.com/ethereum/go-ethereum/mobile") if *local { // If we're building locally, use the build folder and stop afterwards @@ -865,7 +936,7 @@ func doXCodeFramework(cmdline []string) { build.MustRun(bind) return } - archive := "geth-" + archiveBasename("ios", env) + archive := "geth-" + archiveBasename("ios", params.ArchiveVersion(env.Commit)) if err := os.Mkdir(archive, os.ModePerm); err != nil { log.Fatal(err) } @@ -921,7 +992,7 @@ func newPodMetadata(env build.Environment, archive string) podMetadata { } } } - version := build.VERSION() + version := params.Version if isUnstableBuild(env) { version += "-unstable." + env.Buildnum } @@ -951,7 +1022,7 @@ func doXgo(cmdline []string) { if *alltools { args = append(args, []string{"--dest", GOBIN}...) - for _, res := range allToolsArchiveFiles { + for _, res := range allCrossCompiledArchiveFiles { if strings.HasPrefix(res, GOBIN) { // Binary tool found, cross build it explicitly args = append(args, "./"+filepath.Join("cmd", filepath.Base(res))) @@ -990,7 +1061,7 @@ func xgoTool(args []string) *exec.Cmd { func doPurge(cmdline []string) { var ( store = flag.String("store", "", `Destination from where to purge archives (usually "gethstore/builds")`) - limit = flag.Int("days", 30, `Age threshold above which to delete unstalbe archives`) + limit = flag.Int("days", 30, `Age threshold above which to delete unstable archives`) ) flag.CommandLine.Parse(cmdline) @@ -1017,23 +1088,14 @@ func doPurge(cmdline []string) { } for i := 0; i < len(blobs); i++ { for j := i + 1; j < len(blobs); j++ { - iTime, err := time.Parse(time.RFC1123, blobs[i].Properties.LastModified) - if err != nil { - log.Fatal(err) - } - jTime, err := time.Parse(time.RFC1123, blobs[j].Properties.LastModified) - if err != nil { - log.Fatal(err) - } - if iTime.After(jTime) { + if blobs[i].Properties.LastModified.After(blobs[j].Properties.LastModified) { blobs[i], blobs[j] = blobs[j], blobs[i] } } } // Filter out all archives more recent that the given threshold for i, blob := range blobs { - timestamp, _ := time.Parse(time.RFC1123, blob.Properties.LastModified) - if time.Since(timestamp) < time.Duration(*limit)*24*time.Hour { + if time.Since(blob.Properties.LastModified) < time.Duration(*limit)*24*time.Hour { blobs = blobs[:i] break } diff --git a/build/clean_go_build_cache.sh b/build/clean_go_build_cache.sh new file mode 100755 index 0000000000..1666381d98 --- /dev/null +++ b/build/clean_go_build_cache.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +# Cleaning the Go cache only makes sense if we actually have Go installed... or +# if Go is actually callable. This does not hold true during deb packaging, so +# we need an explicit check to avoid build failures. +if ! command -v go > /dev/null; then + exit +fi + +version_gt() { + test "$(printf '%s\n' "$@" | sort -V | head -n 1)" != "$1" +} + +golang_version=$(go version |cut -d' ' -f3 |sed 's/go//') + +# Clean go build cache when go version is greater than or equal to 1.10 +if !(version_gt 1.10 $golang_version); then + go clean -cache +fi diff --git a/build/deb.install b/build/deb.install deleted file mode 100644 index 7dc76e1f56..0000000000 --- a/build/deb.install +++ /dev/null @@ -1 +0,0 @@ -build/bin/{{.Name}} usr/bin diff --git a/build/deb.rules b/build/deb.rules deleted file mode 100644 index 7a78525139..0000000000 --- a/build/deb.rules +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/make -f -# -*- makefile -*- - -# Uncomment this to turn on verbose mode. -#export DH_VERBOSE=1 - -override_dh_auto_build: - build/env.sh /usr/lib/go-1.9/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: - -%: - dh $@ diff --git a/build/deb.changelog b/build/deb/ethereum-swarm/deb.changelog similarity index 100% rename from build/deb.changelog rename to build/deb/ethereum-swarm/deb.changelog diff --git a/build/deb/ethereum-swarm/deb.control b/build/deb/ethereum-swarm/deb.control new file mode 100644 index 0000000000..b0ced141b6 --- /dev/null +++ b/build/deb/ethereum-swarm/deb.control @@ -0,0 +1,19 @@ +Source: {{.Name}} +Section: science +Priority: extra +Maintainer: {{.Author}} +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 +Vcs-Browser: https://github.com/ethereum/go-ethereum + +{{range .Executables}} +Package: {{$.ExeName .}} +Conflicts: {{$.ExeConflicts .}} +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Built-Using: ${misc:Built-Using} +Description: {{.Description}} + {{.Description}} +{{end}} diff --git a/build/deb.copyright b/build/deb/ethereum-swarm/deb.copyright similarity index 93% rename from build/deb.copyright rename to build/deb/ethereum-swarm/deb.copyright index 513be45b19..fe6e36ad9d 100644 --- a/build/deb.copyright +++ b/build/deb/ethereum-swarm/deb.copyright @@ -1,4 +1,4 @@ -Copyright 2016 The go-ethereum Authors +Copyright 2018 The go-ethereum Authors 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 diff --git a/build/deb.docs b/build/deb/ethereum-swarm/deb.docs similarity index 100% rename from build/deb.docs rename to build/deb/ethereum-swarm/deb.docs diff --git a/build/deb/ethereum-swarm/deb.install b/build/deb/ethereum-swarm/deb.install new file mode 100644 index 0000000000..e7666ce5fb --- /dev/null +++ b/build/deb/ethereum-swarm/deb.install @@ -0,0 +1 @@ +build/bin/{{.BinaryName}} usr/bin diff --git a/build/deb/ethereum-swarm/deb.rules b/build/deb/ethereum-swarm/deb.rules new file mode 100644 index 0000000000..5280e0e55a --- /dev/null +++ b/build/deb/ethereum-swarm/deb.rules @@ -0,0 +1,16 @@ +#!/usr/bin/make -f +# -*- makefile -*- + +# 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.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: + +%: + dh $@ diff --git a/build/deb/ethereum/deb.changelog b/build/deb/ethereum/deb.changelog new file mode 100644 index 0000000000..83f804a833 --- /dev/null +++ b/build/deb/ethereum/deb.changelog @@ -0,0 +1,5 @@ +{{.Name}} ({{.VersionString}}) {{.Distro}}; urgency=low + + * git build of {{.Env.Commit}} + + -- {{.Author}} {{.Time}} diff --git a/build/deb.control b/build/deb/ethereum/deb.control similarity index 76% rename from build/deb.control rename to build/deb/ethereum/deb.control index 5c9ce6705c..018067a19d 100644 --- a/build/deb.control +++ b/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.9 +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 @@ -11,8 +11,8 @@ Vcs-Browser: https://github.com/ethereum/go-ethereum Package: {{.Name}} Architecture: any Depends: ${misc:Depends}, {{.ExeList}} -Description: Meta-package to install geth and other tools - Meta-package to install geth and other tools +Description: Meta-package to install geth, swarm, and other tools + Meta-package to install geth, swarm and other tools {{range .Executables}} Package: {{$.ExeName .}} diff --git a/build/deb/ethereum/deb.copyright b/build/deb/ethereum/deb.copyright new file mode 100644 index 0000000000..fe6e36ad9d --- /dev/null +++ b/build/deb/ethereum/deb.copyright @@ -0,0 +1,14 @@ +Copyright 2018 The go-ethereum Authors + +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 . diff --git a/build/deb/ethereum/deb.docs b/build/deb/ethereum/deb.docs new file mode 100644 index 0000000000..62deb04972 --- /dev/null +++ b/build/deb/ethereum/deb.docs @@ -0,0 +1 @@ +AUTHORS diff --git a/build/deb/ethereum/deb.install b/build/deb/ethereum/deb.install new file mode 100644 index 0000000000..e7666ce5fb --- /dev/null +++ b/build/deb/ethereum/deb.install @@ -0,0 +1 @@ +build/bin/{{.BinaryName}} usr/bin diff --git a/build/deb/ethereum/deb.rules b/build/deb/ethereum/deb.rules new file mode 100644 index 0000000000..5280e0e55a --- /dev/null +++ b/build/deb/ethereum/deb.rules @@ -0,0 +1,16 @@ +#!/usr/bin/make -f +# -*- makefile -*- + +# 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.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: + +%: + dh $@ diff --git a/build/goimports.sh b/build/goimports.sh new file mode 100755 index 0000000000..1fcace6a4b --- /dev/null +++ b/build/goimports.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +find_files() { + find . ! \( \ + \( \ + -path '.github' \ + -o -path './build/_workspace' \ + -o -path './build/bin' \ + -o -path './crypto/bn256' \ + -o -path '*/vendor/*' \ + \) -prune \ + \) -name '*.go' +} + +GOFMT="gofmt -s -w" +GOIMPORTS="goimports -w" +find_files | xargs $GOFMT +find_files | xargs $GOIMPORTS diff --git a/build/travis_keepalive.sh b/build/travis_keepalive.sh new file mode 100755 index 0000000000..77cc623eaf --- /dev/null +++ b/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/build/update-license.go b/build/update-license.go index 3d69598b75..e3e00d4cc0 100644 --- a/build/update-license.go +++ b/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 /* @@ -55,10 +71,9 @@ var ( "crypto/sha3/", "internal/jsre/deps", "log/", + "common/bitutil/bitutil", // don't license generated files - "contracts/chequebook/contract/", - "contracts/ens/contract/", - "contracts/release/contract.go", + "contracts/chequebook/contract/code.go", } // paths with this prefix are licensed as GPL. all other files are LGPL. diff --git a/cmd/abigen/main.go b/cmd/abigen/main.go index 3a1ae6f4c3..25bb2c3b73 100644 --- a/cmd/abigen/main.go +++ b/cmd/abigen/main.go @@ -29,7 +29,7 @@ import ( ) var ( - abiFlag = flag.String("abi", "", "Path to the Ethereum contract ABI json to bind") + abiFlag = flag.String("abi", "", "Path to the Ethereum contract ABI json to bind, - for STDIN") binFlag = flag.String("bin", "", "Path to the Ethereum contract bytecode (generate deploy method)") typFlag = flag.String("type", "", "Struct name for the binding (default = package name)") @@ -75,16 +75,27 @@ func main() { bins []string types []string ) - if *solFlag != "" { + if *solFlag != "" || (*abiFlag == "-" && *pkgFlag == "") { // Generate the list of types to exclude from binding exclude := make(map[string]bool) for _, kind := range strings.Split(*excFlag, ",") { exclude[strings.ToLower(kind)] = true } - contracts, err := compiler.CompileSolidity(*solcFlag, *solFlag) - if err != nil { - fmt.Printf("Failed to build Solidity contract: %v\n", err) - os.Exit(-1) + + var contracts map[string]*compiler.Contract + var err error + if *solFlag != "" { + contracts, err = compiler.CompileSolidity(*solcFlag, *solFlag) + if err != nil { + fmt.Printf("Failed to build Solidity contract: %v\n", err) + os.Exit(-1) + } + } else { + contracts, err = contractsFromStdin() + if err != nil { + fmt.Printf("Failed to read input ABIs from STDIN: %v\n", err) + os.Exit(-1) + } } // Gather all non-excluded contract for binding for name, contract := range contracts { @@ -100,14 +111,20 @@ func main() { } } else { // Otherwise load up the ABI, optional bytecode and type name from the parameters - abi, err := ioutil.ReadFile(*abiFlag) + var abi []byte + var err error + if *abiFlag == "-" { + abi, err = ioutil.ReadAll(os.Stdin) + } else { + abi, err = ioutil.ReadFile(*abiFlag) + } if err != nil { fmt.Printf("Failed to read input ABI: %v\n", err) os.Exit(-1) } 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) @@ -138,3 +155,11 @@ func main() { os.Exit(-1) } } + +func contractsFromStdin() (map[string]*compiler.Contract, error) { + bytes, err := ioutil.ReadAll(os.Stdin) + if err != nil { + return nil, err + } + return compiler.ParseCombinedJSON(bytes, "", "", "", "") +} diff --git a/cmd/bootnode/main.go b/cmd/bootnode/main.go index ecfc6fc24e..a40b32b600 100644 --- a/cmd/bootnode/main.go +++ b/cmd/bootnode/main.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p/discover" "github.com/ethereum/go-ethereum/p2p/discv5" + "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/p2p/netutil" ) @@ -37,7 +38,7 @@ func main() { var ( listenAddr = flag.String("addr", ":30301", "listen address") genKey = flag.String("genkey", "", "generate a node key") - writeAddr = flag.Bool("writeaddress", false, "write out the node's pubkey hash and quit") + writeAddr = flag.Bool("writeaddress", false, "write out the node's public key and quit") nodeKeyFile = flag.String("nodekey", "", "private key filename") nodeKeyHex = flag.String("nodekeyhex", "", "private key as hex (for testing)") natdesc = flag.String("nat", "none", "port mapping mechanism (any|none|upnp|pmp|extip:)") @@ -85,7 +86,7 @@ func main() { } if *writeAddr { - fmt.Printf("%v\n", discover.PubkeyID(&nodeKey.PublicKey)) + fmt.Printf("%x\n", crypto.FromECDSAPub(&nodeKey.PublicKey)[1:]) os.Exit(0) } @@ -111,21 +112,38 @@ 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, realaddr, "", restrictList); err != nil { + if _, err := discv5.ListenUDP(nodeKey, conn, "", restrictList); err != nil { utils.Fatalf("%v", err) } } else { - if _, err := discover.ListenUDP(nodeKey, conn, realaddr, nil, "", restrictList); err != nil { + db, _ := enode.OpenDB("") + ln := enode.NewLocalNode(db, nodeKey) + cfg := discover.Config{ + PrivateKey: nodeKey, + NetRestrict: restrictList, + } + if _, err := discover.ListenUDP(conn, ln, cfg); err != nil { utils.Fatalf("%v", err) } } 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/cmd/clef/4byte.json b/cmd/clef/4byte.json new file mode 100644 index 0000000000..5603d5931d --- /dev/null +++ b/cmd/clef/4byte.json @@ -0,0 +1 @@ +{"0x22ec1244": "shaBid(bytes32,address,uint256,bytes32)", "0xcae9ca51": "approveAndCall(address,uint256,bytes)", "0x4fb2e45d": "transferOwner(address)", "0x7741b4ec": "RandomNumberFromSeed(uint256)", "0x267127ec": "getTokenSettings()", "0xb7213bd4": "readLog(uint256)", "0x3018205f": "getController()", "0xc8edf65e": "GetAndReduceFeesByFraction(uint256)", "0xeec2b628": "beforeExecute(address)", "0xfc0c546a": "token()", "0x40a3d246": "toggle()", "0x70983e91": "startBoardProposal(uint256,address)", "0x6b5caec4": "setBot(address)", "0x78524b2e": "halveMinQuorum()", "0x2c60a055": "MapTest()", "0xc2fb8f36": "TinyHuman(address,address,address)", "0x6822abae": "getMinimumCallCost(uint256)", "0x6f9fb98a": "getContractBalance()", "0x5c17f9f4": "approve(address,uint256,bytes)", "0x504ac982": "transfer(string,string)", "0x06e53f47": "whichChainIsThis()", "0xf359671c": "withdrawWithReference(address,uint256,string)", "0xf97d0591": "parseTimestamp(uint256)", "0xd3c0715b": "vote(uint256,bool,string)", "0x6b069710": "scheduleCall(address,bytes,uint256,uint256,uint8)", "0x37ae43a3": "BetOnHashV81()", "0xab519020": "calcShare(uint256,uint256)", "0x6572ae13": "calculateWinner(uint256,uint256)", "0x6aaba012": "ErrorGenerator()", "0xfe05e8b1": "assertFact(uint256,string)", "0x6e940a29": "changeHost(address)", "0x669ee827": "RegisterDevice()", "0x6f4dd69c": "testSetBalanceUpdatesSupply()", "0x4401a6e4": "safeSend(address)", "0x27dc297e": "__callback(bytes32,string)", "0xe4dedc7f": "DeleteContract()", "0x7fef036e": "totalEntries()", "0x64325ddb": "currentClaimPrice()", "0x2fc0aad3": "isNumericString(string)", "0xbc45d789": "setConfigUint(int256,bytes32,uint256)", "0xee95feaf": "isSeller(address)", "0x358d5dc2": "getIsCashed(uint256,uint256)", "0x1397fdbd": "getShares(address,bytes,int256[])", "0x2d8c1c35": "level_up()", "0x24600fc3": "withdrawFunds()", "0x05f8b6f5": "_rewireIdentities(bytes32[],uint256,uint256,uint32)", "0x1840f0ca": "countVotes(uint256)", "0xd44aadf7": "initROS()", "0xca1d209d": "fund(uint256)", "0x5fa513d5": "findPtr(uint256,uint256,uint256,uint256)", "0x3c314a91": "playerGetPendingTxByAddress(address)", "0xd5582205": "getCertifiedStudentAtIndex(uint256)", "0xe45ebe93": "checkVoteStatus()", "0xcd9380d5": "testSetBalanceSetsSupplyCumulatively()", "0x637e86eb": "totBOTs()", "0x5bb47808": "setFactory(address)", "0x674cc1f5": "getMarketHashes(bytes32[])", "0x648bf774": "recover(address,address)", "0x0221038a": "payOut(address,uint256)", "0x4016535a": "parseBlock(bytes,uint256)", "0xa3908e1b": "convert(uint256)", "0xd9e7ee1c": "new_game(uint256,uint256)", "0x929e626e": "getShareDistribution(bytes32)", "0xa20495d3": "Managed()", "0xd409ddda": "EtherizationUtils()", "0xcb2b9031": "addressToBytes(address,address)", "0xfff3c457": "readMessages(uint256)", "0x043753ba": "makeDecision(uint256,bool)", "0x85b4bb53": "getSettings()", "0x60726abb": "copy()", "0xe50d0473": "SetRank(uint8,address,uint16)", "0x54ae8492": "CustodialForward()", "0xd6d02c51": "whois(string)", "0xcb712535": "_transferFrom(address,address,uint256)", "0xb152f19e": "getFirstSchedulableBlock()", "0x9334ab61": "Infos()", "0x88a49164": "testErrorUnauthorizedTransfer()", "0x17db59a4": "dEthereumlotteryNet(address,address,address)", "0xf85aefba": "testBitsSetFailIndexOOB()", "0xae99847b": "daylimit(uint256)", "0xd93e7573": "disown(bytes32)", "0xa5468081": "Pyramid(address)", "0x00e7d289": "registerListening(address)", "0x57ee24af": "getNum(bytes32,uint256)", "0xdaea85c5": "approve(address)", "0x36ffa905": "getMyProposals()", "0x7143059f": "getParticipant(address)", "0x55ff440a": "castStringToUInt(string)", "0x6a4a6b6e": "_myAddressHelper()", "0xb67fabdf": "scheduleTransaction(address,uint256,uint256,bytes)", "0xbcca1fd3": "changeVotingRules(uint256,uint256,int256)", "0x1d3390a1": "carefulSendWithFixedGas(address,uint256,uint256)", "0x45104b16": "EXECUTION_GAS_OVERHEAD()", "0xa26759cb": "addFunds()", "0x232523e8": "forceDivestOfAllInvestors()", "0x7e904a48": "getNumContents(uint256)", "0xb69c0896": "BaseScheduler(address,address,uint256)", "0xc6ed8e1b": "getApprovedProxys()", "0x4d1f8c31": "owner(uint64)", "0x17c65aa7": "getMaxLossAfterTrade(address,uint256,int256,int256)", "0x2c02d622": "precalculate()", "0xa035b1fe": "price()", "0x43b0e8df": "set(uint256,uint256,uint256)", "0x9b5fde7d": "payOut(uint256,string)", "0x89fcd099": "getApproval(address,address)", "0x4c0eceb5": "plusOnePonzi()", "0x880cdc31": "updateOwner(address)", "0xdab80d6f": "addSponsor(address)", "0x0fcda174": "getAccountTokenBalance(address,address)", "0xa55cab95": "getName(uint8,uint8)", "0x934db458": "Big()", "0xeb782d8c": "ContentSeries(address)", "0xdbfef710": "getDefaultRequiredGas()", "0x4f09eba7": "proxyApprove(address,uint256,bytes32)", "0xf4c5ab7c": "validateCallGas(uint256,uint256)", "0x376fe102": "userId(address)", "0x922dd59a": "icapTransfer(bytes,address,bytes,uint256)", "0x7318b453": "setVotetUntil(uint8)", "0xb8c86aa6": "getArraySettingResult()", "0x37bdc99b": "release(uint256)", "0x7cbcc254": "__reset__()", "0x37664643": "retractLatestRevision(bytes32)", "0x4b031d0f": "shortSellShares(bytes,uint8,uint256,uint256)", "0xad8d5f48": "exec(address,bytes,uint256)", "0x2f95b833": "requiredStackDepth()", "0xe3848e5b": "thing(string,string,string)", "0xaa272d4b": "getNodeIndexId(bytes)", "0xd7f746ce": "tickingBomb()", "0x3b84edbd": "setRNG(address)", "0x1fb2f2a0": "testUpdateLatestRevision()", "0xb7fba4d3": "getProxy(address)", "0x4b8e1ba8": "isMinter(int256,address)", "0xba4c206e": "removeCertificationDocumentInternal(address,bytes32)", "0x884b5dc2": "fill(uint256[])", "0x88017e05": "setContribution(uint256)", "0x1ff517ff": "totalDebt(address)", "0xd0315658": "getShareDistributionWithTimestamp(bytes)", "0x7d03f5f3": "newGame()", "0xb7538f3e": "ChangeClient(address)", "0xbf4d89b5": "parseInt(string,uint256)", "0x7b55c8b5": "scheduleCall(address,bytes4,bytes,uint8,uint256[4])", "0x350d141e": "getWasApprovedBeforeDeadline()", "0x27960c5f": "validateEndowment(uint256,uint256,uint256,uint256,uint256,uint256,uint256)", "0xb774d3d7": "BankOwner_GetDonationsBalance()", "0x267b6922": "entries(bytes32)", "0x08b7c13b": "getExists(bytes20)", "0x7e7a2fbf": "contribute_toTheGame()", "0x5b86914d": "bet_value()", "0x0e1087c3": "getMarketMakerFunds()", "0xf7149220": "RNG()", "0x345006b6": "getGenerationForCall(address)", "0xc4b14e0b": "getSignature(bytes32)", "0x419945f8": "ExpiringMarket(uint256)", "0x41868769": "CallAborted(address,bytes)", "0x29092d0e": "remove(address)", "0x746c9171": "m_required()", "0x5020dcf4": "convertToEach(uint256,string,uint256)", "0xa06db7dc": "gracePeriod()", "0xbf8fc670": "sendToAggregation(uint256)", "0xf14fcbc8": "commit(bytes32)", "0xa538d287": "getMinMax()", "0xcae523c1": "testOwnedTryAuthUnauthorized()", "0x04d10f1c": "isValidChainyJson(string)", "0x9ba5b4e9": "getEventHashes(bytes32[])", "0xfedfd535": "Config()", "0x42ce0f30": "testThrowUpdateLatestRevisionNotOwner()", "0x31be6985": "testBitXorSuccess()", "0x173cb7de": "getNumReleasesForNameHash(bytes32)", "0xd90a88cd": "getContentReplies(uint256,uint256)", "0x92eefe9b": "setController(address)", "0x052b81c7": "releaseBadges()", "0xb2855b4f": "setFeeAddr(address)", "0x19a9c2f1": "generateId(string)", "0xfa9acb05": "addressInArray(address,address)", "0x3da5c3ce": "puzzle(address,bytes32)", "0x7a427d98": "forceReturn()", "0x70e71ea3": "etherandomSeedWithGasLimit(uint256)", "0xd7a58658": "changeHouseedge(uint8)", "0x72b75585": "getOriginalClient()", "0xf802075f": "requiredEndowment()", "0x7997b997": "doMelt(uint256,uint256)", "0x6d5433e6": "max(uint256,uint256)", "0xb651cbaf": "add_level(address,bytes)", "0xb4d6d4c7": "getPackageData(bytes32)", "0x90e3c278": "getShares(uint256[128])", "0x179b73da": "killBoardProposal(uint256,address)", "0xc944a38e": "CharlyLifeLog(string,int256)", "0xe1c66292": "Create(uint32,address)", "0x69c8b344": "ownedToken(address)", "0xabcf1328": "InterestBank()", "0x532e7e6a": "calcEarningsSelling(bytes,uint256,uint256[],uint8,uint256)", "0x43d24a5e": "addUpdater(address)", "0xd1feca67": "addSpendingRequest(address)", "0x2d34ba79": "setup(address,address)", "0xcb14d93b": "getHash(bytes,address,uint256)", "0x309424fe": "get_all_names()", "0x96c52fc3": "____forward(address,uint256,uint256,bytes)", "0xde39acea": "get32(bytes,uint256)", "0xf3dd3d8a": "newCurrency(string,string,uint8)", "0x2432eb23": "testThrowRetractLatestRevisionNotUpdatable()", "0x7fcf3a2f": "throwFooBar()", "0xabe9f569": "oraclize_getPrice(string,uint256)", "0x41ee903e": "clear(uint256,uint256)", "0xd249a52e": "update(bytes,uint256[],uint256[])", "0xc3d014d6": "setContent(bytes32,bytes32)", "0x3ac5cb73": "GeometricPonzi()", "0x4a1aa767": "claim_victory(uint256,uint8,uint8,uint8)", "0xce592586": "setThresold(uint256,uint256)", "0x63deb2c5": "changeMemberAddress(address)", "0x2e6e504a": "trusteeWithdraw()", "0xcfed9199": "timePassed(uint256)", "0xb782fc9b": "getFirstActiveDuel2()", "0x35b28153": "addAuthorization(address)", "0x46f7a883": "BuyTicket(uint8,uint8,uint8)", "0x83c51a38": "thesimplegame()", "0xfa28ba0d": "validateReleaseLockfileURI(string)", "0xa7b2d4cb": "remove(int256,address)", "0x010731c0": "sendCryptedHand(bytes32)", "0xe9e99d81": "getChannelFeed(address,uint256,uint256,uint256)", "0x4e30a66c": "safeToAdd(uint256,uint256)", "0x2c4e591b": "totalGames()", "0xa3221c8e": "step8()", "0x783ce458": "expmod(uint256,uint256,uint256)", "0xe417291b": "undelegateDAOTokens(uint256)", "0x8e5d97a2": "releasePendingTransfer(uint256)", "0xbc5ff5e1": "oraclize_query(string,string[4],uint256)", "0x38f77d69": "getDistributeProfitsInfo()", "0xbb510a77": "createChannel(address,uint256)", "0x650955d4": "HashToken()", "0xa8484938": "doApprove(address,uint256)", "0x64ed31fe": "authVotes(address)", "0xf7ae9421": "checkInvestorBalance(address)", "0xba904eed": "removeRegistrar(address)", "0xdce4a447": "at(address)", "0xdb4cacec": "Other()", "0x3647b87a": "buildFactory()", "0xa51aea2d": "changeMaxMultiplier(uint256)", "0x4974bc27": "download()", "0xf8a8fd6d": "test()", "0xd8c90762": "addTrustedIssuer(address,string)", "0xdf6c13c3": "getMinFunding()", "0x867904b4": "issue(address,uint256)", "0x1531c267": "fipsRegisterMulti(uint256,address,bytes)", "0x40a49a96": "searchSmallestInvestor()", "0x61bffe01": "addIdentities(bytes32[],bytes32[])", "0xf77a0923": "BitcoinProcessor(address)", "0xd02528e6": "GetGameIndexesToProcess()", "0x9f927be7": "getNextCall(uint256)", "0xd8162db7": "lockedUntilBlock()", "0x36dfe260": "payOneTimeReward()", "0xc5b1a53c": "deposit(bytes16[],uint64)", "0xc2b6b58c": "isClosed()", "0xc88cc6ac": "getCertification(address)", "0x77ac3da5": "oraclize_query(uint256,string,string[1],uint256)", "0x70ab8ba8": "creditUpdate()", "0xd3ea3322": "testBuildTokenSystemCost()", "0x72388610": "paybackAll()", "0xca6d56dc": "addMember(address)", "0x0994a0a0": "DSTokenTest()", "0xe53e04a5": "refillGas()", "0xc1d5e84f": "addNewUser(address)", "0x89ed0b30": "setOraclizeGas(uint32)", "0x02ba8742": "sendCoins(address,uint256)", "0xb0de1cb7": "publish(uint64,bytes,uint64)", "0x0e13b9af": "getValue(uint8,uint8)", "0xb3dfcdc3": "Contribution(uint256)", "0xa9b35240": "packageExists(bytes32)", "0xd1d3bb92": "testSetPkg()", "0x97297467": "checkAndVerify(bytes)", "0xe31bfa00": "next_id()", "0x9948e493": "calcMarketFee(bytes,uint256)", "0xd148288f": "setHoldingPeriod(uint256)", "0xc032dc30": "execute(uint256,address)", "0xdad99989": "burnCoins(address)", "0xb1999937": "leapYearsBefore(uint256)", "0xa6cbcdd5": "numSignatures(bytes4)", "0xaca66aec": "DVIP()", "0x20bf0c52": "Derived(uint256)", "0x693ec85e": "get(string)", "0x0411bca8": "getChallengeAnswerResult(uint256)", "0x61584936": "sealedBids(bytes32)", "0x2f1927cb": "prepareRoll(uint256,uint256,uint256)", "0xeaa1f9fe": "reqisterListening(address)", "0xb623f5e5": "checkSetCosignerAddress(address)", "0xa88c5ef7": "NextPayout()", "0x66ad484c": "newfirst_player(address)", "0xb4022950": "collectFeesInEther(uint256)", "0xbff0fbb8": "calculateMeat(uint256)", "0xd62b255b": "setOwner(address,string)", "0x2fd6d40b": "getBetValueByGamble(uint8)", "0x3b0506f7": "getVoteByAddress(address,uint256)", "0xbddd3a6b": "step7()", "0x67fbd289": "destroyTokens(uint256)", "0x9844347b": "createCertificate(bytes,bytes,uint256,bytes)", "0x5e68ac2c": "Kingdom(string,address,address,address,uint256,uint256,uint256,uint256,uint256)", "0x8ba9f354": "testClearBitSuccess()", "0x48027610": "transferPaidOut(address,address,uint256)", "0x912de8de": "fixBalance()", "0x04509918": "scheduleCall(address)", "0x7cf0ffcb": "forceDivestAll()", "0x3b3b57de": "addr(bytes32)", "0xeb7c6f72": "step6()", "0xfe6f0d82": "testConstructorEvent()", "0x55b62dcf": "getThresold(uint256)", "0xfbae5e7d": "Investors(uint256)", "0x29e206bd": "forceDivestAll(bool)", "0x6a226a49": "addMessage(string)", "0x8e2a6470": "allocateShares(address,uint256)", "0xe6e7237f": "claim_time_victory(uint256)", "0x17a601b5": "MAX_STACK_DEPTH_REQUIREMENT()", "0x87fd0421": "TheEthereumLottery()", "0xc17e6817": "sendSafe(address,uint256)", "0xa5dfee67": "testThrowsCreateNewRevisionNotUpdatable()", "0xb35893f3": "setExporter()", "0x1ceea715": "GetMyInvestFee()", "0xb78bd4a5": "breakCookie(string)", "0x05215b2f": "createStandardToken(uint256)", "0x2632bf20": "unblockMe()", "0x5292af1f": "sendBalance(address)", "0xc2e9fab3": "SubUser()", "0x6493d7fc": "CircuitBreaker(address,address,uint256,uint256)", "0x4f896d4f": "resolve(uint256)", "0x16870257": "getTileDescription(uint8,uint8)", "0x3ef87414": "getRevisionCount(bytes20)", "0x747586b8": "setInt(int256)", "0x5714f6a1": "getTotalAvailableRelays()", "0x99154b49": "ARK()", "0x1efb17ee": "changeHouseAddress(address)", "0x354d7e40": "Payout()", "0x2da0d1ea": "etherSold()", "0xea46193e": "getEtherBalance()", "0x11fe773d": "memcpy(uint256,uint256,uint256)", "0x1e701780": "MICRODAO(address,uint256,uint256,uint256,address)", "0x1c31f710": "setBeneficiary(address)", "0x0a4caed0": "getChannelByRank(address,uint256)", "0xf3125a1f": "deposit(address,uint256,bytes,uint256)", "0x00e46700": "setMinimumPassPercentage(uint8)", "0x92d282c1": "Send()", "0x89d59ee5": "createPersonalDepositAddress()", "0xbe1c766b": "getLength()", "0x70a08231": "balanceOf(address)", "0xae0a6b28": "signature(string,bytes32)", "0xb3485dca": "UpdatePrice(uint8,uint32)", "0xf8ec4bf2": "setAllowTransactions(bool)", "0x53d97e65": "setPrizes(uint32[])", "0xd1b1a22b": "set(string,uint256[],uint256[],uint256[],bool[],uint256[])", "0x96286cc9": "isTokenOwner(address)", "0x154af6b1": "sendShares(uint256,uint8,uint256,address)", "0xbe2430fe": "sendValues()", "0x57a373a1": "uintInArray(uint256,uint256,int256,uint256[],uint256)", "0x8fd28bcf": "testFailAuthorityAuth()", "0x89ef40e7": "numberOfHealthyGenerations()", "0x23e9c216": "setBounty(address,string,uint256)", "0x71dd99fe": "BigRisk()", "0x1e9fcc77": "activateAllowance(address,address)", "0x561e91a1": "makeBet()", "0x32d2fb9f": "getRefRemainingTime(uint256)", "0x992c870d": "transferName(bytes,address)", "0x6b3fdc5a": "oraclize_setNetwork(uint8)", "0x2ea459b8": "claimThrone(bytes)", "0x33a99e04": "selectWinner()", "0x3b49a77b": "hasConfirmed(bytes,address)", "0xa352f1a8": "calcSHA3(bytes)", "0x4bb4b260": "cashAllOut()", "0xb89a73cb": "isShareholder(address)", "0xba5a2d33": "exitPool(address)", "0xddd41ef6": "transferDirector(address)", "0xa06cab79": "Registrar(address,bytes32)", "0x871113c3": "oraclize_query(string,string[1],uint256)", "0x1f0f711f": "discontinue()", "0x632f0ba6": "descriptionHashes(bytes)", "0x980e8c81": "FutureBlockCall(address,uint256,uint8,address,bytes,uint256,uint256,uint256)", "0x4ae8c55f": "getWwLength()", "0x82fc49b8": "setCosignerAddress(address)", "0xc4bd8ebc": "num_monsters()", "0x0381cb3b": "setRowcol(uint256,uint256[2])", "0x124eaee6": "Identity()", "0x3f4be889": "callContractAddress()", "0xef3a6031": "testBaseToken()", "0x954ab4b2": "say()", "0x1b855044": "getHash(uint256,uint256)", "0xd9d73887": "Diana()", "0x5103a5a3": "certify(address,bytes32)", "0x51560da9": "topDogInfo()", "0xf3ee6305": "removeCertificationDocument(address,bytes32)", "0x049ae734": "scheduleCall(address,bytes4,uint256,uint256,uint8)", "0xd8a8e03a": "move(uint256,address)", "0xc3c5a547": "isRegistered(address)", "0x06005754": "nameRegAddress()", "0xbe592488": "validateName(bytes)", "0x0eecae21": "draw()", "0xac3e7d24": "addChainyData(string)", "0xfd83f3e3": "QueueUserMayBeDeliveryDroneCotnrol()", "0x7772a380": "isInGeneration(address,uint256)", "0xeb1ff845": "changeId(uint256,uint256,uint256)", "0x9cc9299e": "killSwap()", "0x1e2ca0f3": "updateLeftLottery(address)", "0x998446a8": "acceptRequest(uint256,bytes)", "0x8e1ffb19": "testThrowsRetractLatestRevisionEnforceRevisions()", "0x9935935f": "setResolveHandler(bytes,address)", "0xcd4b6914": "getRandom(uint256)", "0xc08dd1dc": "IOU(string,string,uint8)", "0xbe4054b9": "commitReading(address,uint256,uint256,string)", "0xbc21ce9d": "Aggregation()", "0x6e173a7f": "storeBlockHeader(bytes,bytes)", "0x114d69b2": "setCRLaddr(address)", "0x3fa4f245": "value()", "0x69573648": "remove(bytes,bytes)", "0x7fee4ecb": "GAS_PER_DEPTH()", "0x591c515f": "append(string,string)", "0x727b1cd6": "next_draw(bytes32,uint256,uint256,uint256,uint256,uint256)", "0xc60ce271": "findNextMinute(uint256,bytes)", "0xd337616e": "resetLottery()", "0xdacaeb07": "pledge(bool,uint256)", "0xb29c2493": "token(uint256,string,uint8,string)", "0x61047ff4": "fibonacci(uint256)", "0x8f367001": "numTokensAbleToPurchase()", "0x12cc08f2": "getPackageReleaseHashes(string,uint256,uint256)", "0x67a59d91": "scheduleCall(address,bytes,bytes,uint256,uint256,uint8)", "0xe6c3b4ab": "testBalanceAuth()", "0xd526b9bd": "_allow()", "0x29de91db": "setMsg(address,uint256)", "0xd1cf113e": "multiAccessSetRecipient(address)", "0xc2412676": "Token()", "0x391f2e96": "InvestCancel()", "0xc0ae6a3a": "ultimateOutcomes(bytes)", "0x202d6eaf": "addInvestorsValue(uint256)", "0x30b9af98": "withdrawFunding()", "0xe80bd3e5": "addCertificationDocumentToSelf(bytes32)", "0xf4e36afd": "findThroneByNameHash(uint256)", "0x30677b83": "multiplierFactor()", "0x590528a9": "sellShares(uint256,uint8,uint256,uint256)", "0x01cceb38": "setExpiry(uint256)", "0x779beca0": "getNumOfSalesWithSameId(bytes)", "0xac940823": "betOnLowHigh(bool)", "0x06961560": "DAO(address,uint256,uint256,uint256,address)", "0xd42bf301": "doTriggerTryAuth()", "0xfa566ddd": "doAllowance(address,address)", "0x6677febe": "get_all_accepted()", "0xaa67c919": "depositFor(address)", "0xf28386bf": "Nexium()", "0x77e4fb04": "testFailNotEnoughValue()", "0x12b58349": "getTotalBalance()", "0xc0d2834b": "DataSource()", "0x3e82055a": "addSignature(uint256,bytes16,bytes)", "0xcff2fa42": "_returnFee(address,uint256)", "0xa056469a": "extractFeeLength()", "0xc98031be": "hintURL(int256,bytes32,string)", "0x6ebbe863": "updatePublishContract(address)", "0x08216c0f": "createHumanStandardToken(uint256,string,uint8,string)", "0xc36af460": "getLatest()", "0xdb5b4183": "oracleOutcomes(bytes,address)", "0x0b5ab3d5": "destroyDeed()", "0xe1c7392a": "init()", "0x4ca1fad8": "addRequest(uint256)", "0x305b73d9": "configure(address,address,uint256,uint8,bytes32,bytes32)", "0x9077dcfd": "submitCoding(string,uint256)", "0x38fff2d0": "getPoolId()", "0x07bc6fad": "withdraw(address,uint256,bytes32,uint256)", "0xfbf58b3e": "transfer(string,address)", "0x1d8b70da": "order_received(string)", "0x0b3ed536": "claimDonations(uint256)", "0x6f374a12": "setBool()", "0x0ca35682": "recover(uint256)", "0x3ae7cdfa": "fipsLegacyRegister(bytes20[],address)", "0xe6c1beb4": "prepend(address)", "0x776d62f6": "costs()", "0xe4690a0b": "popRequest()", "0x74eb9b68": "isAccountLocked(address)", "0x7d32e7bd": "transfer(address,bytes32)", "0xdf2f0a4a": "getDecisionBlockNumber(uint256,uint256)", "0xc494f71a": "LedgerFund(uint32,uint32,uint64,uint64)", "0x446d5aa4": "getAttributes(address)", "0x4cdc6a73": "Marriage()", "0x677cee54": "SafeConditionalHFTransfer()", "0x7b48ba20": "testThrowDisownNotOwner()", "0x1288c42a": "Prism()", "0xe8b13c44": "getChainyTimestamp(string)", "0xe4c2db06": "getPreviousFile(bytes)", "0xf0586f0d": "doThrow(bool)", "0xc1b06513": "registerEvent(bytes32[])", "0x521eb273": "wallet()", "0x32254992": "getPrevHash(int256)", "0x1fd96b69": "ManagedAccount(address,bool)", "0xabf74a93": "pitFee()", "0xa480ca79": "collectFees(address)", "0xa0bde7e8": "getShareDistributionWithTimestamp(bytes32)", "0xff27c476": "shiftBitsRight(bytes,uint256)", "0x172d8a30": "setDirectorLock(uint256,uint256)", "0xf262de8c": "add_staircase(uint16)", "0x990f3f53": "computeResponseSecondHalf(uint256,uint16)", "0x26745909": "PRNG_Challenge()", "0xcacc24eb": "transferFromViaProxy(address,address,address,uint256)", "0x94f3f81d": "removeAuthorization(address)", "0x3f0ec70b": "RequestFactory(address)", "0xa2a8336f": "claimEtherSigner(uint256)", "0xaa5d4719": "getTransferable(bytes20)", "0x23cd7cd5": "Model()", "0x3fb0b2c9": "CancelRoundAndRefundAll()", "0xd5fa2b00": "setAddr(bytes32,address)", "0xa0f61310": "FakeRelay(bytes)", "0x4ea66c38": "buyinInternal(address,uint256)", "0xbe040fb0": "redeem()", "0xb845c9a2": "WEI()", "0x26a7985a": "getMaximumCallGas()", "0x06661abd": "count()", "0xc89f8f08": "testGetController()", "0x81baf820": "BlockScheduler(address)", "0x9801cb8e": "ProofOfExistence()", "0xeb7492d1": "testTotalSupply()", "0x3dfb4843": "renewDeed(bytes32)", "0xc3fa5f93": "BlockScheduler(address,address)", "0x7958533a": "meta(uint256,bytes32)", "0xa1a66e56": "deductFunds(uint256)", "0xaf92a693": "addRegistrar(address)", "0xb2aac51f": "lookupUser(string)", "0xd70cf105": "moveBalance(address,address,uint256)", "0x2afb21bc": "InvestWithdraw()", "0x6d09e2ec": "commitCurrency(address,uint256,uint256)", "0x7b1a4909": "transferETH(address,uint256)", "0x96c824a8": "createAccountFundContract()", "0xe0a70811": "restart(bytes20,bytes)", "0x22057bc7": "getAllRevisionBlockNumbers(bytes20)", "0x6af2da2f": "testKeyedHash()", "0x7f6d8955": "RegisterOne(uint32,address,address)", "0x65f27bea": "testSubBalanceFailsBelowZero()", "0xa2f16d80": "dexWithdrawCollectedFees()", "0xc179520c": "ManageAccount()", "0x2672b3e2": "SplitterEtcToEth()", "0xe839e65e": "query2(string,string,string)", "0x39f64b52": "calcTokenPrice()", "0x4ef5710a": "WatchNumberOfPlayerInCurrentRound()", "0x3017fe24": "callAPIVersion()", "0x2977b1b1": "testAllowanceStartsAtZero()", "0x531c1b33": "getOperatingBudget()", "0xb7f2f33c": "transferRightIfApproved(address,bytes)", "0x00873367": "comparisonchr(string)", "0x2a0d79ef": "totalSupply(bytes)", "0xa715ff59": "EtherandomProxy()", "0xd6ca8ccb": "disown(bytes20)", "0x6ad2a0b3": "buildContract(address)", "0x45596e2e": "setFeeRate(uint256)", "0x0e97cfdf": "placeOrder(uint256,uint256,uint256)", "0x9549355e": "oracalizeReading(uint256)", "0x8d7af473": "numberOfProposals()", "0x728af7ec": "getInterest(uint256,uint256)", "0x11b9fee8": "ForkChecker(uint256,bytes32)", "0xd850288b": "etherlist_top()", "0xf4dc2d21": "Deed(uint256)", "0xf8b11853": "getGenerationStartAt(uint256)", "0x7c7a52bf": "newChallenge(uint256,address)", "0xd2d4bd72": "getCrossRate(bytes,bytes)", "0xe9b93569": "OwnerGetFee()", "0xfb72d24e": "shift_right(uint64,uint256)", "0x112e39a8": "scheduleCall(uint256)", "0x6c494843": "multiAccessChangeOwnerD(address,address,address)", "0x313ce567": "decimals()", "0x9bac8602": "testFailAddBalanceAboveOverflow()", "0xa70a9ad7": "switchDeity(address)", "0x6a61e5fc": "setTokenPrice(uint256)", "0x990c8f79": "returnValue()", "0xa4136862": "setGreeting(string)", "0x0af4626d": "testRetract()", "0x5e11544b": "newPeriod()", "0xdc206e5f": "oraclize_query(uint256,string,string[])", "0xcaa648b4": "getTotalValue()", "0x20bfec70": "WatchFees()", "0x62a0b56b": "testUnset()", "0x42f6e389": "isModule(address)", "0x769796fe": "resetAction(uint256)", "0x402e6230": "getTotalGambles()", "0xe8a1c08f": "nibbleToChar(uint256)", "0x1aa3a008": "register()", "0x96d02099": "rsplit()", "0x83324e8c": "numGroups()", "0x72c7c85a": "minority()", "0xb8d94b95": "buildDSNullMap()", "0xe039e4a1": "getOwner(uint8,uint8)", "0x625cc465": "baseDonation()", "0x77372213": "setName(bytes32,string)", "0xa7dfc874": "unregister(bytes,address,uint256,bytes)", "0x37f4c00e": "anchorGasPrice()", "0xb2bfd948": "checkNumbers(uint8[3])", "0x512f1e64": "orderBookLength()", "0xafed762b": "toSlice(string)", "0xbb6a1427": "testThrowRestartEnforceRevisions()", "0x734d8287": "unclaimedFees()", "0xf295206f": "_unsafeSend(address,uint256)", "0x69d01268": "concatUInt(uint256)", "0x0494630f": "oraclize_query(uint256,string,string[4],uint256)", "0x13fc6ac2": "getEventData(bytes32)", "0xbff974e8": "getContentReplies(uint256)", "0x18921de4": "addSignature(string,uint256[],uint256[],uint256[],bool[],uint256[])", "0xa87e7552": "isValid(bytes,bytes)", "0xb8d3bfe3": "MeatGrindersAssociation(address,address,uint256,uint256,uint256,address)", "0x61461954": "execute()", "0xecb0256b": "relayTx(bytes,int256,int256[],int256,int256,bytes,int256,int256[],int256,int256)", "0x7cdbae63": "addRegistryIntoTagsIndex(address)", "0x1f4e996b": "challenge(bool)", "0x0eb0afa6": "createDebt(address,address,uint256)", "0x5f6a1301": "clearPending()", "0x305a762a": "getTicketsCountByBuyer(uint256,address)", "0x724ae9d0": "getMinInvestment()", "0x1e39499d": "scheduleCall(address,bytes,uint256)", "0x4f197ee7": "transferPackageOwner(string,address)", "0x7e3faec1": "GoldTxFeePool(address,address,bytes)", "0x8d68cf59": "sendFunds()", "0x83eed3d5": "queryN(uint256,string,bytes)", "0x15c91115": "pbkdf2(bytes,bytes,uint256)", "0xeb121e2f": "update(uint256,uint256[101][])", "0x5e44daf3": "vote(uint256,int256)", "0xac562666": "freezeCoin()", "0xb0166b04": "testTransferringMkr()", "0x631de4d6": "replace(address,address)", "0x4bd70ea3": "testFailGetUnset()", "0xf738e5ca": "ownerTakeProfit()", "0xc6236a5c": "scheduleCall(bytes,uint256,uint256,uint8,uint256)", "0x119aa5c8": "checkForward(bytes)", "0x541aea0f": "put(uint256,uint256)", "0x6386c1c7": "getUserInfo(address)", "0x4e209678": "testFailBreach()", "0xe9fe799e": "registrantRemove(address)", "0x2aee19c7": "testCreateWithNonce()", "0xa0ec4e09": "getUltimateOutcomes(bytes32[])", "0x4d9e4e22": "Etheria()", "0xa6b513ee": "finalPrice()", "0x82f0d875": "makeHash()", "0x78ae88d1": "newDeal(uint256,uint256,uint256,uint256,uint256)", "0x177766e6": "getOptionChain(uint256)", "0xf1173928": "RemovedFromGeneration(address,uint256)", "0xea2ea847": "testChallengeFinalize()", "0xbd35d570": "GAS_TO_COMPLETE_EXECUTION()", "0x364ea9e7": "set(uint256,uint256,bool[],uint256[])", "0x17ff0caa": "WeatherBet(uint256,address,address,address)", "0x4e23a144": "fundUser(address,uint256)", "0x144267e0": "refundSecurity(address,uint256,uint256)", "0x31c6c4cf": "transferFromWithReference(address,address,uint256,bytes32,string)", "0x2eb5c61f": "testThrowsUpdateLatestRevisionEnforceRevisions()", "0xde640e19": "Investment(uint256)", "0x9cb8a26a": "selfDestruct()", "0x9c43d950": "registration(uint256,uint256,uint256)", "0xe2fdcc17": "escrow()", "0xc618d15f": "ConvertNumbers(bytes5)", "0x8c98117c": "getBill(uint256,uint256)", "0x2d7788db": "rejectRequest(uint256)", "0xfaab9d39": "setRegistrar(address)", "0xa289673b": "fipsChangeOwner(bytes20,address,address)", "0x54d9d6f8": "findNextDay(uint256,bytes)", "0x008a745d": "claimDividendShare(uint256)", "0x6f4812e2": "testFailControllerInsufficientFundsTransfer()", "0x5e983d08": "setPrices()", "0x798974dd": "getNumProposals()", "0x4ca168cf": "register(bytes,uint256,address,string,uint256)", "0xa1e4d3c2": "MembershipRoster()", "0xd4065763": "returnRemainingMoney()", "0x0c4326a0": "getMajorMinorPatch(bytes32)", "0xeece1e1f": "scheduleShuffling()", "0x226685ee": "Visit()", "0x323082d7": "Vote(string)", "0x0b15650b": "randInt(uint256,uint256)", "0xc9cfac55": "refundCurrency(address,uint256,uint256)", "0xfe4a3ac9": "setExecPrice(uint256)", "0x6a0e605f": "MyToken(uint256,string,uint8,string,address)", "0xb549793d": "scheduleCall(bytes4,bytes,uint256,uint256,uint8,uint256)", "0x85e68531": "revokeAccess(address)", "0x01991313": "scheduleCall(address,bytes4,uint256)", "0x0a6be0e7": "BalancedPonzi()", "0xf463edd1": "createDocument(uint256)", "0xa20c404f": "ModifySettings(uint256,uint256,uint256,uint256,uint256,uint256,uint256)", "0x560bb612": "SignatureValidator(address)", "0xf7654176": "split()", "0x48f05187": "scheduleCall(address,bytes4,bytes,uint256)", "0xf2b904c3": "checkBetColumn(uint8,address,bytes32,bytes32)", "0x7bc0ff20": "setupExportFee(address,uint256)", "0xeb06e65e": "allowanceFromProxy(address,address,address)", "0xfe757fb5": "lastClaimPrice()", "0xa5d0bab1": "buyPartial(uint256,uint256)", "0xda7d0082": "isCertification(address,bytes32)", "0xe570be18": "DVIPBackend(address,address)", "0x54738157": "OwnerCloseContract()", "0xc1e5304a": "CreateNewDraw(uint256,bytes)", "0x0c26e42e": "getReleaseHashForNameHash(bytes32,uint256)", "0x0f7d6673": "Channel()", "0x54ea4000": "identify(address[])", "0x69307c80": "rotateBits(bytes,int256)", "0x78f0161a": "setGreyGreenPrice(uint8)", "0x23b872dd": "transferFrom(address,address,uint256)", "0x578bcc20": "reduceDebt(address,address,uint256)", "0x59e148fc": "getLastOfferId()", "0xb5299ca6": "giveMeat()", "0xae30d35d": "ARK_TROGLOg_1_00()", "0x2d2c44f2": "Vault()", "0xce19419b": "testThrowsSetNotUpdatableNotOwner()", "0xffcf21a9": "eventOracles(bytes,uint256)", "0xf46c50dc": "doFail()", "0x73b55eaf": "registerData(address,int256,bytes32,address)", "0x53770f9a": "isStateless()", "0x4d47feaa": "ShareholderDB(uint256)", "0x40b31937": "pledgeDecline(uint256)", "0x01cb3b20": "checkGoalReached()", "0x62e05175": "setMotionDB(address)", "0xf362d78f": "testBitNotEqualSuccess()", "0xd2531590": "CANCEL_EXTRA_GAS()", "0x9a92b7e7": "EthVenturesFinal()", "0x79b0797c": "AmIPlayer1()", "0x6241bfd1": "Token(uint256)", "0x94a1710d": "testNonOwnerCantBreach()", "0xb466b76f": "fresh()", "0x4a5dddd2": "proxyPurchase(address)", "0xc0a1a949": "x15()", "0xc3b8bfe5": "transferIfNoHF(address)", "0x4a7e049e": "getFullCompany(address,uint256)", "0x481b659d": "permitPermanentApproval(address)", "0x16ce8a69": "setBuilding(uint256,uint256)", "0x1593a8c7": "endLottery()", "0x078c3fa4": "_transferToICAPWithReference(bytes32,uint256,string)", "0xfa3f1e99": "testBlobStoreRegistered()", "0x0b9e9817": "CanaryV7FastTestnet()", "0x6663bbec": "orderMatch(uint256,uint256,int256,uint256,uint256,address,uint8,bytes,bytes,int256)", "0x273bc3c9": "numberOfThrones()", "0x3c84f868": "set(int256,address,uint256)", "0x1ac61e8c": "testBlobCreate()", "0x5ccc3eaa": "roundMoneyUpToWholeFinney(uint256)", "0x0ccec396": "getNumReleases()", "0x6ac6205c": "addDataPoint(int256,uint256,bool,string)", "0x1d124fe4": "setUtils2(address)", "0x4c471cde": "scheduleCall(address,bytes4,bytes,uint256,uint256,uint8,uint256)", "0x52a554a1": "voteBoardProposal(uint256,address,bool)", "0x745a8be2": "flip32(bytes)", "0xbac1e2e0": "testBitsAndSuccess()", "0x25fda176": "notify(address,uint256)", "0x3b8e6f2e": "balanceAt(address,uint256)", "0x60585358": "getByte()", "0xc853c03d": "newDraw(uint256,uint8[3],uint256,uint256,uint256,uint256)", "0x741273d6": "testThrowRegisterContractAgain()", "0x8f2c44a2": "UnicornMilker()", "0x59d96db5": "terminate(uint256,string)", "0x483ba09e": "setBitcoinBridge(address)", "0x74fbbc86": "rate(uint256,uint256,string)", "0x83ea0620": "packageExists(string)", "0xd917deb5": "Donate()", "0x3fc6bc94": "payDAO()", "0x6558488a": "scheduleSetBool(address,uint256,bool)", "0x83e78b31": "bet(uint8,bool,uint8)", "0xeccb15bc": "SatPosition(int256,int256)", "0x7daa10ce": "getMyInfo()", "0x3e4565d2": "testErrorUnauthorizedNameRegister2()", "0x2143da91": "GameOfThrones()", "0xb29f0835": "doIt()", "0xdcc0ccf3": "Dao(address)", "0x70d53be5": "find()", "0x9a828a71": "oracalizeReading(uint256,string)", "0x6a6d31db": "externalEnter()", "0xf8b71c64": "rewardTo(address,uint256)", "0x0399c357": "assignFreeReadings(address,uint8)", "0x81ade307": "query(string,string)", "0xdb83694c": "getSaleInfo()", "0xa6bf3df0": "oraclize_query(string,string[2],uint256)", "0x29605e77": "transferOperator(address)", "0xf29d2f28": "setTokenHolder(address)", "0xa96f8668": "releaseTokens()", "0x8a3bc2bc": "iPropose(bytes,uint256,bool)", "0xd18611d6": "reactivate()", "0x7620a65b": "Publisher()", "0xa268b332": "testBitXorFailIndexOOB()", "0x6b1781b6": "Emergency()", "0x1003e2d2": "add(uint256)", "0x1209b1f6": "ticketPrice()", "0xe5a27038": "Pluton(uint256,string,uint8,string)", "0x22bc3b8e": "getArgument(uint256)", "0x47bdb7f4": "transferDisable(bytes20)", "0x13137731": "testThrowsUpdateLatestRevisionNotUpdatable()", "0x3f3935d1": "confirmReverse(string)", "0xecb4136e": "NotAnotherPonzi()", "0x49e347ae": "getContents(uint256[],uint256)", "0x669dafe8": "toWei(uint256)", "0xc233e870": "isLatestPatchTree(bytes32,bytes32)", "0x7b789b3d": "agreement(bytes,bytes,bytes)", "0x682d3bb0": "pdfCertificateProof(bytes)", "0x42346c5e": "parseInt(string)", "0x3177029f": "approveAndCall(address,uint256)", "0x71ffcb16": "changeFeeAccount(address)", "0xc971442c": "getDBs()", "0x362e2565": "returnDeposits()", "0xe10e274a": "CrazyEarning()", "0x6d705ebb": "register(address,uint256)", "0xbe9a6555": "start()", "0x1ce624d6": "Crypted_RPS()", "0x2c4cb4be": "removeRegistryFromNameIndex(address)", "0x68742da6": "withdrawFunds(address)", "0x18f3fae1": "setOversight(address)", "0x061ea8cc": "countByOwner(address)", "0xd6d22fa4": "MetaCoin()", "0x85654c9c": "setMembershipRoster(address)", "0x8aa33776": "setMsgPrice(uint256)", "0x4dd850fb": "UfoPonzi()", "0x07e00bcb": "kissBTCCallback(uint256,uint256)", "0xa1b7ae62": "setdirectorName(string)", "0xb4d9cc3a": "profitDisperser()", "0x0f24f5c8": "doTransfer(address,uint256)", "0x8d72a473": "deductFunds(address,uint256)", "0x28f03554": "ProcessDividend()", "0x98391c94": "muteMe(bool)", "0x346cabbc": "scheduleCall(address,bytes4,uint256,bytes,uint256)", "0xa42e36c6": "scheduleTransaction(address,bytes,uint8,uint256[5],uint256)", "0x21b36a08": "setFee(uint64,uint256)", "0xd94073d4": "PT()", "0xe8580dd4": "Survey(address,uint256,string,bytes32[])", "0x1f0c1e0c": "getEventTokenAddress(bytes32,uint256)", "0xce8b7151": "isHF()", "0x9bee757b": "requestExecution(bytes,uint256)", "0x775dec49": "keccak()", "0x6673ce2b": "Results_of_the_last_round()", "0x9f87acd0": "exec(bytes32,bytes32,uint256)", "0x02394872": "getLastBlockHeight()", "0x615664ba": "Market()", "0x0d7af726": "addGame(address,string,string)", "0xf4aa1291": "withdrawFundsAdvanced(address,uint256,uint256)", "0x8ed67a44": "setPrice(uint16)", "0x84ebde52": "Under_the_Hood()", "0x5a28340a": "accessOperatingBudget(uint256)", "0x9a89ad65": "within6Confirms(int256,int256)", "0xdfce8ac3": "fipsLegacyRegister(bytes20,address,bytes)", "0x73f310df": "multiAccessRemoveOwner(address)", "0x4cbee813": "logout(string)", "0xd992bd5b": "testResultNotZero()", "0x05b34410": "creationDate()", "0xfed4614b": "funeral(bytes,int256)", "0x58cb7323": "MainnetETCSurvey()", "0xbb504317": "divest(address,uint256)", "0x82381c96": "WatchCurrentMultiplier()", "0xcce81927": "EtherDice(address,address)", "0x70961774": "getBlockCreatedOn()", "0x84a7b223": "Canary(address)", "0x9378a9e2": "setUInt(uint256)", "0xe4360fc8": "getFileListElement(bytes)", "0xe597f402": "create(bytes1,bytes32,bytes)", "0x95d5a1be": "SignatureReg()", "0x33ce7787": "transferInvestorAccount(address,address)", "0x46c52b1a": "blockHexCoordsValid(int8,int8)", "0x3092afd5": "removeMinter(address)", "0x30945443": "update(address,string,string)", "0xc37ff3d9": "sha(uint256,uint256)", "0x29a6f31b": "oraclize_query(uint256,string,string[2],uint256)", "0x227f9633": "addOption(string,address,uint256)", "0x38eaf913": "setDirectorNode(string)", "0xab67aa58": "transferFrom(address,address,uint256,bytes)", "0x0ce3151c": "personUpdateRelation(uint256,string)", "0x216ef940": "proxyUpgrade(address,address,bytes)", "0x76bc21d9": "fireEventLog2Anonym()", "0xf004073a": "performAction(uint256)", "0xdba7ef7d": "Bookie(address,address)", "0xa0469b02": "inputToDigit(uint256)", "0x1d007f5f": "changeDAO(address)", "0x9dcb5c65": "resultsWeightedByEther()", "0x14ab9038": "setTTL(bytes32,uint64)", "0xf4d94699": "EndowmentRetriever()", "0xe74b9d11": "safeToSubtract(uint256,uint256)", "0xd7504385": "validateToAddress(address)", "0x57e2880d": "scheduleTransaction(uint256,uint256)", "0xe73a914c": "setDAO(address)", "0xc47bc007": "add_funds()", "0x37881810": "setCallbackAddress(address)", "0x686f2c90": "collectAllFees()", "0x278b8c0e": "cancelOrder(address,uint256,address,uint256,uint256,uint256,uint8,bytes32,bytes32)", "0xfac34ff6": "throwFoo()", "0x6d98e9fc": "totalWei()", "0xb0bcc610": "scheduleTransaction(address)", "0x665bcc32": "ProcessGames(uint256[],bool)", "0x3fd1f232": "LookAtAllTheseTastyFees()", "0xdd727ea6": "runJackpot()", "0x0acc4382": "getMinDailyWithdrawLimit()", "0x46b207b8": "checkExpiry()", "0xde5d953a": "logSingleIndex(bytes,bytes,uint256)", "0xf504e0da": "load_level(uint16)", "0x4b63e601": "scheduleCall(address,uint256,bytes)", "0x4a71d469": "collectRev()", "0x80db79d9": "StructAndFor()", "0x090637a1": "GetPart(bytes,uint256)", "0xc003b082": "getMyPlayerID()", "0x00a7d6b3": "checkTransferFromToICAP(address,bytes32,uint256)", "0xdcf8113e": "campaignEndedSuccessfully()", "0xd1af8a5a": "LinkerExample()", "0x01fd89a4": "getFlags(bytes20)", "0xa39a45b7": "replaceOwner(address)", "0x0a3b1cd2": "setHotwallet(address)", "0x075fe877": "scheduleCall(address,bytes,uint256,uint256)", "0x3e5fd9b5": "dEthereumlotteryNet(address,address,bool,address)", "0xa6403636": "resolve(uint8,bytes32,bytes32,bytes32)", "0x0b2acb3f": "add(address,bytes)", "0x6d522b19": "multiAccessChangeRequirementD(uint256,address)", "0x4311de8f": "ownerWithdraw()", "0xa99e7e29": "register(bytes,address)", "0x1ed6f423": "changeDescription(address,string)", "0xcd50d44f": "CheckRepresentment()", "0x4c0e207a": "__outputCallback(uint256)", "0xea8a1af0": "cancel()", "0x67387d6b": "testThrowCreateWithNonceExistingNonce()", "0xdc583801": "doubleyour5()", "0xb8077e28": "getTxOrigin()", "0xbfbc793c": "computeNameFuzzyHash(string)", "0x79baa8a9": "BasicIncome_CoFund()", "0xf4dbeb9d": "getCredRanksByContents(address,uint256[])", "0x227185d6": "Send1Get2()", "0x75c4aaa6": "addUnderDog(uint256)", "0xa7abc124": "activate(bool,bool)", "0x8df554b3": "Dividend()", "0x092b25e9": "setOwner(string,address)", "0x67af26fb": "transferOtherFrom(address,address,address,uint256)", "0x4bb278f3": "finalize()", "0xd1e15045": "sendBack()", "0xa4699cad": "resetWithdrawls()", "0xb61d27f6": "execute(address,uint256,bytes)", "0x9772c982": "scheduleCall(address,bytes4,bytes,uint256,uint256)", "0x1b3a8e6f": "directionCount(int256,int256,int256,int256)", "0xd499555b": "getFirstActiveDuel()", "0xb738169c": "betOnOddEven(bool,bool)", "0x411c4e72": "ModifyFeeFraction(uint256)", "0x06f36cc9": "helpBlue()", "0x9e65c7e5": "updateLatestRevision(bytes20,bytes)", "0xb47fa7e0": "DepositLimit(uint256)", "0xf1736d86": "m_dailyLimit()", "0x62ea82db": "bids(address)", "0x4166c1fd": "getElevation(uint8,uint8)", "0x8702735c": "setCapitol(uint256,uint256)", "0x3cc7790a": "GSI()", "0x83f6d9a4": "validateNameInternal(string)", "0x8d99b2eb": "endPoll()", "0x8bbda7e3": "setContent(string,bytes)", "0x52efea6e": "clear()", "0x2581c674": "testBitsOrFailIndexOOB()", "0x05d87fe2": "issueLetterOfCredit(uint256,uint256,uint256)", "0xcbf0b0c0": "kill(address)", "0xf83d96c1": "InsuranceAgent()", "0x8dd5e298": "canEnterPool(address)", "0x2d580ef6": "add(address,bytes32)", "0xeeda149c": "Register(address)", "0xcc25decd": "SampleOffer(address,bytes,uint256,uint256,uint256,uint256,uint256)", "0x428d64bd": "getShares(address,bytes32[])", "0x3c9a4baa": "requestOutput(bytes)", "0x8cae1374": "editBlock(uint8,uint8,uint256,int8[5])", "0x419db07b": "generousFee()", "0x202e3924": "getOperation(uint256)", "0x5ee345e4": "computeEndowment(uint256,uint256,uint256,uint256,uint256,uint256)", "0x7df23b6a": "ReleaseOracle(address[])", "0x9b2ea4bd": "setAddress(string,address)", "0x65093661": "newCommunity(address)", "0x33637d5a": "getPendingBlock(uint256)", "0x7910085d": "fipsIsRegistered(bytes20)", "0x730720b8": "testControllerValidTransfers()", "0xb0c80972": "setBalance(uint256,bool)", "0xdcf537b1": "multiply7(int256)", "0xdf5cc291": "get4(bytes,uint256)", "0x9ae4e388": "ChangeClientTokenAccount(address,bool)", "0x3121369d": "validateRequiredStackDepth(uint256)", "0x1747dfd4": "ContractPlay()", "0x598647f8": "bid(uint256,uint256)", "0xc368109c": "monster_hp(uint256)", "0x7fa22001": "assertEq0(bytes,bytes,bytes)", "0x8e280dce": "findNextYear(uint256,bytes)", "0x39d1f908": "actualBalance()", "0x8143f8a8": "totalGas(bytes)", "0xfe55932a": "setName(uint256,string)", "0x0fbf7151": "startsWith()", "0x4f20f35a": "payExpenses(address,uint256)", "0x705eeb90": "MultipleConstructorTest(bool)", "0x2df8e00d": "becomeMortal(uint256)", "0x645dce72": "updateRelease(uint32,uint32,uint32,bytes20,bool)", "0x1f6e5117": "getCallbackAddress()", "0xf51cbc72": "Level()", "0x64edfbf0": "purchase()", "0x35930e13": "setMinimalRewardedBalance(uint256)", "0x015e4f3a": "getConfigUint(int256,bytes)", "0x2c329e99": "Last_block_number_and_bloctime_used()", "0x6f3a7561": "SimpleAuction(address)", "0x6de00927": "GetUserRank(uint8,address)", "0xbe600276": "move(uint16)", "0x27d6c032": "unregister(bytes)", "0x4188d79c": "releaseExists(string,uint32,uint32,uint32,string,string)", "0x7ba38916": "changeAdminFromBoard(address)", "0x3369dace": "flipTheCoinAndWin()", "0xfa8dc33a": "checkRecordExists(bytes)", "0xebaf7f2f": "returnReward(uint256)", "0xc88961da": "createKingdom(string,address,address,address)", "0x21970c0c": "pay_royalty()", "0xb4a5ef58": "updateDefaultTimeoutPeriod(uint256)", "0x57bcccb6": "revokePermanentApproval(address)", "0xd1d1c8ae": "ConvertNumbers(bytes)", "0xc1c0e9c4": "exec()", "0xcc131be1": "CreateNewDraw(uint256)", "0x75f96ead": "Guess(uint256)", "0x8a5fb3ca": "currentFeePercentage()", "0x550bcd8d": "testThrowUpdateLatestRevisionEnforceRevisions()", "0xa6780857": "fireEventLog0Anonym()", "0x2d0104a5": "updateFirstDuel1(uint256)", "0xcbf1304d": "balances(address,uint256)", "0xdda9939c": "Store(address[])", "0xf41bfa9e": "mint(int256,uint256,string)", "0x044215c6": "token(uint256)", "0x1f903037": "getBytes32()", "0xa6f9dae1": "changeOwner(address)", "0xf9391d24": "AllPayAuction()", "0xabebb7f3": "MarketsContract()", "0x9e1e6528": "uncertify(address)", "0x81788e2b": "addAllowedAddress(address)", "0x4f44728d": "ownerChangeOwner(address)", "0x3da0ac79": "compare()", "0x96e438a1": "reclaimDeposit(uint256)", "0x5fe22c8b": "testFailTransferWithoutApproval()", "0x6835f32c": "build(bytes)", "0x5cac8b27": "amazing()", "0xad605729": "getParticipantCount()", "0xb6294bde": "AdminGetFee()", "0xec81e22e": "returnmoneycreator(uint8,uint256)", "0xc535165f": "revealAndPayout(bytes,bytes)", "0x6e0bd282": "destroy(bytes32)", "0xdda44b10": "buyRecipient(address,uint8,bytes32,bytes32)", "0xd4859dbc": "UniversalFunctionSecure(uint8,bytes32,bytes32,bytes32,bytes32,bytes32)", "0xd2602930": "RockPaperScissors()", "0xa08b3367": "EC()", "0x92d66313": "getYear(uint256)", "0xe49dcee9": "fixTokens()", "0x36555b85": "add(string,uint256)", "0x25010816": "get_length(uint256,uint256)", "0x610d5de8": "validateEndowment(uint256,uint256,uint256,uint256,uint256)", "0x79ce9fac": "transfer(bytes32,address)", "0x3ced516c": "descriptionHashes(bytes32)", "0xcf69df28": "getDataRequestLength()", "0x706dfe54": "getIssueState(uint256,bytes32)", "0x5af77fff": "Contract()", "0x66e5cb50": "stopTransfer(uint256)", "0x5f72f450": "check(uint256)", "0xf3b50c04": "rescind()", "0x57aee888": "_eraseNodeHierarchy(uint256,bytes32[],bytes32)", "0xaacc5a17": "getRandom()", "0x40275f85": "getPersonalDepositAddress(address)", "0x75700437": "query1_withGasLimit(uint256,string,string,uint256)", "0x6eb7b4c2": "underdogInfo(uint256)", "0x0f3eb785": "add(string,uint256,uint256,uint256)", "0xdc19266f": "Total_of_Players()", "0x9743dfc1": "jesterAutomaticCollectFee()", "0x6618b008": "cancelSellOrder(address)", "0x65538c73": "fireEventLog0()", "0xa4502cb8": "setExportFee(address,uint256)", "0x97bb2a63": "newvow(uint256,address)", "0xb400d149": "betOnNumber(uint8)", "0x030d406b": "entryPayout(uint256)", "0x1d71a1cd": "newIncome(string)", "0x85dd2148": "getSaleDate(bytes16)", "0x29917954": "exitPool()", "0xa25057de": "_transferToICAP(bytes32,uint256)", "0x24fc65ed": "getId(uint256,uint256)", "0x938199a5": "getDateOfLastPayment()", "0x04bb754c": "TradeFinancing()", "0xe37aa618": "distributeValue()", "0x547916ea": "finishRound()", "0xed01bf29": "budget()", "0x95ee1221": "isCancelled()", "0xfe777bcd": "etherForSale()", "0xffe302d1": "setPlz(string)", "0x891de9ed": "fromTLA(string)", "0x84734476": "copyBytes(bytes,uint256,uint256,bytes,uint256)", "0xfb114f57": "oraclize_query(uint256,string,string[3],uint256)", "0xceebe28d": "repoInterfaceVersion()", "0xb0ad38c4": "buildCity(string,uint256[2],uint256[2])", "0xefa7e56b": "GameEnds()", "0xcc3471af": "maxClaimBlock()", "0xa7c5052e": "buildDSTokenRegistry()", "0x6831c169": "totalPayedOut()", "0x98f3b81a": "getShares(address,bytes32[],int256[])", "0x2d077ad0": "Latch()", "0x0ac28725": "requestTradeDeal(uint256,uint256,string)", "0xb311ee0c": "refundClaimDeposit()", "0xadd82871": "strEqual(string,string)", "0x7879e19e": "CollectAllFees()", "0x5bd74490": "regProxy(address,address)", "0xd2b0d554": "getDisclaimer()", "0x0b74edc6": "testFinalHash()", "0x6cf761d4": "getMinConfirmationsByAddr(address)", "0x4cedf74e": "get_party1()", "0x4adcbd19": "isThisHardforkedVersion()", "0xefdecd9b": "check_withdrawdao()", "0x996a8046": "__callback(bytes32,string,bool)", "0x7c9cd7df": "changeDeveloper_only_Dev(address)", "0x3f77b560": "newDocument(bytes)", "0x06b5f02d": "calcWinnings(uint256,uint256)", "0x0a2282ae": "JackPot()", "0x378a2178": "tallyVotes()", "0xd8915fc5": "DCAssetBackend(bytes32,bytes32)", "0x0f590c36": "emergencyFixGameResult(uint64,uint256)", "0xea4af029": "ConferenceCertification()", "0x769dc523": "GetCategoryNumber(bytes4)", "0xd5df7559": "removeDocument(uint256)", "0x749aa2d9": "endRound()", "0xd8e5ae6a": "Etheramid()", "0xc0576b73": "monsters(uint256)", "0x32fefb4c": "add_account(address,address)", "0x7d619d9b": "holdCoin(address,address)", "0x5b067cce": "testCreateCostMain()", "0x384b1393": "follow(uint256)", "0x4162169f": "dao()", "0x5d8227e6": "FactoryBase(string,string,string)", "0x6bf52ffa": "Vote()", "0xeb5904c0": "setProfitDistributionContract(address)", "0x366a68dc": "setBlockLock(uint256)", "0x80d9eaa6": "refCount()", "0x89b8b492": "read(uint64)", "0x46b5e202": "set_num_levels(uint256,uint256)", "0xd96de4ce": "AdminDrawError()", "0x47b47102": "bakeCookie(string)", "0x1d7b5baf": "setUint(int256,bytes32,string,uint256)", "0x0699d07d": "updateMaxVal()", "0xfa544161": "getOwner(address)", "0x638560cf": "registerBool(address,bool)", "0x7c25f260": "Government()", "0x24a852c6": "unset(bytes)", "0xa32f0f41": "testFailControllerUnapprovedTransferFrom()", "0x0968f264": "withdraw(bytes)", "0x5f52e9fd": "WithdrawCashForHardwareReturn(uint256)", "0xc0f68859": "getMinimumGracePeriod()", "0x1bf6c21b": "USD()", "0x0fe234ed": "testSetController()", "0x05a17fc6": "getAccountFeed(address,uint256,uint256,uint256)", "0x673448dd": "isApproved(address)", "0x59dac714": "hashTo256(bytes)", "0x5a09f2f4": "setHouseFee(uint256)", "0x013cf08b": "proposals(uint256)", "0xeebf9808": "PiggyBank()", "0xadd43c59": "EtherTopDog()", "0xf909d60d": "getMinimumGasLimit()", "0xeb045789": "ChannelSeries(address)", "0x66d38203": "setup(address)", "0xe8641652": "strCompare(string,string)", "0x1959a002": "userInfo(address)", "0x737c8ea1": "_getRevisionBlockNumber(bytes32,uint256)", "0x127714c7": "getBudget()", "0x97daa043": "register(bytes,address,address,uint256,bytes)", "0xb5784f6f": "testMultiplePackages()", "0x0ce46c43": "scheduleCall(address,bytes4,bytes,uint16,uint8,uint256[5])", "0xe5782fd5": "setFeeStructure(uint256,uint256,uint256)", "0xa9f6def0": "HonestDice()", "0xeb7cdb56": "rankDown(uint256,uint256)", "0xb17b94c1": "testSystem()", "0xdd36e18b": "ContractStatus()", "0xee0dc478": "testSetEnforceRevisions()", "0x918359c6": "needsBirth()", "0xa5b1e13d": "settle(address,address,uint256,uint256)", "0x6b76484e": "swap(address,address)", "0x68402460": "scheduleCall(address,bytes4,uint256,uint256,uint8,uint256)", "0x733480b7": "transferToICAP(bytes32,uint256)", "0x567dbf18": "__forward(address,uint256,uint256,bytes)", "0x73e1743a": "buildDSBasicAuthority()", "0x482961e1": "updateReading(uint256,uint256)", "0x4e6ba0a9": "testCreateCostMultisig()", "0x8d7108e5": "isValidLocation(uint8,uint8,int8[5],int8[24])", "0x10142785": "assign(bytes,uint256,bytes1)", "0xfe97ee88": "hasPhone(address)", "0xe2861c8d": "cashOutProfit()", "0x0fa9ced4": "emergencyFuneral()", "0x8389f353": "setNumCities(uint256)", "0xdba1ac3d": "getEnforceRevisions(bytes20)", "0x1b4fa6ab": "getDefaultStackCheck()", "0x79be02af": "Read(address)", "0x70844f7a": "sendBadge(address,uint256)", "0x7bfaad96": "addNode(bytes,address)", "0x4d782cbc": "executeSellOrder()", "0xbe71248a": "payWinner()", "0x41304fac": "log(string)", "0x4f059a43": "getClaimAmountForBlock()", "0x6d2cb794": "airaTransfer(address,address,uint256)", "0x5a5383ac": "canExitPool()", "0xcabd27de": "Motion(address)", "0x433d4aab": "resolve(uint8,uint8)", "0x7d89ae63": "__findRef(string)", "0x4e1053cc": "RobinHoodPonzi()", "0x0220a5b4": "terminate(string)", "0x419ffa03": "fipsRegister(address)", "0x77a7e6be": "getRefTotal(uint256)", "0xed64bea4": "JamCoin()", "0x3cf885c4": "isBitSet(uint256,uint8)", "0xf2da67db": "setMany(uint256,int256,uint256,bytes20,address,bytes)", "0xe26c8434": "AdminStartDraw(string,bytes)", "0x13df7091": "mintAll(int256)", "0x8a46bf6d": "testFallback()", "0x29bed3bf": "EthereumRoulette()", "0xf869b11a": "declareVictor(uint256,uint256)", "0x45c41478": "getMarkets(bytes,address)", "0x90cf581c": "voteYes()", "0x9ec35352": "returnRandom()", "0x5025b9ae": "expire(uint256,uint256,uint8,bytes,bytes,bytes)", "0x338a1379": "_setPackedBlockNumber(bytes20,uint256)", "0xdb641ab4": "Game_balance_in_Ethers()", "0xbc0e7adb": "testThrowsDisownNotOwner()", "0x302d350e": "firstChainedCallback(uint256)", "0x5af73f3f": "getMinimalBalance(uint256,address)", "0x4c488dac": "getChannelValidUntil(bytes)", "0xa1616429": "testBitOrSuccess()", "0xaa64c43b": "transferPool(address,address,uint256)", "0x78e97925": "startTime()", "0xa0355f4e": "decline(uint256)", "0x02556de3": "updateMajorTree(bytes32)", "0x01984892": "name(address)", "0xfad4b99a": "updateChannelMinimum(address,uint256)", "0x4f39ca59": "drop(bytes32)", "0x61591a7c": "personUpdateDOB(uint256,int256)", "0x17b3a34b": "_addIdentities(uint256,bytes32[])", "0x91d8b14e": "BuyTickets()", "0x1aadcc34": "convertGreyGreen(uint8,uint8)", "0x9a863892": "NewProposal(uint256)", "0xc5487661": "proxyTransferToICAPWithReference(bytes32,uint256,string)", "0x85f8c16d": "claimHours(int256)", "0xa71f94c8": "scheduleSetUInt(address,uint256,uint256)", "0x7ef09476": "transfer(uint64,address)", "0x94bcdb4c": "Example2()", "0x37930615": "extend(bytes16[],uint64)", "0xfb09b1ac": "testBalanceOfReflectsTransfer()", "0x19a278b9": "getBAddress()", "0xc0a239e3": "valuePerShare()", "0xa039e3c7": "testSetNotTransferable()", "0x22593300": "Small(address)", "0xe21608be": "ReserveToken()", "0xc2985578": "foo()", "0xb463bcde": "testThrowsSetNotTransferableNotOwner()", "0x88d695b2": "batchTransfer(address[],uint256[])", "0x37b0574a": "isClassic()", "0x1da6822c": "testThrowsTransferEnableNotTransferable()", "0xdcfa9cc0": "testProxyCall()", "0x478aa69e": "unauthorizeUser(address)", "0x102accc1": "fireEventLog2()", "0xed62cf1f": "setCanCall(address,address,bytes,bool)", "0x15f73331": "invalidateName(string)", "0x73e30e49": "majorEventFunc(uint256,bytes,bytes)", "0x00c721ab": "setHand(uint256)", "0xf9e27106": "investmentEntryCost()", "0x4c7f74df": "EtherDelta(address,address,address,uint256,uint256,uint256)", "0xb74e452b": "today()", "0xd3118a5a": "addDoc(string,string)", "0xc204f9f1": "_transferFromToICAP(address,bytes32,uint256)", "0xf50d3914": "resetFoundationtList()", "0xe67cdfb7": "moveOldUser(uint256)", "0x98eaca94": "inKissBTC(uint256)", "0xc633084f": "sendGreeting(address,string)", "0xde10f04b": "eraseNode(bytes32[])", "0xd50495f4": "addTransaction(bytes)", "0x96cff3df": "getMinimumCallCost(uint256,uint256)", "0xce373b95": "heroOfThePit()", "0x39e525f9": "resolveCallback(uint256)", "0x942b90d3": "getRewardTable()", "0xedca914c": "buyTicket()", "0x5fcb568c": "release(string,uint32,uint32,uint32,string,string,string)", "0x6c9c2faf": "getSupply()", "0xf1448e10": "requestExecution(bytes)", "0x0c08bf88": "terminate()", "0x08aba5aa": "setAccountBalance(uint256)", "0x2c46d8d5": "EndRound(uint256)", "0x3d5db1c2": "incrUserOnholdBal(address,uint256,bool)", "0xf2f254c7": "getLatestMinorTree(bytes32,uint32)", "0x373a1bc3": "scheduleCall(address,bytes4)", "0x3a96fdd7": "compare(string,string)", "0x738ddabe": "getContentIndexedAccountCred(uint256,address,address)", "0x5acce36b": "getEndowmentBalance()", "0x1ca60aeb": "setMeltingContract(address)", "0x52375093": "m_lastDay()", "0x565a2e2c": "getBeneficiary()", "0x9d5c6061": "getMsgGas()", "0x41d31feb": "get_read_only_keys()", "0x796b89b9": "getBlockTimestamp()", "0x4a41e045": "getUint8(int8)", "0x38e48f06": "save(string)", "0x1cda37f2": "eraseRecords(bytes32)", "0xae978f08": "getLatestTweet()", "0x20909fa0": "communityCurrency()", "0xafbec8df": "TheGrid()", "0x1c14179a": "GavCoin()", "0x0b6142fc": "breach()", "0x3ab1e703": "roundMoneyDown3SF(uint256)", "0x414ceac0": "investorAddFee(uint256)", "0x82a62137": "activateAccount(address)", "0x4ca7fbd0": "updateTokenPriceWeekTwo()", "0x2551858e": "getFlags(bytes32)", "0x4ad07b0e": "oracleOutcomes(bytes32,address)", "0x60b431a4": "testGetSig()", "0xa5f8cdbb": "buyTicket(address)", "0x64aabe92": "tryExec(address,bytes,uint256)", "0xa6c01cfd": "isInGeneration(uint256)", "0x149c5066": "ChanceOfWinning(uint256)", "0xc068eae0": "player_collect_winnings(uint256)", "0x8129fc1c": "initialize()", "0xcf832ce2": "ownerRefundPlayer(bytes32,address,uint256,uint256)", "0x3517a740": "getNodeParent(bytes)", "0xec6afc22": "oraclize_query(uint256,string,string[3])", "0x50944a8f": "setMembership(address)", "0x85b1423e": "returnAll()", "0xd95a2d42": "lendGovernmentMoney(address)", "0x347632e8": "getShareholderAdressByID(uint256)", "0xbb39a960": "trade(address,uint256,address,uint256)", "0x8abadb6b": "setAccountLevel(address,uint256)", "0xa502aae8": "getNextGenerationId()", "0xb5bfdd73": "addDSource(string,bytes1,uint256)", "0x28d3ad3f": "getPot(uint256)", "0x08933d11": "getJoinBlock(address)", "0x8383bfc8": "EscrowFoundry()", "0x2ca15122": "sign()", "0xf340fa01": "deposit(address)", "0x9ed93318": "create(address)", "0xa1c0539d": "scheduleCall(address,bytes4,bytes)", "0xced92670": "changeMultiplier(uint256)", "0xb2c652f3": "getMarkets(uint256[128])", "0x69b144eb": "testThrowsCreateNewRevisionNotOwner()", "0x16c72721": "forked()", "0x712ca0f8": "getOrder(string)", "0x0cf45ba5": "updateFirstDuel2(uint256)", "0x4173b181": "setWeiPrice(uint256)", "0x689b3e2d": "Moonraker(address,address)", "0x8691162a": "TlcCoin()", "0x432ced04": "reserve(bytes32)", "0x38178fbe": "addString(string,string)", "0x8f1327c0": "getRound(uint256)", "0xa9eed530": "reduceOrderQty(uint256,uint256)", "0x408938d0": "testUpdatePackageDb()", "0x56105a08": "DgxSwap()", "0xc43d0575": "scheduleCall(bytes4,uint256)", "0xdba21657": "askForEther(uint256)", "0xca3b5c91": "hasRelation(bytes,bytes,address)", "0xc71cbcf3": "recoverAccount(address,address)", "0xb010d94a": "canExitPool(address)", "0x0a16697a": "targetBlock()", "0xff1f7046": "requiresAuction(string)", "0x0b811cb6": "executeProposal(uint256,bytes32)", "0xbb8be064": "HardwareToken()", "0xe2b05077": "getSaleDate(bytes,uint256)", "0x1e9a6950": "redeem(address,uint256)", "0xd21b84ac": "createNewDAO(address)", "0xd644e356": "index(uint256,address,uint256,uint256)", "0xea27a881": "getMinimumEndowment(uint256,uint256,uint256,uint256)", "0x99a88ec4": "upgrade(address,address)", "0xc8e4acef": "playerByAddress(address)", "0x0b7abf77": "TOTAL_TOKENS()", "0xfb5d7376": "step4()", "0xc0aa18e7": "History()", "0xe2233ada": "smartDoor(address[])", "0xd6006e88": "send(address[],uint256[],uint256)", "0x95671958": "getFileListTail()", "0x16bac350": "overthrow(string)", "0x5cb18a6d": "fipsLegacyRegisterMulti(bytes20[],address,bytes)", "0x60116397": "Registrar(address,bytes32,uint256)", "0x60fe47b1": "set(uint256)", "0x5f8f0483": "buyBankerAgreementFromImporterBank()", "0x4c8cc20b": "toContentID(address,string,string,address,uint256)", "0x45ca25ed": "changeName(address,string)", "0xb21bce4c": "vote(bytes,bool)", "0x334dc700": "CanaryV7Testnet()", "0xc31d0031": "CrowdFundDAO(string,uint8,string)", "0xf3d91708": "isEligibleForUpgrade(address)", "0x0ee07836": "adjustDifficulty(uint256)", "0xf6232556": "Security_GetNumberOfAttemptsToConnectBankAccountToANewOwnerAddress()", "0xb2d37e95": "remove_order(uint32)", "0x691d58e7": "_applyRefund(uint256)", "0x1c2353e1": "isCertifier(address)", "0xcf158fe9": "scheduleTransaction(uint256,uint256,uint256)", "0x5d96ec65": "setAdministrator(address,string,bool)", "0x0651844e": "activateBalance(address)", "0x217311ac": "getWords(uint64)", "0xc127c247": "addMember(address,string)", "0x40c0bcb9": "checkBetNumber(uint8,address,bytes32,bytes32)", "0xb633620c": "getTimestamp(uint256)", "0x5b764811": "_jMul(uint256,uint256,uint256,uint256)", "0xfe029156": "swap(address,address,uint256,uint256)", "0x31db4b95": "doTriggerAuth()", "0x203c03fa": "Coinflip()", "0x209a5b8a": "moneySumAtSettlement(address,uint256,int256,uint256)", "0xf10ae2ab": "__dig_then_proxy(uint256,address,bytes)", "0xd532e481": "activateFrozenAccount(address)", "0xe9a9c1b4": "get_party1_balance()", "0x8fcc9cfb": "setMinDeposit(uint256)", "0xe5c7e509": "testThrowTransferDisableNotEnabled()", "0x4e077f2a": "addGasEther()", "0xb7c93330": "ResourcePoolTester()", "0x82661dc4": "splitDAO(uint256,address)", "0x0e554bd8": "scheduleCall(bytes,uint256,uint256,uint8)", "0x49041903": "getGame(uint64)", "0x0e1da6c3": "claimTimeout()", "0xc53ad76f": "Kardashian()", "0x8b7bcc86": "numWinners()", "0x1043dcdf": "LastIsMe(uint256,uint256)", "0x6cd22eaf": "updateAuthority(address,bool)", "0xb796a339": "addRegistryIntoOwnerIndex(address,address)", "0x308d6613": "getSignData(uint256,uint8)", "0xed88c68e": "donate()", "0xb719d1d0": "getRegInfo(address)", "0xac8d6030": "removeRequest(address)", "0x46f0975a": "signers()", "0x434cb64c": "startNextGeneration()", "0x6cb3d30a": "triggerTryAuth()", "0x3c067945": "fundBalance()", "0x26c7edaa": "flip4(bytes)", "0xf76f950e": "uint2str(uint256)", "0x860e9960": "BetPriceLimit()", "0xb0ecca8f": "LookAtLastTimePerZone(uint256)", "0xa35cfa22": "make_move(uint256,uint8,uint8,uint8,uint8)", "0x3f74fecb": "DSTrueFallbackTest()", "0xdd2ad311": "scheduleCall(bytes,uint256)", "0x0ae5e739": "grantAccess(address)", "0x7d5fec5a": "setOwner(uint8,uint8,address)", "0x6a4b6aa5": "untrustedChildWithdraw()", "0x332f93a9": "nextPayoutGoal()", "0xc5ae6e0e": "Kernal()", "0x75438e49": "fillGas()", "0x51404cbe": "forceDivestOfOneInvestor(address)", "0xeacfc0ae": "Authorized()", "0xe59d843a": "Replicator(bytes,uint256,uint256,address)", "0xf00e8651": "createRequest(address[2],address,uint256[11],uint256,bytes)", "0x02acdb44": "setAnyoneCanCall(address,bytes4,bool)", "0x2a24f46c": "auctionEnd()", "0x7ef1925b": "getShareRange(uint256,uint8)", "0x2fac1a54": "newOrder(bool,uint256,uint256,uint256,uint256)", "0x56b8c724": "transfer(address,uint256,string)", "0x33fd066d": "doBalanceFor(address)", "0xf29617da": "registrationDeposit(address)", "0x2b297f9e": "registerDao(address)", "0x79cce1c5": "getReleaseHashes(uint256,uint256)", "0xbed1b8b9": "convertToInt(string)", "0xef5daf01": "_dumpToCompany()", "0x23dc42e7": "query1(uint256,string,string)", "0xa53b1c1e": "setInt256(int256)", "0xb8cf14e7": "updateStatusPlayer()", "0x61aa8d93": "processFee()", "0x10f41715": "updateMintingData(uint256,uint256)", "0x048e2e94": "getAccountSize(address,uint256)", "0x7c47965e": "isInCurrentGeneration()", "0x420a8ac8": "NanoPyramid()", "0xe56556a9": "getPlayerID(address)", "0x5cd2f4d3": "approve(address,bytes32)", "0x8da4d776": "newCommune(address)", "0x4d30b6be": "balanceOf(address,bytes32)", "0x4a606c53": "_db()", "0x4956eaf0": "deploy(address,uint256)", "0xf1fe42b8": "TransactionRequest(address[3],address,uint256[11],uint256,bytes)", "0x63e38ff3": "id_for_nym(uint256)", "0x0e757a2e": "testSetAndGet()", "0x3facd57c": "registerBill(uint256,address,address,uint256,uint256,uint256)", "0xe548cf13": "betOnColumn(bool,bool,bool)", "0x2f1e4968": "makeNewProposal(string,uint256)", "0x0b467b9b": "revoke(bytes)", "0x74bfb965": "addNewProxy(address)", "0x02de2cf3": "isLatestPreReleaseTree(bytes32,bytes32)", "0xfc1f7652": "_isBoardMember(address)", "0xefef39a1": "purchase(uint256)", "0x3ae9b510": "getLatestMajorTree(bytes32)", "0xc24924d6": "setQueryFee(uint256)", "0x839930ba": "getMinimumBet()", "0x8f5e9ca7": "acceptTOS(address,bool)", "0xd1100691": "BookCafe()", "0x839849c0": "changeBaseMultiplier(uint256)", "0x758971e8": "ownerTakeProfit(bool)", "0x2b785960": "testBitAndSuccess()", "0xd96a094a": "buy(uint256)", "0x379607f5": "claim(uint256)", "0x88e072b2": "checkTransfer(address,uint256)", "0x05fefda7": "setPrices(uint256,uint256)", "0xfc63d4fb": "order(bool,uint32,uint128)", "0x5718b994": "checkEvent(address,bytes,bytes,uint256)", "0x0c0662a8": "getLastWithdrawal()", "0xeb947f19": "ExampleResourcePool()", "0xb51c4f96": "getCodeSize(address)", "0x702fc7da": "ReviewModel()", "0xc6cb7a96": "orderMatchTest(uint256,uint256,int256,uint256,uint256,address,address,uint256,int256)", "0xb7760c8f": "transfer(uint256,address)", "0x32b12eac": "setFallback(address)", "0x0a4d564c": "TieUpLooseEnds()", "0xc3ad5ecb": "getTweet(uint256)", "0xe86afde0": "description(uint64)", "0xd0549602": "scheduleTransaction(address,uint256,uint256,uint256)", "0xbf2e694f": "getPreviousRequest(address,address)", "0x2525f5c1": "cancelBid(address,bytes32)", "0x19f02ceb": "set(address,address,uint256)", "0xf00acc47": "prepareRoll(uint256,uint256)", "0x29d28aad": "Broker(address)", "0x041d0c0b": "MyTokenLoad(uint256,string,uint8,string,address)", "0xd81ab0c1": "invoke(uint256,address,address,bytes)", "0xab09ee80": "respond(uint256,uint256,uint256,uint256)", "0xd985f122": "RelayToolsTest()", "0xbe0638e4": "WealthShare()", "0x5263ba87": "getLatestPatchTree(bytes32,uint32,uint32)", "0xb7bae9b7": "exists(bytes,bytes)", "0x0b80f8d3": "invmod(uint256,uint256)", "0xbb4d7cd1": "tag(uint256,string)", "0xadf54e0c": "betOnLowHigh(bool,bool)", "0xed54746e": "lastAuction()", "0xf158458c": "getMinimumEndowment(uint256,uint256)", "0x5fcc2edb": "IndividualityTokenRoot(address)", "0x7cc48875": "Slots()", "0x2885b593": "extractMasterKeyIndexLength()", "0x8940aebe": "publicKey(uint256)", "0x0aece23c": "getFeeAmount(int256)", "0x72c3015c": "mint(int256,address,string)", "0xd6a619e3": "transferIfPuritanical(address)", "0xe30443bc": "setBalance(address,uint256)", "0x1277e24f": "payOneTimeFee()", "0xb958a5e1": "getPhoneByAddress(address)", "0x4e71d92d": "claim()", "0x3e0d4f4a": "ApproveContractorProposal()", "0x18160ddd": "totalSupply()", "0x150ad2a8": "owner_transfer_ownership(address)", "0xa2b5591c": "oraclize_query(uint256,string,string[],uint256)", "0x8d227fc0": "getPeriodInfo()", "0x1c0b6367": "processTransaction(bytes,uint256)", "0xf245b9e4": "DVIP(address)", "0x392327b5": "owner_set_fraction(uint256)", "0xadaccd74": "getNickname(address)", "0x2e0ef395": "voteOnNewEntryFees_only_VIP(uint8)", "0x89c19ddb": "concat(string,string)", "0xcef8d343": "buyShare(uint256,bool)", "0xd224118f": "PrepareDraw()", "0x4269d8ef": "_safeSend(address,uint256)", "0xda1441cd": "KudosBank(uint256)", "0x7ccfd45a": "removeSubUser(address)", "0xcc70bb1a": "publish(string,string,string,address)", "0x708f29a6": "getTotalPayments()", "0x05459f42": "WeeklyLotteryB(address)", "0x452d44dc": "checkBothNotNull()", "0x659fb968": "getOracleOutcomes(bytes32[],address[])", "0x3570c2ee": "PosRewards()", "0xbca86986": "testSetup()", "0xff49b26e": "createEvent(uint256,uint256,uint8,uint32,address,uint256,uint8)", "0x541d920c": "commit(bytes,string)", "0xa6a20ff6": "DSEasyMultisig(uint256,uint256,uint256,uint256)", "0x0f5381f1": "testUserCanIncreaseVersionNumber()", "0xf8f46b5f": "getCurrentMinerAddress()", "0xfcfff16f": "open()", "0x5a9b0b89": "getInfo()", "0xb8017221": "get_party2_balance()", "0x514dcfe3": "seller_accept()", "0x2004dff6": "Basics()", "0x0b6d8d52": "createDAO(address,uint256,uint256)", "0xf18d20be": "adminWithdraw()", "0x8f9df278": "newEntry(int256,bool,uint256,int256,string,bytes32,address,uint256[])", "0x75949c13": "sendHalf(address)", "0x64ac2c4a": "WavesPresale()", "0x8946d33f": "SplitterEthToEtc()", "0x11400d8e": "priv_fastGetBlockHash__(int256,int256)", "0x7266f4a4": "X3()", "0xb189ad2a": "testErrorUnauthorizedAfterTransfer()", "0x31c2bd0b": "propose(address,bytes,uint256)", "0x100c8ada": "setCAmodulus(bytes)", "0x296ed88f": "testFailControllerInsufficientFundsTransferFrom()", "0xd5dbb1ad": "solveBet(address,uint8,bool,uint8,bytes32,bytes32)", "0x8a9ffb90": "transfer(string,string,bool)", "0x968908a3": "createMarketMaker(uint256,uint16,uint256)", "0x7b02b2c9": "sendMsg(address,string)", "0xa33dd801": "setTreasuryBalance(uint256)", "0x2f553d31": "isCreated(bytes32)", "0xf712d7ff": "testFailControllerTransferFromWithoutApproval()", "0xe51ff1fc": "iterateOverThings()", "0x60fd902c": "gnosisToken()", "0x2ef875fb": "div10(uint256,uint8)", "0x640f244b": "findSuitableGen()", "0x16cb9a01": "assertFalse(bool,bytes)", "0xe671f510": "onEtherandomExec(bytes32,bytes32,uint256)", "0x758b5172": "setPlayersPerRound(uint256)", "0x6423db34": "Reset()", "0x21958a50": "AddressSeries(address)", "0xfb87d5ea": "TransactionRequest(address[4],address,uint256[11],uint256,bytes)", "0xfb279ef3": "tip(uint256,address,uint256)", "0x338cdca1": "request()", "0x4e7ad367": "fireEventLog1Anonym()", "0xbd9335c0": "scheduleHangouts()", "0x4cb85356": "BranchSender(uint256,bytes32)", "0x1d7e1f68": "getContentRank(address,uint256)", "0x1a1df394": "Play(bool)", "0x468129a5": "setUnit(uint256,uint256,uint256)", "0xecb70fb7": "hasEnded()", "0x2d49ffcd": "getLocked()", "0x2e06c756": "post(string,string,string,uint256,uint256,address)", "0x73f93a48": "getAccountContentTip(address,uint256)", "0xf6a3d24e": "exists(address)", "0x5fbddcf3": "isLivingMonarch()", "0x6d568c43": "weiToCents(uint256)", "0xacf4280c": "buildDSApprovalDB()", "0xf3541901": "execute(address,bytes,uint256,uint256)", "0x88eb7af7": "_isHuman()", "0x48a490fb": "transferFromTreasury(address,uint256)", "0x5e03d393": "setAccountFrozenStatus(address,bool)", "0xfc687311": "betOn(int8)", "0x5bbfe9b6": "_myGroupHelper()", "0x5629c6d9": "doExecution(address)", "0xe3a9b508": "EnableDisableTokenProxy()", "0x9229c504": "new_mainPlayer(address)", "0x6f6c0244": "generateShortLink()", "0x33613cbe": "getBondBalance(address)", "0x4229616d": "collectPercentOfFees(uint256)", "0x4ed3885e": "set(string)", "0x043bb5e7": "getIdentities(address[])", "0xad2fea7c": "removeMinter(int256,address)", "0x0b7e9c44": "payout(address)", "0x17f5de95": "MAX_TOKENS_SOLD()", "0x50ea1932": "lookupISO3116_1_alpha_2(bytes)", "0x96f7807a": "getDuel2(uint256)", "0xa97ffd5e": "safeToSell(uint256)", "0x2f4ee5d4": "registerThrone(bytes,uint256,address,uint256,uint256)", "0x4c0bcfe5": "getTransferableBalance(address)", "0x0d17bc2e": "_disallow()", "0x0ca7395f": "returnFund(address,uint256)", "0x69fe0e2d": "setFee(uint256)", "0xfaf27bca": "greeter(string)", "0x0c7de59d": "edit(address,bytes,bool)", "0x16e27349": "getFeeRecipient(int256,int256)", "0x37751b35": "doTransfer(address,address,uint256)", "0x67fc1c6a": "validateProposedMonarchName(string)", "0xf59f99ee": "createNextGeneration()", "0x6be505f5": "selectWinner(bytes32)", "0xf6bd5893": "getGas(uint256)", "0x35b09a6e": "someFunction()", "0xb3aaa277": "validate(address[4],address,uint256[11],uint256,bytes,uint256)", "0x4f052648": "XaurumDataContract()", "0x117b4705": "retract(bytes32)", "0x2145e36c": "testBitSetFailIndexOOB()", "0x3d750b28": "found()", "0x1334a5e2": "eventCallback(uint8,address,address,uint256)", "0x3c2c21a0": "scheduleCall(address,uint256,bytes4)", "0x82996d9f": "rent()", "0xaf640d0f": "id()", "0xdaf22f4d": "identify(bytes32)", "0xfe4667e9": "getMaxLossAfterTrade(address,uint256,uint256,int256,int256)", "0xfc108f70": "GamblerPerAddress(address)", "0x89f4ed7a": "getLastTag(uint256)", "0xfcc11241": "addOrder(uint256,uint256,uint256,uint256,uint256,uint8)", "0x43243797": "fundsOf(address)", "0x892c0214": "NumberOfCurrentBlockMiners()", "0xb5a6c525": "extractFrozenAccountLength()", "0x1acb2719": "getNextRequest(address,address)", "0xa89a4f09": "creatorBalanceChecker()", "0x1e83409a": "claim(address)", "0x5e1d7ae4": "changeFeeRebate(uint256)", "0xb7482509": "deposit(address,string)", "0xfb47a067": "_getRevisionBlockNumber(bytes20,uint256)", "0x5dcdddd1": "testSafeToAddFix()", "0x9aa26f06": "registerBytes32(address,bytes)", "0xd085e66e": "GetPart(bytes32,uint256)", "0x2cd78450": "activateExportFeeChargeRecord(address)", "0x35d129f6": "untag(string)", "0x1a7a98e2": "getDomain(uint256)", "0x877653f0": "_storeBalanceRecord(address)", "0x446fbcd1": "CredSign()", "0xfae8f9a2": "setInitialParent(int256,int256,int256,int256,int256,int256)", "0xc1b056b0": "getNodeLeftChild(bytes)", "0x71f297cc": "XaurumToken(address)", "0xe3ffc9a3": "sendEtherToOwner()", "0xeccf1b29": "CrystalDoubler()", "0x57f4d5ec": "processDividends(address,uint256)", "0x75c589a0": "getMinimumCallCost()", "0x66772438": "computeResponse(uint16)", "0x7fefde53": "WillRegistry()", "0x8f4fb958": "calculateRandomNumberByBlockhash(uint256,address)", "0xed498fa8": "userTokens(address)", "0x5601eaea": "execute(uint256,uint256)", "0x8dd8596c": "sendDonation()", "0x15a0df43": "testThrowCreateNewRevisionNotOwner()", "0x0382c254": "CheckHash(uint8,uint8,uint8,uint8,bytes32)", "0x157f8f51": "feePaid(int256,int256,int256,int256)", "0xf00aac7f": "ArrayRR()", "0x7b7d7225": "_approve(address,uint256)", "0x54ed7b6e": "addHash(bytes)", "0x235c002d": "transferOther(address,address,uint256)", "0x7057c20d": "CFD(address)", "0xd5563f31": "createAuction(uint256)", "0x46c3166f": "testThrowRetractLatestRevisionNotOwner()", "0x4420e486": "register(address)", "0x9a969768": "distributeProfits(uint256)", "0x464f37c9": "trustedChildRefund()", "0x5d495aea": "pickWinner()", "0xdf55b41a": "owner(string)", "0x10e6e06c": "vote(bool,uint256)", "0xe7faecec": "testFailInsufficientFundsTransfers()", "0xea98e540": "proxyTransferFromToICAPWithReference(address,bytes32,uint256,string)", "0xfff78f9c": "doThrow()", "0x9bb01b5f": "ElcoinDb(address)", "0xdc6dd152": "playerRollDice(uint256)", "0x5d0be9de": "softWithdrawRevenueFor(address)", "0xcd591822": "CanaryV7Fast()", "0x36e6b92e": "taskProcessedWithCosting(uint256,uint256)", "0x7bb6a4c6": "uno(uint256)", "0x03427656": "getDefaultSoftResolutionBlocks()", "0xc1fd4339": "createMarket(bytes32,uint256,uint256,address)", "0xeb95b7d5": "Bounty(address,address)", "0x4dd49ab4": "get(bytes,uint256)", "0xfa6d373c": "LeaderHash()", "0x8c8d98a0": "toTimestamp(uint16,uint8,uint8)", "0x9a79f4a8": "testFailHeaderInsufficientFee()", "0xdd90c403": "getAccountFeed(address,uint256,uint256)", "0x58e59c32": "get_entry(uint256,uint256,uint256)", "0xfd747c0b": "rsaVerify(bytes,bytes,uint256,bytes)", "0x0f4cf692": "numMessages()", "0x18433bb7": "DrawPrepare()", "0x1dea0c57": "getRealBet(uint256)", "0x7d60e343": "getFileListSize()", "0xd24ddcfe": "buyKissBTC()", "0xa055fe64": "_projectCommitNew(address)", "0x5f17114e": "TimeDeposit()", "0x85fe0448": "testThrowRestartNotUpdatable()", "0x901717d1": "one()", "0x528fd7b0": "manualPayExpiredDuel()", "0x85952454": "newOwner(address)", "0xf34c7010": "commitSecurity(address,uint256,uint256)", "0x3bf2313d": "__transferToICAPWithReference(bytes32,uint256,string)", "0x67b830ad": "fillOrder(uint256)", "0x73fac6f0": "confirmReceived()", "0xf1b3f968": "getRaceEndBlock()", "0xf99fc046": "dEthereumlotteryNet()", "0xb409da05": "logDoubleIndex(bytes,bytes,bytes,uint256)", "0x9e920587": "testOwnedAuth()", "0x8e7cb6e1": "getIndex(uint256)", "0xe2f8a017": "payInstallment(uint256)", "0xac3e6b2f": "testSetNotRetractable()", "0x8fbc3ecd": "BUFFER()", "0x4b729aff": "buyNumber(uint256)", "0x166c4b85": "len(bytes32)", "0x6299f8cf": "stop(uint256)", "0xd767aee0": "bbb()", "0x29090202": "Resolver(address)", "0xcc2c2bcf": "MotionFactory(string,string,string)", "0xfd260dfc": "getCertificationDbStatus(address)", "0x30aceb89": "validateRequestParams(address[3],address,uint256[11],uint256,bytes,uint256)", "0xd11f13df": "numberOfParticipantsWaitingForPayout()", "0xd05c78da": "safeMul(uint256,uint256)", "0x69953501": "setUtils(address)", "0xff7f5f2a": "EtherizationUtils2()", "0xde4b3262": "setBasePrice(uint256)", "0x6cf9cc58": "registerResource(bytes,uint256,bytes,string)", "0x7ac37d58": "ownerTransferEther(address,uint256)", "0x0121b93f": "vote(uint256)", "0x07b6f631": "testTestHarnessAuth()", "0x869b3f6a": "testThrowsRetractNotOwner()", "0x18253234": "ticketsAvailable()", "0x5581004d": "createThrone(bytes,uint256,uint256,uint256,uint256)", "0x7102c138": "Standard_Token(uint256)", "0xce5566c5": "cash(uint256,uint256)", "0x16a25cbd": "ttl(bytes32)", "0x0c9fcec9": "setApproval(address,address,uint256)", "0xe6d95eb8": "DSAuthorized()", "0x34c0d654": "setPackageDb(address)", "0x0ee79fb3": "closeReferendums()", "0xe2cdd42a": "vote(uint256,address,bool)", "0xd3f297d6": "claimLiquidityReward()", "0xf37b437b": "scheduleCall(address,bytes,uint256,uint256,uint8,uint256,uint256)", "0x2090cf8b": "consultBalance(address)", "0xc9296d14": "scheduleTransaction(address,uint256,uint256,uint256,bytes)", "0x7993e5c2": "Devcon2TokenForTesting()", "0x268bb78e": "propose(address,bytes,uint256,uint256)", "0x2b16b56a": "setIndex(uint256,uint256)", "0x6d15f208": "reject(string,uint256,uint16,address,uint256)", "0xc4ff3614": "Wallet(address[],uint256,uint256)", "0xb47d89ad": "Details()", "0x0ae08793": "confirmAndCheck(bytes32)", "0x061e494f": "getBet(uint256)", "0x314e99a2": "abdicate()", "0xe487eb58": "getOwner(bytes20)", "0x7ee65635": "LookAtDepositsToPlay()", "0x9e9d3aa4": "FirstBloodToken(address,address,uint256,uint256)", "0x4dfd1b02": "setUint8(int8,uint8)", "0x82fbdc9c": "register(bytes)", "0xa8b60b93": "ackMsg(uint256,string)", "0x081e806d": "PayOut(uint256)", "0x8bab8791": "testPkgUpdate()", "0xc262df45": "isKnownRequest(address,address)", "0x4123cb6b": "m_numOwners()", "0x62be3172": "Message(address,address,address,string)", "0x0d368fee": "deverify(address)", "0x5f1231ea": "getMemberInfo(address)", "0xa07daa65": "newRequest(uint256)", "0xa4406bcd": "placeSellOrder(uint256,uint256)", "0x5b7d47a9": "betOnColor(bool,bool)", "0x9c6034a7": "sendIfNotForked()", "0x26a4861c": "CROWDFUNDING_PERIOD()", "0xbaac5300": "createTokenProxy(address)", "0xfc72c1ef": "ERC20Base(uint256)", "0x316b08a0": "scheduleTransaction(address,bytes,uint256[7],uint256)", "0x0b590c6b": "SingularDTVToken()", "0x750e443a": "voteAgainst(uint256)", "0xfc7b9c18": "totalDebt()", "0x7ff9b596": "tokenPrice()", "0xd67cbec9": "release(uint32,uint32,uint32,bytes20)", "0x553cc48d": "Player(string)", "0x579cdf17": "getAdminName(address)", "0x7e1c4205": "query2(uint256,string,string,string,uint256)", "0x54107401": "declareLove(string,string)", "0xea4ba8eb": "getOutcome(bytes)", "0x9b5adea2": "setMinter()", "0x185061da": "undoIt()", "0x90c3a370": "AuctionMaster()", "0xbd02e4f6": "calcRandomNumberAndGetPreliminaryGameResult(uint256,uint64)", "0xbc126ba1": "totalCents()", "0xa3747fef": "register(bytes,bytes)", "0x805210b7": "AmIPlayer2()", "0x4e05ded6": "ClassicCheck()", "0xec2ac54e": "deposit(address,uint256,bytes32,uint256)", "0x49c15bd9": "Purchase()", "0x87bb7ae0": "getTicketPrice()", "0xf2f03877": "commit(uint256,bytes32)", "0x167d3e9c": "SetOwner(address)", "0x5c634241": "CanaryV6()", "0xba15e52e": "getInfo(bytes20)", "0x06c1df7b": "checkBetColumn(uint8)", "0xf7bc39bf": "owns(address)", "0x27b752b8": "sha3HexAddress(address)", "0x5ac801fe": "setName(bytes32)", "0x1ae460e5": "isInPool()", "0x85c7a953": "WithdrawFullBalanceFromBankAccount()", "0x755b5b75": "setNumUnits(uint256,uint256)", "0xaefc8c72": "unsealBid(bytes32,address,uint256,bytes32)", "0xfab43cb1": "getPongAddress()", "0x9e997121": "getConfigAddress(bytes)", "0xda2b7416": "testBitsAndFailIndexOOB()", "0xd0e30db0": "deposit()", "0x4a0d89ba": "getSwap(uint256)", "0x63a9c3d7": "verify(address)", "0x337b1cf9": "setIpfsHash(bytes)", "0xbaf00f76": "removeAllSubUsers()", "0x1b370abb": "getPreviousNode(bytes)", "0x741e2345": "registerMany(address,uint256,int256,uint256,bytes20,address,bytes)", "0xb3760c80": "orderMatch(uint256,uint256,uint256,int256,uint256,uint256,address,uint8,bytes,bytes,int256)", "0x73ffd969": "setMap(uint256,uint256,uint256)", "0x50b44712": "tickets(uint256)", "0x6a9d2afd": "playToWinTest(uint256)", "0x644998ae": "maintain(int256,uint256,uint256)", "0x2203ab56": "ABI(bytes32,uint256)", "0x9c67f06f": "registryStarted()", "0x93423e9c": "getAccountBalance(address)", "0x524e4e61": "testDistribution()", "0xa17042cc": "getMsgValue()", "0x4f9d719e": "testEvent()", "0xcbcaacab": "checkTransferWithReference(address,uint256,string)", "0x1bcf5758": "getOccupies(uint8)", "0x1d4b0796": "updateTxStats()", "0xd173707d": "hasPhysicalAddress(address)", "0xa54a2b8b": "testBlockHashFetch()", "0xc51bf934": "CEILING()", "0x0e54b872": "registerUser(string,address)", "0xba51a6df": "changeRequirement(uint256)", "0x6bd92f7c": "activateAllowanceRecord(address,address)", "0x90daaf67": "getMinimalDeposit()", "0x85d5c971": "logTransfer(address,address,bytes32)", "0x8b9e5385": "MeterSlock(uint256,uint256,address)", "0x7bcd7fad": "getRecordAtIndex(uint256)", "0x8e035ac1": "BetOnHashV82()", "0x5dbe47e8": "contains(address)", "0x21bb79fe": "luckyDogInfo()", "0xdd467064": "lock(uint256)", "0xa4beffa7": "increaseInvestment()", "0x8400c307": "isRecipientAllowed(address)", "0x0965bf7d": "processProposals()", "0x4b5dc8cb": "roundMoneyDown3SFExt(uint256)", "0x777feff5": "getCertificationDbAtIndex(uint256)", "0x9462eae5": "ChangeContractor(address)", "0x4c6d1d9e": "checkOutTag(string)", "0x09a399a7": "personAdd(string,int256,int256,string)", "0x31380c89": "TokenSale()", "0xd0bff051": "testSetBalanceDb()", "0x4c738909": "getMyBalance()", "0xb2310cc5": "payRequstedSum(uint256,uint256)", "0xda3c300d": "currentFee()", "0x6ed7c013": "move_monsters()", "0x4f073130": "takeOrder(bool,uint256,uint256)", "0x6860fd58": "Fees(uint256)", "0x214c9d50": "WritedrawStatus()", "0xf314bf46": "setReleaseDb(address)", "0x561a4873": "buyAd(string,string,string,uint256,uint8,address)", "0xf249cf19": "get_all_challenges()", "0xbbed7177": "getContentTimestamp(uint256)", "0xc864e760": "recordCommissionEarned(uint256)", "0x1896f70a": "setResolver(bytes32,address)", "0xfd35e71b": "entryPayoutDue(uint256)", "0x5a58cd4c": "deleteContract()", "0xb29b5366": "setRentable(bool)", "0xad5c613d": "purchase(bytes)", "0x6949a058": "sendOwnerEther()", "0xc03e382f": "calculateShare()", "0xf5bade66": "setDeposit(uint256)", "0x384e5018": "etherandomCallbackAddress()", "0xf06186c7": "testReality()", "0x677342ce": "sqrt(uint256)", "0x10e89b22": "remove_deal(uint32)", "0xf2b445ad": "rowround(uint256,uint256)", "0xd7ed7453": "redeemWinnings(uint256)", "0x92b4bb50": "rps()", "0x089327de": "MyToken()", "0x87ebd76c": "initContract(string,string,uint256,uint256)", "0xdbc45228": "newProposal(address,uint256,bytes,bytes)", "0x6b1feeeb": "get_my_sig()", "0x6837ff1e": "newContract(address)", "0x9f181b5e": "tokenCount()", "0x92ba4ba6": "GridMember(string,uint256,bool,address,address)", "0x45755dd6": "returnFunds(uint256)", "0xb4b9d1f1": "lookup(uint256,uint256)", "0x98024f18": "testThrowsTransferDisableNotEnabled()", "0x9e7b8d61": "giveRightToVote(address)", "0x8112821f": "EthVentures()", "0xe65d6b49": "getCommission()", "0x068c966b": "DrawDetails(uint256)", "0x9bb5239a": "CheckPrize(address,uint256)", "0xff08d2b0": "PayMiners()", "0x9be1fcee": "BankOwner_DisableConnectBankAccountToNewOwnerAddress()", "0x5f972df8": "_jDiv(uint256,uint256,uint256,uint256)", "0xfe8b6642": "setEnforceRevisions(bytes32)", "0xe4cc1161": "seedWithGasLimit(uint256)", "0x5fd4b08a": "getName(address)", "0xaa51793c": "isLosingBet(uint256)", "0x31757f2e": "collisionCount()", "0xe1f5ebc5": "_projectAddNew(address,uint256)", "0x64228857": "getRevisionCount(bytes32)", "0x5ca3400c": "WithBeneficiary(address)", "0x39f4debc": "fillOrderAuto()", "0xcc2c5453": "add_sword(uint16)", "0x0a19b14a": "trade(address,uint256,address,uint256,uint256,uint256,address,uint8,bytes32,bytes32,uint256)", "0x4d207d9a": "identify(address)", "0x3e83fe36": "getMyShares()", "0x8bb0faee": "setRef(string,string)", "0x38bbfa50": "__callback(bytes32,string,bytes)", "0xcee6f93c": "getResultOfLastFlip()", "0xbbba3333": "safer_ecrecover(bytes32,uint8,bytes32,bytes32)", "0x8e19899e": "withdraw(bytes32)", "0xd8389dc5": "hash(bytes32)", "0x8a4068dd": "transfer()", "0xea9e107a": "acceptRegistrarTransfer(bytes32,address,uint256)", "0x8f4ffcb1": "receiveApproval(address,uint256,address,bytes)", "0xf67abd87": "entryDetails(uint256)", "0x67acd805": "lowerMinWager(uint256)", "0xec035393": "_getAllRevisionBlockNumbers(bytes20)", "0xbd858288": "orderMatch(uint256,uint256,int256,uint256,uint256,address,uint8,bytes32,bytes32,int256)", "0x112c7075": "ManualDeposit()", "0xd81a91e9": "get_party2()", "0xc52bd836": "setDappOwner(bytes32,address)", "0xf84f420b": "getRandomNumber(address,uint256)", "0xcfe9a7b8": "getPackageName(uint256)", "0xe97dcb62": "enter()", "0x48db5f89": "player()", "0x6bdbf8e6": "concat()", "0x3c959aca": "CheckTickets()", "0x3aa5f4f7": "changeTokenSettings(uint16,uint256,uint256)", "0xac20902e": "NormalizeMoney()", "0x2fac1d36": "isReadyFor(address)", "0xdcaa5620": "findNextWeekday(uint256,bytes)", "0xf9909915": "bulkStoreHeader(bytes,int256,bytes,int256)", "0xcd2cdd5b": "claimOwnershi()", "0xcfae3217": "greet()", "0xf5c8d71b": "forceMove(address,address,uint256)", "0x9718b524": "newTreasury(address)", "0xd0679d34": "send(address,uint256)", "0x1301ee02": "transferringETC(address)", "0x60eb2826": "Badge()", "0x0d0c2008": "TwoAndAHalfPonzi()", "0x17e1bfb7": "addInstitution(address,string)", "0x06394c9b": "changeOperator(address)", "0x80c951bf": "currentClaimPriceInFinney()", "0xd063f55f": "toLittleEndian(uint64)", "0x53f818d6": "checkBetValue()", "0x9205fbc2": "testAuthorityAuth()", "0x3e4c0c82": "player_1(uint256)", "0xe571c35e": "ReverseRegistrar(address,bytes32)", "0x24804cef": "Deed()", "0x622e88cb": "testBitsXorSuccess()", "0xdfca2f53": "LookAtPrizes()", "0xafa293d4": "getSource()", "0x755f99c2": "AddNewSmallContract(address)", "0x7137ed47": "setProxyContract(address)", "0x835b42fc": "testThrowUpdateLatestRevisionNotUpdatable()", "0xdd34e129": "PriceTest()", "0xedb27f4e": "switchWizard(address)", "0x1c5d9faa": "setNickname(string)", "0x4746cef8": "_confirmAndCheck(address,bytes32)", "0x189c94ae": "testFallbackStaticSig()", "0x0cb749b6": "FutureBlockCall(address,uint256,uint8,address,bytes,bytes,uint256,uint256,uint16,uint256,uint256)", "0x2b25a7e4": "giveKudos(address,uint256)", "0x294f3d4d": "setUpLimit(uint256)", "0x2cce81aa": "getBlockHash(int256)", "0x4cd11943": "NewManualInvestor(address,uint256)", "0x7eaef50c": "over()", "0x8ac4e1d8": "TemperatureOracle()", "0xf108a7d2": "withdraw(uint256,address,string)", "0x00a676f9": "getExists(bytes32)", "0xb8d4efb5": "validate_percent(uint8)", "0xc7489441": "closeMarketMaker(uint256)", "0x3def449b": "FipsNotary()", "0x5687f2b8": "emitApproval(address,address,uint256)", "0xa9f8ec6c": "AlarmClockTipFaucet()", "0xd8e5c048": "scheduleCall(address,uint256,uint256)", "0x135217e7": "requires_depth()", "0x0aa46c12": "testClearBitFailIndexOOB()", "0x77d32e94": "ecrecovery(bytes32,bytes)", "0xace523c4": "createReferendum(string,string,uint256,uint256)", "0x5ca8bc52": "returnIt()", "0xdb318833": "_ecAdd(uint256,uint256,uint256,uint256,uint256,uint256)", "0x623195b0": "setABI(bytes32,uint256,bytes)", "0xd7bb99ba": "contribute()", "0x2880ebe7": "underdogPayoutMarkup()", "0x4ce01d86": "totalBetValue()", "0x837a7ba5": "testThrowTransferDisabled()", "0x386fcda8": "testCreateCostToken()", "0x0e850239": "scheduleCall(bytes4,bytes)", "0x163aba3c": "getQueryFee()", "0x9941e3d0": "setCallAddress(address)", "0x23637e60": "votePrice(uint256,bool)", "0xde78e78a": "tokenLaunched()", "0xe3579ea5": "publish(string,string,address,uint256)", "0x59a547b0": "recordCommission(uint256)", "0x1aa86370": "updateXIPFSPublicKey(string)", "0x97fcb54e": "transfer_eth(address,uint256)", "0x05d2f92a": "check_depth(address,uint256)", "0xdfcbb794": "TrustFund(address,uint256,address)", "0xb7dd1d17": "getAllRevisionBlockNumbers(bytes32)", "0x75862df4": "TokenWithEStop(address)", "0xd22057a9": "register(bytes32,address)", "0x29d017b5": "TestWithConstructor(address,uint256[])", "0xd216d55d": "etherandomExec(bytes32,bytes32,uint256)", "0xfba06849": "fipsPublishDataMulti(bytes20[],bytes)", "0xa37fd390": "setHomeAdv(uint256,string)", "0xcf2e3efc": "GetBankAccountBalance()", "0x423e7e79": "_dispatchEarnings()", "0x74087040": "testBitsNotEqualSuccess()", "0x61d585da": "state(bytes32)", "0xcfb3a493": "getMyBounty(uint256)", "0x5afeb106": "Sqrt()", "0xf9e84395": "unexempt(address)", "0x5669c94f": "issueToken(address,string)", "0x19b05f49": "accept(uint256)", "0x3ae01f84": "USDOracle()", "0x8c172fa2": "getEvent(bytes32)", "0x4671e65e": "proposeEmergencyWithdrawal(address)", "0xc27d7721": "create(uint256[101][])", "0x5c52e51e": "processPayout()", "0xf7a0fa0a": "getShareDistribution(bytes)", "0x31a3a506": "closeFunding()", "0x465e759b": "testRestart()", "0xb60d4288": "fund()", "0x52200a13": "getNumHolders(uint256)", "0xf2c298be": "register(string)", "0x7bc25372": "UserCheckBalance(address)", "0x104d5fdd": "getPriceProxy()", "0x447cd682": "scheduleTransaction(address,uint256)", "0xa045fdff": "scheduleCall(address,bytes)", "0x4757f1d2": "redeemAllOutcomes(uint256,uint256)", "0x5e855f14": "Dice(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)", "0x5d3c1d4c": "_getRequest(uint256)", "0x416c8701": "beyond()", "0x63aea3e0": "PlayerInfo(uint256)", "0xa163a624": "Test()", "0xedede601": "testBalance()", "0x13651124": "WithdrawAmountFromBankAccount(uint256)", "0x893d20e8": "getOwner()", "0x90b5561d": "insert(uint256)", "0xf9983a12": "GetMyInvestmentBalance()", "0xb71c47a2": "surrender()", "0xf2a75fe4": "empty()", "0x804ba97a": "tryGet(bytes)", "0x6506b623": "rotateBitsLeft(bytes,uint256)", "0x3ef8ec78": "announce_numbers(uint8,uint8,uint8,uint8,uint32,bytes32)", "0x73abecbb": "kill1()", "0xd5171523": "euroteambet()", "0x8e52cb51": "getRecordKey(bytes,bytes,bytes)", "0x7adbf973": "setOracle(address)", "0x4aa16737": "enter(uint8)", "0xf0cb556c": "updateLatestRevision(bytes32,bytes)", "0xbc8fbbf8": "nuke()", "0xc8e55708": "oraclize_query(string,string[1])", "0x7332b520": "getRewardsCount(uint256)", "0xf7c2b38c": "seconds_left()", "0xba344743": "_rawTransfer(address,address,uint256)", "0xcab5c0f1": "_incrementState()", "0xe044c2de": "newLoan(bytes,address,uint256,uint256,uint256,uint256,uint256,uint256)", "0x76abc03b": "getShareDistribution(uint256)", "0xf0da84f8": "getTransferable(bytes32)", "0xcde99727": "calculateROI()", "0x155dd5ee": "withdrawFunds(uint256)", "0x8b543b80": "maximumCredit(address)", "0x340ddda6": "MeatConversionCalculator(uint256,uint256)", "0x524f3889": "getPrice(string)", "0x84054d3d": "cashout()", "0x856f3080": "WhatWasMyHash(bytes32)", "0x0386a016": "closeProposal(uint256)", "0xcebce72d": "token(uint64)", "0x7f480f9d": "processDividends(address)", "0x11d12402": "testEasyPropose()", "0x2f695053": "getCertifierAtIndex(uint256)", "0xd9fcb31f": "comm_channel()", "0x141c4e60": "challenge(uint256,address)", "0x4ff13571": "x2()", "0xa01bc729": "monster_attack(uint256)", "0x2fe9541f": "addIssueBounty(string,uint256)", "0x5503a659": "smallponzi()", "0xdfc765dc": "getMatchers_by_index(uint256)", "0x0b7623ba": "abs(int8)", "0xcde0a4f8": "setRegulator(address)", "0xf95b5a58": "getInitialAnswer(uint256)", "0x66b42dcb": "register(address,string,uint256,string)", "0x9f2ce678": "vote(bytes32,bool)", "0xb3559460": "getGenerationSize(uint256)", "0x5ddae283": "transferRegistrars(bytes32)", "0x59dc735c": "getClient()", "0xc258ff74": "List()", "0x4fb4bcec": "step5()", "0xed684cc6": "trigger(uint256)", "0x09405164": "getOpenCandidates()", "0x5c5d625e": "getProof()", "0x9f5f7c7f": "tokenSplit(address,address,address,uint256)", "0x0e38901a": "unvault(uint256)", "0x75160a20": "pay_royalties()", "0x15398afe": "compareNumericStrings(string,string)", "0xbbd8b602": "getOracleOutcomes(bytes,address[])", "0xebae35a6": "DAOTokenCreationProxyTransferer(address,address)", "0x15abc160": "createValidatedRequest(address[3],address,uint256[11],uint256,bytes)", "0x830953ab": "claimAmount()", "0x26b916b4": "Set_Interest_Rate(uint256)", "0x1fb291cb": "registerInt(address,int256)", "0x505fb46c": "add(uint256,uint256,uint256)", "0xf00d4b5d": "changeOwner(address,address)", "0x034187fd": "setEthToCents(uint256)", "0x94d9cf8f": "CreateProxyWithControllerAndRecovery(address,address[],uint256,uint256)", "0xacbf98a7": "endsWith()", "0xfc2c3e08": "getIteration()", "0x6d7da0b1": "MyContract()", "0x1558ae4d": "Etheroll()", "0x42cbb15c": "getBlockNumber()", "0x29cd62ea": "setPubkey(bytes32,bytes32,bytes32)", "0x2030f721": "num_objects()", "0xbc08afd9": "WebOfTrustToken(address,uint256)", "0x8cdfb1e6": "transferIfHF(address)", "0xa0bd3c0f": "scheduleCall(address,bytes,bytes,uint256)", "0x4e71e0c8": "claimOwnership()", "0xc1cc0775": "calculateFeeDynamic(uint256,uint256)", "0x50c42921": "replicate()", "0x25495998": "getMinimumConsumerDeposit()", "0x3d8e2947": "getFileAddress(bytes)", "0x1f794436": "getBlockHeader(int256)", "0x7d380265": "addOptionChain(uint256,string,uint256,uint256,bytes32,address,int256[])", "0xec0b4153": "getMoneyness(int256,uint256,uint256)", "0x01775f23": "_closeBooks()", "0x9d063ed8": "FIFSRegistrar(address,bytes32)", "0x083b2732": "callback()", "0xa1920586": "offer(uint256,uint256)", "0x19c47214": "getBlockVersion(bytes)", "0xa293d1e8": "safeSub(uint256,uint256)", "0xfe73e3ec": "preliminaryGameResult(uint64)", "0xf004b12b": "CrowdFund(uint256,uint256,address)", "0x54d03b5c": "changeFeeMake(uint256)", "0x9dbc4f9b": "participantDetails(uint256)", "0xd002462b": "setDeploymentFee(uint256)", "0xed2b8e0b": "getPoolRotationDelay()", "0xf697a0ed": "ppb(uint256,uint256)", "0x964c836c": "receiveExecutionNotification()", "0x5e0e2957": "dumpOut()", "0x33232609": "blake2b(uint64[],uint64[],uint64)", "0x88f53db1": "getDataRequest(uint256)", "0x0caf9d39": "testFailTooManyMembers()", "0x1f2e886c": "testControllerTransferTriggersEvent()", "0x586a69fa": "getMaximumStackCheck()", "0xf64fca2e": "getNodeId(bytes)", "0x8b95ec0c": "testAddBalance()", "0x32e7c5bf": "B()", "0x57e6c2f4": "isAuthorized()", "0xb2f2588b": "sortNumbers(uint8[3])", "0xe95bee59": "checkFormat(string)", "0xcef887b0": "storeBlockWithFee(bytes,int256)", "0xbe26733c": "Kill()", "0xe82f7dd4": "testThrowsRetractLatestRevisionNotUpdatable()", "0xfd7ac203": "TestToken()", "0x6d052f56": "testBitsSetSuccess()", "0xf65c4d42": "Participate(uint256)", "0x432c685f": "trustClient(address)", "0xb0171fa4": "getCurrentGenerationId()", "0x03251a08": "setMin(uint256,uint256)", "0x58d3b617": "Notifier(string)", "0x15dacbea": "transferFrom(address,address,address,uint256)", "0x83f7b8e1": "getNumberOfPhotos()", "0xf1076703": "getVerificationId(address,bytes,bytes)", "0x752a3df6": "transferIfHardForked(address)", "0xaf93afdd": "Shipment(bytes,bytes,bytes,bytes,string,bytes,uint256,uint256,bytes,bytes,uint256,uint256,string,bytes,bytes,bytes)", "0x7fcf532c": "Withdrawal(address,uint256)", "0x72ea4b8c": "getNumInvestors()", "0x7df52ba8": "Arbitrate(uint32,uint32,bool)", "0xea25f24a": "TokenCreation(uint256,uint256,address)", "0xf74100e3": "getBits(bytes)", "0x63bfe3d8": "SkillBeatsLuck()", "0x80599e4b": "remove(string)", "0x6c050eae": "look()", "0xf9a794ad": "EtherLovers()", "0x501e8428": "getPart(bytes,uint256)", "0xf446c1d0": "A()", "0x2d67bb91": "World()", "0xeef547d7": "deal_details(uint32)", "0xa6cb9e64": "scheduleCall(address,bytes,bytes)", "0x659010e7": "m_spentToday()", "0x9b0b9c07": "acceptBankDraft()", "0x315e2f1b": "setTestString(string)", "0x69bcdb7d": "getCommitment(uint256)", "0xe1376da2": "updateFirstActiveGamble(uint256)", "0xc70d169d": "answerRequest(uint256,bytes)", "0xa094a031": "isReady()", "0x74e60a48": "cancelOrder(address,uint256,address,uint256,uint256,uint256,address,uint8,bytes32,bytes32)", "0x1b5ee6ae": "mintToken(int256,address,uint256)", "0x7f791833": "toTimestamp(uint16,uint8,uint8,uint8)", "0x5e6ad49d": "_setCosignerAddress(address)", "0xb2e85b67": "getPlayerStatus(address,uint256)", "0x30a24abd": "create(bytes4,bytes)", "0x9f0e3107": "get_timestamp(bytes32)", "0x33397816": "withdrawAccountBalance(address)", "0x0da3e613": "EthFactory()", "0xa5f3c23b": "add(int256,int256)", "0xc1829a14": "testFailTooFewConfirms()", "0x5322f0c5": "getChannelOwner(bytes)", "0x0fd1f94e": "firstClaimBlock()", "0x639d57f2": "testGetBitSuccess()", "0xd3aa22c7": "transferTLA(string,address)", "0x86314af9": "BetOnHashV84()", "0x3059ac30": "Escrow(address,address)", "0x0efafd01": "getPlayerGainLossOnLastFlip()", "0x49bf66d3": "addRegistryIntoNameIndex(address)", "0x3af39c21": "undefined()", "0xb660d77c": "switchMPO(address,address)", "0x0fdb468f": "fee(uint64)", "0x72479140": "CreateTicket(address,uint8,uint8,uint8)", "0xe79a198f": "unregister()", "0x688dcfd7": "setProofType(bytes1)", "0xfb9a4595": "GitHubBounty()", "0xd02a9889": "getDateOfFirstPayment()", "0xca35271c": "numDebtors(address)", "0x08714bfa": "TestContract()", "0x16d960b5": "createThing(bytes32[],bytes32[],uint88)", "0x17961d0f": "ord()", "0x62ba9687": "toTimestamp(uint16,uint8,uint8,uint8,uint8)", "0xbba91ea7": "getHomeadvIndex(uint256)", "0xb45105b2": "post(string,address,string)", "0xa7e25683": "testShortOutput()", "0xa068e8d3": "convict(uint256,uint256,uint256,uint256)", "0x09a69f57": "getRewardAmount()", "0xe7334156": "processNextDeposit(address)", "0x62ee6d29": "changeHashtoLowOrHigh(uint256)", "0xa80d4e9a": "EtherAuction(uint256)", "0x18489f50": "thingExist(bytes32[])", "0x5323c6cf": "calcCostsBuying(bytes,uint256,uint256[],uint8,uint256)", "0x9a777d5d": "buyCoins()", "0x36344022": "testAuthorizedTransfer()", "0x8b863095": "setContractorProposal(uint256,bytes)", "0xd10e99fe": "mint(int256,bytes32)", "0x12c82bcc": "sendRobust(address,uint256)", "0x0bf75567": "voteSuperQuorum(uint256,bool)", "0xf5f6ea26": "EthOne()", "0x14918f5e": "performInitialWithdrawal()", "0xdf32754b": "owned()", "0x1632070c": "setRewardDivisor(uint256)", "0xe50a3bb1": "oraclize_query(string,string[],uint256)", "0x9b619d3b": "_deleteAllPackedRevisionBlockNumbers(bytes32)", "0x3b751f7f": "claimThroneRP(string)", "0xd55ec697": "upgrade()", "0x43703b0e": "getEventData(bytes)", "0xd1bf9aba": "nextRune()", "0x76849376": "addNode(bytes32,address)", "0xfd958695": "isAlphaNumeric(bytes1)", "0x9fa5e5d5": "setARKowner(address)", "0x6e2cde85": "drawPot(string,string)", "0x4d5b080c": "scheduleTransaction(uint256,address,uint256)", "0xf1e4a540": "unsetCoordinator()", "0x364f4896": "emission(address,address,uint256,uint16,uint16)", "0x9183fd01": "getSeedPrice()", "0x9832ee65": "resultsWeightedByTokens()", "0xdd5244b4": "testTryProxyCallWithValue()", "0xec2ec781": "testFailGetUnsetToken()", "0x7db9743b": "Registry()", "0x1adf2d1a": "Offer(address,address,bytes,uint256,uint256,uint128,uint256)", "0x1ba326c4": "calcShare(uint256,uint256,uint256)", "0x3ced842b": "make_offer()", "0xea295ec2": "calcRevenue(address)", "0x3c894475": "scheduleTransaction(address,bytes,uint8,uint256[6],uint256)", "0x477bddaa": "setContractAddress(address)", "0xed180443": "getUint256(int256)", "0xee725d44": "toChannelID(string)", "0xa4898fd5": "deployContract(address)", "0x75ee85bd": "salsa20_8(uint256,uint256)", "0xbe7c29c1": "getNewDAOAddress(uint256)", "0xfe01f1ff": "TokenTester()", "0x6103d915": "Winners(uint256)", "0xa30b5c69": "AttributeModel()", "0x81064e2d": "getCreditorAmounts()", "0x23584a21": "initStats(string,address,uint256)", "0xe2894a8a": "OwnerAnnounce(string)", "0xa84c5330": "createNewRevision(bytes20,bytes)", "0xb742398b": "trade(address,uint256,bytes,address,uint256,bytes)", "0x3211bb90": "OwnerAddFunds()", "0xa0befa94": "getStake(uint256,uint256)", "0x6dc3edcf": "executeExecutable(uint256,uint256)", "0x17e875e3": "Transparancy()", "0x6939864b": "lotteryState()", "0x3b107682": "DualIndex()", "0x51b3d7b9": "_transferWithReference(address,uint256,string)", "0xdf7cec28": "cancelBid(bytes32)", "0x1e74a2d3": "getMinimumEndowment()", "0x39b333d9": "Play(uint8,uint8,uint8,uint8)", "0xcbd08c8c": "config(uint256,uint256,uint256,uint256)", "0xca6ad1e4": "setCustomGasPrice(uint256)", "0x510f44cb": "TestFactoryUser()", "0xcee6ee38": "aEthereumlotteryNet()", "0x11610c25": "bet()", "0xb73405a9": "roundMoneyDownNicely(uint256)", "0xb8851fea": "endDateStart()", "0xa4325485": "getCreatorBalance()", "0x2c181929": "getChainWork()", "0xffb4c857": "_confirmAndCheck(bytes32)", "0x9e66cd38": "free(uint64)", "0x44e43cb8": "depositRevenue()", "0xa553a597": "configure(uint256,uint256,uint8,address)", "0xc47f0027": "setName(string)", "0x565a2ecf": "classicTransfer(address)", "0x1da0fb1b": "updateSettings(uint256,uint256,uint256,uint256,uint256,bool)", "0xa5ebf389": "getMoneyTotals()", "0x7f445c24": "subRegistrar(string)", "0x9ad4f98e": "BlocksureInfo()", "0xd6b4ec12": "getDailyWithdrawalLimit()", "0xe0886f90": "at(uint256)", "0x5dc77e26": "andThen(string,address)", "0xe7d50e5c": "FarmShare()", "0x3f2965f0": "registerSeller(address)", "0x85b73d3c": "testCreateNewRevision()", "0x49437210": "getUpdatable(bytes32)", "0xe1a9109d": "setSeedPrice(uint256)", "0x95978868": "strConcat(string,string,string,string,string)", "0x511b1df9": "addr(string)", "0xc5b1d9aa": "newRound()", "0xecf6eb22": "setConfigAddress(bytes,address)", "0x9a9c9c53": "DepositToBankAccount()", "0x27ea6f2b": "setLimit(uint256)", "0xd2dc0869": "add(string,uint256,string,string,address)", "0xc86a90fe": "sendCoin(uint256,address)", "0x5dfc2e4a": "noop()", "0xd81e8423": "get(address,address)", "0x4cad42d3": "testWager()", "0xd120a284": "getBytesFromNumbers(uint8[3])", "0x991ffd4e": "scheduleCall(address,bytes,bytes,uint256,uint256,uint8,uint256)", "0x60c311fd": "doBurnFromContract(address,uint256)", "0xbb6a0853": "GreedPit()", "0xc27b2c2d": "collectEarnings()", "0x446294ad": "multiAccessGetOwners()", "0x5bec9e67": "infinite()", "0x47e7ef24": "deposit(address,uint256)", "0x8d216186": "roll(uint256,bytes32)", "0xdf300b46": "getThing(bytes32[])", "0x5a6c787e": "updateWithMPO()", "0x1f2dc5ef": "divisor()", "0x421aeda6": "Set_your_game_number(string)", "0xba1162d7": "getFmLength()", "0x853255cc": "sum()", "0x20768ee8": "getProposalID()", "0xf5c57382": "nameOf(address)", "0x4e417a98": "callData()", "0xc90d080a": "registerEvent(bytes)", "0x0b1e400a": "_transferFromToICAPWithReference(address,bytes32,uint256,string)", "0xe420264a": "g(uint256)", "0x8a00a82f": "withdrawRewardFor(address)", "0x06638e92": "GetNumbersFromHash(bytes32)", "0xf63da25b": "Emailer()", "0xc01706dd": "getContentByRank(address,uint256,uint256)", "0xe1108706": "rfind()", "0xffd10e07": "enterPool(address)", "0xc4254c7b": "CoreWallet()", "0x30e0789e": "_transfer(address,address,uint256)", "0x992ae976": "isSafePunctuation(bytes1)", "0x4afce471": "test_requires_depth(uint16)", "0xda7fc24f": "setBackend(address)", "0xeb7402f5": "multiAccessHasConfirmed(bytes32,address)", "0x6c1a5b8c": "TOKEN_TARGET()", "0xb3a2a999": "nextWithdrawal(bytes16)", "0x4a420138": "scheduleHeartbeat()", "0xb1233451": "setTerm(uint256,string)", "0x266710ca": "manualUpdateBalances_only_Dev()", "0x98866c1a": "personUpdateDOD(uint256,int256)", "0xaa6be303": "debtors(address)", "0xda5c0a7c": "testDisown()", "0x8757a2cd": "test_depth(uint256,uint256)", "0xe1bedf2a": "AlarmTester(address)", "0x5dcbac7a": "registerBytes(address,bytes)", "0xa587da29": "setPackage(bytes,uint8,uint8,uint8,bytes)", "0xc3da42b8": "c()", "0x4b8772c1": "buyUnit(uint256,uint256)", "0x67f12ecf": "validate(address,uint256,uint256[101][])", "0x0bd089ab": "MyAdvancedToken(uint256,string,uint8,string,address)", "0x32829a23": "OpenBankAccount()", "0xdea06188": "NumberOfBlockAlreadyMined()", "0x61e539da": "testFailWrongAccountTransfers()", "0x8a3e44d4": "assetMoveInformation(address,address)", "0x1327d3d8": "setValidator(address)", "0x207c64fb": "validate(address)", "0x80acaafb": "profitDistribution()", "0x90b98a11": "sendCoin(address,uint256)", "0x8b147245": "update(bytes32)", "0x920c94df": "BuyTicketForOther(address,uint8,uint8,uint8)", "0x6f698fb5": "setMinimumQuorum(uint256)", "0xac5e81a9": "historyPayout(address)", "0x70d084c0": "SingularDTVCrowdfunding()", "0x67ce940d": "getOverhead()", "0x7a791524": "setNextFeePercentage(uint8)", "0xd6d902c4": "claimThroneFor(bytes,address)", "0xc71e48d6": "setOutcome(bytes32,bytes32[])", "0xef41e06f": "testThrowSetEnforceRevisionsNotOwner()", "0x70be4ffa": "testErrorUnauthorizedSetPackage()", "0x6d12301c": "getBetValue(bytes32,uint8)", "0x4e69d560": "getStatus()", "0x55234ec0": "remaining()", "0x5cfd8c24": "ResetPonzi()", "0xe29fb547": "scheduleCall(bytes4,uint256,uint256,uint8,uint256)", "0xbd119967": "add_rating(uint256,uint256)", "0x966acb38": "testThrowTransferNotTransferable()", "0x5c665f89": "getFunds(address,bool)", "0xa59d6986": "recoverLostFunds()", "0x403abbc7": "updateFirstActiveGamble()", "0x0230a07c": "releaseDeed(bytes32)", "0x2d116186": "deityBalance()", "0x602acca1": "InchainICO(address[],uint256)", "0xd393c871": "register(string,address,uint256)", "0xe0fe075e": "payoutReady()", "0xf3e3c629": "testBalanceOfStartsAtZero()", "0x48cd4cb1": "startBlock()", "0x669459a7": "removeRegistryFromOwnerIndex(address)", "0x74d89c47": "testUpdateNameDb()", "0x182db370": "getWhatHappened()", "0xf363441f": "getCreatorDotBalance()", "0x6896fabf": "getAccountBalance()", "0xb29a0308": "logAnonymous(bytes,bytes,bytes,uint256)", "0x3023d0c4": "Ethstick()", "0x1077f06c": "makeClaim(uint256)", "0x8a519fb9": "BlockChainEnterprise()", "0xbffbe61c": "node(address)", "0xe20bbd8d": "RecoveryWithTenant()", "0x03bda14e": "raiseMaxNumBets(uint256)", "0xe1041d86": "__throw()", "0x3d79d1c8": "bal()", "0xbd3f0965": "AiraEtherFunds(string,string)", "0xc388cca6": "testBitAndFailIndexOOB()", "0x921f98bb": "resolveFailVote()", "0x4bbb216c": "_target(address)", "0x10922cc1": "testTransferCost()", "0xeceb2945": "checkProposalCode(uint256,address,uint256,bytes)", "0x3df4ddf4": "first()", "0x21a49ec2": "LCoin()", "0x6d1f00a6": "ThroneMaker(uint256)", "0xcaed4f9f": "DataService()", "0x5cff876b": "carrotsCaught()", "0x3a7fb796": "mintGreen(int256,address,uint256)", "0x370b6939": "AdminSetDrawer(address)", "0x2d9a37d3": "getMaxPayout()", "0x739f888c": "setNewEstimate(int256,int256)", "0x04dd69fa": "getGenerationIdForCall(address)", "0xb764e273": "failSend()", "0xd4dfadbf": "getMarket(address)", "0xa0e67e2b": "getOwners()", "0x2d592a34": "sellKissBTC(uint256)", "0x8a341c83": "testErrorRootAuthorityChangeUnownedPackage()", "0xfcc6b5d5": "fillTheirOrder(address)", "0x61649472": "getPoolFreezePeriod()", "0x3dd297da": "safeMultiply(uint256,uint256)", "0x5d3278f0": "LooneyFifty()", "0x7399646a": "theRun()", "0x3e450fff": "adminDeleteAccount()", "0x93cc9162": "taskRejected(uint256,uint256)", "0xbc5d0f65": "beginExecution()", "0x1934d55a": "isPermanentlyApproved(address,address)", "0xf1cff4b5": "testBitsNotSetSuccess()", "0xf240f7c3": "dispute()", "0xf6d5959b": "getActionStatus(uint256)", "0x0f23cbaa": "recycle()", "0x74f8d96e": "getRevisionBlockNumber(bytes20,uint256)", "0x0bad342a": "EscrowContract(address,address,address,address,uint256,uint256,uint256,uint256)", "0xa6afd5fd": "getBets()", "0x84ad6ff3": "ReversibleDemo()", "0x62b3b833": "createCoupon(string)", "0x523ccfa8": "isKnownCall(address)", "0xacc8cb18": "pushTerm(string)", "0xa753d6f2": "CreateProposal(string,string,string,string,string,string,uint32,uint32)", "0xc5699d68": "_compare(int256,bytes,int256)", "0xe2faf044": "createDAO(address,uint256,uint256,uint256)", "0xa15afb48": "Replicator()", "0x352d2790": "UUID4()", "0x7dee2cad": "CancelMyInvestment()", "0xbeabacc8": "transfer(address,address,uint256)", "0x674f220f": "previousOwner()", "0x4b3b6168": "SetNewBigContract(address)", "0x54ba7daa": "enter(bytes,bytes)", "0x06fdde03": "name()", "0x5944427b": "getRequestResult(uint256)", "0x983ef725": "getDifficulty(uint256)", "0x9287c877": "getNavLength()", "0xa987d654": "restoreItem(uint256)", "0x05433a26": "GetNumbersFromHash(bytes)", "0xd04bfc9c": "buyer_pay()", "0x4a9b3f95": "personUpdateName(uint256,string)", "0xe6b972f5": "userName(address)", "0x88782386": "UnicornMilk()", "0x74580e2f": "changeCreator(address)", "0x1785f53c": "removeAdmin(address)", "0xad544dcb": "testSetNotUpdatable()", "0xafd09bab": "quadrupler()", "0x77bc222c": "_eraseSingleNode(bytes32)", "0x09957e69": "newSale(bytes,uint256,uint256)", "0xa21931ea": "CreateProposal(string,string,string,uint32,string,string,string,uint32,uint32)", "0xbb6b4619": "SendETC(address)", "0x3aa94b1d": "getCoinStats(uint256)", "0x9e2262f5": "testCreateCostData()", "0x2bf4e53d": "getCurrentShareholders()", "0x6111dd02": "calcCostsSelling(uint256,uint8,uint8,uint256)", "0x6b9b1006": "TransactionRecorder()", "0x83b23b40": "cEthereumlotteryNet()", "0x770c6cbb": "WithDrawPreForkChildDAO()", "0x67080f6e": "testThrowsSetEnforceRevisionsNotOwner()", "0xa10bee85": "_transferFromWithReference(address,address,uint256,string)", "0x49cc954b": "twoYearsPassed()", "0x88c3ba85": "ParallelGambling()", "0x03985426": "getMode(bytes32)", "0xad8ed335": "__proxy(address)", "0x306387a4": "dealStatus(uint256)", "0x0343dfa0": "checkInvariants()", "0x23df9df5": "_refund(uint256)", "0x837e7cc6": "rollDice()", "0x98b1e06a": "deposit(bytes)", "0xa0440426": "purchaseProduct(uint256,uint256)", "0x4cb71b9b": "getAllReleaseHashes()", "0x3a7d280c": "login(string)", "0xb9a904f9": "testUnauthorizedSetBetaPackage()", "0xe94a4db1": "isSuitableGen(uint256,uint256)", "0x60f8af90": "refundRound()", "0x43bf718e": "getHashOfTheProposalDocument()", "0x4a30f976": "censorship(uint256,bool,bool)", "0x47e46806": "toString()", "0x8d59cc02": "register(address,string,string)", "0xb3fb14ad": "getGameResult()", "0x4a23dc52": "FileStore()", "0x8da5cb5b": "owner()", "0x3cc8daf7": "setNameOwner(bytes,address)", "0x14cbdb54": "EspCoin()", "0xc47cf5de": "getAddress(bytes)", "0x71e11354": "updateRegistration(string,string)", "0x8b2e6dcf": "publish(bytes32)", "0x12d00c2e": "soloWithdraw(uint256)", "0xd68199dc": "gameStats()", "0xf0f967e8": "canCall(address,address,bytes)", "0xe0c7c117": "Randao()", "0xddeae033": "claimFor(address)", "0xcec7260b": "move_monster(uint16,uint16)", "0xe51ace16": "record(string)", "0x4f76cb02": "testGetBitFailIndexOOB()", "0x942385eb": "getPayroll()", "0x46d667db": "setBytes32(bytes)", "0x35a063b4": "abort()", "0xb1d51d31": "pay(uint64,address)", "0x7140bdf3": "get_all_best_offers()", "0x0380e2f3": "getHashOfTheSignedDocument()", "0x2feda2fa": "POI()", "0x3c0870ae": "challenge(uint256,uint256,uint256,bool)", "0x27a5c7c6": "voteDecline(uint256)", "0xafd8c8c4": "GasProxy(address,address)", "0x8de93222": "purchase(address,uint256)", "0x087e055a": "getConfigBool(bytes)", "0xbaccc92b": "RegulatorIfc(address)", "0x8c546f81": "GNT()", "0x57cb2fc4": "getInt8()", "0xe3083fb5": "removeFromContribution(uint256)", "0x1a092541": "getDescription()", "0x7486a8e3": "get_publisher(bytes32)", "0x089e0ad0": "buildDSMap()", "0x29161820": "Base(uint256)", "0xe2f8feb2": "internal_tester(int256)", "0x1d2dbb22": "CancelMyInvest()", "0x726ab4ef": "getParentHash(bytes)", "0x83d8a90f": "theDonkeyKing()", "0x9babdad6": "removeShareholder(address)", "0xdeb931a2": "getOwner(bytes32)", "0x90cb04e1": "buy(string,uint256,uint16)", "0x2ff92323": "oraclize_query(uint256,string,string[4])", "0xf91a792e": "decryptHand(string,uint256,uint256,uint256)", "0xebf6e91d": "hit(uint256)", "0xb085b9a5": "Example()", "0x07b2779f": "BasicRegulator(address,uint256,uint256)", "0xe10e5dce": "_build(bytes)", "0x3e239e1a": "getHour(uint256)", "0xacc5a0dc": "GetPrize()", "0xa79deb4f": "acceptTradeDeal()", "0xd7c26adb": "oraclize_setProof(bytes1)", "0xc6a17d2b": "pow10(uint256,uint8)", "0xa87d942c": "getCount()", "0xe706918c": "testToggleBitSuccess()", "0xc1812b15": "reorganizeOwners()", "0x7c7c7695": "getAccountID(address)", "0x1a26ed1c": "validateReservedWindowSize(uint256,uint256)", "0x87393bc6": "verifyFirstHalf(uint256[4],uint256[4])", "0x2e52d606": "n()", "0x2037fcbf": "withdrawInvestment(uint256)", "0x77228659": "query2(uint256,string,string,string)", "0xf67a1d37": "BlockChainChallenge()", "0xc67146a5": "check_bet(uint256,address,uint8)", "0xc89f2ce4": "funds()", "0x58e29e17": "initiateProof()", "0xf0e10c0d": "play(address,uint256)", "0x480b70bd": "scheduleCall(address,bytes4,uint256,uint256)", "0x5294157f": "sendWithAllOurGasExceptExt(address,uint256,uint256)", "0xad447a19": "getBalanceDB()", "0x41095b60": "voteForUltimateOutcome(bytes,uint16)", "0x5521d17b": "betOnColor(bool)", "0xc8f8d75d": "Config(uint8,address)", "0x10ae4ce2": "setReleaseValidator(address)", "0x9fd4f7d1": "replaceWizard(address)", "0x77c78df9": "getCurrentLevel()", "0x1dda5c7d": "testFailSubBalanceBelowZero()", "0x21e5383a": "addBalance(address,uint256)", "0xb0414a2d": "setMinimumGasLimit(uint256)", "0x919840ad": "check()", "0xf651bf44": "move_to(uint16)", "0x0b97bc86": "startDate()", "0x29f1bff4": "withdrawFromChildDAO(uint256)", "0x7a02dc06": "getInfo(bytes32)", "0xe5bf93b9": "balanceEther(uint256)", "0x288c6ed2": "getSeedCost(uint256)", "0x4db3da83": "scheduleCall(bytes4)", "0x270cfee1": "getTokenAccount()", "0xb5d03751": "YoutubeViews()", "0x27e056a5": "addMinter(int256,address)", "0xfa7d68f1": "getAccountInfo(uint256,uint256)", "0x09fc8f6d": "isTokenUpgraded(bytes32)", "0xa5b9e922": "getContentTimetamp(uint256)", "0x1f8947c1": "extractUint(int256,bytes,uint256,uint256)", "0xbcc941b6": "totalWinners()", "0x1db71ffb": "doLoops(uint256)", "0x35ae41c9": "godAutomaticCollectFee()", "0x42cf0e72": "searchByOwner(address)", "0x69f18967": "testSetBitFailIndexOOB()", "0x57b07cd9": "getReleaseHash(uint256)", "0x2baf4f22": "_safeFalse()", "0x3133f2a7": "outstandingBalance()", "0x773c84ee": "exec(address,bytes,uint256,uint256)", "0x9070b18d": "_getAllRevisionBlockNumbers(bytes32)", "0x476e04c7": "NewMessage(string)", "0x3b91ceef": "setMax(uint256,uint256)", "0xe6cb9013": "safeAdd(uint256,uint256)", "0xc2038560": "setOutcome(bytes,bytes)", "0xbed34bba": "compareStrings(string,string)", "0xba8661a2": "TimestampScheduler(address)", "0x4c4aea87": "getReleaseData(bytes32)", "0x1177892f": "getBalanceByAdress(address)", "0x126a710e": "dnsrr(bytes32)", "0x60913244": "botOnSale(uint256,uint256)", "0x5731f357": "oraclize_query(uint256,string,string,string)", "0x3e58c58c": "send(address)", "0x2187a833": "setGreenToken()", "0x5f09952e": "voteAllowTransactions(bool)", "0xf2b26d8f": "nextEtherForSale()", "0x1f201e39": "etherandomExecWithGasLimit(bytes32,bytes32,uint256,uint256)", "0x43d726d6": "close()", "0x6cdf4c90": "ownerSetMinBet(uint256)", "0xe6e8c692": "computeResponseFirstHalf(uint256,uint16)", "0xd1d80fdf": "setAddr(address)", "0x6da1833c": "getInstitutionByName(string)", "0x7682e6ff": "getTrustSetting(address)", "0x8f6f988c": "setUltimateOutcome(bytes)", "0xe299beb3": "SimpleIndex()", "0xa2bb5d48": "get_username(address)", "0x780900dc": "create(uint256)", "0x78710d37": "seven()", "0x2b20e397": "registrar()", "0x4094ef5e": "addDataRequest(string)", "0xc630f92b": "canEnterPool()", "0xdd114c22": "publish(address,uint256,address,uint256)", "0x57006864": "checkBetParity(uint8)", "0x45788ce2": "prev(address)", "0xee8ff562": "setMaxProfit()", "0xdc63a62c": "getFileListHead()", "0x9447fd0a": "until()", "0xb303dcbd": "Owned()", "0x0ecaea73": "create(address,uint256)", "0x20339891": "addGridMember(address)", "0xc8c01a55": "request(address,uint256)", "0x76f10ad0": "getSnapshot(uint256)", "0xc06c4474": "get_burned(bytes32)", "0x67cb61b6": "getChoice()", "0xca708230": "funnel()", "0x08b7fa31": "PriceFeed()", "0xac6bc853": "startSpin()", "0xf4bbfd6a": "scheduleCall(bytes,bytes)", "0xab73e316": "next(address)", "0xba0179b5": "confirm(uint256)", "0x1e62be25": "Bytes32Passer()", "0xb950556a": "setThingValid(bytes32[],bool)", "0xb61c0503": "fireEventLog1()", "0x79a85e6c": "getProductInfo(uint256)", "0x959ac484": "push(uint256)", "0x78e80b39": "UserGetPrize()", "0xff74927b": "strConcat(string,string)", "0xd207e757": "ownerSetOraclizeSafeGas(uint32)", "0x5819dde2": "getNumbersFromBytes(bytes3)", "0xf34ed4e6": "RanDAOPlus(address)", "0x3943807b": "insert(bytes,bytes,int256)", "0x38cc4831": "getAddress()", "0x12a7b914": "getBool()", "0xa4fd6f56": "isEnded()", "0x6c86888b": "testTrade(address,uint256,address,uint256,uint256,uint256,address,uint8,bytes32,bytes32,uint256,address)", "0x0bebd0f9": "addAddressToGeneration(address,uint256)", "0x003074ff": "getFrontend()", "0x2776a859": "computeResponseSecondHalf(uint16)", "0xadfe6b80": "InvestAdd()", "0x6981b5f4": "getLength(string)", "0x4a994eef": "setDelegate(address,bool)", "0xbac1e9f6": "getChannelSize(address,uint256)", "0xbdfdb519": "accept(string,uint256,uint16)", "0x68f5aa0f": "setShareholderDB(address)", "0xafb95eed": "logApproval(address,address,bytes32)", "0xae152cf4": "oraclize_query(string,string,uint256)", "0xe3b26a8c": "SocialNetwork()", "0x54204ad4": "triple()", "0xbc8f3bcb": "ZeroDollarHomePage()", "0xf0350c04": "transfer_ownership(address)", "0xfde9ba41": "transfer(bytes,address,uint256)", "0xfa2acd87": "G(uint64[16],uint256,uint256,uint256,uint256,uint64,uint64)", "0x3a76abff": "_eraseNode(uint256,bytes32[],bytes32)", "0x0acf473b": "AdminCloseContract()", "0x299e7318": "resolveVoting()", "0xb414d4b6": "frozenAccount(address)", "0x8d375da2": "testMakeItFail()", "0x6e8dad74": "retrieveAccountBalance(bytes,bytes)", "0xd3aa831f": "testOwnedTryAuth()", "0x13220305": "doTransferOther(address,address,address,uint256)", "0xb0c7f709": "kingAutomaticCollectFee()", "0x2dabbeed": "reclaim(uint256)", "0x5c19a95c": "delegate(address)", "0xbc2a4dd6": "doBalanceOf(address)", "0x8e7ea5b2": "getWinner()", "0xdb37e42f": "multisetProofType(uint256[],address[])", "0xa6b197aa": "Order(address,uint256)", "0x8cf4dbfb": "collectBalance()", "0xd0821b0e": "bet(uint8)", "0xa02b161e": "unregister(uint256)", "0x09dd0e81": "getBlockchainHead()", "0x8a0807b7": "indexOf(string,string)", "0xe3914699": "dEthereumlotteryNetWinners(address)", "0x44d75fa9": "updateMinorTree(bytes32)", "0x3c21db0a": "theGames(uint256)", "0xf0e959f9": "TokenSales(address)", "0x696bda86": "submitProposal(uint256,bytes)", "0x3b343a13": "getNodeAddress(bytes)", "0x2812f8b8": "FutureCall(address,uint256,uint16,address,bytes4,bytes,uint256,uint256,uint256)", "0xbf32bf97": "FailGuyTax()", "0x89ced196": "setNotUpdatable(bytes32)", "0xb94e962a": "allocateTickets(uint256)", "0x7a479160": "getRequestArgs(uint256)", "0x5a825cbb": "getPayment(uint256,uint256)", "0x4ca8b0d0": "registerExistingThrone(bytes,address,uint256,uint256)", "0x82afd23b": "isActive(uint256)", "0x6ebf10fe": "storeHeader(bytes,address)", "0x1437f9a3": "Set_your_game_number(uint16)", "0xd98d011d": "getCandidateKey(bytes,bytes,bytes,bytes)", "0x8b676ae8": "scheduleCall(address,bytes4,uint256,uint256,uint8,uint256,uint256)", "0x90fd53ec": "farmTile(uint8,uint8,int8)", "0x46e44f63": "getCheckRecordTS(bytes)", "0x1de38038": "makercoin(uint256)", "0xc038a38e": "totals()", "0xfa80918b": "computeNodeId(bytes,bytes)", "0xc76a4bfb": "relayReceiveApproval(address,address,uint256,bytes)", "0x2406cedb": "setPackageOwner(bytes32,address)", "0xb7297cf3": "gameSettings()", "0xe94acf0e": "TinyRouter(address)", "0x4a2b0c38": "DividendProfit()", "0x0e3f732a": "TheGame()", "0xd62457f6": "callValue()", "0x4961b40c": "getReleaseValidator()", "0x540cafe0": "storeHeaderWithFee(bytes,int256,address)", "0x7ff729fc": "fillUpProject(uint256,uint256)", "0x253459e3": "feesSeperateFromBalanceApproximately()", "0x930a80b4": "testAuthorizedSetPackage()", "0xb3cb8885": "nextUnderdogPayout()", "0x62c7855b": "getConfigBytes(bytes32)", "0x4f28af6a": "handleBet(uint256)", "0x103f9251": "transferFrom(address,address)", "0x9b19251a": "whitelist(address)", "0x9928811b": "testBroken()", "0xb33a8a11": "setTokenReference(address)", "0x27f06fff": "requestFillUp(uint256)", "0x2f570a23": "test(bytes)", "0x96ef7aa0": "cash_transfered(string)", "0x3983d5c4": "calcBaseFee(uint256)", "0xec0f1025": "testBitsOrSuccess()", "0xd35f4a99": "mint(int256,address,uint256)", "0x09dfdc71": "currentPyramidBalanceApproximately()", "0xac4e73f9": "proposeReverse(string,address)", "0xac4bd53a": "currentLeader()", "0x5a2ee019": "m()", "0xeba36dbd": "setAddr(uint256,address)", "0x0358d965": "addPayout(uint256)", "0xd7206124": "setInvestorLock(bool)", "0xe916d0f0": "doBalance(address)", "0x67c2a360": "authorizeUser(address)", "0x828d671c": "dyn_sig()", "0xaf6fe8e2": "testGetToken()", "0x283a4576": "Tomeka()", "0x8ac0ca36": "buyViaJohan()", "0xcc872b66": "issue(uint256)", "0xd826f88f": "reset()", "0x2aa3177a": "self_store()", "0x53b7b2e9": "cEthereumlotteryNet(bytes)", "0xce88b145": "getAccount(uint256)", "0x1fa03a2b": "isApprovedFor(address,address)", "0xe42d5be0": "getPaymentOf(address)", "0xb722a9ef": "getPreviousShareholder(address)", "0xfadf87b1": "testGetBitsSuccess()", "0xd26c8a8a": "coinBalance()", "0x30ccebb5": "getStatus(address)", "0x47799da8": "last()", "0x4a5db3b5": "authorizeAddress(address)", "0x22686250": "index(int256,uint256)", "0x07ef99a0": "demintTokens(int256,address,uint8)", "0xea2d4cf8": "__DeployerFunctions(address,address,uint256)", "0x092a2e37": "multiAccessAddOwnerD(address,address)", "0x671fa0a0": "Inscription(string)", "0xa10edc55": "GeneralPurposeProfitSplitter()", "0xd9c67404": "getMerkleRoot(bytes)", "0xdc419fd8": "cancelOrder(bool,uint256)", "0xc9734ebd": "WatchLastPayout()", "0xc7d6faf1": "easyPropose(address,uint256)", "0xfe63300a": "registerExternalBill(uint256,address,address,uint256,uint256,uint256)", "0xd3437fe0": "assertFact(uint256,bytes)", "0x5fb3e119": "Auction()", "0x665beae7": "ExecutableBase(bytes)", "0xc8bb73ef": "testGetBitsFailIndexOOB()", "0xc1d4f708": "getMwLength()", "0x22b0f6ee": "getStatusOfPayout(uint256)", "0x21520c5f": "calculatePayout(uint8,bool,uint256)", "0x66e98c31": "createCoin(string,uint256,uint256,string,string,address)", "0x7b352962": "isFinished()", "0x48d9614d": "GetFee()", "0xfe0d94c1": "execute(uint256)", "0xe4547f98": "documentExists(bytes)", "0x4e10c3ee": "transferWithoutReward(address,uint256)", "0x58ae8bcf": "voteInMasterKey(address)", "0x1dcb304b": "fipsGenerate()", "0xb595181f": "ShapeshiftBot()", "0xe02426c1": "getSignatureHash(bytes4,uint256)", "0x67546967": "EthBtcEscrow()", "0x85b31d7b": "myInfo()", "0xaa677354": "register(address,address)", "0x1d2e2cc4": "ENS()", "0x1097e579": "Enter()", "0x13a396d8": "getRequiredDeposit(bytes)", "0x6df3edef": "getSavedBytes()", "0x09b30ed5": "afterExecute(address)", "0x718e6302": "play(string)", "0x8e46fbb2": "testBitsXorFailIndexOOB()", "0x0d87a7c0": "WLBDrawsDB()", "0xbbe42771": "closeDeed(uint256)", "0xedfbf7b6": "setVotingDeadline(uint256)", "0x299e6b07": "Wallet(address)", "0x5cbc85d0": "returnBounty(uint256)", "0xe5225381": "collect()", "0x94f60a63": "getKudosLeft(address)", "0xd6960697": "confirmPurchase()", "0x4a1f0bf6": "inheritToNextGeneration(address)", "0x244ded7a": "ChangeOwnership(address)", "0x39b35753": "authCancel(address)", "0x75cb2672": "configure(address)", "0x938ae4cc": "testThrowDisownNotTransferable()", "0x04fc11d5": "getActual()", "0xacab021c": "getTOS(address)", "0x812cddf2": "getSavedString()", "0x8ae475a9": "notorize(string)", "0xb1d05422": "SendEmail(string,string)", "0x0fffbb54": "changeRankingSize(uint256)", "0xb6ed9f15": "PFOffer(address,address,bytes,uint256,uint256,uint128)", "0xda333ca6": "payOut(uint256)", "0x652f1f16": "addSignature(string)", "0x983b2d56": "addMinter(address)", "0x5e1936d4": "testThrowSetNotTransferableNotOwner()", "0x4ac1ad78": "getWeekday(uint256)", "0x6ba0b4f2": "isKnownSelector(bytes4)", "0x7c4c27c8": "isThisPuritanicalVersion()", "0x7ae2b5c7": "min(uint256,uint256)", "0x63bd1d4a": "payout()", "0x3fd94686": "changeEligibleDonkeys(uint256)", "0x7fe0518a": "asyncSend(address,uint256)", "0x5a8dd79f": "getDesignatedCaller(address,uint256)", "0x2635f4de": "registerLibrary(bytes,address)", "0x1335ff36": "createEventAndMarketMaker(uint256,uint256,uint8,uint32,address,uint256,uint8,uint16,uint256)", "0x181be00d": "getValue(uint8)", "0x9c1500f0": "registerMany(address,uint256,int256,uint256,bytes,address,bytes)", "0x16f9ce49": "_slotCommitNew(address)", "0x8ca4eef6": "getBuild(bytes32)", "0x8ee21b8e": "get_default_keys()", "0xa66f7ad6": "signRelease(uint256)", "0x414053be": "best_adjustment_for(bool,uint128)", "0x83a51ad0": "oraclize_setConfig(bytes32)", "0x262c0b72": "getPayoutFreezePeriod()", "0x499af77c": "current_spin_number()", "0x4209fff1": "isUser(address)", "0x6e1b6bcc": "checkMyBet(address)", "0xb46300ec": "send()", "0x6b1cb549": "orderMatch(uint256,uint256,uint256,int256,uint256,uint256,address,uint8,bytes32,bytes32,int256)", "0x58d9fa04": "addUser(uint256,address)", "0x24c93343": "error(string)", "0xa95d017d": "getRevisionBlockNumber(bytes32,uint256)", "0x46af23f5": "InstantLottery(address,address,bool,address)", "0x29ef56b1": "getAskOrderBookStats()", "0xe97db66e": "setJackpot()", "0x4b59e880": "puzzle(address,bytes32,bytes32)", "0xc7f86c37": "withdrawFundsRP()", "0x57d4021b": "nextPayoutWhenPyramidBalanceTotalsApproximately()", "0xf1c760ae": "fixBalanceInternal(address)", "0x0908178f": "NoFeePonzi()", "0x22ebb3ac": "DieselPricePeg()", "0xb39a64cd": "getNumCalled()", "0x1c02708d": "killContract()", "0x65228934": "setOperationsCallGas(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)", "0x3397ca17": "numBalanceRecords(address)", "0xe436bdf3": "Draws(uint256)", "0xaf55bba0": "removeRegistryFromTagsIndex(address)", "0x11103599": "Token_Offer(address,address,uint16)", "0xb3a2a6c0": "setOfficialWebsite(string)", "0xb06eb03f": "DSEasyMultisig(uint256,uint256,uint256)", "0x775c300c": "deploy()", "0xb1c6517a": "LookAtNumberOfPlayers()", "0xc19d93fb": "state()", "0xac9873c7": "CanaryV7()", "0x750cae6a": "enableBetting_only_Dev()", "0xdf3c8620": "num_challenges()", "0xbb00fc55": "bookEarnings()", "0x0bd2ae1c": "ERW()", "0x580bdf3c": "disableBetting_only_Dev()", "0x5c3f9765": "endDateClose()", "0xc4128b6d": "upgradeCount()", "0x140b4465": "executeSpendingRequests()", "0xfaa1a8ff": "getOwnedBot(address,uint256)", "0x40e58ee5": "cancel(uint256)", "0xf4ea95b9": "validateReleaseVersion(uint32[3])", "0x2ba0b09f": "AddNewCategory(bytes4,uint8,uint8,address)", "0x55db4092": "setTOS(address,bool)", "0xf9cc0605": "getAvailable()", "0x3f2f46b4": "revealRock(string)", "0x2af7ceff": "testPrice(uint256)", "0xcaaf2dd7": "getInitialAnswerResult(uint256)", "0x6f36ce79": "insert_deal(address,address,uint64,uint128,uint32)", "0xa18c751e": "set(bytes,bytes)", "0x4d536fe3": "doit()", "0x3197cbb6": "endTime()", "0xb83069c5": "getStemPrice()", "0x3f15457f": "ens()", "0x81ebdeea": "testThrowCreateWithNonceRetracted()", "0x249b4d0b": "removeTrustedIssuer(address,bytes)", "0xe7b48f74": "get(int256,address)", "0x089d5c4a": "repr()", "0x3a9e7433": "scheduleCall(bytes4,uint256,uint256,uint8)", "0x504f1671": "getSize(address)", "0xf3a44fe1": "withdrawForWorkshop()", "0x7a837213": "setAllowedAccount(address)", "0x4551b1d7": "ProxyPayment(address,address)", "0x5dac1601": "SimpleStablecoin()", "0x87914c6f": "prolongateContract()", "0xe3ceb06d": "YesNo(bytes32,address,string,address,uint256)", "0x42a745cb": "testBitEqualSuccess()", "0xaa8dea8c": "fipsAddToLedger(bytes20,address,bytes)", "0x986dcd4d": "setCycleLimit(uint256)", "0x1e44c112": "find_strike(uint64,uint32,uint32)", "0x1ecfe64d": "_jSub(uint256,uint256,uint256,uint256)", "0x4ae85627": "grindUnicorns(uint256)", "0x200ebe34": "addTokensToGive(address)", "0x7b632c41": "TimestampScheduler(address,address)", "0x979b6f6f": "RoundInfo()", "0xb3ea3924": "PointlessCoin(int256,uint256,string,uint8,string,address)", "0x1d834a1b": "insert(uint256,uint256)", "0x931df75f": "validateProposedThroneName(bytes)", "0x6189be15": "columnround(uint256,uint256)", "0xdf5dd1a5": "addOracle(address)", "0x22d8cf5b": "CheckUserVote(uint8,uint8)", "0xdd62ed3e": "allowance(address,address)", "0xc0eb2325": "scheduleTransaction(address,bytes,uint256)", "0x038461ea": "getCertifiedStudentsCount()", "0x9ee035c9": "lookupCanonicalFormat(bytes)", "0x0ab58ead": "SingularDTVFund()", "0x550ed1f0": "getMaxBetAmount()", "0x6e63015c": "getCertifiersCount()", "0xbbd4f854": "buyShares(bytes32,uint8,uint256,uint256)", "0x306b031d": "getGenerationEndAt(uint256)", "0x1bd9c46e": "setImporter()", "0xc80c28a2": "getNumberOfParticipants()", "0xcb553ac9": "sweepWizardCommission(uint256)", "0x6389654e": "changeDailyWithdrawalLimit(uint256)", "0xc0a963c9": "notifyWinner(address,uint256)", "0x3c335b0e": "getRetractable(bytes20)", "0x017972af": "getNumbersFromHash(bytes32)", "0x07da68f5": "stop()", "0x1e8c72b4": "incrUserAvailBal(address,uint256,bool)", "0x0df71602": "setWinner(uint256)", "0x85e5bb3a": "Security_AddPasswordSha3HashToBankAccount(bytes32)", "0x2ade6c36": "getNodeAddress(bytes32)", "0xb33926cb": "owner_withdraw(uint256)", "0x57764094": "getRate(uint256)", "0x13827950": "getShareholderDB()", "0x26826bf8": "setImage(bytes)", "0x76d438b0": "sendReward(uint256,uint256)", "0x51d6e547": "getNonce(bytes)", "0x4f24186a": "newProposal(string)", "0x1a695230": "transfer(address)", "0xe820a32f": "vetoPayout(uint256,uint256)", "0xfb3a1fb2": "getReleaseDb()", "0x6bae05cf": "preRegister(address)", "0xae2df7b3": "setImporterBank()", "0x56d73ad1": "getCertifierDb()", "0x8396392d": "add(string,string,string,address)", "0xeb08b304": "changeMeatProvider(address)", "0xb60e72cc": "log(string,uint256)", "0x76999896": "KingOfTheEtherThrone()", "0xea851885": "buyStake(bool)", "0xa5982885": "assertFalse(bool)", "0xfbf1f78a": "unapprove(address)", "0xc2ba5b40": "getPackageData(string)", "0x83d51a38": "concatString(string)", "0x68af4971": "registerListening()", "0x14ba5c09": "getDay()", "0xe4849b32": "sell(uint256)", "0x44dd4b3b": "lookupGeneration(uint256)", "0x3fda1281": "get_keys()", "0x09241200": "wasSuccessful()", "0xbc9147a4": "Foundation()", "0xe33734fd": "changeProposalDeposit(uint256)", "0x2cce4abe": "_finishNoCallback()", "0x45e965cd": "strConcat(string,string,string,string)", "0xd4245e5b": "transferringETH(address)", "0x10082bff": "getActorBillXdetail(address,uint256,bool)", "0xc831391d": "getPoolOverlapSize()", "0x15e33901": "digest(bytes,uint256)", "0x5f0edfb8": "create(bytes,bytes32,bytes1)", "0xadd4c784": "getResult(bytes32)", "0x3233c686": "claimerDeposit()", "0x187a62d5": "voteEmergencyWithdrawal(bool)", "0x5404bbf7": "getEntropy()", "0x3f5b7675": "periodTwo()", "0x7ec0f30d": "ack(string)", "0xd30a512e": "betOnColumnOrDozen(bool,bool,bool)", "0x9fcbc738": "setIntermediate(address)", "0x539e2bfb": "secondChainedCallback(uint256)", "0xe724529c": "freezeAccount(address,bool)", "0x5aa97eeb": "getMarkets(bytes32[],address)", "0xc51be90f": "query_withGasLimit(uint256,string,string,uint256)", "0x531b97d7": "oneCentOfWei()", "0xeace4827": "player_make_bet(uint8)", "0x9c851ebc": "new_entry()", "0x98c9cdf4": "getMinimumCallGas()", "0xd8f012c6": "StatelessFactory(string,string,string)", "0xceeafd9d": "withdrawFundsAdvancedRP(address,uint256,uint256)", "0xd6d7d525": "get(bytes)", "0xbf55486b": "Tanya()", "0xd35ada32": "addParticipant(address,address)", "0xa8239d0b": "getPrice(string,address)", "0x12514bba": "transfer(uint256)", "0xb00140aa": "getHash(bytes)", "0x36f66528": "EtherDelta(address,uint256,uint256)", "0x279e0912": "getDownloadPrice()", "0x8173b813": "setNumCities(uint256,uint256)", "0xb98fdc36": "IconomiToken(uint256,string,uint8,string,uint256)", "0x3c7a3aff": "commit()", "0xcac77df7": "__transferFromToICAPWithReference(address,bytes32,uint256,string)", "0xfbeaebc6": "murder()", "0x2fa7cbfb": "getExecCost(uint256)", "0xe44d3084": "testFailure()", "0xede8acdb": "startAuction(bytes32)", "0xd5544f94": "getFundsAndAvailable(address)", "0x3824d8ee": "buy100DaoFor1Eth()", "0xbe3945e4": "getFee(address,address,uint256)", "0x1917ab5c": "activate(string)", "0x23509e69": "donkeysEligibleForFees()", "0xf460590b": "updateSigner(address,bool)", "0xc55c1cb6": "queryN_withGasLimit(uint256,string,bytes,uint256)", "0xd96d7ea2": "PRE_EXECUTION_GAS()", "0x1f7b6d32": "length()", "0xacf8bf2a": "channelCount()", "0x18968a03": "finalize(uint256,address,address)", "0x5674a3ed": "runLottery()", "0xe3280126": "addOrder(string,bool)", "0x32afa2f9": "claimEtherOwner(uint256)", "0x355474d2": "commitReading(address)", "0x00601d6c": "board(uint256,uint8,uint8)", "0x2667f407": "__proxy(address,bytes)", "0x79716e43": "confirmTransaction(bytes32)", "0x272cda88": "EternalDB()", "0x76ca0c77": "scheduleCall(address,bytes,uint256,bytes,uint256)", "0x338b5dea": "depositToken(address,uint256)", "0xfa93f883": "getMinute(uint256)", "0xafc4a982": "PathCost(uint16,uint32)", "0xf7d97577": "setPrice(uint256,uint256)", "0x842bc37b": "GetSmallCotractIndex(address)", "0x75f40f40": "underdogPayoutFund()", "0x23a1c271": "setPongval(int8)", "0x02571be3": "owner(bytes32)", "0xf79b22e0": "betOnATeam(uint256)", "0x10cf5d47": "awaitingPayout()", "0x1b00fe51": "testHypothesis()", "0xd449ce7c": "Administered()", "0x455259cb": "getGasPrice()", "0x975057e7": "store()", "0xdfdb5f17": "doBurn(address,uint256)", "0xaa497b9d": "scheduleCall(address,uint256,bytes,uint256,uint256,uint8)", "0xcabfb934": "replace(address)", "0x1f1f5e76": "addValueToContribution(uint256)", "0xa0eda9f2": "_transferFee(address,uint256,string)", "0xa8d95fb2": "claim(address,string)", "0x03ee8f08": "getCoeff(uint16)", "0x9872a20a": "registerUInt(address,uint256)", "0xb20d30a9": "setDailyLimit(uint256)", "0xe116b17e": "getKudosLeftForProject(address,address)", "0xf7c9f74a": "insert_contribution(address,uint256)", "0xc7a1865b": "play(bytes32)", "0x356594ab": "EtherTransfer()", "0xe22b0c46": "verify(uint256,uint256,uint8,bytes,bytes)", "0x2fea7b81": "getIdentity(address)", "0x6fa8de90": "changeMeatParameters(uint256,uint256)", "0x37c390e3": "allow_move(uint16)", "0xd22c391a": "validateProposedThroneRules(uint256,uint256,uint256,uint256,uint256)", "0xf6d339e4": "setAddress(bytes32,string,address)", "0xd7cc8362": "isLatestMajorTree(bytes32,bytes32)", "0xdd012a15": "setIt(uint256)", "0x254c91b3": "testBitNotSetSuccess()", "0x47e40553": "nextRound()", "0xa6b206bf": "doSomething(uint256)", "0xac996e7e": "resolvePledging()", "0x71e2d919": "lol()", "0x07d5b826": "buyAllOutcomes(bytes32,uint256)", "0x5f68804e": "SimpleLotto()", "0xa510f776": "setCompany()", "0x0d48e8d0": "doBalance()", "0xd21d7950": "changeGasLimitOfSafeSend(uint256)", "0x3358d2d3": "buildDSTokenFrontend()", "0xec93cfae": "FountainOfWealth()", "0x65b1fdf4": "scheduleIssuePOIs()", "0xdc3080f2": "spentAllowance(address,address)", "0xd1f0bb2d": "populateAllowedFreeExchanges()", "0xd591221f": "testTransfer()", "0xf24b5779": "removeTrustedIssuer(address,string)", "0xed4b1d0d": "scheduleTransaction(uint256)", "0xa83627de": "updatePeriod()", "0xf597a499": "UserDatabase(uint256)", "0x21f8a721": "getAddress(bytes32)", "0x5548c837": "Deposit(address,address,uint256)", "0x55b775ea": "setFeed(address)", "0x01b869f1": "release(uint32,uint32,uint32,bytes)", "0x609ff1bd": "winningProposal()", "0xdf98ef33": "getResource(bytes,uint256,bytes)", "0xd39eb301": "getStatus(uint8,uint8)", "0x2cc0b254": "init(address,bytes32)", "0x4228974c": "Videos()", "0xc431f885": "addToContribution()", "0x00e43ee9": "setMigrationStatus(uint256,address)", "0xd9f8a4e2": "calcCurrentTokenPrice()", "0xb9e6f1d9": "get_amount()", "0x6b3a87d2": "WatchWinningPot()", "0xef4592fb": "getResult(bytes)", "0x41b9dc2b": "has(bytes32,bytes32)", "0x3b9901cc": "getChannelsByRanks(address,uint256,uint256)", "0x83876bc9": "newProposalInWei(address,uint256,string,bytes)", "0x50a3bd39": "enterPool()", "0xc976bbbb": "_compare(int256,bytes2,int256)", "0x0e47c76f": "rotate(uint64,uint256)", "0x6f85c7e4": "WAITING_PERIOD()", "0x7075b1d8": "latestMonarchInternal()", "0x9209b3c0": "getCrtDetails(bytes)", "0x305075db": "NormalizeRanks()", "0xb6b55f25": "deposit(uint256)", "0xf09ea2a6": "offer(uint256,address,uint256,address)", "0xf1320af2": "exempt(address)", "0xc813c30e": "testThrowSomething()", "0x4faa2d54": "getTimeElapsed()", "0x22017c5f": "DSTokenBase(uint256)", "0x6637b882": "setDao(address)", "0xd0b52156": "getIpfsHash(address,address)", "0x13bd4e2c": "_prepareAndSendReward()", "0xdb7ca38a": "XaurmProxyContract()", "0x1bad1d2e": "monitorWallet(address)", "0x691f3431": "name(bytes32)", "0x3169ff3e": "LooneyLottery()", "0x446a7974": "Fokitol()", "0xdc3ab866": "checkEarnings(address)", "0xfad9bf9e": "storeBlockWithFeeAndRecipient(bytes,int256,int256,bytes,int256,int256)", "0xaf408d89": "setStatus(bytes)", "0xd02bf162": "spinTheWheel()", "0x9a36f932": "feeDivisor()", "0xca77ab8a": "getNextFile(bytes)", "0xc8e49707": "activateExportFee(address)", "0x502414e4": "marketMaker(string)", "0x78ec81a0": "sendEarnings(address)", "0x14167bf0": "oraclize_query(string,string[])", "0xba13a572": "lottery()", "0x299ed37a": "emergencyCall()", "0x6ec3af26": "addTrustedIssuer(address,bytes)", "0x3d69b403": "isOutcomeSet(bytes)", "0x9a19a953": "setInt8(int8)", "0x7817a60f": "acceptMember(address,string)", "0x1e223143": "getFirst()", "0x5437b39b": "hasUnprocessedDividends(address)", "0x8f0c724c": "setOperationsCallGas(uint256)", "0x3c925f16": "getAccountHolder()", "0x477801b1": "getLastRoundResults_by_index(uint256)", "0x3d21aa42": "sendApproval(address,uint256,address)", "0xd2b8035a": "draw(uint256,uint256)", "0x19c32e0b": "hmacsha256(bytes,bytes)", "0x28f90e4b": "Etheramid2()", "0xe87df70e": "fivetimes()", "0xc028df06": "offer()", "0xacb6c69b": "setTrustedClient(address)", "0xac7ffae3": "updt(uint256,string,uint256,uint256,string,string,address)", "0x0e5ffb3c": "hashVersion(uint32,uint32,uint32,string,string)", "0x4ac6b2be": "getCheckRecordCreator(bytes)", "0x93dafba2": "getSubpot(uint256)", "0x592685d5": "getWindowStart(address,address)", "0xc24a0f8b": "endDate()", "0x3f9b250a": "getDocument(uint256)", "0xd845a4b3": "request(uint256)", "0xa5bfa9a9": "claimToken(bytes32)", "0x8e3957d9": "RandomNumber()", "0x62fb09b2": "getRefDescr(uint256)", "0x9f35d3b2": "start(string,string,uint256,uint256,uint256,uint256)", "0xea1bf386": "getNextSellerBOTdata(uint256)", "0xe27fe50f": "startAuctions(bytes32[])", "0x031d973e": "closeMarket(bytes32)", "0x754dea40": "setBackendOwner(address)", "0xd83a8d11": "testProposing()", "0xf24a534e": "Oracle()", "0xd08275f1": "WolframAlpha()", "0x932db761": "profitsFromBitnationDebitCard()", "0xd96aee49": "MultipleConstructorTest()", "0x4594d06a": "delMinter(int256,address)", "0xb9f256cd": "newProposalInEther(address,uint256,string,bytes)", "0x1d2bca17": "MyToken(uint256,string,uint8,string)", "0x6edbd134": "hasHash()", "0x847f8a10": "Refund(uint32)", "0xb0604a26": "schedule()", "0x6676871d": "reserved_funds()", "0x05888fcd": "tradeBalances(address,uint256,address,uint256,address,uint256)", "0xe771066f": "marriageProof(bytes)", "0x7e32a592": "repairTheCastle()", "0xbab2f552": "currentCycle()", "0x45a3b0bf": "resolveFailPledge()", "0x070a888f": "updateRewardDuration(uint256)", "0x20d9822e": "setAnyoneCanCall(address,string,bool)", "0x224993c2": "setTimeBlock(uint256)", "0x01bd4051": "disown(string)", "0x4bc2a657": "setVoter(address)", "0x522103fa": "changeUnicorn(uint256,address)", "0xc988d70f": "getDailyWithdrawLimit()", "0x2f7f3ecf": "findNextHour(uint256,bytes)", "0x1b769e74": "testThrowsRestartNotUpdatable()", "0x4d561721": "etherandomSetNetwork()", "0x92a781d8": "changeBaseValue(uint256)", "0xf0a78538": "scheduleTransaction(uint256,bytes)", "0x64ef212e": "proxyTransferWithReference(address,uint256,bytes32,string)", "0x97c3ccd8": "ban(address)", "0xdeb6930c": "PriceTicker()", "0x6cc5fdaa": "setBytes32(bytes,bytes)", "0x92c8eb96": "DSFalseFallbackTest()", "0x6534b4e2": "IsPayoutReady__InfoFunction(bytes32)", "0x15e812ad": "getBaseFee()", "0xf5b53e17": "getInt256()", "0x081bf263": "isOOB(uint8,uint8)", "0xd2fb8787": "recordExists(bytes)", "0x86c57fcc": "b32ToBytes(bytes)", "0xe3a199d6": "testThrowCreateNewRevisionNotUpdatable()", "0x57cfeeee": "transfer(address,uint256,bytes32)", "0xb72e717d": "fromAddress(address)", "0x61b20d8c": "retrieveFunds()", "0xf4b103d4": "SimpleStorage(uint256)", "0xe2056c46": "ExtraBalToken()", "0xc3ee6311": "lockAndCall(string)", "0x136af582": "next(bytes,bytes,bytes,bytes,bytes,bytes,bytes)", "0xc5d5997c": "changeSubUser(address,address)", "0xf8018a79": "prepend(address,address)", "0xf6b4dfb4": "contractAddress()", "0x9450b1c8": "addCharityFundation(string,string,string)", "0xd1a8d447": "get_all_bet_values()", "0x66d8c463": "reveal(bytes32,string)", "0xbb963c8a": "transferLibOwnership(bytes,address)", "0xd56b2889": "finish()", "0x9fb25d9e": "LeaderMessage()", "0x6ad50ed4": "investmentEntryInfos()", "0xa4d575ce": "_forward(address,bytes)", "0xa3ec5616": "next(bytes,bytes,bytes,bytes,bytes,bytes,bytes,uint256)", "0x0db73c72": "noevent()", "0xf449619e": "collectPrize(uint256)", "0x1afccfa5": "Proposal(address,address,address,bytes,bool)", "0x4788cabf": "getContractId()", "0x4112987c": "strConcat(string,string,string)", "0x928a00d2": "deleteCoin(uint256)", "0xd9ec0508": "testThrowTransferNotEnabled()", "0x9aaf442c": "applyCensorship(uint256)", "0x49407a44": "claimEther(uint256)", "0x4fcf8210": "eraseRecord(bytes32)", "0x5ed84aa6": "getNymCenterAPIURL()", "0xa3c2c462": "totalReceived()", "0x5938748e": "changeVotingRules(address,address,uint256,uint256,uint256)", "0x6fc9d5e4": "changeCompareTo(uint256)", "0xe2ee9941": "tap(bytes20)", "0x0ff4f160": "oraclize_query(uint256,string,string[1])", "0x43ec3f38": "toSliceB32(bytes32)", "0x3288eb0b": "ChineseCookies()", "0x373c98a2": "authCall(address,bytes32)", "0x6ea056a9": "sweep(address,uint256)", "0x8dc45377": "getDuel1(uint256)", "0xd4625a3a": "equals()", "0x616fca9b": "adopt(address)", "0x32cea83e": "birth(bytes)", "0x002a5cc9": "getTicketHolders(uint256)", "0x31119b4d": "changeDeveloper(address)", "0x69569a51": "setFrontend(address)", "0xb7e24979": "addThing(bytes)", "0x164e68de": "withdrawFees(address)", "0x42bf4431": "orderMatchTest(uint256,uint256,uint256,int256,uint256,uint256,address,address,int256)", "0x5dd672ec": "latestBid()", "0x45fe6e2a": "Scheduler()", "0x55cc4e57": "setIssuer(address)", "0x1df5e755": "Etherandom()", "0x8f70009d": "id_for_address(address,address)", "0x39b50688": "cancelSellOrder()", "0x40953102": "scheduleCall(address,uint256,bytes,uint256,uint256,uint8,uint256)", "0x677913e9": "setAmount(int32)", "0x66671c71": "BaseScheduler(address,address)", "0xfe71aec5": "LittleCactus()", "0x879d46fd": "DAOTrust(address,address,bytes,uint256,uint256,uint128)", "0x3b143184": "Congress(uint256,uint256,int256,address)", "0x7370a38d": "getNumPackages()", "0xfee35ff8": "newInvest(uint256,address,uint256)", "0x57dc9760": "DaoChallenge()", "0x8ac78c80": "Docsign()", "0x76d66f5d": "_Transfer(address,address,bytes32)", "0x9dc2c8f5": "fireEventLog4Anonym()", "0x43114842": "acceptChallenge(uint256,uint256,uint256)", "0x2043285d": "getMarketMakers()", "0xfb32f4f5": "ARK_FLAGGER_1_00()", "0x69431ab6": "TokenCreation(uint256,uint256,address,string,string,uint8)", "0x045c6ce0": "voteForProposal(uint256)", "0xa140e79c": "setMinimumDebatePeriod(uint256)", "0x331a72d1": "getRetractable(bytes32)", "0x87cc1e1c": "setExporterBank()", "0x7183616c": "notarize(string)", "0xce79add1": "givableBalanceOf(address)", "0x6f0cfab6": "DNSResolver()", "0x1c2f38ff": "paid(uint64)", "0xb7de47d3": "getIndex(uint256,uint256)", "0x04a2b2c2": "testOwnerCanBreach()", "0x65a4dfb3": "oraclize_query(uint256,string,string,string,uint256)", "0xf2ddc772": "confirm(bytes)", "0xa00ce377": "getIsContractValid()", "0xfe9fbb80": "isAuthorized(address)", "0xbbd39ac0": "coinBalanceOf(address)", "0xa4fde8bc": "player_declare_taking_too_long()", "0xd052fbf6": "getHistory(string,uint256)", "0xd205ad7d": "proposeDissolve(bytes)", "0x5a3b7e42": "standard()", "0xf27197ab": "getIsAvailable()", "0x00a94b6e": "oraclize_query(uint256,string,string[5],uint256)", "0x971c803f": "getMinimumStackCheck()", "0x5168afa4": "getPackageHash(bytes,uint8,uint8,uint8)", "0xaef99eef": "Game()", "0x7f924c4e": "testDeposit()", "0xb1adc241": "BalanceDB()", "0x6a704d7b": "AddedToGeneration(address,uint256)", "0xb9f37c86": "Registrar()", "0xc631b292": "closeVoting()", "0x19350aea": "nameFor(address)", "0x85dee34c": "query2_withGasLimit(uint256,string,string,string,uint256)", "0xbf187478": "shift_left(uint64,uint256)", "0x5b6b431d": "Withdraw(uint256)", "0xe5dd90a5": "HumanStandardToken(uint256,string,uint8,string)", "0xbf8c50ff": "scheduleTransaction()", "0x013d64bd": "setCanCall(address,address,string,bool)", "0xb870ecbb": "testNormalWhitelistAdd()", "0xbcd3d8ca": "Collector(address,address,uint256)", "0x4401ff5c": "sellShares(bytes,uint8,uint256,uint256)", "0x3e0dfbdf": "getInvestorByAddress(address)", "0xcb3e64fd": "unhalt()", "0xafc24e3d": "getChallengeAnswer(uint256)", "0xa36c8ec2": "UpdateContractorAddress(address)", "0xd5a4a3c6": "findRecentBet(address)", "0xb028ee13": "s2b(string)", "0x692ad3a9": "round(uint256,uint256,uint256,uint256)", "0x0a7493b4": "Etheropt(uint256,string,uint256,uint256,bytes,address,int256[])", "0x60689557": "Rock()", "0x717fedf0": "getFirstActiveDuel1()", "0xe837ab59": "getParticipantByAddress(address)", "0x32d5fe98": "revealCampaign(uint256,uint256)", "0x0178b8bf": "resolver(bytes32)", "0x44faa139": "Withdraw(uint32)", "0x418cf199": "setEstimateCost(uint256,uint256)", "0xae45850b": "schedulerAddress()", "0xd4871517": "BTCLotto(address,uint256)", "0xfbffb355": "testBitsEqualFailIndexOOB()", "0x2be6d43c": "ARKTagger_1_00()", "0x1df47aad": "ReplayProtection()", "0xb36a0b15": "getSignDetails(uint256,uint8)", "0x9c4baf27": "Skywalker(address,address)", "0xfb34fc6f": "WatchNextBlockReward()", "0xceba30b5": "scheduleTransaction(address,bytes,uint256[4],uint256)", "0xfc94dd18": "verifyHumanStandardToken(address)", "0x1ff13086": "size(int256)", "0xce92dced": "newBid(bytes32)", "0x231944e2": "moveUnits(uint256,uint256,uint256[])", "0x784813e0": "lookupBet(uint256,uint256)", "0xe0e3ba5a": "getLosesShare(address)", "0x5c1b3ca1": "getConfigUint(int256,bytes32)", "0x91060168": "fetchString(address,bytes4,bytes32)", "0x354b2735": "testDeploy()", "0xb88eef53": "registryCreated()", "0x8e3d4e5e": "Fibonacci(bytes)", "0x64bd87d6": "scheduleCall(address,bytes,bytes,uint256,uint256)", "0x5c3d005d": "demote(address)", "0xb6509c12": "Ethereum_twelve_bagger()", "0xe87508be": "investorDeposit()", "0xcb96012e": "hashTo256(bytes32)", "0x314e0fb6": "scheduleTransaction(address,bytes,uint256[3],uint256)", "0x5b6a54bc": "adjustTransactionFee(uint256)", "0x5f515226": "checkBalance(address)", "0x76cd7cbc": "sign(bytes)", "0xce220ecf": "testAddBalanceFailsAboveOverflow()", "0x922fc84b": "taskProcessedNoCosting(uint256)", "0xf8b2cb4f": "getBalance(address)", "0x7a29332d": "buyAllOutcomes(uint256,uint256)", "0x04106c8b": "startGeneration()", "0x8eaa1e29": "getContentByData(address,uint256,string,string)", "0x5a7a8850": "rollWithSeed(bytes32)", "0x2facc4e8": "depositGovernance(uint256,address)", "0xf2561a43": "voteSuicide(address)", "0xee1b4828": "closeBooks()", "0x18f303a1": "SetInternalValues(uint8,uint256)", "0xce60f78d": "createMarriage(bytes,bytes,uint256,bytes,bytes)", "0x18b749c4": "payEther(uint256)", "0xbbc6eb1f": "getDefaultDonation()", "0x0b1ca49a": "removeMember(address)", "0xccf4f413": "setSubRegistrar(string,address)", "0x4616caa9": "pushCoin(uint256,address,string)", "0xd69450d5": "setUUID4Bytes(bytes)", "0xc98165b6": "createTarget()", "0x8c79a24d": "refName(uint256)", "0x56d88e27": "len()", "0xbfc3d84b": "CT()", "0xc7f2e6af": "Contribute(bytes20)", "0xd7e11e9d": "AddTicket(bytes)", "0x2d06177a": "addManager(address)", "0xd588acc4": "claimMiningReward()", "0x2ffb9e64": "updateGasForXaurData(uint256,uint256)", "0xf896503a": "getConfigAddress(bytes32)", "0x9af8c4ba": "respond(uint256,address,bytes)", "0x82a5285d": "getMinBetAmount()", "0x3ead67b5": "changeContractOwner(address)", "0xb29d7914": "getRefResults(uint256)", "0x135128c2": "CounterPartyDeposit()", "0x795b9a6f": "scheduleCall(address,bytes4,uint256,bytes)", "0x83197ef0": "destroy()", "0x433836dc": "scheduleTransaction(address,bytes,uint8,uint256[3],uint256)", "0xf009347d": "KudosProxy(address)", "0xf2fde38b": "transferOwnership(address)", "0x62c99e84": "_Approval(address,address,bytes32)", "0x1b83b823": "notifyPlayer(uint256)", "0xe56c8552": "spinTheWheel(address)", "0x93eec1fb": "setName(uint8,uint8,string)", "0x11af3c68": "divest(address)", "0x8279c7db": "setReceiverAddress(address)", "0x44691f7e": "hasStarted()", "0x349501b7": "checkDepth(uint256)", "0xe8beef5b": "fireEventLog3Anonym()", "0x0870607b": "addSubUser(address)", "0x063925c8": "scheduleCall(bytes,uint256,uint256)", "0xa23744f0": "tryCreateCheckRecord(bytes)", "0x35d79fad": "CertificationDb(address,uint256,address)", "0x44691f2b": "Dispute()", "0xd7ccc2c3": "getLastPayment()", "0x152583de": "getAttributes()", "0x1a9360dd": "checkDate()", "0x420ef2b3": "TargetHash()", "0xf0caea2b": "SmartRoulette()", "0x5d268629": "Refund()", "0x23385089": "emitApprove(address,address,uint256)", "0x7648c929": "returnRemainingEther()", "0x5d5bc4cb": "BetOnRed()", "0xde8fa431": "getSize()", "0xda6b31b9": "testErrorTransferToNullAuthority()", "0x444dd6f3": "Elcoin()", "0xe1fa8e84": "register(bytes32)", "0x3e0a322d": "setStartTime(uint256)", "0x21bacf28": "getDefaultFee()", "0xb1662d58": "setModule(address,bool)", "0x5b0fc9c3": "setOwner(bytes32,address)", "0x40193d17": "getPongvalConstant()", "0xfb95adeb": "testFailBlockhashInsuffiecientFee()", "0x8ecc0950": "returnToOwner()", "0x34b7ac9b": "END_MINTING()", "0xeaa37394": "create(bytes,bytes32,bool,bool,bool,bool,bool)", "0xd7bc23af": "newParameters(int256,uint256,uint256,uint256)", "0x97709cde": "ARK_VOTER_1_00(uint256,uint256,uint256,uint256,uint256,uint256)", "0xcf4a1612": "scheduleTransaction(uint256,address,bytes,uint256)", "0x40695625": "testRetractLatestRevision()", "0x90c3f38f": "setDescription(string)", "0x5fdf05d7": "two()", "0xaaac50bd": "transferDisable(bytes32)", "0x206a44f3": "getNum(bytes,uint256)", "0x7ac26aeb": "getTag(string,uint256)", "0xdc3f65d3": "createdByMe()", "0xe99543aa": "Trash(uint256)", "0x1bcad37a": "getTotalCost()", "0xa7f43779": "remove()", "0x3416f9d4": "subtractSafely(uint256,uint256)", "0x3bcf7d22": "newBribedCitizen(address)", "0x918f1bb5": "ProjectKudos()", "0xcf09e6e1": "SetBigContract(address)", "0x23add736": "claim(uint256,uint256,uint8,bytes,bytes)", "0x8ac6a869": "isObsolete()", "0x2324c67c": "getAllSignatureHashes(bytes4)", "0x981a60f5": "extractNameFromData(bytes)", "0xc018d0e6": "getFeeAmount(int256,int256)", "0x50e06b57": "Etherization()", "0x49e65440": "setSymbol(bytes32)", "0xfaee13b9": "set(int8)", "0x01ffc9a7": "supportsInterface(bytes4)", "0xc0b92612": "changePig(address)", "0x3f9f5b68": "setPreviousID(uint256,int256)", "0x2e9c5e77": "doStackExtension(uint256)", "0xc83be888": "single_move(uint256,uint8,uint8)", "0xef19c332": "_checkSigned(bytes32,uint256,uint8,bytes32,bytes32)", "0x2f30c6f6": "set(uint256,address)", "0x62986e27": "Canary(address,uint16)", "0x44dfdce0": "getNameOwner(bytes)", "0x4b7fcee7": "ownerPausePayouts(bool)", "0x84dac46e": "Fucksign()", "0x0878bc51": "getAttachesto(uint8)", "0x42d16748": "getMinDailyWithdrawalLimit()", "0x4ecd73e2": "DistributeDividends(uint256)", "0x03750d94": "serverSeed(address,bytes32)", "0xea0a5237": "announce(string)", "0x611daa7e": "EmergencyBalanceReset(uint256)", "0x2ae87a70": "getNumContents(address,uint256)", "0x5ec01e4d": "random()", "0xfd735602": "executeN()", "0xfebefd61": "startAuctionsAndBid(bytes32[],bytes32)", "0x8b64d70e": "owner_set_time_limit(uint256)", "0x2839e928": "ackermann(uint256,uint256)", "0xaf29e720": "remainingGasFund(uint256)", "0x9eee85fe": "bookEarnings(address,uint256)", "0x3733ffca": "convertTo(uint256,string,string)", "0xdbde1988": "transferFromWithoutReward(address,address,uint256)", "0xd3edcb5b": "getCreditorAddresses()", "0x77fcb91d": "forward(address,bool)", "0xf062e26b": "check_darkdao()", "0xdef2489b": "convert(address)", "0xccbda1af": "getChannelByName(string)", "0x267c8507": "authorizeManager(address)", "0xf1c30ec0": "reclaim(bytes)", "0xe6470fbe": "updateDefaultPayment()", "0x8fe58eb9": "Triger()", "0xd6b44859": "scheduleUndoIt(uint256)", "0x0eb8ed07": "transferEnable(bytes32)", "0xfc1f2a70": "Add(uint256,string,string)", "0x058026d0": "checkTransferToICAPWithReference(bytes32,uint256,string)", "0xaf27c7b3": "Security_HasPasswordSha3HashBeenAddedToBankAccount()", "0x5b151fd2": "fifty_fifty()", "0x531d1974": "testThrowRetractLatestRevisionEnforceRevisions()", "0x60213b88": "getInitialWithdrawal()", "0x29e94503": "VersionedBlob()", "0x9c5d7030": "reimburseGas(uint256,address,uint256,uint256)", "0xcd9a3c98": "any(bool[7])", "0xb484e532": "getMyMsg()", "0xd1f59db9": "isLatestMinorTree(bytes32,bytes32)", "0xe0c6190d": "checkTime()", "0xaf5610dd": "isThisPreforkVersion()", "0xfa968eea": "minBetAmount()", "0x003538c5": "TestRegistrar(address,bytes32)", "0x71c59097": "MainnetSurvey(uint256,string,bytes32[])", "0xc82aac47": "searchByTag(bytes32)", "0xeca5c793": "testErrorUnauthorizedNameRegister()", "0xdc75f2db": "multiowned(address[],uint256)", "0x4c9ed763": "requestTokensBack()", "0xbd9a5673": "oraclize_query(string,string[5])", "0xb11e3b82": "createEvent(bytes32,bool,int256,int256,uint8,address,address,bytes32[])", "0x86e4e178": "CheckTickets(address,uint256,uint256)", "0x53c84526": "setSmartAffiliateContract(address)", "0x89029d8c": "get_all(uint256,uint256)", "0xc25e6908": "ultimateOutcomes(bytes32)", "0x6b1e564a": "challengeWinningOutcome(bytes32,uint16)", "0x1c895915": "getNumberOfPayments(uint256)", "0x244fcd03": "removeRelease(bytes32,string)", "0x2ca6d2c0": "getAccountSize(address)", "0xfe67a54b": "endAuction()", "0x756fb8c9": "getOptionChain()", "0x88102583": "safeCastSigned(uint256)", "0x60063887": "transferDebt(address,address,address,uint256)", "0x16216f39": "return13()", "0x8089d001": "getHashOfBlock(uint256)", "0x27bc39c0": "submitCanonicalCandidate(bytes,bytes,bytes,bytes)", "0xb29ae23f": "getDateOfSignature()", "0xdd729530": "add_shield(uint16)", "0x38557648": "executeSellOrder(address)", "0xe2a71f12": "accountDelete()", "0xce869a64": "fails()", "0x69bdfd3a": "toContractDie(bytes,bytes,uint256)", "0x99aeade3": "iterateTable(uint256,uint256)", "0x46bdca9a": "equal(string,string)", "0x5e07f240": "shiftBitsLeft(bytes,uint256)", "0x76285b5b": "_is360thDay()", "0x594151e0": "Dice()", "0x4dc43eaf": "setTreasury(uint256,uint256)", "0xec727000": "getApprovalDB()", "0xb144adfb": "balance_of(address)", "0x63052d82": "getOwnersIndex(address)", "0x833b4596": "testApproveSetsAllowance()", "0xc67d376d": "getClosedCandidates()", "0xcf03f5f4": "activateMasterKey(address)", "0x7ca55e00": "etherandomVerify(bytes32,bytes32,bytes32,uint256,uint256)", "0xd92ebe46": "createDAO(address,uint256,uint256,uint256,string,string,uint8)", "0x3773930e": "ConfigureFunction(address,uint256,uint16,uint16,uint16)", "0xfee6d28c": "addSnapshot(string)", "0xe71264fa": "addNewTokens(uint256)", "0xc4d9102f": "setNextID(uint256,int256)", "0xa6f0e577": "isLeapYear(uint16)", "0xc7102df7": "__stopBlock()", "0xfa93019c": "getBlocks(uint8,uint8)", "0xe9794dc1": "CreateHash(uint8,string)", "0x5460ef10": "sendWithExtraGas(address,uint256,uint256)", "0x2f62a6ff": "fipsRegister(uint256,address,bytes)", "0xd630bd53": "pledgeApprove(uint256)", "0x3448c7d6": "createHistory(bytes,address,address)", "0xdda3342b": "ReplicatorFactory()", "0x0cd865ec": "recover(address)", "0xb9f28076": "historyIdx(address)", "0x4dda1764": "CafeMaker()", "0x883ba26b": "getIsSettled()", "0x3f5e268f": "convictInitial(uint256,uint256)", "0x4a3b0eec": "authorizeOpen(uint256,bool,string)", "0xee6d2641": "sendWithExtraGasExt(address,uint256,uint256)", "0xde14bbf7": "randomGen(uint256,uint256)", "0x7f3bd56e": "disburse(address,uint256)", "0x20d8741f": "Feed()", "0x60c6b3a5": "claim(bytes,address,uint256,uint8,bytes,bytes)", "0xda4b5e29": "contains()", "0xb3c25835": "addUser(address,string,string,uint256)", "0xee2af3fb": "set_factory(address)", "0xb821f815": "pay_winner(uint256)", "0x138cc941": "testErrorTransferToRejectAuthority()", "0xc0b6f0c2": "NextRoundAndEvents()", "0xc7e67360": "GAS_BUFFER()", "0x058d7433": "setAlliesContract(address)", "0xd810f298": "computeSettlementAmount()", "0xa24d23eb": "ProcessGame(uint256,uint256)", "0x7ac91cc2": "testFailOwnedAuth()", "0x79c3ddc1": "isPackageOwner(string,address,address)", "0x478ae93c": "playToWin(uint256)", "0x6632a507": "testSetupPrecondition()", "0xb6013cef": "finalize(uint256,uint256)", "0x37b7bf11": "Tile(int256,int256)", "0xecfc7ecc": "placeBid()", "0x70b1d9d4": "requestCanonicalFormat(bytes)", "0x315fdea3": "TreasureChest()", "0xc5575ef0": "checkTransferFrom(address,address,uint256)", "0x65c72840": "getDay(uint256)", "0xd6eafd08": "scheduleCall(address,bytes,bytes,uint8,uint256[4])", "0x350fbe2e": "calcNextDrawTime()", "0x8af784dc": "expectEventsExact(address)", "0x2db89533": "Auth(uint8,address)", "0x9f203255": "setAuditor(address)", "0x2526d960": "clawback()", "0x3fbd40fd": "ProcessDraw()", "0xface030b": "SpinTheWheel(address)", "0x648621ec": "xnotify(string)", "0x22dc36e2": "processed(uint64)", "0x6f52167d": "payDuel(address,string,address,string)", "0x8f70bfa0": "processDeposit()", "0x25ea269e": "Scissors()", "0x93feb13b": "ForceSendHelper(address)", "0xb688a363": "join()", "0x89859b50": "updateLatestTree(bytes32)", "0xf83d08ba": "lock()", "0x7d287697": "testTryGetUnset()", "0x98d5fdca": "getPrice()", "0xfe72e717": "toDie(bytes)", "0xb3c06f50": "transferFrom(address,address,bytes32)", "0x1465aa97": "testingContract()", "0x069d6d1c": "closeOrder(uint256)", "0xa79f26dc": "force()", "0xf2371fb3": "grantGiveableKudos(address,uint256)", "0xaa7dcd84": "testUpdateAuthorityEvent()", "0x0d8b5fa2": "testControllerValidTransferFrom()", "0x0e0f55d0": "RewardOrder(uint256,uint256)", "0x9ea1b79d": "getContentChannel(uint256)", "0x4a67fa7d": "setLotteryFee(uint256)", "0xdb006a75": "redeem(uint256)", "0x8f4ed333": "step2()", "0x1a10cfc3": "delete_entry(uint256,uint256,uint256)", "0xd422e4e0": "takeFee(address,uint256,string)", "0x61a00f6d": "Ballot(bytes32[])", "0x9c30936f": "removeCertificationDocumentFromSelf(bytes32)", "0xa5f4af33": "playerWithdrawPendingTransactions()", "0x07ad9ecb": "safeSend(address,uint256)", "0x8f99ea43": "setDividendDB(address)", "0x1df473bc": "newContract(bytes)", "0xea5ea470": "payFunding(uint256)", "0x743e0c9b": "receiveTokens(uint256)", "0x21835af6": "__dig(uint256)", "0x47448e8a": "set(bytes32,string,bytes32)", "0x9b1ad792": "destroyToken(address,uint256)", "0xf765088f": "UpdateClientAddress(address)", "0xddbbc35c": "searchByName(string)", "0x5ed7ca5b": "halt()", "0x97950740": "roomForBirth()", "0xfc01abbe": "stringToBytes32(string,string)", "0xea3d508a": "selector()", "0x8c88752a": "ContributorList(uint256)", "0x5837e083": "move_history(uint256)", "0xf7c3ee7a": "immortality()", "0x1b9f9647": "accessMyWallet(address)", "0xc8691b2a": "getHistory(uint256)", "0x91e8d3dc": "testBitOrFailIndexOOB()", "0x5c89c10d": "setBannedCycles(uint256[])", "0x4500054f": "isCancellable()", "0x334ef224": "testThrowsUpdateLatestRevisionNotOwner()", "0x763a738c": "allNames()", "0x45590ec8": "addTag(uint256,string)", "0xe7740cf9": "revealPaper(string)", "0xd9d2d058": "Splitter()", "0xb412d4d6": "CafeDelivered()", "0x8365172c": "num_levels()", "0x41c0e1b5": "kill()", "0x3106fea0": "voteOnProposal(uint256,bool,uint256)", "0x82ab890a": "update(uint256)", "0x4636a159": "newPhoneToAddr(address,uint256)", "0x2f29d8c5": "elapsed()", "0x1bf20668": "testAdminTransfer()", "0xf709dd51": "getTrademark()", "0x8b859409": "setRelease(bytes32,bytes32,string)", "0x03959bb7": "setDataContract(address)", "0x4247f52d": "DoRoll()", "0x31ab4066": "testAuthorityTryAuth()", "0xac4b2bae": "newParameters(int256,uint256,int256,uint256)", "0x57eaeddf": "_isContract()", "0x4a3a87e2": "CreateProxyWithControllerAndRecoveryKey(address,address,uint256,uint256)", "0xd116c8c4": "releasePayment()", "0x6615dd83": "setSeedSourceB(address)", "0xb8aca90b": "CurrentGame()", "0xc124e2ea": "checkBetDozen(uint8)", "0x4b0bbf84": "addEntropy()", "0x452fbc41": "USN(address,address,bytes,uint256,uint256,uint128)", "0xcdb6753b": "setNav(uint32)", "0xbb5d40eb": "isValid()", "0xd6f42038": "PhoneToAddress()", "0x6bc3e0f0": "verifySecondHalf(uint256[4],uint256[4],uint256[4])", "0x33893071": "checkMyWithdraw(address)", "0xfb46d4c5": "tweet(string)", "0x248582b0": "receivePaymentForGoodsSoldEarly()", "0x766a3f2e": "Security_ConnectBankAccountToNewOwnerAddress(uint32,string)", "0x1c8d5d38": "allowance(address,address,bytes32)", "0x6b256f57": "DAOSecurity(address,address,bytes,uint256,uint256,uint128)", "0xe8d1e961": "lockAccount(uint256)", "0x152fb125": "SimpleMixer()", "0xf72457af": "CertifierDb()", "0xe8a5282d": "setConfig(bytes32)", "0xbeb92f55": "setCaller(address)", "0x9a571d9f": "isAlphaLower(bytes1)", "0x46a2679a": "getSubpotsCount(uint256)", "0xd62d3115": "testCreate()", "0xb6ed0632": "cancelOrder(uint256,uint256)", "0xc95e81cb": "MyBet(uint8,address)", "0x1d5a9f3f": "object_types(uint256)", "0xa49d53a1": "SmartRevshare()", "0x5b65b9ab": "setFee(uint256,uint256,uint256)", "0x116c6eab": "getProfitShare(address)", "0x8e46afa9": "getDefaultGracePeriod()", "0xdabc706e": "getProposalCost()", "0x3fbb539d": "scheduleCall(address,bytes,uint256,bytes)", "0x86269a88": "checkBetNumber(uint8)", "0xb6ac24df": "updatePatchTree(bytes32)", "0x4637d827": "trust(address)", "0x1c1b8772": "update(address)", "0x5a9f2def": "scheduleCall(bytes4,bytes,uint256,uint256)", "0x81a60c0d": "getResults(uint256)", "0xd1b4ff7e": "multiAccessRevokeD(bytes32,address)", "0x92b7d5b9": "getCurrentGaslimit()", "0x77ceded8": "mintGrey(int256,address,uint256)", "0x2a095fbe": "unlinkEID(bytes,bytes,address)", "0xa6e16ba2": "testThrowsRetractLatestRevisionNotOwner()", "0x4579268a": "getOffer(uint256)", "0xcabb3a3a": "isAlphaNumeric(string)", "0xfadc51cf": "isAlpha(bytes1)", "0xf2022905": "toldYouItWouldWork()", "0x686e8aaa": "GetMoney()", "0x07718a3b": "BankOwner_WithdrawDonations()", "0xc58343ef": "getRequest(uint256)", "0x7b1a547c": "registerAs(address,string,uint256,string,address)", "0x213b9eb8": "setAddr(string,address)", "0x75090ebf": "changeDomain(uint256,uint256,uint256,address)", "0xdbbdf083": "register(uint256,address)", "0xfa4e5e5a": "notify(uint8,string,string)", "0x86a5ff97": "changeStatus(string)", "0xb8f71f26": "scheduleTransaction(uint256,address)", "0xa2ec191a": "addDSource(string,uint256)", "0x18b31f94": "registerLengthFunction(string,string,address)", "0x7b395487": "voteForUltimateOutcome(bytes32,uint16)", "0x39246d75": "VersionModel()", "0xd500dd6a": "challengeTimeout(uint256,bool,address)", "0xd1da09ee": "extractImportFeeChargeLength()", "0xc74e907b": "commit(address,uint256,uint256)", "0x4b09ebb2": "e_exp(uint256)", "0xec3af4a9": "getProjectKudos(address)", "0x714064f3": "BreakableBond(address,address,uint256)", "0xc4bc5da5": "resumeContract()", "0xf7888aec": "balanceOf(address,address)", "0x2f597e71": "testLongInput()", "0x7212b67e": "add_potion(uint16)", "0x9a15f4f3": "getBlockHeader(int256,int256)", "0x6eacd48a": "ownerPauseGame(bool)", "0xf739ed4c": "id_for_user_version(uint256,uint256)", "0xfaf0952b": "testThrowRestartNotOwner()", "0x88a1e895": "test2Fails()", "0x237e9492": "executeProposal(uint256,bytes)", "0x7cb97b2b": "set_owner(address)", "0x2bb685bc": "kill2()", "0xdc52696f": "tokenSupplyChanged()", "0x83d852d9": "shutdownTransactions()", "0x525b25b1": "getDeploymentReward()", "0xeac116c4": "createKingdom(string,address,address,address,address)", "0x014e5fde": "ARKController_1_00()", "0xc6ae3b57": "dEthereumlotteryNet(address,address)", "0xcddbe729": "game(uint256)", "0x8823a9c0": "changeFeeTake(uint256)", "0x021991e7": "getBetsLocked()", "0x3015394c": "cancelRequest(uint256)", "0x9d118770": "destroy(uint256)", "0xe854dfb4": "Order(address,uint256,uint256)", "0x8435be4b": "getLastFarm(uint8,uint8)", "0x27fbcac5": "getChannelFeed(address,uint256,uint256)", "0xc1be4031": "XaurumProxyERC20()", "0x8e25071a": "setProxyCurrator(address)", "0x4f139314": "compensateLatestMonarch(uint256)", "0x85c78fac": "retryOraclizeRequest(uint256)", "0x478e25bf": "resetAction(bytes32)", "0xc74c251f": "addSafely(uint256,uint256)", "0x058aace1": "divest()", "0x6d1da953": "createWithNonce(bytes32,bytes)", "0x30c0f8d6": "scheduleTransaction(address,bytes)", "0x69a5e902": "multiAccessCall(address,uint256,bytes)", "0x6f8b44b0": "setMaxSupply(uint256)", "0x919edc7c": "getChainySender(string)", "0x0b7ad54c": "getContent(uint256)", "0x5bfdc700": "registerData(address,int256,bytes,address)", "0x0d1fce42": "getBankroll()", "0x739b47ca": "recordWin(address)", "0xa5ea11da": "getParameters()", "0xf8af9e6f": "setAdv(uint256,string,string)", "0xe32e9f22": "setDeploymentReward(uint256)", "0x0baaaed9": "setConfigBytes(bytes,bytes)", "0x99f4b251": "mine()", "0x362af076": "createRequest(address[3],address,uint256[11],uint256,bytes)", "0x7fd238ba": "doCoinage(address[],uint256[],uint256,uint256,uint256)", "0x3adb2de7": "bet_this_spin()", "0xa311dd70": "setArray(uint8[10])", "0xc5bf339c": "getLastNonPublished()", "0x9d1bbd7e": "CancelRoundAndRefundAll(uint256)", "0x89790192": "WithFee(address,uint256)", "0x1c879c47": "getMarketHashes(bytes)", "0xbb84d362": "splitProfitVIP_only_Dev()", "0xffb1a6cb": "getWins(address)", "0x3b355af6": "baseData()", "0xb181a8fc": "resetContract()", "0x7d3d6522": "goalReached()", "0xd4c2b6b1": "scheduleTransaction(address,bytes,uint256[5],uint256)", "0xd65ab5f2": "startGame()", "0x4c4766e8": "KittenRegistry()", "0x77e5bf84": "getTxGasprice()", "0xff981099": "getVotes(uint256)", "0x4a7b26ec": "join_game(uint256)", "0xcccf7a8e": "has(uint256)", "0xa525f42c": "transferFromToICAP(address,bytes32,uint256)", "0xeef8e35f": "setChainyURL(string)", "0x557ed1ba": "getTime()", "0x595da94d": "has_owners(uint256)", "0x12511c14": "transferEnable(bytes20)", "0x2b291eb6": "UserAddTicket(bytes)", "0x50baa622": "withdrawToken(uint256)", "0xc01a8c84": "confirmTransaction(uint256)", "0x671dacdc": "CalculateSqrt(uint256)", "0xe74ffbd5": "getPart(bytes32,uint256)", "0xdd54a62f": "content(string)", "0x4025b293": "redeemAllOutcomes(bytes32,uint256)", "0xa8659216": "setInitialLockinDays(uint256)", "0x00b5b223": "computeResponse(uint256,uint16)", "0x2ef761d3": "buyTile(uint8,uint8)", "0x0a874df6": "lookup(uint256)", "0x42c69566": "get_address(address,string)", "0x02dc2e1d": "queuePayment(bytes)", "0x86bb7121": "getBlocksPerRound()", "0xacfdfd1c": "deploy(uint256,string,string,address)", "0x7d298ee3": "beforeExecute(address,uint256)", "0x5023d124": "TestFactory()", "0x827ef325": "_parseMsgData(bytes)", "0xd35b9d83": "codeAt(address)", "0x26161670": "donkeyRanking(uint256)", "0xe0834ea4": "WatchBalanceInEther()", "0xd44f2d3d": "getInitialWithdrawalDone()", "0x4f223fe3": "StatefulFactory(string,string,string)", "0x91cd242d": "setMeta(bytes32,bytes32,bytes32)", "0x9a97043b": "depositIdx(address)", "0x85db2dda": "PayoutQueueSize()", "0x423e1298": "setDoNotAutoRefundTo(bool)", "0xb7a97a2b": "isValidChannel(uint256)", "0xc1441172": "setBlackFlagRequest(uint256,uint256)", "0x53d9d910": "create(address[],uint256,uint256)", "0x64d905c0": "awaitingParticipants()", "0x718bd6dd": "setRequestUntil(uint8)", "0x5a353193": "KrakenPriceTicker()", "0xfb099c84": "newInvestor()", "0xd264e05e": "forward()", "0xcd9f05b8": "balanceEtherAddress(address)", "0xa1da2fb9": "retrieveDAOReward(bool)", "0x60708ae3": "issueAndCommit(address,address,uint256,uint256)", "0x109df68e": "rotateBitsRight(bytes,uint256)", "0x793cd71e": "cashOut()", "0xd3017193": "addUser(address,uint256)", "0xaacf5328": "setVideoID(string,uint256)", "0xb56e1bca": "setExchangeToken()", "0x9341231c": "sendOrThrow(address,uint256)", "0xaed8f3da": "partsPerBillion(uint256,uint256)", "0xdcff5581": "NewFeeAddress(address)", "0xbbe4fd50": "getNow()", "0x3df16377": "make_move_and_claim_victory(uint256,uint8,uint8,uint8,uint8,uint8,uint8,uint8)", "0x5ae5df8f": "deleteRef(string)", "0x6d853ab6": "isSubUser(address)", "0x28472c6c": "claimComputation(bytes,bytes)", "0x2c215998": "updateStatus(string)", "0x7eff1465": "setAccountAllowance(address,address,uint256)", "0xd5089396": "Token(string,string,uint8,uint256)", "0xd1f7a4e4": "createCertificate(bytes)", "0x8c0e2a31": "regProxy(address)", "0xa819819b": "sweepDeityCommission(uint256)", "0x2b861629": "storeBlockHeader(bytes)", "0x25d4bdeb": "LookAtCollectedFees()", "0x5dddea66": "updateState(uint256,uint8,uint256)", "0x3ccfd60b": "withdraw()", "0x6795dbcd": "getAddress(bytes32,string)", "0x9b9ba572": "oraclize_query(string,string[3])", "0xa925d85e": "Exchange(address,address)", "0xbfe8c107": "betOnDozen(bool,bool,bool)", "0x1af716ba": "transferFrom(address,address,uint256,string)", "0x67eae672": "sendCoinFrom(address,uint256,address)", "0x311d5a2a": "recordBalance(address)", "0x7ca823d5": "getAverageChainWork()", "0x19483cd1": "checkHash()", "0xd366fbab": "startLottery(bytes32,uint256,uint256,uint256,uint256,bool)", "0x4d70d1d7": "generateId(uint256)", "0xe13dc28b": "testValidTransfers()", "0x12065fe0": "getBalance()", "0xdd67a360": "OrderLifeCycle()", "0xd7c23572": "historyTimesPlayed(address)", "0x2675c123": "CloseContract()", "0x1381e400": "cancel(uint32)", "0xa48a663c": "transferFromToICAPWithReference(address,bytes32,uint256,string)", "0xb03260be": "scheduleTransaction(uint256,address,bytes)", "0xb37217a4": "getRandomNumber(uint256)", "0x5c54305e": "InsufficientFunds(address,uint256,uint256)", "0x17e1b09b": "minimumDeposit(uint256)", "0x10c4e8b0": "all()", "0xa31d5580": "Registrar(address,bytes32,address)", "0xbe6307c8": "getDraw(uint256)", "0xc985c221": "get_all_levels()", "0x91b7f5ed": "setPrice(uint256)", "0xe42def21": "CryptoHill()", "0x738486bd": "BeerCoin(uint256)", "0xe422ebe9": "getBot()", "0x67dd74ca": "buyTicket(uint256)", "0x276b94e1": "copypaste()", "0x39aaba25": "get_status()", "0x7ed19af9": "multiAccessRevoke(bytes32)", "0x4c1b2446": "transmitInteger(address,bytes,bytes,uint256,uint16)", "0xd014c01f": "enter(address)", "0x1d49e081": "EXECUTE_EXTRA_GAS()", "0x9dafbc13": "initBlock(uint256)", "0xc7e22ac4": "setOracleGas(uint256)", "0xa3053236": "SafeInvestments()", "0xf42ac1de": "minQuorum(uint256)", "0x04d91c6a": "testFail()", "0x0e662cf0": "buyTokens(uint16)", "0x1ef0625b": "player_2(uint256)", "0xcec1365a": "ShortLimit(uint256)", "0x340f5e4e": "get_all_num_levels()", "0x3e2729bf": "isRevocated(bytes)", "0x5a1cc358": "getChannelRank(address,uint256)", "0x4d366398": "runPeerBalance()", "0xaf9a3f9b": "hashName(string)", "0x33298e25": "invoke(uint256,uint256)", "0x63def590": "untrustClient(address)", "0x836d6d66": "WeeklyLotteryB(address,uint256)", "0x7f497550": "scheduleTransfer(address,uint256,uint256)", "0xf9e05ed9": "sha(uint128)", "0xf6458c6a": "toZ1(uint256[3],uint256)", "0xf41017fc": "finalize(uint24)", "0xeeb57139": "CollectMoney(uint256)", "0xfdacd576": "setCompleted(uint256)", "0xb7266456": "StandardToken()", "0x6a8c2437": "totalRescues()", "0x1fdf6e0c": "protectKingdom()", "0xcf31e9fe": "getOutputHash()", "0xc8117b5b": "extractBalanceOfLength()", "0x0674763c": "assert(bool)", "0x87def081": "getFeeRecipient(int256)", "0xc63ff8dd": "claim(bytes)", "0x329bfc33": "getCurrentWinner()", "0x3d6a3664": "setNewOracle(address)", "0xdaa21e0e": "testBitSetSuccess()", "0xbf8783e0": "callAndGetReturn(address,bytes,uint256)", "0xb06df18e": "transfer(bytes20,address)", "0x00100a18": "NewPoll(string,string,uint256,uint256)", "0x2ffb8631": "getReleaseLockfileURI(bytes32)", "0x6716a692": "setDVIP(address)", "0xe8223468": "sha3clone(bytes)", "0x0aeacb5e": "getTotalRecords()", "0x29e30910": "testThrowCreateExistingNonce()", "0x240ecad5": "transferViaProxy(address,address,uint256)", "0xa33d4968": "Tripler()", "0x8caaaae6": "totalWeiPrice()", "0xf28a7912": "quick2()", "0xcbe9ef39": "BasicCoin(uint256,address)", "0xea3d2827": "selectWinner(string)", "0x92e9fd5e": "ColdWallet(address,address)", "0xcd5e3c5d": "roll()", "0x4a82534b": "create(address,address,address,uint256,uint8,uint8,uint256)", "0x5ccd2f9b": "_deleteAllPackedRevisionBlockNumbers(bytes20)", "0x9380b8e7": "testFailAddingMembers()", "0x31b0795c": "registerAddress(address,address)", "0xb76e4890": "Tester()", "0x29c08ba2": "payPremium()", "0xd7f31eb9": "forward(address,uint256,bytes)", "0xd7ef1356": "best_adjustment(bool)", "0x48d9a374": "blockTransfer(address,uint256)", "0x88b9e10e": "seizeTokens(address,uint256)", "0x8736fd16": "getRefStatus(uint256)", "0x2b30d2b8": "invoke(uint256)", "0xd4e78272": "Draw()", "0x0257c48c": "meta(bytes32,bytes32)", "0xc1246d39": "simulatePathwayFromBeneficiary()", "0x699b328a": "randomize()", "0xa200dc73": "getNextShareholder(address)", "0x9a7a7c11": "makeRoll(uint256)", "0x2bf1f9da": "restart(bytes32,bytes)", "0x943a32bc": "Relay(address)", "0x93503337": "isAllowed(bytes32,uint256)", "0xe97b2190": "add_wall(uint16)", "0x0448f79f": "addOptionChain(uint256,string,uint256,uint256,bytes,address,int256[])", "0xc0df77d0": "getRefName(uint256)", "0x27121069": "verify(bytes,uint8,bytes,bytes)", "0xb7009613": "canCall(address,address,bytes4)", "0x0295d71b": "currentDepositLimit()", "0x35ee2783": "Alarm()", "0x71b6663e": "play1(address,uint256)", "0x0178fe3f": "getData(uint256)", "0x489306eb": "oraclize_query(string,string)", "0xfce59d0c": "MangoRepo()", "0x8efc777f": "isBeta(bytes)", "0x1f7b8622": "getVotingDeadline()", "0x76da5667": "admin_kill()", "0x152cf9db": "getDataPoint(int256,uint256,uint256)", "0xd09de08a": "increment()", "0x64ee49fe": "scheduleCall(address,uint256,bytes4,uint256,uint256,uint8)", "0xd9fe60f3": "DTHPool(address,address,uint256,string,string,string)", "0x6b4dd158": "getPrice(bytes)", "0x0a80ef45": "getIsClosed()", "0x51fdaf92": "checkExpiredfunds()", "0x694e0d5b": "StringPasser(uint8[])", "0x0e1d88fc": "addTender(uint256,uint256,address,uint256)", "0x53850db3": "getParticipantById(uint256)", "0xb6cb405b": "getContractor()", "0x4c6b25b1": "results(bytes32)", "0x1c4e6cd0": "NameReg()", "0x53aab434": "buyIn()", "0x1ebe5c0f": "sendWithAllOurGasExcept(address,uint256,uint256)", "0xd98b9bb5": "placeBid(address,uint256)", "0x02e8d8c0": "scheduleTransaction(address,uint256,uint256)", "0x8a120dc9": "testBitEqualFailIndexOOB()", "0x33f707d1": "ownerWithdraw(uint256)", "0x98e00e54": "getCallWindowSize()", "0x4da74ee6": "setVoteIntention(uint256,bool,bool,string)", "0x6617e11a": "NiceGuyTax()", "0xfe13a823": "computeResponseFirstHalf(uint16)", "0xf7bd2361": "LookAtBalance()", "0xb09bc3bf": "try_to_get()", "0x0cee22e9": "testSetBalanceSetsSupply()", "0xae404996": "oraclize_query(string,string[3],uint256)", "0x2ad95786": "winner(address)", "0xe5fe4f31": "buy(uint8,bytes32,bytes32)", "0xe23941bc": "testDepositWithdraw()", "0xfc89aff6": "submitVerifiedUsers(address[])", "0xddf187b0": "dogFight()", "0xb5f5962a": "CALL_GAS_CEILING(uint256)", "0x92093dd6": "getLastResult()", "0xbfad16f4": "new_offer(uint256,uint256)", "0x01df7f30": "validateProposedThroneConfig(uint256,uint256,uint256,uint256)", "0x4054f5de": "EthVentures3()", "0x244c23ee": "Token(uint256,string,uint8,string)", "0xc3daab96": "withdrawBond(uint256)", "0x5fa21f1f": "enableBetting()", "0x3b591ea7": "AmountToForgeTheNextBlock()", "0x8c3c4b34": "getSaleStatus()", "0x7429f1eb": "multiAccessSetRecipientD(address,address)", "0xf99ff4df": "paged(uint256,uint256)", "0x2a64fb63": "getSaleDate(bytes)", "0x749f9889": "changeAllowedRecipients(address,bool)", "0x053c351b": "oraclize_getPrice(string)", "0x19663f7f": "TransferAmountFromBankAccountToAddress(uint256,address)", "0x5292c1a9": "testThrowsRestartEnforceRevisions()", "0x68f2ab8e": "Currency(string,string)", "0xd6e0bf29": "OwnerDeposit()", "0x94c3fa2e": "getLastBlockHashUsed()", "0x45362978": "query1(string,string)", "0xaff21c65": "getMinimumEndowment(uint256)", "0xe33c7ae2": "scheduleTransaction(uint256,uint256,bytes)", "0x9eb9dd3b": "getBetsProcessed()", "0x3807ba1b": "poi()", "0x7281854d": "GetCategoryValue(uint8)", "0x45ee49b9": "getUltimateOutcomes(bytes)", "0x0109f22e": "CrowdSale()", "0x98596726": "note(uint224)", "0x06900c41": "ZeroPonzi()", "0x3df76482": "fipsPublishData(bytes20,bytes)", "0xe0429b6c": "ShinySquirrels()", "0xa4a7cf5c": "redeemWinnings(bytes32)", "0x2e898ddc": "validateTemporalUnit(uint256)", "0x3af75ee1": "storeBlockWithFee(bytes,int256,bytes,int256)", "0x43e6125d": "Badge(address)", "0x75a6a332": "testThrowRetractNotRetractable()", "0xbed411a0": "CheckPrize(address)", "0x16f3cb5e": "__kill()", "0xe8efc1a0": "updatedValue(bytes32)", "0x9c7264d7": "fillOrder(address,uint256)", "0x9a0af2ec": "getStLength()", "0xf62cce34": "_clearRecordHierarchy(uint256,bytes32[],bytes32)", "0x940f851c": "Ballot(uint8)", "0xd96e5565": "testThrowsRetractNotRetractable()", "0x3a314b24": "SendETH(address)", "0xbd8c1d33": "checkTransferFromToICAPWithReference(address,bytes32,uint256,string)", "0x01da73ff": "isValidChannel(bytes)", "0x8f8bde82": "MicroDAO()", "0x2973e372": "isAlphaUpper(bytes1)", "0x1d2b7155": "activateImportFeeChargeRecord(address)", "0x06ab5923": "setSubnodeOwner(bytes32,bytes32,address)", "0x9d7d6667": "multipliers()", "0x8af49ab7": "maintain(uint256,uint256)", "0x1f3a3a53": "mint(int256,uint256)", "0x74389991": "breakit()", "0x64371977": "set(uint256,string)", "0x3fa6497f": "AdminAddFunds()", "0xba7dc45f": "_removeOperation(bytes32)", "0xf81d087d": "prepareLottery()", "0xd239ea8b": "getSchemasLenght()", "0xa2f3ede2": "computeNameHash(bytes)", "0xa28ecf0b": "sendCryptedHand(bytes)", "0x003b9d88": "setLowerFeePercentage(uint8)", "0x98ea5fca": "depositEther()", "0xb9a0a708": "testChargesAmountApproved()", "0x55291dbd": "claimEther()", "0x2d2800f1": "react()", "0xa9d2293d": "lastClaimBlock()", "0xc45aa04c": "queryShareholders(bytes,uint256)", "0x67af1c81": "getRoundIndex()", "0x50b7b7a2": "setRating(bytes32,uint256)", "0x0aa7881a": "MintableToken(int256,uint256)", "0x0eb3f5a0": "sweepCommission(uint256)", "0x97d47a60": "registerAccountant(bytes,address)", "0xe2c61114": "setImportFee(address,uint256)", "0x6dbe31eb": "testSubBalance()", "0xf5c98aff": "GreeterB(bytes)", "0x79216f5f": "add_monster(uint16,uint16,uint16)", "0x023c23db": "getSize(uint256)", "0x0e1ca8a5": "Oraclize()", "0xa05e822a": "howManyOwners()", "0x313b7b19": "finance()", "0x51a5f2f2": "ConsultingHalf(address,address)", "0x1fb6e99d": "paymentNeeded(uint64)", "0x2bffc7ed": "add(string,address)", "0x5c52c2f5": "resetSpentToday()", "0x39cdde32": "ecverify(bytes32,bytes,address)", "0x64e24f4b": "UpdateClientTokenAccount(address)", "0x0d2560ee": "addMe()", "0xd8589be3": "CoinFlipper()", "0x3b46a7df": "ivote(bool)", "0xa6823189": "parseAddr(string)", "0xd0c24e93": "setNotUpdatable(bytes20)", "0x1f13de92": "inEther(uint256)", "0xb6ce5581": "oraclize_query(string,string[5],uint256)", "0x31ae0019": "KissBTC()", "0xdabf7dc8": "PayoutDividendEarly(uint256,bool)", "0xe3da41b5": "sortWinningNumbers(uint8[5])", "0x8ea98117": "setCoordinator(address)", "0xeff6be2f": "changeBaseFee(uint256)", "0x483a83df": "setKYC(address)", "0xf98a4eca": "executeVote(uint256)", "0x776d1a01": "unvest(uint256,uint256,uint256,uint256,uint256,bool)", "0x1cf52f2b": "isActiveRegistrant(address)", "0x24c9bf5e": "Prizes()", "0xb3822da8": "getContents(uint256[])", "0x999a9965": "setMany(uint256,int256,uint256,bytes,address,bytes)", "0xbade6033": "propose(bytes,uint256)", "0xd38159b8": "testPass()", "0xdabf7ec4": "helper(uint256)", "0xf4993bbd": "executeEmergencyWithdrawal()", "0x46ddb7db": "setAccountBalance(address,uint256)", "0xc12af1ce": "fipsRegister(uint256,bytes)", "0x8f420866": "DEFAULT_SEND_GAS()", "0x62770252": "needsFuneral(uint256)", "0x32921690": "checkDepth(address,uint256)", "0xb3c1a588": "parseMsgData(bytes)", "0x29cd5777": "_tryEraseSingleNode(bytes32)", "0xc6e0c908": "checkTransferFromWithReference(address,address,uint256,string)", "0x9bd99195": "multiAccessChangeOwner(address,address)", "0xa360b26f": "Migrations()", "0x6c6f1d93": "getContractCreationValue()", "0x5445e38c": "_isCycleValid(uint256)", "0x2c85f8e0": "oraclize_query(string,string,string,uint256)", "0xcdda62ad": "FutureBlockCall(address,uint256,uint8,address,bytes4,bytes,uint256,uint256,uint16,uint256,uint256)", "0xc8fdc891": "numberOfMonarchs()", "0xf578fd85": "assertEq0(bytes,bytes)", "0xda311588": "getCoin(uint256)", "0x9a35f886": "__dig_then_proxy(uint256)", "0xfa14df6b": "getChangeRecipientFee()", "0x95f0684b": "getPackageNameHash(uint256)", "0x42909a9e": "create_game()", "0x51582ef3": "sendProxyTransaction(address,uint256,uint256,bytes)", "0xc4e41b22": "getTotalSupply()", "0x110df916": "getChannelID(uint256)", "0x4dc3141b": "CalcAll()", "0xb88a802f": "claimReward()", "0x82b2e257": "getTokenBalance()", "0x9bb0e4df": "getUint(int256,bytes32,string)", "0xc1ae4044": "checkBetColor(uint8)", "0x4a8b5389": "allocateBountyAndEcosystemTokens()", "0xdf06f906": "numBets()", "0xdeb80111": "transfer_asset(address,uint256)", "0x5216aeec": "totalInvested()", "0xe2deaa81": "set_reference(uint256,uint256,uint256)", "0x2ffda1e0": "setBlackflag(uint256,bool)", "0xba45b0b8": "transfer(address,address)", "0x7d7c2a1c": "rebalance()", "0xf32efd3c": "recoverUser(address,address,uint256,uint8,bytes32,bytes32)", "0x4571d4c4": "FutureCall(address,uint256,uint16,address,bytes,bytes,uint256,uint256,uint256)", "0x5fc5d48b": "burnUnsoldCoins(address)", "0x4da47ba0": "TokenSale(address,uint256)", "0x3d9ce89b": "scheduleCall(bytes4,bytes,uint256)", "0x6662e4be": "isWinningBet(uint256)", "0xa501e88d": "Content()", "0x4b70cec4": "getTime(address)", "0x12253a6c": "stopContract()", "0x173825d9": "removeOwner(address)", "0x26121ff0": "f()", "0x7b647652": "LittleEthereumDoubler()", "0x0c5c2ca3": "getIndexName(bytes)", "0x90f2c86d": "convertToWei(uint256,string)", "0x83f95f13": "openClaim(string)", "0xe8b5e51f": "invest()", "0xfdc4b338": "authorizeExtension(uint256,bool,string)", "0x4e116eb8": "unRegisterCertificationDb(address)", "0x5c8a1053": "extend(string)", "0xa932ed0d": "whitelistRemove(address)", "0xa1188e56": "getCurrentDifficulty()", "0xbf1fe420": "setGasPrice(uint256)", "0xead710c4": "greet(string)", "0x144fa6d7": "setToken(address)", "0x42402c2c": "fipsTransferMulti(bytes20[],address)", "0x93e84cd9": "play()", "0x741b3c39": "depositBond()", "0x23306ed6": "getMinimumBond()", "0x5f2e686d": "Ethereum_eight_bagger()", "0x9890220b": "drain()", "0x233120aa": "getChainyURL()", "0xe9dc0614": "vote(bytes)", "0x4df53a0f": "testSetApprovalDb()", "0x5fe27ab0": "createHKG(address)", "0xb56b2627": "add_owner(uint256,address)", "0x6f9a023c": "theultimatepyramid()", "0xc8796572": "collectFees()", "0xea3ebae6": "getConfigBool(bytes32)", "0x213ac932": "addUser(address,uint256,uint8,bytes32,bytes32)", "0xfae9d06d": "calculateTxFee(uint256,address)", "0x45d27edf": "forward_method(bytes,address,uint256,bytes)", "0x8e9ccd04": "computeIndexId(address,bytes)", "0x2f6ae467": "transferDocument(bytes,address)", "0x6e353a1d": "emergencyWithdrawal(address)", "0x7dd56411": "ownerOf(bytes32)", "0x9dc35799": "updateReading(uint256)", "0x246c02e6": "check_depth(uint16)", "0x03d22885": "scheduleCall(address,uint256,bytes4,uint256,uint256,uint8,uint256)", "0x881be8f7": "undo()", "0x953307d8": "revealScissors(string)", "0x7af30442": "testToggleBitFailIndexOOB()", "0x1e0c7ed4": "setConfigBool(bytes32,bool)", "0x2e3be78d": "setPrecisionDirect(uint8)", "0x95a078e8": "hasAccess(address)", "0x245a03ec": "scheduleSetIt(uint256,uint256)", "0xb863bd37": "random(uint256)", "0xa5e62f02": "fallbackRP()", "0x618fa9ce": "getBotBillingIndex(uint256,uint256)", "0x06909f69": "cancel(string,uint256)", "0x2b198366": "addCertifier(address)", "0x57e871e7": "blockNumber()", "0x2b98222e": "getInstitutionByAddress(address)", "0x89eedf00": "setPdfHash(bytes,bytes)", "0x7ac4b05e": "returnMyMoney(uint256)", "0x7fc90182": "Pool(uint256)", "0x291e6777": "sendVote(uint256,uint256)", "0x579badf6": "UniversalFunction(uint8,bytes32,bytes32,bytes32,bytes32,bytes32)", "0xe1f21c67": "approve(address,address,uint256)", "0xa1b9af31": "unlockBets()", "0x92d0d153": "t()", "0x095ea7b3": "approve(address,uint256)", "0x9cb31079": "setLowLimit(uint256)", "0xb971b4e5": "setNotTransferable(bytes20)", "0x2a745971": "BlockKing()", "0x582ca57b": "get_associations()", "0xa0d605c6": "addCertificationDocumentInternal(address,bytes32)", "0x85233869": "NumberOfMiners()", "0xb0349184": "clearRecords(bytes32[])", "0x3e8f5b90": "setConfig(string,uint256)", "0x7c73f846": "getMinimumEndowment(uint256,uint256,uint256)", "0xcc9ae3f6": "getMyReward()", "0xac900c2d": "unregisterSeller(address)", "0x306df22d": "GPSDestination(int256,int256,uint256)", "0x5e968a49": "ownerSetMaxProfitAsPercentOfHouse(uint256)", "0x80dcaf27": "getRefNumber()", "0x4245b0f7": "Lottery()", "0xe46164c5": "waitingForPayout()", "0xa8c3ec48": "oraclize_query(uint256,string,string[2])", "0x58ea80e5": "setThroneCreationPrice(uint256)", "0x8a4fb16a": "getWithdrawal(uint256)", "0x4464aec7": "testTryGet()", "0xf3c37bd5": "Verifier(address,uint256,uint8)", "0xb4c4e005": "testTransferToAcceptAuthority()", "0x346b306a": "oraclize_query(string,string,string)", "0x24032866": "checkExecutionAuthorization(address,uint256)", "0x509f8633": "create_account()", "0x26da8e17": "ownerUpdateCostToCallOraclize(uint256)", "0x74a93e6c": "setTokenHolder(address,address)", "0x1baaeb91": "getSignature(bytes4,uint256)", "0x337c1e28": "getIndexRoot(bytes)", "0xac92fdb5": "getSaleDate(bytes16,uint256)", "0x13b2663b": "cash_received(string)", "0x68e4bd99": "testSetBitSuccess()", "0x20620f37": "onAuctionEnd(string)", "0x85528394": "currentClaimPriceWei()", "0x1995333b": "burnFunds(uint256)", "0x5184ffc9": "setAmbiAddress(address,bytes)", "0x269975d0": "GameDetails(uint256)", "0x29274fe1": "buyBOTx(uint256,string,string,address,uint256)", "0x720c4798": "workshop()", "0x6f9a5eab": "createTx(uint256,address,uint256)", "0xb66a323c": "claimThrone(string)", "0x14cabddb": "joinProof(uint256)", "0x76e4ca0d": "voteQuorum(uint256,bool)", "0xbcb3b5d2": "getGamblesList(uint256)", "0xf2080ba6": "Pong(int8)", "0xab470f05": "getCaller()", "0xe0b1cccb": "updateBalance(address,uint256)", "0x4889ca88": "receiveApproval(address,uint256,address)", "0xbc4b3365": "addFunds(address,uint256)", "0x5d1a3b82": "getOutcome(bytes32)", "0x8204ecdd": "getFee(bytes)", "0x49aa4ee2": "removeVote()", "0x9131d803": "testSetFrontend()", "0x72929b56": "getKudosPerProject(address)", "0x287418e7": "query(uint256,uint16)", "0xbb7859b5": "periodThree()", "0x7dc5cd32": "_patternToNumber(bytes)", "0xf7ea7a3d": "setTotalSupply(uint256)", "0xb3f98adc": "vote(uint8)", "0x655388be": "walkTowardsBlock()", "0x856deacf": "findTag(string)", "0xcaab0acc": "testThrowCreateRetracted()", "0xede8ebf3": "checkApprove(address,uint256)", "0x4296a9cb": "getNodeRightChild(bytes)", "0x03cf4fd6": "expire(uint256,uint256,uint8,bytes32,bytes32,bytes32)", "0x87045369": "setCanCall(address,address,bytes4,bool)", "0x0ed21029": "getIssueAssignee(uint256,bytes32)", "0xc5958bda": "removeFile(bytes)", "0xa8026912": "setSource(address)", "0x05a5b8c6": "verifyTx(bytes,int256,int256[],int256,bytes,int256,int256[],int256)", "0xed3058e0": "transferRight(address,bytes)", "0xba487e62": "newCampaign(uint32,uint96,uint16,uint16)", "0xd6c19fe0": "build(bytes,uint256,uint256,address)", "0xebb741cb": "getChannelSize(uint256)", "0x3b996f40": "quarter(uint32,uint32,uint32,uint32)", "0x0b7373d6": "giveAllBack()", "0x3f887fad": "buyShares(uint256,uint8,uint256,uint256)", "0xb5deeca7": "BaseRegistry()", "0x6dd6e87b": "checkOut(int256)", "0x90a85119": "checkBetResult(uint8)", "0x724121ae": "contentExists(uint256)", "0x67bd69a6": "getLastDuel2()", "0x821e9169": "testFailControllerChargeMoreThanApproved()", "0x083ae1fe": "setPackage(string)", "0x8eaa6ac0": "get(bytes32)", "0xf42aa287": "getBlobStore(bytes12)", "0x32a2c5d0": "getContractAddress()", "0x69d89575": "releaseFunds()", "0x984ac378": "lotteryTitle()", "0x3baf4e1e": "newPayment(uint256,uint256)", "0x938c4307": "scheduleCall(bytes4,bytes,uint16,uint8,uint256,uint256,uint256,uint256,uint256)", "0x47372325": "getChannelSize(address)", "0xcb10e0c5": "getLastDuel1()", "0x1a0919dc": "unregister(bytes32)", "0x6a3c1198": "_projectCancelNew()", "0x976b01c0": "setNotRetractable(bytes20)", "0x44d03ac6": "BlockhashFetch(address)", "0xb0fd935b": "registerCertificationDb(address)", "0x2c7c4549": "PurchasableToken(uint256)", "0x3e0a51b4": "TweetAccount()", "0xc5f310c0": "register(bytes12)", "0xc10dd4c6": "getEvents(bytes32[],address)", "0x37a6b9f8": "recordCallback(address,uint256,bytes,bytes)", "0x1b9265b8": "pay()", "0xc91d7e9c": "getFee(bytes32[])", "0xf6c5c80d": "cleanUp()", "0x590e1ae3": "refund()", "0x9c709343": "split(bool,address)", "0xe68d3ae3": "escrow(uint256,string,address,uint256)", "0xa1cb31b7": "_state()", "0xfbac3951": "isBlocked(address)", "0x29dfdded": "addNewDonkey(address)", "0x7bc49a95": "play(uint256,uint256)", "0x5329c681": "checkTimeout(uint256)", "0x7c05caf3": "testCreateCostAuth()", "0x8606f905": "balanceOf(address,bytes)", "0xbe45fd62": "transfer(address,uint256,bytes)", "0xd7130651": "getCity(uint256)", "0xb2353d69": "updateRightLottery(address)", "0x01bb85a4": "__startBlock(string)", "0x4316abbb": "newJester(address)", "0x5c3e426c": "adminRetrieveDonations(address)", "0x293ffca3": "AddressReg()", "0x4156fdb7": "createSwap(uint256)", "0x2852b71c": "accept()", "0x027a5e3f": "getLastVersion(bytes)", "0x3d90d44d": "addPowerSource(address,uint256,uint256)", "0x1ab06ee5": "set(uint256,uint256)", "0x50f07cf9": "setReadingDelay(uint256)", "0x669e48aa": "get(uint256,uint256)", "0xdea9c72b": "getLatestPreReleaseTree(bytes32,uint32,uint32,uint32)", "0x60f66701": "useCoupon(string)", "0x2431f164": "process_payment()", "0x17623e5b": "unauthorizeManager(address)", "0x367bbd78": "strlen(string)", "0xbab86ea8": "test(string,string)", "0x25f3da52": "GetBankAccountNumber()", "0xebb045fa": "PublicResolver(address)", "0xdd57d5c5": "setTrust(address)", "0x22e803c2": "transferBounty()", "0x12c8052f": "won()", "0x3535cd52": "setDailyCosts(uint256)", "0x92d8c8cf": "setupImportFee(address,uint256)", "0x53caf582": "testThrowSetNotUpdatableNotOwner()", "0xb3ade772": "shipProducts(string,string)", "0x61472fd4": "CSGOBets()", "0x5c7c9aa4": "checkAccountState(address)", "0x6560a307": "suggestedGas()", "0xd0d552dd": "setAsset(address)", "0xc02f081a": "shiftBits(bytes,int256)", "0x9348cef7": "reveal(uint256,uint256)", "0x5ca1c5a0": "getNodeValue(bytes)", "0x34c1b4ba": "sha(bytes)", "0xe0117441": "setRegistrationPrice(uint256)", "0x92698814": "reserved(bytes32)", "0xaa1e84de": "hash(bytes)", "0x2125b65b": "transfer(uint32,address,uint224)", "0x9f9eac67": "ChangeName(string)", "0x7eb69ba1": "hint(int256,bytes32,string,bytes20)", "0xc6888fa1": "multiply(uint256)", "0xa9059cbb": "transfer(address,uint256)", "0x84c344fe": "_register(bytes4,string)", "0x744d8b4f": "recordWin(uint256,uint256)", "0xad1ef61e": "donkeyInvested(address)", "0xb4787dc5": "linkEID(bytes,bytes)", "0x7b1cbb13": "getChannelValue(bytes)", "0xd0febe4c": "buyTokens()", "0x74f519db": "setLastTimestamp(uint256,uint256)", "0xe30081a0": "setAddress(address)", "0x6fd902e1": "getCurrentBlockNumber()", "0x25d8dcf2": "betAndFlip()", "0xc062f578": "updateStage()", "0xe0cfc05c": "testThrowsRetractLatestRevisionDoesntHaveAdditionalRevisions()", "0x854f4817": "buyKissBTCWithCallback(address,uint256)", "0x58b1f29c": "refundBounty(uint256)", "0x0645b5d5": "getMyShareholderID()", "0xe9c63b9c": "requestPeerBalance()", "0x1b03316f": "getSecond()", "0xbcc6092a": "MyEtherBank()", "0x1cf43b63": "extractExportFeeChargeLength()", "0x5e58f141": "shares(address,bytes,int256)", "0x6103d70b": "withdrawPayments()", "0x3e0663e0": "AdminDrawProcess()", "0xa0f029fc": "ContractorInterface(address,address,address)", "0xe604cf9f": "get_all_squares()", "0xd13d1ace": "scheduleCall(bytes,bytes,uint16,uint8,uint256,uint256,uint256,uint256,uint256)", "0xb74bc710": "LuckyDoubler()", "0x611f69de": "__proxy_motion(address,uint256,uint256,bytes)", "0xbb814e9e": "versionExists(bytes32)", "0x545e7c61": "deploy(address,address)", "0x1b437d0c": "compareLastCalldata(bytes)", "0x845051d3": "testContractsNotNull()", "0x23de6651": "emitTransfer(address,address,uint256)", "0xd78c20ff": "voteApprove(uint256)", "0x6f13e01b": "EthVenturePlugin()", "0x1f6b0a9d": "getReleaseLockfileURI(string,uint32,uint32,uint32,string,string)", "0x13d4bc24": "buyTokenProxy(address)", "0xd509b16c": "testWithdraw()", "0x2f54bf6e": "isOwner(address)", "0xf60381a1": "stra2cbor(string[])", "0x34dbe44d": "getLastBlockNumberUsed()", "0x28dcfdac": "getSignsCount(uint256)", "0x2888f9d0": "updateMaxBet()", "0xc3b2556d": "lookup(bytes)", "0x6fbaaa1e": "currentMultiplier()", "0xe241c1d9": "deriveKey(uint256,uint256,uint256)", "0x5b37e150": "create(bytes32,bytes)", "0xa1c95ac2": "GSIToken(uint256,string,uint8,string,address)", "0xfc9e53df": "setNextRegistrar(address)", "0x34e8980f": "bootUpHangouts()", "0x457dd8b3": "setMasterKey(address)", "0xdb833e3a": "sellShares(bytes32,uint8,uint256,uint256)", "0x1e5330ca": "checkBetResult(uint8,address,bytes32,bytes32)", "0x4a00a522": "homebase(int256,int256)", "0xb938bf42": "sendBounty(bytes32)", "0x46be96c3": "amountFilled(address,uint256,address,uint256,uint256,uint256,address,uint8,bytes32,bytes32)", "0x2fa00e58": "fipsTransfer(bytes20,address)", "0x95669952": "debtor(address,uint256)", "0x3f19d043": "getContributions(address)", "0xeb455dc6": "sendBitcoin(string,uint256)", "0x034cb28e": "addressOf(address,bytes)", "0x1e26fd33": "setBool(bool)", "0x1b55ba3a": "Start()", "0x6f3fe404": "updateBalances()", "0xc45b415e": "createRequest(address[4],address,uint256[11],uint256,bytes)", "0x180aadb7": "underLimit(uint256)", "0xb44bd51d": "getConfig(string)", "0x93d79105": "hashRelease(bytes32,bytes32)", "0x9f8a13d7": "isActive(address)", "0x257bcd6a": "placeBet(uint256,bytes32,bytes32)", "0xdd10d97e": "getPlayerWaiting()", "0x6d16f79c": "__transferWithReference(address,uint256,string)", "0x6ce1417e": "Fund()", "0x67beaccb": "scheduleCall(bytes)", "0x4b0697e4": "Manager(address)", "0x6a7fc8b7": "setDailyWithdrawLimit(uint128)", "0x7a6e9df7": "getTimestamp(bytes)", "0x797af627": "confirm(bytes32)", "0x81183633": "setStandard(bytes32)", "0x6a1db1bf": "changeFee(uint256)", "0x4e6ab570": "insert_order(address,bool,uint32,uint128)", "0xa4e2d634": "isLocked()", "0x7c79ebce": "expired(uint64)", "0x20965255": "getValue()", "0xfd408767": "fireEventLog4()", "0xcf6b3822": "WatchCollectedFeesInSzabo()", "0x8f7fe231": "ValidetherOracle()", "0xbf12165e": "fillUpSlot(uint256,uint256)", "0xdabdc1f2": "ChangeActiveDigger(address)", "0xe9e7a667": "get_stake(bytes32)", "0x0ad95b44": "bribery()", "0xdb6fcf01": "is_destroyed(uint256)", "0x4378a6e3": "getAttributes(uint256)", "0x71589d6b": "newponzi()", "0x47274dbe": "disableUser(address,address)", "0xb40a5627": "bidCount()", "0xf1eae25c": "mortal()", "0x13af4035": "setOwner(address)", "0xaf030d2c": "setResult(uint256,uint256,bytes32)", "0x098ab6a1": "snapshotCount()", "0x27cca148": "lastClaimedBlock()", "0x940c154b": "lockBet(uint256)", "0x378c0605": "buyTickets(address)", "0xbcfcb03e": "allocateFounderTokens()", "0x0138e31b": "_jAdd(uint256,uint256,uint256,uint256)", "0x0a7f4239": "getAccountFundContract(address)", "0xc96593a0": "The10ETHPyramid()", "0x22beb9b9": "scheduleDoIt(uint256)", "0xdb0e127a": "openDoor()", "0x3dc02266": "fipsRegister(uint256)", "0x7d242ae5": "setBasePrice(uint256,bytes)", "0xe82b7cb2": "proxySetCosignerAddress(address,bytes32)", "0xa60bbcd3": "ModelCoordinator()", "0xc26aa3c9": "lockUnicorn(uint256)", "0x96ff7e97": "requestIdentity()", "0x99753de7": "clear_level()", "0x69d79ad5": "moneySumAtSettlement(address,uint256,uint256,int256,uint256,uint256)", "0xda359dc8": "setBytes(bytes)", "0x6edb4cf6": "testThrowRetractLatestRevisionDoesntHaveAdditionalRevisions()", "0x9d170c5d": "getRef(string)", "0x11cd98ed": "convertToAllTable(uint256,string)", "0x67f809e9": "DynamicPyramid()", "0xd5f37f95": "sign(uint256,uint256,address)", "0xf5562753": "getClaimAmountForBlock(uint256)", "0xc9bbc8c0": "donkeyName(address)", "0x5858ef10": "testErrorNonOwnerCantBreach()", "0x74388347": "checkBetDozen(uint8,address,bytes32,bytes32)", "0xee564544": "_slotCancelNew()", "0xf3bb9741": "commitmentCampaign(uint256,bytes32)", "0x2b68b9c6": "destruct()", "0xa9b8f7b8": "ProtectTheCastle()", "0x16181bb7": "shortSellShares(bytes32,uint8,uint256,uint256)", "0xb524abcf": "totalSupply(bytes32)", "0x8006745b": "getPayout(address)", "0x137c638b": "getExtraGas()", "0x824d5603": "getIndex(uint16,uint16)", "0x245a6f74": "isProxyLegit(address)", "0x9eded57a": "paybackLast()", "0x7b1aa45f": "ownerDeposit()", "0x974654f4": "requiredGas()", "0x76d690bb": "BountyList()", "0xf4b2dfea": "Matching_Finneys()", "0xbd66528a": "claim(bytes32)", "0x85eac05f": "changeOwnerAddress(address)", "0xa69df4b5": "unlock()", "0xe6d9bb0f": "secondsUntilEnd()", "0xcd57a448": "SwapContract(address,uint256)", "0xb245fc92": "findNextMonth(uint256,bytes)", "0x7620f4bb": "fipsNotaryLegacy68b4()", "0x61886014": "combineDice(uint8,uint8)", "0xdf4ec249": "step3()", "0x2262cd94": "wroom()", "0x1099d3ec": "scheduleTransaction(uint256,uint256,uint256,bytes)", "0xd8c34127": "isKnownSignature(string)", "0x8afa08bd": "setDrawDate(uint256)", "0xdb18c972": "play4(address,uint256)", "0x2f30283e": "testSomething()", "0x8ca17995": "divest(uint256)", "0x1ef3755d": "restart()", "0x99bb875c": "funeralAndBirth(bytes,int256,bytes)", "0x157ad5a1": "canWithdrawBond(address,uint256)", "0xfd8055d2": "updateBOTBillingInfo(uint256,string,address,string,string,uint256)", "0xa10889fa": "setVersion(uint32,uint32,uint32,string,string)", "0x51cff8d9": "withdraw(address)", "0xbe999705": "addFunds(uint256)", "0x2e5d1042": "requestPayout(uint256,uint256,bytes32,uint256,uint256)", "0xb50954b6": "cancelWaitingForOpponent()", "0xc42cd8cf": "etherSplit(address,address)", "0x42ce1488": "upload(string)", "0xad04592e": "owner_deposit()", "0xc2cf7326": "hasConfirmed(bytes32,address)", "0x1dbf3bc7": "spend(uint256)", "0x36b81feb": "Deed(address)", "0xf47289e1": "_ecDouble(uint256,uint256,uint256)", "0x026993e0": "Midas(address,address)", "0x5e404de3": "setMaximumCredit(uint256)", "0x0194db8e": "sum(uint256[])", "0xa04a0908": "execute(address,bytes,uint256)", "0x2b4a3b31": "doTransferFrom(address,address,uint256)", "0x96ed10a4": "issuePOIs()", "0xb75c7dc6": "revoke(bytes32)", "0x6056969b": "announce(bytes32)", "0xd63547e6": "GetFreeCnt()", "0x788e26e7": "sponsorDeposit()", "0x550dd006": "calcCostsBuying(uint256,uint8,uint8,uint256)", "0xd4b1d19f": "testThrowsTransferDisabled()", "0x04706fdf": "giveContributionsBackProfitBugged()", "0x5d5483b3": "WatchAppliedFeePercentage()", "0x6bf8f85a": "forceFinish()", "0x3edd90e7": "NewOwner(address)", "0x7c69b5d1": "NewDeposit(uint256)", "0x866f6736": "trustedChildWithdraw()", "0xcdcb7c8f": "chase()", "0x60dccd89": "getContentAccount(uint256)", "0xbff1f9e1": "totalUsers()", "0x1aca00fd": "variable(uint256)", "0x6e658fbe": "myFundsExpireIn(uint256)", "0xddb1bdc8": "credit(address,uint256,uint256)", "0x934bc29d": "exampleFunction(uint256)", "0x113e6b66": "fipsAddToLedger(bytes20,address)", "0x1a88bc66": "slot()", "0xec97cff7": "addCertificationDocument(address,bytes32)", "0x0790e880": "setBlockappsAddr(address)", "0xe0ad411d": "assets(bytes)", "0x791b51f1": "Consulting(address,address)", "0xa26dbf26": "totalParticipants()", "0xb78b52df": "allocate(address,uint256)", "0xdb29fe12": "addShareholder(address)", "0x06459119": "testThrowsTransferNotTransferable()", "0xbadbaa3c": "setCallData()", "0x2c6b2c92": "checkProfitLossSinceInvestorChange()", "0x8aa6f1b1": "setUltimateOutcome(bytes32)", "0xecb98714": "random_damage(uint256)", "0x506e106c": "setToS(string)", "0xf0d474f9": "underdogCount()", "0x2212dbc3": "get_timestamp()", "0xd504ea1d": "getArray()", "0x9b29cb23": "getDailyPayment()", "0x9d3e069c": "StartDraw()", "0x12494160": "isHolder()", "0xbbd4e8c9": "numDeposits()", "0xfea2920e": "createNewDraw()", "0xff556ecb": "releaseUnicorn(uint256)", "0x3bed33ce": "withdrawEther(uint256)", "0xaa9669c1": "roll(uint256,bytes)", "0xa00aede9": "scheduleCall(uint256,address)", "0xc0819961": "Invest()", "0x1ed24195": "getPeriod()", "0x5babb758": "testSetUp()", "0xaaf9d13e": "buyTopDog(uint256,uint256)", "0x7c45ef6c": "stringToSig(string,string)", "0x7353f62b": "testGetApprovalDb()", "0xef7507c8": "testWinner(uint256)", "0x7ef95c6f": "extractAccountAllowanceRecordLength(address)", "0x66099706": "getChannelCred(address,uint256)", "0x5c242c59": "query1(uint256,string,string,uint256)", "0x299a7bcc": "setOwner(address,address)", "0xe1152343": "payout(uint256)", "0xd40a71fb": "step1()", "0xda9c6a46": "getReplyCount(uint256)", "0xffb7bfba": "watchProposal(uint256)", "0x2e1a7d4d": "withdraw(uint256)", "0x03da8902": "transfearDBOwner(address)", "0xc9bd2893": "fines()", "0xfdd3a879": "quick()", "0xda0774ad": "getCallFeeScalar(uint256,uint256)", "0x0f2c9329": "split(address,address)", "0xa3912ec8": "receiveEther()", "0xfd6f5430": "setContent(string,bytes32)", "0x99e0021f": "mergencyCall()", "0xb7aec6a5": "scheduleCall(address,bytes,uint256,uint256,uint8,uint256)", "0x23145ca0": "forceCheck()", "0xc7cf28fe": "canClaimTimeout()", "0x26db7648": "proposedVersion()", "0x60a60fd8": "testProxyCallWithValue()", "0x044d0b06": "oraclize_query(string,string[2])", "0x4f013184": "investInTheSystem()", "0x0c9fd581": "assertTrue(bool)", "0x09574810": "getOperationsNumber()", "0x6e2edf30": "ETCSurvey(address)", "0x3cc86b80": "GetMoney(uint256,address)", "0xf7b89a3e": "getTotalCosts()", "0xb18c6847": "manualUpdateBalances()", "0x8a65d874": "userStats(address)", "0xf80b3cfa": "checkBetLowhigh(uint8)", "0xc2def3b9": "getOrganizer()", "0x2dae9878": "BankOwner_EnableConnectBankAccountToNewOwnerAddress()", "0x1998aeef": "bid()", "0xc64e8bc0": "executeN(uint256)", "0xd4088e33": "setPrice(uint256,uint256,uint64)", "0xd263b7eb": "ownerkill()", "0xc478fc37": "EtherWheel(uint256,uint256,uint8)", "0x05b765ea": "getCertifierStatus(address)", "0x93c32e06": "changeFounder(address)", "0xf207564e": "register(uint256)", "0xae6c0b03": "canWithdrawBond(uint256)", "0x2b1071c9": "testTransferToNullAuthority()", "0xd9feeeb6": "fillMyOrder(uint256)", "0x9fb755d7": "setHotWallet(address)", "0x7f98444f": "randomEnd()", "0xf3fef3a3": "withdraw(address,uint256)", "0x48a0d754": "available()", "0x3af94817": "getPongvalRemote()", "0xec21a913": "setUint256(int256,uint256)", "0x6099af40": "setConfigBool(bytes,bool)", "0xf0cbe059": "proxyTransferFromWithReference(address,address,uint256,bytes32,string)", "0xf93589ce": "didWin(bytes)", "0x1eb5ea2e": "returnFunds()", "0xa6027d53": "IconomiTokenTest(uint256,string,uint8,string,uint256)", "0x8a323b38": "Contract(uint256,string,uint8,string)", "0xb0f07e44": "registerData()", "0xc9d27afe": "vote(uint256,bool)", "0x64265b1a": "share_transfered(string)", "0x78205f67": "testThrowTransferEnableNotTransferable()", "0x081780f4": "clearRecord(bytes32)", "0xdd137b5d": "toBase58(uint256,uint8)", "0x9483e91a": "withdraw(address,uint256,bytes,uint256)", "0xc6502da8": "basePayment()", "0xe17e1274": "testTransferToRejectAuthority()", "0x9af605cb": "__proxy(address,bytes,uint256)", "0x7a8df1b9": "getAffiliateInfo(address)", "0x46b305d6": "lockBetsForWithdraw()", "0x7d4cf602": "buildDSBalanceDB()", "0xce87f626": "replaceWizardRP(address)", "0x125b8f06": "isInNextGeneration()", "0xd0068f80": "getClient(uint256)", "0x7f0899f2": "AddTicket(bytes5[])", "0xb15dcc25": "query(address,bytes2,uint256)", "0x07a9574a": "changeLeaderMessage(string)", "0x16e55626": "getDogName(address)", "0xbc058968": "updateThingData(bytes32[],bytes32[],uint88)", "0x02aa274b": "setForward(bytes4,address)", "0x08f235ec": "getDefaultPayment()", "0x1dd4914b": "withdrawEtherOrThrow(uint256)", "0x7ca31724": "tokenId(address)", "0x0c4f65bd": "getOwnerAddress()", "0xeec3cb41": "placeBet(bool[],uint256,uint256)", "0x9054bdec": "toTimestamp(uint16,uint8,uint8,uint8,uint8,uint8)", "0x468f02d2": "getUnderlyingPrice()", "0x74331be7": "sete(address)", "0xb05e390a": "TokenEther(string,string)", "0x89cc5ea8": "bid(string,address,uint256)", "0xa8893a6e": "getNumOfSalesWithSameId(bytes16)", "0x3defb962": "heartbeat()", "0x15a03930": "TossMyCoin()", "0x1d8ae626": "Security(string,string)", "0xf1bca7a4": "doCall(uint256)", "0xae6215d8": "getBlockHeight(bytes)", "0x8124bb0f": "continueExecution()", "0xc1cbbca7": "contribute(uint256)", "0xa48566ba": "serverSeed(address,bytes)", "0xc0f5a9cb": "deleteThing(bytes32[])", "0x4136aa35": "isAlive()", "0x6fe665e9": "SlotMachine()", "0xfaff50a8": "rootNode()", "0xaf769eff": "Paper()", "0x77863b61": "CrossWhitehatWithdraw(uint256,address)", "0x2bed55b0": "buildDSEasyMultisig(uint256,uint256,uint256)", "0xd2ef7398": "challenge()", "0x96e4ee3d": "convert(uint256,uint256)", "0x2dff6941": "content(bytes32)", "0x4d536f9f": "validateNameExt(bytes)", "0xd4d5d32a": "collectFee()", "0x6620a935": "sendToOwner()", "0x5084da18": "fipsOwner(bytes20)", "0xe419f189": "multiAccessIsOwner(address)", "0xa9fbc614": "lookupTicketHolder(uint256)", "0x11f72496": "testT()", "0x7365870b": "bet(uint256)", "0x09861b81": "flooredSub(uint256,uint256)", "0xe28fed1e": "userRescues(address)", "0x28cc413a": "getProof(uint256,uint256,uint256)", "0x9a8f09bd": "newKing(address)", "0x5d068051": "sendFees(address)", "0x49cbe338": "tryRead(uint64)", "0x691bfc89": "goods(uint16,uint256)", "0xfc36e15b": "vote(string)", "0x48107843": "getNextCallSibling(address)", "0x6461fe39": "transferFromWithReference(address,address,uint256,string)", "0x804e11dc": "testThrowsDisownNotTransferable()", "0x76f30ca1": "toContentID(address,uint256,string,bytes)", "0xa77b2e37": "Coin()", "0x3f2f1596": "setupTreasury(address,uint256)", "0x3de9e4c6": "__transferFromWithReference(address,address,uint256,string)", "0x612e45a3": "newProposal(address,uint256,string,bytes,uint256,bool)", "0x4cdb48e4": "isValidNym(address)", "0x5afa5036": "isCertified(address)", "0x9a1b420b": "OraclizeAddrResolver()", "0xec5c9036": "Crowdsale(address,uint256,uint256)", "0x01095962": "oraclize_setCustomGasPrice(uint256)", "0xe7e2aa0e": "buyer_cancel()", "0x2da8f764": "submitVideo(string,string)", "0x3395dc70": "acceptTransfer(address,address,uint256)", "0xdf143fb7": "HackerGold(address)", "0x63334c58": "transferETC(address)", "0x6a5da6e5": "followCampaign(uint256)", "0x49fb2dc5": "add_to_association(uint256,uint256,uint256)", "0x953aa435": "GetPrice(uint8)", "0xc1257bad": "testPassingAProposal()", "0x3bc5de30": "getData()", "0x4abb9d39": "depletable()", "0x129484b6": "changeFeeRecipient(int256,int256,int256,int256,int256,int256)", "0x902e64e5": "Oath()", "0x8c4dd5cd": "Democracy()", "0xbea124a6": "query(bytes,bytes,int256)", "0x69347990": "ownerWithdrawl()", "0x606deecd": "requestData()", "0x6720ceb1": "sendPayment()", "0xb1050da5": "newProposal(address,uint256,string,bytes)", "0xfeaa29d8": "insertProfitHere()", "0x36f9f49c": "etherandomSeed()", "0xae815843": "query(uint256,string,string,uint256)", "0x752d349c": "depthCheck(int256,int256)", "0xa24835d1": "destroy(address,uint256)", "0x26070774": "Token(address)", "0x6e0d98fe": "setProbabilities(uint32[])", "0x0761a004": "step(uint256,bytes)", "0xad82dcac": "testBlockhashCorrectFee()", "0x0900f010": "upgrade(address)", "0xa288fb1f": "setConfigUint(int256,bytes,uint256)", "0xe88b8ac6": "confirmAndCheck(bytes)", "0xf1a00a53": "unregisterListening(address)", "0xb17acdcd": "collectFees(uint256)", "0xb5d0f16e": "getGasScalar(uint256,uint256)", "0xae999ece": "reserve(string)", "0x95ceb4b3": "winningProtocal()", "0x1a93fa4b": "reorganizeSubUsers()", "0x9243e088": "setEnforceRevisions(bytes20)", "0x342454c7": "isDigit(bytes1)", "0x8e2c6f4d": "initiateVerification(address,bytes,bytes)", "0xddb5b3ac": "SellTokens()", "0xd18dfdc9": "parrot(uint256)", "0xd3732642": "FastRealisticPyramid()", "0x37ab8f20": "notifyPlayer(uint256,uint256,uint256,uint256)", "0xfb6e155f": "availableVolume(address,uint256,address,uint256,uint256,uint256,address,uint8,bytes32,bytes32)", "0x50ab6f7f": "getMsgs()", "0x6b6a53fa": "testThrowsRestartNotOwner()", "0x4dc7cc55": "terminateAlt()", "0x8b9726c1": "multiAccessCallD(address,uint256,bytes,address)", "0x5a74dee5": "multiAccessRemoveOwnerD(address,address)", "0xfd339d18": "testAuthorityTryAuthUnauthorized()", "0xd3d6a975": "testThrowsTransferNotEnabled()", "0x8aa001fc": "getSecond(uint256)", "0x2ec2c246": "unregister(address)", "0xbbdb31cb": "challenge(uint256,address,bool)", "0x635cfda2": "Incrementer()", "0x704b6c02": "setAdmin(address)", "0xc1c723f4": "validateProposedMonarchName(bytes)", "0xadf5e565": "verify(bytes,address,uint256,uint8,bytes,bytes)", "0xbe7cddf8": "TwoD()", "0xc71b583b": "closeRequest()", "0x9cbf9e36": "createToken()", "0x69c4113d": "setNewBudget(uint256,uint256,uint256,uint256)", "0xd4649fde": "expire(uint256,uint8,bytes32,bytes32,bytes32)", "0xf9a7a2ef": "named(bytes)", "0xdbf45aa3": "EthBank()", "0xbb3ce7fe": "DepositHolder()", "0xfb5d5729": "getPongvalTransactional()", "0x2f0b15f6": "testGetUnset()", "0x62891b5d": "multiAccessChangeRequirement(uint256)", "0x538e0759": "refill()", "0x24c65f35": "updateRefundGas()", "0x62b24189": "DepositToBankAccountFromDifferentAddress(uint32)", "0xd81f53fd": "EtherId()", "0xcea943ee": "getSaleConfig()", "0x23647398": "testThrowRetractNotOwner()", "0xcdcd77c0": "baz(uint32,bool)", "0xa677fbd9": "example2Func()", "0xa02b9aac": "getPaymentDataByAddress(address)", "0x268eb055": "setDescription(uint64,bytes)", "0x09d2d0b9": "setServiceAccount(address,bool)", "0x5f70d9ac": "getBot(uint256)", "0x63f80de3": "issueCoin(address,uint256,uint256)", "0x8570153e": "publish(string,string,bytes,address[])", "0x7975c56e": "oraclize_query(uint256,string,string)", "0x7c3064f1": "refundStake()", "0xef4ffee2": "Honestgamble()", "0xfdc193a4": "test3Fails()", "0x0eb495c2": "pushCity()", "0x6a357465": "payHours(address,uint256)", "0x93f0bb51": "order(address,uint256,address,uint256,uint256,uint256,uint8,bytes32,bytes32)", "0x0a9254e4": "setUp()", "0xc490a266": "toUInt(bytes)", "0xf666323e": "UUIDProvider()", "0x857d4c07": "throwScraps(uint256)", "0x7fd8ee68": "computeNameHashExt(bytes)", "0x7bd703e8": "getBalanceInEth(address)", "0x68f65f02": "ChangeShownDenomination(bool,bool,bool,bool)", "0xc7f758a8": "getProposal(uint256)", "0x824dbc9a": "changeMembership(address,uint256,bool,string)", "0x2a228fc2": "processWithdrawals()", "0xe0457884": "betResolution(uint8,uint8,uint8,bool)", "0x550538f6": "getOneTimeCosts()", "0xf3e84cf3": "createNewRevision(bytes32,bytes)", "0x77fe38a4": "transferToICAPWithReference(bytes32,uint256,string)", "0xcc189d00": "Vault(address,uint256)", "0x9e281a98": "withdrawToken(address,uint256)", "0x7b12df39": "userProfits()", "0xa843c97f": "attack(uint256,uint256,uint256[])", "0x9da680f3": "adjustRegistrationFee(uint256)", "0x3ea3f6c5": "activateRegistrar()", "0xb36df681": "ExecutableBase()", "0x0f3a1412": "getArrlist(uint256,uint256)", "0x8b7f0ddd": "register(address,address,string,string,bytes32[],uint256,string)", "0xb5d3a379": "CanaryTestnet()", "0x9894221a": "SendCashForHardwareReturn()", "0xc2b12a73": "setBytes32(bytes32)", "0xff1b4341": "easyPropose(address,uint256,uint256)", "0x927ed13a": "newClient(uint256,address)", "0x9b9d0364": "_setFeeStructure(uint256,uint256,uint256)", "0x01518d76": "sendQuery(uint256)", "0x4112b7f1": "tryGetNameOwner(bytes)", "0xb759f954": "approve(uint256)", "0x810a882f": "setConfigBytes(bytes32,bytes32)", "0xea7a7184": "testGetBalanceDb()", "0xb0c8f9dc": "add(string)", "0xe59f611f": "InputLimit(uint256)", "0xdce293a7": "minLength(uint256)", "0xf509b627": "confirm(address,uint224,uint32,address)", "0xd48bfca7": "addToken(address)", "0x044f9ac8": "findThroneCalled(bytes)", "0x1d57bcf7": "ProofLibInterface()", "0x75830463": "checkBetLowhigh(uint8,address,bytes32,bytes32)", "0x2a45a39a": "Post(address)", "0x29cbdc86": "buyin(address,uint256)", "0x3cbfed74": "getBondBalance()", "0x80a23ddf": "mintBadge(int256,address,uint256)", "0x96b76c23": "stand(uint256)", "0xc392f5a0": "getAllPackageReleaseHashes(string)", "0x4847a79c": "_transfer(address,uint256)", "0x905e6e42": "JSON_Test()", "0x9f489e4e": "getDeposit(uint256,address)", "0x4f8e624e": "Greeter(string)", "0x96013c9c": "testLatestPkgGetter()", "0xe4fc6b6d": "distribute()", "0x423d4ef2": "createChannel()", "0x24d7806c": "isAdmin(address)", "0x691fb8ea": "jumpIn()", "0xd50f6bf0": "transferETH(address)", "0xd0e0813a": "promote(address)", "0x528eedcb": "sendSafe(address,address,uint256)", "0x00faf4dd": "getTokenDivisor()", "0x46a1d95f": "closeMarket(bytes)", "0x318a3fee": "relayTx(bytes,int256,int256[],int256,int256)", "0x49d55d9d": "receiveTransfer(uint256)", "0x4fa99dd0": "Matching_Ethers()", "0x99a5d747": "calculateFee(uint256)", "0x3c67c51e": "testLogs()", "0x12ab7242": "setupStackDepthLib(address)", "0xad9ec17e": "setGreyToken()", "0xc37e8cb2": "testExportAuthorized()", "0x43046844": "placeBet(uint8)", "0xc6e1c178": "TheLuckyOne(bytes)", "0x13d1aa2e": "f(uint256,uint256)", "0x64a4a5d7": "testBitsEqualSuccess()", "0xfb1669ca": "setBalance(uint256)", "0x40fdef80": "administration(uint256,string,uint256,uint256,address)", "0xcf7315c6": "retract(bytes20)", "0x76196c88": "setDnsrr(bytes32,bytes)", "0x08bf2d0d": "getOrderBook(uint256,uint256)", "0x021c309a": "solveBet(address,uint8,bool,uint8)", "0x4de162e4": "extractAccountLength()", "0x56fa47f0": "split(address)", "0xb3a0b1ef": "basicInfoGetter()", "0x26066ad5": "offer(uint256,bytes,uint256,bytes)", "0x99c724ef": "skipInLine(uint256,uint256)", "0x838445e8": "EtherAds(address,address,address)", "0xe06174e4": "settings()", "0xfac5bb92": "getPreRelease(bytes32)", "0x93c94acb": "calculateRewards(uint256[3][3])", "0xd7fa1007": "setHash(bytes32,bytes32)", "0x2a714078": "triggerAuth()", "0x4cd995da": "registerCompany(address,string)", "0xf6469342": "_setPackedBlockNumber(bytes32,uint256)", "0x8e7fd292": "trySetSubnodeOwner(bytes32,address)", "0x4f573cb2": "withdrawRevenue()", "0x924c28c1": "ContractInterface(address,address,address)", "0x4fc9c91a": "identityOf(bytes32)", "0x19901f1d": "TokenSale(uint256,uint256)", "0xaf8b7525": "CollectAndReduceFees(uint256)", "0x3ccb7dc9": "CrowdFund(uint256,uint256)", "0xaeeb96af": "Highlander()", "0xa126c5df": "GAS_TO_AUTHORIZE_EXECUTION()", "0x13c89a8f": "getAllowedTime(bytes32)", "0xf38b0600": "fireEventLog3()", "0xc7144269": "changeSettings_only_Dev(uint256,uint256,uint256,uint256,uint16,uint256,uint256,uint256,uint8,uint8)", "0xefc81a8c": "create()", "0x7429c086": "repeat()", "0x9c0a4bbc": "AlwaysFail()", "0xc3d23e10": "checkBet()", "0x28a45038": "testTryProxyCall()", "0xa668d7c9": "NiceGuyPonzi()", "0x06fe1fd7": "getPackageName(bytes32)", "0x29f27577": "InvestorList(uint256)", "0x57e25a79": "PullPaymentCapable()", "0x6d1669e1": "approveAndCall(address,address,uint256,bytes)", "0xa7e93e87": "retractLatestRevision(bytes20)", "0x9c7e8a03": "addParticipant(address,address,uint256)", "0xc6ab4514": "sendRobust(address,uint256,uint256)", "0xe8f6bc2e": "changeAccountLevelsAddr(address)", "0xb5d1990d": "numRecords()", "0x3e853128": "getGasForXau(address)", "0xa1add510": "hasRelation(bytes32,bytes32,address)", "0x31e3e2fe": "WithDraw()", "0x86723215": "createMarket(bytes,uint256,uint256,address)", "0xce845d1d": "currentBalance()", "0xc3a2c0c3": "scheduleCall()", "0xcf8eeb7e": "subBalance(address,uint256)", "0xaeb4f0d3": "RegisterTwo(address,address)", "0x3c716e08": "updateAuthority(address)", "0x9919b1cc": "getContentsByRanks(address,uint256,uint256,uint256)", "0x0f06670a": "didWin(bytes32)", "0x74e4435f": "getUserAddress(uint256,bytes32)", "0x4664b235": "bytes32_to_bytes(bytes,bytes,bytes)", "0x2ac9bf09": "bid(uint256,uint256,uint256)", "0xf11c4482": "approveFromProxy(address,address,uint256)", "0xfe992c98": "balanceOfAll(address)", "0x43e332c5": "Last_block_number_and_blockhash_used()", "0x0066753e": "removeCertifier(address)", "0xd299dac0": "blake2b(bytes,bytes,uint64)", "0x41395efa": "dgxBalance()", "0xac1b14ff": "proxyCall(uint256)", "0x7a6ce2e1": "getMsgSender()", "0x3855dcd6": "getContrarians_by_index(uint256)", "0xe6febc9b": "investorWithdraw(uint256)", "0xe6e91cfc": "voidFailedPayment(uint256)", "0x547eeac1": "acceptTransfer()", "0x9824425a": "takeOrder(uint256,uint256,uint256,uint256)", "0xdf25ee23": "getIndexId(address,bytes)", "0x0f3d7c3e": "release(string,uint32[3],string,string,string)", "0x15cff546": "isOperationBlocked()", "0x0b927666": "order(address,uint256,address,uint256,uint256,uint256)", "0x00ce2057": "triggerPayment()", "0x9a9c29f6": "settle(uint256,uint256)", "0x0f096163": "Chainy()", "0x2f5a5c5b": "timegame()", "0x900d85fa": "updatePreReleaseTree(bytes32)", "0x1cbd0519": "accountLevel(address)", "0x29a065bd": "getLOg(uint256)", "0xcec95aa1": "getReleaseHashForPackage(string,uint256)", "0x41524433": "sellKissBTCWithCallback(uint256,address,uint256)", "0x5e431709": "sealedBids(address,bytes32)", "0xf55b23c0": "externalLeave()", "0x31375242": "ownerSetTreasury(address)", "0x51b42b00": "deactivate()", "0x5af36e3e": "refund(uint256,uint256)", "0xc5096a69": "feeFor(address,address,uint256)", "0x059a500c": "makeDeposit(uint256)", "0x3c2e7d54": "priv_inMainChain__(int256,int256)", "0x9431f5f0": "withdrawFees(bytes)", "0x91b4a0e7": "Difficulty()", "0x268d50fe": "ownerSetHouseEdge(uint256)", "0x9644fcbd": "changeMembership(address,bool,string)", "0x66aa6f26": "payFee(bytes)", "0x353928d8": "helpRed()", "0x9c1193ea": "GreeterA(bytes)", "0xdd79e33e": "splitIdentifiers(string)", "0x4d268ddd": "payImporterBankForGoodsBought()", "0x656d2f63": "ManagedAccount(address)", "0x1216e771": "expiration(uint64)", "0x36f7cd70": "setPricePerStake(uint256)", "0x7842a3a4": "payReward()", "0x0ae50a39": "GetOwner()", "0xc81caae7": "acceptMember(address,string,string)", "0xe50dce71": "testControllerApproveSetsAllowance()", "0x4b64e492": "execute(address)", "0xd9e947f3": "kickOutMember(address)", "0x35cc59a9": "createSchema(bytes)", "0x2530c905": "rand(uint256)", "0x4894e37f": "__callback(bytes,string,bytes)", "0x70480275": "addAdmin(address)", "0x969cb7c3": "getPublisher(uint256)", "0x4ed4831a": "all(bool[7])", "0x2ef3accc": "getPrice(string,uint256)", "0x67854643": "getGenerationMemberLength(uint256)", "0xe6690fb1": "nextAuction(uint256)", "0x5829d310": "entries(int256)", "0x7fe1dc7e": "getToken(bytes)", "0xe7329e71": "scheduleCall(bytes,bytes,uint256,uint256,uint8,uint256)", "0x41c12a70": "voteNo()", "0x6a28db13": "getQrLength()", "0xdd93890b": "setMeta(uint256,bytes32,bytes32)", "0xa48bdb7c": "results()", "0x9d888e86": "currentVersion()", "0xff81fb91": "unhint(int256,bytes32)", "0x9ec32d45": "challengeWinningOutcome(bytes,uint16)", "0xa0a2f629": "setReferralId(uint256,address)", "0x76577eae": "distributeEarnings()", "0x3e5cee05": "issueIOU(string,uint256,address)", "0xf3c7d275": "prenup(string,string,string,string,string,address,address)", "0x7154ae61": "CheckNumbers(uint8[5])", "0x05de4f07": "getContentParent(uint256)", "0xb81e43fc": "getEventName()", "0xa7eeea37": "NewContributor(uint256)", "0xe816a515": "takeFlight()", "0x05b2b03a": "CertificationCentre(address)", "0x74d4ab27": "fipsRegister()", "0x65fa2f7f": "getLastPrice(uint256)", "0xcc8b34ab": "CrowdCoin()", "0xe2b178a0": "getAuthority()", "0x5fb64fd6": "checkMembership(address)", "0x7948f523": "setAmbiAddress(address,bytes32)", "0xebb71194": "withdrawFees(bytes32)", "0x6545bed3": "Dice(uint256,uint256,uint256,uint256,uint256,uint256,uint256)", "0x7065cb48": "addOwner(address)", "0x913f424c": "_ecMul(uint256,uint256,uint256,uint256)", "0xdbecc372": "Example(uint256)", "0x9f7f760c": "SimpleDice()", "0xca94692d": "abiSignature()", "0x61ba3377": "WatchLastTime()", "0x20e647e1": "checkBetColor(uint8,address,bytes32,bytes32)", "0x0a3b0a4f": "add(address)", "0xc51cf179": "calcBaseFeeForShares(uint256)", "0x8baced64": "isInPool(address)", "0x4dc415de": "reject()", "0x1555e337": "ConferenceCertificate()", "0x9555a942": "withdrawFrom(address,address,uint256)", "0xe1efda6d": "airaSend(address,address,uint256)", "0x8bfc2f33": "delegateDAOTokens(uint256)", "0xb964608d": "get_return_by_level(uint256)", "0x0c1fad51": "setSeedSourceA(address)", "0x98688a95": "Ai()", "0xd930a90b": "testFailMoveBalanceDueToInsufficientFunds()", "0x337b5988": "testSimpleNameRegister()", "0xf06d335e": "_recoverAccount(address,address)", "0x025bbbe5": "newSale(bytes16,uint256,uint256)", "0x984413b8": "_eraseNode(bytes32)", "0x5ea187c9": "BuildByteArray(bytes)", "0xc2a95cc9": "updateTrustSettings(address,uint256)", "0xde0ff7c5": "getEther()", "0x4ac7becf": "SimpleSign()", "0x252786e4": "WatchBlockSizeInEther()", "0xf2016a4f": "updateMinEthPerNotification(uint256)", "0xd743ca38": "newWinner(uint256,address,uint256,uint256,uint256)", "0x9eab5253": "getMembers()", "0x51d38d5f": "addDeveloper(address,string)", "0x930ed251": "getSavedVar()", "0x715ef4ff": "resendFailedPayment(uint256)", "0xb1418cf4": "payHouse()", "0xe1569f6b": "testThrowsSetNotRetractableNotOwner()", "0x4ae9af61": "getBotStats(uint256,uint256)", "0xbf8ecf9c": "authProposals()", "0xc00ca383": "getByOwner(address,uint256)", "0xc8e7ca2e": "getMsgData()", "0x711953ef": "setGameAddress(address)", "0x63a8dac2": "changeSettings(uint256,uint256,uint256,uint8,uint256,uint256,uint8,uint8)", "0x72c87075": "testBlockHeaderFetch()", "0x4c7a2254": "checkMyWithdraw()", "0xab91c7b0": "queueLength()", "0x25209260": "PrepareRoll(uint256)", "0x58150c8b": "GameRegistry()", "0x75608264": "get_hash(uint8,bytes32)", "0x6510ef4d": "oraclize_query(uint256,string,string[5])", "0xd57a12f5": "testCheckSigs()", "0x3f415772": "releaseExists(bytes32)", "0xda25c0cd": "ThisExternalAssembly()", "0xf239e528": "sendOneEtherHome()", "0xc4321adb": "investInTheSystem(uint256)", "0x4fab2ca4": "testGetFrontend()", "0x05261aea": "finalize(uint256)", "0x576eac66": "setFundingGoal(uint256)", "0xe75528cc": "buyBuilding(uint256,uint256)", "0x6ed43eb0": "getInvestorList(uint256)", "0xb38415f3": "getConfigBytes(bytes)", "0x771ad635": "getContentCred(address,uint256)", "0x93c166ec": "computeEndowment(uint256,uint256,uint256,uint256)", "0xac35caee": "transferWithReference(address,uint256,string)", "0xc6803622": "wasCalled()", "0x8cfd8901": "_incBlock()", "0xfcf0f55b": "eventOracles(bytes32,uint256)", "0x505ff574": "register(address,uint256,bool)", "0xf824384a": "addInvestorAtID(uint256)", "0x6b9f96ea": "flush()", "0xc3d0a564": "getAccountBalance(bytes)", "0x30fd300f": "registerBytes32(address,bytes32)", "0xc3169ef2": "respond(uint256,uint256[4])", "0xcf1cd249": "secureSend(address)", "0x62c335c1": "checkCallback(address,uint256,bytes,bytes)", "0xb599afc8": "totalBetCount()", "0x69433e12": "setExchange(uint256)", "0x899942b8": "Devcon2Token()", "0x4c2d71b3": "setConfigAddress(bytes32,address)", "0xb974b0a3": "allData()", "0x27e8c2d8": "burnUnicornShares()", "0xf639365d": "testSetGet()", "0x2f5d3916": "testControllerApproveTriggersEvent()", "0x938b5f32": "origin()", "0xd60dcb5d": "Switch()", "0xde629235": "getCertificationDocumentAtIndex(address,uint256)", "0x329ce29e": "buyTile(uint256)", "0x59e2d30e": "testThrowBlobStoreNotRegistered()", "0xa005b87b": "NullMapTest()", "0xc13afa91": "object_locations(uint256)", "0x4848b1a5": "setData(uint256,uint256)", "0x80ede329": "getDocumentDetails(uint256)", "0x35d13969": "SendAllMoney()", "0x8040cac4": "testOverflow()", "0x9507d39a": "get(uint256)", "0xc040e6b8": "stage()", "0x18178358": "poke()", "0xfd782de5": "Proxy()", "0xfd68a422": "returnmoneycreator(uint8,uint128)", "0x86a50535": "voteFor(uint256)", "0x44602a7d": "testFallbackReturn()", "0xa230c524": "isMember(address)", "0x3ffbd47f": "register(string,string)", "0x8cecf66e": "_inverse(uint256)", "0x51017702": "isOutcomeSet(bytes32)", "0xd408746a": "GetContractAddr()", "0x20130753": "testThrowSetNotRetractableNotOwner()", "0xa0e2abf7": "getFirstActiveGamble()", "0x7c582304": "updateInvestmentTotal(address,uint256)", "0x95d89b41": "symbol()", "0x1768b436": "ETCSurvey()", "0x6d4ce63c": "get()", "0xc41a360a": "getOwner(uint256)", "0x49942ccb": "scheduleCall(bytes,bytes,uint256,uint256)", "0x6b64c769": "startAuction()", "0x084d72f4": "getWinningOutcome(uint256)", "0xd379be23": "claimer()", "0x41fa4876": "multiBlockRandomGen(uint256,uint256)", "0x5bc7e259": "updateRelease(uint32,uint32,uint32,bytes,bool)", "0x47f3d794": "configure(uint256,uint8,uint256,uint256,uint256,uint256)", "0xe2bbb158": "deposit(uint256,uint256)", "0x953a7fab": "testMoveBalance()", "0xeacc5b3b": "safeSend(address,uint256,uint256)", "0x96f0aa8f": "findNextSecond(uint256,bytes)", "0xc8690233": "pubkey(bytes32)", "0x459f93f7": "getBuyers(uint256,address)", "0xf714de9c": "MultiAccess()", "0xf4a81d08": "getKudosGiven(address)", "0x5aa94a68": "computeResultVoteExtraInvestFeesRate()", "0xdb2a0cb7": "HumanStandardTokenFactory()", "0xdf3a6b10": "testMemberAddedEvent()", "0xce8d054e": "_setupNoCallback()", "0x8ea822d8": "createThings(bytes32[],uint16[],bytes32[],uint16[],uint88)", "0x24fb563f": "PlayerTickets(address,uint256,uint256)", "0x8c0e156d": "scheduleCall(bytes4,uint256,uint256)", "0xef04fdb7": "buyShares(bytes,uint8,uint256,uint256)", "0xa0afd731": "dividendBalance(address)", "0xc3c95c7b": "getMarket(bytes32)", "0x94ed9b77": "append(address,address)", "0xc87b36ed": "disableBetting()", "0x566735d8": "PreVNK(uint256,string,string,uint8)", "0x400aae08": "isInCurrentGeneration(address)", "0x44dd4b5e": "scheduleTransaction(address,uint256,bytes)", "0x48c54b9d": "claimTokens()", "0xe8930efd": "Investors(address)", "0xa6f2ae3a": "buy()", "0x12819817": "setXauForGasCurrator(address)", "0x056e1059": "oraclize_query(uint256,string,string,uint256)", "0x7824407f": "tokenSupply()", "0x7f0c949c": "setJurisdication(string)", "0x2e817963": "set_sdl(address)", "0xaee84f6b": "setTime(address,uint256)", "0x3c0dde1c": "_addPools(address,address)", "0xf8bd526e": "setCoinageContract(address)", "0x04b07a5e": "removeUpdater(address)", "0x11149ada": "getProof(uint256)", "0x4306cc3f": "queryEarnings(address)", "0x55241077": "setValue(uint256)", "0x492b67ea": "Etherdoc()", "0xadf59f99": "query(uint256,string,string)", "0x951b01c5": "setCertifierDb(address)", "0x8ae986cf": "registrantApprove(address)", "0xfa68b4ce": "lookupISO3116_1_alpha_3(bytes)", "0x7fdc8290": "isUnderscore(bytes1)", "0x89495172": "convictFinal(uint256,uint256)", "0x93e02d13": "FallenLeaders()", "0x3e476053": "moveFunds(address,uint256)", "0x8894dd2b": "addEther()", "0x8f03850b": "numContributors()", "0xbfc3cd2f": "testFailChargeMoreThanApproved()", "0x1d82e9c7": "EXTRA_GAS()", "0x278ecde1": "refund(uint256)", "0x0f825673": "deleteCoupon(string)", "0xa324ad24": "getMonth(uint256)", "0xd628e0a6": "WatchBalance()", "0xb238ad0e": "getDaysInMonth(uint8,uint16)", "0xd6febde8": "buy(uint256,uint256)", "0x370ec1c5": "_fillOrder(address,uint256)", "0x4c33fe94": "cancel(address)", "0xcdd13701": "getEventHashes(uint256[256])", "0xe1bc3003": "reveal(bytes,string)", "0xa2e62045": "update()", "0x75f45878": "scheduleCall(bytes,bytes,uint256)", "0xd2756e11": "finalizeNumber(uint256)", "0x48519189": "MonedaAlcala(string,string)", "0x009b9369": "getVoteNumber(uint256)", "0xdaa283c8": "__callback(bytes,string)", "0xfcce2622": "challengeAnswer(uint256,bytes)", "0xac18de43": "removeManager(address)", "0x16d9356f": "oraclize_query(string,string[4])", "0xd1734eac": "isInNextGeneration(address)", "0x524fa7b9": "whitelistAdd(address)", "0xa5eb7a4e": "operated()", "0xb0aab296": "getNextNode(bytes)", "0x1982ed58": "ChangeReuseCashInHarware(bool,uint16,uint16)", "0xdf811d7d": "numberOfPlayersInCurrentRound()", "0xca7dc5b1": "getNumberOfTweets()", "0x488b3538": "shares(address,bytes32,int256)", "0xebd83378": "get_blocks_for(uint256)", "0x399fdb86": "testFailNormalWhitelistReset()", "0xca0c1e62": "computeMerkle(int256,int256,int256[],int256,int256,int256[])", "0x8963dab4": "getNodeId(bytes,bytes)", "0x7d94792a": "seed()", "0xbcf175c8": "oraclize_cbAddress()", "0x38eee93e": "scheduleCall(address,bytes,bytes,uint16,uint8,uint256[5])", "0xa08d3f83": "Etheropt(uint256,string,uint256,uint256,bytes32,address,int256[])", "0xae47a290": "changeMaxBet(uint256)", "0xd12c1e28": "badgesOf(address)", "0x001f8d11": "removePackage(bytes32,string)", "0x54fd4d50": "version()", "0x89abeb19": "ProcessGameExt(uint256)", "0x3dd7c1b9": "newProduct(string,string,uint256,uint256)", "0xa396541e": "getPongvalTxRetrievalAttempted()", "0xcc8af0fe": "bytesToUInt(bytes,bytes)", "0x983b94fb": "finalizeAuction(bytes32)", "0x3df91162": "getUpdatable(bytes20)", "0x045236b4": "getChainyData(string)", "0x9c172f87": "EthVentures4()", "0x996a4be3": "uintToBytes(uint256,uint256)", "0x775a8f5e": "toBytes(uint256)", "0xb6db75a0": "isAdmin()", "0x0b6fcdb0": "getEnforceRevisions(bytes32)", "0x29d6f899": "BetOnBlue()", "0xe6cbcba9": "PlusOnePonzi()", "0xc9030ea0": "addMember(address,bool)", "0x8f283970": "changeAdmin(address)", "0x670c884e": "setup(address,uint256,uint256,uint256,address)", "0x808ab1d6": "getCertificationDbCount()", "0x018f5472": "isAUser(address)", "0x59c87d70": "request(bytes32)", "0x407cfe5e": "get_all_players()", "0x33f472b9": "MPO()", "0x662dbe96": "getNodeHeight(bytes)", "0x60b1e173": "getProof(uint256,address,address)", "0xf25eb5c1": "removeReverse()", "0x1d065dde": "_transferWithReward(address,address,uint256)", "0x65343fcb": "TrustEth()", "0xaa237e21": "set(bool,uint256)", "0x60e519c0": "computeMarginAmount()", "0xd9597016": "multisetCustomGasPrice(uint256[],address[])", "0x4f10acc1": "updateGoldFeeData(uint256)", "0x1e9ea66a": "balanceEther10000000(uint256)", "0xffe34512": "getNumChannels(address)", "0x71dd8862": "IndexOf()", "0xdd9dd688": "calcStopPrice()", "0x934354e7": "finishSpin()", "0x26881518": "setupFee(address)", "0x5eb3f639": "assertTrue(bool,bytes)", "0xe9540395": "getRewardDivisor()", "0x8e4afa51": "checkTransferToICAP(bytes32,uint256)", "0xb5b33eda": "scheduleCall(address,uint256)", "0x3d6a32bd": "createTradeContract(address,uint256,uint256,uint256,bool,bool)", "0x5fd9dff6": "allowance(address,address,bytes)", "0x0d244d68": "setNotRetractable(bytes32)", "0xe63697c8": "withdraw(uint256,address,uint256)", "0x3e5087cc": "testBasicThing()", "0xee77fe86": "scheduleCall(address,bytes4,bytes,uint256,uint256,uint8)", "0xb1cc4348": "placeWager()", "0xb95594e5": "lineOfPlayers(uint256)", "0xa9cc4718": "fail()", "0x54385526": "setStatus(uint8,uint8,string)", "0xb45c48dc": "Security_AddPasswordSha3HashToBankAccount(bytes)", "0xace51abc": "helperVerifyHash__(uint256,int256,int256[],int256,uint256,int256,int256[],int256)", "0x1f5d0b4c": "address(address,address,uint256)", "0x7acbfb65": "setOwner(uint256,uint256)", "0x3462f32d": "execWithGasLimit(bytes32,bytes32,uint256,uint256)", "0xac04f5a7": "append(address)", "0x2fcb6628": "_stringGas(string,string)", "0xe977992d": "Doubler()", "0xc57a050e": "fairandeasy()", "0x412664ae": "sendToken(address,uint256)", "0x0afa9fb9": "contains(int256,address)", "0xb69ef8a8": "balance()", "0x264c8e9a": "whatWasTheVal()", "0x255016c8": "checkIfExploded()", "0xd716222c": "is_owner(uint256,address)", "0xc398f030": "expire(uint256,uint8,bytes,bytes,bytes)", "0xb7d454a4": "setNotTransferable(bytes32)", "0x4789aaef": "EthereumDice()", "0xc0171112": "timestamp(uint64)", "0x4f60f334": "multiAccessAddOwner(address)", "0x80aed05f": "LooneyDice()", "0x55ba343f": "getMarket(bytes)", "0x943b0747": "RewardOffer(address,address,bytes,uint256,uint256,uint128,uint256)", "0xa27c672a": "owner_reveal_and_commit(uint8,bytes32,bytes32)", "0x8f731077": "extractAllowanceRecordLength(address)", "0xc3d345c4": "getHangoutAddress()", "0xa8978434": "softResolveAnswer(uint256)", "0x7cef6047": "getNavHistory(uint256)", "0xfae14192": "changeFeePercentage(uint256)", "0x2ddbc04a": "play2(address,uint256)", "0x3fb27b85": "seal()", "0xe8038e25": "TokenSale(uint256,uint256,address)", "0x8d92fdf3": "withdrawAsset(uint256)", "0x8579cbde": "getPrice(string,uint256,address)", "0x0d61b519": "executeProposal(uint256)", "0x63a599a4": "emergencyStop()", "0x661e3605": "ConstructorContract(uint256)", "0xfd7c460d": "ciberLottery()", "0x1f83f440": "getPaymentByAddress(address)", "0xdcf73856": "generateGroups()", "0x3c6e03d7": "thewhalegame()", "0x271cd760": "getPackageDb()", "0x53fefd7d": "changeMaxDeposit(uint256)", "0xae169a50": "claimReward(uint256)", "0x6da84ec0": "calcMarketFee(bytes32,uint256)", "0xb16562fe": "fipsRegister(address,bytes)", "0x041fe13d": "onEtherandomSeed(bytes32,bytes32)", "0x4a617faa": "shaBid(bytes32,uint256,bytes32)", "0x052b2aa7": "getRegistrants()", "0x0ff0a4df": "reFund()", "0xe56b9dce": "GetPrize(uint256)", "0x8eec99c8": "setNewAdmin(address)", "0xffcce369": "changeIPFSHash(string)", "0x40fdf515": "issuetender(address,uint256,uint256)", "0xef4bdfdd": "Set_your_game_number_between_1_15(string)", "0xa991cb0e": "respond(uint256)", "0x617fba04": "getRecord(address)", "0x475a9fa9": "issueTokens(address,uint256)", "0xd30fbd0d": "safeSubtract(uint256,uint256)", "0xe54d4051": "receiveInteger(bytes,uint256,uint16)", "0x8023ffbd": "getOverallSize()", "0x8390b02a": "rfindPtr(uint256,uint256,uint256,uint256)", "0x11e99c22": "arrival()", "0x10c1952f": "setLocked()", "0x039a21b8": "tryExecute(address,bytes,uint256)", "0x201dcd7a": "newChallenge(uint256,uint256)", "0x5aebfd14": "createFile(bytes)", "0xa6b1caa3": "gasScalar(uint256)", "0x200538c6": "DTE()", "0xd1738b72": "wroomWroom()", "0x22f607f6": "Escrow()", "0x7e81b6aa": "KingdomFactory()", "0x901d7775": "voteOutMasterKey(address)", "0xd6af9411": "Rouleth()", "0x7b0383b2": "initializeDispute(uint256)", "0x70c9edb7": "BTCRelayTools(address)", "0xe9c31315": "checkBetParity(uint8,address,bytes32,bytes32)", "0xee82ac5e": "getBlockHash(uint256)", "0x727089f1": "extractAllowanceLength()", "0x8bbb5af7": "test1Fails()", "0x47872b42": "unsealBid(bytes32,uint256,bytes32)", "0x46b04e53": "PlayerInfoPerZone(uint256,uint256)", "0x752bacce": "getExecPrice()", "0x89d8ca67": "drawPot(bytes32,bytes32)", "0xc23697a8": "check(address)", "0x0af658ca": "personUpdateActivity(uint256,bool)", "0x24d4e90a": "ln(uint256)", "0x09d33f1d": "addRequest(address,uint256)", "0xc913b552": "getVersions(bytes)", "0xbb3b8dca": "getCertificateHash(bytes)", "0x3809c0bf": "doInfinite()", "0x853552d7": "_slotAddNew(address)", "0xccf1ab9b": "usurpation()", "0xe7dafdb6": "transfer_token(address,address,uint256)", "0x0c77a697": "claimFounders()", "0xda82a035": "sweepCommission()"} \ No newline at end of file diff --git a/cmd/clef/README.md b/cmd/clef/README.md new file mode 100644 index 0000000000..036e71b286 --- /dev/null +++ b/cmd/clef/README.md @@ -0,0 +1,991 @@ +Clef +---- +Clef can be used to sign transactions and data and is meant as a replacement for geth's account management. +This allows DApps not to depend on geth's account management. When a DApp wants to sign data it can send the data to +the signer, the signer will then provide the user with context and asks the user for permission to sign the data. If +the users grants the signing request the signer will send the signature back to the DApp. + +This setup allows a DApp to connect to a remote Ethereum node and send transactions that are locally signed. This can +help in situations when a DApp is connected to a remote node because a local Ethereum node is not available, not +synchronised with the chain or a particular Ethereum node that has no built-in (or limited) account management. + +Clef can run as a daemon on the same machine, or off a usb-stick like [usb armory](https://inversepath.com/usbarmory), +or a separate VM in a [QubesOS](https://www.qubes-os.org/) type os setup. + +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: +``` +COMMANDS: + init Initialize the signer, generate secret storage + attest Attest that a js-file is to be used + 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") + --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 (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 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 + +``` + + +Example: +``` +signer -keystore /my/keystore -chainid 4 +``` + + +## Security model + +The security model of the signer is as follows: + +* One critical component (the signer binary / daemon) is responsible for handling cryptographic operations: signing, private keys, encryption/decryption of keystore files. +* The signer binary has a well-defined 'external' API. +* The 'external' API is considered UNTRUSTED. +* The signer binary also communicates with whatever process that invoked the binary, via stdin/stdout. + * This channel is considered 'trusted'. Over this channel, approvals and passwords are communicated. + +The general flow for signing a transaction using e.g. geth is as follows: +![image](sign_flow.png) + +In this case, `geth` would be started with `--externalsigner=http://localhost:8550` and would relay requests to `eth.sendTransaction`. + +## TODOs + +Some snags and todos + +* [ ] The signer should take a startup param "--no-change", for UIs that do not contain the capability + to perform changes to things, only approve/deny. Such a UI should be able to start the signer in + a more secure mode by telling it that it only wants approve/deny capabilities. + +* [x] It would be nice if the signer could collect new 4byte-id:s/method selectors, and have a +secondary database for those (`4byte_custom.json`). Users could then (optionally) submit their collections for +inclusion upstream. + +* It should be possible to configure the signer to check if an account is indeed known to it, before +passing on to the UI. The reason it currently does not, is that it would make it possible to enumerate +accounts if it immediately returned "unknown account". +* [x] It should be possible to configure the signer to auto-allow listing (certain) accounts, instead of asking every time. +* [x] Done Upon startup, the signer should spit out some info to the caller (particularly important when executed in `stdio-ui`-mode), +invoking methods with the following info: + * [x] Version info about the signer + * [x] Address of API (http/ipc) + * [ ] List of known accounts +* [ ] Have a default timeout on signing operations, so that if the user has not answered within e.g. 60 seconds, the request is rejected. +* [ ] `account_signRawTransaction` +* [ ] `account_bulkSignTransactions([] transactions)` should + * only exist if enabled via config/flag + * only allow non-data-sending transactions + * all txs must use the same `from`-account + * let the user confirm, showing + * the total amount + * the number of unique recipients + +* Geth todos + - The signer should pass the `Origin` header as call-info to the UI. As of right now, the way that info about the request is +put together is a bit of a hack into the http server. This could probably be greatly improved + - Relay: Geth should be started in `geth --external_signer localhost:8550`. + - Currently, the Geth APIs use `common.Address` in the arguments to transaction submission (e.g `to` field). This + type is 20 `bytes`, and is incapable of carrying checksum information. The signer uses `common.MixedcaseAddress`, which + retains the original input. + - The Geth api should switch to use the same type, and relay `to`-account verbatim to the external api. + +* [x] Storage + * [x] An encrypted key-value storage should be implemented + * See [rules.md](rules.md) for more info about this. + +* Another potential thing to introduce is pairing. + * To prevent spurious requests which users just accept, implement a way to "pair" the caller with the signer (external API). + * Thus geth/mist/cpp would cryptographically handshake and afterwards the caller would be allowed to make signing requests. + * This feature would make the addition of rules less dangerous. + +* Wallets / accounts. Add API methods for wallets. + +## Communication + +### External API + +The signer listens to HTTP requests on `rpcaddr`:`rpcport`, with the same JSONRPC standard as Geth. The messages are +expected to be JSON [jsonrpc 2.0 standard](http://www.jsonrpc.org/specification). + +Some of these call can require user interaction. Clients must be aware that responses +may be delayed significantly or may never be received if a users decides to ignore the confirmation request. + +The External API is **untrusted** : it does not accept credentials over this api, nor does it expect +that requests have any authority. + +### UI API + +The signer has one native console-based UI, for operation without any standalone tools. +However, there is also an API to communicate with an external UI. To enable that UI, +the signer needs to be executed with the `--stdio-ui` option, which allocates the +`stdin`/`stdout` for the UI-api. + +An example (insecure) proof-of-concept of has been implemented in `pythonsigner.py`. + +The model is as follows: + +* The user starts the UI app (`pythonsigner.py`). +* The UI app starts the `signer` with `--stdio-ui`, and listens to the +process output for confirmation-requests. +* The `signer` opens the external http api. +* When the `signer` receives requests, it sends a `jsonrpc` request via `stdout`. +* The UI app prompts the user accordingly, and responds to the `signer` +* The `signer` signs (or not), and responds to the original request. + +## External API + +See the [external api changelog](extapi_changelog.md) for information about changes to this API. + +### Encoding +- number: positive integers that are hex encoded +- data: hex encoded data +- string: ASCII string + +All hex encoded values must be prefixed with `0x`. + +## Methods + +### account_new + +#### Create new password protected account + +The signer will generate a new private key, encrypts it according to [web3 keystore spec](https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition) and stores it in the keystore directory. +The client is responsible for creating a backup of the keystore. If the keystore is lost there is no method of retrieving lost accounts. + +#### Arguments + +None + +#### Result + - address [string]: account address that is derived from the generated key + - url [string]: location of the keyfile + +#### Sample call +```json +{ + "id": 0, + "jsonrpc": "2.0", + "method": "account_new", + "params": [] +} +``` +Response +``` +{ + "id": 0, + "jsonrpc": "2.0", + "result": { + "address": "0xbea9183f8f4f03d427f6bcea17388bdff1cab133", + "url": "keystore:///my/keystore/UTC--2017-08-24T08-40-15.419655028Z--bea9183f8f4f03d427f6bcea17388bdff1cab133" + } +} +``` + +### account_list + +#### List available accounts + List all accounts that this signer currently manages + +#### Arguments + +None + +#### Result + - array with account records: + - account.address [string]: account address that is derived from the generated key + - account.type [string]: type of the + - account.url [string]: location of the account + +#### Sample call +```json +{ + "id": 1, + "jsonrpc": "2.0", + "method": "account_list" +} +``` +Response +``` +{ + "id": 1, + "jsonrpc": "2.0", + "result": [ + { + "address": "0xafb2f771f58513609765698f65d3f2f0224a956f", + "type": "account", + "url": "keystore:///tmp/keystore/UTC--2017-08-24T07-26-47.162109726Z--afb2f771f58513609765698f65d3f2f0224a956f" + }, + { + "address": "0xbea9183f8f4f03d427f6bcea17388bdff1cab133", + "type": "account", + "url": "keystore:///tmp/keystore/UTC--2017-08-24T08-40-15.419655028Z--bea9183f8f4f03d427f6bcea17388bdff1cab133" + } + ] +} +``` + +### account_signTransaction + +#### Sign transactions + Signs a transactions and responds with the signed transaction in RLP encoded form. + +#### Arguments + 2. transaction object: + - `from` [address]: account to send the transaction from + - `to` [address]: receiver account. If omitted or `0x`, will cause contract creation. + - `gas` [number]: maximum amount of gas to burn + - `gasPrice` [number]: gas price + - `value` [number:optional]: amount of Wei to send with the transaction + - `data` [data:optional]: input data + - `nonce` [number]: account nonce + 3. method signature [string:optional] + - The method signature, if present, is to aid decoding the calldata. Should consist of `methodname(paramtype,...)`, e.g. `transfer(uint256,address)`. The signer may use this data to parse the supplied calldata, and show the user. The data, however, is considered totally untrusted, and reliability is not expected. + + +#### Result + - signed transaction in RLP encoded form [data] + +#### Sample call +```json +{ + "id": 2, + "jsonrpc": "2.0", + "method": "account_signTransaction", + "params": [ + { + "from": "0x1923f626bb8dc025849e00f99c25fe2b2f7fb0db", + "gas": "0x55555", + "gasPrice": "0x1234", + "input": "0xabcd", + "nonce": "0x0", + "to": "0x07a565b7ed7d7a678680a4c162885bedbb695fe0", + "value": "0x1234" + } + ] +} +``` +Response + +```json +{ + "id": 2, + "jsonrpc": "2.0", + "error": { + "code": -32000, + "message": "Request denied" + } +} +``` +#### Sample call with ABI-data + + +```json +{ + "id": 67, + "jsonrpc": "2.0", + "method": "account_signTransaction", + "params": [ + { + "from": "0x694267f14675d7e1b9494fd8d72fefe1755710fa", + "gas": "0x333", + "gasPrice": "0x1", + "nonce": "0x0", + "to": "0x07a565b7ed7d7a678680a4c162885bedbb695fe0", + "value": "0x0", + "data": "0x4401a6e40000000000000000000000000000000000000000000000000000000000000012" + }, + "safeSend(address)" + ] +} +``` +Response + +```json +{ + "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" + } + } +} +``` + +Bash example: +```bash +#curl -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/ + +{"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_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 [object]: data to sign + +#### Result + - calculated signature [data] + +#### Sample call +```json +{ + "id": 3, + "jsonrpc": "2.0", + "method": "account_signData", + "params": [ + "data/plain", + "0x1923f626bb8dc025849e00f99c25fe2b2f7fb0db", + "0xaabbccdd" + ] +} +``` +Response + +```json +{ + "id": 3, + "jsonrpc": "2.0", + "result": "0x5b6693f153b48ec1c706ba4169960386dbaa6903e249cc79a8e6ddc434451d417e1e57327872c7f538beeb323c300afa9999a3d4a5de6caf3be0d5ef832b67ef1c" +} +``` + +### 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 + +#### 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 + +#### Result + - derived account [address] + +#### Sample call +```json +{ + "id": 4, + "jsonrpc": "2.0", + "method": "account_ecRecover", + "params": [ + "data/plain", + "0xaabbccdd", + "0x5b6693f153b48ec1c706ba4169960386dbaa6903e249cc79a8e6ddc434451d417e1e57327872c7f538beeb323c300afa9999a3d4a5de6caf3be0d5ef832b67ef1c" + ] +} +``` +Response + +```json +{ + "id": 4, + "jsonrpc": "2.0", + "result": "0x1923f626bb8dc025849e00f99c25fe2b2f7fb0db" +} +``` + +### account_import + +#### Import account + Import a private key into the keystore. The imported key is expected to be encrypted according to the web3 keystore + format. + +#### Arguments + - account [object]: key in [web3 keystore format](https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition) (retrieved with account_export) + +#### Result + - imported key [object]: + - key.address [address]: address of the imported key + - key.type [string]: type of the account + - key.url [string]: key URL + +#### Sample call +```json +{ + "id": 6, + "jsonrpc": "2.0", + "method": "account_import", + "params": [ + { + "address": "c7412fc59930fd90099c917a50e5f11d0934b2f5", + "crypto": { + "cipher": "aes-128-ctr", + "cipherparams": { + "iv": "401c39a7c7af0388491c3d3ecb39f532" + }, + "ciphertext": "eb045260b18dd35cd0e6d99ead52f8fa1e63a6b0af2d52a8de198e59ad783204", + "kdf": "scrypt", + "kdfparams": { + "dklen": 32, + "n": 262144, + "p": 1, + "r": 8, + "salt": "9a657e3618527c9b5580ded60c12092e5038922667b7b76b906496f021bb841a" + }, + "mac": "880dc10bc06e9cec78eb9830aeb1e7a4a26b4c2c19615c94acb632992b952806" + }, + "id": "09bccb61-b8d3-4e93-bf4f-205a8194f0b9", + "version": 3 + } + ] +} +``` +Response + +```json +{ + "id": 6, + "jsonrpc": "2.0", + "result": { + "address": "0xc7412fc59930fd90099c917a50e5f11d0934b2f5", + "type": "account", + "url": "keystore:///tmp/keystore/UTC--2017-08-24T11-00-42.032024108Z--c7412fc59930fd90099c917a50e5f11d0934b2f5" + } +} +``` + +### account_export + +#### Export account from keystore + Export a private key from the keystore. The exported private key is encrypted with the original passphrase. When the + key is imported later this passphrase is required. + +#### Arguments + - account [address]: export private key that is associated with this account + +#### Result + - exported key, see [web3 keystore format](https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition) for + more information + +#### Sample call +```json +{ + "id": 5, + "jsonrpc": "2.0", + "method": "account_export", + "params": [ + "0xc7412fc59930fd90099c917a50e5f11d0934b2f5" + ] +} +``` +Response + +```json +{ + "id": 5, + "jsonrpc": "2.0", + "result": { + "address": "c7412fc59930fd90099c917a50e5f11d0934b2f5", + "crypto": { + "cipher": "aes-128-ctr", + "cipherparams": { + "iv": "401c39a7c7af0388491c3d3ecb39f532" + }, + "ciphertext": "eb045260b18dd35cd0e6d99ead52f8fa1e63a6b0af2d52a8de198e59ad783204", + "kdf": "scrypt", + "kdfparams": { + "dklen": 32, + "n": 262144, + "p": 1, + "r": 8, + "salt": "9a657e3618527c9b5580ded60c12092e5038922667b7b76b906496f021bb841a" + }, + "mac": "880dc10bc06e9cec78eb9830aeb1e7a4a26b4c2c19615c94acb632992b952806" + }, + "id": "09bccb61-b8d3-4e93-bf4f-205a8194f0b9", + "version": 3 + } +} +``` + + + +## UI API + +These methods needs to be implemented by a UI listener. + +By starting the signer with the switch `--stdio-ui-test`, the signer will invoke all known methods, and expect the UI to respond with +denials. This can be used during development to ensure that the API is (at least somewhat) correctly implemented. +See `pythonsigner`, which can be invoked via `python3 pythonsigner.py test` to perform the 'denial-handshake-test'. + +All methods in this API uses object-based parameters, so that there can be no mixups of parameters: each piece of data is accessed by key. + +See the [ui api changelog](intapi_changelog.md) for information about changes to this API. + +OBS! A slight deviation from `json` standard is in place: every request and response should be confined to a single line. +Whereas the `json` specification allows for linebreaks, linebreaks __should not__ be used in this communication channel, to make +things simpler for both parties. + +### ApproveTx + +Invoked when there's a transaction for approval. + + +#### Sample call + +Here's a method invocation: +```bash + +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/ +``` + +```json + +{ + "jsonrpc": "2.0", + "id": 1, + "method": "ApproveTx", + "params": [ + { + "transaction": { + "from": "0x0x694267f14675d7e1b9494fd8d72fefe1755710fa", + "to": "0x0x07a565b7ed7d7a678680a4c162885bedbb695fe0", + "gas": "0x333", + "gasPrice": "0x1", + "value": "0x0", + "nonce": "0x0", + "data": "0x4401a6e40000000000000000000000000000000000000000000000000000000000000012", + "input": null + }, + "call_info": [ + { + "type": "WARNING", + "message": "Invalid checksum on to-address" + }, + { + "type": "Info", + "message": "safeSend(address: 0x0000000000000000000000000000000000000012)" + } + ], + "meta": { + "remote": "127.0.0.1:48486", + "local": "localhost:8550", + "scheme": "HTTP/1.1" + } + } + ] +} + +``` + +The same method invocation, but with invalid data: +```bash + +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":"0x4401a6e40000000000000002000000000000000000000000000000000000000000000012"},"safeSend(address)"],"id":67}' http://localhost:8550/ +``` + +```json + +{ + "jsonrpc": "2.0", + "id": 1, + "method": "ApproveTx", + "params": [ + { + "transaction": { + "from": "0x0x694267f14675d7e1b9494fd8d72fefe1755710fa", + "to": "0x0x07a565b7ed7d7a678680a4c162885bedbb695fe0", + "gas": "0x333", + "gasPrice": "0x1", + "value": "0x0", + "nonce": "0x0", + "data": "0x4401a6e40000000000000002000000000000000000000000000000000000000000000012", + "input": null + }, + "call_info": [ + { + "type": "WARNING", + "message": "Invalid checksum on to-address" + }, + { + "type": "WARNING", + "message": "Transaction data did not match ABI-interface: WARNING: Supplied data is stuffed with extra data. \nWant 0000000000000002000000000000000000000000000000000000000000000012\nHave 0000000000000000000000000000000000000000000000000000000000000012\nfor method safeSend(address)" + } + ], + "meta": { + "remote": "127.0.0.1:48492", + "local": "localhost:8550", + "scheme": "HTTP/1.1" + } + } + ] +} + + +``` + +One which has missing `to`, but with no `data`: + + +```json + +{ + "jsonrpc": "2.0", + "id": 3, + "method": "ApproveTx", + "params": [ + { + "transaction": { + "from": "", + "to": null, + "gas": "0x0", + "gasPrice": "0x0", + "value": "0x0", + "nonce": "0x0", + "data": null, + "input": null + }, + "call_info": [ + { + "type": "CRITICAL", + "message": "Tx will create contract with empty code!" + } + ], + "meta": { + "remote": "signer binary", + "local": "main", + "scheme": "in-proc" + } + } + ] +} +``` + +### 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 + +Invoked when a request for account listing has been made. + +#### Sample call + +```json + +{ + "jsonrpc": "2.0", + "id": 5, + "method": "ApproveListing", + "params": [ + { + "accounts": [ + { + "type": "Account", + "url": "keystore:///home/bazonk/.ethereum/keystore/UTC--2017-11-20T14-44-54.089682944Z--123409812340981234098123409812deadbeef42", + "address": "0x123409812340981234098123409812deadbeef42" + }, + { + "type": "Account", + "url": "keystore:///home/bazonk/.ethereum/keystore/UTC--2017-11-23T21-59-03.199240693Z--cafebabedeadbeef34098123409812deadbeef42", + "address": "0xcafebabedeadbeef34098123409812deadbeef42" + } + ], + "meta": { + "remote": "signer binary", + "local": "main", + "scheme": "in-proc" + } + } + ] +} + +``` + + +### ApproveSignData + +#### Sample call + +```json +{ + "jsonrpc": "2.0", + "id": 4, + "method": "ApproveSignData", + "params": [ + { + "address": "0x123409812340981234098123409812deadbeef42", + "raw_data": "0x01020304", + "message": "\u0019Ethereum Signed Message:\n4\u0001\u0002\u0003\u0004", + "hash": "0x7e3a4e7a9d1744bc5c675c25e1234ca8ed9162bd17f78b9085e48047c15ac310", + "meta": { + "remote": "signer binary", + "local": "main", + "scheme": "in-proc" + } + } + ] +} + +``` + +### ShowInfo + +The UI should show the info to the user. Does not expect response. + +#### Sample call + +```json +{ + "jsonrpc": "2.0", + "id": 9, + "method": "ShowInfo", + "params": [ + { + "text": "Tests completed" + } + ] +} + +``` + +### ShowError + +The UI should show the info to the user. Does not expect response. + +```json + +{ + "jsonrpc": "2.0", + "id": 2, + "method": "ShowError", + "params": [ + { + "text": "Testing 'ShowError'" + } + ] +} + +``` + +### OnApproved + +`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. + +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 + +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. + +Example call: +```json + +{ + "jsonrpc": "2.0", + "id": 1, + "method": "OnSignerStartup", + "params": [ + { + "info": { + "extapi_http": "http://localhost:8550", + "extapi_ipc": null, + "extapi_version": "2.0.0", + "intapi_version": "1.2.0" + } + } + ] +} + +``` + + +### Rules for UI apis + +A UI should conform to the following rules. + +* A UI MUST NOT load any external resources that were not embedded/part of the UI package. + * For example, not load icons, stylesheets from the internet + * Not load files from the filesystem, unless they reside in the same local directory (e.g. config files) +* A Graphical UI MUST show the blocky-identicon for ethereum addresses. +* A UI MUST warn display approproate warning if the destination-account is formatted with invalid checksum. +* A UI MUST NOT open any ports or services + * The signer opens the public port +* A UI SHOULD verify the permissions on the signer binary, and refuse to execute or warn if permissions allow non-user write. +* A UI SHOULD inform the user about the `SHA256` or `MD5` hash of the binary being executed +* A UI SHOULD NOT maintain a secondary storage of data, e.g. list of accounts + * The signer provides accounts +* A UI SHOULD, to the best extent possible, use static linking / bundling, so that required libraries are bundled +along with the UI. + + +### UI Implementations + +There are a couple of implementation for a UI. We'll try to keep this list up to date. + +| Name | Repo | UI type| No external resources| Blocky support| Verifies permissions | Hash information | No secondary storage | Statically linked| Can modify parameters| +| ---- | ---- | -------| ---- | ---- | ---- |---- | ---- | ---- | ---- | +| QtSigner| https://github.com/holiman/qtsigner/| Python3/QT-based| :+1:| :+1:| :+1:| :+1:| :+1:| :x: | :+1: (partially)| +| GtkSigner| https://github.com/holiman/gtksigner| Python3/GTK-based| :+1:| :x:| :x:| :+1:| :+1:| :x: | :x: | +| Frame | https://github.com/floating/frame/commits/go-signer| Electron-based| :x:| :x:| :x:| :x:| ?| :x: | :x: | +| Clef UI| https://github.com/kyokan/clef-ui| Golang/QT-based| :+1:| :+1:| :x:| :+1:| :+1:| :x: | :+1: (approve tx only)| diff --git a/cmd/clef/datatypes.md b/cmd/clef/datatypes.md new file mode 100644 index 0000000000..e345a2bbd5 --- /dev/null +++ b/cmd/clef/datatypes.md @@ -0,0 +1,219 @@ +## 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, + "Password": "apassword" +} +``` +### SignDataResponse - deny + +Response to SignDataRequest + +Example: +```json +{ + "approved": false, + "Password": "" +} +``` +### 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" + } +} +``` +### SignDataResponse - approve + +Response to SignDataRequest. 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, + "password": "apassword" +} +``` +### SignDataResponse - deny + +Response to SignDataRequest. When denying a request, there's no need to provide the transaction in return + +Example: +```json +{ + "approved": false, + "Password": "" +} +``` +### 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 SignDataRequest + +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" + } +} +``` +### UserInputResponse + +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/cmd/clef/docs/clef_architecture_pt1.png b/cmd/clef/docs/clef_architecture_pt1.png new file mode 100644 index 0000000000..e40e532f30 Binary files /dev/null and b/cmd/clef/docs/clef_architecture_pt1.png differ diff --git a/cmd/clef/docs/clef_architecture_pt2.png b/cmd/clef/docs/clef_architecture_pt2.png new file mode 100644 index 0000000000..f617d755e2 Binary files /dev/null and b/cmd/clef/docs/clef_architecture_pt2.png differ diff --git a/cmd/clef/docs/clef_architecture_pt3.png b/cmd/clef/docs/clef_architecture_pt3.png new file mode 100644 index 0000000000..b9d6954473 Binary files /dev/null and b/cmd/clef/docs/clef_architecture_pt3.png differ diff --git a/cmd/clef/docs/clef_architecture_pt4.png b/cmd/clef/docs/clef_architecture_pt4.png new file mode 100644 index 0000000000..a6cb3b4df2 Binary files /dev/null and b/cmd/clef/docs/clef_architecture_pt4.png differ diff --git a/cmd/clef/docs/qubes/clef_qubes_http.png b/cmd/clef/docs/qubes/clef_qubes_http.png new file mode 100644 index 0000000000..e95ad8da4a Binary files /dev/null and b/cmd/clef/docs/qubes/clef_qubes_http.png differ diff --git a/cmd/clef/docs/qubes/clef_qubes_qrexec.png b/cmd/clef/docs/qubes/clef_qubes_qrexec.png new file mode 100644 index 0000000000..b1814e7c36 Binary files /dev/null and b/cmd/clef/docs/qubes/clef_qubes_qrexec.png differ diff --git a/cmd/clef/docs/qubes/qrexec-example.png b/cmd/clef/docs/qubes/qrexec-example.png new file mode 100644 index 0000000000..fc5d57725d Binary files /dev/null and b/cmd/clef/docs/qubes/qrexec-example.png differ diff --git a/cmd/clef/docs/qubes/qubes-client.py b/cmd/clef/docs/qubes/qubes-client.py new file mode 100644 index 0000000000..93a74b899b --- /dev/null +++ b/cmd/clef/docs/qubes/qubes-client.py @@ -0,0 +1,23 @@ +""" +This implements a dispatcher which listens to localhost:8550, and proxies +requests via qrexec to the service qubes.EthSign on a target domain +""" + +import http.server +import socketserver,subprocess + +PORT=8550 +TARGET_DOMAIN= 'debian-work' + +class Dispatcher(http.server.BaseHTTPRequestHandler): + def do_POST(self): + post_data = self.rfile.read(int(self.headers['Content-Length'])) + p = subprocess.Popen(['/usr/bin/qrexec-client-vm',TARGET_DOMAIN,'qubes.Clefsign'],stdin=subprocess.PIPE, stdout=subprocess.PIPE) + output = p.communicate(post_data)[0] + self.wfile.write(output) + + +with socketserver.TCPServer(("",PORT), Dispatcher) as httpd: + print("Serving at port", PORT) + httpd.serve_forever() + diff --git a/cmd/clef/docs/qubes/qubes.Clefsign b/cmd/clef/docs/qubes/qubes.Clefsign new file mode 100644 index 0000000000..9b5af7b4fe --- /dev/null +++ b/cmd/clef/docs/qubes/qubes.Clefsign @@ -0,0 +1,16 @@ +#!/bin/bash + +SIGNER_BIN="/home/user/tools/clef/clef" +SIGNER_CMD="/home/user/tools/gtksigner/gtkui.py -s $SIGNER_BIN" + +# Start clef if not already started +if [ ! -S /home/user/.clef/clef.ipc ]; then + $SIGNER_CMD & + sleep 1 +fi + +# Should be started by now +if [ -S /home/user/.clef/clef.ipc ]; then + # Post incoming request to HTTP channel + curl -H "Content-Type: application/json" -X POST -d @- http://localhost:8550 2>/dev/null +fi diff --git a/cmd/clef/docs/qubes/qubes_newaccount-1.png b/cmd/clef/docs/qubes/qubes_newaccount-1.png new file mode 100644 index 0000000000..3bfc8b5b7e Binary files /dev/null and b/cmd/clef/docs/qubes/qubes_newaccount-1.png differ diff --git a/cmd/clef/docs/qubes/qubes_newaccount-2.png b/cmd/clef/docs/qubes/qubes_newaccount-2.png new file mode 100644 index 0000000000..c6dbd535dd Binary files /dev/null and b/cmd/clef/docs/qubes/qubes_newaccount-2.png differ diff --git a/cmd/clef/docs/setup.md b/cmd/clef/docs/setup.md new file mode 100644 index 0000000000..33d2b0381f --- /dev/null +++ b/cmd/clef/docs/setup.md @@ -0,0 +1,198 @@ +# Setting up Clef + +This document describes how Clef can be used in a more secure manner than executing it from your everyday laptop, +in order to ensure that the keys remain safe in the event that your computer should get compromised. + +## Qubes OS + + +### Background + +The Qubes operating system is based around virtual machines (qubes), where a set of virtual machines are configured, typically for +different purposes such as: + +- personal + - Your personal email, browsing etc +- work + - Work email etc +- vault + - a VM without network access, where gpg-keys and/or keepass credentials are stored. + +A couple of dedicated virtual machines handle externalities: + +- sys-net provides networking to all other (network-enabled) machines +- sys-firewall handles firewall rules +- sys-usb handles USB devices, and can map usb-devices to certain qubes. + +The goal of this document is to describe how we can set up clef to provide secure transaction +signing from a `vault` vm, to another networked qube which runs Dapps. + +### Setup + +There are two ways that this can be achieved: integrated via Qubes or integrated via networking. + + +#### 1. Qubes Integrated + +Qubes provdes a facility for inter-qubes communication via `qrexec`. A qube can request to make a cross-qube RPC request +to another qube. The OS then asks the user if the call is permitted. + +![Example](qubes/qrexec-example.png) + +A policy-file can be created to allow such interaction. On the `target` domain, a service is invoked which can read the +`stdin` from the `client` qube. + +This is how [Split GPG](https://www.qubes-os.org/doc/split-gpg/) is implemented. We can set up Clef the same way: + +##### Server + +![Clef via qrexec](qubes/clef_qubes_qrexec.png) + +On the `target` qubes, we need to define the rpc service. + +[qubes.Clefsign](qubes/qubes.Clefsign): + +```bash +#!/bin/bash + +SIGNER_BIN="/home/user/tools/clef/clef" +SIGNER_CMD="/home/user/tools/gtksigner/gtkui.py -s $SIGNER_BIN" + +# Start clef if not already started +if [ ! -S /home/user/.clef/clef.ipc ]; then + $SIGNER_CMD & + sleep 1 +fi + +# Should be started by now +if [ -S /home/user/.clef/clef.ipc ]; then + # Post incoming request to HTTP channel + curl -H "Content-Type: application/json" -X POST -d @- http://localhost:8550 2>/dev/null +fi + +``` +This RPC service is not complete (see notes about HTTP headers below), but works as a proof-of-concept. +It will forward the data received on `stdin` (forwarded by the OS) to Clef's HTTP channel. + +It would have been possible to send data directly to the `/home/user/.clef/.clef.ipc` +socket via e.g `nc -U /home/user/.clef/clef.ipc`, but the reason for sending the request +data over `HTTP` instead of `IPC` is that we want the ability to forward `HTTP` headers. + +To enable the service: + +``` bash +sudo cp qubes.Clefsign /etc/qubes-rpc/ +sudo chmod +x /etc/qubes-rpc/ qubes.Clefsign +``` + +This setup uses [gtksigner](https://github.com/holiman/gtksigner), which is a very minimal GTK-based UI that works well +with minimal requirements. + +##### Client + + +On the `client` qube, we need to create a listener which will receive the request from the Dapp, and proxy it. + + +[qubes-client.py](qubes/client/qubes-client.py): + +```python + +""" +This implements a dispatcher which listens to localhost:8550, and proxies +requests via qrexec to the service qubes.EthSign on a target domain +""" + +import http.server +import socketserver,subprocess + +PORT=8550 +TARGET_DOMAIN= 'debian-work' + +class Dispatcher(http.server.BaseHTTPRequestHandler): + def do_POST(self): + post_data = self.rfile.read(int(self.headers['Content-Length'])) + p = subprocess.Popen(['/usr/bin/qrexec-client-vm',TARGET_DOMAIN,'qubes.Clefsign'],stdin=subprocess.PIPE, stdout=subprocess.PIPE) + output = p.communicate(post_data)[0] + self.wfile.write(output) + + +with socketserver.TCPServer(("",PORT), Dispatcher) as httpd: + print("Serving at port", PORT) + httpd.serve_forever() + + +``` + +#### Testing + +To test the flow, if we have set up `debian-work` as the `target`, we can do + +```bash +$ cat newaccnt.json +{ "id": 0, "jsonrpc": "2.0","method": "account_new","params": []} + +$ cat newaccnt.json| qrexec-client-vm debian-work qubes.Clefsign +``` + +This should pop up first a dialog to allow the IPC call: + +![one](qubes/qubes_newaccount-1.png) + +Followed by a GTK-dialog to approve the operation + +![two](qubes/qubes_newaccount-2.png) + +To test the full flow, we use the client wrapper. Start it on the `client` qube: +``` +[user@work qubes]$ python3 qubes-client.py +``` + +Make the request over http (`client` qube): +``` +[user@work clef]$ cat newaccnt.json | curl -X POST -d @- http://localhost:8550 +``` +And it should show the same popups again. + +##### Pros and cons + +The benefits of this setup are: + +- This is the qubes-os intended model for inter-qube communication, +- and thus benefits from qubes-os dialogs and policies for user approval + +However, it comes with a couple of drawbacks: + +- The `qubes-gpg-client` must forward the http request via RPC to the `target` qube. When doing so, the proxy + will either drop important headers, or replace them. + - The `Host` header is most likely `localhost` + - The `Origin` header must be forwarded + - Information about the remote ip must be added as a `X-Forwarded-For`. However, Clef cannot always trust an `XFF` header, + since malicious clients may lie about `XFF` in order to fool the http server into believing it comes from another address. +- Even with a policy in place to allow rpc-calls between `caller` and `target`, there will be several popups: + - One qubes-specific where the user specifies the `target` vm + - One clef-specific to approve the transaction + + +#### 2. Network integrated + +The second way to set up Clef on a qubes system is to allow networking, and have Clef listen to a port which is accessible +form other qubes. + +![Clef via http](qubes/clef_qubes_http.png) + + + + +## USBArmory + +The [USB armory](https://inversepath.com/usbarmory) is an open source hardware design with an 800 Mhz ARM processor. It is a pocket-size +computer. When inserted into a laptop, it identifies itself as a USB network interface, basically adding another network +to your computer. Over this new network interface, you can SSH into the device. + +Running Clef off a USB armory means that you can use the armory as a very versatile offline computer, which only +ever connects to a local network between your computer and the device itself. + +Needless to say, the while this model should be fairly secure against remote attacks, an attacker with physical access +to the USB Armory would trivially be able to extract the contents of the device filesystem. + diff --git a/cmd/clef/extapi_changelog.md b/cmd/clef/extapi_changelog.md new file mode 100644 index 0000000000..dc7e65c01b --- /dev/null +++ b/cmd/clef/extapi_changelog.md @@ -0,0 +1,47 @@ +### 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. +* The external `account_Import`-method was removed. + +#### 3.0.0 + +* The external `account_List`-method was changed to not expose `url`, which contained info about the local filesystem. It now returns only a list of addresses. + +#### 2.0.0 + +* Commit `73abaf04b1372fa4c43201fb1b8019fe6b0a6f8d`, move `from` into `transaction` object in `signTransaction`. This +makes the `accounts_signTransaction` identical to the old `eth_signTransaction`. + + +#### 1.0.0 + +Initial release. + +### Versioning + +The API uses [semantic versioning](https://semver.org/). + +TLDR; Given a version number MAJOR.MINOR.PATCH, increment the: + +* MAJOR version when you make incompatible API changes, +* MINOR version when you add functionality in a backwards-compatible manner, and +* PATCH version when you make backwards-compatible bug fixes. + +Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format. diff --git a/cmd/clef/intapi_changelog.md b/cmd/clef/intapi_changelog.md new file mode 100644 index 0000000000..db3353bb7d --- /dev/null +++ b/cmd/clef/intapi_changelog.md @@ -0,0 +1,140 @@ +### Changelog for internal API (ui-api) + +### 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 + +### 2.1.0 + +* Add `OnInputRequired(info UserInputRequest)` to internal API. This method is used when Clef needs user input, e.g. passwords. + +The following structures are used: +```golang + UserInputRequest struct { + Prompt string `json:"prompt"` + Title string `json:"title"` + IsPassword bool `json:"isPassword"` + } + UserInputResponse struct { + Text string `json:"text"` + } + +### 2.0.0 + +* Modify how `call_info` on a transaction is conveyed. New format: + +``` +{ + "jsonrpc": "2.0", + "id": 2, + "method": "ApproveTx", + "params": [ + { + "transaction": { + "from": "0x82A2A876D39022B3019932D30Cd9c97ad5616813", + "to": "0x07a565b7ed7d7a678680a4c162885bedbb695fe0", + "gas": "0x333", + "gasPrice": "0x123", + "value": "0x10", + "nonce": "0x0", + "data": "0x4401a6e40000000000000000000000000000000000000000000000000000000000000012", + "input": null + }, + "call_info": [ + { + "type": "WARNING", + "message": "Invalid checksum on to-address" + }, + { + "type": "WARNING", + "message": "Tx contains data, but provided ABI signature could not be matched: Did not match: test (0 matches)" + } + ], + "meta": { + "remote": "127.0.0.1:54286", + "local": "localhost:8550", + "scheme": "HTTP/1.1" + } + } + ] +} +``` + +#### 1.2.0 + +* Add `OnStartup` method, to provide the UI with information about what API version +the signer uses (both internal and external) aswell as build-info and external api. + +Example call: +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "OnSignerStartup", + "params": [ + { + "info": { + "extapi_http": "http://localhost:8550", + "extapi_ipc": null, + "extapi_version": "2.0.0", + "intapi_version": "1.2.0" + } + } + ] +} +``` + +#### 1.1.0 + +* Add `OnApproved` method + +#### 1.0.0 + +Initial release. + +### Versioning + +The API uses [semantic versioning](https://semver.org/). + +TLDR; Given a version number MAJOR.MINOR.PATCH, increment the: + +* MAJOR version when you make incompatible API changes, +* MINOR version when you add functionality in a backwards-compatible manner, and +* PATCH version when you make backwards-compatible bug fixes. + +Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format. diff --git a/cmd/clef/main.go b/cmd/clef/main.go new file mode 100644 index 0000000000..088701eeee --- /dev/null +++ b/cmd/clef/main.go @@ -0,0 +1,932 @@ +// 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 . + +// signer is a utility that can be used so sign transactions and +// arbitrary data. +package main + +import ( + "bufio" + "context" + "crypto/rand" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "math/big" + "os" + "os/signal" + "os/user" + "path/filepath" + "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" + "github.com/ethereum/go-ethereum/signer/storage" + "gopkg.in/urfave/cli.v1" +) + +const legalWarning = ` +WARNING! + +Clef is alpha software, and not yet publically released. This software has _not_ been audited, and there +are no guarantees about the workings of this software. It may contain severe flaws. You should not use this software +unless you agree to take full responsibility for doing so, and know what you are doing. + +TLDR; THIS IS NOT PRODUCTION-READY SOFTWARE! + +` + +var ( + logLevelFlag = cli.IntFlag{ + Name: "loglevel", + Value: 4, + Usage: "log level to emit to the screen", + } + advancedMode = cli.BoolFlag{ + Name: "advanced", + Usage: "If enabled, issues warnings instead of rejections for suspicious requests. Default off", + } + keystoreFlag = cli.StringFlag{ + Name: "keystore", + Value: filepath.Join(node.DefaultDataDir(), "keystore"), + Usage: "Directory for the keystore", + } + configdirFlag = cli.StringFlag{ + Name: "configdir", + 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", + Value: node.DefaultHTTPPort + 5, + } + signerSecretFlag = cli.StringFlag{ + Name: "signersecret", + Usage: "A file containing the (encrypted) master seed to encrypt Clef data, e.g. keystore credentials and ruleset hash", + } + dBFlag = cli.StringFlag{ + Name: "4bytedb", + Usage: "File containing 4byte-identifiers", + Value: "./4byte.json", + } + customDBFlag = cli.StringFlag{ + Name: "4bytedb-custom", + Usage: "File used for writing new 4byte-identifiers submitted via API", + Value: "./4byte-custom.json", + } + auditLogFlag = cli.StringFlag{ + Name: "auditlog", + Usage: "File used to emit audit logs. Set to \"\" to disable", + Value: "audit.log", + } + ruleFlag = cli.StringFlag{ + Name: "rules", + Usage: "Enable rule-engine", + Value: "rules.json", + } + stdiouiFlag = cli.BoolFlag{ + Name: "stdio-ui", + Usage: "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.", + } + testFlag = cli.BoolFlag{ + Name: "stdio-ui-test", + Usage: "Mechanism to test interface between Clef and UI. Requires 'stdio-ui'.", + } + app = cli.NewApp() + initCommand = cli.Command{ + Action: utils.MigrateFlags(initializeSecrets), + Name: "init", + Usage: "Initialize the signer, generate secret storage", + ArgsUsage: "", + Flags: []cli.Flag{ + logLevelFlag, + configdirFlag, + }, + Description: ` +The init command generates a master seed which Clef can use to store credentials and data needed for +the rule-engine to work.`, + } + attestCommand = cli.Command{ + Action: utils.MigrateFlags(attestFile), + Name: "attest", + Usage: "Attest that a js-file is to be used", + ArgsUsage: "", + Flags: []cli.Flag{ + logLevelFlag, + configdirFlag, + signerSecretFlag, + }, + Description: ` +The attest command stores the sha256 of the rule.js-file that you want to use for automatic processing of +incoming requests. + +Whenever you make an edit to the rule file, you need to use attestation to tell +Clef that the file is 'safe' to execute.`, + } + + setCredentialCommand = cli.Command{ + Action: utils.MigrateFlags(setCredential), + Name: "setpw", + Usage: "Store a credential for a keystore file", + ArgsUsage: "
", + Flags: []cli.Flag{ + logLevelFlag, + configdirFlag, + signerSecretFlag, + }, + Description: ` +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() { + app.Name = "Clef" + app.Usage = "Manage Ethereum account operations" + app.Flags = []cli.Flag{ + logLevelFlag, + keystoreFlag, + configdirFlag, + chainIdFlag, + utils.LightKDFFlag, + utils.NoUSBFlag, + utils.RPCListenAddrFlag, + utils.RPCVirtualHostsFlag, + utils.IPCDisabledFlag, + utils.IPCPathFlag, + utils.RPCEnabledFlag, + rpcPortFlag, + signerSecretFlag, + dBFlag, + customDBFlag, + auditLogFlag, + ruleFlag, + stdiouiFlag, + testFlag, + advancedMode, + } + app.Action = signer + app.Commands = []cli.Command{initCommand, attestCommand, setCredentialCommand, gendocCommand} + +} +func main() { + if err := app.Run(os.Args); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +func initializeSecrets(c *cli.Context) error { + if err := initialize(c); err != nil { + return err + } + configDir := c.GlobalString(configdirFlag.Name) + + masterSeed := make([]byte, 256) + num, err := io.ReadFull(rand.Reader, masterSeed) + if err != nil { + return err + } + if num != len(masterSeed) { + return fmt.Errorf("failed to read enough random") + } + + n, p := keystore.StandardScryptN, keystore.StandardScryptP + if c.GlobalBool(utils.LightKDFFlag.Name) { + n, p = keystore.LightScryptN, keystore.LightScryptP + } + text := "The master seed of clef is locked with a password. Please give a password. Do not forget this password." + var password string + for { + password = getPassPhrase(text, true) + if err := core.ValidatePasswordFormat(password); err != nil { + fmt.Printf("invalid password: %v\n", err) + } else { + break + } + } + cipherSeed, err := encryptSeed(masterSeed, []byte(password), n, p) + if err != nil { + return fmt.Errorf("failed to encrypt master seed: %v", err) + } + + err = os.Mkdir(configDir, 0700) + if err != nil && !os.IsExist(err) { + return err + } + location := filepath.Join(configDir, "masterseed.json") + if _, err := os.Stat(location); err == nil { + return fmt.Errorf("file %v already exists, will not overwrite", location) + } + err = ioutil.WriteFile(location, cipherSeed, 0400) + if err != nil { + return err + } + fmt.Printf("A master seed has been generated into %s\n", location) + fmt.Printf(` +This is required to be able to store credentials, such as : +* Passwords for keystores (used by rule engine) +* Storage for javascript rules +* Hash of rule-file + +You should treat that file with utmost secrecy, and make a backup of it. +NOTE: This file does not contain your accounts. Those need to be backed up separately! + +`) + return nil +} +func attestFile(ctx *cli.Context) error { + if len(ctx.Args()) < 1 { + utils.Fatalf("This command requires an argument.") + } + if err := initialize(ctx); err != nil { + return err + } + + stretchedKey, err := readMasterKey(ctx, nil) + if err != nil { + utils.Fatalf(err.Error()) + } + configDir := ctx.GlobalString(configdirFlag.Name) + vaultLocation := filepath.Join(configDir, common.Bytes2Hex(crypto.Keccak256([]byte("vault"), stretchedKey)[:10])) + confKey := crypto.Keccak256([]byte("config"), stretchedKey) + + // Initialize the encrypted storages + configStorage := storage.NewAESEncryptedStorage(filepath.Join(vaultLocation, "config.json"), confKey) + val := ctx.Args().First() + configStorage.Put("ruleset_sha256", val) + log.Info("Ruleset attestation updated", "sha256", val) + return nil +} + +func setCredential(ctx *cli.Context) error { + if len(ctx.Args()) < 1 { + utils.Fatalf("This command requires an address to be passed as an argument.") + } + if err := initialize(ctx); err != nil { + return err + } + + address := ctx.Args().First() + password := getPassPhrase("Enter a passphrase to store with this address.", true) + + stretchedKey, err := readMasterKey(ctx, nil) + if err != nil { + utils.Fatalf(err.Error()) + } + configDir := ctx.GlobalString(configdirFlag.Name) + vaultLocation := filepath.Join(configDir, common.Bytes2Hex(crypto.Keccak256([]byte("vault"), stretchedKey)[:10])) + pwkey := crypto.Keccak256([]byte("credentials"), stretchedKey) + + // Initialize the encrypted storages + pwStorage := storage.NewAESEncryptedStorage(filepath.Join(vaultLocation, "credentials.json"), pwkey) + pwStorage.Put(address, password) + log.Info("Credential store updated", "key", address) + return nil +} + +func initialize(c *cli.Context) error { + // Set up the logger to print everything + logOutput := os.Stdout + if c.GlobalBool(stdiouiFlag.Name) { + logOutput = os.Stderr + // If using the stdioui, we can't do the 'confirm'-flow + fmt.Fprintf(logOutput, legalWarning) + } else { + if !confirm(legalWarning) { + return fmt.Errorf("aborted by user") + } + } + + log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(c.Int(logLevelFlag.Name)), log.StreamHandler(logOutput, log.TerminalFormat(true)))) + return nil +} + +func signer(c *cli.Context) error { + if err := initialize(c); err != nil { + return err + } + var ( + ui core.UIClientAPI + ) + if c.GlobalBool(stdiouiFlag.Name) { + log.Info("Using stdin/stdout as UI-channel") + ui = core.NewStdIOUI() + } else { + log.Info("Using CLI as UI-channel") + ui = core.NewCommandlineUI() + } + fourByteDb := c.GlobalString(dBFlag.Name) + fourByteLocal := c.GlobalString(customDBFlag.Name) + db, err := core.NewAbiDBFromFiles(fourByteDb, fourByteLocal) + if err != nil { + utils.Fatalf(err.Error()) + } + log.Info("Loaded 4byte db", "signatures", db.Size(), "file", fourByteDb, "local", fourByteLocal) + + var ( + api core.ExternalAPI + ) + + 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 + pwkey := crypto.Keccak256([]byte("credentials"), stretchedKey) + jskey := crypto.Keccak256([]byte("jsstorage"), stretchedKey) + confkey := crypto.Keccak256([]byte("config"), stretchedKey) + + // Initialize the encrypted storages + 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) + } else { + // Initialize rules + ruleEngine, err := rules.NewRuleEvaluator(ui, jsStorage, pwStorage) + if err != nil { + utils.Fatalf(err.Error()) + } + 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) + + // 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 != "" { + api, err = core.NewAuditLogger(logfile, api) + if err != nil { + utils.Fatalf(err.Error()) + } + log.Info("Audit logs configured", "file", logfile) + } + // register signer API with server + var ( + extapiURL = "n/a" + ipcapiURL = "n/a" + ) + rpcAPI := []rpc.API{ + { + Namespace: "account", + Public: true, + Service: api, + Version: "1.0"}, + } + if c.GlobalBool(utils.RPCEnabledFlag.Name) { + + vhosts := splitAndTrim(c.GlobalString(utils.RPCVirtualHostsFlag.Name)) + cors := splitAndTrim(c.GlobalString(utils.RPCCORSDomainFlag.Name)) + + // start http server + httpEndpoint := fmt.Sprintf("%s:%d", c.GlobalString(utils.RPCListenAddrFlag.Name), c.Int(rpcPortFlag.Name)) + listener, _, err := rpc.StartHTTPEndpoint(httpEndpoint, rpcAPI, []string{"account"}, cors, vhosts, rpc.DefaultHTTPTimeouts) + if err != nil { + utils.Fatalf("Could not start RPC api: %v", err) + } + extapiURL = fmt.Sprintf("http://%s", httpEndpoint) + log.Info("HTTP endpoint opened", "url", extapiURL) + + defer func() { + listener.Close() + log.Info("HTTP endpoint closed", "url", httpEndpoint) + }() + + } + if !c.GlobalBool(utils.IPCDisabledFlag.Name) { + if c.IsSet(utils.IPCPathFlag.Name) { + ipcapiURL = c.GlobalString(utils.IPCPathFlag.Name) + } else { + ipcapiURL = filepath.Join(configDir, "clef.ipc") + } + + listener, _, err := rpc.StartIPCEndpoint(ipcapiURL, rpcAPI) + if err != nil { + utils.Fatalf("Could not start IPC api: %v", err) + } + log.Info("IPC endpoint opened", "url", ipcapiURL) + defer func() { + listener.Close() + log.Info("IPC endpoint closed", "url", ipcapiURL) + }() + + } + + if c.GlobalBool(testFlag.Name) { + log.Info("Performing UI test") + go testExternalUI(apiImpl) + } + ui.OnSignerStartup(core.StartupInfo{ + Info: map[string]interface{}{ + "extapi_version": core.ExternalAPIVersion, + "intapi_version": core.InternalAPIVersion, + "extapi_http": extapiURL, + "extapi_ipc": ipcapiURL, + }, + }) + + abortChan := make(chan os.Signal) + signal.Notify(abortChan, os.Interrupt) + + sig := <-abortChan + log.Info("Exiting...", "signal", sig) + + return nil +} + +// splitAndTrim splits input separated by a comma +// and trims excessive white space from the substrings. +func splitAndTrim(input string) []string { + result := strings.Split(input, ",") + for i, r := range result { + result[i] = strings.TrimSpace(r) + } + return result +} + +// DefaultConfigDir is the default config directory to use for the vaults and other +// persistence requirements. +func DefaultConfigDir() string { + // Try to place the data folder in the user's home dir + home := homeDir() + if home != "" { + if runtime.GOOS == "darwin" { + return filepath.Join(home, "Library", "Signer") + } else if runtime.GOOS == "windows" { + 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") + } + } + // As we cannot guess a stable location, return empty and handle later + return "" +} + +func homeDir() string { + if home := os.Getenv("HOME"); home != "" { + return home + } + if usr, err := user.Current(); err == nil { + return usr.HomeDir + } + return "" +} +func readMasterKey(ctx *cli.Context, ui core.UIClientAPI) ([]byte, error) { + var ( + file string + configDir = ctx.GlobalString(configdirFlag.Name) + ) + if ctx.GlobalIsSet(signerSecretFlag.Name) { + file = ctx.GlobalString(signerSecretFlag.Name) + } else { + file = filepath.Join(configDir, "masterseed.json") + } + if err := checkFile(file); err != nil { + return nil, err + } + cipherKey, err := ioutil.ReadFile(file) + if err != nil { + return nil, err + } + var password string + // If ui is not nil, get the password from ui. + if ui != nil { + resp, err := ui.OnInputRequired(core.UserInputRequest{ + Title: "Master Password", + Prompt: "Please enter the password to decrypt the master seed", + IsPassword: true}) + if err != nil { + return nil, err + } + password = resp.Text + } else { + password = getPassPhrase("Decrypt master seed of clef", false) + } + masterSeed, err := decryptSeed(cipherKey, password) + if err != nil { + return nil, fmt.Errorf("failed to decrypt the master seed of clef") + } + if len(masterSeed) < 256 { + return nil, fmt.Errorf("master seed of insufficient length, expected >255 bytes, got %d", len(masterSeed)) + } + + // Create vault location + vaultLocation := filepath.Join(configDir, common.Bytes2Hex(crypto.Keccak256([]byte("vault"), masterSeed)[:10])) + err = os.Mkdir(vaultLocation, 0700) + if err != nil && !os.IsExist(err) { + return nil, err + } + return masterSeed, nil +} + +// checkFile is a convenience function to check if a file +// * exists +// * is mode 0400 +func checkFile(filename string) error { + info, err := os.Stat(filename) + if err != nil { + return fmt.Errorf("failed stat on %s: %v", filename, err) + } + // Check the unix permission bits + if info.Mode().Perm()&0377 != 0 { + return fmt.Errorf("file (%v) has insecure file permissions (%v)", filename, info.Mode().String()) + } + return nil +} + +// confirm displays a text and asks for user confirmation +func confirm(text string) bool { + fmt.Printf(text) + fmt.Printf("\nEnter 'ok' to proceed:\n>") + + text, err := bufio.NewReader(os.Stdin).ReadString('\n') + if err != nil { + log.Crit("Failed to read user input", "err", err) + } + + if text := strings.TrimSpace(text); text == "ok" { + return true + } + return false +} + +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'") + + checkErr := func(method string, err error) { + if err != nil && err != core.ErrRequestDenied { + errs = append(errs, fmt.Sprintf("%v: %v", method, err.Error())) + } + } + var err error + + 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, err := common.NewMixedcaseAddressFromString("0x0011223344556677889900112233445566778899") + if err != nil { + utils.Fatalf("Should not error: %v", err) + } + _, err = api.SignData(ctx, "application/clique", *addr, cliqueRlp) + checkErr("SignData", err) + + _, err = api.SignTransaction(ctx, core.SendTxArgs{From: common.MixedcaseAddress{}}, nil) + checkErr("SignTransaction", err) + _, err = api.SignData(ctx, "text/plain", common.MixedcaseAddress{}, common.Hex2Bytes("01020304")) + checkErr("SignData", err) + //_, err = api.SignTypedData(ctx, common.MixedcaseAddress{}, core.TypedData{}) + //checkErr("SignTypedData", err) + _, err = api.List(ctx) + checkErr("List", err) + _, err = api.New(ctx) + checkErr("New", err) + + api.UI.ShowInfo("Tests completed") + + if len(errs) > 0 { + log.Error("Got errors") + for _, e := range errs { + log.Error(e) + } + } else { + log.Info("No errors") + } +} + +// getPassPhrase retrieves the password associated with clef, either fetched +// from a list of preloaded passphrases, or requested interactively from the user. +// TODO: there are many `getPassPhrase` functions, it will be better to abstract them into one. +func getPassPhrase(prompt string, confirmation bool) string { + fmt.Println(prompt) + password, err := console.Stdin.PromptPassword("Passphrase: ") + if err != nil { + utils.Fatalf("Failed to read passphrase: %v", err) + } + if confirmation { + confirm, err := console.Stdin.PromptPassword("Repeat passphrase: ") + if err != nil { + utils.Fatalf("Failed to read passphrase confirmation: %v", err) + } + if password != confirm { + utils.Fatalf("Passphrases do not match") + } + } + return password +} + +type encryptedSeedStorage struct { + Description string `json:"description"` + Version int `json:"version"` + Params keystore.CryptoJSON `json:"params"` +} + +// encryptSeed uses a similar scheme as the keystore uses, but with a different wrapping, +// to encrypt the master seed +func encryptSeed(seed []byte, auth []byte, scryptN, scryptP int) ([]byte, error) { + cryptoStruct, err := keystore.EncryptDataV3(seed, auth, scryptN, scryptP) + if err != nil { + return nil, err + } + return json.Marshal(&encryptedSeedStorage{"Clef seed", 1, cryptoStruct}) +} + +// decryptSeed decrypts the master seed +func decryptSeed(keyjson []byte, auth string) ([]byte, error) { + var encSeed encryptedSeedStorage + if err := json.Unmarshal(keyjson, &encSeed); err != nil { + return nil, err + } + if encSeed.Version != 1 { + log.Warn(fmt.Sprintf("unsupported encryption format of seed: %d, operation will likely fail", encSeed.Version)) + } + seed, err := keystore.DecryptDataV3(encSeed.Params, auth) + if err != nil { + return nil, err + } + 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{Password: "apassword", 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("SignDataResponse - approve", "Response to SignDataRequest. This response needs to contain the `transaction`"+ + ", because the UI is free to make modifications to the transaction.", + &core.SignTxResponse{Password: "apassword", 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("SignDataResponse - deny", "Response to SignDataRequest. When denying a request, there's no need to "+ + "provide the transaction in return", + &core.SignDataResponse{}) + } + { // 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 SignDataRequest", + &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("UserInputResponse", "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 + +curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"account_new","params":["test"],"id":67}' localhost:8550 + +// List accounts + +curl -i -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"account_list","params":[""],"id":67}' http://localhost:8550/ + +// Make Transaction +// safeSend(0x12) +// 4401a6e40000000000000000000000000000000000000000000000000000000000000012 + +// supplied abi +curl -i -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"account_signTransaction","params":[{"from":"0x82A2A876D39022B3019932D30Cd9c97ad5616813","gas":"0x333","gasPrice":"0x123","nonce":"0x0","to":"0x07a565b7ed7d7a678680a4c162885bedbb695fe0", "value":"0x10", "data":"0x4401a6e40000000000000000000000000000000000000000000000000000000000000012"},"test"],"id":67}' http://localhost:8550/ + +// Not supplied +curl -i -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"account_signTransaction","params":[{"from":"0x82A2A876D39022B3019932D30Cd9c97ad5616813","gas":"0x333","gasPrice":"0x123","nonce":"0x0","to":"0x07a565b7ed7d7a678680a4c162885bedbb695fe0", "value":"0x10", "data":"0x4401a6e40000000000000000000000000000000000000000000000000000000000000012"}],"id":67}' http://localhost:8550/ + +// Sign data + +curl -i -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"account_sign","params":["0x694267f14675d7e1b9494fd8d72fefe1755710fa","bazonk gaz baz"],"id":67}' http://localhost:8550/ + + +**/ diff --git a/cmd/clef/pythonsigner.py b/cmd/clef/pythonsigner.py new file mode 100644 index 0000000000..46fa23bd8c --- /dev/null +++ b/cmd/clef/pythonsigner.py @@ -0,0 +1,179 @@ +import os,sys, subprocess +from tinyrpc.transports import ServerTransport +from tinyrpc.protocols.jsonrpc import JSONRPCProtocol +from tinyrpc.dispatch import public,RPCDispatcher +from tinyrpc.server import RPCServer + +""" This is a POC example of how to write a custom UI for Clef. The UI starts the +clef process with the '--stdio-ui' option, and communicates with clef using standard input / output. + +The standard input/output is a relatively secure way to communicate, as it does not require opening any ports +or IPC files. Needless to say, it does not protect against memory inspection mechanisms where an attacker +can access process memory.""" + +try: + import urllib.parse as urlparse +except ImportError: + import urllib as urlparse + +class StdIOTransport(ServerTransport): + """ Uses std input/output for RPC """ + def receive_message(self): + return None, urlparse.unquote(sys.stdin.readline()) + + def send_reply(self, context, reply): + print(reply) + +class PipeTransport(ServerTransport): + """ Uses std a pipe for RPC """ + + def __init__(self,input, output): + self.input = input + self.output = output + + def receive_message(self): + data = self.input.readline() + print(">> {}".format( data)) + return None, urlparse.unquote(data) + + def send_reply(self, context, reply): + print("<< {}".format( reply)) + self.output.write(reply) + self.output.write("\n") + +class StdIOHandler(): + + def __init__(self): + pass + + @public + def ApproveTx(self,req): + """ + Example request: + { + "jsonrpc": "2.0", + "method": "ApproveTx", + "params": [{ + "transaction": { + "to": "0xae967917c465db8578ca9024c205720b1a3651A9", + "gas": "0x333", + "gasPrice": "0x123", + "value": "0x10", + "data": "0xd7a5865800000000000000000000000000000000000000000000000000000000000000ff", + "nonce": "0x0" + }, + "from": "0xAe967917c465db8578ca9024c205720b1a3651A9", + "call_info": "Warning! Could not validate ABI-data against calldata\nSupplied ABI spec does not contain method signature in data: 0xd7a58658", + "meta": { + "remote": "127.0.0.1:34572", + "local": "localhost:8550", + "scheme": "HTTP/1.1" + } + }], + "id": 1 + } + + :param transaction: transaction info + :param call_info: info abou the call, e.g. if ABI info could not be + :param meta: metadata about the request, e.g. where the call comes from + :return: + """ + transaction = req.get('transaction') + _from = req.get('from') + call_info = req.get('call_info') + meta = req.get('meta') + + return { + "approved" : False, + #"transaction" : transaction, + # "from" : _from, +# "password" : None, + } + + @public + def ApproveSignData(self, req): + """ Example request + + """ + return {"approved": False, "password" : None} + + @public + def ApproveExport(self, req): + """ Example request + + """ + return {"approved" : False} + + @public + def ApproveImport(self, req): + """ Example request + + """ + return { "approved" : False, "old_password": "", "new_password": ""} + + @public + def ApproveListing(self, req): + """ Example request + + """ + return {'accounts': []} + + @public + def ApproveNewAccount(self, req): + """ + Example request + + :return: + """ + return {"approved": False, + #"password": "" + } + + @public + def ShowError(self,message = {}): + """ + Example request: + + {"jsonrpc":"2.0","method":"ShowInfo","params":{"message":"Testing 'ShowError'"},"id":1} + + :param message: to show + :return: nothing + """ + if 'text' in message.keys(): + sys.stderr.write("Error: {}\n".format( message['text'])) + return + + @public + def ShowInfo(self,message = {}): + """ + Example request + {"jsonrpc":"2.0","method":"ShowInfo","params":{"message":"Testing 'ShowInfo'"},"id":0} + + :param message: to display + :return:nothing + """ + + if 'text' in message.keys(): + sys.stdout.write("Error: {}\n".format( message['text'])) + return + +def main(args): + + cmd = ["./clef", "--stdio-ui"] + if len(args) > 0 and args[0] == "test": + cmd.extend(["--stdio-ui-test"]) + print("cmd: {}".format(" ".join(cmd))) + dispatcher = RPCDispatcher() + dispatcher.register_instance(StdIOHandler(), '') + # line buffered + p = subprocess.Popen(cmd, bufsize=1, universal_newlines=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE) + + rpc_server = RPCServer( + PipeTransport(p.stdout, p.stdin), + JSONRPCProtocol(), + dispatcher + ) + rpc_server.serve_forever() + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/cmd/clef/rules.md b/cmd/clef/rules.md new file mode 100644 index 0000000000..327ba765c5 --- /dev/null +++ b/cmd/clef/rules.md @@ -0,0 +1,236 @@ +# Rules + +The `signer` binary contains a ruleset engine, implemented with [OttoVM](https://github.com/robertkrimen/otto) + +It enables usecases like the following: + +* I want to auto-approve transactions with contract `CasinoDapp`, with up to `0.05 ether` in value to maximum `1 ether` per 24h period +* I want to auto-approve transaction to contract `EthAlarmClock` with `data`=`0xdeadbeef`, if `value=0`, `gas < 44k` and `gasPrice < 40Gwei` + +The two main features that are required for this to work well are; + +1. Rule Implementation: how to create, manage and interpret rules in a flexible but secure manner +2. Credential managements and credentials; how to provide auto-unlock without exposing keys unnecessarily. + +The section below deals with both of them + +## Rule Implementation + +A ruleset file is implemented as a `js` file. Under the hood, the ruleset-engine is a `SignerUI`, implementing the same methods as the `json-rpc` methods +defined in the UI protocol. Example: + +```javascript + +function asBig(str){ + if(str.slice(0,2) == "0x"){ return new BigNumber(str.slice(2),16)} + return new BigNumber(str) +} + +// Approve transactions to a certain contract if value is below a certain limit +function ApproveTx(req){ + + var limit = big.Newint("0xb1a2bc2ec50000") + var value = asBig(req.transaction.value); + + if(req.transaction.to.toLowerCase()=="0xae967917c465db8578ca9024c205720b1a3651a9") + && value.lt(limit) ){ + return "Approve" + } + // If we return "Reject", it will be rejected. + // By not returning anything, it will be passed to the next UI, for manual processing +} + +//Approve listings if request made from IPC +function ApproveListing(req){ + if (req.metadata.scheme == "ipc"){ return "Approve"} +} + +``` + +Whenever the external API is called (and the ruleset is enabled), the `signer` calls the UI, which is an instance of a ruleset-engine. The ruleset-engine +invokes the corresponding method. In doing so, there are three possible outcomes: + +1. JS returns "Approve" + * Auto-approve request +2. JS returns "Reject" + * Auto-reject request +3. Error occurs, or something else is returned + * Pass on to `next` ui: the regular UI channel. + +A more advanced example can be found below, "Example 1: ruleset for a rate-limited window", using `storage` to `Put` and `Get` `string`s by key. + +* At the time of writing, storage only exists as an ephemeral unencrypted implementation, to be used during testing. + +### Things to note + +The Otto vm has a few [caveats](https://github.com/robertkrimen/otto): + +* "use strict" will parse, but does nothing. +* The regular expression engine (re2/regexp) is not fully compatible with the ECMA5 specification. +* Otto targets ES5. ES6 features (eg: Typed Arrays) are not supported. + +Additionally, a few more have been added + +* The rule execution cannot load external javascript files. +* The only preloaded libary is [`bignumber.js`](https://github.com/MikeMcl/bignumber.js) version `2.0.3`. This one is fairly old, and is not aligned with the documentation at the github repository. +* Each invocation is made in a fresh virtual machine. This means that you cannot store data in global variables between invocations. This is a deliberate choice -- if you want to store data, use the disk-backed `storage`, since rules should not rely on ephemeral data. +* Javascript API parameters are _always_ an object. This is also a design choice, to ensure that parameters are accessed by _key_ and not by order. This is to prevent mistakes due to missing parameters or parameter changes. +* The JS engine has access to `storage` and `console`. + +#### Security considerations + +##### Security of ruleset + +Some security precautions can be made, such as: + +* Never load `ruleset.js` unless the file is `readonly` (`r-??-??-?`). If the user wishes to modify the ruleset, he must make it writeable and then set back to readonly. + * This is to prevent attacks where files are dropped on the users disk. +* Since we're going to have to have some form of secure storage (not defined in this section), we could also store the `sha3` of the `ruleset.js` file in there. + * If the user wishes to modify the ruleset, he'd then have to perform e.g. `signer --attest /path/to/ruleset --credential ` + +##### Security of implementation + +The drawbacks of this very flexible solution is that the `signer` needs to contain a javascript engine. This is pretty simple to implement, since it's already +implemented for `geth`. There are no known security vulnerabilities in, nor have we had any security-problems with it so far. + +The javascript engine would be an added attack surface; but if the validation of `rulesets` is made good (with hash-based attestation), the actual javascript cannot be considered +an attack surface -- if an attacker can control the ruleset, a much simpler attack would be to implement an "always-approve" rule instead of exploiting the js vm. The only benefit +to be gained from attacking the actual `signer` process from the `js` side would be if it could somehow extract cryptographic keys from memory. + +##### Security in usability + +Javascript is flexible, but also easy to get wrong, especially when users assume that `js` can handle large integers natively. Typical errors +include trying to multiply `gasCost` with `gas` without using `bigint`:s. + +It's unclear whether any other DSL could be more secure; since there's always the possibility of erroneously implementing a rule. + + +## Credential management + +The ability to auto-approve transaction means that the signer needs to have necessary credentials to decrypt keyfiles. These passwords are hereafter called `ksp` (keystore pass). + +### Example implementation + +Upon startup of the signer, the signer is given a switch: `--seed ` +The `seed` contains a blob of bytes, which is the master seed for the `signer`. + +The `signer` uses the `seed` to: + +* Generate the `path` where the settings are stored. + * `./settings/1df094eb-c2b1-4689-90dd-790046d38025/vault.dat` + * `./settings/1df094eb-c2b1-4689-90dd-790046d38025/rules.js` +* Generate the encryption password for `vault.dat`. + +The `vault.dat` would be an encrypted container storing the following information: + +* `ksp` entries +* `sha256` hash of `rules.js` +* Information about pair:ed callers (not yet specified) + +### Security considerations + +This would leave it up to the user to ensure that the `path/to/masterseed` is handled in a secure way. It's difficult to get around this, although one could +imagine leveraging OS-level keychains where supported. The setup is however in general similar to how ssh-keys are stored in `.ssh/`. + + +# Implementation status + +This is now implemented (with ephemeral non-encrypted storage for now, so not yet enabled). + +## Example 1: ruleset for a rate-limited window + + +```javascript + + function big(str){ + if(str.slice(0,2) == "0x"){ return new BigNumber(str.slice(2),16)} + return new BigNumber(str) + } + + // Time window: 1 week + var window = 1000* 3600*24*7; + + // Limit : 1 ether + var limit = new BigNumber("1e18"); + + function isLimitOk(transaction){ + var value = big(transaction.value) + // Start of our window function + var windowstart = new Date().getTime() - window; + + var txs = []; + var stored = storage.Get('txs'); + + if(stored != ""){ + txs = JSON.parse(stored) + } + // First, remove all that have passed out of the time-window + var newtxs = txs.filter(function(tx){return tx.tstamp > windowstart}); + console.log(txs, newtxs.length); + + // Secondly, aggregate the current sum + sum = new BigNumber(0) + + sum = newtxs.reduce(function(agg, tx){ return big(tx.value).plus(agg)}, sum); + console.log("ApproveTx > Sum so far", sum); + console.log("ApproveTx > Requested", value.toNumber()); + + // Would we exceed weekly limit ? + return sum.plus(value).lt(limit) + + } + function ApproveTx(r){ + if (isLimitOk(r.transaction)){ + return "Approve" + } + return "Nope" + } + + /** + * OnApprovedTx(str) is called when a transaction has been approved and signed. The parameter + * 'response_str' contains the return value that will be sent to the external caller. + * The return value from this method is ignore - the reason for having this callback is to allow the + * ruleset to keep track of approved transactions. + * + * When implementing rate-limited rules, this callback should be used. + * If a rule responds with neither 'Approve' nor 'Reject' - the tx goes to manual processing. If the user + * then accepts the transaction, this method will be called. + * + * TLDR; Use this method to keep track of signed transactions, instead of using the data in ApproveTx. + */ + function OnApprovedTx(resp){ + var value = big(resp.tx.value) + var txs = [] + // Load stored transactions + var stored = storage.Get('txs'); + if(stored != ""){ + txs = JSON.parse(stored) + } + // Add this to the storage + txs.push({tstamp: new Date().getTime(), value: value}); + storage.Put("txs", JSON.stringify(txs)); + } + +``` + +## Example 2: allow destination + +```javascript + + function ApproveTx(r){ + if(r.transaction.from.toLowerCase()=="0x0000000000000000000000000000000000001337"){ return "Approve"} + if(r.transaction.from.toLowerCase()=="0x000000000000000000000000000000000000dead"){ return "Reject"} + // Otherwise goes to manual processing + } + +``` + +## Example 3: Allow listing + +```javascript + + function ApproveListing(){ + return "Approve" + } + +``` \ No newline at end of file diff --git a/cmd/clef/sign_flow.png b/cmd/clef/sign_flow.png new file mode 100644 index 0000000000..93ef81a32e Binary files /dev/null and b/cmd/clef/sign_flow.png differ diff --git a/cmd/clef/tests/testsigner.js b/cmd/clef/tests/testsigner.js new file mode 100644 index 0000000000..86b2c45395 --- /dev/null +++ b/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/cmd/clef/tutorial.md b/cmd/clef/tutorial.md new file mode 100644 index 0000000000..dfb31ba4ef --- /dev/null +++ b/cmd/clef/tutorial.md @@ -0,0 +1,211 @@ +## Initializing the signer + +First, initialize the master seed. + +```text +#./signer init + +WARNING! + +The signer is alpha software, and not yet publically released. This software has _not_ been audited, and there +are no guarantees about the workings of this software. It may contain severe flaws. You should not use this software +unless you agree to take full responsibility for doing so, and know what you are doing. + +TLDR; THIS IS NOT PRODUCTION-READY SOFTWARE! + + +Enter 'ok' to proceed: +>ok +A master seed has been generated into /home/martin/.signer/secrets.dat + +This is required to be able to store credentials, such as : +* Passwords for keystores (used by rule engine) +* Storage for javascript rules +* Hash of rule-file + +You should treat that file with utmost secrecy, and make a backup of it. +NOTE: This file does not contain your accounts. Those need to be backed up separately! +``` + +(for readability purposes, we'll remove the WARNING printout in the rest of this document) + +## Creating rules + +Now, you can create a rule-file. Note that it is not mandatory to use predefined rules, but it's really handy. + +```javascript +function ApproveListing(){ + return "Approve" +} +``` + +Get the `sha256` hash. If you have openssl, you can do `openssl sha256 rules.js`... +```text +#sha256sum rules.js +6c21d1737429d6d4f2e55146da0797782f3c0a0355227f19d702df377c165d72 rules.js +``` +...now `attest` the file... +```text +#./signer attest 6c21d1737429d6d4f2e55146da0797782f3c0a0355227f19d702df377c165d72 + +INFO [02-21|12:14:38] Ruleset attestation updated sha256=6c21d1737429d6d4f2e55146da0797782f3c0a0355227f19d702df377c165d72 +``` + +...and (this is required only for non-production versions) load a mock-up `4byte.json` by copying the file from the source to your current working directory: +```text +#cp $GOPATH/src/github.com/ethereum/go-ethereum/cmd/clef/4byte.json $PWD +``` + +At this point, we can start the signer with the rule-file: +```text +#./signer --rules rules.js --rpc + +INFO [09-25|20:28:11.866] Using CLI as UI-channel +INFO [09-25|20:28:11.876] Loaded 4byte db signatures=5509 file=./4byte.json +INFO [09-25|20:28:11.877] Rule engine configured file=./rules.js +DEBUG[09-25|20:28:11.877] FS scan times list=100.781µs set=13.253µs diff=5.761µs +DEBUG[09-25|20:28:11.884] Ledger support enabled +DEBUG[09-25|20:28:11.888] Trezor support enabled +INFO [09-25|20:28:11.888] Audit logs configured file=audit.log +DEBUG[09-25|20:28:11.888] HTTP registered namespace=account +INFO [09-25|20:28:11.890] HTTP endpoint opened url=http://localhost:8550 +DEBUG[09-25|20:28:11.890] IPC registered namespace=account +INFO [09-25|20:28:11.890] IPC endpoint opened url= +------- Signer info ------- +* extapi_version : 2.0.0 +* intapi_version : 2.0.0 +* extapi_http : http://localhost:8550 +* extapi_ipc : +``` + +Any list-requests will now be auto-approved by our rule-file. + +## Under the hood + +While doing the operations above, these files have been created: + +```text +#ls -laR ~/.signer/ +/home/martin/.signer/: +total 16 +drwx------ 3 martin martin 4096 feb 21 12:14 . +drwxr-xr-x 71 martin martin 4096 feb 21 12:12 .. +drwx------ 2 martin martin 4096 feb 21 12:14 43f73718397aa54d1b22 +-rwx------ 1 martin martin 256 feb 21 12:12 secrets.dat + +/home/martin/.signer/43f73718397aa54d1b22: +total 12 +drwx------ 2 martin martin 4096 feb 21 12:14 . +drwx------ 3 martin martin 4096 feb 21 12:14 .. +-rw------- 1 martin martin 159 feb 21 12:14 config.json + +#cat /home/martin/.signer/43f73718397aa54d1b22/config.json +{"ruleset_sha256":{"iv":"6v4W4tfJxj3zZFbl","c":"6dt5RTDiTq93yh1qDEjpsat/tsKG7cb+vr3sza26IPL2fvsQ6ZoqFx++CPUa8yy6fD9Bbq41L01ehkKHTG3pOAeqTW6zc/+t0wv3AB6xPmU="}} + +``` + +In `~/.signer`, the `secrets.dat` file was created, containing the `master_seed`. +The `master_seed` was then used to derive a few other things: + +- `vault_location` : in this case `43f73718397aa54d1b22` . + - Thus, if you use a different `master_seed`, another `vault_location` will be used that does not conflict with each other. + - Example: `signer --signersecret /path/to/afile ...` +- `config.json` which is the encrypted key/value storage for configuration data, containing the key `ruleset_sha256`. + + +## Adding credentials + +In order to make more useful rules like signing transactions, the signer needs access to the passwords needed to unlock keystores. + +```text +#./signer addpw "0x694267f14675d7e1b9494fd8d72fefe1755710fa" "test_password" + +INFO [02-21|13:43:21] Credential store updated key=0x694267f14675d7e1b9494fd8d72fefe1755710fa +``` +## More advanced rules + +Now let's update the rules to make use of credentials: + +```javascript +function ApproveListing(){ + return "Approve" +} +function ApproveSignData(r){ + if( r.address.toLowerCase() == "0x694267f14675d7e1b9494fd8d72fefe1755710fa") + { + if(r.message.indexOf("bazonk") >= 0){ + return "Approve" + } + return "Reject" + } + // Otherwise goes to manual processing +} + +``` +In this example: +* Any requests to sign data with the account `0x694...` will be + * auto-approved if the message contains with `bazonk` + * auto-rejected if it does not. +* Any other signing-requests will be passed along for manual approve/reject. + +_Note: make sure that `0x694...` is an account you have access to. You can create it either via the clef or the traditional account cli tool. If the latter was chosen, make sure both clef and geth use the same keystore by specifing `--keystore path/to/your/keystore` when running clef._ + +Attest the new file... +```text +#sha256sum rules.js +2a0cb661dacfc804b6e95d935d813fd17c0997a7170e4092ffbc34ca976acd9f rules.js + +#./signer attest 2a0cb661dacfc804b6e95d935d813fd17c0997a7170e4092ffbc34ca976acd9f + +INFO [02-21|14:36:30] Ruleset attestation updated sha256=2a0cb661dacfc804b6e95d935d813fd17c0997a7170e4092ffbc34ca976acd9f +``` + +And start the signer: + +``` +#./signer --rules rules.js --rpc + +INFO [09-25|21:02:16.450] Using CLI as UI-channel +INFO [09-25|21:02:16.466] Loaded 4byte db signatures=5509 file=./4byte.json +INFO [09-25|21:02:16.467] Rule engine configured file=./rules.js +DEBUG[09-25|21:02:16.468] FS scan times list=1.45262ms set=21.926µs diff=6.944µs +DEBUG[09-25|21:02:16.473] Ledger support enabled +DEBUG[09-25|21:02:16.475] Trezor support enabled +INFO [09-25|21:02:16.476] Audit logs configured file=audit.log +DEBUG[09-25|21:02:16.476] HTTP registered namespace=account +INFO [09-25|21:02:16.478] HTTP endpoint opened url=http://localhost:8550 +DEBUG[09-25|21:02:16.478] IPC registered namespace=account +INFO [09-25|21:02:16.478] IPC endpoint opened url= +------- Signer info ------- +* extapi_version : 2.0.0 +* intapi_version : 2.0.0 +* extapi_http : http://localhost:8550 +* extapi_ipc : +``` + +And then test signing, once with `bazonk` and once without: + +``` +#curl -H "Content-Type: application/json" -X POST --data "{\"jsonrpc\":\"2.0\",\"method\":\"account_sign\",\"params\":[\"0x694267f14675d7e1b9494fd8d72fefe1755710fa\",\"0x$(xxd -pu <<< ' bazonk baz gaz')\"],\"id\":67}" http://localhost:8550/ +{"jsonrpc":"2.0","id":67,"result":"0x93e6161840c3ae1efc26dc68dedab6e8fc233bb3fefa1b4645dbf6609b93dace160572ea4ab33240256bb6d3dadb60dcd9c515d6374d3cf614ee897408d41d541c"} + +#curl -H "Content-Type: application/json" -X POST --data "{\"jsonrpc\":\"2.0\",\"method\":\"account_sign\",\"params\":[\"0x694267f14675d7e1b9494fd8d72fefe1755710fa\",\"0x$(xxd -pu <<< ' bonk baz gaz')\"],\"id\":67}" http://localhost:8550/ +{"jsonrpc":"2.0","id":67,"error":{"code":-32000,"message":"Request denied"}} + +``` + +Meanwhile, in the signer output: +```text +INFO [02-21|14:42:41] Op approved +INFO [02-21|14:42:56] Op rejected +``` + +The signer also stores all traffic over the external API in a log file. The last 4 lines shows the two requests and their responses: + +```text +#tail -n 4 audit.log +t=2018-02-21T14:42:41+0100 lvl=info msg=Sign api=signer type=request metadata="{\"remote\":\"127.0.0.1:49706\",\"local\":\"localhost:8550\",\"scheme\":\"HTTP/1.1\"}" addr="0x694267f14675d7e1b9494fd8d72fefe1755710fa [chksum INVALID]" data=202062617a6f6e6b2062617a2067617a0a +t=2018-02-21T14:42:42+0100 lvl=info msg=Sign api=signer type=response data=93e6161840c3ae1efc26dc68dedab6e8fc233bb3fefa1b4645dbf6609b93dace160572ea4ab33240256bb6d3dadb60dcd9c515d6374d3cf614ee897408d41d541c error=nil +t=2018-02-21T14:42:56+0100 lvl=info msg=Sign api=signer type=request metadata="{\"remote\":\"127.0.0.1:49708\",\"local\":\"localhost:8550\",\"scheme\":\"HTTP/1.1\"}" addr="0x694267f14675d7e1b9494fd8d72fefe1755710fa [chksum INVALID]" data=2020626f6e6b2062617a2067617a0a +t=2018-02-21T14:42:56+0100 lvl=info msg=Sign api=signer type=response data= error="Request denied" +``` \ No newline at end of file diff --git a/cmd/ethkey/README.md b/cmd/ethkey/README.md index cf72ba43d7..48d3c9e9b7 100644 --- a/cmd/ethkey/README.md +++ b/cmd/ethkey/README.md @@ -21,21 +21,33 @@ Private key information can be printed by using the `--private` flag; make sure to use this feature with great caution! -### `ethkey sign ` +### `ethkey signmessage ` Sign the message with a keyfile. It is possible to refer to a file containing the message. +To sign a message contained in a file, use the `--msgfile` flag. -### `ethkey verify
` +### `ethkey verifymessage
` Verify the signature of the message. It is possible to refer to a file containing the message. +To sign a message contained in a file, use the --msgfile flag. + + +### `ethkey changepassphrase ` + +Change the passphrase of a keyfile. +use the `--newpasswordfile` to point to the new password file. ## Passphrases For every command that uses a keyfile, you will be prompted to provide the passphrase for decrypting the keyfile. To avoid this message, it is possible -to pass the passphrase by using the `--passphrase` flag pointing to a file that +to pass the passphrase by using the `--passwordfile` flag pointing to a file that contains the passphrase. + +## JSON + +In case you need to output the result in a JSON format, you shall by using the `--json` flag. diff --git a/cmd/ethkey/changepassphrase.go b/cmd/ethkey/changepassphrase.go new file mode 100644 index 0000000000..d1ae2ae0d8 --- /dev/null +++ b/cmd/ethkey/changepassphrase.go @@ -0,0 +1,72 @@ +package main + +import ( + "fmt" + "io/ioutil" + "strings" + + "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/ethereum/go-ethereum/cmd/utils" + "gopkg.in/urfave/cli.v1" +) + +var newPassphraseFlag = cli.StringFlag{ + Name: "newpasswordfile", + Usage: "the file that contains the new passphrase for the keyfile", +} + +var commandChangePassphrase = cli.Command{ + Name: "changepassphrase", + Usage: "change the passphrase on a keyfile", + ArgsUsage: "", + Description: ` +Change the passphrase of a keyfile.`, + Flags: []cli.Flag{ + passphraseFlag, + newPassphraseFlag, + }, + Action: func(ctx *cli.Context) error { + keyfilepath := ctx.Args().First() + + // Read key from file. + keyjson, err := ioutil.ReadFile(keyfilepath) + if err != nil { + utils.Fatalf("Failed to read the keyfile at '%s': %v", keyfilepath, err) + } + + // Decrypt key with passphrase. + passphrase := getPassphrase(ctx) + key, err := keystore.DecryptKey(keyjson, passphrase) + if err != nil { + utils.Fatalf("Error decrypting key: %v", err) + } + + // Get a new passphrase. + fmt.Println("Please provide a new passphrase") + var newPhrase string + if passFile := ctx.String(newPassphraseFlag.Name); passFile != "" { + content, err := ioutil.ReadFile(passFile) + if err != nil { + utils.Fatalf("Failed to read new passphrase file '%s': %v", passFile, err) + } + newPhrase = strings.TrimRight(string(content), "\r\n") + } else { + newPhrase = promptPassphrase(true) + } + + // Encrypt the key with the new passphrase. + newJson, err := keystore.EncryptKey(key, newPhrase, keystore.StandardScryptN, keystore.StandardScryptP) + if err != nil { + utils.Fatalf("Error encrypting with new passphrase: %v", err) + } + + // Then write the new keyfile in place of the old one. + if err := ioutil.WriteFile(keyfilepath, newJson, 600); err != nil { + utils.Fatalf("Error writing new keyfile to disk: %v", err) + } + + // Don't print anything. Just return successfully, + // producing a positive exit code. + return nil + }, +} diff --git a/cmd/ethkey/generate.go b/cmd/ethkey/generate.go index 6d57d17fb4..fe9a0c1519 100644 --- a/cmd/ethkey/generate.go +++ b/cmd/ethkey/generate.go @@ -90,7 +90,7 @@ If you want to encrypt an existing private key, it can be specified by setting } // Encrypt key with passphrase. - passphrase := getPassPhrase(ctx, true) + passphrase := promptPassphrase(true) keyjson, err := keystore.EncryptKey(key, passphrase, keystore.StandardScryptN, keystore.StandardScryptP) if err != nil { utils.Fatalf("Error encrypting key: %v", err) diff --git a/cmd/ethkey/inspect.go b/cmd/ethkey/inspect.go index 219a5460b8..ba03d4d936 100644 --- a/cmd/ethkey/inspect.go +++ b/cmd/ethkey/inspect.go @@ -1,3 +1,19 @@ +// Copyright 2017 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 ( @@ -44,7 +60,7 @@ make sure to use this feature with great caution!`, } // Decrypt key with passphrase. - passphrase := getPassPhrase(ctx, false) + passphrase := getPassphrase(ctx) key, err := keystore.DecryptKey(keyjson, passphrase) if err != nil { utils.Fatalf("Error decrypting key: %v", err) diff --git a/cmd/ethkey/main.go b/cmd/ethkey/main.go index 2a9e5ee483..c434da0c05 100644 --- a/cmd/ethkey/main.go +++ b/cmd/ethkey/main.go @@ -38,6 +38,7 @@ func init() { app.Commands = []cli.Command{ commandGenerate, commandInspect, + commandChangePassphrase, commandSignMessage, commandVerifyMessage, } @@ -53,10 +54,6 @@ var ( Name: "json", Usage: "output JSON instead of human-readable format", } - messageFlag = cli.StringFlag{ - Name: "message", - Usage: "the file that contains the message to sign/verify", - } ) func main() { diff --git a/cmd/ethkey/message.go b/cmd/ethkey/message.go index 531a931c82..5caea69ff6 100644 --- a/cmd/ethkey/message.go +++ b/cmd/ethkey/message.go @@ -62,7 +62,7 @@ To sign a message contained in a file, use the --msgfile flag. } // Decrypt key with passphrase. - passphrase := getPassPhrase(ctx, false) + passphrase := getPassphrase(ctx) key, err := keystore.DecryptKey(keyjson, passphrase) if err != nil { utils.Fatalf("Error decrypting key: %v", err) diff --git a/cmd/ethkey/message_test.go b/cmd/ethkey/message_test.go index fb16f03d02..39352b1d22 100644 --- a/cmd/ethkey/message_test.go +++ b/cmd/ethkey/message_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 The go-ethereum Authors +// 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 diff --git a/cmd/ethkey/run_test.go b/cmd/ethkey/run_test.go index 8ce4fe5cde..6006f6b5bb 100644 --- a/cmd/ethkey/run_test.go +++ b/cmd/ethkey/run_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 The go-ethereum Authors +// 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 diff --git a/cmd/ethkey/utils.go b/cmd/ethkey/utils.go index 0e563bf922..6f60ebaf1b 100644 --- a/cmd/ethkey/utils.go +++ b/cmd/ethkey/utils.go @@ -28,11 +28,32 @@ import ( "gopkg.in/urfave/cli.v1" ) -// getPassPhrase obtains a passphrase given by the user. It first checks the -// --passphrase command line flag and ultimately prompts the user for a +// promptPassphrase prompts the user for a passphrase. Set confirmation to true +// to require the user to confirm the passphrase. +func promptPassphrase(confirmation bool) string { + passphrase, err := console.Stdin.PromptPassword("Passphrase: ") + if err != nil { + utils.Fatalf("Failed to read passphrase: %v", err) + } + + if confirmation { + confirm, err := console.Stdin.PromptPassword("Repeat passphrase: ") + if err != nil { + utils.Fatalf("Failed to read passphrase confirmation: %v", err) + } + if passphrase != confirm { + utils.Fatalf("Passphrases do not match") + } + } + + return passphrase +} + +// getPassphrase obtains a passphrase given by the user. It first checks the +// --passfile command line flag and ultimately prompts the user for a // passphrase. -func getPassPhrase(ctx *cli.Context, confirmation bool) string { - // Look for the --passphrase flag. +func getPassphrase(ctx *cli.Context) string { + // Look for the --passwordfile flag. passphraseFile := ctx.String(passphraseFlag.Name) if passphraseFile != "" { content, err := ioutil.ReadFile(passphraseFile) @@ -44,20 +65,7 @@ func getPassPhrase(ctx *cli.Context, confirmation bool) string { } // Otherwise prompt the user for the passphrase. - passphrase, err := console.Stdin.PromptPassword("Passphrase: ") - if err != nil { - utils.Fatalf("Failed to read passphrase: %v", err) - } - if confirmation { - confirm, err := console.Stdin.PromptPassword("Repeat passphrase: ") - if err != nil { - utils.Fatalf("Failed to read passphrase confirmation: %v", err) - } - if passphrase != confirm { - utils.Fatalf("Passphrases do not match") - } - } - return passphrase + return promptPassphrase(false) } // signHash is a helper function that calculates a hash for the given message diff --git a/cmd/evm/disasm.go b/cmd/evm/disasm.go index 4a442cf784..69f611e39b 100644 --- a/cmd/evm/disasm.go +++ b/cmd/evm/disasm.go @@ -44,7 +44,7 @@ func disasmCmd(ctx *cli.Context) error { return err } - code := strings.TrimSpace(string(in[:])) + code := strings.TrimSpace(string(in)) fmt.Printf("%v\n", code) return asm.PrintDisassembled(code) } diff --git a/cmd/evm/main.go b/cmd/evm/main.go index 6c39cf8b88..ebac2047aa 100644 --- a/cmd/evm/main.go +++ b/cmd/evm/main.go @@ -86,10 +86,6 @@ var ( Name: "create", Usage: "indicates the action should be create rather than call", } - DisableGasMeteringFlag = cli.BoolFlag{ - Name: "nogasmetering", - Usage: "disable gas metering", - } GenesisFlag = cli.StringFlag{ Name: "prestate", Usage: "JSON file with prestate (genesis) config", @@ -114,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() { @@ -128,7 +129,6 @@ func init() { ValueFlag, DumpFlag, InputFlag, - DisableGasMeteringFlag, MemProfileFlag, CPUProfileFlag, StatDumpFlag, @@ -138,6 +138,7 @@ func init() { ReceiverFlag, DisableMemoryFlag, DisableStackFlag, + EVMInterpreterFlag, } app.Commands = []cli.Command{ compileCommand, diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index 96de0c76ac..c732c8b574 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -21,12 +21,12 @@ import ( "encoding/json" "fmt" "io/ioutil" + "math/big" "os" + goruntime "runtime" "runtime/pprof" "time" - goruntime "runtime" - "github.com/ethereum/go-ethereum/cmd/evm/internal/compiler" "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common" @@ -76,18 +76,20 @@ func runCmd(ctx *cli.Context) error { logconfig := &vm.LogConfig{ DisableMemory: ctx.GlobalBool(DisableMemoryFlag.Name), DisableStack: ctx.GlobalBool(DisableStackFlag.Name), + Debug: ctx.GlobalBool(DebugFlag.Name), } var ( - tracer vm.Tracer - debugLogger *vm.StructLogger - statedb *state.StateDB - chainConfig *params.ChainConfig - sender = common.StringToAddress("sender") - receiver = common.StringToAddress("receiver") + tracer vm.Tracer + debugLogger *vm.StructLogger + statedb *state.StateDB + chainConfig *params.ChainConfig + sender = common.BytesToAddress([]byte("sender")) + receiver = common.BytesToAddress([]byte("receiver")) + 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 @@ -96,11 +98,14 @@ func runCmd(ctx *cli.Context) error { } if ctx.GlobalString(GenesisFlag.Name) != "" { gen := readGenesis(ctx.GlobalString(GenesisFlag.Name)) - _, statedb = gen.ToBlock() + genesisConfig = gen + db := ethdb.NewMemDatabase() + genesis := gen.ToBlock(db) + statedb, _ = state.New(genesis.Root(), state.NewDatabase(db)) chainConfig = gen.Config } else { - db, _ := ethdb.NewMemDatabase() - statedb, _ = state.New(common.Hash{}, state.NewDatabase(db)) + statedb, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) + genesisConfig = new(core.Genesis) } if ctx.GlobalString(SenderFlag.Name) != "" { sender = common.HexToAddress(ctx.GlobalString(SenderFlag.Name)) @@ -152,16 +157,23 @@ func runCmd(ctx *cli.Context) error { } initialGas := ctx.GlobalUint64(GasFlag.Name) + if genesisConfig.GasLimit != 0 { + initialGas = genesisConfig.GasLimit + } runtimeConfig := runtime.Config{ - Origin: sender, - State: statedb, - GasLimit: initialGas, - GasPrice: utils.GlobalBig(ctx, PriceFlag.Name), - Value: utils.GlobalBig(ctx, ValueFlag.Name), + Origin: sender, + State: statedb, + GasLimit: initialGas, + GasPrice: utils.GlobalBig(ctx, PriceFlag.Name), + Value: utils.GlobalBig(ctx, ValueFlag.Name), + Difficulty: genesisConfig.Difficulty, + Time: new(big.Int).SetUint64(genesisConfig.Timestamp), + Coinbase: genesisConfig.Coinbase, + BlockNumber: new(big.Int).SetUint64(genesisConfig.Number), EVMConfig: vm.Config{ - Tracer: tracer, - Debug: ctx.GlobalBool(DebugFlag.Name) || ctx.GlobalBool(MachineFlag.Name), - DisableGasMetering: ctx.GlobalBool(DisableGasMeteringFlag.Name), + Tracer: tracer, + Debug: ctx.GlobalBool(DebugFlag.Name) || ctx.GlobalBool(MachineFlag.Name), + EVMInterpreter: ctx.GlobalString(EVMInterpreterFlag.Name), }, } @@ -195,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())) } @@ -233,9 +246,7 @@ Gas used: %d `, execTime, mem.HeapObjects, mem.Alloc, mem.TotalAlloc, mem.NumGC, initialGas-leftOverGas) } - if tracer != nil { - tracer.CaptureEnd(ret, initialGas-leftOverGas, execTime, err) - } else { + if tracer == nil { fmt.Printf("0x%x\n", ret) if err != nil { fmt.Printf(" error: %v\n", err) diff --git a/cmd/evm/staterunner.go b/cmd/evm/staterunner.go index 071ea94ad0..b3c69d9b9d 100644 --- a/cmd/evm/staterunner.go +++ b/cmd/evm/staterunner.go @@ -38,6 +38,8 @@ var stateTestCommand = cli.Command{ ArgsUsage: "", } +// StatetestResult contains the execution status after running a state test, any +// error that might have occurred and a dump of the final state if requested. type StatetestResult struct { Name string `json:"name"` Pass bool `json:"pass"` @@ -66,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) @@ -95,6 +97,10 @@ func stateTestCmd(ctx *cli.Context) error { // Run the test and aggregate the result result := &StatetestResult{Name: key, Fork: st.Fork, Pass: true} state, err := test.Run(st, cfg) + // print state root for evmlab tracing + if ctx.GlobalBool(MachineFlag.Name) && state != nil { + fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%x\"}\n", state.IntermediateRoot(false)) + } if err != nil { // Test failed, mark as so and dump any state to aid debugging result.Pass, result.Error = false, err.Error() @@ -103,10 +109,6 @@ func stateTestCmd(ctx *cli.Context) error { result.State = &dump } } - // print state root for evmlab tracing (already committed above, so no need to delete objects again - if ctx.GlobalBool(MachineFlag.Name) && state != nil { - fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%x\"}\n", state.IntermediateRoot(false)) - } results = append(results, *result) diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go index 99527f9d1e..5e4b77a6a5 100644 --- a/cmd/faucet/faucet.go +++ b/cmd/faucet/faucet.go @@ -54,8 +54,8 @@ 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/discover" "github.com/ethereum/go-ethereum/p2p/discv5" + "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/params" "golang.org/x/net/websocket" @@ -77,9 +77,6 @@ var ( accJSONFlag = flag.String("account.json", "", "Key json file to fund user requests with") accPassFlag = flag.String("account.pass", "", "Decryption password to access faucet funds") - githubUser = flag.String("github.user", "", "GitHub user to authenticate with for Gist access") - githubToken = flag.String("github.token", "", "GitHub personal token to access Gists with") - captchaToken = flag.String("captcha.token", "", "Recaptcha site key to authenticate client side") captchaSecret = flag.String("captcha.secret", "", "Recaptcha secret key to authenticate server side") @@ -160,7 +157,8 @@ func main() { if blob, err = ioutil.ReadFile(*accPassFlag); err != nil { log.Crit("Failed to read account password contents", "file", *accPassFlag, "err", err) } - pass := string(blob) + // Delete trailing newline in password + pass := strings.TrimSuffix(string(blob), "\n") ks := keystore.NewKeyStore(filepath.Join(os.Getenv("HOME"), ".faucet", "keys"), keystore.StandardScryptN, keystore.StandardScryptP) if blob, err = ioutil.ReadFile(*accJSONFlag); err != nil { @@ -201,6 +199,8 @@ type faucet struct { keystore *keystore.KeyStore // Keystore containing the single signer account accounts.Account // Account funding user faucet requests + head *types.Header // Current head header of the faucet + balance *big.Int // Current balance of the faucet nonce uint64 // Current pending nonce of the faucet price *big.Int // Current gas price to issue funds with @@ -216,7 +216,7 @@ func newFaucet(genesis *core.Genesis, port int, enodes []*discv5.Node, network u // Assemble the raw devp2p protocol stack stack, err := node.New(&node.Config{ Name: "geth", - Version: params.Version, + Version: params.VersionWithMeta, DataDir: filepath.Join(os.Getenv("HOME"), ".faucet"), P2P: p2p.Config{ NAT: nat.Any(), @@ -255,8 +255,10 @@ func newFaucet(genesis *core.Genesis, port int, enodes []*discv5.Node, network u return nil, err } for _, boot := range enodes { - old, _ := discover.ParseNode(boot.String()) - stack.Server().AddPeer(old) + old, err := enode.ParseV4(boot.String()) + if err == nil { + stack.Server().AddPeer(old) + } } // Attach to the client and retrieve and interesting metadatas api, err := stack.Attach() @@ -280,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 @@ -326,33 +328,30 @@ func (f *faucet) apiHandler(conn *websocket.Conn) { nonce uint64 err error ) - for { - // Attempt to retrieve the stats, may error on no faucet connectivity - ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) - head, err = f.client.HeaderByNumber(ctx, nil) - if err == nil { - balance, err = f.client.BalanceAt(ctx, f.account.Address, head.Number) - if err == nil { - nonce, err = f.client.NonceAt(ctx, f.account.Address, nil) - } + for head == nil || balance == nil { + // Retrieve the current stats cached by the faucet + f.lock.RLock() + if f.head != nil { + head = types.CopyHeader(f.head) } - cancel() + if f.balance != nil { + balance = new(big.Int).Set(f.balance) + } + nonce = f.nonce + f.lock.RUnlock() - // If stats retrieval failed, wait a bit and retry - if err != nil { - if err = sendError(conn, errors.New("Faucet offline: "+err.Error())); err != nil { + if head == nil || balance == nil { + // Report the faucet offline until initial stats are ready + if err = sendError(conn, errors.New("Faucet offline")); err != nil { log.Warn("Failed to send faucet error to client", "err", err) return } time.Sleep(3 * time.Second) - continue } - // Initial stats reported successfully, proceed with user interaction - break } // Send over the initial stats and the latest header if err = send(conn, map[string]interface{}{ - "funds": balance.Div(balance, ether), + "funds": new(big.Int).Div(balance, ether), "funded": nonce, "peers": f.stack.Server().PeerCount(), "requests": f.reqs, @@ -474,7 +473,7 @@ func (f *faucet) apiHandler(conn *websocket.Conn) { amount = new(big.Int).Div(amount, new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(msg.Tier)), nil)) tx := types.NewTransaction(f.nonce+uint64(len(f.reqs)), address, amount, 21000, f.price, nil) - signed, err := f.keystore.SignTx(f.account, tx, f.config.ChainId) + signed, err := f.keystore.SignTx(f.account, tx, f.config.ChainID) if err != nil { f.lock.Unlock() if err = sendError(conn, err); err != nil { @@ -522,6 +521,47 @@ func (f *faucet) apiHandler(conn *websocket.Conn) { } } +// refresh attempts to retrieve the latest header from the chain and extract the +// associated faucet balance and nonce for connectivity caching. +func (f *faucet) refresh(head *types.Header) error { + // Ensure a state update does not run for too long + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + // If no header was specified, use the current chain head + var err error + if head == nil { + if head, err = f.client.HeaderByNumber(ctx, nil); err != nil { + return err + } + } + // Retrieve the balance, nonce and gas price from the current head + var ( + balance *big.Int + nonce uint64 + price *big.Int + ) + if balance, err = f.client.BalanceAt(ctx, f.account.Address, head.Number); err != nil { + return err + } + if nonce, err = f.client.NonceAt(ctx, f.account.Address, head.Number); err != nil { + return err + } + if price, err = f.client.SuggestGasPrice(ctx); err != nil { + return err + } + // Everything succeeded, update the cached stats and eject old requests + f.lock.Lock() + f.head, f.balance = head, balance + f.price, f.nonce = price, nonce + for len(f.reqs) > 0 && f.reqs[0].Tx.Nonce() < f.nonce { + f.reqs = f.reqs[1:] + } + f.lock.Unlock() + + return nil +} + // loop keeps waiting for interesting events and pushes them out to connected // websockets. func (f *faucet) loop() { @@ -533,49 +573,33 @@ func (f *faucet) loop() { } defer sub.Unsubscribe() - for { - select { - case head := <-heads: - // New chain head arrived, query the current stats and stream to clients - var ( - balance *big.Int - nonce uint64 - price *big.Int - err error - ) - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - balance, err = f.client.BalanceAt(ctx, f.account.Address, head.Number) - if err == nil { - nonce, err = f.client.NonceAt(ctx, f.account.Address, nil) - if err == nil { - price, err = f.client.SuggestGasPrice(ctx) - } - } - cancel() + // Start a goroutine to update the state from head notifications in the background + update := make(chan *types.Header) - // If querying the data failed, try for the next block - if err != nil { + go func() { + for head := range update { + // New chain head arrived, query the current stats and stream to clients + timestamp := time.Unix(head.Time.Int64(), 0) + if time.Since(timestamp) > time.Hour { + log.Warn("Skipping faucet refresh, head too old", "number", head.Number, "hash", head.Hash(), "age", common.PrettyAge(timestamp)) + continue + } + if err := f.refresh(head); err != nil { log.Warn("Failed to update faucet state", "block", head.Number, "hash", head.Hash(), "err", err) continue - } else { - log.Info("Updated faucet state", "block", head.Number, "hash", head.Hash(), "balance", balance, "nonce", nonce, "price", price) } // Faucet state retrieved, update locally and send to clients - balance = new(big.Int).Div(balance, ether) - - f.lock.Lock() - f.price, f.nonce = price, nonce - for len(f.reqs) > 0 && f.reqs[0].Tx.Nonce() < f.nonce { - f.reqs = f.reqs[1:] - } - f.lock.Unlock() - f.lock.RLock() + log.Info("Updated faucet state", "number", head.Number, "hash", head.Hash(), "age", common.PrettyAge(timestamp), "balance", f.balance, "nonce", f.nonce, "price", f.price) + + balance := new(big.Int).Div(f.balance, ether) + peers := f.stack.Server().PeerCount() + for _, conn := range f.conns { if err := send(conn, map[string]interface{}{ "funds": balance, "funded": f.nonce, - "peers": f.stack.Server().PeerCount(), + "peers": peers, "requests": f.reqs, }, time.Second); err != nil { log.Warn("Failed to send stats to client", "err", err) @@ -588,6 +612,17 @@ func (f *faucet) loop() { } } f.lock.RUnlock() + } + }() + // Wait for various events and assing to the appropriate background threads + for { + select { + case head := <-heads: + // New head arrived, send if for state update if there's none running + select { + case update <- head: + default: + } case <-f.update: // Pending requests updated, stream to clients @@ -625,59 +660,6 @@ func sendSuccess(conn *websocket.Conn, msg string) error { return send(conn, map[string]string{"success": msg}, time.Second) } -// authGitHub tries to authenticate a faucet request using GitHub gists, returning -// the username, avatar URL and Ethereum address to fund on success. -func authGitHub(url string) (string, string, common.Address, error) { - // Retrieve the gist from the GitHub Gist APIs - parts := strings.Split(url, "/") - req, _ := http.NewRequest("GET", "https://api.github.com/gists/"+parts[len(parts)-1], nil) - if *githubUser != "" { - req.SetBasicAuth(*githubUser, *githubToken) - } - res, err := http.DefaultClient.Do(req) - if err != nil { - return "", "", common.Address{}, err - } - var gist struct { - Owner struct { - Login string `json:"login"` - } `json:"owner"` - Files map[string]struct { - Content string `json:"content"` - } `json:"files"` - } - err = json.NewDecoder(res.Body).Decode(&gist) - res.Body.Close() - if err != nil { - return "", "", common.Address{}, err - } - if gist.Owner.Login == "" { - return "", "", common.Address{}, errors.New("Anonymous Gists not allowed") - } - // Iterate over all the files and look for Ethereum addresses - var address common.Address - for _, file := range gist.Files { - content := strings.TrimSpace(file.Content) - if len(content) == 2+common.AddressLength*2 { - address = common.HexToAddress(content) - } - } - if address == (common.Address{}) { - return "", "", common.Address{}, errors.New("No Ethereum address found to fund") - } - // Validate the user's existence since the API is unhelpful here - if res, err = http.Head("https://github.com/" + gist.Owner.Login); err != nil { - return "", "", common.Address{}, err - } - res.Body.Close() - - if res.StatusCode != 200 { - return "", "", common.Address{}, errors.New("Invalid user... boom!") - } - // Everything passed validation, return the gathered infos - return gist.Owner.Login + "@github", fmt.Sprintf("https://github.com/%s.png?size=64", gist.Owner.Login), address, nil -} - // authTwitter tries to authenticate a faucet request using Twitter posts, returning // the username, avatar URL and Ethereum address to fund on success. func authTwitter(url string) (string, string, common.Address, error) { @@ -686,8 +668,6 @@ func authTwitter(url string) (string, string, common.Address, error) { if len(parts) < 4 || parts[len(parts)-2] != "status" { return "", "", common.Address{}, errors.New("Invalid Twitter status URL") } - username := parts[len(parts)-3] - // Twitter's API isn't really friendly with direct links. Still, we don't // want to do ask read permissions from users, so just load the public posts and // scrape it for the Ethereum address and profile URL. @@ -697,6 +677,13 @@ func authTwitter(url string) (string, string, common.Address, error) { } defer res.Body.Close() + // Resolve the username from the final redirect, no intermediate junk + parts = strings.Split(res.Request.URL.String(), "/") + if len(parts) < 4 || parts[len(parts)-2] != "status" { + return "", "", common.Address{}, errors.New("Invalid Twitter status URL") + } + username := parts[len(parts)-3] + body, err := ioutil.ReadAll(res.Body) if err != nil { return "", "", common.Address{}, err diff --git a/cmd/geth/accountcmd.go b/cmd/geth/accountcmd.go index 0db5c4ce0f..071be85397 100644 --- a/cmd/geth/accountcmd.go +++ b/cmd/geth/accountcmd.go @@ -340,7 +340,7 @@ func importWallet(ctx *cli.Context) error { if len(keyfile) == 0 { utils.Fatalf("keyfile must be given as argument") } - keyJson, err := ioutil.ReadFile(keyfile) + keyJSON, err := ioutil.ReadFile(keyfile) if err != nil { utils.Fatalf("Could not read wallet file: %v", err) } @@ -349,7 +349,7 @@ func importWallet(ctx *cli.Context) error { passphrase := getPassPhrase("", false, 0, utils.MakePasswordList(ctx)) ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) - acct, err := ks.ImportPreSaleKey(keyJson, passphrase) + acct, err := ks.ImportPreSaleKey(keyJSON, passphrase) if err != nil { utils.Fatalf("%v", err) } diff --git a/cmd/geth/bugcmd.go b/cmd/geth/bugcmd.go index ce9dbe6c0a..0adc69d1fa 100644 --- a/cmd/geth/bugcmd.go +++ b/cmd/geth/bugcmd.go @@ -41,7 +41,7 @@ var bugCommand = cli.Command{ Category: "MISCELLANEOUS COMMANDS", } -const issueUrl = "https://github.com/ethereum/go-ethereum/issues/new" +const issueURL = "https://github.com/ethereum/go-ethereum/issues/new" // reportBug reports a bug by opening a new URL to the go-ethereum GH issue // tracker and setting default values as the issue body. @@ -49,15 +49,17 @@ func reportBug(ctx *cli.Context) error { // execute template and write contents to buff var buff bytes.Buffer - fmt.Fprintln(&buff, header) - fmt.Fprintln(&buff, "Version:", params.Version) + fmt.Fprintln(&buff, "#### System information") + fmt.Fprintln(&buff) + fmt.Fprintln(&buff, "Version:", params.VersionWithMeta) fmt.Fprintln(&buff, "Go Version:", runtime.Version()) fmt.Fprintln(&buff, "OS:", runtime.GOOS) printOSDetails(&buff) + fmt.Fprintln(&buff, header) // open a new GH issue - if !browser.Open(issueUrl + "?body=" + url.QueryEscape(buff.String())) { - fmt.Printf("Please file a new issue at %s using this template:\n%s", issueUrl, buff.String()) + if !browser.Open(issueURL + "?body=" + url.QueryEscape(buff.String())) { + fmt.Printf("Please file a new issue at %s using this template:\n\n%s", issueURL, buff.String()) } return nil } @@ -97,13 +99,15 @@ func printCmdOut(w io.Writer, prefix, path string, args ...string) { fmt.Fprintf(w, "%s%s\n", prefix, bytes.TrimSpace(out)) } -const header = `Please answer these questions before submitting your issue. Thanks! +const header = ` +#### Expected behaviour -#### What did you do? - -#### What did you expect to see? - -#### What did you see instead? - -#### System details + +#### Actual behaviour + + +#### Steps to reproduce the behaviour + + +#### Backtrace ` diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 4a9a7b11b5..6d41261f80 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -48,7 +48,6 @@ var ( ArgsUsage: "", Flags: []cli.Flag{ utils.DataDirFlag, - utils.LightModeFlag, }, Category: "BLOCKCHAIN COMMANDS", Description: ` @@ -66,7 +65,10 @@ It expects the genesis file as argument.`, Flags: []cli.Flag{ utils.DataDirFlag, utils.CacheFlag, - utils.LightModeFlag, + utils.SyncModeFlag, + utils.GCModeFlag, + utils.CacheDatabaseFlag, + utils.CacheGCFlag, }, Category: "BLOCKCHAIN COMMANDS", Description: ` @@ -84,14 +86,43 @@ processing will proceed even if an individual RLP-file import failure occurs.`, Flags: []cli.Flag{ utils.DataDirFlag, utils.CacheFlag, - utils.LightModeFlag, + utils.SyncModeFlag, }, Category: "BLOCKCHAIN COMMANDS", Description: ` Requires a first argument of the file to write to. Optional second and third arguments control the first and last block to write. In this mode, the file will be appended -if already existing.`, +if already existing. If the file ends with .gz, the output will +be gzipped.`, + } + importPreimagesCommand = cli.Command{ + Action: utils.MigrateFlags(importPreimages), + Name: "import-preimages", + Usage: "Import the preimage database from an RLP stream", + ArgsUsage: "", + Flags: []cli.Flag{ + utils.DataDirFlag, + utils.CacheFlag, + utils.SyncModeFlag, + }, + Category: "BLOCKCHAIN COMMANDS", + Description: ` + The import-preimages command imports hash preimages from an RLP encoded stream.`, + } + exportPreimagesCommand = cli.Command{ + Action: utils.MigrateFlags(exportPreimages), + Name: "export-preimages", + Usage: "Export the preimage database into an RLP stream", + ArgsUsage: "", + Flags: []cli.Flag{ + utils.DataDirFlag, + utils.CacheFlag, + utils.SyncModeFlag, + }, + Category: "BLOCKCHAIN COMMANDS", + Description: ` +The export-preimages command export hash preimages to an RLP encoded stream`, } copydbCommand = cli.Command{ Action: utils.MigrateFlags(copyDb), @@ -117,7 +148,6 @@ The first argument must be the directory containing the blockchain to download f ArgsUsage: " ", Flags: []cli.Flag{ utils.DataDirFlag, - utils.LightModeFlag, }, Category: "BLOCKCHAIN COMMANDS", Description: ` @@ -131,7 +161,7 @@ Remove blockchain and state databases`, Flags: []cli.Flag{ utils.DataDirFlag, utils.CacheFlag, - utils.LightModeFlag, + utils.SyncModeFlag, }, Category: "BLOCKCHAIN COMMANDS", Description: ` @@ -160,6 +190,8 @@ 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) if err != nil { @@ -179,6 +211,8 @@ func importChain(ctx *cli.Context) error { utils.Fatalf("This command requires an argument.") } stack := makeFullNode(ctx) + defer stack.Close() + chain, chainDb := utils.MakeChain(ctx, stack) defer chainDb.Close() @@ -202,7 +236,7 @@ func importChain(ctx *cli.Context) error { if len(ctx.Args()) == 1 { if err := utils.ImportChain(chain, ctx.Args().First()); err != nil { - utils.Fatalf("Import error: %v", err) + log.Error("Import error", "err", err) } } else { for _, arg := range ctx.Args() { @@ -211,7 +245,7 @@ func importChain(ctx *cli.Context) error { } } } - + chain.Stop() fmt.Printf("Import done in %v.\n\n", time.Since(start)) // Output pre-compaction stats mostly to see the import trashing @@ -222,6 +256,13 @@ func importChain(ctx *cli.Context) error { utils.Fatalf("Failed to read database stats: %v", err) } fmt.Println(stats) + + ioStats, err := db.LDB().GetProperty("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()) @@ -252,6 +293,12 @@ func importChain(ctx *cli.Context) error { } fmt.Println(stats) + ioStats, err = db.LDB().GetProperty("leveldb.iostats") + if err != nil { + utils.Fatalf("Failed to read database iostats: %v", err) + } + fmt.Println(ioStats) + return nil } @@ -260,6 +307,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() @@ -283,7 +332,43 @@ func exportChain(ctx *cli.Context) error { if err != nil { utils.Fatalf("Export error: %v\n", err) } - fmt.Printf("Export done in %v", time.Since(start)) + fmt.Printf("Export done in %v\n", time.Since(start)) + return nil +} + +// importPreimages imports preimage data from the specified file. +func importPreimages(ctx *cli.Context) error { + if len(ctx.Args()) < 1 { + utils.Fatalf("This command requires an argument.") + } + stack := makeFullNode(ctx) + defer stack.Close() + + diskdb := utils.MakeChainDatabase(ctx, stack).(*ethdb.LDBDatabase) + start := time.Now() + + if err := utils.ImportPreimages(diskdb, ctx.Args().First()); err != nil { + utils.Fatalf("Import error: %v\n", err) + } + fmt.Printf("Import done in %v\n", time.Since(start)) + return nil +} + +// exportPreimages dumps the preimage data to specified json file in streaming way. +func exportPreimages(ctx *cli.Context) error { + if len(ctx.Args()) < 1 { + utils.Fatalf("This command requires an argument.") + } + stack := makeFullNode(ctx) + defer stack.Close() + + diskdb := utils.MakeChainDatabase(ctx, stack).(*ethdb.LDBDatabase) + start := time.Now() + + if err := utils.ExportPreimages(diskdb, ctx.Args().First()); err != nil { + utils.Fatalf("Export error: %v\n", err) + } + fmt.Printf("Export done in %v\n", time.Since(start)) return nil } @@ -294,8 +379,9 @@ 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) @@ -366,6 +452,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/cmd/geth/config.go b/cmd/geth/config.go index 50e4de2e78..f316380cee 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -20,7 +20,7 @@ import ( "bufio" "errors" "fmt" - "io" + "math/big" "os" "reflect" "unicode" @@ -30,9 +30,10 @@ 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/whisperv5" + whisper "github.com/ethereum/go-ethereum/whisper/whisperv6" "github.com/naoina/toml" ) @@ -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) { @@ -168,9 +172,19 @@ func makeFullNode(ctx *cli.Context) *node.Node { if ctx.GlobalIsSet(utils.WhisperMinPOWFlag.Name) { cfg.Shh.MinimumAcceptedPOW = ctx.Float64(utils.WhisperMinPOWFlag.Name) } + if ctx.GlobalIsSet(utils.WhisperRestrictConnectionBetweenLightClientsFlag.Name) { + cfg.Shh.RestrictConnectionBetweenLightClients = true + } 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) @@ -192,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/cmd/geth/consolecmd.go b/cmd/geth/consolecmd.go index 9d5cc38a1b..d4443b3282 100644 --- a/cmd/geth/consolecmd.go +++ b/cmd/geth/consolecmd.go @@ -22,6 +22,7 @@ import ( "os/signal" "path/filepath" "strings" + "syscall" "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/console" @@ -42,7 +43,7 @@ var ( Description: ` The Geth console is an interactive shell for the JavaScript runtime environment which exposes a node admin interface as well as the Ðapp JavaScript API. -See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console.`, +See https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console.`, } attachCommand = cli.Command{ @@ -55,7 +56,7 @@ See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console.`, Description: ` The Geth console is an interactive shell for the JavaScript runtime environment which exposes a node admin interface as well as the Ðapp JavaScript API. -See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console. +See https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console. This command allows to open a console on a running geth node.`, } @@ -68,7 +69,7 @@ This command allows to open a console on a running geth node.`, Category: "CONSOLE COMMANDS", Description: ` The JavaScript VM exposes a node admin interface as well as the Ðapp -JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console`, +JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console`, } ) @@ -78,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() @@ -179,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() @@ -207,7 +208,7 @@ func ephemeralConsole(ctx *cli.Context) error { } // Wait for pending callbacks, but stop for Ctrl-C. abort := make(chan os.Signal, 1) - signal.Notify(abort, os.Interrupt) + signal.Notify(abort, syscall.SIGINT, syscall.SIGTERM) go func() { <-abort diff --git a/cmd/geth/consolecmd_test.go b/cmd/geth/consolecmd_test.go index 258b9e6dd9..34ba877020 100644 --- a/cmd/geth/consolecmd_test.go +++ b/cmd/geth/consolecmd_test.go @@ -31,7 +31,7 @@ import ( ) const ( - ipcAPIs = "admin:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 shh:1.0 txpool:1.0 web3:1.0" + ipcAPIs = "admin:1.0 debug:1.0 eth:1.0 ethash:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 shh:1.0 txpool:1.0 web3:1.0" httpAPIs = "eth:1.0 net:1.0 rpc:1.0 web3:1.0" ) @@ -50,7 +50,7 @@ func TestConsoleWelcome(t *testing.T) { geth.SetTemplateFunc("goos", func() string { return runtime.GOOS }) geth.SetTemplateFunc("goarch", func() string { return runtime.GOARCH }) geth.SetTemplateFunc("gover", runtime.Version) - geth.SetTemplateFunc("gethver", func() string { return params.Version }) + geth.SetTemplateFunc("gethver", func() string { return params.VersionWithMeta }) geth.SetTemplateFunc("niltime", func() string { return time.Unix(0, 0).Format(time.RFC1123) }) geth.SetTemplateFunc("apis", func() string { return ipcAPIs }) @@ -133,7 +133,7 @@ func testAttachWelcome(t *testing.T, geth *testgeth, endpoint, apis string) { attach.SetTemplateFunc("goos", func() string { return runtime.GOOS }) attach.SetTemplateFunc("goarch", func() string { return runtime.GOARCH }) attach.SetTemplateFunc("gover", runtime.Version) - attach.SetTemplateFunc("gethver", func() string { return params.Version }) + attach.SetTemplateFunc("gethver", func() string { return params.VersionWithMeta }) attach.SetTemplateFunc("etherbase", func() string { return geth.Etherbase }) attach.SetTemplateFunc("niltime", func() string { return time.Unix(0, 0).Format(time.RFC1123) }) attach.SetTemplateFunc("ipc", func() bool { return strings.HasPrefix(endpoint, "ipc") }) diff --git a/cmd/geth/dao_test.go b/cmd/geth/dao_test.go index a8dbc51630..52983ff2af 100644 --- a/cmd/geth/dao_test.go +++ b/cmd/geth/dao_test.go @@ -24,7 +24,7 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" ) @@ -131,8 +131,8 @@ func testDAOForkBlockNewChain(t *testing.T, test int, genesis string, expectBloc if genesis != "" { genesisHash = daoGenesisHash } - config, err := core.GetChainConfig(db, genesisHash) - if err != nil { + config := rawdb.ReadChainConfig(db, genesisHash) + if config == nil { t.Errorf("test %d: failed to retrieve chain config: %v", test, err) return // we want to return here, the other checks can't make it past this point (nil panic). } diff --git a/cmd/geth/genesis_test.go b/cmd/geth/genesis_test.go index a00ae00c19..e75b542cbb 100644 --- a/cmd/geth/genesis_test.go +++ b/cmd/geth/genesis_test.go @@ -77,7 +77,7 @@ var customGenesisTests = []struct { "homesteadBlock" : 314, "daoForkBlock" : 141, "daoForkSupport" : true - }, + } }`, query: "eth.getBlock(0).nonce", result: "0x0000000000000042", diff --git a/cmd/geth/main.go b/cmd/geth/main.go index b955bd243e..a331abc9fd 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -19,24 +19,28 @@ package main import ( "fmt" + "math" "os" - "runtime" + godebug "runtime/debug" "sort" + "strconv" "strings" "time" + "github.com/elastic/gosigar" "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 ( @@ -46,8 +50,6 @@ const ( var ( // Git SHA1 commit hash of the release (set via linker flags) gitCommit = "" - // Ethereum address of the Geth release oracle. - relOracle = common.HexToAddress("0xfa7b9770ca4cb04296cac84f37736d4041251cdf") // The app that holds all commands and flags. app = utils.NewApp(gitCommit, "the go-ethereum command line interface") // flags that configure the node @@ -60,18 +62,19 @@ var ( utils.BootnodesV5Flag, utils.DataDirFlag, utils.KeyStoreDirFlag, + utils.ExternalSignerFlag, utils.NoUSBFlag, utils.DashboardEnabledFlag, utils.DashboardAddrFlag, utils.DashboardPortFlag, utils.DashboardRefreshFlag, - utils.DashboardAssetsFlag, utils.EthashCacheDirFlag, utils.EthashCachesInMemoryFlag, utils.EthashCachesOnDiskFlag, utils.EthashDatasetDirFlag, utils.EthashDatasetsInMemoryFlag, utils.EthashDatasetsOnDiskFlag, + utils.TxPoolLocalsFlag, utils.TxPoolNoLocalsFlag, utils.TxPoolJournalFlag, utils.TxPoolRejournalFlag, @@ -82,22 +85,42 @@ var ( utils.TxPoolAccountQueueFlag, utils.TxPoolGlobalQueueFlag, utils.TxPoolLifetimeFlag, - utils.FastSyncFlag, - utils.LightModeFlag, + 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, - utils.EtherbaseFlag, - utils.GasPriceFlag, - utils.MinerThreadsFlag, utils.MiningEnabledFlag, - utils.TargetGasLimitFlag, + utils.MinerThreadsFlag, + utils.MinerLegacyThreadsFlag, + utils.MinerNotifyFlag, + utils.MinerGasTargetFlag, + utils.MinerLegacyGasTargetFlag, + utils.MinerGasLimitFlag, + utils.MinerGasPriceFlag, + utils.MinerLegacyGasPriceFlag, + utils.MinerEtherbaseFlag, + utils.MinerLegacyEtherbaseFlag, + utils.MinerExtraDataFlag, + utils.MinerLegacyExtraDataFlag, + utils.MinerRecommitIntervalFlag, + utils.MinerNoVerfiyFlag, utils.NATFlag, utils.NoDiscoverFlag, utils.DiscoveryV5Flag, @@ -108,16 +131,20 @@ 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, utils.GpoPercentileFlag, - utils.ExtraDataFlag, + utils.EWASMInterpreterFlag, + utils.EVMInterpreterFlag, configFileFlag, } @@ -125,6 +152,11 @@ var ( utils.RPCEnabledFlag, utils.RPCListenAddrFlag, utils.RPCPortFlag, + utils.GraphQLEnabledFlag, + utils.GraphQLListenAddrFlag, + utils.GraphQLPortFlag, + utils.GraphQLCORSDomainFlag, + utils.GraphQLVirtualHostsFlag, utils.RPCApiFlag, utils.WSEnabledFlag, utils.WSListenAddrFlag, @@ -139,6 +171,16 @@ var ( utils.WhisperEnabledFlag, utils.WhisperMaxMessageSizeFlag, utils.WhisperMinPOWFlag, + utils.WhisperRestrictConnectionBetweenLightClientsFlag, + } + + metricsFlags = []cli.Flag{ + utils.MetricsEnableInfluxDBFlag, + utils.MetricsInfluxDBEndpointFlag, + utils.MetricsInfluxDBDatabaseFlag, + utils.MetricsInfluxDBUsernameFlag, + utils.MetricsInfluxDBPasswordFlag, + utils.MetricsInfluxDBTagsFlag, } ) @@ -146,12 +188,14 @@ 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-2017 The go-ethereum Authors" + app.Copyright = "Copyright 2013-2019 The go-ethereum Authors" app.Commands = []cli.Command{ // See chaincmd.go: initCommand, importCommand, exportCommand, + importPreimagesCommand, + exportPreimagesCommand, copydbCommand, removedbCommand, dumpCommand, @@ -180,16 +224,38 @@ func init() { app.Flags = append(app.Flags, consoleFlags...) app.Flags = append(app.Flags, debug.Flags...) app.Flags = append(app.Flags, whisperFlags...) + app.Flags = append(app.Flags, metricsFlags...) app.Before = func(ctx *cli.Context) error { - runtime.GOMAXPROCS(runtime.NumCPU()) - if err := debug.Setup(ctx); err != nil { + logdir := "" + if ctx.GlobalBool(utils.DashboardEnabledFlag.Name) { + logdir = (&node.Config{DataDir: utils.MakeDataDir(ctx)}).ResolvePath("logs") + } + if err := debug.Setup(ctx, logdir); err != nil { return err } + // Cap the cache allowance and tune the garbage collector + var mem gosigar.Mem + if err := mem.Get(); err == nil { + allowance := int(mem.Total / 1024 / 1024 / 3) + if cache := ctx.GlobalInt(utils.CacheFlag.Name); cache > allowance { + log.Warn("Sanitizing cache to Go's GC limits", "provided", cache, "updated", allowance) + ctx.GlobalSet(utils.CacheFlag.Name, strconv.Itoa(allowance)) + } + } + // Ensure Go's GC ignores the database cache for trigger percentage + cache := ctx.GlobalInt(utils.CacheFlag.Name) + gogc := math.Max(20, math.Min(100, 100/(float64(cache)/1024))) + + log.Debug("Sanitizing Go's GC trigger", "percent", int(gogc)) + godebug.SetGCPercent(int(gogc)) + + // Start metrics export if enabled + utils.SetupMetrics(ctx) + // Start system runtime metrics collection go metrics.CollectProcessMetrics(3 * time.Second) - utils.SetupNetwork(ctx) return nil } @@ -211,7 +277,11 @@ func main() { // It creates a default node based on the command line arguments and runs it in // blocking mode, waiting for it to be shut down. func geth(ctx *cli.Context) error { + if args := ctx.Args(); len(args) > 0 { + return fmt.Errorf("invalid command: %q", args[0]) + } node := makeFullNode(ctx) + defer node.Close() startNode(ctx, node) node.Wait() return nil @@ -221,17 +291,20 @@ func geth(ctx *cli.Context) error { // it unlocks any requested accounts, and starts the RPC/IPC interfaces and the // miner. func startNode(ctx *cli.Context, stack *node.Node) { + debug.Memsize.Add("node", stack) + // Start up the node itself 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 @@ -239,7 +312,7 @@ func startNode(ctx *cli.Context, stack *node.Node) { stack.AccountManager().Subscribe(events) go func() { - // Create an chain state reader for self-derivation + // Create a chain state reader for self-derivation rpcClient, err := stack.Attach() if err != nil { utils.Fatalf("Failed to attach to self: %v", err) @@ -263,11 +336,11 @@ func startNode(ctx *cli.Context, stack *node.Node) { status, _ := event.Wallet.Status() log.Info("New wallet appeared", "url", event.Wallet.URL(), "status", status) + derivationPath := accounts.DefaultBaseDerivationPath if event.Wallet.URL().Scheme == "ledger" { - event.Wallet.SelfDerive(accounts.DefaultLedgerBaseDerivationPath, stateReader) - } else { - event.Wallet.SelfDerive(accounts.DefaultBaseDerivationPath, stateReader) + derivationPath = accounts.DefaultLedgerBaseDerivationPath } + event.Wallet.SelfDerive(derivationPath, stateReader) case accounts.WalletDropped: log.Info("Old wallet dropped", "url", event.Wallet.URL()) @@ -275,28 +348,54 @@ 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 - if ctx.GlobalBool(utils.LightModeFlag.Name) || ctx.GlobalString(utils.SyncModeFlag.Name) == "light" { + if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" { utils.Fatalf("Light clients do not support mining") } var ethereum *eth.Ethereum if err := stack.Service(ðereum); err != nil { utils.Fatalf("Ethereum service not running: %v", err) } - // Use a reduced number of threads if requested - if threads := ctx.GlobalInt(utils.MinerThreadsFlag.Name); threads > 0 { - type threaded interface { - SetThreads(threads int) - } - if th, ok := ethereum.Engine().(threaded); ok { - th.SetThreads(threads) - } - } // Set the gas price to the limits from the CLI and start mining - ethereum.TxPool().SetGasPrice(utils.GlobalBig(ctx, utils.GasPriceFlag.Name)) - if err := ethereum.StartMining(true); err != nil { + gasprice := utils.GlobalBig(ctx, utils.MinerLegacyGasPriceFlag.Name) + if ctx.IsSet(utils.MinerGasPriceFlag.Name) { + gasprice = utils.GlobalBig(ctx, utils.MinerGasPriceFlag.Name) + } + ethereum.TxPool().SetGasPrice(gasprice) + + threads := ctx.GlobalInt(utils.MinerLegacyThreadsFlag.Name) + if ctx.GlobalIsSet(utils.MinerThreadsFlag.Name) { + threads = ctx.GlobalInt(utils.MinerThreadsFlag.Name) + } + if err := ethereum.StartMining(threads); err != nil { utils.Fatalf("Failed to start mining: %v", err) } } diff --git a/cmd/geth/misccmd.go b/cmd/geth/misccmd.go index aa9b1ee568..f62e254786 100644 --- a/cmd/geth/misccmd.go +++ b/cmd/geth/misccmd.go @@ -108,7 +108,7 @@ func makedag(ctx *cli.Context) error { func version(ctx *cli.Context) error { fmt.Println(strings.Title(clientIdentifier)) - fmt.Println("Version:", params.Version) + fmt.Println("Version:", params.VersionWithMeta) if gitCommit != "" { fmt.Println("Git Commit:", gitCommit) } diff --git a/cmd/geth/monitorcmd.go b/cmd/geth/monitorcmd.go index cd19caa276..34e090e1ec 100644 --- a/cmd/geth/monitorcmd.go +++ b/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,18 +179,18 @@ 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) if len(parts) > 1 { for _, variation := range strings.Split(parts[0], ",") { - if submetrics, ok := metrics[variation].(map[string]interface{}); !ok { + submetrics, ok := metrics[variation].(map[string]interface{}) + if !ok { utils.Fatalf("Failed to retrieve system metrics: %s", path+variation) return nil - } else { - results = append(results, resolveMetric(submetrics, parts[1], path+variation+"/")...) } + results = append(results, resolveMetric(submetrics, parts[1], path+variation+"/")...) } return results } @@ -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/cmd/geth/usage.go b/cmd/geth/usage.go index a834d5b7ae..0338e447e4 100644 --- a/cmd/geth/usage.go +++ b/cmd/geth/usage.go @@ -22,17 +22,18 @@ import ( "io" "sort" + "strings" + "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/internal/debug" - "gopkg.in/urfave/cli.v1" - "strings" + 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-2017 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}} @@ -73,15 +74,22 @@ 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, }, }, - {Name: "DEVELOPER CHAIN", + { + Name: "DEVELOPER CHAIN", Flags: []cli.Flag{ utils.DeveloperFlag, utils.DeveloperPeriodFlag, @@ -111,6 +119,7 @@ var AppHelpFlagGroups = []flagGroup{ { Name: "TRANSACTION POOL", Flags: []cli.Flag{ + utils.TxPoolLocalsFlag, utils.TxPoolNoLocalsFlag, utils.TxPoolJournalFlag, utils.TxPoolRejournalFlag, @@ -127,6 +136,9 @@ var AppHelpFlagGroups = []flagGroup{ Name: "PERFORMANCE TUNING", Flags: []cli.Flag{ utils.CacheFlag, + utils.CacheDatabaseFlag, + utils.CacheTrieFlag, + utils.CacheGCFlag, utils.TrieCacheGenFlag, }, }, @@ -135,6 +147,7 @@ var AppHelpFlagGroups = []flagGroup{ Flags: []cli.Flag{ utils.UnlockedAccountFlag, utils.PasswordFileFlag, + utils.ExternalSignerFlag, }, }, { @@ -152,6 +165,7 @@ var AppHelpFlagGroups = []flagGroup{ utils.IPCDisabledFlag, utils.IPCPathFlag, utils.RPCCORSDomainFlag, + utils.RPCVirtualHostsFlag, utils.JSpathFlag, utils.ExecFlag, utils.PreloadJSFlag, @@ -179,10 +193,14 @@ var AppHelpFlagGroups = []flagGroup{ Flags: []cli.Flag{ utils.MiningEnabledFlag, utils.MinerThreadsFlag, - utils.EtherbaseFlag, - utils.TargetGasLimitFlag, - utils.GasPriceFlag, - utils.ExtraDataFlag, + utils.MinerNotifyFlag, + utils.MinerGasPriceFlag, + utils.MinerGasTargetFlag, + utils.MinerGasLimitFlag, + utils.MinerEtherbaseFlag, + utils.MinerExtraDataFlag, + utils.MinerRecommitIntervalFlag, + utils.MinerNoVerfiyFlag, }, }, { @@ -196,16 +214,29 @@ var AppHelpFlagGroups = []flagGroup{ Name: "VIRTUAL MACHINE", Flags: []cli.Flag{ utils.VMEnableDebugFlag, + utils.EVMInterpreterFlag, + utils.EWASMInterpreterFlag, }, }, { Name: "LOGGING AND DEBUGGING", Flags: append([]cli.Flag{ - utils.MetricsEnabledFlag, utils.FakePoWFlag, utils.NoCompactionFlag, }, debug.Flags...), }, + { + Name: "METRICS AND STATS", + Flags: []cli.Flag{ + utils.MetricsEnabledFlag, + utils.MetricsEnableInfluxDBFlag, + utils.MetricsInfluxDBEndpointFlag, + utils.MetricsInfluxDBDatabaseFlag, + utils.MetricsInfluxDBUsernameFlag, + utils.MetricsInfluxDBPasswordFlag, + utils.MetricsInfluxDBTagsFlag, + }, + }, { Name: "WHISPER (EXPERIMENTAL)", Flags: whisperFlags, @@ -213,8 +244,11 @@ var AppHelpFlagGroups = []flagGroup{ { Name: "DEPRECATED", Flags: []cli.Flag{ - utils.FastSyncFlag, - utils.LightModeFlag, + utils.MinerLegacyThreadsFlag, + utils.MinerLegacyGasTargetFlag, + utils.MinerLegacyGasPriceFlag, + utils.MinerLegacyEtherbaseFlag, + utils.MinerLegacyExtraDataFlag, }, }, { @@ -276,7 +310,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/cmd/p2psim/main.go b/cmd/p2psim/main.go index 56b74d135b..f2c1bf9703 100644 --- a/cmd/p2psim/main.go +++ b/cmd/p2psim/main.go @@ -1,3 +1,19 @@ +// Copyright 2017 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 . + // p2psim provides a command-line client for a simulation HTTP API. // // Here is an example of creating a 2 node network with the first node @@ -31,7 +47,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/discover" + "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" @@ -164,7 +180,10 @@ func main() { }, }, } - app.Run(os.Args) + if err := app.Run(os.Args); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } } func showNetwork(ctx *cli.Context) error { @@ -259,15 +278,14 @@ func createNode(ctx *cli.Context) error { if len(ctx.Args()) != 0 { return cli.ShowCommandHelp(ctx, ctx.Command.Name) } - config := &adapters.NodeConfig{ - Name: ctx.String("name"), - } + config := adapters.RandomNodeConfig() + config.Name = ctx.String("name") if key := ctx.String("key"); key != "" { privKey, err := crypto.HexToECDSA(key) if err != nil { return err } - config.ID = discover.PubkeyID(&privKey.PublicKey) + config.ID = enode.PubkeyToIDV4(&privKey.PublicKey) config.PrivateKey = privKey } if services := ctx.String("services"); services != "" { diff --git a/cmd/puppeth/genesis.go b/cmd/puppeth/genesis.go index f747f47395..ae7675cd9b 100644 --- a/cmd/puppeth/genesis.go +++ b/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) - spec.Params.NetworkID = (hexutil.Uint64)(genesis.Config.ChainId.Uint64()) - spec.Params.ChainID = (hexutil.Uint64)(genesis.Config.ChainId.Uint64()) + // 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"` - GasLimitBoundDivisor hexutil.Uint64 `json:"gasLimitBoundDivisor"` - 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"` - 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.GasLimitBoundDivisor = (hexutil.Uint64)(params.GasLimitBoundDivisor) 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.NetworkID = (hexutil.Uint64)(genesis.Config.ChainId.Uint64()) + 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/cmd/puppeth/genesis_test.go b/cmd/puppeth/genesis_test.go new file mode 100644 index 0000000000..83e7383605 --- /dev/null +++ b/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/cmd/puppeth/module_dashboard.go b/cmd/puppeth/module_dashboard.go index 1092c4c88e..9a77587b4a 100644 --- a/cmd/puppeth/module_dashboard.go +++ b/cmd/puppeth/module_dashboard.go @@ -117,7 +117,7 @@ var dashboardContent = `

To run an archive node, download {{.GethGenesis}} and start Geth with:

geth --datadir=$HOME/.{{.Network}} init {{.GethGenesis}}
-
geth --networkid={{.NetworkID}} --datadir=$HOME/.{{.Network}} --cache=1024 --syncmode=full{{if .Ethstats}} --ethstats='{{.Ethstats}}'{{end}} --bootnodes={{.BootnodesFullFlat}}
+
geth --networkid={{.NetworkID}} --datadir=$HOME/.{{.Network}} --cache=1024 --syncmode=full{{if .Ethstats}} --ethstats='{{.Ethstats}}'{{end}} --bootnodes={{.BootnodesFlat}}


You can download Geth from https://geth.ethereum.org/downloads/.

@@ -136,7 +136,7 @@ var dashboardContent = `

To run a full node, download {{.GethGenesis}} and start Geth with:

geth --datadir=$HOME/.{{.Network}} init {{.GethGenesis}}
-
geth --networkid={{.NetworkID}} --datadir=$HOME/.{{.Network}} --cache=512{{if .Ethstats}} --ethstats='{{.Ethstats}}'{{end}} --bootnodes={{.BootnodesFullFlat}}
+
geth --networkid={{.NetworkID}} --datadir=$HOME/.{{.Network}} --cache=512{{if .Ethstats}} --ethstats='{{.Ethstats}}'{{end}} --bootnodes={{.BootnodesFlat}}


You can download Geth from https://geth.ethereum.org/downloads/.

@@ -158,7 +158,7 @@ var dashboardContent = `

To run a light node, download {{.GethGenesis}} and start Geth with:

geth --datadir=$HOME/.{{.Network}} init {{.GethGenesis}}
-
geth --networkid={{.NetworkID}} --datadir=$HOME/.{{.Network}} --syncmode=light{{if .Ethstats}} --ethstats='{{.Ethstats}}'{{end}} --bootnodes={{.BootnodesLightFlat}}
+
geth --networkid={{.NetworkID}} --datadir=$HOME/.{{.Network}} --syncmode=light{{if .Ethstats}} --ethstats='{{.Ethstats}}'{{end}} --bootnodes={{.BootnodesFlat}}


You can download Geth from https://geth.ethereum.org/downloads/.

@@ -177,7 +177,7 @@ var dashboardContent = `

To run an embedded node, download {{.GethGenesis}} and start Geth with:

geth --datadir=$HOME/.{{.Network}} init {{.GethGenesis}}
-
geth --networkid={{.NetworkID}} --datadir=$HOME/.{{.Network}} --cache=16 --ethash.cachesinmem=1 --syncmode=light{{if .Ethstats}} --ethstats='{{.Ethstats}}'{{end}} --bootnodes={{.BootnodesLightFlat}}
+
geth --networkid={{.NetworkID}} --datadir=$HOME/.{{.Network}} --cache=16 --ethash.cachesinmem=1 --syncmode=light{{if .Ethstats}} --ethstats='{{.Ethstats}}'{{end}} --bootnodes={{.BootnodesFlat}}


You can download Geth from https://geth.ethereum.org/downloads/.

@@ -208,7 +208,7 @@ var dashboardContent = `
geth --datadir=$HOME/.{{.Network}} init {{.GethGenesis}}

With your local chain initialized, you can start the Ethereum Wallet: -

ethereumwallet --rpc $HOME/.{{.Network}}/geth.ipc --node-networkid={{.NetworkID}} --node-datadir=$HOME/.{{.Network}}{{if .Ethstats}} --node-ethstats='{{.Ethstats}}'{{end}} --node-bootnodes={{.BootnodesFullFlat}}
+
ethereumwallet --rpc $HOME/.{{.Network}}/geth.ipc --node-networkid={{.NetworkID}} --node-datadir=$HOME/.{{.Network}}{{if .Ethstats}} --node-ethstats='{{.Ethstats}}'{{end}} --node-bootnodes={{.BootnodesFlat}}


You can download the Ethereum Wallet from https://github.com/ethereum/mist/releases.

@@ -229,7 +229,7 @@ var dashboardContent = `
geth --datadir=$HOME/.{{.Network}} init {{.GethGenesis}}

With your local chain initialized, you can start Mist: -

mist --rpc $HOME/.{{.Network}}/geth.ipc --node-networkid={{.NetworkID}} --node-datadir=$HOME/.{{.Network}}{{if .Ethstats}} --node-ethstats='{{.Ethstats}}'{{end}} --node-bootnodes={{.BootnodesFullFlat}}
+
mist --rpc $HOME/.{{.Network}}/geth.ipc --node-networkid={{.NetworkID}} --node-datadir=$HOME/.{{.Network}}{{if .Ethstats}} --node-ethstats='{{.Ethstats}}'{{end}} --node-bootnodes={{.BootnodesFlat}}


You can download the Mist browser from https://github.com/ethereum/mist/releases.

@@ -261,7 +261,7 @@ var dashboardContent = `

Inside your Java code you can now import the geth archive and connect to Ethereum:

import org.ethereum.geth.*;
-Enodes bootnodes = new Enodes();{{range .BootnodesLight}}
+Enodes bootnodes = new Enodes();{{range .Bootnodes}}
 bootnodes.append(new Enode("{{.}}"));{{end}}
 
 NodeConfig config = new NodeConfig();
@@ -294,7 +294,7 @@ node.start();
 
 var error: NSError?
 
-let bootnodes = GethNewEnodesEmpty(){{range .BootnodesLight}}
+let bootnodes = GethNewEnodesEmpty(){{range .Bootnodes}}
 bootnodes?.append(GethNewEnode("{{.}}", &error)){{end}}
 
 let config = GethNewNodeConfig()
@@ -595,44 +595,44 @@ func deployDashboard(client *sshClient, network string, conf *config, config *da
 		statsLogin = ""
 	}
 	indexfile := new(bytes.Buffer)
-	bootCpp := make([]string, len(conf.bootFull))
-	for i, boot := range conf.bootFull {
+	bootCpp := make([]string, len(conf.bootnodes))
+	for i, boot := range conf.bootnodes {
 		bootCpp[i] = "required:" + strings.TrimPrefix(boot, "enode://")
 	}
-	bootHarmony := make([]string, len(conf.bootFull))
-	for i, boot := range conf.bootFull {
+	bootHarmony := make([]string, len(conf.bootnodes))
+	for i, boot := range conf.bootnodes {
 		bootHarmony[i] = fmt.Sprintf("-Dpeer.active.%d.url=%s", i, boot)
 	}
-	bootPython := make([]string, len(conf.bootFull))
-	for i, boot := range conf.bootFull {
+	bootPython := make([]string, len(conf.bootnodes))
+	for i, boot := range conf.bootnodes {
 		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",
-		"BootnodesFull":      conf.bootFull,
-		"BootnodesLight":     conf.bootLight,
-		"BootnodesFullFlat":  strings.Join(conf.bootFull, ","),
-		"BootnodesLightFlat": strings.Join(conf.bootLight, ","),
-		"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,
+		"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()
 
@@ -641,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
 		}
@@ -651,7 +651,7 @@ func deployDashboard(client *sshClient, network string, conf *config, config *da
 		harmonySpecJSON, _ := conf.Genesis.MarshalJSON()
 		files[filepath.Join(workdir, network+"-harmony.json")] = harmonySpecJSON
 
-		paritySpec, err := newParityChainSpec(network, conf.Genesis, conf.bootFull)
+		paritySpec, err := newParityChainSpec(network, conf.Genesis, conf.bootnodes)
 		if err != nil {
 			return nil, err
 		}
@@ -679,12 +679,12 @@ func deployDashboard(client *sshClient, network string, conf *config, config *da
 
 	// Build and deploy the dashboard service
 	if nocache {
-		return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s build --pull --no-cache && docker-compose -p %s up -d --force-recreate", workdir, network, network))
+		return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s build --pull --no-cache && docker-compose -p %s up -d --force-recreate --timeout 60", workdir, network, network))
 	}
-	return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s up -d --build --force-recreate", workdir, network))
+	return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s up -d --build --force-recreate --timeout 60", workdir, network))
 }
 
-// dashboardInfos is returned from an dashboard status check to allow reporting
+// dashboardInfos is returned from a dashboard status check to allow reporting
 // various configuration parameters.
 type dashboardInfos struct {
 	host    string
diff --git a/cmd/puppeth/module_ethstats.go b/cmd/puppeth/module_ethstats.go
index 20b7afe236..58ecb83951 100644
--- a/cmd/puppeth/module_ethstats.go
+++ b/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:
@@ -100,9 +101,9 @@ func deployEthstats(client *sshClient, network string, port int, secret string,
 
 	// Build and deploy the ethstats service
 	if nocache {
-		return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s build --pull --no-cache && docker-compose -p %s up -d --force-recreate", workdir, network, network))
+		return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s build --pull --no-cache && docker-compose -p %s up -d --force-recreate --timeout 60", workdir, network, network))
 	}
-	return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s up -d --build --force-recreate", workdir, network))
+	return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s up -d --build --force-recreate --timeout 60", workdir, network))
 }
 
 // ethstatsInfos is returned from an ethstats status check to allow reporting
@@ -122,7 +123,7 @@ func (info *ethstatsInfos) Report() map[string]string {
 		"Website address":       info.host,
 		"Website listener port": strconv.Itoa(info.port),
 		"Login secret":          info.secret,
-		"Banned addresses":      fmt.Sprintf("%v", info.banned),
+		"Banned addresses":      strings.Join(info.banned, "\n"),
 	}
 }
 
diff --git a/cmd/puppeth/module_explorer.go b/cmd/puppeth/module_explorer.go
index 427134153b..e465fa04ad 100644
--- a/cmd/puppeth/module_explorer.go
+++ b/cmd/puppeth/module_explorer.go
@@ -38,7 +38,7 @@ ADD chain.json /chain.json
 RUN \
   echo '(cd ../eth-net-intelligence-api && pm2 start /ethstats.json)' >  explorer.sh && \
 	echo '(cd ../etherchain-light && npm start &)'                      >> explorer.sh && \
-	echo '/parity/parity --chain=/chain.json --port={{.NodePort}} --tracing=on --fat-db=on --pruning=archive' >> explorer.sh
+	echo 'exec /parity/parity --chain=/chain.json --port={{.NodePort}} --tracing=on --fat-db=on --pruning=archive' >> explorer.sh
 
 ENTRYPOINT ["/bin/sh", "explorer.sh"]
 `
@@ -77,6 +77,7 @@ services:
   explorer:
     build: .
     image: {{.Network}}/explorer
+    container_name: {{.Network}}_explorer_1
     ports:
       - "{{.NodePort}}:{{.NodePort}}"
       - "{{.NodePort}}:{{.NodePort}}/udp"{{if not .VHost}}
@@ -140,9 +141,9 @@ func deployExplorer(client *sshClient, network string, chainspec []byte, config
 
 	// Build and deploy the boot or seal node service
 	if nocache {
-		return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s build --pull --no-cache && docker-compose -p %s up -d --force-recreate", workdir, network, network))
+		return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s build --pull --no-cache && docker-compose -p %s up -d --force-recreate --timeout 60", workdir, network, network))
 	}
-	return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s up -d --build --force-recreate", workdir, network))
+	return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s up -d --build --force-recreate --timeout 60", workdir, network))
 }
 
 // explorerInfos is returned from a block explorer status check to allow reporting
@@ -168,7 +169,7 @@ func (info *explorerInfos) Report() map[string]string {
 	return report
 }
 
-// checkExplorer does a health-check against an block explorer server to verify
+// checkExplorer does a health-check against a block explorer server to verify
 // whether it's running, and if yes, whether it's responsive.
 func checkExplorer(client *sshClient, network string) (*explorerInfos, error) {
 	// Inspect a possible block explorer container on the host
diff --git a/cmd/puppeth/module_faucet.go b/cmd/puppeth/module_faucet.go
index 92b4cb2861..3a06bf3c68 100644
--- a/cmd/puppeth/module_faucet.go
+++ b/cmd/puppeth/module_faucet.go
@@ -30,7 +30,7 @@ import (
 	"github.com/ethereum/go-ethereum/log"
 )
 
-// faucetDockerfile is the Dockerfile required to build an faucet container to
+// faucetDockerfile is the Dockerfile required to build a faucet container to
 // grant crypto tokens based on GitHub authentications.
 var faucetDockerfile = `
 FROM ethereum/client-go:alltools-latest
@@ -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
@@ -93,7 +95,7 @@ func deployFaucet(client *sshClient, network string, bootnodes []string, config
 		"NetworkID":     config.node.network,
 		"Bootnodes":     strings.Join(bootnodes, ","),
 		"Ethstats":      config.node.ethstats,
-		"EthPort":       config.node.portFull,
+		"EthPort":       config.node.port,
 		"CaptchaToken":  config.captchaToken,
 		"CaptchaSecret": config.captchaSecret,
 		"FaucetName":    strings.Title(network),
@@ -110,7 +112,7 @@ func deployFaucet(client *sshClient, network string, bootnodes []string, config
 		"Datadir":       config.node.datadir,
 		"VHost":         config.host,
 		"ApiPort":       config.port,
-		"EthPort":       config.node.portFull,
+		"EthPort":       config.node.port,
 		"EthName":       config.node.ethstats[:strings.Index(config.node.ethstats, ":")],
 		"CaptchaToken":  config.captchaToken,
 		"CaptchaSecret": config.captchaSecret,
@@ -133,12 +135,12 @@ func deployFaucet(client *sshClient, network string, bootnodes []string, config
 
 	// Build and deploy the faucet service
 	if nocache {
-		return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s build --pull --no-cache && docker-compose -p %s up -d --force-recreate", workdir, network, network))
+		return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s build --pull --no-cache && docker-compose -p %s up -d --force-recreate --timeout 60", workdir, network, network))
 	}
-	return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s up -d --build --force-recreate", workdir, network))
+	return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s up -d --build --force-recreate --timeout 60", workdir, network))
 }
 
-// faucetInfos is returned from an faucet status check to allow reporting various
+// faucetInfos is returned from a faucet status check to allow reporting various
 // configuration parameters.
 type faucetInfos struct {
 	node          *nodeInfos
@@ -158,7 +160,7 @@ func (info *faucetInfos) Report() map[string]string {
 	report := map[string]string{
 		"Website address":              info.host,
 		"Website listener port":        strconv.Itoa(info.port),
-		"Ethereum listener port":       strconv.Itoa(info.node.portFull),
+		"Ethereum listener port":       strconv.Itoa(info.node.port),
 		"Funding amount (base tier)":   fmt.Sprintf("%d Ethers", info.amount),
 		"Funding cooldown (base tier)": fmt.Sprintf("%d mins", info.minutes),
 		"Funding tiers":                strconv.Itoa(info.tiers),
@@ -181,7 +183,7 @@ func (info *faucetInfos) Report() map[string]string {
 	return report
 }
 
-// checkFaucet does a health-check against an faucet server to verify whether
+// checkFaucet does a health-check against a faucet server to verify whether
 // it's running, and if yes, gathering a collection of useful infos about it.
 func checkFaucet(client *sshClient, network string) (*faucetInfos, error) {
 	// Inspect a possible faucet container on the host
@@ -228,7 +230,7 @@ func checkFaucet(client *sshClient, network string) (*faucetInfos, error) {
 	return &faucetInfos{
 		node: &nodeInfos{
 			datadir:  infos.volumes["/root/.faucet"],
-			portFull: infos.portmap[infos.envvars["ETH_PORT"]+"/tcp"],
+			port:     infos.portmap[infos.envvars["ETH_PORT"]+"/tcp"],
 			ethstats: infos.envvars["ETH_NAME"],
 			keyJSON:  keyJSON,
 			keyPass:  keyPass,
diff --git a/cmd/puppeth/module_nginx.go b/cmd/puppeth/module_nginx.go
index 35c0efc8ad..1b1ae61ff5 100644
--- a/cmd/puppeth/module_nginx.go
+++ b/cmd/puppeth/module_nginx.go
@@ -40,6 +40,7 @@ services:
   nginx:
     build: .
     image: {{.Network}}/nginx
+    container_name: {{.Network}}_nginx_1
     ports:
       - "{{.Port}}:80"
     volumes:
@@ -81,9 +82,9 @@ func deployNginx(client *sshClient, network string, port int, nocache bool) ([]b
 
 	// Build and deploy the reverse-proxy service
 	if nocache {
-		return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s build --pull --no-cache && docker-compose -p %s up -d --force-recreate", workdir, network, network))
+		return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s build --pull --no-cache && docker-compose -p %s up -d --force-recreate --timeout 60", workdir, network, network))
 	}
-	return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s up -d --build --force-recreate", workdir, network))
+	return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s up -d --build --force-recreate --timeout 60", workdir, network))
 }
 
 // nginxInfos is returned from an nginx reverse-proxy status check to allow
diff --git a/cmd/puppeth/module_node.go b/cmd/puppeth/module_node.go
index 69cb19c349..5d9ef46523 100644
--- a/cmd/puppeth/module_node.go
+++ b/cmd/puppeth/module_node.go
@@ -42,7 +42,7 @@ ADD genesis.json /genesis.json
 RUN \
   echo 'geth --cache 512 init /genesis.json' > geth.sh && \{{if .Unlock}}
 	echo 'mkdir -p /root/.ethereum/keystore/ && cp /signer.json /root/.ethereum/keystore/' >> geth.sh && \{{end}}
-	echo $'geth --networkid {{.NetworkID}} --cache 512 --port {{.Port}} --maxpeers {{.Peers}} {{.LightFlag}} --ethstats \'{{.Ethstats}}\' {{if .BootV4}}--bootnodesv4 {{.BootV4}}{{end}} {{if .BootV5}}--bootnodesv5 {{.BootV5}}{{end}} {{if .Etherbase}}--etherbase {{.Etherbase}} --mine --minerthreads 1{{end}} {{if .Unlock}}--unlock 0 --password /signer.pass --mine{{end}} --targetgaslimit {{.GasTarget}} --gasprice {{.GasPrice}}' >> geth.sh
+	echo $'exec geth --networkid {{.NetworkID}} --cache 512 --port {{.Port}} --nat extip:{{.IP}} --maxpeers {{.Peers}} {{.LightFlag}} --ethstats \'{{.Ethstats}}\' {{if .Bootnodes}}--bootnodes {{.Bootnodes}}{{end}} {{if .Etherbase}}--miner.etherbase {{.Etherbase}} --mine --miner.threads 1{{end}} {{if .Unlock}}--unlock 0 --password /signer.pass --mine{{end}} --miner.gastarget {{.GasTarget}} --miner.gaslimit {{.GasLimit}} --miner.gasprice {{.GasPrice}}' >> geth.sh
 
 ENTRYPOINT ["/bin/sh", "geth.sh"]
 `
@@ -55,21 +55,21 @@ services:
   {{.Type}}:
     build: .
     image: {{.Network}}/{{.Type}}
+    container_name: {{.Network}}_{{.Type}}_1
     ports:
-      - "{{.FullPort}}:{{.FullPort}}"
-      - "{{.FullPort}}:{{.FullPort}}/udp"{{if .Light}}
-      - "{{.LightPort}}:{{.LightPort}}/udp"{{end}}
+      - "{{.Port}}:{{.Port}}"
+      - "{{.Port}}:{{.Port}}/udp"
     volumes:
       - {{.Datadir}}:/root/.ethereum{{if .Ethashdir}}
       - {{.Ethashdir}}:/root/.ethash{{end}}
     environment:
-      - FULL_PORT={{.FullPort}}/tcp
-      - LIGHT_PORT={{.LightPort}}/udp
+      - PORT={{.Port}}/tcp
       - TOTAL_PEERS={{.TotalPeers}}
       - LIGHT_PEERS={{.LightPeers}}
       - STATS_NAME={{.Ethstats}}
       - MINER_NAME={{.Etherbase}}
       - GAS_TARGET={{.GasTarget}}
+      - GAS_LIMIT={{.GasLimit}}
       - GAS_PRICE={{.GasPrice}}
     logging:
       driver: "json-file"
@@ -82,12 +82,11 @@ services:
 // deployNode deploys a new Ethereum node container to a remote machine via SSH,
 // docker and docker-compose. If an instance with the specified network name
 // already exists there, it will be overwritten!
-func deployNode(client *sshClient, network string, bootv4, bootv5 []string, config *nodeInfos, nocache bool) ([]byte, error) {
+func deployNode(client *sshClient, network string, bootnodes []string, config *nodeInfos, nocache bool) ([]byte, error) {
 	kind := "sealnode"
 	if config.keyJSON == "" && config.etherbase == "" {
 		kind = "bootnode"
-		bootv4 = make([]string, 0)
-		bootv5 = make([]string, 0)
+		bootnodes = make([]string, 0)
 	}
 	// Generate the content to upload to the server
 	workdir := fmt.Sprintf("%d", rand.Int63())
@@ -100,14 +99,15 @@ func deployNode(client *sshClient, network string, bootv4, bootv5 []string, conf
 	dockerfile := new(bytes.Buffer)
 	template.Must(template.New("").Parse(nodeDockerfile)).Execute(dockerfile, map[string]interface{}{
 		"NetworkID": config.network,
-		"Port":      config.portFull,
+		"Port":      config.port,
+		"IP":        client.address,
 		"Peers":     config.peersTotal,
 		"LightFlag": lightFlag,
-		"BootV4":    strings.Join(bootv4, ","),
-		"BootV5":    strings.Join(bootv5, ","),
+		"Bootnodes": strings.Join(bootnodes, ","),
 		"Ethstats":  config.ethstats,
 		"Etherbase": config.etherbase,
 		"GasTarget": uint64(1000000 * config.gasTarget),
+		"GasLimit":  uint64(1000000 * config.gasLimit),
 		"GasPrice":  uint64(1000000000 * config.gasPrice),
 		"Unlock":    config.keyJSON != "",
 	})
@@ -119,14 +119,14 @@ func deployNode(client *sshClient, network string, bootv4, bootv5 []string, conf
 		"Datadir":    config.datadir,
 		"Ethashdir":  config.ethashdir,
 		"Network":    network,
-		"FullPort":   config.portFull,
+		"Port":       config.port,
 		"TotalPeers": config.peersTotal,
 		"Light":      config.peersLight > 0,
-		"LightPort":  config.portFull + 1,
 		"LightPeers": config.peersLight,
 		"Ethstats":   config.ethstats[:strings.Index(config.ethstats, ":")],
 		"Etherbase":  config.etherbase,
 		"GasTarget":  config.gasTarget,
+		"GasLimit":   config.gasLimit,
 		"GasPrice":   config.gasPrice,
 	})
 	files[filepath.Join(workdir, "docker-compose.yaml")] = composefile.Bytes()
@@ -144,9 +144,9 @@ func deployNode(client *sshClient, network string, bootv4, bootv5 []string, conf
 
 	// Build and deploy the boot or seal node service
 	if nocache {
-		return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s build --pull --no-cache && docker-compose -p %s up -d --force-recreate", workdir, network, network))
+		return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s build --pull --no-cache && docker-compose -p %s up -d --force-recreate --timeout 60", workdir, network, network))
 	}
-	return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s up -d --build --force-recreate", workdir, network))
+	return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s up -d --build --force-recreate --timeout 60", workdir, network))
 }
 
 // nodeInfos is returned from a boot or seal node status check to allow reporting
@@ -157,16 +157,15 @@ type nodeInfos struct {
 	datadir    string
 	ethashdir  string
 	ethstats   string
-	portFull   int
-	portLight  int
-	enodeFull  string
-	enodeLight string
+	port       int
+	enode      string
 	peersTotal int
 	peersLight int
 	etherbase  string
 	keyJSON    string
 	keyPass    string
 	gasTarget  float64
+	gasLimit   float64
 	gasPrice   float64
 }
 
@@ -174,20 +173,17 @@ type nodeInfos struct {
 // most - but not all - fields for reporting to the user.
 func (info *nodeInfos) Report() map[string]string {
 	report := map[string]string{
-		"Data directory":             info.datadir,
-		"Listener port (full nodes)": strconv.Itoa(info.portFull),
-		"Peer count (all total)":     strconv.Itoa(info.peersTotal),
-		"Peer count (light nodes)":   strconv.Itoa(info.peersLight),
-		"Ethstats username":          info.ethstats,
-	}
-	if info.peersLight > 0 {
-		// Light server enabled
-		report["Listener port (light nodes)"] = strconv.Itoa(info.portLight)
+		"Data directory":           info.datadir,
+		"Listener port":            strconv.Itoa(info.port),
+		"Peer count (all total)":   strconv.Itoa(info.peersTotal),
+		"Peer count (light nodes)": strconv.Itoa(info.peersLight),
+		"Ethstats username":        info.ethstats,
 	}
 	if info.gasTarget > 0 {
 		// Miner or signer node
-		report["Gas limit (baseline target)"] = fmt.Sprintf("%0.3f MGas", info.gasTarget)
 		report["Gas price (minimum accepted)"] = fmt.Sprintf("%0.3f GWei", info.gasPrice)
+		report["Gas floor (baseline target)"] = fmt.Sprintf("%0.3f MGas", info.gasTarget)
+		report["Gas ceil  (target maximum)"] = fmt.Sprintf("%0.3f MGas", info.gasLimit)
 
 		if info.etherbase != "" {
 			// Ethash proof-of-work miner
@@ -209,7 +205,7 @@ func (info *nodeInfos) Report() map[string]string {
 	return report
 }
 
-// checkNode does a health-check against an boot or seal node server to verify
+// checkNode does a health-check against a boot or seal node server to verify
 // whether it's running, and if yes, whether it's responsive.
 func checkNode(client *sshClient, network string, boot bool) (*nodeInfos, error) {
 	kind := "bootnode"
@@ -228,14 +224,15 @@ func checkNode(client *sshClient, network string, boot bool) (*nodeInfos, error)
 	totalPeers, _ := strconv.Atoi(infos.envvars["TOTAL_PEERS"])
 	lightPeers, _ := strconv.Atoi(infos.envvars["LIGHT_PEERS"])
 	gasTarget, _ := strconv.ParseFloat(infos.envvars["GAS_TARGET"], 64)
+	gasLimit, _ := strconv.ParseFloat(infos.envvars["GAS_LIMIT"], 64)
 	gasPrice, _ := strconv.ParseFloat(infos.envvars["GAS_PRICE"], 64)
 
 	// Container available, retrieve its node ID and its genesis json
 	var out []byte
-	if out, err = client.Run(fmt.Sprintf("docker exec %s_%s_1 geth --exec admin.nodeInfo.id attach", network, kind)); err != nil {
+	if out, err = client.Run(fmt.Sprintf("docker exec %s_%s_1 geth --exec admin.nodeInfo.enode --cache=16 attach", network, kind)); err != nil {
 		return nil, ErrServiceUnreachable
 	}
-	id := bytes.Trim(bytes.TrimSpace(out), "\"")
+	enode := bytes.Trim(bytes.TrimSpace(out), "\"")
 
 	if out, err = client.Run(fmt.Sprintf("docker exec %s_%s_1 cat /genesis.json", network, kind)); err != nil {
 		return nil, ErrServiceUnreachable
@@ -250,7 +247,7 @@ func checkNode(client *sshClient, network string, boot bool) (*nodeInfos, error)
 		keyPass = string(bytes.TrimSpace(out))
 	}
 	// Run a sanity check to see if the devp2p is reachable
-	port := infos.portmap[infos.envvars["FULL_PORT"]]
+	port := infos.portmap[infos.envvars["PORT"]]
 	if err = checkPort(client.server, port); err != nil {
 		log.Warn(fmt.Sprintf("%s devp2p port seems unreachable", strings.Title(kind)), "server", client.server, "port", port, "err", err)
 	}
@@ -259,8 +256,7 @@ func checkNode(client *sshClient, network string, boot bool) (*nodeInfos, error)
 		genesis:    genesis,
 		datadir:    infos.volumes["/root/.ethereum"],
 		ethashdir:  infos.volumes["/root/.ethash"],
-		portFull:   infos.portmap[infos.envvars["FULL_PORT"]],
-		portLight:  infos.portmap[infos.envvars["LIGHT_PORT"]],
+		port:       port,
 		peersTotal: totalPeers,
 		peersLight: lightPeers,
 		ethstats:   infos.envvars["STATS_NAME"],
@@ -268,11 +264,10 @@ func checkNode(client *sshClient, network string, boot bool) (*nodeInfos, error)
 		keyJSON:    keyJSON,
 		keyPass:    keyPass,
 		gasTarget:  gasTarget,
+		gasLimit:   gasLimit,
 		gasPrice:   gasPrice,
 	}
-	stats.enodeFull = fmt.Sprintf("enode://%s@%s:%d", id, client.address, stats.portFull)
-	if stats.portLight != 0 {
-		stats.enodeLight = fmt.Sprintf("enode://%s@%s:%d?discport=%d", id, client.address, stats.portFull, stats.portLight)
-	}
+	stats.enode = string(enode)
+
 	return stats, nil
 }
diff --git a/cmd/puppeth/module_wallet.go b/cmd/puppeth/module_wallet.go
index 67f47c70e8..ebaa5b6ae1 100644
--- a/cmd/puppeth/module_wallet.go
+++ b/cmd/puppeth/module_wallet.go
@@ -37,7 +37,7 @@ ADD genesis.json /genesis.json
 RUN \
   echo 'node server.js &'                     > wallet.sh && \
 	echo 'geth --cache 512 init /genesis.json' >> wallet.sh && \
-	echo $'geth --networkid {{.NetworkID}} --port {{.NodePort}} --bootnodes {{.Bootnodes}} --ethstats \'{{.Ethstats}}\' --cache=512 --rpc --rpcaddr=0.0.0.0 --rpccorsdomain "*"' >> wallet.sh
+	echo $'exec geth --networkid {{.NetworkID}} --port {{.NodePort}} --bootnodes {{.Bootnodes}} --ethstats \'{{.Ethstats}}\' --cache=512 --rpc --rpcaddr=0.0.0.0 --rpccorsdomain "*" --rpcvhosts "*"' >> wallet.sh
 
 RUN \
 	sed -i 's/PuppethNetworkID/{{.NetworkID}}/g' dist/js/etherwallet-master.js && \
@@ -57,6 +57,7 @@ services:
   wallet:
     build: .
     image: {{.Network}}/wallet
+    container_name: {{.Network}}_wallet_1
     ports:
       - "{{.NodePort}}:{{.NodePort}}"
       - "{{.NodePort}}:{{.NodePort}}/udp"
@@ -120,9 +121,9 @@ func deployWallet(client *sshClient, network string, bootnodes []string, config
 
 	// Build and deploy the boot or seal node service
 	if nocache {
-		return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s build --pull --no-cache && docker-compose -p %s up -d --force-recreate", workdir, network, network))
+		return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s build --pull --no-cache && docker-compose -p %s up -d --force-recreate --timeout 60", workdir, network, network))
 	}
-	return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s up -d --build --force-recreate", workdir, network))
+	return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s up -d --build --force-recreate --timeout 60", workdir, network))
 }
 
 // walletInfos is returned from a web wallet status check to allow reporting
diff --git a/cmd/puppeth/puppeth.go b/cmd/puppeth/puppeth.go
index 26382dac13..c3de5f9360 100644
--- a/cmd/puppeth/puppeth.go
+++ b/cmd/puppeth/puppeth.go
@@ -20,6 +20,7 @@ package main
 import (
 	"math/rand"
 	"os"
+	"strings"
 	"time"
 
 	"github.com/ethereum/go-ethereum/log"
@@ -34,7 +35,7 @@ func main() {
 	app.Flags = []cli.Flag{
 		cli.StringFlag{
 			Name:  "network",
-			Usage: "name of the network to administer",
+			Usage: "name of the network to administer (no spaces or hyphens, please)",
 		},
 		cli.IntFlag{
 			Name:  "loglevel",
@@ -42,14 +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())
 
-		// 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/cmd/puppeth/ssh.go b/cmd/puppeth/ssh.go
index 158261ce05..c507596065 100644
--- a/cmd/puppeth/ssh.go
+++ b/cmd/puppeth/ssh.go
@@ -45,33 +45,44 @@ type sshClient struct {
 
 // dial establishes an SSH connection to a remote node using the current user and
 // the user's configured private RSA key. If that fails, password authentication
-// is fallen back to. The caller may override the login user via user@server:port.
+// is fallen back to. server can be a string like user:identity@server:port.
 func dial(server string, pubkey []byte) (*sshClient, error) {
-	// Figure out a label for the server and a logger
-	label := server
-	if strings.Contains(label, ":") {
-		label = label[:strings.Index(label, ":")]
-	}
-	login := ""
+	// Figure out username, identity, hostname and port
+	hostname := ""
+	hostport := server
+	username := ""
+	identity := "id_rsa" // default
+
 	if strings.Contains(server, "@") {
-		login = label[:strings.Index(label, "@")]
-		label = label[strings.Index(label, "@")+1:]
-		server = server[strings.Index(server, "@")+1:]
+		prefix := server[:strings.Index(server, "@")]
+		if strings.Contains(prefix, ":") {
+			username = prefix[:strings.Index(prefix, ":")]
+			identity = prefix[strings.Index(prefix, ":")+1:]
+		} else {
+			username = prefix
+		}
+		hostport = server[strings.Index(server, "@")+1:]
 	}
-	logger := log.New("server", label)
+	if strings.Contains(hostport, ":") {
+		hostname = hostport[:strings.Index(hostport, ":")]
+	} else {
+		hostname = hostport
+		hostport += ":22"
+	}
+	logger := log.New("server", server)
 	logger.Debug("Attempting to establish SSH connection")
 
 	user, err := user.Current()
 	if err != nil {
 		return nil, err
 	}
-	if login == "" {
-		login = user.Username
+	if username == "" {
+		username = user.Username
 	}
 	// Configure the supported authentication methods (private key and password)
 	var auths []ssh.AuthMethod
 
-	path := filepath.Join(user.HomeDir, ".ssh", "id_rsa")
+	path := filepath.Join(user.HomeDir, ".ssh", identity)
 	if buf, err := ioutil.ReadFile(path); err != nil {
 		log.Warn("No SSH key, falling back to passwords", "path", path, "err", err)
 	} else {
@@ -94,14 +105,14 @@ func dial(server string, pubkey []byte) (*sshClient, error) {
 		}
 	}
 	auths = append(auths, ssh.PasswordCallback(func() (string, error) {
-		fmt.Printf("What's the login password for %s at %s? (won't be echoed)\n> ", login, server)
+		fmt.Printf("What's the login password for %s at %s? (won't be echoed)\n> ", username, server)
 		blob, err := terminal.ReadPassword(int(os.Stdin.Fd()))
 
 		fmt.Println()
 		return string(blob), err
 	}))
 	// Resolve the IP address of the remote server
-	addr, err := net.LookupHost(label)
+	addr, err := net.LookupHost(hostname)
 	if err != nil {
 		return nil, err
 	}
@@ -109,10 +120,7 @@ func dial(server string, pubkey []byte) (*sshClient, error) {
 		return nil, errors.New("no IPs associated with domain")
 	}
 	// Try to dial in to the remote server
-	logger.Trace("Dialing remote SSH server", "user", login)
-	if !strings.Contains(server, ":") {
-		server += ":22"
-	}
+	logger.Trace("Dialing remote SSH server", "user", username)
 	keycheck := func(hostname string, remote net.Addr, key ssh.PublicKey) error {
 		// If no public key is known for SSH, ask the user to confirm
 		if pubkey == nil {
@@ -139,13 +147,13 @@ func dial(server string, pubkey []byte) (*sshClient, error) {
 		// We have a mismatch, forbid connecting
 		return errors.New("ssh key mismatch, readd the machine to update")
 	}
-	client, err := ssh.Dial("tcp", server, &ssh.ClientConfig{User: login, Auth: auths, HostKeyCallback: keycheck})
+	client, err := ssh.Dial("tcp", hostport, &ssh.ClientConfig{User: username, Auth: auths, HostKeyCallback: keycheck})
 	if err != nil {
 		return nil, err
 	}
 	// Connection established, return our utility wrapper
 	c := &sshClient{
-		server:  label,
+		server:  hostname,
 		address: addr[0],
 		pubkey:  pubkey,
 		client:  client,
diff --git a/cmd/puppeth/testdata/stureby_aleth.json b/cmd/puppeth/testdata/stureby_aleth.json
new file mode 100644
index 0000000000..1ef1d8ae18
--- /dev/null
+++ b/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/cmd/puppeth/testdata/stureby_geth.json b/cmd/puppeth/testdata/stureby_geth.json
new file mode 100644
index 0000000000..c8c3b3c956
--- /dev/null
+++ b/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/cmd/puppeth/testdata/stureby_parity.json b/cmd/puppeth/testdata/stureby_parity.json
new file mode 100644
index 0000000000..f3fa8386a0
--- /dev/null
+++ b/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/cmd/puppeth/wizard.go b/cmd/puppeth/wizard.go
index 2e2b4644cf..83536506c4 100644
--- a/cmd/puppeth/wizard.go
+++ b/cmd/puppeth/wizard.go
@@ -23,6 +23,7 @@ import (
 	"io/ioutil"
 	"math/big"
 	"net"
+	"net/url"
 	"os"
 	"path/filepath"
 	"sort"
@@ -40,8 +41,7 @@ import (
 // between sessions.
 type config struct {
 	path      string   // File containing the configuration values
-	bootFull  []string // Bootnodes to always connect to by full nodes
-	bootLight []string // Bootnodes to always connect to by light nodes
+	bootnodes []string // Bootnodes to always connect to by all nodes
 	ethstats  string   // Ethstats settings to cache for node deploys
 
 	Genesis *core.Genesis     `json:"genesis,omitempty"` // Genesis block to cache for node deploys
@@ -119,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/cmd/puppeth/wizard_dashboard.go b/cmd/puppeth/wizard_dashboard.go
index 5f781c4152..8a8370845b 100644
--- a/cmd/puppeth/wizard_dashboard.go
+++ b/cmd/puppeth/wizard_dashboard.go
@@ -92,7 +92,7 @@ func (w *wizard) deployDashboard() {
 				pages = append(pages, page)
 			}
 		}
-		// Promt the user to chose one, enter manually or simply not list this service
+		// Prompt the user to chose one, enter manually or simply not list this service
 		defLabel, defChoice := "don't list", len(pages)+2
 		if len(pages) > 0 {
 			defLabel, defChoice = pages[0], 1
@@ -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/cmd/puppeth/wizard_ethstats.go b/cmd/puppeth/wizard_ethstats.go
index fb2529c267..58ff3efbe9 100644
--- a/cmd/puppeth/wizard_ethstats.go
+++ b/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/cmd/puppeth/wizard_explorer.go b/cmd/puppeth/wizard_explorer.go
index 10ef72f788..a128fb9fb5 100644
--- a/cmd/puppeth/wizard_explorer.go
+++ b/cmd/puppeth/wizard_explorer.go
@@ -55,7 +55,7 @@ func (w *wizard) deployExplorer() {
 	}
 	existed := err == nil
 
-	chainspec, err := newParityChainSpec(w.network, w.conf.Genesis, w.conf.bootFull)
+	chainspec, err := newParityChainSpec(w.network, w.conf.Genesis, w.conf.bootnodes)
 	if err != nil {
 		log.Error("Failed to create chain spec for explorer", "err", err)
 		return
@@ -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/cmd/puppeth/wizard_faucet.go b/cmd/puppeth/wizard_faucet.go
index 191575b168..9068c1d30b 100644
--- a/cmd/puppeth/wizard_faucet.go
+++ b/cmd/puppeth/wizard_faucet.go
@@ -38,7 +38,7 @@ func (w *wizard) deployFaucet() {
 	infos, err := checkFaucet(client, w.network)
 	if err != nil {
 		infos = &faucetInfos{
-			node:    &nodeInfos{portFull: 30303, peersTotal: 25},
+			node:    &nodeInfos{port: 30303, peersTotal: 25},
 			port:    80,
 			host:    client.server,
 			amount:  1,
@@ -49,7 +49,7 @@ func (w *wizard) deployFaucet() {
 	existed := err == nil
 
 	infos.node.genesis, _ = json.MarshalIndent(w.conf.Genesis, "", "  ")
-	infos.node.network = w.conf.Genesis.Config.ChainId.Int64()
+	infos.node.network = w.conf.Genesis.Config.ChainID.Int64()
 
 	// Figure out which port to listen on
 	fmt.Println()
@@ -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
@@ -113,8 +113,8 @@ func (w *wizard) deployFaucet() {
 	}
 	// Figure out which port to listen on
 	fmt.Println()
-	fmt.Printf("Which TCP/UDP port should the light client listen on? (default = %d)\n", infos.node.portFull)
-	infos.node.portFull = w.readDefaultInt(infos.node.portFull)
+	fmt.Printf("Which TCP/UDP port should the light client listen on? (default = %d)\n", infos.node.port)
+	infos.node.port = w.readDefaultInt(infos.node.port)
 
 	// Set a proper name to report on the stats page
 	fmt.Println()
@@ -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,9 +166,9 @@ 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.bootLight, infos, nocache); err != nil {
+	if out, err := deployFaucet(client, w.network, w.conf.bootnodes, infos, nocache); err != nil {
 		log.Error("Failed to deploy faucet container", "err", err)
 		if len(out) > 0 {
 			fmt.Printf("%s\n", out)
diff --git a/cmd/puppeth/wizard_genesis.go b/cmd/puppeth/wizard_genesis.go
index f255ef6e65..6aed09f141 100644
--- a/cmd/puppeth/wizard_genesis.go
+++ b/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,14 +119,18 @@ 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()
 	fmt.Println("Specify your chain/network ID if you want an explicit one (default = random)")
-	genesis.Config.ChainId = new(big.Int).SetUint64(uint64(w.readDefaultInt(rand.Intn(65536))))
+	genesis.Config.ChainID = new(big.Int).SetUint64(uint64(w.readDefaultInt(rand.Intn(65536))))
 
 	// All done, store the genesis and flush to disk
 	log.Info("Configured new genesis block")
@@ -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/cmd/puppeth/wizard_intro.go b/cmd/puppeth/wizard_intro.go
index 84998afc93..75fb04b76f 100644
--- a/cmd/puppeth/wizard_intro.go
+++ b/cmd/puppeth/wizard_intro.go
@@ -59,15 +59,16 @@ func (w *wizard) run() {
 	fmt.Println()
 
 	// 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, 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, " ") {
+			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")
+			log.Error("I also like to live dangerously, still no spaces, hyphens or capital letters")
 		}
 	}
 	log.Info("Administering Ethereum network", "name", w.network)
@@ -130,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()
 			}
@@ -148,7 +162,6 @@ func (w *wizard) run() {
 			} else {
 				w.manageComponents()
 			}
-
 		default:
 			log.Error("That's not something I can do")
 		}
diff --git a/cmd/puppeth/wizard_netstats.go b/cmd/puppeth/wizard_netstats.go
index e19180bb16..99ca11bb17 100644
--- a/cmd/puppeth/wizard_netstats.go
+++ b/cmd/puppeth/wizard_netstats.go
@@ -37,8 +37,7 @@ func (w *wizard) networkStats() {
 	}
 	// Clear out some previous configs to refill from current scan
 	w.conf.ethstats = ""
-	w.conf.bootFull = w.conf.bootFull[:0]
-	w.conf.bootLight = w.conf.bootLight[:0]
+	w.conf.bootnodes = w.conf.bootnodes[:0]
 
 	// Iterate over all the specified hosts and check their status
 	var pend sync.WaitGroup
@@ -76,15 +75,13 @@ func (w *wizard) gatherStats(server string, pubkey []byte, client *sshClient) *s
 	var (
 		genesis   string
 		ethstats  string
-		bootFull  []string
-		bootLight []string
+		bootnodes []string
 	)
 	// Ensure a valid SSH connection to the remote server
 	logger := log.New("server", server)
 	logger.Info("Starting remote server health-check")
 
 	stat := &serverStat{
-		address:  client.address,
 		services: make(map[string]map[string]string),
 	}
 	if client == nil {
@@ -96,6 +93,8 @@ func (w *wizard) gatherStats(server string, pubkey []byte, client *sshClient) *s
 		}
 		client = conn
 	}
+	stat.address = client.address
+
 	// Client connected one way or another, run health-checks
 	logger.Debug("Checking for nginx availability")
 	if infos, err := checkNginx(client, w.network); err != nil {
@@ -123,10 +122,7 @@ func (w *wizard) gatherStats(server string, pubkey []byte, client *sshClient) *s
 		stat.services["bootnode"] = infos.Report()
 
 		genesis = string(infos.genesis)
-		bootFull = append(bootFull, infos.enodeFull)
-		if infos.enodeLight != "" {
-			bootLight = append(bootLight, infos.enodeLight)
-		}
+		bootnodes = append(bootnodes, infos.enode)
 	}
 	logger.Debug("Checking for sealnode availability")
 	if infos, err := checkNode(client, w.network, false); err != nil {
@@ -184,8 +180,7 @@ func (w *wizard) gatherStats(server string, pubkey []byte, client *sshClient) *s
 	if ethstats != "" {
 		w.conf.ethstats = ethstats
 	}
-	w.conf.bootFull = append(w.conf.bootFull, bootFull...)
-	w.conf.bootLight = append(w.conf.bootLight, bootLight...)
+	w.conf.bootnodes = append(w.conf.bootnodes, bootnodes...)
 
 	return stat
 }
@@ -209,7 +204,7 @@ func (stats serverStats) render() {
 
 	table.SetHeader([]string{"Server", "Address", "Service", "Config", "Value"})
 	table.SetAlignment(tablewriter.ALIGN_LEFT)
-	table.SetColWidth(100)
+	table.SetColWidth(40)
 
 	// Find the longest lines for all columns for the hacked separator
 	separator := make([]string, 5)
@@ -220,6 +215,9 @@ func (stats serverStats) render() {
 		if len(stat.address) > len(separator[1]) {
 			separator[1] = strings.Repeat("-", len(stat.address))
 		}
+		if len(stat.failure) > len(separator[1]) {
+			separator[1] = strings.Repeat("-", len(stat.failure))
+		}
 		for service, configs := range stat.services {
 			if len(service) > len(separator[2]) {
 				separator[2] = strings.Repeat("-", len(service))
@@ -228,8 +226,10 @@ func (stats serverStats) render() {
 				if len(config) > len(separator[3]) {
 					separator[3] = strings.Repeat("-", len(config))
 				}
-				if len(value) > len(separator[4]) {
-					separator[4] = strings.Repeat("-", len(value))
+				for _, val := range strings.Split(value, "\n") {
+					if len(val) > len(separator[4]) {
+						separator[4] = strings.Repeat("-", len(val))
+					}
 				}
 			}
 		}
@@ -254,7 +254,11 @@ func (stats serverStats) render() {
 		sort.Strings(services)
 
 		if len(services) == 0 {
-			table.Append([]string{server, stats[server].address, "", "", ""})
+			if stats[server].failure != "" {
+				table.Append([]string{server, stats[server].failure, "", "", ""})
+			} else {
+				table.Append([]string{server, stats[server].address, "", "", ""})
+			}
 		}
 		for j, service := range services {
 			// Add an empty line between all services
@@ -269,26 +273,20 @@ func (stats serverStats) render() {
 			sort.Strings(configs)
 
 			for k, config := range configs {
-				switch {
-				case j == 0 && k == 0:
-					table.Append([]string{server, stats[server].address, service, config, stats[server].services[service][config]})
-				case k == 0:
-					table.Append([]string{"", "", service, config, stats[server].services[service][config]})
-				default:
-					table.Append([]string{"", "", "", config, stats[server].services[service][config]})
+				for l, value := range strings.Split(stats[server].services[service][config], "\n") {
+					switch {
+					case j == 0 && k == 0 && l == 0:
+						table.Append([]string{server, stats[server].address, service, config, value})
+					case k == 0 && l == 0:
+						table.Append([]string{"", "", service, config, value})
+					case l == 0:
+						table.Append([]string{"", "", "", config, value})
+					default:
+						table.Append([]string{"", "", "", "", value})
+					}
 				}
 			}
 		}
 	}
 	table.Render()
 }
-
-// protips contains a collection of network infos to report pro-tips
-// based on.
-type protips struct {
-	genesis   string
-	network   int64
-	bootFull  []string
-	bootLight []string
-	ethstats  string
-}
diff --git a/cmd/puppeth/wizard_network.go b/cmd/puppeth/wizard_network.go
index d780c550b1..83b10cf375 100644
--- a/cmd/puppeth/wizard_network.go
+++ b/cmd/puppeth/wizard_network.go
@@ -62,14 +62,14 @@ func (w *wizard) manageServers() {
 	}
 }
 
-// makeServer reads a single line from stdin and interprets it as a hostname to
-// connect to. It tries to establish a new SSH session and also executing some
-// baseline validations.
+// makeServer reads a single line from stdin and interprets it as
+// username:identity@hostname to connect to. It tries to establish a
+// new SSH session and also executing some baseline validations.
 //
 // If connection succeeds, the server is added to the wizards configs!
 func (w *wizard) makeServer() string {
 	fmt.Println()
-	fmt.Println("Please enter remote server's address:")
+	fmt.Println("What is the remote server's address ([username[:identity]@]hostname[:port])?")
 
 	// Read and dial the server to ensure docker is present
 	input := w.readString()
@@ -87,7 +87,7 @@ func (w *wizard) makeServer() string {
 	return input
 }
 
-// selectServer lists the user all the currnetly known servers to choose from,
+// selectServer lists the user all the currently known servers to choose from,
 // also granting the option to add a new one.
 func (w *wizard) selectServer() string {
 	// List the available server to the user and wait for a choice
@@ -115,7 +115,7 @@ func (w *wizard) selectServer() string {
 // manageComponents displays a list of network components the user can tear down
 // and an option
 func (w *wizard) manageComponents() {
-	// List all the componens we can tear down, along with an entry to deploy a new one
+	// List all the components we can tear down, along with an entry to deploy a new one
 	fmt.Println()
 
 	var serviceHosts, serviceNames []string
diff --git a/cmd/puppeth/wizard_nginx.go b/cmd/puppeth/wizard_nginx.go
index 4eeae93a0b..8397b7fd57 100644
--- a/cmd/puppeth/wizard_nginx.go
+++ b/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/cmd/puppeth/wizard_node.go b/cmd/puppeth/wizard_node.go
index 097e2e41aa..e37297f6d6 100644
--- a/cmd/puppeth/wizard_node.go
+++ b/cmd/puppeth/wizard_node.go
@@ -48,15 +48,15 @@ func (w *wizard) deployNode(boot bool) {
 	infos, err := checkNode(client, w.network, boot)
 	if err != nil {
 		if boot {
-			infos = &nodeInfos{portFull: 30303, peersTotal: 512, peersLight: 256}
+			infos = &nodeInfos{port: 30303, peersTotal: 512, peersLight: 256}
 		} else {
-			infos = &nodeInfos{portFull: 30303, peersTotal: 50, peersLight: 0, gasTarget: 4.7, gasPrice: 18}
+			infos = &nodeInfos{port: 30303, peersTotal: 50, peersLight: 0, gasTarget: 7.5, gasLimit: 10, gasPrice: 1}
 		}
 	}
 	existed := err == nil
 
 	infos.genesis, _ = json.MarshalIndent(w.conf.Genesis, "", "  ")
-	infos.network = w.conf.Genesis.Config.ChainId.Int64()
+	infos.network = w.conf.Genesis.Config.ChainID.Int64()
 
 	// Figure out where the user wants to store the persistent data
 	fmt.Println()
@@ -79,8 +79,8 @@ func (w *wizard) deployNode(boot bool) {
 	}
 	// Figure out which port to listen on
 	fmt.Println()
-	fmt.Printf("Which TCP/UDP port to listen on? (default = %d)\n", infos.portFull)
-	infos.portFull = w.readDefaultInt(infos.portFull)
+	fmt.Printf("Which TCP/UDP port to listen on? (default = %d)\n", infos.port)
+	infos.port = w.readDefaultInt(infos.port)
 
 	// Figure out how many peers to allow (different based on node type)
 	fmt.Println()
@@ -107,7 +107,7 @@ func (w *wizard) deployNode(boot bool) {
 			// Ethash based miners only need an etherbase to mine against
 			fmt.Println()
 			if infos.etherbase == "" {
-				fmt.Printf("What address should the miner user?\n")
+				fmt.Printf("What address should the miner use?\n")
 				for {
 					if address := w.readAddress(); address != nil {
 						infos.etherbase = address.Hex()
@@ -115,7 +115,7 @@ func (w *wizard) deployNode(boot bool) {
 					}
 				}
 			} else {
-				fmt.Printf("What address should the miner user? (default = %s)\n", infos.etherbase)
+				fmt.Printf("What address should the miner use? (default = %s)\n", infos.etherbase)
 				infos.etherbase = w.readDefaultAddress(common.HexToAddress(infos.etherbase)).Hex()
 			}
 		} else if w.conf.Genesis.Config.Clique != nil {
@@ -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 = "", ""
 					}
 				}
@@ -152,6 +152,10 @@ func (w *wizard) deployNode(boot bool) {
 		fmt.Printf("What gas limit should empty blocks target (MGas)? (default = %0.3f)\n", infos.gasTarget)
 		infos.gasTarget = w.readDefaultFloat(infos.gasTarget)
 
+		fmt.Println()
+		fmt.Printf("What gas limit should full blocks target (MGas)? (default = %0.3f)\n", infos.gasLimit)
+		infos.gasLimit = w.readDefaultFloat(infos.gasLimit)
+
 		fmt.Println()
 		fmt.Printf("What gas price should the signer require (GWei)? (default = %0.3f)\n", infos.gasPrice)
 		infos.gasPrice = w.readDefaultFloat(infos.gasPrice)
@@ -161,9 +165,9 @@ 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.bootFull, w.conf.bootLight, infos, nocache); err != nil {
+	if out, err := deployNode(client, w.network, w.conf.bootnodes, infos, nocache); err != nil {
 		log.Error("Failed to deploy Ethereum node container", "err", err)
 		if len(out) > 0 {
 			fmt.Printf("%s\n", out)
diff --git a/cmd/puppeth/wizard_wallet.go b/cmd/puppeth/wizard_wallet.go
index 7c3896a17c..ca1ea5bd25 100644
--- a/cmd/puppeth/wizard_wallet.go
+++ b/cmd/puppeth/wizard_wallet.go
@@ -52,7 +52,7 @@ func (w *wizard) deployWallet() {
 	existed := err == nil
 
 	infos.genesis, _ = json.MarshalIndent(w.conf.Genesis, "", "  ")
-	infos.network = w.conf.Genesis.Config.ChainId.Int64()
+	infos.network = w.conf.Genesis.Config.ChainID.Int64()
 
 	// Figure out which port to listen on
 	fmt.Println()
@@ -96,9 +96,9 @@ 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.bootFull, infos, nocache); err != nil {
+	if out, err := deployWallet(client, w.network, w.conf.bootnodes, infos, nocache); err != nil {
 		log.Error("Failed to deploy wallet container", "err", err)
 		if len(out) > 0 {
 			fmt.Printf("%s\n", out)
diff --git a/cmd/swarm/access.go b/cmd/swarm/access.go
new file mode 100644
index 0000000000..cc0cc8201a
--- /dev/null
+++ b/cmd/swarm/access.go
@@ -0,0 +1,297 @@
+// 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 (
+	"crypto/rand"
+	"encoding/json"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"strings"
+
+	"github.com/ethereum/go-ethereum/cmd/utils"
+	"github.com/ethereum/go-ethereum/swarm/api"
+	"github.com/ethereum/go-ethereum/swarm/api/client"
+	"gopkg.in/urfave/cli.v1"
+)
+
+var (
+	salt          = make([]byte, 32)
+	accessCommand = cli.Command{
+		CustomHelpTemplate: helpTemplate,
+		Name:               "access",
+		Usage:              "encrypts a reference and embeds it into a root manifest",
+		ArgsUsage:          "",
+		Description:        "encrypts a reference and embeds it into a root manifest",
+		Subcommands: []cli.Command{
+			{
+				CustomHelpTemplate: helpTemplate,
+				Name:               "new",
+				Usage:              "encrypts a reference and embeds it into a root manifest",
+				ArgsUsage:          "",
+				Description:        "encrypts a reference and embeds it into a root access manifest and prints the resulting manifest",
+				Subcommands: []cli.Command{
+					{
+						Action:             accessNewPass,
+						CustomHelpTemplate: helpTemplate,
+						Flags: []cli.Flag{
+							utils.PasswordFileFlag,
+							SwarmDryRunFlag,
+						},
+						Name:        "pass",
+						Usage:       "encrypts a reference with a password and embeds it into a root manifest",
+						ArgsUsage:   "",
+						Description: "encrypts a reference and embeds it into a root access manifest and prints the resulting manifest",
+					},
+					{
+						Action:             accessNewPK,
+						CustomHelpTemplate: helpTemplate,
+						Flags: []cli.Flag{
+							utils.PasswordFileFlag,
+							SwarmDryRunFlag,
+							SwarmAccessGrantKeyFlag,
+						},
+						Name:        "pk",
+						Usage:       "encrypts a reference with the node's private key and a given grantee's public key and embeds it into a root manifest",
+						ArgsUsage:   "",
+						Description: "encrypts a reference and embeds it into a root access manifest and prints the resulting manifest",
+					},
+					{
+						Action:             accessNewACT,
+						CustomHelpTemplate: helpTemplate,
+						Flags: []cli.Flag{
+							SwarmAccessGrantKeysFlag,
+							SwarmDryRunFlag,
+							utils.PasswordFileFlag,
+						},
+						Name:        "act",
+						Usage:       "encrypts a reference with the node's private key and a given grantee's public key and embeds it into a root manifest",
+						ArgsUsage:   "",
+						Description: "encrypts a reference and embeds it into a root access manifest and prints the resulting manifest",
+					},
+				},
+			},
+		},
+	}
+)
+
+func init() {
+	if _, err := io.ReadFull(rand.Reader, salt); err != nil {
+		panic("reading from crypto/rand failed: " + err.Error())
+	}
+}
+
+func accessNewPass(ctx *cli.Context) {
+	args := ctx.Args()
+	if len(args) != 1 {
+		utils.Fatalf("Expected 1 argument - the ref")
+	}
+
+	var (
+		ae        *api.AccessEntry
+		accessKey []byte
+		err       error
+		ref       = args[0]
+		password  = getPassPhrase("", 0, makePasswordList(ctx))
+		dryRun    = ctx.Bool(SwarmDryRunFlag.Name)
+	)
+	accessKey, ae, err = api.DoPassword(ctx, password, salt)
+	if err != nil {
+		utils.Fatalf("error getting session key: %v", err)
+	}
+	m, err := api.GenerateAccessControlManifest(ctx, ref, accessKey, ae)
+	if err != nil {
+		utils.Fatalf("had an error generating the manifest: %v", err)
+	}
+	if dryRun {
+		err = printManifests(m, nil)
+		if err != nil {
+			utils.Fatalf("had an error printing the manifests: %v", err)
+		}
+	} else {
+		err = uploadManifests(ctx, m, nil)
+		if err != nil {
+			utils.Fatalf("had an error uploading the manifests: %v", err)
+		}
+	}
+}
+
+func accessNewPK(ctx *cli.Context) {
+	args := ctx.Args()
+	if len(args) != 1 {
+		utils.Fatalf("Expected 1 argument - the ref")
+	}
+
+	var (
+		ae               *api.AccessEntry
+		sessionKey       []byte
+		err              error
+		ref              = args[0]
+		privateKey       = getPrivKey(ctx)
+		granteePublicKey = ctx.String(SwarmAccessGrantKeyFlag.Name)
+		dryRun           = ctx.Bool(SwarmDryRunFlag.Name)
+	)
+	sessionKey, ae, err = api.DoPK(ctx, privateKey, granteePublicKey, salt)
+	if err != nil {
+		utils.Fatalf("error getting session key: %v", err)
+	}
+	m, err := api.GenerateAccessControlManifest(ctx, ref, sessionKey, ae)
+	if err != nil {
+		utils.Fatalf("had an error generating the manifest: %v", err)
+	}
+	if dryRun {
+		err = printManifests(m, nil)
+		if err != nil {
+			utils.Fatalf("had an error printing the manifests: %v", err)
+		}
+	} else {
+		err = uploadManifests(ctx, m, nil)
+		if err != nil {
+			utils.Fatalf("had an error uploading the manifests: %v", err)
+		}
+	}
+}
+
+func accessNewACT(ctx *cli.Context) {
+	args := ctx.Args()
+	if len(args) != 1 {
+		utils.Fatalf("Expected 1 argument - the ref")
+	}
+
+	var (
+		ae                   *api.AccessEntry
+		actManifest          *api.Manifest
+		accessKey            []byte
+		err                  error
+		ref                  = args[0]
+		pkGrantees           []string
+		passGrantees         []string
+		pkGranteesFilename   = ctx.String(SwarmAccessGrantKeysFlag.Name)
+		passGranteesFilename = ctx.String(utils.PasswordFileFlag.Name)
+		privateKey           = getPrivKey(ctx)
+		dryRun               = ctx.Bool(SwarmDryRunFlag.Name)
+	)
+	if pkGranteesFilename == "" && passGranteesFilename == "" {
+		utils.Fatalf("you have to provide either a grantee public-keys file or an encryption passwords file (or both)")
+	}
+
+	if pkGranteesFilename != "" {
+		bytes, err := ioutil.ReadFile(pkGranteesFilename)
+		if err != nil {
+			utils.Fatalf("had an error reading the grantee public key list")
+		}
+		pkGrantees = strings.Split(strings.Trim(string(bytes), "\n"), "\n")
+	}
+
+	if passGranteesFilename != "" {
+		bytes, err := ioutil.ReadFile(passGranteesFilename)
+		if err != nil {
+			utils.Fatalf("could not read password filename: %v", err)
+		}
+		passGrantees = strings.Split(strings.Trim(string(bytes), "\n"), "\n")
+	}
+	accessKey, ae, actManifest, err = api.DoACT(ctx, privateKey, salt, pkGrantees, passGrantees)
+	if err != nil {
+		utils.Fatalf("error generating ACT manifest: %v", err)
+	}
+
+	if err != nil {
+		utils.Fatalf("error getting session key: %v", err)
+	}
+	m, err := api.GenerateAccessControlManifest(ctx, ref, accessKey, ae)
+	if err != nil {
+		utils.Fatalf("error generating root access manifest: %v", err)
+	}
+
+	if dryRun {
+		err = printManifests(m, actManifest)
+		if err != nil {
+			utils.Fatalf("had an error printing the manifests: %v", err)
+		}
+	} else {
+		err = uploadManifests(ctx, m, actManifest)
+		if err != nil {
+			utils.Fatalf("had an error uploading the manifests: %v", err)
+		}
+	}
+}
+
+func printManifests(rootAccessManifest, actManifest *api.Manifest) error {
+	js, err := json.Marshal(rootAccessManifest)
+	if err != nil {
+		return err
+	}
+	fmt.Println(string(js))
+
+	if actManifest != nil {
+		js, err := json.Marshal(actManifest)
+		if err != nil {
+			return err
+		}
+		fmt.Println(string(js))
+	}
+	return nil
+}
+
+func uploadManifests(ctx *cli.Context, rootAccessManifest, actManifest *api.Manifest) error {
+	bzzapi := strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
+	client := client.NewClient(bzzapi)
+
+	var (
+		key string
+		err error
+	)
+	if actManifest != nil {
+		key, err = client.UploadManifest(actManifest, false)
+		if err != nil {
+			return err
+		}
+
+		rootAccessManifest.Entries[0].Access.Act = key
+	}
+	key, err = client.UploadManifest(rootAccessManifest, false)
+	if err != nil {
+		return err
+	}
+	fmt.Println(key)
+	return nil
+}
+
+// makePasswordList reads password lines from the file specified by the global --password flag
+// and also by the same subcommand --password flag.
+// This function ia a fork of utils.MakePasswordList to lookup cli context for subcommand.
+// Function ctx.SetGlobal is not setting the global flag value that can be accessed
+// by ctx.GlobalString using the current version of cli package.
+func makePasswordList(ctx *cli.Context) []string {
+	path := ctx.GlobalString(utils.PasswordFileFlag.Name)
+	if path == "" {
+		path = ctx.String(utils.PasswordFileFlag.Name)
+		if path == "" {
+			return nil
+		}
+	}
+	text, err := ioutil.ReadFile(path)
+	if err != nil {
+		utils.Fatalf("Failed to read password file: %v", err)
+	}
+	lines := strings.Split(string(text), "\n")
+	// Sanitise DOS line endings.
+	for i := range lines {
+		lines[i] = strings.TrimRight(lines[i], "\r")
+	}
+	return lines
+}
diff --git a/cmd/swarm/access_test.go b/cmd/swarm/access_test.go
new file mode 100644
index 0000000000..0898d33bca
--- /dev/null
+++ b/cmd/swarm/access_test.go
@@ -0,0 +1,614 @@
+// 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"
+	"crypto/rand"
+	"encoding/hex"
+	"encoding/json"
+	"io"
+	"io/ioutil"
+	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/log"
+	"github.com/ethereum/go-ethereum/swarm/api"
+	swarmapi "github.com/ethereum/go-ethereum/swarm/api/client"
+	"github.com/ethereum/go-ethereum/swarm/testutil"
+	"golang.org/x/crypto/sha3"
+)
+
+const (
+	hashRegexp = `[a-f\d]{128}`
+	data       = "notsorandomdata"
+)
+
+var DefaultCurve = crypto.S256()
+
+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 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",
+		cluster.Nodes[0].URL,
+		"up",
+		"--encrypt",
+		dataFilename)
+	_, matches := up.ExpectRegexp(hashRegexp)
+	up.ExpectExit()
+
+	if len(matches) < 1 {
+		t.Fatal("no matches found")
+	}
+
+	ref := matches[0]
+	tmp, err := ioutil.TempDir("", "swarm-test")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(tmp)
+	password := "smth"
+	passwordFilename := testutil.TempFileWithContent(t, "smth")
+	defer os.RemoveAll(passwordFilename)
+
+	up = runSwarm(t,
+		"access",
+		"new",
+		"pass",
+		"--dry-run",
+		"--password",
+		passwordFilename,
+		ref,
+	)
+
+	_, matches = up.ExpectRegexp(".+")
+	up.ExpectExit()
+
+	if len(matches) == 0 {
+		t.Fatalf("stdout not matched")
+	}
+
+	var m api.Manifest
+
+	err = json.Unmarshal([]byte(matches[0]), &m)
+	if err != nil {
+		t.Fatalf("unmarshal manifest: %v", err)
+	}
+
+	if len(m.Entries) != 1 {
+		t.Fatalf("expected one manifest entry, got %v", len(m.Entries))
+	}
+
+	e := m.Entries[0]
+
+	ct := "application/bzz-manifest+json"
+	if e.ContentType != ct {
+		t.Errorf("expected %q content type, got %q", ct, e.ContentType)
+	}
+
+	if e.Access == nil {
+		t.Fatal("manifest access is nil")
+	}
+
+	a := e.Access
+
+	if a.Type != "pass" {
+		t.Errorf(`got access type %q, expected "pass"`, a.Type)
+	}
+	if len(a.Salt) < 32 {
+		t.Errorf(`got salt with length %v, expected not less the 32 bytes`, len(a.Salt))
+	}
+	if a.KdfParams == nil {
+		t.Fatal("manifest access kdf params is nil")
+	}
+	if a.Publisher != "" {
+		t.Fatal("should be empty")
+	}
+
+	client := swarmapi.NewClient(cluster.Nodes[0].URL)
+
+	hash, err := client.UploadManifest(&m, false)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	url := cluster.Nodes[0].URL + "/" + "bzz:/" + hash
+
+	httpClient := &http.Client{}
+	response, err := httpClient.Get(url)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if response.StatusCode != http.StatusUnauthorized {
+		t.Fatal("should be a 401")
+	}
+	authHeader := response.Header.Get("WWW-Authenticate")
+	if authHeader == "" {
+		t.Fatal("should be something here")
+	}
+
+	req, err := http.NewRequest(http.MethodGet, url, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	req.SetBasicAuth("", password)
+
+	response, err = http.DefaultClient.Do(req)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer response.Body.Close()
+
+	if response.StatusCode != http.StatusOK {
+		t.Errorf("expected status %v, got %v", http.StatusOK, response.StatusCode)
+	}
+	d, err := ioutil.ReadAll(response.Body)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if string(d) != data {
+		t.Errorf("expected decrypted data %q, got %q", data, string(d))
+	}
+
+	wrongPasswordFilename := testutil.TempFileWithContent(t, "just wr0ng")
+	defer os.RemoveAll(wrongPasswordFilename)
+
+	//download file with 'swarm down' with wrong password
+	up = runSwarm(t,
+		"--bzzapi",
+		cluster.Nodes[0].URL,
+		"down",
+		"bzz:/"+hash,
+		tmp,
+		"--password",
+		wrongPasswordFilename)
+
+	_, matches = up.ExpectRegexp("unauthorized")
+	if len(matches) != 1 && matches[0] != "unauthorized" {
+		t.Fatal(`"unauthorized" not found in output"`)
+	}
+	up.ExpectExit()
+}
+
+// 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 testPK(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",
+		cluster.Nodes[0].URL,
+		"up",
+		"--encrypt",
+		dataFilename)
+	_, matches := up.ExpectRegexp(hashRegexp)
+	up.ExpectExit()
+
+	if len(matches) < 1 {
+		t.Fatal("no matches found")
+	}
+
+	ref := matches[0]
+	pk := cluster.Nodes[0].PrivateKey
+	granteePubKey := crypto.CompressPubkey(&pk.PublicKey)
+
+	publisherDir, err := ioutil.TempDir("", "swarm-account-dir-temp")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	passwordFilename := testutil.TempFileWithContent(t, testPassphrase)
+	defer os.RemoveAll(passwordFilename)
+
+	_, publisherAccount := getTestAccount(t, publisherDir)
+	up = runSwarm(t,
+		"--bzzaccount",
+		publisherAccount.Address.String(),
+		"--password",
+		passwordFilename,
+		"--datadir",
+		publisherDir,
+		"--bzzapi",
+		cluster.Nodes[0].URL,
+		"access",
+		"new",
+		"pk",
+		"--dry-run",
+		"--grant-key",
+		hex.EncodeToString(granteePubKey),
+		ref,
+	)
+
+	_, matches = up.ExpectRegexp(".+")
+	up.ExpectExit()
+
+	if len(matches) == 0 {
+		t.Fatalf("stdout not matched")
+	}
+
+	//get the public key from the publisher directory
+	publicKeyFromDataDir := runSwarm(t,
+		"--bzzaccount",
+		publisherAccount.Address.String(),
+		"--password",
+		passwordFilename,
+		"--datadir",
+		publisherDir,
+		"print-keys",
+		"--compressed",
+	)
+	_, publicKeyString := publicKeyFromDataDir.ExpectRegexp(".+")
+	publicKeyFromDataDir.ExpectExit()
+	pkComp := strings.Split(publicKeyString[0], "=")[1]
+	var m api.Manifest
+
+	err = json.Unmarshal([]byte(matches[0]), &m)
+	if err != nil {
+		t.Fatalf("unmarshal manifest: %v", err)
+	}
+
+	if len(m.Entries) != 1 {
+		t.Fatalf("expected one manifest entry, got %v", len(m.Entries))
+	}
+
+	e := m.Entries[0]
+
+	ct := "application/bzz-manifest+json"
+	if e.ContentType != ct {
+		t.Errorf("expected %q content type, got %q", ct, e.ContentType)
+	}
+
+	if e.Access == nil {
+		t.Fatal("manifest access is nil")
+	}
+
+	a := e.Access
+
+	if a.Type != "pk" {
+		t.Errorf(`got access type %q, expected "pk"`, a.Type)
+	}
+	if len(a.Salt) < 32 {
+		t.Errorf(`got salt with length %v, expected not less the 32 bytes`, len(a.Salt))
+	}
+	if a.KdfParams != nil {
+		t.Fatal("manifest access kdf params should be nil")
+	}
+	if a.Publisher != pkComp {
+		t.Fatal("publisher key did not match")
+	}
+	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
+	response, err := httpClient.Get(url)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if response.StatusCode != http.StatusOK {
+		t.Fatal("should be a 200")
+	}
+	d, err := ioutil.ReadAll(response.Body)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if string(d) != data {
+		t.Errorf("expected decrypted data %q, got %q", data, string(d))
+	}
+}
+
+// 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)
+}
+
+// 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)
+}
+
+// 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 testACT(t *testing.T, bogusEntries int) {
+	var uploadThroughNode = cluster.Nodes[0]
+	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`)
+	dataFilename := testutil.TempFileWithContent(t, data)
+	defer os.RemoveAll(dataFilename)
+
+	// upload the file with 'swarm up' and expect a hash
+	up := runSwarm(t,
+		"--bzzapi",
+		cluster.Nodes[0].URL,
+		"up",
+		"--encrypt",
+		dataFilename)
+	_, matches := up.ExpectRegexp(hashRegexp)
+	up.ExpectExit()
+
+	if len(matches) < 1 {
+		t.Fatal("no matches found")
+	}
+
+	ref := matches[0]
+	var grantees []string
+	for i, v := range cluster.Nodes {
+		if i == nodeToSkip {
+			continue
+		}
+		pk := v.PrivateKey
+		granteePubKey := crypto.CompressPubkey(&pk.PublicKey)
+		grantees = append(grantees, hex.EncodeToString(granteePubKey))
+	}
+
+	if bogusEntries > 0 {
+		var bogusGrantees []string
+
+		for i := 0; i < bogusEntries; i++ {
+			prv, err := ecies.GenerateKey(rand.Reader, DefaultCurve, nil)
+			if err != nil {
+				t.Fatal(err)
+			}
+			bogusGrantees = append(bogusGrantees, hex.EncodeToString(crypto.CompressPubkey(&prv.ExportECDSA().PublicKey)))
+		}
+		r2 := gorand.New(gorand.NewSource(time.Now().UnixNano()))
+		for i := 0; i < len(grantees); i++ {
+			insertAtIdx := r2.Intn(len(bogusGrantees))
+			bogusGrantees = append(bogusGrantees[:insertAtIdx], append([]string{grantees[i]}, bogusGrantees[insertAtIdx:]...)...)
+		}
+		grantees = bogusGrantees
+	}
+	granteesPubkeyListFile := testutil.TempFileWithContent(t, strings.Join(grantees, "\n"))
+	defer os.RemoveAll(granteesPubkeyListFile)
+
+	publisherDir, err := ioutil.TempDir("", "swarm-account-dir-temp")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(publisherDir)
+
+	passwordFilename := testutil.TempFileWithContent(t, testPassphrase)
+	defer os.RemoveAll(passwordFilename)
+	actPasswordFilename := testutil.TempFileWithContent(t, "smth")
+	defer os.RemoveAll(actPasswordFilename)
+	_, publisherAccount := getTestAccount(t, publisherDir)
+	up = runSwarm(t,
+		"--bzzaccount",
+		publisherAccount.Address.String(),
+		"--password",
+		passwordFilename,
+		"--datadir",
+		publisherDir,
+		"--bzzapi",
+		cluster.Nodes[0].URL,
+		"access",
+		"new",
+		"act",
+		"--grant-keys",
+		granteesPubkeyListFile,
+		"--password",
+		actPasswordFilename,
+		ref,
+	)
+
+	_, matches = up.ExpectRegexp(`[a-f\d]{64}`)
+	up.ExpectExit()
+
+	if len(matches) == 0 {
+		t.Fatalf("stdout not matched")
+	}
+
+	//get the public key from the publisher directory
+	publicKeyFromDataDir := runSwarm(t,
+		"--bzzaccount",
+		publisherAccount.Address.String(),
+		"--password",
+		passwordFilename,
+		"--datadir",
+		publisherDir,
+		"print-keys",
+		"--compressed",
+	)
+	_, publicKeyString := publicKeyFromDataDir.ExpectRegexp(".+")
+	publicKeyFromDataDir.ExpectExit()
+	pkComp := strings.Split(publicKeyString[0], "=")[1]
+
+	hash := matches[0]
+	m, _, err := client.DownloadManifest(hash)
+	if err != nil {
+		t.Fatalf("unmarshal manifest: %v", err)
+	}
+
+	if len(m.Entries) != 1 {
+		t.Fatalf("expected one manifest entry, got %v", len(m.Entries))
+	}
+
+	e := m.Entries[0]
+
+	ct := "application/bzz-manifest+json"
+	if e.ContentType != ct {
+		t.Errorf("expected %q content type, got %q", ct, e.ContentType)
+	}
+
+	if e.Access == nil {
+		t.Fatal("manifest access is nil")
+	}
+
+	a := e.Access
+
+	if a.Type != "act" {
+		t.Fatalf(`got access type %q, expected "act"`, a.Type)
+	}
+	if len(a.Salt) < 32 {
+		t.Fatalf(`got salt with length %v, expected not less the 32 bytes`, len(a.Salt))
+	}
+
+	if a.Publisher != pkComp {
+		t.Fatal("publisher key did not match")
+	}
+	httpClient := &http.Client{}
+
+	// all nodes except the skipped node should be able to decrypt the content
+	for i, node := range cluster.Nodes {
+		log.Debug("trying to fetch from node", "node index", i)
+
+		url := node.URL + "/" + "bzz:/" + hash
+		response, err := httpClient.Get(url)
+		if err != nil {
+			t.Fatal(err)
+		}
+		log.Debug("got response from node", "response code", response.StatusCode)
+
+		if i == nodeToSkip {
+			log.Debug("reached node to skip", "status code", response.StatusCode)
+
+			if response.StatusCode != http.StatusUnauthorized {
+				t.Fatalf("should be a 401")
+			}
+
+			// try downloading using a password instead, using the unauthorized node
+			passwordUrl := strings.Replace(url, "http://", "http://:smth@", -1)
+			response, err = httpClient.Get(passwordUrl)
+			if err != nil {
+				t.Fatal(err)
+			}
+			if response.StatusCode != http.StatusOK {
+				t.Fatal("should be a 200")
+			}
+
+			// now try with the wrong password, expect 401
+			passwordUrl = strings.Replace(url, "http://", "http://:smthWrong@", -1)
+			response, err = httpClient.Get(passwordUrl)
+			if err != nil {
+				t.Fatal(err)
+			}
+			if response.StatusCode != http.StatusUnauthorized {
+				t.Fatal("should be a 401")
+			}
+			continue
+		}
+
+		if response.StatusCode != http.StatusOK {
+			t.Fatal("should be a 200")
+		}
+		d, err := ioutil.ReadAll(response.Body)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if string(d) != data {
+			t.Errorf("expected decrypted data %q, got %q", data, string(d))
+		}
+	}
+}
+
+// TestKeypairSanity is a sanity test for the crypto scheme for ACT. it asserts the correct shared secret according to
+// the specs at https://github.com/ethersphere/swarm-docs/blob/eb857afda906c6e7bb90d37f3f334ccce5eef230/act.md
+func TestKeypairSanity(t *testing.T) {
+	salt := make([]byte, 32)
+	if _, err := io.ReadFull(rand.Reader, salt); err != nil {
+		t.Fatalf("reading from crypto/rand failed: %v", err.Error())
+	}
+	sharedSecret := "a85586744a1ddd56a7ed9f33fa24f40dd745b3a941be296a0d60e329dbdb896d"
+
+	for i, v := range []struct {
+		publisherPriv string
+		granteePub    string
+	}{
+		{
+			publisherPriv: "ec5541555f3bc6376788425e9d1a62f55a82901683fd7062c5eddcc373a73459",
+			granteePub:    "0226f213613e843a413ad35b40f193910d26eb35f00154afcde9ded57479a6224a",
+		},
+		{
+			publisherPriv: "70c7a73011aa56584a0009ab874794ee7e5652fd0c6911cd02f8b6267dd82d2d",
+			granteePub:    "02e6f8d5e28faaa899744972bb847b6eb805a160494690c9ee7197ae9f619181db",
+		},
+	} {
+		b, _ := hex.DecodeString(v.granteePub)
+		granteePub, _ := crypto.DecompressPubkey(b)
+		publisherPrivate, _ := crypto.HexToECDSA(v.publisherPriv)
+
+		ssKey, err := api.NewSessionKeyPK(publisherPrivate, granteePub, salt)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		hasher := sha3.NewLegacyKeccak256()
+		hasher.Write(salt)
+		shared, err := hex.DecodeString(sharedSecret)
+		if err != nil {
+			t.Fatal(err)
+		}
+		hasher.Write(shared)
+		sum := hasher.Sum(nil)
+
+		if !bytes.Equal(ssKey, sum) {
+			t.Fatalf("%d: got a session key mismatch", i)
+		}
+	}
+}
diff --git a/cmd/swarm/bootnodes.go b/cmd/swarm/bootnodes.go
new file mode 100644
index 0000000000..ce3cd5288e
--- /dev/null
+++ b/cmd/swarm/bootnodes.go
@@ -0,0 +1,24 @@
+// 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
+
+var SwarmBootnodes = []string{
+	// 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/cmd/swarm/config.go b/cmd/swarm/config.go
index 29b5faefa8..0e1e5e39ba 100644
--- a/cmd/swarm/config.go
+++ b/cmd/swarm/config.go
@@ -23,6 +23,8 @@ import (
 	"os"
 	"reflect"
 	"strconv"
+	"strings"
+	"time"
 	"unicode"
 
 	cli "gopkg.in/urfave/cli.v1"
@@ -57,19 +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_ENABLE     = "SWARM_SYNC_ENABLE"
-	SWARM_ENV_ENS_API         = "SWARM_ENS_API"
-	SWARM_ENV_ENS_ADDR        = "SWARM_ENS_ADDR"
-	SWARM_ENV_CORS            = "SWARM_CORS"
-	SWARM_ENV_BOOTNODES       = "SWARM_BOOTNODES"
-	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.
@@ -91,16 +105,19 @@ var tomlSettings = toml.Config{
 
 //before booting the swarm node, build the configuration
 func buildConfig(ctx *cli.Context) (config *bzzapi.Config, err error) {
-	//check for deprecated flags
-	checkDeprecated(ctx)
 	//start by creating a default config
-	config = bzzapi.NewDefaultConfig()
+	config = bzzapi.NewConfig()
 	//first load settings from config file (if provided)
 	config, err = configFileOverride(config, ctx)
+	if err != nil {
+		return nil, err
+	}
 	//override settings provided by environment variables
 	config = envVarsOverride(config)
 	//override settings provided by command line
 	config = cmdLineOverride(config, ctx)
+	//validate configuration parameters
+	err = validateConfig(config)
 
 	return
 }
@@ -111,7 +128,7 @@ func initSwarmNode(config *bzzapi.Config, stack *node.Node, ctx *cli.Context) {
 	//get the account for the provided swarm account
 	prvkey := getAccount(config.BzzAccount, ctx, stack)
 	//set the resolved config path (geth --datadir)
-	config.Path = stack.InstanceDir()
+	config.Path = expandPath(stack.InstanceDir())
 	//finally, initialize the configuration
 	config.Init(prvkey)
 	//configuration phase completed here
@@ -120,7 +137,7 @@ func initSwarmNode(config *bzzapi.Config, stack *node.Node, ctx *cli.Context) {
 	log.Debug(printConfig(config))
 }
 
-//override the current config with whatever is in the config file, if a config file has been provided
+//configFileOverride overrides the current config with the config file, if a config file has been provided
 func configFileOverride(config *bzzapi.Config, ctx *cli.Context) (*bzzapi.Config, error) {
 	var err error
 
@@ -130,7 +147,8 @@ func configFileOverride(config *bzzapi.Config, ctx *cli.Context) (*bzzapi.Config
 		if filepath = ctx.GlobalString(SwarmTomlConfigPathFlag.Name); filepath == "" {
 			utils.Fatalf("Config file flag provided with invalid file path")
 		}
-		f, err := os.Open(filepath)
+		var f *os.File
+		f, err = os.Open(filepath)
 		if err != nil {
 			return nil, err
 		}
@@ -148,10 +166,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
 	}
@@ -161,14 +178,18 @@ func cmdLineOverride(currentConfig *bzzapi.Config, ctx *cli.Context) *bzzapi.Con
 	}
 
 	if networkid := ctx.GlobalString(SwarmNetworkIdFlag.Name); networkid != "" {
-		if id, _ := strconv.Atoi(networkid); id != 0 {
-			currentConfig.NetworkId = uint64(id)
+		id, err := strconv.ParseUint(networkid, 10, 64)
+		if err != nil {
+			utils.Fatalf("invalid cli flag %s: %v", SwarmNetworkIdFlag.Name, err)
+		}
+		if id != 0 {
+			currentConfig.NetworkID = id
 		}
 	}
 
 	if ctx.GlobalIsSet(utils.DataDirFlag.Name) {
 		if datadir := ctx.GlobalString(utils.DataDirFlag.Name); datadir != "" {
-			currentConfig.Path = datadir
+			currentConfig.Path = expandPath(datadir)
 		}
 	}
 
@@ -185,102 +206,182 @@ func cmdLineOverride(currentConfig *bzzapi.Config, ctx *cli.Context) *bzzapi.Con
 		currentConfig.SwapEnabled = true
 	}
 
-	if ctx.GlobalIsSet(SwarmSyncEnabledFlag.Name) {
-		currentConfig.SyncEnabled = true
+	if ctx.GlobalIsSet(SwarmSyncDisabledFlag.Name) {
+		currentConfig.SyncEnabled = false
 	}
 
-	currentConfig.SwapApi = ctx.GlobalString(SwarmSwapAPIFlag.Name)
-	if currentConfig.SwapEnabled && currentConfig.SwapApi == "" {
-		utils.Fatalf(SWARM_ERR_SWAP_SET_NO_API)
+	if d := ctx.GlobalDuration(SwarmSyncUpdateDelay.Name); d > 0 {
+		currentConfig.SyncUpdateDelay = d
+	}
+
+	// any value including 0 is acceptable
+	currentConfig.MaxStreamPeerServers = ctx.GlobalInt(SwarmMaxStreamPeerServersFlag.Name)
+
+	if ctx.GlobalIsSet(SwarmLightNodeEnabled.Name) {
+		currentConfig.LightNodeEnabled = true
+	}
+
+	if ctx.GlobalIsSet(SwarmDeliverySkipCheckFlag.Name) {
+		currentConfig.DeliverySkipCheck = true
+	}
+
+	currentConfig.SwapAPI = ctx.GlobalString(SwarmSwapAPIFlag.Name)
+	if currentConfig.SwapEnabled && currentConfig.SwapAPI == "" {
+		utils.Fatalf(SwarmErrSwapSetNoAPI)
 	}
 
-	//EnsApi can be set to "", so can't check for empty string, as it is allowed!
 	if ctx.GlobalIsSet(EnsAPIFlag.Name) {
-		currentConfig.EnsApi = ctx.GlobalString(EnsAPIFlag.Name)
-	}
+		ensAPIs := ctx.GlobalStringSlice(EnsAPIFlag.Name)
+		// preserve backward compatibility to disable ENS with --ens-api=""
+		if len(ensAPIs) == 1 && ensAPIs[0] == "" {
+			ensAPIs = nil
+		}
+		for i := range ensAPIs {
+			ensAPIs[i] = expandPath(ensAPIs[i])
+		}
 
-	if ensaddr := ctx.GlobalString(EnsAddrFlag.Name); ensaddr != "" {
-		currentConfig.EnsRoot = common.HexToAddress(ensaddr)
+		currentConfig.EnsAPIs = ensAPIs
 	}
 
 	if cors := ctx.GlobalString(CorsStringFlag.Name); cors != "" {
 		currentConfig.Cors = cors
 	}
 
-	if ctx.GlobalIsSet(utils.BootnodesFlag.Name) {
-		currentConfig.BootNodes = ctx.GlobalString(utils.BootnodesFlag.Name)
+	if storePath := ctx.GlobalString(SwarmStorePath.Name); storePath != "" {
+		currentConfig.LocalStoreParams.ChunkDbPath = storePath
+	}
+
+	if storeCapacity := ctx.GlobalUint64(SwarmStoreCapacity.Name); storeCapacity != 0 {
+		currentConfig.LocalStoreParams.DbCapacity = storeCapacity
+	}
+
+	if storeCacheCapacity := ctx.GlobalUint(SwarmStoreCacheCapacity.Name); storeCacheCapacity != 0 {
+		currentConfig.LocalStoreParams.CacheCapacity = storeCacheCapacity
+	}
+
+	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 id, _ := strconv.Atoi(networkid); id != 0 {
-			currentConfig.NetworkId = uint64(id)
+	if networkid := os.Getenv(SwarmEnvNetworkID); networkid != "" {
+		id, err := strconv.ParseUint(networkid, 10, 64)
+		if err != nil {
+			utils.Fatalf("invalid environment variable %s: %v", SwarmEnvNetworkID, err)
+		}
+		if id != 0 {
+			currentConfig.NetworkID = id
 		}
 	}
 
-	if datadir := os.Getenv(GETH_ENV_DATADIR); datadir != "" {
-		currentConfig.Path = 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 swap, err := strconv.ParseBool(swapenable); err != nil {
-			currentConfig.SwapEnabled = swap
+	if swapenable := os.Getenv(SwarmEnvSwapEnable); swapenable != "" {
+		swap, err := strconv.ParseBool(swapenable)
+		if err != nil {
+			utils.Fatalf("invalid environment variable %s: %v", SwarmEnvSwapEnable, err)
+		}
+		currentConfig.SwapEnabled = swap
+	}
+
+	if syncdisable := os.Getenv(SwarmEnvSyncDisable); syncdisable != "" {
+		sync, err := strconv.ParseBool(syncdisable)
+		if err != nil {
+			utils.Fatalf("invalid environment variable %s: %v", SwarmEnvSyncDisable, err)
+		}
+		currentConfig.SyncEnabled = !sync
+	}
+
+	if v := os.Getenv(SwarmEnvDeliverySkipCheck); v != "" {
+		skipCheck, err := strconv.ParseBool(v)
+		if err != nil {
+			currentConfig.DeliverySkipCheck = skipCheck
 		}
 	}
 
-	if syncenable := os.Getenv(SWARM_ENV_SYNC_ENABLE); syncenable != "" {
-		if sync, err := strconv.ParseBool(syncenable); err != nil {
-			currentConfig.SyncEnabled = sync
+	if v := os.Getenv(SwarmEnvSyncUpdateDelay); v != "" {
+		d, err := time.ParseDuration(v)
+		if err != nil {
+			utils.Fatalf("invalid environment variable %s: %v", SwarmEnvSyncUpdateDelay, err)
 		}
+		currentConfig.SyncUpdateDelay = d
 	}
 
-	if swapapi := os.Getenv(SWARM_ENV_SWAP_API); swapapi != "" {
-		currentConfig.SwapApi = swapapi
+	if max := os.Getenv(SwarmEnvMaxStreamPeerServers); max != "" {
+		m, err := strconv.Atoi(max)
+		if err != nil {
+			utils.Fatalf("invalid environment variable %s: %v", SwarmEnvMaxStreamPeerServers, err)
+		}
+		currentConfig.MaxStreamPeerServers = m
 	}
 
-	if currentConfig.SwapEnabled && currentConfig.SwapApi == "" {
-		utils.Fatalf(SWARM_ERR_SWAP_SET_NO_API)
+	if lne := os.Getenv(SwarmEnvLightNodeEnable); lne != "" {
+		lightnode, err := strconv.ParseBool(lne)
+		if err != nil {
+			utils.Fatalf("invalid environment variable %s: %v", SwarmEnvLightNodeEnable, err)
+		}
+		currentConfig.LightNodeEnabled = lightnode
 	}
 
-	//EnsApi can be set to "", so can't check for empty string, as it is allowed
-	if ensapi, exists := os.LookupEnv(SWARM_ENV_ENS_API); exists {
-		currentConfig.EnsApi = ensapi
+	if swapapi := os.Getenv(SwarmEnvSwapAPI); swapapi != "" {
+		currentConfig.SwapAPI = swapapi
 	}
 
-	if ensaddr := os.Getenv(SWARM_ENV_ENS_ADDR); ensaddr != "" {
+	if currentConfig.SwapEnabled && currentConfig.SwapAPI == "" {
+		utils.Fatalf(SwarmErrSwapSetNoAPI)
+	}
+
+	if ensapi := os.Getenv(SwarmEnvENSAPI); ensapi != "" {
+		currentConfig.EnsAPIs = strings.Split(ensapi, ",")
+	}
+
+	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 bootnodes := os.Getenv(SWARM_ENV_BOOTNODES); bootnodes != "" {
-		currentConfig.BootNodes = bootnodes
+	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
@@ -303,12 +404,37 @@ func dumpConfig(ctx *cli.Context) error {
 	return nil
 }
 
-//deprecated flags checked here
-func checkDeprecated(ctx *cli.Context) {
-	// exit if the deprecated --ethapi flag is set
-	if ctx.GlobalString(DeprecatedEthAPIFlag.Name) != "" {
-		utils.Fatalf("--ethapi is no longer a valid command line flag, please use --ens-api and/or --swap-api.")
+//validate configuration parameters
+func validateConfig(cfg *bzzapi.Config) (err error) {
+	for _, ensAPI := range cfg.EnsAPIs {
+		if ensAPI != "" {
+			if err := validateEnsAPIs(ensAPI); err != nil {
+				return fmt.Errorf("invalid format [tld:][contract-addr@]url for ENS API endpoint configuration %q: %v", ensAPI, err)
+			}
+		}
 	}
+	return nil
+}
+
+//validate EnsAPIs configuration parameter
+func validateEnsAPIs(s string) (err error) {
+	// missing contract address
+	if strings.HasPrefix(s, "@") {
+		return errors.New("missing contract address")
+	}
+	// missing url
+	if strings.HasSuffix(s, "@") {
+		return errors.New("missing url")
+	}
+	// missing tld
+	if strings.HasPrefix(s, ":") {
+		return errors.New("missing tld")
+	}
+	// missing url
+	if strings.HasSuffix(s, ":") {
+		return errors.New("missing url")
+	}
+	return nil
 }
 
 //print a Config as string
diff --git a/cmd/swarm/config_test.go b/cmd/swarm/config_test.go
index 166980d148..869edd0f70 100644
--- a/cmd/swarm/config_test.go
+++ b/cmd/swarm/config_test.go
@@ -20,21 +20,22 @@ import (
 	"fmt"
 	"io"
 	"io/ioutil"
+	"net"
 	"os"
 	"os/exec"
 	"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.NewDefaultConfig()
+	defaultConf := api.NewConfig()
 	out, err := tomlSettings.Marshal(&defaultConf)
 	if err != nil {
 		t.Fatal(err)
@@ -43,7 +44,7 @@ func TestDumpConfig(t *testing.T) {
 	swarm.ExpectExit()
 }
 
-func TestFailsSwapEnabledNoSwapApi(t *testing.T) {
+func TestConfigFailsSwapEnabledNoSwapApi(t *testing.T) {
 	flags := []string{
 		fmt.Sprintf("--%s", SwarmNetworkIdFlag.Name), "42",
 		fmt.Sprintf("--%s", SwarmPortFlag.Name), "54545",
@@ -51,22 +52,22 @@ func TestFailsSwapEnabledNoSwapApi(t *testing.T) {
 	}
 
 	swarm := runSwarm(t, flags...)
-	swarm.Expect("Fatal: " + SWARM_ERR_SWAP_SET_NO_API + "\n")
+	swarm.Expect("Fatal: " + SwarmErrSwapSetNoAPI + "\n")
 	swarm.ExpectExit()
 }
 
-func TestFailsNoBzzAccount(t *testing.T) {
+func TestConfigFailsNoBzzAccount(t *testing.T) {
 	flags := []string{
 		fmt.Sprintf("--%s", SwarmNetworkIdFlag.Name), "42",
 		fmt.Sprintf("--%s", SwarmPortFlag.Name), "54545",
 	}
 
 	swarm := runSwarm(t, flags...)
-	swarm.Expect("Fatal: " + SWARM_ERR_NO_BZZACCOUNT + "\n")
+	swarm.Expect("Fatal: " + SwarmErrNoBZZAccount + "\n")
 	swarm.ExpectExit()
 }
 
-func TestCmdLineOverrides(t *testing.T) {
+func TestConfigCmdLineOverrides(t *testing.T) {
 	dir, err := ioutil.TempDir("", "bzztest")
 	if err != nil {
 		t.Fatal(err)
@@ -85,12 +86,13 @@ func TestCmdLineOverrides(t *testing.T) {
 	flags := []string{
 		fmt.Sprintf("--%s", SwarmNetworkIdFlag.Name), "42",
 		fmt.Sprintf("--%s", SwarmPortFlag.Name), httpPort,
-		fmt.Sprintf("--%s", SwarmSyncEnabledFlag.Name),
+		fmt.Sprintf("--%s", SwarmSyncDisabledFlag.Name),
 		fmt.Sprintf("--%s", CorsStringFlag.Name), "*",
 		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)
@@ -120,12 +122,16 @@ func TestCmdLineOverrides(t *testing.T) {
 		t.Fatalf("Expected port to be %s, got %s", httpPort, info.Port)
 	}
 
-	if info.NetworkId != 42 {
-		t.Fatalf("Expected network ID to be %d, got %d", 42, info.NetworkId)
+	if info.NetworkID != 42 {
+		t.Fatalf("Expected network ID to be %d, got %d", 42, info.NetworkID)
 	}
 
-	if !info.SyncEnabled {
-		t.Fatal("Expected Sync to be enabled, but is false")
+	if info.SyncEnabled {
+		t.Fatal("Expected Sync to be disabled, but is true")
+	}
+
+	if !info.DeliverySkipCheck {
+		t.Fatal("Expected DeliverySkipCheck to be enabled, but it is not")
 	}
 
 	if info.Cors != "*" {
@@ -135,7 +141,7 @@ func TestCmdLineOverrides(t *testing.T) {
 	node.Shutdown()
 }
 
-func TestFileOverrides(t *testing.T) {
+func TestConfigFileOverrides(t *testing.T) {
 
 	// assign ports
 	httpPort, err := assignTCPPort()
@@ -145,16 +151,16 @@ func TestFileOverrides(t *testing.T) {
 
 	//create a config file
 	//first, create a default conf
-	defaultConf := api.NewDefaultConfig()
+	defaultConf := api.NewConfig()
 	//change some values in order to test if they have been loaded
-	defaultConf.SyncEnabled = true
-	defaultConf.NetworkId = 54
+	defaultConf.SyncEnabled = false
+	defaultConf.DeliverySkipCheck = true
+	defaultConf.NetworkID = 54
 	defaultConf.Port = httpPort
-	defaultConf.StoreParams.DbCapacity = 9000000
-	defaultConf.ChunkerParams.Branches = 64
-	defaultConf.HiveParams.CallInterval = 6000000000
+	defaultConf.DbCapacity = 9000000
+	defaultConf.HiveParams.KeepAliveInterval = 6000000000
 	defaultConf.Swap.Params.Strategy.AutoCashInterval = 600 * time.Second
-	defaultConf.SyncParams.KeyBufferSize = 512
+	//defaultConf.SyncParams.KeyBufferSize = 512
 	//create a TOML string
 	out, err := tomlSettings.Marshal(&defaultConf)
 	if err != nil {
@@ -183,9 +189,9 @@ func TestFileOverrides(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)
@@ -215,38 +221,38 @@ func TestFileOverrides(t *testing.T) {
 		t.Fatalf("Expected port to be %s, got %s", httpPort, info.Port)
 	}
 
-	if info.NetworkId != 54 {
-		t.Fatalf("Expected network ID to be %d, got %d", 54, info.NetworkId)
+	if info.NetworkID != 54 {
+		t.Fatalf("Expected network ID to be %d, got %d", 54, info.NetworkID)
 	}
 
-	if !info.SyncEnabled {
-		t.Fatal("Expected Sync to be enabled, but is false")
+	if info.SyncEnabled {
+		t.Fatal("Expected Sync to be disabled, but is true")
 	}
 
-	if info.StoreParams.DbCapacity != 9000000 {
-		t.Fatalf("Expected network ID to be %d, got %d", 54, info.NetworkId)
+	if !info.DeliverySkipCheck {
+		t.Fatal("Expected DeliverySkipCheck to be enabled, but it is not")
 	}
 
-	if info.ChunkerParams.Branches != 64 {
-		t.Fatalf("Expected chunker params branches to be %d, got %d", 64, info.ChunkerParams.Branches)
+	if info.DbCapacity != 9000000 {
+		t.Fatalf("Expected network ID to be %d, got %d", 54, info.NetworkID)
 	}
 
-	if info.HiveParams.CallInterval != 6000000000 {
-		t.Fatalf("Expected HiveParams CallInterval to be %d, got %d", uint64(6000000000), uint64(info.HiveParams.CallInterval))
+	if info.HiveParams.KeepAliveInterval != 6000000000 {
+		t.Fatalf("Expected HiveParams KeepAliveInterval to be %d, got %d", uint64(6000000000), uint64(info.HiveParams.KeepAliveInterval))
 	}
 
 	if info.Swap.Params.Strategy.AutoCashInterval != 600*time.Second {
 		t.Fatalf("Expected SwapParams AutoCashInterval to be %ds, got %d", 600, info.Swap.Params.Strategy.AutoCashInterval)
 	}
 
-	if info.SyncParams.KeyBufferSize != 512 {
-		t.Fatalf("Expected info.SyncParams.KeyBufferSize to be %d, got %d", 512, info.SyncParams.KeyBufferSize)
-	}
+	//	if info.SyncParams.KeyBufferSize != 512 {
+	//		t.Fatalf("Expected info.SyncParams.KeyBufferSize to be %d, got %d", 512, info.SyncParams.KeyBufferSize)
+	//	}
 
 	node.Shutdown()
 }
 
-func TestEnvVars(t *testing.T) {
+func TestConfigEnvVars(t *testing.T) {
 	// assign ports
 	httpPort, err := assignTCPPort()
 	if err != nil {
@@ -257,7 +263,8 @@ func TestEnvVars(t *testing.T) {
 	envVars = append(envVars, fmt.Sprintf("%s=%s", SwarmPortFlag.EnvVar, httpPort))
 	envVars = append(envVars, fmt.Sprintf("%s=%s", SwarmNetworkIdFlag.EnvVar, "999"))
 	envVars = append(envVars, fmt.Sprintf("%s=%s", CorsStringFlag.EnvVar, "*"))
-	envVars = append(envVars, fmt.Sprintf("%s=%s", SwarmSyncEnabledFlag.EnvVar, "true"))
+	envVars = append(envVars, fmt.Sprintf("%s=%s", SwarmSyncDisabledFlag.EnvVar, "true"))
+	envVars = append(envVars, fmt.Sprintf("%s=%s", SwarmDeliverySkipCheckFlag.EnvVar, "true"))
 
 	dir, err := ioutil.TempDir("", "bzztest")
 	if err != nil {
@@ -326,23 +333,27 @@ func TestEnvVars(t *testing.T) {
 		t.Fatalf("Expected port to be %s, got %s", httpPort, info.Port)
 	}
 
-	if info.NetworkId != 999 {
-		t.Fatalf("Expected network ID to be %d, got %d", 999, info.NetworkId)
+	if info.NetworkID != 999 {
+		t.Fatalf("Expected network ID to be %d, got %d", 999, info.NetworkID)
 	}
 
 	if info.Cors != "*" {
 		t.Fatalf("Expected Cors flag to be set to %s, got %s", "*", info.Cors)
 	}
 
-	if !info.SyncEnabled {
-		t.Fatal("Expected Sync to be enabled, but is false")
+	if info.SyncEnabled {
+		t.Fatal("Expected Sync to be disabled, but is true")
+	}
+
+	if !info.DeliverySkipCheck {
+		t.Fatal("Expected DeliverySkipCheck to be enabled, but it is not")
 	}
 
 	node.Shutdown()
 	cmd.Process.Kill()
 }
 
-func TestCmdLineOverridesFile(t *testing.T) {
+func TestConfigCmdLineOverridesFile(t *testing.T) {
 
 	// assign ports
 	httpPort, err := assignTCPPort()
@@ -352,26 +363,27 @@ func TestCmdLineOverridesFile(t *testing.T) {
 
 	//create a config file
 	//first, create a default conf
-	defaultConf := api.NewDefaultConfig()
+	defaultConf := api.NewConfig()
 	//change some values in order to test if they have been loaded
-	defaultConf.SyncEnabled = false
-	defaultConf.NetworkId = 54
+	defaultConf.SyncEnabled = true
+	defaultConf.NetworkID = 54
 	defaultConf.Port = "8588"
-	defaultConf.StoreParams.DbCapacity = 9000000
-	defaultConf.ChunkerParams.Branches = 64
-	defaultConf.HiveParams.CallInterval = 6000000000
+	defaultConf.DbCapacity = 9000000
+	defaultConf.HiveParams.KeepAliveInterval = 6000000000
 	defaultConf.Swap.Params.Strategy.AutoCashInterval = 600 * time.Second
-	defaultConf.SyncParams.KeyBufferSize = 512
+	//defaultConf.SyncParams.KeyBufferSize = 512
 	//create a TOML file
 	out, err := tomlSettings.Marshal(&defaultConf)
 	if err != nil {
 		t.Fatalf("Error creating TOML file in TestFileOverride: %v", err)
 	}
 	//write file
-	f, err := ioutil.TempFile("", "testconfig.toml")
+	fname := "testconfig.toml"
+	f, err := ioutil.TempFile("", fname)
 	if err != nil {
 		t.Fatalf("Error writing TOML file in TestFileOverride: %v", err)
 	}
+	defer os.Remove(fname)
 	//write file
 	_, err = f.WriteString(string(out))
 	if err != nil {
@@ -392,12 +404,12 @@ func TestCmdLineOverridesFile(t *testing.T) {
 	flags := []string{
 		fmt.Sprintf("--%s", SwarmNetworkIdFlag.Name), "77",
 		fmt.Sprintf("--%s", SwarmPortFlag.Name), httpPort,
-		fmt.Sprintf("--%s", SwarmSyncEnabledFlag.Name),
+		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)
@@ -427,33 +439,137 @@ func TestCmdLineOverridesFile(t *testing.T) {
 		t.Fatalf("Expected port to be %s, got %s", httpPort, info.Port)
 	}
 
-	if info.NetworkId != expectNetworkId {
-		t.Fatalf("Expected network ID to be %d, got %d", expectNetworkId, info.NetworkId)
+	if info.NetworkID != expectNetworkId {
+		t.Fatalf("Expected network ID to be %d, got %d", expectNetworkId, info.NetworkID)
 	}
 
-	if !info.SyncEnabled {
-		t.Fatal("Expected Sync to be enabled, but is false")
+	if info.SyncEnabled {
+		t.Fatal("Expected Sync to be disabled, but is true")
 	}
 
-	if info.StoreParams.DbCapacity != 9000000 {
-		t.Fatalf("Expected network ID to be %d, got %d", 54, info.NetworkId)
+	if info.LocalStoreParams.DbCapacity != 9000000 {
+		t.Fatalf("Expected Capacity to be %d, got %d", 9000000, info.LocalStoreParams.DbCapacity)
 	}
 
-	if info.ChunkerParams.Branches != 64 {
-		t.Fatalf("Expected chunker params branches to be %d, got %d", 64, info.ChunkerParams.Branches)
-	}
-
-	if info.HiveParams.CallInterval != 6000000000 {
-		t.Fatalf("Expected HiveParams CallInterval to be %d, got %d", uint64(6000000000), uint64(info.HiveParams.CallInterval))
+	if info.HiveParams.KeepAliveInterval != 6000000000 {
+		t.Fatalf("Expected HiveParams KeepAliveInterval to be %d, got %d", uint64(6000000000), uint64(info.HiveParams.KeepAliveInterval))
 	}
 
 	if info.Swap.Params.Strategy.AutoCashInterval != 600*time.Second {
 		t.Fatalf("Expected SwapParams AutoCashInterval to be %ds, got %d", 600, info.Swap.Params.Strategy.AutoCashInterval)
 	}
 
-	if info.SyncParams.KeyBufferSize != 512 {
-		t.Fatalf("Expected info.SyncParams.KeyBufferSize to be %d, got %d", 512, info.SyncParams.KeyBufferSize)
-	}
+	//	if info.SyncParams.KeyBufferSize != 512 {
+	//		t.Fatalf("Expected info.SyncParams.KeyBufferSize to be %d, got %d", 512, info.SyncParams.KeyBufferSize)
+	//	}
 
 	node.Shutdown()
 }
+
+func TestConfigValidate(t *testing.T) {
+	for _, c := range []struct {
+		cfg *api.Config
+		err string
+	}{
+		{
+			cfg: &api.Config{EnsAPIs: []string{
+				"/data/testnet/geth.ipc",
+			}},
+		},
+		{
+			cfg: &api.Config{EnsAPIs: []string{
+				"http://127.0.0.1:1234",
+			}},
+		},
+		{
+			cfg: &api.Config{EnsAPIs: []string{
+				"ws://127.0.0.1:1234",
+			}},
+		},
+		{
+			cfg: &api.Config{EnsAPIs: []string{
+				"test:/data/testnet/geth.ipc",
+			}},
+		},
+		{
+			cfg: &api.Config{EnsAPIs: []string{
+				"test:ws://127.0.0.1:1234",
+			}},
+		},
+		{
+			cfg: &api.Config{EnsAPIs: []string{
+				"314159265dD8dbb310642f98f50C066173C1259b@/data/testnet/geth.ipc",
+			}},
+		},
+		{
+			cfg: &api.Config{EnsAPIs: []string{
+				"314159265dD8dbb310642f98f50C066173C1259b@http://127.0.0.1:1234",
+			}},
+		},
+		{
+			cfg: &api.Config{EnsAPIs: []string{
+				"314159265dD8dbb310642f98f50C066173C1259b@ws://127.0.0.1:1234",
+			}},
+		},
+		{
+			cfg: &api.Config{EnsAPIs: []string{
+				"test:314159265dD8dbb310642f98f50C066173C1259b@/data/testnet/geth.ipc",
+			}},
+		},
+		{
+			cfg: &api.Config{EnsAPIs: []string{
+				"eth:314159265dD8dbb310642f98f50C066173C1259b@http://127.0.0.1:1234",
+			}},
+		},
+		{
+			cfg: &api.Config{EnsAPIs: []string{
+				"eth:314159265dD8dbb310642f98f50C066173C1259b@ws://127.0.0.1:12344",
+			}},
+		},
+		{
+			cfg: &api.Config{EnsAPIs: []string{
+				"eth:",
+			}},
+			err: "invalid format [tld:][contract-addr@]url for ENS API endpoint configuration \"eth:\": missing url",
+		},
+		{
+			cfg: &api.Config{EnsAPIs: []string{
+				"314159265dD8dbb310642f98f50C066173C1259b@",
+			}},
+			err: "invalid format [tld:][contract-addr@]url for ENS API endpoint configuration \"314159265dD8dbb310642f98f50C066173C1259b@\": missing url",
+		},
+		{
+			cfg: &api.Config{EnsAPIs: []string{
+				":314159265dD8dbb310642f98f50C066173C1259",
+			}},
+			err: "invalid format [tld:][contract-addr@]url for ENS API endpoint configuration \":314159265dD8dbb310642f98f50C066173C1259\": missing tld",
+		},
+		{
+			cfg: &api.Config{EnsAPIs: []string{
+				"@/data/testnet/geth.ipc",
+			}},
+			err: "invalid format [tld:][contract-addr@]url for ENS API endpoint configuration \"@/data/testnet/geth.ipc\": missing contract address",
+		},
+	} {
+		err := validateConfig(c.cfg)
+		if c.err != "" && err.Error() != c.err {
+			t.Errorf("expected error %q, got %q", c.err, err)
+		}
+		if c.err == "" && err != nil {
+			t.Errorf("unexpected error %q", err)
+		}
+	}
+}
+
+func assignTCPPort() (string, error) {
+	l, err := net.Listen("tcp", "127.0.0.1:0")
+	if err != nil {
+		return "", err
+	}
+	l.Close()
+	_, port, err := net.SplitHostPort(l.Addr().String())
+	if err != nil {
+		return "", err
+	}
+	return port, nil
+}
diff --git a/cmd/swarm/db.go b/cmd/swarm/db.go
index dfd2d069b9..7916beffce 100644
--- a/cmd/swarm/db.go
+++ b/cmd/swarm/db.go
@@ -23,18 +23,61 @@ import (
 	"path/filepath"
 
 	"github.com/ethereum/go-ethereum/cmd/utils"
+	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/log"
 	"github.com/ethereum/go-ethereum/swarm/storage"
 	"gopkg.in/urfave/cli.v1"
 )
 
+var dbCommand = cli.Command{
+	Name:               "db",
+	CustomHelpTemplate: helpTemplate,
+	Usage:              "manage the local chunk database",
+	ArgsUsage:          "db COMMAND",
+	Description:        "Manage the local chunk database",
+	Subcommands: []cli.Command{
+		{
+			Action:             dbExport,
+			CustomHelpTemplate: helpTemplate,
+			Name:               "export",
+			Usage:              "export a local chunk database as a tar archive (use - to send to stdout)",
+			ArgsUsage:          " ",
+			Description: `
+Export a local chunk database as a tar archive (use - to send to stdout).
+
+    swarm db export ~/.ethereum/swarm/bzz-KEY/chunks chunks.tar
+
+The export may be quite large, consider piping the output through the Unix
+pv(1) tool to get a progress bar:
+
+    swarm db export ~/.ethereum/swarm/bzz-KEY/chunks - | pv > chunks.tar
+`,
+		},
+		{
+			Action:             dbImport,
+			CustomHelpTemplate: helpTemplate,
+			Name:               "import",
+			Usage:              "import chunks from a tar archive into a local chunk database (use - to read from stdin)",
+			ArgsUsage:          " ",
+			Description: `Import chunks from a tar archive into a local chunk database (use - to read from stdin).
+
+    swarm db import ~/.ethereum/swarm/bzz-KEY/chunks chunks.tar
+
+The import may be quite large, consider piping the input through the Unix
+pv(1) tool to get a progress bar:
+
+    pv chunks.tar | swarm db import ~/.ethereum/swarm/bzz-KEY/chunks -`,
+		},
+	},
+}
+
 func dbExport(ctx *cli.Context) {
 	args := ctx.Args()
-	if len(args) != 2 {
-		utils.Fatalf("invalid arguments, please specify both  (path to a local chunk database) and  (path to write the tar archive to, - for stdout)")
+	if len(args) != 3 {
+		utils.Fatalf("invalid arguments, please specify both  (path to a local chunk database),  (path to write the tar archive to, - for stdout) and the base key")
 	}
 
-	store, err := openDbStore(args[0])
+	store, err := openLDBStore(args[0], common.Hex2Bytes(args[2]))
 	if err != nil {
 		utils.Fatalf("error opening local chunk database: %s", err)
 	}
@@ -62,11 +105,11 @@ func dbExport(ctx *cli.Context) {
 
 func dbImport(ctx *cli.Context) {
 	args := ctx.Args()
-	if len(args) != 2 {
-		utils.Fatalf("invalid arguments, please specify both  (path to a local chunk database) and  (path to read the tar archive from, - for stdin)")
+	if len(args) != 3 {
+		utils.Fatalf("invalid arguments, please specify both  (path to a local chunk database),  (path to read the tar archive from, - for stdin) and the base key")
 	}
 
-	store, err := openDbStore(args[0])
+	store, err := openLDBStore(args[0], common.Hex2Bytes(args[2]))
 	if err != nil {
 		utils.Fatalf("error opening local chunk database: %s", err)
 	}
@@ -92,25 +135,13 @@ func dbImport(ctx *cli.Context) {
 	log.Info(fmt.Sprintf("successfully imported %d chunks", count))
 }
 
-func dbClean(ctx *cli.Context) {
-	args := ctx.Args()
-	if len(args) != 1 {
-		utils.Fatalf("invalid arguments, please specify  (path to a local chunk database)")
-	}
-
-	store, err := openDbStore(args[0])
-	if err != nil {
-		utils.Fatalf("error opening local chunk database: %s", err)
-	}
-	defer store.Close()
-
-	store.Cleanup()
-}
-
-func openDbStore(path string) (*storage.DbStore, error) {
+func openLDBStore(path string, basekey []byte) (*storage.LDBStore, error) {
 	if _, err := os.Stat(filepath.Join(path, "CURRENT")); err != nil {
 		return nil, fmt.Errorf("invalid chunkdb path: %s", err)
 	}
-	hash := storage.MakeHashFunc("SHA3")
-	return storage.NewDbStore(path, hash, 10000000, 0)
+
+	storeparams := storage.NewDefaultStoreParams()
+	ldbparams := storage.NewLDBStoreParams(storeparams, path)
+	ldbparams.BaseKey = basekey
+	return storage.NewLDBStore(ldbparams)
 }
diff --git a/cmd/swarm/download.go b/cmd/swarm/download.go
new file mode 100644
index 0000000000..fcbefa0206
--- /dev/null
+++ b/cmd/swarm/download.go
@@ -0,0 +1,112 @@
+// 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"
+	"path/filepath"
+	"strings"
+
+	"github.com/ethereum/go-ethereum/cmd/utils"
+	"github.com/ethereum/go-ethereum/log"
+	"github.com/ethereum/go-ethereum/swarm/api"
+	swarm "github.com/ethereum/go-ethereum/swarm/api/client"
+	"gopkg.in/urfave/cli.v1"
+)
+
+var downloadCommand = cli.Command{
+	Action:      download,
+	Name:        "down",
+	Flags:       []cli.Flag{SwarmRecursiveFlag, SwarmAccessPasswordFlag},
+	Usage:       "downloads a swarm manifest or a file inside a manifest",
+	ArgsUsage:   "  []",
+	Description: `Downloads a swarm bzz uri to the given dir. When no dir is provided, working directory is assumed. --recursive flag is expected when downloading a manifest with multiple entries.`,
+}
+
+func download(ctx *cli.Context) {
+	log.Debug("downloading content using swarm down")
+	args := ctx.Args()
+	dest := "."
+
+	switch len(args) {
+	case 0:
+		utils.Fatalf("Usage: swarm down [options]  []")
+	case 1:
+		log.Trace(fmt.Sprintf("swarm down: no destination path - assuming working dir"))
+	default:
+		log.Trace(fmt.Sprintf("destination path arg: %s", args[1]))
+		if absDest, err := filepath.Abs(args[1]); err == nil {
+			dest = absDest
+		} else {
+			utils.Fatalf("could not get download path: %v", err)
+		}
+	}
+
+	var (
+		bzzapi      = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
+		isRecursive = ctx.Bool(SwarmRecursiveFlag.Name)
+		client      = swarm.NewClient(bzzapi)
+	)
+
+	if fi, err := os.Stat(dest); err == nil {
+		if isRecursive && !fi.Mode().IsDir() {
+			utils.Fatalf("destination path is not a directory!")
+		}
+	} else {
+		if !os.IsNotExist(err) {
+			utils.Fatalf("could not stat path: %v", err)
+		}
+	}
+
+	uri, err := api.Parse(args[0])
+	if err != nil {
+		utils.Fatalf("could not parse uri argument: %v", err)
+	}
+
+	dl := func(credentials string) error {
+		// assume behaviour according to --recursive switch
+		if isRecursive {
+			if err := client.DownloadDirectory(uri.Addr, uri.Path, dest, credentials); err != nil {
+				if err == swarm.ErrUnauthorized {
+					return err
+				}
+				return fmt.Errorf("directory %s: %v", uri.Path, err)
+			}
+		} else {
+			// we are downloading a file
+			log.Debug("downloading file/path from a manifest", "uri.Addr", uri.Addr, "uri.Path", uri.Path)
+
+			err := client.DownloadFile(uri.Addr, uri.Path, dest, credentials)
+			if err != nil {
+				if err == swarm.ErrUnauthorized {
+					return err
+				}
+				return fmt.Errorf("file %s from address: %s: %v", uri.Path, uri.Addr, err)
+			}
+		}
+		return nil
+	}
+	if passwords := makePasswordList(ctx); passwords != nil {
+		password := getPassPhrase(fmt.Sprintf("Downloading %s is restricted", uri), 0, passwords)
+		err = dl(password)
+	} else {
+		err = dl("")
+	}
+	if err != nil {
+		utils.Fatalf("download: %v", err)
+	}
+}
diff --git a/cmd/swarm/explore.go b/cmd/swarm/explore.go
new file mode 100644
index 0000000000..5b5b8bf41f
--- /dev/null
+++ b/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/cmd/swarm/export_test.go b/cmd/swarm/export_test.go
new file mode 100644
index 0000000000..e8671eea79
--- /dev/null
+++ b/cmd/swarm/export_test.go
@@ -0,0 +1,119 @@
+// 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"
+	"crypto/md5"
+	"io"
+	"net/http"
+	"os"
+	"runtime"
+	"strings"
+	"testing"
+
+	"github.com/ethereum/go-ethereum/swarm"
+	"github.com/ethereum/go-ethereum/swarm/testutil"
+)
+
+// TestCLISwarmExportImport perform the following test:
+// 1. runs swarm node
+// 2. uploads a random file
+// 3. runs an export of the local datastore
+// 4. runs a second swarm node
+// 5. imports the exported datastore
+// 6. fetches the uploaded random file from the second node
+func TestCLISwarmExportImport(t *testing.T) {
+	if runtime.GOOS == "windows" {
+		t.Skip()
+	}
+	cluster := newTestCluster(t, 1)
+
+	// generate random 1mb file
+	content := testutil.RandomBytes(1, 1000000)
+	fileName := testutil.TempFileWithContent(t, string(content))
+	defer os.Remove(fileName)
+
+	// upload the file with 'swarm up' and expect a hash
+	up := runSwarm(t, "--bzzapi", cluster.Nodes[0].URL, "up", fileName)
+	_, matches := up.ExpectRegexp(`[a-f\d]{64}`)
+	up.ExpectExit()
+	hash := matches[0]
+
+	var info swarm.Info
+	if err := cluster.Nodes[0].Client.Call(&info, "bzz_info"); err != nil {
+		t.Fatal(err)
+	}
+
+	cluster.Stop()
+	defer cluster.Cleanup()
+
+	// generate an export.tar
+	exportCmd := runSwarm(t, "db", "export", info.Path+"/chunks", info.Path+"/export.tar", strings.TrimPrefix(info.BzzKey, "0x"))
+	exportCmd.ExpectExit()
+
+	// start second cluster
+	cluster2 := newTestCluster(t, 1)
+
+	var info2 swarm.Info
+	if err := cluster2.Nodes[0].Client.Call(&info2, "bzz_info"); err != nil {
+		t.Fatal(err)
+	}
+
+	// stop second cluster, so that we close LevelDB
+	cluster2.Stop()
+	defer cluster2.Cleanup()
+
+	// import the export.tar
+	importCmd := runSwarm(t, "db", "import", info2.Path+"/chunks", info.Path+"/export.tar", strings.TrimPrefix(info2.BzzKey, "0x"))
+	importCmd.ExpectExit()
+
+	// spin second cluster back up
+	cluster2.StartExistingNodes(t, 1, strings.TrimPrefix(info2.BzzAccount, "0x"))
+
+	// try to fetch imported file
+	res, err := http.Get(cluster2.Nodes[0].URL + "/bzz:/" + hash)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if res.StatusCode != 200 {
+		t.Fatalf("expected HTTP status %d, got %s", 200, res.Status)
+	}
+
+	// compare downloaded file with the generated random file
+	mustEqualFiles(t, bytes.NewReader(content), res.Body)
+}
+
+func mustEqualFiles(t *testing.T, up io.Reader, down io.Reader) {
+	h := md5.New()
+	upLen, err := io.Copy(h, up)
+	if err != nil {
+		t.Fatal(err)
+	}
+	upHash := h.Sum(nil)
+	h.Reset()
+	downLen, err := io.Copy(h, down)
+	if err != nil {
+		t.Fatal(err)
+	}
+	downHash := h.Sum(nil)
+
+	if !bytes.Equal(upHash, downHash) || upLen != downLen {
+		t.Fatalf("downloaded imported file md5=%x (length %v) is not the same as the generated one mp5=%x (length %v)", downHash, downLen, upHash, upLen)
+	}
+}
diff --git a/cmd/swarm/feeds.go b/cmd/swarm/feeds.go
new file mode 100644
index 0000000000..6cd971a92c
--- /dev/null
+++ b/cmd/swarm/feeds.go
@@ -0,0 +1,238 @@
+// Copyright 2016 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 feed allows the user to create and update signed Swarm feeds
+package main
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/common/hexutil"
+	"github.com/ethereum/go-ethereum/crypto"
+
+	"github.com/ethereum/go-ethereum/cmd/utils"
+	swarm "github.com/ethereum/go-ethereum/swarm/api/client"
+	"github.com/ethereum/go-ethereum/swarm/storage/feed"
+	"gopkg.in/urfave/cli.v1"
+)
+
+var feedCommand = cli.Command{
+	CustomHelpTemplate: helpTemplate,
+	Name:               "feed",
+	Usage:              "(Advanced) Create and update Swarm Feeds",
+	ArgsUsage:          "",
+	Description:        "Works with Swarm Feeds",
+	Subcommands: []cli.Command{
+		{
+			Action:             feedCreateManifest,
+			CustomHelpTemplate: helpTemplate,
+			Name:               "create",
+			Usage:              "creates and publishes a new feed manifest",
+			Description: `creates and publishes a new feed manifest pointing to a specified user's updates about a particular topic.
+					The feed topic can be built in the following ways:
+					* use --topic to set the topic to an arbitrary binary hex string.
+					* use --name to set the topic to a human-readable name.
+					    For example --name could be set to "profile-picture", meaning this feed allows to get this user's current profile picture.
+					* use both --topic and --name to create named subtopics. 
+						For example, --topic could be set to an Ethereum contract address and --name could be set to "comments", meaning
+						this feed tracks a discussion about that contract.
+					The --user flag allows to have this manifest refer to a user other than yourself. If not specified,
+					it will then default to your local account (--bzzaccount)`,
+			Flags: []cli.Flag{SwarmFeedNameFlag, SwarmFeedTopicFlag, SwarmFeedUserFlag},
+		},
+		{
+			Action:             feedUpdate,
+			CustomHelpTemplate: helpTemplate,
+			Name:               "update",
+			Usage:              "updates the content of an existing Swarm Feed",
+			ArgsUsage:          "<0x Hex data>",
+			Description: `publishes a new update on the specified topic
+					The feed topic can be built in the following ways:
+					* use --topic to set the topic to an arbitrary binary hex string.
+					* use --name to set the topic to a human-readable name.
+					    For example --name could be set to "profile-picture", meaning this feed allows to get this user's current profile picture.
+					* use both --topic and --name to create named subtopics. 
+						For example, --topic could be set to an Ethereum contract address and --name could be set to "comments", meaning
+						this feed tracks a discussion about that contract.
+					
+					If you have a manifest, you can specify it with --manifest to refer to the feed,
+					instead of using --topic / --name
+					`,
+			Flags: []cli.Flag{SwarmFeedManifestFlag, SwarmFeedNameFlag, SwarmFeedTopicFlag},
+		},
+		{
+			Action:             feedInfo,
+			CustomHelpTemplate: helpTemplate,
+			Name:               "info",
+			Usage:              "obtains information about an existing Swarm feed",
+			Description: `obtains information about an existing Swarm feed
+					The topic can be specified directly with the --topic flag as an hex string
+					If no topic is specified, the default topic (zero) will be used
+					The --name flag can be used to specify subtopics with a specific name.
+					The --user flag allows to refer to a user other than yourself. If not specified,
+					it will then default to your local account (--bzzaccount)
+					If you have a manifest, you can specify it with --manifest instead of --topic / --name / ---user
+					to refer to the feed`,
+			Flags: []cli.Flag{SwarmFeedManifestFlag, SwarmFeedNameFlag, SwarmFeedTopicFlag, SwarmFeedUserFlag},
+		},
+	},
+}
+
+func NewGenericSigner(ctx *cli.Context) feed.Signer {
+	return feed.NewGenericSigner(getPrivKey(ctx))
+}
+
+func getTopic(ctx *cli.Context) (topic feed.Topic) {
+	var name = ctx.String(SwarmFeedNameFlag.Name)
+	var relatedTopic = ctx.String(SwarmFeedTopicFlag.Name)
+	var relatedTopicBytes []byte
+	var err error
+
+	if relatedTopic != "" {
+		relatedTopicBytes, err = hexutil.Decode(relatedTopic)
+		if err != nil {
+			utils.Fatalf("Error parsing topic: %s", err)
+		}
+	}
+
+	topic, err = feed.NewTopic(name, relatedTopicBytes)
+	if err != nil {
+		utils.Fatalf("Error parsing topic: %s", err)
+	}
+	return topic
+}
+
+// swarm feed create  [--name ] [--data <0x Hexdata> [--multihash=false]]
+// swarm feed update  <0x Hexdata> [--multihash=false]
+// swarm feed info 
+
+func feedCreateManifest(ctx *cli.Context) {
+	var (
+		bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
+		client = swarm.NewClient(bzzapi)
+	)
+
+	newFeedUpdateRequest := feed.NewFirstRequest(getTopic(ctx))
+	newFeedUpdateRequest.Feed.User = feedGetUser(ctx)
+
+	manifestAddress, err := client.CreateFeedWithManifest(newFeedUpdateRequest)
+	if err != nil {
+		utils.Fatalf("Error creating feed manifest: %s", err.Error())
+		return
+	}
+	fmt.Println(manifestAddress) // output manifest address to the user in a single line (useful for other commands to pick up)
+
+}
+
+func feedUpdate(ctx *cli.Context) {
+	args := ctx.Args()
+
+	var (
+		bzzapi                  = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
+		client                  = swarm.NewClient(bzzapi)
+		manifestAddressOrDomain = ctx.String(SwarmFeedManifestFlag.Name)
+	)
+
+	if len(args) < 1 {
+		fmt.Println("Incorrect number of arguments")
+		cli.ShowCommandHelpAndExit(ctx, "update", 1)
+		return
+	}
+
+	signer := NewGenericSigner(ctx)
+
+	data, err := hexutil.Decode(args[0])
+	if err != nil {
+		utils.Fatalf("Error parsing data: %s", err.Error())
+		return
+	}
+
+	var updateRequest *feed.Request
+	var query *feed.Query
+
+	if manifestAddressOrDomain == "" {
+		query = new(feed.Query)
+		query.User = signer.Address()
+		query.Topic = getTopic(ctx)
+	}
+
+	// Retrieve a feed update request
+	updateRequest, err = client.GetFeedRequest(query, manifestAddressOrDomain)
+	if err != nil {
+		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)
+
+	// sign update
+	if err = updateRequest.Sign(signer); err != nil {
+		utils.Fatalf("Error signing feed update: %s", err.Error())
+	}
+
+	// post update
+	err = client.UpdateFeed(updateRequest)
+	if err != nil {
+		utils.Fatalf("Error updating feed: %s", err.Error())
+		return
+	}
+}
+
+func feedInfo(ctx *cli.Context) {
+	var (
+		bzzapi                  = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
+		client                  = swarm.NewClient(bzzapi)
+		manifestAddressOrDomain = ctx.String(SwarmFeedManifestFlag.Name)
+	)
+
+	var query *feed.Query
+	if manifestAddressOrDomain == "" {
+		query = new(feed.Query)
+		query.Topic = getTopic(ctx)
+		query.User = feedGetUser(ctx)
+	}
+
+	metadata, err := client.GetFeedRequest(query, manifestAddressOrDomain)
+	if err != nil {
+		utils.Fatalf("Error retrieving feed metadata: %s", err.Error())
+		return
+	}
+	encodedMetadata, err := metadata.MarshalJSON()
+	if err != nil {
+		utils.Fatalf("Error encoding metadata to JSON for display:%s", err)
+	}
+	fmt.Println(string(encodedMetadata))
+}
+
+func feedGetUser(ctx *cli.Context) common.Address {
+	var user = ctx.String(SwarmFeedUserFlag.Name)
+	if user != "" {
+		return common.HexToAddress(user)
+	}
+	pk := getPrivKey(ctx)
+	if pk == nil {
+		utils.Fatalf("Cannot read private key. Must specify --user or --bzzaccount")
+	}
+	return crypto.PubkeyToAddress(pk.PublicKey)
+
+}
diff --git a/cmd/swarm/feeds_test.go b/cmd/swarm/feeds_test.go
new file mode 100644
index 0000000000..4c40f62a82
--- /dev/null
+++ b/cmd/swarm/feeds_test.go
@@ -0,0 +1,196 @@
+// Copyright 2017 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"
+	"encoding/json"
+	"io/ioutil"
+	"os"
+	"testing"
+
+	"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/api"
+	swarm "github.com/ethereum/go-ethereum/swarm/api/client"
+	swarmhttp "github.com/ethereum/go-ethereum/swarm/api/http"
+	"github.com/ethereum/go-ethereum/swarm/storage/feed"
+	"github.com/ethereum/go-ethereum/swarm/storage/feed/lookup"
+	"github.com/ethereum/go-ethereum/swarm/testutil"
+)
+
+func TestCLIFeedUpdate(t *testing.T) {
+	srv := swarmhttp.NewTestSwarmServer(t, func(api *api.API) swarmhttp.TestServer {
+		return swarmhttp.NewServer(api, "")
+	}, nil)
+	log.Info("starting a test swarm server")
+	defer srv.Close()
+
+	// create a private key file for signing
+	privkeyHex := "0000000000000000000000000000000000000000000000000000000000001979"
+	privKey, _ := crypto.HexToECDSA(privkeyHex)
+	address := crypto.PubkeyToAddress(privKey.PublicKey)
+
+	pkFileName := testutil.TempFileWithContent(t, privkeyHex)
+	defer os.Remove(pkFileName)
+
+	// compose a topic. We'll be doing quotes about Miguel de Cervantes
+	var topic feed.Topic
+	subject := []byte("Miguel de Cervantes")
+	copy(topic[:], subject[:])
+	name := "quotes"
+
+	// prepare some data for the update
+	data := []byte("En boca cerrada no entran moscas")
+	hexData := hexutil.Encode(data)
+
+	flags := []string{
+		"--bzzapi", srv.URL,
+		"--bzzaccount", pkFileName,
+		"feed", "update",
+		"--topic", topic.Hex(),
+		"--name", name,
+		hexData}
+
+	// create an update and expect an exit without errors
+	log.Info("updating a feed with 'swarm feed update'")
+	cmd := runSwarm(t, flags...)
+	cmd.ExpectExit()
+
+	// now try to get the update using the client
+	client := swarm.NewClient(srv.URL)
+
+	// build the same topic as before, this time
+	// we use NewTopic to create a topic automatically.
+	topic, err := feed.NewTopic(name, subject)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Feed configures whose updates we will be looking up.
+	fd := feed.Feed{
+		Topic: topic,
+		User:  address,
+	}
+
+	// Build a query to get the latest update
+	query := feed.NewQueryLatest(&fd, lookup.NoClue)
+
+	// retrieve content!
+	reader, err := client.QueryFeed(query, "")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	retrieved, err := ioutil.ReadAll(reader)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// check we retrieved the sent information
+	if !bytes.Equal(data, retrieved) {
+		t.Fatalf("Received %s, expected %s", retrieved, data)
+	}
+
+	// Now retrieve info for the next update
+	flags = []string{
+		"--bzzapi", srv.URL,
+		"feed", "info",
+		"--topic", topic.Hex(),
+		"--user", address.Hex(),
+	}
+
+	log.Info("getting feed info with 'swarm feed info'")
+	cmd = runSwarm(t, flags...)
+	_, matches := cmd.ExpectRegexp(`.*`) // regex hack to extract stdout
+	cmd.ExpectExit()
+
+	// verify we can deserialize the result as a valid JSON
+	var request feed.Request
+	err = json.Unmarshal([]byte(matches[0]), &request)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// make sure the retrieved feed is the same
+	if request.Feed != fd {
+		t.Fatalf("Expected feed to be: %s, got %s", fd, request.Feed)
+	}
+
+	// test publishing a manifest
+	flags = []string{
+		"--bzzapi", srv.URL,
+		"--bzzaccount", pkFileName,
+		"feed", "create",
+		"--topic", topic.Hex(),
+	}
+
+	log.Info("Publishing manifest with 'swarm feed create'")
+	cmd = runSwarm(t, flags...)
+	_, matches = cmd.ExpectRegexp(`[a-f\d]{64}`)
+	cmd.ExpectExit()
+
+	manifestAddress := matches[0] // read the received feed manifest
+
+	// now attempt to lookup the latest update using a manifest instead
+	reader, err = client.QueryFeed(nil, manifestAddress)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	retrieved, err = ioutil.ReadAll(reader)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	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/cmd/swarm/flags.go b/cmd/swarm/flags.go
new file mode 100644
index 0000000000..5e1ada6329
--- /dev/null
+++ b/cmd/swarm/flags.go
@@ -0,0 +1,185 @@
+// 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 .
+
+// Command feed allows the user to create and update signed Swarm feeds
+package main
+
+import cli "gopkg.in/urfave/cli.v1"
+
+var (
+	ChequebookAddrFlag = cli.StringFlag{
+		Name:   "chequebook",
+		Usage:  "chequebook contract address",
+		EnvVar: SwarmEnvChequebookAddr,
+	}
+	SwarmAccountFlag = cli.StringFlag{
+		Name:   "bzzaccount",
+		Usage:  "Swarm account key file",
+		EnvVar: SwarmEnvAccount,
+	}
+	SwarmListenAddrFlag = cli.StringFlag{
+		Name:   "httpaddr",
+		Usage:  "Swarm HTTP API listening interface",
+		EnvVar: SwarmEnvListenAddr,
+	}
+	SwarmPortFlag = cli.StringFlag{
+		Name:   "bzzport",
+		Usage:  "Swarm local http api port",
+		EnvVar: SwarmEnvPort,
+	}
+	SwarmNetworkIdFlag = cli.IntFlag{
+		Name:   "bzznetworkid",
+		Usage:  "Network identifier (integer, default 3=swarm testnet)",
+		EnvVar: SwarmEnvNetworkID,
+	}
+	SwarmSwapEnabledFlag = cli.BoolFlag{
+		Name:   "swap",
+		Usage:  "Swarm SWAP enabled (default false)",
+		EnvVar: SwarmEnvSwapEnable,
+	}
+	SwarmSwapAPIFlag = cli.StringFlag{
+		Name:   "swap-api",
+		Usage:  "URL of the Ethereum API provider to use to settle SWAP payments",
+		EnvVar: SwarmEnvSwapAPI,
+	}
+	SwarmSyncDisabledFlag = cli.BoolTFlag{
+		Name:   "nosync",
+		Usage:  "Disable swarm syncing",
+		EnvVar: SwarmEnvSyncDisable,
+	}
+	SwarmSyncUpdateDelay = cli.DurationFlag{
+		Name:   "sync-update-delay",
+		Usage:  "Duration for sync subscriptions update after no new peers are added (default 15s)",
+		EnvVar: SwarmEnvSyncUpdateDelay,
+	}
+	SwarmMaxStreamPeerServersFlag = cli.IntFlag{
+		Name:   "max-stream-peer-servers",
+		Usage:  "Limit of Stream peer servers, 0 denotes unlimited",
+		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: SwarmEnvLightNodeEnable,
+	}
+	SwarmDeliverySkipCheckFlag = cli.BoolFlag{
+		Name:   "delivery-skip-check",
+		Usage:  "Skip chunk delivery check (default false)",
+		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: SwarmEnvENSAPI,
+	}
+	SwarmApiFlag = cli.StringFlag{
+		Name:  "bzzapi",
+		Usage: "Specifies the Swarm HTTP endpoint to connect to",
+		Value: "http://127.0.0.1:8500",
+	}
+	SwarmRecursiveFlag = cli.BoolFlag{
+		Name:  "recursive",
+		Usage: "Upload directories recursively",
+	}
+	SwarmWantManifestFlag = cli.BoolTFlag{
+		Name:  "manifest",
+		Usage: "Automatic manifest upload (default true)",
+	}
+	SwarmUploadDefaultPath = cli.StringFlag{
+		Name:  "defaultpath",
+		Usage: "path to file served for empty url path (none)",
+	}
+	SwarmAccessGrantKeyFlag = cli.StringFlag{
+		Name:  "grant-key",
+		Usage: "grants a given public key access to an ACT",
+	}
+	SwarmAccessGrantKeysFlag = cli.StringFlag{
+		Name:  "grant-keys",
+		Usage: "grants a given list of public keys in the following file (separated by line breaks) access to an ACT",
+	}
+	SwarmUpFromStdinFlag = cli.BoolFlag{
+		Name:  "stdin",
+		Usage: "reads data to be uploaded from stdin",
+	}
+	SwarmUploadMimeType = cli.StringFlag{
+		Name:  "mime",
+		Usage: "Manually specify MIME type",
+	}
+	SwarmEncryptedFlag = cli.BoolFlag{
+		Name:  "encrypt",
+		Usage: "use encrypted upload",
+	}
+	SwarmAccessPasswordFlag = cli.StringFlag{
+		Name:   "password",
+		Usage:  "Password",
+		EnvVar: SwarmAccessPassword,
+	}
+	SwarmDryRunFlag = cli.BoolFlag{
+		Name:  "dry-run",
+		Usage: "dry-run",
+	}
+	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: SwarmEnvCORS,
+	}
+	SwarmStorePath = cli.StringFlag{
+		Name:   "store.path",
+		Usage:  "Path to leveldb chunk DB (default <$GETH_ENV_DIR>/swarm/bzz-<$BZZ_KEY>/chunks)",
+		EnvVar: SwarmEnvStorePath,
+	}
+	SwarmStoreCapacity = cli.Uint64Flag{
+		Name:   "store.size",
+		Usage:  "Number of chunks (5M is roughly 20-25GB) (default 5000000)",
+		EnvVar: SwarmEnvStoreCapacity,
+	}
+	SwarmStoreCacheCapacity = cli.UintFlag{
+		Name:   "store.cache.size",
+		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",
+	}
+	SwarmFeedTopicFlag = cli.StringFlag{
+		Name:  "topic",
+		Usage: "User-defined topic this feed is tracking, hex encoded. Limited to 64 hexadecimal characters",
+	}
+	SwarmFeedManifestFlag = cli.StringFlag{
+		Name:  "manifest",
+		Usage: "Refers to the feed through a manifest",
+	}
+	SwarmFeedUserFlag = cli.StringFlag{
+		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/cmd/swarm/fs.go b/cmd/swarm/fs.go
new file mode 100644
index 0000000000..7f156523ba
--- /dev/null
+++ b/cmd/swarm/fs.go
@@ -0,0 +1,162 @@
+// 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"
+	"fmt"
+	"path/filepath"
+	"strings"
+	"time"
+
+	"github.com/ethereum/go-ethereum/cmd/utils"
+	"github.com/ethereum/go-ethereum/log"
+	"github.com/ethereum/go-ethereum/rpc"
+	"github.com/ethereum/go-ethereum/swarm/fuse"
+	"gopkg.in/urfave/cli.v1"
+)
+
+var fsCommand = cli.Command{
+	Name:               "fs",
+	CustomHelpTemplate: helpTemplate,
+	Usage:              "perform FUSE operations",
+	ArgsUsage:          "fs COMMAND",
+	Description:        "Performs FUSE operations by mounting/unmounting/listing mount points. This assumes you already have a Swarm node running locally. For all operation you must reference the correct path to bzzd.ipc in order to communicate with the node",
+	Subcommands: []cli.Command{
+		{
+			Action:             mount,
+			CustomHelpTemplate: helpTemplate,
+			Name:               "mount",
+			Usage:              "mount a swarm hash to a mount point",
+			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",
+			Usage:              "unmount a swarmfs mount",
+			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",
+			Usage:              "list swarmfs mounts",
+			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",
+		},
+	},
+}
+
+func mount(cliContext *cli.Context) {
+	args := cliContext.Args()
+	if len(args) < 2 {
+		utils.Fatalf("Usage: swarm fs mount  ")
+	}
+
+	client, err := dialRPC(cliContext)
+	if err != nil {
+		utils.Fatalf("had an error dailing to RPC endpoint: %v", err)
+	}
+	defer client.Close()
+
+	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
+	defer cancel()
+
+	mf := &fuse.MountInfo{}
+	mountPoint, err := filepath.Abs(filepath.Clean(args[1]))
+	if err != nil {
+		utils.Fatalf("error expanding path for mount point: %v", err)
+	}
+	err = client.CallContext(ctx, mf, "swarmfs_mount", args[0], mountPoint)
+	if err != nil {
+		utils.Fatalf("had an error calling the RPC endpoint while mounting: %v", err)
+	}
+}
+
+func unmount(cliContext *cli.Context) {
+	args := cliContext.Args()
+
+	if len(args) < 1 {
+		utils.Fatalf("Usage: swarm fs unmount ")
+	}
+	client, err := dialRPC(cliContext)
+	if err != nil {
+		utils.Fatalf("had an error dailing to RPC endpoint: %v", err)
+	}
+	defer client.Close()
+
+	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
+	defer cancel()
+
+	mf := fuse.MountInfo{}
+	err = client.CallContext(ctx, &mf, "swarmfs_unmount", args[0])
+	if err != nil {
+		utils.Fatalf("encountered an error calling the RPC endpoint while unmounting: %v", err)
+	}
+	fmt.Printf("%s\n", mf.LatestManifest) //print the latest manifest hash for user reference
+}
+
+func listMounts(cliContext *cli.Context) {
+	client, err := dialRPC(cliContext)
+	if err != nil {
+		utils.Fatalf("had an error dailing to RPC endpoint: %v", err)
+	}
+	defer client.Close()
+
+	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
+	defer cancel()
+
+	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)
+	}
+	if len(mf) == 0 {
+		fmt.Print("Could not found any swarmfs mounts. Please make sure you've specified the correct RPC endpoint\n")
+	} else {
+		fmt.Printf("Found %d swarmfs mount(s):\n", len(mf))
+		for i, mountInfo := range mf {
+			fmt.Printf("%d:\n", i)
+			fmt.Printf("\tMount point: %s\n", mountInfo.MountPoint)
+			fmt.Printf("\tLatest Manifest: %s\n", mountInfo.LatestManifest)
+			fmt.Printf("\tStart Manifest: %s\n", mountInfo.StartManifest)
+		}
+	}
+}
+
+func dialRPC(ctx *cli.Context) (*rpc.Client, error) {
+	endpoint := getIPCEndpoint(ctx)
+	log.Info("IPC endpoint", "path", endpoint)
+	return rpc.Dial(endpoint)
+}
+
+func getIPCEndpoint(ctx *cli.Context) string {
+	cfg := defaultNodeConfig
+	utils.SetNodeConfig(ctx, &cfg)
+
+	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 endpoint
+}
diff --git a/cmd/swarm/fs_test.go b/cmd/swarm/fs_test.go
new file mode 100644
index 0000000000..5f58d6c0d8
--- /dev/null
+++ b/cmd/swarm/fs_test.go
@@ -0,0 +1,260 @@
+// 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 .
+
+// +build linux freebsd
+
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"strings"
+	"testing"
+	"time"
+
+	"github.com/ethereum/go-ethereum/cmd/utils"
+	"github.com/ethereum/go-ethereum/log"
+)
+
+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
+// and without any log messages in the log:
+// /Library/Filesystems/osxfuse.fs/Contents/Resources/load_osxfuse.
+// This is the reason for this file not being built on darwin architecture.
+func TestCLISwarmFs(t *testing.T) {
+	cluster := newTestCluster(t, 3)
+	defer cluster.Shutdown()
+
+	// create a tmp dir
+	mountPoint, err := ioutil.TempDir("", "swarm-test")
+	log.Debug("swarmfs cli test", "1st mount", mountPoint)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(mountPoint)
+
+	handlingNode := cluster.Nodes[0]
+	mhash := doUploadEmptyDir(t, handlingNode)
+	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",
+		mhash,
+		mountPoint,
+	}...)
+	mount.ExpectExit()
+
+	filesToAssert := []*testFile{}
+
+	dirPath, err := createDirInDir(mountPoint, "testSubDir")
+	if err != nil {
+		t.Fatal(err)
+	}
+	dirPath2, err := createDirInDir(dirPath, "AnotherTestSubDir")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	dummyContent := "somerandomtestcontentthatshouldbeasserted"
+	dirs := []string{
+		mountPoint,
+		dirPath,
+		dirPath2,
+	}
+	files := []string{"f1.tmp", "f2.tmp"}
+	for _, d := range dirs {
+		for _, entry := range files {
+			tFile, err := createTestFileInPath(d, entry, dummyContent)
+			if err != nil {
+				t.Fatal(err)
+			}
+			filesToAssert = append(filesToAssert, tFile)
+		}
+	}
+	if len(filesToAssert) != len(dirs)*len(files) {
+		t.Fatalf("should have %d files to assert now, got %d", len(dirs)*len(files), len(filesToAssert))
+	}
+	hashRegexp := `[a-f\d]{64}`
+	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",
+		mountPoint,
+	}...)
+	_, matches := unmount.ExpectRegexp(hashRegexp)
+	unmount.ExpectExit()
+
+	hash := matches[0]
+	if hash == mhash {
+		t.Fatal("this should not be equal")
+	}
+	log.Debug("swarmfs cli test: asserting no files in mount point")
+
+	//check that there's nothing in the mount folder
+	filesInDir, err := ioutil.ReadDir(mountPoint)
+	if err != nil {
+		t.Fatalf("had an error reading the directory: %v", err)
+	}
+
+	if len(filesInDir) != 0 {
+		t.Fatal("there shouldn't be anything here")
+	}
+
+	secondMountPoint, err := ioutil.TempDir("", "swarm-test")
+	log.Debug("swarmfs cli test", "2nd mount point at", secondMountPoint)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(secondMountPoint)
+
+	log.Debug("swarmfs cli test: remounting at second mount point", "ipc path", filepath.Join(handlingNode.Dir, handlingNode.IpcPath))
+
+	//remount, check files
+	newMount := runSwarm(t, []string{
+		fmt.Sprintf("--%s", utils.IPCPathFlag.Name), filepath.Join(handlingNode.Dir, handlingNode.IpcPath),
+		"fs",
+		"mount",
+		hash, // the latest hash
+		secondMountPoint,
+	}...)
+
+	newMount.ExpectExit()
+	time.Sleep(1 * time.Second)
+
+	filesInDir, err = ioutil.ReadDir(secondMountPoint)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if len(filesInDir) == 0 {
+		t.Fatal("there should be something here")
+	}
+
+	log.Debug("swarmfs cli test: traversing file tree to see it matches previous mount")
+
+	for _, file := range filesToAssert {
+		file.filePath = strings.Replace(file.filePath, mountPoint, secondMountPoint, -1)
+		fileBytes, err := ioutil.ReadFile(file.filePath)
+
+		if err != nil {
+			t.Fatal(err)
+		}
+		if !bytes.Equal(fileBytes, bytes.NewBufferString(file.content).Bytes()) {
+			t.Fatal("this should be equal")
+		}
+	}
+
+	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",
+		secondMountPoint,
+	}...)
+
+	_, matches = unmountSec.ExpectRegexp(hashRegexp)
+	unmountSec.ExpectExit()
+
+	if matches[0] != hash {
+		t.Fatal("these should be equal - no changes made")
+	}
+}
+
+func doUploadEmptyDir(t *testing.T, node *testNode) string {
+	// create a tmp dir
+	tmpDir, err := ioutil.TempDir("", "swarm-test")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(tmpDir)
+
+	hashRegexp := `[a-f\d]{64}`
+
+	flags := []string{
+		"--bzzapi", node.URL,
+		"--recursive",
+		"up",
+		tmpDir}
+
+	log.Info("swarmfs cli test: uploading dir with 'swarm up'")
+	up := runSwarm(t, flags...)
+	_, matches := up.ExpectRegexp(hashRegexp)
+	up.ExpectExit()
+	hash := matches[0]
+	log.Info("swarmfs cli test: dir uploaded", "hash", hash)
+	return hash
+}
+
+func createDirInDir(createInDir string, dirToCreate string) (string, error) {
+	fullpath := filepath.Join(createInDir, dirToCreate)
+	err := os.MkdirAll(fullpath, 0777)
+	if err != nil {
+		return "", err
+	}
+	return fullpath, nil
+}
+
+func createTestFileInPath(dir, filename, content string) (*testFile, error) {
+	tFile := &testFile{}
+	filePath := filepath.Join(dir, filename)
+	if file, err := os.Create(filePath); err == nil {
+		tFile.content = content
+		tFile.filePath = filePath
+
+		_, err = io.WriteString(file, content)
+		if err != nil {
+			return nil, err
+		}
+		file.Close()
+	}
+
+	return tFile, nil
+}
diff --git a/cmd/swarm/global-store/explorer.go b/cmd/swarm/global-store/explorer.go
new file mode 100644
index 0000000000..634ff1ebb6
--- /dev/null
+++ b/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/cmd/swarm/global-store/explorer_test.go b/cmd/swarm/global-store/explorer_test.go
new file mode 100644
index 0000000000..2e4928c8fc
--- /dev/null
+++ b/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/cmd/swarm/global-store/global_store.go b/cmd/swarm/global-store/global_store.go
new file mode 100644
index 0000000000..f93b464dbc
--- /dev/null
+++ b/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/cmd/swarm/global-store/global_store_test.go b/cmd/swarm/global-store/global_store_test.go
new file mode 100644
index 0000000000..c437c9d453
--- /dev/null
+++ b/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/cmd/swarm/global-store/main.go b/cmd/swarm/global-store/main.go
new file mode 100644
index 0000000000..52fafc8f6a
--- /dev/null
+++ b/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/cmd/swarm/global-store/run_test.go b/cmd/swarm/global-store/run_test.go
new file mode 100644
index 0000000000..d7ef626e55
--- /dev/null
+++ b/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/cmd/swarm/hash.go b/cmd/swarm/hash.go
index 792e8d0d7a..471feb53d6 100644
--- a/cmd/swarm/hash.go
+++ b/cmd/swarm/hash.go
@@ -18,6 +18,7 @@
 package main
 
 import (
+	"context"
 	"fmt"
 	"os"
 
@@ -26,6 +27,15 @@ import (
 	"gopkg.in/urfave/cli.v1"
 )
 
+var hashCommand = cli.Command{
+	Action:             hash,
+	CustomHelpTemplate: helpTemplate,
+	Name:               "hash",
+	Usage:              "print the swarm hash of a file or directory",
+	ArgsUsage:          "",
+	Description:        "Prints the swarm hash of file or directory",
+}
+
 func hash(ctx *cli.Context) {
 	args := ctx.Args()
 	if len(args) < 1 {
@@ -38,11 +48,11 @@ func hash(ctx *cli.Context) {
 	defer f.Close()
 
 	stat, _ := f.Stat()
-	chunker := storage.NewTreeChunker(storage.NewChunkerParams())
-	key, err := chunker.Split(f, stat.Size(), nil, nil, nil)
+	fileStore := storage.NewFileStore(&storage.FakeChunkStore{}, storage.NewFileStoreParams())
+	addr, _, err := fileStore.Store(context.TODO(), f, stat.Size(), false)
 	if err != nil {
 		utils.Fatalf("%v\n", err)
 	} else {
-		fmt.Printf("%v\n", key)
+		fmt.Printf("%v\n", addr)
 	}
 }
diff --git a/cmd/swarm/list.go b/cmd/swarm/list.go
index 57b5517c6e..5d35154a57 100644
--- a/cmd/swarm/list.go
+++ b/cmd/swarm/list.go
@@ -27,6 +27,15 @@ import (
 	"gopkg.in/urfave/cli.v1"
 )
 
+var listCommand = cli.Command{
+	Action:             list,
+	CustomHelpTemplate: helpTemplate,
+	Name:               "ls",
+	Usage:              "list files and directories contained in a manifest",
+	ArgsUsage:          " []",
+	Description:        "Lists files and directories contained in a manifest",
+}
+
 func list(ctx *cli.Context) {
 	args := ctx.Args()
 
@@ -44,7 +53,7 @@ func list(ctx *cli.Context) {
 
 	bzzapi := strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
 	client := swarm.NewClient(bzzapi)
-	list, err := client.List(manifest, prefix)
+	list, err := client.List(manifest, prefix, "")
 	if err != nil {
 		utils.Fatalf("Failed to generate file and directory list: %s", err)
 	}
diff --git a/cmd/swarm/main.go b/cmd/swarm/main.go
index 77315a4265..06d5b0bb2b 100644
--- a/cmd/swarm/main.go
+++ b/cmd/swarm/main.go
@@ -17,11 +17,10 @@
 package main
 
 import (
-	"context"
 	"crypto/ecdsa"
+	"encoding/hex"
 	"fmt"
 	"io/ioutil"
-	"math/big"
 	"os"
 	"os/signal"
 	"runtime"
@@ -29,299 +28,131 @@ import (
 	"strconv"
 	"strings"
 	"syscall"
-	"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/console"
-	"github.com/ethereum/go-ethereum/contracts/ens"
 	"github.com/ethereum/go-ethereum/crypto"
-	"github.com/ethereum/go-ethereum/ethclient"
 	"github.com/ethereum/go-ethereum/internal/debug"
 	"github.com/ethereum/go-ethereum/log"
 	"github.com/ethereum/go-ethereum/node"
-	"github.com/ethereum/go-ethereum/p2p"
-	"github.com/ethereum/go-ethereum/p2p/discover"
-	"github.com/ethereum/go-ethereum/params"
+	"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"
+const helpTemplate = `NAME:
+{{.HelpName}} - {{.Usage}}
 
-var (
-	gitCommit        string // Git SHA1 commit hash of the release (set via linker flags)
-	testbetBootNodes = []string{
-		"enode://ec8ae764f7cb0417bdfb009b9d0f18ab3818a3a4e8e7c67dd5f18971a93510a2e6f43cd0b69a27e439a9629457ea804104f37c85e41eed057d3faabbf7744cdf@13.74.157.139:30429",
-		"enode://c2e1fceb3bf3be19dff71eec6cccf19f2dbf7567ee017d130240c670be8594bc9163353ca55dd8df7a4f161dd94b36d0615c17418b5a3cdcbb4e9d99dfa4de37@13.74.157.139:30430",
-		"enode://fe29b82319b734ce1ec68b84657d57145fee237387e63273989d354486731e59f78858e452ef800a020559da22dcca759536e6aa5517c53930d29ce0b1029286@13.74.157.139:30431",
-		"enode://1d7187e7bde45cf0bee489ce9852dd6d1a0d9aa67a33a6b8e6db8a4fbc6fcfa6f0f1a5419343671521b863b187d1c73bad3603bae66421d157ffef357669ddb8@13.74.157.139:30432",
-		"enode://0e4cba800f7b1ee73673afa6a4acead4018f0149d2e3216be3f133318fd165b324cd71b81fbe1e80deac8dbf56e57a49db7be67f8b9bc81bd2b7ee496434fb5d@13.74.157.139:30433",
-	}
-)
+USAGE:
+{{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}}{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Category}}
 
-var (
-	ChequebookAddrFlag = cli.StringFlag{
-		Name:   "chequebook",
-		Usage:  "chequebook contract address",
-		EnvVar: SWARM_ENV_CHEQUEBOOK_ADDR,
-	}
-	SwarmAccountFlag = cli.StringFlag{
-		Name:   "bzzaccount",
-		Usage:  "Swarm account key file",
-		EnvVar: SWARM_ENV_ACCOUNT,
-	}
-	SwarmListenAddrFlag = cli.StringFlag{
-		Name:   "httpaddr",
-		Usage:  "Swarm HTTP API listening interface",
-		EnvVar: SWARM_ENV_LISTEN_ADDR,
-	}
-	SwarmPortFlag = cli.StringFlag{
-		Name:   "bzzport",
-		Usage:  "Swarm local http api port",
-		EnvVar: SWARM_ENV_PORT,
-	}
-	SwarmNetworkIdFlag = cli.IntFlag{
-		Name:   "bzznetworkid",
-		Usage:  "Network identifier (integer, default 3=swarm testnet)",
-		EnvVar: SWARM_ENV_NETWORK_ID,
-	}
-	SwarmConfigPathFlag = cli.StringFlag{
-		Name:  "bzzconfig",
-		Usage: "DEPRECATED: please use --config path/to/TOML-file",
-	}
-	SwarmSwapEnabledFlag = cli.BoolFlag{
-		Name:   "swap",
-		Usage:  "Swarm SWAP enabled (default false)",
-		EnvVar: SWARM_ENV_SWAP_ENABLE,
-	}
-	SwarmSwapAPIFlag = cli.StringFlag{
-		Name:   "swap-api",
-		Usage:  "URL of the Ethereum API provider to use to settle SWAP payments",
-		EnvVar: SWARM_ENV_SWAP_API,
-	}
-	SwarmSyncEnabledFlag = cli.BoolTFlag{
-		Name:   "sync",
-		Usage:  "Swarm Syncing enabled (default true)",
-		EnvVar: SWARM_ENV_SYNC_ENABLE,
-	}
-	EnsAPIFlag = cli.StringFlag{
-		Name:   "ens-api",
-		Usage:  "URL of the Ethereum API provider to use for ENS record lookups",
-		EnvVar: SWARM_ENV_ENS_API,
-	}
-	EnsAddrFlag = cli.StringFlag{
-		Name:   "ens-addr",
-		Usage:  "ENS contract address (default is detected as testnet or mainnet using --ens-api)",
-		EnvVar: SWARM_ENV_ENS_ADDR,
-	}
-	SwarmApiFlag = cli.StringFlag{
-		Name:  "bzzapi",
-		Usage: "Swarm HTTP endpoint",
-		Value: "http://127.0.0.1:8500",
-	}
-	SwarmRecursiveUploadFlag = cli.BoolFlag{
-		Name:  "recursive",
-		Usage: "Upload directories recursively",
-	}
-	SwarmWantManifestFlag = cli.BoolTFlag{
-		Name:  "manifest",
-		Usage: "Automatic manifest upload",
-	}
-	SwarmUploadDefaultPath = cli.StringFlag{
-		Name:  "defaultpath",
-		Usage: "path to file served for empty url path (none)",
-	}
-	SwarmUpFromStdinFlag = cli.BoolFlag{
-		Name:  "stdin",
-		Usage: "reads data to be uploaded from stdin",
-	}
-	SwarmUploadMimeType = cli.StringFlag{
-		Name:  "mime",
-		Usage: "force mime type",
-	}
-	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,
-	}
+CATEGORY:
+{{.Category}}{{end}}{{if .Description}}
 
-	// the following flags are deprecated and should be removed in the future
-	DeprecatedEthAPIFlag = cli.StringFlag{
-		Name:  "ethapi",
-		Usage: "DEPRECATED: please use --ens-api and --swap-api",
-	}
-)
+DESCRIPTION:
+{{.Description}}{{end}}{{if .VisibleFlags}}
+
+OPTIONS:
+{{range .VisibleFlags}}{{.}}
+{{end}}{{end}}
+`
+
+// 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
+var defaultSubcommandHelp = cli.Command{
+	Action:             func(ctx *cli.Context) { cli.ShowCommandHelpAndExit(ctx, "", 1) },
+	CustomHelpTemplate: helpTemplate,
+	Name:               "help",
+	Usage:              "shows this help",
+	Hidden:             true,
+}
+
 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 = params.VersionWithCommit(gitCommit)
+	defaultNodeConfig.Version = sv.VersionWithCommit(gitCommit)
 	defaultNodeConfig.P2P.ListenAddr = ":30399"
 	defaultNodeConfig.IPCPath = "bzzd.ipc"
 	// Set flag defaults for --help display.
 	utils.ListenPortFlag.Value = 30399
 }
 
-var app = utils.NewApp(gitCommit, "Ethereum Swarm")
+var app = utils.NewApp("", "Ethereum Swarm")
 
 // This init function creates the cli.App.
 func init() {
 	app.Action = bzzd
-	app.HideVersion = true // we have a command to print the version
+	app.Version = sv.ArchiveVersion(gitCommit)
 	app.Copyright = "Copyright 2013-2016 The go-ethereum Authors"
 	app.Commands = []cli.Command{
 		{
-			Action:    version,
-			Name:      "version",
-			Usage:     "Print version numbers",
-			ArgsUsage: " ",
-			Description: `
-The output of this command is supposed to be machine-readable.
-`,
+			Action:             version,
+			CustomHelpTemplate: helpTemplate,
+			Name:               "version",
+			Usage:              "Print version numbers",
+			Description:        "The output of this command is supposed to be machine-readable",
 		},
 		{
-			Action:    upload,
-			Name:      "up",
-			Usage:     "upload a file or directory to swarm using the HTTP API",
-			ArgsUsage: " ",
-			Description: `
-"upload a file or directory to swarm using the HTTP API and prints the root hash",
-`,
-		},
-		{
-			Action:    list,
-			Name:      "ls",
-			Usage:     "list files and directories contained in a manifest",
-			ArgsUsage: "  []",
-			Description: `
-Lists files and directories contained in a manifest.
-`,
-		},
-		{
-			Action:    hash,
-			Name:      "hash",
-			Usage:     "print the swarm hash of a file or directory",
-			ArgsUsage: " ",
-			Description: `
-Prints the swarm hash of file or directory.
-`,
-		},
-		{
-			Name:      "manifest",
-			Usage:     "update a MANIFEST",
-			ArgsUsage: "manifest COMMAND",
-			Description: `
-Updates a MANIFEST by adding/removing/updating the hash of a path.
-`,
-			Subcommands: []cli.Command{
-				{
-					Action:    add,
-					Name:      "add",
-					Usage:     "add a new path to the manifest",
-					ArgsUsage: "   []",
-					Description: `
-Adds a new path to the manifest
-`,
-				},
-				{
-					Action:    update,
-					Name:      "update",
-					Usage:     "update the hash for an already existing path in the manifest",
-					ArgsUsage: "   []",
-					Description: `
-Update the hash for an already existing path in the manifest
-`,
-				},
-				{
-					Action:    remove,
-					Name:      "remove",
-					Usage:     "removes a path from the manifest",
-					ArgsUsage: " ",
-					Description: `
-Removes a path from the manifest
-`,
-				},
-			},
-		},
-		{
-			Name:      "db",
-			Usage:     "manage the local chunk database",
-			ArgsUsage: "db COMMAND",
-			Description: `
-Manage the local chunk database.
-`,
-			Subcommands: []cli.Command{
-				{
-					Action:    dbExport,
-					Name:      "export",
-					Usage:     "export a local chunk database as a tar archive (use - to send to stdout)",
-					ArgsUsage: " ",
-					Description: `
-Export a local chunk database as a tar archive (use - to send to stdout).
-
-    swarm db export ~/.ethereum/swarm/bzz-KEY/chunks chunks.tar
-
-The export may be quite large, consider piping the output through the Unix
-pv(1) tool to get a progress bar:
-
-    swarm db export ~/.ethereum/swarm/bzz-KEY/chunks - | pv > chunks.tar
-`,
-				},
-				{
-					Action:    dbImport,
-					Name:      "import",
-					Usage:     "import chunks from a tar archive into a local chunk database (use - to read from stdin)",
-					ArgsUsage: " ",
-					Description: `
-Import chunks from a tar archive into a local chunk database (use - to read from stdin).
-
-    swarm db import ~/.ethereum/swarm/bzz-KEY/chunks chunks.tar
-
-The import may be quite large, consider piping the input through the Unix
-pv(1) tool to get a progress bar:
-
-    pv chunks.tar | swarm db import ~/.ethereum/swarm/bzz-KEY/chunks -
-`,
-				},
-				{
-					Action:    dbClean,
-					Name:      "clean",
-					Usage:     "remove corrupt entries from a local chunk database",
-					ArgsUsage: "",
-					Description: `
-Remove corrupt entries from a local chunk database.
-`,
-				},
-			},
-		},
-		{
-			Action: func(ctx *cli.Context) {
-				utils.Fatalf("ERROR: 'swarm cleandb' has been removed, please use 'swarm db clean'.")
-			},
-			Name:      "cleandb",
-			Usage:     "DEPRECATED: use 'swarm db clean'",
-			ArgsUsage: " ",
-			Description: `
-DEPRECATED: use 'swarm db clean'.
-`,
+			Action:             keys,
+			CustomHelpTemplate: helpTemplate,
+			Name:               "print-keys",
+			Flags:              []cli.Flag{SwarmCompressedFlag},
+			Usage:              "Print public key information",
+			Description:        "The output of this command is supposed to be machine-readable",
 		},
+		// See upload.go
+		upCommand,
+		// See access.go
+		accessCommand,
+		// See feeds.go
+		feedCommand,
+		// See list.go
+		listCommand,
+		// See hash.go
+		hashCommand,
+		// See download.go
+		downloadCommand,
+		// See manifest.go
+		manifestCommand,
+		// See fs.go
+		fsCommand,
+		// See db.go
+		dbCommand,
 		// See config.go
 		DumpConfigCommand,
+		// hashesCommand
+		hashesCommand,
 	}
+
+	// append a hidden help subcommand to all commands that have subcommands
+	// if a help command was already defined above, that one will take precedence.
+	addDefaultHelpSubcommands(app.Commands)
+
 	sort.Sort(cli.CommandsByName(app.Commands))
 
 	app.Flags = []cli.Flag{
@@ -330,7 +161,6 @@ DEPRECATED: use 'swarm db clean'.
 		utils.BootnodesFlag,
 		utils.KeyStoreDirFlag,
 		utils.ListenPortFlag,
-		utils.NoDiscoverFlag,
 		utils.DiscoveryV5Flag,
 		utils.NetrestrictFlag,
 		utils.NodeKeyFileFlag,
@@ -343,12 +173,14 @@ DEPRECATED: use 'swarm db clean'.
 		// bzzd-specific flags
 		CorsStringFlag,
 		EnsAPIFlag,
-		EnsAddrFlag,
 		SwarmTomlConfigPathFlag,
-		SwarmConfigPathFlag,
 		SwarmSwapEnabledFlag,
 		SwarmSwapAPIFlag,
-		SwarmSyncEnabledFlag,
+		SwarmSyncDisabledFlag,
+		SwarmSyncUpdateDelay,
+		SwarmMaxStreamPeerServersFlag,
+		SwarmLightNodeEnabled,
+		SwarmDeliverySkipCheckFlag,
 		SwarmListenAddrFlag,
 		SwarmPortFlag,
 		SwarmAccountFlag,
@@ -356,18 +188,38 @@ DEPRECATED: use 'swarm db clean'.
 		ChequebookAddrFlag,
 		// upload flags
 		SwarmApiFlag,
-		SwarmRecursiveUploadFlag,
+		SwarmRecursiveFlag,
 		SwarmWantManifestFlag,
 		SwarmUploadDefaultPath,
 		SwarmUpFromStdinFlag,
 		SwarmUploadMimeType,
-		//deprecated flags
-		DeprecatedEthAPIFlag,
+		// bootnode mode
+		SwarmBootnodeModeFlag,
+		// storage flags
+		SwarmStorePath,
+		SwarmStoreCapacity,
+		SwarmStoreCacheCapacity,
+		SwarmGlobalStoreAPIFlag,
 	}
+	rpcFlags := []cli.Flag{
+		utils.WSEnabledFlag,
+		utils.WSListenAddrFlag,
+		utils.WSPortFlag,
+		utils.WSApiFlag,
+		utils.WSAllowedOriginsFlag,
+	}
+	app.Flags = append(app.Flags, rpcFlags...)
 	app.Flags = append(app.Flags, debug.Flags...)
+	app.Flags = append(app.Flags, swarmmetrics.Flags...)
+	app.Flags = append(app.Flags, tracing.Flags...)
 	app.Before = func(ctx *cli.Context) error {
 		runtime.GOMAXPROCS(runtime.NumCPU())
-		return debug.Setup(ctx)
+		if err := debug.Setup(ctx, ""); err != nil {
+			return err
+		}
+		swarmmetrics.Setup(ctx)
+		tracing.Setup(ctx)
+		return nil
 	}
 	app.After = func(ctx *cli.Context) error {
 		debug.Exit()
@@ -382,46 +234,73 @@ func main() {
 	}
 }
 
+func keys(ctx *cli.Context) error {
+	privateKey := getPrivKey(ctx)
+	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("bzzkey=%s", bzzkey[2:]))
+		fmt.Println(fmt.Sprintf("publicKey=%s", pubkeyhex))
+	}
+	fmt.Println(fmt.Sprintf("publicKeyCompressed=%s", pubCompressed))
+
+	return nil
+}
+
 func version(ctx *cli.Context) error {
 	fmt.Println(strings.Title(clientIdentifier))
-	fmt.Println("Version:", params.Version)
+	fmt.Println("Version:", sv.VersionWithMeta)
 	if gitCommit != "" {
 		fmt.Println("Git Commit:", gitCommit)
 	}
-	fmt.Println("Network Id:", ctx.GlobalInt(utils.NetworkIdFlag.Name))
 	fmt.Println("Go Version:", runtime.Version())
 	fmt.Println("OS:", runtime.GOOS)
-	fmt.Printf("GOPATH=%s\n", os.Getenv("GOPATH"))
-	fmt.Printf("GOROOT=%s\n", runtime.GOROOT())
 	return nil
 }
 
 func bzzd(ctx *cli.Context) error {
 	//build a valid bzzapi.Config from all available sources:
 	//default config, file config, command line and env vars
+
 	bzzconfig, err := buildConfig(ctx)
 	if err != nil {
 		utils.Fatalf("unable to configure swarm: %v", err)
 	}
 
 	cfg := defaultNodeConfig
+
+	//pss operates on ws
+	cfg.WSModules = append(cfg.WSModules, "pss")
+
 	//geth only supports --datadir via command line
 	//in order to be consistent within swarm, if we pass --datadir via environment variable
 	//or via config file, we get the same directory for geth and swarm
 	if _, err := os.Stat(bzzconfig.Path); err == nil {
 		cfg.DataDir = bzzconfig.Path
 	}
+
+	//optionally set the bootnodes before configuring the node
+	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)
 	//register BZZ as node.Service in the ethereum node
-	registerBzzService(bzzconfig, ctx, stack)
+	registerBzzService(bzzconfig, stack)
 	//start the node
 	utils.StartNode(stack)
 
@@ -434,87 +313,34 @@ func bzzd(ctx *cli.Context) error {
 		stack.Stop()
 	}()
 
-	// Add bootnodes as initial peers.
-	if bzzconfig.BootNodes != "" {
-		bootnodes := strings.Split(bzzconfig.BootNodes, ",")
-		injectBootnodes(stack.Server(), bootnodes)
-	} else {
-		if bzzconfig.NetworkId == 3 {
-			injectBootnodes(stack.Server(), testbetBootNodes)
+	// 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
 }
 
-// detectEnsAddr determines the ENS contract address by getting both the
-// version and genesis hash using the client and matching them to either
-// mainnet or testnet addresses
-func detectEnsAddr(client *rpc.Client) (common.Address, error) {
-	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
-	defer cancel()
-
-	var version string
-	if err := client.CallContext(ctx, &version, "net_version"); err != nil {
-		return common.Address{}, err
-	}
-
-	block, err := ethclient.NewClient(client).BlockByNumber(ctx, big.NewInt(0))
-	if err != nil {
-		return common.Address{}, err
-	}
-
-	switch {
-
-	case version == "1" && block.Hash() == params.MainnetGenesisHash:
-		log.Info("using Mainnet ENS contract address", "addr", ens.MainNetAddress)
-		return ens.MainNetAddress, nil
-
-	case version == "3" && block.Hash() == params.TestnetGenesisHash:
-		log.Info("using Testnet ENS contract address", "addr", ens.TestNetAddress)
-		return ens.TestNetAddress, nil
-
-	default:
-		return common.Address{}, fmt.Errorf("unknown version and genesis hash: %s %s", version, block.Hash())
-	}
-}
-
-func registerBzzService(bzzconfig *bzzapi.Config, ctx *cli.Context, stack *node.Node) {
-
+func registerBzzService(bzzconfig *bzzapi.Config, stack *node.Node) {
 	//define the swarm service boot function
-	boot := func(ctx *node.ServiceContext) (node.Service, error) {
-		var swapClient *ethclient.Client
-		var err error
-		if bzzconfig.SwapApi != "" {
-			log.Info("connecting to SWAP API", "url", bzzconfig.SwapApi)
-			swapClient, err = ethclient.Dial(bzzconfig.SwapApi)
+	boot := func(_ *node.ServiceContext) (node.Service, error) {
+		var nodeStore *mock.NodeStore
+		if bzzconfig.GlobalStoreAPI != "" {
+			// connect to global store
+			client, err := rpc.Dial(bzzconfig.GlobalStoreAPI)
 			if err != nil {
-				return nil, fmt.Errorf("error connecting to SWAP API %s: %s", bzzconfig.SwapApi, err)
+				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))
 		}
-
-		var ensClient *ethclient.Client
-		if bzzconfig.EnsApi != "" {
-			log.Info("connecting to ENS API", "url", bzzconfig.EnsApi)
-			client, err := rpc.Dial(bzzconfig.EnsApi)
-			if err != nil {
-				return nil, fmt.Errorf("error connecting to ENS API %s: %s", bzzconfig.EnsApi, err)
-			}
-			ensClient = ethclient.NewClient(client)
-
-			//no ENS root address set yet
-			if bzzconfig.EnsRoot == (common.Address{}) {
-				ensAddr, err := detectEnsAddr(client)
-				if err == nil {
-					bzzconfig.EnsRoot = ensAddr
-				} else {
-					log.Warn(fmt.Sprintf("could not determine ENS contract address, using default %s", bzzconfig.EnsRoot), "err", err)
-				}
-			}
-		}
-
-		return swarm.NewSwarm(ctx, swapClient, ensClient, bzzconfig, bzzconfig.SwapEnabled, bzzconfig.SyncEnabled, bzzconfig.Cors)
+		return swarm.NewSwarm(bzzconfig, nodeStore)
 	}
 	//register within the ethereum node
 	if err := stack.Register(boot); err != nil {
@@ -525,7 +351,7 @@ func registerBzzService(bzzconfig *bzzapi.Config, ctx *cli.Context, stack *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 {
@@ -539,6 +365,28 @@ func getAccount(bzzaccount string, ctx *cli.Context, stack *node.Node) *ecdsa.Pr
 	return decryptStoreAccount(ks, bzzaccount, utils.MakePasswordList(ctx))
 }
 
+// getPrivKey returns the private key of the specified bzzaccount
+// Used only by client commands, such as `feed`
+func getPrivKey(ctx *cli.Context) *ecdsa.PrivateKey {
+	// booting up the swarm node just as we do in bzzd action
+	bzzconfig, err := buildConfig(ctx)
+	if err != nil {
+		utils.Fatalf("unable to configure swarm: %v", err)
+	}
+	cfg := defaultNodeConfig
+	if _, err := os.Stat(bzzconfig.Path); err == nil {
+		cfg.DataDir = bzzconfig.Path
+	}
+	utils.SetNodeConfig(ctx, &cfg)
+	stack, err := node.New(&cfg)
+	if err != nil {
+		utils.Fatalf("can't create node: %v", err)
+	}
+	defer stack.Close()
+
+	return getAccount(bzzconfig.BzzAccount, ctx, stack)
+}
+
 func decryptStoreAccount(ks *keystore.KeyStore, account string, passwords []string) *ecdsa.PrivateKey {
 	var a accounts.Account
 	var err error
@@ -593,13 +441,32 @@ func getPassPhrase(prompt string, i int, passwords []string) string {
 	return password
 }
 
-func injectBootnodes(srv *p2p.Server, nodes []string) {
-	for _, url := range nodes {
-		n, err := discover.ParseNode(url)
-		if err != nil {
-			log.Error("Invalid swarm bootnode", "err", err)
-			continue
+// addDefaultHelpSubcommand scans through defined CLI commands and adds
+// a basic help subcommand to each
+// if a help command is already defined, it will take precedence over the default.
+func addDefaultHelpSubcommands(commands []cli.Command) {
+	for i := range commands {
+		cmd := &commands[i]
+		if cmd.Subcommands != nil {
+			cmd.Subcommands = append(cmd.Subcommands, defaultSubcommandHelp)
+			addDefaultHelpSubcommands(cmd.Subcommands)
 		}
-		srv.AddPeer(n)
 	}
 }
+
+func setSwarmBootstrapNodes(ctx *cli.Context, cfg *node.Config) {
+	if ctx.GlobalIsSet(utils.BootnodesFlag.Name) || ctx.GlobalIsSet(utils.BootnodesV4Flag.Name) {
+		return
+	}
+
+	cfg.P2P.BootstrapNodes = []*enode.Node{}
+
+	for _, url := range SwarmBootnodes {
+		node, err := enode.ParseV4(url)
+		if err != nil {
+			log.Error("Bootstrap URL invalid", "enode", url, "err", err)
+		}
+		cfg.P2P.BootstrapNodes = append(cfg.P2P.BootstrapNodes, node)
+	}
+
+}
diff --git a/cmd/swarm/manifest.go b/cmd/swarm/manifest.go
index aa276e0f9b..312c72fa21 100644
--- a/cmd/swarm/manifest.go
+++ b/cmd/swarm/manifest.go
@@ -18,10 +18,8 @@
 package main
 
 import (
-	"encoding/json"
 	"fmt"
-	"mime"
-	"path/filepath"
+	"os"
 	"strings"
 
 	"github.com/ethereum/go-ethereum/cmd/utils"
@@ -30,127 +28,152 @@ import (
 	"gopkg.in/urfave/cli.v1"
 )
 
-const bzzManifestJSON = "application/bzz-manifest+json"
+var manifestCommand = cli.Command{
+	Name:               "manifest",
+	CustomHelpTemplate: helpTemplate,
+	Usage:              "perform operations on swarm manifests",
+	ArgsUsage:          "COMMAND",
+	Description:        "Updates a MANIFEST by adding/removing/updating the hash of a path.\nCOMMAND could be: add, update, remove",
+	Subcommands: []cli.Command{
+		{
+			Action:             manifestAdd,
+			CustomHelpTemplate: helpTemplate,
+			Name:               "add",
+			Usage:              "add a new path to the manifest",
+			ArgsUsage:          "  ",
+			Description:        "Adds a new path to the manifest",
+		},
+		{
+			Action:             manifestUpdate,
+			CustomHelpTemplate: helpTemplate,
+			Name:               "update",
+			Usage:              "update the hash for an already existing path in the manifest",
+			ArgsUsage:          "  ",
+			Description:        "Update the hash for an already existing path in the manifest",
+		},
+		{
+			Action:             manifestRemove,
+			CustomHelpTemplate: helpTemplate,
+			Name:               "remove",
+			Usage:              "removes a path from the manifest",
+			ArgsUsage:          " ",
+			Description:        "Removes a path from the manifest",
+		},
+	},
+}
 
-func add(ctx *cli.Context) {
+// manifestAdd adds a new entry to the manifest at the given path.
+// New entry hash, the last argument, must be the hash of a manifest
+// with only one entry, which meta-data will be added to the original manifest.
+// On success, this function will print new (updated) manifest's hash.
+func manifestAdd(ctx *cli.Context) {
 	args := ctx.Args()
-	if len(args) < 3 {
-		utils.Fatalf("Need atleast three arguments    []")
+	if len(args) != 3 {
+		utils.Fatalf("Need exactly three arguments   ")
 	}
 
 	var (
 		mhash = args[0]
 		path  = args[1]
 		hash  = args[2]
-
-		ctype        string
-		wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name)
-		mroot        api.Manifest
 	)
 
-	if len(args) > 3 {
-		ctype = args[3]
-	} else {
-		ctype = mime.TypeByExtension(filepath.Ext(path))
+	bzzapi := strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
+	client := swarm.NewClient(bzzapi)
+
+	m, _, err := client.DownloadManifest(hash)
+	if err != nil {
+		utils.Fatalf("Error downloading manifest to add: %v", err)
+	}
+	l := len(m.Entries)
+	if l == 0 {
+		utils.Fatalf("No entries in manifest %s", hash)
+	} else if l > 1 {
+		utils.Fatalf("Too many entries in manifest %s", hash)
 	}
 
-	newManifest := addEntryToManifest(ctx, mhash, path, hash, ctype)
+	newManifest := addEntryToManifest(client, mhash, path, m.Entries[0])
 	fmt.Println(newManifest)
-
-	if !wantManifest {
-		// Print the manifest. This is the only output to stdout.
-		mrootJSON, _ := json.MarshalIndent(mroot, "", "  ")
-		fmt.Println(string(mrootJSON))
-		return
-	}
 }
 
-func update(ctx *cli.Context) {
-
+// manifestUpdate replaces an existing entry of the manifest at the given path.
+// New entry hash, the last argument, must be the hash of a manifest
+// with only one entry, which meta-data will be added to the original manifest.
+// On success, this function will print hash of the updated manifest.
+func manifestUpdate(ctx *cli.Context) {
 	args := ctx.Args()
-	if len(args) < 3 {
-		utils.Fatalf("Need atleast three arguments   ")
+	if len(args) != 3 {
+		utils.Fatalf("Need exactly three arguments   ")
 	}
 
 	var (
 		mhash = args[0]
 		path  = args[1]
 		hash  = args[2]
-
-		ctype        string
-		wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name)
-		mroot        api.Manifest
 	)
-	if len(args) > 3 {
-		ctype = args[3]
-	} else {
-		ctype = mime.TypeByExtension(filepath.Ext(path))
+
+	bzzapi := strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
+	client := swarm.NewClient(bzzapi)
+
+	m, _, err := client.DownloadManifest(hash)
+	if err != nil {
+		utils.Fatalf("Error downloading manifest to update: %v", err)
+	}
+	l := len(m.Entries)
+	if l == 0 {
+		utils.Fatalf("No entries in manifest %s", hash)
+	} else if l > 1 {
+		utils.Fatalf("Too many entries in manifest %s", hash)
 	}
 
-	newManifest := updateEntryInManifest(ctx, mhash, path, hash, ctype)
+	newManifest, _, defaultEntryUpdated := updateEntryInManifest(client, mhash, path, m.Entries[0], true)
+	if defaultEntryUpdated {
+		// Print informational message to stderr
+		// allowing the user to get the new manifest hash from stdout
+		// without the need to parse the complete output.
+		fmt.Fprintln(os.Stderr, "Manifest default entry is updated, too")
+	}
 	fmt.Println(newManifest)
-
-	if !wantManifest {
-		// Print the manifest. This is the only output to stdout.
-		mrootJSON, _ := json.MarshalIndent(mroot, "", "  ")
-		fmt.Println(string(mrootJSON))
-		return
-	}
 }
 
-func remove(ctx *cli.Context) {
+// manifestRemove removes an existing entry of the manifest at the given path.
+// On success, this function will print hash of the manifest which does not
+// contain the path.
+func manifestRemove(ctx *cli.Context) {
 	args := ctx.Args()
-	if len(args) < 2 {
-		utils.Fatalf("Need atleast two arguments  ")
+	if len(args) != 2 {
+		utils.Fatalf("Need exactly two arguments  ")
 	}
 
 	var (
 		mhash = args[0]
 		path  = args[1]
-
-		wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name)
-		mroot        api.Manifest
 	)
 
-	newManifest := removeEntryFromManifest(ctx, mhash, path)
-	fmt.Println(newManifest)
+	bzzapi := strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
+	client := swarm.NewClient(bzzapi)
 
-	if !wantManifest {
-		// Print the manifest. This is the only output to stdout.
-		mrootJSON, _ := json.MarshalIndent(mroot, "", "  ")
-		fmt.Println(string(mrootJSON))
-		return
-	}
+	newManifest := removeEntryFromManifest(client, mhash, path)
+	fmt.Println(newManifest)
 }
 
-func addEntryToManifest(ctx *cli.Context, mhash, path, hash, ctype string) string {
+func addEntryToManifest(client *swarm.Client, mhash, path string, entry api.ManifestEntry) string {
+	var longestPathEntry = api.ManifestEntry{}
 
-	var (
-		bzzapi           = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
-		client           = swarm.NewClient(bzzapi)
-		longestPathEntry = api.ManifestEntry{}
-	)
-
-	mroot, err := client.DownloadManifest(mhash)
+	mroot, isEncrypted, err := client.DownloadManifest(mhash)
 	if err != nil {
 		utils.Fatalf("Manifest download failed: %v", err)
 	}
 
-	//TODO: check if the "hash" to add is valid and present in swarm
-	_, err = client.DownloadManifest(hash)
-	if err != nil {
-		utils.Fatalf("Hash to add is not present: %v", err)
-	}
-
 	// See if we path is in this Manifest or do we have to dig deeper
-	for _, entry := range mroot.Entries {
-		if path == entry.Path {
+	for _, e := range mroot.Entries {
+		if path == e.Path {
 			utils.Fatalf("Path %s already present, not adding anything", path)
 		} else {
-			if entry.ContentType == bzzManifestJSON {
-				prfxlen := strings.HasPrefix(path, entry.Path)
+			if e.ContentType == api.ManifestType {
+				prfxlen := strings.HasPrefix(path, e.Path)
 				if prfxlen && len(path) > len(longestPathEntry.Path) {
-					longestPathEntry = entry
+					longestPathEntry = e
 				}
 			}
 		}
@@ -159,60 +182,59 @@ func addEntryToManifest(ctx *cli.Context, mhash, path, hash, ctype string) strin
 	if longestPathEntry.Path != "" {
 		// Load the child Manifest add the entry there
 		newPath := path[len(longestPathEntry.Path):]
-		newHash := addEntryToManifest(ctx, longestPathEntry.Hash, newPath, hash, ctype)
+		newHash := addEntryToManifest(client, longestPathEntry.Hash, newPath, entry)
 
 		// Replace the hash for parent Manifests
 		newMRoot := &api.Manifest{}
-		for _, entry := range mroot.Entries {
-			if longestPathEntry.Path == entry.Path {
-				entry.Hash = newHash
+		for _, e := range mroot.Entries {
+			if longestPathEntry.Path == e.Path {
+				e.Hash = newHash
 			}
-			newMRoot.Entries = append(newMRoot.Entries, entry)
+			newMRoot.Entries = append(newMRoot.Entries, e)
 		}
 		mroot = newMRoot
 	} else {
 		// Add the entry in the leaf Manifest
-		newEntry := api.ManifestEntry{
-			Hash:        hash,
-			Path:        path,
-			ContentType: ctype,
-		}
-		mroot.Entries = append(mroot.Entries, newEntry)
+		entry.Path = path
+		mroot.Entries = append(mroot.Entries, entry)
 	}
 
-	newManifestHash, err := client.UploadManifest(mroot)
+	newManifestHash, err := client.UploadManifest(mroot, isEncrypted)
 	if err != nil {
 		utils.Fatalf("Manifest upload failed: %v", err)
 	}
 	return newManifestHash
-
 }
 
-func updateEntryInManifest(ctx *cli.Context, mhash, path, hash, ctype string) string {
-
+// updateEntryInManifest updates an existing entry o path with a new one in the manifest with provided mhash
+// finding the path recursively through all nested manifests. Argument isRoot is used for default
+// entry update detection. If the updated entry has the same hash as the default entry, then the
+// default entry in root manifest will be updated too.
+// Returned values are the new manifest hash, hash of the entry that was replaced by the new entry and
+// a a bool that is true if default entry is updated.
+func updateEntryInManifest(client *swarm.Client, mhash, path string, entry api.ManifestEntry, isRoot bool) (newManifestHash, oldHash string, defaultEntryUpdated bool) {
 	var (
-		bzzapi           = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
-		client           = swarm.NewClient(bzzapi)
 		newEntry         = api.ManifestEntry{}
 		longestPathEntry = api.ManifestEntry{}
 	)
 
-	mroot, err := client.DownloadManifest(mhash)
+	mroot, isEncrypted, err := client.DownloadManifest(mhash)
 	if err != nil {
 		utils.Fatalf("Manifest download failed: %v", err)
 	}
 
-	//TODO: check if the "hash" with which to update is valid and present in swarm
-
 	// See if we path is in this Manifest or do we have to dig deeper
-	for _, entry := range mroot.Entries {
-		if path == entry.Path {
-			newEntry = entry
+	for _, e := range mroot.Entries {
+		if path == e.Path {
+			newEntry = e
+			// keep the reference of the hash of the entry that should be replaced
+			// for default entry detection
+			oldHash = e.Hash
 		} else {
-			if entry.ContentType == bzzManifestJSON {
-				prfxlen := strings.HasPrefix(path, entry.Path)
+			if e.ContentType == api.ManifestType {
+				prfxlen := strings.HasPrefix(path, e.Path)
 				if prfxlen && len(path) > len(longestPathEntry.Path) {
-					longestPathEntry = entry
+					longestPathEntry = e
 				}
 			}
 		}
@@ -225,55 +247,55 @@ func updateEntryInManifest(ctx *cli.Context, mhash, path, hash, ctype string) st
 	if longestPathEntry.Path != "" {
 		// Load the child Manifest add the entry there
 		newPath := path[len(longestPathEntry.Path):]
-		newHash := updateEntryInManifest(ctx, longestPathEntry.Hash, newPath, hash, ctype)
+		var newHash string
+		newHash, oldHash, _ = updateEntryInManifest(client, longestPathEntry.Hash, newPath, entry, false)
 
 		// Replace the hash for parent Manifests
 		newMRoot := &api.Manifest{}
-		for _, entry := range mroot.Entries {
-			if longestPathEntry.Path == entry.Path {
-				entry.Hash = newHash
+		for _, e := range mroot.Entries {
+			if longestPathEntry.Path == e.Path {
+				e.Hash = newHash
 			}
-			newMRoot.Entries = append(newMRoot.Entries, entry)
+			newMRoot.Entries = append(newMRoot.Entries, e)
 
 		}
 		mroot = newMRoot
 	}
 
-	if newEntry.Path != "" {
+	// update the manifest if the new entry is found and
+	// check if default entry should be updated
+	if newEntry.Path != "" || isRoot {
 		// Replace the hash for leaf Manifest
 		newMRoot := &api.Manifest{}
-		for _, entry := range mroot.Entries {
-			if newEntry.Path == entry.Path {
-				myEntry := api.ManifestEntry{
-					Hash:        hash,
-					Path:        entry.Path,
-					ContentType: ctype,
-				}
-				newMRoot.Entries = append(newMRoot.Entries, myEntry)
-			} else {
+		for _, e := range mroot.Entries {
+			if newEntry.Path == e.Path {
+				entry.Path = e.Path
 				newMRoot.Entries = append(newMRoot.Entries, entry)
+			} else if isRoot && e.Path == "" && e.Hash == oldHash {
+				entry.Path = e.Path
+				newMRoot.Entries = append(newMRoot.Entries, entry)
+				defaultEntryUpdated = true
+			} else {
+				newMRoot.Entries = append(newMRoot.Entries, e)
 			}
 		}
 		mroot = newMRoot
 	}
 
-	newManifestHash, err := client.UploadManifest(mroot)
+	newManifestHash, err = client.UploadManifest(mroot, isEncrypted)
 	if err != nil {
 		utils.Fatalf("Manifest upload failed: %v", err)
 	}
-	return newManifestHash
+	return newManifestHash, oldHash, defaultEntryUpdated
 }
 
-func removeEntryFromManifest(ctx *cli.Context, mhash, path string) string {
-
+func removeEntryFromManifest(client *swarm.Client, mhash, path string) string {
 	var (
-		bzzapi           = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
-		client           = swarm.NewClient(bzzapi)
 		entryToRemove    = api.ManifestEntry{}
 		longestPathEntry = api.ManifestEntry{}
 	)
 
-	mroot, err := client.DownloadManifest(mhash)
+	mroot, isEncrypted, err := client.DownloadManifest(mhash)
 	if err != nil {
 		utils.Fatalf("Manifest download failed: %v", err)
 	}
@@ -283,7 +305,7 @@ func removeEntryFromManifest(ctx *cli.Context, mhash, path string) string {
 		if path == entry.Path {
 			entryToRemove = entry
 		} else {
-			if entry.ContentType == bzzManifestJSON {
+			if entry.ContentType == api.ManifestType {
 				prfxlen := strings.HasPrefix(path, entry.Path)
 				if prfxlen && len(path) > len(longestPathEntry.Path) {
 					longestPathEntry = entry
@@ -299,7 +321,7 @@ func removeEntryFromManifest(ctx *cli.Context, mhash, path string) string {
 	if longestPathEntry.Path != "" {
 		// Load the child Manifest remove the entry there
 		newPath := path[len(longestPathEntry.Path):]
-		newHash := removeEntryFromManifest(ctx, longestPathEntry.Hash, newPath)
+		newHash := removeEntryFromManifest(client, longestPathEntry.Hash, newPath)
 
 		// Replace the hash for parent Manifests
 		newMRoot := &api.Manifest{}
@@ -323,7 +345,7 @@ func removeEntryFromManifest(ctx *cli.Context, mhash, path string) string {
 		mroot = newMRoot
 	}
 
-	newManifestHash, err := client.UploadManifest(mroot)
+	newManifestHash, err := client.UploadManifest(mroot, isEncrypted)
 	if err != nil {
 		utils.Fatalf("Manifest upload failed: %v", err)
 	}
diff --git a/cmd/swarm/manifest_test.go b/cmd/swarm/manifest_test.go
new file mode 100644
index 0000000000..01d982aa7a
--- /dev/null
+++ b/cmd/swarm/manifest_test.go
@@ -0,0 +1,597 @@
+// 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"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"runtime"
+	"testing"
+
+	"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"
+)
+
+// TestManifestChange tests manifest add, update and remove
+// cli commands without encryption.
+func TestManifestChange(t *testing.T) {
+	if runtime.GOOS == "windows" {
+		t.Skip()
+	}
+
+	testManifestChange(t, false)
+}
+
+// TestManifestChange tests manifest add, update and remove
+// cli commands with encryption enabled.
+func TestManifestChangeEncrypted(t *testing.T) {
+	if runtime.GOOS == "windows" {
+		t.Skip()
+	}
+
+	testManifestChange(t, true)
+}
+
+// testManifestChange performs cli commands:
+// - manifest add
+// - manifest update
+// - manifest remove
+// on a manifest, testing the functionality of this
+// comands on paths that are in root manifest or a nested one.
+// Argument encrypt controls whether to use encryption or not.
+func testManifestChange(t *testing.T, encrypt bool) {
+	t.Parallel()
+	srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil)
+	defer srv.Close()
+
+	tmp, err := ioutil.TempDir("", "swarm-manifest-test")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(tmp)
+
+	origDir := filepath.Join(tmp, "orig")
+	if err := os.Mkdir(origDir, 0777); err != nil {
+		t.Fatal(err)
+	}
+
+	indexDataFilename := filepath.Join(origDir, "index.html")
+	err = ioutil.WriteFile(indexDataFilename, []byte("

Test

"), 0666) + if err != nil { + t.Fatal(err) + } + // Files paths robots.txt and robots.html share the same prefix "robots." + // which will result a manifest with a nested manifest under path "robots.". + // This will allow testing manifest changes on both root and nested manifest. + err = ioutil.WriteFile(filepath.Join(origDir, "robots.txt"), []byte("Disallow: /"), 0666) + if err != nil { + t.Fatal(err) + } + err = ioutil.WriteFile(filepath.Join(origDir, "robots.html"), []byte("No Robots Allowed"), 0666) + if err != nil { + t.Fatal(err) + } + err = ioutil.WriteFile(filepath.Join(origDir, "mutants.txt"), []byte("Frank\nMarcus"), 0666) + if err != nil { + t.Fatal(err) + } + + args := []string{ + "--bzzapi", + srv.URL, + "--recursive", + "--defaultpath", + indexDataFilename, + "up", + origDir, + } + if encrypt { + args = append(args, "--encrypt") + } + + origManifestHash := runSwarmExpectHash(t, args...) + + checkHashLength(t, origManifestHash, encrypt) + + client := swarm.NewClient(srv.URL) + + // upload a new file and use its manifest to add it the original manifest. + t.Run("add", func(t *testing.T) { + humansData := []byte("Ann\nBob") + humansDataFilename := filepath.Join(tmp, "humans.txt") + err = ioutil.WriteFile(humansDataFilename, humansData, 0666) + if err != nil { + t.Fatal(err) + } + + humansManifestHash := runSwarmExpectHash(t, + "--bzzapi", + srv.URL, + "up", + humansDataFilename, + ) + + newManifestHash := runSwarmExpectHash(t, + "--bzzapi", + srv.URL, + "manifest", + "add", + origManifestHash, + "humans.txt", + humansManifestHash, + ) + + checkHashLength(t, newManifestHash, encrypt) + + newManifest := downloadManifest(t, client, newManifestHash, encrypt) + + var found bool + for _, e := range newManifest.Entries { + if e.Path == "humans.txt" { + found = true + if e.Size != int64(len(humansData)) { + t.Errorf("expected humans.txt size %v, got %v", len(humansData), e.Size) + } + if e.ModTime.IsZero() { + t.Errorf("got zero mod time for humans.txt") + } + ct := "text/plain; charset=utf-8" + if e.ContentType != ct { + t.Errorf("expected content type %q, got %q", ct, e.ContentType) + } + break + } + } + if !found { + t.Fatal("no humans.txt in new manifest") + } + + checkFile(t, client, newManifestHash, "humans.txt", humansData) + }) + + // upload a new file and use its manifest to add it the original manifest, + // but ensure that the file will be in the nested manifest of the original one. + t.Run("add nested", func(t *testing.T) { + robotsData := []byte(`{"disallow": "/"}`) + robotsDataFilename := filepath.Join(tmp, "robots.json") + err = ioutil.WriteFile(robotsDataFilename, robotsData, 0666) + if err != nil { + t.Fatal(err) + } + + robotsManifestHash := runSwarmExpectHash(t, + "--bzzapi", + srv.URL, + "up", + robotsDataFilename, + ) + + newManifestHash := runSwarmExpectHash(t, + "--bzzapi", + srv.URL, + "manifest", + "add", + origManifestHash, + "robots.json", + robotsManifestHash, + ) + + checkHashLength(t, newManifestHash, encrypt) + + newManifest := downloadManifest(t, client, newManifestHash, encrypt) + + var found bool + loop: + for _, e := range newManifest.Entries { + if e.Path == "robots." { + nestedManifest := downloadManifest(t, client, e.Hash, encrypt) + for _, e := range nestedManifest.Entries { + if e.Path == "json" { + found = true + if e.Size != int64(len(robotsData)) { + t.Errorf("expected robots.json size %v, got %v", len(robotsData), e.Size) + } + if e.ModTime.IsZero() { + t.Errorf("got zero mod time for robots.json") + } + ct := "application/json" + if e.ContentType != ct { + t.Errorf("expected content type %q, got %q", ct, e.ContentType) + } + break loop + } + } + } + } + if !found { + t.Fatal("no robots.json in new manifest") + } + + checkFile(t, client, newManifestHash, "robots.json", robotsData) + }) + + // upload a new file and use its manifest to change the file it the original manifest. + t.Run("update", func(t *testing.T) { + indexData := []byte("

Ethereum Swarm

") + indexDataFilename := filepath.Join(tmp, "index.html") + err = ioutil.WriteFile(indexDataFilename, indexData, 0666) + if err != nil { + t.Fatal(err) + } + + indexManifestHash := runSwarmExpectHash(t, + "--bzzapi", + srv.URL, + "up", + indexDataFilename, + ) + + newManifestHash := runSwarmExpectHash(t, + "--bzzapi", + srv.URL, + "manifest", + "update", + origManifestHash, + "index.html", + indexManifestHash, + ) + + checkHashLength(t, newManifestHash, encrypt) + + newManifest := downloadManifest(t, client, newManifestHash, encrypt) + + var found bool + for _, e := range newManifest.Entries { + if e.Path == "index.html" { + found = true + if e.Size != int64(len(indexData)) { + t.Errorf("expected index.html size %v, got %v", len(indexData), e.Size) + } + if e.ModTime.IsZero() { + t.Errorf("got zero mod time for index.html") + } + ct := "text/html; charset=utf-8" + if e.ContentType != ct { + t.Errorf("expected content type %q, got %q", ct, e.ContentType) + } + break + } + } + if !found { + t.Fatal("no index.html in new manifest") + } + + checkFile(t, client, newManifestHash, "index.html", indexData) + + // check default entry change + checkFile(t, client, newManifestHash, "", indexData) + }) + + // upload a new file and use its manifest to change the file it the original manifest, + // but ensure that the file is in the nested manifest of the original one. + t.Run("update nested", func(t *testing.T) { + robotsData := []byte(`Only humans allowed!!!`) + robotsDataFilename := filepath.Join(tmp, "robots.html") + err = ioutil.WriteFile(robotsDataFilename, robotsData, 0666) + if err != nil { + t.Fatal(err) + } + + humansManifestHash := runSwarmExpectHash(t, + "--bzzapi", + srv.URL, + "up", + robotsDataFilename, + ) + + newManifestHash := runSwarmExpectHash(t, + "--bzzapi", + srv.URL, + "manifest", + "update", + origManifestHash, + "robots.html", + humansManifestHash, + ) + + checkHashLength(t, newManifestHash, encrypt) + + newManifest := downloadManifest(t, client, newManifestHash, encrypt) + + var found bool + loop: + for _, e := range newManifest.Entries { + if e.Path == "robots." { + nestedManifest := downloadManifest(t, client, e.Hash, encrypt) + for _, e := range nestedManifest.Entries { + if e.Path == "html" { + found = true + if e.Size != int64(len(robotsData)) { + t.Errorf("expected robots.html size %v, got %v", len(robotsData), e.Size) + } + if e.ModTime.IsZero() { + t.Errorf("got zero mod time for robots.html") + } + ct := "text/html; charset=utf-8" + if e.ContentType != ct { + t.Errorf("expected content type %q, got %q", ct, e.ContentType) + } + break loop + } + } + } + } + if !found { + t.Fatal("no robots.html in new manifest") + } + + checkFile(t, client, newManifestHash, "robots.html", robotsData) + }) + + // remove a file from the manifest. + t.Run("remove", func(t *testing.T) { + newManifestHash := runSwarmExpectHash(t, + "--bzzapi", + srv.URL, + "manifest", + "remove", + origManifestHash, + "mutants.txt", + ) + + checkHashLength(t, newManifestHash, encrypt) + + newManifest := downloadManifest(t, client, newManifestHash, encrypt) + + var found bool + for _, e := range newManifest.Entries { + if e.Path == "mutants.txt" { + found = true + break + } + } + if found { + t.Fatal("mutants.txt is not removed") + } + }) + + // remove a file from the manifest, but ensure that the file is in + // the nested manifest of the original one. + t.Run("remove nested", func(t *testing.T) { + newManifestHash := runSwarmExpectHash(t, + "--bzzapi", + srv.URL, + "manifest", + "remove", + origManifestHash, + "robots.html", + ) + + checkHashLength(t, newManifestHash, encrypt) + + newManifest := downloadManifest(t, client, newManifestHash, encrypt) + + var found bool + loop: + for _, e := range newManifest.Entries { + if e.Path == "robots." { + nestedManifest := downloadManifest(t, client, e.Hash, encrypt) + for _, e := range nestedManifest.Entries { + if e.Path == "html" { + found = true + break loop + } + } + } + } + if found { + t.Fatal("robots.html in not removed") + } + }) +} + +// TestNestedDefaultEntryUpdate tests if the default entry is updated +// if the file in nested manifest used for it is also updated. +func TestNestedDefaultEntryUpdate(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip() + } + + testNestedDefaultEntryUpdate(t, false) +} + +// TestNestedDefaultEntryUpdateEncrypted tests if the default entry +// of encrypted upload is updated if the file in nested manifest +// used for it is also updated. +func TestNestedDefaultEntryUpdateEncrypted(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip() + } + + testNestedDefaultEntryUpdate(t, true) +} + +func testNestedDefaultEntryUpdate(t *testing.T, encrypt bool) { + t.Parallel() + srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil) + defer srv.Close() + + tmp, err := ioutil.TempDir("", "swarm-manifest-test") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmp) + + origDir := filepath.Join(tmp, "orig") + if err := os.Mkdir(origDir, 0777); err != nil { + t.Fatal(err) + } + + indexData := []byte("

Test

") + indexDataFilename := filepath.Join(origDir, "index.html") + err = ioutil.WriteFile(indexDataFilename, indexData, 0666) + if err != nil { + t.Fatal(err) + } + // Add another file with common prefix as the default entry to test updates of + // default entry with nested manifests. + err = ioutil.WriteFile(filepath.Join(origDir, "index.txt"), []byte("Test"), 0666) + if err != nil { + t.Fatal(err) + } + + args := []string{ + "--bzzapi", + srv.URL, + "--recursive", + "--defaultpath", + indexDataFilename, + "up", + origDir, + } + if encrypt { + args = append(args, "--encrypt") + } + + origManifestHash := runSwarmExpectHash(t, args...) + + checkHashLength(t, origManifestHash, encrypt) + + client := swarm.NewClient(srv.URL) + + newIndexData := []byte("

Ethereum Swarm

") + newIndexDataFilename := filepath.Join(tmp, "index.html") + err = ioutil.WriteFile(newIndexDataFilename, newIndexData, 0666) + if err != nil { + t.Fatal(err) + } + + newIndexManifestHash := runSwarmExpectHash(t, + "--bzzapi", + srv.URL, + "up", + newIndexDataFilename, + ) + + newManifestHash := runSwarmExpectHash(t, + "--bzzapi", + srv.URL, + "manifest", + "update", + origManifestHash, + "index.html", + newIndexManifestHash, + ) + + checkHashLength(t, newManifestHash, encrypt) + + newManifest := downloadManifest(t, client, newManifestHash, encrypt) + + var found bool + for _, e := range newManifest.Entries { + if e.Path == "index." { + found = true + newManifest = downloadManifest(t, client, e.Hash, encrypt) + break + } + } + if !found { + t.Fatal("no index. path in new manifest") + } + + found = false + for _, e := range newManifest.Entries { + if e.Path == "html" { + found = true + if e.Size != int64(len(newIndexData)) { + t.Errorf("expected index.html size %v, got %v", len(newIndexData), e.Size) + } + if e.ModTime.IsZero() { + t.Errorf("got zero mod time for index.html") + } + ct := "text/html; charset=utf-8" + if e.ContentType != ct { + t.Errorf("expected content type %q, got %q", ct, e.ContentType) + } + break + } + } + if !found { + t.Fatal("no html in new manifest") + } + + checkFile(t, client, newManifestHash, "index.html", newIndexData) + + // check default entry change + checkFile(t, client, newManifestHash, "", newIndexData) +} + +func runSwarmExpectHash(t *testing.T, args ...string) (hash string) { + t.Helper() + hashRegexp := `[a-f\d]{64,128}` + up := runSwarm(t, args...) + _, matches := up.ExpectRegexp(hashRegexp) + up.ExpectExit() + + if len(matches) < 1 { + t.Fatal("no matches found") + } + return matches[0] +} + +func checkHashLength(t *testing.T, hash string, encrypted bool) { + t.Helper() + l := len(hash) + if encrypted && l != 128 { + t.Errorf("expected hash length 128, got %v", l) + } + if !encrypted && l != 64 { + t.Errorf("expected hash length 64, got %v", l) + } +} + +func downloadManifest(t *testing.T, client *swarm.Client, hash string, encrypted bool) (manifest *api.Manifest) { + t.Helper() + m, isEncrypted, err := client.DownloadManifest(hash) + if err != nil { + t.Fatal(err) + } + + if encrypted != isEncrypted { + t.Error("new manifest encryption flag is not correct") + } + return m +} + +func checkFile(t *testing.T, client *swarm.Client, hash, path string, expected []byte) { + t.Helper() + f, err := client.Download(hash, path) + if err != nil { + t.Fatal(err) + } + + got, err := ioutil.ReadAll(f) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(got, expected) { + t.Errorf("expected file content %q, got %q", expected, got) + } +} diff --git a/cmd/swarm/mimegen/generator.go b/cmd/swarm/mimegen/generator.go new file mode 100644 index 0000000000..68f9e306e5 --- /dev/null +++ b/cmd/swarm/mimegen/generator.go @@ -0,0 +1,124 @@ +// 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 + +// Standard "mime" package rely on system-settings, see mime.osInitMime +// Swarm will run on many OS/Platform/Docker and must behave similar +// This command generates code to add common mime types based on mime.types file +// +// mime.types file provided by mailcap, which follow https://www.iana.org/assignments/media-types/media-types.xhtml +// +// Get last version of mime.types file by: +// docker run --rm -v $(pwd):/tmp alpine:edge /bin/sh -c "apk add -U mailcap; mv /etc/mime.types /tmp" + +import ( + "bufio" + "bytes" + "flag" + "html/template" + "io/ioutil" + "strings" + + "log" +) + +var ( + typesFlag = flag.String("types", "", "Input mime.types file") + packageFlag = flag.String("package", "", "Golang package in output file") + outFlag = flag.String("out", "", "Output file name for the generated mime types") +) + +type mime struct { + Name string + Exts []string +} + +type templateParams struct { + PackageName string + Mimes []mime +} + +func main() { + // Parse and ensure all needed inputs are specified + flag.Parse() + if *typesFlag == "" { + log.Fatalf("--types is required") + } + if *packageFlag == "" { + log.Fatalf("--types is required") + } + if *outFlag == "" { + log.Fatalf("--out is required") + } + + params := templateParams{ + PackageName: *packageFlag, + } + + types, err := ioutil.ReadFile(*typesFlag) + if err != nil { + log.Fatal(err) + } + + scanner := bufio.NewScanner(bytes.NewReader(types)) + for scanner.Scan() { + txt := scanner.Text() + if strings.HasPrefix(txt, "#") || len(txt) == 0 { + continue + } + parts := strings.Fields(txt) + if len(parts) == 1 { + continue + } + params.Mimes = append(params.Mimes, mime{parts[0], parts[1:]}) + } + + if err = scanner.Err(); err != nil { + log.Fatal(err) + } + + result := bytes.NewBuffer([]byte{}) + + if err := template.Must(template.New("_").Parse(tpl)).Execute(result, params); err != nil { + log.Fatal(err) + } + + if err := ioutil.WriteFile(*outFlag, result.Bytes(), 0600); err != nil { + log.Fatal(err) + } +} + +var tpl = `// Code generated by github.com/ethereum/go-ethereum/cmd/swarm/mimegen. DO NOT EDIT. + +package {{ .PackageName }} + +import "mime" +func init() { + var mimeTypes = map[string]string{ +{{- range .Mimes -}} + {{ $name := .Name -}} + {{- range .Exts }} + ".{{ . }}": "{{ $name | html }}", + {{- end }} +{{- end }} + } + for ext, name := range mimeTypes { + if err := mime.AddExtensionType(ext, name); err != nil { + panic(err) + } + } +} +` diff --git a/cmd/swarm/mimegen/mime.types b/cmd/swarm/mimegen/mime.types new file mode 100644 index 0000000000..1bdf211490 --- /dev/null +++ b/cmd/swarm/mimegen/mime.types @@ -0,0 +1,1828 @@ +# This is a comment. I love comments. -*- indent-tabs-mode: t -*- + +# This file controls what Internet media types are sent to the client for +# given file extension(s). Sending the correct media type to the client +# is important so they know how to handle the content of the file. +# Extra types can either be added here or by using an AddType directive +# in your config files. For more information about Internet media types, +# please read RFC 2045, 2046, 2047, 2048, and 2077. The Internet media type +# registry is at . + +# IANA types + +# MIME type Extensions +application/1d-interleaved-parityfec +application/3gpdash-qoe-report+xml +application/3gpp-ims+xml +application/A2L a2l +application/activemessage +application/alto-costmap+json +application/alto-costmapfilter+json +application/alto-directory+json +application/alto-endpointcost+json +application/alto-endpointcostparams+json +application/alto-endpointprop+json +application/alto-endpointpropparams+json +application/alto-error+json +application/alto-networkmap+json +application/alto-networkmapfilter+json +application/AML aml +application/andrew-inset ez +application/applefile +application/ATF atf +application/ATFX atfx +application/ATXML atxml +application/atom+xml atom +application/atomcat+xml atomcat +application/atomdeleted+xml atomdeleted +application/atomicmail +application/atomsvc+xml atomsvc +application/auth-policy+xml apxml +application/bacnet-xdd+zip xdd +application/batch-SMTP +application/beep+xml +application/calendar+json +application/calendar+xml xcs +application/call-completion +application/cals-1840 +application/cbor cbor +application/ccmp+xml ccmp +application/ccxml+xml ccxml +application/CDFX+XML cdfx +application/cdmi-capability cdmia +application/cdmi-container cdmic +application/cdmi-domain cdmid +application/cdmi-object cdmio +application/cdmi-queue cdmiq +application/cdni +application/CEA cea +application/cea-2018+xml +application/cellml+xml cellml cml +application/cfw +application/clue_info+xml clue +application/cms cmsc +application/cnrp+xml +application/coap-group+json +application/coap-payload +application/commonground +application/conference-info+xml +application/cpl+xml cpl +application/cose +application/cose-key +application/cose-key-set +application/csrattrs csrattrs +application/csta+xml +application/CSTAdata+xml +application/csvm+json +application/cybercash +application/dash+xml mpd +application/dashdelta mpdd +application/davmount+xml davmount +application/dca-rft +application/DCD dcd +application/dec-dx +application/dialog-info+xml +application/dicom dcm +application/dicom+json +application/dicom+xml +application/DII dii +application/DIT dit +application/dns +application/dskpp+xml xmls +application/dssc+der dssc +application/dssc+xml xdssc +application/dvcs dvc +application/ecmascript es +application/EDI-Consent +application/EDI-X12 +application/EDIFACT +application/efi efi +application/EmergencyCallData.Comment+xml +application/EmergencyCallData.Control+xml +application/EmergencyCallData.DeviceInfo+xml +application/EmergencyCallData.eCall.MSD +application/EmergencyCallData.ProviderInfo+xml +application/EmergencyCallData.ServiceInfo+xml +application/EmergencyCallData.SubscriberInfo+xml +application/EmergencyCallData.VEDS+xml +application/emma+xml emma +application/emotionml+xml emotionml +application/encaprtp +application/epp+xml +application/epub+zip epub +application/eshop +application/exi exi +application/fastinfoset finf +application/fastsoap +application/fdt+xml fdt +# fits, fit, fts: image/fits +application/fits +# application/font-sfnt deprecated in favor of font/sfnt +application/font-tdpfr pfr +# application/font-woff deprecated in favor of font/woff +application/framework-attributes+xml +application/geo+json geojson +application/geo+json-seq +application/gml+xml gml +application/gzip gz tgz +application/H224 +application/held+xml +application/http +application/hyperstudio stk +application/ibe-key-request+xml +application/ibe-pkg-reply+xml +application/ibe-pp-data +application/iges +application/im-iscomposing+xml +application/index +application/index.cmd +application/index.obj +application/index.response +application/index.vnd +application/inkml+xml ink inkml +application/iotp +application/ipfix ipfix +application/ipp +application/isup +application/its+xml its +application/javascript js +application/jose +application/jose+json +application/jrd+json jrd +application/json json +application/json-patch+json json-patch +application/json-seq +application/jwk+json +application/jwk-set+json +application/jwt +application/kpml-request+xml +application/kpml-response+xml +application/ld+json jsonld +application/lgr+xml lgr +application/link-format wlnk +application/load-control+xml +application/lost+xml lostxml +application/lostsync+xml lostsyncxml +application/LXF lxf +application/mac-binhex40 hqx +application/macwriteii +application/mads+xml mads +application/marc mrc +application/marcxml+xml mrcx +application/mathematica nb ma mb +application/mathml-content+xml +application/mathml-presentation+xml +application/mathml+xml mml +application/mbms-associated-procedure-description+xml +application/mbms-deregister+xml +application/mbms-envelope+xml +application/mbms-msk-response+xml +application/mbms-msk+xml +application/mbms-protection-description+xml +application/mbms-reception-report+xml +application/mbms-register-response+xml +application/mbms-register+xml +application/mbms-schedule+xml +application/mbms-user-service-description+xml +application/mbox mbox +application/media_control+xml +# mpf: text/vnd.ms-mediapackage +application/media-policy-dataset+xml +application/mediaservercontrol+xml +application/merge-patch+json +application/metalink4+xml meta4 +application/mets+xml mets +application/MF4 mf4 +application/mikey +application/mods+xml mods +application/moss-keys +application/moss-signature +application/mosskey-data +application/mosskey-request +application/mp21 m21 mp21 +# mp4, mpg4: video/mp4, see RFC 4337 +application/mp4 +application/mpeg4-generic +application/mpeg4-iod +application/mpeg4-iod-xmt +# xdf: application/xcap-diff+xml +application/mrb-consumer+xml +application/mrb-publish+xml +application/msc-ivr+xml +application/msc-mixer+xml +application/msword doc +application/mud+json +application/mxf mxf +application/n-quads nq +application/n-triples nt +application/nasdata +application/news-checkgroups +application/news-groupinfo +application/news-transmission +application/nlsml+xml +application/nss +application/ocsp-request orq +application/ocsp-response ors +application/octet-stream bin lha lzh exe class so dll img iso +application/oda oda +application/ODX odx +application/oebps-package+xml opf +application/ogg ogx +application/oxps oxps +application/p2p-overlay+xml relo +application/parityfec +# xer: application/xcap-error+xml +application/patch-ops-error+xml +application/pdf pdf +application/PDX pdx +application/pgp-encrypted pgp +application/pgp-keys +application/pgp-signature sig +application/pidf-diff+xml +application/pidf+xml +application/pkcs10 p10 +application/pkcs12 p12 pfx +application/pkcs7-mime p7m p7c +application/pkcs7-signature p7s +application/pkcs8 p8 +# ac: application/vnd.nokia.n-gage.ac+xml +application/pkix-attr-cert +application/pkix-cert cer +application/pkix-crl crl +application/pkix-pkipath pkipath +application/pkixcmp pki +application/pls+xml pls +application/poc-settings+xml +application/postscript ps eps ai +application/ppsp-tracker+json +application/problem+json +application/problem+xml +application/provenance+xml provx +application/prs.alvestrand.titrax-sheet +application/prs.cww cw cww +application/prs.hpub+zip hpub +application/prs.nprend rnd rct +application/prs.plucker +application/prs.rdf-xml-crypt rdf-crypt +application/prs.xsf+xml xsf +application/pskc+xml pskcxml +application/qsig +application/raptorfec +application/rdap+json +application/rdf+xml rdf +application/reginfo+xml rif +application/relax-ng-compact-syntax rnc +application/remote-printing +application/reputon+json +application/resource-lists-diff+xml rld +application/resource-lists+xml rl +application/rfc+xml rfcxml +application/riscos +application/rlmi+xml +application/rls-services+xml rs +application/rpki-ghostbusters gbr +application/rpki-manifest mft +application/rpki-publication +application/rpki-roa roa +application/rpki-updown +application/rtf rtf +application/rtploopback +application/rtx +application/samlassertion+xml +application/samlmetadata+xml +application/sbml+xml +application/scaip+xml +# scm: application/vnd.lotus-screencam +application/scim+json scim +application/scvp-cv-request scq +application/scvp-cv-response scs +application/scvp-vp-request spq +application/scvp-vp-response spp +application/sdp sdp +application/sep+xml +application/sep-exi +application/session-info +application/set-payment +application/set-payment-initiation +application/set-registration +application/set-registration-initiation +application/sgml +application/sgml-open-catalog soc +application/shf+xml shf +application/sieve siv sieve +application/simple-filter+xml cl +application/simple-message-summary +application/simpleSymbolContainer +application/slate +# application/smil obsoleted by application/smil+xml +application/smil+xml smil smi sml +application/smpte336m +application/soap+fastinfoset +application/soap+xml +application/sparql-query rq +application/sparql-results+xml srx +application/spirits-event+xml +application/sql sql +application/srgs gram +application/srgs+xml grxml +application/sru+xml sru +application/ssml+xml ssml +application/tamp-apex-update tau +application/tamp-apex-update-confirm auc +application/tamp-community-update tcu +application/tamp-community-update-confirm cuc +application/tamp-error ter +application/tamp-sequence-adjust tsa +application/tamp-sequence-adjust-confirm sac +# tsq: application/timestamp-query +application/tamp-status-query +# tsr: application/timestamp-reply +application/tamp-status-response +application/tamp-update tur +application/tamp-update-confirm tuc +application/tei+xml tei teiCorpus odd +application/thraud+xml tfi +application/timestamp-query tsq +application/timestamp-reply tsr +application/timestamped-data tsd +application/trig trig +application/ttml+xml ttml +application/tve-trigger +application/ulpfec +application/urc-grpsheet+xml gsheet +application/urc-ressheet+xml rsheet +application/urc-targetdesc+xml td +application/urc-uisocketdesc+xml uis +application/vcard+json +application/vcard+xml +application/vemmi +application/vnd.3gpp.access-transfer-events+xml +application/vnd.3gpp.bsf+xml +application/vnd.3gpp.mid-call+xml +application/vnd.3gpp.pic-bw-large plb +application/vnd.3gpp.pic-bw-small psb +application/vnd.3gpp.pic-bw-var pvb +application/vnd.3gpp-prose+xml +application/vnd.3gpp-prose-pc3ch+xml +# sms: application/vnd.3gpp2.sms +application/vnd.3gpp.sms +application/vnd.3gpp.sms+xml +application/vnd.3gpp.srvcc-ext+xml +application/vnd.3gpp.SRVCC-info+xml +application/vnd.3gpp.state-and-event-info+xml +application/vnd.3gpp.ussd+xml +application/vnd.3gpp2.bcmcsinfo+xml +application/vnd.3gpp2.sms sms +application/vnd.3gpp2.tcap tcap +application/vnd.3lightssoftware.imagescal imgcal +application/vnd.3M.Post-it-Notes pwn +application/vnd.accpac.simply.aso aso +application/vnd.accpac.simply.imp imp +application/vnd.acucobol acu +application/vnd.acucorp atc acutc +application/vnd.adobe.flash.movie swf +application/vnd.adobe.formscentral.fcdt fcdt +application/vnd.adobe.fxp fxp fxpl +application/vnd.adobe.partial-upload +application/vnd.adobe.xdp+xml xdp +application/vnd.adobe.xfdf xfdf +application/vnd.aether.imp +application/vnd.ah-barcode +application/vnd.ahead.space ahead +application/vnd.airzip.filesecure.azf azf +application/vnd.airzip.filesecure.azs azs +application/vnd.amazon.mobi8-ebook azw3 +application/vnd.americandynamics.acc acc +application/vnd.amiga.ami ami +application/vnd.amundsen.maze+xml +application/vnd.anki apkg +application/vnd.anser-web-certificate-issue-initiation cii +# Not in IANA listing, but is on FTP site? +application/vnd.anser-web-funds-transfer-initiation fti +# atx: audio/ATRAC-X +application/vnd.antix.game-component +application/vnd.apache.thrift.binary +application/vnd.apache.thrift.compact +application/vnd.apache.thrift.json +application/vnd.api+json +application/vnd.apothekende.reservation+json +application/vnd.apple.installer+xml dist distz pkg mpkg +# m3u: audio/x-mpegurl for now +application/vnd.apple.mpegurl m3u8 +# application/vnd.arastra.swi obsoleted by application/vnd.aristanetworks.swi +application/vnd.aristanetworks.swi swi +application/vnd.artsquare +application/vnd.astraea-software.iota iota +application/vnd.audiograph aep +application/vnd.autopackage package +application/vnd.avistar+xml +application/vnd.balsamiq.bmml+xml bmml +application/vnd.balsamiq.bmpr bmpr +application/vnd.bekitzur-stech+json +application/vnd.bint.med-content +application/vnd.biopax.rdf+xml +application/vnd.blueice.multipass mpm +application/vnd.bluetooth.ep.oob ep +application/vnd.bluetooth.le.oob le +application/vnd.bmi bmi +application/vnd.businessobjects rep +application/vnd.cab-jscript +application/vnd.canon-cpdl +application/vnd.canon-lips +application/vnd.capasystems-pg+json +application/vnd.cendio.thinlinc.clientconf tlclient +application/vnd.century-systems.tcp_stream +application/vnd.chemdraw+xml cdxml +application/vnd.chess-pgn pgn +application/vnd.chipnuts.karaoke-mmd mmd +application/vnd.cinderella cdy +application/vnd.cirpack.isdn-ext +application/vnd.citationstyles.style+xml csl +application/vnd.claymore cla +application/vnd.cloanto.rp9 rp9 +application/vnd.clonk.c4group c4g c4d c4f c4p c4u +application/vnd.cluetrust.cartomobile-config c11amc +application/vnd.cluetrust.cartomobile-config-pkg c11amz +application/vnd.coffeescript coffee +application/vnd.collection+json +application/vnd.collection.doc+json +application/vnd.collection.next+json +application/vnd.comicbook+zip cbz +# icc: application/vnd.iccprofile +application/vnd.commerce-battelle ica icf icd ic0 ic1 ic2 ic3 ic4 ic5 ic6 ic7 ic8 +application/vnd.commonspace csp cst +application/vnd.contact.cmsg cdbcmsg +application/vnd.coreos.ignition+json ign ignition +application/vnd.cosmocaller cmc +application/vnd.crick.clicker clkx +application/vnd.crick.clicker.keyboard clkk +application/vnd.crick.clicker.palette clkp +application/vnd.crick.clicker.template clkt +application/vnd.crick.clicker.wordbank clkw +application/vnd.criticaltools.wbs+xml wbs +application/vnd.ctc-posml pml +application/vnd.ctct.ws+xml +application/vnd.cups-pdf +application/vnd.cups-postscript +application/vnd.cups-ppd ppd +application/vnd.cups-raster +application/vnd.cups-raw +application/vnd.curl curl +application/vnd.cyan.dean.root+xml +application/vnd.cybank +application/vnd.d2l.coursepackage1p0+zip +application/vnd.dart dart +application/vnd.data-vision.rdz rdz +application/vnd.datapackage+json +application/vnd.dataresource+json +application/vnd.debian.binary-package deb udeb +application/vnd.dece.data uvf uvvf uvd uvvd +application/vnd.dece.ttml+xml uvt uvvt +application/vnd.dece.unspecified uvx uvvx +application/vnd.dece.zip uvz uvvz +application/vnd.denovo.fcselayout-link fe_launch +application/vnd.desmume.movie dsm +application/vnd.dir-bi.plate-dl-nosuffix +application/vnd.dm.delegation+xml +application/vnd.dna dna +application/vnd.document+json docjson +application/vnd.dolby.mobile.1 +application/vnd.dolby.mobile.2 +application/vnd.doremir.scorecloud-binary-document scld +application/vnd.dpgraph dpg mwc dpgraph +application/vnd.dreamfactory dfac +application/vnd.drive+json +application/vnd.dtg.local +application/vnd.dtg.local.flash fla +application/vnd.dtg.local.html +application/vnd.dvb.ait ait +# class: application/octet-stream +application/vnd.dvb.dvbj +application/vnd.dvb.esgcontainer +application/vnd.dvb.ipdcdftnotifaccess +application/vnd.dvb.ipdcesgaccess +application/vnd.dvb.ipdcesgaccess2 +application/vnd.dvb.ipdcesgpdd +application/vnd.dvb.ipdcroaming +application/vnd.dvb.iptv.alfec-base +application/vnd.dvb.iptv.alfec-enhancement +application/vnd.dvb.notif-aggregate-root+xml +application/vnd.dvb.notif-container+xml +application/vnd.dvb.notif-generic+xml +application/vnd.dvb.notif-ia-msglist+xml +application/vnd.dvb.notif-ia-registration-request+xml +application/vnd.dvb.notif-ia-registration-response+xml +application/vnd.dvb.notif-init+xml +# pfr: application/font-tdpfr +application/vnd.dvb.pfr +application/vnd.dvb.service svc +# dxr: application/x-director +application/vnd.dxr +application/vnd.dynageo geo +application/vnd.dzr dzr +application/vnd.easykaraoke.cdgdownload +application/vnd.ecdis-update +application/vnd.ecowin.chart mag +application/vnd.ecowin.filerequest +application/vnd.ecowin.fileupdate +application/vnd.ecowin.series +application/vnd.ecowin.seriesrequest +application/vnd.ecowin.seriesupdate +# img: application/octet-stream +application/vnd.efi-img +# iso: application/octet-stream +application/vnd.efi-iso +application/vnd.enliven nml +application/vnd.enphase.envoy +application/vnd.eprints.data+xml +application/vnd.epson.esf esf +application/vnd.epson.msf msf +application/vnd.epson.quickanime qam +application/vnd.epson.salt slt +application/vnd.epson.ssf ssf +application/vnd.ericsson.quickcall qcall qca +application/vnd.espass-espass+zip espass +application/vnd.eszigno3+xml es3 et3 +application/vnd.etsi.aoc+xml +application/vnd.etsi.asic-e+zip asice sce +# scs: application/scvp-cv-response +application/vnd.etsi.asic-s+zip asics +application/vnd.etsi.cug+xml +application/vnd.etsi.iptvcommand+xml +application/vnd.etsi.iptvdiscovery+xml +application/vnd.etsi.iptvprofile+xml +application/vnd.etsi.iptvsad-bc+xml +application/vnd.etsi.iptvsad-cod+xml +application/vnd.etsi.iptvsad-npvr+xml +application/vnd.etsi.iptvservice+xml +application/vnd.etsi.iptvsync+xml +application/vnd.etsi.iptvueprofile+xml +application/vnd.etsi.mcid+xml +application/vnd.etsi.mheg5 +application/vnd.etsi.overload-control-policy-dataset+xml +application/vnd.etsi.pstn+xml +application/vnd.etsi.sci+xml +application/vnd.etsi.simservs+xml +application/vnd.etsi.timestamp-token tst +application/vnd.etsi.tsl.der +application/vnd.etsi.tsl+xml +application/vnd.eudora.data +application/vnd.ezpix-album ez2 +application/vnd.ezpix-package ez3 +application/vnd.f-secure.mobile +application/vnd.fastcopy-disk-image dim +application/vnd.fdf fdf +application/vnd.fdsn.mseed msd mseed +application/vnd.fdsn.seed seed dataless +application/vnd.ffsns +application/vnd.filmit.zfc zfc +# all extensions: application/vnd.hbci +application/vnd.fints +application/vnd.firemonkeys.cloudcell +application/vnd.FloGraphIt gph +application/vnd.fluxtime.clip ftc +application/vnd.font-fontforge-sfd sfd +application/vnd.framemaker fm +application/vnd.frogans.fnc fnc +application/vnd.frogans.ltf ltf +application/vnd.fsc.weblaunch fsc +application/vnd.fujitsu.oasys oas +application/vnd.fujitsu.oasys2 oa2 +application/vnd.fujitsu.oasys3 oa3 +application/vnd.fujitsu.oasysgp fg5 +application/vnd.fujitsu.oasysprs bh2 +application/vnd.fujixerox.ART-EX +application/vnd.fujixerox.ART4 +application/vnd.fujixerox.ddd ddd +application/vnd.fujixerox.docuworks xdw +application/vnd.fujixerox.docuworks.binder xbd +application/vnd.fujixerox.docuworks.container xct +application/vnd.fujixerox.HBPL +application/vnd.fut-misnet +application/vnd.fuzzysheet fzs +application/vnd.genomatix.tuxedo txd +# application/vnd.geo+json obsoleted by application/geo+json +application/vnd.geocube+xml g3 g³ +application/vnd.geogebra.file ggb +application/vnd.geogebra.tool ggt +application/vnd.geometry-explorer gex gre +application/vnd.geonext gxt +application/vnd.geoplan g2w +application/vnd.geospace g3w +# gbr: application/rpki-ghostbusters +application/vnd.gerber +application/vnd.globalplatform.card-content-mgt +application/vnd.globalplatform.card-content-mgt-response +application/vnd.gmx gmx +application/vnd.google-earth.kml+xml kml +application/vnd.google-earth.kmz kmz +application/vnd.gov.sk.e-form+xml +application/vnd.gov.sk.e-form+zip +application/vnd.gov.sk.xmldatacontainer+xml +application/vnd.grafeq gqf gqs +application/vnd.gridmp +application/vnd.groove-account gac +application/vnd.groove-help ghf +application/vnd.groove-identity-message gim +application/vnd.groove-injector grv +application/vnd.groove-tool-message gtm +application/vnd.groove-tool-template tpl +application/vnd.groove-vcard vcg +application/vnd.hal+json +application/vnd.hal+xml hal +application/vnd.HandHeld-Entertainment+xml zmm +application/vnd.hbci hbci hbc kom upa pkd bpd +application/vnd.hc+json +# rep: application/vnd.businessobjects +application/vnd.hcl-bireports +application/vnd.hdt hdt +application/vnd.heroku+json +application/vnd.hhe.lesson-player les +application/vnd.hp-HPGL hpgl +application/vnd.hp-hpid hpi hpid +application/vnd.hp-hps hps +application/vnd.hp-jlyt jlt +application/vnd.hp-PCL pcl +application/vnd.hp-PCLXL +application/vnd.httphone +application/vnd.hydrostatix.sof-data sfd-hdstx +application/vnd.hyperdrive+json +application/vnd.hzn-3d-crossword x3d +application/vnd.ibm.afplinedata +application/vnd.ibm.electronic-media emm +application/vnd.ibm.MiniPay mpy +application/vnd.ibm.modcap list3820 listafp afp pseg3820 +application/vnd.ibm.rights-management irm +application/vnd.ibm.secure-container sc +application/vnd.iccprofile icc icm +application/vnd.ieee.1905 1905.1 +application/vnd.igloader igl +application/vnd.imagemeter.folder+zip imf +application/vnd.imagemeter.image+zip imi +application/vnd.immervision-ivp ivp +application/vnd.immervision-ivu ivu +application/vnd.ims.imsccv1p1 imscc +application/vnd.ims.imsccv1p2 +application/vnd.ims.imsccv1p3 +application/vnd.ims.lis.v2.result+json +application/vnd.ims.lti.v2.toolconsumerprofile+json +application/vnd.ims.lti.v2.toolproxy.id+json +application/vnd.ims.lti.v2.toolproxy+json +application/vnd.ims.lti.v2.toolsettings+json +application/vnd.ims.lti.v2.toolsettings.simple+json +application/vnd.informedcontrol.rms+xml +# application/vnd.informix-visionary obsoleted by application/vnd.visionary +application/vnd.infotech.project +application/vnd.infotech.project+xml +application/vnd.innopath.wamp.notification +application/vnd.insors.igm igm +application/vnd.intercon.formnet xpw xpx +application/vnd.intergeo i2g +application/vnd.intertrust.digibox +application/vnd.intertrust.nncp +application/vnd.intu.qbo qbo +application/vnd.intu.qfx qfx +application/vnd.iptc.g2.catalogitem+xml +application/vnd.iptc.g2.conceptitem+xml +application/vnd.iptc.g2.knowledgeitem+xml +application/vnd.iptc.g2.newsitem+xml +application/vnd.iptc.g2.newsmessage+xml +application/vnd.iptc.g2.packageitem+xml +application/vnd.iptc.g2.planningitem+xml +application/vnd.ipunplugged.rcprofile rcprofile +application/vnd.irepository.package+xml irp +application/vnd.is-xpr xpr +application/vnd.isac.fcs fcs +application/vnd.jam jam +application/vnd.japannet-directory-service +application/vnd.japannet-jpnstore-wakeup +application/vnd.japannet-payment-wakeup +application/vnd.japannet-registration +application/vnd.japannet-registration-wakeup +application/vnd.japannet-setstore-wakeup +application/vnd.japannet-verification +application/vnd.japannet-verification-wakeup +application/vnd.jcp.javame.midlet-rms rms +application/vnd.jisp jisp +application/vnd.joost.joda-archive joda +application/vnd.jsk.isdn-ngn +application/vnd.kahootz ktz ktr +application/vnd.kde.karbon karbon +application/vnd.kde.kchart chrt +application/vnd.kde.kformula kfo +application/vnd.kde.kivio flw +application/vnd.kde.kontour kon +application/vnd.kde.kpresenter kpr kpt +application/vnd.kde.kspread ksp +application/vnd.kde.kword kwd kwt +application/vnd.kenameaapp htke +application/vnd.kidspiration kia +application/vnd.Kinar kne knp sdf +application/vnd.koan skp skd skm skt +application/vnd.kodak-descriptor sse +application/vnd.las.las+json lasjson +application/vnd.las.las+xml lasxml +application/vnd.liberty-request+xml +application/vnd.llamagraphics.life-balance.desktop lbd +application/vnd.llamagraphics.life-balance.exchange+xml lbe +application/vnd.lotus-1-2-3 123 wk4 wk3 wk1 +application/vnd.lotus-approach apr vew +application/vnd.lotus-freelance prz pre +application/vnd.lotus-notes nsf ntf ndl ns4 ns3 ns2 nsh nsg +application/vnd.lotus-organizer or3 or2 org +application/vnd.lotus-screencam scm +application/vnd.lotus-wordpro lwp sam +application/vnd.macports.portpkg portpkg +application/vnd.mapbox-vector-tile mvt +application/vnd.marlin.drm.actiontoken+xml +application/vnd.marlin.drm.conftoken+xml +application/vnd.marlin.drm.license+xml +application/vnd.marlin.drm.mdcf mdc +application/vnd.mason+json +application/vnd.maxmind.maxmind-db mmdb +application/vnd.mcd mcd +application/vnd.medcalcdata mc1 +application/vnd.mediastation.cdkey cdkey +application/vnd.meridian-slingshot +application/vnd.MFER mwf +application/vnd.mfmp mfm +application/vnd.micro+json +application/vnd.micrografx.flo flo +application/vnd.micrografx.igx igx +application/vnd.microsoft.portable-executable +application/vnd.microsoft.windows.thumbnail-cache +application/vnd.miele+json +application/vnd.mif mif +application/vnd.minisoft-hp3000-save +application/vnd.mitsubishi.misty-guard.trustweb +application/vnd.Mobius.DAF daf +application/vnd.Mobius.DIS dis +application/vnd.Mobius.MBK mbk +application/vnd.Mobius.MQY mqy +application/vnd.Mobius.MSL msl +application/vnd.Mobius.PLC plc +application/vnd.Mobius.TXF txf +application/vnd.mophun.application mpn +application/vnd.mophun.certificate mpc +application/vnd.motorola.flexsuite +application/vnd.motorola.flexsuite.adsi +application/vnd.motorola.flexsuite.fis +application/vnd.motorola.flexsuite.gotap +application/vnd.motorola.flexsuite.kmr +application/vnd.motorola.flexsuite.ttc +application/vnd.motorola.flexsuite.wem +application/vnd.motorola.iprm +application/vnd.mozilla.xul+xml xul +application/vnd.ms-3mfdocument 3mf +application/vnd.ms-artgalry cil +application/vnd.ms-asf asf +application/vnd.ms-cab-compressed cab +application/vnd.ms-excel xls xlm xla xlc xlt xlw +application/vnd.ms-excel.template.macroEnabled.12 xltm +application/vnd.ms-excel.addin.macroEnabled.12 xlam +application/vnd.ms-excel.sheet.binary.macroEnabled.12 xlsb +application/vnd.ms-excel.sheet.macroEnabled.12 xlsm +application/vnd.ms-fontobject eot +application/vnd.ms-htmlhelp chm +application/vnd.ms-ims ims +application/vnd.ms-lrm lrm +application/vnd.ms-office.activeX+xml +application/vnd.ms-officetheme thmx +application/vnd.ms-playready.initiator+xml +application/vnd.ms-powerpoint ppt pps pot +application/vnd.ms-powerpoint.addin.macroEnabled.12 ppam +application/vnd.ms-powerpoint.presentation.macroEnabled.12 pptm +application/vnd.ms-powerpoint.slide.macroEnabled.12 sldm +application/vnd.ms-powerpoint.slideshow.macroEnabled.12 ppsm +application/vnd.ms-powerpoint.template.macroEnabled.12 potm +application/vnd.ms-PrintDeviceCapabilities+xml +application/vnd.ms-PrintSchemaTicket+xml +application/vnd.ms-project mpp mpt +application/vnd.ms-tnef tnef tnf +application/vnd.ms-windows.devicepairing +application/vnd.ms-windows.nwprinting.oob +application/vnd.ms-windows.printerpairing +application/vnd.ms-windows.wsd.oob +application/vnd.ms-wmdrm.lic-chlg-req +application/vnd.ms-wmdrm.lic-resp +application/vnd.ms-wmdrm.meter-chlg-req +application/vnd.ms-wmdrm.meter-resp +application/vnd.ms-word.document.macroEnabled.12 docm +application/vnd.ms-word.template.macroEnabled.12 dotm +application/vnd.ms-works wcm wdb wks wps +application/vnd.ms-wpl wpl +application/vnd.ms-xpsdocument xps +application/vnd.msa-disk-image msa +application/vnd.mseq mseq +application/vnd.msign +application/vnd.multiad.creator crtr +application/vnd.multiad.creator.cif cif +application/vnd.music-niff +application/vnd.musician mus +application/vnd.muvee.style msty +application/vnd.mynfc taglet +application/vnd.ncd.control +application/vnd.ncd.reference +application/vnd.nearst.inv+json +application/vnd.nervana entity request bkm kcm +application/vnd.netfpx +# ntf: application/vnd.lotus-notes +application/vnd.nitf nitf +application/vnd.neurolanguage.nlu nlu +application/vnd.nintendo.nitro.rom nds +application/vnd.nintendo.snes.rom sfc smc +application/vnd.noblenet-directory nnd +application/vnd.noblenet-sealer nns +application/vnd.noblenet-web nnw +application/vnd.nokia.catalogs +application/vnd.nokia.conml+wbxml +application/vnd.nokia.conml+xml +application/vnd.nokia.iptv.config+xml +application/vnd.nokia.iSDS-radio-presets +application/vnd.nokia.landmark+wbxml +application/vnd.nokia.landmark+xml +application/vnd.nokia.landmarkcollection+xml +application/vnd.nokia.n-gage.ac+xml ac +application/vnd.nokia.n-gage.data ngdat +application/vnd.nokia.n-gage.symbian.install n-gage +application/vnd.nokia.ncd +application/vnd.nokia.pcd+wbxml +application/vnd.nokia.pcd+xml +application/vnd.nokia.radio-preset rpst +application/vnd.nokia.radio-presets rpss +application/vnd.novadigm.EDM edm +application/vnd.novadigm.EDX edx +application/vnd.novadigm.EXT ext +application/vnd.ntt-local.content-share +application/vnd.ntt-local.file-transfer +application/vnd.ntt-local.ogw_remote-access +application/vnd.ntt-local.sip-ta_remote +application/vnd.ntt-local.sip-ta_tcp_stream +application/vnd.oasis.opendocument.chart odc +application/vnd.oasis.opendocument.chart-template otc +application/vnd.oasis.opendocument.database odb +application/vnd.oasis.opendocument.formula odf +# otf: font/otf +application/vnd.oasis.opendocument.formula-template +application/vnd.oasis.opendocument.graphics odg +application/vnd.oasis.opendocument.graphics-template otg +application/vnd.oasis.opendocument.image odi +application/vnd.oasis.opendocument.image-template oti +application/vnd.oasis.opendocument.presentation odp +application/vnd.oasis.opendocument.presentation-template otp +application/vnd.oasis.opendocument.spreadsheet ods +application/vnd.oasis.opendocument.spreadsheet-template ots +application/vnd.oasis.opendocument.text odt +application/vnd.oasis.opendocument.text-master odm +application/vnd.oasis.opendocument.text-template ott +application/vnd.oasis.opendocument.text-web oth +application/vnd.obn +application/vnd.ocf+cbor +application/vnd.oftn.l10n+json +application/vnd.oipf.contentaccessdownload+xml +application/vnd.oipf.contentaccessstreaming+xml +application/vnd.oipf.cspg-hexbinary +application/vnd.oipf.dae.svg+xml +application/vnd.oipf.dae.xhtml+xml +application/vnd.oipf.mippvcontrolmessage+xml +application/vnd.oipf.pae.gem +application/vnd.oipf.spdiscovery+xml +application/vnd.oipf.spdlist+xml +application/vnd.oipf.ueprofile+xml +application/vnd.olpc-sugar xo +application/vnd.oma.bcast.associated-procedure-parameter+xml +application/vnd.oma.bcast.drm-trigger+xml +application/vnd.oma.bcast.imd+xml +application/vnd.oma.bcast.ltkm +application/vnd.oma.bcast.notification+xml +application/vnd.oma.bcast.provisioningtrigger +application/vnd.oma.bcast.sgboot +application/vnd.oma.bcast.sgdd+xml +application/vnd.oma.bcast.sgdu +application/vnd.oma.bcast.simple-symbol-container +application/vnd.oma.bcast.smartcard-trigger+xml +application/vnd.oma.bcast.sprov+xml +application/vnd.oma.bcast.stkm +application/vnd.oma.cab-address-book+xml +application/vnd.oma.cab-feature-handler+xml +application/vnd.oma.cab-pcc+xml +application/vnd.oma.cab-subs-invite+xml +application/vnd.oma.cab-user-prefs+xml +application/vnd.oma.dcd +application/vnd.oma.dcdc +application/vnd.oma.dd2+xml dd2 +application/vnd.oma.drm.risd+xml +application/vnd.oma.group-usage-list+xml +application/vnd.oma.lwm2m+json +application/vnd.oma.lwm2m+tlv +application/vnd.oma.pal+xml +application/vnd.oma.poc.detailed-progress-report+xml +application/vnd.oma.poc.final-report+xml +application/vnd.oma.poc.groups+xml +application/vnd.oma.poc.invocation-descriptor+xml +application/vnd.oma.poc.optimized-progress-report+xml +application/vnd.oma.push +application/vnd.oma.scidm.messages+xml +application/vnd.oma.xcap-directory+xml +application/vnd.oma-scws-config +application/vnd.oma-scws-http-request +application/vnd.oma-scws-http-response +application/vnd.omads-email+xml +application/vnd.omads-file+xml +application/vnd.omads-folder+xml +application/vnd.omaloc-supl-init +application/vnd.onepager tam +application/vnd.onepagertamp tamp +application/vnd.onepagertamx tamx +application/vnd.onepagertat tat +application/vnd.onepagertatp tatp +application/vnd.onepagertatx tatx +application/vnd.openblox.game+xml obgx +application/vnd.openblox.game-binary obg +application/vnd.openeye.oeb oeb +application/vnd.openofficeorg.extension oxt +application/vnd.openstreetmap.data+xml osm +application/vnd.openxmlformats-officedocument.custom-properties+xml +application/vnd.openxmlformats-officedocument.customXmlProperties+xml +application/vnd.openxmlformats-officedocument.drawing+xml +application/vnd.openxmlformats-officedocument.drawingml.chart+xml +application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml +application/vnd.openxmlformats-officedocument.drawingml.diagramColors+xml +application/vnd.openxmlformats-officedocument.drawingml.diagramData+xml +application/vnd.openxmlformats-officedocument.drawingml.diagramLayout+xml +application/vnd.openxmlformats-officedocument.drawingml.diagramStyle+xml +application/vnd.openxmlformats-officedocument.extended-properties+xml +application/vnd.openxmlformats-officedocument.presentationml.commentAuthors+xml +application/vnd.openxmlformats-officedocument.presentationml.comments+xml +application/vnd.openxmlformats-officedocument.presentationml.handoutMaster+xml +application/vnd.openxmlformats-officedocument.presentationml.notesMaster+xml +application/vnd.openxmlformats-officedocument.presentationml.notesSlide+xml +application/vnd.openxmlformats-officedocument.presentationml.presProps+xml +application/vnd.openxmlformats-officedocument.presentationml.presentation pptx +application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml +application/vnd.openxmlformats-officedocument.presentationml.slide sldx +application/vnd.openxmlformats-officedocument.presentationml.slide+xml +application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml +application/vnd.openxmlformats-officedocument.presentationml.slideMaster+xml +application/vnd.openxmlformats-officedocument.presentationml.slideUpdateInfo+xml +application/vnd.openxmlformats-officedocument.presentationml.slideshow ppsx +application/vnd.openxmlformats-officedocument.presentationml.slideshow.main+xml +application/vnd.openxmlformats-officedocument.presentationml.tableStyles+xml +application/vnd.openxmlformats-officedocument.presentationml.tags+xml +application/vnd.openxmlformats-officedocument.presentationml.template potx +application/vnd.openxmlformats-officedocument.presentationml.template.main+xml +application/vnd.openxmlformats-officedocument.presentationml.viewProps+xml +application/vnd.openxmlformats-officedocument.spreadsheetml.calcChain+xml +application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml +application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml +application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml +application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml +application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml +application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml +application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheRecords+xml +application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml +application/vnd.openxmlformats-officedocument.spreadsheetml.queryTable+xml +application/vnd.openxmlformats-officedocument.spreadsheetml.revisionHeaders+xml +application/vnd.openxmlformats-officedocument.spreadsheetml.revisionLog+xml +application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml +application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx +application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml +application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml +application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml +application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml +application/vnd.openxmlformats-officedocument.spreadsheetml.tableSingleCells+xml +application/vnd.openxmlformats-officedocument.spreadsheetml.template xltx +application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml +application/vnd.openxmlformats-officedocument.spreadsheetml.userNames+xml +application/vnd.openxmlformats-officedocument.spreadsheetml.volatileDependencies+xml +application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml +application/vnd.openxmlformats-officedocument.theme+xml +application/vnd.openxmlformats-officedocument.themeOverride+xml +application/vnd.openxmlformats-officedocument.vmlDrawing +application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml +application/vnd.openxmlformats-officedocument.wordprocessingml.document docx +application/vnd.openxmlformats-officedocument.wordprocessingml.document.glossary+xml +application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml +application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml +application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml +application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml +application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml +application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml +application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml +application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml +application/vnd.openxmlformats-officedocument.wordprocessingml.template dotx +application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml +application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml +application/vnd.openxmlformats-package.core-properties+xml +application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml +application/vnd.openxmlformats-package.relationships+xml +application/vnd.oracle.resource+json +application/vnd.orange.indata +application/vnd.osa.netdeploy ndc +application/vnd.osgeo.mapguide.package mgp +# jar: application/x-java-archive +application/vnd.osgi.bundle +application/vnd.osgi.dp dp +application/vnd.osgi.subsystem esa +application/vnd.otps.ct-kip+xml +application/vnd.oxli.countgraph oxlicg +application/vnd.pagerduty+json +application/vnd.palm prc pdb pqa oprc +application/vnd.panoply plp +application/vnd.paos+xml +application/vnd.pawaafile paw +application/vnd.pcos +application/vnd.pg.format str +application/vnd.pg.osasli ei6 +application/vnd.piaccess.application-license pil +application/vnd.picsel efif +application/vnd.pmi.widget wg +application/vnd.poc.group-advertisement+xml +application/vnd.pocketlearn plf +application/vnd.powerbuilder6 pbd +application/vnd.powerbuilder6-s +application/vnd.powerbuilder7 +application/vnd.powerbuilder7-s +application/vnd.powerbuilder75 +application/vnd.powerbuilder75-s +application/vnd.preminet preminet +application/vnd.previewsystems.box box vbox +application/vnd.proteus.magazine mgz +application/vnd.publishare-delta-tree qps +# pti: image/prs.pti +application/vnd.pvi.ptid1 ptid +application/vnd.pwg-multiplexed +application/vnd.pwg-xhtml-print+xml +application/vnd.qualcomm.brew-app-res bar +application/vnd.quarantainenet +application/vnd.Quark.QuarkXPress qxd qxt qwd qwt qxl qxb +application/vnd.quobject-quoxdocument quox quiz +application/vnd.radisys.moml+xml +application/vnd.radisys.msml-audit-conf+xml +application/vnd.radisys.msml-audit-conn+xml +application/vnd.radisys.msml-audit-dialog+xml +application/vnd.radisys.msml-audit-stream+xml +application/vnd.radisys.msml-audit+xml +application/vnd.radisys.msml-conf+xml +application/vnd.radisys.msml-dialog-base+xml +application/vnd.radisys.msml-dialog-fax-detect+xml +application/vnd.radisys.msml-dialog-fax-sendrecv+xml +application/vnd.radisys.msml-dialog-group+xml +application/vnd.radisys.msml-dialog-speech+xml +application/vnd.radisys.msml-dialog-transform+xml +application/vnd.radisys.msml-dialog+xml +application/vnd.radisys.msml+xml +application/vnd.rainstor.data tree +application/vnd.rapid +application/vnd.rar rar +application/vnd.realvnc.bed bed +application/vnd.recordare.musicxml mxl +application/vnd.recordare.musicxml+xml +application/vnd.RenLearn.rlprint +application/vnd.rig.cryptonote cryptonote +application/vnd.route66.link66+xml link66 +# gbr: application/rpki-ghostbusters +application/vnd.rs-274x +application/vnd.ruckus.download +application/vnd.s3sms +application/vnd.sailingtracker.track st +application/vnd.sbm.cid +application/vnd.sbm.mid2 +application/vnd.scribus scd sla slaz +application/vnd.sealed.3df s3df +application/vnd.sealed.csf scsf +application/vnd.sealed.doc sdoc sdo s1w +application/vnd.sealed.eml seml sem +application/vnd.sealed.mht smht smh +application/vnd.sealed.net +# spp: application/scvp-vp-response +application/vnd.sealed.ppt sppt s1p +application/vnd.sealed.tiff stif +application/vnd.sealed.xls sxls sxl s1e +# stm: audio/x-stm +application/vnd.sealedmedia.softseal.html stml s1h +application/vnd.sealedmedia.softseal.pdf spdf spd s1a +application/vnd.seemail see +application/vnd.sema sema +application/vnd.semd semd +application/vnd.semf semf +application/vnd.shana.informed.formdata ifm +application/vnd.shana.informed.formtemplate itp +application/vnd.shana.informed.interchange iif +application/vnd.shana.informed.package ipk +application/vnd.SimTech-MindMapper twd twds +application/vnd.siren+json +application/vnd.smaf mmf +application/vnd.smart.notebook notebook +application/vnd.smart.teacher teacher +application/vnd.software602.filler.form+xml fo +application/vnd.software602.filler.form-xml-zip zfo +application/vnd.solent.sdkm+xml sdkm sdkd +application/vnd.spotfire.dxp dxp +application/vnd.spotfire.sfs sfs +application/vnd.sss-cod +application/vnd.sss-dtf +application/vnd.sss-ntf +application/vnd.stepmania.package smzip +application/vnd.stepmania.stepchart sm +application/vnd.street-stream +application/vnd.sun.wadl+xml wadl +application/vnd.sus-calendar sus susp +application/vnd.svd +application/vnd.swiftview-ics +application/vnd.syncml+xml xsm +application/vnd.syncml.dm+wbxml bdm +application/vnd.syncml.dm+xml xdm +application/vnd.syncml.dm.notification +application/vnd.syncml.dmddf+wbxml +application/vnd.syncml.dmddf+xml ddf +application/vnd.syncml.dmtnds+wbxml +application/vnd.syncml.dmtnds+xml +application/vnd.syncml.ds.notification +application/vnd.tableschema+json +application/vnd.tao.intent-module-archive tao +application/vnd.tcpdump.pcap pcap cap dmp +application/vnd.theqvd qvd +application/vnd.tmd.mediaflex.api+xml +application/vnd.tml vfr viaframe +application/vnd.tmobile-livetv tmo +application/vnd.tri.onesource +application/vnd.trid.tpt tpt +application/vnd.triscape.mxs mxs +application/vnd.trueapp tra +application/vnd.truedoc +# cab: application/vnd.ms-cab-compressed +application/vnd.ubisoft.webplayer +application/vnd.ufdl ufdl ufd frm +application/vnd.uiq.theme utz +application/vnd.umajin umj +application/vnd.unity unityweb +application/vnd.uoml+xml uoml uo +application/vnd.uplanet.alert +application/vnd.uplanet.alert-wbxml +application/vnd.uplanet.bearer-choice +application/vnd.uplanet.bearer-choice-wbxml +application/vnd.uplanet.cacheop +application/vnd.uplanet.cacheop-wbxml +application/vnd.uplanet.channel +application/vnd.uplanet.channel-wbxml +application/vnd.uplanet.list +application/vnd.uplanet.list-wbxml +application/vnd.uplanet.listcmd +application/vnd.uplanet.listcmd-wbxml +application/vnd.uplanet.signal +application/vnd.uri-map urim urimap +application/vnd.valve.source.material vmt +application/vnd.vcx vcx +# sxi: application/vnd.sun.xml.impress +application/vnd.vd-study mxi study-inter model-inter +# mcd: application/vnd.mcd +application/vnd.vectorworks vwx +application/vnd.vel+json +application/vnd.verimatrix.vcas +application/vnd.vidsoft.vidconference vsc +application/vnd.visio vsd vst vsw vss +application/vnd.visionary vis +# vsc: application/vnd.vidsoft.vidconference +application/vnd.vividence.scriptfile +application/vnd.vsf vsf +application/vnd.wap.sic sic +application/vnd.wap.slc slc +application/vnd.wap.wbxml wbxml +application/vnd.wap.wmlc wmlc +application/vnd.wap.wmlscriptc wmlsc +application/vnd.webturbo wtb +application/vnd.wfa.p2p p2p +application/vnd.wfa.wsc wsc +application/vnd.windows.devicepairing +application/vnd.wmc wmc +application/vnd.wmf.bootstrap +# nb: application/mathematica for now +application/vnd.wolfram.mathematica +application/vnd.wolfram.mathematica.package m +application/vnd.wolfram.player nbp +application/vnd.wordperfect wpd +application/vnd.wqd wqd +application/vnd.wrq-hp3000-labelled +application/vnd.wt.stf stf +application/vnd.wv.csp+xml +application/vnd.wv.csp+wbxml wv +application/vnd.wv.ssp+xml +application/vnd.xacml+json +application/vnd.xara xar +application/vnd.xfdl xfdl xfd +application/vnd.xfdl.webform +application/vnd.xmi+xml +application/vnd.xmpie.cpkg cpkg +application/vnd.xmpie.dpkg dpkg +# dpkg: application/vnd.xmpie.dpkg +application/vnd.xmpie.plan +application/vnd.xmpie.ppkg ppkg +application/vnd.xmpie.xlim xlim +application/vnd.yamaha.hv-dic hvd +application/vnd.yamaha.hv-script hvs +application/vnd.yamaha.hv-voice hvp +application/vnd.yamaha.openscoreformat osf +application/vnd.yamaha.openscoreformat.osfpvg+xml +application/vnd.yamaha.remote-setup +application/vnd.yamaha.smaf-audio saf +application/vnd.yamaha.smaf-phrase spf +application/vnd.yamaha.through-ngn +application/vnd.yamaha.tunnel-udpencap +application/vnd.yaoweme yme +application/vnd.yellowriver-custom-menu cmp +application/vnd.zul zir zirz +application/vnd.zzazz.deck+xml zaz +application/voicexml+xml vxml +application/vq-rtcp-xr +application/watcherinfo+xml wif +application/whoispp-query +application/whoispp-response +application/widget wgt +application/wita +application/wordperfect5.1 +application/wsdl+xml wsdl +application/wspolicy+xml wspolicy +# yes, this *is* IANA registered despite of x- +application/x-www-form-urlencoded +application/x400-bp +application/xacml+xml +application/xcap-att+xml xav +application/xcap-caps+xml xca +application/xcap-diff+xml xdf +application/xcap-el+xml xel +application/xcap-error+xml xer +application/xcap-ns+xml xns +application/xcon-conference-info-diff+xml +application/xcon-conference-info+xml +application/xenc+xml +application/xhtml+xml xhtml xhtm xht +# xml, xsd, rng: text/xml +application/xml +# mod: audio/x-mod +application/xml-dtd dtd +# ent: text/xml-external-parsed-entity +application/xml-external-parsed-entity +application/xml-patch+xml +application/xmpp+xml +application/xop+xml xop +application/xslt+xml xsl xslt +application/xv+xml mxml xhvml xvml xvm +application/yang yang +application/yang-data+json +application/yang-data+xml +application/yang-patch+json +application/yang-patch+xml +application/yin+xml yin +application/zip zip +application/zlib +audio/1d-interleaved-parityfec +audio/32kadpcm 726 +# 3gp, 3gpp: video/3gpp +audio/3gpp +# 3g2, 3gpp2: video/3gpp2 +audio/3gpp2 +audio/ac3 ac3 +audio/AMR amr +audio/AMR-WB awb +audio/amr-wb+ +audio/aptx +audio/asc acn +# aa3, omg: audio/ATRAC3 +audio/ATRAC-ADVANCED-LOSSLESS aal +# aa3, omg: audio/ATRAC3 +audio/ATRAC-X atx +audio/ATRAC3 at3 aa3 omg +audio/basic au snd +audio/BV16 +audio/BV32 +audio/clearmode +audio/CN +audio/DAT12 +audio/dls dls +audio/dsr-es201108 +audio/dsr-es202050 +audio/dsr-es202211 +audio/dsr-es202212 +audio/DV +audio/DVI4 +audio/eac3 +audio/encaprtp +audio/EVRC evc +# qcp: audio/qcelp +audio/EVRC-QCP +audio/EVRC0 +audio/EVRC1 +audio/EVRCB evb +audio/EVRCB0 +audio/EVRCB1 +audio/EVRCNW enw +audio/EVRCNW0 +audio/EVRCNW1 +audio/EVRCWB evw +audio/EVRCWB0 +audio/EVRCWB1 +audio/EVS +audio/example +audio/fwdred +audio/G711-0 +audio/G719 +audio/G722 +audio/G7221 +audio/G723 +audio/G726-16 +audio/G726-24 +audio/G726-32 +audio/G726-40 +audio/G728 +audio/G729 +audio/G7291 +audio/G729D +audio/G729E +audio/GSM +audio/GSM-EFR +audio/GSM-HR-08 +audio/iLBC lbc +audio/ip-mr_v2.5 +# wav: audio/x-wav +audio/L16 l16 +audio/L20 +audio/L24 +audio/L8 +audio/LPC +audio/MELP +audio/MELP600 +audio/MELP1200 +audio/MELP2400 +audio/mobile-xmf mxmf +# mp4, mpg4: video/mp4, see RFC 4337 +audio/mp4 m4a +audio/MP4A-LATM +audio/MPA +audio/mpa-robust +audio/mpeg mp3 mpga mp1 mp2 +audio/mpeg4-generic +audio/ogg oga ogg opus spx +audio/opus +audio/parityfec +audio/PCMA +audio/PCMA-WB +audio/PCMU +audio/PCMU-WB +audio/prs.sid sid psid +audio/qcelp qcp +audio/raptorfec +audio/RED +audio/rtp-enc-aescm128 +audio/rtp-midi +audio/rtploopback +audio/rtx +audio/SMV smv +# qcp: audio/qcelp, see RFC 3625 +audio/SMV-QCP +audio/SMV0 +# mid: audio/midi +audio/sp-midi +audio/speex +audio/t140c +audio/t38 +audio/telephone-event +audio/tone +audio/UEMCLIP +audio/ulpfec +audio/VDVI +audio/VMR-WB +audio/vnd.3gpp.iufp +audio/vnd.4SB +audio/vnd.audikoz koz +audio/vnd.CELP +audio/vnd.cisco.nse +audio/vnd.cmles.radio-events +audio/vnd.cns.anp1 +audio/vnd.cns.inf1 +audio/vnd.dece.audio uva uvva +audio/vnd.digital-winds eol +audio/vnd.dlna.adts +audio/vnd.dolby.heaac.1 +audio/vnd.dolby.heaac.2 +audio/vnd.dolby.mlp mlp +audio/vnd.dolby.mps +audio/vnd.dolby.pl2 +audio/vnd.dolby.pl2x +audio/vnd.dolby.pl2z +audio/vnd.dolby.pulse.1 +audio/vnd.dra +# wav: audio/x-wav, cpt: application/mac-compactpro +audio/vnd.dts dts +audio/vnd.dts.hd dtshd +# dvb: video/vnd.dvb.file +audio/vnd.dvb.file +audio/vnd.everad.plj plj +# rm: audio/x-pn-realaudio +audio/vnd.hns.audio +audio/vnd.lucent.voice lvp +audio/vnd.ms-playready.media.pya pya +# mxmf: audio/mobile-xmf +audio/vnd.nokia.mobile-xmf +audio/vnd.nortel.vbk vbk +audio/vnd.nuera.ecelp4800 ecelp4800 +audio/vnd.nuera.ecelp7470 ecelp7470 +audio/vnd.nuera.ecelp9600 ecelp9600 +audio/vnd.octel.sbc +# audio/vnd.qcelp deprecated in favour of audio/qcelp +audio/vnd.rhetorex.32kadpcm +audio/vnd.rip rip +audio/vnd.sealedmedia.softseal.mpeg smp3 smp s1m +audio/vnd.vmx.cvsd +audio/vorbis +audio/vorbis-config +font/collection ttc +font/otf otf +font/sfnt +font/ttf ttf +font/woff woff +font/woff2 woff2 +image/bmp bmp dib +image/cgm cgm +image/dicom-rle drle +image/emf emf +image/example +image/fits fits fit fts +image/g3fax +image/gif gif +image/ief ief +image/jls jls +image/jp2 jp2 jpg2 +image/jpeg jpg jpeg jpe jfif +image/jpm jpm jpgm +image/jpx jpx jpf +image/ktx ktx +image/naplps +image/png png +image/prs.btif btif btf +image/prs.pti pti +image/pwg-raster +image/svg+xml svg svgz +image/t38 t38 +image/tiff tiff tif +image/tiff-fx tfx +image/vnd.adobe.photoshop psd +image/vnd.airzip.accelerator.azv azv +image/vnd.cns.inf2 +image/vnd.dece.graphic uvi uvvi uvg uvvg +image/vnd.djvu djvu djv +# sub: text/vnd.dvb.subtitle +image/vnd.dvb.subtitle +image/vnd.dwg dwg +image/vnd.dxf dxf +image/vnd.fastbidsheet fbs +image/vnd.fpx fpx +image/vnd.fst fst +image/vnd.fujixerox.edmics-mmr mmr +image/vnd.fujixerox.edmics-rlc rlc +image/vnd.globalgraphics.pgb pgb +image/vnd.microsoft.icon ico +image/vnd.mix +image/vnd.mozilla.apng apng +image/vnd.ms-modi mdi +image/vnd.net-fpx +image/vnd.radiance hdr rgbe xyze +image/vnd.sealed.png spng spn s1n +image/vnd.sealedmedia.softseal.gif sgif sgi s1g +image/vnd.sealedmedia.softseal.jpg sjpg sjp s1j +image/vnd.svf +image/vnd.tencent.tap tap +image/vnd.valve.source.texture vtf +image/vnd.wap.wbmp wbmp +image/vnd.xiff xif +image/vnd.zbrush.pcx pcx +image/wmf wmf +message/CPIM +message/delivery-status +message/disposition-notification +message/example +message/external-body +message/feedback-report +message/global u8msg +message/global-delivery-status u8dsn +message/global-disposition-notification u8mdn +message/global-headers u8hdr +message/http +# cl: application/simple-filter+xml +message/imdn+xml +# message/news obsoleted by message/rfc822 +message/partial +message/rfc822 eml mail art +message/s-http +message/sip +message/sipfrag +message/tracking-status +message/vnd.si.simp +# wsc: application/vnd.wfa.wsc +message/vnd.wfa.wsc +model/example +model/gltf+json gltf +model/iges igs iges +model/mesh msh mesh silo +model/vnd.collada+xml dae +model/vnd.dwf dwf +# 3dml, 3dm: text/vnd.in3d.3dml +model/vnd.flatland.3dml +model/vnd.gdl gdl gsm win dor lmp rsm msm ism +model/vnd.gs-gdl +model/vnd.gtw gtw +model/vnd.moml+xml moml +model/vnd.mts mts +model/vnd.opengex ogex +model/vnd.parasolid.transmit.binary x_b xmt_bin +model/vnd.parasolid.transmit.text x_t xmt_txt +model/vnd.rosette.annotated-data-model +model/vnd.valve.source.compiled-map bsp +model/vnd.vtu vtu +model/vrml wrl vrml +# x3db: model/x3d+xml +model/x3d+fastinfoset +# x3d: application/vnd.hzn-3d-crossword +model/x3d+xml x3db +model/x3d-vrml x3dv x3dvz +multipart/alternative +multipart/appledouble +multipart/byteranges +multipart/digest +multipart/encrypted +multipart/form-data +multipart/header-set +multipart/mixed +multipart/parallel +multipart/related +multipart/report +multipart/signed +multipart/vnd.bint.med-plus bmed +multipart/voice-message vpm +multipart/x-mixed-replace +text/1d-interleaved-parityfec +text/cache-manifest appcache manifest +text/calendar ics ifb +text/css css +text/csv csv +text/csv-schema csvs +text/directory +text/dns soa zone +text/encaprtp +# text/ecmascript obsoleted by application/ecmascript +text/enriched +text/example +text/fwdred +text/grammar-ref-list +text/html html htm +# text/javascript obsoleted by application/javascript +text/jcr-cnd cnd +text/markdown markdown md +text/mizar miz +text/n3 n3 +text/parameters +text/parityfec +text/plain txt asc text pm el c h cc hh cxx hxx f90 conf log +text/provenance-notation provn +text/prs.fallenstein.rst rst +text/prs.lines.tag tag dsc +text/prs.prop.logic +text/raptorfec +text/RED +text/rfc822-headers +text/richtext rtx +# rtf: application/rtf +text/rtf +text/rtp-enc-aescm128 +text/rtploopback +text/rtx +text/sgml sgml sgm +text/strings +text/t140 +text/tab-separated-values tsv +text/troff t tr roff +text/turtle ttl +text/ulpfec +text/uri-list uris uri +text/vcard vcf vcard +text/vnd.a a +text/vnd.abc abc +text/vnd.ascii-art ascii +# curl: application/vnd.curl +text/vnd.curl +text/vnd.debian.copyright copyright +text/vnd.DMClientScript dms +text/vnd.dvb.subtitle sub +text/vnd.esmertec.theme-descriptor jtd +text/vnd.fly fly +text/vnd.fmi.flexstor flx +text/vnd.graphviz gv dot +text/vnd.in3d.3dml 3dml 3dm +text/vnd.in3d.spot spot spo +text/vnd.IPTC.NewsML +text/vnd.IPTC.NITF +text/vnd.latex-z +text/vnd.motorola.reflex +text/vnd.ms-mediapackage mpf +text/vnd.net2phone.commcenter.command ccc +text/vnd.radisys.msml-basic-layout +text/vnd.si.uricatalogue uric +text/vnd.sun.j2me.app-descriptor jad +text/vnd.trolltech.linguist ts +text/vnd.wap.si si +text/vnd.wap.sl sl +text/vnd.wap.wml wml +text/vnd.wap.wmlscript wmls +text/xml xml xsd rng +text/xml-external-parsed-entity ent +video/1d-interleaved-parityfec +video/3gpp 3gp 3gpp +video/3gpp2 3g2 3gpp2 +video/3gpp-tt +video/BMPEG +video/BT656 +video/CelB +video/DV +video/encaprtp +video/example +video/H261 +video/H263 +video/H263-1998 +video/H263-2000 +video/H264 +video/H264-RCDO +video/H264-SVC +video/H265 +video/iso.segment m4s +video/JPEG +video/jpeg2000 +video/mj2 mj2 mjp2 +video/MP1S +video/MP2P +video/MP2T +video/mp4 mp4 mpg4 m4v +video/MP4V-ES +video/mpeg mpeg mpg mpe m1v m2v +video/mpeg4-generic +video/MPV +video/nv +video/ogg ogv +video/parityfec +video/pointer +video/quicktime mov qt +video/raptorfec +video/raw +video/rtp-enc-aescm128 +video/rtploopback +video/rtx +video/SMPTE292M +video/ulpfec +video/vc1 +video/vnd.CCTV +video/vnd.dece.hd uvh uvvh +video/vnd.dece.mobile uvm uvvm +video/vnd.dece.mp4 uvu uvvu +video/vnd.dece.pd uvp uvvp +video/vnd.dece.sd uvs uvvs +video/vnd.dece.video uvv uvvv +video/vnd.directv.mpeg +video/vnd.directv.mpeg-tts +video/vnd.dlna.mpeg-tts +video/vnd.dvb.file dvb +video/vnd.fvt fvt +# rm: audio/x-pn-realaudio +video/vnd.hns.video +video/vnd.iptvforum.1dparityfec-1010 +video/vnd.iptvforum.1dparityfec-2005 +video/vnd.iptvforum.2dparityfec-1010 +video/vnd.iptvforum.2dparityfec-2005 +video/vnd.iptvforum.ttsavc +video/vnd.iptvforum.ttsmpeg2 +video/vnd.motorola.video +video/vnd.motorola.videop +video/vnd.mpegurl mxu m4u +video/vnd.ms-playready.media.pyv pyv +video/vnd.nokia.interleaved-multimedia nim +video/vnd.nokia.videovoip +# mp4: video/mp4 +video/vnd.objectvideo +video/vnd.radgamettools.bink bik bk2 +video/vnd.radgamettools.smacker smk +video/vnd.sealed.mpeg1 smpg s11 +# smpg: video/vnd.sealed.mpeg1 +video/vnd.sealed.mpeg4 s14 +video/vnd.sealed.swf sswf ssw +video/vnd.sealedmedia.softseal.mov smov smo s1q +# uvu, uvvu: video/vnd.dece.mp4 +video/vnd.uvvu.mp4 +video/vnd.vivo viv +video/VP8 + +# Non-IANA types + +application/mac-compactpro cpt +application/metalink+xml metalink +application/owl+xml owx +application/rss+xml rss +application/vnd.android.package-archive apk +application/vnd.oma.dd+xml dd +application/vnd.oma.drm.content dcf +# odf: application/vnd.oasis.opendocument.formula +application/vnd.oma.drm.dcf o4a o4v +application/vnd.oma.drm.message dm +application/vnd.oma.drm.rights+wbxml drc +application/vnd.oma.drm.rights+xml dr +application/vnd.sun.xml.calc sxc +application/vnd.sun.xml.calc.template stc +application/vnd.sun.xml.draw sxd +application/vnd.sun.xml.draw.template std +application/vnd.sun.xml.impress sxi +application/vnd.sun.xml.impress.template sti +application/vnd.sun.xml.math sxm +application/vnd.sun.xml.writer sxw +application/vnd.sun.xml.writer.global sxg +application/vnd.sun.xml.writer.template stw +application/vnd.symbian.install sis +application/vnd.wap.mms-message mms +application/x-annodex anx +application/x-bcpio bcpio +application/x-bittorrent torrent +application/x-bzip2 bz2 +application/x-cdlink vcd +application/x-chrome-extension crx +application/x-cpio cpio +application/x-csh csh +application/x-director dcr dir dxr +application/x-dvi dvi +application/x-futuresplash spl +application/x-gtar gtar +application/x-hdf hdf +application/x-java-archive jar +application/x-java-jnlp-file jnlp +application/x-java-pack200 pack +application/x-killustrator kil +application/x-latex latex +application/x-netcdf nc cdf +application/x-perl pl +application/x-rpm rpm +application/x-sh sh +application/x-shar shar +application/x-stuffit sit +application/x-sv4cpio sv4cpio +application/x-sv4crc sv4crc +application/x-tar tar +application/x-tcl tcl +application/x-tex tex +application/x-texinfo texinfo texi +application/x-troff-man man 1 2 3 4 5 6 7 8 +application/x-troff-me me +application/x-troff-ms ms +application/x-ustar ustar +application/x-wais-source src +application/x-xpinstall xpi +application/x-xspf+xml xspf +application/x-xz xz +audio/midi mid midi kar +audio/x-aiff aif aiff aifc +audio/x-annodex axa +audio/x-flac flac +audio/x-matroska mka +audio/x-mod mod ult uni m15 mtm 669 med +audio/x-mpegurl m3u +audio/x-ms-wax wax +audio/x-ms-wma wma +audio/x-pn-realaudio ram rm +audio/x-realaudio ra +audio/x-s3m s3m +audio/x-stm stm +audio/x-wav wav +chemical/x-xyz xyz +image/webp webp +image/x-cmu-raster ras +image/x-portable-anymap pnm +image/x-portable-bitmap pbm +image/x-portable-graymap pgm +image/x-portable-pixmap ppm +image/x-rgb rgb +image/x-targa tga +image/x-xbitmap xbm +image/x-xpixmap xpm +image/x-xwindowdump xwd +text/html-sandboxed sandboxed +text/x-pod pod +text/x-setext etx +video/webm webm +video/x-annodex axv +video/x-flv flv +video/x-javafx fxm +video/x-matroska mkv +video/x-matroska-3d mk3d +video/x-ms-asf asx +video/x-ms-wm wm +video/x-ms-wmv wmv +video/x-ms-wmx wmx +video/x-ms-wvx wvx +video/x-msvideo avi +video/x-sgi-movie movie +x-conference/x-cooltalk ice +x-epoc/x-sisx-app sisx diff --git a/cmd/swarm/run_test.go b/cmd/swarm/run_test.go index ed15028685..4a6a56d9b8 100644 --- a/cmd/swarm/run_test.go +++ b/cmd/swarm/run_test.go @@ -1,4 +1,4 @@ -// Copyright 2016 The go-ethereum Authors +// Copyright 2017 The go-ethereum Authors // This file is part of go-ethereum. // // go-ethereum is free software: you can redistribute it and/or modify @@ -17,12 +17,18 @@ package main import ( + "context" + "crypto/ecdsa" + "flag" "fmt" "io/ioutil" "net" "os" + "path" "path/filepath" "runtime" + "sync" + "syscall" "testing" "time" @@ -34,8 +40,12 @@ import ( "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/swarm" + "github.com/ethereum/go-ethereum/swarm/api" + swarmhttp "github.com/ethereum/go-ethereum/swarm/api/http" ) +var loglevel = flag.Int("loglevel", 3, "verbosity of logs") + func init() { // Run the app if we've been exec'd as "swarm-test" in runSwarm. reexec.Register("swarm-test", func() { @@ -47,6 +57,20 @@ 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, "") +} func TestMain(m *testing.M) { // check if we have been reexec'd if reexec.Init() { @@ -81,6 +105,7 @@ type testCluster struct { // // When starting more than one node, they are connected together using the // admin SetPeer RPC method. + func newTestCluster(t *testing.T, size int) *testCluster { cluster := &testCluster{} defer func() { @@ -96,18 +121,7 @@ func newTestCluster(t *testing.T, size int) *testCluster { cluster.TmpDir = tmpdir // start the nodes - cluster.Nodes = make([]*testNode, 0, size) - for i := 0; i < size; i++ { - dir := filepath.Join(cluster.TmpDir, fmt.Sprintf("swarm%02d", i)) - if err := os.Mkdir(dir, 0700); err != nil { - t.Fatal(err) - } - - node := newTestNode(t, dir) - node.Name = fmt.Sprintf("swarm%02d", i) - - cluster.Nodes = append(cluster.Nodes, node) - } + cluster.StartNewNodes(t, size) if size == 1 { return cluster @@ -145,14 +159,52 @@ func (c *testCluster) Shutdown() { os.RemoveAll(c.TmpDir) } +func (c *testCluster) Stop() { + for _, node := range c.Nodes { + node.Shutdown() + } +} + +func (c *testCluster) StartNewNodes(t *testing.T, size int) { + c.Nodes = make([]*testNode, 0, size) + for i := 0; i < size; i++ { + dir := filepath.Join(c.TmpDir, fmt.Sprintf("swarm%02d", i)) + if err := os.Mkdir(dir, 0700); err != nil { + t.Fatal(err) + } + + node := newTestNode(t, dir) + node.Name = fmt.Sprintf("swarm%02d", i) + + c.Nodes = append(c.Nodes, node) + } +} + +func (c *testCluster) StartExistingNodes(t *testing.T, size int, bzzaccount string) { + c.Nodes = make([]*testNode, 0, size) + for i := 0; i < size; i++ { + dir := filepath.Join(c.TmpDir, fmt.Sprintf("swarm%02d", i)) + node := existingTestNode(t, dir, bzzaccount) + node.Name = fmt.Sprintf("swarm%02d", i) + + c.Nodes = append(c.Nodes, node) + } +} + +func (c *testCluster) Cleanup() { + os.RemoveAll(c.TmpDir) +} + type testNode struct { - Name string - Addr string - URL string - Enode string - Dir string - Client *rpc.Client - Cmd *cmdtest.TestCmd + Name string + Addr string + URL string + Enode string + Dir string + IpcPath string + PrivateKey *ecdsa.PrivateKey + Client *rpc.Client + Cmd *cmdtest.TestCmd } const testPassphrase = "swarm-test-passphrase" @@ -181,32 +233,34 @@ func getTestAccount(t *testing.T, dir string) (conf *node.Config, account accoun return conf, account } -func newTestNode(t *testing.T, dir string) *testNode { - - conf, account := getTestAccount(t, dir) +func existingTestNode(t *testing.T, dir string, bzzaccount string) *testNode { + conf, _ := getTestAccount(t, dir) node := &testNode{Dir: dir} + // use a unique IPCPath when running tests on Windows + if runtime.GOOS == "windows" { + conf.IPCPath = fmt.Sprintf("bzzd-%s.ipc", bzzaccount) + } + // assign ports - httpPort, err := assignTCPPort() - if err != nil { - t.Fatal(err) - } - p2pPort, err := assignTCPPort() + ports, err := getAvailableTCPPorts(2) if err != nil { t.Fatal(err) } + p2pPort := ports[0] + httpPort := ports[1] // start the node node.Cmd = runSwarm(t, "--port", p2pPort, - "--nodiscover", + "--nat", "extip:127.0.0.1", "--datadir", dir, "--ipcpath", conf.IPCPath, "--ens-api", "", - "--bzzaccount", account.Address.String(), + "--bzzaccount", bzzaccount, "--bzznetworkid", "321", "--bzzport", httpPort, - "--verbosity", "6", + "--verbosity", fmt.Sprint(*loglevel), ) node.Cmd.InputLine(testPassphrase) defer func() { @@ -215,6 +269,17 @@ func newTestNode(t *testing.T, dir string) *testNode { } }() + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + // ensure that all ports have active listeners + // so that the next node will not get the same + // when calling getAvailableTCPPorts + err = waitTCPPorts(ctx, ports...) + if err != nil { + t.Fatal(err) + } + // wait for the node to start for start := time.Now(); time.Since(start) < 10*time.Second; time.Sleep(50 * time.Millisecond) { node.Client, err = rpc.Dial(conf.IPCEndpoint()) @@ -238,8 +303,83 @@ func newTestNode(t *testing.T, dir string) *testNode { if err := node.Client.Call(&nodeInfo, "admin_nodeInfo"); err != nil { t.Fatal(err) } - node.Enode = fmt.Sprintf("enode://%s@127.0.0.1:%s", nodeInfo.ID, p2pPort) + node.Enode = nodeInfo.Enode + node.IpcPath = conf.IPCPath + return node +} +func newTestNode(t *testing.T, dir string) *testNode { + + conf, account := getTestAccount(t, dir) + ks := keystore.NewKeyStore(path.Join(dir, "keystore"), 1<<18, 1) + + pk := decryptStoreAccount(ks, account.Address.Hex(), []string{testPassphrase}) + + node := &testNode{Dir: dir, PrivateKey: pk} + + // assign ports + ports, err := getAvailableTCPPorts(2) + if err != nil { + t.Fatal(err) + } + p2pPort := ports[0] + httpPort := ports[1] + + // start the node + node.Cmd = runSwarm(t, + "--port", p2pPort, + "--nat", "extip:127.0.0.1", + "--datadir", dir, + "--ipcpath", conf.IPCPath, + "--ens-api", "", + "--bzzaccount", account.Address.String(), + "--bzznetworkid", "321", + "--bzzport", httpPort, + "--verbosity", fmt.Sprint(*loglevel), + ) + node.Cmd.InputLine(testPassphrase) + defer func() { + if t.Failed() { + node.Shutdown() + } + }() + + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + // ensure that all ports have active listeners + // so that the next node will not get the same + // when calling getAvailableTCPPorts + err = waitTCPPorts(ctx, ports...) + if err != nil { + t.Fatal(err) + } + + // wait for the node to start + for start := time.Now(); time.Since(start) < 10*time.Second; time.Sleep(50 * time.Millisecond) { + node.Client, err = rpc.Dial(conf.IPCEndpoint()) + if err == nil { + break + } + } + if node.Client == nil { + t.Fatal(err) + } + + // load info + var info swarm.Info + if err := node.Client.Call(&info, "bzz_info"); err != nil { + t.Fatal(err) + } + node.Addr = net.JoinHostPort("127.0.0.1", info.Port) + node.URL = "http://" + node.Addr + + var nodeInfo p2p.NodeInfo + if err := node.Client.Call(&nodeInfo, "admin_nodeInfo"); err != nil { + t.Fatal(err) + } + node.Enode = nodeInfo.Enode + node.IpcPath = conf.IPCPath return node } @@ -249,15 +389,92 @@ func (n *testNode) Shutdown() { } } -func assignTCPPort() (string, error) { - l, err := net.Listen("tcp", "127.0.0.1:0") - if err != nil { - return "", err +// getAvailableTCPPorts returns a set of ports that +// nothing is listening on at the time. +// +// Function assignTCPPort cannot be called in sequence +// and guardantee that the same port will be returned in +// different calls as the listener is closed within the function, +// not after all listeners are started and selected unique +// available ports. +func getAvailableTCPPorts(count int) (ports []string, err error) { + for i := 0; i < count; i++ { + l, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + return nil, err + } + // defer close in the loop to be sure the same port will not + // be selected in the next iteration + defer l.Close() + + _, port, err := net.SplitHostPort(l.Addr().String()) + if err != nil { + return nil, err + } + ports = append(ports, port) + } + return ports, nil +} + +// waitTCPPorts blocks until tcp connections can be +// established on all provided ports. It runs all +// ports dialers in parallel, and returns the first +// encountered error. +// See waitTCPPort also. +func waitTCPPorts(ctx context.Context, ports ...string) error { + var err error + // mu locks err variable that is assigned in + // other goroutines + var mu sync.Mutex + + // cancel is canceling all goroutines + // when the firs error is returned + // to prevent unnecessary waiting + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + var wg sync.WaitGroup + for _, port := range ports { + wg.Add(1) + go func(port string) { + defer wg.Done() + + e := waitTCPPort(ctx, port) + + mu.Lock() + defer mu.Unlock() + if e != nil && err == nil { + err = e + cancel() + } + }(port) + } + wg.Wait() + + return err +} + +// waitTCPPort blocks until tcp connection can be established +// ona provided port. It has a 3 minute timeout as maximum, +// to prevent long waiting, but it can be shortened with +// a provided context instance. Dialer has a 10 second timeout +// in every iteration, and connection refused error will be +// retried in 100 milliseconds periods. +func waitTCPPort(ctx context.Context, port string) error { + ctx, cancel := context.WithTimeout(ctx, 3*time.Minute) + defer cancel() + + for { + c, err := (&net.Dialer{Timeout: 10 * time.Second}).DialContext(ctx, "tcp", "127.0.0.1:"+port) + if err != nil { + if operr, ok := err.(*net.OpError); ok { + if syserr, ok := operr.Err.(*os.SyscallError); ok && syserr.Err == syscall.ECONNREFUSED { + time.Sleep(100 * time.Millisecond) + continue + } + } + return err + } + return c.Close() } - l.Close() - _, port, err := net.SplitHostPort(l.Addr().String()) - if err != nil { - return "", err - } - return port, nil } diff --git a/cmd/swarm/swarm-smoke/feed_upload_and_sync.go b/cmd/swarm/swarm-smoke/feed_upload_and_sync.go new file mode 100644 index 0000000000..6b3fed0c7e --- /dev/null +++ b/cmd/swarm/swarm-smoke/feed_upload_and_sync.go @@ -0,0 +1,291 @@ +package main + +import ( + "bytes" + "crypto/md5" + "fmt" + "io" + "io/ioutil" + "os" + "os/exec" + "strings" + "sync" + "time" + + "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/swarm/storage/feed" + "github.com/ethereum/go-ethereum/swarm/testutil" + "github.com/pborman/uuid" + cli "gopkg.in/urfave/cli.v1" +) + +const ( + feedRandomDataLength = 8 +) + +func feedUploadAndSyncCmd(ctx *cli.Context, tuid string) error { + errc := make(chan error) + + go func() { + errc <- feedUploadAndSync(ctx, tuid) + }() + + 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) + + return fmt.Errorf("timeout after %v sec", timeout) + } +} + +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") + if err != nil { + return err + } + defer pkFile.Close() + defer os.Remove(pkFile.Name()) + + privkeyHex := "0000000000000000000000000000000000000000000000000000000000001976" + privKey, err := crypto.HexToECDSA(privkeyHex) + if err != nil { + return err + } + user := crypto.PubkeyToAddress(privKey.PublicKey) + userHex := hexutil.Encode(user.Bytes()) + + // save the private key to a file + _, err = io.WriteString(pkFile, privkeyHex) + if err != nil { + return err + } + + // keep hex strings for topic and subtopic + var topicHex string + var subTopicHex string + + // and create combination hex topics for bzz-feed retrieval + // xor'ed with topic (zero-value topic if no topic) + var subTopicOnlyHex string + var mergedSubTopicHex string + + // generate random topic and subtopic and put a hex on them + topicBytes, err := generateRandomData(feed.TopicLength) + topicHex = hexutil.Encode(topicBytes) + subTopicBytes, err := generateRandomData(8) + subTopicHex = hexutil.Encode(subTopicBytes) + if err != nil { + return err + } + mergedSubTopic, err := feed.NewTopic(subTopicHex, topicBytes) + if err != nil { + return err + } + mergedSubTopicHex = hexutil.Encode(mergedSubTopic[:]) + subTopicOnlyBytes, err := feed.NewTopic(subTopicHex, nil) + if err != nil { + return err + } + subTopicOnlyHex = hexutil.Encode(subTopicOnlyBytes[:]) + + // create feed manifest, topic only + var out bytes.Buffer + 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() + if err != nil { + return err + } + manifestWithTopic := strings.TrimRight(out.String(), string([]byte{0x0a})) + if len(manifestWithTopic) != 64 { + return fmt.Errorf("unknown feed create manifest hash format (topic): (%d) %s", len(out.String()), manifestWithTopic) + } + log.Debug("create topic feed", "manifest", manifestWithTopic) + out.Reset() + + // create feed manifest, subtopic only + 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() + if err != nil { + return err + } + manifestWithSubTopic := strings.TrimRight(out.String(), string([]byte{0x0a})) + if len(manifestWithSubTopic) != 64 { + return fmt.Errorf("unknown feed create manifest hash format (subtopic): (%d) %s", len(out.String()), manifestWithSubTopic) + } + log.Debug("create subtopic feed", "manifest", manifestWithTopic) + out.Reset() + + // create feed manifest, merged topic + 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() + if err != nil { + log.Error(err.Error()) + return err + } + manifestWithMergedTopic := strings.TrimRight(out.String(), string([]byte{0x0a})) + if len(manifestWithMergedTopic) != 64 { + return fmt.Errorf("unknown feed create manifest hash format (mergedtopic): (%d) %s", len(out.String()), manifestWithMergedTopic) + } + log.Debug("create mergedtopic feed", "manifest", manifestWithMergedTopic) + out.Reset() + + // create test data + data, err := generateRandomData(feedRandomDataLength) + if err != nil { + return err + } + h := md5.New() + h.Write(data) + dataHash := h.Sum(nil) + dataHex := hexutil.Encode(data) + + // update with topic + 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() + if err != nil { + return err + } + log.Debug("feed update topic", "out", out) + out.Reset() + + // update with subtopic + 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() + if err != nil { + return err + } + log.Debug("feed update subtopic", "out", out) + out.Reset() + + // update with merged topic + 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() + if err != nil { + return err + } + log.Debug("feed update mergedtopic", "out", out) + out.Reset() + + time.Sleep(3 * time.Second) + + // retrieve the data + wg := sync.WaitGroup{} + 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, httpEndpoint(host), dataHash, ruid) + if err != nil { + continue + } + + wg.Done() + return + } + }(hex, httpEndpoint(host), ruid) + } + } + wg.Wait() + log.Info("all endpoints synced random data successfully") + + // upload test file + log.Info("feed uploading to "+httpEndpoint(hosts[0])+" and syncing", "seed", seed) + + randomBytes := testutil.RandomBytes(seed, filesize*1000) + + hash, err := upload(randomBytes, httpEndpoint(hosts[0])) + if err != nil { + return err + } + hashBytes, err := hexutil.Decode("0x" + hash) + 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", httpEndpoint(hosts[0]), "feed", "update", "--topic", topicHex, multihashHex) + cmd.Stdout = &out + err = cmd.Run() + if err != nil { + return err + } + log.Debug("feed update topic", "out", out) + out.Reset() + + // update file with subtopic + 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 { + return err + } + log.Debug("feed update subtopic", "out", out) + out.Reset() + + // update file with merged topic + 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 { + return err + } + log.Debug("feed update mergedtopic", "out", out) + out.Reset() + + time.Sleep(3 * time.Second) + + for _, host := range hosts { + + // manifest retrieve, topic only + for _, url := range []string{manifestWithTopic, manifestWithSubTopic, manifestWithMergedTopic} { + wg.Add(1) + ruid := uuid.New()[:8] + go func(url string, endpoint string, ruid string) { + for { + err := fetch(url, endpoint, fileHash, ruid, "") + if err != nil { + continue + } + + wg.Done() + return + } + }(url, httpEndpoint(host), ruid) + } + + } + wg.Wait() + log.Info("all endpoints synced random file successfully") + + return nil +} diff --git a/cmd/swarm/swarm-smoke/main.go b/cmd/swarm/swarm-smoke/main.go new file mode 100644 index 0000000000..43d2c1ff51 --- /dev/null +++ b/cmd/swarm/swarm-smoke/main.go @@ -0,0 +1,190 @@ +// 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" + "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 ( + gitCommit string // Git SHA1 commit hash of the release (set via linker flags) +) + +var ( + allhosts string + hosts []string + filesize int + syncDelay int + httpPort int + wsPort int + verbosity int + timeout int + single bool + trackTimeout int +) + +func main() { + + app := cli.NewApp() + app.Name = "smoke-test" + app.Usage = "" + + app.Flags = []cli.Flag{ + cli.StringFlag{ + Name: "hosts", + Value: "", + Usage: "comma-separated list of swarm hosts", + Destination: &allhosts, + }, + cli.IntFlag{ + Name: "http-port", + Value: 80, + Usage: "http port", + Destination: &httpPort, + }, + cli.IntFlag{ + Name: "ws-port", + Value: 8546, + Usage: "ws port", + Destination: &wsPort, + }, + cli.IntFlag{ + Name: "filesize", + Value: 1024, + 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: wrapCliCommand("upload-and-sync", uploadAndSyncCmd), + }, + { + Name: "feed_sync", + Aliases: []string{"f"}, + Usage: "feed update generate, upload and sync", + 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/cmd/swarm/swarm-smoke/sliding_window.go b/cmd/swarm/swarm-smoke/sliding_window.go new file mode 100644 index 0000000000..d589124bd1 --- /dev/null +++ b/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/cmd/swarm/swarm-smoke/upload_and_sync.go b/cmd/swarm/swarm-smoke/upload_and_sync.go new file mode 100644 index 0000000000..90230df253 --- /dev/null +++ b/cmd/swarm/swarm-smoke/upload_and_sync.go @@ -0,0 +1,194 @@ +// 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" + "fmt" + "io/ioutil" + "math/rand" + "os" + "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 uploadAndSyncCmd(ctx *cli.Context, tuid string) error { + randomBytes := testutil.RandomBytes(seed, filesize*1000) + + errc := make(chan error) + + go func() { + errc <- uplaodAndSync(ctx, randomBytes, tuid) + }() + + 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) + + e := fmt.Errorf("timeout after %v sec", timeout) + // trigger debug functionality on randomBytes + err := trackChunks(randomBytes[:]) + if err != nil { + e = fmt.Errorf("%v; triggerChunkDebug failed: %v", e, err) + } + + return e + } +} + +func trackChunks(testData []byte) error { + log.Warn("Test timed out; running chunk debug sequence") + + addrs, err := getAllRefs(testData) + if err != nil { + return err + } + log.Trace("All references retrieved") + + // has-chunks + for _, host := range hosts { + httpHost := fmt.Sprintf("ws://%s:%d", host, 8546) + log.Trace("Calling `Has` on host", "httpHost", httpHost) + rpcClient, err := rpc.Dial(httpHost) + if err != nil { + log.Trace("Error dialing host", "err", err) + return err + } + log.Trace("rpc dial ok") + var hasInfo []api.HasInfo + err = rpcClient.Call(&hasInfo, "bzz_has", addrs) + if err != nil { + log.Trace("Error calling host", "err", err) + return err + } + log.Trace("rpc call ok") + count := 0 + for _, info := range hasInfo { + if !info.Has { + count++ + log.Error("Host does not have chunk", "host", httpHost, "chunk", info.Addr) + } + } + if count == 0 { + log.Info("Host reported to have all chunks", "host", httpHost) + } + } + return nil +} + +func getAllRefs(testData []byte) (storage.AddressCollection, error) { + log.Trace("Getting all references for given root hash") + 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 uplaodAndSync(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 + } + + log.Info("uploaded successfully", "tuid", tuid, "hash", hash, "took", t2, "digest", fmt.Sprintf("%x", fhash)) + + time.Sleep(time.Duration(syncDelay) * time.Second) + + wg := sync.WaitGroup{} + if single { + randIndex := 1 + rand.Intn(len(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.single.fetch-time", nil).Update(ended) + log.Info("fetch successful", "tuid", tuid, "ruid", ruid, "took", ended, "endpoint", endpoint) + wg.Done() + return + } + }(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 hosts synced random file successfully") + + return nil +} diff --git a/cmd/swarm/swarm-smoke/upload_speed.go b/cmd/swarm/swarm-smoke/upload_speed.go new file mode 100644 index 0000000000..20bf7b86ca --- /dev/null +++ b/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/cmd/swarm/swarm-smoke/util.go b/cmd/swarm/swarm-smoke/util.go new file mode 100644 index 0000000000..87abb44b0b --- /dev/null +++ b/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/cmd/swarm/swarm-snapshot/create.go b/cmd/swarm/swarm-snapshot/create.go new file mode 100644 index 0000000000..434561a491 --- /dev/null +++ b/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/cmd/swarm/swarm-snapshot/create_test.go b/cmd/swarm/swarm-snapshot/create_test.go new file mode 100644 index 0000000000..b2e30c2016 --- /dev/null +++ b/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/cmd/swarm/swarm-snapshot/main.go b/cmd/swarm/swarm-snapshot/main.go new file mode 100644 index 0000000000..136295e511 --- /dev/null +++ b/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/cmd/swarm/swarm-snapshot/run_test.go b/cmd/swarm/swarm-snapshot/run_test.go new file mode 100644 index 0000000000..d9a041597e --- /dev/null +++ b/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/cmd/swarm/upload.go b/cmd/swarm/upload.go index 9f4c525bb9..ab07908351 100644 --- a/cmd/swarm/upload.go +++ b/cmd/swarm/upload.go @@ -22,33 +22,51 @@ import ( "fmt" "io" "io/ioutil" - "mime" - "net/http" "os" "os/user" "path" "path/filepath" + "strconv" "strings" - "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/log" swarm "github.com/ethereum/go-ethereum/swarm/api/client" + + "github.com/ethereum/go-ethereum/cmd/utils" "gopkg.in/urfave/cli.v1" ) -func upload(ctx *cli.Context) { +var upCommand = cli.Command{ + Action: upload, + CustomHelpTemplate: helpTemplate, + Name: "up", + Usage: "uploads a file or directory to swarm using the HTTP API", + ArgsUsage: "", + Flags: []cli.Flag{SwarmEncryptedFlag}, + Description: "uploads a file or directory to swarm using the HTTP API and prints the root hash", +} +func upload(ctx *cli.Context) { args := ctx.Args() var ( - bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") - recursive = ctx.GlobalBool(SwarmRecursiveUploadFlag.Name) - wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name) - defaultPath = ctx.GlobalString(SwarmUploadDefaultPath.Name) - fromStdin = ctx.GlobalBool(SwarmUpFromStdinFlag.Name) - mimeType = ctx.GlobalString(SwarmUploadMimeType.Name) - client = swarm.NewClient(bzzapi) - file string + bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") + recursive = ctx.GlobalBool(SwarmRecursiveFlag.Name) + wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name) + defaultPath = ctx.GlobalString(SwarmUploadDefaultPath.Name) + fromStdin = ctx.GlobalBool(SwarmUpFromStdinFlag.Name) + mimeType = ctx.GlobalString(SwarmUploadMimeType.Name) + client = swarm.NewClient(bzzapi) + toEncrypt = ctx.Bool(SwarmEncryptedFlag.Name) + autoDefaultPath = false + file string ) - + if autoDefaultPathString := os.Getenv(SwarmAutoDefaultPath); autoDefaultPathString != "" { + b, err := strconv.ParseBool(autoDefaultPathString) + if err != nil { + utils.Fatalf("invalid environment variable %s: %v", SwarmAutoDefaultPath, err) + } + autoDefaultPath = b + } if len(args) != 1 { if fromStdin { tmp, err := ioutil.TempFile("", "swarm-stdin") @@ -76,7 +94,7 @@ func upload(ctx *cli.Context) { utils.Fatalf("Error opening file: %s", err) } defer f.Close() - hash, err := client.UploadRaw(f, f.Size) + hash, err := client.UploadRaw(f, f.Size, toEncrypt) if err != nil { utils.Fatalf("Upload failed: %s", err) } @@ -97,7 +115,27 @@ func upload(ctx *cli.Context) { if !recursive { return "", errors.New("Argument is a directory and recursive upload is disabled") } - return client.UploadDirectory(file, defaultPath, "") + if autoDefaultPath && defaultPath == "" { + defaultEntryCandidate := path.Join(file, "index.html") + log.Debug("trying to find default path", "path", defaultEntryCandidate) + defaultEntryStat, err := os.Stat(defaultEntryCandidate) + if err == nil && !defaultEntryStat.IsDir() { + log.Debug("setting auto detected default path", "path", defaultEntryCandidate) + defaultPath = defaultEntryCandidate + } + } + if defaultPath != "" { + // construct absolute default path + absDefaultPath, _ := filepath.Abs(defaultPath) + absFile, _ := filepath.Abs(file) + // make sure absolute directory ends with only one "/" + // to trim it from absolute default path and get relative default path + absFile = strings.TrimRight(absFile, "/") + "/" + if absDefaultPath != "" && absFile != "" && strings.HasPrefix(absDefaultPath, absFile) { + defaultPath = strings.TrimPrefix(absDefaultPath, absFile) + } + } + return client.UploadDirectory(file, defaultPath, "", toEncrypt) } } else { doUpload = func() (string, error) { @@ -106,11 +144,10 @@ func upload(ctx *cli.Context) { return "", fmt.Errorf("error opening file: %s", err) } defer f.Close() - if mimeType == "" { - mimeType = detectMimeType(file) + if mimeType != "" { + f.ContentType = mimeType } - f.ContentType = mimeType - return client.Upload(f, "") + return client.Upload(f, "", toEncrypt) } } hash, err := doUpload() @@ -126,6 +163,12 @@ func upload(ctx *cli.Context) { // 3. cleans the path, e.g. /a/b/../c -> /a/c // Note, it has limitations, e.g. ~someuser/tmp will not be expanded func expandPath(p string) string { + if i := strings.Index(p, ":"); i > 0 { + return p + } + if i := strings.Index(p, "@"); i > 0 { + return p + } if strings.HasPrefix(p, "~/") || strings.HasPrefix(p, "~\\") { if home := homeDir(); home != "" { p = home + p[1:] @@ -143,19 +186,3 @@ func homeDir() string { } return "" } - -func detectMimeType(file string) string { - if ext := filepath.Ext(file); ext != "" { - return mime.TypeByExtension(ext) - } - f, err := os.Open(file) - if err != nil { - return "" - } - defer f.Close() - buf := make([]byte, 512) - if n, _ := f.Read(buf); n > 0 { - return http.DetectContentType(buf) - } - return "" -} diff --git a/cmd/swarm/upload_test.go b/cmd/swarm/upload_test.go index 5656186e1c..616486e37c 100644 --- a/cmd/swarm/upload_test.go +++ b/cmd/swarm/upload_test.go @@ -1,4 +1,4 @@ -// Copyright 2016 The go-ethereum Authors +// Copyright 2017 The go-ethereum Authors // This file is part of go-ethereum. // // go-ethereum is free software: you can redistribute it and/or modify @@ -17,60 +17,340 @@ package main import ( + "bytes" + "fmt" "io" "io/ioutil" "net/http" "os" + "path" + "path/filepath" + "runtime" + "strings" "testing" + "time" + + "github.com/ethereum/go-ethereum/log" + swarmapi "github.com/ethereum/go-ethereum/swarm/api/client" + "github.com/ethereum/go-ethereum/swarm/testutil" + "github.com/mattn/go-colorable" ) -// TestCLISwarmUp tests that running 'swarm up' makes the resulting file +func init() { + log.PrintOrigins(true) + log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true)))) +} + +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) { - // start 3 node cluster - t.Log("starting 3 node cluster") - cluster := newTestCluster(t, 3) - defer cluster.Shutdown() +func testNoEncryption(t *testing.T) { + testDefault(false, t) +} - // create a tmp file - tmp, err := ioutil.TempFile("", "swarm-test") - assertNil(t, err) - defer tmp.Close() - defer os.Remove(tmp.Name()) - _, err = io.WriteString(tmp, "data") - assertNil(t, err) +// testEncrypted tests that running 'swarm up --encrypted' makes the resulting file +// available from all nodes via the HTTP API +func testEncrypted(t *testing.T) { + testDefault(true, t) +} +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) + + // write data to file + hashRegexp := `[a-f\d]{64}` + flags := []string{ + "--bzzapi", cluster.Nodes[0].URL, + "up", + tmpFileName} + if toEncrypt { + hashRegexp = `[a-f\d]{128}` + flags = []string{ + "--bzzapi", cluster.Nodes[0].URL, + "up", + "--encrypt", + tmpFileName} + } // upload the file with 'swarm up' and expect a hash - t.Log("uploading file with 'swarm up'") - up := runSwarm(t, "--bzzapi", cluster.Nodes[0].URL, "up", tmp.Name()) - _, matches := up.ExpectRegexp(`[a-f\d]{64}`) + log.Info(fmt.Sprintf("uploading file with 'swarm up'")) + up := runSwarm(t, flags...) + _, matches := up.ExpectRegexp(hashRegexp) up.ExpectExit() hash := matches[0] - t.Logf("file uploaded with hash %s", hash) + log.Info("file uploaded", "hash", hash) // get the file from the HTTP API of each node for _, node := range cluster.Nodes { - t.Logf("getting file from %s", node.Name) + log.Info("getting file from node", "node", node.Name) + res, err := http.Get(node.URL + "/bzz:/" + hash) - assertNil(t, err) - assertHTTPResponse(t, res, http.StatusOK, "data") + if err != nil { + t.Fatal(err) + } + defer res.Body.Close() + + reply, err := ioutil.ReadAll(res.Body) + if err != nil { + t.Fatal(err) + } + if res.StatusCode != 200 { + t.Fatalf("expected HTTP status 200, got %s", res.Status) + } + if string(reply) != data { + t.Fatalf("expected HTTP body %q, got %q", data, reply) + } + log.Debug("verifying uploaded file using `swarm down`") + //try to get the content with `swarm down` + tmpDownload, err := ioutil.TempDir("", "swarm-test") + tmpDownload = path.Join(tmpDownload, "tmpfile.tmp") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpDownload) + + bzzLocator := "bzz:/" + hash + flags = []string{ + "--bzzapi", cluster.Nodes[0].URL, + "down", + bzzLocator, + tmpDownload, + } + + down := runSwarm(t, flags...) + down.ExpectExit() + + fi, err := os.Stat(tmpDownload) + if err != nil { + t.Fatalf("could not stat path: %v", err) + } + + switch mode := fi.Mode(); { + case mode.IsRegular(): + downloadedBytes, err := ioutil.ReadFile(tmpDownload) + if err != nil { + t.Fatalf("had an error reading the downloaded file: %v", err) + } + if !bytes.Equal(downloadedBytes, bytes.NewBufferString(data).Bytes()) { + t.Fatalf("retrieved data and posted data not equal!") + } + + default: + t.Fatalf("expected to download regular file, got %s", fi.Mode()) + } + } + + timeout := time.Duration(2 * time.Second) + httpClient := http.Client{ + Timeout: timeout, + } + + // try to squeeze a timeout by getting an non-existent hash from each node + for _, node := range cluster.Nodes { + _, err := httpClient.Get(node.URL + "/bzz:/1023e8bae0f70be7d7b5f74343088ba408a218254391490c85ae16278e230340") + // we're speeding up the timeout here since netstore has a 60 seconds timeout on a request + if err != nil && !strings.Contains(err.Error(), "Client.Timeout exceeded while awaiting headers") { + t.Fatal(err) + } + // this is disabled since it takes 60s due to netstore timeout + // if res.StatusCode != 404 { + // t.Fatalf("expected HTTP status 404, got %s", res.Status) + // } } } -func assertNil(t *testing.T, err error) { +func testRecursive(toEncrypt bool, t *testing.T) { + tmpUploadDir, err := ioutil.TempDir("", "swarm-test") if err != nil { t.Fatal(err) } + defer os.RemoveAll(tmpUploadDir) + // create tmp files + for _, path := range []string{"tmp1", "tmp2"} { + if err := ioutil.WriteFile(filepath.Join(tmpUploadDir, path), bytes.NewBufferString(data).Bytes(), 0644); err != nil { + t.Fatal(err) + } + } + + hashRegexp := `[a-f\d]{64}` + flags := []string{ + "--bzzapi", cluster.Nodes[0].URL, + "--recursive", + "up", + tmpUploadDir} + if toEncrypt { + hashRegexp = `[a-f\d]{128}` + flags = []string{ + "--bzzapi", cluster.Nodes[0].URL, + "--recursive", + "up", + "--encrypt", + tmpUploadDir} + } + // upload the file with 'swarm up' and expect a hash + log.Info(fmt.Sprintf("uploading file with 'swarm up'")) + up := runSwarm(t, flags...) + _, matches := up.ExpectRegexp(hashRegexp) + up.ExpectExit() + hash := matches[0] + log.Info("dir uploaded", "hash", hash) + + // get the file from the HTTP API of each node + for _, node := range cluster.Nodes { + log.Info("getting file from node", "node", node.Name) + //try to get the content with `swarm down` + tmpDownload, err := ioutil.TempDir("", "swarm-test") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpDownload) + bzzLocator := "bzz:/" + hash + flagss := []string{ + "--bzzapi", cluster.Nodes[0].URL, + "down", + "--recursive", + bzzLocator, + tmpDownload, + } + + fmt.Println("downloading from swarm with recursive") + down := runSwarm(t, flagss...) + down.ExpectExit() + + files, err := ioutil.ReadDir(tmpDownload) + for _, v := range files { + fi, err := os.Stat(path.Join(tmpDownload, v.Name())) + if err != nil { + t.Fatalf("got an error: %v", err) + } + + switch mode := fi.Mode(); { + case mode.IsRegular(): + 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)) + io.ReadFull(file, ff) + buf := bytes.NewBufferString(data) + + if !bytes.Equal(ff, buf.Bytes()) { + t.Fatalf("retrieved data and posted data not equal!") + } + } + default: + t.Fatalf("this shouldnt happen") + } + } + if err != nil { + t.Fatalf("could not list files at: %v", files) + } + } } -func assertHTTPResponse(t *testing.T, res *http.Response, expectedStatus int, expectedBody string) { - defer res.Body.Close() - if res.StatusCode != expectedStatus { - t.Fatalf("expected HTTP status %d, got %s", expectedStatus, res.Status) +// testDefaultPathAll tests swarm recursive upload with relative and absolute +// default paths and with encryption. +func testDefaultPathAll(t *testing.T) { + testDefaultPath(false, false, t) + testDefaultPath(false, true, t) + testDefaultPath(true, false, t) + testDefaultPath(true, true, t) +} + +func testDefaultPath(toEncrypt bool, absDefaultPath bool, t *testing.T) { + tmp, err := ioutil.TempDir("", "swarm-defaultpath-test") + if err != nil { + t.Fatal(err) } - data, err := ioutil.ReadAll(res.Body) - assertNil(t, err) - if string(data) != expectedBody { - t.Fatalf("expected HTTP body %q, got %q", expectedBody, data) + defer os.RemoveAll(tmp) + + err = ioutil.WriteFile(filepath.Join(tmp, "index.html"), []byte("

Test

"), 0666) + if err != nil { + t.Fatal(err) + } + err = ioutil.WriteFile(filepath.Join(tmp, "robots.txt"), []byte("Disallow: /"), 0666) + if err != nil { + t.Fatal(err) + } + + defaultPath := "index.html" + if absDefaultPath { + defaultPath = filepath.Join(tmp, defaultPath) + } + + args := []string{ + "--bzzapi", + cluster.Nodes[0].URL, + "--recursive", + "--defaultpath", + defaultPath, + "up", + tmp, + } + if toEncrypt { + args = append(args, "--encrypt") + } + + up := runSwarm(t, args...) + hashRegexp := `[a-f\d]{64,128}` + _, matches := up.ExpectRegexp(hashRegexp) + up.ExpectExit() + hash := matches[0] + + client := swarmapi.NewClient(cluster.Nodes[0].URL) + + m, isEncrypted, err := client.DownloadManifest(hash) + if err != nil { + t.Fatal(err) + } + + if toEncrypt != isEncrypted { + t.Error("downloaded manifest is not encrypted") + } + + var found bool + var entriesCount int + for _, e := range m.Entries { + entriesCount++ + if e.Path == "" { + found = true + } + } + + if !found { + t.Error("manifest default entry was not found") + } + + if entriesCount != 3 { + t.Errorf("manifest contains %v entries, expected %v", entriesCount, 3) } } diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index 23b10c2d74..f23aa5775b 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -25,9 +25,14 @@ import ( "os/signal" "runtime" "strings" + "syscall" + "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/crypto" + "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/internal/debug" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" @@ -64,7 +69,7 @@ func StartNode(stack *node.Node) { } go func() { sigc := make(chan os.Signal, 1) - signal.Notify(sigc, os.Interrupt) + signal.Notify(sigc, syscall.SIGINT, syscall.SIGTERM) defer signal.Stop(sigc) <-sigc log.Info("Got interrupt, shutting down...") @@ -85,7 +90,7 @@ func ImportChain(chain *core.BlockChain, fn string) error { // If a signal is received, the import will stop at the next batch. interrupt := make(chan os.Signal, 1) stop := make(chan struct{}) - signal.Notify(interrupt, os.Interrupt) + signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM) defer signal.Stop(interrupt) defer close(interrupt) go func() { @@ -104,6 +109,8 @@ func ImportChain(chain *core.BlockChain, fn string) error { } log.Info("Importing blockchain", "file", fn) + + // Open the file handle and potentially unwrap the gzip stream fh, err := os.Open(fn) if err != nil { return err @@ -116,7 +123,6 @@ func ImportChain(chain *core.BlockChain, fn string) error { return err } } - stream := rlp.NewStream(reader, 0) // Run actual the import. @@ -150,29 +156,42 @@ func ImportChain(chain *core.BlockChain, fn string) error { if checkInterrupt() { return fmt.Errorf("interrupted") } - if hasAllBlocks(chain, blocks[:i]) { + missing := missingBlocks(chain, blocks[:i]) + if len(missing) == 0 { log.Info("Skipping batch as all blocks present", "batch", batch, "first", blocks[0].Hash(), "last", blocks[i-1].Hash()) continue } - - if _, err := chain.InsertChain(blocks[:i]); err != nil { + if _, err := chain.InsertChain(missing); err != nil { return fmt.Errorf("invalid block %d: %v", n, err) } } return nil } -func hasAllBlocks(chain *core.BlockChain, bs []*types.Block) bool { - for _, b := range bs { - if !chain.HasBlock(b.Hash(), b.NumberU64()) { - return false +func missingBlocks(chain *core.BlockChain, blocks []*types.Block) []*types.Block { + head := chain.CurrentBlock() + for i, block := range blocks { + // If we're behind the chain head, only check block, state is available at head + if head.NumberU64() > block.NumberU64() { + if !chain.HasBlock(block.Hash(), block.NumberU64()) { + return blocks[i:] + } + continue + } + // If we're above the chain head, state availability is a must + if !chain.HasBlockAndState(block.Hash(), block.NumberU64()) { + return blocks[i:] } } - return true + return nil } +// ExportChain exports a blockchain into the specified file, truncating any data +// already present in the file. func ExportChain(blockchain *core.BlockChain, fn string) error { log.Info("Exporting blockchain", "file", fn) + + // Open the file handle and potentially wrap with a gzip stream fh, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm) if err != nil { return err @@ -184,7 +203,7 @@ func ExportChain(blockchain *core.BlockChain, fn string) error { writer = gzip.NewWriter(writer) defer writer.(*gzip.Writer).Close() } - + // Iterate over the blocks and export them if err := blockchain.Export(writer); err != nil { return err } @@ -193,9 +212,12 @@ func ExportChain(blockchain *core.BlockChain, fn string) error { return nil } +// ExportAppendChain exports a blockchain into the specified file, appending to +// the file if data already exists in it. func ExportAppendChain(blockchain *core.BlockChain, fn string, first uint64, last uint64) error { log.Info("Exporting blockchain", "file", fn) - // TODO verify mode perms + + // Open the file handle and potentially wrap with a gzip stream fh, err := os.OpenFile(fn, os.O_CREATE|os.O_APPEND|os.O_WRONLY, os.ModePerm) if err != nil { return err @@ -207,10 +229,84 @@ func ExportAppendChain(blockchain *core.BlockChain, fn string, first uint64, las writer = gzip.NewWriter(writer) defer writer.(*gzip.Writer).Close() } - + // Iterate over the blocks and export them if err := blockchain.ExportN(writer, first, last); err != nil { return err } log.Info("Exported blockchain to", "file", fn) return nil } + +// ImportPreimages imports a batch of exported hash preimages into the database. +func ImportPreimages(db *ethdb.LDBDatabase, fn string) error { + log.Info("Importing preimages", "file", fn) + + // Open the file handle and potentially unwrap the gzip stream + fh, err := os.Open(fn) + if err != nil { + return err + } + defer fh.Close() + + var reader io.Reader = fh + if strings.HasSuffix(fn, ".gz") { + if reader, err = gzip.NewReader(reader); err != nil { + return err + } + } + stream := rlp.NewStream(reader, 0) + + // Import the preimages in batches to prevent disk trashing + preimages := make(map[common.Hash][]byte) + + for { + // Read the next entry and ensure it's not junk + var blob []byte + + if err := stream.Decode(&blob); err != nil { + if err == io.EOF { + break + } + return err + } + // Accumulate the preimages and flush when enough ws gathered + preimages[crypto.Keccak256Hash(blob)] = common.CopyBytes(blob) + if len(preimages) > 1024 { + rawdb.WritePreimages(db, preimages) + preimages = make(map[common.Hash][]byte) + } + } + // Flush the last batch preimage data + if len(preimages) > 0 { + rawdb.WritePreimages(db, preimages) + } + return nil +} + +// 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 { + log.Info("Exporting preimages", "file", fn) + + // Open the file handle and potentially wrap with a gzip stream + fh, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm) + if err != nil { + return err + } + defer fh.Close() + + var writer io.Writer = fh + if strings.HasSuffix(fn, ".gz") { + writer = gzip.NewWriter(writer) + defer writer.(*gzip.Writer).Close() + } + // Iterate over the preimages and export them + it := db.NewIteratorWithPrefix([]byte("secure-key-")) + for it.Next() { + if err := rlp.Encode(writer, it.Value()); err != nil { + return err + } + } + log.Info("Exported preimages", "file", fn) + return nil +} diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 89d16b968f..4db59097d7 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -19,14 +19,15 @@ package utils import ( "crypto/ecdsa" + "encoding/json" "fmt" "io/ioutil" "math/big" "os" "path/filepath" - "runtime" "strconv" "strings" + "time" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" @@ -48,15 +49,16 @@ import ( "github.com/ethereum/go-ethereum/les" "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/discover" "github.com/ethereum/go-ethereum/p2p/discv5" + "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/p2p/netutil" "github.com/ethereum/go-ethereum/params" - whisper "github.com/ethereum/go-ethereum/whisper/whisperv5" - "gopkg.in/urfave/cli.v1" + whisper "github.com/ethereum/go-ethereum/whisper/whisperv6" + cli "gopkg.in/urfave/cli.v1" ) var ( @@ -64,7 +66,7 @@ var ( {{if .cmd.Description}}{{.cmd.Description}} {{end}}{{if .cmd.Subcommands}} SUBCOMMANDS: - {{range .cmd.Subcommands}}{{.cmd.Name}}{{with .cmd.ShortName}}, {{.cmd}}{{end}}{{ "\t" }}{{.cmd.Usage}} + {{range .cmd.Subcommands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}} {{end}}{{end}}{{if .categorizedFlags}} {{range $idx, $categorized := .categorizedFlags}}{{$categorized.Name}} OPTIONS: {{range $categorized.Flags}}{{"\t"}}{{.}} @@ -96,7 +98,7 @@ func NewApp(gitCommit, usage string) *cli.App { app.Author = "" //app.Authors = nil app.Email = "" - app.Version = params.Version + app.Version = params.VersionWithMeta if len(gitCommit) >= 8 { app.Version += "-" + gitCommit[:8] } @@ -139,6 +141,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", @@ -156,13 +166,25 @@ var ( Usage: "Document Root for HTTPClient file scheme", Value: DirectoryString{homeDir()}, } - FastSyncFlag = cli.BoolFlag{ - Name: "fast", - Usage: "Enable fast syncing through state downloads", + ExitWhenSyncedFlag = cli.BoolFlag{ + Name: "exitwhensynced", + Usage: "Exists syncing after block synchronisation", } - LightModeFlag = cli.BoolFlag{ - Name: "light", - Usage: "Enable light client mode", + 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{ @@ -170,24 +192,42 @@ var ( Usage: `Blockchain sync mode ("fast", "full", or "light")`, Value: &defaultSyncMode, } - + GCModeFlag = cli.StringFlag{ + Name: "gcmode", + Usage: `Blockchain garbage collection mode ("full", "archive")`, + Value: "full", + } 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", - Value: 20, + Value: eth.DefaultConfig.LightPeers, } LightKDFFlag = cli.BoolFlag{ 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: "dashboard", + Name: metrics.DashboardEnabledFlag, Usage: "Enable the dashboard", } DashboardAddrFlag = cli.StringFlag{ @@ -205,11 +245,6 @@ var ( Usage: "Dashboard metrics collection refresh rate", Value: dashboard.DefaultConfig.Refresh, } - DashboardAssetsFlag = cli.StringFlag{ - Name: "dashboard.assets", - Usage: "Developer flag to serve the dashboard from the local file system", - Value: dashboard.DefaultConfig.Assets, - } // Ethash settings EthashCacheDirFlag = DirectoryFlag{ Name: "ethash.cachedir", @@ -241,6 +276,10 @@ var ( Value: eth.DefaultConfig.Ethash.DatasetsOnDisk, } // Transaction pool settings + TxPoolLocalsFlag = cli.StringFlag{ + Name: "txpool.locals", + Usage: "Comma separated accounts to treat as locals (no flush, priority inclusion)", + } TxPoolNoLocalsFlag = cli.BoolFlag{ Name: "txpool.nolocals", Usage: "Disables price exemptions for locally submitted transactions", @@ -293,8 +332,23 @@ var ( // Performance tuning settings CacheFlag = cli.IntFlag{ Name: "cache", - Usage: "Megabytes of memory allocated to internal caching (min 16MB / database forced)", - Value: 128, + Usage: "Megabytes of memory allocated to internal caching", + Value: 1024, + } + CacheDatabaseFlag = cli.IntFlag{ + Name: "cache.database", + Usage: "Percentage of cache memory allowance to use for database io", + 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 (default = 25% full mode, 0% archive mode)", + Value: 25, } TrieCacheGenFlag = cli.IntFlag{ Name: "trie-cache-gens", @@ -307,29 +361,71 @@ var ( Usage: "Enable mining", } MinerThreadsFlag = cli.IntFlag{ - Name: "minerthreads", + Name: "miner.threads", Usage: "Number of CPU threads to use for mining", - Value: runtime.NumCPU(), + Value: 0, } - TargetGasLimitFlag = cli.Uint64Flag{ + MinerLegacyThreadsFlag = cli.IntFlag{ + Name: "minerthreads", + Usage: "Number of CPU threads to use for mining (deprecated, use --miner.threads)", + Value: 0, + } + MinerNotifyFlag = cli.StringFlag{ + Name: "miner.notify", + Usage: "Comma separated HTTP URL list to notify of new work packages", + } + MinerGasTargetFlag = cli.Uint64Flag{ + Name: "miner.gastarget", + Usage: "Target gas floor for mined blocks", + Value: eth.DefaultConfig.MinerGasFloor, + } + MinerLegacyGasTargetFlag = cli.Uint64Flag{ Name: "targetgaslimit", - Usage: "Target gas limit sets the artificial target gas floor for the blocks to mine", - Value: params.GenesisGasLimit, + Usage: "Target gas floor for mined blocks (deprecated, use --miner.gastarget)", + Value: eth.DefaultConfig.MinerGasFloor, } - EtherbaseFlag = cli.StringFlag{ - Name: "etherbase", - Usage: "Public address for block mining rewards (default = first account created)", + MinerGasLimitFlag = cli.Uint64Flag{ + Name: "miner.gaslimit", + Usage: "Target gas ceiling for mined blocks", + Value: eth.DefaultConfig.MinerGasCeil, + } + MinerGasPriceFlag = BigFlag{ + Name: "miner.gasprice", + Usage: "Minimum gas price for mining a transaction", + Value: eth.DefaultConfig.MinerGasPrice, + } + MinerLegacyGasPriceFlag = BigFlag{ + Name: "gasprice", + Usage: "Minimum gas price for mining a transaction (deprecated, use --miner.gasprice)", + Value: eth.DefaultConfig.MinerGasPrice, + } + MinerEtherbaseFlag = cli.StringFlag{ + Name: "miner.etherbase", + Usage: "Public address for block mining rewards (default = first account)", Value: "0", } - GasPriceFlag = BigFlag{ - Name: "gasprice", - Usage: "Minimal gas price to accept for mining a transactions", - Value: eth.DefaultConfig.GasPrice, + MinerLegacyEtherbaseFlag = cli.StringFlag{ + Name: "etherbase", + Usage: "Public address for block mining rewards (default = first account, deprecated, use --miner.etherbase)", + Value: "0", } - ExtraDataFlag = cli.StringFlag{ - Name: "extradata", + MinerExtraDataFlag = cli.StringFlag{ + Name: "miner.extradata", Usage: "Block extra data set by the miner (default = client version)", } + MinerLegacyExtraDataFlag = cli.StringFlag{ + Name: "extradata", + Usage: "Block extra data set by the miner (default = client version, deprecated, use --miner.extradata)", + } + MinerRecommitIntervalFlag = cli.DurationFlag{ + Name: "miner.recommit", + Usage: "Time interval to recreate the block being mined", + Value: eth.DefaultConfig.MinerRecommit, + } + MinerNoVerfiyFlag = cli.BoolFlag{ + Name: "miner.noverify", + Usage: "Disable remote sealing verification", + } // Account settings UnlockedAccountFlag = cli.StringFlag{ Name: "unlock", @@ -341,7 +437,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", @@ -351,10 +451,6 @@ var ( Name: "ethstats", Usage: "Reporting URL of a ethstats service (nodename:secret@host:port)", } - MetricsEnabledFlag = cli.BoolFlag{ - Name: metrics.MetricsEnabledFlag, - Usage: "Enable metrics collection and reporting", - } FakePoWFlag = cli.BoolFlag{ Name: "fakepow", Usage: "Disables proof-of-work verification", @@ -378,11 +474,40 @@ 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)", Value: "", } + RPCVirtualHostsFlag = cli.StringFlag{ + Name: "rpcvhosts", + Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.", + Value: strings.Join(node.DefaultConfig.HTTPVirtualHosts, ","), + } RPCApiFlag = cli.StringFlag{ Name: "rpcapi", Usage: "API's offered over the HTTP-RPC interface", @@ -518,6 +643,60 @@ var ( Usage: "Minimum POW accepted", Value: whisper.DefaultMinimumPoW, } + WhisperRestrictConnectionBetweenLightClientsFlag = cli.BoolFlag{ + Name: "shh.restrict-light", + Usage: "Restrict connection between two whisper light clients", + } + + // Metrics flags + MetricsEnabledFlag = cli.BoolFlag{ + Name: metrics.MetricsEnabledFlag, + Usage: "Enable metrics collection and reporting", + } + MetricsEnableInfluxDBFlag = cli.BoolFlag{ + Name: "metrics.influxdb", + Usage: "Enable metrics export/push to an external InfluxDB database", + } + MetricsInfluxDBEndpointFlag = cli.StringFlag{ + Name: "metrics.influxdb.endpoint", + Usage: "InfluxDB API endpoint to report metrics to", + Value: "http://localhost:8086", + } + MetricsInfluxDBDatabaseFlag = cli.StringFlag{ + Name: "metrics.influxdb.database", + Usage: "InfluxDB database name to push reported metrics to", + Value: "geth", + } + MetricsInfluxDBUsernameFlag = cli.StringFlag{ + Name: "metrics.influxdb.username", + Usage: "Username to authorize access to the database", + Value: "test", + } + MetricsInfluxDBPasswordFlag = cli.StringFlag{ + Name: "metrics.influxdb.password", + Usage: "Password to authorize access to the database", + Value: "test", + } + // 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 + MetricsInfluxDBTagsFlag = cli.StringFlag{ + Name: "metrics.influxdb.tags", + Usage: "Comma-separated InfluxDB tags (key/values) attached to all measurements", + Value: "host=localhost", + } + + EWASMInterpreterFlag = cli.StringFlag{ + Name: "vm.ewasm", + Usage: "External ewasm configuration (default = built-in interpreter)", + Value: "", + } + EVMInterpreterFlag = cli.StringFlag{ + Name: "vm.evm", + Usage: "External EVM configuration (default = built-in interpreter)", + Value: "", + } ) // MakeDataDir retrieves the currently requested data directory, terminating @@ -531,6 +710,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)") @@ -585,18 +767,21 @@ 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([]*discover.Node, 0, len(urls)) + cfg.BootstrapNodes = make([]*enode.Node, 0, len(urls)) for _, url := range urls { - node, err := discover.ParseNode(url) - if err != nil { - log.Error("Bootstrap URL invalid", "enode", url, "err", err) - continue + if url != "" { + node, err := enode.ParseV4(url) + if err != nil { + log.Crit("Bootstrap URL invalid", "enode", url, "err", err) + } + cfg.BootstrapNodes = append(cfg.BootstrapNodes, node) } - cfg.BootstrapNodes = append(cfg.BootstrapNodes, node) } } @@ -613,6 +798,8 @@ 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. } @@ -676,6 +863,27 @@ func setHTTP(ctx *cli.Context, cfg *node.Config) { if ctx.GlobalIsSet(RPCApiFlag.Name) { cfg.HTTPModules = splitAndTrim(ctx.GlobalString(RPCApiFlag.Name)) } + if ctx.GlobalIsSet(RPCVirtualHostsFlag.Name) { + cfg.HTTPVirtualHosts = splitAndTrim(ctx.GlobalString(RPCVirtualHostsFlag.Name)) + } +} + +// 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 @@ -711,20 +919,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 { - if err := fdlimit.Raise(2048); err != nil { - Fatalf("Failed to raise file descriptor allowance: %v", err) - } - limit, err := fdlimit.Current() + limit, err := fdlimit.Maximum() if err != nil { Fatalf("Failed to retrieve file descriptor allowance: %v", err) } - if limit > 2048 { // cap database file descriptors even if more is available - limit = 2048 + raised, err := fdlimit.Raise(uint64(limit)) + if err != nil { + Fatalf("Failed to raise file descriptor allowance: %v", err) } - 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 @@ -755,12 +995,25 @@ func MakeAddress(ks *keystore.KeyStore, account string) (accounts.Account, error // setEtherbase retrieves the etherbase either from the directly specified // command line flags or from the keystore if CLI indexed. func setEtherbase(ctx *cli.Context, ks *keystore.KeyStore, cfg *eth.Config) { - if ctx.GlobalIsSet(EtherbaseFlag.Name) { - account, err := MakeAddress(ks, ctx.GlobalString(EtherbaseFlag.Name)) - if err != nil { - Fatalf("Option %q: %v", EtherbaseFlag.Name, err) + // Extract the current etherbase, new flag overriding legacy one + var etherbase string + if ctx.GlobalIsSet(MinerLegacyEtherbaseFlag.Name) { + etherbase = ctx.GlobalString(MinerLegacyEtherbaseFlag.Name) + } + if ctx.GlobalIsSet(MinerEtherbaseFlag.Name) { + etherbase = ctx.GlobalString(MinerEtherbaseFlag.Name) + } + // Convert the etherbase into an address and configure it + if etherbase != "" { + 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 } } @@ -789,20 +1042,43 @@ func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) { setBootstrapNodes(ctx, cfg) setBootstrapNodesV5(ctx, cfg) + lightClient := ctx.GlobalString(SyncModeFlag.Name) == "light" + lightServer := ctx.GlobalInt(LightServFlag.Name) != 0 + lightPeers := ctx.GlobalInt(LightPeersFlag.Name) + if ctx.GlobalIsSet(MaxPeersFlag.Name) { cfg.MaxPeers = ctx.GlobalInt(MaxPeersFlag.Name) + if lightServer && !ctx.GlobalIsSet(LightPeersFlag.Name) { + cfg.MaxPeers += lightPeers + } + } else { + if lightServer { + cfg.MaxPeers += lightPeers + } + if lightClient && ctx.GlobalIsSet(LightPeersFlag.Name) && cfg.MaxPeers < lightPeers { + cfg.MaxPeers = lightPeers + } } + if !(lightClient || lightServer) { + lightPeers = 0 + } + ethPeers := cfg.MaxPeers - lightPeers + if lightClient { + ethPeers = 0 + } + log.Info("Maximum peer count", "ETH", ethPeers, "LES", lightPeers, "total", cfg.MaxPeers) + if ctx.GlobalIsSet(MaxPendingPeersFlag.Name) { cfg.MaxPendingPeers = ctx.GlobalInt(MaxPendingPeersFlag.Name) } - if ctx.GlobalIsSet(NoDiscoverFlag.Name) || ctx.GlobalBool(LightModeFlag.Name) { + if ctx.GlobalIsSet(NoDiscoverFlag.Name) || lightClient { cfg.NoDiscovery = true } // if we're running a light client or server, force enable the v5 peer discovery // unless it is explicitly disabled with --nodiscover note that explicitly specifying // --v5disc overrides --nodiscover, in which case the later only disables v4 discovery - forceV5Discovery := (ctx.GlobalBool(LightModeFlag.Name) || ctx.GlobalInt(LightServFlag.Name) > 0) && !ctx.GlobalBool(NoDiscoverFlag.Name) + forceV5Discovery := (lightClient || lightServer) && !ctx.GlobalBool(NoDiscoverFlag.Name) if ctx.GlobalIsSet(DiscoveryV5Flag.Name) { cfg.DiscoveryV5 = ctx.GlobalBool(DiscoveryV5Flag.Name) } else if forceV5Discovery { @@ -831,18 +1107,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) { @@ -856,6 +1127,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) @@ -866,6 +1152,16 @@ func setGPO(ctx *cli.Context, cfg *gasprice.Config) { } func setTxPool(ctx *cli.Context, cfg *core.TxPoolConfig) { + if ctx.GlobalIsSet(TxPoolLocalsFlag.Name) { + locals := strings.Split(ctx.GlobalString(TxPoolLocalsFlag.Name), ",") + for _, account := range locals { + if trimmed := strings.TrimSpace(account); !common.IsHexAddress(trimmed) { + Fatalf("Invalid account in --txpool.locals: %s", trimmed) + } else { + cfg.Locals = append(cfg.Locals, common.HexToAddress(account)) + } + } + } if ctx.GlobalIsSet(TxPoolNoLocalsFlag.Name) { cfg.NoLocals = ctx.GlobalBool(TxPoolNoLocalsFlag.Name) } @@ -919,7 +1215,30 @@ func setEthash(ctx *cli.Context, cfg *eth.Config) { } } -// checkExclusive verifies that only a single isntance of the provided flags was +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. func checkExclusive(ctx *cli.Context, args ...interface{}) { @@ -936,11 +1255,14 @@ func checkExclusive(ctx *cli.Context, args ...interface{}) { if i+1 < len(args) { switch option := args[i+1].(type) { case string: - // Extended flag, expand the name and shift the arguments + // Extended flag check, make sure value set doesn't conflict with passed in option if ctx.GlobalString(flag.GetName()) == option { name += "=" + option + set = append(set, "--"+name) } + // shift arguments and continue i++ + continue case cli.Flag: default: @@ -965,62 +1287,107 @@ func SetShhConfig(ctx *cli.Context, stack *node.Node, cfg *whisper.Config) { if ctx.GlobalIsSet(WhisperMinPOWFlag.Name) { cfg.MinimumAcceptedPOW = ctx.GlobalFloat64(WhisperMinPOWFlag.Name) } + if ctx.GlobalIsSet(WhisperRestrictConnectionBetweenLightClientsFlag.Name) { + cfg.RestrictConnectionBetweenLightClients = true + } } // 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, FastSyncFlag, LightModeFlag, SyncModeFlag) - checkExclusive(ctx, LightServFlag, LightModeFlag) + 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) - switch { - case ctx.GlobalIsSet(SyncModeFlag.Name): + if ctx.GlobalIsSet(SyncModeFlag.Name) { cfg.SyncMode = *GlobalTextMarshaler(ctx, SyncModeFlag.Name).(*downloader.SyncMode) - case ctx.GlobalBool(FastSyncFlag.Name): - cfg.SyncMode = downloader.FastSync - case ctx.GlobalBool(LightModeFlag.Name): - cfg.SyncMode = downloader.LightSync } 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) { - cfg.DatabaseCache = ctx.GlobalInt(CacheFlag.Name) + if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheDatabaseFlag.Name) { + cfg.DatabaseCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100 } cfg.DatabaseHandles = makeDatabaseHandles() - if ctx.GlobalIsSet(MinerThreadsFlag.Name) { - cfg.MinerThreads = ctx.GlobalInt(MinerThreadsFlag.Name) + if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" { + Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name) + } + 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.TrieDirtyCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100 + } + if ctx.GlobalIsSet(MinerNotifyFlag.Name) { + cfg.MinerNotify = strings.Split(ctx.GlobalString(MinerNotifyFlag.Name), ",") } if ctx.GlobalIsSet(DocRootFlag.Name) { cfg.DocRoot = ctx.GlobalString(DocRootFlag.Name) } - if ctx.GlobalIsSet(ExtraDataFlag.Name) { - cfg.ExtraData = []byte(ctx.GlobalString(ExtraDataFlag.Name)) + if ctx.GlobalIsSet(MinerLegacyExtraDataFlag.Name) { + cfg.MinerExtraData = []byte(ctx.GlobalString(MinerLegacyExtraDataFlag.Name)) } - if ctx.GlobalIsSet(GasPriceFlag.Name) { - cfg.GasPrice = GlobalBig(ctx, GasPriceFlag.Name) + if ctx.GlobalIsSet(MinerExtraDataFlag.Name) { + cfg.MinerExtraData = []byte(ctx.GlobalString(MinerExtraDataFlag.Name)) + } + if ctx.GlobalIsSet(MinerLegacyGasTargetFlag.Name) { + cfg.MinerGasFloor = ctx.GlobalUint64(MinerLegacyGasTargetFlag.Name) + } + if ctx.GlobalIsSet(MinerGasTargetFlag.Name) { + cfg.MinerGasFloor = ctx.GlobalUint64(MinerGasTargetFlag.Name) + } + if ctx.GlobalIsSet(MinerGasLimitFlag.Name) { + cfg.MinerGasCeil = ctx.GlobalUint64(MinerGasLimitFlag.Name) + } + if ctx.GlobalIsSet(MinerLegacyGasPriceFlag.Name) { + cfg.MinerGasPrice = GlobalBig(ctx, MinerLegacyGasPriceFlag.Name) + } + if ctx.GlobalIsSet(MinerGasPriceFlag.Name) { + cfg.MinerGasPrice = GlobalBig(ctx, MinerGasPriceFlag.Name) + } + if ctx.GlobalIsSet(MinerRecommitIntervalFlag.Name) { + cfg.MinerRecommit = ctx.Duration(MinerRecommitIntervalFlag.Name) + } + if ctx.GlobalIsSet(MinerNoVerfiyFlag.Name) { + cfg.MinerNoverify = ctx.Bool(MinerNoVerfiyFlag.Name) } if ctx.GlobalIsSet(VMEnableDebugFlag.Name) { // TODO(fjl): force-enable this in --dev mode cfg.EnablePreimageRecording = ctx.GlobalBool(VMEnableDebugFlag.Name) } + if ctx.GlobalIsSet(EWASMInterpreterFlag.Name) { + cfg.EWASMInterpreter = ctx.GlobalString(EWASMInterpreterFlag.Name) + } + + if ctx.GlobalIsSet(EVMInterpreterFlag.Name) { + cfg.EVMInterpreter = ctx.GlobalString(EVMInterpreterFlag.Name) + } + // Override any default configs for hard coded networks. switch { case ctx.GlobalBool(TestnetFlag.Name): @@ -1033,7 +1400,15 @@ 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 + } // Create new developer account or reuse existing one var ( developer accounts.Account @@ -1053,8 +1428,8 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) { log.Info("Using developer account", "address", developer.Address) cfg.Genesis = core.DeveloperGenesisBlock(uint64(ctx.GlobalInt(DeveloperPeriodFlag.Name)), developer.Address) - if !ctx.GlobalIsSet(GasPriceFlag.Name) { - cfg.GasPrice = big.NewInt(1) + if !ctx.GlobalIsSet(MinerGasPriceFlag.Name) && !ctx.GlobalIsSet(MinerLegacyGasPriceFlag.Name) { + cfg.MinerGasPrice = big.NewInt(1) } } // TODO(fjl): move trie cache generations into config @@ -1068,7 +1443,6 @@ func SetDashboardConfig(ctx *cli.Context, cfg *dashboard.Config) { cfg.Host = ctx.GlobalString(DashboardAddrFlag.Name) cfg.Port = ctx.GlobalInt(DashboardPortFlag.Name) cfg.Refresh = ctx.GlobalDuration(DashboardRefreshFlag.Name) - cfg.Assets = ctx.GlobalString(DashboardAssetsFlag.Name) } // RegisterEthService adds an Ethereum client to the stack. @@ -1096,7 +1470,7 @@ func RegisterEthService(stack *node.Node, cfg *eth.Config) { // RegisterDashboardService adds a dashboard to the stack. func RegisterDashboardService(stack *node.Node, cfg *dashboard.Config, commit string) { stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { - return dashboard.New(cfg, commit) + return dashboard.New(cfg, commit, ctx.ResolvePath("logs")), nil }) } @@ -1110,7 +1484,7 @@ func RegisterShhService(stack *node.Node, cfg *whisper.Config) { } // RegisterEthStatsService configures the Ethereum Stats daemon and adds it to -// th egiven node. +// the given node. func RegisterEthStatsService(stack *node.Node, url string) { if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { // Retrieve both eth and les services @@ -1126,20 +1500,52 @@ func RegisterEthStatsService(stack *node.Node, url string) { } } -// SetupNetwork configures the system for either the main net or some test network. -func SetupNetwork(ctx *cli.Context) { - // TODO(fjl): move target gas limit into config - params.TargetGasLimit = ctx.GlobalUint64(TargetGasLimitFlag.Name) +func SetupMetrics(ctx *cli.Context) { + if metrics.Enabled { + log.Info("Enabling metrics collection") + var ( + enableExport = ctx.GlobalBool(MetricsEnableInfluxDBFlag.Name) + endpoint = ctx.GlobalString(MetricsInfluxDBEndpointFlag.Name) + database = ctx.GlobalString(MetricsInfluxDBDatabaseFlag.Name) + username = ctx.GlobalString(MetricsInfluxDBUsernameFlag.Name) + password = ctx.GlobalString(MetricsInfluxDBPasswordFlag.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.", 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 ( - cache = ctx.GlobalInt(CacheFlag.Name) + cache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100 handles = makeDatabaseHandles() ) name := "chaindata" - if ctx.GlobalBool(LightModeFlag.Name) { + if ctx.GlobalString(SyncModeFlag.Name) == "light" { name = "lightchaindata" } chainDb, err := stack.OpenDatabase(name, cache, handles) @@ -1156,6 +1562,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") } @@ -1166,7 +1574,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) @@ -1184,11 +1591,26 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai DatasetDir: stack.ResolvePath(eth.DefaultConfig.Ethash.DatasetDir), DatasetsInMem: eth.DefaultConfig.Ethash.DatasetsInMem, DatasetsOnDisk: eth.DefaultConfig.Ethash.DatasetsOnDisk, - }) + }, nil, false) } } + if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" { + Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name) + } + cache := &core.CacheConfig{ + 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.TrieDirtyLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100 + } vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)} - chain, err = core.NewBlockChain(chainDb, config, engine, vmcfg) + chain, err = core.NewBlockChain(chainDb, cache, config, engine, vmcfg, nil) if err != nil { Fatalf("Can't create BlockChain: %v", err) } @@ -1203,7 +1625,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/cmd/utils/flags_test.go b/cmd/utils/flags_test.go new file mode 100644 index 0000000000..adfdd0903e --- /dev/null +++ b/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/cmd/wnode/main.go b/cmd/wnode/main.go index e69b57d69f..97e5852013 100644 --- a/cmd/wnode/main.go +++ b/cmd/wnode/main.go @@ -22,6 +22,7 @@ package main import ( "bufio" "crypto/ecdsa" + crand "crypto/rand" "crypto/sha512" "encoding/binary" "encoding/hex" @@ -40,14 +41,15 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/discover" + "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/whisper/mailserver" - whisper "github.com/ethereum/go-ethereum/whisper/whisperv5" + whisper "github.com/ethereum/go-ethereum/whisper/whisperv6" "golang.org/x/crypto/pbkdf2" ) const quitCommand = "~Q" +const entropySize = 32 // singletons var ( @@ -55,33 +57,37 @@ var ( shh *whisper.Whisper done chan struct{} mailServer mailserver.WMailServer + entropy [entropySize]byte input = bufio.NewReader(os.Stdin) ) // encryption var ( - symKey []byte - pub *ecdsa.PublicKey - asymKey *ecdsa.PrivateKey - nodeid *ecdsa.PrivateKey - topic whisper.TopicType - asymKeyID string - filterID string - symPass string - msPassword string + symKey []byte + pub *ecdsa.PublicKey + asymKey *ecdsa.PrivateKey + nodeid *ecdsa.PrivateKey + topic whisper.TopicType + + asymKeyID string + asymFilterID string + symFilterID string + symPass string + msPassword string ) // cmd arguments var ( - bootstrapMode = flag.Bool("standalone", false, "boostrap node: don't actively connect to peers, wait for incoming connections") - forwarderMode = flag.Bool("forwarder", false, "forwarder mode: only forward messages, neither send nor decrypt messages") + bootstrapMode = flag.Bool("standalone", false, "boostrap node: don't initiate connection to peers, just wait for incoming connections") + forwarderMode = flag.Bool("forwarder", false, "forwarder mode: only forward messages, neither encrypt nor decrypt messages") mailServerMode = flag.Bool("mailserver", false, "mail server mode: delivers expired messages on demand") requestMail = flag.Bool("mailclient", false, "request expired messages from the bootstrap server") asymmetricMode = flag.Bool("asym", false, "use asymmetric encryption") generateKey = flag.Bool("generatekey", false, "generate and show the private key") fileExMode = flag.Bool("fileexchange", false, "file exchange mode") - testMode = flag.Bool("test", false, "use of predefined parameters for diagnostics") + fileReader = flag.Bool("filereader", false, "load and decrypt messages saved as files, display as plain text") + testMode = flag.Bool("test", false, "use of predefined parameters for diagnostics (password, etc.)") echoMode = flag.Bool("echo", false, "echo mode: prints some arguments for diagnostics") argVerbosity = flag.Int("verbosity", int(log.LvlError), "log verbosity level") @@ -97,13 +103,14 @@ var ( argIDFile = flag.String("idfile", "", "file name with node id (private key)") argEnode = flag.String("boot", "", "bootstrap node you want to connect to (e.g. enode://e454......08d50@52.176.211.200:16428)") argTopic = flag.String("topic", "", "topic in hexadecimal format (e.g. 70a4beef)") - argSaveDir = flag.String("savedir", "", "directory where incoming messages will be saved as files") + argSaveDir = flag.String("savedir", "", "directory where all incoming messages will be saved as files") ) func main() { processArgs() initialize() run() + shutdown() } func processArgs() { @@ -133,8 +140,8 @@ func processArgs() { } if *asymmetricMode && len(*argPub) > 0 { - pub = crypto.ToECDSAPub(common.FromHex(*argPub)) - if !isKeyValid(pub) { + var err error + if pub, err = crypto.UnmarshalPubkey(common.FromHex(*argPub)); err != nil { utils.Fatalf("invalid public key") } } @@ -168,7 +175,7 @@ func initialize() { log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*argVerbosity), log.StreamHandler(os.Stderr, log.TerminalFormat(false)))) done = make(chan struct{}) - var peers []*discover.Node + var peers []*enode.Node var err error if *generateKey { @@ -190,19 +197,16 @@ func initialize() { if len(*argIP) == 0 { argIP = scanLineA("Please enter your IP and port (e.g. 127.0.0.1:30348): ") } + } else if *fileReader { + *bootstrapMode = true } else { if len(*argEnode) == 0 { argEnode = scanLineA("Please enter the peer's enode: ") } - peer := discover.MustParseNode(*argEnode) + peer := enode.MustParseV4(*argEnode) peers = append(peers, peer) } - cfg := &whisper.Config{ - MaxMessageSize: uint32(*argMaxSize), - MinimumAcceptedPOW: *argPoW, - } - if *mailServerMode { if len(msPassword) == 0 { msPassword, err = console.Stdin.PromptPassword("Please enter the Mail Server password: ") @@ -210,14 +214,15 @@ func initialize() { utils.Fatalf("Failed to read Mail Server password: %s", err) } } - - shh = whisper.New(cfg) - shh.RegisterServer(&mailServer) - mailServer.Init(shh, *argDBPath, msPassword, *argServerPoW) - } else { - shh = whisper.New(cfg) } + cfg := &whisper.Config{ + MaxMessageSize: uint32(*argMaxSize), + MinimumAcceptedPOW: *argPoW, + } + + shh = whisper.New(cfg) + if *argPoW != whisper.DefaultMinimumPoW { err := shh.SetMinimumPoW(*argPoW) if err != nil { @@ -259,11 +264,23 @@ func initialize() { maxPeers = 800 } + _, err = crand.Read(entropy[:]) + if err != nil { + utils.Fatalf("crypto/rand failed: %s", err) + } + + if *mailServerMode { + shh.RegisterServer(&mailServer) + if err := mailServer.Init(shh, *argDBPath, msPassword, *argServerPoW); err != nil { + utils.Fatalf("Failed to init MailServer: %s", err) + } + } + server = &p2p.Server{ Config: p2p.Config{ PrivateKey: nodeid, MaxPeers: maxPeers, - Name: common.MakeName("wnode", "5.0"), + Name: common.MakeName("wnode", "6.0"), Protocols: shh.Protocols(), ListenAddr: *argIP, NAT: nat.Any(), @@ -274,10 +291,11 @@ func initialize() { } } -func startServer() { +func startServer() error { err := server.Start() if err != nil { - utils.Fatalf("Failed to start Whisper peer: %s.", err) + fmt.Printf("Failed to start Whisper peer: %s.", err) + return err } fmt.Printf("my public key: %s \n", common.ToHex(crypto.FromECDSAPub(&asymKey.PublicKey))) @@ -293,13 +311,14 @@ func startServer() { configureNode() } - if !*forwarderMode { + if *fileExMode { + fmt.Printf("Please type the file name to be send. To quit type: '%s'\n", quitCommand) + } else if *fileReader { + fmt.Printf("Please type the file name to be decrypted. To quit type: '%s'\n", quitCommand) + } else if !*forwarderMode { fmt.Printf("Please type the message. To quit type: '%s'\n", quitCommand) } -} - -func isKeyValid(k *ecdsa.PublicKey) bool { - return k.X != nil && k.Y != nil + return nil } func configureNode() { @@ -317,9 +336,8 @@ func configureNode() { if b == nil { utils.Fatalf("Error: can not convert hexadecimal string") } - pub = crypto.ToECDSAPub(b) - if !isKeyValid(pub) { - utils.Fatalf("Error: invalid public key") + if pub, err = crypto.UnmarshalPubkey(b); err != nil { + utils.Fatalf("Error: invalid peer public key") } } } @@ -363,13 +381,22 @@ func configureNode() { } } - filter := whisper.Filter{ + symFilter := whisper.Filter{ KeySym: symKey, + Topics: [][]byte{topic[:]}, + AllowP2P: p2pAccept, + } + symFilterID, err = shh.Subscribe(&symFilter) + if err != nil { + utils.Fatalf("Failed to install filter: %s", err) + } + + asymFilter := whisper.Filter{ KeyAsym: asymKey, Topics: [][]byte{topic[:]}, AllowP2P: p2pAccept, } - filterID, err = shh.Subscribe(&filter) + asymFilterID, err = shh.Subscribe(&asymFilter) if err != nil { utils.Fatalf("Failed to install filter: %s", err) } @@ -400,8 +427,10 @@ func waitForConnection(timeout bool) { } func run() { - defer mailServer.Close() - startServer() + err := startServer() + if err != nil { + return + } defer server.Stop() shh.Start(nil) defer shh.Stop() @@ -414,21 +443,26 @@ func run() { requestExpiredMessagesLoop() } else if *fileExMode { sendFilesLoop() + } else if *fileReader { + fileReaderLoop() } else { sendLoop() } } +func shutdown() { + close(done) + mailServer.Close() +} + func sendLoop() { for { s := scanLine("") if s == quitCommand { fmt.Println("Quit command received") - close(done) - break + return } sendMsg([]byte(s)) - if *asymmetricMode { // print your own message for convenience, // because in asymmetric mode it is impossible to decrypt it @@ -444,13 +478,11 @@ func sendFilesLoop() { s := scanLine("") if s == quitCommand { fmt.Println("Quit command received") - close(done) - break + return } b, err := ioutil.ReadFile(s) if err != nil { fmt.Printf(">>> Error: %s \n", err) - continue } else { h := sendMsg(b) if (h == common.Hash{}) { @@ -464,6 +496,38 @@ func sendFilesLoop() { } } +func fileReaderLoop() { + watcher1 := shh.GetFilter(symFilterID) + watcher2 := shh.GetFilter(asymFilterID) + if watcher1 == nil && watcher2 == nil { + fmt.Println("Error: neither symmetric nor asymmetric filter is installed") + return + } + + for { + s := scanLine("") + if s == quitCommand { + fmt.Println("Quit command received") + return + } + raw, err := ioutil.ReadFile(s) + if err != nil { + fmt.Printf(">>> Error: %s \n", err) + } else { + env := whisper.Envelope{Data: raw} // the topic is zero + msg := env.Open(watcher1) // force-open envelope regardless of the topic + if msg == nil { + msg = env.Open(watcher2) + } + if msg == nil { + fmt.Printf(">>> Error: failed to decrypt the message \n") + } else { + printMessageInfo(msg) + } + } + } +} + func scanLine(prompt string) string { if len(prompt) > 0 { fmt.Print(prompt) @@ -506,6 +570,7 @@ func sendMsg(payload []byte) common.Hash { if err != nil { utils.Fatalf("failed to create new message: %s", err) } + envelope, err := msg.Wrap(¶ms) if err != nil { fmt.Printf("failed to seal message: %v \n", err) @@ -522,9 +587,14 @@ func sendMsg(payload []byte) common.Hash { } func messageLoop() { - f := shh.GetFilter(filterID) - if f == nil { - utils.Fatalf("filter is not installed") + sf := shh.GetFilter(symFilterID) + if sf == nil { + utils.Fatalf("symmetric filter is not installed") + } + + af := shh.GetFilter(asymFilterID) + if af == nil { + utils.Fatalf("asymmetric filter is not installed") } ticker := time.NewTicker(time.Millisecond * 50) @@ -532,12 +602,21 @@ func messageLoop() { for { select { case <-ticker.C: - messages := f.Retrieve() + m1 := sf.Retrieve() + m2 := af.Retrieve() + messages := append(m1, m2...) for _, msg := range messages { - if *fileExMode || len(msg.Payload) > 2048 { - writeMessageToFile(*argSaveDir, msg) - } else { + reportedOnce := false + if !*fileExMode && len(msg.Payload) <= 2048 { printMessageInfo(msg) + reportedOnce = true + } + + // All messages are saved upon specifying argSaveDir. + // fileExMode only specifies how messages are displayed on the console after they are saved. + // if fileExMode == true, only the hashes are displayed, since messages might be too big. + if len(*argSaveDir) > 0 { + writeMessageToFile(*argSaveDir, msg, !reportedOnce) } } case <-done: @@ -562,7 +641,11 @@ func printMessageInfo(msg *whisper.ReceivedMessage) { } } -func writeMessageToFile(dir string, msg *whisper.ReceivedMessage) { +func writeMessageToFile(dir string, msg *whisper.ReceivedMessage, show bool) { + if len(dir) == 0 { + return + } + timestamp := fmt.Sprintf("%d", msg.Sent) name := fmt.Sprintf("%x", msg.EnvelopeHash) @@ -571,27 +654,32 @@ func writeMessageToFile(dir string, msg *whisper.ReceivedMessage) { address = crypto.PubkeyToAddress(*msg.Src) } - if whisper.IsPubKeyEqual(msg.Src, &asymKey.PublicKey) { - // message from myself: don't save, only report - fmt.Printf("\n%s <%x>: message received: '%s'\n", timestamp, address, name) - } else if len(dir) > 0 { - fullpath := filepath.Join(dir, name) - err := ioutil.WriteFile(fullpath, msg.Payload, 0644) - if err != nil { - fmt.Printf("\n%s {%x}: message received but not saved: %s\n", timestamp, address, err) - } else { - fmt.Printf("\n%s {%x}: message received and saved as '%s' (%d bytes)\n", timestamp, address, name, len(msg.Payload)) - } - } else { - fmt.Printf("\n%s {%x}: big message received (%d bytes), but not saved: %s\n", timestamp, address, len(msg.Payload), name) + env := shh.GetEnvelope(msg.EnvelopeHash) + if env == nil { + fmt.Printf("\nUnexpected error: envelope not found: %x\n", msg.EnvelopeHash) + return + } + + // this is a sample code; uncomment if you don't want to save your own messages. + //if whisper.IsPubKeyEqual(msg.Src, &asymKey.PublicKey) { + // fmt.Printf("\n%s <%x>: message from myself received, not saved: '%s'\n", timestamp, address, name) + // return + //} + + fullpath := filepath.Join(dir, name) + err := ioutil.WriteFile(fullpath, env.Data, 0644) + if err != nil { + fmt.Printf("\n%s {%x}: message received but not saved: %s\n", timestamp, address, err) + } else if show { + fmt.Printf("\n%s {%x}: message received and saved as '%s' (%d bytes)\n", timestamp, address, name, len(env.Data)) } } func requestExpiredMessagesLoop() { - var key, peerID []byte + var key, peerID, bloom []byte var timeLow, timeUpp uint32 var t string - var xt, empty whisper.TopicType + var xt whisper.TopicType keyID, err := shh.AddSymKeyFromPassword(msPassword) if err != nil { @@ -607,31 +695,37 @@ func requestExpiredMessagesLoop() { for { timeLow = scanUint("Please enter the lower limit of the time range (unix timestamp): ") timeUpp = scanUint("Please enter the upper limit of the time range (unix timestamp): ") - t = scanLine("Please enter the topic (hexadecimal): ") - if len(t) >= whisper.TopicLength*2 { + t = scanLine("Enter the topic (hex). Press enter to request all messages, regardless of the topic: ") + if len(t) == whisper.TopicLength*2 { x, err := hex.DecodeString(t) if err != nil { - utils.Fatalf("Failed to parse the topic: %s", err) + fmt.Printf("Failed to parse the topic: %s \n", err) + continue } xt = whisper.BytesToTopic(x) + bloom = whisper.TopicToBloom(xt) + obfuscateBloom(bloom) + } else if len(t) == 0 { + bloom = whisper.MakeFullNodeBloom() + } else { + fmt.Println("Error: topic is invalid, request aborted") + continue } + if timeUpp == 0 { timeUpp = 0xFFFFFFFF } - data := make([]byte, 8+whisper.TopicLength) + data := make([]byte, 8, 8+whisper.BloomFilterSize) binary.BigEndian.PutUint32(data, timeLow) binary.BigEndian.PutUint32(data[4:], timeUpp) - copy(data[8:], xt[:]) - if xt == empty { - data = data[:8] - } + data = append(data, bloom...) var params whisper.MessageParams params.PoW = *argServerPoW params.Payload = data params.KeySym = key - params.Src = nodeid + params.Src = asymKey params.WorkTime = 5 msg, err := whisper.NewSentMessage(¶ms) @@ -653,9 +747,26 @@ func requestExpiredMessagesLoop() { } func extractIDFromEnode(s string) []byte { - n, err := discover.ParseNode(s) + n, err := enode.ParseV4(s) if err != nil { utils.Fatalf("Failed to parse enode: %s", err) } - return n.ID[:] + return n.ID().Bytes() +} + +// obfuscateBloom adds 16 random bits to the bloom +// filter, in order to obfuscate the containing topics. +// it does so deterministically within every session. +// despite additional bits, it will match on average +// 32000 times less messages than full node's bloom filter. +func obfuscateBloom(bloom []byte) { + const half = entropySize / 2 + for i := 0; i < half; i++ { + x := int(entropy[i]) + if entropy[half+i] < 128 { + x += 256 + } + + bloom[x/8] = 1 << uint(x%8) // set the bit number X + } } diff --git a/common/big.go b/common/big.go index b552608bc7..65d4377bf7 100644 --- a/common/big.go +++ b/common/big.go @@ -25,6 +25,6 @@ var ( Big3 = big.NewInt(3) Big0 = big.NewInt(0) Big32 = big.NewInt(32) - Big256 = big.NewInt(0xff) + Big256 = big.NewInt(256) Big257 = big.NewInt(257) ) diff --git a/common/bitutil/compress_test.go b/common/bitutil/compress_test.go index 9bd1de103a..13a13011dc 100644 --- a/common/bitutil/compress_test.go +++ b/common/bitutil/compress_test.go @@ -117,7 +117,7 @@ func TestDecodingCycle(t *testing.T) { // TestCompression tests that compression works by returning either the bitset // encoded input, or the actual input if the bitset version is longer. func TestCompression(t *testing.T) { - // Check the the compression returns the bitset encoding is shorter + // Check the compression returns the bitset encoding is shorter in := hexutil.MustDecode("0x4912385c0e7b64000000") out := hexutil.MustDecode("0x80fe4912385c0e7b64") @@ -127,7 +127,7 @@ func TestCompression(t *testing.T) { if data, err := DecompressBytes(out, len(in)); err != nil || !bytes.Equal(data, in) { t.Errorf("decoding mismatch for sparse data: have %x, want %x, error %v", data, in, err) } - // Check the the compression returns the input if the bitset encoding is longer + // Check the compression returns the input if the bitset encoding is longer in = hexutil.MustDecode("0xdf7070533534333636313639343638373532313536346c1bc33339343837313070706336343035336336346c65fefb3930393233383838ac2f65fefb") out = hexutil.MustDecode("0xdf7070533534333636313639343638373532313536346c1bc33339343837313070706336343035336336346c65fefb3930393233383838ac2f65fefb") diff --git a/common/bytes.go b/common/bytes.go index ba00e8a4b2..c82e616241 100644 --- a/common/bytes.go +++ b/common/bytes.go @@ -19,15 +19,29 @@ package common import "encoding/hex" +// ToHex returns the hex representation of b, prefixed with '0x'. +// For empty slices, the return value is "0x0". +// +// Deprecated: use hexutil.Encode instead. func ToHex(b []byte) string { hex := Bytes2Hex(b) - // Prefer output of "0x0" instead of "0x" if len(hex) == 0 { hex = "0" } return "0x" + hex } +// ToHexArray creates a array of hex-string based on []byte +func ToHexArray(b [][]byte) []string { + r := make([]string, len(b)) + for i := range b { + r[i] = ToHex(b[i]) + } + return r +} + +// FromHex returns the bytes represented by the hexadecimal string s. +// s may be prefixed with "0x". func FromHex(s string) []byte { if len(s) > 1 { if s[0:2] == "0x" || s[0:2] == "0X" { @@ -40,9 +54,7 @@ func FromHex(s string) []byte { return Hex2Bytes(s) } -// Copy bytes -// -// Returns an exact copy of the provided bytes +// CopyBytes returns an exact copy of the provided bytes. func CopyBytes(b []byte) (copiedBytes []byte) { if b == nil { return nil @@ -53,14 +65,17 @@ func CopyBytes(b []byte) (copiedBytes []byte) { return } +// hasHexPrefix validates str begins with '0x' or '0X'. func hasHexPrefix(str string) bool { return len(str) >= 2 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X') } +// isHexCharacter returns bool of c being a valid hexadecimal. func isHexCharacter(c byte) bool { return ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F') } +// isHex validates whether each byte is valid hexadecimal string. func isHex(str string) bool { if len(str)%2 != 0 { return false @@ -73,31 +88,32 @@ func isHex(str string) bool { return true } +// Bytes2Hex returns the hexadecimal encoding of d. func Bytes2Hex(d []byte) string { return hex.EncodeToString(d) } +// Hex2Bytes returns the bytes represented by the hexadecimal string str. func Hex2Bytes(str string) []byte { h, _ := hex.DecodeString(str) - return h } +// Hex2BytesFixed returns bytes of a specified fixed length flen. func Hex2BytesFixed(str string, flen int) []byte { h, _ := hex.DecodeString(str) if len(h) == flen { return h - } else { - if len(h) > flen { - return h[len(h)-flen:] - } else { - hh := make([]byte, flen) - copy(hh[flen-len(h):flen], h[:]) - return hh - } } + if len(h) > flen { + return h[len(h)-flen:] + } + hh := make([]byte, flen) + copy(hh[flen-len(h):flen], h) + return hh } +// RightPadBytes zero-pads slice to the right up to length l. func RightPadBytes(slice []byte, l int) []byte { if l <= len(slice) { return slice @@ -109,6 +125,7 @@ func RightPadBytes(slice []byte, l int) []byte { return padded } +// LeftPadBytes zero-pads slice to the left up to length l. func LeftPadBytes(slice []byte, l int) []byte { if l <= len(slice) { return slice diff --git a/common/compiler/solidity.go b/common/compiler/solidity.go index abb8039896..b7c8ec5638 100644 --- a/common/compiler/solidity.go +++ b/common/compiler/solidity.go @@ -31,17 +31,26 @@ import ( 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"` - Info ContractInfo `json:"info"` + 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"` @@ -57,15 +66,16 @@ type Solidity struct { // --combined-output format type solcOutput struct { Contracts map[string]struct { - Bin, Abi, Devdoc, Userdoc, Metadata string + BinRuntime string `json:"bin-runtime"` + SrcMapRuntime string `json:"srcmap-runtime"` + Bin, SrcMap, Abi, Devdoc, Userdoc, Metadata string } Version string } func (s *Solidity) makeArgs() []string { p := []string{ - "--combined-json", "bin,abi,userdoc,devdoc", - "--add-std", // include standard lib contracts + "--combined-json", "bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc", "--optimize", // code optimizer switched on } if s.Major > 0 || s.Minor > 4 || s.Patch > 6 { @@ -143,8 +153,22 @@ func (s *Solidity) run(cmd *exec.Cmd, source string) (map[string]*Contract, erro if err := cmd.Run(); err != nil { return nil, fmt.Errorf("solc: %v\n%s", err, stderr.Bytes()) } + + return ParseCombinedJSON(stdout.Bytes(), source, s.Version, s.Version, strings.Join(s.makeArgs(), " ")) +} + +// ParseCombinedJSON takes the direct output of a solc --combined-output 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 solc output is expected to contain ABI, source mapping, user docs, and dev docs. +// +// Returns an error if the JSON is malformed or missing data, or if the JSON +// embedded within the JSON is malformed. +func ParseCombinedJSON(combinedJSON []byte, source string, languageVersion string, compilerVersion string, compilerOptions string) (map[string]*Contract, error) { var output solcOutput - if err := json.Unmarshal(stdout.Bytes(), &output); err != nil { + if err := json.Unmarshal(combinedJSON, &output); err != nil { return nil, err } @@ -165,13 +189,16 @@ func (s *Solidity) run(cmd *exec.Cmd, source string) (map[string]*Contract, erro return nil, fmt.Errorf("solc: error reading dev doc: %v", err) } contracts[name] = &Contract{ - Code: "0x" + info.Bin, + Code: "0x" + info.Bin, + RuntimeCode: "0x" + info.BinRuntime, Info: ContractInfo{ Source: source, Language: "Solidity", - LanguageVersion: s.Version, - CompilerVersion: s.Version, - CompilerOptions: strings.Join(s.makeArgs(), " "), + LanguageVersion: languageVersion, + CompilerVersion: compilerVersion, + CompilerOptions: compilerOptions, + SrcMap: info.SrcMap, + SrcMapRuntime: info.SrcMapRuntime, AbiDefinition: abi, UserDoc: userdoc, DeveloperDoc: devdoc, diff --git a/common/compiler/solidity_test.go b/common/compiler/solidity_test.go index 0da3bb337e..cb954b720e 100644 --- a/common/compiler/solidity_test.go +++ b/common/compiler/solidity_test.go @@ -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; } } diff --git a/common/fdlimit/fdlimit_darwin.go b/common/fdlimit/fdlimit_darwin.go new file mode 100644 index 0000000000..88dd0f56cb --- /dev/null +++ b/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/common/fdlimit/fdlimit_freebsd.go b/common/fdlimit/fdlimit_freebsd.go index 25caaafe21..0d8727138e 100644 --- a/common/fdlimit/fdlimit_freebsd.go +++ b/common/fdlimit/fdlimit_freebsd.go @@ -1,18 +1,18 @@ // Copyright 2016 The go-ethereum Authors -// This file is part of go-ethereum. +// This file is part of the go-ethereum library. // -// 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 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. // -// go-ethereum is distributed in the hope that it will be useful, +// 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 General Public License for more details. +// GNU Lesser 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 . +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . // +build freebsd @@ -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/common/fdlimit/fdlimit_test.go b/common/fdlimit/fdlimit_test.go index 05e9f0b658..21362b8463 100644 --- a/common/fdlimit/fdlimit_test.go +++ b/common/fdlimit/fdlimit_test.go @@ -1,18 +1,18 @@ // Copyright 2016 The go-ethereum Authors -// This file is part of go-ethereum. +// This file is part of the go-ethereum library. // -// 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 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. // -// go-ethereum is distributed in the hope that it will be useful, +// 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 General Public License for more details. +// GNU Lesser 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 . +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . package fdlimit @@ -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/common/fdlimit/fdlimit_unix.go b/common/fdlimit/fdlimit_unix.go index 27c7e783f7..e5a575f7a7 100644 --- a/common/fdlimit/fdlimit_unix.go +++ b/common/fdlimit/fdlimit_unix.go @@ -1,20 +1,20 @@ // Copyright 2016 The go-ethereum Authors -// This file is part of go-ethereum. +// This file is part of the go-ethereum library. // -// 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 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. // -// go-ethereum is distributed in the hope that it will be useful, +// 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 General Public License for more details. +// GNU Lesser 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 . +// 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/common/fdlimit/fdlimit_windows.go b/common/fdlimit/fdlimit_windows.go index efcd3220ea..f472153662 100644 --- a/common/fdlimit/fdlimit_windows.go +++ b/common/fdlimit/fdlimit_windows.go @@ -1,43 +1,46 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of go-ethereum. +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. // -// 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 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. // -// go-ethereum is distributed in the hope that it will be useful, +// 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 General Public License for more details. +// GNU Lesser 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 . +// 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 "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/common/format.go b/common/format.go index fccc299620..6fc21af719 100644 --- a/common/format.go +++ b/common/format.go @@ -38,3 +38,45 @@ func (d PrettyDuration) String() string { } return label } + +// PrettyAge is a pretty printed version of a time.Duration value that rounds +// the values up to a single most significant unit, days/weeks/years included. +type PrettyAge time.Time + +// ageUnits is a list of units the age pretty printing uses. +var ageUnits = []struct { + Size time.Duration + Symbol string +}{ + {12 * 30 * 24 * time.Hour, "y"}, + {30 * 24 * time.Hour, "mo"}, + {7 * 24 * time.Hour, "w"}, + {24 * time.Hour, "d"}, + {time.Hour, "h"}, + {time.Minute, "m"}, + {time.Second, "s"}, +} + +// String implements the Stringer interface, allowing pretty printing of duration +// values rounded to the most significant time unit. +func (t PrettyAge) String() string { + // Calculate the time difference and handle the 0 cornercase + diff := time.Since(time.Time(t)) + if diff < time.Second { + return "0" + } + // Accumulate a precision of 3 components before returning + result, prec := "", 0 + + for _, unit := range ageUnits { + if diff > unit.Size { + result = fmt.Sprintf("%s%d%s", result, diff/unit.Size, unit.Symbol) + diff %= unit.Size + + if prec += 1; prec >= 3 { + break + } + } + } + return result +} diff --git a/common/hexutil/hexutil.go b/common/hexutil/hexutil.go index 02c488a3f1..46223a2815 100644 --- a/common/hexutil/hexutil.go +++ b/common/hexutil/hexutil.go @@ -39,6 +39,7 @@ import ( const uintBits = 32 << (uint64(^uint(0)) >> 63) +// Errors var ( ErrEmptyString = &decError{"empty hex string"} ErrSyntax = &decError{"invalid hex string"} diff --git a/common/hexutil/json.go b/common/hexutil/json.go index fbc21241c8..777b08eca4 100644 --- a/common/hexutil/json.go +++ b/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/common/math/big.go b/common/math/big.go index 7872786503..9d2e7946d1 100644 --- a/common/math/big.go +++ b/common/math/big.go @@ -22,12 +22,13 @@ import ( "math/big" ) +// Various big integer limit values. var ( tt255 = BigPow(2, 255) tt256 = BigPow(2, 256) tt256m1 = new(big.Int).Sub(tt256, big.NewInt(1)) - MaxBig256 = new(big.Int).Set(tt256m1) tt63 = BigPow(2, 63) + MaxBig256 = new(big.Int).Set(tt256m1) MaxBig63 = new(big.Int).Sub(tt63, big.NewInt(1)) ) @@ -78,7 +79,7 @@ func ParseBig256(s string) (*big.Int, bool) { return bigint, ok } -// MustParseBig parses s as a 256 bit big integer and panics if the string is invalid. +// MustParseBig256 parses s as a 256 bit big integer and panics if the string is invalid. func MustParseBig256(s string) *big.Int { v, ok := ParseBig256(s) if !ok { @@ -186,9 +187,8 @@ func U256(x *big.Int) *big.Int { func S256(x *big.Int) *big.Int { if x.Cmp(tt255) < 0 { return x - } else { - return new(big.Int).Sub(x, tt256) } + return new(big.Int).Sub(x, tt256) } // Exp implements exponentiation by squaring. diff --git a/common/math/integer.go b/common/math/integer.go index 7eff4d3b00..93b1d036dd 100644 --- a/common/math/integer.go +++ b/common/math/integer.go @@ -21,8 +21,8 @@ import ( "strconv" ) +// Integer limit values. const ( - // Integer limit values. MaxInt8 = 1<<7 - 1 MinInt8 = -1 << 7 MaxInt16 = 1<<15 - 1 diff --git a/common/mclock/mclock.go b/common/mclock/mclock.go index 92005252eb..dcac59c6ce 100644 --- a/common/mclock/mclock.go +++ b/common/mclock/mclock.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 . -// package mclock is a wrapper for a monotonic clock source +// Package mclock is a wrapper for a monotonic clock source package mclock import ( @@ -23,8 +23,41 @@ import ( "github.com/aristanetworks/goarista/monotime" ) -type AbsTime time.Duration // absolute monotonic time +// AbsTime represents absolute monotonic time. +type AbsTime time.Duration +// Now returns the current absolute monotonic time. func Now() AbsTime { return AbsTime(monotime.Now()) } + +// Add returns t + d. +func (t AbsTime) Add(d time.Duration) AbsTime { + return t + AbsTime(d) +} + +// Clock interface makes it possible to replace the monotonic system clock with +// a simulated clock. +type Clock interface { + Now() AbsTime + Sleep(time.Duration) + After(time.Duration) <-chan time.Time +} + +// System implements Clock using the system clock. +type System struct{} + +// Now implements Clock. +func (System) Now() AbsTime { + return AbsTime(monotime.Now()) +} + +// Sleep implements Clock. +func (System) Sleep(d time.Duration) { + time.Sleep(d) +} + +// After implements Clock. +func (System) After(d time.Duration) <-chan time.Time { + return time.After(d) +} diff --git a/common/mclock/simclock.go b/common/mclock/simclock.go new file mode 100644 index 0000000000..e014f56150 --- /dev/null +++ b/common/mclock/simclock.go @@ -0,0 +1,129 @@ +// 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 mclock + +import ( + "sync" + "time" +) + +// Simulated implements a virtual Clock for reproducible time-sensitive tests. It +// simulates a scheduler on a virtual timescale where actual processing takes zero time. +// +// The virtual clock doesn't advance on its own, call Run to advance it and execute timers. +// Since there is no way to influence the Go scheduler, testing timeout behaviour involving +// goroutines needs special care. A good way to test such timeouts is as follows: First +// perform the action that is supposed to time out. Ensure that the timer you want to test +// is created. Then run the clock until after the timeout. Finally observe the effect of +// the timeout using a channel or semaphore. +type Simulated struct { + now AbsTime + scheduled []event + mu sync.RWMutex + cond *sync.Cond +} + +type event struct { + do func() + at AbsTime +} + +// Run moves the clock by the given duration, executing all timers before that duration. +func (s *Simulated) Run(d time.Duration) { + s.mu.Lock() + defer s.mu.Unlock() + s.init() + + end := s.now + AbsTime(d) + for len(s.scheduled) > 0 { + ev := s.scheduled[0] + if ev.at > end { + break + } + s.now = ev.at + ev.do() + s.scheduled = s.scheduled[1:] + } + s.now = end +} + +func (s *Simulated) ActiveTimers() int { + s.mu.RLock() + defer s.mu.RUnlock() + + return len(s.scheduled) +} + +func (s *Simulated) WaitForTimers(n int) { + s.mu.Lock() + defer s.mu.Unlock() + s.init() + + for len(s.scheduled) < n { + s.cond.Wait() + } +} + +// Now implements Clock. +func (s *Simulated) Now() AbsTime { + s.mu.RLock() + defer s.mu.RUnlock() + + return s.now +} + +// Sleep implements Clock. +func (s *Simulated) Sleep(d time.Duration) { + <-s.After(d) +} + +// After implements Clock. +func (s *Simulated) After(d time.Duration) <-chan time.Time { + after := make(chan time.Time, 1) + s.insert(d, func() { + after <- (time.Time{}).Add(time.Duration(s.now)) + }) + return after +} + +func (s *Simulated) insert(d time.Duration, do func()) { + s.mu.Lock() + defer s.mu.Unlock() + s.init() + + at := s.now + AbsTime(d) + l, h := 0, len(s.scheduled) + ll := h + for l != h { + m := (l + h) / 2 + if at < s.scheduled[m].at { + h = m + } else { + l = m + 1 + } + } + s.scheduled = append(s.scheduled, event{}) + copy(s.scheduled[l+1:], s.scheduled[l:ll]) + s.scheduled[l] = event{do: do, at: at} + s.cond.Broadcast() +} + +func (s *Simulated) init() { + if s.cond == nil { + s.cond = sync.NewCond(&s.mu) + } +} diff --git a/common/number/int.go b/common/number/int.go deleted file mode 100644 index 6dab2436de..0000000000 --- a/common/number/int.go +++ /dev/null @@ -1,197 +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 number - -import ( - "math/big" - - "github.com/ethereum/go-ethereum/common" -) - -var tt256 = new(big.Int).Lsh(big.NewInt(1), 256) -var tt256m1 = new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(1)) -var tt255 = new(big.Int).Lsh(big.NewInt(1), 255) - -func limitUnsigned256(x *Number) *Number { - x.num.And(x.num, tt256m1) - return x -} - -func limitSigned256(x *Number) *Number { - if x.num.Cmp(tt255) < 0 { - return x - } else { - x.num.Sub(x.num, tt256) - return x - } -} - -// Number function -type Initialiser func(n int64) *Number - -// A Number represents a generic integer with a bounding function limiter. Limit is called after each operations -// to give "fake" bounded integers. New types of Number can be created through NewInitialiser returning a lambda -// with the new Initialiser. -type Number struct { - num *big.Int - limit func(n *Number) *Number -} - -// Returns a new initialiser for a new *Number without having to expose certain fields -func NewInitialiser(limiter func(*Number) *Number) Initialiser { - return func(n int64) *Number { - return &Number{big.NewInt(n), limiter} - } -} - -// Return a Number with a UNSIGNED limiter up to 256 bits -func Uint256(n int64) *Number { - return &Number{big.NewInt(n), limitUnsigned256} -} - -// Return a Number with a SIGNED limiter up to 256 bits -func Int256(n int64) *Number { - return &Number{big.NewInt(n), limitSigned256} -} - -// Returns a Number with a SIGNED unlimited size -func Big(n int64) *Number { - return &Number{big.NewInt(n), func(x *Number) *Number { return x }} -} - -// Sets i to sum of x+y -func (i *Number) Add(x, y *Number) *Number { - i.num.Add(x.num, y.num) - return i.limit(i) -} - -// Sets i to difference of x-y -func (i *Number) Sub(x, y *Number) *Number { - i.num.Sub(x.num, y.num) - return i.limit(i) -} - -// Sets i to product of x*y -func (i *Number) Mul(x, y *Number) *Number { - i.num.Mul(x.num, y.num) - return i.limit(i) -} - -// Sets i to the quotient prodject of x/y -func (i *Number) Div(x, y *Number) *Number { - i.num.Div(x.num, y.num) - return i.limit(i) -} - -// Sets i to x % y -func (i *Number) Mod(x, y *Number) *Number { - i.num.Mod(x.num, y.num) - return i.limit(i) -} - -// Sets i to x << s -func (i *Number) Lsh(x *Number, s uint) *Number { - i.num.Lsh(x.num, s) - return i.limit(i) -} - -// Sets i to x^y -func (i *Number) Pow(x, y *Number) *Number { - i.num.Exp(x.num, y.num, big.NewInt(0)) - return i.limit(i) -} - -// Setters - -// Set x to i -func (i *Number) Set(x *Number) *Number { - i.num.Set(x.num) - return i.limit(i) -} - -// Set x bytes to i -func (i *Number) SetBytes(x []byte) *Number { - i.num.SetBytes(x) - return i.limit(i) -} - -// Cmp compares x and y and returns: -// -// -1 if x < y -// 0 if x == y -// +1 if x > y -func (i *Number) Cmp(x *Number) int { - return i.num.Cmp(x.num) -} - -// Getters - -// Returns the string representation of i -func (i *Number) String() string { - return i.num.String() -} - -// Returns the byte representation of i -func (i *Number) Bytes() []byte { - return i.num.Bytes() -} - -// Uint64 returns the Uint64 representation of x. If x cannot be represented in an int64, the result is undefined. -func (i *Number) Uint64() uint64 { - return i.num.Uint64() -} - -// Int64 returns the int64 representation of x. If x cannot be represented in an int64, the result is undefined. -func (i *Number) Int64() int64 { - return i.num.Int64() -} - -// Returns the signed version of i -func (i *Number) Int256() *Number { - return Int(0).Set(i) -} - -// Returns the unsigned version of i -func (i *Number) Uint256() *Number { - return Uint(0).Set(i) -} - -// Returns the index of the first bit that's set to 1 -func (i *Number) FirstBitSet() int { - for j := 0; j < i.num.BitLen(); j++ { - if i.num.Bit(j) > 0 { - return j - } - } - - return i.num.BitLen() -} - -// Variables - -var ( - Zero = Uint(0) - One = Uint(1) - Two = Uint(2) - MaxUint256 = Uint(0).SetBytes(common.Hex2Bytes("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) - - MinOne = Int(-1) - - // "typedefs" - Uint = Uint256 - Int = Int256 -) diff --git a/common/number/uint_test.go b/common/number/uint_test.go deleted file mode 100644 index 3ab9e4c344..0000000000 --- a/common/number/uint_test.go +++ /dev/null @@ -1,108 +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 number - -import ( - "math/big" - "testing" - - "github.com/ethereum/go-ethereum/common" -) - -func TestSet(t *testing.T) { - a := Uint(0) - b := Uint(10) - a.Set(b) - if a.num.Cmp(b.num) != 0 { - t.Error("didn't compare", a, b) - } - - c := Uint(0).SetBytes(common.Hex2Bytes("0a")) - if c.num.Cmp(big.NewInt(10)) != 0 { - t.Error("c set bytes failed.") - } -} - -func TestInitialiser(t *testing.T) { - check := false - init := NewInitialiser(func(x *Number) *Number { - check = true - return x - }) - a := init(0).Add(init(1), init(2)) - if a.Cmp(init(3)) != 0 { - t.Error("expected 3. got", a) - } - if !check { - t.Error("expected limiter to be called") - } -} - -func TestGet(t *testing.T) { - a := Uint(10) - if a.Uint64() != 10 { - t.Error("expected to get 10. got", a.Uint64()) - } - - a = Uint(10) - if a.Int64() != 10 { - t.Error("expected to get 10. got", a.Int64()) - } -} - -func TestCmp(t *testing.T) { - a := Uint(10) - b := Uint(10) - c := Uint(11) - - if a.Cmp(b) != 0 { - t.Error("a b == 0 failed", a, b) - } - - if a.Cmp(c) >= 0 { - t.Error("a c < 0 failed", a, c) - } - - if c.Cmp(b) <= 0 { - t.Error("c b > 0 failed", c, b) - } -} - -func TestMaxArith(t *testing.T) { - a := Uint(0).Add(MaxUint256, One) - if a.Cmp(Zero) != 0 { - t.Error("expected max256 + 1 = 0 got", a) - } - - a = Uint(0).Sub(Uint(0), One) - if a.Cmp(MaxUint256) != 0 { - t.Error("expected 0 - 1 = max256 got", a) - } - - a = Int(0).Sub(Int(0), One) - if a.Cmp(MinOne) != 0 { - t.Error("expected 0 - 1 = -1 got", a) - } -} - -func TestConversion(t *testing.T) { - a := Int(-1) - b := a.Uint256() - if b.Cmp(MaxUint256) != 0 { - t.Error("expected -1 => unsigned to return max. got", b) - } -} diff --git a/common/path.go b/common/path.go index bd8da86e74..69820cfe5d 100644 --- a/common/path.go +++ b/common/path.go @@ -30,6 +30,7 @@ func MakeName(name, version string) string { return fmt.Sprintf("%s/v%s/%s/%s", name, version, runtime.GOOS, runtime.Version()) } +// FileExist checks if a file exists at filePath. func FileExist(filePath string) bool { _, err := os.Stat(filePath) if err != nil && os.IsNotExist(err) { @@ -39,9 +40,10 @@ func FileExist(filePath string) bool { return true } -func AbsolutePath(Datadir string, filename string) string { +// AbsolutePath returns datadir + filename, or filename if it is absolute. +func AbsolutePath(datadir string, filename string) string { if filepath.IsAbs(filename) { return filename } - return filepath.Join(Datadir, filename) + return filepath.Join(datadir, filename) } diff --git a/common/prque/prque.go b/common/prque/prque.go new file mode 100755 index 0000000000..9fd31a2e5d --- /dev/null +++ b/common/prque/prque.go @@ -0,0 +1,57 @@ +// This is a duplicated and slightly modified version of "gopkg.in/karalabe/cookiejar.v2/collections/prque". + +package prque + +import ( + "container/heap" +) + +// Priority queue data structure. +type Prque struct { + cont *sstack +} + +// Creates a new priority queue. +func New(setIndex setIndexCallback) *Prque { + return &Prque{newSstack(setIndex)} +} + +// Pushes a value with a given priority into the queue, expanding if necessary. +func (p *Prque) Push(data interface{}, priority int64) { + heap.Push(p.cont, &item{data, priority}) +} + +// Pops the value with the greates priority off the stack and returns it. +// Currently no shrinking is done. +func (p *Prque) Pop() (interface{}, int64) { + item := heap.Pop(p.cont).(*item) + return item.value, item.priority +} + +// Pops only the item from the queue, dropping the associated priority value. +func (p *Prque) PopItem() interface{} { + return heap.Pop(p.cont).(*item).value +} + +// Remove removes the element with the given index. +func (p *Prque) Remove(i int) interface{} { + if i < 0 { + return nil + } + return heap.Remove(p.cont, i) +} + +// Checks whether the priority queue is empty. +func (p *Prque) Empty() bool { + return p.cont.Len() == 0 +} + +// Returns the number of element in the priority queue. +func (p *Prque) Size() int { + return p.cont.Len() +} + +// Clears the contents of the priority queue. +func (p *Prque) Reset() { + *p = *New(p.cont.setIndex) +} diff --git a/vendor/gopkg.in/karalabe/cookiejar.v2/collections/prque/sstack.go b/common/prque/sstack.go similarity index 62% rename from vendor/gopkg.in/karalabe/cookiejar.v2/collections/prque/sstack.go rename to common/prque/sstack.go index 9f393196ef..4875dae99d 100755 --- a/vendor/gopkg.in/karalabe/cookiejar.v2/collections/prque/sstack.go +++ b/common/prque/sstack.go @@ -1,10 +1,4 @@ -// CookieJar - A contestant's algorithm toolbox -// Copyright (c) 2013 Peter Szilagyi. All rights reserved. -// -// CookieJar is dual licensed: use of this source code is governed by a BSD -// license that can be found in the LICENSE file. Alternatively, the CookieJar -// toolbox may be used in accordance with the terms and conditions contained -// in a signed written agreement between you and the author(s). +// This is a duplicated and slightly modified version of "gopkg.in/karalabe/cookiejar.v2/collections/prque". package prque @@ -12,15 +6,24 @@ package prque const blockSize = 4096 // A prioritized item in the sorted stack. +// +// Note: priorities can "wrap around" the int64 range, a comes before b if (a.priority - b.priority) > 0. +// The difference between the lowest and highest priorities in the queue at any point should be less than 2^63. type item struct { value interface{} - priority float32 + priority int64 } +// setIndexCallback is called when the element is moved to a new index. +// Providing setIndexCallback is optional, it is needed only if the application needs +// to delete elements other than the top one. +type setIndexCallback func(a interface{}, i int) + // Internal sortable stack data structure. Implements the Push and Pop ops for // the stack (heap) functionality and the Len, Less and Swap methods for the // sortability requirements of the heaps. type sstack struct { + setIndex setIndexCallback size int capacity int offset int @@ -30,8 +33,9 @@ type sstack struct { } // Creates a new, empty stack. -func newSstack() *sstack { +func newSstack(setIndex setIndexCallback) *sstack { result := new(sstack) + result.setIndex = setIndex result.active = make([]*item, blockSize) result.blocks = [][]*item{result.active} result.capacity = blockSize @@ -50,6 +54,9 @@ func (s *sstack) Push(data interface{}) { s.active = s.blocks[s.size/blockSize] s.offset = 0 } + if s.setIndex != nil { + s.setIndex(data.(*item).value, s.size) + } s.active[s.offset] = data.(*item) s.offset++ s.size++ @@ -65,6 +72,9 @@ func (s *sstack) Pop() (res interface{}) { s.active = s.blocks[s.size/blockSize] } res, s.active[s.offset] = s.active[s.offset], nil + if s.setIndex != nil { + s.setIndex(res.(*item).value, -1) + } return } @@ -76,16 +86,21 @@ func (s *sstack) Len() int { // Compares the priority of two elements of the stack (higher is first). // Required by sort.Interface. func (s *sstack) Less(i, j int) bool { - return s.blocks[i/blockSize][i%blockSize].priority > s.blocks[j/blockSize][j%blockSize].priority + return (s.blocks[i/blockSize][i%blockSize].priority - s.blocks[j/blockSize][j%blockSize].priority) > 0 } // Swaps two elements in the stack. Required by sort.Interface. func (s *sstack) Swap(i, j int) { ib, io, jb, jo := i/blockSize, i%blockSize, j/blockSize, j%blockSize - s.blocks[ib][io], s.blocks[jb][jo] = s.blocks[jb][jo], s.blocks[ib][io] + a, b := s.blocks[jb][jo], s.blocks[ib][io] + if s.setIndex != nil { + s.setIndex(a.value, i) + s.setIndex(b.value, j) + } + s.blocks[ib][io], s.blocks[jb][jo] = a, b } // Resets the stack, effectively clearing its contents. func (s *sstack) Reset() { - *s = *newSstack() + *s = *newSstack(s.setIndex) } diff --git a/common/size.go b/common/size.go index c5a0cb0f2d..6381499a48 100644 --- a/common/size.go +++ b/common/size.go @@ -20,18 +20,29 @@ import ( "fmt" ) +// StorageSize is a wrapper around a float value that supports user friendly +// formatting. type StorageSize float64 -func (self StorageSize) String() string { - if self > 1000000 { - return fmt.Sprintf("%.2f mB", self/1000000) - } else if self > 1000 { - return fmt.Sprintf("%.2f kB", self/1000) +// String implements the stringer interface. +func (s StorageSize) String() string { + 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", self) + return fmt.Sprintf("%.2f B", s) } } -func (self StorageSize) Int64() int64 { - return int64(self) +// TerminalString implements log.TerminalStringer, formatting a string for console +// output during logging. +func (s StorageSize) TerminalString() string { + 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/common/size_test.go b/common/size_test.go index f5b6c725e2..0938d483c4 100644 --- a/common/size_test.go +++ b/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/common/types.go b/common/types.go index fdc67480c2..48043788fd 100644 --- a/common/types.go +++ b/common/types.go @@ -17,18 +17,24 @@ package common import ( + "database/sql/driver" "encoding/hex" + "encoding/json" "fmt" "math/big" "math/rand" "reflect" + "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. const ( - HashLength = 32 + // HashLength is the expected length of the hash + HashLength = 32 + // AddressLength is the expected length of the address AddressLength = 20 ) @@ -40,20 +46,30 @@ var ( // Hash represents the 32 byte Keccak256 hash of arbitrary data. type Hash [HashLength]byte +// BytesToHash sets b to hash. +// If b is larger than len(h), b will be cropped from the left. func BytesToHash(b []byte) Hash { var h Hash h.SetBytes(b) return h } -func StringToHash(s string) Hash { return BytesToHash([]byte(s)) } -func BigToHash(b *big.Int) Hash { return BytesToHash(b.Bytes()) } -func HexToHash(s string) Hash { return BytesToHash(FromHex(s)) } -// Get the string representation of the underlying hash -func (h Hash) Str() string { return string(h[:]) } +// BigToHash sets byte representation of b to hash. +// If b is larger than len(h), b will be cropped from the left. +func BigToHash(b *big.Int) Hash { return BytesToHash(b.Bytes()) } + +// HexToHash sets byte representation of s to hash. +// If b is larger than len(h), b will be cropped from the left. +func HexToHash(s string) Hash { return BytesToHash(FromHex(s)) } + +// Bytes gets the byte representation of the underlying hash. func (h Hash) Bytes() []byte { return h[:] } + +// Big converts a hash to a big integer. func (h Hash) Big() *big.Int { return new(big.Int).SetBytes(h[:]) } -func (h Hash) Hex() string { return hexutil.Encode(h[:]) } + +// Hex converts a hash to a hex string. +func (h Hash) Hex() string { return hexutil.Encode(h[:]) } // TerminalString implements log.TerminalStringer, formatting a string for console // output during logging. @@ -88,7 +104,8 @@ func (h Hash) MarshalText() ([]byte, error) { return hexutil.Bytes(h[:]).MarshalText() } -// Sets the hash to the value of b. If b is larger than len(h), 'b' will be cropped (from the left). +// SetBytes sets the hash to the value of b. +// If b is larger than len(h), b will be cropped from the left. func (h *Hash) SetBytes(b []byte) { if len(b) > len(h) { b = b[len(b)-HashLength:] @@ -97,16 +114,6 @@ func (h *Hash) SetBytes(b []byte) { copy(h[HashLength-len(b):], b) } -// Set string `s` to h. If s is larger than len(h) s will be cropped (from left) to fit. -func (h *Hash) SetString(s string) { h.SetBytes([]byte(s)) } - -// Sets h to other -func (h *Hash) Set(other Hash) { - for i, v := range other { - h[i] = v - } -} - // Generate implements testing/quick.Generator. func (h Hash) Generate(rand *rand.Rand, size int) reflect.Value { m := rand.Intn(len(h)) @@ -116,8 +123,37 @@ func (h Hash) Generate(rand *rand.Rand, size int) reflect.Value { return reflect.ValueOf(h) } -func EmptyHash(h Hash) bool { - return h == Hash{} +// Scan implements Scanner for database/sql. +func (h *Hash) Scan(src interface{}) error { + srcB, ok := src.([]byte) + if !ok { + return fmt.Errorf("can't scan %T into Hash", src) + } + if len(srcB) != HashLength { + return fmt.Errorf("can't scan []byte of len %d into Hash, want %d", len(srcB), HashLength) + } + copy(h[:], srcB) + return nil +} + +// Value implements valuer for database/sql. +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. @@ -138,14 +174,21 @@ func (h UnprefixedHash) MarshalText() ([]byte, error) { // Address represents the 20 byte address of an Ethereum account. type Address [AddressLength]byte +// BytesToAddress returns Address with value b. +// If b is larger than len(h), b will be cropped from the left. func BytesToAddress(b []byte) Address { var a Address a.SetBytes(b) return a } -func StringToAddress(s string) Address { return BytesToAddress([]byte(s)) } -func BigToAddress(b *big.Int) Address { return BytesToAddress(b.Bytes()) } -func HexToAddress(s string) Address { return BytesToAddress(FromHex(s)) } + +// BigToAddress returns Address with byte values of b. +// If b is larger than len(h), b will be cropped from the left. +func BigToAddress(b *big.Int) Address { return BytesToAddress(b.Bytes()) } + +// HexToAddress returns Address with byte values of s. +// If s is larger than len(h), s will be cropped from the left. +func HexToAddress(s string) Address { return BytesToAddress(FromHex(s)) } // IsHexAddress verifies whether a string can represent a valid hex-encoded // Ethereum address or not. @@ -156,16 +199,19 @@ func IsHexAddress(s string) bool { return len(s) == 2*AddressLength && isHex(s) } -// Get the string representation of the underlying address -func (a Address) Str() string { return string(a[:]) } +// 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[:]) } -func (a Address) Hash() Hash { return BytesToHash(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) @@ -184,7 +230,7 @@ func (a Address) Hex() string { return "0x" + string(result) } -// String implements the stringer interface and is used also by the logger. +// String implements fmt.Stringer. func (a Address) String() string { return a.Hex() } @@ -195,7 +241,8 @@ func (a Address) Format(s fmt.State, c rune) { fmt.Fprintf(s, "%"+string(c), a[:]) } -// Sets the address to the value of b. If b is larger than len(a) it will panic +// SetBytes sets the address to the value of b. +// If b is larger than len(a) it will panic. func (a *Address) SetBytes(b []byte) { if len(b) > len(a) { b = b[len(b)-AddressLength:] @@ -203,16 +250,6 @@ func (a *Address) SetBytes(b []byte) { copy(a[AddressLength-len(b):], b) } -// Set string `s` to a. If s is larger than len(a) it will panic -func (a *Address) SetString(s string) { a.SetBytes([]byte(s)) } - -// Sets a to other -func (a *Address) Set(other Address) { - for i, v := range other { - a[i] = v - } -} - // MarshalText returns the hex representation of a. func (a Address) MarshalText() ([]byte, error) { return hexutil.Bytes(a[:]).MarshalText() @@ -228,7 +265,40 @@ func (a *Address) UnmarshalJSON(input []byte) error { return hexutil.UnmarshalFixedJSON(addressT, input, a[:]) } -// UnprefixedHash allows marshaling an Address without 0x prefix. +// Scan implements Scanner for database/sql. +func (a *Address) Scan(src interface{}) error { + srcB, ok := src.([]byte) + if !ok { + return fmt.Errorf("can't scan %T into Address", src) + } + if len(srcB) != AddressLength { + return fmt.Errorf("can't scan []byte of len %d into Address, want %d", len(srcB), AddressLength) + } + copy(a[:], srcB) + return nil +} + +// Value implements valuer for database/sql. +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 // UnmarshalText decodes the address from hex. The 0x prefix is optional. @@ -240,3 +310,63 @@ func (a *UnprefixedAddress) UnmarshalText(input []byte) error { func (a UnprefixedAddress) MarshalText() ([]byte, error) { return []byte(hex.EncodeToString(a[:])), nil } + +// MixedcaseAddress retains the original string, which may or may not be +// correctly checksummed +type MixedcaseAddress struct { + addr Address + original string +} + +// NewMixedcaseAddress constructor (mainly for testing) +func NewMixedcaseAddress(addr Address) MixedcaseAddress { + return MixedcaseAddress{addr: addr, original: addr.Hex()} +} + +// NewMixedcaseAddressFromString is mainly meant for unit-testing +func NewMixedcaseAddressFromString(hexaddr string) (*MixedcaseAddress, error) { + if !IsHexAddress(hexaddr) { + return nil, fmt.Errorf("Invalid address") + } + a := FromHex(hexaddr) + return &MixedcaseAddress{addr: BytesToAddress(a), original: hexaddr}, nil +} + +// UnmarshalJSON parses MixedcaseAddress +func (ma *MixedcaseAddress) UnmarshalJSON(input []byte) error { + if err := hexutil.UnmarshalFixedJSON(addressT, input, ma.addr[:]); err != nil { + return err + } + return json.Unmarshal(input, &ma.original) +} + +// MarshalJSON marshals the original value +func (ma *MixedcaseAddress) MarshalJSON() ([]byte, error) { + if strings.HasPrefix(ma.original, "0x") || strings.HasPrefix(ma.original, "0X") { + return json.Marshal(fmt.Sprintf("0x%s", ma.original[2:])) + } + return json.Marshal(fmt.Sprintf("0x%s", ma.original)) +} + +// Address returns the address +func (ma *MixedcaseAddress) Address() Address { + return ma.addr +} + +// String implements fmt.Stringer +func (ma *MixedcaseAddress) String() string { + if ma.ValidChecksum() { + return fmt.Sprintf("%s [chksum ok]", ma.original) + } + return fmt.Sprintf("%s [chksum INVALID]", ma.original) +} + +// ValidChecksum returns true if the address has valid checksum +func (ma *MixedcaseAddress) ValidChecksum() bool { + return ma.original == ma.addr.Hex() +} + +// Original returns the mixed-case input string +func (ma *MixedcaseAddress) Original() string { + return ma.original +} diff --git a/common/types_template.go b/common/types_template.go deleted file mode 100644 index 9a8f29977b..0000000000 --- a/common/types_template.go +++ /dev/null @@ -1,64 +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 . - -// +build none -//sed -e 's/_N_/Hash/g' -e 's/_S_/32/g' -e '1d' types_template.go | gofmt -w hash.go - -package common - -import "math/big" - -type _N_ [_S_]byte - -func BytesTo_N_(b []byte) _N_ { - var h _N_ - h.SetBytes(b) - return h -} -func StringTo_N_(s string) _N_ { return BytesTo_N_([]byte(s)) } -func BigTo_N_(b *big.Int) _N_ { return BytesTo_N_(b.Bytes()) } -func HexTo_N_(s string) _N_ { return BytesTo_N_(FromHex(s)) } - -// Don't use the default 'String' method in case we want to overwrite - -// Get the string representation of the underlying hash -func (h _N_) Str() string { return string(h[:]) } -func (h _N_) Bytes() []byte { return h[:] } -func (h _N_) Big() *big.Int { return new(big.Int).SetBytes(h[:]) } -func (h _N_) Hex() string { return "0x" + Bytes2Hex(h[:]) } - -// Sets the hash to the value of b. If b is larger than len(h) it will panic -func (h *_N_) SetBytes(b []byte) { - // Use the right most bytes - if len(b) > len(h) { - b = b[len(b)-_S_:] - } - - // Reverse the loop - for i := len(b) - 1; i >= 0; i-- { - h[_S_-len(b)+i] = b[i] - } -} - -// Set string `s` to h. If s is larger than len(h) it will panic -func (h *_N_) SetString(s string) { h.SetBytes([]byte(s)) } - -// Sets h to other -func (h *_N_) Set(other _N_) { - for i, v := range other { - h[i] = v - } -} diff --git a/common/types_test.go b/common/types_test.go index db636812ce..7095ccd019 100644 --- a/common/types_test.go +++ b/common/types_test.go @@ -17,8 +17,10 @@ package common import ( + "database/sql/driver" "encoding/json" "math/big" + "reflect" "strings" "testing" ) @@ -149,3 +151,223 @@ func BenchmarkAddressHex(b *testing.B) { testAddr.Hex() } } + +func TestMixedcaseAccount_Address(t *testing.T) { + + // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md + // Note: 0X{checksum_addr} is not valid according to spec above + + var res []struct { + A MixedcaseAddress + Valid bool + } + if err := json.Unmarshal([]byte(`[ + {"A" : "0xae967917c465db8578ca9024c205720b1a3651A9", "Valid": false}, + {"A" : "0xAe967917c465db8578ca9024c205720b1a3651A9", "Valid": true}, + {"A" : "0XAe967917c465db8578ca9024c205720b1a3651A9", "Valid": false}, + {"A" : "0x1111111111111111111112222222222223333323", "Valid": true} + ]`), &res); err != nil { + t.Fatal(err) + } + + for _, r := range res { + if got := r.A.ValidChecksum(); got != r.Valid { + t.Errorf("Expected checksum %v, got checksum %v, input %v", r.Valid, got, r.A.String()) + } + } + + //These should throw exceptions: + var r2 []MixedcaseAddress + for _, r := range []string{ + `["0x11111111111111111111122222222222233333"]`, // Too short + `["0x111111111111111111111222222222222333332"]`, // Too short + `["0x11111111111111111111122222222222233333234"]`, // Too long + `["0x111111111111111111111222222222222333332344"]`, // Too long + `["1111111111111111111112222222222223333323"]`, // Missing 0x + `["x1111111111111111111112222222222223333323"]`, // Missing 0 + `["0xG111111111111111111112222222222223333323"]`, //Non-hex + } { + if err := json.Unmarshal([]byte(r), &r2); err == nil { + t.Errorf("Expected failure, input %v", r) + } + + } + +} + +func TestHash_Scan(t *testing.T) { + type args struct { + src interface{} + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "working scan", + args: args{src: []byte{ + 0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e, + 0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15, + 0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15, + 0x10, 0x00, + }}, + wantErr: false, + }, + { + name: "non working scan", + args: args{src: int64(1234567890)}, + wantErr: true, + }, + { + name: "invalid length scan", + args: args{src: []byte{ + 0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e, + 0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15, + 0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15, + }}, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + h := &Hash{} + if err := h.Scan(tt.args.src); (err != nil) != tt.wantErr { + t.Errorf("Hash.Scan() error = %v, wantErr %v", err, tt.wantErr) + } + + if !tt.wantErr { + for i := range h { + if h[i] != tt.args.src.([]byte)[i] { + t.Errorf( + "Hash.Scan() didn't scan the %d src correctly (have %X, want %X)", + i, h[i], tt.args.src.([]byte)[i], + ) + } + } + } + }) + } +} + +func TestHash_Value(t *testing.T) { + b := []byte{ + 0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e, + 0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15, + 0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15, + 0x10, 0x00, + } + var usedH Hash + usedH.SetBytes(b) + tests := []struct { + name string + h Hash + want driver.Value + wantErr bool + }{ + { + name: "Working value", + h: usedH, + want: b, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.h.Value() + if (err != nil) != tt.wantErr { + t.Errorf("Hash.Value() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("Hash.Value() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestAddress_Scan(t *testing.T) { + type args struct { + src interface{} + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "working scan", + args: args{src: []byte{ + 0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e, + 0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15, + }}, + wantErr: false, + }, + { + name: "non working scan", + args: args{src: int64(1234567890)}, + wantErr: true, + }, + { + name: "invalid length scan", + args: args{src: []byte{ + 0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e, + 0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, + }}, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := &Address{} + if err := a.Scan(tt.args.src); (err != nil) != tt.wantErr { + t.Errorf("Address.Scan() error = %v, wantErr %v", err, tt.wantErr) + } + + if !tt.wantErr { + for i := range a { + if a[i] != tt.args.src.([]byte)[i] { + t.Errorf( + "Address.Scan() didn't scan the %d src correctly (have %X, want %X)", + i, a[i], tt.args.src.([]byte)[i], + ) + } + } + } + }) + } +} + +func TestAddress_Value(t *testing.T) { + b := []byte{ + 0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e, + 0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15, + } + var usedA Address + usedA.SetBytes(b) + tests := []struct { + name string + a Address + want driver.Value + wantErr bool + }{ + { + name: "Working value", + a: usedA, + want: b, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.a.Value() + if (err != nil) != tt.wantErr { + t.Errorf("Address.Value() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("Address.Value() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/compression/rle/read_write.go b/compression/rle/read_write.go deleted file mode 100644 index 0e7ad90aec..0000000000 --- a/compression/rle/read_write.go +++ /dev/null @@ -1,101 +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 rle implements the run-length encoding used for Ethereum data. -package rle - -import ( - "bytes" - "errors" - - "github.com/ethereum/go-ethereum/crypto" -) - -const ( - token byte = 0xfe - emptyShaToken = 0xfd - emptyListShaToken = 0xfe - tokenToken = 0xff -) - -var empty = crypto.Keccak256([]byte("")) -var emptyList = crypto.Keccak256([]byte{0x80}) - -func Decompress(dat []byte) ([]byte, error) { - buf := new(bytes.Buffer) - - for i := 0; i < len(dat); i++ { - if dat[i] == token { - if i+1 < len(dat) { - switch dat[i+1] { - case emptyShaToken: - buf.Write(empty) - case emptyListShaToken: - buf.Write(emptyList) - case tokenToken: - buf.WriteByte(token) - default: - buf.Write(make([]byte, int(dat[i+1]-2))) - } - i++ - } else { - return nil, errors.New("error reading bytes. token encountered without proceeding bytes") - } - } else { - buf.WriteByte(dat[i]) - } - } - - return buf.Bytes(), nil -} - -func compressChunk(dat []byte) (ret []byte, n int) { - switch { - case dat[0] == token: - return []byte{token, tokenToken}, 1 - case len(dat) > 1 && dat[0] == 0x0 && dat[1] == 0x0: - j := 0 - for j <= 254 && j < len(dat) { - if dat[j] != 0 { - break - } - j++ - } - return []byte{token, byte(j + 2)}, j - case len(dat) >= 32: - if dat[0] == empty[0] && bytes.Equal(dat[:32], empty) { - return []byte{token, emptyShaToken}, 32 - } else if dat[0] == emptyList[0] && bytes.Equal(dat[:32], emptyList) { - return []byte{token, emptyListShaToken}, 32 - } - fallthrough - default: - return dat[:1], 1 - } -} - -func Compress(dat []byte) []byte { - buf := new(bytes.Buffer) - - i := 0 - for i < len(dat) { - b, n := compressChunk(dat[i:]) - buf.Write(b) - i += n - } - - return buf.Bytes() -} diff --git a/compression/rle/read_write_test.go b/compression/rle/read_write_test.go deleted file mode 100644 index b36f7907bc..0000000000 --- a/compression/rle/read_write_test.go +++ /dev/null @@ -1,50 +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 rle - -import ( - "testing" - - checker "gopkg.in/check.v1" -) - -func Test(t *testing.T) { checker.TestingT(t) } - -type CompressionRleSuite struct{} - -var _ = checker.Suite(&CompressionRleSuite{}) - -func (s *CompressionRleSuite) TestDecompressSimple(c *checker.C) { - exp := []byte{0xc5, 0xd2, 0x46, 0x1, 0x86, 0xf7, 0x23, 0x3c, 0x92, 0x7e, 0x7d, 0xb2, 0xdc, 0xc7, 0x3, 0xc0, 0xe5, 0x0, 0xb6, 0x53, 0xca, 0x82, 0x27, 0x3b, 0x7b, 0xfa, 0xd8, 0x4, 0x5d, 0x85, 0xa4, 0x70} - res, err := Decompress([]byte{token, 0xfd}) - c.Assert(err, checker.IsNil) - c.Assert(res, checker.DeepEquals, exp) - - exp = []byte{0x56, 0xe8, 0x1f, 0x17, 0x1b, 0xcc, 0x55, 0xa6, 0xff, 0x83, 0x45, 0xe6, 0x92, 0xc0, 0xf8, 0x6e, 0x5b, 0x48, 0xe0, 0x1b, 0x99, 0x6c, 0xad, 0xc0, 0x1, 0x62, 0x2f, 0xb5, 0xe3, 0x63, 0xb4, 0x21} - res, err = Decompress([]byte{token, 0xfe}) - c.Assert(err, checker.IsNil) - c.Assert(res, checker.DeepEquals, exp) - - res, err = Decompress([]byte{token, 0xff}) - c.Assert(err, checker.IsNil) - c.Assert(res, checker.DeepEquals, []byte{token}) - - res, err = Decompress([]byte{token, 12}) - c.Assert(err, checker.IsNil) - c.Assert(res, checker.DeepEquals, make([]byte, 10)) - -} diff --git a/consensus/clique/api.go b/consensus/clique/api.go index b875eef012..6bcf987af5 100644 --- a/consensus/clique/api.go +++ b/consensus/clique/api.go @@ -75,7 +75,7 @@ func (api *API) GetSigners(number *rpc.BlockNumber) ([]common.Address, error) { return snap.signers(), nil } -// GetSignersAtHash retrieves the state snapshot at a given block. +// GetSignersAtHash retrieves the list of authorized signers at the specified block. func (api *API) GetSignersAtHash(hash common.Hash) ([]common.Address, error) { header := api.chain.GetHeaderByHash(hash) if header == nil { diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index 2bdad9092a..967a843dec 100644 --- a/consensus/clique/clique.go +++ b/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 ( @@ -53,7 +54,6 @@ const ( // Clique proof-of-authority protocol constants. var ( epochLength = uint64(30000) // Default number of blocks after which to checkpoint and reset the pending votes - blockPeriod = uint64(15) // Default minimum difference between two consecutive block's timestamps extraVanity = 32 // Fixed number of extra-data prefix bytes reserved for signer vanity extraSeal = 65 // Fixed number of extra-data suffix bytes reserved for signer seal @@ -94,27 +94,33 @@ var ( // errMissingSignature is returned if a block's extra-data section doesn't seem // to contain a 65 byte secp256k1 signature. - errMissingSignature = errors.New("extra-data 65 byte suffix signature missing") + errMissingSignature = errors.New("extra-data 65 byte signature suffix missing") // errExtraSigners is returned if non-checkpoint block contain signer data in // their extra-data fields. errExtraSigners = errors.New("non-checkpoint block contains extra signer list") // errInvalidCheckpointSigners is returned if a checkpoint block contains an - // invalid list of signers (i.e. non divisible by 20 bytes, or not the correct - // ones). + // invalid list of signers (i.e. non divisible by 20 bytes). errInvalidCheckpointSigners = errors.New("invalid signer list on checkpoint block") + // errMismatchingCheckpointSigners is returned if a checkpoint block contains a + // list of signers different than the one the local node calculated. + errMismatchingCheckpointSigners = errors.New("mismatching signer list on checkpoint block") + // errInvalidMixDigest is returned if a block's mix digest is non-zero. errInvalidMixDigest = errors.New("non-zero mix digest") // errInvalidUncleHash is returned if a block contains an non-empty uncle list. errInvalidUncleHash = errors.New("non empty uncle hash") - // errInvalidDifficulty is returned if the difficulty of a block is not either - // of 1 or 2, or if the value does not match the turn of the signer. + // errInvalidDifficulty is returned if the difficulty of a block neither 1 or 2. errInvalidDifficulty = errors.New("invalid difficulty") + // errWrongDifficulty is returned if the difficulty of a block doesn't match the + // turn of the signer. + errWrongDifficulty = errors.New("wrong difficulty") + // ErrInvalidTimestamp is returned if the timestamp of a block is lower than // the previous block's timestamp + the minimum block period. ErrInvalidTimestamp = errors.New("invalid timestamp") @@ -123,49 +129,17 @@ var ( // be modified via out-of-range or non-contiguous headers. errInvalidVotingChain = errors.New("invalid voting chain") - // errUnauthorized is returned if a header is signed by a non-authorized entity. - errUnauthorized = errors.New("unauthorized") + // errUnauthorizedSigner is returned if a header is signed by a non-authorized entity. + errUnauthorizedSigner = errors.New("unauthorized signer") - // errWaitTransactions is returned if an empty block is attempted to be sealed - // on an instant chain (0 second period). It's important to refuse these as the - // block reward is zero, so an empty block just bloats the chain... fast. - errWaitTransactions = errors.New("waiting for transactions") + // errRecentlySigned is returned if a header is signed by an authorized entity + // that already signed a header recently, thus is temporarily not allowed to. + 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) { @@ -181,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 } @@ -206,6 +180,9 @@ type Clique struct { signer common.Address // Ethereum address of the signing key signFn SignerFn // Signer function to authorize hashes with lock sync.RWMutex // Protects the signer fields + + // The fields below are for testing only + fakeDiff bool // Skip difficulty verifications } // New creates a Clique proof-of-authority consensus engine with the initial @@ -360,7 +337,7 @@ func (c *Clique) verifyCascadingFields(chain consensus.ChainReader, header *type } extraSuffix := len(header.Extra) - extraSeal if !bytes.Equal(header.Extra[extraVanity:extraSuffix], signers) { - return errInvalidCheckpointSigners + return errMismatchingCheckpointSigners } } // All basic checks passed, verify the seal and return @@ -383,27 +360,28 @@ func (c *Clique) snapshot(chain consensus.ChainReader, number uint64, hash commo // If an on-disk checkpoint snapshot can be found, use that if number%checkpointInterval == 0 { if s, err := loadSnapshot(c.config, c.signatures, c.db, hash); err == nil { - log.Trace("Loaded voting snapshot form disk", "number", number, "hash", hash) + log.Trace("Loaded voting snapshot from disk", "number", number, "hash", hash) snap = s break } } - // If we're at block zero, make a snapshot - if number == 0 { - genesis := chain.GetHeaderByNumber(0) - if err := c.VerifyHeader(chain, genesis, false); err != nil { - return nil, err + // If we're at an checkpoint block, make a snapshot if it's known + if number == 0 || (number%c.config.Epoch == 0 && chain.GetHeaderByNumber(number-1) == nil) { + checkpoint := chain.GetHeaderByNumber(number) + if checkpoint != nil { + hash := checkpoint.Hash() + + signers := make([]common.Address, (len(checkpoint.Extra)-extraVanity-extraSeal)/common.AddressLength) + for i := 0; i < len(signers); i++ { + copy(signers[i][:], checkpoint.Extra[extraVanity+i*common.AddressLength:]) + } + snap = newSnapshot(c.config, c.signatures, number, hash, signers) + if err := snap.store(c.db); err != nil { + return nil, err + } + log.Info("Stored checkpoint snapshot to disk", "number", number, "hash", hash) + break } - signers := make([]common.Address, (len(genesis.Extra)-extraVanity-extraSeal)/common.AddressLength) - for i := 0; i < len(signers); i++ { - copy(signers[i][:], genesis.Extra[extraVanity+i*common.AddressLength:]) - } - snap = newSnapshot(c.config, c.signatures, 0, genesis.Hash(), signers) - if err := snap.store(c.db); err != nil { - return nil, err - } - log.Trace("Stored genesis voting snapshot to disk") - break } // No snapshot for this header, gather the header and move backward var header *types.Header @@ -481,23 +459,25 @@ func (c *Clique) verifySeal(chain consensus.ChainReader, header *types.Header, p return err } if _, ok := snap.Signers[signer]; !ok { - return errUnauthorized + return errUnauthorizedSigner } for seen, recent := range snap.Recents { if recent == signer { // Signer is among recents, only fail if the current block doesn't shift it out if limit := uint64(len(snap.Signers)/2 + 1); seen > number-limit { - return errUnauthorized + return errRecentlySigned } } } // Ensure that the difficulty corresponds to the turn-ness of the signer - inturn := snap.inturn(header.Number.Uint64(), signer) - if inturn && header.Difficulty.Cmp(diffInTurn) != 0 { - return errInvalidDifficulty - } - if !inturn && header.Difficulty.Cmp(diffNoTurn) != 0 { - return errInvalidDifficulty + if !c.fakeDiff { + inturn := snap.inturn(header.Number.Uint64(), signer) + if inturn && header.Difficulty.Cmp(diffInTurn) != 0 { + return errWrongDifficulty + } + if !inturn && header.Difficulty.Cmp(diffNoTurn) != 0 { + return errWrongDifficulty + } } return nil } @@ -590,17 +570,18 @@ func (c *Clique) Authorize(signer common.Address, signFn SignerFn) { // Seal implements consensus.Engine, attempting to create a sealed block using // the local signing credentials. -func (c *Clique) Seal(chain consensus.ChainReader, block *types.Block, stop <-chan struct{}) (*types.Block, error) { +func (c *Clique) Seal(chain consensus.ChainReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error { header := block.Header() // Sealing the genesis block is not supported number := header.Number.Uint64() if number == 0 { - return nil, errUnknownBlock + return errUnknownBlock } // For 0-period chains, refuse to seal empty blocks (no reward but would spin sealing) if c.config.Period == 0 && len(block.Transactions()) == 0 { - return nil, errWaitTransactions + log.Info("Sealing paused, waiting for transactions") + return nil } // Don't hold the signer fields for the entire sealing procedure c.lock.RLock() @@ -610,10 +591,10 @@ func (c *Clique) Seal(chain consensus.ChainReader, block *types.Block, stop <-ch // Bail out if we're unauthorized to sign a block snap, err := c.snapshot(chain, number-1, header.ParentHash, nil) if err != nil { - return nil, err + return err } if _, authorized := snap.Signers[signer]; !authorized { - return nil, errUnauthorized + return errUnauthorizedSigner } // If we're amongst the recent signers, wait for the next block for seen, recent := range snap.Recents { @@ -621,8 +602,7 @@ func (c *Clique) Seal(chain consensus.ChainReader, block *types.Block, stop <-ch // Signer is among recents, only wait if the current block doesn't shift it out if limit := uint64(len(snap.Signers)/2 + 1); number < limit || seen > number-limit { log.Info("Signed recently, must wait for others") - <-stop - return nil, nil + return nil } } } @@ -635,21 +615,29 @@ func (c *Clique) Seal(chain consensus.ChainReader, block *types.Block, stop <-ch log.Trace("Out-of-turn signing requested", "wiggle", common.PrettyDuration(wiggle)) } - log.Trace("Waiting for slot to sign and propagate", "delay", common.PrettyDuration(delay)) - - select { - case <-stop: - return nil, nil - case <-time.After(delay): - } // 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 nil, err + return err } copy(header.Extra[len(header.Extra)-extraSeal:], sighash) + // Wait until sealing is terminated or delay timeout. + log.Trace("Waiting for slot to sign and propagate", "delay", common.PrettyDuration(delay)) + go func() { + select { + case <-stop: + return + case <-time.After(delay): + } - return block.WithSeal(header), nil + select { + case results <- block.WithSeal(header): + default: + log.Warn("Sealing result is not read by miner", "sealhash", SealHash(header)) + } + }() + + return nil } // CalcDifficulty is the difficulty adjustment algorithm. It returns the difficulty @@ -673,6 +661,16 @@ func CalcDifficulty(snap *Snapshot, signer common.Address) *big.Int { return new(big.Int).Set(diffNoTurn) } +// SealHash returns the hash of a block prior to it being sealed. +func (c *Clique) SealHash(header *types.Header) common.Hash { + return SealHash(header) +} + +// Close implements consensus.Engine. It's a noop for clique as there are no background threads. +func (c *Clique) Close() error { + return nil +} + // APIs implements consensus.Engine, returning the user facing RPC API to allow // controlling the signer voting. func (c *Clique) APIs(chain consensus.ChainReader) []rpc.API { @@ -683,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/consensus/clique/snapshot.go b/consensus/clique/snapshot.go index 9ebdb8df15..54d4555f3b 100644 --- a/consensus/clique/snapshot.go +++ b/consensus/clique/snapshot.go @@ -19,6 +19,7 @@ package clique import ( "bytes" "encoding/json" + "sort" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -56,6 +57,13 @@ type Snapshot struct { Tally map[common.Address]Tally `json:"tally"` // Current vote tally to avoid recalculating } +// signersAscending implements the sort interface to allow sorting a list of addresses +type signersAscending []common.Address + +func (s signersAscending) Len() int { return len(s) } +func (s signersAscending) Less(i, j int) bool { return bytes.Compare(s[i][:], s[j][:]) < 0 } +func (s signersAscending) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + // newSnapshot creates a new snapshot with the specified startup parameters. This // method does not initialize the set of recent signers, so only ever use if for // the genesis block. @@ -206,11 +214,11 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) { return nil, err } if _, ok := snap.Signers[signer]; !ok { - return nil, errUnauthorized + return nil, errUnauthorizedSigner } for _, recent := range snap.Recents { if recent == signer { - return nil, errUnauthorized + return nil, errRecentlySigned } } snap.Recents[number] = signer @@ -286,18 +294,12 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) { // signers retrieves the list of authorized signers in ascending order. func (s *Snapshot) signers() []common.Address { - signers := make([]common.Address, 0, len(s.Signers)) - for signer := range s.Signers { - signers = append(signers, signer) + sigs := make([]common.Address, 0, len(s.Signers)) + for sig := range s.Signers { + sigs = append(sigs, sig) } - for i := 0; i < len(signers); i++ { - for j := i + 1; j < len(signers); j++ { - if bytes.Compare(signers[i][:], signers[j][:]) > 0 { - signers[i], signers[j] = signers[j], signers[i] - } - } - } - return signers + sort.Sort(signersAscending(sigs)) + return sigs } // inturn returns if a signer at a given block height is in-turn or not. diff --git a/consensus/clique/snapshot_test.go b/consensus/clique/snapshot_test.go index 8b51e6e094..b920312a89 100644 --- a/consensus/clique/snapshot_test.go +++ b/consensus/clique/snapshot_test.go @@ -19,23 +19,18 @@ package clique import ( "bytes" "crypto/ecdsa" - "math/big" + "sort" "testing" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "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" ) -type testerVote struct { - signer string - voted string - auth bool -} - // testerAccountPool is a pool to maintain currently active tester accounts, // mapped from textual names used in the tests below to actual Ethereum private // keys capable of signing transactions. @@ -49,17 +44,26 @@ func newTesterAccountPool() *testerAccountPool { } } -func (ap *testerAccountPool) sign(header *types.Header, signer string) { - // Ensure we have a persistent key for the signer - if ap.accounts[signer] == nil { - ap.accounts[signer], _ = crypto.GenerateKey() +// checkpoint creates a Clique checkpoint signer section from the provided list +// of authorized signers and embeds it into the provided header. +func (ap *testerAccountPool) checkpoint(header *types.Header, signers []string) { + auths := make([]common.Address, len(signers)) + for i, signer := range signers { + auths[i] = ap.address(signer) + } + sort.Sort(signersAscending(auths)) + for i, auth := range auths { + copy(header.Extra[extraVanity+i*common.AddressLength:], auth.Bytes()) } - // Sign the header and embed the signature in extra data - sig, _ := crypto.Sign(sigHash(header).Bytes(), ap.accounts[signer]) - copy(header.Extra[len(header.Extra)-65:], sig) } +// address retrieves the Ethereum address of a tester account by label, creating +// a new account if no previous one exists yet. func (ap *testerAccountPool) address(account string) common.Address { + // Return the zero account for non-addresses + if account == "" { + return common.Address{} + } // Ensure we have a persistent key for the account if ap.accounts[account] == nil { ap.accounts[account], _ = crypto.GenerateKey() @@ -68,32 +72,38 @@ func (ap *testerAccountPool) address(account string) common.Address { return crypto.PubkeyToAddress(ap.accounts[account].PublicKey) } -// testerChainReader implements consensus.ChainReader to access the genesis -// block. All other methods and requests will panic. -type testerChainReader struct { - db ethdb.Database -} - -func (r *testerChainReader) Config() *params.ChainConfig { return params.AllCliqueProtocolChanges } -func (r *testerChainReader) CurrentHeader() *types.Header { panic("not supported") } -func (r *testerChainReader) GetHeader(common.Hash, uint64) *types.Header { panic("not supported") } -func (r *testerChainReader) GetBlock(common.Hash, uint64) *types.Block { panic("not supported") } -func (r *testerChainReader) GetHeaderByHash(common.Hash) *types.Header { panic("not supported") } -func (r *testerChainReader) GetHeaderByNumber(number uint64) *types.Header { - if number == 0 { - return core.GetHeader(r.db, core.GetCanonicalHash(r.db, 0), 0) +// sign calculates a Clique digital signature for the given block and embeds it +// back into the header. +func (ap *testerAccountPool) sign(header *types.Header, signer string) { + // Ensure we have a persistent key for the signer + if ap.accounts[signer] == nil { + ap.accounts[signer], _ = crypto.GenerateKey() } - panic("not supported") + // Sign the header and embed the signature in extra data + sig, _ := crypto.Sign(SealHash(header).Bytes(), ap.accounts[signer]) + copy(header.Extra[len(header.Extra)-extraSeal:], sig) } -// Tests that voting is evaluated correctly for various simple and complex scenarios. -func TestVoting(t *testing.T) { +// testerVote represents a single block signed by a parcitular account, where +// the account may or may not have cast a Clique vote. +type testerVote struct { + signer string + voted string + auth bool + checkpoint []string + newbatch bool +} + +// Tests that Clique signer voting is evaluated correctly for various simple and +// complex scenarios, as well as that a few special corner cases fail correctly. +func TestClique(t *testing.T) { // Define the various voting scenarios to test tests := []struct { epoch uint64 signers []string votes []testerVote results []string + failure error }{ { // Single signer, no votes cast @@ -321,10 +331,49 @@ func TestVoting(t *testing.T) { votes: []testerVote{ {signer: "A", voted: "C", auth: true}, {signer: "B"}, - {signer: "A"}, // Checkpoint block, (don't vote here, it's validated outside of snapshots) + {signer: "A", checkpoint: []string{"A", "B"}}, {signer: "B", voted: "C", auth: true}, }, results: []string{"A", "B"}, + }, { + // An unauthorized signer should not be able to sign blocks + signers: []string{"A"}, + votes: []testerVote{ + {signer: "B"}, + }, + failure: errUnauthorizedSigner, + }, { + // An authorized signer that signed recenty should not be able to sign again + signers: []string{"A", "B"}, + votes: []testerVote{ + {signer: "A"}, + {signer: "A"}, + }, + failure: errRecentlySigned, + }, { + // Recent signatures should not reset on checkpoint blocks imported in a batch + epoch: 3, + signers: []string{"A", "B", "C"}, + votes: []testerVote{ + {signer: "A"}, + {signer: "B"}, + {signer: "A", checkpoint: []string{"A", "B", "C"}}, + {signer: "A"}, + }, + failure: errRecentlySigned, + }, { + // Recent signatures should not reset on checkpoint blocks imported in a new + // batch (https://github.com/ethereum/go-ethereum/issues/17593). Whilst this + // seems overly specific and weird, it was a Rinkeby consensus split. + epoch: 3, + signers: []string{"A", "B", "C"}, + votes: []testerVote{ + {signer: "A"}, + {signer: "B"}, + {signer: "A", checkpoint: []string{"A", "B", "C"}}, + {signer: "A", newbatch: true}, + }, + failure: errRecentlySigned, }, } // Run through the scenarios and test them @@ -351,32 +400,82 @@ func TestVoting(t *testing.T) { copy(genesis.ExtraData[extraVanity+j*common.AddressLength:], signer[:]) } // Create a pristine blockchain with the genesis injected - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() genesis.Commit(db) // Assemble a chain of headers from the cast votes - headers := make([]*types.Header, len(tt.votes)) - for j, vote := range tt.votes { - headers[j] = &types.Header{ - Number: big.NewInt(int64(j) + 1), - Time: big.NewInt(int64(j) * int64(blockPeriod)), - Coinbase: accounts.address(vote.voted), - Extra: make([]byte, extraVanity+extraSeal), + config := *params.TestChainConfig + config.Clique = ¶ms.CliqueConfig{ + Period: 1, + Epoch: tt.epoch, + } + engine := New(config.Clique, db) + engine.fakeDiff = true + + blocks, _ := core.GenerateChain(&config, genesis.ToBlock(db), engine, db, len(tt.votes), func(j int, gen *core.BlockGen) { + // Cast the vote contained in this block + gen.SetCoinbase(accounts.address(tt.votes[j].voted)) + if tt.votes[j].auth { + var nonce types.BlockNonce + copy(nonce[:], nonceAuthVote) + gen.SetNonce(nonce) } + }) + // Iterate through the blocks and seal them individually + for j, block := range blocks { + // Geth the header and prepare it for signing + header := block.Header() if j > 0 { - headers[j].ParentHash = headers[j-1].Hash() + header.ParentHash = blocks[j-1].Hash() } - if vote.auth { - copy(headers[j].Nonce[:], nonceAuthVote) + header.Extra = make([]byte, extraVanity+extraSeal) + if auths := tt.votes[j].checkpoint; auths != nil { + header.Extra = make([]byte, extraVanity+len(auths)*common.AddressLength+extraSeal) + accounts.checkpoint(header, auths) } - accounts.sign(headers[j], vote.signer) + header.Difficulty = diffInTurn // Ignored, we just need a valid number + + // Generate the signature, embed it into the header and the block + accounts.sign(header, tt.votes[j].signer) + blocks[j] = block.WithSeal(header) + } + // Split the blocks up into individual import batches (cornercase testing) + batches := [][]*types.Block{nil} + for j, block := range blocks { + if tt.votes[j].newbatch { + batches = append(batches, nil) + } + batches[len(batches)-1] = append(batches[len(batches)-1], block) } // Pass all the headers through clique and ensure tallying succeeds - head := headers[len(headers)-1] - - snap, err := New(¶ms.CliqueConfig{Epoch: tt.epoch}, db).snapshot(&testerChainReader{db: db}, head.Number.Uint64(), head.Hash(), headers) + chain, err := core.NewBlockChain(db, nil, &config, engine, vm.Config{}, nil) if err != nil { - t.Errorf("test %d: failed to create voting snapshot: %v", i, err) + t.Errorf("test %d: failed to create test chain: %v", i, err) + continue + } + failed := false + for j := 0; j < len(batches)-1; j++ { + if k, err := chain.InsertChain(batches[j]); err != nil { + t.Errorf("test %d: failed to import batch %d, block %d: %v", i, j, k, err) + failed = true + break + } + } + if failed { + continue + } + if _, err = chain.InsertChain(batches[len(batches)-1]); err != tt.failure { + t.Errorf("test %d: failure mismatch: have %v, want %v", i, err, tt.failure) + } + if tt.failure != nil { + continue + } + // No failure was produced or requested, generate the final voting snapshot + head := blocks[len(blocks)-1] + + snap, err := engine.snapshot(chain, head.NumberU64(), head.Hash(), nil) + if err != nil { + t.Errorf("test %d: failed to retrieve voting snapshot: %v", i, err) continue } // Verify the final list of signers against the expected ones diff --git a/consensus/consensus.go b/consensus/consensus.go index be5e661c12..487b07be77 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -18,12 +18,13 @@ package consensus import ( + "math/big" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" - "math/big" ) // ChainReader defines a small collection of methods needed to access the local @@ -85,9 +86,15 @@ type Engine interface { Finalize(chain ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) - // Seal generates a new block for the given input block with the local miner's - // seal place on top. - Seal(chain ChainReader, block *types.Block, stop <-chan struct{}) (*types.Block, error) + // Seal generates a new sealing request for the given input block and pushes + // the result into the given channel. + // + // Note, the method returns immediately and will send the result async. More + // than one result may also be returned depending on the consensus algorithm. + Seal(chain ChainReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error + + // SealHash returns the hash of a block prior to it being sealed. + SealHash(header *types.Header) common.Hash // CalcDifficulty is the difficulty adjustment algorithm. It returns the difficulty // that a new block should have. @@ -95,6 +102,9 @@ type Engine interface { // APIs returns the RPC APIs this consensus engine provides. APIs(chain ChainReader) []rpc.API + + // Close terminates any background threads maintained by the consensus engine. + Close() error } // PoW is a consensus engine based on proof-of-work. diff --git a/consensus/errors.go b/consensus/errors.go index 3b136dbdd1..a005c5f63d 100644 --- a/consensus/errors.go +++ b/consensus/errors.go @@ -23,6 +23,10 @@ var ( // that is unknown. ErrUnknownAncestor = errors.New("unknown ancestor") + // ErrPrunedAncestor is returned when validating a block requires an ancestor + // that is known, but the state of which is not available. + ErrPrunedAncestor = errors.New("pruned ancestor") + // ErrFutureBlock is returned when a block's timestamp is in the future according // to the current node. ErrFutureBlock = errors.New("block in the future") diff --git a/consensus/ethash/algorithm.go b/consensus/ethash/algorithm.go index 10767bb312..d6c871092e 100644 --- a/consensus/ethash/algorithm.go +++ b/consensus/ethash/algorithm.go @@ -19,6 +19,7 @@ package ethash import ( "encoding/binary" "hash" + "math/big" "reflect" "runtime" "sync" @@ -29,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 ( @@ -47,18 +48,71 @@ const ( loopAccesses = 64 // Number of accesses in hashimoto loop ) +// cacheSize returns the size of the ethash verification cache that belongs to a certain +// block number. +func cacheSize(block uint64) uint64 { + epoch := int(block / epochLength) + if epoch < maxEpoch { + return cacheSizes[epoch] + } + return calcCacheSize(epoch) +} + +// calcCacheSize calculates the cache size for epoch. The cache size grows linearly, +// however, we always take the highest prime below the linearly growing threshold in order +// to reduce the risk of accidental regularities leading to cyclic behavior. +func calcCacheSize(epoch int) uint64 { + size := cacheInitBytes + cacheGrowthBytes*uint64(epoch) - hashBytes + for !new(big.Int).SetUint64(size / hashBytes).ProbablyPrime(1) { // Always accurate for n < 2^64 + size -= 2 * hashBytes + } + return size +} + +// datasetSize returns the size of the ethash mining dataset that belongs to a certain +// block number. +func datasetSize(block uint64) uint64 { + epoch := int(block / epochLength) + if epoch < maxEpoch { + return datasetSizes[epoch] + } + return calcDatasetSize(epoch) +} + +// calcDatasetSize calculates the dataset size for epoch. The dataset size grows linearly, +// however, we always take the highest prime below the linearly growing threshold in order +// to reduce the risk of accidental regularities leading to cyclic behavior. +func calcDatasetSize(epoch int) uint64 { + size := datasetInitBytes + datasetGrowthBytes*uint64(epoch) - mixBytes + for !new(big.Int).SetUint64(size / mixBytes).ProbablyPrime(1) { // Always accurate for n < 2^64 + size -= 2 * mixBytes + } + return size +} + // hasher is a repetitive hasher allowing the same hash data structures to be // reused between hash runs instead of requiring new ones to be created. type hasher func(dest []byte, data []byte) -// makeHasher creates a repetitive hasher, allowing the same hash data structures -// to be reused between hash runs instead of requiring new ones to be created. -// The returned function is not thread safe! +// makeHasher creates a repetitive hasher, allowing the same hash data structures to +// be reused between hash runs instead of requiring new ones to be created. The returned +// function is not thread safe! func makeHasher(h hash.Hash) hasher { + // sha3.state supports Read to get the sum, use it to avoid the overhead of Sum. + // Read alters the state but we reset the hash before every operation. + type readerHash interface { + hash.Hash + Read([]byte) (int, error) + } + rh, ok := h.(readerHash) + if !ok { + panic("can't find Read method on hash") + } + outputLen := rh.Size() return func(dest []byte, data []byte) { - h.Write(data) - h.Sum(dest[:0]) - h.Reset() + rh.Reset() + rh.Write(data) + rh.Read(dest[:outputLen]) } } @@ -69,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) } @@ -123,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) @@ -160,15 +214,6 @@ func swap(buffer []byte) { } } -// prepare converts an ethash cache or dataset from a byte stream into the internal -// int representation. All ethash methods work with ints to avoid constant byte to -// int conversions as well as to handle both little and big endian systems. -func prepare(dest []uint32, src []byte) { - for i := 0; i < len(dest); i++ { - dest[i] = binary.LittleEndian.Uint32(src[i*4:]) - } -} - // fnv is an algorithm inspired by the FNV hash, which in some cases is used as // a non-associative substitute for XOR. Note that we multiply the prime with // the full 32-bit input, in contrast with the FNV-1 spec which multiplies the @@ -256,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))) @@ -330,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/consensus/ethash/algorithm_go1.7.go b/consensus/ethash/algorithm_go1.7.go deleted file mode 100644 index c7f7f48e41..0000000000 --- a/consensus/ethash/algorithm_go1.7.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2017 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 !go1.8 - -package ethash - -// cacheSize calculates and returns the size of the ethash verification cache that -// belongs to a certain block number. The cache size grows linearly, however, we -// always take the highest prime below the linearly growing threshold in order to -// reduce the risk of accidental regularities leading to cyclic behavior. -func cacheSize(block uint64) uint64 { - // If we have a pre-generated value, use that - epoch := int(block / epochLength) - if epoch < maxEpoch { - return cacheSizes[epoch] - } - // We don't have a way to verify primes fast before Go 1.8 - panic("fast prime testing unsupported in Go < 1.8") -} - -// datasetSize calculates and returns the size of the ethash mining dataset that -// belongs to a certain block number. The dataset size grows linearly, however, we -// always take the highest prime below the linearly growing threshold in order to -// reduce the risk of accidental regularities leading to cyclic behavior. -func datasetSize(block uint64) uint64 { - // If we have a pre-generated value, use that - epoch := int(block / epochLength) - if epoch < maxEpoch { - return datasetSizes[epoch] - } - // We don't have a way to verify primes fast before Go 1.8 - panic("fast prime testing unsupported in Go < 1.8") -} diff --git a/consensus/ethash/algorithm_go1.8.go b/consensus/ethash/algorithm_go1.8.go deleted file mode 100644 index 975fdffe51..0000000000 --- a/consensus/ethash/algorithm_go1.8.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2017 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 go1.8 - -package ethash - -import "math/big" - -// cacheSize returns the size of the ethash verification cache that belongs to a certain -// block number. -func cacheSize(block uint64) uint64 { - epoch := int(block / epochLength) - if epoch < maxEpoch { - return cacheSizes[epoch] - } - return calcCacheSize(epoch) -} - -// calcCacheSize calculates the cache size for epoch. The cache size grows linearly, -// however, we always take the highest prime below the linearly growing threshold in order -// to reduce the risk of accidental regularities leading to cyclic behavior. -func calcCacheSize(epoch int) uint64 { - size := cacheInitBytes + cacheGrowthBytes*uint64(epoch) - hashBytes - for !new(big.Int).SetUint64(size / hashBytes).ProbablyPrime(1) { // Always accurate for n < 2^64 - size -= 2 * hashBytes - } - return size -} - -// datasetSize returns the size of the ethash mining dataset that belongs to a certain -// block number. -func datasetSize(block uint64) uint64 { - epoch := int(block / epochLength) - if epoch < maxEpoch { - return datasetSizes[epoch] - } - return calcDatasetSize(epoch) -} - -// calcDatasetSize calculates the dataset size for epoch. The dataset size grows linearly, -// however, we always take the highest prime below the linearly growing threshold in order -// to reduce the risk of accidental regularities leading to cyclic behavior. -func calcDatasetSize(epoch int) uint64 { - size := datasetInitBytes + datasetGrowthBytes*uint64(epoch) - mixBytes - for !new(big.Int).SetUint64(size / mixBytes).ProbablyPrime(1) { // Always accurate for n < 2^64 - size -= 2 * mixBytes - } - return size -} diff --git a/consensus/ethash/algorithm_test.go b/consensus/ethash/algorithm_test.go index a54f3b582c..c58479e289 100644 --- a/consensus/ethash/algorithm_test.go +++ b/consensus/ethash/algorithm_test.go @@ -18,6 +18,7 @@ package ethash import ( "bytes" + "encoding/binary" "io/ioutil" "math/big" "os" @@ -30,6 +31,31 @@ import ( "github.com/ethereum/go-ethereum/core/types" ) +// prepare converts an ethash cache or dataset from a byte stream into the internal +// int representation. All ethash methods work with ints to avoid constant byte to +// int conversions as well as to handle both little and big endian systems. +func prepare(dest []uint32, src []byte) { + for i := 0; i < len(dest); i++ { + dest[i] = binary.LittleEndian.Uint32(src[i*4:]) + } +} + +// Tests whether the dataset size calculator works correctly by cross checking the +// hard coded lookup table with the value generated by it. +func TestSizeCalculations(t *testing.T) { + // Verify all the cache and dataset sizes from the lookup table. + for epoch, want := range cacheSizes { + if size := calcCacheSize(epoch); size != want { + t.Errorf("cache %d: cache size mismatch: have %d, want %d", epoch, size, want) + } + } + for epoch, want := range datasetSizes { + if size := calcDatasetSize(epoch); size != want { + t.Errorf("dataset %d: dataset size mismatch: have %d, want %d", epoch, size, want) + } + } +} + // Tests that verification caches can be correctly generated. func TestCacheGeneration(t *testing.T) { tests := []struct { @@ -703,7 +729,8 @@ func TestConcurrentDiskCacheGeneration(t *testing.T) { go func(idx int) { defer pend.Done() - ethash := New(Config{cachedir, 0, 1, "", 0, 0, ModeNormal}) + ethash := New(Config{cachedir, 0, 1, "", 0, 0, ModeNormal}, nil, false) + defer ethash.Close() if err := ethash.VerifySeal(nil, block.Header()); err != nil { t.Errorf("proc %d: block verification failed: %v", idx, err) } diff --git a/consensus/ethash/api.go b/consensus/ethash/api.go new file mode 100644 index 0000000000..4d8eed4161 --- /dev/null +++ b/consensus/ethash/api.go @@ -0,0 +1,118 @@ +// 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 ethash + +import ( + "errors" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/types" +) + +var errEthashStopped = errors.New("ethash stopped") + +// API exposes ethash related methods for the RPC interface. +type API struct { + ethash *Ethash // Make sure the mode of ethash is normal. +} + +// GetWork returns a work package for external miner. +// +// The work package consists of 3 strings: +// result[0] - 32 bytes hex encoded current block header pow-hash +// result[1] - 32 bytes hex encoded seed hash used for DAG +// result[2] - 32 bytes hex encoded boundary condition ("target"), 2^256/difficulty +// result[3] - hex encoded block number +func (api *API) GetWork() ([4]string, error) { + if api.ethash.config.PowMode != ModeNormal && api.ethash.config.PowMode != ModeTest { + return [4]string{}, errors.New("not supported") + } + + var ( + workCh = make(chan [4]string, 1) + errc = make(chan error, 1) + ) + + select { + case api.ethash.fetchWorkCh <- &sealWork{errc: errc, res: workCh}: + case <-api.ethash.exitCh: + return [4]string{}, errEthashStopped + } + + select { + case work := <-workCh: + return work, nil + case err := <-errc: + return [4]string{}, err + } +} + +// SubmitWork can be used by external miner to submit their POW solution. +// It returns an indication if the work was accepted. +// Note either an invalid solution, a stale work a non-existent work will return false. +func (api *API) SubmitWork(nonce types.BlockNonce, hash, digest common.Hash) bool { + if api.ethash.config.PowMode != ModeNormal && api.ethash.config.PowMode != ModeTest { + return false + } + + var errc = make(chan error, 1) + + select { + case api.ethash.submitWorkCh <- &mineResult{ + nonce: nonce, + mixDigest: digest, + hash: hash, + errc: errc, + }: + case <-api.ethash.exitCh: + return false + } + + err := <-errc + return err == nil +} + +// SubmitHashrate can be used for remote miners to submit their hash rate. +// This enables the node to report the combined hash rate of all miners +// which submit work through this node. +// +// It accepts the miner hash rate and an identifier which must be unique +// between nodes. +func (api *API) SubmitHashRate(rate hexutil.Uint64, id common.Hash) bool { + if api.ethash.config.PowMode != ModeNormal && api.ethash.config.PowMode != ModeTest { + return false + } + + var done = make(chan struct{}, 1) + + select { + case api.ethash.submitRateCh <- &hashrate{done: done, rate: uint64(rate), id: id}: + case <-api.ethash.exitCh: + return false + } + + // Block until hash rate submitted successfully. + <-done + + return true +} + +// GetHashrate returns the current hashrate for local CPU miner and remote miner. +func (api *API) GetHashrate() uint64 { + return uint64(api.ethash.Hashrate()) +} diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 92a23d4a4d..62e3f8fca9 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -24,6 +24,7 @@ import ( "runtime" "time" + mapset "github.com/deckarep/golang-set" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/consensus" @@ -31,15 +32,30 @@ import ( "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" - set "gopkg.in/fatih/set.v0" + "github.com/ethereum/go-ethereum/rlp" + "golang.org/x/crypto/sha3" ) // Ethash proof-of-work protocol constants. var ( - FrontierBlockReward *big.Int = big.NewInt(5e+18) // Block reward in wei for successfully mining a block - ByzantiumBlockReward *big.Int = big.NewInt(3e+18) // Block reward in wei for successfully mining a block upward from Byzantium - maxUncles = 2 // Maximum number of uncles allowed in a single block - allowedFutureBlockTime = 15 * time.Second // Max time from current time allowed for blocks, before they're considered future blocks + FrontierBlockReward = big.NewInt(5e+18) // Block reward in wei for successfully mining a block + ByzantiumBlockReward = big.NewInt(3e+18) // Block reward in wei for successfully mining a block upward from Byzantium + ConstantinopleBlockReward = big.NewInt(2e+18) // Block reward in wei for successfully mining a block upward from Constantinople + maxUncles = 2 // Maximum number of uncles allowed in a single block + allowedFutureBlockTime = 15 * time.Second // Max time from current time allowed for blocks, before they're considered future blocks + + // calcDifficultyConstantinople is the difficulty adjustment algorithm for Constantinople. + // It returns the difficulty that a new block should have when created at time given the + // parent block's time and difficulty. The calculation uses the Byzantium rules, but with + // bomb offset 5M. + // Specification EIP-1234: https://eips.ethereum.org/EIPS/eip-1234 + calcDifficultyConstantinople = makeDifficultyCalculator(big.NewInt(5000000)) + + // calcDifficultyByzantium is the difficulty adjustment algorithm. It returns + // the difficulty that a new block should have when created at time given the + // parent block's time and difficulty. The calculation uses the Byzantium rules. + // Specification EIP-649: https://eips.ethereum.org/EIPS/eip-649 + calcDifficultyByzantium = makeDifficultyCalculator(big.NewInt(3000000)) ) // Various error messages to mark blocks invalid. These should be private to @@ -53,7 +69,6 @@ var ( errDuplicateUncle = errors.New("duplicate uncle") errUncleIsAncestor = errors.New("uncle is ancestor") errDanglingUncle = errors.New("uncle's parent is not ancestor") - errNonceOutOfRange = errors.New("nonce out of range") errInvalidDifficulty = errors.New("non-positive difficulty") errInvalidMixDigest = errors.New("invalid mix digest") errInvalidPoW = errors.New("invalid proof-of-work") @@ -178,7 +193,7 @@ func (ethash *Ethash) VerifyUncles(chain consensus.ChainReader, block *types.Blo return errTooManyUncles } // Gather the set of past uncles and ancestors - uncles, ancestors := set.New(), make(map[common.Hash]*types.Header) + uncles, ancestors := mapset.NewSet(), make(map[common.Hash]*types.Header) number, parent := block.NumberU64()-1, block.ParentHash() for i := 0; i < 7; i++ { @@ -199,7 +214,7 @@ func (ethash *Ethash) VerifyUncles(chain consensus.ChainReader, block *types.Blo for _, uncle := range block.Uncles() { // Make sure every uncle is rewarded only once hash := uncle.Hash() - if uncles.Has(hash) { + if uncles.Contains(hash) { return errDuplicateUncle } uncles.Add(hash) @@ -298,6 +313,8 @@ func (ethash *Ethash) CalcDifficulty(chain consensus.ChainReader, time uint64, p func CalcDifficulty(config *params.ChainConfig, time uint64, parent *types.Header) *big.Int { next := new(big.Int).Add(parent.Number, big1) switch { + case config.IsConstantinople(next): + return calcDifficultyConstantinople(time, parent) case config.IsByzantium(next): return calcDifficultyByzantium(time, parent) case config.IsHomestead(next): @@ -315,66 +332,69 @@ var ( big9 = big.NewInt(9) big10 = big.NewInt(10) bigMinus99 = big.NewInt(-99) - big2999999 = big.NewInt(2999999) ) -// calcDifficultyByzantium is the difficulty adjustment algorithm. It returns -// the difficulty that a new block should have when created at time given the -// parent block's time and difficulty. The calculation uses the Byzantium rules. -func calcDifficultyByzantium(time uint64, parent *types.Header) *big.Int { - // https://github.com/ethereum/EIPs/issues/100. - // algorithm: - // diff = (parent_diff + - // (parent_diff / 2048 * max((2 if len(parent.uncles) else 1) - ((timestamp - parent.timestamp) // 9), -99)) - // ) + 2^(periodCount - 2) +// makeDifficultyCalculator creates a difficultyCalculator with the given bomb-delay. +// the difficulty is calculated with Byzantium rules, which differs from Homestead in +// how uncles affect the calculation +func makeDifficultyCalculator(bombDelay *big.Int) func(time uint64, parent *types.Header) *big.Int { + // Note, the calculations below looks at the parent number, which is 1 below + // the block number. Thus we remove one from the delay given + bombDelayFromParent := new(big.Int).Sub(bombDelay, big1) + return func(time uint64, parent *types.Header) *big.Int { + // https://github.com/ethereum/EIPs/issues/100. + // algorithm: + // diff = (parent_diff + + // (parent_diff / 2048 * max((2 if len(parent.uncles) else 1) - ((timestamp - parent.timestamp) // 9), -99)) + // ) + 2^(periodCount - 2) - bigTime := new(big.Int).SetUint64(time) - bigParentTime := new(big.Int).Set(parent.Time) + bigTime := new(big.Int).SetUint64(time) + bigParentTime := new(big.Int).Set(parent.Time) - // holds intermediate values to make the algo easier to read & audit - x := new(big.Int) - y := new(big.Int) + // holds intermediate values to make the algo easier to read & audit + x := new(big.Int) + y := new(big.Int) - // (2 if len(parent_uncles) else 1) - (block_timestamp - parent_timestamp) // 9 - x.Sub(bigTime, bigParentTime) - x.Div(x, big9) - if parent.UncleHash == types.EmptyUncleHash { - x.Sub(big1, x) - } else { - x.Sub(big2, x) - } - // max((2 if len(parent_uncles) else 1) - (block_timestamp - parent_timestamp) // 9, -99) - if x.Cmp(bigMinus99) < 0 { - x.Set(bigMinus99) - } - // parent_diff + (parent_diff / 2048 * max((2 if len(parent.uncles) else 1) - ((timestamp - parent.timestamp) // 9), -99)) - y.Div(parent.Difficulty, params.DifficultyBoundDivisor) - x.Mul(y, x) - x.Add(parent.Difficulty, x) + // (2 if len(parent_uncles) else 1) - (block_timestamp - parent_timestamp) // 9 + x.Sub(bigTime, bigParentTime) + x.Div(x, big9) + if parent.UncleHash == types.EmptyUncleHash { + x.Sub(big1, x) + } else { + x.Sub(big2, x) + } + // max((2 if len(parent_uncles) else 1) - (block_timestamp - parent_timestamp) // 9, -99) + if x.Cmp(bigMinus99) < 0 { + x.Set(bigMinus99) + } + // parent_diff + (parent_diff / 2048 * max((2 if len(parent.uncles) else 1) - ((timestamp - parent.timestamp) // 9), -99)) + y.Div(parent.Difficulty, params.DifficultyBoundDivisor) + x.Mul(y, x) + x.Add(parent.Difficulty, x) - // minimum difficulty can ever be (before exponential factor) - if x.Cmp(params.MinimumDifficulty) < 0 { - x.Set(params.MinimumDifficulty) - } - // calculate a fake block numer for the ice-age delay: - // https://github.com/ethereum/EIPs/pull/669 - // fake_block_number = min(0, block.number - 3_000_000 - fakeBlockNumber := new(big.Int) - if parent.Number.Cmp(big2999999) >= 0 { - fakeBlockNumber = fakeBlockNumber.Sub(parent.Number, big2999999) // Note, parent is 1 less than the actual block number - } - // for the exponential factor - periodCount := fakeBlockNumber - periodCount.Div(periodCount, expDiffPeriod) + // minimum difficulty can ever be (before exponential factor) + if x.Cmp(params.MinimumDifficulty) < 0 { + x.Set(params.MinimumDifficulty) + } + // calculate a fake block number for the ice-age delay + // Specification: https://eips.ethereum.org/EIPS/eip-1234 + fakeBlockNumber := new(big.Int) + if parent.Number.Cmp(bombDelayFromParent) >= 0 { + fakeBlockNumber = fakeBlockNumber.Sub(parent.Number, bombDelayFromParent) + } + // for the exponential factor + periodCount := fakeBlockNumber + periodCount.Div(periodCount, expDiffPeriod) - // the exponential factor, commonly referred to as "the bomb" - // diff = diff + 2^(periodCount - 2) - if periodCount.Cmp(big1) > 0 { - y.Sub(periodCount, big2) - y.Exp(big2, y, nil) - x.Add(x, y) + // the exponential factor, commonly referred to as "the bomb" + // diff = diff + 2^(periodCount - 2) + if periodCount.Cmp(big1) > 0 { + y.Sub(periodCount, big2) + y.Exp(big2, y, nil) + x.Add(x, y) + } + return x } - return x } // calcDifficultyHomestead is the difficulty adjustment algorithm. It returns @@ -462,6 +482,13 @@ func calcDifficultyFrontier(time uint64, parent *types.Header) *big.Int { // VerifySeal implements consensus.Engine, checking whether the given block satisfies // the PoW difficulty requirements. func (ethash *Ethash) VerifySeal(chain consensus.ChainReader, header *types.Header) error { + return ethash.verifySeal(chain, header, false) +} + +// verifySeal checks whether a block satisfies the PoW difficulty requirements, +// either using the usual ethash cache for it, or alternatively using a full DAG +// to make remote mining fast. +func (ethash *Ethash) verifySeal(chain consensus.ChainReader, header *types.Header, fulldag bool) error { // If we're running a fake PoW, accept any seal as valid if ethash.config.PowMode == ModeFake || ethash.config.PowMode == ModeFullFake { time.Sleep(ethash.fakeDelay) @@ -472,34 +499,52 @@ func (ethash *Ethash) VerifySeal(chain consensus.ChainReader, header *types.Head } // If we're running a shared PoW, delegate verification to it if ethash.shared != nil { - return ethash.shared.VerifySeal(chain, header) - } - // Sanity check that the block number is below the lookup table size (60M blocks) - number := header.Number.Uint64() - if number/epochLength >= maxEpoch { - // Go < 1.7 cannot calculate new cache/dataset sizes (no fast prime check) - return errNonceOutOfRange + return ethash.shared.verifySeal(chain, header, fulldag) } // Ensure that we have a valid difficulty for the block if header.Difficulty.Sign() <= 0 { return errInvalidDifficulty } + // Recompute the digest and PoW values + number := header.Number.Uint64() - // Recompute the digest and PoW value and verify against the header - cache := ethash.cache(number) - size := datasetSize(number) - if ethash.config.PowMode == ModeTest { - size = 32 * 1024 + var ( + digest []byte + result []byte + ) + // If fast-but-heavy PoW verification was requested, use an ethash dataset + if fulldag { + dataset := ethash.dataset(number, true) + if dataset.generated() { + digest, result = hashimotoFull(dataset.dataset, ethash.SealHash(header).Bytes(), header.Nonce.Uint64()) + + // Datasets are unmapped in a finalizer. Ensure that the dataset stays alive + // until after the call to hashimotoFull so it's not unmapped while being used. + runtime.KeepAlive(dataset) + } else { + // Dataset not yet generated, don't hang, use a cache instead + fulldag = false + } } - digest, result := hashimotoLight(size, cache.cache, header.HashNoNonce().Bytes(), header.Nonce.Uint64()) - // Caches are unmapped in a finalizer. Ensure that the cache stays live - // until after the call to hashimotoLight so it's not unmapped while being used. - runtime.KeepAlive(cache) + // If slow-but-light PoW verification was requested (or DAG not yet ready), use an ethash cache + if !fulldag { + cache := ethash.cache(number) + size := datasetSize(number) + if ethash.config.PowMode == ModeTest { + size = 32 * 1024 + } + digest, result = hashimotoLight(size, cache.cache, ethash.SealHash(header).Bytes(), header.Nonce.Uint64()) + + // Caches are unmapped in a finalizer. Ensure that the cache stays alive + // until after the call to hashimotoLight so it's not unmapped while being used. + runtime.KeepAlive(cache) + } + // Verify the calculated values against the ones provided in the header if !bytes.Equal(header.MixDigest[:], digest) { return errInvalidMixDigest } - target := new(big.Int).Div(maxUint256, header.Difficulty) + target := new(big.Int).Div(two256, header.Difficulty) if new(big.Int).SetBytes(result).Cmp(target) > 0 { return errInvalidPoW } @@ -528,6 +573,29 @@ func (ethash *Ethash) Finalize(chain consensus.ChainReader, header *types.Header return types.NewBlock(header, txs, uncles, receipts), nil } +// SealHash returns the hash of a block prior to it being sealed. +func (ethash *Ethash) SealHash(header *types.Header) (hash common.Hash) { + hasher := sha3.NewLegacyKeccak256() + + 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, + }) + hasher.Sum(hash[:0]) + return hash +} + // Some weird constants to avoid constant memory allocs for them. var ( big8 = big.NewInt(8) @@ -543,6 +611,9 @@ func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header if config.IsByzantium(header.Number) { blockReward = ByzantiumBlockReward } + if config.IsConstantinople(header.Number) { + blockReward = ConstantinopleBlockReward + } // Accumulate the rewards for the miner and any included uncles reward := new(big.Int).Set(blockReward) r := new(big.Int) diff --git a/consensus/ethash/ethash.go b/consensus/ethash/ethash.go index 91e20112ae..78892e1da8 100644 --- a/consensus/ethash/ethash.go +++ b/consensus/ethash/ethash.go @@ -29,25 +29,28 @@ import ( "runtime" "strconv" "sync" + "sync/atomic" "time" "unsafe" mmap "github.com/edsrzf/mmap-go" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/rpc" "github.com/hashicorp/golang-lru/simplelru" - metrics "github.com/rcrowley/go-metrics" ) var ErrInvalidDumpMagic = errors.New("invalid dump magic") var ( - // maxUint256 is a big integer representing 2^256-1 - maxUint256 = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0)) + // two256 is a big integer representing 2^256 + two256 = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0)) // sharedEthash is a full instance that can be shared between multiple users. - sharedEthash = New(Config{"", 3, 0, "", 1, 0, ModeNormal}) + sharedEthash = New(Config{"", 3, 0, "", 1, 0, ModeNormal}, nil, false) // algorithmRevision is the data structure version used for file naming. algorithmRevision = 23 @@ -156,7 +159,7 @@ type lru struct { futureItem interface{} } -// newlru create a new least-recently-used cache for ither the verification caches +// newlru create a new least-recently-used cache for either the verification caches // or the mining datasets. func newlru(what string, maxItems int, new func(epoch uint64) interface{}) *lru { if maxItems <= 0 { @@ -279,6 +282,7 @@ type dataset struct { mmap mmap.MMap // Memory map itself to unmap before releasing dataset []uint32 // The actual cache data content once sync.Once // Ensures the cache is generated only once + done uint32 // Atomic flag to determine generation status } // newDataset creates a new ethash mining dataset and returns it as a plain Go @@ -290,6 +294,9 @@ func newDataset(epoch uint64) interface{} { // generate ensures that the dataset content is generated before use. func (d *dataset) generate(dir string, limit int, test bool) { d.once.Do(func() { + // Mark the dataset generated after we're done. This is needed for remote + defer atomic.StoreUint32(&d.done, 1) + csize := cacheSize(d.epoch*epochLength + 1) dsize := datasetSize(d.epoch*epochLength + 1) seed := seedHash(d.epoch*epochLength + 1) @@ -304,6 +311,8 @@ func (d *dataset) generate(dir string, limit int, test bool) { d.dataset = make([]uint32, dsize/4) generateDataset(d.dataset, d.epoch, cache) + + return } // Disk storage is needed, this will get fancy var endian string @@ -346,6 +355,13 @@ func (d *dataset) generate(dir string, limit int, test bool) { }) } +// generated returns whether this particular dataset finished generating already +// or not (it may not have been started at all). This is useful for remote miners +// to default to verification caches instead of blocking on DAG generations. +func (d *dataset) generated() bool { + return atomic.LoadUint32(&d.done) == 1 +} + // finalizer closes any file handlers and memory maps open. func (d *dataset) finalizer() { if d.mmap != nil { @@ -389,7 +405,37 @@ type Config struct { PowMode Mode } -// Ethash is a consensus engine based on proot-of-work implementing the ethash +// sealTask wraps a seal block with relative result channel for remote sealer thread. +type sealTask struct { + block *types.Block + results chan<- *types.Block +} + +// mineResult wraps the pow solution parameters for the specified block. +type mineResult struct { + nonce types.BlockNonce + mixDigest common.Hash + hash common.Hash + + errc chan error +} + +// hashrate wraps the hash rate submitted by the remote sealer. +type hashrate struct { + id common.Hash + ping time.Time + rate uint64 + + done chan struct{} +} + +// sealWork wraps a seal work package for remote sealer. +type sealWork struct { + errc chan error + res chan [4]string +} + +// Ethash is a consensus engine based on proof-of-work implementing the ethash // algorithm. type Ethash struct { config Config @@ -403,16 +449,27 @@ type Ethash struct { update chan struct{} // Notification channel to update mining parameters hashrate metrics.Meter // Meter tracking the average hashrate + // Remote sealer related fields + workCh chan *sealTask // Notification channel to push new work and relative result channel to remote sealer + fetchWorkCh chan *sealWork // Channel used for remote sealer to fetch mining work + submitWorkCh chan *mineResult // Channel used for remote sealer to submit their mining result + fetchRateCh chan chan uint64 // Channel used to gather submitted hash rate for local or remote sealer. + submitRateCh chan *hashrate // Channel used for remote sealer to submit their mining hashrate + // The fields below are hooks for testing shared *Ethash // Shared PoW verifier to avoid cache regeneration fakeFail uint64 // Block number which fails PoW check even in fake mode fakeDelay time.Duration // Time delay to sleep for before returning from verify - lock sync.Mutex // Ensures thread safety for the in-memory caches and mining fields + lock sync.Mutex // Ensures thread safety for the in-memory caches and mining fields + closeOnce sync.Once // Ensures exit channel will not be closed twice. + exitCh chan chan error // Notification channel to exiting backend threads } -// New creates a full sized ethash PoW scheme. -func New(config Config) *Ethash { +// New creates a full sized ethash PoW scheme and starts a background thread for +// remote mining, also optionally notifying a batch of remote services of new work +// packages. +func New(config Config, notify []string, noverify bool) *Ethash { if config.CachesInMem <= 0 { log.Warn("One ethash cache must always be in memory", "requested", config.CachesInMem) config.CachesInMem = 1 @@ -423,19 +480,41 @@ func New(config Config) *Ethash { if config.DatasetDir != "" && config.DatasetsOnDisk > 0 { log.Info("Disk storage enabled for ethash DAGs", "dir", config.DatasetDir, "count", config.DatasetsOnDisk) } - return &Ethash{ - config: config, - caches: newlru("cache", config.CachesInMem, newCache), - datasets: newlru("dataset", config.DatasetsInMem, newDataset), - update: make(chan struct{}), - hashrate: metrics.NewMeter(), + ethash := &Ethash{ + config: config, + caches: newlru("cache", config.CachesInMem, newCache), + datasets: newlru("dataset", config.DatasetsInMem, newDataset), + update: make(chan struct{}), + hashrate: metrics.NewMeterForced(), + workCh: make(chan *sealTask), + fetchWorkCh: make(chan *sealWork), + submitWorkCh: make(chan *mineResult), + fetchRateCh: make(chan chan uint64), + submitRateCh: make(chan *hashrate), + exitCh: make(chan chan error), } + go ethash.remote(notify, noverify) + return ethash } // NewTester creates a small sized ethash PoW scheme useful only for testing // purposes. -func NewTester() *Ethash { - return New(Config{CachesInMem: 1, PowMode: ModeTest}) +func NewTester(notify []string, noverify bool) *Ethash { + ethash := &Ethash{ + config: Config{PowMode: ModeTest}, + caches: newlru("cache", 1, newCache), + datasets: newlru("dataset", 1, newDataset), + update: make(chan struct{}), + hashrate: metrics.NewMeterForced(), + workCh: make(chan *sealTask), + fetchWorkCh: make(chan *sealWork), + submitWorkCh: make(chan *mineResult), + fetchRateCh: make(chan chan uint64), + submitRateCh: make(chan *hashrate), + exitCh: make(chan chan error), + } + go ethash.remote(notify, noverify) + return ethash } // NewFaker creates a ethash consensus engine with a fake PoW scheme that accepts @@ -489,6 +568,22 @@ func NewShared() *Ethash { return &Ethash{shared: sharedEthash} } +// Close closes the exit channel to notify all backend threads exiting. +func (ethash *Ethash) Close() error { + var err error + ethash.closeOnce.Do(func() { + // Short circuit if the exit channel is not allocated. + if ethash.exitCh == nil { + return + } + errc := make(chan error) + ethash.exitCh <- errc + err = <-errc + close(ethash.exitCh) + }) + return err +} + // cache tries to retrieve a verification cache for the specified block number // by first checking against a list of in-memory caches, then against caches // stored on disk, and finally generating one if none can be found. @@ -511,20 +606,34 @@ func (ethash *Ethash) cache(block uint64) *cache { // dataset tries to retrieve a mining dataset for the specified block number // by first checking against a list of in-memory datasets, then against DAGs // stored on disk, and finally generating one if none can be found. -func (ethash *Ethash) dataset(block uint64) *dataset { +// +// If async is specified, not only the future but the current DAG is also +// generates on a background thread. +func (ethash *Ethash) dataset(block uint64, async bool) *dataset { + // Retrieve the requested ethash dataset epoch := block / epochLength currentI, futureI := ethash.datasets.get(epoch) current := currentI.(*dataset) - // Wait for generation finish. - current.generate(ethash.config.DatasetDir, ethash.config.DatasetsOnDisk, ethash.config.PowMode == ModeTest) + // If async is specified, generate everything in a background thread + if async && !current.generated() { + go func() { + current.generate(ethash.config.DatasetDir, ethash.config.DatasetsOnDisk, ethash.config.PowMode == ModeTest) - // If we need a new future dataset, now's a good time to regenerate it. - if futureI != nil { - future := futureI.(*dataset) - go future.generate(ethash.config.DatasetDir, ethash.config.DatasetsOnDisk, ethash.config.PowMode == ModeTest) + if futureI != nil { + future := futureI.(*dataset) + future.generate(ethash.config.DatasetDir, ethash.config.DatasetsOnDisk, ethash.config.PowMode == ModeTest) + } + }() + } else { + // Either blocking generation was requested, or already done + current.generate(ethash.config.DatasetDir, ethash.config.DatasetsOnDisk, ethash.config.PowMode == ModeTest) + + if futureI != nil { + future := futureI.(*dataset) + go future.generate(ethash.config.DatasetDir, ethash.config.DatasetsOnDisk, ethash.config.PowMode == ModeTest) + } } - return current } @@ -561,14 +670,44 @@ func (ethash *Ethash) SetThreads(threads int) { // Hashrate implements PoW, returning the measured rate of the search invocations // per second over the last minute. +// Note the returned hashrate includes local hashrate, but also includes the total +// hashrate of all remote miner. func (ethash *Ethash) Hashrate() float64 { - return ethash.hashrate.Rate1() + // Short circuit if we are run the ethash in normal/test mode. + if ethash.config.PowMode != ModeNormal && ethash.config.PowMode != ModeTest { + return ethash.hashrate.Rate1() + } + var res = make(chan uint64, 1) + + select { + case ethash.fetchRateCh <- res: + case <-ethash.exitCh: + // Return local hashrate only if ethash is stopped. + return ethash.hashrate.Rate1() + } + + // Gather total submitted hash rate of remote sealers. + return ethash.hashrate.Rate1() + float64(<-res) } -// APIs implements consensus.Engine, returning the user facing RPC APIs. Currently -// that is empty. +// APIs implements consensus.Engine, returning the user facing RPC APIs. func (ethash *Ethash) APIs(chain consensus.ChainReader) []rpc.API { - return nil + // In order to ensure backward compatibility, we exposes ethash RPC APIs + // to both eth and ethash namespaces. + return []rpc.API{ + { + Namespace: "eth", + Version: "1.0", + Service: &API{ethash}, + Public: true, + }, + { + Namespace: "ethash", + Version: "1.0", + Service: &API{ethash}, + Public: true, + }, + } } // SeedHash is the seed to use for generating a verification cache and the mining diff --git a/consensus/ethash/ethash_test.go b/consensus/ethash/ethash_test.go index 31116da437..90cb6470f7 100644 --- a/consensus/ethash/ethash_test.go +++ b/consensus/ethash/ethash_test.go @@ -23,23 +23,34 @@ import ( "os" "sync" "testing" + "time" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" ) // Tests that ethash works correctly in test mode. func TestTestMode(t *testing.T) { - head := &types.Header{Number: big.NewInt(1), Difficulty: big.NewInt(100)} + header := &types.Header{Number: big.NewInt(1), Difficulty: big.NewInt(100)} - ethash := NewTester() - block, err := ethash.Seal(nil, types.NewBlockWithHeader(head), nil) + ethash := NewTester(nil, false) + defer ethash.Close() + + results := make(chan *types.Block) + err := ethash.Seal(nil, types.NewBlockWithHeader(header), results, nil) if err != nil { t.Fatalf("failed to seal block: %v", err) } - head.Nonce = types.EncodeNonce(block.Nonce()) - head.MixDigest = block.MixDigest() - if err := ethash.VerifySeal(nil, head); err != nil { - t.Fatalf("unexpected verification error: %v", err) + select { + case block := <-results: + header.Nonce = types.EncodeNonce(block.Nonce()) + header.MixDigest = block.MixDigest() + if err := ethash.VerifySeal(nil, header); err != nil { + t.Fatalf("unexpected verification error: %v", err) + } + case <-time.NewTimer(time.Second).C: + t.Error("sealing result timeout") } } @@ -51,7 +62,8 @@ func TestCacheFileEvict(t *testing.T) { t.Fatal(err) } defer os.RemoveAll(tmpdir) - e := New(Config{CachesInMem: 3, CachesOnDisk: 10, CacheDir: tmpdir, PowMode: ModeTest}) + e := New(Config{CachesInMem: 3, CachesOnDisk: 10, CacheDir: tmpdir, PowMode: ModeTest}, nil, false) + defer e.Close() workers := 8 epochs := 100 @@ -73,7 +85,85 @@ func verifyTest(wg *sync.WaitGroup, e *Ethash, workerIndex, epochs int) { if block < 0 { block = 0 } - head := &types.Header{Number: big.NewInt(block), Difficulty: big.NewInt(100)} - e.VerifySeal(nil, head) + header := &types.Header{Number: big.NewInt(block), Difficulty: big.NewInt(100)} + e.VerifySeal(nil, header) + } +} + +func TestRemoteSealer(t *testing.T) { + ethash := NewTester(nil, false) + defer ethash.Close() + + api := &API{ethash} + if _, err := api.GetWork(); err != errNoMiningWork { + t.Error("expect to return an error indicate there is no mining work") + } + header := &types.Header{Number: big.NewInt(1), Difficulty: big.NewInt(100)} + block := types.NewBlockWithHeader(header) + sealhash := ethash.SealHash(header) + + // Push new work. + results := make(chan *types.Block) + ethash.Seal(nil, block, results, nil) + + var ( + work [4]string + err error + ) + if work, err = api.GetWork(); err != nil || work[0] != sealhash.Hex() { + t.Error("expect to return a mining work has same hash") + } + + if res := api.SubmitWork(types.BlockNonce{}, sealhash, common.Hash{}); res { + t.Error("expect to return false when submit a fake solution") + } + // Push new block with same block number to replace the original one. + header = &types.Header{Number: big.NewInt(1), Difficulty: big.NewInt(1000)} + block = types.NewBlockWithHeader(header) + sealhash = ethash.SealHash(header) + ethash.Seal(nil, block, results, nil) + + if work, err = api.GetWork(); err != nil || work[0] != sealhash.Hex() { + t.Error("expect to return the latest pushed work") + } +} + +func TestHashRate(t *testing.T) { + var ( + hashrate = []hexutil.Uint64{100, 200, 300} + expect uint64 + ids = []common.Hash{common.HexToHash("a"), common.HexToHash("b"), common.HexToHash("c")} + ) + ethash := NewTester(nil, false) + defer ethash.Close() + + if tot := ethash.Hashrate(); tot != 0 { + t.Error("expect the result should be zero") + } + + api := &API{ethash} + for i := 0; i < len(hashrate); i += 1 { + if res := api.SubmitHashRate(hashrate[i], ids[i]); !res { + t.Error("remote miner submit hashrate failed") + } + expect += uint64(hashrate[i]) + } + if tot := ethash.Hashrate(); tot != float64(expect) { + t.Error("expect total hashrate should be same") + } +} + +func TestClosedRemoteSealer(t *testing.T) { + ethash := NewTester(nil, false) + time.Sleep(1 * time.Second) // ensure exit channel is listening + ethash.Close() + + api := &API{ethash} + if _, err := api.GetWork(); err != errEthashStopped { + t.Error("expect to return an error to indicate ethash is stopped") + } + + if res := api.SubmitHashRate(hexutil.Uint64(100), common.HexToHash("a")); res { + t.Error("expect to return false when submit hashrate to a stopped ethash") } } diff --git a/consensus/ethash/sealer.go b/consensus/ethash/sealer.go index b5e742d8bb..3a0919ca99 100644 --- a/consensus/ethash/sealer.go +++ b/consensus/ethash/sealer.go @@ -17,35 +17,55 @@ package ethash import ( + "bytes" crand "crypto/rand" + "encoding/json" + "errors" "math" "math/big" "math/rand" + "net/http" "runtime" "sync" + "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" ) +const ( + // staleThreshold is the maximum depth of the acceptable stale but valid ethash solution. + staleThreshold = 7 +) + +var ( + errNoMiningWork = errors.New("no mining work available yet") + errInvalidSealResult = errors.New("invalid or stale proof-of-work solution") +) + // Seal implements consensus.Engine, attempting to find a nonce that satisfies // the block's difficulty requirements. -func (ethash *Ethash) Seal(chain consensus.ChainReader, block *types.Block, stop <-chan struct{}) (*types.Block, error) { +func (ethash *Ethash) Seal(chain consensus.ChainReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error { // If we're running a fake PoW, simply return a 0 nonce immediately if ethash.config.PowMode == ModeFake || ethash.config.PowMode == ModeFullFake { header := block.Header() header.Nonce, header.MixDigest = types.BlockNonce{}, common.Hash{} - return block.WithSeal(header), nil + select { + case results <- block.WithSeal(header): + default: + log.Warn("Sealing result is not read by miner", "mode", "fake", "sealhash", ethash.SealHash(block.Header())) + } + return nil } // If we're running a shared PoW, delegate sealing to it if ethash.shared != nil { - return ethash.shared.Seal(chain, block, stop) + return ethash.shared.Seal(chain, block, results, stop) } // Create a runner and the multiple search threads it directs abort := make(chan struct{}) - found := make(chan *types.Block) ethash.lock.Lock() threads := ethash.threads @@ -53,7 +73,7 @@ func (ethash *Ethash) Seal(chain consensus.ChainReader, block *types.Block, stop seed, err := crand.Int(crand.Reader, big.NewInt(math.MaxInt64)) if err != nil { ethash.lock.Unlock() - return nil, err + return err } ethash.rand = rand.New(rand.NewSource(seed.Int64())) } @@ -64,32 +84,47 @@ func (ethash *Ethash) Seal(chain consensus.ChainReader, block *types.Block, stop if threads < 0 { threads = 0 // Allows disabling local mining without extra logic around local/remote } - var pend sync.WaitGroup + // Push new work to remote sealer + if ethash.workCh != nil { + ethash.workCh <- &sealTask{block: block, results: results} + } + var ( + pend sync.WaitGroup + locals = make(chan *types.Block) + ) for i := 0; i < threads; i++ { pend.Add(1) go func(id int, nonce uint64) { defer pend.Done() - ethash.mine(block, id, nonce, abort, found) + ethash.mine(block, id, nonce, abort, locals) }(i, uint64(ethash.rand.Int63())) } // Wait until sealing is terminated or a nonce is found - var result *types.Block - select { - case <-stop: - // Outside abort, stop all miner threads - close(abort) - case result = <-found: - // One of the threads found a block, abort all others - close(abort) - case <-ethash.update: - // Thread count was changed on user request, restart - close(abort) + go func() { + var result *types.Block + select { + case <-stop: + // Outside abort, stop all miner threads + close(abort) + case result = <-locals: + // One of the threads found a block, abort all others + select { + case results <- result: + default: + log.Warn("Sealing result is not read by miner", "mode", "local", "sealhash", ethash.SealHash(block.Header())) + } + close(abort) + case <-ethash.update: + // Thread count was changed on user request, restart + close(abort) + if err := ethash.Seal(chain, block, results, stop); err != nil { + log.Error("Failed to restart sealing after update", "err", err) + } + } + // Wait for all miners to terminate and return the block pend.Wait() - return ethash.Seal(chain, block, stop) - } - // Wait for all miners to terminate and return the block - pend.Wait() - return result, nil + }() + return nil } // mine is the actual proof-of-work miner that searches for a nonce starting from @@ -98,10 +133,10 @@ func (ethash *Ethash) mine(block *types.Block, id int, seed uint64, abort chan s // Extract some data from the header var ( header = block.Header() - hash = header.HashNoNonce().Bytes() - target = new(big.Int).Div(maxUint256, header.Difficulty) + hash = ethash.SealHash(header).Bytes() + target = new(big.Int).Div(two256, header.Difficulty) number = header.Number.Uint64() - dataset = ethash.dataset(number) + dataset = ethash.dataset(number, false) ) // Start generating random nonces until we abort or find a good one var ( @@ -150,3 +185,187 @@ search: // during sealing so it's not unmapped while being read. runtime.KeepAlive(dataset) } + +// remote is a standalone goroutine to handle remote mining related stuff. +func (ethash *Ethash) remote(notify []string, noverify bool) { + var ( + works = make(map[common.Hash]*types.Block) + rates = make(map[common.Hash]hashrate) + + results chan<- *types.Block + currentBlock *types.Block + currentWork [4]string + + notifyTransport = &http.Transport{} + notifyClient = &http.Client{ + Transport: notifyTransport, + Timeout: time.Second, + } + notifyReqs = make([]*http.Request, len(notify)) + ) + // notifyWork notifies all the specified mining endpoints of the availability of + // new work to be processed. + notifyWork := func() { + work := currentWork + blob, _ := json.Marshal(work) + + for i, url := range notify { + // Terminate any previously pending request and create the new work + if notifyReqs[i] != nil { + notifyTransport.CancelRequest(notifyReqs[i]) + } + notifyReqs[i], _ = http.NewRequest("POST", url, bytes.NewReader(blob)) + notifyReqs[i].Header.Set("Content-Type", "application/json") + + // Push the new work concurrently to all the remote nodes + go func(req *http.Request, url string) { + res, err := notifyClient.Do(req) + if err != nil { + log.Warn("Failed to notify remote miner", "err", err) + } else { + log.Trace("Notified remote miner", "miner", url, "hash", log.Lazy{Fn: func() common.Hash { return common.HexToHash(work[0]) }}, "target", work[2]) + res.Body.Close() + } + }(notifyReqs[i], url) + } + } + // makeWork creates a work package for external miner. + // + // The work package consists of 3 strings: + // result[0], 32 bytes hex encoded current block header pow-hash + // result[1], 32 bytes hex encoded seed hash used for DAG + // result[2], 32 bytes hex encoded boundary condition ("target"), 2^256/difficulty + // result[3], hex encoded block number + makeWork := func(block *types.Block) { + hash := ethash.SealHash(block.Header()) + + currentWork[0] = hash.Hex() + currentWork[1] = common.BytesToHash(SeedHash(block.NumberU64())).Hex() + currentWork[2] = common.BytesToHash(new(big.Int).Div(two256, block.Difficulty()).Bytes()).Hex() + currentWork[3] = hexutil.EncodeBig(block.Number()) + + // Trace the seal work fetched by remote sealer. + currentBlock = block + works[hash] = block + } + // submitWork verifies the submitted pow solution, returning + // whether the solution was accepted or not (not can be both a bad pow as well as + // any other error, like no pending work or stale mining result). + submitWork := func(nonce types.BlockNonce, mixDigest common.Hash, sealhash common.Hash) bool { + if currentBlock == nil { + log.Error("Pending work without block", "sealhash", sealhash) + return false + } + // Make sure the work submitted is present + block := works[sealhash] + if block == nil { + log.Warn("Work submitted but none pending", "sealhash", sealhash, "curnumber", currentBlock.NumberU64()) + return false + } + // Verify the correctness of submitted result. + header := block.Header() + header.Nonce = nonce + header.MixDigest = mixDigest + + start := time.Now() + if !noverify { + if err := ethash.verifySeal(nil, header, true); err != nil { + log.Warn("Invalid proof-of-work submitted", "sealhash", sealhash, "elapsed", time.Since(start), "err", err) + return false + } + } + // Make sure the result channel is assigned. + if results == nil { + log.Warn("Ethash result channel is empty, submitted mining result is rejected") + return false + } + log.Trace("Verified correct proof-of-work", "sealhash", sealhash, "elapsed", time.Since(start)) + + // Solutions seems to be valid, return to the miner and notify acceptance. + solution := block.WithSeal(header) + + // The submitted solution is within the scope of acceptance. + if solution.NumberU64()+staleThreshold > currentBlock.NumberU64() { + select { + case results <- solution: + log.Debug("Work submitted is acceptable", "number", solution.NumberU64(), "sealhash", sealhash, "hash", solution.Hash()) + return true + default: + log.Warn("Sealing result is not read by miner", "mode", "remote", "sealhash", sealhash) + return false + } + } + // The submitted block is too old to accept, drop it. + log.Warn("Work submitted is too old", "number", solution.NumberU64(), "sealhash", sealhash, "hash", solution.Hash()) + return false + } + + ticker := time.NewTicker(5 * time.Second) + defer ticker.Stop() + + for { + select { + case work := <-ethash.workCh: + // Update current work with new received block. + // Note same work can be past twice, happens when changing CPU threads. + results = work.results + + makeWork(work.block) + + // Notify and requested URLs of the new work availability + notifyWork() + + case work := <-ethash.fetchWorkCh: + // Return current mining work to remote miner. + if currentBlock == nil { + work.errc <- errNoMiningWork + } else { + work.res <- currentWork + } + + case result := <-ethash.submitWorkCh: + // Verify submitted PoW solution based on maintained mining blocks. + if submitWork(result.nonce, result.mixDigest, result.hash) { + result.errc <- nil + } else { + result.errc <- errInvalidSealResult + } + + case result := <-ethash.submitRateCh: + // Trace remote sealer's hash rate by submitted value. + rates[result.id] = hashrate{rate: result.rate, ping: time.Now()} + close(result.done) + + case req := <-ethash.fetchRateCh: + // Gather all hash rate submitted by remote sealer. + var total uint64 + for _, rate := range rates { + // this could overflow + total += rate.rate + } + req <- total + + case <-ticker.C: + // Clear stale submitted hash rate. + for id, rate := range rates { + if time.Since(rate.ping) > 10*time.Second { + delete(rates, id) + } + } + // Clear stale pending blocks + if currentBlock != nil { + for hash, block := range works { + if block.NumberU64()+staleThreshold <= currentBlock.NumberU64() { + delete(works, hash) + } + } + } + + case errc := <-ethash.exitCh: + // Exit remote loop if ethash is closed and return relevant error. + errc <- nil + log.Trace("Ethash remote sealer is exiting") + return + } + } +} diff --git a/consensus/ethash/sealer_test.go b/consensus/ethash/sealer_test.go new file mode 100644 index 0000000000..436359af7c --- /dev/null +++ b/consensus/ethash/sealer_test.go @@ -0,0 +1,211 @@ +package ethash + +import ( + "encoding/json" + "io/ioutil" + "math/big" + "net" + "net/http" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// Tests whether remote HTTP servers are correctly notified of new work. +func TestRemoteNotify(t *testing.T) { + // Start a simple webserver to capture notifications + sink := make(chan [3]string) + + server := &http.Server{ + Handler: http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + blob, err := ioutil.ReadAll(req.Body) + if err != nil { + t.Fatalf("failed to read miner notification: %v", err) + } + var work [3]string + if err := json.Unmarshal(blob, &work); err != nil { + t.Fatalf("failed to unmarshal miner notification: %v", err) + } + sink <- work + }), + } + // Open a custom listener to extract its local address + listener, err := net.Listen("tcp", "localhost:0") + if err != nil { + t.Fatalf("failed to open notification server: %v", err) + } + defer listener.Close() + + go server.Serve(listener) + + // Wait for server to start listening + var tries int + for tries = 0; tries < 10; tries++ { + conn, _ := net.DialTimeout("tcp", listener.Addr().String(), 1*time.Second) + if conn != nil { + break + } + } + if tries == 10 { + t.Fatal("tcp listener not ready for more than 10 seconds") + } + + // Create the custom ethash engine + ethash := NewTester([]string{"http://" + listener.Addr().String()}, false) + defer ethash.Close() + + // Stream a work task and ensure the notification bubbles out + header := &types.Header{Number: big.NewInt(1), Difficulty: big.NewInt(100)} + block := types.NewBlockWithHeader(header) + + ethash.Seal(nil, block, nil, nil) + select { + case work := <-sink: + if want := ethash.SealHash(header).Hex(); work[0] != want { + t.Errorf("work packet hash mismatch: have %s, want %s", work[0], want) + } + if want := common.BytesToHash(SeedHash(header.Number.Uint64())).Hex(); work[1] != want { + t.Errorf("work packet seed mismatch: have %s, want %s", work[1], want) + } + target := new(big.Int).Div(new(big.Int).Lsh(big.NewInt(1), 256), header.Difficulty) + if want := common.BytesToHash(target.Bytes()).Hex(); work[2] != want { + t.Errorf("work packet target mismatch: have %s, want %s", work[2], want) + } + case <-time.After(3 * time.Second): + t.Fatalf("notification timed out") + } +} + +// Tests that pushing work packages fast to the miner doesn't cause any data race +// issues in the notifications. +func TestRemoteMultiNotify(t *testing.T) { + // Start a simple webserver to capture notifications + sink := make(chan [3]string, 64) + + server := &http.Server{ + Handler: http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + blob, err := ioutil.ReadAll(req.Body) + if err != nil { + t.Fatalf("failed to read miner notification: %v", err) + } + var work [3]string + if err := json.Unmarshal(blob, &work); err != nil { + t.Fatalf("failed to unmarshal miner notification: %v", err) + } + sink <- work + }), + } + // Open a custom listener to extract its local address + listener, err := net.Listen("tcp", "localhost:0") + if err != nil { + t.Fatalf("failed to open notification server: %v", err) + } + defer listener.Close() + + go server.Serve(listener) + + // Create the custom ethash engine + ethash := NewTester([]string{"http://" + listener.Addr().String()}, false) + defer ethash.Close() + + // Stream a lot of work task and ensure all the notifications bubble out + for i := 0; i < cap(sink); i++ { + header := &types.Header{Number: big.NewInt(int64(i)), Difficulty: big.NewInt(100)} + block := types.NewBlockWithHeader(header) + + ethash.Seal(nil, block, nil, nil) + } + for i := 0; i < cap(sink); i++ { + select { + case <-sink: + case <-time.After(3 * time.Second): + t.Fatalf("notification %d timed out", i) + } + } +} + +// Tests whether stale solutions are correctly processed. +func TestStaleSubmission(t *testing.T) { + ethash := NewTester(nil, true) + defer ethash.Close() + api := &API{ethash} + + fakeNonce, fakeDigest := types.BlockNonce{0x01, 0x02, 0x03}, common.HexToHash("deadbeef") + + testcases := []struct { + headers []*types.Header + submitIndex int + submitRes bool + }{ + // Case1: submit solution for the latest mining package + { + []*types.Header{ + {ParentHash: common.BytesToHash([]byte{0xa}), Number: big.NewInt(1), Difficulty: big.NewInt(100000000)}, + }, + 0, + true, + }, + // Case2: submit solution for the previous package but have same parent. + { + []*types.Header{ + {ParentHash: common.BytesToHash([]byte{0xb}), Number: big.NewInt(2), Difficulty: big.NewInt(100000000)}, + {ParentHash: common.BytesToHash([]byte{0xb}), Number: big.NewInt(2), Difficulty: big.NewInt(100000001)}, + }, + 0, + true, + }, + // Case3: submit stale but acceptable solution + { + []*types.Header{ + {ParentHash: common.BytesToHash([]byte{0xc}), Number: big.NewInt(3), Difficulty: big.NewInt(100000000)}, + {ParentHash: common.BytesToHash([]byte{0xd}), Number: big.NewInt(9), Difficulty: big.NewInt(100000000)}, + }, + 0, + true, + }, + // Case4: submit very old solution + { + []*types.Header{ + {ParentHash: common.BytesToHash([]byte{0xe}), Number: big.NewInt(10), Difficulty: big.NewInt(100000000)}, + {ParentHash: common.BytesToHash([]byte{0xf}), Number: big.NewInt(17), Difficulty: big.NewInt(100000000)}, + }, + 0, + false, + }, + } + results := make(chan *types.Block, 16) + + for id, c := range testcases { + for _, h := range c.headers { + ethash.Seal(nil, types.NewBlockWithHeader(h), results, nil) + } + if res := api.SubmitWork(fakeNonce, ethash.SealHash(c.headers[c.submitIndex]), fakeDigest); res != c.submitRes { + t.Errorf("case %d submit result mismatch, want %t, get %t", id+1, c.submitRes, res) + } + if !c.submitRes { + continue + } + select { + case res := <-results: + if res.Header().Nonce != fakeNonce { + t.Errorf("case %d block nonce mismatch, want %s, get %s", id+1, fakeNonce, res.Header().Nonce) + } + if res.Header().MixDigest != fakeDigest { + t.Errorf("case %d block digest mismatch, want %s, get %s", id+1, fakeDigest, res.Header().MixDigest) + } + if res.Header().Difficulty.Uint64() != c.headers[c.submitIndex].Difficulty.Uint64() { + t.Errorf("case %d block difficulty mismatch, want %d, get %d", id+1, c.headers[c.submitIndex].Difficulty, res.Header().Difficulty) + } + if res.Header().Number.Uint64() != c.headers[c.submitIndex].Number.Uint64() { + t.Errorf("case %d block number mismatch, want %d, get %d", id+1, c.headers[c.submitIndex].Number.Uint64(), res.Header().Number.Uint64()) + } + if res.Header().ParentHash != c.headers[c.submitIndex].ParentHash { + t.Errorf("case %d block parent hash mismatch, want %s, get %s", id+1, c.headers[c.submitIndex].ParentHash.Hex(), res.Header().ParentHash.Hex()) + } + case <-time.NewTimer(time.Second).C: + t.Errorf("case %d fetch ethash result timeout", id+1) + } + } +} diff --git a/console/bridge.go b/console/bridge.go index b28cc438e2..33277cf6ee 100644 --- a/console/bridge.go +++ b/console/bridge.go @@ -87,7 +87,7 @@ func (b *bridge) NewAccount(call otto.FunctionCall) (response otto.Value) { // OpenWallet is a wrapper around personal.openWallet which can interpret and // react to certain error messages, such as the Trezor PIN matrix request. func (b *bridge) OpenWallet(call otto.FunctionCall) (response otto.Value) { - // Make sure we have an wallet specified to open + // Make sure we have a wallet specified to open if !call.Argument(0).IsString() { throwJSException("first argument must be the wallet URL to open") } @@ -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 @@ -271,7 +296,7 @@ func (b *bridge) SleepBlocks(call otto.FunctionCall) (response otto.Value) { } type jsonrpcCall struct { - Id int64 + ID int64 Method string Params []interface{} } @@ -304,7 +329,7 @@ func (b *bridge) Send(call otto.FunctionCall) (response otto.Value) { resps, _ := call.Otto.Object("new Array()") for _, req := range reqs { resp, _ := call.Otto.Object(`({"jsonrpc":"2.0"})`) - resp.Set("id", req.Id) + resp.Set("id", req.ID) var result json.RawMessage err = b.client.Call(&result, req.Method, req.Params...) switch err := err.(type) { diff --git a/console/console.go b/console/console.go index 52fe1f542a..50196d7f48 100644 --- a/console/console.go +++ b/console/console.go @@ -26,6 +26,7 @@ import ( "regexp" "sort" "strings" + "syscall" "github.com/ethereum/go-ethereum/internal/jsre" "github.com/ethereum/go-ethereum/internal/web3ext" @@ -59,7 +60,7 @@ type Config struct { Preload []string // Absolute paths to JavaScript files to preload } -// Console is a JavaScript interpreted runtime environment. It is a fully fleged +// Console is a JavaScript interpreted runtime environment. It is a fully fledged // JavaScript console attached to a running node via an external or in-process RPC // client. type Console struct { @@ -72,6 +73,8 @@ type Console struct { printer io.Writer // Output writer to serialize any display strings to } +// New initializes a JavaScript interpreted runtime environment and sets defaults +// with the config struct. func New(config Config) (*Console, error) { // Handle unset config values gracefully if config.Prompter == nil { @@ -117,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 { @@ -233,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)) } @@ -311,7 +314,7 @@ func (c *Console) Interactive() { input = "" // Current user input scheduler = make(chan string) // Channel to send the next prompt on and receive the input ) - // Start a goroutine to listen for promt requests and send back inputs + // Start a goroutine to listen for prompt requests and send back inputs go func() { for { // Read the next user input @@ -332,7 +335,7 @@ func (c *Console) Interactive() { }() // Monitor Ctrl-C too in case the input is empty and we need to bail abort := make(chan os.Signal, 1) - signal.Notify(abort, os.Interrupt) + signal.Notify(abort, syscall.SIGINT, syscall.SIGTERM) // Start sending prompts to the user and reading back inputs for { diff --git a/console/console_test.go b/console/console_test.go index 7b1629c032..55d799725a 100644 --- a/console/console_test.go +++ b/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) } @@ -201,7 +201,7 @@ func TestInteractive(t *testing.T) { go tester.console.Interactive() - // Wait for a promt and send a statement back + // Wait for a prompt and send a statement back select { case <-tester.input.scheduler: case <-time.After(time.Second): @@ -212,7 +212,7 @@ func TestInteractive(t *testing.T) { case <-time.After(time.Second): t.Fatalf("input feedback timeout") } - // Wait for the second promt and ensure first statement was evaluated + // Wait for the second prompt and ensure first statement was evaluated select { case <-tester.input.scheduler: case <-time.After(time.Second): @@ -249,7 +249,7 @@ func TestExecute(t *testing.T) { } // Tests that the JavaScript objects returned by statement executions are properly -// pretty printed instead of just displaing "[object]". +// pretty printed instead of just displaying "[object]". func TestPrettyPrint(t *testing.T) { tester := newTester(t, nil) defer tester.Close(t) @@ -300,7 +300,7 @@ func TestIndenting(t *testing.T) { }{ {`var a = 1;`, 0}, {`"some string"`, 0}, - {`"some string with (parentesis`, 0}, + {`"some string with (parenthesis`, 0}, {`"some string with newline ("`, 0}, {`function v(a,b) {}`, 0}, diff --git a/console/prompter.go b/console/prompter.go index c477b48178..29a53aeadd 100644 --- a/console/prompter.go +++ b/console/prompter.go @@ -27,7 +27,7 @@ import ( // Only this reader may be used for input because it keeps an internal buffer. var Stdin = newTerminalPrompter() -// UserPrompter defines the methods needed by the console to promt the user for +// UserPrompter defines the methods needed by the console to prompt the user for // various types of inputs. type UserPrompter interface { // PromptInput displays the given prompt to the user and requests some textual @@ -43,7 +43,7 @@ type UserPrompter interface { // choice to be made, returning that choice. PromptConfirm(prompt string) (bool, error) - // SetHistory sets the the input scrollback history that the prompter will allow + // SetHistory sets the input scrollback history that the prompter will allow // the user to scroll back to. SetHistory(history []string) @@ -149,7 +149,7 @@ func (p *terminalPrompter) PromptConfirm(prompt string) (bool, error) { return false, err } -// SetHistory sets the the input scrollback history that the prompter will allow +// SetHistory sets the input scrollback history that the prompter will allow // the user to scroll back to. func (p *terminalPrompter) SetHistory(history []string) { p.State.ReadHistory(strings.NewReader(strings.Join(history, "\n"))) diff --git a/containers/docker/develop-alpine/Dockerfile b/containers/docker/develop-alpine/Dockerfile deleted file mode 100644 index 1f3e1112ec..0000000000 --- a/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/containers/docker/develop-ubuntu/Dockerfile b/containers/docker/develop-ubuntu/Dockerfile deleted file mode 100644 index 8c4fe9f595..0000000000 --- a/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/containers/docker/master-alpine/Dockerfile b/containers/docker/master-alpine/Dockerfile deleted file mode 100644 index c7b71c7263..0000000000 --- a/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.7 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/containers/docker/master-ubuntu/Dockerfile b/containers/docker/master-ubuntu/Dockerfile deleted file mode 100644 index bba70abfdd..0000000000 --- a/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.7 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/containers/vagrant/.gitignore b/containers/vagrant/.gitignore deleted file mode 100644 index 8000dd9db4..0000000000 --- a/containers/vagrant/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.vagrant diff --git a/containers/vagrant/Vagrantfile b/containers/vagrant/Vagrantfile deleted file mode 100644 index 72ec366e21..0000000000 --- a/containers/vagrant/Vagrantfile +++ /dev/null @@ -1,38 +0,0 @@ -# -*- mode: ruby -*- -# vi: set ft=ruby : - -require 'yaml' - -VAGRANTFILE_API_VERSION = 2 -VM_RAM = 2048 - -Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| - - config.vm.define "ubuntu", :primary => true do |ubuntu| - ubuntu.vm.box = "ubuntu/trusty64" - ubuntu.vm.provision "shell", :path => "provisioners/shell/ubuntu.sh" - end - - config.vm.define "debian", :primary => true do |debian| - debian.vm.box = "debian/jessie64" - debian.vm.provision "shell", :path => "provisioners/shell/debian.sh" - end - - config.vm.define "centos", :autostart => false do |centos| - centos.vm.box = "centos/7" - centos.vm.provision "shell", :path => "provisioners/shell/centos.sh" - end - - config.vm.provider "virtualbox" do |vb| - vb.memory = VM_RAM - end - - config.vm.provider "libvirt" do |lv| - lv.memory = VM_RAM - - config.vm.synced_folder ".", "/home/vagrant/sync", :disabled => true - end - - config.vm.synced_folder ".", "/vagrant", :disabled => true - config.vm.synced_folder "../../", "/home/vagrant/go/src/github.com/ethereum/go-ethereum" -end diff --git a/containers/vagrant/provisioners/shell/centos.sh b/containers/vagrant/provisioners/shell/centos.sh deleted file mode 100755 index 744da4bfd4..0000000000 --- a/containers/vagrant/provisioners/shell/centos.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -sudo yum install -y git wget -sudo yum update -y - -wget --continue https://storage.googleapis.com/golang/go1.8.1.linux-amd64.tar.gz -sudo tar -C /usr/local -xzf go1.8.1.linux-amd64.tar.gz - -GETH_PATH="~vagrant/go/src/github.com/ethereum/go-ethereum/build/bin/" - -echo "export PATH=$PATH:/usr/local/go/bin:$GETH_PATH" >> ~vagrant/.bashrc diff --git a/containers/vagrant/provisioners/shell/debian.sh b/containers/vagrant/provisioners/shell/debian.sh deleted file mode 100755 index 1c1793336d..0000000000 --- a/containers/vagrant/provisioners/shell/debian.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -sudo apt-get install -y build-essential git-all wget -sudo apt-get update - -wget --continue https://storage.googleapis.com/golang/go1.8.1.linux-amd64.tar.gz -sudo tar -C /usr/local -xzf go1.8.1.linux-amd64.tar.gz - -GETH_PATH="~vagrant/go/src/github.com/ethereum/go-ethereum/build/bin/" - -echo "export PATH=$PATH:/usr/local/go/bin:$GETH_PATH" >> ~vagrant/.bashrc diff --git a/containers/vagrant/provisioners/shell/ubuntu.sh b/containers/vagrant/provisioners/shell/ubuntu.sh deleted file mode 100755 index 1c1793336d..0000000000 --- a/containers/vagrant/provisioners/shell/ubuntu.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -sudo apt-get install -y build-essential git-all wget -sudo apt-get update - -wget --continue https://storage.googleapis.com/golang/go1.8.1.linux-amd64.tar.gz -sudo tar -C /usr/local -xzf go1.8.1.linux-amd64.tar.gz - -GETH_PATH="~vagrant/go/src/github.com/ethereum/go-ethereum/build/bin/" - -echo "export PATH=$PATH:/usr/local/go/bin:$GETH_PATH" >> ~vagrant/.bashrc diff --git a/contracts/chequebook/api.go b/contracts/chequebook/api.go index b2b2365f31..fb7080308b 100644 --- a/contracts/chequebook/api.go +++ b/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/contracts/chequebook/cheque.go b/contracts/chequebook/cheque.go index 92bd896e0a..32e8406768 100644 --- a/contracts/chequebook/cheque.go +++ b/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/contracts/chequebook/cheque_test.go b/contracts/chequebook/cheque_test.go index b7555d0815..4bd2e176b1 100644 --- a/contracts/chequebook/cheque_test.go +++ b/contracts/chequebook/cheque_test.go @@ -46,7 +46,7 @@ func newTestBackend() *backends.SimulatedBackend { addr0: {Balance: big.NewInt(1000000000)}, addr1: {Balance: big.NewInt(1000000000)}, addr2: {Balance: big.NewInt(1000000000)}, - }) + }, 10000000) } func deploy(prvKey *ecdsa.PrivateKey, amount *big.Int, backend *backends.SimulatedBackend) (common.Address, error) { @@ -281,8 +281,8 @@ func TestDeposit(t *testing.T) { t.Fatalf("expected balance %v, got %v", exp, chbook.Balance()) } - // autodeposit every 30ms if new cheque issued - interval := 30 * time.Millisecond + // autodeposit every 200ms if new cheque issued + interval := 200 * time.Millisecond chbook.AutoDeposit(interval, common.Big1, balance) _, err = chbook.Issue(addr1, amount) if err != nil { diff --git a/contracts/chequebook/contract/chequebook.go b/contracts/chequebook/contract/chequebook.go index e275ac9b8d..3129b811c6 100644 --- a/contracts/chequebook/contract/chequebook.go +++ b/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/contracts/chequebook/gencode.go b/contracts/chequebook/gencode.go index 45f6d68f3e..ddfe8d1512 100644 --- a/contracts/chequebook/gencode.go +++ b/contracts/chequebook/gencode.go @@ -40,7 +40,7 @@ var ( ) func main() { - backend := backends.NewSimulatedBackend(testAlloc) + backend := backends.NewSimulatedBackend(testAlloc, uint64(100000000)) auth := bind.NewKeyedTransactor(testKey) // Deploy the contract, get the code. diff --git a/contracts/ens/contract/ens.go b/contracts/ens/contract/ens.go index cbf6cb05b3..8827071afc 100644 --- a/contracts/ens/contract/ens.go +++ b/contracts/ens/contract/ens.go @@ -227,10 +227,10 @@ 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. +// TTL is a free data retrieval call binding the contract method 0x16a25cbd. // // Solidity: function ttl(node bytes32) constant returns(uint64) -func (_ENS *ENSCaller) Ttl(opts *bind.CallOpts, node [32]byte) (uint64, error) { +func (_ENS *ENSCaller) TTL(opts *bind.CallOpts, node [32]byte) (uint64, error) { var ( ret0 = new(uint64) ) @@ -239,18 +239,18 @@ func (_ENS *ENSCaller) Ttl(opts *bind.CallOpts, node [32]byte) (uint64, error) { return *ret0, err } -// Ttl is a free data retrieval call binding the contract method 0x16a25cbd. +// TTL is a free data retrieval call binding the contract method 0x16a25cbd. // // Solidity: function ttl(node bytes32) constant returns(uint64) -func (_ENS *ENSSession) Ttl(node [32]byte) (uint64, error) { - return _ENS.Contract.Ttl(&_ENS.CallOpts, node) +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. +// TTL is a free data retrieval call binding the contract method 0x16a25cbd. // // Solidity: function ttl(node bytes32) constant returns(uint64) -func (_ENS *ENSCallerSession) Ttl(node [32]byte) (uint64, error) { - return _ENS.Contract.Ttl(&_ENS.CallOpts, node) +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. @@ -682,7 +682,7 @@ func (it *ENSNewTTLIterator) Close() error { // ENSNewTTL represents a NewTTL event raised by the ENS contract. type ENSNewTTL struct { Node [32]byte - Ttl uint64 + TTL uint64 Raw types.Log // Blockchain specific contextual infos } diff --git a/contracts/ens/ens.go b/contracts/ens/ens.go index 06045a5cd8..b1841ab17d 100644 --- a/contracts/ens/ens.go +++ b/contracts/ens/ens.go @@ -35,7 +35,7 @@ var ( TestNetAddress = common.HexToAddress("0x112234455c3a32fd11230c42e7bccd4a84e02010") ) -// swarm domain name registry and resolver +// ENS is the swarm domain name registry and resolver type ENS struct { *contract.ENSSession contractBackend bind.ContractBackend @@ -48,7 +48,6 @@ func NewENS(transactOpts *bind.TransactOpts, contractAddr common.Address, contra if err != nil { return nil, err } - return &ENS{ &contract.ENSSession{ Contract: ens, @@ -60,27 +59,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. + // Deploy the ENS registry ensAddr, _, _, err := contract.DeployENS(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,90 +85,111 @@ 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 { +func EnsNode(name string) common.Hash { parentNode, parentLabel := ensParentNode(name) 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) getRegistrar(node [32]byte) (*contract.FIFSRegistrarSession, error) { + registrarAddr, err := ens.Owner(node) if err != nil { return nil, err } - - registrar, err := contract.NewFIFSRegistrar(registrarAddr, self.contractBackend) + 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) { - node := ensNode(name) +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) if err != nil { return common.Hash{}, err } - return common.BytesToHash(ret[:]), nil } +// Addr is a non-transactional call that returns the address associated with a name. +func (ens *ENS) Addr(name string) (common.Address, error) { + node := EnsNode(name) + + 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 (ens *ENS) SetAddr(name string, addr common.Address) (*types.Transaction, error) { + node := EnsNode(name) + + resolver, err := ens.getResolver(node) + if err != nil { + return nil, err + } + 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) { - node := ensNode(name) +func (ens *ENS) SetContentHash(name string, hash common.Hash) (*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) } diff --git a/contracts/ens/ens_test.go b/contracts/ens/ens_test.go index 0016f47dbf..cd64fbf15f 100644 --- a/contracts/ens/ens_test.go +++ b/contracts/ens/ens_test.go @@ -22,20 +22,22 @@ import ( "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/contracts/ens/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) + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + name = "my name on ENS" + hash = crypto.Keccak256Hash([]byte("my content")) + addr = crypto.PubkeyToAddress(key.PublicKey) + testAddr = common.HexToAddress("0x1234123412341234123412341234123412341234") ) func TestENS(t *testing.T) { - contractBackend := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}}) + contractBackend := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}}, 10000000) transactOpts := bind.NewKeyedTransactor(key) ensAddr, ens, err := DeployENS(transactOpts, contractBackend) @@ -55,7 +57,7 @@ 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 { + if _, err := ens.SetResolver(EnsNode(name), resolverAddr); err != nil { t.Fatalf("can't set resolver: %v", err) } contractBackend.Commit() @@ -74,4 +76,19 @@ func TestENS(t *testing.T) { if vhost != hash { t.Fatalf("resolve error, expected %v, got %v", hash.Hex(), vhost.Hex()) } + + // set the address for the name + if _, err = ens.SetAddr(name, testAddr); err != nil { + t.Fatalf("can't set address: %v", err) + } + contractBackend.Commit() + + // Try to resolve the name to an address + recoveredAddr, err := ens.Addr(name) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + if vhost != hash { + t.Fatalf("resolve error, expected %v, got %v", testAddr.Hex(), recoveredAddr.Hex()) + } } diff --git a/core/asm/asm.go b/core/asm/asm.go index ce22f93f92..4257198cc7 100644 --- a/core/asm/asm.go +++ b/core/asm/asm.go @@ -109,9 +109,9 @@ func PrintDisassembled(code string) error { it := NewInstructionIterator(script) for it.Next() { if it.Arg() != nil && 0 < len(it.Arg()) { - fmt.Printf("%06v: %v 0x%x\n", it.PC(), it.Op(), it.Arg()) + fmt.Printf("%05x: %v 0x%x\n", it.PC(), it.Op(), it.Arg()) } else { - fmt.Printf("%06v: %v\n", it.PC(), it.Op()) + fmt.Printf("%05x: %v\n", it.PC(), it.Op()) } } return it.Error() @@ -124,9 +124,9 @@ func Disassemble(script []byte) ([]string, error) { it := NewInstructionIterator(script) for it.Next() { if it.Arg() != nil && 0 < len(it.Arg()) { - instrs = append(instrs, fmt.Sprintf("%06v: %v 0x%x\n", it.PC(), it.Op(), it.Arg())) + instrs = append(instrs, fmt.Sprintf("%05x: %v 0x%x\n", it.PC(), it.Op(), it.Arg())) } else { - instrs = append(instrs, fmt.Sprintf("%06v: %v\n", it.PC(), it.Op())) + instrs = append(instrs, fmt.Sprintf("%05x: %v\n", it.PC(), it.Op())) } } if err := it.Error(); err != nil { diff --git a/core/asm/compiler.go b/core/asm/compiler.go index 318c4e4d80..c7a5440701 100644 --- a/core/asm/compiler.go +++ b/core/asm/compiler.go @@ -17,7 +17,6 @@ package asm import ( - "errors" "fmt" "math/big" "os" @@ -52,7 +51,7 @@ func NewCompiler(debug bool) *Compiler { // the compiler. // // feed is the first pass in the compile stage as it -// collect the used labels in the program and keeps a +// collects the used labels in the program and keeps a // program counter which is used to determine the locations // of the jump dests. The labels can than be used in the // second stage to push labels and determine the right @@ -114,15 +113,15 @@ func (c *Compiler) Compile() (string, []error) { } // next returns the next token and increments the -// posititon. +// position. func (c *Compiler) next() token { token := c.tokens[c.pos] c.pos++ return token } -// compile line compiles a single line instruction e.g. -// "push 1", "jump @labal". +// compileLine compiles a single line instruction e.g. +// "push 1", "jump @label". func (c *Compiler) compileLine() error { n := c.next() if n.typ != lineStart { @@ -237,19 +236,16 @@ func (c *Compiler) pushBin(v interface{}) { // isPush returns whether the string op is either any of // push(N). func isPush(op string) bool { - return op == "push" + return strings.ToUpper(op) == "PUSH" } // isJump returns whether the string op is jump(i) func isJump(op string) bool { - return op == "jumpi" || op == "jump" + return strings.ToUpper(op) == "JUMPI" || strings.ToUpper(op) == "JUMP" } // toBinary converts text to a vm.OpCode func toBinary(text string) vm.OpCode { - if isPush(text) { - text = "push1" - } return vm.StringToOp(strings.ToUpper(text)) } @@ -264,11 +260,6 @@ func (err compileError) Error() string { return fmt.Sprintf("%d syntax error: unexpected %v, expected %v", err.lineno, err.got, err.want) } -var ( - errExpBol = errors.New("expected beginning of line") - errExpElementOrLabel = errors.New("expected beginning of line") -) - func compileErr(c token, got, want string) error { return compileError{ got: got, diff --git a/core/asm/lexer.go b/core/asm/lexer.go index a34b2cbd8f..91caeb27bc 100644 --- a/core/asm/lexer.go +++ b/core/asm/lexer.go @@ -48,7 +48,7 @@ const ( lineEnd // emitted when a line ends invalidStatement // any invalid statement element // any element during element parsing - label // label is emitted when a labal is found + label // label is emitted when a label is found labelDef // label definition is emitted when a new label is found number // number is emitted when a number is found stringValue // stringValue is emitted when a string has been found @@ -206,7 +206,7 @@ func lexLine(l *lexer) stateFn { return lexComment case isSpace(r): l.ignore() - case isAlphaNumeric(r) || r == '_': + case isLetter(r) || r == '_': return lexElement case isNumber(r): return lexNumber @@ -242,7 +242,7 @@ func lexLabel(l *lexer) stateFn { } // lexInsideString lexes the inside of a string until -// until the state function finds the closing quote. +// the state function finds the closing quote. // It returns the lex text state function. func lexInsideString(l *lexer) stateFn { if l.acceptRunUntil('"') { @@ -278,7 +278,7 @@ func lexElement(l *lexer) stateFn { return lexLine } -func isAlphaNumeric(t rune) bool { +func isLetter(t rune) bool { return unicode.IsLetter(t) } diff --git a/core/bench_test.go b/core/bench_test.go index f976331d17..53cba05170 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "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" @@ -110,7 +111,8 @@ func init() { func genTxRing(naccounts int) func(int, *BlockGen) { from := 0 return func(i int, gen *BlockGen) { - gas := CalcGasLimit(gen.PrevBlock(i - 1)) + block := gen.PrevBlock(i - 1) + gas := CalcGasLimit(block, block.GasLimit(), block.GasLimit()) for { gas -= params.TxGas if gas < params.TxGas { @@ -148,7 +150,7 @@ 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 = ethdb.NewMemDatabase() } else { dir, err := ioutil.TempDir("", "eth-core-bench") if err != nil { @@ -173,7 +175,7 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) { // Time the insertion of the new chain. // State and blocks are stored in the same DB. - chainman, _ := NewBlockChain(db, gspec.Config, ethash.NewFaker(), vm.Config{}) + chainman, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) defer chainman.Stop() b.ReportAllocs() b.ResetTimer() @@ -234,13 +236,15 @@ func makeChainForBench(db ethdb.Database, full bool, count uint64) { ReceiptHash: types.EmptyRootHash, } hash = header.Hash() - WriteHeader(db, header) - WriteCanonicalHash(db, hash, n) - WriteTd(db, hash, n, big.NewInt(int64(n+1))) + + rawdb.WriteHeader(db, header) + rawdb.WriteCanonicalHash(db, hash, n) + rawdb.WriteTd(db, hash, n, big.NewInt(int64(n+1))) + if full || n == 0 { block := types.NewBlockWithHeader(header) - WriteBody(db, hash, n, block.Body()) - WriteBlockReceipts(db, hash, n, nil) + rawdb.WriteBody(db, hash, n, block.Body()) + rawdb.WriteReceipts(db, hash, n, nil) } } } @@ -283,7 +287,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) { if err != nil { b.Fatalf("error opening database at %v: %v", dir, err) } - chain, err := NewBlockChain(db, params.TestChainConfig, ethash.NewFaker(), vm.Config{}) + chain, err := NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil) if err != nil { b.Fatalf("error creating chain: %v", err) } @@ -292,11 +296,10 @@ func benchReadChain(b *testing.B, full bool, count uint64) { header := chain.GetHeaderByNumber(n) if full { hash := header.Hash() - GetBody(db, hash, n) - GetBlockReceipts(db, hash, n) + rawdb.ReadBody(db, hash, n) + rawdb.ReadReceipts(db, hash, n) } } - chain.Stop() db.Close() } diff --git a/core/block_validator.go b/core/block_validator.go index 143728bb84..3b9496fece 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -45,17 +45,14 @@ func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, engin return validator } -// ValidateBody validates the given block's uncles and verifies the the block +// ValidateBody validates the given block's uncles and verifies the block // header's transaction and uncle roots. The headers are assumed to be already // validated at this point. func (v *BlockValidator) ValidateBody(block *types.Block) error { // Check whether the block's known, and if not, that it's linkable - if v.bc.HasBlockAndState(block.Hash()) { + if v.bc.HasBlockAndState(block.Hash(), block.NumberU64()) { return ErrKnownBlock } - if !v.bc.HasBlockAndState(block.ParentHash()) { - return consensus.ErrUnknownAncestor - } // Header validity is known at this point, check the uncles and transactions header := block.Header() if err := v.engine.VerifyUncles(v.bc, block); err != nil { @@ -67,6 +64,12 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error { if hash := types.DeriveSha(block.Transactions()); hash != header.TxHash { return fmt.Errorf("transaction root hash mismatch: have %x, want %x", hash, header.TxHash) } + if !v.bc.HasBlockAndState(block.ParentHash(), block.NumberU64()-1) { + if !v.bc.HasBlock(block.ParentHash(), block.NumberU64()-1) { + return consensus.ErrUnknownAncestor + } + return consensus.ErrPrunedAncestor + } return nil } @@ -98,9 +101,11 @@ func (v *BlockValidator) ValidateState(block, parent *types.Block, statedb *stat return nil } -// CalcGasLimit computes the gas limit of the next block after parent. -// This is miner strategy, not consensus protocol. -func CalcGasLimit(parent *types.Block) uint64 { +// CalcGasLimit computes the gas limit of the next block after parent. It aims +// to keep the baseline gas above the provided floor, and increase it towards the +// ceil if the blocks are full. If the ceil is exceeded, it will always decrease +// the gas allowance. +func CalcGasLimit(parent *types.Block, gasFloor, gasCeil uint64) uint64 { // contrib = (parentGasUsed * 3 / 2) / 1024 contrib := (parent.GasUsed() + parent.GasUsed()/2) / params.GasLimitBoundDivisor @@ -118,12 +123,16 @@ func CalcGasLimit(parent *types.Block) uint64 { if limit < params.MinGasLimit { limit = params.MinGasLimit } - // however, if we're now below the target (TargetGasLimit) we increase the - // limit as much as we can (parentGasLimit / 1024 -1) - if limit < params.TargetGasLimit { + // If we're outside our allowed gas range, we try to hone towards them + if limit < gasFloor { limit = parent.GasLimit() + decay - if limit > params.TargetGasLimit { - limit = params.TargetGasLimit + if limit > gasFloor { + limit = gasFloor + } + } else if limit > gasCeil { + limit = parent.GasLimit() - decay + if limit < gasCeil { + limit = gasCeil } } return limit diff --git a/core/block_validator_test.go b/core/block_validator_test.go index e668601f38..9319a7835d 100644 --- a/core/block_validator_test.go +++ b/core/block_validator_test.go @@ -32,7 +32,7 @@ import ( func TestHeaderVerification(t *testing.T) { // Create a simple chain to verify var ( - testdb, _ = ethdb.NewMemDatabase() + testdb = ethdb.NewMemDatabase() gspec = &Genesis{Config: params.TestChainConfig} genesis = gspec.MustCommit(testdb) blocks, _ = GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), testdb, 8, nil) @@ -42,7 +42,7 @@ func TestHeaderVerification(t *testing.T) { headers[i] = block.Header() } // Run the header checker for blocks one-by-one, checking for both valid and invalid nonces - chain, _ := NewBlockChain(testdb, params.TestChainConfig, ethash.NewFaker(), vm.Config{}) + chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil) defer chain.Stop() for i := 0; i < len(blocks); i++ { @@ -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 = ethdb.NewMemDatabase() gspec = &Genesis{Config: params.TestChainConfig} genesis = gspec.MustCommit(testdb) blocks, _ = GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), testdb, 8, nil) @@ -106,11 +106,11 @@ func testHeaderConcurrentVerification(t *testing.T, threads int) { var results <-chan error if valid { - chain, _ := NewBlockChain(testdb, params.TestChainConfig, ethash.NewFaker(), vm.Config{}) + chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil) _, results = chain.engine.VerifyHeaders(chain, headers, seals) chain.Stop() } else { - chain, _ := NewBlockChain(testdb, params.TestChainConfig, ethash.NewFakeFailer(uint64(len(headers)-1)), vm.Config{}) + chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeFailer(uint64(len(headers)-1)), vm.Config{}, nil) _, results = chain.engine.VerifyHeaders(chain, headers, seals) chain.Stop() } @@ -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 = ethdb.NewMemDatabase() gspec = &Genesis{Config: params.TestChainConfig} genesis = gspec.MustCommit(testdb) blocks, _ = GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), testdb, 1024, nil) @@ -173,7 +173,7 @@ func testHeaderConcurrentAbortion(t *testing.T, threads int) { defer runtime.GOMAXPROCS(old) // Start the verifications and immediately abort - chain, _ := NewBlockChain(testdb, params.TestChainConfig, ethash.NewFakeDelayer(time.Millisecond), vm.Config{}) + chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeDelayer(time.Millisecond), vm.Config{}, nil) defer chain.Stop() abort, results := chain.engine.VerifyHeaders(chain, headers, seals) diff --git a/core/blockchain.go b/core/blockchain.go index d5e139e311..7b4f4b3038 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -29,7 +29,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/mclock" + "github.com/ethereum/go-ethereum/common/prque" "github.com/ethereum/go-ethereum/consensus" + "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" @@ -45,7 +47,10 @@ import ( ) var ( - blockInsertTimer = metrics.NewTimer("chain/inserts") + 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") ) @@ -53,14 +58,31 @@ var ( const ( bodyCacheLimit = 256 blockCacheLimit = 256 + receiptsCacheLimit = 32 maxFutureBlocks = 256 maxTimeFutureBlocks = 30 badBlockLimit = 10 + 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) + 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 // block. The Blockchain manages chain imports, reverts, chain reorganisations. // @@ -76,31 +98,36 @@ const ( // included in the canonical one where as GetBlockByNumber always represents the // canonical chain. type BlockChain struct { - config *params.ChainConfig // chain & network configuration + chainConfig *params.ChainConfig // Chain & network configuration + cacheConfig *CacheConfig // Cache configuration for pruning + + db ethdb.Database // Low level persistent database to store final content in + triegc *prque.Prque // Priority queue mapping block numbers to tries to gc + gcproc time.Duration // Accumulates canonical block processing for trie dumping hc *HeaderChain - chainDb ethdb.Database rmLogsFeed event.Feed chainFeed event.Feed 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 checkpoint int // checkpoint counts towards the new checkpoint - currentBlock *types.Block // Current head of the block chain - currentFastBlock *types.Block // Current head of the fast-sync chain (may be above the block chain!) + currentBlock atomic.Value // Current head of the block chain + currentFastBlock atomic.Value // Current head of the fast-sync chain (may be above the block chain!) - stateCache state.Database // State database to reuse between imports (contains state cache) - 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 - futureBlocks *lru.Cache // future blocks are blocks added for later processing + stateCache state.Database // State database to reuse between imports (contains state cache) + bodyCache *lru.Cache // Cache for the most recent block bodies + bodyRLPCache *lru.Cache // Cache for the most recent block bodies in RLP encoded format + receiptsCache *lru.Cache // Cache for the most recent receipts per block + blockCache *lru.Cache // Cache for the most recent entire blocks + futureBlocks *lru.Cache // future blocks are blocks added for later processing quit chan struct{} // blockchain quit channel running int32 // running must be called atomically @@ -113,37 +140,50 @@ type BlockChain struct { validator Validator // block and state validator interface vmConfig vm.Config - badBlocks *lru.Cache // Bad block cache + badBlocks *lru.Cache // Bad block cache + shouldPreserve func(*types.Block) bool // Function used to determine whether should preserve the given block. } // NewBlockChain returns a fully initialised block chain using information // available in the database. It initialises the default Ethereum Validator and // Processor. -func NewBlockChain(chainDb ethdb.Database, config *params.ChainConfig, engine consensus.Engine, vmConfig vm.Config) (*BlockChain, error) { +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{ + TrieCleanLimit: 256, + TrieDirtyLimit: 256, + TrieTimeLimit: 5 * time.Minute, + } + } bodyCache, _ := lru.New(bodyCacheLimit) bodyRLPCache, _ := lru.New(bodyCacheLimit) + receiptsCache, _ := lru.New(receiptsCacheLimit) blockCache, _ := lru.New(blockCacheLimit) futureBlocks, _ := lru.New(maxFutureBlocks) badBlocks, _ := lru.New(badBlockLimit) bc := &BlockChain{ - config: config, - chainDb: chainDb, - stateCache: state.NewDatabase(chainDb), - quit: make(chan struct{}), - bodyCache: bodyCache, - bodyRLPCache: bodyRLPCache, - blockCache: blockCache, - futureBlocks: futureBlocks, - engine: engine, - vmConfig: vmConfig, - badBlocks: badBlocks, + chainConfig: chainConfig, + cacheConfig: cacheConfig, + db: db, + triegc: prque.New(nil), + stateCache: state.NewDatabaseWithCache(db, cacheConfig.TrieCleanLimit), + quit: make(chan struct{}), + shouldPreserve: shouldPreserve, + bodyCache: bodyCache, + bodyRLPCache: bodyRLPCache, + receiptsCache: receiptsCache, + blockCache: blockCache, + futureBlocks: futureBlocks, + engine: engine, + vmConfig: vmConfig, + badBlocks: badBlocks, } - bc.SetValidator(NewBlockValidator(config, bc, engine)) - bc.SetProcessor(NewStateProcessor(config, bc, engine)) + bc.SetValidator(NewBlockValidator(chainConfig, bc, engine)) + bc.SetProcessor(NewStateProcessor(chainConfig, bc, engine)) var err error - bc.hc, err = NewHeaderChain(chainDb, config, engine, bc.getProcInterrupt) + bc.hc, err = NewHeaderChain(db, chainConfig, engine, bc.getProcInterrupt) if err != nil { return nil, err } @@ -176,11 +216,16 @@ 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 { // Restore the last known head block - head := GetHeadBlockHash(bc.chainDb) + head := rawdb.ReadHeadBlockHash(bc.db) if head == (common.Hash{}) { // Corrupt or empty database, init from scratch log.Warn("Empty database, resetting chain") @@ -196,15 +241,17 @@ func (bc *BlockChain) loadLastState() error { // Make sure the state associated with the block is available if _, err := state.New(currentBlock.Root(), bc.stateCache); err != nil { // Dangling block without a state associated, init from scratch - log.Warn("Head state missing, resetting chain", "number", currentBlock.Number(), "hash", currentBlock.Hash()) - return bc.Reset() + log.Warn("Head state missing, repairing chain", "number", currentBlock.Number(), "hash", currentBlock.Hash()) + if err := bc.repair(¤tBlock); err != nil { + return err + } } // Everything seems to be fine, set as the head block - bc.currentBlock = currentBlock + bc.currentBlock.Store(currentBlock) // Restore the last known head header - currentHeader := bc.currentBlock.Header() - if head := GetHeadHeaderHash(bc.chainDb); head != (common.Hash{}) { + currentHeader := currentBlock.Header() + if head := rawdb.ReadHeadHeaderHash(bc.db); head != (common.Hash{}) { if header := bc.GetHeaderByHash(head); header != nil { currentHeader = header } @@ -212,21 +259,23 @@ func (bc *BlockChain) loadLastState() error { bc.hc.SetCurrentHeader(currentHeader) // Restore the last known head fast block - bc.currentFastBlock = bc.currentBlock - if head := GetHeadFastBlockHash(bc.chainDb); head != (common.Hash{}) { + bc.currentFastBlock.Store(currentBlock) + if head := rawdb.ReadHeadFastBlockHash(bc.db); head != (common.Hash{}) { if block := bc.GetBlockByHash(head); block != nil { - bc.currentFastBlock = block + bc.currentFastBlock.Store(block) } } // Issue a status log for the user - headerTd := bc.GetTd(currentHeader.Hash(), currentHeader.Number.Uint64()) - blockTd := bc.GetTd(bc.currentBlock.Hash(), bc.currentBlock.NumberU64()) - fastTd := bc.GetTd(bc.currentFastBlock.Hash(), bc.currentFastBlock.NumberU64()) + currentFastBlock := bc.CurrentFastBlock() - log.Info("Loaded most recent local header", "number", currentHeader.Number, "hash", currentHeader.Hash(), "td", headerTd) - log.Info("Loaded most recent local full block", "number", bc.currentBlock.Number(), "hash", bc.currentBlock.Hash(), "td", blockTd) - log.Info("Loaded most recent local fast block", "number", bc.currentFastBlock.Number(), "hash", bc.currentFastBlock.Hash(), "td", fastTd) + headerTd := bc.GetTd(currentHeader.Hash(), currentHeader.Number.Uint64()) + blockTd := bc.GetTd(currentBlock.Hash(), currentBlock.NumberU64()) + fastTd := bc.GetTd(currentFastBlock.Hash(), currentFastBlock.NumberU64()) + + log.Info("Loaded most recent local header", "number", currentHeader.Number, "hash", currentHeader.Hash(), "td", headerTd, "age", common.PrettyAge(time.Unix(currentHeader.Time.Int64(), 0))) + log.Info("Loaded most recent local full block", "number", currentBlock.Number(), "hash", currentBlock.Hash(), "td", blockTd, "age", common.PrettyAge(time.Unix(currentBlock.Time().Int64(), 0))) + log.Info("Loaded most recent local fast block", "number", currentFastBlock.Number(), "hash", currentFastBlock.Hash(), "td", fastTd, "age", common.PrettyAge(time.Unix(currentFastBlock.Time().Int64(), 0))) return nil } @@ -238,12 +287,12 @@ 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(hash common.Hash, num uint64) { - DeleteBody(bc.chainDb, hash, num) + delFn := func(db rawdb.DatabaseDeleter, hash common.Hash, num uint64) { + rawdb.DeleteBody(db, hash, num) } bc.hc.SetHead(head, delFn) currentHeader := bc.hc.CurrentHeader() @@ -251,36 +300,37 @@ func (bc *BlockChain) SetHead(head uint64) error { // Clear out any stale content from the caches bc.bodyCache.Purge() bc.bodyRLPCache.Purge() + bc.receiptsCache.Purge() bc.blockCache.Purge() bc.futureBlocks.Purge() // Rewind the block chain, ensuring we don't end up with a stateless head block - if bc.currentBlock != nil && currentHeader.Number.Uint64() < bc.currentBlock.NumberU64() { - bc.currentBlock = bc.GetBlock(currentHeader.Hash(), currentHeader.Number.Uint64()) + if currentBlock := bc.CurrentBlock(); currentBlock != nil && currentHeader.Number.Uint64() < currentBlock.NumberU64() { + bc.currentBlock.Store(bc.GetBlock(currentHeader.Hash(), currentHeader.Number.Uint64())) } - if bc.currentBlock != nil { - if _, err := state.New(bc.currentBlock.Root(), bc.stateCache); err != nil { + if currentBlock := bc.CurrentBlock(); currentBlock != nil { + if _, err := state.New(currentBlock.Root(), bc.stateCache); err != nil { // Rewound state missing, rolled back to before pivot, reset to genesis - bc.currentBlock = nil + bc.currentBlock.Store(bc.genesisBlock) } } // Rewind the fast block in a simpleton way to the target head - if bc.currentFastBlock != nil && currentHeader.Number.Uint64() < bc.currentFastBlock.NumberU64() { - bc.currentFastBlock = bc.GetBlock(currentHeader.Hash(), currentHeader.Number.Uint64()) + if currentFastBlock := bc.CurrentFastBlock(); currentFastBlock != nil && currentHeader.Number.Uint64() < currentFastBlock.NumberU64() { + bc.currentFastBlock.Store(bc.GetBlock(currentHeader.Hash(), currentHeader.Number.Uint64())) } // If either blocks reached nil, reset to the genesis state - if bc.currentBlock == nil { - bc.currentBlock = bc.genesisBlock + if currentBlock := bc.CurrentBlock(); currentBlock == nil { + bc.currentBlock.Store(bc.genesisBlock) } - if bc.currentFastBlock == nil { - bc.currentFastBlock = bc.genesisBlock - } - if err := WriteHeadBlockHash(bc.chainDb, bc.currentBlock.Hash()); err != nil { - log.Crit("Failed to reset head full block", "err", err) - } - if err := WriteHeadFastBlockHash(bc.chainDb, bc.currentFastBlock.Hash()); err != nil { - log.Crit("Failed to reset head fast block", "err", err) + if currentFastBlock := bc.CurrentFastBlock(); currentFastBlock == nil { + bc.currentFastBlock.Store(bc.genesisBlock) } + currentBlock := bc.CurrentBlock() + currentFastBlock := bc.CurrentFastBlock() + + rawdb.WriteHeadBlockHash(bc.db, currentBlock.Hash()) + rawdb.WriteHeadFastBlockHash(bc.db, currentFastBlock.Hash()) + return bc.loadLastState() } @@ -292,13 +342,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.chainDb, 0); err != nil { + if _, err := trie.NewSecure(block.Root(), bc.stateCache.TrieDB(), 0); err != nil { return err } // If all checks out, manually set the head block - bc.mu.Lock() - bc.currentBlock = block - bc.mu.Unlock() + bc.chainmu.Lock() + bc.currentBlock.Store(block) + bc.chainmu.Unlock() log.Info("Committed new head block", "number", block.Number(), "hash", hash) return nil @@ -306,28 +356,19 @@ func (bc *BlockChain) FastSyncCommitHead(hash common.Hash) error { // GasLimit returns the gas limit of the current HEAD block. func (bc *BlockChain) GasLimit() uint64 { - bc.mu.RLock() - defer bc.mu.RUnlock() - - return bc.currentBlock.GasLimit() + return bc.CurrentBlock().GasLimit() } // CurrentBlock retrieves the current head block of the canonical chain. The // block is retrieved from the blockchain's internal cache. func (bc *BlockChain) CurrentBlock() *types.Block { - bc.mu.RLock() - defer bc.mu.RUnlock() - - return bc.currentBlock + return bc.currentBlock.Load().(*types.Block) } // CurrentFastBlock retrieves the current fast-sync head block of the canonical // chain. The block is retrieved from the blockchain's internal cache. func (bc *BlockChain) CurrentFastBlock() *types.Block { - bc.mu.RLock() - defer bc.mu.RUnlock() - - return bc.currentFastBlock + return bc.currentFastBlock.Load().(*types.Block) } // SetProcessor sets the processor required for making state modifications. @@ -368,6 +409,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) @@ -380,52 +426,76 @@ 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 { log.Crit("Failed to write genesis block TD", "err", err) } - if err := WriteBlock(bc.chainDb, genesis); err != nil { - log.Crit("Failed to write genesis block", "err", err) - } + rawdb.WriteBlock(bc.db, genesis) + bc.genesisBlock = genesis bc.insert(bc.genesisBlock) - bc.currentBlock = bc.genesisBlock + bc.currentBlock.Store(bc.genesisBlock) bc.hc.SetGenesis(bc.genesisBlock.Header()) bc.hc.SetCurrentHeader(bc.genesisBlock.Header()) - bc.currentFastBlock = bc.genesisBlock + bc.currentFastBlock.Store(bc.genesisBlock) return nil } +// repair tries to repair the current blockchain by rolling back the current block +// until one with associated state is found. This is needed to fix incomplete db +// writes caused either by crashes/power outages, or simply non-committed tries. +// +// This method only rolls back the current block. The current header and current +// fast block are left intact. +func (bc *BlockChain) repair(head **types.Block) error { + for { + // Abort if we've rewound to a head block that does have associated state + if _, err := state.New((*head).Root(), bc.stateCache); err == nil { + log.Info("Rewound blockchain to past state", "number", (*head).Number(), "hash", (*head).Hash()) + return nil + } + // Otherwise rewind one block and recheck state availability there + 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 + } +} + // Export writes the active chain to the given writer. func (bc *BlockChain) Export(w io.Writer) error { - return bc.ExportN(w, uint64(0), bc.currentBlock.NumberU64()) + return bc.ExportN(w, uint64(0), bc.CurrentBlock().NumberU64()) } // 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) } log.Info("Exporting batch of blocks", "count", last-first+1) + start, reported := time.Now(), time.Now() for nr := first; nr <= last; nr++ { block := bc.GetBlockByNumber(nr) if block == nil { return fmt.Errorf("export failed on #%d: not found", nr) } - if err := block.EncodeRLP(w); err != nil { return err } + if time.Since(reported) >= statsReportLimit { + log.Info("Exporting blocks", "exported", block.NumberU64()-first, "elapsed", common.PrettyDuration(time.Since(start))) + reported = time.Now() + } } - return nil } @@ -437,25 +507,20 @@ func (bc *BlockChain) ExportN(w io.Writer, first uint64, last uint64) error { // Note, this function assumes that the `mu` mutex is held! func (bc *BlockChain) insert(block *types.Block) { // If the block is on a side chain or an unknown one, force other heads onto it too - updateHeads := GetCanonicalHash(bc.chainDb, block.NumberU64()) != block.Hash() + updateHeads := rawdb.ReadCanonicalHash(bc.db, block.NumberU64()) != block.Hash() // Add the block to the canonical chain number scheme and mark as the head - if err := WriteCanonicalHash(bc.chainDb, block.Hash(), block.NumberU64()); err != nil { - log.Crit("Failed to insert block number", "err", err) - } - if err := WriteHeadBlockHash(bc.chainDb, block.Hash()); err != nil { - log.Crit("Failed to insert head block hash", "err", err) - } - bc.currentBlock = block + rawdb.WriteCanonicalHash(bc.db, block.Hash(), block.NumberU64()) + rawdb.WriteHeadBlockHash(bc.db, block.Hash()) + + bc.currentBlock.Store(block) // If the block is better than our head or is on a different chain, force update heads if updateHeads { bc.hc.SetCurrentHeader(block.Header()) + rawdb.WriteHeadFastBlockHash(bc.db, block.Hash()) - if err := WriteHeadFastBlockHash(bc.chainDb, block.Hash()); err != nil { - log.Crit("Failed to insert head fast block hash", "err", err) - } - bc.currentFastBlock = block + bc.currentFastBlock.Store(block) } } @@ -472,7 +537,11 @@ func (bc *BlockChain) GetBody(hash common.Hash) *types.Body { body := cached.(*types.Body) return body } - body := GetBody(bc.chainDb, hash, bc.hc.GetBlockNumber(hash)) + number := bc.hc.GetBlockNumber(hash) + if number == nil { + return nil + } + body := rawdb.ReadBody(bc.db, hash, *number) if body == nil { return nil } @@ -488,7 +557,11 @@ func (bc *BlockChain) GetBodyRLP(hash common.Hash) rlp.RawValue { if cached, ok := bc.bodyRLPCache.Get(hash); ok { return cached.(rlp.RawValue) } - body := GetBodyRLP(bc.chainDb, hash, bc.hc.GetBlockNumber(hash)) + number := bc.hc.GetBlockNumber(hash) + if number == nil { + return nil + } + body := rawdb.ReadBodyRLP(bc.db, hash, *number) if len(body) == 0 { return nil } @@ -502,21 +575,35 @@ func (bc *BlockChain) HasBlock(hash common.Hash, number uint64) bool { if bc.blockCache.Contains(hash) { return true } - ok, _ := bc.chainDb.Has(blockBodyKey(hash, number)) - return ok + 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) + return err == nil } // HasBlockAndState checks if a block and associated state trie is fully present // in the database or not, caching it if present. -func (bc *BlockChain) HasBlockAndState(hash common.Hash) bool { +func (bc *BlockChain) HasBlockAndState(hash common.Hash, number uint64) bool { // Check first that the block itself is known - block := bc.GetBlockByHash(hash) + block := bc.GetBlock(hash, number) if block == nil { return false } - // Ensure the associated state is also present - _, err := bc.stateCache.OpenTrie(block.Root()) - return err == nil + return bc.HasState(block.Root()) } // GetBlock retrieves a block from the database by hash and number, @@ -526,7 +613,7 @@ func (bc *BlockChain) GetBlock(hash common.Hash, number uint64) *types.Block { if block, ok := bc.blockCache.Get(hash); ok { return block.(*types.Block) } - block := GetBlock(bc.chainDb, hash, number) + block := rawdb.ReadBlock(bc.db, hash, number) if block == nil { return nil } @@ -537,31 +624,55 @@ func (bc *BlockChain) GetBlock(hash common.Hash, number uint64) *types.Block { // GetBlockByHash retrieves a block from the database by hash, caching it if found. func (bc *BlockChain) GetBlockByHash(hash common.Hash) *types.Block { - return bc.GetBlock(hash, bc.hc.GetBlockNumber(hash)) + number := bc.hc.GetBlockNumber(hash) + if number == nil { + return nil + } + return bc.GetBlock(hash, *number) } // GetBlockByNumber retrieves a block from the database by number, caching it // (associated with its hash) if found. func (bc *BlockChain) GetBlockByNumber(number uint64) *types.Block { - hash := GetCanonicalHash(bc.chainDb, number) + hash := rawdb.ReadCanonicalHash(bc.db, number) if hash == (common.Hash{}) { return nil } return bc.GetBlock(hash, number) } +// GetReceiptsByHash retrieves the receipts for all transactions in a given block. +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 +} + // GetBlocksFromHash returns the block corresponding to hash and up to n-1 ancestors. // [deprecated by eth/62] func (bc *BlockChain) GetBlocksFromHash(hash common.Hash, n int) (blocks []*types.Block) { number := bc.hc.GetBlockNumber(hash) + if number == nil { + return nil + } for i := 0; i < n; i++ { - block := bc.GetBlock(hash, number) + block := bc.GetBlock(hash, *number) if block == nil { break } blocks = append(blocks, block) hash = block.ParentHash() - number-- + *number-- } return } @@ -577,6 +688,12 @@ func (bc *BlockChain) GetUnclesInChain(block *types.Block, length int) []*types. return uncles } +// TrieNode retrieves a blob of data associated with a trie node (or code hash) +// either from ephemeral in-memory cache, or from persistent storage. +func (bc *BlockChain) TrieNode(hash common.Hash) ([]byte, error) { + return bc.stateCache.TrieDB().Node(hash) +} + // Stop stops the blockchain service. If any imports are currently in progress // it will abort them using the procInterrupt. func (bc *BlockChain) Stop() { @@ -589,6 +706,32 @@ func (bc *BlockChain) Stop() { atomic.StoreInt32(&bc.procInterrupt, 1) bc.wg.Wait() + + // Ensure the state of a recent block is also stored to disk before exiting. + // We're writing three different states to catch different restart scenarios: + // - HEAD: So we don't need to reprocess any blocks in the general case + // - HEAD-1: So we don't do large reorgs if our HEAD becomes an uncle + // - HEAD-127: So we have a hard limit on the number of blocks reexecuted + if !bc.cacheConfig.Disabled { + triedb := bc.stateCache.TrieDB() + + for _, offset := range []uint64{0, 1, triesInMemory - 1} { + if number := bc.CurrentBlock().NumberU64(); number > offset { + recent := bc.GetBlockByNumber(number - offset) + + log.Info("Writing cached state to disk", "block", recent.Number(), "hash", recent.Hash(), "root", recent.Root()) + if err := triedb.Commit(recent.Root(), true); err != nil { + log.Error("Failed to commit recent state trie", "err", err) + } + } + } + for !bc.triegc.Empty() { + triedb.Dereference(bc.triegc.PopItem().(common.Hash)) + } + if size, _ := triedb.Size(); size != 0 { + log.Error("Dangling trie nodes after full cleanup") + } + } log.Info("Blockchain manager stopped") } @@ -621,8 +764,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] @@ -631,22 +774,27 @@ func (bc *BlockChain) Rollback(chain []common.Hash) { if currentHeader.Hash() == hash { bc.hc.SetCurrentHeader(bc.GetHeader(currentHeader.ParentHash, currentHeader.Number.Uint64()-1)) } - if bc.currentFastBlock.Hash() == hash { - bc.currentFastBlock = bc.GetBlock(bc.currentFastBlock.ParentHash(), bc.currentFastBlock.NumberU64()-1) - WriteHeadFastBlockHash(bc.chainDb, bc.currentFastBlock.Hash()) + if currentFastBlock := bc.CurrentFastBlock(); currentFastBlock.Hash() == hash { + newFastBlock := bc.GetBlock(currentFastBlock.ParentHash(), currentFastBlock.NumberU64()-1) + bc.currentFastBlock.Store(newFastBlock) + rawdb.WriteHeadFastBlockHash(bc.db, newFastBlock.Hash()) } - if bc.currentBlock.Hash() == hash { - bc.currentBlock = bc.GetBlock(bc.currentBlock.ParentHash(), bc.currentBlock.NumberU64()-1) - WriteHeadBlockHash(bc.chainDb, bc.currentBlock.Hash()) + if currentBlock := bc.CurrentBlock(); currentBlock.Hash() == hash { + newBlock := bc.GetBlock(currentBlock.ParentHash(), currentBlock.NumberU64()-1) + bc.currentBlock.Store(newBlock) + rawdb.WriteHeadBlockHash(bc.db, newBlock.Hash()) } } } // SetReceiptsData computes all the non-consensus fields of the receipts -func SetReceiptsData(config *params.ChainConfig, block *types.Block, receipts types.Receipts) { +func SetReceiptsData(config *params.ChainConfig, block *types.Block, receipts types.Receipts) error { signer := types.MakeSigner(config, block.Number()) transactions, logIndex := block.Transactions(), uint(0) + if len(transactions) != len(receipts) { + return errors.New("transaction and receipt count mismatch") + } for j := 0; j < len(receipts); j++ { // The transaction hash can be retrieved from the transaction itself @@ -674,6 +822,7 @@ func SetReceiptsData(config *params.ChainConfig, block *types.Block, receipts ty logIndex++ } } + return nil } // InsertReceiptChain attempts to complete an already existing header chain with @@ -696,7 +845,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ stats = struct{ processed, ignored int32 }{} start = time.Now() bytes = 0 - batch = bc.chainDb.NewBatch() + batch = bc.db.NewBatch() ) for i, block := range blockChain { receipts := receiptChain[i] @@ -714,17 +863,14 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ continue } // Compute all the non-consensus fields of the receipts - SetReceiptsData(bc.config, block, receipts) + if err := SetReceiptsData(bc.chainConfig, block, receipts); err != nil { + return i, fmt.Errorf("failed to set receipts data: %v", err) + } // Write all the data out into the database - if err := WriteBody(batch, block.Hash(), block.NumberU64(), block.Body()); err != nil { - return i, fmt.Errorf("failed to write block body: %v", err) - } - if err := WriteBlockReceipts(batch, block.Hash(), block.NumberU64(), receipts); err != nil { - return i, fmt.Errorf("failed to write block receipts: %v", err) - } - if err := WriteTxLookupEntries(batch, block); err != nil { - return i, fmt.Errorf("failed to write lookup metadata: %v", err) - } + rawdb.WriteBody(batch, block.Hash(), block.NumberU64(), block.Body()) + rawdb.WriteReceipts(batch, block.Hash(), block.NumberU64(), receipts) + rawdb.WriteTxLookupEntries(batch, block) + stats.processed++ if batch.ValueSize() >= ethdb.IdealBatchSize { @@ -743,30 +889,58 @@ 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 - if bc.GetTd(bc.currentFastBlock.Hash(), bc.currentFastBlock.NumberU64()).Cmp(td) < 0 { - if err := WriteHeadFastBlockHash(bc.chainDb, head.Hash()); err != nil { - log.Crit("Failed to update head fast block hash", "err", err) - } - bc.currentFastBlock = head + currentFastBlock := bc.CurrentFastBlock() + if bc.GetTd(currentFastBlock.Hash(), currentFastBlock.NumberU64()).Cmp(td) < 0 { + rawdb.WriteHeadFastBlockHash(bc.db, head.Hash()) + bc.currentFastBlock.Store(head) } } - bc.mu.Unlock() + bc.chainmu.Unlock() + + context := []interface{}{ + "count", stats.processed, "elapsed", common.PrettyDuration(time.Since(start)), + "number", head.Number(), "hash", head.Hash(), "age", common.PrettyAge(time.Unix(head.Time().Int64(), 0)), + "size", common.StorageSize(bytes), + } + if stats.ignored > 0 { + context = append(context, []interface{}{"ignored", stats.ignored}...) + } + log.Info("Imported new block receipts", context...) - log.Info("Imported new block receipts", - "count", stats.processed, - "elapsed", common.PrettyDuration(time.Since(start)), - "bytes", bytes, - "number", head.Number(), - "hash", head.Hash(), - "ignored", stats.ignored) return 0, nil } -// WriteBlock writes the block to the chain. -func (bc *BlockChain) WriteBlockAndState(block *types.Block, receipts []*types.Receipt, state *state.StateDB) (status WriteStatus, err error) { +var lastWrite uint64 + +// WriteBlockWithoutState writes only the block and its metadata to the database, +// but does not write any state. This is used to construct competing side forks +// up to the point where they exceed the canonical total difficulty. +func (bc *BlockChain) WriteBlockWithoutState(block *types.Block, td *big.Int) (err error) { + bc.wg.Add(1) + defer bc.wg.Done() + + if err := bc.hc.WriteTd(block.Hash(), block.NumberU64(), td); err != nil { + return err + } + rawdb.WriteBlock(bc.db, block) + + return nil +} + +// 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() @@ -776,51 +950,108 @@ func (bc *BlockChain) WriteBlockAndState(block *types.Block, receipts []*types.R return NonStatTy, consensus.ErrUnknownAncestor } // Make sure no inconsistent state is leaked during insertion - bc.mu.Lock() - defer bc.mu.Unlock() - - localTd := bc.GetTd(bc.currentBlock.Hash(), bc.currentBlock.NumberU64()) + currentBlock := bc.CurrentBlock() + localTd := bc.GetTd(currentBlock.Hash(), currentBlock.NumberU64()) externTd := new(big.Int).Add(block.Difficulty(), ptd) // Irrelevant of the canonical status, write the block itself to the database if err := bc.hc.WriteTd(block.Hash(), block.NumberU64(), externTd); err != nil { return NonStatTy, err } + rawdb.WriteBlock(bc.db, block) + + root, err := state.Commit(bc.chainConfig.IsEIP158(block.Number())) + if err != nil { + return NonStatTy, err + } + triedb := bc.stateCache.TrieDB() + + // If we're running an archive node, always flush + if bc.cacheConfig.Disabled { + if err := triedb.Commit(root, false); err != nil { + return NonStatTy, err + } + } else { + // Full but not archive node, do proper garbage collection + triedb.Reference(root, common.Hash{}) // metadata reference to keep trie alive + bc.triegc.Push(root, -int64(block.NumberU64())) + + if current := block.NumberU64(); current > triesInMemory { + // If we exceeded our memory allowance, flush matured singleton nodes to disk + var ( + nodes, imgs = triedb.Size() + 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 + chosen := current - triesInMemory + + // If we exceeded out time allowance, flush an entire trie to disk + if bc.gcproc > bc.cacheConfig.TrieTimeLimit { + // 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 + } + } + // Garbage collect anything below our required write retention + for !bc.triegc.Empty() { + root, number := bc.triegc.Pop() + if uint64(-number) > chosen { + bc.triegc.Push(root, number) + break + } + triedb.Dereference(root.(common.Hash)) + } + } + } + // Write other block data using a batch. - batch := bc.chainDb.NewBatch() - if err := WriteBlock(batch, block); err != nil { - return NonStatTy, err - } - if _, err := state.CommitTo(batch, bc.config.IsEIP158(block.Number())); err != nil { - return NonStatTy, err - } - if err := WriteBlockReceipts(batch, block.Hash(), block.NumberU64(), receipts); err != nil { - return NonStatTy, err - } + batch := bc.db.NewBatch() + rawdb.WriteReceipts(batch, block.Hash(), block.NumberU64(), receipts) // If the total difficulty is higher than our known, add it to the canonical chain // Second clause in the if statement reduces the vulnerability to selfish mining. // Please refer to http://www.cs.cornell.edu/~ie53/publications/btcProcFC.pdf reorg := externTd.Cmp(localTd) > 0 + currentBlock = bc.CurrentBlock() if !reorg && externTd.Cmp(localTd) == 0 { - // Split same-difficulty blocks by number, then at random - reorg = block.NumberU64() < bc.currentBlock.NumberU64() || (block.NumberU64() == bc.currentBlock.NumberU64() && mrand.Float64() < 0.5) + // Split same-difficulty blocks by number, then preferentially select + // the block generated by the local miner as the canonical block. + if block.NumberU64() < currentBlock.NumberU64() { + reorg = true + } else if block.NumberU64() == currentBlock.NumberU64() { + var currentPreserve, blockPreserve bool + if bc.shouldPreserve != nil { + currentPreserve, blockPreserve = bc.shouldPreserve(currentBlock), bc.shouldPreserve(block) + } + reorg = !currentPreserve && (blockPreserve || mrand.Float64() < 0.5) + } } if reorg { // Reorganise the chain if the parent is not the head block - if block.ParentHash() != bc.currentBlock.Hash() { - if err := bc.reorg(bc.currentBlock, block); err != nil { + if block.ParentHash() != currentBlock.Hash() { + if err := bc.reorg(currentBlock, block); err != nil { return NonStatTy, err } } - // Write the positional metadata for transaction and receipt lookups - if err := WriteTxLookupEntries(batch, block); err != nil { - return NonStatTy, err - } - // Write hash preimages - if err := WritePreimages(bc.chainDb, block.NumberU64(), state.Preimages()); err != nil { - return NonStatTy, err - } + // Write the positional metadata for transaction/receipt lookups and preimages + rawdb.WriteTxLookupEntries(batch, block) + rawdb.WritePreimages(batch, state.Preimages()) + status = CanonStatTy } else { status = SideStatTy @@ -837,6 +1068,18 @@ func (bc *BlockChain) WriteBlockAndState(block *types.Block, receipts []*types.R 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 @@ -844,32 +1087,57 @@ func (bc *BlockChain) WriteBlockAndState(block *types.Block, receipts []*types.R // // 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 -} + // Sanity check that we have something meaningful to import + if len(chain) == 0 { + return 0, nil + } -// 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) { + 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() { - // Chain broke ancestry, log a messge (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()) + 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", 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 @@ -886,13 +1154,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) - // Iterate over the blocks and insert when the verifier permits - for i, block := range chain { + // Peek the error for the first block to decide the directing import logic + it := newInsertIterator(chain, results, bc.Validator()) + + 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") @@ -901,148 +1214,212 @@ 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) - } - if err != nil { - if err == ErrKnownBlock { - stats.ignored++ - continue - } - - if 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 - } - - if err == consensus.ErrUnknownAncestor && bc.futureBlocks.Contains(block.ParentHash()) { - bc.futureBlocks.Add(block.Hash(), block) - stats.queued++ - continue - } - - 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 := it.previous() + if parent == nil { parent = bc.GetBlock(block.ParentHash(), block.NumberU64()-1) - } else { - parent = chain[i-1] } 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. + t0 := time.Now() receipts, logs, usedGas, err := bc.processor.Process(block, state, bc.vmConfig) + t1 := time.Now() if err != nil { bc.reportBlock(block, receipts, err) - return i, events, coalescedLogs, err + return it.index, events, coalescedLogs, err } // Validate the state using the default validator - err = bc.Validator().ValidateState(block, parent, state, receipts, usedGas) - if err != nil { + if err := bc.Validator().ValidateState(block, parent, state, receipts, usedGas); err != nil { bc.reportBlock(block, receipts, err) - return i, events, coalescedLogs, err + return it.index, events, coalescedLogs, err } + t2 := time.Now() + proctime := time.Since(start) + // Write the block to the chain and get the status. - status, err := bc.WriteBlockAndState(block, receipts, state) + status, err := bc.writeBlockWithState(block, receipts, state) + t3 := time.Now() if err != nil { - return i, events, coalescedLogs, err + return it.index, events, coalescedLogs, err } + blockInsertTimer.UpdateSince(start) + blockExecutionTimer.Update(t1.Sub(t0)) + blockValidationTimer.Update(t2.Sub(t1)) + blockWriteTimer.Update(t3.Sub(t2)) 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 - 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())) + // Only count canonical blocks for GC processing time + bc.gcproc += proctime - blockInsertTimer.UpdateSince(bstart) + case SideStatTy: + 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}) } + blockInsertTimer.UpdateSince(start) stats.processed++ stats.usedGas += usedGas - stats.report(chain, i) + + 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 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) { - // 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 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...) + // 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()) - *st = insertStats{startTime: now, lastIndex: index + 1} - } -} + // 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 externTd == nil { + externTd = bc.GetTd(block.ParentHash(), block.NumberU64()-1) + } + externTd = new(big.Int).Add(externTd, block.Difficulty()) -func countTransactions(chain []*types.Block) (c int) { - for _, b := range chain { - c += len(b.Transactions()) + 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()) + } } - return c + // 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().NumberU64(), "sidetd", externTd, "localtd", localTd) + return it.index, nil, nil, err + } + // Gather all the sidechain hashes (full blocks may be memory heavy) + var ( + hashes []common.Hash + numbers []uint64 + ) + parent := bc.GetHeader(it.previous().Hash(), it.previous().NumberU64()) + 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 @@ -1058,9 +1435,13 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error { // collectLogs collects the logs that were generated during the // processing of the block that corresponds with the given hash. // These logs are later announced as deleted. - collectLogs = func(h common.Hash) { + collectLogs = func(hash common.Hash) { // Coalesce logs and set 'Removed'. - receipts := GetBlockReceipts(bc.chainDb, h, bc.hc.GetBlockNumber(h)) + number := bc.hc.GetBlockNumber(hash) + if number == nil { + return + } + receipts := rawdb.ReadReceipts(bc.db, hash, *number) for _, receipt := range receipts { for _, log := range receipt.Logs { del := *log @@ -1129,18 +1510,19 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error { // insert the block in the canonical way, re-writing history bc.insert(newChain[i]) // write lookup entries for hash based transaction/receipt searches - if err := WriteTxLookupEntries(bc.chainDb, newChain[i]); err != nil { - return err - } + rawdb.WriteTxLookupEntries(bc.db, newChain[i]) addedTxs = append(addedTxs, newChain[i].Transactions()...) } // calculate the difference between deleted and added transactions diff := types.TxDifference(deletedTxs, addedTxs) // When transactions get deleted from the database that means the // receipts that were created in the fork must also be deleted + batch := bc.db.NewBatch() for _, tx := range diff { - DeleteTxLookupEntry(bc.chainDb, tx.Hash()) + rawdb.DeleteTxLookupEntry(batch, tx.Hash()) } + batch.Write() + if len(deletedLogs) > 0 { go bc.rmLogsFeed.Send(RemovedLogsEvent{deletedLogs}) } @@ -1190,27 +1572,21 @@ func (bc *BlockChain) update() { } } -// BadBlockArgs represents the entries in the list returned when bad blocks are queried. -type BadBlockArgs struct { - Hash common.Hash `json:"hash"` - Header *types.Header `json:"header"` -} - // BadBlocks returns a list of the last 'bad blocks' that the client has seen on the network -func (bc *BlockChain) BadBlocks() ([]BadBlockArgs, error) { - headers := make([]BadBlockArgs, 0, bc.badBlocks.Len()) +func (bc *BlockChain) BadBlocks() []*types.Block { + blocks := make([]*types.Block, 0, bc.badBlocks.Len()) for _, hash := range bc.badBlocks.Keys() { - if hdr, exist := bc.badBlocks.Peek(hash); exist { - header := hdr.(*types.Header) - headers = append(headers, BadBlockArgs{header.Hash(), header}) + if blk, exist := bc.badBlocks.Peek(hash); exist { + block := blk.(*types.Block) + blocks = append(blocks, block) } } - return headers, nil + return blocks } // addBadBlock adds a bad block to the bad-block LRU cache func (bc *BlockChain) addBadBlock(block *types.Block) { - bc.badBlocks.Add(block.Header().Hash(), block.Header()) + bc.badBlocks.Add(block.Hash(), block) } // reportBlock logs a bad block error. @@ -1218,8 +1594,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 ######### @@ -1231,7 +1609,7 @@ Hash: 0x%x Error: %v ############################## -`, bc.config, block.Number(), block.Hash(), receiptString, err)) +`, bc.chainConfig, block.Number(), block.Hash(), receiptString, err)) } // InsertHeaderChain attempts to insert the given header chain in to the local @@ -1256,42 +1634,15 @@ 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 { - bc.mu.RLock() - defer bc.mu.RUnlock() - return bc.hc.CurrentHeader() } @@ -1331,6 +1682,18 @@ func (bc *BlockChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []com return bc.hc.GetBlockHashesFromHash(hash, max) } +// GetAncestor retrieves the Nth ancestor of a given block. It assumes that either the given block or +// a close ancestor of it is canonical. maxNonCanonical points to a downwards counter limiting the +// 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 *BlockChain) GetAncestor(hash common.Hash, number, ancestor uint64, maxNonCanonical *uint64) (common.Hash, uint64) { + bc.chainmu.RLock() + defer bc.chainmu.RUnlock() + + return bc.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 (bc *BlockChain) GetHeaderByNumber(number uint64) *types.Header { @@ -1338,7 +1701,7 @@ func (bc *BlockChain) GetHeaderByNumber(number uint64) *types.Header { } // Config retrieves the blockchain's chain configuration. -func (bc *BlockChain) Config() *params.ChainConfig { return bc.config } +func (bc *BlockChain) Config() *params.ChainConfig { return bc.chainConfig } // Engine retrieves the blockchain's consensus engine. func (bc *BlockChain) Engine() consensus.Engine { return bc.engine } @@ -1367,3 +1730,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/core/blockchain_insert.go b/core/blockchain_insert.go new file mode 100644 index 0000000000..f07e24d750 --- /dev/null +++ b/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 block was being processed, or nil +func (it *insertIterator) previous() *types.Block { + if it.index < 1 { + return nil + } + return it.chain[it.index-1] +} + +// 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/core/blockchain_test.go b/core/blockchain_test.go index cbde3bcd2d..1ac7b03fc6 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -17,7 +17,6 @@ package core import ( - "fmt" "math/big" "math/rand" "sync" @@ -25,7 +24,9 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/ethash" + "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" @@ -34,24 +35,37 @@ import ( "github.com/ethereum/go-ethereum/params" ) -// newTestBlockChain creates a blockchain without validation. -func newTestBlockChain(fake bool) *BlockChain { - db, _ := ethdb.NewMemDatabase() - gspec := &Genesis{ - Config: params.TestChainConfig, - Difficulty: big.NewInt(1), +// So we can deterministically seed different blockchains +var ( + canonicalSeed = 1 + forkSeed = 2 +) + +// newCanonical creates a chain database, and injects a deterministic canonical +// chain. Depending on the full flag, if creates either a full block chain or a +// header only chain. +func newCanonical(engine consensus.Engine, n int, full bool) (ethdb.Database, *BlockChain, error) { + var ( + db = ethdb.NewMemDatabase() + genesis = new(Genesis).MustCommit(db) + ) + + // Initialize a fresh chain with only a genesis block + blockchain, _ := NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil) + // Create and inject the requested chain + if n == 0 { + return db, blockchain, nil } - gspec.MustCommit(db) - engine := ethash.NewFullFaker() - if !fake { - engine = ethash.NewTester() + if full { + // Full block-chain requested + blocks := makeBlockChain(genesis, n, engine, db, canonicalSeed) + _, err := blockchain.InsertChain(blocks) + return db, blockchain, err } - blockchain, err := NewBlockChain(db, gspec.Config, engine, vm.Config{}) - if err != nil { - panic(err) - } - blockchain.SetValidator(bproc{}) - return blockchain + // Header-only chain requested + headers := makeHeaderChain(genesis.Header(), n, engine, db, canonicalSeed) + _, err := blockchain.InsertHeaderChain(headers, 1) + return db, blockchain, err } // Test fork of length N starting from block i @@ -111,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 { @@ -147,11 +154,11 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error { blockchain.reportBlock(block, receipts, err) return err } - blockchain.mu.Lock() - WriteTd(blockchain.chainDb, block.Hash(), block.NumberU64(), new(big.Int).Add(block.Difficulty(), blockchain.GetTdByHash(block.ParentHash()))) - WriteBlock(blockchain.chainDb, block) - statedb.CommitTo(blockchain.chainDb, false) - blockchain.mu.Unlock() + 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.chainmu.Unlock() } return nil } @@ -165,31 +172,27 @@ 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() - WriteTd(blockchain.chainDb, header.Hash(), header.Number.Uint64(), new(big.Int).Add(header.Difficulty, blockchain.GetTdByHash(header.ParentHash))) - WriteHeader(blockchain.chainDb, header) - blockchain.mu.Unlock() + 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.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) { - bchain := newTestBlockChain(false) - defer bchain.Stop() + _, blockchain, err := newCanonical(ethash.NewFaker(), 0, true) + if err != nil { + t.Fatalf("failed to create pristine chain: %v", err) + } + defer blockchain.Stop() - block := makeBlockChain(bchain.CurrentBlock(), 1, ethash.NewFaker(), bchain.chainDb, 0)[0] - bchain.insert(block) - if block.Hash() != GetHeadBlockHash(bchain.chainDb) { - t.Errorf("Write/Get HeadBlockHash failed") + blocks := makeBlockChain(blockchain.CurrentBlock(), 1, ethash.NewFullFaker(), blockchain.db, 0) + if _, err := blockchain.InsertChain(blocks); err != nil { + t.Fatalf("Failed to insert block: %v", err) + } + if blocks[len(blocks)-1].Hash() != rawdb.ReadHeadBlockHash(blockchain.db) { + t.Fatalf("Write/Get HeadBlockHash failed") } } @@ -337,55 +340,13 @@ func testBrokenChain(t *testing.T, full bool) { } } -type bproc struct{} - -func (bproc) ValidateBody(*types.Block) error { return nil } -func (bproc) ValidateState(block, parent *types.Block, state *state.StateDB, receipts types.Receipts, usedGas uint64) error { - return nil -} -func (bproc) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, error) { - return nil, nil, 0, nil -} - -func makeHeaderChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.Header { - blocks := makeBlockChainWithDiff(genesis, d, seed) - headers := make([]*types.Header, len(blocks)) - for i, block := range blocks { - headers[i] = block.Header() - } - return headers -} - -func makeBlockChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.Block { - var chain []*types.Block - for i, difficulty := range d { - header := &types.Header{ - Coinbase: common.Address{seed}, - Number: big.NewInt(int64(i + 1)), - Difficulty: big.NewInt(int64(difficulty)), - UncleHash: types.EmptyUncleHash, - TxHash: types.EmptyRootHash, - ReceiptHash: types.EmptyRootHash, - Time: big.NewInt(int64(i) + 1), - } - if i == 0 { - header.ParentHash = genesis.Hash() - } else { - header.ParentHash = chain[i-1].Hash() - } - block := types.NewBlockWithHeader(header) - chain = append(chain, block) - } - return chain -} - // Tests that reorganising a long difficult chain after a short easy one // overwrites the canonical numbers and links in the database. func TestReorgLongHeaders(t *testing.T) { testReorgLong(t, false) } func TestReorgLongBlocks(t *testing.T) { testReorgLong(t, true) } func testReorgLong(t *testing.T, full bool) { - testReorg(t, []int{1, 2, 4}, []int{1, 2, 3, 4}, 10, full) + testReorg(t, []int64{0, 0, -9}, []int64{0, 0, 0, -9}, 393280, full) } // Tests that reorganising a short difficult chain after a long easy one @@ -394,45 +355,82 @@ func TestReorgShortHeaders(t *testing.T) { testReorgShort(t, false) } func TestReorgShortBlocks(t *testing.T) { testReorgShort(t, true) } func testReorgShort(t *testing.T, full bool) { - testReorg(t, []int{1, 2, 3, 4}, []int{1, 10}, 11, full) + // Create a long easy chain vs. a short heavy one. Due to difficulty adjustment + // we need a fairly long chain of blocks with different difficulties for a short + // one to become heavyer than a long one. The 96 is an empirical value. + easy := make([]int64, 96) + for i := 0; i < len(easy); i++ { + easy[i] = 60 + } + diff := make([]int64, len(easy)-1) + for i := 0; i < len(diff); i++ { + diff[i] = -9 + } + testReorg(t, easy, diff, 12615120, full) } -func testReorg(t *testing.T, first, second []int, td int64, full bool) { - bc := newTestBlockChain(true) - defer bc.Stop() +func testReorg(t *testing.T, first, second []int64, td int64, full bool) { + // Create a pristine chain and database + db, blockchain, err := newCanonical(ethash.NewFaker(), 0, full) + if err != nil { + t.Fatalf("failed to create pristine chain: %v", err) + } + defer blockchain.Stop() // Insert an easy and a difficult chain afterwards + easyBlocks, _ := GenerateChain(params.TestChainConfig, blockchain.CurrentBlock(), ethash.NewFaker(), db, len(first), func(i int, b *BlockGen) { + b.OffsetTime(first[i]) + }) + diffBlocks, _ := GenerateChain(params.TestChainConfig, blockchain.CurrentBlock(), ethash.NewFaker(), db, len(second), func(i int, b *BlockGen) { + b.OffsetTime(second[i]) + }) if full { - bc.InsertChain(makeBlockChainWithDiff(bc.genesisBlock, first, 11)) - bc.InsertChain(makeBlockChainWithDiff(bc.genesisBlock, second, 22)) + if _, err := blockchain.InsertChain(easyBlocks); err != nil { + t.Fatalf("failed to insert easy chain: %v", err) + } + if _, err := blockchain.InsertChain(diffBlocks); err != nil { + t.Fatalf("failed to insert difficult chain: %v", err) + } } else { - bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, first, 11), 1) - bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, second, 22), 1) + easyHeaders := make([]*types.Header, len(easyBlocks)) + for i, block := range easyBlocks { + easyHeaders[i] = block.Header() + } + diffHeaders := make([]*types.Header, len(diffBlocks)) + for i, block := range diffBlocks { + diffHeaders[i] = block.Header() + } + if _, err := blockchain.InsertHeaderChain(easyHeaders, 1); err != nil { + t.Fatalf("failed to insert easy chain: %v", err) + } + if _, err := blockchain.InsertHeaderChain(diffHeaders, 1); err != nil { + t.Fatalf("failed to insert difficult chain: %v", err) + } } // Check that the chain is valid number and link wise if full { - prev := bc.CurrentBlock() - for block := bc.GetBlockByNumber(bc.CurrentBlock().NumberU64() - 1); block.NumberU64() != 0; prev, block = block, bc.GetBlockByNumber(block.NumberU64()-1) { + prev := blockchain.CurrentBlock() + for block := blockchain.GetBlockByNumber(blockchain.CurrentBlock().NumberU64() - 1); block.NumberU64() != 0; prev, block = block, blockchain.GetBlockByNumber(block.NumberU64()-1) { if prev.ParentHash() != block.Hash() { t.Errorf("parent block hash mismatch: have %x, want %x", prev.ParentHash(), block.Hash()) } } } else { - prev := bc.CurrentHeader() - for header := bc.GetHeaderByNumber(bc.CurrentHeader().Number.Uint64() - 1); header.Number.Uint64() != 0; prev, header = header, bc.GetHeaderByNumber(header.Number.Uint64()-1) { + prev := blockchain.CurrentHeader() + for header := blockchain.GetHeaderByNumber(blockchain.CurrentHeader().Number.Uint64() - 1); header.Number.Uint64() != 0; prev, header = header, blockchain.GetHeaderByNumber(header.Number.Uint64()-1) { if prev.ParentHash != header.Hash() { t.Errorf("parent header hash mismatch: have %x, want %x", prev.ParentHash, header.Hash()) } } } // Make sure the chain total difficulty is the correct one - want := new(big.Int).Add(bc.genesisBlock.Difficulty(), big.NewInt(td)) + want := new(big.Int).Add(blockchain.genesisBlock.Difficulty(), big.NewInt(td)) if full { - if have := bc.GetTdByHash(bc.CurrentBlock().Hash()); have.Cmp(want) != 0 { + if have := blockchain.GetTdByHash(blockchain.CurrentBlock().Hash()); have.Cmp(want) != 0 { t.Errorf("total difficulty mismatch: have %v, want %v", have, want) } } else { - if have := bc.GetTdByHash(bc.CurrentHeader().Hash()); have.Cmp(want) != 0 { + if have := blockchain.GetTdByHash(blockchain.CurrentHeader().Hash()); have.Cmp(want) != 0 { t.Errorf("total difficulty mismatch: have %v, want %v", have, want) } } @@ -443,19 +441,28 @@ func TestBadHeaderHashes(t *testing.T) { testBadHashes(t, false) } func TestBadBlockHashes(t *testing.T) { testBadHashes(t, true) } func testBadHashes(t *testing.T, full bool) { - bc := newTestBlockChain(true) - defer bc.Stop() + // Create a pristine chain and database + db, blockchain, err := newCanonical(ethash.NewFaker(), 0, full) + if err != nil { + t.Fatalf("failed to create pristine chain: %v", err) + } + defer blockchain.Stop() // Create a chain, ban a hash and try to import - var err error if full { - blocks := makeBlockChainWithDiff(bc.genesisBlock, []int{1, 2, 4}, 10) + blocks := makeBlockChain(blockchain.CurrentBlock(), 3, ethash.NewFaker(), db, 10) + BadHashes[blocks[2].Header().Hash()] = true - _, err = bc.InsertChain(blocks) + defer func() { delete(BadHashes, blocks[2].Header().Hash()) }() + + _, err = blockchain.InsertChain(blocks) } else { - headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 4}, 10) + headers := makeHeaderChain(blockchain.CurrentHeader(), 3, ethash.NewFaker(), db, 10) + BadHashes[headers[2].Hash()] = true - _, err = bc.InsertHeaderChain(headers, 1) + defer func() { delete(BadHashes, headers[2].Hash()) }() + + _, err = blockchain.InsertHeaderChain(headers, 1) } if err != ErrBlacklistedHash { t.Errorf("error mismatch: have: %v, want: %v", err, ErrBlacklistedHash) @@ -468,40 +475,41 @@ func TestReorgBadHeaderHashes(t *testing.T) { testReorgBadHashes(t, false) } func TestReorgBadBlockHashes(t *testing.T) { testReorgBadHashes(t, true) } func testReorgBadHashes(t *testing.T, full bool) { - bc := newTestBlockChain(true) - defer bc.Stop() - + // Create a pristine chain and database + db, blockchain, err := newCanonical(ethash.NewFaker(), 0, full) + if err != nil { + t.Fatalf("failed to create pristine chain: %v", err) + } // Create a chain, import and ban afterwards - headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 3, 4}, 10) - blocks := makeBlockChainWithDiff(bc.genesisBlock, []int{1, 2, 3, 4}, 10) + headers := makeHeaderChain(blockchain.CurrentHeader(), 4, ethash.NewFaker(), db, 10) + blocks := makeBlockChain(blockchain.CurrentBlock(), 4, ethash.NewFaker(), db, 10) if full { - if _, err := bc.InsertChain(blocks); err != nil { - t.Fatalf("failed to import blocks: %v", err) + if _, err = blockchain.InsertChain(blocks); err != nil { + t.Errorf("failed to import blocks: %v", err) } - if bc.CurrentBlock().Hash() != blocks[3].Hash() { - t.Errorf("last block hash mismatch: have: %x, want %x", bc.CurrentBlock().Hash(), blocks[3].Header().Hash()) + if blockchain.CurrentBlock().Hash() != blocks[3].Hash() { + t.Errorf("last block hash mismatch: have: %x, want %x", blockchain.CurrentBlock().Hash(), blocks[3].Header().Hash()) } BadHashes[blocks[3].Header().Hash()] = true defer func() { delete(BadHashes, blocks[3].Header().Hash()) }() } else { - if _, err := bc.InsertHeaderChain(headers, 1); err != nil { - t.Fatalf("failed to import headers: %v", err) + if _, err = blockchain.InsertHeaderChain(headers, 1); err != nil { + t.Errorf("failed to import headers: %v", err) } - if bc.CurrentHeader().Hash() != headers[3].Hash() { - t.Errorf("last header hash mismatch: have: %x, want %x", bc.CurrentHeader().Hash(), headers[3].Hash()) + if blockchain.CurrentHeader().Hash() != headers[3].Hash() { + t.Errorf("last header hash mismatch: have: %x, want %x", blockchain.CurrentHeader().Hash(), headers[3].Hash()) } BadHashes[headers[3].Hash()] = true defer func() { delete(BadHashes, headers[3].Hash()) }() } + blockchain.Stop() // Create a new BlockChain and check that it rolled back the state. - ncm, err := NewBlockChain(bc.chainDb, bc.config, ethash.NewFaker(), vm.Config{}) + ncm, err := NewBlockChain(blockchain.db, nil, blockchain.chainConfig, ethash.NewFaker(), vm.Config{}, nil) if err != nil { t.Fatalf("failed to create new chain manager: %v", err) } - defer ncm.Stop() - if full { if ncm.CurrentBlock().Hash() != blocks[2].Header().Hash() { t.Errorf("last block hash mismatch: have: %x, want %x", ncm.CurrentBlock().Hash(), blocks[2].Header().Hash()) @@ -514,6 +522,7 @@ func testReorgBadHashes(t *testing.T, full bool) { t.Errorf("last header hash mismatch: have: %x, want %x", ncm.CurrentHeader().Hash(), headers[2].Hash()) } } + ncm.Stop() } // Tests chain insertions in the face of one entity containing an invalid nonce. @@ -553,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 { @@ -577,16 +586,16 @@ func testInsertNonceError(t *testing.T, full bool) { func TestFastVsFullChains(t *testing.T) { // Configure and generate a sample block chain var ( - gendb, _ = ethdb.NewMemDatabase() - key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - address = crypto.PubkeyToAddress(key.PublicKey) - funds = big.NewInt(1000000000) - gspec = &Genesis{ + gendb = ethdb.NewMemDatabase() + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + address = crypto.PubkeyToAddress(key.PublicKey) + funds = big.NewInt(1000000000) + gspec = &Genesis{ Config: params.TestChainConfig, Alloc: GenesisAlloc{address: {Balance: funds}}, } genesis = gspec.MustCommit(gendb) - signer = types.NewEIP155Signer(gspec.Config.ChainId) + signer = types.NewEIP155Signer(gspec.Config.ChainID) ) blocks, receipts := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), gendb, 1024, func(i int, block *BlockGen) { block.SetCoinbase(common.Address{0x00}) @@ -607,18 +616,18 @@ func TestFastVsFullChains(t *testing.T) { } }) // Import the chain as an archive node for the comparison baseline - archiveDb, _ := ethdb.NewMemDatabase() + archiveDb := ethdb.NewMemDatabase() gspec.MustCommit(archiveDb) - archive, _ := NewBlockChain(archiveDb, gspec.Config, ethash.NewFaker(), vm.Config{}) + archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) defer archive.Stop() if n, err := archive.InsertChain(blocks); err != nil { 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 := ethdb.NewMemDatabase() gspec.MustCommit(fastDb) - fast, _ := NewBlockChain(fastDb, gspec.Config, ethash.NewFaker(), vm.Config{}) + fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) defer fast.Stop() headers := make([]*types.Header, len(blocks)) @@ -648,13 +657,13 @@ func TestFastVsFullChains(t *testing.T) { } else if types.CalcUncleHash(fblock.Uncles()) != types.CalcUncleHash(ablock.Uncles()) { t.Errorf("block #%d [%x]: uncles mismatch: have %v, want %v", num, hash, fblock.Uncles(), ablock.Uncles()) } - if freceipts, areceipts := GetBlockReceipts(fastDb, hash, GetBlockNumber(fastDb, hash)), GetBlockReceipts(archiveDb, hash, GetBlockNumber(archiveDb, hash)); types.DeriveSha(freceipts) != types.DeriveSha(areceipts) { + if freceipts, areceipts := rawdb.ReadReceipts(fastDb, hash, *rawdb.ReadHeaderNumber(fastDb, hash)), rawdb.ReadReceipts(archiveDb, hash, *rawdb.ReadHeaderNumber(archiveDb, hash)); types.DeriveSha(freceipts) != types.DeriveSha(areceipts) { t.Errorf("block #%d [%x]: receipts mismatch: have %v, want %v", num, hash, freceipts, areceipts) } } // Check that the canonical chains are the same between the databases for i := 0; i < len(blocks)+1; i++ { - if fhash, ahash := GetCanonicalHash(fastDb, uint64(i)), GetCanonicalHash(archiveDb, uint64(i)); fhash != ahash { + if fhash, ahash := rawdb.ReadCanonicalHash(fastDb, uint64(i)), rawdb.ReadCanonicalHash(archiveDb, uint64(i)); fhash != ahash { t.Errorf("block #%d: canonical hash mismatch: have %v, want %v", i, fhash, ahash) } } @@ -665,12 +674,12 @@ func TestFastVsFullChains(t *testing.T) { func TestLightVsFastVsFullChainHeads(t *testing.T) { // Configure and generate a sample block chain var ( - gendb, _ = ethdb.NewMemDatabase() - key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - address = crypto.PubkeyToAddress(key.PublicKey) - funds = big.NewInt(1000000000) - gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{address: {Balance: funds}}} - genesis = gspec.MustCommit(gendb) + gendb = ethdb.NewMemDatabase() + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + address = crypto.PubkeyToAddress(key.PublicKey) + funds = big.NewInt(1000000000) + gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{address: {Balance: funds}}} + genesis = gspec.MustCommit(gendb) ) height := uint64(1024) blocks, receipts := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), gendb, int(height), nil) @@ -693,10 +702,10 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { } } // Import the chain as an archive node and ensure all pointers are updated - archiveDb, _ := ethdb.NewMemDatabase() + archiveDb := ethdb.NewMemDatabase() gspec.MustCommit(archiveDb) - archive, _ := NewBlockChain(archiveDb, gspec.Config, ethash.NewFaker(), vm.Config{}) + archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) if n, err := archive.InsertChain(blocks); err != nil { t.Fatalf("failed to process block %d: %v", n, err) } @@ -707,9 +716,9 @@ 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 := ethdb.NewMemDatabase() gspec.MustCommit(fastDb) - fast, _ := NewBlockChain(fastDb, gspec.Config, ethash.NewFaker(), vm.Config{}) + fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) defer fast.Stop() headers := make([]*types.Header, len(blocks)) @@ -727,10 +736,10 @@ 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 := ethdb.NewMemDatabase() gspec.MustCommit(lightDb) - light, _ := NewBlockChain(lightDb, gspec.Config, ethash.NewFaker(), vm.Config{}) + light, _ := NewBlockChain(lightDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) if n, err := light.InsertHeaderChain(headers, 1); err != nil { t.Fatalf("failed to insert header %d: %v", n, err) } @@ -750,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 = ethdb.NewMemDatabase() gspec = &Genesis{ Config: params.TestChainConfig, GasLimit: 3141592, @@ -761,7 +770,7 @@ func TestChainTxReorgs(t *testing.T) { }, } genesis = gspec.MustCommit(db) - signer = types.NewEIP155Signer(gspec.Config.ChainId) + signer = types.NewEIP155Signer(gspec.Config.ChainID) ) // Create two transactions shared between the chains: @@ -799,7 +808,7 @@ func TestChainTxReorgs(t *testing.T) { } }) // Import the chain. This runs all block validation rules. - blockchain, _ := NewBlockChain(db, gspec.Config, ethash.NewFaker(), vm.Config{}) + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) if i, err := blockchain.InsertChain(chain); err != nil { t.Fatalf("failed to insert original chain[%d]: %v", i, err) } @@ -830,28 +839,28 @@ func TestChainTxReorgs(t *testing.T) { // removed tx for i, tx := range (types.Transactions{pastDrop, freshDrop}) { - if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn != nil { + if txn, _, _, _ := rawdb.ReadTransaction(db, tx.Hash()); txn != nil { t.Errorf("drop %d: tx %v found while shouldn't have been", i, txn) } - if rcpt, _, _, _ := GetReceipt(db, tx.Hash()); rcpt != nil { + if rcpt, _, _, _ := rawdb.ReadReceipt(db, tx.Hash()); rcpt != nil { t.Errorf("drop %d: receipt %v found while shouldn't have been", i, rcpt) } } // added tx for i, tx := range (types.Transactions{pastAdd, freshAdd, futureAdd}) { - if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn == nil { + if txn, _, _, _ := rawdb.ReadTransaction(db, tx.Hash()); txn == nil { t.Errorf("add %d: expected tx to be found", i) } - if rcpt, _, _, _ := GetReceipt(db, tx.Hash()); rcpt == nil { + if rcpt, _, _, _ := rawdb.ReadReceipt(db, tx.Hash()); rcpt == nil { t.Errorf("add %d: expected receipt to be found", i) } } // shared tx for i, tx := range (types.Transactions{postponed, swapped}) { - if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn == nil { + if txn, _, _, _ := rawdb.ReadTransaction(db, tx.Hash()); txn == nil { t.Errorf("share %d: expected tx to be found", i) } - if rcpt, _, _, _ := GetReceipt(db, tx.Hash()); rcpt == nil { + if rcpt, _, _, _ := rawdb.ReadReceipt(db, tx.Hash()); rcpt == nil { t.Errorf("share %d: expected receipt to be found", i) } } @@ -862,15 +871,15 @@ func TestLogReorgs(t *testing.T) { var ( key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr1 = crypto.PubkeyToAddress(key1.PublicKey) - db, _ = ethdb.NewMemDatabase() + db = ethdb.NewMemDatabase() // this code generates a log code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00") gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}}} genesis = gspec.MustCommit(db) - signer = types.NewEIP155Signer(gspec.Config.ChainId) + signer = types.NewEIP155Signer(gspec.Config.ChainID) ) - blockchain, _ := NewBlockChain(db, gspec.Config, ethash.NewFaker(), vm.Config{}) + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) defer blockchain.Stop() rmLogsCh := make(chan RemovedLogsEvent) @@ -906,7 +915,7 @@ func TestLogReorgs(t *testing.T) { func TestReorgSideEvent(t *testing.T) { var ( - db, _ = ethdb.NewMemDatabase() + db = ethdb.NewMemDatabase() key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr1 = crypto.PubkeyToAddress(key1.PublicKey) gspec = &Genesis{ @@ -914,10 +923,10 @@ func TestReorgSideEvent(t *testing.T) { Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}}, } genesis = gspec.MustCommit(db) - signer = types.NewEIP155Signer(gspec.Config.ChainId) + signer = types.NewEIP155Signer(gspec.Config.ChainID) ) - blockchain, _ := NewBlockChain(db, gspec.Config, ethash.NewFaker(), vm.Config{}) + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) defer blockchain.Stop() chain, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, gen *BlockGen) {}) @@ -989,10 +998,13 @@ done: // Tests if the canonical block can be fetched from the database during chain insertion. func TestCanonicalBlockRetrieval(t *testing.T) { - bc := newTestBlockChain(true) - defer bc.Stop() + _, blockchain, err := newCanonical(ethash.NewFaker(), 0, true) + if err != nil { + t.Fatalf("failed to create pristine chain: %v", err) + } + defer blockchain.Stop() - chain, _ := GenerateChain(bc.config, bc.genesisBlock, ethash.NewFaker(), bc.chainDb, 10, func(i int, gen *BlockGen) {}) + chain, _ := GenerateChain(blockchain.chainConfig, blockchain.genesisBlock, ethash.NewFaker(), blockchain.db, 10, func(i int, gen *BlockGen) {}) var pend sync.WaitGroup pend.Add(len(chain)) @@ -1003,14 +1015,14 @@ func TestCanonicalBlockRetrieval(t *testing.T) { // try to retrieve a block by its canonical hash and see if the block data can be retrieved. for { - ch := GetCanonicalHash(bc.chainDb, block.NumberU64()) + ch := rawdb.ReadCanonicalHash(blockchain.db, block.NumberU64()) if ch == (common.Hash{}) { continue // busy wait for canonical hash to be written } if ch != block.Hash() { t.Fatalf("unknown canonical hash, want %s, got %s", block.Hash().Hex(), ch.Hex()) } - fb := GetBlock(bc.chainDb, ch, block.NumberU64()) + fb := rawdb.ReadBlock(blockchain.db, ch, block.NumberU64()) if fb == nil { t.Fatalf("unable to retrieve block %d for canonical hash: %s", block.NumberU64(), ch.Hex()) } @@ -1021,7 +1033,7 @@ func TestCanonicalBlockRetrieval(t *testing.T) { } }(chain[i]) - if _, err := bc.InsertChain(types.Blocks{chain[i]}); err != nil { + if _, err := blockchain.InsertChain(types.Blocks{chain[i]}); err != nil { t.Fatalf("failed to insert block %d: %v", i, err) } } @@ -1031,19 +1043,19 @@ func TestCanonicalBlockRetrieval(t *testing.T) { func TestEIP155Transition(t *testing.T) { // Configure and generate a sample block chain var ( - db, _ = ethdb.NewMemDatabase() + db = ethdb.NewMemDatabase() key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") address = crypto.PubkeyToAddress(key.PublicKey) funds = big.NewInt(1000000000) deleteAddr = common.Address{1} gspec = &Genesis{ - Config: ¶ms.ChainConfig{ChainId: big.NewInt(1), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}, + Config: ¶ms.ChainConfig{ChainID: big.NewInt(1), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}, Alloc: GenesisAlloc{address: {Balance: funds}, deleteAddr: {Balance: new(big.Int)}}, } genesis = gspec.MustCommit(db) ) - blockchain, _ := NewBlockChain(db, gspec.Config, ethash.NewFaker(), vm.Config{}) + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) defer blockchain.Stop() blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 4, func(i int, block *BlockGen) { @@ -1068,7 +1080,7 @@ func TestEIP155Transition(t *testing.T) { } block.AddTx(tx) - tx, err = basicTx(types.NewEIP155Signer(gspec.Config.ChainId)) + tx, err = basicTx(types.NewEIP155Signer(gspec.Config.ChainID)) if err != nil { t.Fatal(err) } @@ -1080,7 +1092,7 @@ func TestEIP155Transition(t *testing.T) { } block.AddTx(tx) - tx, err = basicTx(types.NewEIP155Signer(gspec.Config.ChainId)) + tx, err = basicTx(types.NewEIP155Signer(gspec.Config.ChainID)) if err != nil { t.Fatal(err) } @@ -1108,7 +1120,7 @@ func TestEIP155Transition(t *testing.T) { } // generate an invalid chain id transaction - config := ¶ms.ChainConfig{ChainId: big.NewInt(2), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)} + config := ¶ms.ChainConfig{ChainID: big.NewInt(2), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)} blocks, _ = GenerateChain(config, blocks[len(blocks)-1], ethash.NewFaker(), db, 4, func(i int, block *BlockGen) { var ( tx *types.Transaction @@ -1117,8 +1129,7 @@ func TestEIP155Transition(t *testing.T) { return types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), 21000, new(big.Int), nil), signer, key) } ) - switch i { - case 0: + if i == 0 { tx, err = basicTx(types.NewEIP155Signer(big.NewInt(2))) if err != nil { t.Fatal(err) @@ -1135,14 +1146,14 @@ func TestEIP155Transition(t *testing.T) { func TestEIP161AccountRemoval(t *testing.T) { // Configure and generate a sample block chain var ( - db, _ = ethdb.NewMemDatabase() + db = ethdb.NewMemDatabase() key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") address = crypto.PubkeyToAddress(key.PublicKey) funds = big.NewInt(1000000000) theAddr = common.Address{1} gspec = &Genesis{ Config: ¶ms.ChainConfig{ - ChainId: big.NewInt(1), + ChainID: big.NewInt(1), HomesteadBlock: new(big.Int), EIP155Block: new(big.Int), EIP158Block: big.NewInt(2), @@ -1151,14 +1162,14 @@ func TestEIP161AccountRemoval(t *testing.T) { } genesis = gspec.MustCommit(db) ) - blockchain, _ := NewBlockChain(db, gspec.Config, ethash.NewFaker(), vm.Config{}) + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) defer blockchain.Stop() blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, block *BlockGen) { var ( tx *types.Transaction err error - signer = types.NewEIP155Signer(gspec.Config.ChainId) + signer = types.NewEIP155Signer(gspec.Config.ChainID) ) switch i { case 0: @@ -1207,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 := ethdb.NewMemDatabase() genesis := new(Genesis).MustCommit(db) blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 64, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) @@ -1223,10 +1234,10 @@ 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 := ethdb.NewMemDatabase() new(Genesis).MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, params.TestChainConfig, engine, vm.Config{}) + chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1245,3 +1256,350 @@ func TestBlockchainHeaderchainReorgConsistency(t *testing.T) { } } } + +// Tests that importing small side forks doesn't leave junk in the trie database +// cache (which would eventually cause memory issues). +func TestTrieForkGC(t *testing.T) { + // Generate a canonical chain to act as the main dataset + engine := ethash.NewFaker() + + db := ethdb.NewMemDatabase() + genesis := new(Genesis).MustCommit(db) + blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*triesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) + + // Generate a bunch of fork blocks, each side forking from the canonical chain + forks := make([]*types.Block, len(blocks)) + for i := 0; i < len(forks); i++ { + parent := genesis + if i > 0 { + parent = blocks[i-1] + } + fork, _ := GenerateChain(params.TestChainConfig, parent, engine, db, 1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }) + forks[i] = fork[0] + } + // Import the canonical and fork chain side by side, forcing the trie cache to cache both + diskdb := ethdb.NewMemDatabase() + 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) + } + for i := 0; i < len(blocks); i++ { + if _, err := chain.InsertChain(blocks[i : i+1]); err != nil { + t.Fatalf("block %d: failed to insert into chain: %v", i, err) + } + if _, err := chain.InsertChain(forks[i : i+1]); err != nil { + t.Fatalf("fork %d: failed to insert into chain: %v", i, err) + } + } + // Dereference all the recent tries and ensure no past trie is left in + for i := 0; i < triesInMemory; i++ { + chain.stateCache.TrieDB().Dereference(blocks[len(blocks)-1-i].Root()) + chain.stateCache.TrieDB().Dereference(forks[len(blocks)-1-i].Root()) + } + if len(chain.stateCache.TrieDB().Nodes()) > 0 { + t.Fatalf("stale tries still alive after garbase collection") + } +} + +// Tests that doing large reorgs works even if the state associated with the +// forking point is not available any more. +func TestLargeReorgTrieGC(t *testing.T) { + // Generate the original common chain segment and the two competing forks + engine := ethash.NewFaker() + + db := ethdb.NewMemDatabase() + genesis := new(Genesis).MustCommit(db) + + shared, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 64, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) + original, _ := GenerateChain(params.TestChainConfig, shared[len(shared)-1], engine, db, 2*triesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }) + 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() + 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 _, err := chain.InsertChain(shared); err != nil { + t.Fatalf("failed to insert shared chain: %v", err) + } + if _, err := chain.InsertChain(original); err != nil { + 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 { + t.Fatalf("common-but-old ancestor still cache") + } + // Import the competitor chain without exceeding the canonical's TD and ensure + // we have not processed any of the blocks (protection against malicious blocks) + if _, err := chain.InsertChain(competitor[:len(competitor)-2]); err != nil { + t.Fatalf("failed to insert competitor chain: %v", err) + } + for i, block := range competitor[:len(competitor)-2] { + if node, _ := chain.stateCache.TrieDB().Node(block.Root()); node != nil { + t.Fatalf("competitor %d: low TD chain became processed", i) + } + } + // Import the head of the competitor chain, triggering the reorg and ensure we + // successfully reprocess all the stashed away blocks. + if _, err := chain.InsertChain(competitor[len(competitor)-2:]); err != nil { + t.Fatalf("failed to finalize competitor chain: %v", err) + } + for i, block := range competitor[:len(competitor)-triesInMemory] { + if node, _ := chain.stateCache.TrieDB().Node(block.Root()); node != nil { + t.Fatalf("competitor %d: competing chain state missing", i) + } + } +} + +// Benchmarks large blocks with value transfers to non-existing accounts +func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks int, recipientFn func(uint64) common.Address, dataFn func(uint64) []byte) { + var ( + signer = types.HomesteadSigner{} + testBankKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + testBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey) + bankFunds = big.NewInt(100000000000000000) + gspec = Genesis{ + Config: params.TestChainConfig, + Alloc: GenesisAlloc{ + testBankAddress: {Balance: bankFunds}, + common.HexToAddress("0xc0de"): { + Code: []byte{0x60, 0x01, 0x50}, + Balance: big.NewInt(0), + }, // push 1, pop + }, + GasLimit: 100e6, // 100 M + } + ) + // Generate the original common chain segment and the two competing forks + engine := ethash.NewFaker() + db := ethdb.NewMemDatabase() + genesis := gspec.MustCommit(db) + + blockGenerator := func(i int, block *BlockGen) { + block.SetCoinbase(common.Address{1}) + for txi := 0; txi < numTxs; txi++ { + uniq := uint64(i*numTxs + txi) + recipient := recipientFn(uniq) + //recipient := common.BigToAddress(big.NewInt(0).SetUint64(1337 + uniq)) + tx, err := types.SignTx(types.NewTransaction(uniq, recipient, big.NewInt(1), params.TxGas, big.NewInt(1), nil), signer, testBankKey) + if err != nil { + b.Error(err) + } + block.AddTx(tx) + } + } + + shared, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, numBlocks, blockGenerator) + b.StopTimer() + b.ResetTimer() + for i := 0; i < b.N; i++ { + // Import the shared chain and the original canonical one + diskdb := ethdb.NewMemDatabase() + gspec.MustCommit(diskdb) + + chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil) + if err != nil { + b.Fatalf("failed to create tester chain: %v", err) + } + b.StartTimer() + if _, err := chain.InsertChain(shared); err != nil { + b.Fatalf("failed to insert shared chain: %v", err) + } + b.StopTimer() + if got := chain.CurrentBlock().Transactions().Len(); got != numTxs*numBlocks { + b.Fatalf("Transactions were not included, expected %d, got %d", numTxs*numBlocks, got) + + } + } +} +func BenchmarkBlockChain_1x1000ValueTransferToNonexisting(b *testing.B) { + var ( + numTxs = 1000 + numBlocks = 1 + ) + + recipientFn := func(nonce uint64) common.Address { + return common.BigToAddress(big.NewInt(0).SetUint64(1337 + nonce)) + } + dataFn := func(nonce uint64) []byte { + return nil + } + + benchmarkLargeNumberOfValueToNonexisting(b, numTxs, numBlocks, recipientFn, dataFn) +} +func BenchmarkBlockChain_1x1000ValueTransferToExisting(b *testing.B) { + var ( + numTxs = 1000 + numBlocks = 1 + ) + b.StopTimer() + b.ResetTimer() + + recipientFn := func(nonce uint64) common.Address { + return common.BigToAddress(big.NewInt(0).SetUint64(1337)) + } + dataFn := func(nonce uint64) []byte { + return nil + } + + benchmarkLargeNumberOfValueToNonexisting(b, numTxs, numBlocks, recipientFn, dataFn) +} +func BenchmarkBlockChain_1x1000Executions(b *testing.B) { + var ( + numTxs = 1000 + numBlocks = 1 + ) + b.StopTimer() + b.ResetTimer() + + recipientFn := func(nonce uint64) common.Address { + return common.BigToAddress(big.NewInt(0).SetUint64(0xc0de)) + } + dataFn := func(nonce uint64) []byte { + return nil + } + + 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 := ethdb.NewMemDatabase() + 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 := ethdb.NewMemDatabase() + 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 := ethdb.NewMemDatabase() + genesis := new(Genesis).MustCommit(db) + + // Generate and import the canonical chain + blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*triesInMemory, nil) + diskdb := ethdb.NewMemDatabase() + 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/core/bloombits/generator.go b/core/bloombits/generator.go index 540085450d..ae07481ada 100644 --- a/core/bloombits/generator.go +++ b/core/bloombits/generator.go @@ -22,16 +22,22 @@ import ( "github.com/ethereum/go-ethereum/core/types" ) -// errSectionOutOfBounds is returned if the user tried to add more bloom filters -// to the batch than available space, or if tries to retrieve above the capacity, -var errSectionOutOfBounds = errors.New("section out of bounds") +var ( + // errSectionOutOfBounds is returned if the user tried to add more bloom filters + // to the batch than available space, or if tries to retrieve above the capacity. + errSectionOutOfBounds = errors.New("section out of bounds") + + // errBloomBitOutOfBounds is returned if the user tried to retrieve specified + // bit bloom above the capacity. + errBloomBitOutOfBounds = errors.New("bloom bit out of bounds") +) // Generator takes a number of bloom filters and generates the rotated bloom bits // to be used for batched filtering. type Generator struct { blooms [types.BloomBitLength][]byte // Rotated blooms for per-bit matching sections uint // Number of sections to batch together - nextBit uint // Next bit to set when adding a bloom + nextSec uint // Next section to set when adding a bloom } // NewGenerator creates a rotated bloom generator that can iteratively fill a @@ -51,15 +57,15 @@ func NewGenerator(sections uint) (*Generator, error) { // in memory accordingly. func (b *Generator) AddBloom(index uint, bloom types.Bloom) error { // Make sure we're not adding more bloom filters than our capacity - if b.nextBit >= b.sections { + if b.nextSec >= b.sections { return errSectionOutOfBounds } - if b.nextBit != index { + if b.nextSec != index { return errors.New("bloom filter with unexpected index") } // Rotate the bloom and insert into our collection - byteIndex := b.nextBit / 8 - bitMask := byte(1) << byte(7-b.nextBit%8) + byteIndex := b.nextSec / 8 + bitMask := byte(1) << byte(7-b.nextSec%8) for i := 0; i < types.BloomBitLength; i++ { bloomByteIndex := types.BloomByteLength - 1 - i/8 @@ -69,7 +75,7 @@ func (b *Generator) AddBloom(index uint, bloom types.Bloom) error { b.blooms[i][byteIndex] |= bitMask } } - b.nextBit++ + b.nextSec++ return nil } @@ -77,11 +83,11 @@ func (b *Generator) AddBloom(index uint, bloom types.Bloom) error { // Bitset returns the bit vector belonging to the given bit index after all // blooms have been added. func (b *Generator) Bitset(idx uint) ([]byte, error) { - if b.nextBit != b.sections { + if b.nextSec != b.sections { return nil, errors.New("bloom not fully generated yet") } - if idx >= b.sections { - return nil, errSectionOutOfBounds + if idx >= types.BloomBitLength { + return nil, errBloomBitOutOfBounds } return b.blooms[idx], nil } diff --git a/core/bloombits/matcher.go b/core/bloombits/matcher.go index ce3031702f..3ec0d5ae94 100644 --- a/core/bloombits/matcher.go +++ b/core/bloombits/matcher.go @@ -59,7 +59,7 @@ type partialMatches struct { // It can also have the actual results set to be used as a delivery data struct. // // The contest and error fields are used by the light client to terminate matching -// early if an error is enountered on some path of the pipeline. +// early if an error is encountered on some path of the pipeline. type Retrieval struct { Bit uint Sections []uint64 @@ -218,7 +218,7 @@ func (m *Matcher) Start(ctx context.Context, begin, end uint64, results chan uin // run creates a daisy-chain of sub-matchers, one for the address set and one // for each topic set, each sub-matcher receiving a section only if the previous // ones have all found a potential match in one of the blocks of the section, -// then binary AND-ing its own matches and forwaring the result to the next one. +// then binary AND-ing its own matches and forwarding the result to the next one. // // The method starts feeding the section indexes into the first sub-matcher on a // new goroutine and returns a sink channel receiving the results. @@ -392,7 +392,7 @@ func (m *Matcher) distributor(dist chan *request, session *MatcherSession) { shutdown = session.quit // Shutdown request channel, will gracefully wait for pending requests ) - // assign is a helper method fo try to assign a pending bit an an actively + // assign is a helper method fo try to assign a pending bit an actively // listening servicer, or schedule it up for later when one arrives. assign := func(bit uint) { select { @@ -543,7 +543,7 @@ func (s *MatcherSession) Error() error { } // AllocateRetrieval assigns a bloom bit index to a client process that can either -// immediately reuest and fetch the section contents assigned to this bit or wait +// immediately request and fetch the section contents assigned to this bit or wait // a little while for more sections to be requested. func (s *MatcherSession) AllocateRetrieval() (uint, bool) { fetcher := make(chan uint) @@ -599,8 +599,8 @@ func (s *MatcherSession) DeliverSections(bit uint, sections []uint64, bitsets [] } } -// Multiplex polls the matcher session for rerieval tasks and multiplexes it into -// the reuested retrieval queue to be serviced together with other sessions. +// Multiplex polls the matcher session for retrieval tasks and multiplexes it into +// the requested retrieval queue to be serviced together with other sessions. // // This method will block for the lifetime of the session. Even after termination // of the session, any request in-flight need to be responded to! Empty responses diff --git a/core/bloombits/matcher_test.go b/core/bloombits/matcher_test.go index 7a5f78ef3a..91143e525e 100644 --- a/core/bloombits/matcher_test.go +++ b/core/bloombits/matcher_test.go @@ -156,7 +156,7 @@ func testMatcher(t *testing.T, filter [][]bloomIndexes, start, blocks uint64, in // Track the number of retrieval requests made var requested uint32 - // Start the matching session for the filter and the retriver goroutines + // Start the matching session for the filter and the retriever goroutines quit := make(chan struct{}) matches := make(chan uint64, 16) diff --git a/core/chain_indexer.go b/core/chain_indexer.go index 7fb184aaa7..1adde1fcb4 100644 --- a/core/chain_indexer.go +++ b/core/chain_indexer.go @@ -17,6 +17,7 @@ package core import ( + "context" "encoding/binary" "fmt" "sync" @@ -24,6 +25,7 @@ import ( "time" "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" @@ -36,11 +38,11 @@ import ( type ChainIndexerBackend interface { // Reset initiates the processing of a new chain segment, potentially terminating // any partially completed operations (in case of a reorg). - Reset(section uint64, prevHead common.Hash) error + Reset(ctx context.Context, section uint64, prevHead common.Hash) error // Process crunches through the next header in the chain segment. The caller // will ensure a sequential order of headers. - Process(header *types.Header) + Process(ctx context.Context, header *types.Header) error // Commit finalizes the section metadata and stores it into the database. Commit() error @@ -51,14 +53,14 @@ type ChainIndexerChain interface { // CurrentHeader retrieves the latest locally known header. CurrentHeader() *types.Header - // SubscribeChainEvent subscribes to new head header notifications. - SubscribeChainEvent(ch chan<- ChainEvent) event.Subscription + // SubscribeChainHeadEvent subscribes to new head header notifications. + SubscribeChainHeadEvent(ch chan<- ChainHeadEvent) event.Subscription } // ChainIndexer does a post-processing job for equally sized sections of the // canonical chain (like BlooomBits and CHT structures). A ChainIndexer is // connected to the blockchain through the event system by starting a -// ChainEventLoop in a goroutine. +// ChainHeadEventLoop in a goroutine. // // Further child ChainIndexers can be added which use the output of the parent // section indexer. These child indexers receive new head notifications only @@ -70,9 +72,11 @@ type ChainIndexer struct { backend ChainIndexerBackend // Background processor generating the index data content children []*ChainIndexer // Child indexers to cascade chain updates to - active uint32 // Flag whether the event loop was started - update chan struct{} // Notification channel that headers should be processed - quit chan chan error // Quit channel to tear down running goroutines + active uint32 // Flag whether the event loop was started + update chan struct{} // Notification channel that headers should be processed + quit chan chan error // Quit channel to tear down running goroutines + ctx context.Context + ctxCancel func() sectionSize uint64 // Number of blocks in a single chain segment to process confirmsReq uint64 // Number of confirmations before processing a completed segment @@ -81,6 +85,9 @@ type ChainIndexer struct { knownSections uint64 // Number of sections known to be complete (block wise) cascadedHead uint64 // Block number of the last completed section cascaded to subindexers + checkpointSections uint64 // Number of sections covered by the checkpoint + checkpointHead common.Hash // Section head belonging to the checkpoint + throttling time.Duration // Disk throttling to prevent a heavy upgrade from hogging resources log log.Logger @@ -104,17 +111,26 @@ func NewChainIndexer(chainDb, indexDb ethdb.Database, backend ChainIndexerBacken } // Initialize database dependent fields and start the updater c.loadValidSections() + c.ctx, c.ctxCancel = context.WithCancel(context.Background()) + go c.updateLoop() return c } -// AddKnownSectionHead marks a new section head as known/processed if it is newer -// than the already known best section head -func (c *ChainIndexer) AddKnownSectionHead(section uint64, shead common.Hash) { +// AddCheckpoint adds a checkpoint. Sections are never processed and the chain +// is not expected to be available before this point. The indexer assumes that +// the backend has sufficient information available to process subsequent sections. +// +// Note: knownSections == 0 and storedSections == checkpointSections until +// syncing reaches the checkpoint +func (c *ChainIndexer) AddCheckpoint(section uint64, shead common.Hash) { c.lock.Lock() defer c.lock.Unlock() + c.checkpointSections = section + 1 + c.checkpointHead = shead + if section < c.storedSections { return } @@ -126,8 +142,8 @@ func (c *ChainIndexer) AddKnownSectionHead(section uint64, shead common.Hash) { // cascading background processing. Children do not need to be started, they // are notified about new events by their parents. func (c *ChainIndexer) Start(chain ChainIndexerChain) { - events := make(chan ChainEvent, 10) - sub := chain.SubscribeChainEvent(events) + events := make(chan ChainHeadEvent, 10) + sub := chain.SubscribeChainHeadEvent(events) go c.eventLoop(chain.CurrentHeader(), events, sub) } @@ -137,6 +153,8 @@ func (c *ChainIndexer) Start(chain ChainIndexerChain) { func (c *ChainIndexer) Close() error { var errs []error + c.ctxCancel() + // Tear down the primary update loop errc := make(chan error) c.quit <- errc @@ -172,7 +190,7 @@ func (c *ChainIndexer) Close() error { // eventLoop is a secondary - optional - event loop of the indexer which is only // started for the outermost indexer to push chain head events into a processing // queue. -func (c *ChainIndexer) eventLoop(currentHeader *types.Header, events chan ChainEvent, sub event.Subscription) { +func (c *ChainIndexer) eventLoop(currentHeader *types.Header, events chan ChainHeadEvent, sub event.Subscription) { // Mark the chain indexer as active, requiring an additional teardown atomic.StoreUint32(&c.active, 1) @@ -201,10 +219,13 @@ func (c *ChainIndexer) eventLoop(currentHeader *types.Header, events chan ChainE } header := ev.Block.Header() if header.ParentHash != prevHash { - // Reorg to the common ancestor (might not exist in light sync mode, skip reorg then) + // Reorg to the common ancestor if needed (might not exist in light sync mode, skip reorg then) // TODO(karalabe, zsfelfoldi): This seems a bit brittle, can we detect this case explicitly? - if h := FindCommonAncestor(c.chainDb, prevHeader, header); h != nil { - c.newHead(h.Number.Uint64(), true) + + if rawdb.ReadCanonicalHash(c.chainDb, prevHeader.Number.Uint64()) != prevHash { + if h := rawdb.FindCommonAncestor(c.chainDb, prevHeader, header); h != nil { + c.newHead(h.Number.Uint64(), true) + } } } c.newHead(header.Number.Uint64(), false) @@ -222,16 +243,23 @@ func (c *ChainIndexer) newHead(head uint64, reorg bool) { // If a reorg happened, invalidate all sections until that point if reorg { // Revert the known section number to the reorg point - changed := head / c.sectionSize - if changed < c.knownSections { - c.knownSections = changed + known := head / c.sectionSize + stored := known + if known < c.checkpointSections { + known = 0 + } + if stored < c.checkpointSections { + stored = c.checkpointSections + } + if known < c.knownSections { + c.knownSections = known } // Revert the stored sections from the database to the reorg point - if changed < c.storedSections { - c.setValidSections(changed) + if stored < c.storedSections { + c.setValidSections(stored) } // Update the new head number to the finalized section end and notify children - head = changed * c.sectionSize + head = known * c.sectionSize if head < c.cascadedHead { c.cascadedHead = head @@ -245,7 +273,18 @@ func (c *ChainIndexer) newHead(head uint64, reorg bool) { var sections uint64 if head >= c.confirmsReq { sections = (head + 1 - c.confirmsReq) / c.sectionSize + if sections < c.checkpointSections { + sections = 0 + } if sections > c.knownSections { + if c.knownSections < c.checkpointSections { + // syncing reached the checkpoint, verify section head + syncedHead := rawdb.ReadCanonicalHash(c.chainDb, c.checkpointSections*c.sectionSize-1) + if syncedHead != c.checkpointHead { + c.log.Error("Synced chain does not match checkpoint", "number", c.checkpointSections*c.sectionSize-1, "expected", c.checkpointHead, "synced", syncedHead) + return + } + } c.knownSections = sections select { @@ -293,6 +332,12 @@ func (c *ChainIndexer) updateLoop() { c.lock.Unlock() newHead, err := c.processSection(section, oldHead) if err != nil { + select { + case <-c.ctx.Done(): + <-c.quit <- nil + return + default: + } c.log.Error("Section processing failed", "error", err) } c.lock.Lock() @@ -305,7 +350,6 @@ func (c *ChainIndexer) updateLoop() { updating = false c.log.Info("Finished upgrading chain index") } - c.cascadedHead = c.storedSections*c.sectionSize - 1 for _, child := range c.children { c.log.Trace("Cascading chain index update", "head", c.cascadedHead) @@ -340,27 +384,28 @@ func (c *ChainIndexer) processSection(section uint64, lastHead common.Hash) (com // Reset and partial processing - if err := c.backend.Reset(section, lastHead); err != nil { + if err := c.backend.Reset(c.ctx, section, lastHead); err != nil { c.setValidSections(0) return common.Hash{}, err } for number := section * c.sectionSize; number < (section+1)*c.sectionSize; number++ { - hash := GetCanonicalHash(c.chainDb, number) + hash := rawdb.ReadCanonicalHash(c.chainDb, number) if hash == (common.Hash{}) { return common.Hash{}, fmt.Errorf("canonical block #%d unknown", number) } - header := GetHeader(c.chainDb, hash, number) + header := rawdb.ReadHeader(c.chainDb, hash, number) if header == nil { return common.Hash{}, fmt.Errorf("block #%d [%x…] not found", number, hash[:4]) } else if header.ParentHash != lastHead { return common.Hash{}, fmt.Errorf("chain reorged during section processing") } - c.backend.Process(header) + if err := c.backend.Process(c.ctx, header); err != nil { + return common.Hash{}, err + } lastHead = header.Hash() } if err := c.backend.Commit(); err != nil { - c.log.Error("Section commit failed", "error", err) return common.Hash{}, err } return lastHead, nil @@ -384,8 +429,14 @@ func (c *ChainIndexer) AddChildIndexer(indexer *ChainIndexer) { c.children = append(c.children, indexer) // Cascade any pending updates to new children too - if c.storedSections > 0 { - indexer.newHead(c.storedSections*c.sectionSize-1, false) + sections := c.storedSections + if c.knownSections < sections { + // if a section is "stored" but not "known" then it is a checkpoint without + // available chain data so we should not cascade it yet + sections = c.knownSections + } + if sections > 0 { + indexer.newHead(sections*c.sectionSize-1, false) } } @@ -394,7 +445,7 @@ func (c *ChainIndexer) AddChildIndexer(indexer *ChainIndexer) { func (c *ChainIndexer) loadValidSections() { data, _ := c.indexDb.Get([]byte("count")) if len(data) == 8 { - c.storedSections = binary.BigEndian.Uint64(data[:]) + c.storedSections = binary.BigEndian.Uint64(data) } } diff --git a/core/chain_indexer_test.go b/core/chain_indexer_test.go index 9fc09eda51..a029dec626 100644 --- a/core/chain_indexer_test.go +++ b/core/chain_indexer_test.go @@ -17,6 +17,7 @@ package core import ( + "context" "fmt" "math/big" "math/rand" @@ -24,6 +25,7 @@ import ( "time" "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" ) @@ -47,7 +49,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 := ethdb.NewMemDatabase() defer db.Close() // Create a chain of indexers and ensure they all report empty @@ -92,10 +94,10 @@ func testChainIndexer(t *testing.T, count int) { inject := func(number uint64) { header := &types.Header{Number: big.NewInt(int64(number)), Extra: big.NewInt(rand.Int63()).Bytes()} if number > 0 { - header.ParentHash = GetCanonicalHash(db, number-1) + header.ParentHash = rawdb.ReadCanonicalHash(db, number-1) } - WriteHeader(db, header) - WriteCanonicalHash(db, header.Hash(), number) + rawdb.WriteHeader(db, header) + rawdb.WriteCanonicalHash(db, header.Hash(), number) } // Start indexer with an already existing chain for i := uint64(0); i <= 100; i++ { @@ -209,13 +211,13 @@ func (b *testChainIndexBackend) reorg(headNum uint64) uint64 { return b.stored * b.indexer.sectionSize } -func (b *testChainIndexBackend) Reset(section uint64, prevHead common.Hash) error { +func (b *testChainIndexBackend) Reset(ctx context.Context, section uint64, prevHead common.Hash) error { b.section = section b.headerCnt = 0 return nil } -func (b *testChainIndexBackend) Process(header *types.Header) { +func (b *testChainIndexBackend) Process(ctx context.Context, header *types.Header) error { b.headerCnt++ if b.headerCnt > b.indexer.sectionSize { b.t.Error("Processing too many headers") @@ -226,6 +228,7 @@ func (b *testChainIndexBackend) Process(header *types.Header) { b.t.Fatal("Unexpected call to Process") case b.processCh <- header.Number.Uint64(): } + return nil } func (b *testChainIndexBackend) Commit() error { diff --git a/core/chain_makers.go b/core/chain_makers.go index 5e264a9942..0b5a3d1843 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -30,21 +30,14 @@ import ( "github.com/ethereum/go-ethereum/params" ) -// So we can deterministically seed different blockchains -var ( - canonicalSeed = 1 - forkSeed = 2 -) - // BlockGen creates blocks for testing. // See GenerateChain for a detailed explanation. type BlockGen struct { - i int - parent *types.Block - chain []*types.Block - chainReader consensus.ChainReader - header *types.Header - statedb *state.StateDB + i int + parent *types.Block + chain []*types.Block + header *types.Header + statedb *state.StateDB gasPool *GasPool txs []*types.Transaction @@ -73,6 +66,11 @@ func (b *BlockGen) SetExtra(data []byte) { b.header.Extra = data } +// SetNonce sets the nonce field of the generated block. +func (b *BlockGen) SetNonce(nonce types.BlockNonce) { + b.header.Nonce = nonce +} + // AddTx adds a transaction to the generated block. If no coinbase has // been set, the block's coinbase is set to the zero address. // @@ -82,11 +80,23 @@ func (b *BlockGen) SetExtra(data []byte) { // added. Notably, contract code relying on the BLOCKHASH instruction // will panic during execution. func (b *BlockGen) AddTx(tx *types.Transaction) { + b.AddTxWithChain(nil, tx) +} + +// AddTxWithChain adds a transaction to the generated block. If no coinbase has +// been set, the block's coinbase is set to the zero address. +// +// AddTxWithChain panics if the transaction cannot be executed. In addition to +// the protocol-imposed limitations (gas limit, etc.), there are some +// further limitations on the content of transactions that can be +// added. If contract code relies on the BLOCKHASH instruction, +// the block in chain will be returned. +func (b *BlockGen) AddTxWithChain(bc *BlockChain, tx *types.Transaction) { if b.gasPool == nil { b.SetCoinbase(common.Address{}) } b.statedb.Prepare(tx.Hash(), common.Hash{}, len(b.txs)) - receipt, _, err := ApplyTransaction(b.config, nil, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vm.Config{}) + receipt, _, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vm.Config{}) if err != nil { panic(err) } @@ -127,7 +137,7 @@ func (b *BlockGen) AddUncle(h *types.Header) { // For index -1, PrevBlock returns the parent block given to GenerateChain. func (b *BlockGen) PrevBlock(index int) *types.Block { if index >= b.i { - panic("block index out of range") + panic(fmt.Errorf("block index %d out of range (%d,%d)", index, -1, b.i)) } if index == -1 { return b.parent @@ -139,11 +149,12 @@ 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") } - b.header.Difficulty = b.engine.CalcDifficulty(b.chainReader, b.header.Time.Uint64(), b.parent.Header()) + chainreader := &fakeChainReader{config: b.config} + b.header.Difficulty = b.engine.CalcDifficulty(chainreader, b.header.Time.Uint64(), b.parent.Header()) } // GenerateChain creates a chain of n blocks. The first block's @@ -163,14 +174,10 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse config = params.TestChainConfig } blocks, receipts := make(types.Blocks, n), make([]types.Receipts, n) + chainreader := &fakeChainReader{config: config} genblock := func(i int, parent *types.Block, statedb *state.StateDB) (*types.Block, types.Receipts) { - // TODO(karalabe): This is needed for clique, which depends on multiple blocks. - // It's nonetheless ugly to spin up a blockchain here. Get rid of this somehow. - blockchain, _ := NewBlockChain(db, config, engine, vm.Config{}) - defer blockchain.Stop() - - b := &BlockGen{i: i, parent: parent, chain: blocks, chainReader: blockchain, statedb: statedb, config: config, engine: engine} - b.header = makeHeader(b.chainReader, parent, statedb, b.engine) + b := &BlockGen{i: i, chain: blocks, parent: parent, statedb: statedb, config: config, engine: engine} + b.header = makeHeader(chainreader, parent, statedb, b.engine) // Mutate the state and block according to any hard-fork specs if daoBlock := config.DAOForkBlock; daoBlock != nil { @@ -184,18 +191,22 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse if config.DAOForkSupport && config.DAOForkBlock != nil && config.DAOForkBlock.Cmp(b.header.Number) == 0 { misc.ApplyDAOHardFork(statedb) } - // Execute any user modifications to the block and finalize it + // Execute any user modifications to the block if gen != nil { gen(i, b) } - if b.engine != nil { - block, _ := b.engine.Finalize(b.chainReader, b.header, statedb, b.txs, b.uncles, b.receipts) + // Finalize and seal the block + block, _ := b.engine.Finalize(chainreader, b.header, statedb, b.txs, b.uncles, b.receipts) + // Write state changes to db - _, err := statedb.CommitTo(db, config.IsEIP158(b.header.Number)) + root, err := statedb.Commit(config.IsEIP158(b.header.Number)) if err != nil { panic(fmt.Sprintf("state write error: %v", err)) } + if err := statedb.Database().TrieDB().Commit(root, false); err != nil { + panic(fmt.Sprintf("trie write error: %v", err)) + } return block, b.receipts } return nil, nil @@ -231,38 +242,12 @@ func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.S Difficulty: parent.Difficulty(), UncleHash: parent.UncleHash(), }), - GasLimit: CalcGasLimit(parent), + GasLimit: CalcGasLimit(parent, parent.GasLimit(), parent.GasLimit()), Number: new(big.Int).Add(parent.Number(), common.Big1), Time: time, } } -// newCanonical creates a chain database, and injects a deterministic canonical -// chain. Depending on the full flag, if creates either a full block chain or a -// header only chain. -func newCanonical(engine consensus.Engine, n int, full bool) (ethdb.Database, *BlockChain, error) { - // Initialize a fresh chain with only a genesis block - gspec := new(Genesis) - db, _ := ethdb.NewMemDatabase() - genesis := gspec.MustCommit(db) - - blockchain, _ := NewBlockChain(db, params.AllEthashProtocolChanges, engine, vm.Config{}) - // Create and inject the requested chain - if n == 0 { - return db, blockchain, nil - } - if full { - // Full block-chain requested - blocks := makeBlockChain(genesis, n, engine, db, canonicalSeed) - _, err := blockchain.InsertChain(blocks) - return db, blockchain, err - } - // Header-only chain requested - headers := makeHeaderChain(genesis.Header(), n, engine, db, canonicalSeed) - _, err := blockchain.InsertHeaderChain(headers, 1) - return db, blockchain, err -} - // makeHeaderChain creates a deterministic chain of headers rooted at parent. func makeHeaderChain(parent *types.Header, n int, engine consensus.Engine, db ethdb.Database, seed int) []*types.Header { blocks := makeBlockChain(types.NewBlockWithHeader(parent), n, engine, db, seed) @@ -280,3 +265,19 @@ func makeBlockChain(parent *types.Block, n int, engine consensus.Engine, db ethd }) return blocks } + +type fakeChainReader struct { + config *params.ChainConfig + genesis *types.Block +} + +// Config returns the chain configuration. +func (cr *fakeChainReader) Config() *params.ChainConfig { + return cr.config +} + +func (cr *fakeChainReader) CurrentHeader() *types.Header { return nil } +func (cr *fakeChainReader) GetHeaderByNumber(number uint64) *types.Header { return nil } +func (cr *fakeChainReader) GetHeaderByHash(hash common.Hash) *types.Header { return nil } +func (cr *fakeChainReader) GetHeader(hash common.Hash, number uint64) *types.Header { return nil } +func (cr *fakeChainReader) GetBlock(hash common.Hash, number uint64) *types.Block { return nil } diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index a3b80da299..64b64fd6a3 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -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 = ethdb.NewMemDatabase() ) // Ensure that key1 has some funds in the genesis block. @@ -79,7 +79,7 @@ func ExampleGenerateChain() { }) // Import the chain. This runs all block validation rules. - blockchain, _ := NewBlockChain(db, gspec.Config, ethash.NewFaker(), vm.Config{}) + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) defer blockchain.Stop() if i, err := blockchain.InsertChain(chain); err != nil { diff --git a/core/dao_test.go b/core/dao_test.go index 43e2982a52..966139bce3 100644 --- a/core/dao_test.go +++ b/core/dao_test.go @@ -32,30 +32,30 @@ func TestDAOForkRangeExtradata(t *testing.T) { forkBlock := big.NewInt(32) // Generate a common prefix for both pro-forkers and non-forkers - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() 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 := ethdb.NewMemDatabase() gspec.MustCommit(proDb) proConf := *params.TestChainConfig proConf.DAOForkBlock = forkBlock proConf.DAOForkSupport = true - proBc, _ := NewBlockChain(proDb, &proConf, ethash.NewFaker(), vm.Config{}) + proBc, _ := NewBlockChain(proDb, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil) defer proBc.Stop() - conDb, _ := ethdb.NewMemDatabase() + conDb := ethdb.NewMemDatabase() gspec.MustCommit(conDb) conConf := *params.TestChainConfig conConf.DAOForkBlock = forkBlock conConf.DAOForkSupport = false - conBc, _ := NewBlockChain(conDb, &conConf, ethash.NewFaker(), vm.Config{}) + conBc, _ := NewBlockChain(conDb, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil) defer conBc.Stop() if _, err := proBc.InsertChain(prefix); err != nil { @@ -67,9 +67,9 @@ 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 = ethdb.NewMemDatabase() gspec.MustCommit(db) - bc, _ := NewBlockChain(db, &conConf, ethash.NewFaker(), vm.Config{}) + bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil) defer bc.Stop() blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64())) @@ -79,6 +79,9 @@ func TestDAOForkRangeExtradata(t *testing.T) { if _, err := bc.InsertChain(blocks); err != nil { t.Fatalf("failed to import contra-fork chain for expansion: %v", err) } + if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, true); err != nil { + t.Fatalf("failed to commit contra-fork head for expansion: %v", err) + } blocks, _ = GenerateChain(&proConf, conBc.CurrentBlock(), ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) {}) if _, err := conBc.InsertChain(blocks); err == nil { t.Fatalf("contra-fork chain accepted pro-fork block: %v", blocks[0]) @@ -89,9 +92,9 @@ 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 = ethdb.NewMemDatabase() gspec.MustCommit(db) - bc, _ = NewBlockChain(db, &proConf, ethash.NewFaker(), vm.Config{}) + bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil) defer bc.Stop() blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64())) @@ -101,6 +104,9 @@ func TestDAOForkRangeExtradata(t *testing.T) { if _, err := bc.InsertChain(blocks); err != nil { t.Fatalf("failed to import pro-fork chain for expansion: %v", err) } + if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, true); err != nil { + t.Fatalf("failed to commit pro-fork head for expansion: %v", err) + } blocks, _ = GenerateChain(&conConf, proBc.CurrentBlock(), ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) {}) if _, err := proBc.InsertChain(blocks); err == nil { t.Fatalf("pro-fork chain accepted contra-fork block: %v", blocks[0]) @@ -112,9 +118,9 @@ func TestDAOForkRangeExtradata(t *testing.T) { } } // Verify that contra-forkers accept pro-fork extra-datas after forking finishes - db, _ = ethdb.NewMemDatabase() + db = ethdb.NewMemDatabase() gspec.MustCommit(db) - bc, _ := NewBlockChain(db, &conConf, ethash.NewFaker(), vm.Config{}) + bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil) defer bc.Stop() blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64())) @@ -124,14 +130,17 @@ func TestDAOForkRangeExtradata(t *testing.T) { if _, err := bc.InsertChain(blocks); err != nil { t.Fatalf("failed to import contra-fork chain for expansion: %v", err) } + if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, true); err != nil { + t.Fatalf("failed to commit contra-fork head for expansion: %v", err) + } blocks, _ = GenerateChain(&proConf, conBc.CurrentBlock(), ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) {}) if _, err := conBc.InsertChain(blocks); err != nil { 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 = ethdb.NewMemDatabase() gspec.MustCommit(db) - bc, _ = NewBlockChain(db, &proConf, ethash.NewFaker(), vm.Config{}) + bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil) defer bc.Stop() blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64())) @@ -141,6 +150,9 @@ func TestDAOForkRangeExtradata(t *testing.T) { if _, err := bc.InsertChain(blocks); err != nil { t.Fatalf("failed to import pro-fork chain for expansion: %v", err) } + if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, true); err != nil { + t.Fatalf("failed to commit pro-fork head for expansion: %v", err) + } blocks, _ = GenerateChain(&conConf, proBc.CurrentBlock(), ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) {}) if _, err := proBc.InsertChain(blocks); err != nil { t.Fatalf("pro-fork chain didn't accept contra-fork block post-fork: %v", err) diff --git a/core/database_util.go b/core/database_util.go deleted file mode 100644 index c6b125dae9..0000000000 --- a/core/database_util.go +++ /dev/null @@ -1,632 +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 core - -import ( - "bytes" - "encoding/binary" - "encoding/json" - "errors" - "fmt" - "math/big" - - "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/metrics" - "github.com/ethereum/go-ethereum/params" - "github.com/ethereum/go-ethereum/rlp" -) - -// DatabaseReader wraps the Get method of a backing data store. -type DatabaseReader interface { - Get(key []byte) (value []byte, err error) -} - -// DatabaseDeleter wraps the Delete method of a backing data store. -type DatabaseDeleter interface { - Delete(key []byte) error -} - -var ( - headHeaderKey = []byte("LastHeader") - headBlockKey = []byte("LastBlock") - headFastKey = []byte("LastFast") - - // Data item prefixes (use single byte to avoid mixing data types, avoid `i`). - headerPrefix = []byte("h") // headerPrefix + num (uint64 big endian) + hash -> header - tdSuffix = []byte("t") // headerPrefix + num (uint64 big endian) + hash + tdSuffix -> td - numSuffix = []byte("n") // headerPrefix + num (uint64 big endian) + numSuffix -> hash - blockHashPrefix = []byte("H") // blockHashPrefix + hash -> num (uint64 big endian) - bodyPrefix = []byte("b") // bodyPrefix + num (uint64 big endian) + hash -> block body - blockReceiptsPrefix = []byte("r") // blockReceiptsPrefix + num (uint64 big endian) + hash -> block receipts - lookupPrefix = []byte("l") // lookupPrefix + hash -> transaction/receipt lookup metadata - bloomBitsPrefix = []byte("B") // bloomBitsPrefix + bit (uint16 big endian) + section (uint64 big endian) + hash -> bloom bits - - preimagePrefix = "secure-key-" // preimagePrefix + hash -> preimage - configPrefix = []byte("ethereum-config-") // config prefix for the db - - // Chain index prefixes (use `i` + single byte to avoid mixing data types). - BloomBitsIndexPrefix = []byte("iB") // BloomBitsIndexPrefix is the data table of a chain indexer to track its progress - - // used by old db, now only used for conversion - oldReceiptsPrefix = []byte("receipts-") - oldTxMetaSuffix = []byte{0x01} - - ErrChainConfigNotFound = errors.New("ChainConfig not found") // general config not found error - - preimageCounter = metrics.NewCounter("db/preimage/total") - preimageHitCounter = metrics.NewCounter("db/preimage/hits") -) - -// TxLookupEntry is a positional metadata to help looking up the data content of -// a transaction or receipt given only its hash. -type TxLookupEntry struct { - BlockHash common.Hash - BlockIndex uint64 - Index uint64 -} - -// encodeBlockNumber encodes a block number as big endian uint64 -func encodeBlockNumber(number uint64) []byte { - enc := make([]byte, 8) - binary.BigEndian.PutUint64(enc, number) - return enc -} - -// GetCanonicalHash retrieves a hash assigned to a canonical block number. -func GetCanonicalHash(db DatabaseReader, number uint64) common.Hash { - data, _ := db.Get(append(append(headerPrefix, encodeBlockNumber(number)...), numSuffix...)) - if len(data) == 0 { - return common.Hash{} - } - return common.BytesToHash(data) -} - -// missingNumber is returned by GetBlockNumber if no header with the -// given block hash has been stored in the database -const missingNumber = uint64(0xffffffffffffffff) - -// GetBlockNumber returns the block number assigned to a block hash -// if the corresponding header is present in the database -func GetBlockNumber(db DatabaseReader, hash common.Hash) uint64 { - data, _ := db.Get(append(blockHashPrefix, hash.Bytes()...)) - if len(data) != 8 { - return missingNumber - } - return binary.BigEndian.Uint64(data) -} - -// GetHeadHeaderHash retrieves the hash of the current canonical head block's -// header. The difference between this and GetHeadBlockHash is that whereas the -// last block hash is only updated upon a full block import, the last header -// hash is updated already at header import, allowing head tracking for the -// light synchronization mechanism. -func GetHeadHeaderHash(db DatabaseReader) common.Hash { - data, _ := db.Get(headHeaderKey) - if len(data) == 0 { - return common.Hash{} - } - return common.BytesToHash(data) -} - -// GetHeadBlockHash retrieves the hash of the current canonical head block. -func GetHeadBlockHash(db DatabaseReader) common.Hash { - data, _ := db.Get(headBlockKey) - if len(data) == 0 { - return common.Hash{} - } - return common.BytesToHash(data) -} - -// GetHeadFastBlockHash retrieves the hash of the current canonical head block during -// fast synchronization. The difference between this and GetHeadBlockHash is that -// whereas the last block hash is only updated upon a full block import, the last -// fast hash is updated when importing pre-processed blocks. -func GetHeadFastBlockHash(db DatabaseReader) common.Hash { - data, _ := db.Get(headFastKey) - if len(data) == 0 { - return common.Hash{} - } - return common.BytesToHash(data) -} - -// GetHeaderRLP retrieves a block header in its raw RLP database encoding, or nil -// if the header's not found. -func GetHeaderRLP(db DatabaseReader, hash common.Hash, number uint64) rlp.RawValue { - data, _ := db.Get(headerKey(hash, number)) - return data -} - -// GetHeader retrieves the block header corresponding to the hash, nil if none -// found. -func GetHeader(db DatabaseReader, hash common.Hash, number uint64) *types.Header { - data := GetHeaderRLP(db, hash, number) - if len(data) == 0 { - return nil - } - header := new(types.Header) - if err := rlp.Decode(bytes.NewReader(data), header); err != nil { - log.Error("Invalid block header RLP", "hash", hash, "err", err) - return nil - } - return header -} - -// GetBodyRLP retrieves the block body (transactions and uncles) in RLP encoding. -func GetBodyRLP(db DatabaseReader, hash common.Hash, number uint64) rlp.RawValue { - data, _ := db.Get(blockBodyKey(hash, number)) - return data -} - -func headerKey(hash common.Hash, number uint64) []byte { - return append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...) -} - -func blockBodyKey(hash common.Hash, number uint64) []byte { - return append(append(bodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...) -} - -// GetBody retrieves the block body (transactons, uncles) corresponding to the -// hash, nil if none found. -func GetBody(db DatabaseReader, hash common.Hash, number uint64) *types.Body { - data := GetBodyRLP(db, hash, number) - if len(data) == 0 { - return nil - } - body := new(types.Body) - if err := rlp.Decode(bytes.NewReader(data), body); err != nil { - log.Error("Invalid block body RLP", "hash", hash, "err", err) - return nil - } - return body -} - -// GetTd retrieves a block's total difficulty corresponding to the hash, nil if -// none found. -func GetTd(db DatabaseReader, hash common.Hash, number uint64) *big.Int { - data, _ := db.Get(append(append(append(headerPrefix, encodeBlockNumber(number)...), hash[:]...), tdSuffix...)) - if len(data) == 0 { - return nil - } - td := new(big.Int) - if err := rlp.Decode(bytes.NewReader(data), td); err != nil { - log.Error("Invalid block total difficulty RLP", "hash", hash, "err", err) - return nil - } - return td -} - -// GetBlock retrieves an entire block corresponding to the hash, assembling it -// back from the stored header and body. If either the header or body could not -// be retrieved nil is returned. -// -// 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 GetBlock(db DatabaseReader, hash common.Hash, number uint64) *types.Block { - // Retrieve the block header and body contents - header := GetHeader(db, hash, number) - if header == nil { - return nil - } - body := GetBody(db, hash, number) - if body == nil { - return nil - } - // Reassemble the block and return - return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles) -} - -// GetBlockReceipts retrieves the receipts generated by the transactions included -// in a block given by its hash. -func GetBlockReceipts(db DatabaseReader, hash common.Hash, number uint64) types.Receipts { - data, _ := db.Get(append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash[:]...)) - if len(data) == 0 { - return nil - } - storageReceipts := []*types.ReceiptForStorage{} - if err := rlp.DecodeBytes(data, &storageReceipts); err != nil { - log.Error("Invalid receipt array RLP", "hash", hash, "err", err) - return nil - } - receipts := make(types.Receipts, len(storageReceipts)) - for i, receipt := range storageReceipts { - receipts[i] = (*types.Receipt)(receipt) - } - return receipts -} - -// GetTxLookupEntry retrieves the positional metadata associated with a transaction -// hash to allow retrieving the transaction or receipt by hash. -func GetTxLookupEntry(db DatabaseReader, hash common.Hash) (common.Hash, uint64, uint64) { - // Load the positional metadata from disk and bail if it fails - data, _ := db.Get(append(lookupPrefix, hash.Bytes()...)) - if len(data) == 0 { - return common.Hash{}, 0, 0 - } - // Parse and return the contents of the lookup entry - var entry TxLookupEntry - if err := rlp.DecodeBytes(data, &entry); err != nil { - log.Error("Invalid lookup entry RLP", "hash", hash, "err", err) - return common.Hash{}, 0, 0 - } - return entry.BlockHash, entry.BlockIndex, entry.Index -} - -// GetTransaction retrieves a specific transaction from the database, along with -// its added positional metadata. -func GetTransaction(db DatabaseReader, hash common.Hash) (*types.Transaction, common.Hash, uint64, uint64) { - // Retrieve the lookup metadata and resolve the transaction from the body - blockHash, blockNumber, txIndex := GetTxLookupEntry(db, hash) - - if blockHash != (common.Hash{}) { - body := GetBody(db, blockHash, blockNumber) - if body == nil || len(body.Transactions) <= int(txIndex) { - log.Error("Transaction referenced missing", "number", blockNumber, "hash", blockHash, "index", txIndex) - return nil, common.Hash{}, 0, 0 - } - return body.Transactions[txIndex], blockHash, blockNumber, txIndex - } - // Old transaction representation, load the transaction and it's metadata separately - data, _ := db.Get(hash.Bytes()) - if len(data) == 0 { - return nil, common.Hash{}, 0, 0 - } - var tx types.Transaction - if err := rlp.DecodeBytes(data, &tx); err != nil { - return nil, common.Hash{}, 0, 0 - } - // Retrieve the blockchain positional metadata - data, _ = db.Get(append(hash.Bytes(), oldTxMetaSuffix...)) - if len(data) == 0 { - return nil, common.Hash{}, 0, 0 - } - var entry TxLookupEntry - if err := rlp.DecodeBytes(data, &entry); err != nil { - return nil, common.Hash{}, 0, 0 - } - return &tx, entry.BlockHash, entry.BlockIndex, entry.Index -} - -// GetReceipt retrieves a specific transaction receipt from the database, along with -// its added positional metadata. -func GetReceipt(db DatabaseReader, hash common.Hash) (*types.Receipt, common.Hash, uint64, uint64) { - // Retrieve the lookup metadata and resolve the receipt from the receipts - blockHash, blockNumber, receiptIndex := GetTxLookupEntry(db, hash) - - if blockHash != (common.Hash{}) { - receipts := GetBlockReceipts(db, blockHash, blockNumber) - if len(receipts) <= int(receiptIndex) { - log.Error("Receipt refereced missing", "number", blockNumber, "hash", blockHash, "index", receiptIndex) - return nil, common.Hash{}, 0, 0 - } - return receipts[receiptIndex], blockHash, blockNumber, receiptIndex - } - // Old receipt representation, load the receipt and set an unknown metadata - data, _ := db.Get(append(oldReceiptsPrefix, hash[:]...)) - if len(data) == 0 { - return nil, common.Hash{}, 0, 0 - } - var receipt types.ReceiptForStorage - err := rlp.DecodeBytes(data, &receipt) - if err != nil { - log.Error("Invalid receipt RLP", "hash", hash, "err", err) - } - return (*types.Receipt)(&receipt), common.Hash{}, 0, 0 -} - -// GetBloomBits retrieves the compressed bloom bit vector belonging to the given -// section and bit index from the. -func GetBloomBits(db DatabaseReader, bit uint, section uint64, head common.Hash) ([]byte, error) { - key := append(append(bloomBitsPrefix, make([]byte, 10)...), head.Bytes()...) - - binary.BigEndian.PutUint16(key[1:], uint16(bit)) - binary.BigEndian.PutUint64(key[3:], section) - - return db.Get(key) -} - -// WriteCanonicalHash stores the canonical hash for the given block number. -func WriteCanonicalHash(db ethdb.Putter, hash common.Hash, number uint64) error { - key := append(append(headerPrefix, encodeBlockNumber(number)...), numSuffix...) - if err := db.Put(key, hash.Bytes()); err != nil { - log.Crit("Failed to store number to hash mapping", "err", err) - } - return nil -} - -// WriteHeadHeaderHash stores the head header's hash. -func WriteHeadHeaderHash(db ethdb.Putter, hash common.Hash) error { - if err := db.Put(headHeaderKey, hash.Bytes()); err != nil { - log.Crit("Failed to store last header's hash", "err", err) - } - return nil -} - -// WriteHeadBlockHash stores the head block's hash. -func WriteHeadBlockHash(db ethdb.Putter, hash common.Hash) error { - if err := db.Put(headBlockKey, hash.Bytes()); err != nil { - log.Crit("Failed to store last block's hash", "err", err) - } - return nil -} - -// WriteHeadFastBlockHash stores the fast head block's hash. -func WriteHeadFastBlockHash(db ethdb.Putter, hash common.Hash) error { - if err := db.Put(headFastKey, hash.Bytes()); err != nil { - log.Crit("Failed to store last fast block's hash", "err", err) - } - return nil -} - -// WriteHeader serializes a block header into the database. -func WriteHeader(db ethdb.Putter, header *types.Header) error { - data, err := rlp.EncodeToBytes(header) - if err != nil { - return err - } - hash := header.Hash().Bytes() - num := header.Number.Uint64() - encNum := encodeBlockNumber(num) - key := append(blockHashPrefix, hash...) - if err := db.Put(key, encNum); err != nil { - log.Crit("Failed to store hash to number mapping", "err", err) - } - key = append(append(headerPrefix, encNum...), hash...) - if err := db.Put(key, data); err != nil { - log.Crit("Failed to store header", "err", err) - } - return nil -} - -// WriteBody serializes the body of a block into the database. -func WriteBody(db ethdb.Putter, hash common.Hash, number uint64, body *types.Body) error { - data, err := rlp.EncodeToBytes(body) - if err != nil { - return err - } - return WriteBodyRLP(db, hash, number, data) -} - -// WriteBodyRLP writes a serialized body of a block into the database. -func WriteBodyRLP(db ethdb.Putter, hash common.Hash, number uint64, rlp rlp.RawValue) error { - key := append(append(bodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...) - if err := db.Put(key, rlp); err != nil { - log.Crit("Failed to store block body", "err", err) - } - return nil -} - -// WriteTd serializes the total difficulty of a block into the database. -func WriteTd(db ethdb.Putter, hash common.Hash, number uint64, td *big.Int) error { - data, err := rlp.EncodeToBytes(td) - if err != nil { - return err - } - key := append(append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...), tdSuffix...) - if err := db.Put(key, data); err != nil { - log.Crit("Failed to store block total difficulty", "err", err) - } - return nil -} - -// WriteBlock serializes a block into the database, header and body separately. -func WriteBlock(db ethdb.Putter, block *types.Block) error { - // Store the body first to retain database consistency - if err := WriteBody(db, block.Hash(), block.NumberU64(), block.Body()); err != nil { - return err - } - // Store the header too, signaling full block ownership - if err := WriteHeader(db, block.Header()); err != nil { - return err - } - return nil -} - -// WriteBlockReceipts stores all the transaction receipts belonging to a block -// as a single receipt slice. This is used during chain reorganisations for -// rescheduling dropped transactions. -func WriteBlockReceipts(db ethdb.Putter, hash common.Hash, number uint64, receipts types.Receipts) error { - // Convert the receipts into their storage form and serialize them - storageReceipts := make([]*types.ReceiptForStorage, len(receipts)) - for i, receipt := range receipts { - storageReceipts[i] = (*types.ReceiptForStorage)(receipt) - } - bytes, err := rlp.EncodeToBytes(storageReceipts) - if err != nil { - return err - } - // Store the flattened receipt slice - key := append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash.Bytes()...) - if err := db.Put(key, bytes); err != nil { - log.Crit("Failed to store block receipts", "err", err) - } - return nil -} - -// WriteTxLookupEntries stores a positional metadata for every transaction from -// a block, enabling hash based transaction and receipt lookups. -func WriteTxLookupEntries(db ethdb.Putter, block *types.Block) error { - // Iterate over each transaction and encode its metadata - 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 { - return err - } - if err := db.Put(append(lookupPrefix, tx.Hash().Bytes()...), data); err != nil { - return err - } - } - return nil -} - -// WriteBloomBits writes the compressed bloom bits vector belonging to the given -// section and bit index. -func WriteBloomBits(db ethdb.Putter, bit uint, section uint64, head common.Hash, bits []byte) { - key := append(append(bloomBitsPrefix, make([]byte, 10)...), head.Bytes()...) - - binary.BigEndian.PutUint16(key[1:], uint16(bit)) - binary.BigEndian.PutUint64(key[3:], section) - - if err := db.Put(key, bits); err != nil { - log.Crit("Failed to store bloom bits", "err", err) - } -} - -// DeleteCanonicalHash removes the number to hash canonical mapping. -func DeleteCanonicalHash(db DatabaseDeleter, number uint64) { - db.Delete(append(append(headerPrefix, encodeBlockNumber(number)...), numSuffix...)) -} - -// DeleteHeader removes all block header data associated with a hash. -func DeleteHeader(db DatabaseDeleter, hash common.Hash, number uint64) { - db.Delete(append(blockHashPrefix, hash.Bytes()...)) - db.Delete(append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...)) -} - -// DeleteBody removes all block body data associated with a hash. -func DeleteBody(db DatabaseDeleter, hash common.Hash, number uint64) { - db.Delete(append(append(bodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...)) -} - -// DeleteTd removes all block total difficulty data associated with a hash. -func DeleteTd(db DatabaseDeleter, hash common.Hash, number uint64) { - db.Delete(append(append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...), tdSuffix...)) -} - -// DeleteBlock removes all block data associated with a hash. -func DeleteBlock(db DatabaseDeleter, hash common.Hash, number uint64) { - DeleteBlockReceipts(db, hash, number) - DeleteHeader(db, hash, number) - DeleteBody(db, hash, number) - DeleteTd(db, hash, number) -} - -// DeleteBlockReceipts removes all receipt data associated with a block hash. -func DeleteBlockReceipts(db DatabaseDeleter, hash common.Hash, number uint64) { - db.Delete(append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash.Bytes()...)) -} - -// DeleteTxLookupEntry removes all transaction data associated with a hash. -func DeleteTxLookupEntry(db DatabaseDeleter, hash common.Hash) { - db.Delete(append(lookupPrefix, hash.Bytes()...)) -} - -// PreimageTable returns a Database instance with the key prefix for preimage entries. -func PreimageTable(db ethdb.Database) ethdb.Database { - return ethdb.NewTable(db, preimagePrefix) -} - -// WritePreimages writes the provided set of preimages to the database. `number` is the -// current block number, and is used for debug messages only. -func WritePreimages(db ethdb.Database, number uint64, preimages map[common.Hash][]byte) error { - table := PreimageTable(db) - batch := table.NewBatch() - hitCount := 0 - for hash, preimage := range preimages { - if _, err := table.Get(hash.Bytes()); err != nil { - batch.Put(hash.Bytes(), preimage) - hitCount++ - } - } - preimageCounter.Inc(int64(len(preimages))) - preimageHitCounter.Inc(int64(hitCount)) - if hitCount > 0 { - if err := batch.Write(); err != nil { - return fmt.Errorf("preimage write fail for block %d: %v", number, err) - } - } - return nil -} - -// GetBlockChainVersion reads the version number from db. -func GetBlockChainVersion(db DatabaseReader) int { - var vsn uint - enc, _ := db.Get([]byte("BlockchainVersion")) - rlp.DecodeBytes(enc, &vsn) - return int(vsn) -} - -// WriteBlockChainVersion writes vsn as the version number to db. -func WriteBlockChainVersion(db ethdb.Putter, vsn int) { - enc, _ := rlp.EncodeToBytes(uint(vsn)) - db.Put([]byte("BlockchainVersion"), enc) -} - -// WriteChainConfig writes the chain config settings to the database. -func WriteChainConfig(db ethdb.Putter, hash common.Hash, cfg *params.ChainConfig) error { - // short circuit and ignore if nil config. GetChainConfig - // will return a default. - if cfg == nil { - return nil - } - - jsonChainConfig, err := json.Marshal(cfg) - if err != nil { - return err - } - - return db.Put(append(configPrefix, hash[:]...), jsonChainConfig) -} - -// GetChainConfig will fetch the network settings based on the given hash. -func GetChainConfig(db DatabaseReader, hash common.Hash) (*params.ChainConfig, error) { - jsonChainConfig, _ := db.Get(append(configPrefix, hash[:]...)) - if len(jsonChainConfig) == 0 { - return nil, ErrChainConfigNotFound - } - - var config params.ChainConfig - if err := json.Unmarshal(jsonChainConfig, &config); err != nil { - return nil, err - } - - return &config, nil -} - -// FindCommonAncestor returns the last common ancestor of two block headers -func FindCommonAncestor(db DatabaseReader, a, b *types.Header) *types.Header { - for bn := b.Number.Uint64(); a.Number.Uint64() > bn; { - a = GetHeader(db, a.ParentHash, a.Number.Uint64()-1) - if a == nil { - return nil - } - } - for an := a.Number.Uint64(); an < b.Number.Uint64(); { - b = GetHeader(db, b.ParentHash, b.Number.Uint64()-1) - if b == nil { - return nil - } - } - for a.Hash() != b.Hash() { - a = GetHeader(db, a.ParentHash, a.Number.Uint64()-1) - if a == nil { - return nil - } - b = GetHeader(db, b.ParentHash, b.Number.Uint64()-1) - if b == nil { - return nil - } - } - return a -} diff --git a/core/events.go b/core/events.go index 6f404f612b..710bdb5894 100644 --- a/core/events.go +++ b/core/events.go @@ -21,23 +21,17 @@ import ( "github.com/ethereum/go-ethereum/core/types" ) -// TxPreEvent is posted when a transaction enters the transaction pool. -type TxPreEvent struct{ Tx *types.Transaction } +// NewTxsEvent is posted when a batch of transactions enter the transaction pool. +type NewTxsEvent struct{ Txs []*types.Transaction } // PendingLogsEvent is posted pre mining and notifies of pending logs. type PendingLogsEvent struct { Logs []*types.Log } -// PendingStateEvent is posted pre mining and notifies of pending state changes. -type PendingStateEvent struct{} - // NewMinedBlockEvent is posted when a block has been imported. type NewMinedBlockEvent struct{ Block *types.Block } -// RemovedTransactionEvent is posted when a reorg happens -type RemovedTransactionEvent struct{ Txs types.Transactions } - // RemovedLogsEvent is posted when a reorg happens type RemovedLogsEvent struct{ Logs []*types.Log } diff --git a/core/evm.go b/core/evm.go index 55db53927b..d303c40a40 100644 --- a/core/evm.go +++ b/core/evm.go @@ -60,18 +60,31 @@ func NewEVMContext(msg Message, header *types.Header, chain ChainContext, author // GetHashFn returns a GetHashFunc which retrieves header hashes by number func GetHashFn(ref *types.Header, chain ChainContext) func(n uint64) common.Hash { + var cache map[uint64]common.Hash + return func(n uint64) common.Hash { - for header := chain.GetHeader(ref.ParentHash, ref.Number.Uint64()-1); header != nil; header = chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) { - if header.Number.Uint64() == n { - return header.Hash() + // If there's no hash cache yet, make one + if cache == nil { + cache = map[uint64]common.Hash{ + ref.Number.Uint64() - 1: ref.ParentHash, + } + } + // Try to fulfill the request from the cache + if hash, ok := cache[n]; ok { + return hash + } + // Not cached, iterate the blocks and cache the hashes + for header := chain.GetHeader(ref.ParentHash, ref.Number.Uint64()-1); header != nil; header = chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) { + cache[header.Number.Uint64()-1] = header.ParentHash + if n == header.Number.Uint64()-1 { + return header.ParentHash } } - return common.Hash{} } } -// CanTransfer checks wether there are enough funds in the address' account to make a transfer. +// CanTransfer checks whether there are enough funds in the address' account to make a transfer. // This does not take the necessary gas in to account to make the transfer valid. func CanTransfer(db vm.StateDB, addr common.Address, amount *big.Int) bool { return db.GetBalance(addr).Cmp(amount) >= 0 diff --git a/core/genesis.go b/core/genesis.go index e22985b800..cbb6eecd28 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -28,6 +28,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/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" @@ -150,12 +151,14 @@ 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 := GetCanonicalHash(db, 0) + stored := rawdb.ReadCanonicalHash(db, 0) if (stored == common.Hash{}) { if genesis == nil { log.Info("Writing default main-net genesis block") @@ -169,23 +172,23 @@ func SetupGenesisBlock(db ethdb.Database, genesis *Genesis) (*params.ChainConfig // Check whether the genesis block is already written. if genesis != nil { - block, _ := genesis.ToBlock() - hash := block.Hash() + hash := genesis.ToBlock(nil).Hash() if hash != stored { - return genesis.Config, block.Hash(), &GenesisMismatchError{stored, hash} + return genesis.Config, hash, &GenesisMismatchError{stored, hash} } } // Get the existing chain configuration. newcfg := genesis.configOrDefault(stored) - storedcfg, err := GetChainConfig(db, stored) - if err != nil { - if err == ErrChainConfigNotFound { - // This case happens if a genesis write was interrupted. - log.Warn("Found genesis block without chain config") - err = WriteChainConfig(db, stored, newcfg) - } - return newcfg, stored, err + 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") + rawdb.WriteChainConfig(db, stored, newcfg) + return newcfg, stored, nil } // Special case: don't change the existing config of a non-mainnet chain if no new // config is supplied. These chains would get AllProtocolChanges (and a compat error) @@ -196,15 +199,16 @@ func SetupGenesisBlock(db ethdb.Database, genesis *Genesis) (*params.ChainConfig // Check config compatibility and write the config. Compatibility errors // are returned to the caller unless we're already at block zero. - height := GetBlockNumber(db, GetHeadHeaderHash(db)) - if height == missingNumber { + height := rawdb.ReadHeaderNumber(db, rawdb.ReadHeadHeaderHash(db)) + if height == nil { return newcfg, stored, fmt.Errorf("missing block number for head header hash") } - compatErr := storedcfg.CheckCompatible(newcfg, height) - if compatErr != nil && height != 0 && compatErr.RewindTo != 0 { + compatErr := storedcfg.CheckCompatible(newcfg, *height) + if compatErr != nil && *height != 0 && compatErr.RewindTo != 0 { return newcfg, stored, compatErr } - return newcfg, stored, WriteChainConfig(db, stored, newcfg) + rawdb.WriteChainConfig(db, stored, newcfg) + return newcfg, stored, nil } func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig { @@ -220,9 +224,12 @@ func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig { } } -// ToBlock creates the block and state of a genesis specification. -func (g *Genesis) ToBlock() (*types.Block, *state.StateDB) { - db, _ := ethdb.NewMemDatabase() +// ToBlock creates the genesis block and writes state of a genesis specification +// to the given database (or discards it if nil). +func (g *Genesis) ToBlock(db ethdb.Database) *types.Block { + if db == nil { + db = ethdb.NewMemDatabase() + } statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) for addr, account := range g.Alloc { statedb.AddBalance(addr, account.Balance) @@ -252,42 +259,32 @@ func (g *Genesis) ToBlock() (*types.Block, *state.StateDB) { if g.Difficulty == nil { head.Difficulty = params.GenesisDifficulty } - return types.NewBlock(head, nil, nil, nil), statedb + statedb.Commit(false) + statedb.Database().TrieDB().Commit(root, true) + + return types.NewBlock(head, nil, nil, nil) } // Commit writes the block and state of a genesis specification to the database. // The block is committed as the canonical head block. func (g *Genesis) Commit(db ethdb.Database) (*types.Block, error) { - block, statedb := g.ToBlock() + block := g.ToBlock(db) if block.Number().Sign() != 0 { return nil, fmt.Errorf("can't commit genesis block with number > 0") } - if _, err := statedb.CommitTo(db, false); err != nil { - return nil, fmt.Errorf("cannot write state: %v", err) - } - if err := WriteTd(db, block.Hash(), block.NumberU64(), g.Difficulty); err != nil { - return nil, err - } - if err := WriteBlock(db, block); err != nil { - return nil, err - } - if err := WriteBlockReceipts(db, block.Hash(), block.NumberU64(), nil); err != nil { - return nil, err - } - if err := WriteCanonicalHash(db, block.Hash(), block.NumberU64()); err != nil { - return nil, err - } - if err := WriteHeadBlockHash(db, block.Hash()); err != nil { - return nil, err - } - if err := WriteHeadHeaderHash(db, block.Hash()); err != nil { - return nil, err - } + rawdb.WriteTd(db, block.Hash(), block.NumberU64(), g.Difficulty) + rawdb.WriteBlock(db, block) + rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), nil) + rawdb.WriteCanonicalHash(db, block.Hash(), block.NumberU64()) + rawdb.WriteHeadBlockHash(db, block.Hash()) + rawdb.WriteHeadHeaderHash(db, block.Hash()) + config := g.Config if config == nil { config = params.AllEthashProtocolChanges } - return block, WriteChainConfig(db, block.Hash(), config) + rawdb.WriteChainConfig(db, block.Hash(), config) + return block, nil } // MustCommit writes the genesis block and state to db, panicking on error. @@ -342,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 { @@ -364,7 +373,7 @@ func DeveloperGenesisBlock(period uint64, faucet common.Address) *Genesis { common.BytesToAddress([]byte{6}): {Balance: big.NewInt(1)}, // ECAdd common.BytesToAddress([]byte{7}): {Balance: big.NewInt(1)}, // ECScalarMul common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing - faucet: {Balance: new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(9))}, + faucet: {Balance: new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(9))}, }, } } diff --git a/core/genesis_alloc.go b/core/genesis_alloc.go index 4cb7d6839f..81477a6f6b 100644 --- a/core/genesis_alloc.go +++ b/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/core/genesis_test.go b/core/genesis_test.go index 2fe931b244..c7d54f2057 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -24,17 +24,18 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/ethereum/go-ethereum/common" "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" ) func TestDefaultGenesisBlock(t *testing.T) { - block, _ := DefaultGenesisBlock().ToBlock() + block := DefaultGenesisBlock().ToBlock(nil) if block.Hash() != params.MainnetGenesisHash { t.Errorf("wrong mainnet genesis hash, got %v, want %v", block.Hash(), params.MainnetGenesisHash) } - block, _ = DefaultTestnetGenesisBlock().ToBlock() + block = DefaultTestnetGenesisBlock().ToBlock(nil) if block.Hash() != params.TestnetGenesisHash { t.Errorf("wrong testnet genesis hash, got %v, want %v", block.Hash(), params.TestnetGenesisHash) } @@ -118,10 +119,12 @@ func TestSetupGenesis(t *testing.T) { // Commit the 'old' genesis block with Homestead transition at #2. // Advance to block #4, past the homestead transition block of customg. genesis := oldcustomg.MustCommit(db) - bc, _ := NewBlockChain(db, oldcustomg.Config, ethash.NewFullFaker(), vm.Config{}) + + bc, _ := NewBlockChain(db, nil, oldcustomg.Config, ethash.NewFullFaker(), vm.Config{}, nil) defer bc.Stop() - bc.SetValidator(bproc{}) - bc.InsertChain(makeBlockChainWithDiff(genesis, []int{2, 3, 4, 5}, 0)) + + blocks, _ := GenerateChain(oldcustomg.Config, genesis, ethash.NewFaker(), db, 4, nil) + bc.InsertChain(blocks) bc.CurrentBlock() // This should return a compatibility error. return SetupGenesisBlock(db, &customg) @@ -138,7 +141,7 @@ func TestSetupGenesis(t *testing.T) { } for _, test := range tests { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() config, hash, err := test.fn(db) // Check the return values. if !reflect.DeepEqual(err, test.wantErr) { @@ -152,7 +155,7 @@ func TestSetupGenesis(t *testing.T) { t.Errorf("%s: returned hash %s, want %s", test.name, hash.Hex(), test.wantHash.Hex()) } else if err == nil { // Check database content. - stored := GetBlock(db, test.wantHash, 0) + stored := rawdb.ReadBlock(db, test.wantHash, 0) if stored.Hash() != test.wantHash { t.Errorf("%s: block in DB has hash %s, want %s", test.name, stored.Hash(), test.wantHash) } diff --git a/core/headerchain.go b/core/headerchain.go index 0e5215293d..8904dd887b 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -23,10 +23,12 @@ import ( "math" "math/big" mrand "math/rand" + "sync/atomic" "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" + "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/log" @@ -51,8 +53,8 @@ type HeaderChain struct { chainDb ethdb.Database genesisHeader *types.Header - currentHeader *types.Header // Current head of the header chain (may be above the block chain!) - currentHeaderHash common.Hash // Hash of the current head of the header chain (prevent recomputing all the time) + currentHeader atomic.Value // Current head of the header chain (may be above the block chain!) + currentHeaderHash common.Hash // Hash of the current head of the header chain (prevent recomputing all the time) headerCache *lru.Cache // Cache for the most recent block headers tdCache *lru.Cache // Cache for the most recent block total difficulties @@ -95,26 +97,27 @@ func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, engine c return nil, ErrNoGenesis } - hc.currentHeader = hc.genesisHeader - if head := GetHeadBlockHash(chainDb); head != (common.Hash{}) { + hc.currentHeader.Store(hc.genesisHeader) + if head := rawdb.ReadHeadBlockHash(chainDb); head != (common.Hash{}) { if chead := hc.GetHeaderByHash(head); chead != nil { - hc.currentHeader = chead + hc.currentHeader.Store(chead) } } - hc.currentHeaderHash = hc.currentHeader.Hash() + hc.currentHeaderHash = hc.CurrentHeader().Hash() return hc, nil } // GetBlockNumber retrieves the block number belonging to the given hash // from the cache or database -func (hc *HeaderChain) GetBlockNumber(hash common.Hash) uint64 { +func (hc *HeaderChain) GetBlockNumber(hash common.Hash) *uint64 { if cached, ok := hc.numberCache.Get(hash); ok { - return cached.(uint64) + number := cached.(uint64) + return &number } - number := GetBlockNumber(hc.chainDb, hash) - if number != missingNumber { - hc.numberCache.Add(hash, number) + number := rawdb.ReadHeaderNumber(hc.chainDb, hash) + if number != nil { + hc.numberCache.Add(hash, *number) } return number } @@ -139,49 +142,49 @@ func (hc *HeaderChain) WriteHeader(header *types.Header) (status WriteStatus, er if ptd == nil { return NonStatTy, consensus.ErrUnknownAncestor } - localTd := hc.GetTd(hc.currentHeaderHash, hc.currentHeader.Number.Uint64()) + localTd := hc.GetTd(hc.currentHeaderHash, hc.CurrentHeader().Number.Uint64()) externTd := new(big.Int).Add(header.Difficulty, ptd) // Irrelevant of the canonical status, write the td and header to the database if err := hc.WriteTd(hash, number, externTd); err != nil { log.Crit("Failed to write header total difficulty", "err", err) } - if err := WriteHeader(hc.chainDb, header); err != nil { - log.Crit("Failed to write header content", "err", err) - } + rawdb.WriteHeader(hc.chainDb, header) + // If the total difficulty is higher than our known, add it to the canonical chain // Second clause in the if statement reduces the vulnerability to selfish mining. // Please refer to http://www.cs.cornell.edu/~ie53/publications/btcProcFC.pdf if externTd.Cmp(localTd) > 0 || (externTd.Cmp(localTd) == 0 && mrand.Float64() < 0.5) { // Delete any canonical number assignments above the new head + batch := hc.chainDb.NewBatch() for i := number + 1; ; i++ { - hash := GetCanonicalHash(hc.chainDb, i) + hash := rawdb.ReadCanonicalHash(hc.chainDb, i) if hash == (common.Hash{}) { break } - DeleteCanonicalHash(hc.chainDb, i) + rawdb.DeleteCanonicalHash(batch, i) } + batch.Write() + // Overwrite any stale canonical number assignments var ( headHash = header.ParentHash headNumber = header.Number.Uint64() - 1 headHeader = hc.GetHeader(headHash, headNumber) ) - for GetCanonicalHash(hc.chainDb, headNumber) != headHash { - WriteCanonicalHash(hc.chainDb, headHash, headNumber) + for rawdb.ReadCanonicalHash(hc.chainDb, headNumber) != headHash { + rawdb.WriteCanonicalHash(hc.chainDb, headHash, headNumber) headHash = headHeader.ParentHash headNumber = headHeader.Number.Uint64() - 1 headHeader = hc.GetHeader(headHash, headNumber) } // Extend the canonical chain with the new header - if err := WriteCanonicalHash(hc.chainDb, hash, number); err != nil { - log.Crit("Failed to insert header number", "err", err) - } - if err := WriteHeadHeaderHash(hc.chainDb, hash); err != nil { - log.Crit("Failed to insert head header hash", "err", err) - } - hc.currentHeaderHash, hc.currentHeader = hash, types.CopyHeader(header) + rawdb.WriteCanonicalHash(hc.chainDb, hash, number) + rawdb.WriteHeadHeaderHash(hc.chainDb, hash) + + hc.currentHeaderHash = hash + hc.currentHeader.Store(types.CopyHeader(header)) status = CanonStatTy } else { @@ -205,7 +208,7 @@ func (hc *HeaderChain) ValidateHeaderChain(chain []*types.Header, checkFreq int) // Do a sanity check that the provided chain is actually ordered and linked for i := 1; i < len(chain); i++ { if chain[i].Number.Uint64() != chain[i-1].Number.Uint64()+1 || chain[i].ParentHash != chain[i-1].Hash() { - // Chain broke ancestry, log a messge (programming error) and skip insertion + // Chain broke ancestry, log a message (programming error) and skip insertion log.Error("Non contiguous header insert", "number", chain[i].Number, "hash", chain[i].Hash(), "parent", chain[i].ParentHash, "prevnumber", chain[i-1].Number, "prevhash", chain[i-1].Hash()) @@ -216,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) @@ -278,8 +285,18 @@ func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, writeHeader WhCa } // Report some public statistics so the user has a clue what's going on last := chain[len(chain)-1] - log.Info("Imported new block headers", "count", stats.processed, "elapsed", common.PrettyDuration(time.Since(start)), - "number", last.Number, "hash", last.Hash(), "ignored", stats.ignored) + + context := []interface{}{ + "count", stats.processed, "elapsed", common.PrettyDuration(time.Since(start)), + "number", last.Number, "hash", last.Hash(), + } + if timestamp := time.Unix(last.Time.Int64(), 0); time.Since(timestamp) > time.Minute { + context = append(context, []interface{}{"age", common.PrettyAge(timestamp)}...) + } + if stats.ignored > 0 { + context = append(context, []interface{}{"ignored", stats.ignored}...) + } + log.Info("Imported new block headers", context...) return 0, nil } @@ -307,6 +324,43 @@ func (hc *HeaderChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []co return chain } +// GetAncestor retrieves the Nth ancestor of a given block. It assumes that either the given block or +// a close ancestor of it is canonical. maxNonCanonical points to a downwards counter limiting the +// 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 (hc *HeaderChain) GetAncestor(hash common.Hash, number, ancestor uint64, maxNonCanonical *uint64) (common.Hash, uint64) { + if ancestor > number { + return common.Hash{}, 0 + } + if ancestor == 1 { + // in this case it is cheaper to just read the header + if header := hc.GetHeader(hash, number); header != nil { + return header.ParentHash, number - 1 + } else { + return common.Hash{}, 0 + } + } + for ancestor != 0 { + if rawdb.ReadCanonicalHash(hc.chainDb, number) == hash { + number -= ancestor + return rawdb.ReadCanonicalHash(hc.chainDb, number), number + } + if *maxNonCanonical == 0 { + return common.Hash{}, 0 + } + *maxNonCanonical-- + ancestor-- + header := hc.GetHeader(hash, number) + if header == nil { + return common.Hash{}, 0 + } + hash = header.ParentHash + number-- + } + return hash, number +} + // GetTd retrieves a block's total difficulty in the canonical chain from the // database by hash and number, caching it if found. func (hc *HeaderChain) GetTd(hash common.Hash, number uint64) *big.Int { @@ -314,7 +368,7 @@ func (hc *HeaderChain) GetTd(hash common.Hash, number uint64) *big.Int { if cached, ok := hc.tdCache.Get(hash); ok { return cached.(*big.Int) } - td := GetTd(hc.chainDb, hash, number) + td := rawdb.ReadTd(hc.chainDb, hash, number) if td == nil { return nil } @@ -326,15 +380,17 @@ func (hc *HeaderChain) GetTd(hash common.Hash, number uint64) *big.Int { // GetTdByHash retrieves a block's total difficulty in the canonical chain from the // database by hash, caching it if found. func (hc *HeaderChain) GetTdByHash(hash common.Hash) *big.Int { - return hc.GetTd(hash, hc.GetBlockNumber(hash)) + number := hc.GetBlockNumber(hash) + if number == nil { + return nil + } + return hc.GetTd(hash, *number) } // WriteTd stores a block's total difficulty into the database, also caching it // along the way. func (hc *HeaderChain) WriteTd(hash common.Hash, number uint64, td *big.Int) error { - if err := WriteTd(hc.chainDb, hash, number, td); err != nil { - return err - } + rawdb.WriteTd(hc.chainDb, hash, number, td) hc.tdCache.Add(hash, new(big.Int).Set(td)) return nil } @@ -346,7 +402,7 @@ func (hc *HeaderChain) GetHeader(hash common.Hash, number uint64) *types.Header if header, ok := hc.headerCache.Get(hash); ok { return header.(*types.Header) } - header := GetHeader(hc.chainDb, hash, number) + header := rawdb.ReadHeader(hc.chainDb, hash, number) if header == nil { return nil } @@ -358,7 +414,11 @@ func (hc *HeaderChain) GetHeader(hash common.Hash, number uint64) *types.Header // GetHeaderByHash retrieves a block header from the database by hash, caching it if // found. func (hc *HeaderChain) GetHeaderByHash(hash common.Hash) *types.Header { - return hc.GetHeader(hash, hc.GetBlockNumber(hash)) + number := hc.GetBlockNumber(hash) + if number == nil { + return nil + } + return hc.GetHeader(hash, *number) } // HasHeader checks if a block header is present in the database or not. @@ -366,14 +426,13 @@ func (hc *HeaderChain) HasHeader(hash common.Hash, number uint64) bool { if hc.numberCache.Contains(hash) || hc.headerCache.Contains(hash) { return true } - ok, _ := hc.chainDb.Has(headerKey(hash, number)) - return ok + return rawdb.HasHeader(hc.chainDb, hash, number) } // GetHeaderByNumber retrieves a block header from the database by number, // caching it (associated with its hash) if found. func (hc *HeaderChain) GetHeaderByNumber(number uint64) *types.Header { - hash := GetCanonicalHash(hc.chainDb, number) + hash := rawdb.ReadCanonicalHash(hc.chainDb, number) if hash == (common.Hash{}) { return nil } @@ -383,57 +442,58 @@ func (hc *HeaderChain) GetHeaderByNumber(number uint64) *types.Header { // CurrentHeader retrieves the current head header of the canonical chain. The // header is retrieved from the HeaderChain's internal cache. func (hc *HeaderChain) CurrentHeader() *types.Header { - return hc.currentHeader + return hc.currentHeader.Load().(*types.Header) } // SetCurrentHeader sets the current head header of the canonical chain. func (hc *HeaderChain) SetCurrentHeader(head *types.Header) { - if err := WriteHeadHeaderHash(hc.chainDb, head.Hash()); err != nil { - log.Crit("Failed to insert head header hash", "err", err) - } - hc.currentHeader = head + rawdb.WriteHeadHeaderHash(hc.chainDb, head.Hash()) + + hc.currentHeader.Store(head) hc.currentHeaderHash = head.Hash() } // DeleteCallback is a callback function that is called by SetHead before // each header is deleted. -type DeleteCallback func(common.Hash, uint64) +type DeleteCallback func(rawdb.DatabaseDeleter, 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. func (hc *HeaderChain) SetHead(head uint64, delFn DeleteCallback) { height := uint64(0) - if hc.currentHeader != nil { - height = hc.currentHeader.Number.Uint64() - } - for hc.currentHeader != nil && hc.currentHeader.Number.Uint64() > head { - hash := hc.currentHeader.Hash() - num := hc.currentHeader.Number.Uint64() + if hdr := hc.CurrentHeader(); hdr != nil { + height = hdr.Number.Uint64() + } + batch := hc.chainDb.NewBatch() + for hdr := hc.CurrentHeader(); hdr != nil && hdr.Number.Uint64() > head; hdr = hc.CurrentHeader() { + hash := hdr.Hash() + num := hdr.Number.Uint64() if delFn != nil { - delFn(hash, num) + delFn(batch, hash, num) } - DeleteHeader(hc.chainDb, hash, num) - DeleteTd(hc.chainDb, hash, num) - hc.currentHeader = hc.GetHeader(hc.currentHeader.ParentHash, hc.currentHeader.Number.Uint64()-1) + rawdb.DeleteHeader(batch, hash, num) + rawdb.DeleteTd(batch, hash, num) + + hc.currentHeader.Store(hc.GetHeader(hdr.ParentHash, hdr.Number.Uint64()-1)) } // Roll back the canonical chain numbering for i := height; i > head; i-- { - DeleteCanonicalHash(hc.chainDb, i) + rawdb.DeleteCanonicalHash(batch, i) } + batch.Write() + // Clear out any stale content from the caches hc.headerCache.Purge() hc.tdCache.Purge() hc.numberCache.Purge() - if hc.currentHeader == nil { - hc.currentHeader = hc.genesisHeader + if hc.CurrentHeader() == nil { + hc.currentHeader.Store(hc.genesisHeader) } - hc.currentHeaderHash = hc.currentHeader.Hash() + hc.currentHeaderHash = hc.CurrentHeader().Hash() - if err := WriteHeadHeaderHash(hc.chainDb, hc.currentHeaderHash); err != nil { - log.Crit("Failed to reset head header hash", "err", err) - } + rawdb.WriteHeadHeaderHash(hc.chainDb, hc.currentHeaderHash) } // SetGenesis sets a new genesis block header for the chain diff --git a/core/helper_test.go b/core/helper_test.go index 698a2924cb..051384d854 100644 --- a/core/helper_test.go +++ b/core/helper_test.go @@ -18,7 +18,6 @@ package core import ( "container/list" - "fmt" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" @@ -77,18 +76,11 @@ func (tm *TestManager) Db() ethdb.Database { } func NewTestManager() *TestManager { - db, err := ethdb.NewMemDatabase() - if err != nil { - fmt.Println("Could not create mem-db, failing") - return nil - } - testManager := &TestManager{} testManager.eventMux = new(event.TypeMux) - testManager.db = db + testManager.db = ethdb.NewMemDatabase() // testManager.txPool = NewTxPool(testManager) // testManager.blockChain = NewBlockChain(testManager) // testManager.stateManager = NewStateManager(testManager) - return testManager } diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go new file mode 100644 index 0000000000..8a95dafe95 --- /dev/null +++ b/core/rawdb/accessors_chain.go @@ -0,0 +1,394 @@ +// 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 ( + "bytes" + "encoding/binary" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "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 { + data, _ := db.Get(headerHashKey(number)) + if len(data) == 0 { + return common.Hash{} + } + return common.BytesToHash(data) +} + +// WriteCanonicalHash stores the hash assigned to a canonical block number. +func WriteCanonicalHash(db DatabaseWriter, 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) { + 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 { + data, _ := db.Get(headerNumberKey(hash)) + if len(data) != 8 { + return nil + } + number := binary.BigEndian.Uint64(data) + return &number +} + +// ReadHeadHeaderHash retrieves the hash of the current canonical head header. +func ReadHeadHeaderHash(db DatabaseReader) common.Hash { + data, _ := db.Get(headHeaderKey) + if len(data) == 0 { + return common.Hash{} + } + return common.BytesToHash(data) +} + +// WriteHeadHeaderHash stores the hash of the current canonical head header. +func WriteHeadHeaderHash(db DatabaseWriter, 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 { + data, _ := db.Get(headBlockKey) + if len(data) == 0 { + return common.Hash{} + } + return common.BytesToHash(data) +} + +// WriteHeadBlockHash stores the head block's hash. +func WriteHeadBlockHash(db DatabaseWriter, 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 { + data, _ := db.Get(headFastBlockKey) + if len(data) == 0 { + return common.Hash{} + } + return common.BytesToHash(data) +} + +// WriteHeadFastBlockHash stores the hash of the current fast-sync head block. +func WriteHeadFastBlockHash(db DatabaseWriter, hash common.Hash) { + if err := db.Put(headFastBlockKey, hash.Bytes()); err != nil { + log.Crit("Failed to store last fast block's hash", "err", err) + } +} + +// ReadFastTrieProgress retrieves the number of tries nodes fast synced to allow +// reporting correct numbers across restarts. +func ReadFastTrieProgress(db DatabaseReader) uint64 { + data, _ := db.Get(fastTrieProgressKey) + if len(data) == 0 { + return 0 + } + return new(big.Int).SetBytes(data).Uint64() +} + +// WriteFastTrieProgress stores the fast sync trie process counter to support +// retrieving it across restarts. +func WriteFastTrieProgress(db DatabaseWriter, 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 { + 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 { + if has, err := db.Has(headerKey(number, hash)); !has || err != nil { + return false + } + return true +} + +// ReadHeader retrieves the block header corresponding to the hash. +func ReadHeader(db DatabaseReader, hash common.Hash, number uint64) *types.Header { + data := ReadHeaderRLP(db, hash, number) + if len(data) == 0 { + return nil + } + header := new(types.Header) + if err := rlp.Decode(bytes.NewReader(data), header); err != nil { + log.Error("Invalid block header RLP", "hash", hash, "err", err) + return nil + } + return header +} + +// WriteHeader stores a block header into the database and also stores the hash- +// to-number mapping. +func WriteHeader(db DatabaseWriter, header *types.Header) { + // Write the hash -> number mapping + var ( + hash = header.Hash() + number = header.Number.Uint64() + encoded = encodeBlockNumber(number) + ) + key := headerNumberKey(hash) + if err := db.Put(key, encoded); err != nil { + log.Crit("Failed to store hash to number mapping", "err", err) + } + // Write the encoded header + data, err := rlp.EncodeToBytes(header) + if err != nil { + log.Crit("Failed to RLP encode header", "err", err) + } + key = headerKey(number, hash) + if err := db.Put(key, data); err != nil { + log.Crit("Failed to store header", "err", err) + } +} + +// 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) + } + if err := db.Delete(headerNumberKey(hash)); err != nil { + log.Crit("Failed to delete hash to number mapping", "err", err) + } +} + +// ReadBodyRLP retrieves the block body (transactions and uncles) in RLP encoding. +func ReadBodyRLP(db DatabaseReader, 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) { + 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 { + if has, err := db.Has(blockBodyKey(number, hash)); !has || err != nil { + return false + } + return true +} + +// ReadBody retrieves the block body corresponding to the hash. +func ReadBody(db DatabaseReader, hash common.Hash, number uint64) *types.Body { + data := ReadBodyRLP(db, hash, number) + if len(data) == 0 { + return nil + } + body := new(types.Body) + if err := rlp.Decode(bytes.NewReader(data), body); err != nil { + log.Error("Invalid block body RLP", "hash", hash, "err", err) + return nil + } + return body +} + +// WriteBody storea a block body into the database. +func WriteBody(db DatabaseWriter, 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) + } + WriteBodyRLP(db, hash, number, data) +} + +// DeleteBody removes all block body data associated with a hash. +func DeleteBody(db DatabaseDeleter, 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 { + data, _ := db.Get(headerTDKey(number, hash)) + if len(data) == 0 { + return nil + } + td := new(big.Int) + if err := rlp.Decode(bytes.NewReader(data), td); err != nil { + log.Error("Invalid block total difficulty RLP", "hash", hash, "err", err) + return nil + } + return td +} + +// WriteTd stores the total difficulty of a block into the database. +func WriteTd(db DatabaseWriter, 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) + } + if err := db.Put(headerTDKey(number, hash), data); err != nil { + log.Crit("Failed to store block total difficulty", "err", err) + } +} + +// DeleteTd removes all block total difficulty data associated with a hash. +func DeleteTd(db DatabaseDeleter, hash common.Hash, number uint64) { + if err := db.Delete(headerTDKey(number, hash)); err != nil { + log.Crit("Failed to delete block total difficulty", "err", err) + } +} + +// HasReceipts verifies the existence of all the transaction receipts belonging +// to a block. +func HasReceipts(db DatabaseReader, hash common.Hash, number uint64) bool { + if has, err := db.Has(blockReceiptsKey(number, hash)); !has || err != nil { + return false + } + return true +} + +// 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 + data, _ := db.Get(blockReceiptsKey(number, hash)) + if len(data) == 0 { + return nil + } + // Convert the receipts from their storage form to their internal representation + storageReceipts := []*types.ReceiptForStorage{} + if err := rlp.DecodeBytes(data, &storageReceipts); err != nil { + log.Error("Invalid receipt array RLP", "hash", hash, "err", err) + 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) + } + return receipts +} + +// WriteReceipts stores all the transaction receipts belonging to a block. +func WriteReceipts(db DatabaseWriter, 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 { + storageReceipts[i] = (*types.ReceiptForStorage)(receipt) + } + bytes, err := rlp.EncodeToBytes(storageReceipts) + if err != nil { + log.Crit("Failed to encode block receipts", "err", err) + } + // Store the flattened receipt slice + if err := db.Put(blockReceiptsKey(number, hash), bytes); err != nil { + log.Crit("Failed to store block receipts", "err", err) + } +} + +// DeleteReceipts removes all receipt data associated with a block hash. +func DeleteReceipts(db DatabaseDeleter, hash common.Hash, number uint64) { + if err := db.Delete(blockReceiptsKey(number, hash)); err != nil { + log.Crit("Failed to delete block receipts", "err", err) + } +} + +// ReadBlock retrieves an entire block corresponding to the hash, assembling it +// back from the stored header and body. If either the header or body could not +// be retrieved nil is returned. +// +// 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 { + header := ReadHeader(db, hash, number) + if header == nil { + return nil + } + body := ReadBody(db, hash, number) + if body == nil { + return nil + } + return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles) +} + +// WriteBlock serializes a block into the database, header and body separately. +func WriteBlock(db DatabaseWriter, 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) { + DeleteReceipts(db, hash, number) + DeleteHeader(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 { + for bn := b.Number.Uint64(); a.Number.Uint64() > bn; { + a = ReadHeader(db, a.ParentHash, a.Number.Uint64()-1) + if a == nil { + return nil + } + } + for an := a.Number.Uint64(); an < b.Number.Uint64(); { + b = ReadHeader(db, b.ParentHash, b.Number.Uint64()-1) + if b == nil { + return nil + } + } + for a.Hash() != b.Hash() { + a = ReadHeader(db, a.ParentHash, a.Number.Uint64()-1) + if a == nil { + return nil + } + b = ReadHeader(db, b.ParentHash, b.Number.Uint64()-1) + if b == nil { + return nil + } + } + return a +} diff --git a/core/database_util_test.go b/core/rawdb/accessors_chain_test.go similarity index 58% rename from core/database_util_test.go rename to core/rawdb/accessors_chain_test.go index ab4e45a478..37e0d4fda1 100644 --- a/core/database_util_test.go +++ b/core/rawdb/accessors_chain_test.go @@ -1,4 +1,4 @@ -// Copyright 2015 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,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 core +package rawdb import ( "bytes" @@ -23,33 +23,31 @@ 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 := ethdb.NewMemDatabase() // 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")} - if entry := GetHeader(db, header.Hash(), header.Number.Uint64()); entry != nil { + if entry := ReadHeader(db, header.Hash(), header.Number.Uint64()); entry != nil { t.Fatalf("Non existent header returned: %v", entry) } // Write and verify the header in the database - if err := WriteHeader(db, header); err != nil { - t.Fatalf("Failed to write header into database: %v", err) - } - if entry := GetHeader(db, header.Hash(), header.Number.Uint64()); entry == nil { + WriteHeader(db, header) + if entry := ReadHeader(db, header.Hash(), header.Number.Uint64()); entry == nil { t.Fatalf("Stored header not found") } else if entry.Hash() != header.Hash() { t.Fatalf("Retrieved header mismatch: have %v, want %v", entry, header) } - if entry := GetHeaderRLP(db, header.Hash(), header.Number.Uint64()); entry == nil { + 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() { @@ -58,38 +56,36 @@ func TestHeaderStorage(t *testing.T) { } // Delete the header and verify the execution DeleteHeader(db, header.Hash(), header.Number.Uint64()) - if entry := GetHeader(db, header.Hash(), header.Number.Uint64()); entry != nil { + if entry := ReadHeader(db, header.Hash(), header.Number.Uint64()); entry != nil { t.Fatalf("Deleted header returned: %v", entry) } } // Tests block body storage and retrieval operations. func TestBodyStorage(t *testing.T) { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() // 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)) - if entry := GetBody(db, hash, 0); entry != nil { + if entry := ReadBody(db, hash, 0); entry != nil { t.Fatalf("Non existent body returned: %v", entry) } // Write and verify the body in the database - if err := WriteBody(db, hash, 0, body); err != nil { - t.Fatalf("Failed to write body into database: %v", err) - } - if entry := GetBody(db, hash, 0); entry == nil { + WriteBody(db, hash, 0, body) + if entry := ReadBody(db, hash, 0); entry == nil { t.Fatalf("Stored body not found") } else if types.DeriveSha(types.Transactions(entry.Transactions)) != types.DeriveSha(types.Transactions(body.Transactions)) || types.CalcUncleHash(entry.Uncles) != types.CalcUncleHash(body.Uncles) { t.Fatalf("Retrieved body mismatch: have %v, want %v", entry, body) } - if entry := GetBodyRLP(db, hash, 0); entry == nil { + 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 { @@ -98,14 +94,14 @@ func TestBodyStorage(t *testing.T) { } // Delete the body and verify the execution DeleteBody(db, hash, 0) - if entry := GetBody(db, hash, 0); entry != nil { + if entry := ReadBody(db, hash, 0); entry != nil { t.Fatalf("Deleted body returned: %v", entry) } } // Tests block storage and retrieval operations. func TestBlockStorage(t *testing.T) { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() // Create a test block to move around the database and make sure it's really new block := types.NewBlockWithHeader(&types.Header{ @@ -114,50 +110,48 @@ func TestBlockStorage(t *testing.T) { TxHash: types.EmptyRootHash, ReceiptHash: types.EmptyRootHash, }) - if entry := GetBlock(db, block.Hash(), block.NumberU64()); entry != nil { + if entry := ReadBlock(db, block.Hash(), block.NumberU64()); entry != nil { t.Fatalf("Non existent block returned: %v", entry) } - if entry := GetHeader(db, block.Hash(), block.NumberU64()); entry != nil { + if entry := ReadHeader(db, block.Hash(), block.NumberU64()); entry != nil { t.Fatalf("Non existent header returned: %v", entry) } - if entry := GetBody(db, block.Hash(), block.NumberU64()); entry != nil { + if entry := ReadBody(db, block.Hash(), block.NumberU64()); entry != nil { t.Fatalf("Non existent body returned: %v", entry) } // Write and verify the block in the database - if err := WriteBlock(db, block); err != nil { - t.Fatalf("Failed to write block into database: %v", err) - } - if entry := GetBlock(db, block.Hash(), block.NumberU64()); entry == nil { + WriteBlock(db, block) + if entry := ReadBlock(db, block.Hash(), block.NumberU64()); entry == nil { t.Fatalf("Stored block not found") } else if entry.Hash() != block.Hash() { t.Fatalf("Retrieved block mismatch: have %v, want %v", entry, block) } - if entry := GetHeader(db, block.Hash(), block.NumberU64()); entry == nil { + if entry := ReadHeader(db, block.Hash(), block.NumberU64()); entry == nil { t.Fatalf("Stored header not found") } else if entry.Hash() != block.Header().Hash() { t.Fatalf("Retrieved header mismatch: have %v, want %v", entry, block.Header()) } - if entry := GetBody(db, block.Hash(), block.NumberU64()); entry == nil { + if entry := ReadBody(db, block.Hash(), block.NumberU64()); entry == nil { t.Fatalf("Stored body not found") } else if types.DeriveSha(types.Transactions(entry.Transactions)) != types.DeriveSha(block.Transactions()) || types.CalcUncleHash(entry.Uncles) != types.CalcUncleHash(block.Uncles()) { t.Fatalf("Retrieved body mismatch: have %v, want %v", entry, block.Body()) } // Delete the block and verify the execution DeleteBlock(db, block.Hash(), block.NumberU64()) - if entry := GetBlock(db, block.Hash(), block.NumberU64()); entry != nil { + if entry := ReadBlock(db, block.Hash(), block.NumberU64()); entry != nil { t.Fatalf("Deleted block returned: %v", entry) } - if entry := GetHeader(db, block.Hash(), block.NumberU64()); entry != nil { + if entry := ReadHeader(db, block.Hash(), block.NumberU64()); entry != nil { t.Fatalf("Deleted header returned: %v", entry) } - if entry := GetBody(db, block.Hash(), block.NumberU64()); entry != nil { + if entry := ReadBody(db, block.Hash(), block.NumberU64()); entry != nil { t.Fatalf("Deleted body returned: %v", entry) } } // Tests that partial block contents don't get reassembled into full blocks. func TestPartialBlockStorage(t *testing.T) { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() block := types.NewBlockWithHeader(&types.Header{ Extra: []byte("test block"), UncleHash: types.EmptyUncleHash, @@ -165,31 +159,24 @@ func TestPartialBlockStorage(t *testing.T) { ReceiptHash: types.EmptyRootHash, }) // Store a header and check that it's not recognized as a block - if err := WriteHeader(db, block.Header()); err != nil { - t.Fatalf("Failed to write header into database: %v", err) - } - if entry := GetBlock(db, block.Hash(), block.NumberU64()); entry != nil { + WriteHeader(db, block.Header()) + if entry := ReadBlock(db, block.Hash(), block.NumberU64()); entry != nil { t.Fatalf("Non existent block returned: %v", entry) } DeleteHeader(db, block.Hash(), block.NumberU64()) // Store a body and check that it's not recognized as a block - if err := WriteBody(db, block.Hash(), block.NumberU64(), block.Body()); err != nil { - t.Fatalf("Failed to write body into database: %v", err) - } - if entry := GetBlock(db, block.Hash(), block.NumberU64()); entry != nil { + WriteBody(db, block.Hash(), block.NumberU64(), block.Body()) + if entry := ReadBlock(db, block.Hash(), block.NumberU64()); entry != nil { t.Fatalf("Non existent block returned: %v", entry) } DeleteBody(db, block.Hash(), block.NumberU64()) // Store a header and a body separately and check reassembly - if err := WriteHeader(db, block.Header()); err != nil { - t.Fatalf("Failed to write header into database: %v", err) - } - if err := WriteBody(db, block.Hash(), block.NumberU64(), block.Body()); err != nil { - t.Fatalf("Failed to write body into database: %v", err) - } - if entry := GetBlock(db, block.Hash(), block.NumberU64()); entry == nil { + WriteHeader(db, block.Header()) + WriteBody(db, block.Hash(), block.NumberU64(), block.Body()) + + if entry := ReadBlock(db, block.Hash(), block.NumberU64()); entry == nil { t.Fatalf("Stored block not found") } else if entry.Hash() != block.Hash() { t.Fatalf("Retrieved block mismatch: have %v, want %v", entry, block) @@ -198,142 +185,88 @@ func TestPartialBlockStorage(t *testing.T) { // Tests block total difficulty storage and retrieval operations. func TestTdStorage(t *testing.T) { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() // Create a test TD to move around the database and make sure it's really new hash, td := common.Hash{}, big.NewInt(314) - if entry := GetTd(db, hash, 0); entry != nil { + if entry := ReadTd(db, hash, 0); entry != nil { t.Fatalf("Non existent TD returned: %v", entry) } // Write and verify the TD in the database - if err := WriteTd(db, hash, 0, td); err != nil { - t.Fatalf("Failed to write TD into database: %v", err) - } - if entry := GetTd(db, hash, 0); entry == nil { + WriteTd(db, hash, 0, td) + if entry := ReadTd(db, hash, 0); entry == nil { t.Fatalf("Stored TD not found") } else if entry.Cmp(td) != 0 { t.Fatalf("Retrieved TD mismatch: have %v, want %v", entry, td) } // Delete the TD and verify the execution DeleteTd(db, hash, 0) - if entry := GetTd(db, hash, 0); entry != nil { + if entry := ReadTd(db, hash, 0); entry != nil { t.Fatalf("Deleted TD returned: %v", entry) } } // Tests that canonical numbers can be mapped to hashes and retrieved. func TestCanonicalMappingStorage(t *testing.T) { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() // Create a test canonical number and assinged hash to move around hash, number := common.Hash{0: 0xff}, uint64(314) - if entry := GetCanonicalHash(db, number); entry != (common.Hash{}) { + if entry := ReadCanonicalHash(db, number); entry != (common.Hash{}) { t.Fatalf("Non existent canonical mapping returned: %v", entry) } // Write and verify the TD in the database - if err := WriteCanonicalHash(db, hash, number); err != nil { - t.Fatalf("Failed to write canonical mapping into database: %v", err) - } - if entry := GetCanonicalHash(db, number); entry == (common.Hash{}) { + WriteCanonicalHash(db, hash, number) + if entry := ReadCanonicalHash(db, number); entry == (common.Hash{}) { t.Fatalf("Stored canonical mapping not found") } else if entry != hash { t.Fatalf("Retrieved canonical mapping mismatch: have %v, want %v", entry, hash) } // Delete the TD and verify the execution DeleteCanonicalHash(db, number) - if entry := GetCanonicalHash(db, number); entry != (common.Hash{}) { + if entry := ReadCanonicalHash(db, number); entry != (common.Hash{}) { t.Fatalf("Deleted canonical mapping returned: %v", entry) } } // Tests that head headers and head blocks can be assigned, individually. func TestHeadStorage(t *testing.T) { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() blockHead := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block header")}) blockFull := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block full")}) blockFast := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block fast")}) // Check that no head entries are in a pristine database - if entry := GetHeadHeaderHash(db); entry != (common.Hash{}) { + if entry := ReadHeadHeaderHash(db); entry != (common.Hash{}) { t.Fatalf("Non head header entry returned: %v", entry) } - if entry := GetHeadBlockHash(db); entry != (common.Hash{}) { + if entry := ReadHeadBlockHash(db); entry != (common.Hash{}) { t.Fatalf("Non head block entry returned: %v", entry) } - if entry := GetHeadFastBlockHash(db); entry != (common.Hash{}) { + if entry := ReadHeadFastBlockHash(db); entry != (common.Hash{}) { t.Fatalf("Non fast head block entry returned: %v", entry) } // Assign separate entries for the head header and block - if err := WriteHeadHeaderHash(db, blockHead.Hash()); err != nil { - t.Fatalf("Failed to write head header hash: %v", err) - } - if err := WriteHeadBlockHash(db, blockFull.Hash()); err != nil { - t.Fatalf("Failed to write head block hash: %v", err) - } - if err := WriteHeadFastBlockHash(db, blockFast.Hash()); err != nil { - t.Fatalf("Failed to write fast head block hash: %v", err) - } + WriteHeadHeaderHash(db, blockHead.Hash()) + WriteHeadBlockHash(db, blockFull.Hash()) + WriteHeadFastBlockHash(db, blockFast.Hash()) + // Check that both heads are present, and different (i.e. two heads maintained) - if entry := GetHeadHeaderHash(db); entry != blockHead.Hash() { + if entry := ReadHeadHeaderHash(db); entry != blockHead.Hash() { t.Fatalf("Head header hash mismatch: have %v, want %v", entry, blockHead.Hash()) } - if entry := GetHeadBlockHash(db); entry != blockFull.Hash() { + if entry := ReadHeadBlockHash(db); entry != blockFull.Hash() { t.Fatalf("Head block hash mismatch: have %v, want %v", entry, blockFull.Hash()) } - if entry := GetHeadFastBlockHash(db); entry != blockFast.Hash() { + if entry := ReadHeadFastBlockHash(db); entry != blockFast.Hash() { t.Fatalf("Fast head block hash mismatch: have %v, want %v", entry, blockFast.Hash()) } } -// Tests that positional lookup metadata can be stored and retrieved. -func TestLookupStorage(t *testing.T) { - db, _ := ethdb.NewMemDatabase() - - 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}) - tx3 := types.NewTransaction(3, common.BytesToAddress([]byte{0x33}), big.NewInt(333), 3333, big.NewInt(33333), []byte{0x33, 0x33, 0x33}) - txs := []*types.Transaction{tx1, tx2, tx3} - - block := types.NewBlock(&types.Header{Number: big.NewInt(314)}, txs, nil, nil) - - // Check that no transactions entries are in a pristine database - for i, tx := range txs { - if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn != nil { - t.Fatalf("tx #%d [%x]: non existent transaction returned: %v", i, tx.Hash(), txn) - } - } - // Insert all the transactions into the database, and verify contents - if err := WriteBlock(db, block); err != nil { - t.Fatalf("failed to write block contents: %v", err) - } - if err := WriteTxLookupEntries(db, block); err != nil { - t.Fatalf("failed to write transactions: %v", err) - } - for i, tx := range txs { - if txn, hash, number, index := GetTransaction(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.String() != txn.String() { - t.Fatalf("tx #%d [%x]: transaction mismatch: have %v, want %v", i, tx.Hash(), txn, tx) - } - } - } - // Delete the transactions and check purge - for i, tx := range txs { - DeleteTxLookupEntry(db, tx.Hash()) - if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn != nil { - t.Fatalf("tx #%d [%x]: deleted transaction returned: %v", i, tx.Hash(), txn) - } - } -} - // Tests that receipts associated with a single block can be stored and retrieved. func TestBlockReceiptStorage(t *testing.T) { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() receipt1 := &types.Receipt{ Status: types.ReceiptStatusFailed, @@ -346,6 +279,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, @@ -357,18 +291,17 @@ 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 hash := common.BytesToHash([]byte{0x03, 0x14}) - if rs := GetBlockReceipts(db, hash, 0); len(rs) != 0 { + if rs := ReadReceipts(db, hash, 0); len(rs) != 0 { t.Fatalf("non existent receipts returned: %v", rs) } // Insert the receipt slice into the database and check presence - if err := WriteBlockReceipts(db, hash, 0, receipts); err != nil { - t.Fatalf("failed to write block receipts: %v", err) - } - if rs := GetBlockReceipts(db, hash, 0); len(rs) == 0 { + WriteReceipts(db, hash, 0, receipts) + if rs := ReadReceipts(db, hash, 0); len(rs) == 0 { t.Fatalf("no receipts returned") } else { for i := 0; i < len(receipts); i++ { @@ -381,8 +314,8 @@ func TestBlockReceiptStorage(t *testing.T) { } } // Delete the receipt slice and check purge - DeleteBlockReceipts(db, hash, 0) - if rs := GetBlockReceipts(db, hash, 0); len(rs) != 0 { + DeleteReceipts(db, hash, 0) + if rs := ReadReceipts(db, hash, 0); len(rs) != 0 { t.Fatalf("deleted receipts returned: %v", rs) } } diff --git a/core/rawdb/accessors_indexes.go b/core/rawdb/accessors_indexes.go new file mode 100644 index 0000000000..e6f7782a12 --- /dev/null +++ b/core/rawdb/accessors_indexes.go @@ -0,0 +1,118 @@ +// 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/common" + "github.com/ethereum/go-ethereum/core/types" + "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 { + data, _ := db.Get(txLookupKey(hash)) + if len(data) == 0 { + return common.Hash{} + } + 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, "blob", data, "err", err) + return common.Hash{} + } + 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 _, 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) { + 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 := ReadTxLookupEntry(db, hash) + if blockHash == (common.Hash{}) { + return nil, common.Hash{}, 0, 0 + } + blockNumber := ReadHeaderNumber(db, blockHash) + if blockNumber == nil { + return nil, common.Hash{}, 0, 0 + } + 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 := ReadTxLookupEntry(db, hash) + if blockHash == (common.Hash{}) { + return nil, common.Hash{}, 0, 0 + } + blockNumber := ReadHeaderNumber(db, blockHash) + if blockNumber == nil { + return nil, common.Hash{}, 0, 0 + } + 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) { + 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) { + if err := db.Put(bloomBitsKey(bit, section, head), bits); err != nil { + log.Crit("Failed to store bloom bits", "err", err) + } +} diff --git a/core/rawdb/accessors_indexes_test.go b/core/rawdb/accessors_indexes_test.go new file mode 100644 index 0000000000..bed03a5e6b --- /dev/null +++ b/core/rawdb/accessors_indexes_test.go @@ -0,0 +1,91 @@ +// 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 ( + "math/big" + "testing" + + "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() + + 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}) + tx3 := types.NewTransaction(3, common.BytesToAddress([]byte{0x33}), big.NewInt(333), 3333, big.NewInt(33333), []byte{0x33, 0x33, 0x33}) + txs := []*types.Transaction{tx1, tx2, tx3} + + block := types.NewBlock(&types.Header{Number: big.NewInt(314)}, txs, nil, nil) + + // Check that no transactions entries are in a pristine database + for i, tx := range txs { + if txn, _, _, _ := ReadTransaction(db, tx.Hash()); txn != nil { + t.Fatalf("tx #%d [%x]: non existent transaction returned: %v", i, tx.Hash(), txn) + } + } + // Insert all the transactions into the database, and verify contents + WriteBlock(db, block) + WriteTxLookupEntries(db, block) + + 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) + } + } + } + // Delete the transactions and check purge + for i, tx := range txs { + DeleteTxLookupEntry(db, tx.Hash()) + if txn, _, _, _ := ReadTransaction(db, tx.Hash()); txn != nil { + 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/core/rawdb/accessors_metadata.go b/core/rawdb/accessors_metadata.go new file mode 100644 index 0000000000..82e4bf0455 --- /dev/null +++ b/core/rawdb/accessors_metadata.go @@ -0,0 +1,97 @@ +// 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 ( + "encoding/json" + + "github.com/ethereum/go-ethereum/common" + "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) *uint64 { + var version uint64 + + enc, _ := db.Get(databaseVerisionKey) + if len(enc) == 0 { + return nil + } + if err := rlp.DecodeBytes(enc, &version); err != nil { + return nil + } + + return &version +} + +// WriteDatabaseVersion stores the version number of the database +func WriteDatabaseVersion(db DatabaseWriter, 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 { + data, _ := db.Get(configKey(hash)) + if len(data) == 0 { + return nil + } + var config params.ChainConfig + if err := json.Unmarshal(data, &config); err != nil { + log.Error("Invalid chain config JSON", "hash", hash, "err", err) + return nil + } + return &config +} + +// WriteChainConfig writes the chain config settings to the database. +func WriteChainConfig(db DatabaseWriter, hash common.Hash, cfg *params.ChainConfig) { + if cfg == nil { + return + } + data, err := json.Marshal(cfg) + if err != nil { + log.Crit("Failed to JSON encode chain config", "err", err) + } + if err := db.Put(configKey(hash), data); err != nil { + log.Crit("Failed to store chain config", "err", err) + } +} + +// ReadPreimage retrieves a single preimage of the provided hash. +func ReadPreimage(db DatabaseReader, 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) { + for hash, preimage := range preimages { + if err := db.Put(preimageKey(hash), preimage); err != nil { + log.Crit("Failed to store trie preimage", "err", err) + } + } + preimageCounter.Inc(int64(len(preimages))) + preimageHitCounter.Inc(int64(len(preimages))) +} diff --git a/core/rawdb/interfaces.go b/core/rawdb/interfaces.go new file mode 100644 index 0000000000..3bdf55124a --- /dev/null +++ b/core/rawdb/interfaces.go @@ -0,0 +1,33 @@ +// 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 + +// 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 +} diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go new file mode 100644 index 0000000000..3bb86e7ffb --- /dev/null +++ b/core/rawdb/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 rawdb contains a collection of low level database accessors. +package rawdb + +import ( + "encoding/binary" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/metrics" +) + +// The fields below define the low level database schema prefixing. +var ( + // databaseVerisionKey tracks the current database version. + databaseVerisionKey = []byte("DatabaseVersion") + + // headHeaderKey tracks the latest know header's hash. + headHeaderKey = []byte("LastHeader") + + // headBlockKey tracks the latest know full block's hash. + headBlockKey = []byte("LastBlock") + + // headFastBlockKey tracks the latest known incomplete block's hash during fast sync. + headFastBlockKey = []byte("LastFast") + + // fastTrieProgressKey tracks the number of trie entries imported during fast sync. + fastTrieProgressKey = []byte("TrieSync") + + // Data item prefixes (use single byte to avoid mixing data types, avoid `i`, used for indexes). + headerPrefix = []byte("h") // headerPrefix + num (uint64 big endian) + hash -> header + headerTDSuffix = []byte("t") // headerPrefix + num (uint64 big endian) + hash + headerTDSuffix -> td + headerHashSuffix = []byte("n") // headerPrefix + num (uint64 big endian) + headerHashSuffix -> hash + headerNumberPrefix = []byte("H") // headerNumberPrefix + hash -> num (uint64 big endian) + + blockBodyPrefix = []byte("b") // blockBodyPrefix + num (uint64 big endian) + hash -> block body + blockReceiptsPrefix = []byte("r") // blockReceiptsPrefix + num (uint64 big endian) + hash -> block receipts + + txLookupPrefix = []byte("l") // txLookupPrefix + hash -> transaction/receipt lookup metadata + bloomBitsPrefix = []byte("B") // bloomBitsPrefix + bit (uint16 big endian) + section (uint64 big endian) + hash -> bloom bits + + preimagePrefix = []byte("secure-key-") // preimagePrefix + hash -> preimage + configPrefix = []byte("ethereum-config-") // config prefix for the db + + // Chain index prefixes (use `i` + single byte to avoid mixing data types). + BloomBitsIndexPrefix = []byte("iB") // BloomBitsIndexPrefix is the data table of a chain indexer to track its progress + + preimageCounter = metrics.NewRegisteredCounter("db/preimage/total", nil) + preimageHitCounter = metrics.NewRegisteredCounter("db/preimage/hits", nil) +) + +// LegacyTxLookupEntry is the legacy TxLookupEntry definition with some unnecessary +// fields. +type LegacyTxLookupEntry struct { + BlockHash common.Hash + BlockIndex uint64 + Index uint64 +} + +// encodeBlockNumber encodes a block number as big endian uint64 +func encodeBlockNumber(number uint64) []byte { + enc := make([]byte, 8) + binary.BigEndian.PutUint64(enc, number) + return enc +} + +// headerKey = headerPrefix + num (uint64 big endian) + hash +func headerKey(number uint64, hash common.Hash) []byte { + return append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...) +} + +// headerTDKey = headerPrefix + num (uint64 big endian) + hash + headerTDSuffix +func headerTDKey(number uint64, hash common.Hash) []byte { + return append(headerKey(number, hash), headerTDSuffix...) +} + +// headerHashKey = headerPrefix + num (uint64 big endian) + headerHashSuffix +func headerHashKey(number uint64) []byte { + return append(append(headerPrefix, encodeBlockNumber(number)...), headerHashSuffix...) +} + +// headerNumberKey = headerNumberPrefix + hash +func headerNumberKey(hash common.Hash) []byte { + return append(headerNumberPrefix, hash.Bytes()...) +} + +// blockBodyKey = blockBodyPrefix + num (uint64 big endian) + hash +func blockBodyKey(number uint64, hash common.Hash) []byte { + return append(append(blockBodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...) +} + +// blockReceiptsKey = blockReceiptsPrefix + num (uint64 big endian) + hash +func blockReceiptsKey(number uint64, hash common.Hash) []byte { + return append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash.Bytes()...) +} + +// txLookupKey = txLookupPrefix + hash +func txLookupKey(hash common.Hash) []byte { + return append(txLookupPrefix, hash.Bytes()...) +} + +// bloomBitsKey = bloomBitsPrefix + bit (uint16 big endian) + section (uint64 big endian) + hash +func bloomBitsKey(bit uint, section uint64, hash common.Hash) []byte { + key := append(append(bloomBitsPrefix, make([]byte, 10)...), hash.Bytes()...) + + binary.BigEndian.PutUint16(key[1:], uint16(bit)) + binary.BigEndian.PutUint64(key[3:], section) + + return key +} + +// preimageKey = preimagePrefix + hash +func preimageKey(hash common.Hash) []byte { + return append(preimagePrefix, hash.Bytes()...) +} + +// configKey = configPrefix + hash +func configKey(hash common.Hash) []byte { + return append(configPrefix, hash.Bytes()...) +} diff --git a/core/state/database.go b/core/state/database.go index 946625e76e..f6ea144b9b 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -26,7 +26,7 @@ import ( lru "github.com/hashicorp/golang-lru" ) -// Trie cache generation limit after which to evic trie nodes from memory. +// Trie cache generation limit after which to evict trie nodes from memory. var MaxTrieCacheGen = uint16(120) const ( @@ -40,16 +40,23 @@ const ( // Database wraps access to tries and contract code. type Database interface { - // Accessing tries: // OpenTrie opens the main account trie. - // OpenStorageTrie opens the storage trie of an account. OpenTrie(root common.Hash) (Trie, error) + + // OpenStorageTrie opens the storage trie of an account. OpenStorageTrie(addrHash, root common.Hash) (Trie, error) - // Accessing contract code: - ContractCode(addrHash, codeHash common.Hash) ([]byte, error) - ContractCodeSize(addrHash, codeHash common.Hash) (int, error) + // CopyTrie returns an independent copy of the given trie. CopyTrie(Trie) Trie + + // ContractCode retrieves a particular contract's code. + ContractCode(addrHash, codeHash common.Hash) ([]byte, error) + + // ContractCodeSize retrieves a particular contracts code's size. + ContractCodeSize(addrHash, codeHash common.Hash) (int, error) + + // TrieDB retrieves the low level trie database used for data storage. + TrieDB() *trie.Database } // Trie is a Ethereum Merkle Trie. @@ -57,26 +64,39 @@ type Trie interface { TryGet(key []byte) ([]byte, error) TryUpdate(key, value []byte) error TryDelete(key []byte) error - CommitTo(trie.DatabaseWriter) (common.Hash, error) + Commit(onleaf trie.LeafCallback) (common.Hash, error) Hash() common.Hash 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 } // NewDatabase creates a backing store for state. The returned database is safe for -// concurrent use and retains cached trie nodes in memory. +// concurrent use and retains a few recent expanded trie nodes in memory. To keep +// more historical state in memory, use the NewDatabaseWithCache constructor. func NewDatabase(db ethdb.Database) Database { + return NewDatabaseWithCache(db, 0) +} + +// NewDatabase creates a backing store for state. The returned database is safe for +// concurrent use and retains both a few recent expanded trie nodes in memory, as +// well as 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: db, codeSizeCache: csc} + return &cachingDB{ + db: trie.NewDatabaseWithCache(db, cache), + codeSizeCache: csc, + } } type cachingDB struct { - db ethdb.Database + db *trie.Database mu sync.Mutex pastTries []*trie.SecureTrie codeSizeCache *lru.Cache } +// OpenTrie opens the main account trie. func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) { db.mu.Lock() defer db.mu.Unlock() @@ -105,10 +125,12 @@ func (db *cachingDB) pushTrie(t *trie.SecureTrie) { } } +// 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) } +// CopyTrie returns an independent copy of the given trie. func (db *cachingDB) CopyTrie(t Trie) Trie { switch t := t.(type) { case cachedTrie: @@ -120,35 +142,43 @@ func (db *cachingDB) CopyTrie(t Trie) Trie { } } +// ContractCode retrieves a particular contract's code. func (db *cachingDB) ContractCode(addrHash, codeHash common.Hash) ([]byte, error) { - code, err := db.db.Get(codeHash[:]) + code, err := db.db.Node(codeHash) if err == nil { db.codeSizeCache.Add(codeHash, len(code)) } return code, err } +// ContractCodeSize retrieves a particular contracts code's size. func (db *cachingDB) ContractCodeSize(addrHash, codeHash common.Hash) (int, error) { if cached, ok := db.codeSizeCache.Get(codeHash); ok { return cached.(int), nil } code, err := db.ContractCode(addrHash, codeHash) - if err == nil { - db.codeSizeCache.Add(codeHash, len(code)) - } return len(code), err } +// TrieDB retrieves any intermediate trie-node caching layer. +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) CommitTo(dbw trie.DatabaseWriter) (common.Hash, error) { - root, err := m.SecureTrie.CommitTo(dbw) +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/core/state/dump.go b/core/state/dump.go index 46e612850a..072dbbf053 100644 --- a/core/state/dump.go +++ b/core/state/dump.go @@ -53,7 +53,7 @@ func (self *StateDB) RawDump() Dump { panic(err) } - obj := newObject(nil, common.BytesToAddress(addr), data, nil) + obj := newObject(nil, common.BytesToAddress(addr), data) account := DumpAccount{ Balance: data.Balance.String(), Nonce: data.Nonce, diff --git a/core/state/iterator_test.go b/core/state/iterator_test.go index ff66ba7a94..9e46c851cd 100644 --- a/core/state/iterator_test.go +++ b/core/state/iterator_test.go @@ -21,12 +21,13 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethdb" ) // Tests that the node iterator indeed walks over the entire database contents. func TestNodeIteratorCoverage(t *testing.T) { // Create some arbitrary test state to iterate - db, mem, root, _ := makeTestState() + db, root, _ := makeTestState() state, err := New(root, db) if err != nil { @@ -39,14 +40,18 @@ func TestNodeIteratorCoverage(t *testing.T) { hashes[it.Hash] = struct{}{} } } - - // Cross check the hashes and the database itself + // Cross check the iterated hashes and the database/nodepool content for hash := range hashes { - if _, err := mem.Get(hash.Bytes()); err != nil { - t.Errorf("failed to retrieve reported node %x: %v", hash, err) + if _, err := db.TrieDB().Node(hash); err != nil { + t.Errorf("failed to retrieve reported node %x", hash) } } - for _, key := range mem.Keys() { + for _, hash := range db.TrieDB().Nodes() { + if _, ok := hashes[hash]; !ok { + t.Errorf("state entry not reported %x", hash) + } + } + for _, key := range db.TrieDB().DiskDB().(*ethdb.MemDatabase).Keys() { if bytes.HasPrefix(key, []byte("secure-key-")) { continue } diff --git a/core/state/journal.go b/core/state/journal.go index a89bb3d13a..a03ca57dbc 100644 --- a/core/state/journal.go +++ b/core/state/journal.go @@ -22,11 +22,67 @@ import ( "github.com/ethereum/go-ethereum/common" ) +// journalEntry is a modification entry in the state change journal that can be +// reverted on demand. type journalEntry interface { - undo(*StateDB) + // revert undoes the changes introduced by this journal entry. + revert(*StateDB) + + // dirtied returns the Ethereum address modified by this journal entry. + dirtied() *common.Address } -type journal []journalEntry +// journal contains the list of state modifications applied since the last state +// commit. These are tracked to be able to be reverted in case of an execution +// exception or revertal request. +type journal struct { + entries []journalEntry // Current changes tracked by the journal + dirties map[common.Address]int // Dirty accounts and the number of changes +} + +// newJournal create a new initialized journal. +func newJournal() *journal { + return &journal{ + dirties: make(map[common.Address]int), + } +} + +// append inserts a new modification entry to the end of the change journal. +func (j *journal) append(entry journalEntry) { + j.entries = append(j.entries, entry) + if addr := entry.dirtied(); addr != nil { + j.dirties[*addr]++ + } +} + +// revert undoes a batch of journalled modifications along with any reverted +// dirty handling too. +func (j *journal) revert(statedb *StateDB, snapshot int) { + for i := len(j.entries) - 1; i >= snapshot; i-- { + // Undo the changes made by the operation + j.entries[i].revert(statedb) + + // Drop any dirty tracking induced by the change + if addr := j.entries[i].dirtied(); addr != nil { + if j.dirties[*addr]--; j.dirties[*addr] == 0 { + delete(j.dirties, *addr) + } + } + } + j.entries = j.entries[:snapshot] +} + +// dirty explicitly sets an address to dirty, even if the change entries would +// otherwise suggest it as clean. This method is an ugly hack to handle the RIPEMD +// precompile consensus exception. +func (j *journal) dirty(addr common.Address) { + j.dirties[addr]++ +} + +// length returns the current number of entries in the journal. +func (j *journal) length() int { + return len(j.entries) +} type ( // Changes to the account trie. @@ -77,16 +133,24 @@ type ( } ) -func (ch createObjectChange) undo(s *StateDB) { +func (ch createObjectChange) revert(s *StateDB) { delete(s.stateObjects, *ch.account) delete(s.stateObjectsDirty, *ch.account) } -func (ch resetObjectChange) undo(s *StateDB) { +func (ch createObjectChange) dirtied() *common.Address { + return ch.account +} + +func (ch resetObjectChange) revert(s *StateDB) { s.setStateObject(ch.prev) } -func (ch suicideChange) undo(s *StateDB) { +func (ch resetObjectChange) dirtied() *common.Address { + return nil +} + +func (ch suicideChange) revert(s *StateDB) { obj := s.getStateObject(*ch.account) if obj != nil { obj.suicided = ch.prev @@ -94,38 +158,60 @@ func (ch suicideChange) undo(s *StateDB) { } } -var ripemd = common.HexToAddress("0000000000000000000000000000000000000003") - -func (ch touchChange) undo(s *StateDB) { - if !ch.prev && *ch.account != ripemd { - s.getStateObject(*ch.account).touched = ch.prev - if !ch.prevDirty { - delete(s.stateObjectsDirty, *ch.account) - } - } +func (ch suicideChange) dirtied() *common.Address { + return ch.account } -func (ch balanceChange) undo(s *StateDB) { +var ripemd = common.HexToAddress("0000000000000000000000000000000000000003") + +func (ch touchChange) revert(s *StateDB) { +} + +func (ch touchChange) dirtied() *common.Address { + return ch.account +} + +func (ch balanceChange) revert(s *StateDB) { s.getStateObject(*ch.account).setBalance(ch.prev) } -func (ch nonceChange) undo(s *StateDB) { +func (ch balanceChange) dirtied() *common.Address { + return ch.account +} + +func (ch nonceChange) revert(s *StateDB) { s.getStateObject(*ch.account).setNonce(ch.prev) } -func (ch codeChange) undo(s *StateDB) { +func (ch nonceChange) dirtied() *common.Address { + return ch.account +} + +func (ch codeChange) revert(s *StateDB) { s.getStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode) } -func (ch storageChange) undo(s *StateDB) { +func (ch codeChange) dirtied() *common.Address { + return ch.account +} + +func (ch storageChange) revert(s *StateDB) { s.getStateObject(*ch.account).setState(ch.key, ch.prevalue) } -func (ch refundChange) undo(s *StateDB) { +func (ch storageChange) dirtied() *common.Address { + return ch.account +} + +func (ch refundChange) revert(s *StateDB) { s.refund = ch.prev } -func (ch addLogChange) undo(s *StateDB) { +func (ch refundChange) dirtied() *common.Address { + return nil +} + +func (ch addLogChange) revert(s *StateDB) { logs := s.logs[ch.txhash] if len(logs) == 1 { delete(s.logs, ch.txhash) @@ -135,6 +221,14 @@ func (ch addLogChange) undo(s *StateDB) { s.logSize-- } -func (ch addPreimageChange) undo(s *StateDB) { +func (ch addLogChange) dirtied() *common.Address { + return nil +} + +func (ch addPreimageChange) revert(s *StateDB) { delete(s.preimages, ch.hash) } + +func (ch addPreimageChange) dirtied() *common.Address { + return nil +} diff --git a/core/state/managed_state_test.go b/core/state/managed_state_test.go index 1cfdd3a890..3d9c4e8676 100644 --- a/core/state/managed_state_test.go +++ b/core/state/managed_state_test.go @@ -26,8 +26,7 @@ import ( var addr = common.BytesToAddress([]byte("test")) func create() (*ManagedState, *account) { - db, _ := ethdb.NewMemDatabase() - statedb, _ := New(common.Hash{}, NewDatabase(db)) + statedb, _ := New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase())) ms := ManageState(statedb) ms.StateDB.SetNonce(addr, 100) ms.accounts[addr] = newAccount(ms.StateDB.getStateObject(addr)) diff --git a/core/state/state_object.go b/core/state/state_object.go index b2378c69c8..f41ab04092 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -25,7 +25,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/rlp" - "github.com/ethereum/go-ethereum/trie" ) var emptyCodeHash = crypto.Keccak256(nil) @@ -78,7 +77,7 @@ type stateObject struct { trie Trie // storage trie, which becomes non-nil on first access code Code // contract bytecode, which gets set when code is loaded - cachedStorage Storage // Storage entry cache to avoid duplicate reads + originStorage Storage // Storage cache of original entries to dedup rewrites dirtyStorage Storage // Storage entries that need to be flushed to disk // Cache flags. @@ -86,9 +85,7 @@ type stateObject struct { // during the "update" phase of the state transition. dirtyCode bool // true if the code was updated suicided bool - touched bool deleted bool - onDirty func(addr common.Address) // Callback method to mark a state object newly dirty } // empty returns whether the account is considered empty. @@ -106,7 +103,7 @@ type Account struct { } // newObject creates a state object. -func newObject(db *StateDB, address common.Address, data Account, onDirty func(addr common.Address)) *stateObject { +func newObject(db *StateDB, address common.Address, data Account) *stateObject { if data.Balance == nil { data.Balance = new(big.Int) } @@ -118,9 +115,8 @@ func newObject(db *StateDB, address common.Address, data Account, onDirty func(a address: address, addrHash: crypto.Keccak256Hash(address[:]), data: data, - cachedStorage: make(Storage), + originStorage: make(Storage), dirtyStorage: make(Storage), - onDirty: onDirty, } } @@ -138,23 +134,17 @@ func (self *stateObject) setError(err error) { func (self *stateObject) markSuicided() { self.suicided = true - if self.onDirty != nil { - self.onDirty(self.Address()) - self.onDirty = nil - } } func (c *stateObject) touch() { - c.db.journal = append(c.db.journal, touchChange{ - account: &c.address, - prev: c.touched, - prevDirty: c.onDirty == nil, + c.db.journal.append(touchChange{ + account: &c.address, }) - if c.onDirty != nil { - c.onDirty(c.Address()) - c.onDirty = nil + if c.address == ripemd { + // Explicitly put it in the dirty-cache, which is otherwise generated from + // flattened journals. + c.db.journal.dirty(c.address) } - c.touched = true } func (c *stateObject) getTrie(db Database) Trie { @@ -169,13 +159,25 @@ func (c *stateObject) getTrie(db Database) Trie { return c.trie } -// GetState returns a value in account storage. +// GetState retrieves a value from the account storage trie. func (self *stateObject) GetState(db Database, key common.Hash) common.Hash { - value, exists := self.cachedStorage[key] - if exists { + // If we have a dirty value for this state entry, return it + value, dirty := self.dirtyStorage[key] + if dirty { return value } - // Load from DB in case it is missing. + // Otherwise return the entry's original value + return self.GetCommittedState(db, key) +} + +// GetCommittedState retrieves a value from the committed account storage trie. +func (self *stateObject) GetCommittedState(db Database, key common.Hash) common.Hash { + // If we have the original value cached, return that + value, cached := self.originStorage[key] + if cached { + return value + } + // Otherwise load the value from the database enc, err := self.getTrie(db).TryGet(key[:]) if err != nil { self.setError(err) @@ -188,30 +190,28 @@ func (self *stateObject) GetState(db Database, key common.Hash) common.Hash { } value.SetBytes(content) } - if (value != common.Hash{}) { - self.cachedStorage[key] = value - } + self.originStorage[key] = value return value } // SetState updates a value in account storage. func (self *stateObject) SetState(db Database, key, value common.Hash) { - self.db.journal = append(self.db.journal, storageChange{ + // If the new value is the same as old, don't set + prev := self.GetState(db, key) + if prev == value { + return + } + // New value is different, update and journal the change + self.db.journal.append(storageChange{ account: &self.address, key: key, - prevalue: self.GetState(db, key), + prevalue: prev, }) self.setState(key, value) } func (self *stateObject) setState(key, value common.Hash) { - self.cachedStorage[key] = value self.dirtyStorage[key] = value - - if self.onDirty != nil { - self.onDirty(self.Address()) - self.onDirty = nil - } } // updateTrie writes cached storage modifications into the object's storage trie. @@ -219,6 +219,13 @@ func (self *stateObject) updateTrie(db Database) Trie { tr := self.getTrie(db) for key, value := range self.dirtyStorage { delete(self.dirtyStorage, key) + + // Skip noop changes, persist actual changes + if value == self.originStorage[key] { + continue + } + self.originStorage[key] = value + if (value == common.Hash{}) { self.setError(tr.TryDelete(key[:])) continue @@ -236,14 +243,14 @@ func (self *stateObject) updateRoot(db Database) { self.data.Root = self.trie.Hash() } -// CommitTrie the storage trie of the object to dwb. +// CommitTrie the storage trie of the object to db. // This updates the trie root. -func (self *stateObject) CommitTrie(db Database, dbw trie.DatabaseWriter) error { +func (self *stateObject) CommitTrie(db Database) error { self.updateTrie(db) if self.dbErr != nil { return self.dbErr } - root, err := self.trie.CommitTo(dbw) + root, err := self.trie.Commit(nil) if err == nil { self.data.Root = root } @@ -275,7 +282,7 @@ func (c *stateObject) SubBalance(amount *big.Int) { } func (self *stateObject) SetBalance(amount *big.Int) { - self.db.journal = append(self.db.journal, balanceChange{ + self.db.journal.append(balanceChange{ account: &self.address, prev: new(big.Int).Set(self.data.Balance), }) @@ -284,23 +291,19 @@ func (self *stateObject) SetBalance(amount *big.Int) { func (self *stateObject) setBalance(amount *big.Int) { self.data.Balance = amount - if self.onDirty != nil { - self.onDirty(self.Address()) - self.onDirty = nil - } } // Return the gas back to the origin. Used by the Virtual machine or Closures func (c *stateObject) ReturnGas(gas *big.Int) {} -func (self *stateObject) deepCopy(db *StateDB, onDirty func(addr common.Address)) *stateObject { - stateObject := newObject(db, self.address, self.data, onDirty) +func (self *stateObject) deepCopy(db *StateDB) *stateObject { + stateObject := newObject(db, self.address, self.data) if self.trie != nil { stateObject.trie = db.db.CopyTrie(self.trie) } stateObject.code = self.code stateObject.dirtyStorage = self.dirtyStorage.Copy() - stateObject.cachedStorage = self.dirtyStorage.Copy() + stateObject.originStorage = self.originStorage.Copy() stateObject.suicided = self.suicided stateObject.dirtyCode = self.dirtyCode stateObject.deleted = self.deleted @@ -334,7 +337,7 @@ func (self *stateObject) Code(db Database) []byte { func (self *stateObject) SetCode(codeHash common.Hash, code []byte) { prevcode := self.Code(self.db.db) - self.db.journal = append(self.db.journal, codeChange{ + self.db.journal.append(codeChange{ account: &self.address, prevhash: self.CodeHash(), prevcode: prevcode, @@ -346,14 +349,10 @@ func (self *stateObject) setCode(codeHash common.Hash, code []byte) { self.code = code self.data.CodeHash = codeHash[:] self.dirtyCode = true - if self.onDirty != nil { - self.onDirty(self.Address()) - self.onDirty = nil - } } func (self *stateObject) SetNonce(nonce uint64) { - self.db.journal = append(self.db.journal, nonceChange{ + self.db.journal.append(nonceChange{ account: &self.address, prev: self.data.Nonce, }) @@ -362,10 +361,6 @@ func (self *stateObject) SetNonce(nonce uint64) { func (self *stateObject) setNonce(nonce uint64) { self.data.Nonce = nonce - if self.onDirty != nil { - self.onDirty(self.Address()) - self.onDirty = nil - } } func (self *stateObject) CodeHash() []byte { diff --git a/core/state/state_test.go b/core/state/state_test.go index bbae3685bb..a09273f3b1 100644 --- a/core/state/state_test.go +++ b/core/state/state_test.go @@ -48,7 +48,7 @@ func (s *StateSuite) TestDump(c *checker.C) { // write some of them to the trie s.state.updateStateObject(obj1) s.state.updateStateObject(obj2) - s.state.CommitTo(s.db, false) + s.state.Commit(false) // check that dump contains the state objects that are in trie got := string(s.state.Dump()) @@ -87,7 +87,7 @@ func (s *StateSuite) TestDump(c *checker.C) { } func (s *StateSuite) SetUpTest(c *checker.C) { - s.db, _ = ethdb.NewMemDatabase() + s.db = ethdb.NewMemDatabase() s.state, _ = New(common.Hash{}, NewDatabase(s.db)) } @@ -96,11 +96,15 @@ func (s *StateSuite) TestNull(c *checker.C) { s.state.CreateAccount(address) //value := common.FromHex("0x823140710bf13990e4500136726d8b55") var value common.Hash + s.state.SetState(address, common.Hash{}, value) - s.state.CommitTo(s.db, false) - value = s.state.GetState(address, common.Hash{}) - if !common.EmptyHash(value) { - c.Errorf("expected empty hash. got %x", value) + s.state.Commit(false) + + if value := s.state.GetState(address, common.Hash{}); value != (common.Hash{}) { + c.Errorf("expected empty current value, got %x", value) + } + if value := s.state.GetCommittedState(address, common.Hash{}); value != (common.Hash{}) { + c.Errorf("expected empty committed value, got %x", value) } } @@ -110,20 +114,24 @@ func (s *StateSuite) TestSnapshot(c *checker.C) { data1 := common.BytesToHash([]byte{42}) data2 := common.BytesToHash([]byte{43}) + // snapshot the genesis state + genesis := s.state.Snapshot() + // set initial state object value s.state.SetState(stateobjaddr, storageaddr, data1) - // get snapshot of current state snapshot := s.state.Snapshot() - // set new state object value + // set a new state object value, revert it and ensure correct content s.state.SetState(stateobjaddr, storageaddr, data2) - // restore snapshot s.state.RevertToSnapshot(snapshot) - // get state storage value - res := s.state.GetState(stateobjaddr, storageaddr) + c.Assert(s.state.GetState(stateobjaddr, storageaddr), checker.DeepEquals, data1) + c.Assert(s.state.GetCommittedState(stateobjaddr, storageaddr), checker.DeepEquals, common.Hash{}) - c.Assert(data1, checker.DeepEquals, res) + // revert up to the genesis state and ensure correct content + s.state.RevertToSnapshot(genesis) + c.Assert(s.state.GetState(stateobjaddr, storageaddr), checker.DeepEquals, common.Hash{}) + c.Assert(s.state.GetCommittedState(stateobjaddr, storageaddr), checker.DeepEquals, common.Hash{}) } func (s *StateSuite) TestSnapshotEmpty(c *checker.C) { @@ -133,8 +141,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) { - db, _ := ethdb.NewMemDatabase() - state, _ := New(common.Hash{}, NewDatabase(db)) + state, _ := New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase())) stateobjaddr0 := toAddr([]byte("so0")) stateobjaddr1 := toAddr([]byte("so1")) @@ -155,7 +162,7 @@ func TestSnapshot2(t *testing.T) { so0.deleted = false state.setStateObject(so0) - root, _ := state.CommitTo(db, false) + root, _ := state.Commit(false) state.Reset(root) // and one with deleted == true @@ -209,24 +216,30 @@ func compareStateObjects(so0, so1 *stateObject, t *testing.T) { t.Fatalf("Code mismatch: have %v, want %v", so0.code, so1.code) } - if len(so1.cachedStorage) != len(so0.cachedStorage) { - t.Errorf("Storage size mismatch: have %d, want %d", len(so1.cachedStorage), len(so0.cachedStorage)) + if len(so1.dirtyStorage) != len(so0.dirtyStorage) { + t.Errorf("Dirty storage size mismatch: have %d, want %d", len(so1.dirtyStorage), len(so0.dirtyStorage)) } - for k, v := range so1.cachedStorage { - if so0.cachedStorage[k] != v { - t.Errorf("Storage key %x mismatch: have %v, want %v", k, so0.cachedStorage[k], v) + for k, v := range so1.dirtyStorage { + if so0.dirtyStorage[k] != v { + t.Errorf("Dirty storage key %x mismatch: have %v, want %v", k, so0.dirtyStorage[k], v) } } - for k, v := range so0.cachedStorage { - if so1.cachedStorage[k] != v { - t.Errorf("Storage key %x mismatch: have %v, want none.", k, v) + for k, v := range so0.dirtyStorage { + if so1.dirtyStorage[k] != v { + t.Errorf("Dirty storage key %x mismatch: have %v, want none.", k, v) } } - - if so0.suicided != so1.suicided { - t.Fatalf("suicided mismatch: have %v, want %v", so0.suicided, so1.suicided) + if len(so1.originStorage) != len(so0.originStorage) { + t.Errorf("Origin storage size mismatch: have %d, want %d", len(so1.originStorage), len(so0.originStorage)) } - if so0.deleted != so1.deleted { - t.Fatalf("Deleted mismatch: have %v, want %v", so0.deleted, so1.deleted) + for k, v := range so1.originStorage { + if so0.originStorage[k] != v { + t.Errorf("Origin storage key %x mismatch: have %v, want %v", k, so0.originStorage[k], v) + } + } + for k, v := range so0.originStorage { + if so1.originStorage[k] != v { + t.Errorf("Origin storage key %x mismatch: have %v, want none.", k, v) + } } } diff --git a/core/state/statedb.go b/core/state/statedb.go index 8e29104d59..8ad25a5824 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -18,10 +18,10 @@ package state import ( + "errors" "fmt" "math/big" "sort" - "sync" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -36,6 +36,21 @@ type revision struct { journalIndex int } +var ( + // emptyState is the known hash of an empty state trie entry. + emptyState = crypto.Keccak256Hash(nil) + + // emptyCode is the known hash of the empty EVM bytecode. + emptyCode = crypto.Keccak256Hash(nil) +) + +type proofList [][]byte + +func (n *proofList) Put(key []byte, value []byte) error { + *n = append(*n, value) + return nil +} + // 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: @@ -68,14 +83,12 @@ type StateDB struct { // Journal of state modifications. This is the backbone of // Snapshot and RevertToSnapshot. - journal journal + journal *journal validRevisions []revision nextRevisionId int - - lock sync.Mutex } -// Create a new state from a given trie +// Create a new state from a given trie. func New(root common.Hash, db Database) (*StateDB, error) { tr, err := db.OpenTrie(root) if err != nil { @@ -88,6 +101,7 @@ func New(root common.Hash, db Database) (*StateDB, error) { stateObjectsDirty: make(map[common.Address]struct{}), logs: make(map[common.Hash][]*types.Log), preimages: make(map[common.Hash][]byte), + journal: newJournal(), }, nil } @@ -102,7 +116,7 @@ func (self *StateDB) Error() error { return self.dbErr } -// Reset clears out all emphemeral state objects from the state db, but keeps +// Reset clears out all ephemeral state objects from the state db, but keeps // the underlying state trie to avoid reloading data for the next operations. func (self *StateDB) Reset(root common.Hash) error { tr, err := self.db.OpenTrie(root) @@ -123,7 +137,7 @@ func (self *StateDB) Reset(root common.Hash) error { } func (self *StateDB) AddLog(log *types.Log) { - self.journal = append(self.journal, addLogChange{txhash: self.thash}) + self.journal.append(addLogChange{txhash: self.thash}) log.TxHash = self.thash log.BlockHash = self.bhash @@ -148,7 +162,7 @@ func (self *StateDB) Logs() []*types.Log { // AddPreimage records a SHA3 preimage seen by the VM. func (self *StateDB) AddPreimage(hash common.Hash, preimage []byte) { if _, ok := self.preimages[hash]; !ok { - self.journal = append(self.journal, addPreimageChange{hash: hash}) + self.journal.append(addPreimageChange{hash: hash}) pi := make([]byte, len(preimage)) copy(pi, preimage) self.preimages[hash] = pi @@ -160,11 +174,22 @@ func (self *StateDB) Preimages() map[common.Hash][]byte { return self.preimages } +// AddRefund adds gas to the refund counter func (self *StateDB) AddRefund(gas uint64) { - self.journal = append(self.journal, refundChange{prev: self.refund}) + self.journal.append(refundChange{prev: self.refund}) self.refund += gas } +// SubRefund removes gas from the refund counter. +// This method will panic if the refund counter goes below zero +func (self *StateDB) SubRefund(gas uint64) { + self.journal.append(refundChange{prev: self.refund}) + if gas > self.refund { + panic("Refund counter below zero") + } + self.refund -= gas +} + // Exist reports whether the given account address exists in the state. // Notably this also returns true for suicided accounts. func (self *StateDB) Exist(addr common.Address) bool { @@ -227,22 +252,55 @@ func (self *StateDB) GetCodeHash(addr common.Address) common.Hash { return common.BytesToHash(stateObject.CodeHash()) } -func (self *StateDB) GetState(a common.Address, b common.Hash) common.Hash { - stateObject := self.getStateObject(a) +// GetState retrieves a value from the given account's storage trie. +func (self *StateDB) GetState(addr common.Address, hash common.Hash) common.Hash { + stateObject := self.getStateObject(addr) if stateObject != nil { - return stateObject.GetState(self.db, b) + return stateObject.GetState(self.db, hash) } return common.Hash{} } +// GetProof returns the MerkleProof for a given Account +func (self *StateDB) GetProof(a common.Address) ([][]byte, error) { + var proof proofList + err := self.trie.Prove(crypto.Keccak256(a.Bytes()), 0, &proof) + return [][]byte(proof), err +} + +// GetProof returns the StorageProof for given key +func (self *StateDB) GetStorageProof(a common.Address, key common.Hash) ([][]byte, error) { + var proof proofList + trie := self.StorageTrie(a) + if trie == nil { + return proof, errors.New("storage trie for requested address does not exist") + } + err := trie.Prove(crypto.Keccak256(key.Bytes()), 0, &proof) + return [][]byte(proof), err +} + +// GetCommittedState retrieves a value from the given account's committed storage trie. +func (self *StateDB) GetCommittedState(addr common.Address, hash common.Hash) common.Hash { + stateObject := self.getStateObject(addr) + if stateObject != nil { + return stateObject.GetCommittedState(self.db, hash) + } + return common.Hash{} +} + +// Database retrieves the low level database supporting the lower level trie ops. +func (self *StateDB) Database() Database { + return self.db +} + // StorageTrie returns the storage trie of an account. // The return value is a copy and is nil for non-existent accounts. -func (self *StateDB) StorageTrie(a common.Address) Trie { - stateObject := self.getStateObject(a) +func (self *StateDB) StorageTrie(addr common.Address) Trie { + stateObject := self.getStateObject(addr) if stateObject == nil { return nil } - cpy := stateObject.deepCopy(self, nil) + cpy := stateObject.deepCopy(self) return cpy.updateTrie(self.db) } @@ -258,7 +316,7 @@ func (self *StateDB) HasSuicided(addr common.Address) bool { * SETTERS */ -// AddBalance adds amount to the account associated with addr +// AddBalance adds amount to the account associated with addr. func (self *StateDB) AddBalance(addr common.Address, amount *big.Int) { stateObject := self.GetOrNewStateObject(addr) if stateObject != nil { @@ -266,7 +324,7 @@ func (self *StateDB) AddBalance(addr common.Address, amount *big.Int) { } } -// SubBalance subtracts amount from the account associated with addr +// SubBalance subtracts amount from the account associated with addr. func (self *StateDB) SubBalance(addr common.Address, amount *big.Int) { stateObject := self.GetOrNewStateObject(addr) if stateObject != nil { @@ -295,7 +353,7 @@ func (self *StateDB) SetCode(addr common.Address, code []byte) { } } -func (self *StateDB) SetState(addr common.Address, key common.Hash, value common.Hash) { +func (self *StateDB) SetState(addr common.Address, key, value common.Hash) { stateObject := self.GetOrNewStateObject(addr) if stateObject != nil { stateObject.SetState(self.db, key, value) @@ -312,7 +370,7 @@ func (self *StateDB) Suicide(addr common.Address) bool { if stateObject == nil { return false } - self.journal = append(self.journal, suicideChange{ + self.journal.append(suicideChange{ account: &addr, prev: stateObject.suicided, prevbalance: new(big.Int).Set(stateObject.Balance()), @@ -324,7 +382,7 @@ func (self *StateDB) Suicide(addr common.Address) bool { } // -// Setting, updating & deleting state object methods +// Setting, updating & deleting state object methods. // // updateStateObject writes the given object to the trie. @@ -344,7 +402,7 @@ func (self *StateDB) deleteStateObject(stateObject *stateObject) { self.setError(self.trie.TryDelete(addr[:])) } -// Retrieve a state object given my the address. Returns nil if not found. +// 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 { @@ -366,7 +424,7 @@ func (self *StateDB) getStateObject(addr common.Address) (stateObject *stateObje return nil } // Insert into the live set. - obj := newObject(self, addr, data, self.MarkStateObjectDirty) + obj := newObject(self, addr, data) self.setStateObject(obj) return obj } @@ -375,7 +433,7 @@ func (self *StateDB) setStateObject(object *stateObject) { self.stateObjects[object.Address()] = object } -// Retrieve a state object or create a new state object if nil +// Retrieve a state object or create a new state object if nil. func (self *StateDB) GetOrNewStateObject(addr common.Address) *stateObject { stateObject := self.getStateObject(addr) if stateObject == nil || stateObject.deleted { @@ -384,22 +442,16 @@ func (self *StateDB) GetOrNewStateObject(addr common.Address) *stateObject { return stateObject } -// MarkStateObjectDirty adds the specified object to the dirty map to avoid costly -// state object cache iteration to find a handful of modified ones. -func (self *StateDB) MarkStateObjectDirty(addr common.Address) { - self.stateObjectsDirty[addr] = struct{}{} -} - // createObject creates a new state object. If there is an existing account with // the given address, it is overwritten and returned as the second return value. func (self *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) { prev = self.getStateObject(addr) - newobj = newObject(self, addr, Account{}, self.MarkStateObjectDirty) + newobj = newObject(self, addr, Account{}) newobj.setNonce(0) // sets the object to dirty if prev == nil { - self.journal = append(self.journal, createObjectChange{account: &addr}) + self.journal.append(createObjectChange{account: &addr}) } else { - self.journal = append(self.journal, resetObjectChange{prev: prev}) + self.journal.append(resetObjectChange{prev: prev}) } self.setStateObject(newobj) return newobj, prev @@ -416,9 +468,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) } } @@ -427,47 +479,59 @@ func (db *StateDB) ForEachStorage(addr common.Address, cb func(key, value common if so == nil { return } - - // When iterating over the storage check the cache first - for h, value := range so.cachedStorage { - cb(h, value) - } - it := trie.NewIterator(so.getTrie(db.db).NodeIterator(nil)) for it.Next() { - // ignore cached values key := common.BytesToHash(db.trie.GetKey(it.Key)) - if _, ok := so.cachedStorage[key]; !ok { - cb(key, common.BytesToHash(it.Value)) + if value, dirty := so.dirtyStorage[key]; dirty { + cb(key, value) + continue } + cb(key, common.BytesToHash(it.Value)) } } // Copy creates a deep, independent copy of the state. // Snapshots of the copied state cannot be applied to the copy. func (self *StateDB) Copy() *StateDB { - self.lock.Lock() - defer self.lock.Unlock() - // Copy all the basic fields, initialize the memory ones state := &StateDB{ db: self.db, trie: self.db.CopyTrie(self.trie), - stateObjects: make(map[common.Address]*stateObject, len(self.stateObjectsDirty)), - stateObjectsDirty: make(map[common.Address]struct{}, len(self.stateObjectsDirty)), + stateObjects: make(map[common.Address]*stateObject, len(self.journal.dirties)), + stateObjectsDirty: make(map[common.Address]struct{}, len(self.journal.dirties)), 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 + for addr := range self.journal.dirties { + // As documented [here](https://github.com/ethereum/go-ethereum/pull/16485#issuecomment-380438527), + // and in the Finalise-method, there is a case where an object is in the journal but not + // in the stateObjects: OOG after touch on ripeMD prior to Byzantium. Thus, we need to check for + // nil + if object, exist := self.stateObjects[addr]; exist { + state.stateObjects[addr] = object.deepCopy(state) + state.stateObjectsDirty[addr] = struct{}{} + } + } + // Above, we don't copy the actual journal. This means that if the copy is copied, the + // loop above will be a no-op, since the copy's journal is empty. + // Thus, here we iterate over stateObjects, to enable copies of copies for addr := range self.stateObjectsDirty { - state.stateObjects[addr] = self.stateObjects[addr].deepCopy(state, state.MarkStateObjectDirty) - state.stateObjectsDirty[addr] = struct{}{} + if _, exist := state.stateObjects[addr]; !exist { + state.stateObjects[addr] = self.stateObjects[addr].deepCopy(state) + state.stateObjectsDirty[addr] = struct{}{} + } } for hash, logs := range self.logs { - state.logs[hash] = make([]*types.Log, len(logs)) - copy(state.logs[hash], logs) + cpy := make([]*types.Log, len(logs)) + for i, l := range logs { + cpy[i] = new(types.Log) + *cpy[i] = *l + } + state.logs[hash] = cpy } for hash, preimage := range self.preimages { state.preimages[hash] = preimage @@ -479,7 +543,7 @@ func (self *StateDB) Copy() *StateDB { func (self *StateDB) Snapshot() int { id := self.nextRevisionId self.nextRevisionId++ - self.validRevisions = append(self.validRevisions, revision{id, len(self.journal)}) + self.validRevisions = append(self.validRevisions, revision{id, self.journal.length()}) return id } @@ -494,13 +558,8 @@ func (self *StateDB) RevertToSnapshot(revid int) { } snapshot := self.validRevisions[idx].journalIndex - // Replay the journal to undo changes. - for i := len(self.journal) - 1; i >= snapshot; i-- { - self.journal[i].undo(self) - } - self.journal = self.journal[:snapshot] - - // Remove invalidated snapshots from the stack. + // Replay the journal to undo changes and remove invalidated snapshots + self.journal.revert(self, snapshot) self.validRevisions = self.validRevisions[:idx] } @@ -512,14 +571,25 @@ func (self *StateDB) GetRefund() uint64 { // Finalise finalises the state by removing the self destructed objects // and clears the journal as well as the refunds. func (s *StateDB) Finalise(deleteEmptyObjects bool) { - for addr := range s.stateObjectsDirty { - stateObject := s.stateObjects[addr] + for addr := range s.journal.dirties { + stateObject, exist := s.stateObjects[addr] + if !exist { + // ripeMD is 'touched' at block 1714175, in tx 0x1237f737031e40bcde4a8b7e717b2d15e3ecadfe49bb1bbc71ee9deb09c6fcf2 + // That tx goes out of gas, and although the notion of 'touched' does not exist there, the + // touch-event will still be recorded in the journal. Since ripeMD is a special snowflake, + // it will persist in the journal even though the journal is reverted. In this special circumstance, + // it may exist in `s.journal.dirties` but not in `s.stateObjects`. + // Thus, we can safely ignore it here + continue + } + if stateObject.suicided || (deleteEmptyObjects && stateObject.empty()) { s.deleteStateObject(stateObject) } else { stateObject.updateRoot(s.db) s.updateStateObject(stateObject) } + s.stateObjectsDirty[addr] = struct{}{} } // Invalidate journal because reverting across transactions is not allowed. s.clearJournalAndRefund() @@ -541,37 +611,19 @@ func (self *StateDB) Prepare(thash, bhash common.Hash, ti int) { self.txIndex = ti } -// DeleteSuicides flags the suicided objects for deletion so that it -// won't be referenced again when called / queried up on. -// -// DeleteSuicides should not be used for consensus related updates -// under any circumstances. -func (s *StateDB) DeleteSuicides() { - // Reset refund so that any used-gas calculations can use this method. - s.clearJournalAndRefund() - - for addr := range s.stateObjectsDirty { - stateObject := s.stateObjects[addr] - - // If the object has been removed by a suicide - // flag the object as deleted. - if stateObject.suicided { - stateObject.deleted = true - } - delete(s.stateObjectsDirty, addr) - } -} - func (s *StateDB) clearJournalAndRefund() { - s.journal = nil + s.journal = newJournal() s.validRevisions = s.validRevisions[:0] s.refund = 0 } -// CommitTo writes the state to the given database. -func (s *StateDB) CommitTo(dbw trie.DatabaseWriter, deleteEmptyObjects bool) (root common.Hash, err error) { +// Commit writes the state to the underlying in-memory trie database. +func (s *StateDB) Commit(deleteEmptyObjects bool) (root common.Hash, err error) { defer s.clearJournalAndRefund() + for addr := range s.journal.dirties { + s.stateObjectsDirty[addr] = struct{}{} + } // Commit objects to the trie. for addr, stateObject := range s.stateObjects { _, isDirty := s.stateObjectsDirty[addr] @@ -583,13 +635,11 @@ func (s *StateDB) CommitTo(dbw trie.DatabaseWriter, deleteEmptyObjects bool) (ro case isDirty: // Write any contract code associated with the state object if stateObject.code != nil && stateObject.dirtyCode { - if err := dbw.Put(stateObject.CodeHash(), stateObject.code); err != nil { - return common.Hash{}, err - } + s.db.TrieDB().InsertBlob(common.BytesToHash(stateObject.CodeHash()), stateObject.code) stateObject.dirtyCode = false } // Write any storage changes in the state object to its storage trie. - if err := stateObject.CommitTrie(s.db, dbw); err != nil { + if err := stateObject.CommitTrie(s.db); err != nil { return common.Hash{}, err } // Update the object in the main account trie. @@ -598,7 +648,20 @@ func (s *StateDB) CommitTo(dbw trie.DatabaseWriter, deleteEmptyObjects bool) (ro delete(s.stateObjectsDirty, addr) } // Write trie changes. - root, err = s.trie.CommitTo(dbw) + 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 { + s.db.TrieDB().Reference(account.Root, parent) + } + code := common.BytesToHash(account.CodeHash) + if code != emptyCode { + s.db.TrieDB().Reference(code, parent) + } + return nil + }) log.Debug("Trie cache stats after commit", "misses", trie.CacheMisses(), "unloads", trie.CacheUnloads()) return root, err } diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index 5c80e3aa56..69392d972e 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -39,7 +39,7 @@ import ( // actually committing the state. func TestUpdateLeaks(t *testing.T) { // Create an empty state database - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() state, _ := New(common.Hash{}, NewDatabase(db)) // Update it with some accounts @@ -66,8 +66,8 @@ func TestUpdateLeaks(t *testing.T) { // 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 := ethdb.NewMemDatabase() + finalDb := ethdb.NewMemDatabase() transState, _ := New(common.Hash{}, NewDatabase(transDb)) finalState, _ := New(common.Hash{}, NewDatabase(finalDb)) @@ -97,10 +97,10 @@ func TestIntermediateLeaks(t *testing.T) { } // Commit and cross check the databases. - if _, err := transState.CommitTo(transDb, false); err != nil { + if _, err := transState.Commit(false); err != nil { t.Fatalf("failed to commit transition state: %v", err) } - if _, err := finalState.CommitTo(finalDb, false); err != nil { + if _, err := finalState.Commit(false); err != nil { t.Fatalf("failed to commit final state: %v", err) } for _, key := range finalDb.Keys() { @@ -122,8 +122,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" - mem, _ := ethdb.NewMemDatabase() - orig, _ := New(common.Hash{}, NewDatabase(mem)) + orig, _ := New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase())) for i := byte(0); i < 255; i++ { obj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) @@ -277,6 +276,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 @@ -334,8 +342,7 @@ func (test *snapshotTest) String() string { func (test *snapshotTest) run() bool { // Run all actions and create snapshots. var ( - db, _ = ethdb.NewMemDatabase() - state, _ = New(common.Hash{}, NewDatabase(db)) + state, _ = New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase())) snapshotRevs = make([]int, len(test.snapshots)) sindex = 0 ) @@ -346,11 +353,10 @@ func (test *snapshotTest) run() bool { } action.fn(action, state) } - // Revert all snapshots in reverse order. Each revert must yield a state // that is equivalent to fresh state with all actions up the snapshot applied. for sindex--; sindex >= 0; sindex-- { - checkstate, _ := New(common.Hash{}, NewDatabase(db)) + checkstate, _ := New(common.Hash{}, state.Database()) for _, action := range test.actions[:test.snapshots[sindex]] { action.fn(action, checkstate) } @@ -384,11 +390,11 @@ func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error { checkeq("GetCodeSize", state.GetCodeSize(addr), checkstate.GetCodeSize(addr)) // Check storage. if obj := state.getStateObject(addr); obj != nil { - state.ForEachStorage(addr, func(key, val common.Hash) bool { - return checkeq("GetState("+key.Hex()+")", val, checkstate.GetState(addr, key)) + state.ForEachStorage(addr, func(key, value common.Hash) bool { + return checkeq("GetState("+key.Hex()+")", checkstate.GetState(addr, key), value) }) - checkstate.ForEachStorage(addr, func(key, checkval common.Hash) bool { - return checkeq("GetState("+key.Hex()+")", state.GetState(addr, key), checkval) + checkstate.ForEachStorage(addr, func(key, value common.Hash) bool { + return checkeq("GetState("+key.Hex()+")", checkstate.GetState(addr, key), value) }) } if err != nil { @@ -409,17 +415,32 @@ func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error { func (s *StateSuite) TestTouchDelete(c *check.C) { s.state.GetOrNewStateObject(common.Address{}) - root, _ := s.state.CommitTo(s.db, false) + root, _ := s.state.Commit(false) s.state.Reset(root) snapshot := s.state.Snapshot() s.state.AddBalance(common.Address{}, new(big.Int)) - if len(s.state.stateObjectsDirty) != 1 { + + if len(s.state.journal.dirties) != 1 { c.Fatal("expected one dirty state object") } - s.state.RevertToSnapshot(snapshot) - if len(s.state.stateObjectsDirty) != 0 { + if len(s.state.journal.dirties) != 0 { c.Fatal("expected no dirty state object") } } + +// 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())) + addr := common.HexToAddress("aaaa") + sdb.SetBalance(addr, big.NewInt(42)) + + if got := sdb.Copy().GetBalance(addr).Uint64(); got != 42 { + t.Fatalf("1st copy fail, expected 42, got %v", got) + } + if got := sdb.Copy().Copy().GetBalance(addr).Uint64(); got != 42 { + t.Fatalf("2nd copy fail, expected 42, got %v", got) + } +} diff --git a/core/state/sync.go b/core/state/sync.go index 28fcf6ae05..c566e79073 100644 --- a/core/state/sync.go +++ b/core/state/sync.go @@ -25,8 +25,8 @@ import ( ) // NewStateSync create a new state trie download scheduler. -func NewStateSync(root common.Hash, database trie.DatabaseReader) *trie.TrieSync { - var syncer *trie.TrieSync +func NewStateSync(root common.Hash, database trie.DatabaseReader) *trie.Sync { + var syncer *trie.Sync callback := func(leaf []byte, parent common.Hash) error { var obj Account if err := rlp.Decode(bytes.NewReader(leaf), &obj); err != nil { @@ -36,6 +36,6 @@ func NewStateSync(root common.Hash, database trie.DatabaseReader) *trie.TrieSync syncer.AddRawEntry(common.BytesToHash(obj.CodeHash), 64, parent) return nil } - syncer = trie.NewTrieSync(root, database, callback) + syncer = trie.NewSync(root, database, callback) return syncer } diff --git a/core/state/sync_test.go b/core/state/sync_test.go index 06c572ea62..3177401608 100644 --- a/core/state/sync_test.go +++ b/core/state/sync_test.go @@ -36,10 +36,9 @@ type testAccount struct { } // makeTestState create a sample test state to test node-wise reconstruction. -func makeTestState() (Database, *ethdb.MemDatabase, common.Hash, []*testAccount) { +func makeTestState() (Database, common.Hash, []*testAccount) { // Create an empty state - mem, _ := ethdb.NewMemDatabase() - db := NewDatabase(mem) + db := NewDatabase(ethdb.NewMemDatabase()) state, _ := New(common.Hash{}, db) // Fill it with some arbitrary data @@ -61,10 +60,10 @@ func makeTestState() (Database, *ethdb.MemDatabase, common.Hash, []*testAccount) state.updateStateObject(obj) accounts = append(accounts, acc) } - root, _ := state.CommitTo(mem, false) + root, _ := state.Commit(false) // Return the generated state - return db, mem, root, accounts + return db, root, accounts } // checkStateAccounts cross references a reconstructed state with an expected @@ -96,7 +95,7 @@ func checkTrieConsistency(db ethdb.Database, root common.Hash) error { if v, _ := db.Get(root[:]); v == nil { return nil // Consider a non existent state consistent. } - trie, err := trie.New(root, db) + trie, err := trie.New(root, trie.NewDatabase(db)) if err != nil { return err } @@ -125,8 +124,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") - db, _ := ethdb.NewMemDatabase() - if req := NewStateSync(empty, db).Missing(1); len(req) != 0 { + if req := NewStateSync(empty, ethdb.NewMemDatabase()).Missing(1); len(req) != 0 { t.Errorf("content requested for empty state: %v", req) } } @@ -138,19 +136,19 @@ func TestIterativeStateSyncBatched(t *testing.T) { testIterativeStateSync(t, func testIterativeStateSync(t *testing.T, batch int) { // Create a random state to copy - _, srcMem, srcRoot, srcAccounts := makeTestState() + srcDb, srcRoot, srcAccounts := makeTestState() // Create a destination state and sync with the scheduler - dstDb, _ := ethdb.NewMemDatabase() + dstDb := ethdb.NewMemDatabase() sched := NewStateSync(srcRoot, dstDb) queue := append([]common.Hash{}, sched.Missing(batch)...) for len(queue) > 0 { results := make([]trie.SyncResult, len(queue)) for i, hash := range queue { - data, err := srcMem.Get(hash.Bytes()) + data, err := srcDb.TrieDB().Node(hash) if err != nil { - t.Fatalf("failed to retrieve node data for %x: %v", hash, err) + t.Fatalf("failed to retrieve node data for %x", hash) } results[i] = trie.SyncResult{Hash: hash, Data: data} } @@ -170,10 +168,10 @@ func testIterativeStateSync(t *testing.T, batch int) { // partial results are returned, and the others sent only later. func TestIterativeDelayedStateSync(t *testing.T) { // Create a random state to copy - _, srcMem, srcRoot, srcAccounts := makeTestState() + srcDb, srcRoot, srcAccounts := makeTestState() // Create a destination state and sync with the scheduler - dstDb, _ := ethdb.NewMemDatabase() + dstDb := ethdb.NewMemDatabase() sched := NewStateSync(srcRoot, dstDb) queue := append([]common.Hash{}, sched.Missing(0)...) @@ -181,9 +179,9 @@ func TestIterativeDelayedStateSync(t *testing.T) { // Sync only half of the scheduled nodes results := make([]trie.SyncResult, len(queue)/2+1) for i, hash := range queue[:len(results)] { - data, err := srcMem.Get(hash.Bytes()) + data, err := srcDb.TrieDB().Node(hash) if err != nil { - t.Fatalf("failed to retrieve node data for %x: %v", hash, err) + t.Fatalf("failed to retrieve node data for %x", hash) } results[i] = trie.SyncResult{Hash: hash, Data: data} } @@ -207,10 +205,10 @@ func TestIterativeRandomStateSyncBatched(t *testing.T) { testIterativeRandomS func testIterativeRandomStateSync(t *testing.T, batch int) { // Create a random state to copy - _, srcMem, srcRoot, srcAccounts := makeTestState() + srcDb, srcRoot, srcAccounts := makeTestState() // Create a destination state and sync with the scheduler - dstDb, _ := ethdb.NewMemDatabase() + dstDb := ethdb.NewMemDatabase() sched := NewStateSync(srcRoot, dstDb) queue := make(map[common.Hash]struct{}) @@ -221,9 +219,9 @@ func testIterativeRandomStateSync(t *testing.T, batch int) { // Fetch all the queued nodes in a random order results := make([]trie.SyncResult, 0, len(queue)) for hash := range queue { - data, err := srcMem.Get(hash.Bytes()) + data, err := srcDb.TrieDB().Node(hash) if err != nil { - t.Fatalf("failed to retrieve node data for %x: %v", hash, err) + t.Fatalf("failed to retrieve node data for %x", hash) } results = append(results, trie.SyncResult{Hash: hash, Data: data}) } @@ -247,10 +245,10 @@ func testIterativeRandomStateSync(t *testing.T, batch int) { // partial results are returned (Even those randomly), others sent only later. func TestIterativeRandomDelayedStateSync(t *testing.T) { // Create a random state to copy - _, srcMem, srcRoot, srcAccounts := makeTestState() + srcDb, srcRoot, srcAccounts := makeTestState() // Create a destination state and sync with the scheduler - dstDb, _ := ethdb.NewMemDatabase() + dstDb := ethdb.NewMemDatabase() sched := NewStateSync(srcRoot, dstDb) queue := make(map[common.Hash]struct{}) @@ -263,9 +261,9 @@ func TestIterativeRandomDelayedStateSync(t *testing.T) { for hash := range queue { delete(queue, hash) - data, err := srcMem.Get(hash.Bytes()) + data, err := srcDb.TrieDB().Node(hash) if err != nil { - t.Fatalf("failed to retrieve node data for %x: %v", hash, err) + t.Fatalf("failed to retrieve node data for %x", hash) } results = append(results, trie.SyncResult{Hash: hash, Data: data}) @@ -292,12 +290,12 @@ func TestIterativeRandomDelayedStateSync(t *testing.T) { // the database. func TestIncompleteStateSync(t *testing.T) { // Create a random state to copy - _, srcMem, srcRoot, srcAccounts := makeTestState() + srcDb, srcRoot, srcAccounts := makeTestState() - checkTrieConsistency(srcMem, srcRoot) + checkTrieConsistency(srcDb.TrieDB().DiskDB().(ethdb.Database), srcRoot) // Create a destination state and sync with the scheduler - dstDb, _ := ethdb.NewMemDatabase() + dstDb := ethdb.NewMemDatabase() sched := NewStateSync(srcRoot, dstDb) added := []common.Hash{} @@ -306,9 +304,9 @@ func TestIncompleteStateSync(t *testing.T) { // Fetch a batch of state nodes results := make([]trie.SyncResult, len(queue)) for i, hash := range queue { - data, err := srcMem.Get(hash.Bytes()) + data, err := srcDb.TrieDB().Node(hash) if err != nil { - t.Fatalf("failed to retrieve node data for %x: %v", hash, err) + t.Fatalf("failed to retrieve node data for %x", hash) } results[i] = trie.SyncResult{Hash: hash, Data: data} } diff --git a/core/state_processor.go b/core/state_processor.go index 4dc58b9dea..503a35d16a 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -61,7 +61,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg allLogs []*types.Log gp = new(GasPool).AddGas(block.GasLimit()) ) - // Mutate the the block and state according to any hard-fork specs + // Mutate the block and state according to any hard-fork specs if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { misc.ApplyDAOHardFork(statedb) } @@ -85,7 +85,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg // and uses the input parameters for its environment. It returns the receipt // for the transaction, gas used and an error if the transaction failed, // indicating the block was invalid. -func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, uint64, error) { +func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, uint64, error) { msg, err := tx.AsMessage(types.MakeSigner(config, header.Number)) if err != nil { return nil, 0, err @@ -110,7 +110,7 @@ func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common *usedGas += gas // Create a new receipt for the transaction, storing the intermediate root and gas used by the tx - // based on the eip phase, we're passing wether the root touch-delete accounts. + // based on the eip phase, we're passing whether the root touch-delete accounts. receipt := types.NewReceipt(root, failed, *usedGas) receipt.TxHash = tx.Hash() receipt.GasUsed = gas diff --git a/core/state_transition.go b/core/state_transition.go index 390473fffd..fda081b7d1 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -35,7 +35,7 @@ var ( The State Transitioning Model A state transition is a change made when a transaction is applied to the current world state -The state transitioning model does all all the necessary work to work out a valid new state root. +The state transitioning model does all the necessary work to work out a valid new state root. 1) Nonce handling 2) Pre pay gas @@ -132,28 +132,12 @@ func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) ([]byte, uint64, bool, return NewStateTransition(evm, msg, gp).TransitionDb() } -func (st *StateTransition) from() vm.AccountRef { - f := st.msg.From() - if !st.state.Exist(f) { - st.state.CreateAccount(f) +// to returns the recipient of the message. +func (st *StateTransition) to() common.Address { + if st.msg == nil || st.msg.To() == nil /* contract creation */ { + return common.Address{} } - return vm.AccountRef(f) -} - -func (st *StateTransition) to() vm.AccountRef { - if st.msg == nil { - return vm.AccountRef{} - } - to := st.msg.To() - if to == nil { - return vm.AccountRef{} // contract creation - } - - reference := vm.AccountRef(*to) - if !st.state.Exist(*to) { - st.state.CreateAccount(*to) - } - return reference + return *st.msg.To() } func (st *StateTransition) useGas(amount uint64) error { @@ -166,12 +150,8 @@ func (st *StateTransition) useGas(amount uint64) error { } func (st *StateTransition) buyGas() error { - var ( - state = st.state - sender = st.from() - ) mgval := new(big.Int).Mul(new(big.Int).SetUint64(st.msg.Gas()), st.gasPrice) - if state.GetBalance(sender.Address()).Cmp(mgval) < 0 { + if st.state.GetBalance(st.msg.From()).Cmp(mgval) < 0 { return errInsufficientBalanceForGas } if err := st.gp.SubGas(st.msg.Gas()); err != nil { @@ -180,20 +160,17 @@ func (st *StateTransition) buyGas() error { st.gas += st.msg.Gas() st.initialGas = st.msg.Gas() - state.SubBalance(sender.Address(), mgval) + st.state.SubBalance(st.msg.From(), mgval) return nil } func (st *StateTransition) preCheck() error { - msg := st.msg - sender := st.from() - - // Make sure this transaction's nonce is correct - if msg.CheckNonce() { - nonce := st.state.GetNonce(sender.Address()) - if nonce < msg.Nonce() { + // Make sure this transaction's nonce is correct. + if st.msg.CheckNonce() { + nonce := st.state.GetNonce(st.msg.From()) + if nonce < st.msg.Nonce() { return ErrNonceTooHigh - } else if nonce > msg.Nonce() { + } else if nonce > st.msg.Nonce() { return ErrNonceTooLow } } @@ -201,20 +178,22 @@ func (st *StateTransition) preCheck() error { } // TransitionDb will transition the state by applying the current message and -// returning the result including the the used gas. It returns an error if it -// failed. An error indicates a consensus issue. +// returning the result including the used gas. It returns an error if failed. +// An error indicates a consensus issue. func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bool, err error) { if err = st.preCheck(); err != nil { return } msg := st.msg - sender := st.from() // err checked in preCheck - + sender := vm.AccountRef(msg.From()) homestead := st.evm.ChainConfig().IsHomestead(st.evm.BlockNumber) contractCreation := msg.To() == nil // Pay intrinsic gas gas, err := IntrinsicGas(st.data, contractCreation, homestead) + if err != nil { + return nil, 0, false, err + } if err = st.useGas(gas); err != nil { return nil, 0, false, err } @@ -230,8 +209,8 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo ret, _, st.gas, vmerr = evm.Create(sender, st.data, st.gas, st.value) } else { // Increment the nonce for the next transaction - st.state.SetNonce(sender.Address(), st.state.GetNonce(sender.Address())+1) - ret, st.gas, vmerr = evm.Call(sender, st.to().Address(), st.data, st.gas, st.value) + st.state.SetNonce(msg.From(), st.state.GetNonce(sender.Address())+1) + ret, st.gas, vmerr = evm.Call(sender, st.to(), st.data, st.gas, st.value) } if vmerr != nil { log.Debug("VM returned with error", "err", vmerr) @@ -257,10 +236,8 @@ func (st *StateTransition) refundGas() { st.gas += refund // Return ETH for remaining gas, exchanged at the original rate. - sender := st.from() - remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gas), st.gasPrice) - st.state.AddBalance(sender.Address(), remaining) + st.state.AddBalance(st.msg.From(), remaining) // Also return remaining gas to the block gas counter so it is // available for the next transaction. diff --git a/core/tx_cacher.go b/core/tx_cacher.go new file mode 100644 index 0000000000..b1e5d676a2 --- /dev/null +++ b/core/tx_cacher.go @@ -0,0 +1,105 @@ +// 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 ( + "runtime" + + "github.com/ethereum/go-ethereum/core/types" +) + +// senderCacher is a concurrent transaction sender recoverer and cacher. +var senderCacher = newTxSenderCacher(runtime.NumCPU()) + +// txSenderCacherRequest is a request for recovering transaction senders with a +// specific signature scheme and caching it into the transactions themselves. +// +// The inc field defines the number of transactions to skip after each recovery, +// which is used to feed the same underlying input array to different threads but +// ensure they process the early transactions fast. +type txSenderCacherRequest struct { + signer types.Signer + txs []*types.Transaction + inc int +} + +// txSenderCacher is a helper structure to concurrently ecrecover transaction +// senders from digital signatures on background threads. +type txSenderCacher struct { + threads int + tasks chan *txSenderCacherRequest +} + +// newTxSenderCacher creates a new transaction sender background cacher and starts +// as many processing goroutines as allowed by the GOMAXPROCS on construction. +func newTxSenderCacher(threads int) *txSenderCacher { + cacher := &txSenderCacher{ + tasks: make(chan *txSenderCacherRequest, threads), + threads: threads, + } + for i := 0; i < threads; i++ { + go cacher.cache() + } + return cacher +} + +// cache is an infinite loop, caching transaction senders from various forms of +// data structures. +func (cacher *txSenderCacher) cache() { + for task := range cacher.tasks { + for i := 0; i < len(task.txs); i += task.inc { + types.Sender(task.signer, task.txs[i]) + } + } +} + +// recover recovers the senders from a batch of transactions and caches them +// back into the same data structures. There is no validation being done, nor +// any reaction to invalid signatures. That is up to calling code later. +func (cacher *txSenderCacher) recover(signer types.Signer, txs []*types.Transaction) { + // If there's nothing to recover, abort + if len(txs) == 0 { + return + } + // Ensure we have meaningful task sizes and schedule the recoveries + tasks := cacher.threads + if len(txs) < tasks*4 { + tasks = (len(txs) + 3) / 4 + } + for i := 0; i < tasks; i++ { + cacher.tasks <- &txSenderCacherRequest{ + signer: signer, + txs: txs[i:], + inc: tasks, + } + } +} + +// recoverFromBlocks recovers the senders from a batch of blocks and caches them +// back into the same data structures. There is no validation being done, nor +// any reaction to invalid signatures. That is up to calling code later. +func (cacher *txSenderCacher) recoverFromBlocks(signer types.Signer, blocks []*types.Block) { + count := 0 + for _, block := range blocks { + count += len(block.Transactions()) + } + txs := make([]*types.Transaction, 0, count) + for _, block := range blocks { + txs = append(txs, block.Transactions()...) + } + cacher.recover(signer, txs) +} diff --git a/core/tx_journal.go b/core/tx_journal.go index e872d7b530..41b5156d4a 100644 --- a/core/tx_journal.go +++ b/core/tx_journal.go @@ -34,7 +34,7 @@ var errNoActiveJournal = errors.New("no active journal") // devNull is a WriteCloser that just discards anything written into it. Its // goal is to allow the transaction journal to write into a fake journal when // loading transactions on startup without printing warnings due to no file -// being readt for write. +// being read for write. type devNull struct{} func (*devNull) Write(p []byte) (n int, err error) { return len(p), nil } @@ -56,8 +56,8 @@ func newTxJournal(path string) *txJournal { // load parses a transaction journal dump from disk, loading its contents into // the specified pool. -func (journal *txJournal) load(add func(*types.Transaction) error) error { - // Skip the parsing if the journal file doens't exist at all +func (journal *txJournal) load(add func([]*types.Transaction) []error) error { + // Skip the parsing if the journal file doesn't exist at all if _, err := os.Stat(journal.path); os.IsNotExist(err) { return nil } @@ -76,7 +76,21 @@ func (journal *txJournal) load(add func(*types.Transaction) error) error { stream := rlp.NewStream(input, 0) total, dropped := 0, 0 - var failure error + // Create a method to load a limited batch of transactions and bump the + // appropriate progress counters. Then use this method to load all the + // journaled transactions in small-ish batches. + loadBatch := func(txs types.Transactions) { + for _, err := range add(txs) { + if err != nil { + log.Debug("Failed to add journaled transaction", "err", err) + dropped++ + } + } + } + var ( + failure error + batch types.Transactions + ) for { // Parse the next transaction and terminate on error tx := new(types.Transaction) @@ -84,14 +98,17 @@ func (journal *txJournal) load(add func(*types.Transaction) error) error { if err != io.EOF { failure = err } + if batch.Len() > 0 { + loadBatch(batch) + } break } - // Import the transaction and bump the appropriate progress counters + // New transaction parsed, queue up for later, import if threshold is reached total++ - if err = add(tx); err != nil { - log.Debug("Failed to add journaled transaction", "err", err) - dropped++ - continue + + if batch = append(batch, tx); batch.Len() > 1024 { + loadBatch(batch) + batch = batch[:0] } } log.Info("Loaded local transaction journal", "transactions", total, "dropped", dropped) diff --git a/core/tx_list.go b/core/tx_list.go index 55fc42617d..57abc51486 100644 --- a/core/tx_list.go +++ b/core/tx_list.go @@ -367,9 +367,20 @@ func (l *txList) Flatten() types.Transactions { // price-sorted transactions to discard when the pool fills up. type priceHeap []*types.Transaction -func (h priceHeap) Len() int { return len(h) } -func (h priceHeap) Less(i, j int) bool { return h[i].GasPrice().Cmp(h[j].GasPrice()) < 0 } -func (h priceHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] } +func (h priceHeap) Len() int { return len(h) } +func (h priceHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] } + +func (h priceHeap) Less(i, j int) bool { + // Sort primarily by price, returning the cheaper one + switch h[i].GasPrice().Cmp(h[j].GasPrice()) { + case -1: + return true + case 1: + return false + } + // If the prices match, stabilize via nonces (high nonce is worse) + return h[i].Nonce() > h[j].Nonce() +} func (h *priceHeap) Push(x interface{}) { *h = append(*h, x.(*types.Transaction)) @@ -386,13 +397,13 @@ func (h *priceHeap) Pop() interface{} { // txPricedList is a price-sorted heap to allow operating on transactions pool // contents in a price-incrementing way. type txPricedList struct { - all *map[common.Hash]*types.Transaction // Pointer to the map of all transactions - items *priceHeap // Heap of prices of all the stored transactions - stales int // Number of stale price points to (re-heap trigger) + all *txLookup // Pointer to the map of all transactions + items *priceHeap // Heap of prices of all the stored transactions + stales int // Number of stale price points to (re-heap trigger) } // newTxPricedList creates a new price-sorted transaction heap. -func newTxPricedList(all *map[common.Hash]*types.Transaction) *txPricedList { +func newTxPricedList(all *txLookup) *txPricedList { return &txPricedList{ all: all, items: new(priceHeap), @@ -414,17 +425,18 @@ func (l *txPricedList) Removed() { return } // Seems we've reached a critical number of stale transactions, reheap - reheap := make(priceHeap, 0, len(*l.all)) + reheap := make(priceHeap, 0, l.all.Count()) l.stales, l.items = 0, &reheap - for _, tx := range *l.all { + l.all.Range(func(hash common.Hash, tx *types.Transaction) bool { *l.items = append(*l.items, tx) - } + return true + }) heap.Init(l.items) } // Cap finds all the transactions below the given price threshold, drops them -// from the priced list and returs them for further removal from the entire pool. +// from the priced list and returns them for further removal from the entire pool. func (l *txPricedList) Cap(threshold *big.Int, local *accountSet) types.Transactions { drop := make(types.Transactions, 0, 128) // Remote underpriced transactions to drop save := make(types.Transactions, 0, 64) // Local underpriced transactions to keep @@ -432,7 +444,7 @@ func (l *txPricedList) Cap(threshold *big.Int, local *accountSet) types.Transact for len(*l.items) > 0 { // Discard stale transactions if found during cleanup tx := heap.Pop(l.items).(*types.Transaction) - if _, ok := (*l.all)[tx.Hash()]; !ok { + if l.all.Get(tx.Hash()) == nil { l.stales-- continue } @@ -464,7 +476,7 @@ func (l *txPricedList) Underpriced(tx *types.Transaction, local *accountSet) boo // Discard stale price points if found at the heap start for len(*l.items) > 0 { head := []*types.Transaction(*l.items)[0] - if _, ok := (*l.all)[head.Hash()]; !ok { + if l.all.Get(head.Hash()) == nil { l.stales-- heap.Pop(l.items) continue @@ -489,7 +501,7 @@ func (l *txPricedList) Discard(count int, local *accountSet) types.Transactions for len(*l.items) > 0 && count > 0 { // Discard stale transactions if found during cleanup tx := heap.Pop(l.items).(*types.Transaction) - if _, ok := (*l.all)[tx.Hash()]; !ok { + if l.all.Get(tx.Hash()) == nil { l.stales-- continue } diff --git a/core/tx_pool.go b/core/tx_pool.go index dc3ddc4232..552d3692b3 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -26,20 +26,18 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/prque" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/params" - "gopkg.in/karalabe/cookiejar.v2/collections/prque" ) const ( // chainHeadChanSize is the size of channel listening to ChainHeadEvent. chainHeadChanSize = 10 - // rmTxChanSize is the size of channel listening to RemovedTransactionEvent. - rmTxChanSize = 10 ) var ( @@ -87,20 +85,20 @@ var ( var ( // Metrics for the pending pool - pendingDiscardCounter = metrics.NewCounter("txpool/pending/discard") - pendingReplaceCounter = metrics.NewCounter("txpool/pending/replace") - pendingRateLimitCounter = metrics.NewCounter("txpool/pending/ratelimit") // Dropped due to rate limiting - pendingNofundsCounter = metrics.NewCounter("txpool/pending/nofunds") // Dropped due to out-of-funds + pendingDiscardCounter = metrics.NewRegisteredCounter("txpool/pending/discard", nil) + pendingReplaceCounter = metrics.NewRegisteredCounter("txpool/pending/replace", nil) + pendingRateLimitCounter = metrics.NewRegisteredCounter("txpool/pending/ratelimit", nil) // Dropped due to rate limiting + pendingNofundsCounter = metrics.NewRegisteredCounter("txpool/pending/nofunds", nil) // Dropped due to out-of-funds // Metrics for the queued pool - queuedDiscardCounter = metrics.NewCounter("txpool/queued/discard") - queuedReplaceCounter = metrics.NewCounter("txpool/queued/replace") - queuedRateLimitCounter = metrics.NewCounter("txpool/queued/ratelimit") // Dropped due to rate limiting - queuedNofundsCounter = metrics.NewCounter("txpool/queued/nofunds") // Dropped due to out-of-funds + queuedDiscardCounter = metrics.NewRegisteredCounter("txpool/queued/discard", nil) + queuedReplaceCounter = metrics.NewRegisteredCounter("txpool/queued/replace", nil) + queuedRateLimitCounter = metrics.NewRegisteredCounter("txpool/queued/ratelimit", nil) // Dropped due to rate limiting + queuedNofundsCounter = metrics.NewRegisteredCounter("txpool/queued/nofunds", nil) // Dropped due to out-of-funds // General tx metrics - invalidTxCounter = metrics.NewCounter("txpool/invalid") - underpricedTxCounter = metrics.NewCounter("txpool/underpriced") + invalidTxCounter = metrics.NewRegisteredCounter("txpool/invalid", nil) + underpricedTxCounter = metrics.NewRegisteredCounter("txpool/underpriced", nil) ) // TxStatus is the current status of a transaction as seen by the pool. @@ -125,14 +123,15 @@ type blockChain interface { // TxPoolConfig are the configuration parameters of the transaction pool. type TxPoolConfig struct { - NoLocals bool // Whether local transaction handling should be disabled - Journal string // Journal of local transactions to survive node restarts - Rejournal time.Duration // Time interval to regenerate the local transaction journal + Locals []common.Address // Addresses that should be treated by default as local + NoLocals bool // Whether local transaction handling should be disabled + Journal string // Journal of local transactions to survive node restarts + Rejournal time.Duration // Time interval to regenerate the local transaction journal PriceLimit uint64 // Minimum gas price to enforce for acceptance into the pool PriceBump uint64 // Minimum price bump percentage to replace an already existing transaction (nonce) - AccountSlots uint64 // Minimum number of executable transaction slots guaranteed per account + AccountSlots uint64 // Number of executable transaction slots guaranteed per account GlobalSlots uint64 // Maximum number of executable transaction slots for all accounts AccountQueue uint64 // Maximum number of non-executable transaction slots permitted per account GlobalQueue uint64 // Maximum number of non-executable transaction slots for all accounts @@ -173,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 } @@ -202,11 +221,11 @@ type TxPool struct { locals *accountSet // Set of local transaction to exempt from eviction rules journal *txJournal // Journal of local transaction to back up to disk - pending map[common.Address]*txList // All currently processable transactions - queue map[common.Address]*txList // Queued but non-processable transactions - beats map[common.Address]time.Time // Last heartbeat from each known account - all map[common.Hash]*types.Transaction // All transactions to allow lookups - priced *txPricedList // All transactions sorted by price + pending map[common.Address]*txList // All currently processable transactions + queue map[common.Address]*txList // Queued but non-processable transactions + beats map[common.Address]time.Time // Last heartbeat from each known account + all *txLookup // All transactions to allow lookups + priced *txPricedList // All transactions sorted by price wg sync.WaitGroup // for shutdown sync @@ -224,23 +243,27 @@ func NewTxPool(config TxPoolConfig, chainconfig *params.ChainConfig, chain block config: config, chainconfig: chainconfig, chain: chain, - signer: types.NewEIP155Signer(chainconfig.ChainId), + signer: types.NewEIP155Signer(chainconfig.ChainID), pending: make(map[common.Address]*txList), queue: make(map[common.Address]*txList), beats: make(map[common.Address]time.Time), - all: make(map[common.Hash]*types.Transaction), + all: newTxLookup(), chainHeadCh: make(chan ChainHeadEvent, chainHeadChanSize), gasPrice: new(big.Int).SetUint64(config.PriceLimit), } pool.locals = newAccountSet(pool.signer) - pool.priced = newTxPricedList(&pool.all) + for _, addr := range config.Locals { + log.Info("Setting new local account", "address", addr) + pool.locals.add(addr) + } + pool.priced = newTxPricedList(pool.all) pool.reset(nil, chain.CurrentBlock().Header()) // If local transactions and journaling is enabled, load from disk if !config.NoLocals && config.Journal != "" { pool.journal = newTxJournal(config.Journal) - if err := pool.journal.load(pool.AddLocal); err != nil { + if err := pool.journal.load(pool.AddLocals); err != nil { log.Warn("Failed to load transaction journal", "err", err) } if err := pool.journal.rotate(pool.local()); err != nil { @@ -320,7 +343,7 @@ func (pool *TxPool) loop() { // Any non-locals old enough should be removed if time.Since(pool.beats[addr]) > pool.config.Lifetime { for _, tx := range pool.queue[addr].Flatten() { - pool.removeTx(tx.Hash()) + pool.removeTx(tx.Hash(), true) } } } @@ -413,6 +436,7 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) { // Inject any transactions discarded due to reorgs log.Debug("Reinjecting stale transactions", "count", len(reinject)) + senderCacher.recover(pool.signer, reinject) pool.addTxsLocked(reinject, false) // validate the pool of pending transactions, this will remove @@ -446,9 +470,9 @@ func (pool *TxPool) Stop() { log.Info("Transaction pool stopped") } -// SubscribeTxPreEvent registers a subscription of TxPreEvent and +// SubscribeNewTxsEvent registers a subscription of NewTxsEvent and // starts sending event to the given channel. -func (pool *TxPool) SubscribeTxPreEvent(ch chan<- TxPreEvent) event.Subscription { +func (pool *TxPool) SubscribeNewTxsEvent(ch chan<- NewTxsEvent) event.Subscription { return pool.scope.Track(pool.txFeed.Subscribe(ch)) } @@ -468,7 +492,7 @@ func (pool *TxPool) SetGasPrice(price *big.Int) { pool.gasPrice = price for _, tx := range pool.priced.Cap(price, pool.locals) { - pool.removeTx(tx.Hash()) + pool.removeTx(tx.Hash(), false) } log.Info("Transaction pool price threshold updated", "price", price) } @@ -521,7 +545,7 @@ func (pool *TxPool) Content() (map[common.Address]types.Transactions, map[common return pending, queued } -// Pending retrieves all currently processable transactions, groupped by origin +// Pending retrieves all currently processable transactions, grouped by origin // account and sorted by nonce. The returned transaction set is a copy and can be // freely modified by calling code. func (pool *TxPool) Pending() (map[common.Address]types.Transactions, error) { @@ -535,7 +559,15 @@ func (pool *TxPool) Pending() (map[common.Address]types.Transactions, error) { return pending, nil } -// local retrieves all currently known local transactions, groupped by origin +// Locals retrieves the accounts currently considered local by the pool. +func (pool *TxPool) Locals() []common.Address { + pool.mu.Lock() + defer pool.mu.Unlock() + + return pool.locals.flatten() +} + +// local retrieves all currently known local transactions, grouped by origin // account and sorted by nonce. The returned transaction set is a copy and can be // freely modified by calling code. func (pool *TxPool) local() map[common.Address]types.Transactions { @@ -607,7 +639,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { func (pool *TxPool) add(tx *types.Transaction, local bool) (bool, error) { // If the transaction is already known, discard it hash := tx.Hash() - if pool.all[hash] != nil { + if pool.all.Get(hash) != nil { log.Trace("Discarding already known transaction", "hash", hash) return false, fmt.Errorf("known transaction: %x", hash) } @@ -618,19 +650,19 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (bool, error) { return false, err } // If the transaction pool is full, discard underpriced transactions - if uint64(len(pool.all)) >= pool.config.GlobalSlots+pool.config.GlobalQueue { + if uint64(pool.all.Count()) >= pool.config.GlobalSlots+pool.config.GlobalQueue { // If the new transaction is underpriced, don't accept it - if pool.priced.Underpriced(tx, pool.locals) { + if !local && pool.priced.Underpriced(tx, pool.locals) { log.Trace("Discarding underpriced transaction", "hash", hash, "price", tx.GasPrice()) underpricedTxCounter.Inc(1) return false, ErrUnderpriced } // New transaction is better than our worse ones, make room for it - drop := pool.priced.Discard(len(pool.all)-int(pool.config.GlobalSlots+pool.config.GlobalQueue-1), pool.locals) + drop := pool.priced.Discard(pool.all.Count()-int(pool.config.GlobalSlots+pool.config.GlobalQueue-1), pool.locals) for _, tx := range drop { log.Trace("Discarding freshly underpriced transaction", "hash", tx.Hash(), "price", tx.GasPrice()) underpricedTxCounter.Inc(1) - pool.removeTx(tx.Hash()) + pool.removeTx(tx.Hash(), false) } } // If the transaction is replacing an already pending one, do directly @@ -644,18 +676,18 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (bool, error) { } // New transaction is better, replace old one if old != nil { - delete(pool.all, old.Hash()) + pool.all.Remove(old.Hash()) pool.priced.Removed() pendingReplaceCounter.Inc(1) } - pool.all[tx.Hash()] = tx + pool.all.Add(tx) pool.priced.Put(tx) pool.journalTx(from, tx) log.Trace("Pooled new executable transaction", "hash", hash, "from", from, "to", tx.To()) // We've directly injected a replacement transaction, notify subsystems - go pool.txFeed.Send(TxPreEvent{tx}) + go pool.txFeed.Send(NewTxsEvent{types.Transactions{tx}}) return old != nil, nil } @@ -666,7 +698,10 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (bool, error) { } // Mark local addresses and journal local transactions if local { - pool.locals.add(from) + if !pool.locals.contains(from) { + log.Info("Setting new local account", "address", from) + pool.locals.add(from) + } } pool.journalTx(from, tx) @@ -691,12 +726,14 @@ func (pool *TxPool) enqueueTx(hash common.Hash, tx *types.Transaction) (bool, er } // Discard any previous transaction and mark this if old != nil { - delete(pool.all, old.Hash()) + pool.all.Remove(old.Hash()) pool.priced.Removed() queuedReplaceCounter.Inc(1) } - pool.all[hash] = tx - pool.priced.Put(tx) + if pool.all.Get(hash) == nil { + pool.all.Add(tx) + pool.priced.Put(tx) + } return old != nil, nil } @@ -712,10 +749,11 @@ func (pool *TxPool) journalTx(from common.Address, tx *types.Transaction) { } } -// promoteTx adds a transaction to the pending (processable) list of transactions. +// promoteTx adds a transaction to the pending (processable) list of transactions +// and returns whether it was inserted or an older was better. // // Note, this method assumes the pool lock is held! -func (pool *TxPool) promoteTx(addr common.Address, hash common.Hash, tx *types.Transaction) { +func (pool *TxPool) promoteTx(addr common.Address, hash common.Hash, tx *types.Transaction) bool { // Try to insert the transaction into the pending queue if pool.pending[addr] == nil { pool.pending[addr] = newTxList(true) @@ -725,29 +763,29 @@ func (pool *TxPool) promoteTx(addr common.Address, hash common.Hash, tx *types.T inserted, old := list.Add(tx, pool.config.PriceBump) if !inserted { // An older transaction was better, discard this - delete(pool.all, hash) + pool.all.Remove(hash) pool.priced.Removed() pendingDiscardCounter.Inc(1) - return + return false } // Otherwise discard any previous transaction and mark this if old != nil { - delete(pool.all, old.Hash()) + pool.all.Remove(old.Hash()) pool.priced.Removed() pendingReplaceCounter.Inc(1) } // Failsafe to work around direct pending inserts (tests) - if pool.all[hash] == nil { - pool.all[hash] = tx + if pool.all.Get(hash) == nil { + pool.all.Add(tx) pool.priced.Put(tx) } // Set the potentially new pending nonce and notify any subsystems of the new tx pool.beats[addr] = time.Now() pool.pendingState.SetNonce(addr, tx.Nonce()+1) - go pool.txFeed.Send(TxPreEvent{tx}) + return true } // AddLocal enqueues a single transaction into the pool if it is valid, marking @@ -807,17 +845,15 @@ 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)) for i, tx := range txs { var replace bool - if replace, errs[i] = pool.add(tx, local); errs[i] == nil { - if !replace { - from, _ := types.Sender(pool.signer, tx) // already validated - dirty[from] = struct{}{} - } + if replace, errs[i] = pool.add(tx, local); errs[i] == nil && !replace { + from, _ := types.Sender(pool.signer, tx) // already validated + dirty[from] = struct{}{} } } // Only reprocess the internal state if something was actually added @@ -839,7 +875,7 @@ func (pool *TxPool) Status(hashes []common.Hash) []TxStatus { status := make([]TxStatus, len(hashes)) for i, hash := range hashes { - if tx := pool.all[hash]; tx != nil { + if tx := pool.all.Get(hash); tx != nil { from, _ := types.Sender(pool.signer, tx) // already validated if pool.pending[from] != nil && pool.pending[from].txs.items[tx.Nonce()] != nil { status[i] = TxStatusPending @@ -854,38 +890,35 @@ func (pool *TxPool) Status(hashes []common.Hash) []TxStatus { // Get returns a transaction if it is contained in the pool // and nil otherwise. func (pool *TxPool) Get(hash common.Hash) *types.Transaction { - pool.mu.RLock() - defer pool.mu.RUnlock() - - return pool.all[hash] + return pool.all.Get(hash) } // removeTx removes a single transaction from the queue, moving all subsequent // transactions back to the future queue. -func (pool *TxPool) removeTx(hash common.Hash) { +func (pool *TxPool) removeTx(hash common.Hash, outofbound bool) { // Fetch the transaction we wish to delete - tx, ok := pool.all[hash] - if !ok { + tx := pool.all.Get(hash) + if tx == nil { return } addr, _ := types.Sender(pool.signer, tx) // already validated during insertion // Remove it from the list of known transactions - delete(pool.all, hash) - pool.priced.Removed() - + pool.all.Remove(hash) + if outofbound { + pool.priced.Removed() + } // Remove the transaction from the pending lists and reset the account nonce if pending := pool.pending[addr]; pending != nil { if removed, invalids := pending.Remove(tx); removed { - // If no more transactions are left, remove the list + // If no more pending transactions are left, remove the list if pending.Empty() { delete(pool.pending, addr) delete(pool.beats, addr) - } else { - // Otherwise postpone any invalidated transactions - for _, tx := range invalids { - pool.enqueueTx(tx.Hash(), tx) - } + } + // Postpone any invalidated transactions + for _, tx := range invalids { + pool.enqueueTx(tx.Hash(), tx) } // Update the account nonce if needed if nonce := tx.Nonce(); pool.pendingState.GetNonce(addr) > nonce { @@ -907,6 +940,9 @@ func (pool *TxPool) removeTx(hash common.Hash) { // future queue to the set of pending transactions. During this process, all // invalidated transactions (low nonce, low balance) are deleted. func (pool *TxPool) promoteExecutables(accounts []common.Address) { + // Track the promoted transactions to broadcast them at once + var promoted []*types.Transaction + // Gather all the accounts potentially needing updates if accounts == nil { accounts = make([]common.Address, 0, len(pool.queue)) @@ -924,7 +960,7 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) { for _, tx := range list.Forward(pool.currentState.GetNonce(addr)) { hash := tx.Hash() log.Trace("Removed old queued transaction", "hash", hash) - delete(pool.all, hash) + pool.all.Remove(hash) pool.priced.Removed() } // Drop all transactions that are too costly (low balance or out of gas) @@ -932,21 +968,23 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) { for _, tx := range drops { hash := tx.Hash() log.Trace("Removed unpayable queued transaction", "hash", hash) - delete(pool.all, hash) + pool.all.Remove(hash) pool.priced.Removed() queuedNofundsCounter.Inc(1) } // Gather all executable transactions and promote them for _, tx := range list.Ready(pool.pendingState.GetNonce(addr)) { hash := tx.Hash() - log.Trace("Promoting queued transaction", "hash", hash) - pool.promoteTx(addr, hash, tx) + if pool.promoteTx(addr, hash, tx) { + log.Trace("Promoting queued transaction", "hash", hash) + promoted = append(promoted, tx) + } } // Drop all transactions over the allowed limit if !pool.locals.contains(addr) { for _, tx := range list.Cap(int(pool.config.AccountQueue)) { hash := tx.Hash() - delete(pool.all, hash) + pool.all.Remove(hash) pool.priced.Removed() queuedRateLimitCounter.Inc(1) log.Trace("Removed cap-exceeding queued transaction", "hash", hash) @@ -957,6 +995,10 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) { delete(pool.queue, addr) } } + // Notify subsystem for new promoted transactions. + if len(promoted) > 0 { + go pool.txFeed.Send(NewTxsEvent{promoted}) + } // If the pending limit is overflown, start equalizing allowances pending := uint64(0) for _, list := range pool.pending { @@ -965,11 +1007,11 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) { if pending > pool.config.GlobalSlots { pendingBeforeCap := pending // Assemble a spam order to penalize large transactors first - spammers := prque.New() + spammers := prque.New(nil) for addr, list := range pool.pending { // Only evict transactions from high rollers if !pool.locals.contains(addr) && uint64(list.Len()) > pool.config.AccountSlots { - spammers.Push(addr, float32(list.Len())) + spammers.Push(addr, int64(list.Len())) } } // Gradually drop transactions from offenders @@ -991,7 +1033,7 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) { for _, tx := range list.Cap(list.Len() - 1) { // Drop the transaction from the global pools too hash := tx.Hash() - delete(pool.all, hash) + pool.all.Remove(hash) pool.priced.Removed() // Update the account nonce to the dropped transaction @@ -1013,7 +1055,7 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) { for _, tx := range list.Cap(list.Len() - 1) { // Drop the transaction from the global pools too hash := tx.Hash() - delete(pool.all, hash) + pool.all.Remove(hash) pool.priced.Removed() // Update the account nonce to the dropped transaction @@ -1035,7 +1077,7 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) { } if queued > pool.config.GlobalQueue { // Sort all accounts with queued transactions by heartbeat - addresses := make(addresssByHeartbeat, 0, len(pool.queue)) + addresses := make(addressesByHeartbeat, 0, len(pool.queue)) for addr := range pool.queue { if !pool.locals.contains(addr) { // don't drop locals addresses = append(addresses, addressByHeartbeat{addr, pool.beats[addr]}) @@ -1053,7 +1095,7 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) { // Drop all transactions if they are less than the overflow if size := uint64(list.Len()); size <= drop { for _, tx := range list.Flatten() { - pool.removeTx(tx.Hash()) + pool.removeTx(tx.Hash(), true) } drop -= size queuedRateLimitCounter.Inc(int64(size)) @@ -1062,7 +1104,7 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) { // Otherwise drop only last few transactions txs := list.Flatten() for i := len(txs) - 1; i >= 0 && drop > 0; i-- { - pool.removeTx(txs[i].Hash()) + pool.removeTx(txs[i].Hash(), true) drop-- queuedRateLimitCounter.Inc(1) } @@ -1082,7 +1124,7 @@ func (pool *TxPool) demoteUnexecutables() { for _, tx := range list.Forward(nonce) { hash := tx.Hash() log.Trace("Removed old pending transaction", "hash", hash) - delete(pool.all, hash) + pool.all.Remove(hash) pool.priced.Removed() } // Drop all transactions that are too costly (low balance or out of gas), and queue any invalids back for later @@ -1090,7 +1132,7 @@ func (pool *TxPool) demoteUnexecutables() { for _, tx := range drops { hash := tx.Hash() log.Trace("Removed unpayable pending transaction", "hash", hash) - delete(pool.all, hash) + pool.all.Remove(hash) pool.priced.Removed() pendingNofundsCounter.Inc(1) } @@ -1099,7 +1141,7 @@ func (pool *TxPool) demoteUnexecutables() { log.Trace("Demoting pending transaction", "hash", hash) pool.enqueueTx(hash, tx) } - // If there's a gap in front, warn (should never happen) and postpone all transactions + // If there's a gap in front, alert (should never happen) and postpone all transactions if list.Len() > 0 && list.txs.Get(nonce) == nil { for _, tx := range list.Cap(0) { hash := tx.Hash() @@ -1121,17 +1163,18 @@ type addressByHeartbeat struct { heartbeat time.Time } -type addresssByHeartbeat []addressByHeartbeat +type addressesByHeartbeat []addressByHeartbeat -func (a addresssByHeartbeat) Len() int { return len(a) } -func (a addresssByHeartbeat) Less(i, j int) bool { return a[i].heartbeat.Before(a[j].heartbeat) } -func (a addresssByHeartbeat) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a addressesByHeartbeat) Len() int { return len(a) } +func (a addressesByHeartbeat) Less(i, j int) bool { return a[i].heartbeat.Before(a[j].heartbeat) } +func (a addressesByHeartbeat) Swap(i, j int) { a[i], a[j] = a[j], a[i] } // accountSet is simply a set of addresses to check for existence, and a signer // capable of deriving addresses from transactions. type accountSet struct { accounts map[common.Address]struct{} signer types.Signer + cache *[]common.Address } // newAccountSet creates a new address set with an associated signer for sender @@ -1161,4 +1204,83 @@ func (as *accountSet) containsTx(tx *types.Transaction) bool { // add inserts a new address into the set to track. func (as *accountSet) add(addr common.Address) { as.accounts[addr] = struct{}{} + as.cache = nil +} + +// flatten returns the list of addresses within this set, also caching it for later +// reuse. The returned slice should not be changed! +func (as *accountSet) flatten() []common.Address { + if as.cache == nil { + accounts := make([]common.Address, 0, len(as.accounts)) + for account := range as.accounts { + accounts = append(accounts, account) + } + as.cache = &accounts + } + return *as.cache +} + +// txLookup is used internally by TxPool to track transactions while allowing lookup without +// mutex contention. +// +// Note, although this type is properly protected against concurrent access, it +// is **not** a type that should ever be mutated or even exposed outside of the +// transaction pool, since its internal state is tightly coupled with the pools +// internal mechanisms. The sole purpose of the type is to permit out-of-bound +// peeking into the pool in TxPool.Get without having to acquire the widely scoped +// TxPool.mu mutex. +type txLookup struct { + all map[common.Hash]*types.Transaction + lock sync.RWMutex +} + +// newTxLookup returns a new txLookup structure. +func newTxLookup() *txLookup { + return &txLookup{ + all: make(map[common.Hash]*types.Transaction), + } +} + +// Range calls f on each key and value present in the map. +func (t *txLookup) Range(f func(hash common.Hash, tx *types.Transaction) bool) { + t.lock.RLock() + defer t.lock.RUnlock() + + for key, value := range t.all { + if !f(key, value) { + break + } + } +} + +// Get returns a transaction if it exists in the lookup, or nil if not found. +func (t *txLookup) Get(hash common.Hash) *types.Transaction { + t.lock.RLock() + defer t.lock.RUnlock() + + return t.all[hash] +} + +// Count returns the current number of items in the lookup. +func (t *txLookup) Count() int { + t.lock.RLock() + defer t.lock.RUnlock() + + return len(t.all) +} + +// Add adds a transaction to the lookup. +func (t *txLookup) Add(tx *types.Transaction) { + t.lock.Lock() + defer t.lock.Unlock() + + t.all[tx.Hash()] = tx +} + +// Remove removes a transaction from the lookup. +func (t *txLookup) Remove(hash common.Hash) { + t.lock.Lock() + defer t.lock.Unlock() + + delete(t.all, hash) } diff --git a/core/tx_pool_test.go b/core/tx_pool_test.go index cd11f2ba29..e1c2e06696 100644 --- a/core/tx_pool_test.go +++ b/core/tx_pool_test.go @@ -78,8 +78,7 @@ func pricedTransaction(nonce uint64, gaslimit uint64, gasprice *big.Int, key *ec } func setupTxPool() (*TxPool, *ecdsa.PrivateKey) { - db, _ := ethdb.NewMemDatabase() - statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) + statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} key, _ := crypto.GenerateKey() @@ -95,7 +94,7 @@ func validateTxPoolInternals(pool *TxPool) error { // Ensure the total transaction set is consistent with pending + queued pending, queued := pool.stats() - if total := len(pool.all); total != pending+queued { + if total := pool.all.Count(); total != pending+queued { return fmt.Errorf("total transaction count %d != %d pending + %d queued", total, pending, queued) } if priced := pool.priced.items.Len() - pool.priced.stales; priced != pending+queued { @@ -119,21 +118,27 @@ func validateTxPoolInternals(pool *TxPool) error { // validateEvents checks that the correct number of transaction addition events // were fired on the pool's event feed. -func validateEvents(events chan TxPreEvent, count int) error { - for i := 0; i < count; i++ { +func validateEvents(events chan NewTxsEvent, count int) error { + var received []*types.Transaction + + for len(received) < count { select { - case <-events: + case ev := <-events: + received = append(received, ev.Txs...) case <-time.After(time.Second): - return fmt.Errorf("event #%d not fired", i) + return fmt.Errorf("event #%d not fired", len(received)) } } + if len(received) > count { + return fmt.Errorf("more than %d events fired: %v", count, received[count:]) + } select { - case tx := <-events: - return fmt.Errorf("more than %d events fired: %v", count, tx.Tx) + case ev := <-events: + return fmt.Errorf("more than %d events fired: %v", count, ev.Txs) case <-time.After(50 * time.Millisecond): // This branch should be "default", but it's a data race between goroutines, - // reading the event channel and pushng into it, so better wait a bit ensuring + // reading the event channel and pushing into it, so better wait a bit ensuring // really nothing gets injected. } return nil @@ -158,8 +163,7 @@ func (c *testChain) State() (*state.StateDB, error) { // a state change between those fetches. stdb := c.statedb if *c.trigger { - db, _ := ethdb.NewMemDatabase() - c.statedb, _ = state.New(common.Hash{}, state.NewDatabase(db)) + c.statedb, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) // 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)) @@ -175,10 +179,9 @@ func TestStateChangeDuringTransactionPoolReset(t *testing.T) { t.Parallel() var ( - db, _ = ethdb.NewMemDatabase() key, _ = crypto.GenerateKey() address = crypto.PubkeyToAddress(key.PublicKey) - statedb, _ = state.New(common.Hash{}, state.NewDatabase(db)) + statedb, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) trigger = false ) @@ -209,15 +212,10 @@ func TestStateChangeDuringTransactionPoolReset(t *testing.T) { pool.lockedReset(nil, nil) - pendingTx, err := pool.Pending() + _, err := pool.Pending() if err != nil { t.Fatalf("Could not fetch pending transactions: %v", err) } - - for addr, txs := range pendingTx { - t.Logf("%0x: %d\n", addr, len(txs)) - } - nonce = pool.State().GetNonce(address) if nonce != 2 { t.Fatalf("Invalid nonce, want 2, got %d", nonce) @@ -337,8 +335,7 @@ func TestTransactionChainFork(t *testing.T) { addr := crypto.PubkeyToAddress(key.PublicKey) resetState := func() { - db, _ := ethdb.NewMemDatabase() - statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) + statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) statedb.AddBalance(addr, big.NewInt(100000000000000)) pool.chain = &testBlockChain{statedb, 1000000, new(event.Feed)} @@ -350,7 +347,7 @@ func TestTransactionChainFork(t *testing.T) { if _, err := pool.add(tx, false); err != nil { t.Error("didn't expect error", err) } - pool.removeTx(tx.Hash()) + pool.removeTx(tx.Hash(), true) // reset the pool's internal state resetState() @@ -367,8 +364,7 @@ func TestTransactionDoubleNonce(t *testing.T) { addr := crypto.PubkeyToAddress(key.PublicKey) resetState := func() { - db, _ := ethdb.NewMemDatabase() - statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) + statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) statedb.AddBalance(addr, big.NewInt(100000000000000)) pool.chain = &testBlockChain{statedb, 1000000, new(event.Feed)} @@ -405,8 +401,8 @@ func TestTransactionDoubleNonce(t *testing.T) { t.Errorf("transaction mismatch: have %x, want %x", tx.Hash(), tx2.Hash()) } // Ensure the total transaction count is correct - if len(pool.all) != 1 { - t.Error("expected 1 total transactions, got", len(pool.all)) + if pool.all.Count() != 1 { + t.Error("expected 1 total transactions, got", pool.all.Count()) } } @@ -428,8 +424,8 @@ func TestTransactionMissingNonce(t *testing.T) { if pool.queue[addr].Len() != 1 { t.Error("expected 1 queued transaction, got", pool.queue[addr].Len()) } - if len(pool.all) != 1 { - t.Error("expected 1 total transactions, got", len(pool.all)) + if pool.all.Count() != 1 { + t.Error("expected 1 total transactions, got", pool.all.Count()) } } @@ -492,8 +488,8 @@ func TestTransactionDropping(t *testing.T) { if pool.queue[account].Len() != 3 { t.Errorf("queued transaction mismatch: have %d, want %d", pool.queue[account].Len(), 3) } - if len(pool.all) != 6 { - t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), 6) + if pool.all.Count() != 6 { + t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), 6) } pool.lockedReset(nil, nil) if pool.pending[account].Len() != 3 { @@ -502,8 +498,8 @@ func TestTransactionDropping(t *testing.T) { if pool.queue[account].Len() != 3 { t.Errorf("queued transaction mismatch: have %d, want %d", pool.queue[account].Len(), 3) } - if len(pool.all) != 6 { - t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), 6) + if pool.all.Count() != 6 { + t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), 6) } // Reduce the balance of the account, and check that invalidated transactions are dropped pool.currentState.AddBalance(account, big.NewInt(-650)) @@ -527,8 +523,8 @@ func TestTransactionDropping(t *testing.T) { if _, ok := pool.queue[account].txs.items[tx12.Nonce()]; ok { t.Errorf("out-of-fund queued transaction present: %v", tx11) } - if len(pool.all) != 4 { - t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), 4) + if pool.all.Count() != 4 { + t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), 4) } // Reduce the block gas limit, check that invalidated transactions are dropped pool.chain.(*testBlockChain).gasLimit = 100 @@ -546,8 +542,8 @@ func TestTransactionDropping(t *testing.T) { if _, ok := pool.queue[account].txs.items[tx11.Nonce()]; ok { t.Errorf("over-gased queued transaction present: %v", tx11) } - if len(pool.all) != 2 { - t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), 2) + if pool.all.Count() != 2 { + t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), 2) } } @@ -557,74 +553,111 @@ func TestTransactionDropping(t *testing.T) { func TestTransactionPostponing(t *testing.T) { t.Parallel() - // Create a test account and fund it - pool, key := setupTxPool() + // Create the pool to test the postponing with + statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) + blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} + + pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) defer pool.Stop() - account, _ := deriveSender(transaction(0, 0, key)) - pool.currentState.AddBalance(account, big.NewInt(1000)) + // Create two test accounts to produce different gap profiles with + keys := make([]*ecdsa.PrivateKey, 2) + accs := make([]common.Address, len(keys)) + for i := 0; i < len(keys); i++ { + keys[i], _ = crypto.GenerateKey() + accs[i] = crypto.PubkeyToAddress(keys[i].PublicKey) + + pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(50100)) + } // Add a batch consecutive pending transactions for validation - txns := []*types.Transaction{} - for i := 0; i < 100; i++ { - var tx *types.Transaction - if i%2 == 0 { - tx = transaction(uint64(i), 100, key) - } else { - tx = transaction(uint64(i), 500, key) + txs := []*types.Transaction{} + for i, key := range keys { + + for j := 0; j < 100; j++ { + var tx *types.Transaction + if (i+j)%2 == 0 { + tx = transaction(uint64(j), 25000, key) + } else { + tx = transaction(uint64(j), 50000, key) + } + txs = append(txs, tx) + } + } + for i, err := range pool.AddRemotes(txs) { + if err != nil { + t.Fatalf("tx %d: failed to add transactions: %v", i, err) } - pool.promoteTx(account, tx.Hash(), tx) - txns = append(txns, tx) } // Check that pre and post validations leave the pool as is - if pool.pending[account].Len() != len(txns) { - t.Errorf("pending transaction mismatch: have %d, want %d", pool.pending[account].Len(), len(txns)) + if pending := pool.pending[accs[0]].Len() + pool.pending[accs[1]].Len(); pending != len(txs) { + t.Errorf("pending transaction mismatch: have %d, want %d", pending, len(txs)) } if len(pool.queue) != 0 { - t.Errorf("queued transaction mismatch: have %d, want %d", pool.queue[account].Len(), 0) + t.Errorf("queued accounts mismatch: have %d, want %d", len(pool.queue), 0) } - if len(pool.all) != len(txns) { - t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txns)) + if pool.all.Count() != len(txs) { + t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), len(txs)) } pool.lockedReset(nil, nil) - if pool.pending[account].Len() != len(txns) { - t.Errorf("pending transaction mismatch: have %d, want %d", pool.pending[account].Len(), len(txns)) + if pending := pool.pending[accs[0]].Len() + pool.pending[accs[1]].Len(); pending != len(txs) { + t.Errorf("pending transaction mismatch: have %d, want %d", pending, len(txs)) } if len(pool.queue) != 0 { - t.Errorf("queued transaction mismatch: have %d, want %d", pool.queue[account].Len(), 0) + t.Errorf("queued accounts mismatch: have %d, want %d", len(pool.queue), 0) } - if len(pool.all) != len(txns) { - t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txns)) + if pool.all.Count() != len(txs) { + t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), len(txs)) } // Reduce the balance of the account, and check that transactions are reorganised - pool.currentState.AddBalance(account, big.NewInt(-750)) + for _, addr := range accs { + pool.currentState.AddBalance(addr, big.NewInt(-1)) + } pool.lockedReset(nil, nil) - if _, ok := pool.pending[account].txs.items[txns[0].Nonce()]; !ok { - t.Errorf("tx %d: valid and funded transaction missing from pending pool: %v", 0, txns[0]) + // The first account's first transaction remains valid, check that subsequent + // ones are either filtered out, or queued up for later. + if _, ok := pool.pending[accs[0]].txs.items[txs[0].Nonce()]; !ok { + t.Errorf("tx %d: valid and funded transaction missing from pending pool: %v", 0, txs[0]) } - if _, ok := pool.queue[account].txs.items[txns[0].Nonce()]; ok { - t.Errorf("tx %d: valid and funded transaction present in future queue: %v", 0, txns[0]) + if _, ok := pool.queue[accs[0]].txs.items[txs[0].Nonce()]; ok { + t.Errorf("tx %d: valid and funded transaction present in future queue: %v", 0, txs[0]) } - for i, tx := range txns[1:] { + for i, tx := range txs[1:100] { if i%2 == 1 { - if _, ok := pool.pending[account].txs.items[tx.Nonce()]; ok { + if _, ok := pool.pending[accs[0]].txs.items[tx.Nonce()]; ok { t.Errorf("tx %d: valid but future transaction present in pending pool: %v", i+1, tx) } - if _, ok := pool.queue[account].txs.items[tx.Nonce()]; !ok { + if _, ok := pool.queue[accs[0]].txs.items[tx.Nonce()]; !ok { t.Errorf("tx %d: valid but future transaction missing from future queue: %v", i+1, tx) } } else { - if _, ok := pool.pending[account].txs.items[tx.Nonce()]; ok { + if _, ok := pool.pending[accs[0]].txs.items[tx.Nonce()]; ok { t.Errorf("tx %d: out-of-fund transaction present in pending pool: %v", i+1, tx) } - if _, ok := pool.queue[account].txs.items[tx.Nonce()]; ok { + if _, ok := pool.queue[accs[0]].txs.items[tx.Nonce()]; ok { t.Errorf("tx %d: out-of-fund transaction present in future queue: %v", i+1, tx) } } } - if len(pool.all) != len(txns)/2 { - t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txns)/2) + // The second account's first transaction got invalid, check that all transactions + // are either filtered out, or queued up for later. + if pool.pending[accs[1]] != nil { + t.Errorf("invalidated account still has pending transactions") + } + for i, tx := range txs[100:] { + if i%2 == 1 { + if _, ok := pool.queue[accs[1]].txs.items[tx.Nonce()]; !ok { + t.Errorf("tx %d: valid but future transaction missing from future queue: %v", 100+i, tx) + } + } else { + if _, ok := pool.queue[accs[1]].txs.items[tx.Nonce()]; ok { + t.Errorf("tx %d: out-of-fund transaction present in future queue: %v", 100+i, tx) + } + } + } + if pool.all.Count() != len(txs)/2 { + t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), len(txs)/2) } } @@ -642,7 +675,7 @@ func TestTransactionGapFilling(t *testing.T) { pool.currentState.AddBalance(account, big.NewInt(1000000)) // Keep track of transaction events to ensure all executables get announced - events := make(chan TxPreEvent, testTxPoolConfig.AccountQueue+5) + events := make(chan NewTxsEvent, testTxPoolConfig.AccountQueue+5) sub := pool.txFeed.Subscribe(events) defer sub.Unsubscribe() @@ -715,8 +748,8 @@ func TestTransactionQueueAccountLimiting(t *testing.T) { } } } - if len(pool.all) != int(testTxPoolConfig.AccountQueue) { - t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), testTxPoolConfig.AccountQueue) + if pool.all.Count() != int(testTxPoolConfig.AccountQueue) { + t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), testTxPoolConfig.AccountQueue) } } @@ -736,8 +769,7 @@ func testTransactionQueueGlobalLimiting(t *testing.T, nolocals bool) { t.Parallel() // Create the pool to test the limit enforcement with - db, _ := ethdb.NewMemDatabase() - statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) + statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} config := testTxPoolConfig @@ -825,8 +857,7 @@ func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) { evictionInterval = time.Second // Create the pool to test the non-expiration enforcement - db, _ := ethdb.NewMemDatabase() - statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) + statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} config := testTxPoolConfig @@ -895,7 +926,7 @@ func TestTransactionPendingLimiting(t *testing.T) { pool.currentState.AddBalance(account, big.NewInt(1000000)) // Keep track of transaction events to ensure all executables get announced - events := make(chan TxPreEvent, testTxPoolConfig.AccountQueue+5) + events := make(chan NewTxsEvent, testTxPoolConfig.AccountQueue+5) sub := pool.txFeed.Subscribe(events) defer sub.Unsubscribe() @@ -911,8 +942,8 @@ func TestTransactionPendingLimiting(t *testing.T) { t.Errorf("tx %d: queue size mismatch: have %d, want %d", i, pool.queue[account].Len(), 0) } } - if len(pool.all) != int(testTxPoolConfig.AccountQueue+5) { - t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), testTxPoolConfig.AccountQueue+5) + if pool.all.Count() != int(testTxPoolConfig.AccountQueue+5) { + t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), testTxPoolConfig.AccountQueue+5) } if err := validateEvents(events, int(testTxPoolConfig.AccountQueue+5)); err != nil { t.Fatalf("event firing failed: %v", err) @@ -949,11 +980,11 @@ func testTransactionLimitingEquivalency(t *testing.T, origin uint64) { account2, _ := deriveSender(transaction(0, 0, key2)) pool2.currentState.AddBalance(account2, big.NewInt(1000000)) - txns := []*types.Transaction{} + txs := []*types.Transaction{} for i := uint64(0); i < testTxPoolConfig.AccountQueue+5; i++ { - txns = append(txns, transaction(origin+i, 100000, key2)) + txs = append(txs, transaction(origin+i, 100000, key2)) } - pool2.AddRemotes(txns) + pool2.AddRemotes(txs) // Ensure the batch optimization honors the same pool mechanics if len(pool1.pending) != len(pool2.pending) { @@ -962,8 +993,8 @@ func testTransactionLimitingEquivalency(t *testing.T, origin uint64) { if len(pool1.queue) != len(pool2.queue) { t.Errorf("queued transaction count mismatch: one-by-one algo: %d, batch algo: %d", len(pool1.queue), len(pool2.queue)) } - if len(pool1.all) != len(pool2.all) { - t.Errorf("total transaction count mismatch: one-by-one algo %d, batch algo %d", len(pool1.all), len(pool2.all)) + if pool1.all.Count() != pool2.all.Count() { + t.Errorf("total transaction count mismatch: one-by-one algo %d, batch algo %d", pool1.all.Count(), pool2.all.Count()) } if err := validateTxPoolInternals(pool1); err != nil { t.Errorf("pool 1 internal state corrupted: %v", err) @@ -980,8 +1011,7 @@ func TestTransactionPendingGlobalLimiting(t *testing.T) { t.Parallel() // Create the pool to test the limit enforcement with - db, _ := ethdb.NewMemDatabase() - statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) + statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} config := testTxPoolConfig @@ -1027,8 +1057,7 @@ func TestTransactionCapClearsFromAll(t *testing.T) { t.Parallel() // Create the pool to test the limit enforcement with - db, _ := ethdb.NewMemDatabase() - statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) + statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} config := testTxPoolConfig @@ -1062,12 +1091,11 @@ func TestTransactionPendingMinimumAllowance(t *testing.T) { t.Parallel() // Create the pool to test the limit enforcement with - db, _ := ethdb.NewMemDatabase() - statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) + statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} config := testTxPoolConfig - config.GlobalSlots = 0 + config.GlobalSlots = 1 pool := NewTxPool(config, params.TestChainConfig, blockchain) defer pool.Stop() @@ -1111,20 +1139,19 @@ func TestTransactionPoolRepricing(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - db, _ := ethdb.NewMemDatabase() - statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) + statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) defer pool.Stop() // Keep track of transaction events to ensure all executables get announced - events := make(chan TxPreEvent, 32) + events := make(chan NewTxsEvent, 32) sub := pool.txFeed.Subscribe(events) defer sub.Unsubscribe() // Create a number of test accounts and fund them - keys := make([]*ecdsa.PrivateKey, 3) + keys := make([]*ecdsa.PrivateKey, 4) for i := 0; i < len(keys); i++ { keys[i], _ = crypto.GenerateKey() pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000)) @@ -1136,24 +1163,28 @@ func TestTransactionPoolRepricing(t *testing.T) { txs = append(txs, pricedTransaction(1, 100000, big.NewInt(1), keys[0])) txs = append(txs, pricedTransaction(2, 100000, big.NewInt(2), keys[0])) + txs = append(txs, pricedTransaction(0, 100000, big.NewInt(1), keys[1])) txs = append(txs, pricedTransaction(1, 100000, big.NewInt(2), keys[1])) - txs = append(txs, pricedTransaction(2, 100000, big.NewInt(1), keys[1])) - txs = append(txs, pricedTransaction(3, 100000, big.NewInt(2), keys[1])) + txs = append(txs, pricedTransaction(2, 100000, big.NewInt(2), keys[1])) - ltx := pricedTransaction(0, 100000, big.NewInt(1), keys[2]) + txs = append(txs, pricedTransaction(1, 100000, big.NewInt(2), keys[2])) + txs = append(txs, pricedTransaction(2, 100000, big.NewInt(1), keys[2])) + txs = append(txs, pricedTransaction(3, 100000, big.NewInt(2), keys[2])) + + ltx := pricedTransaction(0, 100000, big.NewInt(1), keys[3]) // Import the batch and that both pending and queued transactions match up pool.AddRemotes(txs) pool.AddLocal(ltx) pending, queued := pool.Stats() - if pending != 4 { - t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 4) + if pending != 7 { + t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 7) } if queued != 3 { t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 3) } - if err := validateEvents(events, 4); err != nil { + if err := validateEvents(events, 7); err != nil { t.Fatalf("original event firing failed: %v", err) } if err := validateTxPoolInternals(pool); err != nil { @@ -1166,8 +1197,8 @@ func TestTransactionPoolRepricing(t *testing.T) { if pending != 2 { t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2) } - if queued != 3 { - t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 3) + if queued != 5 { + t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 5) } if err := validateEvents(events, 0); err != nil { t.Fatalf("reprice event firing failed: %v", err) @@ -1179,7 +1210,10 @@ func TestTransactionPoolRepricing(t *testing.T) { if err := pool.AddRemote(pricedTransaction(1, 100000, big.NewInt(1), keys[0])); err != ErrUnderpriced { t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, ErrUnderpriced) } - if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(1), keys[1])); err != ErrUnderpriced { + if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(1), keys[1])); err != ErrUnderpriced { + t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, ErrUnderpriced) + } + if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(1), keys[2])); err != ErrUnderpriced { t.Fatalf("adding underpriced queued transaction error mismatch: have %v, want %v", err, ErrUnderpriced) } if err := validateEvents(events, 0); err != nil { @@ -1189,7 +1223,7 @@ func TestTransactionPoolRepricing(t *testing.T) { t.Fatalf("pool internal state corrupted: %v", err) } // However we can add local underpriced transactions - tx := pricedTransaction(1, 100000, big.NewInt(1), keys[2]) + tx := pricedTransaction(1, 100000, big.NewInt(1), keys[3]) if err := pool.AddLocal(tx); err != nil { t.Fatalf("failed to add underpriced local transaction: %v", err) } @@ -1202,6 +1236,22 @@ func TestTransactionPoolRepricing(t *testing.T) { if err := validateTxPoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } + // And we can fill gaps with properly priced transactions + if err := pool.AddRemote(pricedTransaction(1, 100000, big.NewInt(2), keys[0])); err != nil { + t.Fatalf("failed to add pending transaction: %v", err) + } + if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(2), keys[1])); err != nil { + t.Fatalf("failed to add pending transaction: %v", err) + } + if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(2), keys[2])); err != nil { + t.Fatalf("failed to add queued transaction: %v", err) + } + if err := validateEvents(events, 5); err != nil { + t.Fatalf("post-reprice event firing failed: %v", err) + } + if err := validateTxPoolInternals(pool); err != nil { + t.Fatalf("pool internal state corrupted: %v", err) + } } // Tests that setting the transaction pool gas price to a higher value does not @@ -1210,8 +1260,7 @@ func TestTransactionPoolRepricingKeepsLocals(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - db, _ := ethdb.NewMemDatabase() - statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) + statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) @@ -1225,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) } } @@ -1273,8 +1322,7 @@ func TestTransactionPoolUnderpricing(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - db, _ := ethdb.NewMemDatabase() - statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) + statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} config := testTxPoolConfig @@ -1285,12 +1333,12 @@ func TestTransactionPoolUnderpricing(t *testing.T) { defer pool.Stop() // Keep track of transaction events to ensure all executables get announced - events := make(chan TxPreEvent, 32) + events := make(chan NewTxsEvent, 32) sub := pool.txFeed.Subscribe(events) defer sub.Unsubscribe() // Create a number of test accounts and fund them - keys := make([]*ecdsa.PrivateKey, 3) + keys := make([]*ecdsa.PrivateKey, 4) for i := 0; i < len(keys); i++ { keys[i], _ = crypto.GenerateKey() pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000)) @@ -1327,13 +1375,13 @@ func TestTransactionPoolUnderpricing(t *testing.T) { t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, ErrUnderpriced) } // Ensure that adding high priced transactions drops cheap ones, but not own - if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(3), keys[1])); err != nil { + if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(3), keys[1])); err != nil { // +K1:0 => -K1:1 => Pend K0:0, K0:1, K1:0, K2:0; Que - t.Fatalf("failed to add well priced transaction: %v", err) } - if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(4), keys[1])); err != nil { + if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(4), keys[1])); err != nil { // +K1:2 => -K0:0 => Pend K1:0, K2:0; Que K0:1 K1:2 t.Fatalf("failed to add well priced transaction: %v", err) } - if err := pool.AddRemote(pricedTransaction(3, 100000, big.NewInt(5), keys[1])); err != nil { + if err := pool.AddRemote(pricedTransaction(3, 100000, big.NewInt(5), keys[1])); err != nil { // +K1:3 => -K0:1 => Pend K1:0, K2:0; Que K1:2 K1:3 t.Fatalf("failed to add well priced transaction: %v", err) } pending, queued = pool.Stats() @@ -1343,25 +1391,29 @@ func TestTransactionPoolUnderpricing(t *testing.T) { if queued != 2 { t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2) } - if err := validateEvents(events, 2); err != nil { - t.Fatalf("additional event firing failed: %v", err) - } - if err := validateTxPoolInternals(pool); err != nil { - t.Fatalf("pool internal state corrupted: %v", err) - } - // Ensure that adding local transactions can push out even higher priced ones - tx := pricedTransaction(1, 100000, big.NewInt(0), keys[2]) - if err := pool.AddLocal(tx); err != nil { - t.Fatalf("failed to add underpriced local transaction: %v", err) - } - pending, queued = pool.Stats() - if pending != 2 { - t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2) - } - if queued != 2 { - t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2) - } if err := validateEvents(events, 1); err != nil { + t.Fatalf("additional event firing failed: %v", err) + } + if err := validateTxPoolInternals(pool); err != nil { + t.Fatalf("pool internal state corrupted: %v", err) + } + // Ensure that adding local transactions can push out even higher priced ones + ltx = pricedTransaction(1, 100000, big.NewInt(0), keys[2]) + if err := pool.AddLocal(ltx); err != nil { + t.Fatalf("failed to append underpriced local transaction: %v", err) + } + ltx = pricedTransaction(0, 100000, big.NewInt(0), keys[3]) + if err := pool.AddLocal(ltx); err != nil { + t.Fatalf("failed to add new underpriced local transaction: %v", err) + } + pending, queued = pool.Stats() + if pending != 3 { + t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3) + } + if queued != 1 { + t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1) + } + if err := validateEvents(events, 2); err != nil { t.Fatalf("local event firing failed: %v", err) } if err := validateTxPoolInternals(pool); err != nil { @@ -1369,21 +1421,87 @@ func TestTransactionPoolUnderpricing(t *testing.T) { } } +// Tests that more expensive transactions push out cheap ones from the pool, but +// without producing instability by creating gaps that start jumping transactions +// back and forth between queued/pending. +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())) + blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} + + config := testTxPoolConfig + config.GlobalSlots = 128 + config.GlobalQueue = 0 + + pool := NewTxPool(config, params.TestChainConfig, blockchain) + defer pool.Stop() + + // Keep track of transaction events to ensure all executables get announced + events := make(chan NewTxsEvent, 32) + sub := pool.txFeed.Subscribe(events) + defer sub.Unsubscribe() + + // Create a number of test accounts and fund them + keys := make([]*ecdsa.PrivateKey, 2) + for i := 0; i < len(keys); i++ { + keys[i], _ = crypto.GenerateKey() + pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000)) + } + // Fill up the entire queue with the same transaction price points + txs := types.Transactions{} + for i := uint64(0); i < config.GlobalSlots; i++ { + txs = append(txs, pricedTransaction(i, 100000, big.NewInt(1), keys[0])) + } + pool.AddRemotes(txs) + + pending, queued := pool.Stats() + if pending != int(config.GlobalSlots) { + t.Fatalf("pending transactions mismatched: have %d, want %d", pending, config.GlobalSlots) + } + if queued != 0 { + t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) + } + if err := validateEvents(events, int(config.GlobalSlots)); err != nil { + t.Fatalf("original event firing failed: %v", err) + } + if err := validateTxPoolInternals(pool); err != nil { + t.Fatalf("pool internal state corrupted: %v", err) + } + // Ensure that adding high priced transactions drops a cheap, but doesn't produce a gap + if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(3), keys[1])); err != nil { + t.Fatalf("failed to add well priced transaction: %v", err) + } + pending, queued = pool.Stats() + if pending != int(config.GlobalSlots) { + t.Fatalf("pending transactions mismatched: have %d, want %d", pending, config.GlobalSlots) + } + if queued != 0 { + t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) + } + if err := validateEvents(events, 1); err != nil { + t.Fatalf("additional event firing failed: %v", err) + } + if err := validateTxPoolInternals(pool); err != nil { + t.Fatalf("pool internal state corrupted: %v", err) + } +} + // Tests that the pool rejects replacement transactions that don't meet the minimum // price bump required. func TestTransactionReplacement(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - db, _ := ethdb.NewMemDatabase() - statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) + statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) defer pool.Stop() // Keep track of transaction events to ensure all executables get announced - events := make(chan TxPreEvent, 32) + events := make(chan NewTxsEvent, 32) sub := pool.txFeed.Subscribe(events) defer sub.Unsubscribe() @@ -1470,8 +1588,7 @@ func testTransactionJournaling(t *testing.T, nolocals bool) { os.Remove(journal) // Create the original pool to inject transaction into the journal - db, _ := ethdb.NewMemDatabase() - statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) + statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} config := testTxPoolConfig @@ -1569,8 +1686,7 @@ func TestTransactionStatusCheck(t *testing.T) { t.Parallel() // Create the pool to test the status retrievals with - db, _ := ethdb.NewMemDatabase() - statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) + statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) diff --git a/core/types/block.go b/core/types/block.go index ffe3173427..b84e13c65a 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -19,17 +19,17 @@ package types import ( "encoding/binary" - "fmt" "io" "math/big" + "reflect" "sort" "sync/atomic" "time" "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,27 +102,16 @@ func (h *Header) Hash() common.Hash { return rlpHash(h) } -// HashNoNonce returns the hash which is used as input for the proof-of-work search. -func (h *Header) HashNoNonce() common.Hash { - return rlpHash([]interface{}{ - h.ParentHash, - h.UncleHash, - h.Coinbase, - h.Root, - h.TxHash, - h.ReceiptHash, - h.Bloom, - h.Difficulty, - h.Number, - h.GasLimit, - h.GasUsed, - h.Time, - h.Extra, - }) +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 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 @@ -318,10 +307,8 @@ func (b *Block) Header() *Header { return CopyHeader(b.header) } // Body returns the non-header content of the block. func (b *Block) Body() *Body { return &Body{b.transactions, b.uncles} } -func (b *Block) HashNoNonce() common.Hash { - return b.header.HashNoNonce() -} - +// Size returns the true RLP encoded storage size of the block, either by encoding +// and returning it, or returning a previsouly cached value. func (b *Block) Size() common.StorageSize { if size := b.size.Load(); size != nil { return size.(common.StorageSize) @@ -380,40 +367,6 @@ func (b *Block) Hash() common.Hash { return v } -func (b *Block) String() string { - str := fmt.Sprintf(`Block(#%v): Size: %v { -MinerHash: %x -%v -Transactions: -%v -Uncles: -%v -} -`, b.Number(), b.Size(), b.header.HashNoNonce(), b.header, b.transactions, b.uncles) - return str -} - -func (h *Header) String() string { - return fmt.Sprintf(`Header(%x): -[ - ParentHash: %x - UncleHash: %x - Coinbase: %x - Root: %x - TxSha %x - ReceiptSha: %x - Bloom: %x - Difficulty: %v - Number: %v - GasLimit: %v - GasUsed: %v - Time: %v - Extra: %s - MixDigest: %x - Nonce: %x -]`, h.Hash(), h.ParentHash, h.UncleHash, h.Coinbase, h.Root, h.TxHash, h.ReceiptHash, h.Bloom, h.Difficulty, h.Number, h.GasLimit, h.GasUsed, h.Time, h.Extra, h.MixDigest, h.Nonce) -} - type Blocks []*Block type BlockBy func(b1, b2 *Block) bool diff --git a/core/types/bloom9.go b/core/types/bloom9.go index a76b6f33c5..d045c9e667 100644 --- a/core/types/bloom9.go +++ b/core/types/bloom9.go @@ -113,7 +113,7 @@ func LogsBloom(logs []*Log) *big.Int { } func bloom9(b []byte) *big.Int { - b = crypto.Keccak256(b[:]) + b = crypto.Keccak256(b) r := new(big.Int) @@ -130,7 +130,7 @@ var Bloom9 = bloom9 func BloomLookup(bin Bloom, topic bytesBacked) bool { bloom := bin.Big() - cmp := bloom9(topic.Bytes()[:]) + cmp := bloom9(topic.Bytes()) return bloom.And(bloom, cmp).Cmp(cmp) == 0 } diff --git a/core/types/gen_header_json.go b/core/types/gen_header_json.go index 1b92cd9cf4..59a1c9c439 100644 --- a/core/types/gen_header_json.go +++ b/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/core/types/gen_log_json.go b/core/types/gen_log_json.go index 1b5ae3c653..6e94339478 100644 --- a/core/types/gen_log_json.go +++ b/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/core/types/gen_receipt_json.go b/core/types/gen_receipt_json.go index c297adebb6..5c807a4ccb 100644 --- a/core/types/gen_receipt_json.go +++ b/core/types/gen_receipt_json.go @@ -12,10 +12,11 @@ import ( var _ = (*receiptMarshaling)(nil) +// MarshalJSON marshals as JSON. func (r Receipt) MarshalJSON() ([]byte, error) { type Receipt struct { PostState hexutil.Bytes `json:"root"` - Status hexutil.Uint `json:"status"` + Status hexutil.Uint64 `json:"status"` CumulativeGasUsed hexutil.Uint64 `json:"cumulativeGasUsed" gencodec:"required"` Bloom Bloom `json:"logsBloom" gencodec:"required"` Logs []*Log `json:"logs" gencodec:"required"` @@ -25,7 +26,7 @@ func (r Receipt) MarshalJSON() ([]byte, error) { } var enc Receipt enc.PostState = r.PostState - enc.Status = hexutil.Uint(r.Status) + enc.Status = hexutil.Uint64(r.Status) enc.CumulativeGasUsed = hexutil.Uint64(r.CumulativeGasUsed) enc.Bloom = r.Bloom enc.Logs = r.Logs @@ -35,10 +36,11 @@ func (r Receipt) MarshalJSON() ([]byte, error) { return json.Marshal(&enc) } +// UnmarshalJSON unmarshals from JSON. func (r *Receipt) UnmarshalJSON(input []byte) error { type Receipt struct { PostState *hexutil.Bytes `json:"root"` - Status *hexutil.Uint `json:"status"` + Status *hexutil.Uint64 `json:"status"` CumulativeGasUsed *hexutil.Uint64 `json:"cumulativeGasUsed" gencodec:"required"` Bloom *Bloom `json:"logsBloom" gencodec:"required"` Logs []*Log `json:"logs" gencodec:"required"` @@ -54,7 +56,7 @@ func (r *Receipt) UnmarshalJSON(input []byte) error { r.PostState = *dec.PostState } if dec.Status != nil { - r.Status = uint(*dec.Status) + r.Status = uint64(*dec.Status) } if dec.CumulativeGasUsed == nil { return errors.New("missing required field 'cumulativeGasUsed' for Receipt") diff --git a/core/types/log.go b/core/types/log.go index be5de38da7..864af5ef41 100644 --- a/core/types/log.go +++ b/core/types/log.go @@ -17,7 +17,6 @@ package types import ( - "fmt" "io" "github.com/ethereum/go-ethereum/common" @@ -48,7 +47,7 @@ type Log struct { TxIndex uint `json:"transactionIndex" gencodec:"required"` // hash of the block in which the transaction was included BlockHash common.Hash `json:"blockHash"` - // index of the log in the receipt + // index of the log in the block Index uint `json:"logIndex" gencodec:"required"` // The Removed field is true if this log was reverted due to a chain reorganisation. @@ -69,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 @@ -95,10 +98,6 @@ func (l *Log) DecodeRLP(s *rlp.Stream) error { return err } -func (l *Log) String() string { - return fmt.Sprintf(`log: %x %x %x %x %d %x %d`, l.Address, l.Topics, l.Data, l.TxHash, l.TxIndex, l.BlockHash, l.Index) -} - // LogForStorage is a wrapper around a Log that flattens and parses the entire content of // a log including non-consensus fields. type LogForStorage Log @@ -106,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/core/types/receipt.go b/core/types/receipt.go index 208d54aaa1..0ba2f6e994 100644 --- a/core/types/receipt.go +++ b/core/types/receipt.go @@ -20,6 +20,7 @@ import ( "bytes" "fmt" "io" + "unsafe" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -35,17 +36,17 @@ var ( const ( // ReceiptStatusFailed is the status code of a transaction if execution failed. - ReceiptStatusFailed = uint(0) + ReceiptStatusFailed = uint64(0) // ReceiptStatusSuccessful is the status code of a transaction if execution succeeded. - ReceiptStatusSuccessful = uint(1) + ReceiptStatusSuccessful = uint64(1) ) // Receipt represents the results of a transaction. type Receipt struct { // Consensus fields PostState []byte `json:"root"` - Status uint `json:"status"` + Status uint64 `json:"status"` CumulativeGasUsed uint64 `json:"cumulativeGasUsed" gencodec:"required"` Bloom Bloom `json:"logsBloom" gencodec:"required"` Logs []*Log `json:"logs" gencodec:"required"` @@ -58,7 +59,7 @@ type Receipt struct { type receiptMarshaling struct { PostState hexutil.Bytes - Status hexutil.Uint + Status hexutil.Uint64 CumulativeGasUsed hexutil.Uint64 GasUsed hexutil.Uint64 } @@ -71,7 +72,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 @@ -136,12 +148,16 @@ func (r *Receipt) statusEncoding() []byte { return r.PostState } -// String implements the Stringer interface. -func (r *Receipt) String() string { - if len(r.PostState) == 0 { - return fmt.Sprintf("receipt{status=%d cgas=%v bloom=%x logs=%v}", r.Status, r.CumulativeGasUsed, r.Bloom, r.Logs) +// Size returns the approximate memory used by all internal contents. It is used +// to approximate and limit the memory consumption of various caches. +func (r *Receipt) Size() common.StorageSize { + size := common.StorageSize(unsafe.Sizeof(*r)) + common.StorageSize(len(r.PostState)) + + size += common.StorageSize(len(r.Logs)) * common.StorageSize(unsafe.Sizeof(Log{})) + for _, log := range r.Logs { + size += common.StorageSize(len(log.Topics)*common.HashLength + len(log.Data)) } - return fmt.Sprintf("receipt{med=%x cgas=%v bloom=%x logs=%v}", r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs) + return size } // ReceiptForStorage is a wrapper around a Receipt that flattens and parses the @@ -154,7 +170,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)), @@ -169,19 +184,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/core/types/transaction.go b/core/types/transaction.go index a7ed211e42..ba3d5de91d 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -19,7 +19,6 @@ package types import ( "container/heap" "errors" - "fmt" "io" "math/big" "sync/atomic" @@ -34,18 +33,8 @@ import ( var ( ErrInvalidSig = errors.New("invalid transaction v, r, s values") - errNoSigner = errors.New("missing signing methods") ) -// deriveSigner makes a *best* guess about which signer to use. -func deriveSigner(V *big.Int) Signer { - if V.Sign() != 0 && isProtectedV(V) { - return NewEIP155Signer(deriveChainId(V)) - } else { - return HomesteadSigner{} - } -} - type Transaction struct { data txdata // caches @@ -130,7 +119,7 @@ func isProtectedV(V *big.Int) bool { v := V.Uint64() return v != 27 && v != 28 } - // anything not 27 or 28 are considered unprotected + // anything not 27 or 28 is considered protected return true } @@ -164,16 +153,21 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { if err := dec.UnmarshalJSON(input); err != nil { return err } - var V byte - if isProtectedV(dec.V) { - chainID := deriveChainId(dec.V).Uint64() - V = byte(dec.V.Uint64() - 35 - 2*chainID) - } else { - V = byte(dec.V.Uint64() - 27) - } - if !crypto.ValidateSignatureValues(V, dec.R, dec.S, false) { - return ErrInvalidSig + + withSignature := dec.V.Sign() != 0 || dec.R.Sign() != 0 || dec.S.Sign() != 0 + if withSignature { + var V byte + if isProtectedV(dec.V) { + chainID := deriveChainId(dec.V).Uint64() + V = byte(dec.V.Uint64() - 35 - 2*chainID) + } else { + V = byte(dec.V.Uint64() - 27) + } + if !crypto.ValidateSignatureValues(V, dec.R, dec.S, false) { + return ErrInvalidSig + } } + *tx = Transaction{data: dec} return nil } @@ -206,6 +200,8 @@ func (tx *Transaction) Hash() common.Hash { return v } +// Size returns the true RLP encoded storage size of the transaction, either by +// encoding and returning it, or returning a previsouly cached value. func (tx *Transaction) Size() common.StorageSize { if size := tx.size.Load(); size != nil { return size.(common.StorageSize) @@ -238,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 { @@ -260,58 +256,6 @@ func (tx *Transaction) RawSignatureValues() (*big.Int, *big.Int, *big.Int) { return tx.data.V, tx.data.R, tx.data.S } -func (tx *Transaction) String() string { - var from, to string - if tx.data.V != nil { - // make a best guess about the signer and use that to derive - // the sender. - signer := deriveSigner(tx.data.V) - if f, err := Sender(signer, tx); err != nil { // derive but don't cache - from = "[invalid sender: invalid sig]" - } else { - from = fmt.Sprintf("%x", f[:]) - } - } else { - from = "[invalid sender: nil V field]" - } - - if tx.data.Recipient == nil { - to = "[contract creation]" - } else { - to = fmt.Sprintf("%x", tx.data.Recipient[:]) - } - enc, _ := rlp.EncodeToBytes(&tx.data) - return fmt.Sprintf(` - TX(%x) - Contract: %v - From: %s - To: %s - Nonce: %v - GasPrice: %#x - GasLimit %#x - Value: %#x - Data: 0x%x - V: %#x - R: %#x - S: %#x - Hex: %x -`, - tx.Hash(), - tx.data.Recipient == nil, - from, - to, - tx.data.AccountNonce, - tx.data.Price, - tx.data.GasLimit, - tx.data.Amount, - tx.data.Payload, - tx.data.V, - tx.data.R, - tx.data.S, - enc, - ) -} - // Transactions is a Transaction slice type for basic sorting. type Transactions []*Transaction @@ -327,9 +271,9 @@ func (s Transactions) GetRlp(i int) []byte { return enc } -// TxDifference returns a new set t which is the difference between a to b. -func TxDifference(a, b Transactions) (keep Transactions) { - keep = make(Transactions, 0, len(a)) +// TxDifference returns a new set which is the difference between a and b. +func TxDifference(a, b Transactions) Transactions { + keep := make(Transactions, 0, len(a)) remove := make(map[common.Hash]struct{}) for _, tx := range b { @@ -391,11 +335,14 @@ type TransactionsByPriceAndNonce struct { func NewTransactionsByPriceAndNonce(signer Signer, txs map[common.Address]Transactions) *TransactionsByPriceAndNonce { // Initialize a price based heap with the head transactions heads := make(TxByPrice, 0, len(txs)) - for _, accTxs := range txs { + for from, accTxs := range txs { heads = append(heads, accTxs[0]) // Ensure the sender address is from the signer acc, _ := Sender(signer, accTxs[0]) txs[acc] = accTxs[1:] + if from != acc { + delete(txs, from) + } } heap.Init(&heads) diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index dfc84fdac7..63132048ee 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -43,7 +43,7 @@ func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer { var signer Signer switch { case config.IsEIP155(blockNumber): - signer = NewEIP155Signer(config.ChainId) + signer = NewEIP155Signer(config.ChainID) case config.IsHomestead(blockNumber): signer = HomesteadSigner{} default: @@ -136,7 +136,7 @@ func (s EIP155Signer) Sender(tx *Transaction) (common.Address, error) { return recoverPlain(s.Hash(tx), tx.data.R, tx.data.S, V, true) } -// WithSignature returns a new transaction with the given signature. This signature +// SignatureValues returns signature values. This signature // needs to be in the [R || S || V] format where V is 0 or 1. func (s EIP155Signer) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) { R, S, V, err = HomesteadSigner{}.SignatureValues(tx, sig) @@ -227,13 +227,13 @@ func recoverPlain(sighash common.Hash, R, S, Vb *big.Int, homestead bool) (commo if !crypto.ValidateSignatureValues(V, R, S, homestead) { return common.Address{}, ErrInvalidSig } - // encode the snature in uncompressed format + // encode the signature in uncompressed format r, s := R.Bytes(), S.Bytes() sig := make([]byte, 65) copy(sig[32-len(r):32], r) copy(sig[64-len(s):64], s) sig[64] = V - // recover the public key from the snature + // recover the public key from the signature pub, err := crypto.Ecrecover(sighash[:], sig) if err != nil { return common.Address{}, err diff --git a/core/types/transaction_test.go b/core/types/transaction_test.go index d1861b14cd..f38d8e7177 100644 --- a/core/types/transaction_test.go +++ b/core/types/transaction_test.go @@ -165,28 +165,13 @@ func TestTransactionPriceNonceSort(t *testing.T) { t.Errorf("invalid nonce ordering: tx #%d (A=%x N=%v) < tx #%d (A=%x N=%v)", i, fromi[:4], txi.Nonce(), i+j, fromj[:4], txj.Nonce()) } } - // Find the previous and next nonce of this account - prev, next := i-1, i+1 - for j := i - 1; j >= 0; j-- { - if fromj, _ := Sender(signer, txs[j]); fromi == fromj { - prev = j - break - } - } - for j := i + 1; j < len(txs); j++ { - if fromj, _ := Sender(signer, txs[j]); fromi == fromj { - next = j - break - } - } - // Make sure that in between the neighbor nonces, the transaction is correctly positioned price wise - for j := prev + 1; j < next; j++ { - fromj, _ := Sender(signer, txs[j]) - if j < i && txs[j].GasPrice().Cmp(txi.GasPrice()) < 0 { - t.Errorf("invalid gasprice ordering: tx #%d (A=%x P=%v) < tx #%d (A=%x P=%v)", j, fromj[:4], txs[j].GasPrice(), i, fromi[:4], txi.GasPrice()) - } - if j > i && txs[j].GasPrice().Cmp(txi.GasPrice()) > 0 { - t.Errorf("invalid gasprice ordering: tx #%d (A=%x P=%v) > tx #%d (A=%x P=%v)", j, fromj[:4], txs[j].GasPrice(), i, fromi[:4], txi.GasPrice()) + + // If the next tx has different from account, the price must be lower than the current one + if i+1 < len(txs) { + next := txs[i+1] + fromNext, _ := Sender(signer, next) + if fromi != fromNext && txi.GasPrice().Cmp(next.GasPrice()) < 0 { + t.Errorf("invalid gasprice ordering: tx #%d (A=%x P=%v) < tx #%d (A=%x P=%v)", i, fromi[:4], txi.GasPrice(), i+1, fromNext[:4], next.GasPrice()) } } } @@ -200,6 +185,7 @@ func TestTransactionJSON(t *testing.T) { } signer := NewEIP155Signer(common.Big1) + transactions := make([]*Transaction, 0, 50) for i := uint64(0); i < 25; i++ { var tx *Transaction switch i % 2 { @@ -208,20 +194,25 @@ func TestTransactionJSON(t *testing.T) { case 1: tx = NewContractCreation(i, common.Big0, 1, common.Big2, []byte("abcdef")) } + transactions = append(transactions, tx) - tx, err := SignTx(tx, signer, key) + signedTx, err := SignTx(tx, signer, key) if err != nil { t.Fatalf("could not sign transaction: %v", err) } + transactions = append(transactions, signedTx) + } + + for _, tx := range transactions { data, err := json.Marshal(tx) if err != nil { - t.Errorf("json.Marshal failed: %v", err) + t.Fatalf("json.Marshal failed: %v", err) } var parsedTx *Transaction if err := json.Unmarshal(data, &parsedTx); err != nil { - t.Errorf("json.Unmarshal failed: %v", err) + t.Fatalf("json.Unmarshal failed: %v", err) } // compare nonce, price, gaslimit, recipient, amount, payload, V, R, S diff --git a/core/vm/analysis.go b/core/vm/analysis.go index f9c4298d39..0ccf47b979 100644 --- a/core/vm/analysis.go +++ b/core/vm/analysis.go @@ -16,34 +16,6 @@ package vm -import ( - "math/big" - - "github.com/ethereum/go-ethereum/common" -) - -// destinations stores one map per contract (keyed by hash of code). -// The maps contain an entry for each location of a JUMPDEST -// instruction. -type destinations map[common.Hash]bitvec - -// has checks whether code has a JUMPDEST at dest. -func (d destinations) has(codehash common.Hash, code []byte, dest *big.Int) bool { - // PC cannot go beyond len(code) and certainly can't be bigger than 63bits. - // Don't bother checking for JUMPDEST in that case. - udest := dest.Uint64() - if dest.BitLen() >= 63 || udest >= uint64(len(code)) { - return false - } - - m, analysed := d[codehash] - if !analysed { - m = codeBitmap(code) - d[codehash] = m - } - return OpCode(code[udest]) == JUMPDEST && m.codeSegment(udest) -} - // bitvec is a bit vector which maps bytes in a program. // An unset bit means the byte is an opcode, a set bit means // it's data (i.e. argument of PUSHxx). diff --git a/core/vm/analysis_test.go b/core/vm/analysis_test.go index a64f90ed9c..fd2d744d87 100644 --- a/core/vm/analysis_test.go +++ b/core/vm/analysis_test.go @@ -16,7 +16,11 @@ package vm -import "testing" +import ( + "testing" + + "github.com/ethereum/go-ethereum/crypto" +) func TestJumpDestAnalysis(t *testing.T) { tests := []struct { @@ -49,5 +53,23 @@ func TestJumpDestAnalysis(t *testing.T) { t.Fatalf("expected %x, got %02x", test.exp, ret[test.which]) } } - +} + +func BenchmarkJumpdestAnalysis_1200k(bench *testing.B) { + // 1.4 ms + code := make([]byte, 1200000) + bench.ResetTimer() + for i := 0; i < bench.N; i++ { + codeBitmap(code) + } + bench.StopTimer() +} +func BenchmarkJumpdestHashing_1200k(bench *testing.B) { + // 4 ms + code := make([]byte, 1200000) + bench.ResetTimer() + for i := 0; i < bench.N; i++ { + crypto.Keccak256Hash(code) + } + bench.StopTimer() } diff --git a/core/vm/contract.go b/core/vm/contract.go index 66748e8215..20baa6e751 100644 --- a/core/vm/contract.go +++ b/core/vm/contract.go @@ -40,7 +40,7 @@ type AccountRef common.Address func (ar AccountRef) Address() common.Address { return (common.Address)(ar) } // Contract represents an ethereum contract in the state database. It contains -// the the contract code, calling arguments. Contract implements ContractRef +// the contract code, calling arguments. Contract implements ContractRef type Contract struct { // CallerAddress is the result of the caller which initialised this // contract. However when the "call method" is delegated this value @@ -49,7 +49,8 @@ type Contract struct { caller ContractRef self ContractRef - jumpdests destinations // result of JUMPDEST analysis. + jumpdests map[common.Hash]bitvec // Aggregated result of JUMPDEST analysis. + analysis bitvec // Locally cached result of JUMPDEST analysis Code []byte CodeHash common.Hash @@ -58,21 +59,17 @@ type Contract struct { Gas uint64 value *big.Int - - Args []byte - - DelegateCall bool } // NewContract returns a new contract environment for the execution of EVM. func NewContract(caller ContractRef, object ContractRef, value *big.Int, gas uint64) *Contract { - c := &Contract{CallerAddress: caller.Address(), caller: caller, self: object, Args: nil} + c := &Contract{CallerAddress: caller.Address(), caller: caller, self: object} if parent, ok := caller.(*Contract); ok { // Reuse JUMPDEST analysis from parent context if available. c.jumpdests = parent.jumpdests } else { - c.jumpdests = make(destinations) + c.jumpdests = make(map[common.Hash]bitvec) } // Gas should be a pointer so it can safely be reduced through the run @@ -84,10 +81,42 @@ func NewContract(caller ContractRef, object ContractRef, value *big.Int, gas uin return c } +func (c *Contract) validJumpdest(dest *big.Int) bool { + udest := dest.Uint64() + // PC cannot go beyond len(code) and certainly can't be bigger than 63bits. + // Don't bother checking for JUMPDEST in that case. + if dest.BitLen() >= 63 || udest >= uint64(len(c.Code)) { + return false + } + // Only JUMPDESTs allowed for destinations + if OpCode(c.Code[udest]) != JUMPDEST { + return false + } + // Do we have a contract hash already? + if c.CodeHash != (common.Hash{}) { + // Does parent context have the analysis? + analysis, exist := c.jumpdests[c.CodeHash] + if !exist { + // Do the analysis and save in parent context + // We do not need to store it in c.analysis + analysis = codeBitmap(c.Code) + c.jumpdests[c.CodeHash] = analysis + } + return analysis.codeSegment(udest) + } + // We don't have the code hash, most likely a piece of initcode not already + // in state trie. In that case, we do an analysis, and save it locally, so + // we don't have to recalculate it for every JUMP instruction in the execution + // However, we don't save it within the parent context + if c.analysis == nil { + c.analysis = codeBitmap(c.Code) + } + return c.analysis.codeSegment(udest) +} + // AsDelegate sets the contract to be a delegate call and returns the current // contract (for chaining calls) func (c *Contract) AsDelegate() *Contract { - c.DelegateCall = true // NOTE: caller must, at all times be a contract. It should never happen // that caller is something other than a Contract. parent := c.caller.(*Contract) @@ -138,16 +167,18 @@ func (c *Contract) Value() *big.Int { return c.value } -// SetCode sets the code to the contract -func (self *Contract) SetCode(hash common.Hash, code []byte) { - self.Code = code - self.CodeHash = hash -} - // SetCallCode sets the code of the contract and address of the backing data // object -func (self *Contract) SetCallCode(addr *common.Address, hash common.Hash, code []byte) { - self.Code = code - self.CodeHash = hash - self.CodeAddr = addr +func (c *Contract) SetCallCode(addr *common.Address, hash common.Hash, code []byte) { + c.Code = code + c.CodeHash = hash + c.CodeAddr = addr +} + +// SetCodeOptionalHash can be used to provide code, but it's optional to provide hash. +// In case hash is not provided, the jumpdest analysis will not be saved to the parent context +func (c *Contract) SetCodeOptionalHash(addr *common.Address, codeAndHash *codeAndHash) { + c.Code = codeAndHash.code + c.CodeHash = codeAndHash.hash + c.CodeAddr = addr } diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 7344b6043c..20b741f8f1 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -116,7 +116,7 @@ func (c *sha256hash) Run(input []byte) ([]byte, error) { return h[:], nil } -// RIPMED160 implemented as a native contract. +// RIPEMD160 implemented as a native contract. type ripemd160hash struct{} // RequiredGas returns the gas required to execute the pre-compiled contract. @@ -251,26 +251,12 @@ func (c *bigModExp) Run(input []byte) ([]byte, error) { return common.LeftPadBytes(base.Exp(base, exp, mod).Bytes(), int(modLen)), nil } -var ( - // errNotOnCurve is returned if a point being unmarshalled as a bn256 elliptic - // curve point is not on the curve. - errNotOnCurve = errors.New("point not on elliptic curve") - - // errInvalidCurvePoint is returned if a point being unmarshalled as a bn256 - // elliptic curve point is invalid. - errInvalidCurvePoint = errors.New("invalid elliptic curve point") -) - // newCurvePoint unmarshals a binary blob into a bn256 elliptic curve point, // returning it, or an error if the point is invalid. func newCurvePoint(blob []byte) (*bn256.G1, error) { - p, onCurve := new(bn256.G1).Unmarshal(blob) - if !onCurve { - return nil, errNotOnCurve - } - gx, gy, _, _ := p.CurvePoints() - if gx.Cmp(bn256.P) >= 0 || gy.Cmp(bn256.P) >= 0 { - return nil, errInvalidCurvePoint + p := new(bn256.G1) + if _, err := p.Unmarshal(blob); err != nil { + return nil, err } return p, nil } @@ -278,14 +264,9 @@ func newCurvePoint(blob []byte) (*bn256.G1, error) { // newTwistPoint unmarshals a binary blob into a bn256 elliptic curve point, // returning it, or an error if the point is invalid. func newTwistPoint(blob []byte) (*bn256.G2, error) { - p, onCurve := new(bn256.G2).Unmarshal(blob) - if !onCurve { - return nil, errNotOnCurve - } - x2, y2, _, _ := p.CurvePoints() - if x2.Real().Cmp(bn256.P) >= 0 || x2.Imag().Cmp(bn256.P) >= 0 || - y2.Real().Cmp(bn256.P) >= 0 || y2.Imag().Cmp(bn256.P) >= 0 { - return nil, errInvalidCurvePoint + p := new(bn256.G2) + if _, err := p.Unmarshal(blob); err != nil { + return nil, err } return p, nil } diff --git a/core/vm/contracts_test.go b/core/vm/contracts_test.go index 513651835a..96083337c9 100644 --- a/core/vm/contracts_test.go +++ b/core/vm/contracts_test.go @@ -1,3 +1,19 @@ +// Copyright 2017 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 vm import ( diff --git a/core/vm/doc.go b/core/vm/doc.go index 239be2cfec..5864d0cfa2 100644 --- a/core/vm/doc.go +++ b/core/vm/doc.go @@ -17,19 +17,8 @@ /* Package vm implements the Ethereum Virtual Machine. -The vm package implements two EVMs, a byte code VM and a JIT VM. The BC -(Byte Code) VM loops over a set of bytes and executes them according to the set -of rules defined in the Ethereum yellow paper. When the BC VM is invoked it -invokes the JIT VM in a separate goroutine and compiles the byte code in JIT -instructions. - -The JIT VM, when invoked, loops around a set of pre-defined instructions until -it either runs of gas, causes an internal error, returns or stops. - -The JIT optimiser attempts to pre-compile instructions in to chunks or segments -such as multiple PUSH operations and static JUMPs. It does this by analysing the -opcodes and attempts to match certain regions to known sets. Whenever the -optimiser finds said segments it creates a new instruction and replaces the -first occurrence in the sequence. +The vm package implements one EVM, a byte code VM. The BC (Byte Code) VM loops +over a set of bytes and executes them according to the set of rules defined +in the Ethereum yellow paper. */ package vm diff --git a/core/vm/errors.go b/core/vm/errors.go index b19366be0e..7f88f324ea 100644 --- a/core/vm/errors.go +++ b/core/vm/errors.go @@ -18,6 +18,7 @@ package vm import "errors" +// List execution errors var ( ErrOutOfGas = errors.New("out of gas") ErrCodeStoreOutOfGas = errors.New("contract creation code storage out of gas") @@ -25,4 +26,5 @@ var ( ErrTraceLimitReached = errors.New("the number of logs reached the specified limit") ErrInsufficientBalance = errors.New("insufficient balance for transfer") ErrContractAddressCollision = errors.New("contract address collision") + ErrNoCompatibleInterpreter = errors.New("no compatible interpreter") ) diff --git a/core/vm/evm.go b/core/vm/evm.go index 46e7baff4c..70e1cd1b87 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -31,15 +31,17 @@ import ( var emptyCodeHash = crypto.Keccak256Hash(nil) type ( + // CanTransferFunc is the signature of a transfer guard function CanTransferFunc func(StateDB, common.Address, *big.Int) bool - TransferFunc func(StateDB, common.Address, common.Address, *big.Int) + // TransferFunc is the signature of a transfer function + TransferFunc func(StateDB, common.Address, common.Address, *big.Int) // GetHashFunc returns the nth block hash in the blockchain // and is used by the BLOCKHASH EVM op code. GetHashFunc func(uint64) common.Hash ) // run runs the given contract and takes care of running precompiles with a fallback to the byte code interpreter. -func run(evm *EVM, contract *Contract, input []byte) ([]byte, error) { +func run(evm *EVM, contract *Contract, input []byte, readOnly bool) ([]byte, error) { if contract.CodeAddr != nil { precompiles := PrecompiledContractsHomestead if evm.ChainConfig().IsByzantium(evm.BlockNumber) { @@ -49,7 +51,20 @@ func run(evm *EVM, contract *Contract, input []byte) ([]byte, error) { return RunPrecompiledContract(p, input, contract) } } - return evm.interpreter.Run(contract, input) + for _, interpreter := range evm.interpreters { + if interpreter.CanRun(contract.Code) { + if evm.interpreter != interpreter { + // Ensure that the interpreter pointer is set back + // to its current value upon return. + defer func(i Interpreter) { + evm.interpreter = i + }(evm.interpreter) + evm.interpreter = interpreter + } + return interpreter.Run(contract, input, readOnly) + } + } + return nil, ErrNoCompatibleInterpreter } // Context provides the EVM with auxiliary information. Once provided @@ -101,7 +116,8 @@ type EVM struct { vmConfig Config // global (to this context) ethereum virtual machine // used throughout the execution of the tx. - interpreter *Interpreter + interpreters []Interpreter + interpreter Interpreter // abort is used to abort the EVM calling operations // NOTE: must be set atomically abort int32 @@ -111,18 +127,39 @@ type EVM struct { callGasTemp uint64 } -// NewEVM retutrns a new EVM . The returned EVM is not thread safe and should +// NewEVM returns a new EVM. The returned EVM is not thread safe and should // only ever be used *once*. func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmConfig Config) *EVM { evm := &EVM{ - Context: ctx, - StateDB: statedb, - vmConfig: vmConfig, - chainConfig: chainConfig, - chainRules: chainConfig.Rules(ctx.BlockNumber), + Context: ctx, + StateDB: statedb, + vmConfig: vmConfig, + chainConfig: chainConfig, + chainRules: chainConfig.Rules(ctx.BlockNumber), + interpreters: make([]Interpreter, 0, 1), } - evm.interpreter = NewInterpreter(evm, vmConfig) + if chainConfig.IsEWASM(ctx.BlockNumber) { + // to be implemented by EVM-C and Wagon PRs. + // if vmConfig.EWASMInterpreter != "" { + // extIntOpts := strings.Split(vmConfig.EWASMInterpreter, ":") + // path := extIntOpts[0] + // options := []string{} + // if len(extIntOpts) > 1 { + // options = extIntOpts[1..] + // } + // evm.interpreters = append(evm.interpreters, NewEVMVCInterpreter(evm, vmConfig, options)) + // } else { + // evm.interpreters = append(evm.interpreters, NewEWASMInterpreter(evm, vmConfig)) + // } + panic("No supported ewasm interpreter yet.") + } + + // vmConfig.EVMInterpreter will be used by EVM-C, it won't be checked here + // as we always want to have the built-in EVM as the failover option. + evm.interpreters = append(evm.interpreters, NewEVMInterpreter(evm, vmConfig)) + evm.interpreter = evm.interpreters[0] + return evm } @@ -132,6 +169,11 @@ func (evm *EVM) Cancel() { atomic.StoreInt32(&evm.abort, 1) } +// Interpreter returns the current interpreter +func (evm *EVM) Interpreter() Interpreter { + return evm.interpreter +} + // Call executes the contract associated with the addr with the given input as // parameters. It also handles any necessary value transfer required and takes // the necessary steps to create accounts and reverses the state in case of an @@ -160,17 +202,22 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas precompiles = PrecompiledContractsByzantium } if precompiles[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.Sign() == 0 { + // Calling a non existing account, don't do anything, but ping the tracer + if evm.vmConfig.Debug && evm.depth == 0 { + evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value) + evm.vmConfig.Tracer.CaptureEnd(ret, 0, 0, nil) + } return nil, gas, nil } evm.StateDB.CreateAccount(addr) } evm.Transfer(evm.StateDB, caller.Address(), to.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. contract := NewContract(caller, to, value, gas) contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) + // Even if the account has no code, we need to continue because it might be a precompile start := time.Now() // Capture the tracer start/end events in debug mode @@ -181,7 +228,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err) }() } - ret, err = run(evm, contract, input) + ret, err = run(evm, contract, input, false) // 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 @@ -220,13 +267,12 @@ 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 - // E The contract is a scoped evmironment 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)) - ret, err = run(evm, contract, input) + ret, err = run(evm, contract, input, false) if err != nil { evm.StateDB.RevertToSnapshot(snapshot) if err != errExecutionReverted { @@ -259,7 +305,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by contract := NewContract(caller, to, nil, gas).AsDelegate() contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) - ret, err = run(evm, contract, input) + ret, err = run(evm, contract, input, false) if err != nil { evm.StateDB.RevertToSnapshot(snapshot) if err != errExecutionReverted { @@ -281,28 +327,26 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte if evm.depth > int(params.CallCreateDepth) { return nil, gas, ErrDepth } - // Make sure the readonly is only set if we aren't in readonly yet - // this makes also sure that the readonly flag isn't removed for - // child calls. - if !evm.interpreter.readOnly { - evm.interpreter.readOnly = true - defer func() { evm.interpreter.readOnly = false }() - } var ( 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. - ret, err = run(evm, contract, input) + ret, err = run(evm, contract, input, true) if err != nil { evm.StateDB.RevertToSnapshot(snapshot) if err != errExecutionReverted { @@ -312,9 +356,20 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte return ret, contract.Gas, err } -// Create creates a new contract using code as deployment code. -func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { +type codeAndHash struct { + code []byte + hash common.Hash +} +func (c *codeAndHash) Hash() common.Hash { + if c.hash == (common.Hash{}) { + c.hash = crypto.Keccak256Hash(c.code) + } + return c.hash +} + +// create creates a new contract using code as deployment code. +func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, value *big.Int, address common.Address) ([]byte, common.Address, uint64, error) { // Depth check execution. Fail if we're trying to execute above the // limit. if evm.depth > int(params.CallCreateDepth) { @@ -323,39 +378,37 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I if !evm.CanTransfer(evm.StateDB, caller.Address(), value) { return nil, common.Address{}, gas, ErrInsufficientBalance } - // Ensure there's no existing contract already at the designated address nonce := evm.StateDB.GetNonce(caller.Address()) evm.StateDB.SetNonce(caller.Address(), nonce+1) - contractAddr = crypto.CreateAddress(caller.Address(), nonce) - contractHash := evm.StateDB.GetCodeHash(contractAddr) - if evm.StateDB.GetNonce(contractAddr) != 0 || (contractHash != (common.Hash{}) && contractHash != emptyCodeHash) { + // Ensure there's no existing contract already at the designated address + contractHash := evm.StateDB.GetCodeHash(address) + if evm.StateDB.GetNonce(address) != 0 || (contractHash != (common.Hash{}) && contractHash != emptyCodeHash) { return nil, common.Address{}, 0, ErrContractAddressCollision } // Create a new account on the state snapshot := evm.StateDB.Snapshot() - evm.StateDB.CreateAccount(contractAddr) + evm.StateDB.CreateAccount(address) if evm.ChainConfig().IsEIP158(evm.BlockNumber) { - evm.StateDB.SetNonce(contractAddr, 1) + evm.StateDB.SetNonce(address, 1) } - evm.Transfer(evm.StateDB, caller.Address(), contractAddr, value) + evm.Transfer(evm.StateDB, caller.Address(), address, value) - // initialise a new contract and set the code that is to be used by the - // E The contract is a scoped evmironment for this execution context - // only. - contract := NewContract(caller, AccountRef(contractAddr), value, gas) - contract.SetCallCode(&contractAddr, crypto.Keccak256Hash(code), code) + // 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) if evm.vmConfig.NoRecursion && evm.depth > 0 { - return nil, contractAddr, gas, nil + return nil, address, gas, nil } if evm.vmConfig.Debug && evm.depth == 0 { - evm.vmConfig.Tracer.CaptureStart(caller.Address(), contractAddr, true, code, gas, value) + evm.vmConfig.Tracer.CaptureStart(caller.Address(), address, true, codeAndHash.code, gas, value) } start := time.Now() - ret, err = run(evm, contract, nil) + ret, err := run(evm, contract, nil, false) // check whether the max code size has been exceeded maxCodeSizeExceeded := evm.ChainConfig().IsEIP158(evm.BlockNumber) && len(ret) > params.MaxCodeSize @@ -366,7 +419,7 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I if err == nil && !maxCodeSizeExceeded { createDataGas := uint64(len(ret)) * params.CreateDataGas if contract.UseGas(createDataGas) { - evm.StateDB.SetCode(contractAddr, ret) + evm.StateDB.SetCode(address, ret) } else { err = ErrCodeStoreOutOfGas } @@ -388,11 +441,25 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I if evm.vmConfig.Debug && evm.depth == 0 { evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err) } - return ret, contractAddr, contract.Gas, err + return ret, address, contract.Gas, err + +} + +// Create creates a new contract using code as deployment code. +func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { + contractAddr = crypto.CreateAddress(caller.Address(), evm.StateDB.GetNonce(caller.Address())) + return evm.create(caller, &codeAndHash{code: code}, gas, value, contractAddr) +} + +// Create2 creates a new contract using code as deployment code. +// +// The different between Create2 with Create is Create2 uses sha3(0xff ++ msg.sender ++ salt ++ sha3(init_code))[12:] +// instead of the usual sender-and-nonce-hash as the address where the contract is initialized at. +func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment *big.Int, salt *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { + codeAndHash := &codeAndHash{code: code} + contractAddr = crypto.CreateAddress2(caller.Address(), common.BigToHash(salt), codeAndHash.Hash().Bytes()) + return evm.create(caller, codeAndHash, gas, endowment, contractAddr) } // ChainConfig returns the environment's chain configuration func (evm *EVM) ChainConfig() *params.ChainConfig { return evm.chainConfig } - -// Interpreter returns the EVM interpreter -func (evm *EVM) Interpreter() *Interpreter { return evm.interpreter } diff --git a/core/vm/gas.go b/core/vm/gas.go index dd64d5f178..dba1b3a02f 100644 --- a/core/vm/gas.go +++ b/core/vm/gas.go @@ -22,6 +22,7 @@ import ( "github.com/ethereum/go-ethereum/params" ) +// Gas costs const ( GasQuickStep uint64 = 2 GasFastestStep uint64 = 3 @@ -29,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. diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index 83adba428e..f22463c331 100644 --- a/core/vm/gas_table.go +++ b/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) { @@ -117,24 +117,71 @@ func gasReturnDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack * func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { var ( - y, x = stack.Back(1), stack.Back(0) - val = evm.StateDB.GetState(contract.Address(), common.BigToHash(x)) + y, x = stack.Back(1), stack.Back(0) + current = evm.StateDB.GetState(contract.Address(), common.BigToHash(x)) ) - // This checks for 3 scenario's and calculates gas accordingly - // 1. From a zero-value address to a non-zero value (NEW VALUE) - // 2. From a non-zero value address to a zero-value address (DELETE) - // 3. From a non-zero to a non-zero (CHANGE) - if common.EmptyHash(val) && !common.EmptyHash(common.BigToHash(y)) { - // 0 => non 0 - return params.SstoreSetGas, nil - } else if !common.EmptyHash(val) && common.EmptyHash(common.BigToHash(y)) { - evm.StateDB.AddRefund(params.SstoreRefundGas) - - return params.SstoreClearGas, nil - } else { - // non 0 => non 0 (or 0 => 0) - return params.SstoreResetGas, nil + // The legacy gas metering only takes into consideration the current state + // 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) + // 2. From a non-zero value address to a zero-value address (DELETE) + // 3. From a non-zero to a non-zero (CHANGE) + switch { + case current == (common.Hash{}) && y.Sign() != 0: // 0 => non 0 + return params.SstoreSetGas, nil + case current != (common.Hash{}) && y.Sign() == 0: // non 0 => 0 + evm.StateDB.AddRefund(params.SstoreRefundGas) + return params.SstoreClearGas, nil + default: // non 0 => non 0 (or 0 => 0) + return params.SstoreResetGas, nil + } } + // The new gas metering is based on net gas costs (EIP-1283): + // + // 1. If current value equals new value (this is a no-op), 200 gas is deducted. + // 2. If current value does not equal new value + // 2.1. If original value equals current value (this storage slot has not been changed by the current execution context) + // 2.1.1. If original value is 0, 20000 gas is deducted. + // 2.1.2. Otherwise, 5000 gas is deducted. If new value is 0, add 15000 gas to refund counter. + // 2.2. If original value does not equal current value (this storage slot is dirty), 200 gas is deducted. Apply both of the following clauses. + // 2.2.1. If original value is not 0 + // 2.2.1.1. If current value is 0 (also means that new value is not 0), remove 15000 gas from refund counter. We can prove that refund counter will never go below 0. + // 2.2.1.2. If new value is 0 (also means that current value is not 0), add 15000 gas to refund counter. + // 2.2.2. If original value equals new value (this storage slot is reset) + // 2.2.2.1. If original value is 0, add 19800 gas to refund counter. + // 2.2.2.2. Otherwise, add 4800 gas to refund counter. + value := common.BigToHash(y) + if current == value { // noop (1) + return params.NetSstoreNoopGas, nil + } + original := evm.StateDB.GetCommittedState(contract.Address(), common.BigToHash(x)) + if original == current { + if original == (common.Hash{}) { // create slot (2.1.1) + return params.NetSstoreInitGas, nil + } + if value == (common.Hash{}) { // delete slot (2.1.2b) + evm.StateDB.AddRefund(params.NetSstoreClearRefund) + } + return params.NetSstoreCleanGas, nil // write existing slot (2.1.2) + } + if original != (common.Hash{}) { + if current == (common.Hash{}) { // recreate slot (2.2.1.1) + evm.StateDB.SubRefund(params.NetSstoreClearRefund) + } else if value == (common.Hash{}) { // delete slot (2.2.1.2) + evm.StateDB.AddRefund(params.NetSstoreClearRefund) + } + } + if original == value { + if original == (common.Hash{}) { // reset to original inexistent slot (2.2.2.1) + evm.StateDB.AddRefund(params.NetSstoreResetClearRefund) + } else { // reset to original existing slot (2.2.2.2) + evm.StateDB.AddRefund(params.NetSstoreResetRefund) + } + } + return params.NetSstoreDirtyGas, nil } func makeGasLog(n uint64) gasFunc { @@ -241,6 +288,10 @@ func gasExtCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Sta return gas, nil } +func gasExtCodeHash(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + return gt.ExtcodeHash, nil +} + func gasMLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { var overflow bool gas, err := memoryGasCost(mem, memorySize) @@ -289,6 +340,29 @@ func gasCreate(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, m return gas, nil } +func gasCreate2(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + var overflow bool + gas, err := memoryGasCost(mem, memorySize) + if err != nil { + return 0, err + } + if gas, overflow = math.SafeAdd(gas, params.Create2Gas); overflow { + return 0, errGasUintOverflow + } + wordGas, overflow := bigUint64(stack.Back(2)) + if overflow { + return 0, errGasUintOverflow + } + if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.Sha3WordGas); overflow { + return 0, errGasUintOverflow + } + if gas, overflow = math.SafeAdd(gas, wordGas); overflow { + return 0, errGasUintOverflow + } + + return gas, nil +} + func gasBalance(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { return gt.Balance, nil } @@ -308,7 +382,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 diff --git a/core/vm/gen_structlog.go b/core/vm/gen_structlog.go index ade3ca6318..726012e59e 100644 --- a/core/vm/gen_structlog.go +++ b/core/vm/gen_structlog.go @@ -13,20 +13,22 @@ import ( var _ = (*structLogMarshaling)(nil) +// MarshalJSON marshals as JSON. func (s StructLog) MarshalJSON() ([]byte, error) { type StructLog struct { - Pc uint64 `json:"pc"` - Op OpCode `json:"op"` - Gas math.HexOrDecimal64 `json:"gas"` - GasCost math.HexOrDecimal64 `json:"gasCost"` - Memory hexutil.Bytes `json:"memory"` - MemorySize int `json:"memSize"` - Stack []*math.HexOrDecimal256 `json:"stack"` - Storage map[common.Hash]common.Hash `json:"-"` - Depth int `json:"depth"` - Err error `json:"-"` - OpName string `json:"opName"` - ErrorString string `json:"error"` + Pc uint64 `json:"pc"` + Op OpCode `json:"op"` + Gas math.HexOrDecimal64 `json:"gas"` + GasCost math.HexOrDecimal64 `json:"gasCost"` + Memory hexutil.Bytes `json:"memory"` + MemorySize int `json:"memSize"` + Stack []*math.HexOrDecimal256 `json:"stack"` + Storage map[common.Hash]common.Hash `json:"-"` + Depth int `json:"depth"` + RefundCounter uint64 `json:"refund"` + Err error `json:"-"` + OpName string `json:"opName"` + ErrorString string `json:"error"` } var enc StructLog enc.Pc = s.Pc @@ -43,24 +45,27 @@ func (s StructLog) MarshalJSON() ([]byte, error) { } enc.Storage = s.Storage enc.Depth = s.Depth + enc.RefundCounter = s.RefundCounter enc.Err = s.Err enc.OpName = s.OpName() enc.ErrorString = s.ErrorString() return json.Marshal(&enc) } +// UnmarshalJSON unmarshals from JSON. func (s *StructLog) UnmarshalJSON(input []byte) error { type StructLog struct { - Pc *uint64 `json:"pc"` - Op *OpCode `json:"op"` - Gas *math.HexOrDecimal64 `json:"gas"` - GasCost *math.HexOrDecimal64 `json:"gasCost"` - Memory *hexutil.Bytes `json:"memory"` - MemorySize *int `json:"memSize"` - Stack []*math.HexOrDecimal256 `json:"stack"` - Storage map[common.Hash]common.Hash `json:"-"` - Depth *int `json:"depth"` - Err error `json:"-"` + Pc *uint64 `json:"pc"` + Op *OpCode `json:"op"` + Gas *math.HexOrDecimal64 `json:"gas"` + GasCost *math.HexOrDecimal64 `json:"gasCost"` + Memory *hexutil.Bytes `json:"memory"` + MemorySize *int `json:"memSize"` + Stack []*math.HexOrDecimal256 `json:"stack"` + Storage map[common.Hash]common.Hash `json:"-"` + Depth *int `json:"depth"` + RefundCounter *uint64 `json:"refund"` + Err error `json:"-"` } var dec StructLog if err := json.Unmarshal(input, &dec); err != nil { @@ -96,6 +101,9 @@ func (s *StructLog) UnmarshalJSON(input []byte) error { if dec.Depth != nil { s.Depth = *dec.Depth } + if dec.RefundCounter != nil { + s.RefundCounter = *dec.RefundCounter + } if dec.Err != nil { s.Err = dec.Err } diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 7661725010..5195e716b2 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -24,123 +24,126 @@ import ( "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" "github.com/ethereum/go-ethereum/params" + "golang.org/x/crypto/sha3" ) var ( bigZero = new(big.Int) + tt255 = math.BigPow(2, 255) errWriteProtection = errors.New("evm: write protection") errReturnDataOutOfBounds = errors.New("evm: return data out of bounds") errExecutionReverted = errors.New("evm: execution reverted") errMaxCodeSizeExceeded = errors.New("evm: max code size exceeded") ) -func opAdd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.pop() - stack.push(math.U256(x.Add(x, y))) - - evm.interpreter.intPool.put(y) +func opAdd(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + x, y := stack.pop(), stack.peek() + math.U256(y.Add(x, y)) + interpreter.intPool.put(x) return nil, nil } -func opSub(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.pop() - stack.push(math.U256(x.Sub(x, y))) - - evm.interpreter.intPool.put(y) +func opSub(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + x, y := stack.pop(), stack.peek() + math.U256(y.Sub(x, y)) + interpreter.intPool.put(x) return nil, nil } -func opMul(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opMul(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() stack.push(math.U256(x.Mul(x, y))) - evm.interpreter.intPool.put(y) + interpreter.intPool.put(y) return nil, nil } -func opDiv(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.pop() +func opDiv(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + x, y := stack.pop(), stack.peek() if y.Sign() != 0 { - stack.push(math.U256(x.Div(x, y))) + math.U256(y.Div(x, y)) } else { - stack.push(new(big.Int)) + y.SetUint64(0) } - - evm.interpreter.intPool.put(y) - + interpreter.intPool.put(x) return nil, nil } -func opSdiv(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opSdiv(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := math.S256(stack.pop()), math.S256(stack.pop()) - if y.Sign() == 0 { - stack.push(new(big.Int)) - return nil, nil + res := interpreter.intPool.getZero() + + if y.Sign() == 0 || x.Sign() == 0 { + stack.push(res) } else { - n := new(big.Int) - if evm.interpreter.intPool.get().Mul(x, y).Sign() < 0 { - n.SetInt64(-1) + if x.Sign() != y.Sign() { + res.Div(x.Abs(x), y.Abs(y)) + res.Neg(res) } else { - n.SetInt64(1) + res.Div(x.Abs(x), y.Abs(y)) } - - res := x.Div(x.Abs(x), y.Abs(y)) - res.Mul(res, n) - stack.push(math.U256(res)) } - evm.interpreter.intPool.put(y) + interpreter.intPool.put(x, y) return nil, nil } -func opMod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opMod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() if y.Sign() == 0 { - stack.push(new(big.Int)) + stack.push(x.SetUint64(0)) } else { stack.push(math.U256(x.Mod(x, y))) } - evm.interpreter.intPool.put(y) + interpreter.intPool.put(y) return nil, nil } -func opSmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opSmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := math.S256(stack.pop()), math.S256(stack.pop()) + res := interpreter.intPool.getZero() if y.Sign() == 0 { - stack.push(new(big.Int)) + stack.push(res) } else { - n := new(big.Int) if x.Sign() < 0 { - n.SetInt64(-1) + res.Mod(x.Abs(x), y.Abs(y)) + res.Neg(res) } else { - n.SetInt64(1) + res.Mod(x.Abs(x), y.Abs(y)) } - - res := x.Mod(x.Abs(x), y.Abs(y)) - res.Mul(res, n) - stack.push(math.U256(res)) } - evm.interpreter.intPool.put(y) + interpreter.intPool.put(x, y) return nil, nil } -func opExp(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opExp(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { base, exponent := stack.pop(), stack.pop() - stack.push(math.Exp(base, exponent)) - - evm.interpreter.intPool.put(base, exponent) - + // some shortcuts + cmpToOne := exponent.Cmp(big1) + if cmpToOne < 0 { // Exponent is zero + // x ^ 0 == 1 + stack.push(base.SetUint64(1)) + } else if base.Sign() == 0 { + // 0 ^ y, if y != 0, == 0 + stack.push(base.SetUint64(0)) + } else if cmpToOne == 0 { // Exponent is one + // x ^ 1 == x + stack.push(base) + } else { + stack.push(math.Exp(base, exponent)) + interpreter.intPool.put(base) + } + interpreter.intPool.put(exponent) return nil, nil } -func opSignExtend(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opSignExtend(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { back := stack.pop() if back.Cmp(big.NewInt(31)) < 0 { bit := uint(back.Uint64()*8 + 7) @@ -156,113 +159,132 @@ func opSignExtend(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stac stack.push(math.U256(num)) } - evm.interpreter.intPool.put(back) + interpreter.intPool.put(back) return nil, nil } -func opNot(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x := stack.pop() - stack.push(math.U256(x.Not(x))) +func opNot(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + x := stack.peek() + math.U256(x.Not(x)) return nil, nil } -func opLt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.pop() +func opLt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + x, y := stack.pop(), stack.peek() if x.Cmp(y) < 0 { - stack.push(evm.interpreter.intPool.get().SetUint64(1)) + y.SetUint64(1) } else { - stack.push(new(big.Int)) + y.SetUint64(0) } - - evm.interpreter.intPool.put(x, y) + interpreter.intPool.put(x) return nil, nil } -func opGt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.pop() +func opGt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + x, y := stack.pop(), stack.peek() if x.Cmp(y) > 0 { - stack.push(evm.interpreter.intPool.get().SetUint64(1)) + y.SetUint64(1) } else { - stack.push(new(big.Int)) + y.SetUint64(0) } - - evm.interpreter.intPool.put(x, y) + interpreter.intPool.put(x) return nil, nil } -func opSlt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := math.S256(stack.pop()), math.S256(stack.pop()) - if x.Cmp(math.S256(y)) < 0 { - stack.push(evm.interpreter.intPool.get().SetUint64(1)) - } else { - stack.push(new(big.Int)) - } +func opSlt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + x, y := stack.pop(), stack.peek() - evm.interpreter.intPool.put(x, y) + xSign := x.Cmp(tt255) + ySign := y.Cmp(tt255) + + switch { + case xSign >= 0 && ySign < 0: + y.SetUint64(1) + + case xSign < 0 && ySign >= 0: + y.SetUint64(0) + + default: + if x.Cmp(y) < 0 { + y.SetUint64(1) + } else { + y.SetUint64(0) + } + } + interpreter.intPool.put(x) return nil, nil } -func opSgt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := math.S256(stack.pop()), math.S256(stack.pop()) - if x.Cmp(y) > 0 { - stack.push(evm.interpreter.intPool.get().SetUint64(1)) - } else { - stack.push(new(big.Int)) - } +func opSgt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + x, y := stack.pop(), stack.peek() - evm.interpreter.intPool.put(x, y) + xSign := x.Cmp(tt255) + ySign := y.Cmp(tt255) + + switch { + case xSign >= 0 && ySign < 0: + y.SetUint64(0) + + case xSign < 0 && ySign >= 0: + y.SetUint64(1) + + default: + if x.Cmp(y) > 0 { + y.SetUint64(1) + } else { + y.SetUint64(0) + } + } + interpreter.intPool.put(x) return nil, nil } -func opEq(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.pop() +func opEq(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + x, y := stack.pop(), stack.peek() if x.Cmp(y) == 0 { - stack.push(evm.interpreter.intPool.get().SetUint64(1)) + y.SetUint64(1) } else { - stack.push(new(big.Int)) + y.SetUint64(0) } - - evm.interpreter.intPool.put(x, y) + interpreter.intPool.put(x) return nil, nil } -func opIszero(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x := stack.pop() +func opIszero(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + x := stack.peek() if x.Sign() > 0 { - stack.push(new(big.Int)) + x.SetUint64(0) } else { - stack.push(evm.interpreter.intPool.get().SetUint64(1)) + x.SetUint64(1) } - - evm.interpreter.intPool.put(x) return nil, nil } -func opAnd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opAnd(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() stack.push(x.And(x, y)) - evm.interpreter.intPool.put(y) + interpreter.intPool.put(y) return nil, nil } -func opOr(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.pop() - stack.push(x.Or(x, y)) +func opOr(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + x, y := stack.pop(), stack.peek() + y.Or(x, y) - evm.interpreter.intPool.put(y) + interpreter.intPool.put(x) return nil, nil } -func opXor(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.pop() - stack.push(x.Xor(x, y)) +func opXor(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + x, y := stack.pop(), stack.peek() + y.Xor(x, y) - evm.interpreter.intPool.put(y) + interpreter.intPool.put(x) return nil, nil } -func opByte(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opByte(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { th, val := stack.pop(), stack.peek() if th.Cmp(common.Big32) < 0 { b := math.Byte(val, 32, int(th.Int64())) @@ -270,92 +292,155 @@ func opByte(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta } else { val.SetUint64(0) } - evm.interpreter.intPool.put(th) + interpreter.intPool.put(th) return nil, nil } -func opAddmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opAddmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y, z := stack.pop(), stack.pop(), stack.pop() if z.Cmp(bigZero) > 0 { - add := x.Add(x, y) - add.Mod(add, z) - stack.push(math.U256(add)) + x.Add(x, y) + x.Mod(x, z) + stack.push(math.U256(x)) } else { - stack.push(new(big.Int)) + stack.push(x.SetUint64(0)) } - - evm.interpreter.intPool.put(y, z) + interpreter.intPool.put(y, z) return nil, nil } -func opMulmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opMulmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y, z := stack.pop(), stack.pop(), stack.pop() if z.Cmp(bigZero) > 0 { - mul := x.Mul(x, y) - mul.Mod(mul, z) - stack.push(math.U256(mul)) + x.Mul(x, y) + x.Mod(x, z) + stack.push(math.U256(x)) } else { - stack.push(new(big.Int)) + stack.push(x.SetUint64(0)) } - - evm.interpreter.intPool.put(y, z) + interpreter.intPool.put(y, z) return nil, nil } -func opSha3(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +// opSHL implements Shift Left +// The SHL instruction (shift left) pops 2 values from the stack, first arg1 and then arg2, +// and pushes on the stack arg2 shifted to the left by arg1 number of bits. +func opSHL(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + // Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards + shift, value := math.U256(stack.pop()), math.U256(stack.peek()) + defer interpreter.intPool.put(shift) // First operand back into the pool + + if shift.Cmp(common.Big256) >= 0 { + value.SetUint64(0) + return nil, nil + } + n := uint(shift.Uint64()) + math.U256(value.Lsh(value, n)) + + return nil, nil +} + +// opSHR implements Logical Shift Right +// The SHR instruction (logical shift right) pops 2 values from the stack, first arg1 and then arg2, +// and pushes on the stack arg2 shifted to the right by arg1 number of bits with zero fill. +func opSHR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + // Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards + shift, value := math.U256(stack.pop()), math.U256(stack.peek()) + defer interpreter.intPool.put(shift) // First operand back into the pool + + if shift.Cmp(common.Big256) >= 0 { + value.SetUint64(0) + return nil, nil + } + n := uint(shift.Uint64()) + math.U256(value.Rsh(value, n)) + + return nil, nil +} + +// opSAR implements Arithmetic Shift Right +// The SAR instruction (arithmetic shift right) pops 2 values from the stack, first arg1 and then arg2, +// and pushes on the stack arg2 shifted to the right by arg1 number of bits with sign extension. +func opSAR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + // Note, S256 returns (potentially) a new bigint, so we're popping, not peeking this one + shift, value := math.U256(stack.pop()), math.S256(stack.pop()) + defer interpreter.intPool.put(shift) // First operand back into the pool + + if shift.Cmp(common.Big256) >= 0 { + if value.Sign() >= 0 { + value.SetUint64(0) + } else { + value.SetInt64(-1) + } + stack.push(math.U256(value)) + return nil, nil + } + n := uint(shift.Uint64()) + value.Rsh(value, n) + stack.push(math.U256(value)) + + return nil, nil +} + +func opSha3(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { offset, size := stack.pop(), stack.pop() data := memory.Get(offset.Int64(), size.Int64()) - hash := crypto.Keccak256(data) - if evm.vmConfig.EnablePreimageRecording { - evm.StateDB.AddPreimage(common.BytesToHash(hash), data) + if interpreter.hasher == nil { + interpreter.hasher = sha3.NewLegacyKeccak256().(keccakState) + } else { + interpreter.hasher.Reset() } + interpreter.hasher.Write(data) + interpreter.hasher.Read(interpreter.hasherBuf[:]) - stack.push(new(big.Int).SetBytes(hash)) + evm := interpreter.evm + if evm.vmConfig.EnablePreimageRecording { + evm.StateDB.AddPreimage(interpreter.hasherBuf, data) + } + stack.push(interpreter.intPool.get().SetBytes(interpreter.hasherBuf[:])) - evm.interpreter.intPool.put(offset, size) + interpreter.intPool.put(offset, size) return nil, nil } -func opAddress(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opAddress(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.push(contract.Address().Big()) return nil, nil } -func opBalance(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - addr := common.BigToAddress(stack.pop()) - balance := evm.StateDB.GetBalance(addr) - - stack.push(new(big.Int).Set(balance)) +func opBalance(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + slot := stack.peek() + slot.Set(interpreter.evm.StateDB.GetBalance(common.BigToAddress(slot))) return nil, nil } -func opOrigin(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(evm.Origin.Big()) +func opOrigin(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(interpreter.evm.Origin.Big()) return nil, nil } -func opCaller(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opCaller(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.push(contract.Caller().Big()) return nil, nil } -func opCallValue(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(evm.interpreter.intPool.get().Set(contract.value)) +func opCallValue(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(interpreter.intPool.get().Set(contract.value)) return nil, nil } -func opCallDataLoad(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(new(big.Int).SetBytes(getDataBig(contract.Input, stack.pop(), big32))) +func opCallDataLoad(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(interpreter.intPool.get().SetBytes(getDataBig(contract.Input, stack.pop(), big32))) return nil, nil } -func opCallDataSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(evm.interpreter.intPool.get().SetInt64(int64(len(contract.Input)))) +func opCallDataSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(interpreter.intPool.get().SetInt64(int64(len(contract.Input)))) return nil, nil } -func opCallDataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opCallDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { var ( memOffset = stack.pop() dataOffset = stack.pop() @@ -363,49 +448,48 @@ func opCallDataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, st ) memory.Set(memOffset.Uint64(), length.Uint64(), getDataBig(contract.Input, dataOffset, length)) - evm.interpreter.intPool.put(memOffset, dataOffset, length) + interpreter.intPool.put(memOffset, dataOffset, length) return nil, nil } -func opReturnDataSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(evm.interpreter.intPool.get().SetUint64(uint64(len(evm.interpreter.returnData)))) +func opReturnDataSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(interpreter.intPool.get().SetUint64(uint64(len(interpreter.returnData)))) return nil, nil } -func opReturnDataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { var ( memOffset = stack.pop() dataOffset = stack.pop() length = stack.pop() - ) - defer evm.interpreter.intPool.put(memOffset, dataOffset, length) - end := new(big.Int).Add(dataOffset, length) - if end.BitLen() > 64 || uint64(len(evm.interpreter.returnData)) < end.Uint64() { + end = interpreter.intPool.get().Add(dataOffset, length) + ) + defer interpreter.intPool.put(memOffset, dataOffset, length, end) + + if end.BitLen() > 64 || uint64(len(interpreter.returnData)) < end.Uint64() { return nil, errReturnDataOutOfBounds } - memory.Set(memOffset.Uint64(), length.Uint64(), evm.interpreter.returnData[dataOffset.Uint64():end.Uint64()]) + memory.Set(memOffset.Uint64(), length.Uint64(), interpreter.returnData[dataOffset.Uint64():end.Uint64()]) return nil, nil } -func opExtCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - a := stack.pop() - - addr := common.BigToAddress(a) - a.SetInt64(int64(evm.StateDB.GetCodeSize(addr))) - stack.push(a) +func opExtCodeSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + slot := stack.peek() + slot.SetUint64(uint64(interpreter.evm.StateDB.GetCodeSize(common.BigToAddress(slot)))) return nil, nil } -func opCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - l := evm.interpreter.intPool.get().SetInt64(int64(len(contract.Code))) +func opCodeSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + l := interpreter.intPool.get().SetInt64(int64(len(contract.Code))) stack.push(l) + return nil, nil } -func opCodeCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { var ( memOffset = stack.pop() codeOffset = stack.pop() @@ -414,130 +498,166 @@ func opCodeCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack codeCopy := getDataBig(contract.Code, codeOffset, length) memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy) - evm.interpreter.intPool.put(memOffset, codeOffset, length) + interpreter.intPool.put(memOffset, codeOffset, length) return nil, nil } -func opExtCodeCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { var ( addr = common.BigToAddress(stack.pop()) memOffset = stack.pop() codeOffset = stack.pop() length = stack.pop() ) - codeCopy := getDataBig(evm.StateDB.GetCode(addr), codeOffset, length) + codeCopy := getDataBig(interpreter.evm.StateDB.GetCode(addr), codeOffset, length) memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy) - evm.interpreter.intPool.put(memOffset, codeOffset, length) + interpreter.intPool.put(memOffset, codeOffset, length) return nil, nil } -func opGasprice(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(evm.interpreter.intPool.get().Set(evm.GasPrice)) +// opExtCodeHash returns the code hash of a specified account. +// There are several cases when the function is called, while we can relay everything +// to `state.GetCodeHash` function to ensure the correctness. +// (1) Caller tries to get the code hash of a normal contract account, state +// should return the relative code hash and set it as the result. +// +// (2) Caller tries to get the code hash of a non-existent account, state should +// return common.Hash{} and zero will be set as the result. +// +// (3) Caller tries to get the code hash for an account without contract code, +// state should return emptyCodeHash(0xc5d246...) as the result. +// +// (4) Caller tries to get the code hash of a precompiled account, the result +// should be zero or emptyCodeHash. +// +// It is worth noting that in order to avoid unnecessary create and clean, +// all precompile accounts on mainnet have been transferred 1 wei, so the return +// here should be emptyCodeHash. +// If the precompile account is not transferred any amount on a private or +// customized chain, the return value will be zero. +// +// (5) Caller tries to get the code hash for an account which is marked as suicided +// in the current transaction, the code hash of this account should be returned. +// +// (6) Caller tries to get the code hash for an account which is marked as deleted, +// this account should be regarded as a non-existent account and zero should be returned. +func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + slot := stack.peek() + address := common.BigToAddress(slot) + if interpreter.evm.StateDB.Empty(address) { + slot.SetUint64(0) + } else { + slot.SetBytes(interpreter.evm.StateDB.GetCodeHash(address).Bytes()) + } return nil, nil } -func opBlockhash(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opGasprice(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(interpreter.intPool.get().Set(interpreter.evm.GasPrice)) + return nil, nil +} + +func opBlockhash(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { num := stack.pop() - n := evm.interpreter.intPool.get().Sub(evm.BlockNumber, common.Big257) - if num.Cmp(n) > 0 && num.Cmp(evm.BlockNumber) < 0 { - stack.push(evm.GetHash(num.Uint64()).Big()) + n := interpreter.intPool.get().Sub(interpreter.evm.BlockNumber, common.Big257) + if num.Cmp(n) > 0 && num.Cmp(interpreter.evm.BlockNumber) < 0 { + stack.push(interpreter.evm.GetHash(num.Uint64()).Big()) } else { - stack.push(new(big.Int)) + stack.push(interpreter.intPool.getZero()) } - - evm.interpreter.intPool.put(num, n) + interpreter.intPool.put(num, n) return nil, nil } -func opCoinbase(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(evm.Coinbase.Big()) +func opCoinbase(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(interpreter.evm.Coinbase.Big()) return nil, nil } -func opTimestamp(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(math.U256(new(big.Int).Set(evm.Time))) +func opTimestamp(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.Time))) return nil, nil } -func opNumber(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(math.U256(new(big.Int).Set(evm.BlockNumber))) +func opNumber(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.BlockNumber))) return nil, nil } -func opDifficulty(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(math.U256(new(big.Int).Set(evm.Difficulty))) +func opDifficulty(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.Difficulty))) return nil, nil } -func opGasLimit(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(math.U256(new(big.Int).SetUint64(evm.GasLimit))) +func opGasLimit(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(math.U256(interpreter.intPool.get().SetUint64(interpreter.evm.GasLimit))) return nil, nil } -func opPop(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - evm.interpreter.intPool.put(stack.pop()) +func opPop(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + interpreter.intPool.put(stack.pop()) return nil, nil } -func opMload(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opMload(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { offset := stack.pop() - val := new(big.Int).SetBytes(memory.Get(offset.Int64(), 32)) + val := interpreter.intPool.get().SetBytes(memory.Get(offset.Int64(), 32)) stack.push(val) - evm.interpreter.intPool.put(offset) + interpreter.intPool.put(offset) return nil, nil } -func opMstore(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opMstore(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { // pop value of the stack mStart, val := stack.pop(), stack.pop() - memory.Set(mStart.Uint64(), 32, math.PaddedBigBytes(val, 32)) + memory.Set32(mStart.Uint64(), val) - evm.interpreter.intPool.put(mStart, val) + interpreter.intPool.put(mStart, val) return nil, nil } -func opMstore8(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opMstore8(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { off, val := stack.pop().Int64(), stack.pop().Int64() memory.store[off] = byte(val & 0xff) return nil, nil } -func opSload(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - loc := common.BigToHash(stack.pop()) - val := evm.StateDB.GetState(contract.Address(), loc).Big() - stack.push(val) +func opSload(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + loc := stack.peek() + val := interpreter.evm.StateDB.GetState(contract.Address(), common.BigToHash(loc)) + loc.SetBytes(val.Bytes()) return nil, nil } -func opSstore(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opSstore(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { loc := common.BigToHash(stack.pop()) val := stack.pop() - evm.StateDB.SetState(contract.Address(), loc, common.BigToHash(val)) + interpreter.evm.StateDB.SetState(contract.Address(), loc, common.BigToHash(val)) - evm.interpreter.intPool.put(val) + interpreter.intPool.put(val) return nil, nil } -func opJump(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opJump(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { pos := stack.pop() - if !contract.jumpdests.has(contract.CodeHash, contract.Code, pos) { + if !contract.validJumpdest(pos) { nop := contract.GetOp(pos.Uint64()) return nil, fmt.Errorf("invalid jump destination (%v) %v", nop, pos) } *pc = pos.Uint64() - evm.interpreter.intPool.put(pos) + interpreter.intPool.put(pos) return nil, nil } -func opJumpi(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opJumpi(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { pos, cond := stack.pop(), stack.pop() if cond.Sign() != 0 { - if !contract.jumpdests.has(contract.CodeHash, contract.Code, pos) { + if !contract.validJumpdest(pos) { nop := contract.GetOp(pos.Uint64()) return nil, fmt.Errorf("invalid jump destination (%v) %v", nop, pos) } @@ -546,55 +666,55 @@ func opJumpi(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *St *pc++ } - evm.interpreter.intPool.put(pos, cond) + interpreter.intPool.put(pos, cond) return nil, nil } -func opJumpdest(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opJumpdest(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { return nil, nil } -func opPc(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(evm.interpreter.intPool.get().SetUint64(*pc)) +func opPc(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(interpreter.intPool.get().SetUint64(*pc)) return nil, nil } -func opMsize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(evm.interpreter.intPool.get().SetInt64(int64(memory.Len()))) +func opMsize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(interpreter.intPool.get().SetInt64(int64(memory.Len()))) return nil, nil } -func opGas(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(evm.interpreter.intPool.get().SetUint64(contract.Gas)) +func opGas(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(interpreter.intPool.get().SetUint64(contract.Gas)) return nil, nil } -func opCreate(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opCreate(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { var ( value = stack.pop() offset, size = stack.pop(), stack.pop() input = memory.Get(offset.Int64(), size.Int64()) gas = contract.Gas ) - if evm.ChainConfig().IsEIP150(evm.BlockNumber) { + if interpreter.evm.ChainConfig().IsEIP150(interpreter.evm.BlockNumber) { gas -= gas / 64 } contract.UseGas(gas) - res, addr, returnGas, suberr := evm.Create(contract, input, gas, value) + res, addr, returnGas, suberr := interpreter.evm.Create(contract, input, gas, value) // Push item on the stack based on the returned error. If the ruleset is // homestead we must check for CodeStoreOutOfGasError (homestead only // rule) and treat as an error, if the ruleset is frontier we must // ignore this error and pretend the operation was successful. - if evm.ChainConfig().IsHomestead(evm.BlockNumber) && suberr == ErrCodeStoreOutOfGas { - stack.push(new(big.Int)) + if interpreter.evm.ChainConfig().IsHomestead(interpreter.evm.BlockNumber) && suberr == ErrCodeStoreOutOfGas { + stack.push(interpreter.intPool.getZero()) } else if suberr != nil && suberr != ErrCodeStoreOutOfGas { - stack.push(new(big.Int)) + stack.push(interpreter.intPool.getZero()) } else { stack.push(addr.Big()) } contract.Gas += returnGas - evm.interpreter.intPool.put(value, offset, size) + interpreter.intPool.put(value, offset, size) if suberr == errExecutionReverted { return res, nil @@ -602,10 +722,38 @@ func opCreate(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S return nil, nil } -func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - // Pop gas. The actual gas in in evm.callGasTemp. - evm.interpreter.intPool.put(stack.pop()) - gas := evm.callGasTemp +func opCreate2(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + var ( + endowment = stack.pop() + offset, size = stack.pop(), stack.pop() + salt = stack.pop() + input = memory.Get(offset.Int64(), size.Int64()) + gas = contract.Gas + ) + + // Apply EIP150 + gas -= gas / 64 + contract.UseGas(gas) + res, addr, returnGas, suberr := interpreter.evm.Create2(contract, input, gas, endowment, salt) + // Push item on the stack based on the returned error. + if suberr != nil { + stack.push(interpreter.intPool.getZero()) + } else { + stack.push(addr.Big()) + } + contract.Gas += returnGas + interpreter.intPool.put(endowment, offset, size, salt) + + if suberr == errExecutionReverted { + return res, nil + } + return nil, nil +} + +func opCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + // Pop gas. The actual gas in interpreter.evm.callGasTemp. + interpreter.intPool.put(stack.pop()) + gas := interpreter.evm.callGasTemp // Pop other call parameters. addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() toAddr := common.BigToAddress(addr) @@ -616,25 +764,25 @@ func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta if value.Sign() != 0 { gas += params.CallStipend } - ret, returnGas, err := evm.Call(contract, toAddr, args, gas, value) + ret, returnGas, err := interpreter.evm.Call(contract, toAddr, args, gas, value) if err != nil { - stack.push(new(big.Int)) + stack.push(interpreter.intPool.getZero()) } else { - stack.push(big.NewInt(1)) + stack.push(interpreter.intPool.get().SetUint64(1)) } if err == nil || err == errExecutionReverted { memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } contract.Gas += returnGas - evm.interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize) + interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize) return ret, nil } -func opCallCode(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - // Pop gas. The actual gas is in evm.callGasTemp. - evm.interpreter.intPool.put(stack.pop()) - gas := evm.callGasTemp +func opCallCode(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + // Pop gas. The actual gas is in interpreter.evm.callGasTemp. + interpreter.intPool.put(stack.pop()) + gas := interpreter.evm.callGasTemp // Pop other call parameters. addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() toAddr := common.BigToAddress(addr) @@ -645,96 +793,96 @@ func opCallCode(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack if value.Sign() != 0 { gas += params.CallStipend } - ret, returnGas, err := evm.CallCode(contract, toAddr, args, gas, value) + ret, returnGas, err := interpreter.evm.CallCode(contract, toAddr, args, gas, value) if err != nil { - stack.push(new(big.Int)) + stack.push(interpreter.intPool.getZero()) } else { - stack.push(big.NewInt(1)) + stack.push(interpreter.intPool.get().SetUint64(1)) } if err == nil || err == errExecutionReverted { memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } contract.Gas += returnGas - evm.interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize) + interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize) return ret, nil } -func opDelegateCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - // Pop gas. The actual gas is in evm.callGasTemp. - evm.interpreter.intPool.put(stack.pop()) - gas := evm.callGasTemp +func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + // Pop gas. The actual gas is in interpreter.evm.callGasTemp. + interpreter.intPool.put(stack.pop()) + gas := interpreter.evm.callGasTemp // Pop other call parameters. addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() toAddr := common.BigToAddress(addr) // Get arguments from the memory. args := memory.Get(inOffset.Int64(), inSize.Int64()) - ret, returnGas, err := evm.DelegateCall(contract, toAddr, args, gas) + ret, returnGas, err := interpreter.evm.DelegateCall(contract, toAddr, args, gas) if err != nil { - stack.push(new(big.Int)) + stack.push(interpreter.intPool.getZero()) } else { - stack.push(big.NewInt(1)) + stack.push(interpreter.intPool.get().SetUint64(1)) } if err == nil || err == errExecutionReverted { memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } contract.Gas += returnGas - evm.interpreter.intPool.put(addr, inOffset, inSize, retOffset, retSize) + interpreter.intPool.put(addr, inOffset, inSize, retOffset, retSize) return ret, nil } -func opStaticCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - // Pop gas. The actual gas is in evm.callGasTemp. - evm.interpreter.intPool.put(stack.pop()) - gas := evm.callGasTemp +func opStaticCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + // Pop gas. The actual gas is in interpreter.evm.callGasTemp. + interpreter.intPool.put(stack.pop()) + gas := interpreter.evm.callGasTemp // Pop other call parameters. addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() toAddr := common.BigToAddress(addr) // Get arguments from the memory. args := memory.Get(inOffset.Int64(), inSize.Int64()) - ret, returnGas, err := evm.StaticCall(contract, toAddr, args, gas) + ret, returnGas, err := interpreter.evm.StaticCall(contract, toAddr, args, gas) if err != nil { - stack.push(new(big.Int)) + stack.push(interpreter.intPool.getZero()) } else { - stack.push(big.NewInt(1)) + stack.push(interpreter.intPool.get().SetUint64(1)) } if err == nil || err == errExecutionReverted { memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } contract.Gas += returnGas - evm.interpreter.intPool.put(addr, inOffset, inSize, retOffset, retSize) + interpreter.intPool.put(addr, inOffset, inSize, retOffset, retSize) return ret, nil } -func opReturn(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opReturn(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { offset, size := stack.pop(), stack.pop() ret := memory.GetPtr(offset.Int64(), size.Int64()) - evm.interpreter.intPool.put(offset, size) + interpreter.intPool.put(offset, size) return ret, nil } -func opRevert(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opRevert(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { offset, size := stack.pop(), stack.pop() ret := memory.GetPtr(offset.Int64(), size.Int64()) - evm.interpreter.intPool.put(offset, size) + interpreter.intPool.put(offset, size) return ret, nil } -func opStop(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opStop(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { return nil, nil } -func opSuicide(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - balance := evm.StateDB.GetBalance(contract.Address()) - evm.StateDB.AddBalance(common.BigToAddress(stack.pop()), balance) +func opSuicide(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + balance := interpreter.evm.StateDB.GetBalance(contract.Address()) + interpreter.evm.StateDB.AddBalance(common.BigToAddress(stack.pop()), balance) - evm.StateDB.Suicide(contract.Address()) + interpreter.evm.StateDB.Suicide(contract.Address()) return nil, nil } @@ -742,7 +890,7 @@ func opSuicide(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack * // make log instruction function func makeLog(size int) executionFunc { - return func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { topics := make([]common.Hash, size) mStart, mSize := stack.pop(), stack.pop() for i := 0; i < size; i++ { @@ -750,23 +898,23 @@ func makeLog(size int) executionFunc { } d := memory.Get(mStart.Int64(), mSize.Int64()) - evm.StateDB.AddLog(&types.Log{ + interpreter.evm.StateDB.AddLog(&types.Log{ Address: contract.Address(), Topics: topics, Data: d, // This is a non-consensus field, but assigned here because // core/state doesn't know the current block number. - BlockNumber: evm.BlockNumber.Uint64(), + BlockNumber: interpreter.evm.BlockNumber.Uint64(), }) - evm.interpreter.intPool.put(mStart, mSize) + interpreter.intPool.put(mStart, mSize) return nil, nil } } // make push instruction function func makePush(size uint64, pushByteSize int) executionFunc { - return func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { codeLen := len(contract.Code) startMin := codeLen @@ -779,7 +927,7 @@ func makePush(size uint64, pushByteSize int) executionFunc { endMin = startMin + pushByteSize } - integer := evm.interpreter.intPool.get() + integer := interpreter.intPool.get() stack.push(integer.SetBytes(common.RightPadBytes(contract.Code[startMin:endMin], pushByteSize))) *pc += size @@ -787,10 +935,10 @@ func makePush(size uint64, pushByteSize int) executionFunc { } } -// make push instruction function +// make dup instruction function func makeDup(size int64) executionFunc { - return func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.dup(evm.interpreter.intPool, int(size)) + return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.dup(interpreter.intPool, int(size)) return nil, nil } } @@ -798,8 +946,8 @@ func makeDup(size int64) executionFunc { // make swap instruction function func makeSwap(size int64) executionFunc { // switch n + 1 otherwise n would be swapped with n - size += 1 - return func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + size++ + return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.swap(int(size)) return nil, nil } diff --git a/core/vm/instructions_test.go b/core/vm/instructions_test.go index 18644989c1..8a48d765dd 100644 --- a/core/vm/instructions_test.go +++ b/core/vm/instructions_test.go @@ -1,18 +1,87 @@ +// Copyright 2017 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 vm import ( + "bytes" "math/big" "testing" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" ) +type twoOperandTest struct { + x string + y string + expected string +} + +func testTwoOperandOp(t *testing.T, tests []twoOperandTest, opFn func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error)) { + var ( + env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) + stack = newstack() + pc = uint64(0) + evmInterpreter = NewEVMInterpreter(env, env.vmConfig) + ) + + env.interpreter = evmInterpreter + evmInterpreter.intPool = poolOfIntPools.get() + for i, test := range tests { + x := new(big.Int).SetBytes(common.Hex2Bytes(test.x)) + shift := new(big.Int).SetBytes(common.Hex2Bytes(test.y)) + expected := new(big.Int).SetBytes(common.Hex2Bytes(test.expected)) + stack.push(x) + stack.push(shift) + opFn(&pc, evmInterpreter, nil, nil, stack) + actual := stack.pop() + if actual.Cmp(expected) != 0 { + t.Errorf("Testcase %d, expected %v, got %v", i, expected, actual) + } + // Check pool usage + // 1.pool is not allowed to contain anything on the stack + // 2.pool is not allowed to contain the same pointers twice + if evmInterpreter.intPool.pool.len() > 0 { + + poolvals := make(map[*big.Int]struct{}) + poolvals[actual] = struct{}{} + + for evmInterpreter.intPool.pool.len() > 0 { + key := evmInterpreter.intPool.get() + if _, exist := poolvals[key]; exist { + t.Errorf("Testcase %d, pool contains double-entry", i) + } + poolvals[key] = struct{}{} + } + } + } + poolOfIntPools.put(evmInterpreter.intPool) +} + func TestByteOp(t *testing.T) { var ( - env = NewEVM(Context{}, nil, params.TestChainConfig, Config{EnableJit: false, ForceJit: false}) - stack = newstack() + env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) + stack = newstack() + evmInterpreter = NewEVMInterpreter(env, env.vmConfig) ) + + env.interpreter = evmInterpreter + evmInterpreter.intPool = poolOfIntPools.get() tests := []struct { v string th uint64 @@ -33,19 +102,121 @@ func TestByteOp(t *testing.T) { th := new(big.Int).SetUint64(test.th) stack.push(val) stack.push(th) - opByte(&pc, env, nil, nil, stack) + opByte(&pc, evmInterpreter, nil, nil, stack) actual := stack.pop() if actual.Cmp(test.expected) != 0 { t.Fatalf("Expected [%v] %v:th byte to be %v, was %v.", test.v, test.th, test.expected, actual) } } + poolOfIntPools.put(evmInterpreter.intPool) } -func opBenchmark(bench *testing.B, op func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error), args ...string) { +func TestSHL(t *testing.T) { + // Testcases from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-145.md#shl-shift-left + tests := []twoOperandTest{ + {"0000000000000000000000000000000000000000000000000000000000000001", "00", "0000000000000000000000000000000000000000000000000000000000000001"}, + {"0000000000000000000000000000000000000000000000000000000000000001", "01", "0000000000000000000000000000000000000000000000000000000000000002"}, + {"0000000000000000000000000000000000000000000000000000000000000001", "ff", "8000000000000000000000000000000000000000000000000000000000000000"}, + {"0000000000000000000000000000000000000000000000000000000000000001", "0100", "0000000000000000000000000000000000000000000000000000000000000000"}, + {"0000000000000000000000000000000000000000000000000000000000000001", "0101", "0000000000000000000000000000000000000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "00", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "01", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ff", "8000000000000000000000000000000000000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0100", "0000000000000000000000000000000000000000000000000000000000000000"}, + {"0000000000000000000000000000000000000000000000000000000000000000", "01", "0000000000000000000000000000000000000000000000000000000000000000"}, + {"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "01", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"}, + } + testTwoOperandOp(t, tests, opSHL) +} + +func TestSHR(t *testing.T) { + // Testcases from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-145.md#shr-logical-shift-right + tests := []twoOperandTest{ + {"0000000000000000000000000000000000000000000000000000000000000001", "00", "0000000000000000000000000000000000000000000000000000000000000001"}, + {"0000000000000000000000000000000000000000000000000000000000000001", "01", "0000000000000000000000000000000000000000000000000000000000000000"}, + {"8000000000000000000000000000000000000000000000000000000000000000", "01", "4000000000000000000000000000000000000000000000000000000000000000"}, + {"8000000000000000000000000000000000000000000000000000000000000000", "ff", "0000000000000000000000000000000000000000000000000000000000000001"}, + {"8000000000000000000000000000000000000000000000000000000000000000", "0100", "0000000000000000000000000000000000000000000000000000000000000000"}, + {"8000000000000000000000000000000000000000000000000000000000000000", "0101", "0000000000000000000000000000000000000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "00", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "01", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ff", "0000000000000000000000000000000000000000000000000000000000000001"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0100", "0000000000000000000000000000000000000000000000000000000000000000"}, + {"0000000000000000000000000000000000000000000000000000000000000000", "01", "0000000000000000000000000000000000000000000000000000000000000000"}, + } + testTwoOperandOp(t, tests, opSHR) +} + +func TestSAR(t *testing.T) { + // Testcases from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-145.md#sar-arithmetic-shift-right + tests := []twoOperandTest{ + {"0000000000000000000000000000000000000000000000000000000000000001", "00", "0000000000000000000000000000000000000000000000000000000000000001"}, + {"0000000000000000000000000000000000000000000000000000000000000001", "01", "0000000000000000000000000000000000000000000000000000000000000000"}, + {"8000000000000000000000000000000000000000000000000000000000000000", "01", "c000000000000000000000000000000000000000000000000000000000000000"}, + {"8000000000000000000000000000000000000000000000000000000000000000", "ff", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, + {"8000000000000000000000000000000000000000000000000000000000000000", "0100", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, + {"8000000000000000000000000000000000000000000000000000000000000000", "0101", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "00", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "01", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ff", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0100", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, + {"0000000000000000000000000000000000000000000000000000000000000000", "01", "0000000000000000000000000000000000000000000000000000000000000000"}, + {"4000000000000000000000000000000000000000000000000000000000000000", "fe", "0000000000000000000000000000000000000000000000000000000000000001"}, + {"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "f8", "000000000000000000000000000000000000000000000000000000000000007f"}, + {"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "fe", "0000000000000000000000000000000000000000000000000000000000000001"}, + {"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ff", "0000000000000000000000000000000000000000000000000000000000000000"}, + {"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0100", "0000000000000000000000000000000000000000000000000000000000000000"}, + } + + testTwoOperandOp(t, tests, opSAR) +} + +func TestSGT(t *testing.T) { + tests := []twoOperandTest{ + + {"0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"}, + {"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"}, + {"0000000000000000000000000000000000000000000000000000000000000001", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000001"}, + {"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001"}, + {"0000000000000000000000000000000000000000000000000000000000000001", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"}, + {"8000000000000000000000000000000000000000000000000000000000000001", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"}, + {"8000000000000000000000000000000000000000000000000000000000000001", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000001"}, + {"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd", "0000000000000000000000000000000000000000000000000000000000000001"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb", "0000000000000000000000000000000000000000000000000000000000000000"}, + } + testTwoOperandOp(t, tests, opSgt) +} + +func TestSLT(t *testing.T) { + tests := []twoOperandTest{ + {"0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"}, + {"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"}, + {"0000000000000000000000000000000000000000000000000000000000000001", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"}, + {"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"}, + {"0000000000000000000000000000000000000000000000000000000000000001", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000001"}, + {"8000000000000000000000000000000000000000000000000000000000000001", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"}, + {"8000000000000000000000000000000000000000000000000000000000000001", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"}, + {"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd", "0000000000000000000000000000000000000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb", "0000000000000000000000000000000000000000000000000000000000000001"}, + } + testTwoOperandOp(t, tests, opSlt) +} + +func opBenchmark(bench *testing.B, op func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error), args ...string) { var ( - env = NewEVM(Context{}, nil, params.TestChainConfig, Config{EnableJit: false, ForceJit: false}) - stack = newstack() + env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) + stack = newstack() + evmInterpreter = NewEVMInterpreter(env, env.vmConfig) ) + + env.interpreter = evmInterpreter + evmInterpreter.intPool = poolOfIntPools.get() // convert args byteArgs := make([][]byte, len(args)) for i, arg := range args { @@ -58,9 +229,10 @@ func opBenchmark(bench *testing.B, op func(pc *uint64, evm *EVM, contract *Contr a := new(big.Int).SetBytes(arg) stack.push(a) } - op(&pc, env, nil, nil, stack) + op(&pc, evmInterpreter, nil, nil, stack) stack.pop() } + poolOfIntPools.put(evmInterpreter.intPool) } func BenchmarkOpAdd64(b *testing.B) { @@ -199,7 +371,11 @@ func BenchmarkOpEq(b *testing.B) { opBenchmark(b, opEq, x, y) } - +func BenchmarkOpEq2(b *testing.B) { + x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff" + y := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201fffffffe" + opBenchmark(b, opEq, x, y) +} func BenchmarkOpAnd(b *testing.B) { x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" @@ -243,3 +419,171 @@ func BenchmarkOpMulmod(b *testing.B) { opBenchmark(b, opMulmod, x, y, z) } + +func BenchmarkOpSHL(b *testing.B) { + x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff" + y := "ff" + + opBenchmark(b, opSHL, x, y) +} +func BenchmarkOpSHR(b *testing.B) { + x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff" + y := "ff" + + opBenchmark(b, opSHR, x, y) +} +func BenchmarkOpSAR(b *testing.B) { + x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff" + y := "ff" + + opBenchmark(b, opSAR, x, y) +} +func BenchmarkOpIsZero(b *testing.B) { + x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff" + opBenchmark(b, opIszero, x) +} + +func TestOpMstore(t *testing.T) { + var ( + env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) + stack = newstack() + mem = NewMemory() + evmInterpreter = NewEVMInterpreter(env, env.vmConfig) + ) + + env.interpreter = evmInterpreter + evmInterpreter.intPool = poolOfIntPools.get() + mem.Resize(64) + pc := uint64(0) + v := "abcdef00000000000000abba000000000deaf000000c0de00100000000133700" + stack.pushN(new(big.Int).SetBytes(common.Hex2Bytes(v)), big.NewInt(0)) + opMstore(&pc, evmInterpreter, nil, mem, stack) + if got := common.Bytes2Hex(mem.Get(0, 32)); got != v { + t.Fatalf("Mstore fail, got %v, expected %v", got, v) + } + stack.pushN(big.NewInt(0x1), big.NewInt(0)) + opMstore(&pc, evmInterpreter, nil, mem, stack) + if common.Bytes2Hex(mem.Get(0, 32)) != "0000000000000000000000000000000000000000000000000000000000000001" { + t.Fatalf("Mstore failed to overwrite previous value") + } + poolOfIntPools.put(evmInterpreter.intPool) +} + +func BenchmarkOpMstore(bench *testing.B) { + var ( + env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) + stack = newstack() + mem = NewMemory() + evmInterpreter = NewEVMInterpreter(env, env.vmConfig) + ) + + env.interpreter = evmInterpreter + evmInterpreter.intPool = poolOfIntPools.get() + mem.Resize(64) + pc := uint64(0) + memStart := big.NewInt(0) + value := big.NewInt(0x1337) + + bench.ResetTimer() + for i := 0; i < bench.N; i++ { + stack.pushN(value, memStart) + opMstore(&pc, evmInterpreter, nil, mem, stack) + } + poolOfIntPools.put(evmInterpreter.intPool) +} + +func BenchmarkOpSHA3(bench *testing.B) { + var ( + env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) + stack = newstack() + mem = NewMemory() + evmInterpreter = NewEVMInterpreter(env, env.vmConfig) + ) + env.interpreter = evmInterpreter + evmInterpreter.intPool = poolOfIntPools.get() + mem.Resize(32) + pc := uint64(0) + start := big.NewInt(0) + + bench.ResetTimer() + for i := 0; i < bench.N; i++ { + stack.pushN(big.NewInt(32), start) + opSha3(&pc, evmInterpreter, nil, mem, stack) + } + poolOfIntPools.put(evmInterpreter.intPool) +} + +func TestCreate2Addreses(t *testing.T) { + type testcase struct { + origin string + salt string + code string + expected string + } + + for i, tt := range []testcase{ + { + origin: "0x0000000000000000000000000000000000000000", + salt: "0x0000000000000000000000000000000000000000", + code: "0x00", + expected: "0x4d1a2e2bb4f88f0250f26ffff098b0b30b26bf38", + }, + { + origin: "0xdeadbeef00000000000000000000000000000000", + salt: "0x0000000000000000000000000000000000000000", + code: "0x00", + expected: "0xB928f69Bb1D91Cd65274e3c79d8986362984fDA3", + }, + { + origin: "0xdeadbeef00000000000000000000000000000000", + salt: "0xfeed000000000000000000000000000000000000", + code: "0x00", + expected: "0xD04116cDd17beBE565EB2422F2497E06cC1C9833", + }, + { + origin: "0x0000000000000000000000000000000000000000", + salt: "0x0000000000000000000000000000000000000000", + code: "0xdeadbeef", + expected: "0x70f2b2914A2a4b783FaEFb75f459A580616Fcb5e", + }, + { + origin: "0x00000000000000000000000000000000deadbeef", + salt: "0xcafebabe", + code: "0xdeadbeef", + expected: "0x60f3f640a8508fC6a86d45DF051962668E1e8AC7", + }, + { + origin: "0x00000000000000000000000000000000deadbeef", + salt: "0xcafebabe", + code: "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", + expected: "0x1d8bfDC5D46DC4f61D6b6115972536eBE6A8854C", + }, + { + origin: "0x0000000000000000000000000000000000000000", + salt: "0x0000000000000000000000000000000000000000", + code: "0x", + expected: "0xE33C0C7F7df4809055C3ebA6c09CFe4BaF1BD9e0", + }, + } { + + origin := common.BytesToAddress(common.FromHex(tt.origin)) + salt := common.BytesToHash(common.FromHex(tt.salt)) + code := common.FromHex(tt.code) + codeHash := crypto.Keccak256(code) + address := crypto.CreateAddress2(origin, salt, codeHash) + /* + stack := newstack() + // salt, but we don't need that for this test + stack.push(big.NewInt(int64(len(code)))) //size + stack.push(big.NewInt(0)) // memstart + stack.push(big.NewInt(0)) // value + gas, _ := gasCreate2(params.GasTable{}, nil, nil, stack, nil, 0) + fmt.Printf("Example %d\n* address `0x%x`\n* salt `0x%x`\n* init_code `0x%x`\n* gas (assuming no mem expansion): `%v`\n* result: `%s`\n\n", i,origin, salt, code, gas, address.String()) + */ + expected := common.BytesToAddress(common.FromHex(tt.expected)) + if !bytes.Equal(expected.Bytes(), address.Bytes()) { + t.Errorf("test %d: expected %s, got %s", i, expected.String(), address.String()) + } + + } +} diff --git a/core/vm/interface.go b/core/vm/interface.go index 1ef91cf1d6..fc15082f18 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -40,8 +40,10 @@ type StateDB interface { GetCodeSize(common.Address) int AddRefund(uint64) + SubRefund(uint64) GetRefund() uint64 + GetCommittedState(common.Address, common.Hash) common.Hash GetState(common.Address, common.Hash) common.Hash SetState(common.Address, common.Hash, common.Hash) @@ -64,7 +66,7 @@ type StateDB interface { ForEachStorage(common.Address, func(common.Hash, common.Hash) bool) } -// CallContext provides a basic interface for the EVM calling conventions. The EVM EVM +// CallContext provides a basic interface for the EVM calling conventions. The EVM // depends on this context being implemented for doing subcalls and initialising new EVM contracts. type CallContext interface { // Call another contract diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 482e67a3a9..c9dc3c00c6 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -18,11 +18,11 @@ package vm import ( "fmt" + "hash" "sync/atomic" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" ) @@ -30,46 +30,78 @@ import ( type Config struct { // Debug enabled debugging Interpreter options Debug bool - // EnableJit enabled the JIT VM - EnableJit bool - // ForceJit forces the JIT VM - ForceJit bool // Tracer is the op code logger Tracer Tracer // NoRecursion disabled Interpreter call, callcode, // delegate call and create. NoRecursion bool - // Disable gas metering - DisableGasMetering bool // Enable recording of SHA3/keccak preimages EnablePreimageRecording bool // JumpTable contains the EVM instruction table. This // may be left uninitialised and will be set to the default // table. JumpTable [256]operation + + // Type of the EWASM interpreter + EWASMInterpreter string + // Type of the EVM interpreter + EVMInterpreter string } // Interpreter is used to run Ethereum based contracts and will utilise the -// passed evmironment to query external sources for state information. -// The Interpreter will run the byte code VM or JIT VM based on the passed +// passed environment to query external sources for state information. +// The Interpreter will run the byte code VM based on the passed // configuration. -type Interpreter struct { +type Interpreter interface { + // 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. + Run(contract *Contract, input []byte, static bool) ([]byte, error) + // CanRun tells if the contract, passed as an argument, can be + // run by the current interpreter. This is meant so that the + // caller can do something like: + // + // ```golang + // for _, interpreter := range interpreters { + // if interpreter.CanRun(contract.code) { + // interpreter.Run(contract.code, input) + // } + // } + // ``` + CanRun([]byte) bool +} + +// keccakState wraps sha3.state. In addition to the usual hash methods, it also supports +// Read to get a variable amount of data from the hash state. Read is faster than Sum +// because it doesn't copy the internal state, but also modifies the internal state. +type keccakState interface { + hash.Hash + Read([]byte) (int, error) +} + +// EVMInterpreter represents an EVM interpreter +type EVMInterpreter struct { evm *EVM cfg Config gasTable params.GasTable - intPool *intPool + + intPool *intPool + + hasher keccakState // Keccak256 hasher instance shared across opcodes + hasherBuf common.Hash // Keccak256 hasher result array shared aross opcodes readOnly bool // Whether to throw on stateful modifications returnData []byte // Last CALL's return data for subsequent reuse } -// NewInterpreter returns a new instance of the Interpreter. -func NewInterpreter(evm *EVM, cfg Config) *Interpreter { +// NewEVMInterpreter returns a new instance of the Interpreter. +func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter { // We use the STOP instruction whether to see // the jump table was initialised. If it was not // we'll set the default jump table. if !cfg.JumpTable[STOP].valid { switch { + case evm.ChainConfig().IsConstantinople(evm.BlockNumber): + cfg.JumpTable = constantinopleInstructionSet case evm.ChainConfig().IsByzantium(evm.BlockNumber): cfg.JumpTable = byzantiumInstructionSet case evm.ChainConfig().IsHomestead(evm.BlockNumber): @@ -79,15 +111,14 @@ func NewInterpreter(evm *EVM, cfg Config) *Interpreter { } } - return &Interpreter{ + return &EVMInterpreter{ evm: evm, cfg: cfg, gasTable: evm.ChainConfig().GasTable(evm.BlockNumber), - intPool: newIntPool(), } } -func (in *Interpreter) enforceRestrictions(op OpCode, operation operation, stack *Stack) error { +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 @@ -109,11 +140,26 @@ func (in *Interpreter) enforceRestrictions(op OpCode, operation operation, stack // It's important to note that any errors returned by the interpreter should be // considered a revert-and-consume-all-gas operation except for // errExecutionReverted which means revert-and-keep-gas-left. -func (in *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err error) { +func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (ret []byte, err error) { + if in.intPool == nil { + in.intPool = poolOfIntPools.get() + defer func() { + poolOfIntPools.put(in.intPool) + in.intPool = nil + }() + } + // Increment the call depth which is restricted to 1024 in.evm.depth++ defer func() { in.evm.depth-- }() + // Make sure the readOnly is only set if we aren't in readOnly yet. + // This makes also sure that the readOnly flag isn't removed for child calls. + if readOnly && !in.readOnly { + in.readOnly = true + defer func() { in.readOnly = false }() + } + // Reset the previous call's return data. It's unimportant to preserve the old buffer // as every returning call will return new data anyway. in.returnData = nil @@ -123,11 +169,6 @@ func (in *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err er return nil, nil } - codehash := contract.CodeHash // codehash is used when doing jump dest caching - if codehash == (common.Hash{}) { - codehash = crypto.Keccak256Hash(contract.Code) - } - var ( op OpCode // current opcode mem = NewMemory() // bound memory @@ -141,9 +182,13 @@ func (in *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err er 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 + // Reclaim the stack as an int pool when the execution stops + defer func() { in.intPool.put(stack.data...) }() + if in.cfg.Debug { defer func() { if err != nil { @@ -172,11 +217,11 @@ func (in *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err er if !operation.valid { return nil, fmt.Errorf("invalid opcode 0x%x", int(op)) } - if err := operation.validateStack(stack); err != nil { + if err = operation.validateStack(stack); err != nil { return nil, err } // If the operation is valid, enforce and write restrictions - if err := in.enforceRestrictions(op, operation, stack); err != nil { + if err = in.enforceRestrictions(op, operation, stack); err != nil { return nil, err } @@ -194,14 +239,11 @@ func (in *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err er return nil, errGasUintOverflow } } - - if !in.cfg.DisableGasMetering { - // consume the gas and return an error if not enough gas is available. - // cost is explicitly set so that the capture state defer method cas 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 - } + // 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 memorySize > 0 { mem.Resize(memorySize) @@ -213,7 +255,7 @@ func (in *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err er } // execute the operation - res, err := operation.execute(&pc, in.evm, 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 { @@ -238,3 +280,9 @@ func (in *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err er } return nil, nil } + +// CanRun tells if the contract, passed as an argument, can be +// run by the current interpreter. +func (in *EVMInterpreter) CanRun(code []byte) bool { + return true +} diff --git a/core/vm/intpool.go b/core/vm/intpool.go index 384f5df59b..917a78d560 100644 --- a/core/vm/intpool.go +++ b/core/vm/intpool.go @@ -16,7 +16,10 @@ package vm -import "math/big" +import ( + "math/big" + "sync" +) var checkVal = big.NewInt(-42) @@ -32,24 +35,72 @@ func newIntPool() *intPool { return &intPool{pool: newstack()} } +// get retrieves a big int from the pool, allocating one if the pool is empty. +// Note, the returned int's value is arbitrary and will not be zeroed! func (p *intPool) get() *big.Int { if p.pool.len() > 0 { return p.pool.pop() } return new(big.Int) } + +// getZero retrieves a big int from the pool, setting it to zero or allocating +// a new one if the pool is empty. +func (p *intPool) getZero() *big.Int { + if p.pool.len() > 0 { + return p.pool.pop().SetUint64(0) + } + return new(big.Int) +} + +// put returns an allocated big int to the pool to be later reused by get calls. +// Note, the values as saved as is; neither put nor get zeroes the ints out! func (p *intPool) put(is ...*big.Int) { if len(p.pool.data) > poolLimit { return } - for _, i := range is { // verifyPool is a build flag. Pool verification makes sure the integrity // of the integer pool by comparing values to a default value. if verifyPool { i.Set(checkVal) } - p.pool.push(i) } } + +// The intPool pool's default capacity +const poolDefaultCap = 25 + +// intPoolPool manages a pool of intPools. +type intPoolPool struct { + pools []*intPool + lock sync.Mutex +} + +var poolOfIntPools = &intPoolPool{ + pools: make([]*intPool, 0, poolDefaultCap), +} + +// get is looking for an available pool to return. +func (ipp *intPoolPool) get() *intPool { + ipp.lock.Lock() + defer ipp.lock.Unlock() + + if len(poolOfIntPools.pools) > 0 { + ip := ipp.pools[len(ipp.pools)-1] + ipp.pools = ipp.pools[:len(ipp.pools)-1] + return ip + } + return newIntPool() +} + +// put a pool that has been allocated with get. +func (ipp *intPoolPool) put(ip *intPool) { + ipp.lock.Lock() + defer ipp.lock.Unlock() + + if len(ipp.pools) < cap(ipp.pools) { + ipp.pools = append(ipp.pools, ip) + } +} diff --git a/core/vm/intpool_test.go b/core/vm/intpool_test.go new file mode 100644 index 0000000000..6c0d00f3ce --- /dev/null +++ b/core/vm/intpool_test.go @@ -0,0 +1,55 @@ +// 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 vm + +import ( + "testing" +) + +func TestIntPoolPoolGet(t *testing.T) { + poolOfIntPools.pools = make([]*intPool, 0, poolDefaultCap) + + nip := poolOfIntPools.get() + if nip == nil { + t.Fatalf("Invalid pool allocation") + } +} + +func TestIntPoolPoolPut(t *testing.T) { + poolOfIntPools.pools = make([]*intPool, 0, poolDefaultCap) + + nip := poolOfIntPools.get() + if len(poolOfIntPools.pools) != 0 { + t.Fatalf("Pool got added to list when none should have been") + } + + poolOfIntPools.put(nip) + if len(poolOfIntPools.pools) == 0 { + t.Fatalf("Pool did not get added to list when one should have been") + } +} + +func TestIntPoolPoolReUse(t *testing.T) { + poolOfIntPools.pools = make([]*intPool, 0, poolDefaultCap) + nip := poolOfIntPools.get() + poolOfIntPools.put(nip) + poolOfIntPools.get() + + if len(poolOfIntPools.pools) != 0 { + t.Fatalf("Invalid number of pools. Got %d, expected %d", len(poolOfIntPools.pools), 0) + } +} diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index a1c5ad9c67..deedf70cdb 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -24,7 +24,7 @@ import ( ) type ( - executionFunc func(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) + 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 @@ -33,7 +33,7 @@ type ( var errGasUintOverflow = errors.New("gas uint64 overflow") type operation struct { - // op is the operation function + // execute is the operation function execute executionFunc // gasCost is the gas function and returns the gas required for execution gasCost gasFunc @@ -51,16 +51,58 @@ type operation struct { } var ( - frontierInstructionSet = NewFrontierInstructionSet() - homesteadInstructionSet = NewHomesteadInstructionSet() - byzantiumInstructionSet = NewByzantiumInstructionSet() + frontierInstructionSet = newFrontierInstructionSet() + homesteadInstructionSet = newHomesteadInstructionSet() + byzantiumInstructionSet = newByzantiumInstructionSet() + constantinopleInstructionSet = newConstantinopleInstructionSet() ) +// NewConstantinopleInstructionSet returns the frontier, homestead +// byzantium and contantinople instructions. +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, + } + instructionSet[SHR] = operation{ + execute: opSHR, + gasCost: constGasFunc(GasFastestStep), + validateStack: makeStackFunc(2, 1), + valid: true, + } + instructionSet[SAR] = operation{ + execute: opSAR, + gasCost: constGasFunc(GasFastestStep), + validateStack: makeStackFunc(2, 1), + valid: true, + } + instructionSet[EXTCODEHASH] = operation{ + execute: opExtCodeHash, + gasCost: gasExtCodeHash, + validateStack: makeStackFunc(1, 1), + valid: true, + } + instructionSet[CREATE2] = operation{ + execute: opCreate2, + gasCost: gasCreate2, + validateStack: makeStackFunc(4, 1), + memorySize: memoryCreate2, + valid: true, + writes: true, + returns: true, + } + return instructionSet +} + // NewByzantiumInstructionSet returns the frontier, homestead and // byzantium instructions. -func NewByzantiumInstructionSet() [256]operation { +func newByzantiumInstructionSet() [256]operation { // instructions that can be executed during the homestead phase. - instructionSet := NewHomesteadInstructionSet() + instructionSet := newHomesteadInstructionSet() instructionSet[STATICCALL] = operation{ execute: opStaticCall, gasCost: gasStaticCall, @@ -96,8 +138,8 @@ func NewByzantiumInstructionSet() [256]operation { // NewHomesteadInstructionSet returns the frontier and homestead // instructions that can be executed during the homestead phase. -func NewHomesteadInstructionSet() [256]operation { - instructionSet := NewFrontierInstructionSet() +func newHomesteadInstructionSet() [256]operation { + instructionSet := newFrontierInstructionSet() instructionSet[DELEGATECALL] = operation{ execute: opDelegateCall, gasCost: gasDelegateCall, @@ -111,7 +153,7 @@ func NewHomesteadInstructionSet() [256]operation { // NewFrontierInstructionSet returns the frontier instructions // that can be executed during the frontier phase. -func NewFrontierInstructionSet() [256]operation { +func newFrontierInstructionSet() [256]operation { return [256]operation{ STOP: { execute: opStop, diff --git a/core/vm/logger.go b/core/vm/logger.go index 4c820d8b53..1733bf2700 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -29,11 +29,13 @@ import ( "github.com/ethereum/go-ethereum/core/types" ) +// Storage represents a contract's storage. type Storage map[common.Hash]common.Hash -func (self Storage) Copy() Storage { +// Copy duplicates the current storage. +func (s Storage) Copy() Storage { cpy := make(Storage) - for key, value := range self { + for key, value := range s { cpy[key] = value } @@ -45,6 +47,7 @@ type LogConfig struct { DisableMemory bool // disable memory capture DisableStack bool // disable stack capture DisableStorage bool // disable storage capture + Debug bool // print output during capture end Limit int // maximum length of output, but zero means unlimited } @@ -53,16 +56,17 @@ type LogConfig struct { // StructLog is emitted to the EVM each cycle and lists information about the current internal state // prior to the execution of the statement. type StructLog struct { - Pc uint64 `json:"pc"` - Op OpCode `json:"op"` - Gas uint64 `json:"gas"` - GasCost uint64 `json:"gasCost"` - Memory []byte `json:"memory"` - MemorySize int `json:"memSize"` - Stack []*big.Int `json:"stack"` - Storage map[common.Hash]common.Hash `json:"-"` - Depth int `json:"depth"` - Err error `json:"-"` + Pc uint64 `json:"pc"` + Op OpCode `json:"op"` + Gas uint64 `json:"gas"` + GasCost uint64 `json:"gasCost"` + Memory []byte `json:"memory"` + MemorySize int `json:"memSize"` + Stack []*big.Int `json:"stack"` + Storage map[common.Hash]common.Hash `json:"-"` + Depth int `json:"depth"` + RefundCounter uint64 `json:"refund"` + Err error `json:"-"` } // overrides for gencodec @@ -75,10 +79,12 @@ type structLogMarshaling struct { ErrorString string `json:"error"` // adds call to ErrorString() in MarshalJSON } +// OpName formats the operand name in a human-readable format. func (s *StructLog) OpName() string { return s.Op.String() } +// ErrorString formats the log's error as a string. func (s *StructLog) ErrorString() string { if s.Err != nil { return s.Err.Error() @@ -123,6 +129,7 @@ func NewStructLogger(cfg *LogConfig) *StructLogger { return logger } +// CaptureStart implements the Tracer interface to initialize the tracing operation. func (l *StructLogger) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) error { return nil } @@ -171,19 +178,28 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui storage = l.changedValues[contract.Address()].Copy() } // create a new snaptshot of the EVM. - log := StructLog{pc, op, gas, cost, mem, memory.Len(), stck, storage, depth, err} + log := StructLog{pc, op, gas, cost, mem, memory.Len(), stck, storage, depth, env.StateDB.GetRefund(), err} l.logs = append(l.logs, log) return nil } +// CaptureFault implements the Tracer interface to trace an execution fault +// while running an opcode. func (l *StructLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error { return nil } +// CaptureEnd is called after the call finishes to finalize the tracing. func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error { l.output = output l.err = err + if l.cfg.Debug { + fmt.Printf("0x%x\n", output) + if err != nil { + fmt.Printf(" error: %v\n", err) + } + } return nil } diff --git a/cmd/evm/json_logger.go b/core/vm/logger_json.go similarity index 53% rename from cmd/evm/json_logger.go rename to core/vm/logger_json.go index 47daf7dbbc..ff379a4efd 100644 --- a/cmd/evm/json_logger.go +++ b/core/vm/logger_json.go @@ -1,20 +1,20 @@ // Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. +// This file is part of go-ethereum. // -// 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 +// 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. // -// The go-ethereum library is distributed in the hope that it will be useful, +// 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 Lesser General Public License for more details. +// GNU 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 . +// 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,16 +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 } -func NewJSONLogger(cfg *vm.LogConfig, writer io.Writer) *JSONLogger { - return &JSONLogger{json.NewEncoder(writer), cfg} +// NewJSONLogger creates a new EVM tracer that prints execution steps as JSON objects +// into the provided stream. +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 { @@ -41,16 +46,17 @@ 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{ - Pc: pc, - Op: op, - Gas: gas, - GasCost: cost, - MemorySize: memory.Len(), - Storage: nil, - Depth: depth, - Err: err, +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, + GasCost: cost, + MemorySize: memory.Len(), + Storage: nil, + Depth: depth, + RefundCounter: env.StateDB.GetRefund(), + Err: err, } if !l.cfg.DisableMemory { log.Memory = memory.Data() @@ -62,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/core/vm/logger_test.go b/core/vm/logger_test.go index 915f7177e7..2ea7535a79 100644 --- a/core/vm/logger_test.go +++ b/core/vm/logger_test.go @@ -21,6 +21,7 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/params" ) @@ -41,14 +42,15 @@ func (d *dummyContractRef) SetBalance(*big.Int) {} func (d *dummyContractRef) SetNonce(uint64) {} func (d *dummyContractRef) Balance() *big.Int { return new(big.Int) } -type dummyStateDB struct { - NoopStateDB - ref *dummyContractRef +type dummyStatedb struct { + state.StateDB } +func (*dummyStatedb) GetRefund() uint64 { return 1337 } + func TestStoreCapture(t *testing.T) { var ( - env = NewEVM(Context{}, nil, params.TestChainConfig, Config{EnableJit: false, ForceJit: false}) + env = NewEVM(Context{}, &dummyStatedb{}, params.TestChainConfig, Config{}) logger = NewStructLogger(nil) mem = NewMemory() stack = newstack() @@ -56,9 +58,7 @@ func TestStoreCapture(t *testing.T) { ) stack.push(big.NewInt(1)) stack.push(big.NewInt(0)) - var index common.Hash - logger.CaptureState(env, 0, SSTORE, 0, 0, mem, stack, contract, 0, nil) if len(logger.changedValues[contract.Address()]) == 0 { t.Fatalf("expected exactly 1 changed value on address %x, got %d", contract.Address(), len(logger.changedValues[contract.Address()])) diff --git a/core/vm/memory.go b/core/vm/memory.go index 99a84d2271..7e6f0eb940 100644 --- a/core/vm/memory.go +++ b/core/vm/memory.go @@ -16,7 +16,12 @@ package vm -import "fmt" +import ( + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common/math" +) // Memory implements a simple memory model for the ethereum virtual machine. type Memory struct { @@ -24,25 +29,39 @@ type Memory struct { lastGasCost uint64 } +// NewMemory returns a new memory model. func NewMemory() *Memory { return &Memory{} } // Set sets offset + size to value func (m *Memory) Set(offset, size uint64, value []byte) { - // length of store may never be less than offset + size. - // The store should be resized PRIOR to setting the memory - if size > uint64(len(m.store)) { - panic("INVALID memory: store empty") - } - // It's possible the offset is greater than 0 and size equals 0. This is because // the calcMemSize (common.go) could potentially return 0 when size is zero (NO-OP) if size > 0 { + // length of store may never be less than offset + size. + // The store should be resized PRIOR to setting the memory + if offset+size > uint64(len(m.store)) { + panic("invalid memory: store empty") + } copy(m.store[offset:offset+size], value) } } +// Set32 sets the 32 bytes starting at offset to the value of val, left-padded with zeroes to +// 32 bytes. +func (m *Memory) Set32(offset uint64, val *big.Int) { + // length of store may never be less than offset + size. + // The store should be resized PRIOR to setting the memory + if offset+32 > uint64(len(m.store)) { + panic("invalid memory: store empty") + } + // Zero the memory area + copy(m.store[offset:offset+32], []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, 0, 0}) + // Fill in relevant bits + math.ReadBits(val, m.store[offset:offset+32]) +} + // Resize resizes the memory to size func (m *Memory) Resize(size uint64) { if uint64(m.Len()) < size { @@ -51,14 +70,14 @@ func (m *Memory) Resize(size uint64) { } // Get returns offset + size as a new slice -func (self *Memory) Get(offset, size int64) (cpy []byte) { +func (m *Memory) Get(offset, size int64) (cpy []byte) { if size == 0 { return nil } - if len(self.store) > int(offset) { + if len(m.store) > int(offset) { cpy = make([]byte, size) - copy(cpy, self.store[offset:offset+size]) + copy(cpy, m.store[offset:offset+size]) return } @@ -67,13 +86,13 @@ func (self *Memory) Get(offset, size int64) (cpy []byte) { } // GetPtr returns the offset + size -func (self *Memory) GetPtr(offset, size int64) []byte { +func (m *Memory) GetPtr(offset, size int64) []byte { if size == 0 { return nil } - if len(self.store) > int(offset) { - return self.store[offset : offset+size] + if len(m.store) > int(offset) { + return m.store[offset : offset+size] } return nil @@ -89,6 +108,7 @@ func (m *Memory) Data() []byte { return m.store } +// Print dumps the content of the memory. func (m *Memory) Print() { fmt.Printf("### mem %d bytes ###\n", len(m.store)) if len(m.store) > 0 { diff --git a/core/vm/memory_table.go b/core/vm/memory_table.go index bec0235bcc..8fa6c90ca7 100644 --- a/core/vm/memory_table.go +++ b/core/vm/memory_table.go @@ -58,6 +58,10 @@ func memoryCreate(stack *Stack) *big.Int { return calcMemSize(stack.Back(1), stack.Back(2)) } +func memoryCreate2(stack *Stack) *big.Int { + return calcMemSize(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)) @@ -65,12 +69,6 @@ func memoryCall(stack *Stack) *big.Int { return math.BigMax(x, y) } -func memoryCallCode(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 memoryDelegateCall(stack *Stack) *big.Int { x := calcMemSize(stack.Back(4), stack.Back(5)) y := calcMemSize(stack.Back(2), stack.Back(3)) diff --git a/core/vm/noop.go b/core/vm/noop.go deleted file mode 100644 index b71ead0d77..0000000000 --- a/core/vm/noop.go +++ /dev/null @@ -1,70 +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 vm - -import ( - "math/big" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" -) - -func NoopCanTransfer(db StateDB, from common.Address, balance *big.Int) bool { - return true -} -func NoopTransfer(db StateDB, from, to common.Address, amount *big.Int) {} - -type NoopEVMCallContext struct{} - -func (NoopEVMCallContext) Call(caller ContractRef, addr common.Address, data []byte, gas, value *big.Int) ([]byte, error) { - return nil, nil -} -func (NoopEVMCallContext) CallCode(caller ContractRef, addr common.Address, data []byte, gas, value *big.Int) ([]byte, error) { - return nil, nil -} -func (NoopEVMCallContext) Create(caller ContractRef, data []byte, gas, value *big.Int) ([]byte, common.Address, error) { - return nil, common.Address{}, nil -} -func (NoopEVMCallContext) DelegateCall(me ContractRef, addr common.Address, data []byte, gas *big.Int) ([]byte, error) { - return nil, nil -} - -type NoopStateDB struct{} - -func (NoopStateDB) CreateAccount(common.Address) {} -func (NoopStateDB) SubBalance(common.Address, *big.Int) {} -func (NoopStateDB) AddBalance(common.Address, *big.Int) {} -func (NoopStateDB) GetBalance(common.Address) *big.Int { return nil } -func (NoopStateDB) GetNonce(common.Address) uint64 { return 0 } -func (NoopStateDB) SetNonce(common.Address, uint64) {} -func (NoopStateDB) GetCodeHash(common.Address) common.Hash { return common.Hash{} } -func (NoopStateDB) GetCode(common.Address) []byte { return nil } -func (NoopStateDB) SetCode(common.Address, []byte) {} -func (NoopStateDB) GetCodeSize(common.Address) int { return 0 } -func (NoopStateDB) AddRefund(uint64) {} -func (NoopStateDB) GetRefund() uint64 { return 0 } -func (NoopStateDB) GetState(common.Address, common.Hash) common.Hash { return common.Hash{} } -func (NoopStateDB) SetState(common.Address, common.Hash, common.Hash) {} -func (NoopStateDB) Suicide(common.Address) bool { return false } -func (NoopStateDB) HasSuicided(common.Address) bool { return false } -func (NoopStateDB) Exist(common.Address) bool { return false } -func (NoopStateDB) Empty(common.Address) bool { return false } -func (NoopStateDB) RevertToSnapshot(int) {} -func (NoopStateDB) Snapshot() int { return 0 } -func (NoopStateDB) AddLog(*types.Log) {} -func (NoopStateDB) AddPreimage(common.Hash, []byte) {} -func (NoopStateDB) ForEachStorage(common.Address, func(common.Hash, common.Hash) bool) {} diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go index 0c65507355..4349ffd295 100644 --- a/core/vm/opcodes.go +++ b/core/vm/opcodes.go @@ -23,6 +23,7 @@ import ( // OpCode is an EVM opcode type OpCode byte +// IsPush specifies if an opcode is a PUSH opcode. func (op OpCode) IsPush() bool { switch op { case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32: @@ -31,12 +32,13 @@ func (op OpCode) IsPush() bool { return false } +// IsStaticJump specifies if an opcode is JUMP. func (op OpCode) IsStaticJump() bool { return op == JUMP } +// 0x0 range - arithmetic ops. const ( - // 0x0 range - arithmetic ops STOP OpCode = iota ADD MUL @@ -51,6 +53,7 @@ const ( SIGNEXTEND ) +// 0x10 range - comparison ops. const ( LT OpCode = iota + 0x10 GT @@ -63,12 +66,15 @@ const ( XOR NOT BYTE + SHL + SHR + SAR SHA3 = 0x20 ) +// 0x30 range - closure state. const ( - // 0x30 range - closure state ADDRESS OpCode = 0x30 + iota BALANCE ORIGIN @@ -84,10 +90,11 @@ const ( EXTCODECOPY RETURNDATASIZE RETURNDATACOPY + EXTCODEHASH ) +// 0x40 range - block operations. const ( - // 0x40 range - block operations BLOCKHASH OpCode = 0x40 + iota COINBASE TIMESTAMP @@ -96,8 +103,8 @@ const ( GASLIMIT ) +// 0x50 range - 'storage' and execution. const ( - // 0x50 range - 'storage' and execution POP OpCode = 0x50 + iota MLOAD MSTORE @@ -112,8 +119,8 @@ const ( JUMPDEST ) +// 0x60 range. const ( - // 0x60 range PUSH1 OpCode = 0x60 + iota PUSH2 PUSH3 @@ -180,6 +187,7 @@ const ( SWAP16 ) +// 0xa0 range - logging ops. const ( LOG0 OpCode = 0xa0 + iota LOG1 @@ -188,29 +196,30 @@ const ( LOG4 ) -// unofficial opcodes used for parsing +// unofficial opcodes used for parsing. const ( PUSH OpCode = 0xb0 + iota DUP SWAP ) +// 0xf0 range - closures. const ( - // 0xf0 range - closures CREATE OpCode = 0xf0 + iota CALL CALLCODE RETURN DELEGATECALL + CREATE2 STATICCALL = 0xfa REVERT = 0xfd SELFDESTRUCT = 0xff ) -// Since the opcodes aren't all in order we can't use a regular slice +// Since the opcodes aren't all in order we can't use a regular slice. var opCodeToString = map[OpCode]string{ - // 0x0 range - arithmetic ops + // 0x0 range - arithmetic ops. STOP: "STOP", ADD: "ADD", MUL: "MUL", @@ -229,18 +238,21 @@ var opCodeToString = map[OpCode]string{ ISZERO: "ISZERO", SIGNEXTEND: "SIGNEXTEND", - // 0x10 range - bit ops + // 0x10 range - bit ops. AND: "AND", OR: "OR", XOR: "XOR", BYTE: "BYTE", + SHL: "SHL", + SHR: "SHR", + SAR: "SAR", ADDMOD: "ADDMOD", MULMOD: "MULMOD", - // 0x20 range - crypto + // 0x20 range - crypto. SHA3: "SHA3", - // 0x30 range - closure state + // 0x30 range - closure state. ADDRESS: "ADDRESS", BALANCE: "BALANCE", ORIGIN: "ORIGIN", @@ -256,8 +268,9 @@ var opCodeToString = map[OpCode]string{ EXTCODECOPY: "EXTCODECOPY", RETURNDATASIZE: "RETURNDATASIZE", RETURNDATACOPY: "RETURNDATACOPY", + EXTCODEHASH: "EXTCODEHASH", - // 0x40 range - block operations + // 0x40 range - block operations. BLOCKHASH: "BLOCKHASH", COINBASE: "COINBASE", TIMESTAMP: "TIMESTAMP", @@ -265,7 +278,7 @@ var opCodeToString = map[OpCode]string{ DIFFICULTY: "DIFFICULTY", GASLIMIT: "GASLIMIT", - // 0x50 range - 'storage' and execution + // 0x50 range - 'storage' and execution. POP: "POP", //DUP: "DUP", //SWAP: "SWAP", @@ -281,7 +294,7 @@ var opCodeToString = map[OpCode]string{ GAS: "GAS", JUMPDEST: "JUMPDEST", - // 0x60 range - push + // 0x60 range - push. PUSH1: "PUSH1", PUSH2: "PUSH2", PUSH3: "PUSH3", @@ -354,12 +367,13 @@ var opCodeToString = map[OpCode]string{ LOG3: "LOG3", LOG4: "LOG4", - // 0xf0 range + // 0xf0 range. CREATE: "CREATE", CALL: "CALL", RETURN: "RETURN", CALLCODE: "CALLCODE", DELEGATECALL: "DELEGATECALL", + CREATE2: "CREATE2", STATICCALL: "STATICCALL", REVERT: "REVERT", SELFDESTRUCT: "SELFDESTRUCT", @@ -369,10 +383,10 @@ var opCodeToString = map[OpCode]string{ SWAP: "SWAP", } -func (o OpCode) String() string { - str := opCodeToString[o] +func (op OpCode) String() string { + str := opCodeToString[op] if len(str) == 0 { - return fmt.Sprintf("Missing opcode 0x%x", int(o)) + return fmt.Sprintf("Missing opcode 0x%x", int(op)) } return str @@ -400,6 +414,9 @@ var stringToOp = map[string]OpCode{ "OR": OR, "XOR": XOR, "BYTE": BYTE, + "SHL": SHL, + "SHR": SHR, + "SAR": SAR, "ADDMOD": ADDMOD, "MULMOD": MULMOD, "SHA3": SHA3, @@ -420,6 +437,7 @@ var stringToOp = map[string]OpCode{ "EXTCODECOPY": EXTCODECOPY, "RETURNDATASIZE": RETURNDATASIZE, "RETURNDATACOPY": RETURNDATACOPY, + "EXTCODEHASH": EXTCODEHASH, "BLOCKHASH": BLOCKHASH, "COINBASE": COINBASE, "TIMESTAMP": TIMESTAMP, @@ -508,6 +526,7 @@ var stringToOp = map[string]OpCode{ "LOG3": LOG3, "LOG4": LOG4, "CREATE": CREATE, + "CREATE2": CREATE2, "CALL": CALL, "RETURN": RETURN, "CALLCODE": CALLCODE, @@ -515,6 +534,7 @@ var stringToOp = map[string]OpCode{ "SELFDESTRUCT": SELFDESTRUCT, } +// StringToOp finds the opcode whose name is stored in `str`. func StringToOp(str string) OpCode { return stringToOp[str] } diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index edbf541766..cda49a34b4 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -41,7 +41,6 @@ type Config struct { GasLimit uint64 GasPrice *big.Int Value *big.Int - DisableJit bool // "disable" so it's enabled by default Debug bool EVMConfig vm.Config @@ -53,7 +52,7 @@ type Config struct { func setDefaults(cfg *Config) { if cfg.ChainConfig == nil { cfg.ChainConfig = ¶ms.ChainConfig{ - ChainId: big.NewInt(1), + ChainID: big.NewInt(1), HomesteadBlock: new(big.Int), DAOForkBlock: new(big.Int), DAOForkSupport: false, @@ -92,8 +91,7 @@ func setDefaults(cfg *Config) { // It returns the EVM's return value, the new state and an error if it failed. // // Executes sets up a in memory, temporarily, environment for the execution of -// the given code. It enabled the JIT by default and make sure that it's restored -// to it's original state afterwards. +// the given code. It makes sure that it's restored to it's original state afterwards. func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { if cfg == nil { cfg = new(Config) @@ -101,11 +99,10 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { setDefaults(cfg) if cfg.State == nil { - db, _ := ethdb.NewMemDatabase() - cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(db)) + cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) } var ( - address = common.StringToAddress("contract") + address = common.BytesToAddress([]byte("contract")) vmenv = NewEnv(cfg) sender = vm.AccountRef(cfg.Origin) ) @@ -115,7 +112,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { // Call the code with the given configuration. ret, _, err := vmenv.Call( sender, - common.StringToAddress("contract"), + common.BytesToAddress([]byte("contract")), input, cfg.GasLimit, cfg.Value, @@ -132,8 +129,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { setDefaults(cfg) if cfg.State == nil { - db, _ := ethdb.NewMemDatabase() - cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(db)) + cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) } var ( vmenv = NewEnv(cfg) diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index 2c4dc50265..bac06e524b 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -26,6 +26,7 @@ import ( "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" ) func TestDefaults(t *testing.T) { @@ -94,8 +95,7 @@ func TestExecute(t *testing.T) { } func TestCall(t *testing.T) { - db, _ := ethdb.NewMemDatabase() - state, _ := state.New(common.Hash{}, state.NewDatabase(db)) + state, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) address := common.HexToAddress("0x0a") state.SetCode(address, []byte{ byte(vm.PUSH1), 10, @@ -149,3 +149,57 @@ func BenchmarkCall(b *testing.B) { } } } +func benchmarkEVM_Create(bench *testing.B, code string) { + var ( + statedb, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) + sender = common.BytesToAddress([]byte("sender")) + receiver = common.BytesToAddress([]byte("receiver")) + ) + + statedb.CreateAccount(sender) + statedb.SetCode(receiver, common.FromHex(code)) + runtimeConfig := Config{ + Origin: sender, + State: statedb, + GasLimit: 10000000, + Difficulty: big.NewInt(0x200000), + Time: new(big.Int).SetUint64(0), + Coinbase: common.Address{}, + BlockNumber: new(big.Int).SetUint64(1), + ChainConfig: ¶ms.ChainConfig{ + ChainID: big.NewInt(1), + HomesteadBlock: new(big.Int), + ByzantiumBlock: new(big.Int), + ConstantinopleBlock: new(big.Int), + DAOForkBlock: new(big.Int), + DAOForkSupport: false, + EIP150Block: new(big.Int), + EIP155Block: new(big.Int), + EIP158Block: new(big.Int), + }, + EVMConfig: vm.Config{}, + } + // Warm up the intpools and stuff + bench.ResetTimer() + for i := 0; i < bench.N; i++ { + Call(receiver, []byte{}, &runtimeConfig) + } + bench.StopTimer() +} + +func BenchmarkEVM_CREATE_500(bench *testing.B) { + // initcode size 500K, repeatedly calls CREATE and then modifies the mem contents + benchmarkEVM_Create(bench, "5b6207a120600080f0600152600056") +} +func BenchmarkEVM_CREATE2_500(bench *testing.B) { + // initcode size 500K, repeatedly calls CREATE2 and then modifies the mem contents + benchmarkEVM_Create(bench, "5b586207a120600080f5600152600056") +} +func BenchmarkEVM_CREATE_1200(bench *testing.B) { + // initcode size 1200K, repeatedly calls CREATE and then modifies the mem contents + benchmarkEVM_Create(bench, "5b62124f80600080f0600152600056") +} +func BenchmarkEVM_CREATE2_1200(bench *testing.B) { + // initcode size 1200K, repeatedly calls CREATE2 and then modifies the mem contents + benchmarkEVM_Create(bench, "5b5862124f80600080f5600152600056") +} diff --git a/core/vm/stack.go b/core/vm/stack.go index 9c10d50ad1..4c1b9e8037 100644 --- a/core/vm/stack.go +++ b/core/vm/stack.go @@ -21,7 +21,7 @@ import ( "math/big" ) -// stack is an object for basic stack operations. Items popped to the stack are +// Stack is an object for basic stack operations. Items popped to the stack are // expected to be changed and modified. stack does not take care of adding newly // initialised objects. type Stack struct { @@ -32,6 +32,7 @@ func newstack() *Stack { return &Stack{data: make([]*big.Int, 0, 1024)} } +// Data returns the underlying big.Int array. func (st *Stack) Data() []*big.Int { return st.data } @@ -80,6 +81,7 @@ func (st *Stack) require(n int) error { return nil } +// Print dumps the content of the stack func (st *Stack) Print() { fmt.Println("### stack ###") if len(st.data) > 0 { diff --git a/core/vm/vm_jit.go b/core/vm/vm_jit.go deleted file mode 100644 index eb3acfb10d..0000000000 --- a/core/vm/vm_jit.go +++ /dev/null @@ -1,389 +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 . - -// +build evmjit - -package vm - -/* - -void* evmjit_create(); -int evmjit_run(void* _jit, void* _data, void* _env); -void evmjit_destroy(void* _jit); - -// Shared library evmjit (e.g. libevmjit.so) is expected to be installed in /usr/local/lib -// More: https://github.com/ethereum/evmjit -#cgo LDFLAGS: -levmjit -*/ -import "C" - -/* -import ( - "bytes" - "errors" - "fmt" - "math/big" - "unsafe" - - "github.com/ethereum/go-ethereum/core/state" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/params" -) - -type JitVm struct { - env EVM - me ContextRef - callerAddr []byte - price *big.Int - data RuntimeData -} - -type i256 [32]byte - -type RuntimeData struct { - gas int64 - gasPrice int64 - callData *byte - callDataSize uint64 - address i256 - caller i256 - origin i256 - callValue i256 - coinBase i256 - difficulty i256 - gasLimit i256 - number uint64 - timestamp int64 - code *byte - codeSize uint64 - codeHash i256 -} - -func hash2llvm(h []byte) i256 { - var m i256 - copy(m[len(m)-len(h):], h) // right aligned copy - return m -} - -func llvm2hash(m *i256) []byte { - return C.GoBytes(unsafe.Pointer(m), C.int(len(m))) -} - -func llvm2hashRef(m *i256) []byte { - return (*[1 << 30]byte)(unsafe.Pointer(m))[:len(m):len(m)] -} - -func address2llvm(addr []byte) i256 { - n := hash2llvm(addr) - bswap(&n) - return n -} - -// bswap swap bytes of the 256-bit integer on LLVM side -// TODO: Do not change memory on LLVM side, that can conflict with memory access optimizations -func bswap(m *i256) *i256 { - for i, l := 0, len(m); i < l/2; i++ { - m[i], m[l-i-1] = m[l-i-1], m[i] - } - return m -} - -func trim(m []byte) []byte { - skip := 0 - for i := 0; i < len(m); i++ { - if m[i] == 0 { - skip++ - } else { - break - } - } - return m[skip:] -} - -func getDataPtr(m []byte) *byte { - var p *byte - if len(m) > 0 { - p = &m[0] - } - return p -} - -func big2llvm(n *big.Int) i256 { - m := hash2llvm(n.Bytes()) - bswap(&m) - return m -} - -func llvm2big(m *i256) *big.Int { - n := big.NewInt(0) - for i := 0; i < len(m); i++ { - b := big.NewInt(int64(m[i])) - b.Lsh(b, uint(i)*8) - n.Add(n, b) - } - return n -} - -// llvm2bytesRef creates a []byte slice that references byte buffer on LLVM side (as of that not controller by GC) -// User must ensure that referenced memory is available to Go until the data is copied or not needed any more -func llvm2bytesRef(data *byte, length uint64) []byte { - if length == 0 { - return nil - } - if data == nil { - panic("Unexpected nil data pointer") - } - return (*[1 << 30]byte)(unsafe.Pointer(data))[:length:length] -} - -func untested(condition bool, message string) { - if condition { - panic("Condition `" + message + "` tested. Remove assert.") - } -} - -func assert(condition bool, message string) { - if !condition { - panic("Assert `" + message + "` failed!") - } -} - -func NewJitVm(env EVM) *JitVm { - return &JitVm{env: env} -} - -func (self *JitVm) Run(me, caller ContextRef, code []byte, value, gas, price *big.Int, callData []byte) (ret []byte, err error) { - // TODO: depth is increased but never checked by VM. VM should not know about it at all. - self.env.SetDepth(self.env.Depth() + 1) - - // TODO: Move it to Env.Call() or sth - if Precompiled[string(me.Address())] != nil { - // if it's address of precompiled contract - // fallback to standard VM - stdVm := New(self.env) - return stdVm.Run(me, caller, code, value, gas, price, callData) - } - - if self.me != nil { - panic("JitVm.Run() can be called only once per JitVm instance") - } - - self.me = me - self.callerAddr = caller.Address() - self.price = price - - self.data.gas = gas.Int64() - self.data.gasPrice = price.Int64() - self.data.callData = getDataPtr(callData) - self.data.callDataSize = uint64(len(callData)) - self.data.address = address2llvm(self.me.Address()) - self.data.caller = address2llvm(caller.Address()) - self.data.origin = address2llvm(self.env.Origin()) - self.data.callValue = big2llvm(value) - self.data.coinBase = address2llvm(self.env.Coinbase()) - self.data.difficulty = big2llvm(self.env.Difficulty()) - self.data.gasLimit = big2llvm(self.env.GasLimit()) - self.data.number = self.env.BlockNumber().Uint64() - self.data.timestamp = self.env.Time() - self.data.code = getDataPtr(code) - self.data.codeSize = uint64(len(code)) - self.data.codeHash = hash2llvm(crypto.Keccak256(code)) // TODO: Get already computed hash? - - jit := C.evmjit_create() - retCode := C.evmjit_run(jit, unsafe.Pointer(&self.data), unsafe.Pointer(self)) - - if retCode < 0 { - err = errors.New("OOG from JIT") - gas.SetInt64(0) // Set gas to 0, JIT does not bother - } else { - gas.SetInt64(self.data.gas) - if retCode == 1 { // RETURN - ret = C.GoBytes(unsafe.Pointer(self.data.callData), C.int(self.data.callDataSize)) - } else if retCode == 2 { // SUICIDE - // TODO: Suicide support logic should be moved to Env to be shared by VM implementations - state := self.Env().State() - receiverAddr := llvm2hashRef(bswap(&self.data.address)) - receiver := state.GetOrNewStateObject(receiverAddr) - balance := state.GetBalance(me.Address()) - receiver.AddBalance(balance) - state.Delete(me.Address()) - } - } - - C.evmjit_destroy(jit) - return -} - -func (self *JitVm) Printf(format string, v ...interface{}) VirtualMachine { - return self -} - -func (self *JitVm) Endl() VirtualMachine { - return self -} - -func (self *JitVm) Env() EVM { - return self.env -} - -//export env_sha3 -func env_sha3(dataPtr *byte, length uint64, resultPtr unsafe.Pointer) { - data := llvm2bytesRef(dataPtr, length) - hash := crypto.Keccak256(data) - result := (*i256)(resultPtr) - *result = hash2llvm(hash) -} - -//export env_sstore -func env_sstore(vmPtr unsafe.Pointer, indexPtr unsafe.Pointer, valuePtr unsafe.Pointer) { - vm := (*JitVm)(vmPtr) - index := llvm2hash(bswap((*i256)(indexPtr))) - value := llvm2hash(bswap((*i256)(valuePtr))) - value = trim(value) - if len(value) == 0 { - prevValue := vm.env.State().GetState(vm.me.Address(), index) - if len(prevValue) != 0 { - vm.Env().State().Refund(vm.callerAddr, GasSStoreRefund) - } - } - - vm.env.State().SetState(vm.me.Address(), index, value) -} - -//export env_sload -func env_sload(vmPtr unsafe.Pointer, indexPtr unsafe.Pointer, resultPtr unsafe.Pointer) { - vm := (*JitVm)(vmPtr) - index := llvm2hash(bswap((*i256)(indexPtr))) - value := vm.env.State().GetState(vm.me.Address(), index) - result := (*i256)(resultPtr) - *result = hash2llvm(value) - bswap(result) -} - -//export env_balance -func env_balance(_vm unsafe.Pointer, _addr unsafe.Pointer, _result unsafe.Pointer) { - vm := (*JitVm)(_vm) - addr := llvm2hash((*i256)(_addr)) - balance := vm.Env().State().GetBalance(addr) - result := (*i256)(_result) - *result = big2llvm(balance) -} - -//export env_blockhash -func env_blockhash(_vm unsafe.Pointer, _number unsafe.Pointer, _result unsafe.Pointer) { - vm := (*JitVm)(_vm) - number := llvm2big((*i256)(_number)) - result := (*i256)(_result) - - currNumber := vm.Env().BlockNumber() - limit := big.NewInt(0).Sub(currNumber, big.NewInt(256)) - if number.Cmp(limit) >= 0 && number.Cmp(currNumber) < 0 { - hash := vm.Env().GetHash(uint64(number.Int64())) - *result = hash2llvm(hash) - } else { - *result = i256{} - } -} - -//export env_call -func env_call(_vm unsafe.Pointer, _gas *int64, _receiveAddr unsafe.Pointer, _value unsafe.Pointer, inDataPtr unsafe.Pointer, inDataLen uint64, outDataPtr *byte, outDataLen uint64, _codeAddr unsafe.Pointer) bool { - vm := (*JitVm)(_vm) - - //fmt.Printf("env_call (depth %d)\n", vm.Env().Depth()) - - defer func() { - if r := recover(); r != nil { - fmt.Printf("Recovered in env_call (depth %d, out %p %d): %s\n", vm.Env().Depth(), outDataPtr, outDataLen, r) - } - }() - - balance := vm.Env().State().GetBalance(vm.me.Address()) - value := llvm2big((*i256)(_value)) - - if balance.Cmp(value) >= 0 { - receiveAddr := llvm2hash((*i256)(_receiveAddr)) - inData := C.GoBytes(inDataPtr, C.int(inDataLen)) - outData := llvm2bytesRef(outDataPtr, outDataLen) - codeAddr := llvm2hash((*i256)(_codeAddr)) - gas := big.NewInt(*_gas) - var out []byte - var err error - if bytes.Equal(codeAddr, receiveAddr) { - out, err = vm.env.Call(vm.me, codeAddr, inData, gas, vm.price, value) - } else { - out, err = vm.env.CallCode(vm.me, codeAddr, inData, gas, vm.price, value) - } - *_gas = gas.Int64() - if err == nil { - copy(outData, out) - return true - } - } - - return false -} - -//export env_create -func env_create(_vm unsafe.Pointer, _gas *int64, _value unsafe.Pointer, initDataPtr unsafe.Pointer, initDataLen uint64, _result unsafe.Pointer) { - vm := (*JitVm)(_vm) - - value := llvm2big((*i256)(_value)) - initData := C.GoBytes(initDataPtr, C.int(initDataLen)) // TODO: Unnecessary if low balance - result := (*i256)(_result) - *result = i256{} - - gas := big.NewInt(*_gas) - ret, suberr, ref := vm.env.Create(vm.me, nil, initData, gas, vm.price, value) - if suberr == nil { - dataGas := big.NewInt(int64(len(ret))) // TODO: Not the best design. env.Create can do it, it has the reference to gas counter - dataGas.Mul(dataGas, params.CreateDataGas) - gas.Sub(gas, dataGas) - *result = hash2llvm(ref.Address()) - } - *_gas = gas.Int64() -} - -//export env_log -func env_log(_vm unsafe.Pointer, dataPtr unsafe.Pointer, dataLen uint64, _topic1 unsafe.Pointer, _topic2 unsafe.Pointer, _topic3 unsafe.Pointer, _topic4 unsafe.Pointer) { - vm := (*JitVm)(_vm) - - data := C.GoBytes(dataPtr, C.int(dataLen)) - - topics := make([][]byte, 0, 4) - if _topic1 != nil { - topics = append(topics, llvm2hash((*i256)(_topic1))) - } - if _topic2 != nil { - topics = append(topics, llvm2hash((*i256)(_topic2))) - } - if _topic3 != nil { - topics = append(topics, llvm2hash((*i256)(_topic3))) - } - if _topic4 != nil { - topics = append(topics, llvm2hash((*i256)(_topic4))) - } - - vm.Env().AddLog(state.NewLog(vm.me.Address(), topics, data, vm.env.BlockNumber().Uint64())) -} - -//export env_extcode -func env_extcode(_vm unsafe.Pointer, _addr unsafe.Pointer, o_size *uint64) *byte { - vm := (*JitVm)(_vm) - addr := llvm2hash((*i256)(_addr)) - code := vm.Env().State().GetCode(addr) - *o_size = uint64(len(code)) - return getDataPtr(code) -}*/ diff --git a/crypto/bn256/LICENSE b/crypto/bn256/LICENSE new file mode 100644 index 0000000000..634e0cb2c3 --- /dev/null +++ b/crypto/bn256/LICENSE @@ -0,0 +1,28 @@ +Copyright (c) 2012 The Go Authors. All rights reserved. +Copyright (c) 2018 Péter Szilágyi. All rights reserved. + +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. diff --git a/crypto/bn256/bn256_fast.go b/crypto/bn256/bn256_fast.go new file mode 100644 index 0000000000..5c081493b0 --- /dev/null +++ b/crypto/bn256/bn256_fast.go @@ -0,0 +1,23 @@ +// Copyright 2018 Péter Szilágyi. 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 arm64 + +// Package bn256 implements the Optimal Ate pairing over a 256-bit Barreto-Naehrig curve. +package bn256 + +import "github.com/ethereum/go-ethereum/crypto/bn256/cloudflare" + +// G1 is an abstract cyclic group. The zero value is suitable for use as the +// output of an operation, but cannot be used as an input. +type G1 = bn256.G1 + +// G2 is an abstract cyclic group. The zero value is suitable for use as the +// output of an operation, but cannot be used as an input. +type G2 = bn256.G2 + +// PairingCheck calculates the Optimal Ate pairing for a set of points. +func PairingCheck(a []*G1, b []*G2) bool { + return bn256.PairingCheck(a, b) +} diff --git a/crypto/bn256/bn256_fuzz.go b/crypto/bn256/bn256_fuzz.go new file mode 100644 index 0000000000..6aa1421170 --- /dev/null +++ b/crypto/bn256/bn256_fuzz.go @@ -0,0 +1,126 @@ +// Copyright 2018 Péter Szilágyi. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be found +// in the LICENSE file. + +// +build gofuzz + +package bn256 + +import ( + "bytes" + "math/big" + + cloudflare "github.com/ethereum/go-ethereum/crypto/bn256/cloudflare" + google "github.com/ethereum/go-ethereum/crypto/bn256/google" +) + +// FuzzAdd fuzzez bn256 addition between the Google and Cloudflare libraries. +func FuzzAdd(data []byte) int { + // Ensure we have enough data in the first place + if len(data) != 128 { + return 0 + } + // Ensure both libs can parse the first curve point + xc := new(cloudflare.G1) + _, errc := xc.Unmarshal(data[:64]) + + xg := new(google.G1) + _, errg := xg.Unmarshal(data[:64]) + + if (errc == nil) != (errg == nil) { + panic("parse mismatch") + } else if errc != nil { + return 0 + } + // Ensure both libs can parse the second curve point + yc := new(cloudflare.G1) + _, errc = yc.Unmarshal(data[64:]) + + yg := new(google.G1) + _, errg = yg.Unmarshal(data[64:]) + + if (errc == nil) != (errg == nil) { + panic("parse mismatch") + } else if errc != nil { + return 0 + } + // Add the two points and ensure they result in the same output + rc := new(cloudflare.G1) + rc.Add(xc, yc) + + rg := new(google.G1) + rg.Add(xg, yg) + + if !bytes.Equal(rc.Marshal(), rg.Marshal()) { + panic("add mismatch") + } + return 0 +} + +// FuzzMul fuzzez bn256 scalar multiplication between the Google and Cloudflare +// libraries. +func FuzzMul(data []byte) int { + // Ensure we have enough data in the first place + if len(data) != 96 { + return 0 + } + // Ensure both libs can parse the curve point + pc := new(cloudflare.G1) + _, errc := pc.Unmarshal(data[:64]) + + pg := new(google.G1) + _, errg := pg.Unmarshal(data[:64]) + + if (errc == nil) != (errg == nil) { + panic("parse mismatch") + } else if errc != nil { + return 0 + } + // Add the two points and ensure they result in the same output + rc := new(cloudflare.G1) + rc.ScalarMult(pc, new(big.Int).SetBytes(data[64:])) + + rg := new(google.G1) + rg.ScalarMult(pg, new(big.Int).SetBytes(data[64:])) + + if !bytes.Equal(rc.Marshal(), rg.Marshal()) { + panic("scalar mul mismatch") + } + return 0 +} + +func FuzzPair(data []byte) int { + // Ensure we have enough data in the first place + if len(data) != 192 { + return 0 + } + // Ensure both libs can parse the curve point + pc := new(cloudflare.G1) + _, errc := pc.Unmarshal(data[:64]) + + pg := new(google.G1) + _, errg := pg.Unmarshal(data[:64]) + + if (errc == nil) != (errg == nil) { + panic("parse mismatch") + } else if errc != nil { + return 0 + } + // Ensure both libs can parse the twist point + tc := new(cloudflare.G2) + _, errc = tc.Unmarshal(data[64:]) + + tg := new(google.G2) + _, errg = tg.Unmarshal(data[64:]) + + if (errc == nil) != (errg == nil) { + panic("parse mismatch") + } else if errc != nil { + return 0 + } + // Pair the two points and ensure thet result in the same output + if cloudflare.PairingCheck([]*cloudflare.G1{pc}, []*cloudflare.G2{tc}) != google.PairingCheck([]*google.G1{pg}, []*google.G2{tg}) { + panic("pair mismatch") + } + return 0 +} diff --git a/crypto/bn256/bn256_slow.go b/crypto/bn256/bn256_slow.go new file mode 100644 index 0000000000..47df49d417 --- /dev/null +++ b/crypto/bn256/bn256_slow.go @@ -0,0 +1,23 @@ +// Copyright 2018 Péter Szilágyi. 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,!arm64 + +// Package bn256 implements the Optimal Ate pairing over a 256-bit Barreto-Naehrig curve. +package bn256 + +import "github.com/ethereum/go-ethereum/crypto/bn256/google" + +// G1 is an abstract cyclic group. The zero value is suitable for use as the +// output of an operation, but cannot be used as an input. +type G1 = bn256.G1 + +// G2 is an abstract cyclic group. The zero value is suitable for use as the +// output of an operation, but cannot be used as an input. +type G2 = bn256.G2 + +// PairingCheck calculates the Optimal Ate pairing for a set of points. +func PairingCheck(a []*G1, b []*G2) bool { + return bn256.PairingCheck(a, b) +} diff --git a/crypto/sha3/LICENSE b/crypto/bn256/cloudflare/LICENSE similarity index 100% rename from crypto/sha3/LICENSE rename to crypto/bn256/cloudflare/LICENSE diff --git a/crypto/bn256/cloudflare/bn256.go b/crypto/bn256/cloudflare/bn256.go new file mode 100644 index 0000000000..c6ea2d07e0 --- /dev/null +++ b/crypto/bn256/cloudflare/bn256.go @@ -0,0 +1,481 @@ +// Package bn256 implements a particular bilinear group at the 128-bit security +// level. +// +// Bilinear groups are the basis of many of the new cryptographic protocols that +// have been proposed over the past decade. They consist of a triplet of groups +// (G₁, G₂ and GT) such that there exists a function e(g₁ˣ,g₂ʸ)=gTˣʸ (where gₓ +// is a generator of the respective group). That function is called a pairing +// function. +// +// This package specifically implements the Optimal Ate pairing over a 256-bit +// Barreto-Naehrig curve as described in +// http://cryptojedi.org/papers/dclxvi-20100714.pdf. Its output is compatible +// with the implementation described in that paper. +package bn256 + +import ( + "crypto/rand" + "errors" + "io" + "math/big" +) + +func randomK(r io.Reader) (k *big.Int, err error) { + for { + k, err = rand.Int(r, Order) + if k.Sign() > 0 || err != nil { + return + } + } +} + +// G1 is an abstract cyclic group. The zero value is suitable for use as the +// output of an operation, but cannot be used as an input. +type G1 struct { + p *curvePoint +} + +// RandomG1 returns x and g₁ˣ where x is a random, non-zero number read from r. +func RandomG1(r io.Reader) (*big.Int, *G1, error) { + k, err := randomK(r) + if err != nil { + return nil, nil, err + } + + return k, new(G1).ScalarBaseMult(k), nil +} + +func (g *G1) String() string { + return "bn256.G1" + g.p.String() +} + +// ScalarBaseMult sets e to g*k where g is the generator of the group and then +// returns e. +func (e *G1) ScalarBaseMult(k *big.Int) *G1 { + if e.p == nil { + e.p = &curvePoint{} + } + e.p.Mul(curveGen, k) + return e +} + +// ScalarMult sets e to a*k and then returns e. +func (e *G1) ScalarMult(a *G1, k *big.Int) *G1 { + if e.p == nil { + e.p = &curvePoint{} + } + e.p.Mul(a.p, k) + return e +} + +// Add sets e to a+b and then returns e. +func (e *G1) Add(a, b *G1) *G1 { + if e.p == nil { + e.p = &curvePoint{} + } + e.p.Add(a.p, b.p) + return e +} + +// Neg sets e to -a and then returns e. +func (e *G1) Neg(a *G1) *G1 { + if e.p == nil { + e.p = &curvePoint{} + } + e.p.Neg(a.p) + return e +} + +// Set sets e to a and then returns e. +func (e *G1) Set(a *G1) *G1 { + if e.p == nil { + e.p = &curvePoint{} + } + e.p.Set(a.p) + return e +} + +// Marshal converts e to a byte slice. +func (e *G1) Marshal() []byte { + // Each value is a 256-bit number. + const numBytes = 256 / 8 + + e.p.MakeAffine() + ret := make([]byte, numBytes*2) + if e.p.IsInfinity() { + return ret + } + temp := &gfP{} + + montDecode(temp, &e.p.x) + temp.Marshal(ret) + montDecode(temp, &e.p.y) + temp.Marshal(ret[numBytes:]) + + return ret +} + +// Unmarshal sets e to the result of converting the output of Marshal back into +// a group element and then returns e. +func (e *G1) Unmarshal(m []byte) ([]byte, error) { + // Each value is a 256-bit number. + const numBytes = 256 / 8 + if len(m) < 2*numBytes { + return nil, errors.New("bn256: not enough data") + } + // Unmarshal the points and check their caps + if e.p == nil { + e.p = &curvePoint{} + } else { + e.p.x, e.p.y = gfP{0}, gfP{0} + } + var err error + if err = e.p.x.Unmarshal(m); err != nil { + return nil, err + } + if err = e.p.y.Unmarshal(m[numBytes:]); err != nil { + return nil, err + } + // Encode into Montgomery form and ensure it's on the curve + montEncode(&e.p.x, &e.p.x) + montEncode(&e.p.y, &e.p.y) + + zero := gfP{0} + if e.p.x == zero && e.p.y == zero { + // This is the point at infinity. + e.p.y = *newGFp(1) + e.p.z = gfP{0} + e.p.t = gfP{0} + } else { + e.p.z = *newGFp(1) + e.p.t = *newGFp(1) + + if !e.p.IsOnCurve() { + return nil, errors.New("bn256: malformed point") + } + } + return m[2*numBytes:], nil +} + +// G2 is an abstract cyclic group. The zero value is suitable for use as the +// output of an operation, but cannot be used as an input. +type G2 struct { + p *twistPoint +} + +// RandomG2 returns x and g₂ˣ where x is a random, non-zero number read from r. +func RandomG2(r io.Reader) (*big.Int, *G2, error) { + k, err := randomK(r) + if err != nil { + return nil, nil, err + } + + return k, new(G2).ScalarBaseMult(k), nil +} + +func (e *G2) String() string { + return "bn256.G2" + e.p.String() +} + +// ScalarBaseMult sets e to g*k where g is the generator of the group and then +// returns out. +func (e *G2) ScalarBaseMult(k *big.Int) *G2 { + if e.p == nil { + e.p = &twistPoint{} + } + e.p.Mul(twistGen, k) + return e +} + +// ScalarMult sets e to a*k and then returns e. +func (e *G2) ScalarMult(a *G2, k *big.Int) *G2 { + if e.p == nil { + e.p = &twistPoint{} + } + e.p.Mul(a.p, k) + return e +} + +// Add sets e to a+b and then returns e. +func (e *G2) Add(a, b *G2) *G2 { + if e.p == nil { + e.p = &twistPoint{} + } + e.p.Add(a.p, b.p) + return e +} + +// Neg sets e to -a and then returns e. +func (e *G2) Neg(a *G2) *G2 { + if e.p == nil { + e.p = &twistPoint{} + } + e.p.Neg(a.p) + return e +} + +// Set sets e to a and then returns e. +func (e *G2) Set(a *G2) *G2 { + if e.p == nil { + e.p = &twistPoint{} + } + e.p.Set(a.p) + return e +} + +// Marshal converts e into a byte slice. +func (e *G2) Marshal() []byte { + // Each value is a 256-bit number. + const numBytes = 256 / 8 + + if e.p == nil { + e.p = &twistPoint{} + } + + e.p.MakeAffine() + ret := make([]byte, numBytes*4) + if e.p.IsInfinity() { + return ret + } + temp := &gfP{} + + montDecode(temp, &e.p.x.x) + temp.Marshal(ret) + montDecode(temp, &e.p.x.y) + temp.Marshal(ret[numBytes:]) + montDecode(temp, &e.p.y.x) + temp.Marshal(ret[2*numBytes:]) + montDecode(temp, &e.p.y.y) + temp.Marshal(ret[3*numBytes:]) + + return ret +} + +// Unmarshal sets e to the result of converting the output of Marshal back into +// a group element and then returns e. +func (e *G2) Unmarshal(m []byte) ([]byte, error) { + // Each value is a 256-bit number. + const numBytes = 256 / 8 + if len(m) < 4*numBytes { + return nil, errors.New("bn256: not enough data") + } + // Unmarshal the points and check their caps + if e.p == nil { + e.p = &twistPoint{} + } + var err error + if err = e.p.x.x.Unmarshal(m); err != nil { + return nil, err + } + if err = e.p.x.y.Unmarshal(m[numBytes:]); err != nil { + return nil, err + } + if err = e.p.y.x.Unmarshal(m[2*numBytes:]); err != nil { + return nil, err + } + if err = e.p.y.y.Unmarshal(m[3*numBytes:]); err != nil { + return nil, err + } + // Encode into Montgomery form and ensure it's on the curve + montEncode(&e.p.x.x, &e.p.x.x) + montEncode(&e.p.x.y, &e.p.x.y) + montEncode(&e.p.y.x, &e.p.y.x) + montEncode(&e.p.y.y, &e.p.y.y) + + if e.p.x.IsZero() && e.p.y.IsZero() { + // This is the point at infinity. + e.p.y.SetOne() + e.p.z.SetZero() + e.p.t.SetZero() + } else { + e.p.z.SetOne() + e.p.t.SetOne() + + if !e.p.IsOnCurve() { + return nil, errors.New("bn256: malformed point") + } + } + return m[4*numBytes:], nil +} + +// GT is an abstract cyclic group. The zero value is suitable for use as the +// output of an operation, but cannot be used as an input. +type GT struct { + p *gfP12 +} + +// Pair calculates an Optimal Ate pairing. +func Pair(g1 *G1, g2 *G2) *GT { + return >{optimalAte(g2.p, g1.p)} +} + +// PairingCheck calculates the Optimal Ate pairing for a set of points. +func PairingCheck(a []*G1, b []*G2) bool { + acc := new(gfP12) + acc.SetOne() + + for i := 0; i < len(a); i++ { + if a[i].p.IsInfinity() || b[i].p.IsInfinity() { + continue + } + acc.Mul(acc, miller(b[i].p, a[i].p)) + } + return finalExponentiation(acc).IsOne() +} + +// Miller applies Miller's algorithm, which is a bilinear function from the +// source groups to F_p^12. Miller(g1, g2).Finalize() is equivalent to Pair(g1, +// g2). +func Miller(g1 *G1, g2 *G2) *GT { + return >{miller(g2.p, g1.p)} +} + +func (g *GT) String() string { + return "bn256.GT" + g.p.String() +} + +// ScalarMult sets e to a*k and then returns e. +func (e *GT) ScalarMult(a *GT, k *big.Int) *GT { + if e.p == nil { + e.p = &gfP12{} + } + e.p.Exp(a.p, k) + return e +} + +// Add sets e to a+b and then returns e. +func (e *GT) Add(a, b *GT) *GT { + if e.p == nil { + e.p = &gfP12{} + } + e.p.Mul(a.p, b.p) + return e +} + +// Neg sets e to -a and then returns e. +func (e *GT) Neg(a *GT) *GT { + if e.p == nil { + e.p = &gfP12{} + } + e.p.Conjugate(a.p) + return e +} + +// Set sets e to a and then returns e. +func (e *GT) Set(a *GT) *GT { + if e.p == nil { + e.p = &gfP12{} + } + e.p.Set(a.p) + return e +} + +// Finalize is a linear function from F_p^12 to GT. +func (e *GT) Finalize() *GT { + ret := finalExponentiation(e.p) + e.p.Set(ret) + return e +} + +// Marshal converts e into a byte slice. +func (e *GT) Marshal() []byte { + // Each value is a 256-bit number. + const numBytes = 256 / 8 + + ret := make([]byte, numBytes*12) + temp := &gfP{} + + montDecode(temp, &e.p.x.x.x) + temp.Marshal(ret) + montDecode(temp, &e.p.x.x.y) + temp.Marshal(ret[numBytes:]) + montDecode(temp, &e.p.x.y.x) + temp.Marshal(ret[2*numBytes:]) + montDecode(temp, &e.p.x.y.y) + temp.Marshal(ret[3*numBytes:]) + montDecode(temp, &e.p.x.z.x) + temp.Marshal(ret[4*numBytes:]) + montDecode(temp, &e.p.x.z.y) + temp.Marshal(ret[5*numBytes:]) + montDecode(temp, &e.p.y.x.x) + temp.Marshal(ret[6*numBytes:]) + montDecode(temp, &e.p.y.x.y) + temp.Marshal(ret[7*numBytes:]) + montDecode(temp, &e.p.y.y.x) + temp.Marshal(ret[8*numBytes:]) + montDecode(temp, &e.p.y.y.y) + temp.Marshal(ret[9*numBytes:]) + montDecode(temp, &e.p.y.z.x) + temp.Marshal(ret[10*numBytes:]) + montDecode(temp, &e.p.y.z.y) + temp.Marshal(ret[11*numBytes:]) + + return ret +} + +// Unmarshal sets e to the result of converting the output of Marshal back into +// a group element and then returns e. +func (e *GT) Unmarshal(m []byte) ([]byte, error) { + // Each value is a 256-bit number. + const numBytes = 256 / 8 + + if len(m) < 12*numBytes { + return nil, errors.New("bn256: not enough data") + } + + if e.p == nil { + e.p = &gfP12{} + } + + var err error + if err = e.p.x.x.x.Unmarshal(m); err != nil { + return nil, err + } + if err = e.p.x.x.y.Unmarshal(m[numBytes:]); err != nil { + return nil, err + } + if err = e.p.x.y.x.Unmarshal(m[2*numBytes:]); err != nil { + return nil, err + } + if err = e.p.x.y.y.Unmarshal(m[3*numBytes:]); err != nil { + return nil, err + } + if err = e.p.x.z.x.Unmarshal(m[4*numBytes:]); err != nil { + return nil, err + } + if err = e.p.x.z.y.Unmarshal(m[5*numBytes:]); err != nil { + return nil, err + } + if err = e.p.y.x.x.Unmarshal(m[6*numBytes:]); err != nil { + return nil, err + } + if err = e.p.y.x.y.Unmarshal(m[7*numBytes:]); err != nil { + return nil, err + } + if err = e.p.y.y.x.Unmarshal(m[8*numBytes:]); err != nil { + return nil, err + } + if err = e.p.y.y.y.Unmarshal(m[9*numBytes:]); err != nil { + return nil, err + } + if err = e.p.y.z.x.Unmarshal(m[10*numBytes:]); err != nil { + return nil, err + } + if err = e.p.y.z.y.Unmarshal(m[11*numBytes:]); err != nil { + return nil, err + } + montEncode(&e.p.x.x.x, &e.p.x.x.x) + montEncode(&e.p.x.x.y, &e.p.x.x.y) + montEncode(&e.p.x.y.x, &e.p.x.y.x) + montEncode(&e.p.x.y.y, &e.p.x.y.y) + montEncode(&e.p.x.z.x, &e.p.x.z.x) + montEncode(&e.p.x.z.y, &e.p.x.z.y) + montEncode(&e.p.y.x.x, &e.p.y.x.x) + montEncode(&e.p.y.x.y, &e.p.y.x.y) + montEncode(&e.p.y.y.x, &e.p.y.y.x) + montEncode(&e.p.y.y.y, &e.p.y.y.y) + montEncode(&e.p.y.z.x, &e.p.y.z.x) + montEncode(&e.p.y.z.y, &e.p.y.z.y) + + return m[12*numBytes:], nil +} diff --git a/crypto/bn256/cloudflare/bn256_test.go b/crypto/bn256/cloudflare/bn256_test.go new file mode 100644 index 0000000000..0c8016d86c --- /dev/null +++ b/crypto/bn256/cloudflare/bn256_test.go @@ -0,0 +1,116 @@ +package bn256 + +import ( + "bytes" + "crypto/rand" + "testing" +) + +func TestG1Marshal(t *testing.T) { + _, Ga, err := RandomG1(rand.Reader) + if err != nil { + t.Fatal(err) + } + ma := Ga.Marshal() + + Gb := new(G1) + _, err = Gb.Unmarshal(ma) + if err != nil { + t.Fatal(err) + } + mb := Gb.Marshal() + + if !bytes.Equal(ma, mb) { + t.Fatal("bytes are different") + } +} + +func TestG2Marshal(t *testing.T) { + _, Ga, err := RandomG2(rand.Reader) + if err != nil { + t.Fatal(err) + } + ma := Ga.Marshal() + + Gb := new(G2) + _, err = Gb.Unmarshal(ma) + if err != nil { + t.Fatal(err) + } + mb := Gb.Marshal() + + if !bytes.Equal(ma, mb) { + t.Fatal("bytes are different") + } +} + +func TestBilinearity(t *testing.T) { + for i := 0; i < 2; i++ { + a, p1, _ := RandomG1(rand.Reader) + b, p2, _ := RandomG2(rand.Reader) + e1 := Pair(p1, p2) + + e2 := Pair(&G1{curveGen}, &G2{twistGen}) + e2.ScalarMult(e2, a) + e2.ScalarMult(e2, b) + + if *e1.p != *e2.p { + t.Fatalf("bad pairing result: %s", e1) + } + } +} + +func TestTripartiteDiffieHellman(t *testing.T) { + a, _ := rand.Int(rand.Reader, Order) + b, _ := rand.Int(rand.Reader, Order) + c, _ := rand.Int(rand.Reader, Order) + + pa, pb, pc := new(G1), new(G1), new(G1) + qa, qb, qc := new(G2), new(G2), new(G2) + + pa.Unmarshal(new(G1).ScalarBaseMult(a).Marshal()) + qa.Unmarshal(new(G2).ScalarBaseMult(a).Marshal()) + pb.Unmarshal(new(G1).ScalarBaseMult(b).Marshal()) + qb.Unmarshal(new(G2).ScalarBaseMult(b).Marshal()) + pc.Unmarshal(new(G1).ScalarBaseMult(c).Marshal()) + qc.Unmarshal(new(G2).ScalarBaseMult(c).Marshal()) + + k1 := Pair(pb, qc) + k1.ScalarMult(k1, a) + k1Bytes := k1.Marshal() + + k2 := Pair(pc, qa) + k2.ScalarMult(k2, b) + k2Bytes := k2.Marshal() + + k3 := Pair(pa, qb) + k3.ScalarMult(k3, c) + k3Bytes := k3.Marshal() + + if !bytes.Equal(k1Bytes, k2Bytes) || !bytes.Equal(k2Bytes, k3Bytes) { + t.Errorf("keys didn't agree") + } +} + +func BenchmarkG1(b *testing.B) { + x, _ := rand.Int(rand.Reader, Order) + b.ResetTimer() + + for i := 0; i < b.N; i++ { + new(G1).ScalarBaseMult(x) + } +} + +func BenchmarkG2(b *testing.B) { + x, _ := rand.Int(rand.Reader, Order) + b.ResetTimer() + + for i := 0; i < b.N; i++ { + new(G2).ScalarBaseMult(x) + } +} +func BenchmarkPairing(b *testing.B) { + for i := 0; i < b.N; i++ { + Pair(&G1{curveGen}, &G2{twistGen}) + } +} diff --git a/crypto/bn256/cloudflare/constants.go b/crypto/bn256/cloudflare/constants.go new file mode 100644 index 0000000000..5122aae64f --- /dev/null +++ b/crypto/bn256/cloudflare/constants.go @@ -0,0 +1,59 @@ +// Copyright 2012 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 bn256 + +import ( + "math/big" +) + +func bigFromBase10(s string) *big.Int { + n, _ := new(big.Int).SetString(s, 10) + return n +} + +// u is the BN parameter that determines the prime: 1868033³. +var u = bigFromBase10("4965661367192848881") + +// Order is the number of elements in both G₁ and G₂: 36u⁴+36u³+18u²+6u+1. +var Order = bigFromBase10("21888242871839275222246405745257275088548364400416034343698204186575808495617") + +// P is a prime over which we form a basic field: 36u⁴+36u³+24u²+6u+1. +var P = bigFromBase10("21888242871839275222246405745257275088696311157297823662689037894645226208583") + +// p2 is p, represented as little-endian 64-bit words. +var p2 = [4]uint64{0x3c208c16d87cfd47, 0x97816a916871ca8d, 0xb85045b68181585d, 0x30644e72e131a029} + +// np is the negative inverse of p, mod 2^256. +var np = [4]uint64{0x87d20782e4866389, 0x9ede7d651eca6ac9, 0xd8afcbd01833da80, 0xf57a22b791888c6b} + +// rN1 is R^-1 where R = 2^256 mod p. +var rN1 = &gfP{0xed84884a014afa37, 0xeb2022850278edf8, 0xcf63e9cfb74492d9, 0x2e67157159e5c639} + +// r2 is R^2 where R = 2^256 mod p. +var r2 = &gfP{0xf32cfc5b538afa89, 0xb5e71911d44501fb, 0x47ab1eff0a417ff6, 0x06d89f71cab8351f} + +// r3 is R^3 where R = 2^256 mod p. +var r3 = &gfP{0xb1cd6dafda1530df, 0x62f210e6a7283db6, 0xef7f0b0c0ada0afb, 0x20fd6e902d592544} + +// xiToPMinus1Over6 is ξ^((p-1)/6) where ξ = i+9. +var xiToPMinus1Over6 = &gfP2{gfP{0xa222ae234c492d72, 0xd00f02a4565de15b, 0xdc2ff3a253dfc926, 0x10a75716b3899551}, gfP{0xaf9ba69633144907, 0xca6b1d7387afb78a, 0x11bded5ef08a2087, 0x02f34d751a1f3a7c}} + +// xiToPMinus1Over3 is ξ^((p-1)/3) where ξ = i+9. +var xiToPMinus1Over3 = &gfP2{gfP{0x6e849f1ea0aa4757, 0xaa1c7b6d89f89141, 0xb6e713cdfae0ca3a, 0x26694fbb4e82ebc3}, gfP{0xb5773b104563ab30, 0x347f91c8a9aa6454, 0x7a007127242e0991, 0x1956bcd8118214ec}} + +// xiToPMinus1Over2 is ξ^((p-1)/2) where ξ = i+9. +var xiToPMinus1Over2 = &gfP2{gfP{0xa1d77ce45ffe77c7, 0x07affd117826d1db, 0x6d16bd27bb7edc6b, 0x2c87200285defecc}, gfP{0xe4bbdd0c2936b629, 0xbb30f162e133bacb, 0x31a9d1b6f9645366, 0x253570bea500f8dd}} + +// xiToPSquaredMinus1Over3 is ξ^((p²-1)/3) where ξ = i+9. +var xiToPSquaredMinus1Over3 = &gfP{0x3350c88e13e80b9c, 0x7dce557cdb5e56b9, 0x6001b4b8b615564a, 0x2682e617020217e0} + +// xiTo2PSquaredMinus2Over3 is ξ^((2p²-2)/3) where ξ = i+9 (a cubic root of unity, mod p). +var xiTo2PSquaredMinus2Over3 = &gfP{0x71930c11d782e155, 0xa6bb947cffbe3323, 0xaa303344d4741444, 0x2c3b3f0d26594943} + +// xiToPSquaredMinus1Over6 is ξ^((1p²-1)/6) where ξ = i+9 (a cubic root of -1, mod p). +var xiToPSquaredMinus1Over6 = &gfP{0xca8d800500fa1bf2, 0xf0c5d61468b39769, 0x0e201271ad0d4418, 0x04290f65bad856e6} + +// xiTo2PMinus2Over3 is ξ^((2p-2)/3) where ξ = i+9. +var xiTo2PMinus2Over3 = &gfP2{gfP{0x5dddfd154bd8c949, 0x62cb29a5a4445b60, 0x37bc870a0c7dd2b9, 0x24830a9d3171f0fd}, gfP{0x7361d77f843abe92, 0xa5bb2bd3273411fb, 0x9c941f314b3e2399, 0x15df9cddbb9fd3ec}} diff --git a/crypto/bn256/cloudflare/curve.go b/crypto/bn256/cloudflare/curve.go new file mode 100644 index 0000000000..18e9b38f3f --- /dev/null +++ b/crypto/bn256/cloudflare/curve.go @@ -0,0 +1,238 @@ +package bn256 + +import ( + "math/big" +) + +// curvePoint implements the elliptic curve y²=x³+3. Points are kept in Jacobian +// form and t=z² when valid. G₁ is the set of points of this curve on GF(p). +type curvePoint struct { + x, y, z, t gfP +} + +var curveB = newGFp(3) + +// curveGen is the generator of G₁. +var curveGen = &curvePoint{ + x: *newGFp(1), + y: *newGFp(2), + z: *newGFp(1), + t: *newGFp(1), +} + +func (c *curvePoint) String() string { + c.MakeAffine() + x, y := &gfP{}, &gfP{} + montDecode(x, &c.x) + montDecode(y, &c.y) + return "(" + x.String() + ", " + y.String() + ")" +} + +func (c *curvePoint) Set(a *curvePoint) { + c.x.Set(&a.x) + c.y.Set(&a.y) + c.z.Set(&a.z) + c.t.Set(&a.t) +} + +// IsOnCurve returns true iff c is on the curve. +func (c *curvePoint) IsOnCurve() bool { + c.MakeAffine() + if c.IsInfinity() { + return true + } + + y2, x3 := &gfP{}, &gfP{} + gfpMul(y2, &c.y, &c.y) + gfpMul(x3, &c.x, &c.x) + gfpMul(x3, x3, &c.x) + gfpAdd(x3, x3, curveB) + + return *y2 == *x3 +} + +func (c *curvePoint) SetInfinity() { + c.x = gfP{0} + c.y = *newGFp(1) + c.z = gfP{0} + c.t = gfP{0} +} + +func (c *curvePoint) IsInfinity() bool { + return c.z == gfP{0} +} + +func (c *curvePoint) Add(a, b *curvePoint) { + if a.IsInfinity() { + c.Set(b) + return + } + if b.IsInfinity() { + c.Set(a) + return + } + + // See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3 + + // Normalize the points by replacing a = [x1:y1:z1] and b = [x2:y2:z2] + // by [u1:s1:z1·z2] and [u2:s2:z1·z2] + // where u1 = x1·z2², s1 = y1·z2³ and u1 = x2·z1², s2 = y2·z1³ + z12, z22 := &gfP{}, &gfP{} + gfpMul(z12, &a.z, &a.z) + gfpMul(z22, &b.z, &b.z) + + u1, u2 := &gfP{}, &gfP{} + gfpMul(u1, &a.x, z22) + gfpMul(u2, &b.x, z12) + + t, s1 := &gfP{}, &gfP{} + gfpMul(t, &b.z, z22) + gfpMul(s1, &a.y, t) + + s2 := &gfP{} + gfpMul(t, &a.z, z12) + gfpMul(s2, &b.y, t) + + // Compute x = (2h)²(s²-u1-u2) + // where s = (s2-s1)/(u2-u1) is the slope of the line through + // (u1,s1) and (u2,s2). The extra factor 2h = 2(u2-u1) comes from the value of z below. + // This is also: + // 4(s2-s1)² - 4h²(u1+u2) = 4(s2-s1)² - 4h³ - 4h²(2u1) + // = r² - j - 2v + // with the notations below. + h := &gfP{} + gfpSub(h, u2, u1) + xEqual := *h == gfP{0} + + gfpAdd(t, h, h) + // i = 4h² + i := &gfP{} + gfpMul(i, t, t) + // j = 4h³ + j := &gfP{} + gfpMul(j, h, i) + + gfpSub(t, s2, s1) + yEqual := *t == gfP{0} + if xEqual && yEqual { + c.Double(a) + return + } + r := &gfP{} + gfpAdd(r, t, t) + + v := &gfP{} + gfpMul(v, u1, i) + + // t4 = 4(s2-s1)² + t4, t6 := &gfP{}, &gfP{} + gfpMul(t4, r, r) + gfpAdd(t, v, v) + gfpSub(t6, t4, j) + + gfpSub(&c.x, t6, t) + + // Set y = -(2h)³(s1 + s*(x/4h²-u1)) + // This is also + // y = - 2·s1·j - (s2-s1)(2x - 2i·u1) = r(v-x) - 2·s1·j + gfpSub(t, v, &c.x) // t7 + gfpMul(t4, s1, j) // t8 + gfpAdd(t6, t4, t4) // t9 + gfpMul(t4, r, t) // t10 + gfpSub(&c.y, t4, t6) + + // Set z = 2(u2-u1)·z1·z2 = 2h·z1·z2 + gfpAdd(t, &a.z, &b.z) // t11 + gfpMul(t4, t, t) // t12 + gfpSub(t, t4, z12) // t13 + gfpSub(t4, t, z22) // t14 + gfpMul(&c.z, t4, h) +} + +func (c *curvePoint) Double(a *curvePoint) { + // See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3 + A, B, C := &gfP{}, &gfP{}, &gfP{} + gfpMul(A, &a.x, &a.x) + gfpMul(B, &a.y, &a.y) + gfpMul(C, B, B) + + t, t2 := &gfP{}, &gfP{} + gfpAdd(t, &a.x, B) + gfpMul(t2, t, t) + gfpSub(t, t2, A) + gfpSub(t2, t, C) + + d, e, f := &gfP{}, &gfP{}, &gfP{} + gfpAdd(d, t2, t2) + gfpAdd(t, A, A) + gfpAdd(e, t, A) + gfpMul(f, e, e) + + gfpAdd(t, d, d) + gfpSub(&c.x, f, t) + + gfpAdd(t, C, C) + gfpAdd(t2, t, t) + gfpAdd(t, t2, t2) + gfpSub(&c.y, d, &c.x) + gfpMul(t2, e, &c.y) + gfpSub(&c.y, t2, t) + + gfpMul(t, &a.y, &a.z) + gfpAdd(&c.z, t, t) +} + +func (c *curvePoint) Mul(a *curvePoint, scalar *big.Int) { + precomp := [1 << 2]*curvePoint{nil, {}, {}, {}} + precomp[1].Set(a) + precomp[2].Set(a) + gfpMul(&precomp[2].x, &precomp[2].x, xiTo2PSquaredMinus2Over3) + precomp[3].Add(precomp[1], precomp[2]) + + multiScalar := curveLattice.Multi(scalar) + + sum := &curvePoint{} + sum.SetInfinity() + t := &curvePoint{} + + for i := len(multiScalar) - 1; i >= 0; i-- { + t.Double(sum) + if multiScalar[i] == 0 { + sum.Set(t) + } else { + sum.Add(t, precomp[multiScalar[i]]) + } + } + c.Set(sum) +} + +func (c *curvePoint) MakeAffine() { + if c.z == *newGFp(1) { + return + } else if c.z == *newGFp(0) { + c.x = gfP{0} + c.y = *newGFp(1) + c.t = gfP{0} + return + } + + zInv := &gfP{} + zInv.Invert(&c.z) + + t, zInv2 := &gfP{}, &gfP{} + gfpMul(t, &c.y, zInv) + gfpMul(zInv2, zInv, zInv) + + gfpMul(&c.x, &c.x, zInv2) + gfpMul(&c.y, t, zInv2) + + c.z = *newGFp(1) + c.t = *newGFp(1) +} + +func (c *curvePoint) Neg(a *curvePoint) { + c.x.Set(&a.x) + gfpNeg(&c.y, &a.y) + c.z.Set(&a.z) + c.t = gfP{0} +} diff --git a/crypto/bn256/cloudflare/example_test.go b/crypto/bn256/cloudflare/example_test.go new file mode 100644 index 0000000000..6c285995cb --- /dev/null +++ b/crypto/bn256/cloudflare/example_test.go @@ -0,0 +1,51 @@ +// Copyright 2012 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 bn256 + +import ( + "crypto/rand" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestExamplePair(t *testing.T) { + // This implements the tripartite Diffie-Hellman algorithm from "A One + // Round Protocol for Tripartite Diffie-Hellman", A. Joux. + // http://www.springerlink.com/content/cddc57yyva0hburb/fulltext.pdf + + // Each of three parties, a, b and c, generate a private value. + a, _ := rand.Int(rand.Reader, Order) + b, _ := rand.Int(rand.Reader, Order) + c, _ := rand.Int(rand.Reader, Order) + + // Then each party calculates g₁ and g₂ times their private value. + pa := new(G1).ScalarBaseMult(a) + qa := new(G2).ScalarBaseMult(a) + + pb := new(G1).ScalarBaseMult(b) + qb := new(G2).ScalarBaseMult(b) + + pc := new(G1).ScalarBaseMult(c) + qc := new(G2).ScalarBaseMult(c) + + // Now each party exchanges its public values with the other two and + // all parties can calculate the shared key. + k1 := Pair(pb, qc) + k1.ScalarMult(k1, a) + + k2 := Pair(pc, qa) + k2.ScalarMult(k2, b) + + k3 := Pair(pa, qb) + k3.ScalarMult(k3, c) + + // k1, k2 and k3 will all be equal. + + require.Equal(t, k1, k2) + require.Equal(t, k1, k3) + + require.Equal(t, len(np), 4) //Avoid gometalinter varcheck err on np +} diff --git a/crypto/bn256/cloudflare/gfp.go b/crypto/bn256/cloudflare/gfp.go new file mode 100644 index 0000000000..e8e84e7b3b --- /dev/null +++ b/crypto/bn256/cloudflare/gfp.go @@ -0,0 +1,81 @@ +package bn256 + +import ( + "errors" + "fmt" +) + +type gfP [4]uint64 + +func newGFp(x int64) (out *gfP) { + if x >= 0 { + out = &gfP{uint64(x)} + } else { + out = &gfP{uint64(-x)} + gfpNeg(out, out) + } + + montEncode(out, out) + return out +} + +func (e *gfP) String() string { + return fmt.Sprintf("%16.16x%16.16x%16.16x%16.16x", e[3], e[2], e[1], e[0]) +} + +func (e *gfP) Set(f *gfP) { + e[0] = f[0] + e[1] = f[1] + e[2] = f[2] + e[3] = f[3] +} + +func (e *gfP) Invert(f *gfP) { + bits := [4]uint64{0x3c208c16d87cfd45, 0x97816a916871ca8d, 0xb85045b68181585d, 0x30644e72e131a029} + + sum, power := &gfP{}, &gfP{} + sum.Set(rN1) + power.Set(f) + + for word := 0; word < 4; word++ { + for bit := uint(0); bit < 64; bit++ { + if (bits[word]>>bit)&1 == 1 { + gfpMul(sum, sum, power) + } + gfpMul(power, power, power) + } + } + + gfpMul(sum, sum, r3) + e.Set(sum) +} + +func (e *gfP) Marshal(out []byte) { + for w := uint(0); w < 4; w++ { + for b := uint(0); b < 8; b++ { + out[8*w+b] = byte(e[3-w] >> (56 - 8*b)) + } + } +} + +func (e *gfP) Unmarshal(in []byte) error { + // Unmarshal the bytes into little endian form + for w := uint(0); w < 4; w++ { + for b := uint(0); b < 8; b++ { + e[3-w] += uint64(in[8*w+b]) << (56 - 8*b) + } + } + // Ensure the point respects the curve modulus + for i := 3; i >= 0; i-- { + if e[i] < p2[i] { + return nil + } + if e[i] > p2[i] { + return errors.New("bn256: coordinate exceeds modulus") + } + } + return errors.New("bn256: coordinate equals modulus") +} + +func montEncode(c, a *gfP) { gfpMul(c, a, r2) } +func montDecode(c, a *gfP) { gfpMul(c, a, &gfP{1}) } diff --git a/crypto/bn256/cloudflare/gfp12.go b/crypto/bn256/cloudflare/gfp12.go new file mode 100644 index 0000000000..93fb368a7b --- /dev/null +++ b/crypto/bn256/cloudflare/gfp12.go @@ -0,0 +1,160 @@ +package bn256 + +// For details of the algorithms used, see "Multiplication and Squaring on +// Pairing-Friendly Fields, Devegili et al. +// http://eprint.iacr.org/2006/471.pdf. + +import ( + "math/big" +) + +// gfP12 implements the field of size p¹² as a quadratic extension of gfP6 +// where ω²=τ. +type gfP12 struct { + x, y gfP6 // value is xω + y +} + +func (e *gfP12) String() string { + return "(" + e.x.String() + "," + e.y.String() + ")" +} + +func (e *gfP12) Set(a *gfP12) *gfP12 { + e.x.Set(&a.x) + e.y.Set(&a.y) + return e +} + +func (e *gfP12) SetZero() *gfP12 { + e.x.SetZero() + e.y.SetZero() + return e +} + +func (e *gfP12) SetOne() *gfP12 { + e.x.SetZero() + e.y.SetOne() + return e +} + +func (e *gfP12) IsZero() bool { + return e.x.IsZero() && e.y.IsZero() +} + +func (e *gfP12) IsOne() bool { + return e.x.IsZero() && e.y.IsOne() +} + +func (e *gfP12) Conjugate(a *gfP12) *gfP12 { + e.x.Neg(&a.x) + e.y.Set(&a.y) + return e +} + +func (e *gfP12) Neg(a *gfP12) *gfP12 { + e.x.Neg(&a.x) + e.y.Neg(&a.y) + return e +} + +// Frobenius computes (xω+y)^p = x^p ω·ξ^((p-1)/6) + y^p +func (e *gfP12) Frobenius(a *gfP12) *gfP12 { + e.x.Frobenius(&a.x) + e.y.Frobenius(&a.y) + e.x.MulScalar(&e.x, xiToPMinus1Over6) + return e +} + +// FrobeniusP2 computes (xω+y)^p² = x^p² ω·ξ^((p²-1)/6) + y^p² +func (e *gfP12) FrobeniusP2(a *gfP12) *gfP12 { + e.x.FrobeniusP2(&a.x) + e.x.MulGFP(&e.x, xiToPSquaredMinus1Over6) + e.y.FrobeniusP2(&a.y) + return e +} + +func (e *gfP12) FrobeniusP4(a *gfP12) *gfP12 { + e.x.FrobeniusP4(&a.x) + e.x.MulGFP(&e.x, xiToPSquaredMinus1Over3) + e.y.FrobeniusP4(&a.y) + return e +} + +func (e *gfP12) Add(a, b *gfP12) *gfP12 { + e.x.Add(&a.x, &b.x) + e.y.Add(&a.y, &b.y) + return e +} + +func (e *gfP12) Sub(a, b *gfP12) *gfP12 { + e.x.Sub(&a.x, &b.x) + e.y.Sub(&a.y, &b.y) + return e +} + +func (e *gfP12) Mul(a, b *gfP12) *gfP12 { + tx := (&gfP6{}).Mul(&a.x, &b.y) + t := (&gfP6{}).Mul(&b.x, &a.y) + tx.Add(tx, t) + + ty := (&gfP6{}).Mul(&a.y, &b.y) + t.Mul(&a.x, &b.x).MulTau(t) + + e.x.Set(tx) + e.y.Add(ty, t) + return e +} + +func (e *gfP12) MulScalar(a *gfP12, b *gfP6) *gfP12 { + e.x.Mul(&e.x, b) + e.y.Mul(&e.y, b) + return e +} + +func (c *gfP12) Exp(a *gfP12, power *big.Int) *gfP12 { + sum := (&gfP12{}).SetOne() + t := &gfP12{} + + for i := power.BitLen() - 1; i >= 0; i-- { + t.Square(sum) + if power.Bit(i) != 0 { + sum.Mul(t, a) + } else { + sum.Set(t) + } + } + + c.Set(sum) + return c +} + +func (e *gfP12) Square(a *gfP12) *gfP12 { + // Complex squaring algorithm + v0 := (&gfP6{}).Mul(&a.x, &a.y) + + t := (&gfP6{}).MulTau(&a.x) + t.Add(&a.y, t) + ty := (&gfP6{}).Add(&a.x, &a.y) + ty.Mul(ty, t).Sub(ty, v0) + t.MulTau(v0) + ty.Sub(ty, t) + + e.x.Add(v0, v0) + e.y.Set(ty) + return e +} + +func (e *gfP12) Invert(a *gfP12) *gfP12 { + // See "Implementing cryptographic pairings", M. Scott, section 3.2. + // ftp://136.206.11.249/pub/crypto/pairings.pdf + t1, t2 := &gfP6{}, &gfP6{} + + t1.Square(&a.x) + t2.Square(&a.y) + t1.MulTau(t1).Sub(t2, t1) + t2.Invert(t1) + + e.x.Neg(&a.x) + e.y.Set(&a.y) + e.MulScalar(e, t2) + return e +} diff --git a/crypto/bn256/cloudflare/gfp2.go b/crypto/bn256/cloudflare/gfp2.go new file mode 100644 index 0000000000..90a89e8b47 --- /dev/null +++ b/crypto/bn256/cloudflare/gfp2.go @@ -0,0 +1,156 @@ +package bn256 + +// For details of the algorithms used, see "Multiplication and Squaring on +// Pairing-Friendly Fields, Devegili et al. +// http://eprint.iacr.org/2006/471.pdf. + +// gfP2 implements a field of size p² as a quadratic extension of the base field +// where i²=-1. +type gfP2 struct { + x, y gfP // value is xi+y. +} + +func gfP2Decode(in *gfP2) *gfP2 { + out := &gfP2{} + montDecode(&out.x, &in.x) + montDecode(&out.y, &in.y) + return out +} + +func (e *gfP2) String() string { + return "(" + e.x.String() + ", " + e.y.String() + ")" +} + +func (e *gfP2) Set(a *gfP2) *gfP2 { + e.x.Set(&a.x) + e.y.Set(&a.y) + return e +} + +func (e *gfP2) SetZero() *gfP2 { + e.x = gfP{0} + e.y = gfP{0} + return e +} + +func (e *gfP2) SetOne() *gfP2 { + e.x = gfP{0} + e.y = *newGFp(1) + return e +} + +func (e *gfP2) IsZero() bool { + zero := gfP{0} + return e.x == zero && e.y == zero +} + +func (e *gfP2) IsOne() bool { + zero, one := gfP{0}, *newGFp(1) + return e.x == zero && e.y == one +} + +func (e *gfP2) Conjugate(a *gfP2) *gfP2 { + e.y.Set(&a.y) + gfpNeg(&e.x, &a.x) + return e +} + +func (e *gfP2) Neg(a *gfP2) *gfP2 { + gfpNeg(&e.x, &a.x) + gfpNeg(&e.y, &a.y) + return e +} + +func (e *gfP2) Add(a, b *gfP2) *gfP2 { + gfpAdd(&e.x, &a.x, &b.x) + gfpAdd(&e.y, &a.y, &b.y) + return e +} + +func (e *gfP2) Sub(a, b *gfP2) *gfP2 { + gfpSub(&e.x, &a.x, &b.x) + gfpSub(&e.y, &a.y, &b.y) + return e +} + +// See "Multiplication and Squaring in Pairing-Friendly Fields", +// http://eprint.iacr.org/2006/471.pdf +func (e *gfP2) Mul(a, b *gfP2) *gfP2 { + tx, t := &gfP{}, &gfP{} + gfpMul(tx, &a.x, &b.y) + gfpMul(t, &b.x, &a.y) + gfpAdd(tx, tx, t) + + ty := &gfP{} + gfpMul(ty, &a.y, &b.y) + gfpMul(t, &a.x, &b.x) + gfpSub(ty, ty, t) + + e.x.Set(tx) + e.y.Set(ty) + return e +} + +func (e *gfP2) MulScalar(a *gfP2, b *gfP) *gfP2 { + gfpMul(&e.x, &a.x, b) + gfpMul(&e.y, &a.y, b) + return e +} + +// MulXi sets e=ξa where ξ=i+9 and then returns e. +func (e *gfP2) MulXi(a *gfP2) *gfP2 { + // (xi+y)(i+9) = (9x+y)i+(9y-x) + tx := &gfP{} + gfpAdd(tx, &a.x, &a.x) + gfpAdd(tx, tx, tx) + gfpAdd(tx, tx, tx) + gfpAdd(tx, tx, &a.x) + + gfpAdd(tx, tx, &a.y) + + ty := &gfP{} + gfpAdd(ty, &a.y, &a.y) + gfpAdd(ty, ty, ty) + gfpAdd(ty, ty, ty) + gfpAdd(ty, ty, &a.y) + + gfpSub(ty, ty, &a.x) + + e.x.Set(tx) + e.y.Set(ty) + return e +} + +func (e *gfP2) Square(a *gfP2) *gfP2 { + // Complex squaring algorithm: + // (xi+y)² = (x+y)(y-x) + 2*i*x*y + tx, ty := &gfP{}, &gfP{} + gfpSub(tx, &a.y, &a.x) + gfpAdd(ty, &a.x, &a.y) + gfpMul(ty, tx, ty) + + gfpMul(tx, &a.x, &a.y) + gfpAdd(tx, tx, tx) + + e.x.Set(tx) + e.y.Set(ty) + return e +} + +func (e *gfP2) Invert(a *gfP2) *gfP2 { + // See "Implementing cryptographic pairings", M. Scott, section 3.2. + // ftp://136.206.11.249/pub/crypto/pairings.pdf + t1, t2 := &gfP{}, &gfP{} + gfpMul(t1, &a.x, &a.x) + gfpMul(t2, &a.y, &a.y) + gfpAdd(t1, t1, t2) + + inv := &gfP{} + inv.Invert(t1) + + gfpNeg(t1, &a.x) + + gfpMul(&e.x, t1, inv) + gfpMul(&e.y, &a.y, inv) + return e +} diff --git a/crypto/bn256/cloudflare/gfp6.go b/crypto/bn256/cloudflare/gfp6.go new file mode 100644 index 0000000000..83d61b781f --- /dev/null +++ b/crypto/bn256/cloudflare/gfp6.go @@ -0,0 +1,213 @@ +package bn256 + +// For details of the algorithms used, see "Multiplication and Squaring on +// Pairing-Friendly Fields, Devegili et al. +// http://eprint.iacr.org/2006/471.pdf. + +// gfP6 implements the field of size p⁶ as a cubic extension of gfP2 where τ³=ξ +// and ξ=i+3. +type gfP6 struct { + x, y, z gfP2 // value is xτ² + yτ + z +} + +func (e *gfP6) String() string { + return "(" + e.x.String() + ", " + e.y.String() + ", " + e.z.String() + ")" +} + +func (e *gfP6) Set(a *gfP6) *gfP6 { + e.x.Set(&a.x) + e.y.Set(&a.y) + e.z.Set(&a.z) + return e +} + +func (e *gfP6) SetZero() *gfP6 { + e.x.SetZero() + e.y.SetZero() + e.z.SetZero() + return e +} + +func (e *gfP6) SetOne() *gfP6 { + e.x.SetZero() + e.y.SetZero() + e.z.SetOne() + return e +} + +func (e *gfP6) IsZero() bool { + return e.x.IsZero() && e.y.IsZero() && e.z.IsZero() +} + +func (e *gfP6) IsOne() bool { + return e.x.IsZero() && e.y.IsZero() && e.z.IsOne() +} + +func (e *gfP6) Neg(a *gfP6) *gfP6 { + e.x.Neg(&a.x) + e.y.Neg(&a.y) + e.z.Neg(&a.z) + return e +} + +func (e *gfP6) Frobenius(a *gfP6) *gfP6 { + e.x.Conjugate(&a.x) + e.y.Conjugate(&a.y) + e.z.Conjugate(&a.z) + + e.x.Mul(&e.x, xiTo2PMinus2Over3) + e.y.Mul(&e.y, xiToPMinus1Over3) + return e +} + +// FrobeniusP2 computes (xτ²+yτ+z)^(p²) = xτ^(2p²) + yτ^(p²) + z +func (e *gfP6) FrobeniusP2(a *gfP6) *gfP6 { + // τ^(2p²) = τ²τ^(2p²-2) = τ²ξ^((2p²-2)/3) + e.x.MulScalar(&a.x, xiTo2PSquaredMinus2Over3) + // τ^(p²) = ττ^(p²-1) = τξ^((p²-1)/3) + e.y.MulScalar(&a.y, xiToPSquaredMinus1Over3) + e.z.Set(&a.z) + return e +} + +func (e *gfP6) FrobeniusP4(a *gfP6) *gfP6 { + e.x.MulScalar(&a.x, xiToPSquaredMinus1Over3) + e.y.MulScalar(&a.y, xiTo2PSquaredMinus2Over3) + e.z.Set(&a.z) + return e +} + +func (e *gfP6) Add(a, b *gfP6) *gfP6 { + e.x.Add(&a.x, &b.x) + e.y.Add(&a.y, &b.y) + e.z.Add(&a.z, &b.z) + return e +} + +func (e *gfP6) Sub(a, b *gfP6) *gfP6 { + e.x.Sub(&a.x, &b.x) + e.y.Sub(&a.y, &b.y) + e.z.Sub(&a.z, &b.z) + return e +} + +func (e *gfP6) Mul(a, b *gfP6) *gfP6 { + // "Multiplication and Squaring on Pairing-Friendly Fields" + // Section 4, Karatsuba method. + // http://eprint.iacr.org/2006/471.pdf + v0 := (&gfP2{}).Mul(&a.z, &b.z) + v1 := (&gfP2{}).Mul(&a.y, &b.y) + v2 := (&gfP2{}).Mul(&a.x, &b.x) + + t0 := (&gfP2{}).Add(&a.x, &a.y) + t1 := (&gfP2{}).Add(&b.x, &b.y) + tz := (&gfP2{}).Mul(t0, t1) + tz.Sub(tz, v1).Sub(tz, v2).MulXi(tz).Add(tz, v0) + + t0.Add(&a.y, &a.z) + t1.Add(&b.y, &b.z) + ty := (&gfP2{}).Mul(t0, t1) + t0.MulXi(v2) + ty.Sub(ty, v0).Sub(ty, v1).Add(ty, t0) + + t0.Add(&a.x, &a.z) + t1.Add(&b.x, &b.z) + tx := (&gfP2{}).Mul(t0, t1) + tx.Sub(tx, v0).Add(tx, v1).Sub(tx, v2) + + e.x.Set(tx) + e.y.Set(ty) + e.z.Set(tz) + return e +} + +func (e *gfP6) MulScalar(a *gfP6, b *gfP2) *gfP6 { + e.x.Mul(&a.x, b) + e.y.Mul(&a.y, b) + e.z.Mul(&a.z, b) + return e +} + +func (e *gfP6) MulGFP(a *gfP6, b *gfP) *gfP6 { + e.x.MulScalar(&a.x, b) + e.y.MulScalar(&a.y, b) + e.z.MulScalar(&a.z, b) + return e +} + +// MulTau computes τ·(aτ²+bτ+c) = bτ²+cτ+aξ +func (e *gfP6) MulTau(a *gfP6) *gfP6 { + tz := (&gfP2{}).MulXi(&a.x) + ty := (&gfP2{}).Set(&a.y) + + e.y.Set(&a.z) + e.x.Set(ty) + e.z.Set(tz) + return e +} + +func (e *gfP6) Square(a *gfP6) *gfP6 { + v0 := (&gfP2{}).Square(&a.z) + v1 := (&gfP2{}).Square(&a.y) + v2 := (&gfP2{}).Square(&a.x) + + c0 := (&gfP2{}).Add(&a.x, &a.y) + c0.Square(c0).Sub(c0, v1).Sub(c0, v2).MulXi(c0).Add(c0, v0) + + c1 := (&gfP2{}).Add(&a.y, &a.z) + c1.Square(c1).Sub(c1, v0).Sub(c1, v1) + xiV2 := (&gfP2{}).MulXi(v2) + c1.Add(c1, xiV2) + + c2 := (&gfP2{}).Add(&a.x, &a.z) + c2.Square(c2).Sub(c2, v0).Add(c2, v1).Sub(c2, v2) + + e.x.Set(c2) + e.y.Set(c1) + e.z.Set(c0) + return e +} + +func (e *gfP6) Invert(a *gfP6) *gfP6 { + // See "Implementing cryptographic pairings", M. Scott, section 3.2. + // ftp://136.206.11.249/pub/crypto/pairings.pdf + + // Here we can give a short explanation of how it works: let j be a cubic root of + // unity in GF(p²) so that 1+j+j²=0. + // Then (xτ² + yτ + z)(xj²τ² + yjτ + z)(xjτ² + yj²τ + z) + // = (xτ² + yτ + z)(Cτ²+Bτ+A) + // = (x³ξ²+y³ξ+z³-3ξxyz) = F is an element of the base field (the norm). + // + // On the other hand (xj²τ² + yjτ + z)(xjτ² + yj²τ + z) + // = τ²(y²-ξxz) + τ(ξx²-yz) + (z²-ξxy) + // + // So that's why A = (z²-ξxy), B = (ξx²-yz), C = (y²-ξxz) + t1 := (&gfP2{}).Mul(&a.x, &a.y) + t1.MulXi(t1) + + A := (&gfP2{}).Square(&a.z) + A.Sub(A, t1) + + B := (&gfP2{}).Square(&a.x) + B.MulXi(B) + t1.Mul(&a.y, &a.z) + B.Sub(B, t1) + + C := (&gfP2{}).Square(&a.y) + t1.Mul(&a.x, &a.z) + C.Sub(C, t1) + + F := (&gfP2{}).Mul(C, &a.y) + F.MulXi(F) + t1.Mul(A, &a.z) + F.Add(F, t1) + t1.Mul(B, &a.x).MulXi(t1) + F.Add(F, t1) + + F.Invert(F) + + e.x.Mul(C, F) + e.y.Mul(B, F) + e.z.Mul(A, F) + return e +} diff --git a/crypto/bn256/cloudflare/gfp_amd64.s b/crypto/bn256/cloudflare/gfp_amd64.s new file mode 100644 index 0000000000..bdb4ffb787 --- /dev/null +++ b/crypto/bn256/cloudflare/gfp_amd64.s @@ -0,0 +1,129 @@ +// +build amd64,!generic + +#define storeBlock(a0,a1,a2,a3, r) \ + MOVQ a0, 0+r \ + MOVQ a1, 8+r \ + MOVQ a2, 16+r \ + MOVQ a3, 24+r + +#define loadBlock(r, a0,a1,a2,a3) \ + MOVQ 0+r, a0 \ + MOVQ 8+r, a1 \ + MOVQ 16+r, a2 \ + MOVQ 24+r, a3 + +#define gfpCarry(a0,a1,a2,a3,a4, b0,b1,b2,b3,b4) \ + \ // b = a-p + MOVQ a0, b0 \ + MOVQ a1, b1 \ + MOVQ a2, b2 \ + MOVQ a3, b3 \ + MOVQ a4, b4 \ + \ + SUBQ ·p2+0(SB), b0 \ + SBBQ ·p2+8(SB), b1 \ + SBBQ ·p2+16(SB), b2 \ + SBBQ ·p2+24(SB), b3 \ + SBBQ $0, b4 \ + \ + \ // if b is negative then return a + \ // else return b + CMOVQCC b0, a0 \ + CMOVQCC b1, a1 \ + CMOVQCC b2, a2 \ + CMOVQCC b3, a3 + +#include "mul_amd64.h" +#include "mul_bmi2_amd64.h" + +TEXT ·gfpNeg(SB),0,$0-16 + MOVQ ·p2+0(SB), R8 + MOVQ ·p2+8(SB), R9 + MOVQ ·p2+16(SB), R10 + MOVQ ·p2+24(SB), R11 + + MOVQ a+8(FP), DI + SUBQ 0(DI), R8 + SBBQ 8(DI), R9 + SBBQ 16(DI), R10 + SBBQ 24(DI), R11 + + MOVQ $0, AX + gfpCarry(R8,R9,R10,R11,AX, R12,R13,R14,R15,BX) + + MOVQ c+0(FP), DI + storeBlock(R8,R9,R10,R11, 0(DI)) + RET + +TEXT ·gfpAdd(SB),0,$0-24 + MOVQ a+8(FP), DI + MOVQ b+16(FP), SI + + loadBlock(0(DI), R8,R9,R10,R11) + MOVQ $0, R12 + + ADDQ 0(SI), R8 + ADCQ 8(SI), R9 + ADCQ 16(SI), R10 + ADCQ 24(SI), R11 + ADCQ $0, R12 + + gfpCarry(R8,R9,R10,R11,R12, R13,R14,R15,AX,BX) + + MOVQ c+0(FP), DI + storeBlock(R8,R9,R10,R11, 0(DI)) + RET + +TEXT ·gfpSub(SB),0,$0-24 + MOVQ a+8(FP), DI + MOVQ b+16(FP), SI + + loadBlock(0(DI), R8,R9,R10,R11) + + MOVQ ·p2+0(SB), R12 + MOVQ ·p2+8(SB), R13 + MOVQ ·p2+16(SB), R14 + MOVQ ·p2+24(SB), R15 + MOVQ $0, AX + + SUBQ 0(SI), R8 + SBBQ 8(SI), R9 + SBBQ 16(SI), R10 + SBBQ 24(SI), R11 + + CMOVQCC AX, R12 + CMOVQCC AX, R13 + CMOVQCC AX, R14 + CMOVQCC AX, R15 + + ADDQ R12, R8 + ADCQ R13, R9 + ADCQ R14, R10 + ADCQ R15, R11 + + MOVQ c+0(FP), DI + storeBlock(R8,R9,R10,R11, 0(DI)) + RET + +TEXT ·gfpMul(SB),0,$160-24 + MOVQ a+8(FP), DI + MOVQ b+16(FP), SI + + // Jump to a slightly different implementation if MULX isn't supported. + CMPB ·hasBMI2(SB), $0 + JE nobmi2Mul + + mulBMI2(0(DI),8(DI),16(DI),24(DI), 0(SI)) + storeBlock( R8, R9,R10,R11, 0(SP)) + storeBlock(R12,R13,R14,R15, 32(SP)) + gfpReduceBMI2() + JMP end + +nobmi2Mul: + mul(0(DI),8(DI),16(DI),24(DI), 0(SI), 0(SP)) + gfpReduce(0(SP)) + +end: + MOVQ c+0(FP), DI + storeBlock(R12,R13,R14,R15, 0(DI)) + RET diff --git a/crypto/bn256/cloudflare/gfp_arm64.s b/crypto/bn256/cloudflare/gfp_arm64.s new file mode 100644 index 0000000000..c65e80168c --- /dev/null +++ b/crypto/bn256/cloudflare/gfp_arm64.s @@ -0,0 +1,113 @@ +// +build arm64,!generic + +#define storeBlock(a0,a1,a2,a3, r) \ + MOVD a0, 0+r \ + MOVD a1, 8+r \ + MOVD a2, 16+r \ + MOVD a3, 24+r + +#define loadBlock(r, a0,a1,a2,a3) \ + MOVD 0+r, a0 \ + MOVD 8+r, a1 \ + MOVD 16+r, a2 \ + MOVD 24+r, a3 + +#define loadModulus(p0,p1,p2,p3) \ + MOVD ·p2+0(SB), p0 \ + MOVD ·p2+8(SB), p1 \ + MOVD ·p2+16(SB), p2 \ + MOVD ·p2+24(SB), p3 + +#include "mul_arm64.h" + +TEXT ·gfpNeg(SB),0,$0-16 + MOVD a+8(FP), R0 + loadBlock(0(R0), R1,R2,R3,R4) + loadModulus(R5,R6,R7,R8) + + SUBS R1, R5, R1 + SBCS R2, R6, R2 + SBCS R3, R7, R3 + SBCS R4, R8, R4 + + SUBS R5, R1, R5 + SBCS R6, R2, R6 + SBCS R7, R3, R7 + SBCS R8, R4, R8 + + CSEL CS, R5, R1, R1 + CSEL CS, R6, R2, R2 + CSEL CS, R7, R3, R3 + CSEL CS, R8, R4, R4 + + MOVD c+0(FP), R0 + storeBlock(R1,R2,R3,R4, 0(R0)) + RET + +TEXT ·gfpAdd(SB),0,$0-24 + MOVD a+8(FP), R0 + loadBlock(0(R0), R1,R2,R3,R4) + MOVD b+16(FP), R0 + loadBlock(0(R0), R5,R6,R7,R8) + loadModulus(R9,R10,R11,R12) + MOVD ZR, R0 + + ADDS R5, R1 + ADCS R6, R2 + ADCS R7, R3 + ADCS R8, R4 + ADCS ZR, R0 + + SUBS R9, R1, R5 + SBCS R10, R2, R6 + SBCS R11, R3, R7 + SBCS R12, R4, R8 + SBCS ZR, R0, R0 + + CSEL CS, R5, R1, R1 + CSEL CS, R6, R2, R2 + CSEL CS, R7, R3, R3 + CSEL CS, R8, R4, R4 + + MOVD c+0(FP), R0 + storeBlock(R1,R2,R3,R4, 0(R0)) + RET + +TEXT ·gfpSub(SB),0,$0-24 + MOVD a+8(FP), R0 + loadBlock(0(R0), R1,R2,R3,R4) + MOVD b+16(FP), R0 + loadBlock(0(R0), R5,R6,R7,R8) + loadModulus(R9,R10,R11,R12) + + SUBS R5, R1 + SBCS R6, R2 + SBCS R7, R3 + SBCS R8, R4 + + CSEL CS, ZR, R9, R9 + CSEL CS, ZR, R10, R10 + CSEL CS, ZR, R11, R11 + CSEL CS, ZR, R12, R12 + + ADDS R9, R1 + ADCS R10, R2 + ADCS R11, R3 + ADCS R12, R4 + + MOVD c+0(FP), R0 + storeBlock(R1,R2,R3,R4, 0(R0)) + RET + +TEXT ·gfpMul(SB),0,$0-24 + MOVD a+8(FP), R0 + loadBlock(0(R0), R1,R2,R3,R4) + MOVD b+16(FP), R0 + loadBlock(0(R0), R5,R6,R7,R8) + + mul(R9,R10,R11,R12,R13,R14,R15,R16) + gfpReduce() + + MOVD c+0(FP), R0 + storeBlock(R1,R2,R3,R4, 0(R0)) + RET diff --git a/crypto/bn256/cloudflare/gfp_decl.go b/crypto/bn256/cloudflare/gfp_decl.go new file mode 100644 index 0000000000..fdea5c11a5 --- /dev/null +++ b/crypto/bn256/cloudflare/gfp_decl.go @@ -0,0 +1,25 @@ +// +build amd64,!generic arm64,!generic + +package bn256 + +// This file contains forward declarations for the architecture-specific +// assembly implementations of these functions, provided that they exist. + +import ( + "golang.org/x/sys/cpu" +) + +//nolint:varcheck +var hasBMI2 = cpu.X86.HasBMI2 + +// go:noescape +func gfpNeg(c, a *gfP) + +//go:noescape +func gfpAdd(c, a, b *gfP) + +//go:noescape +func gfpSub(c, a, b *gfP) + +//go:noescape +func gfpMul(c, a, b *gfP) diff --git a/crypto/bn256/cloudflare/gfp_generic.go b/crypto/bn256/cloudflare/gfp_generic.go new file mode 100644 index 0000000000..8e6be95961 --- /dev/null +++ b/crypto/bn256/cloudflare/gfp_generic.go @@ -0,0 +1,173 @@ +// +build !amd64,!arm64 generic + +package bn256 + +func gfpCarry(a *gfP, head uint64) { + b := &gfP{} + + var carry uint64 + for i, pi := range p2 { + ai := a[i] + bi := ai - pi - carry + b[i] = bi + carry = (pi&^ai | (pi|^ai)&bi) >> 63 + } + carry = carry &^ head + + // If b is negative, then return a. + // Else return b. + carry = -carry + ncarry := ^carry + for i := 0; i < 4; i++ { + a[i] = (a[i] & carry) | (b[i] & ncarry) + } +} + +func gfpNeg(c, a *gfP) { + var carry uint64 + for i, pi := range p2 { + ai := a[i] + ci := pi - ai - carry + c[i] = ci + carry = (ai&^pi | (ai|^pi)&ci) >> 63 + } + gfpCarry(c, 0) +} + +func gfpAdd(c, a, b *gfP) { + var carry uint64 + for i, ai := range a { + bi := b[i] + ci := ai + bi + carry + c[i] = ci + carry = (ai&bi | (ai|bi)&^ci) >> 63 + } + gfpCarry(c, carry) +} + +func gfpSub(c, a, b *gfP) { + t := &gfP{} + + var carry uint64 + for i, pi := range p2 { + bi := b[i] + ti := pi - bi - carry + t[i] = ti + carry = (bi&^pi | (bi|^pi)&ti) >> 63 + } + + carry = 0 + for i, ai := range a { + ti := t[i] + ci := ai + ti + carry + c[i] = ci + carry = (ai&ti | (ai|ti)&^ci) >> 63 + } + gfpCarry(c, carry) +} + +func mul(a, b [4]uint64) [8]uint64 { + const ( + mask16 uint64 = 0x0000ffff + mask32 uint64 = 0xffffffff + ) + + var buff [32]uint64 + for i, ai := range a { + a0, a1, a2, a3 := ai&mask16, (ai>>16)&mask16, (ai>>32)&mask16, ai>>48 + + for j, bj := range b { + b0, b2 := bj&mask32, bj>>32 + + off := 4 * (i + j) + buff[off+0] += a0 * b0 + buff[off+1] += a1 * b0 + buff[off+2] += a2*b0 + a0*b2 + buff[off+3] += a3*b0 + a1*b2 + buff[off+4] += a2 * b2 + buff[off+5] += a3 * b2 + } + } + + for i := uint(1); i < 4; i++ { + shift := 16 * i + + var head, carry uint64 + for j := uint(0); j < 8; j++ { + block := 4 * j + + xi := buff[block] + yi := (buff[block+i] << shift) + head + zi := xi + yi + carry + buff[block] = zi + carry = (xi&yi | (xi|yi)&^zi) >> 63 + + head = buff[block+i] >> (64 - shift) + } + } + + return [8]uint64{buff[0], buff[4], buff[8], buff[12], buff[16], buff[20], buff[24], buff[28]} +} + +func halfMul(a, b [4]uint64) [4]uint64 { + const ( + mask16 uint64 = 0x0000ffff + mask32 uint64 = 0xffffffff + ) + + var buff [18]uint64 + for i, ai := range a { + a0, a1, a2, a3 := ai&mask16, (ai>>16)&mask16, (ai>>32)&mask16, ai>>48 + + for j, bj := range b { + if i+j > 3 { + break + } + b0, b2 := bj&mask32, bj>>32 + + off := 4 * (i + j) + buff[off+0] += a0 * b0 + buff[off+1] += a1 * b0 + buff[off+2] += a2*b0 + a0*b2 + buff[off+3] += a3*b0 + a1*b2 + buff[off+4] += a2 * b2 + buff[off+5] += a3 * b2 + } + } + + for i := uint(1); i < 4; i++ { + shift := 16 * i + + var head, carry uint64 + for j := uint(0); j < 4; j++ { + block := 4 * j + + xi := buff[block] + yi := (buff[block+i] << shift) + head + zi := xi + yi + carry + buff[block] = zi + carry = (xi&yi | (xi|yi)&^zi) >> 63 + + head = buff[block+i] >> (64 - shift) + } + } + + return [4]uint64{buff[0], buff[4], buff[8], buff[12]} +} + +func gfpMul(c, a, b *gfP) { + T := mul(*a, *b) + m := halfMul([4]uint64{T[0], T[1], T[2], T[3]}, np) + t := mul([4]uint64{m[0], m[1], m[2], m[3]}, p2) + + var carry uint64 + for i, Ti := range T { + ti := t[i] + zi := Ti + ti + carry + T[i] = zi + carry = (Ti&ti | (Ti|ti)&^zi) >> 63 + } + + *c = gfP{T[4], T[5], T[6], T[7]} + gfpCarry(c, carry) +} diff --git a/crypto/bn256/cloudflare/gfp_test.go b/crypto/bn256/cloudflare/gfp_test.go new file mode 100644 index 0000000000..16ab2a8410 --- /dev/null +++ b/crypto/bn256/cloudflare/gfp_test.go @@ -0,0 +1,60 @@ +package bn256 + +import ( + "testing" +) + +// Tests that negation works the same way on both assembly-optimized and pure Go +// implementation. +func TestGFpNeg(t *testing.T) { + n := &gfP{0x0123456789abcdef, 0xfedcba9876543210, 0xdeadbeefdeadbeef, 0xfeebdaedfeebdaed} + w := &gfP{0xfedcba9876543211, 0x0123456789abcdef, 0x2152411021524110, 0x0114251201142512} + h := &gfP{} + + gfpNeg(h, n) + if *h != *w { + t.Errorf("negation mismatch: have %#x, want %#x", *h, *w) + } +} + +// Tests that addition works the same way on both assembly-optimized and pure Go +// implementation. +func TestGFpAdd(t *testing.T) { + a := &gfP{0x0123456789abcdef, 0xfedcba9876543210, 0xdeadbeefdeadbeef, 0xfeebdaedfeebdaed} + b := &gfP{0xfedcba9876543210, 0x0123456789abcdef, 0xfeebdaedfeebdaed, 0xdeadbeefdeadbeef} + w := &gfP{0xc3df73e9278302b8, 0x687e956e978e3572, 0x254954275c18417f, 0xad354b6afc67f9b4} + h := &gfP{} + + gfpAdd(h, a, b) + if *h != *w { + t.Errorf("addition mismatch: have %#x, want %#x", *h, *w) + } +} + +// Tests that subtraction works the same way on both assembly-optimized and pure Go +// implementation. +func TestGFpSub(t *testing.T) { + a := &gfP{0x0123456789abcdef, 0xfedcba9876543210, 0xdeadbeefdeadbeef, 0xfeebdaedfeebdaed} + b := &gfP{0xfedcba9876543210, 0x0123456789abcdef, 0xfeebdaedfeebdaed, 0xdeadbeefdeadbeef} + w := &gfP{0x02468acf13579bdf, 0xfdb97530eca86420, 0xdfc1e401dfc1e402, 0x203e1bfe203e1bfd} + h := &gfP{} + + gfpSub(h, a, b) + if *h != *w { + t.Errorf("subtraction mismatch: have %#x, want %#x", *h, *w) + } +} + +// Tests that multiplication works the same way on both assembly-optimized and pure Go +// implementation. +func TestGFpMul(t *testing.T) { + a := &gfP{0x0123456789abcdef, 0xfedcba9876543210, 0xdeadbeefdeadbeef, 0xfeebdaedfeebdaed} + b := &gfP{0xfedcba9876543210, 0x0123456789abcdef, 0xfeebdaedfeebdaed, 0xdeadbeefdeadbeef} + w := &gfP{0xcbcbd377f7ad22d3, 0x3b89ba5d849379bf, 0x87b61627bd38b6d2, 0xc44052a2a0e654b2} + h := &gfP{} + + gfpMul(h, a, b) + if *h != *w { + t.Errorf("multiplication mismatch: have %#x, want %#x", *h, *w) + } +} diff --git a/crypto/bn256/cloudflare/lattice.go b/crypto/bn256/cloudflare/lattice.go new file mode 100644 index 0000000000..f9ace4d9fc --- /dev/null +++ b/crypto/bn256/cloudflare/lattice.go @@ -0,0 +1,115 @@ +package bn256 + +import ( + "math/big" +) + +var half = new(big.Int).Rsh(Order, 1) + +var curveLattice = &lattice{ + vectors: [][]*big.Int{ + {bigFromBase10("147946756881789319000765030803803410728"), bigFromBase10("147946756881789319010696353538189108491")}, + {bigFromBase10("147946756881789319020627676272574806254"), bigFromBase10("-147946756881789318990833708069417712965")}, + }, + inverse: []*big.Int{ + bigFromBase10("147946756881789318990833708069417712965"), + bigFromBase10("147946756881789319010696353538189108491"), + }, + det: bigFromBase10("43776485743678550444492811490514550177096728800832068687396408373151616991234"), +} + +var targetLattice = &lattice{ + vectors: [][]*big.Int{ + {bigFromBase10("9931322734385697761"), bigFromBase10("9931322734385697761"), bigFromBase10("9931322734385697763"), bigFromBase10("9931322734385697764")}, + {bigFromBase10("4965661367192848881"), bigFromBase10("4965661367192848881"), bigFromBase10("4965661367192848882"), bigFromBase10("-9931322734385697762")}, + {bigFromBase10("-9931322734385697762"), bigFromBase10("-4965661367192848881"), bigFromBase10("4965661367192848881"), bigFromBase10("-4965661367192848882")}, + {bigFromBase10("9931322734385697763"), bigFromBase10("-4965661367192848881"), bigFromBase10("-4965661367192848881"), bigFromBase10("-4965661367192848881")}, + }, + inverse: []*big.Int{ + bigFromBase10("734653495049373973658254490726798021314063399421879442165"), + bigFromBase10("147946756881789319000765030803803410728"), + bigFromBase10("-147946756881789319005730692170996259609"), + bigFromBase10("1469306990098747947464455738335385361643788813749140841702"), + }, + det: new(big.Int).Set(Order), +} + +type lattice struct { + vectors [][]*big.Int + inverse []*big.Int + det *big.Int +} + +// decompose takes a scalar mod Order as input and finds a short, positive decomposition of it wrt to the lattice basis. +func (l *lattice) decompose(k *big.Int) []*big.Int { + n := len(l.inverse) + + // Calculate closest vector in lattice to with Babai's rounding. + c := make([]*big.Int, n) + for i := 0; i < n; i++ { + c[i] = new(big.Int).Mul(k, l.inverse[i]) + round(c[i], l.det) + } + + // Transform vectors according to c and subtract . + out := make([]*big.Int, n) + temp := new(big.Int) + + for i := 0; i < n; i++ { + out[i] = new(big.Int) + + for j := 0; j < n; j++ { + temp.Mul(c[j], l.vectors[j][i]) + out[i].Add(out[i], temp) + } + + out[i].Neg(out[i]) + out[i].Add(out[i], l.vectors[0][i]).Add(out[i], l.vectors[0][i]) + } + out[0].Add(out[0], k) + + return out +} + +func (l *lattice) Precompute(add func(i, j uint)) { + n := uint(len(l.vectors)) + total := uint(1) << n + + for i := uint(0); i < n; i++ { + for j := uint(0); j < total; j++ { + if (j>>i)&1 == 1 { + add(i, j) + } + } + } +} + +func (l *lattice) Multi(scalar *big.Int) []uint8 { + decomp := l.decompose(scalar) + + maxLen := 0 + for _, x := range decomp { + if x.BitLen() > maxLen { + maxLen = x.BitLen() + } + } + + out := make([]uint8, maxLen) + for j, x := range decomp { + for i := 0; i < maxLen; i++ { + out[i] += uint8(x.Bit(i)) << uint(j) + } + } + + return out +} + +// round sets num to num/denom rounded to the nearest integer. +func round(num, denom *big.Int) { + r := new(big.Int) + num.DivMod(num, denom, r) + + if r.Cmp(half) == 1 { + num.Add(num, big.NewInt(1)) + } +} diff --git a/crypto/bn256/cloudflare/lattice_test.go b/crypto/bn256/cloudflare/lattice_test.go new file mode 100644 index 0000000000..4d52ad9b27 --- /dev/null +++ b/crypto/bn256/cloudflare/lattice_test.go @@ -0,0 +1,29 @@ +package bn256 + +import ( + "crypto/rand" + + "testing" +) + +func TestLatticeReduceCurve(t *testing.T) { + k, _ := rand.Int(rand.Reader, Order) + ks := curveLattice.decompose(k) + + if ks[0].BitLen() > 130 || ks[1].BitLen() > 130 { + t.Fatal("reduction too large") + } else if ks[0].Sign() < 0 || ks[1].Sign() < 0 { + t.Fatal("reduction must be positive") + } +} + +func TestLatticeReduceTarget(t *testing.T) { + k, _ := rand.Int(rand.Reader, Order) + ks := targetLattice.decompose(k) + + if ks[0].BitLen() > 66 || ks[1].BitLen() > 66 || ks[2].BitLen() > 66 || ks[3].BitLen() > 66 { + t.Fatal("reduction too large") + } else if ks[0].Sign() < 0 || ks[1].Sign() < 0 || ks[2].Sign() < 0 || ks[3].Sign() < 0 { + t.Fatal("reduction must be positive") + } +} diff --git a/crypto/bn256/main_test.go b/crypto/bn256/cloudflare/main_test.go similarity index 98% rename from crypto/bn256/main_test.go rename to crypto/bn256/cloudflare/main_test.go index 0230f1b199..c0c85457be 100644 --- a/crypto/bn256/main_test.go +++ b/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/crypto/bn256/cloudflare/mul_amd64.h b/crypto/bn256/cloudflare/mul_amd64.h new file mode 100644 index 0000000000..bab5da8313 --- /dev/null +++ b/crypto/bn256/cloudflare/mul_amd64.h @@ -0,0 +1,181 @@ +#define mul(a0,a1,a2,a3, rb, stack) \ + MOVQ a0, AX \ + MULQ 0+rb \ + MOVQ AX, R8 \ + MOVQ DX, R9 \ + MOVQ a0, AX \ + MULQ 8+rb \ + ADDQ AX, R9 \ + ADCQ $0, DX \ + MOVQ DX, R10 \ + MOVQ a0, AX \ + MULQ 16+rb \ + ADDQ AX, R10 \ + ADCQ $0, DX \ + MOVQ DX, R11 \ + MOVQ a0, AX \ + MULQ 24+rb \ + ADDQ AX, R11 \ + ADCQ $0, DX \ + MOVQ DX, R12 \ + \ + storeBlock(R8,R9,R10,R11, 0+stack) \ + MOVQ R12, 32+stack \ + \ + MOVQ a1, AX \ + MULQ 0+rb \ + MOVQ AX, R8 \ + MOVQ DX, R9 \ + MOVQ a1, AX \ + MULQ 8+rb \ + ADDQ AX, R9 \ + ADCQ $0, DX \ + MOVQ DX, R10 \ + MOVQ a1, AX \ + MULQ 16+rb \ + ADDQ AX, R10 \ + ADCQ $0, DX \ + MOVQ DX, R11 \ + MOVQ a1, AX \ + MULQ 24+rb \ + ADDQ AX, R11 \ + ADCQ $0, DX \ + MOVQ DX, R12 \ + \ + ADDQ 8+stack, R8 \ + ADCQ 16+stack, R9 \ + ADCQ 24+stack, R10 \ + ADCQ 32+stack, R11 \ + ADCQ $0, R12 \ + storeBlock(R8,R9,R10,R11, 8+stack) \ + MOVQ R12, 40+stack \ + \ + MOVQ a2, AX \ + MULQ 0+rb \ + MOVQ AX, R8 \ + MOVQ DX, R9 \ + MOVQ a2, AX \ + MULQ 8+rb \ + ADDQ AX, R9 \ + ADCQ $0, DX \ + MOVQ DX, R10 \ + MOVQ a2, AX \ + MULQ 16+rb \ + ADDQ AX, R10 \ + ADCQ $0, DX \ + MOVQ DX, R11 \ + MOVQ a2, AX \ + MULQ 24+rb \ + ADDQ AX, R11 \ + ADCQ $0, DX \ + MOVQ DX, R12 \ + \ + ADDQ 16+stack, R8 \ + ADCQ 24+stack, R9 \ + ADCQ 32+stack, R10 \ + ADCQ 40+stack, R11 \ + ADCQ $0, R12 \ + storeBlock(R8,R9,R10,R11, 16+stack) \ + MOVQ R12, 48+stack \ + \ + MOVQ a3, AX \ + MULQ 0+rb \ + MOVQ AX, R8 \ + MOVQ DX, R9 \ + MOVQ a3, AX \ + MULQ 8+rb \ + ADDQ AX, R9 \ + ADCQ $0, DX \ + MOVQ DX, R10 \ + MOVQ a3, AX \ + MULQ 16+rb \ + ADDQ AX, R10 \ + ADCQ $0, DX \ + MOVQ DX, R11 \ + MOVQ a3, AX \ + MULQ 24+rb \ + ADDQ AX, R11 \ + ADCQ $0, DX \ + MOVQ DX, R12 \ + \ + ADDQ 24+stack, R8 \ + ADCQ 32+stack, R9 \ + ADCQ 40+stack, R10 \ + ADCQ 48+stack, R11 \ + ADCQ $0, R12 \ + storeBlock(R8,R9,R10,R11, 24+stack) \ + MOVQ R12, 56+stack + +#define gfpReduce(stack) \ + \ // m = (T * N') mod R, store m in R8:R9:R10:R11 + MOVQ ·np+0(SB), AX \ + MULQ 0+stack \ + MOVQ AX, R8 \ + MOVQ DX, R9 \ + MOVQ ·np+0(SB), AX \ + MULQ 8+stack \ + ADDQ AX, R9 \ + ADCQ $0, DX \ + MOVQ DX, R10 \ + MOVQ ·np+0(SB), AX \ + MULQ 16+stack \ + ADDQ AX, R10 \ + ADCQ $0, DX \ + MOVQ DX, R11 \ + MOVQ ·np+0(SB), AX \ + MULQ 24+stack \ + ADDQ AX, R11 \ + \ + MOVQ ·np+8(SB), AX \ + MULQ 0+stack \ + MOVQ AX, R12 \ + MOVQ DX, R13 \ + MOVQ ·np+8(SB), AX \ + MULQ 8+stack \ + ADDQ AX, R13 \ + ADCQ $0, DX \ + MOVQ DX, R14 \ + MOVQ ·np+8(SB), AX \ + MULQ 16+stack \ + ADDQ AX, R14 \ + \ + ADDQ R12, R9 \ + ADCQ R13, R10 \ + ADCQ R14, R11 \ + \ + MOVQ ·np+16(SB), AX \ + MULQ 0+stack \ + MOVQ AX, R12 \ + MOVQ DX, R13 \ + MOVQ ·np+16(SB), AX \ + MULQ 8+stack \ + ADDQ AX, R13 \ + \ + ADDQ R12, R10 \ + ADCQ R13, R11 \ + \ + MOVQ ·np+24(SB), AX \ + MULQ 0+stack \ + ADDQ AX, R11 \ + \ + storeBlock(R8,R9,R10,R11, 64+stack) \ + \ + \ // m * N + mul(·p2+0(SB),·p2+8(SB),·p2+16(SB),·p2+24(SB), 64+stack, 96+stack) \ + \ + \ // Add the 512-bit intermediate to m*N + loadBlock(96+stack, R8,R9,R10,R11) \ + loadBlock(128+stack, R12,R13,R14,R15) \ + \ + MOVQ $0, AX \ + ADDQ 0+stack, R8 \ + ADCQ 8+stack, R9 \ + ADCQ 16+stack, R10 \ + ADCQ 24+stack, R11 \ + ADCQ 32+stack, R12 \ + ADCQ 40+stack, R13 \ + ADCQ 48+stack, R14 \ + ADCQ 56+stack, R15 \ + ADCQ $0, AX \ + \ + gfpCarry(R12,R13,R14,R15,AX, R8,R9,R10,R11,BX) diff --git a/crypto/bn256/cloudflare/mul_arm64.h b/crypto/bn256/cloudflare/mul_arm64.h new file mode 100644 index 0000000000..d405eb8f72 --- /dev/null +++ b/crypto/bn256/cloudflare/mul_arm64.h @@ -0,0 +1,133 @@ +#define mul(c0,c1,c2,c3,c4,c5,c6,c7) \ + MUL R1, R5, c0 \ + UMULH R1, R5, c1 \ + MUL R1, R6, R0 \ + ADDS R0, c1 \ + UMULH R1, R6, c2 \ + MUL R1, R7, R0 \ + ADCS R0, c2 \ + UMULH R1, R7, c3 \ + MUL R1, R8, R0 \ + ADCS R0, c3 \ + UMULH R1, R8, c4 \ + ADCS ZR, c4 \ + \ + MUL R2, R5, R1 \ + UMULH R2, R5, R26 \ + MUL R2, R6, R0 \ + ADDS R0, R26 \ + UMULH R2, R6, R27 \ + MUL R2, R7, R0 \ + ADCS R0, R27 \ + UMULH R2, R7, R29 \ + MUL R2, R8, R0 \ + ADCS R0, R29 \ + UMULH R2, R8, c5 \ + ADCS ZR, c5 \ + ADDS R1, c1 \ + ADCS R26, c2 \ + ADCS R27, c3 \ + ADCS R29, c4 \ + ADCS ZR, c5 \ + \ + MUL R3, R5, R1 \ + UMULH R3, R5, R26 \ + MUL R3, R6, R0 \ + ADDS R0, R26 \ + UMULH R3, R6, R27 \ + MUL R3, R7, R0 \ + ADCS R0, R27 \ + UMULH R3, R7, R29 \ + MUL R3, R8, R0 \ + ADCS R0, R29 \ + UMULH R3, R8, c6 \ + ADCS ZR, c6 \ + ADDS R1, c2 \ + ADCS R26, c3 \ + ADCS R27, c4 \ + ADCS R29, c5 \ + ADCS ZR, c6 \ + \ + MUL R4, R5, R1 \ + UMULH R4, R5, R26 \ + MUL R4, R6, R0 \ + ADDS R0, R26 \ + UMULH R4, R6, R27 \ + MUL R4, R7, R0 \ + ADCS R0, R27 \ + UMULH R4, R7, R29 \ + MUL R4, R8, R0 \ + ADCS R0, R29 \ + UMULH R4, R8, c7 \ + ADCS ZR, c7 \ + ADDS R1, c3 \ + ADCS R26, c4 \ + ADCS R27, c5 \ + ADCS R29, c6 \ + ADCS ZR, c7 + +#define gfpReduce() \ + \ // m = (T * N') mod R, store m in R1:R2:R3:R4 + MOVD ·np+0(SB), R17 \ + 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, R25, R0 \ + ADDS R0, R2 \ + UMULH R9, R25, R3 \ + MUL R9, R19, R0 \ + ADCS R0, R3 \ + UMULH R9, R19, R4 \ + MUL R9, R20, R0 \ + ADCS R0, R4 \ + \ + MUL R10, R17, R21 \ + UMULH R10, R17, R22 \ + MUL R10, R25, R0 \ + ADDS R0, R22 \ + UMULH R10, R25, R23 \ + MUL R10, R19, R0 \ + ADCS R0, R23 \ + ADDS R21, R2 \ + ADCS R22, R3 \ + ADCS R23, R4 \ + \ + MUL R11, R17, R21 \ + UMULH R11, R17, R22 \ + MUL R11, R25, R0 \ + ADDS R0, R22 \ + ADDS R21, R3 \ + ADCS R22, R4 \ + \ + MUL R12, R17, R21 \ + ADDS R21, R4 \ + \ + \ // m * N + loadModulus(R5,R6,R7,R8) \ + mul(R17,R25,R19,R20,R21,R22,R23,R24) \ + \ + \ // Add the 512-bit intermediate to m*N + MOVD ZR, R0 \ + ADDS R9, R17 \ + ADCS R10, R25 \ + ADCS R11, R19 \ + ADCS R12, R20 \ + ADCS R13, R21 \ + ADCS R14, R22 \ + ADCS R15, R23 \ + ADCS R16, R24 \ + ADCS ZR, R0 \ + \ + \ // Our output is R21:R22:R23:R24. Reduce mod p if necessary. + SUBS R5, R21, R10 \ + SBCS R6, R22, R11 \ + SBCS R7, R23, R12 \ + SBCS R8, R24, R13 \ + \ + CSEL CS, R10, R21, R1 \ + CSEL CS, R11, R22, R2 \ + CSEL CS, R12, R23, R3 \ + CSEL CS, R13, R24, R4 diff --git a/crypto/bn256/cloudflare/mul_bmi2_amd64.h b/crypto/bn256/cloudflare/mul_bmi2_amd64.h new file mode 100644 index 0000000000..71ad0499af --- /dev/null +++ b/crypto/bn256/cloudflare/mul_bmi2_amd64.h @@ -0,0 +1,112 @@ +#define mulBMI2(a0,a1,a2,a3, rb) \ + MOVQ a0, DX \ + MOVQ $0, R13 \ + MULXQ 0+rb, R8, R9 \ + MULXQ 8+rb, AX, R10 \ + ADDQ AX, R9 \ + MULXQ 16+rb, AX, R11 \ + ADCQ AX, R10 \ + MULXQ 24+rb, AX, R12 \ + ADCQ AX, R11 \ + ADCQ $0, R12 \ + ADCQ $0, R13 \ + \ + MOVQ a1, DX \ + MOVQ $0, R14 \ + MULXQ 0+rb, AX, BX \ + ADDQ AX, R9 \ + ADCQ BX, R10 \ + MULXQ 16+rb, AX, BX \ + ADCQ AX, R11 \ + ADCQ BX, R12 \ + ADCQ $0, R13 \ + MULXQ 8+rb, AX, BX \ + ADDQ AX, R10 \ + ADCQ BX, R11 \ + MULXQ 24+rb, AX, BX \ + ADCQ AX, R12 \ + ADCQ BX, R13 \ + ADCQ $0, R14 \ + \ + MOVQ a2, DX \ + MOVQ $0, R15 \ + MULXQ 0+rb, AX, BX \ + ADDQ AX, R10 \ + ADCQ BX, R11 \ + MULXQ 16+rb, AX, BX \ + ADCQ AX, R12 \ + ADCQ BX, R13 \ + ADCQ $0, R14 \ + MULXQ 8+rb, AX, BX \ + ADDQ AX, R11 \ + ADCQ BX, R12 \ + MULXQ 24+rb, AX, BX \ + ADCQ AX, R13 \ + ADCQ BX, R14 \ + ADCQ $0, R15 \ + \ + MOVQ a3, DX \ + MULXQ 0+rb, AX, BX \ + ADDQ AX, R11 \ + ADCQ BX, R12 \ + MULXQ 16+rb, AX, BX \ + ADCQ AX, R13 \ + ADCQ BX, R14 \ + ADCQ $0, R15 \ + MULXQ 8+rb, AX, BX \ + ADDQ AX, R12 \ + ADCQ BX, R13 \ + MULXQ 24+rb, AX, BX \ + ADCQ AX, R14 \ + ADCQ BX, R15 + +#define gfpReduceBMI2() \ + \ // m = (T * N') mod R, store m in R8:R9:R10:R11 + MOVQ ·np+0(SB), DX \ + MULXQ 0(SP), R8, R9 \ + MULXQ 8(SP), AX, R10 \ + ADDQ AX, R9 \ + MULXQ 16(SP), AX, R11 \ + ADCQ AX, R10 \ + MULXQ 24(SP), AX, BX \ + ADCQ AX, R11 \ + \ + MOVQ ·np+8(SB), DX \ + MULXQ 0(SP), AX, BX \ + ADDQ AX, R9 \ + ADCQ BX, R10 \ + MULXQ 16(SP), AX, BX \ + ADCQ AX, R11 \ + MULXQ 8(SP), AX, BX \ + ADDQ AX, R10 \ + ADCQ BX, R11 \ + \ + MOVQ ·np+16(SB), DX \ + MULXQ 0(SP), AX, BX \ + ADDQ AX, R10 \ + ADCQ BX, R11 \ + MULXQ 8(SP), AX, BX \ + ADDQ AX, R11 \ + \ + MOVQ ·np+24(SB), DX \ + MULXQ 0(SP), AX, BX \ + ADDQ AX, R11 \ + \ + storeBlock(R8,R9,R10,R11, 64(SP)) \ + \ + \ // m * N + mulBMI2(·p2+0(SB),·p2+8(SB),·p2+16(SB),·p2+24(SB), 64(SP)) \ + \ + \ // Add the 512-bit intermediate to m*N + MOVQ $0, AX \ + ADDQ 0(SP), R8 \ + ADCQ 8(SP), R9 \ + ADCQ 16(SP), R10 \ + ADCQ 24(SP), R11 \ + ADCQ 32(SP), R12 \ + ADCQ 40(SP), R13 \ + ADCQ 48(SP), R14 \ + ADCQ 56(SP), R15 \ + ADCQ $0, AX \ + \ + gfpCarry(R12,R13,R14,R15,AX, R8,R9,R10,R11,BX) diff --git a/crypto/bn256/cloudflare/optate.go b/crypto/bn256/cloudflare/optate.go new file mode 100644 index 0000000000..b71e50e3a2 --- /dev/null +++ b/crypto/bn256/cloudflare/optate.go @@ -0,0 +1,271 @@ +package bn256 + +func lineFunctionAdd(r, p *twistPoint, q *curvePoint, r2 *gfP2) (a, b, c *gfP2, rOut *twistPoint) { + // See the mixed addition algorithm from "Faster Computation of the + // Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf + B := (&gfP2{}).Mul(&p.x, &r.t) + + D := (&gfP2{}).Add(&p.y, &r.z) + D.Square(D).Sub(D, r2).Sub(D, &r.t).Mul(D, &r.t) + + H := (&gfP2{}).Sub(B, &r.x) + I := (&gfP2{}).Square(H) + + E := (&gfP2{}).Add(I, I) + E.Add(E, E) + + J := (&gfP2{}).Mul(H, E) + + L1 := (&gfP2{}).Sub(D, &r.y) + L1.Sub(L1, &r.y) + + V := (&gfP2{}).Mul(&r.x, E) + + rOut = &twistPoint{} + rOut.x.Square(L1).Sub(&rOut.x, J).Sub(&rOut.x, V).Sub(&rOut.x, V) + + rOut.z.Add(&r.z, H).Square(&rOut.z).Sub(&rOut.z, &r.t).Sub(&rOut.z, I) + + t := (&gfP2{}).Sub(V, &rOut.x) + t.Mul(t, L1) + t2 := (&gfP2{}).Mul(&r.y, J) + t2.Add(t2, t2) + rOut.y.Sub(t, t2) + + rOut.t.Square(&rOut.z) + + t.Add(&p.y, &rOut.z).Square(t).Sub(t, r2).Sub(t, &rOut.t) + + t2.Mul(L1, &p.x) + t2.Add(t2, t2) + a = (&gfP2{}).Sub(t2, t) + + c = (&gfP2{}).MulScalar(&rOut.z, &q.y) + c.Add(c, c) + + b = (&gfP2{}).Neg(L1) + b.MulScalar(b, &q.x).Add(b, b) + + return +} + +func lineFunctionDouble(r *twistPoint, q *curvePoint) (a, b, c *gfP2, rOut *twistPoint) { + // See the doubling algorithm for a=0 from "Faster Computation of the + // Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf + A := (&gfP2{}).Square(&r.x) + B := (&gfP2{}).Square(&r.y) + C := (&gfP2{}).Square(B) + + D := (&gfP2{}).Add(&r.x, B) + D.Square(D).Sub(D, A).Sub(D, C).Add(D, D) + + E := (&gfP2{}).Add(A, A) + E.Add(E, A) + + G := (&gfP2{}).Square(E) + + rOut = &twistPoint{} + rOut.x.Sub(G, D).Sub(&rOut.x, D) + + rOut.z.Add(&r.y, &r.z).Square(&rOut.z).Sub(&rOut.z, B).Sub(&rOut.z, &r.t) + + rOut.y.Sub(D, &rOut.x).Mul(&rOut.y, E) + t := (&gfP2{}).Add(C, C) + t.Add(t, t).Add(t, t) + rOut.y.Sub(&rOut.y, t) + + rOut.t.Square(&rOut.z) + + t.Mul(E, &r.t).Add(t, t) + b = (&gfP2{}).Neg(t) + b.MulScalar(b, &q.x) + + a = (&gfP2{}).Add(&r.x, E) + a.Square(a).Sub(a, A).Sub(a, G) + t.Add(B, B).Add(t, t) + a.Sub(a, t) + + c = (&gfP2{}).Mul(&rOut.z, &r.t) + c.Add(c, c).MulScalar(c, &q.y) + + return +} + +func mulLine(ret *gfP12, a, b, c *gfP2) { + a2 := &gfP6{} + a2.y.Set(a) + a2.z.Set(b) + a2.Mul(a2, &ret.x) + t3 := (&gfP6{}).MulScalar(&ret.y, c) + + t := (&gfP2{}).Add(b, c) + t2 := &gfP6{} + t2.y.Set(a) + t2.z.Set(t) + ret.x.Add(&ret.x, &ret.y) + + ret.y.Set(t3) + + ret.x.Mul(&ret.x, t2).Sub(&ret.x, a2).Sub(&ret.x, &ret.y) + a2.MulTau(a2) + ret.y.Add(&ret.y, a2) +} + +// sixuPlus2NAF is 6u+2 in non-adjacent form. +var sixuPlus2NAF = []int8{0, 0, 0, 1, 0, 1, 0, -1, 0, 0, 1, -1, 0, 0, 1, 0, + 0, 1, 1, 0, -1, 0, 0, 1, 0, -1, 0, 0, 0, 0, 1, 1, + 1, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 1, + 1, 0, 0, -1, 0, 0, 0, 1, 1, 0, -1, 0, 0, 1, 0, 1, 1} + +// miller implements the Miller loop for calculating the Optimal Ate pairing. +// See algorithm 1 from http://cryptojedi.org/papers/dclxvi-20100714.pdf +func miller(q *twistPoint, p *curvePoint) *gfP12 { + ret := (&gfP12{}).SetOne() + + aAffine := &twistPoint{} + aAffine.Set(q) + aAffine.MakeAffine() + + bAffine := &curvePoint{} + bAffine.Set(p) + bAffine.MakeAffine() + + minusA := &twistPoint{} + minusA.Neg(aAffine) + + r := &twistPoint{} + r.Set(aAffine) + + r2 := (&gfP2{}).Square(&aAffine.y) + + for i := len(sixuPlus2NAF) - 1; i > 0; i-- { + a, b, c, newR := lineFunctionDouble(r, bAffine) + if i != len(sixuPlus2NAF)-1 { + ret.Square(ret) + } + + mulLine(ret, a, b, c) + r = newR + + switch sixuPlus2NAF[i-1] { + case 1: + a, b, c, newR = lineFunctionAdd(r, aAffine, bAffine, r2) + case -1: + a, b, c, newR = lineFunctionAdd(r, minusA, bAffine, r2) + default: + continue + } + + mulLine(ret, a, b, c) + r = newR + } + + // In order to calculate Q1 we have to convert q from the sextic twist + // to the full GF(p^12) group, apply the Frobenius there, and convert + // back. + // + // The twist isomorphism is (x', y') -> (xω², yω³). If we consider just + // x for a moment, then after applying the Frobenius, we have x̄ω^(2p) + // where x̄ is the conjugate of x. If we are going to apply the inverse + // isomorphism we need a value with a single coefficient of ω² so we + // rewrite this as x̄ω^(2p-2)ω². ξ⁶ = ω and, due to the construction of + // p, 2p-2 is a multiple of six. Therefore we can rewrite as + // x̄ξ^((p-1)/3)ω² and applying the inverse isomorphism eliminates the + // ω². + // + // A similar argument can be made for the y value. + + q1 := &twistPoint{} + q1.x.Conjugate(&aAffine.x).Mul(&q1.x, xiToPMinus1Over3) + q1.y.Conjugate(&aAffine.y).Mul(&q1.y, xiToPMinus1Over2) + q1.z.SetOne() + q1.t.SetOne() + + // For Q2 we are applying the p² Frobenius. The two conjugations cancel + // out and we are left only with the factors from the isomorphism. In + // the case of x, we end up with a pure number which is why + // xiToPSquaredMinus1Over3 is ∈ GF(p). With y we get a factor of -1. We + // ignore this to end up with -Q2. + + minusQ2 := &twistPoint{} + minusQ2.x.MulScalar(&aAffine.x, xiToPSquaredMinus1Over3) + minusQ2.y.Set(&aAffine.y) + minusQ2.z.SetOne() + minusQ2.t.SetOne() + + r2.Square(&q1.y) + a, b, c, newR := lineFunctionAdd(r, q1, bAffine, r2) + mulLine(ret, a, b, c) + r = newR + + r2.Square(&minusQ2.y) + a, b, c, newR = lineFunctionAdd(r, minusQ2, bAffine, r2) + mulLine(ret, a, b, c) + r = newR + + return ret +} + +// finalExponentiation computes the (p¹²-1)/Order-th power of an element of +// GF(p¹²) to obtain an element of GT (steps 13-15 of algorithm 1 from +// http://cryptojedi.org/papers/dclxvi-20100714.pdf) +func finalExponentiation(in *gfP12) *gfP12 { + t1 := &gfP12{} + + // This is the p^6-Frobenius + t1.x.Neg(&in.x) + t1.y.Set(&in.y) + + inv := &gfP12{} + inv.Invert(in) + t1.Mul(t1, inv) + + t2 := (&gfP12{}).FrobeniusP2(t1) + t1.Mul(t1, t2) + + fp := (&gfP12{}).Frobenius(t1) + fp2 := (&gfP12{}).FrobeniusP2(t1) + fp3 := (&gfP12{}).Frobenius(fp2) + + fu := (&gfP12{}).Exp(t1, u) + fu2 := (&gfP12{}).Exp(fu, u) + fu3 := (&gfP12{}).Exp(fu2, u) + + y3 := (&gfP12{}).Frobenius(fu) + fu2p := (&gfP12{}).Frobenius(fu2) + fu3p := (&gfP12{}).Frobenius(fu3) + y2 := (&gfP12{}).FrobeniusP2(fu2) + + y0 := &gfP12{} + y0.Mul(fp, fp2).Mul(y0, fp3) + + y1 := (&gfP12{}).Conjugate(t1) + y5 := (&gfP12{}).Conjugate(fu2) + y3.Conjugate(y3) + y4 := (&gfP12{}).Mul(fu, fu2p) + y4.Conjugate(y4) + + y6 := (&gfP12{}).Mul(fu3, fu3p) + y6.Conjugate(y6) + + t0 := (&gfP12{}).Square(y6) + t0.Mul(t0, y4).Mul(t0, y5) + t1.Mul(y3, y5).Mul(t1, t0) + t0.Mul(t0, y2) + t1.Square(t1).Mul(t1, t0).Square(t1) + t0.Mul(t1, y1) + t1.Mul(t1, y0) + t0.Square(t0).Mul(t0, t1) + + return t0 +} + +func optimalAte(a *twistPoint, b *curvePoint) *gfP12 { + e := miller(a, b) + ret := finalExponentiation(e) + + if a.IsInfinity() || b.IsInfinity() { + ret.SetOne() + } + return ret +} diff --git a/crypto/bn256/cloudflare/twist.go b/crypto/bn256/cloudflare/twist.go new file mode 100644 index 0000000000..0c2f80d4ed --- /dev/null +++ b/crypto/bn256/cloudflare/twist.go @@ -0,0 +1,204 @@ +package bn256 + +import ( + "math/big" +) + +// twistPoint implements the elliptic curve y²=x³+3/ξ over GF(p²). Points are +// kept in Jacobian form and t=z² when valid. The group G₂ is the set of +// n-torsion points of this curve over GF(p²) (where n = Order) +type twistPoint struct { + x, y, z, t gfP2 +} + +var twistB = &gfP2{ + gfP{0x38e7ecccd1dcff67, 0x65f0b37d93ce0d3e, 0xd749d0dd22ac00aa, 0x0141b9ce4a688d4d}, + gfP{0x3bf938e377b802a8, 0x020b1b273633535d, 0x26b7edf049755260, 0x2514c6324384a86d}, +} + +// twistGen is the generator of group G₂. +var twistGen = &twistPoint{ + gfP2{ + gfP{0xafb4737da84c6140, 0x6043dd5a5802d8c4, 0x09e950fc52a02f86, 0x14fef0833aea7b6b}, + gfP{0x8e83b5d102bc2026, 0xdceb1935497b0172, 0xfbb8264797811adf, 0x19573841af96503b}, + }, + gfP2{ + gfP{0x64095b56c71856ee, 0xdc57f922327d3cbb, 0x55f935be33351076, 0x0da4a0e693fd6482}, + gfP{0x619dfa9d886be9f6, 0xfe7fd297f59e9b78, 0xff9e1a62231b7dfe, 0x28fd7eebae9e4206}, + }, + gfP2{*newGFp(0), *newGFp(1)}, + gfP2{*newGFp(0), *newGFp(1)}, +} + +func (c *twistPoint) String() string { + c.MakeAffine() + x, y := gfP2Decode(&c.x), gfP2Decode(&c.y) + return "(" + x.String() + ", " + y.String() + ")" +} + +func (c *twistPoint) Set(a *twistPoint) { + c.x.Set(&a.x) + c.y.Set(&a.y) + c.z.Set(&a.z) + c.t.Set(&a.t) +} + +// IsOnCurve returns true iff c is on the curve. +func (c *twistPoint) IsOnCurve() bool { + c.MakeAffine() + if c.IsInfinity() { + return true + } + + y2, x3 := &gfP2{}, &gfP2{} + y2.Square(&c.y) + x3.Square(&c.x).Mul(x3, &c.x).Add(x3, twistB) + + if *y2 != *x3 { + return false + } + cneg := &twistPoint{} + cneg.Mul(c, Order) + return cneg.z.IsZero() +} + +func (c *twistPoint) SetInfinity() { + c.x.SetZero() + c.y.SetOne() + c.z.SetZero() + c.t.SetZero() +} + +func (c *twistPoint) IsInfinity() bool { + return c.z.IsZero() +} + +func (c *twistPoint) Add(a, b *twistPoint) { + // For additional comments, see the same function in curve.go. + + if a.IsInfinity() { + c.Set(b) + return + } + if b.IsInfinity() { + c.Set(a) + return + } + + // See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3 + z12 := (&gfP2{}).Square(&a.z) + z22 := (&gfP2{}).Square(&b.z) + u1 := (&gfP2{}).Mul(&a.x, z22) + u2 := (&gfP2{}).Mul(&b.x, z12) + + t := (&gfP2{}).Mul(&b.z, z22) + s1 := (&gfP2{}).Mul(&a.y, t) + + t.Mul(&a.z, z12) + s2 := (&gfP2{}).Mul(&b.y, t) + + h := (&gfP2{}).Sub(u2, u1) + xEqual := h.IsZero() + + t.Add(h, h) + i := (&gfP2{}).Square(t) + j := (&gfP2{}).Mul(h, i) + + t.Sub(s2, s1) + yEqual := t.IsZero() + if xEqual && yEqual { + c.Double(a) + return + } + r := (&gfP2{}).Add(t, t) + + v := (&gfP2{}).Mul(u1, i) + + t4 := (&gfP2{}).Square(r) + t.Add(v, v) + t6 := (&gfP2{}).Sub(t4, j) + c.x.Sub(t6, t) + + t.Sub(v, &c.x) // t7 + t4.Mul(s1, j) // t8 + t6.Add(t4, t4) // t9 + t4.Mul(r, t) // t10 + c.y.Sub(t4, t6) + + t.Add(&a.z, &b.z) // t11 + t4.Square(t) // t12 + t.Sub(t4, z12) // t13 + t4.Sub(t, z22) // t14 + c.z.Mul(t4, h) +} + +func (c *twistPoint) Double(a *twistPoint) { + // See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3 + A := (&gfP2{}).Square(&a.x) + B := (&gfP2{}).Square(&a.y) + C := (&gfP2{}).Square(B) + + t := (&gfP2{}).Add(&a.x, B) + t2 := (&gfP2{}).Square(t) + t.Sub(t2, A) + t2.Sub(t, C) + d := (&gfP2{}).Add(t2, t2) + t.Add(A, A) + e := (&gfP2{}).Add(t, A) + f := (&gfP2{}).Square(e) + + t.Add(d, d) + c.x.Sub(f, t) + + t.Add(C, C) + t2.Add(t, t) + t.Add(t2, t2) + c.y.Sub(d, &c.x) + t2.Mul(e, &c.y) + c.y.Sub(t2, t) + + t.Mul(&a.y, &a.z) + c.z.Add(t, t) +} + +func (c *twistPoint) Mul(a *twistPoint, scalar *big.Int) { + sum, t := &twistPoint{}, &twistPoint{} + + for i := scalar.BitLen(); i >= 0; i-- { + t.Double(sum) + if scalar.Bit(i) != 0 { + sum.Add(t, a) + } else { + sum.Set(t) + } + } + + c.Set(sum) +} + +func (c *twistPoint) MakeAffine() { + if c.z.IsOne() { + return + } else if c.z.IsZero() { + c.x.SetZero() + c.y.SetOne() + c.t.SetZero() + return + } + + zInv := (&gfP2{}).Invert(&c.z) + t := (&gfP2{}).Mul(&c.y, zInv) + zInv2 := (&gfP2{}).Square(zInv) + c.y.Mul(t, zInv2) + t.Mul(&c.x, zInv2) + c.x.Set(t) + c.z.SetOne() + c.t.SetOne() +} + +func (c *twistPoint) Neg(a *twistPoint) { + c.x.Set(&a.x) + c.y.Neg(&a.y) + c.z.Set(&a.z) + c.t.SetZero() +} diff --git a/crypto/bn256/bn256.go b/crypto/bn256/google/bn256.go similarity index 84% rename from crypto/bn256/bn256.go rename to crypto/bn256/google/bn256.go index 7144c31a8a..e0402e51f0 100644 --- a/crypto/bn256/bn256.go +++ b/crypto/bn256/google/bn256.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. -// Package bn256 implements a particular bilinear group at the 128-bit security level. +// Package bn256 implements a particular bilinear group. // // Bilinear groups are the basis of many of the new cryptographic protocols // that have been proposed over the past decade. They consist of a triplet of @@ -14,10 +14,15 @@ // Barreto-Naehrig curve as described in // http://cryptojedi.org/papers/dclxvi-20100714.pdf. Its output is compatible // with the implementation described in that paper. +// +// (This package previously claimed to operate at a 128-bit security level. +// However, recent improvements in attacks mean that is no longer true. See +// https://moderncrypto.org/mail-archive/curves/2016/000740.html.) package bn256 import ( "crypto/rand" + "errors" "io" "math/big" ) @@ -49,8 +54,8 @@ func RandomG1(r io.Reader) (*big.Int, *G1, error) { return k, new(G1).ScalarBaseMult(k), nil } -func (g *G1) String() string { - return "bn256.G1" + g.p.String() +func (e *G1) String() string { + return "bn256.G1" + e.p.String() } // CurvePoints returns p's curve points in big integer @@ -97,15 +102,19 @@ func (e *G1) Neg(a *G1) *G1 { } // Marshal converts n to a byte slice. -func (n *G1) Marshal() []byte { - n.p.MakeAffine(nil) - - xBytes := new(big.Int).Mod(n.p.x, P).Bytes() - yBytes := new(big.Int).Mod(n.p.y, P).Bytes() - +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() + ret := make([]byte, numBytes*2) copy(ret[1*numBytes-len(xBytes):], xBytes) copy(ret[2*numBytes-len(yBytes):], yBytes) @@ -115,21 +124,25 @@ func (n *G1) Marshal() []byte { // Unmarshal sets e to the result of converting the output of Marshal back into // a group element and then returns e. -func (e *G1) Unmarshal(m []byte) (*G1, bool) { +func (e *G1) Unmarshal(m []byte) ([]byte, error) { // Each value is a 256-bit number. const numBytes = 256 / 8 - if len(m) != 2*numBytes { - return nil, false + return nil, errors.New("bn256: not enough data") } - + // Unmarshal the points and check their caps if e.p == nil { e.p = newCurvePoint(nil) } - e.p.x.SetBytes(m[0*numBytes : 1*numBytes]) + if e.p.x.Cmp(P) >= 0 { + return nil, errors.New("bn256: coordinate exceeds modulus") + } e.p.y.SetBytes(m[1*numBytes : 2*numBytes]) - + if e.p.y.Cmp(P) >= 0 { + return nil, errors.New("bn256: coordinate exceeds modulus") + } + // Ensure the point is on the curve if e.p.x.Sign() == 0 && e.p.y.Sign() == 0 { // This is the point at infinity. e.p.y.SetInt64(1) @@ -140,11 +153,10 @@ func (e *G1) Unmarshal(m []byte) (*G1, bool) { e.p.t.SetInt64(1) if !e.p.IsOnCurve() { - return nil, false + return nil, errors.New("bn256: malformed point") } } - - return e, true + return m[2*numBytes:], nil } // G2 is an abstract cyclic group. The zero value is suitable for use as the @@ -171,8 +183,8 @@ func RandomG2(r io.Reader) (*big.Int, *G2, error) { return k, new(G2).ScalarBaseMult(k), nil } -func (g *G2) String() string { - return "bn256.G2" + g.p.String() +func (e *G2) String() string { + return "bn256.G2" + e.p.String() } // CurvePoints returns the curve points of p which includes the real @@ -212,6 +224,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() @@ -219,9 +238,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) @@ -233,23 +249,33 @@ func (n *G2) Marshal() []byte { // Unmarshal sets e to the result of converting the output of Marshal back into // a group element and then returns e. -func (e *G2) Unmarshal(m []byte) (*G2, bool) { +func (e *G2) Unmarshal(m []byte) ([]byte, error) { // Each value is a 256-bit number. const numBytes = 256 / 8 - if len(m) != 4*numBytes { - return nil, false + return nil, errors.New("bn256: not enough data") } - + // Unmarshal the points and check their caps if e.p == nil { e.p = newTwistPoint(nil) } - e.p.x.x.SetBytes(m[0*numBytes : 1*numBytes]) + if e.p.x.x.Cmp(P) >= 0 { + return nil, errors.New("bn256: coordinate exceeds modulus") + } e.p.x.y.SetBytes(m[1*numBytes : 2*numBytes]) + if e.p.x.y.Cmp(P) >= 0 { + return nil, errors.New("bn256: coordinate exceeds modulus") + } e.p.y.x.SetBytes(m[2*numBytes : 3*numBytes]) + if e.p.y.x.Cmp(P) >= 0 { + return nil, errors.New("bn256: coordinate exceeds modulus") + } e.p.y.y.SetBytes(m[3*numBytes : 4*numBytes]) - + if e.p.y.y.Cmp(P) >= 0 { + return nil, errors.New("bn256: coordinate exceeds modulus") + } + // Ensure the point is on the curve if e.p.x.x.Sign() == 0 && e.p.x.y.Sign() == 0 && e.p.y.x.Sign() == 0 && @@ -263,11 +289,10 @@ func (e *G2) Unmarshal(m []byte) (*G2, bool) { e.p.t.SetOne() if !e.p.IsOnCurve() { - return nil, false + return nil, errors.New("bn256: malformed point") } } - - return e, true + return m[4*numBytes:], nil } // GT is an abstract cyclic group. The zero value is suitable for use as the diff --git a/crypto/bn256/bn256_test.go b/crypto/bn256/google/bn256_test.go similarity index 90% rename from crypto/bn256/bn256_test.go rename to crypto/bn256/google/bn256_test.go index 866065d0ca..a4497ada9b 100644 --- a/crypto/bn256/bn256_test.go +++ b/crypto/bn256/google/bn256_test.go @@ -219,15 +219,16 @@ func TestBilinearity(t *testing.T) { func TestG1Marshal(t *testing.T) { g := new(G1).ScalarBaseMult(new(big.Int).SetInt64(1)) form := g.Marshal() - _, ok := new(G1).Unmarshal(form) - if !ok { + _, err := new(G1).Unmarshal(form) + if err != nil { t.Fatalf("failed to unmarshal") } g.ScalarBaseMult(Order) form = g.Marshal() - g2, ok := new(G1).Unmarshal(form) - if !ok { + + g2 := new(G1) + if _, err = g2.Unmarshal(form); err != nil { t.Fatalf("failed to unmarshal ∞") } if !g2.p.IsInfinity() { @@ -238,15 +239,15 @@ func TestG1Marshal(t *testing.T) { func TestG2Marshal(t *testing.T) { g := new(G2).ScalarBaseMult(new(big.Int).SetInt64(1)) form := g.Marshal() - _, ok := new(G2).Unmarshal(form) - if !ok { + _, err := new(G2).Unmarshal(form) + if err != nil { t.Fatalf("failed to unmarshal") } g.ScalarBaseMult(Order) form = g.Marshal() - g2, ok := new(G2).Unmarshal(form) - if !ok { + g2 := new(G2) + if _, err = g2.Unmarshal(form); err != nil { t.Fatalf("failed to unmarshal ∞") } if !g2.p.IsInfinity() { @@ -273,12 +274,18 @@ func TestTripartiteDiffieHellman(t *testing.T) { b, _ := rand.Int(rand.Reader, Order) c, _ := rand.Int(rand.Reader, Order) - pa, _ := new(G1).Unmarshal(new(G1).ScalarBaseMult(a).Marshal()) - qa, _ := new(G2).Unmarshal(new(G2).ScalarBaseMult(a).Marshal()) - pb, _ := new(G1).Unmarshal(new(G1).ScalarBaseMult(b).Marshal()) - qb, _ := new(G2).Unmarshal(new(G2).ScalarBaseMult(b).Marshal()) - pc, _ := new(G1).Unmarshal(new(G1).ScalarBaseMult(c).Marshal()) - qc, _ := new(G2).Unmarshal(new(G2).ScalarBaseMult(c).Marshal()) + pa := new(G1) + pa.Unmarshal(new(G1).ScalarBaseMult(a).Marshal()) + qa := new(G2) + qa.Unmarshal(new(G2).ScalarBaseMult(a).Marshal()) + pb := new(G1) + pb.Unmarshal(new(G1).ScalarBaseMult(b).Marshal()) + qb := new(G2) + qb.Unmarshal(new(G2).ScalarBaseMult(b).Marshal()) + pc := new(G1) + pc.Unmarshal(new(G1).ScalarBaseMult(c).Marshal()) + qc := new(G2) + qc.Unmarshal(new(G2).ScalarBaseMult(c).Marshal()) k1 := Pair(pb, qc) k1.ScalarMult(k1, a) diff --git a/crypto/bn256/constants.go b/crypto/bn256/google/constants.go similarity index 100% rename from crypto/bn256/constants.go rename to crypto/bn256/google/constants.go diff --git a/crypto/bn256/curve.go b/crypto/bn256/google/curve.go similarity index 96% rename from crypto/bn256/curve.go rename to crypto/bn256/google/curve.go index 3e679fdc7e..819cb81da7 100644 --- a/crypto/bn256/curve.go +++ b/crypto/bn256/google/curve.go @@ -245,11 +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) t.Mod(t, P) diff --git a/crypto/bn256/example_test.go b/crypto/bn256/google/example_test.go similarity index 100% rename from crypto/bn256/example_test.go rename to crypto/bn256/google/example_test.go diff --git a/crypto/bn256/gfp12.go b/crypto/bn256/google/gfp12.go similarity index 100% rename from crypto/bn256/gfp12.go rename to crypto/bn256/google/gfp12.go diff --git a/crypto/bn256/gfp2.go b/crypto/bn256/google/gfp2.go similarity index 100% rename from crypto/bn256/gfp2.go rename to crypto/bn256/google/gfp2.go diff --git a/crypto/bn256/gfp6.go b/crypto/bn256/google/gfp6.go similarity index 100% rename from crypto/bn256/gfp6.go rename to crypto/bn256/google/gfp6.go diff --git a/crypto/bn256/google/main_test.go b/crypto/bn256/google/main_test.go new file mode 100644 index 0000000000..c0c85457be --- /dev/null +++ b/crypto/bn256/google/main_test.go @@ -0,0 +1,71 @@ +package bn256 + +import ( + "testing" + + "crypto/rand" +) + +func TestRandomG2Marshal(t *testing.T) { + for i := 0; i < 10; i++ { + n, g2, err := RandomG2(rand.Reader) + if err != nil { + t.Error(err) + continue + } + t.Logf("%v: %x\n", n, g2.Marshal()) + } +} + +func TestPairings(t *testing.T) { + a1 := new(G1).ScalarBaseMult(bigFromBase10("1")) + a2 := new(G1).ScalarBaseMult(bigFromBase10("2")) + a37 := new(G1).ScalarBaseMult(bigFromBase10("37")) + an1 := new(G1).ScalarBaseMult(bigFromBase10("21888242871839275222246405745257275088548364400416034343698204186575808495616")) + + b0 := new(G2).ScalarBaseMult(bigFromBase10("0")) + b1 := new(G2).ScalarBaseMult(bigFromBase10("1")) + b2 := new(G2).ScalarBaseMult(bigFromBase10("2")) + b27 := new(G2).ScalarBaseMult(bigFromBase10("27")) + b999 := new(G2).ScalarBaseMult(bigFromBase10("999")) + bn1 := new(G2).ScalarBaseMult(bigFromBase10("21888242871839275222246405745257275088548364400416034343698204186575808495616")) + + p1 := Pair(a1, b1) + pn1 := Pair(a1, bn1) + np1 := Pair(an1, b1) + if pn1.String() != np1.String() { + t.Error("Pairing mismatch: e(a, -b) != e(-a, b)") + } + if !PairingCheck([]*G1{a1, an1}, []*G2{b1, b1}) { + t.Error("MultiAte check gave false negative!") + } + p0 := new(GT).Add(p1, pn1) + p0_2 := Pair(a1, b0) + if p0.String() != p0_2.String() { + t.Error("Pairing mismatch: e(a, b) * e(a, -b) != 1") + } + p0_3 := new(GT).ScalarMult(p1, bigFromBase10("21888242871839275222246405745257275088548364400416034343698204186575808495617")) + if p0.String() != p0_3.String() { + t.Error("Pairing mismatch: e(a, b) has wrong order") + } + p2 := Pair(a2, b1) + p2_2 := Pair(a1, b2) + p2_3 := new(GT).ScalarMult(p1, bigFromBase10("2")) + if p2.String() != p2_2.String() { + t.Error("Pairing mismatch: e(a, b * 2) != e(a * 2, b)") + } + if p2.String() != p2_3.String() { + t.Error("Pairing mismatch: e(a, b * 2) != e(a, b) ** 2") + } + if p2.String() == p1.String() { + t.Error("Pairing is degenerate!") + } + if PairingCheck([]*G1{a1, a1}, []*G2{b1, b1}) { + t.Error("MultiAte check gave false positive!") + } + p999 := Pair(a37, b27) + p999_2 := Pair(a1, b999) + if p999.String() != p999_2.String() { + t.Error("Pairing mismatch: e(a * 37, b * 27) != e(a, b * 999)") + } +} diff --git a/crypto/bn256/optate.go b/crypto/bn256/google/optate.go similarity index 100% rename from crypto/bn256/optate.go rename to crypto/bn256/google/optate.go diff --git a/crypto/bn256/twist.go b/crypto/bn256/google/twist.go similarity index 93% rename from crypto/bn256/twist.go rename to crypto/bn256/google/twist.go index 95b966e2ed..43364ff5b7 100644 --- a/crypto/bn256/twist.go +++ b/crypto/bn256/google/twist.go @@ -76,7 +76,13 @@ func (c *twistPoint) IsOnCurve() bool { yy.Sub(yy, xxx) yy.Sub(yy, twistB) yy.Minimal() - return yy.x.Sign() == 0 && yy.y.Sign() == 0 + + if yy.x.Sign() != 0 || yy.y.Sign() != 0 { + return false + } + cneg := newTwistPoint(pool) + cneg.Mul(c, Order, pool) + return cneg.z.IsZero() } func (c *twistPoint) SetInfinity() { @@ -219,11 +225,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) zInv2 := newGFp2(pool).Square(zInv, pool) diff --git a/crypto/crypto.go b/crypto/crypto.go index 1c4d5a2e02..4567fafc72 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -30,18 +30,20 @@ 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 ( - secp256k1_N, _ = new(big.Int).SetString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16) - secp256k1_halfN = new(big.Int).Div(secp256k1_N, big.NewInt(2)) + secp256k1N, _ = new(big.Int).SetString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16) + secp256k1halfN = new(big.Int).Div(secp256k1N, big.NewInt(2)) ) +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) } @@ -51,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) } @@ -61,19 +63,25 @@ 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) } return d.Sum(nil) } -// Creates an ethereum address given the bytes and the nonce +// CreateAddress creates an ethereum address given the bytes and the nonce func CreateAddress(b common.Address, nonce uint64) common.Address { data, _ := rlp.EncodeToBytes([]interface{}{b, nonce}) return common.BytesToAddress(Keccak256(data)[12:]) } +// CreateAddress2 creates an ethereum address given the address bytes, initial +// contract code hash and a salt. +func CreateAddress2(b common.Address, salt [32]byte, inithash []byte) common.Address { + return common.BytesToAddress(Keccak256([]byte{0xff}, b.Bytes(), salt[:], inithash)[12:]) +} + // ToECDSA creates a private key with the given D value. func ToECDSA(d []byte) (*ecdsa.PrivateKey, error) { return toECDSA(d, true) @@ -99,7 +107,7 @@ func toECDSA(d []byte, strict bool) (*ecdsa.PrivateKey, error) { priv.D = new(big.Int).SetBytes(d) // The priv.D must < N - if priv.D.Cmp(secp256k1_N) >= 0 { + if priv.D.Cmp(secp256k1N) >= 0 { return nil, fmt.Errorf("invalid private key, >=N") } // The priv.D must not be zero or negative. @@ -122,12 +130,13 @@ func FromECDSA(priv *ecdsa.PrivateKey) []byte { return math.PaddedBigBytes(priv.D, priv.Params().BitSize/8) } -func ToECDSAPub(pub []byte) *ecdsa.PublicKey { - if len(pub) == 0 { - return nil - } +// UnmarshalPubkey converts bytes to a secp256k1 public key. +func UnmarshalPubkey(pub []byte) (*ecdsa.PublicKey, error) { x, y := elliptic.Unmarshal(S256(), pub) - return &ecdsa.PublicKey{Curve: S256(), X: x, Y: y} + if x == nil { + return nil, errInvalidPubkey + } + return &ecdsa.PublicKey{Curve: S256(), X: x, Y: y}, nil } func FromECDSAPub(pub *ecdsa.PublicKey) []byte { @@ -184,11 +193,11 @@ func ValidateSignatureValues(v byte, r, s *big.Int, homestead bool) bool { } // reject upper range of s values (ECDSA malleability) // see discussion in secp256k1/libsecp256k1/include/secp256k1.h - if homestead && s.Cmp(secp256k1_halfN) > 0 { + if homestead && s.Cmp(secp256k1halfN) > 0 { return false } // Frontier: allow s to be in full N range - return r.Cmp(secp256k1_N) < 0 && s.Cmp(secp256k1_N) < 0 && (v == 0 || v == 1) + return r.Cmp(secp256k1N) < 0 && s.Cmp(secp256k1N) < 0 && (v == 0 || v == 1) } func PubkeyToAddress(p ecdsa.PublicKey) common.Address { diff --git a/crypto/crypto_test.go b/crypto/crypto_test.go index 8350354623..177c19c0cf 100644 --- a/crypto/crypto_test.go +++ b/crypto/crypto_test.go @@ -23,9 +23,11 @@ import ( "io/ioutil" "math/big" "os" + "reflect" "testing" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" ) var testAddrHex = "970e8128ab834e8eac17ab8e3812f010678cf791" @@ -56,6 +58,33 @@ func BenchmarkSha3(b *testing.B) { } } +func TestUnmarshalPubkey(t *testing.T) { + key, err := UnmarshalPubkey(nil) + if err != errInvalidPubkey || key != nil { + t.Fatalf("expected error, got %v, %v", err, key) + } + key, err = UnmarshalPubkey([]byte{1, 2, 3}) + if err != errInvalidPubkey || key != nil { + t.Fatalf("expected error, got %v, %v", err, key) + } + + var ( + enc, _ = hex.DecodeString("04760c4460e5336ac9bbd87952a3c7ec4363fc0a97bd31c86430806e287b437fd1b01abc6e1db640cf3106b520344af1d58b00b57823db3e1407cbc433e1b6d04d") + dec = &ecdsa.PublicKey{ + Curve: S256(), + X: hexutil.MustDecodeBig("0x760c4460e5336ac9bbd87952a3c7ec4363fc0a97bd31c86430806e287b437fd1"), + Y: hexutil.MustDecodeBig("0xb01abc6e1db640cf3106b520344af1d58b00b57823db3e1407cbc433e1b6d04d"), + } + ) + key, err = UnmarshalPubkey(enc) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + if !reflect.DeepEqual(key, dec) { + t.Fatal("wrong result") + } +} + func TestSign(t *testing.T) { key, _ := HexToECDSA(testPrivHex) addr := common.HexToAddress(testAddrHex) @@ -69,7 +98,7 @@ func TestSign(t *testing.T) { if err != nil { t.Errorf("ECRecover error: %s", err) } - pubKey := ToECDSAPub(recoveredPub) + pubKey, _ := UnmarshalPubkey(recoveredPub) recoveredAddr := PubkeyToAddress(*pubKey) if addr != recoveredAddr { t.Errorf("Address mismatch: want: %x have: %x", addr, recoveredAddr) @@ -154,7 +183,7 @@ func TestValidateSignatureValues(t *testing.T) { minusOne := big.NewInt(-1) one := common.Big1 zero := common.Big0 - secp256k1nMinus1 := new(big.Int).Sub(secp256k1_N, common.Big1) + secp256k1nMinus1 := new(big.Int).Sub(secp256k1N, common.Big1) // correct v,r,s check(true, 0, one, one) @@ -181,9 +210,9 @@ func TestValidateSignatureValues(t *testing.T) { // correct sig with max r,s check(true, 0, secp256k1nMinus1, secp256k1nMinus1) // correct v, combinations of incorrect r,s at upper limit - check(false, 0, secp256k1_N, secp256k1nMinus1) - check(false, 0, secp256k1nMinus1, secp256k1_N) - check(false, 0, secp256k1_N, secp256k1_N) + check(false, 0, secp256k1N, secp256k1nMinus1) + check(false, 0, secp256k1nMinus1, secp256k1N) + check(false, 0, secp256k1N, secp256k1N) // current callers ensures r,s cannot be negative, but let's test for that too // as crypto package could be used stand-alone diff --git a/crypto/ecies/ecies.go b/crypto/ecies/ecies.go index 2ed91c895d..1474181482 100644 --- a/crypto/ecies/ecies.go +++ b/crypto/ecies/ecies.go @@ -230,7 +230,7 @@ func symEncrypt(rand io.Reader, params *ECIESParams, key, m []byte) (ct []byte, // symDecrypt carries out CTR decryption using the block cipher specified in // the parameters -func symDecrypt(rand io.Reader, params *ECIESParams, key, ct []byte) (m []byte, err error) { +func symDecrypt(params *ECIESParams, key, ct []byte) (m []byte, err error) { c, err := params.Cipher(key) if err != nil { return @@ -292,7 +292,7 @@ func Encrypt(rand io.Reader, pub *PublicKey, m, s1, s2 []byte) (ct []byte, err e } // Decrypt decrypts an ECIES ciphertext. -func (prv *PrivateKey) Decrypt(rand io.Reader, c, s1, s2 []byte) (m []byte, err error) { +func (prv *PrivateKey) Decrypt(c, s1, s2 []byte) (m []byte, err error) { if len(c) == 0 { return nil, ErrInvalidMessage } @@ -361,6 +361,6 @@ func (prv *PrivateKey) Decrypt(rand io.Reader, c, s1, s2 []byte) (m []byte, err return } - m, err = symDecrypt(rand, params, Ke, c[mStart:mEnd]) + m, err = symDecrypt(params, Ke, c[mStart:mEnd]) return } diff --git a/crypto/ecies/ecies_test.go b/crypto/ecies/ecies_test.go index 9cd5c79f7e..6bd57145db 100644 --- a/crypto/ecies/ecies_test.go +++ b/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) @@ -270,7 +257,7 @@ func TestEncryptDecrypt(t *testing.T) { t.FailNow() } - pt, err := prv2.Decrypt(rand.Reader, ct, nil, nil) + pt, err := prv2.Decrypt(ct, nil, nil) if err != nil { fmt.Println(err.Error()) t.FailNow() @@ -281,7 +268,7 @@ func TestEncryptDecrypt(t *testing.T) { t.FailNow() } - _, err = prv1.Decrypt(rand.Reader, ct, nil, nil) + _, err = prv1.Decrypt(ct, nil, nil) if err == nil { fmt.Println("ecies: encryption should not have succeeded") t.FailNow() @@ -301,7 +288,7 @@ func TestDecryptShared2(t *testing.T) { } // Check that decrypting with correct shared data works. - pt, err := prv.Decrypt(rand.Reader, ct, nil, shared2) + pt, err := prv.Decrypt(ct, nil, shared2) if err != nil { t.Fatal(err) } @@ -310,10 +297,10 @@ func TestDecryptShared2(t *testing.T) { } // Decrypting without shared data or incorrect shared data fails. - if _, err = prv.Decrypt(rand.Reader, ct, nil, nil); err == nil { + if _, err = prv.Decrypt(ct, nil, nil); err == nil { t.Fatal("ecies: decrypting without shared data didn't fail") } - if _, err = prv.Decrypt(rand.Reader, ct, nil, []byte("garbage")); err == nil { + if _, err = prv.Decrypt(ct, nil, []byte("garbage")); err == nil { t.Fatal("ecies: decrypting with incorrect shared data didn't fail") } } @@ -381,7 +368,7 @@ func testParamSelection(t *testing.T, c testCase) { t.FailNow() } - pt, err := prv2.Decrypt(rand.Reader, ct, nil, nil) + pt, err := prv2.Decrypt(ct, nil, nil) if err != nil { fmt.Printf("%s (%s)\n", err.Error(), c.Name) t.FailNow() @@ -393,7 +380,7 @@ func testParamSelection(t *testing.T, c testCase) { t.FailNow() } - _, err = prv1.Decrypt(rand.Reader, ct, nil, nil) + _, err = prv1.Decrypt(ct, nil, nil) if err == nil { fmt.Printf("ecies: encryption should not have succeeded (%s)\n", c.Name) @@ -422,7 +409,7 @@ func TestBasicKeyValidation(t *testing.T) { for _, b := range badBytes { ct[0] = b - _, err := prv.Decrypt(rand.Reader, ct, nil, nil) + _, err := prv.Decrypt(ct, nil, nil) if err != ErrInvalidPublicKey { fmt.Println("ecies: validated an invalid key") t.FailNow() @@ -441,14 +428,14 @@ func TestBox(t *testing.T) { t.Fatal(err) } - pt, err := prv2.Decrypt(rand.Reader, ct, nil, nil) + pt, err := prv2.Decrypt(ct, nil, nil) if err != nil { t.Fatal(err) } if !bytes.Equal(pt, message) { t.Fatal("ecies: plaintext doesn't match message") } - if _, err = prv1.Decrypt(rand.Reader, ct, nil, nil); err == nil { + if _, err = prv1.Decrypt(ct, nil, nil); err == nil { t.Fatal("ecies: encryption should not have succeeded") } } diff --git a/crypto/secp256k1/LICENSE b/crypto/secp256k1/LICENSE new file mode 100644 index 0000000000..f9090e1423 --- /dev/null +++ b/crypto/secp256k1/LICENSE @@ -0,0 +1,31 @@ +Copyright (c) 2010 The Go Authors. All rights reserved. +Copyright (c) 2011 ThePiachu. All rights reserved. +Copyright (c) 2015 Jeffrey Wilcke. All rights reserved. +Copyright (c) 2015 Felix Lange. All rights reserved. +Copyright (c) 2015 Gustav Simonsson. All rights reserved. + +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 the copyright holder. 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. diff --git a/crypto/secp256k1/curve.go b/crypto/secp256k1/curve.go index df80481857..5409ee1d2c 100644 --- a/crypto/secp256k1/curve.go +++ b/crypto/secp256k1/curve.go @@ -1,5 +1,6 @@ // Copyright 2010 The Go Authors. All rights reserved. // Copyright 2011 ThePiachu. All rights reserved. +// Copyright 2015 Jeffrey Wilcke, Felix Lange, Gustav Simonsson. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -35,8 +36,6 @@ import ( "crypto/elliptic" "math/big" "unsafe" - - "github.com/ethereum/go-ethereum/common/math" ) /* @@ -45,6 +44,27 @@ extern int secp256k1_ext_scalar_mul(const secp256k1_context* ctx, const unsigned */ import "C" +const ( + // number of bits in a big.Word + wordBits = 32 << (uint64(^big.Word(0)) >> 63) + // number of bytes in a big.Word + wordBytes = wordBits / 8 +) + +// readBits encodes the absolute value of bigint as big-endian bytes. Callers +// must ensure that buf has enough space. If buf is too short the result will +// be incomplete. +func readBits(bigint *big.Int, buf []byte) { + i := len(buf) + for _, d := range bigint.Bits() { + for j := 0; j < wordBytes && i > 0; j++ { + i-- + buf[i] = byte(d) + d >>= 8 + } + } +} + // This code is from https://github.com/ThePiachu/GoBit and implements // several Koblitz elliptic curves over prime fields. // @@ -77,7 +97,7 @@ func (BitCurve *BitCurve) Params() *elliptic.CurveParams { } } -// IsOnBitCurve returns true if the given (x,y) lies on the BitCurve. +// IsOnCurve returns true if the given (x,y) lies on the BitCurve. func (BitCurve *BitCurve) IsOnCurve(x, y *big.Int) bool { // y² = x³ + b y2 := new(big.Int).Mul(y, y) //y² @@ -231,8 +251,9 @@ func (BitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, // Do the multiplication in C, updating point. point := make([]byte, 64) - math.ReadBits(Bx, point[:32]) - math.ReadBits(By, point[32:]) + readBits(Bx, point[:32]) + readBits(By, point[32:]) + pointPtr := (*C.uchar)(unsafe.Pointer(&point[0])) scalarPtr := (*C.uchar)(unsafe.Pointer(&scalar[0])) res := C.secp256k1_ext_scalar_mul(context, pointPtr, scalarPtr) @@ -264,8 +285,8 @@ func (BitCurve *BitCurve) Marshal(x, y *big.Int) []byte { byteLen := (BitCurve.BitSize + 7) >> 3 ret := make([]byte, 1+2*byteLen) ret[0] = 4 // uncompressed point flag - math.ReadBits(x, ret[1:1+byteLen]) - math.ReadBits(y, ret[1+byteLen:]) + readBits(x, ret[1:1+byteLen]) + readBits(y, ret[1+byteLen:]) return ret } @@ -289,12 +310,12 @@ 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 - theCurve.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16) - theCurve.N, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16) - theCurve.B, _ = new(big.Int).SetString("0000000000000000000000000000000000000000000000000000000000000007", 16) - theCurve.Gx, _ = new(big.Int).SetString("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 16) - theCurve.Gy, _ = new(big.Int).SetString("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 16) + // 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) + theCurve.Gx, _ = new(big.Int).SetString("0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 0) + theCurve.Gy, _ = new(big.Int).SetString("0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 0) theCurve.BitSize = 256 } diff --git a/crypto/secp256k1/ext.h b/crypto/secp256k1/ext.h index 9b043c724e..e422fe4b49 100644 --- a/crypto/secp256k1/ext.h +++ b/crypto/secp256k1/ext.h @@ -1,18 +1,6 @@ -// 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 . +// Copyright 2015 Jeffrey Wilcke, Felix Lange, Gustav Simonsson. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be found in +// the LICENSE file. // secp256k1_context_create_sign_verify creates a context for signing and signature verification. static secp256k1_context* secp256k1_context_create_sign_verify() { diff --git a/crypto/secp256k1/libsecp256k1/src/num.h b/crypto/secp256k1/libsecp256k1/src/num.h index 7bb9c5be8c..eff842200f 100644 --- a/crypto/secp256k1/libsecp256k1/src/num.h +++ b/crypto/secp256k1/libsecp256k1/src/num.h @@ -54,7 +54,7 @@ static void secp256k1_num_mul(secp256k1_num *r, const secp256k1_num *a, const se even if r was negative. */ static void secp256k1_num_mod(secp256k1_num *r, const secp256k1_num *m); -/** Right-shift the passed number by bits bits. */ +/** Right-shift the passed number by bits. */ static void secp256k1_num_shift(secp256k1_num *r, int bits); /** Check whether a number is zero. */ diff --git a/crypto/secp256k1/libsecp256k1/src/secp256k1.c b/crypto/secp256k1/libsecp256k1/src/secp256k1.c index fb8b882faa..7d637bfad1 100755 --- a/crypto/secp256k1/libsecp256k1/src/secp256k1.c +++ b/crypto/secp256k1/libsecp256k1/src/secp256k1.c @@ -26,7 +26,6 @@ } while(0) static void default_illegal_callback_fn(const char* str, void* data) { - (void)data; fprintf(stderr, "[libsecp256k1] illegal argument: %s\n", str); abort(); } @@ -37,7 +36,6 @@ static const secp256k1_callback default_illegal_callback = { }; static void default_error_callback_fn(const char* str, void* data) { - (void)data; fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str); abort(); } diff --git a/crypto/secp256k1/panic_cb.go b/crypto/secp256k1/panic_cb.go index e0e9034ee0..6d59a1d247 100644 --- a/crypto/secp256k1/panic_cb.go +++ b/crypto/secp256k1/panic_cb.go @@ -1,18 +1,6 @@ -// 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 . +// Copyright 2015 Jeffrey Wilcke, Felix Lange, Gustav Simonsson. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be found in +// the LICENSE file. package secp256k1 diff --git a/crypto/secp256k1/secp256.go b/crypto/secp256k1/secp256.go index eefbb99ee4..35d0eef34a 100644 --- a/crypto/secp256k1/secp256.go +++ b/crypto/secp256k1/secp256.go @@ -1,18 +1,6 @@ -// 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 . +// Copyright 2015 Jeffrey Wilcke, Felix Lange, Gustav Simonsson. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be found in +// the LICENSE file. // Package secp256k1 wraps the bitcoin secp256k1 C library. package secp256k1 @@ -98,7 +86,7 @@ func Sign(msg []byte, seckey []byte) ([]byte, error) { return sig, nil } -// RecoverPubkey returns the the public key of the signer. +// RecoverPubkey returns the public key of the signer. // msg must be the 32-byte hash of the message to be signed. // sig must be a 65-byte compact ECDSA signature containing the // recovery id as the last element. diff --git a/crypto/secp256k1/secp256_test.go b/crypto/secp256k1/secp256_test.go index f6582ecd54..ef2a3a3790 100644 --- a/crypto/secp256k1/secp256_test.go +++ b/crypto/secp256k1/secp256_test.go @@ -1,18 +1,6 @@ -// 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 . +// Copyright 2015 Jeffrey Wilcke, Felix Lange, Gustav Simonsson. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be found in +// the LICENSE file. package secp256k1 @@ -22,10 +10,8 @@ import ( "crypto/elliptic" "crypto/rand" "encoding/hex" + "io" "testing" - - "github.com/ethereum/go-ethereum/common/math" - "github.com/ethereum/go-ethereum/crypto/randentropy" ) const TestCount = 1000 @@ -36,11 +22,24 @@ func generateKeyPair() (pubkey, privkey []byte) { panic(err) } pubkey = elliptic.Marshal(S256(), key.X, key.Y) - return pubkey, math.PaddedBigBytes(key.D, 32) + + privkey = make([]byte, 32) + blob := key.D.Bytes() + copy(privkey[32-len(blob):], blob) + + return pubkey, privkey +} + +func csprngEntropy(n int) []byte { + buf := make([]byte, n) + if _, err := io.ReadFull(rand.Reader, buf); err != nil { + panic("reading from crypto/rand failed: " + err.Error()) + } + return buf } func randSig() []byte { - sig := randentropy.GetEntropyCSPRNG(65) + sig := csprngEntropy(65) sig[32] &= 0x70 sig[64] %= 4 return sig @@ -49,7 +48,7 @@ func randSig() []byte { // tests for malleability // highest bit of signature ECDSA s value must be 0, in the 33th byte func compactSigCheck(t *testing.T, sig []byte) { - var b int = int(sig[32]) + var b = int(sig[32]) if b < 0 { t.Errorf("highest bit is negative: %d", b) } @@ -63,7 +62,7 @@ func compactSigCheck(t *testing.T, sig []byte) { func TestSignatureValidity(t *testing.T) { pubkey, seckey := generateKeyPair() - msg := randentropy.GetEntropyCSPRNG(32) + msg := csprngEntropy(32) sig, err := Sign(msg, seckey) if err != nil { t.Errorf("signature error: %s", err) @@ -86,7 +85,7 @@ func TestSignatureValidity(t *testing.T) { func TestInvalidRecoveryID(t *testing.T) { _, seckey := generateKeyPair() - msg := randentropy.GetEntropyCSPRNG(32) + msg := csprngEntropy(32) sig, _ := Sign(msg, seckey) sig[64] = 99 _, err := RecoverPubkey(msg, sig) @@ -97,7 +96,7 @@ func TestInvalidRecoveryID(t *testing.T) { func TestSignAndRecover(t *testing.T) { pubkey1, seckey := generateKeyPair() - msg := randentropy.GetEntropyCSPRNG(32) + msg := csprngEntropy(32) sig, err := Sign(msg, seckey) if err != nil { t.Errorf("signature error: %s", err) @@ -148,7 +147,7 @@ func TestRandomMessagesWithRandomKeys(t *testing.T) { func signAndRecoverWithRandomMessages(t *testing.T, keys func() ([]byte, []byte)) { for i := 0; i < TestCount; i++ { pubkey1, seckey := keys() - msg := randentropy.GetEntropyCSPRNG(32) + msg := csprngEntropy(32) sig, err := Sign(msg, seckey) if err != nil { t.Fatalf("signature error: %s", err) @@ -176,7 +175,7 @@ func signAndRecoverWithRandomMessages(t *testing.T, keys func() ([]byte, []byte) func TestRecoveryOfRandomSignature(t *testing.T) { pubkey1, _ := generateKeyPair() - msg := randentropy.GetEntropyCSPRNG(32) + msg := csprngEntropy(32) for i := 0; i < TestCount; i++ { // recovery can sometimes work, but if so should always give wrong pubkey @@ -189,11 +188,11 @@ func TestRecoveryOfRandomSignature(t *testing.T) { func TestRandomMessagesAgainstValidSig(t *testing.T) { pubkey1, seckey := generateKeyPair() - msg := randentropy.GetEntropyCSPRNG(32) + msg := csprngEntropy(32) sig, _ := Sign(msg, seckey) for i := 0; i < TestCount; i++ { - msg = randentropy.GetEntropyCSPRNG(32) + msg = csprngEntropy(32) pubkey2, _ := RecoverPubkey(msg, sig) // recovery can sometimes work, but if so should always give wrong pubkey if bytes.Equal(pubkey1, pubkey2) { @@ -219,7 +218,7 @@ func TestRecoverSanity(t *testing.T) { func BenchmarkSign(b *testing.B) { _, seckey := generateKeyPair() - msg := randentropy.GetEntropyCSPRNG(32) + msg := csprngEntropy(32) b.ResetTimer() for i := 0; i < b.N; i++ { @@ -228,7 +227,7 @@ func BenchmarkSign(b *testing.B) { } func BenchmarkRecover(b *testing.B) { - msg := randentropy.GetEntropyCSPRNG(32) + msg := csprngEntropy(32) _, seckey := generateKeyPair() sig, _ := Sign(msg, seckey) b.ResetTimer() diff --git a/crypto/sha3/PATENTS b/crypto/sha3/PATENTS deleted file mode 100644 index 733099041f..0000000000 --- a/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/crypto/sha3/sha3_test.go b/crypto/sha3/sha3_test.go deleted file mode 100644 index 0e33676ce6..0000000000 --- a/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/crypto/sha3/testdata/keccakKats.json.deflate b/crypto/sha3/testdata/keccakKats.json.deflate deleted file mode 100644 index 62e85ae242..0000000000 Binary files a/crypto/sha3/testdata/keccakKats.json.deflate and /dev/null differ diff --git a/crypto/signature_cgo.go b/crypto/signature_cgo.go index 340bfc221e..aadf028d26 100644 --- a/crypto/signature_cgo.go +++ b/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/crypto/signature_nocgo.go b/crypto/signature_nocgo.go index f636b23772..90d072cda7 100644 --- a/crypto/signature_nocgo.go +++ b/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 @@ -88,7 +88,7 @@ func VerifySignature(pubkey, hash, signature []byte) bool { return false } // Reject malleable signatures. libsecp256k1 does this check but btcec doesn't. - if sig.S.Cmp(secp256k1_halfN) > 0 { + if sig.S.Cmp(secp256k1halfN) > 0 { return false } return sig.Verify(hash, key) diff --git a/dashboard/README.md b/dashboard/README.md index e010095ab2..641c5f44bc 100644 --- a/dashboard/README.md +++ b/dashboard/README.md @@ -12,28 +12,27 @@ The client's UI uses [React][React] with JSX syntax, which is validated by the [ As the dashboard depends on certain NPM packages (which are not included in the `go-ethereum` repo), these need to be installed first: ``` -$ (cd dashboard/assets && npm install) -$ (cd dashboard/assets && ./node_modules/.bin/flow-typed install) +$ (cd dashboard/assets && yarn install && yarn flow) ``` -Normally the dashboard assets are bundled into Geth via `go-bindata` to avoid external dependencies. Rebuilding Geth after each UI modification however is not feasible from a developer perspective. Instead, we can run `webpack` in watch mode to automatically rebundle the UI, and ask `geth` to use external assets to not rely on compiled resources: +Normally the dashboard assets are bundled into Geth via `go-bindata` to avoid external dependencies. Rebuilding Geth after each UI modification however is not feasible from a developer perspective. Instead, we can run `yarn dev` to watch for file system changes and refresh the browser automatically. ``` -$ (cd dashboard/assets && ./node_modules/.bin/webpack --watch) -$ geth --dashboard --dashboard.assets=dashboard/assets --vmodule=dashboard=5 +$ geth --dashboard --vmodule=dashboard=5 +$ (cd dashboard/assets && yarn dev) ``` To bundle up the final UI into Geth, run `go generate`: ``` -$ go generate ./dashboard +$ (cd dashboard && go generate) ``` ### Static type checking Since JavaScript doesn't provide type safety, [Flow][Flow] is used to check types. These are only useful during development, so at the end of the process Babel will strip them. -To take advantage of static type checking, your IDE needs to be prepared for it. In case of [Atom][Atom] a configuration guide can be found [here][Atom config]: Install the [Nuclide][Nuclide] package for Flow support, making sure it installs all of its support packages by enabling `Install Recommended Packages on Startup`, and set the path of the `flow-bin` which were installed previously by `npm`. +To take advantage of static type checking, your IDE needs to be prepared for it. In case of [Atom][Atom] a configuration guide can be found [here][Atom config]: Install the [Nuclide][Nuclide] package for Flow support, making sure it installs all of its support packages by enabling `Install Recommended Packages on Startup`, and set the path of the `flow-bin` which were installed previously by `yarn`. For more IDE support install the `linter-eslint` package too, which finds the `.eslintrc` file, and provides real-time linting. Atom warns, that these two packages are incompatible, but they seem to work well together. For third-party library errors and auto-completion [flow-typed][flow-typed] is used. @@ -41,7 +40,7 @@ For more IDE support install the `linter-eslint` package too, which finds the `. [Webpack][Webpack] offers handy tools for visualizing the bundle's dependency tree and space usage. -* Generate the bundle's profile running `webpack --profile --json > stats.json` +* Generate the bundle's profile running `yarn stats` * For the _dependency tree_ go to [Webpack Analyze][WA], and import `stats.json` * For the _space usage_ go to [Webpack Visualizer][WV], and import `stats.json` diff --git a/dashboard/assets.go b/dashboard/assets.go index 8337cf080d..f3e7cf9815 100644 --- a/dashboard/assets.go +++ b/dashboard/assets.go @@ -1,6 +1,6 @@ // Code generated by go-bindata. DO NOT EDIT. // sources: -// assets/dashboard.html +// assets/index.html // assets/bundle.js package dashboard @@ -48,7 +48,7 @@ func (fi bindataFileInfo) Sys() interface{} { } //nolint:misspell -var _dashboardHtml = []byte(` +var _indexHtml = []byte(` @@ -64,6 +64,9 @@ var _dashboardHtml = []byte(` ::-webkit-scrollbar-thumb { background: #212121; } + ::-webkit-scrollbar-corner { + background: transparent; + } @@ -73,18 +76,18 @@ var _dashboardHtml = []byte(` `) -func dashboardHtmlBytes() ([]byte, error) { - return _dashboardHtml, nil +func indexHtmlBytes() ([]byte, error) { + return _indexHtml, nil } -func dashboardHtml() (*asset, error) { - bytes, err := dashboardHtmlBytes() +func indexHtml() (*asset, error) { + bytes, err := indexHtmlBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "dashboard.html", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x6b, 0xd9, 0xa6, 0xeb, 0x32, 0x49, 0x9b, 0xe5, 0x3a, 0xcb, 0x99, 0xd3, 0xb6, 0x69, 0x7f, 0xde, 0x35, 0x9d, 0x5, 0x96, 0x84, 0xc0, 0x14, 0xef, 0xbe, 0x58, 0x10, 0x5e, 0x40, 0xf2, 0x12, 0x97}} + 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}} return a, nil } @@ -116,11 +119,11 @@ var _bundleJs = []byte((((((((((`!function(modules) { 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 = 331); + }, __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__(332) : module.exports = __webpack_require__(333); + "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) { @@ -128,8 +131,8 @@ var _bundleJs = []byte((((((((((`!function(modules) { 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__(374)(isValidElement, !0); - } else module.exports = __webpack_require__(375)(); + module.exports = __webpack_require__(418)(isValidElement, !0); + } else module.exports = __webpack_require__(419)(); }).call(exports, __webpack_require__(2)); }, function(module, exports) { function defaultSetTimout() { @@ -289,7 +292,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { }), __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__(164), __WEBPACK_IMPORTED_MODULE_1_lodash_isString___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_lodash_isString__), __WEBPACK_IMPORTED_MODULE_2_lodash_isObject__ = __webpack_require__(31), __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__(12), __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 = { + 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, @@ -434,7 +437,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { }, 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__.g)(width) || width <= 0 || !Object(__WEBPACK_IMPORTED_MODULE_7__DataUtils__.g)(height) || height <= 0); + 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) { @@ -499,17 +502,10 @@ var _bundleJs = []byte((((((((((`!function(modules) { component.prototype.shouldComponentUpdate = shouldComponentUpdate; } __webpack_exports__.b = shallowEqual, __webpack_exports__.a = pureRenderDecorator; -}, 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__) { "use strict"; exports.__esModule = !0; - var _assign = __webpack_require__(205), _assign2 = function(obj) { + var _assign = __webpack_require__(222), _assign2 = function(obj) { return obj && obj.__esModule ? obj : { default: obj }; @@ -521,38 +517,47 @@ var _bundleJs = []byte((((((((((`!function(modules) { } 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__(42), isObject = __webpack_require__(31), asyncTag = "[object AsyncFunction]", funcTag = "[object Function]", genTag = "[object GeneratorFunction]", proxyTag = "[object Proxy]"; + 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__, "i", function() { + __webpack_require__.d(__webpack_exports__, "j", function() { return mathSign; - }), __webpack_require__.d(__webpack_exports__, "h", function() { + }), __webpack_require__.d(__webpack_exports__, "i", function() { return isPercent; - }), __webpack_require__.d(__webpack_exports__, "g", function() { + }), __webpack_require__.d(__webpack_exports__, "h", function() { return isNumber; - }), __webpack_require__.d(__webpack_exports__, "f", function() { + }), __webpack_require__.d(__webpack_exports__, "g", function() { return isNumOrStr; - }), __webpack_require__.d(__webpack_exports__, "j", function() { + }), __webpack_require__.d(__webpack_exports__, "k", function() { return uniqueId; - }), __webpack_require__.d(__webpack_exports__, "c", function() { + }), __webpack_require__.d(__webpack_exports__, "d", function() { return getPercentValue; }), __webpack_require__.d(__webpack_exports__, "b", function() { return getAnyElementOfObject; - }), __webpack_require__.d(__webpack_exports__, "d", function() { - return hasDuplicate; }), __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__(165), __WEBPACK_IMPORTED_MODULE_0_lodash_get___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_lodash_get__), __WEBPACK_IMPORTED_MODULE_1_lodash_isArray__ = __webpack_require__(12), __WEBPACK_IMPORTED_MODULE_1_lodash_isArray___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_lodash_isArray__), __WEBPACK_IMPORTED_MODULE_2_lodash_isNaN__ = __webpack_require__(117), __WEBPACK_IMPORTED_MODULE_2_lodash_isNaN___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_2_lodash_isNaN__), __WEBPACK_IMPORTED_MODULE_3_lodash_isNumber__ = __webpack_require__(170), __WEBPACK_IMPORTED_MODULE_3_lodash_isNumber___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_3_lodash_isNumber__), __WEBPACK_IMPORTED_MODULE_4_lodash_isString__ = __webpack_require__(164), __WEBPACK_IMPORTED_MODULE_4_lodash_isString___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_4_lodash_isString__), mathSign = function(value) { + 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; @@ -594,6 +599,18 @@ var _bundleJs = []byte((((((((((`!function(modules) { 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"; @@ -609,12 +626,12 @@ var _bundleJs = []byte((((((((((`!function(modules) { Object.defineProperty(exports, "__esModule", { value: !0 }), exports.sheetsManager = void 0; - var _keys = __webpack_require__(41), _keys2 = _interopRequireDefault(_keys), _extends2 = __webpack_require__(7), _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__(6), _objectWithoutProperties3 = _interopRequireDefault(_objectWithoutProperties2), _map = __webpack_require__(397), _map2 = _interopRequireDefault(_map), _minSafeInteger = __webpack_require__(413), _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__(152), _hoistNonReactStatics2 = _interopRequireDefault(_hoistNonReactStatics), _getDisplayName = __webpack_require__(226), _getDisplayName2 = _interopRequireDefault(_getDisplayName), _wrapDisplayName = __webpack_require__(75), _wrapDisplayName2 = _interopRequireDefault(_wrapDisplayName), _contextTypes = __webpack_require__(416), _contextTypes2 = _interopRequireDefault(_contextTypes), _jss = __webpack_require__(228), _ns = __webpack_require__(227), ns = function(obj) { + 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__(439), _jssPreset2 = _interopRequireDefault(_jssPreset), _createMuiTheme = __webpack_require__(151), _createMuiTheme2 = _interopRequireDefault(_createMuiTheme), _themeListener = __webpack_require__(150), _themeListener2 = _interopRequireDefault(_themeListener), _createGenerateClassName = __webpack_require__(451), _createGenerateClassName2 = _interopRequireDefault(_createGenerateClassName), _getStylesCreator = __webpack_require__(452), _getStylesCreator2 = _interopRequireDefault(_getStylesCreator), jss = (0, + }(_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) { @@ -716,10 +733,10 @@ var _bundleJs = []byte((((((((((`!function(modules) { 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, + 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, + _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; @@ -755,7 +772,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { 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 (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() { @@ -768,13 +785,10 @@ var _bundleJs = []byte((((((((((`!function(modules) { } }), module.exports = warning; }).call(exports, __webpack_require__(2)); -}, function(module, exports) { - var isArray = Array.isArray; - module.exports = isArray; }, function(module, exports, __webpack_require__) { "use strict"; exports.__esModule = !0; - var _defineProperty = __webpack_require__(143), _defineProperty2 = function(obj) { + var _defineProperty = __webpack_require__(154), _defineProperty2 = function(obj) { return obj && obj.__esModule ? obj : { default: obj }; @@ -787,6 +801,9 @@ var _bundleJs = []byte((((((((((`!function(modules) { 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) { @@ -812,7 +829,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { }; Layer.propTypes = propTypes, __webpack_exports__.a = Layer; }, function(module, exports, __webpack_require__) { - var global = __webpack_require__(158), core = __webpack_require__(159), hide = __webpack_require__(244), redefine = __webpack_require__(534), ctx = __webpack_require__(537), $export = function(type, name, source) { + 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], @@ -900,37 +917,36 @@ var _bundleJs = []byte((((((((((`!function(modules) { }), __webpack_require__.d(__webpack_exports__, "y", function() { return parseDomainOfCategoryAxis; }); - var __WEBPACK_IMPORTED_MODULE_0_lodash_isEqual__ = __webpack_require__(34), __WEBPACK_IMPORTED_MODULE_0_lodash_isEqual___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_lodash_isEqual__), __WEBPACK_IMPORTED_MODULE_1_lodash_sortBy__ = __webpack_require__(281), __WEBPACK_IMPORTED_MODULE_1_lodash_sortBy___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_lodash_sortBy__), __WEBPACK_IMPORTED_MODULE_2_lodash_isNaN__ = __webpack_require__(117), __WEBPACK_IMPORTED_MODULE_2_lodash_isNaN___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_2_lodash_isNaN__), __WEBPACK_IMPORTED_MODULE_3_lodash_isString__ = __webpack_require__(164), __WEBPACK_IMPORTED_MODULE_3_lodash_isString___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_3_lodash_isString__), __WEBPACK_IMPORTED_MODULE_4_lodash_max__ = __webpack_require__(702), __WEBPACK_IMPORTED_MODULE_4_lodash_max___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_4_lodash_max__), __WEBPACK_IMPORTED_MODULE_5_lodash_min__ = __webpack_require__(284), __WEBPACK_IMPORTED_MODULE_5_lodash_min___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_5_lodash_min__), __WEBPACK_IMPORTED_MODULE_6_lodash_isArray__ = __webpack_require__(12), __WEBPACK_IMPORTED_MODULE_6_lodash_isArray___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_6_lodash_isArray__), __WEBPACK_IMPORTED_MODULE_7_lodash_isFunction__ = __webpack_require__(8), __WEBPACK_IMPORTED_MODULE_7_lodash_isFunction___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_7_lodash_isFunction__), __WEBPACK_IMPORTED_MODULE_8_lodash_get__ = __webpack_require__(165), __WEBPACK_IMPORTED_MODULE_8_lodash_get___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_8_lodash_get__), __WEBPACK_IMPORTED_MODULE_9_lodash_isNil__ = __webpack_require__(20), __WEBPACK_IMPORTED_MODULE_9_lodash_isNil___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_9_lodash_isNil__), __WEBPACK_IMPORTED_MODULE_10_recharts_scale__ = __webpack_require__(703), __WEBPACK_IMPORTED_MODULE_11_d3_scale__ = (__webpack_require__.n(__WEBPACK_IMPORTED_MODULE_10_recharts_scale__), - __webpack_require__(287)), __WEBPACK_IMPORTED_MODULE_12_d3_shape__ = __webpack_require__(173), __WEBPACK_IMPORTED_MODULE_13__DataUtils__ = __webpack_require__(9), __WEBPACK_IMPORTED_MODULE_14__cartesian_ReferenceDot__ = __webpack_require__(320), __WEBPACK_IMPORTED_MODULE_15__cartesian_ReferenceLine__ = __webpack_require__(321), __WEBPACK_IMPORTED_MODULE_16__cartesian_ReferenceArea__ = __webpack_require__(322), __WEBPACK_IMPORTED_MODULE_17__cartesian_ErrorBar__ = __webpack_require__(91), __WEBPACK_IMPORTED_MODULE_18__component_Legend__ = __webpack_require__(171), __WEBPACK_IMPORTED_MODULE_19__ReactUtils__ = __webpack_require__(4), _extends = Object.assign || function(target) { + 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_9_lodash_isNil___default()(obj) || __WEBPACK_IMPORTED_MODULE_9_lodash_isNil___default()(dataKey) ? defaultValue : Object(__WEBPACK_IMPORTED_MODULE_13__DataUtils__.f)(dataKey) ? __WEBPACK_IMPORTED_MODULE_8_lodash_get___default()(obj, dataKey, defaultValue) : __WEBPACK_IMPORTED_MODULE_7_lodash_isFunction___default()(dataKey) ? dataKey(obj) : 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 = data.reduce(function(result, entry) { - var value = getValueByDataKey(entry, key); - return __WEBPACK_IMPORTED_MODULE_6_lodash_isArray___default()(value) ? [].concat(_toConsumableArray(result), _toConsumableArray(value)) : [].concat(_toConsumableArray(result), [ value ]); - }, []); + 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_13__DataUtils__.g); + 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_9_lodash_isNil___default()(entry); + return !__WEBPACK_IMPORTED_MODULE_10_lodash_isNil___default()(entry); }) : flattenData).map(function(entry) { - return Object(__WEBPACK_IMPORTED_MODULE_13__DataUtils__.f)(entry) ? 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_13__DataUtils__.i)(cur - before) !== Object(__WEBPACK_IMPORTED_MODULE_13__DataUtils__.i)(after - cur)) { + 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_13__DataUtils__.i)(after - cur) === Object(__WEBPACK_IMPORTED_MODULE_13__DataUtils__.i)(range[1] - range[0])) { + 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); @@ -971,7 +987,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { } return result; }, getLegendProps = function(_ref) { - var children = _ref.children, formatedGraphicalItems = _ref.formatedGraphicalItems, legendWidth = _ref.legendWidth, legendContent = _ref.legendContent, legendItem = Object(__WEBPACK_IMPORTED_MODULE_19__ReactUtils__.i)(children, __WEBPACK_IMPORTED_MODULE_18__component_Legend__.a); + 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) { @@ -994,7 +1010,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { value: name || dataKey, payload: item.props }; - }), _extends({}, legendItem.props, __WEBPACK_IMPORTED_MODULE_18__component_Legend__.a.getWithHeight(legendItem, legendWidth), { + }), _extends({}, legendItem.props, __WEBPACK_IMPORTED_MODULE_19__component_Legend__.a.getWithHeight(legendItem, legendWidth), { payload: legendData, item: legendItem }); @@ -1003,14 +1019,14 @@ var _bundleJs = []byte((((((((((`!function(modules) { 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_19__ReactUtils__.j)(item.type).indexOf("Bar") >= 0; + 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_9_lodash_isNil___default()(selfSize) ? globalSize : selfSize + barSize: __WEBPACK_IMPORTED_MODULE_10_lodash_isNil___default()(selfSize) ? globalSize : selfSize }); } } @@ -1018,7 +1034,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { }, 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_13__DataUtils__.c)(barGap, bandSize, 0, !0), result = void 0; + 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; @@ -1046,7 +1062,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { }), newRes; }, []); } else { - var _offset = Object(__WEBPACK_IMPORTED_MODULE_13__DataUtils__.c)(barCategoryGap, bandSize, 0, !0); + 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); @@ -1077,14 +1093,14 @@ var _bundleJs = []byte((((((((((`!function(modules) { }), 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_13__DataUtils__.g)(offset[align]) && (newOffset = _extends({}, offset, _defineProperty({}, align, newOffset[align] + (box.width || 0)))), - ("horizontal" === layout || "vertical" === layout && "center" === align) && Object(__WEBPACK_IMPORTED_MODULE_13__DataUtils__.g)(offset[verticalAlign]) && (newOffset = _extends({}, offset, _defineProperty({}, verticalAlign, newOffset[verticalAlign] + (box.height || 0)))); + ("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_19__ReactUtils__.h)(children, __WEBPACK_IMPORTED_MODULE_17__cartesian_ErrorBar__.a).filter(function(errorBarChild) { + 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_9_lodash_isNil___default()(direction) && !__WEBPACK_IMPORTED_MODULE_9_lodash_isNil___default()(axisType)) || axisType.indexOf(direction) >= 0; + 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) { @@ -1103,7 +1119,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { var domains = items.map(function(item) { return getDomainOfErrorBars(data, item, dataKey, axisType); }).filter(function(entry) { - return !__WEBPACK_IMPORTED_MODULE_9_lodash_isNil___default()(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]) ]; @@ -1133,7 +1149,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { }, 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_13__DataUtils__.i)(range[0] - range[1]) * offset : offset, + 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 { @@ -1164,40 +1180,40 @@ var _bundleJs = []byte((((((((((`!function(modules) { }); }, combineEventHandlers = function(defaultHandler, parentHandler, childHandler) { var customizedHandler = void 0; - return __WEBPACK_IMPORTED_MODULE_7_lodash_isFunction___default()(childHandler) ? customizedHandler = childHandler : __WEBPACK_IMPORTED_MODULE_7_lodash_isFunction___default()(parentHandler) && (customizedHandler = parentHandler), - __WEBPACK_IMPORTED_MODULE_7_lodash_isFunction___default()(defaultHandler) || customizedHandler ? function(arg1, arg2, arg3, arg4) { - __WEBPACK_IMPORTED_MODULE_7_lodash_isFunction___default()(defaultHandler) && defaultHandler(arg1, arg2, arg3, arg4), - __WEBPACK_IMPORTED_MODULE_7_lodash_isFunction___default()(customizedHandler) && customizedHandler(arg1, arg2, arg3, arg4); + 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_11_d3_scale__.scaleBand(), + scale: __WEBPACK_IMPORTED_MODULE_12_d3_scale__.scaleBand(), realScaleType: "band" } : "radial" === layout && "angleAxis" === axisType ? { - scale: __WEBPACK_IMPORTED_MODULE_11_d3_scale__.scaleLinear(), + 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_11_d3_scale__.scalePoint(), + scale: __WEBPACK_IMPORTED_MODULE_12_d3_scale__.scalePoint(), realScaleType: "point" } : "category" === type ? { - scale: __WEBPACK_IMPORTED_MODULE_11_d3_scale__.scaleBand(), + scale: __WEBPACK_IMPORTED_MODULE_12_d3_scale__.scaleBand(), realScaleType: "band" } : { - scale: __WEBPACK_IMPORTED_MODULE_11_d3_scale__.scaleLinear(), + 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_11_d3_scale__[name] || __WEBPACK_IMPORTED_MODULE_11_d3_scale__.scalePoint)(), - realScaleType: __WEBPACK_IMPORTED_MODULE_11_d3_scale__[name] ? name : "point" + 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_7_lodash_isFunction___default()(scale) ? { + return __WEBPACK_IMPORTED_MODULE_8_lodash_isFunction___default()(scale) ? { scale: scale } : { - scale: __WEBPACK_IMPORTED_MODULE_11_d3_scale__.scalePoint(), + scale: __WEBPACK_IMPORTED_MODULE_12_d3_scale__.scalePoint(), realScaleType: "point" }; }, checkDomainOfScale = function(scale) { @@ -1211,10 +1227,10 @@ var _bundleJs = []byte((((((((((`!function(modules) { 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_13__DataUtils__.g)(domain[0]) || !Object(__WEBPACK_IMPORTED_MODULE_13__DataUtils__.g)(domain[1])) return value; + 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_13__DataUtils__.g)(value[0]) || value[0] < min) && (result[0] = min), - (!Object(__WEBPACK_IMPORTED_MODULE_13__DataUtils__.g)(value[1]) || value[1] > max) && (result[1] = max), + 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; @@ -1225,17 +1241,17 @@ var _bundleJs = []byte((((((((((`!function(modules) { } }, STACK_OFFSET_MAP = { sign: offsetSign, - expand: __WEBPACK_IMPORTED_MODULE_12_d3_shape__.o, - none: __WEBPACK_IMPORTED_MODULE_12_d3_shape__.p, - silhouette: __WEBPACK_IMPORTED_MODULE_12_d3_shape__.q, - wiggle: __WEBPACK_IMPORTED_MODULE_12_d3_shape__.r + 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_12_d3_shape__.n)().keys(dataKeys).value(function(d, key) { + return Object(__WEBPACK_IMPORTED_MODULE_13_d3_shape__.n)().keys(dataKeys).value(function(d, key) { return +getValueByDataKey(d, key, 0); - }).order(__WEBPACK_IMPORTED_MODULE_12_d3_shape__.s).offset(STACK_OFFSET_MAP[offsetType])(data); + }).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) { @@ -1245,14 +1261,14 @@ var _bundleJs = []byte((((((((((`!function(modules) { hasStack: !1, stackGroups: {} }; - if (Object(__WEBPACK_IMPORTED_MODULE_13__DataUtils__.f)(stackId)) { + 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_13__DataUtils__.j)("_stackId_")] = { + } else parentGroup.stackGroups[Object(__WEBPACK_IMPORTED_MODULE_14__DataUtils__.k)("_stackId_")] = { numericAxisId: numericAxisId, cateAxisId: cateAxisId, items: [ item ] @@ -1277,7 +1293,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { 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_10_recharts_scale__.getNiceTickValues)(domain, tickCount, allowDecimals); + var domain = scale.domain(), tickValues = Object(__WEBPACK_IMPORTED_MODULE_11_recharts_scale__.getNiceTickValues)(domain, tickCount, allowDecimals); return scale.domain(calculateDomainOfTicks(tickValues, type)), { niceTicks: tickValues }; @@ -1285,26 +1301,26 @@ var _bundleJs = []byte((((((((((`!function(modules) { if (tickCount && "number" === type) { var _domain = scale.domain(); return { - niceTicks: Object(__WEBPACK_IMPORTED_MODULE_10_recharts_scale__.getTickValuesFixedDomain)(_domain, tickCount, allowDecimals) + 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_9_lodash_isNil___default()(entry[axis.dataKey])) { - var matchedTick = Object(__WEBPACK_IMPORTED_MODULE_13__DataUtils__.a)(ticks, "value", entry[axis.dataKey]); + 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_9_lodash_isNil___default()(value) ? null : axis.scale(value); + 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_9_lodash_isNil___default()(value) ? null : axis.scale(value) - bandSize / 2 + offset; + 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) { @@ -1313,9 +1329,9 @@ var _bundleJs = []byte((((((((((`!function(modules) { } return domain[0]; }, detectReferenceElementsDomain = function(children, domain, axisId, axisType, specifiedTicks) { - var lines = Object(__WEBPACK_IMPORTED_MODULE_19__ReactUtils__.h)(children, __WEBPACK_IMPORTED_MODULE_15__cartesian_ReferenceLine__.a), dots = Object(__WEBPACK_IMPORTED_MODULE_19__ReactUtils__.h)(children, __WEBPACK_IMPORTED_MODULE_14__cartesian_ReferenceDot__.a), elements = lines.concat(dots), areas = Object(__WEBPACK_IMPORTED_MODULE_19__ReactUtils__.h)(children, __WEBPACK_IMPORTED_MODULE_16__cartesian_ReferenceArea__.a), idKey = axisType + "Id", valueKey = axisType[0], finalDomain = domain; + 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_13__DataUtils__.g)(el.props[valueKey])) { + 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) ]; } @@ -1323,7 +1339,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { }, 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_13__DataUtils__.g)(el.props[key1]) && Object(__WEBPACK_IMPORTED_MODULE_13__DataUtils__.g)(el.props[key2])) { + 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) ]; } @@ -1331,11 +1347,11 @@ var _bundleJs = []byte((((((((((`!function(modules) { }, finalDomain); } return specifiedTicks && specifiedTicks.length && (finalDomain = specifiedTicks.reduce(function(result, tick) { - return Object(__WEBPACK_IMPORTED_MODULE_13__DataUtils__.g)(tick) ? [ Math.min(result[0], tick), Math.max(result[1], tick) ] : result; + 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_13__DataUtils__.f)(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) { @@ -1348,7 +1364,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { return null; }, getDomainOfSingle = function(data) { return data.reduce(function(result, entry) { - return [ Math.min.apply(null, entry.concat([ result[0] ]).filter(__WEBPACK_IMPORTED_MODULE_13__DataUtils__.g)), Math.max.apply(null, entry.concat([ result[1] ]).filter(__WEBPACK_IMPORTED_MODULE_13__DataUtils__.g)) ]; + 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) { @@ -1363,14 +1379,14 @@ var _bundleJs = []byte((((((((((`!function(modules) { }, 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_13__DataUtils__.g)(specifiedDomain[0])) domain[0] = allowDataOverflow ? specifiedDomain[0] : Math.min(specifiedDomain[0], dataDomain[0]); else if (MIN_VALUE_REG.test(specifiedDomain[0])) { + 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_7_lodash_isFunction___default()(specifiedDomain[0]) ? domain[0] = specifiedDomain[0](dataDomain[0]) : domain[0] = dataDomain[0]; - if (Object(__WEBPACK_IMPORTED_MODULE_13__DataUtils__.g)(specifiedDomain[1])) domain[1] = allowDataOverflow ? specifiedDomain[1] : Math.max(specifiedDomain[1], dataDomain[1]); else if (MAX_VALUE_REG.test(specifiedDomain[1])) { + } 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_7_lodash_isFunction___default()(specifiedDomain[1]) ? domain[1] = specifiedDomain[1](dataDomain[1]) : domain[1] = dataDomain[1]; + } 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; @@ -1389,11 +1405,11 @@ var _bundleJs = []byte((((((((((`!function(modules) { } return 0; }, parseDomainOfCategoryAxis = function(specifiedDomain, calculatedDomain, axisChild) { - return specifiedDomain && specifiedDomain.length ? __WEBPACK_IMPORTED_MODULE_0_lodash_isEqual___default()(specifiedDomain, __WEBPACK_IMPORTED_MODULE_8_lodash_get___default()(axisChild, "type.defaultProps.domain")) ? calculatedDomain : specifiedDomain : calculatedDomain; + 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.3" + version: "2.5.7" }; "number" == typeof __e && (__e = core); }, function(module, __webpack_exports__, __webpack_require__) { @@ -1436,10 +1452,10 @@ var _bundleJs = []byte((((((((((`!function(modules) { __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__(47), hide = __webpack_require__(40), $export = function(type, name, source) { + 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]) && key in exports || (out = own ? target[key] : source[key], + 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) { @@ -1469,12 +1485,12 @@ var _bundleJs = []byte((((((((((`!function(modules) { } module.exports = isNil; }, function(module, exports, __webpack_require__) { - var store = __webpack_require__(140)("wks"), uid = __webpack_require__(98), Symbol = __webpack_require__(24).Symbol, USE_SYMBOL = "function" == typeof Symbol; + 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__(48), IE8_DOM_DEFINE = __webpack_require__(207), toPrimitive = __webpack_require__(134), dP = Object.defineProperty; + 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); @@ -1525,7 +1541,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { }; 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__.c)(props.cx, width, width / 2), cy = Object(__WEBPACK_IMPORTED_MODULE_1__DataUtils__.c)(props.cy, height, height / 2), maxRadius = getMaxRadius(width, height, offset), innerRadius = Object(__WEBPACK_IMPORTED_MODULE_1__DataUtils__.c)(props.innerRadius, maxRadius, 0), outerRadius = Object(__WEBPACK_IMPORTED_MODULE_1__DataUtils__.c)(props.outerRadius, maxRadius, .8 * maxRadius); + 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 ]), @@ -1604,7 +1620,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { 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__(49)(function() { + module.exports = !__webpack_require__(53)(function() { return 7 != Object.defineProperty({}, "a", { get: function() { return 7; @@ -1613,7 +1629,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { }); }, function(module, exports, __webpack_require__) { module.exports = { - default: __webpack_require__(350), + default: __webpack_require__(394), __esModule: !0 }; }, function(module, exports, __webpack_require__) { @@ -1624,7 +1640,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { }, function(module, exports, __webpack_require__) { "use strict"; exports.__esModule = !0; - var _defineProperty = __webpack_require__(143), _defineProperty2 = function(obj) { + var _defineProperty = __webpack_require__(154), _defineProperty2 = function(obj) { return obj && obj.__esModule ? obj : { default: obj }; @@ -1645,7 +1661,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { }, function(module, exports, __webpack_require__) { "use strict"; exports.__esModule = !0; - var _typeof2 = __webpack_require__(100), _typeof3 = function(obj) { + var _typeof2 = __webpack_require__(105), _typeof3 = function(obj) { return obj && obj.__esModule ? obj : { default: obj }; @@ -1662,7 +1678,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { }; } exports.__esModule = !0; - var _setPrototypeOf = __webpack_require__(367), _setPrototypeOf2 = _interopRequireDefault(_setPrototypeOf), _create = __webpack_require__(371), _create2 = _interopRequireDefault(_create), _typeof2 = __webpack_require__(100), _typeof3 = _interopRequireDefault(_typeof2); + 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))); @@ -1675,15 +1691,15 @@ var _bundleJs = []byte((((((((((`!function(modules) { } }), 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__) { - var freeGlobal = __webpack_require__(242), freeSelf = "object" == typeof self && self && self.Object === Object && self, root = freeGlobal || freeSelf || Function("return this")(); - module.exports = root; }, function(module, exports, __webpack_require__) { "use strict"; function _interopRequireDefault(obj) { @@ -1694,53 +1710,48 @@ var _bundleJs = []byte((((((((((`!function(modules) { Object.defineProperty(exports, "__esModule", { value: !0 }), exports.translateStyle = exports.AnimateGroup = exports.configBezier = exports.configSpring = void 0; - var _Animate = __webpack_require__(263), _Animate2 = _interopRequireDefault(_Animate), _easing = __webpack_require__(275), _util = __webpack_require__(123), _AnimateGroup = __webpack_require__(679), _AnimateGroup2 = _interopRequireDefault(_AnimateGroup); + 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, __webpack_require__) { - function isEqual(value, other) { - return baseIsEqual(value, other); - } - var baseIsEqual = __webpack_require__(178); - module.exports = isEqual; +}, 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) { - function isObjectLike(value) { - return null != value && "object" == typeof value; - } - module.exports = isObjectLike; +}, 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__(288); + 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__(64); + 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__(289); + 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__(707), __webpack_require__(708), - __webpack_require__(291), __webpack_require__(293), __webpack_require__(709), __webpack_require__(712), - __webpack_require__(713), __webpack_require__(297), __webpack_require__(714), __webpack_require__(715), - __webpack_require__(716), __webpack_require__(717), __webpack_require__(298), __webpack_require__(290), - __webpack_require__(718), __webpack_require__(185)); + 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__(295); + 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__(719), __webpack_require__(720), - __webpack_require__(721), __webpack_require__(296)); + 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() { @@ -1748,7 +1759,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { }), __webpack_require__.d(__webpack_exports__, "g", function() { return __WEBPACK_IMPORTED_MODULE_23__src_ticks__.c; }); - __webpack_require__(299), __webpack_require__(292), __webpack_require__(722); + __webpack_require__(343), __webpack_require__(336), __webpack_require__(863); }, function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.d(__webpack_exports__, "d", function() { @@ -1764,38 +1775,39 @@ var _bundleJs = []byte((((((((((`!function(modules) { }); var durationSecond = 1e3, durationMinute = 6e4, durationHour = 36e5, durationDay = 864e5, durationWeek = 6048e5; }, 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 dP = __webpack_require__(22), createDesc = __webpack_require__(71); + 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, __webpack_require__) { - module.exports = { - default: __webpack_require__(378), - __esModule: !0 - }; +}, 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__(77), getRawTag = __webpack_require__(520), objectToString = __webpack_require__(521), nullTag = "[object Null]", undefinedTag = "[object Undefined]", symToStringTag = Symbol ? Symbol.toStringTag : void 0; + 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) { @@ -1820,7 +1832,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { className: __WEBPACK_IMPORTED_MODULE_5_classnames___default()("recharts-label", className) }, attrs, positionAttrs), label); } - var __WEBPACK_IMPORTED_MODULE_0_lodash_isObject__ = __webpack_require__(31), __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__(55), __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) { + 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]); @@ -1853,13 +1865,13 @@ var _bundleJs = []byte((((((((((`!function(modules) { 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__.i)(endAngle - startAngle) * Math.min(Math.abs(endAngle - startAngle), 360); + 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__.j)("recharts-radial-line-") : labelProps.id; + 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) @@ -1955,9 +1967,9 @@ var _bundleJs = []byte((((((((((`!function(modules) { y: y + height - sign * offset, textAnchor: "end", verticalAnchor: "end" - } : __WEBPACK_IMPORTED_MODULE_0_lodash_isObject___default()(position) && (Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.g)(position.x) || Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.h)(position.x)) && (Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.g)(position.y) || Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.h)(position.y)) ? { - x: x + Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.c)(position.x, width), - y: y + Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.c)(position.y, height), + } : __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" } : { @@ -1967,31 +1979,31 @@ var _bundleJs = []byte((((((((((`!function(modules) { verticalAnchor: "middle" }; }, isPolar = function(viewBox) { - return Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.g)(viewBox.cx); + 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__.g)(width) && Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.g)(height)) { - if (Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.g)(x) && Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.g)(y)) return { + 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__.g)(top) && Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.g)(left)) return { + 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__.g)(x) && Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.g)(y) ? { + 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__.g)(cx) && Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.g)(cy) ? { + } : 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, @@ -2004,7 +2016,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { 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__.f)(label) ? __WEBPACK_IMPORTED_MODULE_3_react___default.a.createElement(Label, { + }) : 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 @@ -2030,9 +2042,15 @@ var _bundleJs = []byte((((((((((`!function(modules) { }; 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__(188); + 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() { @@ -2040,13 +2058,13 @@ var _bundleJs = []byte((((((((((`!function(modules) { }), __webpack_require__.d(__webpack_exports__, "d", function() { return __WEBPACK_IMPORTED_MODULE_0__src_color__.f; }); - var __WEBPACK_IMPORTED_MODULE_1__src_lab__ = __webpack_require__(730); + 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__(731); + 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; }); @@ -2082,7 +2100,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { })); })) : null; } - var __WEBPACK_IMPORTED_MODULE_0_lodash_isObject__ = __webpack_require__(31), __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__(781), __WEBPACK_IMPORTED_MODULE_3_lodash_last___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_3_lodash_last__), __WEBPACK_IMPORTED_MODULE_4_lodash_isArray__ = __webpack_require__(12), __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__(43), __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) { + 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]); @@ -2166,7 +2184,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { } }), superClass && (Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass); } - var __WEBPACK_IMPORTED_MODULE_0_lodash_sortBy__ = __webpack_require__(281), __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__(329), __WEBPACK_IMPORTED_MODULE_2_lodash_range___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_2_lodash_range__), __WEBPACK_IMPORTED_MODULE_3_lodash_throttle__ = __webpack_require__(790), __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__(78), __WEBPACK_IMPORTED_MODULE_9__container_Layer__ = __webpack_require__(14), __WEBPACK_IMPORTED_MODULE_10__component_Tooltip__ = __webpack_require__(122), __WEBPACK_IMPORTED_MODULE_11__component_Legend__ = __webpack_require__(171), __WEBPACK_IMPORTED_MODULE_12__shape_Curve__ = __webpack_require__(66), __WEBPACK_IMPORTED_MODULE_13__shape_Cross__ = __webpack_require__(323), __WEBPACK_IMPORTED_MODULE_14__shape_Sector__ = __webpack_require__(128), __WEBPACK_IMPORTED_MODULE_15__shape_Dot__ = __webpack_require__(57), __WEBPACK_IMPORTED_MODULE_16__shape_Rectangle__ = __webpack_require__(65), __WEBPACK_IMPORTED_MODULE_17__util_ReactUtils__ = __webpack_require__(4), __WEBPACK_IMPORTED_MODULE_18__cartesian_CartesianAxis__ = __webpack_require__(330), __WEBPACK_IMPORTED_MODULE_19__cartesian_Brush__ = __webpack_require__(328), __WEBPACK_IMPORTED_MODULE_20__util_DOMUtils__ = __webpack_require__(184), __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__(791), _extends = Object.assign || function(target) { + 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]); @@ -2204,7 +2222,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { props: props }, defaultState, { updateId: 0 - }))), _this.uniqueChartId = __WEBPACK_IMPORTED_MODULE_4_lodash_isNil___default()(props.id) ? Object(__WEBPACK_IMPORTED_MODULE_21__util_DataUtils__.j)("recharts") : props.id, + }))), _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; } @@ -2289,7 +2307,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { 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__.d)(domain); + 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 ]); }, [])); @@ -2908,7 +2926,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { 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__.g)(dataStartIndex) && Object(__WEBPACK_IMPORTED_MODULE_21__util_DataUtils__.g)(dataEndIndex) ? data.slice(dataStartIndex, dataEndIndex + 1) : []; + 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) { @@ -3110,10 +3128,10 @@ var _bundleJs = []byte((((((((((`!function(modules) { 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__.g)(props.x) ? props.x : offset.left, - y: Object(__WEBPACK_IMPORTED_MODULE_21__util_DataUtils__.g)(props.y) ? props.y : offset.top, - width: Object(__WEBPACK_IMPORTED_MODULE_21__util_DataUtils__.g)(props.width) ? props.width : offset.width, - height: Object(__WEBPACK_IMPORTED_MODULE_21__util_DataUtils__.g)(props.height) ? props.height : offset.height, + 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, @@ -3143,9 +3161,9 @@ var _bundleJs = []byte((((((((((`!function(modules) { 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__.g)(element.props.x) ? element.props.x : offset.left, - y: Object(__WEBPACK_IMPORTED_MODULE_21__util_DataUtils__.g)(element.props.y) ? element.props.y : offset.top + offset.height + offset.brushBottom - (margin.bottom || 0), - width: Object(__WEBPACK_IMPORTED_MODULE_21__util_DataUtils__.g)(element.props.width) ? element.props.width : offset.width, + 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 @@ -3186,7 +3204,42 @@ var _bundleJs = []byte((((((((((`!function(modules) { }; __webpack_exports__.a = generateCategoricalChart; }, function(module, exports, __webpack_require__) { - var aFunction = __webpack_require__(206); + "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) { @@ -3228,17 +3281,11 @@ var _bundleJs = []byte((((((((((`!function(modules) { module.exports = function(it, key) { return hasOwnProperty.call(it, key); }; -}, 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__) { + module.exports = { + default: __webpack_require__(421), + __esModule: !0 + }; }, function(module, exports, __webpack_require__) { "use strict"; (function(process) { @@ -3247,9 +3294,9 @@ var _bundleJs = []byte((((((((((`!function(modules) { default: obj }; } - function capitalizeFirstLetter(string) { - return "production" !== process.env.NODE_ENV && (0, _warning2.default)("string" == typeof string, "Material-UI: capitalizeFirstLetter(string) expects a string argument."), - string.charAt(0).toUpperCase() + string.slice(1); + 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) { @@ -3283,9 +3330,9 @@ var _bundleJs = []byte((((((((((`!function(modules) { Object.defineProperty(exports, "__esModule", { value: !0 }); - var _typeof2 = __webpack_require__(100), _typeof3 = _interopRequireDefault(_typeof2), _keys = __webpack_require__(41), _keys2 = _interopRequireDefault(_keys); - exports.capitalizeFirstLetter = capitalizeFirstLetter, exports.contains = contains, - exports.findIndex = findIndex, exports.find = find, exports.createChainedFunction = createChainedFunction; + 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__) { @@ -3293,7 +3340,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { var value = getValue(object, key); return baseIsNative(value) ? value : void 0; } - var baseIsNative = __webpack_require__(562), getValue = __webpack_require__(565); + var baseIsNative = __webpack_require__(611), getValue = __webpack_require__(614); module.exports = getNative; }, function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -3302,6 +3349,19 @@ var _bundleJs = []byte((((((((((`!function(modules) { 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) { @@ -3327,7 +3387,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { } }), 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__(686), __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__(184), _extends = Object.assign || function(target) { + 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]); @@ -3427,8 +3487,8 @@ var _bundleJs = []byte((((((((((`!function(modules) { 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__.f)(textProps.x) || !Object(__WEBPACK_IMPORTED_MODULE_5__util_DataUtils__.f)(textProps.y)) return null; - var x = textProps.x + (Object(__WEBPACK_IMPORTED_MODULE_5__util_DataUtils__.g)(dx) ? dx : 0), y = textProps.y + (Object(__WEBPACK_IMPORTED_MODULE_5__util_DataUtils__.g)(dy) ? dy : 0), startDy = void 0; + 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 + ")"); @@ -3547,12 +3607,12 @@ var _bundleJs = []byte((((((((((`!function(modules) { }, _class = _temp)) || _class; __webpack_exports__.a = Dot; }, function(module, exports, __webpack_require__) { - var IObject = __webpack_require__(135), defined = __webpack_require__(137); + 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__(137); + var defined = __webpack_require__(148); module.exports = function(it) { return Object(defined(it)); }; @@ -3591,7 +3651,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { return protoProps && defineProperties(Constructor.prototype, protoProps), staticProps && defineProperties(Constructor, staticProps), Constructor; }; - }(), _warning = __webpack_require__(11), _warning2 = _interopRequireDefault(_warning), _toCss = __webpack_require__(153), _toCss2 = _interopRequireDefault(_toCss), _toCssValue = __webpack_require__(105), _toCssValue2 = _interopRequireDefault(_toCssValue), StyleRule = function() { + }(), _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; @@ -3600,22 +3660,24 @@ var _bundleJs = []byte((((((((((`!function(modules) { } return _createClass(StyleRule, [ { key: "prop", - value: function(name, nextValue) { - if (null != nextValue) { - if (this.style[name] !== nextValue) if (nextValue = this.options.jss.plugins.onChangeValue(nextValue, name, this), - this.style[name] = nextValue, this.renderable) this.renderer.setStyle(this.renderable, name, nextValue); else { - var sheet = this.options.sheet; - sheet && sheet.attached && (0, _warning2.default)(!1, 'Rule is not linked. Missing sheet option "link: true".'); - } - return this; - } - return this.style[name]; + 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.setStyle(renderable, prop, json[prop]); + for (var prop in json) this.renderer.setProperty(renderable, prop, json[prop]); return this; } }, { @@ -3653,69 +3715,11 @@ var _bundleJs = []byte((((((((((`!function(modules) { } ]), StyleRule; }(); exports.default = StyleRule; -}, 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, exports, __webpack_require__) { function isSymbol(value) { return "symbol" == typeof value || isObjectLike(value) && baseGetTag(value) == symbolTag; } - var baseGetTag = __webpack_require__(42), isObjectLike = __webpack_require__(36), symbolTag = "[object Symbol]"; + var baseGetTag = __webpack_require__(41), isObjectLike = __webpack_require__(42), symbolTag = "[object Symbol]"; module.exports = isSymbol; }, function(module, exports) { function identity(value) { @@ -3892,7 +3896,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { } }), superClass && (Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass); } - var _class, _class2, _temp, __WEBPACK_IMPORTED_MODULE_0_lodash_isArray__ = __webpack_require__(12), __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__(173), __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) { + 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]); @@ -3954,7 +3958,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { return d.base.y; }), lineFunction.defined(defined).curve(curveFactory), lineFunction(areaPoints); } - return lineFunction = "vertical" === layout && Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.g)(baseLine) ? Object(__WEBPACK_IMPORTED_MODULE_4_d3_shape__.a)().y(getY).x1(getX).x0(baseLine) : Object(__WEBPACK_IMPORTED_MODULE_8__util_DataUtils__.g)(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), + 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); } }, { @@ -4210,26 +4214,6 @@ var _bundleJs = []byte((((((((((`!function(modules) { } return to; }; -}, 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) { module.exports = function(bitmap, value) { return { @@ -4240,7 +4224,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { }; }; }, function(module, exports, __webpack_require__) { - var $keys = __webpack_require__(209), enumBugKeys = __webpack_require__(141); + var $keys = __webpack_require__(226), enumBugKeys = __webpack_require__(152); module.exports = Object.keys || function(O) { return $keys(O, enumBugKeys); }; @@ -4292,13 +4276,13 @@ var _bundleJs = []byte((((((((((`!function(modules) { Object.defineProperty(exports, "__esModule", { value: !0 }), exports.keys = void 0; - var _extends2 = __webpack_require__(7), _extends3 = _interopRequireDefault(_extends2), _objectWithoutProperties2 = __webpack_require__(6), _objectWithoutProperties3 = _interopRequireDefault(_objectWithoutProperties2); + 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__(226), _getDisplayName2 = function(obj) { + var _getDisplayName = __webpack_require__(244), _getDisplayName2 = function(obj) { return obj && obj.__esModule ? obj : { default: obj }; @@ -4337,7 +4321,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { return protoProps && defineProperties(Constructor.prototype, protoProps), staticProps && defineProperties(Constructor, staticProps), Constructor; }; - }(), _createRule = __webpack_require__(106), _createRule2 = _interopRequireDefault(_createRule), _linkRule = __webpack_require__(231), _linkRule2 = _interopRequireDefault(_linkRule), _StyleRule = __webpack_require__(60), _StyleRule2 = _interopRequireDefault(_StyleRule), _escape = __webpack_require__(424), _escape2 = _interopRequireDefault(_escape), RuleList = function() { + }(), _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; @@ -4424,8 +4408,63 @@ var _bundleJs = []byte((((((((((`!function(modules) { }(); exports.default = RuleList; }, function(module, exports, __webpack_require__) { - var root = __webpack_require__(32), Symbol = root.Symbol; - module.exports = Symbol; + "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) { @@ -4469,9 +4508,12 @@ var _bundleJs = []byte((((((((((`!function(modules) { 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__(584); + 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; }); @@ -4519,18 +4561,6 @@ var _bundleJs = []byte((((((((((`!function(modules) { for (var n = series.length, o = new Array(n); --n >= 0; ) o[n] = n; return o; }; -}, function(module, exports, __webpack_require__) { - function isArrayLike(value) { - return null != value && isLength(value.length) && !isFunction(value); - } - var isFunction = __webpack_require__(8), isLength = __webpack_require__(182); - module.exports = isArrayLike; -}, 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__(669), baseMatchesProperty = __webpack_require__(672), identity = __webpack_require__(63), isArray = __webpack_require__(12), property = __webpack_require__(676); - module.exports = baseIteratee; }, function(module, __webpack_exports__, __webpack_require__) { "use strict"; function Cell() { @@ -4546,6 +4576,12 @@ var _bundleJs = []byte((((((((((`!function(modules) { }; 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) { @@ -4580,29 +4616,29 @@ var _bundleJs = []byte((((((((((`!function(modules) { }, 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__(88), __WEBPACK_IMPORTED_MODULE_2__continuous__ = __webpack_require__(126), __WEBPACK_IMPORTED_MODULE_3__tickFormat__ = __webpack_require__(742); + 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__(187); + 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__(305), __webpack_require__(190), - __webpack_require__(303), __webpack_require__(306), __webpack_require__(125)); + 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__(307), __webpack_require__(732)); + 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__(308), __webpack_require__(733), - __webpack_require__(736), __webpack_require__(302), __webpack_require__(737), __webpack_require__(738), - __webpack_require__(739), __webpack_require__(740)); + 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__(741); + __webpack_require__(882); }, function(module, __webpack_exports__, __webpack_require__) { "use strict"; function linear(a, d) { @@ -4629,7 +4665,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { 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__(304); + var __WEBPACK_IMPORTED_MODULE_0__constant__ = __webpack_require__(348); }, function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_exports__.a = function(s) { @@ -4824,7 +4860,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { }, function(module, exports, __webpack_require__) { "use strict"; (function(process) { - var emptyFunction = __webpack_require__(39), warning = emptyFunction; + 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]; @@ -4837,7 +4873,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { } catch (x) {} }; warning = function(condition, format) { - if (void 0 === format) throw new Error("` + "`")) + (`warning(condition, format, ...args)` + ("`" + ` requires a warning message argument"); + 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)); @@ -4859,7 +4895,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { } } } - "production" === process.env.NODE_ENV ? (checkDCE(), module.exports = __webpack_require__(334)) : module.exports = __webpack_require__(337); + "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"; @@ -4877,10 +4913,12 @@ var _bundleJs = []byte((((((((((`!function(modules) { var hasOwnProperty = Object.prototype.hasOwnProperty; module.exports = shallowEqual; }, function(module, exports, __webpack_require__) { - var toInteger = __webpack_require__(138), min = Math.min; + 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) { @@ -4896,7 +4934,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { }; } exports.__esModule = !0; - var _iterator = __webpack_require__(352), _iterator2 = _interopRequireDefault(_iterator), _symbol = __webpack_require__(360), _symbol2 = _interopRequireDefault(_symbol), _typeof = "function" == typeof _symbol2.default && "symbol" == typeof _iterator2.default ? function(obj) { + 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; @@ -4907,9 +4945,9 @@ var _bundleJs = []byte((((((((((`!function(modules) { 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__(48), dPs = __webpack_require__(356), enumBugKeys = __webpack_require__(141), IE_PROTO = __webpack_require__(139)("IE_PROTO"), Empty = function() {}, createDict = function() { - var iframeDocument, iframe = __webpack_require__(208)("iframe"), i = enumBugKeys.length; - for (iframe.style.display = "none", __webpack_require__(357).appendChild(iframe), + 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(" + + + + + +
Loading...
+ + + +`) diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go new file mode 100644 index 0000000000..d63418398a --- /dev/null +++ b/graphql/graphql_test.go @@ -0,0 +1,29 @@ +// 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 + +import ( + "testing" +) + +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/graphql/schema.go b/graphql/schema.go new file mode 100644 index 0000000000..c1ba87d2d6 --- /dev/null +++ b/graphql/schema.go @@ -0,0 +1,305 @@ +// 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. + 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 beenn 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!]! + } + + # 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 operationn. + 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 + } + + type Query { + # Account fetches an Ethereum account at the specified block number. + # If blockNumber is not provided, it defaults to the most recent block. + account(address: Address!, blockNumber: Long): Account! + # 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!]! + # Transaction returns a transaction specified by its hash. + transaction(hash: Bytes32!): Transaction + # Call executes a local call operation. If blockNumber is not specified, + # it defaults to the most recent known block. + call(data: CallData!, blockNumber: Long): CallResult + # EstimateGas estimates the amount of gas that will be required for + # successful execution of a transaction. If blockNumber is not specified, + # it defaults ot the most recent known block. + estimateGas(data: CallData!, blockNumber: Long): Long! + # 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/interfaces.go b/interfaces.go index 1ae1eba48a..1ff31f96b6 100644 --- a/interfaces.go +++ b/interfaces.go @@ -131,6 +131,7 @@ type ContractCaller interface { // FilterQuery contains options for contract log filtering. type FilterQuery struct { + BlockHash *common.Hash // used by eth_getLogs, return logs only from block with this hash FromBlock *big.Int // beginning of the queried range, nil means genesis block ToBlock *big.Int // end of the range, nil means latest block Addresses []common.Address // restricts matches to events created by specific contracts @@ -143,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/internal/build/azure.go b/internal/build/azure.go index 2081a9a0b1..086dff2c4a 100644 --- a/internal/build/azure.go +++ b/internal/build/azure.go @@ -17,10 +17,12 @@ package build import ( + "context" "fmt" + "net/url" "os" - storage "github.com/Azure/azure-storage-go" + "github.com/Azure/azure-storage-blob-go/2018-03-28/azblob" ) // AzureBlobstoreConfig is an authentication and configuration struct containing @@ -43,11 +45,14 @@ func AzureBlobstoreUpload(path string, name string, config AzureBlobstoreConfig) return nil } // Create an authenticated client against the Azure cloud - rawClient, err := storage.NewBasicClient(config.Account, config.Token) - if err != nil { - return err - } - client := rawClient.GetBlobService() + credential := azblob.NewSharedKeyCredential(config.Account, config.Token) + pipeline := azblob.NewPipeline(credential, azblob.PipelineOptions{}) + + u, _ := url.Parse(fmt.Sprintf("https://%s.blob.core.windows.net", config.Account)) + service := azblob.NewServiceURL(*u, pipeline) + + container := service.NewContainerURL(config.Container) + blockblob := container.NewBlockBlobURL(name) // Stream the file to upload into the designated blobstore container in, err := os.Open(path) @@ -56,38 +61,33 @@ func AzureBlobstoreUpload(path string, name string, config AzureBlobstoreConfig) } defer in.Close() - info, err := in.Stat() - if err != nil { - return err - } - return client.CreateBlockBlobFromReader(config.Container, name, uint64(info.Size()), in, nil) + _, err = blockblob.Upload(context.Background(), in, azblob.BlobHTTPHeaders{}, azblob.Metadata{}, azblob.BlobAccessConditions{}) + return err } // AzureBlobstoreList lists all the files contained within an azure blobstore. -func AzureBlobstoreList(config AzureBlobstoreConfig) ([]storage.Blob, error) { - // Create an authenticated client against the Azure cloud - rawClient, err := storage.NewBasicClient(config.Account, config.Token) - if err != nil { - return nil, err - } - client := rawClient.GetBlobService() +func AzureBlobstoreList(config AzureBlobstoreConfig) ([]azblob.BlobItem, error) { + credential := azblob.NewSharedKeyCredential(config.Account, config.Token) + pipeline := azblob.NewPipeline(credential, azblob.PipelineOptions{}) + + u, _ := url.Parse(fmt.Sprintf("https://%s.blob.core.windows.net", config.Account)) + service := azblob.NewServiceURL(*u, pipeline) // List all the blobs from the container and return them - container := client.GetContainerReference(config.Container) + container := service.NewContainerURL(config.Container) - blobs, err := container.ListBlobs(storage.ListBlobsParameters{ + res, err := container.ListBlobsFlatSegment(context.Background(), azblob.Marker{}, azblob.ListBlobsSegmentOptions{ MaxResults: 1024 * 1024 * 1024, // Yes, fetch all of them - Timeout: 3600, // Yes, wait for all of them }) if err != nil { return nil, err } - return blobs.Blobs, nil + return res.Segment.BlobItems, nil } // AzureBlobstoreDelete iterates over a list of files to delete and removes them // from the blobstore. -func AzureBlobstoreDelete(config AzureBlobstoreConfig, blobs []storage.Blob) error { +func AzureBlobstoreDelete(config AzureBlobstoreConfig, blobs []azblob.BlobItem) error { if *DryRunFlag { for _, blob := range blobs { fmt.Printf("would delete %s (%s) from %s/%s\n", blob.Name, blob.Properties.LastModified, config.Account, config.Container) @@ -95,15 +95,18 @@ func AzureBlobstoreDelete(config AzureBlobstoreConfig, blobs []storage.Blob) err return nil } // Create an authenticated client against the Azure cloud - rawClient, err := storage.NewBasicClient(config.Account, config.Token) - if err != nil { - return err - } - client := rawClient.GetBlobService() + credential := azblob.NewSharedKeyCredential(config.Account, config.Token) + pipeline := azblob.NewPipeline(credential, azblob.PipelineOptions{}) + + u, _ := url.Parse(fmt.Sprintf("https://%s.blob.core.windows.net", config.Account)) + service := azblob.NewServiceURL(*u, pipeline) + + container := service.NewContainerURL(config.Container) // Iterate over the blobs and delete them for _, blob := range blobs { - if err := client.DeleteBlob(config.Container, blob.Name, nil); err != nil { + blockblob := container.NewBlockBlobURL(blob.Name) + if _, err := blockblob.Delete(context.Background(), azblob.DeleteSnapshotsOptionInclude, azblob.BlobAccessConditions{}); err != nil { return err } } diff --git a/internal/build/env.go b/internal/build/env.go index c9848bf82c..b553e0ed80 100644 --- a/internal/build/env.go +++ b/internal/build/env.go @@ -94,7 +94,7 @@ func LocalEnv() Environment { } if env.Branch == "" { if head != "HEAD" { - env.Branch = strings.TrimLeft(head, "refs/heads/") + env.Branch = strings.TrimPrefix(head, "refs/heads/") } } if info, err := os.Stat(".git/objects"); err == nil && info.IsDir() && env.Tag == "" { diff --git a/internal/build/pgp.go b/internal/build/pgp.go index 79ab9c06f1..c7d0d23397 100644 --- a/internal/build/pgp.go +++ b/internal/build/pgp.go @@ -57,3 +57,15 @@ func PGPSignFile(input string, output string, pgpkey string) error { // Generate the signature and return return openpgp.ArmoredDetachSign(out, keys[0], in, nil) } + +// PGPKeyID parses an armored key and returns the key ID. +func PGPKeyID(pgpkey string) (string, error) { + keys, err := openpgp.ReadArmoredKeyRing(bytes.NewBufferString(pgpkey)) + if err != nil { + return "", err + } + if len(keys) != 1 { + return "", fmt.Errorf("key count mismatch: have %d, want %d", len(keys), 1) + } + return keys[0].PrimaryKey.KeyIdString(), nil +} diff --git a/internal/build/util.go b/internal/build/util.go index c6e059f0df..b34371c2dd 100644 --- a/internal/build/util.go +++ b/internal/build/util.go @@ -60,15 +60,6 @@ func GOPATH() string { return os.Getenv("GOPATH") } -// VERSION returns the content of the VERSION file. -func VERSION() string { - version, err := ioutil.ReadFile("VERSION") - if err != nil { - log.Fatal(err) - } - return string(bytes.TrimSpace(version)) -} - var warnedAboutGit bool // RunGit runs a git subcommand and returns its output. @@ -152,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.8/bin/go run build/ci.go ... +// /usr/lib/go-1.12/bin/go run build/ci.go ... // -// runs using go 1.8 and invokes go 1.8 tools from the same GOROOT. This is also important +// runs using go 1.12 and invokes go 1.12 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...) @@ -186,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/internal/cmdtest/test_cmd.go b/internal/cmdtest/test_cmd.go index fae61cfe32..f8b1b43c01 100644 --- a/internal/cmdtest/test_cmd.go +++ b/internal/cmdtest/test_cmd.go @@ -1,18 +1,18 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of go-ethereum. +// Copyright 2017 The go-ethereum Authors +// This file is part of the go-ethereum library. // -// 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 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. // -// go-ethereum is distributed in the hope that it will be useful, +// 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 General Public License for more details. +// GNU Lesser 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 . +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . package cmdtest @@ -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/internal/debug/api.go b/internal/debug/api.go index 3547b05641..86a4218f6a 100644 --- a/internal/debug/api.go +++ b/internal/debug/api.go @@ -21,6 +21,7 @@ package debug import ( + "bytes" "errors" "io" "os" @@ -140,10 +141,9 @@ func (h *HandlerT) GoTrace(file string, nsec uint) error { return nil } -// BlockProfile turns on CPU profiling for nsec seconds and writes -// profile data to file. It uses a profile rate of 1 for most accurate -// information. If a different rate is desired, set the rate -// and write the profile manually. +// BlockProfile turns on goroutine profiling for nsec seconds and writes profile data to +// file. It uses a profile rate of 1 for most accurate information. If a different rate is +// desired, set the rate and write the profile manually. func (*HandlerT) BlockProfile(file string, nsec uint) error { runtime.SetBlockProfileRate(1) time.Sleep(time.Duration(nsec) * time.Second) @@ -162,6 +162,26 @@ func (*HandlerT) WriteBlockProfile(file string) error { return writeProfile("block", file) } +// MutexProfile turns on mutex profiling for nsec seconds and writes profile data to file. +// It uses a profile rate of 1 for most accurate information. If a different rate is +// desired, set the rate and write the profile manually. +func (*HandlerT) MutexProfile(file string, nsec uint) error { + runtime.SetMutexProfileFraction(1) + time.Sleep(time.Duration(nsec) * time.Second) + defer runtime.SetMutexProfileFraction(0) + return writeProfile("mutex", file) +} + +// SetMutexProfileFraction sets the rate of mutex profiling. +func (*HandlerT) SetMutexProfileFraction(rate int) { + runtime.SetMutexProfileFraction(rate) +} + +// WriteMutexProfile writes a goroutine blocking profile to the given file. +func (*HandlerT) WriteMutexProfile(file string) error { + return writeProfile("mutex", file) +} + // WriteMemProfile writes an allocation profile to the given file. // Note that the profiling rate cannot be set through the API, // it must be set on the command line. @@ -171,9 +191,9 @@ func (*HandlerT) WriteMemProfile(file string) error { // Stacks returns a printed representation of the stacks of all goroutines. func (*HandlerT) Stacks() string { - buf := make([]byte, 1024*1024) - buf = buf[:runtime.Stack(buf, true)] - return string(buf) + buf := new(bytes.Buffer) + pprof.Lookup("goroutine").WriteTo(buf, 2) + return buf.String() } // FreeOSMemory returns unused memory to the OS. diff --git a/internal/debug/flags.go b/internal/debug/flags.go index 6247cc7dc0..46c8fe9f80 100644 --- a/internal/debug/flags.go +++ b/internal/debug/flags.go @@ -25,11 +25,16 @@ import ( "runtime" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/log/term" + "github.com/ethereum/go-ethereum/metrics" + "github.com/ethereum/go-ethereum/metrics/exp" + "github.com/fjl/memsize/memsizeui" colorable "github.com/mattn/go-colorable" + "github.com/mattn/go-isatty" "gopkg.in/urfave/cli.v1" ) +var Memsize memsizeui.Handler + var ( verbosityFlag = cli.IntFlag{ Name: "verbosity", @@ -90,22 +95,37 @@ var Flags = []cli.Flag{ memprofilerateFlag, blockprofilerateFlag, cpuprofileFlag, traceFlag, } -var glogger *log.GlogHandler +var ( + ostream log.Handler + glogger *log.GlogHandler +) func init() { - usecolor := term.IsTty(os.Stderr.Fd()) && os.Getenv("TERM") != "dumb" + usecolor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb" output := io.Writer(os.Stderr) if usecolor { output = colorable.NewColorableStderr() } - glogger = log.NewGlogHandler(log.StreamHandler(output, log.TerminalFormat(usecolor))) + ostream = log.StreamHandler(output, log.TerminalFormat(usecolor)) + glogger = log.NewGlogHandler(ostream) } // Setup initializes profiling and logging based on the CLI flags. // It should be called as early as possible in the program. -func Setup(ctx *cli.Context) error { +func Setup(ctx *cli.Context, logdir string) error { // logging log.PrintOrigins(ctx.GlobalBool(debugFlag.Name)) + if logdir != "" { + rfh, err := log.RotatingFileHandler( + logdir, + 262144, + log.JSONFormatOrderedEx(false, true), + ) + if err != nil { + return err + } + glogger.SetHandler(log.MultiHandler(ostream, rfh)) + } glogger.Verbosity(log.Lvl(ctx.GlobalInt(verbosityFlag.Name))) glogger.Vmodule(ctx.GlobalString(vmoduleFlag.Name)) glogger.BacktraceAt(ctx.GlobalString(backtraceAtFlag.Name)) @@ -128,16 +148,24 @@ func Setup(ctx *cli.Context) error { // pprof server if ctx.GlobalBool(pprofFlag.Name) { address := fmt.Sprintf("%s:%d", ctx.GlobalString(pprofAddrFlag.Name), ctx.GlobalInt(pprofPortFlag.Name)) - go func() { - log.Info("Starting pprof server", "addr", fmt.Sprintf("http://%s/debug/pprof", address)) - if err := http.ListenAndServe(address, nil); err != nil { - log.Error("Failure in running pprof server", "err", err) - } - }() + StartPProf(address) } return nil } +func StartPProf(address string) { + // Hook go-metrics into expvar on any /debug/metrics request, load all vars + // from the registry into expvar, and execute regular expvar handler. + exp.Exp(metrics.DefaultRegistry) + http.Handle("/memsize/", http.StripPrefix("/memsize", &Memsize)) + log.Info("Starting pprof server", "addr", fmt.Sprintf("http://%s/debug/pprof", address)) + go func() { + if err := http.ListenAndServe(address, nil); err != nil { + log.Error("Failure in running pprof server", "err", err) + } + }() +} + // Exit stops all running profiles, flushing their output to the // respective file. func Exit() { diff --git a/internal/ethapi/addrlock.go b/internal/ethapi/addrlock.go index 5a9c948b83..61ddff688c 100644 --- a/internal/ethapi/addrlock.go +++ b/internal/ethapi/addrlock.go @@ -1,4 +1,4 @@ -// Copyright 2015 The go-ethereum Authors +// Copyright 2017 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 diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index a4cba7a4db..4d5ef27da1 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -25,13 +25,16 @@ import ( "strings" "time" + "github.com/davecgh/go-spew/spew" "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/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" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" @@ -45,7 +48,7 @@ import ( ) const ( - defaultGasPrice = 50 * params.Shannon + defaultGasPrice = params.GWei ) // PublicEthereumAPI provides an API to access Ethereum related information. @@ -60,8 +63,9 @@ func NewPublicEthereumAPI(b Backend) *PublicEthereumAPI { } // GasPrice returns a suggestion for a gas price. -func (s *PublicEthereumAPI) GasPrice(ctx context.Context) (*big.Int, error) { - return s.b.SuggestPrice(ctx) +func (s *PublicEthereumAPI) GasPrice(ctx context.Context) (*hexutil.Big, error) { + price, err := s.b.SuggestPrice(ctx) + return (*hexutil.Big)(price), err } // ProtocolVersion returns the current Ethereum protocol version this node supports @@ -214,7 +218,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() { @@ -325,6 +329,9 @@ func (s *PrivateAccountAPI) UnlockAccount(addr common.Address, password string, d = time.Duration(*duration) * time.Second } err := fetchKeystore(s.am).TimedUnlock(accounts.Account{Address: addr}, password, d) + if err != nil { + log.Warn("Failed account unlock attempt", "address", addr, "err", err) + } return err == nil, err } @@ -333,10 +340,10 @@ 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) { +func (s *PrivateAccountAPI) signTransaction(ctx context.Context, args *SendTxArgs, passwd string) (*types.Transaction, error) { // Look up the wallet containing the requested signer account := accounts.Account{Address: args.From} wallet, err := s.am.Find(account) @@ -350,11 +357,7 @@ func (s *PrivateAccountAPI) signTransaction(ctx context.Context, args SendTxArgs // 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 @@ -367,11 +370,12 @@ func (s *PrivateAccountAPI) SendTransaction(ctx context.Context, args SendTxArgs s.nonceLock.LockAddr(args.From) defer s.nonceLock.UnlockAddr(args.From) } - signed, err := s.signTransaction(ctx, args, passwd) + signed, err := s.signTransaction(ctx, &args, passwd) if err != nil { + 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 @@ -390,8 +394,9 @@ func (s *PrivateAccountAPI) SignTransaction(ctx context.Context, args SendTxArgs if args.Nonce == nil { return nil, fmt.Errorf("nonce not specified") } - signed, err := s.signTransaction(ctx, args, passwd) + signed, err := s.signTransaction(ctx, &args, passwd) if err != nil { + log.Warn("Failed transaction sign attempt", "from", args.From, "to", args.To, "value", args.Value.ToInt(), "err", err) return nil, err } data, err := rlp.EncodeToBytes(signed) @@ -401,18 +406,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)) // @@ -431,8 +424,9 @@ 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 } signature[64] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper @@ -446,7 +440,7 @@ func (s *PrivateAccountAPI) Sign(ctx context.Context, data hexutil.Bytes, addr c // 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. +// the V value must be 27 or 28 for legacy reasons. // // https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal_ecRecover func (s *PrivateAccountAPI) EcRecover(ctx context.Context, data, sig hexutil.Bytes) (common.Address, error) { @@ -458,13 +452,11 @@ 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.Ecrecover(signHash(data), sig) + rpk, err := crypto.SigToPub(accounts.TextHash(data), sig) if err != nil { return common.Address{}, err } - pubKey := crypto.ToECDSAPub(rpk) - recoveredAddr := crypto.PubkeyToAddress(*pubKey) - return recoveredAddr, nil + return crypto.PubkeyToAddress(*rpk), nil } // SignAndSendTransaction was renamed to SendTransaction. This method is deprecated @@ -485,21 +477,86 @@ func NewPublicBlockChainAPI(b Backend) *PublicBlockChainAPI { } // BlockNumber returns the block number of the chain head. -func (s *PublicBlockChainAPI) BlockNumber() *big.Int { +func (s *PublicBlockChainAPI) BlockNumber() hexutil.Uint64 { header, _ := s.b.HeaderByNumber(context.Background(), rpc.LatestBlockNumber) // latest header should always be available - return header.Number + return hexutil.Uint64(header.Number.Uint64()) } // GetBalance returns the amount of wei for the given address in the state of the // given block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta // block numbers are also allowed. -func (s *PublicBlockChainAPI) GetBalance(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (*big.Int, error) { +func (s *PublicBlockChainAPI) GetBalance(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (*hexutil.Big, error) { state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr) if state == nil || err != nil { return nil, err } - b := state.GetBalance(address) - return b, state.Error() + return (*hexutil.Big)(state.GetBalance(address)), state.Error() +} + +// Result structs for GetProof +type AccountResult struct { + Address common.Address `json:"address"` + AccountProof []string `json:"accountProof"` + Balance *hexutil.Big `json:"balance"` + CodeHash common.Hash `json:"codeHash"` + Nonce hexutil.Uint64 `json:"nonce"` + StorageHash common.Hash `json:"storageHash"` + StorageProof []StorageResult `json:"storageProof"` +} +type StorageResult struct { + Key string `json:"key"` + Value *hexutil.Big `json:"value"` + Proof []string `json:"proof"` +} + +// GetProof returns the Merkle-proof for a given account and optionally some storage keys. +func (s *PublicBlockChainAPI) GetProof(ctx context.Context, address common.Address, storageKeys []string, blockNr rpc.BlockNumber) (*AccountResult, error) { + state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr) + if state == nil || err != nil { + return nil, err + } + + storageTrie := state.StorageTrie(address) + storageHash := types.EmptyRootHash + codeHash := state.GetCodeHash(address) + storageProof := make([]StorageResult, len(storageKeys)) + + // if we have a storageTrie, (which means the account exists), we can update the storagehash + if storageTrie != nil { + storageHash = storageTrie.Hash() + } else { + // no storageTrie means the account does not exist, so the codeHash is the hash of an empty bytearray. + codeHash = crypto.Keccak256Hash(nil) + } + + // create the proof for the storageKeys + for i, key := range storageKeys { + if storageTrie != nil { + proof, storageError := state.GetStorageProof(address, common.HexToHash(key)) + if storageError != nil { + return nil, storageError + } + storageProof[i] = StorageResult{key, (*hexutil.Big)(state.GetState(address, common.HexToHash(key)).Big()), common.ToHexArray(proof)} + } else { + storageProof[i] = StorageResult{key, &hexutil.Big{}, []string{}} + } + } + + // create the accountProof + accountProof, proofErr := state.GetProof(address) + if proofErr != nil { + return nil, proofErr + } + + return &AccountResult{ + Address: address, + AccountProof: common.ToHexArray(accountProof), + Balance: (*hexutil.Big)(state.GetBalance(address)), + CodeHash: codeHash, + Nonce: hexutil.Uint64(state.GetNonce(address)), + StorageHash: storageHash, + StorageProof: storageProof, + }, state.Error() } // GetBlockByNumber returns the requested block. When blockNr is -1 the chain head is returned. When fullTx is true all @@ -603,56 +660,69 @@ 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) ([]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 = 50000000 + 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. var cancel context.CancelFunc - if vmCfg.DisableGasMetering { - ctx, cancel = context.WithTimeout(ctx, time.Second*5) + if timeout > 0 { + ctx, cancel = context.WithTimeout(ctx, timeout) } else { ctx, cancel = context.WithCancel(ctx) } // Make sure the context is cancelled when the call has completed // this makes sure resources are cleaned up. - defer func() { cancel() }() + 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 } @@ -676,24 +746,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{DisableGasMetering: true}) + 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 } @@ -703,9 +771,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{}) + _, _, failed, err := DoCall(ctx, b, args, rpc.PendingBlockNumber, vm.Config{}, 0) if err != nil || failed { return false } @@ -729,6 +797,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 @@ -753,7 +827,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 { @@ -790,10 +864,10 @@ func FormatLogs(logs []vm.StructLog) []StructLogRes { return formatted } -// rpcOutputBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are +// RPCMarshalBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are // returned. When fullTx is true the returned block contains full transaction details, otherwise it will only contain // transaction hashes. -func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { +func RPCMarshalBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { head := b.Header() // copies the header once fields := map[string]interface{}{ "number": (*hexutil.Big)(head.Number), @@ -806,9 +880,8 @@ func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx "stateRoot": head.Root, "miner": head.Coinbase, "difficulty": (*hexutil.Big)(head.Difficulty), - "totalDifficulty": (*hexutil.Big)(s.b.GetTd(b.Hash())), "extraData": hexutil.Bytes(head.Extra), - "size": hexutil.Uint64(uint64(b.Size().Int64())), + "size": hexutil.Uint64(b.Size()), "gasLimit": hexutil.Uint64(head.GasLimit), "gasUsed": hexutil.Uint64(head.GasUsed), "timestamp": (*hexutil.Big)(head.Time), @@ -820,17 +893,15 @@ func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx formatTx := func(tx *types.Transaction) (interface{}, error) { return tx.Hash(), nil } - if fullTx { formatTx = func(tx *types.Transaction) (interface{}, error) { return newRPCTransactionFromBlockHash(b, tx.Hash()), nil } } - txs := b.Transactions() transactions := make([]interface{}, len(txs)) var err error - for i, tx := range b.Transactions() { + for i, tx := range txs { if transactions[i], err = formatTx(tx); err != nil { return nil, err } @@ -848,6 +919,17 @@ func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx return fields, nil } +// rpcOutputBlock uses the generalized output filler, then adds the total difficulty field, which requires +// a `PublicBlockchainAPI`. +func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { + fields, err := RPCMarshalBlock(b, inclTx, fullTx) + if err != nil { + return nil, err + } + fields["totalDifficulty"] = (*hexutil.Big)(s.b.GetTd(b.Hash())) + return fields, err +} + // RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction type RPCTransaction struct { BlockHash common.Hash `json:"blockHash"` @@ -994,6 +1076,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 @@ -1005,7 +1096,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionCount(ctx context.Context, addr // GetTransactionByHash returns the transaction for the given hash func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) *RPCTransaction { // Try to return an already finalized transaction - if tx, blockHash, blockNumber, index := core.GetTransaction(s.b.ChainDb(), hash); tx != nil { + if tx, blockHash, blockNumber, index := rawdb.ReadTransaction(s.b.ChainDb(), hash); tx != nil { return newRPCTransaction(tx, blockHash, blockNumber, index) } // No finalized transaction, try to retrieve it from the pool @@ -1021,7 +1112,7 @@ func (s *PublicTransactionPoolAPI) GetRawTransactionByHash(ctx context.Context, var tx *types.Transaction // Retrieve a finalized transaction, or a pooled otherwise - if tx, _, _, _ = core.GetTransaction(s.b.ChainDb(), hash); tx == nil { + if tx, _, _, _ = rawdb.ReadTransaction(s.b.ChainDb(), hash); tx == nil { if tx = s.b.GetPoolTransaction(hash); tx == nil { // Transaction not found anywhere, abort return nil, nil @@ -1032,15 +1123,19 @@ func (s *PublicTransactionPoolAPI) GetRawTransactionByHash(ctx context.Context, } // GetTransactionReceipt returns the transaction receipt for the given transaction hash. -func (s *PublicTransactionPoolAPI) GetTransactionReceipt(hash common.Hash) (map[string]interface{}, error) { - tx, blockHash, blockNumber, index := core.GetTransaction(s.b.ChainDb(), hash) +func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) { + tx, blockHash, blockNumber, index := rawdb.ReadTransaction(s.b.ChainDb(), hash) if tx == nil { - return nil, errors.New("unknown transaction") + return nil, nil } - receipt, _, _, _ := core.GetReceipt(s.b.ChainDb(), hash) // Old receipts don't have the lookup data available - if receipt == nil { - return nil, errors.New("unknown receipt") + receipts, err := s.b.GetReceipts(ctx, blockHash) + if err != nil { + return nil, err } + if len(receipts) <= int(index) { + return nil, nil + } + receipt := receipts[index] var signer types.Signer = types.FrontierSigner{} if tx.Protected() { @@ -1088,11 +1183,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. @@ -1135,6 +1226,18 @@ func (args *SendTxArgs) setDefaults(ctx context.Context, b Backend) error { if args.Data != nil && args.Input != nil && !bytes.Equal(*args.Data, *args.Input) { return errors.New(`Both "data" and "input" are set and not equal. Please use "input" to pass transaction call data.`) } + if args.To == nil { + // Contract creation + var input []byte + if args.Data != nil { + input = *args.Data + } else if args.Input != nil { + input = *args.Input + } + if len(input) == 0 { + return errors.New(`contract creation without any data provided`) + } + } return nil } @@ -1151,8 +1254,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 } @@ -1196,15 +1299,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. @@ -1214,7 +1313,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: @@ -1235,7 +1334,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 } @@ -1275,14 +1374,19 @@ func (s *PublicTransactionPoolAPI) SignTransaction(ctx context.Context, args Sen return &SignTransactionResult{data, tx}, nil } -// PendingTransactions returns the transactions that are in the transaction pool and have a from address that is one of -// the accounts this node manages. +// PendingTransactions returns the transactions that are in the transaction pool +// and have a from address that is one of the accounts this node manages. func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*RPCTransaction, error) { pending, err := s.b.GetPoolTransactions() if err != nil { return nil, err } - + accounts := make(map[common.Address]struct{}) + for _, wallet := range s.b.AccountManager().Wallets() { + for _, account := range wallet.Accounts() { + accounts[account.Address] = struct{}{} + } + } transactions := make([]*RPCTransaction, 0, len(pending)) for _, tx := range pending { var signer types.Signer = types.HomesteadSigner{} @@ -1290,7 +1394,7 @@ func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*RPCTransaction, err signer = types.NewEIP155Signer(tx.ChainId()) } from, _ := types.Sender(signer, tx) - if _, err := s.b.AccountManager().Find(accounts.Account{Address: from}); err == nil { + if _, exists := accounts[from]; exists { transactions = append(transactions, newRPCPendingTransaction(tx)) } } @@ -1321,10 +1425,10 @@ func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, sendArgs SendTxAr if pFrom, err := types.Sender(signer, p); err == nil && pFrom == sendArgs.From && signer.Hash(p) == wantSigHash { // Match. Re-sign and send the transaction. - if gasPrice != nil { + if gasPrice != nil && (*big.Int)(gasPrice).Sign() != 0 { sendArgs.GasPrice = gasPrice } - if gasLimit != nil { + if gasLimit != nil && *gasLimit != 0 { sendArgs.Gas = gasLimit } signedTx, err := s.sign(sendArgs.From, sendArgs.toTransaction()) @@ -1366,13 +1470,52 @@ 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)) if block == nil { return "", fmt.Errorf("block #%d not found", number) } - return block.String(), nil + return spew.Sdump(block), nil } // SeedHash retrieves the seed hash of a block. diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index af95d7906f..e23ee03b15 100644 --- a/internal/ethapi/backend.go +++ b/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 @@ -65,7 +65,7 @@ type Backend interface { GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) Stats() (pending int, queued int) TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions) - SubscribeTxPreEvent(chan<- core.TxPreEvent) event.Subscription + SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription ChainConfig() *params.ChainConfig CurrentBlock() *types.Block diff --git a/internal/jsre/deps/web3.js b/internal/jsre/deps/web3.js index 9bb899384b..df920bb1d3 100644 --- a/internal/jsre/deps/web3.js +++ b/internal/jsre/deps/web3.js @@ -1021,7 +1021,7 @@ var formatOutputInt = function (param) { var value = param.staticPart() || "0"; // check if it's negative number - // it it is, return two's complement + // it is, return two's complement if (signedIsNegative(value)) { return new BigNumber(value, 16).minus(new BigNumber('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16)).minus(1); } @@ -2193,7 +2193,7 @@ var toWei = function(number, unit) { }; /** - * Takes an input and transforms it into an bignumber + * Takes an input and transforms it into a bignumber * * @method toBigNumber * @param {Number|String|BigNumber} a number, string, HEX string or BigNumber @@ -2250,7 +2250,7 @@ var isAddress = function (address) { // check if it has the basic requirements of an address return false; } else if (/^(0x)?[0-9a-f]{40}$/.test(address) || /^(0x)?[0-9A-F]{40}$/.test(address)) { - // If it's all small caps or all all caps, return true + // If it's all small caps or all caps, return true return true; } else { // Otherwise check each case diff --git a/internal/jsre/jsre.go b/internal/jsre/jsre.go index f05865eca6..1b3528a036 100644 --- a/internal/jsre/jsre.go +++ b/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") ) /* @@ -102,8 +102,8 @@ func randomSource() *rand.Rand { // call the functions of the otto vm directly to circumvent the queue. These // functions should be used if and only if running a routine that was already // called from JS through an RPC call. -func (self *JSRE) runEventLoop() { - defer close(self.closed) +func (re *JSRE) runEventLoop() { + defer close(re.closed) vm := otto.New() r := randomSource() @@ -202,14 +202,14 @@ loop: break loop } } - case req := <-self.evalQueue: + case req := <-re.evalQueue: // run the code, send the result back req.fn(vm) close(req.done) if waitForCallbacks && (len(registry) == 0) { break loop } - case waitForCallbacks = <-self.stopEventLoop: + case waitForCallbacks = <-re.stopEventLoop: if !waitForCallbacks || (len(registry) == 0) { break loop } @@ -223,31 +223,31 @@ loop: } // Do executes the given function on the JS event loop. -func (self *JSRE) Do(fn func(*otto.Otto)) { +func (re *JSRE) Do(fn func(*otto.Otto)) { done := make(chan bool) req := &evalReq{fn, done} - self.evalQueue <- req + re.evalQueue <- req <-done } // stops the event loop before exit, optionally waits for all timers to expire -func (self *JSRE) Stop(waitForCallbacks bool) { +func (re *JSRE) Stop(waitForCallbacks bool) { select { - case <-self.closed: - case self.stopEventLoop <- waitForCallbacks: - <-self.closed + case <-re.closed: + case re.stopEventLoop <- waitForCallbacks: + <-re.closed } } // Exec(file) loads and runs the contents of a file // if a relative path is given, the jsre's assetPath is used -func (self *JSRE) Exec(file string) error { - code, err := ioutil.ReadFile(common.AbsolutePath(self.assetPath, file)) +func (re *JSRE) Exec(file string) error { + code, err := ioutil.ReadFile(common.AbsolutePath(re.assetPath, file)) if err != nil { return err } var script *otto.Script - self.Do(func(vm *otto.Otto) { + re.Do(func(vm *otto.Otto) { script, err = vm.Compile(file, code) if err != nil { return @@ -259,36 +259,36 @@ func (self *JSRE) Exec(file string) error { // Bind assigns value v to a variable in the JS environment // This method is deprecated, use Set. -func (self *JSRE) Bind(name string, v interface{}) error { - return self.Set(name, v) +func (re *JSRE) Bind(name string, v interface{}) error { + return re.Set(name, v) } // Run runs a piece of JS code. -func (self *JSRE) Run(code string) (v otto.Value, err error) { - self.Do(func(vm *otto.Otto) { v, err = vm.Run(code) }) +func (re *JSRE) Run(code string) (v otto.Value, err error) { + re.Do(func(vm *otto.Otto) { v, err = vm.Run(code) }) return v, err } // Get returns the value of a variable in the JS environment. -func (self *JSRE) Get(ns string) (v otto.Value, err error) { - self.Do(func(vm *otto.Otto) { v, err = vm.Get(ns) }) +func (re *JSRE) Get(ns string) (v otto.Value, err error) { + re.Do(func(vm *otto.Otto) { v, err = vm.Get(ns) }) return v, err } // Set assigns value v to a variable in the JS environment. -func (self *JSRE) Set(ns string, v interface{}) (err error) { - self.Do(func(vm *otto.Otto) { err = vm.Set(ns, v) }) +func (re *JSRE) Set(ns string, v interface{}) (err error) { + re.Do(func(vm *otto.Otto) { err = vm.Set(ns, v) }) return err } // loadScript executes a JS script from inside the currently executing JS code. -func (self *JSRE) loadScript(call otto.FunctionCall) otto.Value { +func (re *JSRE) loadScript(call otto.FunctionCall) otto.Value { file, err := call.Argument(0).ToString() if err != nil { // TODO: throw exception return otto.FalseValue() } - file = common.AbsolutePath(self.assetPath, file) + file = common.AbsolutePath(re.assetPath, file) source, err := ioutil.ReadFile(file) if err != nil { // TODO: throw exception @@ -305,10 +305,10 @@ func (self *JSRE) loadScript(call otto.FunctionCall) otto.Value { // Evaluate executes code and pretty prints the result to the specified output // stream. -func (self *JSRE) Evaluate(code string, w io.Writer) error { +func (re *JSRE) Evaluate(code string, w io.Writer) error { var fail error - self.Do(func(vm *otto.Otto) { + re.Do(func(vm *otto.Otto) { val, err := vm.Run(code) if err != nil { prettyError(vm, err, w) @@ -321,8 +321,8 @@ func (self *JSRE) Evaluate(code string, w io.Writer) error { } // Compile compiles and then runs a piece of JS code. -func (self *JSRE) Compile(filename string, src interface{}) (err error) { - self.Do(func(vm *otto.Otto) { _, err = compileAndRun(vm, filename, src) }) +func (re *JSRE) Compile(filename string, src interface{}) (err error) { + re.Do(func(vm *otto.Otto) { _, err = compileAndRun(vm, filename, src) }) return err } diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index a6b81b4c2a..e1577fe2f8 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -18,21 +18,23 @@ package web3ext var Modules = map[string]string{ - "admin": Admin_JS, - "chequebook": Chequebook_JS, - "clique": Clique_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: [ @@ -63,7 +65,7 @@ web3._extend({ }); ` -const Clique_JS = ` +const CliqueJs = ` web3._extend({ property: 'clique', methods: [ @@ -109,7 +111,35 @@ web3._extend({ }); ` -const Admin_JS = ` +const EthashJs = ` +web3._extend({ + property: 'ethash', + methods: [ + new web3._extend.Method({ + name: 'getWork', + call: 'ethash_getWork', + params: 0 + }), + new web3._extend.Method({ + name: 'getHashrate', + call: 'ethash_getHashrate', + params: 0 + }), + new web3._extend.Method({ + name: 'submitWork', + call: 'ethash_submitWork', + params: 3, + }), + new web3._extend.Method({ + name: 'submitHashRate', + call: 'ethash_submitHashRate', + params: 2, + }), + ] +}); +` + +const AdminJs = ` web3._extend({ property: 'admin', methods: [ @@ -123,6 +153,16 @@ web3._extend({ call: 'admin_removePeer', params: 1 }), + new web3._extend.Method({ + name: 'addTrustedPeer', + call: 'admin_addTrustedPeer', + params: 1 + }), + new web3._extend.Method({ + name: 'removeTrustedPeer', + call: 'admin_removeTrustedPeer', + params: 1 + }), new web3._extend.Method({ name: 'exportChain', call: 'admin_exportChain', @@ -177,7 +217,7 @@ web3._extend({ }); ` -const Debug_JS = ` +const DebugJs = ` web3._extend({ property: 'debug', methods: [ @@ -191,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', @@ -307,6 +353,21 @@ web3._extend({ call: 'debug_writeBlockProfile', params: 1 }), + new web3._extend.Method({ + name: 'mutexProfile', + call: 'debug_mutexProfile', + params: 2 + }), + new web3._extend.Method({ + name: 'setMutexProfileFraction', + call: 'debug_setMutexProfileFraction', + params: 1 + }), + new web3._extend.Method({ + name: 'writeMutexProfile', + call: 'debug_writeMutexProfile', + params: 1 + }), new web3._extend.Method({ name: 'writeMemProfile', call: 'debug_writeMemProfile', @@ -324,6 +385,24 @@ web3._extend({ params: 2, inputFormatter: [null, null] }), + new web3._extend.Method({ + name: 'traceBadBlock', + call: 'debug_traceBadBlock', + 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', @@ -375,10 +454,15 @@ web3._extend({ }); ` -const Eth_JS = ` +const EthJs = ` web3._extend({ property: 'eth', methods: [ + new web3._extend.Method({ + name: 'chainId', + call: 'eth_chainId', + params: 0 + }), new web3._extend.Method({ name: 'sign', call: 'eth_sign', @@ -416,6 +500,12 @@ web3._extend({ params: 2, inputFormatter: [web3._extend.formatters.inputBlockNumberFormatter, web3._extend.utils.toHex] }), + new web3._extend.Method({ + name: 'getProof', + call: 'eth_getProof', + params: 3, + inputFormatter: [web3._extend.formatters.inputAddressFormatter, null, web3._extend.formatters.inputBlockNumberFormatter] + }), ], properties: [ new web3._extend.Property({ @@ -434,7 +524,7 @@ web3._extend({ }); ` -const Miner_JS = ` +const MinerJs = ` web3._extend({ property: 'miner', methods: [ @@ -465,6 +555,11 @@ web3._extend({ params: 1, inputFormatter: [web3._extend.utils.fromDecimal] }), + new web3._extend.Method({ + name: 'setRecommitInterval', + call: 'miner_setRecommitInterval', + params: 1, + }), new web3._extend.Method({ name: 'getHashrate', call: 'miner_getHashrate' @@ -474,7 +569,7 @@ web3._extend({ }); ` -const Net_JS = ` +const NetJs = ` web3._extend({ property: 'net', methods: [], @@ -487,7 +582,7 @@ web3._extend({ }); ` -const Personal_JS = ` +const PersonalJs = ` web3._extend({ property: 'personal', methods: [ @@ -533,7 +628,7 @@ web3._extend({ }) ` -const RPC_JS = ` +const RpcJs = ` web3._extend({ property: 'rpc', methods: [], @@ -546,7 +641,7 @@ web3._extend({ }); ` -const Shh_JS = ` +const ShhJs = ` web3._extend({ property: 'shh', methods: [ @@ -566,7 +661,7 @@ web3._extend({ }); ` -const SWARMFS_JS = ` +const SwarmfsJs = ` web3._extend({ property: 'swarmfs', methods: @@ -590,7 +685,7 @@ web3._extend({ }); ` -const TxPool_JS = ` +const TxpoolJs = ` web3._extend({ property: 'txpool', methods: [], @@ -616,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/les/api.go b/les/api.go new file mode 100644 index 0000000000..a933cbd068 --- /dev/null +++ b/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/les/api_backend.go b/les/api_backend.go index 56f617a7db..7531396235 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -25,6 +25,7 @@ import ( "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/bloombits" + "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" @@ -59,10 +60,13 @@ func (b *LesApiBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNum if blockNr == rpc.LatestBlockNumber || blockNr == rpc.PendingBlockNumber { return b.eth.blockchain.CurrentHeader(), nil } - return b.eth.blockchain.GetHeaderByNumberOdr(ctx, uint64(blockNr)) } +func (b *LesApiBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { + return b.eth.blockchain.GetHeaderByHash(hash), nil +} + func (b *LesApiBackend) BlockByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Block, error) { header, err := b.HeaderByNumber(ctx, blockNr) if header == nil || err != nil { @@ -83,18 +87,28 @@ func (b *LesApiBackend) GetBlock(ctx context.Context, blockHash common.Hash) (*t return b.eth.blockchain.GetBlockByHash(ctx, blockHash) } -func (b *LesApiBackend) GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) { - return light.GetBlockReceipts(ctx, b.eth.odr, blockHash, core.GetBlockNumber(b.eth.chainDb, blockHash)) +func (b *LesApiBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { + if number := rawdb.ReadHeaderNumber(b.eth.chainDb, hash); number != nil { + return light.GetBlockReceipts(ctx, b.eth.odr, hash, *number) + } + return nil, nil } -func (b *LesApiBackend) GetTd(blockHash common.Hash) *big.Int { - return b.eth.blockchain.GetTdByHash(blockHash) +func (b *LesApiBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) { + if number := rawdb.ReadHeaderNumber(b.eth.chainDb, hash); number != nil { + return light.GetBlockLogs(ctx, b.eth.odr, hash, *number) + } + return nil, nil } -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) 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) (*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 { @@ -125,8 +139,8 @@ func (b *LesApiBackend) TxPoolContent() (map[common.Address]types.Transactions, return b.eth.txPool.Content() } -func (b *LesApiBackend) SubscribeTxPreEvent(ch chan<- core.TxPreEvent) event.Subscription { - return b.eth.txPool.SubscribeTxPreEvent(ch) +func (b *LesApiBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription { + return b.eth.txPool.SubscribeNewTxsEvent(ch) } func (b *LesApiBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { @@ -178,7 +192,7 @@ func (b *LesApiBackend) BloomStatus() (uint64, uint64) { return 0, 0 } sections, _, _ := b.eth.bloomIndexer.Sections() - return light.BloomTrieFrequency, sections + return params.BloomBitsBlocksClient, sections } func (b *LesApiBackend) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) { diff --git a/les/api_test.go b/les/api_test.go new file mode 100644 index 0000000000..cec9459625 --- /dev/null +++ b/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/les/backend.go b/les/backend.go index 798e44e85c..67ddf17e4c 100644 --- a/les/backend.go +++ b/les/backend.go @@ -25,15 +25,16 @@ 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" + "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/eth/downloader" "github.com/ethereum/go-ethereum/eth/filters" "github.com/ethereum/go-ethereum/eth/gasprice" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/light" @@ -46,24 +47,24 @@ import ( ) type LightEthereum struct { + lesCommons + odr *LesOdr relay *LesTxRelay chainConfig *params.ChainConfig // Channel for shutting down the service shutdownChan chan bool - // Handlers - peers *peerSet - txPool *light.TxPool - blockchain *light.LightChain - protocolManager *ProtocolManager - serverPool *serverPool - reqDist *requestDistributor - retriever *retrieveManager - // DB interfaces - chainDb ethdb.Database // Block chain database - bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests - bloomIndexer, chtIndexer, bloomTrieIndexer *core.ChainIndexer + // Handlers + peers *peerSet + txPool *light.TxPool + blockchain *light.LightChain + serverPool *serverPool + reqDist *requestDistributor + retriever *retrieveManager + + bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests + bloomIndexer *core.ChainIndexer ApiBackend *LesApiBackend @@ -82,7 +83,7 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) { 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 } @@ -92,44 +93,84 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) { quitSync := make(chan struct{}) leth := &LightEthereum{ - chainConfig: chainConfig, - chainDb: chainDb, - eventMux: ctx.EventMux, - peers: peers, - reqDist: newRequestDistributor(peers, quitSync), - accountManager: ctx.AccountManager, - engine: eth.CreateConsensusEngine(ctx, &config.Ethash, chainConfig, chainDb), - shutdownChan: make(chan bool), - networkId: config.NetworkId, - bloomRequests: make(chan chan *bloombits.Retrieval), - bloomIndexer: eth.NewBloomIndexer(chainDb, light.BloomTrieFrequency), - chtIndexer: light.NewChtIndexer(chainDb, true), - bloomTrieIndexer: light.NewBloomTrieIndexer(chainDb, true), + lesCommons: lesCommons{ + chainDb: chainDb, + config: config, + iConfig: light.DefaultClientIndexerConfig, + }, + chainConfig: chainConfig, + eventMux: ctx.EventMux, + peers: peers, + reqDist: newRequestDistributor(peers, quitSync, &mclock.System{}), + accountManager: ctx.AccountManager, + engine: eth.CreateConsensusEngine(ctx, chainConfig, &config.Ethash, nil, false, chainDb), + shutdownChan: make(chan bool), + networkId: config.NetworkId, + bloomRequests: make(chan chan *bloombits.Retrieval), + 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, leth.chtIndexer, leth.bloomTrieIndexer, leth.bloomIndexer, leth.retriever) + + leth.odr = NewLesOdr(chainDb, light.DefaultClientIndexerConfig, leth.retriever) + leth.chtIndexer = light.NewChtIndexer(chainDb, leth.odr, params.CHTFrequencyClient, params.HelperTrieConfirmations) + leth.bloomTrieIndexer = light.NewBloomTrieIndexer(chainDb, leth.odr, params.BloomBitsBlocksClient, params.BloomTrieFrequency) + leth.odr.SetIndexers(leth.chtIndexer, leth.bloomTrieIndexer, leth.bloomIndexer) + + // Note: NewLightChain adds the trusted checkpoint so it needs an ODR with + // indexers already set but not started yet if leth.blockchain, err = light.NewLightChain(leth.odr, leth.chainConfig, leth.engine); err != nil { return nil, err } + // Note: AddChildIndexer starts the update process for the child + leth.bloomIndexer.AddChildIndexer(leth.bloomTrieIndexer) + leth.chtIndexer.Start(leth.blockchain) leth.bloomIndexer.Start(leth.blockchain) + // Rewind the chain in case of an incompatible config upgrade. if compat, ok := genesisErr.(*params.ConfigCompatError); ok { log.Warn("Rewinding chain to upgrade configuration", "err", compat) leth.blockchain.SetHead(compat.RewindTo) - core.WriteChainConfig(chainDb, genesisHash, chainConfig) + rawdb.WriteChainConfig(chainDb, genesisHash, chainConfig) } leth.txPool = light.NewTxPool(leth.chainConfig, leth.blockchain, leth.relay) - if leth.protocolManager, err = NewProtocolManager(leth.chainConfig, true, ClientProtocolVersions, config.NetworkId, leth.eventMux, leth.engine, leth.peers, leth.blockchain, nil, chainDb, leth.odr, leth.relay, 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.GasPrice + gpoParams.Default = config.MinerGasPrice } leth.ApiBackend.gpo = gasprice.NewOracle(leth.ApiBackend, gpoParams) return leth, nil @@ -205,26 +246,26 @@ func (s *LightEthereum) ResetWithGenesisBlock(gb *types.Block) { func (s *LightEthereum) BlockChain() *light.LightChain { return s.blockchain } func (s *LightEthereum) TxPool() *light.TxPool { return s.txPool } func (s *LightEthereum) Engine() consensus.Engine { return s.engine } -func (s *LightEthereum) LesVersion() int { return int(s.protocolManager.SubProtocols[0].Version) } +func (s *LightEthereum) LesVersion() int { return int(ClientProtocolVersions[0]) } func (s *LightEthereum) Downloader() *downloader.Downloader { return s.protocolManager.downloader } func (s *LightEthereum) EventMux() *event.TypeMux { return s.eventMux } // Protocols implements node.Service, returning all the currently configured // network protocols to start. func (s *LightEthereum) Protocols() []p2p.Protocol { - return s.protocolManager.SubProtocols + return s.makeProtocols(ClientProtocolVersions) } // Start implements node.Service, starting all internal goroutines needed by the // Ethereum protocol implementation. func (s *LightEthereum) Start(srvr *p2p.Server) error { - s.startBloomHandlers() log.Warn("Light client mode is an experimental feature") + s.startBloomHandlers(params.BloomBitsBlocksClient) s.netRPCService = ethapi.NewPublicNetAPI(srvr, s.networkId) // clients are searching for the first advertised protocol in the list protocolVersion := AdvertiseProtocolVersions[0] s.serverPool.start(srvr, lesTopic(s.blockchain.Genesis().Hash(), protocolVersion)) - s.protocolManager.Start() + s.protocolManager.Start(s.config.LightPeers) return nil } @@ -232,18 +273,12 @@ func (s *LightEthereum) Start(srvr *p2p.Server) error { // Ethereum protocol. func (s *LightEthereum) Stop() error { s.odr.Stop() - if s.bloomIndexer != nil { - s.bloomIndexer.Close() - } - if s.chtIndexer != nil { - s.chtIndexer.Close() - } - if s.bloomTrieIndexer != nil { - s.bloomTrieIndexer.Close() - } + s.bloomIndexer.Close() + s.chtIndexer.Close() s.blockchain.Stop() s.protocolManager.Stop() s.txPool.Stop() + s.engine.Close() s.eventMux.Stop() diff --git a/les/benchmark.go b/les/benchmark.go new file mode 100644 index 0000000000..cb302c6ea5 --- /dev/null +++ b/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/les/bloombits.go b/les/bloombits.go index de233d7518..aea0fcd5f4 100644 --- a/les/bloombits.go +++ b/les/bloombits.go @@ -43,7 +43,7 @@ const ( // startBloomHandlers starts a batch of goroutines to accept bloom bit database // retrievals from possibly a range of filters and serving the data to satisfy. -func (eth *LightEthereum) startBloomHandlers() { +func (eth *LightEthereum) startBloomHandlers(sectionSize uint64) { for i := 0; i < bloomServiceThreads; i++ { go func() { for { @@ -57,7 +57,7 @@ func (eth *LightEthereum) startBloomHandlers() { compVectors, err := light.GetBloomBits(task.Context, eth.odr, task.Bit, task.Sections) if err == nil { for i := range task.Sections { - if blob, err := bitutil.DecompressBytes(compVectors[i], int(light.BloomTrieFrequency/8)); err == nil { + if blob, err := bitutil.DecompressBytes(compVectors[i], int(sectionSize/8)); err == nil { task.Bitsets[i] = blob } else { task.Error = err @@ -72,13 +72,3 @@ func (eth *LightEthereum) startBloomHandlers() { }() } } - -const ( - // bloomConfirms is the number of confirmation blocks before a bloom section is - // considered probably final and its rotated bits are calculated. - bloomConfirms = 256 - - // bloomThrottling is the time to wait between processing two consecutive index - // sections. It's useful during chain upgrades to prevent disk overload. - bloomThrottling = 100 * time.Millisecond -) diff --git a/les/commons.go b/les/commons.go new file mode 100644 index 0000000000..21fb25714a --- /dev/null +++ b/les/commons.go @@ -0,0 +1,120 @@ +// 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 ( + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/light" + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/params" +) + +// lesCommons contains fields needed by both server and client. +type lesCommons struct { + config *eth.Config + iConfig *light.IndexerConfig + chainDb ethdb.Database + protocolManager *ProtocolManager + chtIndexer, bloomTrieIndexer *core.ChainIndexer +} + +// NodeInfo represents a short summary of the Ethereum sub-protocol metadata +// known about the host peer. +type NodeInfo struct { + Network uint64 `json:"network"` // Ethereum network ID (1=Frontier, 2=Morden, Ropsten=3, Rinkeby=4) + Difficulty *big.Int `json:"difficulty"` // Total difficulty of the host's blockchain + Genesis common.Hash `json:"genesis"` // SHA3 hash of the host's genesis block + Config *params.ChainConfig `json:"config"` // Chain configuration for the fork rules + Head common.Hash `json:"head"` // SHA3 hash of the host's best owned block + CHT params.TrustedCheckpoint `json:"cht"` // Trused CHT checkpoint for fast catchup +} + +// makeProtocols creates protocol descriptors for the given LES versions. +func (c *lesCommons) makeProtocols(versions []uint) []p2p.Protocol { + protos := make([]p2p.Protocol, len(versions)) + for i, version := range versions { + version := version + protos[i] = p2p.Protocol{ + Name: "les", + Version: version, + Length: ProtocolLengths[version], + NodeInfo: c.nodeInfo, + Run: func(p *p2p.Peer, rw p2p.MsgReadWriter) error { + return c.protocolManager.runPeer(version, p, rw) + }, + PeerInfo: func(id enode.ID) interface{} { + if p := c.protocolManager.peers.Peer(fmt.Sprintf("%x", id[:8])); p != nil { + return p.Info() + } + return nil + }, + } + } + return protos +} + +// nodeInfo retrieves some protocol metadata about the running host node. +func (c *lesCommons) nodeInfo() interface{} { + var cht params.TrustedCheckpoint + sections, _, _ := c.chtIndexer.Sections() + sections2, _, _ := c.bloomTrieIndexer.Sections() + + if !c.protocolManager.lightSync { + // convert to client section size if running in server mode + sections /= c.iConfig.PairChtSize / c.iConfig.ChtSize + } + + if sections2 < sections { + sections = sections2 + } + if sections > 0 { + sectionIndex := sections - 1 + sectionHead := c.bloomTrieIndexer.SectionHead(sectionIndex) + var chtRoot common.Hash + if c.protocolManager.lightSync { + chtRoot = light.GetChtRoot(c.chainDb, sectionIndex, sectionHead) + } else { + idxV2 := (sectionIndex+1)*c.iConfig.PairChtSize/c.iConfig.ChtSize - 1 + chtRoot = light.GetChtRoot(c.chainDb, idxV2, sectionHead) + } + cht = params.TrustedCheckpoint{ + SectionIndex: sectionIndex, + SectionHead: sectionHead, + CHTRoot: chtRoot, + BloomRoot: light.GetBloomTrieRoot(c.chainDb, sectionIndex, sectionHead), + } + } + + chain := c.protocolManager.blockchain + head := chain.CurrentHeader() + hash := head.Hash() + return &NodeInfo{ + Network: c.config.NetworkId, + Difficulty: chain.GetTd(hash, head.Number.Uint64()), + Genesis: chain.Genesis().Hash(), + Config: chain.Config(), + Head: chain.CurrentHeader().Hash(), + CHT: cht, + } +} diff --git a/les/costtracker.go b/les/costtracker.go new file mode 100644 index 0000000000..69531937ef --- /dev/null +++ b/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/les/distributor.go b/les/distributor.go index 159fa4c73f..1de267f27f 100644 --- a/les/distributor.go +++ b/les/distributor.go @@ -14,24 +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" - "errors" "sync" "time" -) -// ErrNoPeers is returned if no peers capable of serving a queued request are available -var ErrNoPeers = errors.New("no suitable peers available") + "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{} @@ -71,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, @@ -118,7 +116,9 @@ func (d *requestDistributor) loop() { d.lock.Lock() elem := d.reqQueue.Front() for elem != nil { - close(elem.Value.(*distReq).sentChn) + req := elem.Value.(*distReq) + close(req.sentChn) + req.sentChn = nil elem = elem.Next() } d.lock.Unlock() @@ -150,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/les/distributor_test.go b/les/distributor_test.go index 55defb69be..d2247212cd 100644 --- a/les/distributor_test.go +++ b/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 { @@ -87,7 +87,7 @@ const ( testDistBufLimit = 10000000 testDistMaxCost = 1000000 testDistPeerCount = 5 - testDistReqCount = 50000 + testDistReqCount = 5000 testDistMaxResendCount = 3 ) @@ -97,9 +97,8 @@ func (p *testDistPeer) waitBefore(cost uint64) (time.Duration, float64) { p.lock.RUnlock() if sumCost < testDistBufLimit { return 0, float64(testDistBufLimit-sumCost) / float64(testDistBufLimit) - } else { - return time.Duration(sumCost - testDistBufLimit), 0 } + return time.Duration(sumCost - testDistBufLimit), 0 } func (p *testDistPeer) canQueue() bool { @@ -122,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/les/fetcher.go b/les/fetcher.go index 3fc4df30b9..057552f532 100644 --- a/les/fetcher.go +++ b/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 ( @@ -25,35 +24,46 @@ import ( "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/types" "github.com/ethereum/go-ethereum/light" "github.com/ethereum/go-ethereum/log" ) const ( - blockDelayTimeout = time.Second * 10 // timeout for a peer to announce a head that has already been confirmed by others - maxNodeCount = 20 // maximum number of fetcherTreeNode entries remembered for each peer + blockDelayTimeout = time.Second * 10 // timeout for a peer to announce a head that has already been confirmed by others + maxNodeCount = 20 // maximum number of fetcherTreeNode entries remembered for each peer + serverStateAvailable = 100 // number of recent blocks where state availability is assumed ) -// lightFetcher +// lightFetcher implements retrieval of newly announced headers. It also provides a peerHasBlock function for the +// ODR system to ensure that we only request data related to a certain block from peers who have already processed +// and announced that block. 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 peers map[*peer]*fetcherPeerInfo lastUpdateStats *updateStatsEntry + syncing bool + syncDone chan *peer - lock sync.Mutex // qwerqwerqwe - deliverChn chan fetchResponse - reqMu sync.RWMutex - requested map[uint64]fetchRequest - timeoutChn chan uint64 - requestChn chan bool // true if initiated from outside - 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 + 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 @@ -138,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() @@ -206,6 +220,7 @@ func (f *lightFetcher) syncLoop() { f.checkSyncedHeaders(p) f.syncing = false f.lock.Unlock() + f.requestChn <- false } } } @@ -213,14 +228,13 @@ func (f *lightFetcher) syncLoop() { // registerPeer adds a new peer to the fetcher's peer set func (f *lightFetcher) registerPeer(p *peer) { p.lock.Lock() - p.hasBlock = func(hash common.Hash, number uint64) bool { - return f.peerHasBlock(p, hash, number) + p.hasBlock = func(hash common.Hash, number uint64, hasState bool) bool { + return f.peerHasBlock(p, hash, number, hasState) } p.lock.Unlock() f.lock.Lock() defer f.lock.Unlock() - f.peers[p] = &fetcherPeerInfo{nodeByHash: make(map[common.Hash]*fetcherTreeNode)} } @@ -265,6 +279,15 @@ func (f *lightFetcher) announce(p *peer, head *announceData) { } n = n.parent } + // n is now the reorg common ancestor, add a new branch of nodes + if n != nil && (head.Number >= n.number+maxNodeCount || head.Number <= n.number) { + // if announced head block height is lower or same as n or too far from it to add + // intermediate nodes then discard previous announcement info and trigger a resync + n = nil + 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 { // 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 @@ -278,7 +301,7 @@ func (f *lightFetcher) announce(p *peer, head *announceData) { // if one of root's children is canonical, keep it, delete other branches and root itself var newRoot *fetcherTreeNode for i, nn := range fp.root.children { - if core.GetCanonicalHash(f.pm.chainDb, nn.number) == nn.hash { + if rawdb.ReadCanonicalHash(f.pm.chainDb, nn.number) == nn.hash { fp.root.children = append(fp.root.children[:i], fp.root.children[i+1:]...) nn.parent = nil newRoot = nn @@ -311,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 { @@ -335,21 +359,27 @@ func (f *lightFetcher) announce(p *peer, head *announceData) { // peerHasBlock returns true if we can assume the peer knows the given block // based on its announcements -func (f *lightFetcher) peerHasBlock(p *peer, hash common.Hash, number uint64) bool { +func (f *lightFetcher) peerHasBlock(p *peer, hash common.Hash, number uint64, hasState bool) bool { f.lock.Lock() defer f.lock.Unlock() + fp := f.peers[p] + if fp == nil || fp.root == nil { + return false + } + + if hasState { + if fp.lastAnnounced == nil || fp.lastAnnounced.number > number+serverStateAvailable { + return false + } + } + if f.syncing { // always return true when syncing // false positives are acceptable, a more sophisticated condition can be implemented later return true } - fp := f.peers[p] - if fp == nil || fp.root == nil { - return false - } - if number >= fp.root.number { // it is recent enough that if it is known, is should be in the peer's block tree return fp.nodeByHash[hash] != nil @@ -361,7 +391,7 @@ func (f *lightFetcher) peerHasBlock(p *peer, hash common.Hash, number uint64) bo // // when syncing, just check if it is part of the known chain, there is nothing better we // can do since we do not know the most recent block hash yet - return core.GetCanonicalHash(f.pm.chainDb, fp.root.number) == fp.root.hash && core.GetCanonicalHash(f.pm.chainDb, number) == hash + return rawdb.ReadCanonicalHash(f.pm.chainDb, fp.root.number) == fp.root.hash && rawdb.ReadCanonicalHash(f.pm.chainDb, number) == hash } // requestAmount calculates the amount of headers to be downloaded starting @@ -389,99 +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) - 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 @@ -499,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 @@ -523,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") @@ -532,6 +621,7 @@ func (f *lightFetcher) newHeaders(headers []*types.Header, tds []*big.Int) { maxTd = fp.confirmedTd } } + if maxTd != nil { f.updateMaxConfirmedTd(maxTd) } @@ -557,8 +647,13 @@ func (f *lightFetcher) checkAnnouncedHeaders(fp *fetcherPeerInfo, headers []*typ return true } // we ran out of recently delivered headers but have not reached a node known by this peer yet, continue matching - td = f.chain.GetTd(header.ParentHash, header.Number.Uint64()-1) - header = f.chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) + hash, number := header.ParentHash, header.Number.Uint64()-1 + td = f.chain.GetTd(hash, number) + header = f.chain.GetHeader(hash, number) + if header == nil || td == nil { + log.Error("Missing parent of validated header", "hash", hash, "number", number) + return false + } } else { header = headers[i] td = tds[i] @@ -614,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) @@ -642,13 +787,18 @@ func (f *lightFetcher) checkKnownNode(p *peer, n *fetcherTreeNode) bool { if td == nil { return false } + header := f.chain.GetHeader(n.hash, n.number) + // check the availability of both header and td because reads are not protected by chain db mutex + // Note: returning false is always safe here + if header == nil { + return false + } fp := f.peers[p] if fp == nil { p.Log().Debug("Unknown peer to check known nodes") return false } - header := f.chain.GetHeader(n.hash, n.number) if !f.checkAnnouncedHeaders(fp, []*types.Header{header}, []*big.Int{td}) { p.Log().Debug("Inconsistent announcement") go f.pm.removePeer(p.id) @@ -716,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) @@ -738,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/les/fetcher_test.go b/les/fetcher_test.go new file mode 100644 index 0000000000..cc678c8c13 --- /dev/null +++ b/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/les/flowcontrol/control.go b/les/flowcontrol/control.go index d50eb809cc..c03f673b28 100644 --- a/les/flowcontrol/control.go +++ b/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/les/flowcontrol/logger.go b/les/flowcontrol/logger.go new file mode 100644 index 0000000000..fcd1285a59 --- /dev/null +++ b/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/les/flowcontrol/manager.go b/les/flowcontrol/manager.go index 28cc6f0fe7..532e6a4050 100644 --- a/les/flowcontrol/manager.go +++ b/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/les/flowcontrol/manager_test.go b/les/flowcontrol/manager_test.go new file mode 100644 index 0000000000..4e7746d400 --- /dev/null +++ b/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/les/freeclient.go b/les/freeclient.go new file mode 100644 index 0000000000..d859337c26 --- /dev/null +++ b/les/freeclient.go @@ -0,0 +1,323 @@ +// 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 ( + "io" + "math" + "net" + "sync" + "time" + + "github.com/ethereum/go-ethereum/common/mclock" + "github.com/ethereum/go-ethereum/common/prque" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/rlp" +) + +// freeClientPool implements a client database that limits the connection time +// of each client and manages accepting/rejecting incoming connections and even +// kicking out some connected clients. The pool calculates recent usage time +// for each known client (a value that increases linearly when the client is +// connected and decreases exponentially when not connected). Clients with lower +// recent usage are preferred, unknown nodes have the highest priority. Already +// connected nodes receive a small bias in their favor in order to avoid accepting +// and instantly kicking out clients. +// +// Note: the pool can use any string for client identification. Using signature +// keys for that purpose would not make sense when being known has a negative +// 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 + removePeer func(string) + + connectedLimit, totalLimit int + freeClientCap uint64 + + addressMap map[string]*freeClientPoolEntry + connPool, disconnPool *prque.Prque + startupTime mclock.AbsTime + logOffsetAtStartup int64 +} + +const ( + recentUsageExpTC = time.Hour // time constant of the exponential weighting window for "recent" server usage + fixedPointMultiplier = 0x1000000 // constant to convert logarithms to fixed point format + connectedBias = time.Minute // this bias is applied in favor of already connected clients in order to avoid kicking them out very soon +) + +// newFreeClientPool creates a new free client pool +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), + freeClientCap: freeClientCap, + totalLimit: totalLimit, + removePeer: removePeer, + } + pool.loadFromDb() + return pool +} + +func (f *freeClientPool) stop() { + f.lock.Lock() + f.closed = true + f.saveToDb() + 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. +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, id: id} + f.addressMap[address] = e + } else { + if e.connected { + log.Debug("Client already connected", "address", address) + return false + } + recentUsage = int64(math.Exp(float64(e.logUsage-f.logOffset(now)) / fixedPointMultiplier)) + } + e.linUsage = recentUsage - int64(now) + // check whether (linUsage+connectedBias) is smaller than the highest entry in the connected pool + if f.connPool.Size() == f.connectedLimit { + i := f.connPool.PopItem().(*freeClientPoolEntry) + if e.linUsage+int64(connectedBias)-i.linUsage < 0 { + // kick it out and accept the new client + f.dropClient(i, now) + } else { + // keep the old client and reject the new one + f.connPool.Push(i, i.linUsage) + log.Debug("Client rejected", "address", address) + return false + } + } + f.disconnPool.Remove(e.index) + e.connected = true + e.id = id + f.connPool.Push(e, e.linUsage) + if f.connPool.Size()+f.disconnPool.Size() > f.totalLimit { + f.disconnPool.Pop() + } + log.Debug("Client accepted", "address", address) + 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. +func (f *freeClientPool) disconnect(address string) { + f.lock.Lock() + defer f.lock.Unlock() + + if f.closed { + return + } + e := f.addressMap[address] + now := f.clock.Now() + if !e.connected { + log.Debug("Client already disconnected", "address", address) + return + } + + f.connPool.Remove(e.index) + f.calcLogUsage(e, now) + e.connected = false + f.disconnPool.Push(e, -e.logUsage) + 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 { + // Note: fixedPointMultiplier acts as a multiplier here; the reason for dividing the divisor + // is to avoid int64 overflow. We assume that int64(recentUsageExpTC) >> fixedPointMultiplier. + logDecay := int64((time.Duration(now - f.startupTime)) / (recentUsageExpTC / fixedPointMultiplier)) + return f.logOffsetAtStartup + logDecay +} + +// calcLogUsage converts recent usage from linear to logarithmic representation +// when disconnecting a peer or closing the client pool +func (f *freeClientPool) calcLogUsage(e *freeClientPoolEntry, now mclock.AbsTime) { + dt := e.linUsage + int64(now) + if dt < 1 { + dt = 1 + } + e.logUsage = int64(math.Log(float64(dt))*fixedPointMultiplier) + f.logOffset(now) +} + +// freeClientPoolStorage is the RLP representation of the pool's database storage +type freeClientPoolStorage struct { + LogOffset uint64 + List []*freeClientPoolEntry +} + +// loadFromDb restores pool status from the database storage +// (automatically called at initialization) +func (f *freeClientPool) loadFromDb() { + enc, err := f.db.Get([]byte("freeClientPool")) + if err != nil { + return + } + var storage freeClientPoolStorage + err = rlp.DecodeBytes(enc, &storage) + if err != nil { + log.Error("Failed to decode client list", "err", err) + return + } + f.logOffsetAtStartup = int64(storage.LogOffset) + f.startupTime = f.clock.Now() + for _, e := range storage.List { + log.Debug("Loaded free client record", "address", e.address, "logUsage", e.logUsage) + f.addressMap[e.address] = e + f.disconnPool.Push(e, -e.logUsage) + } +} + +// saveToDb saves pool status to the database storage +// (automatically called during shutdown) +func (f *freeClientPool) saveToDb() { + now := f.clock.Now() + storage := freeClientPoolStorage{ + LogOffset: uint64(f.logOffset(now)), + List: make([]*freeClientPoolEntry, len(f.addressMap)), + } + i := 0 + for _, e := range f.addressMap { + if e.connected { + f.calcLogUsage(e, now) + } + storage.List[i] = e + i++ + } + enc, err := rlp.EncodeToBytes(storage) + if err != nil { + log.Error("Failed to encode client list", "err", err) + } else { + f.db.Put([]byte("freeClientPool"), enc) + } +} + +// freeClientPoolEntry represents a client address known by the pool. +// When connected, recent usage is calculated as linUsage + int64(clock.Now()) +// When disconnected, it is calculated as exp(logUsage - logOffset) where logOffset +// also grows linearly with time while the server is running. +// Conversion between linear and logarithmic representation happens when connecting +// or disconnecting the node. +// +// Note: linUsage and logUsage are values used with constantly growing offsets so +// 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, id string + connected bool + disconnectFn func() + linUsage, logUsage int64 + index int +} + +func (e *freeClientPoolEntry) EncodeRLP(w io.Writer) error { + return rlp.Encode(w, []interface{}{e.address, uint64(e.logUsage)}) +} + +func (e *freeClientPoolEntry) DecodeRLP(s *rlp.Stream) error { + var entry struct { + Address string + LogUsage uint64 + } + if err := s.Decode(&entry); err != nil { + return err + } + e.address = entry.Address + e.logUsage = int64(entry.LogUsage) + e.connected = false + e.index = -1 + return nil +} + +// poolSetIndex callback is used by both priority queues to set/update the index of +// the element in the queue. Index is needed to remove elements other than the top one. +func poolSetIndex(a interface{}, i int) { + a.(*freeClientPoolEntry).index = i +} diff --git a/les/freeclient_test.go b/les/freeclient_test.go new file mode 100644 index 0000000000..dc8b51a8d2 --- /dev/null +++ b/les/freeclient_test.go @@ -0,0 +1,145 @@ +// Copyright 2017 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 ( + "fmt" + "math/rand" + "strconv" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common/mclock" + "github.com/ethereum/go-ethereum/ethdb" +) + +func TestFreeClientPoolL10C100(t *testing.T) { + testFreeClientPool(t, 10, 100) +} + +func TestFreeClientPoolL40C200(t *testing.T) { + testFreeClientPool(t, 40, 200) +} + +func TestFreeClientPoolL100C300(t *testing.T) { + testFreeClientPool(t, 100, 300) +} + +const testFreeClientPoolTicks = 500000 + +func testFreeClientPool(t *testing.T, connLimit, clientCount int) { + var ( + clock mclock.Simulated + db = ethdb.NewMemDatabase() + 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(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(peerAddress(connLimit), peerId(connLimit)) { + connected[connLimit] = true + t.Fatalf("Peer accepted over connected limit") + } + + // randomly connect and disconnect peers, expect to have a similar total connection time at the end + for tickCounter := 0; tickCounter < testFreeClientPoolTicks; tickCounter++ { + clock.Run(1 * time.Second) + + i := rand.Intn(clientCount) + if connected[i] { + pool.disconnect(peerAddress(i)) + connected[i] = false + connTicks[i] += tickCounter + } else { + if pool.connect(peerAddress(i), peerId(i)) { + connected[i] = true + connTicks[i] -= tickCounter + } + } + pollDisconnects: + for { + select { + case i := <-disconnCh: + pool.disconnect(peerAddress(i)) + if connected[i] { + connTicks[i] += tickCounter + connected[i] = false + } + default: + break pollDisconnects + } + } + } + + expTicks := testFreeClientPoolTicks * connLimit / clientCount + expMin := expTicks - expTicks/10 + expMax := expTicks + expTicks/10 + + // check if the total connected time of peers are all in the expected range + for i, c := range connected { + if c { + connTicks[i] += testFreeClientPoolTicks + } + if connTicks[i] < expMin || connTicks[i] > expMax { + t.Errorf("Total connected time of test node #%d (%d) outside expected range (%d to %d)", i, connTicks[i], expMin, expMax) + } + } + + // a previously unknown peer should be accepted now + if !pool.connect("newAddr", "newId") { + t.Fatalf("Previously unknown peer rejected") + } + + // close and restart pool + pool.stop() + 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(peerAddress(i), peerId(i)) + } + // expect pool to remember known nodes and kick out one of them to accept a new one + if !pool.connect("newAddr2", "newId2") { + t.Errorf("Previously unknown peer rejected after restarting pool") + } + pool.stop() +} diff --git a/les/handler.go b/les/handler.go index ad2e8058f9..0352f5b039 100644 --- a/les/handler.go +++ b/les/handler.go @@ -14,31 +14,29 @@ // 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 ( - "bytes" "encoding/binary" - "errors" + "encoding/json" "fmt" "math/big" - "net" "sync" "time" "github.com/ethereum/go-ethereum/common" "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" "github.com/ethereum/go-ethereum/light" "github.com/ethereum/go-ethereum/log" "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" @@ -63,10 +61,6 @@ const ( disableClientRemovePeer = false ) -// errIncompatibleConfig is returned if the requested protocols and configs are -// not compatible (low protocol version restrictions and high requirements). -var errIncompatibleConfig = errors.New("incompatible configuration") - func errResp(code errCode, format string, v ...interface{}) error { return fmt.Errorf("%v - %v", code, fmt.Sprintf(format, v...)) } @@ -78,10 +72,11 @@ type BlockChain interface { GetHeaderByHash(hash common.Hash) *types.Header CurrentHeader() *types.Header GetTd(hash common.Hash, number uint64) *big.Int + State() (*state.StateDB, error) InsertHeaderChain(chain []*types.Header, checkFreq int) (int, error) Rollback(chain []common.Hash) GetHeaderByNumber(number uint64) *types.Header - GetBlockHashesFromHash(hash common.Hash, max uint64) []common.Hash + GetAncestor(hash common.Hash, number, ancestor uint64, maxNonCanonical *uint64) (common.Hash, uint64) Genesis() *types.Block SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription } @@ -92,25 +87,26 @@ type txPool interface { } type ProtocolManager struct { - lightSync bool - txpool txPool - txrelay *LesTxRelay - networkId uint64 - chainConfig *params.ChainConfig - blockchain BlockChain - chainDb ethdb.Database - odr *LesOdr - server *LesServer - serverPool *serverPool - 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 peers *peerSet - - SubProtocols []p2p.Protocol + maxPeers int eventMux *event.TypeMux @@ -121,23 +117,42 @@ 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, lightSync bool, protocolVersions []uint, networkId uint64, mux *event.TypeMux, engine consensus.Engine, peers *peerSet, blockchain BlockChain, txpool txPool, chainDb ethdb.Database, odr *LesOdr, txrelay *LesTxRelay, 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, eventMux: mux, blockchain: blockchain, chainConfig: chainConfig, + iConfig: indexerConfig, chainDb: chainDb, odr: odr, networkId: networkId, txpool: txpool, txrelay: txrelay, + serverPool: serverPool, peers: peers, newPeerCh: make(chan *peer), quitSync: quitSync, @@ -147,54 +162,12 @@ func NewProtocolManager(chainConfig *params.ChainConfig, lightSync bool, protoco if odr != nil { manager.retriever = odr.retriever manager.reqDist = odr.retriever.dist + } else { + manager.servingQueue = newServingQueue(int64(time.Millisecond * 10)) } - // Initiate a sub-protocol for every implemented version we can handle - manager.SubProtocols = make([]p2p.Protocol, 0, len(protocolVersions)) - for _, version := range protocolVersions { - // Compatible, initialize the sub-protocol - version := version // Closure for the run - manager.SubProtocols = append(manager.SubProtocols, p2p.Protocol{ - Name: "les", - Version: version, - Length: ProtocolLengths[version], - Run: func(p *p2p.Peer, rw p2p.MsgReadWriter) error { - var entry *poolEntry - peer := manager.newPeer(int(version), networkId, p, rw) - if manager.serverPool != nil { - addr := p.RemoteAddr().(*net.TCPAddr) - entry = manager.serverPool.connect(peer, addr.IP, uint16(addr.Port)) - } - peer.poolEntry = entry - select { - case manager.newPeerCh <- peer: - manager.wg.Add(1) - defer manager.wg.Done() - err := manager.handle(peer) - if entry != nil { - manager.serverPool.disconnect(entry) - } - return err - case <-manager.quitSync: - if entry != nil { - manager.serverPool.disconnect(entry) - } - return p2p.DiscQuitting - } - }, - NodeInfo: func() interface{} { - return manager.NodeInfo() - }, - PeerInfo: func(id discover.NodeID) interface{} { - if p := manager.peers.Peer(fmt.Sprintf("%x", id[:8])); p != nil { - return p.Info() - } - return nil - }, - }) - } - if len(manager.SubProtocols) == 0 { - return nil, errIncompatibleConfig + if ulcConfig != nil { + manager.ulc = newULC(ulcConfig) } removePeer := manager.removePeer @@ -207,7 +180,6 @@ func NewProtocolManager(chainConfig *params.ChainConfig, lightSync bool, protoco manager.peers.notify((*downloaderPeerNotify)(manager)) manager.fetcher = newLightFetcher(manager) } - return manager, nil } @@ -216,7 +188,8 @@ func (pm *ProtocolManager) removePeer(id string) { pm.peers.Unregister(id) } -func (pm *ProtocolManager) Start() { +func (pm *ProtocolManager) Start(maxPeers int) { + pm.maxPeers = maxPeers if pm.lightSync { go pm.syncer() } else { @@ -238,6 +211,10 @@ func (pm *ProtocolManager) Stop() { close(pm.quitSync) // quits syncer, fetcher + if pm.servingQueue != nil { + pm.servingQueue.stop() + } + // Disconnect existing sessions. // This also closes the gate for any new registrations on the peer set. // sessions which are already established but not added to pm.peers yet @@ -250,13 +227,48 @@ func (pm *ProtocolManager) Stop() { log.Info("Light Ethereum protocol stopped") } +// runPeer is the p2p protocol run function for the given version. +func (pm *ProtocolManager) runPeer(version uint, p *p2p.Peer, rw p2p.MsgReadWriter) error { + var entry *poolEntry + peer := pm.newPeer(int(version), pm.networkId, p, rw) + if pm.serverPool != nil { + entry = pm.serverPool.connect(peer, peer.Node()) + } + peer.poolEntry = entry + select { + case pm.newPeerCh <- peer: + pm.wg.Add(1) + defer pm.wg.Done() + err := pm.handle(peer) + if entry != nil { + pm.serverPool.disconnect(entry) + } + return err + case <-pm.quitSync: + if entry != nil { + pm.serverPool.disconnect(entry) + } + return p2p.DiscQuitting + } +} + 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 // this function terminates, the peer is disconnected. func (pm *ProtocolManager) handle(p *peer) error { + // Ignore maxPeers if this is a trusted peer + // In server mode we try to check into the client pool after handshake + if pm.lightSync && pm.peers.Len() >= pm.maxPeers && !p.Peer.Info().Network.Trusted { + return p2p.DiscTooManyPeers + } + p.Log().Debug("Light Ethereum peer connected", "name", p.Name()) // Execute the LES handshake @@ -271,20 +283,23 @@ func (pm *ProtocolManager) handle(p *peer) error { p.Log().Debug("Light Ethereum handshake failed", "err", err) return err } + 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() @@ -299,31 +314,18 @@ 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 { @@ -334,22 +336,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 { @@ -359,6 +370,31 @@ 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 { + p.errCh <- err + } + }) + } + } + // Handle the message depending on its contents switch msg.Code { case StatusMsg: @@ -369,26 +405,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.pubKey); 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: @@ -403,74 +446,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{}) - - // 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 { - origin = pm.blockchain.GetHeaderByHash(query.Origin.Hash) - } else { - origin = pm.blockchain.GetHeaderByNumber(query.Origin.Number) - } - if origin == nil { - break - } - number := origin.Number.Uint64() - headers = append(headers, origin) - bytes += estHeaderRlpSize - - // Advance to the next header of the query - switch { - case query.Origin.Hash != (common.Hash{}) && query.Reverse: - // Hash based traversal towards the genesis block - for i := 0; i < int(query.Skip)+1; i++ { - if header := pm.blockchain.GetHeader(query.Origin.Hash, number); header != nil { - query.Origin.Hash = header.ParentHash - number-- - } else { - unknown = true - break - } + // 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 } - case query.Origin.Hash != (common.Hash{}) && !query.Reverse: - // Hash based traversal towards the leaf block - if header := pm.blockchain.GetHeaderByNumber(origin.Number.Uint64() + query.Skip + 1); header != nil { - if pm.blockchain.GetBlockHashesFromHash(header.Hash(), query.Skip+1)[query.Skip] == query.Origin.Hash { - query.Origin.Hash = header.Hash() + // 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.GetHeaderByNumber(query.Origin.Number) + } + 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 + } 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 } - } 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 { @@ -486,7 +549,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 { @@ -512,22 +575,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 + 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) + } + } } - // Retrieve the requested block body, stopping if enough was found - if data := core.GetBodyRLP(pm.chainDb, hash, core.GetBlockNumber(pm.chainDb, hash)); 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 { @@ -543,7 +611,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, @@ -566,29 +634,36 @@ 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 header := core.GetHeader(pm.chainDb, req.BHash, core.GetBlockNumber(pm.chainDb, req.BHash)); header != nil { - if trie, _ := trie.New(header.Root, pm.chainDb); trie != nil { - sdata := trie.Get(req.AccKey) - var acc state.Account - if err := rlp.DecodeBytes(sdata, &acc); err == nil { - entry, _ := pm.chainDb.Get(acc.CodeHash) - if bytes+len(entry) >= softResponseLimit { + go func() { + for i, req := range req.Reqs { + if i != 0 && !task.waitOrStop() { + return + } + // 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)) + + data = append(data, code) + if bytes += len(code); bytes >= softResponseLimit { break } - data = append(data, entry) - bytes += len(entry) } } } - } - 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 { @@ -604,7 +679,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, @@ -627,31 +702,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 - results := core.GetBlockReceipts(pm.chainDb, hash, core.GetBlockNumber(pm.chainDb, hash)) - 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 { @@ -667,7 +748,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, @@ -690,36 +771,45 @@ 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 { - if bytes >= softResponseLimit { - break - } - // Retrieve the requested state entry, stopping if enough was found - if header := core.GetHeader(pm.chainDb, req.BHash, core.GetBlockNumber(pm.chainDb, req.BHash)); header != nil { - if tr, _ := trie.New(header.Root, pm.chainDb); tr != nil { - if len(req.AccKey) > 0 { - sdata := tr.Get(req.AccKey) - tr = nil - var acc state.Account - if err := rlp.DecodeBytes(sdata, &acc); err == nil { - tr, _ = trie.New(acc.Root, pm.chainDb) + go func() { + for i, req := range req.Reqs { + if i != 0 && !task.waitOrStop() { + return + } + // 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 + } + 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) + } + if trie != nil { + var proof light.NodeList + trie.Prove(req.Key, 0, &proof) + + proofs = append(proofs, proof) + if bytes += proof.DataSize(); bytes >= softResponseLimit { + break + } } - } - if tr != nil { - var proof light.NodeList - tr.Prove(req.Key, 0, &proof) - proofs = append(proofs, proof) - bytes += proof.DataSize() } } } - } - 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") @@ -733,53 +823,58 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { } // Gather state data until the fetch or network limits is reached var ( - lastBHash common.Hash - lastAccKey []byte - tr, str *trie.Trie + 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 _, req := range req.Reqs { - if nodes.DataSize() >= softResponseLimit { - break - } - if tr == nil || req.BHash != lastBHash { - if header := core.GetHeader(pm.chainDb, req.BHash, core.GetBlockNumber(pm.chainDb, req.BHash)); header != nil { - tr, _ = trie.New(header.Root, pm.chainDb) - } else { - tr = nil + for i, req := range req.Reqs { + if i != 0 && !task.waitOrStop() { + return } - lastBHash = req.BHash - str = nil - } - if tr != nil { - if len(req.AccKey) > 0 { - if str == nil || !bytes.Equal(req.AccKey, lastAccKey) { - sdata := tr.Get(req.AccKey) - str = nil - var acc state.Account - if err := rlp.DecodeBytes(sdata, &acc); err == nil { - str, _ = trie.New(acc.Root, pm.chainDb) + // 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 { + if header := rawdb.ReadHeader(pm.chainDb, req.BHash, *number); header != nil { + statedb, _ = pm.blockchain.State() + root = header.Root } - lastAccKey = common.CopyBytes(req.AccKey) } - if str != nil { - str.Prove(req.Key, req.FromLevel, nodes) + } + 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 { + continue } + trie, _ = statedb.Database().OpenStorageTrie(common.BytesToHash(req.AccKey), account.Root) } else { - tr.Prove(req.Key, req.FromLevel, nodes) + trie, _ = statedb.Database().OpenTrie(root) + } + 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 } } - } - proofs := nodes.NodeList() - 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, proofs) + sendResponse(req.ReqID, uint64(reqCnt), p.ReplyProofsV2(req.ReqID, nodes.NodeList()), task.done()) + }() case ProofsV1Msg: if pm.odr == nil { @@ -795,7 +890,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, @@ -816,7 +911,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, @@ -839,32 +934,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 := ethdb.NewTable(pm.chainDb, light.ChtTablePrefix) - for _, req := range req.Reqs { - if bytes >= softResponseLimit { - break - } - - if header := pm.blockchain.GetHeaderByNumber(req.BlockNum); header != nil { - sectionHead := core.GetCanonicalHash(pm.chainDb, req.ChtNum*light.ChtV1Frequency-1) - if root := light.GetChtRoot(pm.chainDb, req.ChtNum-1, sectionHead); root != (common.Hash{}) { - if tr, _ := trie.New(root, trieDb); tr != nil { + go func() { + trieDb := trie.NewDatabase(ethdb.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 - tr.Prove(encNumber[:], 0, &proof) + trie.Prove(encNumber[:], 0, &proof) + proofs = append(proofs, ChtResp{Header: header, Proof: proof}) - bytes += proof.DataSize() + estHeaderRlpSize + 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") @@ -882,56 +982,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 - tr *trie.Trie - ) + 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 - nodes := light.NewNodeSet() - - for _, req := range req.Reqs { - if nodes.DataSize()+auxBytes >= softResponseLimit { - break - } - if tr == nil || req.HelperTrieType != lastType || req.TrieIdx != lastIdx { - var prefix string - root, prefix = pm.getHelperTrie(req.HelperTrieType, req.TrieIdx) - if root != (common.Hash{}) { - if t, err := trie.New(root, ethdb.NewTable(pm.chainDb, prefix)); err == nil { - tr = t + 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))) } } - lastType = req.HelperTrieType - lastIdx = req.TrieIdx - } - if req.AuxReq == auxRoot { - var data []byte - if root != (common.Hash{}) { - data = root[:] - } - auxData = append(auxData, data) - auxBytes += len(data) - } else { - if tr != nil { - tr.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 } } - } - proofs := nodes.NodeList() - 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: proofs, 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 { @@ -946,7 +1043,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, @@ -967,7 +1064,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, @@ -984,13 +1081,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 { @@ -1005,29 +1107,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 { @@ -1042,13 +1142,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 { @@ -1064,7 +1170,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) @@ -1083,14 +1189,32 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { return nil } +// 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()) + if err != nil { + return state.Account{}, err + } + blob, err := trie.TryGet(hash[:]) + if err != nil { + return state.Account{}, err + } + var account state.Account + if err = rlp.DecodeBytes(blob, &account); err != nil { + return state.Account{}, err + } + return account, nil +} + // getHelperTrie returns the post-processed trie root for the given trie ID and section index func (pm *ProtocolManager) getHelperTrie(id uint, idx uint64) (common.Hash, string) { switch id { case htCanonical: - sectionHead := core.GetCanonicalHash(pm.chainDb, (idx+1)*light.ChtFrequency-1) - return light.GetChtV2Root(pm.chainDb, idx, sectionHead), light.ChtTablePrefix + idxV1 := (idx+1)*(pm.iConfig.PairChtSize/pm.iConfig.ChtSize) - 1 + sectionHead := rawdb.ReadCanonicalHash(pm.chainDb, (idxV1+1)*pm.iConfig.ChtSize-1) + return light.GetChtRoot(pm.chainDb, idxV1, sectionHead), light.ChtTablePrefix case htBloomBits: - sectionHead := core.GetCanonicalHash(pm.chainDb, (idx+1)*light.BloomTrieFrequency-1) + sectionHead := rawdb.ReadCanonicalHash(pm.chainDb, (idx+1)*pm.iConfig.BloomTrieSize-1) return light.GetBloomTrieRoot(pm.chainDb, idx, sectionHead), light.BloomTrieTablePrefix } return common.Hash{}, "" @@ -1098,56 +1222,33 @@ func (pm *ProtocolManager) getHelperTrie(id uint, idx uint64) (common.Hash, stri // getHelperTrieAuxData returns requested auxiliary data for the given HelperTrie request func (pm *ProtocolManager) getHelperTrieAuxData(req HelperTrieReq) []byte { - if req.HelperTrieType == htCanonical && req.AuxReq == auxHeader { - if len(req.Key) != 8 { - return nil - } + if req.Type == htCanonical && req.AuxReq == auxHeader && len(req.Key) == 8 { blockNum := binary.BigEndian.Uint64(req.Key) - hash := core.GetCanonicalHash(pm.chainDb, blockNum) - return core.GetHeaderRLP(pm.chainDb, hash, blockNum) + hash := rawdb.ReadCanonicalHash(pm.chainDb, blockNum) + return rawdb.ReadHeaderRLP(pm.chainDb, hash, blockNum) } 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 := core.GetTxLookupEntry(pm.chainDb, hashes[i]); block != (common.Hash{}) { - stats[i].Status = core.TxStatusIncluded - stats[i].Lookup = &core.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 } -// NodeInfo represents a short summary of the Ethereum sub-protocol metadata -// known about the host peer. -type NodeInfo struct { - Network uint64 `json:"network"` // Ethereum network ID (1=Frontier, 2=Morden, Ropsten=3, Rinkeby=4) - Difficulty *big.Int `json:"difficulty"` // Total difficulty of the host's blockchain - Genesis common.Hash `json:"genesis"` // SHA3 hash of the host's genesis block - Config *params.ChainConfig `json:"config"` // Chain configuration for the fork rules - Head common.Hash `json:"head"` // SHA3 hash of the host's best owned block -} - -// NodeInfo retrieves some protocol metadata about the running host node. -func (self *ProtocolManager) NodeInfo() *NodeInfo { - head := self.blockchain.CurrentHeader() - hash := head.Hash() - - return &NodeInfo{ - Network: self.networkId, - Difficulty: self.blockchain.GetTd(hash, head.Number.Uint64()), - Genesis: self.blockchain.Genesis().Hash(), - Config: self.blockchain.Config(), - Head: hash, +// 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 @@ -1175,13 +1276,13 @@ 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) } }, } _, ok := <-pc.manager.reqDist.queue(rq) if !ok { - return ErrNoPeers + return light.ErrNoPeers } return nil } @@ -1199,13 +1300,13 @@ 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) } }, } _, ok := <-pc.manager.reqDist.queue(rq) if !ok { - return ErrNoPeers + return light.ErrNoPeers } return nil } diff --git a/les/handler_test.go b/les/handler_test.go index 10e5499a33..e9033729ea 100644 --- a/les/handler_test.go +++ b/les/handler_test.go @@ -17,7 +17,7 @@ package les import ( - "bytes" + "encoding/binary" "math/big" "math/rand" "testing" @@ -26,6 +26,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/crypto" "github.com/ethereum/go-ethereum/eth/downloader" @@ -45,35 +46,14 @@ func expectResponse(r p2p.MsgReader, msgcode, reqID, bv uint64, data interface{} return p2p.ExpectMsg(r, msgcode, resp{reqID, bv, data}) } -func testCheckProof(t *testing.T, exp *light.NodeSet, got light.NodeList) { - if exp.KeyCount() > len(got) { - t.Errorf("proof has fewer nodes than expected") - return - } - if exp.KeyCount() < len(got) { - t.Errorf("proof has more nodes than expected") - return - } - for _, node := range got { - n, _ := exp.Get(crypto.Keccak256(node)) - if !bytes.Equal(n, node) { - t.Errorf("proof contents mismatch") - return - } - } -} - // Tests that block headers can be retrieved from a remote chain based on user queries. func TestGetBlockHeadersLes1(t *testing.T) { testGetBlockHeaders(t, 1) } - func TestGetBlockHeadersLes2(t *testing.T) { testGetBlockHeaders(t, 2) } func testGetBlockHeaders(t *testing.T, protocol int) { - db, _ := ethdb.NewMemDatabase() - pm := newTestProtocolManagerMust(t, false, downloader.MaxHashFetch+15, nil, nil, nil, db) - bc := pm.blockchain.(*core.BlockChain) - peer, _ := newTestPeer(t, "peer", protocol, pm, true) - defer peer.close() + server, tearDown := newServerEnv(t, downloader.MaxHashFetch+15, protocol, nil) + defer tearDown() + bc := server.pm.blockchain.(*core.BlockChain) // Create a "random" unknown hash for testing var unknown common.Hash @@ -186,9 +166,9 @@ func testGetBlockHeaders(t *testing.T, protocol int) { } // Send the hash request and verify the response reqID++ - cost := peer.GetRequestCost(GetBlockHeadersMsg, int(tt.query.Amount)) - sendRequest(peer.app, GetBlockHeadersMsg, reqID, cost, tt.query) - if err := expectResponse(peer.app, BlockHeadersMsg, reqID, testBufLimit, headers); err != nil { + cost := server.tPeer.GetRequestCost(GetBlockHeadersMsg, int(tt.query.Amount)) + sendRequest(server.tPeer.app, GetBlockHeadersMsg, reqID, cost, tt.query) + if err := expectResponse(server.tPeer.app, BlockHeadersMsg, reqID, testBufLimit, headers); err != nil { t.Errorf("test %d: headers mismatch: %v", i, err) } } @@ -196,15 +176,12 @@ func testGetBlockHeaders(t *testing.T, protocol int) { // Tests that block contents can be retrieved from a remote chain based on their hashes. func TestGetBlockBodiesLes1(t *testing.T) { testGetBlockBodies(t, 1) } - func TestGetBlockBodiesLes2(t *testing.T) { testGetBlockBodies(t, 2) } func testGetBlockBodies(t *testing.T, protocol int) { - db, _ := ethdb.NewMemDatabase() - pm := newTestProtocolManagerMust(t, false, downloader.MaxBlockFetch+15, nil, nil, nil, db) - bc := pm.blockchain.(*core.BlockChain) - peer, _ := newTestPeer(t, "peer", protocol, pm, true) - defer peer.close() + server, tearDown := newServerEnv(t, downloader.MaxBlockFetch+15, protocol, nil) + defer tearDown() + bc := server.pm.blockchain.(*core.BlockChain) // Create a batch of tests for various scenarios limit := MaxBodyFetch @@ -264,9 +241,9 @@ func testGetBlockBodies(t *testing.T, protocol int) { } reqID++ // Send the hash request and verify the response - cost := peer.GetRequestCost(GetBlockBodiesMsg, len(hashes)) - sendRequest(peer.app, GetBlockBodiesMsg, reqID, cost, hashes) - if err := expectResponse(peer.app, BlockBodiesMsg, reqID, testBufLimit, bodies); err != nil { + cost := server.tPeer.GetRequestCost(GetBlockBodiesMsg, len(hashes)) + sendRequest(server.tPeer.app, GetBlockBodiesMsg, reqID, cost, hashes) + if err := expectResponse(server.tPeer.app, BlockBodiesMsg, reqID, testBufLimit, bodies); err != nil { t.Errorf("test %d: bodies mismatch: %v", i, err) } } @@ -274,16 +251,13 @@ func testGetBlockBodies(t *testing.T, protocol int) { // Tests that the contract codes can be retrieved based on account addresses. func TestGetCodeLes1(t *testing.T) { testGetCode(t, 1) } - func TestGetCodeLes2(t *testing.T) { testGetCode(t, 2) } func testGetCode(t *testing.T, protocol int) { // Assemble the test environment - db, _ := ethdb.NewMemDatabase() - pm := newTestProtocolManagerMust(t, false, 4, testChainGen, nil, nil, db) - bc := pm.blockchain.(*core.BlockChain) - peer, _ := newTestPeer(t, "peer", protocol, pm, true) - defer peer.close() + server, tearDown := newServerEnv(t, 4, protocol, nil) + defer tearDown() + bc := server.pm.blockchain.(*core.BlockChain) var codereqs []*CodeReq var codes [][]byte @@ -300,25 +274,22 @@ func testGetCode(t *testing.T, protocol int) { } } - cost := peer.GetRequestCost(GetCodeMsg, len(codereqs)) - sendRequest(peer.app, GetCodeMsg, 42, cost, codereqs) - if err := expectResponse(peer.app, CodeMsg, 42, testBufLimit, codes); err != nil { + cost := server.tPeer.GetRequestCost(GetCodeMsg, len(codereqs)) + sendRequest(server.tPeer.app, GetCodeMsg, 42, cost, codereqs) + if err := expectResponse(server.tPeer.app, CodeMsg, 42, testBufLimit, codes); err != nil { t.Errorf("codes mismatch: %v", err) } } // Tests that the transaction receipts can be retrieved based on hashes. func TestGetReceiptLes1(t *testing.T) { testGetReceipt(t, 1) } - func TestGetReceiptLes2(t *testing.T) { testGetReceipt(t, 2) } func testGetReceipt(t *testing.T, protocol int) { // Assemble the test environment - db, _ := ethdb.NewMemDatabase() - pm := newTestProtocolManagerMust(t, false, 4, testChainGen, nil, nil, db) - bc := pm.blockchain.(*core.BlockChain) - peer, _ := newTestPeer(t, "peer", protocol, pm, true) - defer peer.close() + server, tearDown := newServerEnv(t, 4, protocol, nil) + defer tearDown() + bc := server.pm.blockchain.(*core.BlockChain) // Collect the hashes to request, and the response to expect hashes, receipts := []common.Hash{}, []types.Receipts{} @@ -326,28 +297,25 @@ func testGetReceipt(t *testing.T, protocol int) { block := bc.GetBlockByNumber(i) hashes = append(hashes, block.Hash()) - receipts = append(receipts, core.GetBlockReceipts(db, block.Hash(), block.NumberU64())) + receipts = append(receipts, rawdb.ReadReceipts(server.db, block.Hash(), block.NumberU64())) } // Send the hash request and verify the response - cost := peer.GetRequestCost(GetReceiptsMsg, len(hashes)) - sendRequest(peer.app, GetReceiptsMsg, 42, cost, hashes) - if err := expectResponse(peer.app, ReceiptsMsg, 42, testBufLimit, receipts); err != nil { + cost := server.tPeer.GetRequestCost(GetReceiptsMsg, len(hashes)) + sendRequest(server.tPeer.app, GetReceiptsMsg, 42, cost, hashes) + if err := expectResponse(server.tPeer.app, ReceiptsMsg, 42, testBufLimit, receipts); err != nil { t.Errorf("receipts mismatch: %v", err) } } // Tests that trie merkle proofs can be retrieved func TestGetProofsLes1(t *testing.T) { testGetProofs(t, 1) } - func TestGetProofsLes2(t *testing.T) { testGetProofs(t, 2) } func testGetProofs(t *testing.T, protocol int) { // Assemble the test environment - db, _ := ethdb.NewMemDatabase() - pm := newTestProtocolManagerMust(t, false, 4, testChainGen, nil, nil, db) - bc := pm.blockchain.(*core.BlockChain) - peer, _ := newTestPeer(t, "peer", protocol, pm, true) - defer peer.close() + server, tearDown := newServerEnv(t, 4, protocol, nil) + defer tearDown() + bc := server.pm.blockchain.(*core.BlockChain) var ( proofreqs []ProofReq @@ -359,7 +327,7 @@ func testGetProofs(t *testing.T, protocol int) { for i := uint64(0); i <= bc.CurrentBlock().NumberU64(); i++ { header := bc.GetHeaderByNumber(i) root := header.Root - trie, _ := trie.New(root, db) + trie, _ := trie.New(root, trie.NewDatabase(server.db)) for _, acc := range accounts { req := ProofReq{ @@ -381,41 +349,152 @@ func testGetProofs(t *testing.T, protocol int) { // Send the proof request and verify the response switch protocol { case 1: - cost := peer.GetRequestCost(GetProofsV1Msg, len(proofreqs)) - sendRequest(peer.app, GetProofsV1Msg, 42, cost, proofreqs) - if err := expectResponse(peer.app, ProofsV1Msg, 42, testBufLimit, proofsV1); err != nil { + cost := server.tPeer.GetRequestCost(GetProofsV1Msg, len(proofreqs)) + sendRequest(server.tPeer.app, GetProofsV1Msg, 42, cost, proofreqs) + if err := expectResponse(server.tPeer.app, ProofsV1Msg, 42, testBufLimit, proofsV1); err != nil { t.Errorf("proofs mismatch: %v", err) } case 2: - cost := peer.GetRequestCost(GetProofsV2Msg, len(proofreqs)) - sendRequest(peer.app, GetProofsV2Msg, 42, cost, proofreqs) - msg, err := peer.app.ReadMsg() - if err != nil { - t.Errorf("Message read error: %v", err) + cost := server.tPeer.GetRequestCost(GetProofsV2Msg, len(proofreqs)) + sendRequest(server.tPeer.app, GetProofsV2Msg, 42, cost, proofreqs) + if err := expectResponse(server.tPeer.app, ProofsV2Msg, 42, testBufLimit, proofsV2.NodeList()); err != nil { + t.Errorf("proofs mismatch: %v", err) } - var resp struct { - ReqID, BV uint64 - Data light.NodeList + } +} + +// Tests that CHT proofs can be correctly retrieved. +func TestGetCHTProofsLes1(t *testing.T) { testGetCHTProofs(t, 1) } +func TestGetCHTProofsLes2(t *testing.T) { testGetCHTProofs(t, 2) } + +func testGetCHTProofs(t *testing.T, protocol int) { + config := light.TestServerIndexerConfig + frequency := config.ChtSize + if protocol == 2 { + frequency = config.PairChtSize + } + + waitIndexers := func(cIndexer, bIndexer, btIndexer *core.ChainIndexer) { + expectSections := frequency / config.ChtSize + for { + cs, _, _ := cIndexer.Sections() + bs, _, _ := bIndexer.Sections() + if cs >= expectSections && bs >= expectSections { + break + } + time.Sleep(10 * time.Millisecond) } - if err := msg.Decode(&resp); err != nil { - t.Errorf("reply decode error: %v", err) + } + server, tearDown := newServerEnv(t, int(frequency+config.ChtConfirms), protocol, waitIndexers) + defer tearDown() + bc := server.pm.blockchain.(*core.BlockChain) + + // Assemble the proofs from the different protocols + header := bc.GetHeaderByNumber(frequency - 1) + rlp, _ := rlp.EncodeToBytes(header) + + key := make([]byte, 8) + binary.BigEndian.PutUint64(key, frequency-1) + + proofsV1 := []ChtResp{{ + Header: header, + }} + proofsV2 := HelperTrieResps{ + AuxData: [][]byte{rlp}, + } + 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))) + + var proof light.NodeList + trie.Prove(key, 0, &proof) + proofsV1[0].Proof = proof + + 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.Prove(key, 0, &proofsV2.Proofs) + } + // Assemble the requests for the different protocols + requestsV1 := []ChtReq{{ + ChtNum: frequency / config.ChtSize, + BlockNum: frequency - 1, + }} + requestsV2 := []HelperTrieReq{{ + Type: htCanonical, + TrieIdx: frequency/config.PairChtSize - 1, + Key: key, + AuxReq: auxHeader, + }} + // Send the proof request and verify the response + switch protocol { + case 1: + cost := server.tPeer.GetRequestCost(GetHeaderProofsMsg, len(requestsV1)) + sendRequest(server.tPeer.app, GetHeaderProofsMsg, 42, cost, requestsV1) + if err := expectResponse(server.tPeer.app, HeaderProofsMsg, 42, testBufLimit, proofsV1); err != nil { + t.Errorf("proofs mismatch: %v", err) } - if msg.Code != ProofsV2Msg { - t.Errorf("Message code mismatch") + case 2: + cost := server.tPeer.GetRequestCost(GetHelperTrieProofsMsg, len(requestsV2)) + sendRequest(server.tPeer.app, GetHelperTrieProofsMsg, 42, cost, requestsV2) + if err := expectResponse(server.tPeer.app, HelperTrieProofsMsg, 42, testBufLimit, proofsV2); err != nil { + t.Errorf("proofs mismatch: %v", err) } - if resp.ReqID != 42 { - t.Errorf("ReqID mismatch") + } +} + +// Tests that bloombits proofs can be correctly retrieved. +func TestGetBloombitsProofs(t *testing.T) { + config := light.TestServerIndexerConfig + + waitIndexers := func(cIndexer, bIndexer, btIndexer *core.ChainIndexer) { + for { + cs, _, _ := cIndexer.Sections() + bs, _, _ := bIndexer.Sections() + bts, _, _ := btIndexer.Sections() + if cs >= 8 && bs >= 8 && bts >= 1 { + break + } + time.Sleep(10 * time.Millisecond) } - if resp.BV != testBufLimit { - t.Errorf("BV mismatch") + } + server, tearDown := newServerEnv(t, int(config.BloomTrieSize+config.BloomTrieConfirms), 2, waitIndexers) + defer tearDown() + bc := server.pm.blockchain.(*core.BlockChain) + + // Request and verify each bit of the bloom bits proofs + for bit := 0; bit < 2048; bit++ { + // Assemble the request and proofs for the bloombits + key := make([]byte, 10) + + binary.BigEndian.PutUint16(key[:2], uint16(bit)) + // Only the first bloom section has data. + binary.BigEndian.PutUint64(key[2:], 0) + + requests := []HelperTrieReq{{ + Type: htBloomBits, + TrieIdx: 0, + Key: key, + }} + 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.Prove(key, 0, &proofs.Proofs) + + // Send the proof request and verify the response + cost := server.tPeer.GetRequestCost(GetHelperTrieProofsMsg, len(requests)) + sendRequest(server.tPeer.app, GetHelperTrieProofsMsg, 42, cost, requests) + if err := expectResponse(server.tPeer.app, HelperTrieProofsMsg, 42, testBufLimit, proofs); err != nil { + t.Errorf("bit %d: proofs mismatch: %v", bit, err) } - testCheckProof(t, proofsV2, resp.Data) } } func TestTransactionStatusLes2(t *testing.T) { - db, _ := ethdb.NewMemDatabase() - pm := newTestProtocolManagerMust(t, false, 0, nil, nil, nil, db) + db := ethdb.NewMemDatabase() + pm := newTestProtocolManagerMust(t, false, 0, nil, nil, nil, db, nil) chain := pm.blockchain.(*core.BlockChain) config := core.DefaultTxPoolConfig config.Journal = "" @@ -479,9 +558,9 @@ func TestTransactionStatusLes2(t *testing.T) { } // check if their status is included now - block1hash := core.GetCanonicalHash(db, 1) - test(tx1, false, txStatus{Status: core.TxStatusIncluded, Lookup: &core.TxLookupEntry{BlockHash: block1hash, BlockIndex: 1, Index: 0}}) - test(tx2, false, txStatus{Status: core.TxStatusIncluded, Lookup: &core.TxLookupEntry{BlockHash: block1hash, BlockIndex: 1, Index: 1}}) + block1hash := rawdb.ReadCanonicalHash(db, 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/les/helper_test.go b/les/helper_test.go index 57e6939962..a8097708ee 100644 --- a/les/helper_test.go +++ b/les/helper_test.go @@ -24,19 +24,22 @@ import ( "math/big" "sync" "testing" + "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/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/les/flowcontrol" "github.com/ethereum/go-ethereum/light" "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/discover" + "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/params" ) @@ -55,6 +58,9 @@ var ( testContractCodeDeployed = testContractCode[16:] testContractDeployed = uint64(2) + testEventEmitterCode = common.Hex2Bytes("60606040523415600e57600080fd5b7f57050ab73f6b9ebdd9f76b8d4997793f48cf956e965ee070551b9ca0bb71584e60405160405180910390a160358060476000396000f3006060604052600080fd00a165627a7a723058203f727efcad8b5811f8cb1fc2620ce5e8c63570d697aef968172de296ea3994140029") + testEventEmitterAddr common.Address + testBufLimit = uint64(100) ) @@ -85,15 +91,19 @@ func testChainGen(i int, block *core.BlockGen) { // In block 2, the test bank sends some more ether to account #1. // acc1Addr passes it on to account #2. // acc1Addr creates a test contract. - tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey) + // acc1Addr creates a test event. nonce := block.TxNonce(acc1Addr) + + tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey) tx2, _ := types.SignTx(types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key) - nonce++ - tx3, _ := types.SignTx(types.NewContractCreation(nonce, big.NewInt(0), 200000, big.NewInt(0), testContractCode), signer, acc1Key) - testContractAddr = crypto.CreateAddress(acc1Addr, nonce) + tx3, _ := types.SignTx(types.NewContractCreation(nonce+1, big.NewInt(0), 200000, big.NewInt(0), testContractCode), signer, acc1Key) + testContractAddr = crypto.CreateAddress(acc1Addr, nonce+1) + tx4, _ := types.SignTx(types.NewContractCreation(nonce+2, big.NewInt(0), 200000, big.NewInt(0), testEventEmitterCode), signer, acc1Key) + testEventEmitterAddr = crypto.CreateAddress(acc1Addr, nonce+2) block.AddTx(tx1) block.AddTx(tx2) block.AddTx(tx3) + block.AddTx(tx4) case 2: // Block 3 is empty but was mined by account #2. block.SetCoinbase(acc2Addr) @@ -115,20 +125,19 @@ func testChainGen(i int, block *core.BlockGen) { } } -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 +// testIndexers creates a set of indexers with specified params for testing purpose. +func testIndexers(db ethdb.Database, odr light.OdrBackend, iConfig *light.IndexerConfig) (*core.ChainIndexer, *core.ChainIndexer, *core.ChainIndexer) { + chtIndexer := light.NewChtIndexer(db, odr, iConfig.ChtSize, iConfig.ChtConfirms) + bloomIndexer := eth.NewBloomIndexer(db, iConfig.BloomSize, iConfig.BloomConfirms) + bloomTrieIndexer := light.NewBloomTrieIndexer(db, odr, iConfig.BloomSize, iConfig.BloomTrieSize) + bloomIndexer.AddChildIndexer(bloomTrieIndexer) + return chtIndexer, bloomIndexer, bloomTrieIndexer } // 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(lightSync bool, blocks int, generator func(int, *core.BlockGen), peers *peerSet, odr *LesOdr, db ethdb.Database) (*ProtocolManager, error) { +// 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, ulcConfig *eth.ULCConfig) (*ProtocolManager, error) { var ( evmux = new(event.TypeMux) engine = ethash.NewFaker() @@ -146,7 +155,7 @@ func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *cor if lightSync { chain, _ = light.NewLightChain(odr, gspec.Config, engine) } else { - blockchain, _ := core.NewBlockChain(db, gspec.Config, engine, vm.Config{}) + blockchain, _ := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil) gchain, _ := core.GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, blocks, generator) if _, err := blockchain.InsertChain(gchain); err != nil { panic(err) @@ -154,38 +163,36 @@ func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *cor chain = blockchain } - var protocolVersions []uint + indexConfig := light.TestServerIndexerConfig if lightSync { - protocolVersions = ClientProtocolVersions - } else { - protocolVersions = ServerProtocolVersions + indexConfig = light.TestClientIndexerConfig } - pm, err := NewProtocolManager(gspec.Config, lightSync, protocolVersions, NetworkId, evmux, engine, peers, chain, nil, db, odr, 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{protocolManager: pm} + 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() + pm.Start(1000) return pm, nil } // newTestProtocolManagerMust creates a new protocol manager for testing purposes, -// with the given number of blocks already known, and potential notification -// channels for different events. In case of an error, the constructor force- +// 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), peers *peerSet, odr *LesOdr, db ethdb.Database) *ProtocolManager { - pm, err := newTestProtocolManager(lightSync, blocks, generator, peers, odr, 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) } @@ -205,7 +212,7 @@ func newTestPeer(t *testing.T, name string, version int, pm *ProtocolManager, sh app, net := p2p.MsgPipe() // Generate a random id and create the peer - var id discover.NodeID + var id enode.ID rand.Read(id[:]) peer := pm.newPeer(version, NetworkId, p2p.NewPeer(id, name, nil), net) @@ -242,7 +249,7 @@ func newTestPeerPair(name string, version int, pm, pm2 *ProtocolManager) (*peer, app, net := p2p.MsgPipe() // Generate a random id and create the peer - var id discover.NodeID + var id enode.ID rand.Read(id[:]) peer := pm.newPeer(version, NetworkId, p2p.NewPeer(id, name, nil), net) @@ -288,7 +295,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) @@ -297,7 +304,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, } @@ -308,3 +315,122 @@ func (p *testPeer) handshake(t *testing.T, td *big.Int, head common.Hash, headNu func (p *testPeer) close() { p.app.Close() } + +// TestEntity represents a network entity for testing with necessary auxiliary fields. +type TestEntity struct { + db ethdb.Database + rPeer *peer + tPeer *testPeer + peers *peerSet + pm *ProtocolManager + // Indexers + chtIndexer *core.ChainIndexer + bloomIndexer *core.ChainIndexer + bloomTrieIndexer *core.ChainIndexer +} + +// 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() + cIndexer, bIndexer, btIndexer := testIndexers(db, nil, light.TestServerIndexerConfig) + + pm := newTestProtocolManagerMust(t, false, blocks, testChainGen, nil, nil, db, nil) + peer, _ := newTestPeer(t, "peer", protocol, pm, true) + + cIndexer.Start(pm.blockchain.(*core.BlockChain)) + bIndexer.Start(pm.blockchain.(*core.BlockChain)) + + // Wait until indexers generate enough index data. + if waitIndexers != nil { + waitIndexers(cIndexer, bIndexer, btIndexer) + } + + return &TestEntity{ + db: db, + tPeer: peer, + pm: pm, + chtIndexer: cIndexer, + bloomIndexer: bIndexer, + bloomTrieIndexer: btIndexer, + }, func() { + peer.close() + // Note bloom trie indexer will be closed by it parent recursively. + cIndexer.Close() + bIndexer.Close() + } +} + +// 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() + peers, lPeers := newPeerSet(), newPeerSet() + + dist := newRequestDistributor(lPeers, make(chan struct{}), &mclock.System{}) + rm := newRetrieveManager(lPeers, dist, nil) + odr := NewLesOdr(ldb, light.TestClientIndexerConfig, rm) + + cIndexer, bIndexer, btIndexer := testIndexers(db, nil, light.TestServerIndexerConfig) + lcIndexer, lbIndexer, lbtIndexer := testIndexers(ldb, odr, light.TestClientIndexerConfig) + odr.SetIndexers(lcIndexer, lbtIndexer, lbIndexer) + + 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 { + lcIndexer.Start(pm.blockchain.(*light.LightChain)) + lbIndexer.Start(pm.blockchain.(*light.LightChain)) + } else { + cIndexer.Start(pm.blockchain.(*core.BlockChain)) + bIndexer.Start(pm.blockchain.(*core.BlockChain)) + } + } + + startIndexers(false, pm) + startIndexers(true, lpm) + + // Execute wait until function if it is specified. + if waitIndexers != nil { + waitIndexers(cIndexer, bIndexer, btIndexer) + } + + var ( + peer, lPeer *peer + err1, err2 <-chan error + ) + if newPeer { + peer, err1, lPeer, err2 = newTestPeerPair("peer", protocol, pm, lpm) + select { + case <-time.After(time.Millisecond * 100): + case err := <-err1: + t.Fatalf("peer 1 handshake error: %v", err) + case err := <-err2: + t.Fatalf("peer 2 handshake error: %v", err) + } + } + + return &TestEntity{ + db: db, + pm: pm, + rPeer: peer, + peers: peers, + chtIndexer: cIndexer, + bloomIndexer: bIndexer, + bloomTrieIndexer: btIndexer, + }, &TestEntity{ + db: ldb, + pm: lpm, + rPeer: lPeer, + peers: lPeers, + chtIndexer: lcIndexer, + bloomIndexer: lbIndexer, + bloomTrieIndexer: lbtIndexer, + }, func() { + // Note bloom trie indexers will be closed by their parents recursively. + cIndexer.Close() + bIndexer.Close() + lcIndexer.Close() + lbIndexer.Close() + } +} diff --git a/les/metrics.go b/les/metrics.go index 0162a1d1ad..c282a62a1a 100644 --- a/les/metrics.go +++ b/les/metrics.go @@ -58,10 +58,10 @@ var ( reqReceiptInTrafficMeter = metrics.NewMeter("eth/req/receipts/in/traffic") reqReceiptOutPacketsMeter = metrics.NewMeter("eth/req/receipts/out/packets") reqReceiptOutTrafficMeter = metrics.NewMeter("eth/req/receipts/out/traffic")*/ - miscInPacketsMeter = metrics.NewMeter("les/misc/in/packets") - miscInTrafficMeter = metrics.NewMeter("les/misc/in/traffic") - miscOutPacketsMeter = metrics.NewMeter("les/misc/out/packets") - miscOutTrafficMeter = metrics.NewMeter("les/misc/out/traffic") + miscInPacketsMeter = metrics.NewRegisteredMeter("les/misc/in/packets", nil) + miscInTrafficMeter = metrics.NewRegisteredMeter("les/misc/in/traffic", nil) + miscOutPacketsMeter = metrics.NewRegisteredMeter("les/misc/out/packets", nil) + miscOutTrafficMeter = metrics.NewRegisteredMeter("les/misc/out/traffic", nil) ) // meteredMsgReadWriter is a wrapper around a p2p.MsgReadWriter, capable of diff --git a/les/odr.go b/les/odr.go index f8412aaad7..5d98c66a90 100644 --- a/les/odr.go +++ b/les/odr.go @@ -28,19 +28,18 @@ import ( // LesOdr implements light.OdrBackend type LesOdr struct { db ethdb.Database + indexerConfig *light.IndexerConfig chtIndexer, bloomTrieIndexer, bloomIndexer *core.ChainIndexer retriever *retrieveManager stop chan struct{} } -func NewLesOdr(db ethdb.Database, chtIndexer, bloomTrieIndexer, bloomIndexer *core.ChainIndexer, retriever *retrieveManager) *LesOdr { +func NewLesOdr(db ethdb.Database, config *light.IndexerConfig, retriever *retrieveManager) *LesOdr { return &LesOdr{ - db: db, - chtIndexer: chtIndexer, - bloomTrieIndexer: bloomTrieIndexer, - bloomIndexer: bloomIndexer, - retriever: retriever, - stop: make(chan struct{}), + db: db, + indexerConfig: config, + retriever: retriever, + stop: make(chan struct{}), } } @@ -54,6 +53,13 @@ func (odr *LesOdr) Database() ethdb.Database { return odr.db } +// SetIndexers adds the necessary chain indexers to the ODR backend +func (odr *LesOdr) SetIndexers(chtIndexer, bloomTrieIndexer, bloomIndexer *core.ChainIndexer) { + odr.chtIndexer = chtIndexer + odr.bloomTrieIndexer = bloomTrieIndexer + odr.bloomIndexer = bloomIndexer +} + // ChtIndexer returns the CHT chain indexer func (odr *LesOdr) ChtIndexer() *core.ChainIndexer { return odr.chtIndexer @@ -69,6 +75,11 @@ func (odr *LesOdr) BloomIndexer() *core.ChainIndexer { return odr.bloomIndexer } +// IndexerConfig returns the indexer config. +func (odr *LesOdr) IndexerConfig() *light.IndexerConfig { + return odr.indexerConfig +} + const ( MsgBlockBodies = iota MsgCode @@ -98,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/les/odr_requests.go b/les/odr_requests.go index 937a4f1d9d..7b7876762d 100644 --- a/les/odr_requests.go +++ b/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 ( @@ -24,7 +22,7 @@ import ( "fmt" "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/crypto" "github.com/ethereum/go-ethereum/ethdb" @@ -84,7 +82,7 @@ func (r *BlockRequest) GetCost(peer *peer) uint64 { // CanSend tells if a certain peer is suitable for serving the given request func (r *BlockRequest) CanSend(peer *peer) bool { - return peer.HasBlock(r.Hash, r.Number) + return peer.HasBlock(r.Hash, r.Number, false) } // Request sends an ODR request to the LES network (implementation of LesOdrRequest) @@ -110,7 +108,7 @@ func (r *BlockRequest) Validate(db ethdb.Database, msg *Msg) error { body := bodies[0] // Retrieve our stored header and validate block content against it - header := core.GetHeader(db, r.Hash, r.Number) + header := rawdb.ReadHeader(db, r.Hash, r.Number) if header == nil { return errHeaderUnavailable } @@ -140,7 +138,7 @@ func (r *ReceiptsRequest) GetCost(peer *peer) uint64 { // CanSend tells if a certain peer is suitable for serving the given request func (r *ReceiptsRequest) CanSend(peer *peer) bool { - return peer.HasBlock(r.Hash, r.Number) + return peer.HasBlock(r.Hash, r.Number, false) } // Request sends an ODR request to the LES network (implementation of LesOdrRequest) @@ -166,7 +164,7 @@ func (r *ReceiptsRequest) Validate(db ethdb.Database, msg *Msg) error { receipt := receipts[0] // Retrieve our stored header and validate receipt content against it - header := core.GetHeader(db, r.Hash, r.Number) + header := rawdb.ReadHeader(db, r.Hash, r.Number) if header == nil { return errHeaderUnavailable } @@ -202,7 +200,7 @@ func (r *TrieRequest) GetCost(peer *peer) uint64 { // CanSend tells if a certain peer is suitable for serving the given request func (r *TrieRequest) CanSend(peer *peer) bool { - return peer.HasBlock(r.Id.BlockHash, r.Id.BlockNumber) + return peer.HasBlock(r.Id.BlockHash, r.Id.BlockNumber, true) } // Request sends an ODR request to the LES network (implementation of LesOdrRequest) @@ -230,7 +228,7 @@ func (r *TrieRequest) Validate(db ethdb.Database, msg *Msg) error { } nodeSet := proofs[0].NodeSet() // Verify the proof and store if checks out - if _, err, _ := trie.VerifyProof(r.Id.Root, r.Key, nodeSet); err != nil { + if _, _, err := trie.VerifyProof(r.Id.Root, r.Key, nodeSet); err != nil { return fmt.Errorf("merkle proof verification failed: %v", err) } r.Proof = nodeSet @@ -241,7 +239,7 @@ func (r *TrieRequest) Validate(db ethdb.Database, msg *Msg) error { // Verify the proof and store if checks out nodeSet := proofs.NodeSet() reads := &readTraceDB{db: nodeSet} - if _, err, _ := trie.VerifyProof(r.Id.Root, r.Key, reads); err != nil { + if _, _, err := trie.VerifyProof(r.Id.Root, r.Key, reads); err != nil { return fmt.Errorf("merkle proof verification failed: %v", err) } // check if all nodes have been read by VerifyProof @@ -272,7 +270,7 @@ func (r *CodeRequest) GetCost(peer *peer) uint64 { // CanSend tells if a certain peer is suitable for serving the given request func (r *CodeRequest) CanSend(peer *peer) bool { - return peer.HasBlock(r.Id.BlockHash, r.Id.BlockNumber) + return peer.HasBlock(r.Id.BlockHash, r.Id.BlockNumber, true) } // Request sends an ODR request to the LES network (implementation of LesOdrRequest) @@ -321,7 +319,7 @@ const ( ) type HelperTrieReq struct { - HelperTrieType uint + Type uint TrieIdx uint64 Key []byte FromLevel, AuxReq uint @@ -365,7 +363,7 @@ func (r *ChtRequest) CanSend(peer *peer) bool { peer.lock.RLock() defer peer.lock.RUnlock() - return peer.headInfo.Number >= light.HelperTrieConfirmations && r.ChtNum <= (peer.headInfo.Number-light.HelperTrieConfirmations)/light.ChtFrequency + return peer.headInfo.Number >= r.Config.ChtConfirms && r.ChtNum <= (peer.headInfo.Number-r.Config.ChtConfirms)/r.Config.ChtSize } // Request sends an ODR request to the LES network (implementation of LesOdrRequest) @@ -374,12 +372,26 @@ func (r *ChtRequest) Request(reqID uint64, peer *peer) error { var encNum [8]byte binary.BigEndian.PutUint64(encNum[:], r.BlockNum) req := HelperTrieReq{ - HelperTrieType: htCanonical, - TrieIdx: r.ChtNum, - Key: encNum[:], - AuxReq: auxHeader, + Type: htCanonical, + TrieIdx: r.ChtNum, + Key: encNum[:], + AuxReq: auxHeader, + } + switch peer.version { + case lpv1: + var reqsV1 ChtReq + if req.Type != htCanonical || req.AuxReq != auxHeader || len(req.Key) != 8 { + return fmt.Errorf("Request invalid in LES/1 mode") + } + blockNum := binary.BigEndian.Uint64(req.Key) + // convert HelperTrie request to old CHT request + reqsV1 = ChtReq{ChtNum: (req.TrieIdx + 1) * (r.Config.ChtSize / r.Config.PairChtSize), BlockNum: blockNum, FromLevel: req.FromLevel} + return peer.RequestHelperTrieProofs(reqID, r.GetCost(peer), []ChtReq{reqsV1}) + case lpv2: + return peer.RequestHelperTrieProofs(reqID, r.GetCost(peer), []HelperTrieReq{req}) + default: + panic(nil) } - return peer.RequestHelperTrieProofs(reqID, r.GetCost(peer), []HelperTrieReq{req}) } // Valid processes an ODR request reply message from the LES network @@ -400,7 +412,7 @@ func (r *ChtRequest) Validate(db ethdb.Database, msg *Msg) error { var encNumber [8]byte binary.BigEndian.PutUint64(encNumber[:], r.BlockNum) - value, err, _ := trie.VerifyProof(r.ChtRoot, encNumber[:], light.NodeList(proof.Proof).NodeSet()) + value, _, err := trie.VerifyProof(r.ChtRoot, encNumber[:], light.NodeList(proof.Proof).NodeSet()) if err != nil { return err } @@ -435,7 +447,7 @@ func (r *ChtRequest) Validate(db ethdb.Database, msg *Msg) error { binary.BigEndian.PutUint64(encNumber[:], r.BlockNum) reads := &readTraceDB{db: nodeSet} - value, err, _ := trie.VerifyProof(r.ChtRoot, encNumber[:], reads) + value, _, err := trie.VerifyProof(r.ChtRoot, encNumber[:], reads) if err != nil { return fmt.Errorf("merkle proof verification failed: %v", err) } @@ -464,7 +476,7 @@ func (r *ChtRequest) Validate(db ethdb.Database, msg *Msg) error { } type BloomReq struct { - BloomTrieNum, BitIdx, SectionIdx, FromLevel uint64 + BloomTrieNum, BitIdx, SectionIndex, FromLevel uint64 } // ODR request type for requesting headers by Canonical Hash Trie, see LesOdrRequest interface @@ -473,7 +485,7 @@ type BloomRequest light.BloomRequest // GetCost returns the cost of the given ODR request according to the serving // peer's cost table (implementation of LesOdrRequest) func (r *BloomRequest) GetCost(peer *peer) uint64 { - return peer.GetRequestCost(GetHelperTrieProofsMsg, len(r.SectionIdxList)) + return peer.GetRequestCost(GetHelperTrieProofsMsg, len(r.SectionIndexList)) } // CanSend tells if a certain peer is suitable for serving the given request @@ -484,23 +496,23 @@ func (r *BloomRequest) CanSend(peer *peer) bool { if peer.version < lpv2 { return false } - return peer.headInfo.Number >= light.HelperTrieConfirmations && r.BloomTrieNum <= (peer.headInfo.Number-light.HelperTrieConfirmations)/light.BloomTrieFrequency + return peer.headInfo.Number >= r.Config.BloomTrieConfirms && r.BloomTrieNum <= (peer.headInfo.Number-r.Config.BloomTrieConfirms)/r.Config.BloomTrieSize } // Request sends an ODR request to the LES network (implementation of LesOdrRequest) func (r *BloomRequest) Request(reqID uint64, peer *peer) error { - peer.Log().Debug("Requesting BloomBits", "bloomTrie", r.BloomTrieNum, "bitIdx", r.BitIdx, "sections", r.SectionIdxList) - reqs := make([]HelperTrieReq, len(r.SectionIdxList)) + peer.Log().Debug("Requesting BloomBits", "bloomTrie", r.BloomTrieNum, "bitIdx", r.BitIdx, "sections", r.SectionIndexList) + reqs := make([]HelperTrieReq, len(r.SectionIndexList)) var encNumber [10]byte - binary.BigEndian.PutUint16(encNumber[0:2], uint16(r.BitIdx)) + binary.BigEndian.PutUint16(encNumber[:2], uint16(r.BitIdx)) - for i, sectionIdx := range r.SectionIdxList { - binary.BigEndian.PutUint64(encNumber[2:10], sectionIdx) + for i, sectionIdx := range r.SectionIndexList { + binary.BigEndian.PutUint64(encNumber[2:], sectionIdx) reqs[i] = HelperTrieReq{ - HelperTrieType: htBloomBits, - TrieIdx: r.BloomTrieNum, - Key: common.CopyBytes(encNumber[:]), + Type: htBloomBits, + TrieIdx: r.BloomTrieNum, + Key: common.CopyBytes(encNumber[:]), } } return peer.RequestHelperTrieProofs(reqID, r.GetCost(peer), reqs) @@ -510,7 +522,7 @@ func (r *BloomRequest) Request(reqID uint64, peer *peer) error { // returns true and stores results in memory if the message was a valid reply // to the request (implementation of LesOdrRequest) func (r *BloomRequest) Validate(db ethdb.Database, msg *Msg) error { - log.Debug("Validating BloomBits", "bloomTrie", r.BloomTrieNum, "bitIdx", r.BitIdx, "sections", r.SectionIdxList) + log.Debug("Validating BloomBits", "bloomTrie", r.BloomTrieNum, "bitIdx", r.BitIdx, "sections", r.SectionIndexList) // Ensure we have a correct message with a single proof element if msg.MsgType != MsgHelperTrieProofs { @@ -521,15 +533,15 @@ func (r *BloomRequest) Validate(db ethdb.Database, msg *Msg) error { nodeSet := proofs.NodeSet() reads := &readTraceDB{db: nodeSet} - r.BloomBits = make([][]byte, len(r.SectionIdxList)) + r.BloomBits = make([][]byte, len(r.SectionIndexList)) // Verify the proofs var encNumber [10]byte - binary.BigEndian.PutUint16(encNumber[0:2], uint16(r.BitIdx)) + binary.BigEndian.PutUint16(encNumber[:2], uint16(r.BitIdx)) - for i, idx := range r.SectionIdxList { - binary.BigEndian.PutUint64(encNumber[2:10], idx) - value, err, _ := trie.VerifyProof(r.BloomTrieRoot, encNumber[:], reads) + for i, idx := range r.SectionIndexList { + binary.BigEndian.PutUint64(encNumber[2:], idx) + value, _, err := trie.VerifyProof(r.BloomTrieRoot, encNumber[:], reads) if err != nil { return err } diff --git a/les/odr_test.go b/les/odr_test.go index cf609be882..ac81fbcf02 100644 --- a/les/odr_test.go +++ b/les/odr_test.go @@ -26,10 +26,10 @@ import ( "github.com/ethereum/go-ethereum/common" "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/eth" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/light" "github.com/ethereum/go-ethereum/params" @@ -63,9 +63,13 @@ func TestOdrGetReceiptsLes2(t *testing.T) { testOdr(t, 2, 1, odrGetReceipts) } func odrGetReceipts(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte { var receipts types.Receipts if bc != nil { - receipts = core.GetBlockReceipts(db, bhash, core.GetBlockNumber(db, bhash)) + if number := rawdb.ReadHeaderNumber(db, bhash); number != nil { + receipts = rawdb.ReadReceipts(db, bhash, *number) + } } else { - receipts, _ = light.GetBlockReceipts(ctx, lc.Odr(), bhash, core.GetBlockNumber(db, bhash)) + if number := rawdb.ReadHeaderNumber(db, bhash); number != nil { + receipts, _ = light.GetBlockReceipts(ctx, lc.Odr(), bhash, *number) + } } if receipts == nil { return nil @@ -101,7 +105,6 @@ func odrAccounts(ctx context.Context, db ethdb.Database, config *params.ChainCon res = append(res, rlp...) } } - return res } @@ -156,35 +159,21 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai return res } +// testOdr tests odr requests whose validation guaranteed by block headers. func testOdr(t *testing.T, protocol int, expFail uint64, fn odrTestFn) { // Assemble the test environment - peers := newPeerSet() - dist := newRequestDistributor(peers, make(chan struct{})) - rm := newRetrieveManager(peers, dist, nil) - db, _ := ethdb.NewMemDatabase() - ldb, _ := ethdb.NewMemDatabase() - odr := NewLesOdr(ldb, light.NewChtIndexer(db, true), light.NewBloomTrieIndexer(db, true), eth.NewBloomIndexer(db, light.BloomTrieFrequency), rm) - pm := newTestProtocolManagerMust(t, false, 4, testChainGen, nil, nil, db) - lpm := newTestProtocolManagerMust(t, true, 0, nil, peers, odr, ldb) - _, err1, lpeer, err2 := newTestPeerPair("peer", protocol, pm, lpm) - select { - case <-time.After(time.Millisecond * 100): - case err := <-err1: - t.Fatalf("peer 1 handshake error: %v", err) - case err := <-err2: - t.Fatalf("peer 1 handshake error: %v", err) - } - - lpm.synchronise(lpeer) + server, client, tearDown := newClientServerEnv(t, 4, protocol, nil, true) + defer tearDown() + client.pm.synchronise(client.rPeer) test := func(expFail uint64) { - for i := uint64(0); i <= pm.blockchain.CurrentHeader().Number.Uint64(); i++ { - bhash := core.GetCanonicalHash(db, i) - b1 := fn(light.NoOdr, db, pm.chainConfig, pm.blockchain.(*core.BlockChain), nil, bhash) + for i := uint64(0); i <= server.pm.blockchain.CurrentHeader().Number.Uint64(); i++ { + bhash := rawdb.ReadCanonicalHash(server.db, i) + b1 := fn(light.NoOdr, server.db, server.pm.chainConfig, server.pm.blockchain.(*core.BlockChain), nil, bhash) ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond) defer cancel() - b2 := fn(ctx, ldb, lpm.chainConfig, nil, lpm.blockchain.(*light.LightChain), bhash) + b2 := fn(ctx, client.db, client.pm.chainConfig, nil, client.pm.blockchain.(*light.LightChain), bhash) eq := bytes.Equal(b1, b2) exp := i < expFail @@ -196,21 +185,20 @@ func testOdr(t *testing.T, protocol int, expFail uint64, fn odrTestFn) { } } } - // temporarily remove peer to test odr fails // expect retrievals to fail (except genesis block) without a les peer - peers.Unregister(lpeer.id) + client.peers.Unregister(client.rPeer.id) time.Sleep(time.Millisecond * 10) // ensure that all peerSetNotify callbacks are executed test(expFail) // expect all retrievals to pass - peers.Register(lpeer) + client.peers.Register(client.rPeer) time.Sleep(time.Millisecond * 10) // ensure that all peerSetNotify callbacks are executed - lpeer.lock.Lock() - lpeer.hasBlock = func(common.Hash, uint64) bool { return true } - lpeer.lock.Unlock() + client.peers.lock.Lock() + client.rPeer.hasBlock = func(common.Hash, uint64, bool) bool { return true } + client.peers.lock.Unlock() test(5) // still expect all retrievals to pass, now data should be cached locally - peers.Unregister(lpeer.id) + client.peers.Unregister(client.rPeer.id) time.Sleep(time.Millisecond * 10) // ensure that all peerSetNotify callbacks are executed test(5) } diff --git a/les/peer.go b/les/peer.go index b72c80d35a..8b506de629 100644 --- a/les/peer.go +++ b/les/peer.go @@ -14,12 +14,9 @@ // 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" "errors" "fmt" "math/big" @@ -27,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" @@ -36,13 +34,25 @@ import ( ) var ( - errClosed = errors.New("peer set is closed") - errAlreadyRegistered = errors.New("peer is already registered") - errNotRegistered = errors.New("peer is not registered") + errClosed = errors.New("peer set is closed") + errAlreadyRegistered = errors.New("peer is already registered") + errNotRegistered = errors.New("peer is not registered") + errInvalidHelpTrieReq = errors.New("invalid help trie request") ) 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 @@ -51,48 +61,76 @@ const ( type peer struct { *p2p.Peer - pubKey *ecdsa.PublicKey rw p2p.MsgReadWriter 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 + 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 { +func newPeer(version int, network uint64, isTrusted bool, p *p2p.Peer, rw p2p.MsgReadWriter) *peer { id := p.ID() - pubKey, _ := id.Pubkey() return &peer{ - Peer: p, - pubKey: pubKey, - 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", id), + isTrusted: isTrusted, } } +// 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() } @@ -147,6 +185,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 @@ -155,12 +207,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 { @@ -168,18 +235,44 @@ 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 } // HasBlock checks if the peer has a given block -func (p *peer) HasBlock(hash common.Hash, number uint64) bool { +func (p *peer) HasBlock(hash common.Hash, number uint64, hasState bool) bool { p.lock.RLock() hasBlock := p.hasBlock p.lock.RUnlock() - return hasBlock != nil && hasBlock(hash, number) + return hasBlock != nil && hasBlock(hash, number, hasState) } // SendAnnounce announces the availability of a number of blocks through @@ -188,52 +281,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 @@ -281,25 +383,24 @@ func (p *peer) RequestProofs(reqID, cost uint64, reqs []ProofReq) error { default: panic(nil) } - } // RequestHelperTrieProofs fetches a batch of HelperTrie merkle proofs from a remote node. -func (p *peer) RequestHelperTrieProofs(reqID, cost uint64, reqs []HelperTrieReq) error { - p.Log().Debug("Fetching batch of HelperTrie proofs", "count", len(reqs)) +func (p *peer) RequestHelperTrieProofs(reqID, cost uint64, data interface{}) error { switch p.version { case lpv1: - reqsV1 := make([]ChtReq, len(reqs)) - for i, req := range reqs { - if req.HelperTrieType != htCanonical || req.AuxReq != auxHeader || len(req.Key) != 8 { - return fmt.Errorf("Request invalid in LES/1 mode") - } - blockNum := binary.BigEndian.Uint64(req.Key) - // convert HelperTrie request to old CHT request - reqsV1[i] = ChtReq{ChtNum: (req.TrieIdx + 1) * (light.ChtFrequency / light.ChtV1Frequency), BlockNum: blockNum, FromLevel: req.FromLevel} + reqs, ok := data.([]ChtReq) + if !ok { + return errInvalidHelpTrieReq } - return sendRequest(p.rw, GetHeaderProofsMsg, reqID, cost, reqsV1) + p.Log().Debug("Fetching batch of header proofs", "count", len(reqs)) + return sendRequest(p.rw, GetHeaderProofsMsg, reqID, cost, reqs) case lpv2: + reqs, ok := data.([]HelperTrieReq) + if !ok { + return errInvalidHelpTrieReq + } + p.Log().Debug("Fetching batch of HelperTrie proofs", "count", len(reqs)) return sendRequest(p.rw, GetHelperTrieProofsMsg, reqID, cost, reqs) default: panic(nil) @@ -312,9 +413,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 @@ -345,12 +446,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 { @@ -406,24 +509,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 @@ -457,26 +577,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 } @@ -487,15 +615,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, @@ -546,9 +697,11 @@ func (ps *peerSet) notify(n peerSetNotify) { func (ps *peerSet) Register(p *peer) error { ps.lock.Lock() if ps.closed { + ps.lock.Unlock() return errClosed } if _, ok := ps.peers[p.id]; ok { + ps.lock.Unlock() return errAlreadyRegistered } ps.peers[p.id] = p @@ -579,8 +732,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/les/peer_test.go b/les/peer_test.go new file mode 100644 index 0000000000..8b12dd291c --- /dev/null +++ b/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/les/protocol.go b/les/protocol.go index e1c4625bce..65395ac052 100644 --- a/les/protocol.go +++ b/les/protocol.go @@ -14,13 +14,10 @@ // 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 ( - "bytes" "crypto/ecdsa" - "crypto/elliptic" "errors" "fmt" "io" @@ -28,8 +25,9 @@ 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/crypto" - "github.com/ethereum/go-ethereum/crypto/secp256k1" + "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/rlp" ) @@ -82,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 ( @@ -147,22 +164,20 @@ 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(pubKey *ecdsa.PublicKey) 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}) - recPubkey, err := secp256k1.RecoverPubkey(crypto.Keccak256(rlp), sig) + recPubkey, err := crypto.SigToPub(crypto.Keccak256(rlp), sig) if err != nil { return err } - pbytes := elliptic.Marshal(pubKey.Curve, pubKey.X, pubKey.Y) - if bytes.Equal(pbytes, recPubkey) { + if id == enode.PubkeyToIDV4(recPubkey) { return nil - } else { - return errors.New("Wrong signature") } + return errors.New("wrong signature") } type blockInfo struct { @@ -224,6 +239,6 @@ type proofsData [][]rlp.RawValue type txStatus struct { Status core.TxStatus - Lookup *core.TxLookupEntry `rlp:"nil"` + Lookup *rawdb.LegacyTxLookupEntry `rlp:"nil"` Error string } diff --git a/les/randselect.go b/les/randselect.go index 1a9d0695bd..8efe0c94d3 100644 --- a/les/randselect.go +++ b/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 ( @@ -118,17 +117,16 @@ func (n *wrsNode) insert(item wrsItem, weight int64) int { if n.level == 0 { n.items[branch] = item return branch - } else { - var subNode *wrsNode - if n.items[branch] == nil { - subNode = &wrsNode{maxItems: n.maxItems / wrsBranches, level: n.level - 1} - n.items[branch] = subNode - } else { - subNode = n.items[branch].(*wrsNode) - } - subIdx := subNode.insert(item, weight) - return subNode.maxItems*branch + subIdx } + var subNode *wrsNode + if n.items[branch] == nil { + subNode = &wrsNode{maxItems: n.maxItems / wrsBranches, level: n.level - 1} + n.items[branch] = subNode + } else { + subNode = n.items[branch].(*wrsNode) + } + subIdx := subNode.insert(item, weight) + return subNode.maxItems*branch + subIdx } // setWeight updates the weight of a certain item (which should exist) and returns @@ -162,12 +160,10 @@ func (n *wrsNode) choose(val int64) (wrsItem, int64) { if val < w { if n.level == 0 { return n.items[i].(wrsItem), n.weights[i] - } else { - return n.items[i].(*wrsNode).choose(val) } - } else { - val -= w + return n.items[i].(*wrsNode).choose(val) } + val -= w } panic(nil) } diff --git a/les/request_test.go b/les/request_test.go index c13625de8e..c9c1851982 100644 --- a/les/request_test.go +++ b/les/request_test.go @@ -22,9 +22,8 @@ import ( "time" "github.com/ethereum/go-ethereum/common" - "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/ethdb" "github.com/ethereum/go-ethereum/light" ) @@ -58,15 +57,22 @@ func TestTrieEntryAccessLes1(t *testing.T) { testAccess(t, 1, tfTrieEntryAccess) func TestTrieEntryAccessLes2(t *testing.T) { testAccess(t, 2, tfTrieEntryAccess) } func tfTrieEntryAccess(db ethdb.Database, bhash common.Hash, number uint64) light.OdrRequest { - return &light.TrieRequest{Id: light.StateTrieID(core.GetHeader(db, bhash, core.GetBlockNumber(db, bhash))), Key: testBankSecureTrieKey} + if number := rawdb.ReadHeaderNumber(db, bhash); number != nil { + return &light.TrieRequest{Id: light.StateTrieID(rawdb.ReadHeader(db, bhash, *number)), Key: testBankSecureTrieKey} + } + return nil } func TestCodeAccessLes1(t *testing.T) { testAccess(t, 1, tfCodeAccess) } func TestCodeAccessLes2(t *testing.T) { testAccess(t, 2, tfCodeAccess) } -func tfCodeAccess(db ethdb.Database, bhash common.Hash, number uint64) light.OdrRequest { - header := core.GetHeader(db, bhash, core.GetBlockNumber(db, bhash)) +func tfCodeAccess(db ethdb.Database, bhash common.Hash, num uint64) light.OdrRequest { + number := rawdb.ReadHeaderNumber(db, bhash) + if number != nil { + return nil + } + header := rawdb.ReadHeader(db, bhash, *number) if header.Number.Uint64() < testContractDeployed { return nil } @@ -77,34 +83,17 @@ func tfCodeAccess(db ethdb.Database, bhash common.Hash, number uint64) light.Odr func testAccess(t *testing.T, protocol int, fn accessTestFn) { // Assemble the test environment - peers := newPeerSet() - dist := newRequestDistributor(peers, make(chan struct{})) - rm := newRetrieveManager(peers, dist, nil) - db, _ := ethdb.NewMemDatabase() - ldb, _ := ethdb.NewMemDatabase() - odr := NewLesOdr(ldb, light.NewChtIndexer(db, true), light.NewBloomTrieIndexer(db, true), eth.NewBloomIndexer(db, light.BloomTrieFrequency), rm) - - pm := newTestProtocolManagerMust(t, false, 4, testChainGen, nil, nil, db) - lpm := newTestProtocolManagerMust(t, true, 0, nil, peers, odr, ldb) - _, err1, lpeer, err2 := newTestPeerPair("peer", protocol, pm, lpm) - select { - case <-time.After(time.Millisecond * 100): - case err := <-err1: - t.Fatalf("peer 1 handshake error: %v", err) - case err := <-err2: - t.Fatalf("peer 1 handshake error: %v", err) - } - - lpm.synchronise(lpeer) + server, client, tearDown := newClientServerEnv(t, 4, protocol, nil, true) + defer tearDown() + client.pm.synchronise(client.rPeer) test := func(expFail uint64) { - for i := uint64(0); i <= pm.blockchain.CurrentHeader().Number.Uint64(); i++ { - bhash := core.GetCanonicalHash(db, i) - if req := fn(ldb, bhash, i); req != nil { + for i := uint64(0); i <= server.pm.blockchain.CurrentHeader().Number.Uint64(); i++ { + bhash := rawdb.ReadCanonicalHash(server.db, i) + if req := fn(client.db, bhash, i); req != nil { ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond) defer cancel() - - err := odr.Retrieve(ctx, req) + err := client.pm.odr.Retrieve(ctx, req) got := err == nil exp := i < expFail if exp && !got { @@ -118,16 +107,16 @@ func testAccess(t *testing.T, protocol int, fn accessTestFn) { } // temporarily remove peer to test odr fails - peers.Unregister(lpeer.id) + client.peers.Unregister(client.rPeer.id) time.Sleep(time.Millisecond * 10) // ensure that all peerSetNotify callbacks are executed // expect retrievals to fail (except genesis block) without a les peer test(0) - peers.Register(lpeer) + client.peers.Register(client.rPeer) time.Sleep(time.Millisecond * 10) // ensure that all peerSetNotify callbacks are executed - lpeer.lock.Lock() - lpeer.hasBlock = func(common.Hash, uint64) bool { return true } - lpeer.lock.Unlock() + client.rPeer.lock.Lock() + client.rPeer.hasBlock = func(common.Hash, uint64, bool) bool { return true } + client.rPeer.lock.Unlock() // expect all retrievals to pass test(5) } diff --git a/les/retrieve.go b/les/retrieve.go index dd15b56acf..dd9d14598b 100644 --- a/les/retrieve.go +++ b/les/retrieve.go @@ -1,4 +1,4 @@ -// Copyright 2016 The go-ethereum Authors +// Copyright 2017 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,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 ( @@ -27,6 +25,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common/mclock" + "github.com/ethereum/go-ethereum/light" ) var ( @@ -69,9 +68,9 @@ type sentReq struct { lock sync.RWMutex // protect access to sentTo map sentTo map[distPeer]sentReqToPeer - reqQueued bool // a request has been queued but not sent - reqSent bool // a request has been sent but not timed out - reqSrtoCount int // number of requests that reached soft (but not hard) timeout + lastReqQueued bool // last request has been queued but not sent + lastReqSentTo distPeer // if not nil then last request has been sent to given peer but not timed out + reqSrtoCount int // number of requests that reached soft (but not hard) timeout } // sentReqToPeer notifies the request-from-peer goroutine (tryRequest) about a response @@ -180,7 +179,7 @@ type reqStateFn func() reqStateFn // retrieveLoop is the retrieval state machine event loop func (r *sentReq) retrieveLoop() { go r.tryRequest() - r.reqQueued = true + r.lastReqQueued = true state := r.stateRequesting for state != nil { @@ -207,14 +206,21 @@ func (r *sentReq) stateRequesting() reqStateFn { return r.stateNoMorePeers } // nothing to wait for, no more peers to ask, return with error - r.stop(ErrNoPeers) + r.stop(light.ErrNoPeers) // no need to go to stopped state because waiting() already returned false return nil } case rpSoftTimeout: // last request timed out, try asking a new peer go r.tryRequest() - r.reqQueued = true + r.lastReqQueued = true + return r.stateRequesting + case rpDeliveredInvalid: + // if it was the last sent request (set to nil by update) then start a new one + if !r.lastReqQueued && r.lastReqSentTo == nil { + go r.tryRequest() + r.lastReqQueued = true + } return r.stateRequesting case rpDeliveredValid: r.stop(nil) @@ -233,7 +239,7 @@ func (r *sentReq) stateNoMorePeers() reqStateFn { select { case <-time.After(retryQueue): go r.tryRequest() - r.reqQueued = true + r.lastReqQueued = true return r.stateRequesting case ev := <-r.eventsCh: r.update(ev) @@ -241,7 +247,11 @@ func (r *sentReq) stateNoMorePeers() reqStateFn { r.stop(nil) return r.stateStopped } - return r.stateNoMorePeers + if r.waiting() { + return r.stateNoMorePeers + } + r.stop(light.ErrNoPeers) + return nil case <-r.stopCh: return r.stateStopped } @@ -260,22 +270,26 @@ func (r *sentReq) stateStopped() reqStateFn { func (r *sentReq) update(ev reqPeerEvent) { switch ev.event { case rpSent: - r.reqQueued = false - if ev.peer != nil { - r.reqSent = true - } + r.lastReqQueued = false + r.lastReqSentTo = ev.peer case rpSoftTimeout: - r.reqSent = false + r.lastReqSentTo = nil r.reqSrtoCount++ - case rpHardTimeout, rpDeliveredValid, rpDeliveredInvalid: + case rpHardTimeout: r.reqSrtoCount-- + case rpDeliveredValid, rpDeliveredInvalid: + if ev.peer == r.lastReqSentTo { + r.lastReqSentTo = nil + } else { + r.reqSrtoCount-- + } } } // waiting returns true if the retrieval mechanism is waiting for an answer from // any peer func (r *sentReq) waiting() bool { - return r.reqQueued || r.reqSent || r.reqSrtoCount > 0 + return r.lastReqQueued || r.lastReqSentTo != nil || r.reqSrtoCount > 0 } // tryRequest tries to send the request to a new peer and waits for it to either diff --git a/les/server.go b/les/server.go index ec2e44fecc..270640f025 100644 --- a/les/server.go +++ b/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" - "fmt" - "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/rlp" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rpc" ) -type LesServer struct { - protocolManager *ProtocolManager - fcManager *flowcontrol.ClientManager // nil if our node is client only - fcCostStats *requestCostStats - defParams *flowcontrol.ServerParams - lesTopics []discv5.Topic - privateKey *ecdsa.PrivateKey - quitSync chan struct{} +const bufLimitRatio = 6000 // fixed bufLimit/MRR ratio - chtIndexer, bloomTrieIndexer *core.ChainIndexer +type LesServer struct { + lesCommons + + 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(), false, ServerProtocolVersions, config.NetworkId, eth.EventMux(), eth.Engine(), newPeerSet(), eth.BlockChain(), eth.TxPool(), eth.ChainDb(), 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 } @@ -62,62 +85,147 @@ func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) { } srv := &LesServer{ - protocolManager: pm, - quitSync: quitSync, - lesTopics: lesTopics, - chtIndexer: light.NewChtIndexer(eth.ChainDb(), false), - bloomTrieIndexer: light.NewBloomTrieIndexer(eth.ChainDb(), false), + lesCommons: lesCommons{ + config: config, + chainDb: eth.ChainDb(), + iConfig: light.DefaultServerIndexerConfig, + chtIndexer: light.NewChtIndexer(eth.ChainDb(), nil, params.CHTFrequencyServer, params.HelperTrieProcessConfirmations), + bloomTrieIndexer: light.NewBloomTrieIndexer(eth.ChainDb(), nil, params.BloomBitsBlocks, params.BloomTrieFrequency), + protocolManager: pm, + }, + 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 / (light.ChtFrequency / light.ChtV1Frequency) + chtV2SectionCount := chtV1SectionCount / (params.CHTFrequencyClient / params.CHTFrequencyServer) if chtV2SectionCount != 0 { // convert to LES/2 section chtLastSection := chtV2SectionCount - 1 // convert last LES/2 section index back to LES/1 index for chtIndexer.SectionHead - chtLastSectionV1 := (chtLastSection+1)*(light.ChtFrequency/light.ChtV1Frequency) - 1 + chtLastSectionV1 := (chtLastSection+1)*(params.CHTFrequencyClient/params.CHTFrequencyServer) - 1 chtSectionHead := srv.chtIndexer.SectionHead(chtLastSectionV1) - chtRoot := light.GetChtV2Root(pm.chainDb, chtLastSection, chtSectionHead) - logger.Info("CHT", "section", chtLastSection, "sectionHead", fmt.Sprintf("%064x", chtSectionHead), "root", fmt.Sprintf("%064x", chtRoot)) + chtRoot := light.GetChtRoot(pm.chainDb, chtLastSectionV1, chtSectionHead) + logger.Info("Loaded CHT", "section", chtLastSection, "head", chtSectionHead, "root", chtRoot) } - bloomTrieSectionCount, _, _ := srv.bloomTrieIndexer.Sections() if bloomTrieSectionCount != 0 { bloomTrieLastSection := bloomTrieSectionCount - 1 bloomTrieSectionHead := srv.bloomTrieIndexer.SectionHead(bloomTrieLastSection) bloomTrieRoot := light.GetBloomTrieRoot(pm.chainDb, bloomTrieLastSection, bloomTrieSectionHead) - logger.Info("BloomTrie", "section", bloomTrieLastSection, "sectionHead", fmt.Sprintf("%064x", bloomTrieSectionHead), "root", fmt.Sprintf("%064x", bloomTrieRoot)) + logger.Info("Loaded bloom trie", "section", bloomTrieLastSection, "head", bloomTrieSectionHead, "root", bloomTrieRoot) } 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.protocolManager.SubProtocols + return s.makeProtocols(ServerProtocolVersions) } // Start starts the LES server func (s *LesServer) Start(srvr *p2p.Server) { - s.protocolManager.Start() - for _, topic := range s.lesTopics { - topic := topic - go func() { - logger := log.New("topic", topic) - logger.Info("Starting topic registration") - defer logger.Info("Terminated topic registration") + 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) + } - srvr.DiscV5.RegisterTopic(topic, s.quitSync) - }() + 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 { + topic := topic + go func() { + logger := log.New("topic", topic) + logger.Info("Starting topic registration") + defer logger.Info("Terminated topic registration") + + srvr.DiscV5.RegisterTopic(topic, s.quitSync) + }() + } } s.privateKey = srvr.PrivateKey s.protocolManager.blockLoop() @@ -131,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) @@ -327,11 +262,11 @@ func (pm *ProtocolManager) blockLoop() { header := ev.Block.Header() hash := header.Hash() number := header.Number.Uint64() - td := core.GetTd(pm.chainDb, hash, number) + td := rawdb.ReadTd(pm.chainDb, hash, number) if td != nil && td.Cmp(lastBroadcastTd) > 0 { var reorg uint64 if lastHead != nil { - reorg = lastHead.Number.Uint64() - core.FindCommonAncestor(pm.chainDb, header, lastHead).Number.Uint64() + reorg = lastHead.Number.Uint64() - rawdb.FindCommonAncestor(pm.chainDb, header, lastHead).Number.Uint64() } lastHead = header lastBroadcastTd = td @@ -348,12 +283,7 @@ func (pm *ProtocolManager) blockLoop() { 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 @@ -361,11 +291,7 @@ func (pm *ProtocolManager) blockLoop() { signed = true } - select { - case p.announceChn <- signedAnnounce: - default: - pm.removePeer(p.id) - } + p.queueSend(func() { p.SendAnnounce(signedAnnounce) }) } } } diff --git a/les/serverpool.go b/les/serverpool.go index a84c29c3ac..668f39c562 100644 --- a/les/serverpool.go +++ b/les/serverpool.go @@ -14,10 +14,10 @@ // 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" "fmt" "io" "math" @@ -28,11 +28,12 @@ import ( "time" "github.com/ethereum/go-ethereum/common/mclock" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "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/p2p/enode" "github.com/ethereum/go-ethereum/rlp" ) @@ -73,7 +74,6 @@ const ( // and a short term value which is adjusted exponentially with a factor of // pstatRecentAdjust with each dial/connection and also returned exponentially // to the average with the time constant pstatReturnToMeanTC - pstatRecentAdjust = 0.1 pstatReturnToMeanTC = time.Hour // node address selection weight is dropped by a factor of exp(-addrFailDropLn) after // each unsuccessful connection (restored after a successful one) @@ -83,14 +83,31 @@ const ( responseScoreTC = time.Millisecond * 100 delayScoreTC = time.Second * 5 timeoutPow = 10 - // peerSelectMinWeight is added to calculated weights at request peer selection - // to give poorly performing peers a little chance of coming back - peerSelectMinWeight = 0.005 // initStatsWeight is used to initialize previously unknown peers with good // statistics to give a chance to prove themselves initStatsWeight = 1 ) +// connReq represents a request for peer connection. +type connReq struct { + p *peer + node *enode.Node + result chan *poolEntry +} + +// disconnReq represents a request for peer disconnection. +type disconnReq struct { + entry *poolEntry + stopped bool + done chan struct{} +} + +// registerReq represents a request for peer registration. +type registerReq struct { + entry *poolEntry + done chan struct{} +} + // serverPool implements a pool for storing and selecting newly discovered and already // known light server nodes. It received discovered nodes, stores statistics about // known nodes and takes care of always having enough good quality servers connected. @@ -105,11 +122,11 @@ type serverPool struct { topic discv5.Topic discSetPeriod chan time.Duration - discNodes chan *discv5.Node + discNodes chan *enode.Node discLookups chan bool - entries map[discover.NodeID]*poolEntry - lock sync.Mutex + trustedNodes map[enode.ID]*enode.Node + entries map[enode.ID]*poolEntry timeout, enableRetry chan *poolEntry adjustStats chan poolStatAdjust @@ -117,22 +134,30 @@ type serverPool struct { 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, wg: wg, - entries: make(map[discover.NodeID]*poolEntry), + entries: make(map[enode.ID]*poolEntry), timeout: make(chan *poolEntry, 1), adjustStats: make(chan poolStatAdjust, 100), enableRetry: make(chan *poolEntry, 1), + connCh: make(chan *connReq), + disconnCh: make(chan *disconnReq), + registerCh: make(chan *registerReq), knownSelect: newWeightedRandomSelect(), newSelect: newWeightedRandomSelect(), fastDiscover: true, + trustedNodes: parseTrustedNodes(trustedNodes), } + pool.knownQueue = newPoolEntryQueue(maxKnownEntries, pool.removeEntry) pool.newQueue = newPoolEntryQueue(maxNewEntries, pool.removeEntry) return pool @@ -144,16 +169,32 @@ 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) - pool.discNodes = make(chan *discv5.Node, 100) + pool.discNodes = make(chan *enode.Node, 100) pool.discLookups = make(chan bool, 100) - go pool.server.DiscV5.SearchTopic(pool.topic, pool.discSetPeriod, pool.discNodes, pool.discLookups) + go pool.discoverNodes() } - - go pool.eventLoop() pool.checkDial() + go pool.eventLoop() +} + +// discoverNodes wraps SearchTopic, converting result nodes to enode.Node. +func (pool *serverPool) discoverNodes() { + ch := make(chan *discv5.Node) + go func() { + pool.server.DiscV5.SearchTopic(pool.topic, pool.discSetPeriod, ch, pool.discLookups) + close(ch) + }() + for n := range ch { + pubkey, err := decodePubkey64(n.ID[:]) + if err != nil { + continue + } + pool.discNodes <- enode.NewV4(pubkey, n.IP, int(n.TCP), int(n.UDP)) + } } // connect should be called upon any incoming connection. If the connection has been @@ -161,84 +202,45 @@ func (pool *serverPool) start(server *p2p.Server, topic discv5.Topic) { // Otherwise, the connection should be rejected. // Note that whenever a connection has been accepted and a pool entry has been returned, // disconnect should also always be called. -func (pool *serverPool) connect(p *peer, ip net.IP, port uint16) *poolEntry { - pool.lock.Lock() - defer pool.lock.Unlock() - entry := pool.entries[p.ID()] - if entry == nil { - entry = pool.findOrNewNode(p.ID(), ip, port) - } - p.Log().Debug("Connecting to new peer", "state", entry.state) - if entry.state == psConnected || entry.state == psRegistered { +func (pool *serverPool) connect(p *peer, node *enode.Node) *poolEntry { + log.Debug("Connect new entry", "enode", p.id) + req := &connReq{p: p, node: node, result: make(chan *poolEntry, 1)} + select { + case pool.connCh <- req: + case <-pool.quit: return nil } - pool.connWg.Add(1) - entry.peer = p - entry.state = psConnected - addr := &poolEntryAddress{ - ip: ip, - port: port, - lastSeen: mclock.Now(), - } - entry.lastConnected = addr - entry.addr = make(map[string]*poolEntryAddress) - entry.addr[addr.strKey()] = addr - entry.addrSelect = *newWeightedRandomSelect() - entry.addrSelect.update(addr) - return entry + return <-req.result } // registered should be called after a successful handshake func (pool *serverPool) registered(entry *poolEntry) { - log.Debug("Registered new entry", "enode", entry.id) - pool.lock.Lock() - defer pool.lock.Unlock() - - entry.state = psRegistered - entry.regTime = mclock.Now() - if !entry.known { - pool.newQueue.remove(entry) - entry.known = true + log.Debug("Registered new entry", "enode", entry.node.ID()) + req := ®isterReq{entry: entry, done: make(chan struct{})} + select { + case pool.registerCh <- req: + case <-pool.quit: + return } - pool.knownQueue.setLatest(entry) - entry.shortRetry = shortRetryCnt + <-req.done } // disconnect should be called when ending a connection. Service quality statistics // can be updated optionally (not updated if no registration happened, in this case // only connection statistics are updated, just like in case of timeout) func (pool *serverPool) disconnect(entry *poolEntry) { - log.Debug("Disconnected old entry", "enode", entry.id) - pool.lock.Lock() - defer pool.lock.Unlock() - - if entry.state == psRegistered { - connTime := mclock.Now() - entry.regTime - connAdjust := float64(connTime) / float64(targetConnTime) - if connAdjust > 1 { - connAdjust = 1 - } - stopped := false - select { - case <-pool.quit: - stopped = true - default: - } - if stopped { - entry.connectStats.add(1, connAdjust) - } else { - entry.connectStats.add(connAdjust, 1) - } + stopped := false + select { + case <-pool.quit: + stopped = true + default: } + log.Debug("Disconnected old entry", "enode", entry.node.ID()) + req := &disconnReq{entry: entry, stopped: stopped, done: make(chan struct{})} - entry.state = psNotConnected - if entry.knownSelected { - pool.knownSelected-- - } else { - pool.newSelected-- - } - pool.setRetryDial(entry) - pool.connWg.Done() + // Block until disconnection request is served. + pool.disconnCh <- req + <-req.done } const ( @@ -281,25 +283,51 @@ func (pool *serverPool) eventLoop() { if pool.discSetPeriod != nil { pool.discSetPeriod <- time.Millisecond * 100 } + + // disconnect updates service quality statistics depending on the connection time + // and disconnection initiator. + disconnect := func(req *disconnReq, stopped bool) { + // Handle peer disconnection requests. + entry := req.entry + if entry.state == psRegistered { + connAdjust := float64(mclock.Now()-entry.regTime) / float64(targetConnTime) + if connAdjust > 1 { + connAdjust = 1 + } + if stopped { + // disconnect requested by ourselves. + entry.connectStats.add(1, connAdjust) + } else { + // disconnect requested by server side. + entry.connectStats.add(connAdjust, 1) + } + } + entry.state = psNotConnected + + if entry.knownSelected { + pool.knownSelected-- + } else { + pool.newSelected-- + } + pool.setRetryDial(entry) + pool.connWg.Done() + close(req.done) + } + for { select { case entry := <-pool.timeout: - pool.lock.Lock() if !entry.removed { pool.checkDialTimeout(entry) } - pool.lock.Unlock() case entry := <-pool.enableRetry: - pool.lock.Lock() if !entry.removed { entry.delayedRetry = false pool.updateCheckDial(entry) } - pool.lock.Unlock() case adj := <-pool.adjustStats: - pool.lock.Lock() switch adj.adjustType { case pseBlockDelay: adj.entry.delayStats.add(float64(adj.time), 1) @@ -309,13 +337,12 @@ func (pool *serverPool) eventLoop() { case pseResponseTimeout: adj.entry.timeoutStats.add(1, 1) } - pool.lock.Unlock() case node := <-pool.discNodes: - pool.lock.Lock() - entry := pool.findOrNewNode(discover.NodeID(node.ID), node.IP, node.TCP) - pool.updateCheckDial(entry) - pool.lock.Unlock() + if pool.trustedNodes[node.ID()] == nil { + entry := pool.findOrNewNode(node) + pool.updateCheckDial(entry) + } case conv := <-pool.discLookups: if conv { @@ -331,31 +358,87 @@ func (pool *serverPool) eventLoop() { } } + case req := <-pool.connCh: + if pool.trustedNodes[req.p.ID()] != nil { + // ignore trusted nodes + req.result <- nil + } 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 + } + + case req := <-pool.registerCh: + // Handle peer registration requests. + entry := req.entry + entry.state = psRegistered + entry.regTime = mclock.Now() + if !entry.known { + pool.newQueue.remove(entry) + entry.known = true + } + pool.knownQueue.setLatest(entry) + entry.shortRetry = shortRetryCnt + close(req.done) + + case req := <-pool.disconnCh: + // Handle peer disconnection requests. + disconnect(req, req.stopped) + case <-pool.quit: if pool.discSetPeriod != nil { close(pool.discSetPeriod) } - pool.connWg.Wait() + + // Spawn a goroutine to close the disconnCh after all connections are disconnected. + go func() { + pool.connWg.Wait() + close(pool.disconnCh) + }() + + // Handle all remaining disconnection requests before exit. + for req := range pool.disconnCh { + disconnect(req, true) + } pool.saveNodes() pool.wg.Done() return - } } } -func (pool *serverPool) findOrNewNode(id discover.NodeID, ip net.IP, port uint16) *poolEntry { +func (pool *serverPool) findOrNewNode(node *enode.Node) *poolEntry { now := mclock.Now() - entry := pool.entries[id] + entry := pool.entries[node.ID()] if entry == nil { - log.Debug("Discovered new entry", "id", id) + log.Debug("Discovered new entry", "id", node.ID()) entry = &poolEntry{ - id: id, + node: node, addr: make(map[string]*poolEntryAddress), addrSelect: *newWeightedRandomSelect(), shortRetry: shortRetryCnt, } - pool.entries[id] = entry + pool.entries[node.ID()] = entry // initialize previously unknown peers with good statistics to give a chance to prove themselves entry.connectStats.add(1, initStatsWeight) entry.delayStats.add(0, initStatsWeight) @@ -363,10 +446,7 @@ func (pool *serverPool) findOrNewNode(id discover.NodeID, ip net.IP, port uint16 entry.timeoutStats.add(0, initStatsWeight) } entry.lastDiscovered = now - addr := &poolEntryAddress{ - ip: ip, - port: port, - } + addr := &poolEntryAddress{ip: node.IP(), port: uint16(node.TCP())} if a, ok := entry.addr[addr.strKey()]; ok { addr = a } else { @@ -393,17 +473,48 @@ func (pool *serverPool) loadNodes() { return } for _, e := range list { - log.Debug("Loaded server stats", "id", e.id, "fails", e.lastConnected.fails, + log.Debug("Loaded server stats", "id", e.node.ID(), "fails", e.lastConnected.fails, "conn", fmt.Sprintf("%v/%v", e.connectStats.avg, e.connectStats.weight), "delay", fmt.Sprintf("%v/%v", time.Duration(e.delayStats.avg), e.delayStats.weight), "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.id] = e - pool.knownQueue.setLatest(e) - pool.knownSelect.update((*knownEntry)(e)) + pool.entries[e.node.ID()] = 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() { @@ -424,7 +535,7 @@ func (pool *serverPool) removeEntry(entry *poolEntry) { pool.newSelect.remove((*discoveredEntry)(entry)) pool.knownSelect.remove((*knownEntry)(entry)) entry.removed = true - delete(pool.entries, entry.id) + delete(pool.entries, entry.node.ID()) } // setRetryDial starts the timer which will enable dialing a certain node again @@ -502,10 +613,10 @@ func (pool *serverPool) dial(entry *poolEntry, knownSelected bool) { pool.newSelected++ } addr := entry.addrSelect.choose().(*poolEntryAddress) - log.Debug("Dialing new peer", "lesaddr", entry.id.String()+"@"+addr.strKey(), "set", len(entry.addr), "known", knownSelected) + log.Debug("Dialing new peer", "lesaddr", entry.node.ID().String()+"@"+addr.strKey(), "set", len(entry.addr), "known", knownSelected) entry.dialed = addr go func() { - pool.server.AddPeer(discover.NewNode(entry.id, addr.ip, addr.port, addr.port)) + pool.server.AddPeer(entry.node) select { case <-pool.quit: case <-time.After(dialTimeout): @@ -523,7 +634,7 @@ func (pool *serverPool) checkDialTimeout(entry *poolEntry) { if entry.state != psDialed { return } - log.Debug("Dial timeout", "lesaddr", entry.id.String()+"@"+entry.dialed.strKey()) + log.Debug("Dial timeout", "lesaddr", entry.node.ID().String()+"@"+entry.dialed.strKey()) entry.state = psNotConnected if entry.knownSelected { pool.knownSelected-- @@ -545,8 +656,9 @@ const ( // poolEntry represents a server node and stores its current state and statistics. type poolEntry struct { peer *peer - id discover.NodeID + pubkey [64]byte // secp256k1 key of the node addr map[string]*poolEntryAddress + node *enode.Node lastConnected, dialed *poolEntryAddress addrSelect weightedRandomSelect @@ -563,23 +675,39 @@ type poolEntry struct { shortRetry int } +// poolEntryEnc is the RLP encoding of poolEntry. +type poolEntryEnc struct { + Pubkey []byte + IP net.IP + Port uint16 + Fails uint + CStat, DStat, RStat, TStat poolStats +} + func (e *poolEntry) EncodeRLP(w io.Writer) error { - return rlp.Encode(w, []interface{}{e.id, e.lastConnected.ip, e.lastConnected.port, e.lastConnected.fails, &e.connectStats, &e.delayStats, &e.responseStats, &e.timeoutStats}) + return rlp.Encode(w, &poolEntryEnc{ + Pubkey: encodePubkey64(e.node.Pubkey()), + IP: e.lastConnected.ip, + Port: e.lastConnected.port, + Fails: e.lastConnected.fails, + CStat: e.connectStats, + DStat: e.delayStats, + RStat: e.responseStats, + TStat: e.timeoutStats, + }) } func (e *poolEntry) DecodeRLP(s *rlp.Stream) error { - var entry struct { - ID discover.NodeID - IP net.IP - Port uint16 - Fails uint - CStat, DStat, RStat, TStat poolStats - } + var entry poolEntryEnc if err := s.Decode(&entry); err != nil { return err } + pubkey, err := decodePubkey64(entry.Pubkey) + if err != nil { + return err + } addr := &poolEntryAddress{ip: entry.IP, port: entry.Port, fails: entry.Fails, lastSeen: mclock.Now()} - e.id = entry.ID + e.node = enode.NewV4(pubkey, entry.IP, int(entry.Port), int(entry.Port)) e.addr = make(map[string]*poolEntryAddress) e.addr[addr.strKey()] = addr e.addrSelect = *newWeightedRandomSelect() @@ -594,6 +722,14 @@ func (e *poolEntry) DecodeRLP(s *rlp.Stream) error { return nil } +func encodePubkey64(pub *ecdsa.PublicKey) []byte { + return crypto.FromECDSAPub(pub)[1:] +} + +func decodePubkey64(b []byte) (*ecdsa.PublicKey, error) { + return crypto.UnmarshalPubkey(append([]byte{0x04}, b...)) +} + // discoveredEntry implements wrsItem type discoveredEntry poolEntry @@ -605,9 +741,8 @@ func (e *discoveredEntry) Weight() int64 { t := time.Duration(mclock.Now() - e.lastDiscovered) if t <= discoverExpireStart { return 1000000000 - } else { - return int64(1000000000 * math.Exp(-float64(t-discoverExpireStart)/float64(discoverExpireConst))) } + return int64(1000000000 * math.Exp(-float64(t-discoverExpireStart)/float64(discoverExpireConst))) } // knownEntry implements wrsItem diff --git a/les/servingqueue.go b/les/servingqueue.go new file mode 100644 index 0000000000..2438fdfe3c --- /dev/null +++ b/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/les/sync.go b/les/sync.go index c0e17f97d9..1ac6455852 100644 --- a/les/sync.go +++ b/les/sync.go @@ -20,16 +20,11 @@ import ( "context" "time" - "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/light" ) -const ( - //forceSyncCycle = 10 * time.Second // Time interval to force syncs, even if few peers are available - minDesiredPeerCount = 5 // Amount of peers desired to start syncing -) - // syncer is responsible for periodically synchronising with the network, both // downloading hashes and blocks as well as handling the announcement handler. func (pm *ProtocolManager) syncer() { @@ -61,7 +56,7 @@ func (pm *ProtocolManager) syncer() { func (pm *ProtocolManager) needToSync(peerHead blockInfo) bool { head := pm.blockchain.CurrentHeader() - currentTd := core.GetTd(pm.chainDb, head.Hash(), head.Number.Uint64()) + currentTd := rawdb.ReadTd(pm.chainDb, head.Hash(), head.Number.Uint64()) return currentTd != nil && peerHead.Td.Cmp(currentTd) > 0 } diff --git a/les/txrelay.go b/les/txrelay.go index 7a02cc837e..a790bbec9c 100644 --- a/les/txrelay.go +++ b/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/les/ulc.go b/les/ulc.go new file mode 100644 index 0000000000..d9f7dc76c9 --- /dev/null +++ b/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/les/ulc_test.go b/les/ulc_test.go new file mode 100644 index 0000000000..69ea62059d --- /dev/null +++ b/les/ulc_test.go @@ -0,0 +1,240 @@ +package les + +import ( + "fmt" + "reflect" + "testing" + "time" + + "net" + + "crypto/ecdsa" + "math/big" + + "github.com/ethereum/go-ethereum/common/mclock" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/ethdb" + "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 := ethdb.NewMemDatabase() + + 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 := ethdb.NewMemDatabase() + + 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/light/lightchain.go b/light/lightchain.go index f479575120..fb5f8ead25 100644 --- a/light/lightchain.go +++ b/light/lightchain.go @@ -14,10 +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 light implements on-demand retrieval capable state and chain objects +// for the Ethereum Light Client. package light import ( "context" + "errors" "math/big" "sync" "sync/atomic" @@ -26,13 +29,15 @@ import ( "github.com/ethereum/go-ethereum/common" "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/ethdb" "github.com/ethereum/go-ethereum/event" "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 ( @@ -45,7 +50,9 @@ var ( // interface. It only does header validation during chain insertion. type LightChain struct { hc *core.HeaderChain + indexerConfig *IndexerConfig chainDb ethdb.Database + engine consensus.Engine odr OdrBackend chainFeed event.Feed chainSideFeed event.Feed @@ -53,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 @@ -78,13 +83,14 @@ func NewLightChain(odr OdrBackend, config *params.ChainConfig, engine consensus. blockCache, _ := lru.New(blockCacheLimit) bc := &LightChain{ - chainDb: odr.Database(), - odr: odr, - quit: make(chan struct{}), - bodyCache: bodyCache, - bodyRLPCache: bodyRLPCache, - blockCache: blockCache, - engine: engine, + chainDb: odr.Database(), + indexerConfig: odr.IndexerConfig(), + odr: odr, + quit: make(chan struct{}), + bodyCache: bodyCache, + bodyRLPCache: bodyRLPCache, + blockCache: blockCache, + engine: engine, } var err error bc.hc, err = core.NewHeaderChain(odr.Database(), config, bc.engine, bc.getProcInterrupt) @@ -98,7 +104,6 @@ func NewLightChain(odr OdrBackend, config *params.ChainConfig, engine consensus. if cp, ok := trustedCheckpoints[bc.genesisBlock.Hash()]; ok { bc.addTrustedCheckpoint(cp) } - if err := bc.loadLastState(); err != nil { return nil, err } @@ -114,216 +119,227 @@ func NewLightChain(odr OdrBackend, config *params.ChainConfig, engine consensus. } // addTrustedCheckpoint adds a trusted checkpoint to the blockchain -func (self *LightChain) addTrustedCheckpoint(cp trustedCheckpoint) { - if self.odr.ChtIndexer() != nil { - StoreChtRoot(self.chainDb, cp.sectionIdx, cp.sectionHead, cp.chtRoot) - self.odr.ChtIndexer().AddKnownSectionHead(cp.sectionIdx, 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.sectionIdx, cp.sectionHead, cp.bloomTrieRoot) - self.odr.BloomTrieIndexer().AddKnownSectionHead(cp.sectionIdx, 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().AddKnownSectionHead(cp.sectionIdx, cp.sectionHead) + if lc.odr.BloomIndexer() != nil { + lc.odr.BloomIndexer().AddCheckpoint(cp.SectionIndex, cp.SectionHead) } - log.Info("Added trusted checkpoint", "chain name", cp.name) + 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 := core.GetHeadHeaderHash(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()) - log.Info("Loaded most recent local header", "number", header.Number, "hash", header.Hash(), "td", headerTd) + 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 } // 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 { - self.mu.RLock() - defer self.mu.RUnlock() - - 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 - if err := core.WriteTd(bc.chainDb, genesis.Hash(), genesis.NumberU64(), genesis.Difficulty()); err != nil { - log.Crit("Failed to write genesis block TD", "err", err) - } - if err := core.WriteBlock(bc.chainDb, genesis); err != nil { - log.Crit("Failed to write genesis block", "err", err) - } - bc.genesisBlock = genesis - bc.hc.SetGenesis(bc.genesisBlock.Header()) - bc.hc.SetCurrentHeader(bc.genesisBlock.Header()) + rawdb.WriteTd(lc.chainDb, genesis.Hash(), genesis.NumberU64(), genesis.Difficulty()) + rawdb.WriteBlock(lc.chainDb, genesis) + + 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 (lc *LightChain) State() (*state.StateDB, error) { + return nil, errors.New("not implemented, needs client/server interface split") } // 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 } - body, err := GetBody(ctx, self.odr, hash, self.hc.GetBlockNumber(hash)) + number := lc.hc.GetBlockNumber(hash) + if number == nil { + return nil, errors.New("unknown block") + } + 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 } - body, err := GetBodyRLP(ctx, self.odr, hash, self.hc.GetBlockNumber(hash)) + number := lc.hc.GetBlockNumber(hash) + if number == nil { + return nil, errors.New("unknown block") + } + 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) { - return self.GetBlock(ctx, hash, 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 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) } } } @@ -339,28 +355,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: @@ -373,129 +386,158 @@ 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 { - self.mu.RLock() - defer self.mu.RUnlock() - - 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 +// a close ancestor of it is canonical. maxNonCanonical points to a downwards counter limiting the +// 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 (lc *LightChain) GetAncestor(hash common.Hash, number, ancestor uint64, maxNonCanonical *uint64) (common.Hash, uint64) { + lc.chainmu.RLock() + defer lc.chainmu.RUnlock() + + 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 { - if self.odr.ChtIndexer() == nil { +func (lc *LightChain) SyncCht(ctx context.Context) bool { + // If we don't have a CHT indexer, abort + if lc.odr.ChtIndexer() == nil { return false } - headNum := self.CurrentHeader().Number.Uint64() - chtCount, _, _ := self.odr.ChtIndexer().Sections() - if headNum+1 < chtCount*ChtFrequency { - num := chtCount*ChtFrequency - 1 - header, err := GetHeaderByNumber(ctx, self.odr, num) - if header != nil && err == nil { - self.mu.Lock() - if self.hc.CurrentHeader().Number.Uint64() < header.Number.Uint64() { - self.hc.SetCurrentHeader(header) - } - self.mu.Unlock() - return true + // Ensure the remote CHT head is ahead of us + head := lc.CurrentHeader().Number.Uint64() + sections, _, _ := lc.odr.ChtIndexer().Sections() + + 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, 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 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))) + lc.hc.SetCurrentHeader(header) } + return true } return false } // 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/light/lightchain_test.go b/light/lightchain_test.go index 0af7551d41..374cb53198 100644 --- a/light/lightchain_test.go +++ b/light/lightchain_test.go @@ -24,6 +24,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/ethdb" "github.com/ethereum/go-ethereum/params" @@ -51,10 +52,10 @@ 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 := ethdb.NewMemDatabase() gspec := core.Genesis{Config: params.TestChainConfig} genesis := gspec.MustCommit(db) - blockchain, _ := NewLightChain(&dummyOdr{db: db}, gspec.Config, ethash.NewFaker()) + blockchain, _ := NewLightChain(&dummyOdr{db: db, indexerConfig: TestClientIndexerConfig}, gspec.Config, ethash.NewFaker()) // Create and inject the requested chain if n == 0 { @@ -68,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 := ethdb.NewMemDatabase() gspec := &core.Genesis{ Difficulty: big.NewInt(1), Config: params.TestChainConfig, @@ -121,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() - core.WriteTd(lightchain.chainDb, header.Hash(), header.Number.Uint64(), new(big.Int).Add(header.Difficulty, lightchain.GetTdByHash(header.ParentHash))) - core.WriteHeader(lightchain.chainDb, header) - lightchain.mu.Unlock() + 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.chainmu.Unlock() } return nil } @@ -264,7 +265,8 @@ func makeHeaderChainWithDiff(genesis *types.Block, d []int, seed byte) []*types. type dummyOdr struct { OdrBackend - db ethdb.Database + db ethdb.Database + indexerConfig *IndexerConfig } func (odr *dummyOdr) Database() ethdb.Database { @@ -275,6 +277,10 @@ func (odr *dummyOdr) Retrieve(ctx context.Context, req OdrRequest) error { return nil } +func (odr *dummyOdr) IndexerConfig() *IndexerConfig { + return odr.indexerConfig +} + // Tests that reorganizing a long difficult chain after a short easy one // overwrites the canonical numbers and links in the database. func TestReorgLongHeaders(t *testing.T) { @@ -325,7 +331,7 @@ func TestBadHeaderHashes(t *testing.T) { func TestReorgBadHeaderHashes(t *testing.T) { bc := newTestLightChain() - // Create a chain, import and ban aferwards + // Create a chain, import and ban afterwards headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 3, 4}, 10) if _, err := bc.InsertHeaderChain(headers, 1); err != nil { diff --git a/light/nodeset.go b/light/nodeset.go index c530a4fbe2..6f25219c13 100644 --- a/light/nodeset.go +++ b/light/nodeset.go @@ -1,4 +1,4 @@ -// Copyright 2014 The go-ethereum Authors +// Copyright 2017 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 @@ -22,14 +22,16 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/rlp" - "github.com/ethereum/go-ethereum/trie" ) // NodeSet stores a set of trie nodes. It implements trie.Database and can also // act as a cache for another trie.Database. type NodeSet struct { - db map[string][]byte + nodes map[string][]byte + order []string + dataSize int lock sync.RWMutex } @@ -37,7 +39,7 @@ type NodeSet struct { // NewNodeSet creates an empty node set func NewNodeSet() *NodeSet { return &NodeSet{ - db: make(map[string][]byte), + nodes: make(map[string][]byte), } } @@ -46,10 +48,15 @@ func (db *NodeSet) Put(key []byte, value []byte) error { db.lock.Lock() defer db.lock.Unlock() - if _, ok := db.db[string(key)]; !ok { - db.db[string(key)] = common.CopyBytes(value) - db.dataSize += len(value) + if _, ok := db.nodes[string(key)]; ok { + return nil } + keystr := string(key) + + db.nodes[keystr] = common.CopyBytes(value) + db.order = append(db.order, keystr) + db.dataSize += len(value) + return nil } @@ -58,7 +65,7 @@ func (db *NodeSet) Get(key []byte) ([]byte, error) { db.lock.RLock() defer db.lock.RUnlock() - if entry, ok := db.db[string(key)]; ok { + if entry, ok := db.nodes[string(key)]; ok { return entry, nil } return nil, errors.New("not found") @@ -75,7 +82,7 @@ func (db *NodeSet) KeyCount() int { db.lock.RLock() defer db.lock.RUnlock() - return len(db.db) + return len(db.nodes) } // DataSize returns the aggregated data size of nodes in the set @@ -92,27 +99,27 @@ func (db *NodeSet) NodeList() NodeList { defer db.lock.RUnlock() var values NodeList - for _, value := range db.db { - values = append(values, value) + for _, key := range db.order { + values = append(values, db.nodes[key]) } return values } // Store writes the contents of the set to the given database -func (db *NodeSet) Store(target trie.Database) { +func (db *NodeSet) Store(target ethdb.Putter) { db.lock.RLock() defer db.lock.RUnlock() - for key, value := range db.db { + for key, value := range db.nodes { target.Put([]byte(key), value) } } -// NodeList stores an ordered list of trie nodes. It implements trie.DatabaseWriter. +// NodeList stores an ordered list of trie nodes. It implements ethdb.Putter. type NodeList []rlp.RawValue // Store writes the contents of the list to the given database -func (n NodeList) Store(db trie.Database) { +func (n NodeList) Store(db ethdb.Putter) { for _, node := range n { db.Put(crypto.Keccak256(node), node) } diff --git a/light/odr.go b/light/odr.go index e2c3d9c5a4..95f1948e75 100644 --- a/light/odr.go +++ b/light/odr.go @@ -14,16 +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 light implements on-demand retrieval capable state and chain objects -// for the Ethereum Light Client. package light import ( "context" + "errors" "math/big" "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/ethdb" ) @@ -32,6 +32,9 @@ import ( // service is not required. var NoOdr = context.Background() +// ErrNoPeers is returned if no peers capable of serving a queued request are available +var ErrNoPeers = errors.New("no suitable peers available") + // OdrBackend is an interface to a backend service that handles ODR retrievals type type OdrBackend interface { Database() ethdb.Database @@ -39,6 +42,7 @@ type OdrBackend interface { BloomTrieIndexer() *core.ChainIndexer BloomIndexer() *core.ChainIndexer Retrieve(ctx context.Context, req OdrRequest) error + IndexerConfig() *IndexerConfig } // OdrRequest is an interface for retrieval requests @@ -112,7 +116,7 @@ type BlockRequest struct { // StoreResult stores the retrieved data in local database func (req *BlockRequest) StoreResult(db ethdb.Database) { - core.WriteBodyRLP(db, req.Hash, req.Number, req.Rlp) + rawdb.WriteBodyRLP(db, req.Hash, req.Number, req.Rlp) } // ReceiptsRequest is the ODR request type for retrieving block bodies @@ -125,12 +129,13 @@ type ReceiptsRequest struct { // StoreResult stores the retrieved data in local database func (req *ReceiptsRequest) StoreResult(db ethdb.Database) { - core.WriteBlockReceipts(db, req.Hash, req.Number, req.Receipts) + rawdb.WriteReceipts(db, req.Hash, req.Number, req.Receipts) } // ChtRequest is the ODR request type for state/storage trie entries type ChtRequest struct { OdrRequest + Config *IndexerConfig ChtNum, BlockNum uint64 ChtRoot common.Hash Header *types.Header @@ -140,32 +145,33 @@ type ChtRequest struct { // StoreResult stores the retrieved data in local database func (req *ChtRequest) StoreResult(db ethdb.Database) { - // if there is a canonical hash, there is a header too - core.WriteHeader(db, req.Header) hash, num := req.Header.Hash(), req.Header.Number.Uint64() - core.WriteTd(db, hash, num, req.Td) - core.WriteCanonicalHash(db, hash, num) + + rawdb.WriteHeader(db, req.Header) + rawdb.WriteTd(db, hash, num, req.Td) + rawdb.WriteCanonicalHash(db, hash, num) } // BloomRequest is the ODR request type for retrieving bloom filters from a CHT structure type BloomRequest struct { OdrRequest - BloomTrieNum uint64 - BitIdx uint - SectionIdxList []uint64 - BloomTrieRoot common.Hash - BloomBits [][]byte - Proofs *NodeSet + Config *IndexerConfig + BloomTrieNum uint64 + BitIdx uint + SectionIndexList []uint64 + BloomTrieRoot common.Hash + BloomBits [][]byte + Proofs *NodeSet } // StoreResult stores the retrieved data in local database func (req *BloomRequest) StoreResult(db ethdb.Database) { - for i, sectionIdx := range req.SectionIdxList { - sectionHead := core.GetCanonicalHash(db, (sectionIdx+1)*BloomTrieFrequency-1) + for i, sectionIdx := range req.SectionIndexList { + sectionHead := rawdb.ReadCanonicalHash(db, (sectionIdx+1)*req.Config.BloomTrieSize-1) // if we don't have the canonical hash stored for this section head number, we'll still store it under // a key with a zero sectionHead. GetBloomBits will look there too if we still don't have the canonical // hash. In the unlikely case we've retrieved the section head hash since then, we'll just retrieve the // bit vector again from the network. - core.WriteBloomBits(db, req.BitIdx, sectionIdx, sectionHead, req.BloomBits[i]) + rawdb.WriteBloomBits(db, req.BitIdx, sectionIdx, sectionHead, req.BloomBits[i]) } } diff --git a/light/odr_test.go b/light/odr_test.go index e3d07518a8..3da7b3055e 100644 --- a/light/odr_test.go +++ b/light/odr_test.go @@ -28,6 +28,7 @@ import ( "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/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" @@ -54,8 +55,9 @@ var ( type testOdr struct { OdrBackend - sdb, ldb ethdb.Database - disable bool + indexerConfig *IndexerConfig + sdb, ldb ethdb.Database + disable bool } func (odr *testOdr) Database() ethdb.Database { @@ -70,11 +72,17 @@ func (odr *testOdr) Retrieve(ctx context.Context, req OdrRequest) error { } switch req := req.(type) { case *BlockRequest: - req.Rlp = core.GetBodyRLP(odr.sdb, req.Hash, core.GetBlockNumber(odr.sdb, req.Hash)) + number := rawdb.ReadHeaderNumber(odr.sdb, req.Hash) + if number != nil { + req.Rlp = rawdb.ReadBodyRLP(odr.sdb, req.Hash, *number) + } case *ReceiptsRequest: - req.Receipts = core.GetBlockReceipts(odr.sdb, req.Hash, core.GetBlockNumber(odr.sdb, req.Hash)) + number := rawdb.ReadHeaderNumber(odr.sdb, req.Hash) + if number != nil { + req.Receipts = rawdb.ReadReceipts(odr.sdb, req.Hash, *number) + } case *TrieRequest: - t, _ := trie.New(req.Id.Root, odr.sdb) + t, _ := trie.New(req.Id.Root, trie.NewDatabase(odr.sdb)) nodes := NewNodeSet() t.Prove(req.Key, 0, nodes) req.Proof = nodes @@ -85,6 +93,10 @@ func (odr *testOdr) Retrieve(ctx context.Context, req OdrRequest) error { return nil } +func (odr *testOdr) IndexerConfig() *IndexerConfig { + return odr.indexerConfig +} + type odrTestFn func(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) func TestOdrGetBlockLes1(t *testing.T) { testChainOdr(t, 1, odrGetBlock) } @@ -108,9 +120,15 @@ func TestOdrGetReceiptsLes1(t *testing.T) { testChainOdr(t, 1, odrGetReceipts) } func odrGetReceipts(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) { var receipts types.Receipts if bc != nil { - receipts = core.GetBlockReceipts(db, bhash, core.GetBlockNumber(db, bhash)) + number := rawdb.ReadHeaderNumber(db, bhash) + if number != nil { + receipts = rawdb.ReadReceipts(db, bhash, *number) + } } else { - receipts, _ = GetBlockReceipts(ctx, lc.Odr(), bhash, core.GetBlockNumber(db, bhash)) + number := rawdb.ReadHeaderNumber(db, bhash) + if number != nil { + receipts, _ = GetBlockReceipts(ctx, lc.Odr(), bhash, *number) + } } if receipts == nil { return nil, nil @@ -232,20 +250,20 @@ func testChainGen(i int, block *core.BlockGen) { func testChainOdr(t *testing.T, protocol int, fn odrTestFn) { var ( - sdb, _ = ethdb.NewMemDatabase() - ldb, _ = ethdb.NewMemDatabase() + sdb = ethdb.NewMemDatabase() + ldb = ethdb.NewMemDatabase() gspec = core.Genesis{Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}} genesis = gspec.MustCommit(sdb) ) gspec.MustCommit(ldb) // Assemble the test environment - blockchain, _ := core.NewBlockChain(sdb, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}) + blockchain, _ := core.NewBlockChain(sdb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil) gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), sdb, 4, testChainGen) if _, err := blockchain.InsertChain(gchain); err != nil { t.Fatal(err) } - odr := &testOdr{sdb: sdb, ldb: ldb} + odr := &testOdr{sdb: sdb, ldb: ldb, indexerConfig: TestClientIndexerConfig} lightchain, err := NewLightChain(odr, params.TestChainConfig, ethash.NewFullFaker()) if err != nil { t.Fatal(err) @@ -260,7 +278,7 @@ func testChainOdr(t *testing.T, protocol int, fn odrTestFn) { test := func(expFail int) { for i := uint64(0); i <= blockchain.CurrentHeader().Number.Uint64(); i++ { - bhash := core.GetCanonicalHash(sdb, i) + bhash := rawdb.ReadCanonicalHash(sdb, i) b1, err := fn(NoOdr, sdb, blockchain, nil, bhash) if err != nil { t.Fatalf("error in full-node test for block %d: %v", i, err) diff --git a/light/odr_util.go b/light/odr_util.go index a0eb6303d4..00103a76bd 100644 --- a/light/odr_util.go +++ b/light/odr_util.go @@ -22,19 +22,20 @@ 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/crypto" "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() - hash := core.GetCanonicalHash(db, number) + hash := rawdb.ReadCanonicalHash(db, number) if (hash != common.Hash{}) { // if there is a canonical hash, there is a header too - header := core.GetHeader(db, hash, number) + header := rawdb.ReadHeader(db, hash, number) if header == nil { panic("Canonical hash present but header not found") } @@ -47,32 +48,29 @@ func GetHeaderByNumber(ctx context.Context, odr OdrBackend, number uint64) (*typ ) if odr.ChtIndexer() != nil { chtCount, sectionHeadNum, sectionHead = odr.ChtIndexer().Sections() - canonicalHash := core.GetCanonicalHash(db, sectionHeadNum) + canonicalHash := rawdb.ReadCanonicalHash(db, sectionHeadNum) // if the CHT was injected as a trusted checkpoint, we have no canonical hash yet so we accept zero hash too for chtCount > 0 && canonicalHash != sectionHead && canonicalHash != (common.Hash{}) { chtCount-- if chtCount > 0 { - sectionHeadNum = chtCount*ChtFrequency - 1 + sectionHeadNum = chtCount*odr.IndexerConfig().ChtSize - 1 sectionHead = odr.ChtIndexer().SectionHead(chtCount - 1) - canonicalHash = core.GetCanonicalHash(db, sectionHeadNum) + canonicalHash = rawdb.ReadCanonicalHash(db, sectionHeadNum) } } } - - if number >= chtCount*ChtFrequency { + if number >= chtCount*odr.IndexerConfig().ChtSize { return nil, ErrNoTrustedCht } - - r := &ChtRequest{ChtRoot: GetChtRoot(db, chtCount-1, sectionHead), ChtNum: chtCount - 1, BlockNum: number} + r := &ChtRequest{ChtRoot: GetChtRoot(db, chtCount-1, sectionHead), ChtNum: chtCount - 1, BlockNum: number, Config: odr.IndexerConfig()} if err := odr.Retrieve(ctx, r); err != nil { return nil, err - } else { - return r.Header, nil } + return r.Header, nil } func GetCanonicalHash(ctx context.Context, odr OdrBackend, number uint64) (common.Hash, error) { - hash := core.GetCanonicalHash(odr.Database(), number) + hash := rawdb.ReadCanonicalHash(odr.Database(), number) if (hash != common.Hash{}) { return hash, nil } @@ -85,7 +83,7 @@ func GetCanonicalHash(ctx context.Context, odr OdrBackend, number uint64) (commo // GetBodyRLP retrieves the block body (transactions and uncles) in RLP encoding. func GetBodyRLP(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (rlp.RawValue, error) { - if data := core.GetBodyRLP(odr.Database(), hash, number); data != nil { + if data := rawdb.ReadBodyRLP(odr.Database(), hash, number); data != nil { return data, nil } r := &BlockRequest{Hash: hash, Number: number} @@ -114,7 +112,7 @@ func GetBody(ctx context.Context, odr OdrBackend, hash common.Hash, number uint6 // back from the stored header and body. func GetBlock(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (*types.Block, error) { // Retrieve the block header and body contents - header := core.GetHeader(odr.Database(), hash, number) + header := rawdb.ReadHeader(odr.Database(), hash, number) if header == nil { return nil, ErrNoHeader } @@ -129,22 +127,57 @@ func GetBlock(ctx context.Context, odr OdrBackend, hash common.Hash, number uint // GetBlockReceipts retrieves the receipts generated by the transactions included // in a block given by its hash. func GetBlockReceipts(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (types.Receipts, error) { - receipts := core.GetBlockReceipts(odr.Database(), hash, number) - if receipts != nil { - return receipts, nil + // Retrieve the potentially incomplete receipts from disk or network + receipts := rawdb.ReadReceipts(odr.Database(), hash, number) + if receipts == nil { + r := &ReceiptsRequest{Hash: hash, Number: number} + if err := odr.Retrieve(ctx, r); err != nil { + return nil, err + } + receipts = r.Receipts } - r := &ReceiptsRequest{Hash: hash, Number: number} - if err := odr.Retrieve(ctx, r); err != nil { - return nil, err + // If the receipts are incomplete, fill the derived fields + if len(receipts) > 0 && receipts[0].TxHash == (common.Hash{}) { + block, err := GetBlock(ctx, odr, hash, number) + if err != nil { + return nil, err + } + genesis := rawdb.ReadCanonicalHash(odr.Database(), 0) + config := rawdb.ReadChainConfig(odr.Database(), genesis) + + if err := core.SetReceiptsData(config, block, receipts); err != nil { + return nil, err + } + rawdb.WriteReceipts(odr.Database(), hash, number, receipts) } - return r.Receipts, nil + return receipts, nil +} + +// GetBlockLogs retrieves the logs generated by the transactions included in a +// block given by its hash. +func GetBlockLogs(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) ([][]*types.Log, error) { + // Retrieve the potentially incomplete receipts from disk or network + receipts := rawdb.ReadReceipts(odr.Database(), hash, number) + if receipts == nil { + r := &ReceiptsRequest{Hash: hash, Number: number} + if err := odr.Retrieve(ctx, r); err != nil { + return nil, err + } + receipts = r.Receipts + } + // Return the logs without deriving any computed fields on the receipts + logs := make([][]*types.Log, len(receipts)) + for i, receipt := range receipts { + logs[i] = receipt.Logs + } + return logs, nil } // GetBloomBits retrieves a batch of compressed bloomBits vectors belonging to the given bit index and section indexes func GetBloomBits(ctx context.Context, odr OdrBackend, bitIdx uint, sectionIdxList []uint64) ([][]byte, error) { - db := odr.Database() - result := make([][]byte, len(sectionIdxList)) var ( + db = odr.Database() + result = make([][]byte, len(sectionIdxList)) reqList []uint64 reqIdx []int ) @@ -155,27 +188,28 @@ func GetBloomBits(ctx context.Context, odr OdrBackend, bitIdx uint, sectionIdxLi ) if odr.BloomTrieIndexer() != nil { bloomTrieCount, sectionHeadNum, sectionHead = odr.BloomTrieIndexer().Sections() - canonicalHash := core.GetCanonicalHash(db, sectionHeadNum) + canonicalHash := rawdb.ReadCanonicalHash(db, sectionHeadNum) // if the BloomTrie was injected as a trusted checkpoint, we have no canonical hash yet so we accept zero hash too for bloomTrieCount > 0 && canonicalHash != sectionHead && canonicalHash != (common.Hash{}) { bloomTrieCount-- if bloomTrieCount > 0 { - sectionHeadNum = bloomTrieCount*BloomTrieFrequency - 1 + sectionHeadNum = bloomTrieCount*odr.IndexerConfig().BloomTrieSize - 1 sectionHead = odr.BloomTrieIndexer().SectionHead(bloomTrieCount - 1) - canonicalHash = core.GetCanonicalHash(db, sectionHeadNum) + canonicalHash = rawdb.ReadCanonicalHash(db, sectionHeadNum) } } } for i, sectionIdx := range sectionIdxList { - sectionHead := core.GetCanonicalHash(db, (sectionIdx+1)*BloomTrieFrequency-1) + sectionHead := rawdb.ReadCanonicalHash(db, (sectionIdx+1)*odr.IndexerConfig().BloomSize-1) // if we don't have the canonical hash stored for this section head number, we'll still look for // an entry with a zero sectionHead (we store it with zero section head too if we don't know it // at the time of the retrieval) - bloomBits, err := core.GetBloomBits(db, bitIdx, sectionIdx, sectionHead) + bloomBits, err := rawdb.ReadBloomBits(db, bitIdx, sectionIdx, sectionHead) if err == nil { result[i] = bloomBits } else { + // TODO(rjl493456442) Convert sectionIndex to BloomTrie relative index if sectionIdx >= bloomTrieCount { return nil, ErrNoTrustedBloomTrie } @@ -187,7 +221,8 @@ func GetBloomBits(ctx context.Context, odr OdrBackend, bitIdx uint, sectionIdxLi return result, nil } - r := &BloomRequest{BloomTrieRoot: GetBloomTrieRoot(db, bloomTrieCount-1, sectionHead), BloomTrieNum: bloomTrieCount - 1, BitIdx: bitIdx, SectionIdxList: reqList} + r := &BloomRequest{BloomTrieRoot: GetBloomTrieRoot(db, bloomTrieCount-1, sectionHead), BloomTrieNum: bloomTrieCount - 1, + BitIdx: bitIdx, SectionIndexList: reqList, Config: odr.IndexerConfig()} if err := odr.Retrieve(ctx, r); err != nil { return nil, err } else { diff --git a/light/postprocess.go b/light/postprocess.go index 32dbc102be..dd1b74a7be 100644 --- a/light/postprocess.go +++ b/light/postprocess.go @@ -1,4 +1,4 @@ -// Copyright 2016 The go-ethereum Authors +// Copyright 2017 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,6 +17,7 @@ package light import ( + "context" "encoding/binary" "errors" "fmt" @@ -26,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/bitutil" "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/ethdb" "github.com/ethereum/go-ethereum/log" @@ -34,50 +36,85 @@ import ( "github.com/ethereum/go-ethereum/trie" ) -const ( - ChtFrequency = 32768 - ChtV1Frequency = 4096 // as long as we want to retain LES/1 compatibility, servers generate CHTs with the old, higher frequency - HelperTrieConfirmations = 2048 // number of confirmations before a server is expected to have the given HelperTrie available - HelperTrieProcessConfirmations = 256 // number of confirmations before a HelperTrie is generated -) +// IndexerConfig includes a set of configs for chain indexers. +type IndexerConfig struct { + // The block frequency for creating CHTs. + ChtSize uint64 -// trustedCheckpoint represents a set of post-processed trie roots (CHT and BloomTrie) associated with -// the appropriate section index and head hash. It is used to start light syncing from this checkpoint -// and avoid downloading the entire header chain while still being able to securely access old headers/logs. -type trustedCheckpoint struct { - name string - sectionIdx uint64 - sectionHead, chtRoot, bloomTrieRoot common.Hash + // A special auxiliary field represents client's chtsize for server config, otherwise represents server's chtsize. + PairChtSize uint64 + + // The number of confirmations needed to generate/accept a canonical hash help trie. + ChtConfirms uint64 + + // The block frequency for creating new bloom bits. + BloomSize uint64 + + // The number of confirmation needed before a bloom section is considered probably final and its rotated bits + // are calculated. + BloomConfirms uint64 + + // The block frequency for creating BloomTrie. + BloomTrieSize uint64 + + // The number of confirmations needed to generate/accept a bloom trie. + BloomTrieConfirms uint64 } var ( - mainnetCheckpoint = trustedCheckpoint{ - name: "ETH mainnet", - sectionIdx: 150, - sectionHead: common.HexToHash("1e2e67f289565cbe7bd4367f7960dbd73a3f7c53439e1047cd7ba331c8109e39"), - chtRoot: common.HexToHash("f2a6c9ca143d647b44523cc249f1072c8912358ab873a77a5fdc792b8df99e80"), - bloomTrieRoot: common.HexToHash("c018952fa1513c97857e79fbb9a37acaf8432d5b85e52a78eca7dff5fd5900ee"), + // DefaultServerIndexerConfig wraps a set of configs as a default indexer config for server side. + DefaultServerIndexerConfig = &IndexerConfig{ + ChtSize: params.CHTFrequencyServer, + PairChtSize: params.CHTFrequencyClient, + ChtConfirms: params.HelperTrieProcessConfirmations, + BloomSize: params.BloomBitsBlocks, + BloomConfirms: params.BloomConfirms, + BloomTrieSize: params.BloomTrieFrequency, + BloomTrieConfirms: params.HelperTrieProcessConfirmations, } - - ropstenCheckpoint = trustedCheckpoint{ - name: "Ropsten testnet", - sectionIdx: 75, - sectionHead: common.HexToHash("12e68324f4578ea3e8e7fb3968167686729396c9279287fa1f1a8b51bb2d05b4"), - chtRoot: common.HexToHash("3e51dc095c69fa654a4cac766e0afff7357515b4b3c3a379c675f810363e54be"), - bloomTrieRoot: common.HexToHash("33e3a70b33c1d73aa698d496a80615e98ed31fa8f56969876180553b32333339"), + // DefaultClientIndexerConfig wraps a set of configs as a default indexer config for client side. + DefaultClientIndexerConfig = &IndexerConfig{ + ChtSize: params.CHTFrequencyClient, + PairChtSize: params.CHTFrequencyServer, + ChtConfirms: params.HelperTrieConfirmations, + BloomSize: params.BloomBitsBlocksClient, + BloomConfirms: params.HelperTrieConfirmations, + BloomTrieSize: params.BloomTrieFrequency, + BloomTrieConfirms: params.HelperTrieConfirmations, + } + // TestServerIndexerConfig wraps a set of configs as a test indexer config for server side. + TestServerIndexerConfig = &IndexerConfig{ + ChtSize: 64, + PairChtSize: 512, + ChtConfirms: 4, + BloomSize: 64, + BloomConfirms: 4, + BloomTrieSize: 512, + BloomTrieConfirms: 4, + } + // TestClientIndexerConfig wraps a set of configs as a test indexer config for client side. + TestClientIndexerConfig = &IndexerConfig{ + ChtSize: 512, + PairChtSize: 64, + ChtConfirms: 32, + BloomSize: 512, + BloomConfirms: 32, + BloomTrieSize: 512, + BloomTrieConfirms: 32, } ) // trustedCheckpoints associates each known checkpoint with the genesis hash of the chain it belongs to -var trustedCheckpoints = map[common.Hash]trustedCheckpoint{ - params.MainnetGenesisHash: mainnetCheckpoint, - params.TestnetGenesisHash: ropstenCheckpoint, +var trustedCheckpoints = map[common.Hash]*params.TrustedCheckpoint{ + params.MainnetGenesisHash: params.MainnetTrustedCheckpoint, + params.TestnetGenesisHash: params.TestnetTrustedCheckpoint, + params.RinkebyGenesisHash: params.RinkebyTrustedCheckpoint, } var ( - ErrNoTrustedCht = errors.New("No trusted canonical hash trie") - ErrNoTrustedBloomTrie = errors.New("No trusted bloom trie") - ErrNoHeader = errors.New("Header not found") + ErrNoTrustedCht = errors.New("no trusted canonical hash trie") + ErrNoTrustedBloomTrie = errors.New("no trusted bloom trie") + ErrNoHeader = errors.New("header not found") chtPrefix = []byte("chtRoot-") // chtPrefix + chtNum (uint64 big endian) -> trie root hash ChtTablePrefix = "cht-" ) @@ -88,8 +125,8 @@ type ChtNode struct { Td *big.Int } -// GetChtRoot reads the CHT root assoctiated to the given section from the database -// Note that sectionIdx is specified according to LES/1 CHT section size +// GetChtRoot reads the CHT root associated to the given section from the database +// Note that sectionIdx is specified according to LES/1 CHT section size. func GetChtRoot(db ethdb.Database, sectionIdx uint64, sectionHead common.Hash) common.Hash { var encNumber [8]byte binary.BigEndian.PutUint64(encNumber[:], sectionIdx) @@ -97,61 +134,88 @@ func GetChtRoot(db ethdb.Database, sectionIdx uint64, sectionHead common.Hash) c return common.BytesToHash(data) } -// GetChtV2Root reads the CHT root assoctiated to the given section from the database -// Note that sectionIdx is specified according to LES/2 CHT section size -func GetChtV2Root(db ethdb.Database, sectionIdx uint64, sectionHead common.Hash) common.Hash { - return GetChtRoot(db, (sectionIdx+1)*(ChtFrequency/ChtV1Frequency)-1, sectionHead) -} - -// StoreChtRoot writes the CHT root assoctiated to the given section into the database -// Note that sectionIdx is specified according to LES/1 CHT section size +// StoreChtRoot writes the CHT root associated to the given section into the database +// Note that sectionIdx is specified according to LES/1 CHT section size. func StoreChtRoot(db ethdb.Database, sectionIdx uint64, sectionHead, root common.Hash) { var encNumber [8]byte binary.BigEndian.PutUint64(encNumber[:], sectionIdx) db.Put(append(append(chtPrefix, encNumber[:]...), sectionHead.Bytes()...), root.Bytes()) } -// ChtIndexerBackend implements core.ChainIndexerBackend +// ChtIndexerBackend implements core.ChainIndexerBackend. type ChtIndexerBackend struct { - db, cdb ethdb.Database + diskdb, trieTable ethdb.Database + odr OdrBackend + triedb *trie.Database section, sectionSize uint64 lastHash common.Hash trie *trie.Trie } -// NewBloomTrieIndexer creates a BloomTrie chain indexer -func NewChtIndexer(db ethdb.Database, clientMode bool) *core.ChainIndexer { - cdb := ethdb.NewTable(db, ChtTablePrefix) - idb := ethdb.NewTable(db, "chtIndex-") - var sectionSize, confirmReq uint64 - if clientMode { - sectionSize = ChtFrequency - confirmReq = HelperTrieConfirmations - } else { - sectionSize = ChtV1Frequency - confirmReq = HelperTrieProcessConfirmations +// NewChtIndexer creates a Cht chain indexer +func NewChtIndexer(db ethdb.Database, odr OdrBackend, size, confirms uint64) *core.ChainIndexer { + trieTable := ethdb.NewTable(db, ChtTablePrefix) + backend := &ChtIndexerBackend{ + diskdb: db, + odr: odr, + trieTable: 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") +} + +// fetchMissingNodes tries to retrieve the last entry of the latest trusted CHT from the +// ODR backend in order to be able to add new entries and calculate subsequent root hashes +func (c *ChtIndexerBackend) fetchMissingNodes(ctx context.Context, section uint64, root common.Hash) error { + batch := c.trieTable.NewBatch() + r := &ChtRequest{ChtRoot: root, ChtNum: section - 1, BlockNum: section*c.sectionSize - 1, Config: c.odr.IndexerConfig()} + for { + err := c.odr.Retrieve(ctx, r) + switch err { + case nil: + r.Proof.Store(batch) + return batch.Write() + case ErrNoPeers: + // if there are no peers to serve, retry later + select { + case <-ctx.Done(): + return ctx.Err() + case <-time.After(time.Second * 10): + // stay in the loop and try again + } + default: + return err + } } - return core.NewChainIndexer(db, idb, &ChtIndexerBackend{db: db, cdb: cdb, sectionSize: sectionSize}, sectionSize, confirmReq, time.Millisecond*100, "cht") } // Reset implements core.ChainIndexerBackend -func (c *ChtIndexerBackend) Reset(section uint64, lastSectionHead common.Hash) error { +func (c *ChtIndexerBackend) Reset(ctx context.Context, section uint64, lastSectionHead common.Hash) error { var root common.Hash if section > 0 { - root = GetChtRoot(c.db, section-1, lastSectionHead) + root = GetChtRoot(c.diskdb, section-1, lastSectionHead) } var err error - c.trie, err = trie.New(root, c.cdb) + c.trie, err = trie.New(root, c.triedb) + + if err != nil && c.odr != nil { + err = c.fetchMissingNodes(ctx, section, root) + if err == nil { + c.trie, err = trie.New(root, c.triedb) + } + } + c.section = section return err } // Process implements core.ChainIndexerBackend -func (c *ChtIndexerBackend) Process(header *types.Header) { +func (c *ChtIndexerBackend) Process(ctx context.Context, header *types.Header) error { hash, num := header.Hash(), header.Number.Uint64() c.lastHash = hash - td := core.GetTd(c.db, hash, num) + td := rawdb.ReadTd(c.diskdb, hash, num) if td == nil { panic(nil) } @@ -159,30 +223,24 @@ func (c *ChtIndexerBackend) Process(header *types.Header) { binary.BigEndian.PutUint64(encNumber[:], num) data, _ := rlp.EncodeToBytes(ChtNode{hash, td}) c.trie.Update(encNumber[:], data) + return nil } // Commit implements core.ChainIndexerBackend func (c *ChtIndexerBackend) Commit() error { - batch := c.cdb.NewBatch() - root, err := c.trie.CommitTo(batch) + root, err := c.trie.Commit(nil) if err != nil { return err - } else { - batch.Write() - if ((c.section+1)*c.sectionSize)%ChtFrequency == 0 { - log.Info("Storing CHT", "idx", c.section*c.sectionSize/ChtFrequency, "sectionHead", fmt.Sprintf("%064x", c.lastHash), "root", fmt.Sprintf("%064x", root)) - } - StoreChtRoot(c.db, c.section, c.lastHash, root) } + c.triedb.Commit(root, false) + + if ((c.section+1)*c.sectionSize)%params.CHTFrequencyClient == 0 { + log.Info("Storing CHT", "section", c.section*c.sectionSize/params.CHTFrequencyClient, "head", fmt.Sprintf("%064x", c.lastHash), "root", fmt.Sprintf("%064x", root)) + } + StoreChtRoot(c.diskdb, c.section, c.lastHash, root) return nil } -const ( - BloomTrieFrequency = 32768 - ethBloomBitsSection = 4096 - ethBloomBitsConfirmations = 256 -) - var ( bloomTriePrefix = []byte("bltRoot-") // bloomTriePrefix + bloomTrieNum (uint64 big endian) -> trie root hash BloomTrieTablePrefix = "blt-" @@ -205,48 +263,105 @@ func StoreBloomTrieRoot(db ethdb.Database, sectionIdx uint64, sectionHead, root // BloomTrieIndexerBackend implements core.ChainIndexerBackend type BloomTrieIndexerBackend struct { - db, cdb ethdb.Database - section, parentSectionSize, bloomTrieRatio uint64 - trie *trie.Trie - sectionHeads []common.Hash + diskdb, trieTable ethdb.Database + triedb *trie.Database + odr OdrBackend + section uint64 + parentSize uint64 + size uint64 + bloomTrieRatio uint64 + trie *trie.Trie + sectionHeads []common.Hash } // NewBloomTrieIndexer creates a BloomTrie chain indexer -func NewBloomTrieIndexer(db ethdb.Database, clientMode bool) *core.ChainIndexer { - cdb := ethdb.NewTable(db, BloomTrieTablePrefix) - idb := ethdb.NewTable(db, "bltIndex-") - backend := &BloomTrieIndexerBackend{db: db, cdb: cdb} - var confirmReq uint64 - if clientMode { - backend.parentSectionSize = BloomTrieFrequency - confirmReq = HelperTrieConfirmations - } else { - backend.parentSectionSize = ethBloomBitsSection - confirmReq = HelperTrieProcessConfirmations +func NewBloomTrieIndexer(db ethdb.Database, odr OdrBackend, parentSize, size uint64) *core.ChainIndexer { + trieTable := ethdb.NewTable(db, BloomTrieTablePrefix) + backend := &BloomTrieIndexerBackend{ + diskdb: db, + odr: odr, + trieTable: trieTable, + triedb: trie.NewDatabaseWithCache(trieTable, 1), // Use a tiny cache only to keep memory down + parentSize: parentSize, + size: size, } - backend.bloomTrieRatio = BloomTrieFrequency / backend.parentSectionSize + backend.bloomTrieRatio = size / parentSize backend.sectionHeads = make([]common.Hash, backend.bloomTrieRatio) - return core.NewChainIndexer(db, idb, backend, BloomTrieFrequency, confirmReq-ethBloomBitsConfirmations, time.Millisecond*100, "bloomtrie") + return core.NewChainIndexer(db, ethdb.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 +// ODR backend in order to be able to add new entries and calculate subsequent root hashes +func (b *BloomTrieIndexerBackend) fetchMissingNodes(ctx context.Context, section uint64, root common.Hash) error { + indexCh := make(chan uint, types.BloomBitLength) + type res struct { + nodes *NodeSet + err error + } + resCh := make(chan res, types.BloomBitLength) + for i := 0; i < 20; i++ { + go func() { + for bitIndex := range indexCh { + r := &BloomRequest{BloomTrieRoot: root, BloomTrieNum: section - 1, BitIdx: bitIndex, SectionIndexList: []uint64{section - 1}, Config: b.odr.IndexerConfig()} + for { + if err := b.odr.Retrieve(ctx, r); err == ErrNoPeers { + // if there are no peers to serve, retry later + select { + case <-ctx.Done(): + resCh <- res{nil, ctx.Err()} + return + case <-time.After(time.Second * 10): + // stay in the loop and try again + } + } else { + resCh <- res{r.Proofs, err} + break + } + } + } + }() + } + + for i := uint(0); i < types.BloomBitLength; i++ { + indexCh <- i + } + close(indexCh) + batch := b.trieTable.NewBatch() + for i := uint(0); i < types.BloomBitLength; i++ { + res := <-resCh + if res.err != nil { + return res.err + } + res.nodes.Store(batch) + } + return batch.Write() } // Reset implements core.ChainIndexerBackend -func (b *BloomTrieIndexerBackend) Reset(section uint64, lastSectionHead common.Hash) error { +func (b *BloomTrieIndexerBackend) Reset(ctx context.Context, section uint64, lastSectionHead common.Hash) error { var root common.Hash if section > 0 { - root = GetBloomTrieRoot(b.db, section-1, lastSectionHead) + root = GetBloomTrieRoot(b.diskdb, section-1, lastSectionHead) } var err error - b.trie, err = trie.New(root, b.cdb) + b.trie, err = trie.New(root, b.triedb) + if err != nil && b.odr != nil { + err = b.fetchMissingNodes(ctx, section, root) + if err == nil { + b.trie, err = trie.New(root, b.triedb) + } + } b.section = section return err } // Process implements core.ChainIndexerBackend -func (b *BloomTrieIndexerBackend) Process(header *types.Header) { - num := header.Number.Uint64() - b.section*BloomTrieFrequency - if (num+1)%b.parentSectionSize == 0 { - b.sectionHeads[num/b.parentSectionSize] = header.Hash() +func (b *BloomTrieIndexerBackend) Process(ctx context.Context, header *types.Header) error { + num := header.Number.Uint64() - b.section*b.size + if (num+1)%b.parentSize == 0 { + b.sectionHeads[num/b.parentSize] = header.Hash() } + return nil } // Commit implements core.ChainIndexerBackend @@ -259,11 +374,11 @@ func (b *BloomTrieIndexerBackend) Commit() error { binary.BigEndian.PutUint64(encKey[2:10], b.section) var decomp []byte for j := uint64(0); j < b.bloomTrieRatio; j++ { - data, err := core.GetBloomBits(b.db, i, b.section*b.bloomTrieRatio+j, b.sectionHeads[j]) + data, err := rawdb.ReadBloomBits(b.diskdb, i, b.section*b.bloomTrieRatio+j, b.sectionHeads[j]) if err != nil { return err } - decompData, err2 := bitutil.DecompressBytes(data, int(b.parentSectionSize/8)) + decompData, err2 := bitutil.DecompressBytes(data, int(b.parentSize/8)) if err2 != nil { return err2 } @@ -279,17 +394,14 @@ func (b *BloomTrieIndexerBackend) Commit() error { b.trie.Delete(encKey[:]) } } - - batch := b.cdb.NewBatch() - root, err := b.trie.CommitTo(batch) + root, err := b.trie.Commit(nil) if err != nil { return err - } else { - batch.Write() - sectionHead := b.sectionHeads[b.bloomTrieRatio-1] - log.Info("Storing BloomTrie", "section", b.section, "sectionHead", fmt.Sprintf("%064x", sectionHead), "root", fmt.Sprintf("%064x", root), "compression ratio", float64(compSize)/float64(decompSize)) - StoreBloomTrieRoot(b.db, b.section, sectionHead, root) } + b.triedb.Commit(root, false) + sectionHead := b.sectionHeads[b.bloomTrieRatio-1] + log.Info("Storing bloom trie", "section", b.section, "head", fmt.Sprintf("%064x", sectionHead), "root", fmt.Sprintf("%064x", root), "compression", float64(compSize)/float64(decompSize)) + StoreBloomTrieRoot(b.diskdb, b.section, sectionHead, root) return nil } diff --git a/light/trie.go b/light/trie.go index 7a9c86b98d..4d4abe1375 100644 --- a/light/trie.go +++ b/light/trie.go @@ -18,12 +18,14 @@ package light import ( "context" + "errors" "fmt" "github.com/ethereum/go-ethereum/common" "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/trie" ) @@ -65,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 { @@ -83,6 +85,10 @@ func (db *odrDatabase) ContractCodeSize(addrHash, codeHash common.Hash) (int, er return len(code), err } +func (db *odrDatabase) TrieDB() *trie.Database { + return nil +} + type odrTrie struct { db *odrDatabase id *TrieID @@ -102,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) }) } @@ -113,11 +119,11 @@ func (t *odrTrie) TryDelete(key []byte) error { }) } -func (t *odrTrie) CommitTo(db trie.DatabaseWriter) (common.Hash, error) { +func (t *odrTrie) Commit(onleaf trie.LeafCallback) (common.Hash, error) { if t.trie == nil { return t.id.Root, nil } - return t.trie.CommitTo(db) + return t.trie.Commit(onleaf) } func (t *odrTrie) Hash() common.Hash { @@ -135,13 +141,17 @@ func (t *odrTrie) GetKey(sha []byte) []byte { return nil } +func (t *odrTrie) Prove(key []byte, fromLevel uint, proofDb ethdb.Putter) error { + return errors.New("not implemented, needs client/server interface split") +} + // do tries and retries to execute a function until it returns with no error or // an error type other than MissingNodeError func (t *odrTrie) do(key []byte, fn func() error) error { for { var err error if t.trie == nil { - t.trie, err = trie.New(t.id.Root, t.db.backend.Database()) + t.trie, err = trie.New(t.id.Root, trie.NewDatabase(t.db.backend.Database())) } if err == nil { err = fn() @@ -167,7 +177,7 @@ func newNodeIterator(t *odrTrie, startkey []byte) trie.NodeIterator { // Open the actual non-ODR trie if that hasn't happened yet. if t.trie == nil { it.do(func() error { - t, err := trie.New(t.id.Root, t.db.backend.Database()) + t, err := trie.New(t.id.Root, trie.NewDatabase(t.db.backend.Database())) if err == nil { it.t.trie = t } diff --git a/light/trie_test.go b/light/trie_test.go index d99664718f..5b5fce31d9 100644 --- a/light/trie_test.go +++ b/light/trie_test.go @@ -34,20 +34,20 @@ import ( func TestNodeIterator(t *testing.T) { var ( - fulldb, _ = ethdb.NewMemDatabase() - lightdb, _ = ethdb.NewMemDatabase() - gspec = core.Genesis{Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}} - genesis = gspec.MustCommit(fulldb) + fulldb = ethdb.NewMemDatabase() + lightdb = ethdb.NewMemDatabase() + gspec = core.Genesis{Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}} + genesis = gspec.MustCommit(fulldb) ) gspec.MustCommit(lightdb) - blockchain, _ := core.NewBlockChain(fulldb, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}) + blockchain, _ := core.NewBlockChain(fulldb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil) gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), fulldb, 4, testChainGen) if _, err := blockchain.InsertChain(gchain); err != nil { panic(err) } ctx := context.Background() - odr := &testOdr{sdb: fulldb, ldb: lightdb} + odr := &testOdr{sdb: fulldb, ldb: lightdb, indexerConfig: TestClientIndexerConfig} head := blockchain.CurrentHeader() lightTrie, _ := NewStateDatabase(ctx, head, odr).OpenTrie(head.Root) fullTrie, _ := state.NewDatabase(fulldb).OpenTrie(head.Root) @@ -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/light/txpool.go b/light/txpool.go index ca41490bdc..e945ef2ec1 100644 --- a/light/txpool.go +++ b/light/txpool.go @@ -24,6 +24,7 @@ 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/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" @@ -88,7 +89,7 @@ type TxRelayBackend interface { func NewTxPool(config *params.ChainConfig, chain *LightChain, relay TxRelayBackend) *TxPool { pool := &TxPool{ config: config, - signer: types.NewEIP155Signer(config.ChainId), + signer: types.NewEIP155Signer(config.ChainID), nonce: make(map[common.Address]uint64), pending: make(map[common.Hash]*types.Transaction), mined: make(map[common.Hash][]*types.Transaction), @@ -183,9 +184,8 @@ func (pool *TxPool) checkMinedTxs(ctx context.Context, hash common.Hash, number if _, err := GetBlockReceipts(ctx, pool.odr, hash, number); err != nil { // ODR caches, ignore results return err } - if err := core.WriteTxLookupEntries(pool.chainDb, block); err != nil { - return err - } + rawdb.WriteTxLookupEntries(pool.chainDb, block) + // Update the transaction pool's state for _, tx := range list { delete(pool.pending, tx.Hash()) @@ -199,15 +199,17 @@ func (pool *TxPool) checkMinedTxs(ctx context.Context, hash common.Hash, number // rollbackTxs marks the transactions contained in recently rolled back blocks // as rolled back. It also removes any positional lookup entries. func (pool *TxPool) rollbackTxs(hash common.Hash, txc txStateChanges) { + batch := pool.chainDb.NewBatch() if list, ok := pool.mined[hash]; ok { for _, tx := range list { txHash := tx.Hash() - core.DeleteTxLookupEntry(pool.chainDb, txHash) + rawdb.DeleteTxLookupEntry(batch, txHash) pool.pending[txHash] = tx txc.setState(txHash, false) } delete(pool.mined, hash) } + batch.Write() } // reorgOnNewHead sets a new head header, processing (and rolling back if necessary) @@ -258,7 +260,7 @@ func (pool *TxPool) reorgOnNewHead(ctx context.Context, newHeader *types.Header) idx2 := idx - txPermanent if len(pool.mined) > 0 { for i := pool.clearIdx; i < idx2; i++ { - hash := core.GetCanonicalHash(pool.chainDb, i) + hash := rawdb.ReadCanonicalHash(pool.chainDb, i) if list, ok := pool.mined[hash]; ok { hashes := make([]common.Hash, len(list)) for i, tx := range list { @@ -321,9 +323,9 @@ func (pool *TxPool) Stop() { log.Info("Transaction pool stopped") } -// SubscribeTxPreEvent registers a subscription of core.TxPreEvent and +// SubscribeNewTxsEvent registers a subscription of core.NewTxsEvent and // starts sending event to the given channel. -func (pool *TxPool) SubscribeTxPreEvent(ch chan<- core.TxPreEvent) event.Subscription { +func (pool *TxPool) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription { return pool.scope.Track(pool.txFeed.Subscribe(ch)) } @@ -388,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.TxPreEvent{Tx: 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 @@ -470,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++ } @@ -485,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 @@ -501,18 +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 := pool.chainDb.NewBatch() for _, tx := range txs { - //self.RemoveTx(tx.Hash()) hash := tx.Hash() - delete(self.pending, hash) - self.chainDb.Delete(hash[:]) + delete(pool.pending, hash) + batch.Delete(hash.Bytes()) hashes = append(hashes, hash) } - self.relay.Discard(hashes) + batch.Write() + pool.relay.Discard(hashes) } // RemoveTx removes the transaction with the given hash from the pool. diff --git a/light/txpool_test.go b/light/txpool_test.go index b343f79b05..ce77573efd 100644 --- a/light/txpool_test.go +++ b/light/txpool_test.go @@ -81,20 +81,20 @@ func TestTxPool(t *testing.T) { } var ( - sdb, _ = ethdb.NewMemDatabase() - ldb, _ = ethdb.NewMemDatabase() + sdb = ethdb.NewMemDatabase() + ldb = ethdb.NewMemDatabase() gspec = core.Genesis{Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}} genesis = gspec.MustCommit(sdb) ) gspec.MustCommit(ldb) // Assemble the test environment - blockchain, _ := core.NewBlockChain(sdb, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}) + blockchain, _ := core.NewBlockChain(sdb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil) gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), sdb, poolTestBlocks, txPoolTestChainGen) if _, err := blockchain.InsertChain(gchain); err != nil { panic(err) } - odr := &testOdr{sdb: sdb, ldb: ldb} + odr := &testOdr{sdb: sdb, ldb: ldb, indexerConfig: TestClientIndexerConfig} relay := &testTxRelay{ send: make(chan int, 1), discard: make(chan int, 1), diff --git a/log/README.md b/log/README.md index 0951b21cb5..b4476577b6 100644 --- a/log/README.md +++ b/log/README.md @@ -45,7 +45,7 @@ srvlog.SetHandler(log.MultiHandler( log.StreamHandler(os.Stderr, log.LogfmtFormat()), log.LvlFilterHandler( log.LvlError, - log.Must.FileHandler("errors.json", log.JsonFormat())))) + log.Must.FileHandler("errors.json", log.JSONFormat())))) ``` Will result in output that looks like this: diff --git a/log/doc.go b/log/doc.go index 83ad8c54f6..bff2f4966a 100644 --- a/log/doc.go +++ b/log/doc.go @@ -86,7 +86,7 @@ from the rpc package in logfmt to standard out. The other prints records at Erro or above in JSON formatted output to the file /var/log/service.json handler := log.MultiHandler( - log.LvlFilterHandler(log.LvlError, log.Must.FileHandler("/var/log/service.json", log.JsonFormat())), + log.LvlFilterHandler(log.LvlError, log.Must.FileHandler("/var/log/service.json", log.JSONFormat())), log.MatchFilterHandler("pkg", "app/rpc" log.StdoutHandler()) ) @@ -304,8 +304,8 @@ For all Handler functions which can return an error, there is a version of that function which will return no error but panics on failure. They are all available on the Must object. For example: - log.Must.FileHandler("/path", log.JsonFormat) - log.Must.NetHandler("tcp", ":1234", log.JsonFormat) + log.Must.FileHandler("/path", log.JSONFormat) + log.Must.NetHandler("tcp", ":1234", log.JSONFormat) Inspiration and Credit diff --git a/log/format.go b/log/format.go index 0b07abb2ac..7902b296e6 100644 --- a/log/format.go +++ b/log/format.go @@ -15,7 +15,7 @@ import ( const ( timeFormat = "2006-01-02T15:04:05-0700" - termTimeFormat = "01-02|15:04:05" + termTimeFormat = "01-02|15:04:05.000" floatFormat = 'f' termMsgJust = 40 ) @@ -77,11 +77,11 @@ type TerminalStringer interface { // a terminal with color-coded level output and terser human friendly timestamp. // This format should only be used for interactive programs or while developing. // -// [TIME] [LEVEL] MESAGE key=value key=value ... +// [LEVEL] [TIME] MESAGE key=value key=value ... // // Example: // -// [May 16 20:58:45] [DBUG] remove route ns=haproxy addr=127.0.0.1:50002 +// [DBUG] [May 16 20:58:45] remove route ns=haproxy addr=127.0.0.1:50002 // func TerminalFormat(usecolor bool) Format { return FormatFunc(func(r *Record) []byte { @@ -196,16 +196,58 @@ func logfmt(buf *bytes.Buffer, ctx []interface{}, color int, term bool) { buf.WriteByte('\n') } -// JsonFormat formats log records as JSON objects separated by newlines. -// It is the equivalent of JsonFormatEx(false, true). -func JsonFormat() Format { - return JsonFormatEx(false, true) +// JSONFormat formats log records as JSON objects separated by newlines. +// It is the equivalent of JSONFormatEx(false, true). +func JSONFormat() Format { + return JSONFormatEx(false, true) } -// JsonFormatEx formats log records as JSON objects. If pretty is true, +// JSONFormatOrderedEx formats log records as JSON arrays. If pretty is true, // records will be pretty-printed. If lineSeparated is true, records // will be logged with a new line between each record. -func JsonFormatEx(pretty, lineSeparated bool) Format { +func JSONFormatOrderedEx(pretty, lineSeparated bool) Format { + jsonMarshal := json.Marshal + if pretty { + jsonMarshal = func(v interface{}) ([]byte, error) { + return json.MarshalIndent(v, "", " ") + } + } + return FormatFunc(func(r *Record) []byte { + props := make(map[string]interface{}) + + props[r.KeyNames.Time] = r.Time + props[r.KeyNames.Lvl] = r.Lvl.String() + props[r.KeyNames.Msg] = r.Msg + + ctx := make([]string, len(r.Ctx)) + for i := 0; i < len(r.Ctx); i += 2 { + k, ok := r.Ctx[i].(string) + if !ok { + props[errorKey] = fmt.Sprintf("%+v is not a string key,", r.Ctx[i]) + } + ctx[i] = k + ctx[i+1] = formatLogfmtValue(r.Ctx[i+1], true) + } + props[r.KeyNames.Ctx] = ctx + + b, err := jsonMarshal(props) + if err != nil { + b, _ = jsonMarshal(map[string]string{ + errorKey: err.Error(), + }) + return b + } + if lineSeparated { + b = append(b, '\n') + } + return b + }) +} + +// JSONFormatEx formats log records as JSON objects. If pretty is true, +// records will be pretty-printed. If lineSeparated is true, records +// will be logged with a new line between each record. +func JSONFormatEx(pretty, lineSeparated bool) Format { jsonMarshal := json.Marshal if pretty { jsonMarshal = func(v interface{}) ([]byte, error) { @@ -225,7 +267,7 @@ func JsonFormatEx(pretty, lineSeparated bool) Format { if !ok { props[errorKey] = fmt.Sprintf("%+v is not a string key", r.Ctx[i]) } - props[k] = formatJsonValue(r.Ctx[i+1]) + props[k] = formatJSONValue(r.Ctx[i+1]) } b, err := jsonMarshal(props) @@ -270,7 +312,7 @@ func formatShared(value interface{}) (result interface{}) { } } -func formatJsonValue(value interface{}) interface{} { +func formatJSONValue(value interface{}) interface{} { value = formatShared(value) switch value.(type) { case int, int8, int16, int32, int64, float32, float64, uint, uint8, uint16, uint32, uint64, string: diff --git a/log/handler.go b/log/handler.go index d5594b853d..2f01b5dc6f 100644 --- a/log/handler.go +++ b/log/handler.go @@ -8,11 +8,16 @@ import ( "reflect" "sync" + "io/ioutil" + "path/filepath" + "regexp" + "strings" + "github.com/go-stack/stack" ) +// Handler defines where and how log records are written. // A Logger prints its log records by writing to a Handler. -// The Handler interface defines where and how log records are written. // Handlers are composable, providing you great flexibility in combining // them to achieve the logging structure that suits your applications. type Handler interface { @@ -70,6 +75,111 @@ func FileHandler(path string, fmtr Format) (Handler, error) { return closingHandler{f, StreamHandler(f, fmtr)}, nil } +// countingWriter wraps a WriteCloser object in order to count the written bytes. +type countingWriter struct { + w io.WriteCloser // the wrapped object + count uint // number of bytes written +} + +// Write increments the byte counter by the number of bytes written. +// Implements the WriteCloser interface. +func (w *countingWriter) Write(p []byte) (n int, err error) { + n, err = w.w.Write(p) + w.count += uint(n) + return n, err +} + +// Close implements the WriteCloser interface. +func (w *countingWriter) Close() error { + return w.w.Close() +} + +// prepFile opens the log file at the given path, and cuts off the invalid part +// from the end, because the previous execution could have been finished by interruption. +// Assumes that every line ended by '\n' contains a valid log record. +func prepFile(path string) (*countingWriter, error) { + f, err := os.OpenFile(path, os.O_RDWR|os.O_APPEND, 0600) + if err != nil { + return nil, err + } + _, err = f.Seek(-1, io.SeekEnd) + if err != nil { + return nil, err + } + buf := make([]byte, 1) + var cut int64 + for { + if _, err := f.Read(buf); err != nil { + return nil, err + } + if buf[0] == '\n' { + break + } + if _, err = f.Seek(-2, io.SeekCurrent); err != nil { + return nil, err + } + cut++ + } + fi, err := f.Stat() + if err != nil { + return nil, err + } + ns := fi.Size() - cut + if err = f.Truncate(ns); err != nil { + return nil, err + } + return &countingWriter{w: f, count: uint(ns)}, nil +} + +// RotatingFileHandler returns a handler which writes log records to file chunks +// at the given path. When a file's size reaches the limit, the handler creates +// a new file named after the timestamp of the first log record it will contain. +func RotatingFileHandler(path string, limit uint, formatter Format) (Handler, error) { + if err := os.MkdirAll(path, 0700); err != nil { + return nil, err + } + files, err := ioutil.ReadDir(path) + if err != nil { + return nil, err + } + re := regexp.MustCompile(`\.log$`) + last := len(files) - 1 + for last >= 0 && (!files[last].Mode().IsRegular() || !re.MatchString(files[last].Name())) { + last-- + } + var counter *countingWriter + if last >= 0 && files[last].Size() < int64(limit) { + // Open the last file, and continue to write into it until it's size reaches the limit. + if counter, err = prepFile(filepath.Join(path, files[last].Name())); err != nil { + return nil, err + } + } + if counter == nil { + counter = new(countingWriter) + } + h := StreamHandler(counter, formatter) + + return FuncHandler(func(r *Record) error { + if counter.count > limit { + counter.Close() + counter.w = nil + } + if counter.w == nil { + f, err := os.OpenFile( + filepath.Join(path, fmt.Sprintf("%s.log", strings.Replace(r.Time.Format("060102150405.00"), ".", "", 1))), + os.O_CREATE|os.O_APPEND|os.O_WRONLY, + 0600, + ) + if err != nil { + return err + } + counter.w = f + counter.count = 0 + } + return h.Log(r) + }), nil +} + // NetHandler opens a socket to the given address and writes records // over the connection. func NetHandler(network, addr string, fmtr Format) (Handler, error) { @@ -193,7 +303,7 @@ func LvlFilterHandler(maxLvl Lvl, h Handler) Handler { }, h) } -// A MultiHandler dispatches any write to each of its handlers. +// MultiHandler dispatches any write to each of its handlers. // This is useful for writing different types of log information // to different locations. For example, to log to a file and // standard error: @@ -212,7 +322,7 @@ func MultiHandler(hs ...Handler) Handler { }) } -// A FailoverHandler writes all log records to the first handler +// FailoverHandler writes all log records to the first handler // specified, but will failover and write to the second handler if // the first handler has failed, and so on for all handlers specified. // For example you might want to log to a network socket, but failover @@ -220,7 +330,7 @@ func MultiHandler(hs ...Handler) Handler { // standard out if the file write fails: // // log.FailoverHandler( -// log.Must.NetHandler("tcp", ":9090", log.JsonFormat()), +// log.Must.NetHandler("tcp", ":9090", log.JSONFormat()), // log.Must.FileHandler("/var/log/app.log", log.LogfmtFormat()), // log.StdoutHandler) // @@ -234,9 +344,8 @@ func FailoverHandler(hs ...Handler) Handler { err = h.Log(r) if err == nil { return nil - } else { - r.Ctx = append(r.Ctx, fmt.Sprintf("failover_err_%d", i), err) } + r.Ctx = append(r.Ctx, fmt.Sprintf("failover_err_%d", i), err) } return err @@ -320,13 +429,12 @@ func evaluateLazy(lz Lazy) (interface{}, error) { results := value.Call([]reflect.Value{}) if len(results) == 1 { return results[0].Interface(), nil - } else { - values := make([]interface{}, len(results)) - for i, v := range results { - values[i] = v.Interface() - } - return values, nil } + values := make([]interface{}, len(results)) + for i, v := range results { + values[i] = v.Interface() + } + return values, nil } // DiscardHandler reports success for all writes but does nothing. @@ -338,7 +446,7 @@ func DiscardHandler() Handler { }) } -// The Must object provides the following Handler creation functions +// Must provides the following Handler creation functions // which instead of returning an error parameter only return a Handler // and panic on failure: FileHandler, NetHandler, SyslogHandler, SyslogNetHandler var Must muster diff --git a/log/handler_glog.go b/log/handler_glog.go index f8b932fd1b..83dae44bd5 100644 --- a/log/handler_glog.go +++ b/log/handler_glog.go @@ -57,6 +57,11 @@ func NewGlogHandler(h Handler) *GlogHandler { } } +// SetHandler updates the handler to write records to the specified sub-handler. +func (h *GlogHandler) SetHandler(nh Handler) { + h.origin = nh +} + // pattern contains a filter for the Vmodule option, holding a verbosity level // and a file pattern to match. type pattern struct { diff --git a/log/logger.go b/log/logger.go index 15c83a9b25..ca3e0b0599 100644 --- a/log/logger.go +++ b/log/logger.go @@ -11,7 +11,9 @@ import ( const timeKey = "t" const lvlKey = "lvl" const msgKey = "msg" +const ctxKey = "ctx" const errorKey = "LOG15_ERROR" +const skipLevel = 2 type Lvl int @@ -24,7 +26,7 @@ const ( LvlTrace ) -// Aligned returns a 5-character string containing the name of a Lvl. +// AlignedString returns a 5-character string containing the name of a Lvl. func (l Lvl) AlignedString() string { switch l { case LvlTrace: @@ -64,7 +66,7 @@ func (l Lvl) String() string { } } -// Returns the appropriate Lvl from a string name. +// LvlFromString returns the appropriate Lvl from a string name. // Useful for parsing command line args and configuration files. func LvlFromString(lvlString string) (Lvl, error) { switch lvlString { @@ -95,10 +97,12 @@ type Record struct { KeyNames RecordKeyNames } +// RecordKeyNames gets stored in a Record when the write function is executed. type RecordKeyNames struct { Time string Msg string Lvl string + Ctx string } // A Logger writes key/value pairs to a Handler @@ -126,17 +130,18 @@ type logger struct { h *swapHandler } -func (l *logger) write(msg string, lvl Lvl, ctx []interface{}) { +func (l *logger) write(msg string, lvl Lvl, ctx []interface{}, skip int) { l.h.Log(&Record{ Time: time.Now(), Lvl: lvl, Msg: msg, Ctx: newContext(l.ctx, ctx), - Call: stack.Caller(2), + Call: stack.Caller(skip), KeyNames: RecordKeyNames{ Time: timeKey, Msg: msgKey, Lvl: lvlKey, + Ctx: ctxKey, }, }) } @@ -156,27 +161,27 @@ func newContext(prefix []interface{}, suffix []interface{}) []interface{} { } func (l *logger) Trace(msg string, ctx ...interface{}) { - l.write(msg, LvlTrace, ctx) + l.write(msg, LvlTrace, ctx, skipLevel) } func (l *logger) Debug(msg string, ctx ...interface{}) { - l.write(msg, LvlDebug, ctx) + l.write(msg, LvlDebug, ctx, skipLevel) } func (l *logger) Info(msg string, ctx ...interface{}) { - l.write(msg, LvlInfo, ctx) + l.write(msg, LvlInfo, ctx, skipLevel) } func (l *logger) Warn(msg string, ctx ...interface{}) { - l.write(msg, LvlWarn, ctx) + l.write(msg, LvlWarn, ctx, skipLevel) } func (l *logger) Error(msg string, ctx ...interface{}) { - l.write(msg, LvlError, ctx) + l.write(msg, LvlError, ctx, skipLevel) } func (l *logger) Crit(msg string, ctx ...interface{}) { - l.write(msg, LvlCrit, ctx) + l.write(msg, LvlCrit, ctx, skipLevel) os.Exit(1) } diff --git a/log/root.go b/log/root.go index 71b8cef6d4..9fb4c5ae0b 100644 --- a/log/root.go +++ b/log/root.go @@ -31,31 +31,40 @@ func Root() Logger { // Trace is a convenient alias for Root().Trace func Trace(msg string, ctx ...interface{}) { - root.write(msg, LvlTrace, ctx) + root.write(msg, LvlTrace, ctx, skipLevel) } // Debug is a convenient alias for Root().Debug func Debug(msg string, ctx ...interface{}) { - root.write(msg, LvlDebug, ctx) + root.write(msg, LvlDebug, ctx, skipLevel) } // Info is a convenient alias for Root().Info func Info(msg string, ctx ...interface{}) { - root.write(msg, LvlInfo, ctx) + root.write(msg, LvlInfo, ctx, skipLevel) } // Warn is a convenient alias for Root().Warn func Warn(msg string, ctx ...interface{}) { - root.write(msg, LvlWarn, ctx) + root.write(msg, LvlWarn, ctx, skipLevel) } // Error is a convenient alias for Root().Error func Error(msg string, ctx ...interface{}) { - root.write(msg, LvlError, ctx) + root.write(msg, LvlError, ctx, skipLevel) } // Crit is a convenient alias for Root().Crit func Crit(msg string, ctx ...interface{}) { - root.write(msg, LvlCrit, ctx) + root.write(msg, LvlCrit, ctx, skipLevel) os.Exit(1) } + +// Output is a convenient alias for write, allowing for the modification of +// the calldepth (number of stack frames to skip). +// calldepth influences the reported line number of the log message. +// A calldepth of zero reports the immediate caller of Output. +// Non-zero calldepth skips as many stack frames. +func Output(msg string, lvl Lvl, calldepth int, ctx ...interface{}) { + root.write(msg, lvl, ctx, calldepth+skipLevel) +} diff --git a/log/term/terminal_appengine.go b/log/term/terminal_appengine.go deleted file mode 100644 index c1b5d2a3b1..0000000000 --- a/log/term/terminal_appengine.go +++ /dev/null @@ -1,13 +0,0 @@ -// Based on ssh/terminal: -// Copyright 2013 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 term - -// IsTty always returns false on AppEngine. -func IsTty(fd uintptr) bool { - return false -} diff --git a/log/term/terminal_darwin.go b/log/term/terminal_darwin.go deleted file mode 100644 index d8f351b1b1..0000000000 --- a/log/term/terminal_darwin.go +++ /dev/null @@ -1,13 +0,0 @@ -// Based on ssh/terminal: -// Copyright 2013 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 term - -import "syscall" - -const ioctlReadTermios = syscall.TIOCGETA - -type Termios syscall.Termios diff --git a/log/term/terminal_freebsd.go b/log/term/terminal_freebsd.go deleted file mode 100644 index cfaceab337..0000000000 --- a/log/term/terminal_freebsd.go +++ /dev/null @@ -1,18 +0,0 @@ -package term - -import ( - "syscall" -) - -const ioctlReadTermios = syscall.TIOCGETA - -// Go 1.2 doesn't include Termios for FreeBSD. This should be added in 1.3 and this could be merged with terminal_darwin. -type Termios struct { - Iflag uint32 - Oflag uint32 - Cflag uint32 - Lflag uint32 - Cc [20]uint8 - Ispeed uint32 - Ospeed uint32 -} diff --git a/log/term/terminal_linux.go b/log/term/terminal_linux.go deleted file mode 100644 index 5290468d69..0000000000 --- a/log/term/terminal_linux.go +++ /dev/null @@ -1,14 +0,0 @@ -// Based on ssh/terminal: -// Copyright 2013 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 term - -import "syscall" - -const ioctlReadTermios = syscall.TCGETS - -type Termios syscall.Termios diff --git a/log/term/terminal_netbsd.go b/log/term/terminal_netbsd.go deleted file mode 100644 index f9bb9e1c23..0000000000 --- a/log/term/terminal_netbsd.go +++ /dev/null @@ -1,7 +0,0 @@ -package term - -import "syscall" - -const ioctlReadTermios = syscall.TIOCGETA - -type Termios syscall.Termios diff --git a/log/term/terminal_notwindows.go b/log/term/terminal_notwindows.go deleted file mode 100644 index c9af534f62..0000000000 --- a/log/term/terminal_notwindows.go +++ /dev/null @@ -1,20 +0,0 @@ -// Based on ssh/terminal: -// Copyright 2011 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 linux,!appengine darwin freebsd openbsd netbsd - -package term - -import ( - "syscall" - "unsafe" -) - -// IsTty returns true if the given file descriptor is a terminal. -func IsTty(fd uintptr) bool { - var termios Termios - _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) - return err == 0 -} diff --git a/log/term/terminal_openbsd.go b/log/term/terminal_openbsd.go deleted file mode 100644 index f9bb9e1c23..0000000000 --- a/log/term/terminal_openbsd.go +++ /dev/null @@ -1,7 +0,0 @@ -package term - -import "syscall" - -const ioctlReadTermios = syscall.TIOCGETA - -type Termios syscall.Termios diff --git a/log/term/terminal_solaris.go b/log/term/terminal_solaris.go deleted file mode 100644 index 033c163246..0000000000 --- a/log/term/terminal_solaris.go +++ /dev/null @@ -1,9 +0,0 @@ -package term - -import "golang.org/x/sys/unix" - -// IsTty returns true if the given file descriptor is a terminal. -func IsTty(fd uintptr) bool { - _, err := unix.IoctlGetTermios(int(fd), unix.TCGETA) - return err == nil -} diff --git a/log/term/terminal_windows.go b/log/term/terminal_windows.go deleted file mode 100644 index df3c30c158..0000000000 --- a/log/term/terminal_windows.go +++ /dev/null @@ -1,26 +0,0 @@ -// Based on ssh/terminal: -// Copyright 2011 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 windows - -package term - -import ( - "syscall" - "unsafe" -) - -var kernel32 = syscall.NewLazyDLL("kernel32.dll") - -var ( - procGetConsoleMode = kernel32.NewProc("GetConsoleMode") -) - -// IsTty returns true if the given file descriptor is a terminal. -func IsTty(fd uintptr) bool { - var st uint32 - r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0) - return r != 0 && e == 0 -} diff --git a/metrics/FORK.md b/metrics/FORK.md new file mode 100644 index 0000000000..b19985bf56 --- /dev/null +++ b/metrics/FORK.md @@ -0,0 +1 @@ +This repo has been forked from https://github.com/rcrowley/go-metrics at commit e181e09 diff --git a/vendor/github.com/rcrowley/go-metrics/LICENSE b/metrics/LICENSE similarity index 100% rename from vendor/github.com/rcrowley/go-metrics/LICENSE rename to metrics/LICENSE diff --git a/vendor/github.com/rcrowley/go-metrics/README.md b/metrics/README.md similarity index 81% rename from vendor/github.com/rcrowley/go-metrics/README.md rename to metrics/README.md index 2d1a6dcfa4..bc2a45a838 100644 --- a/vendor/github.com/rcrowley/go-metrics/README.md +++ b/metrics/README.md @@ -42,12 +42,22 @@ t.Update(47) Register() is not threadsafe. For threadsafe metric registration use GetOrRegister: -``` +```go t := metrics.GetOrRegisterTimer("account.create.latency", nil) t.Time(func() {}) t.Update(47) ``` +**NOTE:** Be sure to unregister short-lived meters and timers otherwise they will +leak memory: + +```go +// Will call Stop() on the Meter to allow for garbage collection +metrics.Unregister("quux") +// Or similarly for a Timer that embeds a Meter +metrics.Unregister("bang") +``` + Periodically log every metric in human-readable form to standard error: ```go @@ -81,12 +91,13 @@ issues [#121](https://github.com/rcrowley/go-metrics/issues/121) and ```go import "github.com/vrischmann/go-metrics-influxdb" -go influxdb.Influxdb(metrics.DefaultRegistry, 10e9, &influxdb.Config{ - Host: "127.0.0.1:8086", - Database: "metrics", - Username: "test", - Password: "test", -}) +go influxdb.InfluxDB(metrics.DefaultRegistry, + 10e9, + "127.0.0.1:8086", + "database-name", + "username", + "password" +) ``` Periodically upload every metric to Librato using the [Librato client](https://github.com/mihasya/go-metrics-librato): @@ -146,8 +157,10 @@ Publishing Metrics Clients are available for the following destinations: -* Librato - [https://github.com/mihasya/go-metrics-librato](https://github.com/mihasya/go-metrics-librato) -* Graphite - [https://github.com/cyberdelia/go-metrics-graphite](https://github.com/cyberdelia/go-metrics-graphite) -* InfluxDB - [https://github.com/vrischmann/go-metrics-influxdb](https://github.com/vrischmann/go-metrics-influxdb) -* Ganglia - [https://github.com/appscode/metlia](https://github.com/appscode/metlia) -* Prometheus - [https://github.com/deathowl/go-metrics-prometheus](https://github.com/deathowl/go-metrics-prometheus) +* Librato - https://github.com/mihasya/go-metrics-librato +* Graphite - https://github.com/cyberdelia/go-metrics-graphite +* InfluxDB - https://github.com/vrischmann/go-metrics-influxdb +* Ganglia - https://github.com/appscode/metlia +* Prometheus - https://github.com/deathowl/go-metrics-prometheus +* DataDog - https://github.com/syntaqx/go-metrics-datadog +* SignalFX - https://github.com/pascallouisperez/go-metrics-signalfx diff --git a/vendor/github.com/rcrowley/go-metrics/counter.go b/metrics/counter.go similarity index 70% rename from vendor/github.com/rcrowley/go-metrics/counter.go rename to metrics/counter.go index bb7b039cb5..2f78c90d5c 100644 --- a/vendor/github.com/rcrowley/go-metrics/counter.go +++ b/metrics/counter.go @@ -1,6 +1,8 @@ package metrics -import "sync/atomic" +import ( + "sync/atomic" +) // Counters hold an int64 value that can be incremented and decremented. type Counter interface { @@ -20,14 +22,31 @@ func GetOrRegisterCounter(name string, r Registry) Counter { return r.GetOrRegister(name, NewCounter).(Counter) } +// GetOrRegisterCounterForced returns an existing Counter or constructs and registers a +// new Counter no matter the global switch is enabled or not. +// Be sure to unregister the counter from the registry once it is of no use to +// allow for garbage collection. +func GetOrRegisterCounterForced(name string, r Registry) Counter { + if nil == r { + r = DefaultRegistry + } + return r.GetOrRegister(name, NewCounterForced).(Counter) +} + // NewCounter constructs a new StandardCounter. func NewCounter() Counter { - if UseNilMetrics { + if !Enabled { return NilCounter{} } return &StandardCounter{0} } +// NewCounterForced constructs a new StandardCounter and returns it no matter if +// the global switch is enabled or not. +func NewCounterForced() Counter { + return &StandardCounter{0} +} + // NewRegisteredCounter constructs and registers a new StandardCounter. func NewRegisteredCounter(name string, r Registry) Counter { c := NewCounter() @@ -38,6 +57,19 @@ func NewRegisteredCounter(name string, r Registry) Counter { return c } +// NewRegisteredCounterForced constructs and registers a new StandardCounter +// and launches a goroutine no matter the global switch is enabled or not. +// Be sure to unregister the counter from the registry once it is of no use to +// allow for garbage collection. +func NewRegisteredCounterForced(name string, r Registry) Counter { + c := NewCounterForced() + if nil == r { + r = DefaultRegistry + } + r.Register(name, c) + return c +} + // CounterSnapshot is a read-only copy of another Counter. type CounterSnapshot int64 diff --git a/metrics/counter_test.go b/metrics/counter_test.go new file mode 100644 index 0000000000..dfb03b4e88 --- /dev/null +++ b/metrics/counter_test.go @@ -0,0 +1,77 @@ +package metrics + +import "testing" + +func BenchmarkCounter(b *testing.B) { + c := NewCounter() + b.ResetTimer() + for i := 0; i < b.N; i++ { + c.Inc(1) + } +} + +func TestCounterClear(t *testing.T) { + c := NewCounter() + c.Inc(1) + c.Clear() + if count := c.Count(); 0 != count { + t.Errorf("c.Count(): 0 != %v\n", count) + } +} + +func TestCounterDec1(t *testing.T) { + c := NewCounter() + c.Dec(1) + if count := c.Count(); -1 != count { + t.Errorf("c.Count(): -1 != %v\n", count) + } +} + +func TestCounterDec2(t *testing.T) { + c := NewCounter() + c.Dec(2) + if count := c.Count(); -2 != count { + t.Errorf("c.Count(): -2 != %v\n", count) + } +} + +func TestCounterInc1(t *testing.T) { + c := NewCounter() + c.Inc(1) + if count := c.Count(); 1 != count { + t.Errorf("c.Count(): 1 != %v\n", count) + } +} + +func TestCounterInc2(t *testing.T) { + c := NewCounter() + c.Inc(2) + if count := c.Count(); 2 != count { + t.Errorf("c.Count(): 2 != %v\n", count) + } +} + +func TestCounterSnapshot(t *testing.T) { + c := NewCounter() + c.Inc(1) + snapshot := c.Snapshot() + c.Inc(1) + if count := snapshot.Count(); 1 != count { + t.Errorf("c.Count(): 1 != %v\n", count) + } +} + +func TestCounterZero(t *testing.T) { + c := NewCounter() + if count := c.Count(); 0 != count { + t.Errorf("c.Count(): 0 != %v\n", count) + } +} + +func TestGetOrRegisterCounter(t *testing.T) { + r := NewRegistry() + NewRegisteredCounter("foo", r).Inc(47) + if c := GetOrRegisterCounter("foo", r); 47 != c.Count() { + t.Fatal(c) + } +} diff --git a/vendor/github.com/rcrowley/go-metrics/debug.go b/metrics/debug.go similarity index 94% rename from vendor/github.com/rcrowley/go-metrics/debug.go rename to metrics/debug.go index 043ccefab6..de4a2739fe 100644 --- a/vendor/github.com/rcrowley/go-metrics/debug.go +++ b/metrics/debug.go @@ -22,7 +22,7 @@ var ( // Capture new values for the Go garbage collector statistics exported in // debug.GCStats. This is designed to be called as a goroutine. func CaptureDebugGCStats(r Registry, d time.Duration) { - for _ = range time.Tick(d) { + for range time.Tick(d) { CaptureDebugGCStatsOnce(r) } } @@ -41,8 +41,8 @@ func CaptureDebugGCStatsOnce(r Registry) { debug.ReadGCStats(&gcStats) debugMetrics.ReadGCStats.UpdateSince(t) - debugMetrics.GCStats.LastGC.Update(int64(gcStats.LastGC.UnixNano())) - debugMetrics.GCStats.NumGC.Update(int64(gcStats.NumGC)) + debugMetrics.GCStats.LastGC.Update(gcStats.LastGC.UnixNano()) + debugMetrics.GCStats.NumGC.Update(gcStats.NumGC) if lastGC != gcStats.LastGC && 0 < len(gcStats.Pause) { debugMetrics.GCStats.Pause.Update(int64(gcStats.Pause[0])) } diff --git a/metrics/debug_test.go b/metrics/debug_test.go new file mode 100644 index 0000000000..07eb867841 --- /dev/null +++ b/metrics/debug_test.go @@ -0,0 +1,48 @@ +package metrics + +import ( + "runtime" + "runtime/debug" + "testing" + "time" +) + +func BenchmarkDebugGCStats(b *testing.B) { + r := NewRegistry() + RegisterDebugGCStats(r) + b.ResetTimer() + for i := 0; i < b.N; i++ { + CaptureDebugGCStatsOnce(r) + } +} + +func TestDebugGCStatsBlocking(t *testing.T) { + if g := runtime.GOMAXPROCS(0); g < 2 { + t.Skipf("skipping TestDebugGCMemStatsBlocking with GOMAXPROCS=%d\n", g) + return + } + ch := make(chan int) + go testDebugGCStatsBlocking(ch) + var gcStats debug.GCStats + t0 := time.Now() + debug.ReadGCStats(&gcStats) + t1 := time.Now() + t.Log("i++ during debug.ReadGCStats:", <-ch) + go testDebugGCStatsBlocking(ch) + d := t1.Sub(t0) + t.Log(d) + time.Sleep(d) + t.Log("i++ during time.Sleep:", <-ch) +} + +func testDebugGCStatsBlocking(ch chan int) { + i := 0 + for { + select { + case ch <- i: + return + default: + i++ + } + } +} diff --git a/vendor/github.com/rcrowley/go-metrics/ewma.go b/metrics/ewma.go similarity index 98% rename from vendor/github.com/rcrowley/go-metrics/ewma.go rename to metrics/ewma.go index 694a1d0330..57c949e7d4 100644 --- a/vendor/github.com/rcrowley/go-metrics/ewma.go +++ b/metrics/ewma.go @@ -17,9 +17,6 @@ type EWMA interface { // NewEWMA constructs a new EWMA with the given alpha. func NewEWMA(alpha float64) EWMA { - if UseNilMetrics { - return NilEWMA{} - } return &StandardEWMA{alpha: alpha} } diff --git a/metrics/ewma_test.go b/metrics/ewma_test.go new file mode 100644 index 0000000000..0430fbd247 --- /dev/null +++ b/metrics/ewma_test.go @@ -0,0 +1,225 @@ +package metrics + +import "testing" + +func BenchmarkEWMA(b *testing.B) { + a := NewEWMA1() + b.ResetTimer() + for i := 0; i < b.N; i++ { + a.Update(1) + a.Tick() + } +} + +func TestEWMA1(t *testing.T) { + a := NewEWMA1() + a.Update(3) + a.Tick() + if rate := a.Rate(); 0.6 != rate { + t.Errorf("initial a.Rate(): 0.6 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.22072766470286553 != rate { + t.Errorf("1 minute a.Rate(): 0.22072766470286553 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.08120116994196772 != rate { + t.Errorf("2 minute a.Rate(): 0.08120116994196772 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.029872241020718428 != rate { + t.Errorf("3 minute a.Rate(): 0.029872241020718428 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.01098938333324054 != rate { + t.Errorf("4 minute a.Rate(): 0.01098938333324054 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.004042768199451294 != rate { + t.Errorf("5 minute a.Rate(): 0.004042768199451294 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.0014872513059998212 != rate { + t.Errorf("6 minute a.Rate(): 0.0014872513059998212 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.0005471291793327122 != rate { + t.Errorf("7 minute a.Rate(): 0.0005471291793327122 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.00020127757674150815 != rate { + t.Errorf("8 minute a.Rate(): 0.00020127757674150815 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 7.404588245200814e-05 != rate { + t.Errorf("9 minute a.Rate(): 7.404588245200814e-05 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 2.7239957857491083e-05 != rate { + t.Errorf("10 minute a.Rate(): 2.7239957857491083e-05 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 1.0021020474147462e-05 != rate { + t.Errorf("11 minute a.Rate(): 1.0021020474147462e-05 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 3.6865274119969525e-06 != rate { + t.Errorf("12 minute a.Rate(): 3.6865274119969525e-06 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 1.3561976441886433e-06 != rate { + t.Errorf("13 minute a.Rate(): 1.3561976441886433e-06 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 4.989172314621449e-07 != rate { + t.Errorf("14 minute a.Rate(): 4.989172314621449e-07 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 1.8354139230109722e-07 != rate { + t.Errorf("15 minute a.Rate(): 1.8354139230109722e-07 != %v\n", rate) + } +} + +func TestEWMA5(t *testing.T) { + a := NewEWMA5() + a.Update(3) + a.Tick() + if rate := a.Rate(); 0.6 != rate { + t.Errorf("initial a.Rate(): 0.6 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.49123845184678905 != rate { + t.Errorf("1 minute a.Rate(): 0.49123845184678905 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.4021920276213837 != rate { + t.Errorf("2 minute a.Rate(): 0.4021920276213837 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.32928698165641596 != rate { + t.Errorf("3 minute a.Rate(): 0.32928698165641596 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.269597378470333 != rate { + t.Errorf("4 minute a.Rate(): 0.269597378470333 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.2207276647028654 != rate { + t.Errorf("5 minute a.Rate(): 0.2207276647028654 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.18071652714732128 != rate { + t.Errorf("6 minute a.Rate(): 0.18071652714732128 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.14795817836496392 != rate { + t.Errorf("7 minute a.Rate(): 0.14795817836496392 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.12113791079679326 != rate { + t.Errorf("8 minute a.Rate(): 0.12113791079679326 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.09917933293295193 != rate { + t.Errorf("9 minute a.Rate(): 0.09917933293295193 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.08120116994196763 != rate { + t.Errorf("10 minute a.Rate(): 0.08120116994196763 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.06648189501740036 != rate { + t.Errorf("11 minute a.Rate(): 0.06648189501740036 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.05443077197364752 != rate { + t.Errorf("12 minute a.Rate(): 0.05443077197364752 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.04456414692860035 != rate { + t.Errorf("13 minute a.Rate(): 0.04456414692860035 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.03648603757513079 != rate { + t.Errorf("14 minute a.Rate(): 0.03648603757513079 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.0298722410207183831020718428 != rate { + t.Errorf("15 minute a.Rate(): 0.0298722410207183831020718428 != %v\n", rate) + } +} + +func TestEWMA15(t *testing.T) { + a := NewEWMA15() + a.Update(3) + a.Tick() + if rate := a.Rate(); 0.6 != rate { + t.Errorf("initial a.Rate(): 0.6 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.5613041910189706 != rate { + t.Errorf("1 minute a.Rate(): 0.5613041910189706 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.5251039914257684 != rate { + t.Errorf("2 minute a.Rate(): 0.5251039914257684 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.4912384518467888184678905 != rate { + t.Errorf("3 minute a.Rate(): 0.4912384518467888184678905 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.459557003018789 != rate { + t.Errorf("4 minute a.Rate(): 0.459557003018789 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.4299187863442732 != rate { + t.Errorf("5 minute a.Rate(): 0.4299187863442732 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.4021920276213831 != rate { + t.Errorf("6 minute a.Rate(): 0.4021920276213831 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.37625345116383313 != rate { + t.Errorf("7 minute a.Rate(): 0.37625345116383313 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.3519877317060185 != rate { + t.Errorf("8 minute a.Rate(): 0.3519877317060185 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.3292869816564153165641596 != rate { + t.Errorf("9 minute a.Rate(): 0.3292869816564153165641596 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.3080502714195546 != rate { + t.Errorf("10 minute a.Rate(): 0.3080502714195546 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.2881831806538789 != rate { + t.Errorf("11 minute a.Rate(): 0.2881831806538789 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.26959737847033216 != rate { + t.Errorf("12 minute a.Rate(): 0.26959737847033216 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.2522102307052083 != rate { + t.Errorf("13 minute a.Rate(): 0.2522102307052083 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.23594443252115815 != rate { + t.Errorf("14 minute a.Rate(): 0.23594443252115815 != %v\n", rate) + } + elapseMinute(a) + if rate := a.Rate(); 0.2207276647028646247028654470286553 != rate { + t.Errorf("15 minute a.Rate(): 0.2207276647028646247028654470286553 != %v\n", rate) + } +} + +func elapseMinute(a EWMA) { + for i := 0; i < 12; i++ { + a.Tick() + } +} diff --git a/vendor/github.com/rcrowley/go-metrics/exp/exp.go b/metrics/exp/exp.go similarity index 64% rename from vendor/github.com/rcrowley/go-metrics/exp/exp.go rename to metrics/exp/exp.go index 11dd3f898a..325a193c77 100644 --- a/vendor/github.com/rcrowley/go-metrics/exp/exp.go +++ b/metrics/exp/exp.go @@ -8,7 +8,7 @@ import ( "net/http" "sync" - "github.com/rcrowley/go-metrics" + "github.com/ethereum/go-ethereum/metrics" ) type exp struct { @@ -97,22 +97,22 @@ func (exp *exp) publishHistogram(name string, metric metrics.Histogram) { exp.getInt(name + ".count").Set(h.Count()) exp.getFloat(name + ".min").Set(float64(h.Min())) exp.getFloat(name + ".max").Set(float64(h.Max())) - exp.getFloat(name + ".mean").Set(float64(h.Mean())) - exp.getFloat(name + ".std-dev").Set(float64(h.StdDev())) - exp.getFloat(name + ".50-percentile").Set(float64(ps[0])) - exp.getFloat(name + ".75-percentile").Set(float64(ps[1])) - exp.getFloat(name + ".95-percentile").Set(float64(ps[2])) - exp.getFloat(name + ".99-percentile").Set(float64(ps[3])) - exp.getFloat(name + ".999-percentile").Set(float64(ps[4])) + exp.getFloat(name + ".mean").Set(h.Mean()) + exp.getFloat(name + ".std-dev").Set(h.StdDev()) + exp.getFloat(name + ".50-percentile").Set(ps[0]) + exp.getFloat(name + ".75-percentile").Set(ps[1]) + exp.getFloat(name + ".95-percentile").Set(ps[2]) + exp.getFloat(name + ".99-percentile").Set(ps[3]) + exp.getFloat(name + ".999-percentile").Set(ps[4]) } func (exp *exp) publishMeter(name string, metric metrics.Meter) { m := metric.Snapshot() exp.getInt(name + ".count").Set(m.Count()) - exp.getFloat(name + ".one-minute").Set(float64(m.Rate1())) - exp.getFloat(name + ".five-minute").Set(float64(m.Rate5())) - exp.getFloat(name + ".fifteen-minute").Set(float64((m.Rate15()))) - exp.getFloat(name + ".mean").Set(float64(m.RateMean())) + exp.getFloat(name + ".one-minute").Set(m.Rate1()) + exp.getFloat(name + ".five-minute").Set(m.Rate5()) + exp.getFloat(name + ".fifteen-minute").Set((m.Rate15())) + exp.getFloat(name + ".mean").Set(m.RateMean()) } func (exp *exp) publishTimer(name string, metric metrics.Timer) { @@ -121,34 +121,47 @@ func (exp *exp) publishTimer(name string, metric metrics.Timer) { exp.getInt(name + ".count").Set(t.Count()) exp.getFloat(name + ".min").Set(float64(t.Min())) exp.getFloat(name + ".max").Set(float64(t.Max())) - exp.getFloat(name + ".mean").Set(float64(t.Mean())) - exp.getFloat(name + ".std-dev").Set(float64(t.StdDev())) - exp.getFloat(name + ".50-percentile").Set(float64(ps[0])) - exp.getFloat(name + ".75-percentile").Set(float64(ps[1])) - exp.getFloat(name + ".95-percentile").Set(float64(ps[2])) - exp.getFloat(name + ".99-percentile").Set(float64(ps[3])) - exp.getFloat(name + ".999-percentile").Set(float64(ps[4])) - exp.getFloat(name + ".one-minute").Set(float64(t.Rate1())) - exp.getFloat(name + ".five-minute").Set(float64(t.Rate5())) - exp.getFloat(name + ".fifteen-minute").Set(float64((t.Rate15()))) - exp.getFloat(name + ".mean-rate").Set(float64(t.RateMean())) + exp.getFloat(name + ".mean").Set(t.Mean()) + exp.getFloat(name + ".std-dev").Set(t.StdDev()) + exp.getFloat(name + ".50-percentile").Set(ps[0]) + exp.getFloat(name + ".75-percentile").Set(ps[1]) + exp.getFloat(name + ".95-percentile").Set(ps[2]) + exp.getFloat(name + ".99-percentile").Set(ps[3]) + exp.getFloat(name + ".999-percentile").Set(ps[4]) + exp.getFloat(name + ".one-minute").Set(t.Rate1()) + exp.getFloat(name + ".five-minute").Set(t.Rate5()) + exp.getFloat(name + ".fifteen-minute").Set(t.Rate15()) + exp.getFloat(name + ".mean-rate").Set(t.RateMean()) +} + +func (exp *exp) publishResettingTimer(name string, metric metrics.ResettingTimer) { + t := metric.Snapshot() + ps := t.Percentiles([]float64{50, 75, 95, 99}) + exp.getInt(name + ".count").Set(int64(len(t.Values()))) + exp.getFloat(name + ".mean").Set(t.Mean()) + exp.getInt(name + ".50-percentile").Set(ps[0]) + exp.getInt(name + ".75-percentile").Set(ps[1]) + exp.getInt(name + ".95-percentile").Set(ps[2]) + exp.getInt(name + ".99-percentile").Set(ps[3]) } func (exp *exp) syncToExpvar() { exp.registry.Each(func(name string, i interface{}) { - switch i.(type) { + switch i := i.(type) { case metrics.Counter: - exp.publishCounter(name, i.(metrics.Counter)) + exp.publishCounter(name, i) case metrics.Gauge: - exp.publishGauge(name, i.(metrics.Gauge)) + exp.publishGauge(name, i) case metrics.GaugeFloat64: - exp.publishGaugeFloat64(name, i.(metrics.GaugeFloat64)) + exp.publishGaugeFloat64(name, i) case metrics.Histogram: - exp.publishHistogram(name, i.(metrics.Histogram)) + exp.publishHistogram(name, i) case metrics.Meter: - exp.publishMeter(name, i.(metrics.Meter)) + exp.publishMeter(name, i) case metrics.Timer: - exp.publishTimer(name, i.(metrics.Timer)) + exp.publishTimer(name, i) + case metrics.ResettingTimer: + exp.publishResettingTimer(name, i) default: panic(fmt.Sprintf("unsupported type for '%s': %T", name, i)) } diff --git a/vendor/github.com/rcrowley/go-metrics/gauge.go b/metrics/gauge.go similarity index 98% rename from vendor/github.com/rcrowley/go-metrics/gauge.go rename to metrics/gauge.go index cb57a93889..0fbfdb8603 100644 --- a/vendor/github.com/rcrowley/go-metrics/gauge.go +++ b/metrics/gauge.go @@ -20,7 +20,7 @@ func GetOrRegisterGauge(name string, r Registry) Gauge { // NewGauge constructs a new StandardGauge. func NewGauge() Gauge { - if UseNilMetrics { + if !Enabled { return NilGauge{} } return &StandardGauge{0} @@ -38,7 +38,7 @@ func NewRegisteredGauge(name string, r Registry) Gauge { // NewFunctionalGauge constructs a new FunctionalGauge. func NewFunctionalGauge(f func() int64) Gauge { - if UseNilMetrics { + if !Enabled { return NilGauge{} } return &FunctionalGauge{value: f} diff --git a/vendor/github.com/rcrowley/go-metrics/gauge_float64.go b/metrics/gauge_float64.go similarity index 98% rename from vendor/github.com/rcrowley/go-metrics/gauge_float64.go rename to metrics/gauge_float64.go index 6f93920b2c..66819c9577 100644 --- a/vendor/github.com/rcrowley/go-metrics/gauge_float64.go +++ b/metrics/gauge_float64.go @@ -20,7 +20,7 @@ func GetOrRegisterGaugeFloat64(name string, r Registry) GaugeFloat64 { // NewGaugeFloat64 constructs a new StandardGaugeFloat64. func NewGaugeFloat64() GaugeFloat64 { - if UseNilMetrics { + if !Enabled { return NilGaugeFloat64{} } return &StandardGaugeFloat64{ @@ -40,7 +40,7 @@ func NewRegisteredGaugeFloat64(name string, r Registry) GaugeFloat64 { // NewFunctionalGauge constructs a new FunctionalGauge. func NewFunctionalGaugeFloat64(f func() float64) GaugeFloat64 { - if UseNilMetrics { + if !Enabled { return NilGaugeFloat64{} } return &FunctionalGaugeFloat64{value: f} diff --git a/metrics/gauge_float64_test.go b/metrics/gauge_float64_test.go new file mode 100644 index 0000000000..99e62a4030 --- /dev/null +++ b/metrics/gauge_float64_test.go @@ -0,0 +1,59 @@ +package metrics + +import "testing" + +func BenchmarkGuageFloat64(b *testing.B) { + g := NewGaugeFloat64() + b.ResetTimer() + for i := 0; i < b.N; i++ { + g.Update(float64(i)) + } +} + +func TestGaugeFloat64(t *testing.T) { + g := NewGaugeFloat64() + g.Update(float64(47.0)) + if v := g.Value(); float64(47.0) != v { + t.Errorf("g.Value(): 47.0 != %v\n", v) + } +} + +func TestGaugeFloat64Snapshot(t *testing.T) { + g := NewGaugeFloat64() + g.Update(float64(47.0)) + snapshot := g.Snapshot() + g.Update(float64(0)) + if v := snapshot.Value(); float64(47.0) != v { + t.Errorf("g.Value(): 47.0 != %v\n", v) + } +} + +func TestGetOrRegisterGaugeFloat64(t *testing.T) { + r := NewRegistry() + NewRegisteredGaugeFloat64("foo", r).Update(float64(47.0)) + t.Logf("registry: %v", r) + if g := GetOrRegisterGaugeFloat64("foo", r); float64(47.0) != g.Value() { + t.Fatal(g) + } +} + +func TestFunctionalGaugeFloat64(t *testing.T) { + var counter float64 + fg := NewFunctionalGaugeFloat64(func() float64 { + counter++ + return counter + }) + fg.Value() + fg.Value() + if counter != 2 { + t.Error("counter != 2") + } +} + +func TestGetOrRegisterFunctionalGaugeFloat64(t *testing.T) { + r := NewRegistry() + NewRegisteredFunctionalGaugeFloat64("foo", r, func() float64 { return 47 }) + if g := GetOrRegisterGaugeFloat64("foo", r); 47 != g.Value() { + t.Fatal(g) + } +} diff --git a/metrics/gauge_test.go b/metrics/gauge_test.go new file mode 100644 index 0000000000..1f2603d339 --- /dev/null +++ b/metrics/gauge_test.go @@ -0,0 +1,68 @@ +package metrics + +import ( + "fmt" + "testing" +) + +func BenchmarkGuage(b *testing.B) { + g := NewGauge() + b.ResetTimer() + for i := 0; i < b.N; i++ { + g.Update(int64(i)) + } +} + +func TestGauge(t *testing.T) { + g := NewGauge() + g.Update(int64(47)) + if v := g.Value(); 47 != v { + t.Errorf("g.Value(): 47 != %v\n", v) + } +} + +func TestGaugeSnapshot(t *testing.T) { + g := NewGauge() + g.Update(int64(47)) + snapshot := g.Snapshot() + g.Update(int64(0)) + if v := snapshot.Value(); 47 != v { + t.Errorf("g.Value(): 47 != %v\n", v) + } +} + +func TestGetOrRegisterGauge(t *testing.T) { + r := NewRegistry() + NewRegisteredGauge("foo", r).Update(47) + if g := GetOrRegisterGauge("foo", r); 47 != g.Value() { + t.Fatal(g) + } +} + +func TestFunctionalGauge(t *testing.T) { + var counter int64 + fg := NewFunctionalGauge(func() int64 { + counter++ + return counter + }) + fg.Value() + fg.Value() + if counter != 2 { + t.Error("counter != 2") + } +} + +func TestGetOrRegisterFunctionalGauge(t *testing.T) { + r := NewRegistry() + NewRegisteredFunctionalGauge("foo", r, func() int64 { return 47 }) + if g := GetOrRegisterGauge("foo", r); 47 != g.Value() { + t.Fatal(g) + } +} + +func ExampleGetOrRegisterGauge() { + m := "server.bytes_sent" + g := GetOrRegisterGauge(m, nil) + g.Update(47) + fmt.Println(g.Value()) // Output: 47 +} diff --git a/vendor/github.com/rcrowley/go-metrics/graphite.go b/metrics/graphite.go similarity index 99% rename from vendor/github.com/rcrowley/go-metrics/graphite.go rename to metrics/graphite.go index abd0a7d291..142eec86be 100644 --- a/vendor/github.com/rcrowley/go-metrics/graphite.go +++ b/metrics/graphite.go @@ -39,7 +39,7 @@ func Graphite(r Registry, d time.Duration, prefix string, addr *net.TCPAddr) { // but it takes a GraphiteConfig instead. func GraphiteWithConfig(c GraphiteConfig) { log.Printf("WARNING: This go-metrics client has been DEPRECATED! It has been moved to https://github.com/cyberdelia/go-metrics-graphite and will be removed from rcrowley/go-metrics on August 12th 2015") - for _ = range time.Tick(c.FlushInterval) { + for range time.Tick(c.FlushInterval) { if err := graphite(&c); nil != err { log.Println(err) } diff --git a/metrics/graphite_test.go b/metrics/graphite_test.go new file mode 100644 index 0000000000..c797c781df --- /dev/null +++ b/metrics/graphite_test.go @@ -0,0 +1,22 @@ +package metrics + +import ( + "net" + "time" +) + +func ExampleGraphite() { + addr, _ := net.ResolveTCPAddr("net", ":2003") + go Graphite(DefaultRegistry, 1*time.Second, "some.prefix", addr) +} + +func ExampleGraphiteWithConfig() { + addr, _ := net.ResolveTCPAddr("net", ":2003") + go GraphiteWithConfig(GraphiteConfig{ + Addr: addr, + Registry: DefaultRegistry, + FlushInterval: 1 * time.Second, + DurationUnit: time.Millisecond, + Percentiles: []float64{0.5, 0.75, 0.99, 0.999}, + }) +} diff --git a/vendor/github.com/rcrowley/go-metrics/healthcheck.go b/metrics/healthcheck.go similarity index 98% rename from vendor/github.com/rcrowley/go-metrics/healthcheck.go rename to metrics/healthcheck.go index 445131caee..f1ae31e34a 100644 --- a/vendor/github.com/rcrowley/go-metrics/healthcheck.go +++ b/metrics/healthcheck.go @@ -11,7 +11,7 @@ type Healthcheck interface { // NewHealthcheck constructs a new Healthcheck which will use the given // function to update its status. func NewHealthcheck(f func(Healthcheck)) Healthcheck { - if UseNilMetrics { + if !Enabled { return NilHealthcheck{} } return &StandardHealthcheck{nil, f} diff --git a/vendor/github.com/rcrowley/go-metrics/histogram.go b/metrics/histogram.go similarity index 99% rename from vendor/github.com/rcrowley/go-metrics/histogram.go rename to metrics/histogram.go index dbc837fe4d..46f3bbd2f1 100644 --- a/vendor/github.com/rcrowley/go-metrics/histogram.go +++ b/metrics/histogram.go @@ -28,7 +28,7 @@ func GetOrRegisterHistogram(name string, r Registry, s Sample) Histogram { // NewHistogram constructs a new StandardHistogram from a Sample. func NewHistogram(s Sample) Histogram { - if UseNilMetrics { + if !Enabled { return NilHistogram{} } return &StandardHistogram{sample: s} diff --git a/metrics/histogram_test.go b/metrics/histogram_test.go new file mode 100644 index 0000000000..d7f4f0171c --- /dev/null +++ b/metrics/histogram_test.go @@ -0,0 +1,95 @@ +package metrics + +import "testing" + +func BenchmarkHistogram(b *testing.B) { + h := NewHistogram(NewUniformSample(100)) + b.ResetTimer() + for i := 0; i < b.N; i++ { + h.Update(int64(i)) + } +} + +func TestGetOrRegisterHistogram(t *testing.T) { + r := NewRegistry() + s := NewUniformSample(100) + NewRegisteredHistogram("foo", r, s).Update(47) + if h := GetOrRegisterHistogram("foo", r, s); 1 != h.Count() { + t.Fatal(h) + } +} + +func TestHistogram10000(t *testing.T) { + h := NewHistogram(NewUniformSample(100000)) + for i := 1; i <= 10000; i++ { + h.Update(int64(i)) + } + testHistogram10000(t, h) +} + +func TestHistogramEmpty(t *testing.T) { + h := NewHistogram(NewUniformSample(100)) + if count := h.Count(); 0 != count { + t.Errorf("h.Count(): 0 != %v\n", count) + } + if min := h.Min(); 0 != min { + t.Errorf("h.Min(): 0 != %v\n", min) + } + if max := h.Max(); 0 != max { + t.Errorf("h.Max(): 0 != %v\n", max) + } + if mean := h.Mean(); 0.0 != mean { + t.Errorf("h.Mean(): 0.0 != %v\n", mean) + } + if stdDev := h.StdDev(); 0.0 != stdDev { + t.Errorf("h.StdDev(): 0.0 != %v\n", stdDev) + } + ps := h.Percentiles([]float64{0.5, 0.75, 0.99}) + if 0.0 != ps[0] { + t.Errorf("median: 0.0 != %v\n", ps[0]) + } + if 0.0 != ps[1] { + t.Errorf("75th percentile: 0.0 != %v\n", ps[1]) + } + if 0.0 != ps[2] { + t.Errorf("99th percentile: 0.0 != %v\n", ps[2]) + } +} + +func TestHistogramSnapshot(t *testing.T) { + h := NewHistogram(NewUniformSample(100000)) + for i := 1; i <= 10000; i++ { + h.Update(int64(i)) + } + snapshot := h.Snapshot() + h.Update(0) + testHistogram10000(t, snapshot) +} + +func testHistogram10000(t *testing.T, h Histogram) { + if count := h.Count(); 10000 != count { + t.Errorf("h.Count(): 10000 != %v\n", count) + } + if min := h.Min(); 1 != min { + t.Errorf("h.Min(): 1 != %v\n", min) + } + if max := h.Max(); 10000 != max { + t.Errorf("h.Max(): 10000 != %v\n", max) + } + if mean := h.Mean(); 5000.5 != mean { + t.Errorf("h.Mean(): 5000.5 != %v\n", mean) + } + if stdDev := h.StdDev(); 2886.751331514372 != stdDev { + t.Errorf("h.StdDev(): 2886.751331514372 != %v\n", stdDev) + } + ps := h.Percentiles([]float64{0.5, 0.75, 0.99}) + if 5000.5 != ps[0] { + t.Errorf("median: 5000.5 != %v\n", ps[0]) + } + if 7500.75 != ps[1] { + t.Errorf("75th percentile: 7500.75 != %v\n", ps[1]) + } + if 9900.99 != ps[2] { + t.Errorf("99th percentile: 9900.99 != %v\n", ps[2]) + } +} diff --git a/metrics/influxdb/LICENSE b/metrics/influxdb/LICENSE new file mode 100644 index 0000000000..e5bf20cdb5 --- /dev/null +++ b/metrics/influxdb/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2015 Vincent Rischmann + +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/metrics/influxdb/README.md b/metrics/influxdb/README.md new file mode 100644 index 0000000000..b76b1a3f99 --- /dev/null +++ b/metrics/influxdb/README.md @@ -0,0 +1,30 @@ +go-metrics-influxdb +=================== + +This is a reporter for the [go-metrics](https://github.com/rcrowley/go-metrics) library which will post the metrics to [InfluxDB](https://influxdb.com/). + +Note +---- + +This is only compatible with InfluxDB 0.9+. + +Usage +----- + +```go +import "github.com/vrischmann/go-metrics-influxdb" + +go influxdb.InfluxDB( + metrics.DefaultRegistry, // metrics registry + time.Second * 10, // interval + "http://localhost:8086", // the InfluxDB url + "mydb", // your InfluxDB database + "myuser", // your InfluxDB user + "mypassword", // your InfluxDB password +) +``` + +License +------- + +go-metrics-influxdb is licensed under the MIT license. See the LICENSE file for details. diff --git a/metrics/influxdb/influxdb.go b/metrics/influxdb/influxdb.go new file mode 100644 index 0000000000..c4ef927234 --- /dev/null +++ b/metrics/influxdb/influxdb.go @@ -0,0 +1,255 @@ +package influxdb + +import ( + "fmt" + uurl "net/url" + "time" + + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" + "github.com/influxdata/influxdb/client" +) + +type reporter struct { + reg metrics.Registry + interval time.Duration + + url uurl.URL + database string + username string + password string + namespace string + tags map[string]string + + client *client.Client + + cache map[string]int64 +} + +// InfluxDB starts a InfluxDB reporter which will post the from the given metrics.Registry at each d interval. +func InfluxDB(r metrics.Registry, d time.Duration, url, database, username, password, namespace string) { + InfluxDBWithTags(r, d, url, database, username, password, namespace, nil) +} + +// InfluxDBWithTags starts a InfluxDB reporter which will post the from the given metrics.Registry at each d interval with the specified tags +func InfluxDBWithTags(r metrics.Registry, d time.Duration, url, database, username, password, namespace string, tags map[string]string) { + u, err := uurl.Parse(url) + if err != nil { + log.Warn("Unable to parse InfluxDB", "url", url, "err", err) + return + } + + rep := &reporter{ + reg: r, + interval: d, + url: *u, + database: database, + username: username, + password: password, + namespace: namespace, + tags: tags, + cache: make(map[string]int64), + } + if err := rep.makeClient(); err != nil { + log.Warn("Unable to make InfluxDB client", "err", err) + return + } + + 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, + }) + + return +} + +func (r *reporter) run() { + intervalTicker := time.Tick(r.interval) + pingTicker := time.Tick(time.Second * 5) + + for { + select { + case <-intervalTicker: + if err := r.send(); err != nil { + log.Warn("Unable to send to InfluxDB", "err", err) + } + case <-pingTicker: + _, _, err := r.client.Ping() + if err != nil { + log.Warn("Got error while sending a ping to InfluxDB, trying to recreate client", "err", err) + + if err = r.makeClient(); err != nil { + log.Warn("Unable to make InfluxDB client", "err", err) + } + } + } + } +} + +func (r *reporter) send() error { + var pts []client.Point + + r.reg.Each(func(name string, i interface{}) { + now := time.Now() + namespace := r.namespace + + switch metric := i.(type) { + case metrics.Counter: + v := metric.Count() + l := r.cache[name] + pts = append(pts, client.Point{ + Measurement: fmt.Sprintf("%s%s.count", namespace, name), + Tags: r.tags, + Fields: map[string]interface{}{ + "value": v - l, + }, + Time: now, + }) + r.cache[name] = v + case metrics.Gauge: + ms := metric.Snapshot() + pts = append(pts, client.Point{ + Measurement: fmt.Sprintf("%s%s.gauge", namespace, name), + Tags: r.tags, + Fields: map[string]interface{}{ + "value": ms.Value(), + }, + Time: now, + }) + case metrics.GaugeFloat64: + ms := metric.Snapshot() + pts = append(pts, client.Point{ + Measurement: fmt.Sprintf("%s%s.gauge", namespace, name), + Tags: r.tags, + Fields: map[string]interface{}{ + "value": ms.Value(), + }, + Time: now, + }) + case metrics.Histogram: + ms := metric.Snapshot() + ps := ms.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999, 0.9999}) + pts = append(pts, client.Point{ + Measurement: fmt.Sprintf("%s%s.histogram", namespace, name), + Tags: r.tags, + Fields: map[string]interface{}{ + "count": ms.Count(), + "max": ms.Max(), + "mean": ms.Mean(), + "min": ms.Min(), + "stddev": ms.StdDev(), + "variance": ms.Variance(), + "p50": ps[0], + "p75": ps[1], + "p95": ps[2], + "p99": ps[3], + "p999": ps[4], + "p9999": ps[5], + }, + Time: now, + }) + case metrics.Meter: + ms := metric.Snapshot() + pts = append(pts, client.Point{ + Measurement: fmt.Sprintf("%s%s.meter", namespace, name), + Tags: r.tags, + Fields: map[string]interface{}{ + "count": ms.Count(), + "m1": ms.Rate1(), + "m5": ms.Rate5(), + "m15": ms.Rate15(), + "mean": ms.RateMean(), + }, + Time: now, + }) + case metrics.Timer: + ms := metric.Snapshot() + ps := ms.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999, 0.9999}) + pts = append(pts, client.Point{ + Measurement: fmt.Sprintf("%s%s.timer", namespace, name), + Tags: r.tags, + Fields: map[string]interface{}{ + "count": ms.Count(), + "max": ms.Max(), + "mean": ms.Mean(), + "min": ms.Min(), + "stddev": ms.StdDev(), + "variance": ms.Variance(), + "p50": ps[0], + "p75": ps[1], + "p95": ps[2], + "p99": ps[3], + "p999": ps[4], + "p9999": ps[5], + "m1": ms.Rate1(), + "m5": ms.Rate5(), + "m15": ms.Rate15(), + "meanrate": ms.RateMean(), + }, + Time: now, + }) + case metrics.ResettingTimer: + t := metric.Snapshot() + + if len(t.Values()) > 0 { + ps := t.Percentiles([]float64{50, 95, 99}) + val := t.Values() + pts = append(pts, client.Point{ + Measurement: fmt.Sprintf("%s%s.span", namespace, name), + Tags: r.tags, + Fields: map[string]interface{}{ + "count": len(val), + "max": val[len(val)-1], + "mean": t.Mean(), + "min": val[0], + "p50": ps[0], + "p95": ps[1], + "p99": ps[2], + }, + Time: now, + }) + } + } + }) + + bps := client.BatchPoints{ + Points: pts, + Database: r.database, + } + + _, err := r.client.Write(bps) + return err +} diff --git a/metrics/init_test.go b/metrics/init_test.go new file mode 100644 index 0000000000..43401e833c --- /dev/null +++ b/metrics/init_test.go @@ -0,0 +1,5 @@ +package metrics + +func init() { + Enabled = true +} diff --git a/metrics/json.go b/metrics/json.go new file mode 100644 index 0000000000..2087d8211e --- /dev/null +++ b/metrics/json.go @@ -0,0 +1,31 @@ +package metrics + +import ( + "encoding/json" + "io" + "time" +) + +// MarshalJSON returns a byte slice containing a JSON representation of all +// the metrics in the Registry. +func (r *StandardRegistry) MarshalJSON() ([]byte, error) { + return json.Marshal(r.GetAll()) +} + +// WriteJSON writes metrics from the given registry periodically to the +// specified io.Writer as JSON. +func WriteJSON(r Registry, d time.Duration, w io.Writer) { + for range time.Tick(d) { + WriteJSONOnce(r, w) + } +} + +// WriteJSONOnce writes metrics from the given registry to the specified +// io.Writer as JSON. +func WriteJSONOnce(r Registry, w io.Writer) { + json.NewEncoder(w).Encode(r) +} + +func (p *PrefixedRegistry) MarshalJSON() ([]byte, error) { + return json.Marshal(p.GetAll()) +} diff --git a/metrics/json_test.go b/metrics/json_test.go new file mode 100644 index 0000000000..cf70051f7a --- /dev/null +++ b/metrics/json_test.go @@ -0,0 +1,28 @@ +package metrics + +import ( + "bytes" + "encoding/json" + "testing" +) + +func TestRegistryMarshallJSON(t *testing.T) { + b := &bytes.Buffer{} + enc := json.NewEncoder(b) + r := NewRegistry() + r.Register("counter", NewCounter()) + enc.Encode(r) + if s := b.String(); "{\"counter\":{\"count\":0}}\n" != s { + t.Fatalf(s) + } +} + +func TestRegistryWriteJSONOnce(t *testing.T) { + r := NewRegistry() + r.Register("counter", NewCounter()) + b := &bytes.Buffer{} + WriteJSONOnce(r, b) + if s := b.String(); s != "{\"counter\":{\"count\":0}}\n" { + t.Fail() + } +} diff --git a/metrics/librato/client.go b/metrics/librato/client.go new file mode 100644 index 0000000000..1f8920cb1a --- /dev/null +++ b/metrics/librato/client.go @@ -0,0 +1,102 @@ +package librato + +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" +) + +const Operations = "operations" +const OperationsShort = "ops" + +type LibratoClient struct { + Email, Token string +} + +// property strings +const ( + // display attributes + Color = "color" + DisplayMax = "display_max" + DisplayMin = "display_min" + DisplayUnitsLong = "display_units_long" + DisplayUnitsShort = "display_units_short" + DisplayStacked = "display_stacked" + DisplayTransform = "display_transform" + // special gauge display attributes + SummarizeFunction = "summarize_function" + Aggregate = "aggregate" + + // metric keys + Name = "name" + Period = "period" + Description = "description" + DisplayName = "display_name" + Attributes = "attributes" + + // measurement keys + MeasureTime = "measure_time" + Source = "source" + Value = "value" + + // special gauge keys + Count = "count" + Sum = "sum" + Max = "max" + Min = "min" + SumSquares = "sum_squares" + + // batch keys + Counters = "counters" + Gauges = "gauges" + + MetricsPostUrl = "https://metrics-api.librato.com/v1/metrics" +) + +type Measurement map[string]interface{} +type Metric map[string]interface{} + +type Batch struct { + Gauges []Measurement `json:"gauges,omitempty"` + Counters []Measurement `json:"counters,omitempty"` + MeasureTime int64 `json:"measure_time"` + Source string `json:"source"` +} + +func (c *LibratoClient) PostMetrics(batch Batch) (err error) { + var ( + js []byte + req *http.Request + resp *http.Response + ) + + if len(batch.Counters) == 0 && len(batch.Gauges) == 0 { + return nil + } + + if js, err = json.Marshal(batch); err != nil { + return + } + + if req, err = http.NewRequest("POST", MetricsPostUrl, bytes.NewBuffer(js)); err != nil { + return + } + + req.Header.Set("Content-Type", "application/json") + req.SetBasicAuth(c.Email, c.Token) + + if resp, err = http.DefaultClient.Do(req); err != nil { + return + } + + if resp.StatusCode != http.StatusOK { + var body []byte + if body, err = ioutil.ReadAll(resp.Body); err != nil { + body = []byte(fmt.Sprintf("(could not fetch response body for error: %s)", err)) + } + err = fmt.Errorf("Unable to post to Librato: %d %s %s", resp.StatusCode, resp.Status, string(body)) + } + return +} diff --git a/metrics/librato/librato.go b/metrics/librato/librato.go new file mode 100644 index 0000000000..2138e01ae8 --- /dev/null +++ b/metrics/librato/librato.go @@ -0,0 +1,235 @@ +package librato + +import ( + "fmt" + "log" + "math" + "regexp" + "time" + + "github.com/ethereum/go-ethereum/metrics" +) + +// a regexp for extracting the unit from time.Duration.String +var unitRegexp = regexp.MustCompile(`[^\\d]+$`) + +// a helper that turns a time.Duration into librato display attributes for timer metrics +func translateTimerAttributes(d time.Duration) (attrs map[string]interface{}) { + attrs = make(map[string]interface{}) + attrs[DisplayTransform] = fmt.Sprintf("x/%d", int64(d)) + attrs[DisplayUnitsShort] = string(unitRegexp.Find([]byte(d.String()))) + return +} + +type Reporter struct { + Email, Token string + Namespace string + Source string + Interval time.Duration + Registry metrics.Registry + Percentiles []float64 // percentiles to report on histogram metrics + TimerAttributes map[string]interface{} // units in which timers will be displayed + intervalSec int64 +} + +func NewReporter(r metrics.Registry, d time.Duration, e string, t string, s string, p []float64, u time.Duration) *Reporter { + return &Reporter{e, t, "", s, d, r, p, translateTimerAttributes(u), int64(d / time.Second)} +} + +func Librato(r metrics.Registry, d time.Duration, e string, t string, s string, p []float64, u time.Duration) { + NewReporter(r, d, e, t, s, p, u).Run() +} + +func (rep *Reporter) Run() { + log.Printf("WARNING: This client has been DEPRECATED! It has been moved to https://github.com/mihasya/go-metrics-librato and will be removed from rcrowley/go-metrics on August 5th 2015") + ticker := time.Tick(rep.Interval) + metricsApi := &LibratoClient{rep.Email, rep.Token} + for now := range ticker { + var metrics Batch + var err error + if metrics, err = rep.BuildRequest(now, rep.Registry); err != nil { + log.Printf("ERROR constructing librato request body %s", err) + continue + } + if err := metricsApi.PostMetrics(metrics); err != nil { + log.Printf("ERROR sending metrics to librato %s", err) + continue + } + } +} + +// calculate sum of squares from data provided by metrics.Histogram +// see http://en.wikipedia.org/wiki/Standard_deviation#Rapid_calculation_methods +func sumSquares(s metrics.Sample) float64 { + count := float64(s.Count()) + sumSquared := math.Pow(count*s.Mean(), 2) + sumSquares := math.Pow(count*s.StdDev(), 2) + sumSquared/count + if math.IsNaN(sumSquares) { + return 0.0 + } + return sumSquares +} +func sumSquaresTimer(t metrics.Timer) float64 { + count := float64(t.Count()) + sumSquared := math.Pow(count*t.Mean(), 2) + sumSquares := math.Pow(count*t.StdDev(), 2) + sumSquared/count + if math.IsNaN(sumSquares) { + return 0.0 + } + return sumSquares +} + +func (rep *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot Batch, err error) { + snapshot = Batch{ + // coerce timestamps to a stepping fn so that they line up in Librato graphs + MeasureTime: (now.Unix() / rep.intervalSec) * rep.intervalSec, + Source: rep.Source, + } + snapshot.Gauges = make([]Measurement, 0) + snapshot.Counters = make([]Measurement, 0) + histogramGaugeCount := 1 + len(rep.Percentiles) + r.Each(func(name string, metric interface{}) { + if rep.Namespace != "" { + name = fmt.Sprintf("%s.%s", rep.Namespace, name) + } + measurement := Measurement{} + measurement[Period] = rep.Interval.Seconds() + switch m := metric.(type) { + case metrics.Counter: + if m.Count() > 0 { + measurement[Name] = fmt.Sprintf("%s.%s", name, "count") + measurement[Value] = float64(m.Count()) + measurement[Attributes] = map[string]interface{}{ + DisplayUnitsLong: Operations, + DisplayUnitsShort: OperationsShort, + DisplayMin: "0", + } + snapshot.Counters = append(snapshot.Counters, measurement) + } + case metrics.Gauge: + measurement[Name] = name + measurement[Value] = float64(m.Value()) + snapshot.Gauges = append(snapshot.Gauges, measurement) + case metrics.GaugeFloat64: + measurement[Name] = name + measurement[Value] = m.Value() + snapshot.Gauges = append(snapshot.Gauges, measurement) + case metrics.Histogram: + if m.Count() > 0 { + gauges := make([]Measurement, histogramGaugeCount) + s := m.Sample() + measurement[Name] = fmt.Sprintf("%s.%s", name, "hist") + measurement[Count] = uint64(s.Count()) + measurement[Max] = float64(s.Max()) + measurement[Min] = float64(s.Min()) + measurement[Sum] = float64(s.Sum()) + measurement[SumSquares] = sumSquares(s) + gauges[0] = measurement + for i, p := range rep.Percentiles { + gauges[i+1] = Measurement{ + Name: fmt.Sprintf("%s.%.2f", measurement[Name], p), + Value: s.Percentile(p), + Period: measurement[Period], + } + } + snapshot.Gauges = append(snapshot.Gauges, gauges...) + } + case metrics.Meter: + measurement[Name] = name + measurement[Value] = float64(m.Count()) + snapshot.Counters = append(snapshot.Counters, measurement) + snapshot.Gauges = append(snapshot.Gauges, + Measurement{ + Name: fmt.Sprintf("%s.%s", name, "1min"), + Value: m.Rate1(), + Period: int64(rep.Interval.Seconds()), + Attributes: map[string]interface{}{ + DisplayUnitsLong: Operations, + DisplayUnitsShort: OperationsShort, + DisplayMin: "0", + }, + }, + Measurement{ + Name: fmt.Sprintf("%s.%s", name, "5min"), + Value: m.Rate5(), + Period: int64(rep.Interval.Seconds()), + Attributes: map[string]interface{}{ + DisplayUnitsLong: Operations, + DisplayUnitsShort: OperationsShort, + DisplayMin: "0", + }, + }, + Measurement{ + Name: fmt.Sprintf("%s.%s", name, "15min"), + Value: m.Rate15(), + Period: int64(rep.Interval.Seconds()), + Attributes: map[string]interface{}{ + DisplayUnitsLong: Operations, + DisplayUnitsShort: OperationsShort, + DisplayMin: "0", + }, + }, + ) + case metrics.Timer: + measurement[Name] = name + measurement[Value] = float64(m.Count()) + snapshot.Counters = append(snapshot.Counters, measurement) + if m.Count() > 0 { + libratoName := fmt.Sprintf("%s.%s", name, "timer.mean") + gauges := make([]Measurement, histogramGaugeCount) + gauges[0] = Measurement{ + Name: libratoName, + Count: uint64(m.Count()), + Sum: m.Mean() * float64(m.Count()), + Max: float64(m.Max()), + Min: float64(m.Min()), + SumSquares: sumSquaresTimer(m), + Period: int64(rep.Interval.Seconds()), + Attributes: rep.TimerAttributes, + } + for i, p := range rep.Percentiles { + gauges[i+1] = Measurement{ + Name: fmt.Sprintf("%s.timer.%2.0f", name, p*100), + Value: m.Percentile(p), + Period: int64(rep.Interval.Seconds()), + Attributes: rep.TimerAttributes, + } + } + snapshot.Gauges = append(snapshot.Gauges, gauges...) + snapshot.Gauges = append(snapshot.Gauges, + Measurement{ + Name: fmt.Sprintf("%s.%s", name, "rate.1min"), + Value: m.Rate1(), + Period: int64(rep.Interval.Seconds()), + Attributes: map[string]interface{}{ + DisplayUnitsLong: Operations, + DisplayUnitsShort: OperationsShort, + DisplayMin: "0", + }, + }, + Measurement{ + Name: fmt.Sprintf("%s.%s", name, "rate.5min"), + Value: m.Rate5(), + Period: int64(rep.Interval.Seconds()), + Attributes: map[string]interface{}{ + DisplayUnitsLong: Operations, + DisplayUnitsShort: OperationsShort, + DisplayMin: "0", + }, + }, + Measurement{ + Name: fmt.Sprintf("%s.%s", name, "rate.15min"), + Value: m.Rate15(), + Period: int64(rep.Interval.Seconds()), + Attributes: map[string]interface{}{ + DisplayUnitsLong: Operations, + DisplayUnitsShort: OperationsShort, + DisplayMin: "0", + }, + }, + ) + } + } + }) + return +} diff --git a/vendor/github.com/rcrowley/go-metrics/log.go b/metrics/log.go similarity index 98% rename from vendor/github.com/rcrowley/go-metrics/log.go rename to metrics/log.go index f8074c0457..0c8ea7c971 100644 --- a/vendor/github.com/rcrowley/go-metrics/log.go +++ b/metrics/log.go @@ -18,7 +18,7 @@ func LogScaled(r Registry, freq time.Duration, scale time.Duration, l Logger) { du := float64(scale) duSuffix := scale.String()[1:] - for _ = range time.Tick(freq) { + for range time.Tick(freq) { r.Each(func(name string, i interface{}) { switch metric := i.(type) { case Counter: diff --git a/vendor/github.com/rcrowley/go-metrics/memory.md b/metrics/memory.md similarity index 100% rename from vendor/github.com/rcrowley/go-metrics/memory.md rename to metrics/memory.md diff --git a/vendor/github.com/rcrowley/go-metrics/meter.go b/metrics/meter.go similarity index 66% rename from vendor/github.com/rcrowley/go-metrics/meter.go rename to metrics/meter.go index 0389ab0b8f..58d170fae0 100644 --- a/vendor/github.com/rcrowley/go-metrics/meter.go +++ b/metrics/meter.go @@ -15,10 +15,13 @@ type Meter interface { Rate15() float64 RateMean() float64 Snapshot() Meter + Stop() } // GetOrRegisterMeter returns an existing Meter or constructs and registers a // new StandardMeter. +// Be sure to unregister the meter from the registry once it is of no use to +// allow for garbage collection. func GetOrRegisterMeter(name string, r Registry) Meter { if nil == r { r = DefaultRegistry @@ -26,15 +29,27 @@ func GetOrRegisterMeter(name string, r Registry) Meter { return r.GetOrRegister(name, NewMeter).(Meter) } +// GetOrRegisterMeterForced returns an existing Meter or constructs and registers a +// new StandardMeter no matter the global switch is enabled or not. +// Be sure to unregister the meter from the registry once it is of no use to +// allow for garbage collection. +func GetOrRegisterMeterForced(name string, r Registry) Meter { + if nil == r { + r = DefaultRegistry + } + return r.GetOrRegister(name, NewMeterForced).(Meter) +} + // NewMeter constructs a new StandardMeter and launches a goroutine. +// Be sure to call Stop() once the meter is of no use to allow for garbage collection. func NewMeter() Meter { - if UseNilMetrics { + if !Enabled { return NilMeter{} } m := newStandardMeter() arbiter.Lock() defer arbiter.Unlock() - arbiter.meters = append(arbiter.meters, m) + arbiter.meters[m] = struct{}{} if !arbiter.started { arbiter.started = true go arbiter.tick() @@ -42,8 +57,25 @@ func NewMeter() Meter { return m } -// NewMeter constructs and registers a new StandardMeter and launches a -// goroutine. +// NewMeterForced constructs a new StandardMeter and launches a goroutine no matter +// the global switch is enabled or not. +// Be sure to call Stop() once the meter is of no use to allow for garbage collection. +func NewMeterForced() Meter { + m := newStandardMeter() + arbiter.Lock() + defer arbiter.Unlock() + arbiter.meters[m] = struct{}{} + if !arbiter.started { + arbiter.started = true + go arbiter.tick() + } + return m +} + +// NewRegisteredMeter constructs and registers a new StandardMeter +// and launches a goroutine. +// Be sure to unregister the meter from the registry once it is of no use to +// allow for garbage collection. func NewRegisteredMeter(name string, r Registry) Meter { c := NewMeter() if nil == r { @@ -53,6 +85,19 @@ func NewRegisteredMeter(name string, r Registry) Meter { return c } +// NewRegisteredMeterForced constructs and registers a new StandardMeter +// and launches a goroutine no matter the global switch is enabled or not. +// Be sure to unregister the meter from the registry once it is of no use to +// allow for garbage collection. +func NewRegisteredMeterForced(name string, r Registry) Meter { + c := NewMeterForced() + if nil == r { + r = DefaultRegistry + } + r.Register(name, c) + return c +} + // MeterSnapshot is a read-only copy of another Meter. type MeterSnapshot struct { count int64 @@ -86,6 +131,9 @@ func (m *MeterSnapshot) RateMean() float64 { return m.rateMean } // Snapshot returns the snapshot. func (m *MeterSnapshot) Snapshot() Meter { return m } +// Stop is a no-op. +func (m *MeterSnapshot) Stop() {} + // NilMeter is a no-op Meter. type NilMeter struct{} @@ -110,12 +158,16 @@ func (NilMeter) RateMean() float64 { return 0.0 } // Snapshot is a no-op. func (NilMeter) Snapshot() Meter { return NilMeter{} } +// Stop is a no-op. +func (NilMeter) Stop() {} + // StandardMeter is the standard implementation of a Meter. type StandardMeter struct { lock sync.RWMutex snapshot *MeterSnapshot a1, a5, a15 EWMA startTime time.Time + stopped bool } func newStandardMeter() *StandardMeter { @@ -128,6 +180,19 @@ func newStandardMeter() *StandardMeter { } } +// Stop stops the meter, Mark() will be a no-op if you use it after being stopped. +func (m *StandardMeter) Stop() { + m.lock.Lock() + stopped := m.stopped + m.stopped = true + m.lock.Unlock() + if !stopped { + arbiter.Lock() + delete(arbiter.meters, m) + arbiter.Unlock() + } +} + // Count returns the number of events recorded. func (m *StandardMeter) Count() int64 { m.lock.RLock() @@ -136,10 +201,13 @@ func (m *StandardMeter) Count() int64 { return count } -// Mark records the occurance of n events. +// Mark records the occurrence of n events. func (m *StandardMeter) Mark(n int64) { m.lock.Lock() defer m.lock.Unlock() + if m.stopped { + return + } m.snapshot.count += n m.a1.Update(n) m.a5.Update(n) @@ -205,29 +273,28 @@ func (m *StandardMeter) tick() { m.updateSnapshot() } +// meterArbiter ticks meters every 5s from a single goroutine. +// meters are references in a set for future stopping. type meterArbiter struct { sync.RWMutex started bool - meters []*StandardMeter + meters map[*StandardMeter]struct{} ticker *time.Ticker } -var arbiter = meterArbiter{ticker: time.NewTicker(5e9)} +var arbiter = meterArbiter{ticker: time.NewTicker(5e9), meters: make(map[*StandardMeter]struct{})} // Ticks meters on the scheduled interval func (ma *meterArbiter) tick() { - for { - select { - case <-ma.ticker.C: - ma.tickMeters() - } + for range ma.ticker.C { + ma.tickMeters() } } func (ma *meterArbiter) tickMeters() { ma.RLock() defer ma.RUnlock() - for _, meter := range ma.meters { + for meter := range ma.meters { meter.tick() } } diff --git a/metrics/meter_test.go b/metrics/meter_test.go new file mode 100644 index 0000000000..e889222601 --- /dev/null +++ b/metrics/meter_test.go @@ -0,0 +1,73 @@ +package metrics + +import ( + "testing" + "time" +) + +func BenchmarkMeter(b *testing.B) { + m := NewMeter() + b.ResetTimer() + for i := 0; i < b.N; i++ { + m.Mark(1) + } +} + +func TestGetOrRegisterMeter(t *testing.T) { + r := NewRegistry() + NewRegisteredMeter("foo", r).Mark(47) + if m := GetOrRegisterMeter("foo", r); 47 != m.Count() { + t.Fatal(m) + } +} + +func TestMeterDecay(t *testing.T) { + ma := meterArbiter{ + ticker: time.NewTicker(time.Millisecond), + meters: make(map[*StandardMeter]struct{}), + } + m := newStandardMeter() + ma.meters[m] = struct{}{} + go ma.tick() + m.Mark(1) + rateMean := m.RateMean() + time.Sleep(100 * time.Millisecond) + if m.RateMean() >= rateMean { + t.Error("m.RateMean() didn't decrease") + } +} + +func TestMeterNonzero(t *testing.T) { + m := NewMeter() + m.Mark(3) + if count := m.Count(); 3 != count { + t.Errorf("m.Count(): 3 != %v\n", count) + } +} + +func TestMeterStop(t *testing.T) { + l := len(arbiter.meters) + m := NewMeter() + if len(arbiter.meters) != l+1 { + t.Errorf("arbiter.meters: %d != %d\n", l+1, len(arbiter.meters)) + } + m.Stop() + if len(arbiter.meters) != l { + t.Errorf("arbiter.meters: %d != %d\n", l, len(arbiter.meters)) + } +} + +func TestMeterSnapshot(t *testing.T) { + m := NewMeter() + m.Mark(1) + if snapshot := m.Snapshot(); m.RateMean() != snapshot.RateMean() { + t.Fatal(snapshot) + } +} + +func TestMeterZero(t *testing.T) { + m := NewMeter() + if count := m.Count(); 0 != count { + t.Errorf("m.Count(): 0 != %v\n", count) + } +} diff --git a/metrics/metrics.go b/metrics/metrics.go index c82661d802..5910fb0734 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -1,20 +1,8 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. +// Go port of Coda Hale's Metrics 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 metrics provides general system and process level metrics collection. +// Coda Hale's original work: package metrics import ( @@ -24,17 +12,19 @@ import ( "time" "github.com/ethereum/go-ethereum/log" - "github.com/rcrowley/go-metrics" - "github.com/rcrowley/go-metrics/exp" ) +// Enabled is checked by the constructor functions for all of the +// 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 = false + // MetricsEnabledFlag is the CLI flag name to use to enable metrics collections. const MetricsEnabledFlag = "metrics" const DashboardEnabledFlag = "dashboard" -// Enabled is the flag specifying if metrics are enable or not. -var Enabled = false - // 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. @@ -45,34 +35,6 @@ func init() { Enabled = true } } - exp.Exp(metrics.DefaultRegistry) -} - -// NewCounter create a new metrics Counter, either a real one of a NOP stub depending -// on the metrics flag. -func NewCounter(name string) metrics.Counter { - if !Enabled { - return new(metrics.NilCounter) - } - return metrics.GetOrRegisterCounter(name, metrics.DefaultRegistry) -} - -// NewMeter create a new metrics Meter, either a real one of a NOP stub depending -// on the metrics flag. -func NewMeter(name string) metrics.Meter { - if !Enabled { - return new(metrics.NilMeter) - } - return metrics.GetOrRegisterMeter(name, metrics.DefaultRegistry) -} - -// NewTimer create a new metrics Timer, either a real one of a NOP stub depending -// on the metrics flag. -func NewTimer(name string) metrics.Timer { - if !Enabled { - return new(metrics.NilTimer) - } - return metrics.GetOrRegisterTimer(name, metrics.DefaultRegistry) } // CollectProcessMetrics periodically collects various metrics about the running @@ -90,33 +52,42 @@ func CollectProcessMetrics(refresh time.Duration) { diskstats[i] = new(DiskStats) } // Define the various metrics to collect - memAllocs := metrics.GetOrRegisterMeter("system/memory/allocs", metrics.DefaultRegistry) - memFrees := metrics.GetOrRegisterMeter("system/memory/frees", metrics.DefaultRegistry) - memInuse := metrics.GetOrRegisterMeter("system/memory/inuse", metrics.DefaultRegistry) - memPauses := metrics.GetOrRegisterMeter("system/memory/pauses", metrics.DefaultRegistry) + memAllocs := GetOrRegisterMeter("system/memory/allocs", DefaultRegistry) + memFrees := GetOrRegisterMeter("system/memory/frees", DefaultRegistry) + memInuse := GetOrRegisterMeter("system/memory/inuse", DefaultRegistry) + memPauses := GetOrRegisterMeter("system/memory/pauses", DefaultRegistry) - var diskReads, diskReadBytes, diskWrites, diskWriteBytes metrics.Meter + var diskReads, diskReadBytes, diskWrites, diskWriteBytes Meter + var diskReadBytesCounter, diskWriteBytesCounter Counter if err := ReadDiskStats(diskstats[0]); err == nil { - diskReads = metrics.GetOrRegisterMeter("system/disk/readcount", metrics.DefaultRegistry) - diskReadBytes = metrics.GetOrRegisterMeter("system/disk/readdata", metrics.DefaultRegistry) - diskWrites = metrics.GetOrRegisterMeter("system/disk/writecount", metrics.DefaultRegistry) - diskWriteBytes = metrics.GetOrRegisterMeter("system/disk/writedata", metrics.DefaultRegistry) + diskReads = GetOrRegisterMeter("system/disk/readcount", DefaultRegistry) + diskReadBytes = GetOrRegisterMeter("system/disk/readdata", DefaultRegistry) + diskReadBytesCounter = GetOrRegisterCounter("system/disk/readbytes", DefaultRegistry) + diskWrites = GetOrRegisterMeter("system/disk/writecount", DefaultRegistry) + diskWriteBytes = GetOrRegisterMeter("system/disk/writedata", DefaultRegistry) + diskWriteBytesCounter = GetOrRegisterCounter("system/disk/writebytes", DefaultRegistry) } else { log.Debug("Failed to read disk metrics", "err", err) } // Iterate loading the different stats and updating the meters for i := 1; ; i++ { - runtime.ReadMemStats(memstats[i%2]) - memAllocs.Mark(int64(memstats[i%2].Mallocs - memstats[(i-1)%2].Mallocs)) - memFrees.Mark(int64(memstats[i%2].Frees - memstats[(i-1)%2].Frees)) - memInuse.Mark(int64(memstats[i%2].Alloc - memstats[(i-1)%2].Alloc)) - memPauses.Mark(int64(memstats[i%2].PauseTotalNs - memstats[(i-1)%2].PauseTotalNs)) + location1 := i % 2 + location2 := (i - 1) % 2 - if ReadDiskStats(diskstats[i%2]) == nil { - diskReads.Mark(diskstats[i%2].ReadCount - diskstats[(i-1)%2].ReadCount) - diskReadBytes.Mark(diskstats[i%2].ReadBytes - diskstats[(i-1)%2].ReadBytes) - diskWrites.Mark(diskstats[i%2].WriteCount - diskstats[(i-1)%2].WriteCount) - diskWriteBytes.Mark(diskstats[i%2].WriteBytes - diskstats[(i-1)%2].WriteBytes) + runtime.ReadMemStats(memstats[location1]) + memAllocs.Mark(int64(memstats[location1].Mallocs - memstats[location2].Mallocs)) + memFrees.Mark(int64(memstats[location1].Frees - memstats[location2].Frees)) + memInuse.Mark(int64(memstats[location1].Alloc - memstats[location2].Alloc)) + memPauses.Mark(int64(memstats[location1].PauseTotalNs - memstats[location2].PauseTotalNs)) + + if ReadDiskStats(diskstats[location1]) == nil { + diskReads.Mark(diskstats[location1].ReadCount - diskstats[location2].ReadCount) + diskReadBytes.Mark(diskstats[location1].ReadBytes - diskstats[location2].ReadBytes) + diskWrites.Mark(diskstats[location1].WriteCount - diskstats[location2].WriteCount) + diskWriteBytes.Mark(diskstats[location1].WriteBytes - diskstats[location2].WriteBytes) + + diskReadBytesCounter.Inc(diskstats[location1].ReadBytes - diskstats[location2].ReadBytes) + diskWriteBytesCounter.Inc(diskstats[location1].WriteBytes - diskstats[location2].WriteBytes) } time.Sleep(refresh) } diff --git a/metrics/metrics_test.go b/metrics/metrics_test.go new file mode 100644 index 0000000000..df36da0ade --- /dev/null +++ b/metrics/metrics_test.go @@ -0,0 +1,125 @@ +package metrics + +import ( + "fmt" + "io/ioutil" + "log" + "sync" + "testing" + "time" +) + +const FANOUT = 128 + +// Stop the compiler from complaining during debugging. +var ( + _ = ioutil.Discard + _ = log.LstdFlags +) + +func BenchmarkMetrics(b *testing.B) { + r := NewRegistry() + c := NewRegisteredCounter("counter", r) + g := NewRegisteredGauge("gauge", r) + gf := NewRegisteredGaugeFloat64("gaugefloat64", r) + h := NewRegisteredHistogram("histogram", r, NewUniformSample(100)) + m := NewRegisteredMeter("meter", r) + t := NewRegisteredTimer("timer", r) + RegisterDebugGCStats(r) + RegisterRuntimeMemStats(r) + b.ResetTimer() + ch := make(chan bool) + + wgD := &sync.WaitGroup{} + /* + wgD.Add(1) + go func() { + defer wgD.Done() + //log.Println("go CaptureDebugGCStats") + for { + select { + case <-ch: + //log.Println("done CaptureDebugGCStats") + return + default: + CaptureDebugGCStatsOnce(r) + } + } + }() + //*/ + + wgR := &sync.WaitGroup{} + //* + wgR.Add(1) + go func() { + defer wgR.Done() + //log.Println("go CaptureRuntimeMemStats") + for { + select { + case <-ch: + //log.Println("done CaptureRuntimeMemStats") + return + default: + CaptureRuntimeMemStatsOnce(r) + } + } + }() + //*/ + + wgW := &sync.WaitGroup{} + /* + wgW.Add(1) + go func() { + defer wgW.Done() + //log.Println("go Write") + for { + select { + case <-ch: + //log.Println("done Write") + return + default: + WriteOnce(r, ioutil.Discard) + } + } + }() + //*/ + + wg := &sync.WaitGroup{} + wg.Add(FANOUT) + for i := 0; i < FANOUT; i++ { + go func(i int) { + defer wg.Done() + //log.Println("go", i) + for i := 0; i < b.N; i++ { + c.Inc(1) + g.Update(int64(i)) + gf.Update(float64(i)) + h.Update(int64(i)) + m.Mark(1) + t.Update(1) + } + //log.Println("done", i) + }(i) + } + wg.Wait() + close(ch) + wgD.Wait() + wgR.Wait() + wgW.Wait() +} + +func Example() { + c := NewCounter() + Register("money", c) + c.Inc(17) + + // Threadsafe registration + t := GetOrRegisterTimer("db.get.latency", nil) + t.Time(func() { time.Sleep(10 * time.Millisecond) }) + t.Update(1) + + fmt.Println(c.Count()) + fmt.Println(t.Min()) + // Output: 17 + // 1 +} diff --git a/vendor/github.com/rcrowley/go-metrics/opentsdb.go b/metrics/opentsdb.go similarity index 98% rename from vendor/github.com/rcrowley/go-metrics/opentsdb.go rename to metrics/opentsdb.go index 266b6c93d2..3fde55454b 100644 --- a/vendor/github.com/rcrowley/go-metrics/opentsdb.go +++ b/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 @@ -38,7 +38,7 @@ func OpenTSDB(r Registry, d time.Duration, prefix string, addr *net.TCPAddr) { // OpenTSDBWithConfig is a blocking exporter function just like OpenTSDB, // but it takes a OpenTSDBConfig instead. func OpenTSDBWithConfig(c OpenTSDBConfig) { - for _ = range time.Tick(c.FlushInterval) { + for range time.Tick(c.FlushInterval) { if err := openTSDB(&c); nil != err { log.Println(err) } diff --git a/metrics/opentsdb_test.go b/metrics/opentsdb_test.go new file mode 100644 index 0000000000..c43728960e --- /dev/null +++ b/metrics/opentsdb_test.go @@ -0,0 +1,21 @@ +package metrics + +import ( + "net" + "time" +) + +func ExampleOpenTSDB() { + addr, _ := net.ResolveTCPAddr("net", ":2003") + go OpenTSDB(DefaultRegistry, 1*time.Second, "some.prefix", addr) +} + +func ExampleOpenTSDBWithConfig() { + addr, _ := net.ResolveTCPAddr("net", ":2003") + go OpenTSDBWithConfig(OpenTSDBConfig{ + Addr: addr, + Registry: DefaultRegistry, + FlushInterval: 1 * time.Second, + DurationUnit: time.Millisecond, + }) +} diff --git a/vendor/github.com/rcrowley/go-metrics/registry.go b/metrics/registry.go similarity index 75% rename from vendor/github.com/rcrowley/go-metrics/registry.go rename to metrics/registry.go index 2bb7a1e7d0..c5435adf24 100644 --- a/vendor/github.com/rcrowley/go-metrics/registry.go +++ b/metrics/registry.go @@ -29,6 +29,9 @@ type Registry interface { // Get the metric by the given name or nil if none is registered. Get(string) interface{} + // GetAll metrics in the Registry. + GetAll() map[string]map[string]interface{} + // Gets an existing metric or registers the given one. // The interface can be the metric to register if not found in registry, // or a function returning the metric for lazy instantiation. @@ -109,10 +112,72 @@ func (r *StandardRegistry) RunHealthchecks() { } } +// GetAll metrics in the Registry +func (r *StandardRegistry) GetAll() map[string]map[string]interface{} { + data := make(map[string]map[string]interface{}) + r.Each(func(name string, i interface{}) { + values := make(map[string]interface{}) + switch metric := i.(type) { + case Counter: + values["count"] = metric.Count() + case Gauge: + values["value"] = metric.Value() + case GaugeFloat64: + values["value"] = metric.Value() + case Healthcheck: + values["error"] = nil + metric.Check() + if err := metric.Error(); nil != err { + values["error"] = metric.Error().Error() + } + case Histogram: + h := metric.Snapshot() + ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) + values["count"] = h.Count() + values["min"] = h.Min() + values["max"] = h.Max() + values["mean"] = h.Mean() + values["stddev"] = h.StdDev() + values["median"] = ps[0] + values["75%"] = ps[1] + values["95%"] = ps[2] + values["99%"] = ps[3] + values["99.9%"] = ps[4] + case Meter: + m := metric.Snapshot() + values["count"] = m.Count() + values["1m.rate"] = m.Rate1() + values["5m.rate"] = m.Rate5() + values["15m.rate"] = m.Rate15() + values["mean.rate"] = m.RateMean() + case Timer: + t := metric.Snapshot() + ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) + values["count"] = t.Count() + values["min"] = t.Min() + values["max"] = t.Max() + values["mean"] = t.Mean() + values["stddev"] = t.StdDev() + values["median"] = ps[0] + values["75%"] = ps[1] + values["95%"] = ps[2] + values["99%"] = ps[3] + values["99.9%"] = ps[4] + values["1m.rate"] = t.Rate1() + values["5m.rate"] = t.Rate5() + values["15m.rate"] = t.Rate15() + values["mean.rate"] = t.RateMean() + } + data[name] = values + }) + return data +} + // Unregister the metric with the given name. func (r *StandardRegistry) Unregister(name string) { r.mutex.Lock() defer r.mutex.Unlock() + r.stop(name) delete(r.metrics, name) } @@ -120,7 +185,8 @@ func (r *StandardRegistry) Unregister(name string) { func (r *StandardRegistry) UnregisterAll() { r.mutex.Lock() defer r.mutex.Unlock() - for name, _ := range r.metrics { + for name := range r.metrics { + r.stop(name) delete(r.metrics, name) } } @@ -130,7 +196,7 @@ func (r *StandardRegistry) register(name string, i interface{}) error { return DuplicateMetric(name) } switch i.(type) { - case Counter, Gauge, GaugeFloat64, Healthcheck, Histogram, Meter, Timer: + case Counter, Gauge, GaugeFloat64, Healthcheck, Histogram, Meter, Timer, ResettingTimer: r.metrics[name] = i } return nil @@ -146,6 +212,19 @@ func (r *StandardRegistry) registered() map[string]interface{} { return metrics } +func (r *StandardRegistry) stop(name string) { + if i, ok := r.metrics[name]; ok { + if s, ok := i.(Stoppable); ok { + s.Stop() + } + } +} + +// Stoppable defines the metrics which has to be stopped. +type Stoppable interface { + Stop() +} + type PrefixedRegistry struct { underlying Registry prefix string @@ -216,6 +295,11 @@ func (r *PrefixedRegistry) RunHealthchecks() { r.underlying.RunHealthchecks() } +// GetAll metrics in the Registry +func (r *PrefixedRegistry) GetAll() map[string]map[string]interface{} { + return r.underlying.GetAll() +} + // Unregister the metric with the given name. The name will be prefixed. func (r *PrefixedRegistry) Unregister(name string) { realName := r.prefix + name @@ -227,7 +311,11 @@ func (r *PrefixedRegistry) UnregisterAll() { r.underlying.UnregisterAll() } -var DefaultRegistry Registry = NewRegistry() +var ( + DefaultRegistry = NewRegistry() + EphemeralRegistry = NewRegistry() + AccountingRegistry = NewRegistry() // registry used in swarm +) // Call the given function for each registered metric. func Each(f func(string, interface{})) { diff --git a/metrics/registry_test.go b/metrics/registry_test.go new file mode 100644 index 0000000000..a63e485fe9 --- /dev/null +++ b/metrics/registry_test.go @@ -0,0 +1,305 @@ +package metrics + +import ( + "testing" +) + +func BenchmarkRegistry(b *testing.B) { + r := NewRegistry() + r.Register("foo", NewCounter()) + b.ResetTimer() + for i := 0; i < b.N; i++ { + r.Each(func(string, interface{}) {}) + } +} + +func TestRegistry(t *testing.T) { + r := NewRegistry() + r.Register("foo", NewCounter()) + i := 0 + r.Each(func(name string, iface interface{}) { + i++ + if "foo" != name { + t.Fatal(name) + } + if _, ok := iface.(Counter); !ok { + t.Fatal(iface) + } + }) + if 1 != i { + t.Fatal(i) + } + r.Unregister("foo") + i = 0 + r.Each(func(string, interface{}) { i++ }) + if 0 != i { + t.Fatal(i) + } +} + +func TestRegistryDuplicate(t *testing.T) { + r := NewRegistry() + if err := r.Register("foo", NewCounter()); nil != err { + t.Fatal(err) + } + if err := r.Register("foo", NewGauge()); nil == err { + t.Fatal(err) + } + i := 0 + r.Each(func(name string, iface interface{}) { + i++ + if _, ok := iface.(Counter); !ok { + t.Fatal(iface) + } + }) + if 1 != i { + t.Fatal(i) + } +} + +func TestRegistryGet(t *testing.T) { + r := NewRegistry() + r.Register("foo", NewCounter()) + if count := r.Get("foo").(Counter).Count(); 0 != count { + t.Fatal(count) + } + r.Get("foo").(Counter).Inc(1) + if count := r.Get("foo").(Counter).Count(); 1 != count { + t.Fatal(count) + } +} + +func TestRegistryGetOrRegister(t *testing.T) { + r := NewRegistry() + + // First metric wins with GetOrRegister + _ = r.GetOrRegister("foo", NewCounter()) + m := r.GetOrRegister("foo", NewGauge()) + if _, ok := m.(Counter); !ok { + t.Fatal(m) + } + + i := 0 + r.Each(func(name string, iface interface{}) { + i++ + if name != "foo" { + t.Fatal(name) + } + if _, ok := iface.(Counter); !ok { + t.Fatal(iface) + } + }) + if i != 1 { + t.Fatal(i) + } +} + +func TestRegistryGetOrRegisterWithLazyInstantiation(t *testing.T) { + r := NewRegistry() + + // First metric wins with GetOrRegister + _ = r.GetOrRegister("foo", NewCounter) + m := r.GetOrRegister("foo", NewGauge) + if _, ok := m.(Counter); !ok { + t.Fatal(m) + } + + i := 0 + r.Each(func(name string, iface interface{}) { + i++ + if name != "foo" { + t.Fatal(name) + } + if _, ok := iface.(Counter); !ok { + t.Fatal(iface) + } + }) + if i != 1 { + t.Fatal(i) + } +} + +func TestRegistryUnregister(t *testing.T) { + l := len(arbiter.meters) + r := NewRegistry() + r.Register("foo", NewCounter()) + r.Register("bar", NewMeter()) + r.Register("baz", NewTimer()) + if len(arbiter.meters) != l+2 { + t.Errorf("arbiter.meters: %d != %d\n", l+2, len(arbiter.meters)) + } + r.Unregister("foo") + r.Unregister("bar") + r.Unregister("baz") + if len(arbiter.meters) != l { + t.Errorf("arbiter.meters: %d != %d\n", l+2, len(arbiter.meters)) + } +} + +func TestPrefixedChildRegistryGetOrRegister(t *testing.T) { + r := NewRegistry() + pr := NewPrefixedChildRegistry(r, "prefix.") + + _ = pr.GetOrRegister("foo", NewCounter()) + + i := 0 + r.Each(func(name string, m interface{}) { + i++ + if name != "prefix.foo" { + t.Fatal(name) + } + }) + if i != 1 { + t.Fatal(i) + } +} + +func TestPrefixedRegistryGetOrRegister(t *testing.T) { + r := NewPrefixedRegistry("prefix.") + + _ = r.GetOrRegister("foo", NewCounter()) + + i := 0 + r.Each(func(name string, m interface{}) { + i++ + if name != "prefix.foo" { + t.Fatal(name) + } + }) + if i != 1 { + t.Fatal(i) + } +} + +func TestPrefixedRegistryRegister(t *testing.T) { + r := NewPrefixedRegistry("prefix.") + err := r.Register("foo", NewCounter()) + c := NewCounter() + Register("bar", c) + if err != nil { + t.Fatal(err.Error()) + } + + i := 0 + r.Each(func(name string, m interface{}) { + i++ + if name != "prefix.foo" { + t.Fatal(name) + } + }) + if i != 1 { + t.Fatal(i) + } +} + +func TestPrefixedRegistryUnregister(t *testing.T) { + r := NewPrefixedRegistry("prefix.") + + _ = r.Register("foo", NewCounter()) + + i := 0 + r.Each(func(name string, m interface{}) { + i++ + if name != "prefix.foo" { + t.Fatal(name) + } + }) + if i != 1 { + t.Fatal(i) + } + + r.Unregister("foo") + + i = 0 + r.Each(func(name string, m interface{}) { + i++ + }) + + if i != 0 { + t.Fatal(i) + } +} + +func TestPrefixedRegistryGet(t *testing.T) { + pr := NewPrefixedRegistry("prefix.") + name := "foo" + pr.Register(name, NewCounter()) + + fooCounter := pr.Get(name) + if fooCounter == nil { + t.Fatal(name) + } +} + +func TestPrefixedChildRegistryGet(t *testing.T) { + r := NewRegistry() + pr := NewPrefixedChildRegistry(r, "prefix.") + name := "foo" + pr.Register(name, NewCounter()) + fooCounter := pr.Get(name) + if fooCounter == nil { + t.Fatal(name) + } +} + +func TestChildPrefixedRegistryRegister(t *testing.T) { + r := NewPrefixedChildRegistry(DefaultRegistry, "prefix.") + err := r.Register("foo", NewCounter()) + c := NewCounter() + Register("bar", c) + if err != nil { + t.Fatal(err.Error()) + } + + i := 0 + r.Each(func(name string, m interface{}) { + i++ + if name != "prefix.foo" { + t.Fatal(name) + } + }) + if i != 1 { + t.Fatal(i) + } +} + +func TestChildPrefixedRegistryOfChildRegister(t *testing.T) { + r := NewPrefixedChildRegistry(NewRegistry(), "prefix.") + r2 := NewPrefixedChildRegistry(r, "prefix2.") + err := r.Register("foo2", NewCounter()) + if err != nil { + t.Fatal(err.Error()) + } + err = r2.Register("baz", NewCounter()) + c := NewCounter() + Register("bars", c) + + i := 0 + r2.Each(func(name string, m interface{}) { + i++ + if name != "prefix.prefix2.baz" { + //t.Fatal(name) + } + }) + if i != 1 { + t.Fatal(i) + } +} + +func TestWalkRegistries(t *testing.T) { + r := NewPrefixedChildRegistry(NewRegistry(), "prefix.") + r2 := NewPrefixedChildRegistry(r, "prefix2.") + err := r.Register("foo2", NewCounter()) + if err != nil { + t.Fatal(err.Error()) + } + err = r2.Register("baz", NewCounter()) + c := NewCounter() + Register("bars", c) + + _, prefix := findPrefix(r2, "") + if "prefix.prefix2." != prefix { + t.Fatal(prefix) + } + +} diff --git a/metrics/resetting_timer.go b/metrics/resetting_timer.go new file mode 100644 index 0000000000..e5327d3bd3 --- /dev/null +++ b/metrics/resetting_timer.go @@ -0,0 +1,241 @@ +package metrics + +import ( + "math" + "sort" + "sync" + "time" +) + +// Initial slice capacity for the values stored in a ResettingTimer +const InitialResettingTimerSliceCap = 10 + +// ResettingTimer is used for storing aggregated values for timers, which are reset on every flush interval. +type ResettingTimer interface { + Values() []int64 + Snapshot() ResettingTimer + Percentiles([]float64) []int64 + Mean() float64 + Time(func()) + Update(time.Duration) + UpdateSince(time.Time) +} + +// GetOrRegisterResettingTimer returns an existing ResettingTimer or constructs and registers a +// new StandardResettingTimer. +func GetOrRegisterResettingTimer(name string, r Registry) ResettingTimer { + if nil == r { + r = DefaultRegistry + } + return r.GetOrRegister(name, NewResettingTimer).(ResettingTimer) +} + +// NewRegisteredResettingTimer constructs and registers a new StandardResettingTimer. +func NewRegisteredResettingTimer(name string, r Registry) ResettingTimer { + c := NewResettingTimer() + if nil == r { + r = DefaultRegistry + } + r.Register(name, c) + return c +} + +// NewResettingTimer constructs a new StandardResettingTimer +func NewResettingTimer() ResettingTimer { + if !Enabled { + return NilResettingTimer{} + } + return &StandardResettingTimer{ + values: make([]int64, 0, InitialResettingTimerSliceCap), + } +} + +// NilResettingTimer is a no-op ResettingTimer. +type NilResettingTimer struct { +} + +// Values is a no-op. +func (NilResettingTimer) Values() []int64 { return nil } + +// Snapshot is a no-op. +func (NilResettingTimer) Snapshot() ResettingTimer { + return &ResettingTimerSnapshot{ + values: []int64{}, + } +} + +// Time is a no-op. +func (NilResettingTimer) Time(func()) {} + +// Update is a no-op. +func (NilResettingTimer) Update(time.Duration) {} + +// Percentiles panics. +func (NilResettingTimer) Percentiles([]float64) []int64 { + panic("Percentiles called on a NilResettingTimer") +} + +// Mean panics. +func (NilResettingTimer) Mean() float64 { + panic("Mean called on a NilResettingTimer") +} + +// UpdateSince is a no-op. +func (NilResettingTimer) UpdateSince(time.Time) {} + +// StandardResettingTimer is the standard implementation of a ResettingTimer. +// and Meter. +type StandardResettingTimer struct { + values []int64 + mutex sync.Mutex +} + +// Values returns a slice with all measurements. +func (t *StandardResettingTimer) Values() []int64 { + return t.values +} + +// Snapshot resets the timer and returns a read-only copy of its contents. +func (t *StandardResettingTimer) Snapshot() ResettingTimer { + t.mutex.Lock() + defer t.mutex.Unlock() + currentValues := t.values + t.values = make([]int64, 0, InitialResettingTimerSliceCap) + + return &ResettingTimerSnapshot{ + values: currentValues, + } +} + +// Percentiles panics. +func (t *StandardResettingTimer) Percentiles([]float64) []int64 { + panic("Percentiles called on a StandardResettingTimer") +} + +// Mean panics. +func (t *StandardResettingTimer) Mean() float64 { + panic("Mean called on a StandardResettingTimer") +} + +// Record the duration of the execution of the given function. +func (t *StandardResettingTimer) Time(f func()) { + ts := time.Now() + f() + t.Update(time.Since(ts)) +} + +// Record the duration of an event. +func (t *StandardResettingTimer) Update(d time.Duration) { + t.mutex.Lock() + defer t.mutex.Unlock() + t.values = append(t.values, int64(d)) +} + +// Record the duration of an event that started at a time and ends now. +func (t *StandardResettingTimer) UpdateSince(ts time.Time) { + t.mutex.Lock() + defer t.mutex.Unlock() + t.values = append(t.values, int64(time.Since(ts))) +} + +// ResettingTimerSnapshot is a point-in-time copy of another ResettingTimer. +type ResettingTimerSnapshot struct { + values []int64 + mean float64 + thresholdBoundaries []int64 + calculated bool +} + +// Snapshot returns the snapshot. +func (t *ResettingTimerSnapshot) Snapshot() ResettingTimer { return t } + +// Time panics. +func (*ResettingTimerSnapshot) Time(func()) { + panic("Time called on a ResettingTimerSnapshot") +} + +// Update panics. +func (*ResettingTimerSnapshot) Update(time.Duration) { + panic("Update called on a ResettingTimerSnapshot") +} + +// UpdateSince panics. +func (*ResettingTimerSnapshot) UpdateSince(time.Time) { + panic("UpdateSince called on a ResettingTimerSnapshot") +} + +// Values returns all values from snapshot. +func (t *ResettingTimerSnapshot) Values() []int64 { + return t.values +} + +// Percentiles returns the boundaries for the input percentiles. +func (t *ResettingTimerSnapshot) Percentiles(percentiles []float64) []int64 { + t.calc(percentiles) + + return t.thresholdBoundaries +} + +// Mean returns the mean of the snapshotted values +func (t *ResettingTimerSnapshot) Mean() float64 { + if !t.calculated { + t.calc([]float64{}) + } + + return t.mean +} + +func (t *ResettingTimerSnapshot) calc(percentiles []float64) { + sort.Sort(Int64Slice(t.values)) + + count := len(t.values) + if count > 0 { + min := t.values[0] + max := t.values[count-1] + + cumulativeValues := make([]int64, count) + cumulativeValues[0] = min + for i := 1; i < count; i++ { + cumulativeValues[i] = t.values[i] + cumulativeValues[i-1] + } + + t.thresholdBoundaries = make([]int64, len(percentiles)) + + thresholdBoundary := max + + for i, pct := range percentiles { + if count > 1 { + var abs float64 + if pct >= 0 { + abs = pct + } else { + abs = 100 + pct + } + // poor man's math.Round(x): + // math.Floor(x + 0.5) + indexOfPerc := int(math.Floor(((abs / 100.0) * float64(count)) + 0.5)) + if pct >= 0 && indexOfPerc > 0 { + indexOfPerc -= 1 // index offset=0 + } + thresholdBoundary = t.values[indexOfPerc] + } + + t.thresholdBoundaries[i] = thresholdBoundary + } + + sum := cumulativeValues[count-1] + t.mean = float64(sum) / float64(count) + } else { + t.thresholdBoundaries = make([]int64, len(percentiles)) + t.mean = 0 + } + + t.calculated = true +} + +// Int64Slice attaches the methods of sort.Interface to []int64, sorting in increasing order. +type Int64Slice []int64 + +func (s Int64Slice) Len() int { return len(s) } +func (s Int64Slice) Less(i, j int) bool { return s[i] < s[j] } +func (s Int64Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } diff --git a/metrics/resetting_timer_test.go b/metrics/resetting_timer_test.go new file mode 100644 index 0000000000..77c49dc386 --- /dev/null +++ b/metrics/resetting_timer_test.go @@ -0,0 +1,216 @@ +package metrics + +import ( + "testing" + "time" +) + +func TestResettingTimer(t *testing.T) { + tests := []struct { + values []int64 + start int + end int + wantP50 int64 + wantP95 int64 + wantP99 int64 + wantMean float64 + wantMin int64 + wantMax int64 + }{ + { + values: []int64{}, + start: 1, + end: 11, + wantP50: 5, wantP95: 10, wantP99: 10, + wantMin: 1, wantMax: 10, wantMean: 5.5, + }, + { + values: []int64{}, + start: 1, + end: 101, + wantP50: 50, wantP95: 95, wantP99: 99, + wantMin: 1, wantMax: 100, wantMean: 50.5, + }, + { + values: []int64{1}, + start: 0, + end: 0, + wantP50: 1, wantP95: 1, wantP99: 1, + wantMin: 1, wantMax: 1, wantMean: 1, + }, + { + values: []int64{0}, + start: 0, + end: 0, + wantP50: 0, wantP95: 0, wantP99: 0, + wantMin: 0, wantMax: 0, wantMean: 0, + }, + { + values: []int64{}, + start: 0, + end: 0, + wantP50: 0, wantP95: 0, wantP99: 0, + wantMin: 0, wantMax: 0, wantMean: 0, + }, + { + values: []int64{1, 10}, + start: 0, + end: 0, + wantP50: 1, wantP95: 10, wantP99: 10, + wantMin: 1, wantMax: 10, wantMean: 5.5, + }, + } + for ind, tt := range tests { + timer := NewResettingTimer() + + for i := tt.start; i < tt.end; i++ { + tt.values = append(tt.values, int64(i)) + } + + for _, v := range tt.values { + timer.Update(time.Duration(v)) + } + + snap := timer.Snapshot() + + ps := snap.Percentiles([]float64{50, 95, 99}) + + val := snap.Values() + + if len(val) > 0 { + if tt.wantMin != val[0] { + t.Fatalf("%d: min: got %d, want %d", ind, val[0], tt.wantMin) + } + + if tt.wantMax != val[len(val)-1] { + t.Fatalf("%d: max: got %d, want %d", ind, val[len(val)-1], tt.wantMax) + } + } + + if tt.wantMean != snap.Mean() { + t.Fatalf("%d: mean: got %.2f, want %.2f", ind, snap.Mean(), tt.wantMean) + } + + if tt.wantP50 != ps[0] { + t.Fatalf("%d: p50: got %d, want %d", ind, ps[0], tt.wantP50) + } + + if tt.wantP95 != ps[1] { + t.Fatalf("%d: p95: got %d, want %d", ind, ps[1], tt.wantP95) + } + + if tt.wantP99 != ps[2] { + t.Fatalf("%d: p99: got %d, want %d", ind, ps[2], tt.wantP99) + } + } +} + +func TestResettingTimerWithFivePercentiles(t *testing.T) { + tests := []struct { + values []int64 + start int + end int + wantP05 int64 + wantP20 int64 + wantP50 int64 + wantP95 int64 + wantP99 int64 + wantMean float64 + wantMin int64 + wantMax int64 + }{ + { + values: []int64{}, + start: 1, + end: 11, + wantP05: 1, wantP20: 2, wantP50: 5, wantP95: 10, wantP99: 10, + wantMin: 1, wantMax: 10, wantMean: 5.5, + }, + { + values: []int64{}, + start: 1, + end: 101, + wantP05: 5, wantP20: 20, wantP50: 50, wantP95: 95, wantP99: 99, + wantMin: 1, wantMax: 100, wantMean: 50.5, + }, + { + values: []int64{1}, + start: 0, + end: 0, + wantP05: 1, wantP20: 1, wantP50: 1, wantP95: 1, wantP99: 1, + wantMin: 1, wantMax: 1, wantMean: 1, + }, + { + values: []int64{0}, + start: 0, + end: 0, + wantP05: 0, wantP20: 0, wantP50: 0, wantP95: 0, wantP99: 0, + wantMin: 0, wantMax: 0, wantMean: 0, + }, + { + values: []int64{}, + start: 0, + end: 0, + wantP05: 0, wantP20: 0, wantP50: 0, wantP95: 0, wantP99: 0, + wantMin: 0, wantMax: 0, wantMean: 0, + }, + { + values: []int64{1, 10}, + start: 0, + end: 0, + wantP05: 1, wantP20: 1, wantP50: 1, wantP95: 10, wantP99: 10, + wantMin: 1, wantMax: 10, wantMean: 5.5, + }, + } + for ind, tt := range tests { + timer := NewResettingTimer() + + for i := tt.start; i < tt.end; i++ { + tt.values = append(tt.values, int64(i)) + } + + for _, v := range tt.values { + timer.Update(time.Duration(v)) + } + + snap := timer.Snapshot() + + ps := snap.Percentiles([]float64{5, 20, 50, 95, 99}) + + val := snap.Values() + + if len(val) > 0 { + if tt.wantMin != val[0] { + t.Fatalf("%d: min: got %d, want %d", ind, val[0], tt.wantMin) + } + + if tt.wantMax != val[len(val)-1] { + t.Fatalf("%d: max: got %d, want %d", ind, val[len(val)-1], tt.wantMax) + } + } + + if tt.wantMean != snap.Mean() { + t.Fatalf("%d: mean: got %.2f, want %.2f", ind, snap.Mean(), tt.wantMean) + } + + if tt.wantP05 != ps[0] { + t.Fatalf("%d: p05: got %d, want %d", ind, ps[0], tt.wantP05) + } + + if tt.wantP20 != ps[1] { + t.Fatalf("%d: p20: got %d, want %d", ind, ps[1], tt.wantP20) + } + + if tt.wantP50 != ps[2] { + t.Fatalf("%d: p50: got %d, want %d", ind, ps[2], tt.wantP50) + } + + if tt.wantP95 != ps[3] { + t.Fatalf("%d: p95: got %d, want %d", ind, ps[3], tt.wantP95) + } + + if tt.wantP99 != ps[4] { + t.Fatalf("%d: p99: got %d, want %d", ind, ps[4], tt.wantP99) + } + } +} diff --git a/vendor/github.com/rcrowley/go-metrics/runtime.go b/metrics/runtime.go similarity index 99% rename from vendor/github.com/rcrowley/go-metrics/runtime.go rename to metrics/runtime.go index 11c6b785a0..9450c479ba 100644 --- a/vendor/github.com/rcrowley/go-metrics/runtime.go +++ b/metrics/runtime.go @@ -55,7 +55,7 @@ var ( // Capture new values for the Go runtime statistics exported in // runtime.MemStats. This is designed to be called as a goroutine. func CaptureRuntimeMemStats(r Registry, d time.Duration) { - for _ = range time.Tick(d) { + for range time.Tick(d) { CaptureRuntimeMemStatsOnce(r) } } diff --git a/vendor/github.com/rcrowley/go-metrics/runtime_cgo.go b/metrics/runtime_cgo.go similarity index 100% rename from vendor/github.com/rcrowley/go-metrics/runtime_cgo.go rename to metrics/runtime_cgo.go diff --git a/vendor/github.com/rcrowley/go-metrics/runtime_gccpufraction.go b/metrics/runtime_gccpufraction.go similarity index 100% rename from vendor/github.com/rcrowley/go-metrics/runtime_gccpufraction.go rename to metrics/runtime_gccpufraction.go diff --git a/vendor/github.com/rcrowley/go-metrics/runtime_no_cgo.go b/metrics/runtime_no_cgo.go similarity index 100% rename from vendor/github.com/rcrowley/go-metrics/runtime_no_cgo.go rename to metrics/runtime_no_cgo.go diff --git a/vendor/github.com/rcrowley/go-metrics/runtime_no_gccpufraction.go b/metrics/runtime_no_gccpufraction.go similarity index 100% rename from vendor/github.com/rcrowley/go-metrics/runtime_no_gccpufraction.go rename to metrics/runtime_no_gccpufraction.go diff --git a/metrics/runtime_test.go b/metrics/runtime_test.go new file mode 100644 index 0000000000..ebbfd501a2 --- /dev/null +++ b/metrics/runtime_test.go @@ -0,0 +1,88 @@ +package metrics + +import ( + "runtime" + "testing" + "time" +) + +func BenchmarkRuntimeMemStats(b *testing.B) { + r := NewRegistry() + RegisterRuntimeMemStats(r) + b.ResetTimer() + for i := 0; i < b.N; i++ { + CaptureRuntimeMemStatsOnce(r) + } +} + +func TestRuntimeMemStats(t *testing.T) { + r := NewRegistry() + RegisterRuntimeMemStats(r) + CaptureRuntimeMemStatsOnce(r) + zero := runtimeMetrics.MemStats.PauseNs.Count() // Get a "zero" since GC may have run before these tests. + runtime.GC() + CaptureRuntimeMemStatsOnce(r) + if count := runtimeMetrics.MemStats.PauseNs.Count(); 1 != count-zero { + t.Fatal(count - zero) + } + runtime.GC() + runtime.GC() + CaptureRuntimeMemStatsOnce(r) + if count := runtimeMetrics.MemStats.PauseNs.Count(); 3 != count-zero { + t.Fatal(count - zero) + } + for i := 0; i < 256; i++ { + runtime.GC() + } + CaptureRuntimeMemStatsOnce(r) + if count := runtimeMetrics.MemStats.PauseNs.Count(); 259 != count-zero { + t.Fatal(count - zero) + } + for i := 0; i < 257; i++ { + runtime.GC() + } + CaptureRuntimeMemStatsOnce(r) + if count := runtimeMetrics.MemStats.PauseNs.Count(); 515 != count-zero { // We lost one because there were too many GCs between captures. + t.Fatal(count - zero) + } +} + +func TestRuntimeMemStatsNumThread(t *testing.T) { + r := NewRegistry() + RegisterRuntimeMemStats(r) + CaptureRuntimeMemStatsOnce(r) + + if value := runtimeMetrics.NumThread.Value(); value < 1 { + t.Fatalf("got NumThread: %d, wanted at least 1", value) + } +} + +func TestRuntimeMemStatsBlocking(t *testing.T) { + if g := runtime.GOMAXPROCS(0); g < 2 { + t.Skipf("skipping TestRuntimeMemStatsBlocking with GOMAXPROCS=%d\n", g) + } + ch := make(chan int) + go testRuntimeMemStatsBlocking(ch) + var memStats runtime.MemStats + t0 := time.Now() + runtime.ReadMemStats(&memStats) + t1 := time.Now() + t.Log("i++ during runtime.ReadMemStats:", <-ch) + go testRuntimeMemStatsBlocking(ch) + d := t1.Sub(t0) + t.Log(d) + time.Sleep(d) + t.Log("i++ during time.Sleep:", <-ch) +} + +func testRuntimeMemStatsBlocking(ch chan int) { + i := 0 + for { + select { + case ch <- i: + return + default: + i++ + } + } +} diff --git a/vendor/github.com/rcrowley/go-metrics/sample.go b/metrics/sample.go similarity index 99% rename from vendor/github.com/rcrowley/go-metrics/sample.go rename to metrics/sample.go index fecee5ef68..5c4845a4f8 100644 --- a/vendor/github.com/rcrowley/go-metrics/sample.go +++ b/metrics/sample.go @@ -46,7 +46,7 @@ type ExpDecaySample struct { // NewExpDecaySample constructs a new exponentially-decaying sample with the // given reservoir size and alpha. func NewExpDecaySample(reservoirSize int, alpha float64) Sample { - if UseNilMetrics { + if !Enabled { return NilSample{} } s := &ExpDecaySample{ @@ -407,7 +407,7 @@ type UniformSample struct { // NewUniformSample constructs a new uniform sample with the given reservoir // size. func NewUniformSample(reservoirSize int) Sample { - if UseNilMetrics { + if !Enabled { return NilSample{} } return &UniformSample{ diff --git a/metrics/sample_test.go b/metrics/sample_test.go new file mode 100644 index 0000000000..d60e99c5bb --- /dev/null +++ b/metrics/sample_test.go @@ -0,0 +1,363 @@ +package metrics + +import ( + "math/rand" + "runtime" + "testing" + "time" +) + +// Benchmark{Compute,Copy}{1000,1000000} demonstrate that, even for relatively +// expensive computations like Variance, the cost of copying the Sample, as +// approximated by a make and copy, is much greater than the cost of the +// computation for small samples and only slightly less for large samples. +func BenchmarkCompute1000(b *testing.B) { + s := make([]int64, 1000) + for i := 0; i < len(s); i++ { + s[i] = int64(i) + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + SampleVariance(s) + } +} +func BenchmarkCompute1000000(b *testing.B) { + s := make([]int64, 1000000) + for i := 0; i < len(s); i++ { + s[i] = int64(i) + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + SampleVariance(s) + } +} +func BenchmarkCopy1000(b *testing.B) { + s := make([]int64, 1000) + for i := 0; i < len(s); i++ { + s[i] = int64(i) + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + sCopy := make([]int64, len(s)) + copy(sCopy, s) + } +} +func BenchmarkCopy1000000(b *testing.B) { + s := make([]int64, 1000000) + for i := 0; i < len(s); i++ { + s[i] = int64(i) + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + sCopy := make([]int64, len(s)) + copy(sCopy, s) + } +} + +func BenchmarkExpDecaySample257(b *testing.B) { + benchmarkSample(b, NewExpDecaySample(257, 0.015)) +} + +func BenchmarkExpDecaySample514(b *testing.B) { + benchmarkSample(b, NewExpDecaySample(514, 0.015)) +} + +func BenchmarkExpDecaySample1028(b *testing.B) { + benchmarkSample(b, NewExpDecaySample(1028, 0.015)) +} + +func BenchmarkUniformSample257(b *testing.B) { + benchmarkSample(b, NewUniformSample(257)) +} + +func BenchmarkUniformSample514(b *testing.B) { + benchmarkSample(b, NewUniformSample(514)) +} + +func BenchmarkUniformSample1028(b *testing.B) { + benchmarkSample(b, NewUniformSample(1028)) +} + +func TestExpDecaySample10(t *testing.T) { + rand.Seed(1) + s := NewExpDecaySample(100, 0.99) + for i := 0; i < 10; i++ { + s.Update(int64(i)) + } + if size := s.Count(); 10 != size { + t.Errorf("s.Count(): 10 != %v\n", size) + } + if size := s.Size(); 10 != size { + t.Errorf("s.Size(): 10 != %v\n", size) + } + if l := len(s.Values()); 10 != l { + t.Errorf("len(s.Values()): 10 != %v\n", l) + } + for _, v := range s.Values() { + if v > 10 || v < 0 { + t.Errorf("out of range [0, 10): %v\n", v) + } + } +} + +func TestExpDecaySample100(t *testing.T) { + rand.Seed(1) + s := NewExpDecaySample(1000, 0.01) + for i := 0; i < 100; i++ { + s.Update(int64(i)) + } + if size := s.Count(); 100 != size { + t.Errorf("s.Count(): 100 != %v\n", size) + } + if size := s.Size(); 100 != size { + t.Errorf("s.Size(): 100 != %v\n", size) + } + if l := len(s.Values()); 100 != l { + t.Errorf("len(s.Values()): 100 != %v\n", l) + } + for _, v := range s.Values() { + if v > 100 || v < 0 { + t.Errorf("out of range [0, 100): %v\n", v) + } + } +} + +func TestExpDecaySample1000(t *testing.T) { + rand.Seed(1) + s := NewExpDecaySample(100, 0.99) + for i := 0; i < 1000; i++ { + s.Update(int64(i)) + } + if size := s.Count(); 1000 != size { + t.Errorf("s.Count(): 1000 != %v\n", size) + } + if size := s.Size(); 100 != size { + t.Errorf("s.Size(): 100 != %v\n", size) + } + if l := len(s.Values()); 100 != l { + t.Errorf("len(s.Values()): 100 != %v\n", l) + } + for _, v := range s.Values() { + if v > 1000 || v < 0 { + t.Errorf("out of range [0, 1000): %v\n", v) + } + } +} + +// This test makes sure that the sample's priority is not amplified by using +// nanosecond duration since start rather than second duration since start. +// The priority becomes +Inf quickly after starting if this is done, +// effectively freezing the set of samples until a rescale step happens. +func TestExpDecaySampleNanosecondRegression(t *testing.T) { + rand.Seed(1) + s := NewExpDecaySample(100, 0.99) + for i := 0; i < 100; i++ { + s.Update(10) + } + time.Sleep(1 * time.Millisecond) + for i := 0; i < 100; i++ { + s.Update(20) + } + v := s.Values() + avg := float64(0) + for i := 0; i < len(v); i++ { + avg += float64(v[i]) + } + avg /= float64(len(v)) + if avg > 16 || avg < 14 { + t.Errorf("out of range [14, 16]: %v\n", avg) + } +} + +func TestExpDecaySampleRescale(t *testing.T) { + s := NewExpDecaySample(2, 0.001).(*ExpDecaySample) + s.update(time.Now(), 1) + s.update(time.Now().Add(time.Hour+time.Microsecond), 1) + for _, v := range s.values.Values() { + if v.k == 0.0 { + t.Fatal("v.k == 0.0") + } + } +} + +func TestExpDecaySampleSnapshot(t *testing.T) { + now := time.Now() + rand.Seed(1) + s := NewExpDecaySample(100, 0.99) + for i := 1; i <= 10000; i++ { + s.(*ExpDecaySample).update(now.Add(time.Duration(i)), int64(i)) + } + snapshot := s.Snapshot() + s.Update(1) + testExpDecaySampleStatistics(t, snapshot) +} + +func TestExpDecaySampleStatistics(t *testing.T) { + now := time.Now() + rand.Seed(1) + s := NewExpDecaySample(100, 0.99) + for i := 1; i <= 10000; i++ { + s.(*ExpDecaySample).update(now.Add(time.Duration(i)), int64(i)) + } + testExpDecaySampleStatistics(t, s) +} + +func TestUniformSample(t *testing.T) { + rand.Seed(1) + s := NewUniformSample(100) + for i := 0; i < 1000; i++ { + s.Update(int64(i)) + } + if size := s.Count(); 1000 != size { + t.Errorf("s.Count(): 1000 != %v\n", size) + } + if size := s.Size(); 100 != size { + t.Errorf("s.Size(): 100 != %v\n", size) + } + if l := len(s.Values()); 100 != l { + t.Errorf("len(s.Values()): 100 != %v\n", l) + } + for _, v := range s.Values() { + if v > 1000 || v < 0 { + t.Errorf("out of range [0, 100): %v\n", v) + } + } +} + +func TestUniformSampleIncludesTail(t *testing.T) { + rand.Seed(1) + s := NewUniformSample(100) + max := 100 + for i := 0; i < max; i++ { + s.Update(int64(i)) + } + v := s.Values() + sum := 0 + exp := (max - 1) * max / 2 + for i := 0; i < len(v); i++ { + sum += int(v[i]) + } + if exp != sum { + t.Errorf("sum: %v != %v\n", exp, sum) + } +} + +func TestUniformSampleSnapshot(t *testing.T) { + s := NewUniformSample(100) + for i := 1; i <= 10000; i++ { + s.Update(int64(i)) + } + snapshot := s.Snapshot() + s.Update(1) + testUniformSampleStatistics(t, snapshot) +} + +func TestUniformSampleStatistics(t *testing.T) { + rand.Seed(1) + s := NewUniformSample(100) + for i := 1; i <= 10000; i++ { + s.Update(int64(i)) + } + testUniformSampleStatistics(t, s) +} + +func benchmarkSample(b *testing.B, s Sample) { + var memStats runtime.MemStats + runtime.ReadMemStats(&memStats) + pauseTotalNs := memStats.PauseTotalNs + b.ResetTimer() + for i := 0; i < b.N; i++ { + s.Update(1) + } + b.StopTimer() + runtime.GC() + runtime.ReadMemStats(&memStats) + b.Logf("GC cost: %d ns/op", int(memStats.PauseTotalNs-pauseTotalNs)/b.N) +} + +func testExpDecaySampleStatistics(t *testing.T, s Sample) { + if count := s.Count(); 10000 != count { + t.Errorf("s.Count(): 10000 != %v\n", count) + } + if min := s.Min(); 107 != min { + t.Errorf("s.Min(): 107 != %v\n", min) + } + if max := s.Max(); 10000 != max { + t.Errorf("s.Max(): 10000 != %v\n", max) + } + if mean := s.Mean(); 4965.98 != mean { + t.Errorf("s.Mean(): 4965.98 != %v\n", mean) + } + if stdDev := s.StdDev(); 2959.825156930727 != stdDev { + t.Errorf("s.StdDev(): 2959.825156930727 != %v\n", stdDev) + } + ps := s.Percentiles([]float64{0.5, 0.75, 0.99}) + if 4615 != ps[0] { + t.Errorf("median: 4615 != %v\n", ps[0]) + } + if 7672 != ps[1] { + t.Errorf("75th percentile: 7672 != %v\n", ps[1]) + } + if 9998.99 != ps[2] { + t.Errorf("99th percentile: 9998.99 != %v\n", ps[2]) + } +} + +func testUniformSampleStatistics(t *testing.T, s Sample) { + if count := s.Count(); 10000 != count { + t.Errorf("s.Count(): 10000 != %v\n", count) + } + if min := s.Min(); 37 != min { + t.Errorf("s.Min(): 37 != %v\n", min) + } + if max := s.Max(); 9989 != max { + t.Errorf("s.Max(): 9989 != %v\n", max) + } + if mean := s.Mean(); 4748.14 != mean { + t.Errorf("s.Mean(): 4748.14 != %v\n", mean) + } + if stdDev := s.StdDev(); 2826.684117548333 != stdDev { + t.Errorf("s.StdDev(): 2826.684117548333 != %v\n", stdDev) + } + ps := s.Percentiles([]float64{0.5, 0.75, 0.99}) + if 4599 != ps[0] { + t.Errorf("median: 4599 != %v\n", ps[0]) + } + if 7380.5 != ps[1] { + t.Errorf("75th percentile: 7380.5 != %v\n", ps[1]) + } + if 9986.429999999998 != ps[2] { + t.Errorf("99th percentile: 9986.429999999998 != %v\n", ps[2]) + } +} + +// TestUniformSampleConcurrentUpdateCount would expose data race problems with +// concurrent Update and Count calls on Sample when test is called with -race +// argument +func TestUniformSampleConcurrentUpdateCount(t *testing.T) { + if testing.Short() { + t.Skip("skipping in short mode") + } + s := NewUniformSample(100) + for i := 0; i < 100; i++ { + s.Update(int64(i)) + } + quit := make(chan struct{}) + go func() { + t := time.NewTicker(10 * time.Millisecond) + for { + select { + case <-t.C: + s.Update(rand.Int63()) + case <-quit: + t.Stop() + return + } + } + }() + for i := 0; i < 1000; i++ { + s.Count() + time.Sleep(5 * time.Millisecond) + } + quit <- struct{}{} +} diff --git a/vendor/github.com/rcrowley/go-metrics/syslog.go b/metrics/syslog.go similarity index 98% rename from vendor/github.com/rcrowley/go-metrics/syslog.go rename to metrics/syslog.go index 693f190855..a0ed4b1b23 100644 --- a/vendor/github.com/rcrowley/go-metrics/syslog.go +++ b/metrics/syslog.go @@ -11,7 +11,7 @@ import ( // Output each metric in the given registry to syslog periodically using // the given syslogger. func Syslog(r Registry, d time.Duration, w *syslog.Writer) { - for _ = range time.Tick(d) { + for range time.Tick(d) { r.Each(func(name string, i interface{}) { switch metric := i.(type) { case Counter: diff --git a/vendor/github.com/rcrowley/go-metrics/timer.go b/metrics/timer.go similarity index 93% rename from vendor/github.com/rcrowley/go-metrics/timer.go rename to metrics/timer.go index 17db8f8d20..89e22208fd 100644 --- a/vendor/github.com/rcrowley/go-metrics/timer.go +++ b/metrics/timer.go @@ -19,6 +19,7 @@ type Timer interface { RateMean() float64 Snapshot() Timer StdDev() float64 + Stop() Sum() int64 Time(func()) Update(time.Duration) @@ -28,6 +29,8 @@ type Timer interface { // GetOrRegisterTimer returns an existing Timer or constructs and registers a // new StandardTimer. +// Be sure to unregister the meter from the registry once it is of no use to +// allow for garbage collection. func GetOrRegisterTimer(name string, r Registry) Timer { if nil == r { r = DefaultRegistry @@ -36,8 +39,9 @@ func GetOrRegisterTimer(name string, r Registry) Timer { } // NewCustomTimer constructs a new StandardTimer from a Histogram and a Meter. +// Be sure to call Stop() once the timer is of no use to allow for garbage collection. func NewCustomTimer(h Histogram, m Meter) Timer { - if UseNilMetrics { + if !Enabled { return NilTimer{} } return &StandardTimer{ @@ -47,6 +51,8 @@ func NewCustomTimer(h Histogram, m Meter) Timer { } // NewRegisteredTimer constructs and registers a new StandardTimer. +// Be sure to unregister the meter from the registry once it is of no use to +// allow for garbage collection. func NewRegisteredTimer(name string, r Registry) Timer { c := NewTimer() if nil == r { @@ -58,8 +64,9 @@ func NewRegisteredTimer(name string, r Registry) Timer { // NewTimer constructs a new StandardTimer using an exponentially-decaying // sample with the same reservoir size and alpha as UNIX load averages. +// Be sure to call Stop() once the timer is of no use to allow for garbage collection. func NewTimer() Timer { - if UseNilMetrics { + if !Enabled { return NilTimer{} } return &StandardTimer{ @@ -112,6 +119,9 @@ func (NilTimer) Snapshot() Timer { return NilTimer{} } // StdDev is a no-op. func (NilTimer) StdDev() float64 { return 0.0 } +// Stop is a no-op. +func (NilTimer) Stop() {} + // Sum is a no-op. func (NilTimer) Sum() int64 { return 0 } @@ -201,6 +211,11 @@ func (t *StandardTimer) StdDev() float64 { return t.histogram.StdDev() } +// Stop stops the meter. +func (t *StandardTimer) Stop() { + t.meter.Stop() +} + // Sum returns the sum in the sample. func (t *StandardTimer) Sum() int64 { return t.histogram.Sum() @@ -288,6 +303,9 @@ func (t *TimerSnapshot) Snapshot() Timer { return t } // was taken. func (t *TimerSnapshot) StdDev() float64 { return t.histogram.StdDev() } +// Stop is a no-op. +func (t *TimerSnapshot) Stop() {} + // Sum returns the sum at the time the snapshot was taken. func (t *TimerSnapshot) Sum() int64 { return t.histogram.Sum() } diff --git a/metrics/timer_test.go b/metrics/timer_test.go new file mode 100644 index 0000000000..8638a2270b --- /dev/null +++ b/metrics/timer_test.go @@ -0,0 +1,101 @@ +package metrics + +import ( + "fmt" + "math" + "testing" + "time" +) + +func BenchmarkTimer(b *testing.B) { + tm := NewTimer() + b.ResetTimer() + for i := 0; i < b.N; i++ { + tm.Update(1) + } +} + +func TestGetOrRegisterTimer(t *testing.T) { + r := NewRegistry() + NewRegisteredTimer("foo", r).Update(47) + if tm := GetOrRegisterTimer("foo", r); 1 != tm.Count() { + t.Fatal(tm) + } +} + +func TestTimerExtremes(t *testing.T) { + tm := NewTimer() + tm.Update(math.MaxInt64) + tm.Update(0) + if stdDev := tm.StdDev(); 4.611686018427388e+18 != stdDev { + t.Errorf("tm.StdDev(): 4.611686018427388e+18 != %v\n", stdDev) + } +} + +func TestTimerStop(t *testing.T) { + l := len(arbiter.meters) + tm := NewTimer() + if len(arbiter.meters) != l+1 { + t.Errorf("arbiter.meters: %d != %d\n", l+1, len(arbiter.meters)) + } + tm.Stop() + if len(arbiter.meters) != l { + t.Errorf("arbiter.meters: %d != %d\n", l, len(arbiter.meters)) + } +} + +func TestTimerFunc(t *testing.T) { + tm := NewTimer() + tm.Time(func() { time.Sleep(50e6) }) + if max := tm.Max(); 35e6 > max || max > 145e6 { + t.Errorf("tm.Max(): 35e6 > %v || %v > 145e6\n", max, max) + } +} + +func TestTimerZero(t *testing.T) { + tm := NewTimer() + if count := tm.Count(); 0 != count { + t.Errorf("tm.Count(): 0 != %v\n", count) + } + if min := tm.Min(); 0 != min { + t.Errorf("tm.Min(): 0 != %v\n", min) + } + if max := tm.Max(); 0 != max { + t.Errorf("tm.Max(): 0 != %v\n", max) + } + if mean := tm.Mean(); 0.0 != mean { + t.Errorf("tm.Mean(): 0.0 != %v\n", mean) + } + if stdDev := tm.StdDev(); 0.0 != stdDev { + t.Errorf("tm.StdDev(): 0.0 != %v\n", stdDev) + } + ps := tm.Percentiles([]float64{0.5, 0.75, 0.99}) + if 0.0 != ps[0] { + t.Errorf("median: 0.0 != %v\n", ps[0]) + } + if 0.0 != ps[1] { + t.Errorf("75th percentile: 0.0 != %v\n", ps[1]) + } + if 0.0 != ps[2] { + t.Errorf("99th percentile: 0.0 != %v\n", ps[2]) + } + if rate1 := tm.Rate1(); 0.0 != rate1 { + t.Errorf("tm.Rate1(): 0.0 != %v\n", rate1) + } + if rate5 := tm.Rate5(); 0.0 != rate5 { + t.Errorf("tm.Rate5(): 0.0 != %v\n", rate5) + } + if rate15 := tm.Rate15(); 0.0 != rate15 { + t.Errorf("tm.Rate15(): 0.0 != %v\n", rate15) + } + if rateMean := tm.RateMean(); 0.0 != rateMean { + t.Errorf("tm.RateMean(): 0.0 != %v\n", rateMean) + } +} + +func ExampleGetOrRegisterTimer() { + m := "account.create.latency" + t := GetOrRegisterTimer(m, nil) + t.Update(47) + fmt.Println(t.Max()) // Output: 47 +} diff --git a/vendor/github.com/rcrowley/go-metrics/validate.sh b/metrics/validate.sh similarity index 93% rename from vendor/github.com/rcrowley/go-metrics/validate.sh rename to metrics/validate.sh index f6499982e5..c4ae91e642 100755 --- a/vendor/github.com/rcrowley/go-metrics/validate.sh +++ b/metrics/validate.sh @@ -7,4 +7,4 @@ GOFMT_LINES=`gofmt -l . | wc -l | xargs` test $GOFMT_LINES -eq 0 || echo "gofmt needs to be run, ${GOFMT_LINES} files have issues" # run the tests for the root package -go test . +go test -race . diff --git a/vendor/github.com/rcrowley/go-metrics/writer.go b/metrics/writer.go similarity index 99% rename from vendor/github.com/rcrowley/go-metrics/writer.go rename to metrics/writer.go index 091e971d2e..88521a80d9 100644 --- a/vendor/github.com/rcrowley/go-metrics/writer.go +++ b/metrics/writer.go @@ -10,7 +10,7 @@ import ( // Write sorts writes each metric in the given registry periodically to the // given io.Writer. func Write(r Registry, d time.Duration, w io.Writer) { - for _ = range time.Tick(d) { + for range time.Tick(d) { WriteOnce(r, w) } } diff --git a/metrics/writer_test.go b/metrics/writer_test.go new file mode 100644 index 0000000000..1aacc28712 --- /dev/null +++ b/metrics/writer_test.go @@ -0,0 +1,22 @@ +package metrics + +import ( + "sort" + "testing" +) + +func TestMetricsSorting(t *testing.T) { + var namedMetrics = namedMetricSlice{ + {name: "zzz"}, + {name: "bbb"}, + {name: "fff"}, + {name: "ggg"}, + } + + sort.Sort(namedMetrics) + for i, name := range []string{"bbb", "fff", "ggg", "zzz"} { + if namedMetrics[i].name != name { + t.Fail() + } + } +} diff --git a/miner/agent.go b/miner/agent.go deleted file mode 100644 index e3cebbd2e2..0000000000 --- a/miner/agent.go +++ /dev/null @@ -1,119 +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 miner - -import ( - "sync" - - "sync/atomic" - - "github.com/ethereum/go-ethereum/consensus" - "github.com/ethereum/go-ethereum/log" -) - -type CpuAgent struct { - mu sync.Mutex - - workCh chan *Work - stop chan struct{} - quitCurrentOp chan struct{} - returnCh chan<- *Result - - chain consensus.ChainReader - engine consensus.Engine - - isMining int32 // isMining indicates whether the agent is currently mining -} - -func NewCpuAgent(chain consensus.ChainReader, engine consensus.Engine) *CpuAgent { - miner := &CpuAgent{ - chain: chain, - engine: engine, - stop: make(chan struct{}, 1), - workCh: make(chan *Work, 1), - } - return miner -} - -func (self *CpuAgent) Work() chan<- *Work { return self.workCh } -func (self *CpuAgent) SetReturnCh(ch chan<- *Result) { self.returnCh = ch } - -func (self *CpuAgent) Stop() { - if !atomic.CompareAndSwapInt32(&self.isMining, 1, 0) { - return // agent already stopped - } - self.stop <- struct{}{} -done: - // Empty work channel - for { - select { - case <-self.workCh: - default: - break done - } - } -} - -func (self *CpuAgent) Start() { - if !atomic.CompareAndSwapInt32(&self.isMining, 0, 1) { - return // agent already started - } - go self.update() -} - -func (self *CpuAgent) update() { -out: - for { - select { - case work := <-self.workCh: - self.mu.Lock() - if self.quitCurrentOp != nil { - close(self.quitCurrentOp) - } - self.quitCurrentOp = make(chan struct{}) - go self.mine(work, self.quitCurrentOp) - self.mu.Unlock() - case <-self.stop: - self.mu.Lock() - if self.quitCurrentOp != nil { - close(self.quitCurrentOp) - self.quitCurrentOp = nil - } - self.mu.Unlock() - break out - } - } -} - -func (self *CpuAgent) mine(work *Work, stop <-chan struct{}) { - if result, err := self.engine.Seal(self.chain, work.Block, stop); result != nil { - log.Info("Successfully sealed new block", "number", result.Number(), "hash", result.Hash()) - self.returnCh <- &Result{work, result} - } else { - if err != nil { - log.Warn("Block sealing failed", "err", err) - } - self.returnCh <- nil - } -} - -func (self *CpuAgent) GetHashRate() int64 { - if pow, ok := self.engine.(consensus.PoW); ok { - return int64(pow.Hashrate()) - } - return 0 -} diff --git a/miner/miner.go b/miner/miner.go index fec0a40f5a..5218c12107 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -20,15 +20,14 @@ package miner import ( "fmt" "sync/atomic" + "time" - "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "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/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/params" @@ -36,36 +35,32 @@ import ( // Backend wraps all methods required for mining. type Backend interface { - AccountManager() *accounts.Manager BlockChain() *core.BlockChain TxPool() *core.TxPool - ChainDb() ethdb.Database } // Miner creates blocks and searches for proof-of-work values. type Miner struct { - mux *event.TypeMux - - worker *worker - + mux *event.TypeMux + worker *worker coinbase common.Address - mining int32 eth Backend engine consensus.Engine + exitCh chan struct{} canStart int32 // can start indicates whether we can start the mining operation shouldStart int32 // should start indicates whether we should start after sync } -func New(eth Backend, config *params.ChainConfig, mux *event.TypeMux, engine consensus.Engine) *Miner { +func New(eth Backend, config *params.ChainConfig, mux *event.TypeMux, engine consensus.Engine, recommit time.Duration, gasFloor, gasCeil uint64, isLocalBlock func(block *types.Block) bool) *Miner { miner := &Miner{ eth: eth, mux: mux, engine: engine, - worker: newWorker(config, engine, common.Address{}, eth, mux), + exitCh: make(chan struct{}), + worker: newWorker(config, engine, eth, mux, recommit, gasFloor, gasCeil, isLocalBlock), canStart: 1, } - miner.Register(NewCpuAgent(eth.BlockChain(), engine)) go miner.update() return miner @@ -77,82 +72,69 @@ func New(eth Backend, config *params.ChainConfig, mux *event.TypeMux, engine con // and halt your mining operation for as long as the DOS continues. func (self *Miner) update() { events := self.mux.Subscribe(downloader.StartEvent{}, downloader.DoneEvent{}, downloader.FailedEvent{}) -out: - for ev := range events.Chan() { - switch ev.Data.(type) { - case downloader.StartEvent: - atomic.StoreInt32(&self.canStart, 0) - if self.Mining() { - self.Stop() - atomic.StoreInt32(&self.shouldStart, 1) - log.Info("Mining aborted due to sync") - } - case downloader.DoneEvent, downloader.FailedEvent: - shouldStart := atomic.LoadInt32(&self.shouldStart) == 1 + defer events.Unsubscribe() - atomic.StoreInt32(&self.canStart, 1) - atomic.StoreInt32(&self.shouldStart, 0) - if shouldStart { - self.Start(self.coinbase) + for { + select { + case ev := <-events.Chan(): + if ev == nil { + return } - // unsubscribe. we're only interested in this event once - events.Unsubscribe() - // stop immediately and ignore all further pending events - break out + switch ev.Data.(type) { + case downloader.StartEvent: + atomic.StoreInt32(&self.canStart, 0) + if self.Mining() { + self.Stop() + atomic.StoreInt32(&self.shouldStart, 1) + log.Info("Mining aborted due to sync") + } + case downloader.DoneEvent, downloader.FailedEvent: + shouldStart := atomic.LoadInt32(&self.shouldStart) == 1 + + atomic.StoreInt32(&self.canStart, 1) + atomic.StoreInt32(&self.shouldStart, 0) + if shouldStart { + self.Start(self.coinbase) + } + // stop immediately and ignore all further pending events + return + } + case <-self.exitCh: + return } } } func (self *Miner) Start(coinbase common.Address) { atomic.StoreInt32(&self.shouldStart, 1) - self.worker.setEtherbase(coinbase) - self.coinbase = coinbase + self.SetEtherbase(coinbase) if atomic.LoadInt32(&self.canStart) == 0 { log.Info("Network syncing, will start miner afterwards") return } - atomic.StoreInt32(&self.mining, 1) - - log.Info("Starting mining operation") self.worker.start() - self.worker.commitNewWork() } func (self *Miner) Stop() { self.worker.stop() - atomic.StoreInt32(&self.mining, 0) atomic.StoreInt32(&self.shouldStart, 0) } -func (self *Miner) Register(agent Agent) { - if self.Mining() { - agent.Start() - } - self.worker.register(agent) -} - -func (self *Miner) Unregister(agent Agent) { - self.worker.unregister(agent) +func (self *Miner) Close() { + self.worker.close() + close(self.exitCh) } func (self *Miner) Mining() bool { - return atomic.LoadInt32(&self.mining) > 0 + return self.worker.isRunning() } -func (self *Miner) HashRate() (tot int64) { +func (self *Miner) HashRate() uint64 { if pow, ok := self.engine.(consensus.PoW); ok { - tot += int64(pow.Hashrate()) + return uint64(pow.Hashrate()) } - // do we care this might race? is it worth we're rewriting some - // aspects of the worker/locking up agents so we can get an accurate - // hashrate? - for agent := range self.worker.agents { - if _, ok := agent.(*CpuAgent); !ok { - tot += agent.GetHashRate() - } - } - return + return 0 } func (self *Miner) SetExtra(extra []byte) error { @@ -163,6 +145,11 @@ func (self *Miner) SetExtra(extra []byte) error { return nil } +// SetRecommitInterval sets the interval for sealing work resubmitting. +func (self *Miner) SetRecommitInterval(interval time.Duration) { + self.worker.setRecommitInterval(interval) +} + // Pending returns the currently pending block and associated state. func (self *Miner) Pending() (*types.Block, *state.StateDB) { return self.worker.pending() diff --git a/miner/remote_agent.go b/miner/remote_agent.go deleted file mode 100644 index 287e7530c3..0000000000 --- a/miner/remote_agent.go +++ /dev/null @@ -1,202 +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 miner - -import ( - "errors" - "math/big" - "sync" - "sync/atomic" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/consensus" - "github.com/ethereum/go-ethereum/consensus/ethash" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/log" -) - -type hashrate struct { - ping time.Time - rate uint64 -} - -type RemoteAgent struct { - mu sync.Mutex - - quitCh chan struct{} - workCh chan *Work - returnCh chan<- *Result - - chain consensus.ChainReader - engine consensus.Engine - currentWork *Work - work map[common.Hash]*Work - - hashrateMu sync.RWMutex - hashrate map[common.Hash]hashrate - - running int32 // running indicates whether the agent is active. Call atomically -} - -func NewRemoteAgent(chain consensus.ChainReader, engine consensus.Engine) *RemoteAgent { - return &RemoteAgent{ - chain: chain, - engine: engine, - work: make(map[common.Hash]*Work), - hashrate: make(map[common.Hash]hashrate), - } -} - -func (a *RemoteAgent) SubmitHashrate(id common.Hash, rate uint64) { - a.hashrateMu.Lock() - defer a.hashrateMu.Unlock() - - a.hashrate[id] = hashrate{time.Now(), rate} -} - -func (a *RemoteAgent) Work() chan<- *Work { - return a.workCh -} - -func (a *RemoteAgent) SetReturnCh(returnCh chan<- *Result) { - a.returnCh = returnCh -} - -func (a *RemoteAgent) Start() { - if !atomic.CompareAndSwapInt32(&a.running, 0, 1) { - return - } - a.quitCh = make(chan struct{}) - a.workCh = make(chan *Work, 1) - go a.loop(a.workCh, a.quitCh) -} - -func (a *RemoteAgent) Stop() { - if !atomic.CompareAndSwapInt32(&a.running, 1, 0) { - return - } - close(a.quitCh) - close(a.workCh) -} - -// GetHashRate returns the accumulated hashrate of all identifier combined -func (a *RemoteAgent) GetHashRate() (tot int64) { - a.hashrateMu.RLock() - defer a.hashrateMu.RUnlock() - - // this could overflow - for _, hashrate := range a.hashrate { - tot += int64(hashrate.rate) - } - return -} - -func (a *RemoteAgent) GetWork() ([3]string, error) { - a.mu.Lock() - defer a.mu.Unlock() - - var res [3]string - - if a.currentWork != nil { - block := a.currentWork.Block - - res[0] = block.HashNoNonce().Hex() - seedHash := ethash.SeedHash(block.NumberU64()) - res[1] = common.BytesToHash(seedHash).Hex() - // Calculate the "target" to be returned to the external miner - n := big.NewInt(1) - n.Lsh(n, 255) - n.Div(n, block.Difficulty()) - n.Lsh(n, 1) - res[2] = common.BytesToHash(n.Bytes()).Hex() - - a.work[block.HashNoNonce()] = a.currentWork - return res, nil - } - return res, errors.New("No work available yet, don't panic.") -} - -// SubmitWork tries to inject a pow solution into the remote agent, returning -// whether the solution was accepted or not (not can be both a bad pow as well as -// any other error, like no work pending). -func (a *RemoteAgent) SubmitWork(nonce types.BlockNonce, mixDigest, hash common.Hash) bool { - a.mu.Lock() - defer a.mu.Unlock() - - // Make sure the work submitted is present - work := a.work[hash] - if work == nil { - log.Info("Work submitted but none pending", "hash", hash) - return false - } - // Make sure the Engine solutions is indeed valid - result := work.Block.Header() - result.Nonce = nonce - result.MixDigest = mixDigest - - if err := a.engine.VerifySeal(a.chain, result); err != nil { - log.Warn("Invalid proof-of-work submitted", "hash", hash, "err", err) - return false - } - block := work.Block.WithSeal(result) - - // Solutions seems to be valid, return to the miner and notify acceptance - a.returnCh <- &Result{work, block} - delete(a.work, hash) - - return true -} - -// loop monitors mining events on the work and quit channels, updating the internal -// state of the remote miner until a termination is requested. -// -// Note, the reason the work and quit channels are passed as parameters is because -// RemoteAgent.Start() constantly recreates these channels, so the loop code cannot -// assume data stability in these member fields. -func (a *RemoteAgent) loop(workCh chan *Work, quitCh chan struct{}) { - ticker := time.NewTicker(5 * time.Second) - defer ticker.Stop() - - for { - select { - case <-quitCh: - return - case work := <-workCh: - a.mu.Lock() - a.currentWork = work - a.mu.Unlock() - case <-ticker.C: - // cleanup - a.mu.Lock() - for hash, work := range a.work { - if time.Since(work.createdAt) > 7*(12*time.Second) { - delete(a.work, hash) - } - } - a.mu.Unlock() - - a.hashrateMu.Lock() - for id, hashrate := range a.hashrate { - if time.Since(hashrate.ping) > 10*time.Second { - delete(a.hashrate, id) - } - } - a.hashrateMu.Unlock() - } - } -} diff --git a/miner/stress_clique.go b/miner/stress_clique.go new file mode 100644 index 0000000000..8a355a4dc4 --- /dev/null +++ b/miner/stress_clique.go @@ -0,0 +1,212 @@ +// 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 + +// This file contains a miner stress test based on the Clique consensus engine. +package main + +import ( + "bytes" + "crypto/ecdsa" + "io/ioutil" + "math/big" + "math/rand" + "os" + "time" + + "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/fdlimit" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/eth/downloader" + "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/params" +) + +func main() { + log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) + fdlimit.Raise(2048) + + // Generate a batch of accounts to seal and fund with + faucets := make([]*ecdsa.PrivateKey, 128) + for i := 0; i < len(faucets); i++ { + faucets[i], _ = crypto.GenerateKey() + } + sealers := make([]*ecdsa.PrivateKey, 4) + for i := 0; i < len(sealers); i++ { + sealers[i], _ = crypto.GenerateKey() + } + // Create a Clique network based off of the Rinkeby config + genesis := makeGenesis(faucets, sealers) + + var ( + nodes []*node.Node + enodes []*enode.Node + ) + for _, sealer := range sealers { + // Start the node and wait until it's up + node, err := makeSealer(genesis) + if err != nil { + panic(err) + } + defer node.Close() + + for node.Server().NodeInfo().Ports.Listener == 0 { + time.Sleep(250 * time.Millisecond) + } + // Connect the node to al the previous ones + for _, n := range enodes { + node.Server().AddPeer(n) + } + // Start tracking the node and it's enode + nodes = append(nodes, node) + enodes = append(enodes, node.Server().Self()) + + // Inject the signer key and start sealing with it + store := node.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) + signer, err := store.ImportECDSA(sealer, "") + if err != nil { + panic(err) + } + if err := store.Unlock(signer, ""); err != nil { + panic(err) + } + } + // Iterate over all the nodes and start signing with them + time.Sleep(3 * time.Second) + + for _, node := range nodes { + var ethereum *eth.Ethereum + if err := node.Service(ðereum); err != nil { + panic(err) + } + if err := ethereum.StartMining(1); err != nil { + panic(err) + } + } + time.Sleep(3 * time.Second) + + // Start injecting transactions from the faucet like crazy + nonces := make([]uint64, len(faucets)) + for { + index := rand.Intn(len(faucets)) + + // Fetch the accessor for the relevant signer + var ethereum *eth.Ethereum + if err := nodes[index%len(nodes)].Service(ðereum); err != nil { + panic(err) + } + // Create a self transaction and inject into the pool + tx, err := types.SignTx(types.NewTransaction(nonces[index], crypto.PubkeyToAddress(faucets[index].PublicKey), new(big.Int), 21000, big.NewInt(100000000000), nil), types.HomesteadSigner{}, faucets[index]) + if err != nil { + panic(err) + } + if err := ethereum.TxPool().AddLocal(tx); err != nil { + panic(err) + } + nonces[index]++ + + // Wait if we're too saturated + if pend, _ := ethereum.TxPool().Stats(); pend > 2048 { + time.Sleep(100 * time.Millisecond) + } + } +} + +// makeGenesis creates a custom Clique genesis block based on some pre-defined +// signer and faucet accounts. +func makeGenesis(faucets []*ecdsa.PrivateKey, sealers []*ecdsa.PrivateKey) *core.Genesis { + // Create a Clique network based off of the Rinkeby config + genesis := core.DefaultRinkebyGenesisBlock() + genesis.GasLimit = 25000000 + + genesis.Config.ChainID = big.NewInt(18) + genesis.Config.Clique.Period = 1 + genesis.Config.EIP150Hash = common.Hash{} + + genesis.Alloc = core.GenesisAlloc{} + for _, faucet := range faucets { + genesis.Alloc[crypto.PubkeyToAddress(faucet.PublicKey)] = core.GenesisAccount{ + Balance: new(big.Int).Exp(big.NewInt(2), big.NewInt(128), nil), + } + } + // Sort the signers and embed into the extra-data section + signers := make([]common.Address, len(sealers)) + for i, sealer := range sealers { + signers[i] = crypto.PubkeyToAddress(sealer.PublicKey) + } + for i := 0; i < len(signers); i++ { + for j := i + 1; j < len(signers); j++ { + if bytes.Compare(signers[i][:], signers[j][:]) > 0 { + signers[i], signers[j] = signers[j], signers[i] + } + } + } + genesis.ExtraData = make([]byte, 32+len(signers)*common.AddressLength+65) + for i, signer := range signers { + copy(genesis.ExtraData[32+i*common.AddressLength:], signer[:]) + } + // Return the genesis block for initialization + return genesis +} + +func makeSealer(genesis *core.Genesis) (*node.Node, error) { + // Define the basic configurations for the Ethereum node + datadir, _ := ioutil.TempDir("", "") + + config := &node.Config{ + Name: "geth", + Version: params.Version, + DataDir: datadir, + P2P: p2p.Config{ + ListenAddr: "0.0.0.0:0", + NoDiscovery: true, + MaxPeers: 25, + }, + NoUSB: true, + } + // Start the node and configure a full Ethereum node on it + stack, err := node.New(config) + if err != nil { + return nil, err + } + if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { + return eth.New(ctx, ð.Config{ + Genesis: genesis, + NetworkId: genesis.Config.ChainID.Uint64(), + SyncMode: downloader.FullSync, + DatabaseCache: 256, + DatabaseHandles: 256, + TxPool: core.DefaultTxPoolConfig, + GPO: eth.DefaultConfig.GPO, + MinerGasFloor: genesis.GasLimit * 9 / 10, + MinerGasCeil: genesis.GasLimit * 11 / 10, + MinerGasPrice: big.NewInt(1), + MinerRecommit: time.Second, + }) + }); err != nil { + return nil, err + } + // Start the node and return if successful + return stack, stack.Start() +} diff --git a/miner/stress_ethash.go b/miner/stress_ethash.go new file mode 100644 index 0000000000..040af9fba2 --- /dev/null +++ b/miner/stress_ethash.go @@ -0,0 +1,192 @@ +// 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 + +// This file contains a miner stress test based on the Ethash consensus engine. +package main + +import ( + "crypto/ecdsa" + "io/ioutil" + "math/big" + "math/rand" + "os" + "path/filepath" + "time" + + "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/fdlimit" + "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/eth/downloader" + "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/params" +) + +func main() { + log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) + fdlimit.Raise(2048) + + // Generate a batch of accounts to seal and fund with + faucets := make([]*ecdsa.PrivateKey, 128) + for i := 0; i < len(faucets); i++ { + faucets[i], _ = crypto.GenerateKey() + } + // Pre-generate the ethash mining DAG so we don't race + ethash.MakeDataset(1, filepath.Join(os.Getenv("HOME"), ".ethash")) + + // Create an Ethash network based off of the Ropsten config + genesis := makeGenesis(faucets) + + var ( + nodes []*node.Node + enodes []*enode.Node + ) + for i := 0; i < 4; i++ { + // Start the node and wait until it's up + node, err := makeMiner(genesis) + if err != nil { + panic(err) + } + defer node.Close() + + for node.Server().NodeInfo().Ports.Listener == 0 { + time.Sleep(250 * time.Millisecond) + } + // Connect the node to al the previous ones + for _, n := range enodes { + node.Server().AddPeer(n) + } + // Start tracking the node and it's enode + nodes = append(nodes, node) + enodes = append(enodes, node.Server().Self()) + + // Inject the signer key and start sealing with it + store := node.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) + if _, err := store.NewAccount(""); err != nil { + panic(err) + } + } + // Iterate over all the nodes and start signing with them + time.Sleep(3 * time.Second) + + for _, node := range nodes { + var ethereum *eth.Ethereum + if err := node.Service(ðereum); err != nil { + panic(err) + } + if err := ethereum.StartMining(1); err != nil { + panic(err) + } + } + time.Sleep(3 * time.Second) + + // Start injecting transactions from the faucets like crazy + nonces := make([]uint64, len(faucets)) + for { + index := rand.Intn(len(faucets)) + + // Fetch the accessor for the relevant signer + var ethereum *eth.Ethereum + if err := nodes[index%len(nodes)].Service(ðereum); err != nil { + panic(err) + } + // Create a self transaction and inject into the pool + tx, err := types.SignTx(types.NewTransaction(nonces[index], crypto.PubkeyToAddress(faucets[index].PublicKey), new(big.Int), 21000, big.NewInt(100000000000+rand.Int63n(65536)), nil), types.HomesteadSigner{}, faucets[index]) + if err != nil { + panic(err) + } + if err := ethereum.TxPool().AddLocal(tx); err != nil { + panic(err) + } + nonces[index]++ + + // Wait if we're too saturated + if pend, _ := ethereum.TxPool().Stats(); pend > 2048 { + time.Sleep(100 * time.Millisecond) + } + } +} + +// makeGenesis creates a custom Ethash genesis block based on some pre-defined +// faucet accounts. +func makeGenesis(faucets []*ecdsa.PrivateKey) *core.Genesis { + genesis := core.DefaultTestnetGenesisBlock() + genesis.Difficulty = params.MinimumDifficulty + genesis.GasLimit = 25000000 + + genesis.Config.ChainID = big.NewInt(18) + genesis.Config.EIP150Hash = common.Hash{} + + genesis.Alloc = core.GenesisAlloc{} + for _, faucet := range faucets { + genesis.Alloc[crypto.PubkeyToAddress(faucet.PublicKey)] = core.GenesisAccount{ + Balance: new(big.Int).Exp(big.NewInt(2), big.NewInt(128), nil), + } + } + return genesis +} + +func makeMiner(genesis *core.Genesis) (*node.Node, error) { + // Define the basic configurations for the Ethereum node + datadir, _ := ioutil.TempDir("", "") + + config := &node.Config{ + Name: "geth", + Version: params.Version, + DataDir: datadir, + P2P: p2p.Config{ + ListenAddr: "0.0.0.0:0", + NoDiscovery: true, + MaxPeers: 25, + }, + NoUSB: true, + UseLightweightKDF: true, + } + // Start the node and configure a full Ethereum node on it + stack, err := node.New(config) + if err != nil { + return nil, err + } + if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { + return eth.New(ctx, ð.Config{ + Genesis: genesis, + NetworkId: genesis.Config.ChainID.Uint64(), + SyncMode: downloader.FullSync, + DatabaseCache: 256, + DatabaseHandles: 256, + TxPool: core.DefaultTxPoolConfig, + GPO: eth.DefaultConfig.GPO, + Ethash: eth.DefaultConfig.Ethash, + MinerGasFloor: genesis.GasLimit * 9 / 10, + MinerGasCeil: genesis.GasLimit * 11 / 10, + MinerGasPrice: big.NewInt(1), + MinerRecommit: time.Second, + }) + }); err != nil { + return nil, err + } + // Start the node and return if successful + return stack, stack.Start() +} diff --git a/miner/unconfirmed.go b/miner/unconfirmed.go index 7a4fc7cc5a..3a176e8bd6 100644 --- a/miner/unconfirmed.go +++ b/miner/unconfirmed.go @@ -25,11 +25,14 @@ import ( "github.com/ethereum/go-ethereum/log" ) -// headerRetriever is used by the unconfirmed block set to verify whether a previously +// chainRetriever is used by the unconfirmed block set to verify whether a previously // mined block is part of the canonical chain or not. -type headerRetriever interface { +type chainRetriever interface { // GetHeaderByNumber retrieves the canonical header associated with a block number. GetHeaderByNumber(number uint64) *types.Header + + // GetBlockByNumber retrieves the canonical block associated with a block number. + GetBlockByNumber(number uint64) *types.Block } // unconfirmedBlock is a small collection of metadata about a locally mined block @@ -40,18 +43,18 @@ type unconfirmedBlock struct { } // unconfirmedBlocks implements a data structure to maintain locally mined blocks -// have have not yet reached enough maturity to guarantee chain inclusion. It is +// have not yet reached enough maturity to guarantee chain inclusion. It is // used by the miner to provide logs to the user when a previously mined block // has a high enough guarantee to not be reorged out of the canonical chain. type unconfirmedBlocks struct { - chain headerRetriever // Blockchain to verify canonical status through - depth uint // Depth after which to discard previous blocks - blocks *ring.Ring // Block infos to allow canonical chain cross checks - lock sync.RWMutex // Protects the fields from concurrent access + chain chainRetriever // Blockchain to verify canonical status through + depth uint // Depth after which to discard previous blocks + blocks *ring.Ring // Block infos to allow canonical chain cross checks + lock sync.RWMutex // Protects the fields from concurrent access } // newUnconfirmedBlocks returns new data structure to track currently unconfirmed blocks. -func newUnconfirmedBlocks(chain headerRetriever, depth uint) *unconfirmedBlocks { +func newUnconfirmedBlocks(chain chainRetriever, depth uint) *unconfirmedBlocks { return &unconfirmedBlocks{ chain: chain, depth: depth, @@ -103,7 +106,23 @@ func (set *unconfirmedBlocks) Shift(height uint64) { case header.Hash() == next.hash: log.Info("🔗 block reached canonical chain", "number", next.index, "hash", next.hash) default: - log.Info("⑂ block became a side fork", "number", next.index, "hash", next.hash) + // Block is not canonical, check whether we have an uncle or a lost block + included := false + for number := next.index; !included && number < next.index+uint64(set.depth) && number <= height; number++ { + if block := set.chain.GetBlockByNumber(number); block != nil { + for _, uncle := range block.Uncles() { + if uncle.Hash() == next.hash { + included = true + break + } + } + } + } + if included { + log.Info("⑂ block became an uncle", "number", next.index, "hash", next.hash) + } else { + log.Info("😱 block lost", "number", next.index, "hash", next.hash) + } } // Drop the block out of the ring if set.blocks.Value == set.blocks.Next().Value { diff --git a/miner/unconfirmed_test.go b/miner/unconfirmed_test.go index 456af1764a..42e77f3e64 100644 --- a/miner/unconfirmed_test.go +++ b/miner/unconfirmed_test.go @@ -23,11 +23,14 @@ import ( "github.com/ethereum/go-ethereum/core/types" ) -// noopHeaderRetriever is an implementation of headerRetriever that always +// noopChainRetriever is an implementation of headerRetriever that always // returns nil for any requested headers. -type noopHeaderRetriever struct{} +type noopChainRetriever struct{} -func (r *noopHeaderRetriever) GetHeaderByNumber(number uint64) *types.Header { +func (r *noopChainRetriever) GetHeaderByNumber(number uint64) *types.Header { + return nil +} +func (r *noopChainRetriever) GetBlockByNumber(number uint64) *types.Block { return nil } @@ -36,7 +39,7 @@ func (r *noopHeaderRetriever) GetHeaderByNumber(number uint64) *types.Header { func TestUnconfirmedInsertBounds(t *testing.T) { limit := uint(10) - pool := newUnconfirmedBlocks(new(noopHeaderRetriever), limit) + pool := newUnconfirmedBlocks(new(noopChainRetriever), limit) for depth := uint64(0); depth < 2*uint64(limit); depth++ { // Insert multiple blocks for the same level just to stress it for i := 0; i < int(depth); i++ { @@ -58,7 +61,7 @@ func TestUnconfirmedShifts(t *testing.T) { // Create a pool with a few blocks on various depths limit, start := uint(10), uint64(25) - pool := newUnconfirmedBlocks(new(noopHeaderRetriever), limit) + pool := newUnconfirmedBlocks(new(noopChainRetriever), limit) for depth := start; depth < start+uint64(limit); depth++ { pool.Insert(depth, common.Hash([32]byte{byte(depth)})) } diff --git a/miner/worker.go b/miner/worker.go index 1520277e17..48473796bc 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -18,503 +18,726 @@ package miner import ( "bytes" - "fmt" + "errors" "math/big" "sync" "sync/atomic" "time" + mapset "github.com/deckarep/golang-set" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/misc" "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/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" - "gopkg.in/fatih/set.v0" ) const ( - resultQueueSize = 10 - miningLogAtDepth = 5 + // resultQueueSize is the size of channel listening to sealing result. + resultQueueSize = 10 - // txChanSize is the size of channel listening to TxPreEvent. + // txChanSize is the size of channel listening to NewTxsEvent. // The number is referenced from the size of tx pool. txChanSize = 4096 + // chainHeadChanSize is the size of channel listening to ChainHeadEvent. chainHeadChanSize = 10 + // chainSideChanSize is the size of channel listening to ChainSideEvent. chainSideChanSize = 10 + + // resubmitAdjustChanSize is the size of resubmitting interval adjustment channel. + resubmitAdjustChanSize = 10 + + // miningLogAtDepth is the number of confirmations before logging successful mining. + miningLogAtDepth = 7 + + // minRecommitInterval is the minimal time interval to recreate the mining block with + // any newly arrived transactions. + minRecommitInterval = 1 * time.Second + + // maxRecommitInterval is the maximum time interval to recreate the mining block with + // any newly arrived transactions. + maxRecommitInterval = 15 * time.Second + + // intervalAdjustRatio is the impact a single interval adjustment has on sealing work + // resubmitting interval. + intervalAdjustRatio = 0.1 + + // intervalAdjustBias is applied during the new resubmit interval calculation in favor of + // increasing upper limit or decreasing lower limit so that the limit can be reachable. + intervalAdjustBias = 200 * 1000.0 * 1000.0 + + // staleThreshold is the maximum depth of the acceptable stale block. + staleThreshold = 7 ) -// Agent can register themself with the worker -type Agent interface { - Work() chan<- *Work - SetReturnCh(chan<- *Result) - Stop() - Start() - GetHashRate() int64 -} - -// Work is the workers current environment and holds -// all of the current state information -type Work struct { - config *params.ChainConfig +// environment is the worker's current environment and holds all of the current state information. +type environment struct { signer types.Signer state *state.StateDB // apply state changes here - ancestors *set.Set // ancestor set (used for checking uncle parent validity) - family *set.Set // family set (used for checking uncle invalidity) - uncles *set.Set // uncle set + ancestors mapset.Set // ancestor set (used for checking uncle parent validity) + family mapset.Set // family set (used for checking uncle invalidity) + uncles mapset.Set // uncle set tcount int // tx count in cycle - - Block *types.Block // the new block + gasPool *core.GasPool // available gas used to pack transactions header *types.Header txs []*types.Transaction receipts []*types.Receipt +} +// task contains all information for consensus engine sealing and result submitting. +type task struct { + receipts []*types.Receipt + state *state.StateDB + block *types.Block createdAt time.Time } -type Result struct { - Work *Work - Block *types.Block +const ( + commitInterruptNone int32 = iota + commitInterruptNewHead + commitInterruptResubmit +) + +// newWorkReq represents a request for new sealing work submitting with relative interrupt notifier. +type newWorkReq struct { + interrupt *int32 + noempty bool + timestamp int64 } -// worker is the main object which takes care of applying messages to the new state +// intervalAdjust represents a resubmitting interval adjustment. +type intervalAdjust struct { + ratio float64 + inc bool +} + +// worker is the main object which takes care of submitting new work to consensus engine +// and gathering the sealing result. type worker struct { config *params.ChainConfig engine consensus.Engine + eth Backend + chain *core.BlockChain - mu sync.Mutex + gasFloor uint64 + gasCeil uint64 - // update loop + // Subscriptions mux *event.TypeMux - txCh chan core.TxPreEvent - txSub event.Subscription + txsCh chan core.NewTxsEvent + txsSub event.Subscription chainHeadCh chan core.ChainHeadEvent chainHeadSub event.Subscription chainSideCh chan core.ChainSideEvent chainSideSub event.Subscription - wg sync.WaitGroup - agents map[Agent]struct{} - recv chan *Result + // Channels + newWorkCh chan *newWorkReq + taskCh chan *task + resultCh chan *types.Block + startCh chan struct{} + exitCh chan struct{} + resubmitIntervalCh chan time.Duration + resubmitAdjustCh chan *intervalAdjust - eth Backend - chain *core.BlockChain - proc core.Validator - chainDb ethdb.Database + current *environment // An environment for current running cycle. + localUncles map[common.Hash]*types.Block // A set of side blocks generated locally as the possible uncle blocks. + remoteUncles map[common.Hash]*types.Block // A set of side blocks as the possible uncle blocks. + unconfirmed *unconfirmedBlocks // A set of locally mined blocks pending canonicalness confirmations. + mu sync.RWMutex // The lock used to protect the coinbase and extra fields coinbase common.Address extra []byte - currentMu sync.Mutex - current *Work + pendingMu sync.RWMutex + pendingTasks map[common.Hash]*task - uncleMu sync.Mutex - possibleUncles map[common.Hash]*types.Block - - unconfirmed *unconfirmedBlocks // set of locally mined blocks pending canonicalness confirmations + snapshotMu sync.RWMutex // The lock used to protect the block snapshot and state snapshot + snapshotBlock *types.Block + snapshotState *state.StateDB // atomic status counters - mining int32 - atWork int32 + running int32 // The indicator whether the consensus engine is running or not. + newTxs int32 // New arrival transaction count since last sealing work submitting. + + // External functions + isLocalBlock func(block *types.Block) bool // Function used to determine whether the specified block is mined by local miner. + + // Test hooks + newTaskHook func(*task) // Method to call upon receiving a new sealing task. + skipSealHook func(*task) bool // Method to decide whether skipping the sealing. + fullTaskHook func() // Method to call before pushing the full sealing task. + resubmitHook func(time.Duration, time.Duration) // Method to call upon updating resubmitting interval. } -func newWorker(config *params.ChainConfig, engine consensus.Engine, coinbase common.Address, eth Backend, mux *event.TypeMux) *worker { +func newWorker(config *params.ChainConfig, engine consensus.Engine, eth Backend, mux *event.TypeMux, recommit time.Duration, gasFloor, gasCeil uint64, isLocalBlock func(*types.Block) bool) *worker { worker := &worker{ - config: config, - engine: engine, - eth: eth, - mux: mux, - txCh: make(chan core.TxPreEvent, txChanSize), - chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize), - chainSideCh: make(chan core.ChainSideEvent, chainSideChanSize), - chainDb: eth.ChainDb(), - recv: make(chan *Result, resultQueueSize), - chain: eth.BlockChain(), - proc: eth.BlockChain().Validator(), - possibleUncles: make(map[common.Hash]*types.Block), - coinbase: coinbase, - agents: make(map[Agent]struct{}), - unconfirmed: newUnconfirmedBlocks(eth.BlockChain(), miningLogAtDepth), + config: config, + engine: engine, + eth: eth, + mux: mux, + chain: eth.BlockChain(), + gasFloor: gasFloor, + gasCeil: gasCeil, + isLocalBlock: isLocalBlock, + localUncles: make(map[common.Hash]*types.Block), + remoteUncles: make(map[common.Hash]*types.Block), + unconfirmed: newUnconfirmedBlocks(eth.BlockChain(), miningLogAtDepth), + pendingTasks: make(map[common.Hash]*task), + txsCh: make(chan core.NewTxsEvent, txChanSize), + chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize), + chainSideCh: make(chan core.ChainSideEvent, chainSideChanSize), + newWorkCh: make(chan *newWorkReq), + taskCh: make(chan *task), + resultCh: make(chan *types.Block, resultQueueSize), + exitCh: make(chan struct{}), + startCh: make(chan struct{}, 1), + resubmitIntervalCh: make(chan time.Duration), + resubmitAdjustCh: make(chan *intervalAdjust, resubmitAdjustChanSize), } - // Subscribe TxPreEvent for tx pool - worker.txSub = eth.TxPool().SubscribeTxPreEvent(worker.txCh) + // Subscribe NewTxsEvent for tx pool + worker.txsSub = eth.TxPool().SubscribeNewTxsEvent(worker.txsCh) // Subscribe events for blockchain worker.chainHeadSub = eth.BlockChain().SubscribeChainHeadEvent(worker.chainHeadCh) worker.chainSideSub = eth.BlockChain().SubscribeChainSideEvent(worker.chainSideCh) - go worker.update() - go worker.wait() - worker.commitNewWork() + // Sanitize recommit interval if the user-specified one is too short. + if recommit < minRecommitInterval { + log.Warn("Sanitizing miner recommit interval", "provided", recommit, "updated", minRecommitInterval) + recommit = minRecommitInterval + } + + go worker.mainLoop() + go worker.newWorkLoop(recommit) + go worker.resultLoop() + go worker.taskLoop() + + // Submit first work to initialize pending state. + worker.startCh <- struct{}{} return worker } -func (self *worker) setEtherbase(addr common.Address) { - self.mu.Lock() - defer self.mu.Unlock() - self.coinbase = addr +// setEtherbase sets the etherbase used to initialize the block coinbase field. +func (w *worker) setEtherbase(addr common.Address) { + w.mu.Lock() + defer w.mu.Unlock() + w.coinbase = addr } -func (self *worker) setExtra(extra []byte) { - self.mu.Lock() - defer self.mu.Unlock() - self.extra = extra +// setExtra sets the content used to initialize the block extra field. +func (w *worker) setExtra(extra []byte) { + w.mu.Lock() + defer w.mu.Unlock() + w.extra = extra } -func (self *worker) pending() (*types.Block, *state.StateDB) { - self.currentMu.Lock() - defer self.currentMu.Unlock() +// setRecommitInterval updates the interval for miner sealing work recommitting. +func (w *worker) setRecommitInterval(interval time.Duration) { + w.resubmitIntervalCh <- interval +} - if atomic.LoadInt32(&self.mining) == 0 { - return types.NewBlock( - self.current.header, - self.current.txs, - nil, - self.current.receipts, - ), self.current.state.Copy() +// pending returns the pending state and corresponding block. +func (w *worker) pending() (*types.Block, *state.StateDB) { + // return a snapshot to avoid contention on currentMu mutex + w.snapshotMu.RLock() + defer w.snapshotMu.RUnlock() + if w.snapshotState == nil { + return nil, nil } - return self.current.Block, self.current.state.Copy() + return w.snapshotBlock, w.snapshotState.Copy() } -func (self *worker) pendingBlock() *types.Block { - self.currentMu.Lock() - defer self.currentMu.Unlock() - - if atomic.LoadInt32(&self.mining) == 0 { - return types.NewBlock( - self.current.header, - self.current.txs, - nil, - self.current.receipts, - ) - } - return self.current.Block +// pendingBlock returns pending block. +func (w *worker) pendingBlock() *types.Block { + // return a snapshot to avoid contention on currentMu mutex + w.snapshotMu.RLock() + defer w.snapshotMu.RUnlock() + return w.snapshotBlock } -func (self *worker) start() { - self.mu.Lock() - defer self.mu.Unlock() - - atomic.StoreInt32(&self.mining, 1) - - // spin up agents - for agent := range self.agents { - agent.Start() - } +// start sets the running status as 1 and triggers new work submitting. +func (w *worker) start() { + atomic.StoreInt32(&w.running, 1) + w.startCh <- struct{}{} } -func (self *worker) stop() { - self.wg.Wait() +// stop sets the running status as 0. +func (w *worker) stop() { + atomic.StoreInt32(&w.running, 0) +} - self.mu.Lock() - defer self.mu.Unlock() - if atomic.LoadInt32(&self.mining) == 1 { - for agent := range self.agents { - agent.Stop() +// isRunning returns an indicator whether worker is running or not. +func (w *worker) isRunning() bool { + return atomic.LoadInt32(&w.running) == 1 +} + +// close terminates all background threads maintained by the worker. +// Note the worker does not support being closed multiple times. +func (w *worker) close() { + close(w.exitCh) +} + +// newWorkLoop is a standalone goroutine to submit new mining work upon received events. +func (w *worker) newWorkLoop(recommit time.Duration) { + var ( + interrupt *int32 + minRecommit = recommit // minimal resubmit interval specified by user. + timestamp int64 // timestamp for each round of mining. + ) + + timer := time.NewTimer(0) + <-timer.C // discard the initial tick + + // commit aborts in-flight transaction execution with given signal and resubmits a new one. + commit := func(noempty bool, s int32) { + if interrupt != nil { + atomic.StoreInt32(interrupt, s) } + interrupt = new(int32) + w.newWorkCh <- &newWorkReq{interrupt: interrupt, noempty: noempty, timestamp: timestamp} + timer.Reset(recommit) + atomic.StoreInt32(&w.newTxs, 0) + } + // recalcRecommit recalculates the resubmitting interval upon feedback. + recalcRecommit := func(target float64, inc bool) { + var ( + prev = float64(recommit.Nanoseconds()) + next float64 + ) + if inc { + next = prev*(1-intervalAdjustRatio) + intervalAdjustRatio*(target+intervalAdjustBias) + // Recap if interval is larger than the maximum time interval + if next > float64(maxRecommitInterval.Nanoseconds()) { + next = float64(maxRecommitInterval.Nanoseconds()) + } + } else { + next = prev*(1-intervalAdjustRatio) + intervalAdjustRatio*(target-intervalAdjustBias) + // Recap if interval is less than the user specified minimum + if next < float64(minRecommit.Nanoseconds()) { + next = float64(minRecommit.Nanoseconds()) + } + } + recommit = time.Duration(int64(next)) + } + // clearPending cleans the stale pending tasks. + clearPending := func(number uint64) { + w.pendingMu.Lock() + for h, t := range w.pendingTasks { + if t.block.NumberU64()+staleThreshold <= number { + delete(w.pendingTasks, h) + } + } + w.pendingMu.Unlock() } - atomic.StoreInt32(&self.mining, 0) - atomic.StoreInt32(&self.atWork, 0) -} - -func (self *worker) register(agent Agent) { - self.mu.Lock() - defer self.mu.Unlock() - self.agents[agent] = struct{}{} - agent.SetReturnCh(self.recv) -} - -func (self *worker) unregister(agent Agent) { - self.mu.Lock() - defer self.mu.Unlock() - delete(self.agents, agent) - agent.Stop() -} - -func (self *worker) update() { - defer self.txSub.Unsubscribe() - defer self.chainHeadSub.Unsubscribe() - defer self.chainSideSub.Unsubscribe() for { - // A real event arrived, process interesting content select { - // Handle ChainHeadEvent - case <-self.chainHeadCh: - self.commitNewWork() + case <-w.startCh: + clearPending(w.chain.CurrentBlock().NumberU64()) + timestamp = time.Now().Unix() + commit(false, commitInterruptNewHead) - // Handle ChainSideEvent - case ev := <-self.chainSideCh: - self.uncleMu.Lock() - self.possibleUncles[ev.Block.Hash()] = ev.Block - self.uncleMu.Unlock() + case head := <-w.chainHeadCh: + clearPending(head.Block.NumberU64()) + timestamp = time.Now().Unix() + commit(false, commitInterruptNewHead) - // Handle TxPreEvent - case ev := <-self.txCh: - // Apply transaction to the pending state if we're not mining - if atomic.LoadInt32(&self.mining) == 0 { - self.currentMu.Lock() - acc, _ := types.Sender(self.current.signer, ev.Tx) - txs := map[common.Address]types.Transactions{acc: {ev.Tx}} - txset := types.NewTransactionsByPriceAndNonce(self.current.signer, txs) - - self.current.commitTransactions(self.mux, txset, self.chain, self.coinbase) - self.currentMu.Unlock() - } else { - // If we're mining, but nothing is being processed, wake on new transactions - if self.config.Clique != nil && self.config.Clique.Period == 0 { - self.commitNewWork() + case <-timer.C: + // If mining is running resubmit a new work cycle periodically to pull in + // higher priced transactions. Disable this overhead for pending blocks. + if w.isRunning() && (w.config.Clique == nil || w.config.Clique.Period > 0) { + // Short circuit if no new transaction arrives. + if atomic.LoadInt32(&w.newTxs) == 0 { + timer.Reset(recommit) + continue } + commit(true, commitInterruptResubmit) } - // System stopped - case <-self.txSub.Err(): - return - case <-self.chainHeadSub.Err(): - return - case <-self.chainSideSub.Err(): + case interval := <-w.resubmitIntervalCh: + // Adjust resubmit interval explicitly by user. + if interval < minRecommitInterval { + log.Warn("Sanitizing miner recommit interval", "provided", interval, "updated", minRecommitInterval) + interval = minRecommitInterval + } + log.Info("Miner recommit interval update", "from", minRecommit, "to", interval) + minRecommit, recommit = interval, interval + + if w.resubmitHook != nil { + w.resubmitHook(minRecommit, recommit) + } + + case adjust := <-w.resubmitAdjustCh: + // Adjust resubmit interval by feedback. + if adjust.inc { + before := recommit + recalcRecommit(float64(recommit.Nanoseconds())/adjust.ratio, true) + log.Trace("Increase miner recommit interval", "from", before, "to", recommit) + } else { + before := recommit + recalcRecommit(float64(minRecommit.Nanoseconds()), false) + log.Trace("Decrease miner recommit interval", "from", before, "to", recommit) + } + + if w.resubmitHook != nil { + w.resubmitHook(minRecommit, recommit) + } + + case <-w.exitCh: return } } } -func (self *worker) wait() { - for { - mustCommitNewWork := true - for result := range self.recv { - atomic.AddInt32(&self.atWork, -1) +// mainLoop is a standalone goroutine to regenerate the sealing task based on the received event. +func (w *worker) mainLoop() { + defer w.txsSub.Unsubscribe() + defer w.chainHeadSub.Unsubscribe() + defer w.chainSideSub.Unsubscribe() - if result == nil { + for { + select { + case req := <-w.newWorkCh: + w.commitNewWork(req.interrupt, req.noempty, req.timestamp) + + case ev := <-w.chainSideCh: + // Short circuit for duplicate side blocks + if _, exist := w.localUncles[ev.Block.Hash()]; exist { continue } - block := result.Block - work := result.Work - - // Update the block hash in all logs since it is now available and not when the - // receipt/log of individual transactions were created. - for _, r := range work.receipts { - for _, l := range r.Logs { - l.BlockHash = block.Hash() + if _, exist := w.remoteUncles[ev.Block.Hash()]; exist { + continue + } + // Add side block to possible uncle block set depending on the author. + if w.isLocalBlock != nil && w.isLocalBlock(ev.Block) { + w.localUncles[ev.Block.Hash()] = ev.Block + } else { + w.remoteUncles[ev.Block.Hash()] = ev.Block + } + // If our mining block contains less than 2 uncle blocks, + // add the new uncle block if valid and regenerate a mining block. + if w.isRunning() && w.current != nil && w.current.uncles.Cardinality() < 2 { + start := time.Now() + if err := w.commitUncle(w.current, ev.Block.Header()); err == nil { + var uncles []*types.Header + w.current.uncles.Each(func(item interface{}) bool { + hash, ok := item.(common.Hash) + if !ok { + return false + } + uncle, exist := w.localUncles[hash] + if !exist { + uncle, exist = w.remoteUncles[hash] + } + if !exist { + return false + } + uncles = append(uncles, uncle.Header()) + return false + }) + w.commit(uncles, nil, true, start) } } - for _, log := range work.state.Logs() { - log.BlockHash = block.Hash() + + case ev := <-w.txsCh: + // Apply transactions to the pending state if we're not mining. + // + // Note all transactions received may not be continuous with transactions + // already included in the current mining block. These transactions will + // be automatically eliminated. + if !w.isRunning() && w.current != nil { + w.mu.RLock() + coinbase := w.coinbase + w.mu.RUnlock() + + txs := make(map[common.Address]types.Transactions) + for _, tx := range ev.Txs { + acc, _ := types.Sender(w.current.signer, tx) + txs[acc] = append(txs[acc], tx) + } + txset := types.NewTransactionsByPriceAndNonce(w.current.signer, txs) + w.commitTransactions(txset, coinbase, nil) + w.updateSnapshot() + } else { + // If we're mining, but nothing is being processed, wake on new transactions + if w.config.Clique != nil && w.config.Clique.Period == 0 { + w.commitNewWork(nil, false, time.Now().Unix()) + } } - stat, err := self.chain.WriteBlockAndState(block, work.receipts, work.state) + atomic.AddInt32(&w.newTxs, int32(len(ev.Txs))) + + // System stopped + case <-w.exitCh: + return + case <-w.txsSub.Err(): + return + case <-w.chainHeadSub.Err(): + return + case <-w.chainSideSub.Err(): + return + } + } +} + +// taskLoop is a standalone goroutine to fetch sealing task from the generator and +// push them to consensus engine. +func (w *worker) taskLoop() { + var ( + stopCh chan struct{} + prev common.Hash + ) + + // interrupt aborts the in-flight sealing task. + interrupt := func() { + if stopCh != nil { + close(stopCh) + stopCh = nil + } + } + for { + select { + case task := <-w.taskCh: + if w.newTaskHook != nil { + w.newTaskHook(task) + } + // Reject duplicate sealing work due to resubmitting. + sealHash := w.engine.SealHash(task.block.Header()) + if sealHash == prev { + continue + } + // Interrupt previous sealing operation + interrupt() + stopCh, prev = make(chan struct{}), sealHash + + if w.skipSealHook != nil && w.skipSealHook(task) { + continue + } + w.pendingMu.Lock() + w.pendingTasks[w.engine.SealHash(task.block.Header())] = task + w.pendingMu.Unlock() + + if err := w.engine.Seal(w.chain, task.block, w.resultCh, stopCh); err != nil { + log.Warn("Block sealing failed", "err", err) + } + case <-w.exitCh: + interrupt() + return + } + } +} + +// resultLoop is a standalone goroutine to handle sealing result submitting +// and flush relative data to the database. +func (w *worker) resultLoop() { + for { + select { + case block := <-w.resultCh: + // Short circuit when receiving empty result. + if block == nil { + continue + } + // Short circuit when receiving duplicate result caused by resubmitting. + if w.chain.HasBlock(block.Hash(), block.NumberU64()) { + continue + } + var ( + sealhash = w.engine.SealHash(block.Header()) + hash = block.Hash() + ) + w.pendingMu.RLock() + task, exist := w.pendingTasks[sealhash] + w.pendingMu.RUnlock() + if !exist { + log.Error("Block found but no relative pending task", "number", block.Number(), "sealhash", sealhash, "hash", hash) + continue + } + // Different block could share same sealhash, deep copy here to prevent write-write conflict. + var ( + receipts = make([]*types.Receipt, len(task.receipts)) + logs []*types.Log + ) + for i, receipt := range task.receipts { + receipts[i] = new(types.Receipt) + *receipts[i] = *receipt + // Update the block hash in all logs since it is now available and not when the + // receipt/log of individual transactions were created. + for _, log := range receipt.Logs { + log.BlockHash = hash + } + logs = append(logs, receipt.Logs...) + } + // Commit block and state to database. + stat, err := w.chain.WriteBlockWithState(block, receipts, task.state) if err != nil { log.Error("Failed writing block to chain", "err", err) continue } - // check if canon block and write transactions - if stat == core.CanonStatTy { - // implicit by posting ChainHeadEvent - mustCommitNewWork = false - } + log.Info("Successfully sealed new block", "number", block.Number(), "sealhash", sealhash, "hash", hash, + "elapsed", common.PrettyDuration(time.Since(task.createdAt))) + // Broadcast the block and announce chain insertion event - self.mux.Post(core.NewMinedBlockEvent{Block: block}) - var ( - events []interface{} - logs = work.state.Logs() - ) - events = append(events, core.ChainEvent{Block: block, Hash: block.Hash(), Logs: logs}) - if stat == core.CanonStatTy { + w.mux.Post(core.NewMinedBlockEvent{Block: block}) + + var events []interface{} + switch stat { + case core.CanonStatTy: + events = append(events, core.ChainEvent{Block: block, Hash: block.Hash(), Logs: logs}) events = append(events, core.ChainHeadEvent{Block: block}) + case core.SideStatTy: + events = append(events, core.ChainSideEvent{Block: block}) } - self.chain.PostChainEvents(events, logs) + w.chain.PostChainEvents(events, logs) - // Insert the block into the set of pending ones to wait for confirmations - self.unconfirmed.Insert(block.NumberU64(), block.Hash()) + // Insert the block into the set of pending ones to resultLoop for confirmations + w.unconfirmed.Insert(block.NumberU64(), block.Hash()) - if mustCommitNewWork { - self.commitNewWork() - } - } - } -} - -// push sends a new work task to currently live miner agents. -func (self *worker) push(work *Work) { - if atomic.LoadInt32(&self.mining) != 1 { - return - } - for agent := range self.agents { - atomic.AddInt32(&self.atWork, 1) - if ch := agent.Work(); ch != nil { - ch <- work + case <-w.exitCh: + return } } } // makeCurrent creates a new environment for the current cycle. -func (self *worker) makeCurrent(parent *types.Block, header *types.Header) error { - state, err := self.chain.StateAt(parent.Root()) +func (w *worker) makeCurrent(parent *types.Block, header *types.Header) error { + state, err := w.chain.StateAt(parent.Root()) if err != nil { return err } - work := &Work{ - config: self.config, - signer: types.NewEIP155Signer(self.config.ChainId), + env := &environment{ + signer: types.NewEIP155Signer(w.config.ChainID), state: state, - ancestors: set.New(), - family: set.New(), - uncles: set.New(), + ancestors: mapset.NewSet(), + family: mapset.NewSet(), + uncles: mapset.NewSet(), header: header, - createdAt: time.Now(), } // when 08 is processed ancestors contain 07 (quick block) - for _, ancestor := range self.chain.GetBlocksFromHash(parent.Hash(), 7) { + for _, ancestor := range w.chain.GetBlocksFromHash(parent.Hash(), 7) { for _, uncle := range ancestor.Uncles() { - work.family.Add(uncle.Hash()) + env.family.Add(uncle.Hash()) } - work.family.Add(ancestor.Hash()) - work.ancestors.Add(ancestor.Hash()) + env.family.Add(ancestor.Hash()) + env.ancestors.Add(ancestor.Hash()) } // Keep track of transactions which return errors so they can be removed - work.tcount = 0 - self.current = work + env.tcount = 0 + w.current = env return nil } -func (self *worker) commitNewWork() { - self.mu.Lock() - defer self.mu.Unlock() - self.uncleMu.Lock() - defer self.uncleMu.Unlock() - self.currentMu.Lock() - defer self.currentMu.Unlock() - - tstart := time.Now() - parent := self.chain.CurrentBlock() - - tstamp := tstart.Unix() - if parent.Time().Cmp(new(big.Int).SetInt64(tstamp)) >= 0 { - tstamp = parent.Time().Int64() + 1 - } - // this will ensure we're not going off too far in the future - if now := time.Now().Unix(); tstamp > now+1 { - wait := time.Duration(tstamp-now) * time.Second - log.Info("Mining too far in the future", "wait", common.PrettyDuration(wait)) - time.Sleep(wait) - } - - num := parent.Number() - header := &types.Header{ - ParentHash: parent.Hash(), - Number: num.Add(num, common.Big1), - GasLimit: core.CalcGasLimit(parent), - Extra: self.extra, - Time: big.NewInt(tstamp), - } - // Only set the coinbase if we are mining (avoid spurious block rewards) - if atomic.LoadInt32(&self.mining) == 1 { - header.Coinbase = self.coinbase - } - if err := self.engine.Prepare(self.chain, header); err != nil { - log.Error("Failed to prepare header for mining", "err", err) - return - } - // If we are care about TheDAO hard-fork check whether to override the extra-data or not - if daoBlock := self.config.DAOForkBlock; daoBlock != nil { - // Check whether the block is among the fork extra-override range - limit := new(big.Int).Add(daoBlock, params.DAOForkExtraRange) - if header.Number.Cmp(daoBlock) >= 0 && header.Number.Cmp(limit) < 0 { - // Depending whether we support or oppose the fork, override differently - if self.config.DAOForkSupport { - header.Extra = common.CopyBytes(params.DAOForkBlockExtra) - } else if bytes.Equal(header.Extra, params.DAOForkBlockExtra) { - header.Extra = []byte{} // If miner opposes, don't let it use the reserved extra-data - } - } - } - // Could potentially happen if starting to mine in an odd state. - err := self.makeCurrent(parent, header) - if err != nil { - log.Error("Failed to create mining context", "err", err) - return - } - // Create the current work task and check any fork transitions needed - work := self.current - if self.config.DAOForkSupport && self.config.DAOForkBlock != nil && self.config.DAOForkBlock.Cmp(header.Number) == 0 { - misc.ApplyDAOHardFork(work.state) - } - pending, err := self.eth.TxPool().Pending() - if err != nil { - log.Error("Failed to fetch pending transactions", "err", err) - return - } - txs := types.NewTransactionsByPriceAndNonce(self.current.signer, pending) - work.commitTransactions(self.mux, txs, self.chain, self.coinbase) - - // compute uncles for the new block. - var ( - uncles []*types.Header - badUncles []common.Hash - ) - for hash, uncle := range self.possibleUncles { - if len(uncles) == 2 { - break - } - if err := self.commitUncle(work, uncle.Header()); err != nil { - log.Trace("Bad uncle found and will be removed", "hash", hash) - log.Trace(fmt.Sprint(uncle)) - - badUncles = append(badUncles, hash) - } else { - log.Debug("Committing new uncle to block", "hash", hash) - uncles = append(uncles, uncle.Header()) - } - } - for _, hash := range badUncles { - delete(self.possibleUncles, hash) - } - // Create the new block to seal with the consensus engine - if work.Block, err = self.engine.Finalize(self.chain, header, work.state, work.txs, uncles, work.receipts); err != nil { - log.Error("Failed to finalize block for sealing", "err", err) - return - } - // We only care about logging if we're actually mining. - if atomic.LoadInt32(&self.mining) == 1 { - log.Info("Commit new mining work", "number", work.Block.Number(), "txs", work.tcount, "uncles", len(uncles), "elapsed", common.PrettyDuration(time.Since(tstart))) - self.unconfirmed.Shift(work.Block.NumberU64() - 1) - } - self.push(work) -} - -func (self *worker) commitUncle(work *Work, uncle *types.Header) error { +// commitUncle adds the given block to uncle block set, returns error if failed to add. +func (w *worker) commitUncle(env *environment, uncle *types.Header) error { hash := uncle.Hash() - if work.uncles.Has(hash) { - return fmt.Errorf("uncle not unique") + if env.uncles.Contains(hash) { + return errors.New("uncle not unique") } - if !work.ancestors.Has(uncle.ParentHash) { - return fmt.Errorf("uncle's parent unknown (%x)", uncle.ParentHash[0:4]) + if env.header.ParentHash == uncle.ParentHash { + return errors.New("uncle is sibling") } - if work.family.Has(hash) { - return fmt.Errorf("uncle already in family (%x)", hash) + if !env.ancestors.Contains(uncle.ParentHash) { + return errors.New("uncle's parent unknown") } - work.uncles.Add(uncle.Hash()) + if env.family.Contains(hash) { + return errors.New("uncle already included") + } + env.uncles.Add(uncle.Hash()) return nil } -func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsByPriceAndNonce, bc *core.BlockChain, coinbase common.Address) { - gp := new(core.GasPool).AddGas(env.header.GasLimit) +// updateSnapshot updates pending snapshot block and state. +// Note this function assumes the current variable is thread safe. +func (w *worker) updateSnapshot() { + w.snapshotMu.Lock() + defer w.snapshotMu.Unlock() + + var uncles []*types.Header + w.current.uncles.Each(func(item interface{}) bool { + hash, ok := item.(common.Hash) + if !ok { + return false + } + uncle, exist := w.localUncles[hash] + if !exist { + uncle, exist = w.remoteUncles[hash] + } + if !exist { + return false + } + uncles = append(uncles, uncle.Header()) + return false + }) + + w.snapshotBlock = types.NewBlock( + w.current.header, + w.current.txs, + uncles, + w.current.receipts, + ) + + w.snapshotState = w.current.state.Copy() +} + +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, *w.chain.GetVMConfig()) + if err != nil { + w.current.state.RevertToSnapshot(snap) + return nil, err + } + w.current.txs = append(w.current.txs, tx) + w.current.receipts = append(w.current.receipts, receipt) + + return receipt.Logs, nil +} + +func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coinbase common.Address, interrupt *int32) bool { + // Short circuit if current is nil + if w.current == nil { + return true + } + + if w.current.gasPool == nil { + w.current.gasPool = new(core.GasPool).AddGas(w.current.header.GasLimit) + } var coalescedLogs []*types.Log for { + // In the following three cases, we will interrupt the execution of the transaction. + // (1) new head block event arrival, the interrupt signal is 1 + // (2) worker start or restart, the interrupt signal is 1 + // (3) worker recreate the mining block with any newly arrived transactions, the interrupt signal is 2. + // For the first two cases, the semi-finished work will be discarded. + // For the third case, the semi-finished work will be submitted to the consensus engine. + if interrupt != nil && atomic.LoadInt32(interrupt) != commitInterruptNone { + // Notify resubmit loop to increase resubmitting interval due to too frequent commits. + if atomic.LoadInt32(interrupt) == commitInterruptResubmit { + ratio := float64(w.current.header.GasLimit-w.current.gasPool.Gas()) / float64(w.current.header.GasLimit) + if ratio < 0.1 { + ratio = 0.1 + } + w.resubmitAdjustCh <- &intervalAdjust{ + ratio: ratio, + inc: true, + } + } + return atomic.LoadInt32(interrupt) == commitInterruptNewHead + } // If we don't have enough gas for any further transactions then we're done - if gp.Gas() < params.TxGas { - log.Trace("Not enough gas for further transactions", "gp", gp) + if w.current.gasPool.Gas() < params.TxGas { + log.Trace("Not enough gas for further transactions", "have", w.current.gasPool, "want", params.TxGas) break } // Retrieve the next transaction and abort if all done @@ -526,19 +749,19 @@ func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsB // during transaction acceptance is the transaction pool. // // We use the eip155 signer regardless of the current hf. - from, _ := types.Sender(env.signer, tx) + from, _ := types.Sender(w.current.signer, tx) // Check whether the tx is replay protected. If we're not in the EIP155 hf // phase, start ignoring the sender until we do. - if tx.Protected() && !env.config.IsEIP155(env.header.Number) { - log.Trace("Ignoring reply protected transaction", "hash", tx.Hash(), "eip155", env.config.EIP155Block) + if tx.Protected() && !w.config.IsEIP155(w.current.header.Number) { + log.Trace("Ignoring reply protected transaction", "hash", tx.Hash(), "eip155", w.config.EIP155Block) txs.Pop() continue } // Start executing the transaction - env.state.Prepare(tx.Hash(), common.Hash{}, env.tcount) + w.current.state.Prepare(tx.Hash(), common.Hash{}, w.current.tcount) - err, logs := env.commitTransaction(tx, bc, coinbase, gp) + logs, err := w.commitTransaction(tx, coinbase) switch err { case core.ErrGasLimitReached: // Pop the current out-of-gas transaction without shifting in the next from the account @@ -558,7 +781,7 @@ func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsB case nil: // Everything ok, collect the logs and shift in the next transaction from the same account coalescedLogs = append(coalescedLogs, logs...) - env.tcount++ + w.current.tcount++ txs.Shift() default: @@ -569,7 +792,11 @@ func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsB } } - if len(coalescedLogs) > 0 || env.tcount > 0 { + if !w.isRunning() && len(coalescedLogs) > 0 { + // We don't push the pendingLogsEvent while we are mining. The reason is that + // when we are mining, the worker will regenerate a mining block every 3 seconds. + // In order to avoid pushing the repeated pendingLog, we disable the pending log pushing. + // make a copy, the state caches the logs and these logs get "upgraded" from pending to mined // logs by filling in the block hash when the block was mined by the local miner. This can // cause a race condition if a log was "upgraded" before the PendingLogsEvent is processed. @@ -578,27 +805,180 @@ func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsB cpy[i] = new(types.Log) *cpy[i] = *l } - go func(logs []*types.Log, tcount int) { - if len(logs) > 0 { - mux.Post(core.PendingLogsEvent{Logs: logs}) - } - if tcount > 0 { - mux.Post(core.PendingStateEvent{}) - } - }(cpy, env.tcount) + go w.mux.Post(core.PendingLogsEvent{Logs: cpy}) } + // Notify resubmit loop to decrease resubmitting interval if current interval is larger + // than the user-specified one. + if interrupt != nil { + w.resubmitAdjustCh <- &intervalAdjust{inc: false} + } + return false } -func (env *Work) commitTransaction(tx *types.Transaction, bc *core.BlockChain, coinbase common.Address, gp *core.GasPool) (error, []*types.Log) { - snap := env.state.Snapshot() +// commitNewWork generates several new sealing tasks based on the parent block. +func (w *worker) commitNewWork(interrupt *int32, noempty bool, timestamp int64) { + w.mu.RLock() + defer w.mu.RUnlock() - receipt, _, err := core.ApplyTransaction(env.config, bc, &coinbase, gp, env.state, env.header, tx, &env.header.GasUsed, vm.Config{}) + tstart := time.Now() + parent := w.chain.CurrentBlock() + + if parent.Time().Cmp(new(big.Int).SetInt64(timestamp)) >= 0 { + timestamp = parent.Time().Int64() + 1 + } + // this will ensure we're not going off too far in the future + if now := time.Now().Unix(); timestamp > now+1 { + wait := time.Duration(timestamp-now) * time.Second + log.Info("Mining too far in the future", "wait", common.PrettyDuration(wait)) + time.Sleep(wait) + } + + num := parent.Number() + header := &types.Header{ + ParentHash: parent.Hash(), + Number: num.Add(num, common.Big1), + GasLimit: core.CalcGasLimit(parent, w.gasFloor, w.gasCeil), + Extra: w.extra, + Time: big.NewInt(timestamp), + } + // Only set the coinbase if our consensus engine is running (avoid spurious block rewards) + if w.isRunning() { + if w.coinbase == (common.Address{}) { + log.Error("Refusing to mine without etherbase") + return + } + header.Coinbase = w.coinbase + } + if err := w.engine.Prepare(w.chain, header); err != nil { + log.Error("Failed to prepare header for mining", "err", err) + return + } + // If we are care about TheDAO hard-fork check whether to override the extra-data or not + if daoBlock := w.config.DAOForkBlock; daoBlock != nil { + // Check whether the block is among the fork extra-override range + limit := new(big.Int).Add(daoBlock, params.DAOForkExtraRange) + if header.Number.Cmp(daoBlock) >= 0 && header.Number.Cmp(limit) < 0 { + // Depending whether we support or oppose the fork, override differently + if w.config.DAOForkSupport { + header.Extra = common.CopyBytes(params.DAOForkBlockExtra) + } else if bytes.Equal(header.Extra, params.DAOForkBlockExtra) { + header.Extra = []byte{} // If miner opposes, don't let it use the reserved extra-data + } + } + } + // Could potentially happen if starting to mine in an odd state. + err := w.makeCurrent(parent, header) if err != nil { - env.state.RevertToSnapshot(snap) - return err, nil + log.Error("Failed to create mining context", "err", err) + return } - env.txs = append(env.txs, tx) - env.receipts = append(env.receipts, receipt) + // Create the current work task and check any fork transitions needed + env := w.current + if w.config.DAOForkSupport && w.config.DAOForkBlock != nil && w.config.DAOForkBlock.Cmp(header.Number) == 0 { + misc.ApplyDAOHardFork(env.state) + } + // Accumulate the uncles for the current block + uncles := make([]*types.Header, 0, 2) + commitUncles := func(blocks map[common.Hash]*types.Block) { + // Clean up stale uncle blocks first + for hash, uncle := range blocks { + if uncle.NumberU64()+staleThreshold <= header.Number.Uint64() { + delete(blocks, hash) + } + } + for hash, uncle := range blocks { + if len(uncles) == 2 { + break + } + if err := w.commitUncle(env, uncle.Header()); err != nil { + log.Trace("Possible uncle rejected", "hash", hash, "reason", err) + } else { + log.Debug("Committing new uncle to block", "hash", hash) + uncles = append(uncles, uncle.Header()) + } + } + } + // Prefer to locally generated uncle + commitUncles(w.localUncles) + commitUncles(w.remoteUncles) - return nil, receipt.Logs + if !noempty { + // Create an empty block based on temporary copied state for sealing in advance without waiting block + // execution finished. + w.commit(uncles, nil, false, tstart) + } + + // Fill the block with all available pending transactions. + pending, err := w.eth.TxPool().Pending() + if err != nil { + log.Error("Failed to fetch pending transactions", "err", err) + return + } + // Short circuit if there is no available pending transactions + if len(pending) == 0 { + w.updateSnapshot() + return + } + // Split the pending transactions into locals and remotes + localTxs, remoteTxs := make(map[common.Address]types.Transactions), pending + for _, account := range w.eth.TxPool().Locals() { + if txs := remoteTxs[account]; len(txs) > 0 { + delete(remoteTxs, account) + localTxs[account] = txs + } + } + if len(localTxs) > 0 { + txs := types.NewTransactionsByPriceAndNonce(w.current.signer, localTxs) + if w.commitTransactions(txs, w.coinbase, interrupt) { + return + } + } + if len(remoteTxs) > 0 { + txs := types.NewTransactionsByPriceAndNonce(w.current.signer, remoteTxs) + if w.commitTransactions(txs, w.coinbase, interrupt) { + return + } + } + w.commit(uncles, w.fullTaskHook, true, tstart) +} + +// commit runs any post-transaction state modifications, assembles the final block +// and commits new work if consensus engine is running. +func (w *worker) commit(uncles []*types.Header, interval func(), update bool, start time.Time) error { + // Deep copy receipts here to avoid interaction between different tasks. + receipts := make([]*types.Receipt, len(w.current.receipts)) + for i, l := range w.current.receipts { + receipts[i] = new(types.Receipt) + *receipts[i] = *l + } + s := w.current.state.Copy() + block, err := w.engine.Finalize(w.chain, w.current.header, s, w.current.txs, uncles, w.current.receipts) + if err != nil { + return err + } + if w.isRunning() { + if interval != nil { + interval() + } + select { + case w.taskCh <- &task{receipts: receipts, state: s, block: block, createdAt: time.Now()}: + w.unconfirmed.Shift(block.NumberU64() - 1) + + feesWei := new(big.Int) + for i, tx := range block.Transactions() { + feesWei.Add(feesWei, new(big.Int).Mul(new(big.Int).SetUint64(receipts[i].GasUsed), tx.GasPrice())) + } + feesEth := new(big.Float).Quo(new(big.Float).SetInt(feesWei), new(big.Float).SetInt(big.NewInt(params.Ether))) + + log.Info("Commit new mining work", "number", block.Number(), "sealhash", w.engine.SealHash(block.Header()), + "uncles", len(uncles), "txs", w.current.tcount, "gas", block.GasUsed(), "fees", feesEth, "elapsed", common.PrettyDuration(time.Since(start))) + + case <-w.exitCh: + log.Info("Worker has exited") + } + } + if update { + w.updateSnapshot() + } + return nil } diff --git a/miner/worker_test.go b/miner/worker_test.go new file mode 100644 index 0000000000..bfa9cbd21d --- /dev/null +++ b/miner/worker_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 miner + +import ( + "math/big" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus" + "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/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/event" + "github.com/ethereum/go-ethereum/params" +) + +var ( + // Test chain configurations + testTxPoolConfig core.TxPoolConfig + ethashChainConfig *params.ChainConfig + cliqueChainConfig *params.ChainConfig + + // Test accounts + testBankKey, _ = crypto.GenerateKey() + testBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey) + testBankFunds = big.NewInt(1000000000000000000) + + testUserKey, _ = crypto.GenerateKey() + testUserAddress = crypto.PubkeyToAddress(testUserKey.PublicKey) + + // Test transactions + pendingTxs []*types.Transaction + newTxs []*types.Transaction +) + +func init() { + testTxPoolConfig = core.DefaultTxPoolConfig + testTxPoolConfig.Journal = "" + ethashChainConfig = params.TestChainConfig + cliqueChainConfig = params.TestChainConfig + cliqueChainConfig.Clique = ¶ms.CliqueConfig{ + Period: 10, + Epoch: 30000, + } + tx1, _ := types.SignTx(types.NewTransaction(0, testUserAddress, big.NewInt(1000), params.TxGas, nil, nil), types.HomesteadSigner{}, testBankKey) + pendingTxs = append(pendingTxs, tx1) + tx2, _ := types.SignTx(types.NewTransaction(1, testUserAddress, big.NewInt(1000), params.TxGas, nil, nil), types.HomesteadSigner{}, testBankKey) + newTxs = append(newTxs, tx2) +} + +// testWorkerBackend implements worker.Backend interfaces and wraps all information needed during the testing. +type testWorkerBackend struct { + db ethdb.Database + txPool *core.TxPool + chain *core.BlockChain + testTxFeed event.Feed + uncleBlock *types.Block +} + +func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, n int) *testWorkerBackend { + var ( + db = ethdb.NewMemDatabase() + gspec = core.Genesis{ + Config: chainConfig, + Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}, + } + ) + + switch engine.(type) { + case *clique.Clique: + gspec.ExtraData = make([]byte, 32+common.AddressLength+65) + copy(gspec.ExtraData[32:], testBankAddress[:]) + case *ethash.Ethash: + default: + t.Fatalf("unexpected consensus engine type: %T", engine) + } + genesis := gspec.MustCommit(db) + + chain, _ := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil) + txpool := core.NewTxPool(testTxPoolConfig, chainConfig, chain) + + // Generate a small n-block chain and an uncle block for it + if n > 0 { + blocks, _ := core.GenerateChain(chainConfig, genesis, engine, db, n, func(i int, gen *core.BlockGen) { + gen.SetCoinbase(testBankAddress) + }) + if _, err := chain.InsertChain(blocks); err != nil { + t.Fatalf("failed to insert origin chain: %v", err) + } + } + parent := genesis + if n > 0 { + parent = chain.GetBlockByHash(chain.CurrentBlock().ParentHash()) + } + blocks, _ := core.GenerateChain(chainConfig, parent, engine, db, 1, func(i int, gen *core.BlockGen) { + gen.SetCoinbase(testUserAddress) + }) + + return &testWorkerBackend{ + db: db, + chain: chain, + txPool: txpool, + uncleBlock: blocks[0], + } +} + +func (b *testWorkerBackend) BlockChain() *core.BlockChain { return b.chain } +func (b *testWorkerBackend) TxPool() *core.TxPool { return b.txPool } +func (b *testWorkerBackend) PostChainEvents(events []interface{}) { + b.chain.PostChainEvents(events, nil) +} + +func newTestWorker(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, blocks int) (*worker, *testWorkerBackend) { + backend := newTestWorkerBackend(t, chainConfig, engine, blocks) + backend.txPool.AddLocals(pendingTxs) + w := newWorker(chainConfig, engine, backend, new(event.TypeMux), time.Second, params.GenesisGasLimit, params.GenesisGasLimit, nil) + w.setEtherbase(testBankAddress) + return w, backend +} + +func TestPendingStateAndBlockEthash(t *testing.T) { + testPendingStateAndBlock(t, ethashChainConfig, ethash.NewFaker()) +} +func TestPendingStateAndBlockClique(t *testing.T) { + testPendingStateAndBlock(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, ethdb.NewMemDatabase())) +} + +func testPendingStateAndBlock(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) { + defer engine.Close() + + w, b := newTestWorker(t, chainConfig, engine, 0) + defer w.close() + + // Ensure snapshot has been updated. + time.Sleep(100 * time.Millisecond) + block, state := w.pending() + if block.NumberU64() != 1 { + t.Errorf("block number mismatch: have %d, want %d", block.NumberU64(), 1) + } + if balance := state.GetBalance(testUserAddress); balance.Cmp(big.NewInt(1000)) != 0 { + t.Errorf("account balance mismatch: have %d, want %d", balance, 1000) + } + b.txPool.AddLocals(newTxs) + + // Ensure the new tx events has been processed + time.Sleep(100 * time.Millisecond) + block, state = w.pending() + if balance := state.GetBalance(testUserAddress); balance.Cmp(big.NewInt(2000)) != 0 { + t.Errorf("account balance mismatch: have %d, want %d", balance, 2000) + } +} + +func TestEmptyWorkEthash(t *testing.T) { + testEmptyWork(t, ethashChainConfig, ethash.NewFaker()) +} +func TestEmptyWorkClique(t *testing.T) { + testEmptyWork(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, ethdb.NewMemDatabase())) +} + +func testEmptyWork(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) { + defer engine.Close() + + w, _ := newTestWorker(t, chainConfig, engine, 0) + defer w.close() + + var ( + taskCh = make(chan struct{}, 2) + taskIndex int + ) + + checkEqual := func(t *testing.T, task *task, index int) { + receiptLen, balance := 0, big.NewInt(0) + if index == 1 { + receiptLen, balance = 1, big.NewInt(1000) + } + if len(task.receipts) != receiptLen { + t.Errorf("receipt number mismatch: have %d, want %d", len(task.receipts), receiptLen) + } + if task.state.GetBalance(testUserAddress).Cmp(balance) != 0 { + t.Errorf("account balance mismatch: have %d, want %d", task.state.GetBalance(testUserAddress), balance) + } + } + + w.newTaskHook = func(task *task) { + if task.block.NumberU64() == 1 { + checkEqual(t, task, taskIndex) + taskIndex += 1 + taskCh <- struct{}{} + } + } + w.fullTaskHook = func() { + time.Sleep(100 * time.Millisecond) + } + + // Ensure worker has finished initialization + for { + b := w.pendingBlock() + if b != nil && b.NumberU64() == 1 { + break + } + } + + w.start() + for i := 0; i < 2; i += 1 { + select { + case <-taskCh: + case <-time.NewTimer(2 * time.Second).C: + t.Error("new task timeout") + } + } +} + +func TestStreamUncleBlock(t *testing.T) { + ethash := ethash.NewFaker() + defer ethash.Close() + + w, b := newTestWorker(t, ethashChainConfig, ethash, 1) + defer w.close() + + var taskCh = make(chan struct{}) + + taskIndex := 0 + w.newTaskHook = func(task *task) { + if task.block.NumberU64() == 2 { + if taskIndex == 2 { + have := task.block.Header().UncleHash + want := types.CalcUncleHash([]*types.Header{b.uncleBlock.Header()}) + if have != want { + t.Errorf("uncle hash mismatch: have %s, want %s", have.Hex(), want.Hex()) + } + } + taskCh <- struct{}{} + taskIndex += 1 + } + } + w.skipSealHook = func(task *task) bool { + return true + } + w.fullTaskHook = func() { + time.Sleep(100 * time.Millisecond) + } + + // Ensure worker has finished initialization + for { + b := w.pendingBlock() + if b != nil && b.NumberU64() == 2 { + break + } + } + w.start() + + // Ignore the first two works + for i := 0; i < 2; i += 1 { + select { + case <-taskCh: + case <-time.NewTimer(time.Second).C: + t.Error("new task timeout") + } + } + b.PostChainEvents([]interface{}{core.ChainSideEvent{Block: b.uncleBlock}}) + + select { + case <-taskCh: + case <-time.NewTimer(time.Second).C: + t.Error("new task timeout") + } +} + +func TestRegenerateMiningBlockEthash(t *testing.T) { + testRegenerateMiningBlock(t, ethashChainConfig, ethash.NewFaker()) +} + +func TestRegenerateMiningBlockClique(t *testing.T) { + testRegenerateMiningBlock(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, ethdb.NewMemDatabase())) +} + +func testRegenerateMiningBlock(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) { + defer engine.Close() + + w, b := newTestWorker(t, chainConfig, engine, 0) + defer w.close() + + var taskCh = make(chan struct{}) + + taskIndex := 0 + w.newTaskHook = func(task *task) { + if task.block.NumberU64() == 1 { + if taskIndex == 2 { + receiptLen, balance := 2, big.NewInt(2000) + if len(task.receipts) != receiptLen { + t.Errorf("receipt number mismatch: have %d, want %d", len(task.receipts), receiptLen) + } + if task.state.GetBalance(testUserAddress).Cmp(balance) != 0 { + t.Errorf("account balance mismatch: have %d, want %d", task.state.GetBalance(testUserAddress), balance) + } + } + taskCh <- struct{}{} + taskIndex += 1 + } + } + w.skipSealHook = func(task *task) bool { + return true + } + w.fullTaskHook = func() { + time.Sleep(100 * time.Millisecond) + } + // Ensure worker has finished initialization + for { + b := w.pendingBlock() + if b != nil && b.NumberU64() == 1 { + break + } + } + + w.start() + // Ignore the first two works + for i := 0; i < 2; i += 1 { + select { + case <-taskCh: + case <-time.NewTimer(time.Second).C: + t.Error("new task timeout") + } + } + b.txPool.AddLocals(newTxs) + time.Sleep(time.Second) + + select { + case <-taskCh: + case <-time.NewTimer(time.Second).C: + t.Error("new task timeout") + } +} + +func TestAdjustIntervalEthash(t *testing.T) { + testAdjustInterval(t, ethashChainConfig, ethash.NewFaker()) +} + +func TestAdjustIntervalClique(t *testing.T) { + testAdjustInterval(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, ethdb.NewMemDatabase())) +} + +func testAdjustInterval(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) { + defer engine.Close() + + w, _ := newTestWorker(t, chainConfig, engine, 0) + defer w.close() + + w.skipSealHook = func(task *task) bool { + return true + } + w.fullTaskHook = func() { + time.Sleep(100 * time.Millisecond) + } + var ( + progress = make(chan struct{}, 10) + result = make([]float64, 0, 10) + index = 0 + start = false + ) + w.resubmitHook = func(minInterval time.Duration, recommitInterval time.Duration) { + // Short circuit if interval checking hasn't started. + if !start { + return + } + var wantMinInterval, wantRecommitInterval time.Duration + + switch index { + case 0: + wantMinInterval, wantRecommitInterval = 3*time.Second, 3*time.Second + case 1: + origin := float64(3 * time.Second.Nanoseconds()) + estimate := origin*(1-intervalAdjustRatio) + intervalAdjustRatio*(origin/0.8+intervalAdjustBias) + wantMinInterval, wantRecommitInterval = 3*time.Second, time.Duration(estimate)*time.Nanosecond + case 2: + estimate := result[index-1] + min := float64(3 * time.Second.Nanoseconds()) + estimate = estimate*(1-intervalAdjustRatio) + intervalAdjustRatio*(min-intervalAdjustBias) + wantMinInterval, wantRecommitInterval = 3*time.Second, time.Duration(estimate)*time.Nanosecond + case 3: + wantMinInterval, wantRecommitInterval = time.Second, time.Second + } + + // Check interval + if minInterval != wantMinInterval { + t.Errorf("resubmit min interval mismatch: have %v, want %v ", minInterval, wantMinInterval) + } + if recommitInterval != wantRecommitInterval { + t.Errorf("resubmit interval mismatch: have %v, want %v", recommitInterval, wantRecommitInterval) + } + result = append(result, float64(recommitInterval.Nanoseconds())) + index += 1 + progress <- struct{}{} + } + // Ensure worker has finished initialization + for { + b := w.pendingBlock() + if b != nil && b.NumberU64() == 1 { + break + } + } + + w.start() + + time.Sleep(time.Second) + + start = true + w.setRecommitInterval(3 * time.Second) + select { + case <-progress: + case <-time.NewTimer(time.Second).C: + t.Error("interval reset timeout") + } + + w.resubmitAdjustCh <- &intervalAdjust{inc: true, ratio: 0.8} + select { + case <-progress: + case <-time.NewTimer(time.Second).C: + t.Error("interval reset timeout") + } + + w.resubmitAdjustCh <- &intervalAdjust{inc: false} + select { + case <-progress: + case <-time.NewTimer(time.Second).C: + t.Error("interval reset timeout") + } + + w.setRecommitInterval(500 * time.Millisecond) + select { + case <-progress: + case <-time.NewTimer(time.Second).C: + t.Error("interval reset timeout") + } +} diff --git a/mobile/big.go b/mobile/big.go index dd7b158786..86ea93245a 100644 --- a/mobile/big.go +++ b/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/mobile/bind.go b/mobile/bind.go index 7a1bf9e605..d6e621a258 100644 --- a/mobile/bind.go +++ b/mobile/bind.go @@ -154,12 +154,20 @@ func (c *BoundContract) GetDeployer() *Transaction { // Call invokes the (constant) contract method with params as input values and // sets the output to result. func (c *BoundContract) Call(opts *CallOpts, out *Interfaces, method string, args *Interfaces) error { - results := make([]interface{}, len(out.objects)) - copy(results, out.objects) - if err := c.contract.Call(&opts.opts, &results, method, args.objects...); err != nil { - return err + if len(out.objects) == 1 { + result := out.objects[0] + if err := c.contract.Call(&opts.opts, result, method, args.objects...); err != nil { + return err + } + out.objects[0] = result + } else { + results := make([]interface{}, len(out.objects)) + copy(results, out.objects) + if err := c.contract.Call(&opts.opts, &results, method, args.objects...); err != nil { + return err + } + copy(out.objects, results) } - copy(out.objects, results) return nil } diff --git a/mobile/ethclient.go b/mobile/ethclient.go index 66399c6b56..662125c4ad 100644 --- a/mobile/ethclient.go +++ b/mobile/ethclient.go @@ -138,7 +138,9 @@ func (ec *EthereumClient) SubscribeNewHead(ctx *Context, handler NewHeadHandler, handler.OnNewHead(&Header{header}) case err := <-rawSub.Err(): - handler.OnError(err.Error()) + if err != nil { + handler.OnError(err.Error()) + } return } } @@ -227,7 +229,9 @@ func (ec *EthereumClient) SubscribeFilterLogs(ctx *Context, query *FilterQuery, handler.OnFilterLogs(&Log{&log}) case err := <-rawSub.Err(): - handler.OnError(err.Error()) + if err != nil { + handler.OnError(err.Error()) + } return } } diff --git a/mobile/ethereum.go b/mobile/ethereum.go index 0eb1d90552..59da852397 100644 --- a/mobile/ethereum.go +++ b/mobile/ethereum.go @@ -67,6 +67,7 @@ func (msg *CallMsg) SetData(data []byte) { msg.msg.Data = common.CopyBytes func (msg *CallMsg) SetTo(address *Address) { if address == nil { msg.msg.To = nil + return } msg.msg.To = &address.address } @@ -125,12 +126,12 @@ func (t *Topics) Append(topics *Hashes) { t.topics = append(t.topics, topics.hashes) } -// FilterQuery contains options for contact log filtering. +// FilterQuery contains options for contract log filtering. type FilterQuery struct { query ethereum.FilterQuery } -// NewFilterQuery creates an empty filter query for contact log filtering. +// NewFilterQuery creates an empty filter query for contract log filtering. func NewFilterQuery() *FilterQuery { return new(FilterQuery) } diff --git a/mobile/geth.go b/mobile/geth.go index 7e3b8f4915..fba3e5711b 100644 --- a/mobile/geth.go +++ b/mobile/geth.go @@ -29,12 +29,13 @@ import ( "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethstats" + "github.com/ethereum/go-ethereum/internal/debug" "github.com/ethereum/go-ethereum/les" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/params" - whisper "github.com/ethereum/go-ethereum/whisper/whisperv5" + whisper "github.com/ethereum/go-ethereum/whisper/whisperv6" ) // NodeConfig represents the collection of configuration values to fine tune the Geth @@ -72,6 +73,12 @@ type NodeConfig struct { // WhisperEnabled specifies whether the node should run the Whisper protocol. WhisperEnabled bool + + // 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 @@ -107,10 +114,15 @@ func NewNode(datadir string, config *NodeConfig) (stack *Node, _ error) { if config.BootstrapNodes == nil || config.BootstrapNodes.Size() == 0 { config.BootstrapNodes = defaultNodeConfig.BootstrapNodes } + + if config.PprofAddress != "" { + debug.StartPProf(config.PprofAddress) + } + // Create the empty networking stack nodeConf := &node.Config{ Name: clientIdentifier, - Version: params.Version, + Version: params.VersionWithMeta, DataDir: datadir, KeyStoreDir: filepath.Join(datadir, "keystore"), // Mobile should never use internal keystores! P2P: p2p.Config{ @@ -122,11 +134,14 @@ func NewNode(datadir string, config *NodeConfig) (stack *Node, _ error) { MaxPeers: config.MaxPeers, }, } + rawStack, err := node.New(nodeConf) if err != nil { return nil, err } + debug.Memsize.Add("node", rawStack) + var genesis *core.Genesis if config.EthereumGenesis != "" { // Parse the user supplied genesis spec if not mainnet @@ -177,12 +192,18 @@ 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() } -// Stop terminates a running node along with all it's services. In the node was +// Stop terminates a running node along with all it's services. If the node was // not started, an error is returned. func (n *Node) Stop() error { return n.node.Stop() diff --git a/mobile/shhclient.go b/mobile/shhclient.go new file mode 100644 index 0000000000..a069c9bd40 --- /dev/null +++ b/mobile/shhclient.go @@ -0,0 +1,195 @@ +// Copyright 2017 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 a wrapper for the Whisper client. + +package geth + +import ( + "github.com/ethereum/go-ethereum/whisper/shhclient" + whisper "github.com/ethereum/go-ethereum/whisper/whisperv6" +) + +// WhisperClient provides access to the Ethereum APIs. +type WhisperClient struct { + client *shhclient.Client +} + +// NewWhisperClient connects a client to the given URL. +func NewWhisperClient(rawurl string) (client *WhisperClient, _ error) { + rawClient, err := shhclient.Dial(rawurl) + return &WhisperClient{rawClient}, err +} + +// GetVersion returns the Whisper sub-protocol version. +func (wc *WhisperClient) GetVersion(ctx *Context) (version string, _ error) { + return wc.client.Version(ctx.context) +} + +// Info returns diagnostic information about the whisper node. +func (wc *WhisperClient) GetInfo(ctx *Context) (info *Info, _ error) { + rawInfo, err := wc.client.Info(ctx.context) + return &Info{&rawInfo}, err +} + +// SetMaxMessageSize sets the maximal message size allowed by this node. Incoming +// and outgoing messages with a larger size will be rejected. Whisper message size +// can never exceed the limit imposed by the underlying P2P protocol (10 Mb). +func (wc *WhisperClient) SetMaxMessageSize(ctx *Context, size int32) error { + return wc.client.SetMaxMessageSize(ctx.context, uint32(size)) +} + +// SetMinimumPoW (experimental) sets the minimal PoW required by this node. +// This experimental function was introduced for the future dynamic adjustment of +// PoW requirement. If the node is overwhelmed with messages, it should raise the +// PoW requirement and notify the peers. The new value should be set relative to +// the old value (e.g. double). The old value could be obtained via shh_info call. +func (wc *WhisperClient) SetMinimumPoW(ctx *Context, pow float64) error { + return wc.client.SetMinimumPoW(ctx.context, pow) +} + +// Marks specific 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 (wc *WhisperClient) MarkTrustedPeer(ctx *Context, enode string) error { + return wc.client.MarkTrustedPeer(ctx.context, enode) +} + +// NewKeyPair generates a new public and private key pair for message decryption and encryption. +// It returns an identifier that can be used to refer to the key. +func (wc *WhisperClient) NewKeyPair(ctx *Context) (string, error) { + return wc.client.NewKeyPair(ctx.context) +} + +// AddPrivateKey stored the key pair, and returns its ID. +func (wc *WhisperClient) AddPrivateKey(ctx *Context, key []byte) (string, error) { + return wc.client.AddPrivateKey(ctx.context, key) +} + +// DeleteKeyPair delete the specifies key. +func (wc *WhisperClient) DeleteKeyPair(ctx *Context, id string) (string, error) { + return wc.client.DeleteKeyPair(ctx.context, id) +} + +// HasKeyPair returns an indication if the node has a private key or +// key pair matching the given ID. +func (wc *WhisperClient) HasKeyPair(ctx *Context, id string) (bool, error) { + return wc.client.HasKeyPair(ctx.context, id) +} + +// GetPublicKey return the public key for a key ID. +func (wc *WhisperClient) GetPublicKey(ctx *Context, id string) ([]byte, error) { + return wc.client.PublicKey(ctx.context, id) +} + +// GetPrivateKey return the private key for a key ID. +func (wc *WhisperClient) GetPrivateKey(ctx *Context, id string) ([]byte, error) { + return wc.client.PrivateKey(ctx.context, id) +} + +// NewSymmetricKey generates a random symmetric key and returns its identifier. +// Can be used encrypting and decrypting messages where the key is known to both parties. +func (wc *WhisperClient) NewSymmetricKey(ctx *Context) (string, error) { + return wc.client.NewSymmetricKey(ctx.context) +} + +// AddSymmetricKey stores the key, and returns its identifier. +func (wc *WhisperClient) AddSymmetricKey(ctx *Context, key []byte) (string, error) { + return wc.client.AddSymmetricKey(ctx.context, key) +} + +// GenerateSymmetricKeyFromPassword generates the key from password, stores it, and returns its identifier. +func (wc *WhisperClient) GenerateSymmetricKeyFromPassword(ctx *Context, passwd string) (string, error) { + return wc.client.GenerateSymmetricKeyFromPassword(ctx.context, passwd) +} + +// HasSymmetricKey returns an indication if the key associated with the given id is stored in the node. +func (wc *WhisperClient) HasSymmetricKey(ctx *Context, id string) (bool, error) { + return wc.client.HasSymmetricKey(ctx.context, id) +} + +// GetSymmetricKey returns the symmetric key associated with the given identifier. +func (wc *WhisperClient) GetSymmetricKey(ctx *Context, id string) ([]byte, error) { + return wc.client.GetSymmetricKey(ctx.context, id) +} + +// DeleteSymmetricKey deletes the symmetric key associated with the given identifier. +func (wc *WhisperClient) DeleteSymmetricKey(ctx *Context, id string) error { + return wc.client.DeleteSymmetricKey(ctx.context, id) +} + +// Post a message onto the network. +func (wc *WhisperClient) Post(ctx *Context, message *NewMessage) (string, error) { + return wc.client.Post(ctx.context, *message.newMessage) +} + +// NewHeadHandler is a client-side subscription callback to invoke on events and +// subscription failure. +type NewMessageHandler interface { + OnNewMessage(message *Message) + OnError(failure string) +} + +// SubscribeMessages subscribes to messages that match the given criteria. This method +// is only supported on bi-directional connections such as websockets and IPC. +// NewMessageFilter uses polling and is supported over HTTP. +func (wc *WhisperClient) SubscribeMessages(ctx *Context, criteria *Criteria, handler NewMessageHandler, buffer int) (*Subscription, error) { + // Subscribe to the event internally + ch := make(chan *whisper.Message, buffer) + rawSub, err := wc.client.SubscribeMessages(ctx.context, *criteria.criteria, ch) + if err != nil { + return nil, err + } + // Start up a dispatcher to feed into the callback + go func() { + for { + select { + case message := <-ch: + handler.OnNewMessage(&Message{message}) + + case err := <-rawSub.Err(): + if err != nil { + handler.OnError(err.Error()) + } + return + } + } + }() + return &Subscription{rawSub}, nil +} + +// NewMessageFilter creates a filter within the node. This filter can be used to poll +// for new messages (see FilterMessages) that satisfy the given criteria. A filter can +// timeout when it was polled for in whisper.filterTimeout. +func (wc *WhisperClient) NewMessageFilter(ctx *Context, criteria *Criteria) (string, error) { + return wc.client.NewMessageFilter(ctx.context, *criteria.criteria) +} + +// DeleteMessageFilter removes the filter associated with the given id. +func (wc *WhisperClient) DeleteMessageFilter(ctx *Context, id string) error { + return wc.client.DeleteMessageFilter(ctx.context, id) +} + +// GetFilterMessages retrieves all messages that are received between the last call to +// this function and match the criteria that where given when the filter was created. +func (wc *WhisperClient) GetFilterMessages(ctx *Context, id string) (*Messages, error) { + rawFilterMessages, err := wc.client.FilterMessages(ctx.context, id) + if err != nil { + return nil, err + } + res := make([]*whisper.Message, len(rawFilterMessages)) + copy(res, rawFilterMessages) + return &Messages{res}, nil +} diff --git a/mobile/types.go b/mobile/types.go index 4790afceff..1a0389cb54 100644 --- a/mobile/types.go +++ b/mobile/types.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" + whisper "github.com/ethereum/go-ethereum/whisper/whisperv6" ) // A Nonce is a 64-bit hash which proves (combined with the mix-hash) that @@ -80,7 +81,7 @@ func (h *Header) EncodeRLP() ([]byte, error) { return rlp.EncodeToBytes(h.header) } -// NewHeaderFromJSON parses a header from an JSON data dump. +// NewHeaderFromJSON parses a header from a JSON data dump. func NewHeaderFromJSON(data string) (*Header, error) { h := &Header{ header: new(types.Header), @@ -91,18 +92,12 @@ func NewHeaderFromJSON(data string) (*Header, error) { return h, nil } -// EncodeJSON encodes a header into an JSON data dump. +// EncodeJSON encodes a header into a JSON data dump. func (h *Header) EncodeJSON() (string, error) { data, err := json.Marshal(h.header) return string(data), err } -// String implements the fmt.Stringer interface to print some semi-meaningful -// data dump of the header for debugging purposes. -func (h *Header) String() string { - return h.header.String() -} - func (h *Header) GetParentHash() *Hash { return &Hash{h.header.ParentHash} } func (h *Header) GetUncleHash() *Hash { return &Hash{h.header.UncleHash} } func (h *Header) GetCoinbase() *Address { return &Address{h.header.Coinbase} } @@ -157,7 +152,7 @@ func (b *Block) EncodeRLP() ([]byte, error) { return rlp.EncodeToBytes(b.block) } -// NewBlockFromJSON parses a block from an JSON data dump. +// NewBlockFromJSON parses a block from a JSON data dump. func NewBlockFromJSON(data string) (*Block, error) { b := &Block{ block: new(types.Block), @@ -168,37 +163,28 @@ func NewBlockFromJSON(data string) (*Block, error) { return b, nil } -// EncodeJSON encodes a block into an JSON data dump. +// EncodeJSON encodes a block into a JSON data dump. func (b *Block) EncodeJSON() (string, error) { data, err := json.Marshal(b.block) return string(data), err } -// String implements the fmt.Stringer interface to print some semi-meaningful -// data dump of the block for debugging purposes. -func (b *Block) String() string { - return b.block.String() -} - -func (b *Block) GetParentHash() *Hash { return &Hash{b.block.ParentHash()} } -func (b *Block) GetUncleHash() *Hash { return &Hash{b.block.UncleHash()} } -func (b *Block) GetCoinbase() *Address { return &Address{b.block.Coinbase()} } -func (b *Block) GetRoot() *Hash { return &Hash{b.block.Root()} } -func (b *Block) GetTxHash() *Hash { return &Hash{b.block.TxHash()} } -func (b *Block) GetReceiptHash() *Hash { return &Hash{b.block.ReceiptHash()} } -func (b *Block) GetBloom() *Bloom { return &Bloom{b.block.Bloom()} } -func (b *Block) GetDifficulty() *BigInt { return &BigInt{b.block.Difficulty()} } -func (b *Block) GetNumber() int64 { return b.block.Number().Int64() } -func (b *Block) GetGasLimit() int64 { return int64(b.block.GasLimit()) } -func (b *Block) GetGasUsed() int64 { return int64(b.block.GasUsed()) } -func (b *Block) GetTime() int64 { return b.block.Time().Int64() } -func (b *Block) GetExtra() []byte { return b.block.Extra() } -func (b *Block) GetMixDigest() *Hash { return &Hash{b.block.MixDigest()} } -func (b *Block) GetNonce() int64 { return int64(b.block.Nonce()) } - -func (b *Block) GetHash() *Hash { return &Hash{b.block.Hash()} } -func (b *Block) GetHashNoNonce() *Hash { return &Hash{b.block.HashNoNonce()} } - +func (b *Block) GetParentHash() *Hash { return &Hash{b.block.ParentHash()} } +func (b *Block) GetUncleHash() *Hash { return &Hash{b.block.UncleHash()} } +func (b *Block) GetCoinbase() *Address { return &Address{b.block.Coinbase()} } +func (b *Block) GetRoot() *Hash { return &Hash{b.block.Root()} } +func (b *Block) GetTxHash() *Hash { return &Hash{b.block.TxHash()} } +func (b *Block) GetReceiptHash() *Hash { return &Hash{b.block.ReceiptHash()} } +func (b *Block) GetBloom() *Bloom { return &Bloom{b.block.Bloom()} } +func (b *Block) GetDifficulty() *BigInt { return &BigInt{b.block.Difficulty()} } +func (b *Block) GetNumber() int64 { return b.block.Number().Int64() } +func (b *Block) GetGasLimit() int64 { return int64(b.block.GasLimit()) } +func (b *Block) GetGasUsed() int64 { return int64(b.block.GasUsed()) } +func (b *Block) GetTime() int64 { return b.block.Time().Int64() } +func (b *Block) GetExtra() []byte { return b.block.Extra() } +func (b *Block) GetMixDigest() *Hash { return &Hash{b.block.MixDigest()} } +func (b *Block) GetNonce() int64 { return int64(b.block.Nonce()) } +func (b *Block) GetHash() *Hash { return &Hash{b.block.Hash()} } func (b *Block) GetHeader() *Header { return &Header{b.block.Header()} } func (b *Block) GetUncles() *Headers { return &Headers{b.block.Uncles()} } func (b *Block) GetTransactions() *Transactions { return &Transactions{b.block.Transactions()} } @@ -211,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))} } @@ -232,7 +228,7 @@ func (tx *Transaction) EncodeRLP() ([]byte, error) { return rlp.EncodeToBytes(tx.tx) } -// NewTransactionFromJSON parses a transaction from an JSON data dump. +// NewTransactionFromJSON parses a transaction from a JSON data dump. func NewTransactionFromJSON(data string) (*Transaction, error) { tx := &Transaction{ tx: new(types.Transaction), @@ -243,18 +239,12 @@ func NewTransactionFromJSON(data string) (*Transaction, error) { return tx, nil } -// EncodeJSON encodes a transaction into an JSON data dump. +// EncodeJSON encodes a transaction into a JSON data dump. func (tx *Transaction) EncodeJSON() (string, error) { data, err := json.Marshal(tx.tx) return string(data), err } -// String implements the fmt.Stringer interface to print some semi-meaningful -// data dump of the transaction for debugging purposes. -func (tx *Transaction) String() string { - return tx.tx.String() -} - func (tx *Transaction) GetData() []byte { return tx.tx.Data() } func (tx *Transaction) GetGas() int64 { return int64(tx.tx.Gas()) } func (tx *Transaction) GetGasPrice() *BigInt { return &BigInt{tx.tx.GasPrice()} } @@ -330,7 +320,7 @@ func (r *Receipt) EncodeRLP() ([]byte, error) { return rlp.EncodeToBytes(r.receipt) } -// NewReceiptFromJSON parses a transaction receipt from an JSON data dump. +// NewReceiptFromJSON parses a transaction receipt from a JSON data dump. func NewReceiptFromJSON(data string) (*Receipt, error) { r := &Receipt{ receipt: new(types.Receipt), @@ -341,18 +331,13 @@ func NewReceiptFromJSON(data string) (*Receipt, error) { return r, nil } -// EncodeJSON encodes a transaction receipt into an JSON data dump. +// EncodeJSON encodes a transaction receipt into a JSON data dump. func (r *Receipt) EncodeJSON() (string, error) { data, err := rlp.EncodeToBytes(r.receipt) return string(data), err } -// String implements the fmt.Stringer interface to print some semi-meaningful -// data dump of the transaction receipt for debugging purposes. -func (r *Receipt) String() string { - return r.receipt.String() -} - +func (r *Receipt) GetStatus() int { return int(r.receipt.Status) } func (r *Receipt) GetPostState() []byte { return r.receipt.PostState } func (r *Receipt) GetCumulativeGasUsed() int64 { return int64(r.receipt.CumulativeGasUsed) } func (r *Receipt) GetBloom() *Bloom { return &Bloom{r.receipt.Bloom} } @@ -360,3 +345,95 @@ func (r *Receipt) GetLogs() *Logs { return &Logs{r.receipt.Logs} } func (r *Receipt) GetTxHash() *Hash { return &Hash{r.receipt.TxHash} } func (r *Receipt) GetContractAddress() *Address { return &Address{r.receipt.ContractAddress} } func (r *Receipt) GetGasUsed() int64 { return int64(r.receipt.GasUsed) } + +// Info represents a diagnostic information about the whisper node. +type Info struct { + info *whisper.Info +} + +// NewMessage represents a new whisper message that is posted through the RPC. +type NewMessage struct { + newMessage *whisper.NewMessage +} + +func NewNewMessage() *NewMessage { + nm := &NewMessage{ + newMessage: new(whisper.NewMessage), + } + return nm +} + +func (nm *NewMessage) GetSymKeyID() string { return nm.newMessage.SymKeyID } +func (nm *NewMessage) SetSymKeyID(symKeyID string) { nm.newMessage.SymKeyID = symKeyID } +func (nm *NewMessage) GetPublicKey() []byte { return nm.newMessage.PublicKey } +func (nm *NewMessage) SetPublicKey(publicKey []byte) { + nm.newMessage.PublicKey = common.CopyBytes(publicKey) +} +func (nm *NewMessage) GetSig() string { return nm.newMessage.Sig } +func (nm *NewMessage) SetSig(sig string) { nm.newMessage.Sig = sig } +func (nm *NewMessage) GetTTL() int64 { return int64(nm.newMessage.TTL) } +func (nm *NewMessage) SetTTL(ttl int64) { nm.newMessage.TTL = uint32(ttl) } +func (nm *NewMessage) GetPayload() []byte { return nm.newMessage.Payload } +func (nm *NewMessage) SetPayload(payload []byte) { nm.newMessage.Payload = common.CopyBytes(payload) } +func (nm *NewMessage) GetPowTime() int64 { return int64(nm.newMessage.PowTime) } +func (nm *NewMessage) SetPowTime(powTime int64) { nm.newMessage.PowTime = uint32(powTime) } +func (nm *NewMessage) GetPowTarget() float64 { return nm.newMessage.PowTarget } +func (nm *NewMessage) SetPowTarget(powTarget float64) { nm.newMessage.PowTarget = powTarget } +func (nm *NewMessage) GetTargetPeer() string { return nm.newMessage.TargetPeer } +func (nm *NewMessage) SetTargetPeer(targetPeer string) { nm.newMessage.TargetPeer = targetPeer } +func (nm *NewMessage) GetTopic() []byte { return nm.newMessage.Topic[:] } +func (nm *NewMessage) SetTopic(topic []byte) { nm.newMessage.Topic = whisper.BytesToTopic(topic) } + +// Message represents a whisper message. +type Message struct { + message *whisper.Message +} + +func (m *Message) GetSig() []byte { return m.message.Sig } +func (m *Message) GetTTL() int64 { return int64(m.message.TTL) } +func (m *Message) GetTimestamp() int64 { return int64(m.message.Timestamp) } +func (m *Message) GetPayload() []byte { return m.message.Payload } +func (m *Message) GetPoW() float64 { return m.message.PoW } +func (m *Message) GetHash() []byte { return m.message.Hash } +func (m *Message) GetDst() []byte { return m.message.Dst } + +// Messages represents an array of messages. +type Messages struct { + messages []*whisper.Message +} + +// Size returns the number of messages in the slice. +func (m *Messages) Size() int { + return len(m.messages) +} + +// Get returns the message at the given index from the slice. +func (m *Messages) Get(index int) (message *Message, _ error) { + if index < 0 || index >= len(m.messages) { + return nil, errors.New("index out of bounds") + } + return &Message{m.messages[index]}, nil +} + +// Criteria holds various filter options for inbound messages. +type Criteria struct { + criteria *whisper.Criteria +} + +func NewCriteria(topic []byte) *Criteria { + c := &Criteria{ + criteria: new(whisper.Criteria), + } + encodedTopic := whisper.BytesToTopic(topic) + c.criteria.Topics = []whisper.TopicType{encodedTopic} + return c +} + +func (c *Criteria) GetSymKeyID() string { return c.criteria.SymKeyID } +func (c *Criteria) SetSymKeyID(symKeyID string) { c.criteria.SymKeyID = symKeyID } +func (c *Criteria) GetPrivateKeyID() string { return c.criteria.PrivateKeyID } +func (c *Criteria) SetPrivateKeyID(privateKeyID string) { c.criteria.PrivateKeyID = privateKeyID } +func (c *Criteria) GetSig() []byte { return c.criteria.Sig } +func (c *Criteria) SetSig(sig []byte) { c.criteria.Sig = common.CopyBytes(sig) } +func (c *Criteria) GetMinPow() float64 { return c.criteria.MinPow } +func (c *Criteria) SetMinPow(pow float64) { c.criteria.MinPow = pow } diff --git a/node/api.go b/node/api.go index 1b04b70938..6e36e505d1 100644 --- a/node/api.go +++ b/node/api.go @@ -24,10 +24,10 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/discover" + "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/rpc" - "github.com/rcrowley/go-metrics" ) // PrivateAdminAPI is the collection of administrative API methods exposed only @@ -51,7 +51,7 @@ func (api *PrivateAdminAPI) AddPeer(url string) (bool, error) { return false, ErrNodeStopped } // Try to add the url as a static peer and return - node, err := discover.ParseNode(url) + node, err := enode.ParseV4(url) if err != nil { return false, fmt.Errorf("invalid enode: %v", err) } @@ -59,7 +59,7 @@ func (api *PrivateAdminAPI) AddPeer(url string) (bool, error) { return true, nil } -// RemovePeer disconnects from a a remote node if the connection exists +// RemovePeer disconnects from a remote node if the connection exists func (api *PrivateAdminAPI) RemovePeer(url string) (bool, error) { // Make sure the server is running, fail otherwise server := api.node.Server() @@ -67,7 +67,7 @@ func (api *PrivateAdminAPI) RemovePeer(url string) (bool, error) { return false, ErrNodeStopped } // Try to remove the url as a static peer and return - node, err := discover.ParseNode(url) + node, err := enode.ParseV4(url) if err != nil { return false, fmt.Errorf("invalid enode: %v", err) } @@ -75,6 +75,37 @@ func (api *PrivateAdminAPI) RemovePeer(url string) (bool, error) { return true, nil } +// AddTrustedPeer allows a remote node to always connect, even if slots are full +func (api *PrivateAdminAPI) AddTrustedPeer(url string) (bool, error) { + // Make sure the server is running, fail otherwise + server := api.node.Server() + if server == nil { + return false, ErrNodeStopped + } + node, err := enode.ParseV4(url) + if err != nil { + return false, fmt.Errorf("invalid enode: %v", err) + } + server.AddTrustedPeer(node) + return true, nil +} + +// RemoveTrustedPeer removes a remote node from the trusted peer set, but it +// does not disconnect it automatically. +func (api *PrivateAdminAPI) RemoveTrustedPeer(url string) (bool, error) { + // Make sure the server is running, fail otherwise + server := api.node.Server() + if server == nil { + return false, ErrNodeStopped + } + node, err := enode.ParseV4(url) + if err != nil { + return false, fmt.Errorf("invalid enode: %v", err) + } + server.RemoveTrustedPeer(node) + return true, nil +} + // PeerEvents creates an RPC subscription which receives peer events from the // node's p2p.Server func (api *PrivateAdminAPI) PeerEvents(ctx context.Context) (*rpc.Subscription, error) { @@ -114,7 +145,7 @@ func (api *PrivateAdminAPI) PeerEvents(ctx context.Context) (*rpc.Subscription, } // StartRPC starts the HTTP RPC API server. -func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis *string) (bool, error) { +func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis *string, vhosts *string) (bool, error) { api.node.lock.Lock() defer api.node.lock.Unlock() @@ -141,6 +172,14 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis } } + allowedVHosts := api.node.config.HTTPVirtualHosts + if vhosts != nil { + allowedVHosts = nil + for _, vhost := range strings.Split(*host, ",") { + allowedVHosts = append(allowedVHosts, strings.TrimSpace(vhost)) + } + } + modules := api.node.httpWhitelist if apis != nil { modules = nil @@ -149,7 +188,7 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis } } - if err := api.node.startHTTP(fmt.Sprintf("%s:%d", *host, *port), api.node.rpcAPIs, modules, allowedOrigins); err != nil { + if err := api.node.startHTTP(fmt.Sprintf("%s:%d", *host, *port), api.node.rpcAPIs, modules, allowedOrigins, allowedVHosts, api.node.config.HTTPTimeouts); err != nil { return false, err } return true, nil @@ -209,7 +248,7 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str return true, nil } -// StopRPC terminates an already running websocket RPC API endpoint. +// StopWS terminates an already running websocket RPC API endpoint. func (api *PrivateAdminAPI) StopWS() (bool, error) { api.node.lock.Lock() defer api.node.lock.Unlock() @@ -300,6 +339,11 @@ func (api *PublicDebugAPI) Metrics(raw bool) (map[string]interface{}, error) { // Fill the counter with the metric details, formatting if requested if raw { switch metric := metric.(type) { + case metrics.Counter: + root[name] = map[string]interface{}{ + "Overall": float64(metric.Count()), + } + case metrics.Meter: root[name] = map[string]interface{}{ "AvgRate01Min": metric.Rate1(), @@ -325,11 +369,31 @@ func (api *PublicDebugAPI) Metrics(raw bool) (map[string]interface{}, error) { }, } + case metrics.ResettingTimer: + t := metric.Snapshot() + ps := t.Percentiles([]float64{5, 20, 50, 80, 95}) + root[name] = map[string]interface{}{ + "Measurements": len(t.Values()), + "Mean": t.Mean(), + "Percentiles": map[string]interface{}{ + "5": ps[0], + "20": ps[1], + "50": ps[2], + "80": ps[3], + "95": ps[4], + }, + } + default: root[name] = "Unknown metric type" } } else { switch metric := metric.(type) { + case metrics.Counter: + root[name] = map[string]interface{}{ + "Overall": float64(metric.Count()), + } + case metrics.Meter: root[name] = map[string]interface{}{ "Avg01Min": format(metric.Rate1()*60, metric.Rate1()), @@ -355,6 +419,21 @@ func (api *PublicDebugAPI) Metrics(raw bool) (map[string]interface{}, error) { }, } + case metrics.ResettingTimer: + t := metric.Snapshot() + ps := t.Percentiles([]float64{5, 20, 50, 80, 95}) + root[name] = map[string]interface{}{ + "Measurements": len(t.Values()), + "Mean": time.Duration(t.Mean()).String(), + "Percentiles": map[string]interface{}{ + "5": time.Duration(ps[0]).String(), + "20": time.Duration(ps[1]).String(), + "50": time.Duration(ps[2]).String(), + "80": time.Duration(ps[3]).String(), + "95": time.Duration(ps[4]).String(), + }, + } + default: root[name] = "Unknown metric type" } diff --git a/node/config.go b/node/config.go index 7a0c1688ec..2f871e478b 100644 --- a/node/config.go +++ b/node/config.go @@ -24,15 +24,18 @@ 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" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/discover" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/rpc" ) const ( @@ -78,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"` @@ -100,16 +106,52 @@ 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. HTTPCors []string `toml:",omitempty"` + // HTTPVirtualHosts 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 + HTTPVirtualHosts []string `toml:",omitempty"` + // HTTPModules is a list of API modules to expose via the HTTP RPC interface. // If the module list is empty, all RPC API endpoints designated public will be // exposed. HTTPModules []string `toml:",omitempty"` + // HTTPTimeouts allows for customization of the timeout values used by the HTTP RPC + // interface. + HTTPTimeouts rpc.HTTPTimeouts + // WSHost is the host interface on which to start the websocket RPC server. If // this field is empty, no websocket API endpoint will be started. WSHost string `toml:",omitempty"` @@ -137,7 +179,11 @@ type Config struct { WSExposeAll bool `toml:",omitempty"` // Logger is a custom logger to use with the p2p.Server. - Logger log.Logger + Logger log.Logger `toml:",omitempty"` + + staticNodesWarning bool + trustedNodesWarning bool + oldGethResourceWarning bool } // IPCEndpoint resolves an IPC endpoint based on a configured value, taking into @@ -170,7 +216,7 @@ func (c *Config) NodeDB() string { if c.DataDir == "" { return "" // ephemeral } - return c.resolvePath(datadirNodeDatabase) + return c.ResolvePath(datadirNodeDatabase) } // DefaultIPCEndpoint returns the IPC path used by default. @@ -194,13 +240,22 @@ 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} return config.HTTPEndpoint() } -// WSEndpoint resolves an websocket endpoint based on the configured host interface +// WSEndpoint resolves a websocket endpoint based on the configured host interface // and port parameters. func (c *Config) WSEndpoint() string { if c.WSHost == "" { @@ -249,12 +304,12 @@ 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. -func (c *Config) resolvePath(path string) string { +// ResolvePath resolves path in the instance directory. +func (c *Config) ResolvePath(path string) string { if filepath.IsAbs(path) { return path } @@ -263,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 } } @@ -300,7 +357,7 @@ func (c *Config) NodeKey() *ecdsa.PrivateKey { return key } - keyfile := c.resolvePath(datadirPrivateKey) + keyfile := c.ResolvePath(datadirPrivateKey) if key, err := crypto.LoadECDSA(keyfile); err == nil { return key } @@ -322,18 +379,18 @@ func (c *Config) NodeKey() *ecdsa.PrivateKey { } // StaticNodes returns a list of node enode URLs configured as static nodes. -func (c *Config) StaticNodes() []*discover.Node { - return c.parsePersistentNodes(c.resolvePath(datadirStaticNodes)) +func (c *Config) StaticNodes() []*enode.Node { + return c.parsePersistentNodes(&c.staticNodesWarning, c.ResolvePath(datadirStaticNodes)) } // TrustedNodes returns a list of node enode URLs configured as trusted nodes. -func (c *Config) TrustedNodes() []*discover.Node { - return c.parsePersistentNodes(c.resolvePath(datadirTrustedNodes)) +func (c *Config) TrustedNodes() []*enode.Node { + 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) []*discover.Node { +func (c *Config) parsePersistentNodes(w *bool, path string) []*enode.Node { // Short circuit if no node config is present if c.DataDir == "" { return nil @@ -341,19 +398,21 @@ func (c *Config) parsePersistentNodes(path string) []*discover.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 - var nodes []*discover.Node + var nodes []*enode.Node for _, url := range nodelist { if url == "" { continue } - node, err := discover.ParseNode(url) + node, err := enode.ParseV4(url) if err != nil { log.Error(fmt.Sprintf("Node URL %s: %v\n", url, err)) continue @@ -407,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/node/config_test.go b/node/config_test.go index b81d3d6120..00c24a2391 100644 --- a/node/config_test.go +++ b/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/node/defaults.go b/node/defaults.go index d4e1486834..71e7633460 100644 --- a/node/defaults.go +++ b/node/defaults.go @@ -24,22 +24,27 @@ import ( "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/nat" + "github.com/ethereum/go-ethereum/rpc" ) 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. var DefaultConfig = Config{ - DataDir: DefaultDataDir(), - HTTPPort: DefaultHTTPPort, - HTTPModules: []string{"net", "web3"}, - WSPort: DefaultWSPort, - WSModules: []string{"net", "web3"}, + DataDir: DefaultDataDir(), + HTTPPort: DefaultHTTPPort, + HTTPModules: []string{"net", "web3"}, + HTTPVirtualHosts: []string{"localhost"}, + HTTPTimeouts: rpc.DefaultHTTPTimeouts, + WSPort: DefaultWSPort, + WSModules: []string{"net", "web3"}, P2P: p2p.Config{ ListenAddr: ":30303", MaxPeers: 25, @@ -53,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") } } @@ -65,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/node/doc.go b/node/doc.go index d9688e0a12..e3cc58e5f4 100644 --- a/node/doc.go +++ b/node/doc.go @@ -59,7 +59,7 @@ using the same data directory will store this information in different subdirect the data directory. LevelDB databases are also stored within the instance subdirectory. If multiple node -instances use the same data directory, openening the databases with identical names will +instances use the same data directory, opening the databases with identical names will create one database for each instance. The account key store is shared among all node instances using the same data directory @@ -69,7 +69,7 @@ unless its location is changed through the KeyStoreDir configuration option. Data Directory Sharing Example In this example, two node instances named A and B are started with the same data -directory. Mode instance A opens the database "db", node instance B opens the databases +directory. Node instance A opens the database "db", node instance B opens the databases "db" and "db-2". The following files will be created in the data directory: data-directory/ @@ -84,7 +84,7 @@ directory. Mode instance A opens the database "db", node instance B opens the da static-nodes.json -- devp2p static node list of instance B db/ -- LevelDB content for "db" db-2/ -- LevelDB content for "db-2" - B.ipc -- JSON-RPC UNIX domain socket endpoint of instance A + B.ipc -- JSON-RPC UNIX domain socket endpoint of instance B keystore/ -- account key store, used by both instances */ package node diff --git a/node/node.go b/node/node.go index ff7258033e..9227bf6bb0 100644 --- a/node/node.go +++ b/node/node.go @@ -121,6 +121,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 +220,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 { @@ -263,7 +286,7 @@ func (n *Node) startRPC(services map[reflect.Type]Service) error { n.stopInProc() return err } - if err := n.startHTTP(n.httpEndpoint, apis, n.config.HTTPModules, n.config.HTTPCors); err != nil { + if err := n.startHTTP(n.httpEndpoint, apis, n.config.HTTPModules, n.config.HTTPCors, n.config.HTTPVirtualHosts, n.config.HTTPTimeouts); err != nil { n.stopIPC() n.stopInProc() return err @@ -287,7 +310,7 @@ func (n *Node) startInProc(apis []rpc.API) error { if err := handler.RegisterName(api.Namespace, api.Service); err != nil { return err } - n.log.Debug(fmt.Sprintf("InProc registered %T under '%s'", api.Service, api.Namespace)) + n.log.Debug("InProc registered", "namespace", api.Namespace) } n.inprocHandler = handler return nil @@ -303,50 +326,16 @@ func (n *Node) stopInProc() { // startIPC initializes and starts the IPC RPC endpoint. func (n *Node) startIPC(apis []rpc.API) error { - // Short circuit if the IPC endpoint isn't being exposed if n.ipcEndpoint == "" { - return nil + return nil // IPC disabled. } - // Register all the APIs exposed by the services - handler := rpc.NewServer() - for _, api := range apis { - if err := handler.RegisterName(api.Namespace, api.Service); err != nil { - return err - } - n.log.Debug(fmt.Sprintf("IPC registered %T under '%s'", api.Service, api.Namespace)) - } - // All APIs registered, start the IPC listener - var ( - listener net.Listener - err error - ) - if listener, err = rpc.CreateIPCListener(n.ipcEndpoint); err != nil { + listener, handler, err := rpc.StartIPCEndpoint(n.ipcEndpoint, apis) + if err != nil { return err } - go func() { - n.log.Info(fmt.Sprintf("IPC endpoint opened: %s", n.ipcEndpoint)) - - for { - conn, err := listener.Accept() - if err != nil { - // Terminate if the listener was closed - n.lock.RLock() - closed := n.ipcListener == nil - n.lock.RUnlock() - if closed { - return - } - // Not closed, just some error; report and continue - n.log.Error(fmt.Sprintf("IPC accept failed: %v", err)) - continue - } - go handler.ServeCodec(rpc.NewJSONCodec(conn), rpc.OptionMethodInvocation|rpc.OptionSubscriptions) - } - }() - // All listeners booted successfully n.ipcListener = listener n.ipcHandler = handler - + n.log.Info("IPC endpoint opened", "url", n.ipcEndpoint) return nil } @@ -356,7 +345,7 @@ func (n *Node) stopIPC() { n.ipcListener.Close() n.ipcListener = nil - n.log.Info(fmt.Sprintf("IPC endpoint closed: %s", n.ipcEndpoint)) + n.log.Info("IPC endpoint closed", "url", n.ipcEndpoint) } if n.ipcHandler != nil { n.ipcHandler.Stop() @@ -365,37 +354,16 @@ func (n *Node) stopIPC() { } // startHTTP initializes and starts the HTTP RPC endpoint. -func (n *Node) startHTTP(endpoint string, apis []rpc.API, modules []string, cors []string) error { +func (n *Node) startHTTP(endpoint string, apis []rpc.API, modules []string, cors []string, vhosts []string, timeouts rpc.HTTPTimeouts) error { // Short circuit if the HTTP endpoint isn't being exposed if endpoint == "" { return nil } - // Generate the whitelist based on the allowed modules - whitelist := make(map[string]bool) - for _, module := range modules { - whitelist[module] = true - } - // Register all the APIs exposed by the services - handler := rpc.NewServer() - for _, api := range apis { - if whitelist[api.Namespace] || (len(whitelist) == 0 && api.Public) { - if err := handler.RegisterName(api.Namespace, api.Service); err != nil { - return err - } - n.log.Debug(fmt.Sprintf("HTTP registered %T under '%s'", api.Service, api.Namespace)) - } - } - // All APIs registered, start the HTTP listener - var ( - listener net.Listener - err error - ) - if listener, err = net.Listen("tcp", endpoint); err != nil { + listener, handler, err := rpc.StartHTTPEndpoint(endpoint, apis, modules, cors, vhosts, timeouts) + if err != nil { return err } - go rpc.NewHTTPServer(cors, handler).Serve(listener) - n.log.Info(fmt.Sprintf("HTTP endpoint opened: http://%s", endpoint)) - + n.log.Info("HTTP endpoint opened", "url", fmt.Sprintf("http://%s", endpoint), "cors", strings.Join(cors, ","), "vhosts", strings.Join(vhosts, ",")) // All listeners booted successfully n.httpEndpoint = endpoint n.httpListener = listener @@ -410,7 +378,7 @@ func (n *Node) stopHTTP() { n.httpListener.Close() n.httpListener = nil - n.log.Info(fmt.Sprintf("HTTP endpoint closed: http://%s", n.httpEndpoint)) + n.log.Info("HTTP endpoint closed", "url", fmt.Sprintf("http://%s", n.httpEndpoint)) } if n.httpHandler != nil { n.httpHandler.Stop() @@ -424,32 +392,11 @@ func (n *Node) startWS(endpoint string, apis []rpc.API, modules []string, wsOrig if endpoint == "" { return nil } - // Generate the whitelist based on the allowed modules - whitelist := make(map[string]bool) - for _, module := range modules { - whitelist[module] = true - } - // Register all the APIs exposed by the services - handler := rpc.NewServer() - for _, api := range apis { - if exposeAll || whitelist[api.Namespace] || (len(whitelist) == 0 && api.Public) { - if err := handler.RegisterName(api.Namespace, api.Service); err != nil { - return err - } - n.log.Debug(fmt.Sprintf("WebSocket registered %T under '%s'", api.Service, api.Namespace)) - } - } - // All APIs registered, start the HTTP listener - var ( - listener net.Listener - err error - ) - if listener, err = net.Listen("tcp", endpoint); err != nil { + listener, handler, err := rpc.StartWSEndpoint(endpoint, apis, modules, wsOrigins, exposeAll) + if err != nil { return err } - go rpc.NewWSServer(wsOrigins, handler).Serve(listener) - n.log.Info(fmt.Sprintf("WebSocket endpoint opened: ws://%s", listener.Addr())) - + n.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%s", listener.Addr())) // All listeners booted successfully n.wsEndpoint = endpoint n.wsListener = listener @@ -464,7 +411,7 @@ func (n *Node) stopWS() { n.wsListener.Close() n.wsListener = nil - n.log.Info(fmt.Sprintf("WebSocket endpoint closed: ws://%s", n.wsEndpoint)) + n.log.Info("WebSocket endpoint closed", "url", fmt.Sprintf("ws://%s", n.wsEndpoint)) } if n.wsHandler != nil { n.wsHandler.Stop() @@ -625,11 +572,23 @@ func (n *Node) IPCEndpoint() string { // HTTPEndpoint retrieves the current HTTP endpoint used by the protocol stack. func (n *Node) HTTPEndpoint() string { + n.lock.Lock() + defer n.lock.Unlock() + + if n.httpListener != nil { + return n.httpListener.Addr().String() + } return n.httpEndpoint } // WSEndpoint retrieves the current WS endpoint used by the protocol stack. func (n *Node) WSEndpoint() string { + n.lock.Lock() + defer n.lock.Unlock() + + if n.wsListener != nil { + return n.wsListener.Addr().String() + } return n.wsEndpoint } @@ -644,14 +603,14 @@ func (n *Node) EventMux() *event.TypeMux { // ephemeral, a memory database is returned. func (n *Node) OpenDatabase(name string, cache, handles int) (ethdb.Database, error) { if n.config.DataDir == "" { - return ethdb.NewMemDatabase() + return ethdb.NewMemDatabase(), nil } - return ethdb.NewLDBDatabase(n.config.resolvePath(name), cache, handles) + return ethdb.NewLDBDatabase(n.config.ResolvePath(name), cache, handles) } // ResolvePath returns the absolute path of a resource in the instance directory. func (n *Node) ResolvePath(x string) string { - return n.config.resolvePath(x) + return n.config.ResolvePath(x) } // apis returns the collection of RPC descriptors this node offers. diff --git a/node/node_example_test.go b/node/node_example_test.go index ee06f4065c..57b18855f1 100644 --- a/node/node_example_test.go +++ b/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/node/node_test.go b/node/node_test.go index 2880efa619..c464771cd8 100644 --- a/node/node_test.go +++ b/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,14 +469,16 @@ 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 Maker InstrumentingWrapper }{ - "Zero Protocols": {0, InstrumentedServiceMakerA}, - "Single Protocol": {1, InstrumentedServiceMakerB}, - "Many Protocols": {25, InstrumentedServiceMakerC}, + "zero": {0, InstrumentedServiceMakerA}, + "one": {1, InstrumentedServiceMakerB}, + "many": {10, InstrumentedServiceMakerC}, } for id, config := range services { protocols := make([]p2p.Protocol, config.Count) @@ -480,7 +502,7 @@ func TestProtocolGather(t *testing.T) { defer stack.Stop() protocols := stack.Server().Protocols - if len(protocols) != 26 { + if len(protocols) != 11 { t.Fatalf("mismatching number of protocols launched: have %d, want %d", len(protocols), 26) } for id, config := range services { @@ -505,10 +527,12 @@ 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 { - return &OneMethodApi{fun: func() { calls <- result }} + makeAPI := func(result string) *OneMethodAPI { + return &OneMethodAPI{fun: func() { calls <- result }} } services := map[string]struct { APIs []rpc.API diff --git a/node/service.go b/node/service.go index 55062a5004..6a96d9b1e1 100644 --- a/node/service.go +++ b/node/service.go @@ -41,9 +41,9 @@ type ServiceContext struct { // node is an ephemeral one, a memory database is returned. func (ctx *ServiceContext) OpenDatabase(name string, cache int, handles int) (ethdb.Database, error) { if ctx.config.DataDir == "" { - return ethdb.NewMemDatabase() + return ethdb.NewMemDatabase(), nil } - db, err := ethdb.NewLDBDatabase(ctx.config.resolvePath(name), cache, handles) + db, err := ethdb.NewLDBDatabase(ctx.config.ResolvePath(name), cache, handles) if err != nil { return nil, err } @@ -54,7 +54,7 @@ func (ctx *ServiceContext) OpenDatabase(name string, cache int, handles int) (et // and if the user actually uses persistent storage. It will return an empty string // for emphemeral storage and the user's own input for absolute paths. func (ctx *ServiceContext) ResolvePath(path string) string { - return ctx.config.resolvePath(path) + return ctx.config.ResolvePath(path) } // Service retrieves a currently running service registered of a specific type. diff --git a/node/service_test.go b/node/service_test.go index a7ae439e0a..73c51eccbb 100644 --- a/node/service_test.go +++ b/node/service_test.go @@ -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/node/utils_test.go b/node/utils_test.go index 8eddce3ed7..9801b1ed45 100644 --- a/node/utils_test.go +++ b/node/utils_test.go @@ -121,12 +121,12 @@ func InstrumentedServiceMakerC(base ServiceConstructor) ServiceConstructor { return InstrumentingWrapperMaker(base, reflect.TypeOf(InstrumentedServiceC{})) } -// OneMethodApi is a single-method API handler to be returned by test services. -type OneMethodApi struct { +// OneMethodAPI is a single-method API handler to be returned by test services. +type OneMethodAPI struct { fun func() } -func (api *OneMethodApi) TheOneMethod() { +func (api *OneMethodAPI) TheOneMethod() { if api.fun != nil { api.fun() } diff --git a/p2p/dial.go b/p2p/dial.go index f5ff2c2117..075a0f9368 100644 --- a/p2p/dial.go +++ b/p2p/dial.go @@ -18,14 +18,13 @@ package p2p import ( "container/heap" - "crypto/rand" "errors" "fmt" "net" "time" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/p2p/discover" + "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/netutil" ) @@ -50,7 +49,7 @@ const ( // NodeDialer is used to connect to nodes in the network, typically by using // an underlying net.Dialer but also using net.Pipe in tests type NodeDialer interface { - Dial(*discover.Node) (net.Conn, error) + Dial(*enode.Node) (net.Conn, error) } // TCPDialer implements the NodeDialer interface by using a net.Dialer to @@ -60,8 +59,8 @@ type TCPDialer struct { } // Dial creates a TCP connection to the node -func (t TCPDialer) Dial(dest *discover.Node) (net.Conn, error) { - addr := &net.TCPAddr{IP: dest.IP, Port: int(dest.TCP)} +func (t TCPDialer) Dial(dest *enode.Node) (net.Conn, error) { + addr := &net.TCPAddr{IP: dest.IP(), Port: dest.TCP()} return t.Dialer.Dial("tcp", addr.String()) } @@ -72,24 +71,24 @@ type dialstate struct { maxDynDials int ntab discoverTable netrestrict *netutil.Netlist + self enode.ID lookupRunning bool - dialing map[discover.NodeID]connFlag - lookupBuf []*discover.Node // current discovery lookup results - randomNodes []*discover.Node // filled from Table - static map[discover.NodeID]*dialTask + dialing map[enode.ID]connFlag + lookupBuf []*enode.Node // current discovery lookup results + randomNodes []*enode.Node // filled from Table + static map[enode.ID]*dialTask hist *dialHistory - start time.Time // time when the dialer was first used - bootnodes []*discover.Node // default dials when there are no peers + start time.Time // time when the dialer was first used + bootnodes []*enode.Node // default dials when there are no peers } type discoverTable interface { - Self() *discover.Node Close() - Resolve(target discover.NodeID) *discover.Node - Lookup(target discover.NodeID) []*discover.Node - ReadRandomNodes([]*discover.Node) int + Resolve(*enode.Node) *enode.Node + LookupRandom() []*enode.Node + ReadRandomNodes([]*enode.Node) int } // the dial history remembers recent dials. @@ -97,7 +96,7 @@ type dialHistory []pastDial // pastDial is an entry in the dial history. type pastDial struct { - id discover.NodeID + id enode.ID exp time.Time } @@ -109,7 +108,7 @@ type task interface { // fields cannot be accessed while the task is running. type dialTask struct { flags connFlag - dest *discover.Node + dest *enode.Node lastResolved time.Time resolveDelay time.Duration } @@ -118,7 +117,7 @@ type dialTask struct { // Only one discoverTask is active at any time. // discoverTask.Do performs a random lookup. type discoverTask struct { - results []*discover.Node + results []*enode.Node } // A waitExpireTask is generated if there are no other tasks @@ -127,15 +126,16 @@ type waitExpireTask struct { time.Duration } -func newDialState(static []*discover.Node, bootnodes []*discover.Node, ntab discoverTable, maxdyn int, netrestrict *netutil.Netlist) *dialstate { +func newDialState(self enode.ID, static []*enode.Node, bootnodes []*enode.Node, ntab discoverTable, maxdyn int, netrestrict *netutil.Netlist) *dialstate { s := &dialstate{ maxDynDials: maxdyn, ntab: ntab, + self: self, netrestrict: netrestrict, - static: make(map[discover.NodeID]*dialTask), - dialing: make(map[discover.NodeID]connFlag), - bootnodes: make([]*discover.Node, len(bootnodes)), - randomNodes: make([]*discover.Node, maxdyn/2), + static: make(map[enode.ID]*dialTask), + dialing: make(map[enode.ID]connFlag), + bootnodes: make([]*enode.Node, len(bootnodes)), + randomNodes: make([]*enode.Node, maxdyn/2), hist: new(dialHistory), } copy(s.bootnodes, bootnodes) @@ -145,29 +145,32 @@ func newDialState(static []*discover.Node, bootnodes []*discover.Node, ntab disc return s } -func (s *dialstate) addStatic(n *discover.Node) { - // This overwites the task instead of updating an existing +func (s *dialstate) addStatic(n *enode.Node) { + // This overwrites the task instead of updating an existing // entry, giving users the opportunity to force a resolve operation. - s.static[n.ID] = &dialTask{flags: staticDialedConn, dest: n} + s.static[n.ID()] = &dialTask{flags: staticDialedConn, dest: n} } -func (s *dialstate) removeStatic(n *discover.Node) { +func (s *dialstate) removeStatic(n *enode.Node) { // This removes a task so future attempts to connect will not be made. - delete(s.static, n.ID) + delete(s.static, n.ID()) + // This removes a previous dial timestamp so that application + // can force a server to reconnect with chosen peer immediately. + s.hist.remove(n.ID()) } -func (s *dialstate) newTasks(nRunning int, peers map[discover.NodeID]*Peer, now time.Time) []task { +func (s *dialstate) newTasks(nRunning int, peers map[enode.ID]*Peer, now time.Time) []task { if s.start.IsZero() { s.start = now } var newtasks []task - addDial := func(flag connFlag, n *discover.Node) bool { + addDial := func(flag connFlag, n *enode.Node) bool { if err := s.checkDial(n, peers); err != nil { - log.Trace("Skipping dial candidate", "id", n.ID, "addr", &net.TCPAddr{IP: n.IP, Port: int(n.TCP)}, "err", err) + log.Trace("Skipping dial candidate", "id", n.ID(), "addr", &net.TCPAddr{IP: n.IP(), Port: n.TCP()}, "err", err) return false } - s.dialing[n.ID] = flag + s.dialing[n.ID()] = flag newtasks = append(newtasks, &dialTask{flags: flag, dest: n}) return true } @@ -193,8 +196,8 @@ func (s *dialstate) newTasks(nRunning int, peers map[discover.NodeID]*Peer, now err := s.checkDial(t.dest, peers) switch err { case errNotWhitelisted, errSelf: - log.Warn("Removing static dial candidate", "id", t.dest.ID, "addr", &net.TCPAddr{IP: t.dest.IP, Port: int(t.dest.TCP)}, "err", err) - delete(s.static, t.dest.ID) + log.Warn("Removing static dial candidate", "id", t.dest.ID, "addr", &net.TCPAddr{IP: t.dest.IP(), Port: t.dest.TCP()}, "err", err) + delete(s.static, t.dest.ID()) case nil: s.dialing[id] = t.flags newtasks = append(newtasks, t) @@ -257,18 +260,18 @@ var ( errNotWhitelisted = errors.New("not contained in netrestrict whitelist") ) -func (s *dialstate) checkDial(n *discover.Node, peers map[discover.NodeID]*Peer) error { - _, dialing := s.dialing[n.ID] +func (s *dialstate) checkDial(n *enode.Node, peers map[enode.ID]*Peer) error { + _, dialing := s.dialing[n.ID()] switch { case dialing: return errAlreadyDialing - case peers[n.ID] != nil: + case peers[n.ID()] != nil: return errAlreadyConnected - case s.ntab != nil && n.ID == s.ntab.Self().ID: + case n.ID() == s.self: return errSelf - case s.netrestrict != nil && !s.netrestrict.Contains(n.IP): + case s.netrestrict != nil && !s.netrestrict.Contains(n.IP()): return errNotWhitelisted - case s.hist.contains(n.ID): + case s.hist.contains(n.ID()): return errRecentlyDialed } return nil @@ -277,8 +280,8 @@ func (s *dialstate) checkDial(n *discover.Node, peers map[discover.NodeID]*Peer) func (s *dialstate) taskDone(t task, now time.Time) { switch t := t.(type) { case *dialTask: - s.hist.add(t.dest.ID, now.Add(dialHistoryExpiration)) - delete(s.dialing, t.dest.ID) + s.hist.add(t.dest.ID(), now.Add(dialHistoryExpiration)) + delete(s.dialing, t.dest.ID()) case *discoverTask: s.lookupRunning = false s.lookupBuf = append(s.lookupBuf, t.results...) @@ -320,7 +323,7 @@ func (t *dialTask) resolve(srv *Server) bool { if time.Since(t.lastResolved) < t.resolveDelay { return false } - resolved := srv.ntab.Resolve(t.dest.ID) + resolved := srv.ntab.Resolve(t.dest) t.lastResolved = time.Now() if resolved == nil { t.resolveDelay *= 2 @@ -333,7 +336,7 @@ func (t *dialTask) resolve(srv *Server) bool { // The node was found. t.resolveDelay = initialResolveDelay t.dest = resolved - log.Debug("Resolved node", "id", t.dest.ID, "addr", &net.TCPAddr{IP: t.dest.IP, Port: int(t.dest.TCP)}) + log.Debug("Resolved node", "id", t.dest.ID, "addr", &net.TCPAddr{IP: t.dest.IP(), Port: t.dest.TCP()}) return true } @@ -342,17 +345,18 @@ type dialError struct { } // dial performs the actual connection attempt. -func (t *dialTask) dial(srv *Server, dest *discover.Node) error { +func (t *dialTask) dial(srv *Server, dest *enode.Node) error { fd, err := srv.Dialer.Dial(dest) if err != nil { return &dialError{err} } - mfd := newMeteredConn(fd, false) + mfd := newMeteredConn(fd, false, dest.IP()) return srv.SetupConn(mfd, t.flags, dest) } func (t *dialTask) String() string { - return fmt.Sprintf("%v %x %v:%d", t.flags, t.dest.ID[:8], t.dest.IP, t.dest.TCP) + id := t.dest.ID() + return fmt.Sprintf("%v %x %v:%d", t.flags, id[:8], t.dest.IP(), t.dest.TCP()) } func (t *discoverTask) Do(srv *Server) { @@ -364,9 +368,7 @@ func (t *discoverTask) Do(srv *Server) { time.Sleep(next.Sub(now)) } srv.lastLookup = time.Now() - var target discover.NodeID - rand.Read(target[:]) - t.results = srv.ntab.Lookup(target) + t.results = srv.ntab.LookupRandom() } func (t *discoverTask) String() string { @@ -388,10 +390,20 @@ func (t waitExpireTask) String() string { func (h dialHistory) min() pastDial { return h[0] } -func (h *dialHistory) add(id discover.NodeID, exp time.Time) { +func (h *dialHistory) add(id enode.ID, exp time.Time) { heap.Push(h, pastDial{id, exp}) + } -func (h dialHistory) contains(id discover.NodeID) bool { +func (h *dialHistory) remove(id enode.ID) bool { + for i, v := range *h { + if v.id == id { + heap.Remove(h, i) + return true + } + } + return false +} +func (h dialHistory) contains(id enode.ID) bool { for _, v := range h { if v.id == id { return true diff --git a/p2p/dial_test.go b/p2p/dial_test.go index ad18ef9abe..f41ab77524 100644 --- a/p2p/dial_test.go +++ b/p2p/dial_test.go @@ -24,7 +24,8 @@ import ( "time" "github.com/davecgh/go-spew/spew" - "github.com/ethereum/go-ethereum/p2p/discover" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/enr" "github.com/ethereum/go-ethereum/p2p/netutil" ) @@ -48,10 +49,10 @@ func runDialTest(t *testing.T, test dialtest) { vtime time.Time running int ) - pm := func(ps []*Peer) map[discover.NodeID]*Peer { - m := make(map[discover.NodeID]*Peer) + pm := func(ps []*Peer) map[enode.ID]*Peer { + m := make(map[enode.ID]*Peer) for _, p := range ps { - m[p.rw.id] = p + m[p.ID()] = p } return m } @@ -69,6 +70,7 @@ func runDialTest(t *testing.T, test dialtest) { t.Errorf("round %d: new tasks mismatch:\ngot %v\nwant %v\nstate: %v\nrunning: %v\n", i, spew.Sdump(new), spew.Sdump(round.new), spew.Sdump(test.init), spew.Sdump(running)) } + t.Log("tasks:", spew.Sdump(new)) // Time advances by 16 seconds on every round. vtime = vtime.Add(16 * time.Second) @@ -76,79 +78,79 @@ func runDialTest(t *testing.T, test dialtest) { } } -type fakeTable []*discover.Node +type fakeTable []*enode.Node -func (t fakeTable) Self() *discover.Node { return new(discover.Node) } -func (t fakeTable) Close() {} -func (t fakeTable) Lookup(discover.NodeID) []*discover.Node { return nil } -func (t fakeTable) Resolve(discover.NodeID) *discover.Node { return nil } -func (t fakeTable) ReadRandomNodes(buf []*discover.Node) int { return copy(buf, t) } +func (t fakeTable) Self() *enode.Node { return new(enode.Node) } +func (t fakeTable) Close() {} +func (t fakeTable) LookupRandom() []*enode.Node { return nil } +func (t fakeTable) Resolve(*enode.Node) *enode.Node { return nil } +func (t fakeTable) ReadRandomNodes(buf []*enode.Node) int { return copy(buf, t) } // This test checks that dynamic dials are launched from discovery results. func TestDialStateDynDial(t *testing.T) { runDialTest(t, dialtest{ - init: newDialState(nil, nil, fakeTable{}, 5, nil), + init: newDialState(enode.ID{}, nil, nil, fakeTable{}, 5, nil), rounds: []round{ // A discovery query is launched. { peers: []*Peer{ - {rw: &conn{flags: staticDialedConn, id: uintID(0)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, + {rw: &conn{flags: staticDialedConn, node: newNode(uintID(0), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}}, }, new: []task{&discoverTask{}}, }, // Dynamic dials are launched when it completes. { peers: []*Peer{ - {rw: &conn{flags: staticDialedConn, id: uintID(0)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, + {rw: &conn{flags: staticDialedConn, node: newNode(uintID(0), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}}, }, done: []task{ - &discoverTask{results: []*discover.Node{ - {ID: uintID(2)}, // this one is already connected and not dialed. - {ID: uintID(3)}, - {ID: uintID(4)}, - {ID: uintID(5)}, - {ID: uintID(6)}, // these are not tried because max dyn dials is 5 - {ID: uintID(7)}, // ... + &discoverTask{results: []*enode.Node{ + newNode(uintID(2), nil), // this one is already connected and not dialed. + newNode(uintID(3), nil), + newNode(uintID(4), nil), + newNode(uintID(5), nil), + newNode(uintID(6), nil), // these are not tried because max dyn dials is 5 + newNode(uintID(7), nil), // ... }}, }, new: []task{ - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}}, - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}}, - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(3), nil)}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)}, }, }, // Some of the dials complete but no new ones are launched yet because // the sum of active dial count and dynamic peer count is == maxDynDials. { peers: []*Peer{ - {rw: &conn{flags: staticDialedConn, id: uintID(0)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(3)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(4)}}, + {rw: &conn{flags: staticDialedConn, node: newNode(uintID(0), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(3), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(4), nil)}}, }, done: []task{ - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}}, - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(3), nil)}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)}, }, }, // No new dial tasks are launched in the this round because // maxDynDials has been reached. { peers: []*Peer{ - {rw: &conn{flags: staticDialedConn, id: uintID(0)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(3)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(4)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(5)}}, + {rw: &conn{flags: staticDialedConn, node: newNode(uintID(0), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(3), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(4), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(5), nil)}}, }, done: []task{ - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)}, }, new: []task{ &waitExpireTask{Duration: 14 * time.Second}, @@ -158,14 +160,14 @@ func TestDialStateDynDial(t *testing.T) { // results from last discovery lookup are reused. { peers: []*Peer{ - {rw: &conn{flags: staticDialedConn, id: uintID(0)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(3)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(4)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(5)}}, + {rw: &conn{flags: staticDialedConn, node: newNode(uintID(0), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(3), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(4), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(5), nil)}}, }, new: []task{ - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(6)}}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(6), nil)}, }, }, // More peers (3,4) drop off and dial for ID 6 completes. @@ -173,15 +175,15 @@ func TestDialStateDynDial(t *testing.T) { // and a new one is spawned because more candidates are needed. { peers: []*Peer{ - {rw: &conn{flags: staticDialedConn, id: uintID(0)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(5)}}, + {rw: &conn{flags: staticDialedConn, node: newNode(uintID(0), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(5), nil)}}, }, done: []task{ - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(6)}}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(6), nil)}, }, new: []task{ - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(7)}}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(7), nil)}, &discoverTask{}, }, }, @@ -190,23 +192,23 @@ func TestDialStateDynDial(t *testing.T) { // no new is started. { peers: []*Peer{ - {rw: &conn{flags: staticDialedConn, id: uintID(0)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(5)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(7)}}, + {rw: &conn{flags: staticDialedConn, node: newNode(uintID(0), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(5), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(7), nil)}}, }, done: []task{ - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(7)}}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(7), nil)}, }, }, // Finish the running node discovery with an empty set. A new lookup // should be immediately requested. { peers: []*Peer{ - {rw: &conn{flags: staticDialedConn, id: uintID(0)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(5)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(7)}}, + {rw: &conn{flags: staticDialedConn, node: newNode(uintID(0), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(5), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(7), nil)}}, }, done: []task{ &discoverTask{}, @@ -221,34 +223,34 @@ func TestDialStateDynDial(t *testing.T) { // Tests that bootnodes are dialed if no peers are connectd, but not otherwise. func TestDialStateDynDialBootnode(t *testing.T) { - bootnodes := []*discover.Node{ - {ID: uintID(1)}, - {ID: uintID(2)}, - {ID: uintID(3)}, + bootnodes := []*enode.Node{ + newNode(uintID(1), nil), + newNode(uintID(2), nil), + newNode(uintID(3), nil), } table := fakeTable{ - {ID: uintID(4)}, - {ID: uintID(5)}, - {ID: uintID(6)}, - {ID: uintID(7)}, - {ID: uintID(8)}, + newNode(uintID(4), nil), + newNode(uintID(5), nil), + newNode(uintID(6), nil), + newNode(uintID(7), nil), + newNode(uintID(8), nil), } runDialTest(t, dialtest{ - init: newDialState(nil, bootnodes, table, 5, nil), + init: newDialState(enode.ID{}, nil, bootnodes, table, 5, nil), rounds: []round{ // 2 dynamic dials attempted, bootnodes pending fallback interval { new: []task{ - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}}, - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)}, &discoverTask{}, }, }, // No dials succeed, bootnodes still pending fallback interval { done: []task{ - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}}, - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)}, }, }, // No dials succeed, bootnodes still pending fallback interval @@ -256,51 +258,51 @@ func TestDialStateDynDialBootnode(t *testing.T) { // No dials succeed, 2 dynamic dials attempted and 1 bootnode too as fallback interval was reached { new: []task{ - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}}, - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}}, - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(1), nil)}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)}, }, }, // No dials succeed, 2nd bootnode is attempted { done: []task{ - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}}, - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}}, - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(1), nil)}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)}, }, new: []task{ - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(2)}}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(2), nil)}, }, }, // No dials succeed, 3rd bootnode is attempted { done: []task{ - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(2)}}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(2), nil)}, }, new: []task{ - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(3), nil)}, }, }, // No dials succeed, 1st bootnode is attempted again, expired random nodes retried { done: []task{ - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(3), nil)}, }, new: []task{ - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}}, - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}}, - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(1), nil)}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)}, }, }, // Random dial succeeds, no more bootnodes are attempted { peers: []*Peer{ - {rw: &conn{flags: dynDialedConn, id: uintID(4)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(4), nil)}}, }, done: []task{ - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}}, - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}}, - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(1), nil)}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)}, }, }, }, @@ -311,79 +313,79 @@ func TestDialStateDynDialFromTable(t *testing.T) { // This table always returns the same random nodes // in the order given below. table := fakeTable{ - {ID: uintID(1)}, - {ID: uintID(2)}, - {ID: uintID(3)}, - {ID: uintID(4)}, - {ID: uintID(5)}, - {ID: uintID(6)}, - {ID: uintID(7)}, - {ID: uintID(8)}, + newNode(uintID(1), nil), + newNode(uintID(2), nil), + newNode(uintID(3), nil), + newNode(uintID(4), nil), + newNode(uintID(5), nil), + newNode(uintID(6), nil), + newNode(uintID(7), nil), + newNode(uintID(8), nil), } runDialTest(t, dialtest{ - init: newDialState(nil, nil, table, 10, nil), + init: newDialState(enode.ID{}, nil, nil, table, 10, nil), rounds: []round{ // 5 out of 8 of the nodes returned by ReadRandomNodes are dialed. { new: []task{ - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}}, - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(2)}}, - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}}, - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}}, - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(1), nil)}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(2), nil)}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(3), nil)}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)}, &discoverTask{}, }, }, // Dialing nodes 1,2 succeeds. Dials from the lookup are launched. { peers: []*Peer{ - {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}}, }, done: []task{ - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}}, - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(2)}}, - &discoverTask{results: []*discover.Node{ - {ID: uintID(10)}, - {ID: uintID(11)}, - {ID: uintID(12)}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(1), nil)}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(2), nil)}, + &discoverTask{results: []*enode.Node{ + newNode(uintID(10), nil), + newNode(uintID(11), nil), + newNode(uintID(12), nil), }}, }, new: []task{ - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(10)}}, - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(11)}}, - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(12)}}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(10), nil)}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(11), nil)}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(12), nil)}, &discoverTask{}, }, }, // Dialing nodes 3,4,5 fails. The dials from the lookup succeed. { peers: []*Peer{ - {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(10)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(11)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(12)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(10), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(11), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(12), nil)}}, }, done: []task{ - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}}, - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}}, - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}}, - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(10)}}, - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(11)}}, - &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(12)}}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(3), nil)}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(10), nil)}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(11), nil)}, + &dialTask{flags: dynDialedConn, dest: newNode(uintID(12), nil)}, }, }, // Waiting for expiry. No waitExpireTask is launched because the // discovery query is still running. { peers: []*Peer{ - {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(10)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(11)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(12)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(10), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(11), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(12), nil)}}, }, }, // Nodes 3,4 are not tried again because only the first two @@ -391,36 +393,44 @@ func TestDialStateDynDialFromTable(t *testing.T) { // already connected. { peers: []*Peer{ - {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(10)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(11)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(12)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(10), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(11), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(12), nil)}}, }, }, }, }) } +func newNode(id enode.ID, ip net.IP) *enode.Node { + var r enr.Record + if ip != nil { + r.Set(enr.IP(ip)) + } + return enode.SignNull(&r, id) +} + // This test checks that candidates that do not match the netrestrict list are not dialed. func TestDialStateNetRestrict(t *testing.T) { // This table always returns the same random nodes // in the order given below. table := fakeTable{ - {ID: uintID(1), IP: net.ParseIP("127.0.0.1")}, - {ID: uintID(2), IP: net.ParseIP("127.0.0.2")}, - {ID: uintID(3), IP: net.ParseIP("127.0.0.3")}, - {ID: uintID(4), IP: net.ParseIP("127.0.0.4")}, - {ID: uintID(5), IP: net.ParseIP("127.0.2.5")}, - {ID: uintID(6), IP: net.ParseIP("127.0.2.6")}, - {ID: uintID(7), IP: net.ParseIP("127.0.2.7")}, - {ID: uintID(8), IP: net.ParseIP("127.0.2.8")}, + newNode(uintID(1), net.ParseIP("127.0.0.1")), + newNode(uintID(2), net.ParseIP("127.0.0.2")), + newNode(uintID(3), net.ParseIP("127.0.0.3")), + newNode(uintID(4), net.ParseIP("127.0.0.4")), + newNode(uintID(5), net.ParseIP("127.0.2.5")), + newNode(uintID(6), net.ParseIP("127.0.2.6")), + newNode(uintID(7), net.ParseIP("127.0.2.7")), + newNode(uintID(8), net.ParseIP("127.0.2.8")), } restrict := new(netutil.Netlist) restrict.Add("127.0.2.0/24") runDialTest(t, dialtest{ - init: newDialState(nil, nil, table, 10, restrict), + init: newDialState(enode.ID{}, nil, nil, table, 10, restrict), rounds: []round{ { new: []task{ @@ -434,55 +444,55 @@ func TestDialStateNetRestrict(t *testing.T) { // This test checks that static dials are launched. func TestDialStateStaticDial(t *testing.T) { - wantStatic := []*discover.Node{ - {ID: uintID(1)}, - {ID: uintID(2)}, - {ID: uintID(3)}, - {ID: uintID(4)}, - {ID: uintID(5)}, + wantStatic := []*enode.Node{ + newNode(uintID(1), nil), + newNode(uintID(2), nil), + newNode(uintID(3), nil), + newNode(uintID(4), nil), + newNode(uintID(5), nil), } runDialTest(t, dialtest{ - init: newDialState(wantStatic, nil, fakeTable{}, 0, nil), + init: newDialState(enode.ID{}, wantStatic, nil, fakeTable{}, 0, nil), rounds: []round{ // Static dials are launched for the nodes that // aren't yet connected. { peers: []*Peer{ - {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}}, }, new: []task{ - &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}}, - &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(4)}}, - &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(5)}}, + &dialTask{flags: staticDialedConn, dest: newNode(uintID(3), nil)}, + &dialTask{flags: staticDialedConn, dest: newNode(uintID(4), nil)}, + &dialTask{flags: staticDialedConn, dest: newNode(uintID(5), nil)}, }, }, // No new tasks are launched in this round because all static // nodes are either connected or still being dialed. { peers: []*Peer{ - {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, - {rw: &conn{flags: staticDialedConn, id: uintID(3)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}}, + {rw: &conn{flags: staticDialedConn, node: newNode(uintID(3), nil)}}, }, done: []task{ - &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}}, + &dialTask{flags: staticDialedConn, dest: newNode(uintID(3), nil)}, }, }, // No new dial tasks are launched because all static // nodes are now connected. { peers: []*Peer{ - {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, - {rw: &conn{flags: staticDialedConn, id: uintID(3)}}, - {rw: &conn{flags: staticDialedConn, id: uintID(4)}}, - {rw: &conn{flags: staticDialedConn, id: uintID(5)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}}, + {rw: &conn{flags: staticDialedConn, node: newNode(uintID(3), nil)}}, + {rw: &conn{flags: staticDialedConn, node: newNode(uintID(4), nil)}}, + {rw: &conn{flags: staticDialedConn, node: newNode(uintID(5), nil)}}, }, done: []task{ - &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(4)}}, - &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(5)}}, + &dialTask{flags: staticDialedConn, dest: newNode(uintID(4), nil)}, + &dialTask{flags: staticDialedConn, dest: newNode(uintID(5), nil)}, }, new: []task{ &waitExpireTask{Duration: 14 * time.Second}, @@ -491,72 +501,116 @@ func TestDialStateStaticDial(t *testing.T) { // Wait a round for dial history to expire, no new tasks should spawn. { peers: []*Peer{ - {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, - {rw: &conn{flags: staticDialedConn, id: uintID(3)}}, - {rw: &conn{flags: staticDialedConn, id: uintID(4)}}, - {rw: &conn{flags: staticDialedConn, id: uintID(5)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}}, + {rw: &conn{flags: staticDialedConn, node: newNode(uintID(3), nil)}}, + {rw: &conn{flags: staticDialedConn, node: newNode(uintID(4), nil)}}, + {rw: &conn{flags: staticDialedConn, node: newNode(uintID(5), nil)}}, }, }, // If a static node is dropped, it should be immediately redialed, // irrespective whether it was originally static or dynamic. { peers: []*Peer{ - {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, - {rw: &conn{flags: staticDialedConn, id: uintID(3)}}, - {rw: &conn{flags: staticDialedConn, id: uintID(5)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, + {rw: &conn{flags: staticDialedConn, node: newNode(uintID(3), nil)}}, + {rw: &conn{flags: staticDialedConn, node: newNode(uintID(5), nil)}}, }, new: []task{ - &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}}, - &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(4)}}, + &dialTask{flags: staticDialedConn, dest: newNode(uintID(2), nil)}, + &dialTask{flags: staticDialedConn, dest: newNode(uintID(4), nil)}, }, }, }, }) } +// This test checks that static peers will be redialed immediately if they were re-added to a static list. +func TestDialStaticAfterReset(t *testing.T) { + wantStatic := []*enode.Node{ + newNode(uintID(1), nil), + newNode(uintID(2), nil), + } + + rounds := []round{ + // Static dials are launched for the nodes that aren't yet connected. + { + peers: nil, + new: []task{ + &dialTask{flags: staticDialedConn, dest: newNode(uintID(1), nil)}, + &dialTask{flags: staticDialedConn, dest: newNode(uintID(2), nil)}, + }, + }, + // No new dial tasks, all peers are connected. + { + peers: []*Peer{ + {rw: &conn{flags: staticDialedConn, node: newNode(uintID(1), nil)}}, + {rw: &conn{flags: staticDialedConn, node: newNode(uintID(2), nil)}}, + }, + done: []task{ + &dialTask{flags: staticDialedConn, dest: newNode(uintID(1), nil)}, + &dialTask{flags: staticDialedConn, dest: newNode(uintID(2), nil)}, + }, + new: []task{ + &waitExpireTask{Duration: 30 * time.Second}, + }, + }, + } + dTest := dialtest{ + init: newDialState(enode.ID{}, wantStatic, nil, fakeTable{}, 0, nil), + rounds: rounds, + } + runDialTest(t, dTest) + for _, n := range wantStatic { + dTest.init.removeStatic(n) + dTest.init.addStatic(n) + } + // without removing peers they will be considered recently dialed + runDialTest(t, dTest) +} + // This test checks that past dials are not retried for some time. func TestDialStateCache(t *testing.T) { - wantStatic := []*discover.Node{ - {ID: uintID(1)}, - {ID: uintID(2)}, - {ID: uintID(3)}, + wantStatic := []*enode.Node{ + newNode(uintID(1), nil), + newNode(uintID(2), nil), + newNode(uintID(3), nil), } runDialTest(t, dialtest{ - init: newDialState(wantStatic, nil, fakeTable{}, 0, nil), + init: newDialState(enode.ID{}, wantStatic, nil, fakeTable{}, 0, nil), rounds: []round{ // Static dials are launched for the nodes that // aren't yet connected. { peers: nil, new: []task{ - &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}}, - &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}}, - &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}}, + &dialTask{flags: staticDialedConn, dest: newNode(uintID(1), nil)}, + &dialTask{flags: staticDialedConn, dest: newNode(uintID(2), nil)}, + &dialTask{flags: staticDialedConn, dest: newNode(uintID(3), nil)}, }, }, // No new tasks are launched in this round because all static // nodes are either connected or still being dialed. { peers: []*Peer{ - {rw: &conn{flags: staticDialedConn, id: uintID(1)}}, - {rw: &conn{flags: staticDialedConn, id: uintID(2)}}, + {rw: &conn{flags: staticDialedConn, node: newNode(uintID(1), nil)}}, + {rw: &conn{flags: staticDialedConn, node: newNode(uintID(2), nil)}}, }, done: []task{ - &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}}, - &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}}, + &dialTask{flags: staticDialedConn, dest: newNode(uintID(1), nil)}, + &dialTask{flags: staticDialedConn, dest: newNode(uintID(2), nil)}, }, }, // A salvage task is launched to wait for node 3's history // entry to expire. { peers: []*Peer{ - {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}}, }, done: []task{ - &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}}, + &dialTask{flags: staticDialedConn, dest: newNode(uintID(3), nil)}, }, new: []task{ &waitExpireTask{Duration: 14 * time.Second}, @@ -565,18 +619,18 @@ func TestDialStateCache(t *testing.T) { // Still waiting for node 3's entry to expire in the cache. { peers: []*Peer{ - {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}}, }, }, // The cache entry for node 3 has expired and is retried. { peers: []*Peer{ - {rw: &conn{flags: dynDialedConn, id: uintID(1)}}, - {rw: &conn{flags: dynDialedConn, id: uintID(2)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, + {rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}}, }, new: []task{ - &dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}}, + &dialTask{flags: staticDialedConn, dest: newNode(uintID(3), nil)}, }, }, }, @@ -584,12 +638,12 @@ func TestDialStateCache(t *testing.T) { } func TestDialResolve(t *testing.T) { - resolved := discover.NewNode(uintID(1), net.IP{127, 0, 55, 234}, 3333, 4444) + resolved := newNode(uintID(1), net.IP{127, 0, 55, 234}) table := &resolveMock{answer: resolved} - state := newDialState(nil, nil, table, 0, nil) + state := newDialState(enode.ID{}, nil, nil, table, 0, nil) // Check that the task is generated with an incomplete ID. - dest := discover.NewNode(uintID(1), nil, 0, 0) + dest := newNode(uintID(1), nil) state.addStatic(dest) tasks := state.newTasks(0, nil, time.Time{}) if !reflect.DeepEqual(tasks, []task{&dialTask{flags: staticDialedConn, dest: dest}}) { @@ -600,7 +654,7 @@ func TestDialResolve(t *testing.T) { config := Config{Dialer: TCPDialer{&net.Dialer{Deadline: time.Now().Add(-5 * time.Minute)}}} srv := &Server{ntab: table, Config: config} tasks[0].Do(srv) - if !reflect.DeepEqual(table.resolveCalls, []discover.NodeID{dest.ID}) { + if !reflect.DeepEqual(table.resolveCalls, []*enode.Node{dest}) { t.Fatalf("wrong resolve calls, got %v", table.resolveCalls) } @@ -628,25 +682,24 @@ next: return true } -func uintID(i uint32) discover.NodeID { - var id discover.NodeID +func uintID(i uint32) enode.ID { + var id enode.ID binary.BigEndian.PutUint32(id[:], i) return id } // implements discoverTable for TestDialResolve type resolveMock struct { - resolveCalls []discover.NodeID - answer *discover.Node + resolveCalls []*enode.Node + answer *enode.Node } -func (t *resolveMock) Resolve(id discover.NodeID) *discover.Node { - t.resolveCalls = append(t.resolveCalls, id) +func (t *resolveMock) Resolve(n *enode.Node) *enode.Node { + t.resolveCalls = append(t.resolveCalls, n) return t.answer } -func (t *resolveMock) Self() *discover.Node { return new(discover.Node) } -func (t *resolveMock) Close() {} -func (t *resolveMock) Bootstrap([]*discover.Node) {} -func (t *resolveMock) Lookup(discover.NodeID) []*discover.Node { return nil } -func (t *resolveMock) ReadRandomNodes(buf []*discover.Node) int { return 0 } +func (t *resolveMock) Self() *enode.Node { return new(enode.Node) } +func (t *resolveMock) Close() {} +func (t *resolveMock) LookupRandom() []*enode.Node { return nil } +func (t *resolveMock) ReadRandomNodes(buf []*enode.Node) int { return 0 } diff --git a/p2p/discover/database.go b/p2p/discover/database.go deleted file mode 100644 index b136609f24..0000000000 --- a/p2p/discover/database.go +++ /dev/null @@ -1,365 +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 . - -// Contains the node database, storing previously seen nodes and any collected -// metadata about them for QoS purposes. - -package discover - -import ( - "bytes" - "crypto/rand" - "encoding/binary" - "os" - "sync" - "time" - - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rlp" - "github.com/syndtr/goleveldb/leveldb" - "github.com/syndtr/goleveldb/leveldb/errors" - "github.com/syndtr/goleveldb/leveldb/iterator" - "github.com/syndtr/goleveldb/leveldb/opt" - "github.com/syndtr/goleveldb/leveldb/storage" - "github.com/syndtr/goleveldb/leveldb/util" -) - -var ( - nodeDBNilNodeID = NodeID{} // Special node ID to use as a nil element. - nodeDBNodeExpiration = 24 * time.Hour // Time after which an unseen node should be dropped. - nodeDBCleanupCycle = time.Hour // Time period for running the expiration task. -) - -// nodeDB stores all nodes we know about. -type nodeDB struct { - lvl *leveldb.DB // Interface to the database itself - self NodeID // Own node id to prevent adding it into the database - runner sync.Once // Ensures we can start at most one expirer - quit chan struct{} // Channel to signal the expiring thread to stop -} - -// Schema layout for the node database -var ( - nodeDBVersionKey = []byte("version") // Version of the database to flush if changes - nodeDBItemPrefix = []byte("n:") // Identifier to prefix node entries with - - nodeDBDiscoverRoot = ":discover" - nodeDBDiscoverPing = nodeDBDiscoverRoot + ":lastping" - nodeDBDiscoverPong = nodeDBDiscoverRoot + ":lastpong" - nodeDBDiscoverFindFails = nodeDBDiscoverRoot + ":findfail" -) - -// newNodeDB creates a new node database for storing and retrieving infos about -// known peers in the network. If no path is given, an in-memory, temporary -// database is constructed. -func newNodeDB(path string, version int, self NodeID) (*nodeDB, error) { - if path == "" { - return newMemoryNodeDB(self) - } - return newPersistentNodeDB(path, version, self) -} - -// newMemoryNodeDB creates a new in-memory node database without a persistent -// backend. -func newMemoryNodeDB(self NodeID) (*nodeDB, error) { - db, err := leveldb.Open(storage.NewMemStorage(), nil) - if err != nil { - return nil, err - } - return &nodeDB{ - lvl: db, - self: self, - quit: make(chan struct{}), - }, nil -} - -// newPersistentNodeDB creates/opens a leveldb backed persistent node database, -// also flushing its contents in case of a version mismatch. -func newPersistentNodeDB(path string, version int, self NodeID) (*nodeDB, error) { - opts := &opt.Options{OpenFilesCacheCapacity: 5} - db, err := leveldb.OpenFile(path, opts) - if _, iscorrupted := err.(*errors.ErrCorrupted); iscorrupted { - db, err = leveldb.RecoverFile(path, nil) - } - if err != nil { - return nil, err - } - // The nodes contained in the cache correspond to a certain protocol version. - // Flush all nodes if the version doesn't match. - currentVer := make([]byte, binary.MaxVarintLen64) - currentVer = currentVer[:binary.PutVarint(currentVer, int64(version))] - - blob, err := db.Get(nodeDBVersionKey, nil) - switch err { - case leveldb.ErrNotFound: - // Version not found (i.e. empty cache), insert it - if err := db.Put(nodeDBVersionKey, currentVer, nil); err != nil { - db.Close() - return nil, err - } - - case nil: - // Version present, flush if different - if !bytes.Equal(blob, currentVer) { - db.Close() - if err = os.RemoveAll(path); err != nil { - return nil, err - } - return newPersistentNodeDB(path, version, self) - } - } - return &nodeDB{ - lvl: db, - self: self, - quit: make(chan struct{}), - }, nil -} - -// makeKey generates the leveldb key-blob from a node id and its particular -// field of interest. -func makeKey(id NodeID, field string) []byte { - if bytes.Equal(id[:], nodeDBNilNodeID[:]) { - return []byte(field) - } - return append(nodeDBItemPrefix, append(id[:], field...)...) -} - -// splitKey tries to split a database key into a node id and a field part. -func splitKey(key []byte) (id NodeID, field string) { - // If the key is not of a node, return it plainly - if !bytes.HasPrefix(key, nodeDBItemPrefix) { - return NodeID{}, string(key) - } - // Otherwise split the id and field - item := key[len(nodeDBItemPrefix):] - copy(id[:], item[:len(id)]) - field = string(item[len(id):]) - - return id, field -} - -// fetchInt64 retrieves an integer instance associated with a particular -// database key. -func (db *nodeDB) fetchInt64(key []byte) int64 { - blob, err := db.lvl.Get(key, nil) - if err != nil { - return 0 - } - val, read := binary.Varint(blob) - if read <= 0 { - return 0 - } - return val -} - -// storeInt64 update a specific database entry to the current time instance as a -// unix timestamp. -func (db *nodeDB) storeInt64(key []byte, n int64) error { - blob := make([]byte, binary.MaxVarintLen64) - blob = blob[:binary.PutVarint(blob, n)] - - return db.lvl.Put(key, blob, nil) -} - -// node retrieves a node with a given id from the database. -func (db *nodeDB) node(id NodeID) *Node { - blob, err := db.lvl.Get(makeKey(id, nodeDBDiscoverRoot), nil) - if err != nil { - return nil - } - node := new(Node) - if err := rlp.DecodeBytes(blob, node); err != nil { - log.Error("Failed to decode node RLP", "err", err) - return nil - } - node.sha = crypto.Keccak256Hash(node.ID[:]) - return node -} - -// updateNode inserts - potentially overwriting - a node into the peer database. -func (db *nodeDB) updateNode(node *Node) error { - blob, err := rlp.EncodeToBytes(node) - if err != nil { - return err - } - return db.lvl.Put(makeKey(node.ID, nodeDBDiscoverRoot), blob, nil) -} - -// deleteNode deletes all information/keys associated with a node. -func (db *nodeDB) deleteNode(id NodeID) 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 - } - } - return nil -} - -// ensureExpirer is a small helper method ensuring that the data expiration -// mechanism is running. If the expiration goroutine is already running, this -// method simply returns. -// -// The goal is to start the data evacuation only after the network successfully -// bootstrapped itself (to prevent dumping potentially useful seed nodes). Since -// it would require significant overhead to exactly trace the first successful -// convergence, it's simpler to "ensure" the correct state when an appropriate -// condition occurs (i.e. a successful bonding), and discard further events. -func (db *nodeDB) ensureExpirer() { - db.runner.Do(func() { go db.expirer() }) -} - -// expirer should be started in a go routine, and is responsible for looping ad -// infinitum and dropping stale data from the database. -func (db *nodeDB) expirer() { - tick := time.NewTicker(nodeDBCleanupCycle) - defer tick.Stop() - for { - select { - case <-tick.C: - if err := db.expireNodes(); err != nil { - log.Error("Failed to expire nodedb items", "err", err) - } - case <-db.quit: - return - } - } -} - -// 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 *nodeDB) expireNodes() error { - threshold := time.Now().Add(-nodeDBNodeExpiration) - - // Find discovered nodes that are older than the allowance - it := db.lvl.NewIterator(nil, nil) - defer it.Release() - - for it.Next() { - // Skip the item if not a discovery node - id, field := splitKey(it.Key()) - if field != nodeDBDiscoverRoot { - continue - } - // Skip the node if not expired yet (and not self) - if !bytes.Equal(id[:], db.self[:]) { - if seen := db.lastPong(id); seen.After(threshold) { - continue - } - } - // Otherwise delete all associated information - db.deleteNode(id) - } - return nil -} - -// lastPing retrieves the time of the last ping packet send to a remote node, -// requesting binding. -func (db *nodeDB) lastPing(id NodeID) time.Time { - return time.Unix(db.fetchInt64(makeKey(id, nodeDBDiscoverPing)), 0) -} - -// updateLastPing updates the last time we tried contacting a remote node. -func (db *nodeDB) updateLastPing(id NodeID, instance time.Time) error { - return db.storeInt64(makeKey(id, nodeDBDiscoverPing), instance.Unix()) -} - -// lastPong retrieves the time of the last successful contact from remote node. -func (db *nodeDB) lastPong(id NodeID) time.Time { - return time.Unix(db.fetchInt64(makeKey(id, nodeDBDiscoverPong)), 0) -} - -// updateLastPong updates the last time a remote node successfully contacted. -func (db *nodeDB) updateLastPong(id NodeID, instance time.Time) error { - return db.storeInt64(makeKey(id, nodeDBDiscoverPong), instance.Unix()) -} - -// findFails retrieves the number of findnode failures since bonding. -func (db *nodeDB) findFails(id NodeID) int { - return int(db.fetchInt64(makeKey(id, nodeDBDiscoverFindFails))) -} - -// updateFindFails updates the number of findnode failures since bonding. -func (db *nodeDB) updateFindFails(id NodeID, fails int) error { - return db.storeInt64(makeKey(id, nodeDBDiscoverFindFails), int64(fails)) -} - -// querySeeds retrieves random nodes to be used as potential seed nodes -// for bootstrapping. -func (db *nodeDB) querySeeds(n int, maxAge time.Duration) []*Node { - var ( - now = time.Now() - nodes = make([]*Node, 0, n) - it = db.lvl.NewIterator(nil, nil) - id NodeID - ) - defer it.Release() - -seek: - for seeks := 0; len(nodes) < n && seeks < n*5; seeks++ { - // Seek to a random entry. The first byte is incremented by a - // random amount each time in order to increase the likelihood - // of hitting all existing nodes in very small databases. - ctr := id[0] - rand.Read(id[:]) - id[0] = ctr + id[0]%16 - it.Seek(makeKey(id, nodeDBDiscoverRoot)) - - n := nextNode(it) - if n == nil { - id[0] = 0 - continue seek // iterator exhausted - } - if n.ID == db.self { - continue seek - } - if now.Sub(db.lastPong(n.ID)) > maxAge { - continue seek - } - for i := range nodes { - if nodes[i].ID == n.ID { - continue seek // duplicate - } - } - nodes = append(nodes, n) - } - return nodes -} - -// reads the next node record from the iterator, skipping over other -// database entries. -func nextNode(it iterator.Iterator) *Node { - for end := false; !end; end = !it.Next() { - id, field := splitKey(it.Key()) - if field != nodeDBDiscoverRoot { - continue - } - var n Node - if err := rlp.DecodeBytes(it.Value(), &n); err != nil { - log.Warn("Failed to decode node RLP", "id", id, "err", err) - continue - } - return &n - } - return nil -} - -// close flushes and closes the database files. -func (db *nodeDB) close() { - close(db.quit) - db.lvl.Close() -} diff --git a/p2p/discover/database_test.go b/p2p/discover/database_test.go deleted file mode 100644 index be972fd2c3..0000000000 --- a/p2p/discover/database_test.go +++ /dev/null @@ -1,380 +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 discover - -import ( - "bytes" - "io/ioutil" - "net" - "os" - "path/filepath" - "reflect" - "testing" - "time" -) - -var nodeDBKeyTests = []struct { - id NodeID - field string - key []byte -}{ - { - id: NodeID{}, - field: "version", - key: []byte{0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e}, // field - }, - { - id: MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), - field: ":discover", - key: []byte{0x6e, 0x3a, // prefix - 0x1d, 0xd9, 0xd6, 0x5c, 0x45, 0x52, 0xb5, 0xeb, // node id - 0x43, 0xd5, 0xad, 0x55, 0xa2, 0xee, 0x3f, 0x56, // - 0xc6, 0xcb, 0xc1, 0xc6, 0x4a, 0x5c, 0x8d, 0x65, // - 0x9f, 0x51, 0xfc, 0xd5, 0x1b, 0xac, 0xe2, 0x43, // - 0x51, 0x23, 0x2b, 0x8d, 0x78, 0x21, 0x61, 0x7d, // - 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 - }, - }, -} - -func TestNodeDBKeys(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) - } - } -} - -var nodeDBInt64Tests = []struct { - key []byte - value int64 -}{ - {key: []byte{0x01}, value: 1}, - {key: []byte{0x02}, value: 2}, - {key: []byte{0x03}, value: 3}, -} - -func TestNodeDBInt64(t *testing.T) { - db, _ := newNodeDB("", Version, NodeID{}) - defer db.close() - - tests := nodeDBInt64Tests - for i := 0; i < len(tests); i++ { - // Insert the next value - if err := db.storeInt64(tests[i].key, tests[i].value); err != nil { - t.Errorf("test %d: failed to store value: %v", i, err) - } - // Check all existing and non existing values - for j := 0; j < len(tests); j++ { - num := db.fetchInt64(tests[j].key) - switch { - case j <= i && num != tests[j].value: - t.Errorf("test %d, item %d: value mismatch: have %v, want %v", i, j, num, tests[j].value) - case j > i && num != 0: - t.Errorf("test %d, item %d: value mismatch: have %v, want %v", i, j, num, 0) - } - } - } -} - -func TestNodeDBFetchStore(t *testing.T) { - node := NewNode( - MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), - net.IP{192, 168, 0, 1}, - 30303, - 30303, - ) - inst := time.Now() - num := 314 - - db, _ := newNodeDB("", Version, NodeID{}) - defer db.close() - - // Check fetch/store operations on a node ping object - if stored := db.lastPing(node.ID); stored.Unix() != 0 { - t.Errorf("ping: non-existing object: %v", stored) - } - if err := db.updateLastPing(node.ID, inst); err != nil { - t.Errorf("ping: failed to update: %v", err) - } - if stored := db.lastPing(node.ID); 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.lastPong(node.ID); stored.Unix() != 0 { - t.Errorf("pong: non-existing object: %v", stored) - } - if err := db.updateLastPong(node.ID, inst); err != nil { - t.Errorf("pong: failed to update: %v", err) - } - if stored := db.lastPong(node.ID); 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 { - t.Errorf("find-node fails: non-existing object: %v", stored) - } - if err := db.updateFindFails(node.ID, num); err != nil { - t.Errorf("find-node fails: failed to update: %v", err) - } - if stored := db.findFails(node.ID); stored != num { - t.Errorf("find-node fails: value mismatch: have %v, want %v", stored, num) - } - // Check fetch/store operations on an actual node object - if stored := db.node(node.ID); stored != nil { - t.Errorf("node: non-existing object: %v", stored) - } - if err := db.updateNode(node); err != nil { - t.Errorf("node: failed to update: %v", err) - } - if stored := db.node(node.ID); stored == nil { - t.Errorf("node: not found") - } else if !reflect.DeepEqual(stored, node) { - t.Errorf("node: data mismatch: have %v, want %v", stored, node) - } -} - -var nodeDBSeedQueryNodes = []struct { - node *Node - pong time.Time -}{ - // This one should not be in the result set because its last - // pong time is too far in the past. - { - node: NewNode( - MustHexID("0x84d9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), - net.IP{127, 0, 0, 3}, - 30303, - 30303, - ), - pong: time.Now().Add(-3 * time.Hour), - }, - // This one shouldn't be in in the result set because its - // nodeID is the local node's ID. - { - node: NewNode( - MustHexID("0x57d9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), - net.IP{127, 0, 0, 3}, - 30303, - 30303, - ), - pong: time.Now().Add(-4 * time.Second), - }, - - // These should be in the result set. - { - node: NewNode( - MustHexID("0x22d9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), - net.IP{127, 0, 0, 1}, - 30303, - 30303, - ), - pong: time.Now().Add(-2 * time.Second), - }, - { - node: NewNode( - MustHexID("0x44d9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), - net.IP{127, 0, 0, 2}, - 30303, - 30303, - ), - pong: time.Now().Add(-3 * time.Second), - }, - { - node: NewNode( - MustHexID("0xe2d9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), - net.IP{127, 0, 0, 3}, - 30303, - 30303, - ), - pong: time.Now().Add(-1 * time.Second), - }, -} - -func TestNodeDBSeedQuery(t *testing.T) { - db, _ := newNodeDB("", Version, nodeDBSeedQueryNodes[1].node.ID) - defer db.close() - - // Insert a batch of nodes for querying - for i, seed := range nodeDBSeedQueryNodes { - if err := db.updateNode(seed.node); err != nil { - t.Fatalf("node %d: failed to insert: %v", i, err) - } - if err := db.updateLastPong(seed.node.ID, seed.pong); err != nil { - t.Fatalf("node %d: failed to insert lastPong: %v", i, err) - } - } - - // Retrieve the entire batch and check for duplicates - seeds := db.querySeeds(len(nodeDBSeedQueryNodes)*2, time.Hour) - have := make(map[NodeID]struct{}) - for _, seed := range seeds { - have[seed.ID] = struct{}{} - } - want := make(map[NodeID]struct{}) - for _, seed := range nodeDBSeedQueryNodes[2:] { - want[seed.node.ID] = struct{}{} - } - if len(seeds) != len(want) { - t.Errorf("seed count mismatch: have %v, want %v", len(seeds), len(want)) - } - for id := range have { - if _, ok := want[id]; !ok { - t.Errorf("extra seed: %v", id) - } - } - for id := range want { - if _, ok := have[id]; !ok { - t.Errorf("missing seed: %v", id) - } - } -} - -func TestNodeDBPersistency(t *testing.T) { - root, err := ioutil.TempDir("", "nodedb-") - if err != nil { - t.Fatalf("failed to create temporary data folder: %v", err) - } - defer os.RemoveAll(root) - - var ( - testKey = []byte("somekey") - testInt = int64(314) - ) - - // Create a persistent database and store some values - db, err := newNodeDB(filepath.Join(root, "database"), Version, NodeID{}) - if err != nil { - t.Fatalf("failed to create persistent database: %v", err) - } - if err := db.storeInt64(testKey, testInt); err != nil { - t.Fatalf("failed to store value: %v.", err) - } - db.close() - - // Reopen the database and check the value - db, err = newNodeDB(filepath.Join(root, "database"), Version, NodeID{}) - if err != nil { - t.Fatalf("failed to open persistent database: %v", err) - } - if val := db.fetchInt64(testKey); val != testInt { - t.Fatalf("value mismatch: have %v, want %v", val, testInt) - } - db.close() - - // Change the database version and check flush - db, err = newNodeDB(filepath.Join(root, "database"), Version+1, NodeID{}) - if err != nil { - t.Fatalf("failed to open persistent database: %v", err) - } - if val := db.fetchInt64(testKey); val != 0 { - t.Fatalf("value mismatch: have %v, want %v", val, 0) - } - db.close() -} - -var nodeDBExpirationNodes = []struct { - node *Node - pong time.Time - exp bool -}{ - { - node: NewNode( - MustHexID("0x01d9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), - net.IP{127, 0, 0, 1}, - 30303, - 30303, - ), - pong: time.Now().Add(-nodeDBNodeExpiration + time.Minute), - exp: false, - }, { - node: NewNode( - MustHexID("0x02d9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), - net.IP{127, 0, 0, 2}, - 30303, - 30303, - ), - pong: time.Now().Add(-nodeDBNodeExpiration - time.Minute), - exp: true, - }, -} - -func TestNodeDBExpiration(t *testing.T) { - db, _ := newNodeDB("", Version, NodeID{}) - defer db.close() - - // 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 err := db.updateLastPong(seed.node.ID, seed.pong); err != nil { - t.Fatalf("node %d: failed to update pong: %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) - } - 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) - } - } -} - -func TestNodeDBSelfExpiration(t *testing.T) { - // Find a node in the tests that shouldn't expire, and assign it as self - var self NodeID - for _, node := range nodeDBExpirationNodes { - if !node.exp { - self = node.node.ID - break - } - } - db, _ := newNodeDB("", Version, self) - defer db.close() - - // 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 err := db.updateLastPong(seed.node.ID, seed.pong); err != nil { - t.Fatalf("node %d: failed to update pong: %v", i, err) - } - } - // Expire the nodes and make sure self has been evacuated too - if err := db.expireNodes(); err != nil { - t.Fatalf("failed to expire nodes: %v", err) - } - node := db.node(self) - if node != nil { - t.Errorf("self not evacuated") - } -} diff --git a/p2p/discover/node.go b/p2p/discover/node.go index fc928a91af..8d4af166bb 100644 --- a/p2p/discover/node.go +++ b/p2p/discover/node.go @@ -18,415 +18,88 @@ package discover import ( "crypto/ecdsa" - "crypto/elliptic" - "encoding/hex" "errors" - "fmt" "math/big" - "math/rand" "net" - "net/url" - "regexp" - "strconv" - "strings" + "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/secp256k1" + "github.com/ethereum/go-ethereum/p2p/enode" ) -const NodeIDBits = 512 - -// Node represents a host on the network. +// node represents a host on the network. // The fields of Node may not be modified. -type Node struct { - IP net.IP // len 4 for IPv4 or 16 for IPv6 - UDP, TCP uint16 // port numbers - ID NodeID // the node's public key - - // This is a cached copy of sha3(ID) which is used for node - // distance calculations. This is part of Node in order to make it - // possible to write tests that need a node at a certain distance. - // In those tests, the content of sha will not actually correspond - // with ID. - sha common.Hash - - // whether this node is currently being pinged in order to replace - // it in a bucket - contested bool +type node struct { + enode.Node + addedAt time.Time // time when the node was added to the table + livenessChecks uint // how often liveness was checked } -// NewNode creates a new node. It is mostly meant to be used for -// testing purposes. -func NewNode(id NodeID, ip net.IP, udpPort, tcpPort uint16) *Node { - if ipv4 := ip.To4(); ipv4 != nil { - ip = ipv4 - } - return &Node{ - IP: ip, - UDP: udpPort, - TCP: tcpPort, - ID: id, - sha: crypto.Keccak256Hash(id[:]), - } +type encPubkey [64]byte + +func encodePubkey(key *ecdsa.PublicKey) encPubkey { + var e encPubkey + math.ReadBits(key.X, e[:len(e)/2]) + math.ReadBits(key.Y, e[len(e)/2:]) + return e } -func (n *Node) addr() *net.UDPAddr { - return &net.UDPAddr{IP: n.IP, Port: int(n.UDP)} -} - -// Incomplete returns true for nodes with no IP address. -func (n *Node) Incomplete() bool { - return n.IP == nil -} - -// checks whether n is a valid complete node. -func (n *Node) validateComplete() error { - if n.Incomplete() { - return errors.New("incomplete node") - } - if n.UDP == 0 { - return errors.New("missing UDP port") - } - if n.TCP == 0 { - return errors.New("missing TCP port") - } - if n.IP.IsMulticast() || n.IP.IsUnspecified() { - return errors.New("invalid IP (multicast/unspecified)") - } - _, err := n.ID.Pubkey() // validate the key (on curve, etc.) - return err -} - -// The string representation of a Node is a URL. -// Please see ParseNode for a description of the format. -func (n *Node) String() string { - u := url.URL{Scheme: "enode"} - if n.Incomplete() { - u.Host = fmt.Sprintf("%x", n.ID[:]) - } else { - addr := net.TCPAddr{IP: n.IP, Port: int(n.TCP)} - u.User = url.User(fmt.Sprintf("%x", n.ID[:])) - u.Host = addr.String() - if n.UDP != n.TCP { - u.RawQuery = "discport=" + strconv.Itoa(int(n.UDP)) - } - } - return u.String() -} - -var incompleteNodeURL = regexp.MustCompile("(?i)^(?:enode://)?([0-9a-f]+)$") - -// ParseNode parses a node designator. -// -// There are two basic forms of node designators -// - incomplete nodes, which only have the public key (node ID) -// - complete nodes, which contain the public key and IP/Port information -// -// For incomplete nodes, the designator must look like one of these -// -// enode:// -// -// -// For complete nodes, the node ID is encoded in the username portion -// of the URL, separated from the host by an @ sign. The hostname can -// only be given as an IP address, DNS domain names are not allowed. -// The port in the host name section is the TCP listening port. If the -// TCP and UDP (discovery) ports differ, the UDP port is specified as -// query parameter "discport". -// -// In the following example, the node URL describes -// a node with IP address 10.3.58.6, TCP listening port 30303 -// and UDP discovery port 30301. -// -// enode://@10.3.58.6:30303?discport=30301 -func ParseNode(rawurl string) (*Node, error) { - if m := incompleteNodeURL.FindStringSubmatch(rawurl); m != nil { - id, err := HexID(m[1]) - if err != nil { - return nil, fmt.Errorf("invalid node ID (%v)", err) - } - return NewNode(id, nil, 0, 0), nil - } - return parseComplete(rawurl) -} - -func parseComplete(rawurl string) (*Node, error) { - var ( - id NodeID - ip net.IP - tcpPort, udpPort uint64 - ) - u, err := url.Parse(rawurl) - if err != nil { - return nil, err - } - if u.Scheme != "enode" { - return nil, errors.New("invalid URL scheme, want \"enode\"") - } - // Parse the Node ID from the user portion. - if u.User == nil { - return nil, errors.New("does not contain node ID") - } - if id, err = HexID(u.User.String()); err != nil { - return nil, fmt.Errorf("invalid node ID (%v)", err) - } - // Parse the IP address. - host, port, err := net.SplitHostPort(u.Host) - if err != nil { - return nil, fmt.Errorf("invalid host: %v", err) - } - if ip = net.ParseIP(host); ip == nil { - return nil, errors.New("invalid IP address") - } - // Ensure the IP is 4 bytes long for IPv4 addresses. - if ipv4 := ip.To4(); ipv4 != nil { - ip = ipv4 - } - // Parse the port numbers. - if tcpPort, err = strconv.ParseUint(port, 10, 16); err != nil { - return nil, errors.New("invalid port") - } - udpPort = tcpPort - qv := u.Query() - if qv.Get("discport") != "" { - udpPort, err = strconv.ParseUint(qv.Get("discport"), 10, 16) - if err != nil { - return nil, errors.New("invalid discport in query") - } - } - return NewNode(id, ip, uint16(udpPort), uint16(tcpPort)), nil -} - -// MustParseNode parses a node URL. It panics if the URL is not valid. -func MustParseNode(rawurl string) *Node { - n, err := ParseNode(rawurl) - if err != nil { - panic("invalid node URL: " + err.Error()) - } - return n -} - -// MarshalText implements encoding.TextMarshaler. -func (n *Node) MarshalText() ([]byte, error) { - return []byte(n.String()), nil -} - -// UnmarshalText implements encoding.TextUnmarshaler. -func (n *Node) UnmarshalText(text []byte) error { - dec, err := ParseNode(string(text)) - if err == nil { - *n = *dec - } - return err -} - -// NodeID is a unique identifier for each node. -// The node identifier is a marshaled elliptic curve public key. -type NodeID [NodeIDBits / 8]byte - -// Bytes returns a byte slice representation of the NodeID -func (n NodeID) Bytes() []byte { - return n[:] -} - -// NodeID prints as a long hexadecimal number. -func (n NodeID) String() string { - return fmt.Sprintf("%x", n[:]) -} - -// The Go syntax representation of a NodeID is a call to HexID. -func (n NodeID) GoString() string { - return fmt.Sprintf("discover.HexID(\"%x\")", n[:]) -} - -// TerminalString returns a shortened hex string for terminal logging. -func (n NodeID) TerminalString() string { - return hex.EncodeToString(n[:8]) -} - -// MarshalText implements the encoding.TextMarshaler interface. -func (n NodeID) MarshalText() ([]byte, error) { - return []byte(hex.EncodeToString(n[:])), nil -} - -// UnmarshalText implements the encoding.TextUnmarshaler interface. -func (n *NodeID) UnmarshalText(text []byte) error { - id, err := HexID(string(text)) - if err != nil { - return err - } - *n = id - return nil -} - -// BytesID converts a byte slice to a NodeID -func BytesID(b []byte) (NodeID, error) { - var id NodeID - if len(b) != len(id) { - return id, fmt.Errorf("wrong length, want %d bytes", len(id)) - } - copy(id[:], b) - return id, nil -} - -// MustBytesID converts a byte slice to a NodeID. -// It panics if the byte slice is not a valid NodeID. -func MustBytesID(b []byte) NodeID { - id, err := BytesID(b) - if err != nil { - panic(err) - } - return id -} - -// HexID converts a hex string to a NodeID. -// The string may be prefixed with 0x. -func HexID(in string) (NodeID, error) { - var id NodeID - b, err := hex.DecodeString(strings.TrimPrefix(in, "0x")) - if err != nil { - return id, err - } else if len(b) != len(id) { - return id, fmt.Errorf("wrong length, want %d hex chars", len(id)*2) - } - copy(id[:], b) - return id, nil -} - -// MustHexID converts a hex string to a NodeID. -// It panics if the string is not a valid NodeID. -func MustHexID(in string) NodeID { - id, err := HexID(in) - if err != nil { - panic(err) - } - return id -} - -// PubkeyID returns a marshaled representation of the given public key. -func PubkeyID(pub *ecdsa.PublicKey) NodeID { - var id NodeID - pbytes := elliptic.Marshal(pub.Curve, pub.X, pub.Y) - if len(pbytes)-1 != len(id) { - panic(fmt.Errorf("need %d bit pubkey, got %d bits", (len(id)+1)*8, len(pbytes))) - } - copy(id[:], pbytes[1:]) - return id -} - -// Pubkey returns the public key represented by the node ID. -// It returns an error if the ID is not a point on the curve. -func (id NodeID) Pubkey() (*ecdsa.PublicKey, error) { +func decodePubkey(e encPubkey) (*ecdsa.PublicKey, error) { p := &ecdsa.PublicKey{Curve: crypto.S256(), X: new(big.Int), Y: new(big.Int)} - half := len(id) / 2 - p.X.SetBytes(id[:half]) - p.Y.SetBytes(id[half:]) + half := len(e) / 2 + p.X.SetBytes(e[:half]) + p.Y.SetBytes(e[half:]) if !p.Curve.IsOnCurve(p.X, p.Y) { - return nil, errors.New("id is invalid secp256k1 curve point") + return nil, errors.New("invalid secp256k1 curve point") } return p, nil } -// recoverNodeID computes the public key used to sign the +func (e encPubkey) id() enode.ID { + return enode.ID(crypto.Keccak256Hash(e[:])) +} + +// recoverNodeKey computes the public key used to sign the // given hash from the signature. -func recoverNodeID(hash, sig []byte) (id NodeID, err error) { +func recoverNodeKey(hash, sig []byte) (key encPubkey, err error) { pubkey, err := secp256k1.RecoverPubkey(hash, sig) if err != nil { - return id, err + return key, err } - if len(pubkey)-1 != len(id) { - return id, fmt.Errorf("recovered pubkey has %d bits, want %d bits", len(pubkey)*8, (len(id)+1)*8) - } - for i := range id { - id[i] = pubkey[i+1] - } - return id, nil + copy(key[:], pubkey[1:]) + return key, nil } -// distcmp compares the distances a->target and b->target. -// Returns -1 if a is closer to target, 1 if b is closer to target -// and 0 if they are equal. -func distcmp(target, a, b common.Hash) int { - for i := range target { - da := a[i] ^ target[i] - db := b[i] ^ target[i] - if da > db { - return 1 - } else if da < db { - return -1 - } - } - return 0 +func wrapNode(n *enode.Node) *node { + return &node{Node: *n} } -// table of leading zero counts for bytes [0..255] -var lzcount = [256]int{ - 8, 7, 6, 6, 5, 5, 5, 5, - 4, 4, 4, 4, 4, 4, 4, 4, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 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, 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, 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, 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, 0, 0, 0, 0, +func wrapNodes(ns []*enode.Node) []*node { + result := make([]*node, len(ns)) + for i, n := range ns { + result[i] = wrapNode(n) + } + return result } -// logdist returns the logarithmic distance between a and b, log2(a ^ b). -func logdist(a, b common.Hash) int { - lz := 0 - for i := range a { - x := a[i] ^ b[i] - if x == 0 { - lz += 8 - } else { - lz += lzcount[x] - break - } - } - return len(a)*8 - lz +func unwrapNode(n *node) *enode.Node { + return &n.Node } -// hashAtDistance returns a random hash such that logdist(a, b) == n -func hashAtDistance(a common.Hash, n int) (b common.Hash) { - if n == 0 { - return a +func unwrapNodes(ns []*node) []*enode.Node { + result := make([]*enode.Node, len(ns)) + for i, n := range ns { + result[i] = unwrapNode(n) } - // flip bit at position n, fill the rest with random bits - b = a - pos := len(a) - n/8 - 1 - bit := byte(0x01) << (byte(n%8) - 1) - if bit == 0 { - pos++ - bit = 0x80 - } - b[pos] = a[pos]&^bit | ^a[pos]&bit // TODO: randomize end bits - for i := pos + 1; i < len(a); i++ { - b[i] = byte(rand.Intn(255)) - } - return b + return result +} + +func (n *node) addr() *net.UDPAddr { + return &net.UDPAddr{IP: n.IP(), Port: n.UDP()} +} + +func (n *node) String() string { + return n.Node.String() } diff --git a/p2p/discover/table.go b/p2p/discover/table.go index ec4eb94ad5..ef0c08afce 100644 --- a/p2p/discover/table.go +++ b/p2p/discover/table.go @@ -23,10 +23,11 @@ package discover import ( - "crypto/rand" + "crypto/ecdsa" + crand "crypto/rand" "encoding/binary" - "errors" "fmt" + mrand "math/rand" "net" "sort" "sync" @@ -35,121 +36,139 @@ import ( "github.com/ethereum/go-ethereum/common" "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/netutil" ) const ( - alpha = 3 // Kademlia concurrency factor - bucketSize = 16 // Kademlia bucket size - hashBits = len(common.Hash{}) * 8 - nBuckets = hashBits + 1 // Number of buckets + alpha = 3 // Kademlia concurrency factor + bucketSize = 16 // Kademlia bucket size + maxReplacements = 10 // Size of per-bucket replacement list - maxBondingPingPongs = 16 - maxFindnodeFailures = 5 + // We keep buckets for the upper 1/15 of distances because + // it's very unlikely we'll ever encounter a node that's closer. + hashBits = len(common.Hash{}) * 8 + nBuckets = hashBits / 15 // Number of buckets + bucketMinDistance = hashBits - nBuckets // Log distance of closest bucket - autoRefreshInterval = 1 * time.Hour + // IP address limits. + bucketIPLimit, bucketSubnet = 2, 24 // at most 2 addresses from the same /24 + tableIPLimit, tableSubnet = 10, 24 + + maxFindnodeFailures = 5 // Nodes exceeding this limit are dropped + refreshInterval = 30 * time.Minute + revalidateInterval = 10 * time.Second + copyNodesInterval = 30 * time.Second + seedMinTableTime = 5 * time.Minute seedCount = 30 seedMaxAge = 5 * 24 * time.Hour ) type Table struct { - mutex sync.Mutex // protects buckets, their content, and nursery + mutex sync.Mutex // protects buckets, bucket content, nursery, rand buckets [nBuckets]*bucket // index of known nodes by distance - nursery []*Node // bootstrap nodes - db *nodeDB // database of known nodes + nursery []*node // bootstrap nodes + rand *mrand.Rand // source of randomness, periodically reseeded + ips netutil.DistinctNetSet + db *enode.DB // database of known nodes + net transport refreshReq chan chan struct{} - closeReq chan struct{} - closed chan struct{} + initDone chan struct{} - bondmu sync.Mutex - bonding map[NodeID]*bondproc - bondslots chan struct{} // limits total number of active bonding processes + closeOnce sync.Once + closeReq chan struct{} + closed chan struct{} - nodeAddedHook func(*Node) // for testing - - net transport - self *Node // metadata of the local node -} - -type bondproc struct { - err error - n *Node - done chan struct{} + nodeAddedHook func(*node) // for testing } // transport is implemented by the UDP transport. // it is an interface so we can test without opening lots of UDP // sockets and without generating a private key. type transport interface { - ping(NodeID, *net.UDPAddr) error - waitping(NodeID) error - findnode(toid NodeID, addr *net.UDPAddr, target NodeID) ([]*Node, error) + self() *enode.Node + ping(enode.ID, *net.UDPAddr) error + findnode(toid enode.ID, addr *net.UDPAddr, target encPubkey) ([]*node, error) close() } // bucket contains nodes, ordered by their last activity. the entry // that was most recently active is the first element in entries. -type bucket struct{ entries []*Node } +type bucket struct { + entries []*node // live entries, sorted by time of last contact + replacements []*node // recently seen nodes to be used if revalidation fails + ips netutil.DistinctNetSet +} -func newTable(t transport, ourID NodeID, ourAddr *net.UDPAddr, nodeDBPath string) (*Table, error) { - // If no node database was given, use an in-memory one - db, err := newNodeDB(nodeDBPath, Version, ourID) - if err != nil { - return nil, err - } +func newTable(t transport, db *enode.DB, bootnodes []*enode.Node) (*Table, error) { tab := &Table{ net: t, db: db, - self: NewNode(ourID, ourAddr.IP, uint16(ourAddr.Port), uint16(ourAddr.Port)), - bonding: make(map[NodeID]*bondproc), - bondslots: make(chan struct{}, maxBondingPingPongs), refreshReq: make(chan chan struct{}), + initDone: make(chan struct{}), closeReq: make(chan struct{}), closed: make(chan struct{}), + rand: mrand.New(mrand.NewSource(0)), + ips: netutil.DistinctNetSet{Subnet: tableSubnet, Limit: tableIPLimit}, } - for i := 0; i < cap(tab.bondslots); i++ { - tab.bondslots <- struct{}{} + if err := tab.setFallbackNodes(bootnodes); err != nil { + return nil, err } for i := range tab.buckets { - tab.buckets[i] = new(bucket) + tab.buckets[i] = &bucket{ + ips: netutil.DistinctNetSet{Subnet: bucketSubnet, Limit: bucketIPLimit}, + } } - go tab.refreshLoop() + tab.seedRand() + tab.loadSeedNodes() + + go tab.loop() return tab, nil } -// Self returns the local node. -// The returned node should not be modified by the caller. -func (tab *Table) Self() *Node { - return tab.self +func (tab *Table) self() *enode.Node { + return tab.net.self() } -// ReadRandomNodes fills the given slice with random nodes from the -// table. It will not write the same node more than once. The nodes in -// the slice are copies and can be modified by the caller. -func (tab *Table) ReadRandomNodes(buf []*Node) (n int) { +func (tab *Table) seedRand() { + var b [8]byte + crand.Read(b[:]) + + tab.mutex.Lock() + tab.rand.Seed(int64(binary.BigEndian.Uint64(b[:]))) + tab.mutex.Unlock() +} + +// ReadRandomNodes fills the given slice with random nodes from the table. The results +// are guaranteed to be unique for a single invocation, no node will appear twice. +func (tab *Table) ReadRandomNodes(buf []*enode.Node) (n int) { + if !tab.isInitDone() { + return 0 + } tab.mutex.Lock() defer tab.mutex.Unlock() - // TODO: tree-based buckets would help here + // Find all non-empty buckets and get a fresh slice of their entries. - var buckets [][]*Node - for _, b := range tab.buckets { + var buckets [][]*node + for _, b := range &tab.buckets { if len(b.entries) > 0 { - buckets = append(buckets, b.entries[:]) + buckets = append(buckets, b.entries) } } if len(buckets) == 0 { return 0 } // Shuffle the buckets. - for i := uint32(len(buckets)) - 1; i > 0; i-- { - j := randUint(i) + for i := len(buckets) - 1; i > 0; i-- { + j := tab.rand.Intn(len(buckets)) buckets[i], buckets[j] = buckets[j], buckets[i] } // Move head of each bucket into buf, removing buckets that become empty. var i, j int for ; i < len(buf); i, j = i+1, (j+1)%len(buckets) { b := buckets[j] - buf[i] = &(*b[0]) + buf[i] = unwrapNode(b[0]) buckets[j] = b[1:] if len(b) == 1 { buckets = append(buckets[:j], buckets[j+1:]...) @@ -161,91 +180,85 @@ func (tab *Table) ReadRandomNodes(buf []*Node) (n int) { return i + 1 } -func randUint(max uint32) uint32 { - if max == 0 { - return 0 - } - var b [4]byte - rand.Read(b[:]) - return binary.BigEndian.Uint32(b[:]) % max -} - // Close terminates the network listener and flushes the node database. func (tab *Table) 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 +// setFallbackNodes sets the initial points of contact. These nodes // are used to connect to the network if the table is empty and there // are no known nodes in the database. -func (tab *Table) SetFallbackNodes(nodes []*Node) error { +func (tab *Table) setFallbackNodes(nodes []*enode.Node) error { for _, n := range nodes { - if err := n.validateComplete(); err != nil { - return fmt.Errorf("bad bootstrap/fallback node %q (%v)", n, err) + if err := n.ValidateComplete(); err != nil { + return fmt.Errorf("bad bootstrap node %q: %v", n, err) } } - tab.mutex.Lock() - tab.nursery = make([]*Node, 0, len(nodes)) - for _, n := range nodes { - cpy := *n - // Recompute cpy.sha because the node might not have been - // created by NewNode or ParseNode. - cpy.sha = crypto.Keccak256Hash(n.ID[:]) - tab.nursery = append(tab.nursery, &cpy) - } - tab.mutex.Unlock() - tab.refresh() + tab.nursery = wrapNodes(nodes) return nil } +// isInitDone returns whether the table's initial seeding procedure has completed. +func (tab *Table) isInitDone() bool { + select { + case <-tab.initDone: + return true + default: + return false + } +} + // Resolve searches for a specific node with the given ID. // It returns nil if the node could not be found. -func (tab *Table) Resolve(targetID NodeID) *Node { +func (tab *Table) Resolve(n *enode.Node) *enode.Node { // If the node is present in the local table, no // network interaction is required. - hash := crypto.Keccak256Hash(targetID[:]) + hash := n.ID() tab.mutex.Lock() cl := tab.closest(hash, 1) tab.mutex.Unlock() - if len(cl.entries) > 0 && cl.entries[0].ID == targetID { - return cl.entries[0] + if len(cl.entries) > 0 && cl.entries[0].ID() == hash { + return unwrapNode(cl.entries[0]) } // Otherwise, do a network lookup. - result := tab.Lookup(targetID) + result := tab.lookup(encodePubkey(n.Pubkey()), true) for _, n := range result { - if n.ID == targetID { - return n + if n.ID() == hash { + return unwrapNode(n) } } return nil } -// Lookup performs a network search for nodes close -// to the given target. It approaches the target by querying -// nodes that are closer to it on each iteration. -// The given target does not need to be an actual node -// identifier. -func (tab *Table) Lookup(targetID NodeID) []*Node { - return tab.lookup(targetID, true) +// LookupRandom finds random nodes in the network. +func (tab *Table) LookupRandom() []*enode.Node { + var target encPubkey + crand.Read(target[:]) + return unwrapNodes(tab.lookup(target, true)) } -func (tab *Table) lookup(targetID NodeID, refreshIfEmpty bool) []*Node { +// lookup performs a network search for nodes close to the given target. It approaches the +// target by querying nodes that are closer to it on each iteration. The given target does +// not need to be an actual node identifier. +func (tab *Table) lookup(targetKey encPubkey, refreshIfEmpty bool) []*node { var ( - target = crypto.Keccak256Hash(targetID[:]) - asked = make(map[NodeID]bool) - seen = make(map[NodeID]bool) - reply = make(chan []*Node, alpha) + target = enode.ID(crypto.Keccak256Hash(targetKey[:])) + asked = make(map[enode.ID]bool) + seen = make(map[enode.ID]bool) + reply = make(chan []*node, alpha) pendingQueries = 0 result *nodesByDistance ) // don't query further if we hit ourself. // unlikely to happen often in practice. - asked[tab.self.ID] = true + asked[tab.self().ID()] = true for { tab.mutex.Lock() @@ -267,95 +280,128 @@ func (tab *Table) lookup(targetID NodeID, refreshIfEmpty bool) []*Node { // ask the alpha closest nodes that we haven't asked yet for i := 0; i < len(result.entries) && pendingQueries < alpha; i++ { n := result.entries[i] - if !asked[n.ID] { - asked[n.ID] = true + if !asked[n.ID()] { + asked[n.ID()] = true pendingQueries++ - go func() { - // Find potential neighbors to bond with - r, err := tab.net.findnode(n.ID, n.addr(), targetID) - if err != nil { - // Bump the failure counter to detect and evacuate non-bonded entries - fails := tab.db.findFails(n.ID) + 1 - tab.db.updateFindFails(n.ID, fails) - log.Trace("Bumping findnode failure counter", "id", n.ID, "failcount", fails) - - if fails >= maxFindnodeFailures { - log.Trace("Too many findnode failures, dropping", "id", n.ID, "failcount", fails) - tab.delete(n) - } - } - reply <- tab.bondall(r) - }() + go tab.findnode(n, targetKey, reply) } } if pendingQueries == 0 { // 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-- } return result.entries } +func (tab *Table) findnode(n *node, targetKey encPubkey, reply chan<- []*node) { + fails := tab.db.FindFails(n.ID(), n.IP()) + r, err := tab.net.findnode(n.ID(), n.addr(), targetKey) + if err == errClosed { + // Avoid recording failures on shutdown. + reply <- nil + return + } else if err != nil || len(r) == 0 { + 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(), 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.addSeenNode(n) + } + reply <- r +} + 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 } -// refreshLoop schedules doRefresh runs and coordinates shutdown. -func (tab *Table) refreshLoop() { +// loop schedules refresh, revalidate runs and coordinates shutdown. +func (tab *Table) loop() { var ( - timer = time.NewTicker(autoRefreshInterval) - waiting []chan struct{} // accumulates waiting callers while doRefresh runs - done chan struct{} // where doRefresh reports completion + revalidate = time.NewTimer(tab.nextRevalidateTime()) + refresh = time.NewTicker(refreshInterval) + copyNodes = time.NewTicker(copyNodesInterval) + refreshDone = make(chan struct{}) // where doRefresh reports completion + revalidateDone chan struct{} // where doRevalidate reports completion + waiting = []chan struct{}{tab.initDone} // holds waiting callers while doRefresh runs ) + defer refresh.Stop() + defer revalidate.Stop() + defer copyNodes.Stop() + + // Start initial refresh. + go tab.doRefresh(refreshDone) + loop: for { select { - case <-timer.C: - if done == nil { - done = make(chan struct{}) - go tab.doRefresh(done) + case <-refresh.C: + tab.seedRand() + if refreshDone == nil { + refreshDone = make(chan struct{}) + go tab.doRefresh(refreshDone) } case req := <-tab.refreshReq: waiting = append(waiting, req) - if done == nil { - done = make(chan struct{}) - go tab.doRefresh(done) + if refreshDone == nil { + refreshDone = make(chan struct{}) + go tab.doRefresh(refreshDone) } - case <-done: + case <-refreshDone: for _, ch := range waiting { close(ch) } - waiting = nil - done = nil + waiting, refreshDone = nil, nil + case <-revalidate.C: + revalidateDone = make(chan struct{}) + go tab.doRevalidate(revalidateDone) + case <-revalidateDone: + revalidate.Reset(tab.nextRevalidateTime()) + revalidateDone = nil + case <-copyNodes.C: + go tab.copyLiveNodes() case <-tab.closeReq: break loop } } - if tab.net != nil { - tab.net.close() - } - if done != nil { - <-done + if refreshDone != nil { + <-refreshDone } for _, ch := range waiting { close(ch) } - tab.db.close() + if revalidateDone != nil { + <-revalidateDone + } close(tab.closed) } @@ -365,286 +411,306 @@ loop: func (tab *Table) doRefresh(done chan struct{}) { defer close(done) + // Load nodes from the database and insert + // them. This should yield a few previously seen nodes that are + // (hopefully) still alive. + tab.loadSeedNodes() + + // Run self lookup to discover new neighbor nodes. + // We can only do this if we have a secp256k1 identity. + var key ecdsa.PublicKey + if err := tab.self().Load((*enode.Secp256k1)(&key)); err == nil { + tab.lookup(encodePubkey(&key), false) + } + // The Kademlia paper specifies that the bucket refresh should // perform a lookup in the least recently used bucket. We cannot // adhere to this because the findnode target is a 512bit value // (not hash-sized) and it is not easily possible to generate a // sha3 preimage that falls into a chosen bucket. - // We perform a lookup with a random target instead. - var target NodeID - rand.Read(target[:]) - result := tab.lookup(target, false) - if len(result) > 0 { + // We perform a few lookups with a random target instead. + for i := 0; i < 3; i++ { + var target encPubkey + crand.Read(target[:]) + tab.lookup(target, false) + } +} + +func (tab *Table) loadSeedNodes() { + seeds := wrapNodes(tab.db.QuerySeeds(seedCount, seedMaxAge)) + 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(), seed.IP())) }} + log.Trace("Found seed node in database", "id", seed.ID(), "addr", seed.addr(), "age", age) + tab.addSeenNode(seed) + } +} + +// doRevalidate checks that the last node in a random bucket is still live +// and replaces or deletes the node if it isn't. +func (tab *Table) doRevalidate(done chan<- struct{}) { + defer func() { done <- struct{}{} }() + + last, bi := tab.nodeToRevalidate() + if last == nil { + // No non-empty bucket found. return } - // The table is empty. Load nodes from the database and insert - // them. This should yield a few previously seen nodes that are - // (hopefully) still alive. - seeds := tab.db.querySeeds(seedCount, seedMaxAge) - seeds = tab.bondall(append(seeds, tab.nursery...)) + // Ping the selected node and wait for a pong. + err := tab.net.ping(last.ID(), last.addr()) - if len(seeds) == 0 { - log.Debug("No discv4 seed nodes found") - } - for _, n := range seeds { - age := log.Lazy{Fn: func() time.Duration { return time.Since(tab.db.lastPong(n.ID)) }} - log.Trace("Found seed node in database", "id", n.ID, "addr", n.addr(), "age", age) - } tab.mutex.Lock() - tab.stuff(seeds) - tab.mutex.Unlock() + defer tab.mutex.Unlock() + b := tab.buckets[bi] + if err == nil { + // The node responded, move it to the front. + 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(), "checks", last.livenessChecks, "r", r.ID(), "rip", r.IP()) + } else { + log.Debug("Removed dead node", "b", bi, "id", last.ID(), "ip", last.IP(), "checks", last.livenessChecks) + } +} - // Finally, do a self lookup to fill up the buckets. - tab.lookup(tab.self.ID, false) +// nodeToRevalidate returns the last node in a random, non-empty bucket. +func (tab *Table) nodeToRevalidate() (n *node, bi int) { + tab.mutex.Lock() + defer tab.mutex.Unlock() + + for _, bi = range tab.rand.Perm(len(tab.buckets)) { + b := tab.buckets[bi] + if len(b.entries) > 0 { + last := b.entries[len(b.entries)-1] + return last, bi + } + } + return nil, 0 +} + +func (tab *Table) nextRevalidateTime() time.Duration { + tab.mutex.Lock() + defer tab.mutex.Unlock() + + return time.Duration(tab.rand.Int63n(int64(revalidateInterval))) +} + +// copyLiveNodes adds nodes from the table to the database if they have been in the table +// longer then minTableTime. +func (tab *Table) copyLiveNodes() { + tab.mutex.Lock() + defer tab.mutex.Unlock() + + now := time.Now() + for _, b := range &tab.buckets { + for _, n := range b.entries { + if n.livenessChecks > 0 && now.Sub(n.addedAt) >= seedMinTableTime { + tab.db.UpdateNode(unwrapNode(n)) + } + } + } } // closest returns the n nodes in the table that are closest to the // given id. The caller must hold tab.mutex. -func (tab *Table) closest(target common.Hash, nresults int) *nodesByDistance { +func (tab *Table) closest(target enode.ID, nresults int) *nodesByDistance { // This is a very wasteful way to find the closest nodes but // obviously correct. I believe that tree-based buckets would make // this easier to implement efficiently. close := &nodesByDistance{target: target} - for _, b := range tab.buckets { + for _, b := range &tab.buckets { for _, n := range b.entries { - close.push(n, nresults) + if n.livenessChecks > 0 { + close.push(n, nresults) + } } } return close } func (tab *Table) len() (n int) { - for _, b := range tab.buckets { + for _, b := range &tab.buckets { n += len(b.entries) } return n } -// bondall bonds with all given nodes concurrently and returns -// those nodes for which bonding has probably succeeded. -func (tab *Table) bondall(nodes []*Node) (result []*Node) { - rc := make(chan *Node, len(nodes)) - for i := range nodes { - go func(n *Node) { - nn, _ := tab.bond(false, n.ID, n.addr(), n.TCP) - rc <- nn - }(nodes[i]) +// bucket returns the bucket for the given node ID hash. +func (tab *Table) bucket(id enode.ID) *bucket { + d := enode.LogDist(tab.self().ID(), id) + if d <= bucketMinDistance { + return tab.buckets[0] } - for range nodes { - if n := <-rc; n != nil { - result = append(result, n) - } - } - return result + return tab.buckets[d-bucketMinDistance-1] } -// bond ensures the local node has a bond with the given remote node. -// It also attempts to insert the node into the table if bonding succeeds. -// The caller must not hold tab.mutex. -// -// A bond is must be established before sending findnode requests. -// Both sides must have completed a ping/pong exchange for a bond to -// exist. The total number of active bonding processes is limited in -// order to restrain network use. -// -// bond is meant to operate idempotently in that bonding with a remote -// node which still remembers a previously established bond will work. -// The remote node will simply not send a ping back, causing waitping -// to time out. -// -// If pinged is true, the remote node has just pinged us and one half -// of the process can be skipped. -func (tab *Table) bond(pinged bool, id NodeID, addr *net.UDPAddr, tcpPort uint16) (*Node, error) { - if id == tab.self.ID { - return nil, errors.New("is self") - } - // Retrieve a previously known node and any recent findnode failures - node, fails := tab.db.node(id), 0 - if node != nil { - fails = tab.db.findFails(id) - } - // If the node is unknown (non-bonded) or failed (remotely unknown), bond from scratch - var result error - age := time.Since(tab.db.lastPong(id)) - if node == nil || fails > 0 || age > nodeDBNodeExpiration { - log.Trace("Starting bonding ping/pong", "id", id, "known", node != nil, "failcount", fails, "age", age) - - tab.bondmu.Lock() - w := tab.bonding[id] - if w != nil { - // Wait for an existing bonding process to complete. - tab.bondmu.Unlock() - <-w.done - } else { - // Register a new bonding process. - w = &bondproc{done: make(chan struct{})} - tab.bonding[id] = w - tab.bondmu.Unlock() - // Do the ping/pong. The result goes into w. - tab.pingpong(w, pinged, id, addr, tcpPort) - // Unregister the process after it's done. - tab.bondmu.Lock() - delete(tab.bonding, id) - tab.bondmu.Unlock() - } - // Retrieve the bonding results - result = w.err - if result == nil { - node = w.n - } - } - if node != nil { - // Add the node to the table even if the bonding ping/pong - // fails. It will be relaced quickly if it continues to be - // unresponsive. - tab.add(node) - tab.db.updateFindFails(id, 0) - } - return node, result -} - -func (tab *Table) pingpong(w *bondproc, pinged bool, id NodeID, addr *net.UDPAddr, tcpPort uint16) { - // Request a bonding slot to limit network usage - <-tab.bondslots - defer func() { tab.bondslots <- struct{}{} }() - - // Ping the remote side and wait for a pong. - if w.err = tab.ping(id, addr); w.err != nil { - close(w.done) - return - } - if !pinged { - // Give the remote node a chance to ping us before we start - // sending findnode requests. If they still remember us, - // waitping will simply time out. - tab.net.waitping(id) - } - // Bonding succeeded, update the node database. - w.n = NewNode(id, addr.IP, uint16(addr.Port), tcpPort) - tab.db.updateNode(w.n) - close(w.done) -} - -// ping a remote endpoint and wait for a reply, also updating the node -// database accordingly. -func (tab *Table) ping(id NodeID, addr *net.UDPAddr) error { - tab.db.updateLastPing(id, time.Now()) - if err := tab.net.ping(id, addr); err != nil { - return err - } - tab.db.updateLastPong(id, time.Now()) - - // Start the background expiration goroutine after the first - // successful communication. Subsequent calls have no effect if it - // is already running. We do this here instead of somewhere else - // so that the search for seed nodes also considers older nodes - // that would otherwise be removed by the expiration. - tab.db.ensureExpirer() - return nil -} - -// add attempts to add the given node 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(new *Node) { - b := tab.buckets[logdist(tab.self.sha, new.sha)] - tab.mutex.Lock() - defer tab.mutex.Unlock() - if b.bump(new) { +func (tab *Table) addSeenNode(n *node) { + if n.ID() == tab.self().ID() { return } - var oldest *Node - if len(b.entries) == bucketSize { - oldest = b.entries[bucketSize-1] - if oldest.contested { - // The node is already being replaced, don't attempt - // to replace it. - return - } - oldest.contested = true - // Let go of the mutex so other goroutines can access - // the table while we ping the least recently active node. - tab.mutex.Unlock() - err := tab.ping(oldest.ID, oldest.addr()) - tab.mutex.Lock() - oldest.contested = false - if err == nil { - // The node responded, don't replace it. - return - } - } - added := b.replace(new, oldest) - if added && tab.nodeAddedHook != nil { - tab.nodeAddedHook(new) - } -} -// stuff adds nodes the table to the end of their corresponding bucket -// if the bucket is not full. The caller must hold tab.mutex. -func (tab *Table) stuff(nodes []*Node) { -outer: - for _, n := range nodes { - if n.ID == tab.self.ID { - continue // don't add self - } - bucket := tab.buckets[logdist(tab.self.sha, n.sha)] - for i := range bucket.entries { - if bucket.entries[i].ID == n.ID { - continue outer // already in bucket - } - } - if len(bucket.entries) < bucketSize { - bucket.entries = append(bucket.entries, n) - if tab.nodeAddedHook != nil { - tab.nodeAddedHook(n) - } - } - } -} - -// delete removes an entry from the node table (used to evacuate -// failed/non-bonded discovery peers). -func (tab *Table) delete(node *Node) { tab.mutex.Lock() defer tab.mutex.Unlock() - bucket := tab.buckets[logdist(tab.self.sha, node.sha)] - for i := range bucket.entries { - if bucket.entries[i].ID == node.ID { - bucket.entries = append(bucket.entries[:i], bucket.entries[i+1:]...) - return - } + b := tab.bucket(n.ID()) + 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) } } -func (b *bucket) replace(n *Node, last *Node) bool { - // Don't add if b already contains n. - for i := range b.entries { - if b.entries[i].ID == n.ID { - return false - } +// 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) addVerifiedNode(n *node) { + if !tab.isInitDone() { + return } - // Replace last if it is still the last entry or just add n if b - // isn't full. If is no longer the last entry, it has either been - // replaced with someone else or became active. - if len(b.entries) == bucketSize && (last == nil || b.entries[bucketSize-1].ID != last.ID) { + if n.ID() == tab.self().ID() { + return + } + + tab.mutex.Lock() + defer tab.mutex.Unlock() + 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) + } +} + +// delete removes an entry from the node table. It is used to evacuate dead nodes. +func (tab *Table) delete(node *node) { + tab.mutex.Lock() + defer tab.mutex.Unlock() + + tab.deleteInBucket(tab.bucket(node.ID()), node) +} + +func (tab *Table) addIP(b *bucket, ip net.IP) bool { + if netutil.IsLAN(ip) { + return true + } + if !tab.ips.Add(ip) { + log.Debug("IP exceeds table limit", "ip", ip) return false } - if len(b.entries) < bucketSize { - b.entries = append(b.entries, nil) + if !b.ips.Add(ip) { + log.Debug("IP exceeds bucket limit", "ip", ip) + tab.ips.Remove(ip) + return false } - copy(b.entries[1:], b.entries) - b.entries[0] = n return true } -func (b *bucket) bump(n *Node) bool { +func (tab *Table) removeIP(b *bucket, ip net.IP) { + if netutil.IsLAN(ip) { + return + } + tab.ips.Remove(ip) + b.ips.Remove(ip) +} + +func (tab *Table) addReplacement(b *bucket, n *node) { + for _, e := range b.replacements { + if e.ID() == n.ID() { + return // already in list + } + } + if !tab.addIP(b, n.IP()) { + return + } + var removed *node + b.replacements, removed = pushNode(b.replacements, n, maxReplacements) + if removed != nil { + tab.removeIP(b, removed.IP()) + } +} + +// replace removes n from the replacement list and replaces 'last' with it if it is the +// last entry in the bucket. If 'last' isn't the last entry, it has either been replaced +// with someone else or became active. +func (tab *Table) replace(b *bucket, last *node) *node { + if len(b.entries) == 0 || b.entries[len(b.entries)-1].ID() != last.ID() { + // Entry has moved, don't replace it. + return nil + } + // Still the last entry. + if len(b.replacements) == 0 { + tab.deleteInBucket(b, last) + return nil + } + r := b.replacements[tab.rand.Intn(len(b.replacements))] + b.replacements = deleteNode(b.replacements, r) + b.entries[len(b.entries)-1] = r + tab.removeIP(b, last.IP()) + return r +} + +// bumpInBucket moves the given node to the front of the bucket entry list +// if it is contained in that list. +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 b.entries[i].ID() == n.ID() { + 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 @@ -653,17 +719,52 @@ func (b *bucket) bump(n *Node) bool { return false } +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 { + list = append(list, nil) + } + removed := list[len(list)-1] + copy(list[1:], list) + list[0] = n + return list, removed +} + +// deleteNode removes n from list. +func deleteNode(list []*node, n *node) []*node { + for i := range list { + if list[i].ID() == n.ID() { + return append(list[:i], list[i+1:]...) + } + } + return list +} + // nodesByDistance is a list of nodes, ordered by // distance to target. type nodesByDistance struct { - entries []*Node - target common.Hash + entries []*node + target enode.ID } // push adds the given node to the list, keeping the total size below maxElems. -func (h *nodesByDistance) push(n *Node, maxElems int) { +func (h *nodesByDistance) push(n *node, maxElems int) { ix := sort.Search(len(h.entries), func(i int) bool { - return distcmp(h.target, h.entries[i].sha, n.sha) > 0 + return enode.DistCmp(h.target, h.entries[i].ID(), n.ID()) > 0 }) if len(h.entries) < maxElems { h.entries = append(h.entries, n) diff --git a/p2p/discover/table_test.go b/p2p/discover/table_test.go index 1037cc6099..233687d79e 100644 --- a/p2p/discover/table_test.go +++ b/p2p/discover/table_test.go @@ -27,65 +27,69 @@ import ( "testing/quick" "time" - "github.com/ethereum/go-ethereum/common" "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) { - doit := func(newNodeIsResponding, lastInBucketIsResponding bool) { - transport := newPingRecorder() - tab, _ := newTable(transport, NodeID{}, &net.UDPAddr{}, "") - defer tab.Close() - pingSender := NewNode(MustHexID("a502af0f59b2aab7746995408c79e9ca312d2793cc997e44fc55eda62f0150bbb8c59a6f9269ba3a081518b62699ee807c7c19c20125ddfccca872608af9e370"), net.IP{}, 99, 99) - - // fill up the sender's bucket. - last := fillBucket(tab, 253) - - // this call to bond should replace the last node - // in its bucket if the node is not responding. - transport.responding[last.ID] = lastInBucketIsResponding - transport.responding[pingSender.ID] = newNodeIsResponding - tab.bond(true, pingSender.ID, &net.UDPAddr{}, 0) - - // first ping goes to sender (bonding pingback) - if !transport.pinged[pingSender.ID] { - t.Error("table did not ping back sender") - } - if newNodeIsResponding { - // second ping goes to oldest node in bucket - // to see whether it is still alive. - if !transport.pinged[last.ID] { - t.Error("table did not ping last node in bucket") - } - } - - tab.mutex.Lock() - defer tab.mutex.Unlock() - if l := len(tab.buckets[253].entries); l != bucketSize { - t.Errorf("wrong bucket size after bond: got %d, want %d", l, bucketSize) - } - - if lastInBucketIsResponding || !newNodeIsResponding { - if !contains(tab.buckets[253].entries, last.ID) { - t.Error("last entry was removed") - } - if contains(tab.buckets[253].entries, pingSender.ID) { - t.Error("new entry was added") - } - } else { - if contains(tab.buckets[253].entries, last.ID) { - t.Error("last entry was not removed") - } - if !contains(tab.buckets[253].entries, pingSender.ID) { - t.Error("new entry was not added") - } - } + run := func(newNodeResponding, lastInBucketResponding bool) { + name := fmt.Sprintf("newNodeResponding=%t/lastInBucketResponding=%t", newNodeResponding, lastInBucketResponding) + t.Run(name, func(t *testing.T) { + t.Parallel() + testPingReplace(t, newNodeResponding, lastInBucketResponding) + }) } - doit(true, true) - doit(false, true) - doit(true, false) - doit(false, false) + run(true, true) + run(false, true) + run(true, false) + run(false, false) +} + +func testPingReplace(t *testing.T, newNodeIsResponding, lastInBucketIsResponding bool) { + transport := newPingRecorder() + tab, db := newTestTable(transport) + defer db.Close() + defer tab.Close() + + <-tab.initDone + + // Fill up the sender's bucket. + pingKey, _ := crypto.HexToECDSA("45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8") + pingSender := wrapNode(enode.NewV4(&pingKey.PublicKey, net.IP{}, 99, 99)) + last := fillBucket(tab, pingSender) + + // Add the sender as if it just pinged us. Revalidate should replace the last node in + // its bucket if it is unresponsive. Revalidate again to ensure that + transport.dead[last.ID()] = !lastInBucketIsResponding + transport.dead[pingSender.ID()] = !newNodeIsResponding + tab.addSeenNode(pingSender) + tab.doRevalidate(make(chan struct{}, 1)) + tab.doRevalidate(make(chan struct{}, 1)) + + if !transport.pinged[last.ID()] { + // Oldest node in bucket is pinged to see whether it is still alive. + t.Error("table did not ping last node in bucket") + } + + tab.mutex.Lock() + defer tab.mutex.Unlock() + wantSize := bucketSize + if !lastInBucketIsResponding && !newNodeIsResponding { + wantSize-- + } + if l := len(tab.bucket(pingSender.ID()).entries); l != wantSize { + t.Errorf("wrong bucket size after bond: got %d, want %d", l, wantSize) + } + if found := contains(tab.bucket(pingSender.ID()).entries, last.ID()); found != lastInBucketIsResponding { + t.Errorf("last entry found: %t, want: %t", found, lastInBucketIsResponding) + } + wantNewEntry := newNodeIsResponding && !lastInBucketIsResponding + if found := contains(tab.bucket(pingSender.ID()).entries, pingSender.ID()); found != wantNewEntry { + t.Errorf("new entry found: %t, want: %t", found, wantNewEntry) + } } func TestBucket_bumpNoDuplicates(t *testing.T) { @@ -96,9 +100,9 @@ func TestBucket_bumpNoDuplicates(t *testing.T) { Values: func(args []reflect.Value, rand *rand.Rand) { // generate a random list of nodes. this will be the content of the bucket. n := rand.Intn(bucketSize-1) + 1 - nodes := make([]*Node, n) + nodes := make([]*node, n) for i := range nodes { - nodes[i] = nodeAtDistance(common.Hash{}, 200) + nodes[i] = nodeAtDistance(enode.ID{}, 200, intIP(200)) } args[0] = reflect.ValueOf(nodes) // generate random bump positions. @@ -110,11 +114,15 @@ func TestBucket_bumpNoDuplicates(t *testing.T) { }, } - prop := func(nodes []*Node, bumps []int) (ok bool) { - b := &bucket{entries: make([]*Node, len(nodes))} + 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 { @@ -123,6 +131,7 @@ func TestBucket_bumpNoDuplicates(t *testing.T) { return false } } + checkIPLimitInvariant(t, tab) return true } if err := quick.Check(prop, cfg); err != nil { @@ -130,46 +139,54 @@ func TestBucket_bumpNoDuplicates(t *testing.T) { } } -// fillBucket inserts nodes into the given bucket until -// it is full. The node's IDs dont correspond to their -// hashes. -func fillBucket(tab *Table, ld int) (last *Node) { - b := tab.buckets[ld] - for len(b.entries) < bucketSize { - b.entries = append(b.entries, nodeAtDistance(tab.self.sha, ld)) +// This checks that the table-wide IP limit is applied correctly. +func TestTable_IPLimit(t *testing.T) { + transport := newPingRecorder() + tab, db := newTestTable(transport) + 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.addSeenNode(n) } - return b.entries[bucketSize-1] + if tab.len() > tableIPLimit { + t.Errorf("too many nodes in table") + } + checkIPLimitInvariant(t, tab) } -// nodeAtDistance creates a node for which logdist(base, n.sha) == ld. -// The node's ID does not correspond to n.sha. -func nodeAtDistance(base common.Hash, ld int) (n *Node) { - n = new(Node) - n.sha = hashAtDistance(base, ld) - n.IP = net.IP{10, 0, 2, byte(ld)} - copy(n.ID[:], n.sha[:]) // ensure the node still has a unique ID - return n +// This checks that the per-bucket IP limit is applied correctly. +func TestTable_BucketIPLimit(t *testing.T) { + transport := newPingRecorder() + tab, db := newTestTable(transport) + 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.addSeenNode(n) + } + if tab.len() > bucketIPLimit { + t.Errorf("too many nodes in table") + } + checkIPLimitInvariant(t, tab) } -type pingRecorder struct{ responding, pinged map[NodeID]bool } +// 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() -func newPingRecorder() *pingRecorder { - return &pingRecorder{make(map[NodeID]bool), make(map[NodeID]bool)} -} - -func (t *pingRecorder) findnode(toid NodeID, toaddr *net.UDPAddr, target NodeID) ([]*Node, error) { - panic("findnode called on pingRecorder") -} -func (t *pingRecorder) close() {} -func (t *pingRecorder) waitping(from NodeID) error { - return nil // remote always pings -} -func (t *pingRecorder) ping(toid NodeID, toaddr *net.UDPAddr) error { - t.pinged[toid] = true - if t.responding[toid] { - return nil - } else { - return errTimeout + 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) } } @@ -178,11 +195,13 @@ func TestTable_closest(t *testing.T) { test := func(test *closeTest) bool { // for any node table, Target and N - tab, _ := newTable(nil, test.Self, &net.UDPAddr{}, "") + transport := newPingRecorder() + tab, db := newTestTable(transport) + defer db.Close() defer tab.Close() - tab.stuff(test.All) + fillTable(tab, test.All) - // check that doClosest(Target, N) returns nodes + // check that closest(Target, N) returns nodes result := tab.closest(test.Target, test.N).entries if hasDuplicates(result) { t.Errorf("result contains duplicates") @@ -208,15 +227,15 @@ func TestTable_closest(t *testing.T) { // check that the result nodes have minimum distance to target. for _, b := range tab.buckets { for _, n := range b.entries { - if contains(result, n.ID) { + if contains(result, n.ID()) { continue // don't run the check below for nodes in result } - farthestResult := result[len(result)-1].sha - if distcmp(test.Target, n.sha, farthestResult) < 0 { + farthestResult := result[len(result)-1].ID() + if enode.DistCmp(test.Target, n.ID(), farthestResult) < 0 { t.Errorf("table contains node that is closer to target but it's not in result") t.Logf(" Target: %v", test.Target) t.Logf(" Farthest Result: %v", farthestResult) - t.Logf(" ID: %v", n.ID) + t.Logf(" ID: %v", n.ID()) return false } } @@ -233,22 +252,26 @@ func TestTable_ReadRandomNodesGetAll(t *testing.T) { MaxCount: 200, Rand: rand.New(rand.NewSource(time.Now().Unix())), Values: func(args []reflect.Value, rand *rand.Rand) { - args[0] = reflect.ValueOf(make([]*Node, rand.Intn(1000))) + args[0] = reflect.ValueOf(make([]*enode.Node, rand.Intn(1000))) }, } - test := func(buf []*Node) bool { - tab, _ := newTable(nil, NodeID{}, &net.UDPAddr{}, "") + test := func(buf []*enode.Node) bool { + transport := newPingRecorder() + tab, db := newTestTable(transport) + 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.sha, ld)}) + fillTable(tab, []*node{nodeAtDistance(tab.self().ID(), ld, intIP(ld))}) } gotN := tab.ReadRandomNodes(buf) if gotN != tab.len() { t.Errorf("wrong number of nodes, got %d, want %d", gotN, tab.len()) return false } - if hasDuplicates(buf[:gotN]) { + if hasDuplicates(wrapNodes(buf[:gotN])) { t.Errorf("result contains duplicates") return false } @@ -260,41 +283,110 @@ func TestTable_ReadRandomNodesGetAll(t *testing.T) { } type closeTest struct { - Self NodeID - Target common.Hash - All []*Node + Self enode.ID + Target enode.ID + All []*node N int } func (*closeTest) Generate(rand *rand.Rand, size int) reflect.Value { t := &closeTest{ - Self: gen(NodeID{}, rand).(NodeID), - Target: gen(common.Hash{}, rand).(common.Hash), + Self: gen(enode.ID{}, rand).(enode.ID), + Target: gen(enode.ID{}, rand).(enode.ID), N: rand.Intn(bucketSize), } - for _, id := range gen([]NodeID{}, rand).([]NodeID) { - t.All = append(t.All, &Node{ID: id}) + for _, id := range gen([]enode.ID{}, rand).([]enode.ID) { + 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) { - self := nodeAtDistance(common.Hash{}, 0) - tab, _ := newTable(lookupTestnet, self.ID, &net.UDPAddr{}, "") + tab, db := newTestTable(lookupTestnet) + defer db.Close() defer tab.Close() // lookup on empty table returns no nodes - if results := tab.Lookup(lookupTestnet.target); len(results) > 0 { + if results := tab.lookup(lookupTestnet.target, false); len(results) > 0 { t.Fatalf("lookup on empty table returned %d results: %#v", len(results), results) } // seed table with initial node (otherwise lookup will terminate immediately) - seed := NewNode(lookupTestnet.dists[256][0], net.IP{}, 256, 0) - tab.stuff([]*Node{seed}) + seedKey, _ := decodePubkey(lookupTestnet.dists[256][0]) + 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) + results := tab.lookup(lookupTestnet.target, true) t.Logf("results:") for _, e := range results { - t.Logf(" ld=%d, %x", logdist(lookupTestnet.targetSha, e.sha), e.sha[:]) + t.Logf(" ld=%d, %x", enode.LogDist(lookupTestnet.targetSha, e.ID()), e.ID().Bytes()) } if len(results) != bucketSize { t.Errorf("wrong number of results: got %d, want %d", len(results), bucketSize) @@ -311,250 +403,256 @@ func TestTable_Lookup(t *testing.T) { // This is the test network for the Lookup test. // The nodes were obtained by running testnet.mine with a random NodeID as target. var lookupTestnet = &preminedTestnet{ - target: MustHexID("166aea4f556532c6d34e8b740e5d314af7e9ac0ca79833bd751d6b665f12dfd38ec563c363b32f02aef4a80b44fd3def94612d497b99cb5f17fd24de454927ec"), - targetSha: common.Hash{0x5c, 0x94, 0x4e, 0xe5, 0x1c, 0x5a, 0xe9, 0xf7, 0x2a, 0x95, 0xec, 0xcb, 0x8a, 0xed, 0x3, 0x74, 0xee, 0xcb, 0x51, 0x19, 0xd7, 0x20, 0xcb, 0xea, 0x68, 0x13, 0xe8, 0xe0, 0xd6, 0xad, 0x92, 0x61}, - dists: [257][]NodeID{ + target: hexEncPubkey("166aea4f556532c6d34e8b740e5d314af7e9ac0ca79833bd751d6b665f12dfd38ec563c363b32f02aef4a80b44fd3def94612d497b99cb5f17fd24de454927ec"), + targetSha: enode.HexID("5c944ee51c5ae9f72a95eccb8aed0374eecb5119d720cbea6813e8e0d6ad9261"), + dists: [257][]encPubkey{ 240: { - MustHexID("2001ad5e3e80c71b952161bc0186731cf5ffe942d24a79230a0555802296238e57ea7a32f5b6f18564eadc1c65389448481f8c9338df0a3dbd18f708cbc2cbcb"), - MustHexID("6ba3f4f57d084b6bf94cc4555b8c657e4a8ac7b7baf23c6874efc21dd1e4f56b7eb2721e07f5242d2f1d8381fc8cae535e860197c69236798ba1ad231b105794"), + hexEncPubkey("2001ad5e3e80c71b952161bc0186731cf5ffe942d24a79230a0555802296238e57ea7a32f5b6f18564eadc1c65389448481f8c9338df0a3dbd18f708cbc2cbcb"), + hexEncPubkey("6ba3f4f57d084b6bf94cc4555b8c657e4a8ac7b7baf23c6874efc21dd1e4f56b7eb2721e07f5242d2f1d8381fc8cae535e860197c69236798ba1ad231b105794"), }, 244: { - MustHexID("696ba1f0a9d55c59246f776600542a9e6432490f0cd78f8bb55a196918df2081a9b521c3c3ba48e465a75c10768807717f8f689b0b4adce00e1c75737552a178"), + hexEncPubkey("696ba1f0a9d55c59246f776600542a9e6432490f0cd78f8bb55a196918df2081a9b521c3c3ba48e465a75c10768807717f8f689b0b4adce00e1c75737552a178"), }, 246: { - MustHexID("d6d32178bdc38416f46ffb8b3ec9e4cb2cfff8d04dd7e4311a70e403cb62b10be1b447311b60b4f9ee221a8131fc2cbd45b96dd80deba68a949d467241facfa8"), - MustHexID("3ea3d04a43a3dfb5ac11cffc2319248cf41b6279659393c2f55b8a0a5fc9d12581a9d97ef5d8ff9b5abf3321a290e8f63a4f785f450dc8a672aba3ba2ff4fdab"), - MustHexID("2fc897f05ae585553e5c014effd3078f84f37f9333afacffb109f00ca8e7a3373de810a3946be971cbccdfd40249f9fe7f322118ea459ac71acca85a1ef8b7f4"), + hexEncPubkey("d6d32178bdc38416f46ffb8b3ec9e4cb2cfff8d04dd7e4311a70e403cb62b10be1b447311b60b4f9ee221a8131fc2cbd45b96dd80deba68a949d467241facfa8"), + hexEncPubkey("3ea3d04a43a3dfb5ac11cffc2319248cf41b6279659393c2f55b8a0a5fc9d12581a9d97ef5d8ff9b5abf3321a290e8f63a4f785f450dc8a672aba3ba2ff4fdab"), + hexEncPubkey("2fc897f05ae585553e5c014effd3078f84f37f9333afacffb109f00ca8e7a3373de810a3946be971cbccdfd40249f9fe7f322118ea459ac71acca85a1ef8b7f4"), }, 247: { - MustHexID("3155e1427f85f10a5c9a7755877748041af1bcd8d474ec065eb33df57a97babf54bfd2103575fa829115d224c523596b401065a97f74010610fce76382c0bf32"), - MustHexID("312c55512422cf9b8a4097e9a6ad79402e87a15ae909a4bfefa22398f03d20951933beea1e4dfa6f968212385e829f04c2d314fc2d4e255e0d3bc08792b069db"), - MustHexID("38643200b172dcfef857492156971f0e6aa2c538d8b74010f8e140811d53b98c765dd2d96126051913f44582e8c199ad7c6d6819e9a56483f637feaac9448aac"), - MustHexID("8dcab8618c3253b558d459da53bd8fa68935a719aff8b811197101a4b2b47dd2d47295286fc00cc081bb542d760717d1bdd6bec2c37cd72eca367d6dd3b9df73"), - MustHexID("8b58c6073dd98bbad4e310b97186c8f822d3a5c7d57af40e2136e88e315afd115edb27d2d0685a908cfe5aa49d0debdda6e6e63972691d6bd8c5af2d771dd2a9"), - MustHexID("2cbb718b7dc682da19652e7d9eb4fefaf7b7147d82c1c2b6805edf77b85e29fde9f6da195741467ff2638dc62c8d3e014ea5686693c15ed0080b6de90354c137"), - MustHexID("e84027696d3f12f2de30a9311afea8fbd313c2360daff52bb5fc8c7094d5295758bec3134e4eef24e4cdf377b40da344993284628a7a346eba94f74160998feb"), - MustHexID("f1357a4f04f9d33753a57c0b65ba20a5d8777abbffd04e906014491c9103fb08590e45548d37aa4bd70965e2e81ddba94f31860348df01469eec8c1829200a68"), - MustHexID("4ab0a75941b12892369b4490a1928c8ca52a9ad6d3dffbd1d8c0b907bc200fe74c022d011ec39b64808a39c0ca41f1d3254386c3e7733e7044c44259486461b6"), - MustHexID("d45150a72dc74388773e68e03133a3b5f51447fe91837d566706b3c035ee4b56f160c878c6273394daee7f56cc398985269052f22f75a8057df2fe6172765354"), + hexEncPubkey("3155e1427f85f10a5c9a7755877748041af1bcd8d474ec065eb33df57a97babf54bfd2103575fa829115d224c523596b401065a97f74010610fce76382c0bf32"), + hexEncPubkey("312c55512422cf9b8a4097e9a6ad79402e87a15ae909a4bfefa22398f03d20951933beea1e4dfa6f968212385e829f04c2d314fc2d4e255e0d3bc08792b069db"), + hexEncPubkey("38643200b172dcfef857492156971f0e6aa2c538d8b74010f8e140811d53b98c765dd2d96126051913f44582e8c199ad7c6d6819e9a56483f637feaac9448aac"), + hexEncPubkey("8dcab8618c3253b558d459da53bd8fa68935a719aff8b811197101a4b2b47dd2d47295286fc00cc081bb542d760717d1bdd6bec2c37cd72eca367d6dd3b9df73"), + hexEncPubkey("8b58c6073dd98bbad4e310b97186c8f822d3a5c7d57af40e2136e88e315afd115edb27d2d0685a908cfe5aa49d0debdda6e6e63972691d6bd8c5af2d771dd2a9"), + hexEncPubkey("2cbb718b7dc682da19652e7d9eb4fefaf7b7147d82c1c2b6805edf77b85e29fde9f6da195741467ff2638dc62c8d3e014ea5686693c15ed0080b6de90354c137"), + hexEncPubkey("e84027696d3f12f2de30a9311afea8fbd313c2360daff52bb5fc8c7094d5295758bec3134e4eef24e4cdf377b40da344993284628a7a346eba94f74160998feb"), + hexEncPubkey("f1357a4f04f9d33753a57c0b65ba20a5d8777abbffd04e906014491c9103fb08590e45548d37aa4bd70965e2e81ddba94f31860348df01469eec8c1829200a68"), + hexEncPubkey("4ab0a75941b12892369b4490a1928c8ca52a9ad6d3dffbd1d8c0b907bc200fe74c022d011ec39b64808a39c0ca41f1d3254386c3e7733e7044c44259486461b6"), + hexEncPubkey("d45150a72dc74388773e68e03133a3b5f51447fe91837d566706b3c035ee4b56f160c878c6273394daee7f56cc398985269052f22f75a8057df2fe6172765354"), }, 248: { - MustHexID("6aadfce366a189bab08ac84721567483202c86590642ea6d6a14f37ca78d82bdb6509eb7b8b2f6f63c78ae3ae1d8837c89509e41497d719b23ad53dd81574afa"), - MustHexID("a605ecfd6069a4cf4cf7f5840e5bc0ce10d23a3ac59e2aaa70c6afd5637359d2519b4524f56fc2ca180cdbebe54262f720ccaae8c1b28fd553c485675831624d"), - MustHexID("29701451cb9448ca33fc33680b44b840d815be90146eb521641efbffed0859c154e8892d3906eae9934bfacee72cd1d2fa9dd050fd18888eea49da155ab0efd2"), - MustHexID("3ed426322dee7572b08592e1e079f8b6c6b30e10e6243edd144a6a48fdbdb83df73a6e41b1143722cb82604f2203a32758610b5d9544f44a1a7921ba001528c1"), - MustHexID("b2e2a2b7fdd363572a3256e75435fab1da3b16f7891a8bd2015f30995dae665d7eabfd194d87d99d5df628b4bbc7b04e5b492c596422dd8272746c7a1b0b8e4f"), - MustHexID("0c69c9756162c593e85615b814ce57a2a8ca2df6c690b9c4e4602731b61e1531a3bbe3f7114271554427ffabea80ad8f36fa95a49fa77b675ae182c6ccac1728"), - MustHexID("8d28be21d5a97b0876442fa4f5e5387f5bf3faad0b6f13b8607b64d6e448c0991ca28dd7fe2f64eb8eadd7150bff5d5666aa6ed868b84c71311f4ba9a38569dd"), - MustHexID("2c677e1c64b9c9df6359348a7f5f33dc79e22f0177042486d125f8b6ca7f0dc756b1f672aceee5f1746bcff80aaf6f92a8dc0c9fbeb259b3fa0da060de5ab7e8"), - MustHexID("3994880f94a8678f0cd247a43f474a8af375d2a072128da1ad6cae84a244105ff85e94fc7d8496f639468de7ee998908a91c7e33ef7585fff92e984b210941a1"), - MustHexID("b45a9153c08d002a48090d15d61a7c7dad8c2af85d4ff5bd36ce23a9a11e0709bf8d56614c7b193bc028c16cbf7f20dfbcc751328b64a924995d47b41e452422"), - MustHexID("057ab3a9e53c7a84b0f3fc586117a525cdd18e313f52a67bf31798d48078e325abe5cfee3f6c2533230cb37d0549289d692a29dd400e899b8552d4b928f6f907"), - MustHexID("0ddf663d308791eb92e6bd88a2f8cb45e4f4f35bb16708a0e6ff7f1362aa6a73fedd0a1b1557fb3365e38e1b79d6918e2fae2788728b70c9ab6b51a3b94a4338"), - MustHexID("f637e07ff50cc1e3731735841c4798411059f2023abcf3885674f3e8032531b0edca50fd715df6feb489b6177c345374d64f4b07d257a7745de393a107b013a5"), - MustHexID("e24ec7c6eec094f63c7b3239f56d311ec5a3e45bc4e622a1095a65b95eea6fe13e29f3b6b7a2cbfe40906e3989f17ac834c3102dd0cadaaa26e16ee06d782b72"), - MustHexID("b76ea1a6fd6506ef6e3506a4f1f60ed6287fff8114af6141b2ff13e61242331b54082b023cfea5b3083354a4fb3f9eb8be01fb4a518f579e731a5d0707291a6b"), - MustHexID("9b53a37950ca8890ee349b325032d7b672cab7eced178d3060137b24ef6b92a43977922d5bdfb4a3409a2d80128e02f795f9dae6d7d99973ad0e23a2afb8442f"), + hexEncPubkey("6aadfce366a189bab08ac84721567483202c86590642ea6d6a14f37ca78d82bdb6509eb7b8b2f6f63c78ae3ae1d8837c89509e41497d719b23ad53dd81574afa"), + hexEncPubkey("a605ecfd6069a4cf4cf7f5840e5bc0ce10d23a3ac59e2aaa70c6afd5637359d2519b4524f56fc2ca180cdbebe54262f720ccaae8c1b28fd553c485675831624d"), + hexEncPubkey("29701451cb9448ca33fc33680b44b840d815be90146eb521641efbffed0859c154e8892d3906eae9934bfacee72cd1d2fa9dd050fd18888eea49da155ab0efd2"), + hexEncPubkey("3ed426322dee7572b08592e1e079f8b6c6b30e10e6243edd144a6a48fdbdb83df73a6e41b1143722cb82604f2203a32758610b5d9544f44a1a7921ba001528c1"), + hexEncPubkey("b2e2a2b7fdd363572a3256e75435fab1da3b16f7891a8bd2015f30995dae665d7eabfd194d87d99d5df628b4bbc7b04e5b492c596422dd8272746c7a1b0b8e4f"), + hexEncPubkey("0c69c9756162c593e85615b814ce57a2a8ca2df6c690b9c4e4602731b61e1531a3bbe3f7114271554427ffabea80ad8f36fa95a49fa77b675ae182c6ccac1728"), + hexEncPubkey("8d28be21d5a97b0876442fa4f5e5387f5bf3faad0b6f13b8607b64d6e448c0991ca28dd7fe2f64eb8eadd7150bff5d5666aa6ed868b84c71311f4ba9a38569dd"), + hexEncPubkey("2c677e1c64b9c9df6359348a7f5f33dc79e22f0177042486d125f8b6ca7f0dc756b1f672aceee5f1746bcff80aaf6f92a8dc0c9fbeb259b3fa0da060de5ab7e8"), + hexEncPubkey("3994880f94a8678f0cd247a43f474a8af375d2a072128da1ad6cae84a244105ff85e94fc7d8496f639468de7ee998908a91c7e33ef7585fff92e984b210941a1"), + hexEncPubkey("b45a9153c08d002a48090d15d61a7c7dad8c2af85d4ff5bd36ce23a9a11e0709bf8d56614c7b193bc028c16cbf7f20dfbcc751328b64a924995d47b41e452422"), + hexEncPubkey("057ab3a9e53c7a84b0f3fc586117a525cdd18e313f52a67bf31798d48078e325abe5cfee3f6c2533230cb37d0549289d692a29dd400e899b8552d4b928f6f907"), + hexEncPubkey("0ddf663d308791eb92e6bd88a2f8cb45e4f4f35bb16708a0e6ff7f1362aa6a73fedd0a1b1557fb3365e38e1b79d6918e2fae2788728b70c9ab6b51a3b94a4338"), + hexEncPubkey("f637e07ff50cc1e3731735841c4798411059f2023abcf3885674f3e8032531b0edca50fd715df6feb489b6177c345374d64f4b07d257a7745de393a107b013a5"), + hexEncPubkey("e24ec7c6eec094f63c7b3239f56d311ec5a3e45bc4e622a1095a65b95eea6fe13e29f3b6b7a2cbfe40906e3989f17ac834c3102dd0cadaaa26e16ee06d782b72"), + hexEncPubkey("b76ea1a6fd6506ef6e3506a4f1f60ed6287fff8114af6141b2ff13e61242331b54082b023cfea5b3083354a4fb3f9eb8be01fb4a518f579e731a5d0707291a6b"), + hexEncPubkey("9b53a37950ca8890ee349b325032d7b672cab7eced178d3060137b24ef6b92a43977922d5bdfb4a3409a2d80128e02f795f9dae6d7d99973ad0e23a2afb8442f"), }, 249: { - MustHexID("675ae65567c3c72c50c73bc0fd4f61f202ea5f93346ca57b551de3411ccc614fad61cb9035493af47615311b9d44ee7a161972ee4d77c28fe1ec029d01434e6a"), - MustHexID("8eb81408389da88536ae5800392b16ef5109d7ea132c18e9a82928047ecdb502693f6e4a4cdd18b54296caf561db937185731456c456c98bfe7de0baf0eaa495"), - MustHexID("2adba8b1612a541771cb93a726a38a4b88e97b18eced2593eb7daf82f05a5321ca94a72cc780c306ff21e551a932fc2c6d791e4681907b5ceab7f084c3fa2944"), - MustHexID("b1b4bfbda514d9b8f35b1c28961da5d5216fe50548f4066f69af3b7666a3b2e06eac646735e963e5c8f8138a2fb95af15b13b23ff00c6986eccc0efaa8ee6fb4"), - MustHexID("d2139281b289ad0e4d7b4243c4364f5c51aac8b60f4806135de06b12b5b369c9e43a6eb494eab860d115c15c6fbb8c5a1b0e382972e0e460af395b8385363de7"), - MustHexID("4a693df4b8fc5bdc7cec342c3ed2e228d7c5b4ab7321ddaa6cccbeb45b05a9f1d95766b4002e6d4791c2deacb8a667aadea6a700da28a3eea810a30395701bbc"), - MustHexID("ab41611195ec3c62bb8cd762ee19fb182d194fd141f4a66780efbef4b07ce916246c022b841237a3a6b512a93431157edd221e854ed2a259b72e9c5351f44d0c"), - MustHexID("68e8e26099030d10c3c703ae7045c0a48061fb88058d853b3e67880014c449d4311014da99d617d3150a20f1a3da5e34bf0f14f1c51fe4dd9d58afd222823176"), - MustHexID("3fbcacf546fb129cd70fc48de3b593ba99d3c473798bc309292aca280320e0eacc04442c914cad5c4cf6950345ba79b0d51302df88285d4e83ee3fe41339eee7"), - MustHexID("1d4a623659f7c8f80b6c3939596afdf42e78f892f682c768ad36eb7bfba402dbf97aea3a268f3badd8fe7636be216edf3d67ee1e08789ebbc7be625056bd7109"), - MustHexID("a283c474ab09da02bbc96b16317241d0627646fcc427d1fe790b76a7bf1989ced90f92101a973047ae9940c92720dffbac8eff21df8cae468a50f72f9e159417"), - MustHexID("dbf7e5ad7f87c3dfecae65d87c3039e14ed0bdc56caf00ce81931073e2e16719d746295512ff7937a15c3b03603e7c41a4f9df94fcd37bb200dd8f332767e9cb"), - MustHexID("caaa070a26692f64fc77f30d7b5ae980d419b4393a0f442b1c821ef58c0862898b0d22f74a4f8c5d83069493e3ec0b92f17dc1fe6e4cd437c1ec25039e7ce839"), - MustHexID("874cc8d1213beb65c4e0e1de38ef5d8165235893ac74ab5ea937c885eaab25c8d79dad0456e9fd3e9450626cac7e107b004478fb59842f067857f39a47cee695"), - MustHexID("d94193f236105010972f5df1b7818b55846592a0445b9cdc4eaed811b8c4c0f7c27dc8cc9837a4774656d6b34682d6d329d42b6ebb55da1d475c2474dc3dfdf4"), - MustHexID("edd9af6aded4094e9785637c28fccbd3980cbe28e2eb9a411048a23c2ace4bd6b0b7088a7817997b49a3dd05fc6929ca6c7abbb69438dbdabe65e971d2a794b2"), + hexEncPubkey("675ae65567c3c72c50c73bc0fd4f61f202ea5f93346ca57b551de3411ccc614fad61cb9035493af47615311b9d44ee7a161972ee4d77c28fe1ec029d01434e6a"), + hexEncPubkey("8eb81408389da88536ae5800392b16ef5109d7ea132c18e9a82928047ecdb502693f6e4a4cdd18b54296caf561db937185731456c456c98bfe7de0baf0eaa495"), + hexEncPubkey("2adba8b1612a541771cb93a726a38a4b88e97b18eced2593eb7daf82f05a5321ca94a72cc780c306ff21e551a932fc2c6d791e4681907b5ceab7f084c3fa2944"), + hexEncPubkey("b1b4bfbda514d9b8f35b1c28961da5d5216fe50548f4066f69af3b7666a3b2e06eac646735e963e5c8f8138a2fb95af15b13b23ff00c6986eccc0efaa8ee6fb4"), + hexEncPubkey("d2139281b289ad0e4d7b4243c4364f5c51aac8b60f4806135de06b12b5b369c9e43a6eb494eab860d115c15c6fbb8c5a1b0e382972e0e460af395b8385363de7"), + hexEncPubkey("4a693df4b8fc5bdc7cec342c3ed2e228d7c5b4ab7321ddaa6cccbeb45b05a9f1d95766b4002e6d4791c2deacb8a667aadea6a700da28a3eea810a30395701bbc"), + hexEncPubkey("ab41611195ec3c62bb8cd762ee19fb182d194fd141f4a66780efbef4b07ce916246c022b841237a3a6b512a93431157edd221e854ed2a259b72e9c5351f44d0c"), + hexEncPubkey("68e8e26099030d10c3c703ae7045c0a48061fb88058d853b3e67880014c449d4311014da99d617d3150a20f1a3da5e34bf0f14f1c51fe4dd9d58afd222823176"), + hexEncPubkey("3fbcacf546fb129cd70fc48de3b593ba99d3c473798bc309292aca280320e0eacc04442c914cad5c4cf6950345ba79b0d51302df88285d4e83ee3fe41339eee7"), + hexEncPubkey("1d4a623659f7c8f80b6c3939596afdf42e78f892f682c768ad36eb7bfba402dbf97aea3a268f3badd8fe7636be216edf3d67ee1e08789ebbc7be625056bd7109"), + hexEncPubkey("a283c474ab09da02bbc96b16317241d0627646fcc427d1fe790b76a7bf1989ced90f92101a973047ae9940c92720dffbac8eff21df8cae468a50f72f9e159417"), + hexEncPubkey("dbf7e5ad7f87c3dfecae65d87c3039e14ed0bdc56caf00ce81931073e2e16719d746295512ff7937a15c3b03603e7c41a4f9df94fcd37bb200dd8f332767e9cb"), + hexEncPubkey("caaa070a26692f64fc77f30d7b5ae980d419b4393a0f442b1c821ef58c0862898b0d22f74a4f8c5d83069493e3ec0b92f17dc1fe6e4cd437c1ec25039e7ce839"), + hexEncPubkey("874cc8d1213beb65c4e0e1de38ef5d8165235893ac74ab5ea937c885eaab25c8d79dad0456e9fd3e9450626cac7e107b004478fb59842f067857f39a47cee695"), + hexEncPubkey("d94193f236105010972f5df1b7818b55846592a0445b9cdc4eaed811b8c4c0f7c27dc8cc9837a4774656d6b34682d6d329d42b6ebb55da1d475c2474dc3dfdf4"), + hexEncPubkey("edd9af6aded4094e9785637c28fccbd3980cbe28e2eb9a411048a23c2ace4bd6b0b7088a7817997b49a3dd05fc6929ca6c7abbb69438dbdabe65e971d2a794b2"), }, 250: { - MustHexID("53a5bd1215d4ab709ae8fdc2ced50bba320bced78bd9c5dc92947fb402250c914891786db0978c898c058493f86fc68b1c5de8a5cb36336150ac7a88655b6c39"), - MustHexID("b7f79e3ab59f79262623c9ccefc8f01d682323aee56ffbe295437487e9d5acaf556a9c92e1f1c6a9601f2b9eb6b027ae1aeaebac71d61b9b78e88676efd3e1a3"), - MustHexID("d374bf7e8d7ffff69cc00bebff38ef5bc1dcb0a8d51c1a3d70e61ac6b2e2d6617109254b0ac224354dfbf79009fe4239e09020c483cc60c071e00b9238684f30"), - MustHexID("1e1eac1c9add703eb252eb991594f8f5a173255d526a855fab24ae57dc277e055bc3c7a7ae0b45d437c4f47a72d97eb7b126f2ba344ba6c0e14b2c6f27d4b1e6"), - MustHexID("ae28953f63d4bc4e706712a59319c111f5ff8f312584f65d7436b4cd3d14b217b958f8486bad666b4481fe879019fb1f767cf15b3e3e2711efc33b56d460448a"), - MustHexID("934bb1edf9c7a318b82306aca67feb3d6b434421fa275d694f0b4927afd8b1d3935b727fd4ff6e3d012e0c82f1824385174e8c6450ade59c2a43281a4b3446b6"), - MustHexID("9eef3f28f70ce19637519a0916555bf76d26de31312ac656cf9d3e379899ea44e4dd7ffcce923b4f3563f8a00489a34bd6936db0cbb4c959d32c49f017e07d05"), - MustHexID("82200872e8f871c48f1fad13daec6478298099b591bb3dbc4ef6890aa28ebee5860d07d70be62f4c0af85085a90ae8179ee8f937cf37915c67ea73e704b03ee7"), - MustHexID("6c75a5834a08476b7fc37ff3dc2011dc3ea3b36524bad7a6d319b18878fad813c0ba76d1f4555cacd3890c865438c21f0e0aed1f80e0a157e642124c69f43a11"), - MustHexID("995b873742206cb02b736e73a88580c2aacb0bd4a3c97a647b647bcab3f5e03c0e0736520a8b3600da09edf4248991fb01091ec7ff3ec7cdc8a1beae011e7aae"), - MustHexID("c773a056594b5cdef2e850d30891ff0e927c3b1b9c35cd8e8d53a1017001e237468e1ece3ae33d612ca3e6abb0a9169aa352e9dcda358e5af2ad982b577447db"), - MustHexID("2b46a5f6923f475c6be99ec6d134437a6d11f6bb4b4ac6bcd94572fa1092639d1c08aeefcb51f0912f0a060f71d4f38ee4da70ecc16010b05dd4a674aab14c3a"), - MustHexID("af6ab501366debbaa0d22e20e9688f32ef6b3b644440580fd78de4fe0e99e2a16eb5636bbae0d1c259df8ddda77b35b9a35cbc36137473e9c68fbc9d203ba842"), - MustHexID("c9f6f2dd1a941926f03f770695bda289859e85fabaf94baaae20b93e5015dc014ba41150176a36a1884adb52f405194693e63b0c464a6891cc9cc1c80d450326"), - MustHexID("5b116f0751526868a909b61a30b0c5282c37df6925cc03ddea556ef0d0602a9595fd6c14d371f8ed7d45d89918a032dcd22be4342a8793d88fdbeb3ca3d75bd7"), - MustHexID("50f3222fb6b82481c7c813b2172e1daea43e2710a443b9c2a57a12bd160dd37e20f87aa968c82ad639af6972185609d47036c0d93b4b7269b74ebd7073221c10"), + hexEncPubkey("53a5bd1215d4ab709ae8fdc2ced50bba320bced78bd9c5dc92947fb402250c914891786db0978c898c058493f86fc68b1c5de8a5cb36336150ac7a88655b6c39"), + hexEncPubkey("b7f79e3ab59f79262623c9ccefc8f01d682323aee56ffbe295437487e9d5acaf556a9c92e1f1c6a9601f2b9eb6b027ae1aeaebac71d61b9b78e88676efd3e1a3"), + hexEncPubkey("d374bf7e8d7ffff69cc00bebff38ef5bc1dcb0a8d51c1a3d70e61ac6b2e2d6617109254b0ac224354dfbf79009fe4239e09020c483cc60c071e00b9238684f30"), + hexEncPubkey("1e1eac1c9add703eb252eb991594f8f5a173255d526a855fab24ae57dc277e055bc3c7a7ae0b45d437c4f47a72d97eb7b126f2ba344ba6c0e14b2c6f27d4b1e6"), + hexEncPubkey("ae28953f63d4bc4e706712a59319c111f5ff8f312584f65d7436b4cd3d14b217b958f8486bad666b4481fe879019fb1f767cf15b3e3e2711efc33b56d460448a"), + hexEncPubkey("934bb1edf9c7a318b82306aca67feb3d6b434421fa275d694f0b4927afd8b1d3935b727fd4ff6e3d012e0c82f1824385174e8c6450ade59c2a43281a4b3446b6"), + hexEncPubkey("9eef3f28f70ce19637519a0916555bf76d26de31312ac656cf9d3e379899ea44e4dd7ffcce923b4f3563f8a00489a34bd6936db0cbb4c959d32c49f017e07d05"), + hexEncPubkey("82200872e8f871c48f1fad13daec6478298099b591bb3dbc4ef6890aa28ebee5860d07d70be62f4c0af85085a90ae8179ee8f937cf37915c67ea73e704b03ee7"), + hexEncPubkey("6c75a5834a08476b7fc37ff3dc2011dc3ea3b36524bad7a6d319b18878fad813c0ba76d1f4555cacd3890c865438c21f0e0aed1f80e0a157e642124c69f43a11"), + hexEncPubkey("995b873742206cb02b736e73a88580c2aacb0bd4a3c97a647b647bcab3f5e03c0e0736520a8b3600da09edf4248991fb01091ec7ff3ec7cdc8a1beae011e7aae"), + hexEncPubkey("c773a056594b5cdef2e850d30891ff0e927c3b1b9c35cd8e8d53a1017001e237468e1ece3ae33d612ca3e6abb0a9169aa352e9dcda358e5af2ad982b577447db"), + hexEncPubkey("2b46a5f6923f475c6be99ec6d134437a6d11f6bb4b4ac6bcd94572fa1092639d1c08aeefcb51f0912f0a060f71d4f38ee4da70ecc16010b05dd4a674aab14c3a"), + hexEncPubkey("af6ab501366debbaa0d22e20e9688f32ef6b3b644440580fd78de4fe0e99e2a16eb5636bbae0d1c259df8ddda77b35b9a35cbc36137473e9c68fbc9d203ba842"), + hexEncPubkey("c9f6f2dd1a941926f03f770695bda289859e85fabaf94baaae20b93e5015dc014ba41150176a36a1884adb52f405194693e63b0c464a6891cc9cc1c80d450326"), + hexEncPubkey("5b116f0751526868a909b61a30b0c5282c37df6925cc03ddea556ef0d0602a9595fd6c14d371f8ed7d45d89918a032dcd22be4342a8793d88fdbeb3ca3d75bd7"), + hexEncPubkey("50f3222fb6b82481c7c813b2172e1daea43e2710a443b9c2a57a12bd160dd37e20f87aa968c82ad639af6972185609d47036c0d93b4b7269b74ebd7073221c10"), }, 251: { - MustHexID("9b8f702a62d1bee67bedfeb102eca7f37fa1713e310f0d6651cc0c33ea7c5477575289ccd463e5a2574a00a676a1fdce05658ba447bb9d2827f0ba47b947e894"), - MustHexID("b97532eb83054ed054b4abdf413bb30c00e4205545c93521554dbe77faa3cfaa5bd31ef466a107b0b34a71ec97214c0c83919720142cddac93aa7a3e928d4708"), - MustHexID("2f7a5e952bfb67f2f90b8441b5fadc9ee13b1dcde3afeeb3dd64bf937f86663cc5c55d1fa83952b5422763c7df1b7f2794b751c6be316ebc0beb4942e65ab8c1"), - MustHexID("42c7483781727051a0b3660f14faf39e0d33de5e643702ae933837d036508ab856ce7eec8ec89c4929a4901256e5233a3d847d5d4893f91bcf21835a9a880fee"), - MustHexID("873bae27bf1dc854408fba94046a53ab0c965cebe1e4e12290806fc62b88deb1f4a47f9e18f78fc0e7913a0c6e42ac4d0fc3a20cea6bc65f0c8a0ca90b67521e"), - MustHexID("a7e3a370bbd761d413f8d209e85886f68bf73d5c3089b2dc6fa42aab1ecb5162635497eed95dee2417f3c9c74a3e76319625c48ead2e963c7de877cd4551f347"), - MustHexID("528597534776a40df2addaaea15b6ff832ce36b9748a265768368f657e76d58569d9f30dbb91e91cf0ae7efe8f402f17aa0ae15f5c55051ba03ba830287f4c42"), - MustHexID("461d8bd4f13c3c09031fdb84f104ed737a52f630261463ce0bdb5704259bab4b737dda688285b8444dbecaecad7f50f835190b38684ced5e90c54219e5adf1bc"), - MustHexID("6ec50c0be3fd232737090fc0111caaf0bb6b18f72be453428087a11a97fd6b52db0344acbf789a689bd4f5f50f79017ea784f8fd6fe723ad6ae675b9e3b13e21"), - MustHexID("12fc5e2f77a83fdcc727b79d8ae7fe6a516881138d3011847ee136b400fed7cfba1f53fd7a9730253c7aa4f39abeacd04f138417ba7fcb0f36cccc3514e0dab6"), - MustHexID("4fdbe75914ccd0bce02101606a1ccf3657ec963e3b3c20239d5fec87673fe446d649b4f15f1fe1a40e6cfbd446dda2d31d40bb602b1093b8fcd5f139ba0eb46a"), - MustHexID("3753668a0f6281e425ea69b52cb2d17ab97afbe6eb84cf5d25425bc5e53009388857640668fadd7c110721e6047c9697803bd8a6487b43bb343bfa32ebf24039"), - MustHexID("2e81b16346637dec4410fd88e527346145b9c0a849dbf2628049ac7dae016c8f4305649d5659ec77f1e8a0fac0db457b6080547226f06283598e3740ad94849a"), - MustHexID("802c3cc27f91c89213223d758f8d2ecd41135b357b6d698f24d811cdf113033a81c38e0bdff574a5c005b00a8c193dc2531f8c1fa05fa60acf0ab6f2858af09f"), - MustHexID("fcc9a2e1ac3667026ff16192876d1813bb75abdbf39b929a92863012fe8b1d890badea7a0de36274d5c1eb1e8f975785532c50d80fd44b1a4b692f437303393f"), - MustHexID("6d8b3efb461151dd4f6de809b62726f5b89e9b38e9ba1391967f61cde844f7528fecf821b74049207cee5a527096b31f3ad623928cd3ce51d926fa345a6b2951"), + hexEncPubkey("9b8f702a62d1bee67bedfeb102eca7f37fa1713e310f0d6651cc0c33ea7c5477575289ccd463e5a2574a00a676a1fdce05658ba447bb9d2827f0ba47b947e894"), + hexEncPubkey("b97532eb83054ed054b4abdf413bb30c00e4205545c93521554dbe77faa3cfaa5bd31ef466a107b0b34a71ec97214c0c83919720142cddac93aa7a3e928d4708"), + hexEncPubkey("2f7a5e952bfb67f2f90b8441b5fadc9ee13b1dcde3afeeb3dd64bf937f86663cc5c55d1fa83952b5422763c7df1b7f2794b751c6be316ebc0beb4942e65ab8c1"), + hexEncPubkey("42c7483781727051a0b3660f14faf39e0d33de5e643702ae933837d036508ab856ce7eec8ec89c4929a4901256e5233a3d847d5d4893f91bcf21835a9a880fee"), + hexEncPubkey("873bae27bf1dc854408fba94046a53ab0c965cebe1e4e12290806fc62b88deb1f4a47f9e18f78fc0e7913a0c6e42ac4d0fc3a20cea6bc65f0c8a0ca90b67521e"), + hexEncPubkey("a7e3a370bbd761d413f8d209e85886f68bf73d5c3089b2dc6fa42aab1ecb5162635497eed95dee2417f3c9c74a3e76319625c48ead2e963c7de877cd4551f347"), + hexEncPubkey("528597534776a40df2addaaea15b6ff832ce36b9748a265768368f657e76d58569d9f30dbb91e91cf0ae7efe8f402f17aa0ae15f5c55051ba03ba830287f4c42"), + hexEncPubkey("461d8bd4f13c3c09031fdb84f104ed737a52f630261463ce0bdb5704259bab4b737dda688285b8444dbecaecad7f50f835190b38684ced5e90c54219e5adf1bc"), + hexEncPubkey("6ec50c0be3fd232737090fc0111caaf0bb6b18f72be453428087a11a97fd6b52db0344acbf789a689bd4f5f50f79017ea784f8fd6fe723ad6ae675b9e3b13e21"), + hexEncPubkey("12fc5e2f77a83fdcc727b79d8ae7fe6a516881138d3011847ee136b400fed7cfba1f53fd7a9730253c7aa4f39abeacd04f138417ba7fcb0f36cccc3514e0dab6"), + hexEncPubkey("4fdbe75914ccd0bce02101606a1ccf3657ec963e3b3c20239d5fec87673fe446d649b4f15f1fe1a40e6cfbd446dda2d31d40bb602b1093b8fcd5f139ba0eb46a"), + hexEncPubkey("3753668a0f6281e425ea69b52cb2d17ab97afbe6eb84cf5d25425bc5e53009388857640668fadd7c110721e6047c9697803bd8a6487b43bb343bfa32ebf24039"), + hexEncPubkey("2e81b16346637dec4410fd88e527346145b9c0a849dbf2628049ac7dae016c8f4305649d5659ec77f1e8a0fac0db457b6080547226f06283598e3740ad94849a"), + hexEncPubkey("802c3cc27f91c89213223d758f8d2ecd41135b357b6d698f24d811cdf113033a81c38e0bdff574a5c005b00a8c193dc2531f8c1fa05fa60acf0ab6f2858af09f"), + hexEncPubkey("fcc9a2e1ac3667026ff16192876d1813bb75abdbf39b929a92863012fe8b1d890badea7a0de36274d5c1eb1e8f975785532c50d80fd44b1a4b692f437303393f"), + hexEncPubkey("6d8b3efb461151dd4f6de809b62726f5b89e9b38e9ba1391967f61cde844f7528fecf821b74049207cee5a527096b31f3ad623928cd3ce51d926fa345a6b2951"), }, 252: { - MustHexID("f1ae93157cc48c2075dd5868fbf523e79e06caf4b8198f352f6e526680b78ff4227263de92612f7d63472bd09367bb92a636fff16fe46ccf41614f7a72495c2a"), - MustHexID("587f482d111b239c27c0cb89b51dd5d574db8efd8de14a2e6a1400c54d4567e77c65f89c1da52841212080b91604104768350276b6682f2f961cdaf4039581c7"), - MustHexID("e3f88274d35cefdaabdf205afe0e80e936cc982b8e3e47a84ce664c413b29016a4fb4f3a3ebae0a2f79671f8323661ed462bf4390af94c424dc8ace0c301b90f"), - MustHexID("0ddc736077da9a12ba410dc5ea63cbcbe7659dd08596485b2bff3435221f82c10d263efd9af938e128464be64a178b7cd22e19f400d5802f4c9df54bf89f2619"), - MustHexID("784aa34d833c6ce63fcc1279630113c3272e82c4ae8c126c5a52a88ac461b6baeed4244e607b05dc14e5b2f41c70a273c3804dea237f14f7a1e546f6d1309d14"), - MustHexID("f253a2c354ee0e27cfcae786d726753d4ad24be6516b279a936195a487de4a59dbc296accf20463749ff55293263ed8c1b6365eecb248d44e75e9741c0d18205"), - MustHexID("a1910b80357b3ad9b4593e0628922939614dc9056a5fbf477279c8b2c1d0b4b31d89a0c09d0d41f795271d14d3360ef08a3f821e65e7e1f56c07a36afe49c7c5"), - MustHexID("f1168552c2efe541160f0909b0b4a9d6aeedcf595cdf0e9b165c97e3e197471a1ee6320e93389edfba28af6eaf10de98597ad56e7ab1b504ed762451996c3b98"), - MustHexID("b0c8e5d2c8634a7930e1a6fd082e448c6cf9d2d8b7293558b59238815a4df926c286bf297d2049f14e8296a6eb3256af614ec1812c4f2bbe807673b58bf14c8c"), - MustHexID("0fb346076396a38badc342df3679b55bd7f40a609ab103411fe45082c01f12ea016729e95914b2b5540e987ff5c9b133e85862648e7f36abdfd23100d248d234"), - MustHexID("f736e0cc83417feaa280d9483f5d4d72d1b036cd0c6d9cbdeb8ac35ceb2604780de46dddaa32a378474e1d5ccdf79b373331c30c7911ade2ae32f98832e5de1f"), - MustHexID("8b02991457602f42b38b342d3f2259ae4100c354b3843885f7e4e07bd644f64dab94bb7f38a3915f8b7f11d8e3f81c28e07a0078cf79d7397e38a7b7e0c857e2"), - MustHexID("9221d9f04a8a184993d12baa91116692bb685f887671302999d69300ad103eb2d2c75a09d8979404c6dd28f12362f58a1a43619c493d9108fd47588a23ce5824"), - MustHexID("652797801744dada833fff207d67484742eea6835d695925f3e618d71b68ec3c65bdd85b4302b2cdcb835ad3f94fd00d8da07e570b41bc0d2bcf69a8de1b3284"), - MustHexID("d84f06fe64debc4cd0625e36d19b99014b6218375262cc2209202bdbafd7dffcc4e34ce6398e182e02fd8faeed622c3e175545864902dfd3d1ac57647cddf4c6"), - MustHexID("d0ed87b294f38f1d741eb601020eeec30ac16331d05880fe27868f1e454446de367d7457b41c79e202eaf9525b029e4f1d7e17d85a55f83a557c005c68d7328a"), + hexEncPubkey("f1ae93157cc48c2075dd5868fbf523e79e06caf4b8198f352f6e526680b78ff4227263de92612f7d63472bd09367bb92a636fff16fe46ccf41614f7a72495c2a"), + hexEncPubkey("587f482d111b239c27c0cb89b51dd5d574db8efd8de14a2e6a1400c54d4567e77c65f89c1da52841212080b91604104768350276b6682f2f961cdaf4039581c7"), + hexEncPubkey("e3f88274d35cefdaabdf205afe0e80e936cc982b8e3e47a84ce664c413b29016a4fb4f3a3ebae0a2f79671f8323661ed462bf4390af94c424dc8ace0c301b90f"), + hexEncPubkey("0ddc736077da9a12ba410dc5ea63cbcbe7659dd08596485b2bff3435221f82c10d263efd9af938e128464be64a178b7cd22e19f400d5802f4c9df54bf89f2619"), + hexEncPubkey("784aa34d833c6ce63fcc1279630113c3272e82c4ae8c126c5a52a88ac461b6baeed4244e607b05dc14e5b2f41c70a273c3804dea237f14f7a1e546f6d1309d14"), + hexEncPubkey("f253a2c354ee0e27cfcae786d726753d4ad24be6516b279a936195a487de4a59dbc296accf20463749ff55293263ed8c1b6365eecb248d44e75e9741c0d18205"), + hexEncPubkey("a1910b80357b3ad9b4593e0628922939614dc9056a5fbf477279c8b2c1d0b4b31d89a0c09d0d41f795271d14d3360ef08a3f821e65e7e1f56c07a36afe49c7c5"), + hexEncPubkey("f1168552c2efe541160f0909b0b4a9d6aeedcf595cdf0e9b165c97e3e197471a1ee6320e93389edfba28af6eaf10de98597ad56e7ab1b504ed762451996c3b98"), + hexEncPubkey("b0c8e5d2c8634a7930e1a6fd082e448c6cf9d2d8b7293558b59238815a4df926c286bf297d2049f14e8296a6eb3256af614ec1812c4f2bbe807673b58bf14c8c"), + hexEncPubkey("0fb346076396a38badc342df3679b55bd7f40a609ab103411fe45082c01f12ea016729e95914b2b5540e987ff5c9b133e85862648e7f36abdfd23100d248d234"), + hexEncPubkey("f736e0cc83417feaa280d9483f5d4d72d1b036cd0c6d9cbdeb8ac35ceb2604780de46dddaa32a378474e1d5ccdf79b373331c30c7911ade2ae32f98832e5de1f"), + hexEncPubkey("8b02991457602f42b38b342d3f2259ae4100c354b3843885f7e4e07bd644f64dab94bb7f38a3915f8b7f11d8e3f81c28e07a0078cf79d7397e38a7b7e0c857e2"), + hexEncPubkey("9221d9f04a8a184993d12baa91116692bb685f887671302999d69300ad103eb2d2c75a09d8979404c6dd28f12362f58a1a43619c493d9108fd47588a23ce5824"), + hexEncPubkey("652797801744dada833fff207d67484742eea6835d695925f3e618d71b68ec3c65bdd85b4302b2cdcb835ad3f94fd00d8da07e570b41bc0d2bcf69a8de1b3284"), + hexEncPubkey("d84f06fe64debc4cd0625e36d19b99014b6218375262cc2209202bdbafd7dffcc4e34ce6398e182e02fd8faeed622c3e175545864902dfd3d1ac57647cddf4c6"), + hexEncPubkey("d0ed87b294f38f1d741eb601020eeec30ac16331d05880fe27868f1e454446de367d7457b41c79e202eaf9525b029e4f1d7e17d85a55f83a557c005c68d7328a"), }, 253: { - MustHexID("ad4485e386e3cc7c7310366a7c38fb810b8896c0d52e55944bfd320ca294e7912d6c53c0a0cf85e7ce226e92491d60430e86f8f15cda0161ed71893fb4a9e3a1"), - MustHexID("36d0e7e5b7734f98c6183eeeb8ac5130a85e910a925311a19c4941b1290f945d4fc3996b12ef4966960b6fa0fb29b1604f83a0f81bd5fd6398d2e1a22e46af0c"), - MustHexID("7d307d8acb4a561afa23bdf0bd945d35c90245e26345ec3a1f9f7df354222a7cdcb81339c9ed6744526c27a1a0c8d10857e98df942fa433602facac71ac68a31"), - MustHexID("d97bf55f88c83fae36232661af115d66ca600fc4bd6d1fb35ff9bb4dad674c02cf8c8d05f317525b5522250db58bb1ecafb7157392bf5aa61b178c61f098d995"), - MustHexID("7045d678f1f9eb7a4613764d17bd5698796494d0bf977b16f2dbc272b8a0f7858a60805c022fc3d1fe4f31c37e63cdaca0416c0d053ef48a815f8b19121605e0"), - MustHexID("14e1f21418d445748de2a95cd9a8c3b15b506f86a0acabd8af44bb968ce39885b19c8822af61b3dd58a34d1f265baec30e3ae56149dc7d2aa4a538f7319f69c8"), - MustHexID("b9453d78281b66a4eac95a1546017111eaaa5f92a65d0de10b1122940e92b319728a24edf4dec6acc412321b1c95266d39c7b3a5d265c629c3e49a65fb022c09"), - MustHexID("e8a49248419e3824a00d86af422f22f7366e2d4922b304b7169937616a01d9d6fa5abf5cc01061a352dc866f48e1fa2240dbb453d872b1d7be62bdfc1d5e248c"), - MustHexID("bebcff24b52362f30e0589ee573ce2d86f073d58d18e6852a592fa86ceb1a6c9b96d7fb9ec7ed1ed98a51b6743039e780279f6bb49d0a04327ac7a182d9a56f6"), - MustHexID("d0835e5a4291db249b8d2fca9f503049988180c7d247bedaa2cf3a1bad0a76709360a85d4f9a1423b2cbc82bb4d94b47c0cde20afc430224834c49fe312a9ae3"), - MustHexID("6b087fe2a2da5e4f0b0f4777598a4a7fb66bf77dbd5bfc44e8a7eaa432ab585a6e226891f56a7d4f5ed11a7c57b90f1661bba1059590ca4267a35801c2802913"), - MustHexID("d901e5bde52d1a0f4ddf010a686a53974cdae4ebe5c6551b3c37d6b6d635d38d5b0e5f80bc0186a2c7809dbf3a42870dd09643e68d32db896c6da8ba734579e7"), - MustHexID("96419fb80efae4b674402bb969ebaab86c1274f29a83a311e24516d36cdf148fe21754d46c97688cdd7468f24c08b13e4727c29263393638a3b37b99ff60ebca"), - MustHexID("7b9c1889ae916a5d5abcdfb0aaedcc9c6f9eb1c1a4f68d0c2d034fe79ac610ce917c3abc670744150fa891bfcd8ab14fed6983fca964de920aa393fa7b326748"), - MustHexID("7a369b2b8962cc4c65900be046482fbf7c14f98a135bbbae25152c82ad168fb2097b3d1429197cf46d3ce9fdeb64808f908a489cc6019725db040060fdfe5405"), - MustHexID("47bcae48288da5ecc7f5058dfa07cf14d89d06d6e449cb946e237aa6652ea050d9f5a24a65efdc0013ccf232bf88670979eddef249b054f63f38da9d7796dbd8"), + hexEncPubkey("ad4485e386e3cc7c7310366a7c38fb810b8896c0d52e55944bfd320ca294e7912d6c53c0a0cf85e7ce226e92491d60430e86f8f15cda0161ed71893fb4a9e3a1"), + hexEncPubkey("36d0e7e5b7734f98c6183eeeb8ac5130a85e910a925311a19c4941b1290f945d4fc3996b12ef4966960b6fa0fb29b1604f83a0f81bd5fd6398d2e1a22e46af0c"), + hexEncPubkey("7d307d8acb4a561afa23bdf0bd945d35c90245e26345ec3a1f9f7df354222a7cdcb81339c9ed6744526c27a1a0c8d10857e98df942fa433602facac71ac68a31"), + hexEncPubkey("d97bf55f88c83fae36232661af115d66ca600fc4bd6d1fb35ff9bb4dad674c02cf8c8d05f317525b5522250db58bb1ecafb7157392bf5aa61b178c61f098d995"), + hexEncPubkey("7045d678f1f9eb7a4613764d17bd5698796494d0bf977b16f2dbc272b8a0f7858a60805c022fc3d1fe4f31c37e63cdaca0416c0d053ef48a815f8b19121605e0"), + hexEncPubkey("14e1f21418d445748de2a95cd9a8c3b15b506f86a0acabd8af44bb968ce39885b19c8822af61b3dd58a34d1f265baec30e3ae56149dc7d2aa4a538f7319f69c8"), + hexEncPubkey("b9453d78281b66a4eac95a1546017111eaaa5f92a65d0de10b1122940e92b319728a24edf4dec6acc412321b1c95266d39c7b3a5d265c629c3e49a65fb022c09"), + hexEncPubkey("e8a49248419e3824a00d86af422f22f7366e2d4922b304b7169937616a01d9d6fa5abf5cc01061a352dc866f48e1fa2240dbb453d872b1d7be62bdfc1d5e248c"), + hexEncPubkey("bebcff24b52362f30e0589ee573ce2d86f073d58d18e6852a592fa86ceb1a6c9b96d7fb9ec7ed1ed98a51b6743039e780279f6bb49d0a04327ac7a182d9a56f6"), + hexEncPubkey("d0835e5a4291db249b8d2fca9f503049988180c7d247bedaa2cf3a1bad0a76709360a85d4f9a1423b2cbc82bb4d94b47c0cde20afc430224834c49fe312a9ae3"), + hexEncPubkey("6b087fe2a2da5e4f0b0f4777598a4a7fb66bf77dbd5bfc44e8a7eaa432ab585a6e226891f56a7d4f5ed11a7c57b90f1661bba1059590ca4267a35801c2802913"), + hexEncPubkey("d901e5bde52d1a0f4ddf010a686a53974cdae4ebe5c6551b3c37d6b6d635d38d5b0e5f80bc0186a2c7809dbf3a42870dd09643e68d32db896c6da8ba734579e7"), + hexEncPubkey("96419fb80efae4b674402bb969ebaab86c1274f29a83a311e24516d36cdf148fe21754d46c97688cdd7468f24c08b13e4727c29263393638a3b37b99ff60ebca"), + hexEncPubkey("7b9c1889ae916a5d5abcdfb0aaedcc9c6f9eb1c1a4f68d0c2d034fe79ac610ce917c3abc670744150fa891bfcd8ab14fed6983fca964de920aa393fa7b326748"), + hexEncPubkey("7a369b2b8962cc4c65900be046482fbf7c14f98a135bbbae25152c82ad168fb2097b3d1429197cf46d3ce9fdeb64808f908a489cc6019725db040060fdfe5405"), + hexEncPubkey("47bcae48288da5ecc7f5058dfa07cf14d89d06d6e449cb946e237aa6652ea050d9f5a24a65efdc0013ccf232bf88670979eddef249b054f63f38da9d7796dbd8"), }, 254: { - MustHexID("099739d7abc8abd38ecc7a816c521a1168a4dbd359fa7212a5123ab583ffa1cf485a5fed219575d6475dbcdd541638b2d3631a6c7fce7474e7fe3cba1d4d5853"), - MustHexID("c2b01603b088a7182d0cf7ef29fb2b04c70acb320fccf78526bf9472e10c74ee70b3fcfa6f4b11d167bd7d3bc4d936b660f2c9bff934793d97cb21750e7c3d31"), - MustHexID("20e4d8f45f2f863e94b45548c1ef22a11f7d36f263e4f8623761e05a64c4572379b000a52211751e2561b0f14f4fc92dd4130410c8ccc71eb4f0e95a700d4ca9"), - MustHexID("27f4a16cc085e72d86e25c98bd2eca173eaaee7565c78ec5a52e9e12b2211f35de81b5b45e9195de2ebfe29106742c59112b951a04eb7ae48822911fc1f9389e"), - MustHexID("55db5ee7d98e7f0b1c3b9d5be6f2bc619a1b86c3cdd513160ad4dcf267037a5fffad527ac15d50aeb32c59c13d1d4c1e567ebbf4de0d25236130c8361f9aac63"), - MustHexID("883df308b0130fc928a8559fe50667a0fff80493bc09685d18213b2db241a3ad11310ed86b0ef662b3ce21fc3d9aa7f3fc24b8d9afe17c7407e9afd3345ae548"), - MustHexID("c7af968cc9bc8200c3ee1a387405f7563be1dce6710a3439f42ea40657d0eae9d2b3c16c42d779605351fcdece4da637b9804e60ca08cfb89aec32c197beffa6"), - MustHexID("3e66f2b788e3ff1d04106b80597915cd7afa06c405a7ae026556b6e583dca8e05cfbab5039bb9a1b5d06083ffe8de5780b1775550e7218f5e98624bf7af9a0a8"), - MustHexID("4fc7f53764de3337fdaec0a711d35d3a923e72fa65025444d12230b3552ed43d9b2d1ad08ccb11f2d50c58809e6dd74dde910e195294fca3b47ae5a3967cc479"), - MustHexID("bafdfdcf6ccaa989436752fa97c77477b6baa7deb374b16c095492c529eb133e8e2f99e1977012b64767b9d34b2cf6d2048ed489bd822b5139b523f6a423167b"), - MustHexID("7f5d78008a4312fe059104ce80202c82b8915c2eb4411c6b812b16f7642e57c00f2c9425121f5cbac4257fe0b3e81ef5dea97ea2dbaa98f6a8b6fd4d1e5980bb"), - MustHexID("598c37fe78f922751a052f463aeb0cb0bc7f52b7c2a4cf2da72ec0931c7c32175d4165d0f8998f7320e87324ac3311c03f9382a5385c55f0407b7a66b2acd864"), - MustHexID("f758c4136e1c148777a7f3275a76e2db0b2b04066fd738554ec398c1c6cc9fb47e14a3b4c87bd47deaeab3ffd2110514c3855685a374794daff87b605b27ee2e"), - MustHexID("0307bb9e4fd865a49dcf1fe4333d1b944547db650ab580af0b33e53c4fef6c789531110fac801bbcbce21fc4d6f61b6d5b24abdf5b22e3030646d579f6dca9c2"), - MustHexID("82504b6eb49bb2c0f91a7006ce9cefdbaf6df38706198502c2e06601091fc9dc91e4f15db3410d45c6af355bc270b0f268d3dff560f956985c7332d4b10bd1ed"), - MustHexID("b39b5b677b45944ceebe76e76d1f051de2f2a0ec7b0d650da52135743e66a9a5dba45f638258f9a7545d9a790c7fe6d3fdf82c25425c7887323e45d27d06c057"), + hexEncPubkey("099739d7abc8abd38ecc7a816c521a1168a4dbd359fa7212a5123ab583ffa1cf485a5fed219575d6475dbcdd541638b2d3631a6c7fce7474e7fe3cba1d4d5853"), + hexEncPubkey("c2b01603b088a7182d0cf7ef29fb2b04c70acb320fccf78526bf9472e10c74ee70b3fcfa6f4b11d167bd7d3bc4d936b660f2c9bff934793d97cb21750e7c3d31"), + hexEncPubkey("20e4d8f45f2f863e94b45548c1ef22a11f7d36f263e4f8623761e05a64c4572379b000a52211751e2561b0f14f4fc92dd4130410c8ccc71eb4f0e95a700d4ca9"), + hexEncPubkey("27f4a16cc085e72d86e25c98bd2eca173eaaee7565c78ec5a52e9e12b2211f35de81b5b45e9195de2ebfe29106742c59112b951a04eb7ae48822911fc1f9389e"), + hexEncPubkey("55db5ee7d98e7f0b1c3b9d5be6f2bc619a1b86c3cdd513160ad4dcf267037a5fffad527ac15d50aeb32c59c13d1d4c1e567ebbf4de0d25236130c8361f9aac63"), + hexEncPubkey("883df308b0130fc928a8559fe50667a0fff80493bc09685d18213b2db241a3ad11310ed86b0ef662b3ce21fc3d9aa7f3fc24b8d9afe17c7407e9afd3345ae548"), + hexEncPubkey("c7af968cc9bc8200c3ee1a387405f7563be1dce6710a3439f42ea40657d0eae9d2b3c16c42d779605351fcdece4da637b9804e60ca08cfb89aec32c197beffa6"), + hexEncPubkey("3e66f2b788e3ff1d04106b80597915cd7afa06c405a7ae026556b6e583dca8e05cfbab5039bb9a1b5d06083ffe8de5780b1775550e7218f5e98624bf7af9a0a8"), + hexEncPubkey("4fc7f53764de3337fdaec0a711d35d3a923e72fa65025444d12230b3552ed43d9b2d1ad08ccb11f2d50c58809e6dd74dde910e195294fca3b47ae5a3967cc479"), + hexEncPubkey("bafdfdcf6ccaa989436752fa97c77477b6baa7deb374b16c095492c529eb133e8e2f99e1977012b64767b9d34b2cf6d2048ed489bd822b5139b523f6a423167b"), + hexEncPubkey("7f5d78008a4312fe059104ce80202c82b8915c2eb4411c6b812b16f7642e57c00f2c9425121f5cbac4257fe0b3e81ef5dea97ea2dbaa98f6a8b6fd4d1e5980bb"), + hexEncPubkey("598c37fe78f922751a052f463aeb0cb0bc7f52b7c2a4cf2da72ec0931c7c32175d4165d0f8998f7320e87324ac3311c03f9382a5385c55f0407b7a66b2acd864"), + hexEncPubkey("f758c4136e1c148777a7f3275a76e2db0b2b04066fd738554ec398c1c6cc9fb47e14a3b4c87bd47deaeab3ffd2110514c3855685a374794daff87b605b27ee2e"), + hexEncPubkey("0307bb9e4fd865a49dcf1fe4333d1b944547db650ab580af0b33e53c4fef6c789531110fac801bbcbce21fc4d6f61b6d5b24abdf5b22e3030646d579f6dca9c2"), + hexEncPubkey("82504b6eb49bb2c0f91a7006ce9cefdbaf6df38706198502c2e06601091fc9dc91e4f15db3410d45c6af355bc270b0f268d3dff560f956985c7332d4b10bd1ed"), + hexEncPubkey("b39b5b677b45944ceebe76e76d1f051de2f2a0ec7b0d650da52135743e66a9a5dba45f638258f9a7545d9a790c7fe6d3fdf82c25425c7887323e45d27d06c057"), }, 255: { - MustHexID("5c4d58d46e055dd1f093f81ee60a675e1f02f54da6206720adee4dccef9b67a31efc5c2a2949c31a04ee31beadc79aba10da31440a1f9ff2a24093c63c36d784"), - MustHexID("ea72161ffdd4b1e124c7b93b0684805f4c4b58d617ed498b37a145c670dbc2e04976f8785583d9c805ffbf343c31d492d79f841652bbbd01b61ed85640b23495"), - MustHexID("51caa1d93352d47a8e531692a3612adac1e8ac68d0a200d086c1c57ae1e1a91aa285ab242e8c52ef9d7afe374c9485b122ae815f1707b875569d0433c1c3ce85"), - MustHexID("c08397d5751b47bd3da044b908be0fb0e510d3149574dff7aeab33749b023bb171b5769990fe17469dbebc100bc150e798aeda426a2dcc766699a225fddd75c6"), - MustHexID("0222c1c194b749736e593f937fad67ee348ac57287a15c7e42877aa38a9b87732a408bca370f812efd0eedbff13e6d5b854bf3ba1dec431a796ed47f32552b09"), - MustHexID("03d859cd46ef02d9bfad5268461a6955426845eef4126de6be0fa4e8d7e0727ba2385b78f1a883a8239e95ebb814f2af8379632c7d5b100688eebc5841209582"), - MustHexID("64d5004b7e043c39ff0bd10cb20094c287721d5251715884c280a612b494b3e9e1c64ba6f67614994c7d969a0d0c0295d107d53fc225d47c44c4b82852d6f960"), - MustHexID("b0a5eefb2dab6f786670f35bf9641eefe6dd87fd3f1362bcab4aaa792903500ab23d88fae68411372e0813b057535a601d46e454323745a948017f6063a47b1f"), - MustHexID("0cc6df0a3433d448b5684d2a3ffa9d1a825388177a18f44ad0008c7bd7702f1ec0fc38b83506f7de689c3b6ecb552599927e29699eed6bb867ff08f80068b287"), - MustHexID("50772f7b8c03a4e153355fbbf79c8a80cf32af656ff0c7873c99911099d04a0dae0674706c357e0145ad017a0ade65e6052cb1b0d574fcd6f67da3eee0ace66b"), - MustHexID("1ae37829c9ef41f8b508b82259ebac76b1ed900d7a45c08b7970f25d2d48ddd1829e2f11423a18749940b6dab8598c6e416cef0efd47e46e51f29a0bc65b37cd"), - MustHexID("ba973cab31c2af091fc1644a93527d62b2394999e2b6ccbf158dd5ab9796a43d408786f1803ef4e29debfeb62fce2b6caa5ab2b24d1549c822a11c40c2856665"), - MustHexID("bc413ad270dd6ea25bddba78f3298b03b8ba6f8608ac03d06007d4116fa78ef5a0cfe8c80155089382fc7a193243ee5500082660cb5d7793f60f2d7d18650964"), - MustHexID("5a6a9ef07634d9eec3baa87c997b529b92652afa11473dfee41ef7037d5c06e0ddb9fe842364462d79dd31cff8a59a1b8d5bc2b810dea1d4cbbd3beb80ecec83"), - MustHexID("f492c6ee2696d5f682f7f537757e52744c2ae560f1090a07024609e903d334e9e174fc01609c5a229ddbcac36c9d21adaf6457dab38a25bfd44f2f0ee4277998"), - MustHexID("459e4db99298cb0467a90acee6888b08bb857450deac11015cced5104853be5adce5b69c740968bc7f931495d671a70cad9f48546d7cd203357fe9af0e8d2164"), + hexEncPubkey("5c4d58d46e055dd1f093f81ee60a675e1f02f54da6206720adee4dccef9b67a31efc5c2a2949c31a04ee31beadc79aba10da31440a1f9ff2a24093c63c36d784"), + hexEncPubkey("ea72161ffdd4b1e124c7b93b0684805f4c4b58d617ed498b37a145c670dbc2e04976f8785583d9c805ffbf343c31d492d79f841652bbbd01b61ed85640b23495"), + hexEncPubkey("51caa1d93352d47a8e531692a3612adac1e8ac68d0a200d086c1c57ae1e1a91aa285ab242e8c52ef9d7afe374c9485b122ae815f1707b875569d0433c1c3ce85"), + hexEncPubkey("c08397d5751b47bd3da044b908be0fb0e510d3149574dff7aeab33749b023bb171b5769990fe17469dbebc100bc150e798aeda426a2dcc766699a225fddd75c6"), + hexEncPubkey("0222c1c194b749736e593f937fad67ee348ac57287a15c7e42877aa38a9b87732a408bca370f812efd0eedbff13e6d5b854bf3ba1dec431a796ed47f32552b09"), + hexEncPubkey("03d859cd46ef02d9bfad5268461a6955426845eef4126de6be0fa4e8d7e0727ba2385b78f1a883a8239e95ebb814f2af8379632c7d5b100688eebc5841209582"), + hexEncPubkey("64d5004b7e043c39ff0bd10cb20094c287721d5251715884c280a612b494b3e9e1c64ba6f67614994c7d969a0d0c0295d107d53fc225d47c44c4b82852d6f960"), + hexEncPubkey("b0a5eefb2dab6f786670f35bf9641eefe6dd87fd3f1362bcab4aaa792903500ab23d88fae68411372e0813b057535a601d46e454323745a948017f6063a47b1f"), + hexEncPubkey("0cc6df0a3433d448b5684d2a3ffa9d1a825388177a18f44ad0008c7bd7702f1ec0fc38b83506f7de689c3b6ecb552599927e29699eed6bb867ff08f80068b287"), + hexEncPubkey("50772f7b8c03a4e153355fbbf79c8a80cf32af656ff0c7873c99911099d04a0dae0674706c357e0145ad017a0ade65e6052cb1b0d574fcd6f67da3eee0ace66b"), + hexEncPubkey("1ae37829c9ef41f8b508b82259ebac76b1ed900d7a45c08b7970f25d2d48ddd1829e2f11423a18749940b6dab8598c6e416cef0efd47e46e51f29a0bc65b37cd"), + hexEncPubkey("ba973cab31c2af091fc1644a93527d62b2394999e2b6ccbf158dd5ab9796a43d408786f1803ef4e29debfeb62fce2b6caa5ab2b24d1549c822a11c40c2856665"), + hexEncPubkey("bc413ad270dd6ea25bddba78f3298b03b8ba6f8608ac03d06007d4116fa78ef5a0cfe8c80155089382fc7a193243ee5500082660cb5d7793f60f2d7d18650964"), + hexEncPubkey("5a6a9ef07634d9eec3baa87c997b529b92652afa11473dfee41ef7037d5c06e0ddb9fe842364462d79dd31cff8a59a1b8d5bc2b810dea1d4cbbd3beb80ecec83"), + hexEncPubkey("f492c6ee2696d5f682f7f537757e52744c2ae560f1090a07024609e903d334e9e174fc01609c5a229ddbcac36c9d21adaf6457dab38a25bfd44f2f0ee4277998"), + hexEncPubkey("459e4db99298cb0467a90acee6888b08bb857450deac11015cced5104853be5adce5b69c740968bc7f931495d671a70cad9f48546d7cd203357fe9af0e8d2164"), }, 256: { - MustHexID("a8593af8a4aef7b806b5197612017951bac8845a1917ca9a6a15dd6086d608505144990b245785c4cd2d67a295701c7aac2aa18823fb0033987284b019656268"), - MustHexID("d2eebef914928c3aad77fc1b2a495f52d2294acf5edaa7d8a530b540f094b861a68fe8348a46a7c302f08ab609d85912a4968eacfea0740847b29421b4795d9e"), - MustHexID("b14bfcb31495f32b650b63cf7d08492e3e29071fdc73cf2da0da48d4b191a70ba1a65f42ad8c343206101f00f8a48e8db4b08bf3f622c0853e7323b250835b91"), - MustHexID("7feaee0d818c03eb30e4e0bf03ade0f3c21ca38e938a761aa1781cf70bda8cc5cd631a6cc53dd44f1d4a6d3e2dae6513c6c66ee50cb2f0e9ad6f7e319b309fd9"), - MustHexID("4ca3b657b139311db8d583c25dd5963005e46689e1317620496cc64129c7f3e52870820e0ec7941d28809311df6db8a2867bbd4f235b4248af24d7a9c22d1232"), - MustHexID("1181defb1d16851d42dd951d84424d6bd1479137f587fa184d5a8152be6b6b16ed08bcdb2c2ed8539bcde98c80c432875f9f724737c316a2bd385a39d3cab1d8"), - MustHexID("d9dd818769fa0c3ec9f553c759b92476f082817252a04a47dc1777740b1731d280058c66f982812f173a294acf4944a85ba08346e2de153ba3ba41ce8a62cb64"), - MustHexID("bd7c4f8a9e770aa915c771b15e107ca123d838762da0d3ffc53aa6b53e9cd076cffc534ec4d2e4c334c683f1f5ea72e0e123f6c261915ed5b58ac1b59f003d88"), - MustHexID("3dd5739c73649d510456a70e9d6b46a855864a4a3f744e088fd8c8da11b18e4c9b5f2d7da50b1c147b2bae5ca9609ae01f7a3cdea9dce34f80a91d29cd82f918"), - MustHexID("f0d7df1efc439b4bcc0b762118c1cfa99b2a6143a9f4b10e3c9465125f4c9fca4ab88a2504169bbcad65492cf2f50da9dd5d077c39574a944f94d8246529066b"), - MustHexID("dd598b9ba441448e5fb1a6ec6c5f5aa9605bad6e223297c729b1705d11d05f6bfd3d41988b694681ae69bb03b9a08bff4beab5596503d12a39bffb5cd6e94c7c"), - MustHexID("3fce284ac97e567aebae681b15b7a2b6df9d873945536335883e4bbc26460c064370537f323fd1ada828ea43154992d14ac0cec0940a2bd2a3f42ec156d60c83"), - MustHexID("7c8dfa8c1311cb14fb29a8ac11bca23ecc115e56d9fcf7b7ac1db9066aa4eb39f8b1dabf46e192a65be95ebfb4e839b5ab4533fef414921825e996b210dd53bd"), - MustHexID("cafa6934f82120456620573d7f801390ed5e16ed619613a37e409e44ab355ef755e83565a913b48a9466db786f8d4fbd590bfec474c2524d4a2608d4eafd6abd"), - MustHexID("9d16600d0dd310d77045769fed2cb427f32db88cd57d86e49390c2ba8a9698cfa856f775be2013237226e7bf47b248871cf865d23015937d1edeb20db5e3e760"), - MustHexID("17be6b6ba54199b1d80eff866d348ea11d8a4b341d63ad9a6681d3ef8a43853ac564d153eb2a8737f0afc9ab320f6f95c55aa11aaa13bbb1ff422fd16bdf8188"), + hexEncPubkey("a8593af8a4aef7b806b5197612017951bac8845a1917ca9a6a15dd6086d608505144990b245785c4cd2d67a295701c7aac2aa18823fb0033987284b019656268"), + hexEncPubkey("d2eebef914928c3aad77fc1b2a495f52d2294acf5edaa7d8a530b540f094b861a68fe8348a46a7c302f08ab609d85912a4968eacfea0740847b29421b4795d9e"), + hexEncPubkey("b14bfcb31495f32b650b63cf7d08492e3e29071fdc73cf2da0da48d4b191a70ba1a65f42ad8c343206101f00f8a48e8db4b08bf3f622c0853e7323b250835b91"), + hexEncPubkey("7feaee0d818c03eb30e4e0bf03ade0f3c21ca38e938a761aa1781cf70bda8cc5cd631a6cc53dd44f1d4a6d3e2dae6513c6c66ee50cb2f0e9ad6f7e319b309fd9"), + hexEncPubkey("4ca3b657b139311db8d583c25dd5963005e46689e1317620496cc64129c7f3e52870820e0ec7941d28809311df6db8a2867bbd4f235b4248af24d7a9c22d1232"), + hexEncPubkey("1181defb1d16851d42dd951d84424d6bd1479137f587fa184d5a8152be6b6b16ed08bcdb2c2ed8539bcde98c80c432875f9f724737c316a2bd385a39d3cab1d8"), + hexEncPubkey("d9dd818769fa0c3ec9f553c759b92476f082817252a04a47dc1777740b1731d280058c66f982812f173a294acf4944a85ba08346e2de153ba3ba41ce8a62cb64"), + hexEncPubkey("bd7c4f8a9e770aa915c771b15e107ca123d838762da0d3ffc53aa6b53e9cd076cffc534ec4d2e4c334c683f1f5ea72e0e123f6c261915ed5b58ac1b59f003d88"), + hexEncPubkey("3dd5739c73649d510456a70e9d6b46a855864a4a3f744e088fd8c8da11b18e4c9b5f2d7da50b1c147b2bae5ca9609ae01f7a3cdea9dce34f80a91d29cd82f918"), + hexEncPubkey("f0d7df1efc439b4bcc0b762118c1cfa99b2a6143a9f4b10e3c9465125f4c9fca4ab88a2504169bbcad65492cf2f50da9dd5d077c39574a944f94d8246529066b"), + hexEncPubkey("dd598b9ba441448e5fb1a6ec6c5f5aa9605bad6e223297c729b1705d11d05f6bfd3d41988b694681ae69bb03b9a08bff4beab5596503d12a39bffb5cd6e94c7c"), + hexEncPubkey("3fce284ac97e567aebae681b15b7a2b6df9d873945536335883e4bbc26460c064370537f323fd1ada828ea43154992d14ac0cec0940a2bd2a3f42ec156d60c83"), + hexEncPubkey("7c8dfa8c1311cb14fb29a8ac11bca23ecc115e56d9fcf7b7ac1db9066aa4eb39f8b1dabf46e192a65be95ebfb4e839b5ab4533fef414921825e996b210dd53bd"), + hexEncPubkey("cafa6934f82120456620573d7f801390ed5e16ed619613a37e409e44ab355ef755e83565a913b48a9466db786f8d4fbd590bfec474c2524d4a2608d4eafd6abd"), + hexEncPubkey("9d16600d0dd310d77045769fed2cb427f32db88cd57d86e49390c2ba8a9698cfa856f775be2013237226e7bf47b248871cf865d23015937d1edeb20db5e3e760"), + hexEncPubkey("17be6b6ba54199b1d80eff866d348ea11d8a4b341d63ad9a6681d3ef8a43853ac564d153eb2a8737f0afc9ab320f6f95c55aa11aaa13bbb1ff422fd16bdf8188"), }, }, } type preminedTestnet struct { - target NodeID - targetSha common.Hash // sha3(target) - dists [hashBits + 1][]NodeID + target encPubkey + targetSha enode.ID // sha3(target) + dists [hashBits + 1][]encPubkey } -func (tn *preminedTestnet) findnode(toid NodeID, toaddr *net.UDPAddr, target NodeID) ([]*Node, error) { +func (tn *preminedTestnet) self() *enode.Node { + return nullNode +} + +func (tn *preminedTestnet) findnode(toid enode.ID, toaddr *net.UDPAddr, target encPubkey) ([]*node, error) { // current log distance is encoded in port number // fmt.Println("findnode query at dist", toaddr.Port) if toaddr.Port == 0 { panic("query to node at distance 0") } - next := uint16(toaddr.Port) - 1 - var result []*Node - for i, id := range tn.dists[toaddr.Port] { - result = append(result, NewNode(id, net.ParseIP("127.0.0.1"), next, uint16(i))) + next := toaddr.Port - 1 + var result []*node + for i, ekey := range tn.dists[toaddr.Port] { + key, _ := decodePubkey(ekey) + node := wrapNode(enode.NewV4(key, net.ParseIP("127.0.0.1"), i, next)) + result = append(result, node) } return result, nil } -func (*preminedTestnet) close() {} -func (*preminedTestnet) waitping(from NodeID) error { return nil } -func (*preminedTestnet) ping(toid NodeID, toaddr *net.UDPAddr) error { return nil } +func (*preminedTestnet) close() {} +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 (n *preminedTestnet) mine(target NodeID) { - n.target = target - n.targetSha = crypto.Keccak256Hash(n.target[:]) +func (tn *preminedTestnet) mine(target encPubkey) { + tn.target = target + tn.targetSha = tn.target.id() found := 0 for found < bucketSize*10 { k := newkey() - id := PubkeyID(&k.PublicKey) - sha := crypto.Keccak256Hash(id[:]) - ld := logdist(n.targetSha, sha) - if len(n.dists[ld]) < bucketSize { - n.dists[ld] = append(n.dists[ld], id) + key := encodePubkey(&k.PublicKey) + ld := enode.LogDist(tn.targetSha, key.id()) + if len(tn.dists[ld]) < bucketSize { + tn.dists[ld] = append(tn.dists[ld], key) fmt.Println("found ID with ld", ld) found++ } } fmt.Println("&preminedTestnet{") - fmt.Printf(" target: %#v,\n", n.target) - fmt.Printf(" targetSha: %#v,\n", n.targetSha) - fmt.Printf(" dists: [%d][]NodeID{\n", len(n.dists)) - for ld, ns := range n.dists { + fmt.Printf(" target: %#v,\n", tn.target) + fmt.Printf(" targetSha: %#v,\n", tn.targetSha) + fmt.Printf(" dists: [%d][]encPubkey{\n", len(tn.dists)) + for ld, ns := range tn.dists { if len(ns) == 0 { continue } - fmt.Printf(" %d: []NodeID{\n", ld) + fmt.Printf(" %d: []encPubkey{\n", ld) for _, n := range ns { - fmt.Printf(" MustHexID(\"%x\"),\n", n[:]) + fmt.Printf(" hexEncPubkey(\"%x\"),\n", n[:]) } fmt.Println(" },") } @@ -562,40 +660,6 @@ func (n *preminedTestnet) mine(target NodeID) { fmt.Println("}") } -func hasDuplicates(slice []*Node) bool { - seen := make(map[NodeID]bool) - for i, e := range slice { - if e == nil { - panic(fmt.Sprintf("nil *Node at %d", i)) - } - if seen[e.ID] { - return true - } - seen[e.ID] = true - } - return false -} - -func sortedByDistanceTo(distbase common.Hash, slice []*Node) bool { - var last common.Hash - for i, e := range slice { - if i > 0 && distcmp(distbase, e.sha, last) < 0 { - return false - } - last = e.sha - } - return true -} - -func contains(ns []*Node, id NodeID) bool { - for _, n := range ns { - if n.ID == id { - return true - } - } - return false -} - // gen wraps quick.Value so it's easier to use. // it generates a random value of the given value's type. func gen(typ interface{}, rand *rand.Rand) interface{} { @@ -606,6 +670,19 @@ 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, + Rand: rand.New(rand.NewSource(time.Now().Unix())), + } +} + func newkey() *ecdsa.PrivateKey { key, err := crypto.GenerateKey() if err != nil { diff --git a/p2p/discover/table_util_test.go b/p2p/discover/table_util_test.go new file mode 100644 index 0000000000..f4dbc25a37 --- /dev/null +++ b/p2p/discover/table_util_test.go @@ -0,0 +1,168 @@ +// 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 discover + +import ( + "encoding/hex" + "fmt" + "math/rand" + "net" + "sync" + + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/enr" +) + +var nullNode *enode.Node + +func init() { + var r enr.Record + r.Set(enr.IP{0, 0, 0, 0}) + nullNode = enode.SignNull(&r, enode.ID{}) +} + +func newTestTable(t transport) (*Table, *enode.DB) { + db, _ := enode.OpenDB("") + tab, _ := newTable(t, db, nil) + return tab, db +} + +// nodeAtDistance creates a node for which enode.LogDist(base, n.id) == ld. +func nodeAtDistance(base enode.ID, ld int, ip net.IP) *node { + var r enr.Record + r.Set(enr.IP(ip)) + return wrapNode(enode.SignNull(&r, idAtDistance(base, ld))) +} + +// idAtDistance returns a random hash such that enode.LogDist(a, b) == n +func idAtDistance(a enode.ID, n int) (b enode.ID) { + if n == 0 { + return a + } + // flip bit at position n, fill the rest with random bits + b = a + pos := len(a) - n/8 - 1 + bit := byte(0x01) << (byte(n%8) - 1) + if bit == 0 { + pos++ + bit = 0x80 + } + b[pos] = a[pos]&^bit | ^a[pos]&bit // TODO: randomize end bits + for i := pos + 1; i < len(a); i++ { + b[i] = byte(rand.Intn(255)) + } + return b +} + +func intIP(i int) net.IP { + return net.IP{byte(i), 0, 2, byte(i)} +} + +// fillBucket inserts nodes into the given bucket until it is full. +func fillBucket(tab *Table, n *node) (last *node) { + ld := enode.LogDist(tab.self().ID(), n.ID()) + b := tab.bucket(n.ID()) + for len(b.entries) < bucketSize { + b.entries = append(b.entries, nodeAtDistance(tab.self().ID(), ld, intIP(ld))) + } + 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 + n *enode.Node +} + +func newPingRecorder() *pingRecorder { + var r enr.Record + r.Set(enr.IP{0, 0, 0, 0}) + n := enode.SignNull(&r, enode.ID{}) + + return &pingRecorder{ + dead: make(map[enode.ID]bool), + pinged: make(map[enode.ID]bool), + n: n, + } +} + +func (t *pingRecorder) self() *enode.Node { + return nullNode +} + +func (t *pingRecorder) findnode(toid enode.ID, toaddr *net.UDPAddr, target encPubkey) ([]*node, error) { + return nil, nil +} + +func (t *pingRecorder) ping(toid enode.ID, toaddr *net.UDPAddr) error { + t.mu.Lock() + defer t.mu.Unlock() + + t.pinged[toid] = true + if t.dead[toid] { + return errTimeout + } else { + return nil + } +} + +func (t *pingRecorder) close() {} + +func hasDuplicates(slice []*node) bool { + seen := make(map[enode.ID]bool) + for i, e := range slice { + if e == nil { + panic(fmt.Sprintf("nil *Node at %d", i)) + } + if seen[e.ID()] { + return true + } + seen[e.ID()] = true + } + return false +} + +func sortedByDistanceTo(distbase enode.ID, slice []*node) bool { + var last enode.ID + for i, e := range slice { + if i > 0 && enode.DistCmp(distbase, e.ID(), last) < 0 { + return false + } + last = e.ID() + } + return true +} + +func hexEncPubkey(h string) (ret encPubkey) { + b, err := hex.DecodeString(h) + if err != nil { + panic(err) + } + if len(b) != len(ret) { + panic("invalid length") + } + copy(ret[:], b) + return ret +} diff --git a/p2p/discover/udp.go b/p2p/discover/udp.go index 60436952d8..e386af363d 100644 --- a/p2p/discover/udp.go +++ b/p2p/discover/udp.go @@ -23,17 +23,16 @@ import ( "errors" "fmt" "net" + "sync" "time" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/p2p/nat" + "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/netutil" "github.com/ethereum/go-ethereum/rlp" ) -const Version = 4 - // Errors var ( errPacketTooSmall = errors.New("too small") @@ -48,13 +47,18 @@ var ( // Timeouts const ( - respTimeout = 500 * time.Millisecond - sendTimeout = 500 * time.Millisecond - expiration = 20 * time.Second + respTimeout = 500 * time.Millisecond + expiration = 20 * time.Second + bondExpiration = 24 * time.Hour 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 @@ -68,6 +72,8 @@ const ( // RPC request structures type ( ping struct { + senderKey *ecdsa.PublicKey // filled in by preverify + Version uint From, To rpcEndpoint Expiration uint64 @@ -90,7 +96,7 @@ type ( // findnode is a query for nodes close to the given target. findnode struct { - Target NodeID // doesn't need to be an actual public key + Target encPubkey Expiration uint64 // Ignore additional fields (for forward compatibility). Rest []rlp.RawValue `rlp:"tail"` @@ -108,7 +114,7 @@ type ( IP net.IP // len 4 for IPv4 or 16 for IPv6 UDP uint16 // for discovery protocol TCP uint16 // for RLPx protocol - ID NodeID + ID encPubkey } rpcEndpoint struct { @@ -119,14 +125,16 @@ type ( ) func makeEndpoint(addr *net.UDPAddr, tcpPort uint16) rpcEndpoint { - ip := addr.IP.To4() - if ip == nil { - ip = addr.IP.To16() + ip := net.IP{} + if ip4 := addr.IP.To4(); ip4 != nil { + ip = ip4 + } else if ip6 := addr.IP.To16(); ip6 != nil { + ip = ip6 } return rpcEndpoint{IP: ip, UDP: uint16(addr.Port), TCP: tcpPort} } -func (t *udp) nodeFromRPC(sender *net.UDPAddr, rn rpcNode) (*Node, error) { +func (t *udp) nodeFromRPC(sender *net.UDPAddr, rn rpcNode) (*node, error) { if rn.UDP <= 1024 { return nil, errors.New("low port") } @@ -136,17 +144,31 @@ func (t *udp) nodeFromRPC(sender *net.UDPAddr, rn rpcNode) (*Node, error) { if t.netrestrict != nil && !t.netrestrict.Contains(rn.IP) { return nil, errors.New("not contained in netrestrict whitelist") } - n := NewNode(rn.ID, rn.IP, rn.UDP, rn.TCP) - err := n.validateComplete() + key, err := decodePubkey(rn.ID) + if err != nil { + return nil, err + } + n := wrapNode(enode.NewV4(key, rn.IP, int(rn.TCP), int(rn.UDP))) + err = n.ValidateComplete() return n, err } -func nodeToRPC(n *Node) rpcNode { - return rpcNode{ID: n.ID, IP: n.IP, UDP: n.UDP, TCP: n.TCP} +func nodeToRPC(n *node) rpcNode { + var key ecdsa.PublicKey + var ekey encPubkey + if err := n.Load((*enode.Secp256k1)(&key)); err == nil { + ekey = encodePubkey(&key) + } + 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, fromID NodeID, 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 } @@ -157,54 +179,58 @@ type conn interface { LocalAddr() net.Addr } -// udp implements the RPC protocol. +// udp implements the discovery v4 UDP wire protocol. type udp struct { conn conn netrestrict *netutil.Netlist priv *ecdsa.PrivateKey - ourEndpoint rpcEndpoint + localNode *enode.LocalNode + db *enode.DB + tab *Table + wg sync.WaitGroup - addpending chan *pending - gotreply chan reply - - closing chan struct{} - nat nat.Interface - - *Table + 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 NodeID + 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 NodeID + 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 @@ -216,67 +242,116 @@ type ReadPacket struct { Addr *net.UDPAddr } +// Config holds Table-related settings. +type Config struct { + // These settings are required and configure the UDP listener: + PrivateKey *ecdsa.PrivateKey + + // These settings are optional: + NetRestrict *netutil.Netlist // network whitelist + Bootnodes []*enode.Node // list of bootstrap nodes + Unhandled chan<- ReadPacket // unhandled packets are sent on this channel +} + // ListenUDP returns a new table that listens for UDP packets on laddr. -func ListenUDP(priv *ecdsa.PrivateKey, conn conn, realaddr *net.UDPAddr, unhandled chan ReadPacket, nodeDBPath string, netrestrict *netutil.Netlist) (*Table, error) { - tab, _, err := newUDP(priv, conn, realaddr, unhandled, nodeDBPath, netrestrict) +func ListenUDP(c conn, ln *enode.LocalNode, cfg Config) (*Table, error) { + tab, _, err := newUDP(c, ln, cfg) if err != nil { return nil, err } - log.Info("UDP listener up", "self", tab.self) return tab, nil } -func newUDP(priv *ecdsa.PrivateKey, c conn, realaddr *net.UDPAddr, unhandled chan ReadPacket, nodeDBPath string, netrestrict *netutil.Netlist) (*Table, *udp, error) { +func newUDP(c conn, ln *enode.LocalNode, cfg Config) (*Table, *udp, error) { udp := &udp{ - conn: c, - priv: priv, - netrestrict: netrestrict, - 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), } - // TODO: separate TCP port - udp.ourEndpoint = makeEndpoint(realaddr, uint16(realaddr.Port)) - tab, err := newTable(udp, PubkeyID(&priv.PublicKey), realaddr, nodeDBPath) + tab, err := newTable(udp, ln.Database(), cfg.Bootnodes) if err != nil { return nil, nil, err } - udp.Table = tab + udp.tab = tab + udp.wg.Add(2) go udp.loop() - go udp.readLoop(unhandled) - return udp.Table, udp, nil + go udp.readLoop(cfg.Unhandled) + return udp.tab, udp, nil +} + +func (t *udp) self() *enode.Node { + return t.localNode.Node() } func (t *udp) close() { close(t.closing) t.conn.Close() - // TODO: wait for the loops to end. + t.wg.Wait() +} + +func (t *udp) ourEndpoint() rpcEndpoint { + n := t.self() + a := &net.UDPAddr{IP: n.IP(), Port: n.UDP()} + return makeEndpoint(a, uint16(n.TCP())) } // ping sends a ping message to the given node and waits for a reply. -func (t *udp) ping(toid NodeID, toaddr *net.UDPAddr) error { - // TODO: maybe check for ReplyTo field in callback to measure RTT - errc := t.pending(toid, pongPacket, func(interface{}) bool { return true }) - t.send(toaddr, pingPacket, &ping{ - Version: Version, - From: t.ourEndpoint, - To: makeEndpoint(toaddr, 0), // TODO: maybe use known TCP port from DB - Expiration: uint64(time.Now().Add(expiration).Unix()), - }) - return <-errc +func (t *udp) ping(toid enode.ID, toaddr *net.UDPAddr) error { + return <-t.sendPing(toid, toaddr, nil) } -func (t *udp) waitping(from NodeID) error { - return <-t.pending(from, pingPacket, func(interface{}) bool { return true }) +// sendPing sends a ping message to the given node and invokes the callback +// when the reply arrives. +func (t *udp) sendPing(toid enode.ID, toaddr *net.UDPAddr, callback func()) <-chan error { + req := &ping{ + Version: 4, + From: t.ourEndpoint(), + To: makeEndpoint(toaddr, 0), // TODO: maybe use known TCP port from DB + Expiration: uint64(time.Now().Add(expiration).Unix()), + } + packet, hash, err := encodePacket(t.priv, pingPacket, req) + if err != nil { + errc := make(chan error, 1) + errc <- err + return errc + } + // 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 matched, matched + }) + // Send the packet. + t.localNode.UDPContact(toaddr) + t.write(toaddr, toid, req.name(), packet) + return errc } // 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 NodeID, toaddr *net.UDPAddr, target NodeID) ([]*Node, error) { - nodes := make([]*Node, 0, bucketSize) +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, toaddr.IP)) > bondExpiration { + t.ping(toid, toaddr) + // 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++ @@ -287,23 +362,22 @@ func (t *udp) findnode(toid NodeID, toaddr *net.UDPAddr, target NodeID) ([]*Node } 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()), }) - err := <-errc - return nodes, err + 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 NodeID, 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 @@ -311,10 +385,12 @@ func (t *udp) pending(id NodeID, ptype byte, callback func(interface{}) bool) <- return ch } -func (t *udp) handleReply(from NodeID, 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: @@ -325,11 +401,13 @@ func (t *udp) handleReply(from NodeID, ptype byte, req packet) bool { // loop runs in its own goroutine. it keeps track of // the refresh timer and the pending reply queue. func (t *udp) loop() { + defer t.wg.Done() + 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 @@ -342,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 @@ -363,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) } @@ -396,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) @@ -425,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 ) @@ -440,55 +516,58 @@ 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) error { - packet, err := encodePacket(t.priv, ptype, req) +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 err + return hash, err } - _, err = t.conn.WriteToUDP(packet, toaddr) - log.Trace(">> "+req.name(), "addr", toaddr, "err", err) + return hash, t.write(toaddr, toid, req.name(), packet) +} + +func (t *udp) write(toaddr *net.UDPAddr, toid enode.ID, what string, packet []byte) error { + _, err := t.conn.WriteToUDP(packet, toaddr) + log.Trace(">> "+what, "id", toid, "addr", toaddr, "err", err) return err } -func encodePacket(priv *ecdsa.PrivateKey, ptype byte, req interface{}) ([]byte, error) { +func encodePacket(priv *ecdsa.PrivateKey, ptype byte, req interface{}) (packet, hash []byte, err error) { b := new(bytes.Buffer) b.Write(headSpace) b.WriteByte(ptype) if err := rlp.Encode(b, req); err != nil { log.Error("Can't encode discv4 packet", "err", err) - return nil, err + return nil, nil, err } - packet := b.Bytes() + packet = b.Bytes() sig, err := crypto.Sign(crypto.Keccak256(packet[headSize:]), priv) if err != nil { log.Error("Can't sign discv4 packet", "err", err) - return nil, err + return nil, nil, err } copy(packet[macSize:], sig) // add the hash to the front. Note: this doesn't protect the // packet in any way. Our public key will be part of this hash in // The future. - copy(packet, crypto.Keccak256(packet[macSize:])) - return packet, nil + hash = crypto.Keccak256(packet[macSize:]) + copy(packet, hash) + return packet, hash, nil } // readLoop runs in its own goroutine. it handles incoming UDP packets. -func (t *udp) readLoop(unhandled chan ReadPacket) { - defer t.conn.Close() +func (t *udp) readLoop(unhandled chan<- ReadPacket) { + defer t.wg.Done() if unhandled != nil { 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) { @@ -510,29 +589,36 @@ 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 } -func decodePacket(buf []byte) (packet, NodeID, []byte, error) { +func decodePacket(buf []byte) (packet, encPubkey, []byte, error) { if len(buf) < headSize+1 { - return nil, NodeID{}, nil, errPacketTooSmall + return nil, encPubkey{}, nil, errPacketTooSmall } hash, sig, sigdata := buf[:macSize], buf[macSize:headSize], buf[headSize:] shouldhash := crypto.Keccak256(buf[macSize:]) if !bytes.Equal(hash, shouldhash) { - return nil, NodeID{}, nil, errBadHash + return nil, encPubkey{}, nil, errBadHash } - fromID, err := recoverNodeID(crypto.Keccak256(buf[headSize:]), sig) + fromKey, err := recoverNodeKey(crypto.Keccak256(buf[headSize:]), sig) if err != nil { - return nil, NodeID{}, hash, err + return nil, fromKey, hash, err } + var req packet switch ptype := sigdata[0]; ptype { case pingPacket: @@ -544,90 +630,126 @@ func decodePacket(buf []byte) (packet, NodeID, []byte, error) { case neighborsPacket: req = new(neighbors) default: - return nil, fromID, hash, fmt.Errorf("unknown type: %d", ptype) + return nil, fromKey, hash, fmt.Errorf("unknown type: %d", ptype) } s := rlp.NewStream(bytes.NewReader(sigdata[1:]), 0) err = s.Decode(req) - return req, fromID, hash, err + return req, fromKey, hash, err } -func (req *ping) handle(t *udp, from *net.UDPAddr, fromID NodeID, 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 } - t.send(from, pongPacket, &pong{ + key, err := decodePubkey(fromKey) + if err != nil { + return errors.New("invalid public key") + } + 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()), }) - if !t.handleReply(fromID, pingPacket, req) { - // Note: we're ignoring the provided IP address right now - go t.bond(true, fromID, from, req.From.TCP) + + // 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.addVerifiedNode(n) } - return nil + + // 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)}) } func (req *ping) name() string { return "PING/v4" } -func (req *pong) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error { +func (req *pong) preverify(t *udp, from *net.UDPAddr, fromID enode.ID, fromKey encPubkey) error { if expired(req.Expiration) { return errExpired } - if !t.handleReply(fromID, pongPacket, req) { + if !t.handleReply(fromID, from.IP, pongPacket, req) { return errUnsolicitedReply } 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, fromID NodeID, mac []byte) error { +func (req *findnode) preverify(t *udp, from *net.UDPAddr, fromID enode.ID, fromKey encPubkey) error { if expired(req.Expiration) { return errExpired } - if t.db.node(fromID) == nil { - // No bond 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 and UDP - // port of the target as the source address. The recipient of - // the findnode packet would then send a neighbors packet - // (which is a much bigger packet than findnode) to the victim. + 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 + // and UDP port of the target as the source address. The recipient of the findnode + // packet would then send a neighbors packet (which is a much bigger packet than + // findnode) to the victim. return errUnknownNode } - target := crypto.Keccak256Hash(req.Target[:]) - t.mutex.Lock() - closest := t.closest(target, bucketSize).entries - t.mutex.Unlock() - - p := neighbors{Expiration: uint64(time.Now().Add(expiration).Unix())} - // Send neighbors in chunks with at most maxNeighbors per packet - // to stay below the 1280 byte limit. - for i, n := range closest { - if netutil.CheckRelayIP(from.IP, n.IP) != nil { - continue - } - p.Nodes = append(p.Nodes, nodeToRPC(n)) - if len(p.Nodes) == maxNeighbors || i == len(closest)-1 { - t.send(from, neighborsPacket, &p) - p.Nodes = p.Nodes[:0] - } - } 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 + 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, fromID, neighborsPacket, &p) + p.Nodes = p.Nodes[:0] + sent = true + } + } + if len(p.Nodes) > 0 || !sent { + t.send(from, fromID, neighborsPacket, &p) + } +} + func (req *findnode) name() string { return "FINDNODE/v4" } -func (req *neighbors) handle(t *udp, from *net.UDPAddr, fromID NodeID, 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(fromID, 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/p2p/discover/udp_test.go b/p2p/discover/udp_test.go index b81caf8392..3d53c93099 100644 --- a/p2p/discover/udp_test.go +++ b/p2p/discover/udp_test.go @@ -19,6 +19,7 @@ package discover import ( "bytes" "crypto/ecdsa" + crand "crypto/rand" "encoding/binary" "encoding/hex" "errors" @@ -36,6 +37,7 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/rlp" ) @@ -46,7 +48,7 @@ func init() { // shared test variables var ( futureExp = uint64(time.Now().Add(10 * time.Hour).Unix()) - testTarget = NodeID{0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1} + testTarget = encPubkey{0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1} testRemote = rpcEndpoint{IP: net.ParseIP("1.1.1.1").To4(), UDP: 1, TCP: 2} testLocalAnnounced = rpcEndpoint{IP: net.ParseIP("2.2.2.2").To4(), UDP: 3, TCP: 4} testLocal = rpcEndpoint{IP: net.ParseIP("3.3.3.3").To4(), UDP: 5, TCP: 6} @@ -56,6 +58,7 @@ type udpTest struct { t *testing.T pipe *dgramPipe table *Table + db *enode.DB udp *udp sent [][]byte localkey, remotekey *ecdsa.PrivateKey @@ -70,19 +73,32 @@ func newUDPTest(t *testing.T) *udpTest { remotekey: newkey(), remoteaddr: &net.UDPAddr{IP: net.IP{10, 0, 1, 99}, Port: 30303}, } - realaddr := test.pipe.LocalAddr().(*net.UDPAddr) - test.table, test.udp, _ = newUDP(test.localkey, test.pipe, realaddr, nil, "", nil) + 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 @@ -90,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{}) error { +func (test *udpTest) waitPacketOut(validate interface{}) (*net.UDPAddr, []byte, error) { dgram := test.pipe.waitPacketOut() - p, _, _, err := decodePacket(dgram) + p, _, hash, err := decodePacket(dgram.data) if err != nil { - return 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 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 nil + return &dgram.to, hash, nil } func (test *udpTest) errorf(format string, args ...interface{}) error { @@ -121,9 +137,9 @@ 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: Version}) + test.packetIn(errExpired, pingPacket, &ping{From: testRemote, To: testLocalAnnounced, Version: 4}) test.packetIn(errUnsolicitedReply, pongPacket, &pong{ReplyTok: []byte{}, Expiration: futureExp}) test.packetIn(errUnknownNode, findnodePacket, &findnode{Expiration: futureExp}) test.packetIn(errUnsolicitedReply, neighborsPacket, &neighbors{Expiration: futureExp}) @@ -132,10 +148,10 @@ 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 := NodeID{1, 2, 3, 4} + toid := enode.ID{1, 2, 3, 4} if err := test.udp.ping(toid, toaddr); err != errTimeout { t.Error("expected timeout error, got", err) } @@ -144,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 { @@ -162,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) } }) @@ -216,11 +232,11 @@ 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 := NodeID{1, 2, 3, 4} - target := NodeID{4, 5, 6, 7} + toid := enode.ID{1, 2, 3, 4} + target := encPubkey{4, 5, 6, 7} result, err := test.udp.findnode(toid, toaddr, target) if err != errTimeout { t.Error("expected timeout error, got", err) @@ -232,54 +248,70 @@ 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. - targetHash := crypto.Keccak256Hash(testTarget[:]) - nodes := &nodesByDistance{target: targetHash} - for i := 0; i < bucketSize; i++ { - nodes.push(nodeAtDistance(test.table.self.sha, i+2), bucketSize) + nodes := &nodesByDistance{target: testTarget.id()} + live := make(map[enode.ID]bool) + numCandidates := 2 * bucketSize + for i := 0; i < numCandidates; i++ { + key := newkey() + 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. - test.table.db.updateNode(NewNode( - PubkeyID(&test.remotekey.PublicKey), - test.remoteaddr.IP, - uint16(test.remoteaddr.Port), - 99, - )) - // check that closest neighbors are returned. - test.packetIn(nil, findnodePacket, &findnode{Target: testTarget, Expiration: futureExp}) - expected := test.table.closest(targetHash, bucketSize) + remoteID := encodePubkey(&test.remotekey.PublicKey).id() + test.table.db.UpdateLastPongReceived(remoteID, test.remoteaddr.IP, time.Now()) - waitNeighbors := func(want []*Node) { + // check that closest neighbors are returned. + 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 != 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, test.remoteaddr.IP, time.Now()) // queue a pending findnode request - resultc, errc := make(chan []*Node), make(chan error) + resultc, errc := make(chan []*node), make(chan error) go func() { - rid := PubkeyID(&test.remotekey.PublicKey) + rid := encodePubkey(&test.remotekey.PublicKey).id() ns, err := test.udp.findnode(rid, test.remoteaddr, testTarget) if err != nil && len(ns) == 0 { errc <- err @@ -297,11 +329,11 @@ func TestUDP_findnodeMultiReply(t *testing.T) { }) // send the reply as two packets. - list := []*Node{ - MustParseNode("enode://ba85011c70bcc5c04d8607d3a0ed29aa6179c092cbdda10d5d32684fb33ed01bd94f588ca8f91ac48318087dcb02eaf36773a7a453f0eedd6742af668097b29c@10.0.1.16:30303?discport=30304"), - MustParseNode("enode://81fa361d25f157cd421c60dcc28d8dac5ef6a89476633339c5df30287474520caca09627da18543d9079b5b288698b542d56167aa5c09111e55acdbbdf2ef799@10.0.1.16:30303"), - MustParseNode("enode://9bffefd833d53fac8e652415f4973bee289e8b1a5c6c4cbe70abf817ce8a64cee11b823b66a987f51aaa9fba0d6a91b3e6bf0d5a5d1042de8e9eeea057b217f8@10.0.1.36:30301?discport=17"), - MustParseNode("enode://1b5b4aa662d7cb44a7221bfba67302590b643028197a7d5214790f3bac7aaa4a3241be9e83c09cf1f6c69d007c634faae3dc1b1221793e8446c0b3a09de65960@10.0.1.16:30303"), + list := []*node{ + wrapNode(enode.MustParseV4("enode://ba85011c70bcc5c04d8607d3a0ed29aa6179c092cbdda10d5d32684fb33ed01bd94f588ca8f91ac48318087dcb02eaf36773a7a453f0eedd6742af668097b29c@10.0.1.16:30303?discport=30304")), + wrapNode(enode.MustParseV4("enode://81fa361d25f157cd421c60dcc28d8dac5ef6a89476633339c5df30287474520caca09627da18543d9079b5b288698b542d56167aa5c09111e55acdbbdf2ef799@10.0.1.16:30303")), + wrapNode(enode.MustParseV4("enode://9bffefd833d53fac8e652415f4973bee289e8b1a5c6c4cbe70abf817ce8a64cee11b823b66a987f51aaa9fba0d6a91b3e6bf0d5a5d1042de8e9eeea057b217f8@10.0.1.36:30301?discport=17")), + wrapNode(enode.MustParseV4("enode://1b5b4aa662d7cb44a7221bfba67302590b643028197a7d5214790f3bac7aaa4a3241be9e83c09cf1f6c69d007c634faae3dc1b1221793e8446c0b3a09de65960@10.0.1.16:30303")), } rpclist := make([]rpcNode, len(list)) for i := range list { @@ -324,14 +356,43 @@ 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() + added := make(chan *node, 1) + test.table.nodeAddedHook = func(n *node) { added <- n } + 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: Version, Expiration: futureExp}) + go test.packetIn(nil, pingPacket, &ping{From: testRemote, To: testLocalAnnounced, Version: 4, Expiration: futureExp}) // the ping is replied to. test.waitPacketOut(func(p *pong) { @@ -351,13 +412,14 @@ func TestUDP_successfulPing(t *testing.T) { }) // remote is unknown, the table pings back. - 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) + _, 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()) } wantTo := rpcEndpoint{ // The mirrored UDP address is the UDP packet sender. - IP: test.remoteaddr.IP, UDP: uint16(test.remoteaddr.Port), + IP: test.remoteaddr.IP, + UDP: uint16(test.remoteaddr.Port), TCP: 0, } if !reflect.DeepEqual(p.To, wantTo) { @@ -365,24 +427,24 @@ func TestUDP_successfulPing(t *testing.T) { } return nil }) - test.packetIn(nil, pongPacket, &pong{Expiration: futureExp}) + test.packetIn(nil, pongPacket, &pong{ReplyTok: hash, Expiration: futureExp}) // the node should be added to the table shortly after getting the // pong packet. select { case n := <-added: - rid := PubkeyID(&test.remotekey.PublicKey) - if n.ID != rid { - t.Errorf("node has wrong ID: got %v, want %v", n.ID, rid) + rid := encodePubkey(&test.remotekey.PublicKey).id() + if n.ID() != rid { + t.Errorf("node has wrong ID: got %v, want %v", n.ID(), rid) } - if !n.IP.Equal(test.remoteaddr.IP) { - t.Errorf("node has wrong IP: got %v, want: %v", n.IP, test.remoteaddr.IP) + if !n.IP().Equal(test.remoteaddr.IP) { + t.Errorf("node has wrong IP: got %v, want: %v", n.IP(), test.remoteaddr.IP) } - if int(n.UDP) != test.remoteaddr.Port { - t.Errorf("node has wrong UDP port: got %v, want: %v", n.UDP, test.remoteaddr.Port) + if int(n.UDP()) != test.remoteaddr.Port { + t.Errorf("node has wrong UDP port: got %v, want: %v", n.UDP(), test.remoteaddr.Port) } - if n.TCP != testRemote.TCP { - t.Errorf("node has wrong TCP port: got %v, want: %v", n.TCP, testRemote.TCP) + if n.TCP() != int(testRemote.TCP) { + t.Errorf("node has wrong TCP port: got %v, want: %v", n.TCP(), testRemote.TCP) } case <-time.After(2 * time.Second): t.Errorf("node was not added within 2 seconds") @@ -435,7 +497,7 @@ var testPackets = []struct { { input: "c7c44041b9f7c7e41934417ebac9a8e1a4c6298f74553f2fcfdcae6ed6fe53163eb3d2b52e39fe91831b8a927bf4fc222c3902202027e5e9eb812195f95d20061ef5cd31d502e47ecb61183f74a504fe04c51e73df81f25c4d506b26db4517490103f84eb840ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd31387574077f301b421bc84df7266c44e9e6d569fc56be00812904767bf5ccd1fc7f8443b9a35582999983999999280dc62cc8255c73471e0a61da0c89acdc0e035e260add7fc0c04ad9ebf3919644c91cb247affc82b69bd2ca235c71eab8e49737c937a2c396", wantPacket: &findnode{ - Target: MustHexID("ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd31387574077f301b421bc84df7266c44e9e6d569fc56be00812904767bf5ccd1fc7f"), + Target: hexEncPubkey("ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd31387574077f301b421bc84df7266c44e9e6d569fc56be00812904767bf5ccd1fc7f"), Expiration: 1136239445, Rest: []rlp.RawValue{{0x82, 0x99, 0x99}, {0x83, 0x99, 0x99, 0x99}}, }, @@ -445,25 +507,25 @@ var testPackets = []struct { wantPacket: &neighbors{ Nodes: []rpcNode{ { - ID: MustHexID("3155e1427f85f10a5c9a7755877748041af1bcd8d474ec065eb33df57a97babf54bfd2103575fa829115d224c523596b401065a97f74010610fce76382c0bf32"), + ID: hexEncPubkey("3155e1427f85f10a5c9a7755877748041af1bcd8d474ec065eb33df57a97babf54bfd2103575fa829115d224c523596b401065a97f74010610fce76382c0bf32"), IP: net.ParseIP("99.33.22.55").To4(), UDP: 4444, TCP: 4445, }, { - ID: MustHexID("312c55512422cf9b8a4097e9a6ad79402e87a15ae909a4bfefa22398f03d20951933beea1e4dfa6f968212385e829f04c2d314fc2d4e255e0d3bc08792b069db"), + ID: hexEncPubkey("312c55512422cf9b8a4097e9a6ad79402e87a15ae909a4bfefa22398f03d20951933beea1e4dfa6f968212385e829f04c2d314fc2d4e255e0d3bc08792b069db"), IP: net.ParseIP("1.2.3.4").To4(), UDP: 1, TCP: 1, }, { - ID: MustHexID("38643200b172dcfef857492156971f0e6aa2c538d8b74010f8e140811d53b98c765dd2d96126051913f44582e8c199ad7c6d6819e9a56483f637feaac9448aac"), + ID: hexEncPubkey("38643200b172dcfef857492156971f0e6aa2c538d8b74010f8e140811d53b98c765dd2d96126051913f44582e8c199ad7c6d6819e9a56483f637feaac9448aac"), IP: net.ParseIP("2001:db8:3c4d:15::abcd:ef12"), UDP: 3333, TCP: 3333, }, { - ID: MustHexID("8dcab8618c3253b558d459da53bd8fa68935a719aff8b811197101a4b2b47dd2d47295286fc00cc081bb542d760717d1bdd6bec2c37cd72eca367d6dd3b9df73"), + ID: hexEncPubkey("8dcab8618c3253b558d459da53bd8fa68935a719aff8b811197101a4b2b47dd2d47295286fc00cc081bb542d760717d1bdd6bec2c37cd72eca367d6dd3b9df73"), IP: net.ParseIP("2001:db8:85a3:8d3:1319:8a2e:370:7348"), UDP: 999, TCP: 1000, @@ -477,14 +539,14 @@ var testPackets = []struct { func TestForwardCompatibility(t *testing.T) { testkey, _ := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - wantNodeID := PubkeyID(&testkey.PublicKey) + wantNodeKey := encodePubkey(&testkey.PublicKey) for _, test := range testPackets { input, err := hex.DecodeString(test.input) if err != nil { t.Fatalf("invalid hex: %s", test.input) } - packet, nodeid, _, err := decodePacket(input) + packet, nodekey, _, err := decodePacket(input) if err != nil { t.Errorf("did not accept packet %s\n%v", test.input, err) continue @@ -492,8 +554,8 @@ func TestForwardCompatibility(t *testing.T) { if !reflect.DeepEqual(packet, test.wantPacket) { t.Errorf("got %s\nwant %s", spew.Sdump(packet), spew.Sdump(test.wantPacket)) } - if nodeid != wantNodeID { - t.Errorf("got id %v\nwant id %v", nodeid, wantNodeID) + if nodekey != wantNodeKey { + t.Errorf("got id %v\nwant id %v", nodekey, wantNodeKey) } } } @@ -504,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 { @@ -525,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 } @@ -550,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/p2p/discv5/database_test.go b/p2p/discv5/database_test.go index a2ccb64671..2b86dc9cec 100644 --- a/p2p/discv5/database_test.go +++ b/p2p/discv5/database_test.go @@ -173,7 +173,7 @@ var nodeDBSeedQueryNodes = []struct { ), pong: time.Now().Add(-3 * time.Hour), }, - // This one shouldn't be in in the result set because its + // This one shouldn't be in the result set because its // nodeID is the local node's ID. { node: NewNode( diff --git a/p2p/discv5/metrics.go b/p2p/discv5/metrics.go new file mode 100644 index 0000000000..cb11d7eacf --- /dev/null +++ b/p2p/discv5/metrics.go @@ -0,0 +1,8 @@ +package discv5 + +import "github.com/ethereum/go-ethereum/metrics" + +var ( + ingressTrafficMeter = metrics.NewRegisteredMeter("discv5/InboundTraffic", nil) + egressTrafficMeter = metrics.NewRegisteredMeter("discv5/OutboundTraffic", nil) +) diff --git a/p2p/discv5/net.go b/p2p/discv5/net.go index f9baf126f1..de7d8de6aa 100644 --- a/p2p/discv5/net.go +++ b/p2p/discv5/net.go @@ -27,16 +27,15 @@ 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 ( errInvalidEvent = errors.New("invalid in current state") errNoQuery = errors.New("no pending query") - errWrongAddress = errors.New("unknown sender address") ) const ( @@ -565,18 +564,14 @@ loop: if lookupChn := searchInfo[res.target.topic].lookupChn; lookupChn != nil { lookupChn <- net.ticketStore.radius[res.target.topic].converged } - net.ticketStore.searchLookupDone(res.target, res.nodes, func(n *Node) []byte { - net.ping(n, n.addr()) - return n.pingEcho - }, func(n *Node, topic Topic) []byte { - if n.state == known { + 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: @@ -633,15 +628,20 @@ loop: } net.refreshResp <- refreshDone case <-refreshDone: - log.Trace("<-net.refreshDone") - refreshDone = nil - list := searchReqWhenRefreshDone - searchReqWhenRefreshDone = nil - go func() { - for _, req := range list { - net.topicSearchReq <- req - } - }() + log.Trace("<-net.refreshDone", "table size", net.tab.count) + if net.tab.count != 0 { + refreshDone = nil + list := searchReqWhenRefreshDone + searchReqWhenRefreshDone = nil + go func() { + for _, req := range list { + net.topicSearchReq <- req + } + }() + } else { + refreshDone = make(chan struct{}) + net.refresh(refreshDone) + } } } log.Trace("loop stopped") @@ -677,7 +677,7 @@ func (net *Network) refresh(done chan<- struct{}) { } if len(seeds) == 0 { log.Trace("no seed nodes found") - close(done) + time.AfterFunc(time.Second*10, func() { close(done) }) return } for _, n := range seeds { @@ -751,7 +751,15 @@ func (net *Network) internNodeFromNeighbours(sender *net.UDPAddr, rn rpcNode) (n return n, err } if !n.IP.Equal(rn.IP) || n.UDP != rn.UDP || n.TCP != rn.TCP { - err = fmt.Errorf("metadata mismatch: got %v, want %v", rn, n) + if n.state == known { + // reject address change if node is known by us + err = fmt.Errorf("metadata mismatch: got %v, want %v", rn, n) + } else { + // accept otherwise; this will be handled nicer with signed ENRs + n.IP = rn.IP + n.UDP = rn.UDP + n.TCP = rn.TCP + } } return n, err } @@ -792,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 } @@ -818,11 +826,10 @@ type nodeEvent uint //go:generate stringer -type=nodeEvent const ( - invalidEvent nodeEvent = iota // zero is reserved // Packet type events. // These correspond to packet types in the UDP protocol. - pingPacket + pingPacket = iota + 1 pongPacket findnodePacket neighborsPacket @@ -1220,14 +1227,14 @@ func (net *Network) checkTopicRegister(data *topicRegister) (*pong, error) { if rlpHash(data.Topics) != pongpkt.data.(*pong).TopicHash { return nil, errors.New("topic hash mismatch") } - if data.Idx < 0 || int(data.Idx) >= len(data.Topics) { + if data.Idx >= uint(len(data.Topics)) { return nil, errors.New("topic index out of range") } return pongpkt.data.(*pong), nil } 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/p2p/discv5/net_test.go b/p2p/discv5/net_test.go index 369282ca9c..1a8137673d 100644 --- a/p2p/discv5/net_test.go +++ b/p2p/discv5/net_test.go @@ -336,26 +336,26 @@ func (*preminedTestnet) localAddr() *net.UDPAddr { // mine generates a testnet struct literal with nodes at // various distances to the given target. -func (n *preminedTestnet) mine(target NodeID) { - n.target = target - n.targetSha = crypto.Keccak256Hash(n.target[:]) +func (tn *preminedTestnet) mine(target NodeID) { + tn.target = target + tn.targetSha = crypto.Keccak256Hash(tn.target[:]) found := 0 for found < bucketSize*10 { k := newkey() id := PubkeyID(&k.PublicKey) sha := crypto.Keccak256Hash(id[:]) - ld := logdist(n.targetSha, sha) - if len(n.dists[ld]) < bucketSize { - n.dists[ld] = append(n.dists[ld], id) + ld := logdist(tn.targetSha, sha) + if len(tn.dists[ld]) < bucketSize { + tn.dists[ld] = append(tn.dists[ld], id) fmt.Println("found ID with ld", ld) found++ } } fmt.Println("&preminedTestnet{") - fmt.Printf(" target: %#v,\n", n.target) - fmt.Printf(" targetSha: %#v,\n", n.targetSha) - fmt.Printf(" dists: [%d][]NodeID{\n", len(n.dists)) - for ld, ns := range n.dists { + fmt.Printf(" target: %#v,\n", tn.target) + fmt.Printf(" targetSha: %#v,\n", tn.targetSha) + fmt.Printf(" dists: [%d][]NodeID{\n", len(tn.dists)) + for ld, ns := range &tn.dists { if len(ns) == 0 { continue } diff --git a/p2p/discv5/node.go b/p2p/discv5/node.go index fd88a55b15..3d47485122 100644 --- a/p2p/discv5/node.go +++ b/p2p/discv5/node.go @@ -315,11 +315,11 @@ func PubkeyID(pub *ecdsa.PublicKey) NodeID { // Pubkey returns the public key represented by the node ID. // It returns an error if the ID is not a point on the curve. -func (id NodeID) Pubkey() (*ecdsa.PublicKey, error) { +func (n NodeID) Pubkey() (*ecdsa.PublicKey, error) { p := &ecdsa.PublicKey{Curve: crypto.S256(), X: new(big.Int), Y: new(big.Int)} - half := len(id) / 2 - p.X.SetBytes(id[:half]) - p.Y.SetBytes(id[half:]) + half := len(n) / 2 + p.X.SetBytes(n[:half]) + p.Y.SetBytes(n[half:]) if !p.Curve.IsOnCurve(p.X, p.Y) { return nil, errors.New("id is invalid secp256k1 curve point") } diff --git a/p2p/discv5/nodeevent_string.go b/p2p/discv5/nodeevent_string.go index eb696fb8be..38c1993bac 100644 --- a/p2p/discv5/nodeevent_string.go +++ b/p2p/discv5/nodeevent_string.go @@ -4,24 +4,14 @@ package discv5 import "strconv" -const ( - _nodeEvent_name_0 = "invalidEventpingPacketpongPacketfindnodePacketneighborsPacketfindnodeHashPackettopicRegisterPackettopicQueryPackettopicNodesPacket" - _nodeEvent_name_1 = "pongTimeoutpingTimeoutneighboursTimeout" -) +const _nodeEvent_name = "pongTimeoutpingTimeoutneighboursTimeout" -var ( - _nodeEvent_index_0 = [...]uint8{0, 12, 22, 32, 46, 61, 79, 98, 114, 130} - _nodeEvent_index_1 = [...]uint8{0, 11, 22, 39} -) +var _nodeEvent_index = [...]uint8{0, 11, 22, 39} func (i nodeEvent) String() string { - switch { - case 0 <= i && i <= 8: - return _nodeEvent_name_0[_nodeEvent_index_0[i]:_nodeEvent_index_0[i+1]] - case 265 <= i && i <= 267: - i -= 265 - return _nodeEvent_name_1[_nodeEvent_index_1[i]:_nodeEvent_index_1[i+1]] - default: - return "nodeEvent(" + strconv.FormatInt(int64(i), 10) + ")" + i -= 264 + if i >= nodeEvent(len(_nodeEvent_index)-1) { + return "nodeEvent(" + strconv.FormatInt(int64(i+264), 10) + ")" } + return _nodeEvent_name[_nodeEvent_index[i]:_nodeEvent_index[i+1]] } diff --git a/p2p/discv5/table.go b/p2p/discv5/table.go index 2cf05009cb..4f4b2426f4 100644 --- a/p2p/discv5/table.go +++ b/p2p/discv5/table.go @@ -38,7 +38,6 @@ const ( hashBits = len(common.Hash{}) * 8 nBuckets = hashBits + 1 // Number of buckets - maxBondingPingPongs = 16 maxFindnodeFailures = 5 ) @@ -82,7 +81,7 @@ func (tab *Table) chooseBucketRefreshTarget() common.Hash { if printTable { fmt.Println() } - for i, b := range tab.buckets { + for i, b := range &tab.buckets { entries += len(b.entries) if printTable { for _, e := range b.entries { @@ -94,7 +93,7 @@ func (tab *Table) chooseBucketRefreshTarget() common.Hash { prefix := binary.BigEndian.Uint64(tab.self.sha[0:8]) dist := ^uint64(0) entry := int(randUint(uint32(entries + 1))) - for _, b := range tab.buckets { + for _, b := range &tab.buckets { if entry < len(b.entries) { n := b.entries[entry] dist = binary.BigEndian.Uint64(n.sha[0:8]) ^ prefix @@ -122,9 +121,9 @@ func (tab *Table) readRandomNodes(buf []*Node) (n int) { // TODO: tree-based buckets would help here // Find all non-empty buckets and get a fresh slice of their entries. var buckets [][]*Node - for _, b := range tab.buckets { + for _, b := range &tab.buckets { if len(b.entries) > 0 { - buckets = append(buckets, b.entries[:]) + buckets = append(buckets, b.entries) } } if len(buckets) == 0 { @@ -176,7 +175,7 @@ func (tab *Table) closest(target common.Hash, nresults int) *nodesByDistance { // obviously correct. I believe that tree-based buckets would make // this easier to implement efficiently. close := &nodesByDistance{target: target} - for _, b := range tab.buckets { + for _, b := range &tab.buckets { for _, n := range b.entries { close.push(n, nresults) } diff --git a/p2p/discv5/ticket.go b/p2p/discv5/ticket.go index 37ce8d23cb..ae4b18e7cd 100644 --- a/p2p/discv5/ticket.go +++ b/p2p/discv5/ticket.go @@ -304,8 +304,8 @@ func (s ticketRefByWaitTime) Len() int { return len(s) } -func (r ticketRef) waitTime() mclock.AbsTime { - return r.t.regTime[r.idx] - r.t.issueTime +func (ref ticketRef) waitTime() mclock.AbsTime { + return ref.t.regTime[ref.idx] - ref.t.issueTime } // Less reports whether the element with @@ -494,13 +494,13 @@ func (s *ticketStore) registerLookupDone(lookup lookupInfo, nodes []*Node, ping } } -func (s *ticketStore) searchLookupDone(lookup lookupInfo, nodes []*Node, ping func(n *Node) []byte, query func(n *Node, topic Topic) []byte) { +func (s *ticketStore) searchLookupDone(lookup lookupInfo, nodes []*Node, query func(n *Node, topic Topic) []byte) { now := mclock.Now() for i, n := range nodes { if i == 0 || (binary.BigEndian.Uint64(n.sha[:8])^binary.BigEndian.Uint64(lookup.target[:8])) < s.radius[lookup.topic].minRadius { if lookup.radiusLookup { if lastReq, ok := s.nodeLastReq[n]; !ok || time.Duration(now-lastReq.time) > radiusTC { - s.nodeLastReq[n] = reqInfo{pingHash: ping(n), lookup: lookup, time: now} + s.nodeLastReq[n] = reqInfo{pingHash: nil, lookup: lookup, time: now} } } // else { if s.canQueryTopic(n, lookup.topic) { diff --git a/p2p/discv5/topic.go b/p2p/discv5/topic.go index e7a7f8e02a..609a41297f 100644 --- a/p2p/discv5/topic.go +++ b/p2p/discv5/topic.go @@ -271,15 +271,15 @@ func (t *topicTable) useTicket(node *Node, serialNo uint32, topics []Topic, idx return false } -func (topictab *topicTable) getTicket(node *Node, topics []Topic) *ticket { - topictab.collectGarbage() +func (t *topicTable) getTicket(node *Node, topics []Topic) *ticket { + t.collectGarbage() now := mclock.Now() - n := topictab.getOrNewNode(node) + n := t.getOrNewNode(node) n.lastIssuedTicket++ - topictab.storeTicketCounters(node) + t.storeTicketCounters(node) - t := &ticket{ + tic := &ticket{ issueTime: now, topics: topics, serial: n.lastIssuedTicket, @@ -287,15 +287,15 @@ func (topictab *topicTable) getTicket(node *Node, topics []Topic) *ticket { } for i, topic := range topics { var waitPeriod time.Duration - if topic := topictab.topics[topic]; topic != nil { + if topic := t.topics[topic]; topic != nil { waitPeriod = topic.wcl.waitPeriod } else { waitPeriod = minWaitPeriod } - t.regTime[i] = now + mclock.AbsTime(waitPeriod) + tic.regTime[i] = now + mclock.AbsTime(waitPeriod) } - return t + return tic } const gcInterval = time.Minute diff --git a/p2p/discv5/udp.go b/p2p/discv5/udp.go index 5437718173..ff5ed983ba 100644 --- a/p2p/discv5/udp.go +++ b/p2p/discv5/udp.go @@ -36,25 +36,17 @@ const Version = 4 // Errors var ( - errPacketTooSmall = errors.New("too small") - errBadPrefix = errors.New("bad prefix") - errExpired = errors.New("expired") - errUnsolicitedReply = errors.New("unsolicited reply") - errUnknownNode = errors.New("unknown node") - errTimeout = errors.New("RPC timeout") - errClockWarp = errors.New("reply deadline too far in the future") - errClosed = errors.New("socket closed") + errPacketTooSmall = errors.New("too small") + errBadPrefix = errors.New("bad prefix") + errTimeout = errors.New("RPC timeout") ) // Timeouts const ( respTimeout = 500 * time.Millisecond - sendTimeout = 500 * time.Millisecond expiration = 20 * time.Second - 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 + driftThreshold = 10 * time.Second // Allowed clock drift before warning user ) // RPC request structures @@ -238,7 +230,8 @@ type udp struct { } // ListenUDP returns a new table that listens for UDP packets on laddr. -func ListenUDP(priv *ecdsa.PrivateKey, conn conn, realaddr *net.UDPAddr, nodeDBPath string, netrestrict *netutil.Netlist) (*Network, error) { +func ListenUDP(priv *ecdsa.PrivateKey, conn conn, nodeDBPath string, netrestrict *netutil.Netlist) (*Network, error) { + realaddr := conn.LocalAddr().(*net.UDPAddr) transport, err := listenUDP(priv, conn, realaddr) if err != nil { return nil, err @@ -318,20 +311,20 @@ func (t *udp) sendTopicRegister(remote *Node, topics []Topic, idx int, pong []by func (t *udp) sendTopicNodes(remote *Node, queryHash common.Hash, nodes []*Node) { p := topicNodes{Echo: queryHash} - if len(nodes) == 0 { - t.sendPacket(remote.ID, remote.addr(), byte(topicNodesPacket), p) - return - } - for i, result := range nodes { - if netutil.CheckRelayIP(remote.IP, result.IP) != nil { - continue + var sent bool + for _, result := range nodes { + if result.IP.Equal(t.net.tab.self.IP) || netutil.CheckRelayIP(remote.IP, result.IP) == nil { + p.Nodes = append(p.Nodes, nodeToRPC(result)) } - p.Nodes = append(p.Nodes, nodeToRPC(result)) - if len(p.Nodes) == maxTopicNodes || i == len(nodes)-1 { + if len(p.Nodes) == maxTopicNodes { t.sendPacket(remote.ID, remote.addr(), byte(topicNodesPacket), p) p.Nodes = p.Nodes[:0] + sent = true } } + if !sent || len(p.Nodes) > 0 { + t.sendPacket(remote.ID, remote.addr(), byte(topicNodesPacket), p) + } } func (t *udp) sendPacket(toid NodeID, toaddr *net.UDPAddr, ptype byte, req interface{}) (hash []byte, err error) { @@ -342,8 +335,10 @@ func (t *udp) sendPacket(toid NodeID, toaddr *net.UDPAddr, ptype byte, req inter return hash, err } log.Trace(fmt.Sprintf(">>> %v to %x@%v", nodeEvent(ptype), toid[:8], toaddr)) - if _, err = t.conn.WriteToUDP(packet, toaddr); err != nil { + if nbytes, err := t.conn.WriteToUDP(packet, toaddr); err != nil { log.Trace(fmt.Sprint("UDP send failed:", err)) + } else { + egressTrafficMeter.Mark(int64(nbytes)) } //fmt.Println(err) return hash, err @@ -382,6 +377,7 @@ func (t *udp) readLoop() { buf := make([]byte, 1280) for { nbytes, from, err := t.conn.ReadFromUDP(buf) + ingressTrafficMeter.Mark(int64(nbytes)) if netutil.IsTemporaryError(err) { // Ignore temporary read errors. log.Debug(fmt.Sprintf("Temporary read error: %v", err)) diff --git a/p2p/discv5/udp_test.go b/p2p/discv5/udp_test.go index 7d31815947..62184aa9d3 100644 --- a/p2p/discv5/udp_test.go +++ b/p2p/discv5/udp_test.go @@ -24,7 +24,6 @@ import ( "reflect" "sync" "testing" - "time" "github.com/davecgh/go-spew/spew" "github.com/ethereum/go-ethereum/common" @@ -38,11 +37,7 @@ func init() { // shared test variables var ( - futureExp = uint64(time.Now().Add(10 * time.Hour).Unix()) - testTarget = NodeID{0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1} - testRemote = rpcEndpoint{IP: net.ParseIP("1.1.1.1").To4(), UDP: 1, TCP: 2} - testLocalAnnounced = rpcEndpoint{IP: net.ParseIP("2.2.2.2").To4(), UDP: 3, TCP: 4} - testLocal = rpcEndpoint{IP: net.ParseIP("3.3.3.3").To4(), UDP: 5, TCP: 6} + testLocal = rpcEndpoint{IP: net.ParseIP("3.3.3.3").To4(), UDP: 5, TCP: 6} ) // type udpTest struct { diff --git a/p2p/enode/idscheme.go b/p2p/enode/idscheme.go new file mode 100644 index 0000000000..c1834f0699 --- /dev/null +++ b/p2p/enode/idscheme.go @@ -0,0 +1,160 @@ +// 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 enode + +import ( + "crypto/ecdsa" + "fmt" + "io" + + "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/p2p/enr" + "github.com/ethereum/go-ethereum/rlp" + "golang.org/x/crypto/sha3" +) + +// List of known secure identity schemes. +var ValidSchemes = enr.SchemeMap{ + "v4": V4ID{}, +} + +var ValidSchemesForTesting = enr.SchemeMap{ + "v4": V4ID{}, + "null": NullID{}, +} + +// v4ID is the "v4" identity scheme. +type V4ID struct{} + +// SignV4 signs a record using the v4 scheme. +func SignV4(r *enr.Record, privkey *ecdsa.PrivateKey) error { + // Copy r to avoid modifying it if signing fails. + cpy := *r + cpy.Set(enr.ID("v4")) + cpy.Set(Secp256k1(privkey.PublicKey)) + + h := sha3.NewLegacyKeccak256() + rlp.Encode(h, cpy.AppendElements(nil)) + sig, err := crypto.Sign(h.Sum(nil), privkey) + if err != nil { + return err + } + sig = sig[:len(sig)-1] // remove v + if err = cpy.SetSig(V4ID{}, sig); err == nil { + *r = cpy + } + return err +} + +func (V4ID) Verify(r *enr.Record, sig []byte) error { + var entry s256raw + if err := r.Load(&entry); err != nil { + return err + } else if len(entry) != 33 { + return fmt.Errorf("invalid public key") + } + + h := sha3.NewLegacyKeccak256() + rlp.Encode(h, r.AppendElements(nil)) + if !crypto.VerifySignature(entry, h.Sum(nil), sig) { + return enr.ErrInvalidSig + } + return nil +} + +func (V4ID) NodeAddr(r *enr.Record) []byte { + var pubkey Secp256k1 + err := r.Load(&pubkey) + if err != nil { + return nil + } + buf := make([]byte, 64) + math.ReadBits(pubkey.X, buf[:32]) + math.ReadBits(pubkey.Y, buf[32:]) + return crypto.Keccak256(buf) +} + +// Secp256k1 is the "secp256k1" key, which holds a public key. +type Secp256k1 ecdsa.PublicKey + +func (v Secp256k1) ENRKey() string { return "secp256k1" } + +// EncodeRLP implements rlp.Encoder. +func (v Secp256k1) EncodeRLP(w io.Writer) error { + return rlp.Encode(w, crypto.CompressPubkey((*ecdsa.PublicKey)(&v))) +} + +// DecodeRLP implements rlp.Decoder. +func (v *Secp256k1) DecodeRLP(s *rlp.Stream) error { + buf, err := s.Bytes() + if err != nil { + return err + } + pk, err := crypto.DecompressPubkey(buf) + if err != nil { + return err + } + *v = (Secp256k1)(*pk) + return nil +} + +// s256raw is an unparsed secp256k1 public key entry. +type s256raw []byte + +func (s256raw) ENRKey() string { return "secp256k1" } + +// v4CompatID is a weaker and insecure version of the "v4" scheme which only checks for the +// presence of a secp256k1 public key, but doesn't verify the signature. +type v4CompatID struct { + V4ID +} + +func (v4CompatID) Verify(r *enr.Record, sig []byte) error { + var pubkey Secp256k1 + return r.Load(&pubkey) +} + +func signV4Compat(r *enr.Record, pubkey *ecdsa.PublicKey) { + r.Set((*Secp256k1)(pubkey)) + if err := r.SetSig(v4CompatID{}, []byte{}); err != nil { + panic(err) + } +} + +// NullID is the "null" ENR identity scheme. This scheme stores the node +// ID in the record without any signature. +type NullID struct{} + +func (NullID) Verify(r *enr.Record, sig []byte) error { + return nil +} + +func (NullID) NodeAddr(r *enr.Record) []byte { + var id ID + r.Load(enr.WithEntry("nulladdr", &id)) + return id[:] +} + +func SignNull(r *enr.Record, id ID) *Node { + r.Set(enr.ID("null")) + r.Set(enr.WithEntry("nulladdr", id)) + if err := r.SetSig(NullID{}, []byte{}); err != nil { + panic(err) + } + return &Node{r: *r, id: id} +} diff --git a/p2p/enode/idscheme_test.go b/p2p/enode/idscheme_test.go new file mode 100644 index 0000000000..0910e6e83f --- /dev/null +++ b/p2p/enode/idscheme_test.go @@ -0,0 +1,74 @@ +// 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 enode + +import ( + "bytes" + "crypto/ecdsa" + "encoding/hex" + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/p2p/enr" + "github.com/ethereum/go-ethereum/rlp" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var ( + privkey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + pubkey = &privkey.PublicKey +) + +func TestEmptyNodeID(t *testing.T) { + var r enr.Record + if addr := ValidSchemes.NodeAddr(&r); addr != nil { + t.Errorf("wrong address on empty record: got %v, want %v", addr, nil) + } + + require.NoError(t, SignV4(&r, privkey)) + expected := "a448f24c6d18e575453db13171562b71999873db5b286df957af199ec94617f7" + assert.Equal(t, expected, hex.EncodeToString(ValidSchemes.NodeAddr(&r))) +} + +// Checks that failure to sign leaves the record unmodified. +func TestSignError(t *testing.T) { + invalidKey := &ecdsa.PrivateKey{D: new(big.Int), PublicKey: *pubkey} + + var r enr.Record + emptyEnc, _ := rlp.EncodeToBytes(&r) + if err := SignV4(&r, invalidKey); err == nil { + t.Fatal("expected error from SignV4") + } + newEnc, _ := rlp.EncodeToBytes(&r) + if !bytes.Equal(newEnc, emptyEnc) { + t.Fatal("record modified even though signing failed") + } +} + +// TestGetSetSecp256k1 tests encoding/decoding and setting/getting of the Secp256k1 key. +func TestGetSetSecp256k1(t *testing.T) { + var r enr.Record + if err := SignV4(&r, privkey); err != nil { + t.Fatal(err) + } + + var pk Secp256k1 + require.NoError(t, r.Load(&pk)) + assert.EqualValues(t, pubkey, &pk) +} diff --git a/p2p/enode/localnode.go b/p2p/enode/localnode.go new file mode 100644 index 0000000000..623f8eae18 --- /dev/null +++ b/p2p/enode/localnode.go @@ -0,0 +1,246 @@ +// 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 enode + +import ( + "crypto/ecdsa" + "fmt" + "net" + "reflect" + "strconv" + "sync" + "sync/atomic" + "time" + + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/p2p/enr" + "github.com/ethereum/go-ethereum/p2p/netutil" +) + +const ( + // IP tracker configuration + iptrackMinStatements = 10 + iptrackWindow = 5 * time.Minute + iptrackContactWindow = 10 * time.Minute +) + +// LocalNode produces the signed node record of a local node, i.e. a node run in the +// current process. Setting ENR entries via the Set method updates the record. A new version +// of the record is signed on demand when the Node method is called. +type LocalNode struct { + cur atomic.Value // holds a non-nil node pointer while the record is up-to-date. + id ID + key *ecdsa.PrivateKey + db *DB + + // everything below is protected by a lock + mu sync.Mutex + seq uint64 + entries map[string]enr.Entry + udpTrack *netutil.IPTracker // predicts external UDP endpoint + staticIP net.IP + fallbackIP net.IP + fallbackUDP int +} + +// NewLocalNode creates a local node. +func NewLocalNode(db *DB, key *ecdsa.PrivateKey) *LocalNode { + ln := &LocalNode{ + id: PubkeyToIDV4(&key.PublicKey), + db: db, + key: key, + udpTrack: netutil.NewIPTracker(iptrackWindow, iptrackContactWindow, iptrackMinStatements), + entries: make(map[string]enr.Entry), + } + ln.seq = db.localSeq(ln.id) + ln.invalidate() + return ln +} + +// Database returns the node database associated with the local node. +func (ln *LocalNode) Database() *DB { + return ln.db +} + +// Node returns the current version of the local node record. +func (ln *LocalNode) Node() *Node { + n := ln.cur.Load().(*Node) + if n != nil { + return n + } + // Record was invalidated, sign a new copy. + ln.mu.Lock() + defer ln.mu.Unlock() + ln.sign() + return ln.cur.Load().(*Node) +} + +// ID returns the local node ID. +func (ln *LocalNode) ID() ID { + return ln.id +} + +// Set puts the given entry into the local record, overwriting +// any existing value. +func (ln *LocalNode) Set(e enr.Entry) { + ln.mu.Lock() + defer ln.mu.Unlock() + + ln.set(e) +} + +func (ln *LocalNode) set(e enr.Entry) { + val, exists := ln.entries[e.ENRKey()] + if !exists || !reflect.DeepEqual(val, e) { + ln.entries[e.ENRKey()] = e + ln.invalidate() + } +} + +// Delete removes the given entry from the local record. +func (ln *LocalNode) Delete(e enr.Entry) { + ln.mu.Lock() + defer ln.mu.Unlock() + + ln.delete(e) +} + +func (ln *LocalNode) delete(e enr.Entry) { + _, exists := ln.entries[e.ENRKey()] + if exists { + delete(ln.entries, e.ENRKey()) + ln.invalidate() + } +} + +// SetStaticIP sets the local IP to the given one unconditionally. +// This disables endpoint prediction. +func (ln *LocalNode) SetStaticIP(ip net.IP) { + ln.mu.Lock() + defer ln.mu.Unlock() + + ln.staticIP = ip + ln.updateEndpoints() +} + +// SetFallbackIP sets the last-resort IP address. This address is used +// if no endpoint prediction can be made and no static IP is set. +func (ln *LocalNode) SetFallbackIP(ip net.IP) { + ln.mu.Lock() + defer ln.mu.Unlock() + + ln.fallbackIP = ip + ln.updateEndpoints() +} + +// SetFallbackUDP sets the last-resort UDP port. This port is used +// if no endpoint prediction can be made. +func (ln *LocalNode) SetFallbackUDP(port int) { + ln.mu.Lock() + defer ln.mu.Unlock() + + ln.fallbackUDP = port + ln.updateEndpoints() +} + +// UDPEndpointStatement should be called whenever a statement about the local node's +// UDP endpoint is received. It feeds the local endpoint predictor. +func (ln *LocalNode) UDPEndpointStatement(fromaddr, endpoint *net.UDPAddr) { + ln.mu.Lock() + defer ln.mu.Unlock() + + ln.udpTrack.AddStatement(fromaddr.String(), endpoint.String()) + ln.updateEndpoints() +} + +// UDPContact should be called whenever the local node has announced itself to another node +// via UDP. It feeds the local endpoint predictor. +func (ln *LocalNode) UDPContact(toaddr *net.UDPAddr) { + ln.mu.Lock() + defer ln.mu.Unlock() + + ln.udpTrack.AddContact(toaddr.String()) + ln.updateEndpoints() +} + +func (ln *LocalNode) updateEndpoints() { + // Determine the endpoints. + newIP := ln.fallbackIP + newUDP := ln.fallbackUDP + if ln.staticIP != nil { + newIP = ln.staticIP + } else if ip, port := predictAddr(ln.udpTrack); ip != nil { + newIP = ip + newUDP = port + } + + // Update the record. + if newIP != nil && !newIP.IsUnspecified() { + ln.set(enr.IP(newIP)) + if newUDP != 0 { + ln.set(enr.UDP(newUDP)) + } else { + ln.delete(enr.UDP(0)) + } + } else { + ln.delete(enr.IP{}) + } +} + +// predictAddr wraps IPTracker.PredictEndpoint, converting from its string-based +// endpoint representation to IP and port types. +func predictAddr(t *netutil.IPTracker) (net.IP, int) { + ep := t.PredictEndpoint() + if ep == "" { + return nil, 0 + } + ipString, portString, _ := net.SplitHostPort(ep) + ip := net.ParseIP(ipString) + port, _ := strconv.Atoi(portString) + return ip, port +} + +func (ln *LocalNode) invalidate() { + ln.cur.Store((*Node)(nil)) +} + +func (ln *LocalNode) sign() { + if n := ln.cur.Load().(*Node); n != nil { + return // no changes + } + + var r enr.Record + for _, e := range ln.entries { + r.Set(e) + } + ln.bumpSeq() + r.SetSeq(ln.seq) + if err := SignV4(&r, ln.key); err != nil { + panic(fmt.Errorf("enode: can't sign record: %v", err)) + } + n, err := New(ValidSchemes, &r) + if err != nil { + panic(fmt.Errorf("enode: can't verify local record: %v", err)) + } + ln.cur.Store(n) + log.Info("New local node record", "seq", ln.seq, "id", n.ID(), "ip", n.IP(), "udp", n.UDP(), "tcp", n.TCP()) +} + +func (ln *LocalNode) bumpSeq() { + ln.seq++ + ln.db.storeLocalSeq(ln.id, ln.seq) +} diff --git a/p2p/enode/localnode_test.go b/p2p/enode/localnode_test.go new file mode 100644 index 0000000000..f5e3496d63 --- /dev/null +++ b/p2p/enode/localnode_test.go @@ -0,0 +1,76 @@ +// 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 enode + +import ( + "testing" + + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/p2p/enr" +) + +func newLocalNodeForTesting() (*LocalNode, *DB) { + db, _ := OpenDB("") + key, _ := crypto.GenerateKey() + return NewLocalNode(db, key), db +} + +func TestLocalNode(t *testing.T) { + ln, db := newLocalNodeForTesting() + defer db.Close() + + if ln.Node().ID() != ln.ID() { + t.Fatal("inconsistent ID") + } + + ln.Set(enr.WithEntry("x", uint(3))) + var x uint + if err := ln.Node().Load(enr.WithEntry("x", &x)); err != nil { + t.Fatal("can't load entry 'x':", err) + } else if x != 3 { + t.Fatal("wrong value for entry 'x':", x) + } +} + +func TestLocalNodeSeqPersist(t *testing.T) { + ln, db := newLocalNodeForTesting() + defer db.Close() + + if s := ln.Node().Seq(); s != 1 { + t.Fatalf("wrong initial seq %d, want 1", s) + } + ln.Set(enr.WithEntry("x", uint(1))) + if s := ln.Node().Seq(); s != 2 { + t.Fatalf("wrong seq %d after set, want 2", s) + } + + // Create a new instance, it should reload the sequence number. + // The number increases just after that because a new record is + // created without the "x" entry. + ln2 := NewLocalNode(db, ln.key) + if s := ln2.Node().Seq(); s != 3 { + t.Fatalf("wrong seq %d on new instance, want 3", s) + } + + // Create a new instance with a different node key on the same database. + // This should reset the sequence number. + key, _ := crypto.GenerateKey() + ln3 := NewLocalNode(db, key) + if s := ln3.Node().Seq(); s != 1 { + t.Fatalf("wrong seq %d on instance with changed key, want 1", s) + } +} diff --git a/p2p/enode/node.go b/p2p/enode/node.go new file mode 100644 index 0000000000..b454ab2554 --- /dev/null +++ b/p2p/enode/node.go @@ -0,0 +1,255 @@ +// 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 enode + +import ( + "crypto/ecdsa" + "encoding/hex" + "errors" + "fmt" + "math/bits" + "math/rand" + "net" + "strings" + + "github.com/ethereum/go-ethereum/p2p/enr" +) + +// Node represents a host on the network. +type Node struct { + r enr.Record + id ID +} + +// New wraps a node record. The record must be valid according to the given +// identity scheme. +func New(validSchemes enr.IdentityScheme, r *enr.Record) (*Node, error) { + if err := r.VerifySignature(validSchemes); err != nil { + return nil, err + } + node := &Node{r: *r} + if n := copy(node.id[:], validSchemes.NodeAddr(&node.r)); n != len(ID{}) { + return nil, fmt.Errorf("invalid node ID length %d, need %d", n, len(ID{})) + } + return node, nil +} + +// ID returns the node identifier. +func (n *Node) ID() ID { + return n.id +} + +// Seq returns the sequence number of the underlying record. +func (n *Node) Seq() uint64 { + return n.r.Seq() +} + +// Incomplete returns true for nodes with no IP address. +func (n *Node) Incomplete() bool { + return n.IP() == nil +} + +// Load retrieves an entry from the underlying record. +func (n *Node) Load(k enr.Entry) error { + return n.r.Load(k) +} + +// IP returns the IP address of the node. +func (n *Node) IP() net.IP { + var ip net.IP + n.Load((*enr.IP)(&ip)) + return ip +} + +// UDP returns the UDP port of the node. +func (n *Node) UDP() int { + var port enr.UDP + n.Load(&port) + return int(port) +} + +// UDP returns the TCP port of the node. +func (n *Node) TCP() int { + var port enr.TCP + n.Load(&port) + return int(port) +} + +// Pubkey returns the secp256k1 public key of the node, if present. +func (n *Node) Pubkey() *ecdsa.PublicKey { + var key ecdsa.PublicKey + if n.Load((*Secp256k1)(&key)) != nil { + return nil + } + return &key +} + +// Record returns the node's record. The return value is a copy and may +// be modified by the caller. +func (n *Node) Record() *enr.Record { + cpy := n.r + return &cpy +} + +// checks whether n is a valid complete node. +func (n *Node) ValidateComplete() error { + if n.Incomplete() { + return errors.New("incomplete node") + } + if n.UDP() == 0 { + return errors.New("missing UDP port") + } + ip := n.IP() + if ip.IsMulticast() || ip.IsUnspecified() { + return errors.New("invalid IP (multicast/unspecified)") + } + // Validate the node key (on curve, etc.). + var key Secp256k1 + return n.Load(&key) +} + +// The string representation of a Node is a URL. +// Please see ParseNode for a description of the format. +func (n *Node) String() string { + return n.v4URL() +} + +// MarshalText implements encoding.TextMarshaler. +func (n *Node) MarshalText() ([]byte, error) { + return []byte(n.v4URL()), nil +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (n *Node) UnmarshalText(text []byte) error { + dec, err := ParseV4(string(text)) + if err == nil { + *n = *dec + } + return err +} + +// ID is a unique identifier for each node. +type ID [32]byte + +// Bytes returns a byte slice representation of the ID +func (n ID) Bytes() []byte { + return n[:] +} + +// ID prints as a long hexadecimal number. +func (n ID) String() string { + return fmt.Sprintf("%x", n[:]) +} + +// The Go syntax representation of a ID is a call to HexID. +func (n ID) GoString() string { + return fmt.Sprintf("enode.HexID(\"%x\")", n[:]) +} + +// TerminalString returns a shortened hex string for terminal logging. +func (n ID) TerminalString() string { + return hex.EncodeToString(n[:8]) +} + +// MarshalText implements the encoding.TextMarshaler interface. +func (n ID) MarshalText() ([]byte, error) { + return []byte(hex.EncodeToString(n[:])), nil +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface. +func (n *ID) UnmarshalText(text []byte) error { + id, err := parseID(string(text)) + if err != nil { + return err + } + *n = id + return nil +} + +// HexID converts a hex string to an ID. +// The string may be prefixed with 0x. +// It panics if the string is not a valid ID. +func HexID(in string) ID { + id, err := parseID(in) + if err != nil { + panic(err) + } + return id +} + +func parseID(in string) (ID, error) { + var id ID + b, err := hex.DecodeString(strings.TrimPrefix(in, "0x")) + if err != nil { + return id, err + } else if len(b) != len(id) { + return id, fmt.Errorf("wrong length, want %d hex chars", len(id)*2) + } + copy(id[:], b) + return id, nil +} + +// DistCmp compares the distances a->target and b->target. +// Returns -1 if a is closer to target, 1 if b is closer to target +// and 0 if they are equal. +func DistCmp(target, a, b ID) int { + for i := range target { + da := a[i] ^ target[i] + db := b[i] ^ target[i] + if da > db { + return 1 + } else if da < db { + return -1 + } + } + return 0 +} + +// LogDist returns the logarithmic distance between a and b, log2(a ^ b). +func LogDist(a, b ID) int { + lz := 0 + for i := range a { + x := a[i] ^ b[i] + if x == 0 { + lz += 8 + } else { + lz += bits.LeadingZeros8(x) + break + } + } + return len(a)*8 - lz +} + +// RandomID returns a random ID b such that logdist(a, b) == n. +func RandomID(a ID, n int) (b ID) { + if n == 0 { + return a + } + // flip bit at position n, fill the rest with random bits + b = a + pos := len(a) - n/8 - 1 + bit := byte(0x01) << (byte(n%8) - 1) + if bit == 0 { + pos++ + bit = 0x80 + } + b[pos] = a[pos]&^bit | ^a[pos]&bit // TODO: randomize end bits + for i := pos + 1; i < len(a); i++ { + b[i] = byte(rand.Intn(255)) + } + return b +} diff --git a/p2p/enode/node_test.go b/p2p/enode/node_test.go new file mode 100644 index 0000000000..861a70bd64 --- /dev/null +++ b/p2p/enode/node_test.go @@ -0,0 +1,62 @@ +// 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 enode + +import ( + "encoding/hex" + "fmt" + "testing" + + "github.com/ethereum/go-ethereum/p2p/enr" + "github.com/ethereum/go-ethereum/rlp" + "github.com/stretchr/testify/assert" +) + +var pyRecord, _ = hex.DecodeString("f884b8407098ad865b00a582051940cb9cf36836572411a47278783077011599ed5cd16b76f2635f4e234738f30813a89eb9137e3e3df5266e3a1f11df72ecf1145ccb9c01826964827634826970847f00000189736563703235366b31a103ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd31388375647082765f") + +// TestPythonInterop checks that we can decode and verify a record produced by the Python +// implementation. +func TestPythonInterop(t *testing.T) { + var r enr.Record + if err := rlp.DecodeBytes(pyRecord, &r); err != nil { + t.Fatalf("can't decode: %v", err) + } + n, err := New(ValidSchemes, &r) + if err != nil { + t.Fatalf("can't verify record: %v", err) + } + + var ( + wantID = HexID("a448f24c6d18e575453db13171562b71999873db5b286df957af199ec94617f7") + wantSeq = uint64(1) + wantIP = enr.IP{127, 0, 0, 1} + wantUDP = enr.UDP(30303) + ) + if n.Seq() != wantSeq { + t.Errorf("wrong seq: got %d, want %d", n.Seq(), wantSeq) + } + if n.ID() != wantID { + t.Errorf("wrong id: got %x, want %x", n.ID(), wantID) + } + want := map[enr.Entry]interface{}{new(enr.IP): &wantIP, new(enr.UDP): &wantUDP} + for k, v := range want { + desc := fmt.Sprintf("loading key %q", k.ENRKey()) + if assert.NoError(t, n.Load(k), desc) { + assert.Equal(t, k, v, desc) + } + } +} diff --git a/p2p/enode/nodedb.go b/p2p/enode/nodedb.go new file mode 100644 index 0000000000..a43e63868f --- /dev/null +++ b/p2p/enode/nodedb.go @@ -0,0 +1,447 @@ +// 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 enode + +import ( + "bytes" + "crypto/rand" + "encoding/binary" + "fmt" + "net" + "os" + "sync" + "time" + + "github.com/ethereum/go-ethereum/rlp" + "github.com/syndtr/goleveldb/leveldb" + "github.com/syndtr/goleveldb/leveldb/errors" + "github.com/syndtr/goleveldb/leveldb/iterator" + "github.com/syndtr/goleveldb/leveldb/opt" + "github.com/syndtr/goleveldb/leveldb/storage" + "github.com/syndtr/goleveldb/leveldb/util" +) + +// Keys in the node database. +const ( + dbVersionKey = "version" // Version of the database to flush if changes + dbNodePrefix = "n:" // Identifier to prefix node entries with + dbLocalPrefix = "local:" + dbDiscoverRoot = "v4" + + // 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" +) + +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 = 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 { + lvl *leveldb.DB // Interface to the database itself + runner sync.Once // Ensures we can start at most one expirer + quit chan struct{} // Channel to signal the expiring thread to stop +} + +// OpenDB opens a node database for storing and retrieving infos about known peers in the +// network. If no path is given an in-memory, temporary database is constructed. +func OpenDB(path string) (*DB, error) { + if path == "" { + return newMemoryDB() + } + return newPersistentDB(path) +} + +// newMemoryNodeDB creates a new in-memory node database without a persistent backend. +func newMemoryDB() (*DB, error) { + db, err := leveldb.Open(storage.NewMemStorage(), nil) + if err != nil { + return nil, err + } + return &DB{lvl: db, quit: make(chan struct{})}, nil +} + +// newPersistentNodeDB creates/opens a leveldb backed persistent node database, +// also flushing its contents in case of a version mismatch. +func newPersistentDB(path string) (*DB, error) { + opts := &opt.Options{OpenFilesCacheCapacity: 5} + db, err := leveldb.OpenFile(path, opts) + if _, iscorrupted := err.(*errors.ErrCorrupted); iscorrupted { + db, err = leveldb.RecoverFile(path, nil) + } + if err != nil { + return nil, err + } + // The nodes contained in the cache correspond to a certain protocol version. + // Flush all nodes if the version doesn't match. + currentVer := make([]byte, binary.MaxVarintLen64) + currentVer = currentVer[:binary.PutVarint(currentVer, int64(dbVersion))] + + blob, err := db.Get([]byte(dbVersionKey), nil) + switch err { + case leveldb.ErrNotFound: + // Version not found (i.e. empty cache), insert it + if err := db.Put([]byte(dbVersionKey), currentVer, nil); err != nil { + db.Close() + return nil, err + } + + case nil: + // Version present, flush if different + if !bytes.Equal(blob, currentVer) { + db.Close() + if err = os.RemoveAll(path); err != nil { + return nil, err + } + return newPersistentDB(path) + } + } + return &DB{lvl: db, quit: make(chan struct{})}, nil +} + +// 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 +} + +// 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 + } + item := key[len(dbNodePrefix):] + copy(id[:], item[:len(id)]) + return id, item[len(id)+1:] +} + +// 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. +func (db *DB) fetchInt64(key []byte) int64 { + blob, err := db.lvl.Get(key, nil) + if err != nil { + return 0 + } + val, read := binary.Varint(blob) + if read <= 0 { + return 0 + } + return val +} + +// storeInt64 stores an integer in the given key. +func (db *DB) storeInt64(key []byte, n int64) error { + blob := make([]byte, binary.MaxVarintLen64) + blob = blob[:binary.PutVarint(blob, n)] + return db.lvl.Put(key, blob, nil) +} + +// fetchUint64 retrieves an integer associated with a particular key. +func (db *DB) fetchUint64(key []byte) uint64 { + blob, err := db.lvl.Get(key, nil) + if err != nil { + return 0 + } + val, _ := binary.Uvarint(blob) + return val +} + +// storeUint64 stores an integer in the given key. +func (db *DB) storeUint64(key []byte, n uint64) error { + blob := make([]byte, binary.MaxVarintLen64) + blob = blob[:binary.PutUvarint(blob, n)] + return db.lvl.Put(key, blob, nil) +} + +// Node retrieves a node with a given id from the database. +func (db *DB) Node(id ID) *Node { + blob, err := db.lvl.Get(nodeKey(id), nil) + if err != nil { + return nil + } + return mustDecodeNode(id[:], blob) +} + +func mustDecodeNode(id, data []byte) *Node { + node := new(Node) + if err := rlp.DecodeBytes(data, &node.r); err != nil { + panic(fmt.Errorf("p2p/enode: can't decode node %x in DB: %v", id, err)) + } + // Restore node id cache. + copy(node.id[:], id) + return node +} + +// UpdateNode inserts - potentially overwriting - a node into the peer database. +func (db *DB) UpdateNode(node *Node) error { + if node.Seq() < db.NodeSeq(node.ID()) { + return nil + } + blob, err := rlp.EncodeToBytes(&node.r) + if err != nil { + return err + } + if err := db.lvl.Put(nodeKey(node.ID()), blob, nil); err != nil { + return err + } + 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(nodeItemKey(id, zeroIP, dbNodeSeq)) +} + +// Resolve returns the stored record of the node if it has a larger sequence +// number than n. +func (db *DB) Resolve(n *Node) *Node { + if n.Seq() > db.NodeSeq(n.ID()) { + return n + } + return db.Node(n.ID()) +} + +// 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) + } +} + +// ensureExpirer is a small helper method ensuring that the data expiration +// mechanism is running. If the expiration goroutine is already running, this +// method simply returns. +// +// The goal is to start the data evacuation only after the network successfully +// bootstrapped itself (to prevent dumping potentially useful seed nodes). Since +// it would require significant overhead to exactly trace the first successful +// convergence, it's simpler to "ensure" the correct state when an appropriate +// condition occurs (i.e. a successful bonding), and discard further events. +func (db *DB) ensureExpirer() { + db.runner.Do(func() { go db.expirer() }) +} + +// expirer should be started in a go routine, and is responsible for looping ad +// infinitum and dropping stale data from the database. +func (db *DB) expirer() { + tick := time.NewTicker(dbCleanupCycle) + defer tick.Stop() + for { + select { + case <-tick.C: + db.expireNodes() + case <-db.quit: + return + } + } +} + +// expireNodes iterates over the database and deletes all nodes that have not +// 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() + 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 + } + } +} + +// LastPingReceived retrieves the time of the last ping packet received from +// a remote node. +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, 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, ip net.IP) time.Time { + // Launch expirer + db.ensureExpirer() + 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, 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, 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, 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(localItemKey(id, dbLocalSeq)) +} + +// storeLocalSeq stores the local record sequence counter. +func (db *DB) storeLocalSeq(id ID, n uint64) { + db.storeUint64(localItemKey(id, dbLocalSeq), n) +} + +// QuerySeeds retrieves random nodes to be used as potential seed nodes +// for bootstrapping. +func (db *DB) QuerySeeds(n int, maxAge time.Duration) []*Node { + var ( + now = time.Now() + nodes = make([]*Node, 0, n) + it = db.lvl.NewIterator(nil, nil) + id ID + ) + defer it.Release() + +seek: + for seeks := 0; len(nodes) < n && seeks < n*5; seeks++ { + // Seek to a random entry. The first byte is incremented by a + // random amount each time in order to increase the likelihood + // of hitting all existing nodes in very small databases. + ctr := id[0] + rand.Read(id[:]) + id[0] = ctr + id[0]%16 + it.Seek(nodeKey(id)) + + n := nextNode(it) + if n == nil { + id[0] = 0 + continue seek // iterator exhausted + } + if now.Sub(db.LastPongReceived(n.ID(), n.IP())) > maxAge { + continue seek + } + for i := range nodes { + if nodes[i].ID() == n.ID() { + continue seek // duplicate + } + } + nodes = append(nodes, n) + } + return nodes +} + +// reads the next node record from the iterator, skipping over other +// database entries. +func nextNode(it iterator.Iterator) *Node { + for end := false; !end; end = !it.Next() { + id, rest := splitNodeKey(it.Key()) + if string(rest) != dbDiscoverRoot { + continue + } + return mustDecodeNode(id[:], it.Value()) + } + return nil +} + +// close flushes and closes the database files. +func (db *DB) Close() { + close(db.quit) + db.lvl.Close() +} diff --git a/p2p/enode/nodedb_test.go b/p2p/enode/nodedb_test.go new file mode 100644 index 0000000000..21283524c3 --- /dev/null +++ b/p2p/enode/nodedb_test.go @@ -0,0 +1,464 @@ +// 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 enode + +import ( + "bytes" + "fmt" + "io/ioutil" + "net" + "os" + "path/filepath" + "reflect" + "testing" + "time" +) + +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 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) + } +} + +var nodeDBInt64Tests = []struct { + key []byte + value int64 +}{ + {key: []byte{0x01}, value: 1}, + {key: []byte{0x02}, value: 2}, + {key: []byte{0x03}, value: 3}, +} + +func TestDBInt64(t *testing.T) { + db, _ := OpenDB("") + defer db.Close() + + tests := nodeDBInt64Tests + for i := 0; i < len(tests); i++ { + // Insert the next value + if err := db.storeInt64(tests[i].key, tests[i].value); err != nil { + t.Errorf("test %d: failed to store value: %v", i, err) + } + // Check all existing and non existing values + for j := 0; j < len(tests); j++ { + num := db.fetchInt64(tests[j].key) + switch { + case j <= i && num != tests[j].value: + t.Errorf("test %d, item %d: value mismatch: have %v, want %v", i, j, num, tests[j].value) + case j > i && num != 0: + t.Errorf("test %d, item %d: value mismatch: have %v, want %v", i, j, num, 0) + } + } + } +} + +func TestDBFetchStore(t *testing.T) { + node := NewV4( + hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), + net.IP{192, 168, 0, 1}, + 30303, + 30303, + ) + inst := time.Now() + num := 314 + + db, _ := OpenDB("") + defer db.Close() + + // Check fetch/store operations on a node ping object + 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(), node.IP(), inst); err != nil { + t.Errorf("ping: failed to update: %v", err) + } + 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(), node.IP()); stored.Unix() != 0 { + t.Errorf("pong: non-existing object: %v", stored) + } + 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(), 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(), node.IP()); stored != 0 { + t.Errorf("find-node fails: non-existing object: %v", stored) + } + 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(), 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 + if stored := db.Node(node.ID()); stored != nil { + t.Errorf("node: non-existing object: %v", stored) + } + if err := db.UpdateNode(node); err != nil { + t.Errorf("node: failed to update: %v", err) + } + if stored := db.Node(node.ID()); stored == nil { + t.Errorf("node: not found") + } else if !reflect.DeepEqual(stored, node) { + t.Errorf("node: data mismatch: have %v, want %v", stored, node) + } +} + +var nodeDBSeedQueryNodes = []struct { + node *Node + pong time.Time +}{ + // This one should not be in the result set because its last + // pong time is too far in the past. + { + node: NewV4( + hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), + net.IP{127, 0, 0, 3}, + 30303, + 30303, + ), + pong: time.Now().Add(-3 * time.Hour), + }, + // This one shouldn't be in the result set because its + // nodeID is the local node's ID. + { + node: NewV4( + hexPubkey("ff93ff820abacd4351b0f14e47b324bc82ff014c226f3f66a53535734a3c150e7e38ca03ef0964ba55acddc768f5e99cd59dea95ddd4defbab1339c92fa319b2"), + net.IP{127, 0, 0, 3}, + 30303, + 30303, + ), + pong: time.Now().Add(-4 * time.Second), + }, + + // These should be in the result set. + { + node: NewV4( + hexPubkey("c2b5eb3f5dde05f815b63777809ee3e7e0cbb20035a6b00ce327191e6eaa8f26a8d461c9112b7ab94698e7361fa19fd647e603e73239002946d76085b6f928d6"), + net.IP{127, 0, 0, 1}, + 30303, + 30303, + ), + pong: time.Now().Add(-2 * time.Second), + }, + { + node: NewV4( + hexPubkey("6ca1d400c8ddf8acc94bcb0dd254911ad71a57bed5e0ae5aa205beed59b28c2339908e97990c493499613cff8ecf6c3dc7112a8ead220cdcd00d8847ca3db755"), + net.IP{127, 0, 0, 2}, + 30303, + 30303, + ), + pong: time.Now().Add(-3 * time.Second), + }, + { + node: NewV4( + hexPubkey("234dc63fe4d131212b38236c4c3411288d7bec61cbf7b120ff12c43dc60c96182882f4291d209db66f8a38e986c9c010ff59231a67f9515c7d1668b86b221a47"), + net.IP{127, 0, 0, 3}, + 30303, + 30303, + ), + pong: time.Now().Add(-1 * time.Second), + }, + { + node: NewV4( + hexPubkey("c013a50b4d1ebce5c377d8af8cb7114fd933ffc9627f96ad56d90fef5b7253ec736fd07ef9a81dc2955a997e54b7bf50afd0aa9f110595e2bec5bb7ce1657004"), + net.IP{127, 0, 0, 3}, + 30303, + 30303, + ), + pong: time.Now().Add(-2 * time.Second), + }, + { + node: NewV4( + hexPubkey("f141087e3e08af1aeec261ff75f48b5b1637f594ea9ad670e50051646b0416daa3b134c28788cbe98af26992a47652889cd8577ccc108ac02c6a664db2dc1283"), + net.IP{127, 0, 0, 3}, + 30303, + 30303, + ), + pong: time.Now().Add(-2 * time.Second), + }, +} + +func TestDBSeedQuery(t *testing.T) { + // Querying seeds uses seeks an might not find all nodes + // every time when the database is small. Run the test multiple + // times to avoid flakes. + const attempts = 15 + var err error + for i := 0; i < attempts; i++ { + if err = testSeedQuery(); err == nil { + return + } + } + if err != nil { + t.Errorf("no successful run in %d attempts: %v", attempts, err) + } +} + +func testSeedQuery() error { + db, _ := OpenDB("") + defer db.Close() + + // Insert a batch of nodes for querying + for i, seed := range nodeDBSeedQueryNodes { + 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.node.IP(), seed.pong); err != nil { + return fmt.Errorf("node %d: failed to insert bondTime: %v", i, err) + } + } + + // Retrieve the entire batch and check for duplicates + seeds := db.QuerySeeds(len(nodeDBSeedQueryNodes)*2, time.Hour) + have := make(map[ID]struct{}) + for _, seed := range seeds { + have[seed.ID()] = struct{}{} + } + want := make(map[ID]struct{}) + for _, seed := range nodeDBSeedQueryNodes[1:] { + want[seed.node.ID()] = struct{}{} + } + if len(seeds) != len(want) { + return fmt.Errorf("seed count mismatch: have %v, want %v", len(seeds), len(want)) + } + for id := range have { + if _, ok := want[id]; !ok { + return fmt.Errorf("extra seed: %v", id) + } + } + for id := range want { + if _, ok := have[id]; !ok { + return fmt.Errorf("missing seed: %v", id) + } + } + return nil +} + +func TestDBPersistency(t *testing.T) { + root, err := ioutil.TempDir("", "nodedb-") + if err != nil { + t.Fatalf("failed to create temporary data folder: %v", err) + } + defer os.RemoveAll(root) + + var ( + testKey = []byte("somekey") + testInt = int64(314) + ) + + // Create a persistent database and store some values + db, err := OpenDB(filepath.Join(root, "database")) + if err != nil { + t.Fatalf("failed to create persistent database: %v", err) + } + if err := db.storeInt64(testKey, testInt); err != nil { + t.Fatalf("failed to store value: %v.", err) + } + db.Close() + + // Reopen the database and check the value + db, err = OpenDB(filepath.Join(root, "database")) + if err != nil { + t.Fatalf("failed to open persistent database: %v", err) + } + if val := db.fetchInt64(testKey); val != testInt { + t.Fatalf("value mismatch: have %v, want %v", val, testInt) + } + db.Close() +} + +var nodeDBExpirationNodes = []struct { + node *Node + pong time.Time + storeNode bool + exp bool +}{ + // Node has new enough pong time and isn't expired: + { + node: NewV4( + hexPubkey("8d110e2ed4b446d9b5fb50f117e5f37fb7597af455e1dab0e6f045a6eeaa786a6781141659020d38bdc5e698ed3d4d2bafa8b5061810dfa63e8ac038db2e9b67"), + net.IP{127, 0, 0, 1}, + 30303, + 30303, + ), + 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, + ), + 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, + }, +} + +func TestDBExpiration(t *testing.T) { + db, _ := OpenDB("") + defer db.Close() + + // Add all the test nodes and set their last pong time. + for i, seed := range nodeDBExpirationNodes { + 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.node.IP(), seed.pong); err != nil { + t.Fatalf("node %d: failed to update bondTime: %v", i, 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()) + 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/p2p/enode/urlv4.go b/p2p/enode/urlv4.go new file mode 100644 index 0000000000..50e9485d04 --- /dev/null +++ b/p2p/enode/urlv4.go @@ -0,0 +1,194 @@ +// 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 enode + +import ( + "crypto/ecdsa" + "encoding/hex" + "errors" + "fmt" + "net" + "net/url" + "regexp" + "strconv" + + "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/p2p/enr" +) + +var incompleteNodeURL = regexp.MustCompile("(?i)^(?:enode://)?([0-9a-f]+)$") + +// MustParseV4 parses a node URL. It panics if the URL is not valid. +func MustParseV4(rawurl string) *Node { + n, err := ParseV4(rawurl) + if err != nil { + panic("invalid node URL: " + err.Error()) + } + return n +} + +// ParseV4 parses a node URL. +// +// There are two basic forms of node URLs: +// +// - incomplete nodes, which only have the public key (node ID) +// - complete nodes, which contain the public key and IP/Port information +// +// For incomplete nodes, the designator must look like one of these +// +// enode:// +// +// +// For complete nodes, the node ID is encoded in the username portion +// of the URL, separated from the host by an @ sign. The hostname can +// only be given as an IP address, DNS domain names are not allowed. +// The port in the host name section is the TCP listening port. If the +// TCP and UDP (discovery) ports differ, the UDP port is specified as +// query parameter "discport". +// +// In the following example, the node URL describes +// a node with IP address 10.3.58.6, TCP listening port 30303 +// and UDP discovery port 30301. +// +// enode://@10.3.58.6:30303?discport=30301 +func ParseV4(rawurl string) (*Node, error) { + if m := incompleteNodeURL.FindStringSubmatch(rawurl); m != nil { + id, err := parsePubkey(m[1]) + if err != nil { + return nil, fmt.Errorf("invalid node ID (%v)", err) + } + return NewV4(id, nil, 0, 0), nil + } + return parseComplete(rawurl) +} + +// NewV4 creates a node from discovery v4 node information. The record +// contained in the node has a zero-length signature. +func NewV4(pubkey *ecdsa.PublicKey, ip net.IP, tcp, udp int) *Node { + var r enr.Record + if ip != nil { + r.Set(enr.IP(ip)) + } + if udp != 0 { + r.Set(enr.UDP(udp)) + } + if tcp != 0 { + r.Set(enr.TCP(tcp)) + } + signV4Compat(&r, pubkey) + n, err := New(v4CompatID{}, &r) + if err != nil { + panic(err) + } + return n +} + +func parseComplete(rawurl string) (*Node, error) { + var ( + id *ecdsa.PublicKey + ip net.IP + tcpPort, udpPort uint64 + ) + u, err := url.Parse(rawurl) + if err != nil { + return nil, err + } + if u.Scheme != "enode" { + return nil, errors.New("invalid URL scheme, want \"enode\"") + } + // Parse the Node ID from the user portion. + if u.User == nil { + return nil, errors.New("does not contain node ID") + } + if id, err = parsePubkey(u.User.String()); err != nil { + return nil, fmt.Errorf("invalid node ID (%v)", err) + } + // Parse the IP address. + host, port, err := net.SplitHostPort(u.Host) + if err != nil { + return nil, fmt.Errorf("invalid host: %v", err) + } + if ip = net.ParseIP(host); ip == nil { + return nil, errors.New("invalid IP address") + } + // Ensure the IP is 4 bytes long for IPv4 addresses. + if ipv4 := ip.To4(); ipv4 != nil { + ip = ipv4 + } + // Parse the port numbers. + if tcpPort, err = strconv.ParseUint(port, 10, 16); err != nil { + return nil, errors.New("invalid port") + } + udpPort = tcpPort + qv := u.Query() + if qv.Get("discport") != "" { + udpPort, err = strconv.ParseUint(qv.Get("discport"), 10, 16) + if err != nil { + return nil, errors.New("invalid discport in query") + } + } + return NewV4(id, ip, int(tcpPort), int(udpPort)), nil +} + +// parsePubkey parses a hex-encoded secp256k1 public key. +func parsePubkey(in string) (*ecdsa.PublicKey, error) { + b, err := hex.DecodeString(in) + if err != nil { + return nil, err + } else if len(b) != 64 { + return nil, fmt.Errorf("wrong length, want %d hex chars", 128) + } + b = append([]byte{0x4}, b...) + return crypto.UnmarshalPubkey(b) +} + +func (n *Node) v4URL() string { + var ( + scheme enr.ID + nodeid string + key ecdsa.PublicKey + ) + n.Load(&scheme) + n.Load((*Secp256k1)(&key)) + switch { + case scheme == "v4" || key != ecdsa.PublicKey{}: + nodeid = fmt.Sprintf("%x", crypto.FromECDSAPub(&key)[1:]) + default: + nodeid = fmt.Sprintf("%s.%x", scheme, n.id[:]) + } + u := url.URL{Scheme: "enode"} + if n.Incomplete() { + u.Host = nodeid + } else { + addr := net.TCPAddr{IP: n.IP(), Port: n.TCP()} + u.User = url.User(nodeid) + u.Host = addr.String() + if n.UDP() != n.TCP() { + u.RawQuery = "discport=" + strconv.Itoa(n.UDP()) + } + } + return u.String() +} + +// PubkeyToIDV4 derives the v4 node address from the given public key. +func PubkeyToIDV4(key *ecdsa.PublicKey) ID { + e := make([]byte, 64) + math.ReadBits(key.X, e[:len(e)/2]) + math.ReadBits(key.Y, e[len(e)/2:]) + return ID(crypto.Keccak256Hash(e)) +} diff --git a/p2p/discover/node_test.go b/p2p/enode/urlv4_test.go similarity index 50% rename from p2p/discover/node_test.go rename to p2p/enode/urlv4_test.go index ed8db4dc65..3680ab6b78 100644 --- a/p2p/discover/node_test.go +++ b/p2p/enode/urlv4_test.go @@ -1,4 +1,4 @@ -// Copyright 2015 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,45 +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 discover +package enode import ( "bytes" - "fmt" + "crypto/ecdsa" "math/big" - "math/rand" "net" "reflect" "strings" "testing" "testing/quick" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" ) -func ExampleNewNode() { - id := MustHexID("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439") - - // Complete nodes contain UDP and TCP endpoints: - n1 := NewNode(id, net.ParseIP("2001:db8:3c4d:15::abcd:ef12"), 52150, 30303) - fmt.Println("n1:", n1) - fmt.Println("n1.Incomplete() ->", n1.Incomplete()) - - // An incomplete node can be created by passing zero values - // for all parameters except id. - n2 := NewNode(id, nil, 0, 0) - fmt.Println("n2:", n2) - fmt.Println("n2.Incomplete() ->", n2.Incomplete()) - - // Output: - // n1: enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[2001:db8:3c4d:15::abcd:ef12]:30303?discport=52150 - // n1.Incomplete() -> false - // n2: enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439 - // n2.Incomplete() -> true -} - var parseNodeTests = []struct { rawurl string wantError string @@ -81,8 +55,8 @@ var parseNodeTests = []struct { }, { rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150", - wantResult: NewNode( - MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), + wantResult: NewV4( + hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), net.IP{0x7f, 0x0, 0x0, 0x1}, 52150, 52150, @@ -90,8 +64,8 @@ var parseNodeTests = []struct { }, { rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[::]:52150", - wantResult: NewNode( - MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), + wantResult: NewV4( + hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), net.ParseIP("::"), 52150, 52150, @@ -99,8 +73,8 @@ var parseNodeTests = []struct { }, { rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[2001:db8:3c4d:15::abcd:ef12]:52150", - wantResult: NewNode( - MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), + wantResult: NewV4( + hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), net.ParseIP("2001:db8:3c4d:15::abcd:ef12"), 52150, 52150, @@ -108,25 +82,25 @@ var parseNodeTests = []struct { }, { rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150?discport=22334", - wantResult: NewNode( - MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), + wantResult: NewV4( + hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), net.IP{0x7f, 0x0, 0x0, 0x1}, - 22334, 52150, + 22334, ), }, // Incomplete nodes with no address. { rawurl: "1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439", - wantResult: NewNode( - MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), + wantResult: NewV4( + hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), nil, 0, 0, ), }, { rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439", - wantResult: NewNode( - MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), + wantResult: NewV4( + hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), nil, 0, 0, ), }, @@ -146,9 +120,17 @@ var parseNodeTests = []struct { }, } +func hexPubkey(h string) *ecdsa.PublicKey { + k, err := parsePubkey(h) + if err != nil { + panic(err) + } + return k +} + func TestParseNode(t *testing.T) { for _, test := range parseNodeTests { - n, err := ParseNode(test.rawurl) + n, err := ParseV4(test.rawurl) if test.wantError != "" { if err == nil { t.Errorf("test %q:\n got nil error, expected %#q", test.rawurl, test.wantError) @@ -163,7 +145,7 @@ func TestParseNode(t *testing.T) { continue } if !reflect.DeepEqual(n, test.wantResult) { - t.Errorf("test %q:\n result mismatch:\ngot: %#v, want: %#v", test.rawurl, n, test.wantResult) + t.Errorf("test %q:\n result mismatch:\ngot: %#v\nwant: %#v", test.rawurl, n, test.wantResult) } } } @@ -181,9 +163,9 @@ func TestNodeString(t *testing.T) { } func TestHexID(t *testing.T) { - ref := NodeID{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, 0, 0, 0, 0, 0, 0, 0, 0, 128, 106, 217, 182, 31, 165, 174, 1, 67, 7, 235, 220, 150, 66, 83, 173, 205, 159, 44, 10, 57, 42, 161, 26, 188} - id1 := MustHexID("0x000000000000000000000000000000000000000000000000000000000000000000000000000000806ad9b61fa5ae014307ebdc964253adcd9f2c0a392aa11abc") - id2 := MustHexID("000000000000000000000000000000000000000000000000000000000000000000000000000000806ad9b61fa5ae014307ebdc964253adcd9f2c0a392aa11abc") + ref := ID{0, 0, 0, 0, 0, 0, 0, 128, 106, 217, 182, 31, 165, 174, 1, 67, 7, 235, 220, 150, 66, 83, 173, 205, 159, 44, 10, 57, 42, 161, 26, 188} + id1 := HexID("0x00000000000000806ad9b61fa5ae014307ebdc964253adcd9f2c0a392aa11abc") + id2 := HexID("00000000000000806ad9b61fa5ae014307ebdc964253adcd9f2c0a392aa11abc") if id1 != ref { t.Errorf("wrong id1\ngot %v\nwant %v", id1[:], ref[:]) @@ -193,17 +175,14 @@ func TestHexID(t *testing.T) { } } -func TestNodeID_textEncoding(t *testing.T) { - ref := NodeID{ +func TestID_textEncoding(t *testing.T) { + ref := ID{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x30, - 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x40, - 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x50, - 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x60, - 0x61, 0x62, 0x63, 0x64, + 0x31, 0x32, } - hex := "01020304050607080910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364" + hex := "0102030405060708091011121314151617181920212223242526272829303132" text, err := ref.MarshalText() if err != nil { @@ -213,7 +192,7 @@ func TestNodeID_textEncoding(t *testing.T) { t.Fatalf("text encoding did not match\nexpected: %s\ngot: %s", hex, text) } - id := new(NodeID) + id := new(ID) if err := id.UnmarshalText(text); err != nil { t.Fatal(err) } @@ -222,114 +201,43 @@ func TestNodeID_textEncoding(t *testing.T) { } } -func TestNodeID_recover(t *testing.T) { - prv := newkey() - hash := make([]byte, 32) - sig, err := crypto.Sign(hash, prv) - if err != nil { - t.Fatalf("signing error: %v", err) - } - - pub := PubkeyID(&prv.PublicKey) - recpub, err := recoverNodeID(hash, sig) - if err != nil { - t.Fatalf("recovery error: %v", err) - } - if pub != recpub { - t.Errorf("recovered wrong pubkey:\ngot: %v\nwant: %v", recpub, pub) - } - - ecdsa, err := pub.Pubkey() - if err != nil { - t.Errorf("Pubkey error: %v", err) - } - if !reflect.DeepEqual(ecdsa, &prv.PublicKey) { - t.Errorf("Pubkey mismatch:\n got: %#v\n want: %#v", ecdsa, &prv.PublicKey) - } -} - -func TestNodeID_pubkeyBad(t *testing.T) { - ecdsa, err := NodeID{}.Pubkey() - if err == nil { - t.Error("expected error for zero ID") - } - if ecdsa != nil { - t.Error("expected nil result") - } -} - func TestNodeID_distcmp(t *testing.T) { - distcmpBig := func(target, a, b common.Hash) int { + distcmpBig := func(target, a, b ID) int { tbig := new(big.Int).SetBytes(target[:]) abig := new(big.Int).SetBytes(a[:]) bbig := new(big.Int).SetBytes(b[:]) return new(big.Int).Xor(tbig, abig).Cmp(new(big.Int).Xor(tbig, bbig)) } - if err := quick.CheckEqual(distcmp, distcmpBig, quickcfg()); err != nil { + if err := quick.CheckEqual(DistCmp, distcmpBig, nil); err != nil { t.Error(err) } } -// the random tests is likely to miss the case where they're equal. +// The random tests is likely to miss the case where a and b are equal, +// this test checks it explicitly. func TestNodeID_distcmpEqual(t *testing.T) { - base := common.Hash{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} - x := common.Hash{15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0} - if distcmp(base, x, x) != 0 { - t.Errorf("distcmp(base, x, x) != 0") + base := ID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} + x := ID{15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0} + if DistCmp(base, x, x) != 0 { + t.Errorf("DistCmp(base, x, x) != 0") } } func TestNodeID_logdist(t *testing.T) { - logdistBig := func(a, b common.Hash) int { + logdistBig := func(a, b ID) int { abig, bbig := new(big.Int).SetBytes(a[:]), new(big.Int).SetBytes(b[:]) return new(big.Int).Xor(abig, bbig).BitLen() } - if err := quick.CheckEqual(logdist, logdistBig, quickcfg()); err != nil { + if err := quick.CheckEqual(LogDist, logdistBig, nil); err != nil { t.Error(err) } } -// the random tests is likely to miss the case where they're equal. +// The random tests is likely to miss the case where a and b are equal, +// this test checks it explicitly. func TestNodeID_logdistEqual(t *testing.T) { - x := common.Hash{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} - if logdist(x, x) != 0 { - t.Errorf("logdist(x, x) != 0") + x := ID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} + if LogDist(x, x) != 0 { + t.Errorf("LogDist(x, x) != 0") } } - -func TestNodeID_hashAtDistance(t *testing.T) { - // we don't use quick.Check here because its output isn't - // very helpful when the test fails. - cfg := quickcfg() - for i := 0; i < cfg.MaxCount; i++ { - a := gen(common.Hash{}, cfg.Rand).(common.Hash) - dist := cfg.Rand.Intn(len(common.Hash{}) * 8) - result := hashAtDistance(a, dist) - actualdist := logdist(result, a) - - if dist != actualdist { - t.Log("a: ", a) - t.Log("result:", result) - t.Fatalf("#%d: distance of result is %d, want %d", i, actualdist, dist) - } - } -} - -func quickcfg() *quick.Config { - return &quick.Config{ - MaxCount: 5000, - Rand: rand.New(rand.NewSource(time.Now().Unix())), - } -} - -// TODO: The Generate method can be dropped when we require Go >= 1.5 -// because testing/quick learned to generate arrays in 1.5. - -func (NodeID) Generate(rand *rand.Rand, size int) reflect.Value { - var id NodeID - m := rand.Intn(len(id)) - for i := len(id) - 1; i > m; i-- { - id[i] = byte(rand.Uint32()) - } - return reflect.ValueOf(id) -} diff --git a/p2p/enr/enr.go b/p2p/enr/enr.go index 2c3afb43e9..444820c158 100644 --- a/p2p/enr/enr.go +++ b/p2p/enr/enr.go @@ -15,39 +15,38 @@ // along with the go-ethereum library. If not, see . // Package enr implements Ethereum Node Records as defined in EIP-778. A node record holds -// arbitrary information about a node on the peer-to-peer network. -// -// Records contain named keys. To store and retrieve key/values in a record, use the Entry +// arbitrary information about a node on the peer-to-peer network. Node information is +// stored in key/value pairs. To store and retrieve key/values in a record, use the Entry // interface. // -// Records must be signed before transmitting them to another node. Decoding a record verifies -// its signature. When creating a record, set the entries you want, then call Sign to add the -// signature. Modifying a record invalidates the signature. +// Signature Handling +// +// Records must be signed before transmitting them to another node. +// +// Decoding a record doesn't check its signature. Code working with records from an +// untrusted source must always verify two things: that the record uses an identity scheme +// deemed secure, and that the signature is valid according to the declared scheme. +// +// When creating a record, set the entries you want and use a signing function provided by +// the identity scheme to add the signature. Modifying a record invalidates the signature. // // Package enr supports the "secp256k1-keccak" identity scheme. package enr import ( "bytes" - "crypto/ecdsa" "errors" "fmt" "io" "sort" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/rlp" ) const SizeLimit = 300 // maximum encoded size of a node record in bytes -const ID_SECP256k1_KECCAK = ID("secp256k1-keccak") // the default identity scheme - var ( - errNoID = errors.New("unknown or unspecified identity scheme") - errInvalidSigsize = errors.New("invalid signature size") - errInvalidSig = errors.New("invalid signature") + ErrInvalidSig = errors.New("invalid signature on node record") errNotSorted = errors.New("record key/value pairs are not sorted by key") errDuplicateKey = errors.New("record contains duplicate key") errIncompletePair = errors.New("record contains incomplete k/v pair") @@ -56,6 +55,32 @@ var ( errNotFound = errors.New("no such key in record") ) +// An IdentityScheme is capable of verifying record signatures and +// deriving node addresses. +type IdentityScheme interface { + Verify(r *Record, sig []byte) error + NodeAddr(r *Record) []byte +} + +// SchemeMap is a registry of named identity schemes. +type SchemeMap map[string]IdentityScheme + +func (m SchemeMap) Verify(r *Record, sig []byte) error { + s := m[r.IdentityScheme()] + if s == nil { + return ErrInvalidSig + } + return s.Verify(r, sig) +} + +func (m SchemeMap) NodeAddr(r *Record) []byte { + s := m[r.IdentityScheme()] + if s == nil { + return nil + } + return s.NodeAddr(r) +} + // Record represents a node record. The zero value is an empty record. type Record struct { seq uint64 // sequence number @@ -70,19 +95,14 @@ type pair struct { v rlp.RawValue } -// Signed reports whether the record has a valid signature. -func (r *Record) Signed() bool { - return r.signature != nil -} - // Seq returns the sequence number. func (r *Record) Seq() uint64 { return r.seq } // SetSeq updates the record sequence number. This invalidates any signature on the record. -// Calling SetSeq is usually not required because signing the redord increments the -// sequence number. +// Calling SetSeq is usually not required because setting any key in a signed record +// increments the sequence number. func (r *Record) SetSeq(s uint64) { r.signature = nil r.raw = nil @@ -105,39 +125,48 @@ func (r *Record) Load(e Entry) error { return &KeyError{Key: e.ENRKey(), Err: errNotFound} } -// Set adds or updates the given entry in the record. -// It panics if the value can't be encoded. +// Set adds or updates the given entry in the record. It panics if the value can't be +// encoded. If the record is signed, Set increments the sequence number and invalidates +// the sequence number. func (r *Record) Set(e Entry) { - r.signature = nil - r.raw = nil blob, err := rlp.EncodeToBytes(e) if err != nil { panic(fmt.Errorf("enr: can't encode %s: %v", e.ENRKey(), err)) } + r.invalidate() - i := sort.Search(len(r.pairs), func(i int) bool { return r.pairs[i].k >= e.ENRKey() }) - - if i < len(r.pairs) && r.pairs[i].k == e.ENRKey() { + pairs := make([]pair, len(r.pairs)) + copy(pairs, r.pairs) + i := sort.Search(len(pairs), func(i int) bool { return pairs[i].k >= e.ENRKey() }) + switch { + case i < len(pairs) && pairs[i].k == e.ENRKey(): // element is present at r.pairs[i] - r.pairs[i].v = blob - return - } else if i < len(r.pairs) { + pairs[i].v = blob + case i < len(r.pairs): // insert pair before i-th elem el := pair{e.ENRKey(), blob} - r.pairs = append(r.pairs, pair{}) - copy(r.pairs[i+1:], r.pairs[i:]) - r.pairs[i] = el - return + pairs = append(pairs, pair{}) + copy(pairs[i+1:], pairs[i:]) + pairs[i] = el + default: + // element should be placed at the end of r.pairs + pairs = append(pairs, pair{e.ENRKey(), blob}) } + r.pairs = pairs +} - // element should be placed at the end of r.pairs - r.pairs = append(r.pairs, pair{e.ENRKey(), blob}) +func (r *Record) invalidate() { + if r.signature != nil { + r.seq++ + } + r.signature = nil + r.raw = nil } // EncodeRLP implements rlp.Encoder. Encoding fails if // the record is unsigned. func (r Record) EncodeRLP(w io.Writer) error { - if !r.Signed() { + if r.signature == nil { return errEncodeUnsigned } _, err := w.Write(r.raw) @@ -146,25 +175,34 @@ func (r Record) EncodeRLP(w io.Writer) error { // DecodeRLP implements rlp.Decoder. Decoding verifies the signature. func (r *Record) DecodeRLP(s *rlp.Stream) error { - raw, err := s.Raw() + dec, raw, err := decodeRecord(s) if err != nil { return err } + *r = dec + r.raw = raw + return nil +} + +func decodeRecord(s *rlp.Stream) (dec Record, raw []byte, err error) { + raw, err = s.Raw() + if err != nil { + return dec, raw, err + } if len(raw) > SizeLimit { - return errTooBig + return dec, raw, errTooBig } // Decode the RLP container. - dec := Record{raw: raw} s = rlp.NewStream(bytes.NewReader(raw), 0) if _, err := s.List(); err != nil { - return err + return dec, raw, err } if err = s.Decode(&dec.signature); err != nil { - return err + return dec, raw, err } if err = s.Decode(&dec.seq); err != nil { - return err + return dec, raw, err } // The rest of the record contains sorted k/v pairs. var prevkey string @@ -174,62 +212,73 @@ func (r *Record) DecodeRLP(s *rlp.Stream) error { if err == rlp.EOL { break } - return err + return dec, raw, err } if err := s.Decode(&kv.v); err != nil { if err == rlp.EOL { - return errIncompletePair + return dec, raw, errIncompletePair } - return err + return dec, raw, err } if i > 0 { if kv.k == prevkey { - return errDuplicateKey + return dec, raw, errDuplicateKey } if kv.k < prevkey { - return errNotSorted + return dec, raw, errNotSorted } } dec.pairs = append(dec.pairs, kv) prevkey = kv.k } - if err := s.ListEnd(); err != nil { - return err - } + return dec, raw, s.ListEnd() +} - // Verify signature. - if err = dec.verifySignature(); err != nil { - return err +// IdentityScheme returns the name of the identity scheme in the record. +func (r *Record) IdentityScheme() string { + var id ID + r.Load(&id) + return string(id) +} + +// VerifySignature checks whether the record is signed using the given identity scheme. +func (r *Record) VerifySignature(s IdentityScheme) error { + return s.Verify(r, r.signature) +} + +// SetSig sets the record signature. It returns an error if the encoded record is larger +// than the size limit or if the signature is invalid according to the passed scheme. +// +// You can also use SetSig to remove the signature explicitly by passing a nil scheme +// and signature. +// +// SetSig panics when either the scheme or the signature (but not both) are nil. +func (r *Record) SetSig(s IdentityScheme, sig []byte) error { + switch { + // Prevent storing invalid data. + case s == nil && sig != nil: + panic("enr: invalid call to SetSig with non-nil signature but nil scheme") + case s != nil && sig == nil: + panic("enr: invalid call to SetSig with nil signature but non-nil scheme") + // Verify if we have a scheme. + case s != nil: + if err := s.Verify(r, sig); err != nil { + return err + } + raw, err := r.encode(sig) + if err != nil { + return err + } + r.signature, r.raw = sig, raw + // Reset otherwise. + default: + r.signature, r.raw = nil, nil } - *r = dec return nil } -type s256raw []byte - -func (s256raw) ENRKey() string { return "secp256k1" } - -// NodeAddr returns the node address. The return value will be nil if the record is -// unsigned. -func (r *Record) NodeAddr() []byte { - var entry s256raw - if r.Load(&entry) != nil { - return nil - } - return crypto.Keccak256(entry) -} - -// Sign signs the record with the given private key. It updates the record's identity -// scheme, public key and increments the sequence number. Sign returns an error if the -// encoded record is larger than the size limit. -func (r *Record) Sign(privkey *ecdsa.PrivateKey) error { - r.seq = r.seq + 1 - r.Set(ID_SECP256k1_KECCAK) - r.Set(Secp256k1(privkey.PublicKey)) - return r.signAndEncode(privkey) -} - -func (r *Record) appendPairs(list []interface{}) []interface{} { +// AppendElements appends the sequence number and entries to the given slice. +func (r *Record) AppendElements(list []interface{}) []interface{} { list = append(list, r.seq) for _, p := range r.pairs { list = append(list, p.k, p.v) @@ -237,54 +286,15 @@ func (r *Record) appendPairs(list []interface{}) []interface{} { return list } -func (r *Record) signAndEncode(privkey *ecdsa.PrivateKey) error { - // Put record elements into a flat list. Leave room for the signature. - list := make([]interface{}, 1, len(r.pairs)*2+2) - list = r.appendPairs(list) - - // Sign the tail of the list. - h := sha3.NewKeccak256() - rlp.Encode(h, list[1:]) - sig, err := crypto.Sign(h.Sum(nil), privkey) - if err != nil { - return err +func (r *Record) encode(sig []byte) (raw []byte, err error) { + list := make([]interface{}, 1, 2*len(r.pairs)+1) + list[0] = sig + list = r.AppendElements(list) + if raw, err = rlp.EncodeToBytes(list); err != nil { + return nil, err } - sig = sig[:len(sig)-1] // remove v - - // Put signature in front. - r.signature, list[0] = sig, sig - r.raw, err = rlp.EncodeToBytes(list) - if err != nil { - return err + if len(raw) > SizeLimit { + return nil, errTooBig } - if len(r.raw) > SizeLimit { - return errTooBig - } - return nil -} - -func (r *Record) verifySignature() error { - // Get identity scheme, public key, signature. - var id ID - var entry s256raw - if err := r.Load(&id); err != nil { - return err - } else if id != ID_SECP256k1_KECCAK { - return errNoID - } - if err := r.Load(&entry); err != nil { - return err - } else if len(entry) != 33 { - return fmt.Errorf("invalid public key") - } - - // Verify the signature. - list := make([]interface{}, 0, len(r.pairs)*2+1) - list = r.appendPairs(list) - h := sha3.NewKeccak256() - rlp.Encode(h, list) - if !crypto.VerifySignature(entry, h.Sum(nil), r.signature) { - return errInvalidSig - } - return nil + return raw, nil } diff --git a/p2p/enr/enr_test.go b/p2p/enr/enr_test.go index ce7767d105..449c898a84 100644 --- a/p2p/enr/enr_test.go +++ b/p2p/enr/enr_test.go @@ -18,23 +18,17 @@ package enr import ( "bytes" - "encoding/hex" + "encoding/binary" "fmt" "math/rand" "testing" "time" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/rlp" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -var ( - privkey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - pubkey = &privkey.PublicKey -) - var rnd = rand.New(rand.NewSource(time.Now().UnixNano())) func randomString(strlen int) string { @@ -54,63 +48,51 @@ func TestGetSetID(t *testing.T) { assert.Equal(t, id, id2) } -// TestGetSetIP4 tests encoding/decoding and setting/getting of the IP4 key. +// TestGetSetIP4 tests encoding/decoding and setting/getting of the IP key. func TestGetSetIP4(t *testing.T) { - ip := IP4{192, 168, 0, 3} + ip := IP{192, 168, 0, 3} var r Record r.Set(ip) - var ip2 IP4 + var ip2 IP require.NoError(t, r.Load(&ip2)) assert.Equal(t, ip, ip2) } -// TestGetSetIP6 tests encoding/decoding and setting/getting of the IP6 key. +// TestGetSetIP6 tests encoding/decoding and setting/getting of the IP key. func TestGetSetIP6(t *testing.T) { - ip := IP6{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x00, 0x68} + ip := IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x00, 0x68} var r Record r.Set(ip) - var ip2 IP6 + var ip2 IP require.NoError(t, r.Load(&ip2)) assert.Equal(t, ip, ip2) } // TestGetSetDiscPort tests encoding/decoding and setting/getting of the DiscPort key. -func TestGetSetDiscPort(t *testing.T) { - port := DiscPort(30309) +func TestGetSetUDP(t *testing.T) { + port := UDP(30309) var r Record r.Set(port) - var port2 DiscPort + var port2 UDP require.NoError(t, r.Load(&port2)) assert.Equal(t, port, port2) } -// TestGetSetSecp256k1 tests encoding/decoding and setting/getting of the Secp256k1 key. -func TestGetSetSecp256k1(t *testing.T) { - var r Record - if err := r.Sign(privkey); err != nil { - t.Fatal(err) - } - - var pk Secp256k1 - require.NoError(t, r.Load(&pk)) - assert.EqualValues(t, pubkey, &pk) -} - func TestLoadErrors(t *testing.T) { var r Record - ip4 := IP4{127, 0, 0, 1} + ip4 := IP{127, 0, 0, 1} r.Set(ip4) // Check error for missing keys. - var ip6 IP6 - err := r.Load(&ip6) + var udp UDP + err := r.Load(&udp) if !IsNotFound(err) { t.Error("IsNotFound should return true for missing key") } - assert.Equal(t, &KeyError{Key: ip6.ENRKey(), Err: errNotFound}, err) + assert.Equal(t, &KeyError{Key: udp.ENRKey(), Err: errNotFound}, err) // Check error for invalid keys. var list []uint @@ -167,40 +149,49 @@ func TestSortedGetAndSet(t *testing.T) { func TestDirty(t *testing.T) { var r Record - if r.Signed() { - t.Error("Signed returned true for zero record") - } if _, err := rlp.EncodeToBytes(r); err != errEncodeUnsigned { t.Errorf("expected errEncodeUnsigned, got %#v", err) } - require.NoError(t, r.Sign(privkey)) - if !r.Signed() { - t.Error("Signed return false for signed record") + require.NoError(t, signTest([]byte{5}, &r)) + if len(r.signature) == 0 { + t.Error("record is not signed") } _, err := rlp.EncodeToBytes(r) assert.NoError(t, err) r.SetSeq(3) - if r.Signed() { - t.Error("Signed returned true for modified record") + if len(r.signature) != 0 { + t.Error("signature still set after modification") } if _, err := rlp.EncodeToBytes(r); err != errEncodeUnsigned { t.Errorf("expected errEncodeUnsigned, got %#v", err) } } +func TestSeq(t *testing.T) { + var r Record + + assert.Equal(t, uint64(0), r.Seq()) + r.Set(UDP(1)) + assert.Equal(t, uint64(0), r.Seq()) + signTest([]byte{5}, &r) + assert.Equal(t, uint64(0), r.Seq()) + r.Set(UDP(2)) + assert.Equal(t, uint64(1), r.Seq()) +} + // TestGetSetOverwrite tests value overwrite when setting a new value with an existing key in record. func TestGetSetOverwrite(t *testing.T) { var r Record - ip := IP4{192, 168, 0, 3} + ip := IP{192, 168, 0, 3} r.Set(ip) - ip2 := IP4{192, 168, 0, 4} + ip2 := IP{192, 168, 0, 4} r.Set(ip2) - var ip3 IP4 + var ip3 IP require.NoError(t, r.Load(&ip3)) assert.Equal(t, ip2, ip3) } @@ -208,9 +199,9 @@ func TestGetSetOverwrite(t *testing.T) { // TestSignEncodeAndDecode tests signing, RLP encoding and RLP decoding of a record. func TestSignEncodeAndDecode(t *testing.T) { var r Record - r.Set(DiscPort(30303)) - r.Set(IP4{127, 0, 0, 1}) - require.NoError(t, r.Sign(privkey)) + r.Set(UDP(30303)) + r.Set(IP{127, 0, 0, 1}) + require.NoError(t, signTest([]byte{5}, &r)) blob, err := rlp.EncodeToBytes(r) require.NoError(t, err) @@ -224,62 +215,20 @@ func TestSignEncodeAndDecode(t *testing.T) { assert.Equal(t, blob, blob2) } -func TestNodeAddr(t *testing.T) { - var r Record - if addr := r.NodeAddr(); addr != nil { - t.Errorf("wrong address on empty record: got %v, want %v", addr, nil) - } - - require.NoError(t, r.Sign(privkey)) - expected := "caaa1485d83b18b32ed9ad666026151bf0cae8a0a88c857ae2d4c5be2daa6726" - assert.Equal(t, expected, hex.EncodeToString(r.NodeAddr())) -} - -var pyRecord, _ = hex.DecodeString("f896b840954dc36583c1f4b69ab59b1375f362f06ee99f3723cd77e64b6de6d211c27d7870642a79d4516997f94091325d2a7ca6215376971455fb221d34f35b277149a1018664697363763582765f82696490736563703235366b312d6b656363616b83697034847f00000189736563703235366b31a103ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd3138") - -// TestPythonInterop checks that we can decode and verify a record produced by the Python -// implementation. -func TestPythonInterop(t *testing.T) { - var r Record - if err := rlp.DecodeBytes(pyRecord, &r); err != nil { - t.Fatalf("can't decode: %v", err) - } - - var ( - wantAddr, _ = hex.DecodeString("caaa1485d83b18b32ed9ad666026151bf0cae8a0a88c857ae2d4c5be2daa6726") - wantSeq = uint64(1) - wantIP = IP4{127, 0, 0, 1} - wantDiscport = DiscPort(30303) - ) - if r.Seq() != wantSeq { - t.Errorf("wrong seq: got %d, want %d", r.Seq(), wantSeq) - } - if addr := r.NodeAddr(); !bytes.Equal(addr, wantAddr) { - t.Errorf("wrong addr: got %x, want %x", addr, wantAddr) - } - want := map[Entry]interface{}{new(IP4): &wantIP, new(DiscPort): &wantDiscport} - for k, v := range want { - desc := fmt.Sprintf("loading key %q", k.ENRKey()) - if assert.NoError(t, r.Load(k), desc) { - assert.Equal(t, k, v, desc) - } - } -} - // TestRecordTooBig tests that records bigger than SizeLimit bytes cannot be signed. func TestRecordTooBig(t *testing.T) { var r Record key := randomString(10) // set a big value for random key, expect error - r.Set(WithEntry(key, randomString(300))) - if err := r.Sign(privkey); err != errTooBig { + r.Set(WithEntry(key, randomString(SizeLimit))) + if err := signTest([]byte{5}, &r); err != errTooBig { t.Fatalf("expected to get errTooBig, got %#v", err) } // set an acceptable value for random key, expect no error r.Set(WithEntry(key, randomString(100))) - require.NoError(t, r.Sign(privkey)) + require.NoError(t, signTest([]byte{5}, &r)) } // TestSignEncodeAndDecodeRandom tests encoding/decoding of records containing random key/value pairs. @@ -295,7 +244,7 @@ func TestSignEncodeAndDecodeRandom(t *testing.T) { r.Set(WithEntry(key, &value)) } - require.NoError(t, r.Sign(privkey)) + require.NoError(t, signTest([]byte{5}, &r)) _, err := rlp.EncodeToBytes(r) require.NoError(t, err) @@ -308,11 +257,40 @@ func TestSignEncodeAndDecodeRandom(t *testing.T) { } } -func BenchmarkDecode(b *testing.B) { - var r Record - for i := 0; i < b.N; i++ { - rlp.DecodeBytes(pyRecord, &r) - } - b.StopTimer() - r.NodeAddr() +type testSig struct{} + +type testID []byte + +func (id testID) ENRKey() string { return "testid" } + +func signTest(id []byte, r *Record) error { + r.Set(ID("test")) + r.Set(testID(id)) + return r.SetSig(testSig{}, makeTestSig(id, r.Seq())) +} + +func makeTestSig(id []byte, seq uint64) []byte { + sig := make([]byte, 8, len(id)+8) + binary.BigEndian.PutUint64(sig[:8], seq) + sig = append(sig, id...) + return sig +} + +func (testSig) Verify(r *Record, sig []byte) error { + var id []byte + if err := r.Load((*testID)(&id)); err != nil { + return err + } + if !bytes.Equal(sig, makeTestSig(id, r.Seq())) { + return ErrInvalidSig + } + return nil +} + +func (testSig) NodeAddr(r *Record) []byte { + var id []byte + if err := r.Load((*testID)(&id)); err != nil { + return nil + } + return id } diff --git a/p2p/enr/entries.go b/p2p/enr/entries.go index 7591e6effb..347990ab64 100644 --- a/p2p/enr/entries.go +++ b/p2p/enr/entries.go @@ -17,12 +17,10 @@ package enr import ( - "crypto/ecdsa" "fmt" "io" "net" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/rlp" ) @@ -57,87 +55,47 @@ func WithEntry(k string, v interface{}) Entry { return &generic{key: k, value: v} } -// DiscPort is the "discv5" key, which holds the UDP port for discovery v5. -type DiscPort uint16 +// TCP is the "tcp" key, which holds the TCP port of the node. +type TCP uint16 -func (v DiscPort) ENRKey() string { return "discv5" } +func (v TCP) ENRKey() string { return "tcp" } + +// UDP is the "udp" key, which holds the UDP port of the node. +type UDP uint16 + +func (v UDP) ENRKey() string { return "udp" } // ID is the "id" key, which holds the name of the identity scheme. type ID string +const IDv4 = ID("v4") // the default identity scheme + func (v ID) ENRKey() string { return "id" } -// IP4 is the "ip4" key, which holds a 4-byte IPv4 address. -type IP4 net.IP +// IP is the "ip" key, which holds the IP address of the node. +type IP net.IP -func (v IP4) ENRKey() string { return "ip4" } +func (v IP) ENRKey() string { return "ip" } // EncodeRLP implements rlp.Encoder. -func (v IP4) EncodeRLP(w io.Writer) error { - ip4 := net.IP(v).To4() - if ip4 == nil { - return fmt.Errorf("invalid IPv4 address: %v", v) +func (v IP) EncodeRLP(w io.Writer) error { + if ip4 := net.IP(v).To4(); ip4 != nil { + return rlp.Encode(w, ip4) } - return rlp.Encode(w, ip4) + return rlp.Encode(w, net.IP(v)) } // DecodeRLP implements rlp.Decoder. -func (v *IP4) DecodeRLP(s *rlp.Stream) error { +func (v *IP) DecodeRLP(s *rlp.Stream) error { if err := s.Decode((*net.IP)(v)); err != nil { return err } - if len(*v) != 4 { - return fmt.Errorf("invalid IPv4 address, want 4 bytes: %v", *v) + if len(*v) != 4 && len(*v) != 16 { + return fmt.Errorf("invalid IP address, want 4 or 16 bytes: %v", *v) } return nil } -// IP6 is the "ip6" key, which holds a 16-byte IPv6 address. -type IP6 net.IP - -func (v IP6) ENRKey() string { return "ip6" } - -// EncodeRLP implements rlp.Encoder. -func (v IP6) EncodeRLP(w io.Writer) error { - ip6 := net.IP(v) - return rlp.Encode(w, ip6) -} - -// DecodeRLP implements rlp.Decoder. -func (v *IP6) DecodeRLP(s *rlp.Stream) error { - if err := s.Decode((*net.IP)(v)); err != nil { - return err - } - if len(*v) != 16 { - return fmt.Errorf("invalid IPv6 address, want 16 bytes: %v", *v) - } - return nil -} - -// Secp256k1 is the "secp256k1" key, which holds a public key. -type Secp256k1 ecdsa.PublicKey - -func (v Secp256k1) ENRKey() string { return "secp256k1" } - -// EncodeRLP implements rlp.Encoder. -func (v Secp256k1) EncodeRLP(w io.Writer) error { - return rlp.Encode(w, crypto.CompressPubkey((*ecdsa.PublicKey)(&v))) -} - -// DecodeRLP implements rlp.Decoder. -func (v *Secp256k1) DecodeRLP(s *rlp.Stream) error { - buf, err := s.Bytes() - if err != nil { - return err - } - pk, err := crypto.DecompressPubkey(buf) - if err != nil { - return err - } - *v = (Secp256k1)(*pk) - return nil -} - // KeyError is an error related to a key. type KeyError struct { Key string diff --git a/p2p/message.go b/p2p/message.go index 5690494bf4..ac12666e41 100644 --- a/p2p/message.go +++ b/p2p/message.go @@ -22,13 +22,11 @@ import ( "fmt" "io" "io/ioutil" - "net" - "sync" "sync/atomic" "time" "github.com/ethereum/go-ethereum/event" - "github.com/ethereum/go-ethereum/p2p/discover" + "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/rlp" ) @@ -112,30 +110,6 @@ func SendItems(w MsgWriter, msgcode uint64, elems ...interface{}) error { return Send(w, msgcode, elems) } -// netWrapper wraps a MsgReadWriter with locks around -// ReadMsg/WriteMsg and applies read/write deadlines. -type netWrapper struct { - rmu, wmu sync.Mutex - - rtimeout, wtimeout time.Duration - conn net.Conn - wrapped MsgReadWriter -} - -func (rw *netWrapper) ReadMsg() (Msg, error) { - rw.rmu.Lock() - defer rw.rmu.Unlock() - rw.conn.SetReadDeadline(time.Now().Add(rw.rtimeout)) - return rw.wrapped.ReadMsg() -} - -func (rw *netWrapper) WriteMsg(msg Msg) error { - rw.wmu.Lock() - defer rw.wmu.Unlock() - rw.conn.SetWriteDeadline(time.Now().Add(rw.wtimeout)) - return rw.wrapped.WriteMsg(msg) -} - // eofSignal wraps a reader with eof signaling. the eof channel is // closed when the wrapped reader returns an error or when count bytes // have been read. @@ -255,21 +229,20 @@ func ExpectMsg(r MsgReader, code uint64, content interface{}) error { } if content == nil { return msg.Discard() - } else { - contentEnc, err := rlp.EncodeToBytes(content) - if err != nil { - panic("content encode error: " + err.Error()) - } - if int(msg.Size) != len(contentEnc) { - return fmt.Errorf("message size mismatch: got %d, want %d", msg.Size, len(contentEnc)) - } - actualContent, err := ioutil.ReadAll(msg.Payload) - if err != nil { - return err - } - if !bytes.Equal(actualContent, contentEnc) { - return fmt.Errorf("message payload mismatch:\ngot: %x\nwant: %x", actualContent, contentEnc) - } + } + contentEnc, err := rlp.EncodeToBytes(content) + if err != nil { + panic("content encode error: " + err.Error()) + } + if int(msg.Size) != len(contentEnc) { + return fmt.Errorf("message size mismatch: got %d, want %d", msg.Size, len(contentEnc)) + } + actualContent, err := ioutil.ReadAll(msg.Payload) + if err != nil { + return err + } + if !bytes.Equal(actualContent, contentEnc) { + return fmt.Errorf("message payload mismatch:\ngot: %x\nwant: %x", actualContent, contentEnc) } return nil } @@ -280,13 +253,13 @@ type msgEventer struct { MsgReadWriter feed *event.Feed - peerID discover.NodeID + peerID enode.ID Protocol string } // newMsgEventer returns a msgEventer which sends message events to the given // feed -func newMsgEventer(rw MsgReadWriter, feed *event.Feed, peerID discover.NodeID, proto string) *msgEventer { +func newMsgEventer(rw MsgReadWriter, feed *event.Feed, peerID enode.ID, proto string) *msgEventer { return &msgEventer{ MsgReadWriter: rw, feed: feed, @@ -297,15 +270,15 @@ func newMsgEventer(rw MsgReadWriter, feed *event.Feed, peerID discover.NodeID, p // ReadMsg reads a message from the underlying MsgReadWriter and emits a // "message received" event -func (self *msgEventer) ReadMsg() (Msg, error) { - msg, err := self.MsgReadWriter.ReadMsg() +func (ev *msgEventer) ReadMsg() (Msg, error) { + msg, err := ev.MsgReadWriter.ReadMsg() if err != nil { return msg, err } - self.feed.Send(&PeerEvent{ + ev.feed.Send(&PeerEvent{ Type: PeerEventTypeMsgRecv, - Peer: self.peerID, - Protocol: self.Protocol, + Peer: ev.peerID, + Protocol: ev.Protocol, MsgCode: &msg.Code, MsgSize: &msg.Size, }) @@ -314,15 +287,15 @@ func (self *msgEventer) ReadMsg() (Msg, error) { // WriteMsg writes a message to the underlying MsgReadWriter and emits a // "message sent" event -func (self *msgEventer) WriteMsg(msg Msg) error { - err := self.MsgReadWriter.WriteMsg(msg) +func (ev *msgEventer) WriteMsg(msg Msg) error { + err := ev.MsgReadWriter.WriteMsg(msg) if err != nil { return err } - self.feed.Send(&PeerEvent{ + ev.feed.Send(&PeerEvent{ Type: PeerEventTypeMsgSend, - Peer: self.peerID, - Protocol: self.Protocol, + Peer: ev.peerID, + Protocol: ev.Protocol, MsgCode: &msg.Code, MsgSize: &msg.Size, }) @@ -331,8 +304,8 @@ func (self *msgEventer) WriteMsg(msg Msg) error { // Close closes the underlying MsgReadWriter if it implements the io.Closer // interface -func (self *msgEventer) Close() error { - if v, ok := self.MsgReadWriter.(io.Closer); ok { +func (ev *msgEventer) Close() error { + if v, ok := ev.MsgReadWriter.(io.Closer); ok { return v.Close() } return nil diff --git a/p2p/metrics.go b/p2p/metrics.go index 98b61901d5..8df82bb074 100644 --- a/p2p/metrics.go +++ b/p2p/metrics.go @@ -19,53 +19,214 @@ package p2p import ( + "fmt" "net" + "sync" + "sync/atomic" + "time" + "github.com/ethereum/go-ethereum/p2p/enode" + + "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" ) -var ( - ingressConnectMeter = metrics.NewMeter("p2p/InboundConnects") - ingressTrafficMeter = metrics.NewMeter("p2p/InboundTraffic") - egressConnectMeter = metrics.NewMeter("p2p/OutboundConnects") - egressTrafficMeter = metrics.NewMeter("p2p/OutboundTraffic") +const ( + MetricsInboundConnects = "p2p/InboundConnects" // Name for the registered inbound connects meter + MetricsInboundTraffic = "p2p/InboundTraffic" // Name for the registered inbound traffic meter + MetricsOutboundConnects = "p2p/OutboundConnects" // Name for the registered outbound connects meter + MetricsOutboundTraffic = "p2p/OutboundTraffic" // Name for the registered outbound traffic meter + + MeteredPeerLimit = 1024 // This amount of peers are individually metered ) -// meteredConn is a wrapper around a network TCP connection that meters both the -// inbound and outbound network traffic. -type meteredConn struct { - *net.TCPConn // Network connection to wrap with metering +var ( + ingressConnectMeter = metrics.NewRegisteredMeter(MetricsInboundConnects, nil) // Meter counting the ingress connections + ingressTrafficMeter = metrics.NewRegisteredMeter(MetricsInboundTraffic, nil) // Meter metering the cumulative ingress traffic + egressConnectMeter = metrics.NewRegisteredMeter(MetricsOutboundConnects, nil) // Meter counting the egress connections + egressTrafficMeter = metrics.NewRegisteredMeter(MetricsOutboundTraffic, nil) // Meter metering the cumulative egress traffic + + PeerIngressRegistry = metrics.NewPrefixedChildRegistry(metrics.EphemeralRegistry, MetricsInboundTraffic+"/") // Registry containing the peer ingress + PeerEgressRegistry = metrics.NewPrefixedChildRegistry(metrics.EphemeralRegistry, MetricsOutboundTraffic+"/") // Registry containing the peer egress + + meteredPeerFeed event.Feed // Event feed for peer metrics + meteredPeerCount int32 // Actually stored peer connection count +) + +// MeteredPeerEventType is the type of peer events emitted by a metered connection. +type MeteredPeerEventType int + +const ( + // PeerConnected is the type of event emitted when a peer successfully + // made the handshake. + PeerConnected MeteredPeerEventType = iota + + // PeerDisconnected is the type of event emitted when a peer disconnects. + PeerDisconnected + + // PeerHandshakeFailed is the type of event emitted when a peer fails to + // make the handshake or disconnects before the handshake. + PeerHandshakeFailed +) + +// MeteredPeerEvent is an event emitted when peers connect or disconnect. +type MeteredPeerEvent struct { + Type MeteredPeerEventType // Type of peer event + IP net.IP // IP address of the peer + ID enode.ID // NodeID of the peer + Elapsed time.Duration // Time elapsed between the connection and the handshake/disconnection + Ingress uint64 // Ingress count at the moment of the event + Egress uint64 // Egress count at the moment of the event } -// newMeteredConn creates a new metered connection, also bumping the ingress or -// egress connection meter. If the metrics system is disabled, this function -// returns the original object. -func newMeteredConn(conn net.Conn, ingress bool) net.Conn { +// SubscribeMeteredPeerEvent registers a subscription for peer life-cycle events +// if metrics collection is enabled. +func SubscribeMeteredPeerEvent(ch chan<- MeteredPeerEvent) event.Subscription { + return meteredPeerFeed.Subscribe(ch) +} + +// meteredConn is a wrapper around a net.Conn that meters both the +// inbound and outbound network traffic. +type meteredConn struct { + net.Conn // Network connection to wrap with metering + + connected time.Time // Connection time of the peer + ip net.IP // IP address of the peer + id enode.ID // NodeID of the peer + + // trafficMetered denotes if the peer is registered in the traffic registries. + // Its value is true if the metered peer count doesn't reach the limit in the + // moment of the peer's connection. + trafficMetered bool + ingressMeter metrics.Meter // Meter for the read bytes of the peer + egressMeter metrics.Meter // Meter for the written bytes of the peer + + lock sync.RWMutex // Lock protecting the metered connection's internals +} + +// newMeteredConn creates a new metered connection, bumps the ingress or egress +// connection meter and also increases the metered peer count. If the metrics +// system is disabled or the IP address is unspecified, this function returns +// the original object. +func newMeteredConn(conn net.Conn, ingress bool, ip net.IP) net.Conn { // Short circuit if metrics are disabled if !metrics.Enabled { return conn } - // Otherwise bump the connection counters and wrap the connection + if ip.IsUnspecified() { + log.Warn("Peer IP is unspecified") + return conn + } + // Bump the connection counters and wrap the connection if ingress { ingressConnectMeter.Mark(1) } else { egressConnectMeter.Mark(1) } - return &meteredConn{conn.(*net.TCPConn)} + return &meteredConn{ + Conn: conn, + ip: ip, + connected: time.Now(), + } } -// Read delegates a network read to the underlying connection, bumping the ingress -// traffic meter along the way. +// Read delegates a network read to the underlying connection, bumping the common +// and the peer ingress traffic meters along the way. func (c *meteredConn) Read(b []byte) (n int, err error) { - n, err = c.TCPConn.Read(b) + n, err = c.Conn.Read(b) ingressTrafficMeter.Mark(int64(n)) - return + c.lock.RLock() + if c.trafficMetered { + c.ingressMeter.Mark(int64(n)) + } + c.lock.RUnlock() + return n, err } -// Write delegates a network write to the underlying connection, bumping the -// egress traffic meter along the way. +// Write delegates a network write to the underlying connection, bumping the common +// and the peer egress traffic meters along the way. func (c *meteredConn) Write(b []byte) (n int, err error) { - n, err = c.TCPConn.Write(b) + n, err = c.Conn.Write(b) egressTrafficMeter.Mark(int64(n)) - return + c.lock.RLock() + if c.trafficMetered { + c.egressMeter.Mark(int64(n)) + } + c.lock.RUnlock() + return n, err +} + +// handshakeDone is called when a peer handshake is done. Registers the peer to +// 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) { + if atomic.AddInt32(&meteredPeerCount, 1) >= MeteredPeerLimit { + // Don't register the peer in the traffic registries. + atomic.AddInt32(&meteredPeerCount, -1) + c.lock.Lock() + c.id, c.trafficMetered = id, false + c.lock.Unlock() + log.Warn("Metered peer count reached the limit") + } else { + key := fmt.Sprintf("%s/%s", c.ip, id.String()) + c.lock.Lock() + c.id, c.trafficMetered = id, true + c.ingressMeter = metrics.NewRegisteredMeter(key, PeerIngressRegistry) + c.egressMeter = metrics.NewRegisteredMeter(key, PeerEgressRegistry) + c.lock.Unlock() + } + meteredPeerFeed.Send(MeteredPeerEvent{ + Type: PeerConnected, + IP: c.ip, + ID: id, + Elapsed: time.Since(c.connected), + }) +} + +// Close delegates a close operation to the underlying connection, unregisters +// the peer from the traffic registries and emits close event. +func (c *meteredConn) Close() error { + err := c.Conn.Close() + c.lock.RLock() + if c.id == (enode.ID{}) { + // If the peer disconnects before the handshake. + c.lock.RUnlock() + meteredPeerFeed.Send(MeteredPeerEvent{ + Type: PeerHandshakeFailed, + IP: c.ip, + Elapsed: time.Since(c.connected), + }) + return err + } + id := c.id + if !c.trafficMetered { + // If the peer isn't registered in the traffic registries. + c.lock.RUnlock() + meteredPeerFeed.Send(MeteredPeerEvent{ + Type: PeerDisconnected, + IP: c.ip, + ID: id, + }) + return err + } + ingress, egress := uint64(c.ingressMeter.Count()), uint64(c.egressMeter.Count()) + c.lock.RUnlock() + + // Decrement the metered peer count + atomic.AddInt32(&meteredPeerCount, -1) + + // Unregister the peer from the traffic registries + key := fmt.Sprintf("%s/%s", c.ip, id) + PeerIngressRegistry.Unregister(key) + PeerEgressRegistry.Unregister(key) + + meteredPeerFeed.Send(MeteredPeerEvent{ + Type: PeerDisconnected, + IP: c.ip, + ID: id, + Ingress: ingress, + Egress: egress, + }) + return err } diff --git a/p2p/nat/nat.go b/p2p/nat/nat.go index a254648c66..8fad921c48 100644 --- a/p2p/nat/nat.go +++ b/p2p/nat/nat.go @@ -129,21 +129,15 @@ func Map(m Interface, c chan struct{}, protocol string, extport, intport int, na // ExtIP assumes that the local machine is reachable on the given // external IP address, and that any required ports were mapped manually. // Mapping operations will not return an error but won't actually do anything. -func ExtIP(ip net.IP) Interface { - if ip == nil { - panic("IP must not be nil") - } - return extIP(ip) -} +type ExtIP net.IP -type extIP net.IP - -func (n extIP) ExternalIP() (net.IP, error) { return net.IP(n), nil } -func (n extIP) String() string { return fmt.Sprintf("ExtIP(%v)", net.IP(n)) } +func (n ExtIP) ExternalIP() (net.IP, error) { return net.IP(n), nil } +func (n ExtIP) String() string { return fmt.Sprintf("ExtIP(%v)", net.IP(n)) } // These do nothing. -func (extIP) AddMapping(string, int, int, string, time.Duration) error { return nil } -func (extIP) DeleteMapping(string, int, int) error { return nil } + +func (ExtIP) AddMapping(string, int, int, string, time.Duration) error { return nil } +func (ExtIP) DeleteMapping(string, int, int) error { return nil } // Any returns a port mapper that tries to discover any supported // mechanism on the local network. diff --git a/p2p/nat/nat_test.go b/p2p/nat/nat_test.go index 469101e997..814e6d9e14 100644 --- a/p2p/nat/nat_test.go +++ b/p2p/nat/nat_test.go @@ -28,7 +28,7 @@ import ( func TestAutoDiscRace(t *testing.T) { ad := startautodisc("thing", func() Interface { time.Sleep(500 * time.Millisecond) - return extIP{33, 44, 55, 66} + return ExtIP{33, 44, 55, 66} }) // Spawn a few concurrent calls to ad.ExternalIP. diff --git a/p2p/nat/natpmp.go b/p2p/nat/natpmp.go index 577a424fbe..8ba9714728 100644 --- a/p2p/nat/natpmp.go +++ b/p2p/nat/natpmp.go @@ -115,8 +115,7 @@ func potentialGateways() (gws []net.IP) { return gws } for _, addr := range ifaddrs { - switch x := addr.(type) { - case *net.IPNet: + if x, ok := addr.(*net.IPNet); ok { if lan10.Contains(x.IP) || lan176.Contains(x.IP) || lan192.Contains(x.IP) { ip := x.IP.Mask(x.Mask).To4() if ip != nil { diff --git a/p2p/nat/natupnp.go b/p2p/nat/natupnp.go index 69099ac043..029143b7bc 100644 --- a/p2p/nat/natupnp.go +++ b/p2p/nat/natupnp.go @@ -81,11 +81,8 @@ func (n *upnp) internalAddress() (net.IP, error) { return nil, err } for _, addr := range addrs { - switch x := addr.(type) { - case *net.IPNet: - if x.Contains(devaddr.IP) { - return x.IP, nil - } + if x, ok := addr.(*net.IPNet); ok && x.Contains(devaddr.IP) { + return x.IP, nil } } } diff --git a/p2p/netutil/iptrack.go b/p2p/netutil/iptrack.go new file mode 100644 index 0000000000..b9cbd5e1ca --- /dev/null +++ b/p2p/netutil/iptrack.go @@ -0,0 +1,130 @@ +// 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 netutil + +import ( + "time" + + "github.com/ethereum/go-ethereum/common/mclock" +) + +// IPTracker predicts the external endpoint, i.e. IP address and port, of the local host +// based on statements made by other hosts. +type IPTracker struct { + window time.Duration + contactWindow time.Duration + minStatements int + clock mclock.Clock + statements map[string]ipStatement + contact map[string]mclock.AbsTime + lastStatementGC mclock.AbsTime + lastContactGC mclock.AbsTime +} + +type ipStatement struct { + endpoint string + time mclock.AbsTime +} + +// NewIPTracker creates an IP tracker. +// +// The window parameters configure the amount of past network events which are kept. The +// minStatements parameter enforces a minimum number of statements which must be recorded +// before any prediction is made. Higher values for these parameters decrease 'flapping' of +// predictions as network conditions change. Window duration values should typically be in +// the range of minutes. +func NewIPTracker(window, contactWindow time.Duration, minStatements int) *IPTracker { + return &IPTracker{ + window: window, + contactWindow: contactWindow, + statements: make(map[string]ipStatement), + minStatements: minStatements, + contact: make(map[string]mclock.AbsTime), + clock: mclock.System{}, + } +} + +// PredictFullConeNAT checks whether the local host is behind full cone NAT. It predicts by +// checking whether any statement has been received from a node we didn't contact before +// the statement was made. +func (it *IPTracker) PredictFullConeNAT() bool { + now := it.clock.Now() + it.gcContact(now) + it.gcStatements(now) + for host, st := range it.statements { + if c, ok := it.contact[host]; !ok || c > st.time { + return true + } + } + return false +} + +// PredictEndpoint returns the current prediction of the external endpoint. +func (it *IPTracker) PredictEndpoint() string { + it.gcStatements(it.clock.Now()) + + // The current strategy is simple: find the endpoint with most statements. + counts := make(map[string]int) + maxcount, max := 0, "" + for _, s := range it.statements { + c := counts[s.endpoint] + 1 + counts[s.endpoint] = c + if c > maxcount && c >= it.minStatements { + maxcount, max = c, s.endpoint + } + } + return max +} + +// AddStatement records that a certain host thinks our external endpoint is the one given. +func (it *IPTracker) AddStatement(host, endpoint string) { + now := it.clock.Now() + it.statements[host] = ipStatement{endpoint, now} + if time.Duration(now-it.lastStatementGC) >= it.window { + it.gcStatements(now) + } +} + +// AddContact records that a packet containing our endpoint information has been sent to a +// certain host. +func (it *IPTracker) AddContact(host string) { + now := it.clock.Now() + it.contact[host] = now + if time.Duration(now-it.lastContactGC) >= it.contactWindow { + it.gcContact(now) + } +} + +func (it *IPTracker) gcStatements(now mclock.AbsTime) { + it.lastStatementGC = now + cutoff := now.Add(-it.window) + for host, s := range it.statements { + if s.time < cutoff { + delete(it.statements, host) + } + } +} + +func (it *IPTracker) gcContact(now mclock.AbsTime) { + it.lastContactGC = now + cutoff := now.Add(-it.contactWindow) + for host, ct := range it.contact { + if ct < cutoff { + delete(it.contact, host) + } + } +} diff --git a/p2p/netutil/iptrack_test.go b/p2p/netutil/iptrack_test.go new file mode 100644 index 0000000000..a9a2998a65 --- /dev/null +++ b/p2p/netutil/iptrack_test.go @@ -0,0 +1,138 @@ +// 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 netutil + +import ( + "fmt" + mrand "math/rand" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common/mclock" +) + +const ( + opStatement = iota + opContact + opPredict + opCheckFullCone +) + +type iptrackTestEvent struct { + op int + time int // absolute, in milliseconds + ip, from string +} + +func TestIPTracker(t *testing.T) { + tests := map[string][]iptrackTestEvent{ + "minStatements": { + {opPredict, 0, "", ""}, + {opStatement, 0, "127.0.0.1", "127.0.0.2"}, + {opPredict, 1000, "", ""}, + {opStatement, 1000, "127.0.0.1", "127.0.0.3"}, + {opPredict, 1000, "", ""}, + {opStatement, 1000, "127.0.0.1", "127.0.0.4"}, + {opPredict, 1000, "127.0.0.1", ""}, + }, + "window": { + {opStatement, 0, "127.0.0.1", "127.0.0.2"}, + {opStatement, 2000, "127.0.0.1", "127.0.0.3"}, + {opStatement, 3000, "127.0.0.1", "127.0.0.4"}, + {opPredict, 10000, "127.0.0.1", ""}, + {opPredict, 10001, "", ""}, // first statement expired + {opStatement, 10100, "127.0.0.1", "127.0.0.2"}, + {opPredict, 10200, "127.0.0.1", ""}, + }, + "fullcone": { + {opContact, 0, "", "127.0.0.2"}, + {opStatement, 10, "127.0.0.1", "127.0.0.2"}, + {opContact, 2000, "", "127.0.0.3"}, + {opStatement, 2010, "127.0.0.1", "127.0.0.3"}, + {opContact, 3000, "", "127.0.0.4"}, + {opStatement, 3010, "127.0.0.1", "127.0.0.4"}, + {opCheckFullCone, 3500, "false", ""}, + }, + "fullcone_2": { + {opContact, 0, "", "127.0.0.2"}, + {opStatement, 10, "127.0.0.1", "127.0.0.2"}, + {opContact, 2000, "", "127.0.0.3"}, + {opStatement, 2010, "127.0.0.1", "127.0.0.3"}, + {opStatement, 3000, "127.0.0.1", "127.0.0.4"}, + {opContact, 3010, "", "127.0.0.4"}, + {opCheckFullCone, 3500, "true", ""}, + }, + } + for name, test := range tests { + t.Run(name, func(t *testing.T) { runIPTrackerTest(t, test) }) + } +} + +func runIPTrackerTest(t *testing.T, evs []iptrackTestEvent) { + var ( + clock mclock.Simulated + it = NewIPTracker(10*time.Second, 10*time.Second, 3) + ) + it.clock = &clock + for i, ev := range evs { + evtime := time.Duration(ev.time) * time.Millisecond + clock.Run(evtime - time.Duration(clock.Now())) + switch ev.op { + case opStatement: + it.AddStatement(ev.from, ev.ip) + case opContact: + it.AddContact(ev.from) + case opPredict: + if pred := it.PredictEndpoint(); pred != ev.ip { + t.Errorf("op %d: wrong prediction %q, want %q", i, pred, ev.ip) + } + case opCheckFullCone: + pred := fmt.Sprintf("%t", it.PredictFullConeNAT()) + if pred != ev.ip { + t.Errorf("op %d: wrong prediction %s, want %s", i, pred, ev.ip) + } + } + } +} + +// This checks that old statements and contacts are GCed even if Predict* isn't called. +func TestIPTrackerForceGC(t *testing.T) { + var ( + clock mclock.Simulated + window = 10 * time.Second + rate = 50 * time.Millisecond + max = int(window/rate) + 1 + it = NewIPTracker(window, window, 3) + ) + it.clock = &clock + + for i := 0; i < 5*max; i++ { + e1 := make([]byte, 4) + e2 := make([]byte, 4) + mrand.Read(e1) + mrand.Read(e2) + it.AddStatement(string(e1), string(e2)) + it.AddContact(string(e1)) + clock.Run(rate) + } + if len(it.contact) > 2*max { + t.Errorf("contacts not GCed, have %d", len(it.contact)) + } + if len(it.statements) > 2*max { + t.Errorf("statements not GCed, have %d", len(it.statements)) + } +} diff --git a/p2p/netutil/net.go b/p2p/netutil/net.go index f6005afd21..656abb6825 100644 --- a/p2p/netutil/net.go +++ b/p2p/netutil/net.go @@ -18,8 +18,11 @@ package netutil import ( + "bytes" "errors" + "fmt" "net" + "sort" "strings" ) @@ -189,3 +192,131 @@ func CheckRelayIP(sender, addr net.IP) error { } return nil } + +// SameNet reports whether two IP addresses have an equal prefix of the given bit length. +func SameNet(bits uint, ip, other net.IP) bool { + ip4, other4 := ip.To4(), other.To4() + switch { + case (ip4 == nil) != (other4 == nil): + return false + case ip4 != nil: + return sameNet(bits, ip4, other4) + default: + return sameNet(bits, ip.To16(), other.To16()) + } +} + +func sameNet(bits uint, ip, other net.IP) bool { + nb := int(bits / 8) + mask := ^byte(0xFF >> (bits % 8)) + if mask != 0 && nb < len(ip) && ip[nb]&mask != other[nb]&mask { + return false + } + return nb <= len(ip) && bytes.Equal(ip[:nb], other[:nb]) +} + +// DistinctNetSet tracks IPs, ensuring that at most N of them +// fall into the same network range. +type DistinctNetSet struct { + Subnet uint // number of common prefix bits + Limit uint // maximum number of IPs in each subnet + + members map[string]uint + buf net.IP +} + +// Add adds an IP address to the set. It returns false (and doesn't add the IP) if the +// number of existing IPs in the defined range exceeds the limit. +func (s *DistinctNetSet) Add(ip net.IP) bool { + key := s.key(ip) + n := s.members[string(key)] + if n < s.Limit { + s.members[string(key)] = n + 1 + return true + } + return false +} + +// Remove removes an IP from the set. +func (s *DistinctNetSet) Remove(ip net.IP) { + key := s.key(ip) + if n, ok := s.members[string(key)]; ok { + if n == 1 { + delete(s.members, string(key)) + } else { + s.members[string(key)] = n - 1 + } + } +} + +// Contains whether the given IP is contained in the set. +func (s DistinctNetSet) Contains(ip net.IP) bool { + key := s.key(ip) + _, ok := s.members[string(key)] + return ok +} + +// Len returns the number of tracked IPs. +func (s DistinctNetSet) Len() int { + n := uint(0) + for _, i := range s.members { + n += i + } + return int(n) +} + +// key encodes the map key for an address into a temporary buffer. +// +// The first byte of key is '4' or '6' to distinguish IPv4/IPv6 address types. +// The remainder of the key is the IP, truncated to the number of bits. +func (s *DistinctNetSet) key(ip net.IP) net.IP { + // Lazily initialize storage. + if s.members == nil { + s.members = make(map[string]uint) + s.buf = make(net.IP, 17) + } + // Canonicalize ip and bits. + typ := byte('6') + if ip4 := ip.To4(); ip4 != nil { + typ, ip = '4', ip4 + } + bits := s.Subnet + if bits > uint(len(ip)*8) { + bits = uint(len(ip) * 8) + } + // Encode the prefix into s.buf. + nb := int(bits / 8) + mask := ^byte(0xFF >> (bits % 8)) + s.buf[0] = typ + buf := append(s.buf[:1], ip[:nb]...) + if nb < len(ip) && mask != 0 { + buf = append(buf, ip[nb]&mask) + } + return buf +} + +// String implements fmt.Stringer +func (s DistinctNetSet) String() string { + var buf bytes.Buffer + buf.WriteString("{") + keys := make([]string, 0, len(s.members)) + for k := range s.members { + keys = append(keys, k) + } + sort.Strings(keys) + for i, k := range keys { + var ip net.IP + if k[0] == '4' { + ip = make(net.IP, 4) + } else { + ip = make(net.IP, 16) + } + copy(ip, k[1:]) + fmt.Fprintf(&buf, "%v×%d", ip, s.members[k]) + if i != len(keys)-1 { + buf.WriteString(" ") + } + } + buf.WriteString("}") + return buf.String() +} diff --git a/p2p/netutil/net_test.go b/p2p/netutil/net_test.go index 1ee1fcb4d6..3a6aa081f2 100644 --- a/p2p/netutil/net_test.go +++ b/p2p/netutil/net_test.go @@ -17,9 +17,11 @@ package netutil import ( + "fmt" "net" "reflect" "testing" + "testing/quick" "github.com/davecgh/go-spew/spew" ) @@ -171,3 +173,90 @@ func BenchmarkCheckRelayIP(b *testing.B) { CheckRelayIP(sender, addr) } } + +func TestSameNet(t *testing.T) { + tests := []struct { + ip, other string + bits uint + want bool + }{ + {"0.0.0.0", "0.0.0.0", 32, true}, + {"0.0.0.0", "0.0.0.1", 0, true}, + {"0.0.0.0", "0.0.0.1", 31, true}, + {"0.0.0.0", "0.0.0.1", 32, false}, + {"0.33.0.1", "0.34.0.2", 8, true}, + {"0.33.0.1", "0.34.0.2", 13, true}, + {"0.33.0.1", "0.34.0.2", 15, false}, + } + + for _, test := range tests { + if ok := SameNet(test.bits, parseIP(test.ip), parseIP(test.other)); ok != test.want { + t.Errorf("SameNet(%d, %s, %s) == %t, want %t", test.bits, test.ip, test.other, ok, test.want) + } + } +} + +func ExampleSameNet() { + // This returns true because the IPs are in the same /24 network: + fmt.Println(SameNet(24, net.IP{127, 0, 0, 1}, net.IP{127, 0, 0, 3})) + // This call returns false: + fmt.Println(SameNet(24, net.IP{127, 3, 0, 1}, net.IP{127, 5, 0, 3})) + // Output: + // true + // false +} + +func TestDistinctNetSet(t *testing.T) { + ops := []struct { + add, remove string + fails bool + }{ + {add: "127.0.0.1"}, + {add: "127.0.0.2"}, + {add: "127.0.0.3", fails: true}, + {add: "127.32.0.1"}, + {add: "127.32.0.2"}, + {add: "127.32.0.3", fails: true}, + {add: "127.33.0.1", fails: true}, + {add: "127.34.0.1"}, + {add: "127.34.0.2"}, + {add: "127.34.0.3", fails: true}, + // Make room for an address, then add again. + {remove: "127.0.0.1"}, + {add: "127.0.0.3"}, + {add: "127.0.0.3", fails: true}, + } + + set := DistinctNetSet{Subnet: 15, Limit: 2} + for _, op := range ops { + var desc string + if op.add != "" { + desc = fmt.Sprintf("Add(%s)", op.add) + if ok := set.Add(parseIP(op.add)); ok != !op.fails { + t.Errorf("%s == %t, want %t", desc, ok, !op.fails) + } + } else { + desc = fmt.Sprintf("Remove(%s)", op.remove) + set.Remove(parseIP(op.remove)) + } + t.Logf("%s: %v", desc, set) + } +} + +func TestDistinctNetSetAddRemove(t *testing.T) { + cfg := &quick.Config{} + fn := func(ips []net.IP) bool { + s := DistinctNetSet{Limit: 3, Subnet: 2} + for _, ip := range ips { + s.Add(ip) + } + for _, ip := range ips { + s.Remove(ip) + } + return s.Len() == 0 + } + + if err := quick.Check(fn, cfg); err != nil { + t.Fatal(err) + } +} diff --git a/p2p/peer.go b/p2p/peer.go index bad1c8c8b2..af019d07a8 100644 --- a/p2p/peer.go +++ b/p2p/peer.go @@ -17,6 +17,7 @@ package p2p import ( + "errors" "fmt" "io" "net" @@ -27,10 +28,15 @@ import ( "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/p2p/discover" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/enr" "github.com/ethereum/go-ethereum/rlp" ) +var ( + ErrShuttingDown = errors.New("shutting down") +) + const ( baseProtocolVersion = 5 baseProtocolLength = uint64(16) @@ -47,8 +53,6 @@ const ( discMsg = 0x01 pingMsg = 0x02 pongMsg = 0x03 - getPeersMsg = 0x04 - peersMsg = 0x05 ) // protoHandshake is the RLP structure of the protocol handshake. @@ -57,7 +61,7 @@ type protoHandshake struct { Name string Caps []Cap ListenPort uint64 - ID discover.NodeID + ID []byte // secp256k1 public key // Ignore additional fields (for forward compatibility). Rest []rlp.RawValue `rlp:"tail"` @@ -87,12 +91,12 @@ const ( // PeerEvent is an event emitted when peers are either added or dropped from // a p2p.Server or when a message is sent or received on a peer connection type PeerEvent struct { - Type PeerEventType `json:"type"` - Peer discover.NodeID `json:"peer"` - Error string `json:"error,omitempty"` - Protocol string `json:"protocol,omitempty"` - MsgCode *uint64 `json:"msg_code,omitempty"` - MsgSize *uint32 `json:"msg_size,omitempty"` + Type PeerEventType `json:"type"` + Peer enode.ID `json:"peer"` + Error string `json:"error,omitempty"` + Protocol string `json:"protocol,omitempty"` + MsgCode *uint64 `json:"msg_code,omitempty"` + MsgSize *uint32 `json:"msg_size,omitempty"` } // Peer represents a connected remote node. @@ -112,17 +116,23 @@ type Peer struct { } // NewPeer returns a peer for testing purposes. -func NewPeer(id discover.NodeID, name string, caps []Cap) *Peer { +func NewPeer(id enode.ID, name string, caps []Cap) *Peer { pipe, _ := net.Pipe() - conn := &conn{fd: pipe, transport: nil, id: id, caps: caps, name: name} + node := enode.SignNull(new(enr.Record), id) + conn := &conn{fd: pipe, transport: nil, node: node, caps: caps, name: name} peer := newPeer(conn, nil) close(peer.closed) // ensures Disconnect doesn't block return peer } // ID returns the node's public key. -func (p *Peer) ID() discover.NodeID { - return p.rw.id +func (p *Peer) ID() enode.ID { + return p.rw.node.ID() +} + +// Node returns the peer's node descriptor. +func (p *Peer) Node() *enode.Node { + return p.rw.node } // Name returns the node name that the remote node advertised. @@ -157,12 +167,13 @@ func (p *Peer) Disconnect(reason DiscReason) { // String implements fmt.Stringer. func (p *Peer) String() string { - return fmt.Sprintf("Peer %x %v", p.rw.id[:8], p.RemoteAddr()) + id := p.ID() + return fmt.Sprintf("Peer %x %v", id[:8], p.RemoteAddr()) } // Inbound returns true if the peer is an inbound connection func (p *Peer) Inbound() bool { - return p.rw.flags&inboundConn != 0 + return p.rw.is(inboundConn) } func newPeer(conn *conn, protocols []Protocol) *Peer { @@ -174,7 +185,7 @@ func newPeer(conn *conn, protocols []Protocol) *Peer { disc: make(chan DiscReason), protoErr: make(chan error, len(protomap)+1), // protocols + pingLoop closed: make(chan struct{}), - log: log.New("id", conn.id, "conn", conn.flags), + log: log.New("id", conn.node.ID(), "conn", conn.flags), } return p } @@ -222,6 +233,7 @@ loop: reason = discReasonForError(err) break loop case err = <-p.disc: + reason = discReasonForError(err) break loop } } @@ -372,7 +384,7 @@ func (p *Peer) getProto(code uint64) (*protoRW, error) { type protoRW struct { Protocol - in chan Msg // receices read messages + in chan Msg // receives read messages closed <-chan struct{} // receives when peer is shutting down wstart <-chan struct{} // receives when write may start werr chan<- error // for write results @@ -394,7 +406,7 @@ func (rw *protoRW) WriteMsg(msg Msg) (err error) { // as well but we don't want to rely on that. rw.werr <- err case <-rw.closed: - err = fmt.Errorf("shutting down") + err = ErrShuttingDown } return err } @@ -413,12 +425,16 @@ func (rw *protoRW) ReadMsg() (Msg, error) { // peer. Sub-protocol independent fields are contained and initialized here, with // protocol specifics delegated to all connected sub-protocols. type PeerInfo struct { - ID string `json:"id"` // Unique node identifier (also the encryption key) - Name string `json:"name"` // Name of the node, including client type, version, OS, custom data - Caps []string `json:"caps"` // Sum-protocols advertised by this particular peer + Enode string `json:"enode"` // Node URL + ID string `json:"id"` // Unique node identifier + Name string `json:"name"` // Name of the node, including client type, version, OS, custom data + Caps []string `json:"caps"` // Protocols advertised by this peer Network struct { LocalAddress string `json:"localAddress"` // Local endpoint of the TCP data connection RemoteAddress string `json:"remoteAddress"` // Remote endpoint of the TCP data connection + Inbound bool `json:"inbound"` + Trusted bool `json:"trusted"` + Static bool `json:"static"` } `json:"network"` Protocols map[string]interface{} `json:"protocols"` // Sub-protocol specific metadata fields } @@ -432,6 +448,7 @@ func (p *Peer) Info() *PeerInfo { } // Assemble the generic peer metadata info := &PeerInfo{ + Enode: p.Node().String(), ID: p.ID().String(), Name: p.Name(), Caps: caps, @@ -439,6 +456,9 @@ func (p *Peer) Info() *PeerInfo { } info.Network.LocalAddress = p.LocalAddr().String() info.Network.RemoteAddress = p.RemoteAddr().String() + info.Network.Inbound = p.rw.is(inboundConn) + info.Network.Trusted = p.rw.is(trustedConn) + info.Network.Static = p.rw.is(staticDialedConn) // Gather all the running protocol infos for _, proto := range p.running { diff --git a/p2p/peer_error.go b/p2p/peer_error.go index a1cddb707b..ab61bfef06 100644 --- a/p2p/peer_error.go +++ b/p2p/peer_error.go @@ -48,8 +48,8 @@ func newPeerError(code int, format string, v ...interface{}) *peerError { return err } -func (self *peerError) Error() string { - return self.message +func (pe *peerError) Error() string { + return pe.message } var errProtocolReturned = errors.New("protocol returned") diff --git a/p2p/peer_test.go b/p2p/peer_test.go index a3e1c74fd8..5aa64a32e1 100644 --- a/p2p/peer_test.go +++ b/p2p/peer_test.go @@ -45,8 +45,8 @@ var discard = Protocol{ func testPeer(protos []Protocol) (func(), *conn, *Peer, <-chan error) { fd1, fd2 := net.Pipe() - c1 := &conn{fd: fd1, transport: newTestTransport(randomID(), fd1)} - c2 := &conn{fd: fd2, transport: newTestTransport(randomID(), fd2)} + c1 := &conn{fd: fd1, node: newNode(randomID(), nil), transport: newTestTransport(&newkey().PublicKey, fd1)} + c2 := &conn{fd: fd2, node: newNode(randomID(), nil), transport: newTestTransport(&newkey().PublicKey, fd2)} for _, p := range protos { c1.caps = append(c1.caps, p.cap()) c2.caps = append(c2.caps, p.cap()) diff --git a/p2p/protocol.go b/p2p/protocol.go index ee747ba23d..9438ab8e47 100644 --- a/p2p/protocol.go +++ b/p2p/protocol.go @@ -19,7 +19,8 @@ package p2p import ( "fmt" - "github.com/ethereum/go-ethereum/p2p/discover" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/enr" ) // Protocol represents a P2P subprotocol implementation. @@ -35,7 +36,7 @@ type Protocol struct { // by the protocol. Length uint64 - // Run is called in a new groutine when the protocol has been + // Run is called in a new goroutine when the protocol has been // negotiated with a peer. It should read and write messages from // rw. The Payload for each message must be fully consumed. // @@ -51,7 +52,10 @@ type Protocol struct { // PeerInfo is an optional helper method to retrieve protocol specific metadata // about a certain peer in the network. If an info retrieval function is set, // but returns nil, it is assumed that the protocol handshake is still running. - PeerInfo func(id discover.NodeID) interface{} + PeerInfo func(id enode.ID) interface{} + + // Attributes contains protocol specific information for the node record. + Attributes []enr.Entry } func (p Protocol) cap() Cap { @@ -64,10 +68,6 @@ type Cap struct { Version uint } -func (cap Cap) RlpData() interface{} { - return []interface{}{cap.Name, cap.Version} -} - func (cap Cap) String() string { return fmt.Sprintf("%s/%d", cap.Name, cap.Version) } @@ -79,3 +79,5 @@ func (cs capsByNameAndVersion) Swap(i, j int) { cs[i], cs[j] = cs[j], cs[i] } func (cs capsByNameAndVersion) Less(i, j int) bool { return cs[i].Name < cs[j].Name || (cs[i].Name == cs[j].Name && cs[i].Version < cs[j].Version) } + +func (capsByNameAndVersion) ENRKey() string { return "cap" } diff --git a/p2p/protocols/accounting.go b/p2p/protocols/accounting.go new file mode 100644 index 0000000000..558247254a --- /dev/null +++ b/p2p/protocols/accounting.go @@ -0,0 +1,182 @@ +// 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 ( + "time" + + "github.com/ethereum/go-ethereum/metrics" +) + +// 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 + Price(interface{}) *Price +} + +type Payer bool + +const ( + Sender = Payer(true) + Receiver = Payer(false) +) + +// Price represents the costs of a message +type Price struct { + 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 +func (p *Price) For(payer Payer, size uint32) int64 { + price := p.Value + if p.PerByte { + price *= uint64(size) + } + if p.Payer == payer { + return 0 - int64(price) + } + return int64(price) +} + +// 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 + 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 +type Accounting struct { + Balance // interface to accounting logic + Prices // interface to prices logic +} + +func NewAccounting(balance Balance, po Prices) *Accounting { + ah := &Accounting{ + Prices: po, + Balance: balance, + } + return ah +} + +// 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 +func (ah *Accounting) Send(peer *Peer, size uint32, msg interface{}) error { + // get the price for a message (through the protocol spec) + price := ah.Price(msg) + // this message doesn't need accounting + if price == nil { + return nil + } + // evaluate the price for sending messages + costToLocalNode := price.For(Sender, size) + // do the accounting + err := ah.Add(costToLocalNode, peer) + // record metrics: just increase counters for user-facing metrics + ah.doMetrics(costToLocalNode, size, err) + return err +} + +// 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 +func (ah *Accounting) Receive(peer *Peer, size uint32, msg interface{}) error { + // get the price for a message (through the protocol spec) + price := ah.Price(msg) + // this message doesn't need accounting + if price == nil { + return nil + } + // evaluate the price for receiving messages + costToLocalNode := price.For(Receiver, size) + // do the accounting + err := ah.Add(costToLocalNode, peer) + // 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" +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" + mPeerDrops.Inc(1) + } + } else { + mBalanceDebit.Inc(price) + 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 + mSelfDrops.Inc(1) + } + } +} diff --git a/p2p/protocols/accounting_api.go b/p2p/protocols/accounting_api.go new file mode 100644 index 0000000000..48e2af9fea --- /dev/null +++ b/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/p2p/protocols/accounting_simulation_test.go b/p2p/protocols/accounting_simulation_test.go new file mode 100644 index 0000000000..e90a1d81d2 --- /dev/null +++ b/p2p/protocols/accounting_simulation_test.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 protocols + +import ( + "context" + "flag" + "fmt" + "io/ioutil" + "math/rand" + "os" + "path/filepath" + "reflect" + "sync" + "testing" + "time" + + "github.com/mattn/go-colorable" + + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/rpc" + + "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" +) + +const ( + content = "123456789" +) + +var ( + nodes = flag.Int("nodes", 30, "number of nodes to create (default 30)") + msgs = flag.Int("msgs", 100, "number of messages sent by node (default 100)") + loglevel = flag.Int("loglevel", 0, "verbosity of logs") + rawlog = flag.Bool("rawlog", false, "remove terminal formatting from logs") +) + +func init() { + flag.Parse() + log.PrintOrigins(true) + log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(!*rawlog)))) +} + +//TestAccountingSimulation runs a p2p/simulations simulation +//It creates a *nodes number of nodes, connects each one with each other, +//then sends out a random selection of messages up to *msgs amount of messages +//from the test protocol spec. +//The spec has some accounted messages defined through the Prices interface. +//The test does accounting for all the message exchanged, and then checks +//that every node has the same balance with a peer, but with opposite signs. +//Balance(AwithB) = 0 - Balance(BwithA) or Abs|Balance(AwithB)| == Abs|Balance(BwithA)| +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) { + return bal.newNode(), nil + }, + } + //setup the simulation + adapter := adapters.NewSimAdapter(services) + net := simulations.NewNetwork(adapter, &simulations.NetworkConfig{DefaultService: "accounting"}) + defer net.Shutdown() + + // we send msgs messages per node, wait for all messages to arrive + bal.wg.Add(*nodes * *msgs) + trigger := make(chan enode.ID) + go func() { + // wait for all of them to arrive + bal.wg.Wait() + // then trigger a check + // the selected node for the trigger is irrelevant, + // we just want to trigger the end of the simulation + trigger <- net.Nodes[0].ID() + }() + + // create nodes and start them + for i := 0; i < *nodes; i++ { + conf := adapters.RandomNodeConfig() + bal.id2n[conf.ID] = i + if _, err := net.NewNodeWithConfig(conf); err != nil { + t.Fatal(err) + } + if err := net.Start(conf.ID); err != nil { + t.Fatal(err) + } + } + // fully connect nodes + for i, n := range net.Nodes { + for _, m := range net.Nodes[i+1:] { + if err := net.Connect(n.ID(), m.ID()); err != nil { + t.Fatal(err) + } + } + } + + // empty action + action := func(ctx context.Context) error { + return nil + } + // check always checks out + check := func(ctx context.Context, id enode.ID) (bool, error) { + return true, nil + } + + // run simulation + timeout := 30 * time.Second + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + result := simulations.NewSimulation(net).Run(ctx, &simulations.Step{ + Action: action, + Trigger: trigger, + Expect: &simulations.Expectation{ + Nodes: []enode.ID{net.Nodes[0].ID()}, + Check: check, + }, + }) + + if result.Error != nil { + t.Fatal(result.Error) + } + + // check if balance matrix is symmetric + if err := bal.symmetric(); err != nil { + t.Fatal(err) + } +} + +// matrix is a matrix of nodes and its balances +// matrix is in fact a linear array of size n*n, +// so the balance for any node A with B is at index +// A*n + B, while the balance of node B with A is at +// B*n + A +// (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 +} + +// create a new matrix +func newMatrix(n int) *matrix { + return &matrix{ + n: n, + m: make([]int64, n*n), + } +} + +// called from the testBalance's Add accounting function: register balance change +func (m *matrix) add(i, j int, v int64) error { + // index for the balance of local node i with remote nodde j is + // i * number of nodes + remote node + mi := i*m.n + j + // register that balance + m.m[mi] += v + return nil +} + +// check that the balances are symmetric: +// balance of node i with node j is the same as j with i but with inverted signs +func (m *matrix) symmetric() error { + //iterate all nodes + for i := 0; i < m.n; i++ { + //iterate starting +1 + for j := i + 1; j < m.n; j++ { + log.Debug("bal", "1", i, "2", j, "i,j", m.m[i*m.n+j], "j,i", m.m[j*m.n+i]) + if m.m[i*m.n+j] != -m.m[j*m.n+i] { + return fmt.Errorf("value mismatch. m[%v, %v] = %v; m[%v, %v] = %v", i, j, m.m[i*m.n+j], j, i, m.m[j*m.n+i]) + } + } + } + return nil +} + +// all the balances +type balances struct { + i int + *matrix + id2n map[enode.ID]int + wg *sync.WaitGroup +} + +func newBalances(n int) *balances { + return &balances{ + matrix: newMatrix(n), + id2n: make(map[enode.ID]int), + wg: &sync.WaitGroup{}, + } +} + +// create a new testNode for every node created as part of the service +func (b *balances) newNode() *testNode { + defer func() { b.i++ }() + return &testNode{ + bal: b, + i: b.i, + peers: make([]*testPeer, b.n), //a node will be connected to n-1 peers + } +} + +type testNode struct { + bal *balances + i int + lock sync.Mutex + peers []*testPeer + peerCount int +} + +// do the accounting for the peer's test protocol +// testNode implements protocols.Balance +func (t *testNode) Add(a int64, p *Peer) error { + //get the index for the remote peer + remote := t.bal.id2n[p.ID()] + log.Debug("add", "local", t.i, "remote", remote, "amount", a) + return t.bal.add(t.i, remote, a) +} + +//run the p2p protocol +//for every node, represented by testNode, create a remote testPeer +func (t *testNode) run(p *p2p.Peer, rw p2p.MsgReadWriter) error { + spec := createTestSpec() + //create accounting hook + spec.Hook = NewAccounting(t, &dummyPrices{}) + + //create a peer for this node + tp := &testPeer{NewPeer(p, rw, spec), t.i, t.bal.id2n[p.ID()], t.bal.wg} + t.lock.Lock() + t.peers[t.bal.id2n[p.ID()]] = tp + t.peerCount++ + if t.peerCount == t.bal.n-1 { + //when all peer connections are established, start sending messages from this peer + go t.send() + } + t.lock.Unlock() + return tp.Run(tp.handle) +} + +// p2p message receive handler function +func (tp *testPeer) handle(ctx context.Context, msg interface{}) error { + tp.wg.Done() + log.Debug("receive", "from", tp.remote, "to", tp.local, "type", reflect.TypeOf(msg), "msg", msg) + return nil +} + +type testPeer struct { + *Peer + local, remote int + wg *sync.WaitGroup +} + +func (t *testNode) send() { + log.Debug("start sending") + for i := 0; i < *msgs; i++ { + //determine randomly to which peer to send + whom := rand.Intn(t.bal.n - 1) + if whom >= t.i { + whom++ + } + t.lock.Lock() + p := t.peers[whom] + t.lock.Unlock() + + //determine a random message from the spec's messages to be sent + which := rand.Intn(len(p.spec.Messages)) + msg := p.spec.Messages[which] + switch msg.(type) { + case *perBytesMsgReceiverPays: + msg = &perBytesMsgReceiverPays{Content: content[:rand.Intn(len(content))]} + case *perBytesMsgSenderPays: + msg = &perBytesMsgSenderPays{Content: content[:rand.Intn(len(content))]} + } + log.Debug("send", "from", t.i, "to", whom, "type", reflect.TypeOf(msg), "msg", msg) + p.Send(context.TODO(), msg) + } +} + +// define the protocol +func (t *testNode) Protocols() []p2p.Protocol { + return []p2p.Protocol{{ + Length: 100, + Run: t.run, + }} +} + +func (t *testNode) APIs() []rpc.API { + return nil +} + +func (t *testNode) Start(server *p2p.Server) error { + return nil +} + +func (t *testNode) Stop() error { + return nil +} diff --git a/p2p/protocols/accounting_test.go b/p2p/protocols/accounting_test.go new file mode 100644 index 0000000000..3810ae2c9b --- /dev/null +++ b/p2p/protocols/accounting_test.go @@ -0,0 +1,223 @@ +// 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 ( + "testing" + + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/p2p/simulations/adapters" + "github.com/ethereum/go-ethereum/rlp" +) + +//dummy Balance implementation +type dummyBalance struct { + amount int64 + peer *Peer +} + +//dummy Prices implementation +type dummyPrices struct{} + +//a dummy message which needs size based accounting +//sender pays +type perBytesMsgSenderPays struct { + Content string +} + +//a dummy message which needs size based accounting +//receiver pays +type perBytesMsgReceiverPays struct { + Content string +} + +//a dummy message which is paid for per unit +//sender pays +type perUnitMsgSenderPays struct{} + +//receiver pays +type perUnitMsgReceiverPays struct{} + +//a dummy message which has zero as its price +type zeroPriceMsg struct{} + +//a dummy message which has no accounting +type nilPriceMsg struct{} + +//return the price for the defined messages +func (d *dummyPrices) Price(msg interface{}) *Price { + switch msg.(type) { + //size based message cost, receiver pays + case *perBytesMsgReceiverPays: + return &Price{ + PerByte: true, + Value: uint64(100), + Payer: Receiver, + } + //size based message cost, sender pays + case *perBytesMsgSenderPays: + return &Price{ + PerByte: true, + Value: uint64(100), + Payer: Sender, + } + //unitary cost, receiver pays + case *perUnitMsgReceiverPays: + return &Price{ + PerByte: false, + Value: uint64(99), + Payer: Receiver, + } + //unitary cost, sender pays + case *perUnitMsgSenderPays: + return &Price{ + PerByte: false, + Value: uint64(99), + Payer: Sender, + } + case *zeroPriceMsg: + return &Price{ + PerByte: false, + Value: uint64(0), + Payer: Sender, + } + case *nilPriceMsg: + return nil + } + return nil +} + +//dummy accounting implementation, only stores values for later check +func (d *dummyBalance) Add(amount int64, peer *Peer) error { + d.amount = amount + d.peer = peer + return nil +} + +type testCase struct { + msg interface{} + size uint32 + sendResult int64 + recvResult int64 +} + +//lowest level unit test +func TestBalance(t *testing.T) { + //create instances + balance := &dummyBalance{} + prices := &dummyPrices{} + //create the spec + spec := createTestSpec() + //create the accounting hook for the spec + acc := NewAccounting(balance, prices) + //create a peer + id := adapters.RandomNodeConfig().ID + p := p2p.NewPeer(id, "testPeer", nil) + peer := NewPeer(p, &dummyRW{}, spec) + //price depends on size, receiver pays + msg := &perBytesMsgReceiverPays{Content: "testBalance"} + size, _ := rlp.EncodeToBytes(msg) + + testCases := []testCase{ + { + msg, + uint32(len(size)), + int64(len(size) * 100), + int64(len(size) * -100), + }, + { + &perBytesMsgSenderPays{Content: "testBalance"}, + uint32(len(size)), + int64(len(size) * -100), + int64(len(size) * 100), + }, + { + &perUnitMsgSenderPays{}, + 0, + int64(-99), + int64(99), + }, + { + &perUnitMsgReceiverPays{}, + 0, + int64(99), + int64(-99), + }, + { + &zeroPriceMsg{}, + 0, + int64(0), + int64(0), + }, + { + &nilPriceMsg{}, + 0, + int64(0), + int64(0), + }, + } + checkAccountingTestCases(t, testCases, acc, peer, balance, true) + checkAccountingTestCases(t, testCases, acc, peer, balance, false) +} + +func checkAccountingTestCases(t *testing.T, cases []testCase, acc *Accounting, peer *Peer, balance *dummyBalance, send bool) { + for _, c := range cases { + var err error + var expectedResult int64 + //reset balance before every check + balance.amount = 0 + if send { + err = acc.Send(peer, c.size, c.msg) + expectedResult = c.sendResult + } else { + err = acc.Receive(peer, c.size, c.msg) + expectedResult = c.recvResult + } + + checkResults(t, err, balance, peer, expectedResult) + } +} + +func checkResults(t *testing.T, err error, balance *dummyBalance, peer *Peer, result int64) { + if err != nil { + t.Fatal(err) + } + if balance.peer != peer { + t.Fatalf("expected Add to be called with peer %v, got %v", peer, balance.peer) + } + if balance.amount != result { + t.Fatalf("Expected balance to be %d but is %d", result, balance.amount) + } +} + +//create a test spec +func createTestSpec() *Spec { + spec := &Spec{ + Name: "test", + Version: 42, + MaxMsgSize: 10 * 1024, + Messages: []interface{}{ + &perBytesMsgReceiverPays{}, + &perBytesMsgSenderPays{}, + &perUnitMsgReceiverPays{}, + &perUnitMsgSenderPays{}, + &zeroPriceMsg{}, + &nilPriceMsg{}, + }, + } + return spec +} diff --git a/p2p/protocols/protocol.go b/p2p/protocols/protocol.go new file mode 100644 index 0000000000..1600a11f99 --- /dev/null +++ b/p2p/protocols/protocol.go @@ -0,0 +1,442 @@ +// Copyright 2017 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 is an extension to p2p. It offers a user friendly simple way to define +devp2p subprotocols by abstracting away code standardly shared by protocols. + +* automate assigments of code indexes to messages +* automate RLP decoding/encoding based on reflecting +* provide the forever loop to read incoming messages +* standardise error handling related to communication +* standardised handshake negotiation +* TODO: automatic generation of wire protocol specification for peers + +*/ +package protocols + +import ( + "bufio" + "bytes" + "context" + "fmt" + "io" + "reflect" + "sync" + "time" + + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/swarm/spancontext" + "github.com/ethereum/go-ethereum/swarm/tracing" + opentracing "github.com/opentracing/opentracing-go" +) + +// error codes used by this protocol scheme +const ( + ErrMsgTooLong = iota + ErrDecode + ErrWrite + ErrInvalidMsgCode + ErrInvalidMsgType + ErrHandshake + ErrNoHandler + ErrHandler +) + +// error description strings associated with the codes +var errorToString = map[int]string{ + ErrMsgTooLong: "Message too long", + ErrDecode: "Invalid message (RLP error)", + ErrWrite: "Error sending message", + ErrInvalidMsgCode: "Invalid message code", + ErrInvalidMsgType: "Invalid message type", + ErrHandshake: "Handshake error", + ErrNoHandler: "No handler registered error", + ErrHandler: "Message handler error", +} + +/* +Error implements the standard go error interface. +Use: + + errorf(code, format, params ...interface{}) + +Prints as: + + :
+ +where description is given by code in errorToString +and details is fmt.Sprintf(format, params...) + +exported field Code can be checked +*/ +type Error struct { + Code int + message string + format string + params []interface{} +} + +func (e Error) Error() (message string) { + if len(e.message) == 0 { + name, ok := errorToString[e.Code] + if !ok { + panic("invalid message code") + } + e.message = name + if e.format != "" { + e.message += ": " + fmt.Sprintf(e.format, e.params...) + } + } + return e.message +} + +func errorf(code int, format string, params ...interface{}) *Error { + return &Error{ + Code: code, + format: format, + params: params, + } +} + +// WrappedMsg is used to propagate marshalled context alongside message payloads +type WrappedMsg struct { + Context []byte + Size uint32 + Payload []byte +} + +//For accounting, the design is to allow the Spec to describe which and how its messages are priced +//To access this functionality, we provide a Hook interface which will call accounting methods +//NOTE: there could be more such (horizontal) hooks in the future +type Hook interface { + //A hook for sending messages + Send(peer *Peer, size uint32, msg interface{}) error + //A hook for receiving messages + Receive(peer *Peer, size uint32, msg interface{}) error +} + +// Spec is a protocol specification including its name and version as well as +// the types of messages which are exchanged +type Spec struct { + // Name is the name of the protocol, often a three-letter word + Name string + + // Version is the version number of the protocol + Version uint + + // MaxMsgSize is the maximum accepted length of the message payload + MaxMsgSize uint32 + + // Messages is a list of message data types which this protocol uses, with + // each message type being sent with its array index as the code (so + // [&foo{}, &bar{}, &baz{}] would send foo, bar and baz with codes + // 0, 1 and 2 respectively) + // each message must have a single unique data type + Messages []interface{} + + //hook for accounting (could be extended to multiple hooks in the future) + Hook Hook + + initOnce sync.Once + codes map[reflect.Type]uint64 + types map[uint64]reflect.Type +} + +func (s *Spec) init() { + s.initOnce.Do(func() { + s.codes = make(map[reflect.Type]uint64, len(s.Messages)) + s.types = make(map[uint64]reflect.Type, len(s.Messages)) + for i, msg := range s.Messages { + code := uint64(i) + typ := reflect.TypeOf(msg) + if typ.Kind() == reflect.Ptr { + typ = typ.Elem() + } + s.codes[typ] = code + s.types[code] = typ + } + }) +} + +// Length returns the number of message types in the protocol +func (s *Spec) Length() uint64 { + return uint64(len(s.Messages)) +} + +// GetCode returns the message code of a type, and boolean second argument is +// false if the message type is not found +func (s *Spec) GetCode(msg interface{}) (uint64, bool) { + s.init() + typ := reflect.TypeOf(msg) + if typ.Kind() == reflect.Ptr { + typ = typ.Elem() + } + code, ok := s.codes[typ] + return code, ok +} + +// NewMsg construct a new message type given the code +func (s *Spec) NewMsg(code uint64) (interface{}, bool) { + s.init() + typ, ok := s.types[code] + if !ok { + return nil, false + } + return reflect.New(typ).Interface(), true +} + +// Peer represents a remote peer or protocol instance that is running on a peer connection with +// a remote peer +type Peer struct { + *p2p.Peer // the p2p.Peer object representing the remote + rw p2p.MsgReadWriter // p2p.MsgReadWriter to send messages to and read messages from + spec *Spec +} + +// NewPeer constructs a new peer +// this constructor is called by the p2p.Protocol#Run function +// the first two arguments are the arguments passed to p2p.Protocol.Run function +// the third argument is the Spec describing the protocol +func NewPeer(p *p2p.Peer, rw p2p.MsgReadWriter, spec *Spec) *Peer { + return &Peer{ + Peer: p, + rw: rw, + spec: spec, + } +} + +// Run starts the forever loop that handles incoming messages +// called within the p2p.Protocol#Run function +// the handler argument is a function which is called for each message received +// from the remote peer, a returned error causes the loop to exit +// resulting in disconnection +func (p *Peer) Run(handler func(ctx context.Context, msg interface{}) error) error { + for { + if err := p.handleIncoming(handler); err != nil { + if err != io.EOF { + metrics.GetOrRegisterCounter("peer.handleincoming.error", nil).Inc(1) + log.Error("peer.handleIncoming", "err", err) + } + + return err + } + } +} + +// Drop disconnects a peer. +// TODO: may need to implement protocol drop only? don't want to kick off the peer +// if they are useful for other protocols +func (p *Peer) Drop(err error) { + p.Disconnect(p2p.DiscSubprotocolError) +} + +// Send takes a message, encodes it in RLP, finds the right message code and sends the +// message off to the peer +// this low level call will be wrapped by libraries providing routed or broadcast sends +// but often just used to forward and push messages to directly connected peers +func (p *Peer) Send(ctx context.Context, msg interface{}) error { + defer metrics.GetOrRegisterResettingTimer("peer.send_t", nil).UpdateSince(time.Now()) + metrics.GetOrRegisterCounter("peer.send", nil).Inc(1) + + var b bytes.Buffer + if tracing.Enabled { + writer := bufio.NewWriter(&b) + + tracer := opentracing.GlobalTracer() + + sctx := spancontext.FromContext(ctx) + + if sctx != nil { + err := tracer.Inject( + sctx, + opentracing.Binary, + writer) + if err != nil { + return err + } + } + + writer.Flush() + } + + r, err := rlp.EncodeToBytes(msg) + if err != nil { + return err + } + + wmsg := WrappedMsg{ + Context: b.Bytes(), + Size: uint32(len(r)), + Payload: r, + } + + //if the accounting hook is set, call it + if p.spec.Hook != nil { + err := p.spec.Hook.Send(p, wmsg.Size, msg) + if err != nil { + p.Drop(err) + return err + } + } + + code, found := p.spec.GetCode(msg) + if !found { + return errorf(ErrInvalidMsgType, "%v", code) + } + return p2p.Send(p.rw, code, wmsg) +} + +// handleIncoming(code) +// is called each cycle of the main forever loop that dispatches incoming messages +// if this returns an error the loop returns and the peer is disconnected with the error +// this generic handler +// * checks message size, +// * checks for out-of-range message codes, +// * handles decoding with reflection, +// * call handlers as callbacks +func (p *Peer) handleIncoming(handle func(ctx context.Context, msg interface{}) error) error { + msg, err := p.rw.ReadMsg() + if err != nil { + return err + } + // make sure that the payload has been fully consumed + defer msg.Discard() + + if msg.Size > p.spec.MaxMsgSize { + return errorf(ErrMsgTooLong, "%v > %v", msg.Size, p.spec.MaxMsgSize) + } + + // unmarshal wrapped msg, which might contain context + var wmsg WrappedMsg + err = msg.Decode(&wmsg) + if err != nil { + log.Error(err.Error()) + return err + } + + ctx := context.Background() + + // if tracing is enabled and the context coming within the request is + // not empty, try to unmarshal it + if tracing.Enabled && len(wmsg.Context) > 0 { + var sctx opentracing.SpanContext + + tracer := opentracing.GlobalTracer() + sctx, err = tracer.Extract( + opentracing.Binary, + bytes.NewReader(wmsg.Context)) + if err != nil { + log.Error(err.Error()) + return err + } + + ctx = spancontext.WithContext(ctx, sctx) + } + + val, ok := p.spec.NewMsg(msg.Code) + if !ok { + return errorf(ErrInvalidMsgCode, "%v", msg.Code) + } + if err := rlp.DecodeBytes(wmsg.Payload, val); err != nil { + return errorf(ErrDecode, "<= %v: %v", msg, err) + } + + //if the accounting hook is set, call it + if p.spec.Hook != nil { + err := p.spec.Hook.Receive(p, wmsg.Size, val) + if err != nil { + return err + } + } + + // call the registered handler callbacks + // a registered callback take the decoded message as argument as an interface + // which the handler is supposed to cast to the appropriate type + // it is entirely safe not to check the cast in the handler since the handler is + // chosen based on the proper type in the first place + if err := handle(ctx, val); err != nil { + return errorf(ErrHandler, "(msg code %v): %v", msg.Code, err) + } + return nil +} + +// Handshake negotiates a handshake on the peer connection +// * arguments +// * context +// * the local handshake to be sent to the remote peer +// * 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) (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 + if verify != nil { + return verify(rhs) + } + return nil + } + send := func() { errc <- p.Send(ctx, hs) } + receive := func() { errc <- p.handleIncoming(handle) } + + go func() { + if p.Inbound() { + receive() + send() + } else { + send() + receive() + } + }() + + for i := 0; i < 2; i++ { + var err error + select { + case err = <-errc: + case <-ctx.Done(): + err = ctx.Err() + } + if err != nil { + return nil, errorf(ErrHandshake, err.Error()) + } + } + 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/p2p/protocols/protocol_test.go b/p2p/protocols/protocol_test.go new file mode 100644 index 0000000000..cfdd05f4c9 --- /dev/null +++ b/p2p/protocols/protocol_test.go @@ -0,0 +1,593 @@ +// Copyright 2017 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 ( + "bytes" + "context" + "errors" + "fmt" + "testing" + "time" + + "github.com/ethereum/go-ethereum/rlp" + + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/simulations/adapters" + p2ptest "github.com/ethereum/go-ethereum/p2p/testing" +) + +// handshake message type +type hs0 struct { + C uint +} + +// message to kill/drop the peer with nodeID +type kill struct { + C enode.ID +} + +// message to drop connection +type drop struct { +} + +/// protoHandshake represents module-independent aspects of the protocol and is +// the first message peers send and receive as part the initial exchange +type protoHandshake struct { + Version uint // local and remote peer should have identical version + NetworkID string // local and remote peer should have identical network id +} + +// checkProtoHandshake verifies local and remote protoHandshakes match +func checkProtoHandshake(testVersion uint, testNetworkID string) func(interface{}) error { + return func(rhs interface{}) error { + remote := rhs.(*protoHandshake) + if remote.NetworkID != testNetworkID { + return fmt.Errorf("%s (!= %s)", remote.NetworkID, testNetworkID) + } + + if remote.Version != testVersion { + return fmt.Errorf("%d (!= %d)", remote.Version, testVersion) + } + return nil + } +} + +// newProtocol sets up a protocol +// the run function here demonstrates a typical protocol using peerPool, handshake +// and messages registered to handlers +func newProtocol(pp *p2ptest.TestPeerPool) func(*p2p.Peer, p2p.MsgReadWriter) error { + spec := &Spec{ + Name: "test", + Version: 42, + MaxMsgSize: 10 * 1024, + Messages: []interface{}{ + protoHandshake{}, + hs0{}, + kill{}, + drop{}, + }, + } + return func(p *p2p.Peer, rw p2p.MsgReadWriter) error { + peer := NewPeer(p, rw, spec) + + // initiate one-off protohandshake and check validity + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + phs := &protoHandshake{42, "420"} + hsCheck := checkProtoHandshake(phs.Version, phs.NetworkID) + _, err := peer.Handshake(ctx, phs, hsCheck) + if err != nil { + return err + } + + lhs := &hs0{42} + // module handshake demonstrating a simple repeatable exchange of same-type message + hs, err := peer.Handshake(ctx, lhs, nil) + if err != nil { + return err + } + + if rmhs := hs.(*hs0); rmhs.C > lhs.C { + return fmt.Errorf("handshake mismatch remote %v > local %v", rmhs.C, lhs.C) + } + + handle := func(ctx context.Context, msg interface{}) error { + switch msg := msg.(type) { + + case *protoHandshake: + return errors.New("duplicate handshake") + + case *hs0: + rhs := msg + if rhs.C > lhs.C { + return fmt.Errorf("handshake mismatch remote %v > local %v", rhs.C, lhs.C) + } + lhs.C += rhs.C + return peer.Send(ctx, lhs) + + case *kill: + // demonstrates use of peerPool, killing another peer connection as a response to a message + id := msg.C + pp.Get(id).Drop(errors.New("killed")) + return nil + + case *drop: + // for testing we can trigger self induced disconnect upon receiving drop message + return errors.New("dropped") + + default: + return fmt.Errorf("unknown message type: %T", msg) + } + } + + pp.Add(peer) + defer pp.Remove(peer) + return peer.Run(handle) + } +} + +func protocolTester(pp *p2ptest.TestPeerPool) *p2ptest.ProtocolTester { + conf := adapters.RandomNodeConfig() + return p2ptest.NewProtocolTester(conf.ID, 2, newProtocol(pp)) +} + +func protoHandshakeExchange(id enode.ID, proto *protoHandshake) []p2ptest.Exchange { + + return []p2ptest.Exchange{ + { + Expects: []p2ptest.Expect{ + { + Code: 0, + Msg: &protoHandshake{42, "420"}, + Peer: id, + }, + }, + }, + { + Triggers: []p2ptest.Trigger{ + { + Code: 0, + Msg: proto, + Peer: id, + }, + }, + }, + } +} + +func runProtoHandshake(t *testing.T, proto *protoHandshake, errs ...error) { + pp := p2ptest.NewTestPeerPool() + s := protocolTester(pp) + // TODO: make this more than one handshake + node := s.Nodes[0] + if err := s.TestExchanges(protoHandshakeExchange(node.ID(), proto)...); err != nil { + t.Fatal(err) + } + var disconnects []*p2ptest.Disconnect + for i, err := range errs { + disconnects = append(disconnects, &p2ptest.Disconnect{Peer: s.Nodes[i].ID(), Error: err}) + } + if err := s.TestDisconnected(disconnects...); err != nil { + t.Fatal(err) + } +} + +type dummyHook struct { + peer *Peer + size uint32 + msg interface{} + send bool + err error + waitC chan struct{} +} + +type dummyMsg struct { + Content string +} + +func (d *dummyHook) Send(peer *Peer, size uint32, msg interface{}) error { + d.peer = peer + d.size = size + d.msg = msg + d.send = true + return d.err +} + +func (d *dummyHook) Receive(peer *Peer, size uint32, msg interface{}) error { + d.peer = peer + d.size = size + d.msg = msg + d.send = false + d.waitC <- struct{}{} + return d.err +} + +func TestProtocolHook(t *testing.T) { + testHook := &dummyHook{ + waitC: make(chan struct{}, 1), + } + spec := &Spec{ + Name: "test", + Version: 42, + MaxMsgSize: 10 * 1024, + Messages: []interface{}{ + dummyMsg{}, + }, + Hook: testHook, + } + + runFunc := func(p *p2p.Peer, rw p2p.MsgReadWriter) error { + peer := NewPeer(p, rw, spec) + ctx := context.TODO() + err := peer.Send(ctx, &dummyMsg{ + Content: "handshake"}) + + if err != nil { + t.Fatal(err) + } + + handle := func(ctx context.Context, msg interface{}) error { + return nil + } + + return peer.Run(handle) + } + + conf := adapters.RandomNodeConfig() + tester := p2ptest.NewProtocolTester(conf.ID, 2, runFunc) + err := tester.TestExchanges(p2ptest.Exchange{ + Expects: []p2ptest.Expect{ + { + Code: 0, + Msg: &dummyMsg{Content: "handshake"}, + Peer: tester.Nodes[0].ID(), + }, + }, + }) + if err != nil { + t.Fatal(err) + } + 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 { + 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) + } + + err = tester.TestExchanges(p2ptest.Exchange{ + Triggers: []p2ptest.Trigger{ + { + Code: 0, + Msg: &dummyMsg{Content: "response"}, + Peer: tester.Nodes[1].ID(), + }, + }, + }) + + <-testHook.waitC + + if err != nil { + t.Fatal(err) + } + if testHook.msg == nil || testHook.msg.(*dummyMsg).Content != "response" { + 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[1].ID() { + t.Fatal("Expected peer ID to be set correctly, but it is not") + } + 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.err = fmt.Errorf("dummy error") + err = tester.TestExchanges(p2ptest.Exchange{ + Triggers: []p2ptest.Trigger{ + { + Code: 0, + Msg: &dummyMsg{Content: "response"}, + Peer: tester.Nodes[1].ID(), + }, + }, + }) + + <-testHook.waitC + + time.Sleep(100 * time.Millisecond) + err = tester.TestDisconnected(&p2ptest.Disconnect{Peer: tester.Nodes[1].ID(), Error: testHook.err}) + 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 +//(send,receive) still works +func TestNoHook(t *testing.T) { + //create a test spec + spec := createTestSpec() + //a random node + id := adapters.RandomNodeConfig().ID + //a peer + p := p2p.NewPeer(id, "testPeer", nil) + rw := &dummyRW{} + peer := NewPeer(p, rw, spec) + ctx := context.TODO() + msg := &perBytesMsgSenderPays{Content: "testBalance"} + //send a message + err := peer.Send(ctx, msg) + if err != nil { + t.Fatal(err) + } + //simulate receiving a message + rw.msg = msg + peer.handleIncoming(func(ctx context.Context, msg interface{}) error { + return nil + }) + //all should just work and not result in any error +} + +func TestProtoHandshakeVersionMismatch(t *testing.T) { + runProtoHandshake(t, &protoHandshake{41, "420"}, errorf(ErrHandshake, errorf(ErrHandler, "(msg code 0): 41 (!= 42)").Error())) +} + +func TestProtoHandshakeNetworkIDMismatch(t *testing.T) { + runProtoHandshake(t, &protoHandshake{42, "421"}, errorf(ErrHandshake, errorf(ErrHandler, "(msg code 0): 421 (!= 420)").Error())) +} + +func TestProtoHandshakeSuccess(t *testing.T) { + runProtoHandshake(t, &protoHandshake{42, "420"}) +} + +func moduleHandshakeExchange(id enode.ID, resp uint) []p2ptest.Exchange { + + return []p2ptest.Exchange{ + { + Expects: []p2ptest.Expect{ + { + Code: 1, + Msg: &hs0{42}, + Peer: id, + }, + }, + }, + { + Triggers: []p2ptest.Trigger{ + { + Code: 1, + Msg: &hs0{resp}, + Peer: id, + }, + }, + }, + } +} + +func runModuleHandshake(t *testing.T, resp uint, errs ...error) { + pp := p2ptest.NewTestPeerPool() + s := protocolTester(pp) + node := s.Nodes[0] + if err := s.TestExchanges(protoHandshakeExchange(node.ID(), &protoHandshake{42, "420"})...); err != nil { + t.Fatal(err) + } + if err := s.TestExchanges(moduleHandshakeExchange(node.ID(), resp)...); err != nil { + t.Fatal(err) + } + var disconnects []*p2ptest.Disconnect + for i, err := range errs { + disconnects = append(disconnects, &p2ptest.Disconnect{Peer: s.Nodes[i].ID(), Error: err}) + } + if err := s.TestDisconnected(disconnects...); err != nil { + t.Fatal(err) + } +} + +func TestModuleHandshakeError(t *testing.T) { + runModuleHandshake(t, 43, fmt.Errorf("handshake mismatch remote 43 > local 42")) +} + +func TestModuleHandshakeSuccess(t *testing.T) { + runModuleHandshake(t, 42) +} + +// testing complex interactions over multiple peers, relaying, dropping +func testMultiPeerSetup(a, b enode.ID) []p2ptest.Exchange { + + return []p2ptest.Exchange{ + { + Label: "primary handshake", + Expects: []p2ptest.Expect{ + { + Code: 0, + Msg: &protoHandshake{42, "420"}, + Peer: a, + }, + { + Code: 0, + Msg: &protoHandshake{42, "420"}, + Peer: b, + }, + }, + }, + { + Label: "module handshake", + Triggers: []p2ptest.Trigger{ + { + Code: 0, + Msg: &protoHandshake{42, "420"}, + Peer: a, + }, + { + Code: 0, + Msg: &protoHandshake{42, "420"}, + Peer: b, + }, + }, + Expects: []p2ptest.Expect{ + { + Code: 1, + Msg: &hs0{42}, + Peer: a, + }, + { + Code: 1, + Msg: &hs0{42}, + Peer: b, + }, + }, + }, + + {Label: "alternative module handshake", Triggers: []p2ptest.Trigger{{Code: 1, Msg: &hs0{41}, Peer: a}, + {Code: 1, Msg: &hs0{41}, Peer: b}}}, + {Label: "repeated module handshake", Triggers: []p2ptest.Trigger{{Code: 1, Msg: &hs0{1}, Peer: a}}}, + {Label: "receiving repeated module handshake", Expects: []p2ptest.Expect{{Code: 1, Msg: &hs0{43}, Peer: a}}}} +} + +func runMultiplePeers(t *testing.T, peer int, errs ...error) { + pp := p2ptest.NewTestPeerPool() + s := protocolTester(pp) + + if err := s.TestExchanges(testMultiPeerSetup(s.Nodes[0].ID(), s.Nodes[1].ID())...); err != nil { + t.Fatal(err) + } + // after some exchanges of messages, we can test state changes + // here this is simply demonstrated by the peerPool + // after the handshake negotiations peers must be added to the pool + // time.Sleep(1) + tick := time.NewTicker(10 * time.Millisecond) + timeout := time.NewTimer(1 * time.Second) +WAIT: + for { + select { + case <-tick.C: + if pp.Has(s.Nodes[0].ID()) { + break WAIT + } + case <-timeout.C: + t.Fatal("timeout") + } + } + if !pp.Has(s.Nodes[1].ID()) { + t.Fatalf("missing peer test-1: %v (%v)", pp, s.Nodes) + } + + // peer 0 sends kill request for peer with index + err := s.TestExchanges(p2ptest.Exchange{ + Triggers: []p2ptest.Trigger{ + { + Code: 2, + Msg: &kill{s.Nodes[peer].ID()}, + Peer: s.Nodes[0].ID(), + }, + }, + }) + + if err != nil { + t.Fatal(err) + } + + // the peer not killed sends a drop request + err = s.TestExchanges(p2ptest.Exchange{ + Triggers: []p2ptest.Trigger{ + { + Code: 3, + Msg: &drop{}, + Peer: s.Nodes[(peer+1)%2].ID(), + }, + }, + }) + + if err != nil { + t.Fatal(err) + } + + // check the actual discconnect errors on the individual peers + var disconnects []*p2ptest.Disconnect + for i, err := range errs { + disconnects = append(disconnects, &p2ptest.Disconnect{Peer: s.Nodes[i].ID(), Error: err}) + } + if err := s.TestDisconnected(disconnects...); err != nil { + t.Fatal(err) + } + // test if disconnected peers have been removed from peerPool + if pp.Has(s.Nodes[peer].ID()) { + t.Fatalf("peer test-%v not dropped: %v (%v)", peer, pp, s.Nodes) + } + +} +func XTestMultiplePeersDropSelf(t *testing.T) { + runMultiplePeers(t, 0, + fmt.Errorf("subprotocol error"), + fmt.Errorf("Message handler error: (msg code 3): dropped"), + ) +} + +func XTestMultiplePeersDropOther(t *testing.T) { + runMultiplePeers(t, 1, + fmt.Errorf("Message handler error: (msg code 3): dropped"), + fmt.Errorf("subprotocol error"), + ) +} + +//dummy implementation of a MsgReadWriter +//this allows for quick and easy unit tests without +//having to build up the complete protocol +type dummyRW struct { + msg interface{} + size uint32 + code uint64 +} + +func (d *dummyRW) WriteMsg(msg p2p.Msg) error { + return nil +} + +func (d *dummyRW) ReadMsg() (p2p.Msg, error) { + enc := bytes.NewReader(d.getDummyMsg()) + return p2p.Msg{ + Code: d.code, + Size: d.size, + Payload: enc, + ReceivedAt: time.Now(), + }, nil +} + +func (d *dummyRW) getDummyMsg() []byte { + r, _ := rlp.EncodeToBytes(d.msg) + var b bytes.Buffer + wmsg := WrappedMsg{ + Context: b.Bytes(), + Size: uint32(len(r)), + Payload: r, + } + rr, _ := rlp.EncodeToBytes(wmsg) + d.size = uint32(len(rr)) + return rr +} diff --git a/p2p/protocols/reporter.go b/p2p/protocols/reporter.go new file mode 100644 index 0000000000..9612b4a4d5 --- /dev/null +++ b/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/p2p/protocols/reporter_test.go b/p2p/protocols/reporter_test.go new file mode 100644 index 0000000000..9b0da09b79 --- /dev/null +++ b/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/p2p/rlpx.go b/p2p/rlpx.go index 24037ecc13..67cc1d9bf3 100644 --- a/p2p/rlpx.go +++ b/p2p/rlpx.go @@ -35,13 +35,13 @@ import ( "sync" "time" + "github.com/ethereum/go-ethereum/common/bitutil" "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/p2p/discover" "github.com/ethereum/go-ethereum/rlp" "github.com/golang/snappy" + "golang.org/x/crypto/sha3" ) const ( @@ -108,17 +108,19 @@ func (t *rlpx) close(err error) { // Tell the remote end why we're disconnecting if possible. if t.rw != nil { if r, ok := err.(DiscReason); ok && r != DiscNetworkError { - t.fd.SetWriteDeadline(time.Now().Add(discWriteTimeout)) - SendItems(t.rw, discMsg, r) + // rlpx tries to send DiscReason to disconnected peer + // if the connection is net.Pipe (in-memory simulation) + // it hangs forever, since net.Pipe does not implement + // a write deadline. Because of this only try to send + // the disconnect reason message if there is no error. + if err := t.fd.SetWriteDeadline(time.Now().Add(discWriteTimeout)); err == nil { + SendItems(t.rw, discMsg, r) + } } } t.fd.Close() } -// doEncHandshake runs the protocol handshake using authenticated -// messages. the protocol handshake is the first authenticated message -// and also verifies whether the encryption handshake 'worked' and the -// remote side actually provided the right public key. func (t *rlpx) doProtoHandshake(our *protoHandshake) (their *protoHandshake, err error) { // Writing our handshake happens concurrently, we prefer // returning the handshake read error. If the remote side @@ -149,7 +151,7 @@ func readProtocolHandshake(rw MsgReader, our *protoHandshake) (*protoHandshake, } if msg.Code == discMsg { // Disconnect before protocol handshake is valid according to the - // spec and we send it ourself if the posthanshake checks fail. + // spec and we send it ourself if the post-handshake checks fail. // We can't return the reason directly, though, because it is echoed // back otherwise. Wrap it in a string instead. var reason [1]DiscReason @@ -163,37 +165,39 @@ func readProtocolHandshake(rw MsgReader, our *protoHandshake) (*protoHandshake, if err := msg.Decode(&hs); err != nil { return nil, err } - if (hs.ID == discover.NodeID{}) { + if len(hs.ID) != 64 || !bitutil.TestBytes(hs.ID) { return nil, DiscInvalidIdentity } return &hs, nil } -func (t *rlpx) doEncHandshake(prv *ecdsa.PrivateKey, dial *discover.Node) (discover.NodeID, error) { +// doEncHandshake runs the protocol handshake using authenticated +// messages. the protocol handshake is the first authenticated message +// and also verifies whether the encryption handshake 'worked' and the +// remote side actually provided the right public key. +func (t *rlpx) doEncHandshake(prv *ecdsa.PrivateKey, dial *ecdsa.PublicKey) (*ecdsa.PublicKey, error) { var ( sec secrets err error ) if dial == nil { - sec, err = receiverEncHandshake(t.fd, prv, nil) + sec, err = receiverEncHandshake(t.fd, prv) } else { - sec, err = initiatorEncHandshake(t.fd, prv, dial.ID, nil) + sec, err = initiatorEncHandshake(t.fd, prv, dial) } if err != nil { - return discover.NodeID{}, err + return nil, err } t.wmu.Lock() t.rw = newRLPXFrameRW(t.fd, sec) t.wmu.Unlock() - return sec.RemoteID, nil + return sec.Remote.ExportECDSA(), nil } // encHandshake contains the state of the encryption handshake. type encHandshake struct { - initiator bool - remoteID discover.NodeID - - remotePub *ecies.PublicKey // remote-pubk + initiator bool + remote *ecies.PublicKey // remote-pubk initNonce, respNonce []byte // nonce randomPrivKey *ecies.PrivateKey // ecdhe-random remoteRandomPub *ecies.PublicKey // ecdhe-random-pubk @@ -202,7 +206,7 @@ type encHandshake struct { // secrets represents the connection secrets // which are negotiated during the encryption handshake. type secrets struct { - RemoteID discover.NodeID + Remote *ecies.PublicKey AES, MAC []byte EgressMAC, IngressMAC hash.Hash Token []byte @@ -243,16 +247,16 @@ func (h *encHandshake) secrets(auth, authResp []byte) (secrets, error) { sharedSecret := crypto.Keccak256(ecdheSecret, crypto.Keccak256(h.respNonce, h.initNonce)) aesSecret := crypto.Keccak256(ecdheSecret, sharedSecret) s := secrets{ - RemoteID: h.remoteID, - AES: aesSecret, - MAC: crypto.Keccak256(ecdheSecret, aesSecret), + Remote: h.remote, + AES: aesSecret, + MAC: crypto.Keccak256(ecdheSecret, aesSecret), } // 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 { @@ -267,16 +271,16 @@ func (h *encHandshake) secrets(auth, authResp []byte) (secrets, error) { // staticSharedSecret returns the static shared secret, the result // of key agreement between the local and remote static node key. func (h *encHandshake) staticSharedSecret(prv *ecdsa.PrivateKey) ([]byte, error) { - return ecies.ImportECDSA(prv).GenerateShared(h.remotePub, sskLen, sskLen) + return ecies.ImportECDSA(prv).GenerateShared(h.remote, sskLen, sskLen) } // initiatorEncHandshake negotiates a session token on conn. // it should be called on the dialing side of the connection. // // prv is the local client's private key. -func initiatorEncHandshake(conn io.ReadWriter, prv *ecdsa.PrivateKey, remoteID discover.NodeID, token []byte) (s secrets, err error) { - h := &encHandshake{initiator: true, remoteID: remoteID} - authMsg, err := h.makeAuthMsg(prv, token) +func initiatorEncHandshake(conn io.ReadWriter, prv *ecdsa.PrivateKey, remote *ecdsa.PublicKey) (s secrets, err error) { + h := &encHandshake{initiator: true, remote: ecies.ImportECDSAPublic(remote)} + authMsg, err := h.makeAuthMsg(prv) if err != nil { return s, err } @@ -300,15 +304,11 @@ func initiatorEncHandshake(conn io.ReadWriter, prv *ecdsa.PrivateKey, remoteID d } // makeAuthMsg creates the initiator handshake message. -func (h *encHandshake) makeAuthMsg(prv *ecdsa.PrivateKey, token []byte) (*authMsgV4, error) { - rpub, err := h.remoteID.Pubkey() - if err != nil { - return nil, fmt.Errorf("bad remoteID: %v", err) - } - h.remotePub = ecies.ImportECDSAPublic(rpub) +func (h *encHandshake) makeAuthMsg(prv *ecdsa.PrivateKey) (*authMsgV4, error) { // Generate random initiator nonce. h.initNonce = make([]byte, shaLen) - if _, err := rand.Read(h.initNonce); err != nil { + _, err := rand.Read(h.initNonce) + if err != nil { return nil, err } // Generate random keypair to for ECDH. @@ -318,7 +318,7 @@ func (h *encHandshake) makeAuthMsg(prv *ecdsa.PrivateKey, token []byte) (*authMs } // Sign known message: static-shared-secret ^ nonce - token, err = h.staticSharedSecret(prv) + token, err := h.staticSharedSecret(prv) if err != nil { return nil, err } @@ -346,8 +346,7 @@ func (h *encHandshake) handleAuthResp(msg *authRespV4) (err error) { // it should be called on the listening side of the connection. // // prv is the local client's private key. -// token is the token from a previous session with this node. -func receiverEncHandshake(conn io.ReadWriter, prv *ecdsa.PrivateKey, token []byte) (s secrets, err error) { +func receiverEncHandshake(conn io.ReadWriter, prv *ecdsa.PrivateKey) (s secrets, err error) { authMsg := new(authMsgV4) authPacket, err := readHandshakeMsg(authMsg, encAuthMsgLen, prv, conn) if err != nil { @@ -379,13 +378,12 @@ func receiverEncHandshake(conn io.ReadWriter, prv *ecdsa.PrivateKey, token []byt func (h *encHandshake) handleAuthMsg(msg *authMsgV4, prv *ecdsa.PrivateKey) error { // Import the remote identity. - h.initNonce = msg.Nonce[:] - h.remoteID = msg.InitiatorPubkey - rpub, err := h.remoteID.Pubkey() + rpub, err := importPublicKey(msg.InitiatorPubkey[:]) if err != nil { - return fmt.Errorf("bad remoteID: %#v", err) + return err } - h.remotePub = ecies.ImportECDSAPublic(rpub) + h.initNonce = msg.Nonce[:] + h.remote = rpub // Generate random keypair for ECDH. // If a private key is already set, use it instead of generating one (for testing). @@ -431,7 +429,7 @@ func (msg *authMsgV4) sealPlain(h *encHandshake) ([]byte, error) { n += copy(buf[n:], msg.InitiatorPubkey[:]) n += copy(buf[n:], msg.Nonce[:]) buf[n] = 0 // token-flag - return ecies.Encrypt(rand.Reader, h.remotePub, buf, nil, nil) + return ecies.Encrypt(rand.Reader, h.remote, buf, nil, nil) } func (msg *authMsgV4) decodePlain(input []byte) { @@ -447,7 +445,7 @@ func (msg *authRespV4) sealPlain(hs *encHandshake) ([]byte, error) { buf := make([]byte, authRespLen) n := copy(buf, msg.RandomPubkey[:]) copy(buf[n:], msg.Nonce[:]) - return ecies.Encrypt(rand.Reader, hs.remotePub, buf, nil, nil) + return ecies.Encrypt(rand.Reader, hs.remote, buf, nil, nil) } func (msg *authRespV4) decodePlain(input []byte) { @@ -470,7 +468,7 @@ func sealEIP8(msg interface{}, h *encHandshake) ([]byte, error) { prefix := make([]byte, 2) binary.BigEndian.PutUint16(prefix, uint16(buf.Len()+eciesOverhead)) - enc, err := ecies.Encrypt(rand.Reader, h.remotePub, buf.Bytes(), nil, prefix) + enc, err := ecies.Encrypt(rand.Reader, h.remote, buf.Bytes(), nil, prefix) return append(prefix, enc...), err } @@ -485,7 +483,7 @@ func readHandshakeMsg(msg plainDecoder, plainSize int, prv *ecdsa.PrivateKey, r } // Attempt decoding pre-EIP-8 "plain" format. key := ecies.ImportECDSA(prv) - if dec, err := key.Decrypt(rand.Reader, buf, nil, nil); err == nil { + if dec, err := key.Decrypt(buf, nil, nil); err == nil { msg.decodePlain(dec) return buf, nil } @@ -499,7 +497,7 @@ func readHandshakeMsg(msg plainDecoder, plainSize int, prv *ecdsa.PrivateKey, r if _, err := io.ReadFull(r, buf[plainSize:]); err != nil { return buf, err } - dec, err := key.Decrypt(rand.Reader, buf[2:], nil, prefix) + dec, err := key.Decrypt(buf[2:], nil, prefix) if err != nil { return buf, err } @@ -522,9 +520,9 @@ func importPublicKey(pubKey []byte) (*ecies.PublicKey, error) { return nil, fmt.Errorf("invalid public key length %v (expect 64/65)", len(pubKey)) } // TODO: fewer pointless conversions - pub := crypto.ToECDSAPub(pubKey65) - if pub.X == nil { - return nil, fmt.Errorf("invalid public key") + pub, err := crypto.UnmarshalPubkey(pubKey65) + if err != nil { + return nil, err } return ecies.ImportECDSAPublic(pub), nil } diff --git a/p2p/rlpx_test.go b/p2p/rlpx_test.go index f4cefa650b..5d89818020 100644 --- a/p2p/rlpx_test.go +++ b/p2p/rlpx_test.go @@ -18,6 +18,7 @@ package p2p import ( "bytes" + "crypto/ecdsa" "crypto/rand" "errors" "fmt" @@ -33,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/discover" + "github.com/ethereum/go-ethereum/p2p/simulations/pipes" "github.com/ethereum/go-ethereum/rlp" + "golang.org/x/crypto/sha3" ) func TestSharedSecret(t *testing.T) { @@ -79,9 +80,9 @@ func TestEncHandshake(t *testing.T) { func testEncHandshake(token []byte) error { type result struct { - side string - id discover.NodeID - err error + side string + pubkey *ecdsa.PublicKey + err error } var ( prv0, _ = crypto.GenerateKey() @@ -96,14 +97,12 @@ func testEncHandshake(token []byte) error { defer func() { output <- r }() defer fd0.Close() - dest := &discover.Node{ID: discover.PubkeyID(&prv1.PublicKey)} - r.id, r.err = c0.doEncHandshake(prv0, dest) + r.pubkey, r.err = c0.doEncHandshake(prv0, &prv1.PublicKey) if r.err != nil { return } - id1 := discover.PubkeyID(&prv1.PublicKey) - if r.id != id1 { - r.err = fmt.Errorf("remote ID mismatch: got %v, want: %v", r.id, id1) + if !reflect.DeepEqual(r.pubkey, &prv1.PublicKey) { + r.err = fmt.Errorf("remote pubkey mismatch: got %v, want: %v", r.pubkey, &prv1.PublicKey) } }() go func() { @@ -111,13 +110,12 @@ func testEncHandshake(token []byte) error { defer func() { output <- r }() defer fd1.Close() - r.id, r.err = c1.doEncHandshake(prv1, nil) + r.pubkey, r.err = c1.doEncHandshake(prv1, nil) if r.err != nil { return } - id0 := discover.PubkeyID(&prv0.PublicKey) - if r.id != id0 { - r.err = fmt.Errorf("remote ID mismatch: got %v, want: %v", r.id, id0) + if !reflect.DeepEqual(r.pubkey, &prv0.PublicKey) { + r.err = fmt.Errorf("remote ID mismatch: got %v, want: %v", r.pubkey, &prv0.PublicKey) } }() @@ -149,29 +147,33 @@ func testEncHandshake(token []byte) error { func TestProtocolHandshake(t *testing.T) { var ( prv0, _ = crypto.GenerateKey() - node0 = &discover.Node{ID: discover.PubkeyID(&prv0.PublicKey), IP: net.IP{1, 2, 3, 4}, TCP: 33} - hs0 = &protoHandshake{Version: 3, ID: node0.ID, Caps: []Cap{{"a", 0}, {"b", 2}}} + pub0 = crypto.FromECDSAPub(&prv0.PublicKey)[1:] + hs0 = &protoHandshake{Version: 3, ID: pub0, Caps: []Cap{{"a", 0}, {"b", 2}}} prv1, _ = crypto.GenerateKey() - node1 = &discover.Node{ID: discover.PubkeyID(&prv1.PublicKey), IP: net.IP{5, 6, 7, 8}, TCP: 44} - hs1 = &protoHandshake{Version: 3, ID: node1.ID, Caps: []Cap{{"c", 1}, {"d", 3}}} + pub1 = crypto.FromECDSAPub(&prv1.PublicKey)[1:] + hs1 = &protoHandshake{Version: 3, ID: pub1, Caps: []Cap{{"c", 1}, {"d", 3}}} - fd0, fd1 = net.Pipe() - wg sync.WaitGroup + wg sync.WaitGroup ) + fd0, fd1, err := pipes.TCPPipe() + if err != nil { + t.Fatal(err) + } + wg.Add(2) go func() { defer wg.Done() - defer fd1.Close() + defer fd0.Close() rlpx := newRLPX(fd0) - remid, err := rlpx.doEncHandshake(prv0, node1) + rpubkey, err := rlpx.doEncHandshake(prv0, &prv1.PublicKey) if err != nil { t.Errorf("dial side enc handshake failed: %v", err) return } - if remid != node1.ID { - t.Errorf("dial side remote id mismatch: got %v, want %v", remid, node1.ID) + if !reflect.DeepEqual(rpubkey, &prv1.PublicKey) { + t.Errorf("dial side remote pubkey mismatch: got %v, want %v", rpubkey, &prv1.PublicKey) return } @@ -191,13 +193,13 @@ func TestProtocolHandshake(t *testing.T) { defer wg.Done() defer fd1.Close() rlpx := newRLPX(fd1) - remid, err := rlpx.doEncHandshake(prv1, nil) + rpubkey, err := rlpx.doEncHandshake(prv1, nil) if err != nil { t.Errorf("listen side enc handshake failed: %v", err) return } - if remid != node0.ID { - t.Errorf("listen side remote id mismatch: got %v, want %v", remid, node0.ID) + if !reflect.DeepEqual(rpubkey, &prv0.PublicKey) { + t.Errorf("listen side remote pubkey mismatch: got %v, want %v", rpubkey, &prv0.PublicKey) return } @@ -332,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) @@ -342,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/p2p/server.go b/p2p/server.go index 2cff94ea5b..566f01ffc5 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -18,33 +18,37 @@ package p2p import ( + "bytes" "crypto/ecdsa" + "encoding/hex" "errors" - "fmt" "net" + "sort" "sync" + "sync/atomic" "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/mclock" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p/discover" "github.com/ethereum/go-ethereum/p2p/discv5" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/enr" "github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/p2p/netutil" + "github.com/ethereum/go-ethereum/rlp" ) const ( - defaultDialTimeout = 15 * time.Second - refreshPeersInterval = 30 * time.Second - staticPeerCheckInterval = 15 * time.Second + defaultDialTimeout = 15 * time.Second - // Maximum number of concurrently handshaking inbound connections. - maxAcceptConns = 50 - - // Maximum number of concurrently dialing outbound connections. - maxActiveDialTasks = 16 + // Connectivity defaults. + maxActiveDialTasks = 16 + defaultMaxPendingPeers = 50 + defaultDialRatio = 3 // Maximum time allowed for reading a complete message. // This is effectively the amount of time a connection can be idle. @@ -70,11 +74,16 @@ type Config struct { // Zero defaults to preset values. MaxPendingPeers int `toml:",omitempty"` + // DialRatio controls the ratio of inbound to dialed connections. + // Example: a DialRatio of 2 allows 1/2 of connections to be dialed. + // Setting DialRatio to zero defaults it to 3. + DialRatio int `toml:",omitempty"` + // NoDiscovery can be used to disable the peer discovery mechanism. // Disabling is useful for protocol debugging (manual topology). NoDiscovery bool - // DiscoveryV5 specifies whether the the new topic-discovery based V5 discovery + // DiscoveryV5 specifies whether the new topic-discovery based V5 discovery // protocol should be started or not. DiscoveryV5 bool `toml:",omitempty"` @@ -84,7 +93,7 @@ type Config struct { // BootstrapNodes are used to establish connectivity // with the rest of the network. - BootstrapNodes []*discover.Node + BootstrapNodes []*enode.Node // BootstrapNodesV5 are used to establish connectivity // with the rest of the network using the V5 discovery @@ -93,11 +102,11 @@ type Config struct { // Static nodes are used as pre-configured connections which are always // maintained and re-connected on disconnects. - StaticNodes []*discover.Node + StaticNodes []*enode.Node // Trusted nodes are used as pre-configured connections which are always // allowed to connect, even above the peer limit. - TrustedNodes []*discover.Node + TrustedNodes []*enode.Node // Connectivity can be restricted to certain IP networks. // If this option is set to a non-nil value, only hosts which match one of the @@ -138,7 +147,7 @@ type Config struct { EnableMsgEvents bool // Logger is a custom logger to use with the p2p.Server. - Logger log.Logger + Logger log.Logger `toml:",omitempty"` } // Server manages all peer connections. @@ -154,6 +163,8 @@ type Server struct { lock sync.Mutex // protects running running bool + nodedb *enode.DB + localnode *enode.LocalNode ntab discoverTable listener net.Listener ourHandshake *protoHandshake @@ -165,8 +176,10 @@ type Server struct { peerOpDone chan struct{} quit chan struct{} - addstatic chan *discover.Node - removestatic chan *discover.Node + addstatic chan *enode.Node + removestatic chan *enode.Node + addtrusted chan *enode.Node + removetrusted chan *enode.Node posthandshake chan *conn addpeer chan *conn delpeer chan peerDrop @@ -175,7 +188,7 @@ type Server struct { log log.Logger } -type peerOpFunc func(map[discover.NodeID]*Peer) +type peerOpFunc func(map[enode.ID]*Peer) type peerDrop struct { *Peer @@ -183,7 +196,7 @@ type peerDrop struct { requested bool // true if signaled by the peer } -type connFlag int +type connFlag int32 const ( dynDialedConn connFlag = 1 << iota @@ -197,16 +210,16 @@ const ( type conn struct { fd net.Conn transport + node *enode.Node flags connFlag - cont chan error // The run loop uses cont to signal errors to SetupConn. - id discover.NodeID // valid after the encryption handshake - caps []Cap // valid after the protocol handshake - name string // valid after the protocol handshake + cont chan error // The run loop uses cont to signal errors to SetupConn. + caps []Cap // valid after the protocol handshake + name string // valid after the protocol handshake } type transport interface { // The two handshakes. - doEncHandshake(prv *ecdsa.PrivateKey, dialDest *discover.Node) (discover.NodeID, error) + doEncHandshake(prv *ecdsa.PrivateKey, dialDest *ecdsa.PublicKey) (*ecdsa.PublicKey, error) doProtoHandshake(our *protoHandshake) (*protoHandshake, error) // The MsgReadWriter can only be used after the encryption // handshake has completed. The code uses conn.id to track this @@ -214,14 +227,14 @@ type transport interface { MsgReadWriter // transports must provide Close because we use MsgPipe in some of // the tests. Closing the actual network connection doesn't do - // anything in those tests because NsgPipe doesn't use it. + // anything in those tests because MsgPipe doesn't use it. close(err error) } func (c *conn) String() string { s := c.flags.String() - if (c.id != discover.NodeID{}) { - s += " " + c.id.String() + if (c.node.ID() != enode.ID{}) { + s += " " + c.node.ID().String() } s += " " + c.fd.RemoteAddr().String() return s @@ -248,7 +261,23 @@ func (f connFlag) String() string { } func (c *conn) is(f connFlag) bool { - return c.flags&f != 0 + flags := connFlag(atomic.LoadInt32((*int32)(&c.flags))) + return flags&f != 0 +} + +func (c *conn) set(f connFlag, val bool) { + for { + oldFlags := connFlag(atomic.LoadInt32((*int32)(&c.flags))) + flags := oldFlags + if val { + flags |= f + } else { + flags &= ^f + } + if atomic.CompareAndSwapInt32((*int32)(&c.flags), int32(oldFlags), int32(flags)) { + return + } + } } // Peers returns all connected peers. @@ -258,7 +287,7 @@ func (srv *Server) Peers() []*Peer { // Note: We'd love to put this function into a variable but // that seems to cause a weird compiler error in some // environments. - case srv.peerOp <- func(peers map[discover.NodeID]*Peer) { + case srv.peerOp <- func(peers map[enode.ID]*Peer) { for _, p := range peers { ps = append(ps, p) } @@ -273,7 +302,7 @@ func (srv *Server) Peers() []*Peer { func (srv *Server) PeerCount() int { var count int select { - case srv.peerOp <- func(ps map[discover.NodeID]*Peer) { count = len(ps) }: + case srv.peerOp <- func(ps map[enode.ID]*Peer) { count = len(ps) }: <-srv.peerOpDone case <-srv.quit: } @@ -283,7 +312,7 @@ func (srv *Server) PeerCount() int { // AddPeer connects to the given node and maintains the connection until the // server is shut down. If the connection fails for any reason, the server will // attempt to reconnect the peer. -func (srv *Server) AddPeer(node *discover.Node) { +func (srv *Server) AddPeer(node *enode.Node) { select { case srv.addstatic <- node: case <-srv.quit: @@ -291,55 +320,53 @@ func (srv *Server) AddPeer(node *discover.Node) { } // RemovePeer disconnects from the given node -func (srv *Server) RemovePeer(node *discover.Node) { +func (srv *Server) RemovePeer(node *enode.Node) { select { case srv.removestatic <- node: case <-srv.quit: } } +// AddTrustedPeer adds the given node to a reserved whitelist which allows the +// node to always connect, even if the slot are full. +func (srv *Server) AddTrustedPeer(node *enode.Node) { + select { + case srv.addtrusted <- node: + case <-srv.quit: + } +} + +// RemoveTrustedPeer removes the given node from the trusted peer set. +func (srv *Server) RemoveTrustedPeer(node *enode.Node) { + select { + case srv.removetrusted <- node: + case <-srv.quit: + } +} + // SubscribePeers subscribes the given channel to peer events func (srv *Server) SubscribeEvents(ch chan *PeerEvent) event.Subscription { return srv.peerFeed.Subscribe(ch) } // Self returns the local node's endpoint information. -func (srv *Server) Self() *discover.Node { +func (srv *Server) Self() *enode.Node { srv.lock.Lock() - defer srv.lock.Unlock() + ln := srv.localnode + srv.lock.Unlock() - if !srv.running { - return &discover.Node{IP: net.ParseIP("0.0.0.0")} + if ln == nil { + return enode.NewV4(&srv.PrivateKey.PublicKey, net.ParseIP("0.0.0.0"), 0, 0) } - return srv.makeSelf(srv.listener, srv.ntab) -} - -func (srv *Server) makeSelf(listener net.Listener, ntab discoverTable) *discover.Node { - // If the server's not running, return an empty node. - // If the node is running but discovery is off, manually assemble the node infos. - if ntab == nil { - // Inbound connections disabled, use zero address. - if listener == nil { - return &discover.Node{IP: net.ParseIP("0.0.0.0"), ID: discover.PubkeyID(&srv.PrivateKey.PublicKey)} - } - // Otherwise inject the listener address too - addr := listener.Addr().(*net.TCPAddr) - return &discover.Node{ - ID: discover.PubkeyID(&srv.PrivateKey.PublicKey), - IP: addr.IP, - TCP: uint16(addr.Port), - } - } - // Otherwise return the discovery node. - return ntab.Self() + return ln.Node() } // Stop terminates the server and all active peer connections. // It blocks until all active connections have been closed. func (srv *Server) Stop() { srv.lock.Lock() - defer srv.lock.Unlock() if !srv.running { + srv.lock.Unlock() return } srv.running = false @@ -348,6 +375,7 @@ func (srv *Server) Stop() { srv.listener.Close() } close(srv.quit) + srv.lock.Unlock() srv.loopWG.Wait() } @@ -362,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) { @@ -390,11 +418,13 @@ func (srv *Server) Start() (err error) { if srv.log == nil { srv.log = log.New() } - srv.log.Info("Starting P2P networking") + if srv.NoDial && srv.ListenAddr == "" { + srv.log.Warn("P2P server will be useless, neither dialing nor listening") + } // 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 @@ -406,66 +436,127 @@ func (srv *Server) Start() (err error) { srv.addpeer = make(chan *conn) srv.delpeer = make(chan peerDrop) srv.posthandshake = make(chan *conn) - srv.addstatic = make(chan *discover.Node) - srv.removestatic = make(chan *discover.Node) + srv.addstatic = make(chan *enode.Node) + srv.removestatic = make(chan *enode.Node) + srv.addtrusted = make(chan *enode.Node) + srv.removetrusted = make(chan *enode.Node) srv.peerOp = make(chan peerOpFunc) srv.peerOpDone = make(chan struct{}) - var ( - conn *net.UDPConn - sconn *sharedUDPConn - realaddr *net.UDPAddr - unhandled chan discover.ReadPacket - ) - - if !srv.NoDiscovery || srv.DiscoveryV5 { - addr, err := net.ResolveUDPAddr("udp", srv.ListenAddr) - if err != nil { + if err := srv.setupLocalNode(); err != nil { + return err + } + if srv.ListenAddr != "" { + if err := srv.setupListening(); err != nil { return err } - conn, err = net.ListenUDP("udp", addr) - if err != nil { - return err - } - - realaddr = conn.LocalAddr().(*net.UDPAddr) - if srv.NAT != nil { - if !realaddr.IP.IsLoopback() { - go nat.Map(srv.NAT, srv.quit, "udp", realaddr.Port, realaddr.Port, "ethereum discovery") - } - // TODO: react to external IP changes over time. - if ext, err := srv.NAT.ExternalIP(); err == nil { - realaddr = &net.UDPAddr{IP: ext, Port: realaddr.Port} - } - } + } + if err := srv.setupDiscovery(); err != nil { + return err } - if !srv.NoDiscovery && srv.DiscoveryV5 { - unhandled = make(chan discover.ReadPacket, 100) - sconn = &sharedUDPConn{conn, unhandled} + dynPeers := srv.maxDialedConns() + dialer := newDialState(srv.localnode.ID(), srv.StaticNodes, srv.BootstrapNodes, srv.ntab, dynPeers, srv.NetRestrict) + srv.loopWG.Add(1) + go srv.run(dialer) + return nil +} + +func (srv *Server) setupLocalNode() error { + // Create the devp2p handshake. + pubkey := crypto.FromECDSAPub(&srv.PrivateKey.PublicKey) + srv.ourHandshake = &protoHandshake{Version: baseProtocolVersion, Name: srv.Name, ID: pubkey[1:]} + for _, p := range srv.Protocols { + srv.ourHandshake.Caps = append(srv.ourHandshake.Caps, p.cap()) + } + sort.Sort(capsByNameAndVersion(srv.ourHandshake.Caps)) + + // Create the local node. + db, err := enode.OpenDB(srv.Config.NodeDatabase) + if err != nil { + return err + } + srv.nodedb = db + srv.localnode = enode.NewLocalNode(db, srv.PrivateKey) + srv.localnode.SetFallbackIP(net.IP{127, 0, 0, 1}) + srv.localnode.Set(capsByNameAndVersion(srv.ourHandshake.Caps)) + // TODO: check conflicts + for _, p := range srv.Protocols { + for _, e := range p.Attributes { + srv.localnode.Set(e) + } + } + switch srv.NAT.(type) { + case nil: + // No NAT interface, do nothing. + case nat.ExtIP: + // ExtIP doesn't block, set the IP right away. + ip, _ := srv.NAT.ExternalIP() + srv.localnode.SetStaticIP(ip) + default: + // Ask the router about the IP. This takes a while and blocks startup, + // do it in the background. + srv.loopWG.Add(1) + go func() { + defer srv.loopWG.Done() + if ip, err := srv.NAT.ExternalIP(); err == nil { + srv.localnode.SetStaticIP(ip) + } + }() + } + return nil +} + +func (srv *Server) setupDiscovery() error { + if srv.NoDiscovery && !srv.DiscoveryV5 { + return nil } - // node table + addr, err := net.ResolveUDPAddr("udp", srv.ListenAddr) + if err != nil { + return err + } + conn, err := net.ListenUDP("udp", addr) + if err != nil { + return err + } + realaddr := conn.LocalAddr().(*net.UDPAddr) + srv.log.Debug("UDP listener up", "addr", realaddr) + if srv.NAT != nil { + if !realaddr.IP.IsLoopback() { + go nat.Map(srv.NAT, srv.quit, "udp", realaddr.Port, realaddr.Port, "ethereum discovery") + } + } + srv.localnode.SetFallbackUDP(realaddr.Port) + + // Discovery V4 + var unhandled chan discover.ReadPacket + var sconn *sharedUDPConn if !srv.NoDiscovery { - ntab, err := discover.ListenUDP(srv.PrivateKey, conn, realaddr, unhandled, srv.NodeDatabase, srv.NetRestrict) - if err != nil { - return err + if srv.DiscoveryV5 { + unhandled = make(chan discover.ReadPacket, 100) + sconn = &sharedUDPConn{conn, unhandled} } - if err := ntab.SetFallbackNodes(srv.BootstrapNodes); err != nil { + cfg := discover.Config{ + PrivateKey: srv.PrivateKey, + NetRestrict: srv.NetRestrict, + Bootnodes: srv.BootstrapNodes, + Unhandled: unhandled, + } + ntab, err := discover.ListenUDP(conn, srv.localnode, cfg) + if err != nil { return err } srv.ntab = ntab } - + // Discovery V5 if srv.DiscoveryV5 { - var ( - ntab *discv5.Network - err error - ) + var ntab *discv5.Network + var err error if sconn != nil { - ntab, err = discv5.ListenUDP(srv.PrivateKey, sconn, realaddr, "", srv.NetRestrict) //srv.NodeDatabase) + ntab, err = discv5.ListenUDP(srv.PrivateKey, sconn, "", srv.NetRestrict) } else { - ntab, err = discv5.ListenUDP(srv.PrivateKey, conn, realaddr, "", srv.NetRestrict) //srv.NodeDatabase) + ntab, err = discv5.ListenUDP(srv.PrivateKey, conn, "", srv.NetRestrict) } if err != nil { return err @@ -475,35 +566,10 @@ func (srv *Server) Start() (err error) { } srv.DiscV5 = ntab } - - dynPeers := (srv.MaxPeers + 1) / 2 - if srv.NoDiscovery { - dynPeers = 0 - } - dialer := newDialState(srv.StaticNodes, srv.BootstrapNodes, srv.ntab, dynPeers, srv.NetRestrict) - - // handshake - srv.ourHandshake = &protoHandshake{Version: baseProtocolVersion, Name: srv.Name, ID: discover.PubkeyID(&srv.PrivateKey.PublicKey)} - for _, p := range srv.Protocols { - srv.ourHandshake.Caps = append(srv.ourHandshake.Caps, p.cap()) - } - // listen/dial - if srv.ListenAddr != "" { - if err := srv.startListening(); err != nil { - return err - } - } - if srv.NoDial && srv.ListenAddr == "" { - srv.log.Warn("P2P server will be useless, neither dialing nor listening") - } - - srv.loopWG.Add(1) - go srv.run(dialer) - srv.running = true return nil } -func (srv *Server) startListening() error { +func (srv *Server) setupListening() error { // Launch the TCP listener. listener, err := net.Listen("tcp", srv.ListenAddr) if err != nil { @@ -512,8 +578,11 @@ func (srv *Server) startListening() error { laddr := listener.Addr().(*net.TCPAddr) srv.ListenAddr = laddr.String() srv.listener = listener + srv.localnode.Set(enr.TCP(laddr.Port)) + srv.loopWG.Add(1) go srv.listenLoop() + // Map the TCP listening port if NAT is configured. if !laddr.IP.IsLoopback() && srv.NAT != nil { srv.loopWG.Add(1) @@ -526,26 +595,29 @@ func (srv *Server) startListening() error { } type dialer interface { - newTasks(running int, peers map[discover.NodeID]*Peer, now time.Time) []task + newTasks(running int, peers map[enode.ID]*Peer, now time.Time) []task taskDone(task, time.Time) - addStatic(*discover.Node) - removeStatic(*discover.Node) + addStatic(*enode.Node) + removeStatic(*enode.Node) } func (srv *Server) run(dialstate dialer) { + srv.log.Info("Started P2P networking", "self", srv.localnode.Node()) defer srv.loopWG.Done() + defer srv.nodedb.Close() + var ( - peers = make(map[discover.NodeID]*Peer) - trusted = make(map[discover.NodeID]bool, len(srv.TrustedNodes)) + peers = make(map[enode.ID]*Peer) + inboundCount = 0 + trusted = make(map[enode.ID]bool, len(srv.TrustedNodes)) taskdone = make(chan task, maxActiveDialTasks) runningTasks []task queuedTasks []task // tasks that can't run yet ) // Put trusted nodes into a map to speed up checks. - // Trusted peers are loaded on startup and cannot be - // modified while the server is running. + // Trusted peers are loaded on startup or added via AddTrustedPeer RPC. for _, n := range srv.TrustedNodes { - trusted[n.ID] = true + trusted[n.ID()] = true } // removes t from runningTasks @@ -590,17 +662,37 @@ running: // This channel is used by AddPeer to add to the // ephemeral static peer list. Add it to the dialer, // it will keep the node connected. - srv.log.Debug("Adding static node", "node", n) + srv.log.Trace("Adding static node", "node", n) dialstate.addStatic(n) case n := <-srv.removestatic: // This channel is used by RemovePeer to send a // disconnect request to a peer and begin the - // stop keeping the node connected - srv.log.Debug("Removing static node", "node", n) + // stop keeping the node connected. + srv.log.Trace("Removing static node", "node", n) dialstate.removeStatic(n) - if p, ok := peers[n.ID]; ok { + if p, ok := peers[n.ID()]; ok { p.Disconnect(DiscRequested) } + case n := <-srv.addtrusted: + // This channel is used by AddTrustedPeer to add an enode + // to the trusted node set. + srv.log.Trace("Adding trusted node", "node", n) + trusted[n.ID()] = true + // Mark any already-connected peer as trusted + if p, ok := peers[n.ID()]; ok { + p.rw.set(trustedConn, true) + } + case n := <-srv.removetrusted: + // This channel is used by RemoveTrustedPeer to remove an enode + // from the trusted node set. + srv.log.Trace("Removing trusted node", "node", n) + if _, ok := trusted[n.ID()]; ok { + delete(trusted, n.ID()) + } + // Unmark any already-connected peer as trusted + if p, ok := peers[n.ID()]; ok { + p.rw.set(trustedConn, false) + } case op := <-srv.peerOp: // This channel is used by Peers and PeerCount. op(peers) @@ -615,20 +707,20 @@ running: case c := <-srv.posthandshake: // A connection has passed the encryption handshake so // the remote identity is known (but hasn't been verified yet). - if trusted[c.id] { + if trusted[c.node.ID()] { // Ensure that the trusted flag is set before checking against MaxPeers. c.flags |= trustedConn } // TODO: track in-progress inbound node IDs (pre-Peer) to avoid dialing them. select { - case c.cont <- srv.encHandshakeChecks(peers, c): + case c.cont <- srv.encHandshakeChecks(peers, inboundCount, c): case <-srv.quit: break running } case c := <-srv.addpeer: // At this point the connection is past the protocol handshake. // Its capabilities are known and the remote identity is verified. - err := srv.protoHandshakeChecks(peers, c) + err := srv.protoHandshakeChecks(peers, inboundCount, c) if err == nil { // The handshakes are done and it passed all checks. p := newPeer(c, srv.Protocols) @@ -639,8 +731,11 @@ running: } name := truncateName(c.name) srv.log.Debug("Adding p2p peer", "name", name, "addr", c.fd.RemoteAddr(), "peers", len(peers)+1) - peers[c.id] = p go srv.runPeer(p) + peers[c.node.ID()] = p + if p.Inbound() { + inboundCount++ + } } // The dialer logic relies on the assumption that // dial tasks complete after the peer has been added or @@ -655,6 +750,9 @@ running: d := common.PrettyDuration(mclock.Now() - pd.created) pd.log.Debug("Removing p2p peer", "duration", d, "peers", len(peers)-1, "req", pd.requested, "err", pd.err) delete(peers, pd.ID()) + if pd.Inbound() { + inboundCount-- + } } } @@ -681,43 +779,52 @@ running: } } -func (srv *Server) protoHandshakeChecks(peers map[discover.NodeID]*Peer, c *conn) error { +func (srv *Server) protoHandshakeChecks(peers map[enode.ID]*Peer, inboundCount int, c *conn) error { // Drop connections with no matching protocols. if len(srv.Protocols) > 0 && countMatchingProtocols(srv.Protocols, c.caps) == 0 { return DiscUselessPeer } // Repeat the encryption handshake checks because the // peer set might have changed between the handshakes. - return srv.encHandshakeChecks(peers, c) + return srv.encHandshakeChecks(peers, inboundCount, c) } -func (srv *Server) encHandshakeChecks(peers map[discover.NodeID]*Peer, c *conn) error { +func (srv *Server) encHandshakeChecks(peers map[enode.ID]*Peer, inboundCount int, c *conn) error { switch { case !c.is(trustedConn|staticDialedConn) && len(peers) >= srv.MaxPeers: return DiscTooManyPeers - case peers[c.id] != nil: + case !c.is(trustedConn) && c.is(inboundConn) && inboundCount >= srv.maxInboundConns(): + return DiscTooManyPeers + case peers[c.node.ID()] != nil: return DiscAlreadyConnected - case c.id == srv.Self().ID: + case c.node.ID() == srv.localnode.ID(): return DiscSelf default: return nil } } -type tempError interface { - Temporary() bool +func (srv *Server) maxInboundConns() int { + return srv.MaxPeers - srv.maxDialedConns() +} +func (srv *Server) maxDialedConns() int { + if srv.NoDiscovery || srv.NoDial { + return 0 + } + r := srv.DialRatio + if r == 0 { + r = defaultDialRatio + } + return srv.MaxPeers / r } // listenLoop runs in its own goroutine and accepts // inbound connections. func (srv *Server) listenLoop() { defer srv.loopWG.Done() - srv.log.Info("RLPx listener up", "self", srv.makeSelf(srv.listener, srv.ntab)) + srv.log.Debug("TCP listener up", "addr", srv.listener.Addr()) - // This channel acts as a semaphore limiting - // active inbound connections that are lingering pre-handshake. - // If all slots are taken, no further connections are accepted. - tokens := maxAcceptConns + tokens := defaultMaxPendingPeers if srv.MaxPendingPeers > 0 { tokens = srv.MaxPendingPeers } @@ -736,7 +843,7 @@ func (srv *Server) listenLoop() { ) for { fd, err = srv.listener.Accept() - if tempErr, ok := err.(tempError); ok && tempErr.Temporary() { + if netutil.IsTemporaryError(err) { srv.log.Debug("Temporary read error", "err", err) continue } else if err != nil { @@ -756,11 +863,12 @@ func (srv *Server) listenLoop() { } } - fd = newMeteredConn(fd, true) + var ip net.IP + if tcp, ok := fd.RemoteAddr().(*net.TCPAddr); ok { + ip = tcp.IP + } + fd = newMeteredConn(fd, true, ip) srv.log.Trace("Accepted connection", "addr", fd.RemoteAddr()) - - // Spawn the handler. It will give the slot back when the connection - // has been established. go func() { srv.SetupConn(fd, inboundConn, nil) slots <- struct{}{} @@ -771,21 +879,17 @@ func (srv *Server) listenLoop() { // SetupConn runs the handshakes and attempts to add the connection // as a peer. It returns when the connection has been added as a peer // or the handshakes have failed. -func (srv *Server) SetupConn(fd net.Conn, flags connFlag, dialDest *discover.Node) error { - self := srv.Self() - if self == nil { - return errors.New("shutdown") - } +func (srv *Server) SetupConn(fd net.Conn, flags connFlag, dialDest *enode.Node) error { c := &conn{fd: fd, transport: srv.newTransport(fd), flags: flags, cont: make(chan error)} err := srv.setupConn(c, flags, dialDest) if err != nil { c.close(err) - srv.log.Trace("Setting up connection failed", "id", c.id, "err", err) + srv.log.Trace("Setting up connection failed", "addr", fd.RemoteAddr(), "err", err) } return err } -func (srv *Server) setupConn(c *conn, flags connFlag, dialDest *discover.Node) error { +func (srv *Server) setupConn(c *conn, flags connFlag, dialDest *enode.Node) error { // Prevent leftover pending conns from entering the handshake. srv.lock.Lock() running := srv.running @@ -793,18 +897,33 @@ func (srv *Server) setupConn(c *conn, flags connFlag, dialDest *discover.Node) e if !running { return errServerStopped } + // If dialing, figure out the remote public key. + var dialPubkey *ecdsa.PublicKey + if dialDest != nil { + dialPubkey = new(ecdsa.PublicKey) + if err := dialDest.Load((*enode.Secp256k1)(dialPubkey)); err != nil { + return errors.New("dial destination doesn't have a secp256k1 public key") + } + } // Run the encryption handshake. - var err error - if c.id, err = c.doEncHandshake(srv.PrivateKey, dialDest); err != nil { + remotePubkey, err := c.doEncHandshake(srv.PrivateKey, dialPubkey) + if err != nil { srv.log.Trace("Failed RLPx handshake", "addr", c.fd.RemoteAddr(), "conn", c.flags, "err", err) return err } - clog := srv.log.New("id", c.id, "addr", c.fd.RemoteAddr(), "conn", c.flags) - // For dialed connections, check that the remote public key matches. - if dialDest != nil && c.id != dialDest.ID { - clog.Trace("Dialed identity mismatch", "want", c, dialDest.ID) - return DiscUnexpectedIdentity + if dialDest != nil { + // For dialed connections, check that the remote public key matches. + if dialPubkey.X.Cmp(remotePubkey.X) != 0 || dialPubkey.Y.Cmp(remotePubkey.Y) != 0 { + return DiscUnexpectedIdentity + } + c.node = dialDest + } else { + c.node = nodeFromConn(remotePubkey, c.fd) } + if conn, ok := c.fd.(*meteredConn); ok { + conn.handshakeDone(c.node.ID()) + } + clog := srv.log.New("id", c.node.ID(), "addr", c.fd.RemoteAddr(), "conn", c.flags) err = srv.checkpoint(c, srv.posthandshake) if err != nil { clog.Trace("Rejected peer before protocol handshake", "err", err) @@ -816,8 +935,8 @@ func (srv *Server) setupConn(c *conn, flags connFlag, dialDest *discover.Node) e clog.Trace("Failed proto handshake", "err", err) return err } - if phs.ID != c.id { - clog.Trace("Wrong devp2p handshake identity", "err", phs.ID) + if id := c.node.ID(); !bytes.Equal(crypto.Keccak256(phs.ID), id[:]) { + clog.Trace("Wrong devp2p handshake identity", "phsid", hex.EncodeToString(phs.ID)) return DiscUnexpectedIdentity } c.caps, c.name = phs.Caps, phs.Name @@ -832,6 +951,16 @@ func (srv *Server) setupConn(c *conn, flags connFlag, dialDest *discover.Node) e return nil } +func nodeFromConn(pubkey *ecdsa.PublicKey, conn net.Conn) *enode.Node { + var ip net.IP + var port int + if tcp, ok := conn.RemoteAddr().(*net.TCPAddr); ok { + ip = tcp.IP + port = tcp.Port + } + return enode.NewV4(pubkey, ip, port, port) +} + func truncateName(s string) string { if len(s) > 20 { return s[:20] + "..." @@ -889,6 +1018,7 @@ type NodeInfo struct { ID string `json:"id"` // Unique node identifier (also the encryption key) Name string `json:"name"` // Name of the node, including client type, version, OS, custom data Enode string `json:"enode"` // Enode URL for adding this peer from remote peers + ENR string `json:"enr"` // Ethereum Node Record IP string `json:"ip"` // IP address of the node Ports struct { Discovery int `json:"discovery"` // UDP listening port for discovery protocol @@ -900,19 +1030,21 @@ type NodeInfo struct { // NodeInfo gathers and returns a collection of metadata known about the host. func (srv *Server) NodeInfo() *NodeInfo { - node := srv.Self() - // Gather and assemble the generic node infos + node := srv.Self() info := &NodeInfo{ Name: srv.Name, Enode: node.String(), - ID: node.ID.String(), - IP: node.IP.String(), + ID: node.ID().String(), + IP: node.IP().String(), ListenAddr: srv.ListenAddr, Protocols: make(map[string]interface{}), } - info.Ports.Discovery = int(node.UDP) - info.Ports.Listener = int(node.TCP) + info.Ports.Discovery = node.UDP() + info.Ports.Listener = node.TCP() + if enc, err := rlp.EncodeToBytes(node.Record()); err == nil { + info.ENR = "0x" + hex.EncodeToString(enc) + } // Gather all the running protocol infos (only once per protocol type) for _, proto := range srv.Protocols { diff --git a/p2p/server_test.go b/p2p/server_test.go index 10c36528eb..f665c14245 100644 --- a/p2p/server_test.go +++ b/p2p/server_test.go @@ -26,39 +26,41 @@ 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/discover" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/enr" + "golang.org/x/crypto/sha3" ) -func init() { - // log.Root().SetHandler(log.LvlFilterHandler(log.LvlError, log.StreamHandler(os.Stderr, log.TerminalFormat(false)))) -} +// func init() { +// log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(false)))) +// } type testTransport struct { - id discover.NodeID + rpub *ecdsa.PublicKey *rlpx closeErr error } -func newTestTransport(id discover.NodeID, fd net.Conn) transport { +func newTestTransport(rpub *ecdsa.PublicKey, fd net.Conn) transport { wrapped := newRLPX(fd).(*rlpx) wrapped.rw = newRLPXFrameRW(fd, secrets{ MAC: zero16, AES: zero16, - IngressMAC: sha3.NewKeccak256(), - EgressMAC: sha3.NewKeccak256(), + IngressMAC: sha3.NewLegacyKeccak256(), + EgressMAC: sha3.NewLegacyKeccak256(), }) - return &testTransport{id: id, rlpx: wrapped} + return &testTransport{rpub: rpub, rlpx: wrapped} } -func (c *testTransport) doEncHandshake(prv *ecdsa.PrivateKey, dialDest *discover.Node) (discover.NodeID, error) { - return c.id, nil +func (c *testTransport) doEncHandshake(prv *ecdsa.PrivateKey, dialDest *ecdsa.PublicKey) (*ecdsa.PublicKey, error) { + return c.rpub, nil } func (c *testTransport) doProtoHandshake(our *protoHandshake) (*protoHandshake, error) { - return &protoHandshake{ID: c.id, Name: "test"}, nil + pubkey := crypto.FromECDSAPub(c.rpub)[1:] + return &protoHandshake{ID: pubkey, Name: "test"}, nil } func (c *testTransport) close(err error) { @@ -66,7 +68,7 @@ func (c *testTransport) close(err error) { c.closeErr = err } -func startTestServer(t *testing.T, id discover.NodeID, pf func(*Peer)) *Server { +func startTestServer(t *testing.T, remoteKey *ecdsa.PublicKey, pf func(*Peer)) *Server { config := Config{ Name: "test", MaxPeers: 10, @@ -76,7 +78,7 @@ func startTestServer(t *testing.T, id discover.NodeID, pf func(*Peer)) *Server { server := &Server{ Config: config, newPeerHook: pf, - newTransport: func(fd net.Conn) transport { return newTestTransport(id, fd) }, + newTransport: func(fd net.Conn) transport { return newTestTransport(remoteKey, fd) }, } if err := server.Start(); err != nil { t.Fatalf("Could not start server: %v", err) @@ -87,14 +89,11 @@ func startTestServer(t *testing.T, id discover.NodeID, pf func(*Peer)) *Server { func TestServerListen(t *testing.T) { // start the test server connected := make(chan *Peer) - remid := randomID() + remid := &newkey().PublicKey srv := startTestServer(t, remid, func(p *Peer) { - if p.ID() != remid { + if p.ID() != enode.PubkeyToIDV4(remid) { t.Error("peer func called with wrong node id") } - if p == nil { - t.Error("peer func called with nil conn") - } connected <- p }) defer close(connected) @@ -141,14 +140,15 @@ func TestServerDial(t *testing.T) { // start the server connected := make(chan *Peer) - remid := randomID() + remid := &newkey().PublicKey srv := startTestServer(t, remid, func(p *Peer) { connected <- p }) defer close(connected) defer srv.Stop() // tell the server to connect tcpAddr := listener.Addr().(*net.TCPAddr) - srv.AddPeer(&discover.Node{ID: remid, IP: tcpAddr.IP, TCP: uint16(tcpAddr.Port)}) + node := enode.NewV4(remid, tcpAddr.IP, tcpAddr.Port, 0) + srv.AddPeer(node) select { case conn := <-accepted: @@ -156,7 +156,7 @@ func TestServerDial(t *testing.T) { select { case peer := <-connected: - if peer.ID() != remid { + if peer.ID() != enode.PubkeyToIDV4(remid) { t.Errorf("peer has wrong id") } if peer.Name() != "test" { @@ -170,6 +170,29 @@ func TestServerDial(t *testing.T) { if !reflect.DeepEqual(peers, []*Peer{peer}) { t.Errorf("Peers mismatch: got %v, want %v", peers, []*Peer{peer}) } + + // Test AddTrustedPeer/RemoveTrustedPeer and changing Trusted flags + // Particularly for race conditions on changing the flag state. + if peer := srv.Peers()[0]; peer.Info().Network.Trusted { + t.Errorf("peer is trusted prematurely: %v", peer) + } + done := make(chan bool) + go func() { + srv.AddTrustedPeer(node) + if peer := srv.Peers()[0]; !peer.Info().Network.Trusted { + t.Errorf("peer is not trusted after AddTrustedPeer: %v", peer) + } + srv.RemoveTrustedPeer(node) + if peer := srv.Peers()[0]; peer.Info().Network.Trusted { + t.Errorf("peer is trusted after RemoveTrustedPeer: %v", peer) + } + done <- true + }() + // Trigger potential race conditions + peer = srv.Peers()[0] + _ = peer.Inbound() + _ = peer.Info() + <-done case <-time.After(1 * time.Second): t.Error("server did not launch peer within one second") } @@ -187,7 +210,7 @@ func TestServerTaskScheduling(t *testing.T) { quit, returned = make(chan struct{}), make(chan struct{}) tc = 0 tg = taskgen{ - newFunc: func(running int, peers map[discover.NodeID]*Peer) []task { + newFunc: func(running int, peers map[enode.ID]*Peer) []task { tc++ return []task{&testTask{index: tc - 1}} }, @@ -202,12 +225,15 @@ func TestServerTaskScheduling(t *testing.T) { // The Server in this test isn't actually running // because we're only interested in what run does. + db, _ := enode.OpenDB("") srv := &Server{ - Config: Config{MaxPeers: 10}, - quit: make(chan struct{}), - ntab: fakeTable{}, - running: true, - log: log.New(), + Config: Config{MaxPeers: 10}, + localnode: enode.NewLocalNode(db, newkey()), + nodedb: db, + quit: make(chan struct{}), + ntab: fakeTable{}, + running: true, + log: log.New(), } srv.loopWG.Add(1) go func() { @@ -248,11 +274,14 @@ func TestServerManyTasks(t *testing.T) { } var ( - srv = &Server{ - quit: make(chan struct{}), - ntab: fakeTable{}, - running: true, - log: log.New(), + db, _ = enode.OpenDB("") + srv = &Server{ + quit: make(chan struct{}), + localnode: enode.NewLocalNode(db, newkey()), + nodedb: db, + ntab: fakeTable{}, + running: true, + log: log.New(), } done = make(chan *testTask) start, end = 0, 0 @@ -260,7 +289,7 @@ func TestServerManyTasks(t *testing.T) { defer srv.Stop() srv.loopWG.Add(1) go srv.run(taskgen{ - newFunc: func(running int, peers map[discover.NodeID]*Peer) []task { + newFunc: func(running int, peers map[enode.ID]*Peer) []task { start, end = end, end+maxActiveDialTasks+10 if end > len(alltasks) { end = len(alltasks) @@ -295,19 +324,19 @@ func TestServerManyTasks(t *testing.T) { } type taskgen struct { - newFunc func(running int, peers map[discover.NodeID]*Peer) []task + newFunc func(running int, peers map[enode.ID]*Peer) []task doneFunc func(task) } -func (tg taskgen) newTasks(running int, peers map[discover.NodeID]*Peer, now time.Time) []task { +func (tg taskgen) newTasks(running int, peers map[enode.ID]*Peer, now time.Time) []task { return tg.newFunc(running, peers) } func (tg taskgen) taskDone(t task, now time.Time) { tg.doneFunc(t) } -func (tg taskgen) addStatic(*discover.Node) { +func (tg taskgen) addStatic(*enode.Node) { } -func (tg taskgen) removeStatic(*discover.Node) { +func (tg taskgen) removeStatic(*enode.Node) { } type testTask struct { @@ -323,13 +352,14 @@ func (t *testTask) Do(srv *Server) { // just after the encryption handshake when the server is // at capacity. Trusted connections should still be accepted. func TestServerAtCap(t *testing.T) { - trustedID := randomID() + trustedNode := newkey() + trustedID := enode.PubkeyToIDV4(&trustedNode.PublicKey) srv := &Server{ Config: Config{ PrivateKey: newkey(), MaxPeers: 10, NoDial: true, - TrustedNodes: []*discover.Node{{ID: trustedID}}, + TrustedNodes: []*enode.Node{newNode(trustedID, nil)}, }, } if err := srv.Start(); err != nil { @@ -337,10 +367,11 @@ func TestServerAtCap(t *testing.T) { } defer srv.Stop() - newconn := func(id discover.NodeID) *conn { + newconn := func(id enode.ID) *conn { fd, _ := net.Pipe() - tx := newTestTransport(id, fd) - return &conn{fd: fd, transport: tx, flags: inboundConn, id: id, cont: make(chan error)} + tx := newTestTransport(&trustedNode.PublicKey, fd) + node := enode.SignNull(new(enr.Record), id) + return &conn{fd: fd, transport: tx, flags: inboundConn, node: node, cont: make(chan error)} } // Inject a few connections to fill up the peer set. @@ -351,7 +382,8 @@ func TestServerAtCap(t *testing.T) { } } // Try inserting a non-trusted connection. - c := newconn(randomID()) + anotherID := randomID() + c := newconn(anotherID) if err := srv.checkpoint(c, srv.posthandshake); err != DiscTooManyPeers { t.Error("wrong error for insert:", err) } @@ -364,62 +396,144 @@ func TestServerAtCap(t *testing.T) { t.Error("Server did not set trusted flag") } + // Remove from trusted set and try again + srv.RemoveTrustedPeer(newNode(trustedID, nil)) + c = newconn(trustedID) + if err := srv.checkpoint(c, srv.posthandshake); err != DiscTooManyPeers { + t.Error("wrong error for insert:", err) + } + + // Add anotherID to trusted set and try again + srv.AddTrustedPeer(newNode(anotherID, nil)) + c = newconn(anotherID) + if err := srv.checkpoint(c, srv.posthandshake); err != nil { + t.Error("unexpected error for trusted conn @posthandshake:", err) + } + if !c.is(trustedConn) { + t.Error("Server did not set trusted flag") + } +} + +func TestServerPeerLimits(t *testing.T) { + srvkey := newkey() + clientkey := newkey() + clientnode := enode.NewV4(&clientkey.PublicKey, nil, 0, 0) + + var tp = &setupTransport{ + pubkey: &clientkey.PublicKey, + phs: protoHandshake{ + ID: crypto.FromECDSAPub(&clientkey.PublicKey)[1:], + // Force "DiscUselessPeer" due to unmatching caps + // Caps: []Cap{discard.cap()}, + }, + } + + srv := &Server{ + Config: Config{ + PrivateKey: srvkey, + MaxPeers: 0, + NoDial: true, + Protocols: []Protocol{discard}, + }, + newTransport: func(fd net.Conn) transport { return tp }, + log: log.New(), + } + if err := srv.Start(); err != nil { + t.Fatalf("couldn't start server: %v", err) + } + defer srv.Stop() + + // Check that server is full (MaxPeers=0) + flags := dynDialedConn + dialDest := clientnode + conn, _ := net.Pipe() + srv.SetupConn(conn, flags, dialDest) + if tp.closeErr != DiscTooManyPeers { + t.Errorf("unexpected close error: %q", tp.closeErr) + } + conn.Close() + + srv.AddTrustedPeer(clientnode) + + // Check that server allows a trusted peer despite being full. + conn, _ = net.Pipe() + srv.SetupConn(conn, flags, dialDest) + if tp.closeErr == DiscTooManyPeers { + t.Errorf("failed to bypass MaxPeers with trusted node: %q", tp.closeErr) + } + + if tp.closeErr != DiscUselessPeer { + t.Errorf("unexpected close error: %q", tp.closeErr) + } + conn.Close() + + srv.RemoveTrustedPeer(clientnode) + + // Check that server is full again. + conn, _ = net.Pipe() + srv.SetupConn(conn, flags, dialDest) + if tp.closeErr != DiscTooManyPeers { + t.Errorf("unexpected close error: %q", tp.closeErr) + } + conn.Close() } func TestServerSetupConn(t *testing.T) { - id := randomID() - srvkey := newkey() - srvid := discover.PubkeyID(&srvkey.PublicKey) + var ( + clientkey, srvkey = newkey(), newkey() + clientpub = &clientkey.PublicKey + srvpub = &srvkey.PublicKey + ) tests := []struct { dontstart bool tt *setupTransport flags connFlag - dialDest *discover.Node + dialDest *enode.Node wantCloseErr error wantCalls string }{ { dontstart: true, - tt: &setupTransport{id: id}, + tt: &setupTransport{pubkey: clientpub}, wantCalls: "close,", wantCloseErr: errServerStopped, }, { - tt: &setupTransport{id: id, encHandshakeErr: errors.New("read error")}, + tt: &setupTransport{pubkey: clientpub, encHandshakeErr: errors.New("read error")}, flags: inboundConn, wantCalls: "doEncHandshake,close,", wantCloseErr: errors.New("read error"), }, { - tt: &setupTransport{id: id}, - dialDest: &discover.Node{ID: randomID()}, + tt: &setupTransport{pubkey: clientpub}, + dialDest: enode.NewV4(&newkey().PublicKey, nil, 0, 0), flags: dynDialedConn, wantCalls: "doEncHandshake,close,", wantCloseErr: DiscUnexpectedIdentity, }, { - tt: &setupTransport{id: id, phs: &protoHandshake{ID: randomID()}}, - dialDest: &discover.Node{ID: id}, + tt: &setupTransport{pubkey: clientpub, phs: protoHandshake{ID: randomID().Bytes()}}, + dialDest: enode.NewV4(clientpub, nil, 0, 0), flags: dynDialedConn, wantCalls: "doEncHandshake,doProtoHandshake,close,", wantCloseErr: DiscUnexpectedIdentity, }, { - tt: &setupTransport{id: id, protoHandshakeErr: errors.New("foo")}, - dialDest: &discover.Node{ID: id}, + tt: &setupTransport{pubkey: clientpub, protoHandshakeErr: errors.New("foo")}, + dialDest: enode.NewV4(clientpub, nil, 0, 0), flags: dynDialedConn, wantCalls: "doEncHandshake,doProtoHandshake,close,", wantCloseErr: errors.New("foo"), }, { - tt: &setupTransport{id: srvid, phs: &protoHandshake{ID: srvid}}, + tt: &setupTransport{pubkey: srvpub, phs: protoHandshake{ID: crypto.FromECDSAPub(srvpub)[1:]}}, flags: inboundConn, wantCalls: "doEncHandshake,close,", wantCloseErr: DiscSelf, }, { - tt: &setupTransport{id: id, phs: &protoHandshake{ID: id}}, + tt: &setupTransport{pubkey: clientpub, phs: protoHandshake{ID: crypto.FromECDSAPub(clientpub)[1:]}}, flags: inboundConn, wantCalls: "doEncHandshake,doProtoHandshake,close,", wantCloseErr: DiscUselessPeer, @@ -454,26 +568,26 @@ func TestServerSetupConn(t *testing.T) { } type setupTransport struct { - id discover.NodeID - encHandshakeErr error - - phs *protoHandshake + pubkey *ecdsa.PublicKey + encHandshakeErr error + phs protoHandshake protoHandshakeErr error calls string closeErr error } -func (c *setupTransport) doEncHandshake(prv *ecdsa.PrivateKey, dialDest *discover.Node) (discover.NodeID, error) { +func (c *setupTransport) doEncHandshake(prv *ecdsa.PrivateKey, dialDest *ecdsa.PublicKey) (*ecdsa.PublicKey, error) { c.calls += "doEncHandshake," - return c.id, c.encHandshakeErr + return c.pubkey, c.encHandshakeErr } + func (c *setupTransport) doProtoHandshake(our *protoHandshake) (*protoHandshake, error) { c.calls += "doProtoHandshake," if c.protoHandshakeErr != nil { return nil, c.protoHandshakeErr } - return c.phs, nil + return &c.phs, nil } func (c *setupTransport) close(err error) { c.calls += "close," @@ -496,7 +610,7 @@ func newkey() *ecdsa.PrivateKey { return key } -func randomID() (id discover.NodeID) { +func randomID() (id enode.ID) { for i := range id { id[i] = byte(rand.Intn(255)) } diff --git a/p2p/simulations/README.md b/p2p/simulations/README.md index d1f8649eae..871d71b2c7 100644 --- a/p2p/simulations/README.md +++ b/p2p/simulations/README.md @@ -63,18 +63,6 @@ using the devp2p node stack rather than executing `main()`. The nodes listen for devp2p connections and WebSocket RPC clients on random localhost ports. -### DockerAdapter - -The `DockerAdapter` is similar to the `ExecAdapter` but executes `docker run` -to run the node in a Docker container using a Docker image containing the -simulation binary at `/bin/p2p-node`. - -The Docker image is built using `docker build` when the adapter is initialised, -meaning no prior setup is necessary other than having a working Docker client. - -Each node listens on the external IP of the container and the default p2p and -RPC ports (`30303` and `8546` respectively). - ## Network A simulation network is created with an ID and default service (which is used diff --git a/p2p/simulations/adapters/docker.go b/p2p/simulations/adapters/docker.go deleted file mode 100644 index 8ef5629fb5..0000000000 --- a/p2p/simulations/adapters/docker.go +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright 2017 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 adapters - -import ( - "errors" - "fmt" - "io" - "io/ioutil" - "os" - "os/exec" - "path/filepath" - "runtime" - "strings" - - "github.com/docker/docker/pkg/reexec" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p/discover" -) - -// DockerAdapter is a NodeAdapter which runs simulation nodes inside Docker -// containers. -// -// A Docker image is built which contains the current binary at /bin/p2p-node -// which when executed runs the underlying service (see the description -// of the execP2PNode function for more details) -type DockerAdapter struct { - ExecAdapter -} - -// NewDockerAdapter builds the p2p-node Docker image containing the current -// binary and returns a DockerAdapter -func NewDockerAdapter() (*DockerAdapter, error) { - // Since Docker containers run on Linux and this adapter runs the - // current binary in the container, it must be compiled for Linux. - // - // It is reasonable to require this because the caller can just - // compile the current binary in a Docker container. - if runtime.GOOS != "linux" { - return nil, errors.New("DockerAdapter can only be used on Linux as it uses the current binary (which must be a Linux binary)") - } - - if err := buildDockerImage(); err != nil { - return nil, err - } - - return &DockerAdapter{ - ExecAdapter{ - nodes: make(map[discover.NodeID]*ExecNode), - }, - }, nil -} - -// Name returns the name of the adapter for logging purposes -func (d *DockerAdapter) Name() string { - return "docker-adapter" -} - -// NewNode returns a new DockerNode using the given config -func (d *DockerAdapter) NewNode(config *NodeConfig) (Node, error) { - if len(config.Services) == 0 { - return nil, errors.New("node must have at least one service") - } - for _, service := range config.Services { - if _, exists := serviceFuncs[service]; !exists { - return nil, fmt.Errorf("unknown node service %q", service) - } - } - - // generate the config - conf := &execNodeConfig{ - Stack: node.DefaultConfig, - Node: config, - } - conf.Stack.DataDir = "/data" - conf.Stack.WSHost = "0.0.0.0" - conf.Stack.WSOrigins = []string{"*"} - conf.Stack.WSExposeAll = true - conf.Stack.P2P.EnableMsgEvents = false - conf.Stack.P2P.NoDiscovery = true - conf.Stack.P2P.NAT = nil - conf.Stack.NoUSB = true - conf.Stack.Logger = log.New("node.id", config.ID.String()) - - node := &DockerNode{ - ExecNode: ExecNode{ - ID: config.ID, - Config: conf, - adapter: &d.ExecAdapter, - }, - } - node.newCmd = node.dockerCommand - d.ExecAdapter.nodes[node.ID] = &node.ExecNode - return node, nil -} - -// DockerNode wraps an ExecNode but exec's the current binary in a docker -// container rather than locally -type DockerNode struct { - ExecNode -} - -// dockerCommand returns a command which exec's the binary in a Docker -// container. -// -// It uses a shell so that we can pass the _P2P_NODE_CONFIG environment -// variable to the container using the --env flag. -func (n *DockerNode) dockerCommand() *exec.Cmd { - return exec.Command( - "sh", "-c", - fmt.Sprintf( - `exec docker run --interactive --env _P2P_NODE_CONFIG="${_P2P_NODE_CONFIG}" %s p2p-node %s %s`, - dockerImage, strings.Join(n.Config.Node.Services, ","), n.ID.String(), - ), - ) -} - -// dockerImage is the name of the Docker image which gets built to run the -// simulation node -const dockerImage = "p2p-node" - -// buildDockerImage builds the Docker image which is used to run the simulation -// node in a Docker container. -// -// It adds the current binary as "p2p-node" so that it runs execP2PNode -// when executed. -func buildDockerImage() error { - // create a directory to use as the build context - dir, err := ioutil.TempDir("", "p2p-docker") - if err != nil { - return err - } - defer os.RemoveAll(dir) - - // copy the current binary into the build context - bin, err := os.Open(reexec.Self()) - if err != nil { - return err - } - defer bin.Close() - dst, err := os.OpenFile(filepath.Join(dir, "self.bin"), os.O_WRONLY|os.O_CREATE, 0755) - if err != nil { - return err - } - defer dst.Close() - if _, err := io.Copy(dst, bin); err != nil { - return err - } - - // create the Dockerfile - dockerfile := []byte(` -FROM ubuntu:16.04 -RUN mkdir /data -ADD self.bin /bin/p2p-node - `) - if err := ioutil.WriteFile(filepath.Join(dir, "Dockerfile"), dockerfile, 0644); err != nil { - return err - } - - // run 'docker build' - cmd := exec.Command("docker", "build", "-t", dockerImage, dir) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { - return fmt.Errorf("error building docker image: %s", err) - } - - return nil -} diff --git a/p2p/simulations/adapters/exec.go b/p2p/simulations/adapters/exec.go index a566fb27d8..bd8bcbc856 100644 --- a/p2p/simulations/adapters/exec.go +++ b/p2p/simulations/adapters/exec.go @@ -17,7 +17,7 @@ package adapters import ( - "bufio" + "bytes" "context" "crypto/ecdsa" "encoding/json" @@ -25,11 +25,11 @@ import ( "fmt" "io" "net" + "net/http" "os" "os/exec" "os/signal" "path/filepath" - "regexp" "strings" "sync" "syscall" @@ -39,23 +39,25 @@ 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/discover" + "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/rpc" "golang.org/x/net/websocket" ) -// ExecAdapter is a NodeAdapter which runs simulation nodes by executing the -// current binary as a child process. -// -// An init hook is used so that the child process executes the node services -// (rather than whataver the main() function would normally do), see the -// execP2PNode function for more information. +func init() { + // Register a reexec function to start a simulation node when the current binary is + // executed as "p2p-node" (rather than whatever the main() function would normally do). + reexec.Register("p2p-node", execP2PNode) +} + +// ExecAdapter is a NodeAdapter which runs simulation nodes by executing the current binary +// as a child process. type ExecAdapter struct { // BaseDir is the directory under which the data directories for each // simulation node are created. BaseDir string - nodes map[discover.NodeID]*ExecNode + nodes map[enode.ID]*ExecNode } // NewExecAdapter returns an ExecAdapter which stores node data in @@ -63,7 +65,7 @@ type ExecAdapter struct { func NewExecAdapter(baseDir string) *ExecAdapter { return &ExecAdapter{ BaseDir: baseDir, - nodes: make(map[discover.NodeID]*ExecNode), + nodes: make(map[enode.ID]*ExecNode), } } @@ -95,7 +97,11 @@ func (e *ExecAdapter) NewNode(config *NodeConfig) (Node, error) { 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{"*"} @@ -105,9 +111,9 @@ func (e *ExecAdapter) NewNode(config *NodeConfig) (Node, error) { conf.Stack.P2P.NAT = nil conf.Stack.NoUSB = true - // listen on a random localhost port (we'll get the actual port after - // starting the node through the RPC admin.nodeInfo method) - conf.Stack.P2P.ListenAddr = "127.0.0.1:0" + // listen on a localhost port, which we set when we + // initialise NodeConfig (usually a random port) + conf.Stack.P2P.ListenAddr = fmt.Sprintf(":%d", config.Port) node := &ExecNode{ ID: config.ID, @@ -123,7 +129,7 @@ func (e *ExecAdapter) NewNode(config *NodeConfig) (Node, error) { // ExecNode starts a simulation node by exec'ing the current binary and // running the configured services type ExecNode struct { - ID discover.NodeID + ID enode.ID Dir string Config *execNodeConfig Cmd *exec.Cmd @@ -150,20 +156,14 @@ func (n *ExecNode) Client() (*rpc.Client, error) { return n.client, nil } -// wsAddrPattern is a regex used to read the WebSocket address from the node's -// log -var wsAddrPattern = regexp.MustCompile(`ws://[\d.:]+`) - // Start exec's the node passing the ID and service as command line arguments -// and the node config encoded as JSON in the _P2P_NODE_CONFIG environment -// variable +// and the node config encoded as JSON in an environment variable. func (n *ExecNode) Start(snapshots map[string][]byte) (err error) { if n.Cmd != nil { return errors.New("already started") } defer func() { if err != nil { - log.Error("node failed to start", "err", err) n.Stop() } }() @@ -180,59 +180,78 @@ func (n *ExecNode) Start(snapshots map[string][]byte) (err error) { return fmt.Errorf("error generating node config: %s", err) } - // use a pipe for stderr so we can both copy the node's stderr to - // os.Stderr and read the WebSocket address from the logs - stderrR, stderrW := io.Pipe() - stderr := io.MultiWriter(os.Stderr, stderrW) + // start the one-shot server that waits for startup information + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + statusURL, statusC := n.waitForStartupJSON(ctx) // start the node cmd := n.newCmd() cmd.Stdout = os.Stdout - cmd.Stderr = stderr - cmd.Env = append(os.Environ(), fmt.Sprintf("_P2P_NODE_CONFIG=%s", confData)) + cmd.Stderr = os.Stderr + cmd.Env = append(os.Environ(), + envStatusURL+"="+statusURL, + envNodeConfig+"="+string(confData), + ) if err := cmd.Start(); err != nil { return fmt.Errorf("error starting node: %s", err) } n.Cmd = cmd // read the WebSocket address from the stderr logs - var wsAddr string - wsAddrC := make(chan string) - go func() { - s := bufio.NewScanner(stderrR) - for s.Scan() { - if strings.Contains(s.Text(), "WebSocket endpoint opened:") { - wsAddrC <- wsAddrPattern.FindString(s.Text()) - } - } - }() - select { - case wsAddr = <-wsAddrC: - if wsAddr == "" { - return errors.New("failed to read WebSocket address from stderr") - } - case <-time.After(10 * time.Second): - return errors.New("timed out waiting for WebSocket address on stderr") + status := <-statusC + if status.Err != "" { + return errors.New(status.Err) } - - // create the RPC client and load the node info - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - client, err := rpc.DialWebsocket(ctx, wsAddr, "") + client, err := rpc.DialWebsocket(ctx, status.WSEndpoint, "http://localhost") if err != nil { - return fmt.Errorf("error dialing rpc websocket: %s", err) + return fmt.Errorf("can't connect to RPC server: %v", err) } - var info p2p.NodeInfo - if err := client.CallContext(ctx, &info, "admin_nodeInfo"); err != nil { - return fmt.Errorf("error getting node info: %s", err) - } - n.client = client - n.wsAddr = wsAddr - n.Info = &info + // node ready :) + n.client = client + n.wsAddr = status.WSEndpoint + n.Info = status.NodeInfo return nil } +// waitForStartupJSON runs a one-shot HTTP server to receive a startup report. +func (n *ExecNode) waitForStartupJSON(ctx context.Context) (string, chan nodeStartupJSON) { + var ( + ch = make(chan nodeStartupJSON, 1) + quitOnce sync.Once + srv http.Server + ) + l, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + ch <- nodeStartupJSON{Err: err.Error()} + return "", ch + } + quit := func(status nodeStartupJSON) { + quitOnce.Do(func() { + l.Close() + ch <- status + }) + } + srv.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var status nodeStartupJSON + if err := json.NewDecoder(r.Body).Decode(&status); err != nil { + status.Err = fmt.Sprintf("can't decode startup report: %v", err) + } + quit(status) + }) + // Run the HTTP server, but don't wait forever and shut it down + // if the context is canceled. + go srv.Serve(l) + go func() { + <-ctx.Done() + quit(nodeStartupJSON{Err: "didn't get startup report"}) + }() + + url := "http://" + l.Addr().String() + return url, ch +} + // execCommand returns a command which runs the node locally by exec'ing // the current binary but setting argv[0] to "p2p-node" so that the child // runs execP2PNode @@ -323,12 +342,6 @@ func (n *ExecNode) Snapshots() (map[string][]byte, error) { return snapshots, n.client.Call(&snapshots, "simulation_snapshot") } -func init() { - // register a reexec function to start a devp2p node when the current - // binary is executed as "p2p-node" - reexec.Register("p2p-node", execP2PNode) -} - // execNodeConfig is used to serialize the node configuration so it can be // passed to the child process as a JSON encoded environment variable type execNodeConfig struct { @@ -338,54 +351,69 @@ type execNodeConfig struct { PeerAddrs map[string]string `json:"peer_addrs,omitempty"` } -// execP2PNode starts a devp2p node when the current binary is executed with +// execP2PNode starts a simulation node when the current binary is executed with // argv[0] being "p2p-node", reading the service / ID from argv[1] / argv[2] -// and the node config from the _P2P_NODE_CONFIG environment variable +// and the node config from an environment variable. func execP2PNode() { glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.LogfmtFormat())) glogger.Verbosity(log.LvlInfo) log.Root().SetHandler(glogger) + statusURL := os.Getenv(envStatusURL) + if statusURL == "" { + log.Crit("missing " + envStatusURL) + } + // Start the node and gather startup report. + var status nodeStartupJSON + stack, stackErr := startExecNodeStack() + if stackErr != nil { + status.Err = stackErr.Error() + } else { + status.WSEndpoint = "ws://" + stack.WSEndpoint() + status.NodeInfo = stack.Server().NodeInfo() + } + + // Send status to the host. + statusJSON, _ := json.Marshal(status) + if _, err := http.Post(statusURL, "application/json", bytes.NewReader(statusJSON)); err != nil { + log.Crit("Can't post startup info", "url", statusURL, "err", err) + } + if stackErr != nil { + os.Exit(1) + } + + // Stop the stack if we get a SIGTERM signal. + go func() { + sigc := make(chan os.Signal, 1) + signal.Notify(sigc, syscall.SIGTERM) + defer signal.Stop(sigc) + <-sigc + log.Info("Received SIGTERM, shutting down...") + stack.Stop() + }() + stack.Wait() // Wait for the stack to exit. +} + +func startExecNodeStack() (*node.Node, error) { // read the services from argv serviceNames := strings.Split(os.Args[1], ",") // decode the config - confEnv := os.Getenv("_P2P_NODE_CONFIG") + confEnv := os.Getenv(envNodeConfig) if confEnv == "" { - log.Crit("missing _P2P_NODE_CONFIG") + return nil, fmt.Errorf("missing " + envNodeConfig) } var conf execNodeConfig if err := json.Unmarshal([]byte(confEnv), &conf); err != nil { - log.Crit("error decoding _P2P_NODE_CONFIG", "err", err) + return nil, fmt.Errorf("error decoding %s: %v", envNodeConfig, err) } conf.Stack.P2P.PrivateKey = conf.Node.PrivateKey conf.Stack.Logger = log.New("node.id", conf.Node.ID.String()) - // use explicit IP address in ListenAddr so that Enode URL is usable - externalIP := func() string { - addrs, err := net.InterfaceAddrs() - if err != nil { - log.Crit("error getting IP address", "err", err) - } - for _, addr := range addrs { - if ip, ok := addr.(*net.IPNet); ok && !ip.IP.IsLoopback() { - return ip.IP.String() - } - } - log.Crit("unable to determine explicit IP address") - return "" - } - if strings.HasPrefix(conf.Stack.P2P.ListenAddr, ":") { - conf.Stack.P2P.ListenAddr = externalIP() + conf.Stack.P2P.ListenAddr - } - if conf.Stack.WSHost == "0.0.0.0" { - conf.Stack.WSHost = externalIP() - } - // initialize the devp2p stack stack, err := node.New(&conf.Stack) if err != nil { - log.Crit("error creating node stack", "err", err) + return nil, fmt.Errorf("error creating node stack: %v", err) } // register the services, collecting them into a map so we can wrap @@ -394,7 +422,7 @@ func execP2PNode() { for _, name := range serviceNames { serviceFunc, exists := serviceFuncs[name] if !exists { - log.Crit("unknown node service", "name", name) + return nil, fmt.Errorf("unknown node service %q", err) } constructor := func(nodeCtx *node.ServiceContext) (node.Service, error) { ctx := &ServiceContext{ @@ -413,34 +441,35 @@ func execP2PNode() { return service, nil } if err := stack.Register(constructor); err != nil { - log.Crit("error starting service", "name", name, "err", err) + return stack, fmt.Errorf("error registering service %q: %v", name, err) } } // register the snapshot service - if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { + err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { return &snapshotService{services}, nil - }); err != nil { - log.Crit("error starting snapshot service", "err", err) + }) + if err != nil { + return stack, fmt.Errorf("error starting snapshot service: %v", err) } // start the stack - if err := stack.Start(); err != nil { - log.Crit("error stating node stack", "err", err) + if err = stack.Start(); err != nil { + err = fmt.Errorf("error starting stack: %v", err) } + return stack, err +} - // stop the stack if we get a SIGTERM signal - go func() { - sigc := make(chan os.Signal, 1) - signal.Notify(sigc, syscall.SIGTERM) - defer signal.Stop(sigc) - <-sigc - log.Info("Received SIGTERM, shutting down...") - stack.Stop() - }() +const ( + envStatusURL = "_P2P_STATUS_URL" + envNodeConfig = "_P2P_NODE_CONFIG" +) - // wait for the stack to exit - stack.Wait() +// nodeStartupJSON is sent to the simulation host after startup. +type nodeStartupJSON struct { + Err string + WSEndpoint string + NodeInfo *p2p.NodeInfo } // snapshotService is a node.Service which wraps a list of services and @@ -496,7 +525,7 @@ type wsRPCDialer struct { // DialRPC implements the RPCDialer interface by creating a WebSocket RPC // client of the given node -func (w *wsRPCDialer) DialRPC(id discover.NodeID) (*rpc.Client, error) { +func (w *wsRPCDialer) DialRPC(id enode.ID) (*rpc.Client, error) { addr, ok := w.addrs[id.String()] if !ok { return nil, fmt.Errorf("unknown node: %s", id) diff --git a/p2p/simulations/adapters/inproc.go b/p2p/simulations/adapters/inproc.go index 48d7c17301..bdfbf1c732 100644 --- a/p2p/simulations/adapters/inproc.go +++ b/p2p/simulations/adapters/inproc.go @@ -27,24 +27,36 @@ 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/discover" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/simulations/pipes" "github.com/ethereum/go-ethereum/rpc" ) // SimAdapter is a NodeAdapter which creates in-memory simulation nodes and -// connects them using in-memory net.Pipe connections +// connects them using net.Pipe type SimAdapter struct { + pipe func() (net.Conn, net.Conn, error) mtx sync.RWMutex - nodes map[discover.NodeID]*SimNode + nodes map[enode.ID]*SimNode services map[string]ServiceFunc } // NewSimAdapter creates a SimAdapter which is capable of running in-memory // simulation nodes running any of the given services (the services to run on a // particular node are passed to the NewNode function in the NodeConfig) +// the adapter uses a net.Pipe for in-memory simulated network connections func NewSimAdapter(services map[string]ServiceFunc) *SimAdapter { return &SimAdapter{ - nodes: make(map[discover.NodeID]*SimNode), + pipe: pipes.NetPipe, + nodes: make(map[enode.ID]*SimNode), + services: services, + } +} + +func NewTCPAdapter(services map[string]ServiceFunc) *SimAdapter { + return &SimAdapter{ + pipe: pipes.TCPPipe, + nodes: make(map[enode.ID]*SimNode), services: services, } } @@ -81,7 +93,7 @@ func (s *SimAdapter) NewNode(config *NodeConfig) (Node, error) { MaxPeers: math.MaxInt32, NoDiscovery: true, Dialer: s, - EnableMsgEvents: true, + EnableMsgEvents: config.EnableMsgEvents, }, NoUSB: true, Logger: log.New("node.id", id.String()), @@ -102,24 +114,31 @@ func (s *SimAdapter) NewNode(config *NodeConfig) (Node, error) { } // Dial implements the p2p.NodeDialer interface by connecting to the node using -// an in-memory net.Pipe connection -func (s *SimAdapter) Dial(dest *discover.Node) (conn net.Conn, err error) { - node, ok := s.GetNode(dest.ID) +// an in-memory net.Pipe +func (s *SimAdapter) Dial(dest *enode.Node) (conn net.Conn, err error) { + node, ok := s.GetNode(dest.ID()) if !ok { - return nil, fmt.Errorf("unknown node: %s", dest.ID) + return nil, fmt.Errorf("unknown node: %s", dest.ID()) } srv := node.Server() if srv == nil { - return nil, fmt.Errorf("node not running: %s", dest.ID) + return nil, fmt.Errorf("node not running: %s", dest.ID()) } - pipe1, pipe2 := net.Pipe() + // SimAdapter.pipe is net.Pipe (NewSimAdapter) + pipe1, pipe2, err := s.pipe() + if err != nil { + return nil, err + } + // this is simulated 'listening' + // 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 } // DialRPC implements the RPCDialer interface by creating an in-memory RPC // client of the given node -func (s *SimAdapter) DialRPC(id discover.NodeID) (*rpc.Client, error) { +func (s *SimAdapter) DialRPC(id enode.ID) (*rpc.Client, error) { node, ok := s.GetNode(id) if !ok { return nil, fmt.Errorf("unknown node: %s", id) @@ -132,7 +151,7 @@ func (s *SimAdapter) DialRPC(id discover.NodeID) (*rpc.Client, error) { } // GetNode returns the node with the given ID if it exists -func (s *SimAdapter) GetNode(id discover.NodeID) (*SimNode, bool) { +func (s *SimAdapter) GetNode(id enode.ID) (*SimNode, bool) { s.mtx.RLock() defer s.mtx.RUnlock() node, ok := s.nodes[id] @@ -140,11 +159,11 @@ func (s *SimAdapter) GetNode(id discover.NodeID) (*SimNode, bool) { } // SimNode is an in-memory simulation node which connects to other nodes using -// an in-memory net.Pipe connection (see SimAdapter.Dial), running devp2p -// protocols directly over that pipe +// net.Pipe (see SimAdapter.Dial), running devp2p protocols directly over that +// pipe type SimNode struct { lock sync.RWMutex - ID discover.NodeID + ID enode.ID config *NodeConfig adapter *SimAdapter node *node.Node @@ -153,31 +172,37 @@ type SimNode struct { registerOnce sync.Once } -// Addr returns the node's discovery address -func (self *SimNode) Addr() []byte { - return []byte(self.Node().String()) +// Close closes the underlaying node.Node to release +// acquired resources. +func (sn *SimNode) Close() error { + return sn.node.Close() } -// Node returns a discover.Node representing the SimNode -func (self *SimNode) Node() *discover.Node { - return discover.NewNode(self.ID, net.IP{127, 0, 0, 1}, 30303, 30303) +// Addr returns the node's discovery address +func (sn *SimNode) Addr() []byte { + return []byte(sn.Node().String()) +} + +// Node returns a node descriptor representing the SimNode +func (sn *SimNode) Node() *enode.Node { + return sn.config.Node() } // Client returns an rpc.Client which can be used to communicate with the // underlying services (it is set once the node has started) -func (self *SimNode) Client() (*rpc.Client, error) { - self.lock.RLock() - defer self.lock.RUnlock() - if self.client == nil { +func (sn *SimNode) Client() (*rpc.Client, error) { + sn.lock.RLock() + defer sn.lock.RUnlock() + if sn.client == nil { return nil, errors.New("node not started") } - return self.client, nil + return sn.client, nil } // ServeRPC serves RPC requests over the given connection by creating an // in-memory client to the node's RPC server -func (self *SimNode) ServeRPC(conn net.Conn) error { - handler, err := self.node.RPCHandler() +func (sn *SimNode) ServeRPC(conn net.Conn) error { + handler, err := sn.node.RPCHandler() if err != nil { return err } @@ -187,13 +212,13 @@ func (self *SimNode) ServeRPC(conn net.Conn) error { // Snapshots creates snapshots of the services by calling the // simulation_snapshot RPC method -func (self *SimNode) Snapshots() (map[string][]byte, error) { - self.lock.RLock() - services := make(map[string]node.Service, len(self.running)) - for name, service := range self.running { +func (sn *SimNode) Snapshots() (map[string][]byte, error) { + sn.lock.RLock() + services := make(map[string]node.Service, len(sn.running)) + for name, service := range sn.running { services[name] = service } - self.lock.RUnlock() + sn.lock.RUnlock() if len(services) == 0 { return nil, errors.New("no running services") } @@ -213,23 +238,23 @@ func (self *SimNode) Snapshots() (map[string][]byte, error) { } // Start registers the services and starts the underlying devp2p node -func (self *SimNode) Start(snapshots map[string][]byte) error { +func (sn *SimNode) Start(snapshots map[string][]byte) error { newService := func(name string) func(ctx *node.ServiceContext) (node.Service, error) { return func(nodeCtx *node.ServiceContext) (node.Service, error) { ctx := &ServiceContext{ - RPCDialer: self.adapter, + RPCDialer: sn.adapter, NodeContext: nodeCtx, - Config: self.config, + Config: sn.config, } if snapshots != nil { ctx.Snapshot = snapshots[name] } - serviceFunc := self.adapter.services[name] + serviceFunc := sn.adapter.services[name] service, err := serviceFunc(ctx) if err != nil { return nil, err } - self.running[name] = service + sn.running[name] = service return service, nil } } @@ -237,11 +262,11 @@ func (self *SimNode) Start(snapshots map[string][]byte) error { // ensure we only register the services once in the case of the node // being stopped and then started again var regErr error - self.registerOnce.Do(func() { - for _, name := range self.config.Services { - if err := self.node.Register(newService(name)); err != nil { + sn.registerOnce.Do(func() { + for _, name := range sn.config.Services { + if err := sn.node.Register(newService(name)); err != nil { regErr = err - return + break } } }) @@ -249,54 +274,72 @@ func (self *SimNode) Start(snapshots map[string][]byte) error { return regErr } - if err := self.node.Start(); err != nil { + if err := sn.node.Start(); err != nil { return err } // create an in-process RPC client - handler, err := self.node.RPCHandler() + handler, err := sn.node.RPCHandler() if err != nil { return err } - self.lock.Lock() - self.client = rpc.DialInProc(handler) - self.lock.Unlock() + sn.lock.Lock() + sn.client = rpc.DialInProc(handler) + sn.lock.Unlock() return nil } // Stop closes the RPC client and stops the underlying devp2p node -func (self *SimNode) Stop() error { - self.lock.Lock() - if self.client != nil { - self.client.Close() - self.client = nil +func (sn *SimNode) Stop() error { + sn.lock.Lock() + if sn.client != nil { + sn.client.Close() + sn.client = nil } - self.lock.Unlock() - return self.node.Stop() + sn.lock.Unlock() + return sn.node.Stop() +} + +// Service returns a running service by name +func (sn *SimNode) Service(name string) node.Service { + sn.lock.RLock() + defer sn.lock.RUnlock() + return sn.running[name] } // Services returns a copy of the underlying services -func (self *SimNode) Services() []node.Service { - self.lock.RLock() - defer self.lock.RUnlock() - services := make([]node.Service, 0, len(self.running)) - for _, service := range self.running { +func (sn *SimNode) Services() []node.Service { + sn.lock.RLock() + defer sn.lock.RUnlock() + services := make([]node.Service, 0, len(sn.running)) + for _, service := range sn.running { services = append(services, service) } return services } +// ServiceMap returns a map by names of the underlying services +func (sn *SimNode) ServiceMap() map[string]node.Service { + sn.lock.RLock() + defer sn.lock.RUnlock() + services := make(map[string]node.Service, len(sn.running)) + for name, service := range sn.running { + services[name] = service + } + return services +} + // Server returns the underlying p2p.Server -func (self *SimNode) Server() *p2p.Server { - return self.node.Server() +func (sn *SimNode) Server() *p2p.Server { + return sn.node.Server() } // SubscribeEvents subscribes the given channel to peer events from the // underlying p2p.Server -func (self *SimNode) SubscribeEvents(ch chan *p2p.PeerEvent) event.Subscription { - srv := self.Server() +func (sn *SimNode) SubscribeEvents(ch chan *p2p.PeerEvent) event.Subscription { + srv := sn.Server() if srv == nil { panic("node not running") } @@ -304,12 +347,12 @@ func (self *SimNode) SubscribeEvents(ch chan *p2p.PeerEvent) event.Subscription } // NodeInfo returns information about the node -func (self *SimNode) NodeInfo() *p2p.NodeInfo { - server := self.Server() +func (sn *SimNode) NodeInfo() *p2p.NodeInfo { + server := sn.Server() if server == nil { return &p2p.NodeInfo{ - ID: self.ID.String(), - Enode: self.Node().String(), + ID: sn.ID.String(), + Enode: sn.Node().String(), } } return server.NodeInfo() diff --git a/p2p/simulations/adapters/inproc_test.go b/p2p/simulations/adapters/inproc_test.go new file mode 100644 index 0000000000..e1e092f6e1 --- /dev/null +++ b/p2p/simulations/adapters/inproc_test.go @@ -0,0 +1,259 @@ +// Copyright 2017 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 adapters + +import ( + "bytes" + "encoding/binary" + "fmt" + "testing" + "time" + + "github.com/ethereum/go-ethereum/p2p/simulations/pipes" +) + +func TestTCPPipe(t *testing.T) { + c1, c2, err := pipes.TCPPipe() + if err != nil { + t.Fatal(err) + } + + done := make(chan struct{}) + + go func() { + msgs := 50 + size := 1024 + for i := 0; i < msgs; i++ { + msg := make([]byte, size) + _ = binary.PutUvarint(msg, uint64(i)) + + _, err := c1.Write(msg) + if err != nil { + t.Fatal(err) + } + } + + for i := 0; i < msgs; i++ { + msg := make([]byte, size) + _ = binary.PutUvarint(msg, uint64(i)) + + out := make([]byte, size) + _, err := c2.Read(out) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(msg, out) { + t.Fatalf("expected %#v, got %#v", msg, out) + } + } + done <- struct{}{} + }() + + select { + case <-done: + case <-time.After(5 * time.Second): + t.Fatal("test timeout") + } +} + +func TestTCPPipeBidirections(t *testing.T) { + c1, c2, err := pipes.TCPPipe() + if err != nil { + t.Fatal(err) + } + + done := make(chan struct{}) + + go func() { + msgs := 50 + size := 7 + for i := 0; i < msgs; i++ { + msg := []byte(fmt.Sprintf("ping %02d", i)) + + _, err := c1.Write(msg) + if err != nil { + t.Fatal(err) + } + } + + for i := 0; i < msgs; i++ { + expected := []byte(fmt.Sprintf("ping %02d", i)) + + out := make([]byte, size) + _, err := c2.Read(out) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(expected, out) { + t.Fatalf("expected %#v, got %#v", out, expected) + } else { + msg := []byte(fmt.Sprintf("pong %02d", i)) + _, err := c2.Write(msg) + if err != nil { + t.Fatal(err) + } + } + } + + for i := 0; i < msgs; i++ { + expected := []byte(fmt.Sprintf("pong %02d", i)) + + out := make([]byte, size) + _, err := c1.Read(out) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(expected, out) { + t.Fatalf("expected %#v, got %#v", out, expected) + } + } + done <- struct{}{} + }() + + select { + case <-done: + case <-time.After(5 * time.Second): + t.Fatal("test timeout") + } +} + +func TestNetPipe(t *testing.T) { + c1, c2, err := pipes.NetPipe() + if err != nil { + t.Fatal(err) + } + + done := make(chan struct{}) + + go func() { + msgs := 50 + size := 1024 + // netPipe is blocking, so writes are emitted asynchronously + go func() { + for i := 0; i < msgs; i++ { + msg := make([]byte, size) + _ = binary.PutUvarint(msg, uint64(i)) + + _, err := c1.Write(msg) + if err != nil { + t.Fatal(err) + } + } + }() + + for i := 0; i < msgs; i++ { + msg := make([]byte, size) + _ = binary.PutUvarint(msg, uint64(i)) + + out := make([]byte, size) + _, err := c2.Read(out) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(msg, out) { + t.Fatalf("expected %#v, got %#v", msg, out) + } + } + + done <- struct{}{} + }() + + select { + case <-done: + case <-time.After(5 * time.Second): + t.Fatal("test timeout") + } +} + +func TestNetPipeBidirections(t *testing.T) { + c1, c2, err := pipes.NetPipe() + if err != nil { + t.Fatal(err) + } + + done := make(chan struct{}) + + go func() { + msgs := 1000 + size := 8 + pingTemplate := "ping %03d" + pongTemplate := "pong %03d" + + // netPipe is blocking, so writes are emitted asynchronously + go func() { + for i := 0; i < msgs; i++ { + msg := []byte(fmt.Sprintf(pingTemplate, i)) + + _, err := c1.Write(msg) + if err != nil { + t.Fatal(err) + } + } + }() + + // netPipe is blocking, so reads for pong are emitted asynchronously + go func() { + for i := 0; i < msgs; i++ { + expected := []byte(fmt.Sprintf(pongTemplate, i)) + + out := make([]byte, size) + _, err := c1.Read(out) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(expected, out) { + t.Fatalf("expected %#v, got %#v", expected, out) + } + } + + done <- struct{}{} + }() + + // expect to read pings, and respond with pongs to the alternate connection + for i := 0; i < msgs; i++ { + expected := []byte(fmt.Sprintf(pingTemplate, i)) + + out := make([]byte, size) + _, err := c2.Read(out) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(expected, out) { + t.Fatalf("expected %#v, got %#v", expected, out) + } else { + msg := []byte(fmt.Sprintf(pongTemplate, i)) + + _, err := c2.Write(msg) + if err != nil { + t.Fatal(err) + } + } + } + }() + + select { + case <-done: + case <-time.After(5 * time.Second): + t.Fatal("test timeout") + } +} diff --git a/p2p/simulations/adapters/types.go b/p2p/simulations/adapters/types.go index 5b4b47fe2f..31856b76dd 100644 --- a/p2p/simulations/adapters/types.go +++ b/p2p/simulations/adapters/types.go @@ -23,12 +23,13 @@ import ( "fmt" "net" "os" + "strconv" "github.com/docker/docker/pkg/reexec" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/discover" + "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/rpc" ) @@ -77,7 +78,7 @@ type NodeAdapter interface { type NodeConfig struct { // ID is the node's ID which is used to identify the node in the // simulation network - ID discover.NodeID + ID enode.ID // PrivateKey is the node's private key which is used by the devp2p // stack to encrypt communications @@ -89,6 +90,9 @@ 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 @@ -96,25 +100,31 @@ type NodeConfig struct { Services []string // function to sanction or prevent suggesting a peer - Reachable func(id discover.NodeID) bool + Reachable func(id enode.ID) bool + + Port uint16 } // nodeConfigJSON is used to encode and decode NodeConfig as JSON by encoding // all fields as strings type nodeConfigJSON struct { - ID string `json:"id"` - PrivateKey string `json:"private_key"` - Name string `json:"name"` - Services []string `json:"services"` + ID string `json:"id"` + PrivateKey string `json:"private_key"` + Name string `json:"name"` + Services []string `json:"services"` + EnableMsgEvents bool `json:"enable_msg_events"` + Port uint16 `json:"port"` } // MarshalJSON implements the json.Marshaler interface by encoding the config // fields as strings func (n *NodeConfig) MarshalJSON() ([]byte, error) { confJSON := nodeConfigJSON{ - ID: n.ID.String(), - Name: n.Name, - Services: n.Services, + ID: n.ID.String(), + Name: n.Name, + Services: n.Services, + Port: n.Port, + EnableMsgEvents: n.EnableMsgEvents, } if n.PrivateKey != nil { confJSON.PrivateKey = hex.EncodeToString(crypto.FromECDSA(n.PrivateKey)) @@ -131,11 +141,9 @@ func (n *NodeConfig) UnmarshalJSON(data []byte) error { } if confJSON.ID != "" { - nodeID, err := discover.HexID(confJSON.ID) - if err != nil { + if err := n.ID.UnmarshalText([]byte(confJSON.ID)); err != nil { return err } - n.ID = nodeID } if confJSON.PrivateKey != "" { @@ -152,10 +160,17 @@ func (n *NodeConfig) UnmarshalJSON(data []byte) error { n.Name = confJSON.Name n.Services = confJSON.Services + n.Port = confJSON.Port + n.EnableMsgEvents = confJSON.EnableMsgEvents return nil } +// 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)) +} + // RandomNodeConfig returns node configuration with a randomly generated ID and // PrivateKey func RandomNodeConfig() *NodeConfig { @@ -163,13 +178,36 @@ func RandomNodeConfig() *NodeConfig { if err != nil { panic("unable to generate key") } - var id discover.NodeID - pubkey := crypto.FromECDSAPub(&key.PublicKey) - copy(id[:], pubkey[1:]) - return &NodeConfig{ - ID: id, - PrivateKey: key, + + id := enode.PubkeyToIDV4(&key.PublicKey) + port, err := assignTCPPort() + if err != nil { + panic("unable to assign tcp port") } + return &NodeConfig{ + ID: id, + Name: fmt.Sprintf("node_%s", id.String()), + PrivateKey: key, + Port: port, + EnableMsgEvents: true, + } +} + +func assignTCPPort() (uint16, error) { + l, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + return 0, err + } + l.Close() + _, port, err := net.SplitHostPort(l.Addr().String()) + if err != nil { + return 0, err + } + p, err := strconv.ParseInt(port, 10, 32) + if err != nil { + return 0, err + } + return uint16(p), nil } // ServiceContext is a collection of options and methods which can be utilised @@ -186,7 +224,7 @@ type ServiceContext struct { // other nodes in the network (for example a simulated Swarm node which needs // to connect to a Geth node to resolve ENS names) type RPCDialer interface { - DialRPC(id discover.NodeID) (*rpc.Client, error) + DialRPC(id enode.ID) (*rpc.Client, error) } // Services is a collection of services which can be run in a simulation diff --git a/p2p/simulations/connect.go b/p2p/simulations/connect.go new file mode 100644 index 0000000000..ede96b34c1 --- /dev/null +++ b/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/p2p/simulations/connect_test.go b/p2p/simulations/connect_test.go new file mode 100644 index 0000000000..32d18347d8 --- /dev/null +++ b/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/p2p/simulations/events.go b/p2p/simulations/events.go index f17958c689..984c2e088f 100644 --- a/p2p/simulations/events.go +++ b/p2p/simulations/events.go @@ -58,6 +58,9 @@ type Event struct { // Msg is set if the type is EventTypeMsg Msg *Msg `json:"msg,omitempty"` + + //Optionally provide data (currently for simulation frontends only) + Data interface{} `json:"data"` } // NewEvent creates a new event for the given object which should be either a @@ -97,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/p2p/simulations/examples/ping-pong.go b/p2p/simulations/examples/ping-pong.go index 6a0ead53a5..cde2f3a677 100644 --- a/p2p/simulations/examples/ping-pong.go +++ b/p2p/simulations/examples/ping-pong.go @@ -28,7 +28,7 @@ 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/discover" + "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" @@ -70,14 +70,6 @@ func main() { log.Info("using exec adapter", "tmpdir", tmpdir) adapter = adapters.NewExecAdapter(tmpdir) - case "docker": - log.Info("using docker adapter") - var err error - adapter, err = adapters.NewDockerAdapter() - if err != nil { - log.Crit("error creating docker adapter", "err", err) - } - default: log.Crit(fmt.Sprintf("unknown node adapter %q", *adapterType)) } @@ -96,12 +88,12 @@ func main() { // sends a ping to all its connected peers every 10s and receives a pong in // return type pingPongService struct { - id discover.NodeID + id enode.ID log log.Logger received int64 } -func newPingPongService(id discover.NodeID) *pingPongService { +func newPingPongService(id enode.ID) *pingPongService { return &pingPongService{ id: id, log: log.New("node.id", id), diff --git a/p2p/simulations/http.go b/p2p/simulations/http.go index 97dd742e88..1f44cc6675 100644 --- a/p2p/simulations/http.go +++ b/p2p/simulations/http.go @@ -31,7 +31,7 @@ import ( "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/discover" + "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/simulations/adapters" "github.com/ethereum/go-ethereum/rpc" "github.com/julienschmidt/httprouter" @@ -561,7 +561,8 @@ func (s *Server) LoadSnapshot(w http.ResponseWriter, req *http.Request) { // CreateNode creates a node in the network using the given configuration func (s *Server) CreateNode(w http.ResponseWriter, req *http.Request) { - config := adapters.RandomNodeConfig() + config := &adapters.NodeConfig{} + err := json.NewDecoder(req.Body).Decode(config) if err != nil && err != io.EOF { http.Error(w, err.Error(), http.StatusBadRequest) @@ -708,8 +709,9 @@ func (s *Server) wrapHandler(handler http.HandlerFunc) httprouter.Handle { ctx := context.Background() if id := params.ByName("nodeid"); id != "" { + var nodeID enode.ID var node *Node - if nodeID, err := discover.HexID(id); err == nil { + if nodeID.UnmarshalText([]byte(id)) == nil { node = s.network.GetNode(nodeID) } else { node = s.network.GetNodeByName(id) @@ -722,8 +724,9 @@ func (s *Server) wrapHandler(handler http.HandlerFunc) httprouter.Handle { } if id := params.ByName("peerid"); id != "" { + var peerID enode.ID var peer *Node - if peerID, err := discover.HexID(id); err == nil { + if peerID.UnmarshalText([]byte(id)) == nil { peer = s.network.GetNode(peerID) } else { peer = s.network.GetNodeByName(id) diff --git a/p2p/simulations/http_test.go b/p2p/simulations/http_test.go index 677a8fb147..ed43c0ed76 100644 --- a/p2p/simulations/http_test.go +++ b/p2p/simulations/http_test.go @@ -18,6 +18,7 @@ package simulations import ( "context" + "flag" "fmt" "math/rand" "net/http/httptest" @@ -28,22 +29,35 @@ import ( "time" "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/discover" + "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/simulations/adapters" "github.com/ethereum/go-ethereum/rpc" + "github.com/mattn/go-colorable" ) +var ( + loglevel = flag.Int("loglevel", 2, "verbosity of logs") +) + +func init() { + flag.Parse() + + log.PrintOrigins(true) + log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true)))) +} + // testService implements the node.Service interface and provides protocols // and APIs which are useful for testing nodes in a simulation network type testService struct { - id discover.NodeID + id enode.ID // peerCount is incremented once a peer handshake has been performed peerCount int64 - peers map[discover.NodeID]*testPeer + peers map[enode.ID]*testPeer peersMtx sync.Mutex // state stores []byte which is used to test creating and loading @@ -54,7 +68,7 @@ type testService struct { func newTestService(ctx *adapters.ServiceContext) (node.Service, error) { svc := &testService{ id: ctx.Config.ID, - peers: make(map[discover.NodeID]*testPeer), + peers: make(map[enode.ID]*testPeer), } svc.state.Store(ctx.Snapshot) return svc, nil @@ -65,7 +79,7 @@ type testPeer struct { dumReady chan struct{} } -func (t *testService) peer(id discover.NodeID) *testPeer { +func (t *testService) peer(id enode.ID) *testPeer { t.peersMtx.Lock() defer t.peersMtx.Unlock() if peer, ok := t.peers[id]; ok { @@ -280,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", @@ -348,7 +363,8 @@ func startTestNetwork(t *testing.T, client *Client) []string { nodeCount := 2 nodeIDs := make([]string, nodeCount) for i := 0; i < nodeCount; i++ { - node, err := client.CreateNode(nil) + config := adapters.RandomNodeConfig() + node, err := client.CreateNode(config) if err != nil { t.Fatalf("error creating node: %s", err) } @@ -405,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: discover.MustHexID(id), - }, - Up: up, - }, + Node: &node, } } @@ -420,8 +437,8 @@ func (t *expectEvents) connEvent(one, other string, up bool) *Event { return &Event{ Type: EventTypeConn, Conn: &Conn{ - One: discover.MustHexID(one), - Other: discover.MustHexID(other), + One: enode.HexID(one), + Other: enode.HexID(other), Up: up, }, } @@ -464,6 +481,7 @@ loop: } func (t *expectEvents) expect(events ...*Event) { + t.Helper() timeout := time.After(10 * time.Second) i := 0 for { @@ -485,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: @@ -527,7 +545,9 @@ func TestHTTPNodeRPC(t *testing.T) { // start a node in the network client := NewClient(s.URL) - node, err := client.CreateNode(nil) + + config := adapters.RandomNodeConfig() + node, err := client.CreateNode(config) if err != nil { t.Fatalf("error creating node: %s", err) } @@ -581,15 +601,33 @@ func TestHTTPNodeRPC(t *testing.T) { // TestHTTPSnapshot tests creating and loading network snapshots func TestHTTPSnapshot(t *testing.T) { // start the server - _, s := testHTTPServer(t) + network, s := testHTTPServer(t) defer s.Close() + var eventsDone = make(chan struct{}) + count := 1 + eventsDoneChan := make(chan *Event) + eventSub := network.Events().Subscribe(eventsDoneChan) + go func() { + defer eventSub.Unsubscribe() + for event := range eventsDoneChan { + if event.Type == EventTypeConn && !event.Control { + count-- + if count == 0 { + eventsDone <- struct{}{} + return + } + } + } + }() + // create a two-node network client := NewClient(s.URL) nodeCount := 2 nodes := make([]*p2p.NodeInfo, nodeCount) for i := 0; i < nodeCount; i++ { - node, err := client.CreateNode(nil) + config := adapters.RandomNodeConfig() + node, err := client.CreateNode(config) if err != nil { t.Fatalf("error creating node: %s", err) } @@ -616,7 +654,7 @@ func TestHTTPSnapshot(t *testing.T) { } states[i] = state } - + <-eventsDone // create a snapshot snap, err := client.CreateSnapshot() if err != nil { @@ -630,9 +668,23 @@ func TestHTTPSnapshot(t *testing.T) { } // create another network - _, s = testHTTPServer(t) + network2, s := testHTTPServer(t) defer s.Close() client = NewClient(s.URL) + count = 1 + eventSub = network2.Events().Subscribe(eventsDoneChan) + go func() { + defer eventSub.Unsubscribe() + for event := range eventsDoneChan { + if event.Type == EventTypeConn && !event.Control { + count-- + if count == 0 { + eventsDone <- struct{}{} + return + } + } + } + }() // subscribe to events so we can check them later events := make(chan *Event, 100) @@ -647,6 +699,7 @@ func TestHTTPSnapshot(t *testing.T) { if err := client.LoadSnapshot(snap); err != nil { t.Fatalf("error loading snapshot: %s", err) } + <-eventsDone // check the nodes and connection exists net, err := client.GetNetwork() @@ -672,6 +725,9 @@ func TestHTTPSnapshot(t *testing.T) { if conn.Other.String() != nodes[1].ID { t.Fatalf("expected connection to have other=%q, got other=%q", nodes[1].ID, conn.Other) } + if !conn.Up { + t.Fatal("should be up") + } // check the node states were restored for i, node := range nodes { diff --git a/p2p/simulations/mocker.go b/p2p/simulations/mocker.go index c38e288552..8ce777a010 100644 --- a/p2p/simulations/mocker.go +++ b/p2p/simulations/mocker.go @@ -25,7 +25,8 @@ import ( "time" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/p2p/discover" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/simulations/adapters" ) //a map of mocker names to its function @@ -102,7 +103,13 @@ func startStop(net *Network, quit chan struct{}, nodeCount int) { func probabilistic(net *Network, quit chan struct{}, nodeCount int) { nodes, err := connectNodesInRing(net, nodeCount) if err != nil { - panic("Could not startup node network for mocker") + select { + case <-quit: + //error may be due to abortion of mocking; so the quit channel is closed + return + default: + panic("Could not startup node network for mocker") + } } for { select { @@ -143,15 +150,15 @@ func probabilistic(net *Network, quit chan struct{}, nodeCount int) { log.Debug(fmt.Sprintf("node %v shutting down", nodes[i])) err := net.Stop(nodes[i]) if err != nil { - log.Error(fmt.Sprintf("Error stopping node %s", nodes[i])) + log.Error("Error stopping node", "node", nodes[i]) wg.Done() continue } - go func(id discover.NodeID) { + go func(id enode.ID) { time.Sleep(randWait) err := net.Start(id) if err != nil { - log.Error(fmt.Sprintf("Error starting node %s", id)) + log.Error("Error starting node", "node", id) } wg.Done() }(nodes[i]) @@ -162,12 +169,13 @@ func probabilistic(net *Network, quit chan struct{}, nodeCount int) { } //connect nodeCount number of nodes in a ring -func connectNodesInRing(net *Network, nodeCount int) ([]discover.NodeID, error) { - ids := make([]discover.NodeID, nodeCount) +func connectNodesInRing(net *Network, nodeCount int) ([]enode.ID, error) { + ids := make([]enode.ID, nodeCount) for i := 0; i < nodeCount; i++ { - node, err := net.NewNode() + conf := adapters.RandomNodeConfig() + node, err := net.NewNodeWithConfig(conf) if err != nil { - log.Error("Error creating a node! %s", err) + log.Error("Error creating a node!", "err", err) return nil, err } ids[i] = node.ID() @@ -175,7 +183,7 @@ func connectNodesInRing(net *Network, nodeCount int) ([]discover.NodeID, error) for _, id := range ids { if err := net.Start(id); err != nil { - log.Error("Error starting a node! %s", err) + log.Error("Error starting a node!", "err", err) return nil, err } log.Debug(fmt.Sprintf("node %v starting up", id)) @@ -183,7 +191,7 @@ func connectNodesInRing(net *Network, nodeCount int) ([]discover.NodeID, error) for i, id := range ids { peerID := ids[(i+1)%len(ids)] if err := net.Connect(id, peerID); err != nil { - log.Error("Error connecting a node to a peer! %s", err) + log.Error("Error connecting a node to a peer!", "err", err) return nil, err } } diff --git a/p2p/simulations/mocker_test.go b/p2p/simulations/mocker_test.go index de8ec0b337..069040257e 100644 --- a/p2p/simulations/mocker_test.go +++ b/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 ( @@ -27,7 +27,7 @@ import ( "testing" "time" - "github.com/ethereum/go-ethereum/p2p/discover" + "github.com/ethereum/go-ethereum/p2p/enode" ) func TestMocker(t *testing.T) { @@ -82,7 +82,7 @@ func TestMocker(t *testing.T) { defer sub.Unsubscribe() //wait until all nodes are started and connected //store every node up event in a map (value is irrelevant, mimic Set datatype) - nodemap := make(map[discover.NodeID]bool) + nodemap := make(map[enode.ID]bool) wg.Add(1) nodesComplete := false connCount := 0 @@ -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/p2p/simulations/network.go b/p2p/simulations/network.go index caf428ece1..f03c953e89 100644 --- a/p2p/simulations/network.go +++ b/p2p/simulations/network.go @@ -20,18 +20,21 @@ import ( "bytes" "context" "encoding/json" + "errors" "fmt" + "io" + "math/rand" "sync" "time" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/discover" + "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/simulations/adapters" ) -var dialBanTimeout = 200 * time.Millisecond +var DialBanTimeout = 200 * time.Millisecond // NetworkConfig defines configuration options for starting a Network type NetworkConfig struct { @@ -51,7 +54,7 @@ type Network struct { NetworkConfig Nodes []*Node `json:"nodes"` - nodeMap map[discover.NodeID]int + nodeMap map[enode.ID]int Conns []*Conn `json:"conns"` connMap map[string]int @@ -67,64 +70,48 @@ func NewNetwork(nodeAdapter adapters.NodeAdapter, conf *NetworkConfig) *Network return &Network{ NetworkConfig: *conf, nodeAdapter: nodeAdapter, - nodeMap: make(map[discover.NodeID]int), + nodeMap: make(map[enode.ID]int), connMap: make(map[string]int), quitc: make(chan struct{}), } } // Events returns the output event feed of the Network. -func (self *Network) Events() *event.Feed { - return &self.events -} - -// NewNode adds a new node to the network with a random ID -func (self *Network) NewNode() (*Node, error) { - conf := adapters.RandomNodeConfig() - conf.Services = []string{self.DefaultService} - return self.NewNodeWithConfig(conf) +func (net *Network) Events() *event.Feed { + return &net.events } // NewNodeWithConfig adds a new node to the network with the given config, // returning an error if a node with the same ID or name already exists -func (self *Network) NewNodeWithConfig(conf *adapters.NodeConfig) (*Node, error) { - self.lock.Lock() - defer self.lock.Unlock() +func (net *Network) NewNodeWithConfig(conf *adapters.NodeConfig) (*Node, error) { + net.lock.Lock() + defer net.lock.Unlock() - // create a random ID and PrivateKey if not set - if conf.ID == (discover.NodeID{}) { - c := adapters.RandomNodeConfig() - conf.ID = c.ID - conf.PrivateKey = c.PrivateKey - } - id := conf.ID if conf.Reachable == nil { - conf.Reachable = func(otherID discover.NodeID) bool { - _, err := self.InitConn(conf.ID, otherID) - return err == nil + conf.Reachable = func(otherID enode.ID) bool { + _, err := net.InitConn(conf.ID, otherID) + if err != nil && bytes.Compare(conf.ID.Bytes(), otherID.Bytes()) < 0 { + return false + } + return true } } - // assign a name to the node if not set - if conf.Name == "" { - conf.Name = fmt.Sprintf("node%02d", len(self.Nodes)+1) - } - // check the node doesn't already exist - if node := self.getNode(id); node != nil { - return nil, fmt.Errorf("node with ID %q already exists", id) + if node := net.getNode(conf.ID); node != nil { + return nil, fmt.Errorf("node with ID %q already exists", conf.ID) } - if node := self.getNodeByName(conf.Name); node != nil { + if node := net.getNodeByName(conf.Name); node != nil { return nil, fmt.Errorf("node with name %q already exists", conf.Name) } // if no services are configured, use the default service if len(conf.Services) == 0 { - conf.Services = []string{self.DefaultService} + conf.Services = []string{net.DefaultService} } // use the NodeAdapter to create the node - adapterNode, err := self.nodeAdapter.NewNode(conf) + adapterNode, err := net.nodeAdapter.NewNode(conf) if err != nil { return nil, err } @@ -132,28 +119,28 @@ func (self *Network) NewNodeWithConfig(conf *adapters.NodeConfig) (*Node, error) Node: adapterNode, Config: conf, } - log.Trace(fmt.Sprintf("node %v created", id)) - self.nodeMap[id] = len(self.Nodes) - self.Nodes = append(self.Nodes, node) + log.Trace("Node created", "id", conf.ID) + net.nodeMap[conf.ID] = len(net.Nodes) + net.Nodes = append(net.Nodes, node) // emit a "control" event - self.events.Send(ControlEvent(node)) + net.events.Send(ControlEvent(node)) return node, nil } // Config returns the network configuration -func (self *Network) Config() *NetworkConfig { - return &self.NetworkConfig +func (net *Network) Config() *NetworkConfig { + return &net.NetworkConfig } // StartAll starts all nodes in the network -func (self *Network) StartAll() error { - for _, node := range self.Nodes { - if node.Up { +func (net *Network) StartAll() error { + for _, node := range net.Nodes { + if node.Up() { continue } - if err := self.Start(node.ID()); err != nil { + if err := net.Start(node.ID()); err != nil { return err } } @@ -161,12 +148,12 @@ func (self *Network) StartAll() error { } // StopAll stops all nodes in the network -func (self *Network) StopAll() error { - for _, node := range self.Nodes { - if !node.Up { +func (net *Network) StopAll() error { + for _, node := range net.Nodes { + if !node.Up() { continue } - if err := self.Stop(node.ID()); err != nil { + if err := net.Stop(node.ID()); err != nil { return err } } @@ -174,29 +161,32 @@ func (self *Network) StopAll() error { } // Start starts the node with the given ID -func (self *Network) Start(id discover.NodeID) error { - return self.startWithSnapshots(id, nil) +func (net *Network) Start(id enode.ID) error { + return net.startWithSnapshots(id, nil) } // startWithSnapshots starts the node with the given ID using the give // snapshots -func (self *Network) startWithSnapshots(id discover.NodeID, snapshots map[string][]byte) error { - node := self.GetNode(id) +func (net *Network) startWithSnapshots(id enode.ID, snapshots map[string][]byte) error { + net.lock.Lock() + defer net.lock.Unlock() + + node := net.getNode(id) 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(fmt.Sprintf("starting node %v: %v using %v", id, node.Up, self.nodeAdapter.Name())) + log.Trace("Starting node", "id", id, "adapter", net.nodeAdapter.Name()) if err := node.Start(snapshots); err != nil { - log.Warn(fmt.Sprintf("start up failed: %v", err)) + log.Warn("Node startup failed", "id", id, "err", err) return err } - node.Up = true - log.Info(fmt.Sprintf("started node %v: %v", id, node.Up)) - - self.events.Send(NewEvent(node)) + node.SetUp(true) + log.Info("Started node", "id", id) + ev := NewEvent(node) + net.events.Send(ev) // subscribe to peer events client, err := node.Client() @@ -208,22 +198,27 @@ func (self *Network) startWithSnapshots(id discover.NodeID, snapshots map[string if err != nil { return fmt.Errorf("error getting peer events for node %v: %s", id, err) } - go self.watchPeerEvents(id, events, sub) + go net.watchPeerEvents(id, events, sub) return nil } // watchPeerEvents reads peer events from the given channel and emits // corresponding network events -func (self *Network) watchPeerEvents(id discover.NodeID, events chan *p2p.PeerEvent, sub event.Subscription) { +func (net *Network) watchPeerEvents(id enode.ID, events chan *p2p.PeerEvent, sub event.Subscription) { defer func() { sub.Unsubscribe() // assume the node is now down - self.lock.Lock() - node := self.getNode(id) - node.Up = false - self.lock.Unlock() - self.events.Send(NewEvent(node)) + net.lock.Lock() + defer net.lock.Unlock() + + node := net.getNode(id) + if node == nil { + return + } + node.SetUp(false) + ev := NewEvent(node) + net.events.Send(ev) }() for { select { @@ -235,22 +230,22 @@ func (self *Network) watchPeerEvents(id discover.NodeID, events chan *p2p.PeerEv switch event.Type { case p2p.PeerEventTypeAdd: - self.DidConnect(id, peer) + net.DidConnect(id, peer) case p2p.PeerEventTypeDrop: - self.DidDisconnect(id, peer) + net.DidDisconnect(id, peer) case p2p.PeerEventTypeMsgSend: - self.DidSend(id, peer, event.Protocol, *event.MsgCode) + net.DidSend(id, peer, event.Protocol, *event.MsgCode) case p2p.PeerEventTypeMsgRecv: - self.DidReceive(peer, id, event.Protocol, *event.MsgCode) + net.DidReceive(peer, id, event.Protocol, *event.MsgCode) } case err := <-sub.Err(): if err != nil { - log.Error(fmt.Sprintf("error getting peer events for node %v", id), "err", err) + log.Error("Error in peer event subscription", "id", id, "err", err) } return } @@ -258,29 +253,58 @@ func (self *Network) watchPeerEvents(id discover.NodeID, events chan *p2p.PeerEv } // Stop stops the node with the given ID -func (self *Network) Stop(id discover.NodeID) error { - node := self.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) - } - if err := node.Stop(); err != nil { +func (net *Network) Stop(id enode.ID) error { + // 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: + + var err error + + node, err := func() (*Node, error) { + net.lock.Lock() + 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 } - node.Up = false - log.Info(fmt.Sprintf("stop node %v: %v", id, node.Up)) - self.events.Send(ControlEvent(node)) + 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) + 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 (self *Network) Connect(oneID, otherID discover.NodeID) error { - log.Debug(fmt.Sprintf("connecting %s to %s", oneID, otherID)) - conn, err := self.InitConn(oneID, otherID) +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) if err != nil { return err } @@ -288,14 +312,14 @@ func (self *Network) Connect(oneID, otherID discover.NodeID) error { if err != nil { return err } - self.events.Send(ControlEvent(conn)) + net.events.Send(ControlEvent(conn)) return client.Call(nil, "admin_addPeer", string(conn.other.Addr())) } // Disconnect disconnects two nodes by calling the "admin_removePeer" RPC // method on the "one" node so that it disconnects from the "other" node -func (self *Network) Disconnect(oneID, otherID discover.NodeID) error { - conn := self.GetConn(oneID, otherID) +func (net *Network) Disconnect(oneID, otherID enode.ID) error { + conn := net.GetConn(oneID, otherID) if conn == nil { return fmt.Errorf("connection between %v and %v does not exist", oneID, otherID) } @@ -306,13 +330,15 @@ func (self *Network) Disconnect(oneID, otherID discover.NodeID) error { if err != nil { return err } - self.events.Send(ControlEvent(conn)) + net.events.Send(ControlEvent(conn)) return client.Call(nil, "admin_removePeer", string(conn.other.Addr())) } // DidConnect tracks the fact that the "one" node connected to the "other" node -func (self *Network) DidConnect(one, other discover.NodeID) error { - conn, err := self.GetOrCreateConn(one, other) +func (net *Network) DidConnect(one, other enode.ID) error { + net.lock.Lock() + defer net.lock.Unlock() + conn, err := net.getOrCreateConn(one, other) if err != nil { return fmt.Errorf("connection between %v and %v does not exist", one, other) } @@ -320,14 +346,16 @@ func (self *Network) DidConnect(one, other discover.NodeID) error { return fmt.Errorf("%v and %v already connected", one, other) } conn.Up = true - self.events.Send(NewEvent(conn)) + net.events.Send(NewEvent(conn)) return nil } // DidDisconnect tracks the fact that the "one" node disconnected from the // "other" node -func (self *Network) DidDisconnect(one, other discover.NodeID) error { - conn := self.GetConn(one, other) +func (net *Network) DidDisconnect(one, other enode.ID) error { + net.lock.Lock() + defer net.lock.Unlock() + conn := net.getConn(one, other) if conn == nil { return fmt.Errorf("connection between %v and %v does not exist", one, other) } @@ -335,13 +363,13 @@ func (self *Network) DidDisconnect(one, other discover.NodeID) error { return fmt.Errorf("%v and %v already disconnected", one, other) } conn.Up = false - conn.initiated = time.Now().Add(-dialBanTimeout) - self.events.Send(NewEvent(conn)) + conn.initiated = time.Now().Add(-DialBanTimeout) + net.events.Send(NewEvent(conn)) return nil } // DidSend tracks the fact that "sender" sent a message to "receiver" -func (self *Network) DidSend(sender, receiver discover.NodeID, proto string, code uint64) error { +func (net *Network) DidSend(sender, receiver enode.ID, proto string, code uint64) error { msg := &Msg{ One: sender, Other: receiver, @@ -349,12 +377,12 @@ func (self *Network) DidSend(sender, receiver discover.NodeID, proto string, cod Code: code, Received: false, } - self.events.Send(NewEvent(msg)) + net.events.Send(NewEvent(msg)) return nil } // DidReceive tracks the fact that "receiver" received a message from "sender" -func (self *Network) DidReceive(sender, receiver discover.NodeID, proto string, code uint64) error { +func (net *Network) DidReceive(sender, receiver enode.ID, proto string, code uint64) error { msg := &Msg{ One: sender, Other: receiver, @@ -362,36 +390,36 @@ func (self *Network) DidReceive(sender, receiver discover.NodeID, proto string, Code: code, Received: true, } - self.events.Send(NewEvent(msg)) + net.events.Send(NewEvent(msg)) return nil } // GetNode gets the node with the given ID, returning nil if the node does not // exist -func (self *Network) GetNode(id discover.NodeID) *Node { - self.lock.Lock() - defer self.lock.Unlock() - return self.getNode(id) +func (net *Network) GetNode(id enode.ID) *Node { + net.lock.RLock() + defer net.lock.RUnlock() + return net.getNode(id) +} + +func (net *Network) getNode(id enode.ID) *Node { + i, found := net.nodeMap[id] + if !found { + return nil + } + return net.Nodes[i] } // GetNode gets the node with the given name, returning nil if the node does // not exist -func (self *Network) GetNodeByName(name string) *Node { - self.lock.Lock() - defer self.lock.Unlock() - return self.getNodeByName(name) +func (net *Network) GetNodeByName(name string) *Node { + net.lock.RLock() + defer net.lock.RUnlock() + return net.getNodeByName(name) } -func (self *Network) getNode(id discover.NodeID) *Node { - i, found := self.nodeMap[id] - if !found { - return nil - } - return self.Nodes[i] -} - -func (self *Network) getNodeByName(name string) *Node { - for _, node := range self.Nodes { +func (net *Network) getNodeByName(name string) *Node { + for _, node := range net.Nodes { if node.Config.Name == name { return node } @@ -400,40 +428,105 @@ func (self *Network) getNodeByName(name string) *Node { } // GetNodes returns the existing nodes -func (self *Network) GetNodes() (nodes []*Node) { - self.lock.Lock() - defer self.lock.Unlock() +func (net *Network) GetNodes() (nodes []*Node) { + net.lock.RLock() + defer net.lock.RUnlock() - nodes = append(nodes, self.Nodes...) + 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 (self *Network) GetConn(oneID, otherID discover.NodeID) *Conn { - self.lock.Lock() - defer self.lock.Unlock() - return self.getConn(oneID, otherID) +func (net *Network) GetConn(oneID, otherID enode.ID) *Conn { + net.lock.RLock() + defer net.lock.RUnlock() + return net.getConn(oneID, otherID) } // GetOrCreateConn is like GetConn but creates the connection if it doesn't // already exist -func (self *Network) GetOrCreateConn(oneID, otherID discover.NodeID) (*Conn, error) { - self.lock.Lock() - defer self.lock.Unlock() - return self.getOrCreateConn(oneID, otherID) +func (net *Network) GetOrCreateConn(oneID, otherID enode.ID) (*Conn, error) { + net.lock.Lock() + defer net.lock.Unlock() + return net.getOrCreateConn(oneID, otherID) } -func (self *Network) getOrCreateConn(oneID, otherID discover.NodeID) (*Conn, error) { - if conn := self.getConn(oneID, otherID); conn != nil { +func (net *Network) getOrCreateConn(oneID, otherID enode.ID) (*Conn, error) { + if conn := net.getConn(oneID, otherID); conn != nil { return conn, nil } - one := self.getNode(oneID) + one := net.getNode(oneID) if one == nil { return nil, fmt.Errorf("node %v does not exist", oneID) } - other := self.getNode(otherID) + other := net.getNode(otherID) if other == nil { return nil, fmt.Errorf("node %v does not exist", otherID) } @@ -444,21 +537,21 @@ func (self *Network) getOrCreateConn(oneID, otherID discover.NodeID) (*Conn, err other: other, } label := ConnLabel(oneID, otherID) - self.connMap[label] = len(self.Conns) - self.Conns = append(self.Conns, conn) + net.connMap[label] = len(net.Conns) + net.Conns = append(net.Conns, conn) return conn, nil } -func (self *Network) getConn(oneID, otherID discover.NodeID) *Conn { +func (net *Network) getConn(oneID, otherID enode.ID) *Conn { label := ConnLabel(oneID, otherID) - i, found := self.connMap[label] + i, found := net.connMap[label] if !found { return nil } - return self.Conns[i] + 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 @@ -466,53 +559,66 @@ func (self *Network) getConn(oneID, otherID discover.NodeID) *Conn { // it also checks whether there has been recent attempt to connect the peers // this is cheating as the simulation is used as an oracle and know about // remote peers attempt to connect to a node which will then not initiate the connection -func (self *Network) InitConn(oneID, otherID discover.NodeID) (*Conn, error) { - self.lock.Lock() - defer self.lock.Unlock() +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) } - conn, err := self.getOrCreateConn(oneID, otherID) + conn, err := net.getOrCreateConn(oneID, otherID) if err != nil { return nil, err } - if time.Since(conn.initiated) < dialBanTimeout { - return nil, fmt.Errorf("connection between %v and %v recently attempted", oneID, otherID) - } if conn.Up { return nil, fmt.Errorf("%v and %v already connected", oneID, otherID) } + if time.Since(conn.initiated) < DialBanTimeout { + return nil, fmt.Errorf("connection between %v and %v recently attempted", oneID, otherID) + } + err = conn.nodesUp() if err != nil { + log.Trace("Nodes not up", "err", err) return nil, fmt.Errorf("nodes not up: %v", err) } + log.Debug("Connection initiated", "id", oneID, "other", otherID) conn.initiated = time.Now() return conn, nil } // Shutdown stops all nodes in the network and closes the quit channel -func (self *Network) Shutdown() { - for _, node := range self.Nodes { - log.Debug(fmt.Sprintf("stopping node %s", node.ID().TerminalString())) +func (net *Network) Shutdown() { + for _, node := range net.Nodes { + log.Debug("Stopping node", "id", node.ID()) if err := node.Stop(); err != nil { - log.Warn(fmt.Sprintf("error stopping node %s", node.ID().TerminalString()), "err", err) + 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(self.quitc) + close(net.quitc) } -//Reset resets all network properties: -//emtpies the nodes and the connection list -func (self *Network) Reset() { - self.lock.Lock() - defer self.lock.Unlock() +// Reset resets all network properties: +// empties the nodes and the connection list +func (net *Network) Reset() { + net.lock.Lock() + defer net.lock.Unlock() //re-initialize the maps - self.connMap = make(map[string]int) - self.nodeMap = make(map[discover.NodeID]int) + net.connMap = make(map[string]int) + net.nodeMap = make(map[enode.ID]int) - self.Nodes = nil - self.Conns = nil + net.Nodes = nil + net.Conns = nil } // Node is a wrapper around adapters.Node which is used to track the status @@ -523,52 +629,84 @@ 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 -func (self *Node) ID() discover.NodeID { - return self.Config.ID +func (n *Node) ID() enode.ID { + return n.Config.ID } // String returns a log-friendly string -func (self *Node) String() string { - return fmt.Sprintf("Node %v", self.ID().TerminalString()) +func (n *Node) String() string { + return fmt.Sprintf("Node %v", n.ID().TerminalString()) } // NodeInfo returns information about the node -func (self *Node) NodeInfo() *p2p.NodeInfo { +func (n *Node) NodeInfo() *p2p.NodeInfo { // avoid a panic if the node is not started yet - if self.Node == nil { + if n.Node == nil { return nil } - info := self.Node.NodeInfo() - info.Name = self.Config.Name + info := n.Node.NodeInfo() + info.Name = n.Config.Name return info } // MarshalJSON implements the json.Marshaler interface so that the encoded // JSON includes the NodeInfo -func (self *Node) MarshalJSON() ([]byte, error) { +func (n *Node) MarshalJSON() ([]byte, error) { return json.Marshal(struct { Info *p2p.NodeInfo `json:"info,omitempty"` Config *adapters.NodeConfig `json:"config,omitempty"` Up bool `json:"up"` }{ - Info: self.NodeInfo(), - Config: self.Config, - Up: self.Up, + Info: n.NodeInfo(), + Config: n.Config, + 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 - One discover.NodeID `json:"one"` + One enode.ID `json:"one"` // Other is the node which the connection was made to - Other discover.NodeID `json:"other"` + Other enode.ID `json:"other"` // Up tracks whether or not the connection is active Up bool `json:"up"` @@ -580,40 +718,40 @@ type Conn struct { } // nodesUp returns whether both nodes are currently up -func (self *Conn) nodesUp() error { - if !self.one.Up { - return fmt.Errorf("one %v is not up", self.One) +func (c *Conn) nodesUp() error { + if !c.one.Up() { + return fmt.Errorf("one %v is not up", c.One) } - if !self.other.Up { - return fmt.Errorf("other %v is not up", self.Other) + if !c.other.Up() { + return fmt.Errorf("other %v is not up", c.Other) } return nil } // String returns a log-friendly string -func (self *Conn) String() string { - return fmt.Sprintf("Conn %v->%v", self.One.TerminalString(), self.Other.TerminalString()) +func (c *Conn) String() string { + return fmt.Sprintf("Conn %v->%v", c.One.TerminalString(), c.Other.TerminalString()) } // Msg represents a p2p message sent between two nodes in the network type Msg struct { - One discover.NodeID `json:"one"` - Other discover.NodeID `json:"other"` - Protocol string `json:"protocol"` - Code uint64 `json:"code"` - Received bool `json:"received"` + One enode.ID `json:"one"` + Other enode.ID `json:"other"` + Protocol string `json:"protocol"` + Code uint64 `json:"code"` + Received bool `json:"received"` } // String returns a log-friendly string -func (self *Msg) String() string { - return fmt.Sprintf("Msg(%d) %v->%v", self.Code, self.One.TerminalString(), self.Other.TerminalString()) +func (m *Msg) String() string { + return fmt.Sprintf("Msg(%d) %v->%v", m.Code, m.One.TerminalString(), m.Other.TerminalString()) } // ConnLabel generates a deterministic string which represents a connection // between two nodes, used to compare if two connections are between the same // nodes -func ConnLabel(source, target discover.NodeID) string { - var first, second discover.NodeID +func ConnLabel(source, target enode.ID) string { + var first, second enode.ID if bytes.Compare(source.Bytes(), target.Bytes()) > 0 { first = target second = source @@ -640,16 +778,23 @@ type NodeSnapshot struct { } // Snapshot creates a network snapshot -func (self *Network) Snapshot() (*Snapshot, error) { - self.lock.Lock() - defer self.lock.Unlock() +func (net *Network) Snapshot() (*Snapshot, error) { + return net.snapshot(nil, nil) +} + +func (net *Network) SnapshotWithServices(addServices []string, removeServices []string) (*Snapshot, error) { + return net.snapshot(addServices, removeServices) +} + +func (net *Network) snapshot(addServices []string, removeServices []string) (*Snapshot, error) { + net.lock.Lock() + defer net.lock.Unlock() snap := &Snapshot{ - Nodes: make([]NodeSnapshot, len(self.Nodes)), - Conns: make([]Conn, len(self.Conns)), + Nodes: make([]NodeSnapshot, len(net.Nodes)), } - for i, node := range self.Nodes { + for i, node := range net.Nodes { snap.Nodes[i] = NodeSnapshot{Node: *node} - if !node.Up { + if !node.Up() { continue } snapshots, err := node.Snapshots() @@ -657,42 +802,148 @@ func (self *Network) Snapshot() (*Snapshot, error) { return nil, err } snap.Nodes[i].Snapshots = snapshots + for _, addSvc := range addServices { + haveSvc := false + for _, svc := range snap.Nodes[i].Node.Config.Services { + if svc == addSvc { + haveSvc = true + break + } + } + if !haveSvc { + snap.Nodes[i].Node.Config.Services = append(snap.Nodes[i].Node.Config.Services, addSvc) + } + } + if len(removeServices) > 0 { + var cleanedServices []string + for _, svc := range snap.Nodes[i].Node.Config.Services { + haveSvc := false + for _, rmSvc := range removeServices { + if rmSvc == svc { + haveSvc = true + break + } + } + if !haveSvc { + cleanedServices = append(cleanedServices, svc) + } + + } + snap.Nodes[i].Node.Config.Services = cleanedServices + } } - for i, conn := range self.Conns { - snap.Conns[i] = *conn + for _, conn := range net.Conns { + if conn.Up { + snap.Conns = append(snap.Conns, *conn) + } } return snap, nil } +// longrunning tests may need a longer timeout +var snapshotLoadTimeout = 900 * time.Second + // Load loads a network snapshot -func (self *Network) Load(snap *Snapshot) error { +func (net *Network) Load(snap *Snapshot) error { + // Start nodes. for _, n := range snap.Nodes { - if _, err := self.NewNodeWithConfig(n.Node.Config); err != nil { + if _, err := net.NewNodeWithConfig(n.Node.Config); err != nil { return err } - if !n.Node.Up { + if !n.Node.Up() { continue } - if err := self.startWithSnapshots(n.Node.Config.ID, n.Snapshots); err != nil { + 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 !self.GetNode(conn.One).Up || !self.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 } - if err := self.Connect(conn.One, conn.Other); err != nil { + if err := net.Connect(conn.One, conn.Other); err != nil { 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 } // Subscribe reads control events from a channel and executes them -func (self *Network) Subscribe(events chan *Event) { +func (net *Network) Subscribe(events chan *Event) { for { select { case event, ok := <-events: @@ -700,45 +951,45 @@ func (self *Network) Subscribe(events chan *Event) { return } if event.Control { - self.executeControlEvent(event) + net.executeControlEvent(event) } - case <-self.quitc: + case <-net.quitc: return } } } -func (self *Network) executeControlEvent(event *Event) { - log.Trace("execute control event", "type", event.Type, "event", event) +func (net *Network) executeControlEvent(event *Event) { + log.Trace("Executing control event", "type", event.Type, "event", event) switch event.Type { case EventTypeNode: - if err := self.executeNodeEvent(event); err != nil { - log.Error("error executing node event", "event", event, "err", err) + if err := net.executeNodeEvent(event); err != nil { + log.Error("Error executing node event", "event", event, "err", err) } case EventTypeConn: - if err := self.executeConnEvent(event); err != nil { - log.Error("error executing conn event", "event", event, "err", err) + if err := net.executeConnEvent(event); err != nil { + log.Error("Error executing conn event", "event", event, "err", err) } case EventTypeMsg: - log.Warn("ignoring control msg event") + log.Warn("Ignoring control msg event") } } -func (self *Network) executeNodeEvent(e *Event) error { - if !e.Node.Up { - return self.Stop(e.Node.ID()) +func (net *Network) executeNodeEvent(e *Event) error { + if !e.Node.Up() { + return net.Stop(e.Node.ID()) } - if _, err := self.NewNodeWithConfig(e.Node.Config); err != nil { + if _, err := net.NewNodeWithConfig(e.Node.Config); err != nil { return err } - return self.Start(e.Node.ID()) + return net.Start(e.Node.ID()) } -func (self *Network) executeConnEvent(e *Event) error { +func (net *Network) executeConnEvent(e *Event) error { if e.Conn.Up { - return self.Connect(e.Conn.One, e.Conn.Other) + return net.Connect(e.Conn.One, e.Conn.Other) } else { - return self.Disconnect(e.Conn.One, e.Conn.Other) + return net.Disconnect(e.Conn.One, e.Conn.Other) } } diff --git a/p2p/simulations/network_test.go b/p2p/simulations/network_test.go index 2a062121be..01cd1000de 100644 --- a/p2p/simulations/network_test.go +++ b/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/p2p/discover" + "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 @@ -39,9 +292,10 @@ func TestNetworkSimulation(t *testing.T) { }) defer network.Shutdown() nodeCount := 20 - ids := make([]discover.NodeID, nodeCount) + ids := make([]enode.ID, nodeCount) for i := 0; i < nodeCount; i++ { - node, err := network.NewNode() + conf := adapters.RandomNodeConfig() + node, err := network.NewNodeWithConfig(conf) if err != nil { t.Fatalf("error creating node: %s", err) } @@ -63,7 +317,7 @@ func TestNetworkSimulation(t *testing.T) { } return nil } - check := func(ctx context.Context, id discover.NodeID) (bool, error) { + check := func(ctx context.Context, id enode.ID) (bool, error) { // check we haven't run out of time select { case <-ctx.Done(): @@ -101,7 +355,7 @@ func TestNetworkSimulation(t *testing.T) { defer cancel() // trigger a check every 100ms - trigger := make(chan discover.NodeID) + trigger := make(chan enode.ID) go triggerChecks(ctx, ids, trigger, 100*time.Millisecond) result := NewSimulation(network).Run(ctx, &Step{ @@ -139,7 +393,7 @@ func TestNetworkSimulation(t *testing.T) { } } -func triggerChecks(ctx context.Context, ids []discover.NodeID, trigger chan discover.NodeID, interval time.Duration) { +func triggerChecks(ctx context.Context, ids []enode.ID, trigger chan enode.ID, interval time.Duration) { tick := time.NewTicker(interval) defer tick.Stop() for { @@ -157,3 +411,212 @@ func triggerChecks(ctx context.Context, ids []discover.NodeID, trigger chan disc } } } + +// \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/consensus/ethash/algorithm_go1.8_test.go b/p2p/simulations/pipes/pipes.go similarity index 52% rename from consensus/ethash/algorithm_go1.8_test.go rename to p2p/simulations/pipes/pipes.go index 6648bd6a97..8532c1bcf0 100644 --- a/consensus/ethash/algorithm_go1.8_test.go +++ b/p2p/simulations/pipes/pipes.go @@ -14,24 +14,42 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// +build go1.8 +package pipes -package ethash +import ( + "net" +) -import "testing" - -// Tests whether the dataset size calculator works correctly by cross checking the -// hard coded lookup table with the value generated by it. -func TestSizeCalculations(t *testing.T) { - // Verify all the cache and dataset sizes from the lookup table. - for epoch, want := range cacheSizes { - if size := calcCacheSize(epoch); size != want { - t.Errorf("cache %d: cache size mismatch: have %d, want %d", epoch, size, want) - } - } - for epoch, want := range datasetSizes { - if size := calcDatasetSize(epoch); size != want { - t.Errorf("dataset %d: dataset size mismatch: have %d, want %d", epoch, size, want) - } - } +// NetPipe wraps net.Pipe in a signature returning an error +func NetPipe() (net.Conn, net.Conn, error) { + p1, p2 := net.Pipe() + return p1, p2, nil +} + +// TCPPipe creates an in process full duplex pipe based on a localhost TCP socket +func TCPPipe() (net.Conn, net.Conn, error) { + l, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + return nil, nil, err + } + defer l.Close() + + var aconn net.Conn + aerr := make(chan error, 1) + go func() { + var err error + aconn, err = l.Accept() + aerr <- err + }() + + dconn, err := net.Dial("tcp", l.Addr().String()) + if err != nil { + <-aerr + return nil, nil, err + } + if err := <-aerr; err != nil { + dconn.Close() + return nil, nil, err + } + return aconn, dconn, nil } diff --git a/p2p/simulations/simulation.go b/p2p/simulations/simulation.go index 28886e924a..ae62c42b9c 100644 --- a/p2p/simulations/simulation.go +++ b/p2p/simulations/simulation.go @@ -20,7 +20,7 @@ import ( "context" "time" - "github.com/ethereum/go-ethereum/p2p/discover" + "github.com/ethereum/go-ethereum/p2p/enode" ) // Simulation provides a framework for running actions in a simulated network @@ -55,7 +55,7 @@ func (s *Simulation) Run(ctx context.Context, step *Step) (result *StepResult) { } // wait for all node expectations to either pass, error or timeout - nodes := make(map[discover.NodeID]struct{}, len(step.Expect.Nodes)) + nodes := make(map[enode.ID]struct{}, len(step.Expect.Nodes)) for _, id := range step.Expect.Nodes { nodes[id] = struct{}{} } @@ -119,7 +119,7 @@ type Step struct { // Trigger is a channel which receives node ids and triggers an // expectation check for that node - Trigger chan discover.NodeID + Trigger chan enode.ID // Expect is the expectation to wait for when performing this step Expect *Expectation @@ -127,15 +127,15 @@ type Step struct { type Expectation struct { // Nodes is a list of nodes to check - Nodes []discover.NodeID + Nodes []enode.ID // Check checks whether a given node meets the expectation - Check func(context.Context, discover.NodeID) (bool, error) + Check func(context.Context, enode.ID) (bool, error) } func newStepResult() *StepResult { return &StepResult{ - Passes: make(map[discover.NodeID]time.Time), + Passes: make(map[enode.ID]time.Time), } } @@ -150,7 +150,7 @@ type StepResult struct { FinishedAt time.Time // Passes are the timestamps of the successful node expectations - Passes map[discover.NodeID]time.Time + Passes map[enode.ID]time.Time // NetworkEvents are the network events which occurred during the step NetworkEvents []*Event diff --git a/p2p/simulations/test.go b/p2p/simulations/test.go new file mode 100644 index 0000000000..beeb414e41 --- /dev/null +++ b/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/p2p/testing/peerpool.go b/p2p/testing/peerpool.go new file mode 100644 index 0000000000..01ccce67eb --- /dev/null +++ b/p2p/testing/peerpool.go @@ -0,0 +1,67 @@ +// Copyright 2017 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 testing + +import ( + "fmt" + "sync" + + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/p2p/enode" +) + +type TestPeer interface { + ID() enode.ID + Drop(error) +} + +// TestPeerPool is an example peerPool to demonstrate registration of peer connections +type TestPeerPool struct { + lock sync.Mutex + peers map[enode.ID]TestPeer +} + +func NewTestPeerPool() *TestPeerPool { + return &TestPeerPool{peers: make(map[enode.ID]TestPeer)} +} + +func (p *TestPeerPool) Add(peer TestPeer) { + p.lock.Lock() + defer p.lock.Unlock() + log.Trace(fmt.Sprintf("pp add peer %v", peer.ID())) + p.peers[peer.ID()] = peer + +} + +func (p *TestPeerPool) Remove(peer TestPeer) { + p.lock.Lock() + defer p.lock.Unlock() + delete(p.peers, peer.ID()) +} + +func (p *TestPeerPool) Has(id enode.ID) bool { + p.lock.Lock() + defer p.lock.Unlock() + _, ok := p.peers[id] + return ok +} + +func (p *TestPeerPool) Get(id enode.ID) TestPeer { + p.lock.Lock() + defer p.lock.Unlock() + return p.peers[id] +} diff --git a/p2p/testing/protocolsession.go b/p2p/testing/protocolsession.go new file mode 100644 index 0000000000..476c2a9840 --- /dev/null +++ b/p2p/testing/protocolsession.go @@ -0,0 +1,282 @@ +// Copyright 2017 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 testing + +import ( + "errors" + "fmt" + "sync" + "time" + + "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/simulations/adapters" +) + +var errTimedOut = errors.New("timed out") + +// ProtocolSession is a quasi simulation of a pivot node running +// a service and a number of dummy peers that can send (trigger) or +// receive (expect) messages +type ProtocolSession struct { + Server *p2p.Server + Nodes []*enode.Node + adapter *adapters.SimAdapter + events chan *p2p.PeerEvent +} + +// Exchange is the basic units of protocol tests +// the triggers and expects in the arrays are run immediately and asynchronously +// thus one cannot have multiple expects for the SAME peer with DIFFERENT message types +// because it's unpredictable which expect will receive which message +// (with expect #1 and #2, messages might be sent #2 and #1, and both expects will complain about wrong message code) +// an exchange is defined on a session +type Exchange struct { + Label string + Triggers []Trigger + Expects []Expect + Timeout time.Duration +} + +// Trigger is part of the exchange, incoming message for the pivot node +// sent by a peer +type Trigger struct { + Msg interface{} // type of message to be sent + Code uint64 // code of message is given + Peer enode.ID // the peer to send the message to + Timeout time.Duration // timeout duration for the sending +} + +// Expect is part of an exchange, outgoing message from the pivot node +// received by a peer +type Expect struct { + Msg interface{} // type of message to expect + Code uint64 // code of message is now given + Peer enode.ID // the peer that expects the message + Timeout time.Duration // timeout duration for receiving +} + +// Disconnect represents a disconnect event, used and checked by TestDisconnected +type Disconnect struct { + Peer enode.ID // discconnected peer + Error error // disconnect reason +} + +// trigger sends messages from peers +func (s *ProtocolSession) trigger(trig Trigger) error { + simNode, ok := s.adapter.GetNode(trig.Peer) + if !ok { + return fmt.Errorf("trigger: peer %v does not exist (1- %v)", trig.Peer, len(s.Nodes)) + } + mockNode, ok := simNode.Services()[0].(*mockNode) + if !ok { + return fmt.Errorf("trigger: peer %v is not a mock", trig.Peer) + } + + errc := make(chan error) + + go func() { + log.Trace(fmt.Sprintf("trigger %v (%v)....", trig.Msg, trig.Code)) + errc <- mockNode.Trigger(&trig) + log.Trace(fmt.Sprintf("triggered %v (%v)", trig.Msg, trig.Code)) + }() + + t := trig.Timeout + if t == time.Duration(0) { + t = 1000 * time.Millisecond + } + select { + case err := <-errc: + return err + case <-time.After(t): + return fmt.Errorf("timout expecting %v to send to peer %v", trig.Msg, trig.Peer) + } +} + +// expect checks an expectation of a message sent out by the pivot node +func (s *ProtocolSession) expect(exps []Expect) error { + // construct a map of expectations for each node + peerExpects := make(map[enode.ID][]Expect) + for _, exp := range exps { + if exp.Msg == nil { + return errors.New("no message to expect") + } + peerExpects[exp.Peer] = append(peerExpects[exp.Peer], exp) + } + + // construct a map of mockNodes for each node + mockNodes := make(map[enode.ID]*mockNode) + for nodeID := range peerExpects { + simNode, ok := s.adapter.GetNode(nodeID) + if !ok { + return fmt.Errorf("trigger: peer %v does not exist (1- %v)", nodeID, len(s.Nodes)) + } + mockNode, ok := simNode.Services()[0].(*mockNode) + if !ok { + return fmt.Errorf("trigger: peer %v is not a mock", nodeID) + } + mockNodes[nodeID] = mockNode + } + + // done chanell cancels all created goroutines when function returns + done := make(chan struct{}) + defer close(done) + // errc catches the first error from + errc := make(chan error) + + wg := &sync.WaitGroup{} + wg.Add(len(mockNodes)) + for nodeID, mockNode := range mockNodes { + nodeID := nodeID + mockNode := mockNode + go func() { + defer wg.Done() + + // Sum all Expect timeouts to give the maximum + // time for all expectations to finish. + // mockNode.Expect checks all received messages against + // a list of expected messages and timeout for each + // of them can not be checked separately. + var t time.Duration + for _, exp := range peerExpects[nodeID] { + if exp.Timeout == time.Duration(0) { + t += 2000 * time.Millisecond + } else { + t += exp.Timeout + } + } + alarm := time.NewTimer(t) + defer alarm.Stop() + + // expectErrc is used to check if error returned + // from mockNode.Expect is not nil and to send it to + // errc only in that case. + // done channel will be closed when function + expectErrc := make(chan error) + go func() { + select { + case expectErrc <- mockNode.Expect(peerExpects[nodeID]...): + case <-done: + case <-alarm.C: + } + }() + + select { + case err := <-expectErrc: + if err != nil { + select { + case errc <- err: + case <-done: + case <-alarm.C: + errc <- errTimedOut + } + } + case <-done: + case <-alarm.C: + errc <- errTimedOut + } + + }() + } + + go func() { + wg.Wait() + // close errc when all goroutines finish to return nill err from errc + close(errc) + }() + + return <-errc +} + +// TestExchanges tests a series of exchanges against the session +func (s *ProtocolSession) TestExchanges(exchanges ...Exchange) error { + for i, e := range exchanges { + if err := s.testExchange(e); err != nil { + return fmt.Errorf("exchange #%d %q: %v", i, e.Label, err) + } + log.Trace(fmt.Sprintf("exchange #%d %q: run successfully", i, e.Label)) + } + return nil +} + +// testExchange tests a single Exchange. +// Default timeout value is 2 seconds. +func (s *ProtocolSession) testExchange(e Exchange) error { + errc := make(chan error) + done := make(chan struct{}) + defer close(done) + + go func() { + for _, trig := range e.Triggers { + err := s.trigger(trig) + if err != nil { + errc <- err + return + } + } + + select { + case errc <- s.expect(e.Expects): + case <-done: + } + }() + + // time out globally or finish when all expectations satisfied + t := e.Timeout + if t == 0 { + t = 2000 * time.Millisecond + } + alarm := time.NewTimer(t) + select { + case err := <-errc: + return err + case <-alarm.C: + return errTimedOut + } +} + +// TestDisconnected tests the disconnections given as arguments +// the disconnect structs describe what disconnect error is expected on which peer +func (s *ProtocolSession) TestDisconnected(disconnects ...*Disconnect) error { + expects := make(map[enode.ID]error) + for _, disconnect := range disconnects { + expects[disconnect.Peer] = disconnect.Error + } + + timeout := time.After(time.Second) + for len(expects) > 0 { + select { + case event := <-s.events: + if event.Type != p2p.PeerEventTypeDrop { + continue + } + expectErr, ok := expects[event.Peer] + if !ok { + continue + } + + if !(expectErr == nil && event.Error == "" || expectErr != nil && expectErr.Error() == event.Error) { + return fmt.Errorf("unexpected error on peer %v. expected '%v', got '%v'", event.Peer, expectErr, event.Error) + } + delete(expects, event.Peer) + case <-timeout: + return fmt.Errorf("timed out waiting for peers to disconnect") + } + } + return nil +} diff --git a/p2p/testing/protocoltester.go b/p2p/testing/protocoltester.go new file mode 100644 index 0000000000..cbd8ce6fe5 --- /dev/null +++ b/p2p/testing/protocoltester.go @@ -0,0 +1,283 @@ +// Copyright 2017 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 . + +/* +the p2p/testing package provides a unit test scheme to check simple +protocol message exchanges with one pivot node and a number of dummy peers +The pivot test node runs a node.Service, the dummy peers run a mock node +that can be used to send and receive messages +*/ + +package testing + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "strings" + "sync" + + "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" + "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/rpc" +) + +// ProtocolTester is the tester environment used for unit testing protocol +// message exchanges. It uses p2p/simulations framework +type ProtocolTester struct { + *ProtocolSession + network *simulations.Network +} + +// 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(id enode.ID, n int, run func(*p2p.Peer, p2p.MsgReadWriter) error) *ProtocolTester { + services := adapters.Services{ + "test": func(ctx *adapters.ServiceContext) (node.Service, error) { + return &testNode{run}, nil + }, + "mock": func(ctx *adapters.ServiceContext) (node.Service, error) { + return newMockNode(), nil + }, + } + adapter := adapters.NewSimAdapter(services) + net := simulations.NewNetwork(adapter, &simulations.NetworkConfig{}) + if _, err := net.NewNodeWithConfig(&adapters.NodeConfig{ + ID: id, + EnableMsgEvents: true, + Services: []string{"test"}, + }); err != nil { + panic(err.Error()) + } + if err := net.Start(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++ { + peers[i] = adapters.RandomNodeConfig() + peers[i].Services = []string{"mock"} + nodes[i] = peers[i].Node() + } + events := make(chan *p2p.PeerEvent, 1000) + node.SubscribeEvents(events) + ps := &ProtocolSession{ + Server: node.Server(), + Nodes: nodes, + adapter: adapter, + events: events, + } + self := &ProtocolTester{ + ProtocolSession: ps, + network: net, + } + + self.Connect(id, peers...) + + return self +} + +// Stop stops the p2p server +func (t *ProtocolTester) Stop() error { + 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)) + } + } + +} + +// testNode wraps a protocol run function and implements the node.Service +// interface +type testNode struct { + run func(*p2p.Peer, p2p.MsgReadWriter) error +} + +func (t *testNode) Protocols() []p2p.Protocol { + return []p2p.Protocol{{ + Length: 100, + Run: t.run, + }} +} + +func (t *testNode) APIs() []rpc.API { + return nil +} + +func (t *testNode) Start(server *p2p.Server) error { + return nil +} + +func (t *testNode) Stop() error { + return nil +} + +// mockNode is a testNode which doesn't actually run a protocol, instead +// exposing channels so that tests can manually trigger and expect certain +// messages +type mockNode struct { + testNode + + trigger chan *Trigger + expect chan []Expect + err chan error + stop chan struct{} + stopOnce sync.Once +} + +func newMockNode() *mockNode { + mock := &mockNode{ + trigger: make(chan *Trigger), + expect: make(chan []Expect), + err: make(chan error), + stop: make(chan struct{}), + } + mock.testNode.run = mock.Run + return mock +} + +// Run is a protocol run function which just loops waiting for tests to +// instruct it to either trigger or expect a message from the peer +func (m *mockNode) Run(peer *p2p.Peer, rw p2p.MsgReadWriter) error { + for { + select { + case trig := <-m.trigger: + wmsg := Wrap(trig.Msg) + m.err <- p2p.Send(rw, trig.Code, wmsg) + case exps := <-m.expect: + m.err <- expectMsgs(rw, exps) + case <-m.stop: + return nil + } + } +} + +func (m *mockNode) Trigger(trig *Trigger) error { + m.trigger <- trig + return <-m.err +} + +func (m *mockNode) Expect(exp ...Expect) error { + m.expect <- exp + return <-m.err +} + +func (m *mockNode) Stop() error { + m.stopOnce.Do(func() { close(m.stop) }) + return nil +} + +func expectMsgs(rw p2p.MsgReadWriter, exps []Expect) error { + matched := make([]bool, len(exps)) + for { + msg, err := rw.ReadMsg() + if err != nil { + if err == io.EOF { + break + } + return err + } + actualContent, err := ioutil.ReadAll(msg.Payload) + if err != nil { + return err + } + var found bool + for i, exp := range exps { + if exp.Code == msg.Code && bytes.Equal(actualContent, mustEncodeMsg(Wrap(exp.Msg))) { + if matched[i] { + return fmt.Errorf("message #%d received two times", i) + } + matched[i] = true + found = true + break + } + } + if !found { + expected := make([]string, 0) + for i, exp := range exps { + if matched[i] { + continue + } + expected = append(expected, fmt.Sprintf("code %d payload %x", exp.Code, mustEncodeMsg(Wrap(exp.Msg)))) + } + return fmt.Errorf("unexpected message code %d payload %x, expected %s", msg.Code, actualContent, strings.Join(expected, " or ")) + } + done := true + for _, m := range matched { + if !m { + done = false + break + } + } + if done { + return nil + } + } + for i, m := range matched { + if !m { + return fmt.Errorf("expected message #%d not received", i) + } + } + return nil +} + +// mustEncodeMsg uses rlp to encode a message. +// In case of error it panics. +func mustEncodeMsg(msg interface{}) []byte { + contentEnc, err := rlp.EncodeToBytes(msg) + if err != nil { + panic("content encode error: " + err.Error()) + } + return contentEnc +} + +type WrappedMsg struct { + Context []byte + Size uint32 + Payload []byte +} + +func Wrap(msg interface{}) interface{} { + data, _ := rlp.EncodeToBytes(msg) + return &WrappedMsg{ + Size: uint32(len(data)), + Payload: data, + } +} diff --git a/params/bootnodes.go b/params/bootnodes.go index 31252c7c6e..bdaa4a18c4 100644 --- a/params/bootnodes.go +++ b/params/bootnodes.go @@ -33,8 +33,10 @@ var MainnetBootnodes = []string{ // TestnetBootnodes are the enode URLs of the P2P bootstrap nodes running on the // Ropsten test network. var TestnetBootnodes = []string{ - "enode://6ce05930c72abc632c58e2e4324f7c7ea478cec0ed4fa2528982cf34483094e9cbc9216e7aa349691242576d552a2a56aaeae426c5303ded677ce455ba1acd9d@13.84.180.240:30303", // US-TX - "enode://20c9ad97c081d63397d7b685a412227a40e23c8bdc6688c6f37e97cfbc22d2b4d1db1510d8f61e6a8866ad7f0e17c02b14182d37ea7c3c8b9c2683aeb6b733a1@52.169.14.227:30303", // IE + "enode://30b7ab30a01c124a6cceca36863ece12c4f5fa68e3ba9b0b51407ccc002eeed3b3102d20a88f1c1d3c3154e2449317b8ef95090e77b312d5cc39354f86d5d606@52.176.7.10:30303", // US-Azure geth + "enode://865a63255b3bb68023b6bffd5095118fcc13e79dcf014fe4e47e065c350c7cc72af2e53eff895f11ba1bbb6a2b33271c1116ee870f266618eadfc2e78aa7349c@52.176.100.77:30303", // US-Azure parity + "enode://6332792c4a00e3e4ee0926ed89e0d27ef985424d97b6a45bf0f23e51f0dcb5e66b875777506458aea7af6f9e4ffb69f43f3778ee73c81ed9d34c51c4b16b0b0f@52.232.243.152:30303", // Parity + "enode://94c15d1b9e2fe7ce56e458b9a3b672ef11894ddedd0c6f247e0f1d3487f52b66208fb4aeb8179fce6e3a749ea93ed147c37976d67af557508d199d9594c35f09@192.81.208.223:30303", // @gpip } // RinkebyBootnodes are the enode URLs of the P2P bootstrap nodes running on the @@ -45,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/params/config.go b/params/config.go index 345f6394ab..44b2ffeba8 100644 --- a/params/config.go +++ b/params/config.go @@ -23,85 +23,156 @@ import ( "github.com/ethereum/go-ethereum/common" ) +// Genesis hashes to enforce below configs on. var ( - MainnetGenesisHash = common.HexToHash("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3") // Mainnet genesis hash to enforce below configs on - TestnetGenesisHash = common.HexToHash("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d") // Testnet genesis hash to enforce below configs on + MainnetGenesisHash = common.HexToHash("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3") + TestnetGenesisHash = common.HexToHash("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d") + RinkebyGenesisHash = common.HexToHash("0x6341fd3daf94b748c72ced5a5b26028f2474f5f00d824504e4fa37a75767e177") ) var ( // MainnetChainConfig is the chain parameters to run a node on the main network. MainnetChainConfig = &ChainConfig{ - ChainId: big.NewInt(1), - HomesteadBlock: big.NewInt(1150000), - DAOForkBlock: big.NewInt(1920000), - DAOForkSupport: true, - EIP150Block: big.NewInt(2463000), - EIP150Hash: common.HexToHash("0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0"), - EIP155Block: big.NewInt(2675000), - EIP158Block: big.NewInt(2675000), - ByzantiumBlock: big.NewInt(4370000), + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(1150000), + DAOForkBlock: big.NewInt(1920000), + DAOForkSupport: true, + EIP150Block: big.NewInt(2463000), + EIP150Hash: common.HexToHash("0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0"), + EIP155Block: big.NewInt(2675000), + EIP158Block: big.NewInt(2675000), + ByzantiumBlock: big.NewInt(4370000), + ConstantinopleBlock: big.NewInt(7280000), + PetersburgBlock: big.NewInt(7280000), + Ethash: new(EthashConfig), + } - Ethash: new(EthashConfig), + // MainnetTrustedCheckpoint contains the light client trusted checkpoint for the main network. + MainnetTrustedCheckpoint = &TrustedCheckpoint{ + Name: "mainnet", + 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. TestnetChainConfig = &ChainConfig{ - ChainId: big.NewInt(3), - HomesteadBlock: big.NewInt(0), - DAOForkBlock: nil, - DAOForkSupport: true, - EIP150Block: big.NewInt(0), - EIP150Hash: common.HexToHash("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d"), - EIP155Block: big.NewInt(10), - EIP158Block: big.NewInt(10), - ByzantiumBlock: big.NewInt(1700000), + ChainID: big.NewInt(3), + HomesteadBlock: big.NewInt(0), + DAOForkBlock: nil, + DAOForkSupport: true, + EIP150Block: big.NewInt(0), + EIP150Hash: common.HexToHash("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d"), + EIP155Block: big.NewInt(10), + EIP158Block: big.NewInt(10), + ByzantiumBlock: big.NewInt(1700000), + ConstantinopleBlock: big.NewInt(4230000), + PetersburgBlock: big.NewInt(4939394), + Ethash: new(EthashConfig), + } - Ethash: new(EthashConfig), + // TestnetTrustedCheckpoint contains the light client trusted checkpoint for the Ropsten test network. + TestnetTrustedCheckpoint = &TrustedCheckpoint{ + Name: "testnet", + 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. RinkebyChainConfig = &ChainConfig{ - ChainId: big.NewInt(4), - HomesteadBlock: big.NewInt(1), - DAOForkBlock: nil, - DAOForkSupport: true, - EIP150Block: big.NewInt(2), - EIP150Hash: common.HexToHash("0x9b095b36c15eaf13044373aef8ee0bd3a382a5abb92e402afa44b8249c3a90e9"), - EIP155Block: big.NewInt(3), - EIP158Block: big.NewInt(3), - ByzantiumBlock: big.NewInt(1035301), - + ChainID: big.NewInt(4), + HomesteadBlock: big.NewInt(1), + DAOForkBlock: nil, + DAOForkSupport: true, + EIP150Block: big.NewInt(2), + EIP150Hash: common.HexToHash("0x9b095b36c15eaf13044373aef8ee0bd3a382a5abb92e402afa44b8249c3a90e9"), + EIP155Block: big.NewInt(3), + EIP158Block: big.NewInt(3), + ByzantiumBlock: big.NewInt(1035301), + ConstantinopleBlock: big.NewInt(3660663), + PetersburgBlock: big.NewInt(9999999), //TODO! Insert Rinkeby block number Clique: &CliqueConfig{ Period: 15, Epoch: 30000, }, } + // RinkebyTrustedCheckpoint contains the light client trusted checkpoint for the Rinkeby test network. + RinkebyTrustedCheckpoint = &TrustedCheckpoint{ + Name: "rinkeby", + 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 // and accepted by the Ethereum core developers into the Ethash consensus. // // 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), 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, &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), 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)) ) +// TrustedCheckpoint represents a set of post-processed trie roots (CHT and +// BloomTrie) associated with the appropriate section index and head hash. It is +// used to start light syncing from this checkpoint and avoid downloading the +// entire header chain while still being able to securely access old headers/logs. +type TrustedCheckpoint struct { + Name string `json:"-"` + SectionIndex uint64 `json:"sectionIndex"` + SectionHead common.Hash `json:"sectionHead"` + CHTRoot common.Hash `json:"chtRoot"` + BloomRoot common.Hash `json:"bloomRoot"` +} + // ChainConfig is the core config which determines the blockchain settings. // // ChainConfig is stored in the database on a per block basis. This means // that any network, identified by its genesis block, can have its own // set of configuration options. type ChainConfig struct { - ChainId *big.Int `json:"chainId"` // Chain id identifies the current chain and is used for replay protection + ChainID *big.Int `json:"chainId"` // chainId identifies the current chain and is used for replay protection HomesteadBlock *big.Int `json:"homesteadBlock,omitempty"` // Homestead switch block (nil = no fork, 0 = already homestead) @@ -115,7 +186,10 @@ type ChainConfig struct { EIP155Block *big.Int `json:"eip155Block,omitempty"` // EIP155 HF block EIP158Block *big.Int `json:"eip158Block,omitempty"` // EIP158 HF block - ByzantiumBlock *big.Int `json:"byzantiumBlock,omitempty"` // Byzantium switch block (nil = no fork, 0 = already on byzantium) + 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 Ethash *EthashConfig `json:"ethash,omitempty"` @@ -152,8 +226,8 @@ 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 Engine: %v}", - c.ChainId, + 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, c.DAOForkSupport, @@ -161,6 +235,8 @@ func (c *ChainConfig) String() string { c.EIP155Block, c.EIP158Block, c.ByzantiumBlock, + c.ConstantinopleBlock, + c.PetersburgBlock, engine, ) } @@ -170,27 +246,48 @@ func (c *ChainConfig) IsHomestead(num *big.Int) bool { return isForked(c.HomesteadBlock, num) } -// IsDAO returns whether num is either equal to the DAO fork block or greater. +// IsDAOFork returns whether num is either equal to the DAO fork block or greater. func (c *ChainConfig) IsDAOFork(num *big.Int) bool { return isForked(c.DAOForkBlock, num) } +// IsEIP150 returns whether num is either equal to the EIP150 fork block or greater. func (c *ChainConfig) IsEIP150(num *big.Int) bool { return isForked(c.EIP150Block, num) } +// IsEIP155 returns whether num is either equal to the EIP155 fork block or greater. func (c *ChainConfig) IsEIP155(num *big.Int) bool { return isForked(c.EIP155Block, num) } +// IsEIP158 returns whether num is either equal to the EIP158 fork block or greater. func (c *ChainConfig) IsEIP158(num *big.Int) bool { return isForked(c.EIP158Block, num) } +// IsByzantium returns whether num is either equal to the Byzantium fork block or greater. func (c *ChainConfig) IsByzantium(num *big.Int) bool { return isForked(c.ByzantiumBlock, num) } +// IsConstantinople returns whether num is either equal to the Constantinople fork block or greater. +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) +} + // GasTable returns the gas table corresponding to the current phase (homestead or homestead reprice). // // The returned GasTable's fields shouldn't, under any circumstances, be changed. @@ -199,6 +296,8 @@ func (c *ChainConfig) GasTable(num *big.Int) GasTable { return GasTableHomestead } switch { + case c.IsConstantinople(num): + return GasTableConstantinople case c.IsEIP158(num): return GasTableEIP158 case c.IsEIP150(num): @@ -245,12 +344,21 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, head *big.Int) *Confi if isForkIncompatible(c.EIP158Block, newcfg.EIP158Block, head) { return newCompatError("EIP158 fork block", c.EIP158Block, newcfg.EIP158Block) } - if c.IsEIP158(head) && !configNumEqual(c.ChainId, newcfg.ChainId) { + if c.IsEIP158(head) && !configNumEqual(c.ChainID, newcfg.ChainID) { return newCompatError("EIP158 chain ID", c.EIP158Block, newcfg.EIP158Block) } if isForkIncompatible(c.ByzantiumBlock, newcfg.ByzantiumBlock, head) { return newCompatError("Byzantium fork block", c.ByzantiumBlock, newcfg.ByzantiumBlock) } + 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) + } return nil } @@ -309,21 +417,31 @@ func (err *ConfigCompatError) Error() string { return fmt.Sprintf("mismatching %s in database (have %d, want %d, rewindto %d)", err.What, err.StoredConfig, err.NewConfig, err.RewindTo) } -// Rules wraps ChainConfig and is merely syntatic sugar or can be used for functions +// Rules wraps ChainConfig and is merely syntactic sugar or can be used for functions // that do not have or require information about the block. // // 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 bool + ChainID *big.Int + IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool + IsByzantium, IsConstantinople, IsPetersburg bool } +// Rules ensures c's ChainID is not nil. func (c *ChainConfig) Rules(num *big.Int) Rules { - chainId := c.ChainId - if chainId == nil { - chainId = new(big.Int) + chainID := c.ChainID + if chainID == nil { + chainID = new(big.Int) + } + return Rules{ + ChainID: new(big.Int).Set(chainID), + IsHomestead: c.IsHomestead(num), + IsEIP150: c.IsEIP150(num), + IsEIP155: c.IsEIP155(num), + IsEIP158: c.IsEIP158(num), + IsByzantium: c.IsByzantium(num), + IsConstantinople: c.IsConstantinople(num), + IsPetersburg: c.IsPetersburg(num), } - return Rules{ChainId: new(big.Int).Set(chainId), IsHomestead: c.IsHomestead(num), IsEIP150: c.IsEIP150(num), IsEIP155: c.IsEIP155(num), IsEIP158: c.IsEIP158(num), IsByzantium: c.IsByzantium(num)} } diff --git a/params/denomination.go b/params/denomination.go index 9e1b52506f..fb4da7f412 100644 --- a/params/denomination.go +++ b/params/denomination.go @@ -16,19 +16,13 @@ package params +// These are the multipliers for ether denominations. +// Example: To get the wei value of an amount in 'gwei', use +// +// new(big.Int).Mul(value, big.NewInt(params.GWei)) +// const ( - // These are the multipliers for ether denominations. - // Example: To get the wei value of an amount in 'douglas', use - // - // new(big.Int).Mul(value, big.NewInt(params.Douglas)) - // - Wei = 1 - Ada = 1e3 - Babbage = 1e6 - Shannon = 1e9 - Szabo = 1e12 - Finney = 1e15 - Ether = 1e18 - Einstein = 1e21 - Douglas = 1e42 + Wei = 1 + GWei = 1e9 + Ether = 1e18 ) diff --git a/params/gas_table.go b/params/gas_table.go index 4969382b1b..6c4a38269c 100644 --- a/params/gas_table.go +++ b/params/gas_table.go @@ -16,9 +16,11 @@ package params +// GasTable organizes gas prices for different ethereum phases. type GasTable struct { ExtcodeSize uint64 ExtcodeCopy uint64 + ExtcodeHash uint64 Balance uint64 SLoad uint64 Calls uint64 @@ -34,6 +36,7 @@ type GasTable struct { CreateBySuicide uint64 } +// Variables containing gas prices for different ethereum phases. var ( // GasTableHomestead contain the gas prices for // the homestead phase. @@ -47,8 +50,8 @@ var ( ExpByte: 10, } - // GasTableHomestead contain the gas re-prices for - // the homestead phase. + // GasTableEIP150 contain the gas re-prices for + // the EIP150 phase. GasTableEIP150 = GasTable{ ExtcodeSize: 700, ExtcodeCopy: 700, @@ -60,7 +63,8 @@ var ( CreateBySuicide: 25000, } - + // GasTableEIP158 contain the gas re-prices for + // the EIP155/EIP158 phase. GasTableEIP158 = GasTable{ ExtcodeSize: 700, ExtcodeCopy: 700, @@ -70,6 +74,20 @@ var ( Suicide: 5000, ExpByte: 50, + CreateBySuicide: 25000, + } + // GasTableConstantinople contain the gas re-prices for + // the constantinople phase. + GasTableConstantinople = GasTable{ + ExtcodeSize: 700, + ExtcodeCopy: 700, + ExtcodeHash: 400, + Balance: 400, + SLoad: 200, + Calls: 700, + Suicide: 5000, + ExpByte: 50, + CreateBySuicide: 25000, } ) diff --git a/params/network_params.go b/params/network_params.go index 536a46d3df..f8731e8979 100644 --- a/params/network_params.go +++ b/params/network_params.go @@ -17,10 +17,38 @@ package params // These are network parameters that need to be constant between clients, but -// aren't necesarilly consensus related. +// aren't necessarily consensus related. const ( // BloomBitsBlocks is the number of blocks a single bloom bit section vector - // contains. + // contains on the server side. BloomBitsBlocks uint64 = 4096 + + // BloomBitsBlocksClient is the number of blocks a single bloom bit section vector + // contains on the light client side + BloomBitsBlocksClient uint64 = 32768 + + // BloomConfirms is the number of confirmation blocks before a bloom section is + // considered probably final and its rotated bits are calculated. + BloomConfirms = 256 + + // CHTFrequencyClient is the block frequency for creating CHTs on the client side. + CHTFrequencyClient = 32768 + + // CHTFrequencyServer is the block frequency for creating CHTs on the server side. + // Eventually this can be merged back with the client version, but that requires a + // full database upgrade, so that should be left for a suitable moment. + CHTFrequencyServer = 4096 + + // BloomTrieFrequency is the block frequency for creating BloomTrie on both + // server/client sides. + BloomTrieFrequency = 32768 + + // HelperTrieConfirmations is the number of confirmations before a client is expected + // to have the given HelperTrie available. + HelperTrieConfirmations = 2048 + + // HelperTrieProcessConfirmations is the number of confirmations before a HelperTrie + // is generated + HelperTrieProcessConfirmations = 256 ) diff --git a/params/protocol_params.go b/params/protocol_params.go index 5a0b14d61a..14750f6a1a 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -18,10 +18,6 @@ package params import "math/big" -var ( - TargetGasLimit uint64 = GenesisGasLimit // The artificial target -) - const ( GasLimitBoundDivisor uint64 = 1024 // The bound divisor of the gas limit, used in update calculations. MinGasLimit uint64 = 5000 // Minimum the gas limit may ever be. @@ -36,16 +32,27 @@ const ( TxGasContractCreation uint64 = 53000 // Per transaction that creates a contract. NOTE: Not payable on data of calls between transactions. TxDataZeroGas uint64 = 4 // Per byte of data attached to a transaction that equals zero. NOTE: Not payable on data of calls between transactions. QuadCoeffDiv uint64 = 512 // Divisor for the quadratic particle of the memory cost equation. - SstoreSetGas uint64 = 20000 // Once per SLOAD operation. LogDataGas uint64 = 8 // Per byte in a LOG* operation's data. CallStipend uint64 = 2300 // Free gas given at beginning of call. - Sha3Gas uint64 = 30 // Once per SHA3 operation. - Sha3WordGas uint64 = 6 // Once per word of the SHA3 operation's data. - SstoreResetGas uint64 = 5000 // Once per SSTORE operation if the zeroness changes from zero. - SstoreClearGas uint64 = 5000 // Once per SSTORE operation if the zeroness doesn't change. - SstoreRefundGas uint64 = 15000 // Once per SSTORE operation if the zeroness changes to zero. - JumpdestGas uint64 = 1 // Refunded gas, once per SSTORE operation if the zeroness changes to zero. + Sha3Gas uint64 = 30 // Once per SHA3 operation. + Sha3WordGas uint64 = 6 // Once per word of the SHA3 operation's data. + + SstoreSetGas uint64 = 20000 // Once per SLOAD operation. + SstoreResetGas uint64 = 5000 // Once per SSTORE operation if the zeroness changes from zero. + SstoreClearGas uint64 = 5000 // Once per SSTORE operation if the zeroness doesn't change. + SstoreRefundGas uint64 = 15000 // Once per SSTORE operation if the zeroness changes to zero. + + NetSstoreNoopGas uint64 = 200 // Once per SSTORE operation if the value doesn't change. + NetSstoreInitGas uint64 = 20000 // Once per SSTORE operation from clean zero. + NetSstoreCleanGas uint64 = 5000 // Once per SSTORE operation from clean non-zero. + NetSstoreDirtyGas uint64 = 200 // Once per SSTORE operation from dirty. + + NetSstoreClearRefund uint64 = 15000 // Once per SSTORE operation for clearing an originally existing storage slot + 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 // 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 // @@ -57,6 +64,7 @@ const ( TierStepGas uint64 = 0 // Once per operation, for a selection of them. LogTopicGas uint64 = 375 // Multiplied by the * of the LOG*, per LOG transaction. e.g. LOG0 incurs 0 * c_txLogTopicGas, LOG4 incurs 4 * c_txLogTopicGas. CreateGas uint64 = 32000 // Once per CREATE operation & contract-creation transaction. + Create2Gas uint64 = 32000 // Once per CREATE2 operation SuicideRefundGas uint64 = 24000 // Refunded following a suicide operation. MemoryGas uint64 = 3 // Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL. TxDataNonZeroGas uint64 = 68 // Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions. diff --git a/params/version.go b/params/version.go index 32d4a2e23c..d3954e0bc3 100644 --- a/params/version.go +++ b/params/version.go @@ -22,22 +22,41 @@ import ( const ( VersionMajor = 1 // Major version component of the current release - VersionMinor = 8 // Minor 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. var Version = func() string { - v := fmt.Sprintf("%d.%d.%d", VersionMajor, VersionMinor, VersionPatch) + return fmt.Sprintf("%d.%d.%d", VersionMajor, VersionMinor, VersionPatch) +}() + +// VersionWithMeta holds the textual version string including the metadata. +var VersionWithMeta = func() string { + v := Version if VersionMeta != "" { v += "-" + VersionMeta } return v }() -func VersionWithCommit(gitCommit string) string { +// ArchiveVersion holds the textual version string used for Geth archives. +// e.g. "1.8.11-dea1ce05" for stable releases, or +// "1.8.13-unstable-21c059b6" for unstable releases +func ArchiveVersion(gitCommit string) string { vsn := Version + if VersionMeta != "stable" { + vsn += "-" + VersionMeta + } + if len(gitCommit) >= 8 { + vsn += "-" + gitCommit[:8] + } + return vsn +} + +func VersionWithCommit(gitCommit string) string { + vsn := VersionWithMeta if len(gitCommit) >= 8 { vsn += "-" + gitCommit[:8] } diff --git a/rlp/decode.go b/rlp/decode.go index 60d9dab2b5..e638c01eaf 100644 --- a/rlp/decode.go +++ b/rlp/decode.go @@ -26,11 +26,33 @@ import ( "math/big" "reflect" "strings" + "sync" ) var ( + // EOL is returned when the end of the current list + // has been reached during streaming. + EOL = errors.New("rlp: end of list") + + // Actual Errors + ErrExpectedString = errors.New("rlp: expected String or Byte") + ErrExpectedList = errors.New("rlp: expected List") + ErrCanonInt = errors.New("rlp: non-canonical integer format") + ErrCanonSize = errors.New("rlp: non-canonical size information") + ErrElemTooLarge = errors.New("rlp: element is larger than containing list") + ErrValueTooLarge = errors.New("rlp: value size exceeds available input length") + ErrMoreThanOneValue = errors.New("rlp: input contains more than one value") + + // internal errors + errNotInList = errors.New("rlp: call of ListEnd outside of any list") + errNotAtEOL = errors.New("rlp: call of ListEnd not positioned at EOL") + 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 @@ -109,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 { @@ -274,9 +303,8 @@ func makeListDecoder(typ reflect.Type, tag tags) (decoder, error) { if etype.Kind() == reflect.Uint8 && !reflect.PtrTo(etype).Implements(decoderInterface) { if typ.Kind() == reflect.Array { return decodeByteArray, nil - } else { - return decodeByteSlice, nil } + return decodeByteSlice, nil } etypeinfo, err := cachedTypeInfo1(etype, tags{}) if err != nil { @@ -555,29 +583,6 @@ func (k Kind) String() string { } } -var ( - // EOL is returned when the end of the current list - // has been reached during streaming. - EOL = errors.New("rlp: end of list") - - // Actual Errors - ErrExpectedString = errors.New("rlp: expected String or Byte") - ErrExpectedList = errors.New("rlp: expected List") - ErrCanonInt = errors.New("rlp: non-canonical integer format") - ErrCanonSize = errors.New("rlp: non-canonical size information") - ErrElemTooLarge = errors.New("rlp: element is larger than containing list") - ErrValueTooLarge = errors.New("rlp: value size exceeds available input length") - - // This error is reported by DecodeBytes if the slice contains - // additional data after the first RLP value. - ErrMoreThanOneValue = errors.New("rlp: input contains more than one value") - - // internal errors - errNotInList = errors.New("rlp: call of ListEnd outside of any list") - errNotAtEOL = errors.New("rlp: call of ListEnd not positioned at EOL") - errUintOverflow = errors.New("rlp: uint overflow") -) - // ByteReader must be implemented by any input reader for a Stream. It // is implemented by e.g. bufio.Reader and bytes.Reader. type ByteReader interface { @@ -860,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/rlp/encode.go b/rlp/encode.go index 44592c2f53..445b4b5b21 100644 --- a/rlp/encode.go +++ b/rlp/encode.go @@ -92,7 +92,7 @@ func Encode(w io.Writer, val interface{}) error { return eb.toWriter(w) } -// EncodeBytes returns the RLP encoding of val. +// EncodeToBytes returns the RLP encoding of val. // Please see the documentation of Encode for the encoding rules. func EncodeToBytes(val interface{}) ([]byte, error) { eb := encbufPool.Get().(*encbuf) @@ -104,7 +104,7 @@ func EncodeToBytes(val interface{}) ([]byte, error) { return eb.toBytes(), nil } -// EncodeReader returns a reader from which the RLP encoding of val +// EncodeToReader returns a reader from which the RLP encoding of val // can be read. The returned size is the total size of the encoded // data. // @@ -151,11 +151,10 @@ func puthead(buf []byte, smalltag, largetag byte, size uint64) int { if size < 56 { buf[0] = smalltag + byte(size) return 1 - } else { - sizesize := putint(buf[1:], size) - buf[0] = largetag + byte(sizesize) - return sizesize + 1 } + sizesize := putint(buf[1:], size) + buf[0] = largetag + byte(sizesize) + return sizesize + 1 } // encbufs are pooled. @@ -218,7 +217,7 @@ func (w *encbuf) list() *listhead { func (w *encbuf) listEnd(lh *listhead) { lh.size = w.size() - lh.offset - lh.size if lh.size < 56 { - w.lhsize += 1 // length encoded into kind tag + w.lhsize++ // length encoded into kind tag } else { w.lhsize += 1 + intsize(uint64(lh.size)) } @@ -322,10 +321,9 @@ func (r *encReader) next() []byte { p := r.buf.str[r.strpos:head.offset] r.strpos += sizebefore return p - } else { - r.lhpos++ - return head.encode(r.buf.sizebuf) } + r.lhpos++ + return head.encode(r.buf.sizebuf) case r.strpos < len(r.buf.str): // String data at the end, after all list headers. @@ -576,9 +574,8 @@ func makePtrWriter(typ reflect.Type) (writer, error) { writer := func(val reflect.Value, w *encbuf) error { if val.IsNil() { return nilfunc(w) - } else { - return etypeinfo.writer(val.Elem(), w) } + return etypeinfo.writer(val.Elem(), w) } return writer, err } diff --git a/rlp/typecache.go b/rlp/typecache.go index 3df799e1ec..8c2dd518e2 100644 --- a/rlp/typecache.go +++ b/rlp/typecache.go @@ -76,7 +76,7 @@ func cachedTypeInfo1(typ reflect.Type, tags tags) (*typeinfo, error) { // another goroutine got the write lock first return info, nil } - // put a dummmy value into the cache before generating. + // put a dummy value into the cache before generating. // if the generator tries to lookup itself, it will get // the dummy value and won't call itself recursively. typeCache[key] = new(typeinfo) diff --git a/rpc/client.go b/rpc/client.go index 8aa84ec982..02029dc8f6 100644 --- a/rpc/client.go +++ b/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 ) @@ -60,7 +57,7 @@ const ( // The approach taken here is to maintain a per-subscription linked list buffer // shrinks on demand. If the buffer reaches the size below, the subscription is // dropped. - maxClientSubscriptionBuffer = 8000 + maxClientSubscriptionBuffer = 20000 ) // BatchElem is an element in a batch request. @@ -76,55 +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{} - didQuit 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 { @@ -134,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 @@ -171,6 +175,8 @@ func DialContext(ctx context.Context, rawurl string) (*Client, error) { return DialHTTP(rawurl) case "ws", "wss": return DialWebsocket(ctx, rawurl, "") + case "stdio": + return DialStdIO(ctx) case "": return DialIPC(ctx, rawurl) default: @@ -178,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 } - _, isHTTP := conn.(*httpConn) + 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{}), - didQuit: make(chan struct{}), - reconnected: make(chan net.Conn), + closing: make(chan struct{}), + didClose: make(chan struct{}), + 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 @@ -227,8 +254,8 @@ func (c *Client) Close() { } select { case c.close <- struct{}{}: - <-c.didQuit - case <-c.didQuit: + <-c.didClose + case <-c.didClose: } } @@ -263,8 +290,8 @@ func (c *Client) CallContext(ctx context.Context, result interface{}, method str return err } - // dispatch has accepted the request and will close the channel it when it quits. - switch resp, err := op.wait(ctx); { + // dispatch has accepted the request and will close the channel when it quits. + switch resp, err := op.wait(ctx, c); { case err != nil: return err case resp.Error != nil: @@ -322,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 } @@ -349,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...) @@ -399,53 +442,48 @@ 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 // subscription notifications. return ctx.Err() - case <-c.didQuit: + case <-c.closing: 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) + err := c.writeConn.Write(ctx, msg) if err != nil { c.writeConn = nil } @@ -453,16 +491,25 @@ 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 { case c.reconnected <- newconn: c.writeConn = newconn return nil - case <-c.didQuit: + case <-c.didClose: newconn.Close() return ErrClientQuit } @@ -471,321 +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.didQuit) defer func() { - c.closeRequestOps(ErrClientQuit) - conn.Close() + close(c.closing) 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(fmt.Sprintf("<-readErr: %v", 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(fmt.Sprintf("<-reconnected: (reading=%t) %v", reading, 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(fmt.Sprint("dropping non-subscription message: ", 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(fmt.Sprint("dropping invalid subscription message: ", 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(fmt.Sprintf("unsolicited response %v", 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/rpc/client_example_test.go b/rpc/client_example_test.go index 8276a9eadd..3bb8717b80 100644 --- a/rpc/client_example_test.go +++ b/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", {}) @@ -66,7 +66,7 @@ func subscribeBlocks(client *rpc.Client, subch chan Block) { defer cancel() // Subscribe to new blocks. - sub, err := client.EthSubscribe(ctx, subch, "newBlocks") + sub, err := client.EthSubscribe(ctx, subch, "newHeads") if err != nil { fmt.Println("subscribe error:", err) return diff --git a/rpc/client_test.go b/rpc/client_test.go index 4f354d389e..80fe29f824 100644 --- a/rpc/client_test.go +++ b/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,20 +296,43 @@ 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) { + server := newTestServer() + defer server.Stop() + + for i := 0; i < 20; i++ { + client := DialInProc(server) + nc := make(chan int) + sub, err := client.Subscribe(context.Background(), "nftest", nc, "someSubscription", 3, 1) + if err != nil { + t.Fatal(err) + } + go client.Close() + go sub.Unsubscribe() + select { + case <-sub.Err(): + case <-time.After(5 * time.Second): + t.Fatal("subscription not closed within timeout") + } } } // 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) { @@ -338,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) } @@ -360,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) @@ -375,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) @@ -392,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) }() } @@ -421,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. @@ -442,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()) @@ -469,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) @@ -479,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/rpc/doc.go b/rpc/doc.go index 14b3780ade..e5840c32d3 100644 --- a/rpc/doc.go +++ b/rpc/doc.go @@ -15,50 +15,56 @@ // 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 { return a + b } - func (s *CalculatorService Div(a, b int) (int, error) { + func (s *CalculatorService) Div(a, b int) (int, error) { if b == 0 { return 0, errors.New("divide by zero") } @@ -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 an 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/rpc/endpoints.go b/rpc/endpoints.go new file mode 100644 index 0000000000..8ca6d4eb0c --- /dev/null +++ b/rpc/endpoints.go @@ -0,0 +1,102 @@ +// 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 ( + "net" + + "github.com/ethereum/go-ethereum/log" +) + +// StartHTTPEndpoint starts the HTTP RPC endpoint, configured with cors/vhosts/modules +func StartHTTPEndpoint(endpoint string, apis []API, modules []string, cors []string, vhosts []string, timeouts HTTPTimeouts) (net.Listener, *Server, error) { + // Generate the whitelist based on the allowed modules + whitelist := make(map[string]bool) + for _, module := range modules { + whitelist[module] = true + } + // Register all the APIs exposed by the services + handler := NewServer() + for _, api := range apis { + if whitelist[api.Namespace] || (len(whitelist) == 0 && api.Public) { + if err := handler.RegisterName(api.Namespace, api.Service); err != nil { + return nil, nil, err + } + log.Debug("HTTP registered", "namespace", api.Namespace) + } + } + // All APIs registered, start the HTTP listener + var ( + listener net.Listener + err error + ) + if listener, err = net.Listen("tcp", endpoint); err != nil { + return nil, nil, err + } + go NewHTTPServer(cors, vhosts, timeouts, handler).Serve(listener) + return listener, handler, err +} + +// StartWSEndpoint starts a websocket endpoint +func StartWSEndpoint(endpoint string, apis []API, modules []string, wsOrigins []string, exposeAll bool) (net.Listener, *Server, error) { + + // Generate the whitelist based on the allowed modules + whitelist := make(map[string]bool) + for _, module := range modules { + whitelist[module] = true + } + // Register all the APIs exposed by the services + handler := NewServer() + for _, api := range apis { + if exposeAll || whitelist[api.Namespace] || (len(whitelist) == 0 && api.Public) { + if err := handler.RegisterName(api.Namespace, api.Service); err != nil { + return nil, nil, err + } + log.Debug("WebSocket registered", "service", api.Service, "namespace", api.Namespace) + } + } + // All APIs registered, start the HTTP listener + var ( + listener net.Listener + err error + ) + if listener, err = net.Listen("tcp", endpoint); err != nil { + return nil, nil, err + } + go NewWSServer(wsOrigins, handler).Serve(listener) + return listener, handler, err + +} + +// StartIPCEndpoint starts an IPC endpoint. +func StartIPCEndpoint(ipcEndpoint string, apis []API) (net.Listener, *Server, error) { + // Register all the APIs exposed by the services. + handler := NewServer() + for _, api := range apis { + if err := handler.RegisterName(api.Namespace, api.Service); err != nil { + return nil, nil, err + } + log.Debug("IPC registered", "namespace", api.Namespace) + } + // All APIs registered, start the IPC listener. + listener, err := ipcListen(ipcEndpoint) + if err != nil { + return nil, nil, err + } + go handler.ServeListener(listener) + return listener, handler, nil +} diff --git a/rpc/errors.go b/rpc/errors.go index 9cf9dc60c2..c3aa826cc8 100644 --- a/rpc/errors.go +++ b/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/rpc/handler.go b/rpc/handler.go new file mode 100644 index 0000000000..bc03ef25f4 --- /dev/null +++ b/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/rpc/http.go b/rpc/http.go index 6717899b53..518b3b874f 100644 --- a/rpc/http.go +++ b/rpc/http.go @@ -27,42 +27,81 @@ import ( "mime" "net" "net/http" + "strings" "sync" "time" + "github.com/ethereum/go-ethereum/log" "github.com/rs/cors" ) const ( - contentType = "application/json" - maxHTTPRequestContentLength = 1024 * 128 + 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. +type HTTPTimeouts struct { + // ReadTimeout is the maximum duration for reading the entire + // request, including the body. + // + // Because ReadTimeout does not let Handlers make per-request + // decisions on each request body's acceptable deadline or + // upload rate, most users will prefer to use + // ReadHeaderTimeout. It is valid to use them both. + ReadTimeout time.Duration + + // WriteTimeout is the maximum duration before timing out + // writes of the response. It is reset whenever a new + // request's header is read. Like ReadTimeout, it does not + // let Handlers make decisions on a per-request basis. + WriteTimeout time.Duration + + // IdleTimeout is the maximum amount of time to wait for the + // next request when keep-alives are enabled. If IdleTimeout + // is zero, the value of ReadTimeout is used. If both are + // zero, ReadHeaderTimeout is used. + IdleTimeout time.Duration +} + +// DefaultHTTPTimeouts represents the default timeout values used if further +// configuration is not provided. +var DefaultHTTPTimeouts = HTTPTimeouts{ + ReadTimeout: 30 * time.Second, + WriteTimeout: 30 * time.Second, + IdleTimeout: 120 * time.Second, } // DialHTTPWithClient creates a new RPC client that connects to an RPC server over HTTP @@ -76,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 }) } @@ -89,10 +128,19 @@ func DialHTTP(endpoint string) (*Client, error) { func (c *Client) sendHTTP(ctx context.Context, op *requestOp, msg interface{}) error { hc := c.writeConn.(*httpConn) respBody, err := hc.doRequest(ctx, msg) + if respBody != nil { + defer respBody.Close() + } + if err != nil { + if respBody != nil { + buf := new(bytes.Buffer) + if _, err2 := buf.ReadFrom(respBody); err2 == nil { + return fmt.Errorf("%v %v", err, buf.String()) + } + } return err } - defer respBody.Close() var respmsg jsonrpcMessage if err := json.NewDecoder(respBody).Decode(&respmsg); err != nil { return err @@ -131,29 +179,68 @@ func (hc *httpConn) doRequest(ctx context.Context, msg interface{}) (io.ReadClos if err != nil { return nil, err } + if resp.StatusCode < 200 || resp.StatusCode >= 300 { + return resp.Body, errors.New(resp.Status) + } 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, srv *Server) *http.Server { - return &http.Server{Handler: newCorsHandler(srv, cors)} +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) + + // Make sure timeout values are meaningful + if timeouts.ReadTimeout < time.Second { + log.Warn("Sanitizing invalid HTTP read timeout", "provided", timeouts.ReadTimeout, "updated", DefaultHTTPTimeouts.ReadTimeout) + timeouts.ReadTimeout = DefaultHTTPTimeouts.ReadTimeout + } + if timeouts.WriteTimeout < time.Second { + log.Warn("Sanitizing invalid HTTP write timeout", "provided", timeouts.WriteTimeout, "updated", DefaultHTTPTimeouts.WriteTimeout) + timeouts.WriteTimeout = DefaultHTTPTimeouts.WriteTimeout + } + if timeouts.IdleTimeout < time.Second { + log.Warn("Sanitizing invalid HTTP idle timeout", "provided", timeouts.IdleTimeout, "updated", DefaultHTTPTimeouts.IdleTimeout) + timeouts.IdleTimeout = DefaultHTTPTimeouts.IdleTimeout + } + // Bundle and start the HTTP server + return &http.Server{ + Handler: handler, + ReadTimeout: timeouts.ReadTimeout, + WriteTimeout: timeouts.WriteTimeout, + IdleTimeout: timeouts.IdleTimeout, + } } // 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 @@ -165,11 +252,21 @@ func (srv *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { // All checks passed, create a codec that reads direct from the request body // untilEOF and writes the response to w and order the server to process a // single request. - codec := NewJSONCodec(&httpReadWriteNopCloser{r.Body, w}) - defer codec.Close() + ctx := r.Context() + ctx = context.WithValue(ctx, "remote", r.RemoteAddr) + ctx = context.WithValue(ctx, "scheme", r.Proto) + ctx = context.WithValue(ctx, "local", r.Host) + if ua := r.Header.Get("User-Agent"); ua != "" { + ctx = context.WithValue(ctx, "User-Agent", ua) + } + if origin := r.Header.Get("Origin"); origin != "" { + ctx = context.WithValue(ctx, "Origin", origin) + } w.Header().Set("content-type", contentType) - srv.ServeSingleRequest(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 @@ -178,24 +275,32 @@ func validateRequest(r *http.Request) (int, error) { if r.Method == http.MethodPut || r.Method == http.MethodDelete { return http.StatusMethodNotAllowed, errors.New("method not allowed") } - if r.ContentLength > maxHTTPRequestContentLength { - err := fmt.Errorf("content length too large (%d>%d)", r.ContentLength, maxHTTPRequestContentLength) + if r.ContentLength > maxRequestContentLength { + 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 } - c := cors.New(cors.Options{ AllowedOrigins: allowedOrigins, AllowedMethods: []string{http.MethodPost, http.MethodGet}, @@ -204,3 +309,50 @@ func newCorsHandler(srv *Server, allowedOrigins []string) http.Handler { }) return c.Handler(srv) } + +// virtualHostHandler is a handler which validates the Host-header of incoming requests. +// The virtualHostHandler can prevent DNS rebinding attacks, which do not utilize CORS-headers, +// since they do in-domain requests against the RPC api. Instead, we can see on the Host-header +// which domain was used, and validate that against a whitelist. +type virtualHostHandler struct { + vhosts map[string]struct{} + next http.Handler +} + +// ServeHTTP serves JSON-RPC requests over HTTP, implements http.Handler +func (h *virtualHostHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + // if r.Host is not set, we can continue serving since a browser would set the Host header + if r.Host == "" { + h.next.ServeHTTP(w, r) + return + } + host, _, err := net.SplitHostPort(r.Host) + if err != nil { + // Either invalid (too many colons) or no port specified + host = r.Host + } + if ipAddr := net.ParseIP(host); ipAddr != nil { + // It's an IP address, we can serve that + h.next.ServeHTTP(w, r) + return + + } + // Not an ip address, but a hostname. Need to validate + if _, exist := h.vhosts["*"]; exist { + h.next.ServeHTTP(w, r) + return + } + if _, exist := h.vhosts[host]; exist { + h.next.ServeHTTP(w, r) + return + } + http.Error(w, "invalid host specified", http.StatusForbidden) +} + +func newVHostHandler(vhosts []string, next http.Handler) http.Handler { + vhostMap := make(map[string]struct{}) + for _, allowedHost := range vhosts { + vhostMap[strings.ToLower(allowedHost)] = struct{}{} + } + return &virtualHostHandler{vhostMap, next} +} diff --git a/rpc/http_test.go b/rpc/http_test.go index aed84f6835..b3f694d8af 100644 --- a/rpc/http_test.go +++ b/rpc/http_test.go @@ -32,7 +32,7 @@ func TestHTTPErrorResponseWithPut(t *testing.T) { } func TestHTTPErrorResponseWithMaxContentLength(t *testing.T) { - body := make([]rune, maxHTTPRequestContentLength+1) + body := make([]rune, maxRequestContentLength+1) testHTTPErrorResponse(t, http.MethodPost, contentType, string(body), http.StatusRequestEntityTooLarge) } diff --git a/rpc/inproc.go b/rpc/inproc.go index 595a7ca651..c4456cfc4b 100644 --- a/rpc/inproc.go +++ b/rpc/inproc.go @@ -21,13 +21,13 @@ import ( "net" ) -// NewInProcClient attaches an in-process connection to the given RPC server. +// 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/rpc/ipc.go b/rpc/ipc.go index 8de18a56fe..ad8ce03098 100644 --- a/rpc/ipc.go +++ b/rpc/ipc.go @@ -18,27 +18,24 @@ package rpc import ( "context" - "fmt" "net" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/p2p/netutil" ) -// CreateIPCListener creates an listener, on Unix platforms this is a unix socket, on -// Windows this is a named pipe -func CreateIPCListener(endpoint string) (net.Listener, error) { - return ipcListen(endpoint) -} - // 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 err != nil { + if netutil.IsTemporaryError(err) { + log.Warn("RPC accept error", "err", err) + continue + } else if err != nil { return err } - log.Trace(fmt.Sprint("accepted conn", conn.RemoteAddr())) - go srv.ServeCodec(NewJSONCodec(conn), OptionMethodInvocation|OptionSubscriptions) + log.Trace("Accepted RPC connection", "conn", conn.RemoteAddr()) + go s.ServeCodec(NewJSONCodec(conn), OptionMethodInvocation|OptionSubscriptions) } } @@ -49,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/crypto/randentropy/rand_entropy.go b/rpc/ipc_js.go similarity index 63% rename from crypto/randentropy/rand_entropy.go rename to rpc/ipc_js.go index 539d3ac894..eceef050e7 100644 --- a/crypto/randentropy/rand_entropy.go +++ b/rpc/ipc_js.go @@ -14,29 +14,24 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package randentropy +// +build js + +package rpc import ( - crand "crypto/rand" - "io" + "context" + "errors" + "net" ) -var Reader io.Reader = &randEntropy{} +var errNotSupported = errors.New("rpc: not supported") -type randEntropy struct { +// ipcListen will create a named pipe on the given endpoint. +func ipcListen(endpoint string) (net.Listener, error) { + return nil, errNotSupported } -func (*randEntropy) Read(bytes []byte) (n int, err error) { - readBytes := GetEntropyCSPRNG(len(bytes)) - copy(bytes, readBytes) - return len(bytes), nil -} - -func GetEntropyCSPRNG(n int) []byte { - mainBuff := make([]byte, n) - _, err := io.ReadFull(crand.Reader, mainBuff) - if err != nil { - panic("reading from crypto/rand failed: " + err.Error()) - } - return mainBuff +// newIPCConnection will connect to a named pipe with the given endpoint as name. +func newIPCConnection(ctx context.Context, endpoint string) (net.Conn, error) { + return nil, errNotSupported } diff --git a/rpc/ipc_unix.go b/rpc/ipc_unix.go index 0851ea61e1..707b47fd77 100644 --- a/rpc/ipc_unix.go +++ b/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/rpc/json.go b/rpc/json.go index 2e7fd599e2..b2e8c7bab3 100644 --- a/rpc/json.go +++ b/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 d - d *json.Decoder // decodes incoming requests - encMu sync.Mutex // guards e - e *json.Encoder // encodes responses - rw io.ReadWriteCloser // connection -} - func (err *jsonError) Error() string { if err.Message == "" { return fmt.Sprintf("json-rpc error %d", err.Code) @@ -96,16 +135,126 @@ func (err *jsonError) ErrorCode() int { return err.Code } -// NewJSONCodec creates a new RPC server codec with support for JSON-RPC 2.0 -func NewJSONCodec(rwc io.ReadWriteCloser) ServerCodec { - d := json.NewDecoder(rwc) - d.UseNumber() - return &jsonCodec{closed: make(chan interface{}), d: d, e: json.NewEncoder(rwc), rw: rwc} +// 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(conn Conn, encode, decode func(v interface{}) error) ServerCodec { + codec := &jsonCodec{ + closed: make(chan interface{}), + encode: encode, + decode: decode, + 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(conn Conn) ServerCodec { + enc := json.NewEncoder(conn) + dec := json.NewDecoder(conn) + dec.UseNumber() + return NewCodec(conn, enc.Encode, dec.Decode) +} + +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 @@ -115,241 +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.d.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{} { - if isHexNum(reflect.TypeOf(reply)) { - return &jsonSuccessResponse{Version: jsonrpcVersion, Id: id, Result: fmt.Sprintf(`%#x`, 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()) } - return &jsonSuccessResponse{Version: jsonrpcVersion, Id: id, Result: reply} + // 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{} { - if isHexNum(reflect.TypeOf(event)) { - return &jsonNotification{Version: jsonrpcVersion, Method: namespace + notificationMethodSuffix, - Params: jsonSubscription{Subscription: subid, Result: fmt.Sprintf(`%#x`, event)}} +// 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") } - - 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.e.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 + v, _ := dec.Token() + method, ok := v.(string) + if !ok { + return "", errors.New("expected subscription name as first argument") + } + return method, nil } diff --git a/rpc/json_test.go b/rpc/json_test.go deleted file mode 100644 index 5048d2f7a0..0000000000 --- a/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/rpc/server.go b/rpc/server.go index 30c288349e..5a92847f20 100644 --- a/rpc/server.go +++ b/rpc/server.go @@ -18,20 +18,18 @@ package rpc import ( "context" - "fmt" - "reflect" - "runtime" - "strings" - "sync" + "io" "sync/atomic" + mapset "github.com/deckarep/golang-set" "github.com/ethereum/go-ethereum/log" - "gopkg.in/fatih/set.v0" ) 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: set.New(), - 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,380 +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) - - // already a previous service register under given sname, merge methods/subscriptions - if regsvc, present := s.services[name]; present { - if len(methods) == 0 && len(subscriptions) == 0 { - return fmt.Errorf("Service %T doesn't have any suitable methods/subscriptions to expose", rcvr) - } - 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 - - if len(svc.callbacks) == 0 && len(svc.subscriptions) == 0 { - return fmt.Errorf("Service %T doesn't have any suitable methods/subscriptions to expose", rcvr) - } - - 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(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()) - defer cancel() - - // if the codec supports notification include a notifier that callbacks can use - // to send notification to clients. It is thight 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(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(codec ServerCodec, options CodecOption) { - s.serveRequest(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.method, 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/rpc/server_test.go b/rpc/server_test.go index 90d62f26d8..39099546bb 100644 --- a/rpc/server_test.go +++ b/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/rpc/service.go b/rpc/service.go new file mode 100644 index 0000000000..a9426c6b0e --- /dev/null +++ b/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/rpc/stdio.go b/rpc/stdio.go new file mode 100644 index 0000000000..d5dc066c99 --- /dev/null +++ b/rpc/stdio.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 rpc + +import ( + "context" + "errors" + "io" + "net" + "os" + "time" +) + +// DialStdIO creates a client on stdin/stdout. +func DialStdIO(ctx context.Context) (*Client, error) { + 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 { + in io.Reader + out io.Writer +} + +func (io stdioConn) Read(b []byte) (n int, err error) { + return io.in.Read(b) +} + +func (io stdioConn) Write(b []byte) (n int, err error) { + return io.out.Write(b) +} + +func (io stdioConn) Close() error { + return nil +} + +func (io stdioConn) RemoteAddr() string { + return "/dev/stdin" +} + +func (io stdioConn) SetWriteDeadline(t time.Time) error { + return &net.OpError{Op: "set", Net: "stdio", Source: nil, Addr: nil, Err: errors.New("deadline not supported")} +} diff --git a/rpc/subscription.go b/rpc/subscription.go index 6ce7befa1d..c1e869b8a3 100644 --- a/rpc/subscription.go +++ b/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,91 +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.RWMutex // guards active and inactive maps - active map[ID]*Subscription - inactive map[ID]*Subscription +// 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), +// 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 +} + +// 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 } } -// 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 +func (sub *ClientSubscription) start() { + sub.quitWithError(sub.forward()) } -// 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 -} +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) + } -// 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.RLock() - defer n.subMu.RUnlock() - - sub, active := n.active[id] - if active { - notification := n.codec.CreateNotification(string(id), sub.namespace, data) - if err := n.codec.Write(notification); err != nil { - n.codec.Close() - return err + 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()) } } - return nil } -// Closed returns a channel that is closed when the RPC connection is closed. -func (n *Notifier) Closed() <-chan interface{} { - return n.codec.Closed() +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 } -// 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) - } +func (sub *ClientSubscription) requestUnsubscribe() error { + var result interface{} + return sub.client.Call(&result, sub.namespace+unsubscribeMethodSuffix, sub.subid) } diff --git a/rpc/subscription_test.go b/rpc/subscription_test.go index 0ba177e63b..eba192450d 100644 --- a/rpc/subscription_test.go +++ b/rpc/subscription_test.go @@ -17,313 +17,189 @@ package rpc import ( - "context" "encoding/json" "fmt" "net" - "sync" + "strings" "testing" "time" ) -type NotificationTestService struct { - mu sync.Mutex - unsubscribed bool +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) + } - gotHangSubscriptionReq chan struct{} - unblockHangSubscription chan struct{} -} + 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) Echo(i int) int { - return i -} - -func (s *NotificationTestService) wasUnsubCallbackCalled() bool { - s.mu.Lock() - defer s.mu.Unlock() - return s.unsubscribed -} - -func (s *NotificationTestService) Unsubscribe(subid string) { - s.mu.Lock() - s.unsubscribed = true - s.mu.Unlock() -} - -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. - time.Sleep(5 * time.Second) - 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(): - s.mu.Lock() - s.unsubscribed = true - s.mu.Unlock() - case <-subscription.Err(): - s.mu.Lock() - s.unsubscribed = true - s.mu.Unlock() - } - }() - - 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{} - - 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 - time.Sleep(1 * time.Second) - - if !service.wasUnsubCallbackCalled() { - t.Error("unsubscribe callback not called after closing connection") } } -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"} + namespaces = []string{"eth", "shh", "bzz"} + service = ¬ificationTestService{} + subCount = len(namespaces) + notificationCount = 3 + server = NewServer() - service = NotificationTestService{} 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) + out = json.NewEncoder(clientConn) + in = json.NewDecoder(clientConn) + 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 - n := 3 for i, namespace := range namespaces { request := map[string]interface{}{ "id": i, "method": fmt.Sprintf("%s_subscribe", namespace), "version": "2.0", - "params": []interface{}{"someSubscription", n, i}, + "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", n, 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, 2*len(namespaces)) - count := make(map[string]int, 2*len(namespaces)) - - for { - done := true - for id := range count { - if count, found := count[id]; !found || count < (2*n) { + subids := make(map[string]string, subCount) + count := make(map[string]int, subCount) + allReceived := func() bool { + done := len(count) == subCount + for _, c := range count { + if c < notificationCount { done = false } } - - if done && len(count) == len(namespaces) { - break - } - + return done + } + for !allReceived() { select { + case confirmation := <-successes: // subscription created + subids[namespaces[confirmation.reqid]] = string(confirmation.subid) + case notification := <-notifications: + count[notification.ID]++ case err := <-errors: t.Fatal(err) - case suc := <-successes: // subscription created - subids[namespaces[int(suc.Id.(float64))]] = suc.Result.(string) - case failure := <-failures: - t.Errorf("received error: %v", failure.Error) - case notification := <-notifications: - if cnt, found := count[notification.Params.Subscription]; found { - count[notification.Params.Subscription] = cnt + 1 - } else { - count[notification.Params.Subscription] = 1 - } case <-timeout: for _, namespace := range namespaces { subid, found := subids[namespace] if !found { - t.Errorf("Subscription for '%s' not created", namespace) + t.Errorf("subscription for %q not created", namespace) continue } - if count, found := count[subid]; !found || count < n { - t.Errorf("Didn't receive all notifications (%d<%d) in time for namespace '%s'", count, n, namespace) + if count, found := count[subid]; !found || count < notificationCount { + t.Errorf("didn't receive all notifications (%d<%d) in time for namespace %q", count, notificationCount, namespace) } } + t.Fatal("timed out") + } + } +} + +// 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/rpc/testdata/invalid-badid.js b/rpc/testdata/invalid-badid.js new file mode 100644 index 0000000000..2202b8ccd2 --- /dev/null +++ b/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/rpc/testdata/invalid-batch.js b/rpc/testdata/invalid-batch.js new file mode 100644 index 0000000000..f470574fb5 --- /dev/null +++ b/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/rpc/testdata/invalid-idonly.js b/rpc/testdata/invalid-idonly.js new file mode 100644 index 0000000000..79997bee30 --- /dev/null +++ b/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/rpc/testdata/invalid-nonobj.js b/rpc/testdata/invalid-nonobj.js new file mode 100644 index 0000000000..4b9f4d994c --- /dev/null +++ b/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/rpc/testdata/invalid-syntax.json b/rpc/testdata/invalid-syntax.json new file mode 100644 index 0000000000..b194299603 --- /dev/null +++ b/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/rpc/testdata/reqresp-batch.js b/rpc/testdata/reqresp-batch.js new file mode 100644 index 0000000000..977af76630 --- /dev/null +++ b/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/rpc/testdata/reqresp-echo.js b/rpc/testdata/reqresp-echo.js new file mode 100644 index 0000000000..7a9e90321c --- /dev/null +++ b/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/rpc/testdata/reqresp-namedparam.js b/rpc/testdata/reqresp-namedparam.js new file mode 100644 index 0000000000..9a9372b0a7 --- /dev/null +++ b/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/rpc/testdata/reqresp-noargsrets.js b/rpc/testdata/reqresp-noargsrets.js new file mode 100644 index 0000000000..e61cc708ba --- /dev/null +++ b/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/rpc/testdata/reqresp-nomethod.js b/rpc/testdata/reqresp-nomethod.js new file mode 100644 index 0000000000..58ea6f3079 --- /dev/null +++ b/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/rpc/testdata/reqresp-noparam.js b/rpc/testdata/reqresp-noparam.js new file mode 100644 index 0000000000..2edf486d9f --- /dev/null +++ b/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/rpc/testdata/reqresp-paramsnull.js b/rpc/testdata/reqresp-paramsnull.js new file mode 100644 index 0000000000..8a01bae1bb --- /dev/null +++ b/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/rpc/testdata/revcall.js b/rpc/testdata/revcall.js new file mode 100644 index 0000000000..695d9858f8 --- /dev/null +++ b/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/rpc/testdata/revcall2.js b/rpc/testdata/revcall2.js new file mode 100644 index 0000000000..acab46551e --- /dev/null +++ b/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/rpc/testdata/subscription.js b/rpc/testdata/subscription.js new file mode 100644 index 0000000000..9f10073010 --- /dev/null +++ b/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/rpc/testservice_test.go b/rpc/testservice_test.go new file mode 100644 index 0000000000..470870bacf --- /dev/null +++ b/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/rpc/types.go b/rpc/types.go index f2375604ed..f31f09a774 100644 --- a/rpc/types.go +++ b/rpc/types.go @@ -17,14 +17,12 @@ package rpc import ( + "context" "fmt" "math" - "reflect" "strings" - "sync" "github.com/ethereum/go-ethereum/common/hexutil" - "gopkg.in/fatih/set.v0" ) // API describes the set of methods offered over the RPC interface @@ -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 *set.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/rpc/types_test.go b/rpc/types_test.go index 30cef9b22e..68b6d3c54f 100644 --- a/rpc/types_test.go +++ b/rpc/types_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 The go-ethereum Authors +// 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 diff --git a/rpc/utils.go b/rpc/utils.go deleted file mode 100644 index 9315cab591..0000000000 --- a/rpc/utils.go +++ /dev/null @@ -1,241 +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/big" - "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) -} - -var bigIntType = reflect.TypeOf((*big.Int)(nil)).Elem() - -// Indication if this type should be serialized in hex -func isHexNum(t reflect.Type) bool { - if t == nil { - return false - } - for t.Kind() == reflect.Ptr { - t = t.Elem() - } - - return t == bigIntType -} - -// 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/rpc/websocket.go b/rpc/websocket.go index 4214fc86a0..c5383667d9 100644 --- a/rpc/websocket.go +++ b/rpc/websocket.go @@ -17,8 +17,12 @@ package rpc import ( + "bytes" "context" "crypto/tls" + "encoding/base64" + "encoding/json" + "errors" "fmt" "net" "net/http" @@ -27,24 +31,65 @@ import ( "strings" "time" + mapset "github.com/deckarep/golang-set" "github.com/ethereum/go-ethereum/log" "golang.org/x/net/websocket" - "gopkg.in/fatih/set.v0" ) +// websocketJSONCodec is a custom JSON codec with payload size enforcement and +// special number parsing. +var websocketJSONCodec = websocket.Codec{ + // Marshal is the stock JSON marshaller used by the websocket library too. + Marshal: func(v interface{}) ([]byte, byte, error) { + msg, err := json.Marshal(v) + return msg, websocket.TextFrame, err + }, + // Unmarshal is a specialized unmarshaller to properly convert numbers. + Unmarshal: func(msg []byte, payloadType byte, v interface{}) error { + dec := json.NewDecoder(bytes.NewReader(msg)) + dec.UseNumber() + + return dec.Decode(v) + }, +} + // WebsocketHandler returns a handler that serves JSON-RPC to WebSocket connections. // // 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) { - srv.ServeCodec(NewJSONCodec(conn), 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 @@ -56,7 +101,7 @@ func NewWSServer(allowedOrigins []string, srv *Server) *http.Server { // websocket upgrade process. When a '*' is specified as an allowed origins all // connections are accepted. func wsHandshakeValidator(allowedOrigins []string) func(*websocket.Config, *http.Request) error { - origins := set.New() + origins := mapset.NewSet() allowAllOrigins := false for _, origin := range allowedOrigins { @@ -69,33 +114,36 @@ func wsHandshakeValidator(allowedOrigins []string) func(*websocket.Config, *http } // allow localhost if no allowedOrigins are specified. - if len(origins.List()) == 0 { + if len(origins.ToSlice()) == 0 { origins.Add("http://localhost") if hostname, err := os.Hostname(); err == nil { origins.Add("http://" + strings.ToLower(hostname)) } } - log.Debug(fmt.Sprintf("Allowed origin(s) for WS RPC interface %v\n", origins.List())) + log.Debug(fmt.Sprintf("Allowed origin(s) for WS RPC interface %v", origins.ToSlice())) f := func(cfg *websocket.Config, req *http.Request) error { - origin := strings.ToLower(req.Header.Get("Origin")) - if allowAllOrigins || origins.Has(origin) { + // 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 } - log.Warn(fmt.Sprintf("origin '%s' not allowed on WS-RPC interface\n", origin)) - return fmt.Errorf("origin %s not allowed", origin) + // Verify origin against whitelist. + origin := strings.ToLower(req.Header.Get("Origin")) + if allowAllOrigins || origins.Contains(origin) { + return nil + } + log.Warn("Rejected WebSocket connection", "origin", origin) + return errors.New("origin not allowed") } return f } -// DialWebsocket creates a new RPC client that communicates with a JSON-RPC server -// that is listening on the given endpoint. -// -// The context is used for the initial connection establishment. It does not -// affect subsequent interactions with the client. -func DialWebsocket(ctx context.Context, endpoint, origin string) (*Client, error) { +func wsGetConfig(endpoint, origin string) (*websocket.Config, error) { if origin == "" { var err error if origin, err = os.Hostname(); err != nil { @@ -112,8 +160,31 @@ 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) + if config.Location.User != nil { + b64auth := base64.StdEncoding.EncodeToString([]byte(config.Location.User.String())) + config.Header.Add("Authorization", "Basic "+b64auth) + config.Location.User = nil + } + return config, nil +} + +// DialWebsocket creates a new RPC client that communicates with a JSON-RPC server +// that is listening on the given endpoint. +// +// The context is used for the initial connection establishment. It does not +// affect subsequent interactions with the client. +func DialWebsocket(ctx context.Context, endpoint, origin string) (*Client, error) { + config, err := wsGetConfig(endpoint, origin) + if err != nil { + return nil, err + } + + 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/rpc/websocket_test.go b/rpc/websocket_test.go new file mode 100644 index 0000000000..5bf3780d62 --- /dev/null +++ b/rpc/websocket_test.go @@ -0,0 +1,54 @@ +// 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 rpc + +import "testing" + +func TestWSGetConfigNoAuth(t *testing.T) { + config, err := wsGetConfig("ws://example.com:1234", "") + if err != nil { + t.Logf("wsGetConfig failed: %s", err) + t.Fail() + return + } + if config.Location.User != nil { + t.Log("User should have been stripped from the URL") + t.Fail() + } + if config.Location.Hostname() != "example.com" || + config.Location.Port() != "1234" || config.Location.Scheme != "ws" { + t.Logf("Unexpected URL: %s", config.Location) + t.Fail() + } +} + +func TestWSGetConfigWithBasicAuth(t *testing.T) { + config, err := wsGetConfig("wss://testuser:test-PASS_01@example.com:1234", "") + if err != nil { + t.Logf("wsGetConfig failed: %s", err) + t.Fail() + return + } + if config.Location.User != nil { + t.Log("User should have been stripped from the URL") + t.Fail() + } + if config.Header.Get("Authorization") != "Basic dGVzdHVzZXI6dGVzdC1QQVNTXzAx" { + t.Log("Basic auth header is incorrect") + t.Fail() + } +} diff --git a/signer/core/abihelper.go b/signer/core/abihelper.go new file mode 100644 index 0000000000..88c1da0330 --- /dev/null +++ b/signer/core/abihelper.go @@ -0,0 +1,260 @@ +// 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" + "encoding/json" + "fmt" + "io/ioutil" + "os" + "regexp" + "strings" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" +) + +type decodedArgument struct { + soltype abi.Argument + value interface{} +} +type decodedCallData struct { + signature string + name string + inputs []decodedArgument +} + +// String implements stringer interface, tries to use the underlying value-type +func (arg decodedArgument) String() string { + var value string + switch val := arg.value.(type) { + case fmt.Stringer: + value = val.String() + default: + value = fmt.Sprintf("%v", val) + } + return fmt.Sprintf("%v: %v", arg.soltype.Type.String(), value) +} + +// String implements stringer interface for decodedCallData +func (cd decodedCallData) String() string { + args := make([]string, len(cd.inputs)) + for i, arg := range cd.inputs { + args[i] = arg.String() + } + return fmt.Sprintf("%s(%s)", cd.name, strings.Join(args, ",")) +} + +// parseCallData matches the provided call data against the abi definition, +// and returns a struct containing the actual go-typed values +func parseCallData(calldata []byte, abidata string) (*decodedCallData, error) { + + if len(calldata) < 4 { + return nil, fmt.Errorf("Invalid ABI-data, incomplete method signature of (%d bytes)", len(calldata)) + } + + sigdata, argdata := calldata[:4], calldata[4:] + if len(argdata)%32 != 0 { + return nil, fmt.Errorf("Not ABI-encoded data; length should be a multiple of 32 (was %d)", len(argdata)) + } + + abispec, err := abi.JSON(strings.NewReader(abidata)) + if err != nil { + return nil, fmt.Errorf("Failed parsing JSON ABI: %v, abidata: %v", err, abidata) + } + + method, err := abispec.MethodById(sigdata) + if err != nil { + return nil, err + } + + v, err := method.Inputs.UnpackValues(argdata) + if err != nil { + return nil, err + } + + decoded := decodedCallData{signature: method.Sig(), name: method.Name} + + for n, argument := range method.Inputs { + if err != nil { + return nil, fmt.Errorf("Failed to decode argument %d (signature %v): %v", n, method.Sig(), err) + } + decodedArg := decodedArgument{ + soltype: argument, + value: v[n], + } + decoded.inputs = append(decoded.inputs, decodedArg) + } + + // We're finished decoding the data. At this point, we encode the decoded data to see if it matches with the + // original data. If we didn't do that, it would e.g. be possible to stuff extra data into the arguments, which + // is not detected by merely decoding the data. + + var ( + encoded []byte + ) + encoded, err = method.Inputs.PackValues(v) + + if err != nil { + return nil, err + } + + if !bytes.Equal(encoded, argdata) { + was := common.Bytes2Hex(encoded) + exp := common.Bytes2Hex(argdata) + return nil, fmt.Errorf("WARNING: Supplied data is stuffed with extra data. \nWant %s\nHave %s\nfor method %v", exp, was, method.Sig()) + } + return &decoded, nil +} + +// MethodSelectorToAbi converts a method selector into an ABI struct. The returned data is a valid json string +// which can be consumed by the standard abi package. +func MethodSelectorToAbi(selector string) ([]byte, error) { + + re := regexp.MustCompile(`^([^\)]+)\(([a-z0-9,\[\]]*)\)`) + + type fakeArg struct { + Type string `json:"type"` + } + type fakeABI struct { + Name string `json:"name"` + Type string `json:"type"` + Inputs []fakeArg `json:"inputs"` + } + groups := re.FindStringSubmatch(selector) + if len(groups) != 3 { + return nil, fmt.Errorf("Did not match: %v (%v matches)", selector, len(groups)) + } + name := groups[1] + args := groups[2] + arguments := make([]fakeArg, 0) + if len(args) > 0 { + for _, arg := range strings.Split(args, ",") { + arguments = append(arguments, fakeArg{arg}) + } + } + abicheat := fakeABI{ + name, "function", arguments, + } + return json.Marshal([]fakeABI{abicheat}) + +} + +type AbiDb struct { + db map[string]string + customdb map[string]string + customdbPath string +} + +// NewEmptyAbiDB exists for test purposes +func NewEmptyAbiDB() (*AbiDb, error) { + return &AbiDb{make(map[string]string), make(map[string]string), ""}, nil +} + +// NewAbiDBFromFile loads signature database from file, and +// errors if the file is not valid json. Does no other validation of contents +func NewAbiDBFromFile(path string) (*AbiDb, error) { + raw, err := ioutil.ReadFile(path) + if err != nil { + return nil, err + } + db, err := NewEmptyAbiDB() + if err != nil { + return nil, err + } + if err := json.Unmarshal(raw, &db.db); err != nil { + return nil, err + } + return db, nil +} + +// NewAbiDBFromFiles loads both the standard signature database and a custom database. The latter will be used +// to write new values into if they are submitted via the API +func NewAbiDBFromFiles(standard, custom string) (*AbiDb, error) { + + db := &AbiDb{make(map[string]string), make(map[string]string), custom} + db.customdbPath = custom + + raw, err := ioutil.ReadFile(standard) + if err != nil { + return nil, err + } + 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 + } + if err := json.Unmarshal(raw, &db.customdb); err != nil { + return nil, err + } + } + + return db, nil +} + +// LookupMethodSelector checks the given 4byte-sequence against the known ABI methods. +// OBS: This method does not validate the match, it's assumed the caller will do so +func (db *AbiDb) LookupMethodSelector(id []byte) (string, error) { + if len(id) < 4 { + return "", fmt.Errorf("Expected 4-byte id, got %d", len(id)) + } + sig := common.ToHex(id[:4]) + if key, exists := db.db[sig]; exists { + return key, nil + } + if key, exists := db.customdb[sig]; exists { + return key, nil + } + return "", fmt.Errorf("Signature %v not found", sig) +} +func (db *AbiDb) Size() int { + return len(db.db) +} + +// saveCustomAbi saves a signature ephemerally. If custom file is used, also saves to disk +func (db *AbiDb) saveCustomAbi(selector, signature string) error { + db.customdb[signature] = selector + if db.customdbPath == "" { + return nil //Not an error per se, just not used + } + d, err := json.Marshal(db.customdb) + if err != nil { + return err + } + err = ioutil.WriteFile(db.customdbPath, d, 0600) + return err +} + +// AddSignature to the database, if custom database saving is enabled. +// OBS: This method does _not_ validate the correctness of the data, +// it is assumed that the caller has already done so +func (db *AbiDb) AddSignature(selector string, data []byte) error { + if len(data) < 4 { + return nil + } + _, err := db.LookupMethodSelector(data[:4]) + if err == nil { + return nil + } + sig := common.ToHex(data[:4]) + return db.saveCustomAbi(selector, sig) +} diff --git a/signer/core/abihelper_test.go b/signer/core/abihelper_test.go new file mode 100644 index 0000000000..4a3a2f06d2 --- /dev/null +++ b/signer/core/abihelper_test.go @@ -0,0 +1,250 @@ +// 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 ( + "fmt" + "io/ioutil" + "math/big" + "reflect" + "strings" + "testing" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" +) + +func verify(t *testing.T, jsondata, calldata string, exp []interface{}) { + + abispec, err := abi.JSON(strings.NewReader(jsondata)) + if err != nil { + t.Fatal(err) + } + cd := common.Hex2Bytes(calldata) + sigdata, argdata := cd[:4], cd[4:] + method, err := abispec.MethodById(sigdata) + if err != nil { + t.Fatal(err) + } + data, err := method.Inputs.UnpackValues(argdata) + if err != nil { + t.Fatal(err) + } + if len(data) != len(exp) { + t.Fatalf("Mismatched length, expected %d, got %d", len(exp), len(data)) + } + for i, elem := range data { + if !reflect.DeepEqual(elem, exp[i]) { + t.Fatalf("Unpack error, arg %d, got %v, want %v", i, elem, exp[i]) + } + } +} +func TestNewUnpacker(t *testing.T) { + type unpackTest struct { + jsondata string + calldata string + exp []interface{} + } + testcases := []unpackTest{ + { // https://solidity.readthedocs.io/en/develop/abi-spec.html#use-of-dynamic-types + `[{"type":"function","name":"f", "inputs":[{"type":"uint256"},{"type":"uint32[]"},{"type":"bytes10"},{"type":"bytes"}]}]`, + // 0x123, [0x456, 0x789], "1234567890", "Hello, world!" + "8be65246" + "00000000000000000000000000000000000000000000000000000000000001230000000000000000000000000000000000000000000000000000000000000080313233343536373839300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000004560000000000000000000000000000000000000000000000000000000000000789000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20776f726c642100000000000000000000000000000000000000", + []interface{}{ + big.NewInt(0x123), + []uint32{0x456, 0x789}, + [10]byte{49, 50, 51, 52, 53, 54, 55, 56, 57, 48}, + common.Hex2Bytes("48656c6c6f2c20776f726c6421"), + }, + }, { // https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI#examples + `[{"type":"function","name":"sam","inputs":[{"type":"bytes"},{"type":"bool"},{"type":"uint256[]"}]}]`, + // "dave", true and [1,2,3] + "a5643bf20000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000464617665000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003", + []interface{}{ + []byte{0x64, 0x61, 0x76, 0x65}, + true, + []*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(3)}, + }, + }, { + `[{"type":"function","name":"send","inputs":[{"type":"uint256"}]}]`, + "a52c101e0000000000000000000000000000000000000000000000000000000000000012", + []interface{}{big.NewInt(0x12)}, + }, { + `[{"type":"function","name":"compareAndApprove","inputs":[{"type":"address"},{"type":"uint256"},{"type":"uint256"}]}]`, + "751e107900000000000000000000000000000133700000deadbeef00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", + []interface{}{ + common.HexToAddress("0x00000133700000deadbeef000000000000000000"), + new(big.Int).SetBytes([]byte{0x00}), + big.NewInt(0x1), + }, + }, + } + for _, c := range testcases { + verify(t, c.jsondata, c.calldata, c.exp) + } + +} + +func TestCalldataDecoding(t *testing.T) { + + // send(uint256) : a52c101e + // compareAndApprove(address,uint256,uint256) : 751e1079 + // issue(address[],uint256) : 42958b54 + jsondata := ` +[ + {"type":"function","name":"send","inputs":[{"name":"a","type":"uint256"}]}, + {"type":"function","name":"compareAndApprove","inputs":[{"name":"a","type":"address"},{"name":"a","type":"uint256"},{"name":"a","type":"uint256"}]}, + {"type":"function","name":"issue","inputs":[{"name":"a","type":"address[]"},{"name":"a","type":"uint256"}]}, + {"type":"function","name":"sam","inputs":[{"name":"a","type":"bytes"},{"name":"a","type":"bool"},{"name":"a","type":"uint256[]"}]} +]` + //Expected failures + for i, hexdata := range []string{ + "a52c101e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000042", + "a52c101e000000000000000000000000000000000000000000000000000000000000001200", + "a52c101e00000000000000000000000000000000000000000000000000000000000000", + "a52c101e", + "a52c10", + "", + // Too short + "751e10790000000000000000000000000000000000000000000000000000000000000012", + "751e1079FFffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + //Not valid multiple of 32 + "deadbeef00000000000000000000000000000000000000000000000000000000000000", + //Too short 'issue' + "42958b5400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000042", + // Too short compareAndApprove + "a52c101e00ff0000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000042", + // From https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI + // contains a bool with illegal values + "a5643bf20000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000001100000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000464617665000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003", + } { + _, err := parseCallData(common.Hex2Bytes(hexdata), jsondata) + if err == nil { + t.Errorf("test %d: expected decoding to fail: %s", i, hexdata) + } + } + //Expected success + for i, hexdata := range []string{ + // From https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI + "a5643bf20000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000464617665000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003", + "a52c101e0000000000000000000000000000000000000000000000000000000000000012", + "a52c101eFFffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "751e1079000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "42958b54" + + // start of dynamic type + "0000000000000000000000000000000000000000000000000000000000000040" + + //uint256 + "0000000000000000000000000000000000000000000000000000000000000001" + + // length of array + "0000000000000000000000000000000000000000000000000000000000000002" + + // array values + "000000000000000000000000000000000000000000000000000000000000dead" + + "000000000000000000000000000000000000000000000000000000000000beef", + } { + _, err := parseCallData(common.Hex2Bytes(hexdata), jsondata) + if err != nil { + t.Errorf("test %d: unexpected failure on input %s:\n %v (%d bytes) ", i, hexdata, err, len(common.Hex2Bytes(hexdata))) + } + } +} + +func TestSelectorUnmarshalling(t *testing.T) { + var ( + db *AbiDb + err error + abistring []byte + abistruct abi.ABI + ) + + db, err = NewAbiDBFromFile("../../cmd/clef/4byte.json") + if err != nil { + t.Fatal(err) + } + fmt.Printf("DB size %v\n", db.Size()) + for id, selector := range db.db { + + abistring, err = MethodSelectorToAbi(selector) + if err != nil { + t.Error(err) + return + } + abistruct, err = abi.JSON(strings.NewReader(string(abistring))) + if err != nil { + t.Error(err) + return + } + m, err := abistruct.MethodById(common.Hex2Bytes(id[2:])) + if err != nil { + t.Error(err) + return + } + if m.Sig() != selector { + t.Errorf("Expected equality: %v != %v", m.Sig(), selector) + } + } + +} + +func TestCustomABI(t *testing.T) { + d, err := ioutil.TempDir("", "signer-4byte-test") + if err != nil { + t.Fatal(err) + } + filename := fmt.Sprintf("%s/4byte_custom.json", d) + abidb, err := NewAbiDBFromFiles("../../cmd/clef/4byte.json", filename) + if err != nil { + t.Fatal(err) + } + // Now we'll remove all existing signatures + abidb.db = make(map[string]string) + calldata := common.Hex2Bytes("a52c101edeadbeef") + _, err = abidb.LookupMethodSelector(calldata) + if err == nil { + t.Fatalf("Should not find a match on empty db") + } + if err = abidb.AddSignature("send(uint256)", calldata); err != nil { + t.Fatalf("Failed to save file: %v", err) + } + _, err = abidb.LookupMethodSelector(calldata) + if err != nil { + t.Fatalf("Should find a match for abi signature, got: %v", err) + } + //Check that it wrote to file + abidb2, err := NewAbiDBFromFile(filename) + if err != nil { + t.Fatalf("Failed to create new abidb: %v", err) + } + _, err = abidb2.LookupMethodSelector(calldata) + if err != nil { + t.Fatalf("Save failed: should find a match for abi signature after loading from disk") + } +} + +func TestMaliciousAbiStrings(t *testing.T) { + tests := []string{ + "func(uint256,uint256,[]uint256)", + "func(uint256,uint256,uint256,)", + "func(,uint256,uint256,uint256)", + } + data := common.Hex2Bytes("4401a6e40000000000000000000000000000000000000000000000000000000000000012") + for i, tt := range tests { + _, err := testSelector(tt, data) + if err == nil { + t.Errorf("test %d: expected error for selector '%v'", i, tt) + } + } +} diff --git a/signer/core/api.go b/signer/core/api.go new file mode 100644 index 0000000000..837b7266c3 --- /dev/null +++ b/signer/core/api.go @@ -0,0 +1,520 @@ +// 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" + "errors" + "fmt" + "math/big" + "reflect" + + "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/internal/ethapi" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/rlp" +) + +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 = "4.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) (common.Address, error) + // SignTransaction request to sign the specified transaction + SignTransaction(ctx context.Context, args SendTxArgs, methodSelector *string) (*ethapi.SignTransactionResult, 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) +} + +// 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) + // ApproveNewAccount prompt the user for confirmation to create new Account, and reveal to caller + ApproveNewAccount(request *NewAccountRequest) (NewAccountResponse, error) + // ShowError displays error message to user + ShowError(message string) + // ShowInfo displays info message to user + ShowInfo(message string) + // OnApprovedTx notifies the UI about a transaction having been successfully signed. + // This method can be used by a UI to keep track of e.g. how much has been sent to a particular recipient. + OnApprovedTx(tx ethapi.SignTransactionResult) + // OnSignerStartup is invoked when the signer boots, and tells the UI info about external API location and version + // information + OnSignerStartup(info StartupInfo) + // 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 UIClientAPI + validator *Validator + rejectMode bool +} + +// Metadata about a request +type Metadata struct { + Remote string `json:"remote"` + Local string `json:"local"` + Scheme string `json:"scheme"` + UserAgent string `json:"User-Agent"` + 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 + + if v := ctx.Value("remote"); v != nil { + m.Remote = v.(string) + } + if v := ctx.Value("scheme"); v != nil { + m.Scheme = v.(string) + } + if v := ctx.Value("local"); v != nil { + m.Local = v.(string) + } + if v := ctx.Value("Origin"); v != nil { + m.Origin = v.(string) + } + if v := ctx.Value("User-Agent"); v != nil { + m.UserAgent = v.(string) + } + return m +} + +// String implements Stringer interface +func (m Metadata) String() string { + s, err := json.Marshal(m) + if err == nil { + return string(s) + } + return err.Error() +} + +// types for the requests/response types between signer and UI +type ( + // SignTxRequest contains info about a Transaction to sign + SignTxRequest struct { + Transaction SendTxArgs `json:"transaction"` + Callinfo []ValidationInfo `json:"call_info"` + Meta Metadata `json:"meta"` + } + // SignTxResponse result from SignTxRequest + SignTxResponse struct { + //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 { + 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"` + } + ListRequest struct { + Accounts []accounts.Account `json:"accounts"` + Meta Metadata `json:"meta"` + } + ListResponse struct { + Accounts []accounts.Account `json:"accounts"` + } + Message struct { + Text string `json:"text"` + } + StartupInfo struct { + Info map[string]interface{} `json:"info"` + } + UserInputRequest struct { + Prompt string `json:"prompt"` + Title string `json:"title"` + IsPassword bool `json:"isPassword"` + } + UserInputResponse struct { + Text string `json:"text"` + } +) + +var ErrRequestDenied = errors.New("Request denied") + +// NewSignerAPI creates a new API that can be used for Account management. +// ksLocation specifies the directory where to store the password protected private +// 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(am *accounts.Manager, chainID int64, noUSB bool, ui UIClientAPI, abidb *AbiDb, advancedMode bool) *SignerAPI { + if advancedMode { + log.Info("Clef is in advanced mode: will warn instead of reject") + } + signer := &SignerAPI{big.NewInt(chainID), am, ui, NewValidator(abidb), !advancedMode} + if !noUSB { + signer.startUSBListener() + } + return signer +} +func (api *SignerAPI) openTrezor(url accounts.URL) { + resp, err := api.UI.OnInputRequired(UserInputRequest{ + Prompt: "Pin required to open Trezor wallet\n" + + "Look at the device for number positions\n\n" + + "7 | 8 | 9\n" + + "--+---+--\n" + + "4 | 5 | 6\n" + + "--+---+--\n" + + "1 | 2 | 3\n\n", + IsPassword: true, + Title: "Trezor unlock", + }) + if err != nil { + log.Warn("failed getting trezor pin", "err", err) + return + } + // We're using the URL instead of the pointer to the + // Wallet -- perhaps it is not actually present anymore + w, err := api.am.Wallet(url.String()) + if err != nil { + log.Warn("wallet unavailable", "url", url) + return + } + err = w.Open(resp.Text) + if err != nil { + log.Warn("failed to open wallet", "wallet", url, "err", err) + return + } + +} + +// startUSBListener starts a listener for USB events, for hardware wallet interaction +func (api *SignerAPI) startUSBListener() { + events := make(chan accounts.WalletEvent, 16) + am := api.am + am.Subscribe(events) + go func() { + + // Open any wallets already attached + for _, wallet := range am.Wallets() { + if err := wallet.Open(""); err != nil { + log.Warn("Failed to open wallet", "url", wallet.URL(), "err", err) + if err == usbwallet.ErrTrezorPINNeeded { + go api.openTrezor(wallet.URL()) + } + } + } + // Listen for wallet event till termination + for event := range events { + switch event.Kind { + case accounts.WalletArrived: + if err := event.Wallet.Open(""); err != nil { + log.Warn("New wallet appeared, failed to open", "url", event.Wallet.URL(), "err", err) + if err == usbwallet.ErrTrezorPINNeeded { + go api.openTrezor(event.Wallet.URL()) + } + } + case accounts.WalletOpened: + status, _ := event.Wallet.Status() + log.Info("New wallet appeared", "url", event.Wallet.URL(), "status", status) + + derivationPath := accounts.DefaultBaseDerivationPath + if event.Wallet.URL().Scheme == "ledger" { + derivationPath = accounts.DefaultLedgerBaseDerivationPath + } + var nextPath = derivationPath + // Derive first N accounts, hardcoded for now + for i := 0; i < numberOfAccountsToDerive; i++ { + acc, err := event.Wallet.Derive(nextPath, true) + if err != nil { + log.Warn("account derivation failed", "error", err) + } else { + log.Info("derived account", "address", acc.Address) + } + nextPath[len(nextPath)-1]++ + } + case accounts.WalletDropped: + log.Info("Old wallet dropped", "url", event.Wallet.URL()) + event.Wallet.Close() + } + } + }() +} + +// 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 []accounts.Account + for _, wallet := range api.am.Wallets() { + accs = append(accs, wallet.Accounts()...) + } + result, err := api.UI.ApproveListing(&ListRequest{Accounts: accs, Meta: MetadataFromContext(ctx)}) + if err != nil { + return nil, err + } + if result.Accounts == nil { + return nil, ErrRequestDenied + + } + addresses := make([]common.Address, 0) + for _, acc := range result.Accounts { + addresses = append(addresses, acc.Address) + } + + return addresses, nil +} + +// 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) (common.Address, error) { + be := api.am.Backends(keystore.KeyStoreType) + if len(be) == 0 { + return common.Address{}, errors.New("password based accounts not supported") + } + var ( + resp NewAccountResponse + err error + ) + // Three retries to get a valid password + for i := 0; i < 3; i++ { + resp, err = api.UI.ApproveNewAccount(&NewAccountRequest{MetadataFromContext(ctx)}) + if err != nil { + return common.Address{}, err + } + if !resp.Approved { + return common.Address{}, ErrRequestDenied + } + if pwErr := ValidatePasswordFormat(resp.Password); pwErr != nil { + api.UI.ShowError(fmt.Sprintf("Account creation attempt #%d failed due to password requirements: %v", (i + 1), pwErr)) + } else { + // No error + acc, err := be[0].(*keystore.KeyStore).NewAccount(resp.Password) + return acc.Address, err + } + } + // Otherwise fail, with generic error message + return common.Address{}, errors.New("account creation failed") +} + +// logDiff logs the difference between the incoming (original) transaction and the one returned from the signer. +// it also returns 'true' if the transaction was modified, to make it possible to configure the signer not to allow +// UI-modifications to requests +func logDiff(original *SignTxRequest, new *SignTxResponse) bool { + modified := false + if f0, f1 := original.Transaction.From, new.Transaction.From; !reflect.DeepEqual(f0, f1) { + log.Info("Sender-account changed by UI", "was", f0, "is", f1) + modified = true + } + if t0, t1 := original.Transaction.To, new.Transaction.To; !reflect.DeepEqual(t0, t1) { + log.Info("Recipient-account changed by UI", "was", t0, "is", t1) + modified = true + } + if g0, g1 := original.Transaction.Gas, new.Transaction.Gas; g0 != g1 { + modified = true + log.Info("Gas changed by UI", "was", g0, "is", g1) + } + if g0, g1 := big.Int(original.Transaction.GasPrice), big.Int(new.Transaction.GasPrice); g0.Cmp(&g1) != 0 { + modified = true + log.Info("GasPrice changed by UI", "was", g0, "is", g1) + } + if v0, v1 := big.Int(original.Transaction.Value), big.Int(new.Transaction.Value); v0.Cmp(&v1) != 0 { + modified = true + log.Info("Value changed by UI", "was", v0, "is", v1) + } + if d0, d1 := original.Transaction.Data, new.Transaction.Data; d0 != d1 { + d0s := "" + d1s := "" + if d0 != nil { + d0s = hexutil.Encode(*d0) + } + if d1 != nil { + d1s = hexutil.Encode(*d1) + } + if d1s != d0s { + modified = true + log.Info("Data changed by UI", "was", d0s, "is", d1s) + } + } + if n0, n1 := original.Transaction.Nonce, new.Transaction.Nonce; n0 != n1 { + modified = true + log.Info("Nonce changed by UI", "was", n0, "is", n1) + } + return modified +} + +// 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 ( + err error + result SignTxResponse + ) + msgs, err := api.validator.ValidateTransaction(&args, methodSelector) + if err != nil { + return nil, err + } + // If we are in 'rejectMode', then reject rather than show the user warnings + if api.rejectMode { + if err := msgs.getWarnings(); err != nil { + return nil, err + } + } + + req := SignTxRequest{ + Transaction: args, + Meta: MetadataFromContext(ctx), + Callinfo: msgs.Messages, + } + // Process approval + result, err = api.UI.ApproveTx(&req) + if err != nil { + return nil, err + } + if !result.Approved { + return nil, ErrRequestDenied + } + // Log changes made by the UI to the signing-request + logDiff(&req, &result) + var ( + acc accounts.Account + wallet accounts.Wallet + ) + acc = accounts.Account{Address: result.Transaction.From.Address()} + wallet, err = api.am.Find(acc) + if err != nil { + return nil, err + } + // Convert fields into a real transaction + var unsignedTx = result.Transaction.toTransaction() + + // The one to sign is the one that was returned from the UI + signedTx, err := wallet.SignTxWithPassphrase(acc, result.Password, unsignedTx, api.chainID) + if err != nil { + api.UI.ShowError(err.Error()) + return nil, err + } + + rlpdata, err := rlp.EncodeToBytes(signedTx) + response := ethapi.SignTransactionResult{Raw: rlpdata, Tx: signedTx} + + // Finally, send the signed tx to the UI + api.UI.OnApprovedTx(response) + // ...and to the external caller + return &response, 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/signer/core/api_test.go b/signer/core/api_test.go new file mode 100644 index 0000000000..bf4e91eb95 --- /dev/null +++ b/signer/core/api_test.go @@ -0,0 +1,371 @@ +// 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" + "io/ioutil" + "math/big" + "os" + "path/filepath" + "testing" + "time" + + "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/hexutil" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/internal/ethapi" + "github.com/ethereum/go-ethereum/rlp" +) + +//Used for testing +type HeadlessUI struct { + controller chan string +} + +func (ui *HeadlessUI) OnInputRequired(info UserInputRequest) (UserInputResponse, error) { + return UserInputResponse{}, errors.New("not implemented") +} + +func (ui *HeadlessUI) OnSignerStartup(info StartupInfo) { +} +func (ui *HeadlessUI) RegisterUIServer(api *UIServerAPI) { +} + +func (ui *HeadlessUI) OnApprovedTx(tx ethapi.SignTransactionResult) { + fmt.Printf("OnApproved()\n") +} + +func (ui *HeadlessUI) ApproveTx(request *SignTxRequest) (SignTxResponse, error) { + + switch <-ui.controller { + case "Y": + return SignTxResponse{request.Transaction, true, <-ui.controller}, nil + case "M": //Modify + 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 + default: + 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) 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 { + case "A": + return ListResponse{request.Accounts}, nil + case "1": + l := make([]accounts.Account, 1) + l[0] = request.Accounts[1] + return ListResponse{l}, nil + default: + return ListResponse{nil}, nil + } +} + +func (ui *HeadlessUI) ApproveNewAccount(request *NewAccountRequest) (NewAccountResponse, error) { + if "Y" == <-ui.controller { + return NewAccountResponse{true, <-ui.controller}, nil + } + return NewAccountResponse{false, ""}, nil +} + +func (ui *HeadlessUI) ShowError(message string) { + //stdout is used by communication + fmt.Fprintln(os.Stderr, message) +} + +func (ui *HeadlessUI) ShowInfo(message string) { + //stdout is used by communication + fmt.Fprintln(os.Stderr, message) +} + +func tmpDirName(t *testing.T) string { + d, err := ioutil.TempDir("", "eth-keystore-test") + if err != nil { + t.Fatal(err) + } + d, err = filepath.EvalSymlinks(d) + if err != nil { + t.Fatal(err) + } + return d +} + +func setup(t *testing.T) (*SignerAPI, chan string) { + + controller := make(chan string, 20) + + db, err := NewAbiDBFromFile("../../cmd/clef/4byte.json") + if err != nil { + t.Fatal(err.Error()) + } + var ( + ui = &HeadlessUI{controller} + am = StartClefAccountManager(tmpDirName(t), true, true) + api = NewSignerAPI(am, 1337, true, ui, db, true) + ) + return api, controller +} +func createAccount(control chan string, api *SignerAPI, t *testing.T) { + + control <- "Y" + control <- "a_long_password" + _, err := api.New(context.Background()) + if err != nil { + t.Fatal(err) + } + // Some time to allow changes to propagate + time.Sleep(250 * time.Millisecond) +} + +func failCreateAccountWithPassword(control chan string, api *SignerAPI, password string, t *testing.T) { + + control <- "Y" + control <- password + control <- "Y" + control <- password + control <- "Y" + control <- password + + addr, err := api.New(context.Background()) + if err == nil { + t.Fatal("Should have returned an error") + } + if addr != (common.Address{}) { + t.Fatal("Empty address should be returned") + } +} + +func failCreateAccount(control chan string, api *SignerAPI, t *testing.T) { + control <- "N" + addr, err := api.New(context.Background()) + if err != ErrRequestDenied { + t.Fatal(err) + } + 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 TestNewAcc(t *testing.T) { + api, control := setup(t) + verifyNum := func(num int) { + if list := list(control, api, t); len(list) != num { + t.Errorf("Expected %d accounts, got %d", num, len(list)) + } + } + // Testing create and create-deny + createAccount(control, api, t) + createAccount(control, api, t) + failCreateAccount(control, api, t) + failCreateAccount(control, api, t) + createAccount(control, api, 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" + list, err := api.List(context.Background()) + if err != nil { + t.Fatal(err) + } + if len(list) != 1 { + t.Fatalf("List should only show one Account") + } + // Listing denied + control <- "Nope" + list, err = api.List(context.Background()) + if len(list) != 0 { + t.Fatalf("List should be empty") + } + if err != ErrRequestDenied { + t.Fatal("Expected deny") + } +} + +func mkTestTx(from common.MixedcaseAddress) SendTxArgs { + to := common.NewMixedcaseAddress(common.HexToAddress("0x1337")) + gas := hexutil.Uint64(21000) + gasPrice := (hexutil.Big)(*big.NewInt(2000000000)) + value := (hexutil.Big)(*big.NewInt(1e18)) + nonce := (hexutil.Uint64)(0) + data := hexutil.Bytes(common.Hex2Bytes("01020304050607080a")) + tx := SendTxArgs{ + From: from, + To: &to, + Gas: gas, + GasPrice: gasPrice, + Value: value, + Data: &data, + Nonce: nonce} + return tx +} + +func TestSignTx(t *testing.T) { + var ( + list []common.Address + res, res2 *ethapi.SignTransactionResult + err error + ) + + api, control := setup(t) + createAccount(control, api, t) + control <- "A" + list, err = api.List(context.Background()) + if err != nil { + t.Fatal(err) + } + a := common.NewMixedcaseAddress(list[0]) + + methodSig := "test(uint)" + tx := mkTestTx(a) + + control <- "Y" + control <- "wrongpassword" + res, err = api.SignTransaction(context.Background(), tx, &methodSig) + if res != nil { + t.Errorf("Expected nil-response, got %v", res) + } + if err != keystore.ErrDecrypt { + t.Errorf("Expected ErrLocked! %v", err) + } + control <- "No way" + res, err = api.SignTransaction(context.Background(), tx, &methodSig) + if res != nil { + t.Errorf("Expected nil-response, got %v", res) + } + if err != ErrRequestDenied { + t.Errorf("Expected ErrRequestDenied! %v", err) + } + control <- "Y" + control <- "a_long_password" + res, err = api.SignTransaction(context.Background(), tx, &methodSig) + + if err != nil { + t.Fatal(err) + } + parsedTx := &types.Transaction{} + rlp.Decode(bytes.NewReader(res.Raw), parsedTx) + + //The tx should NOT be modified by the UI + 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" + + res2, err = api.SignTransaction(context.Background(), tx, &methodSig) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(res.Raw, res2.Raw) { + t.Error("Expected tx to be unmodified by UI") + } + + //The tx is modified by the UI + control <- "M" + control <- "a_long_password" + + res2, err = api.SignTransaction(context.Background(), tx, &methodSig) + if err != nil { + t.Fatal(err) + } + parsedTx2 := &types.Transaction{} + rlp.Decode(bytes.NewReader(res.Raw), parsedTx2) + + //The tx should be modified by the UI + if parsedTx2.Value().Cmp(tx.Value.ToInt()) != 0 { + t.Errorf("Expected value to be unchanged, got %v", parsedTx.Value()) + } + if bytes.Equal(res.Raw, res2.Raw) { + t.Error("Expected tx to be modified by UI") + } + +} + +/* +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/signer/core/auditlog.go b/signer/core/auditlog.go new file mode 100644 index 0000000000..9593ad7a53 --- /dev/null +++ b/signer/core/auditlog.go @@ -0,0 +1,104 @@ +// 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" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/internal/ethapi" + "github.com/ethereum/go-ethereum/log" +) + +type AuditLogger struct { + log log.Logger + api ExternalAPI +} + +func (l *AuditLogger) List(ctx context.Context) ([]common.Address, error) { + l.log.Info("List", "type", "request", "metadata", MetadataFromContext(ctx).String()) + res, e := l.api.List(ctx) + l.log.Info("List", "type", "response", "data", res) + + return res, e +} + +func (l *AuditLogger) New(ctx context.Context) (common.Address, error) { + return l.api.New(ctx) +} + +func (l *AuditLogger) SignTransaction(ctx context.Context, args SendTxArgs, methodSelector *string) (*ethapi.SignTransactionResult, error) { + sel := "" + if methodSelector != nil { + sel = *methodSelector + } + l.log.Info("SignTransaction", "type", "request", "metadata", MetadataFromContext(ctx).String(), + "tx", args.String(), + "methodSelector", sel) + + res, e := l.api.SignTransaction(ctx, args, methodSelector) + if res != nil { + l.log.Info("SignTransaction", "type", "response", "data", common.Bytes2Hex(res.Raw), "error", e) + } else { + l.log.Info("SignTransaction", "type", "response", "data", res, "error", e) + } + return res, 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) 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) 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") + handler, err := log.FileHandler(path, log.LogfmtFormat()) + if err != nil { + return nil, err + } + l.SetHandler(handler) + l.Info("Configured", "audit log", path) + return &AuditLogger{l, api}, nil +} diff --git a/signer/core/cliui.go b/signer/core/cliui.go new file mode 100644 index 0000000000..a6c0bdb162 --- /dev/null +++ b/signer/core/cliui.go @@ -0,0 +1,283 @@ +// 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 ( + "bufio" + "encoding/json" + "fmt" + "os" + "strings" + "sync" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/internal/ethapi" + "github.com/ethereum/go-ethereum/log" + "golang.org/x/crypto/ssh/terminal" +) + +type CommandlineUI struct { + in *bufio.Reader + mu sync.Mutex +} + +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 { + for { + fmt.Printf("> ") + text, err := ui.in.ReadString('\n') + if err != nil { + log.Crit("Failed to read user input", "err", err) + } + if text = strings.TrimSpace(text); text != "" { + return text + } + } +} + +// readPassword reads a single line from stdin, trimming it from the trailing new +// line and returns it. The input will not be echoed. +func (ui *CommandlineUI) readPassword() string { + fmt.Printf("Enter password to approve:\n") + fmt.Printf("> ") + + text, err := terminal.ReadPassword(int(os.Stdin.Fd())) + if err != nil { + log.Crit("Failed to read password", "err", err) + } + fmt.Println() + fmt.Println("-----------------------") + return string(text) +} + +// readPassword reads a single line from stdin, trimming it from the trailing new +// line and returns it. The input will not be echoed. +func (ui *CommandlineUI) readPasswordText(inputstring string) string { + fmt.Printf("Enter %s:\n", inputstring) + fmt.Printf("> ") + text, err := terminal.ReadPassword(int(os.Stdin.Fd())) + if err != nil { + log.Crit("Failed to read password", "err", err) + } + fmt.Println("-----------------------") + return string(text) +} + +func (ui *CommandlineUI) OnInputRequired(info UserInputRequest) (UserInputResponse, error) { + fmt.Println(info.Title) + fmt.Println(info.Prompt) + if info.IsPassword { + text, err := terminal.ReadPassword(int(os.Stdin.Fd())) + if err != nil { + log.Error("Failed to read password", "err", err) + } + fmt.Println("-----------------------") + return UserInputResponse{string(text)}, err + } + text := ui.readString() + fmt.Println("-----------------------") + return UserInputResponse{text}, nil +} + +// confirm returns true if user enters 'Yes', otherwise false +func (ui *CommandlineUI) confirm() bool { + fmt.Printf("Approve? [y/N]:\n") + if ui.readString() == "y" { + return true + } + fmt.Println("-----------------------") + return false +} + +func showMetadata(metadata Metadata) { + fmt.Printf("Request context:\n\t%v -> %v -> %v\n", metadata.Remote, metadata.Scheme, metadata.Local) + fmt.Printf("\nAdditional HTTP header data, provided by the external caller:\n") + fmt.Printf("\tUser-Agent: %v\n\tOrigin: %v\n", metadata.UserAgent, metadata.Origin) +} + +// ApproveTx prompt the user for confirmation to request to sign Transaction +func (ui *CommandlineUI) ApproveTx(request *SignTxRequest) (SignTxResponse, error) { + ui.mu.Lock() + defer ui.mu.Unlock() + weival := request.Transaction.Value.ToInt() + fmt.Printf("--------- Transaction request-------------\n") + if to := request.Transaction.To; to != nil { + fmt.Printf("to: %v\n", to.Original()) + if !to.ValidChecksum() { + fmt.Printf("\nWARNING: Invalid checksum on to-address!\n\n") + } + } else { + fmt.Printf("to: \n") + } + fmt.Printf("from: %v\n", request.Transaction.From.String()) + fmt.Printf("value: %v wei\n", weival) + fmt.Printf("gas: %v (%v)\n", request.Transaction.Gas, uint64(request.Transaction.Gas)) + fmt.Printf("gasprice: %v wei\n", request.Transaction.GasPrice.ToInt()) + fmt.Printf("nonce: %v (%v)\n", request.Transaction.Nonce, uint64(request.Transaction.Nonce)) + if request.Transaction.Data != nil { + d := *request.Transaction.Data + if len(d) > 0 { + + fmt.Printf("data: %v\n", hexutil.Encode(d)) + } + } + if request.Callinfo != nil { + fmt.Printf("\nTransaction validation:\n") + for _, m := range request.Callinfo { + fmt.Printf(" * %s : %s\n", m.Typ, m.Message) + } + fmt.Println() + + } + fmt.Printf("\n") + showMetadata(request.Meta) + fmt.Printf("-------------------------------------------\n") + if !ui.confirm() { + return SignTxResponse{request.Transaction, false, ""}, nil + } + return SignTxResponse{request.Transaction, true, ui.readPassword()}, nil +} + +// ApproveSignData prompt the user for confirmation to request to sign data +func (ui *CommandlineUI) ApproveSignData(request *SignDataRequest) (SignDataResponse, error) { + ui.mu.Lock() + defer ui.mu.Unlock() + + fmt.Printf("-------- Sign data request--------------\n") + fmt.Printf("Account: %s\n", request.Address.String()) + 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{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 +} + +// ApproveListing prompt the user for confirmation to list accounts +// the list of accounts to list can be modified by the UI +func (ui *CommandlineUI) ApproveListing(request *ListRequest) (ListResponse, error) { + + ui.mu.Lock() + defer ui.mu.Unlock() + + fmt.Printf("-------- List Account request--------------\n") + fmt.Printf("A request has been made to list all accounts. \n") + fmt.Printf("You can select which accounts the caller can see\n") + for _, account := range request.Accounts { + fmt.Printf(" [x] %v\n", account.Address.Hex()) + fmt.Printf(" URL: %v\n", account.URL) + } + fmt.Printf("-------------------------------------------\n") + showMetadata(request.Meta) + if !ui.confirm() { + return ListResponse{nil}, nil + } + return ListResponse{request.Accounts}, nil +} + +// ApproveNewAccount prompt the user for confirmation to create new Account, and reveal to caller +func (ui *CommandlineUI) ApproveNewAccount(request *NewAccountRequest) (NewAccountResponse, error) { + + ui.mu.Lock() + defer ui.mu.Unlock() + + fmt.Printf("-------- New Account request--------------\n\n") + fmt.Printf("A request has been made to create a new account. \n") + fmt.Printf("Approving this operation means that a new account is created,\n") + 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{true, ui.readPassword()}, 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("-------------------------------------------\n") +} + +// ShowInfo displays info message to user +func (ui *CommandlineUI) ShowInfo(message string) { + fmt.Printf("Info: %v\n", message) +} + +func (ui *CommandlineUI) OnApprovedTx(tx ethapi.SignTransactionResult) { + fmt.Printf("Transaction signed:\n ") + 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) { + + fmt.Printf("------- Signer info -------\n") + for k, v := range info.Info { + fmt.Printf("* %v : %v\n", k, v) + } +} diff --git a/signer/core/signed_data.go b/signer/core/signed_data.go new file mode 100644 index 0000000000..9df39ef59a --- /dev/null +++ b/signer/core/signed_data.go @@ -0,0 +1,911 @@ +// 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 + } + // Sign the data with the wallet + signature, err := wallet.SignDataWithPassphrase(account, res.Password, 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/signer/core/signed_data_test.go b/signer/core/signed_data_test.go new file mode 100644 index 0000000000..7d44bce2ce --- /dev/null +++ b/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 <- "1" + list, err := api.List(context.Background()) + if err != nil { + t.Fatal(err) + } + a := common.NewMixedcaseAddress(list[0]) + + control <- "Y" + control <- "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 <- "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 <- "Y" + control <- "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 <- "Y" + control <- "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/signer/core/stdioui.go b/signer/core/stdioui.go new file mode 100644 index 0000000000..cb25bc2d00 --- /dev/null +++ b/signer/core/stdioui.go @@ -0,0 +1,135 @@ +// 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" + "sync" + + "github.com/ethereum/go-ethereum/internal/ethapi" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/rpc" +) + +type StdIOUI struct { + client rpc.Client + mu sync.Mutex +} + +func NewStdIOUI() *StdIOUI { + client, err := rpc.DialContext(context.Background(), "stdio://") + if err != nil { + log.Crit("Could not create stdio client", "err", err) + } + ui := &StdIOUI{client: *client} + return ui +} + +func (ui *StdIOUI) RegisterUIServer(api *UIServerAPI) { + ui.client.RegisterName("clef", api) +} + +// dispatch sends a request over the stdio +func (ui *StdIOUI) dispatch(serviceMethod string, args interface{}, reply interface{}) error { + err := ui.client.Call(&reply, serviceMethod, args) + if err != nil { + log.Info("Error", "exc", err.Error()) + } + 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) + 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) + return result, err +} + +func (ui *StdIOUI) ApproveListing(request *ListRequest) (ListResponse, error) { + var result ListResponse + err := ui.dispatch("ApproveListing", request, &result) + return result, err +} + +func (ui *StdIOUI) ApproveNewAccount(request *NewAccountRequest) (NewAccountResponse, error) { + var result NewAccountResponse + err := ui.dispatch("ApproveNewAccount", request, &result) + return result, err +} + +func (ui *StdIOUI) ShowError(message string) { + err := ui.notify("ShowError", &Message{message}) + if err != nil { + log.Info("Error calling 'ShowError'", "exc", err.Error(), "msg", message) + } +} + +func (ui *StdIOUI) ShowInfo(message string) { + err := ui.notify("ShowInfo", Message{message}) + if err != nil { + log.Info("Error calling 'ShowInfo'", "exc", err.Error(), "msg", message) + } +} +func (ui *StdIOUI) OnApprovedTx(tx ethapi.SignTransactionResult) { + err := ui.notify("OnApprovedTx", tx) + if err != nil { + log.Info("Error calling 'OnApprovedTx'", "exc", err.Error(), "tx", tx) + } +} + +func (ui *StdIOUI) OnSignerStartup(info StartupInfo) { + err := ui.notify("OnSignerStartup", info) + if err != nil { + log.Info("Error calling 'OnSignerStartup'", "exc", err.Error(), "info", info) + } +} +func (ui *StdIOUI) OnInputRequired(info UserInputRequest) (UserInputResponse, error) { + var result UserInputResponse + err := ui.dispatch("OnInputRequired", info, &result) + if err != nil { + log.Info("Error calling 'OnInputRequired'", "exc", err.Error(), "info", info) + } + return result, err +} diff --git a/signer/core/types.go b/signer/core/types.go new file mode 100644 index 0000000000..8743746ba0 --- /dev/null +++ b/signer/core/types.go @@ -0,0 +1,100 @@ +// 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 ( + "encoding/json" + "fmt" + "math/big" + "strings" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/types" +) + +type ValidationInfo struct { + Typ string `json:"type"` + Message string `json:"message"` +} +type ValidationMessages struct { + Messages []ValidationInfo +} + +const ( + WARN = "WARNING" + CRIT = "CRITICAL" + INFO = "Info" +) + +func (vs *ValidationMessages) crit(msg string) { + vs.Messages = append(vs.Messages, ValidationInfo{CRIT, msg}) +} +func (vs *ValidationMessages) warn(msg string) { + vs.Messages = append(vs.Messages, ValidationInfo{WARN, msg}) +} +func (vs *ValidationMessages) info(msg string) { + vs.Messages = append(vs.Messages, ValidationInfo{INFO, msg}) +} + +/// getWarnings returns an error with all messages of type WARN of above, or nil if no warnings were present +func (v *ValidationMessages) getWarnings() error { + var messages []string + for _, msg := range v.Messages { + if msg.Typ == WARN || msg.Typ == CRIT { + messages = append(messages, msg.Message) + } + } + if len(messages) > 0 { + return fmt.Errorf("Validation failed: %s", strings.Join(messages, ",")) + } + return nil +} + +// SendTxArgs represents the arguments to submit a transaction +type SendTxArgs struct { + From common.MixedcaseAddress `json:"from"` + To *common.MixedcaseAddress `json:"to"` + Gas hexutil.Uint64 `json:"gas"` + GasPrice hexutil.Big `json:"gasPrice"` + Value hexutil.Big `json:"value"` + Nonce hexutil.Uint64 `json:"nonce"` + // We accept "data" and "input" for backwards-compatibility reasons. + Data *hexutil.Bytes `json:"data"` + Input *hexutil.Bytes `json:"input,omitempty"` +} + +func (args SendTxArgs) String() string { + s, err := json.Marshal(args) + if err == nil { + return string(s) + } + return err.Error() +} + +func (args *SendTxArgs) toTransaction() *types.Transaction { + var input []byte + if args.Data != nil { + input = *args.Data + } else if args.Input != nil { + input = *args.Input + } + if args.To == nil { + return types.NewContractCreation(uint64(args.Nonce), (*big.Int)(&args.Value), uint64(args.Gas), (*big.Int)(&args.GasPrice), input) + } + return types.NewTransaction(uint64(args.Nonce), args.To.Address(), (*big.Int)(&args.Value), (uint64)(args.Gas), (*big.Int)(&args.GasPrice), input) +} diff --git a/signer/core/uiapi.go b/signer/core/uiapi.go new file mode 100644 index 0000000000..6dc68313b5 --- /dev/null +++ b/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/signer/core/validation.go b/signer/core/validation.go new file mode 100644 index 0000000000..7c3ec42741 --- /dev/null +++ b/signer/core/validation.go @@ -0,0 +1,171 @@ +// 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" + "errors" + "fmt" + "math/big" + "regexp" + + "github.com/ethereum/go-ethereum/common" +) + +// The validation package contains validation checks for transactions +// - ABI-data validation +// - Transaction semantics validation +// The package provides warnings for typical pitfalls + +type Validator struct { + db *AbiDb +} + +func NewValidator(db *AbiDb) *Validator { + return &Validator{db} +} +func testSelector(selector string, data []byte) (*decodedCallData, error) { + if selector == "" { + return nil, fmt.Errorf("selector not found") + } + abiData, err := MethodSelectorToAbi(selector) + if err != nil { + return nil, err + } + info, err := parseCallData(data, string(abiData)) + if err != nil { + return nil, err + } + return info, nil + +} + +// validateCallData checks if the ABI-data + methodselector (if given) can be parsed and seems to match +func (v *Validator) validateCallData(msgs *ValidationMessages, data []byte, methodSelector *string) { + if len(data) == 0 { + return + } + if len(data) < 4 { + msgs.warn("Tx contains data which is not valid ABI") + return + } + if arglen := len(data) - 4; arglen%32 != 0 { + msgs.warn(fmt.Sprintf("Not ABI-encoded data; length should be a multiple of 32 (was %d)", arglen)) + } + var ( + info *decodedCallData + err error + ) + // Check the provided one + if methodSelector != nil { + info, err = testSelector(*methodSelector, data) + if err != nil { + msgs.warn(fmt.Sprintf("Tx contains data, but provided ABI signature could not be matched: %v", err)) + } else { + msgs.info(info.String()) + //Successfull match. add to db if not there already (ignore errors there) + v.db.AddSignature(*methodSelector, data[:4]) + } + return + } + // Check the db + selector, err := v.db.LookupMethodSelector(data[:4]) + if err != nil { + msgs.warn(fmt.Sprintf("Tx contains data, but the ABI signature could not be found: %v", err)) + return + } + info, err = testSelector(selector, data) + if err != nil { + msgs.warn(fmt.Sprintf("Tx contains data, but provided ABI signature could not be matched: %v", err)) + } else { + msgs.info(info.String()) + } +} + +// validateSemantics checks if the transactions 'makes sense', and generate warnings for a couple of typical scenarios +func (v *Validator) validate(msgs *ValidationMessages, txargs *SendTxArgs, methodSelector *string) error { + // Prevent accidental erroneous usage of both 'input' and 'data' + if txargs.Data != nil && txargs.Input != nil && !bytes.Equal(*txargs.Data, *txargs.Input) { + // This is a showstopper + return errors.New(`Ambiguous request: both "data" and "input" are set and are not identical`) + } + var ( + data []byte + ) + // Place data on 'data', and nil 'input' + if txargs.Input != nil { + txargs.Data = txargs.Input + txargs.Input = nil + } + if txargs.Data != nil { + data = *txargs.Data + } + + if txargs.To == nil { + //Contract creation should contain sufficient data to deploy a contract + // A typical error is omitting sender due to some quirk in the javascript call + // e.g. https://github.com/ethereum/go-ethereum/issues/16106 + if len(data) == 0 { + if txargs.Value.ToInt().Cmp(big.NewInt(0)) > 0 { + // Sending ether into black hole + return errors.New("Tx will create contract with value but empty code!") + } + // No value submitted at least + msgs.crit("Tx will create contract with empty code!") + } else if len(data) < 40 { //Arbitrary limit + msgs.warn(fmt.Sprintf("Tx will will create contract, but payload is suspiciously small (%d b)", len(data))) + } + // methodSelector should be nil for contract creation + if methodSelector != nil { + msgs.warn("Tx will create contract, but method selector supplied; indicating intent to call a method.") + } + + } else { + if !txargs.To.ValidChecksum() { + msgs.warn("Invalid checksum on to-address") + } + // Normal transaction + if bytes.Equal(txargs.To.Address().Bytes(), common.Address{}.Bytes()) { + // Sending to 0 + msgs.crit("Tx destination is the zero address!") + } + // Validate calldata + v.validateCallData(msgs, data, methodSelector) + } + return nil +} + +// ValidateTransaction does a number of checks on the supplied transaction, and returns either a list of warnings, +// or an error, indicating that the transaction should be immediately rejected +func (v *Validator) ValidateTransaction(txArgs *SendTxArgs, methodSelector *string) (*ValidationMessages, error) { + msgs := &ValidationMessages{} + return msgs, v.validate(msgs, txArgs, methodSelector) +} + +var Printable7BitAscii = regexp.MustCompile("^[A-Za-z0-9!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ ]+$") + +// ValidatePasswordFormat returns an error if the password is too short, or consists of characters +// outside the range of the printable 7bit ascii set +func ValidatePasswordFormat(password string) error { + if len(password) < 10 { + return errors.New("password too short (<10 characters)") + } + if !Printable7BitAscii.MatchString(password) { + return errors.New("password contains invalid characters - only 7bit printable ascii allowed") + } + return nil +} diff --git a/signer/core/validation_test.go b/signer/core/validation_test.go new file mode 100644 index 0000000000..1e2e69ecd4 --- /dev/null +++ b/signer/core/validation_test.go @@ -0,0 +1,164 @@ +// 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 ( + "fmt" + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" +) + +func mixAddr(a string) (*common.MixedcaseAddress, error) { + return common.NewMixedcaseAddressFromString(a) +} +func toHexBig(h string) hexutil.Big { + b := big.NewInt(0).SetBytes(common.FromHex(h)) + return hexutil.Big(*b) +} +func toHexUint(h string) hexutil.Uint64 { + b := big.NewInt(0).SetBytes(common.FromHex(h)) + return hexutil.Uint64(b.Uint64()) +} +func dummyTxArgs(t txtestcase) *SendTxArgs { + to, _ := mixAddr(t.to) + from, _ := mixAddr(t.from) + n := toHexUint(t.n) + gas := toHexUint(t.g) + gasPrice := toHexBig(t.gp) + value := toHexBig(t.value) + var ( + data, input *hexutil.Bytes + ) + if t.d != "" { + a := hexutil.Bytes(common.FromHex(t.d)) + data = &a + } + if t.i != "" { + a := hexutil.Bytes(common.FromHex(t.i)) + input = &a + + } + return &SendTxArgs{ + From: *from, + To: to, + Value: value, + Nonce: n, + GasPrice: gasPrice, + Gas: gas, + Data: data, + Input: input, + } +} + +type txtestcase struct { + from, to, n, g, gp, value, d, i string + expectErr bool + numMessages int +} + +func TestValidator(t *testing.T) { + var ( + // use empty db, there are other tests for the abi-specific stuff + db, _ = NewEmptyAbiDB() + v = NewValidator(db) + ) + testcases := []txtestcase{ + // Invalid to checksum + {from: "000000000000000000000000000000000000dead", to: "000000000000000000000000000000000000dead", + n: "0x01", g: "0x20", gp: "0x40", value: "0x01", numMessages: 1}, + // valid 0x000000000000000000000000000000000000dEaD + {from: "000000000000000000000000000000000000dead", to: "0x000000000000000000000000000000000000dEaD", + n: "0x01", g: "0x20", gp: "0x40", value: "0x01", numMessages: 0}, + // conflicting input and data + {from: "000000000000000000000000000000000000dead", to: "0x000000000000000000000000000000000000dEaD", + n: "0x01", g: "0x20", gp: "0x40", value: "0x01", d: "0x01", i: "0x02", expectErr: true}, + // Data can't be parsed + {from: "000000000000000000000000000000000000dead", to: "0x000000000000000000000000000000000000dEaD", + n: "0x01", g: "0x20", gp: "0x40", value: "0x01", d: "0x0102", numMessages: 1}, + // Data (on Input) can't be parsed + {from: "000000000000000000000000000000000000dead", to: "0x000000000000000000000000000000000000dEaD", + n: "0x01", g: "0x20", gp: "0x40", value: "0x01", i: "0x0102", numMessages: 1}, + // Send to 0 + {from: "000000000000000000000000000000000000dead", to: "0x0000000000000000000000000000000000000000", + n: "0x01", g: "0x20", gp: "0x40", value: "0x01", numMessages: 1}, + // Create empty contract (no value) + {from: "000000000000000000000000000000000000dead", to: "", + n: "0x01", g: "0x20", gp: "0x40", value: "0x00", numMessages: 1}, + // Create empty contract (with value) + {from: "000000000000000000000000000000000000dead", to: "", + n: "0x01", g: "0x20", gp: "0x40", value: "0x01", expectErr: true}, + // Small payload for create + {from: "000000000000000000000000000000000000dead", to: "", + n: "0x01", g: "0x20", gp: "0x40", value: "0x01", d: "0x01", numMessages: 1}, + } + for i, test := range testcases { + msgs, err := v.ValidateTransaction(dummyTxArgs(test), nil) + if err == nil && test.expectErr { + t.Errorf("Test %d, expected error", i) + for _, msg := range msgs.Messages { + fmt.Printf("* %s: %s\n", msg.Typ, msg.Message) + } + } + if err != nil && !test.expectErr { + t.Errorf("Test %d, unexpected error: %v", i, err) + } + if err == nil { + got := len(msgs.Messages) + if got != test.numMessages { + for _, msg := range msgs.Messages { + fmt.Printf("* %s: %s\n", msg.Typ, msg.Message) + } + t.Errorf("Test %d, expected %d messages, got %d", i, test.numMessages, got) + } else { + //Debug printout, remove later + for _, msg := range msgs.Messages { + fmt.Printf("* [%d] %s: %s\n", i, msg.Typ, msg.Message) + } + fmt.Println() + } + } + } +} + +func TestPasswordValidation(t *testing.T) { + testcases := []struct { + pw string + shouldFail bool + }{ + {"test", true}, + {"testtest\xbd\xb2\x3d\xbc\x20\xe2\x8c\x98", true}, + {"placeOfInterest⌘", true}, + {"password\nwith\nlinebreak", true}, + {"password\twith\vtabs", true}, + // Ok passwords + {"password WhichIsOk", false}, + {"passwordOk!@#$%^&*()", false}, + {"12301203123012301230123012", false}, + } + for _, test := range testcases { + err := ValidatePasswordFormat(test.pw) + if err == nil && test.shouldFail { + t.Errorf("password '%v' should fail validation", test.pw) + } else if err != nil && !test.shouldFail { + + t.Errorf("password '%v' shound not fail validation, but did: %v", test.pw, err) + } + } +} diff --git a/signer/rules/deps/bignumber.js b/signer/rules/deps/bignumber.js new file mode 100644 index 0000000000..17c8851e24 --- /dev/null +++ b/signer/rules/deps/bignumber.js @@ -0,0 +1,4 @@ +/* bignumber.js v2.0.3 https://github.com/MikeMcl/bignumber.js/LICENCE */ +/* modified by zelig to fix https://github.com/robertkrimen/otto#regular-expression-incompatibility */ +!function(e){"use strict";function n(e){function a(e,n){var t,r,i,o,u,s,f=this;if(!(f instanceof a))return j&&L(26,"constructor call without new",e),new a(e,n);if(null!=n&&H(n,2,64,M,"base")){if(n=0|n,s=e+"",10==n)return f=new a(e instanceof a?e:s),U(f,P+f.e+1,k);if((o="number"==typeof e)&&0*e!=0||!new RegExp("^-?"+(t="["+O.slice(0,n)+"]+")+"(?:\\."+t+")?$",37>n?"i":"").test(s))return g(f,s,o,n);o?(f.s=0>1/e?(s=s.slice(1),-1):1,j&&s.replace(/^0\.0*|\./,"").length>15&&L(M,b,e),o=!1):f.s=45===s.charCodeAt(0)?(s=s.slice(1),-1):1,s=D(s,10,n,f.s)}else{if(e instanceof a)return f.s=e.s,f.e=e.e,f.c=(e=e.c)?e.slice():e,void(M=0);if((o="number"==typeof e)&&0*e==0){if(f.s=0>1/e?(e=-e,-1):1,e===~~e){for(r=0,i=e;i>=10;i/=10,r++);return f.e=r,f.c=[e],void(M=0)}s=e+""}else{if(!p.test(s=e+""))return g(f,s,o);f.s=45===s.charCodeAt(0)?(s=s.slice(1),-1):1}}for((r=s.indexOf("."))>-1&&(s=s.replace(".","")),(i=s.search(/e/i))>0?(0>r&&(r=i),r+=+s.slice(i+1),s=s.substring(0,i)):0>r&&(r=s.length),i=0;48===s.charCodeAt(i);i++);for(u=s.length;48===s.charCodeAt(--u););if(s=s.slice(i,u+1))if(u=s.length,o&&j&&u>15&&L(M,b,f.s*e),r=r-i-1,r>z)f.c=f.e=null;else if(G>r)f.c=[f.e=0];else{if(f.e=r,f.c=[],i=(r+1)%y,0>r&&(i+=y),u>i){for(i&&f.c.push(+s.slice(0,i)),u-=y;u>i;)f.c.push(+s.slice(i,i+=y));s=s.slice(i),i=y-s.length}else i-=u;for(;i--;s+="0");f.c.push(+s)}else f.c=[f.e=0];M=0}function D(e,n,t,i){var o,u,f,c,h,g,p,d=e.indexOf("."),m=P,w=k;for(37>t&&(e=e.toLowerCase()),d>=0&&(f=J,J=0,e=e.replace(".",""),p=new a(t),h=p.pow(e.length-d),J=f,p.c=s(l(r(h.c),h.e),10,n),p.e=p.c.length),g=s(e,t,n),u=f=g.length;0==g[--f];g.pop());if(!g[0])return"0";if(0>d?--u:(h.c=g,h.e=u,h.s=i,h=C(h,p,m,w,n),g=h.c,c=h.r,u=h.e),o=u+m+1,d=g[o],f=n/2,c=c||0>o||null!=g[o+1],c=4>w?(null!=d||c)&&(0==w||w==(h.s<0?3:2)):d>f||d==f&&(4==w||c||6==w&&1&g[o-1]||w==(h.s<0?8:7)),1>o||!g[0])e=c?l("1",-m):"0";else{if(g.length=o,c)for(--n;++g[--o]>n;)g[o]=0,o||(++u,g.unshift(1));for(f=g.length;!g[--f];);for(d=0,e="";f>=d;e+=O.charAt(g[d++]));e=l(e,u)}return e}function _(e,n,t,i){var o,u,s,c,h;if(t=null!=t&&H(t,0,8,i,v)?0|t:k,!e.c)return e.toString();if(o=e.c[0],s=e.e,null==n)h=r(e.c),h=19==i||24==i&&B>=s?f(h,s):l(h,s);else if(e=U(new a(e),n,t),u=e.e,h=r(e.c),c=h.length,19==i||24==i&&(u>=n||B>=u)){for(;n>c;h+="0",c++);h=f(h,u)}else if(n-=s,h=l(h,u),u+1>c){if(--n>0)for(h+=".";n--;h+="0");}else if(n+=u-c,n>0)for(u+1==c&&(h+=".");n--;h+="0");return e.s<0&&o?"-"+h:h}function x(e,n){var t,r,i=0;for(u(e[0])&&(e=e[0]),t=new a(e[0]);++ie||e>t||e!=c(e))&&L(r,(i||"decimal places")+(n>e||e>t?" out of range":" not an integer"),e),!0}function I(e,n,t){for(var r=1,i=n.length;!n[--i];n.pop());for(i=n[0];i>=10;i/=10,r++);return(t=r+t*y-1)>z?e.c=e.e=null:G>t?e.c=[e.e=0]:(e.e=t,e.c=n),e}function L(e,n,t){var r=new Error(["new BigNumber","cmp","config","div","divToInt","eq","gt","gte","lt","lte","minus","mod","plus","precision","random","round","shift","times","toDigits","toExponential","toFixed","toFormat","toFraction","pow","toPrecision","toString","BigNumber"][e]+"() "+n+": "+t);throw r.name="BigNumber Error",M=0,r}function U(e,n,t,r){var i,o,u,s,f,l,c,a=e.c,h=R;if(a){e:{for(i=1,s=a[0];s>=10;s/=10,i++);if(o=n-i,0>o)o+=y,u=n,f=a[l=0],c=f/h[i-u-1]%10|0;else if(l=d((o+1)/y),l>=a.length){if(!r)break e;for(;a.length<=l;a.push(0));f=c=0,i=1,o%=y,u=o-y+1}else{for(f=s=a[l],i=1;s>=10;s/=10,i++);o%=y,u=o-y+i,c=0>u?0:f/h[i-u-1]%10|0}if(r=r||0>n||null!=a[l+1]||(0>u?f:f%h[i-u-1]),r=4>t?(c||r)&&(0==t||t==(e.s<0?3:2)):c>5||5==c&&(4==t||r||6==t&&(o>0?u>0?f/h[i-u]:0:a[l-1])%10&1||t==(e.s<0?8:7)),1>n||!a[0])return a.length=0,r?(n-=e.e+1,a[0]=h[n%y],e.e=-n||0):a[0]=e.e=0,e;if(0==o?(a.length=l,s=1,l--):(a.length=l+1,s=h[y-o],a[l]=u>0?m(f/h[i-u]%h[u])*s:0),r)for(;;){if(0==l){for(o=1,u=a[0];u>=10;u/=10,o++);for(u=a[0]+=s,s=1;u>=10;u/=10,s++);o!=s&&(e.e++,a[0]==N&&(a[0]=1));break}if(a[l]+=s,a[l]!=N)break;a[l--]=0,s=1}for(o=a.length;0===a[--o];a.pop());}e.e>z?e.c=e.e=null:e.et?null!=(e=i[t++]):void 0};return f(n="DECIMAL_PLACES")&&H(e,0,E,2,n)&&(P=0|e),r[n]=P,f(n="ROUNDING_MODE")&&H(e,0,8,2,n)&&(k=0|e),r[n]=k,f(n="EXPONENTIAL_AT")&&(u(e)?H(e[0],-E,0,2,n)&&H(e[1],0,E,2,n)&&(B=0|e[0],$=0|e[1]):H(e,-E,E,2,n)&&(B=-($=0|(0>e?-e:e)))),r[n]=[B,$],f(n="RANGE")&&(u(e)?H(e[0],-E,-1,2,n)&&H(e[1],1,E,2,n)&&(G=0|e[0],z=0|e[1]):H(e,-E,E,2,n)&&(0|e?G=-(z=0|(0>e?-e:e)):j&&L(2,n+" cannot be zero",e))),r[n]=[G,z],f(n="ERRORS")&&(e===!!e||1===e||0===e?(M=0,H=(j=!!e)?F:o):j&&L(2,n+w,e)),r[n]=j,f(n="CRYPTO")&&(e===!!e||1===e||0===e?(V=!(!e||!h||"object"!=typeof h),e&&!V&&j&&L(2,"crypto unavailable",h)):j&&L(2,n+w,e)),r[n]=V,f(n="MODULO_MODE")&&H(e,0,9,2,n)&&(W=0|e),r[n]=W,f(n="POW_PRECISION")&&H(e,0,E,2,n)&&(J=0|e),r[n]=J,f(n="FORMAT")&&("object"==typeof e?X=e:j&&L(2,n+" not an object",e)),r[n]=X,r},a.max=function(){return x(arguments,T.lt)},a.min=function(){return x(arguments,T.gt)},a.random=function(){var e=9007199254740992,n=Math.random()*e&2097151?function(){return m(Math.random()*e)}:function(){return 8388608*(1073741824*Math.random()|0)+(8388608*Math.random()|0)};return function(e){var t,r,i,o,u,s=0,f=[],l=new a(q);if(e=null!=e&&H(e,0,E,14)?0|e:P,o=d(e/y),V)if(h&&h.getRandomValues){for(t=h.getRandomValues(new Uint32Array(o*=2));o>s;)u=131072*t[s]+(t[s+1]>>>11),u>=9e15?(r=h.getRandomValues(new Uint32Array(2)),t[s]=r[0],t[s+1]=r[1]):(f.push(u%1e14),s+=2);s=o/2}else if(h&&h.randomBytes){for(t=h.randomBytes(o*=7);o>s;)u=281474976710656*(31&t[s])+1099511627776*t[s+1]+4294967296*t[s+2]+16777216*t[s+3]+(t[s+4]<<16)+(t[s+5]<<8)+t[s+6],u>=9e15?h.randomBytes(7).copy(t,s):(f.push(u%1e14),s+=7);s=o/7}else j&&L(14,"crypto unavailable",h);if(!s)for(;o>s;)u=n(),9e15>u&&(f[s++]=u%1e14);for(o=f[--s],e%=y,o&&e&&(u=R[y-e],f[s]=m(o/u)*u);0===f[s];f.pop(),s--);if(0>s)f=[i=0];else{for(i=-1;0===f[0];f.shift(),i-=y);for(s=1,u=f[0];u>=10;u/=10,s++);y>s&&(i-=y-s)}return l.e=i,l.c=f,l}}(),C=function(){function e(e,n,t){var r,i,o,u,s=0,f=e.length,l=n%A,c=n/A|0;for(e=e.slice();f--;)o=e[f]%A,u=e[f]/A|0,r=c*o+u*l,i=l*o+r%A*A+s,s=(i/t|0)+(r/A|0)+c*u,e[f]=i%t;return s&&e.unshift(s),e}function n(e,n,t,r){var i,o;if(t!=r)o=t>r?1:-1;else for(i=o=0;t>i;i++)if(e[i]!=n[i]){o=e[i]>n[i]?1:-1;break}return o}function r(e,n,t,r){for(var i=0;t--;)e[t]-=i,i=e[t]1;e.shift());}return function(i,o,u,s,f){var l,c,h,g,p,d,w,v,b,O,S,R,A,E,D,_,x,F=i.s==o.s?1:-1,I=i.c,L=o.c;if(!(I&&I[0]&&L&&L[0]))return new a(i.s&&o.s&&(I?!L||I[0]!=L[0]:L)?I&&0==I[0]||!L?0*F:F/0:0/0);for(v=new a(F),b=v.c=[],c=i.e-o.e,F=u+c+1,f||(f=N,c=t(i.e/y)-t(o.e/y),F=F/y|0),h=0;L[h]==(I[h]||0);h++);if(L[h]>(I[h]||0)&&c--,0>F)b.push(1),g=!0;else{for(E=I.length,_=L.length,h=0,F+=2,p=m(f/(L[0]+1)),p>1&&(L=e(L,p,f),I=e(I,p,f),_=L.length,E=I.length),A=_,O=I.slice(0,_),S=O.length;_>S;O[S++]=0);x=L.slice(),x.unshift(0),D=L[0],L[1]>=f/2&&D++;do p=0,l=n(L,O,_,S),0>l?(R=O[0],_!=S&&(R=R*f+(O[1]||0)),p=m(R/D),p>1?(p>=f&&(p=f-1),d=e(L,p,f),w=d.length,S=O.length,l=n(d,O,w,S),1==l&&(p--,r(d,w>_?x:L,w,f))):(0==p&&(l=p=1),d=L.slice()),w=d.length,S>w&&d.unshift(0),r(O,d,S,f),-1==l&&(S=O.length,l=n(L,O,_,S),1>l&&(p++,r(O,S>_?x:L,S,f))),S=O.length):0===l&&(p++,O=[0]),b[h++]=p,l&&O[0]?O[S++]=I[A]||0:(O=[I[A]],S=1);while((A++=10;F/=10,h++);U(v,u+(v.e=h+c*y-1)+1,s,g)}else v.e=c,v.r=+g;return v}}(),g=function(){var e=/^(-?)0([xbo])(\w[\w.]*$)/i,n=/^([^.]+)\.$/,t=/^\.([^.]+)$/,r=/^-?(Infinity|NaN)$/,i=/^\s*\+([\w.])|^\s+|\s+$/g;return function(o,u,s,f){var l,c=s?u:u.replace(i,"$1");if(r.test(c))o.s=isNaN(c)?null:0>c?-1:1;else{if(!s&&(c=c.replace(e,function(e,n,t){return l="x"==(t=t.toLowerCase())?16:"b"==t?2:8,f&&f!=l?e:n}),f&&(l=f,c=c.replace(n,"$1").replace(t,"0.$1")),u!=c))return new a(c,l);j&&L(M,"not a"+(f?" base "+f:"")+" number",u),o.s=null}o.c=o.e=null,M=0}}(),T.absoluteValue=T.abs=function(){var e=new a(this);return e.s<0&&(e.s=1),e},T.ceil=function(){return U(new a(this),this.e+1,2)},T.comparedTo=T.cmp=function(e,n){return M=1,i(this,new a(e,n))},T.decimalPlaces=T.dp=function(){var e,n,r=this.c;if(!r)return null;if(e=((n=r.length-1)-t(this.e/y))*y,n=r[n])for(;n%10==0;n/=10,e--);return 0>e&&(e=0),e},T.dividedBy=T.div=function(e,n){return M=3,C(this,new a(e,n),P,k)},T.dividedToIntegerBy=T.divToInt=function(e,n){return M=4,C(this,new a(e,n),0,1)},T.equals=T.eq=function(e,n){return M=5,0===i(this,new a(e,n))},T.floor=function(){return U(new a(this),this.e+1,3)},T.greaterThan=T.gt=function(e,n){return M=6,i(this,new a(e,n))>0},T.greaterThanOrEqualTo=T.gte=function(e,n){return M=7,1===(n=i(this,new a(e,n)))||0===n},T.isFinite=function(){return!!this.c},T.isInteger=T.isInt=function(){return!!this.c&&t(this.e/y)>this.c.length-2},T.isNaN=function(){return!this.s},T.isNegative=T.isNeg=function(){return this.s<0},T.isZero=function(){return!!this.c&&0==this.c[0]},T.lessThan=T.lt=function(e,n){return M=8,i(this,new a(e,n))<0},T.lessThanOrEqualTo=T.lte=function(e,n){return M=9,-1===(n=i(this,new a(e,n)))||0===n},T.minus=T.sub=function(e,n){var r,i,o,u,s=this,f=s.s;if(M=10,e=new a(e,n),n=e.s,!f||!n)return new a(0/0);if(f!=n)return e.s=-n,s.plus(e);var l=s.e/y,c=e.e/y,h=s.c,g=e.c;if(!l||!c){if(!h||!g)return h?(e.s=-n,e):new a(g?s:0/0);if(!h[0]||!g[0])return g[0]?(e.s=-n,e):new a(h[0]?s:3==k?-0:0)}if(l=t(l),c=t(c),h=h.slice(),f=l-c){for((u=0>f)?(f=-f,o=h):(c=l,o=g),o.reverse(),n=f;n--;o.push(0));o.reverse()}else for(i=(u=(f=h.length)<(n=g.length))?f:n,f=n=0;i>n;n++)if(h[n]!=g[n]){u=h[n]0)for(;n--;h[r++]=0);for(n=N-1;i>f;){if(h[--i]0?(s=u,r=l):(o=-o,r=f),r.reverse();o--;r.push(0));r.reverse()}for(o=f.length,n=l.length,0>o-n&&(r=l,l=f,f=r,n=o),o=0;n;)o=(f[--n]=f[n]+l[n]+o)/N|0,f[n]%=N;return o&&(f.unshift(o),++s),I(e,f,s)},T.precision=T.sd=function(e){var n,t,r=this,i=r.c;if(null!=e&&e!==!!e&&1!==e&&0!==e&&(j&&L(13,"argument"+w,e),e!=!!e&&(e=null)),!i)return null;if(t=i.length-1,n=t*y+1,t=i[t]){for(;t%10==0;t/=10,n--);for(t=i[0];t>=10;t/=10,n++);}return e&&r.e+1>n&&(n=r.e+1),n},T.round=function(e,n){var t=new a(this);return(null==e||H(e,0,E,15))&&U(t,~~e+this.e+1,null!=n&&H(n,0,8,15,v)?0|n:k),t},T.shift=function(e){var n=this;return H(e,-S,S,16,"argument")?n.times("1e"+c(e)):new a(n.c&&n.c[0]&&(-S>e||e>S)?n.s*(0>e?0:1/0):n)},T.squareRoot=T.sqrt=function(){var e,n,i,o,u,s=this,f=s.c,l=s.s,c=s.e,h=P+4,g=new a("0.5");if(1!==l||!f||!f[0])return new a(!l||0>l&&(!f||f[0])?0/0:f?s:1/0);if(l=Math.sqrt(+s),0==l||l==1/0?(n=r(f),(n.length+c)%2==0&&(n+="0"),l=Math.sqrt(n),c=t((c+1)/2)-(0>c||c%2),l==1/0?n="1e"+c:(n=l.toExponential(),n=n.slice(0,n.indexOf("e")+1)+c),i=new a(n)):i=new a(l+""),i.c[0])for(c=i.e,l=c+h,3>l&&(l=0);;)if(u=i,i=g.times(u.plus(C(s,u,h,1))),r(u.c).slice(0,l)===(n=r(i.c)).slice(0,l)){if(i.el&&(m=O,O=S,S=m,o=l,l=g,g=o),o=l+g,m=[];o--;m.push(0));for(w=N,v=A,o=g;--o>=0;){for(r=0,p=S[o]%v,d=S[o]/v|0,s=l,u=o+s;u>o;)c=O[--s]%v,h=O[s]/v|0,f=d*c+h*p,c=p*c+f%v*v+m[u]+r,r=(c/w|0)+(f/v|0)+d*h,m[u--]=c%w;m[u]=r}return r?++i:m.shift(),I(e,m,i)},T.toDigits=function(e,n){var t=new a(this);return e=null!=e&&H(e,1,E,18,"precision")?0|e:null,n=null!=n&&H(n,0,8,18,v)?0|n:k,e?U(t,e,n):t},T.toExponential=function(e,n){return _(this,null!=e&&H(e,0,E,19)?~~e+1:null,n,19)},T.toFixed=function(e,n){return _(this,null!=e&&H(e,0,E,20)?~~e+this.e+1:null,n,20)},T.toFormat=function(e,n){var t=_(this,null!=e&&H(e,0,E,21)?~~e+this.e+1:null,n,21);if(this.c){var r,i=t.split("."),o=+X.groupSize,u=+X.secondaryGroupSize,s=X.groupSeparator,f=i[0],l=i[1],c=this.s<0,a=c?f.slice(1):f,h=a.length;if(u&&(r=o,o=u,u=r,h-=r),o>0&&h>0){for(r=h%o||o,f=a.substr(0,r);h>r;r+=o)f+=s+a.substr(r,o);u>0&&(f+=s+a.slice(r)),c&&(f="-"+f)}t=l?f+X.decimalSeparator+((u=+X.fractionGroupSize)?l.replace(new RegExp("\\d{"+u+"}\\B","g"),"$&"+X.fractionGroupSeparator):l):f}return t},T.toFraction=function(e){var n,t,i,o,u,s,f,l,c,h=j,g=this,p=g.c,d=new a(q),m=t=new a(q),w=f=new a(q);if(null!=e&&(j=!1,s=new a(e),j=h,(!(h=s.isInt())||s.lt(q))&&(j&&L(22,"max denominator "+(h?"out of range":"not an integer"),e),e=!h&&s.c&&U(s,s.e+1,1).gte(q)?s:null)),!p)return g.toString();for(c=r(p),o=d.e=c.length-g.e-1,d.c[0]=R[(u=o%y)<0?y+u:u],e=!e||s.cmp(d)>0?o>0?d:m:s,u=z,z=1/0,s=new a(c),f.c[0]=0;l=C(s,d,0,1),i=t.plus(l.times(w)),1!=i.cmp(e);)t=w,w=i,m=f.plus(l.times(i=m)),f=i,d=s.minus(l.times(i=d)),s=i;return i=C(e.minus(t),w,0,1),f=f.plus(i.times(m)),t=t.plus(i.times(w)),f.s=m.s=g.s,o*=2,n=C(m,w,o,k).minus(g).abs().cmp(C(f,t,o,k).minus(g).abs())<1?[m.toString(),w.toString()]:[f.toString(),t.toString()],z=u,n},T.toNumber=function(){var e=this;return+e||(e.s?0*e.s:0/0)},T.toPower=T.pow=function(e){var n,t,r=m(0>e?-e:+e),i=this;if(!H(e,-S,S,23,"exponent")&&(!isFinite(e)||r>S&&(e/=0)||parseFloat(e)!=e&&!(e=0/0)))return new a(Math.pow(+i,e));for(n=J?d(J/y+2):0,t=new a(q);;){if(r%2){if(t=t.times(i),!t.c)break;n&&t.c.length>n&&(t.c.length=n)}if(r=m(r/2),!r)break;i=i.times(i),n&&i.c&&i.c.length>n&&(i.c.length=n)}return 0>e&&(t=q.div(t)),n?U(t,J,k):t},T.toPrecision=function(e,n){return _(this,null!=e&&H(e,1,E,24,"precision")?0|e:null,n,24)},T.toString=function(e){var n,t=this,i=t.s,o=t.e;return null===o?i?(n="Infinity",0>i&&(n="-"+n)):n="NaN":(n=r(t.c),n=null!=e&&H(e,2,64,25,"base")?D(l(n,o),0|e,10,i):B>=o||o>=$?f(n,o):l(n,o),0>i&&t.c[0]&&(n="-"+n)),n},T.truncated=T.trunc=function(){return U(new a(this),this.e+1,1)},T.valueOf=T.toJSON=function(){return this.toString()},null!=e&&a.config(e),a}function t(e){var n=0|e;return e>0||e===n?n:n-1}function r(e){for(var n,t,r=1,i=e.length,o=e[0]+"";i>r;){for(n=e[r++]+"",t=y-n.length;t--;n="0"+n);o+=n}for(i=o.length;48===o.charCodeAt(--i););return o.slice(0,i+1||1)}function i(e,n){var t,r,i=e.c,o=n.c,u=e.s,s=n.s,f=e.e,l=n.e;if(!u||!s)return null;if(t=i&&!i[0],r=o&&!o[0],t||r)return t?r?0:-s:u;if(u!=s)return u;if(t=0>u,r=f==l,!i||!o)return r?0:!i^t?1:-1;if(!r)return f>l^t?1:-1;for(s=(f=i.length)<(l=o.length)?f:l,u=0;s>u;u++)if(i[u]!=o[u])return i[u]>o[u]^t?1:-1;return f==l?0:f>l^t?1:-1}function o(e,n,t){return(e=c(e))>=n&&t>=e}function u(e){return"[object Array]"==Object.prototype.toString.call(e)}function s(e,n,t){for(var r,i,o=[0],u=0,s=e.length;s>u;){for(i=o.length;i--;o[i]*=n);for(o[r=0]+=O.indexOf(e.charAt(u++));rt-1&&(null==o[r+1]&&(o[r+1]=0),o[r+1]+=o[r]/t|0,o[r]%=t)}return o.reverse()}function f(e,n){return(e.length>1?e.charAt(0)+"."+e.slice(1):e)+(0>n?"e":"e+")+n}function l(e,n){var t,r;if(0>n){for(r="0.";++n;r+="0");e=r+e}else if(t=e.length,++n>t){for(r="0",n-=t;--n;r+="0");e+=r}else t>n&&(e=e.slice(0,n)+"."+e.slice(n));return e}function c(e){return e=parseFloat(e),0>e?d(e):m(e)}var a,h,g,p=/^-?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,d=Math.ceil,m=Math.floor,w=" not a boolean or binary digit",v="rounding mode",b="number type has more than 15 significant digits",O="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_",N=1e14,y=14,S=9007199254740991,R=[1,10,100,1e3,1e4,1e5,1e6,1e7,1e8,1e9,1e10,1e11,1e12,1e13],A=1e7,E=1e9;if(a=n(),"function"==typeof define&&define.amd)define(function(){return a});else if("undefined"!=typeof module&&module.exports){if(module.exports=a,!h)try{h=require("crypto")}catch(D){}}else e.BigNumber=a}(this); +//# sourceMappingURL=doc/bignumber.js.map diff --git a/signer/rules/deps/bindata.go b/signer/rules/deps/bindata.go new file mode 100644 index 0000000000..0b27f45172 --- /dev/null +++ b/signer/rules/deps/bindata.go @@ -0,0 +1,235 @@ +// Code generated by go-bindata. +// sources: +// bignumber.js +// DO NOT EDIT! + +package deps + +import ( + "bytes" + "compress/gzip" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "strings" + "time" +) + +func bindataRead(data []byte, name string) ([]byte, error) { + gz, err := gzip.NewReader(bytes.NewBuffer(data)) + if err != nil { + return nil, fmt.Errorf("Read %q: %v", name, err) + } + + var buf bytes.Buffer + _, err = io.Copy(&buf, gz) + clErr := gz.Close() + + if err != nil { + return nil, fmt.Errorf("Read %q: %v", name, err) + } + if clErr != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +type asset struct { + bytes []byte + info os.FileInfo +} + +type bindataFileInfo struct { + name string + size int64 + mode os.FileMode + modTime time.Time +} + +func (fi bindataFileInfo) Name() string { + return fi.name +} +func (fi bindataFileInfo) Size() int64 { + return fi.size +} +func (fi bindataFileInfo) Mode() os.FileMode { + return fi.mode +} +func (fi bindataFileInfo) ModTime() time.Time { + return fi.modTime +} +func (fi bindataFileInfo) IsDir() bool { + return false +} +func (fi bindataFileInfo) Sys() interface{} { + return nil +} + +var _bignumberJs = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\xbc\x6b\x77\x9b\xc8\x93\x38\xfc\x7e\x3f\x85\xc4\xc6\x9c\x6e\x53\x20\x90\x9d\x38\x86\x14\x9c\x4c\x62\xe7\xe7\x79\x1c\x3b\x4f\x9c\xcc\xcc\xae\xa2\xc9\x91\x51\x23\x75\x82\x40\xe1\x62\xc7\x09\xfe\x7d\xf6\xff\xa9\x6e\x40\xf2\x25\xbb\xb3\x6f\x2c\xe8\x4b\x75\x75\x75\xdd\xbb\xf0\x68\x77\x70\x29\x17\x59\xbd\xba\x14\x85\xf3\xa5\x1c\x5c\x8d\x1d\xd7\xd9\x1b\x2c\xab\x6a\x5d\xfa\xa3\xd1\x42\x56\xcb\xfa\xd2\x89\xf3\xd5\xe8\xad\xfc\x2a\xde\xc6\xe9\x68\x7b\xf8\xe8\xf4\xe4\xd5\xd1\xd9\xab\xa3\xc1\xee\xe8\x3f\x46\xbb\x83\x55\x3e\x97\x89\x14\xf3\xc1\xe5\xcd\xe0\x87\x48\xe5\x62\x50\xe5\x83\x44\x7e\x7f\x0c\x5c\x91\x5f\x8a\xa2\xfa\x5a\xc8\x95\xc8\x46\x79\x55\xe5\xff\x59\x88\x45\x9d\xce\x0a\x5b\x7c\x5f\x17\xa2\x2c\x65\x9e\xd9\x32\x8b\xf3\xd5\x7a\x56\xc9\x4b\x99\xca\xea\x86\x96\x19\x26\x75\x16\x57\x32\xcf\x98\xe0\x3f\x8d\xba\x14\x83\xb2\x2a\x64\x5c\x19\x41\xd7\x31\x50\x5d\xfd\xdb\x8c\x09\xc8\xf8\xcf\xab\x59\x31\xa8\xa0\x00\x09\x39\xd4\x50\x42\x82\xd5\x52\x96\x81\x4c\xd8\x90\x25\x03\x99\x95\xd5\x2c\x8b\x45\x9e\x0c\x66\x9c\x17\xa2\xaa\x8b\x6c\xf0\xc5\x34\x4f\xd9\xf8\x19\x18\x71\x9e\x95\x55\x51\xc7\x55\x5e\x0c\xe2\x59\x9a\x0e\xae\x65\xb5\xcc\xeb\x6a\x90\x89\x6b\x03\x04\x87\x4c\x5c\xb7\xeb\x10\xc0\xac\x4e\xd3\x21\x66\xa6\xf9\x2f\x96\xc1\x18\x9e\xed\xc3\x5b\x30\x2e\x67\xa5\x30\x38\xff\x49\xfd\xe8\x36\x19\x94\x28\x2c\xc3\x00\xcf\x45\xcc\xba\x15\x13\x6c\x21\xdd\x41\x28\x12\x7e\xc9\xe1\x23\x4b\xe0\x9d\x95\x38\xc2\xf2\xe0\xab\x5a\x87\xe5\x68\xe8\xa3\x30\x10\xab\x9b\x35\x0d\x16\xdc\x34\xdd\x5d\x31\x44\xb7\x69\x86\x04\xec\xbd\x58\x1c\x7d\x5f\x33\xe3\x6f\x3b\x32\x2c\x56\xa1\x31\x31\xac\x73\xa7\x4c\x65\x2c\x98\x0b\x19\xb7\x8c\xa9\x65\x70\xcb\x60\x91\xff\xe9\x93\x63\x58\x95\x65\xf0\xe8\x89\x01\x7b\x07\x61\x16\x19\xd2\xf0\x0d\x83\x3b\x95\x28\x2b\x56\xf6\x84\x59\xb0\x04\x4a\xc8\x69\xbb\x79\xc4\x12\xa7\x44\x37\xf4\x46\x22\x62\x25\x96\x2d\x68\x8f\x83\xed\x71\xdf\x83\x2f\xa6\x59\x3a\x85\x58\xa7\xb3\x58\xb0\xd1\xdf\xee\x27\xc7\xdd\x6d\x3e\x39\x23\x20\xb8\xa9\xc8\x16\xd5\x32\xf4\x9e\x12\xa5\xdf\xc2\x25\xd1\x32\xc7\xa1\xc7\x7d\x02\xba\xff\x14\x11\x4b\x27\x5e\xce\x8a\x57\xf9\x5c\xbc\xac\x98\xcb\x1f\x5d\xa3\xc4\xd7\xac\x04\xcf\x85\x0c\x12\xa7\xe4\xb7\x22\x2d\x05\x11\xfa\x2e\x19\x7b\x22\x3b\x25\x0a\xa7\x84\xc4\x11\x28\x1c\x01\x89\x13\x23\xa3\xc7\x98\x47\xa2\x05\xcd\x7d\x01\x57\xb9\x9c\xb3\xb7\xe8\xfe\x6f\xb4\x46\x74\xd5\xb1\x6e\xd1\x41\xa0\x2d\x5a\xdc\x04\x22\xfe\xfb\xdf\xc4\x90\x79\xc1\x0a\x74\x41\xa2\x08\x64\x88\x9e\x1b\xc8\x11\x7a\x2e\x14\x96\xc5\x83\x1e\x35\x81\x85\x42\x68\x22\xa6\x1b\x04\x6e\x35\xaf\xf4\xfb\x1a\xae\xdb\x13\x51\xcd\xf7\x8f\x85\x07\xff\x17\xe2\xdd\xde\x12\x62\xac\xc0\xd2\x91\xd9\x5c\x7c\x3f\x4f\x98\xe1\x18\x9c\x87\xb6\x67\x9a\x6a\x7c\x77\x78\x86\x63\xd0\xa1\x71\x60\x92\xa0\x88\x59\x11\x2f\xd9\x48\x8c\x24\xe7\xa1\x1b\x31\x37\x2c\x4c\x93\x15\x28\x39\x14\x16\x5a\xdd\x3a\xd2\xf2\x38\xa8\x65\xeb\x4b\x92\xd4\x6c\xc1\x5c\x90\x9c\xfb\xdd\xf8\xb2\xe5\x02\x0e\x12\xdd\x60\xff\xf9\x7d\xb4\x25\x0f\x24\x91\x88\xd0\xac\xfb\xd1\x8f\x0c\xb4\xed\x9a\x07\xea\xb0\x36\xbb\x94\x50\x5b\x1e\xe7\x32\xd9\x9a\x0a\xb9\x69\x7e\x31\xcd\x7a\x8b\xed\x12\xa7\xdc\x15\x1c\x0a\x2c\x6c\x69\x7b\x50\x84\x3f\x38\x1d\x02\x1d\x07\x09\x73\x40\x84\x1f\xc8\x84\xbd\x09\x0b\xd5\x31\xa1\x1e\x77\x1a\x74\x07\xb2\x75\x6e\x53\x90\xc8\x0a\xcb\xe3\x3b\x37\xa0\xb7\x28\x2d\xbc\xe1\x50\x87\x52\xf3\x80\x34\xcd\xc4\x89\x9d\x75\x5d\x2e\x59\x4f\x25\x45\x12\xa8\x6d\xbc\x09\xea\x50\x06\xfc\xe1\x08\x09\x0a\x0e\x0f\xb6\x36\x47\x24\xbb\xb1\xbb\x7d\xdd\x6a\x2c\x6d\xac\x15\xad\x02\x69\xdb\x41\x69\xa1\xe1\x1a\xc4\x11\x3d\x3c\x2d\x1e\x83\xed\x6d\xbc\x45\xf7\xb6\xd7\x97\xaf\x49\x8f\x41\x05\x52\xeb\x4c\xd2\x96\x09\xc4\xb0\x84\x05\xac\x61\x8e\xe2\x0e\x9b\xc0\x0a\xdf\xc1\x35\x7e\x55\x2b\xee\x1d\x84\x95\x69\x2a\x51\xaa\xf2\xd3\xfc\x5a\x14\xaf\x66\xa5\x60\x9c\xc3\x3c\x44\xd7\x34\x59\x82\xbf\xc3\xef\xe8\x02\x8d\xb8\xc7\x55\xb0\x6e\x55\x5f\xc5\x61\x89\x6b\x67\x9d\x5f\x33\xd1\x6e\xcc\x9e\x73\xf8\x1d\x13\x58\x3b\x31\x96\x2c\x65\x05\x5b\x3a\x31\x87\xa5\x23\xb8\x12\x7a\x0e\x6b\x47\xe0\xda\x89\x7b\x4e\x5a\x60\xc9\x04\x54\xd4\x55\x63\x82\x8b\x8e\x69\x5c\xc4\xc5\xc4\xb6\x93\x69\xb0\x70\xd6\xf9\x9a\x71\xc5\x2e\xc3\xc5\xc4\x9d\xb6\x42\x64\xb8\x06\x35\xb9\xe1\x3c\xb2\xed\xda\xa7\x95\x70\x41\x4b\x61\x0d\x4b\xa7\x44\x09\x4b\x7c\xc5\x96\xb0\x86\x15\x5c\x13\xfc\x05\x2e\x9d\x18\x62\x5c\x3a\x05\xd4\xa8\x70\xca\xb1\xb6\x56\x96\x07\x73\x5c\x4c\xf2\x29\x24\x98\x8d\xc6\x10\x63\xdc\x34\x6e\x98\x37\x8d\x36\x0f\x8b\x49\x6e\x79\x53\x88\x71\x3f\xbc\x8e\x5a\x93\x31\x6f\x9a\x98\x9b\x26\x73\x11\xaf\x9b\xe6\x1a\x91\x2d\x9d\xf2\x85\x1b\xed\xf9\x63\xce\xfd\x79\x98\x34\xcd\x1c\x31\x31\x4d\xb6\xaf\x46\xc4\x4d\xf3\x0c\xf1\xda\x34\x3d\x73\x31\xc9\x6d\x6f\xba\x3d\xe9\xb9\x7f\xc0\x39\x78\xb4\xa2\xde\xa0\xc0\x38\x4a\x99\xe1\x19\x60\xaf\xb8\x4f\x1b\xed\xd8\xb7\xa3\x0f\xe6\x10\x73\x3a\x49\xdb\xce\x02\xcb\x22\x52\xe5\xd3\x30\x0b\x38\xed\x03\x5d\xc8\x9b\x86\x59\x56\x0d\x0b\xa7\xce\xca\xa5\x4c\x2a\xe6\x71\x2d\x98\x5b\x34\x1e\xb6\x14\xd6\x1d\x73\x75\xdc\x86\x11\x24\x21\xce\x03\x61\xe1\xb9\x12\xd9\x97\x15\x5b\x4c\xe6\x96\x35\xe5\x3c\x10\x98\x32\x01\x35\xbf\x6d\xd5\x98\xd8\xf0\xe2\xe7\x87\xbc\x58\x12\x2f\xd2\x11\x55\xa8\x89\x56\x91\x9d\xad\xc0\x85\xe7\x20\xe1\x8a\x47\x6e\x53\xf9\x5f\x61\x48\xea\xbc\x03\xe8\x54\xf9\x85\x56\x3d\xea\xbc\x73\xd2\xf5\x13\x77\x4a\x26\xd8\x11\x40\x60\xc8\x06\x2f\xb1\x60\x42\x31\x16\x7a\x87\x88\xb2\x69\xc6\xfb\x88\xd2\x34\x7f\x0b\xb1\x8c\x12\xb6\x84\x92\xfb\xa9\xfa\xe9\x15\x82\xc0\x8f\xac\x35\xd9\x9c\x30\x25\x7e\x23\x98\x3d\x2c\x62\x8c\x56\xed\xdc\x05\xca\xea\x10\xb3\xa6\xf9\x2d\xc4\x9a\x6b\xc5\x10\x64\x61\x1c\x2c\x95\xc0\x42\x4c\x1a\x6f\x89\xb4\x68\xdd\x0a\x2c\x39\x0e\x36\x96\xb0\xc4\x54\xb5\x92\x66\x0b\x63\x65\x79\x6c\x3b\x0b\x5d\x75\x70\x34\xdd\x31\x82\xcc\xb6\x5b\x48\x3c\xd8\xcc\xb6\xb0\xb6\x63\xe8\x86\xd6\x96\x87\x18\x9b\x66\x3b\x87\xdf\x99\xd4\x53\xae\x7c\xe1\x9a\x66\x1e\x19\xb6\x61\x2d\xfd\xe5\xe6\x64\xbe\xdf\xf3\xaa\xd0\xd5\x0a\x9a\x09\x62\x35\xad\x05\xe8\x09\xaa\xce\xa5\xa1\xb7\xc0\xb2\xe4\x8b\x4e\xac\x03\x85\x7b\xd1\xf7\xcb\x29\x87\x61\xe1\x94\xfc\x67\x85\x45\x70\x59\x88\xd9\xd7\xdb\xcc\x21\x7f\x8b\x55\x50\x10\xcc\x0a\x8b\x9e\x4b\xaa\x0d\x2e\xc7\x2d\x97\x14\xc4\x27\xba\x9b\x65\xa1\x68\x1a\x11\x56\x4d\x23\x86\x18\x33\xc1\x39\xe9\xfa\x02\x98\x6c\x1a\x63\x2e\x62\xb9\x9a\xa5\x03\xa5\x81\x4a\x83\x5b\xfd\xf0\xc8\x18\x90\x5f\x97\x27\x83\x62\x96\x2d\x84\xe1\x1b\x83\x2c\xaf\x06\xb3\x6c\x20\xb3\x4a\x2c\x44\x61\x70\xf2\x51\x86\x5b\xfa\xf2\x44\xaf\xae\xcf\x90\xe8\x51\xa0\x07\x12\xb3\x5e\x1e\xb2\x89\x6d\xcb\x69\x90\x75\x1a\x47\x19\x01\xcc\x26\xee\xf4\x57\x7e\x00\x6d\xd4\xaa\x76\x6f\x6c\x8f\x87\x3f\x22\xe1\xc4\xc4\x53\x8a\xdd\xfd\x37\x61\xa5\x1a\x26\x42\xa9\x6e\x9f\xd1\x6f\x05\xd4\x94\x71\xd8\x12\x9d\xd3\x0e\x2d\x8d\x12\x11\xf9\xa8\x28\xf2\x82\x4d\x0c\x7a\xfe\x4d\x2e\xce\xb4\x3b\x03\x46\xbc\x5a\x1b\xca\xc9\x4d\xe4\xc2\x00\x63\x2e\xaf\xf4\xdf\x0f\xf9\x49\x56\x19\x60\x88\x6f\x06\x18\x8b\x4a\xfd\x11\x06\x18\x69\xa5\xfe\xd0\xe3\x4a\x66\x75\x49\xbf\xf9\xdc\x00\x63\x9d\xaa\x97\x75\x21\x62\x49\xfe\xbb\x01\x46\x31\xcb\xe6\xf9\x8a\x1e\xf2\x3a\xa3\x31\x4a\x6f\x18\x60\x54\x72\x25\x68\x70\x95\xbf\x96\x0b\x59\xe9\xc7\xa3\xef\xeb\x3c\x13\x59\x25\x67\xa9\x7a\x3f\x96\xdf\xc5\x5c\x3f\xe5\xc5\x6a\x56\xe9\xc7\x62\xa6\xb6\x48\x2b\xe5\xd7\xaa\xe9\xdd\xd6\x8a\x9d\xac\x1b\x60\x6c\x36\x39\x9d\x88\xa9\x65\x30\x3e\x30\xac\xcc\x32\xfc\x81\x61\x55\x3c\xa8\x96\x45\x7e\x3d\x28\x9c\x6c\xb6\x12\xb8\x19\xac\xe9\x64\xc0\x5b\x74\xa1\xd8\x10\xf4\x63\xc7\x65\x9a\xa4\x7d\x1c\x01\x29\xc4\x30\x23\x95\x02\x4b\x7c\x4f\xfa\x65\xc6\x7f\x0a\x5f\xdb\x7a\x24\xe7\x74\x46\x47\x5d\xaa\xa3\x2e\xd5\x51\x2b\x7f\x46\x29\xa2\xcc\x96\xe0\x86\x39\xcf\x2d\xbc\x81\x1a\x33\x48\x70\x36\x49\xd1\x25\xc3\x90\x8c\x96\x13\x69\xd7\xb6\x37\xdd\xf1\xdc\xc6\xed\x75\x4e\x8a\x73\xc6\x72\xcb\xe3\xa3\x1b\x0e\x69\x88\xb3\xce\xec\x29\xd7\xb0\xe0\x4a\x72\x06\x42\x3b\x01\x5d\xe7\x0b\x4c\x83\x99\x76\x01\x5c\xe2\x41\x8c\x95\x2b\xea\x41\xbe\xa3\x56\xce\xed\x1b\xcb\xd3\x0e\xa6\xd6\xe7\x84\x76\x4a\xce\x8c\xf7\x10\xf5\xad\x39\x12\x62\x74\xc3\x3a\x72\xfd\x7b\xe8\xde\x2a\xd9\x2e\xc8\xe6\x65\x9d\xcd\x9b\x4d\x52\x8b\x8c\x14\xa3\x19\x89\x9f\xec\x74\x33\xc8\xf5\xda\x0f\xab\x88\xc5\x4d\x53\xb4\x16\xb0\x6a\x9a\x0a\x91\x89\x2d\x0b\x18\x87\x4f\x9b\xe6\xa9\xd6\x5a\xfb\x6a\x44\xa1\x2c\x20\x79\x1d\x79\xe8\x46\x75\xe8\x46\x2d\x1a\x53\xdf\xf5\x67\x93\x94\x60\xef\x78\xae\xe9\x6d\x03\xeb\x2c\x63\xd6\x34\xc3\xd9\xc6\xf4\x0f\x3a\x5a\xd1\xb9\x47\xa4\x6c\x85\x0a\xb6\x68\x08\x2e\x27\xd9\xce\xcd\x14\x48\xda\xec\xac\x69\x5c\xee\xab\x66\x25\x85\x20\x94\xcb\x80\x98\x47\xac\x87\x91\x42\x89\x1e\xa4\xb6\xcd\xfd\xad\x46\x8b\xf8\x61\x39\xb9\xb1\xf3\x29\x10\x7d\x91\x50\x5e\xb1\x0e\xe9\x9d\xe5\xa4\x9e\xf2\xdd\xd2\x77\x39\x14\x4a\x4b\x07\x5a\x4b\xba\x88\xa9\xd6\x30\x39\x7a\x50\x6b\x96\xaa\xd5\xb9\xd4\xea\x5c\xf2\x8d\x8b\x4c\x7d\x16\x96\xb4\xfe\x9d\x21\xa5\x3a\xba\x21\x96\xa4\x9d\x1d\x61\x59\x7a\x67\x78\x66\x9a\x4c\x3d\x91\x31\xd7\x6a\x97\x98\x78\x92\x2a\x28\xf4\x3b\xc4\x33\xcd\x55\x01\x91\xd4\x26\x57\xa0\x44\xef\x56\xa3\x33\xdb\x72\xae\x70\xa6\x5c\x06\xe2\x34\xad\xeb\x6e\x85\x23\xee\xab\x30\xe1\x88\x17\x6f\x14\x0e\xbd\x1a\xdb\xb2\xfd\x24\x5b\xaf\x94\xec\x7d\xc0\x99\xb3\x2e\xf2\x2a\xa7\x70\x0b\xbe\xb5\x76\xc2\xe3\xf0\x0e\xc7\x2e\x7c\xc5\x7d\xf8\x0d\xed\x03\x78\x82\x63\x0f\xde\xa0\xed\x89\x03\xf8\x81\xf4\xf7\x0b\x0e\x5d\xf8\x17\x1e\xc3\x1f\x38\xf4\xe0\x4f\xf4\xe0\x77\xf4\x5c\x17\xfe\xc2\x9f\xad\xe6\xbf\x10\xeb\x59\x31\xab\xf2\xc2\x27\xf7\x73\x51\xe4\xf5\x7a\xab\x09\xba\x26\xf9\x43\xf8\x7b\x50\x8a\x38\xcf\xe6\xb3\xe2\xe6\x4d\xdf\xe8\x42\xd2\x2a\xa1\x37\xf7\xe6\x0e\x8c\x7b\x5d\x6a\xf8\x6d\xd0\xb3\xd8\x2c\xcb\xab\xa5\x28\x30\x83\x99\xf3\xfe\xfc\xe3\xd9\xeb\xcf\x1f\xdf\xa1\xdb\xbf\xbc\x3e\xff\xf3\x0c\xbd\xfe\xf5\xd5\xd1\xc9\x29\x8e\xfb\xd7\xe3\xd3\xf3\xf3\xf7\xb8\xd7\xbf\xff\xeb\xe5\xe9\x31\xcd\xdf\xbf\xdb\xa2\x80\x3c\xbd\xdb\x76\xf4\xc7\xd1\x19\x3e\xbb\xdb\xa6\xa0\x1f\xdc\x6d\xd3\x4b\x3c\x87\x99\x73\xf4\xf1\xd5\xe9\xc9\x6b\x3c\x84\x99\xa3\x6d\x03\xf6\xa9\x17\xad\x02\x95\x3e\x24\x61\xc1\x9f\xb7\x20\x71\x56\x2c\xea\x95\xc8\x2a\xe2\x3c\x49\xee\x55\x42\xac\x66\xe4\x97\x5f\x44\x5c\x6d\xa2\xe6\x32\xda\x02\xd3\x92\xa5\x74\x96\xb3\xf2\xfc\x3a\x7b\x57\xe4\x6b\x51\x54\x37\x2c\xe3\x91\x56\x19\x4c\x60\x39\xc9\xa6\xdc\xa7\x60\x78\xe0\xde\xfa\x0f\x27\xcb\x2e\x8d\x50\x6d\xe6\xc8\x49\x45\xce\x65\x37\xab\x8f\xaf\x59\x86\xc6\xeb\xa3\x57\x27\x6f\x5f\x9e\x7e\x7e\x77\xfa\xf2\xd5\xd1\x85\xc1\xc9\x7f\x14\xe0\xc2\x11\x8c\x21\x23\xe5\xf3\x0e\xdd\x86\xa2\xc1\x49\x36\xc5\x77\xa0\xe6\x28\x02\x9d\x9c\xbd\xf9\xfc\xf6\xfc\xf5\xd1\x66\xca\xf3\x6e\xca\xd7\xad\x29\x5f\xf5\x94\xa3\xbf\xde\x9d\x9f\x1d\x9d\x7d\x38\x79\x79\xfa\xf9\xe5\x07\x9a\x43\xde\x11\x8f\xfe\xa5\x5c\x21\xb0\x8f\xc0\x6d\x67\x53\x8b\x37\xdd\xc6\xe0\x37\x02\x47\xa3\x9e\xa8\x07\x6f\xca\x7d\x5a\xd0\x3e\xda\x1e\x62\x33\xea\x65\x6e\x28\x22\x5b\xf8\x82\x73\xde\x22\x30\xf9\x0d\x9e\x4c\x5b\xbc\x5f\x9e\xbd\x39\x7a\x6c\x6d\xdb\xbb\xbb\xb8\xb7\x81\xfc\xa6\x5b\xfc\xc7\x2f\x17\x77\x1b\x11\xbd\x41\x9b\xfd\xb8\x8b\x80\xaf\x33\x66\x90\x59\xc6\x20\x9e\x65\xe4\x39\x5d\x8a\xc1\x0f\x51\xe4\x06\x88\x0d\x7a\x6f\xe0\x47\x8b\xde\xd1\xfb\xf7\xe7\xef\xd5\x11\x30\x81\x88\xc3\xa1\x68\x1a\x0f\x11\x45\xd3\x90\x36\x11\x11\x23\x45\xf0\x2f\x64\x5f\xa8\x8f\x47\xc7\x7e\xbe\xb5\xc8\x35\x01\xd5\x30\xbf\x68\x78\xaf\xde\xff\xd7\xbb\x0f\xe7\xff\x13\xbc\x3f\x70\xc8\xa8\x75\xb8\x6c\x9a\x8e\x35\x87\x1d\x6b\x2e\x39\x08\xd3\x1c\xfe\xa1\xf2\x03\xb4\x86\x11\x17\x37\xeb\x2a\x1f\xd4\xd9\xec\x6a\x26\xd3\xd9\x65\x2a\x0c\x58\xf2\xc7\x71\xf8\x43\xe3\xf0\xf6\xfc\xf5\xc7\xd3\xf3\x7b\x8c\x72\xd8\x51\xee\xcf\x2d\x46\xf9\x53\x4f\x78\x77\xfe\xe7\xe7\x77\xef\x8f\x5e\x9d\x5c\x9c\x9c\x9f\x3d\xc2\x8e\xbf\x6f\x4d\xf9\x5d\x4f\x39\x3e\x7f\xff\xb6\xe5\xa9\x07\xf2\x25\xa2\xbf\x50\x6c\x9f\x44\xeb\xc0\xb6\xe3\x36\xf8\xfe\x05\xc5\x2d\xcc\x9c\xd5\xec\x3b\x3e\x14\xaa\xef\x6c\x23\xce\x1f\x9c\xb4\xe2\x6a\xa8\xcc\xfe\xd7\xa1\x0b\x3d\x54\xfb\x7d\x0f\x34\x06\x1e\xba\xee\x81\x77\x78\x38\x7e\xba\x7f\xb0\xef\x1e\x1e\x8e\x21\xc3\xb7\xb3\x6a\xd9\x8e\x67\x7c\x57\x98\x63\xf7\xf0\xc0\x7b\xea\x3d\xa2\x26\x56\xec\xde\x58\xfe\x98\x3e\x78\xbe\xf7\xfc\xf9\x33\xf7\xf9\x2e\xf3\xdc\x83\xbd\x83\x7d\xef\xf9\x78\x7f\xf7\xce\xbc\xc6\xe5\x16\xeb\x46\xdd\xef\xd9\xe8\x8a\xad\x3c\xf3\xbd\xe4\x31\xba\x90\xe0\x64\x0a\x69\x6b\x93\xbe\x29\x6f\x4e\xb4\x01\xa9\xd8\x9c\xa0\xb7\x4f\xf1\xa8\xf0\xdf\x41\x8e\x73\x26\xc8\x61\xfb\x83\xcb\x84\x2d\x4d\x73\xe9\x2c\x44\xf5\x5e\xad\xfb\xc7\x2c\xad\x45\xa9\xcd\x7b\x85\x0f\x3a\x54\x80\xf9\x51\x66\xd5\xde\xf8\x65\x51\xcc\x6e\x58\xbe\x8b\x63\xce\x83\x3c\x2c\x03\x5e\xa3\xb7\xe7\xb9\x07\xe3\xdd\x6a\x52\x4e\x2d\x56\x4d\x4a\xcb\x9b\x86\x61\xe8\x79\x1c\xea\x10\x0f\x85\xf7\x34\x62\xc5\x3f\x00\x3a\xe6\x1c\x08\x06\x16\x24\xfa\x1a\x0e\x16\x4a\xfa\x59\xa2\x1d\xc7\x7a\xc7\x13\xde\x3e\x87\xd2\xc2\x31\x0f\x4a\xcc\x47\xe3\x3e\xb8\x54\x3b\xd2\x64\xfc\xed\xa6\xda\xde\xcd\x56\x23\x61\x7e\xd0\x23\x3e\x7e\xee\xed\x1f\xec\x1f\x1e\x3c\x3b\xf0\xdc\x67\x4f\x9f\xed\xb2\x3d\xcf\x24\x0c\xb8\xe5\xb9\x87\x87\x4f\x3d\xef\xd9\xf8\xe0\xe0\xe0\xd9\xae\xc6\xc5\xda\x1f\x1f\xee\x1f\x3e\x3b\x18\x1f\xea\x96\xf1\xd4\xf2\x9e\x1d\x1c\x1c\x8c\x3d\xfd\xbe\xd7\xee\x7e\x7f\xfa\xe2\x85\xf7\x8c\xeb\x97\xa7\xd3\x17\x2f\x9e\x73\x8b\x1e\x9f\x4d\x7b\x7a\xdc\xc5\xe9\x80\x3b\x71\xbe\xbe\x61\x15\x85\xf7\x8f\x6c\xf5\x40\x6f\xf5\x40\x6f\x55\xc9\x95\xb7\xff\x2b\xcd\xa0\xd2\x49\xa5\xf6\xdc\xda\x6d\x66\x8c\x03\x2d\x1b\xd6\xa6\xc9\x92\x49\x69\x59\x53\x6c\xc1\x07\xda\x83\x4a\x26\xb6\x5d\x4e\x41\x90\x57\x9d\x9b\xa6\x20\x6d\x8d\xef\x27\x37\xb6\x98\x42\x42\x47\xb2\x62\xf9\xa8\xe6\xbb\x35\x57\x3e\x16\x35\x05\x89\xf6\xb0\xa0\xb4\x6d\xae\x13\x56\x25\x4f\x70\x22\xfb\xac\xa4\x0e\x3f\x6c\xaf\x9d\xe2\xd2\x14\x9d\xb3\xe1\x20\x6d\xbc\xd1\x8b\x97\xca\x9b\x4c\xee\x7b\x93\xca\x55\xbc\x09\xc9\x53\xa4\xb1\x76\xd9\x3b\x68\xa9\x23\x50\x42\xea\xc4\x98\x40\x7a\x7b\xcb\x38\xbc\xda\x16\xf2\x3e\x5a\x12\x77\xc2\xcf\x3b\x82\xd3\xc5\xff\x24\x3e\x3b\x2f\x21\xc6\x6c\xf4\xb2\xd1\xe9\x03\x81\x7d\x02\x3e\x48\x6c\x3b\xe0\x39\x8a\x49\x32\xdd\x79\x09\xb5\x7a\xa0\x81\x50\x60\xbc\x9b\x5b\xf5\x6e\x0a\x12\xd3\xdd\xdc\x2a\x76\x5e\xee\xbe\xb4\xc8\xeb\x60\x72\x54\x29\xe1\x2e\x68\x20\xb7\xe2\xdd\x1a\x68\x1a\xca\x9d\xaa\x13\xeb\xd2\x34\x45\x9f\xbe\x2a\xef\x84\xcc\xd9\x83\x08\x4f\xe5\x99\x86\x58\xf0\x1c\xab\xb0\x88\x3c\xdf\xf6\x74\x18\xa6\xa9\x9b\xa3\x1b\x54\xa1\x54\xf9\x69\x52\x00\x13\x39\x1d\x62\x36\x91\x53\xfe\x93\x10\x97\xd3\x90\x5e\xf4\x34\xed\x58\xb7\x48\xe4\x9b\x45\x8b\xcd\xa2\x5d\x02\x41\x12\x58\xda\xbd\x98\x54\x53\x1b\x25\x48\xa4\xa7\x17\xd9\xa4\x22\x60\x2e\xd0\x1b\xca\xdd\xc2\x52\x03\xa8\x59\x07\x7b\x43\x32\xdb\xb4\xbf\xee\x5e\x25\x10\xdd\x99\xf3\xe0\xf6\xbe\x5e\xeb\x23\x58\xbd\xdd\x74\x93\xe4\x85\x6b\xb8\x82\x4b\x38\x87\x0b\x78\x0f\x2f\xe1\x08\x5e\xc3\x67\xf8\x0e\xc7\x28\x9d\x12\x31\x77\x4a\xb5\x25\x38\x41\xe9\xc4\x70\x8a\xb9\x13\xeb\x7b\xb4\x13\xd3\x3c\x51\x18\x9c\x9a\xe6\x29\x05\x56\x5d\x64\xa5\xd5\xa4\x74\x4a\xd3\xcc\xe9\x0f\x3b\x89\x86\xa7\x4d\x43\x83\x87\x48\x23\xfd\x53\x1e\x9d\x98\xa6\x8b\x48\x6d\x4d\x33\x3c\x8d\xdc\xdd\x63\xff\x78\xe4\xfa\xee\xc8\xd5\xbc\x7a\xd5\x6a\xdb\x63\x0e\x97\x78\xa5\x73\xed\x31\x4a\x47\xd8\xb9\x23\xe0\x18\x6b\x2b\xb6\x3c\x48\x9a\x86\x25\x78\x06\x31\x56\x4c\x3a\xa4\x72\xed\x8a\xe5\xea\x01\x8e\xf1\x78\x74\xd3\xb8\x1c\x96\xe8\x06\xa7\x93\xe5\x14\x91\x9d\x4c\x96\x53\x8a\xe7\x82\x65\x1b\x94\x53\x7b\xd8\x37\x9b\x66\x6c\xdb\xe0\x86\xc7\xfc\x52\x6b\x06\x8f\xc3\x02\x87\xee\x46\xc8\x8e\xf0\xa4\x63\xe8\xcf\x78\xda\x3d\x52\x10\x79\x6c\xe1\x18\xd6\x48\xe1\x1d\xa3\x4d\x5a\x1e\xe7\xb0\x0e\x3d\xd3\x64\xa7\x28\xd8\x29\xac\x21\xe1\x70\x82\x82\x9d\xe8\xc7\xad\xf9\x1b\xa8\x1c\x5e\xe2\x67\x38\xc7\x93\xfe\xaa\xe0\x33\x87\x0b\x3c\xef\xc2\xae\xcf\xe1\x45\x70\x3e\xb9\x20\xb5\xe2\xf2\xe0\x3b\x9e\x76\x12\x04\xdf\x7b\x3e\x77\x39\xbc\x56\x74\x86\xd3\x89\x37\x0d\x31\x19\x8d\x4d\xf3\xb5\x65\x05\xf3\x7c\xb0\x46\x97\x24\x91\x9d\xc2\x39\x7c\x86\x0b\x0e\x6e\x98\x46\xec\x3d\x9e\xd3\xf0\xcf\x43\xbc\x30\x4d\xf6\x1e\xdf\xef\x26\x16\x3b\x9f\x78\x8a\x28\x5c\xed\xea\xfd\xe8\xb5\xda\x4e\xc4\xd6\xa1\x4a\x4a\xaf\x31\xb1\x3d\x0e\xf3\xcd\xde\xae\x71\xde\x6d\x68\x83\xb1\x5a\x6d\x0e\xe7\x70\x4d\xab\x79\x88\x29\xcd\xb5\x6d\x28\xd8\x1c\xae\xc3\xcf\xd1\x77\xff\x14\xae\x21\xe1\x9c\xfb\x14\xf8\xae\x4d\x93\xa5\xb8\x46\x05\xba\xdf\xdd\x5d\xe0\xe1\xb5\x69\xce\xb7\xb7\x5b\xb0\x73\x98\xc3\x05\x21\x61\xb7\x4b\xdc\xc3\xa0\xdf\xaf\x17\x2a\x04\x2c\x4b\x4d\xba\x68\x11\xb8\x50\x08\x6c\xa1\xcd\x7d\xd2\xa4\xdd\xd0\x73\x54\xd9\xcd\xcb\xc9\x92\x08\xbf\x86\xd4\x34\x89\x60\x51\x7b\x12\x27\x93\x97\x44\x29\x9f\x9d\xe3\x84\x9e\xa7\x70\x81\x1e\x0f\xae\x97\x32\x15\x8c\xbd\xb4\xac\x17\x47\x5d\x52\xe4\x5c\x27\x4c\x8f\x49\x91\x2f\x70\xd3\x06\x97\x4a\x12\x2e\x3b\x09\xa6\xa0\x3c\x41\x3c\xd3\x7a\x62\x89\x1e\x1c\x23\x0d\x09\x8e\x95\xe2\x3e\x56\x8a\x5b\x31\xf1\x47\x76\x05\xb5\xc5\xae\x1c\x81\x4b\x2b\x56\x69\x44\xcb\x83\x12\x16\x6d\x26\x99\x3a\x62\xb8\x72\x0a\xb4\x16\x9d\x5a\xbc\x52\xba\xfc\x61\x88\x87\xa3\xbf\x99\x1d\x71\x97\x4d\xbe\x5f\xe6\x53\xce\x3e\x5d\x4f\x3e\x5d\x3b\xd3\xdd\x27\x7c\x24\x21\xa3\xde\xc9\xdf\xce\xd4\xe2\x9f\x9c\x27\x23\xa8\x70\xf4\xf7\x27\xa7\x6d\x79\x32\x82\x02\x47\x7f\xdb\x11\x3b\xc9\x12\x99\xc9\xea\xa6\x39\x9b\x9d\x51\xb3\xa4\x61\xe5\xee\x27\x8b\x29\x58\xbc\xf9\xfb\x53\x69\x35\x9f\x4a\xeb\xc9\x68\xf1\xc0\xfb\xba\xaf\xa3\xb0\x8c\x6a\xbf\xee\xaf\x8f\x24\x18\x4f\x3c\x43\x09\x6e\xa1\x2f\x45\x63\xce\x73\xa7\x44\x59\x9e\xcd\xce\x58\xac\xe3\x48\xdf\x0d\xe3\xc8\xf6\x7c\xaf\xbf\xf2\x18\x92\x16\x8a\x31\xee\x01\x09\xd8\x38\x7c\xda\x72\x75\x16\x0f\x8d\xef\x06\x22\xab\xb0\xba\x77\xad\x15\x79\xcf\x7c\xe3\x92\x3c\xef\x68\xec\x3f\x87\xc4\x34\x93\x21\xa6\x91\xf0\xb3\x5b\x4e\x6f\x2c\xc5\x04\xb6\xd7\xc8\x34\xb2\xfd\x7b\x05\x86\xeb\x50\x0b\x87\x7a\x88\xf1\x3d\x75\x19\x43\xca\x83\x2f\xfa\x8a\xd2\x50\x4e\xbc\x61\xb1\x24\x32\x06\x97\xb3\x52\x0c\x0c\x2b\xf1\x0d\x83\x93\x7f\xdf\xe6\x71\x6b\x0e\xb4\x71\xda\xef\x6d\xee\xc4\x98\xb7\x09\x17\x78\x8b\xae\x3a\xdd\x0f\xce\xec\xb2\xcc\xd3\xba\x12\xca\x07\x44\xf5\xfe\xf0\xc4\xdb\x7b\xb8\xa5\x2c\xef\xdf\x03\x30\xe1\x94\x24\x86\xe2\x16\x3e\x38\xb1\x90\xe9\x23\xd1\x40\x77\x1f\xa2\xe6\x03\xfd\x55\x49\xb4\x31\x57\x73\xf2\xd5\x7a\x56\x88\xf9\x87\x1c\x3f\x38\xf1\x6a\x8d\xdb\x34\xef\x41\xbc\x45\x0f\xa4\x02\xb0\x55\x58\xa1\xe6\xb7\xe9\x9b\x77\x2a\x6f\x8f\x1f\x9c\xf9\xfa\xb1\x9c\x44\xa1\x4a\x3b\x5a\xa3\x54\xf4\x44\xad\xd3\x54\xbb\xe9\x8c\x65\x58\x74\x77\x8b\x1e\xd9\x07\x8d\xe6\xe8\x86\xf3\xdd\x1b\xc8\x90\xc2\x23\xed\xc3\x65\x3b\x9e\x8b\xe8\x06\x99\x92\x2e\x41\x32\xda\x82\x73\x43\xa1\xa2\x4c\xb7\x25\xc7\x5c\x5e\xc9\xb9\x98\xff\x76\x83\xea\xf9\x57\x3b\xdb\x83\x57\xf7\x77\x06\xef\xe0\x2b\xdf\x02\xa1\xd2\xee\x62\x21\x8a\x0e\x96\x6a\xf8\x15\xc0\xfd\x47\x00\xba\xe0\x29\x80\xe2\x5b\x3d\x4b\x89\x4e\xe2\xdb\xaf\xa6\x3f\x05\xd2\x6a\x8f\x53\x3b\x49\xf3\xbc\xf8\xe7\x47\xbc\xa7\x26\x2d\x0a\x31\xab\x44\xf1\x61\x39\xcb\x90\xa2\xc1\x5f\x2d\xfc\xec\x91\x23\x0e\xdd\x7b\x10\xce\x8b\x23\xda\x82\x62\x97\x45\x25\x7e\x05\xeb\x80\xac\x08\xb2\xec\x91\x7d\x70\x1d\xf9\x67\x04\x58\x96\xc7\xa4\x87\xc4\xc3\x2d\x0d\x87\x9a\x63\xf4\xa8\x96\xfc\xd8\x3e\xff\x7a\xb8\x69\x6e\xb1\x4e\xa8\xdb\x3a\xbe\x1a\x6b\x58\x67\xb3\xb3\x47\xe6\xab\xa1\x65\x3b\x42\x2c\x66\x95\xbc\x12\xd8\xbe\x3c\x42\x70\x3d\xfc\x85\xab\x27\xfc\xb7\x28\xf2\xff\x09\x27\x17\x5b\xfe\x9f\xb8\x53\x9a\x91\x8a\xb2\x6c\x8f\x23\xfd\xe5\x71\x3c\x7f\xe4\x38\xf4\x82\xdd\xf4\xed\xb3\x48\x7f\x7d\x16\x87\xca\xde\xfe\xef\x87\xa1\x6e\x8e\xf0\x83\x53\xd6\x97\xf7\x40\xdd\x8d\x18\x14\x8c\x04\x4b\x47\xd5\x6a\xbd\x55\x62\x88\x5b\xbc\x9e\xa9\x5a\x9e\x61\xd2\x34\xc3\xec\xae\xfe\x54\x8e\x23\x19\xcd\xe1\xa6\xc0\x8a\x14\x98\x9d\x41\xe9\xac\xd3\xba\x64\x82\x07\xca\xaa\xa0\x3a\x41\x50\x39\xea\xd1\x0d\x2c\xb1\x74\x62\x58\xa0\x68\x55\x48\xda\x34\x43\x7d\xd1\x3a\x5c\x36\xcd\x70\xd1\x01\x5b\x46\xac\x85\x27\xb8\xaf\xd7\x5c\x44\xa5\xdf\xad\x3b\x5c\x6a\x57\x76\xab\xba\x60\x40\xcf\x0f\x67\xd1\xc0\xa8\xf4\xf7\x10\xbf\x46\xb6\xeb\xbb\xca\xd6\xa7\x58\xb1\x94\x2b\x3f\x56\xdd\x49\x2f\x7b\xbf\x2e\xc1\xd4\x8e\xb5\x1b\xc0\x6a\x74\xc3\x84\x47\x2c\x41\x3b\x81\x1c\x97\xdc\x67\x31\xa6\x90\xe3\x82\xac\x41\x21\xae\x44\x41\xb6\x0a\x32\x4c\xd4\x05\x6f\xbe\xb9\x03\xda\xea\xbe\xdd\x0a\x6a\x58\x8d\x2c\xe9\x6f\xad\xf9\x0b\x96\xf5\x77\xfb\x9c\x47\x89\x9f\x41\x82\x19\xba\x81\x0c\xb3\x20\xd3\x81\xcf\x72\x92\x4d\x87\xb8\x20\xad\xf9\xb3\x46\x7a\x7b\x41\x2f\x9b\xcb\x04\x0a\x7d\x73\x24\xaf\x78\x01\x0b\xcc\x41\x11\x40\x38\x25\xe1\xc5\xe4\x06\xbe\xad\x52\x15\x9d\xdf\xdb\xdd\x54\xeb\x9b\xe9\x49\xd1\xba\xb8\xd4\x94\xe1\x99\xed\x05\x32\x4c\xf4\xf5\xc8\x52\x5d\xb1\xbe\x58\xa8\xd0\x4b\x17\x5a\xc9\xa0\x30\xcd\x21\x75\x14\x53\x9a\x3c\xc5\x8c\x07\xb6\x4d\x4f\xb0\x9c\xc8\xa9\x85\x67\xb7\xf4\x6b\x23\xcd\x52\x77\x19\x14\x2a\xd3\x51\x04\xcb\x3e\x52\xb6\xed\xb8\xd7\xf8\xea\x94\x4e\x98\x80\x25\xc4\xdc\x57\x87\xa8\x4f\xcc\xf3\x3d\xd8\xba\xcc\x00\xa1\x14\xe1\x2a\x9f\xd7\x29\x09\xcb\x2a\x9f\x3f\xc2\xe1\xfa\xd6\x5c\xd5\x20\x6e\xcc\x9e\x77\x97\xb7\x87\xd2\x89\x9b\x66\x28\x9c\xb2\x69\x04\x89\xf6\x50\x17\x2e\x44\x1b\x06\xf7\xa9\xa9\x69\xa4\xea\x95\xdb\xbd\x92\xfb\xec\x10\xf1\xcf\x88\x15\x4a\x44\x94\xed\x86\x0a\x5f\x31\x09\x02\x5c\xd8\xe3\xaa\xa9\x80\xca\x29\x77\xb1\xe0\xfe\xa6\xeb\x4f\x0e\x52\x0b\x28\xab\x1c\x75\x51\xcb\x04\xd7\x36\x21\x23\x6d\x25\xe6\xa8\x9e\xfe\xa9\xef\xa0\xce\x5a\xfb\xbb\xda\x58\x92\xf4\x91\xfb\x31\x7f\x8c\x32\x1d\x5d\x20\xa7\x78\xb3\x95\xfa\xf1\xa3\x52\x9f\xff\x5a\xea\xf3\x87\x52\xdf\xed\xa9\x15\xfb\x1a\x55\x7c\xa8\xab\x40\x46\x37\x90\xa8\x70\x36\xed\xc5\xbe\x6e\x9a\x61\xa9\xc5\x9e\xb4\x4b\x7a\x77\x9d\xbc\x93\xf2\x44\x4b\x79\xba\x25\xe5\xf4\x4c\x6e\xa0\x1a\x48\xfd\x91\xf4\xdd\xdd\x5c\x89\x75\x8d\x15\xab\x39\x29\x36\x56\x92\x28\x27\xbd\x58\xe7\x58\xdb\x6d\xde\x2c\x0f\xdd\x88\x95\x58\x43\x81\x29\xf7\x59\x8e\x76\x0e\x05\x26\x1c\x8a\x8d\xcc\x06\xb9\x6d\x07\xc5\x46\x9c\xb7\xba\xda\x9b\xb9\xa4\x0b\x77\x32\x4c\xbb\x47\x37\xcc\xed\x4c\xd5\xdd\xa5\x40\xee\x69\x82\x05\x64\x98\xd3\xea\x6e\x90\x05\x3c\x47\x96\x4c\x6c\x3b\x9b\x62\x32\xc9\xa6\x56\x4a\x7f\x72\x3e\x3a\x6b\x5c\xa0\x86\x1d\x3c\xeb\xce\x35\x37\x4d\x96\xf4\x21\x57\xce\xc1\xb2\x4a\x0e\x24\x1f\x09\x94\x8a\x57\xfa\x3a\x00\x52\xf3\xdb\x27\xad\xcf\x59\x65\x3d\xf4\x49\x4b\x2c\x34\xd1\xfb\x0c\xaa\x18\xaa\xf4\xbd\x69\x7a\x43\xa4\x77\x57\xff\x30\x9d\x7f\xdb\x03\xa3\xcb\x39\x1b\x2a\x05\x0f\x62\xa8\x87\xb7\x59\x58\x4e\xc2\x73\xdf\xf3\xab\x50\xf6\x5e\x1f\x64\x58\xed\xde\x58\x24\x10\x72\x52\xb5\x5a\x23\xa8\x5a\x77\xaf\x52\xee\x5e\x46\xee\x9e\x4e\x63\x4a\x52\x0b\x95\x0a\xb4\xda\x3e\x0a\xb4\xfa\x5b\x4b\xd3\x2c\xc8\x05\x0a\x89\xb2\xe4\x5b\x0a\xcb\xe3\xa0\xcc\x9c\x2a\x7b\x78\x4c\xfc\x1f\x11\x15\xa6\x2b\x91\x44\xd3\xf4\xf9\xe3\xa7\x9c\x9b\xe6\x47\x56\xc1\xbf\xff\x2d\xac\xde\xd3\xba\x53\x60\xec\xc2\x73\xf0\x9e\xea\xca\xa7\xcc\xff\xca\xa1\xa2\x75\xd5\xa9\x3c\x24\xf9\x1d\x85\xa3\x6e\x75\x2e\xe0\x02\xbc\x67\x5b\xf4\xe4\x51\xd6\xca\xbc\xe1\x09\xc3\x52\xb5\x33\x2d\x2b\x67\xa4\x65\x32\xa5\x64\x4c\x93\xd9\x17\xba\x68\xe6\x82\x66\x94\xbb\xea\x1e\xc8\xf5\x3d\x52\x4a\x99\x3a\xff\xf2\x5b\x3d\x2b\xc4\xfb\x3c\xaf\x88\x01\xbe\x15\xd5\x63\xce\xfa\x03\x3b\x4f\x22\x58\x3a\x25\x45\x7a\xaa\x90\xea\x9d\xb5\x0f\x8b\x96\x5a\x86\xeb\x3c\xd5\xc1\x1e\xb1\x05\xd9\x65\x92\xcc\x64\x4b\xf4\xf4\x38\x32\xd9\xae\x0a\xeb\x69\x80\xea\x8f\xdc\x91\xeb\x27\x51\xa9\x10\x0c\x94\x7d\x55\xa9\x7f\xc2\x8b\x11\xe7\xba\x0a\x60\x8a\xe8\x8d\xdc\x88\x4e\x91\x25\x1c\x58\x57\xc6\x63\xc5\x7c\x67\x8c\xaa\x8a\x31\xd3\x35\x52\xb0\x0d\x20\xd3\x86\x9a\xc5\x96\xc7\x47\x63\x6e\x33\x37\x8c\x9b\x26\xde\x19\xd3\x30\x05\x31\x43\x4d\x4e\x9f\x91\x34\xde\x29\x75\x51\xe6\x39\xdb\xd4\x64\x6f\x2a\x2c\x85\xc1\x2d\x8f\x5b\x31\x07\xd9\x52\x20\xe3\xdc\xef\x9e\x53\xcb\x30\x48\x53\xd3\x79\x28\x43\xa9\xb2\x61\x90\x62\x6c\x2d\x61\x4f\x6d\x3f\x25\x83\x19\xe8\xfa\x57\x09\x64\x69\xf5\xd1\xd6\xda\x01\x7a\xc5\x4a\xa8\x61\x09\x9e\xba\x9c\x63\xb5\x13\xf3\x1e\x8d\x94\x6b\x37\xae\x60\xd2\x89\xf9\x76\xbb\xd2\x89\xd2\x11\x2f\x62\xd3\xb4\xed\x74\x0b\xf9\xd4\xde\x83\x94\x78\xdf\x38\x3c\x3c\x3c\x34\x14\x8f\xb2\xbc\x69\x8c\xfd\xf6\x95\xf3\x9f\x6c\x68\x65\x4d\x33\xb4\xb2\xbe\x10\xd9\x34\x8d\xa7\x06\x62\xd6\x55\x06\xba\xc4\xf4\xec\x23\x93\x20\x1d\x61\xbd\xb3\xc6\x40\x31\x27\x0e\x65\x8b\xbc\xe4\x8e\xf8\xc6\xca\xed\x6a\x85\x61\xae\x66\xd4\x50\xb7\x33\x5c\x0e\x75\xb7\xd7\x6e\x38\xff\x29\xb1\x6e\xe7\x2c\x2d\xdc\x87\x94\xfe\xe4\xe8\xdd\xf6\x81\x4d\xb7\xa4\x07\x5f\x5b\x33\xae\x60\x90\x15\xaf\xd3\xff\xc9\x4f\x6d\xeb\x80\xba\x04\xea\x4a\xa7\x50\x35\x57\x9f\xe3\xa5\x13\xc3\x05\x92\x1d\x3b\xb8\x63\xc7\x78\x97\x39\x3d\x37\xcd\x0b\x9d\x41\x32\xcd\x8b\xad\xcc\xe9\xf0\x92\x0c\xa7\xf6\x00\xce\x4d\x73\xa8\x47\x0c\x2f\x9a\xe6\x82\x7e\xf4\xdb\x79\x5f\x5f\x21\xda\xf8\x5f\x79\x27\xbb\x78\xe9\x94\x40\x90\x23\x5d\x6b\xe1\xea\xfa\x15\x97\xfb\xdb\xf5\x18\x1c\x44\x5b\x92\x56\xb1\x4b\x15\xc9\x58\x15\x13\x3a\x61\xda\x43\x49\x37\xb9\xb3\x05\x5e\xf4\x8f\x8a\xc7\x56\x78\x0e\xe7\x78\x01\x17\xb8\x82\x5c\x99\x15\xe5\xe4\x91\x49\x49\xad\x05\xac\x70\x32\x55\xb6\x6a\xb5\x55\x7e\x94\x17\xec\x1a\xcf\xe0\x0a\x5f\x92\xab\x1a\xd8\x76\x1e\xa2\x1b\x6c\x8a\xe4\xd7\x78\x31\xc9\xa7\x3b\x57\x30\x57\x0f\xa3\xab\xc6\x85\x12\x53\xa8\x31\xb7\xca\xa0\x0e\xf3\x80\xc7\x78\xae\xee\x4d\x76\xae\x60\x89\xe7\x93\x52\x0f\x4a\x70\xbe\x1b\x5b\xcb\xdd\x35\xc4\xb8\xde\x8d\xad\x64\xe7\x6a\xf7\xca\x5a\x4d\xea\xa9\x55\x40\x81\x2c\x1e\x5d\xab\x1b\x82\x84\x46\x73\x6b\xbe\xbb\x84\xd5\xa4\xb6\xed\x29\xc6\x3b\xd7\x01\x8d\xc3\xa2\x63\x87\x22\xb2\x2c\xe9\xaf\x7a\x67\x90\x6c\xdb\x0a\xa4\x66\x8b\xb6\x6c\xed\x1f\xaa\xf6\xc1\xbd\xcb\x41\x8f\x94\xfb\xf3\xed\x52\x39\x7d\x51\xa8\x5c\xa4\x0c\x1f\x2a\xf8\xe7\xbd\x82\x07\x11\x91\x41\xa0\xe5\xfc\x4a\xa3\xb2\xa5\x4b\x1e\x0f\xcb\x3e\xb7\xa1\xd8\x83\xfb\xc9\x43\x1e\x91\x65\xf1\xda\x85\xa9\x41\x83\x54\x95\x77\xff\x37\x60\x63\x57\x03\xeb\xcc\x54\x07\x73\xec\x76\x30\x55\x0d\xdf\xa3\x14\xfb\x25\x4c\xef\x17\x30\x3d\xa5\xc3\x75\x9c\xbb\xe5\x36\x3a\xe5\x3a\x95\x95\x2e\x4d\xcf\xd1\xfa\xcb\xe9\x0b\x79\xa0\xa6\xd7\x87\xb5\x3c\x50\x62\x37\xaa\xab\xe2\x21\x4f\x90\x84\x25\x45\x39\x51\x25\xda\x5d\xfc\x0d\x33\x8c\xa3\xa4\xd7\x5b\x7e\x02\xcb\x4d\xf9\x53\x1b\xe6\x14\x98\x93\x27\x07\x35\x16\xb0\xb4\xb1\xe0\x90\x87\xae\x69\x2e\x43\xb7\xe3\xee\xe5\x4e\xde\x34\x39\x24\x38\x6b\xbf\x89\x60\x2e\x14\x3c\x58\x86\x45\x50\x58\x98\xf3\xc4\xc2\xd2\xea\xfb\x0a\xc8\x79\x50\x87\xaa\x7c\xbe\xed\x50\xcb\x17\x9c\x43\xac\x6a\xea\x0d\xdb\xb0\x12\x7e\x5b\x61\x1a\x25\xd6\x5f\xce\xfd\x12\x27\x8b\x82\x44\xeb\x2f\xe7\x41\x59\x12\x8f\xd2\x4d\x66\x72\xeb\x4b\xa1\x4f\x9f\xe6\x3f\x0d\xab\xb6\x8c\xdb\x4f\x9f\x7e\x33\xc0\x58\x18\x1c\x8c\x27\xa6\xf1\x00\x46\xb7\x02\xf7\x53\xee\x27\x9b\xc2\x5c\x7d\xd8\xed\xd0\x47\xdd\xbe\x7b\x4a\x13\xbf\xc0\x42\xab\xca\x35\x2e\x9c\x18\xe6\xfd\xbd\x3a\xac\xb0\xda\xbc\x5c\x63\x72\xe7\xc6\xbd\x67\x17\xf6\x05\x87\x1e\x94\xd8\x97\x62\x7f\xc1\x25\xb0\x21\xa3\x48\x5e\xe5\x70\x18\xe7\x4d\x53\x3a\x69\xc5\xbe\x29\xe3\xa2\xcb\x23\xc6\x60\xac\x66\xdf\x07\x73\x91\xe5\x2b\x99\xd1\x56\x06\x86\xc5\x96\x91\x71\xaf\x06\xf8\xb1\x12\x60\x81\xc3\xa5\x69\xaa\x84\xcb\x47\x56\x82\x76\xcc\x3c\xee\x2c\x2a\xc1\xbe\xf1\xa8\xf4\x3b\x37\x74\xdd\xc7\xfe\xdb\x65\xe8\xda\x5c\x17\x6c\x4d\x7c\x3a\x77\x04\xf6\x89\xa3\x85\x23\x6c\x0f\xe6\xca\xaa\xe3\xfb\x09\xab\x31\xdf\xb9\xe1\x2f\xdc\xe8\xc6\xaa\xfd\x7a\x4a\x0b\x0b\xda\x4b\xbc\x5a\xb3\x39\x0f\xdd\x88\x82\x85\xb9\xbf\xf2\x4b\xa8\xf1\x07\xfc\x20\x6f\xa3\x27\x45\xcc\x21\xd1\x90\xdc\x20\x45\x32\xf7\x73\x95\x1d\x54\xb2\xa2\x5c\x80\xb4\xb5\x92\xd7\x9c\x83\x37\xa4\x10\x68\xb5\xa6\x08\x89\x57\x78\x0d\xd7\x28\x61\x85\xc9\xdd\x91\x12\x57\x9c\x22\x17\x09\x73\x2c\xdb\x90\x6a\xd3\x37\xe7\x14\xdc\xc8\x4e\xef\x49\x7c\xc5\x44\x17\x4b\x72\xb8\xd6\xab\x27\x1d\xcc\xce\xa4\x13\xc4\xaa\x43\x49\x6e\xa1\x94\x38\x25\xae\x9c\x12\x17\x4e\x09\xf9\x2e\x8e\x21\xc3\x57\x8c\xac\x6b\x0e\x5f\x79\x0b\x77\xc1\x9d\xd9\x65\xc9\xb8\x42\xfd\x15\x4b\xa0\x7a\xac\x97\xbf\xf0\xa2\xc9\x6a\xeb\x0c\xe0\x7a\xeb\x65\xea\x4f\x92\xed\xbe\x6a\xbb\x0f\x7e\x60\xad\xdd\xf9\x2a\xd7\x35\xc2\x0f\x23\xdf\x2d\xc7\xda\x12\x4d\x43\x06\x38\x72\x77\x85\xa3\xf3\x41\x7a\xee\xbb\xfc\x5a\xa5\x15\xd7\xf9\xf5\x2f\xa2\xa1\x55\x57\x4d\x65\x09\xde\xa5\x07\xc8\x41\xe8\x5d\xf5\xf1\x1e\x18\xa2\x55\xf7\xaa\xfe\x67\xd8\x65\x35\x99\xe0\x4d\x53\x84\x17\x14\x03\x8d\xd0\xe5\x4d\xb3\x9e\x15\xa5\x38\x4e\xf3\x59\xc5\x04\x57\x72\x32\x64\x02\x09\x9d\x7b\x37\x0d\xca\x8f\x5d\xe7\xd7\xcc\x92\x20\x78\x97\x61\xf9\x3d\x9a\xb3\xdf\x47\x37\xd6\x98\xfb\x2e\x6c\xa4\xb0\xad\x48\x2d\x76\xc6\xea\x57\x5d\x8b\xb4\x6e\x19\x0c\x2b\x27\x6e\x2b\x45\x33\xd3\xac\xfa\x6c\xa8\x0a\x8c\x36\xaf\x98\x71\x5d\x1e\xbc\x62\xc5\x68\xcc\xa1\x2b\x5a\x0e\x24\x6e\x7c\x3c\xc8\x4c\x53\xa5\x35\xe4\x5d\x30\xf2\x0e\x98\x3b\xd9\xf8\x0a\xbf\x39\x73\x79\xc5\x2a\xce\x21\x53\x56\xf2\x77\xf8\xda\x5b\xc9\xbe\x48\xfc\x9f\x9b\x35\x55\x15\xb7\xff\x2b\x33\x0d\xe3\xfd\xf6\x60\x35\xa7\x3c\x76\xa6\x5d\x7c\x5b\x11\xff\x62\xe5\x88\x60\x2b\x28\x45\xc4\x3c\x92\x14\x6c\x18\xdd\x1d\x99\x01\x6e\x28\x55\x14\x49\x6a\x9d\xbc\xfd\x0c\x8d\xb3\xd9\x99\xe1\x2b\x57\x9c\xe8\xdb\xfb\x07\x2d\x92\xea\x0b\xd3\xf1\xd3\xee\x13\xd3\xe8\x35\x4b\x59\x06\x39\x07\xb7\x11\xe0\xb9\x20\xb9\xff\x5b\x88\x64\x73\x42\x7c\x12\x25\xaa\xcf\xef\x86\xd0\x62\x55\x17\xd1\xf5\x8b\xb6\xcc\x5e\xd4\x59\xdc\x66\x7b\xd4\xf3\x3f\xbf\x0b\xd0\xf7\x0f\x57\xb3\xb4\x16\xe7\x09\x4d\xcf\x7f\xbf\x38\x7f\x24\x13\xae\x53\xdb\x1b\x51\xbb\xdd\xd0\xbf\xab\x3a\x25\x75\x3e\xdb\xd4\x4b\x54\x9b\x58\xd6\x6d\x7a\x6a\x8a\xd0\x6d\x1a\x81\x88\x59\x94\xf9\x99\xed\xdd\xa9\xaf\xd8\x54\x56\x68\x21\xf3\x40\x6e\x8a\x50\x72\xf5\x9d\x8a\x65\x18\x81\x0c\x8b\xd6\x03\xcd\x50\xa8\x6c\xa3\x65\x18\x50\xe1\x8d\xdd\x7f\xcb\x51\xd9\x76\x90\x51\xf4\x67\x65\x3c\xc8\x2d\xcc\x6e\xdb\x42\x90\x3b\x5f\x25\xe6\x77\xbf\x4a\x94\x3c\xe8\xdd\xc0\x7c\xf3\xbd\x9f\xe5\x35\x8d\xc7\x37\x88\xca\xfb\xb9\x41\xe1\xc4\x90\x53\x54\xa4\xbe\x29\x2a\x49\xa7\x3b\xa5\xaa\x9f\xa1\x18\x2f\x73\xc4\x56\x96\xea\x61\xa6\xc3\x34\x87\xca\x89\x29\x30\x37\xcd\x61\xae\x8a\xba\x9a\xa6\xbf\x0d\xab\xa2\x22\x72\x7d\xbb\xf4\x6b\xe5\xb8\x0c\xb1\x87\x51\x6b\x00\x6e\x58\x43\x81\x09\x62\x0a\x43\xd9\x34\xc3\x9c\xf7\x5e\xb1\xeb\x0f\xe5\xdf\x95\x2e\x6b\xb9\x73\xc5\x96\x84\x69\xd7\xae\x8b\x8b\x58\xd2\xa7\x5c\xf8\x0b\x96\xf6\x74\xe2\x51\xe2\x93\x33\xef\x06\x65\x58\x07\xb5\xce\x22\xcb\x49\x3d\x1d\x62\x3e\xa9\xfb\x60\x9e\x5a\x42\x6a\xe8\xa0\xf6\x9f\x49\x63\x1a\xb9\xfe\x66\xb9\x0d\x15\xf3\xbb\xb7\xb7\x4c\xe8\x8f\x7f\x42\x72\xa6\xab\x10\xb7\xaa\x7d\x6a\x62\x8c\xf6\xa3\xbf\x89\x2e\x8e\x1c\xa8\x52\xb8\xa9\x81\x78\xae\xde\x37\xe5\xe7\x3d\x8b\xea\xef\x91\xc4\xd6\xb9\x95\x0f\xbe\xff\x21\xf7\x46\x45\x5b\xb5\x2a\x94\xef\xbf\x77\xa2\xbd\xb6\xdf\x80\x6e\x38\x46\xda\x76\x90\x4f\xe4\x74\x17\xb3\xb6\x1e\x6c\x52\xa0\x3b\xb5\xf0\xbc\x4f\x03\x88\x2e\x30\x26\x42\xf1\xa0\x78\xd1\x4f\x2e\x2c\x8b\xe7\x93\x62\x1a\x56\xea\x6b\x5d\xad\x53\xf2\x49\x61\x79\x24\xce\xfa\x01\x5d\x0e\xfa\xc9\xa2\xae\xe9\xa8\x6a\x5c\x6a\x98\xee\x60\xd5\xeb\xcf\xed\xbb\x80\x7e\x67\xc9\xb6\x7e\x64\x9b\xaa\xa2\x48\x6c\x22\x75\xcb\x70\x0c\x4b\x6c\x5c\x62\xc1\x2d\xe6\x86\x59\x64\x90\xdf\x24\x2c\x83\x5b\xd9\x06\x60\x7a\x87\xc5\x75\xd9\x5a\xd6\xb9\xc5\x86\xeb\x18\x81\x65\x65\xe4\x04\xab\x6f\xd0\x04\x16\x96\xe8\x0b\x0c\xab\x8d\xc8\x5a\x56\x16\x56\x9b\x69\x06\x64\x36\x56\x81\x6d\x6f\x4d\xb5\xb0\xd0\x33\x2b\x65\x33\x36\x75\x65\xfa\x93\xf7\x2d\x9c\x33\xbe\x89\xd1\x36\x98\xc6\x1b\xe6\x18\x08\xbc\x63\x48\x81\x2c\xf4\x9c\x09\xee\xaf\x88\x0f\x68\x33\x33\x1d\xf7\xeb\x6a\x87\x4f\x73\x8b\x7d\x72\x3e\xcd\x77\x79\xd4\xd0\xaf\xc5\x99\x98\x58\xf6\x34\xa2\xc7\xe8\xc9\x88\xdc\x26\x65\x70\x63\x21\x53\x58\xe9\x67\x75\xd5\x0a\xd7\xd8\x56\xeb\x0e\x2e\xf3\x3c\x15\xb3\x6c\x90\x17\x83\x4b\x99\xcd\x8a\x9b\xc1\x9c\xc2\x4d\x03\xae\x50\x7f\x49\x25\xb3\xc5\x60\x95\xcf\x85\x01\x97\xdd\x87\xe9\x03\x62\xd4\xc1\x72\x56\x0e\x56\x79\x21\x06\xd5\x72\x96\x0d\xbc\xa7\x83\x52\x2e\x32\x99\xc8\x78\x96\x55\x1a\x48\x69\xc0\x39\x1a\xae\x37\xde\xdb\x7f\xfa\xec\xe0\xf9\xe1\xec\x32\x9e\x8b\x64\xb1\x94\x5f\xbe\xa6\xab\x2c\x5f\x7f\x2b\xca\xaa\xbe\xba\xfe\x7e\xf3\xe3\xe5\x6f\xaf\x5e\x1f\x1d\xbf\xf9\xd7\xc9\xef\xff\xdf\xe9\xdb\xb3\xf3\x77\xff\xff\xfb\x8b\x0f\x1f\xff\xf8\xf3\xaf\xff\xfa\xef\x27\x9f\x0d\x38\x43\x4f\x78\xfb\x70\x83\xde\x3e\x5c\xdc\x2f\xec\xf5\xe0\x3d\x4e\x3c\x32\x3f\x9e\xeb\x82\x27\xf6\xc0\x13\xfb\xe0\x89\xa7\xe0\x89\x67\xe0\x89\x03\xf0\xc4\x73\xf0\xc4\x21\x78\x82\x06\x09\xcf\xa3\x3f\x63\xfa\xb3\x37\x85\x97\xea\x43\x8e\x23\xf4\xc4\xa1\xfa\xa2\x4a\x55\x51\x1a\xdd\xf1\x6c\x8a\x9d\xe7\x22\x91\x99\x30\x4d\xfd\xeb\xcc\x56\x73\xae\x1f\xd9\x43\x53\x33\xbb\xdd\x7c\xb7\x69\xd4\x99\x1e\x37\xdf\x54\x7f\xab\x0b\x1b\x61\x9a\xfa\xd7\x21\x2f\xab\xa8\xf4\x05\xc0\xdd\x26\x9c\xc1\x70\xc9\xab\xe2\xe6\xe7\x12\x0b\xf1\xad\x96\x85\x60\x6d\x3d\xa8\xc1\x6f\xe3\x59\x15\x2f\xd9\x6b\xfe\xf3\x56\x73\xa0\x70\xfa\x2f\xcb\x70\x76\xdb\x66\x05\xfe\x63\x34\xfa\xcf\x41\x99\xd7\x45\x2c\xde\xce\xd6\x6b\x99\x2d\x3e\xbe\x3f\xc5\x79\x1e\xdf\xf9\xf7\x1a\xce\x6a\xb6\xfe\x8f\xff\x17\x00\x00\xff\xff\x2f\x88\x72\xca\xa2\x43\x00\x00") + +func bignumberJsBytes() ([]byte, error) { + return bindataRead( + _bignumberJs, + "bignumber.js", + ) +} + +func bignumberJs() (*asset, error) { + bytes, err := bignumberJsBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "bignumber.js", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +// Asset loads and returns the asset for the given name. +// It returns an error if the asset could not be found or +// could not be loaded. +func Asset(name string) ([]byte, error) { + cannonicalName := strings.Replace(name, "\\", "/", -1) + if f, ok := _bindata[cannonicalName]; ok { + a, err := f() + if err != nil { + return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) + } + return a.bytes, nil + } + return nil, fmt.Errorf("Asset %s not found", name) +} + +// MustAsset is like Asset but panics when Asset would return an error. +// It simplifies safe initialization of global variables. +func MustAsset(name string) []byte { + a, err := Asset(name) + if err != nil { + panic("asset: Asset(" + name + "): " + err.Error()) + } + + return a +} + +// AssetInfo loads and returns the asset info for the given name. +// It returns an error if the asset could not be found or +// could not be loaded. +func AssetInfo(name string) (os.FileInfo, error) { + cannonicalName := strings.Replace(name, "\\", "/", -1) + if f, ok := _bindata[cannonicalName]; ok { + a, err := f() + if err != nil { + return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) + } + return a.info, nil + } + return nil, fmt.Errorf("AssetInfo %s not found", name) +} + +// AssetNames returns the names of the assets. +func AssetNames() []string { + names := make([]string, 0, len(_bindata)) + for name := range _bindata { + names = append(names, name) + } + return names +} + +// _bindata is a table, holding each asset generator, mapped to its name. +var _bindata = map[string]func() (*asset, error){ + "bignumber.js": bignumberJs, +} + +// AssetDir returns the file names below a certain +// directory embedded in the file by go-bindata. +// For example if you run go-bindata on data/... and data contains the +// following hierarchy: +// data/ +// foo.txt +// img/ +// a.png +// b.png +// then AssetDir("data") would return []string{"foo.txt", "img"} +// AssetDir("data/img") would return []string{"a.png", "b.png"} +// AssetDir("foo.txt") and AssetDir("notexist") would return an error +// AssetDir("") will return []string{"data"}. +func AssetDir(name string) ([]string, error) { + node := _bintree + if len(name) != 0 { + cannonicalName := strings.Replace(name, "\\", "/", -1) + pathList := strings.Split(cannonicalName, "/") + for _, p := range pathList { + node = node.Children[p] + if node == nil { + return nil, fmt.Errorf("Asset %s not found", name) + } + } + } + if node.Func != nil { + return nil, fmt.Errorf("Asset %s not found", name) + } + rv := make([]string, 0, len(node.Children)) + for childName := range node.Children { + rv = append(rv, childName) + } + return rv, nil +} + +type bintree struct { + Func func() (*asset, error) + Children map[string]*bintree +} + +var _bintree = &bintree{nil, map[string]*bintree{ + "bignumber.js": {bignumberJs, map[string]*bintree{}}, +}} + +// RestoreAsset restores an asset under the given directory +func RestoreAsset(dir, name string) error { + data, err := Asset(name) + if err != nil { + return err + } + info, err := AssetInfo(name) + if err != nil { + return err + } + err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) + if err != nil { + return err + } + err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) + if err != nil { + return err + } + err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) + if err != nil { + return err + } + return nil +} + +// RestoreAssets restores an asset under the given directory recursively +func RestoreAssets(dir, name string) error { + children, err := AssetDir(name) + // File + if err != nil { + return RestoreAsset(dir, name) + } + // Dir + for _, child := range children { + err = RestoreAssets(dir, filepath.Join(name, child)) + if err != nil { + return err + } + } + return nil +} + +func _filePath(dir, name string) string { + cannonicalName := strings.Replace(name, "\\", "/", -1) + return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) +} diff --git a/signer/rules/deps/deps.go b/signer/rules/deps/deps.go new file mode 100644 index 0000000000..5ee00b900a --- /dev/null +++ b/signer/rules/deps/deps.go @@ -0,0 +1,21 @@ +// 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 deps contains the console JavaScript dependencies Go embedded. +package deps + +//go:generate go-bindata -nometadata -pkg deps -o bindata.go bignumber.js +//go:generate gofmt -w -s bindata.go diff --git a/signer/rules/rules.go b/signer/rules/rules.go new file mode 100644 index 0000000000..1f81e21bd0 --- /dev/null +++ b/signer/rules/rules.go @@ -0,0 +1,257 @@ +// 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 rules + +import ( + "encoding/json" + "fmt" + "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" + "github.com/ethereum/go-ethereum/signer/rules/deps" + "github.com/ethereum/go-ethereum/signer/storage" + "github.com/robertkrimen/otto" +) + +var ( + BigNumber_JS = deps.MustAsset("bignumber.js") +) + +// 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 consoleOutput(call otto.FunctionCall) otto.Value { + output := []string{"JS:> "} + for _, argument := range call.ArgumentList { + output = append(output, fmt.Sprintf("%v", argument)) + } + fmt.Fprintln(os.Stdout, strings.Join(output, " ")) + return otto.Value{} +} + +// rulesetUI provides an implementation of UIClientAPI that evaluates a javascript +// file for each defined UI-method +type rulesetUI struct { + next core.UIClientAPI // The next handler, for manual processing + storage storage.Storage + credentials storage.Storage + jsRules string // The rules to use +} + +func NewRuleEvaluator(next core.UIClientAPI, jsbackend, credentialsBackend storage.Storage) (*rulesetUI, error) { + c := &rulesetUI{ + next: next, + storage: jsbackend, + credentials: credentialsBackend, + 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 + return nil +} +func (r *rulesetUI) execute(jsfunc string, jsarg interface{}) (otto.Value, error) { + + // Instantiate a fresh vm engine every time + vm := otto.New() + // Set the native callbacks + consoleObj, _ := vm.Get("console") + consoleObj.Object().Set("log", consoleOutput) + consoleObj.Object().Set("error", consoleOutput) + vm.Set("storage", r.storage) + + // Load bootstrap libraries + script, err := vm.Compile("bignumber.js", BigNumber_JS) + if err != nil { + log.Warn("Failed loading libraries", "err", err) + return otto.UndefinedValue(), err + } + vm.Run(script) + + // Run the actual rule implementation + _, err = vm.Run(r.jsRules) + if err != nil { + log.Warn("Execution failed", "err", err) + return otto.UndefinedValue(), err + } + + // And the actual call + // All calls are objects with the parameters being keys in that object. + // To provide additional insulation between js and go, we serialize it into JSON on the Go-side, + // and deserialize it on the JS side. + + jsonbytes, err := json.Marshal(jsarg) + if err != nil { + log.Warn("failed marshalling data", "data", jsarg) + return otto.UndefinedValue(), err + } + // Now, we call foobar(JSON.parse()). + var call string + if len(jsonbytes) > 0 { + call = fmt.Sprintf("%v(JSON.parse(%v))", jsfunc, string(jsonbytes)) + } else { + call = fmt.Sprintf("%v()", jsfunc) + } + return vm.Run(call) +} + +func (r *rulesetUI) checkApproval(jsfunc string, jsarg []byte, err error) (bool, error) { + if err != nil { + return false, err + } + v, err := r.execute(jsfunc, string(jsarg)) + if err != nil { + log.Info("error occurred during execution", "error", err) + return false, err + } + result, err := v.ToString() + if err != nil { + log.Info("error occurred during response unmarshalling", "error", err) + return false, err + } + if result == "Approve" { + log.Info("Op approved") + return true, nil + } else if result == "Reject" { + log.Info("Op rejected") + return false, nil + } + return false, fmt.Errorf("Unknown response") +} + +func (r *rulesetUI) ApproveTx(request *core.SignTxRequest) (core.SignTxResponse, error) { + jsonreq, err := json.Marshal(request) + approved, err := r.checkApproval("ApproveTx", jsonreq, err) + if err != nil { + log.Info("Rule-based approval error, going to manual", "error", err) + return r.next.ApproveTx(request) + } + + if approved { + return core.SignTxResponse{ + Transaction: request.Transaction, + Approved: true, + Password: r.lookupPassword(request.Transaction.From.Address()), + }, + 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) + if err != nil { + log.Info("Rule-based approval error, going to manual", "error", err) + return r.next.ApproveSignData(request) + } + if approved { + return core.SignDataResponse{Approved: true, Password: r.lookupPassword(request.Address.Address())}, 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) +} + +// OnInputRequired not handled by rules +func (r *rulesetUI) OnInputRequired(info core.UserInputRequest) (core.UserInputResponse, error) { + return r.next.OnInputRequired(info) +} + +func (r *rulesetUI) ApproveListing(request *core.ListRequest) (core.ListResponse, error) { + jsonreq, err := json.Marshal(request) + approved, err := r.checkApproval("ApproveListing", jsonreq, err) + if err != nil { + log.Info("Rule-based approval error, going to manual", "error", err) + return r.next.ApproveListing(request) + } + if approved { + return core.ListResponse{Accounts: request.Accounts}, nil + } + return core.ListResponse{}, err +} + +func (r *rulesetUI) ApproveNewAccount(request *core.NewAccountRequest) (core.NewAccountResponse, error) { + // This cannot be handled by rules, requires setting a password + // dispatch to next + return r.next.ApproveNewAccount(request) +} + +func (r *rulesetUI) ShowError(message string) { + log.Error(message) + r.next.ShowError(message) +} + +func (r *rulesetUI) ShowInfo(message string) { + log.Info(message) + r.next.ShowInfo(message) +} + +func (r *rulesetUI) OnSignerStartup(info core.StartupInfo) { + jsonInfo, err := json.Marshal(info) + if err != nil { + log.Warn("failed marshalling data", "data", info) + return + } + r.next.OnSignerStartup(info) + _, err = r.execute("OnSignerStartup", string(jsonInfo)) + if err != nil { + log.Info("error occurred during execution", "error", err) + } +} + +func (r *rulesetUI) OnApprovedTx(tx ethapi.SignTransactionResult) { + jsonTx, err := json.Marshal(tx) + if err != nil { + log.Warn("failed marshalling transaction", "tx", tx) + return + } + _, err = r.execute("OnApprovedTx", string(jsonTx)) + if err != nil { + log.Info("error occurred during execution", "error", err) + } +} diff --git a/signer/rules/rules_test.go b/signer/rules/rules_test.go new file mode 100644 index 0000000000..eca4b29a04 --- /dev/null +++ b/signer/rules/rules_test.go @@ -0,0 +1,661 @@ +// 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 rules + +import ( + "fmt" + "math/big" + "strings" + "testing" + + "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/internal/ethapi" + "github.com/ethereum/go-ethereum/signer/core" + "github.com/ethereum/go-ethereum/signer/storage" +) + +const JS = ` +/** +This is an example implementation of a Javascript rule file. + +When the signer receives a request over the external API, the corresponding method is evaluated. +Three things can happen: + +1. The method returns "Approve". This means the operation is permitted. +2. The method returns "Reject". This means the operation is rejected. +3. Anything else; other return values [*], method not implemented or exception occurred during processing. This means +that the operation will continue to manual processing, via the regular UI method chosen by the user. + +[*] Note: Future version of the ruleset may use more complex json-based returnvalues, making it possible to not +only respond Approve/Reject/Manual, but also modify responses. For example, choose to list only one, but not all +accounts in a list-request. The points above will continue to hold for non-json based responses ("Approve"/"Reject"). + +**/ + +function ApproveListing(request){ + console.log("In js approve listing"); + console.log(request.accounts[3].Address) + console.log(request.meta.Remote) + return "Approve" +} + +function ApproveTx(request){ + console.log("test"); + console.log("from"); + return "Reject"; +} + +function test(thing){ + console.log(thing.String()) +} + +` + +func mixAddr(a string) (*common.MixedcaseAddress, error) { + return common.NewMixedcaseAddressFromString(a) +} + +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) ApproveTx(request *core.SignTxRequest) (core.SignTxResponse, error) { + return core.SignTxResponse{Transaction: request.Transaction, Approved: false, Password: ""}, 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 +} + +func (alwaysDenyUI) ApproveListing(request *core.ListRequest) (core.ListResponse, error) { + return core.ListResponse{Accounts: nil}, nil +} + +func (alwaysDenyUI) ApproveNewAccount(request *core.NewAccountRequest) (core.NewAccountResponse, error) { + return core.NewAccountResponse{Approved: false, Password: ""}, nil +} + +func (alwaysDenyUI) ShowError(message string) { + panic("implement me") +} + +func (alwaysDenyUI) ShowInfo(message string) { + panic("implement me") +} + +func (alwaysDenyUI) OnApprovedTx(tx ethapi.SignTransactionResult) { + panic("implement me") +} + +func initRuleEngine(js string) (*rulesetUI, error) { + r, err := NewRuleEvaluator(&alwaysDenyUI{}, storage.NewEphemeralStorage(), storage.NewEphemeralStorage()) + if err != nil { + return nil, fmt.Errorf("failed to create js engine: %v", err) + } + if err = r.Init(js); err != nil { + return nil, fmt.Errorf("failed to load bootstrap js: %v", err) + } + return r, nil +} + +func TestListRequest(t *testing.T) { + accs := make([]accounts.Account, 5) + + for i := range accs { + addr := fmt.Sprintf("000000000000000000000000000000000000000%x", i) + acc := accounts.Account{ + Address: common.BytesToAddress(common.Hex2Bytes(addr)), + URL: accounts.URL{Scheme: "test", Path: fmt.Sprintf("acc-%d", i)}, + } + accs[i] = acc + } + + js := `function ApproveListing(){ return "Approve" }` + + r, err := initRuleEngine(js) + if err != nil { + t.Errorf("Couldn't create evaluator %v", err) + return + } + resp, _ := r.ApproveListing(&core.ListRequest{ + Accounts: accs, + Meta: core.Metadata{Remote: "remoteip", Local: "localip", Scheme: "inproc"}, + }) + if len(resp.Accounts) != len(accs) { + t.Errorf("Expected check to resolve to 'Approve'") + } +} + +func TestSignTxRequest(t *testing.T) { + + js := ` + function ApproveTx(r){ + console.log("transaction.from", r.transaction.from); + console.log("transaction.to", r.transaction.to); + console.log("transaction.value", r.transaction.value); + console.log("transaction.nonce", r.transaction.nonce); + if(r.transaction.from.toLowerCase()=="0x0000000000000000000000000000000000001337"){ return "Approve"} + if(r.transaction.from.toLowerCase()=="0x000000000000000000000000000000000000dead"){ return "Reject"} + }` + + r, err := initRuleEngine(js) + if err != nil { + t.Errorf("Couldn't create evaluator %v", err) + return + } + to, err := mixAddr("000000000000000000000000000000000000dead") + if err != nil { + t.Error(err) + return + } + from, err := mixAddr("0000000000000000000000000000000000001337") + + if err != nil { + t.Error(err) + return + } + fmt.Printf("to %v", to.Address().String()) + resp, err := r.ApproveTx(&core.SignTxRequest{ + Transaction: core.SendTxArgs{ + From: *from, + To: to}, + Callinfo: nil, + Meta: core.Metadata{Remote: "remoteip", Local: "localip", Scheme: "inproc"}, + }) + if err != nil { + t.Errorf("Unexpected error %v", err) + } + if !resp.Approved { + t.Errorf("Expected check to resolve to 'Approve'") + } +} + +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 +} + +func (d *dummyUI) ApproveTx(request *core.SignTxRequest) (core.SignTxResponse, error) { + d.calls = append(d.calls, "ApproveTx") + return core.SignTxResponse{}, core.ErrRequestDenied +} + +func (d *dummyUI) ApproveSignData(request *core.SignDataRequest) (core.SignDataResponse, error) { + d.calls = append(d.calls, "ApproveSignData") + 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 +} + +func (d *dummyUI) ApproveNewAccount(request *core.NewAccountRequest) (core.NewAccountResponse, error) { + d.calls = append(d.calls, "ApproveNewAccount") + return core.NewAccountResponse{}, core.ErrRequestDenied +} + +func (d *dummyUI) ShowError(message string) { + d.calls = append(d.calls, "ShowError") +} + +func (d *dummyUI) ShowInfo(message string) { + d.calls = append(d.calls, "ShowInfo") +} + +func (d *dummyUI) OnApprovedTx(tx ethapi.SignTransactionResult) { + d.calls = append(d.calls, "OnApprovedTx") +} + +func (d *dummyUI) OnSignerStartup(info core.StartupInfo) { +} + +//TestForwarding tests that the rule-engine correctly dispatches requests to the next caller +func TestForwarding(t *testing.T) { + + js := "" + ui := &dummyUI{make([]string, 0)} + jsBackend := storage.NewEphemeralStorage() + credBackend := storage.NewEphemeralStorage() + r, err := NewRuleEvaluator(ui, jsBackend, credBackend) + if err != nil { + t.Fatalf("Failed to create js engine: %v", err) + } + if err = r.Init(js); err != nil { + t.Fatalf("Failed to load bootstrap js: %v", err) + } + 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 + if len(ui.calls) != expCalls { + + t.Errorf("Expected %d forwarded calls, got %d: %s", expCalls, len(ui.calls), strings.Join(ui.calls, ",")) + + } + +} + +func TestMissingFunc(t *testing.T) { + r, err := initRuleEngine(JS) + if err != nil { + t.Errorf("Couldn't create evaluator %v", err) + return + } + + _, err = r.execute("MissingMethod", "test") + + if err == nil { + t.Error("Expected error") + } + + approved, err := r.checkApproval("MissingMethod", nil, nil) + if err == nil { + t.Errorf("Expected missing method to yield error'") + } + if approved { + t.Errorf("Expected missing method to cause non-approval") + } + fmt.Printf("Err %v", err) + +} +func TestStorage(t *testing.T) { + + js := ` + function testStorage(){ + storage.Put("mykey", "myvalue") + a = storage.Get("mykey") + + storage.Put("mykey", ["a", "list"]) // Should result in "a,list" + a += storage.Get("mykey") + + + storage.Put("mykey", {"an": "object"}) // Should result in "[object Object]" + a += storage.Get("mykey") + + + storage.Put("mykey", JSON.stringify({"an": "object"})) // Should result in '{"an":"object"}' + a += storage.Get("mykey") + + a += storage.Get("missingkey") //Missing keys should result in empty string + storage.Put("","missing key==noop") // Can't store with 0-length key + a += storage.Get("") // Should result in '' + + var b = new BigNumber(2) + var c = new BigNumber(16)//"0xf0",16) + var d = b.plus(c) + console.log(d) + return a + } +` + r, err := initRuleEngine(js) + if err != nil { + t.Errorf("Couldn't create evaluator %v", err) + return + } + + v, err := r.execute("testStorage", nil) + + if err != nil { + t.Errorf("Unexpected error %v", err) + } + + retval, err := v.ToString() + + if err != nil { + t.Errorf("Unexpected error %v", err) + } + exp := `myvaluea,list[object Object]{"an":"object"}` + if retval != exp { + t.Errorf("Unexpected data, expected '%v', got '%v'", exp, retval) + } + fmt.Printf("Err %v", err) + +} + +const ExampleTxWindow = ` + function big(str){ + if(str.slice(0,2) == "0x"){ return new BigNumber(str.slice(2),16)} + return new BigNumber(str) + } + + // Time window: 1 week + var window = 1000* 3600*24*7; + + // Limit : 1 ether + var limit = new BigNumber("1e18"); + + function isLimitOk(transaction){ + var value = big(transaction.value) + // Start of our window function + var windowstart = new Date().getTime() - window; + + var txs = []; + var stored = storage.Get('txs'); + + if(stored != ""){ + txs = JSON.parse(stored) + } + // First, remove all that have passed out of the time-window + var newtxs = txs.filter(function(tx){return tx.tstamp > windowstart}); + console.log(txs, newtxs.length); + + // Secondly, aggregate the current sum + sum = new BigNumber(0) + + sum = newtxs.reduce(function(agg, tx){ return big(tx.value).plus(agg)}, sum); + console.log("ApproveTx > Sum so far", sum); + console.log("ApproveTx > Requested", value.toNumber()); + + // Would we exceed weekly limit ? + return sum.plus(value).lt(limit) + + } + function ApproveTx(r){ + console.log(r) + console.log(typeof(r)) + if (isLimitOk(r.transaction)){ + return "Approve" + } + return "Nope" + } + + /** + * OnApprovedTx(str) is called when a transaction has been approved and signed. The parameter + * 'response_str' contains the return value that will be sent to the external caller. + * The return value from this method is ignore - the reason for having this callback is to allow the + * ruleset to keep track of approved transactions. + * + * When implementing rate-limited rules, this callback should be used. + * If a rule responds with neither 'Approve' nor 'Reject' - the tx goes to manual processing. If the user + * then accepts the transaction, this method will be called. + * + * TLDR; Use this method to keep track of signed transactions, instead of using the data in ApproveTx. + */ + function OnApprovedTx(resp){ + var value = big(resp.tx.value) + var txs = [] + // Load stored transactions + var stored = storage.Get('txs'); + if(stored != ""){ + txs = JSON.parse(stored) + } + // Add this to the storage + txs.push({tstamp: new Date().getTime(), value: value}); + storage.Put("txs", JSON.stringify(txs)); + } + +` + +func dummyTx(value hexutil.Big) *core.SignTxRequest { + + to, _ := mixAddr("000000000000000000000000000000000000dead") + from, _ := mixAddr("000000000000000000000000000000000000dead") + n := hexutil.Uint64(3) + gas := hexutil.Uint64(21000) + gasPrice := hexutil.Big(*big.NewInt(2000000)) + + return &core.SignTxRequest{ + Transaction: core.SendTxArgs{ + From: *from, + To: to, + Value: value, + Nonce: n, + GasPrice: gasPrice, + Gas: gas, + }, + Callinfo: []core.ValidationInfo{ + {Typ: "Warning", Message: "All your base are bellong to us"}, + }, + Meta: core.Metadata{Remote: "remoteip", Local: "localip", Scheme: "inproc"}, + } +} +func dummyTxWithV(value uint64) *core.SignTxRequest { + + v := big.NewInt(0).SetUint64(value) + h := hexutil.Big(*v) + return dummyTx(h) +} +func dummySigned(value *big.Int) *types.Transaction { + to := common.HexToAddress("000000000000000000000000000000000000dead") + gas := uint64(21000) + gasPrice := big.NewInt(2000000) + data := make([]byte, 0) + return types.NewTransaction(3, to, value, gas, gasPrice, data) + +} +func TestLimitWindow(t *testing.T) { + + r, err := initRuleEngine(ExampleTxWindow) + if err != nil { + t.Errorf("Couldn't create evaluator %v", err) + return + } + + // 0.3 ether: 429D069189E0000 wei + v := big.NewInt(0).SetBytes(common.Hex2Bytes("0429D069189E0000")) + h := hexutil.Big(*v) + // The first three should succeed + for i := 0; i < 3; i++ { + unsigned := dummyTx(h) + resp, err := r.ApproveTx(unsigned) + if err != nil { + t.Errorf("Unexpected error %v", err) + } + if !resp.Approved { + t.Errorf("Expected check to resolve to 'Approve'") + } + // Create a dummy signed transaction + + response := ethapi.SignTransactionResult{ + Tx: dummySigned(v), + Raw: common.Hex2Bytes("deadbeef"), + } + r.OnApprovedTx(response) + } + // Fourth should fail + resp, _ := r.ApproveTx(dummyTx(h)) + if resp.Approved { + t.Errorf("Expected check to resolve to 'Reject'") + } + +} + +// dontCallMe is used as a next-handler that does not want to be called - it invokes test failure +type dontCallMe struct { + t *testing.T +} + +func (d *dontCallMe) OnInputRequired(info core.UserInputRequest) (core.UserInputResponse, error) { + d.t.Fatalf("Did not expect next-handler to be called") + return core.UserInputResponse{}, nil +} +func (d *dontCallMe) RegisterUIServer(api *core.UIServerAPI) { +} + +func (d *dontCallMe) OnSignerStartup(info core.StartupInfo) { +} + +func (d *dontCallMe) ApproveTx(request *core.SignTxRequest) (core.SignTxResponse, error) { + d.t.Fatalf("Did not expect next-handler to be called") + return core.SignTxResponse{}, core.ErrRequestDenied +} + +func (d *dontCallMe) ApproveSignData(request *core.SignDataRequest) (core.SignDataResponse, error) { + d.t.Fatalf("Did not expect next-handler to be called") + 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 +} + +func (d *dontCallMe) ApproveNewAccount(request *core.NewAccountRequest) (core.NewAccountResponse, error) { + d.t.Fatalf("Did not expect next-handler to be called") + return core.NewAccountResponse{}, core.ErrRequestDenied +} + +func (d *dontCallMe) ShowError(message string) { + d.t.Fatalf("Did not expect next-handler to be called") +} + +func (d *dontCallMe) ShowInfo(message string) { + d.t.Fatalf("Did not expect next-handler to be called") +} + +func (d *dontCallMe) OnApprovedTx(tx ethapi.SignTransactionResult) { + d.t.Fatalf("Did not expect next-handler to be called") +} + +//TestContextIsCleared tests that the rule-engine does not retain variables over several requests. +// if it does, that would be bad since developers may rely on that to store data, +// instead of using the disk-based data storage +func TestContextIsCleared(t *testing.T) { + + js := ` + function ApproveTx(){ + if (typeof foobar == 'undefined') { + foobar = "Approve" + } + console.log(foobar) + if (foobar == "Approve"){ + foobar = "Reject" + }else{ + foobar = "Approve" + } + return foobar + } + ` + ui := &dontCallMe{t} + r, err := NewRuleEvaluator(ui, storage.NewEphemeralStorage(), storage.NewEphemeralStorage()) + if err != nil { + t.Fatalf("Failed to create js engine: %v", err) + } + if err = r.Init(js); err != nil { + t.Fatalf("Failed to load bootstrap js: %v", err) + } + tx := dummyTxWithV(0) + r1, _ := r.ApproveTx(tx) + r2, _ := r.ApproveTx(tx) + if r1.Approved != r2.Approved { + t.Errorf("Expected execution context to be cleared between executions") + } +} + +func TestSignData(t *testing.T) { + + js := `function ApproveListing(){ + return "Approve" +} +function ApproveSignData(r){ + if( r.address.toLowerCase() == "0x694267f14675d7e1b9494fd8d72fefe1755710fa") + { + if(r.message[0].value.indexOf("bazonk") >= 0){ + return "Approve" + } + return "Reject" + } + // Otherwise goes to manual processing +}` + r, err := initRuleEngine(js) + if err != nil { + t.Errorf("Couldn't create evaluator %v", err) + return + } + 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: nvt, + Hash: hash, + Meta: core.Metadata{Remote: "remoteip", Local: "localip", Scheme: "inproc"}, + Rawdata: []byte(rawdata), + }) + if err != nil { + t.Fatalf("Unexpected error %v", err) + } + if !resp.Approved { + t.Fatalf("Expected approved") + } +} diff --git a/signer/storage/aes_gcm_storage.go b/signer/storage/aes_gcm_storage.go new file mode 100644 index 0000000000..9008318679 --- /dev/null +++ b/signer/storage/aes_gcm_storage.go @@ -0,0 +1,166 @@ +// 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 storage + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "encoding/json" + "io" + "io/ioutil" + "os" + + "github.com/ethereum/go-ethereum/log" +) + +type storedCredential struct { + // The iv + Iv []byte `json:"iv"` + // The ciphertext + CipherText []byte `json:"c"` +} + +// AESEncryptedStorage is a storage type which is backed by a json-file. The json-file contains +// key-value mappings, where the keys are _not_ encrypted, only the values are. +type AESEncryptedStorage struct { + // File to read/write credentials + filename string + // Key stored in base64 + key []byte +} + +// NewAESEncryptedStorage creates a new encrypted storage backed by the given file/key +func NewAESEncryptedStorage(filename string, key []byte) *AESEncryptedStorage { + return &AESEncryptedStorage{ + filename: filename, + key: key, + } +} + +// Put stores a value by key. 0-length keys results in no-op +func (s *AESEncryptedStorage) Put(key, value string) { + if len(key) == 0 { + return + } + data, err := s.readEncryptedStorage() + if err != nil { + log.Warn("Failed to read encrypted storage", "err", err, "file", s.filename) + return + } + ciphertext, iv, err := encrypt(s.key, []byte(value), []byte(key)) + if err != nil { + log.Warn("Failed to encrypt entry", "err", err) + return + } + encrypted := storedCredential{Iv: iv, CipherText: ciphertext} + data[key] = encrypted + if err = s.writeEncryptedStorage(data); err != nil { + log.Warn("Failed to write entry", "err", err) + } +} + +// Get returns the previously stored value, or the empty string if it does not exist or key is of 0-length +func (s *AESEncryptedStorage) Get(key string) string { + if len(key) == 0 { + return "" + } + data, err := s.readEncryptedStorage() + if err != nil { + log.Warn("Failed to read encrypted storage", "err", err, "file", s.filename) + return "" + } + encrypted, exist := data[key] + if !exist { + log.Warn("Key does not exist", "key", key) + return "" + } + entry, err := decrypt(s.key, encrypted.Iv, encrypted.CipherText, []byte(key)) + if err != nil { + log.Warn("Failed to decrypt key", "key", key) + return "" + } + return string(entry) +} + +// readEncryptedStorage reads the file with encrypted creds +func (s *AESEncryptedStorage) readEncryptedStorage() (map[string]storedCredential, error) { + creds := make(map[string]storedCredential) + raw, err := ioutil.ReadFile(s.filename) + + if err != nil { + if os.IsNotExist(err) { + // Doesn't exist yet + return creds, nil + } + log.Warn("Failed to read encrypted storage", "err", err, "file", s.filename) + } + if err = json.Unmarshal(raw, &creds); err != nil { + log.Warn("Failed to unmarshal encrypted storage", "err", err, "file", s.filename) + return nil, err + } + return creds, nil +} + +// writeEncryptedStorage write the file with encrypted creds +func (s *AESEncryptedStorage) writeEncryptedStorage(creds map[string]storedCredential) error { + raw, err := json.Marshal(creds) + if err != nil { + return err + } + if err = ioutil.WriteFile(s.filename, raw, 0600); err != nil { + return err + } + return nil +} + +// encrypt encrypts plaintext with the given key, with additional data +// The 'additionalData' is used to place the (plaintext) KV-store key into the V, +// to prevent the possibility to alter a K, or swap two entries in the KV store with eachother. +func encrypt(key []byte, plaintext []byte, additionalData []byte) ([]byte, []byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, nil, err + } + aesgcm, err := cipher.NewGCM(block) + nonce := make([]byte, aesgcm.NonceSize()) + if _, err := io.ReadFull(rand.Reader, nonce); err != nil { + return nil, nil, err + } + if err != nil { + return nil, nil, err + } + ciphertext := aesgcm.Seal(nil, nonce, plaintext, additionalData) + return ciphertext, nonce, nil +} + +func decrypt(key []byte, nonce []byte, ciphertext []byte, additionalData []byte) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + aesgcm, err := cipher.NewGCM(block) + if err != nil { + return nil, err + } + plaintext, err := aesgcm.Open(nil, nonce, ciphertext, additionalData) + if err != nil { + return nil, err + } + return plaintext, nil +} diff --git a/signer/storage/aes_gcm_storage_test.go b/signer/storage/aes_gcm_storage_test.go new file mode 100644 index 0000000000..a421a8449d --- /dev/null +++ b/signer/storage/aes_gcm_storage_test.go @@ -0,0 +1,164 @@ +// 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 storage + +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/log" + "github.com/mattn/go-colorable" +) + +func TestEncryption(t *testing.T) { + // key := []byte("AES256Key-32Characters1234567890") + // plaintext := []byte(value) + key := []byte("AES256Key-32Characters1234567890") + plaintext := []byte("exampleplaintext") + + c, iv, err := encrypt(key, plaintext, nil) + if err != nil { + t.Fatal(err) + } + fmt.Printf("Ciphertext %x, nonce %x\n", c, iv) + + p, err := decrypt(key, iv, c, nil) + if err != nil { + t.Fatal(err) + } + fmt.Printf("Plaintext %v\n", string(p)) + if !bytes.Equal(plaintext, p) { + t.Errorf("Failed: expected plaintext recovery, got %v expected %v", string(plaintext), string(p)) + } +} + +func TestFileStorage(t *testing.T) { + + a := map[string]storedCredential{ + "secret": { + Iv: common.Hex2Bytes("cdb30036279601aeee60f16b"), + CipherText: common.Hex2Bytes("f311ac49859d7260c2c464c28ffac122daf6be801d3cfd3edcbde7e00c9ff74f"), + }, + "secret2": { + Iv: common.Hex2Bytes("afb8a7579bf971db9f8ceeed"), + CipherText: common.Hex2Bytes("2df87baf86b5073ef1f03e3cc738de75b511400f5465bb0ddeacf47ae4dc267d"), + }, + } + d, err := ioutil.TempDir("", "eth-encrypted-storage-test") + if err != nil { + t.Fatal(err) + } + stored := &AESEncryptedStorage{ + filename: fmt.Sprintf("%v/vault.json", d), + key: []byte("AES256Key-32Characters1234567890"), + } + stored.writeEncryptedStorage(a) + read := &AESEncryptedStorage{ + filename: fmt.Sprintf("%v/vault.json", d), + key: []byte("AES256Key-32Characters1234567890"), + } + creds, err := read.readEncryptedStorage() + if err != nil { + t.Fatal(err) + } + for k, v := range a { + if v2, exist := creds[k]; !exist { + t.Errorf("Missing entry %v", k) + } else { + if !bytes.Equal(v.CipherText, v2.CipherText) { + t.Errorf("Wrong ciphertext, expected %x got %x", v.CipherText, v2.CipherText) + } + if !bytes.Equal(v.Iv, v2.Iv) { + t.Errorf("Wrong iv") + } + } + } +} +func TestEnd2End(t *testing.T) { + log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(3), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true)))) + + d, err := ioutil.TempDir("", "eth-encrypted-storage-test") + if err != nil { + t.Fatal(err) + } + + s1 := &AESEncryptedStorage{ + filename: fmt.Sprintf("%v/vault.json", d), + key: []byte("AES256Key-32Characters1234567890"), + } + s2 := &AESEncryptedStorage{ + filename: fmt.Sprintf("%v/vault.json", d), + key: []byte("AES256Key-32Characters1234567890"), + } + + s1.Put("bazonk", "foobar") + if v := s2.Get("bazonk"); v != "foobar" { + t.Errorf("Expected bazonk->foobar, got '%v'", v) + } +} + +func TestSwappedKeys(t *testing.T) { + // It should not be possible to swap the keys/values, so that + // K1:V1, K2:V2 can be swapped into K1:V2, K2:V1 + log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(3), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true)))) + + d, err := ioutil.TempDir("", "eth-encrypted-storage-test") + if err != nil { + t.Fatal(err) + } + + s1 := &AESEncryptedStorage{ + filename: fmt.Sprintf("%v/vault.json", d), + key: []byte("AES256Key-32Characters1234567890"), + } + s1.Put("k1", "v1") + s1.Put("k2", "v2") + // Now make a modified copy + + creds := make(map[string]storedCredential) + raw, err := ioutil.ReadFile(s1.filename) + if err != nil { + t.Fatal(err) + } + if err = json.Unmarshal(raw, &creds); err != nil { + t.Fatal(err) + } + swap := func() { + // Turn it into K1:V2, K2:V2 + v1, v2 := creds["k1"], creds["k2"] + creds["k2"], creds["k1"] = v1, v2 + raw, err = json.Marshal(creds) + if err != nil { + t.Fatal(err) + } + if err = ioutil.WriteFile(s1.filename, raw, 0600); err != nil { + t.Fatal(err) + } + } + swap() + if v := s1.Get("k1"); v != "" { + t.Errorf("swapped value should return empty") + } + swap() + if v := s1.Get("k1"); v != "v1" { + t.Errorf("double-swapped value should work fine") + } +} diff --git a/signer/storage/storage.go b/signer/storage/storage.go new file mode 100644 index 0000000000..60f4e3892a --- /dev/null +++ b/signer/storage/storage.go @@ -0,0 +1,62 @@ +// 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 storage + +import ( + "fmt" +) + +type Storage interface { + // Put stores a value by key. 0-length keys results in no-op + Put(key, value string) + // Get returns the previously stored value, or the empty string if it does not exist or key is of 0-length + Get(key string) string +} + +// EphemeralStorage is an in-memory storage that does +// not persist values to disk. Mainly used for testing +type EphemeralStorage struct { + data map[string]string + namespace string +} + +func (s *EphemeralStorage) Put(key, value string) { + if len(key) == 0 { + return + } + fmt.Printf("storage: put %v -> %v\n", key, value) + s.data[key] = value +} + +func (s *EphemeralStorage) Get(key string) string { + if len(key) == 0 { + return "" + } + fmt.Printf("storage: get %v\n", key) + if v, exist := s.data[key]; exist { + return v + } + return "" +} + +func NewEphemeralStorage() Storage { + s := &EphemeralStorage{ + data: make(map[string]string), + } + return s +} diff --git a/swarm/AUTHORS b/swarm/AUTHORS new file mode 100644 index 0000000000..f7232f07ce --- /dev/null +++ b/swarm/AUTHORS @@ -0,0 +1,35 @@ +# Core team members + +Viktor Trón - @zelig +Louis Holbrook - @nolash +Lewis Marshall - @lmars +Anton Evangelatov - @nonsense +Janoš Guljaš - @janos +Balint Gabor - @gbalint +Elad Nachmias - @justelad +Daniel A. Nagy - @nagydani +Aron Fischer - @homotopycolimit +Fabio Barone - @holisticode +Zahoor Mohamed - @jmozah +Zsolt Felföldi - @zsfelfoldi + +# External contributors + +Kiel Barry +Gary Rong +Jared Wasinger +Leon Stanko +Javier Peletier [epiclabs.io] +Bartek Borkowski [tungsten-labs.com] +Shane Howley [mainframe.com] +Doug Leonard [mainframe.com] +Ivan Daniluk [status.im] +Felix Lange [EF] +Martin Holst Swende [EF] +Guillaume Ballet [EF] +ligi [EF] +Christopher Dro [blick-labs.com] +Sergii Bomko [ledgerleopard.com] +Domino Valdano +Rafael Matias +Coogan Brennan \ No newline at end of file diff --git a/swarm/OWNERS b/swarm/OWNERS new file mode 100644 index 0000000000..4b9ca96ebe --- /dev/null +++ b/swarm/OWNERS @@ -0,0 +1,25 @@ +# Ownership by go packages + +swarm +├── api ─────────────────── ethersphere +├── bmt ─────────────────── @zelig +├── dev ─────────────────── @lmars +├── fuse ────────────────── @jmozah, @holisticode +├── grafana_dashboards ──── @nonsense +├── metrics ─────────────── @nonsense, @holisticode +├── network ─────────────── ethersphere +│ ├── bitvector ───────── @zelig, @janos, @gbalint +│ ├── priorityqueue ───── @zelig, @janos, @gbalint +│ ├── simulations ─────── @zelig +│ └── stream ──────────── @janos, @zelig, @gbalint, @holisticode, @justelad +│ ├── intervals ───── @janos +│ └── testing ─────── @zelig +├── pot ─────────────────── @zelig +├── pss ─────────────────── @nolash, @zelig, @nonsense +├── services ────────────── @zelig +├── state ───────────────── @justelad +├── storage ─────────────── ethersphere +│ ├── encryption ──────── @gbalint, @zelig, @nagydani +│ ├── mock ────────────── @janos +│ └── feed ────────────── @nolash, @jpeletier +└── testutil ────────────── @lmars \ No newline at end of file diff --git a/swarm/README.md b/swarm/README.md new file mode 100644 index 0000000000..e81963217f --- /dev/null +++ b/swarm/README.md @@ -0,0 +1,244 @@ +## Swarm + +[https://swarm.ethereum.org](https://swarm.ethereum.org) + +Swarm is a distributed storage platform and content distribution service, a native base layer service of the ethereum web3 stack. The primary objective of Swarm is to provide a decentralized and redundant store for dapp code and data as well as block chain and state data. Swarm is also set out to provide various base layer services for web3, including node-to-node messaging, media streaming, decentralised database services and scalable state-channel infrastructure for decentralised service economies. + +[![Travis](https://travis-ci.org/ethereum/go-ethereum.svg?branch=master)](https://travis-ci.org/ethereum/go-ethereum) +[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ethersphere/orange-lounge?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) + +## Table of Contents + +* [Building the source](#building-the-source) +* [Running Swarm](#running-swarm) +* [Documentation](#documentation) +* [Developers Guide](#developers-guide) + * [Go Environment](#development-environment) + * [Vendored Dependencies](#vendored-dependencies) + * [Testing](#testing) + * [Profiling Swarm](#profiling-swarm) + * [Metrics and Instrumentation in Swarm](#metrics-and-instrumentation-in-swarm) +* [Public Gateways](#public-gateways) +* [Swarm Dapps](#swarm-dapps) +* [Contributing](#contributing) +* [License](#license) + +## Building the source + +Building Swarm requires Go (version 1.10 or later). + + go get -d github.com/ethereum/go-ethereum + + go install github.com/ethereum/go-ethereum/cmd/swarm + +## Running Swarm + +Going through all the possible command line flags is out of scope here, but we've enumerated a few common parameter combos to get you up to speed quickly on how you can run your own Swarm node. + +To run Swarm you need an Ethereum account. You can create a new account by running the following command: + + geth account new + +You will be prompted for a password: + + Your new account is locked with a password. Please give a password. Do not forget this password. + Passphrase: + Repeat passphrase: + +Once you have specified the password, the output will be the Ethereum address representing that account. For example: + + Address: {2f1cd699b0bf461dcfbf0098ad8f5587b038f0f1} + +Using this account, connect to Swarm with + + swarm --bzzaccount + + # in our example + + swarm --bzzaccount 2f1cd699b0bf461dcfbf0098ad8f5587b038f0f1 + + +### Verifying that your local Swarm node is running + +When running, Swarm is accessible through an HTTP API on port 8500. + +Confirm that it is up and running by pointing your browser to http://localhost:8500 + +### Ethereum Name Service resolution + +The Ethereum Name Service is the Ethereum equivalent of DNS in the classic web. In order to use ENS to resolve names to Swarm content hashes (e.g. `bzz://theswarm.eth`), `swarm` has to connect to a `geth` instance, which is synced with the Ethereum mainnet. This is done using the `--ens-api` flag. + + swarm --bzzaccount \ + --ens-api '$HOME/.ethereum/geth.ipc' + + # in our example + + swarm --bzzaccount 2f1cd699b0bf461dcfbf0098ad8f5587b038f0f1 \ + --ens-api '$HOME/.ethereum/geth.ipc' + +For more information on usage, features or command line flags, please consult the Documentation. + + +## Documentation + +Swarm documentation can be found at [https://swarm-guide.readthedocs.io](https://swarm-guide.readthedocs.io). + + +## Developers Guide + +### Go Environment + +We assume that you have Go v1.10 installed, and `GOPATH` is set. + +You must have your working copy under `$GOPATH/src/github.com/ethereum/go-ethereum`. + +Most likely you will be working from your fork of `go-ethereum`, let's say from `github.com/nirname/go-ethereum`. Clone or move your fork into the right place: + +``` +git clone git@github.com:nirname/go-ethereum.git $GOPATH/src/github.com/ethereum/go-ethereum +``` + + +### Vendored Dependencies + +All dependencies are tracked in the `vendor` directory. We use `govendor` to manage them. + +If you want to add a new dependency, run `govendor fetch `, then commit the result. + +If you want to update all dependencies to their latest upstream version, run `govendor fetch +v`. + + +### Testing + +This section explains how to run unit, integration, and end-to-end tests in your development sandbox. + +Testing one library: + +``` +go test -v -cpu 4 ./swarm/api +``` + +Note: Using options -cpu (number of cores allowed) and -v (logging even if no error) is recommended. + +Testing only some methods: + +``` +go test -v -cpu 4 ./eth -run TestMethod +``` + +Note: here all tests with prefix TestMethod will be run, so if you got TestMethod, TestMethod1, then both! + +Running benchmarks: + +``` +go test -v -cpu 4 -bench . -run BenchmarkJoin +``` + + +### Profiling Swarm + +This section explains how to add Go `pprof` profiler to Swarm + +If `swarm` is started with the `--pprof` option, a debugging HTTP server is made available on port 6060. + +You can bring up http://localhost:6060/debug/pprof to see the heap, running routines etc. + +By clicking full goroutine stack dump (clicking http://localhost:6060/debug/pprof/goroutine?debug=2) you can generate trace that is useful for debugging. + + +### Metrics and Instrumentation in Swarm + +This section explains how to visualize and use existing Swarm metrics and how to instrument Swarm with a new metric. + +Swarm metrics system is based on the `go-metrics` library. + +The most common types of measurements we use in Swarm are `counters` and `resetting timers`. Consult the `go-metrics` documentation for full reference of available types. + +``` +# incrementing a counter +metrics.GetOrRegisterCounter("network.stream.received_chunks", nil).Inc(1) + +# measuring latency with a resetting timer +start := time.Now() +t := metrics.GetOrRegisterResettingTimer("http.request.GET.time"), nil) +... +t := UpdateSince(start) +``` + +#### Visualizing metrics + +Swarm supports an InfluxDB exporter. Consult the help section to learn about the command line arguments used to configure it: + +``` +swarm --help | grep metrics +``` + +We use Grafana and InfluxDB to visualise metrics reported by Swarm. We keep our Grafana dashboards under version control at `./swarm/grafana_dashboards`. You could use them or design your own. + +We have built a tool to help with automatic start of Grafana and InfluxDB and provisioning of dashboards at https://github.com/nonsense/stateth , which requires that you have Docker installed. + +Once you have `stateth` installed, and you have Docker running locally, you have to: + +1. Run `stateth` and keep it running in the background +``` +stateth --rm --grafana-dashboards-folder $GOPATH/src/github.com/ethereum/go-ethereum/swarm/grafana_dashboards --influxdb-database metrics +``` + +2. Run `swarm` with at least the following params: +``` +--metrics \ +--metrics.influxdb.export \ +--metrics.influxdb.endpoint "http://localhost:8086" \ +--metrics.influxdb.username "admin" \ +--metrics.influxdb.password "admin" \ +--metrics.influxdb.database "metrics" +``` + +3. Open Grafana at http://localhost:3000 and view the dashboards to gain insight into Swarm. + + +## Public Gateways + +Swarm offers a local HTTP proxy API that Dapps can use to interact with Swarm. The Ethereum Foundation is hosting a public gateway, which allows free access so that people can try Swarm without running their own node. + +The Swarm public gateways are temporary and users should not rely on their existence for production services. + +The Swarm public gateway can be found at https://swarm-gateways.net and is always running the latest `stable` Swarm release. + +## Swarm Dapps + +You can find a few reference Swarm decentralised applications at: https://swarm-gateways.net/bzz:/swarmapps.eth + +Their source code can be found at: https://github.com/ethersphere/swarm-dapps + +## Contributing + +Thank you for considering to help out with the source code! We welcome contributions from +anyone on the internet, and are grateful for even the smallest of fixes! + +If you'd like to contribute to Swarm, please fork, fix, commit and send a pull request +for the maintainers to review and merge into the main code base. If you wish to submit more +complex changes though, please check up with the core devs first on [our Swarm gitter channel](https://gitter.im/ethersphere/orange-lounge) +to ensure those changes are in line with the general philosophy of the project and/or get some +early feedback which can make both your efforts much lighter as well as our review and merge +procedures quick and simple. + +Please make sure your contributions adhere to our coding guidelines: + + * Code must adhere to the official Go [formatting](https://golang.org/doc/effective_go.html#formatting) guidelines (i.e. uses [gofmt](https://golang.org/cmd/gofmt/)). + * Code must be documented adhering to the official Go [commentary](https://golang.org/doc/effective_go.html#commentary) guidelines. + * Pull requests need to be based on and opened against the `master` branch. + * [Code review guidelines](https://github.com/ethereum/go-ethereum/wiki/Code-Review-Guidelines). + * Commit messages should be prefixed with the package(s) they modify. + * E.g. "swarm/fuse: ignore default manifest entry" + + +## License + +The go-ethereum library (i.e. all code outside of the `cmd` directory) is licensed under the +[GNU Lesser General Public License v3.0](https://www.gnu.org/licenses/lgpl-3.0.en.html), also +included in our repository in the `COPYING.LESSER` file. + +The go-ethereum binaries (i.e. all code inside of the `cmd` directory) is licensed under the +[GNU General Public License v3.0](https://www.gnu.org/licenses/gpl-3.0.en.html), also included +in our repository in the `COPYING` file. diff --git a/swarm/api/act.go b/swarm/api/act.go new file mode 100644 index 0000000000..a79f1944b9 --- /dev/null +++ b/swarm/api/act.go @@ -0,0 +1,538 @@ +package api + +import ( + "context" + "crypto/ecdsa" + "crypto/rand" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "io" + "strings" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/crypto/ecies" + "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" +) + +var ( + ErrDecrypt = errors.New("cant decrypt - forbidden") + ErrUnknownAccessType = errors.New("unknown access type (or not implemented)") + ErrDecryptDomainForbidden = errors.New("decryption request domain forbidden - can only decrypt on localhost") + AllowedDecryptDomains = []string{ + "localhost", + "127.0.0.1", + } +) + +const EmptyCredentials = "" + +type AccessEntry struct { + Type AccessType + Publisher string + Salt []byte + Act string + KdfParams *KdfParams +} + +type DecryptFunc func(*ManifestEntry) error + +func (a *AccessEntry) MarshalJSON() (out []byte, err error) { + + return json.Marshal(struct { + Type AccessType `json:"type,omitempty"` + Publisher string `json:"publisher,omitempty"` + Salt string `json:"salt,omitempty"` + Act string `json:"act,omitempty"` + KdfParams *KdfParams `json:"kdf_params,omitempty"` + }{ + Type: a.Type, + Publisher: a.Publisher, + Salt: hex.EncodeToString(a.Salt), + Act: a.Act, + KdfParams: a.KdfParams, + }) + +} + +func (a *AccessEntry) UnmarshalJSON(value []byte) error { + v := struct { + Type AccessType `json:"type,omitempty"` + Publisher string `json:"publisher,omitempty"` + Salt string `json:"salt,omitempty"` + Act string `json:"act,omitempty"` + KdfParams *KdfParams `json:"kdf_params,omitempty"` + }{} + + err := json.Unmarshal(value, &v) + if err != nil { + return err + } + a.Act = v.Act + a.KdfParams = v.KdfParams + a.Publisher = v.Publisher + a.Salt, err = hex.DecodeString(v.Salt) + if err != nil { + return err + } + if len(a.Salt) != 32 { + return errors.New("salt should be 32 bytes long") + } + a.Type = v.Type + return nil +} + +type KdfParams struct { + N int `json:"n"` + P int `json:"p"` + R int `json:"r"` +} + +type AccessType string + +const AccessTypePass = AccessType("pass") +const AccessTypePK = AccessType("pk") +const AccessTypeACT = AccessType("act") + +// NewAccessEntryPassword creates a manifest AccessEntry in order to create an ACT protected by a password +func NewAccessEntryPassword(salt []byte, kdfParams *KdfParams) (*AccessEntry, error) { + if len(salt) != 32 { + return nil, fmt.Errorf("salt should be 32 bytes long") + } + return &AccessEntry{ + Type: AccessTypePass, + Salt: salt, + KdfParams: kdfParams, + }, nil +} + +// NewAccessEntryPK creates a manifest AccessEntry in order to create an ACT protected by a pair of Elliptic Curve keys +func NewAccessEntryPK(publisher string, salt []byte) (*AccessEntry, error) { + if len(publisher) != 66 { + return nil, fmt.Errorf("publisher should be 66 characters long, got %d", len(publisher)) + } + if len(salt) != 32 { + return nil, fmt.Errorf("salt should be 32 bytes long") + } + return &AccessEntry{ + Type: AccessTypePK, + Publisher: publisher, + Salt: salt, + }, nil +} + +// NewAccessEntryACT creates a manifest AccessEntry in order to create an ACT protected by a combination of EC keys and passwords +func NewAccessEntryACT(publisher string, salt []byte, act string) (*AccessEntry, error) { + if len(salt) != 32 { + return nil, fmt.Errorf("salt should be 32 bytes long") + } + if len(publisher) != 66 { + return nil, fmt.Errorf("publisher should be 66 characters long") + } + + return &AccessEntry{ + Type: AccessTypeACT, + Publisher: publisher, + Salt: salt, + Act: act, + KdfParams: DefaultKdfParams, + }, nil +} + +// NOOPDecrypt is a generic decrypt function that is passed into the API in places where real ACT decryption capabilities are +// either unwanted, or alternatively, cannot be implemented in the immediate scope +func NOOPDecrypt(*ManifestEntry) error { + return nil +} + +var DefaultKdfParams = NewKdfParams(262144, 1, 8) + +// NewKdfParams returns a KdfParams struct with the given scrypt params +func NewKdfParams(n, p, r int) *KdfParams { + + return &KdfParams{ + N: n, + P: p, + R: r, + } +} + +// NewSessionKeyPassword creates a session key based on a shared secret (password) and the given salt +// and kdf parameters in the access entry +func NewSessionKeyPassword(password string, accessEntry *AccessEntry) ([]byte, error) { + if accessEntry.Type != AccessTypePass && accessEntry.Type != AccessTypeACT { + return nil, errors.New("incorrect access entry type") + + } + return sessionKeyPassword(password, accessEntry.Salt, accessEntry.KdfParams) +} + +func sessionKeyPassword(password string, salt []byte, kdfParams *KdfParams) ([]byte, error) { + return scrypt.Key( + []byte(password), + salt, + kdfParams.N, + kdfParams.R, + kdfParams.P, + 32, + ) +} + +// NewSessionKeyPK creates a new ACT Session Key using an ECDH shared secret for the given key pair and the given salt value +func NewSessionKeyPK(private *ecdsa.PrivateKey, public *ecdsa.PublicKey, salt []byte) ([]byte, error) { + granteePubEcies := ecies.ImportECDSAPublic(public) + privateKey := ecies.ImportECDSA(private) + + bytes, err := privateKey.GenerateShared(granteePubEcies, 16, 16) + if err != nil { + return nil, err + } + bytes = append(salt, bytes...) + sessionKey := crypto.Keccak256(bytes) + return sessionKey, nil +} + +func (a *API) doDecrypt(ctx context.Context, credentials string, pk *ecdsa.PrivateKey) DecryptFunc { + return func(m *ManifestEntry) error { + if m.Access == nil { + return nil + } + + allowed := false + requestDomain := sctx.GetHost(ctx) + for _, v := range AllowedDecryptDomains { + if strings.Contains(requestDomain, v) { + allowed = true + } + } + + if !allowed { + return ErrDecryptDomainForbidden + } + + switch m.Access.Type { + case "pass": + if credentials != "" { + key, err := NewSessionKeyPassword(credentials, m.Access) + if err != nil { + return err + } + + ref, err := hex.DecodeString(m.Hash) + if err != nil { + return err + } + + enc := NewRefEncryption(len(ref) - 8) + decodedRef, err := enc.Decrypt(ref, key) + if err != nil { + return ErrDecrypt + } + + m.Hash = hex.EncodeToString(decodedRef) + m.Access = nil + return nil + } + return ErrDecrypt + case "pk": + publisherBytes, err := hex.DecodeString(m.Access.Publisher) + if err != nil { + return ErrDecrypt + } + publisher, err := crypto.DecompressPubkey(publisherBytes) + if err != nil { + return ErrDecrypt + } + key, err := NewSessionKeyPK(pk, publisher, m.Access.Salt) + if err != nil { + return ErrDecrypt + } + ref, err := hex.DecodeString(m.Hash) + if err != nil { + return err + } + + enc := NewRefEncryption(len(ref) - 8) + decodedRef, err := enc.Decrypt(ref, key) + if err != nil { + return ErrDecrypt + } + + m.Hash = hex.EncodeToString(decodedRef) + m.Access = nil + return nil + case "act": + var ( + sessionKey []byte + err error + ) + + publisherBytes, err := hex.DecodeString(m.Access.Publisher) + if err != nil { + return ErrDecrypt + } + publisher, err := crypto.DecompressPubkey(publisherBytes) + if err != nil { + return ErrDecrypt + } + + sessionKey, err = NewSessionKeyPK(pk, publisher, m.Access.Salt) + if err != nil { + return ErrDecrypt + } + + found, ciphertext, decryptionKey, err := a.getACTDecryptionKey(ctx, storage.Address(common.Hex2Bytes(m.Access.Act)), sessionKey) + if err != nil { + return err + } + if !found { + // try to fall back to password + if credentials != "" { + sessionKey, err = NewSessionKeyPassword(credentials, m.Access) + if err != nil { + return err + } + found, ciphertext, decryptionKey, err = a.getACTDecryptionKey(ctx, storage.Address(common.Hex2Bytes(m.Access.Act)), sessionKey) + if err != nil { + return err + } + if !found { + return ErrDecrypt + } + } else { + return ErrDecrypt + } + } + enc := NewRefEncryption(len(ciphertext) - 8) + decodedRef, err := enc.Decrypt(ciphertext, decryptionKey) + if err != nil { + return ErrDecrypt + } + + ref, err := hex.DecodeString(m.Hash) + if err != nil { + return err + } + + enc = NewRefEncryption(len(ref) - 8) + decodedMainRef, err := enc.Decrypt(ref, decodedRef) + if err != nil { + return ErrDecrypt + } + m.Hash = hex.EncodeToString(decodedMainRef) + m.Access = nil + return nil + } + return ErrUnknownAccessType + } +} + +func (a *API) getACTDecryptionKey(ctx context.Context, actManifestAddress storage.Address, sessionKey []byte) (found bool, ciphertext, decryptionKey []byte, err error) { + hasher := sha3.NewLegacyKeccak256() + hasher.Write(append(sessionKey, 0)) + lookupKey := hasher.Sum(nil) + hasher.Reset() + + hasher.Write(append(sessionKey, 1)) + accessKeyDecryptionKey := hasher.Sum(nil) + hasher.Reset() + + lk := hex.EncodeToString(lookupKey) + list, err := a.GetManifestList(ctx, NOOPDecrypt, actManifestAddress, lk) + if err != nil { + return false, nil, nil, err + } + for _, v := range list.Entries { + if v.Path == lk { + cipherTextBytes, err := hex.DecodeString(v.Hash) + if err != nil { + return false, nil, nil, err + } + return true, cipherTextBytes, accessKeyDecryptionKey, nil + } + } + return false, nil, nil, nil +} + +func GenerateAccessControlManifest(ctx *cli.Context, ref string, accessKey []byte, ae *AccessEntry) (*Manifest, error) { + refBytes, err := hex.DecodeString(ref) + if err != nil { + return nil, err + } + // encrypt ref with accessKey + enc := NewRefEncryption(len(refBytes)) + encrypted, err := enc.Encrypt(refBytes, accessKey) + if err != nil { + return nil, err + } + + m := &Manifest{ + Entries: []ManifestEntry{ + { + Hash: hex.EncodeToString(encrypted), + ContentType: ManifestType, + ModTime: time.Now(), + Access: ae, + }, + }, + } + + return m, nil +} + +// DoPK is a helper function to the CLI API that handles the entire business logic for +// creating a session key and access entry given the cli context, ec keys and salt +func DoPK(ctx *cli.Context, privateKey *ecdsa.PrivateKey, granteePublicKey string, salt []byte) (sessionKey []byte, ae *AccessEntry, err error) { + if granteePublicKey == "" { + return nil, nil, errors.New("need a grantee Public Key") + } + b, err := hex.DecodeString(granteePublicKey) + if err != nil { + log.Error("error decoding grantee public key", "err", err) + return nil, nil, err + } + + granteePub, err := crypto.DecompressPubkey(b) + if err != nil { + log.Error("error decompressing grantee public key", "err", err) + return nil, nil, err + } + + sessionKey, err = NewSessionKeyPK(privateKey, granteePub, salt) + if err != nil { + log.Error("error getting session key", "err", err) + return nil, nil, err + } + + ae, err = NewAccessEntryPK(hex.EncodeToString(crypto.CompressPubkey(&privateKey.PublicKey)), salt) + if err != nil { + log.Error("error generating access entry", "err", err) + return nil, nil, err + } + + return sessionKey, ae, nil +} + +// DoACT is a helper function to the CLI API that handles the entire business logic for +// creating a access key, access entry and ACT manifest (including uploading it) given the cli context, ec keys, password grantees and salt +func DoACT(ctx *cli.Context, privateKey *ecdsa.PrivateKey, salt []byte, grantees []string, encryptPasswords []string) (accessKey []byte, ae *AccessEntry, actManifest *Manifest, err error) { + if len(grantees) == 0 && len(encryptPasswords) == 0 { + return nil, nil, nil, errors.New("did not get any grantee public keys or any encryption passwords") + } + + publisherPub := hex.EncodeToString(crypto.CompressPubkey(&privateKey.PublicKey)) + grantees = append(grantees, publisherPub) + + accessKey = make([]byte, 32) + if _, err := io.ReadFull(rand.Reader, salt); err != nil { + panic("reading from crypto/rand failed: " + err.Error()) + } + if _, err := io.ReadFull(rand.Reader, accessKey); err != nil { + panic("reading from crypto/rand failed: " + err.Error()) + } + + lookupPathEncryptedAccessKeyMap := make(map[string]string) + i := 0 + for _, v := range grantees { + i++ + if v == "" { + return nil, nil, nil, errors.New("need a grantee Public Key") + } + b, err := hex.DecodeString(v) + if err != nil { + log.Error("error decoding grantee public key", "err", err) + return nil, nil, nil, err + } + + granteePub, err := crypto.DecompressPubkey(b) + if err != nil { + log.Error("error decompressing grantee public key", "err", err) + return nil, nil, nil, err + } + sessionKey, err := NewSessionKeyPK(privateKey, granteePub, salt) + if err != nil { + return nil, nil, nil, err + } + + hasher := sha3.NewLegacyKeccak256() + hasher.Write(append(sessionKey, 0)) + lookupKey := hasher.Sum(nil) + + hasher.Reset() + hasher.Write(append(sessionKey, 1)) + + accessKeyEncryptionKey := hasher.Sum(nil) + + enc := NewRefEncryption(len(accessKey)) + encryptedAccessKey, err := enc.Encrypt(accessKey, accessKeyEncryptionKey) + if err != nil { + return nil, nil, nil, err + } + lookupPathEncryptedAccessKeyMap[hex.EncodeToString(lookupKey)] = hex.EncodeToString(encryptedAccessKey) + } + + for _, pass := range encryptPasswords { + sessionKey, err := sessionKeyPassword(pass, salt, DefaultKdfParams) + if err != nil { + return nil, nil, nil, err + } + hasher := sha3.NewLegacyKeccak256() + hasher.Write(append(sessionKey, 0)) + lookupKey := hasher.Sum(nil) + + hasher.Reset() + hasher.Write(append(sessionKey, 1)) + + accessKeyEncryptionKey := hasher.Sum(nil) + + enc := NewRefEncryption(len(accessKey)) + encryptedAccessKey, err := enc.Encrypt(accessKey, accessKeyEncryptionKey) + if err != nil { + return nil, nil, nil, err + } + lookupPathEncryptedAccessKeyMap[hex.EncodeToString(lookupKey)] = hex.EncodeToString(encryptedAccessKey) + } + + m := &Manifest{ + Entries: []ManifestEntry{}, + } + + for k, v := range lookupPathEncryptedAccessKeyMap { + m.Entries = append(m.Entries, ManifestEntry{ + Path: k, + Hash: v, + ContentType: "text/plain", + }) + } + + ae, err = NewAccessEntryACT(hex.EncodeToString(crypto.CompressPubkey(&privateKey.PublicKey)), salt, "") + if err != nil { + return nil, nil, nil, err + } + + return accessKey, ae, m, nil +} + +// DoPassword is a helper function to the CLI API that handles the entire business logic for +// creating a session key and an access entry given the cli context, password and salt. +// By default - DefaultKdfParams are used as the scrypt params +func DoPassword(ctx *cli.Context, password string, salt []byte) (sessionKey []byte, ae *AccessEntry, err error) { + ae, err = NewAccessEntryPassword(salt, DefaultKdfParams) + if err != nil { + return nil, nil, err + } + + sessionKey, err = NewSessionKeyPassword(password, ae) + if err != nil { + return nil, nil, err + } + return sessionKey, ae, nil +} diff --git a/swarm/api/api.go b/swarm/api/api.go index 8c4bca2ec0..86c1119232 100644 --- a/swarm/api/api.go +++ b/swarm/api/api.go @@ -16,13 +16,21 @@ package api +//go:generate mimegen --types=./../../cmd/swarm/mimegen/mime.types --package=api --out=gen_mime.go +//go:generate gofmt -s -w gen_mime.go + import ( + "archive/tar" + "context" + "crypto/ecdsa" + "encoding/hex" + "errors" "fmt" "io" + "math/big" "net/http" - "regexp" + "path" "strings" - "sync" "bytes" "mime" @@ -30,139 +38,582 @@ import ( "time" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/contracts/ens" + "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/spancontext" "github.com/ethereum/go-ethereum/swarm/storage" + "github.com/ethereum/go-ethereum/swarm/storage/feed" + "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup" + + opentracing "github.com/opentracing/opentracing-go" ) -var hashMatcher = regexp.MustCompile("^[0-9A-Fa-f]{64}") +var ( + apiResolveCount = metrics.NewRegisteredCounter("api.resolve.count", nil) + apiResolveFail = metrics.NewRegisteredCounter("api.resolve.fail", nil) + apiPutCount = metrics.NewRegisteredCounter("api.put.count", nil) + apiPutFail = metrics.NewRegisteredCounter("api.put.fail", nil) + apiGetCount = metrics.NewRegisteredCounter("api.get.count", nil) + apiGetNotFound = metrics.NewRegisteredCounter("api.get.notfound", nil) + apiGetHTTP300 = metrics.NewRegisteredCounter("api.get.http.300", nil) + apiManifestUpdateCount = metrics.NewRegisteredCounter("api.manifestupdate.count", nil) + apiManifestUpdateFail = metrics.NewRegisteredCounter("api.manifestupdate.fail", nil) + apiManifestListCount = metrics.NewRegisteredCounter("api.manifestlist.count", nil) + apiManifestListFail = metrics.NewRegisteredCounter("api.manifestlist.fail", nil) + apiDeleteCount = metrics.NewRegisteredCounter("api.delete.count", nil) + apiDeleteFail = metrics.NewRegisteredCounter("api.delete.fail", nil) + apiGetTarCount = metrics.NewRegisteredCounter("api.gettar.count", nil) + apiGetTarFail = metrics.NewRegisteredCounter("api.gettar.fail", nil) + apiUploadTarCount = metrics.NewRegisteredCounter("api.uploadtar.count", nil) + apiUploadTarFail = metrics.NewRegisteredCounter("api.uploadtar.fail", nil) + apiModifyCount = metrics.NewRegisteredCounter("api.modify.count", nil) + apiModifyFail = metrics.NewRegisteredCounter("api.modify.fail", nil) + apiAddFileCount = metrics.NewRegisteredCounter("api.addfile.count", nil) + apiAddFileFail = metrics.NewRegisteredCounter("api.addfile.fail", nil) + apiRmFileCount = metrics.NewRegisteredCounter("api.removefile.count", nil) + apiRmFileFail = metrics.NewRegisteredCounter("api.removefile.fail", nil) + apiAppendFileCount = metrics.NewRegisteredCounter("api.appendfile.count", nil) + apiAppendFileFail = metrics.NewRegisteredCounter("api.appendfile.fail", nil) + apiGetInvalid = metrics.NewRegisteredCounter("api.get.invalid", nil) +) +// Resolver interface resolve a domain name to a hash using ENS type Resolver interface { Resolve(string) (common.Hash, error) } -/* -Api implements webserver/file system related content storage and retrieval -on top of the dpa -it is the public interface of the dpa which is included in the ethereum stack -*/ -type Api struct { - dpa *storage.DPA - dns Resolver +// ResolveValidator is used to validate the contained Resolver +type ResolveValidator interface { + Resolver + Owner(node [32]byte) (common.Address, error) + HeaderByNumber(context.Context, *big.Int) (*types.Header, error) } -//the api constructor initialises -func NewApi(dpa *storage.DPA, dns Resolver) (self *Api) { - self = &Api{ - dpa: dpa, - dns: dns, +// NoResolverError is returned by MultiResolver.Resolve if no resolver +// can be found for the address. +type NoResolverError struct { + TLD string +} + +// NewNoResolverError creates a NoResolverError for the given top level domain +func NewNoResolverError(tld string) *NoResolverError { + return &NoResolverError{TLD: tld} +} + +// Error NoResolverError implements error +func (e *NoResolverError) Error() string { + if e.TLD == "" { + return "no ENS resolver" + } + return fmt.Sprintf("no ENS endpoint configured to resolve .%s TLD names", e.TLD) +} + +// MultiResolver is used to resolve URL addresses based on their TLDs. +// Each TLD can have multiple resolvers, and the resolution from the +// first one in the sequence will be returned. +type MultiResolver struct { + resolvers map[string][]ResolveValidator + nameHash func(string) common.Hash +} + +// MultiResolverOption sets options for MultiResolver and is used as +// arguments for its constructor. +type MultiResolverOption func(*MultiResolver) + +// MultiResolverOptionWithResolver adds a Resolver to a list of resolvers +// for a specific TLD. If TLD is an empty string, the resolver will be added +// to the list of default resolver, the ones that will be used for resolution +// of addresses which do not have their TLD resolver specified. +func MultiResolverOptionWithResolver(r ResolveValidator, tld string) MultiResolverOption { + return func(m *MultiResolver) { + m.resolvers[tld] = append(m.resolvers[tld], r) + } +} + +// NewMultiResolver creates a new instance of MultiResolver. +func NewMultiResolver(opts ...MultiResolverOption) (m *MultiResolver) { + m = &MultiResolver{ + resolvers: make(map[string][]ResolveValidator), + nameHash: ens.EnsNode, + } + for _, o := range opts { + o(m) + } + return m +} + +// Resolve resolves address by choosing a Resolver by TLD. +// If there are more default Resolvers, or for a specific TLD, +// the Hash from the first one which does not return error +// will be returned. +func (m *MultiResolver) Resolve(addr string) (h common.Hash, err error) { + rs, err := m.getResolveValidator(addr) + if err != nil { + return h, err + } + for _, r := range rs { + h, err = r.Resolve(addr) + if err == nil { + return + } } return } -// to be used only in TEST -func (self *Api) Upload(uploadDir, index string) (hash string, err error) { - fs := NewFileSystem(self) - hash, err = fs.Upload(uploadDir, index) - return hash, 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[""] + tld := path.Ext(name) + if tld != "" { + tld = tld[1:] + rstld, ok := m.resolvers[tld] + if ok { + return rstld, nil + } + } + if len(rs) == 0 { + return rs, NewNoResolverError(tld) + } + return rs, nil } -// DPA reader API -func (self *Api) Retrieve(key storage.Key) storage.LazySectionReader { - return self.dpa.Retrieve(key) +/* +API implements webserver/file system related content storage and retrieval +on top of the FileStore +it is the public interface of the FileStore which is included in the ethereum stack +*/ +type API struct { + feed *feed.Handler + fileStore *storage.FileStore + dns Resolver + Decryptor func(context.Context, string) DecryptFunc } -func (self *Api) Store(data io.Reader, size int64, wg *sync.WaitGroup) (key storage.Key, err error) { - return self.dpa.Store(data, size, wg, nil) +// NewAPI the api constructor initialises a new API instance. +func NewAPI(fileStore *storage.FileStore, dns Resolver, feedHandler *feed.Handler, pk *ecdsa.PrivateKey) (self *API) { + self = &API{ + fileStore: fileStore, + dns: dns, + feed: feedHandler, + Decryptor: func(ctx context.Context, credentials string) DecryptFunc { + return self.doDecrypt(ctx, credentials, pk) + }, + } + return } -type ErrResolve error +// Retrieve FileStore reader API +func (a *API) Retrieve(ctx context.Context, addr storage.Address) (reader storage.LazySectionReader, isEncrypted bool) { + return a.fileStore.Retrieve(ctx, addr) +} -// DNS Resolver -func (self *Api) Resolve(uri *URI) (storage.Key, error) { - log.Trace(fmt.Sprintf("Resolving : %v", uri.Addr)) +// Store wraps the Store API call of the embedded FileStore +func (a *API) Store(ctx context.Context, data io.Reader, size int64, toEncrypt bool) (addr storage.Address, wait func(ctx context.Context) error, err error) { + log.Debug("api.store", "size", size) + return a.fileStore.Store(ctx, data, size, toEncrypt) +} - // if the URI is immutable, check if the address is a hash - isHash := hashMatcher.MatchString(uri.Addr) - if uri.Immutable() || uri.DeprecatedImmutable() { - if !isHash { +// 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) { + // if DNS is not configured, return an error + if a.dns == nil { + if hashMatcher.MatchString(address) { + return common.Hex2Bytes(address), nil + } + apiResolveFail.Inc(1) + return nil, fmt.Errorf("no DNS to resolve name: %q", address) + } + // try and resolve the address + resolved, err := a.dns.Resolve(address) + if err != nil { + if hashMatcher.MatchString(address) { + return common.Hex2Bytes(address), nil + } + return nil, err + } + return resolved[:], nil +} + +// Resolve resolves a URI to an Address using the MultiResolver. +func (a *API) ResolveURI(ctx context.Context, uri *URI, credentials string) (storage.Address, error) { + apiResolveCount.Inc(1) + log.Trace("resolving", "uri", uri.Addr) + + var sp opentracing.Span + ctx, sp = spancontext.StartSpan( + ctx, + "api.resolve") + defer sp.Finish() + + // if the URI is immutable, check if the address looks like a hash + if uri.Immutable() { + key := uri.Address() + if key == nil { return nil, fmt.Errorf("immutable address not a content hash: %q", uri.Addr) } - return common.Hex2Bytes(uri.Addr), nil + return key, nil } - // if DNS is not configured, check if the address is a hash - if self.dns == nil { - if !isHash { - return nil, fmt.Errorf("no DNS to resolve name: %q", uri.Addr) - } - return common.Hex2Bytes(uri.Addr), nil - } - - // try and resolve the address - resolved, err := self.dns.Resolve(uri.Addr) - if err == nil { - return resolved[:], nil - } else if !isHash { - return nil, err - } - return common.Hex2Bytes(uri.Addr), nil -} - -// Put provides singleton manifest creation on top of dpa store -func (self *Api) Put(content, contentType string) (storage.Key, error) { - r := strings.NewReader(content) - wg := &sync.WaitGroup{} - key, err := self.dpa.Store(r, int64(len(content)), wg, nil) + addr, err := a.Resolve(ctx, uri.Addr) if err != nil { return nil, err } + + if uri.Path == "" { + return addr, nil + } + walker, err := a.NewManifestWalker(ctx, addr, a.Decryptor(ctx, credentials), nil) + if err != nil { + return nil, err + } + var entry *ManifestEntry + walker.Walk(func(e *ManifestEntry) error { + // if the entry matches the path, set entry and stop + // the walk + if e.Path == uri.Path { + entry = e + // return an error to cancel the walk + return errors.New("found") + } + // ignore non-manifest files + if e.ContentType != ManifestType { + return nil + } + // if the manifest's path is a prefix of the + // requested path, recurse into it by returning + // nil and continuing the walk + if strings.HasPrefix(uri.Path, e.Path) { + return nil + } + return ErrSkipManifest + }) + if entry == nil { + return nil, errors.New("not found") + } + addr = storage.Address(common.Hex2Bytes(entry.Hash)) + return addr, nil +} + +// Put provides singleton manifest creation on top of FileStore store +func (a *API) Put(ctx context.Context, content string, contentType string, toEncrypt bool) (k storage.Address, wait func(context.Context) error, err error) { + apiPutCount.Inc(1) + r := strings.NewReader(content) + key, waitContent, err := a.fileStore.Store(ctx, r, int64(len(content)), toEncrypt) + if err != nil { + apiPutFail.Inc(1) + return nil, nil, err + } manifest := fmt.Sprintf(`{"entries":[{"hash":"%v","contentType":"%s"}]}`, key, contentType) r = strings.NewReader(manifest) - key, err = self.dpa.Store(r, int64(len(manifest)), wg, nil) + key, waitManifest, err := a.fileStore.Store(ctx, r, int64(len(manifest)), toEncrypt) if err != nil { - return nil, err + apiPutFail.Inc(1) + return nil, nil, err } - wg.Wait() - return key, nil + return key, func(ctx context.Context) error { + err := waitContent(ctx) + if err != nil { + return err + } + return waitManifest(ctx) + }, nil } // Get uses iterative manifest retrieval and prefix matching -// to resolve basePath to content using dpa retrieve -// it returns a section reader, mimeType, status and an error -func (self *Api) Get(key storage.Key, path string) (reader storage.LazySectionReader, mimeType string, status int, err error) { - trie, err := loadManifest(self.dpa, key, nil) +// to resolve basePath to content using FileStore retrieve +// it returns a section reader, mimeType, status, the key of the actual content and an error +func (a *API) Get(ctx context.Context, decrypt DecryptFunc, manifestAddr storage.Address, path string) (reader storage.LazySectionReader, mimeType string, status int, contentAddr storage.Address, err error) { + log.Debug("api.get", "key", manifestAddr, "path", path) + apiGetCount.Inc(1) + trie, err := loadManifest(ctx, a.fileStore, manifestAddr, nil, decrypt) if err != nil { + apiGetNotFound.Inc(1) status = http.StatusNotFound - log.Warn(fmt.Sprintf("loadManifestTrie error: %v", err)) - return + return nil, "", http.StatusNotFound, nil, err } - log.Trace(fmt.Sprintf("getEntry(%s)", path)) - + log.Debug("trie getting entry", "key", manifestAddr, "path", path) entry, _ := trie.getEntry(path) if entry != nil { - key = common.Hex2Bytes(entry.Hash) + log.Debug("trie got entry", "key", manifestAddr, "path", path, "entry.Hash", entry.Hash) + + if entry.ContentType == ManifestType { + log.Debug("entry is manifest", "key", manifestAddr, "new key", entry.Hash) + adr, err := hex.DecodeString(entry.Hash) + if err != nil { + return nil, "", 0, nil, err + } + return a.Get(ctx, decrypt, adr, entry.Path) + } + + // we need to do some extra work if this is a Swarm feed manifest + if entry.ContentType == FeedContentType { + if entry.Feed == nil { + return reader, mimeType, status, nil, fmt.Errorf("Cannot decode Feed in manifest") + } + _, err := a.feed.Lookup(ctx, feed.NewQueryLatest(entry.Feed, lookup.NoClue)) + if err != nil { + apiGetNotFound.Inc(1) + status = http.StatusNotFound + log.Debug(fmt.Sprintf("get feed update content error: %v", err)) + return reader, mimeType, status, nil, err + } + // get the data of the update + _, contentAddr, err := a.feed.GetContent(entry.Feed) + if err != nil { + apiGetNotFound.Inc(1) + status = http.StatusNotFound + log.Warn(fmt.Sprintf("get feed update content error: %v", err)) + return reader, mimeType, status, nil, err + } + + // extract content hash + if len(contentAddr) != storage.AddressLength { + apiGetInvalid.Inc(1) + status = http.StatusUnprocessableEntity + 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(contentAddr) + log.Trace("feed update contains swarm hash", "key", manifestAddr) + + // 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) error: %v", err)) + return reader, mimeType, status, nil, err + } + + // finally, get the manifest entry + // it will always be the entry on path "" + entry, _ = trie.getEntry(path) + if entry == nil { + status = http.StatusNotFound + apiGetNotFound.Inc(1) + 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 + } + } + + // regardless of feed update manifests or normal manifests we will converge at this point + // get the key the manifest entry points to and serve it if it's unambiguous + contentAddr = common.Hex2Bytes(entry.Hash) status = entry.Status if status == http.StatusMultipleChoices { - return - } else { - mimeType = entry.ContentType - log.Trace(fmt.Sprintf("content lookup key: '%v' (%v)", key, mimeType)) - reader = self.dpa.Retrieve(key) + apiGetHTTP300.Inc(1) + return nil, entry.ContentType, status, contentAddr, err } + mimeType = entry.ContentType + log.Debug("content lookup key", "key", contentAddr, "mimetype", mimeType) + reader, _ = a.fileStore.Retrieve(ctx, contentAddr) } else { + // no entry found status = http.StatusNotFound - err = fmt.Errorf("manifest entry for '%s' not found", path) - log.Warn(fmt.Sprintf("%v", err)) + apiGetNotFound.Inc(1) + err = fmt.Errorf("Not found: could not find resource '%s'", path) + log.Trace("manifest entry not found", "key", contentAddr, "path", path) } return } -func (self *Api) Modify(key storage.Key, path, contentHash, contentType string) (storage.Key, error) { - quitC := make(chan bool) - trie, err := loadManifest(self.dpa, key, quitC) +func (a *API) Delete(ctx context.Context, addr string, path string) (storage.Address, error) { + apiDeleteCount.Inc(1) + uri, err := Parse("bzz:/" + addr) if err != nil { + apiDeleteFail.Inc(1) + return nil, err + } + key, err := a.ResolveURI(ctx, uri, EmptyCredentials) + + if err != nil { + return nil, err + } + newKey, err := a.UpdateManifest(ctx, key, func(mw *ManifestWriter) error { + log.Debug(fmt.Sprintf("removing %s from manifest %s", path, key.Log())) + return mw.RemoveEntry(path) + }) + if err != nil { + apiDeleteFail.Inc(1) + return nil, err + } + + return newKey, nil +} + +// GetDirectoryTar fetches a requested directory as a tarstream +// it returns an io.Reader and an error. Do not forget to Close() the returned ReadCloser +func (a *API) GetDirectoryTar(ctx context.Context, decrypt DecryptFunc, uri *URI) (io.ReadCloser, error) { + apiGetTarCount.Inc(1) + addr, err := a.Resolve(ctx, uri.Addr) + if err != nil { + return nil, err + } + walker, err := a.NewManifestWalker(ctx, addr, decrypt, nil) + if err != nil { + apiGetTarFail.Inc(1) + return nil, err + } + + piper, pipew := io.Pipe() + + tw := tar.NewWriter(pipew) + + go func() { + err := walker.Walk(func(entry *ManifestEntry) error { + // ignore manifests (walk will recurse into them) + if entry.ContentType == ManifestType { + return nil + } + + // retrieve the entry's key and size + reader, _ := a.Retrieve(ctx, storage.Address(common.Hex2Bytes(entry.Hash))) + size, err := reader.Size(ctx, nil) + if err != nil { + return err + } + + // write a tar header for the entry + hdr := &tar.Header{ + Name: entry.Path, + Mode: entry.Mode, + Size: size, + ModTime: entry.ModTime, + Xattrs: map[string]string{ + "user.swarm.content-type": entry.ContentType, + }, + } + + if err := tw.WriteHeader(hdr); err != nil { + return err + } + + // copy the file into the tar stream + n, err := io.Copy(tw, io.LimitReader(reader, hdr.Size)) + if err != nil { + return err + } else if n != size { + return fmt.Errorf("error writing %s: expected %d bytes but sent %d", entry.Path, size, n) + } + + return nil + }) + // close tar writer before closing pipew + // to flush remaining data to pipew + // regardless of error value + tw.Close() + if err != nil { + apiGetTarFail.Inc(1) + pipew.CloseWithError(err) + } else { + pipew.Close() + } + }() + + return piper, nil +} + +// GetManifestList lists the manifest entries for the specified address and prefix +// and returns it as a ManifestList +func (a *API) GetManifestList(ctx context.Context, decryptor DecryptFunc, addr storage.Address, prefix string) (list ManifestList, err error) { + apiManifestListCount.Inc(1) + walker, err := a.NewManifestWalker(ctx, addr, decryptor, nil) + if err != nil { + apiManifestListFail.Inc(1) + return ManifestList{}, err + } + + err = walker.Walk(func(entry *ManifestEntry) error { + // handle non-manifest files + if entry.ContentType != ManifestType { + // ignore the file if it doesn't have the specified prefix + if !strings.HasPrefix(entry.Path, prefix) { + return nil + } + + // if the path after the prefix contains a slash, add a + // common prefix to the list, otherwise add the entry + suffix := strings.TrimPrefix(entry.Path, prefix) + if index := strings.Index(suffix, "/"); index > -1 { + list.CommonPrefixes = append(list.CommonPrefixes, prefix+suffix[:index+1]) + return nil + } + if entry.Path == "" { + entry.Path = "/" + } + list.Entries = append(list.Entries, entry) + return nil + } + + // if the manifest's path is a prefix of the specified prefix + // then just recurse into the manifest by returning nil and + // continuing the walk + if strings.HasPrefix(prefix, entry.Path) { + return nil + } + + // if the manifest's path has the specified prefix, then if the + // path after the prefix contains a slash, add a common prefix + // to the list and skip the manifest, otherwise recurse into + // the manifest by returning nil and continuing the walk + if strings.HasPrefix(entry.Path, prefix) { + suffix := strings.TrimPrefix(entry.Path, prefix) + if index := strings.Index(suffix, "/"); index > -1 { + list.CommonPrefixes = append(list.CommonPrefixes, prefix+suffix[:index+1]) + return ErrSkipManifest + } + return nil + } + + // the manifest neither has the prefix or needs recursing in to + // so just skip it + return ErrSkipManifest + }) + + if err != nil { + apiManifestListFail.Inc(1) + return ManifestList{}, err + } + + return list, nil +} + +func (a *API) UpdateManifest(ctx context.Context, addr storage.Address, update func(mw *ManifestWriter) error) (storage.Address, error) { + apiManifestUpdateCount.Inc(1) + mw, err := a.NewManifestWriter(ctx, addr, nil) + if err != nil { + apiManifestUpdateFail.Inc(1) + return nil, err + } + + if err := update(mw); err != nil { + apiManifestUpdateFail.Inc(1) + return nil, err + } + + addr, err = mw.Store() + if err != nil { + apiManifestUpdateFail.Inc(1) + return nil, err + } + log.Debug(fmt.Sprintf("generated manifest %s", addr)) + return addr, nil +} + +// Modify loads manifest and checks the content hash before recalculating and storing the manifest. +func (a *API) Modify(ctx context.Context, addr storage.Address, path, contentHash, contentType string) (storage.Address, error) { + apiModifyCount.Inc(1) + quitC := make(chan bool) + trie, err := loadManifest(ctx, a.fileStore, addr, quitC, NOOPDecrypt) + if err != nil { + apiModifyFail.Inc(1) return nil, err } if contentHash != "" { @@ -177,19 +628,24 @@ func (self *Api) Modify(key storage.Key, path, contentHash, contentType string) } if err := trie.recalcAndStore(); err != nil { + apiModifyFail.Inc(1) return nil, err } - return trie.hash, nil + return trie.ref, nil } -func (self *Api) AddFile(mhash, path, fname string, content []byte, nameresolver bool) (storage.Key, string, error) { +// AddFile creates a new manifest entry, adds it to swarm, then adds a file to swarm. +func (a *API) AddFile(ctx context.Context, mhash, path, fname string, content []byte, nameresolver bool) (storage.Address, string, error) { + apiAddFileCount.Inc(1) uri, err := Parse("bzz:/" + mhash) if err != nil { + apiAddFileFail.Inc(1) return nil, "", err } - mkey, err := self.Resolve(uri) + mkey, err := a.ResolveURI(ctx, uri, EmptyCredentials) if err != nil { + apiAddFileFail.Inc(1) return nil, "", err } @@ -206,34 +662,107 @@ func (self *Api) AddFile(mhash, path, fname string, content []byte, nameresolver ModTime: time.Now(), } - mw, err := self.NewManifestWriter(mkey, nil) + mw, err := a.NewManifestWriter(ctx, mkey, nil) if err != nil { + apiAddFileFail.Inc(1) return nil, "", err } - fkey, err := mw.AddEntry(bytes.NewReader(content), entry) + fkey, err := mw.AddEntry(ctx, bytes.NewReader(content), entry) if err != nil { + apiAddFileFail.Inc(1) return nil, "", err } newMkey, err := mw.Store() if err != nil { + apiAddFileFail.Inc(1) return nil, "", err } return fkey, newMkey.String(), nil - } -func (self *Api) RemoveFile(mhash, path, fname string, nameresolver bool) (string, error) { +func (a *API) UploadTar(ctx context.Context, bodyReader io.ReadCloser, manifestPath, defaultPath string, mw *ManifestWriter) (storage.Address, error) { + apiUploadTarCount.Inc(1) + var contentKey storage.Address + tr := tar.NewReader(bodyReader) + defer bodyReader.Close() + var defaultPathFound bool + for { + hdr, err := tr.Next() + if err == io.EOF { + break + } else if err != nil { + apiUploadTarFail.Inc(1) + return nil, fmt.Errorf("error reading tar stream: %s", err) + } + + // only store regular files + if !hdr.FileInfo().Mode().IsRegular() { + continue + } + + // add the entry under the path from the request + manifestPath := path.Join(manifestPath, hdr.Name) + contentType := hdr.Xattrs["user.swarm.content-type"] + if contentType == "" { + contentType = mime.TypeByExtension(filepath.Ext(hdr.Name)) + } + //DetectContentType("") + entry := &ManifestEntry{ + Path: manifestPath, + ContentType: contentType, + Mode: hdr.Mode, + Size: hdr.Size, + ModTime: hdr.ModTime, + } + contentKey, err = mw.AddEntry(ctx, tr, entry) + if err != nil { + apiUploadTarFail.Inc(1) + return nil, fmt.Errorf("error adding manifest entry from tar stream: %s", err) + } + if hdr.Name == defaultPath { + contentType := hdr.Xattrs["user.swarm.content-type"] + if contentType == "" { + contentType = mime.TypeByExtension(filepath.Ext(hdr.Name)) + } + + entry := &ManifestEntry{ + Hash: contentKey.Hex(), + Path: "", // default entry + ContentType: contentType, + Mode: hdr.Mode, + Size: hdr.Size, + ModTime: hdr.ModTime, + } + contentKey, err = mw.AddEntry(ctx, nil, entry) + if err != nil { + apiUploadTarFail.Inc(1) + return nil, fmt.Errorf("error adding default manifest entry from tar stream: %s", err) + } + defaultPathFound = true + } + } + if defaultPath != "" && !defaultPathFound { + return contentKey, fmt.Errorf("default path %q not found", defaultPath) + } + return contentKey, nil +} + +// RemoveFile removes a file entry in a manifest. +func (a *API) RemoveFile(ctx context.Context, mhash string, path string, fname string, nameresolver bool) (string, error) { + apiRmFileCount.Inc(1) uri, err := Parse("bzz:/" + mhash) if err != nil { + apiRmFileFail.Inc(1) return "", err } - mkey, err := self.Resolve(uri) + mkey, err := a.ResolveURI(ctx, uri, EmptyCredentials) if err != nil { + apiRmFileFail.Inc(1) return "", err } @@ -242,18 +771,21 @@ func (self *Api) RemoveFile(mhash, path, fname string, nameresolver bool) (strin path = path[1:] } - mw, err := self.NewManifestWriter(mkey, nil) + mw, err := a.NewManifestWriter(ctx, mkey, nil) if err != nil { + apiRmFileFail.Inc(1) return "", err } err = mw.RemoveEntry(filepath.Join(path, fname)) if err != nil { + apiRmFileFail.Inc(1) return "", err } newMkey, err := mw.Store() if err != nil { + apiRmFileFail.Inc(1) return "", err } @@ -261,7 +793,9 @@ func (self *Api) RemoveFile(mhash, path, fname string, nameresolver bool) (strin return newMkey.String(), nil } -func (self *Api) AppendFile(mhash, path, fname string, existingSize int64, content []byte, oldKey storage.Key, offset int64, addSize int64, nameresolver bool) (storage.Key, string, error) { +// AppendFile removes old manifest, appends file entry to new manifest and adds it to Swarm. +func (a *API) AppendFile(ctx context.Context, mhash, path, fname string, existingSize int64, content []byte, oldAddr storage.Address, offset int64, addSize int64, nameresolver bool) (storage.Address, string, error) { + apiAppendFileCount.Inc(1) buffSize := offset + addSize if buffSize < existingSize { @@ -270,7 +804,7 @@ func (self *Api) AppendFile(mhash, path, fname string, existingSize int64, conte buf := make([]byte, buffSize) - oldReader := self.Retrieve(oldKey) + oldReader, _ := a.Retrieve(ctx, oldAddr) io.ReadAtLeast(oldReader, buf, int(offset)) newReader := bytes.NewReader(content) @@ -284,16 +818,18 @@ func (self *Api) AppendFile(mhash, path, fname string, existingSize int64, conte totalSize := int64(len(buf)) // TODO(jmozah): to append using pyramid chunker when it is ready - //oldReader := self.Retrieve(oldKey) + //oldReader := a.Retrieve(oldKey) //newReader := bytes.NewReader(content) //combinedReader := io.MultiReader(oldReader, newReader) uri, err := Parse("bzz:/" + mhash) if err != nil { + apiAppendFileFail.Inc(1) return nil, "", err } - mkey, err := self.Resolve(uri) + mkey, err := a.ResolveURI(ctx, uri, EmptyCredentials) if err != nil { + apiAppendFileFail.Inc(1) return nil, "", err } @@ -302,13 +838,15 @@ func (self *Api) AppendFile(mhash, path, fname string, existingSize int64, conte path = path[1:] } - mw, err := self.NewManifestWriter(mkey, nil) + mw, err := a.NewManifestWriter(ctx, mkey, nil) if err != nil { + apiAppendFileFail.Inc(1) return nil, "", err } err = mw.RemoveEntry(filepath.Join(path, fname)) if err != nil { + apiAppendFileFail.Inc(1) return nil, "", err } @@ -320,35 +858,38 @@ func (self *Api) AppendFile(mhash, path, fname string, existingSize int64, conte ModTime: time.Now(), } - fkey, err := mw.AddEntry(io.Reader(combinedReader), entry) + fkey, err := mw.AddEntry(ctx, io.Reader(combinedReader), entry) if err != nil { + apiAppendFileFail.Inc(1) return nil, "", err } newMkey, err := mw.Store() if err != nil { + apiAppendFileFail.Inc(1) return nil, "", err } return fkey, newMkey.String(), nil - } -func (self *Api) BuildDirectoryTree(mhash string, nameresolver bool) (key storage.Key, manifestEntryMap map[string]*manifestTrieEntry, err error) { +// BuildDirectoryTree used by swarmfs_unix +func (a *API) BuildDirectoryTree(ctx context.Context, mhash string, nameresolver bool) (addr storage.Address, manifestEntryMap map[string]*manifestTrieEntry, err error) { + uri, err := Parse("bzz:/" + mhash) if err != nil { return nil, nil, err } - key, err = self.Resolve(uri) + addr, err = a.Resolve(ctx, uri.Addr) if err != nil { return nil, nil, err } quitC := make(chan bool) - rootTrie, err := loadManifest(self.dpa, key, quitC) + rootTrie, err := loadManifest(ctx, a.fileStore, addr, quitC, NOOPDecrypt) if err != nil { - return nil, nil, fmt.Errorf("can't load manifest %v: %v", key.String(), err) + return nil, nil, fmt.Errorf("can't load manifest %v: %v", addr.String(), err) } manifestEntryMap = map[string]*manifestTrieEntry{} @@ -357,7 +898,120 @@ func (self *Api) BuildDirectoryTree(mhash string, nameresolver bool) (key storag }) if err != nil { - return nil, nil, fmt.Errorf("list with prefix failed %v: %v", key.String(), err) + return nil, nil, fmt.Errorf("list with prefix failed %v: %v", addr.String(), err) } - return key, manifestEntryMap, nil + return addr, manifestEntryMap, nil +} + +// FeedsLookup finds Swarm feeds updates at specific points in time, or the latest update +func (a *API) FeedsLookup(ctx context.Context, query *feed.Query) ([]byte, error) { + _, err := a.feed.Lookup(ctx, query) + if err != nil { + return nil, err + } + var data []byte + _, data, err = a.feed.GetContent(&query.Feed) + if err != nil { + return nil, err + } + return data, nil +} + +// FeedsNewRequest creates a Request object to update a specific feed +func (a *API) FeedsNewRequest(ctx context.Context, feed *feed.Feed) (*feed.Request, error) { + return a.feed.NewRequest(ctx, feed) +} + +// FeedsUpdate publishes a new update on the given feed +func (a *API) FeedsUpdate(ctx context.Context, request *feed.Request) (storage.Address, error) { + return a.feed.Update(ctx, request) +} + +// ErrCannotLoadFeedManifest is returned when looking up a feeds manifest fails +var ErrCannotLoadFeedManifest = errors.New("Cannot load feed manifest") + +// ErrNotAFeedManifest is returned when the address provided returned something other than a valid manifest +var ErrNotAFeedManifest = errors.New("Not a feed manifest") + +// ResolveFeedManifest retrieves the Swarm feed manifest for the given address, and returns the referenced Feed. +func (a *API) ResolveFeedManifest(ctx context.Context, addr storage.Address) (*feed.Feed, error) { + trie, err := loadManifest(ctx, a.fileStore, addr, nil, NOOPDecrypt) + if err != nil { + return nil, ErrCannotLoadFeedManifest + } + + entry, _ := trie.getEntry("") + if entry.ContentType != FeedContentType { + return nil, ErrNotAFeedManifest + } + + return entry.Feed, nil +} + +// ErrCannotResolveFeedURI is returned when the ENS resolver is not able to translate a name to a Swarm feed +var ErrCannotResolveFeedURI = errors.New("Cannot resolve Feed URI") + +// ErrCannotResolveFeed is returned when values provided are not enough or invalid to recreate a +// feed out of them. +var ErrCannotResolveFeed = errors.New("Cannot resolve Feed") + +// ResolveFeed attempts to extract feed information out of the manifest, if provided +// If not, it attempts to extract the feed out of a set of key-value pairs +func (a *API) ResolveFeed(ctx context.Context, uri *URI, values feed.Values) (*feed.Feed, error) { + var fd *feed.Feed + var err error + if uri.Addr != "" { + // resolve the content key. + manifestAddr := uri.Address() + if manifestAddr == nil { + manifestAddr, err = a.Resolve(ctx, uri.Addr) + if err != nil { + return nil, ErrCannotResolveFeedURI + } + } + + // get the Swarm feed from the manifest + fd, err = a.ResolveFeedManifest(ctx, manifestAddr) + if err != nil { + return nil, err + } + log.Debug("handle.get.feed: resolved", "manifestkey", manifestAddr, "feed", fd.Hex()) + } else { + var f feed.Feed + if err := f.FromValues(values); err != nil { + return nil, ErrCannotResolveFeed + + } + fd = &f + } + return fd, nil +} + +// MimeOctetStream default value of http Content-Type header +const MimeOctetStream = "application/octet-stream" + +// DetectContentType by file file extension, or fallback to content sniff +func DetectContentType(fileName string, f io.ReadSeeker) (string, error) { + ctype := mime.TypeByExtension(filepath.Ext(fileName)) + if ctype != "" { + return ctype, nil + } + + // save/rollback to get content probe from begin of file + currentPosition, err := f.Seek(0, io.SeekCurrent) + if err != nil { + return MimeOctetStream, fmt.Errorf("seeker can't seek, %s", err) + } + + // read a chunk to decide between utf-8 text and binary + var buf [512]byte + n, _ := f.Read(buf[:]) + ctype = http.DetectContentType(buf[:n]) + + _, err = f.Seek(currentPosition, io.SeekStart) // rewind to output whole file + if err != nil { + return MimeOctetStream, fmt.Errorf("seeker can't seek, %s", err) + } + + return ctype, nil } diff --git a/swarm/api/api_test.go b/swarm/api/api_test.go index e673f76c42..eb896f32aa 100644 --- a/swarm/api/api_test.go +++ b/swarm/api/api_test.go @@ -17,33 +17,43 @@ package api import ( + "bytes" + "context" "errors" + "flag" "fmt" "io" "io/ioutil" + "math/big" "os" "testing" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/swarm/sctx" "github.com/ethereum/go-ethereum/swarm/storage" ) -func testApi(t *testing.T, f func(*Api)) { +func init() { + loglevel := flag.Int("loglevel", 2, "loglevel") + flag.Parse() + log.Root().SetHandler(log.CallerFileHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(os.Stderr, log.TerminalFormat(true))))) +} + +func testAPI(t *testing.T, f func(*API, bool)) { datadir, err := ioutil.TempDir("", "bzz-test") if err != nil { t.Fatalf("unable to create temp dir: %v", err) } - os.RemoveAll(datadir) defer os.RemoveAll(datadir) - dpa, err := storage.NewLocalDPA(datadir) + fileStore, err := storage.NewLocalFileStore(datadir, make([]byte, 32)) if err != nil { return } - api := NewApi(dpa, nil) - dpa.Start() - f(api) - dpa.Stop() + api := NewAPI(fileStore, nil, nil, nil) + f(api, false) + f(api, true) } type testResponse struct { @@ -82,15 +92,14 @@ func expResponse(content string, mimeType string, status int) *Response { return &Response{mimeType, status, int64(len(content)), content} } -// func testGet(t *testing.T, api *Api, bzzhash string) *testResponse { -func testGet(t *testing.T, api *Api, bzzhash, path string) *testResponse { - key := storage.Key(common.Hex2Bytes(bzzhash)) - reader, mimeType, status, err := api.Get(key, path) +func testGet(t *testing.T, api *API, bzzhash, path string) *testResponse { + addr := storage.Address(common.Hex2Bytes(bzzhash)) + reader, mimeType, status, _, err := api.Get(context.TODO(), NOOPDecrypt, addr, path) if err != nil { t.Fatalf("unexpected error: %v", err) } quitC := make(chan bool) - size, err := reader.Size(quitC) + size, err := reader.Size(context.TODO(), quitC) if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -106,27 +115,31 @@ func testGet(t *testing.T, api *Api, bzzhash, path string) *testResponse { } func TestApiPut(t *testing.T) { - testApi(t, func(api *Api) { + testAPI(t, func(api *API, toEncrypt bool) { content := "hello" exp := expResponse(content, "text/plain", 0) - // exp := expResponse([]byte(content), "text/plain", 0) - key, err := api.Put(content, exp.MimeType) + ctx := context.TODO() + addr, wait, err := api.Put(ctx, content, exp.MimeType, toEncrypt) if err != nil { t.Fatalf("unexpected error: %v", err) } - resp := testGet(t, api, key.String(), "") + err = wait(ctx) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + resp := testGet(t, api, addr.Hex(), "") checkResponse(t, resp, exp) }) } // testResolver implements the Resolver interface and either returns the given // hash if it is set, or returns a "name not found" error -type testResolver struct { +type testResolveValidator struct { hash *common.Hash } -func newTestResolver(addr string) *testResolver { - r := &testResolver{} +func newTestResolveValidator(addr string) *testResolveValidator { + r := &testResolveValidator{} if addr != "" { hash := common.HexToHash(addr) r.hash = &hash @@ -134,21 +147,28 @@ func newTestResolver(addr string) *testResolver { return r } -func (t *testResolver) Resolve(addr string) (common.Hash, error) { +func (t *testResolveValidator) Resolve(addr string) (common.Hash, error) { if t.hash == nil { return common.Hash{}, fmt.Errorf("DNS name not found: %q", addr) } return *t.hash, nil } +func (t *testResolveValidator) Owner(node [32]byte) (addr common.Address, err error) { + return +} +func (t *testResolveValidator) HeaderByNumber(context.Context, *big.Int) (header *types.Header, err error) { + return +} + // TestAPIResolve tests resolving URIs which can either contain content hashes // or ENS names func TestAPIResolve(t *testing.T) { ensAddr := "swarm.eth" hashAddr := "1111111111111111111111111111111111111111111111111111111111111111" resolvedAddr := "2222222222222222222222222222222222222222222222222222222222222222" - doesResolve := newTestResolver(resolvedAddr) - doesntResolve := newTestResolver("") + doesResolve := newTestResolveValidator(resolvedAddr) + doesntResolve := newTestResolveValidator("") type test struct { desc string @@ -213,12 +233,12 @@ func TestAPIResolve(t *testing.T) { } for _, x := range tests { t.Run(x.desc, func(t *testing.T) { - api := &Api{dns: x.dns} + api := &API{dns: x.dns} uri := &URI{Addr: x.addr, Scheme: "bzz"} if x.immutable { uri.Scheme = "bzz-immutable" } - res, err := api.Resolve(uri) + res, err := api.ResolveURI(context.TODO(), uri, "") if err == nil { if x.expectErr != nil { t.Fatalf("expected error %q, got result %q", x.expectErr, res) @@ -237,3 +257,246 @@ func TestAPIResolve(t *testing.T) { }) } } + +func TestMultiResolver(t *testing.T) { + doesntResolve := newTestResolveValidator("") + + ethAddr := "swarm.eth" + ethHash := "0x2222222222222222222222222222222222222222222222222222222222222222" + ethResolve := newTestResolveValidator(ethHash) + + testAddr := "swarm.test" + testHash := "0x1111111111111111111111111111111111111111111111111111111111111111" + testResolve := newTestResolveValidator(testHash) + + tests := []struct { + desc string + r Resolver + addr string + result string + err error + }{ + { + desc: "No resolvers, returns error", + r: NewMultiResolver(), + err: NewNoResolverError(""), + }, + { + desc: "One default resolver, returns resolved address", + r: NewMultiResolver(MultiResolverOptionWithResolver(ethResolve, "")), + addr: ethAddr, + result: ethHash, + }, + { + desc: "Two default resolvers, returns resolved address", + r: NewMultiResolver( + MultiResolverOptionWithResolver(ethResolve, ""), + MultiResolverOptionWithResolver(ethResolve, ""), + ), + addr: ethAddr, + result: ethHash, + }, + { + desc: "Two default resolvers, first doesn't resolve, returns resolved address", + r: NewMultiResolver( + MultiResolverOptionWithResolver(doesntResolve, ""), + MultiResolverOptionWithResolver(ethResolve, ""), + ), + addr: ethAddr, + result: ethHash, + }, + { + desc: "Default resolver doesn't resolve, tld resolver resolve, returns resolved address", + r: NewMultiResolver( + MultiResolverOptionWithResolver(doesntResolve, ""), + MultiResolverOptionWithResolver(ethResolve, "eth"), + ), + addr: ethAddr, + result: ethHash, + }, + { + desc: "Three TLD resolvers, third resolves, returns resolved address", + r: NewMultiResolver( + MultiResolverOptionWithResolver(doesntResolve, "eth"), + MultiResolverOptionWithResolver(doesntResolve, "eth"), + MultiResolverOptionWithResolver(ethResolve, "eth"), + ), + addr: ethAddr, + result: ethHash, + }, + { + desc: "One TLD resolver doesn't resolve, returns error", + r: NewMultiResolver( + MultiResolverOptionWithResolver(doesntResolve, ""), + MultiResolverOptionWithResolver(ethResolve, "eth"), + ), + addr: ethAddr, + result: ethHash, + }, + { + desc: "One defautl and one TLD resolver, all doesn't resolve, returns error", + r: NewMultiResolver( + MultiResolverOptionWithResolver(doesntResolve, ""), + MultiResolverOptionWithResolver(doesntResolve, "eth"), + ), + addr: ethAddr, + result: ethHash, + err: errors.New(`DNS name not found: "swarm.eth"`), + }, + { + desc: "Two TLD resolvers, both resolve, returns resolved address", + r: NewMultiResolver( + MultiResolverOptionWithResolver(ethResolve, "eth"), + MultiResolverOptionWithResolver(testResolve, "test"), + ), + addr: testAddr, + result: testHash, + }, + { + desc: "One TLD resolver, no default resolver, returns error for different TLD", + r: NewMultiResolver( + MultiResolverOptionWithResolver(ethResolve, "eth"), + ), + addr: testAddr, + err: NewNoResolverError("test"), + }, + } + for _, x := range tests { + t.Run(x.desc, func(t *testing.T) { + res, err := x.r.Resolve(x.addr) + if err == nil { + if x.err != nil { + t.Fatalf("expected error %q, got result %q", x.err, res.Hex()) + } + if res.Hex() != x.result { + t.Fatalf("expected result %q, got %q", x.result, res.Hex()) + } + } else { + if x.err == nil { + t.Fatalf("expected no error, got %q", err) + } + if err.Error() != x.err.Error() { + t.Fatalf("expected error %q, got %q", x.err, err) + } + } + }) + } +} + +func TestDecryptOriginForbidden(t *testing.T) { + ctx := context.TODO() + ctx = sctx.SetHost(ctx, "swarm-gateways.net") + + me := &ManifestEntry{ + Access: &AccessEntry{Type: AccessTypePass}, + } + + api := NewAPI(nil, nil, nil, nil) + + f := api.Decryptor(ctx, "") + err := f(me) + if err != ErrDecryptDomainForbidden { + t.Fatalf("should fail with ErrDecryptDomainForbidden, got %v", err) + } +} + +func TestDecryptOrigin(t *testing.T) { + for _, v := range []struct { + host string + expectError error + }{ + { + host: "localhost", + expectError: ErrDecrypt, + }, + { + host: "127.0.0.1", + expectError: ErrDecrypt, + }, + { + host: "swarm-gateways.net", + expectError: ErrDecryptDomainForbidden, + }, + } { + ctx := context.TODO() + ctx = sctx.SetHost(ctx, v.host) + + me := &ManifestEntry{ + Access: &AccessEntry{Type: AccessTypePass}, + } + + api := NewAPI(nil, nil, nil, nil) + + f := api.Decryptor(ctx, "") + err := f(me) + if err != v.expectError { + t.Fatalf("should fail with %v, got %v", v.expectError, err) + } + } +} + +func TestDetectContentType(t *testing.T) { + for _, tc := range []struct { + file string + content string + expectedContentType string + }{ + { + file: "file-with-correct-css.css", + content: "body {background-color: orange}", + expectedContentType: "text/css; charset=utf-8", + }, + { + file: "empty-file.css", + content: "", + expectedContentType: "text/css; charset=utf-8", + }, + { + file: "empty-file.pdf", + content: "", + expectedContentType: "application/pdf", + }, + { + file: "empty-file.md", + content: "", + expectedContentType: "text/markdown; charset=utf-8", + }, + { + file: "empty-file-with-unknown-content.strangeext", + content: "", + expectedContentType: "text/plain; charset=utf-8", + }, + { + file: "file-with-unknown-extension-and-content.strangeext", + content: "Lorem Ipsum", + expectedContentType: "text/plain; charset=utf-8", + }, + { + file: "file-no-extension", + content: "Lorem Ipsum", + expectedContentType: "text/plain; charset=utf-8", + }, + { + file: "file-no-extension-no-content", + content: "", + expectedContentType: "text/plain; charset=utf-8", + }, + { + file: "css-file-with-html-inside.css", + content: "", + expectedContentType: "text/css; charset=utf-8", + }, + } { + t.Run(tc.file, func(t *testing.T) { + detected, err := DetectContentType(tc.file, bytes.NewReader([]byte(tc.content))) + if err != nil { + t.Fatal(err) + } + + if detected != tc.expectedContentType { + t.Fatalf("File: %s, Expected mime type %s, got %s", tc.file, tc.expectedContentType, detected) + } + + }) + } +} diff --git a/swarm/api/client/client.go b/swarm/api/client/client.go index 8165d52d7e..5e293cca72 100644 --- a/swarm/api/client/client.go +++ b/swarm/api/client/client.go @@ -19,26 +19,34 @@ package client import ( "archive/tar" "bytes" + "context" "encoding/json" "errors" "fmt" "io" "io/ioutil" - "mime" "mime/multipart" "net/http" + "net/http/httptrace" "net/textproto" + "net/url" "os" "path/filepath" + "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" + "github.com/pborman/uuid" ) var ( - DefaultGateway = "http://localhost:8500" - DefaultClient = NewClient(DefaultGateway) + ErrUnauthorized = errors.New("unauthorized") ) func NewClient(gateway string) *Client { @@ -52,12 +60,17 @@ type Client struct { Gateway string } -// UploadRaw uploads raw data to swarm and returns the resulting hash -func (c *Client) UploadRaw(r io.Reader, size int64) (string, error) { +// UploadRaw uploads raw data to swarm and returns the resulting hash. If toEncrypt is true it +// uploads encrypted data +func (c *Client) UploadRaw(r io.Reader, size int64, toEncrypt bool) (string, error) { if size <= 0 { return "", errors.New("data size must be greater than zero") } - req, err := http.NewRequest("POST", c.Gateway+"/bzz-raw:/", r) + addr := "" + if toEncrypt { + addr = "encrypt" + } + req, err := http.NewRequest("POST", c.Gateway+"/bzz-raw:/"+addr, r) if err != nil { return "", err } @@ -77,18 +90,20 @@ func (c *Client) UploadRaw(r io.Reader, size int64) (string, error) { return string(data), nil } -// DownloadRaw downloads raw data from swarm -func (c *Client) DownloadRaw(hash string) (io.ReadCloser, error) { +// DownloadRaw downloads raw data from swarm and it returns a ReadCloser and a bool whether the +// content was encrypted +func (c *Client) DownloadRaw(hash string) (io.ReadCloser, bool, error) { uri := c.Gateway + "/bzz-raw:/" + hash res, err := http.DefaultClient.Get(uri) if err != nil { - return nil, err + return nil, false, err } if res.StatusCode != http.StatusOK { res.Body.Close() - return nil, fmt.Errorf("unexpected HTTP status: %s", res.Status) + return nil, false, fmt.Errorf("unexpected HTTP status: %s", res.Status) } - return res.Body, nil + isEncrypted := (res.Header.Get("X-Decrypted") == "true") + return res.Body, isEncrypted, nil } // File represents a file in a swarm manifest and is used for uploading and @@ -110,10 +125,16 @@ func Open(path string) (*File, error) { f.Close() return nil, err } + + contentType, err := api.DetectContentType(f.Name(), f) + if err != nil { + return nil, err + } + return &File{ ReadCloser: f, ManifestEntry: api.ManifestEntry{ - ContentType: mime.TypeByExtension(filepath.Ext(path)), + ContentType: contentType, Mode: int64(stat.Mode()), Size: stat.Size(), ModTime: stat.ModTime(), @@ -125,11 +146,11 @@ func Open(path string) (*File, error) { // (if the manifest argument is non-empty) or creates a new manifest containing // the file, returning the resulting manifest hash (the file will then be // available at bzz://) -func (c *Client) Upload(file *File, manifest string) (string, error) { +func (c *Client) Upload(file *File, manifest string, toEncrypt bool) (string, error) { if file.Size <= 0 { return "", errors.New("file size must be greater than zero") } - return c.TarUpload(manifest, &FileUploader{file}) + return c.TarUpload(manifest, &FileUploader{file}, "", toEncrypt) } // Download downloads a file with the given path from the swarm manifest with @@ -159,19 +180,27 @@ func (c *Client) Download(hash, path string) (*File, error) { // directory will then be available at bzz://path/to/file), with // the file specified in defaultPath being uploaded to the root of the manifest // (i.e. bzz://) -func (c *Client) UploadDirectory(dir, defaultPath, manifest string) (string, error) { +func (c *Client) UploadDirectory(dir, defaultPath, manifest string, toEncrypt bool) (string, error) { stat, err := os.Stat(dir) if err != nil { return "", err } else if !stat.IsDir() { return "", fmt.Errorf("not a directory: %s", dir) } - return c.TarUpload(manifest, &DirectoryUploader{dir, defaultPath}) + if defaultPath != "" { + if _, err := os.Stat(filepath.Join(dir, defaultPath)); err != nil { + if os.IsNotExist(err) { + return "", fmt.Errorf("the default path %q was not found in the upload directory %q", defaultPath, dir) + } + return "", fmt.Errorf("default path: %v", err) + } + } + return c.TarUpload(manifest, &DirectoryUploader{dir}, defaultPath, toEncrypt) } // DownloadDirectory downloads the files contained in a swarm manifest under // the given path into a local directory (existing files will be overwritten) -func (c *Client) DownloadDirectory(hash, path, destDir string) error { +func (c *Client) DownloadDirectory(hash, path, destDir, credentials string) error { stat, err := os.Stat(destDir) if err != nil { return err @@ -184,13 +213,20 @@ func (c *Client) DownloadDirectory(hash, path, destDir string) error { if err != nil { return err } + if credentials != "" { + req.SetBasicAuth("", credentials) + } req.Header.Set("Accept", "application/x-tar") res, err := http.DefaultClient.Do(req) if err != nil { return err } defer res.Body.Close() - if res.StatusCode != http.StatusOK { + switch res.StatusCode { + case http.StatusOK: + case http.StatusUnauthorized: + return ErrUnauthorized + default: return fmt.Errorf("unexpected HTTP status: %s", res.Status) } tr := tar.NewReader(res.Body) @@ -228,27 +264,115 @@ func (c *Client) DownloadDirectory(hash, path, destDir string) error { } } +// DownloadFile downloads a single file into the destination directory +// if the manifest entry does not specify a file name - it will fallback +// to the hash of the file as a filename +func (c *Client) DownloadFile(hash, path, dest, credentials string) error { + hasDestinationFilename := false + if stat, err := os.Stat(dest); err == nil { + hasDestinationFilename = !stat.IsDir() + } else { + if os.IsNotExist(err) { + // does not exist - should be created + hasDestinationFilename = true + } else { + return fmt.Errorf("could not stat path: %v", err) + } + } + + manifestList, err := c.List(hash, path, credentials) + if err != nil { + return err + } + + switch len(manifestList.Entries) { + case 0: + return fmt.Errorf("could not find path requested at manifest address. make sure the path you've specified is correct") + case 1: + //continue + default: + return fmt.Errorf("got too many matches for this path") + } + + uri := c.Gateway + "/bzz:/" + hash + "/" + path + req, err := http.NewRequest("GET", uri, nil) + if err != nil { + return err + } + if credentials != "" { + req.SetBasicAuth("", credentials) + } + res, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer res.Body.Close() + switch res.StatusCode { + case http.StatusOK: + case http.StatusUnauthorized: + return ErrUnauthorized + default: + return fmt.Errorf("unexpected HTTP status: expected 200 OK, got %d", res.StatusCode) + } + filename := "" + if hasDestinationFilename { + filename = dest + } else { + // try to assert + re := regexp.MustCompile("[^/]+$") //everything after last slash + + if results := re.FindAllString(path, -1); len(results) > 0 { + filename = results[len(results)-1] + } else { + if entry := manifestList.Entries[0]; entry.Path != "" && entry.Path != "/" { + filename = entry.Path + } else { + // assume hash as name if there's nothing from the command line + filename = hash + } + } + filename = filepath.Join(dest, filename) + } + filePath, err := filepath.Abs(filename) + if err != nil { + return err + } + + if err := os.MkdirAll(filepath.Dir(filePath), 0777); err != nil { + return err + } + + dst, err := os.Create(filename) + if err != nil { + return err + } + defer dst.Close() + + _, err = io.Copy(dst, res.Body) + return err +} + // UploadManifest uploads the given manifest to swarm -func (c *Client) UploadManifest(m *api.Manifest) (string, error) { +func (c *Client) UploadManifest(m *api.Manifest, toEncrypt bool) (string, error) { data, err := json.Marshal(m) if err != nil { return "", err } - return c.UploadRaw(bytes.NewReader(data), int64(len(data))) + return c.UploadRaw(bytes.NewReader(data), int64(len(data)), toEncrypt) } // DownloadManifest downloads a swarm manifest -func (c *Client) DownloadManifest(hash string) (*api.Manifest, error) { - res, err := c.DownloadRaw(hash) +func (c *Client) DownloadManifest(hash string) (*api.Manifest, bool, error) { + res, isEncrypted, err := c.DownloadRaw(hash) if err != nil { - return nil, err + return nil, isEncrypted, err } defer res.Close() var manifest api.Manifest if err := json.NewDecoder(res).Decode(&manifest); err != nil { - return nil, err + return nil, isEncrypted, err } - return &manifest, nil + return &manifest, isEncrypted, nil } // List list files in a swarm manifest which have the given prefix, grouping @@ -268,13 +392,24 @@ func (c *Client) DownloadManifest(hash string) (*api.Manifest, error) { // - a prefix of "dir1/" would return [dir1/dir2/, dir1/file3.txt] // // where entries ending with "/" are common prefixes. -func (c *Client) List(hash, prefix string) (*api.ManifestList, error) { - res, err := http.DefaultClient.Get(c.Gateway + "/bzz-list:/" + hash + "/" + prefix) +func (c *Client) List(hash, prefix, credentials string) (*api.ManifestList, error) { + req, err := http.NewRequest(http.MethodGet, c.Gateway+"/bzz-list:/"+hash+"/"+prefix, nil) + if err != nil { + return nil, err + } + if credentials != "" { + req.SetBasicAuth("", credentials) + } + res, err := http.DefaultClient.Do(req) if err != nil { return nil, err } defer res.Body.Close() - if res.StatusCode != http.StatusOK { + switch res.StatusCode { + case http.StatusOK: + case http.StatusUnauthorized: + return nil, ErrUnauthorized + default: return nil, fmt.Errorf("unexpected HTTP status: %s", res.Status) } var list api.ManifestList @@ -298,21 +433,11 @@ func (u UploaderFunc) Upload(upload UploadFn) error { // DirectoryUploader uploads all files in a directory, optionally uploading // a file to the default path type DirectoryUploader struct { - Dir string - DefaultPath string + Dir string } // Upload performs the upload of the directory and default path func (d *DirectoryUploader) Upload(upload UploadFn) error { - if d.DefaultPath != "" { - file, err := Open(d.DefaultPath) - if err != nil { - return err - } - if err := upload(file); err != nil { - return err - } - } return filepath.Walk(d.Dir, func(path string, f os.FileInfo, err error) error { if err != nil { return err @@ -350,14 +475,39 @@ 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) (string, error) { +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() - req, err := http.NewRequest("POST", c.Gateway+"/bzz:/"+hash, reqR) + addr := hash + + // If there is a hash already (a manifest), then that manifest will determine if the upload has + // to be encrypted or not. If there is no manifest then the toEncrypt parameter decides if + // there is encryption or not. + if hash == "" && toEncrypt { + // This is the built-in address for the encrypted upload endpoint + addr = "encrypt" + } + req, err := http.NewRequest("POST", c.Gateway+"/bzz:/"+addr, reqR) 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() + q.Set("defaultpath", defaultPath) + req.URL.RawQuery = q.Encode() + } // use 'Expect: 100-continue' so we don't send the request body if // the server refuses the request @@ -392,8 +542,8 @@ func (c *Client) TarUpload(hash string, uploader Uploader) (string, error) { } reqW.CloseWithError(err) }() - - res, err := http.DefaultClient.Do(req) + tn = time.Now() + res, err := transport.RoundTrip(req) if err != nil { return "", err } @@ -463,3 +613,185 @@ func (c *Client) MultipartUpload(hash string, uploader Uploader) (string, error) } return string(data), nil } + +// ErrNoFeedUpdatesFound is returned when Swarm cannot find updates of the given feed +var ErrNoFeedUpdatesFound = errors.New("No updates found for this feed") + +// CreateFeedWithManifest creates a feed manifest, initializing it with the provided +// data +// Returns the resulting feed manifest address that you can use to include in an ENS Resolver (setContent) +// or reference future updates (Client.UpdateFeed) +func (c *Client) CreateFeedWithManifest(request *feed.Request) (string, error) { + responseStream, err := c.updateFeed(request, true) + if err != nil { + return "", err + } + defer responseStream.Close() + + body, err := ioutil.ReadAll(responseStream) + if err != nil { + return "", err + } + + var manifestAddress string + if err = json.Unmarshal(body, &manifestAddress); err != nil { + return "", err + } + return manifestAddress, nil +} + +// UpdateFeed allows you to set a new version of your content +func (c *Client) UpdateFeed(request *feed.Request) error { + _, err := c.updateFeed(request, false) + return err +} + +func (c *Client) updateFeed(request *feed.Request, createManifest bool) (io.ReadCloser, error) { + URL, err := url.Parse(c.Gateway) + if err != nil { + return nil, err + } + URL.Path = "/bzz-feed:/" + values := URL.Query() + body := request.AppendValues(values) + if createManifest { + values.Set("manifest", "1") + } + URL.RawQuery = values.Encode() + + req, err := http.NewRequest("POST", URL.String(), bytes.NewBuffer(body)) + if err != nil { + return nil, err + } + + res, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + + return res.Body, nil +} + +// QueryFeed returns a byte stream with the raw content of the feed update +// manifestAddressOrDomain is the address you obtained in CreateFeedWithManifest or an ENS domain whose Resolver +// points to that address +func (c *Client) QueryFeed(query *feed.Query, manifestAddressOrDomain string) (io.ReadCloser, error) { + return c.queryFeed(query, manifestAddressOrDomain, false) +} + +// queryFeed returns a byte stream with the raw content of the feed update +// manifestAddressOrDomain is the address you obtained in CreateFeedWithManifest or an ENS domain whose Resolver +// points to that address +// meta set to true will instruct the node return feed metainformation instead +func (c *Client) queryFeed(query *feed.Query, manifestAddressOrDomain string, meta bool) (io.ReadCloser, error) { + URL, err := url.Parse(c.Gateway) + if err != nil { + return nil, err + } + URL.Path = "/bzz-feed:/" + manifestAddressOrDomain + values := URL.Query() + if query != nil { + query.AppendValues(values) //adds query parameters + } + if meta { + values.Set("meta", "1") + } + URL.RawQuery = values.Encode() + res, err := http.Get(URL.String()) + if err != nil { + return nil, err + } + + if res.StatusCode != http.StatusOK { + if res.StatusCode == http.StatusNotFound { + return nil, ErrNoFeedUpdatesFound + } + errorMessageBytes, err := ioutil.ReadAll(res.Body) + var errorMessage string + if err != nil { + errorMessage = "cannot retrieve error message: " + err.Error() + } else { + errorMessage = string(errorMessageBytes) + } + return nil, fmt.Errorf("Error retrieving feed updates: %s", errorMessage) + } + + return res.Body, nil +} + +// GetFeedRequest returns a structure that describes the referenced feed status +// manifestAddressOrDomain is the address you obtained in CreateFeedWithManifest or an ENS domain whose Resolver +// points to that address +func (c *Client) GetFeedRequest(query *feed.Query, manifestAddressOrDomain string) (*feed.Request, error) { + + responseStream, err := c.queryFeed(query, manifestAddressOrDomain, true) + if err != nil { + return nil, err + } + defer responseStream.Close() + + body, err := ioutil.ReadAll(responseStream) + if err != nil { + return nil, err + } + + var metadata feed.Request + if err := metadata.UnmarshalJSON(body); err != nil { + return nil, err + } + 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/swarm/api/client/client_test.go b/swarm/api/client/client_test.go index c1d144e370..39f6e4797d 100644 --- a/swarm/api/client/client_test.go +++ b/swarm/api/client/client_test.go @@ -25,29 +25,49 @@ 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" - "github.com/ethereum/go-ethereum/swarm/testutil" + swarmhttp "github.com/ethereum/go-ethereum/swarm/api/http" + "github.com/ethereum/go-ethereum/swarm/storage/feed" ) +func serverFunc(api *api.API) swarmhttp.TestServer { + return swarmhttp.NewServer(api, "") +} + // TestClientUploadDownloadRaw test uploading and downloading raw data to swarm func TestClientUploadDownloadRaw(t *testing.T) { - srv := testutil.NewTestSwarmServer(t) + testClientUploadDownloadRaw(false, t) +} +func TestClientUploadDownloadRawEncrypted(t *testing.T) { + testClientUploadDownloadRaw(true, t) +} + +func testClientUploadDownloadRaw(toEncrypt bool, t *testing.T) { + srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil) defer srv.Close() client := NewClient(srv.URL) // upload some raw data data := []byte("foo123") - hash, err := client.UploadRaw(bytes.NewReader(data), int64(len(data))) + hash, err := client.UploadRaw(bytes.NewReader(data), int64(len(data)), toEncrypt) if err != nil { t.Fatal(err) } // check we can download the same data - res, err := client.DownloadRaw(hash) + res, isEncrypted, err := client.DownloadRaw(hash) if err != nil { t.Fatal(err) } + if isEncrypted != toEncrypt { + t.Fatalf("Expected encyption status %v got %v", toEncrypt, isEncrypted) + } defer res.Close() gotData, err := ioutil.ReadAll(res) if err != nil { @@ -61,7 +81,15 @@ func TestClientUploadDownloadRaw(t *testing.T) { // TestClientUploadDownloadFiles test uploading and downloading files to swarm // manifests func TestClientUploadDownloadFiles(t *testing.T) { - srv := testutil.NewTestSwarmServer(t) + testClientUploadDownloadFiles(false, t) +} + +func TestClientUploadDownloadFilesEncrypted(t *testing.T) { + testClientUploadDownloadFiles(true, t) +} + +func testClientUploadDownloadFiles(toEncrypt bool, t *testing.T) { + srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil) defer srv.Close() client := NewClient(srv.URL) @@ -74,7 +102,7 @@ func TestClientUploadDownloadFiles(t *testing.T) { Size: int64(len(data)), }, } - hash, err := client.Upload(file, manifest) + hash, err := client.Upload(file, manifest, toEncrypt) if err != nil { t.Fatal(err) } @@ -159,7 +187,7 @@ func newTestDirectory(t *testing.T) string { // TestClientUploadDownloadDirectory tests uploading and downloading a // directory of files to a swarm manifest func TestClientUploadDownloadDirectory(t *testing.T) { - srv := testutil.NewTestSwarmServer(t) + srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil) defer srv.Close() dir := newTestDirectory(t) @@ -167,8 +195,8 @@ func TestClientUploadDownloadDirectory(t *testing.T) { // upload the directory client := NewClient(srv.URL) - defaultPath := filepath.Join(dir, testDirFiles[0]) - hash, err := client.UploadDirectory(dir, defaultPath, "") + defaultPath := testDirFiles[0] + hash, err := client.UploadDirectory(dir, defaultPath, "", false) if err != nil { t.Fatalf("error uploading directory: %s", err) } @@ -201,7 +229,7 @@ func TestClientUploadDownloadDirectory(t *testing.T) { t.Fatal(err) } defer os.RemoveAll(tmp) - if err := client.DownloadDirectory(hash, "", tmp); err != nil { + if err := client.DownloadDirectory(hash, "", tmp, ""); err != nil { t.Fatal(err) } for _, file := range testDirFiles { @@ -217,20 +245,28 @@ func TestClientUploadDownloadDirectory(t *testing.T) { // TestClientFileList tests listing files in a swarm manifest func TestClientFileList(t *testing.T) { - srv := testutil.NewTestSwarmServer(t) + testClientFileList(false, t) +} + +func TestClientFileListEncrypted(t *testing.T) { + testClientFileList(true, t) +} + +func testClientFileList(toEncrypt bool, t *testing.T) { + srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil) defer srv.Close() dir := newTestDirectory(t) defer os.RemoveAll(dir) client := NewClient(srv.URL) - hash, err := client.UploadDirectory(dir, "", "") + hash, err := client.UploadDirectory(dir, "", "", toEncrypt) if err != nil { t.Fatalf("error uploading directory: %s", err) } ls := func(prefix string) []string { - list, err := client.List(hash, prefix) + list, err := client.List(hash, prefix, "") if err != nil { t.Fatal(err) } @@ -275,7 +311,7 @@ func TestClientFileList(t *testing.T) { // TestClientMultipartUpload tests uploading files to swarm using a multipart // upload func TestClientMultipartUpload(t *testing.T) { - srv := testutil.NewTestSwarmServer(t) + srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil) defer srv.Close() // define an uploader which uploads testDirFiles with some data @@ -323,3 +359,231 @@ func TestClientMultipartUpload(t *testing.T) { checkDownloadFile(file) } } + +func newTestSigner() (*feed.GenericSigner, error) { + privKey, err := crypto.HexToECDSA("deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef") + if err != nil { + return nil, err + } + return feed.NewGenericSigner(privKey), nil +} + +// Test the transparent resolving of feed updates with bzz:// scheme +// +// 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 TestClientBzzWithFeed(t *testing.T) { + + signer, _ := newTestSigner() + + // Initialize a Swarm test server + srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil) + swarmClient := NewClient(srv.URL) + defer srv.Close() + + // 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) + // + `) + + // 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)), + }, + } + + // 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) + } + + // convert the hex-encoded manifest hash to a 32-byte slice + manifestAddress := common.FromHex(manifestAddressHex) + + 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)) + } + + // 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) + } + + // 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) + } + + // 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 = swarmClient.QueryFeed(nil, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb") + if err != ErrNoFeedUpdatesFound { + t.Fatalf("Expected to receive ErrNoFeedUpdatesFound error. Got: %s", err) + } + + // 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) + } + defer reader.Close() + gotData, err := ioutil.ReadAll(reader) + if err != nil { + t.Fatal(err) + } + + //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. +func TestClientCreateUpdateFeed(t *testing.T) { + + signer, _ := newTestSigner() + + srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil) + client := NewClient(srv.URL) + defer srv.Close() + + // set raw data for the feed update + databytes := []byte("En un lugar de La Mancha, de cuyo nombre no quiero acordarme...") + + // our feed topic name + topic, _ := feed.NewTopic("El Quijote", nil) + createRequest := feed.NewFirstRequest(topic) + + createRequest.SetData(databytes) + if err := createRequest.Sign(signer); err != nil { + t.Fatalf("Error signing update: %s", err) + } + + feedManifestHash, err := client.CreateFeedWithManifest(createRequest) + if err != nil { + t.Fatal(err) + } + + correctManifestAddrHex := "0e9b645ebc3da167b1d56399adc3276f7a08229301b72a03336be0e7d4b71882" + if feedManifestHash != correctManifestAddrHex { + t.Fatalf("Response feed manifest mismatch, expected '%s', got '%s'", correctManifestAddrHex, feedManifestHash) + } + + reader, err := client.QueryFeed(nil, correctManifestAddrHex) + if err != nil { + t.Fatalf("Error retrieving feed updates: %s", err) + } + defer reader.Close() + gotData, err := ioutil.ReadAll(reader) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(databytes, gotData) { + t.Fatalf("Expected: %v, got %v", databytes, gotData) + } + + // define different data + databytes = []byte("... no ha mucho tiempo que vivía un hidalgo de los de lanza en astillero ...") + + updateRequest, err := client.GetFeedRequest(nil, correctManifestAddrHex) + if err != nil { + t.Fatalf("Error retrieving update request template: %s", err) + } + + updateRequest.SetData(databytes) + if err := updateRequest.Sign(signer); err != nil { + t.Fatalf("Error signing update: %s", err) + } + + if err = client.UpdateFeed(updateRequest); err != nil { + t.Fatalf("Error updating feed: %s", err) + } + + reader, err = client.QueryFeed(nil, correctManifestAddrHex) + if err != nil { + t.Fatalf("Error retrieving feed updates: %s", err) + } + defer reader.Close() + gotData, err = ioutil.ReadAll(reader) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(databytes, gotData) { + t.Fatalf("Expected: %v, got %v", databytes, gotData) + } + + // now try retrieving feed updates without a manifest + + fd := &feed.Feed{ + Topic: topic, + User: signer.Address(), + } + + lookupParams := feed.NewQueryLatest(fd, lookup.NoClue) + reader, err = client.QueryFeed(lookupParams, "") + if err != nil { + t.Fatalf("Error retrieving feed updates: %s", err) + } + defer reader.Close() + gotData, err = ioutil.ReadAll(reader) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(databytes, gotData) { + t.Fatalf("Expected: %v, got %v", databytes, gotData) + } +} diff --git a/swarm/api/config.go b/swarm/api/config.go index 140c938ae0..b8de16f5f0 100644 --- a/swarm/api/config.go +++ b/swarm/api/config.go @@ -21,13 +21,16 @@ import ( "fmt" "os" "path/filepath" + "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/contracts/ens" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" "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" "github.com/ethereum/go-ethereum/swarm/storage" ) @@ -41,47 +44,60 @@ const ( // allow several bzz nodes running in parallel type Config struct { // serialised/persisted fields - *storage.StoreParams - *storage.ChunkerParams + *storage.FileStoreParams + *storage.LocalStoreParams *network.HiveParams - Swap *swap.SwapParams - *network.SyncParams - Contract common.Address - EnsRoot common.Address - EnsApi string - Path string - ListenAddr string - Port string - PublicKey string - BzzKey string - NetworkId uint64 - SwapEnabled bool - SyncEnabled bool - SwapApi string - Cors string - BzzAccount string - BootNodes string + Swap *swap.LocalProfile + Pss *pss.PssParams + //*network.SyncParams + Contract common.Address + EnsRoot common.Address + EnsAPIs []string + Path string + ListenAddr string + Port string + PublicKey string + BzzKey string + NodeID string + NetworkID uint64 + SwapEnabled bool + SyncEnabled bool + SyncingSkipCheck bool + DeliverySkipCheck bool + MaxStreamPeerServers int + LightNodeEnabled bool + BootnodeMode bool + SyncUpdateDelay time.Duration + SwapAPI string + Cors string + BzzAccount string + GlobalStoreAPI string + privateKey *ecdsa.PrivateKey } //create a default config with all parameters to set to defaults -func NewDefaultConfig() (self *Config) { +func NewConfig() (c *Config) { - self = &Config{ - StoreParams: storage.NewDefaultStoreParams(), - ChunkerParams: storage.NewChunkerParams(), - HiveParams: network.NewDefaultHiveParams(), - SyncParams: network.NewDefaultSyncParams(), - Swap: swap.NewDefaultSwapParams(), - ListenAddr: DefaultHTTPListenAddr, - Port: DefaultHTTPPort, - Path: node.DefaultDataDir(), - EnsApi: node.DefaultIPCEndpoint("geth"), - EnsRoot: ens.TestNetAddress, - NetworkId: network.NetworkId, - SwapEnabled: false, - SyncEnabled: true, - SwapApi: "", - BootNodes: "", + c = &Config{ + LocalStoreParams: storage.NewDefaultLocalStoreParams(), + FileStoreParams: storage.NewFileStoreParams(), + HiveParams: network.NewHiveParams(), + //SyncParams: network.NewDefaultSyncParams(), + Swap: swap.NewDefaultSwapParams(), + Pss: pss.NewPssParams(), + ListenAddr: DefaultHTTPListenAddr, + Port: DefaultHTTPPort, + Path: node.DefaultDataDir(), + EnsAPIs: nil, + EnsRoot: ens.TestNetAddress, + NetworkID: network.DefaultNetworkID, + SwapEnabled: false, + SyncEnabled: true, + SyncingSkipCheck: false, + MaxStreamPeerServers: 10000, + DeliverySkipCheck: true, + SyncUpdateDelay: 15 * time.Second, + SwapAPI: "", } return @@ -89,11 +105,11 @@ func NewDefaultConfig() (self *Config) { //some config params need to be initialized after the complete //config building phase is completed (e.g. due to overriding flags) -func (self *Config) Init(prvKey *ecdsa.PrivateKey) { +func (c *Config) Init(prvKey *ecdsa.PrivateKey) { address := crypto.PubkeyToAddress(prvKey.PublicKey) - self.Path = filepath.Join(self.Path, "bzz-"+common.Bytes2Hex(address.Bytes())) - err := os.MkdirAll(self.Path, os.ModePerm) + c.Path = filepath.Join(c.Path, "bzz-"+common.Bytes2Hex(address.Bytes())) + err := os.MkdirAll(c.Path, os.ModePerm) if err != nil { log.Error(fmt.Sprintf("Error creating root swarm data directory: %v", err)) return @@ -103,11 +119,25 @@ func (self *Config) Init(prvKey *ecdsa.PrivateKey) { pubkeyhex := common.ToHex(pubkey) keyhex := crypto.Keccak256Hash(pubkey).Hex() - self.PublicKey = pubkeyhex - self.BzzKey = keyhex + c.PublicKey = pubkeyhex + c.BzzKey = keyhex + c.NodeID = enode.PubkeyToIDV4(&prvKey.PublicKey).String() - self.Swap.Init(self.Contract, prvKey) - self.SyncParams.Init(self.Path) - self.HiveParams.Init(self.Path) - self.StoreParams.Init(self.Path) + if c.SwapEnabled { + c.Swap.Init(c.Contract, prvKey) + } + + c.privateKey = prvKey + c.LocalStoreParams.Init(c.Path) + c.LocalStoreParams.BaseKey = common.FromHex(keyhex) + + c.Pss = c.Pss.WithPrivateKey(c.privateKey) +} + +func (c *Config) ShiftPrivateKey() (privKey *ecdsa.PrivateKey) { + if c.privateKey != nil { + privKey = c.privateKey + c.privateKey = nil + } + return privKey } diff --git a/swarm/api/config_test.go b/swarm/api/config_test.go index 5636b6dafb..bd7e1d8705 100644 --- a/swarm/api/config_test.go +++ b/swarm/api/config_test.go @@ -33,9 +33,10 @@ func TestConfig(t *testing.T) { t.Fatalf("failed to load private key: %v", err) } - one := NewDefaultConfig() - two := NewDefaultConfig() + one := NewConfig() + two := NewConfig() + one.LocalStoreParams = two.LocalStoreParams if equal := reflect.DeepEqual(one, two); !equal { t.Fatal("Two default configs are not equal") } @@ -49,21 +50,10 @@ func TestConfig(t *testing.T) { if one.PublicKey == "" { t.Fatal("Expected PublicKey to be set") } - - //the Init function should append subdirs to the given path - if one.Swap.PayProfile.Beneficiary == (common.Address{}) { + if one.Swap.PayProfile.Beneficiary == (common.Address{}) && one.SwapEnabled { t.Fatal("Failed to correctly initialize SwapParams") } - - if one.SyncParams.RequestDbPath == one.Path { - t.Fatal("Failed to correctly initialize SyncParams") - } - - if one.HiveParams.KadDbPath == one.Path { - t.Fatal("Failed to correctly initialize HiveParams") - } - - if one.StoreParams.ChunkDbPath == one.Path { + if one.ChunkDbPath == one.Path { t.Fatal("Failed to correctly initialize StoreParams") } } diff --git a/swarm/api/encrypt.go b/swarm/api/encrypt.go new file mode 100644 index 0000000000..0d516b3d57 --- /dev/null +++ b/swarm/api/encrypt.go @@ -0,0 +1,78 @@ +// 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 api + +import ( + "encoding/binary" + "errors" + + "github.com/ethereum/go-ethereum/swarm/storage/encryption" + "golang.org/x/crypto/sha3" +) + +type RefEncryption struct { + refSize int + span []byte +} + +func NewRefEncryption(refSize int) *RefEncryption { + span := make([]byte, 8) + binary.LittleEndian.PutUint64(span, uint64(refSize)) + return &RefEncryption{ + refSize: refSize, + span: span, + } +} + +func (re *RefEncryption) Encrypt(ref []byte, key []byte) ([]byte, error) { + 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.NewLegacyKeccak256) + encryptedData, err := dataEncryption.Encrypt(ref) + if err != nil { + return nil, err + } + encryptedRef := make([]byte, len(ref)+8) + copy(encryptedRef[:8], encryptedSpan) + copy(encryptedRef[8:], encryptedData) + + return encryptedRef, nil +} + +func (re *RefEncryption) Decrypt(ref []byte, key []byte) ([]byte, error) { + spanEncryption := encryption.New(key, 0, uint32(re.refSize/32), sha3.NewLegacyKeccak256) + decryptedSpan, err := spanEncryption.Decrypt(ref[:8]) + if err != nil { + return nil, err + } + + size := binary.LittleEndian.Uint64(decryptedSpan) + if size != uint64(len(ref)-8) { + return nil, errors.New("invalid span in encrypted reference") + } + + dataEncryption := encryption.New(key, re.refSize, 0, sha3.NewLegacyKeccak256) + decryptedRef, err := dataEncryption.Decrypt(ref[8:]) + if err != nil { + return nil, err + } + + return decryptedRef, nil +} diff --git a/swarm/api/filesystem.go b/swarm/api/filesystem.go index f5dc90e2e5..266ef71bec 100644 --- a/swarm/api/filesystem.go +++ b/swarm/api/filesystem.go @@ -18,35 +18,36 @@ package api import ( "bufio" + "context" "fmt" "io" - "net/http" "os" "path" "path/filepath" "sync" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/swarm/log" "github.com/ethereum/go-ethereum/swarm/storage" ) const maxParallelFiles = 5 type FileSystem struct { - api *Api + api *API } -func NewFileSystem(api *Api) *FileSystem { +func NewFileSystem(api *API) *FileSystem { return &FileSystem{api} } // Upload replicates a local directory as a manifest file and uploads it -// using dpa store +// using FileStore store +// This function waits the chunks to be stored. // TODO: localpath should point to a manifest // // DEPRECATED: Use the HTTP API instead -func (self *FileSystem) Upload(lpath, index string) (string, error) { +func (fs *FileSystem) Upload(lpath, index string, toEncrypt bool) (string, error) { var list []*manifestTrieEntry localpath, err := filepath.Abs(filepath.Clean(lpath)) if err != nil { @@ -95,54 +96,58 @@ func (self *FileSystem) Upload(lpath, index string) (string, error) { list = append(list, entry) } - cnt := len(list) - errors := make([]error, cnt) - done := make(chan bool, maxParallelFiles) - dcnt := 0 - awg := &sync.WaitGroup{} + errors := make([]error, len(list)) + sem := make(chan bool, maxParallelFiles) + defer close(sem) for i, entry := range list { - if i >= dcnt+maxParallelFiles { - <-done - dcnt++ - } - awg.Add(1) - go func(i int, entry *manifestTrieEntry, done chan bool) { + sem <- true + go func(i int, entry *manifestTrieEntry) { + defer func() { <-sem }() + f, err := os.Open(entry.Path) - if err == nil { - stat, _ := f.Stat() - var hash storage.Key - wg := &sync.WaitGroup{} - hash, err = self.api.dpa.Store(f, stat.Size(), wg, nil) - if hash != nil { - list[i].Hash = hash.String() - } - wg.Wait() - awg.Done() - if err == nil { - first512 := make([]byte, 512) - fread, _ := f.ReadAt(first512, 0) - if fread > 0 { - mimeType := http.DetectContentType(first512[:fread]) - if filepath.Ext(entry.Path) == ".css" { - mimeType = "text/css" - } - list[i].ContentType = mimeType - } - } - f.Close() + if err != nil { + errors[i] = err + return } - errors[i] = err - done <- true - }(i, entry, done) + defer f.Close() + + stat, err := f.Stat() + if err != nil { + errors[i] = err + return + } + + var hash storage.Address + var wait func(context.Context) error + ctx := context.TODO() + hash, wait, err = fs.api.fileStore.Store(ctx, f, stat.Size(), toEncrypt) + if err != nil { + errors[i] = err + return + } + if hash != nil { + list[i].Hash = hash.Hex() + } + if err := wait(ctx); err != nil { + errors[i] = err + return + } + + list[i].ContentType, err = DetectContentType(f.Name(), f) + if err != nil { + errors[i] = err + return + } + + }(i, entry) } - for dcnt < cnt { - <-done - dcnt++ + for i := 0; i < cap(sem); i++ { + sem <- true } trie := &manifestTrie{ - dpa: self.api.dpa, + fileStore: fs.api.fileStore, } quitC := make(chan bool) for i, entry := range list { @@ -163,9 +168,8 @@ func (self *FileSystem) Upload(lpath, index string) (string, error) { err2 := trie.recalcAndStore() var hs string if err2 == nil { - hs = trie.hash.String() + hs = trie.ref.Hex() } - awg.Wait() return hs, err2 } @@ -173,7 +177,7 @@ func (self *FileSystem) Upload(lpath, index string) (string, error) { // under localpath // // DEPRECATED: Use the HTTP API instead -func (self *FileSystem) Download(bzzpath, localpath string) error { +func (fs *FileSystem) Download(bzzpath, localpath string) error { lpath, err := filepath.Abs(filepath.Clean(localpath)) if err != nil { return err @@ -188,7 +192,7 @@ func (self *FileSystem) Download(bzzpath, localpath string) error { if err != nil { return err } - key, err := self.api.Resolve(uri) + addr, err := fs.api.Resolve(context.TODO(), uri.Addr) if err != nil { return err } @@ -199,14 +203,14 @@ func (self *FileSystem) Download(bzzpath, localpath string) error { } quitC := make(chan bool) - trie, err := loadManifest(self.api.dpa, key, quitC) + trie, err := loadManifest(context.TODO(), fs.api.fileStore, addr, quitC, NOOPDecrypt) if err != nil { log.Warn(fmt.Sprintf("fs.Download: loadManifestTrie error: %v", err)) return err } type downloadListEntry struct { - key storage.Key + addr storage.Address path string } @@ -217,7 +221,7 @@ func (self *FileSystem) Download(bzzpath, localpath string) error { err = trie.listWithPrefix(path, quitC, func(entry *manifestTrieEntry, suffix string) { log.Trace(fmt.Sprintf("fs.Download: %#v", entry)) - key = common.Hex2Bytes(entry.Hash) + addr = common.Hex2Bytes(entry.Hash) path := lpath + "/" + suffix dir := filepath.Dir(path) if dir != prevPath { @@ -225,7 +229,7 @@ func (self *FileSystem) Download(bzzpath, localpath string) error { prevPath = dir } if (mde == nil) && (path != dir+"/") { - list = append(list, &downloadListEntry{key: key, path: path}) + list = append(list, &downloadListEntry{addr: addr, path: path}) } }) if err != nil { @@ -244,7 +248,7 @@ func (self *FileSystem) Download(bzzpath, localpath string) error { } go func(i int, entry *downloadListEntry) { defer wg.Done() - err := retrieveToFile(quitC, self.api.dpa, entry.key, entry.path) + err := retrieveToFile(quitC, fs.api.fileStore, entry.addr, entry.path) if err != nil { select { case errC <- err: @@ -267,14 +271,14 @@ func (self *FileSystem) Download(bzzpath, localpath string) error { } } -func retrieveToFile(quitC chan bool, dpa *storage.DPA, key storage.Key, path string) error { +func retrieveToFile(quitC chan bool, fileStore *storage.FileStore, addr storage.Address, path string) error { f, err := os.Create(path) // TODO: basePath separators if err != nil { return err } - reader := dpa.Retrieve(key) + reader, _ := fileStore.Retrieve(context.TODO(), addr) writer := bufio.NewWriter(f) - size, err := reader.Size(quitC) + size, err := reader.Size(context.TODO(), quitC) if err != nil { return err } diff --git a/swarm/api/filesystem_test.go b/swarm/api/filesystem_test.go index 8a15e735dc..02f5bff658 100644 --- a/swarm/api/filesystem_test.go +++ b/swarm/api/filesystem_test.go @@ -18,10 +18,10 @@ package api import ( "bytes" + "context" "io/ioutil" "os" "path/filepath" - "sync" "testing" "github.com/ethereum/go-ethereum/common" @@ -30,9 +30,9 @@ import ( var testDownloadDir, _ = ioutil.TempDir(os.TempDir(), "bzz-test") -func testFileSystem(t *testing.T, f func(*FileSystem)) { - testApi(t, func(api *Api) { - f(NewFileSystem(api)) +func testFileSystem(t *testing.T, f func(*FileSystem, bool)) { + testAPI(t, func(api *API, toEncrypt bool) { + f(NewFileSystem(api), toEncrypt) }) } @@ -47,9 +47,9 @@ func readPath(t *testing.T, parts ...string) string { } func TestApiDirUpload0(t *testing.T) { - testFileSystem(t, func(fs *FileSystem) { + testFileSystem(t, func(fs *FileSystem, toEncrypt bool) { api := fs.api - bzzhash, err := fs.Upload(filepath.Join("testdata", "test0"), "") + bzzhash, err := fs.Upload(filepath.Join("testdata", "test0"), "", toEncrypt) if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -60,11 +60,11 @@ func TestApiDirUpload0(t *testing.T) { content = readPath(t, "testdata", "test0", "index.css") resp = testGet(t, api, bzzhash, "index.css") - exp = expResponse(content, "text/css", 0) + exp = expResponse(content, "text/css; charset=utf-8", 0) checkResponse(t, resp, exp) - key := storage.Key(common.Hex2Bytes(bzzhash)) - _, _, _, err = api.Get(key, "") + addr := storage.Address(common.Hex2Bytes(bzzhash)) + _, _, _, _, err = api.Get(context.TODO(), NOOPDecrypt, addr, "") if err == nil { t.Fatalf("expected error: %v", err) } @@ -75,27 +75,28 @@ func TestApiDirUpload0(t *testing.T) { if err != nil { t.Fatalf("unexpected error: %v", err) } - newbzzhash, err := fs.Upload(downloadDir, "") + newbzzhash, err := fs.Upload(downloadDir, "", toEncrypt) if err != nil { t.Fatalf("unexpected error: %v", err) } - if bzzhash != newbzzhash { + // TODO: currently the hash is not deterministic in the encrypted case + if !toEncrypt && bzzhash != newbzzhash { t.Fatalf("download %v reuploaded has incorrect hash, expected %v, got %v", downloadDir, bzzhash, newbzzhash) } }) } func TestApiDirUploadModify(t *testing.T) { - testFileSystem(t, func(fs *FileSystem) { + testFileSystem(t, func(fs *FileSystem, toEncrypt bool) { api := fs.api - bzzhash, err := fs.Upload(filepath.Join("testdata", "test0"), "") + bzzhash, err := fs.Upload(filepath.Join("testdata", "test0"), "", toEncrypt) if err != nil { t.Errorf("unexpected error: %v", err) return } - key := storage.Key(common.Hex2Bytes(bzzhash)) - key, err = api.Modify(key, "index.html", "", "") + addr := storage.Address(common.Hex2Bytes(bzzhash)) + addr, err = api.Modify(context.TODO(), addr, "index.html", "", "") if err != nil { t.Errorf("unexpected error: %v", err) return @@ -105,24 +106,28 @@ func TestApiDirUploadModify(t *testing.T) { t.Errorf("unexpected error: %v", err) return } - wg := &sync.WaitGroup{} - hash, err := api.Store(bytes.NewReader(index), int64(len(index)), wg) - wg.Wait() + ctx := context.TODO() + hash, wait, err := api.Store(ctx, bytes.NewReader(index), int64(len(index)), toEncrypt) if err != nil { t.Errorf("unexpected error: %v", err) return } - key, err = api.Modify(key, "index2.html", hash.Hex(), "text/html; charset=utf-8") + err = wait(ctx) if err != nil { t.Errorf("unexpected error: %v", err) return } - key, err = api.Modify(key, "img/logo.png", hash.Hex(), "text/html; charset=utf-8") + addr, err = api.Modify(context.TODO(), addr, "index2.html", hash.Hex(), "text/html; charset=utf-8") if err != nil { t.Errorf("unexpected error: %v", err) return } - bzzhash = key.String() + addr, err = api.Modify(context.TODO(), addr, "img/logo.png", hash.Hex(), "text/html; charset=utf-8") + if err != nil { + t.Errorf("unexpected error: %v", err) + return + } + bzzhash = addr.Hex() content := readPath(t, "testdata", "test0", "index.html") resp := testGet(t, api, bzzhash, "index2.html") @@ -135,10 +140,10 @@ func TestApiDirUploadModify(t *testing.T) { content = readPath(t, "testdata", "test0", "index.css") resp = testGet(t, api, bzzhash, "index.css") - exp = expResponse(content, "text/css", 0) + exp = expResponse(content, "text/css; charset=utf-8", 0) checkResponse(t, resp, exp) - _, _, _, err = api.Get(key, "") + _, _, _, _, err = api.Get(context.TODO(), nil, addr, "") if err == nil { t.Errorf("expected error: %v", err) } @@ -146,9 +151,9 @@ func TestApiDirUploadModify(t *testing.T) { } func TestApiDirUploadWithRootFile(t *testing.T) { - testFileSystem(t, func(fs *FileSystem) { + testFileSystem(t, func(fs *FileSystem, toEncrypt bool) { api := fs.api - bzzhash, err := fs.Upload(filepath.Join("testdata", "test0"), "index.html") + bzzhash, err := fs.Upload(filepath.Join("testdata", "test0"), "index.html", toEncrypt) if err != nil { t.Errorf("unexpected error: %v", err) return @@ -162,9 +167,9 @@ func TestApiDirUploadWithRootFile(t *testing.T) { } func TestApiFileUpload(t *testing.T) { - testFileSystem(t, func(fs *FileSystem) { + testFileSystem(t, func(fs *FileSystem, toEncrypt bool) { api := fs.api - bzzhash, err := fs.Upload(filepath.Join("testdata", "test0", "index.html"), "") + bzzhash, err := fs.Upload(filepath.Join("testdata", "test0", "index.html"), "", toEncrypt) if err != nil { t.Errorf("unexpected error: %v", err) return @@ -178,9 +183,9 @@ func TestApiFileUpload(t *testing.T) { } func TestApiFileUploadWithRootFile(t *testing.T) { - testFileSystem(t, func(fs *FileSystem) { + testFileSystem(t, func(fs *FileSystem, toEncrypt bool) { api := fs.api - bzzhash, err := fs.Upload(filepath.Join("testdata", "test0", "index.html"), "index.html") + bzzhash, err := fs.Upload(filepath.Join("testdata", "test0", "index.html"), "index.html", toEncrypt) if err != nil { t.Errorf("unexpected error: %v", err) return diff --git a/swarm/api/gen_mime.go b/swarm/api/gen_mime.go new file mode 100644 index 0000000000..109edeb506 --- /dev/null +++ b/swarm/api/gen_mime.go @@ -0,0 +1,1201 @@ +// Code generated by github.com/ethereum/go-ethereum/cmd/swarm/mimegen. DO NOT EDIT. + +package api + +import "mime" + +func init() { + var mimeTypes = map[string]string{ + ".a2l": "application/A2L", + ".aml": "application/AML", + ".ez": "application/andrew-inset", + ".atf": "application/ATF", + ".atfx": "application/ATFX", + ".atxml": "application/ATXML", + ".atom": "application/atom+xml", + ".atomcat": "application/atomcat+xml", + ".atomdeleted": "application/atomdeleted+xml", + ".atomsvc": "application/atomsvc+xml", + ".apxml": "application/auth-policy+xml", + ".xdd": "application/bacnet-xdd+zip", + ".xcs": "application/calendar+xml", + ".cbor": "application/cbor", + ".ccmp": "application/ccmp+xml", + ".ccxml": "application/ccxml+xml", + ".cdfx": "application/CDFX+XML", + ".cdmia": "application/cdmi-capability", + ".cdmic": "application/cdmi-container", + ".cdmid": "application/cdmi-domain", + ".cdmio": "application/cdmi-object", + ".cdmiq": "application/cdmi-queue", + ".cea": "application/CEA", + ".cellml": "application/cellml+xml", + ".cml": "application/cellml+xml", + ".clue": "application/clue_info+xml", + ".cmsc": "application/cms", + ".cpl": "application/cpl+xml", + ".csrattrs": "application/csrattrs", + ".mpd": "application/dash+xml", + ".mpdd": "application/dashdelta", + ".davmount": "application/davmount+xml", + ".dcd": "application/DCD", + ".dcm": "application/dicom", + ".dii": "application/DII", + ".dit": "application/DIT", + ".xmls": "application/dskpp+xml", + ".dssc": "application/dssc+der", + ".xdssc": "application/dssc+xml", + ".dvc": "application/dvcs", + ".es": "application/ecmascript", + ".efi": "application/efi", + ".emma": "application/emma+xml", + ".emotionml": "application/emotionml+xml", + ".epub": "application/epub+zip", + ".exi": "application/exi", + ".finf": "application/fastinfoset", + ".fdt": "application/fdt+xml", + ".pfr": "application/font-tdpfr", + ".geojson": "application/geo+json", + ".gml": "application/gml+xml", + ".gz": "application/gzip", + ".tgz": "application/gzip", + ".stk": "application/hyperstudio", + ".ink": "application/inkml+xml", + ".inkml": "application/inkml+xml", + ".ipfix": "application/ipfix", + ".its": "application/its+xml", + ".js": "application/javascript", + ".jrd": "application/jrd+json", + ".json": "application/json", + ".json-patch": "application/json-patch+json", + ".jsonld": "application/ld+json", + ".lgr": "application/lgr+xml", + ".wlnk": "application/link-format", + ".lostxml": "application/lost+xml", + ".lostsyncxml": "application/lostsync+xml", + ".lxf": "application/LXF", + ".hqx": "application/mac-binhex40", + ".mads": "application/mads+xml", + ".mrc": "application/marc", + ".mrcx": "application/marcxml+xml", + ".nb": "application/mathematica", + ".ma": "application/mathematica", + ".mb": "application/mathematica", + ".mml": "application/mathml+xml", + ".mbox": "application/mbox", + ".meta4": "application/metalink4+xml", + ".mets": "application/mets+xml", + ".mf4": "application/MF4", + ".mods": "application/mods+xml", + ".m21": "application/mp21", + ".mp21": "application/mp21", + ".doc": "application/msword", + ".mxf": "application/mxf", + ".nq": "application/n-quads", + ".nt": "application/n-triples", + ".orq": "application/ocsp-request", + ".ors": "application/ocsp-response", + ".bin": "application/octet-stream", + ".lha": "application/octet-stream", + ".lzh": "application/octet-stream", + ".exe": "application/octet-stream", + ".class": "application/octet-stream", + ".so": "application/octet-stream", + ".dll": "application/octet-stream", + ".img": "application/octet-stream", + ".iso": "application/octet-stream", + ".oda": "application/oda", + ".odx": "application/ODX", + ".opf": "application/oebps-package+xml", + ".ogx": "application/ogg", + ".oxps": "application/oxps", + ".relo": "application/p2p-overlay+xml", + ".pdf": "application/pdf", + ".pdx": "application/PDX", + ".pgp": "application/pgp-encrypted", + ".sig": "application/pgp-signature", + ".p10": "application/pkcs10", + ".p12": "application/pkcs12", + ".pfx": "application/pkcs12", + ".p7m": "application/pkcs7-mime", + ".p7c": "application/pkcs7-mime", + ".p7s": "application/pkcs7-signature", + ".p8": "application/pkcs8", + ".cer": "application/pkix-cert", + ".crl": "application/pkix-crl", + ".pkipath": "application/pkix-pkipath", + ".pki": "application/pkixcmp", + ".pls": "application/pls+xml", + ".ps": "application/postscript", + ".eps": "application/postscript", + ".ai": "application/postscript", + ".provx": "application/provenance+xml", + ".cw": "application/prs.cww", + ".cww": "application/prs.cww", + ".hpub": "application/prs.hpub+zip", + ".rnd": "application/prs.nprend", + ".rct": "application/prs.nprend", + ".rdf-crypt": "application/prs.rdf-xml-crypt", + ".xsf": "application/prs.xsf+xml", + ".pskcxml": "application/pskc+xml", + ".rdf": "application/rdf+xml", + ".rif": "application/reginfo+xml", + ".rnc": "application/relax-ng-compact-syntax", + ".rld": "application/resource-lists-diff+xml", + ".rl": "application/resource-lists+xml", + ".rfcxml": "application/rfc+xml", + ".rs": "application/rls-services+xml", + ".gbr": "application/rpki-ghostbusters", + ".mft": "application/rpki-manifest", + ".roa": "application/rpki-roa", + ".rtf": "application/rtf", + ".scim": "application/scim+json", + ".scq": "application/scvp-cv-request", + ".scs": "application/scvp-cv-response", + ".spq": "application/scvp-vp-request", + ".spp": "application/scvp-vp-response", + ".sdp": "application/sdp", + ".soc": "application/sgml-open-catalog", + ".shf": "application/shf+xml", + ".siv": "application/sieve", + ".sieve": "application/sieve", + ".cl": "application/simple-filter+xml", + ".smil": "application/smil+xml", + ".smi": "application/smil+xml", + ".sml": "application/smil+xml", + ".rq": "application/sparql-query", + ".srx": "application/sparql-results+xml", + ".sql": "application/sql", + ".gram": "application/srgs", + ".grxml": "application/srgs+xml", + ".sru": "application/sru+xml", + ".ssml": "application/ssml+xml", + ".tau": "application/tamp-apex-update", + ".auc": "application/tamp-apex-update-confirm", + ".tcu": "application/tamp-community-update", + ".cuc": "application/tamp-community-update-confirm", + ".ter": "application/tamp-error", + ".tsa": "application/tamp-sequence-adjust", + ".sac": "application/tamp-sequence-adjust-confirm", + ".tur": "application/tamp-update", + ".tuc": "application/tamp-update-confirm", + ".tei": "application/tei+xml", + ".teiCorpus": "application/tei+xml", + ".odd": "application/tei+xml", + ".tfi": "application/thraud+xml", + ".tsq": "application/timestamp-query", + ".tsr": "application/timestamp-reply", + ".tsd": "application/timestamped-data", + ".trig": "application/trig", + ".ttml": "application/ttml+xml", + ".gsheet": "application/urc-grpsheet+xml", + ".rsheet": "application/urc-ressheet+xml", + ".td": "application/urc-targetdesc+xml", + ".uis": "application/urc-uisocketdesc+xml", + ".plb": "application/vnd.3gpp.pic-bw-large", + ".psb": "application/vnd.3gpp.pic-bw-small", + ".pvb": "application/vnd.3gpp.pic-bw-var", + ".sms": "application/vnd.3gpp2.sms", + ".tcap": "application/vnd.3gpp2.tcap", + ".imgcal": "application/vnd.3lightssoftware.imagescal", + ".pwn": "application/vnd.3M.Post-it-Notes", + ".aso": "application/vnd.accpac.simply.aso", + ".imp": "application/vnd.accpac.simply.imp", + ".acu": "application/vnd.acucobol", + ".atc": "application/vnd.acucorp", + ".acutc": "application/vnd.acucorp", + ".swf": "application/vnd.adobe.flash.movie", + ".fcdt": "application/vnd.adobe.formscentral.fcdt", + ".fxp": "application/vnd.adobe.fxp", + ".fxpl": "application/vnd.adobe.fxp", + ".xdp": "application/vnd.adobe.xdp+xml", + ".xfdf": "application/vnd.adobe.xfdf", + ".ahead": "application/vnd.ahead.space", + ".azf": "application/vnd.airzip.filesecure.azf", + ".azs": "application/vnd.airzip.filesecure.azs", + ".azw3": "application/vnd.amazon.mobi8-ebook", + ".acc": "application/vnd.americandynamics.acc", + ".ami": "application/vnd.amiga.ami", + ".apkg": "application/vnd.anki", + ".cii": "application/vnd.anser-web-certificate-issue-initiation", + ".fti": "application/vnd.anser-web-funds-transfer-initiation", + ".dist": "application/vnd.apple.installer+xml", + ".distz": "application/vnd.apple.installer+xml", + ".pkg": "application/vnd.apple.installer+xml", + ".mpkg": "application/vnd.apple.installer+xml", + ".m3u8": "application/vnd.apple.mpegurl", + ".swi": "application/vnd.aristanetworks.swi", + ".iota": "application/vnd.astraea-software.iota", + ".aep": "application/vnd.audiograph", + ".package": "application/vnd.autopackage", + ".bmml": "application/vnd.balsamiq.bmml+xml", + ".bmpr": "application/vnd.balsamiq.bmpr", + ".mpm": "application/vnd.blueice.multipass", + ".ep": "application/vnd.bluetooth.ep.oob", + ".le": "application/vnd.bluetooth.le.oob", + ".bmi": "application/vnd.bmi", + ".rep": "application/vnd.businessobjects", + ".tlclient": "application/vnd.cendio.thinlinc.clientconf", + ".cdxml": "application/vnd.chemdraw+xml", + ".pgn": "application/vnd.chess-pgn", + ".mmd": "application/vnd.chipnuts.karaoke-mmd", + ".cdy": "application/vnd.cinderella", + ".csl": "application/vnd.citationstyles.style+xml", + ".cla": "application/vnd.claymore", + ".rp9": "application/vnd.cloanto.rp9", + ".c4g": "application/vnd.clonk.c4group", + ".c4d": "application/vnd.clonk.c4group", + ".c4f": "application/vnd.clonk.c4group", + ".c4p": "application/vnd.clonk.c4group", + ".c4u": "application/vnd.clonk.c4group", + ".c11amc": "application/vnd.cluetrust.cartomobile-config", + ".c11amz": "application/vnd.cluetrust.cartomobile-config-pkg", + ".coffee": "application/vnd.coffeescript", + ".cbz": "application/vnd.comicbook+zip", + ".ica": "application/vnd.commerce-battelle", + ".icf": "application/vnd.commerce-battelle", + ".icd": "application/vnd.commerce-battelle", + ".ic0": "application/vnd.commerce-battelle", + ".ic1": "application/vnd.commerce-battelle", + ".ic2": "application/vnd.commerce-battelle", + ".ic3": "application/vnd.commerce-battelle", + ".ic4": "application/vnd.commerce-battelle", + ".ic5": "application/vnd.commerce-battelle", + ".ic6": "application/vnd.commerce-battelle", + ".ic7": "application/vnd.commerce-battelle", + ".ic8": "application/vnd.commerce-battelle", + ".csp": "application/vnd.commonspace", + ".cst": "application/vnd.commonspace", + ".cdbcmsg": "application/vnd.contact.cmsg", + ".ign": "application/vnd.coreos.ignition+json", + ".ignition": "application/vnd.coreos.ignition+json", + ".cmc": "application/vnd.cosmocaller", + ".clkx": "application/vnd.crick.clicker", + ".clkk": "application/vnd.crick.clicker.keyboard", + ".clkp": "application/vnd.crick.clicker.palette", + ".clkt": "application/vnd.crick.clicker.template", + ".clkw": "application/vnd.crick.clicker.wordbank", + ".wbs": "application/vnd.criticaltools.wbs+xml", + ".pml": "application/vnd.ctc-posml", + ".ppd": "application/vnd.cups-ppd", + ".curl": "application/vnd.curl", + ".dart": "application/vnd.dart", + ".rdz": "application/vnd.data-vision.rdz", + ".deb": "application/vnd.debian.binary-package", + ".udeb": "application/vnd.debian.binary-package", + ".uvf": "application/vnd.dece.data", + ".uvvf": "application/vnd.dece.data", + ".uvd": "application/vnd.dece.data", + ".uvvd": "application/vnd.dece.data", + ".uvt": "application/vnd.dece.ttml+xml", + ".uvvt": "application/vnd.dece.ttml+xml", + ".uvx": "application/vnd.dece.unspecified", + ".uvvx": "application/vnd.dece.unspecified", + ".uvz": "application/vnd.dece.zip", + ".uvvz": "application/vnd.dece.zip", + ".fe_launch": "application/vnd.denovo.fcselayout-link", + ".dsm": "application/vnd.desmume.movie", + ".dna": "application/vnd.dna", + ".docjson": "application/vnd.document+json", + ".scld": "application/vnd.doremir.scorecloud-binary-document", + ".dpg": "application/vnd.dpgraph", + ".mwc": "application/vnd.dpgraph", + ".dpgraph": "application/vnd.dpgraph", + ".dfac": "application/vnd.dreamfactory", + ".fla": "application/vnd.dtg.local.flash", + ".ait": "application/vnd.dvb.ait", + ".svc": "application/vnd.dvb.service", + ".geo": "application/vnd.dynageo", + ".dzr": "application/vnd.dzr", + ".mag": "application/vnd.ecowin.chart", + ".nml": "application/vnd.enliven", + ".esf": "application/vnd.epson.esf", + ".msf": "application/vnd.epson.msf", + ".qam": "application/vnd.epson.quickanime", + ".slt": "application/vnd.epson.salt", + ".ssf": "application/vnd.epson.ssf", + ".qcall": "application/vnd.ericsson.quickcall", + ".qca": "application/vnd.ericsson.quickcall", + ".espass": "application/vnd.espass-espass+zip", + ".es3": "application/vnd.eszigno3+xml", + ".et3": "application/vnd.eszigno3+xml", + ".asice": "application/vnd.etsi.asic-e+zip", + ".sce": "application/vnd.etsi.asic-e+zip", + ".asics": "application/vnd.etsi.asic-s+zip", + ".tst": "application/vnd.etsi.timestamp-token", + ".ez2": "application/vnd.ezpix-album", + ".ez3": "application/vnd.ezpix-package", + ".dim": "application/vnd.fastcopy-disk-image", + ".fdf": "application/vnd.fdf", + ".msd": "application/vnd.fdsn.mseed", + ".mseed": "application/vnd.fdsn.mseed", + ".seed": "application/vnd.fdsn.seed", + ".dataless": "application/vnd.fdsn.seed", + ".zfc": "application/vnd.filmit.zfc", + ".gph": "application/vnd.FloGraphIt", + ".ftc": "application/vnd.fluxtime.clip", + ".sfd": "application/vnd.font-fontforge-sfd", + ".fm": "application/vnd.framemaker", + ".fnc": "application/vnd.frogans.fnc", + ".ltf": "application/vnd.frogans.ltf", + ".fsc": "application/vnd.fsc.weblaunch", + ".oas": "application/vnd.fujitsu.oasys", + ".oa2": "application/vnd.fujitsu.oasys2", + ".oa3": "application/vnd.fujitsu.oasys3", + ".fg5": "application/vnd.fujitsu.oasysgp", + ".bh2": "application/vnd.fujitsu.oasysprs", + ".ddd": "application/vnd.fujixerox.ddd", + ".xdw": "application/vnd.fujixerox.docuworks", + ".xbd": "application/vnd.fujixerox.docuworks.binder", + ".xct": "application/vnd.fujixerox.docuworks.container", + ".fzs": "application/vnd.fuzzysheet", + ".txd": "application/vnd.genomatix.tuxedo", + ".g3": "application/vnd.geocube+xml", + ".g³": "application/vnd.geocube+xml", + ".ggb": "application/vnd.geogebra.file", + ".ggt": "application/vnd.geogebra.tool", + ".gex": "application/vnd.geometry-explorer", + ".gre": "application/vnd.geometry-explorer", + ".gxt": "application/vnd.geonext", + ".g2w": "application/vnd.geoplan", + ".g3w": "application/vnd.geospace", + ".gmx": "application/vnd.gmx", + ".kml": "application/vnd.google-earth.kml+xml", + ".kmz": "application/vnd.google-earth.kmz", + ".gqf": "application/vnd.grafeq", + ".gqs": "application/vnd.grafeq", + ".gac": "application/vnd.groove-account", + ".ghf": "application/vnd.groove-help", + ".gim": "application/vnd.groove-identity-message", + ".grv": "application/vnd.groove-injector", + ".gtm": "application/vnd.groove-tool-message", + ".tpl": "application/vnd.groove-tool-template", + ".vcg": "application/vnd.groove-vcard", + ".hal": "application/vnd.hal+xml", + ".zmm": "application/vnd.HandHeld-Entertainment+xml", + ".hbci": "application/vnd.hbci", + ".hbc": "application/vnd.hbci", + ".kom": "application/vnd.hbci", + ".upa": "application/vnd.hbci", + ".pkd": "application/vnd.hbci", + ".bpd": "application/vnd.hbci", + ".hdt": "application/vnd.hdt", + ".les": "application/vnd.hhe.lesson-player", + ".hpgl": "application/vnd.hp-HPGL", + ".hpi": "application/vnd.hp-hpid", + ".hpid": "application/vnd.hp-hpid", + ".hps": "application/vnd.hp-hps", + ".jlt": "application/vnd.hp-jlyt", + ".pcl": "application/vnd.hp-PCL", + ".sfd-hdstx": "application/vnd.hydrostatix.sof-data", + ".x3d": "application/vnd.hzn-3d-crossword", + ".emm": "application/vnd.ibm.electronic-media", + ".mpy": "application/vnd.ibm.MiniPay", + ".list3820": "application/vnd.ibm.modcap", + ".listafp": "application/vnd.ibm.modcap", + ".afp": "application/vnd.ibm.modcap", + ".pseg3820": "application/vnd.ibm.modcap", + ".irm": "application/vnd.ibm.rights-management", + ".sc": "application/vnd.ibm.secure-container", + ".icc": "application/vnd.iccprofile", + ".icm": "application/vnd.iccprofile", + ".1905.1": "application/vnd.ieee.1905", + ".igl": "application/vnd.igloader", + ".imf": "application/vnd.imagemeter.folder+zip", + ".imi": "application/vnd.imagemeter.image+zip", + ".ivp": "application/vnd.immervision-ivp", + ".ivu": "application/vnd.immervision-ivu", + ".imscc": "application/vnd.ims.imsccv1p1", + ".igm": "application/vnd.insors.igm", + ".xpw": "application/vnd.intercon.formnet", + ".xpx": "application/vnd.intercon.formnet", + ".i2g": "application/vnd.intergeo", + ".qbo": "application/vnd.intu.qbo", + ".qfx": "application/vnd.intu.qfx", + ".rcprofile": "application/vnd.ipunplugged.rcprofile", + ".irp": "application/vnd.irepository.package+xml", + ".xpr": "application/vnd.is-xpr", + ".fcs": "application/vnd.isac.fcs", + ".jam": "application/vnd.jam", + ".rms": "application/vnd.jcp.javame.midlet-rms", + ".jisp": "application/vnd.jisp", + ".joda": "application/vnd.joost.joda-archive", + ".ktz": "application/vnd.kahootz", + ".ktr": "application/vnd.kahootz", + ".karbon": "application/vnd.kde.karbon", + ".chrt": "application/vnd.kde.kchart", + ".kfo": "application/vnd.kde.kformula", + ".flw": "application/vnd.kde.kivio", + ".kon": "application/vnd.kde.kontour", + ".kpr": "application/vnd.kde.kpresenter", + ".kpt": "application/vnd.kde.kpresenter", + ".ksp": "application/vnd.kde.kspread", + ".kwd": "application/vnd.kde.kword", + ".kwt": "application/vnd.kde.kword", + ".htke": "application/vnd.kenameaapp", + ".kia": "application/vnd.kidspiration", + ".kne": "application/vnd.Kinar", + ".knp": "application/vnd.Kinar", + ".sdf": "application/vnd.Kinar", + ".skp": "application/vnd.koan", + ".skd": "application/vnd.koan", + ".skm": "application/vnd.koan", + ".skt": "application/vnd.koan", + ".sse": "application/vnd.kodak-descriptor", + ".lasjson": "application/vnd.las.las+json", + ".lasxml": "application/vnd.las.las+xml", + ".lbd": "application/vnd.llamagraphics.life-balance.desktop", + ".lbe": "application/vnd.llamagraphics.life-balance.exchange+xml", + ".123": "application/vnd.lotus-1-2-3", + ".wk4": "application/vnd.lotus-1-2-3", + ".wk3": "application/vnd.lotus-1-2-3", + ".wk1": "application/vnd.lotus-1-2-3", + ".apr": "application/vnd.lotus-approach", + ".vew": "application/vnd.lotus-approach", + ".prz": "application/vnd.lotus-freelance", + ".pre": "application/vnd.lotus-freelance", + ".nsf": "application/vnd.lotus-notes", + ".ntf": "application/vnd.lotus-notes", + ".ndl": "application/vnd.lotus-notes", + ".ns4": "application/vnd.lotus-notes", + ".ns3": "application/vnd.lotus-notes", + ".ns2": "application/vnd.lotus-notes", + ".nsh": "application/vnd.lotus-notes", + ".nsg": "application/vnd.lotus-notes", + ".or3": "application/vnd.lotus-organizer", + ".or2": "application/vnd.lotus-organizer", + ".org": "application/vnd.lotus-organizer", + ".scm": "application/vnd.lotus-screencam", + ".lwp": "application/vnd.lotus-wordpro", + ".sam": "application/vnd.lotus-wordpro", + ".portpkg": "application/vnd.macports.portpkg", + ".mvt": "application/vnd.mapbox-vector-tile", + ".mdc": "application/vnd.marlin.drm.mdcf", + ".mmdb": "application/vnd.maxmind.maxmind-db", + ".mcd": "application/vnd.mcd", + ".mc1": "application/vnd.medcalcdata", + ".cdkey": "application/vnd.mediastation.cdkey", + ".mwf": "application/vnd.MFER", + ".mfm": "application/vnd.mfmp", + ".flo": "application/vnd.micrografx.flo", + ".igx": "application/vnd.micrografx.igx", + ".mif": "application/vnd.mif", + ".daf": "application/vnd.Mobius.DAF", + ".dis": "application/vnd.Mobius.DIS", + ".mbk": "application/vnd.Mobius.MBK", + ".mqy": "application/vnd.Mobius.MQY", + ".msl": "application/vnd.Mobius.MSL", + ".plc": "application/vnd.Mobius.PLC", + ".txf": "application/vnd.Mobius.TXF", + ".mpn": "application/vnd.mophun.application", + ".mpc": "application/vnd.mophun.certificate", + ".xul": "application/vnd.mozilla.xul+xml", + ".3mf": "application/vnd.ms-3mfdocument", + ".cil": "application/vnd.ms-artgalry", + ".asf": "application/vnd.ms-asf", + ".cab": "application/vnd.ms-cab-compressed", + ".xls": "application/vnd.ms-excel", + ".xlm": "application/vnd.ms-excel", + ".xla": "application/vnd.ms-excel", + ".xlc": "application/vnd.ms-excel", + ".xlt": "application/vnd.ms-excel", + ".xlw": "application/vnd.ms-excel", + ".xltm": "application/vnd.ms-excel.template.macroEnabled.12", + ".xlam": "application/vnd.ms-excel.addin.macroEnabled.12", + ".xlsb": "application/vnd.ms-excel.sheet.binary.macroEnabled.12", + ".xlsm": "application/vnd.ms-excel.sheet.macroEnabled.12", + ".eot": "application/vnd.ms-fontobject", + ".chm": "application/vnd.ms-htmlhelp", + ".ims": "application/vnd.ms-ims", + ".lrm": "application/vnd.ms-lrm", + ".thmx": "application/vnd.ms-officetheme", + ".ppt": "application/vnd.ms-powerpoint", + ".pps": "application/vnd.ms-powerpoint", + ".pot": "application/vnd.ms-powerpoint", + ".ppam": "application/vnd.ms-powerpoint.addin.macroEnabled.12", + ".pptm": "application/vnd.ms-powerpoint.presentation.macroEnabled.12", + ".sldm": "application/vnd.ms-powerpoint.slide.macroEnabled.12", + ".ppsm": "application/vnd.ms-powerpoint.slideshow.macroEnabled.12", + ".potm": "application/vnd.ms-powerpoint.template.macroEnabled.12", + ".mpp": "application/vnd.ms-project", + ".mpt": "application/vnd.ms-project", + ".tnef": "application/vnd.ms-tnef", + ".tnf": "application/vnd.ms-tnef", + ".docm": "application/vnd.ms-word.document.macroEnabled.12", + ".dotm": "application/vnd.ms-word.template.macroEnabled.12", + ".wcm": "application/vnd.ms-works", + ".wdb": "application/vnd.ms-works", + ".wks": "application/vnd.ms-works", + ".wps": "application/vnd.ms-works", + ".wpl": "application/vnd.ms-wpl", + ".xps": "application/vnd.ms-xpsdocument", + ".msa": "application/vnd.msa-disk-image", + ".mseq": "application/vnd.mseq", + ".crtr": "application/vnd.multiad.creator", + ".cif": "application/vnd.multiad.creator.cif", + ".mus": "application/vnd.musician", + ".msty": "application/vnd.muvee.style", + ".taglet": "application/vnd.mynfc", + ".entity": "application/vnd.nervana", + ".request": "application/vnd.nervana", + ".bkm": "application/vnd.nervana", + ".kcm": "application/vnd.nervana", + ".nitf": "application/vnd.nitf", + ".nlu": "application/vnd.neurolanguage.nlu", + ".nds": "application/vnd.nintendo.nitro.rom", + ".sfc": "application/vnd.nintendo.snes.rom", + ".smc": "application/vnd.nintendo.snes.rom", + ".nnd": "application/vnd.noblenet-directory", + ".nns": "application/vnd.noblenet-sealer", + ".nnw": "application/vnd.noblenet-web", + ".ac": "application/vnd.nokia.n-gage.ac+xml", + ".ngdat": "application/vnd.nokia.n-gage.data", + ".n-gage": "application/vnd.nokia.n-gage.symbian.install", + ".rpst": "application/vnd.nokia.radio-preset", + ".rpss": "application/vnd.nokia.radio-presets", + ".edm": "application/vnd.novadigm.EDM", + ".edx": "application/vnd.novadigm.EDX", + ".ext": "application/vnd.novadigm.EXT", + ".odc": "application/vnd.oasis.opendocument.chart", + ".otc": "application/vnd.oasis.opendocument.chart-template", + ".odb": "application/vnd.oasis.opendocument.database", + ".odf": "application/vnd.oasis.opendocument.formula", + ".odg": "application/vnd.oasis.opendocument.graphics", + ".otg": "application/vnd.oasis.opendocument.graphics-template", + ".odi": "application/vnd.oasis.opendocument.image", + ".oti": "application/vnd.oasis.opendocument.image-template", + ".odp": "application/vnd.oasis.opendocument.presentation", + ".otp": "application/vnd.oasis.opendocument.presentation-template", + ".ods": "application/vnd.oasis.opendocument.spreadsheet", + ".ots": "application/vnd.oasis.opendocument.spreadsheet-template", + ".odt": "application/vnd.oasis.opendocument.text", + ".odm": "application/vnd.oasis.opendocument.text-master", + ".ott": "application/vnd.oasis.opendocument.text-template", + ".oth": "application/vnd.oasis.opendocument.text-web", + ".xo": "application/vnd.olpc-sugar", + ".dd2": "application/vnd.oma.dd2+xml", + ".tam": "application/vnd.onepager", + ".tamp": "application/vnd.onepagertamp", + ".tamx": "application/vnd.onepagertamx", + ".tat": "application/vnd.onepagertat", + ".tatp": "application/vnd.onepagertatp", + ".tatx": "application/vnd.onepagertatx", + ".obgx": "application/vnd.openblox.game+xml", + ".obg": "application/vnd.openblox.game-binary", + ".oeb": "application/vnd.openeye.oeb", + ".oxt": "application/vnd.openofficeorg.extension", + ".osm": "application/vnd.openstreetmap.data+xml", + ".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation", + ".sldx": "application/vnd.openxmlformats-officedocument.presentationml.slide", + ".ppsx": "application/vnd.openxmlformats-officedocument.presentationml.slideshow", + ".potx": "application/vnd.openxmlformats-officedocument.presentationml.template", + ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + ".xltx": "application/vnd.openxmlformats-officedocument.spreadsheetml.template", + ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + ".dotx": "application/vnd.openxmlformats-officedocument.wordprocessingml.template", + ".ndc": "application/vnd.osa.netdeploy", + ".mgp": "application/vnd.osgeo.mapguide.package", + ".dp": "application/vnd.osgi.dp", + ".esa": "application/vnd.osgi.subsystem", + ".oxlicg": "application/vnd.oxli.countgraph", + ".prc": "application/vnd.palm", + ".pdb": "application/vnd.palm", + ".pqa": "application/vnd.palm", + ".oprc": "application/vnd.palm", + ".plp": "application/vnd.panoply", + ".paw": "application/vnd.pawaafile", + ".str": "application/vnd.pg.format", + ".ei6": "application/vnd.pg.osasli", + ".pil": "application/vnd.piaccess.application-license", + ".efif": "application/vnd.picsel", + ".wg": "application/vnd.pmi.widget", + ".plf": "application/vnd.pocketlearn", + ".pbd": "application/vnd.powerbuilder6", + ".preminet": "application/vnd.preminet", + ".box": "application/vnd.previewsystems.box", + ".vbox": "application/vnd.previewsystems.box", + ".mgz": "application/vnd.proteus.magazine", + ".qps": "application/vnd.publishare-delta-tree", + ".ptid": "application/vnd.pvi.ptid1", + ".bar": "application/vnd.qualcomm.brew-app-res", + ".qxd": "application/vnd.Quark.QuarkXPress", + ".qxt": "application/vnd.Quark.QuarkXPress", + ".qwd": "application/vnd.Quark.QuarkXPress", + ".qwt": "application/vnd.Quark.QuarkXPress", + ".qxl": "application/vnd.Quark.QuarkXPress", + ".qxb": "application/vnd.Quark.QuarkXPress", + ".quox": "application/vnd.quobject-quoxdocument", + ".quiz": "application/vnd.quobject-quoxdocument", + ".tree": "application/vnd.rainstor.data", + ".rar": "application/vnd.rar", + ".bed": "application/vnd.realvnc.bed", + ".mxl": "application/vnd.recordare.musicxml", + ".cryptonote": "application/vnd.rig.cryptonote", + ".link66": "application/vnd.route66.link66+xml", + ".st": "application/vnd.sailingtracker.track", + ".scd": "application/vnd.scribus", + ".sla": "application/vnd.scribus", + ".slaz": "application/vnd.scribus", + ".s3df": "application/vnd.sealed.3df", + ".scsf": "application/vnd.sealed.csf", + ".sdoc": "application/vnd.sealed.doc", + ".sdo": "application/vnd.sealed.doc", + ".s1w": "application/vnd.sealed.doc", + ".seml": "application/vnd.sealed.eml", + ".sem": "application/vnd.sealed.eml", + ".smht": "application/vnd.sealed.mht", + ".smh": "application/vnd.sealed.mht", + ".sppt": "application/vnd.sealed.ppt", + ".s1p": "application/vnd.sealed.ppt", + ".stif": "application/vnd.sealed.tiff", + ".sxls": "application/vnd.sealed.xls", + ".sxl": "application/vnd.sealed.xls", + ".s1e": "application/vnd.sealed.xls", + ".stml": "application/vnd.sealedmedia.softseal.html", + ".s1h": "application/vnd.sealedmedia.softseal.html", + ".spdf": "application/vnd.sealedmedia.softseal.pdf", + ".spd": "application/vnd.sealedmedia.softseal.pdf", + ".s1a": "application/vnd.sealedmedia.softseal.pdf", + ".see": "application/vnd.seemail", + ".sema": "application/vnd.sema", + ".semd": "application/vnd.semd", + ".semf": "application/vnd.semf", + ".ifm": "application/vnd.shana.informed.formdata", + ".itp": "application/vnd.shana.informed.formtemplate", + ".iif": "application/vnd.shana.informed.interchange", + ".ipk": "application/vnd.shana.informed.package", + ".twd": "application/vnd.SimTech-MindMapper", + ".twds": "application/vnd.SimTech-MindMapper", + ".mmf": "application/vnd.smaf", + ".notebook": "application/vnd.smart.notebook", + ".teacher": "application/vnd.smart.teacher", + ".fo": "application/vnd.software602.filler.form+xml", + ".zfo": "application/vnd.software602.filler.form-xml-zip", + ".sdkm": "application/vnd.solent.sdkm+xml", + ".sdkd": "application/vnd.solent.sdkm+xml", + ".dxp": "application/vnd.spotfire.dxp", + ".sfs": "application/vnd.spotfire.sfs", + ".smzip": "application/vnd.stepmania.package", + ".sm": "application/vnd.stepmania.stepchart", + ".wadl": "application/vnd.sun.wadl+xml", + ".sus": "application/vnd.sus-calendar", + ".susp": "application/vnd.sus-calendar", + ".xsm": "application/vnd.syncml+xml", + ".bdm": "application/vnd.syncml.dm+wbxml", + ".xdm": "application/vnd.syncml.dm+xml", + ".ddf": "application/vnd.syncml.dmddf+xml", + ".tao": "application/vnd.tao.intent-module-archive", + ".pcap": "application/vnd.tcpdump.pcap", + ".cap": "application/vnd.tcpdump.pcap", + ".dmp": "application/vnd.tcpdump.pcap", + ".qvd": "application/vnd.theqvd", + ".vfr": "application/vnd.tml", + ".viaframe": "application/vnd.tml", + ".tmo": "application/vnd.tmobile-livetv", + ".tpt": "application/vnd.trid.tpt", + ".mxs": "application/vnd.triscape.mxs", + ".tra": "application/vnd.trueapp", + ".ufdl": "application/vnd.ufdl", + ".ufd": "application/vnd.ufdl", + ".frm": "application/vnd.ufdl", + ".utz": "application/vnd.uiq.theme", + ".umj": "application/vnd.umajin", + ".unityweb": "application/vnd.unity", + ".uoml": "application/vnd.uoml+xml", + ".uo": "application/vnd.uoml+xml", + ".urim": "application/vnd.uri-map", + ".urimap": "application/vnd.uri-map", + ".vmt": "application/vnd.valve.source.material", + ".vcx": "application/vnd.vcx", + ".mxi": "application/vnd.vd-study", + ".study-inter": "application/vnd.vd-study", + ".model-inter": "application/vnd.vd-study", + ".vwx": "application/vnd.vectorworks", + ".vsc": "application/vnd.vidsoft.vidconference", + ".vsd": "application/vnd.visio", + ".vst": "application/vnd.visio", + ".vsw": "application/vnd.visio", + ".vss": "application/vnd.visio", + ".vis": "application/vnd.visionary", + ".vsf": "application/vnd.vsf", + ".sic": "application/vnd.wap.sic", + ".slc": "application/vnd.wap.slc", + ".wbxml": "application/vnd.wap.wbxml", + ".wmlc": "application/vnd.wap.wmlc", + ".wmlsc": "application/vnd.wap.wmlscriptc", + ".wtb": "application/vnd.webturbo", + ".p2p": "application/vnd.wfa.p2p", + ".wsc": "application/vnd.wfa.wsc", + ".wmc": "application/vnd.wmc", + ".m": "application/vnd.wolfram.mathematica.package", + ".nbp": "application/vnd.wolfram.player", + ".wpd": "application/vnd.wordperfect", + ".wqd": "application/vnd.wqd", + ".stf": "application/vnd.wt.stf", + ".wv": "application/vnd.wv.csp+wbxml", + ".xar": "application/vnd.xara", + ".xfdl": "application/vnd.xfdl", + ".xfd": "application/vnd.xfdl", + ".cpkg": "application/vnd.xmpie.cpkg", + ".dpkg": "application/vnd.xmpie.dpkg", + ".ppkg": "application/vnd.xmpie.ppkg", + ".xlim": "application/vnd.xmpie.xlim", + ".hvd": "application/vnd.yamaha.hv-dic", + ".hvs": "application/vnd.yamaha.hv-script", + ".hvp": "application/vnd.yamaha.hv-voice", + ".osf": "application/vnd.yamaha.openscoreformat", + ".saf": "application/vnd.yamaha.smaf-audio", + ".spf": "application/vnd.yamaha.smaf-phrase", + ".yme": "application/vnd.yaoweme", + ".cmp": "application/vnd.yellowriver-custom-menu", + ".zir": "application/vnd.zul", + ".zirz": "application/vnd.zul", + ".zaz": "application/vnd.zzazz.deck+xml", + ".vxml": "application/voicexml+xml", + ".wif": "application/watcherinfo+xml", + ".wgt": "application/widget", + ".wsdl": "application/wsdl+xml", + ".wspolicy": "application/wspolicy+xml", + ".xav": "application/xcap-att+xml", + ".xca": "application/xcap-caps+xml", + ".xdf": "application/xcap-diff+xml", + ".xel": "application/xcap-el+xml", + ".xer": "application/xcap-error+xml", + ".xns": "application/xcap-ns+xml", + ".xhtml": "application/xhtml+xml", + ".xhtm": "application/xhtml+xml", + ".xht": "application/xhtml+xml", + ".dtd": "application/xml-dtd", + ".xop": "application/xop+xml", + ".xsl": "application/xslt+xml", + ".xslt": "application/xslt+xml", + ".mxml": "application/xv+xml", + ".xhvml": "application/xv+xml", + ".xvml": "application/xv+xml", + ".xvm": "application/xv+xml", + ".yang": "application/yang", + ".yin": "application/yin+xml", + ".zip": "application/zip", + ".726": "audio/32kadpcm", + ".ac3": "audio/ac3", + ".amr": "audio/AMR", + ".awb": "audio/AMR-WB", + ".acn": "audio/asc", + ".aal": "audio/ATRAC-ADVANCED-LOSSLESS", + ".atx": "audio/ATRAC-X", + ".at3": "audio/ATRAC3", + ".aa3": "audio/ATRAC3", + ".omg": "audio/ATRAC3", + ".au": "audio/basic", + ".snd": "audio/basic", + ".dls": "audio/dls", + ".evc": "audio/EVRC", + ".evb": "audio/EVRCB", + ".enw": "audio/EVRCNW", + ".evw": "audio/EVRCWB", + ".lbc": "audio/iLBC", + ".l16": "audio/L16", + ".mxmf": "audio/mobile-xmf", + ".m4a": "audio/mp4", + ".mp3": "audio/mpeg", + ".mpga": "audio/mpeg", + ".mp1": "audio/mpeg", + ".mp2": "audio/mpeg", + ".oga": "audio/ogg", + ".ogg": "audio/ogg", + ".opus": "audio/ogg", + ".spx": "audio/ogg", + ".sid": "audio/prs.sid", + ".psid": "audio/prs.sid", + ".qcp": "audio/qcelp", + ".smv": "audio/SMV", + ".koz": "audio/vnd.audikoz", + ".uva": "audio/vnd.dece.audio", + ".uvva": "audio/vnd.dece.audio", + ".eol": "audio/vnd.digital-winds", + ".mlp": "audio/vnd.dolby.mlp", + ".dts": "audio/vnd.dts", + ".dtshd": "audio/vnd.dts.hd", + ".plj": "audio/vnd.everad.plj", + ".lvp": "audio/vnd.lucent.voice", + ".pya": "audio/vnd.ms-playready.media.pya", + ".vbk": "audio/vnd.nortel.vbk", + ".ecelp4800": "audio/vnd.nuera.ecelp4800", + ".ecelp7470": "audio/vnd.nuera.ecelp7470", + ".ecelp9600": "audio/vnd.nuera.ecelp9600", + ".rip": "audio/vnd.rip", + ".smp3": "audio/vnd.sealedmedia.softseal.mpeg", + ".smp": "audio/vnd.sealedmedia.softseal.mpeg", + ".s1m": "audio/vnd.sealedmedia.softseal.mpeg", + ".ttc": "font/collection", + ".otf": "font/otf", + ".ttf": "font/ttf", + ".woff": "font/woff", + ".woff2": "font/woff2", + ".bmp": "image/bmp", + ".dib": "image/bmp", + ".cgm": "image/cgm", + ".drle": "image/dicom-rle", + ".emf": "image/emf", + ".fits": "image/fits", + ".fit": "image/fits", + ".fts": "image/fits", + ".gif": "image/gif", + ".ief": "image/ief", + ".jls": "image/jls", + ".jp2": "image/jp2", + ".jpg2": "image/jp2", + ".jpg": "image/jpeg", + ".jpeg": "image/jpeg", + ".jpe": "image/jpeg", + ".jfif": "image/jpeg", + ".jpm": "image/jpm", + ".jpgm": "image/jpm", + ".jpx": "image/jpx", + ".jpf": "image/jpx", + ".ktx": "image/ktx", + ".png": "image/png", + ".btif": "image/prs.btif", + ".btf": "image/prs.btif", + ".pti": "image/prs.pti", + ".svg": "image/svg+xml", + ".svgz": "image/svg+xml", + ".t38": "image/t38", + ".tiff": "image/tiff", + ".tif": "image/tiff", + ".tfx": "image/tiff-fx", + ".psd": "image/vnd.adobe.photoshop", + ".azv": "image/vnd.airzip.accelerator.azv", + ".uvi": "image/vnd.dece.graphic", + ".uvvi": "image/vnd.dece.graphic", + ".uvg": "image/vnd.dece.graphic", + ".uvvg": "image/vnd.dece.graphic", + ".djvu": "image/vnd.djvu", + ".djv": "image/vnd.djvu", + ".dwg": "image/vnd.dwg", + ".dxf": "image/vnd.dxf", + ".fbs": "image/vnd.fastbidsheet", + ".fpx": "image/vnd.fpx", + ".fst": "image/vnd.fst", + ".mmr": "image/vnd.fujixerox.edmics-mmr", + ".rlc": "image/vnd.fujixerox.edmics-rlc", + ".pgb": "image/vnd.globalgraphics.pgb", + ".ico": "image/vnd.microsoft.icon", + ".apng": "image/vnd.mozilla.apng", + ".mdi": "image/vnd.ms-modi", + ".hdr": "image/vnd.radiance", + ".rgbe": "image/vnd.radiance", + ".xyze": "image/vnd.radiance", + ".spng": "image/vnd.sealed.png", + ".spn": "image/vnd.sealed.png", + ".s1n": "image/vnd.sealed.png", + ".sgif": "image/vnd.sealedmedia.softseal.gif", + ".sgi": "image/vnd.sealedmedia.softseal.gif", + ".s1g": "image/vnd.sealedmedia.softseal.gif", + ".sjpg": "image/vnd.sealedmedia.softseal.jpg", + ".sjp": "image/vnd.sealedmedia.softseal.jpg", + ".s1j": "image/vnd.sealedmedia.softseal.jpg", + ".tap": "image/vnd.tencent.tap", + ".vtf": "image/vnd.valve.source.texture", + ".wbmp": "image/vnd.wap.wbmp", + ".xif": "image/vnd.xiff", + ".pcx": "image/vnd.zbrush.pcx", + ".wmf": "image/wmf", + ".u8msg": "message/global", + ".u8dsn": "message/global-delivery-status", + ".u8mdn": "message/global-disposition-notification", + ".u8hdr": "message/global-headers", + ".eml": "message/rfc822", + ".mail": "message/rfc822", + ".art": "message/rfc822", + ".gltf": "model/gltf+json", + ".igs": "model/iges", + ".iges": "model/iges", + ".msh": "model/mesh", + ".mesh": "model/mesh", + ".silo": "model/mesh", + ".dae": "model/vnd.collada+xml", + ".dwf": "model/vnd.dwf", + ".gdl": "model/vnd.gdl", + ".gsm": "model/vnd.gdl", + ".win": "model/vnd.gdl", + ".dor": "model/vnd.gdl", + ".lmp": "model/vnd.gdl", + ".rsm": "model/vnd.gdl", + ".msm": "model/vnd.gdl", + ".ism": "model/vnd.gdl", + ".gtw": "model/vnd.gtw", + ".moml": "model/vnd.moml+xml", + ".mts": "model/vnd.mts", + ".ogex": "model/vnd.opengex", + ".x_b": "model/vnd.parasolid.transmit.binary", + ".xmt_bin": "model/vnd.parasolid.transmit.binary", + ".x_t": "model/vnd.parasolid.transmit.text", + ".xmt_txt": "model/vnd.parasolid.transmit.text", + ".bsp": "model/vnd.valve.source.compiled-map", + ".vtu": "model/vnd.vtu", + ".wrl": "model/vrml", + ".vrml": "model/vrml", + ".x3db": "model/x3d+xml", + ".x3dv": "model/x3d-vrml", + ".x3dvz": "model/x3d-vrml", + ".bmed": "multipart/vnd.bint.med-plus", + ".vpm": "multipart/voice-message", + ".appcache": "text/cache-manifest", + ".manifest": "text/cache-manifest", + ".ics": "text/calendar", + ".ifb": "text/calendar", + ".css": "text/css", + ".csv": "text/csv", + ".csvs": "text/csv-schema", + ".soa": "text/dns", + ".zone": "text/dns", + ".html": "text/html", + ".htm": "text/html", + ".cnd": "text/jcr-cnd", + ".markdown": "text/markdown", + ".md": "text/markdown", + ".miz": "text/mizar", + ".n3": "text/n3", + ".txt": "text/plain", + ".asc": "text/plain", + ".text": "text/plain", + ".pm": "text/plain", + ".el": "text/plain", + ".c": "text/plain", + ".h": "text/plain", + ".cc": "text/plain", + ".hh": "text/plain", + ".cxx": "text/plain", + ".hxx": "text/plain", + ".f90": "text/plain", + ".conf": "text/plain", + ".log": "text/plain", + ".provn": "text/provenance-notation", + ".rst": "text/prs.fallenstein.rst", + ".tag": "text/prs.lines.tag", + ".dsc": "text/prs.lines.tag", + ".rtx": "text/richtext", + ".sgml": "text/sgml", + ".sgm": "text/sgml", + ".tsv": "text/tab-separated-values", + ".t": "text/troff", + ".tr": "text/troff", + ".roff": "text/troff", + ".ttl": "text/turtle", + ".uris": "text/uri-list", + ".uri": "text/uri-list", + ".vcf": "text/vcard", + ".vcard": "text/vcard", + ".a": "text/vnd.a", + ".abc": "text/vnd.abc", + ".ascii": "text/vnd.ascii-art", + ".copyright": "text/vnd.debian.copyright", + ".dms": "text/vnd.DMClientScript", + ".sub": "text/vnd.dvb.subtitle", + ".jtd": "text/vnd.esmertec.theme-descriptor", + ".fly": "text/vnd.fly", + ".flx": "text/vnd.fmi.flexstor", + ".gv": "text/vnd.graphviz", + ".dot": "text/vnd.graphviz", + ".3dml": "text/vnd.in3d.3dml", + ".3dm": "text/vnd.in3d.3dml", + ".spot": "text/vnd.in3d.spot", + ".spo": "text/vnd.in3d.spot", + ".mpf": "text/vnd.ms-mediapackage", + ".ccc": "text/vnd.net2phone.commcenter.command", + ".uric": "text/vnd.si.uricatalogue", + ".jad": "text/vnd.sun.j2me.app-descriptor", + ".ts": "text/vnd.trolltech.linguist", + ".si": "text/vnd.wap.si", + ".sl": "text/vnd.wap.sl", + ".wml": "text/vnd.wap.wml", + ".wmls": "text/vnd.wap.wmlscript", + ".xml": "text/xml", + ".xsd": "text/xml", + ".rng": "text/xml", + ".ent": "text/xml-external-parsed-entity", + ".3gp": "video/3gpp", + ".3gpp": "video/3gpp", + ".3g2": "video/3gpp2", + ".3gpp2": "video/3gpp2", + ".m4s": "video/iso.segment", + ".mj2": "video/mj2", + ".mjp2": "video/mj2", + ".mp4": "video/mp4", + ".mpg4": "video/mp4", + ".m4v": "video/mp4", + ".mpeg": "video/mpeg", + ".mpg": "video/mpeg", + ".mpe": "video/mpeg", + ".m1v": "video/mpeg", + ".m2v": "video/mpeg", + ".ogv": "video/ogg", + ".mov": "video/quicktime", + ".qt": "video/quicktime", + ".uvh": "video/vnd.dece.hd", + ".uvvh": "video/vnd.dece.hd", + ".uvm": "video/vnd.dece.mobile", + ".uvvm": "video/vnd.dece.mobile", + ".uvu": "video/vnd.dece.mp4", + ".uvvu": "video/vnd.dece.mp4", + ".uvp": "video/vnd.dece.pd", + ".uvvp": "video/vnd.dece.pd", + ".uvs": "video/vnd.dece.sd", + ".uvvs": "video/vnd.dece.sd", + ".uvv": "video/vnd.dece.video", + ".uvvv": "video/vnd.dece.video", + ".dvb": "video/vnd.dvb.file", + ".fvt": "video/vnd.fvt", + ".mxu": "video/vnd.mpegurl", + ".m4u": "video/vnd.mpegurl", + ".pyv": "video/vnd.ms-playready.media.pyv", + ".nim": "video/vnd.nokia.interleaved-multimedia", + ".bik": "video/vnd.radgamettools.bink", + ".bk2": "video/vnd.radgamettools.bink", + ".smk": "video/vnd.radgamettools.smacker", + ".smpg": "video/vnd.sealed.mpeg1", + ".s11": "video/vnd.sealed.mpeg1", + ".s14": "video/vnd.sealed.mpeg4", + ".sswf": "video/vnd.sealed.swf", + ".ssw": "video/vnd.sealed.swf", + ".smov": "video/vnd.sealedmedia.softseal.mov", + ".smo": "video/vnd.sealedmedia.softseal.mov", + ".s1q": "video/vnd.sealedmedia.softseal.mov", + ".viv": "video/vnd.vivo", + ".cpt": "application/mac-compactpro", + ".metalink": "application/metalink+xml", + ".owx": "application/owl+xml", + ".rss": "application/rss+xml", + ".apk": "application/vnd.android.package-archive", + ".dd": "application/vnd.oma.dd+xml", + ".dcf": "application/vnd.oma.drm.content", + ".o4a": "application/vnd.oma.drm.dcf", + ".o4v": "application/vnd.oma.drm.dcf", + ".dm": "application/vnd.oma.drm.message", + ".drc": "application/vnd.oma.drm.rights+wbxml", + ".dr": "application/vnd.oma.drm.rights+xml", + ".sxc": "application/vnd.sun.xml.calc", + ".stc": "application/vnd.sun.xml.calc.template", + ".sxd": "application/vnd.sun.xml.draw", + ".std": "application/vnd.sun.xml.draw.template", + ".sxi": "application/vnd.sun.xml.impress", + ".sti": "application/vnd.sun.xml.impress.template", + ".sxm": "application/vnd.sun.xml.math", + ".sxw": "application/vnd.sun.xml.writer", + ".sxg": "application/vnd.sun.xml.writer.global", + ".stw": "application/vnd.sun.xml.writer.template", + ".sis": "application/vnd.symbian.install", + ".mms": "application/vnd.wap.mms-message", + ".anx": "application/x-annodex", + ".bcpio": "application/x-bcpio", + ".torrent": "application/x-bittorrent", + ".bz2": "application/x-bzip2", + ".vcd": "application/x-cdlink", + ".crx": "application/x-chrome-extension", + ".cpio": "application/x-cpio", + ".csh": "application/x-csh", + ".dcr": "application/x-director", + ".dir": "application/x-director", + ".dxr": "application/x-director", + ".dvi": "application/x-dvi", + ".spl": "application/x-futuresplash", + ".gtar": "application/x-gtar", + ".hdf": "application/x-hdf", + ".jar": "application/x-java-archive", + ".jnlp": "application/x-java-jnlp-file", + ".pack": "application/x-java-pack200", + ".kil": "application/x-killustrator", + ".latex": "application/x-latex", + ".nc": "application/x-netcdf", + ".cdf": "application/x-netcdf", + ".pl": "application/x-perl", + ".rpm": "application/x-rpm", + ".sh": "application/x-sh", + ".shar": "application/x-shar", + ".sit": "application/x-stuffit", + ".sv4cpio": "application/x-sv4cpio", + ".sv4crc": "application/x-sv4crc", + ".tar": "application/x-tar", + ".tcl": "application/x-tcl", + ".tex": "application/x-tex", + ".texinfo": "application/x-texinfo", + ".texi": "application/x-texinfo", + ".man": "application/x-troff-man", + ".1": "application/x-troff-man", + ".2": "application/x-troff-man", + ".3": "application/x-troff-man", + ".4": "application/x-troff-man", + ".5": "application/x-troff-man", + ".6": "application/x-troff-man", + ".7": "application/x-troff-man", + ".8": "application/x-troff-man", + ".me": "application/x-troff-me", + ".ms": "application/x-troff-ms", + ".ustar": "application/x-ustar", + ".src": "application/x-wais-source", + ".xpi": "application/x-xpinstall", + ".xspf": "application/x-xspf+xml", + ".xz": "application/x-xz", + ".mid": "audio/midi", + ".midi": "audio/midi", + ".kar": "audio/midi", + ".aif": "audio/x-aiff", + ".aiff": "audio/x-aiff", + ".aifc": "audio/x-aiff", + ".axa": "audio/x-annodex", + ".flac": "audio/x-flac", + ".mka": "audio/x-matroska", + ".mod": "audio/x-mod", + ".ult": "audio/x-mod", + ".uni": "audio/x-mod", + ".m15": "audio/x-mod", + ".mtm": "audio/x-mod", + ".669": "audio/x-mod", + ".med": "audio/x-mod", + ".m3u": "audio/x-mpegurl", + ".wax": "audio/x-ms-wax", + ".wma": "audio/x-ms-wma", + ".ram": "audio/x-pn-realaudio", + ".rm": "audio/x-pn-realaudio", + ".ra": "audio/x-realaudio", + ".s3m": "audio/x-s3m", + ".stm": "audio/x-stm", + ".wav": "audio/x-wav", + ".xyz": "chemical/x-xyz", + ".webp": "image/webp", + ".ras": "image/x-cmu-raster", + ".pnm": "image/x-portable-anymap", + ".pbm": "image/x-portable-bitmap", + ".pgm": "image/x-portable-graymap", + ".ppm": "image/x-portable-pixmap", + ".rgb": "image/x-rgb", + ".tga": "image/x-targa", + ".xbm": "image/x-xbitmap", + ".xpm": "image/x-xpixmap", + ".xwd": "image/x-xwindowdump", + ".sandboxed": "text/html-sandboxed", + ".pod": "text/x-pod", + ".etx": "text/x-setext", + ".webm": "video/webm", + ".axv": "video/x-annodex", + ".flv": "video/x-flv", + ".fxm": "video/x-javafx", + ".mkv": "video/x-matroska", + ".mk3d": "video/x-matroska-3d", + ".asx": "video/x-ms-asf", + ".wm": "video/x-ms-wm", + ".wmv": "video/x-ms-wmv", + ".wmx": "video/x-ms-wmx", + ".wvx": "video/x-ms-wvx", + ".avi": "video/x-msvideo", + ".movie": "video/x-sgi-movie", + ".ice": "x-conference/x-cooltalk", + ".sisx": "x-epoc/x-sisx-app", + } + for ext, name := range mimeTypes { + if err := mime.AddExtensionType(ext, name); err != nil { + panic(err) + } + } +} diff --git a/swarm/api/http/error.go b/swarm/api/http/error.go deleted file mode 100644 index dbd97182fd..0000000000 --- a/swarm/api/http/error.go +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright 2017 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 . - -/* -Show nicely (but simple) formatted HTML error pages (or respond with JSON -if the appropriate `Accept` header is set)) for the http package. -*/ -package http - -import ( - "encoding/json" - "fmt" - "html/template" - "net/http" - "strings" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/swarm/api" -) - -//templateMap holds a mapping of an HTTP error code to a template -var templateMap map[int]*template.Template - -//parameters needed for formatting the correct HTML page -type ErrorParams struct { - Msg string - Code int - Timestamp string - template *template.Template - Details template.HTML -} - -//we init the error handling right on boot time, so lookup and http response is fast -func init() { - initErrHandling() -} - -func initErrHandling() { - //pages are saved as strings - get these strings - genErrPage := GetGenericErrorPage() - notFoundPage := GetNotFoundErrorPage() - multipleChoicesPage := GetMultipleChoicesErrorPage() - //map the codes to the available pages - tnames := map[int]string{ - 0: genErrPage, //default - http.StatusBadRequest: genErrPage, - http.StatusNotFound: notFoundPage, - http.StatusMultipleChoices: multipleChoicesPage, - http.StatusInternalServerError: genErrPage, - } - templateMap = make(map[int]*template.Template) - for code, tname := range tnames { - //assign formatted HTML to the code - templateMap[code] = template.Must(template.New(fmt.Sprintf("%d", code)).Parse(tname)) - } -} - -//ShowMultipeChoices is used when a user requests a resource in a manifest which results -//in ambiguous results. It returns a HTML page with clickable links of each of the entry -//in the manifest which fits the request URI ambiguity. -//For example, if the user requests bzz://read and that manifest contains entries -//"readme.md" and "readinglist.txt", a HTML page is returned with this two links. -//This only applies if the manifest has no default entry -func ShowMultipleChoices(w http.ResponseWriter, r *http.Request, list api.ManifestList) { - msg := "" - if list.Entries == nil { - ShowError(w, r, "Internal Server Error", http.StatusInternalServerError) - return - } - //make links relative - //requestURI comes with the prefix of the ambiguous path, e.g. "read" for "readme.md" and "readinglist.txt" - //to get clickable links, need to remove the ambiguous path, i.e. "read" - idx := strings.LastIndex(r.RequestURI, "/") - if idx == -1 { - ShowError(w, r, "Internal Server Error", http.StatusInternalServerError) - return - } - //remove ambiguous part - base := r.RequestURI[:idx+1] - for _, e := range list.Entries { - //create clickable link for each entry - msg += "" + e.Path + "
" - } - respond(w, r, &ErrorParams{ - Code: http.StatusMultipleChoices, - Details: template.HTML(msg), - Timestamp: time.Now().Format(time.RFC1123), - template: getTemplate(http.StatusMultipleChoices), - }) -} - -//ShowError is used to show an HTML error page to a client. -//If there is an `Accept` header of `application/json`, JSON will be returned instead -//The function just takes a string message which will be displayed in the error page. -//The code is used to evaluate which template will be displayed -//(and return the correct HTTP status code) -func ShowError(w http.ResponseWriter, r *http.Request, msg string, code int) { - if code == http.StatusInternalServerError { - log.Error(msg) - } - respond(w, r, &ErrorParams{ - Code: code, - Msg: msg, - Timestamp: time.Now().Format(time.RFC1123), - template: getTemplate(code), - }) -} - -//evaluate if client accepts html or json response -func respond(w http.ResponseWriter, r *http.Request, params *ErrorParams) { - w.WriteHeader(params.Code) - if r.Header.Get("Accept") == "application/json" { - respondJson(w, params) - } else { - respondHtml(w, params) - } -} - -//return a HTML page -func respondHtml(w http.ResponseWriter, params *ErrorParams) { - err := params.template.Execute(w, params) - if err != nil { - log.Error(err.Error()) - } -} - -//return JSON -func respondJson(w http.ResponseWriter, params *ErrorParams) { - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(params) -} - -//get the HTML template for a given code -func getTemplate(code int) *template.Template { - if val, tmpl := templateMap[code]; tmpl { - return val - } else { - return templateMap[0] - } -} diff --git a/swarm/api/http/error_templates.go b/swarm/api/http/error_templates.go deleted file mode 100644 index 2c20ba8f99..0000000000 --- a/swarm/api/http/error_templates.go +++ /dev/null @@ -1,553 +0,0 @@ -// Copyright 2017 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 . - -/* -We use html templates to handle simple but as informative as possible error pages. - -To eliminate circular dependency in case of an error, we don't store error pages on swarm. -We can't save the error pages as html files on disk, or when deploying compiled binaries -they won't be found. - -For this reason we resort to save the HTML error pages as strings, which then can be -parsed by Go's html/template package -*/ -package http - -//This returns the HTML for generic errors -func GetGenericErrorPage() string { - page := ` - - - - - - - - - - - - Swarm::HTTP Error Page - - - - -
- -
-
- -
-
-

There was a problem serving the requested page

-
-
-
{{.Timestamp}}
-
-
- - -
- - - - - - - - - - - - - - - - - - - - -
- Hmmmmm....Swarm was not able to serve your request! -
- Error message: -
- {{.Msg}} -
- Error code: -
- {{.Code}} -
-
-
- -
-

- Swarm: Serverless Hosting Incentivised Peer-To-Peer Storage And Content Distribution
- Swarm -

-
- - -
- - - -` - return page -} - -//This returns the HTML for a 404 Not Found error -func GetNotFoundErrorPage() string { - page := ` - - - - - - - - - - - - Swarm::404 HTTP Not Found - - - - -
- -
-
- -
-
-

Resource Not Found

-
-
-
{{.Timestamp}}
-
-
- - -
- - - - - - - - - - - - - - - - - - - - -
- Unfortunately, the resource you were trying to access could not be found on swarm. -
-
- {{.Msg}} -
- Error code: -
- {{.Code}} -
-
-
- -
-

- Swarm: Serverless Hosting Incentivised Peer-To-Peer Storage And Content Distribution
- Swarm -

-
- - -
- - - -` - return page -} - -//This returns the HTML for a page listing disambiguation options -//i.e. if user requested bzz://read and the manifest contains "readme.md" and "readinglist.txt", -//this page is returned with a clickable list the existing disambiguation links in the manifest -func GetMultipleChoicesErrorPage() string { - page := ` - - - - - - - - - - - - Swarm::HTTP Disambiguation Page - - - - -
- -
-
- -
-
-

Swarm: disambiguation

-
-
-
{{.Timestamp}}
-
-
- - -
- - - - - - - - - - - - - - - - - - - - -
- Your request yields ambiguous results! -
- Your request may refer to: -
- {{ .Details}} -
- Error code: -
- {{.Code}} -
-
-
- -
-

- Swarm: Serverless Hosting Incentivised Peer-To-Peer Storage And Content Distribution
- Swarm -

-
- - -
- - - -` - return page -} diff --git a/swarm/api/http/middleware.go b/swarm/api/http/middleware.go new file mode 100644 index 0000000000..320da30462 --- /dev/null +++ b/swarm/api/http/middleware.go @@ -0,0 +1,113 @@ +package http + +import ( + "fmt" + "net/http" + "runtime/debug" + "strings" + "time" + + "github.com/ethereum/go-ethereum/metrics" + "github.com/ethereum/go-ethereum/swarm/api" + "github.com/ethereum/go-ethereum/swarm/log" + "github.com/ethereum/go-ethereum/swarm/sctx" + "github.com/ethereum/go-ethereum/swarm/spancontext" + "github.com/pborman/uuid" +) + +// Adapt chains h (main request handler) main handler to adapters (middleware handlers) +// Please note that the order of execution for `adapters` is FIFO (adapters[0] will be executed first) +func Adapt(h http.Handler, adapters ...Adapter) http.Handler { + for i := range adapters { + adapter := adapters[len(adapters)-1-i] + h = adapter(h) + } + return h +} + +type Adapter func(http.Handler) http.Handler + +func SetRequestID(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + r = r.WithContext(SetRUID(r.Context(), uuid.New()[:8])) + metrics.GetOrRegisterCounter(fmt.Sprintf("http.request.%s", r.Method), nil).Inc(1) + log.Info("created ruid for request", "ruid", GetRUID(r.Context()), "method", r.Method, "url", r.RequestURI) + + h.ServeHTTP(w, r) + }) +} + +func SetRequestHost(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + r = r.WithContext(sctx.SetHost(r.Context(), r.Host)) + log.Info("setting request host", "ruid", GetRUID(r.Context()), "host", sctx.GetHost(r.Context())) + + h.ServeHTTP(w, r) + }) +} + +func ParseURI(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + uri, err := api.Parse(strings.TrimLeft(r.URL.Path, "/")) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + respondError(w, r, fmt.Sprintf("invalid URI %q", r.URL.Path), http.StatusBadRequest) + return + } + if uri.Addr != "" && strings.HasPrefix(uri.Addr, "0x") { + uri.Addr = strings.TrimPrefix(uri.Addr, "0x") + + msg := fmt.Sprintf(`The requested hash seems to be prefixed with '0x'. You will be redirected to the correct URL within 5 seconds.
+ Please click here if your browser does not redirect you within 5 seconds.`, "/"+uri.String()) + w.WriteHeader(http.StatusNotFound) + w.Write([]byte(msg)) + return + } + + ctx := r.Context() + r = r.WithContext(SetURI(ctx, uri)) + log.Debug("parsed request path", "ruid", GetRUID(r.Context()), "method", r.Method, "uri.Addr", uri.Addr, "uri.Path", uri.Path, "uri.Scheme", uri.Scheme) + + h.ServeHTTP(w, r) + }) +} + +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) + + 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) + }) +} + +func InstrumentOpenTracing(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + uri := GetURI(r.Context()) + if uri == nil || r.Method == "" || (uri != nil && uri.Scheme == "") { + h.ServeHTTP(w, r) // soft fail + return + } + 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)) + }) +} + +func RecoverPanic(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + defer func() { + if err := recover(); err != nil { + log.Error("panic recovery!", "stack trace", string(debug.Stack()), "url", r.URL.String(), "headers", r.Header) + } + }() + h.ServeHTTP(w, r) + }) +} diff --git a/swarm/api/http/response.go b/swarm/api/http/response.go new file mode 100644 index 0000000000..d4e81d7f67 --- /dev/null +++ b/swarm/api/http/response.go @@ -0,0 +1,132 @@ +// Copyright 2017 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 http + +import ( + "encoding/json" + "fmt" + "html/template" + "net/http" + "strings" + "time" + + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" + "github.com/ethereum/go-ethereum/swarm/api" +) + +var ( + htmlCounter = metrics.NewRegisteredCounter("api.http.errorpage.html.count", nil) + jsonCounter = metrics.NewRegisteredCounter("api.http.errorpage.json.count", nil) + plaintextCounter = metrics.NewRegisteredCounter("api.http.errorpage.plaintext.count", nil) +) + +type ResponseParams struct { + Msg template.HTML + Code int + Timestamp string + template *template.Template + Details template.HTML +} + +// ShowMultipleChoices is used when a user requests a resource in a manifest which results +// in ambiguous results. It returns a HTML page with clickable links of each of the entry +// in the manifest which fits the request URI ambiguity. +// For example, if the user requests bzz://read and that manifest contains entries +// "readme.md" and "readinglist.txt", a HTML page is returned with this two links. +// This only applies if the manifest has no default entry +func ShowMultipleChoices(w http.ResponseWriter, r *http.Request, list api.ManifestList) { + log.Debug("ShowMultipleChoices", "ruid", GetRUID(r.Context()), "uri", GetURI(r.Context())) + msg := "" + if list.Entries == nil { + respondError(w, r, "Could not resolve", http.StatusInternalServerError) + return + } + requestUri := strings.TrimPrefix(r.RequestURI, "/") + + uri, err := api.Parse(requestUri) + if err != nil { + respondError(w, r, "Bad Request", http.StatusBadRequest) + } + + uri.Scheme = "bzz-list" + msg += fmt.Sprintf("Disambiguation:
Your request may refer to multiple choices.
Click here if your browser does not redirect you within 5 seconds.
", "/"+uri.String()) + respondTemplate(w, r, "error", msg, http.StatusMultipleChoices) +} + +func respondTemplate(w http.ResponseWriter, r *http.Request, templateName, msg string, code int) { + log.Debug("respondTemplate", "ruid", GetRUID(r.Context()), "uri", GetURI(r.Context())) + respond(w, r, &ResponseParams{ + Code: code, + Msg: template.HTML(msg), + Timestamp: time.Now().Format(time.RFC1123), + template: TemplatesMap[templateName], + }) +} + +func respondError(w http.ResponseWriter, r *http.Request, msg string, code int) { + log.Info("respondError", "ruid", GetRUID(r.Context()), "uri", GetURI(r.Context()), "code", code) + respondTemplate(w, r, "error", msg, code) +} + +func respond(w http.ResponseWriter, r *http.Request, params *ResponseParams) { + w.WriteHeader(params.Code) + + if params.Code >= 400 { + w.Header().Del("Cache-Control") + w.Header().Del("ETag") + } + + acceptHeader := r.Header.Get("Accept") + // this cannot be in a switch since an Accept header can have multiple values: "Accept: */*, text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8" + if strings.Contains(acceptHeader, "application/json") { + if err := respondJSON(w, r, params); err != nil { + respondError(w, r, "Internal server error", http.StatusInternalServerError) + } + } else if strings.Contains(acceptHeader, "text/html") { + respondHTML(w, r, params) + } else { + respondPlaintext(w, r, params) //returns nice errors for curl + } +} + +func respondHTML(w http.ResponseWriter, r *http.Request, params *ResponseParams) { + htmlCounter.Inc(1) + log.Info("respondHTML", "ruid", GetRUID(r.Context()), "code", params.Code) + err := params.template.Execute(w, params) + if err != nil { + log.Error(err.Error()) + } +} + +func respondJSON(w http.ResponseWriter, r *http.Request, params *ResponseParams) error { + jsonCounter.Inc(1) + log.Info("respondJSON", "ruid", GetRUID(r.Context()), "code", params.Code) + w.Header().Set("Content-Type", "application/json") + return json.NewEncoder(w).Encode(params) +} + +func respondPlaintext(w http.ResponseWriter, r *http.Request, params *ResponseParams) error { + plaintextCounter.Inc(1) + log.Info("respondPlaintext", "ruid", GetRUID(r.Context()), "code", params.Code) + w.Header().Set("Content-Type", "text/plain") + strToWrite := "Code: " + fmt.Sprintf("%d", params.Code) + "\n" + strToWrite += "Message: " + string(params.Msg) + "\n" + strToWrite += "Timestamp: " + params.Timestamp + "\n" + _, err := w.Write([]byte(strToWrite)) + return err +} diff --git a/swarm/api/http/error_test.go b/swarm/api/http/response_test.go similarity index 72% rename from swarm/api/http/error_test.go rename to swarm/api/http/response_test.go index ed52bafbd2..486c19ab0e 100644 --- a/swarm/api/http/error_test.go +++ b/swarm/api/http/response_test.go @@ -1,4 +1,4 @@ -// Copyright 2016 The go-ethereum Authors +// Copyright 2017 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,22 +14,20 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package http_test +package http import ( "encoding/json" - "golang.org/x/net/html" "io/ioutil" "net/http" "strings" "testing" - "github.com/ethereum/go-ethereum/swarm/testutil" + "golang.org/x/net/html" ) func TestError(t *testing.T) { - - srv := testutil.NewTestSwarmServer(t) + srv := NewTestSwarmServer(t, serverFunc, nil) defer srv.Close() var resp *http.Response @@ -44,7 +42,7 @@ func TestError(t *testing.T) { defer resp.Body.Close() respbody, err = ioutil.ReadAll(resp.Body) - if resp.StatusCode != 400 && !strings.Contains(string(respbody), "Invalid URI "/this_should_fail_as_no_bzz_protocol_present": unknown scheme") { + if resp.StatusCode != 404 && !strings.Contains(string(respbody), "Invalid URI "/this_should_fail_as_no_bzz_protocol_present": unknown scheme") { t.Fatalf("Response body does not match, expected: %v, to contain: %v; received code %d, expected code: %d", string(respbody), "Invalid bzz URI: unknown scheme", 400, resp.StatusCode) } @@ -55,7 +53,7 @@ func TestError(t *testing.T) { } func Test404Page(t *testing.T) { - srv := testutil.NewTestSwarmServer(t) + srv := NewTestSwarmServer(t, serverFunc, nil) defer srv.Close() var resp *http.Response @@ -81,7 +79,7 @@ func Test404Page(t *testing.T) { } func Test500Page(t *testing.T) { - srv := testutil.NewTestSwarmServer(t) + srv := NewTestSwarmServer(t, serverFunc, nil) defer srv.Close() var resp *http.Response @@ -96,8 +94,37 @@ func Test500Page(t *testing.T) { defer resp.Body.Close() respbody, err = ioutil.ReadAll(resp.Body) - if resp.StatusCode != 500 || !strings.Contains(string(respbody), "500") { - t.Fatalf("Invalid Status Code received, expected 500, got %d", resp.StatusCode) + if resp.StatusCode != 404 { + t.Fatalf("Invalid Status Code received, expected 404, got %d", resp.StatusCode) + } + + _, err = html.Parse(strings.NewReader(string(respbody))) + if err != nil { + t.Fatalf("HTML validation failed for error page returned!") + } +} +func Test500PageWith0xHashPrefix(t *testing.T) { + srv := NewTestSwarmServer(t, serverFunc, nil) + defer srv.Close() + + var resp *http.Response + var respbody []byte + + url := srv.URL + "/bzz:/0xthisShouldFailWith500CodeAndAHelpfulMessage" + resp, err := http.Get(url) + + if err != nil { + t.Fatalf("Request failed: %v", err) + } + defer resp.Body.Close() + respbody, err = ioutil.ReadAll(resp.Body) + + if resp.StatusCode != 404 { + t.Fatalf("Invalid Status Code received, expected 404, got %d", resp.StatusCode) + } + + if !strings.Contains(string(respbody), "The requested hash seems to be prefixed with") { + t.Fatalf("Did not receive the expected error message") } _, err = html.Parse(strings.NewReader(string(respbody))) @@ -107,7 +134,7 @@ func Test500Page(t *testing.T) { } func TestJsonResponse(t *testing.T) { - srv := testutil.NewTestSwarmServer(t) + srv := NewTestSwarmServer(t, serverFunc, nil) defer srv.Close() var resp *http.Response @@ -127,8 +154,8 @@ func TestJsonResponse(t *testing.T) { defer resp.Body.Close() respbody, err = ioutil.ReadAll(resp.Body) - if resp.StatusCode != 500 { - t.Fatalf("Invalid Status Code received, expected 500, got %d", resp.StatusCode) + if resp.StatusCode != 404 { + t.Fatalf("Invalid Status Code received, expected 404, got %d", resp.StatusCode) } if !isJSON(string(respbody)) { diff --git a/swarm/api/http/roundtripper.go b/swarm/api/http/roundtripper.go index 0194317716..be8ea39856 100644 --- a/swarm/api/http/roundtripper.go +++ b/swarm/api/http/roundtripper.go @@ -20,7 +20,7 @@ import ( "fmt" "net/http" - "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/swarm/log" ) /* diff --git a/swarm/api/http/sctx.go b/swarm/api/http/sctx.go new file mode 100644 index 0000000000..b8dafab0b7 --- /dev/null +++ b/swarm/api/http/sctx.go @@ -0,0 +1,34 @@ +package http + +import ( + "context" + + "github.com/ethereum/go-ethereum/swarm/api" + "github.com/ethereum/go-ethereum/swarm/sctx" +) + +type uriKey struct{} + +func GetRUID(ctx context.Context) string { + v, ok := ctx.Value(sctx.HTTPRequestIDKey{}).(string) + if ok { + return v + } + return "xxxxxxxx" +} + +func SetRUID(ctx context.Context, ruid string) context.Context { + return context.WithValue(ctx, sctx.HTTPRequestIDKey{}, ruid) +} + +func GetURI(ctx context.Context) *api.URI { + v, ok := ctx.Value(uriKey{}).(*api.URI) + if ok { + return v + } + return nil +} + +func SetURI(ctx context.Context, uri *api.URI) context.Context { + return context.WithValue(ctx, uriKey{}, uri) +} diff --git a/swarm/api/http/server.go b/swarm/api/http/server.go index 74341899d2..3c6735a73e 100644 --- a/swarm/api/http/server.go +++ b/swarm/api/http/server.go @@ -20,9 +20,9 @@ A simple http server interface to Swarm package http import ( - "archive/tar" + "bufio" + "bytes" "encoding/json" - "errors" "fmt" "io" "io/ioutil" @@ -36,114 +36,291 @@ import ( "time" "github.com/ethereum/go-ethereum/common" - "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/log" "github.com/ethereum/go-ethereum/swarm/storage" + "github.com/ethereum/go-ethereum/swarm/storage/feed" "github.com/rs/cors" ) -// ServerConfig is the basic configuration needed for the HTTP server and also -// includes CORS settings. -type ServerConfig struct { - Addr string - CorsString string +var ( + postRawCount = metrics.NewRegisteredCounter("api.http.post.raw.count", nil) + postRawFail = metrics.NewRegisteredCounter("api.http.post.raw.fail", nil) + postFilesCount = metrics.NewRegisteredCounter("api.http.post.files.count", nil) + postFilesFail = metrics.NewRegisteredCounter("api.http.post.files.fail", nil) + deleteCount = metrics.NewRegisteredCounter("api.http.delete.count", nil) + deleteFail = metrics.NewRegisteredCounter("api.http.delete.fail", nil) + getCount = metrics.NewRegisteredCounter("api.http.get.count", nil) + getFail = metrics.NewRegisteredCounter("api.http.get.fail", nil) + getFileCount = metrics.NewRegisteredCounter("api.http.get.file.count", nil) + getFileNotFound = metrics.NewRegisteredCounter("api.http.get.file.notfound", nil) + getFileFail = metrics.NewRegisteredCounter("api.http.get.file.fail", nil) + getListCount = metrics.NewRegisteredCounter("api.http.get.list.count", nil) + getListFail = metrics.NewRegisteredCounter("api.http.get.list.fail", nil) +) + +type methodHandler map[string]http.Handler + +func (m methodHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) { + v, ok := m[r.Method] + if ok { + v.ServeHTTP(rw, r) + return + } + rw.WriteHeader(http.StatusMethodNotAllowed) +} + +func NewServer(api *api.API, corsString string) *Server { + var allowedOrigins []string + for _, domain := range strings.Split(corsString, ",") { + allowedOrigins = append(allowedOrigins, strings.TrimSpace(domain)) + } + c := cors.New(cors.Options{ + AllowedOrigins: allowedOrigins, + AllowedMethods: []string{http.MethodPost, http.MethodGet, http.MethodDelete, http.MethodPatch, http.MethodPut}, + MaxAge: 600, + AllowedHeaders: []string{"*"}, + }) + + server := &Server{api: api} + + defaultMiddlewares := []Adapter{ + RecoverPanic, + SetRequestID, + SetRequestHost, + InitLoggingResponseWriter, + ParseURI, + InstrumentOpenTracing, + } + + mux := http.NewServeMux() + mux.Handle("/bzz:/", methodHandler{ + "GET": Adapt( + http.HandlerFunc(server.HandleBzzGet), + defaultMiddlewares..., + ), + "POST": Adapt( + http.HandlerFunc(server.HandlePostFiles), + defaultMiddlewares..., + ), + "DELETE": Adapt( + http.HandlerFunc(server.HandleDelete), + defaultMiddlewares..., + ), + }) + mux.Handle("/bzz-raw:/", methodHandler{ + "GET": Adapt( + http.HandlerFunc(server.HandleGet), + defaultMiddlewares..., + ), + "POST": Adapt( + http.HandlerFunc(server.HandlePostRaw), + defaultMiddlewares..., + ), + }) + mux.Handle("/bzz-immutable:/", methodHandler{ + "GET": Adapt( + http.HandlerFunc(server.HandleBzzGet), + defaultMiddlewares..., + ), + }) + mux.Handle("/bzz-hash:/", methodHandler{ + "GET": Adapt( + http.HandlerFunc(server.HandleGet), + defaultMiddlewares..., + ), + }) + mux.Handle("/bzz-list:/", methodHandler{ + "GET": Adapt( + http.HandlerFunc(server.HandleGetList), + defaultMiddlewares..., + ), + }) + mux.Handle("/bzz-feed:/", methodHandler{ + "GET": Adapt( + http.HandlerFunc(server.HandleGetFeed), + defaultMiddlewares..., + ), + "POST": Adapt( + http.HandlerFunc(server.HandlePostFeed), + defaultMiddlewares..., + ), + }) + + mux.Handle("/", methodHandler{ + "GET": Adapt( + http.HandlerFunc(server.HandleRootPaths), + SetRequestID, + InitLoggingResponseWriter, + ), + }) + server.Handler = c.Handler(mux) + + return server +} + +func (s *Server) ListenAndServe(addr string) error { + s.listenAddr = addr + return http.ListenAndServe(addr, s) } // browser API for registering bzz url scheme handlers: // https://developer.mozilla.org/en/docs/Web-based_protocol_handlers // electron (chromium) api for registering bzz url scheme handlers: // https://github.com/atom/electron/blob/master/docs/api/protocol.md - -// starts up http server -func StartHttpServer(api *api.Api, config *ServerConfig) { - var allowedOrigins []string - for _, domain := range strings.Split(config.CorsString, ",") { - allowedOrigins = append(allowedOrigins, strings.TrimSpace(domain)) - } - c := cors.New(cors.Options{ - AllowedOrigins: allowedOrigins, - AllowedMethods: []string{"POST", "GET", "DELETE", "PATCH", "PUT"}, - MaxAge: 600, - AllowedHeaders: []string{"*"}, - }) - hdlr := c.Handler(NewServer(api)) - - go http.ListenAndServe(config.Addr, hdlr) -} - -func NewServer(api *api.Api) *Server { - return &Server{api} -} - type Server struct { - api *api.Api + http.Handler + api *api.API + listenAddr string } -// Request wraps http.Request and also includes the parsed bzz URI -type Request struct { - http.Request +func (s *Server) HandleBzzGet(w http.ResponseWriter, r *http.Request) { + log.Debug("handleBzzGet", "ruid", GetRUID(r.Context()), "uri", r.RequestURI) + if r.Header.Get("Accept") == "application/x-tar" { + uri := GetURI(r.Context()) + _, credentials, _ := r.BasicAuth() + reader, err := s.api.GetDirectoryTar(r.Context(), s.api.Decryptor(r.Context(), credentials), uri) + if err != nil { + if isDecryptError(err) { + w.Header().Set("WWW-Authenticate", fmt.Sprintf("Basic realm=%q", uri.Address().String())) + respondError(w, r, err.Error(), http.StatusUnauthorized) + return + } + respondError(w, r, fmt.Sprintf("Had an error building the tarball: %v", err), http.StatusInternalServerError) + return + } + defer reader.Close() - uri *api.URI + w.Header().Set("Content-Type", "application/x-tar") + + fileName := uri.Addr + if found := path.Base(uri.Path); found != "" && found != "." && found != "/" { + fileName = found + } + w.Header().Set("Content-Disposition", fmt.Sprintf("inline; filename=\"%s.tar\"", fileName)) + + w.WriteHeader(http.StatusOK) + io.Copy(w, reader) + return + } + + s.HandleGetFile(w, r) +} + +func (s *Server) HandleRootPaths(w http.ResponseWriter, r *http.Request) { + switch r.RequestURI { + case "/": + respondTemplate(w, r, "landing-page", "Swarm: Please request a valid ENS or swarm hash with the appropriate bzz scheme", 200) + return + case "/robots.txt": + w.Header().Set("Last-Modified", time.Now().Format(http.TimeFormat)) + fmt.Fprintf(w, "User-agent: *\nDisallow: /") + case "/favicon.ico": + w.WriteHeader(http.StatusOK) + w.Write(faviconBytes) + default: + respondError(w, r, "Not Found", http.StatusNotFound) + } } // HandlePostRaw handles a POST request to a raw bzz-raw:/ URI, stores the request -// body in swarm and returns the resulting storage key as a text/plain response -func (s *Server) HandlePostRaw(w http.ResponseWriter, r *Request) { - if r.uri.Path != "" { - s.BadRequest(w, r, "raw POST request cannot contain a path") +// body in swarm and returns the resulting storage address as a text/plain response +func (s *Server) HandlePostRaw(w http.ResponseWriter, r *http.Request) { + ruid := GetRUID(r.Context()) + log.Debug("handle.post.raw", "ruid", ruid) + + postRawCount.Inc(1) + + toEncrypt := false + uri := GetURI(r.Context()) + if uri.Addr == "encrypt" { + toEncrypt = true + } + + if uri.Path != "" { + postRawFail.Inc(1) + respondError(w, r, "raw POST request cannot contain a path", http.StatusBadRequest) + return + } + + if uri.Addr != "" && uri.Addr != "encrypt" { + postRawFail.Inc(1) + respondError(w, r, "raw POST request addr can only be empty or \"encrypt\"", http.StatusBadRequest) return } if r.Header.Get("Content-Length") == "" { - s.BadRequest(w, r, "missing Content-Length header in request") + postRawFail.Inc(1) + respondError(w, r, "missing Content-Length header in request", http.StatusBadRequest) return } - key, err := s.api.Store(r.Body, r.ContentLength, nil) + addr, _, err := s.api.Store(r.Context(), r.Body, r.ContentLength, toEncrypt) if err != nil { - s.Error(w, r, err) + postRawFail.Inc(1) + respondError(w, r, err.Error(), http.StatusInternalServerError) return } - s.logDebug("content for %s stored", key.Log()) + + log.Debug("stored content", "ruid", ruid, "key", addr) w.Header().Set("Content-Type", "text/plain") w.WriteHeader(http.StatusOK) - fmt.Fprint(w, key) + fmt.Fprint(w, addr) } -// HandlePostFiles handles a POST request (or deprecated PUT request) to +// HandlePostFiles handles a POST request to // bzz:// which contains either a single file or multiple files // (either a tar archive or multipart form), adds those files either to an // existing manifest or to a new manifest under and returns the // resulting manifest hash as a text/plain response -func (s *Server) HandlePostFiles(w http.ResponseWriter, r *Request) { +func (s *Server) HandlePostFiles(w http.ResponseWriter, r *http.Request) { + ruid := GetRUID(r.Context()) + log.Debug("handle.post.files", "ruid", ruid) + postFilesCount.Inc(1) + contentType, params, err := mime.ParseMediaType(r.Header.Get("Content-Type")) if err != nil { - s.BadRequest(w, r, err.Error()) + postFilesFail.Inc(1) + respondError(w, r, err.Error(), http.StatusBadRequest) return } - var key storage.Key - if r.uri.Addr != "" { - key, err = s.api.Resolve(r.uri) - if err != nil { - s.Error(w, r, fmt.Errorf("error resolving %s: %s", r.uri.Addr, err)) - return - } - } else { - key, err = s.api.NewManifest() - if err != nil { - s.Error(w, r, err) - return - } + toEncrypt := false + uri := GetURI(r.Context()) + if uri.Addr == "encrypt" { + toEncrypt = true } - newKey, err := s.updateManifest(key, func(mw *api.ManifestWriter) error { + var addr storage.Address + if uri.Addr != "" && uri.Addr != "encrypt" { + addr, err = s.api.Resolve(r.Context(), uri.Addr) + if err != nil { + postFilesFail.Inc(1) + respondError(w, r, fmt.Sprintf("cannot resolve %s: %s", uri.Addr, err), http.StatusInternalServerError) + return + } + log.Debug("resolved key", "ruid", ruid, "key", addr) + } else { + addr, err = s.api.NewManifest(r.Context(), toEncrypt) + if err != nil { + postFilesFail.Inc(1) + respondError(w, r, err.Error(), http.StatusInternalServerError) + return + } + log.Debug("new manifest", "ruid", ruid, "key", addr) + } + + newAddr, err := s.api.UpdateManifest(r.Context(), addr, func(mw *api.ManifestWriter) error { switch contentType { - case "application/x-tar": - return s.handleTarUpload(r, mw) - + _, err := s.handleTarUpload(r, mw) + if err != nil { + respondError(w, r, fmt.Sprintf("error uploading tarball: %v", err), http.StatusInternalServerError) + return err + } + return nil case "multipart/form-data": return s.handleMultipartUpload(r, params["boundary"], mw) @@ -152,50 +329,34 @@ func (s *Server) HandlePostFiles(w http.ResponseWriter, r *Request) { } }) if err != nil { - s.Error(w, r, fmt.Errorf("error creating manifest: %s", err)) + postFilesFail.Inc(1) + respondError(w, r, fmt.Sprintf("cannot create manifest: %s", err), http.StatusInternalServerError) return } + log.Debug("stored content", "ruid", ruid, "key", newAddr) + w.Header().Set("Content-Type", "text/plain") w.WriteHeader(http.StatusOK) - fmt.Fprint(w, newKey) + fmt.Fprint(w, newAddr) } -func (s *Server) handleTarUpload(req *Request, mw *api.ManifestWriter) error { - tr := tar.NewReader(req.Body) - for { - hdr, err := tr.Next() - if err == io.EOF { - return nil - } else if err != nil { - return fmt.Errorf("error reading tar stream: %s", err) - } +func (s *Server) handleTarUpload(r *http.Request, mw *api.ManifestWriter) (storage.Address, error) { + log.Debug("handle.tar.upload", "ruid", GetRUID(r.Context())) - // only store regular files - if !hdr.FileInfo().Mode().IsRegular() { - continue - } + defaultPath := r.URL.Query().Get("defaultpath") - // add the entry under the path from the request - path := path.Join(req.uri.Path, hdr.Name) - entry := &api.ManifestEntry{ - Path: path, - ContentType: hdr.Xattrs["user.swarm.content-type"], - Mode: hdr.Mode, - Size: hdr.Size, - ModTime: hdr.ModTime, - } - s.logDebug("adding %s (%d bytes) to new manifest", entry.Path, entry.Size) - contentKey, err := mw.AddEntry(tr, entry) - if err != nil { - return fmt.Errorf("error adding manifest entry from tar stream: %s", err) - } - s.logDebug("content for %s stored", contentKey.Log()) + key, err := s.api.UploadTar(r.Context(), r.Body, GetURI(r.Context()).Path, defaultPath, mw) + if err != nil { + return nil, err } + return key, nil } -func (s *Server) handleMultipartUpload(req *Request, boundary string, mw *api.ManifestWriter) error { - mr := multipart.NewReader(req.Body, boundary) +func (s *Server) handleMultipartUpload(r *http.Request, boundary string, mw *api.ManifestWriter) error { + ruid := GetRUID(r.Context()) + log.Debug("handle.multipart.upload", "ruid", ruid) + mr := multipart.NewReader(r.Body, boundary) for { part, err := mr.NextPart() if err == io.EOF { @@ -205,7 +366,7 @@ func (s *Server) handleMultipartUpload(req *Request, boundary string, mw *api.Ma } var size int64 - var reader io.Reader = part + var reader io.Reader if contentLength := part.Header.Get("Content-Length"); contentLength != "" { size, err = strconv.ParseInt(contentLength, 10, 64) if err != nil { @@ -235,53 +396,50 @@ func (s *Server) handleMultipartUpload(req *Request, boundary string, mw *api.Ma if name == "" { name = part.FormName() } - path := path.Join(req.uri.Path, name) + uri := GetURI(r.Context()) + path := path.Join(uri.Path, name) entry := &api.ManifestEntry{ Path: path, ContentType: part.Header.Get("Content-Type"), Size: size, - ModTime: time.Now(), } - s.logDebug("adding %s (%d bytes) to new manifest", entry.Path, entry.Size) - contentKey, err := mw.AddEntry(reader, entry) + log.Debug("adding path to new manifest", "ruid", ruid, "bytes", entry.Size, "path", entry.Path) + contentKey, err := mw.AddEntry(r.Context(), reader, entry) if err != nil { return fmt.Errorf("error adding manifest entry from multipart form: %s", err) } - s.logDebug("content for %s stored", contentKey.Log()) + log.Debug("stored content", "ruid", ruid, "key", contentKey) } } -func (s *Server) handleDirectUpload(req *Request, mw *api.ManifestWriter) error { - key, err := mw.AddEntry(req.Body, &api.ManifestEntry{ - Path: req.uri.Path, - ContentType: req.Header.Get("Content-Type"), +func (s *Server) handleDirectUpload(r *http.Request, mw *api.ManifestWriter) error { + ruid := GetRUID(r.Context()) + log.Debug("handle.direct.upload", "ruid", ruid) + key, err := mw.AddEntry(r.Context(), r.Body, &api.ManifestEntry{ + Path: GetURI(r.Context()).Path, + ContentType: r.Header.Get("Content-Type"), Mode: 0644, - Size: req.ContentLength, - ModTime: time.Now(), + Size: r.ContentLength, }) if err != nil { return err } - s.logDebug("content for %s stored", key.Log()) + log.Debug("stored content", "ruid", ruid, "key", key) return nil } // HandleDelete handles a DELETE request to bzz://, removes // from and returns the resulting manifest hash as a // text/plain response -func (s *Server) HandleDelete(w http.ResponseWriter, r *Request) { - key, err := s.api.Resolve(r.uri) +func (s *Server) HandleDelete(w http.ResponseWriter, r *http.Request) { + ruid := GetRUID(r.Context()) + uri := GetURI(r.Context()) + log.Debug("handle.delete", "ruid", ruid) + deleteCount.Inc(1) + newKey, err := s.api.Delete(r.Context(), uri.Addr, uri.Path) if err != nil { - s.Error(w, r, fmt.Errorf("error resolving %s: %s", r.uri.Addr, err)) - return - } - - newKey, err := s.updateManifest(key, func(mw *api.ManifestWriter) error { - s.logDebug("removing %s from manifest %s", r.uri.Path, key.Log()) - return mw.RemoveEntry(r.uri.Path) - }) - if err != nil { - s.Error(w, r, fmt.Errorf("error updating manifest: %s", err)) + deleteFail.Inc(1) + respondError(w, r, fmt.Sprintf("could not delete from manifest: %v", err), http.StatusInternalServerError) return } @@ -290,170 +448,268 @@ func (s *Server) HandleDelete(w http.ResponseWriter, r *Request) { fmt.Fprint(w, newKey) } +// Handles feed manifest creation and feed updates +// The POST request admits a JSON structure as defined in the feeds package: `feed.updateRequestJSON` +// The requests can be to a) create a feed manifest, b) update a feed or c) both a+b: create a feed manifest and publish a first update +func (s *Server) HandlePostFeed(w http.ResponseWriter, r *http.Request) { + ruid := GetRUID(r.Context()) + uri := GetURI(r.Context()) + log.Debug("handle.post.feed", "ruid", ruid) + var err error + + // Creation and update must send feed.updateRequestJSON JSON structure + body, err := ioutil.ReadAll(r.Body) + if err != nil { + respondError(w, r, err.Error(), http.StatusInternalServerError) + return + } + + fd, err := s.api.ResolveFeed(r.Context(), uri, r.URL.Query()) + if err != nil { // couldn't parse query string or retrieve manifest + getFail.Inc(1) + httpStatus := http.StatusBadRequest + if err == api.ErrCannotLoadFeedManifest || err == api.ErrCannotResolveFeedURI { + httpStatus = http.StatusNotFound + } + respondError(w, r, fmt.Sprintf("cannot retrieve feed from manifest: %s", err), httpStatus) + return + } + + var updateRequest feed.Request + updateRequest.Feed = *fd + query := r.URL.Query() + + if err := updateRequest.FromValues(query, body); err != nil { // decodes request from query parameters + respondError(w, r, err.Error(), http.StatusBadRequest) + return + } + + switch { + case updateRequest.IsUpdate(): + // Verify that the signature is intact and that the signer is authorized + // to update this feed + // Check this early, to avoid creating a feed and then not being able to set its first update. + if err = updateRequest.Verify(); err != nil { + respondError(w, r, err.Error(), http.StatusForbidden) + return + } + _, err = s.api.FeedsUpdate(r.Context(), &updateRequest) + if err != nil { + respondError(w, r, err.Error(), http.StatusInternalServerError) + return + } + fallthrough + case query.Get("manifest") == "1": + // we create a manifest so we can retrieve feed updates with bzz:// later + // this manifest has a special "feed type" manifest, and saves the + // feed identification used to retrieve feed updates later + m, err := s.api.NewFeedManifest(r.Context(), &updateRequest.Feed) + if err != nil { + respondError(w, r, fmt.Sprintf("failed to create feed manifest: %v", err), http.StatusInternalServerError) + return + } + // the key to the manifest will be passed back to the client + // the client can access the feed directly through its Feed member + // the manifest key can be set as content in the resolver of the ENS name + outdata, err := json.Marshal(m) + if err != nil { + respondError(w, r, fmt.Sprintf("failed to create json response: %s", err), http.StatusInternalServerError) + return + } + fmt.Fprint(w, string(outdata)) + + w.Header().Add("Content-type", "application/json") + default: + respondError(w, r, "Missing signature in feed update request", http.StatusBadRequest) + } +} + +// HandleGetFeed retrieves Swarm feeds updates: +// bzz-feed:// - get latest feed update, given a manifest address +// - or - +// specify user + topic (optional), subtopic name (optional) directly, without manifest: +// bzz-feed://?user=0x...&topic=0x...&name=subtopic name +// topic defaults to 0x000... if not specified. +// name defaults to empty string if not specified. +// thus, empty name and topic refers to the user's default feed. +// +// Optional parameters: +// time=xx - get the latest update before time (in epoch seconds) +// hint.time=xx - hint the lookup algorithm looking for updates at around that time +// hint.level=xx - hint the lookup algorithm looking for updates at around this frequency level +// meta=1 - get feed metadata and status information instead of performing a feed query +// NOTE: meta=1 will be deprecated in the near future +func (s *Server) HandleGetFeed(w http.ResponseWriter, r *http.Request) { + ruid := GetRUID(r.Context()) + uri := GetURI(r.Context()) + log.Debug("handle.get.feed", "ruid", ruid) + var err error + + fd, err := s.api.ResolveFeed(r.Context(), uri, r.URL.Query()) + if err != nil { // couldn't parse query string or retrieve manifest + getFail.Inc(1) + httpStatus := http.StatusBadRequest + if err == api.ErrCannotLoadFeedManifest || err == api.ErrCannotResolveFeedURI { + httpStatus = http.StatusNotFound + } + respondError(w, r, fmt.Sprintf("cannot retrieve feed information from manifest: %s", err), httpStatus) + return + } + + // determine if the query specifies period and version or it is a metadata query + if r.URL.Query().Get("meta") == "1" { + unsignedUpdateRequest, err := s.api.FeedsNewRequest(r.Context(), fd) + if err != nil { + getFail.Inc(1) + respondError(w, r, fmt.Sprintf("cannot retrieve feed metadata for feed=%s: %s", fd.Hex(), err), http.StatusNotFound) + return + } + rawResponse, err := unsignedUpdateRequest.MarshalJSON() + if err != nil { + respondError(w, r, fmt.Sprintf("cannot encode unsigned feed update request: %v", err), http.StatusInternalServerError) + return + } + w.Header().Add("Content-type", "application/json") + w.WriteHeader(http.StatusOK) + fmt.Fprint(w, string(rawResponse)) + return + } + + lookupParams := &feed.Query{Feed: *fd} + if err = lookupParams.FromValues(r.URL.Query()); err != nil { // parse period, version + respondError(w, r, fmt.Sprintf("invalid feed update request:%s", err), http.StatusBadRequest) + return + } + + data, err := s.api.FeedsLookup(r.Context(), lookupParams) + + // any error from the switch statement will end up here + if err != nil { + code, err2 := s.translateFeedError(w, r, "feed lookup fail", err) + respondError(w, r, err2.Error(), code) + return + } + + // All ok, serve the retrieved update + log.Debug("Found update", "feed", fd.Hex(), "ruid", ruid) + w.Header().Set("Content-Type", api.MimeOctetStream) + http.ServeContent(w, r, "", time.Now(), bytes.NewReader(data)) +} + +func (s *Server) translateFeedError(w http.ResponseWriter, r *http.Request, supErr string, err error) (int, error) { + code := 0 + defaultErr := fmt.Errorf("%s: %v", supErr, err) + rsrcErr, ok := err.(*feed.Error) + if !ok && rsrcErr != nil { + code = rsrcErr.Code() + } + switch code { + case storage.ErrInvalidValue: + return http.StatusBadRequest, defaultErr + case storage.ErrNotFound, storage.ErrNotSynced, storage.ErrNothingToReturn, storage.ErrInit: + return http.StatusNotFound, defaultErr + case storage.ErrUnauthorized, storage.ErrInvalidSignature: + return http.StatusUnauthorized, defaultErr + case storage.ErrDataOverflow: + return http.StatusRequestEntityTooLarge, defaultErr + } + + return http.StatusInternalServerError, defaultErr +} + // HandleGet handles a GET request to // - bzz-raw:// and responds with the raw content stored at the // given storage key // - bzz-hash:// and responds with the hash of the content stored // at the given storage key as a text/plain response -func (s *Server) HandleGet(w http.ResponseWriter, r *Request) { - key, err := s.api.Resolve(r.uri) +func (s *Server) HandleGet(w http.ResponseWriter, r *http.Request) { + ruid := GetRUID(r.Context()) + uri := GetURI(r.Context()) + log.Debug("handle.get", "ruid", ruid, "uri", uri) + getCount.Inc(1) + _, pass, _ := r.BasicAuth() + + addr, err := s.api.ResolveURI(r.Context(), uri, pass) if err != nil { - s.Error(w, r, fmt.Errorf("error resolving %s: %s", r.uri.Addr, err)) + getFail.Inc(1) + respondError(w, r, fmt.Sprintf("cannot resolve %s: %s", uri.Addr, err), http.StatusNotFound) return } + w.Header().Set("Cache-Control", "max-age=2147483648, immutable") // url was of type bzz:///path, so we are sure it is immutable. + + log.Debug("handle.get: resolved", "ruid", ruid, "key", addr) // if path is set, interpret as a manifest and return the // raw entry at the given path - if r.uri.Path != "" { - walker, err := s.api.NewManifestWalker(key, nil) - if err != nil { - s.BadRequest(w, r, fmt.Sprintf("%s is not a manifest", key)) + + etag := common.Bytes2Hex(addr) + noneMatchEtag := r.Header.Get("If-None-Match") + w.Header().Set("ETag", fmt.Sprintf("%q", etag)) // set etag to manifest key or raw entry key. + if noneMatchEtag != "" { + if bytes.Equal(storage.Address(common.Hex2Bytes(noneMatchEtag)), addr) { + w.WriteHeader(http.StatusNotModified) return } - var entry *api.ManifestEntry - walker.Walk(func(e *api.ManifestEntry) error { - // if the entry matches the path, set entry and stop - // the walk - if e.Path == r.uri.Path { - entry = e - // return an error to cancel the walk - return errors.New("found") - } - - // ignore non-manifest files - if e.ContentType != api.ManifestType { - return nil - } - - // if the manifest's path is a prefix of the - // requested path, recurse into it by returning - // nil and continuing the walk - if strings.HasPrefix(r.uri.Path, e.Path) { - return nil - } - - return api.SkipManifest - }) - if entry == nil { - s.NotFound(w, r, fmt.Errorf("Manifest entry could not be loaded")) - return - } - key = storage.Key(common.Hex2Bytes(entry.Hash)) } // check the root chunk exists by retrieving the file's size - reader := s.api.Retrieve(key) - if _, err := reader.Size(nil); err != nil { - s.NotFound(w, r, fmt.Errorf("Root chunk not found %s: %s", key, err)) + reader, isEncrypted := s.api.Retrieve(r.Context(), addr) + if _, err := reader.Size(r.Context(), nil); err != nil { + getFail.Inc(1) + respondError(w, r, fmt.Sprintf("root chunk not found %s: %s", addr, err), http.StatusNotFound) return } + w.Header().Set("X-Decrypted", fmt.Sprintf("%v", isEncrypted)) + switch { - case r.uri.Raw(): + case uri.Raw(): // allow the request to overwrite the content type using a query // parameter - contentType := "application/octet-stream" if typ := r.URL.Query().Get("content_type"); typ != "" { - contentType = typ + w.Header().Set("Content-Type", typ) } - w.Header().Set("Content-Type", contentType) - - http.ServeContent(w, &r.Request, "", time.Now(), reader) - case r.uri.Hash(): + http.ServeContent(w, r, "", time.Now(), reader) + case uri.Hash(): w.Header().Set("Content-Type", "text/plain") w.WriteHeader(http.StatusOK) - fmt.Fprint(w, key) - } -} - -// HandleGetFiles handles a GET request to bzz:/ with an Accept -// header of "application/x-tar" and returns a tar stream of all files -// contained in the manifest -func (s *Server) HandleGetFiles(w http.ResponseWriter, r *Request) { - if r.uri.Path != "" { - s.BadRequest(w, r, "files request cannot contain a path") - return - } - - key, err := s.api.Resolve(r.uri) - if err != nil { - s.Error(w, r, fmt.Errorf("error resolving %s: %s", r.uri.Addr, err)) - return - } - - walker, err := s.api.NewManifestWalker(key, nil) - if err != nil { - s.Error(w, r, err) - return - } - - tw := tar.NewWriter(w) - defer tw.Close() - w.Header().Set("Content-Type", "application/x-tar") - w.WriteHeader(http.StatusOK) - - err = walker.Walk(func(entry *api.ManifestEntry) error { - // ignore manifests (walk will recurse into them) - if entry.ContentType == api.ManifestType { - return nil - } - - // retrieve the entry's key and size - reader := s.api.Retrieve(storage.Key(common.Hex2Bytes(entry.Hash))) - size, err := reader.Size(nil) - if err != nil { - return err - } - - // write a tar header for the entry - hdr := &tar.Header{ - Name: entry.Path, - Mode: entry.Mode, - Size: size, - ModTime: entry.ModTime, - Xattrs: map[string]string{ - "user.swarm.content-type": entry.ContentType, - }, - } - if err := tw.WriteHeader(hdr); err != nil { - return err - } - - // copy the file into the tar stream - n, err := io.Copy(tw, io.LimitReader(reader, hdr.Size)) - if err != nil { - return err - } else if n != size { - return fmt.Errorf("error writing %s: expected %d bytes but sent %d", entry.Path, size, n) - } - - return nil - }) - if err != nil { - s.logError("error generating tar stream: %s", err) + fmt.Fprint(w, addr) } } // HandleGetList handles a GET request to bzz-list:// and returns // a list of all files contained in under grouped into // common prefixes using "/" as a delimiter -func (s *Server) HandleGetList(w http.ResponseWriter, r *Request) { +func (s *Server) HandleGetList(w http.ResponseWriter, r *http.Request) { + ruid := GetRUID(r.Context()) + uri := GetURI(r.Context()) + _, credentials, _ := r.BasicAuth() + log.Debug("handle.get.list", "ruid", ruid, "uri", uri) + getListCount.Inc(1) + // ensure the root path has a trailing slash so that relative URLs work - if r.uri.Path == "" && !strings.HasSuffix(r.URL.Path, "/") { - http.Redirect(w, &r.Request, r.URL.Path+"/", http.StatusMovedPermanently) + if uri.Path == "" && !strings.HasSuffix(r.URL.Path, "/") { + http.Redirect(w, r, r.URL.Path+"/", http.StatusMovedPermanently) return } - key, err := s.api.Resolve(r.uri) + addr, err := s.api.Resolve(r.Context(), uri.Addr) if err != nil { - s.Error(w, r, fmt.Errorf("error resolving %s: %s", r.uri.Addr, err)) + getListFail.Inc(1) + respondError(w, r, fmt.Sprintf("cannot resolve %s: %s", uri.Addr, err), http.StatusNotFound) return } + log.Debug("handle.get.list: resolved", "ruid", ruid, "key", addr) - list, err := s.getManifestList(key, r.uri.Path) - + list, err := s.api.GetManifestList(r.Context(), s.api.Decryptor(r.Context(), credentials), addr, uri.Path) if err != nil { - s.Error(w, r, err) + getListFail.Inc(1) + if isDecryptError(err) { + w.Header().Set("WWW-Authenticate", fmt.Sprintf("Basic realm=%q", addr.String())) + respondError(w, r, err.Error(), http.StatusUnauthorized) + return + } + respondError(w, r, err.Error(), http.StatusInternalServerError) return } @@ -461,16 +717,17 @@ func (s *Server) HandleGetList(w http.ResponseWriter, r *Request) { // HTML index with relative URLs if strings.Contains(r.Header.Get("Accept"), "text/html") { w.Header().Set("Content-Type", "text/html") - err := htmlListTemplate.Execute(w, &htmlListData{ + err := TemplatesMap["bzz-list"].Execute(w, &htmlListData{ URI: &api.URI{ Scheme: "bzz", - Addr: r.uri.Addr, - Path: r.uri.Path, + Addr: uri.Addr, + Path: uri.Path, }, List: &list, }) if err != nil { - s.logError("error rendering list HTML: %s", err) + getListFail.Inc(1) + log.Error(fmt.Sprintf("error rendering list HTML: %s", err)) } return } @@ -479,84 +736,62 @@ func (s *Server) HandleGetList(w http.ResponseWriter, r *Request) { json.NewEncoder(w).Encode(&list) } -func (s *Server) getManifestList(key storage.Key, prefix string) (list api.ManifestList, err error) { - walker, err := s.api.NewManifestWalker(key, nil) - if err != nil { - return - } - - err = walker.Walk(func(entry *api.ManifestEntry) error { - // handle non-manifest files - if entry.ContentType != api.ManifestType { - // ignore the file if it doesn't have the specified prefix - if !strings.HasPrefix(entry.Path, prefix) { - return nil - } - - // if the path after the prefix contains a slash, add a - // common prefix to the list, otherwise add the entry - suffix := strings.TrimPrefix(entry.Path, prefix) - if index := strings.Index(suffix, "/"); index > -1 { - list.CommonPrefixes = append(list.CommonPrefixes, prefix+suffix[:index+1]) - return nil - } - if entry.Path == "" { - entry.Path = "/" - } - list.Entries = append(list.Entries, entry) - return nil - } - - // if the manifest's path is a prefix of the specified prefix - // then just recurse into the manifest by returning nil and - // continuing the walk - if strings.HasPrefix(prefix, entry.Path) { - return nil - } - - // if the manifest's path has the specified prefix, then if the - // path after the prefix contains a slash, add a common prefix - // to the list and skip the manifest, otherwise recurse into - // the manifest by returning nil and continuing the walk - if strings.HasPrefix(entry.Path, prefix) { - suffix := strings.TrimPrefix(entry.Path, prefix) - if index := strings.Index(suffix, "/"); index > -1 { - list.CommonPrefixes = append(list.CommonPrefixes, prefix+suffix[:index+1]) - return api.SkipManifest - } - return nil - } - - // the manifest neither has the prefix or needs recursing in to - // so just skip it - return api.SkipManifest - }) - - return list, nil -} - // HandleGetFile handles a GET request to bzz:/// and responds // with the content of the file at from the given -func (s *Server) HandleGetFile(w http.ResponseWriter, r *Request) { +func (s *Server) HandleGetFile(w http.ResponseWriter, r *http.Request) { + ruid := GetRUID(r.Context()) + uri := GetURI(r.Context()) + _, credentials, _ := r.BasicAuth() + log.Debug("handle.get.file", "ruid", ruid, "uri", r.RequestURI) + getFileCount.Inc(1) + // ensure the root path has a trailing slash so that relative URLs work - if r.uri.Path == "" && !strings.HasSuffix(r.URL.Path, "/") { - http.Redirect(w, &r.Request, r.URL.Path+"/", http.StatusMovedPermanently) + if uri.Path == "" && !strings.HasSuffix(r.URL.Path, "/") { + http.Redirect(w, r, r.URL.Path+"/", http.StatusMovedPermanently) return } + var err error + manifestAddr := uri.Address() - key, err := s.api.Resolve(r.uri) - if err != nil { - s.Error(w, r, fmt.Errorf("error resolving %s: %s", r.uri.Addr, err)) - return + if manifestAddr == nil { + manifestAddr, err = s.api.Resolve(r.Context(), uri.Addr) + if err != nil { + getFileFail.Inc(1) + respondError(w, r, fmt.Sprintf("cannot resolve %s: %s", uri.Addr, err), http.StatusNotFound) + return + } + } else { + w.Header().Set("Cache-Control", "max-age=2147483648, immutable") // url was of type bzz:///path, so we are sure it is immutable. + } + + log.Debug("handle.get.file: resolved", "ruid", ruid, "key", manifestAddr) + + reader, contentType, status, contentKey, err := s.api.Get(r.Context(), s.api.Decryptor(r.Context(), credentials), manifestAddr, uri.Path) + + etag := common.Bytes2Hex(contentKey) + noneMatchEtag := r.Header.Get("If-None-Match") + w.Header().Set("ETag", fmt.Sprintf("%q", etag)) // set etag to actual content key. + if noneMatchEtag != "" { + if bytes.Equal(storage.Address(common.Hex2Bytes(noneMatchEtag)), contentKey) { + w.WriteHeader(http.StatusNotModified) + return + } } - reader, contentType, status, err := s.api.Get(key, r.uri.Path) if err != nil { + if isDecryptError(err) { + w.Header().Set("WWW-Authenticate", fmt.Sprintf("Basic realm=%q", manifestAddr)) + respondError(w, r, err.Error(), http.StatusUnauthorized) + return + } + switch status { case http.StatusNotFound: - s.NotFound(w, r, err) + getFileNotFound.Inc(1) + respondError(w, r, err.Error(), http.StatusNotFound) default: - s.Error(w, r, err) + getFileFail.Inc(1) + respondError(w, r, err.Error(), http.StatusInternalServerError) } return } @@ -564,128 +799,89 @@ func (s *Server) HandleGetFile(w http.ResponseWriter, r *Request) { //the request results in ambiguous files //e.g. /read with readme.md and readinglist.txt available in manifest if status == http.StatusMultipleChoices { - list, err := s.getManifestList(key, r.uri.Path) - + list, err := s.api.GetManifestList(r.Context(), s.api.Decryptor(r.Context(), credentials), manifestAddr, uri.Path) if err != nil { - s.Error(w, r, err) + getFileFail.Inc(1) + if isDecryptError(err) { + w.Header().Set("WWW-Authenticate", fmt.Sprintf("Basic realm=%q", manifestAddr)) + respondError(w, r, err.Error(), http.StatusUnauthorized) + return + } + respondError(w, r, err.Error(), http.StatusInternalServerError) return } - s.logDebug(fmt.Sprintf("Multiple choices! --> %v", list)) + log.Debug(fmt.Sprintf("Multiple choices! --> %v", list), "ruid", ruid) //show a nice page links to available entries - ShowMultipleChoices(w, &r.Request, list) + ShowMultipleChoices(w, r, list) return } // check the root chunk exists by retrieving the file's size - if _, err := reader.Size(nil); err != nil { - s.NotFound(w, r, fmt.Errorf("File not found %s: %s", r.uri, err)) + if _, err := reader.Size(r.Context(), nil); err != nil { + getFileNotFound.Inc(1) + respondError(w, r, fmt.Sprintf("file not found %s: %s", uri, err), http.StatusNotFound) return } - w.Header().Set("Content-Type", contentType) + if contentType != "" { + w.Header().Set("Content-Type", contentType) + } - http.ServeContent(w, &r.Request, "", time.Now(), reader) + fileName := uri.Addr + if found := path.Base(uri.Path); found != "" && found != "." && found != "/" { + fileName = found + } + w.Header().Set("Content-Disposition", fmt.Sprintf("inline; filename=\"%s\"", fileName)) + + http.ServeContent(w, r, fileName, time.Now(), newBufferedReadSeeker(reader, getFileBufferSize)) } -func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { - s.logDebug("HTTP %s request URL: '%s', Host: '%s', Path: '%s', Referer: '%s', Accept: '%s'", r.Method, r.RequestURI, r.URL.Host, r.URL.Path, r.Referer(), r.Header.Get("Accept")) +// The size of buffer used for bufio.Reader on LazyChunkReader passed to +// http.ServeContent in HandleGetFile. +// Warning: This value influences the number of chunk requests and chunker join goroutines +// per file request. +// Recommended value is 4 times the io.Copy default buffer value which is 32kB. +const getFileBufferSize = 4 * 32 * 1024 - uri, err := api.Parse(strings.TrimLeft(r.URL.Path, "/")) - req := &Request{Request: *r, uri: uri} - if err != nil { - s.logError("Invalid URI %q: %s", r.URL.Path, err) - s.BadRequest(w, req, fmt.Sprintf("Invalid URI %q: %s", r.URL.Path, err)) - return - } - s.logDebug("%s request received for %s", r.Method, uri) - - switch r.Method { - case "POST": - if uri.Raw() || uri.DeprecatedRaw() { - s.HandlePostRaw(w, req) - } else { - s.HandlePostFiles(w, req) - } - - case "PUT": - // DEPRECATED: - // clients should send a POST request (the request creates a - // new manifest leaving the existing one intact, so it isn't - // strictly a traditional PUT request which replaces content - // at a URI, and POST is more ubiquitous) - if uri.Raw() || uri.DeprecatedRaw() { - ShowError(w, r, fmt.Sprintf("No PUT to %s allowed.", uri), http.StatusBadRequest) - return - } else { - s.HandlePostFiles(w, req) - } - - case "DELETE": - if uri.Raw() || uri.DeprecatedRaw() { - ShowError(w, r, fmt.Sprintf("No DELETE to %s allowed.", uri), http.StatusBadRequest) - return - } - s.HandleDelete(w, req) - - case "GET": - if uri.Raw() || uri.Hash() || uri.DeprecatedRaw() { - s.HandleGet(w, req) - return - } - - if uri.List() { - s.HandleGetList(w, req) - return - } - - if r.Header.Get("Accept") == "application/x-tar" { - s.HandleGetFiles(w, req) - return - } - - s.HandleGetFile(w, req) - - default: - ShowError(w, r, fmt.Sprintf("Method "+r.Method+" is not supported.", uri), http.StatusMethodNotAllowed) +// bufferedReadSeeker wraps bufio.Reader to expose Seek method +// from the provied io.ReadSeeker in newBufferedReadSeeker. +type bufferedReadSeeker struct { + r io.Reader + s io.Seeker +} +// newBufferedReadSeeker creates a new instance of bufferedReadSeeker, +// out of io.ReadSeeker. Argument `size` is the size of the read buffer. +func newBufferedReadSeeker(readSeeker io.ReadSeeker, size int) bufferedReadSeeker { + return bufferedReadSeeker{ + r: bufio.NewReaderSize(readSeeker, size), + s: readSeeker, } } -func (s *Server) updateManifest(key storage.Key, update func(mw *api.ManifestWriter) error) (storage.Key, error) { - mw, err := s.api.NewManifestWriter(key, nil) - if err != nil { - return nil, err - } - - if err := update(mw); err != nil { - return nil, err - } - - key, err = mw.Store() - if err != nil { - return nil, err - } - s.logDebug("generated manifest %s", key) - return key, nil +func (b bufferedReadSeeker) Read(p []byte) (n int, err error) { + return b.r.Read(p) } -func (s *Server) logDebug(format string, v ...interface{}) { - log.Debug(fmt.Sprintf("[BZZ] HTTP: "+format, v...)) +func (b bufferedReadSeeker) Seek(offset int64, whence int) (int64, error) { + return b.s.Seek(offset, whence) } -func (s *Server) logError(format string, v ...interface{}) { - log.Error(fmt.Sprintf("[BZZ] HTTP: "+format, v...)) +type loggingResponseWriter struct { + http.ResponseWriter + statusCode int } -func (s *Server) BadRequest(w http.ResponseWriter, r *Request, reason string) { - ShowError(w, &r.Request, fmt.Sprintf("Bad request %s %s: %s", r.Method, r.uri, reason), http.StatusBadRequest) +func newLoggingResponseWriter(w http.ResponseWriter) *loggingResponseWriter { + return &loggingResponseWriter{w, http.StatusOK} } -func (s *Server) Error(w http.ResponseWriter, r *Request, err error) { - ShowError(w, &r.Request, fmt.Sprintf("Error serving %s %s: %s", r.Method, r.uri, err), http.StatusInternalServerError) +func (lrw *loggingResponseWriter) WriteHeader(code int) { + lrw.statusCode = code + lrw.ResponseWriter.WriteHeader(code) } -func (s *Server) NotFound(w http.ResponseWriter, r *Request, err error) { - ShowError(w, &r.Request, fmt.Sprintf("NOT FOUND error serving %s %s: %s", r.Method, r.uri, err), http.StatusNotFound) +func isDecryptError(err error) bool { + return strings.Contains(err.Error(), api.ErrDecrypt.Error()) } diff --git a/swarm/api/http/server_test.go b/swarm/api/http/server_test.go index 305d5cf7db..e82762ce05 100644 --- a/swarm/api/http/server_test.go +++ b/swarm/api/http/server_test.go @@ -14,39 +14,457 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package http_test +package http import ( + "archive/tar" "bytes" + "context" + "encoding/json" "errors" + "flag" "fmt" + "io" "io/ioutil" + "math/big" + "mime/multipart" "net/http" + "net/url" + "os" + "path" + "strconv" "strings" - "sync" "testing" + "time" + + "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup" "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/swarm/api" swarm "github.com/ethereum/go-ethereum/swarm/api/client" "github.com/ethereum/go-ethereum/swarm/storage" + "github.com/ethereum/go-ethereum/swarm/storage/feed" "github.com/ethereum/go-ethereum/swarm/testutil" ) -func TestBzzGetPath(t *testing.T) { +func init() { + loglevel := flag.Int("loglevel", 2, "loglevel") + flag.Parse() + log.Root().SetHandler(log.CallerFileHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(os.Stderr, log.TerminalFormat(true))))) +} +func serverFunc(api *api.API) TestServer { + return NewServer(api, "") +} + +func newTestSigner() (*feed.GenericSigner, error) { + privKey, err := crypto.HexToECDSA("deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef") + if err != nil { + return nil, err + } + return feed.NewGenericSigner(privKey), nil +} + +// Test the transparent resolving of feed updates with bzz:// scheme +// +// 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 TestBzzWithFeed(t *testing.T) { + + signer, _ := newTestSigner() + + // Initialize Swarm test server + srv := NewTestSwarmServer(t, serverFunc, nil) + defer srv.Close() + + // 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) + } + manifestAddressHex, err := ioutil.ReadAll(resp.Body) + + if err != nil { + t.Fatal(err) + } + + manifestAddress := common.FromHex(string(manifestAddressHex)) + + 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) + + // 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", "data", common.ToHex(manifestAddress)) + + // Build the feed update http request: + feedUpdateURL, err := url.Parse(fmt.Sprintf("%s/bzz-feed:/", srv.URL)) + if err != nil { + t.Fatal(err) + } + 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 feed manifest back + feedUpdateURL.RawQuery = query.Encode() + + // 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) + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + t.Fatalf("err %s", resp.Status) + } + + feedManifestAddressHex, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + feedManifestAddress := &storage.Address{} + err = json.Unmarshal(feedManifestAddressHex, feedManifestAddress) + if err != nil { + t.Fatalf("data %s could not be unmarshaled: %v", feedManifestAddressHex, err) + } + + 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 + getBzzURL := fmt.Sprintf("%s/bzz:/%s", srv.URL, feedManifestAddress) + resp, err = http.Get(getBzzURL) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + t.Fatalf("err %s", resp.Status) + } + retrievedData, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(retrievedData, []byte(dataBytes)) { + t.Fatalf("retrieved data mismatch, expected %x, got %x", dataBytes, retrievedData) + } +} + +// Test Swarm feeds using the raw update methods +func TestBzzFeed(t *testing.T) { + srv := NewTestSwarmServer(t, serverFunc, nil) + signer, _ := newTestSigner() + + defer srv.Close() + + // data of update 1 + update1Data := testutil.RandomBytes(1, 666) + update1Timestamp := srv.CurrentTime + //data for update 2 + update2Data := []byte("foo") + + topic, _ := feed.NewTopic("foo.eth", nil) + updateRequest := feed.NewFirstRequest(topic) + updateRequest.SetData(update1Data) + + if err := updateRequest.Sign(signer); err != nil { + t.Fatal(err) + } + + // creates feed and sets update 1 + testUrl, err := url.Parse(fmt.Sprintf("%s/bzz-feed:/", srv.URL)) + if err != nil { + t.Fatal(err) + } + urlQuery := testUrl.Query() + body := updateRequest.AppendValues(urlQuery) // this adds all query parameters + urlQuery.Set("manifest", "1") // indicate we want a manifest back + testUrl.RawQuery = urlQuery.Encode() + + resp, err := http.Post(testUrl.String(), "application/octet-stream", bytes.NewReader(body)) + 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) + if err != nil { + t.Fatal(err) + } + rsrcResp := &storage.Address{} + err = json.Unmarshal(b, rsrcResp) + if err != nil { + t.Fatalf("data %s could not be unmarshaled: %v", b, err) + } + + correctManifestAddrHex := "bb056a5264c295c2b0f613c8409b9c87ce9d71576ace02458160df4cc894210b" + if rsrcResp.Hex() != correctManifestAddrHex { + t.Fatalf("Response feed manifest mismatch, expected '%s', got '%s'", correctManifestAddrHex, rsrcResp.Hex()) + } + + // get the manifest + testRawUrl := fmt.Sprintf("%s/bzz-raw:/%s", srv.URL, rsrcResp) + resp, err = http.Get(testRawUrl) + 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) + if err != nil { + t.Fatal(err) + } + manifest := &api.Manifest{} + err = json.Unmarshal(b, manifest) + if err != nil { + t.Fatal(err) + } + if len(manifest.Entries) != 1 { + t.Fatalf("Manifest has %d entries", len(manifest.Entries)) + } + correctFeedHex := "0x666f6f2e65746800000000000000000000000000000000000000000000000000c96aaa54e2d44c299564da76e1cd3184a2386b8d" + if manifest.Entries[0].Feed.Hex() != correctFeedHex { + t.Fatalf("Expected manifest Feed '%s', got '%s'", correctFeedHex, manifest.Entries[0].Feed.Hex()) + } + + // 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 { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.StatusCode == http.StatusOK { + 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 { + t.Fatal(err) + } + + // get non-existent name, should fail + testBzzResUrl := fmt.Sprintf("%s/bzz-feed:/bar", srv.URL) + resp, err = http.Get(testBzzResUrl) + if err != nil { + t.Fatal(err) + } + + if resp.StatusCode != http.StatusNotFound { + t.Fatalf("Expected get non-existent feed manifest to fail with StatusNotFound (404), got %d", resp.StatusCode) + } + + resp.Body.Close() + + // get latest update through bzz-feed directly + log.Info("get update latest = 1.1", "addr", correctManifestAddrHex) + testBzzResUrl = fmt.Sprintf("%s/bzz-feed:/%s", srv.URL, correctManifestAddrHex) + resp, err = http.Get(testBzzResUrl) + 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) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(update1Data, b) { + t.Fatalf("Expected body '%x', got '%x'", update1Data, b) + } + + // update 2 + // Move the clock ahead 1 second + srv.CurrentTime++ + log.Info("update 2") + + // 1.- get metadata about this feed + testBzzResUrl = fmt.Sprintf("%s/bzz-feed:/%s/", srv.URL, correctManifestAddrHex) + resp, err = http.Get(testBzzResUrl + "?meta=1") + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + t.Fatalf("Get feed metadata returned %s", resp.Status) + } + b, err = ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + updateRequest = &feed.Request{} + if err = updateRequest.UnmarshalJSON(b); err != nil { + t.Fatalf("Error decoding feed metadata: %s", err) + } + updateRequest.SetData(update2Data) + if err = updateRequest.Sign(signer); err != nil { + t.Fatal(err) + } + testUrl, err = url.Parse(fmt.Sprintf("%s/bzz-feed:/", srv.URL)) + if err != nil { + t.Fatal(err) + } + urlQuery = testUrl.Query() + body = updateRequest.AppendValues(urlQuery) // this adds all query parameters + goodQueryParameters := urlQuery.Encode() // save the query parameters for a second attempt + + // create bad query parameters in which the signature is missing + urlQuery.Del("signature") + testUrl.RawQuery = urlQuery.Encode() + + // 1st attempt with bad query parameters in which the signature is missing + resp, err = http.Post(testUrl.String(), "application/octet-stream", bytes.NewReader(body)) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + expectedCode := http.StatusBadRequest + if resp.StatusCode != expectedCode { + t.Fatalf("Update returned %s. Expected %d", resp.Status, expectedCode) + } + + // 2nd attempt with bad query parameters in which the signature is of incorrect length + urlQuery.Set("signature", "0xabcd") // should be 130 hex chars + resp, err = http.Post(testUrl.String(), "application/octet-stream", bytes.NewReader(body)) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + expectedCode = http.StatusBadRequest + if resp.StatusCode != expectedCode { + t.Fatalf("Update returned %s. Expected %d", resp.Status, expectedCode) + } + + // 3rd attempt, with good query parameters: + testUrl.RawQuery = goodQueryParameters + resp, err = http.Post(testUrl.String(), "application/octet-stream", bytes.NewReader(body)) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + expectedCode = http.StatusOK + if resp.StatusCode != expectedCode { + t.Fatalf("Update returned %s. Expected %d", resp.Status, expectedCode) + } + + // get latest update through bzz-feed directly + log.Info("get update 1.2") + testBzzResUrl = fmt.Sprintf("%s/bzz-feed:/%s", srv.URL, correctManifestAddrHex) + resp, err = http.Get(testBzzResUrl) + 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) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(update2Data, b) { + t.Fatalf("Expected body '%x', got '%x'", update2Data, b) + } + + // test manifest-less queries + log.Info("get first update in update1Timestamp via direct query") + query := feed.NewQuery(&updateRequest.Feed, update1Timestamp, lookup.NoClue) + + urlq, err := url.Parse(fmt.Sprintf("%s/bzz-feed:/", srv.URL)) + if err != nil { + t.Fatal(err) + } + + values := urlq.Query() + query.AppendValues(values) // this adds feed query parameters + urlq.RawQuery = values.Encode() + resp, err = http.Get(urlq.String()) + 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) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(update1Data, b) { + t.Fatalf("Expected body '%x', got '%x'", update1Data, b) + } + +} + +func TestBzzGetPath(t *testing.T) { + testBzzGetPath(false, t) + testBzzGetPath(true, t) +} + +func testBzzGetPath(encrypted bool, t *testing.T) { var err error testmanifest := []string{ - `{"entries":[{"path":"a/","hash":"674af7073604ebfc0282a4ab21e5ef1a3c22913866879ebc0816f8a89896b2ed","contentType":"application/bzz-manifest+json","status":0}]}`, - `{"entries":[{"path":"a","hash":"011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce","contentType":"","status":0},{"path":"b/","hash":"0a87b1c3e4bf013686cdf107ec58590f2004610ee58cc2240f26939f691215f5","contentType":"application/bzz-manifest+json","status":0}]}`, `{"entries":[{"path":"b","hash":"011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce","contentType":"","status":0},{"path":"c","hash":"011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce","contentType":"","status":0}]}`, + `{"entries":[{"path":"a","hash":"011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce","contentType":"","status":0},{"path":"b/","hash":"","contentType":"application/bzz-manifest+json","status":0}]}`, + `{"entries":[{"path":"a/","hash":"","contentType":"application/bzz-manifest+json","status":0}]}`, } testrequests := make(map[string]int) - testrequests["/"] = 0 + testrequests["/"] = 2 testrequests["/a/"] = 1 - testrequests["/a/b/"] = 2 + testrequests["/a/b/"] = 0 testrequests["/x"] = 0 testrequests[""] = 0 @@ -54,23 +472,31 @@ func TestBzzGetPath(t *testing.T) { reader := [3]*bytes.Reader{} - key := [3]storage.Key{} + addr := [3]storage.Address{} - srv := testutil.NewTestSwarmServer(t) + srv := NewTestSwarmServer(t, serverFunc, nil) defer srv.Close() - wg := &sync.WaitGroup{} - for i, mf := range testmanifest { reader[i] = bytes.NewReader([]byte(mf)) - key[i], err = srv.Dpa.Store(reader[i], int64(len(mf)), wg, nil) + var wait func(context.Context) error + ctx := context.TODO() + addr[i], wait, err = srv.FileStore.Store(ctx, reader[i], int64(len(mf)), encrypted) + if err != nil { + t.Fatal(err) + } + for j := i + 1; j < len(testmanifest); j++ { + testmanifest[j] = strings.Replace(testmanifest[j], fmt.Sprintf("", i), addr[i].Hex(), -1) + } + err = wait(ctx) if err != nil { t.Fatal(err) } - wg.Wait() } - _, err = http.Get(srv.URL + "/bzz-raw:/" + common.ToHex(key[0])[2:] + "/a") + rootRef := addr[2].Hex() + + _, err = http.Get(srv.URL + "/bzz-raw:/" + rootRef + "/a") if err != nil { t.Fatalf("Failed to connect to proxy: %v", err) } @@ -80,8 +506,8 @@ func TestBzzGetPath(t *testing.T) { var respbody []byte url := srv.URL + "/bzz-raw:/" - if k[:] != "" { - url += common.ToHex(key[0])[2:] + "/" + k[1:] + "?content_type=text/plain" + if k != "" { + url += rootRef + "/" + k[1:] + "?content_type=text/plain" } resp, err = http.Get(url) if err != nil { @@ -89,12 +515,15 @@ func TestBzzGetPath(t *testing.T) { } defer resp.Body.Close() respbody, err = ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatalf("Error while reading response body: %v", err) + } if string(respbody) != testmanifest[v] { isexpectedfailrequest := false for _, r := range expectedfailrequests { - if k[:] == r { + if k == r { isexpectedfailrequest = true } } @@ -109,8 +538,8 @@ func TestBzzGetPath(t *testing.T) { var respbody []byte url := srv.URL + "/bzz-hash:/" - if k[:] != "" { - url += common.ToHex(key[0])[2:] + "/" + k[1:] + if k != "" { + url += rootRef + "/" + k[1:] } resp, err = http.Get(url) if err != nil { @@ -122,39 +551,52 @@ func TestBzzGetPath(t *testing.T) { t.Fatalf("Read request body: %v", err) } - if string(respbody) != key[v].String() { + if string(respbody) != addr[v].Hex() { isexpectedfailrequest := false for _, r := range expectedfailrequests { - if k[:] == r { + if k == r { isexpectedfailrequest = true } } if !isexpectedfailrequest { - t.Fatalf("Response body does not match, expected: %v, got %v", key[v], string(respbody)) + t.Fatalf("Response body does not match, expected: %v, got %v", addr[v], string(respbody)) } } } + ref := addr[2].Hex() + for _, c := range []struct { - path string - json string - html string + path string + json string + pageFragments []string }{ { path: "/", json: `{"common_prefixes":["a/"]}`, - html: "\n\n\n \n \n Swarm index of bzz:/262e5c08c03c2789b6daef487dfa14b4d132f5340d781a3ecb1d5122ab65640c/\n\n\n\n

Swarm index of bzz:/262e5c08c03c2789b6daef487dfa14b4d132f5340d781a3ecb1d5122ab65640c/

\n
\n \n \n \n\t\n\t\n\t\n \n \n\n \n \n\t\n\t \n\t \n\t \n\t\n \n\n \n
PathTypeSize
a/DIR-
\n
\n\n", + pageFragments: []string{ + fmt.Sprintf("Swarm index of bzz:/%s/", ref), + `a/`, + }, }, { path: "/a/", json: `{"common_prefixes":["a/b/"],"entries":[{"hash":"011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce","path":"a/a","mod_time":"0001-01-01T00:00:00Z"}]}`, - html: "\n\n\n \n \n Swarm index of bzz:/262e5c08c03c2789b6daef487dfa14b4d132f5340d781a3ecb1d5122ab65640c/a/\n\n\n\n

Swarm index of bzz:/262e5c08c03c2789b6daef487dfa14b4d132f5340d781a3ecb1d5122ab65640c/a/

\n
\n \n \n \n\t\n\t\n\t\n \n \n\n \n \n\t\n\t \n\t \n\t \n\t\n \n\n \n\t\n\t \n\t \n\t \n\t\n \n
PathTypeSize
b/DIR-
a0
\n
\n\n", + pageFragments: []string{ + fmt.Sprintf("Swarm index of bzz:/%s/a/", ref), + `b/`, + fmt.Sprintf(`a`, ref), + }, }, { path: "/a/b/", json: `{"entries":[{"hash":"011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce","path":"a/b/b","mod_time":"0001-01-01T00:00:00Z"},{"hash":"011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce","path":"a/b/c","mod_time":"0001-01-01T00:00:00Z"}]}`, - html: "\n\n\n \n \n Swarm index of bzz:/262e5c08c03c2789b6daef487dfa14b4d132f5340d781a3ecb1d5122ab65640c/a/b/\n\n\n\n

Swarm index of bzz:/262e5c08c03c2789b6daef487dfa14b4d132f5340d781a3ecb1d5122ab65640c/a/b/

\n
\n \n \n \n\t\n\t\n\t\n \n \n\n \n \n\n \n\t\n\t \n\t \n\t \n\t\n \n\t\n\t \n\t \n\t \n\t\n \n
PathTypeSize
b0
c0
\n
\n\n", + pageFragments: []string{ + fmt.Sprintf("Swarm index of bzz:/%s/a/b/", ref), + fmt.Sprintf(`b`, ref), + fmt.Sprintf(`c`, ref), + }, }, { path: "/x", @@ -165,8 +607,8 @@ func TestBzzGetPath(t *testing.T) { } { k := c.path url := srv.URL + "/bzz-list:/" - if k[:] != "" { - url += common.ToHex(key[0])[2:] + "/" + k[1:] + if k != "" { + url += rootRef + "/" + k[1:] } t.Run("json list "+c.path, func(t *testing.T) { resp, err := http.Get(url) @@ -184,7 +626,7 @@ func TestBzzGetPath(t *testing.T) { isexpectedfailrequest := false for _, r := range expectedfailrequests { - if k[:] == r { + if k == r { isexpectedfailrequest = true } } @@ -204,21 +646,25 @@ func TestBzzGetPath(t *testing.T) { t.Fatalf("HTTP request: %v", err) } defer resp.Body.Close() - respbody, err := ioutil.ReadAll(resp.Body) + b, err := ioutil.ReadAll(resp.Body) if err != nil { t.Fatalf("Read response body: %v", err) } - if string(respbody) != c.html { - isexpectedfailrequest := false + body := string(b) - for _, r := range expectedfailrequests { - if k[:] == r { - isexpectedfailrequest = true + for _, f := range c.pageFragments { + if !strings.Contains(body, f) { + isexpectedfailrequest := false + + for _, r := range expectedfailrequests { + if k == r { + isexpectedfailrequest = true + } + } + if !isexpectedfailrequest { + t.Errorf("Response list body %q does not contain %q: body %q", k, f, body) } - } - if !isexpectedfailrequest { - t.Errorf("Response list body %q does not match, expected: %q, got %q", k, c.html, string(respbody)) } } }) @@ -233,11 +679,11 @@ func TestBzzGetPath(t *testing.T) { } nonhashresponses := []string{ - "error resolving name: no DNS to resolve name: "name"", - "error resolving nonhash: immutable address not a content hash: "nonhash"", - "error resolving nonhash: no DNS to resolve name: "nonhash"", - "error resolving nonhash: no DNS to resolve name: "nonhash"", - "error resolving nonhash: no DNS to resolve name: "nonhash"", + `cannot resolve name: no DNS to resolve name: "name"`, + `cannot resolve nonhash: no DNS to resolve name: "nonhash"`, + `cannot resolve nonhash: no DNS to resolve name: "nonhash"`, + `cannot resolve nonhash: no DNS to resolve name: "nonhash"`, + `cannot resolve nonhash: no DNS to resolve name: "nonhash"`, } for i, url := range nonhashtests { @@ -258,14 +704,150 @@ func TestBzzGetPath(t *testing.T) { t.Fatalf("Non-Hash response body does not match, expected: %v, got: %v", nonhashresponses[i], string(respbody)) } } +} +func TestBzzTar(t *testing.T) { + testBzzTar(false, t) + testBzzTar(true, t) +} + +func testBzzTar(encrypted bool, t *testing.T) { + srv := NewTestSwarmServer(t, serverFunc, nil) + defer srv.Close() + fileNames := []string{"tmp1.txt", "tmp2.lock", "tmp3.rtf"} + fileContents := []string{"tmp1textfilevalue", "tmp2lockfilelocked", "tmp3isjustaplaintextfile"} + + buf := &bytes.Buffer{} + tw := tar.NewWriter(buf) + defer tw.Close() + + for i, v := range fileNames { + size := int64(len(fileContents[i])) + hdr := &tar.Header{ + Name: v, + Mode: 0644, + Size: size, + ModTime: time.Now(), + Xattrs: map[string]string{ + "user.swarm.content-type": "text/plain", + }, + } + if err := tw.WriteHeader(hdr); err != nil { + t.Fatal(err) + } + + // copy the file into the tar stream + n, err := io.Copy(tw, bytes.NewBufferString(fileContents[i])) + if err != nil { + t.Fatal(err) + } else if n != size { + t.Fatal("size mismatch") + } + } + + //post tar stream + url := srv.URL + "/bzz:/" + if encrypted { + url = url + "encrypt" + } + req, err := http.NewRequest("POST", url, buf) + if err != nil { + t.Fatal(err) + } + req.Header.Add("Content-Type", "application/x-tar") + client := &http.Client{} + resp2, err := client.Do(req) + if err != nil { + t.Fatal(err) + } + if resp2.StatusCode != http.StatusOK { + t.Fatalf("err %s", resp2.Status) + } + swarmHash, err := ioutil.ReadAll(resp2.Body) + resp2.Body.Close() + if err != nil { + t.Fatal(err) + } + + // now do a GET to get a tarball back + req, err = http.NewRequest("GET", fmt.Sprintf(srv.URL+"/bzz:/%s", string(swarmHash)), nil) + if err != nil { + t.Fatal(err) + } + req.Header.Add("Accept", "application/x-tar") + resp2, err = client.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp2.Body.Close() + + if h := resp2.Header.Get("Content-Type"); h != "application/x-tar" { + t.Fatalf("Content-Type header expected: application/x-tar, got: %s", h) + } + + expectedFileName := string(swarmHash) + ".tar" + expectedContentDisposition := fmt.Sprintf("inline; filename=\"%s\"", expectedFileName) + if h := resp2.Header.Get("Content-Disposition"); h != expectedContentDisposition { + t.Fatalf("Content-Disposition header expected: %s, got: %s", expectedContentDisposition, h) + } + + file, err := ioutil.TempFile("", "swarm-downloaded-tarball") + if err != nil { + t.Fatal(err) + } + defer os.Remove(file.Name()) + _, err = io.Copy(file, resp2.Body) + if err != nil { + t.Fatalf("error getting tarball: %v", err) + } + file.Sync() + file.Close() + + tarFileHandle, err := os.Open(file.Name()) + if err != nil { + t.Fatal(err) + } + tr := tar.NewReader(tarFileHandle) + + for { + hdr, err := tr.Next() + if err == io.EOF { + break + } else if err != nil { + t.Fatalf("error reading tar stream: %s", err) + } + bb := make([]byte, hdr.Size) + _, err = tr.Read(bb) + if err != nil && err != io.EOF { + t.Fatal(err) + } + passed := false + for i, v := range fileNames { + if v == hdr.Name { + if string(bb) == fileContents[i] { + passed = true + break + } + } + } + if !passed { + t.Fatalf("file %s did not pass content assertion", hdr.Name) + } + } } // TestBzzRootRedirect tests that getting the root path of a manifest without // a trailing slash gets redirected to include the trailing slash so that // relative URLs work as expected. func TestBzzRootRedirect(t *testing.T) { - srv := testutil.NewTestSwarmServer(t) + testBzzRootRedirect(false, t) +} +func TestBzzRootRedirectEncrypted(t *testing.T) { + testBzzRootRedirect(true, t) +} + +func testBzzRootRedirect(toEncrypt bool, t *testing.T) { + srv := NewTestSwarmServer(t, serverFunc, nil) defer srv.Close() // create a manifest with some data at the root path @@ -279,7 +861,7 @@ func TestBzzRootRedirect(t *testing.T) { Size: int64(len(data)), }, } - hash, err := client.Upload(file, "") + hash, err := client.Upload(file, "", toEncrypt) if err != nil { t.Fatal(err) } @@ -318,3 +900,414 @@ func TestBzzRootRedirect(t *testing.T) { t.Fatalf("expected response to equal %q, got %q", data, gotData) } } + +func TestMethodsNotAllowed(t *testing.T) { + srv := NewTestSwarmServer(t, serverFunc, nil) + defer srv.Close() + databytes := "bar" + for _, c := range []struct { + url string + code int + }{ + { + url: fmt.Sprintf("%s/bzz-list:/", srv.URL), + code: http.StatusMethodNotAllowed, + }, { + url: fmt.Sprintf("%s/bzz-hash:/", srv.URL), + code: http.StatusMethodNotAllowed, + }, + { + url: fmt.Sprintf("%s/bzz-immutable:/", srv.URL), + code: http.StatusMethodNotAllowed, + }, + } { + res, _ := http.Post(c.url, "text/plain", bytes.NewReader([]byte(databytes))) + if res.StatusCode != c.code { + t.Fatalf("should have failed. requested url: %s, expected code %d, got %d", c.url, c.code, res.StatusCode) + } + } + +} + +func httpDo(httpMethod string, url string, reqBody io.Reader, headers map[string]string, verbose bool, t *testing.T) (*http.Response, string) { + // Build the Request + req, err := http.NewRequest(httpMethod, url, reqBody) + if err != nil { + t.Fatal(err) + } + for key, value := range headers { + req.Header.Set(key, value) + } + if verbose { + t.Log(req.Method, req.URL, req.Header, req.Body) + } + + // Send Request out + httpClient := &http.Client{} + res, err := httpClient.Do(req) + if err != nil { + t.Fatal(err) + } + + // Read the HTTP Body + buffer, err := ioutil.ReadAll(res.Body) + if err != nil { + t.Fatal(err) + } + defer res.Body.Close() + body := string(buffer) + + return res, body +} + +func TestGet(t *testing.T) { + srv := NewTestSwarmServer(t, serverFunc, nil) + defer srv.Close() + + for _, testCase := range []struct { + uri string + method string + headers map[string]string + expectedStatusCode int + assertResponseBody string + verbose bool + }{ + { + uri: fmt.Sprintf("%s/", srv.URL), + method: "GET", + headers: map[string]string{"Accept": "text/html"}, + expectedStatusCode: http.StatusOK, + assertResponseBody: "Swarm: Serverless Hosting Incentivised Peer-To-Peer Storage And Content Distribution", + verbose: false, + }, + { + uri: fmt.Sprintf("%s/", srv.URL), + method: "GET", + headers: map[string]string{"Accept": "application/json"}, + expectedStatusCode: http.StatusOK, + assertResponseBody: "Swarm: Please request a valid ENS or swarm hash with the appropriate bzz scheme", + verbose: false, + }, + { + uri: fmt.Sprintf("%s/robots.txt", srv.URL), + method: "GET", + headers: map[string]string{"Accept": "text/html"}, + expectedStatusCode: http.StatusOK, + assertResponseBody: "User-agent: *\nDisallow: /", + verbose: false, + }, + { + uri: fmt.Sprintf("%s/nonexistent_path", srv.URL), + method: "GET", + headers: map[string]string{}, + expectedStatusCode: http.StatusNotFound, + verbose: false, + }, + { + uri: fmt.Sprintf("%s/bzz:asdf/", srv.URL), + method: "GET", + headers: map[string]string{}, + expectedStatusCode: http.StatusNotFound, + verbose: false, + }, + { + uri: fmt.Sprintf("%s/tbz2/", srv.URL), + method: "GET", + headers: map[string]string{}, + expectedStatusCode: http.StatusNotFound, + verbose: false, + }, + { + uri: fmt.Sprintf("%s/bzz-rack:/", srv.URL), + method: "GET", + headers: map[string]string{}, + expectedStatusCode: http.StatusNotFound, + verbose: false, + }, + { + uri: fmt.Sprintf("%s/bzz-ls", srv.URL), + method: "GET", + headers: map[string]string{}, + expectedStatusCode: http.StatusNotFound, + verbose: false, + }} { + t.Run("GET "+testCase.uri, func(t *testing.T) { + res, body := httpDo(testCase.method, testCase.uri, nil, testCase.headers, testCase.verbose, t) + if res.StatusCode != testCase.expectedStatusCode { + t.Fatalf("expected status code %d but got %d", testCase.expectedStatusCode, res.StatusCode) + } + if testCase.assertResponseBody != "" && !strings.Contains(body, testCase.assertResponseBody) { + t.Fatalf("expected response to be: %s but got: %s", testCase.assertResponseBody, body) + } + }) + } +} + +func TestModify(t *testing.T) { + srv := NewTestSwarmServer(t, serverFunc, nil) + defer srv.Close() + + swarmClient := swarm.NewClient(srv.URL) + data := []byte("data") + file := &swarm.File{ + ReadCloser: ioutil.NopCloser(bytes.NewReader(data)), + ManifestEntry: api.ManifestEntry{ + Path: "", + ContentType: "text/plain", + Size: int64(len(data)), + }, + } + + hash, err := swarmClient.Upload(file, "", false) + if err != nil { + t.Fatal(err) + } + + for _, testCase := range []struct { + uri string + method string + headers map[string]string + requestBody []byte + expectedStatusCode int + assertResponseBody string + assertResponseHeaders map[string]string + verbose bool + }{ + { + uri: fmt.Sprintf("%s/bzz:/%s", srv.URL, hash), + method: "DELETE", + headers: map[string]string{}, + expectedStatusCode: http.StatusOK, + assertResponseBody: "8b634aea26eec353ac0ecbec20c94f44d6f8d11f38d4578a4c207a84c74ef731", + verbose: false, + }, + { + uri: fmt.Sprintf("%s/bzz:/%s", srv.URL, hash), + method: "PUT", + headers: map[string]string{}, + expectedStatusCode: http.StatusMethodNotAllowed, + verbose: false, + }, + { + uri: fmt.Sprintf("%s/bzz-raw:/%s", srv.URL, hash), + method: "PUT", + headers: map[string]string{}, + expectedStatusCode: http.StatusMethodNotAllowed, + verbose: false, + }, + { + uri: fmt.Sprintf("%s/bzz:/%s", srv.URL, hash), + method: "PATCH", + headers: map[string]string{}, + expectedStatusCode: http.StatusMethodNotAllowed, + verbose: false, + }, + { + uri: fmt.Sprintf("%s/bzz-raw:/", srv.URL), + method: "POST", + headers: map[string]string{}, + requestBody: []byte("POSTdata"), + expectedStatusCode: http.StatusOK, + assertResponseHeaders: map[string]string{"Content-Length": "64"}, + verbose: false, + }, + { + uri: fmt.Sprintf("%s/bzz-raw:/encrypt", srv.URL), + method: "POST", + headers: map[string]string{}, + requestBody: []byte("POSTdata"), + expectedStatusCode: http.StatusOK, + assertResponseHeaders: map[string]string{"Content-Length": "128"}, + verbose: false, + }, + } { + t.Run(testCase.method+" "+testCase.uri, func(t *testing.T) { + reqBody := bytes.NewReader(testCase.requestBody) + res, body := httpDo(testCase.method, testCase.uri, reqBody, testCase.headers, testCase.verbose, t) + + if res.StatusCode != testCase.expectedStatusCode { + t.Fatalf("expected status code %d but got %d, %s", testCase.expectedStatusCode, res.StatusCode, body) + } + if testCase.assertResponseBody != "" && !strings.Contains(body, testCase.assertResponseBody) { + t.Log(body) + t.Fatalf("expected response %s but got %s", testCase.assertResponseBody, body) + } + for key, value := range testCase.assertResponseHeaders { + if res.Header.Get(key) != value { + t.Logf("expected %s=%s in HTTP response header but got %s", key, value, res.Header.Get(key)) + } + } + }) + } +} + +func TestMultiPartUpload(t *testing.T) { + // POST /bzz:/ Content-Type: multipart/form-data + verbose := false + // Setup Swarm + srv := NewTestSwarmServer(t, serverFunc, nil) + defer srv.Close() + + url := fmt.Sprintf("%s/bzz:/", srv.URL) + + buf := new(bytes.Buffer) + form := multipart.NewWriter(buf) + form.WriteField("name", "John Doe") + file1, _ := form.CreateFormFile("cv", "cv.txt") + file1.Write([]byte("John Doe's Credentials")) + file2, _ := form.CreateFormFile("profile_picture", "profile.jpg") + file2.Write([]byte("imaginethisisjpegdata")) + form.Close() + + headers := map[string]string{ + "Content-Type": form.FormDataContentType(), + "Content-Length": strconv.Itoa(buf.Len()), + } + res, body := httpDo("POST", url, buf, headers, verbose, t) + + if res.StatusCode != http.StatusOK { + t.Fatalf("expected POST multipart/form-data to return 200, but it returned %d", res.StatusCode) + } + if len(body) != 64 { + t.Fatalf("expected POST multipart/form-data to return a 64 char manifest but the answer was %d chars long", len(body)) + } +} + +// TestBzzGetFileWithResolver tests fetching a file using a mocked ENS resolver +func TestBzzGetFileWithResolver(t *testing.T) { + resolver := newTestResolveValidator("") + srv := NewTestSwarmServer(t, serverFunc, resolver) + defer srv.Close() + fileNames := []string{"dir1/tmp1.txt", "dir2/tmp2.lock", "dir3/tmp3.rtf"} + fileContents := []string{"tmp1textfilevalue", "tmp2lockfilelocked", "tmp3isjustaplaintextfile"} + + buf := &bytes.Buffer{} + tw := tar.NewWriter(buf) + + for i, v := range fileNames { + size := len(fileContents[i]) + hdr := &tar.Header{ + Name: v, + Mode: 0644, + Size: int64(size), + ModTime: time.Now(), + Xattrs: map[string]string{ + "user.swarm.content-type": "text/plain", + }, + } + if err := tw.WriteHeader(hdr); err != nil { + t.Fatal(err) + } + + // copy the file into the tar stream + n, err := io.WriteString(tw, fileContents[i]) + if err != nil { + t.Fatal(err) + } else if n != size { + t.Fatal("size mismatch") + } + } + + if err := tw.Close(); err != nil { + t.Fatal(err) + } + + //post tar stream + url := srv.URL + "/bzz:/" + + req, err := http.NewRequest("POST", url, buf) + if err != nil { + t.Fatal(err) + } + req.Header.Add("Content-Type", "application/x-tar") + client := &http.Client{} + serverResponse, err := client.Do(req) + if err != nil { + t.Fatal(err) + } + if serverResponse.StatusCode != http.StatusOK { + t.Fatalf("err %s", serverResponse.Status) + } + swarmHash, err := ioutil.ReadAll(serverResponse.Body) + serverResponse.Body.Close() + if err != nil { + t.Fatal(err) + } + // set the resolved hash to be the swarm hash of what we've just uploaded + hash := common.HexToHash(string(swarmHash)) + resolver.hash = &hash + for _, v := range []struct { + addr string + path string + expectedStatusCode int + expectedContentType string + expectedFileName string + }{ + { + addr: string(swarmHash), + path: fileNames[0], + expectedStatusCode: http.StatusOK, + expectedContentType: "text/plain", + expectedFileName: path.Base(fileNames[0]), + }, + { + addr: "somebogusensname", + path: fileNames[0], + expectedStatusCode: http.StatusOK, + expectedContentType: "text/plain", + expectedFileName: path.Base(fileNames[0]), + }, + } { + req, err := http.NewRequest("GET", fmt.Sprintf(srv.URL+"/bzz:/%s/%s", v.addr, v.path), nil) + if err != nil { + t.Fatal(err) + } + serverResponse, err := client.Do(req) + if err != nil { + t.Fatal(err) + } + defer serverResponse.Body.Close() + if serverResponse.StatusCode != v.expectedStatusCode { + t.Fatalf("expected %d, got %d", v.expectedStatusCode, serverResponse.StatusCode) + } + + if h := serverResponse.Header.Get("Content-Type"); h != v.expectedContentType { + t.Fatalf("Content-Type header expected: %s, got %s", v.expectedContentType, h) + } + + expectedContentDisposition := fmt.Sprintf("inline; filename=\"%s\"", v.expectedFileName) + if h := serverResponse.Header.Get("Content-Disposition"); h != expectedContentDisposition { + t.Fatalf("Content-Disposition header expected: %s, got: %s", expectedContentDisposition, h) + } + + } +} + +// testResolver implements the Resolver interface and either returns the given +// hash if it is set, or returns a "name not found" error +type testResolveValidator struct { + hash *common.Hash +} + +func newTestResolveValidator(addr string) *testResolveValidator { + r := &testResolveValidator{} + if addr != "" { + hash := common.HexToHash(addr) + r.hash = &hash + } + return r +} + +func (t *testResolveValidator) Resolve(addr string) (common.Hash, error) { + if t.hash == nil { + return common.Hash{}, fmt.Errorf("DNS name not found: %q", addr) + } + return *t.hash, nil +} + +func (t *testResolveValidator) Owner(node [32]byte) (addr common.Address, err error) { + return +} +func (t *testResolveValidator) HeaderByNumber(context.Context, *big.Int) (header *types.Header, err error) { + return +} diff --git a/swarm/api/http/templates.go b/swarm/api/http/templates.go index 53ce7b5a22..986f5f8873 100644 --- a/swarm/api/http/templates.go +++ b/swarm/api/http/templates.go @@ -17,6 +17,8 @@ package http import ( + "encoding/hex" + "fmt" "html/template" "path" @@ -28,44 +30,277 @@ type htmlListData struct { List *api.ManifestList } -var htmlListTemplate = template.Must(template.New("html-list").Funcs(template.FuncMap{"basename": path.Base}).Parse(` - - +var TemplatesMap = make(map[string]*template.Template) +var faviconBytes []byte + +func init() { + for _, v := range []struct { + templateName string + partial string + funcs template.FuncMap + }{ + { + templateName: "error", + partial: errorResponse, + }, + { + templateName: "bzz-list", + partial: bzzList, + funcs: template.FuncMap{ + "basename": path.Base, + "leaflink": leafLink, + }, + }, + { + templateName: "landing-page", + partial: landing, + }, + } { + TemplatesMap[v.templateName] = template.Must(template.New(v.templateName).Funcs(v.funcs).Parse(baseTemplate + css + v.partial + logo)) + } + + bytes, err := hex.DecodeString(favicon) + if err != nil { + panic(err) + } + faviconBytes = bytes +} + +func leafLink(URI api.URI, manifestEntry api.ManifestEntry) string { + return fmt.Sprintf("/bzz:/%s/%s", URI.Addr, manifestEntry.Path) +} + +const bzzList = `{{ define "content" }} +

Swarm index of {{ .URI }}

+
+ + + + + + + + + + + {{ range .List.CommonPrefixes }} + + + + + + {{ end }} + {{ range .List.Entries }} + + + + + + {{ end }} +
PathTypeSize
+ {{ basename . }}/ + DIR-
+ {{ basename .Path }} + {{ .ContentType }}{{ .Size }}
+
+ + {{ end }}` + +const errorResponse = `{{ define "content" }} +
+ + +
+

{{.Msg}}

+
+ +
+
Error code: {{.Code}}
+
+ + +
+{{ end }}` + +const landing = `{{ define "content" }} + + + +
+ + + + + +
+ +{{ end }}` + +const baseTemplate = ` - - - Swarm index of {{ .URI }} + + + + + - -

Swarm index of {{ .URI }}

-
- - - - - - - - - - - {{ range .List.CommonPrefixes }} - - - - - - {{ end }} - - {{ range .List.Entries }} - - - - - - {{ end }} -
PathTypeSize
{{ basename . }}/DIR-
{{ basename .Path }}{{ .ContentType }}{{ .Size }}
-
+ {{ template "content" . }} -`[1:])) + +` + +const css = `{{ define "css" }} +html { + font-size: 18px; + font-size: 1.13rem; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; + font-family: Helvetica, Arial, sans-serif; +} + +body { + background: #f6f6f6; + color: #333; +} + +a, a:visited, a:active { + color: darkorange; +} + +a.normal-link, a.normal-link:active { color: #0000EE; } +a.normal-link:visited { color: #551A8B; } + +table { + border-collapse: separate; +} + +td { + padding: 3px 10px; +} + + +.container { + max-width: 600px; + margin: 40px auto 40px; + text-align: center; +} + +.separate-block { + margin: 40px 0; + word-wrap: break-word; +} + +.footer { + font-size: 12px; + font-size: 0.75rem; + text-align: center; +} + +.orange { + color: #ffa500; +} + +.top-space { + margin-top: 20px; + margin-bottom: 20px; +} + +/* SVG Logos, editable */ + +.searchbar { + padding: 20px 20px 0; +} + +.logo { + margin: 100px 80px 0; +} + +.logo a img { + max-width: 140px; +} + +/* Tablet < 600p*/ + +@media only screen and (max-width: 600px) {} + +/* Mobile phone < 360p*/ + +@media only screen and (max-width: 360px) { + h1 { + font-size: 20px; + font-size: 1.5rem; + } + h2 { + font-size: 0.88rem; + margin: 0; + } + .logo { + margin: 50px 40px 0; + } + .footer { + font-size: 0.63rem; + text-align: center; + } +} + +input[type=text] { + width: 100%; + box-sizing: border-box; + border: 2px solid #777; + border-radius: 2px; + font-size: 16px; + padding: 12px 20px 12px 20px; + transition: border 250ms ease-in-out; +} + +input[type=text]:focus { + border: 2px solid #ffce73; +} + +.button { + background-color: #ffa500; + margin: 20px 0; + border: none; + border-radius: 2px; + color: #222; + padding: 15px 32px; + text-align: center; + text-decoration: none; + display: inline-block; + font-size: 16px; +} +{{ end }}` + +const logo = `{{ define "logo" }} + +{{ end }}` + +const favicon = `000001000400101000000000200068040000460000002020000000002000a8100000ae0400003030000000002000a825000056150000404000000000200028420000fe3a000028000000100000002000000001002000000000004004000000000000000000000000000000000000ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff017e7e7e0362626263545454c548484849ffffff01ffffff01ffffff01ffffff01646464375b5b5bbf4545457758585809ffffff01ffffff01ffffff0164646443626262cf626262ff535353ff454545ff454545b74949492b6868681d626262a5626262fd5c5c5cff464646ff454545dd47474755ffffff01ffffff013f3f3feb565656ff636363ff535353ff464646ff3f3f3fff373737ab393939894d4d4dff626262ff5c5c5cff464646ff424242ff3a3a3af7ffffff01ffffff01383838e9353535ff424242ff474747ff383838ff353535ff363636ab35353587363636ff3a3a3aff4a4a4aff3b3b3bff353535ff363636f5ffffff01ffffff01383838e9303030ff181818ff131313ff232323ff343434ff363636ab35353587343434ff202020ff101010ff1d1d1dff303030ff373737f5ffffff01ffffff01232323c50c0c0cff0d0d0dff131313ff171717ff171717ff2929298b2727276b0f0f0ffd0d0d0dff101010ff171717ff161616ff232323d9ffffff01ffffff014d4d4d030f0f0f650c0c0ce7131313ff161616d51d1d1d4b63636363464646691717173b0d0d0dc50f0f0fff161616ef171717752e2e2e07ffffff01ffffff01ffffff01ffffff011d1d1d0f1515155360606045626262cf636363ff464646ff454545d3484848491414144d24242417ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff013c3c3c374f4f4fff636363ff636363ff464646ff464646ff3f3f3fff3c3c3c41ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff013636363d353535ff3c3c3cff575757ff363636ff181818ff282828ff37373747ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff013636363d363636ff303030ff181818ff292929ff131313ef17171771696969136565653bffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01323232371e1e1eff0d0d0dff0c0c0cff363636ff363636a3ffffff0185858515606060ff4747476bffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01111111450d0d0dd10c0c0cff1b1b1bff2a2a2a993e3e3e0b30303085292929ff37373787ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01363636030e0e0e671616166b45454505323232432e2e2ed9151515c31d1d1d2dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff014e4e4e05ffffff01ffffff01ffffff01ffffff010000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff28000000200000004000000001002000000000008010000000000000000000000000000000000000ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff017272721b646464a54646466f72727205ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0168686845575757b74f4f4f39ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff017e7e7e0b6262627d616161f3636363ff424242ff444444d74f4f4f49ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff016c6c6c27636363b5616161ff555555ff434343ff464646a35858581dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff016666665d616161e3626262ff636363ff636363ff444444ff464646ff434343ff454545b95252522bffffff01ffffff01ffffff01ffffff016c6c6c1363636393616161fb636363ff636363ff555555ff464646ff464646ff444444f5464646836666660bffffff01ffffff01ffffff01ffffff01ffffff016a6a6a3f626262c9616161ff636363ff636363ff636363ff636363ff444444ff464646ff464646ff464646ff434343fb48484897545454135b5b5b036868686f616161ef626262ff636363ff636363ff636363ff555555ff464646ff464646ff464646ff454545ff444444e54a4a4a5fffffff01ffffff01ffffff01ffffff013b3b3bd7505050ff646464ff636363ff636363ff636363ff636363ff444444ff464646ff464646ff464646ff454545ff3a3a3aff33333357313131113c3c3cff5a5a5aff646464ff636363ff636363ff636363ff555555ff464646ff464646ff464646ff464646ff424242ff383838f1ffffff01ffffff01ffffff01ffffff013a3a3ad5353535ff3a3a3aff575757ff646464ff626262ff636363ff444444ff464646ff464646ff3d3d3dff353535ff363636ff3636365535353511363636ff343434ff434343ff606060ff636363ff636363ff555555ff464646ff464646ff444444ff393939ff353535ff373737edffffff01ffffff01ffffff01ffffff013a3a3ad5363636ff363636ff343434ff3f3f3fff5d5d5dff646464ff444444ff404040ff363636ff353535ff363636ff363636ff3636365535353511363636ff363636ff363636ff343434ff4a4a4aff636363ff555555ff454545ff3c3c3cff353535ff363636ff363636ff373737edffffff01ffffff01ffffff01ffffff013a3a3ad5363636ff363636ff363636ff363636ff353535ff3f3f3fff363636ff353535ff363636ff363636ff363636ff363636ff3636365535353511363636ff363636ff363636ff363636ff353535ff383838ff3a3a3aff373737ff353535ff363636ff363636ff363636ff373737edffffff01ffffff01ffffff01ffffff013a3a3ad5363636ff363636ff363636ff323232ff181818ff0e0e0eff171717ff282828ff373737ff363636ff363636ff363636ff3636365535353511363636ff363636ff353535ff373737ff292929ff0f0f0fff111111ff1b1b1bff2f2f2fff373737ff363636ff363636ff373737edffffff01ffffff01ffffff01ffffff013a3a3ad5363636ff363636ff1e1e1eff0b0b0bff0d0d0dff0f0f0fff171717ff161616ff191919ff2c2c2cff373737ff363636ff3636365535353511363636ff373737ff2f2f2fff141414ff0b0b0bff0d0d0dff131313ff171717ff151515ff1f1f1fff333333ff363636ff373737edffffff01ffffff01ffffff01ffffff013b3b3bd5252525ff0d0d0dff0c0c0cff0d0d0dff0d0d0dff0f0f0fff171717ff171717ff171717ff151515ff1c1c1cff313131ff3535355734343411333333ff1a1a1aff0b0b0bff0d0d0dff0d0d0dff0d0d0dff131313ff171717ff171717ff171717ff161616ff242424ff373737efffffff01ffffff01ffffff01ffffff012020205d0b0b0be50b0b0bff0d0d0dff0d0d0dff0d0d0dff0f0f0fff171717ff171717ff171717ff171717ff131313ff161616b73333331f3b3b3b05111111970a0a0afb0d0d0dff0d0d0dff0d0d0dff0d0d0dff131313ff171717ff171717ff171717ff161616ff141414f51c1c1c7fffffff01ffffff01ffffff01ffffff01ffffff014d4d4d0b1212127f0a0a0af50d0d0dff0d0d0dff0f0f0fff171717ff171717ff151515ff151515d522222249ffffff017373731b51515121ffffff011d1d1d2b101010b50a0a0aff0d0d0dff0d0d0dff131313ff171717ff171717ff131313ff181818a12e2e2e1dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff012c2c2c1b0f0f0fa10a0a0afd0f0f0fff161616ff141414e91b1b1b69656565057878780b6363637b626262f3464646f7454545896969690fffffff011c1c1c470c0c0cd30b0b0bff131313ff141414ff151515c32a2a2a37ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff011d1d1d35111111bd1a1a1a8d2f2f2f11ffffff0166666659616161e1626262ff646464ff474747ff454545ff444444e9494949677b7b7b054040400517171769131313cd24242455ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0169696939626262c7616161ff636363ff636363ff646464ff474747ff464646ff464646ff444444ff454545d14e4e4e45ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01424242615e5e5eff636363ff636363ff636363ff636363ff646464ff474747ff464646ff464646ff464646ff464646ff434343ff3f3f3f77ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0136363679343434ff494949ff636363ff636363ff636363ff646464ff474747ff464646ff464646ff474747ff3d3d3dff353535ff3a3a3a8dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0136363679363636ff353535ff363636ff505050ff646464ff636363ff474747ff484848ff2f2f2fff1c1c1cff323232ff363636ff3a3a3a8dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0136363679363636ff363636ff363636ff353535ff3a3a3aff5a5a5aff393939ff0f0f0fff040404ff111111ff151515ff232323ff3535358fffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0136363679363636ff363636ff363636ff363636ff323232ff171717ff2a2a2aff0c0c0cff030303ff111111ff141414fb171717992e2e2e17a3a3a305ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0136363679363636ff363636ff363636ff1f1f1fff0b0b0bff0d0d0dff363636ff383838ff242424ff121212bf2a2a2a2dffffff01ffffff018484842b636363bf6d6d6d2fffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0136363679373737ff252525ff0d0d0dff0c0c0cff0d0d0dff0d0d0dff373737ff363636ff353535ff39393949ffffff01ffffff01ffffff0186868629646464ff656565fb6464649b55555505ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff012e2e2e650e0e0eff0c0c0cff0d0d0dff0d0d0dff0d0d0dff0c0c0cff353535ff363636ff353535ff37373749ffffff01ffffff01ffffff0185858529656565ff525252ff353535ff4b4b4b0fffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff011c1c1c430d0d0dcf0b0b0bff0d0d0dff0d0d0dff0d0d0dff171717ff282828ff363636ff37373749ffffff01ffffff01ffffff0144444459363636ff353535ff353535ff4e4e4e0fffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0162626203161616630b0b0be70c0c0cff0d0d0dff171717ff161616ff171717ed3737372fffffff013e3e3e2b303030b72a2a2aff151515ff262626ff363636ff4b4b4b0fffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff013636360d101010850a0a0af7141414f91717178f45454511ffffff014c4c4c252c2c2cdb303030ff2d2d2dff151515ff131313ff1b1b1bad5a5a5a07ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff012b2b2b2121212127ffffff01ffffff01ffffff01ffffff0161616109313131752b2b2bf1131313cd26262641ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff014e4e4e1359595903ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000028000000300000006000000001002000000000008025000000000000000000000000000000000000ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0173737357545454997c7c7c11ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0176767663515151916c6c6c0dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff017676762d636363bb636363ff4d4d4dff434343eb4f4f4f6d7f7f7f05ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0176767635616161c3626262ff494949ff424242e94f4f4f6392929203ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff017e7e7e19626262955f5f5ffd626262ff666666ff4f4f4fff464646ff424242ff434343d75a5a5a49ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff017777771d6464649f5f5f5fff636363ff656565ff4b4b4bff464646ff424242ff444444d158585841ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff018585850966666677606060ef626262ff636363ff636363ff666666ff4f4f4fff464646ff464646ff464646ff414141ff464646b75d5d5d2dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff018989890d6868687f5f5f5ff5626262ff636363ff636363ff656565ff4b4b4bff464646ff464646ff464646ff404040ff484848b160606027ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff016a6a6a55626262df606060ff636363ff636363ff636363ff636363ff666666ff4f4f4fff464646ff464646ff464646ff464646ff454545ff424242fd484848956a6a6a17ffffff01ffffff01ffffff01ffffff01ffffff016969695f606060e3606060ff636363ff636363ff636363ff636363ff656565ff4b4b4bff464646ff464646ff464646ff464646ff454545ff414141f94a4a4a8d65656513ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff016e6e6e3b656565c15f5f5fff636363ff636363ff636363ff636363ff636363ff636363ff666666ff4f4f4fff464646ff464646ff464646ff464646ff464646ff464646ff444444ff424242ed52525277ffffff01ffffff016c6c6c37676767c95f5f5fff636363ff636363ff636363ff636363ff636363ff636363ff656565ff4b4b4bff464646ff464646ff464646ff464646ff464646ff464646ff434343ff444444e94d4d4d6dffffff01ffffff01ffffff01ffffff01ffffff01ffffff013c3c3cc5454545ff646464ff646464ff636363ff636363ff636363ff636363ff636363ff666666ff4f4f4fff464646ff464646ff464646ff464646ff464646ff464646ff474747ff424242ff333333fb34343409ffffff0131313199494949ff656565ff646464ff636363ff636363ff636363ff636363ff636363ff656565ff4b4b4bff464646ff464646ff464646ff464646ff464646ff464646ff474747ff414141ff373737ebffffff01ffffff01ffffff01ffffff01ffffff01ffffff01404040bf333333ff343434ff4f4f4fff666666ff636363ff636363ff636363ff636363ff666666ff4f4f4fff464646ff464646ff464646ff464646ff474747ff444444ff383838ff343434ff363636f737373707ffffff0135353597343434ff343434ff525252ff666666ff636363ff636363ff636363ff636363ff656565ff4b4b4bff464646ff464646ff464646ff464646ff474747ff444444ff383838ff343434ff393939e3ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01404040bf343434ff363636ff333333ff383838ff585858ff676767ff636363ff636363ff666666ff4f4f4fff464646ff464646ff474747ff464646ff3b3b3bff343434ff363636ff363636ff363636f737373707ffffff0135353597363636ff363636ff333333ff383838ff5a5a5aff666666ff636363ff636363ff656565ff4b4b4bff464646ff464646ff474747ff454545ff3a3a3aff343434ff363636ff363636ff393939e3ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01404040bf343434ff363636ff363636ff363636ff323232ff3d3d3dff5d5d5dff666666ff666666ff4f4f4fff464646ff474747ff3e3e3eff353535ff353535ff363636ff363636ff363636ff363636f737373707ffffff0135353597363636ff363636ff363636ff363636ff313131ff3f3f3fff5f5f5fff666666ff656565ff4b4b4bff464646ff474747ff3d3d3dff353535ff353535ff363636ff363636ff363636ff393939e3ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01404040bf343434ff363636ff363636ff363636ff363636ff353535ff323232ff444444ff676767ff525252ff404040ff363636ff353535ff363636ff363636ff363636ff363636ff363636ff363636f737373707ffffff0135353597363636ff363636ff363636ff363636ff363636ff353535ff323232ff464646ff676767ff4e4e4eff404040ff363636ff353535ff363636ff363636ff363636ff363636ff363636ff393939e3ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01404040bf343434ff363636ff363636ff363636ff363636ff363636ff353535ff383838ff2d2d2dff2b2b2bff373737ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff363636f737373707ffffff0135353597363636ff363636ff363636ff363636ff363636ff363636ff363636ff383838ff2c2c2cff2a2a2aff373737ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff393939e3ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01404040bf343434ff363636ff363636ff363636ff353535ff383838ff343434ff171717ff090909ff151515ff171717ff2d2d2dff383838ff363636ff363636ff363636ff363636ff363636ff363636f737373707ffffff0135353597363636ff363636ff363636ff363636ff353535ff383838ff333333ff151515ff090909ff151515ff181818ff2f2f2fff383838ff363636ff363636ff363636ff363636ff363636ff393939e3ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01404040bf343434ff363636ff363636ff373737ff373737ff1f1f1fff090909ff0c0c0cff0c0c0cff171717ff171717ff141414ff1b1b1bff323232ff383838ff363636ff363636ff363636ff363636f737373707ffffff0135353597363636ff363636ff363636ff373737ff373737ff1d1d1dff0a0a0aff0c0c0cff0c0c0cff171717ff171717ff141414ff1c1c1cff333333ff383838ff353535ff363636ff363636ff393939e3ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01404040bf343434ff363636ff393939ff272727ff0c0c0cff0b0b0bff0d0d0dff0d0d0dff0c0c0cff171717ff171717ff171717ff161616ff141414ff202020ff353535ff373737ff363636ff363636f737373707ffffff0135353597363636ff363636ff383838ff252525ff0b0b0bff0b0b0bff0d0d0dff0d0d0dff0c0c0cff171717ff171717ff171717ff161616ff141414ff222222ff363636ff373737ff363636ff393939e3ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01404040bf383838ff2d2d2dff101010ff0a0a0aff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff171717ff171717ff171717ff171717ff171717ff161616ff141414ff262626ff373737ff373737f737373707ffffff0136363697393939ff2b2b2bff0f0f0fff0a0a0aff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff171717ff171717ff171717ff171717ff171717ff161616ff151515ff272727ff383838ff393939e3ffffff01ffffff01ffffff01ffffff01ffffff01ffffff013a3a3abd131313ff090909ff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff171717ff171717ff171717ff171717ff171717ff171717ff171717ff151515ff171717ff262626fb38383807ffffff012a2a2a97121212ff090909ff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff171717ff171717ff171717ff171717ff171717ff171717ff171717ff151515ff161616ff2a2a2ae7ffffff01ffffff01ffffff01ffffff01ffffff01ffffff015f5f5f0b1616167b090909ef0a0a0aff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff171717ff171717ff171717ff171717ff171717ff171717ff171717ff0f0f0fff181818b74040402dffffff01ffffff014646461118181883080808f30b0b0bff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff171717ff171717ff171717ff171717ff171717ff171717ff161616ff101010ff181818b141414127ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff014d4d4d171212129b090909fd0c0c0cff0d0d0dff0d0d0dff0d0d0dff0c0c0cff171717ff171717ff171717ff171717ff171717ff111111ff141414d335353547ffffff01ffffff01ffffff01ffffff01ffffff01ffffff013838381d131313a5060606ff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff171717ff171717ff171717ff171717ff171717ff111111ff181818cd2e2e2e3dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01333333310f0f0fbb070707ff0d0d0dff0d0d0dff0c0c0cff171717ff171717ff171717ff141414ff121212e72424246d86868603ffffff01ffffff017373732b656565b9464646c95e5e5e3bffffff01ffffff01ffffff01323232370e0e0ec3080808ff0d0d0dff0d0d0dff0c0c0cff171717ff171717ff171717ff121212ff161616e525252563ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff012525254d0e0e0ed9090909ff0c0c0cff171717ff151515ff121212f91d1d1d894d4d4d13ffffff01ffffff0178787815656565935f5f5ffb646464ff484848ff404040ff454545a96a6a6a1fffffff01ffffff01ffffff011b1b1b570e0e0edf080808ff0d0d0dff171717ff151515ff0f0f0ff3212121815656560dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01636363071a1a1a710a0a0aed0f0f0fff1b1b1bad2f2f2f23ffffff01ffffff018d8d8d0566666675616161eb616161ff636363ff646464ff484848ff464646ff454545ff424242f54c4c4c856262620fffffff01ffffff014040400b21212179080808f10f0f0fff1b1b1ba15757571dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff014141411740404037ffffff01ffffff01ffffff016a6a6a4d616161db606060ff636363ff636363ff636363ff646464ff484848ff464646ff464646ff464646ff434343ff434343e751515167ffffff01ffffff01ffffff014646461d30303033ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0176767631616161c35f5f5fff636363ff636363ff636363ff636363ff636363ff646464ff484848ff464646ff464646ff464646ff464646ff464646ff424242ff454545d158585841ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff015252527f636363ff636363ff636363ff636363ff636363ff636363ff636363ff636363ff646464ff484848ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff434343ff454545a1ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01313131b53b3b3bff5b5b5bff676767ff636363ff636363ff636363ff636363ff636363ff646464ff484848ff464646ff464646ff464646ff464646ff464646ff474747ff444444ff393939ff383838d3ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01363636b3363636ff323232ff404040ff616161ff656565ff626262ff636363ff636363ff646464ff484848ff464646ff464646ff454545ff494949ff474747ff3b3b3bff343434ff353535ff3a3a3ad3ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01363636b3363636ff363636ff353535ff323232ff484848ff656565ff646464ff636363ff646464ff484848ff464646ff474747ff494949ff242424ff282828ff383838ff363636ff363636ff3a3a3ad3ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01363636b3363636ff363636ff363636ff363636ff343434ff343434ff515151ff666666ff656565ff484848ff4b4b4bff323232ff070707ff040404ff151515ff181818ff2f2f2fff383838ff3a3a3ad3ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01363636b3363636ff363636ff363636ff363636ff363636ff363636ff333333ff383838ff5f5f5fff3c3c3cff0f0f0fff020202ff050505ff050505ff171717ff171717ff141414ff1c1c1cff323232d7ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01363636b3363636ff363636ff363636ff363636ff363636ff353535ff383838ff343434ff161616ff2a2a2aff0c0c0cff020202ff050505ff050505ff171717ff171717ff101010ff161616bf2e2e2e35ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01363636b3363636ff363636ff363636ff363636ff373737ff383838ff1f1f1fff0a0a0aff0c0c0cff373737ff3a3a3aff262626ff060606ff040404ff121212ff151515dd30303051ffffff01ffffff01ffffff018787872d6b6b6b47ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01363636b3363636ff363636ff363636ff393939ff272727ff0d0d0dff0b0b0bff0d0d0dff0d0d0dff373737ff363636ff373737ff383838ff1c1c1cf92020207568686807ffffff01ffffff01ffffff01ffffff018686863d5f5f5fff676767af77777721ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01363636b3363636ff393939ff2e2e2eff101010ff0a0a0aff0d0d0dff0d0d0dff0d0d0dff0d0d0dff373737ff363636ff363636ff353535ff373737ebffffff01ffffff01ffffff01ffffff01ffffff01ffffff018686863d626262ff666666ff646464f76969698d9494940fffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01383838b5333333ff161616ff090909ff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff373737ff363636ff363636ff363636ff353535ebffffff01ffffff01ffffff01ffffff01ffffff01ffffff018686863d626262ff676767ff6b6b6bff555555ff3a3a3a93ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0125252589030303ff0c0c0cff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff333333ff383838ff353535ff363636ff353535ebffffff01ffffff01ffffff01ffffff01ffffff01ffffff018585853d666666ff5f5f5fff3c3c3cff313131ff3a3a3a93ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff012d2d2d3f0e0e0ecb080808ff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff141414ff222222ff363636ff373737ff353535ebffffff01ffffff01ffffff01ffffff01ffffff01ffffff0177777741414141ff313131ff363636ff353535ff3a3a3a93ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff011e1e1e5f0a0a0ae50a0a0aff0d0d0dff0d0d0dff0d0d0dff0d0d0dff171717ff161616ff151515ff282828ff353535f3ffffff01ffffff01ffffff01ffffff016e6e6e0b37373781242424f1191919ff333333ff383838ff343434ff3a3a3a93ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff015a5a5a0d1919197f0a0a0af30b0b0bff0d0d0dff0d0d0dff171717ff171717ff161616ff0f0f0ffb24242489ffffff01ffffff01ffffff013e3e3e5d2d2d2de52e2e2eff2b2b2bff151515ff141414ff212121ff363636ff3b3b3b95ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff013636361b111111a3080808ff0c0c0cff181818ff0f0f0fff171717b545454525ffffff01ffffff017f7f7f05363636c7282828ff313131ff313131ff2b2b2bff151515ff171717ff161616ff0c0c0cfb3434346bffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01303030350f0f0fc7121212d337373741ffffff01ffffff01ffffff01ffffff01ffffff016b6b6b0b3a3a3a7d2c2c2cf12f2f2fff2b2b2bff151515ff101010ff171717bb4646462dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01515151193535359b242424ff131313d72828284bffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff014e4e4e2b59595905ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff28000000400000008000000001002000000000000042000000000000000000000000000000000000ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0176767635666666914e4e4e457c7c7c09ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff018080801569696989545454696c6c6c0bffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff018484840d70707061616161d5606060fb3d3d3ddf4e4e4e9172727213ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff017070704d626262b35f5f5ffb464646f1454545a16a6a6a33ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff017676760f67676753646464cf5e5e5eff656565ff626262ff414141ff404040ff444444e54b4b4b7b69696919ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01979797036c6c6c45676767a95d5d5dff616161ff626262ff484848ff424242ff3e3e3efd4e4e4e8958585831ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff017e7e7e2b616161a75f5f5fef616161ff636363ff656565ff626262ff424242ff464646ff444444ff414141fd434343b961616153ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff017777771969696981606060e7606060ff636363ff636363ff626262ff484848ff464646ff454545ff424242fd414141d95656566569696911ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01858585056e6e6e29656565995f5f5ff1616161ff636363ff636363ff636363ff656565ff626262ff424242ff464646ff464646ff464646ff444444ff3f3f3fff484848af5353534b86868607ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01797979216a6a6a6f616161ed5e5e5eff636363ff636363ff636363ff636363ff626262ff484848ff464646ff464646ff464646ff464646ff3e3e3eff474747d75151515762626213ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01838383036f6f6f755f5f5fd3606060ff626262ff636363ff636363ff636363ff636363ff656565ff626262ff424242ff464646ff464646ff464646ff464646ff454545ff434343ff404040e94e4e4e8d5f5f5f1bffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff018f8f8f056b6b6b45616161c95f5f5ff7616161ff636363ff636363ff636363ff636363ff636363ff626262ff484848ff464646ff464646ff464646ff464646ff464646ff444444ff424242f1434343b16666662dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff017070700f6969695f626262d35e5e5eff626262ff636363ff636363ff636363ff636363ff636363ff636363ff656565ff626262ff424242ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff404040ff444444f14d4d4d776a6a6a23ffffff01ffffff01ffffff01ffffff017b7b7b096c6c6c39636363c15f5f5ffb626262ff636363ff636363ff636363ff636363ff636363ff636363ff636363ff626262ff484848ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff434343ff414141f54a4a4aa35b5b5b2d70707007ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0171717143676767a7616161f3616161ff636363ff636363ff636363ff636363ff636363ff636363ff636363ff636363ff656565ff626262ff424242ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff444444ff414141f7474747cd54545447ffffff01ffffff015b5b5b096b6b6b99646464e1606060ff626262ff636363ff636363ff636363ff636363ff636363ff636363ff636363ff636363ff626262ff484848ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff444444ff424242ff414141d552525277ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01404040b33b3b3bff5c5c5cff656565ff646464ff636363ff636363ff636363ff636363ff636363ff636363ff636363ff656565ff626262ff424242ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff474747ff454545ff3a3a3aff313131ad34343407ffffff012e2e2e25383838ff535353ff656565ff656565ff636363ff636363ff636363ff636363ff636363ff636363ff636363ff636363ff626262ff484848ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff474747ff464646ff3b3b3bff3a3a3ae9ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01444444a9313131ff363636ff484848ff636363ff676767ff636363ff636363ff636363ff636363ff636363ff636363ff656565ff626262ff424242ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff404040ff363636ff343434ff353535a537373705ffffff0135353521333333ff333333ff434343ff5c5c5cff686868ff636363ff636363ff636363ff636363ff636363ff636363ff636363ff626262ff484848ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff484848ff414141ff393939ff313131ff3c3c3cdbffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01444444a9343434ff363636ff323232ff353535ff4b4b4bff636363ff656565ff636363ff626262ff636363ff636363ff656565ff626262ff424242ff464646ff464646ff464646ff464646ff474747ff464646ff414141ff363636ff343434ff363636ff363636ff363636a537373705ffffff0135353521363636ff363636ff333333ff313131ff484848ff5e5e5eff666666ff646464ff626262ff636363ff636363ff636363ff626262ff484848ff464646ff464646ff464646ff464646ff464646ff474747ff424242ff3a3a3aff343434ff353535ff333333ff3d3d3ddbffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01444444a9343434ff363636ff363636ff343434ff333333ff3d3d3dff555555ff686868ff656565ff626262ff636363ff656565ff626262ff424242ff464646ff464646ff464646ff484848ff444444ff393939ff353535ff353535ff363636ff363636ff363636ff363636a537373705ffffff0135353521363636ff363636ff363636ff353535ff323232ff363636ff515151ff646464ff656565ff636363ff636363ff636363ff626262ff484848ff464646ff464646ff464646ff484848ff454545ff3d3d3dff353535ff343434ff363636ff363636ff333333ff3d3d3ddbffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01444444a9343434ff363636ff363636ff363636ff363636ff343434ff303030ff3f3f3fff575757ff666666ff656565ff646464ff626262ff424242ff464646ff474747ff454545ff3a3a3aff343434ff353535ff363636ff363636ff363636ff363636ff363636ff363636a537373705ffffff0135353521363636ff363636ff363636ff363636ff363636ff363636ff303030ff373737ff535353ff636363ff656565ff636363ff626262ff484848ff464646ff474747ff454545ff3e3e3eff353535ff343434ff363636ff363636ff363636ff363636ff333333ff3d3d3ddbffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01444444a9343434ff363636ff363636ff363636ff363636ff363636ff363636ff333333ff333333ff484848ff606060ff696969ff626262ff434343ff474747ff3e3e3eff363636ff353535ff353535ff363636ff363636ff363636ff363636ff363636ff363636ff363636a537373705ffffff0135353521363636ff363636ff363636ff363636ff363636ff363636ff353535ff343434ff333333ff3e3e3eff5d5d5dff686868ff626262ff484848ff474747ff424242ff373737ff353535ff353535ff363636ff363636ff363636ff363636ff363636ff333333ff3d3d3ddbffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01444444a9343434ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff323232ff323232ff505050ff616161ff3d3d3dff373737ff343434ff353535ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff363636a537373705ffffff0135353521363636ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff343434ff313131ff434343ff606060ff464646ff383838ff343434ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff333333ff3d3d3ddbffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01444444a9343434ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff3a3a3aff2b2b2bff1e1e1eff2d2d2dff383838ff373737ff353535ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff363636a537373705ffffff0135353521363636ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff393939ff323232ff1c1c1cff262626ff373737ff383838ff353535ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff333333ff3d3d3ddbffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01444444a9343434ff363636ff363636ff363636ff363636ff363636ff353535ff373737ff383838ff303030ff191919ff080808ff101010ff141414ff1a1a1aff303030ff383838ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff363636a537373705ffffff0135353521363636ff363636ff363636ff363636ff363636ff363636ff353535ff363636ff383838ff363636ff1d1d1dff0b0b0bff0c0c0cff141414ff181818ff292929ff373737ff373737ff363636ff363636ff363636ff363636ff363636ff363636ff333333ff3d3d3ddbffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01444444a9343434ff363636ff363636ff363636ff363636ff353535ff393939ff363636ff222222ff0c0c0cff0a0a0aff0c0c0cff121212ff171717ff151515ff161616ff212121ff353535ff393939ff363636ff363636ff363636ff363636ff363636ff363636ff363636a537373705ffffff0135353521363636ff363636ff363636ff363636ff363636ff353535ff383838ff3a3a3aff262626ff121212ff0a0a0aff0c0c0cff0f0f0fff171717ff151515ff151515ff1e1e1eff2f2f2fff3a3a3aff363636ff363636ff363636ff363636ff363636ff333333ff3d3d3ddbffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01444444a9343434ff363636ff363636ff363636ff383838ff363636ff262626ff0d0d0dff090909ff0d0d0dff0d0d0dff0c0c0cff121212ff171717ff171717ff171717ff141414ff151515ff232323ff353535ff383838ff363636ff353535ff363636ff363636ff363636a537373705ffffff0135353521363636ff363636ff363636ff353535ff383838ff383838ff292929ff131313ff080808ff0c0c0cff0d0d0dff0d0d0dff0f0f0fff171717ff171717ff171717ff151515ff131313ff202020ff313131ff383838ff363636ff363636ff363636ff333333ff3d3d3ddbffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01444444a9343434ff353535ff363636ff3a3a3aff2e2e2eff131313ff0a0a0aff0b0b0bff0d0d0dff0d0d0dff0d0d0dff0c0c0cff121212ff171717ff171717ff171717ff171717ff161616ff141414ff1a1a1aff2a2a2aff393939ff373737ff363636ff363636ff363636a537373705ffffff0135353521363636ff363636ff363636ff3a3a3aff313131ff1c1c1cff0a0a0aff0a0a0aff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0f0f0fff171717ff171717ff171717ff171717ff161616ff151515ff161616ff282828ff363636ff383838ff363636ff333333ff3d3d3ddbffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01444444a9353535ff383838ff313131ff151515ff080808ff0b0b0bff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff121212ff171717ff171717ff171717ff171717ff171717ff171717ff161616ff131313ff1b1b1bff2d2d2dff373737ff373737ff363636a537373705ffffff0134343421363636ff383838ff333333ff1e1e1eff090909ff0a0a0aff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0f0f0fff171717ff171717ff171717ff171717ff171717ff171717ff171717ff131313ff171717ff2a2a2aff363636ff353535ff3d3d3ddbffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01444444af353535ff1e1e1eff0d0d0dff0a0a0aff0c0c0cff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff121212ff171717ff171717ff171717ff171717ff171717ff171717ff171717ff171717ff151515ff151515ff222222ff333333ff353535ad30303007ffffff0134343423373737ff282828ff0d0d0dff0a0a0aff0c0c0cff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0f0f0fff171717ff171717ff171717ff171717ff171717ff171717ff171717ff171717ff151515ff141414ff1b1b1bff2e2e2eff3e3e3ee1ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff013e3e3e6f0f0f0fd5040404ff0b0b0bff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff121212ff171717ff171717ff171717ff171717ff171717ff171717ff171717ff171717ff171717ff171717ff101010ff0e0e0ee72f2f2f7347474703ffffff013b3b3b13141414cd050505f70a0a0aff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0f0f0fff171717ff171717ff171717ff171717ff171717ff171717ff171717ff171717ff171717ff171717ff121212ff0c0c0cf12a2a2aa5ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff015f5f5f052020202b1a1a1aa1080808f1070707ff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff121212ff171717ff171717ff171717ff171717ff171717ff171717ff171717ff171717ff141414ff0c0c0cff212121af2a2a2a496d6d6d07ffffff01ffffff01ffffff01333333231d1d1d730b0b0beb060606ff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0f0f0fff171717ff171717ff171717ff171717ff171717ff171717ff171717ff171717ff151515ff0e0e0eff181818d72626265546464615ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff014d4d4d29121212af080808ef0a0a0aff0c0c0cff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff121212ff171717ff171717ff171717ff171717ff171717ff171717ff141414ff121212f9141414b93b3b3b4fffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0138383819151515890a0a0ae5080808ff0c0c0cff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0f0f0fff171717ff171717ff171717ff171717ff171717ff171717ff161616ff101010fb151515d72c2c2c614444440dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0133333311262626510f0f0fd7050505ff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff121212ff171717ff171717ff171717ff171717ff171717ff101010ff141414e7242424733a3a3a19ffffff01ffffff01ffffff01878787097272725f4d4d4d736a6a6a11ffffff01ffffff01ffffff016060600524242445191919ad040404ff0a0a0aff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0f0f0fff171717ff171717ff171717ff171717ff171717ff111111ff0e0e0efd242424873232322dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff015c5c5c0d2525255f090909d7080808fb0b0b0bff0d0d0dff0c0c0cff121212ff171717ff171717ff161616ff121212ff121212df2121218965656511ffffff01ffffff01ffffff018080800d6767674b646464d1606060ff454545ff464646df4f4f4f6165656517ffffff01ffffff01ffffff01ffffff012d2d2d4b101010b5060606fb0a0a0aff0d0d0dff0d0d0dff0f0f0fff171717ff171717ff161616ff131313ff101010ef2020209d4242422dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff012c2c2c2d1f1f1f83080808fb080808ff0d0d0dff121212ff171717ff141414ff0f0f0ff91e1e1eb12c2c2c354d4d4d09ffffff01ffffff01ffffff0178787825646464a75f5f5feb616161ff656565ff4a4a4aff414141ff424242f3414141bd69696937ffffff01ffffff01ffffff01ffffff0142424219171717710d0d0de3060606ff0c0c0cff0f0f0fff171717ff151515ff0d0d0dff171717c3292929575656560dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff013737372d1212129d080808ef0d0d0dff121212f5191919bf2e2e2e3d70707003ffffff01ffffff018c8c8c037676762564646497606060ed606060ff636363ff636363ff656565ff4a4a4aff444444ff464646ff444444ff404040f74a4a4aad5555553162626207ffffff01ffffff01ffffff014040401125252589090909dd0a0a0aff121212ff141414c738383869ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff015b5b5b0b1f1f1f591d1d1daf292929673f3f3f19ffffff01ffffff01ffffff01ffffff016d6d6d715f5f5fcd606060ff626262ff636363ff636363ff636363ff656565ff4a4a4aff444444ff464646ff464646ff454545ff434343ff414141db4f4f4f857b7b7b11ffffff01ffffff01ffffff0153535307222222331d1d1da91b1b1b8d4141412365656503ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff017c7c7c0f6868685d636363cb5e5e5eff626262ff636363ff636363ff636363ff636363ff636363ff656565ff4a4a4aff444444ff464646ff464646ff464646ff464646ff464646ff404040ff454545e14c4c4c6b69696917ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0177777733626262a3606060f3616161ff636363ff636363ff636363ff636363ff636363ff636363ff636363ff656565ff4a4a4aff444444ff464646ff464646ff464646ff464646ff464646ff464646ff444444ff424242f9454545b55d5d5d49ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff014b4b4b0f5e5e5e85626262ff626262ff636363ff636363ff636363ff636363ff636363ff636363ff636363ff636363ff636363ff656565ff4a4a4aff444444ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff444444ff414141ff454545a16464641dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0132323225333333cf4e4e4eff646464ff666666ff636363ff636363ff636363ff636363ff636363ff636363ff636363ff636363ff656565ff4a4a4aff444444ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff474747ff404040ff303030e35757573bffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0137373723363636cd313131ff363636ff515151ff636363ff656565ff636363ff636363ff636363ff636363ff636363ff636363ff656565ff4a4a4aff444444ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff414141ff373737ff343434ff323232e159595939ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0137373723363636cd363636ff343434ff333333ff3c3c3cff5b5b5bff686868ff636363ff626262ff636363ff636363ff636363ff656565ff4a4a4aff444444ff464646ff464646ff454545ff464646ff4c4c4cff454545ff393939ff353535ff353535ff353535ff323232e159595939ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0137373723363636cd363636ff363636ff363636ff353535ff313131ff3f3f3fff5d5d5dff666666ff646464ff626262ff636363ff656565ff4a4a4aff444444ff454545ff474747ff4a4a4aff404040ff212121ff2f2f2fff373737ff373737ff353535ff363636ff323232e159595939ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0137373723363636cd363636ff363636ff363636ff363636ff353535ff333333ff363636ff484848ff646464ff676767ff626262ff656565ff4a4a4aff444444ff4b4b4bff4a4a4aff262626ff0b0b0bff090909ff171717ff252525ff353535ff393939ff363636ff323232e159595939ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0137373723363636cd363636ff363636ff363636ff363636ff363636ff363636ff363636ff323232ff363636ff4c4c4cff646464ff676767ff4d4d4dff484848ff2c2c2cff0b0b0bff020202ff040404ff0b0b0bff171717ff141414ff161616ff282828ff353535ff343434e359595939ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0137373723363636cd363636ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff343434ff323232ff3f3f3fff5f5f5fff3a3a3aff161616ff030303ff030303ff050505ff040404ff0b0b0bff171717ff171717ff161616ff151515ff1a1a1aff242424e55555553bffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0137373723363636cd363636ff363636ff363636ff363636ff363636ff363636ff363636ff353535ff363636ff383838ff2e2e2eff191919ff262626ff111111ff030303ff030303ff050505ff040404ff0b0b0bff171717ff171717ff151515ff111111f9121212cd272727557d7d7d09ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0137373723363636cd363636ff363636ff363636ff363636ff363636ff363636ff363636ff383838ff373737ff242424ff0b0b0bff0a0a0aff393939ff393939ff222222ff080808ff020202ff030303ff0b0b0bff181818ff0f0f0fff151515f32424247935353525ffffff01ffffff01ffffff01a3a3a30fffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0137373723363636cd363636ff363636ff363636ff363636ff363636ff383838ff373737ff272727ff0c0c0cff090909ff0c0c0cff0e0e0eff373737ff363636ff3a3a3aff393939ff1e1e1eff080808ff080808ff0f0f0feb232323914040401dffffff01ffffff01ffffff01ffffff01ffffff018282825d626262c36d6d6d4d8d8d8d09ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0137373723363636cd363636ff363636ff353535ff363636ff3a3a3aff2f2f2fff131313ff0b0b0bff0b0b0bff0d0d0dff0c0c0cff0e0e0eff373737ff363636ff353535ff363636ff393939ff303030ff1c1c1cc92626264d68686807ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01868686515e5e5eff646464e9696969957878781fffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0137373723363636cd363636ff373737ff383838ff313131ff161616ff090909ff0b0b0bff0d0d0dff0d0d0dff0d0d0dff0c0c0cff0e0e0eff373737ff363636ff363636ff363636ff353535ff353535ff3c3c3c8fffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0186868651616161ff676767ff646464ff656565f16a6a6a7d7f7f7f25ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0137373723353535cd393939ff373737ff1f1f1fff0d0d0dff0a0a0aff0c0c0cff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff0e0e0eff373737ff363636ff363636ff363636ff363636ff353535ff37373791ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0186868651616161ff676767ff666666ff676767ff686868f9555555cd55555511ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0134343425323232cf212121ff0e0e0eff090909ff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff0e0e0eff383838ff363636ff363636ff363636ff363636ff353535ff37373791ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0186868651616161ff686868ff696969ff5f5f5fff3d3d3dff303030ff4848481dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01474747132323238f020202ff080808ff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff0c0c0cff2e2e2eff393939ff363636ff353535ff363636ff353535ff37373791ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0185858551666666ff676767ff494949ff353535ff323232ff353535ff4e4e4e1bffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0130303045101010af080808f70a0a0aff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff0d0d0dff131313ff1c1c1cff303030ff373737ff363636ff353535ff37373791ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0181818151494949ff363636ff313131ff363636ff353535ff363636ff4e4e4e1bffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0141414113191919690f0f0fdb060606ff0c0c0cff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff0d0d0dff171717ff151515ff161616ff222222ff363636ff383838ff37373791ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff014d4d4d53272727c1242424ff373737ff373737ff353535ff353535ff363636ff4e4e4e1bffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01626262091c1c1c830b0b0bd7090909ff0c0c0cff0d0d0dff0d0d0dff0c0c0cff0d0d0dff171717ff171717ff171717ff141414ff151515ff202020ff35353595ffffff01ffffff01ffffff01ffffff017474740540404049343434af2a2a2aff262626ff101010ff191919ff2e2e2eff373737ff363636ff363636ff4e4e4e1bffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff015a5a5a073636362d141414a7080808f5080808ff0d0d0dff0c0c0cff0d0d0dff171717ff171717ff171717ff151515ff0e0e0efb1b1b1bbb3d3d3d29ffffff01ffffff01ffffff0151515119393939892a2a2ae92d2d2dff323232ff282828ff141414ff151515ff151515ff1f1f1fff343434ff393939ff4949491dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff013636362f111111b5070707f30a0a0aff0d0d0dff171717ff141414ff111111f5111111c74343433d70707005ffffff01ffffff017c7c7c034e4e4e632a2a2af7292929ff323232ff313131ff323232ff282828ff141414ff171717ff171717ff151515ff0e0e0efd222222e153535315ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff012d2d2d151f1f1f590e0e0edb040404ff0f0f0fff171717e7262626673f3f3f1dffffff01ffffff01ffffff01ffffff01ffffff01444444293535358b2d2d2deb2b2b2bff313131ff323232ff282828ff141414ff171717ff121212ff0d0d0dff2222229d2626263dbebebe03ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01505050112626266f1d1d1d7f36363617ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01616161213333339d2c2c2ce92f2f2fff282828ff111111ff111111f7191919ab3c3c3c41ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff015151510b3b3b3b43383838c51f1f1fff141414d71e1e1e654f4f4f13ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff015858580b4d4d4d4159595909ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000` diff --git a/swarm/api/http/test_server.go b/swarm/api/http/test_server.go new file mode 100644 index 0000000000..9245c9c5b8 --- /dev/null +++ b/swarm/api/http/test_server.go @@ -0,0 +1,97 @@ +// Copyright 2017 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 http + +import ( + "io/ioutil" + "net/http" + "net/http/httptest" + "os" + "testing" + + "github.com/ethereum/go-ethereum/swarm/api" + "github.com/ethereum/go-ethereum/swarm/storage" + "github.com/ethereum/go-ethereum/swarm/storage/feed" +) + +type TestServer interface { + ServeHTTP(http.ResponseWriter, *http.Request) +} + +func NewTestSwarmServer(t *testing.T, serverFunc func(*api.API) TestServer, resolver api.Resolver) *TestSwarmServer { + dir, err := ioutil.TempDir("", "swarm-storage-test") + if err != nil { + t.Fatal(err) + } + storeparams := storage.NewDefaultLocalStoreParams() + storeparams.DbCapacity = 5000000 + storeparams.CacheCapacity = 5000 + storeparams.Init(dir) + localStore, err := storage.NewLocalStore(storeparams, nil) + if err != nil { + os.RemoveAll(dir) + t.Fatal(err) + } + fileStore := storage.NewFileStore(localStore, storage.NewFileStoreParams()) + + // Swarm feeds test setup + feedsDir, err := ioutil.TempDir("", "swarm-feeds-test") + if err != nil { + t.Fatal(err) + } + + rhparams := &feed.HandlerParams{} + rh, err := feed.NewTestHandler(feedsDir, rhparams) + if err != nil { + t.Fatal(err) + } + + a := api.NewAPI(fileStore, resolver, rh.Handler, nil) + srv := httptest.NewServer(serverFunc(a)) + tss := &TestSwarmServer{ + Server: srv, + FileStore: fileStore, + dir: dir, + Hasher: storage.MakeHashFunc(storage.DefaultHash)(), + cleanup: func() { + srv.Close() + rh.Close() + os.RemoveAll(dir) + os.RemoveAll(feedsDir) + }, + CurrentTime: 42, + } + feed.TimestampProvider = tss + return tss +} + +type TestSwarmServer struct { + *httptest.Server + Hasher storage.SwarmHash + FileStore *storage.FileStore + dir string + cleanup func() + CurrentTime uint64 +} + +func (t *TestSwarmServer) Close() { + t.cleanup() +} + +func (t *TestSwarmServer) Now() feed.Timestamp { + return feed.Timestamp{Time: t.CurrentTime} +} diff --git a/swarm/api/inspector.go b/swarm/api/inspector.go new file mode 100644 index 0000000000..ea3c4c0494 --- /dev/null +++ b/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/swarm/api/manifest.go b/swarm/api/manifest.go index 685a300fca..890ed88bd4 100644 --- a/swarm/api/manifest.go +++ b/swarm/api/manifest.go @@ -18,22 +18,27 @@ package api import ( "bytes" + "context" "encoding/json" "errors" "fmt" "io" "net/http" "strings" - "sync" "time" + "github.com/ethereum/go-ethereum/swarm/storage/feed" + "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/swarm/log" "github.com/ethereum/go-ethereum/swarm/storage" ) const ( - ManifestType = "application/bzz-manifest+json" + ManifestType = "application/bzz-manifest+json" + FeedContentType = "application/bzz-feed" + + manifestSizeLimit = 5 * 1024 * 1024 ) // Manifest represents a swarm manifest @@ -43,13 +48,15 @@ type Manifest struct { // ManifestEntry represents an entry in a swarm manifest type ManifestEntry struct { - Hash string `json:"hash,omitempty"` - Path string `json:"path,omitempty"` - ContentType string `json:"contentType,omitempty"` - Mode int64 `json:"mode,omitempty"` - Size int64 `json:"size,omitempty"` - ModTime time.Time `json:"mod_time,omitempty"` - Status int `json:"status,omitempty"` + Hash string `json:"hash,omitempty"` + Path string `json:"path,omitempty"` + ContentType string `json:"contentType,omitempty"` + Mode int64 `json:"mode,omitempty"` + Size int64 `json:"size,omitempty"` + ModTime time.Time `json:"mod_time,omitempty"` + Status int `json:"status,omitempty"` + Access *AccessEntry `json:"access,omitempty"` + Feed *feed.Feed `json:"feed,omitempty"` } // ManifestList represents the result of listing files in a manifest @@ -59,40 +66,76 @@ type ManifestList struct { } // NewManifest creates and stores a new, empty manifest -func (a *Api) NewManifest() (storage.Key, error) { +func (a *API) NewManifest(ctx context.Context, toEncrypt bool) (storage.Address, error) { var manifest Manifest data, err := json.Marshal(&manifest) if err != nil { return nil, err } - return a.Store(bytes.NewReader(data), int64(len(data)), &sync.WaitGroup{}) + addr, wait, err := a.Store(ctx, bytes.NewReader(data), int64(len(data)), toEncrypt) + if err != nil { + return nil, err + } + err = wait(ctx) + return addr, err +} + +// Manifest hack for supporting Swarm feeds from the bzz: scheme +// see swarm/api/api.go:API.Get() for more information +func (a *API) NewFeedManifest(ctx context.Context, feed *feed.Feed) (storage.Address, error) { + var manifest Manifest + entry := ManifestEntry{ + Feed: feed, + ContentType: FeedContentType, + } + manifest.Entries = append(manifest.Entries, entry) + data, err := json.Marshal(&manifest) + if err != nil { + return nil, err + } + addr, wait, err := a.Store(ctx, bytes.NewReader(data), int64(len(data)), false) + if err != nil { + return nil, err + } + err = wait(ctx) + return addr, err } // ManifestWriter is used to add and remove entries from an underlying manifest type ManifestWriter struct { - api *Api + api *API trie *manifestTrie quitC chan bool } -func (a *Api) NewManifestWriter(key storage.Key, quitC chan bool) (*ManifestWriter, error) { - trie, err := loadManifest(a.dpa, key, quitC) +func (a *API) NewManifestWriter(ctx context.Context, addr storage.Address, quitC chan bool) (*ManifestWriter, error) { + trie, err := loadManifest(ctx, a.fileStore, addr, quitC, NOOPDecrypt) if err != nil { - return nil, fmt.Errorf("error loading manifest %s: %s", key, err) + return nil, fmt.Errorf("error loading manifest %s: %s", addr, err) } return &ManifestWriter{a, trie, quitC}, nil } -// AddEntry stores the given data and adds the resulting key to the manifest -func (m *ManifestWriter) AddEntry(data io.Reader, e *ManifestEntry) (storage.Key, error) { - key, err := m.api.Store(data, e.Size, nil) - if err != nil { - return nil, err - } +// AddEntry stores the given data and adds the resulting address to the manifest +func (m *ManifestWriter) AddEntry(ctx context.Context, data io.Reader, e *ManifestEntry) (addr storage.Address, err error) { entry := newManifestTrieEntry(e, nil) - entry.Hash = key.String() + if data != nil { + var wait func(context.Context) error + addr, wait, err = m.api.Store(ctx, data, e.Size, m.trie.encrypted) + if err != nil { + return nil, err + } + err = wait(ctx) + if err != nil { + return nil, err + } + entry.Hash = addr.Hex() + } + if entry.Hash == "" { + return addr, errors.New("missing entry hash") + } m.trie.addEntry(entry, m.quitC) - return key, nil + return addr, nil } // RemoveEntry removes the given path from the manifest @@ -101,30 +144,30 @@ func (m *ManifestWriter) RemoveEntry(path string) error { return nil } -// Store stores the manifest, returning the resulting storage key -func (m *ManifestWriter) Store() (storage.Key, error) { - return m.trie.hash, m.trie.recalcAndStore() +// Store stores the manifest, returning the resulting storage address +func (m *ManifestWriter) Store() (storage.Address, error) { + return m.trie.ref, m.trie.recalcAndStore() } // ManifestWalker is used to recursively walk the entries in the manifest and // all of its submanifests type ManifestWalker struct { - api *Api + api *API trie *manifestTrie quitC chan bool } -func (a *Api) NewManifestWalker(key storage.Key, quitC chan bool) (*ManifestWalker, error) { - trie, err := loadManifest(a.dpa, key, quitC) +func (a *API) NewManifestWalker(ctx context.Context, addr storage.Address, decrypt DecryptFunc, quitC chan bool) (*ManifestWalker, error) { + trie, err := loadManifest(ctx, a.fileStore, addr, quitC, decrypt) if err != nil { - return nil, fmt.Errorf("error loading manifest %s: %s", key, err) + return nil, fmt.Errorf("error loading manifest %s: %s", addr, err) } return &ManifestWalker{a, trie, quitC}, nil } -// SkipManifest is used as a return value from WalkFn to indicate that the +// ErrSkipManifest is used as a return value from WalkFn to indicate that the // manifest should be skipped -var SkipManifest = errors.New("skip this manifest") +var ErrSkipManifest = errors.New("skip this manifest") // WalkFn is the type of function called for each entry visited by a recursive // manifest walk @@ -137,14 +180,14 @@ func (m *ManifestWalker) Walk(walkFn WalkFn) error { } func (m *ManifestWalker) walk(trie *manifestTrie, prefix string, walkFn WalkFn) error { - for _, entry := range trie.entries { + for _, entry := range &trie.entries { if entry == nil { continue } entry.Path = prefix + entry.Path err := walkFn(&entry.ManifestEntry) if err != nil { - if entry.ContentType == ManifestType && err == SkipManifest { + if entry.ContentType == ManifestType && err == ErrSkipManifest { continue } return err @@ -163,9 +206,11 @@ func (m *ManifestWalker) walk(trie *manifestTrie, prefix string, walkFn WalkFn) } type manifestTrie struct { - dpa *storage.DPA - entries [257]*manifestTrieEntry // indexed by first character of basePath, entries[256] is the empty basePath entry - hash storage.Key // if hash != nil, it is stored + fileStore *storage.FileStore + entries [257]*manifestTrieEntry // indexed by first character of basePath, entries[256] is the empty basePath entry + ref storage.Address // if ref != nil, it is stored + encrypted bool + decrypt DecryptFunc } func newManifestTrieEntry(entry *ManifestEntry, subtrie *manifestTrie) *manifestTrieEntry { @@ -181,68 +226,90 @@ type manifestTrieEntry struct { subtrie *manifestTrie } -func loadManifest(dpa *storage.DPA, hash storage.Key, quitC chan bool) (trie *manifestTrie, err error) { // non-recursive, subtrees are downloaded on-demand - - log.Trace(fmt.Sprintf("manifest lookup key: '%v'.", hash.Log())) - // retrieve manifest via DPA - manifestReader := dpa.Retrieve(hash) - return readManifest(manifestReader, hash, dpa, quitC) +func loadManifest(ctx context.Context, fileStore *storage.FileStore, addr storage.Address, quitC chan bool, decrypt DecryptFunc) (trie *manifestTrie, err error) { // non-recursive, subtrees are downloaded on-demand + log.Trace("manifest lookup", "addr", addr) + // retrieve manifest via FileStore + manifestReader, isEncrypted := fileStore.Retrieve(ctx, addr) + log.Trace("reader retrieved", "addr", addr) + return readManifest(manifestReader, addr, fileStore, isEncrypted, quitC, decrypt) } -func readManifest(manifestReader storage.LazySectionReader, hash storage.Key, dpa *storage.DPA, quitC chan bool) (trie *manifestTrie, err error) { // non-recursive, subtrees are downloaded on-demand +func readManifest(mr storage.LazySectionReader, addr storage.Address, fileStore *storage.FileStore, isEncrypted bool, quitC chan bool, decrypt DecryptFunc) (trie *manifestTrie, err error) { // non-recursive, subtrees are downloaded on-demand // TODO check size for oversized manifests - size, err := manifestReader.Size(quitC) + size, err := mr.Size(mr.Context(), quitC) if err != nil { // size == 0 // can't determine size means we don't have the root chunk + log.Trace("manifest not found", "addr", addr) err = fmt.Errorf("Manifest not Found") return } + if size > manifestSizeLimit { + log.Warn("manifest exceeds size limit", "addr", addr, "size", size, "limit", manifestSizeLimit) + err = fmt.Errorf("Manifest size of %v bytes exceeds the %v byte limit", size, manifestSizeLimit) + return + } manifestData := make([]byte, size) - read, err := manifestReader.Read(manifestData) + read, err := mr.Read(manifestData) if int64(read) < size { - log.Trace(fmt.Sprintf("Manifest %v not found.", hash.Log())) + log.Trace("manifest not found", "addr", addr) if err == nil { err = fmt.Errorf("Manifest retrieval cut short: read %v, expect %v", read, size) } return } - log.Trace(fmt.Sprintf("Manifest %v retrieved", hash.Log())) + log.Debug("manifest retrieved", "addr", addr) var man struct { Entries []*manifestTrieEntry `json:"entries"` } err = json.Unmarshal(manifestData, &man) if err != nil { - err = fmt.Errorf("Manifest %v is malformed: %v", hash.Log(), err) - log.Trace(fmt.Sprintf("%v", err)) + err = fmt.Errorf("Manifest %v is malformed: %v", addr.Log(), err) + log.Trace("malformed manifest", "addr", addr) return } - log.Trace(fmt.Sprintf("Manifest %v has %d entries.", hash.Log(), len(man.Entries))) + log.Trace("manifest entries", "addr", addr, "len", len(man.Entries)) trie = &manifestTrie{ - dpa: dpa, + fileStore: fileStore, + encrypted: isEncrypted, + decrypt: decrypt, } for _, entry := range man.Entries { - trie.addEntry(entry, quitC) + err = trie.addEntry(entry, quitC) + if err != nil { + return + } } return } -func (self *manifestTrie) addEntry(entry *manifestTrieEntry, quitC chan bool) { - self.hash = nil // trie modified, hash needs to be re-calculated on demand +func (mt *manifestTrie) addEntry(entry *manifestTrieEntry, quitC chan bool) error { + mt.ref = nil // trie modified, hash needs to be re-calculated on demand + + if entry.ManifestEntry.Access != nil { + if mt.decrypt == nil { + return errors.New("dont have decryptor") + } + + err := mt.decrypt(&entry.ManifestEntry) + if err != nil { + return err + } + } if len(entry.Path) == 0 { - self.entries[256] = entry - return + mt.entries[256] = entry + return nil } b := entry.Path[0] - oldentry := self.entries[b] + oldentry := mt.entries[b] if (oldentry == nil) || (oldentry.Path == entry.Path && oldentry.ContentType != ManifestType) { - self.entries[b] = entry - return + mt.entries[b] = entry + return nil } cpl := 0 @@ -251,33 +318,35 @@ func (self *manifestTrie) addEntry(entry *manifestTrieEntry, quitC chan bool) { } if (oldentry.ContentType == ManifestType) && (cpl == len(oldentry.Path)) { - if self.loadSubTrie(oldentry, quitC) != nil { - return + if mt.loadSubTrie(oldentry, quitC) != nil { + return nil } entry.Path = entry.Path[cpl:] oldentry.subtrie.addEntry(entry, quitC) oldentry.Hash = "" - return + return nil } commonPrefix := entry.Path[:cpl] subtrie := &manifestTrie{ - dpa: self.dpa, + fileStore: mt.fileStore, + encrypted: mt.encrypted, } entry.Path = entry.Path[cpl:] oldentry.Path = oldentry.Path[cpl:] subtrie.addEntry(entry, quitC) subtrie.addEntry(oldentry, quitC) - self.entries[b] = newManifestTrieEntry(&ManifestEntry{ + mt.entries[b] = newManifestTrieEntry(&ManifestEntry{ Path: commonPrefix, ContentType: ManifestType, }, subtrie) + return nil } -func (self *manifestTrie) getCountLast() (cnt int, entry *manifestTrieEntry) { - for _, e := range self.entries { +func (mt *manifestTrie) getCountLast() (cnt int, entry *manifestTrieEntry) { + for _, e := range &mt.entries { if e != nil { cnt++ entry = e @@ -286,27 +355,27 @@ func (self *manifestTrie) getCountLast() (cnt int, entry *manifestTrieEntry) { return } -func (self *manifestTrie) deleteEntry(path string, quitC chan bool) { - self.hash = nil // trie modified, hash needs to be re-calculated on demand +func (mt *manifestTrie) deleteEntry(path string, quitC chan bool) { + mt.ref = nil // trie modified, hash needs to be re-calculated on demand if len(path) == 0 { - self.entries[256] = nil + mt.entries[256] = nil return } b := path[0] - entry := self.entries[b] + entry := mt.entries[b] if entry == nil { return } if entry.Path == path { - self.entries[b] = nil + mt.entries[b] = nil return } epl := len(entry.Path) if (entry.ContentType == ManifestType) && (len(path) >= epl) && (path[:epl] == entry.Path) { - if self.loadSubTrie(entry, quitC) != nil { + if mt.loadSubTrie(entry, quitC) != nil { return } entry.subtrie.deleteEntry(path[epl:], quitC) @@ -317,13 +386,13 @@ func (self *manifestTrie) deleteEntry(path string, quitC chan bool) { if lastentry != nil { lastentry.Path = entry.Path + lastentry.Path } - self.entries[b] = lastentry + mt.entries[b] = lastentry } } } -func (self *manifestTrie) recalcAndStore() error { - if self.hash != nil { +func (mt *manifestTrie) recalcAndStore() error { + if mt.ref != nil { return nil } @@ -331,14 +400,14 @@ func (self *manifestTrie) recalcAndStore() error { buffer.WriteString(`{"entries":[`) list := &Manifest{} - for _, entry := range self.entries { + for _, entry := range &mt.entries { if entry != nil { if entry.Hash == "" { // TODO: paralellize err := entry.subtrie.recalcAndStore() if err != nil { return err } - entry.Hash = entry.subtrie.hash.String() + entry.Hash = entry.subtrie.ref.Hex() } list.Entries = append(list.Entries, entry.ManifestEntry) } @@ -351,23 +420,37 @@ func (self *manifestTrie) recalcAndStore() error { } sr := bytes.NewReader(manifest) - wg := &sync.WaitGroup{} - key, err2 := self.dpa.Store(sr, int64(len(manifest)), wg, nil) - wg.Wait() - self.hash = key + ctx := context.TODO() + addr, wait, err2 := mt.fileStore.Store(ctx, sr, int64(len(manifest)), mt.encrypted) + if err2 != nil { + return err2 + } + err2 = wait(ctx) + mt.ref = addr return err2 } -func (self *manifestTrie) loadSubTrie(entry *manifestTrieEntry, quitC chan bool) (err error) { +func (mt *manifestTrie) loadSubTrie(entry *manifestTrieEntry, quitC chan bool) (err error) { + if entry.ManifestEntry.Access != nil { + if mt.decrypt == nil { + return errors.New("dont have decryptor") + } + + err := mt.decrypt(&entry.ManifestEntry) + if err != nil { + return err + } + } + if entry.subtrie == nil { hash := common.Hex2Bytes(entry.Hash) - entry.subtrie, err = loadManifest(self.dpa, hash, quitC) + entry.subtrie, err = loadManifest(context.TODO(), mt.fileStore, hash, quitC, mt.decrypt) entry.Hash = "" // might not match, should be recalculated } return } -func (self *manifestTrie) listWithPrefixInt(prefix, rp string, quitC chan bool, cb func(entry *manifestTrieEntry, suffix string)) error { +func (mt *manifestTrie) listWithPrefixInt(prefix, rp string, quitC chan bool, cb func(entry *manifestTrieEntry, suffix string)) error { plen := len(prefix) var start, stop int if plen == 0 { @@ -384,7 +467,7 @@ func (self *manifestTrie) listWithPrefixInt(prefix, rp string, quitC chan bool, return fmt.Errorf("aborted") default: } - entry := self.entries[i] + entry := mt.entries[i] if entry != nil { epl := len(entry.Path) if entry.ContentType == ManifestType { @@ -393,7 +476,7 @@ func (self *manifestTrie) listWithPrefixInt(prefix, rp string, quitC chan bool, l = epl } if prefix[:l] == entry.Path[:l] { - err := self.loadSubTrie(entry, quitC) + err := mt.loadSubTrie(entry, quitC) if err != nil { return err } @@ -412,23 +495,22 @@ func (self *manifestTrie) listWithPrefixInt(prefix, rp string, quitC chan bool, return nil } -func (self *manifestTrie) listWithPrefix(prefix string, quitC chan bool, cb func(entry *manifestTrieEntry, suffix string)) (err error) { - return self.listWithPrefixInt(prefix, "", quitC, cb) +func (mt *manifestTrie) listWithPrefix(prefix string, quitC chan bool, cb func(entry *manifestTrieEntry, suffix string)) (err error) { + return mt.listWithPrefixInt(prefix, "", quitC, cb) } -func (self *manifestTrie) findPrefixOf(path string, quitC chan bool) (entry *manifestTrieEntry, pos int) { - +func (mt *manifestTrie) findPrefixOf(path string, quitC chan bool) (entry *manifestTrieEntry, pos int) { log.Trace(fmt.Sprintf("findPrefixOf(%s)", path)) if len(path) == 0 { - return self.entries[256], 0 + return mt.entries[256], 0 } //see if first char is in manifest entries b := path[0] - entry = self.entries[b] + entry = mt.entries[b] if entry == nil { - return self.entries[256], 0 + return mt.entries[256], 0 } epl := len(entry.Path) @@ -436,7 +518,7 @@ func (self *manifestTrie) findPrefixOf(path string, quitC chan bool) (entry *man if len(path) <= epl { if entry.Path[:len(path)] == path { if entry.ContentType == ManifestType { - err := self.loadSubTrie(entry, quitC) + err := mt.loadSubTrie(entry, quitC) if err == nil && entry.subtrie != nil { subentries := entry.subtrie.entries for i := 0; i < len(subentries); i++ { @@ -457,7 +539,7 @@ func (self *manifestTrie) findPrefixOf(path string, quitC chan bool) (entry *man log.Trace(fmt.Sprintf("entry.ContentType = %v", entry.ContentType)) //the subentry is a manifest, load subtrie if entry.ContentType == ManifestType && (strings.Contains(entry.Path, path) || strings.Contains(path, entry.Path)) { - err := self.loadSubTrie(entry, quitC) + err := mt.loadSubTrie(entry, quitC) if err != nil { return nil, 0 } @@ -475,10 +557,9 @@ func (self *manifestTrie) findPrefixOf(path string, quitC chan bool) (entry *man if path != entry.Path { return nil, 0 } - pos = epl } } - return + return nil, 0 } // file system manifest always contains regularized paths @@ -495,10 +576,10 @@ func RegularSlashes(path string) (res string) { return } -func (self *manifestTrie) getEntry(spath string) (entry *manifestTrieEntry, fullpath string) { +func (mt *manifestTrie) getEntry(spath string) (entry *manifestTrieEntry, fullpath string) { path := RegularSlashes(spath) var pos int quitC := make(chan bool) - entry, pos = self.findPrefixOf(path, quitC) + entry, pos = mt.findPrefixOf(path, quitC) return entry, path[:pos] } diff --git a/swarm/api/manifest_test.go b/swarm/api/manifest_test.go index 7098ca16fd..1c8e53c433 100644 --- a/swarm/api/manifest_test.go +++ b/swarm/api/manifest_test.go @@ -42,7 +42,9 @@ func manifest(paths ...string) (manifestReader storage.LazySectionReader) { func testGetEntry(t *testing.T, path, match string, multiple bool, paths ...string) *manifestTrie { quitC := make(chan bool) - trie, err := readManifest(manifest(paths...), nil, nil, quitC) + fileStore := storage.NewFileStore(nil, storage.NewFileStoreParams()) + ref := make([]byte, fileStore.HashSize()) + trie, err := readManifest(manifest(paths...), ref, fileStore, false, quitC, NOOPDecrypt) if err != nil { t.Errorf("unexpected error making manifest: %v", err) } @@ -97,7 +99,9 @@ func TestGetEntry(t *testing.T) { func TestExactMatch(t *testing.T) { quitC := make(chan bool) mf := manifest("shouldBeExactMatch.css", "shouldBeExactMatch.css.map") - trie, err := readManifest(mf, nil, nil, quitC) + fileStore := storage.NewFileStore(nil, storage.NewFileStoreParams()) + ref := make([]byte, fileStore.HashSize()) + trie, err := readManifest(mf, ref, fileStore, false, quitC, nil) if err != nil { t.Errorf("unexpected error making manifest: %v", err) } @@ -128,7 +132,9 @@ func TestAddFileWithManifestPath(t *testing.T) { reader := &storage.LazyTestSectionReader{ SectionReader: io.NewSectionReader(bytes.NewReader(manifest), 0, int64(len(manifest))), } - trie, err := readManifest(reader, nil, nil, nil) + fileStore := storage.NewFileStore(nil, storage.NewFileStoreParams()) + ref := make([]byte, fileStore.HashSize()) + trie, err := readManifest(reader, ref, fileStore, false, nil, NOOPDecrypt) if err != nil { t.Fatal(err) } @@ -144,3 +150,26 @@ func TestAddFileWithManifestPath(t *testing.T) { checkEntry(t, "ac", "ac", false, trie) checkEntry(t, "a", "a", false, trie) } + +// TestReadManifestOverSizeLimit creates a manifest reader with data longer then +// manifestSizeLimit and checks if readManifest function will return the exact error +// message. +// The manifest data is not in json-encoded format, preventing possbile +// successful parsing attempts if limit check fails. +func TestReadManifestOverSizeLimit(t *testing.T) { + manifest := make([]byte, manifestSizeLimit+1) + reader := &storage.LazyTestSectionReader{ + SectionReader: io.NewSectionReader(bytes.NewReader(manifest), 0, int64(len(manifest))), + } + _, err := readManifest(reader, storage.Address{}, nil, false, nil, NOOPDecrypt) + if err == nil { + t.Fatal("got no error from readManifest") + } + // Error message is part of the http response body + // which justifies exact string validation. + got := err.Error() + want := fmt.Sprintf("Manifest size of %v bytes exceeds the %v byte limit", len(manifest), manifestSizeLimit) + if got != want { + t.Fatalf("got error mesage %q, expected %q", got, want) + } +} diff --git a/swarm/api/storage.go b/swarm/api/storage.go index 0e3abecfe4..254375b777 100644 --- a/swarm/api/storage.go +++ b/swarm/api/storage.go @@ -16,7 +16,12 @@ package api -import "path" +import ( + "context" + "path" + + "github.com/ethereum/go-ethereum/swarm/storage" +) type Response struct { MimeType string @@ -30,10 +35,10 @@ type Response struct { // // DEPRECATED: Use the HTTP API instead type Storage struct { - api *Api + api *API } -func NewStorage(api *Api) *Storage { +func NewStorage(api *API) *Storage { return &Storage{api} } @@ -41,12 +46,8 @@ func NewStorage(api *Api) *Storage { // its content type // // DEPRECATED: Use the HTTP API instead -func (self *Storage) Put(content, contentType string) (string, error) { - key, err := self.api.Put(content, contentType) - if err != nil { - return "", err - } - return key.String(), err +func (s *Storage) Put(ctx context.Context, content string, contentType string, toEncrypt bool) (storage.Address, func(context.Context) error, error) { + return s.api.Put(ctx, content, contentType, toEncrypt) } // Get retrieves the content from bzzpath and reads the response in full @@ -57,21 +58,21 @@ func (self *Storage) Put(content, contentType string) (string, error) { // size is resp.Size // // DEPRECATED: Use the HTTP API instead -func (self *Storage) Get(bzzpath string) (*Response, error) { +func (s *Storage) Get(ctx context.Context, bzzpath string) (*Response, error) { uri, err := Parse(path.Join("bzz:/", bzzpath)) if err != nil { return nil, err } - key, err := self.api.Resolve(uri) + addr, err := s.api.Resolve(ctx, uri.Addr) if err != nil { return nil, err } - reader, mimeType, status, err := self.api.Get(key, uri.Path) + reader, mimeType, status, _, err := s.api.Get(ctx, nil, addr, uri.Path) if err != nil { return nil, err } quitC := make(chan bool) - expsize, err := reader.Size(quitC) + expsize, err := reader.Size(ctx, quitC) if err != nil { return nil, err } @@ -82,23 +83,3 @@ func (self *Storage) Get(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 (self *Storage) Modify(rootHash, path, contentHash, contentType string) (newRootHash string, err error) { - uri, err := Parse("bzz:/" + rootHash) - if err != nil { - return "", err - } - key, err := self.api.Resolve(uri) - if err != nil { - return "", err - } - key, err = self.api.Modify(key, path, contentHash, contentType) - if err != nil { - return "", err - } - return key.String(), nil -} diff --git a/swarm/api/storage_test.go b/swarm/api/storage_test.go index d260dd61d8..ef96972b68 100644 --- a/swarm/api/storage_test.go +++ b/swarm/api/storage_test.go @@ -17,30 +17,37 @@ package api import ( + "context" "testing" ) -func testStorage(t *testing.T, f func(*Storage)) { - testApi(t, func(api *Api) { - f(NewStorage(api)) +func testStorage(t *testing.T, f func(*Storage, bool)) { + testAPI(t, func(api *API, toEncrypt bool) { + f(NewStorage(api), toEncrypt) }) } func TestStoragePutGet(t *testing.T) { - testStorage(t, func(api *Storage) { + testStorage(t, func(api *Storage, toEncrypt bool) { content := "hello" exp := expResponse(content, "text/plain", 0) // exp := expResponse([]byte(content), "text/plain", 0) - bzzhash, err := api.Put(content, exp.MimeType) + ctx := context.TODO() + bzzkey, wait, err := api.Put(ctx, content, exp.MimeType, toEncrypt) if err != nil { t.Fatalf("unexpected error: %v", err) } - // to check put against the Api#Get + err = wait(ctx) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + bzzhash := bzzkey.Hex() + // to check put against the API#Get resp0 := testGet(t, api.api, bzzhash, "") checkResponse(t, resp0, exp) // check storage#Get - resp, err := api.Get(bzzhash) + resp, err := api.Get(context.TODO(), bzzhash) if err != nil { t.Fatalf("unexpected error: %v", err) } diff --git a/swarm/api/testdata/test0/img/logo.png b/swarm/api/testdata/test0/img/logo.png index e0fb15ab33..9557f96053 100644 Binary files a/swarm/api/testdata/test0/img/logo.png and b/swarm/api/testdata/test0/img/logo.png differ diff --git a/swarm/api/uri.go b/swarm/api/uri.go index d8aafedf41..09cfa45020 100644 --- a/swarm/api/uri.go +++ b/swarm/api/uri.go @@ -19,9 +19,17 @@ package api import ( "fmt" "net/url" + "regexp" "strings" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/swarm/storage" ) +//matches hex swarm hashes +// TODO: this is bad, it should not be hardcoded how long is a hash +var hashMatcher = regexp.MustCompile("^([0-9A-Fa-f]{64})([0-9A-Fa-f]{64})?$") + // URI is a reference to content stored in swarm. type URI struct { // Scheme has one of the following values: @@ -32,22 +40,32 @@ type URI struct { // (address is not resolved) // * bzz-list - list of all files contained in a swarm manifest // - // Deprecated Schemes: - // * bzzr - raw swarm content - // * bzzi - immutable URI of an entry in a swarm manifest - // (address is not resolved) - // * bzz-hash - hash of swarm content - // Scheme string - // Addr is either a hexadecimal storage key or it an address which - // resolves to a storage key + // Addr is either a hexadecimal storage address or it an address which + // resolves to a storage address Addr string + // addr stores the parsed storage address + addr storage.Address + // Path is the path to the content within a swarm manifest Path string } +func (u *URI) MarshalJSON() (out []byte, err error) { + return []byte(`"` + u.String() + `"`), nil +} + +func (u *URI) UnmarshalJSON(value []byte) error { + uri, err := Parse(string(value)) + if err != nil { + return err + } + *u = *uri + return nil +} + // Parse parses rawuri into a URI struct, where rawuri is expected to have one // of the following formats: // @@ -59,7 +77,6 @@ type URI struct { // * :/// // // with scheme one of bzz, bzz-raw, bzz-immutable, bzz-list or bzz-hash -// or deprecated ones bzzr and bzzi func Parse(rawuri string) (*URI, error) { u, err := url.Parse(rawuri) if err != nil { @@ -69,7 +86,7 @@ func Parse(rawuri string) (*URI, error) { // check the scheme is valid switch uri.Scheme { - case "bzz", "bzz-raw", "bzz-immutable", "bzz-list", "bzz-hash", "bzzr", "bzzi": + case "bzz", "bzz-raw", "bzz-immutable", "bzz-list", "bzz-hash", "bzz-feed": default: return nil, fmt.Errorf("unknown scheme %q", u.Scheme) } @@ -91,6 +108,9 @@ func Parse(rawuri string) (*URI, error) { } return uri, nil } +func (u *URI) Feed() bool { + return u.Scheme == "bzz-feed" +} func (u *URI) Raw() bool { return u.Scheme == "bzz-raw" @@ -104,14 +124,6 @@ func (u *URI) List() bool { return u.Scheme == "bzz-list" } -func (u *URI) DeprecatedRaw() bool { - return u.Scheme == "bzzr" -} - -func (u *URI) DeprecatedImmutable() bool { - return u.Scheme == "bzzi" -} - func (u *URI) Hash() bool { return u.Scheme == "bzz-hash" } @@ -119,3 +131,14 @@ func (u *URI) Hash() bool { func (u *URI) String() string { return u.Scheme + ":/" + u.Addr + "/" + u.Path } + +func (u *URI) Address() storage.Address { + if u.addr != nil { + return u.addr + } + if hashMatcher.MatchString(u.Addr) { + u.addr = common.Hex2Bytes(u.Addr) + return u.addr + } + return nil +} diff --git a/swarm/api/uri_test.go b/swarm/api/uri_test.go index 137b4505d4..a03874c433 100644 --- a/swarm/api/uri_test.go +++ b/swarm/api/uri_test.go @@ -17,21 +17,24 @@ package api import ( + "bytes" "reflect" "testing" + + "github.com/ethereum/go-ethereum/swarm/storage" ) 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 + uri string + expectURI *URI + expectErr bool + expectRaw bool + expectImmutable bool + expectList bool + expectHash bool + expectValidKey bool + expectAddr storage.Address } tests := []test{ { @@ -120,24 +123,17 @@ func TestParseURI(t *testing.T) { expectList: true, }, { - uri: "bzzr:", - expectURI: &URI{Scheme: "bzzr"}, - expectDeprecatedRaw: true, - }, - { - uri: "bzzr:/", - expectURI: &URI{Scheme: "bzzr"}, - expectDeprecatedRaw: true, - }, - { - uri: "bzzi:", - expectURI: &URI{Scheme: "bzzi"}, - expectDeprecatedImmutable: true, - }, - { - uri: "bzzi:/", - expectURI: &URI{Scheme: "bzzi"}, - expectDeprecatedImmutable: true, + uri: "bzz-raw://4378d19c26590f1a818ed7d6a62c3809e149b0999cab5ce5f26233b3b423bf8c", + expectURI: &URI{Scheme: "bzz-raw", + Addr: "4378d19c26590f1a818ed7d6a62c3809e149b0999cab5ce5f26233b3b423bf8c", + }, + expectValidKey: true, + expectRaw: true, + expectAddr: storage.Address{67, 120, 209, 156, 38, 89, 15, 26, + 129, 142, 215, 214, 166, 44, 56, 9, + 225, 73, 176, 153, 156, 171, 92, 229, + 242, 98, 51, 179, 180, 35, 191, 140, + }, }, } for _, x := range tests { @@ -166,11 +162,14 @@ func TestParseURI(t *testing.T) { if actual.Hash() != x.expectHash { t.Fatalf("expected %s hash to be %t, got %t", x.uri, x.expectHash, actual.Hash()) } - if actual.DeprecatedRaw() != x.expectDeprecatedRaw { - t.Fatalf("expected %s deprecated raw to be %t, got %t", x.uri, x.expectDeprecatedRaw, actual.DeprecatedRaw()) - } - if actual.DeprecatedImmutable() != x.expectDeprecatedImmutable { - t.Fatalf("expected %s deprecated immutable to be %t, got %t", x.uri, x.expectDeprecatedImmutable, actual.DeprecatedImmutable()) + if x.expectValidKey { + if actual.Address() == nil { + t.Fatalf("expected %s to return a valid key, got nil", x.uri) + } else { + if !bytes.Equal(x.expectAddr, actual.Address()) { + t.Fatalf("expected %s to be decoded to %v", x.expectURI.Addr, x.expectAddr) + } + } } } } diff --git a/swarm/bmt/bmt.go b/swarm/bmt/bmt.go new file mode 100644 index 0000000000..18eab5a2bc --- /dev/null +++ b/swarm/bmt/bmt.go @@ -0,0 +1,690 @@ +// 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 bmt provides a binary merkle tree implementation used for swarm chunk hash +package bmt + +import ( + "fmt" + "hash" + "strings" + "sync" + "sync/atomic" +) + +/* +Binary Merkle Tree Hash is a hash function over arbitrary datachunks of limited size. +It is defined as the root hash of the binary merkle tree built over fixed size segments +of the underlying chunk using any base hash function (e.g., keccak 256 SHA3). +Chunks with data shorter than the fixed size are hashed as if they had zero padding. + +BMT hash is used as the chunk hash function in swarm which in turn is the basis for the +128 branching swarm hash http://swarm-guide.readthedocs.io/en/latest/architecture.html#swarm-hash + +The BMT is optimal for providing compact inclusion proofs, i.e. prove that a +segment is a substring of a chunk starting at a particular offset. +The size of the underlying segments is fixed to the size of the base hash (called the resolution +of the BMT hash), Using Keccak256 SHA3 hash is 32 bytes, the EVM word size to optimize for on-chain BMT verification +as well as the hash size optimal for inclusion proofs in the merkle tree of the swarm hash. + +Two implementations are provided: + +* RefHasher is optimized for code simplicity and meant as a reference implementation + that is simple to understand +* Hasher is optimized for speed taking advantage of concurrency with minimalistic + control structure to coordinate the concurrent routines + + BMT Hasher implements the following interfaces + * standard golang hash.Hash - synchronous, reusable + * SwarmHash - SumWithSpan provided + * io.Writer - synchronous left-to-right datawriter + * AsyncWriter - concurrent section writes and asynchronous Sum call +*/ + +const ( + // PoolSize is the maximum number of bmt trees used by the hashers, i.e, + // the maximum number of concurrent BMT hashing operations performed by the same hasher + PoolSize = 8 +) + +// BaseHasherFunc is a hash.Hash constructor function used for the base hash of the BMT. +// implemented by Keccak256 SHA3 sha3.NewLegacyKeccak256 +type BaseHasherFunc func() hash.Hash + +// Hasher a reusable hasher for fixed maximum size chunks representing a BMT +// - implements the hash.Hash interface +// - reuses a pool of trees for amortised memory allocation and resource control +// - supports order-agnostic concurrent segment writes and section (double segment) writes +// as well as sequential read and write +// - the same hasher instance must not be called concurrently on more than one chunk +// - the same hasher instance is synchronously reuseable +// - Sum gives back the tree to the pool and guaranteed to leave +// the tree and itself in a state reusable for hashing a new chunk +// - generates and verifies segment inclusion proofs (TODO:) +type Hasher struct { + pool *TreePool // BMT resource pool + bmt *tree // prebuilt BMT resource for flowcontrol and proofs +} + +// New creates a reusable BMT Hasher that +// pulls a new tree from a resource pool for hashing each chunk +func New(p *TreePool) *Hasher { + return &Hasher{ + pool: p, + } +} + +// TreePool provides a pool of trees used as resources by the BMT Hasher. +// A tree popped from the pool is guaranteed to have a clean state ready +// for hashing a new chunk. +type TreePool struct { + lock sync.Mutex + c chan *tree // the channel to obtain a resource from the pool + hasher BaseHasherFunc // base hasher to use for the BMT levels + SegmentSize int // size of leaf segments, stipulated to be = hash size + SegmentCount int // the number of segments on the base level of the BMT + Capacity int // pool capacity, controls concurrency + Depth int // depth of the bmt trees = int(log2(segmentCount))+1 + Size int // the total length of the data (count * size) + count int // current count of (ever) allocated resources + zerohashes [][]byte // lookup table for predictable padding subtrees for all levels +} + +// NewTreePool creates a tree pool with hasher, segment size, segment count and capacity +// on Hasher.getTree it reuses free trees or creates a new one if capacity is not reached +func NewTreePool(hasher BaseHasherFunc, segmentCount, capacity int) *TreePool { + // initialises the zerohashes lookup table + depth := calculateDepthFor(segmentCount) + segmentSize := hasher().Size() + zerohashes := make([][]byte, depth+1) + zeros := make([]byte, segmentSize) + zerohashes[0] = zeros + h := hasher() + for i := 1; i < depth+1; i++ { + zeros = doSum(h, nil, zeros, zeros) + zerohashes[i] = zeros + } + return &TreePool{ + c: make(chan *tree, capacity), + hasher: hasher, + SegmentSize: segmentSize, + SegmentCount: segmentCount, + Capacity: capacity, + Size: segmentCount * segmentSize, + Depth: depth, + zerohashes: zerohashes, + } +} + +// Drain drains the pool until it has no more than n resources +func (p *TreePool) Drain(n int) { + p.lock.Lock() + defer p.lock.Unlock() + for len(p.c) > n { + <-p.c + p.count-- + } +} + +// Reserve is blocking until it returns an available tree +// it reuses free trees or creates a new one if size is not reached +// TODO: should use a context here +func (p *TreePool) reserve() *tree { + p.lock.Lock() + defer p.lock.Unlock() + var t *tree + if p.count == p.Capacity { + return <-p.c + } + select { + case t = <-p.c: + default: + t = newTree(p.SegmentSize, p.Depth, p.hasher) + p.count++ + } + return t +} + +// release gives back a tree to the pool. +// this tree is guaranteed to be in reusable state +func (p *TreePool) release(t *tree) { + p.c <- t // can never fail ... +} + +// tree is a reusable control structure representing a BMT +// organised in a binary tree +// Hasher uses a TreePool to obtain a tree for each chunk hash +// the tree is 'locked' while not in the pool +type tree struct { + leaves []*node // leaf nodes of the tree, other nodes accessible via parent links + cursor int // index of rightmost currently open segment + offset int // offset (cursor position) within currently open segment + section []byte // the rightmost open section (double segment) + result chan []byte // result channel + span []byte // The span of the data subsumed under the chunk +} + +// node is a reuseable segment hasher representing a node in a BMT +type node struct { + isLeft bool // whether it is left side of the parent double segment + parent *node // pointer to parent node in the BMT + state int32 // atomic increment impl concurrent boolean toggle + left, right []byte // this is where the two children sections are written + hasher hash.Hash // preconstructed hasher on nodes +} + +// newNode constructs a segment hasher node in the BMT (used by newTree) +func newNode(index int, parent *node, hasher hash.Hash) *node { + return &node{ + parent: parent, + isLeft: index%2 == 0, + hasher: hasher, + } +} + +// Draw draws the BMT (badly) +func (t *tree) draw(hash []byte) string { + var left, right []string + var anc []*node + for i, n := range t.leaves { + left = append(left, fmt.Sprintf("%v", hashstr(n.left))) + if i%2 == 0 { + anc = append(anc, n.parent) + } + right = append(right, fmt.Sprintf("%v", hashstr(n.right))) + } + anc = t.leaves + var hashes [][]string + for l := 0; len(anc) > 0; l++ { + var nodes []*node + hash := []string{""} + for i, n := range anc { + hash = append(hash, fmt.Sprintf("%v|%v", hashstr(n.left), hashstr(n.right))) + if i%2 == 0 && n.parent != nil { + nodes = append(nodes, n.parent) + } + } + hash = append(hash, "") + hashes = append(hashes, hash) + anc = nodes + } + hashes = append(hashes, []string{"", fmt.Sprintf("%v", hashstr(hash)), ""}) + total := 60 + del := " " + var rows []string + for i := len(hashes) - 1; i >= 0; i-- { + var textlen int + hash := hashes[i] + for _, s := range hash { + textlen += len(s) + } + if total < textlen { + total = textlen + len(hash) + } + delsize := (total - textlen) / (len(hash) - 1) + if delsize > len(del) { + delsize = len(del) + } + row := fmt.Sprintf("%v: %v", len(hashes)-i-1, strings.Join(hash, del[:delsize])) + rows = append(rows, row) + + } + rows = append(rows, strings.Join(left, " ")) + rows = append(rows, strings.Join(right, " ")) + return strings.Join(rows, "\n") + "\n" +} + +// newTree initialises a tree by building up the nodes of a BMT +// - segment size is stipulated to be the size of the hash +func newTree(segmentSize, depth int, hashfunc func() hash.Hash) *tree { + n := newNode(0, nil, hashfunc()) + prevlevel := []*node{n} + // iterate over levels and creates 2^(depth-level) nodes + // the 0 level is on double segment sections so we start at depth - 2 since + count := 2 + for level := depth - 2; level >= 0; level-- { + nodes := make([]*node, count) + for i := 0; i < count; i++ { + parent := prevlevel[i/2] + var hasher hash.Hash + if level == 0 { + hasher = hashfunc() + } + nodes[i] = newNode(i, parent, hasher) + } + prevlevel = nodes + count *= 2 + } + // the datanode level is the nodes on the last level + return &tree{ + leaves: prevlevel, + result: make(chan []byte), + section: make([]byte, 2*segmentSize), + } +} + +// methods needed to implement hash.Hash + +// Size returns the size +func (h *Hasher) Size() int { + return h.pool.SegmentSize +} + +// BlockSize returns the block size +func (h *Hasher) BlockSize() int { + return 2 * h.pool.SegmentSize +} + +// Sum returns the BMT root hash of the buffer +// using Sum presupposes sequential synchronous writes (io.Writer interface) +// hash.Hash interface Sum method appends the byte slice to the underlying +// data before it calculates and returns the hash of the chunk +// caller must make sure Sum is not called concurrently with Write, writeSection +func (h *Hasher) Sum(b []byte) (s []byte) { + t := h.getTree() + // write the last section with final flag set to true + go h.writeSection(t.cursor, t.section, true, true) + // wait for the result + s = <-t.result + span := t.span + // release the tree resource back to the pool + h.releaseTree() + // b + sha3(span + BMT(pure_chunk)) + if len(span) == 0 { + return append(b, s...) + } + return doSum(h.pool.hasher(), b, span, s) +} + +// methods needed to implement the SwarmHash and the io.Writer interfaces + +// Write calls sequentially add to the buffer to be hashed, +// with every full segment calls writeSection in a go routine +func (h *Hasher) Write(b []byte) (int, error) { + l := len(b) + if l == 0 || l > h.pool.Size { + return 0, nil + } + t := h.getTree() + secsize := 2 * h.pool.SegmentSize + // calculate length of missing bit to complete current open section + smax := secsize - t.offset + // if at the beginning of chunk or middle of the section + if t.offset < secsize { + // fill up current segment from buffer + copy(t.section[t.offset:], b) + // if input buffer consumed and open section not complete, then + // advance offset and return + if smax == 0 { + smax = secsize + } + if l <= smax { + t.offset += l + return l, nil + } + } else { + // if end of a section + if t.cursor == h.pool.SegmentCount*2 { + return 0, nil + } + } + // read full sections and the last possibly partial section from the input buffer + for smax < l { + // section complete; push to tree asynchronously + go h.writeSection(t.cursor, t.section, true, false) + // reset section + t.section = make([]byte, secsize) + // copy from input buffer at smax to right half of section + copy(t.section, b[smax:]) + // advance cursor + t.cursor++ + // smax here represents successive offsets in the input buffer + smax += secsize + } + t.offset = l - smax + secsize + return l, nil +} + +// Reset needs to be called before writing to the hasher +func (h *Hasher) Reset() { + h.releaseTree() +} + +// methods needed to implement the SwarmHash interface + +// ResetWithLength needs to be called before writing to the hasher +// the argument is supposed to be the byte slice binary representation of +// the length of the data subsumed under the hash, i.e., span +func (h *Hasher) ResetWithLength(span []byte) { + h.Reset() + h.getTree().span = span +} + +// releaseTree gives back the Tree to the pool whereby it unlocks +// it resets tree, segment and index +func (h *Hasher) releaseTree() { + t := h.bmt + if t == nil { + return + } + h.bmt = nil + go func() { + t.cursor = 0 + t.offset = 0 + t.span = nil + t.section = make([]byte, h.pool.SegmentSize*2) + select { + case <-t.result: + default: + } + h.pool.release(t) + }() +} + +// NewAsyncWriter extends Hasher with an interface for concurrent segment/section writes +func (h *Hasher) NewAsyncWriter(double bool) *AsyncHasher { + secsize := h.pool.SegmentSize + if double { + secsize *= 2 + } + write := func(i int, section []byte, final bool) { + h.writeSection(i, section, double, final) + } + return &AsyncHasher{ + Hasher: h, + double: double, + secsize: secsize, + write: write, + } +} + +// SectionWriter is an asynchronous segment/section writer interface +type SectionWriter interface { + Reset() // standard init to be called before reuse + Write(index int, data []byte) // write into section of index + Sum(b []byte, length int, span []byte) []byte // returns the hash of the buffer + SectionSize() int // size of the async section unit to use +} + +// AsyncHasher extends BMT Hasher with an asynchronous segment/section writer interface +// AsyncHasher is unsafe and does not check indexes and section data lengths +// it must be used with the right indexes and length and the right number of sections +// +// behaviour is undefined if +// * non-final sections are shorter or longer than secsize +// * if final section does not match length +// * write a section with index that is higher than length/secsize +// * set length in Sum call when length/secsize < maxsec +// +// * if Sum() is not called on a Hasher that is fully written +// a process will block, can be terminated with Reset +// * it will not leak processes if not all sections are written but it blocks +// and keeps the resource which can be released calling Reset() +type AsyncHasher struct { + *Hasher // extends the Hasher + mtx sync.Mutex // to lock the cursor access + double bool // whether to use double segments (call Hasher.writeSection) + secsize int // size of base section (size of hash or double) + write func(i int, section []byte, final bool) +} + +// methods needed to implement AsyncWriter + +// SectionSize returns the size of async section unit to use +func (sw *AsyncHasher) SectionSize() int { + return sw.secsize +} + +// Write writes the i-th section of the BMT base +// this function can and is meant to be called concurrently +// it sets max segment threadsafely +func (sw *AsyncHasher) Write(i int, section []byte) { + sw.mtx.Lock() + defer sw.mtx.Unlock() + t := sw.getTree() + // cursor keeps track of the rightmost section written so far + // if index is lower than cursor then just write non-final section as is + if i < t.cursor { + // if index is not the rightmost, safe to write section + go sw.write(i, section, false) + return + } + // if there is a previous rightmost section safe to write section + if t.offset > 0 { + if i == t.cursor { + // i==cursor implies cursor was set by Hash call so we can write section as final one + // since it can be shorter, first we copy it to the padded buffer + t.section = make([]byte, sw.secsize) + copy(t.section, section) + go sw.write(i, t.section, true) + return + } + // the rightmost section just changed, so we write the previous one as non-final + go sw.write(t.cursor, t.section, false) + } + // set i as the index of the righmost section written so far + // set t.offset to cursor*secsize+1 + t.cursor = i + t.offset = i*sw.secsize + 1 + t.section = make([]byte, sw.secsize) + copy(t.section, section) +} + +// Sum can be called any time once the length and the span is known +// potentially even before all segments have been written +// in such cases Sum will block until all segments are present and +// the hash for the length can be calculated. +// +// b: digest is appended to b +// length: known length of the input (unsafe; undefined if out of range) +// meta: metadata to hash together with BMT root for the final digest +// e.g., span for protection against existential forgery +func (sw *AsyncHasher) Sum(b []byte, length int, meta []byte) (s []byte) { + sw.mtx.Lock() + t := sw.getTree() + if length == 0 { + sw.mtx.Unlock() + s = sw.pool.zerohashes[sw.pool.Depth] + } else { + // for non-zero input the rightmost section is written to the tree asynchronously + // if the actual last section has been written (t.cursor == length/t.secsize) + maxsec := (length - 1) / sw.secsize + if t.offset > 0 { + go sw.write(t.cursor, t.section, maxsec == t.cursor) + } + // set cursor to maxsec so final section is written when it arrives + t.cursor = maxsec + t.offset = length + result := t.result + sw.mtx.Unlock() + // wait for the result or reset + s = <-result + } + // relesase the tree back to the pool + sw.releaseTree() + // if no meta is given just append digest to b + if len(meta) == 0 { + return append(b, s...) + } + // hash together meta and BMT root hash using the pools + return doSum(sw.pool.hasher(), b, meta, s) +} + +// writeSection writes the hash of i-th section into level 1 node of the BMT tree +func (h *Hasher) writeSection(i int, section []byte, double bool, final bool) { + // select the leaf node for the section + var n *node + var isLeft bool + var hasher hash.Hash + var level int + t := h.getTree() + if double { + level++ + n = t.leaves[i] + hasher = n.hasher + isLeft = n.isLeft + n = n.parent + // hash the section + section = doSum(hasher, nil, section) + } else { + n = t.leaves[i/2] + hasher = n.hasher + isLeft = i%2 == 0 + } + // write hash into parent node + if final { + // for the last segment use writeFinalNode + h.writeFinalNode(level, n, hasher, isLeft, section) + } else { + h.writeNode(n, hasher, isLeft, section) + } +} + +// writeNode pushes the data to the node +// if it is the first of 2 sisters written, the routine terminates +// if it is the second, it calculates the hash and writes it +// to the parent node recursively +// since hashing the parent is synchronous the same hasher can be used +func (h *Hasher) writeNode(n *node, bh hash.Hash, isLeft bool, s []byte) { + level := 1 + for { + // at the root of the bmt just write the result to the result channel + if n == nil { + h.getTree().result <- s + return + } + // otherwise assign child hash to left or right segment + if isLeft { + n.left = s + } else { + n.right = s + } + // the child-thread first arriving will terminate + if n.toggle() { + return + } + // the thread coming second now can be sure both left and right children are written + // so it calculates the hash of left|right and pushes it to the parent + s = doSum(bh, nil, n.left, n.right) + isLeft = n.isLeft + n = n.parent + level++ + } +} + +// writeFinalNode is following the path starting from the final datasegment to the +// BMT root via parents +// for unbalanced trees it fills in the missing right sister nodes using +// the pool's lookup table for BMT subtree root hashes for all-zero sections +// otherwise behaves like `writeNode` +func (h *Hasher) writeFinalNode(level int, n *node, bh hash.Hash, isLeft bool, s []byte) { + + for { + // at the root of the bmt just write the result to the result channel + if n == nil { + if s != nil { + h.getTree().result <- s + } + return + } + var noHash bool + if isLeft { + // coming from left sister branch + // when the final section's path is going via left child node + // we include an all-zero subtree hash for the right level and toggle the node. + n.right = h.pool.zerohashes[level] + if s != nil { + n.left = s + // if a left final node carries a hash, it must be the first (and only thread) + // so the toggle is already in passive state no need no call + // yet thread needs to carry on pushing hash to parent + noHash = false + } else { + // if again first thread then propagate nil and calculate no hash + noHash = n.toggle() + } + } else { + // right sister branch + if s != nil { + // if hash was pushed from right child node, write right segment change state + n.right = s + // if toggle is true, we arrived first so no hashing just push nil to parent + noHash = n.toggle() + + } else { + // if s is nil, then thread arrived first at previous node and here there will be two, + // so no need to do anything and keep s = nil for parent + noHash = true + } + } + // the child-thread first arriving will just continue resetting s to nil + // the second thread now can be sure both left and right children are written + // it calculates the hash of left|right and pushes it to the parent + if noHash { + s = nil + } else { + s = doSum(bh, nil, n.left, n.right) + } + // iterate to parent + isLeft = n.isLeft + n = n.parent + level++ + } +} + +// getTree obtains a BMT resource by reserving one from the pool and assigns it to the bmt field +func (h *Hasher) getTree() *tree { + if h.bmt != nil { + return h.bmt + } + t := h.pool.reserve() + h.bmt = t + return t +} + +// atomic bool toggle implementing a concurrent reusable 2-state object +// atomic addint with %2 implements atomic bool toggle +// it returns true if the toggler just put it in the active/waiting state +func (n *node) toggle() bool { + return atomic.AddInt32(&n.state, 1)%2 == 1 +} + +// calculates the hash of the data using hash.Hash +func doSum(h hash.Hash, b []byte, data ...[]byte) []byte { + h.Reset() + for _, v := range data { + h.Write(v) + } + return h.Sum(b) +} + +// hashstr is a pretty printer for bytes used in tree.draw +func hashstr(b []byte) string { + end := len(b) + if end > 4 { + end = 4 + } + return fmt.Sprintf("%x", b[:end]) +} + +// calculateDepthFor calculates the depth (number of levels) in the BMT tree +func calculateDepthFor(n int) (d int) { + c := 2 + for ; c < n; c *= 2 { + d++ + } + return d + 1 +} diff --git a/swarm/bmt/bmt_r.go b/swarm/bmt/bmt_r.go new file mode 100644 index 0000000000..0cb6c146f5 --- /dev/null +++ b/swarm/bmt/bmt_r.go @@ -0,0 +1,84 @@ +// Copyright 2017 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 bmt is a simple nonconcurrent reference implementation for hashsize segment based +// Binary Merkle tree hash on arbitrary but fixed maximum chunksize +// +// This implementation does not take advantage of any paralellisms and uses +// far more memory than necessary, but it is easy to see that it is correct. +// It can be used for generating test cases for optimized implementations. +// There is extra check on reference hasher correctness in bmt_test.go +// * TestRefHasher +// * testBMTHasherCorrectness function +package bmt + +import ( + "hash" +) + +// RefHasher is the non-optimized easy-to-read reference implementation of BMT +type RefHasher struct { + maxDataLength int // c * hashSize, where c = 2 ^ ceil(log2(count)), where count = ceil(length / hashSize) + sectionLength int // 2 * hashSize + hasher hash.Hash // base hash func (Keccak256 SHA3) +} + +// NewRefHasher returns a new RefHasher +func NewRefHasher(hasher BaseHasherFunc, count int) *RefHasher { + h := hasher() + hashsize := h.Size() + c := 2 + for ; c < count; c *= 2 { + } + return &RefHasher{ + sectionLength: 2 * hashsize, + maxDataLength: c * hashsize, + hasher: h, + } +} + +// Hash returns the BMT hash of the byte slice +// implements the SwarmHash interface +func (rh *RefHasher) Hash(data []byte) []byte { + // if data is shorter than the base length (maxDataLength), we provide padding with zeros + d := make([]byte, rh.maxDataLength) + length := len(data) + if length > rh.maxDataLength { + length = rh.maxDataLength + } + copy(d, data[:length]) + return rh.hash(d, rh.maxDataLength) +} + +// data has length maxDataLength = segmentSize * 2^k +// hash calls itself recursively on both halves of the given slice +// concatenates the results, and returns the hash of that +// if the length of d is 2 * segmentSize then just returns the hash of that section +func (rh *RefHasher) hash(data []byte, length int) []byte { + var section []byte + if length == rh.sectionLength { + // section contains two data segments (d) + section = data + } else { + // section contains hashes of left and right BMT subtreea + // to be calculated by calling hash recursively on left and right half of d + length /= 2 + section = append(rh.hash(data[:length], length), rh.hash(data[length:], length)...) + } + rh.hasher.Reset() + rh.hasher.Write(section) + return rh.hasher.Sum(nil) +} diff --git a/swarm/bmt/bmt_test.go b/swarm/bmt/bmt_test.go new file mode 100644 index 0000000000..ab712d08c2 --- /dev/null +++ b/swarm/bmt/bmt_test.go @@ -0,0 +1,583 @@ +// Copyright 2017 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 bmt + +import ( + "bytes" + "encoding/binary" + "fmt" + "math/rand" + "sync" + "sync/atomic" + "testing" + "time" + + "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) +const BufferSize = 4128 + +const ( + // segmentCount is the maximum number of segments of the underlying chunk + // Should be equal to max-chunk-data-size / hash-size + // Currently set to 128 == 4096 (default chunk size) / 32 (sha3.keccak256 size) + segmentCount = 128 +) + +var counts = []int{1, 2, 3, 4, 5, 8, 9, 15, 16, 17, 32, 37, 42, 53, 63, 64, 65, 111, 127, 128} + +// calculates the Keccak256 SHA3 hash of the data +func sha3hash(data ...[]byte) []byte { + h := sha3.NewLegacyKeccak256() + return doSum(h, nil, data...) +} + +// TestRefHasher tests that the RefHasher computes the expected BMT hash for +// some small data lengths +func TestRefHasher(t *testing.T) { + // the test struct is used to specify the expected BMT hash for + // segment counts between from and to and lengths from 1 to datalength + type test struct { + from int + to int + expected func([]byte) []byte + } + + var tests []*test + // all lengths in [0,64] should be: + // + // sha3hash(data) + // + tests = append(tests, &test{ + from: 1, + to: 2, + expected: func(d []byte) []byte { + data := make([]byte, 64) + copy(data, d) + return sha3hash(data) + }, + }) + + // all lengths in [3,4] should be: + // + // sha3hash( + // sha3hash(data[:64]) + // sha3hash(data[64:]) + // ) + // + tests = append(tests, &test{ + from: 3, + to: 4, + expected: func(d []byte) []byte { + data := make([]byte, 128) + copy(data, d) + return sha3hash(sha3hash(data[:64]), sha3hash(data[64:])) + }, + }) + + // all segmentCounts in [5,8] should be: + // + // sha3hash( + // sha3hash( + // sha3hash(data[:64]) + // sha3hash(data[64:128]) + // ) + // sha3hash( + // sha3hash(data[128:192]) + // sha3hash(data[192:]) + // ) + // ) + // + tests = append(tests, &test{ + from: 5, + to: 8, + expected: func(d []byte) []byte { + data := make([]byte, 256) + copy(data, d) + return sha3hash(sha3hash(sha3hash(data[:64]), sha3hash(data[64:128])), sha3hash(sha3hash(data[128:192]), sha3hash(data[192:]))) + }, + }) + + // run the tests + for i, x := range tests { + for segmentCount := x.from; segmentCount <= x.to; segmentCount++ { + for length := 1; length <= segmentCount*32; length++ { + 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.NewLegacyKeccak256, segmentCount).Hash(data) + if !bytes.Equal(actual, expected) { + t.Fatalf("expected %x, got %x", expected, actual) + } + }) + } + } + } +} + +// tests if hasher responds with correct hash comparing the reference implementation return value +func TestHasherEmptyData(t *testing.T) { + hasher := sha3.NewLegacyKeccak256 + var data []byte + for _, count := range counts { + t.Run(fmt.Sprintf("%d_segments", count), func(t *testing.T) { + pool := NewTreePool(hasher, count, PoolSize) + defer pool.Drain(0) + bmt := New(pool) + rbmt := NewRefHasher(hasher, count) + refHash := rbmt.Hash(data) + expHash := syncHash(bmt, nil, data) + if !bytes.Equal(expHash, refHash) { + t.Fatalf("hash mismatch with reference. expected %x, got %x", refHash, expHash) + } + }) + } +} + +// tests sequential write with entire max size written in one go +func TestSyncHasherCorrectness(t *testing.T) { + data := testutil.RandomBytes(1, BufferSize) + hasher := sha3.NewLegacyKeccak256 + size := hasher().Size() + + var err error + for _, count := range counts { + t.Run(fmt.Sprintf("segments_%v", count), func(t *testing.T) { + max := count * size + var incr int + capacity := 1 + pool := NewTreePool(hasher, count, capacity) + defer pool.Drain(0) + for n := 0; n <= max; n += incr { + incr = 1 + rand.Intn(5) + bmt := New(pool) + err = testHasherCorrectness(bmt, hasher, data, n, count) + if err != nil { + t.Fatal(err) + } + } + }) + } +} + +// 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.NewLegacyKeccak256 + size := hasher().Size() + whs := []whenHash{first, last, random} + + for _, double := range []bool{false, true} { + for _, wh := range whs { + for _, count := range counts { + t.Run(fmt.Sprintf("double_%v_hash_when_%v_segments_%v", double, wh, count), func(t *testing.T) { + max := count * size + var incr int + capacity := 1 + pool := NewTreePool(hasher, count, capacity) + defer pool.Drain(0) + for n := 1; n <= max; n += incr { + incr = 1 + rand.Intn(5) + bmt := New(pool) + d := data[:n] + rbmt := NewRefHasher(hasher, count) + exp := rbmt.Hash(d) + got := syncHash(bmt, nil, d) + if !bytes.Equal(got, exp) { + t.Fatalf("wrong sync hash for datalength %v: expected %x (ref), got %x", n, exp, got) + } + sw := bmt.NewAsyncWriter(double) + got = asyncHashRandom(sw, nil, d, wh) + if !bytes.Equal(got, exp) { + t.Fatalf("wrong async hash for datalength %v: expected %x, got %x", n, exp, got) + } + } + }) + } + } + } +} + +// Tests that the BMT hasher can be synchronously reused with poolsizes 1 and PoolSize +func TestHasherReuse(t *testing.T) { + t.Run(fmt.Sprintf("poolsize_%d", 1), func(t *testing.T) { + testHasherReuse(1, t) + }) + t.Run(fmt.Sprintf("poolsize_%d", PoolSize), func(t *testing.T) { + testHasherReuse(PoolSize, t) + }) +} + +// tests if bmt reuse is not corrupting result +func testHasherReuse(poolsize int, t *testing.T) { + hasher := sha3.NewLegacyKeccak256 + pool := NewTreePool(hasher, segmentCount, poolsize) + defer pool.Drain(0) + bmt := New(pool) + + for i := 0; i < 100; i++ { + data := testutil.RandomBytes(1, BufferSize) + n := rand.Intn(bmt.Size()) + err := testHasherCorrectness(bmt, hasher, data, n, segmentCount) + if err != nil { + t.Fatal(err) + } + } +} + +// Tests if pool can be cleanly reused even in concurrent use by several hasher +func TestBMTConcurrentUse(t *testing.T) { + hasher := sha3.NewLegacyKeccak256 + pool := NewTreePool(hasher, segmentCount, PoolSize) + defer pool.Drain(0) + cycles := 100 + errc := make(chan error) + + for i := 0; i < cycles; i++ { + go func() { + bmt := New(pool) + data := testutil.RandomBytes(1, BufferSize) + n := rand.Intn(bmt.Size()) + errc <- testHasherCorrectness(bmt, hasher, data, n, 128) + }() + } +LOOP: + for { + select { + case <-time.NewTimer(5 * time.Second).C: + t.Fatal("timed out") + case err := <-errc: + if err != nil { + t.Fatal(err) + } + cycles-- + if cycles == 0 { + break LOOP + } + } + } +} + +// Tests BMT Hasher io.Writer interface is working correctly +// even multiple short random write buffers +func TestBMTWriterBuffers(t *testing.T) { + hasher := sha3.NewLegacyKeccak256 + + for _, count := range counts { + t.Run(fmt.Sprintf("%d_segments", count), func(t *testing.T) { + errc := make(chan error) + pool := NewTreePool(hasher, count, PoolSize) + defer pool.Drain(0) + n := count * 32 + bmt := New(pool) + data := testutil.RandomBytes(1, n) + rbmt := NewRefHasher(hasher, count) + refHash := rbmt.Hash(data) + expHash := syncHash(bmt, nil, data) + if !bytes.Equal(expHash, refHash) { + t.Fatalf("hash mismatch with reference. expected %x, got %x", refHash, expHash) + } + attempts := 10 + f := func() error { + bmt := New(pool) + bmt.Reset() + var buflen int + for offset := 0; offset < n; offset += buflen { + buflen = rand.Intn(n-offset) + 1 + read, err := bmt.Write(data[offset : offset+buflen]) + if err != nil { + return err + } + if read != buflen { + return fmt.Errorf("incorrect read. expected %v bytes, got %v", buflen, read) + } + } + hash := bmt.Sum(nil) + if !bytes.Equal(hash, expHash) { + return fmt.Errorf("hash mismatch. expected %x, got %x", hash, expHash) + } + return nil + } + + for j := 0; j < attempts; j++ { + go func() { + errc <- f() + }() + } + timeout := time.NewTimer(2 * time.Second) + for { + select { + case err := <-errc: + if err != nil { + t.Fatal(err) + } + attempts-- + if attempts == 0 { + return + } + case <-timeout.C: + t.Fatalf("timeout") + } + } + }) + } +} + +// helper function that compares reference and optimised implementations on +// correctness +func testHasherCorrectness(bmt *Hasher, hasher BaseHasherFunc, d []byte, n, count int) (err error) { + span := make([]byte, 8) + if len(d) < n { + n = len(d) + } + binary.BigEndian.PutUint64(span, uint64(n)) + data := d[:n] + rbmt := NewRefHasher(hasher, count) + exp := sha3hash(span, rbmt.Hash(data)) + got := syncHash(bmt, span, data) + if !bytes.Equal(got, exp) { + return fmt.Errorf("wrong hash: expected %x, got %x", exp, got) + } + return err +} + +// +func BenchmarkBMT(t *testing.B) { + for size := 4096; size >= 128; size /= 2 { + t.Run(fmt.Sprintf("%v_size_%v", "SHA3", size), func(t *testing.B) { + benchmarkSHA3(t, size) + }) + t.Run(fmt.Sprintf("%v_size_%v", "Baseline", size), func(t *testing.B) { + benchmarkBMTBaseline(t, size) + }) + t.Run(fmt.Sprintf("%v_size_%v", "REF", size), func(t *testing.B) { + benchmarkRefHasher(t, size) + }) + t.Run(fmt.Sprintf("%v_size_%v", "BMT", size), func(t *testing.B) { + benchmarkBMT(t, size) + }) + } +} + +type whenHash = int + +const ( + first whenHash = iota + last + random +) + +func BenchmarkBMTAsync(t *testing.B) { + whs := []whenHash{first, last, random} + for size := 4096; size >= 128; size /= 2 { + for _, wh := range whs { + for _, double := range []bool{false, true} { + t.Run(fmt.Sprintf("double_%v_hash_when_%v_size_%v", double, wh, size), func(t *testing.B) { + benchmarkBMTAsync(t, size, wh, double) + }) + } + } + } +} + +func BenchmarkPool(t *testing.B) { + caps := []int{1, PoolSize} + for size := 4096; size >= 128; size /= 2 { + for _, c := range caps { + t.Run(fmt.Sprintf("poolsize_%v_size_%v", c, size), func(t *testing.B) { + benchmarkPool(t, c, size) + }) + } + } +} + +// benchmarks simple sha3 hash on chunks +func benchmarkSHA3(t *testing.B, n int) { + data := testutil.RandomBytes(1, n) + hasher := sha3.NewLegacyKeccak256 + h := hasher() + + t.ReportAllocs() + t.ResetTimer() + for i := 0; i < t.N; i++ { + doSum(h, nil, data) + } +} + +// benchmarks the minimum hashing time for a balanced (for simplicity) BMT +// by doing count/segmentsize parallel hashings of 2*segmentsize bytes +// doing it on n PoolSize each reusing the base hasher +// 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.NewLegacyKeccak256 + hashSize := hasher().Size() + data := testutil.RandomBytes(1, hashSize) + + t.ReportAllocs() + t.ResetTimer() + for i := 0; i < t.N; i++ { + count := int32((n-1)/hashSize + 1) + wg := sync.WaitGroup{} + wg.Add(PoolSize) + var i int32 + for j := 0; j < PoolSize; j++ { + go func() { + defer wg.Done() + h := hasher() + for atomic.AddInt32(&i, 1) < count { + doSum(h, nil, data) + } + }() + } + wg.Wait() + } +} + +// benchmarks BMT Hasher +func benchmarkBMT(t *testing.B, n int) { + data := testutil.RandomBytes(1, n) + hasher := sha3.NewLegacyKeccak256 + pool := NewTreePool(hasher, segmentCount, PoolSize) + bmt := New(pool) + + t.ReportAllocs() + t.ResetTimer() + for i := 0; i < t.N; i++ { + syncHash(bmt, nil, data) + } +} + +// 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.NewLegacyKeccak256 + pool := NewTreePool(hasher, segmentCount, PoolSize) + bmt := New(pool).NewAsyncWriter(double) + idxs, segments := splitAndShuffle(bmt.SectionSize(), data) + rand.Shuffle(len(idxs), func(i int, j int) { + idxs[i], idxs[j] = idxs[j], idxs[i] + }) + + t.ReportAllocs() + t.ResetTimer() + for i := 0; i < t.N; i++ { + asyncHash(bmt, nil, n, wh, idxs, segments) + } +} + +// benchmarks 100 concurrent bmt hashes with pool capacity +func benchmarkPool(t *testing.B, poolsize, n int) { + data := testutil.RandomBytes(1, n) + hasher := sha3.NewLegacyKeccak256 + pool := NewTreePool(hasher, segmentCount, poolsize) + cycles := 100 + + t.ReportAllocs() + t.ResetTimer() + wg := sync.WaitGroup{} + for i := 0; i < t.N; i++ { + wg.Add(cycles) + for j := 0; j < cycles; j++ { + go func() { + defer wg.Done() + bmt := New(pool) + syncHash(bmt, nil, data) + }() + } + wg.Wait() + } +} + +// benchmarks the reference hasher +func benchmarkRefHasher(t *testing.B, n int) { + data := testutil.RandomBytes(1, n) + hasher := sha3.NewLegacyKeccak256 + rbmt := NewRefHasher(hasher, 128) + + t.ReportAllocs() + t.ResetTimer() + for i := 0; i < t.N; i++ { + rbmt.Hash(data) + } +} + +// Hash hashes the data and the span using the bmt hasher +func syncHash(h *Hasher, span, data []byte) []byte { + h.ResetWithLength(span) + h.Write(data) + return h.Sum(nil) +} + +func splitAndShuffle(secsize int, data []byte) (idxs []int, segments [][]byte) { + l := len(data) + n := l / secsize + if l%secsize > 0 { + n++ + } + for i := 0; i < n; i++ { + idxs = append(idxs, i) + end := (i + 1) * secsize + if end > l { + end = l + } + section := data[i*secsize : end] + segments = append(segments, section) + } + rand.Shuffle(n, func(i int, j int) { + idxs[i], idxs[j] = idxs[j], idxs[i] + }) + return idxs, segments +} + +// splits the input data performs a random shuffle to mock async section writes +func asyncHashRandom(bmt SectionWriter, span []byte, data []byte, wh whenHash) (s []byte) { + idxs, segments := splitAndShuffle(bmt.SectionSize(), data) + return asyncHash(bmt, span, len(data), wh, idxs, segments) +} + +// mock for async section writes for BMT SectionWriter +// requires a permutation (a random shuffle) of list of all indexes of segments +// and writes them in order to the appropriate section +// the Sum function is called according to the wh parameter (first, last, random [relative to segment writes]) +func asyncHash(bmt SectionWriter, span []byte, l int, wh whenHash, idxs []int, segments [][]byte) (s []byte) { + bmt.Reset() + if l == 0 { + return bmt.Sum(nil, l, span) + } + c := make(chan []byte, 1) + hashf := func() { + c <- bmt.Sum(nil, l, span) + } + maxsize := len(idxs) + var r int + if wh == random { + r = rand.Intn(maxsize) + } + for i, idx := range idxs { + bmt.Write(idx, segments[idx]) + if (wh == first || wh == random) && i == r { + go hashf() + } + } + if wh == last { + return bmt.Sum(nil, l, span) + } + return <-c +} diff --git a/swarm/chunk/chunk.go b/swarm/chunk/chunk.go new file mode 100644 index 0000000000..7540af8ce9 --- /dev/null +++ b/swarm/chunk/chunk.go @@ -0,0 +1,109 @@ +package chunk + +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/swarm/chunk/proximity_test.go b/swarm/chunk/proximity_test.go new file mode 100644 index 0000000000..5632114b16 --- /dev/null +++ b/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/swarm/docker/Dockerfile b/swarm/docker/Dockerfile new file mode 100644 index 0000000000..9450609dd8 --- /dev/null +++ b/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/swarm/docker/run-smoke.sh b/swarm/docker/run-smoke.sh new file mode 100755 index 0000000000..ba57a7ecd6 --- /dev/null +++ b/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/swarm/docker/run.sh b/swarm/docker/run.sh new file mode 100755 index 0000000000..3e613b56d9 --- /dev/null +++ b/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/swarm/fuse/fuse_dir.go b/swarm/fuse/fuse_dir.go index 91b236ae8a..7f66451f10 100644 --- a/swarm/fuse/fuse_dir.go +++ b/swarm/fuse/fuse_dir.go @@ -19,12 +19,14 @@ package fuse import ( - "bazil.org/fuse" - "bazil.org/fuse/fs" - "golang.org/x/net/context" "os" "path/filepath" "sync" + + "bazil.org/fuse" + "bazil.org/fuse/fs" + "github.com/ethereum/go-ethereum/swarm/log" + "golang.org/x/net/context" ) var ( @@ -48,6 +50,7 @@ type SwarmDir struct { } func NewSwarmDir(fullpath string, minfo *MountInfo) *SwarmDir { + log.Debug("swarmfs", "NewSwarmDir", fullpath) newdir := &SwarmDir{ inode: NewInode(), name: filepath.Base(fullpath), @@ -61,6 +64,8 @@ func NewSwarmDir(fullpath string, minfo *MountInfo) *SwarmDir { } func (sd *SwarmDir) Attr(ctx context.Context, a *fuse.Attr) error { + sd.lock.RLock() + defer sd.lock.RUnlock() a.Inode = sd.inode a.Mode = os.ModeDir | 0700 a.Uid = uint32(os.Getuid()) @@ -69,7 +74,7 @@ func (sd *SwarmDir) Attr(ctx context.Context, a *fuse.Attr) error { } func (sd *SwarmDir) Lookup(ctx context.Context, req *fuse.LookupRequest, resp *fuse.LookupResponse) (fs.Node, error) { - + log.Debug("swarmfs", "Lookup", req.Name) for _, n := range sd.files { if n.name == req.Name { return n, nil @@ -84,6 +89,7 @@ func (sd *SwarmDir) Lookup(ctx context.Context, req *fuse.LookupRequest, resp *f } func (sd *SwarmDir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { + log.Debug("swarmfs ReadDirAll") var children []fuse.Dirent for _, file := range sd.files { children = append(children, fuse.Dirent{Inode: file.inode, Type: fuse.DT_File, Name: file.name}) @@ -95,6 +101,7 @@ func (sd *SwarmDir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { } func (sd *SwarmDir) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse) (fs.Node, fs.Handle, error) { + log.Debug("swarmfs Create", "path", sd.path, "req.Name", req.Name) newFile := NewSwarmFile(sd.path, req.Name, sd.mountInfo) newFile.fileSize = 0 // 0 means, file is not in swarm yet and it is just created @@ -107,6 +114,7 @@ func (sd *SwarmDir) Create(ctx context.Context, req *fuse.CreateRequest, resp *f } func (sd *SwarmDir) Remove(ctx context.Context, req *fuse.RemoveRequest) error { + log.Debug("swarmfs Remove", "path", sd.path, "req.Name", req.Name) if req.Dir && sd.directories != nil { newDirs := []*SwarmDir{} @@ -143,13 +151,11 @@ func (sd *SwarmDir) Remove(ctx context.Context, req *fuse.RemoveRequest) error { } func (sd *SwarmDir) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (fs.Node, error) { - - newDir := NewSwarmDir(req.Name, sd.mountInfo) - + log.Debug("swarmfs Mkdir", "path", sd.path, "req.Name", req.Name) + newDir := NewSwarmDir(filepath.Join(sd.path, req.Name), sd.mountInfo) sd.lock.Lock() defer sd.lock.Unlock() sd.directories = append(sd.directories, newDir) return newDir, nil - } diff --git a/swarm/fuse/fuse_file.go b/swarm/fuse/fuse_file.go index c94a0773f5..ca04f737e2 100644 --- a/swarm/fuse/fuse_file.go +++ b/swarm/fuse/fuse_file.go @@ -26,7 +26,7 @@ import ( "bazil.org/fuse" "bazil.org/fuse/fs" - "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/swarm/log" "github.com/ethereum/go-ethereum/swarm/storage" "golang.org/x/net/context" ) @@ -50,7 +50,7 @@ type SwarmFile struct { inode uint64 name string path string - key storage.Key + addr storage.Address fileSize int64 reader storage.LazySectionReader @@ -63,7 +63,7 @@ func NewSwarmFile(path, fname string, minfo *MountInfo) *SwarmFile { inode: NewInode(), name: fname, path: path, - key: nil, + addr: nil, fileSize: -1, // -1 means , file already exists in swarm and you need to just get the size from swarm reader: nil, @@ -73,33 +73,38 @@ func NewSwarmFile(path, fname string, minfo *MountInfo) *SwarmFile { return newFile } -func (file *SwarmFile) Attr(ctx context.Context, a *fuse.Attr) error { - - a.Inode = file.inode +func (sf *SwarmFile) Attr(ctx context.Context, a *fuse.Attr) error { + log.Debug("swarmfs Attr", "path", sf.path) + sf.lock.Lock() + defer sf.lock.Unlock() + a.Inode = sf.inode //TODO: need to get permission as argument a.Mode = 0700 a.Uid = uint32(os.Getuid()) a.Gid = uint32(os.Getegid()) - if file.fileSize == -1 { - reader := file.mountInfo.swarmApi.Retrieve(file.key) + if sf.fileSize == -1 { + reader, _ := sf.mountInfo.swarmApi.Retrieve(ctx, sf.addr) quitC := make(chan bool) - size, err := reader.Size(quitC) + size, err := reader.Size(ctx, quitC) if err != nil { - log.Warn("Couldnt get size of file %s : %v", file.path, err) + log.Error("Couldnt get size of file %s : %v", sf.path, err) + return err } - file.fileSize = size + sf.fileSize = size + log.Trace("swarmfs Attr", "size", size) + close(quitC) } - a.Size = uint64(file.fileSize) + a.Size = uint64(sf.fileSize) return nil } func (sf *SwarmFile) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error { - + log.Debug("swarmfs Read", "path", sf.path, "req.String", req.String()) sf.lock.RLock() defer sf.lock.RUnlock() if sf.reader == nil { - sf.reader = sf.mountInfo.swarmApi.Retrieve(sf.key) + sf.reader, _ = sf.mountInfo.swarmApi.Retrieve(ctx, sf.addr) } buf := make([]byte, req.Size) n, err := sf.reader.ReadAt(buf, req.Offset) @@ -108,26 +113,23 @@ func (sf *SwarmFile) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse } resp.Data = buf[:n] sf.reader = nil - return err + return err } func (sf *SwarmFile) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) error { - + log.Debug("swarmfs Write", "path", sf.path, "req.String", req.String()) if sf.fileSize == 0 && req.Offset == 0 { - // A new file is created err := addFileToSwarm(sf, req.Data, len(req.Data)) if err != nil { return err } resp.Size = len(req.Data) - } else if req.Offset <= sf.fileSize { - totalSize := sf.fileSize + int64(len(req.Data)) if totalSize > MaxAppendFileSize { - log.Warn("Append file size reached (%v) : (%v)", sf.fileSize, len(req.Data)) + log.Warn("swarmfs Append file size reached (%v) : (%v)", sf.fileSize, len(req.Data)) return errFileSizeMaxLimixReached } @@ -137,9 +139,8 @@ func (sf *SwarmFile) Write(ctx context.Context, req *fuse.WriteRequest, resp *fu } resp.Size = len(req.Data) } else { - log.Warn("Invalid write request size(%v) : off(%v)", sf.fileSize, req.Offset) + log.Warn("swarmfs Invalid write request size(%v) : off(%v)", sf.fileSize, req.Offset) return errInvalidOffset } - return nil } diff --git a/swarm/fuse/swarmfs.go b/swarm/fuse/swarmfs.go index 2493bdab19..db6aefb54c 100644 --- a/swarm/fuse/swarmfs.go +++ b/swarm/fuse/swarmfs.go @@ -17,16 +17,17 @@ package fuse import ( - "github.com/ethereum/go-ethereum/swarm/api" "sync" "time" + + "github.com/ethereum/go-ethereum/swarm/api" ) 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 ( @@ -38,12 +39,12 @@ var ( ) type SwarmFS struct { - swarmApi *api.Api + swarmApi *api.API activeMounts map[string]*MountInfo swarmFsLock *sync.RWMutex } -func NewSwarmFS(api *api.Api) *SwarmFS { +func NewSwarmFS(api *api.API) *SwarmFS { swarmfsLock.Do(func() { swarmfs = &SwarmFS{ swarmApi: api, diff --git a/swarm/fuse/swarmfs_test.go b/swarm/fuse/swarmfs_test.go index 42af36345f..460e31c4e9 100644 --- a/swarm/fuse/swarmfs_test.go +++ b/swarm/fuse/swarmfs_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 @@ -20,17 +20,34 @@ package fuse import ( "bytes" - "crypto/rand" + "flag" + "fmt" "io" "io/ioutil" + "math/rand" "os" "path/filepath" "testing" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/swarm/api" "github.com/ethereum/go-ethereum/swarm/storage" + "github.com/ethereum/go-ethereum/swarm/testutil" + colorable "github.com/mattn/go-colorable" ) +var ( + loglevel = flag.Int("loglevel", 4, "verbosity of logs") + rawlog = flag.Bool("rawlog", false, "turn off terminal formatting in logs") + longrunning = flag.Bool("longrunning", false, "do run long-running tests") +) + +func init() { + flag.Parse() + log.PrintOrigins(true) + log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(!*rawlog)))) +} + type fileInfo struct { perm uint64 uid int @@ -38,41 +55,70 @@ type fileInfo struct { contents []byte } -func createTestFilesAndUploadToSwarm(t *testing.T, api *api.Api, files map[string]fileInfo, uploadDir string) string { - os.RemoveAll(uploadDir) +//create files from the map of name and content provided and upload them to swarm via api +func createTestFilesAndUploadToSwarm(t *testing.T, api *api.API, files map[string]fileInfo, uploadDir string, toEncrypt bool) string { + //iterate the map for fname, finfo := range files { actualPath := filepath.Join(uploadDir, fname) filePath := filepath.Dir(actualPath) + //create directory err := os.MkdirAll(filePath, 0777) if err != nil { t.Fatalf("Error creating directory '%v' : %v", filePath, err) } + //create file fd, err1 := os.OpenFile(actualPath, os.O_RDWR|os.O_CREATE, os.FileMode(finfo.perm)) if err1 != nil { t.Fatalf("Error creating file %v: %v", actualPath, err1) } - fd.Write(finfo.contents) - fd.Chown(finfo.uid, finfo.gid) - fd.Chmod(os.FileMode(finfo.perm)) - fd.Sync() - fd.Close() + //write content to file + _, err = fd.Write(finfo.contents) + if err != nil { + t.Fatalf("Error writing to file '%v' : %v", filePath, err) + } + /* + Note @holisticode: It's not clear why the Chown command was added to the test suite. + Some files are initialized with different permissions in the individual test, + resulting in errors on Chown which were not checked. + After adding the checks tests would fail. + + What's then the reason to have this check in the first place? + Disabling for now + + err = fd.Chown(finfo.uid, finfo.gid) + if err != nil { + t.Fatalf("Error chown file '%v' : %v", filePath, err) + } + */ + err = fd.Chmod(os.FileMode(finfo.perm)) + if err != nil { + t.Fatalf("Error chmod file '%v' : %v", filePath, err) + } + err = fd.Sync() + if err != nil { + t.Fatalf("Error sync file '%v' : %v", filePath, err) + } + err = fd.Close() + if err != nil { + t.Fatalf("Error closing file '%v' : %v", filePath, err) + } } - bzzhash, err := api.Upload(uploadDir, "") + //upload directory to swarm and return hash + bzzhash, err := Upload(uploadDir, "", api, toEncrypt) if err != nil { - t.Fatalf("Error uploading directory %v: %v", uploadDir, err) + t.Fatalf("Error uploading directory %v: %vm encryption: %v", uploadDir, err, toEncrypt) } return bzzhash } -func mountDir(t *testing.T, api *api.Api, files map[string]fileInfo, bzzHash string, mountDir string) *SwarmFS { - os.RemoveAll(mountDir) - os.MkdirAll(mountDir, 0777) +//mount a swarm hash as a directory on files system via FUSE +func mountDir(t *testing.T, api *api.API, files map[string]fileInfo, bzzHash string, mountDir string) *SwarmFS { swarmfs := NewSwarmFS(api) _, err := swarmfs.Mount(bzzHash, mountDir) if isFUSEUnsupportedError(err) { @@ -81,17 +127,21 @@ func mountDir(t *testing.T, api *api.Api, files map[string]fileInfo, bzzHash str t.Fatalf("Error mounting hash %v: %v", bzzHash, err) } + //check directory is mounted found := false mi := swarmfs.Listmounts() for _, minfo := range mi { + minfo.lock.RLock() if minfo.MountPoint == mountDir { if minfo.StartManifest != bzzHash || minfo.LatestManifest != bzzHash || minfo.fuseConnection == nil { + minfo.lock.RUnlock() t.Fatalf("Error mounting: exp(%s): act(%s)", bzzHash, minfo.StartManifest) } found = true } + minfo.lock.RUnlock() } // Test listMounts @@ -105,6 +155,7 @@ func mountDir(t *testing.T, api *api.Api, files map[string]fileInfo, bzzHash str return swarmfs } +// Check if file and their attributes are as expected func compareGeneratedFileWithFileInMount(t *testing.T, files map[string]fileInfo, mountDir string) { err := filepath.Walk(mountDir, func(path string, f os.FileInfo, err error) error { if f.IsDir() { @@ -142,12 +193,12 @@ func compareGeneratedFileWithFileInMount(t *testing.T, files map[string]fileInfo } if !bytes.Equal(fileContents, finfo.contents) { t.Fatalf("File %v contents mismatch: %v , %v", fname, fileContents, finfo.contents) - } // TODO: check uid and gid } } +//check mounted file with provided content func checkFile(t *testing.T, testMountDir, fname string, contents []byte) { destinationFile := filepath.Join(testMountDir, fname) dfinfo, err1 := os.Stat(destinationFile) @@ -163,20 +214,20 @@ func checkFile(t *testing.T, testMountDir, fname string, contents []byte) { t.Fatalf("Could not open file %v", destinationFile) } newcontent := make([]byte, len(contents)) - fd.Read(newcontent) - fd.Close() + _, err := fd.Read(newcontent) + if err != nil { + t.Fatalf("Could not read from file %v", err) + } + err = fd.Close() + if err != nil { + t.Fatalf("Could not close file %v", err) + } if !bytes.Equal(contents, newcontent) { t.Fatalf("File content mismatch expected (%v): received (%v) ", contents, newcontent) } } -func getRandomBtes(size int) []byte { - contents := make([]byte, size) - rand.Read(contents) - return contents -} - func isDirEmpty(name string) bool { f, err := os.Open(name) if err != nil { @@ -190,647 +241,1431 @@ func isDirEmpty(name string) bool { } type testAPI struct { - api *api.Api + api *api.API } -func (ta *testAPI) mountListAndUnmount(t *testing.T) { - files := make(map[string]fileInfo) - testUploadDir, _ := ioutil.TempDir(os.TempDir(), "fuse-source") - testMountDir, _ := ioutil.TempDir(os.TempDir(), "fuse-dest") +type testData struct { + testDir string + testUploadDir string + testMountDir string + bzzHash string + files map[string]fileInfo + toEncrypt bool + swarmfs *SwarmFS +} - files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - files["2.txt"] = fileInfo{0711, 333, 444, getRandomBtes(10)} - files["3.txt"] = fileInfo{0622, 333, 444, getRandomBtes(100)} - files["4.txt"] = fileInfo{0533, 333, 444, getRandomBtes(1024)} - files["5.txt"] = fileInfo{0544, 333, 444, getRandomBtes(10)} - files["6.txt"] = fileInfo{0555, 333, 444, getRandomBtes(10)} - files["7.txt"] = fileInfo{0666, 333, 444, getRandomBtes(10)} - files["8.txt"] = fileInfo{0777, 333, 333, getRandomBtes(10)} - files["11.txt"] = fileInfo{0777, 333, 444, getRandomBtes(10)} - files["111.txt"] = fileInfo{0777, 333, 444, getRandomBtes(10)} - files["two/2.txt"] = fileInfo{0777, 333, 444, getRandomBtes(10)} - files["two/2/2.txt"] = fileInfo{0777, 333, 444, getRandomBtes(10)} - files["two/2./2.txt"] = fileInfo{0777, 444, 444, getRandomBtes(10)} - files["twice/2.txt"] = fileInfo{0777, 444, 333, getRandomBtes(200)} - files["one/two/three/four/five/six/seven/eight/nine/10.txt"] = fileInfo{0777, 333, 444, getRandomBtes(10240)} - files["one/two/three/four/five/six/six"] = fileInfo{0777, 333, 444, getRandomBtes(10)} - bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir) - - swarmfs := mountDir(t, ta.api, files, bzzHash, testMountDir) - defer swarmfs.Stop() - - // Check unmount - _, err := swarmfs.Unmount(testMountDir) +//create the root dir of a test +func (ta *testAPI) initSubtest(name string) (*testData, error) { + var err error + d := &testData{} + d.testDir, err = ioutil.TempDir(os.TempDir(), name) if err != nil { - t.Fatalf("could not unmount %v", bzzHash) + return nil, fmt.Errorf("Couldn't create test dir: %v", err) } - if !isDirEmpty(testMountDir) { - t.Fatalf("unmount didnt work for %v", testMountDir) - } - + return d, nil } -func (ta *testAPI) maxMounts(t *testing.T) { - files := make(map[string]fileInfo) - files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - uploadDir1, _ := ioutil.TempDir(os.TempDir(), "max-upload1") - bzzHash1 := createTestFilesAndUploadToSwarm(t, ta.api, files, uploadDir1) - mount1, _ := ioutil.TempDir(os.TempDir(), "max-mount1") - swarmfs1 := mountDir(t, ta.api, files, bzzHash1, mount1) - defer swarmfs1.Stop() +//upload data and mount directory +func (ta *testAPI) uploadAndMount(dat *testData, t *testing.T) (*testData, error) { + //create upload dir + err := os.MkdirAll(dat.testUploadDir, 0777) + if err != nil { + return nil, fmt.Errorf("Couldn't create upload dir: %v", err) + } + //create mount dir + err = os.MkdirAll(dat.testMountDir, 0777) + if err != nil { + return nil, fmt.Errorf("Couldn't create mount dir: %v", err) + } + //upload the file + dat.bzzHash = createTestFilesAndUploadToSwarm(t, ta.api, dat.files, dat.testUploadDir, dat.toEncrypt) + log.Debug("Created test files and uploaded to Swarm") + //mount the directory + dat.swarmfs = mountDir(t, ta.api, dat.files, dat.bzzHash, dat.testMountDir) + log.Debug("Mounted swarm fs") + return dat, nil +} - files["2.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - uploadDir2, _ := ioutil.TempDir(os.TempDir(), "max-upload2") - bzzHash2 := createTestFilesAndUploadToSwarm(t, ta.api, files, uploadDir2) - mount2, _ := ioutil.TempDir(os.TempDir(), "max-mount2") - swarmfs2 := mountDir(t, ta.api, files, bzzHash2, mount2) - defer swarmfs2.Stop() +//add a directory to the test directory tree +func addDir(root string, name string) (string, error) { + d := filepath.Join(root, name) + err := os.MkdirAll(d, 0777) + if err != nil { + return "", fmt.Errorf("Couldn't create dir inside test dir: %v", err) + } + return d, nil +} - files["3.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - uploadDir3, _ := ioutil.TempDir(os.TempDir(), "max-upload3") - bzzHash3 := createTestFilesAndUploadToSwarm(t, ta.api, files, uploadDir3) - mount3, _ := ioutil.TempDir(os.TempDir(), "max-mount3") - swarmfs3 := mountDir(t, ta.api, files, bzzHash3, mount3) - defer swarmfs3.Stop() +func (ta *testAPI) mountListAndUnmountEncrypted(t *testing.T) { + log.Debug("Starting mountListAndUnmountEncrypted test") + ta.mountListAndUnmount(t, true) + log.Debug("Test mountListAndUnmountEncrypted terminated") +} - files["4.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - uploadDir4, _ := ioutil.TempDir(os.TempDir(), "max-upload4") - bzzHash4 := createTestFilesAndUploadToSwarm(t, ta.api, files, uploadDir4) - mount4, _ := ioutil.TempDir(os.TempDir(), "max-mount4") - swarmfs4 := mountDir(t, ta.api, files, bzzHash4, mount4) - defer swarmfs4.Stop() +func (ta *testAPI) mountListAndUnmountNonEncrypted(t *testing.T) { + log.Debug("Starting mountListAndUnmountNonEncrypted test") + ta.mountListAndUnmount(t, false) + log.Debug("Test mountListAndUnmountNonEncrypted terminated") +} - files["5.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - uploadDir5, _ := ioutil.TempDir(os.TempDir(), "max-upload5") - bzzHash5 := createTestFilesAndUploadToSwarm(t, ta.api, files, uploadDir5) - mount5, _ := ioutil.TempDir(os.TempDir(), "max-mount5") - swarmfs5 := mountDir(t, ta.api, files, bzzHash5, mount5) - defer swarmfs5.Stop() +//mount a directory unmount and check the directory is empty afterwards +func (ta *testAPI) mountListAndUnmount(t *testing.T, toEncrypt bool) { + dat, err := ta.initSubtest("mountListAndUnmount") + if err != nil { + t.Fatalf("Couldn't initialize subtest dirs: %v", err) + } + defer os.RemoveAll(dat.testDir) - files["6.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - uploadDir6, _ := ioutil.TempDir(os.TempDir(), "max-upload6") - bzzHash6 := createTestFilesAndUploadToSwarm(t, ta.api, files, uploadDir6) - mount6, _ := ioutil.TempDir(os.TempDir(), "max-mount6") + dat.toEncrypt = toEncrypt + dat.testUploadDir = filepath.Join(dat.testDir, "testUploadDir") + dat.testMountDir = filepath.Join(dat.testDir, "testMountDir") + dat.files = make(map[string]fileInfo) - os.RemoveAll(mount6) - os.MkdirAll(mount6, 0777) - _, err := swarmfs.Mount(bzzHash6, mount6) + dat.files["1.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} + dat.files["2.txt"] = fileInfo{0711, 333, 444, testutil.RandomBytes(2, 10)} + dat.files["3.txt"] = fileInfo{0622, 333, 444, testutil.RandomBytes(3, 100)} + dat.files["4.txt"] = fileInfo{0533, 333, 444, testutil.RandomBytes(4, 1024)} + dat.files["5.txt"] = fileInfo{0544, 333, 444, testutil.RandomBytes(5, 10)} + dat.files["6.txt"] = fileInfo{0555, 333, 444, testutil.RandomBytes(6, 10)} + dat.files["7.txt"] = fileInfo{0666, 333, 444, testutil.RandomBytes(7, 10)} + dat.files["8.txt"] = fileInfo{0777, 333, 333, testutil.RandomBytes(8, 10)} + dat.files["11.txt"] = fileInfo{0777, 333, 444, testutil.RandomBytes(9, 10)} + dat.files["111.txt"] = fileInfo{0777, 333, 444, testutil.RandomBytes(10, 10)} + dat.files["two/2.txt"] = fileInfo{0777, 333, 444, testutil.RandomBytes(11, 10)} + dat.files["two/2/2.txt"] = fileInfo{0777, 333, 444, testutil.RandomBytes(12, 10)} + dat.files["two/2./2.txt"] = fileInfo{0777, 444, 444, testutil.RandomBytes(13, 10)} + dat.files["twice/2.txt"] = fileInfo{0777, 444, 333, testutil.RandomBytes(14, 200)} + dat.files["one/two/three/four/five/six/seven/eight/nine/10.txt"] = fileInfo{0777, 333, 444, testutil.RandomBytes(15, 10240)} + dat.files["one/two/three/four/five/six/six"] = fileInfo{0777, 333, 444, testutil.RandomBytes(16, 10)} + + dat, err = ta.uploadAndMount(dat, t) + if err != nil { + t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) + } + defer dat.swarmfs.Stop() + // Check unmount + _, err = dat.swarmfs.Unmount(dat.testMountDir) + if err != nil { + t.Fatalf("could not unmount %v", dat.bzzHash) + } + log.Debug("Unmount successful") + if !isDirEmpty(dat.testMountDir) { + t.Fatalf("unmount didnt work for %v", dat.testMountDir) + } + log.Debug("subtest terminated") +} + +func (ta *testAPI) maxMountsEncrypted(t *testing.T) { + log.Debug("Starting maxMountsEncrypted test") + ta.runMaxMounts(t, true) + log.Debug("Test maxMountsEncrypted terminated") +} + +func (ta *testAPI) maxMountsNonEncrypted(t *testing.T) { + log.Debug("Starting maxMountsNonEncrypted test") + ta.runMaxMounts(t, false) + log.Debug("Test maxMountsNonEncrypted terminated") +} + +//mount several different directories until the maximum has been reached +func (ta *testAPI) runMaxMounts(t *testing.T, toEncrypt bool) { + dat, err := ta.initSubtest("runMaxMounts") + if err != nil { + t.Fatalf("Couldn't initialize subtest dirs: %v", err) + } + defer os.RemoveAll(dat.testDir) + + dat.toEncrypt = toEncrypt + dat.testUploadDir = filepath.Join(dat.testDir, "max-upload1") + dat.testMountDir = filepath.Join(dat.testDir, "max-mount1") + dat.files = make(map[string]fileInfo) + dat.files["1.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} + + dat, err = ta.uploadAndMount(dat, t) + if err != nil { + t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) + } + defer dat.swarmfs.Stop() + + dat.testUploadDir = filepath.Join(dat.testDir, "max-upload2") + dat.testMountDir = filepath.Join(dat.testDir, "max-mount2") + dat.files["2.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} + + dat, err = ta.uploadAndMount(dat, t) + if err != nil { + t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) + } + + dat.testUploadDir = filepath.Join(dat.testDir, "max-upload3") + dat.testMountDir = filepath.Join(dat.testDir, "max-mount3") + dat.files["3.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} + + dat, err = ta.uploadAndMount(dat, t) + if err != nil { + t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) + } + + dat.testUploadDir = filepath.Join(dat.testDir, "max-upload4") + dat.testMountDir = filepath.Join(dat.testDir, "max-mount4") + dat.files["4.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} + + dat, err = ta.uploadAndMount(dat, t) + if err != nil { + t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) + } + + dat.testUploadDir = filepath.Join(dat.testDir, "max-upload5") + dat.testMountDir = filepath.Join(dat.testDir, "max-mount5") + dat.files["5.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} + + dat, err = ta.uploadAndMount(dat, t) + if err != nil { + t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) + } + + //now try an additional mount, should fail due to max mounts reached + testUploadDir6 := filepath.Join(dat.testDir, "max-upload6") + err = os.MkdirAll(testUploadDir6, 0777) + if err != nil { + t.Fatalf("Couldn't create upload dir 6: %v", err) + } + dat.files["6.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} + testMountDir6 := filepath.Join(dat.testDir, "max-mount6") + err = os.MkdirAll(testMountDir6, 0777) + if err != nil { + t.Fatalf("Couldn't create mount dir 5: %v", err) + } + bzzHash6 := createTestFilesAndUploadToSwarm(t, ta.api, dat.files, testUploadDir6, toEncrypt) + log.Debug("Created test files and uploaded to swarm with uploadDir6") + _, err = dat.swarmfs.Mount(bzzHash6, testMountDir6) if err == nil { - t.Fatalf("Error: Going beyond max mounts %v", bzzHash6) + t.Fatalf("Expected this mount to fail due to exceeding max number of allowed mounts, but succeeded. %v", bzzHash6) } - + log.Debug("Maximum mount reached, additional mount failed. Correct.") } -func (ta *testAPI) remount(t *testing.T) { - files := make(map[string]fileInfo) - files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - uploadDir1, _ := ioutil.TempDir(os.TempDir(), "re-upload1") - bzzHash1 := createTestFilesAndUploadToSwarm(t, ta.api, files, uploadDir1) - testMountDir1, _ := ioutil.TempDir(os.TempDir(), "re-mount1") - swarmfs := mountDir(t, ta.api, files, bzzHash1, testMountDir1) - defer swarmfs.Stop() +func (ta *testAPI) remountEncrypted(t *testing.T) { + log.Debug("Starting remountEncrypted test") + ta.remount(t, true) + log.Debug("Test remountEncrypted terminated") +} +func (ta *testAPI) remountNonEncrypted(t *testing.T) { + log.Debug("Starting remountNonEncrypted test") + ta.remount(t, false) + log.Debug("Test remountNonEncrypted terminated") +} - uploadDir2, _ := ioutil.TempDir(os.TempDir(), "re-upload2") - bzzHash2 := createTestFilesAndUploadToSwarm(t, ta.api, files, uploadDir2) - testMountDir2, _ := ioutil.TempDir(os.TempDir(), "re-mount2") +//test remounting same hash second time and different hash in already mounted point +func (ta *testAPI) remount(t *testing.T, toEncrypt bool) { + dat, err := ta.initSubtest("remount") + if err != nil { + t.Fatalf("Couldn't initialize subtest dirs: %v", err) + } + defer os.RemoveAll(dat.testDir) + + dat.toEncrypt = toEncrypt + dat.testUploadDir = filepath.Join(dat.testDir, "remount-upload1") + dat.testMountDir = filepath.Join(dat.testDir, "remount-mount1") + dat.files = make(map[string]fileInfo) + + dat.files["1.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} + + dat, err = ta.uploadAndMount(dat, t) + if err != nil { + t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) + } + defer dat.swarmfs.Stop() // try mounting the same hash second time - os.RemoveAll(testMountDir2) - os.MkdirAll(testMountDir2, 0777) - _, err := swarmfs.Mount(bzzHash1, testMountDir2) - if err != nil { - t.Fatalf("Error mounting hash %v", bzzHash1) + testMountDir2, err2 := addDir(dat.testDir, "remount-mount2") + if err2 != nil { + t.Fatalf("Error creating second mount dir: %v", err2) + } + _, err2 = dat.swarmfs.Mount(dat.bzzHash, testMountDir2) + if err2 != nil { + t.Fatalf("Error mounting hash second time on different dir %v", dat.bzzHash) } // mount a different hash in already mounted point - _, err = swarmfs.Mount(bzzHash2, testMountDir1) + dat.files["2.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} + testUploadDir2, err3 := addDir(dat.testDir, "remount-upload2") + if err3 != nil { + t.Fatalf("Error creating second upload dir: %v", err3) + } + bzzHash2 := createTestFilesAndUploadToSwarm(t, ta.api, dat.files, testUploadDir2, toEncrypt) + _, err = swarmfs.Mount(bzzHash2, dat.testMountDir) if err == nil { t.Fatalf("Error mounting hash %v", bzzHash2) } + log.Debug("Mount on existing mount point failed. Correct.") // mount nonexistent hash - _, err = swarmfs.Mount("0xfea11223344", testMountDir1) + failDir, err3 := addDir(dat.testDir, "remount-fail") + if err3 != nil { + t.Fatalf("Error creating remount dir: %v", bzzHash2) + } + failHash := "0xfea11223344" + _, err = swarmfs.Mount(failHash, failDir) if err == nil { - t.Fatalf("Error mounting hash %v", bzzHash2) + t.Fatalf("Expected this mount to fail due to non existing hash. But succeeded %v", failHash) } + log.Debug("Nonexistent hash hasn't been mounted. Correct.") } -func (ta *testAPI) unmount(t *testing.T) { - files := make(map[string]fileInfo) - uploadDir, _ := ioutil.TempDir(os.TempDir(), "ex-upload") - testMountDir, _ := ioutil.TempDir(os.TempDir(), "ex-mount") - - files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, uploadDir) - - swarmfs := mountDir(t, ta.api, files, bzzHash, testMountDir) - defer swarmfs.Stop() - - swarmfs.Unmount(testMountDir) - - mi := swarmfs.Listmounts() - for _, minfo := range mi { - if minfo.MountPoint == testMountDir { - t.Fatalf("mount state not cleaned up in unmount case %v", testMountDir) - } - } +func (ta *testAPI) unmountEncrypted(t *testing.T) { + log.Debug("Starting unmountEncrypted test") + ta.unmount(t, true) + log.Debug("Test unmountEncrypted terminated") } -func (ta *testAPI) unmountWhenResourceBusy(t *testing.T) { - files := make(map[string]fileInfo) - testUploadDir, _ := ioutil.TempDir(os.TempDir(), "ex-upload") - testMountDir, _ := ioutil.TempDir(os.TempDir(), "ex-mount") +func (ta *testAPI) unmountNonEncrypted(t *testing.T) { + log.Debug("Starting unmountNonEncrypted test") + ta.unmount(t, false) + log.Debug("Test unmountNonEncrypted terminated") +} - files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir) - - swarmfs := mountDir(t, ta.api, files, bzzHash, testMountDir) - defer swarmfs.Stop() - - actualPath := filepath.Join(testMountDir, "2.txt") - d, err := os.OpenFile(actualPath, os.O_RDWR, os.FileMode(0700)) - d.Write(getRandomBtes(10)) - - _, err = swarmfs.Unmount(testMountDir) +//mount then unmount and check that it has been unmounted +func (ta *testAPI) unmount(t *testing.T, toEncrypt bool) { + dat, err := ta.initSubtest("unmount") if err != nil { - t.Fatalf("could not unmount %v", bzzHash) + t.Fatalf("Couldn't initialize subtest dirs: %v", err) } - d.Close() + defer os.RemoveAll(dat.testDir) + + dat.toEncrypt = toEncrypt + dat.testUploadDir = filepath.Join(dat.testDir, "ex-upload1") + dat.testMountDir = filepath.Join(dat.testDir, "ex-mount1") + dat.files = make(map[string]fileInfo) + dat.files["1.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} + + dat, err = ta.uploadAndMount(dat, t) + if err != nil { + t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) + } + defer dat.swarmfs.Stop() + + _, err = dat.swarmfs.Unmount(dat.testMountDir) + if err != nil { + t.Fatalf("could not unmount %v", dat.bzzHash) + } + log.Debug("Unmounted Dir") mi := swarmfs.Listmounts() + log.Debug("Going to list mounts") for _, minfo := range mi { - if minfo.MountPoint == testMountDir { - t.Fatalf("mount state not cleaned up in unmount case %v", testMountDir) + log.Debug("Mount point in list: ", "point", minfo.MountPoint) + if minfo.MountPoint == dat.testMountDir { + t.Fatalf("mount state not cleaned up in unmount case %v", dat.testMountDir) } } + log.Debug("subtest terminated") } -func (ta *testAPI) seekInMultiChunkFile(t *testing.T) { - files := make(map[string]fileInfo) - testUploadDir, _ := ioutil.TempDir(os.TempDir(), "seek-upload") - testMountDir, _ := ioutil.TempDir(os.TempDir(), "seek-mount") +func (ta *testAPI) unmountWhenResourceBusyEncrypted(t *testing.T) { + log.Debug("Starting unmountWhenResourceBusyEncrypted test") + ta.unmountWhenResourceBusy(t, true) + log.Debug("Test unmountWhenResourceBusyEncrypted terminated") +} +func (ta *testAPI) unmountWhenResourceBusyNonEncrypted(t *testing.T) { + log.Debug("Starting unmountWhenResourceBusyNonEncrypted test") + ta.unmountWhenResourceBusy(t, false) + log.Debug("Test unmountWhenResourceBusyNonEncrypted terminated") +} - files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10240)} - bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir) +//unmount while a resource is busy; should fail +func (ta *testAPI) unmountWhenResourceBusy(t *testing.T, toEncrypt bool) { + dat, err := ta.initSubtest("unmountWhenResourceBusy") + if err != nil { + t.Fatalf("Couldn't initialize subtest dirs: %v", err) + } + defer os.RemoveAll(dat.testDir) - swarmfs := mountDir(t, ta.api, files, bzzHash, testMountDir) - defer swarmfs.Stop() + dat.toEncrypt = toEncrypt + dat.testUploadDir = filepath.Join(dat.testDir, "ex-upload1") + dat.testMountDir = filepath.Join(dat.testDir, "ex-mount1") + dat.files = make(map[string]fileInfo) + dat.files["1.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} - // Create a new file seek the second chunk - actualPath := filepath.Join(testMountDir, "1.txt") - d, _ := os.OpenFile(actualPath, os.O_RDONLY, os.FileMode(0700)) + dat, err = ta.uploadAndMount(dat, t) + if err != nil { + t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) + } + defer dat.swarmfs.Stop() - d.Seek(5000, 0) + //create a file in the mounted directory, then try to unmount - should fail + actualPath := filepath.Join(dat.testMountDir, "2.txt") + //d, err := os.OpenFile(actualPath, os.O_RDWR, os.FileMode(0700)) + d, err := os.Create(actualPath) + if err != nil { + t.Fatalf("Couldn't create new file: %v", err) + } + //we need to manually close the file before mount for this test + //but let's defer too in case of errors + defer d.Close() + _, err = d.Write(testutil.RandomBytes(1, 10)) + if err != nil { + t.Fatalf("Couldn't write to file: %v", err) + } + log.Debug("Bytes written") + + _, err = dat.swarmfs.Unmount(dat.testMountDir) + if err == nil { + t.Fatalf("Expected mount to fail due to resource busy, but it succeeded...") + } + //free resources + err = d.Close() + if err != nil { + t.Fatalf("Couldn't close file! %v", dat.bzzHash) + } + log.Debug("File closed") + + //now unmount after explicitly closed file + _, err = dat.swarmfs.Unmount(dat.testMountDir) + if err != nil { + t.Fatalf("Expected mount to succeed after freeing resource, but it failed: %v", err) + } + //check if the dir is still mounted + mi := dat.swarmfs.Listmounts() + log.Debug("Going to list mounts") + for _, minfo := range mi { + log.Debug("Mount point in list: ", "point", minfo.MountPoint) + if minfo.MountPoint == dat.testMountDir { + t.Fatalf("mount state not cleaned up in unmount case %v", dat.testMountDir) + } + } + log.Debug("subtest terminated") +} + +func (ta *testAPI) seekInMultiChunkFileEncrypted(t *testing.T) { + log.Debug("Starting seekInMultiChunkFileEncrypted test") + ta.seekInMultiChunkFile(t, true) + log.Debug("Test seekInMultiChunkFileEncrypted terminated") +} + +func (ta *testAPI) seekInMultiChunkFileNonEncrypted(t *testing.T) { + log.Debug("Starting seekInMultiChunkFileNonEncrypted test") + ta.seekInMultiChunkFile(t, false) + log.Debug("Test seekInMultiChunkFileNonEncrypted terminated") +} + +//open a file in a mounted dir and go to a certain position +func (ta *testAPI) seekInMultiChunkFile(t *testing.T, toEncrypt bool) { + dat, err := ta.initSubtest("seekInMultiChunkFile") + if err != nil { + t.Fatalf("Couldn't initialize subtest dirs: %v", err) + } + defer os.RemoveAll(dat.testDir) + + dat.toEncrypt = toEncrypt + dat.testUploadDir = filepath.Join(dat.testDir, "seek-upload1") + dat.testMountDir = filepath.Join(dat.testDir, "seek-mount") + dat.files = make(map[string]fileInfo) + dat.files["1.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10240)} + + dat, err = ta.uploadAndMount(dat, t) + if err != nil { + t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) + } + defer dat.swarmfs.Stop() + + // Open the file in the mounted dir and seek the second chunk + actualPath := filepath.Join(dat.testMountDir, "1.txt") + d, err := os.OpenFile(actualPath, os.O_RDONLY, os.FileMode(0700)) + if err != nil { + t.Fatalf("Couldn't open file: %v", err) + } + log.Debug("Opened file") + defer func() { + err := d.Close() + if err != nil { + t.Fatalf("Error closing file! %v", err) + } + }() + + _, err = d.Seek(5000, 0) + if err != nil { + t.Fatalf("Error seeking in file: %v", err) + } contents := make([]byte, 1024) - d.Read(contents) - finfo := files["1.txt"] + _, err = d.Read(contents) + if err != nil { + t.Fatalf("Error reading file: %v", err) + } + log.Debug("Read contents") + finfo := dat.files["1.txt"] if !bytes.Equal(finfo.contents[:6024][5000:], contents) { t.Fatalf("File seek contents mismatch") } - d.Close() + log.Debug("subtest terminated") } -func (ta *testAPI) createNewFile(t *testing.T) { - files := make(map[string]fileInfo) - testUploadDir, _ := ioutil.TempDir(os.TempDir(), "create-upload") - testMountDir, _ := ioutil.TempDir(os.TempDir(), "create-mount") +func (ta *testAPI) createNewFileEncrypted(t *testing.T) { + log.Debug("Starting createNewFileEncrypted test") + ta.createNewFile(t, true) + log.Debug("Test createNewFileEncrypted terminated") +} - files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - files["five.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - files["six.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir) +func (ta *testAPI) createNewFileNonEncrypted(t *testing.T) { + log.Debug("Starting createNewFileNonEncrypted test") + ta.createNewFile(t, false) + log.Debug("Test createNewFileNonEncrypted terminated") +} - swarmfs1 := mountDir(t, ta.api, files, bzzHash, testMountDir) - defer swarmfs1.Stop() +//create a new file in a mounted swarm directory, +//unmount the fuse dir and then remount to see if new file is still there +func (ta *testAPI) createNewFile(t *testing.T, toEncrypt bool) { + dat, err := ta.initSubtest("createNewFile") + if err != nil { + t.Fatalf("Couldn't initialize subtest dirs: %v", err) + } + defer os.RemoveAll(dat.testDir) + + dat.toEncrypt = toEncrypt + dat.testUploadDir = filepath.Join(dat.testDir, "create-upload1") + dat.testMountDir = filepath.Join(dat.testDir, "create-mount") + dat.files = make(map[string]fileInfo) + dat.files["1.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} + dat.files["five.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(2, 10)} + dat.files["six.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(3, 10)} + + dat, err = ta.uploadAndMount(dat, t) + if err != nil { + t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) + } + defer dat.swarmfs.Stop() // Create a new file in the root dir and check - actualPath := filepath.Join(testMountDir, "2.txt") + actualPath := filepath.Join(dat.testMountDir, "2.txt") d, err1 := os.OpenFile(actualPath, os.O_RDWR|os.O_CREATE, os.FileMode(0665)) if err1 != nil { - t.Fatalf("Could not create file %s : %v", actualPath, err1) + t.Fatalf("Could not open file %s : %v", actualPath, err1) } - contents := make([]byte, 11) - rand.Read(contents) - d.Write(contents) - d.Close() + defer d.Close() + log.Debug("Opened file") + contents := testutil.RandomBytes(1, 11) + log.Debug("content read") + _, err = d.Write(contents) + if err != nil { + t.Fatalf("Couldn't write contents: %v", err) + } + log.Debug("content written") + err = d.Close() + if err != nil { + t.Fatalf("Couldn't close file: %v", err) + } + log.Debug("file closed") - mi, err2 := swarmfs1.Unmount(testMountDir) + mi, err2 := dat.swarmfs.Unmount(dat.testMountDir) if err2 != nil { t.Fatalf("Could not unmount %v", err2) } + log.Debug("Directory unmounted") - // mount again and see if things are okay - files["2.txt"] = fileInfo{0700, 333, 444, contents} - swarmfs2 := mountDir(t, ta.api, files, mi.LatestManifest, testMountDir) - defer swarmfs2.Stop() - - checkFile(t, testMountDir, "2.txt", contents) -} - -func (ta *testAPI) createNewFileInsideDirectory(t *testing.T) { - files := make(map[string]fileInfo) - testUploadDir, _ := ioutil.TempDir(os.TempDir(), "createinsidedir-upload") - testMountDir, _ := ioutil.TempDir(os.TempDir(), "createinsidedir-mount") - - files["one/1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir) - - swarmfs1 := mountDir(t, ta.api, files, bzzHash, testMountDir) - defer swarmfs1.Stop() - - // Create a new file inside a existing dir and check - dirToCreate := filepath.Join(testMountDir, "one") - actualPath := filepath.Join(dirToCreate, "2.txt") - d, err1 := os.OpenFile(actualPath, os.O_RDWR|os.O_CREATE, os.FileMode(0665)) - if err1 != nil { - t.Fatalf("Could not create file %s : %v", actualPath, err1) - } - contents := make([]byte, 11) - rand.Read(contents) - d.Write(contents) - d.Close() - - mi, err2 := swarmfs1.Unmount(testMountDir) - if err2 != nil { - t.Fatalf("Could not unmount %v", err2) - } - - // mount again and see if things are okay - files["one/2.txt"] = fileInfo{0700, 333, 444, contents} - swarmfs2 := mountDir(t, ta.api, files, mi.LatestManifest, testMountDir) - defer swarmfs2.Stop() - - checkFile(t, testMountDir, "one/2.txt", contents) -} - -func (ta *testAPI) createNewFileInsideNewDirectory(t *testing.T) { - files := make(map[string]fileInfo) - testUploadDir, _ := ioutil.TempDir(os.TempDir(), "createinsidenewdir-upload") - testMountDir, _ := ioutil.TempDir(os.TempDir(), "createinsidenewdir-mount") - - files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir) - - swarmfs1 := mountDir(t, ta.api, files, bzzHash, testMountDir) - defer swarmfs1.Stop() - - // Create a new file inside a existing dir and check - dirToCreate := filepath.Join(testMountDir, "one") - os.MkdirAll(dirToCreate, 0777) - actualPath := filepath.Join(dirToCreate, "2.txt") - d, err1 := os.OpenFile(actualPath, os.O_RDWR|os.O_CREATE, os.FileMode(0665)) - if err1 != nil { - t.Fatalf("Could not create file %s : %v", actualPath, err1) - } - contents := make([]byte, 11) - rand.Read(contents) - d.Write(contents) - d.Close() - - mi, err2 := swarmfs1.Unmount(testMountDir) - if err2 != nil { - t.Fatalf("Could not unmount %v", err2) - } - - // mount again and see if things are okay - files["one/2.txt"] = fileInfo{0700, 333, 444, contents} - swarmfs2 := mountDir(t, ta.api, files, mi.LatestManifest, testMountDir) - defer swarmfs2.Stop() - - checkFile(t, testMountDir, "one/2.txt", contents) -} - -func (ta *testAPI) removeExistingFile(t *testing.T) { - files := make(map[string]fileInfo) - testUploadDir, _ := ioutil.TempDir(os.TempDir(), "remove-upload") - testMountDir, _ := ioutil.TempDir(os.TempDir(), "remove-mount") - - files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - files["five.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - files["six.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir) - - swarmfs1 := mountDir(t, ta.api, files, bzzHash, testMountDir) - defer swarmfs1.Stop() - - // Remove a file in the root dir and check - actualPath := filepath.Join(testMountDir, "five.txt") - os.Remove(actualPath) - - mi, err2 := swarmfs1.Unmount(testMountDir) - if err2 != nil { - t.Fatalf("Could not unmount %v", err2) - } - - // mount again and see if things are okay - delete(files, "five.txt") - swarmfs2 := mountDir(t, ta.api, files, mi.LatestManifest, testMountDir) - defer swarmfs2.Stop() -} - -func (ta *testAPI) removeExistingFileInsideDir(t *testing.T) { - files := make(map[string]fileInfo) - testUploadDir, _ := ioutil.TempDir(os.TempDir(), "remove-upload") - testMountDir, _ := ioutil.TempDir(os.TempDir(), "remove-mount") - - files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - files["one/five.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - files["one/six.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir) - - swarmfs1 := mountDir(t, ta.api, files, bzzHash, testMountDir) - defer swarmfs1.Stop() - - // Remove a file in the root dir and check - actualPath := filepath.Join(testMountDir, "one/five.txt") - os.Remove(actualPath) - - mi, err2 := swarmfs1.Unmount(testMountDir) - if err2 != nil { - t.Fatalf("Could not unmount %v", err2) - } - - // mount again and see if things are okay - delete(files, "one/five.txt") - swarmfs2 := mountDir(t, ta.api, files, mi.LatestManifest, testMountDir) - defer swarmfs2.Stop() -} - -func (ta *testAPI) removeNewlyAddedFile(t *testing.T) { - - files := make(map[string]fileInfo) - testUploadDir, _ := ioutil.TempDir(os.TempDir(), "removenew-upload") - testMountDir, _ := ioutil.TempDir(os.TempDir(), "removenew-mount") - - files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - files["five.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - files["six.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir) - - swarmfs1 := mountDir(t, ta.api, files, bzzHash, testMountDir) - defer swarmfs1.Stop() - - // Adda a new file and remove it - dirToCreate := filepath.Join(testMountDir, "one") - os.MkdirAll(dirToCreate, os.FileMode(0665)) - actualPath := filepath.Join(dirToCreate, "2.txt") - d, err1 := os.OpenFile(actualPath, os.O_RDWR|os.O_CREATE, os.FileMode(0665)) - if err1 != nil { - t.Fatalf("Could not create file %s : %v", actualPath, err1) - } - contents := make([]byte, 11) - rand.Read(contents) - d.Write(contents) - d.Close() - - checkFile(t, testMountDir, "one/2.txt", contents) - - os.Remove(actualPath) - - mi, err2 := swarmfs1.Unmount(testMountDir) - if err2 != nil { - t.Fatalf("Could not unmount %v", err2) - } - - // mount again and see if things are okay - swarmfs2 := mountDir(t, ta.api, files, mi.LatestManifest, testMountDir) - defer swarmfs2.Stop() - - if bzzHash != mi.LatestManifest { - t.Fatalf("same contents different hash orig(%v): new(%v)", bzzHash, mi.LatestManifest) - } -} - -func (ta *testAPI) addNewFileAndModifyContents(t *testing.T) { - files := make(map[string]fileInfo) - testUploadDir, _ := ioutil.TempDir(os.TempDir(), "modifyfile-upload") - testMountDir, _ := ioutil.TempDir(os.TempDir(), "modifyfile-mount") - - files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - files["five.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - files["six.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir) - - swarmfs1 := mountDir(t, ta.api, files, bzzHash, testMountDir) - defer swarmfs1.Stop() - - // Create a new file in the root dir and check - actualPath := filepath.Join(testMountDir, "2.txt") - d, err1 := os.OpenFile(actualPath, os.O_RDWR|os.O_CREATE, os.FileMode(0665)) - if err1 != nil { - t.Fatalf("Could not create file %s : %v", actualPath, err1) - } - line1 := []byte("Line 1") - rand.Read(line1) - d.Write(line1) - d.Close() - - mi1, err2 := swarmfs1.Unmount(testMountDir) - if err2 != nil { - t.Fatalf("Could not unmount %v", err2) - } - - // mount again and see if things are okay - files["2.txt"] = fileInfo{0700, 333, 444, line1} - swarmfs2 := mountDir(t, ta.api, files, mi1.LatestManifest, testMountDir) - defer swarmfs2.Stop() - - checkFile(t, testMountDir, "2.txt", line1) - - mi2, err3 := swarmfs2.Unmount(testMountDir) + testMountDir2, err3 := addDir(dat.testDir, "create-mount2") if err3 != nil { - t.Fatalf("Could not unmount %v", err3) + t.Fatalf("Error creating mount dir2: %v", err3) } + // mount again and see if things are okay + dat.files["2.txt"] = fileInfo{0700, 333, 444, contents} + _ = mountDir(t, ta.api, dat.files, mi.LatestManifest, testMountDir2) + log.Debug("Directory mounted again") - // mount again and modify - swarmfs3 := mountDir(t, ta.api, files, mi2.LatestManifest, testMountDir) - defer swarmfs3.Stop() - - fd, err4 := os.OpenFile(actualPath, os.O_RDWR|os.O_APPEND, os.FileMode(0665)) - if err4 != nil { - t.Fatalf("Could not create file %s : %v", actualPath, err4) + checkFile(t, testMountDir2, "2.txt", contents) + _, err2 = dat.swarmfs.Unmount(testMountDir2) + if err2 != nil { + t.Fatalf("Could not unmount %v", err2) } - line2 := []byte("Line 2") - rand.Read(line2) - fd.Seek(int64(len(line1)), 0) - fd.Write(line2) - fd.Close() + log.Debug("subtest terminated") +} - mi3, err5 := swarmfs3.Unmount(testMountDir) - if err5 != nil { - t.Fatalf("Could not unmount %v", err5) +func (ta *testAPI) createNewFileInsideDirectoryEncrypted(t *testing.T) { + log.Debug("Starting createNewFileInsideDirectoryEncrypted test") + ta.createNewFileInsideDirectory(t, true) + log.Debug("Test createNewFileInsideDirectoryEncrypted terminated") +} + +func (ta *testAPI) createNewFileInsideDirectoryNonEncrypted(t *testing.T) { + log.Debug("Starting createNewFileInsideDirectoryNonEncrypted test") + ta.createNewFileInsideDirectory(t, false) + log.Debug("Test createNewFileInsideDirectoryNonEncrypted terminated") +} + +//create a new file inside a directory inside the mount +func (ta *testAPI) createNewFileInsideDirectory(t *testing.T, toEncrypt bool) { + dat, err := ta.initSubtest("createNewFileInsideDirectory") + if err != nil { + t.Fatalf("Couldn't initialize subtest dirs: %v", err) } + defer os.RemoveAll(dat.testDir) + + dat.toEncrypt = toEncrypt + dat.testUploadDir = filepath.Join(dat.testDir, "createinsidedir-upload") + dat.testMountDir = filepath.Join(dat.testDir, "createinsidedir-mount") + dat.files = make(map[string]fileInfo) + dat.files["one/1.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} + + dat, err = ta.uploadAndMount(dat, t) + if err != nil { + t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) + } + defer dat.swarmfs.Stop() + + // Create a new file inside a existing dir and check + dirToCreate := filepath.Join(dat.testMountDir, "one") + actualPath := filepath.Join(dirToCreate, "2.txt") + d, err1 := os.OpenFile(actualPath, os.O_RDWR|os.O_CREATE, os.FileMode(0665)) + if err1 != nil { + t.Fatalf("Could not create file %s : %v", actualPath, err1) + } + defer d.Close() + log.Debug("File opened") + contents := testutil.RandomBytes(1, 11) + log.Debug("Content read") + _, err = d.Write(contents) + if err != nil { + t.Fatalf("Error writing random bytes into file %v", err) + } + log.Debug("Content written") + err = d.Close() + if err != nil { + t.Fatalf("Error closing file %v", err) + } + log.Debug("File closed") + + mi, err2 := dat.swarmfs.Unmount(dat.testMountDir) + if err2 != nil { + t.Fatalf("Could not unmount %v", err2) + } + log.Debug("Directory unmounted") + + testMountDir2, err3 := addDir(dat.testDir, "createinsidedir-mount2") + if err3 != nil { + t.Fatalf("Error creating mount dir2: %v", err3) + } + // mount again and see if things are okay + dat.files["one/2.txt"] = fileInfo{0700, 333, 444, contents} + _ = mountDir(t, ta.api, dat.files, mi.LatestManifest, testMountDir2) + log.Debug("Directory mounted again") + + checkFile(t, testMountDir2, "one/2.txt", contents) + _, err = dat.swarmfs.Unmount(testMountDir2) + if err != nil { + t.Fatalf("could not unmount %v", dat.bzzHash) + } + log.Debug("subtest terminated") +} + +func (ta *testAPI) createNewFileInsideNewDirectoryEncrypted(t *testing.T) { + log.Debug("Starting createNewFileInsideNewDirectoryEncrypted test") + ta.createNewFileInsideNewDirectory(t, true) + log.Debug("Test createNewFileInsideNewDirectoryEncrypted terminated") +} + +func (ta *testAPI) createNewFileInsideNewDirectoryNonEncrypted(t *testing.T) { + log.Debug("Starting createNewFileInsideNewDirectoryNonEncrypted test") + ta.createNewFileInsideNewDirectory(t, false) + log.Debug("Test createNewFileInsideNewDirectoryNonEncrypted terminated") +} + +//create a new directory in mount and a new file +func (ta *testAPI) createNewFileInsideNewDirectory(t *testing.T, toEncrypt bool) { + dat, err := ta.initSubtest("createNewFileInsideNewDirectory") + if err != nil { + t.Fatalf("Couldn't initialize subtest dirs: %v", err) + } + defer os.RemoveAll(dat.testDir) + + dat.toEncrypt = toEncrypt + dat.testUploadDir = filepath.Join(dat.testDir, "createinsidenewdir-upload") + dat.testMountDir = filepath.Join(dat.testDir, "createinsidenewdir-mount") + dat.files = make(map[string]fileInfo) + dat.files["1.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} + + dat, err = ta.uploadAndMount(dat, t) + if err != nil { + t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) + } + defer dat.swarmfs.Stop() + + // Create a new file inside a existing dir and check + dirToCreate, err2 := addDir(dat.testMountDir, "one") + if err2 != nil { + t.Fatalf("Error creating mount dir2: %v", err2) + } + actualPath := filepath.Join(dirToCreate, "2.txt") + d, err1 := os.OpenFile(actualPath, os.O_RDWR|os.O_CREATE, os.FileMode(0665)) + if err1 != nil { + t.Fatalf("Could not create file %s : %v", actualPath, err1) + } + defer d.Close() + log.Debug("File opened") + contents := testutil.RandomBytes(1, 11) + log.Debug("content read") + _, err = d.Write(contents) + if err != nil { + t.Fatalf("Error writing to file: %v", err) + } + log.Debug("content written") + err = d.Close() + if err != nil { + t.Fatalf("Error closing file: %v", err) + } + log.Debug("File closed") + + mi, err2 := dat.swarmfs.Unmount(dat.testMountDir) + if err2 != nil { + t.Fatalf("Could not unmount %v", err2) + } + log.Debug("Directory unmounted") // mount again and see if things are okay + dat.files["one/2.txt"] = fileInfo{0700, 333, 444, contents} + _ = mountDir(t, ta.api, dat.files, mi.LatestManifest, dat.testMountDir) + log.Debug("Directory mounted again") + + checkFile(t, dat.testMountDir, "one/2.txt", contents) + _, err2 = dat.swarmfs.Unmount(dat.testMountDir) + if err2 != nil { + t.Fatalf("Could not unmount %v", err2) + } + log.Debug("subtest terminated") +} + +func (ta *testAPI) removeExistingFileEncrypted(t *testing.T) { + log.Debug("Starting removeExistingFileEncrypted test") + ta.removeExistingFile(t, true) + log.Debug("Test removeExistingFileEncrypted terminated") +} + +func (ta *testAPI) removeExistingFileNonEncrypted(t *testing.T) { + log.Debug("Starting removeExistingFileNonEncrypted test") + ta.removeExistingFile(t, false) + log.Debug("Test removeExistingFileNonEncrypted terminated") +} + +//remove existing file in mount +func (ta *testAPI) removeExistingFile(t *testing.T, toEncrypt bool) { + dat, err := ta.initSubtest("removeExistingFile") + if err != nil { + t.Fatalf("Couldn't initialize subtest dirs: %v", err) + } + defer os.RemoveAll(dat.testDir) + + dat.toEncrypt = toEncrypt + dat.testUploadDir = filepath.Join(dat.testDir, "remove-upload") + dat.testMountDir = filepath.Join(dat.testDir, "remove-mount") + dat.files = make(map[string]fileInfo) + dat.files["1.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} + dat.files["five.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(2, 10)} + dat.files["six.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(3, 10)} + + dat, err = ta.uploadAndMount(dat, t) + if err != nil { + t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) + } + defer dat.swarmfs.Stop() + + // Remove a file in the root dir and check + actualPath := filepath.Join(dat.testMountDir, "five.txt") + err = os.Remove(actualPath) + if err != nil { + t.Fatalf("Error removing file! %v", err) + } + mi, err2 := dat.swarmfs.Unmount(dat.testMountDir) + if err2 != nil { + t.Fatalf("Could not unmount %v", err2) + } + log.Debug("Directory unmounted") + + // mount again and see if things are okay + delete(dat.files, "five.txt") + _ = mountDir(t, ta.api, dat.files, mi.LatestManifest, dat.testMountDir) + _, err = os.Stat(actualPath) + if err == nil { + t.Fatal("Expected file to not be present in re-mount after removal, but it is there") + } + _, err2 = dat.swarmfs.Unmount(dat.testMountDir) + if err2 != nil { + t.Fatalf("Could not unmount %v", err2) + } + log.Debug("subtest terminated") +} + +func (ta *testAPI) removeExistingFileInsideDirEncrypted(t *testing.T) { + log.Debug("Starting removeExistingFileInsideDirEncrypted test") + ta.removeExistingFileInsideDir(t, true) + log.Debug("Test removeExistingFileInsideDirEncrypted terminated") +} + +func (ta *testAPI) removeExistingFileInsideDirNonEncrypted(t *testing.T) { + log.Debug("Starting removeExistingFileInsideDirNonEncrypted test") + ta.removeExistingFileInsideDir(t, false) + log.Debug("Test removeExistingFileInsideDirNonEncrypted terminated") +} + +//remove a file inside a directory inside a mount +func (ta *testAPI) removeExistingFileInsideDir(t *testing.T, toEncrypt bool) { + dat, err := ta.initSubtest("removeExistingFileInsideDir") + if err != nil { + t.Fatalf("Couldn't initialize subtest dirs: %v", err) + } + defer os.RemoveAll(dat.testDir) + + dat.toEncrypt = toEncrypt + dat.testUploadDir = filepath.Join(dat.testDir, "remove-upload") + dat.testMountDir = filepath.Join(dat.testDir, "remove-mount") + dat.files = make(map[string]fileInfo) + dat.files["1.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} + dat.files["one/five.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(2, 10)} + dat.files["one/six.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(3, 10)} + + dat, err = ta.uploadAndMount(dat, t) + if err != nil { + t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) + } + defer dat.swarmfs.Stop() + + // Remove a file in the root dir and check + actualPath := filepath.Join(dat.testMountDir, "one") + actualPath = filepath.Join(actualPath, "five.txt") + err = os.Remove(actualPath) + if err != nil { + t.Fatalf("Error removing file! %v", err) + } + mi, err2 := dat.swarmfs.Unmount(dat.testMountDir) + if err2 != nil { + t.Fatalf("Could not unmount %v", err2) + } + log.Debug("Directory unmounted") + + // mount again and see if things are okay + delete(dat.files, "one/five.txt") + _ = mountDir(t, ta.api, dat.files, mi.LatestManifest, dat.testMountDir) + _, err = os.Stat(actualPath) + if err == nil { + t.Fatal("Expected file to not be present in re-mount after removal, but it is there") + } + + okPath := filepath.Join(dat.testMountDir, "one") + okPath = filepath.Join(okPath, "six.txt") + _, err = os.Stat(okPath) + if err != nil { + t.Fatal("Expected file to be present in re-mount after removal, but it is not there") + } + _, err2 = dat.swarmfs.Unmount(dat.testMountDir) + if err2 != nil { + t.Fatalf("Could not unmount %v", err2) + } + log.Debug("subtest terminated") +} + +func (ta *testAPI) removeNewlyAddedFileEncrypted(t *testing.T) { + log.Debug("Starting removeNewlyAddedFileEncrypted test") + ta.removeNewlyAddedFile(t, true) + log.Debug("Test removeNewlyAddedFileEncrypted terminated") +} + +func (ta *testAPI) removeNewlyAddedFileNonEncrypted(t *testing.T) { + log.Debug("Starting removeNewlyAddedFileNonEncrypted test") + ta.removeNewlyAddedFile(t, false) + log.Debug("Test removeNewlyAddedFileNonEncrypted terminated") +} + +//add a file in mount and then remove it; on remount file should not be there +func (ta *testAPI) removeNewlyAddedFile(t *testing.T, toEncrypt bool) { + dat, err := ta.initSubtest("removeNewlyAddedFile") + if err != nil { + t.Fatalf("Couldn't initialize subtest dirs: %v", err) + } + defer os.RemoveAll(dat.testDir) + + dat.toEncrypt = toEncrypt + dat.testUploadDir = filepath.Join(dat.testDir, "removenew-upload") + dat.testMountDir = filepath.Join(dat.testDir, "removenew-mount") + dat.files = make(map[string]fileInfo) + dat.files["1.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} + dat.files["five.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(2, 10)} + dat.files["six.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(3, 10)} + + dat, err = ta.uploadAndMount(dat, t) + if err != nil { + t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) + } + defer dat.swarmfs.Stop() + + // Add a a new file and remove it + dirToCreate := filepath.Join(dat.testMountDir, "one") + err = os.MkdirAll(dirToCreate, os.FileMode(0665)) + if err != nil { + t.Fatalf("Error creating dir in mounted dir: %v", err) + } + actualPath := filepath.Join(dirToCreate, "2.txt") + d, err1 := os.OpenFile(actualPath, os.O_RDWR|os.O_CREATE, os.FileMode(0665)) + if err1 != nil { + t.Fatalf("Could not create file %s : %v", actualPath, err1) + } + defer d.Close() + log.Debug("file opened") + contents := testutil.RandomBytes(1, 11) + log.Debug("content read") + _, err = d.Write(contents) + if err != nil { + t.Fatalf("Error writing random bytes to file: %v", err) + } + log.Debug("content written") + err = d.Close() + if err != nil { + t.Fatalf("Error closing file: %v", err) + } + log.Debug("file closed") + + checkFile(t, dat.testMountDir, "one/2.txt", contents) + log.Debug("file checked") + + err = os.Remove(actualPath) + if err != nil { + t.Fatalf("Error removing file: %v", err) + } + log.Debug("file removed") + + mi, err2 := dat.swarmfs.Unmount(dat.testMountDir) + if err2 != nil { + t.Fatalf("Could not unmount %v", err2) + } + log.Debug("Directory unmounted") + + testMountDir2, err3 := addDir(dat.testDir, "removenew-mount2") + if err3 != nil { + t.Fatalf("Error creating mount dir2: %v", err3) + } + // mount again and see if things are okay + _ = mountDir(t, ta.api, dat.files, mi.LatestManifest, testMountDir2) + log.Debug("Directory mounted again") + + if dat.bzzHash != mi.LatestManifest { + t.Fatalf("same contents different hash orig(%v): new(%v)", dat.bzzHash, mi.LatestManifest) + } + _, err2 = dat.swarmfs.Unmount(testMountDir2) + if err2 != nil { + t.Fatalf("Could not unmount %v", err2) + } + log.Debug("subtest terminated") +} + +func (ta *testAPI) addNewFileAndModifyContentsEncrypted(t *testing.T) { + log.Debug("Starting addNewFileAndModifyContentsEncrypted test") + ta.addNewFileAndModifyContents(t, true) + log.Debug("Test addNewFileAndModifyContentsEncrypted terminated") +} + +func (ta *testAPI) addNewFileAndModifyContentsNonEncrypted(t *testing.T) { + log.Debug("Starting addNewFileAndModifyContentsNonEncrypted test") + ta.addNewFileAndModifyContents(t, false) + log.Debug("Test addNewFileAndModifyContentsNonEncrypted terminated") +} + +//add a new file and modify content; remount and check the modified file is intact +func (ta *testAPI) addNewFileAndModifyContents(t *testing.T, toEncrypt bool) { + dat, err := ta.initSubtest("addNewFileAndModifyContents") + if err != nil { + t.Fatalf("Couldn't initialize subtest dirs: %v", err) + } + defer os.RemoveAll(dat.testDir) + + dat.toEncrypt = toEncrypt + dat.testUploadDir = filepath.Join(dat.testDir, "modifyfile-upload") + dat.testMountDir = filepath.Join(dat.testDir, "modifyfile-mount") + dat.files = make(map[string]fileInfo) + dat.files["1.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} + dat.files["five.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(2, 10)} + dat.files["six.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(3, 10)} + + dat, err = ta.uploadAndMount(dat, t) + if err != nil { + t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) + } + defer dat.swarmfs.Stop() + + // Create a new file in the root dir + actualPath := filepath.Join(dat.testMountDir, "2.txt") + d, err1 := os.OpenFile(actualPath, os.O_RDWR|os.O_CREATE, os.FileMode(0665)) + if err1 != nil { + t.Fatalf("Could not create file %s : %v", actualPath, err1) + } + defer d.Close() + //write some random data into the file + log.Debug("file opened") + line1 := []byte("Line 1") + _, err = rand.Read(line1) + if err != nil { + t.Fatalf("Error writing random bytes to byte array: %v", err) + } + log.Debug("line read") + _, err = d.Write(line1) + if err != nil { + t.Fatalf("Error writing random bytes to file: %v", err) + } + log.Debug("line written") + err = d.Close() + if err != nil { + t.Fatalf("Error closing file: %v", err) + } + log.Debug("file closed") + + //unmount the hash on the mounted dir + mi1, err2 := dat.swarmfs.Unmount(dat.testMountDir) + if err2 != nil { + t.Fatalf("Could not unmount %v", err2) + } + log.Debug("Directory unmounted") + + //mount on a different dir to see if modified file is correct + testMountDir2, err3 := addDir(dat.testDir, "modifyfile-mount2") + if err3 != nil { + t.Fatalf("Error creating mount dir2: %v", err3) + } + dat.files["2.txt"] = fileInfo{0700, 333, 444, line1} + _ = mountDir(t, ta.api, dat.files, mi1.LatestManifest, testMountDir2) + log.Debug("Directory mounted again") + + checkFile(t, testMountDir2, "2.txt", line1) + log.Debug("file checked") + + //unmount second dir + mi2, err4 := dat.swarmfs.Unmount(testMountDir2) + if err4 != nil { + t.Fatalf("Could not unmount %v", err4) + } + log.Debug("Directory unmounted again") + + //mount again on original dir and modify the file + //let's clean up the mounted dir first: remove... + err = os.RemoveAll(dat.testMountDir) + if err != nil { + t.Fatalf("Error cleaning up mount dir: %v", err) + } + //...and re-create + err = os.MkdirAll(dat.testMountDir, 0777) + if err != nil { + t.Fatalf("Error re-creating mount dir: %v", err) + } + //now remount + _ = mountDir(t, ta.api, dat.files, mi2.LatestManifest, dat.testMountDir) + log.Debug("Directory mounted yet again") + + //open the file.... + fd, err5 := os.OpenFile(actualPath, os.O_RDWR|os.O_APPEND, os.FileMode(0665)) + if err5 != nil { + t.Fatalf("Could not create file %s : %v", actualPath, err5) + } + defer fd.Close() + log.Debug("file opened") + //...and modify something + line2 := []byte("Line 2") + _, err = rand.Read(line2) + if err != nil { + t.Fatalf("Error modifying random bytes to byte array: %v", err) + } + log.Debug("line read") + _, err = fd.Seek(int64(len(line1)), 0) + if err != nil { + t.Fatalf("Error seeking position for modification: %v", err) + } + _, err = fd.Write(line2) + if err != nil { + t.Fatalf("Error modifying file: %v", err) + } + log.Debug("line written") + err = fd.Close() + if err != nil { + t.Fatalf("Error closing modified file; %v", err) + } + log.Debug("file closed") + + //unmount the modified directory + mi3, err6 := dat.swarmfs.Unmount(dat.testMountDir) + if err6 != nil { + t.Fatalf("Could not unmount %v", err6) + } + log.Debug("Directory unmounted yet again") + + //now remount on a different dir and check that the modified file is ok + testMountDir4, err7 := addDir(dat.testDir, "modifyfile-mount4") + if err7 != nil { + t.Fatalf("Could not unmount %v", err7) + } b := [][]byte{line1, line2} line1and2 := bytes.Join(b, []byte("")) - files["2.txt"] = fileInfo{0700, 333, 444, line1and2} - swarmfs4 := mountDir(t, ta.api, files, mi3.LatestManifest, testMountDir) - defer swarmfs4.Stop() + dat.files["2.txt"] = fileInfo{0700, 333, 444, line1and2} + _ = mountDir(t, ta.api, dat.files, mi3.LatestManifest, testMountDir4) + log.Debug("Directory mounted final time") - checkFile(t, testMountDir, "2.txt", line1and2) + checkFile(t, testMountDir4, "2.txt", line1and2) + _, err = dat.swarmfs.Unmount(testMountDir4) + if err != nil { + t.Fatalf("Could not unmount %v", err) + } + log.Debug("subtest terminated") } -func (ta *testAPI) removeEmptyDir(t *testing.T) { - files := make(map[string]fileInfo) - testUploadDir, _ := ioutil.TempDir(os.TempDir(), "rmdir-upload") - testMountDir, _ := ioutil.TempDir(os.TempDir(), "rmdir-mount") +func (ta *testAPI) removeEmptyDirEncrypted(t *testing.T) { + log.Debug("Starting removeEmptyDirEncrypted test") + ta.removeEmptyDir(t, true) + log.Debug("Test removeEmptyDirEncrypted terminated") +} - files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - files["five.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - files["six.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir) +func (ta *testAPI) removeEmptyDirNonEncrypted(t *testing.T) { + log.Debug("Starting removeEmptyDirNonEncrypted test") + ta.removeEmptyDir(t, false) + log.Debug("Test removeEmptyDirNonEncrypted terminated") +} - swarmfs1 := mountDir(t, ta.api, files, bzzHash, testMountDir) - defer swarmfs1.Stop() +//remove an empty dir inside mount +func (ta *testAPI) removeEmptyDir(t *testing.T, toEncrypt bool) { + dat, err := ta.initSubtest("removeEmptyDir") + if err != nil { + t.Fatalf("Couldn't initialize subtest dirs: %v", err) + } + defer os.RemoveAll(dat.testDir) - os.MkdirAll(filepath.Join(testMountDir, "newdir"), 0777) + dat.toEncrypt = toEncrypt + dat.testUploadDir = filepath.Join(dat.testDir, "rmdir-upload") + dat.testMountDir = filepath.Join(dat.testDir, "rmdir-mount") + dat.files = make(map[string]fileInfo) + dat.files["1.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} + dat.files["five.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(2, 10)} + dat.files["six.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(3, 10)} - mi, err3 := swarmfs1.Unmount(testMountDir) + dat, err = ta.uploadAndMount(dat, t) + if err != nil { + t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) + } + defer dat.swarmfs.Stop() + + _, err2 := addDir(dat.testMountDir, "newdir") + if err2 != nil { + t.Fatalf("Could not unmount %v", err2) + } + mi, err := dat.swarmfs.Unmount(dat.testMountDir) + if err != nil { + t.Fatalf("Could not unmount %v", err) + } + log.Debug("Directory unmounted") + //by just adding an empty dir, the hash doesn't change; test this + if dat.bzzHash != mi.LatestManifest { + t.Fatalf("same contents different hash orig(%v): new(%v)", dat.bzzHash, mi.LatestManifest) + } + log.Debug("subtest terminated") +} + +func (ta *testAPI) removeDirWhichHasFilesEncrypted(t *testing.T) { + log.Debug("Starting removeDirWhichHasFilesEncrypted test") + ta.removeDirWhichHasFiles(t, true) + log.Debug("Test removeDirWhichHasFilesEncrypted terminated") +} +func (ta *testAPI) removeDirWhichHasFilesNonEncrypted(t *testing.T) { + log.Debug("Starting removeDirWhichHasFilesNonEncrypted test") + ta.removeDirWhichHasFiles(t, false) + log.Debug("Test removeDirWhichHasFilesNonEncrypted terminated") +} + +//remove a directory with a file; check on remount file isn't there +func (ta *testAPI) removeDirWhichHasFiles(t *testing.T, toEncrypt bool) { + dat, err := ta.initSubtest("removeDirWhichHasFiles") + if err != nil { + t.Fatalf("Couldn't initialize subtest dirs: %v", err) + } + defer os.RemoveAll(dat.testDir) + + dat.toEncrypt = toEncrypt + dat.testUploadDir = filepath.Join(dat.testDir, "rmdir-upload") + dat.testMountDir = filepath.Join(dat.testDir, "rmdir-mount") + dat.files = make(map[string]fileInfo) + dat.files["one/1.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} + dat.files["two/five.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(2, 10)} + dat.files["two/six.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(3, 10)} + + dat, err = ta.uploadAndMount(dat, t) + if err != nil { + t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) + } + defer dat.swarmfs.Stop() + + //delete a directory inside the mounted dir with all its files + dirPath := filepath.Join(dat.testMountDir, "two") + err = os.RemoveAll(dirPath) + if err != nil { + t.Fatalf("Error removing directory in mounted dir: %v", err) + } + + mi, err2 := dat.swarmfs.Unmount(dat.testMountDir) + if err2 != nil { + t.Fatalf("Could not unmount %v ", err2) + } + log.Debug("Directory unmounted") + + //we deleted files in the OS, so let's delete them also in the files map + delete(dat.files, "two/five.txt") + delete(dat.files, "two/six.txt") + + // mount again and see if deleted files have been deleted indeed + testMountDir2, err3 := addDir(dat.testDir, "remount-mount2") if err3 != nil { t.Fatalf("Could not unmount %v", err3) } - if bzzHash != mi.LatestManifest { - t.Fatalf("same contents different hash orig(%v): new(%v)", bzzHash, mi.LatestManifest) + _ = mountDir(t, ta.api, dat.files, mi.LatestManifest, testMountDir2) + log.Debug("Directory mounted") + actualPath := filepath.Join(dirPath, "five.txt") + _, err = os.Stat(actualPath) + if err == nil { + t.Fatal("Expected file to not be present in re-mount after removal, but it is there") } + _, err = os.Stat(dirPath) + if err == nil { + t.Fatal("Expected file to not be present in re-mount after removal, but it is there") + } + _, err = dat.swarmfs.Unmount(testMountDir2) + if err != nil { + t.Fatalf("Could not unmount %v", err) + } + log.Debug("subtest terminated") } -func (ta *testAPI) removeDirWhichHasFiles(t *testing.T) { - files := make(map[string]fileInfo) - testUploadDir, _ := ioutil.TempDir(os.TempDir(), "rmdir-upload") - testMountDir, _ := ioutil.TempDir(os.TempDir(), "rmdir-mount") +func (ta *testAPI) removeDirWhichHasSubDirsEncrypted(t *testing.T) { + log.Debug("Starting removeDirWhichHasSubDirsEncrypted test") + ta.removeDirWhichHasSubDirs(t, true) + log.Debug("Test removeDirWhichHasSubDirsEncrypted terminated") +} - files["one/1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - files["two/five.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - files["two/six.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir) +func (ta *testAPI) removeDirWhichHasSubDirsNonEncrypted(t *testing.T) { + log.Debug("Starting removeDirWhichHasSubDirsNonEncrypted test") + ta.removeDirWhichHasSubDirs(t, false) + log.Debug("Test removeDirWhichHasSubDirsNonEncrypted terminated") +} - swarmfs1 := mountDir(t, ta.api, files, bzzHash, testMountDir) - defer swarmfs1.Stop() +//remove a directory with subdirectories inside mount; on remount check they are not there +func (ta *testAPI) removeDirWhichHasSubDirs(t *testing.T, toEncrypt bool) { + dat, err := ta.initSubtest("removeDirWhichHasSubDirs") + if err != nil { + t.Fatalf("Couldn't initialize subtest dirs: %v", err) + } + defer os.RemoveAll(dat.testDir) - dirPath := filepath.Join(testMountDir, "two") - os.RemoveAll(dirPath) + dat.toEncrypt = toEncrypt + dat.testUploadDir = filepath.Join(dat.testDir, "rmsubdir-upload") + dat.testMountDir = filepath.Join(dat.testDir, "rmsubdir-mount") + dat.files = make(map[string]fileInfo) + dat.files["one/1.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} + dat.files["two/three/2.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(2, 10)} + dat.files["two/three/3.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(3, 10)} + dat.files["two/four/5.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(4, 10)} + dat.files["two/four/6.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(5, 10)} + dat.files["two/four/six/7.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(6, 10)} - mi, err2 := swarmfs1.Unmount(testMountDir) + dat, err = ta.uploadAndMount(dat, t) + if err != nil { + t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) + } + defer dat.swarmfs.Stop() + + dirPath := filepath.Join(dat.testMountDir, "two") + err = os.RemoveAll(dirPath) + if err != nil { + t.Fatalf("Error removing directory in mounted dir: %v", err) + } + + //delete a directory inside the mounted dir with all its files + mi, err2 := dat.swarmfs.Unmount(dat.testMountDir) if err2 != nil { t.Fatalf("Could not unmount %v ", err2) } + log.Debug("Directory unmounted") + + //we deleted files in the OS, so let's delete them also in the files map + delete(dat.files, "two/three/2.txt") + delete(dat.files, "two/three/3.txt") + delete(dat.files, "two/four/5.txt") + delete(dat.files, "two/four/6.txt") + delete(dat.files, "two/four/six/7.txt") // mount again and see if things are okay - delete(files, "two/five.txt") - delete(files, "two/six.txt") - - swarmfs2 := mountDir(t, ta.api, files, mi.LatestManifest, testMountDir) - defer swarmfs2.Stop() -} - -func (ta *testAPI) removeDirWhichHasSubDirs(t *testing.T) { - files := make(map[string]fileInfo) - testUploadDir, _ := ioutil.TempDir(os.TempDir(), "rmsubdir-upload") - testMountDir, _ := ioutil.TempDir(os.TempDir(), "rmsubdir-mount") - - files["one/1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - files["two/three/2.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - files["two/three/3.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - files["two/four/5.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - files["two/four/6.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - files["two/four/six/7.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} - - bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir) - - swarmfs1 := mountDir(t, ta.api, files, bzzHash, testMountDir) - defer swarmfs1.Stop() - - dirPath := filepath.Join(testMountDir, "two") - os.RemoveAll(dirPath) - - mi, err2 := swarmfs1.Unmount(testMountDir) - if err2 != nil { - t.Fatalf("Could not unmount %v ", err2) + testMountDir2, err3 := addDir(dat.testDir, "remount-mount2") + if err3 != nil { + t.Fatalf("Could not unmount %v", err3) } - - // mount again and see if things are okay - delete(files, "two/three/2.txt") - delete(files, "two/three/3.txt") - delete(files, "two/four/5.txt") - delete(files, "two/four/6.txt") - delete(files, "two/four/six/7.txt") - - swarmfs2 := mountDir(t, ta.api, files, mi.LatestManifest, testMountDir) - defer swarmfs2.Stop() + _ = mountDir(t, ta.api, dat.files, mi.LatestManifest, testMountDir2) + log.Debug("Directory mounted again") + actualPath := filepath.Join(dirPath, "three") + actualPath = filepath.Join(actualPath, "2.txt") + _, err = os.Stat(actualPath) + if err == nil { + t.Fatal("Expected file to not be present in re-mount after removal, but it is there") + } + actualPath = filepath.Join(dirPath, "four") + _, err = os.Stat(actualPath) + if err == nil { + t.Fatal("Expected file to not be present in re-mount after removal, but it is there") + } + _, err = os.Stat(dirPath) + if err == nil { + t.Fatal("Expected file to not be present in re-mount after removal, but it is there") + } + _, err = dat.swarmfs.Unmount(testMountDir2) + if err != nil { + t.Fatalf("Could not unmount %v", err) + } + log.Debug("subtest terminated") } -func (ta *testAPI) appendFileContentsToEnd(t *testing.T) { - files := make(map[string]fileInfo) - testUploadDir, _ := ioutil.TempDir(os.TempDir(), "appendlargefile-upload") - testMountDir, _ := ioutil.TempDir(os.TempDir(), "appendlargefile-mount") +func (ta *testAPI) appendFileContentsToEndEncrypted(t *testing.T) { + log.Debug("Starting appendFileContentsToEndEncrypted test") + ta.appendFileContentsToEnd(t, true) + log.Debug("Test appendFileContentsToEndEncrypted terminated") +} - line1 := make([]byte, 10) - rand.Read(line1) - files["1.txt"] = fileInfo{0700, 333, 444, line1} - bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir) +func (ta *testAPI) appendFileContentsToEndNonEncrypted(t *testing.T) { + log.Debug("Starting appendFileContentsToEndNonEncrypted test") + ta.appendFileContentsToEnd(t, false) + log.Debug("Test appendFileContentsToEndNonEncrypted terminated") +} - swarmfs1 := mountDir(t, ta.api, files, bzzHash, testMountDir) - defer swarmfs1.Stop() +//append contents to the end of a file; remount and check it's intact +func (ta *testAPI) appendFileContentsToEnd(t *testing.T, toEncrypt bool) { + dat, err := ta.initSubtest("appendFileContentsToEnd") + if err != nil { + t.Fatalf("Couldn't initialize subtest dirs: %v", err) + } + defer os.RemoveAll(dat.testDir) - actualPath := filepath.Join(testMountDir, "1.txt") + dat.toEncrypt = toEncrypt + dat.testUploadDir = filepath.Join(dat.testDir, "appendlargefile-upload") + dat.testMountDir = filepath.Join(dat.testDir, "appendlargefile-mount") + dat.files = make(map[string]fileInfo) + + line1 := testutil.RandomBytes(1, 10) + + dat.files["1.txt"] = fileInfo{0700, 333, 444, line1} + + dat, err = ta.uploadAndMount(dat, t) + if err != nil { + t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) + } + defer dat.swarmfs.Stop() + + actualPath := filepath.Join(dat.testMountDir, "1.txt") fd, err4 := os.OpenFile(actualPath, os.O_RDWR|os.O_APPEND, os.FileMode(0665)) if err4 != nil { t.Fatalf("Could not create file %s : %v", actualPath, err4) } - line2 := make([]byte, 5) - rand.Read(line2) - fd.Seek(int64(len(line1)), 0) - fd.Write(line2) - fd.Close() + defer fd.Close() + log.Debug("file opened") + line2 := testutil.RandomBytes(1, 5) + log.Debug("line read") + _, err = fd.Seek(int64(len(line1)), 0) + if err != nil { + t.Fatalf("Error searching for position to append: %v", err) + } + _, err = fd.Write(line2) + if err != nil { + t.Fatalf("Error appending: %v", err) + } + log.Debug("line written") + err = fd.Close() + if err != nil { + t.Fatalf("Error closing file: %v", err) + } + log.Debug("file closed") - mi1, err5 := swarmfs1.Unmount(testMountDir) + mi1, err5 := dat.swarmfs.Unmount(dat.testMountDir) if err5 != nil { t.Fatalf("Could not unmount %v ", err5) } + log.Debug("Directory unmounted") - // mount again and see if things are okay + // mount again and see if appended file is correct b := [][]byte{line1, line2} line1and2 := bytes.Join(b, []byte("")) - files["1.txt"] = fileInfo{0700, 333, 444, line1and2} - swarmfs2 := mountDir(t, ta.api, files, mi1.LatestManifest, testMountDir) - defer swarmfs2.Stop() + dat.files["1.txt"] = fileInfo{0700, 333, 444, line1and2} + testMountDir2, err6 := addDir(dat.testDir, "remount-mount2") + if err6 != nil { + t.Fatalf("Could not unmount %v", err6) + } + _ = mountDir(t, ta.api, dat.files, mi1.LatestManifest, testMountDir2) + log.Debug("Directory mounted") - checkFile(t, testMountDir, "1.txt", line1and2) + checkFile(t, testMountDir2, "1.txt", line1and2) + + _, err = dat.swarmfs.Unmount(testMountDir2) + if err != nil { + t.Fatalf("Could not unmount %v", err) + } + log.Debug("subtest terminated") } +//run all the tests func TestFUSE(t *testing.T) { + t.Skip("disable fuse tests until they are stable") + //create a data directory for swarm datadir, err := ioutil.TempDir("", "fuse") if err != nil { t.Fatalf("unable to create temp dir: %v", err) } - os.RemoveAll(datadir) + defer os.RemoveAll(datadir) - dpa, err := storage.NewLocalDPA(datadir) + fileStore, err := storage.NewLocalFileStore(datadir, make([]byte, 32)) if err != nil { t.Fatal(err) } - ta := &testAPI{api: api.NewApi(dpa, nil)} - dpa.Start() - defer dpa.Stop() + ta := &testAPI{api: api.NewAPI(fileStore, nil, nil, nil)} - t.Run("mountListAndUmount", ta.mountListAndUnmount) - t.Run("maxMounts", ta.maxMounts) - t.Run("remount", ta.remount) - t.Run("unmount", ta.unmount) - t.Run("unmountWhenResourceBusy", ta.unmountWhenResourceBusy) - t.Run("seekInMultiChunkFile", ta.seekInMultiChunkFile) - t.Run("createNewFile", ta.createNewFile) - t.Run("createNewFileInsideDirectory", ta.createNewFileInsideDirectory) - t.Run("createNewFileInsideNewDirectory", ta.createNewFileInsideNewDirectory) - t.Run("removeExistingFile", ta.removeExistingFile) - t.Run("removeExistingFileInsideDir", ta.removeExistingFileInsideDir) - t.Run("removeNewlyAddedFile", ta.removeNewlyAddedFile) - t.Run("addNewFileAndModifyContents", ta.addNewFileAndModifyContents) - t.Run("removeEmptyDir", ta.removeEmptyDir) - t.Run("removeDirWhichHasFiles", ta.removeDirWhichHasFiles) - t.Run("removeDirWhichHasSubDirs", ta.removeDirWhichHasSubDirs) - t.Run("appendFileContentsToEnd", ta.appendFileContentsToEnd) + //run a short suite of tests + //approx time: 28s + t.Run("mountListAndUnmountEncrypted", ta.mountListAndUnmountEncrypted) + t.Run("remountEncrypted", ta.remountEncrypted) + t.Run("unmountWhenResourceBusyNonEncrypted", ta.unmountWhenResourceBusyNonEncrypted) + t.Run("removeExistingFileEncrypted", ta.removeExistingFileEncrypted) + t.Run("addNewFileAndModifyContentsNonEncrypted", ta.addNewFileAndModifyContentsNonEncrypted) + t.Run("removeDirWhichHasFilesNonEncrypted", ta.removeDirWhichHasFilesNonEncrypted) + t.Run("appendFileContentsToEndEncrypted", ta.appendFileContentsToEndEncrypted) + + //provide longrunning flag to execute all tests + //approx time with longrunning: 140s + if *longrunning { + t.Run("mountListAndUnmountNonEncrypted", ta.mountListAndUnmountNonEncrypted) + t.Run("maxMountsEncrypted", ta.maxMountsEncrypted) + t.Run("maxMountsNonEncrypted", ta.maxMountsNonEncrypted) + t.Run("remountNonEncrypted", ta.remountNonEncrypted) + t.Run("unmountEncrypted", ta.unmountEncrypted) + t.Run("unmountNonEncrypted", ta.unmountNonEncrypted) + t.Run("unmountWhenResourceBusyEncrypted", ta.unmountWhenResourceBusyEncrypted) + t.Run("unmountWhenResourceBusyNonEncrypted", ta.unmountWhenResourceBusyNonEncrypted) + t.Run("seekInMultiChunkFileEncrypted", ta.seekInMultiChunkFileEncrypted) + t.Run("seekInMultiChunkFileNonEncrypted", ta.seekInMultiChunkFileNonEncrypted) + t.Run("createNewFileEncrypted", ta.createNewFileEncrypted) + t.Run("createNewFileNonEncrypted", ta.createNewFileNonEncrypted) + t.Run("createNewFileInsideDirectoryEncrypted", ta.createNewFileInsideDirectoryEncrypted) + t.Run("createNewFileInsideDirectoryNonEncrypted", ta.createNewFileInsideDirectoryNonEncrypted) + t.Run("createNewFileInsideNewDirectoryEncrypted", ta.createNewFileInsideNewDirectoryEncrypted) + t.Run("createNewFileInsideNewDirectoryNonEncrypted", ta.createNewFileInsideNewDirectoryNonEncrypted) + t.Run("removeExistingFileNonEncrypted", ta.removeExistingFileNonEncrypted) + t.Run("removeExistingFileInsideDirEncrypted", ta.removeExistingFileInsideDirEncrypted) + t.Run("removeExistingFileInsideDirNonEncrypted", ta.removeExistingFileInsideDirNonEncrypted) + t.Run("removeNewlyAddedFileEncrypted", ta.removeNewlyAddedFileEncrypted) + t.Run("removeNewlyAddedFileNonEncrypted", ta.removeNewlyAddedFileNonEncrypted) + t.Run("addNewFileAndModifyContentsEncrypted", ta.addNewFileAndModifyContentsEncrypted) + t.Run("removeEmptyDirEncrypted", ta.removeEmptyDirEncrypted) + t.Run("removeEmptyDirNonEncrypted", ta.removeEmptyDirNonEncrypted) + t.Run("removeDirWhichHasFilesEncrypted", ta.removeDirWhichHasFilesEncrypted) + t.Run("removeDirWhichHasSubDirsEncrypted", ta.removeDirWhichHasSubDirsEncrypted) + t.Run("removeDirWhichHasSubDirsNonEncrypted", ta.removeDirWhichHasSubDirsNonEncrypted) + t.Run("appendFileContentsToEndNonEncrypted", ta.appendFileContentsToEndNonEncrypted) + } +} + +func Upload(uploadDir, index string, a *api.API, toEncrypt bool) (hash string, err error) { + fs := api.NewFileSystem(a) + hash, err = fs.Upload(uploadDir, index, toEncrypt) + return hash, err } diff --git a/swarm/fuse/swarmfs_unix.go b/swarm/fuse/swarmfs_unix.go index 75742845a2..54b879a4da 100644 --- a/swarm/fuse/swarmfs_unix.go +++ b/swarm/fuse/swarmfs_unix.go @@ -19,6 +19,7 @@ package fuse import ( + "context" "errors" "fmt" "os" @@ -30,15 +31,16 @@ import ( "bazil.org/fuse" "bazil.org/fuse/fs" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/swarm/api" + "github.com/ethereum/go-ethereum/swarm/log" ) var ( - errEmptyMountPoint = errors.New("need non-empty mount point") - errMaxMountCount = errors.New("max FUSE mount count reached") - errMountTimeout = errors.New("mount timeout") - errAlreadyMounted = errors.New("mount point is already serving") + errEmptyMountPoint = errors.New("need non-empty mount point") + errNoRelativeMountPoint = errors.New("invalid path for mount point (need absolute path)") + errMaxMountCount = errors.New("max FUSE mount count reached") + errMountTimeout = errors.New("mount timeout") + errAlreadyMounted = errors.New("mount point is already serving") ) func isFUSEUnsupportedError(err error) bool { @@ -48,18 +50,20 @@ func isFUSEUnsupportedError(err error) bool { return err == fuse.ErrOSXFUSENotFound } -// information about every active mount +// MountInfo contains information about every active mount type MountInfo struct { MountPoint string StartManifest string LatestManifest string rootDir *SwarmDir fuseConnection *fuse.Conn - swarmApi *api.Api + swarmApi *api.API lock *sync.RWMutex + serveClose chan struct{} } -func NewMountInfo(mhash, mpoint string, sapi *api.Api) *MountInfo { +func NewMountInfo(mhash, mpoint string, sapi *api.API) *MountInfo { + log.Debug("swarmfs NewMountInfo", "hash", mhash, "mount point", mpoint) newMountInfo := &MountInfo{ MountPoint: mpoint, StartManifest: mhash, @@ -68,50 +72,61 @@ func NewMountInfo(mhash, mpoint string, sapi *api.Api) *MountInfo { fuseConnection: nil, swarmApi: sapi, lock: &sync.RWMutex{}, + serveClose: make(chan struct{}), } return newMountInfo } -func (self *SwarmFS) Mount(mhash, mountpoint string) (*MountInfo, error) { - +func (swarmfs *SwarmFS) Mount(mhash, mountpoint string) (*MountInfo, error) { + log.Info("swarmfs", "mounting hash", mhash, "mount point", mountpoint) if mountpoint == "" { return nil, errEmptyMountPoint } + if !strings.HasPrefix(mountpoint, "/") { + return nil, errNoRelativeMountPoint + } cleanedMountPoint, err := filepath.Abs(filepath.Clean(mountpoint)) if err != nil { return nil, err } + log.Trace("swarmfs mount", "cleanedMountPoint", cleanedMountPoint) - self.swarmFsLock.Lock() - defer self.swarmFsLock.Unlock() + swarmfs.swarmFsLock.Lock() + defer swarmfs.swarmFsLock.Unlock() - noOfActiveMounts := len(self.activeMounts) - if noOfActiveMounts >= maxFuseMounts { + noOfActiveMounts := len(swarmfs.activeMounts) + log.Debug("swarmfs mount", "# active mounts", noOfActiveMounts) + if noOfActiveMounts >= maxFUSEMounts { return nil, errMaxMountCount } - if _, ok := self.activeMounts[cleanedMountPoint]; ok { + if _, ok := swarmfs.activeMounts[cleanedMountPoint]; ok { return nil, errAlreadyMounted } - log.Info(fmt.Sprintf("Attempting to mount %s ", cleanedMountPoint)) - _, manifestEntryMap, err := self.swarmApi.BuildDirectoryTree(mhash, true) + log.Trace("swarmfs mount: getting manifest tree") + _, manifestEntryMap, err := swarmfs.swarmApi.BuildDirectoryTree(context.TODO(), mhash, true) if err != nil { return nil, err } - mi := NewMountInfo(mhash, cleanedMountPoint, self.swarmApi) + log.Trace("swarmfs mount: building mount info") + mi := NewMountInfo(mhash, cleanedMountPoint, swarmfs.swarmApi) dirTree := map[string]*SwarmDir{} rootDir := NewSwarmDir("/", mi) - dirTree["/"] = rootDir + log.Trace("swarmfs mount", "rootDir", rootDir) mi.rootDir = rootDir + log.Trace("swarmfs mount: traversing manifest map") for suffix, entry := range manifestEntryMap { - key := common.Hex2Bytes(entry.Hash) + if suffix == "" { //empty suffix means that the file has no name - i.e. this is the default entry in a manifest. Since we cannot have files without a name, let us ignore this entry + log.Warn("Manifest has an empty-path (default) entry which will be ignored in FUSE mount.") + continue + } + addr := common.Hex2Bytes(entry.Hash) fullpath := "/" + suffix basepath := filepath.Dir(fullpath) - parentDir := rootDir dirUntilNow := "" paths := strings.Split(basepath, "/") @@ -128,105 +143,143 @@ func (self *SwarmFS) Mount(mhash, mountpoint string) (*MountInfo, error) { } else { parentDir = dirTree[dirUntilNow] } - } } thisFile := NewSwarmFile(basepath, filepath.Base(fullpath), mi) - thisFile.key = key + thisFile.addr = addr parentDir.files = append(parentDir.files, thisFile) } fconn, err := fuse.Mount(cleanedMountPoint, fuse.FSName("swarmfs"), fuse.VolumeName(mhash)) if isFUSEUnsupportedError(err) { - log.Warn("Fuse not installed", "mountpoint", cleanedMountPoint, "err", err) + log.Error("swarmfs error - FUSE not installed", "mountpoint", cleanedMountPoint, "err", err) return nil, err } else if err != nil { fuse.Unmount(cleanedMountPoint) - log.Warn("Error mounting swarm manifest", "mountpoint", cleanedMountPoint, "err", err) + log.Error("swarmfs error mounting swarm manifest", "mountpoint", cleanedMountPoint, "err", err) return nil, err } mi.fuseConnection = fconn serverr := make(chan error, 1) go func() { - log.Info(fmt.Sprintf("Serving %s at %s", mhash, cleanedMountPoint)) + log.Info("swarmfs", "serving hash", mhash, "at", cleanedMountPoint) filesys := &SwarmRoot{root: rootDir} + //start serving the actual file system; see note below if err := fs.Serve(fconn, filesys); err != nil { - log.Warn(fmt.Sprintf("Could not Serve SwarmFileSystem error: %v", err)) + log.Warn("swarmfs could not serve the requested hash", "error", err) serverr <- err } - + mi.serveClose <- struct{}{} }() + /* + IMPORTANT NOTE: the fs.Serve function is blocking; + Serve builds up the actual fuse file system by calling the + Attr functions on each SwarmFile, creating the file inodes; + specifically calling the swarm's LazySectionReader.Size() to set the file size. + + This can take some time, and it appears that if we access the fuse file system + too early, we can bring the tests to deadlock. The assumption so far is that + at this point, the fuse driver didn't finish to initialize the file system. + + Accessing files too early not only deadlocks the tests, but locks the access + of the fuse file completely, resulting in blocked resources at OS system level. + Even a simple `ls /tmp/testDir/testMountDir` could deadlock in a shell. + + Workaround so far is to wait some time to give the OS enough time to initialize + the fuse file system. During tests, this seemed to address the issue. + + HOWEVER IT SHOULD BE NOTED THAT THIS MAY ONLY BE AN EFFECT, + AND THE DEADLOCK CAUSED BY SOMETHING ELSE BLOCKING ACCESS DUE TO SOME RACE CONDITION + (caused in the bazil.org library and/or the SwarmRoot, SwarmDir and SwarmFile implementations) + */ + time.Sleep(2 * time.Second) + + timer := time.NewTimer(mountTimeout) + defer timer.Stop() // Check if the mount process has an error to report. select { - case <-time.After(mountTimeout): - fuse.Unmount(cleanedMountPoint) + case <-timer.C: + log.Warn("swarmfs timed out mounting over FUSE", "mountpoint", cleanedMountPoint, "err", err) + err := fuse.Unmount(cleanedMountPoint) + if err != nil { + return nil, err + } return nil, errMountTimeout - case err := <-serverr: - fuse.Unmount(cleanedMountPoint) - log.Warn("Error serving swarm FUSE FS", "mountpoint", cleanedMountPoint, "err", err) + log.Warn("swarmfs error serving over FUSE", "mountpoint", cleanedMountPoint, "err", err) + err = fuse.Unmount(cleanedMountPoint) return nil, err case <-fconn.Ready: - log.Info("Now serving swarm FUSE FS", "manifest", mhash, "mountpoint", cleanedMountPoint) + //this signals that the actual mount point from the fuse.Mount call is ready; + //it does not signal though that the file system from fs.Serve is actually fully built up + if err := fconn.MountError; err != nil { + log.Error("Mounting error from fuse driver: ", "err", err) + return nil, err + } + log.Info("swarmfs now served over FUSE", "manifest", mhash, "mountpoint", cleanedMountPoint) } - self.activeMounts[cleanedMountPoint] = mi + timer.Stop() + swarmfs.activeMounts[cleanedMountPoint] = mi return mi, nil } -func (self *SwarmFS) Unmount(mountpoint string) (*MountInfo, error) { - - self.swarmFsLock.Lock() - defer self.swarmFsLock.Unlock() +func (swarmfs *SwarmFS) Unmount(mountpoint string) (*MountInfo, error) { + swarmfs.swarmFsLock.Lock() + defer swarmfs.swarmFsLock.Unlock() cleanedMountPoint, err := filepath.Abs(filepath.Clean(mountpoint)) if err != nil { return nil, err } - mountInfo := self.activeMounts[cleanedMountPoint] + mountInfo := swarmfs.activeMounts[cleanedMountPoint] if mountInfo == nil || mountInfo.MountPoint != cleanedMountPoint { - return nil, fmt.Errorf("%s is not mounted", cleanedMountPoint) + return nil, fmt.Errorf("swarmfs %s is not mounted", cleanedMountPoint) } err = fuse.Unmount(cleanedMountPoint) if err != nil { err1 := externalUnmount(cleanedMountPoint) if err1 != nil { - errStr := fmt.Sprintf("UnMount error: %v", err) + errStr := fmt.Sprintf("swarmfs unmount error: %v", err) log.Warn(errStr) return nil, err1 } } - mountInfo.fuseConnection.Close() - delete(self.activeMounts, cleanedMountPoint) + err = mountInfo.fuseConnection.Close() + if err != nil { + return nil, err + } + delete(swarmfs.activeMounts, cleanedMountPoint) - succString := fmt.Sprintf("UnMounting %v succeeded", cleanedMountPoint) + <-mountInfo.serveClose + + succString := fmt.Sprintf("swarmfs unmounting %v succeeded", cleanedMountPoint) log.Info(succString) return mountInfo, nil } -func (self *SwarmFS) Listmounts() []*MountInfo { - self.swarmFsLock.RLock() - defer self.swarmFsLock.RUnlock() - - rows := make([]*MountInfo, 0, len(self.activeMounts)) - for _, mi := range self.activeMounts { +func (swarmfs *SwarmFS) Listmounts() []*MountInfo { + swarmfs.swarmFsLock.RLock() + defer swarmfs.swarmFsLock.RUnlock() + rows := make([]*MountInfo, 0, len(swarmfs.activeMounts)) + for _, mi := range swarmfs.activeMounts { rows = append(rows, mi) } return rows } -func (self *SwarmFS) Stop() bool { - for mp := range self.activeMounts { - mountInfo := self.activeMounts[mp] - self.Unmount(mountInfo.MountPoint) +func (swarmfs *SwarmFS) Stop() bool { + for mp := range swarmfs.activeMounts { + mountInfo := swarmfs.activeMounts[mp] + swarmfs.Unmount(mountInfo.MountPoint) } return true } diff --git a/swarm/fuse/swarmfs_util.go b/swarm/fuse/swarmfs_util.go index d39966c0e3..4f2e1416b6 100644 --- a/swarm/fuse/swarmfs_util.go +++ b/swarm/fuse/swarmfs_util.go @@ -24,7 +24,7 @@ import ( "os/exec" "runtime" - "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/swarm/log" ) func externalUnmount(mountPoint string) error { @@ -38,38 +38,35 @@ func externalUnmount(mountPoint string) error { // Try FUSE-specific commands if umount didn't work. switch runtime.GOOS { case "darwin": - return exec.CommandContext(ctx, "diskutil", "umount", "force", mountPoint).Run() + return exec.CommandContext(ctx, "diskutil", "umount", mountPoint).Run() case "linux": return exec.CommandContext(ctx, "fusermount", "-u", mountPoint).Run() default: - return fmt.Errorf("unmount: unimplemented") + return fmt.Errorf("swarmfs unmount: unimplemented") } } func addFileToSwarm(sf *SwarmFile, content []byte, size int) error { - - fkey, mhash, err := sf.mountInfo.swarmApi.AddFile(sf.mountInfo.LatestManifest, sf.path, sf.name, content, true) + fkey, mhash, err := sf.mountInfo.swarmApi.AddFile(context.TODO(), sf.mountInfo.LatestManifest, sf.path, sf.name, content, true) if err != nil { return err } sf.lock.Lock() defer sf.lock.Unlock() - sf.key = fkey + sf.addr = fkey sf.fileSize = int64(size) sf.mountInfo.lock.Lock() defer sf.mountInfo.lock.Unlock() sf.mountInfo.LatestManifest = mhash - log.Info("Added new file:", "fname", sf.name, "New Manifest hash", mhash) + log.Info("swarmfs added new file:", "fname", sf.name, "new Manifest hash", mhash) return nil - } func removeFileFromSwarm(sf *SwarmFile) error { - - mkey, err := sf.mountInfo.swarmApi.RemoveFile(sf.mountInfo.LatestManifest, sf.path, sf.name, true) + mkey, err := sf.mountInfo.swarmApi.RemoveFile(context.TODO(), sf.mountInfo.LatestManifest, sf.path, sf.name, true) if err != nil { return err } @@ -78,12 +75,11 @@ func removeFileFromSwarm(sf *SwarmFile) error { defer sf.mountInfo.lock.Unlock() sf.mountInfo.LatestManifest = mkey - log.Info("Removed file:", "fname", sf.name, "New Manifest hash", mkey) + log.Info("swarmfs removed file:", "fname", sf.name, "new Manifest hash", mkey) return nil } func removeDirectoryFromSwarm(sd *SwarmDir) error { - if len(sd.directories) == 0 && len(sd.files) == 0 { return nil } @@ -103,26 +99,23 @@ func removeDirectoryFromSwarm(sd *SwarmDir) error { } return nil - } func appendToExistingFileInSwarm(sf *SwarmFile, content []byte, offset int64, length int64) error { - - fkey, mhash, err := sf.mountInfo.swarmApi.AppendFile(sf.mountInfo.LatestManifest, sf.path, sf.name, sf.fileSize, content, sf.key, offset, length, true) + fkey, mhash, err := sf.mountInfo.swarmApi.AppendFile(context.TODO(), sf.mountInfo.LatestManifest, sf.path, sf.name, sf.fileSize, content, sf.addr, offset, length, true) if err != nil { return err } sf.lock.Lock() defer sf.lock.Unlock() - sf.key = fkey + sf.addr = fkey sf.fileSize = sf.fileSize + int64(len(content)) sf.mountInfo.lock.Lock() defer sf.mountInfo.lock.Unlock() sf.mountInfo.LatestManifest = mhash - log.Info("Appended file:", "fname", sf.name, "New Manifest hash", mhash) + log.Info("swarmfs appended file:", "fname", sf.name, "new Manifest hash", mhash) return nil - } diff --git a/swarm/log/log.go b/swarm/log/log.go new file mode 100644 index 0000000000..ce372632e8 --- /dev/null +++ b/swarm/log/log.go @@ -0,0 +1,48 @@ +package log + +import ( + l "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" +) + +const ( + // CallDepth is set to 1 in order to influence to reported line number of + // the log message with 1 skipped stack frame of calling l.Output() + CallDepth = 1 +) + +// Warn is a convenient alias for log.Warn with stats +func Warn(msg string, ctx ...interface{}) { + metrics.GetOrRegisterCounter("warn", nil).Inc(1) + l.Output(msg, l.LvlWarn, CallDepth, ctx...) +} + +// Error is a convenient alias for log.Error with stats +func Error(msg string, ctx ...interface{}) { + metrics.GetOrRegisterCounter("error", nil).Inc(1) + l.Output(msg, l.LvlError, CallDepth, ctx...) +} + +// Crit is a convenient alias for log.Crit with stats +func Crit(msg string, ctx ...interface{}) { + metrics.GetOrRegisterCounter("crit", nil).Inc(1) + l.Output(msg, l.LvlCrit, CallDepth, ctx...) +} + +// Info is a convenient alias for log.Info with stats +func Info(msg string, ctx ...interface{}) { + metrics.GetOrRegisterCounter("info", nil).Inc(1) + l.Output(msg, l.LvlInfo, CallDepth, ctx...) +} + +// Debug is a convenient alias for log.Debug with stats +func Debug(msg string, ctx ...interface{}) { + metrics.GetOrRegisterCounter("debug", nil).Inc(1) + l.Output(msg, l.LvlDebug, CallDepth, ctx...) +} + +// Trace is a convenient alias for log.Trace with stats +func Trace(msg string, ctx ...interface{}) { + metrics.GetOrRegisterCounter("trace", nil).Inc(1) + l.Output(msg, l.LvlTrace, CallDepth, ctx...) +} diff --git a/swarm/metrics/flags.go b/swarm/metrics/flags.go new file mode 100644 index 0000000000..d348dc3e4d --- /dev/null +++ b/swarm/metrics/flags.go @@ -0,0 +1,108 @@ +// 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 metrics + +import ( + "time" + + "github.com/ethereum/go-ethereum/cmd/utils" + gethmetrics "github.com/ethereum/go-ethereum/metrics" + "github.com/ethereum/go-ethereum/metrics/influxdb" + "github.com/ethereum/go-ethereum/swarm/log" + cli "gopkg.in/urfave/cli.v1" +) + +var ( + MetricsEnableInfluxDBExportFlag = cli.BoolFlag{ + Name: "metrics.influxdb.export", + Usage: "Enable metrics export/push to an external InfluxDB database", + } + 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{ + Name: "metrics.influxdb.database", + Usage: "Metrics InfluxDB database", + Value: "metrics", + } + MetricsInfluxDBUsernameFlag = cli.StringFlag{ + Name: "metrics.influxdb.username", + Usage: "Metrics InfluxDB username", + Value: "", + } + MetricsInfluxDBPasswordFlag = cli.StringFlag{ + Name: "metrics.influxdb.password", + Usage: "Metrics InfluxDB password", + Value: "", + } + // 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 + 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, + MetricsEnableInfluxDBAccountingExportFlag, + MetricsInfluxDBEndpointFlag, + MetricsInfluxDBDatabaseFlag, + MetricsInfluxDBUsernameFlag, + MetricsInfluxDBPasswordFlag, + MetricsInfluxDBTagsFlag, +} + +func Setup(ctx *cli.Context) { + if gethmetrics.Enabled { + log.Info("Enabling swarm metrics collection") + var ( + 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.", 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/swarm/network/README.md b/swarm/network/README.md new file mode 100644 index 0000000000..684ad0c8c0 --- /dev/null +++ b/swarm/network/README.md @@ -0,0 +1,152 @@ +## Streaming + +Streaming is a new protocol of the swarm bzz bundle of protocols. +This protocol provides the basic logic for chunk-based data flow. +It implements simple retrieve requests and delivery using priority queue. +A data exchange stream is a directional flow of chunks between peers. +The source of datachunks is the upstream, the receiver is called the +downstream peer. Each streaming protocol defines an outgoing streamer +and an incoming streamer, the former installing on the upstream, +the latter on the downstream peer. + +Subscribe on StreamerPeer launches an incoming streamer that sends +a subscribe msg upstream. The streamer on the upstream peer +handles the subscribe msg by installing the relevant outgoing streamer +. The modules now engage in a process of upstream sending a sequence of hashes of +chunks downstream (OfferedHashesMsg). The downstream peer evaluates which hashes are needed +and get it delivered by sending back a msg (WantedHashesMsg). + +Historical syncing is supported - currently not the right abstraction -- +state kept across sessions by saving a series of intervals after their last +batch actually arrived. + +Live streaming is also supported, by starting session from the first item +after the subscription. + +Provable data exchange. In case a stream represents a swarm document's data layer +or higher level chunks, streaming up to a certain index is always provable. It saves on +sending intermediate chunks. + +Using the streamer logic, various stream types are easy to implement: + +* light node requests: + * url lookup with offset + * document download + * document upload +* syncing + * live session syncing + * historical syncing +* simple retrieve requests and deliveries +* swarm feeds streams +* receipting for finger pointing + +## Syncing + +Syncing is the process that makes sure storer nodes end up storing all and only the chunks that are requested from them. + +### Requirements + +- eventual consistency: so each chunk historical should be syncable +- since the same chunk can and will arrive from many peers, (network traffic should be +optimised, only one transfer of data per chunk) +- explicit request deliveries should be prioritised higher than recent chunks received +during the ongoing session which in turn should be higher than historical chunks. +- insured chunks should get receipted for finger pointing litigation, the receipts storage +should be organised efficiently, upstream peer should also be able to find these +receipts for a deleted chunk easily to refute their challenge. +- syncing should be resilient to cut connections, metadata should be persisted that +keep track of syncing state across sessions, historical syncing state should survive restart +- extra data structures to support syncing should be kept at minimum +- syncing is not organized separately for chunk types (Swarm feed updates v regular content chunk) +- various types of streams should have common logic abstracted + +Syncing is now entirely mediated by the localstore, ie., no processes or memory leaks due to network contention. +When a new chunk is stored, its chunk hash is index by proximity bin + +peers syncronise by getting the chunks closer to the downstream peer than to the upstream one. +Consequently peers just sync all stored items for the kad bin the receiving peer falls into. +The special case of nearest neighbour sets is handled by the downstream peer +indicating they want to sync all kademlia bins with proximity equal to or higher +than their depth. + +This sync state represents the initial state of a sync connection session. +Retrieval is dictated by downstream peers simply using a special streamer protocol. + +Syncing chunks created during the session by the upstream peer is called live session syncing +while syncing of earlier chunks is historical syncing. + +Once the relevant chunk is retrieved, downstream peer looks up all hash segments in its localstore +and sends to the upstream peer a message with a a bitvector to indicate +missing chunks (e.g., for chunk `k`, hash with chunk internal index which case ) +new items. In turn upstream peer sends the relevant chunk data alongside their index. + +On sending chunks there is a priority queue system. If during looking up hashes in its localstore, +downstream peer hits on an open request then a retrieve request is sent immediately to the upstream peer indicating +that no extra round of checks is needed. If another peers syncer hits the same open request, it is slightly unsafe to not ask +that peer too: if the first one disconnects before delivering or fails to deliver and therefore gets +disconnected, we should still be able to continue with the other. The minimum redundant traffic coming from such simultaneous +eventualities should be sufficiently rare not to warrant more complex treatment. + +Session syncing involves downstream peer to request a new state on a bin from upstream. +using the new state, the range (of chunks) between the previous state and the new one are retrieved +and chunks are requested identical to the historical case. After receiving all the missing chunks +from the new hashes, downstream peer will request a new range. If this happens before upstream peer updates a new state, +we say that session syncing is live or the two peers are in sync. In general the time interval passed since downstream peer request up to the current session cursor is a good indication of a permanent (probably increasing) lag. + +If there is no historical backlog, and downstream peer has an acceptable 'last synced' tag, then it is said to be fully synced with the upstream peer. +If a peer is fully synced with all its storer peers, it can advertise itself as globally fully synced. + +The downstream peer persists the record of the last synced offset. When the two peers disconnect and +reconnect syncing can start from there. +This situation however can also happen while historical syncing is not yet complete. +Effectively this means that the peer needs to persist a record of an arbitrary array of offset ranges covered. + +### Delivery requests + +once the appropriate ranges of the hashstream are retrieved and buffered, downstream peer just scans the hashes, looks them up in localstore, if not found, create a request entry. +The range is referenced by the chunk index. Alongside the name (indicating the stream, e.g., content chunks for bin 6) and the range +downstream peer sends a 128 long bitvector indicating which chunks are needed. +Newly created requests are satisfied bound together in a waitgroup which when done, will promptt sending the next one. +to be able to do check and storage concurrently, we keep a buffer of one, we start with two batches of hashes. +If there is nothing to give, upstream peers SetNextBatch is blocking. Subscription ends with an unsubscribe. which removes the syncer from the map. + +Canceling requests (for instance the late chunks of an erasure batch) should be a chan closed +on the request + +Simple request is also a subscribe +different streaming protocols are different p2p protocols with same message types. +the constructor is the Run function itself. which takes a streamerpeer as argument + + +### provable streams + +The swarm hash over the hash stream has many advantages. It implements a provable data transfer +and provide efficient storage for receipts in the form of inclusion proofs useable for finger pointing litigation. +When challenged on a missing chunk, upstream peer will provide an inclusion proof of a chunk hash against the state of the +sync stream. In order to be able to generate such an inclusion proof, upstream peer needs to store the hash index (counting consecutive hash-size segments) alongside the chunk data and preserve it even when the chunk data is deleted until the chunk is no longer insured. +if there is no valid insurance on the files the entry may be deleted. +As long as the chunk is preserved, no takeover proof will be needed since the node can respond to any challenge. +However, once the node needs to delete an insured chunk for capacity reasons, a receipt should be available to +refute the challenge by finger pointing to a downstream peer. +As part of the deletion protocol then, hashes of insured chunks to be removed are pushed to an infinite stream for every bin. + +Downstream peer on the other hand needs to make sure that they can only be finger pointed about a chunk they did receive and store. +For this the check of a state should be exhaustive. If historical syncing finishes on one state, all hashes before are covered, no +surprises. In other words historical syncing this process is self verifying. With session syncing however, it is not enough to check going back covering the range from old offset to new. Continuity (i.e., that the new state is extension of the old) needs to be verified: after downstream peer reads the range into a buffer, it appends the buffer the last known state at the last known offset and verifies the resulting hash matches +the latest state. Past intervals of historical syncing are checked via the session root. +Upstream peer signs the states, downstream peers can use as handover proofs. +Downstream peers sign off on a state together with an initial offset. + +Once historical syncing is complete and the session does not lag, downstream peer only preserves the latest upstream state and store the signed version. + +Upstream peer needs to keep the latest takeover states: each deleted chunk's hash should be covered by takeover proof of at least one peer. If historical syncing is complete, upstream peer typically will store only the latest takeover proof from downstream peer. +Crucially, the structure is totally independent of the number of peers in the bin, so it scales extremely well. + +## implementation + +The simplest protocol just involves upstream peer to prefix the key with the kademlia proximity order (say 0-15 or 0-31) +and simply iterate on index per bin when syncing with a peer. + +priority queues are used for sending chunks so that user triggered requests should be responded to first, session syncing second, and historical with lower priority. +The request on chunks remains implemented as a dataless entry in the memory store. +The lifecycle of this object should be more carefully thought through, ie., when it fails to retrieve it should be removed. diff --git a/swarm/network/bitvector/bitvector.go b/swarm/network/bitvector/bitvector.go new file mode 100644 index 0000000000..9583285023 --- /dev/null +++ b/swarm/network/bitvector/bitvector.go @@ -0,0 +1,62 @@ +// 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 bitvector + +import ( + "errors" +) + +var errInvalidLength = errors.New("invalid length") + +type BitVector struct { + len int + b []byte +} + +func New(l int) (bv *BitVector, err error) { + return NewFromBytes(make([]byte, l/8+1), l) +} + +func NewFromBytes(b []byte, l int) (bv *BitVector, err error) { + if l <= 0 { + return nil, errInvalidLength + } + if len(b)*8 < l { + return nil, errInvalidLength + } + return &BitVector{ + len: l, + b: b, + }, nil +} + +func (bv *BitVector) Get(i int) bool { + bi := i / 8 + return bv.b[bi]&(0x1<. + +package bitvector + +import "testing" + +func TestBitvectorNew(t *testing.T) { + _, err := New(0) + if err != errInvalidLength { + t.Errorf("expected err %v, got %v", errInvalidLength, err) + } + + _, err = NewFromBytes(nil, 0) + if err != errInvalidLength { + t.Errorf("expected err %v, got %v", errInvalidLength, err) + } + + _, err = NewFromBytes([]byte{0}, 9) + if err != errInvalidLength { + t.Errorf("expected err %v, got %v", errInvalidLength, err) + } + + _, err = NewFromBytes(make([]byte, 8), 8) + if err != nil { + t.Error(err) + } +} + +func TestBitvectorGetSet(t *testing.T) { + for _, length := range []int{ + 1, + 2, + 4, + 8, + 9, + 15, + 16, + } { + bv, err := New(length) + if err != nil { + t.Errorf("error for length %v: %v", length, err) + } + + for i := 0; i < length; i++ { + if bv.Get(i) { + t.Errorf("expected false for element on index %v", i) + } + } + + func() { + defer func() { + if err := recover(); err == nil { + t.Errorf("expecting panic") + } + }() + bv.Get(length + 8) + }() + + for i := 0; i < length; i++ { + bv.Set(i, true) + for j := 0; j < length; j++ { + if j == i { + if !bv.Get(j) { + t.Errorf("element on index %v is not set to true", i) + } + } else { + if bv.Get(j) { + t.Errorf("element on index %v is not false", i) + } + } + } + + bv.Set(i, false) + + if bv.Get(i) { + t.Errorf("element on index %v is not set to false", i) + } + } + } +} + +func TestBitvectorNewFromBytesGet(t *testing.T) { + bv, err := NewFromBytes([]byte{8}, 8) + if err != nil { + t.Error(err) + } + if !bv.Get(3) { + t.Fatalf("element 3 is not set to true: state %08b", bv.b[0]) + } +} diff --git a/whisper/whisperv5/config.go b/swarm/network/common.go similarity index 72% rename from whisper/whisperv5/config.go rename to swarm/network/common.go index fcc2307046..15b2e20604 100644 --- a/whisper/whisperv5/config.go +++ b/swarm/network/common.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 @@ -14,14 +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 whisperv5 +package network -type Config struct { - MaxMessageSize uint32 `toml:",omitempty"` - MinimumAcceptedPOW float64 `toml:",omitempty"` -} +import ( + "fmt" + "strings" +) -var DefaultConfig = Config{ - MaxMessageSize: DefaultMaxMessageSize, - MinimumAcceptedPOW: DefaultMinimumPoW, +func LogAddrs(nns [][]byte) string { + var nnsa []string + for _, nn := range nns { + nnsa = append(nnsa, fmt.Sprintf("%08x", nn[:4])) + } + return strings.Join(nnsa, ", ") } diff --git a/swarm/network/depo.go b/swarm/network/depo.go deleted file mode 100644 index 17540d2f9f..0000000000 --- a/swarm/network/depo.go +++ /dev/null @@ -1,217 +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 network - -import ( - "bytes" - "encoding/binary" - "fmt" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/swarm/storage" -) - -// Handler for storage/retrieval related protocol requests -// implements the StorageHandler interface used by the bzz protocol -type Depo struct { - hashfunc storage.SwarmHasher - localStore storage.ChunkStore - netStore storage.ChunkStore -} - -func NewDepo(hash storage.SwarmHasher, localStore, remoteStore storage.ChunkStore) *Depo { - return &Depo{ - hashfunc: hash, - localStore: localStore, - netStore: remoteStore, // entrypoint internal - } -} - -// Handles UnsyncedKeysMsg after msg decoding - unsynced hashes upto sync state -// * the remote sync state is just stored and handled in protocol -// * filters through the new syncRequests and send the ones missing -// * back immediately as a deliveryRequest message -// * empty message just pings back for more (is this needed?) -// * strict signed sync states may be needed. -func (self *Depo) HandleUnsyncedKeysMsg(req *unsyncedKeysMsgData, p *peer) error { - unsynced := req.Unsynced - var missing []*syncRequest - var chunk *storage.Chunk - var err error - for _, req := range unsynced { - // skip keys that are found, - chunk, err = self.localStore.Get(req.Key[:]) - if err != nil || chunk.SData == nil { - missing = append(missing, req) - } - } - log.Debug(fmt.Sprintf("Depo.HandleUnsyncedKeysMsg: received %v unsynced keys: %v missing. new state: %v", len(unsynced), len(missing), req.State)) - log.Trace(fmt.Sprintf("Depo.HandleUnsyncedKeysMsg: received %v", unsynced)) - // send delivery request with missing keys - err = p.deliveryRequest(missing) - if err != nil { - return err - } - // set peers state to persist - p.syncState = req.State - return nil -} - -// Handles deliveryRequestMsg -// * serves actual chunks asked by the remote peer -// by pushing to the delivery queue (sync db) of the correct priority -// (remote peer is free to reprioritize) -// * the message implies remote peer wants more, so trigger for -// * new outgoing unsynced keys message is fired -func (self *Depo) HandleDeliveryRequestMsg(req *deliveryRequestMsgData, p *peer) error { - deliver := req.Deliver - // queue the actual delivery of a chunk () - log.Trace(fmt.Sprintf("Depo.HandleDeliveryRequestMsg: received %v delivery requests: %v", len(deliver), deliver)) - for _, sreq := range deliver { - // TODO: look up in cache here or in deliveries - // priorities are taken from the message so the remote party can - // reprioritise to at their leisure - // r = self.pullCached(sreq.Key) // pulls and deletes from cache - Push(p, sreq.Key, sreq.Priority) - } - - // sends it out as unsyncedKeysMsg - p.syncer.sendUnsyncedKeys() - return nil -} - -// the entrypoint for store requests coming from the bzz wire protocol -// if key found locally, return. otherwise -// remote is untrusted, so hash is verified and chunk passed on to NetStore -func (self *Depo) HandleStoreRequestMsg(req *storeRequestMsgData, p *peer) { - var islocal bool - req.from = p - chunk, err := self.localStore.Get(req.Key) - switch { - case err != nil: - log.Trace(fmt.Sprintf("Depo.handleStoreRequest: %v not found locally. create new chunk/request", req.Key)) - // not found in memory cache, ie., a genuine store request - // create chunk - chunk = storage.NewChunk(req.Key, nil) - - case chunk.SData == nil: - // found chunk in memory store, needs the data, validate now - log.Trace(fmt.Sprintf("Depo.HandleStoreRequest: %v. request entry found", req)) - - default: - // data is found, store request ignored - // this should update access count? - log.Trace(fmt.Sprintf("Depo.HandleStoreRequest: %v found locally. ignore.", req)) - islocal = true - //return - } - - hasher := self.hashfunc() - hasher.Write(req.SData) - if !bytes.Equal(hasher.Sum(nil), req.Key) { - // data does not validate, ignore - // TODO: peer should be penalised/dropped? - log.Warn(fmt.Sprintf("Depo.HandleStoreRequest: chunk invalid. store request ignored: %v", req)) - return - } - - if islocal { - return - } - // update chunk with size and data - chunk.SData = req.SData // protocol validates that SData is minimum 9 bytes long (int64 size + at least one byte of data) - chunk.Size = int64(binary.LittleEndian.Uint64(req.SData[0:8])) - log.Trace(fmt.Sprintf("delivery of %v from %v", chunk, p)) - chunk.Source = p - self.netStore.Put(chunk) -} - -// entrypoint for retrieve requests coming from the bzz wire protocol -// checks swap balance - return if peer has no credit -func (self *Depo) HandleRetrieveRequestMsg(req *retrieveRequestMsgData, p *peer) { - req.from = p - // swap - record credit for 1 request - // note that only charge actual reqsearches - var err error - if p.swap != nil { - err = p.swap.Add(1) - } - if err != nil { - log.Warn(fmt.Sprintf("Depo.HandleRetrieveRequest: %v - cannot process request: %v", req.Key.Log(), err)) - return - } - - // call storage.NetStore#Get which - // blocks until local retrieval finished - // launches cloud retrieval - chunk, _ := self.netStore.Get(req.Key) - req = self.strategyUpdateRequest(chunk.Req, req) - // check if we can immediately deliver - if chunk.SData != nil { - log.Trace(fmt.Sprintf("Depo.HandleRetrieveRequest: %v - content found, delivering...", req.Key.Log())) - - if req.MaxSize == 0 || int64(req.MaxSize) >= chunk.Size { - sreq := &storeRequestMsgData{ - Id: req.Id, - Key: chunk.Key, - SData: chunk.SData, - requestTimeout: req.timeout, // - } - p.syncer.addRequest(sreq, DeliverReq) - } else { - log.Trace(fmt.Sprintf("Depo.HandleRetrieveRequest: %v - content found, not wanted", req.Key.Log())) - } - } else { - log.Trace(fmt.Sprintf("Depo.HandleRetrieveRequest: %v - content not found locally. asked swarm for help. will get back", req.Key.Log())) - } -} - -// add peer request the chunk and decides the timeout for the response if still searching -func (self *Depo) strategyUpdateRequest(rs *storage.RequestStatus, origReq *retrieveRequestMsgData) (req *retrieveRequestMsgData) { - log.Trace(fmt.Sprintf("Depo.strategyUpdateRequest: key %v", origReq.Key.Log())) - // we do not create an alternative one - req = origReq - if rs != nil { - self.addRequester(rs, req) - req.setTimeout(self.searchTimeout(rs, req)) - } - return -} - -// decides the timeout promise sent with the immediate peers response to a retrieve request -// if timeout is explicitly set and expired -func (self *Depo) searchTimeout(rs *storage.RequestStatus, req *retrieveRequestMsgData) (timeout *time.Time) { - reqt := req.getTimeout() - t := time.Now().Add(searchTimeout) - if reqt != nil && reqt.Before(t) { - return reqt - } else { - return &t - } -} - -/* -adds a new peer to an existing open request -only add if less than requesterCount peers forwarded the same request id so far -note this is done irrespective of status (searching or found) -*/ -func (self *Depo) addRequester(rs *storage.RequestStatus, req *retrieveRequestMsgData) { - log.Trace(fmt.Sprintf("Depo.addRequester: key %v - add peer to req.Id %v", req.Key.Log(), req.Id)) - list := rs.Requesters[req.Id] - rs.Requesters[req.Id] = append(list, req) -} diff --git a/swarm/network/discovery.go b/swarm/network/discovery.go new file mode 100644 index 0000000000..4c503047a5 --- /dev/null +++ b/swarm/network/discovery.go @@ -0,0 +1,203 @@ +// 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 network + +import ( + "context" + "fmt" + "sync" + + "github.com/ethereum/go-ethereum/swarm/pot" +) + +// discovery bzz extension for requesting and relaying node address records + +// Peer wraps BzzPeer and embeds Kademlia overlay connectivity driver +type Peer struct { + *BzzPeer + kad *Kademlia + sentPeers bool // whether we already sent peer closer to this address + mtx sync.RWMutex // + peers map[string]bool // tracks node records sent to the peer + depth uint8 // the proximity order advertised by remote as depth of saturation +} + +// NewPeer constructs a discovery peer +func NewPeer(p *BzzPeer, kad *Kademlia) *Peer { + d := &Peer{ + kad: kad, + BzzPeer: p, + peers: make(map[string]bool), + } + // record remote as seen so we never send a peer its own record + d.seen(p.BzzAddr) + return d +} + +// HandleMsg is the message handler that delegates incoming messages +func (d *Peer) HandleMsg(ctx context.Context, msg interface{}) error { + switch msg := msg.(type) { + + case *peersMsg: + return d.handlePeersMsg(msg) + + case *subPeersMsg: + return d.handleSubPeersMsg(msg) + + default: + return fmt.Errorf("unknown message type: %T", msg) + } +} + +// 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 { + val.NotifyDepth(depth) + return true + } + kad.EachConn(nil, 255, f) +} + +// NotifyPeer informs all peers about a newly added node +func NotifyPeer(p *BzzAddr, k *Kademlia) { + f := func(val *Peer, po int) bool { + val.NotifyPeer(p, uint8(po)) + return true + } + k.EachConn(p.Address(), 255, f) +} + +// NotifyPeer notifies the remote node (recipient) about a peer if +// the peer's PO is within the recipients advertised depth +// OR the peer is closer to the recipient than self +// unless already notified during the connection session +func (d *Peer) NotifyPeer(a *BzzAddr, po uint8) { + // immediately return + if (po < d.getDepth() && pot.ProxCmp(d.kad.BaseAddr(), d, a) != 1) || d.seen(a) { + return + } + resp := &peersMsg{ + Peers: []*BzzAddr{a}, + } + go d.Send(context.TODO(), resp) +} + +// NotifyDepth sends a subPeers Msg to the receiver notifying them about +// a change in the depth of saturation +func (d *Peer) NotifyDepth(po uint8) { + go d.Send(context.TODO(), &subPeersMsg{Depth: po}) +} + +/* +peersMsg is the message to pass peer information +It is always a response to a peersRequestMsg + +The encoding of a peer address is identical the devp2p base protocol peers +messages: [IP, Port, NodeID], +Note that a node's FileStore address is not the NodeID but the hash of the NodeID. + +TODO: +To mitigate against spurious peers messages, requests should be remembered +and correctness of responses should be checked + +If the proxBin of peers in the response is incorrect the sender should be +disconnected +*/ + +// peersMsg encapsulates an array of peer addresses +// used for communicating about known peers +// relevant for bootstrapping connectivity and updating peersets +type peersMsg struct { + Peers []*BzzAddr +} + +// String pretty prints a peersMsg +func (msg peersMsg) String() string { + return fmt.Sprintf("%T: %v", msg, msg.Peers) +} + +// handlePeersMsg called by the protocol when receiving peerset (for target address) +// list of nodes ([]PeerAddr in peersMsg) is added to the overlay db using the +// Register interface method +func (d *Peer) handlePeersMsg(msg *peersMsg) error { + // register all addresses + if len(msg.Peers) == 0 { + return nil + } + + for _, a := range msg.Peers { + d.seen(a) + NotifyPeer(a, d.kad) + } + return d.kad.Register(msg.Peers...) +} + +// subPeers msg is communicating the depth of the overlay table of a peer +type subPeersMsg struct { + Depth uint8 +} + +// String returns the pretty printer +func (msg subPeersMsg) String() string { + return fmt.Sprintf("%T: request peers > PO%02d. ", msg, msg.Depth) +} + +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) bool { + if pob, _ := Pof(d, d.kad.BaseAddr(), 0); pob > po { + return false + } + if !d.seen(p.BzzAddr) { + peers = append(peers, p.BzzAddr) + } + return true + }) + if len(peers) > 0 { + go d.Send(context.TODO(), &peersMsg{Peers: peers}) + } + } + d.sentPeers = true + return nil +} + +// seen takes an peer address and checks if it was sent to a peer already +// if not, marks the peer as sent +func (d *Peer) seen(p *BzzAddr) bool { + d.mtx.Lock() + defer d.mtx.Unlock() + k := string(p.Address()) + if d.peers[k] { + return true + } + d.peers[k] = true + return false +} + +func (d *Peer) getDepth() uint8 { + d.mtx.RLock() + defer d.mtx.RUnlock() + return d.depth +} + +func (d *Peer) setDepth(depth uint8) { + d.mtx.Lock() + defer d.mtx.Unlock() + d.depth = depth +} diff --git a/swarm/network/discovery_test.go b/swarm/network/discovery_test.go new file mode 100644 index 0000000000..dd3299c0f1 --- /dev/null +++ b/swarm/network/discovery_test.go @@ -0,0 +1,57 @@ +// 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 network + +import ( + "testing" + + p2ptest "github.com/ethereum/go-ethereum/p2p/testing" +) + +/*** + * + * - after connect, that outgoing subpeersmsg is sent + * + */ +func TestDiscovery(t *testing.T) { + params := NewHiveParams() + s, pp := newHiveTester(t, params, 1, nil) + + node := s.Nodes[0] + raddr := NewAddr(node) + pp.Register(raddr) + + // start the hive and wait for the connection + pp.Start(s.Server) + defer pp.Stop() + + // send subPeersMsg to the peer + err := s.TestExchanges(p2ptest.Exchange{ + Label: "outgoing subPeersMsg", + Expects: []p2ptest.Expect{ + { + Code: 1, + Msg: &subPeersMsg{Depth: 0}, + Peer: node.ID(), + }, + }, + }) + + if err != nil { + t.Fatal(err) + } +} diff --git a/swarm/network/fetcher.go b/swarm/network/fetcher.go new file mode 100644 index 0000000000..6b21751669 --- /dev/null +++ b/swarm/network/fetcher.go @@ -0,0 +1,323 @@ +// 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 network + +import ( + "context" + "sync" + "time" + + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/swarm/storage" +) + +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 + +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 because the requester cancelled/timed out +// Fetcher self destroys itself after it is completed. +// TODO: cancel all forward requests after termination +type Fetcher struct { + protoRequestFunc RequestFunc // request function fetcher calls to issue retrieve request for a chunk + 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 { + Addr storage.Address // chunk address + Source *enode.ID // nodeID of peer to request from (can be nil) + SkipCheck bool // whether to offer the chunk first or deliver directly + peersToSkip *sync.Map // peers not to request chunk from (only makes sense if source is nil) + HopCount uint8 // number of forwarded requests (hops) +} + +// NewRequest returns a new instance of Request based on chunk address skip check and +// a map of peers to skip. +func NewRequest(addr storage.Address, skipCheck bool, peersToSkip *sync.Map) *Request { + return &Request{ + Addr: addr, + SkipCheck: skipCheck, + peersToSkip: peersToSkip, + } +} + +// SkipPeer returns if the peer with nodeID should not be requested to deliver a chunk. +// Peers to skip are kept per Request and for a time period of RequestTimeout. +// This function is used in stream package in Delivery.RequestFromPeers to optimize +// requests for chunks. +func (r *Request) SkipPeer(nodeID string) bool { + val, ok := r.peersToSkip.Load(nodeID) + if !ok { + return false + } + t, ok := val.(time.Time) + if ok && time.Now().After(t.Add(RequestTimeout)) { + // deadline expired + r.peersToSkip.Delete(nodeID) + return false + } + return true +} + +// FetcherFactory is initialised with a request function and can create fetchers +type FetcherFactory struct { + request RequestFunc + skipCheck bool +} + +// NewFetcherFactory takes a request function and skip check parameter and creates a FetcherFactory +func NewFetcherFactory(request RequestFunc, skipCheck bool) *FetcherFactory { + return &FetcherFactory{ + request: request, + skipCheck: skipCheck, + } +} + +// 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, 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(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(source *enode.ID) { + // First we need to have this select to make sure that we return if context is done + select { + case <-f.ctx.Done(): + return + default: + } + + // This select alone would not guarantee that we return of context is done, it could potentially + // 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 <-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(hopCount uint8) { + // First we need to have this select to make sure that we return if context is done + select { + case <-f.ctx.Done(): + return + default: + } + + if hopCount >= maxHopCount { + log.Debug("fetcher request hop count limit reached", "hops", hopCount) + return + } + + // This select alone would not guarantee that we return of context is done, it could potentially + // 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 <-f.ctx.Done(): + } +} + +// start prepares the Fetcher +// it keeps the Fetcher alive within the lifecycle of the passed context +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 + waitC <-chan time.Time // timer channel + sources []*enode.ID // known sources, ie. peers that offered the chunk + requested bool // true if the chunk was actually requested + hopCount uint8 + ) + gone := make(chan *enode.ID) // channel to signal that a peer we requested from disconnected + + // 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 + // 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 { + select { + + // incoming offer + case source := <-f.offerC: + log.Trace("new source", "peer addr", source, "request addr", f.addr) + // 1) the chunk is offered by a syncing peer + // add to known sources + sources = append(sources, source) + // launch a request to the source iff the chunk was requested (not just expected because its offered by a syncing peer) + doRequest = requested + + // 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 + 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 + + // 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: requesting", "request addr", f.addr) + doRequest = requested + + // all Fetcher context closed, can quit + case <-f.ctx.Done(): + log.Trace("terminate fetcher", "request addr", f.addr) + // 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(gone, peers, sources, hopCount) + if err != nil { + log.Info("unable to request", "request addr", f.addr, "err", err) + } + } + + // if wait channel is not set, set it to a timer + if requested { + if wait == nil { + wait = time.NewTimer(f.searchTimeout) + defer wait.Stop() + waitC = wait.C + } else { + // stop the timer and drain the channel if it was not drained earlier + if !wait.Stop() { + select { + case <-wait.C: + default: + } + } + // reset the timer to go off after defaultSearchTimeout + wait.Reset(f.searchTimeout) + } + } + doRequest = false + } +} + +// doRequest attempts at finding a peer to request the chunk from +// * first it tries to request explicitly from peers that are known to have offered the chunk +// * if there are no such peers (available) it tries to request it from a peer closest to the chunk address +// excluding those in the peersToSkip map +// * if no such peer is found an error is returned +// +// if a request is successful, +// * 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(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{} + + req := &Request{ + Addr: f.addr, + SkipCheck: f.skipCheck, + peersToSkip: peersToSkip, + HopCount: hopCount, + } + + foundSource := false + // iterate over known sources + for i = 0; i < len(sources); i++ { + req.Source = sources[i] + var err error + 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 + sources = append(sources[:i], sources[i+1:]...) + foundSource = true + break + } + } + + // if there are no known sources, or none available, we try request from a closest node + if !foundSource { + req.Source = nil + var err error + sourceID, quit, err = f.protoRequestFunc(f.ctx, req) + if err != nil { + // if no peers found to request from + return sources, err + } + } + // add peer to the set of peers to skip from now + peersToSkip.Store(sourceID.String(), time.Now()) + + // if the quit channel is closed, it indicates that the source peer we requested from + // disconnected or terminated its streamer + // here start a go routine that watches this channel and reports the source peer on the gone channel + // this go routine quits if the fetcher global context is done to prevent process leak + go func() { + select { + case <-quit: + gone <- sourceID + case <-f.ctx.Done(): + } + }() + return sources, nil +} diff --git a/swarm/network/fetcher_test.go b/swarm/network/fetcher_test.go new file mode 100644 index 0000000000..4e464f10f3 --- /dev/null +++ b/swarm/network/fetcher_test.go @@ -0,0 +1,476 @@ +// 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 network + +import ( + "context" + "sync" + "testing" + "time" + + "github.com/ethereum/go-ethereum/p2p/enode" +) + +var requestedPeerID = enode.HexID("3431c3939e1ee2a6345e976a8234f9870152d64879f30bc272a074f6859e75e8") +var sourcePeerID = enode.HexID("99d8594b52298567d2ca3f4c441a5ba0140ee9245e26460d01102a52773c73b9") + +// mockRequester pushes every request to the requestC channel when its doRequest function is called +type mockRequester struct { + // requests []Request + requestC chan *Request // when a request is coming it is pushed to requestC + waitTimes []time.Duration // with waitTimes[i] you can define how much to wait on the ith request (optional) + count int //counts the number of requests + quitC chan struct{} +} + +func newMockRequester(waitTimes ...time.Duration) *mockRequester { + return &mockRequester{ + requestC: make(chan *Request), + waitTimes: waitTimes, + quitC: make(chan struct{}), + } +} + +func (m *mockRequester) doRequest(ctx context.Context, request *Request) (*enode.ID, chan struct{}, error) { + waitTime := time.Duration(0) + if m.count < len(m.waitTimes) { + waitTime = m.waitTimes[m.count] + m.count++ + } + time.Sleep(waitTime) + m.requestC <- request + + // if there is a Source in the request use that, if not use the global requestedPeerId + source := request.Source + if source == nil { + source = &requestedPeerID + } + return source, m.quitC, nil +} + +// TestFetcherSingleRequest creates a Fetcher using mockRequester, and run it with a sample set of peers to skip. +// mockRequester pushes a Request on a channel every time the request function is called. Using +// this channel we test if calling Fetcher.Request calls the request function, and whether it uses +// the correct peers to skip which we provided for the fetcher.run function. +func TestFetcherSingleRequest(t *testing.T) { + requester := newMockRequester() + addr := make([]byte, 32) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + fetcher := NewFetcher(ctx, addr, requester.doRequest, true) + + peers := []string{"a", "b", "c", "d"} + peersToSkip := &sync.Map{} + for _, p := range peers { + peersToSkip.Store(p, time.Now()) + } + + go fetcher.run(peersToSkip) + + fetcher.Request(0) + + select { + case request := <-requester.requestC: + // request should contain all peers from peersToSkip provided to the fetcher + for _, p := range peers { + if _, ok := request.peersToSkip.Load(p); !ok { + t.Fatalf("request.peersToSkip misses peer") + } + } + + // source peer should be also added to peersToSkip eventually + time.Sleep(100 * time.Millisecond) + if _, ok := request.peersToSkip.Load(requestedPeerID.String()); !ok { + t.Fatalf("request.peersToSkip does not contain peer returned by the request function") + } + + // hopCount in the forwarded request should be incremented + if request.HopCount != 1 { + t.Fatalf("Expected request.HopCount 1 got %v", request.HopCount) + } + + // fetch should trigger a request, if it doesn't happen in time, test should fail + case <-time.After(200 * time.Millisecond): + t.Fatalf("fetch timeout") + } +} + +// TestCancelStopsFetcher tests that a cancelled fetcher does not initiate further requests even if its fetch function is called +func TestFetcherCancelStopsFetcher(t *testing.T) { + requester := newMockRequester() + addr := make([]byte, 32) + + 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(peersToSkip) + cancel() + + // we call Request with an active context + fetcher.Request(0) + + // fetcher should not initiate request, we can only check by waiting a bit and making sure no request is happening + select { + case <-requester.requestC: + t.Fatalf("cancelled fetcher initiated request") + case <-time.After(200 * time.Millisecond): + } +} + +// 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) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + fetcher := NewFetcher(ctx, addr, requester.doRequest, true) + + peersToSkip := &sync.Map{} + + // we start the fetcher with an active context + go fetcher.run(peersToSkip) + + // we call Request with a cancelled context + fetcher.Request(0) + + // fetcher should not initiate request, we can only check by waiting a bit and making sure no request is happening + select { + case <-requester.requestC: + t.Fatalf("cancelled fetch function initiated request") + case <-time.After(200 * time.Millisecond): + } + + // if there is another Request with active context, there should be a request, because the fetcher itself is not cancelled + fetcher.Request(0) + + select { + case <-requester.requestC: + case <-time.After(200 * time.Millisecond): + t.Fatalf("expected request") + } +} + +// TestOfferUsesSource tests Fetcher Offer behavior. +// In this case there should be 1 (and only one) request initiated from the source peer, and the +// source nodeid should appear in the peersToSkip map. +func TestFetcherOfferUsesSource(t *testing.T) { + requester := newMockRequester(100 * time.Millisecond) + addr := make([]byte, 32) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + fetcher := NewFetcher(ctx, addr, requester.doRequest, true) + + peersToSkip := &sync.Map{} + + // start the fetcher + go fetcher.run(peersToSkip) + + // call the Offer function with the source peer + fetcher.Offer(&sourcePeerID) + + // fetcher should not initiate request + select { + case <-requester.requestC: + t.Fatalf("fetcher initiated request") + case <-time.After(200 * time.Millisecond): + } + + // call Request after the Offer + fetcher.Request(0) + + // there should be exactly 1 request coming from fetcher + var request *Request + select { + case request = <-requester.requestC: + if *request.Source != sourcePeerID { + t.Fatalf("Expected source id %v got %v", sourcePeerID, request.Source) + } + case <-time.After(200 * time.Millisecond): + t.Fatalf("fetcher did not initiate request") + } + + select { + case <-requester.requestC: + t.Fatalf("Fetcher number of requests expected 1 got 2") + case <-time.After(200 * time.Millisecond): + } + + // source peer should be added to peersToSkip eventually + time.Sleep(100 * time.Millisecond) + if _, ok := request.peersToSkip.Load(sourcePeerID.String()); !ok { + t.Fatalf("SourcePeerId not added to peersToSkip") + } +} + +func TestFetcherOfferAfterRequestUsesSourceFromContext(t *testing.T) { + requester := newMockRequester(100 * time.Millisecond) + addr := make([]byte, 32) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + fetcher := NewFetcher(ctx, addr, requester.doRequest, true) + + peersToSkip := &sync.Map{} + + // start the fetcher + go fetcher.run(peersToSkip) + + // call Request first + fetcher.Request(0) + + // there should be a request coming from fetcher + var request *Request + select { + case request = <-requester.requestC: + if request.Source != nil { + t.Fatalf("Incorrect source peer id, expected nil got %v", request.Source) + } + case <-time.After(200 * time.Millisecond): + t.Fatalf("fetcher did not initiate request") + } + + // after the Request call Offer + fetcher.Offer(&sourcePeerID) + + // there should be a request coming from fetcher + select { + case request = <-requester.requestC: + if *request.Source != sourcePeerID { + t.Fatalf("Incorrect source peer id, expected %v got %v", sourcePeerID, request.Source) + } + case <-time.After(200 * time.Millisecond): + t.Fatalf("fetcher did not initiate request") + } + + // source peer should be added to peersToSkip eventually + time.Sleep(100 * time.Millisecond) + if _, ok := request.peersToSkip.Load(sourcePeerID.String()); !ok { + t.Fatalf("SourcePeerId not added to peersToSkip") + } +} + +// TestFetcherRetryOnTimeout tests that fetch retries after searchTimeOut has passed +func TestFetcherRetryOnTimeout(t *testing.T) { + requester := newMockRequester() + addr := make([]byte, 32) + + 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(peersToSkip) + + // call the fetch function with an active context + fetcher.Request(0) + + // after 100ms the first request should be initiated + time.Sleep(100 * time.Millisecond) + + select { + case <-requester.requestC: + default: + t.Fatalf("fetch did not initiate request") + } + + // after another 100ms no new request should be initiated, because search timeout is 250ms + time.Sleep(100 * time.Millisecond) + + select { + case <-requester.requestC: + t.Fatalf("unexpected request from fetcher") + default: + } + + // after another 300ms search timeout is over, there should be a new request + time.Sleep(300 * time.Millisecond) + + select { + case <-requester.requestC: + default: + t.Fatalf("fetch did not retry request") + } +} + +// TestFetcherFactory creates a FetcherFactory and checks if the factory really creates and starts +// a Fetcher when it return a fetch function. We test the fetching functionality just by checking if +// a request is initiated when the fetch function is called +func TestFetcherFactory(t *testing.T) { + requester := newMockRequester(100 * time.Millisecond) + addr := make([]byte, 32) + fetcherFactory := NewFetcherFactory(requester.doRequest, false) + + peersToSkip := &sync.Map{} + + fetcher := fetcherFactory.New(context.Background(), addr, peersToSkip) + + fetcher.Request(0) + + // check if the created fetchFunction really starts a fetcher and initiates a request + select { + case <-requester.requestC: + case <-time.After(200 * time.Millisecond): + t.Fatalf("fetch timeout") + } + +} + +func TestFetcherRequestQuitRetriesRequest(t *testing.T) { + requester := newMockRequester() + addr := make([]byte, 32) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + fetcher := NewFetcher(ctx, addr, requester.doRequest, true) + + // 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: + case <-time.After(200 * time.Millisecond): + t.Fatalf("request is not initiated") + } + + close(requester.quitC) + + select { + case <-requester.requestC: + case <-time.After(200 * time.Millisecond): + t.Fatalf("request is not initiated after failed request") + } +} + +// TestRequestSkipPeer checks if PeerSkip function will skip provided peer +// and not skip unknown one. +func TestRequestSkipPeer(t *testing.T) { + addr := make([]byte, 32) + peers := []enode.ID{ + enode.HexID("3431c3939e1ee2a6345e976a8234f9870152d64879f30bc272a074f6859e75e8"), + enode.HexID("99d8594b52298567d2ca3f4c441a5ba0140ee9245e26460d01102a52773c73b9"), + } + + peersToSkip := new(sync.Map) + peersToSkip.Store(peers[0].String(), time.Now()) + r := NewRequest(addr, false, peersToSkip) + + if !r.SkipPeer(peers[0].String()) { + t.Errorf("peer not skipped") + } + + if r.SkipPeer(peers[1].String()) { + t.Errorf("peer skipped") + } +} + +// TestRequestSkipPeerExpired checks if a peer to skip is not skipped +// after RequestTimeout has passed. +func TestRequestSkipPeerExpired(t *testing.T) { + addr := make([]byte, 32) + peer := enode.HexID("3431c3939e1ee2a6345e976a8234f9870152d64879f30bc272a074f6859e75e8") + + // set RequestTimeout to a low value and reset it after the test + defer func(t time.Duration) { RequestTimeout = t }(RequestTimeout) + RequestTimeout = 250 * time.Millisecond + + peersToSkip := new(sync.Map) + peersToSkip.Store(peer.String(), time.Now()) + r := NewRequest(addr, false, peersToSkip) + + if !r.SkipPeer(peer.String()) { + t.Errorf("peer not skipped") + } + + time.Sleep(500 * time.Millisecond) + + if r.SkipPeer(peer.String()) { + t.Errorf("peer skipped") + } +} + +// TestRequestSkipPeerPermanent checks if a peer to skip is not skipped +// after RequestTimeout is not skipped if it is set for a permanent skipping +// by value to peersToSkip map is not time.Duration. +func TestRequestSkipPeerPermanent(t *testing.T) { + addr := make([]byte, 32) + peer := enode.HexID("3431c3939e1ee2a6345e976a8234f9870152d64879f30bc272a074f6859e75e8") + + // set RequestTimeout to a low value and reset it after the test + defer func(t time.Duration) { RequestTimeout = t }(RequestTimeout) + RequestTimeout = 250 * time.Millisecond + + peersToSkip := new(sync.Map) + peersToSkip.Store(peer.String(), true) + r := NewRequest(addr, false, peersToSkip) + + if !r.SkipPeer(peer.String()) { + t.Errorf("peer not skipped") + } + + time.Sleep(500 * time.Millisecond) + + if !r.SkipPeer(peer.String()) { + t.Errorf("peer not skipped") + } +} + +func TestFetcherMaxHopCount(t *testing.T) { + requester := newMockRequester() + addr := make([]byte, 32) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + fetcher := NewFetcher(ctx, addr, requester.doRequest, true) + + peersToSkip := &sync.Map{} + + go fetcher.run(peersToSkip) + + // if hopCount is already at max no request should be initiated + select { + case <-requester.requestC: + t.Fatalf("cancelled fetcher initiated request") + case <-time.After(200 * time.Millisecond): + } +} diff --git a/swarm/network/forwarding.go b/swarm/network/forwarding.go deleted file mode 100644 index 88a82a678c..0000000000 --- a/swarm/network/forwarding.go +++ /dev/null @@ -1,150 +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 network - -import ( - "fmt" - "math/rand" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/swarm/storage" -) - -const requesterCount = 3 - -/* -forwarder implements the CloudStore interface (use by storage.NetStore) -and serves as the cloud store backend orchestrating storage/retrieval/delivery -via the native bzz protocol -which uses an MSB logarithmic distance-based semi-permanent Kademlia table for -* recursive forwarding style routing for retrieval -* smart syncronisation -*/ - -type forwarder struct { - hive *Hive -} - -func NewForwarder(hive *Hive) *forwarder { - return &forwarder{hive: hive} -} - -// generate a unique id uint64 -func generateId() uint64 { - r := rand.New(rand.NewSource(time.Now().UnixNano())) - return uint64(r.Int63()) -} - -var searchTimeout = 3 * time.Second - -// forwarding logic -// logic propagating retrieve requests to peers given by the kademlia hive -func (self *forwarder) Retrieve(chunk *storage.Chunk) { - peers := self.hive.getPeers(chunk.Key, 0) - log.Trace(fmt.Sprintf("forwarder.Retrieve: %v - received %d peers from KΛÐΞMLIΛ...", chunk.Key.Log(), len(peers))) -OUT: - for _, p := range peers { - log.Trace(fmt.Sprintf("forwarder.Retrieve: sending retrieveRequest %v to peer [%v]", chunk.Key.Log(), p)) - for _, recipients := range chunk.Req.Requesters { - for _, recipient := range recipients { - req := recipient.(*retrieveRequestMsgData) - if req.from.Addr() == p.Addr() { - continue OUT - } - } - } - req := &retrieveRequestMsgData{ - Key: chunk.Key, - Id: generateId(), - } - var err error - if p.swap != nil { - err = p.swap.Add(-1) - } - if err == nil { - p.retrieve(req) - break OUT - } - log.Warn(fmt.Sprintf("forwarder.Retrieve: unable to send retrieveRequest to peer [%v]: %v", chunk.Key.Log(), err)) - } -} - -// requests to specific peers given by the kademlia hive -// except for peers that the store request came from (if any) -// delivery queueing taken care of by syncer -func (self *forwarder) Store(chunk *storage.Chunk) { - var n int - msg := &storeRequestMsgData{ - Key: chunk.Key, - SData: chunk.SData, - } - var source *peer - if chunk.Source != nil { - source = chunk.Source.(*peer) - } - for _, p := range self.hive.getPeers(chunk.Key, 0) { - log.Trace(fmt.Sprintf("forwarder.Store: %v %v", p, chunk)) - - if p.syncer != nil && (source == nil || p.Addr() != source.Addr()) { - n++ - Deliver(p, msg, PropagateReq) - } - } - log.Trace(fmt.Sprintf("forwarder.Store: sent to %v peers (chunk = %v)", n, chunk)) -} - -// once a chunk is found deliver it to its requesters unless timed out -func (self *forwarder) Deliver(chunk *storage.Chunk) { - // iterate over request entries - for id, requesters := range chunk.Req.Requesters { - counter := requesterCount - msg := &storeRequestMsgData{ - Key: chunk.Key, - SData: chunk.SData, - } - var n int - var req *retrieveRequestMsgData - // iterate over requesters with the same id - for id, r := range requesters { - req = r.(*retrieveRequestMsgData) - if req.timeout == nil || req.timeout.After(time.Now()) { - log.Trace(fmt.Sprintf("forwarder.Deliver: %v -> %v", req.Id, req.from)) - msg.Id = uint64(id) - Deliver(req.from, msg, DeliverReq) - n++ - counter-- - if counter <= 0 { - break - } - } - } - log.Trace(fmt.Sprintf("forwarder.Deliver: submit chunk %v (request id %v) for delivery to %v peers", chunk.Key.Log(), id, n)) - } -} - -// initiate delivery of a chunk to a particular peer via syncer#addRequest -// depending on syncer mode and priority settings and sync request type -// this either goes via confirmation roundtrip or queued or pushed directly -func Deliver(p *peer, req interface{}, ty int) { - p.syncer.addRequest(req, ty) -} - -// push chunk over to peer -func Push(p *peer, key storage.Key, priority uint) { - p.syncer.doDelivery(key, priority, p.syncer.quit) -} diff --git a/swarm/network/hive.go b/swarm/network/hive.go index 2504a46100..a0b6b988ab 100644 --- a/swarm/network/hive.go +++ b/swarm/network/hive.go @@ -18,376 +18,227 @@ package network import ( "fmt" - "math/rand" - "path/filepath" + "sync" "time" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/p2p/discover" - "github.com/ethereum/go-ethereum/p2p/netutil" - "github.com/ethereum/go-ethereum/swarm/network/kademlia" - "github.com/ethereum/go-ethereum/swarm/storage" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/swarm/log" + "github.com/ethereum/go-ethereum/swarm/state" ) -// Hive is the logistic manager of the swarm -// it uses a generic kademlia nodetable to find best peer list -// for any target -// this is used by the netstore to search for content in the swarm -// the bzz protocol peersMsgData exchange is relayed to Kademlia -// for db storage and filtering -// connections and disconnections are reported and relayed -// to keep the nodetable uptodate +/* +Hive is the logistic manager of the swarm -type Hive struct { - listenAddr func() string - callInterval uint64 - id discover.NodeID - addr kademlia.Address - kad *kademlia.Kademlia - path string - quit chan bool - toggle chan bool - more chan bool - - // for testing only - swapEnabled bool - syncEnabled bool - blockRead bool - blockWrite bool -} - -const ( - callInterval = 3000000000 - // bucketSize = 3 - // maxProx = 8 - // proxBinSize = 4 -) +When the hive is started, a forever loop is launched that +asks the kademlia nodetable +to suggest peers to bootstrap connectivity +*/ +// HiveParams holds the config options to hive type HiveParams struct { - CallInterval uint64 - KadDbPath string - *kademlia.KadParams + Discovery bool // if want discovery of not + PeersBroadcastSetSize uint8 // how many peers to use when relaying + MaxPeersPerRequest uint8 // max size for peer address batches + KeepAliveInterval time.Duration } -//create default params -func NewDefaultHiveParams() *HiveParams { - kad := kademlia.NewDefaultKadParams() - // kad.BucketSize = bucketSize - // kad.MaxProx = maxProx - // kad.ProxBinSize = proxBinSize - +// NewHiveParams returns hive config with only the +func NewHiveParams() *HiveParams { return &HiveParams{ - CallInterval: callInterval, - KadParams: kad, + Discovery: true, + PeersBroadcastSetSize: 3, + MaxPeersPerRequest: 5, + KeepAliveInterval: 500 * time.Millisecond, } } -//this can only finally be set after all config options (file, cmd line, env vars) -//have been evaluated -func (self *HiveParams) Init(path string) { - self.KadDbPath = filepath.Join(path, "bzz-peers.json") +// Hive manages network connections of the swarm node +type Hive struct { + *HiveParams // settings + *Kademlia // the overlay connectiviy driver + Store state.Store // storage interface to save peers across sessions + addPeer func(*enode.Node) // server callback to connect to a peer + // bookkeeping + lock sync.Mutex + peers map[enode.ID]*BzzPeer + ticker *time.Ticker } -func NewHive(addr common.Hash, params *HiveParams, swapEnabled, syncEnabled bool) *Hive { - kad := kademlia.New(kademlia.Address(addr), params.KadParams) +// NewHive constructs a new hive +// HiveParams: config parameters +// Kademlia: connectivity driver using a network topology +// StateStore: to save peers across sessions +func NewHive(params *HiveParams, kad *Kademlia, store state.Store) *Hive { return &Hive{ - callInterval: params.CallInterval, - kad: kad, - addr: kad.Addr(), - path: params.KadDbPath, - swapEnabled: swapEnabled, - syncEnabled: syncEnabled, + HiveParams: params, + Kademlia: kad, + Store: store, + peers: make(map[enode.ID]*BzzPeer), } } -func (self *Hive) SyncEnabled(on bool) { - self.syncEnabled = on -} - -func (self *Hive) SwapEnabled(on bool) { - self.swapEnabled = on -} - -func (self *Hive) BlockNetworkRead(on bool) { - self.blockRead = on -} - -func (self *Hive) BlockNetworkWrite(on bool) { - self.blockWrite = on -} - -// public accessor to the hive base address -func (self *Hive) Addr() kademlia.Address { - return self.addr -} - -// Start receives network info only at startup -// listedAddr is a function to retrieve listening address to advertise to peers -// connectPeer is a function to connect to a peer based on its NodeID or enode URL -// there are called on the p2p.Server which runs on the node -func (self *Hive) Start(id discover.NodeID, listenAddr func() string, connectPeer func(string) error) (err error) { - self.toggle = make(chan bool) - self.more = make(chan bool) - self.quit = make(chan bool) - self.id = id - self.listenAddr = listenAddr - err = self.kad.Load(self.path, nil) - if err != nil { - log.Warn(fmt.Sprintf("Warning: error reading kaddb '%s' (skipping): %v", self.path, err)) - err = nil +// Start stars the hive, receives p2p.Server only at startup +// server is used to connect to a peer based on its NodeID or enode URL +// these are called on the p2p.Server which runs on the node +func (h *Hive) Start(server *p2p.Server) error { + log.Info("Starting hive", "baseaddr", fmt.Sprintf("%x", h.BaseAddr()[:4])) + // if state store is specified, load peers to prepopulate the overlay address book + if h.Store != nil { + log.Info("Detected an existing store. trying to load peers") + if err := h.loadPeers(); err != nil { + log.Error(fmt.Sprintf("%08x hive encoutered an error trying to load peers", h.BaseAddr()[:4])) + return err + } } + // assigns the p2p.Server#AddPeer function to connect to peers + h.addPeer = server.AddPeer + // ticker to keep the hive alive + h.ticker = time.NewTicker(h.KeepAliveInterval) // this loop is doing bootstrapping and maintains a healthy table - go self.keepAlive() - go func() { - // whenever toggled ask kademlia about most preferred peer - for alive := range self.more { - if !alive { - // receiving false closes the loop while allowing parallel routines - // to attempt to write to more (remove Peer when shutting down) - return - } - node, need, proxLimit := self.kad.Suggest() - - if node != nil && len(node.Url) > 0 { - log.Trace(fmt.Sprintf("call known bee %v", node.Url)) - // enode or any lower level connection address is unnecessary in future - // discovery table is used to look it up. - connectPeer(node.Url) - } - if need { - // a random peer is taken from the table - peers := self.kad.FindClosest(kademlia.RandomAddressAt(self.addr, rand.Intn(self.kad.MaxProx)), 1) - if len(peers) > 0 { - // a random address at prox bin 0 is sent for lookup - randAddr := kademlia.RandomAddressAt(self.addr, proxLimit) - req := &retrieveRequestMsgData{ - Key: storage.Key(randAddr[:]), - } - log.Trace(fmt.Sprintf("call any bee near %v (PO%03d) - messenger bee: %v", randAddr, proxLimit, peers[0])) - peers[0].(*peer).retrieve(req) - } else { - log.Warn(fmt.Sprintf("no peer")) - } - log.Trace(fmt.Sprintf("buzz kept alive")) - } else { - log.Info(fmt.Sprintf("no need for more bees")) - } - select { - case self.toggle <- need: - case <-self.quit: - return - } - log.Debug(fmt.Sprintf("queen's address: %v, population: %d (%d)", self.addr, self.kad.Count(), self.kad.DBCount())) - } - }() - return -} - -// keepAlive is a forever loop -// in its awake state it periodically triggers connection attempts -// by writing to self.more until Kademlia Table is saturated -// wake state is toggled by writing to self.toggle -// it restarts if the table becomes non-full again due to disconnections -func (self *Hive) keepAlive() { - alarm := time.NewTicker(time.Duration(self.callInterval)).C - for { - select { - case <-alarm: - if self.kad.DBCount() > 0 { - select { - case self.more <- true: - log.Debug(fmt.Sprintf("buzz wakeup")) - default: - } - } - case need := <-self.toggle: - if alarm == nil && need { - alarm = time.NewTicker(time.Duration(self.callInterval)).C - } - if alarm != nil && !need { - alarm = nil - - } - case <-self.quit: - return - } - } -} - -func (self *Hive) Stop() error { - // closing toggle channel quits the updateloop - close(self.quit) - return self.kad.Save(self.path, saveSync) -} - -// called at the end of a successful protocol handshake -func (self *Hive) addPeer(p *peer) error { - defer func() { - select { - case self.more <- true: - default: - } - }() - log.Trace(fmt.Sprintf("hi new bee %v", p)) - err := self.kad.On(p, loadSync) - if err != nil { - return err - } - // self lookup (can be encoded as nil/zero key since peers addr known) + no id () - // the most common way of saying hi in bzz is initiation of gossip - // let me know about anyone new from my hood , here is the storageradius - // to send the 6 byte self lookup - // we do not record as request or forward it, just reply with peers - p.retrieve(&retrieveRequestMsgData{}) - log.Trace(fmt.Sprintf("'whatsup wheresdaparty' sent to %v", p)) - + go h.connect() return nil } -// called after peer disconnected -func (self *Hive) removePeer(p *peer) { - log.Debug(fmt.Sprintf("bee %v removed", p)) - self.kad.Off(p, saveSync) - select { - case self.more <- true: - default: - } - if self.kad.Count() == 0 { - log.Debug(fmt.Sprintf("empty, all bees gone")) +// Stop terminates the updateloop and saves the peers +func (h *Hive) Stop() error { + log.Info(fmt.Sprintf("%08x hive stopping, saving peers", h.BaseAddr()[:4])) + h.ticker.Stop() + if h.Store != nil { + if err := h.savePeers(); err != nil { + return fmt.Errorf("could not save peers to persistence store: %v", err) + } + if err := h.Store.Close(); err != nil { + return fmt.Errorf("could not close file handle to persistence store: %v", err) + } } + log.Info(fmt.Sprintf("%08x hive stopped, dropping peers", h.BaseAddr()[:4])) + 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 + }) + + log.Info(fmt.Sprintf("%08x all peers dropped", h.BaseAddr()[:4])) + return nil } -// Retrieve a list of live peers that are closer to target than us -func (self *Hive) getPeers(target storage.Key, max int) (peers []*peer) { - var addr kademlia.Address - copy(addr[:], target[:]) - for _, node := range self.kad.FindClosest(addr, max) { - peers = append(peers, node.(*peer)) - } - return -} +// connect is a forever loop +// at each iteration, ask the overlay driver to suggest the most preferred peer to connect to +// as well as advertises saturation depth if needed +func (h *Hive) connect() { + for range h.ticker.C { -// disconnects all the peers -func (self *Hive) DropAll() { - log.Info(fmt.Sprintf("dropping all bees")) - for _, node := range self.kad.FindClosest(kademlia.Address{}, 0) { - node.Drop() - } -} - -// contructor for kademlia.NodeRecord based on peer address alone -// TODO: should go away and only addr passed to kademlia -func newNodeRecord(addr *peerAddr) *kademlia.NodeRecord { - now := time.Now() - return &kademlia.NodeRecord{ - Addr: addr.Addr, - Url: addr.String(), - Seen: now, - After: now, - } -} - -// called by the protocol when receiving peerset (for target address) -// peersMsgData is converted to a slice of NodeRecords for Kademlia -// this is to store all thats needed -func (self *Hive) HandlePeersMsg(req *peersMsgData, from *peer) { - var nrs []*kademlia.NodeRecord - for _, p := range req.Peers { - if err := netutil.CheckRelayIP(from.remoteAddr.IP, p.IP); err != nil { - log.Trace(fmt.Sprintf("invalid peer IP %v from %v: %v", from.remoteAddr.IP, p.IP, err)) + addr, depth, changed := h.SuggestPeer() + if h.Discovery && changed { + NotifyDepth(uint8(depth), h.Kademlia) + } + if addr == nil { continue } - nrs = append(nrs, newNodeRecord(p)) + + log.Trace(fmt.Sprintf("%08x hive connect() suggested %08x", h.BaseAddr()[:4], addr.Address()[:4])) + under, err := enode.ParseV4(string(addr.Under())) + if err != nil { + log.Warn(fmt.Sprintf("%08x unable to connect to bee %08x: invalid node URL: %v", h.BaseAddr()[:4], addr.Address()[:4], err)) + continue + } + log.Trace(fmt.Sprintf("%08x attempt to connect to bee %08x", h.BaseAddr()[:4], addr.Address()[:4])) + h.addPeer(under) } - self.kad.Add(nrs) } -// peer wraps the protocol instance to represent a connected peer -// it implements kademlia.Node interface -type peer struct { - *bzz // protocol instance running on peer connection -} +// Run protocol run function +func (h *Hive) Run(p *BzzPeer) error { + h.trackPeer(p) + defer h.untrackPeer(p) -// protocol instance implements kademlia.Node interface (embedded peer) -func (self *peer) Addr() kademlia.Address { - return self.remoteAddr.Addr -} - -func (self *peer) Url() string { - return self.remoteAddr.String() -} - -// TODO take into account traffic -func (self *peer) LastActive() time.Time { - return self.lastActive -} - -// reads the serialised form of sync state persisted as the 'Meta' attribute -// and sets the decoded syncState on the online node -func loadSync(record *kademlia.NodeRecord, node kademlia.Node) error { - p, ok := node.(*peer) - if !ok { - return fmt.Errorf("invalid type") + dp := NewPeer(p, h.Kademlia) + depth, changed := h.On(dp) + // if we want discovery, advertise change of depth + if h.Discovery { + if changed { + // if depth changed, send to all peers + NotifyDepth(depth, h.Kademlia) + } else { + // otherwise just send depth to new peer + dp.NotifyDepth(depth) + } + NotifyPeer(p.BzzAddr, h.Kademlia) } - if record.Meta == nil { - log.Debug(fmt.Sprintf("no sync state for node record %v setting default", record)) - p.syncState = &syncState{DbSyncState: &storage.DbSyncState{}} + defer h.Off(dp) + return dp.Run(dp.HandleMsg) +} + +func (h *Hive) trackPeer(p *BzzPeer) { + h.lock.Lock() + h.peers[p.ID()] = p + h.lock.Unlock() +} + +func (h *Hive) untrackPeer(p *BzzPeer) { + h.lock.Lock() + delete(h.peers, p.ID()) + h.lock.Unlock() +} + +// NodeInfo function is used by the p2p.server RPC interface to display +// protocol specific node information +func (h *Hive) NodeInfo() interface{} { + return h.String() +} + +// PeerInfo function is used by the p2p.server RPC interface to display +// protocol specific information any connected peer referred to by their NodeID +func (h *Hive) PeerInfo(id enode.ID) interface{} { + h.lock.Lock() + p := h.peers[id] + h.lock.Unlock() + + if p == nil { return nil } - state, err := decodeSync(record.Meta) + addr := NewAddr(p.Node()) + return struct { + OAddr hexutil.Bytes + UAddr hexutil.Bytes + }{ + OAddr: addr.OAddr, + UAddr: addr.UAddr, + } +} + +// loadPeers, savePeer implement persistence callback/ +func (h *Hive) loadPeers() error { + var as []*BzzAddr + err := h.Store.Get("peers", &as) if err != nil { - return fmt.Errorf("error decoding kddb record meta info into a sync state: %v", err) - } - log.Trace(fmt.Sprintf("sync state for node record %v read from Meta: %s", record, string(*(record.Meta)))) - p.syncState = state - return err -} - -// callback when saving a sync state -func saveSync(record *kademlia.NodeRecord, node kademlia.Node) { - if p, ok := node.(*peer); ok { - meta, err := encodeSync(p.syncState) - if err != nil { - log.Warn(fmt.Sprintf("error saving sync state for %v: %v", node, err)) - return + if err == state.ErrNotFound { + log.Info(fmt.Sprintf("hive %08x: no persisted peers found", h.BaseAddr()[:4])) + return nil } - log.Trace(fmt.Sprintf("saved sync state for %v: %s", node, string(*meta))) - record.Meta = meta + return err } + log.Info(fmt.Sprintf("hive %08x: peers loaded", h.BaseAddr()[:4])) + + return h.Register(as...) } -// the immediate response to a retrieve request, -// sends relevant peer data given by the kademlia hive to the requester -// TODO: remember peers sent for duration of the session, only new peers sent -func (self *Hive) peers(req *retrieveRequestMsgData) { - if req != nil { - var addrs []*peerAddr - if req.timeout == nil || time.Now().Before(*(req.timeout)) { - key := req.Key - // self lookup from remote peer - if storage.IsZeroKey(key) { - addr := req.from.Addr() - key = storage.Key(addr[:]) - req.Key = nil - } - // get peer addresses from hive - for _, peer := range self.getPeers(key, int(req.MaxPeers)) { - addrs = append(addrs, peer.remoteAddr) - } - log.Debug(fmt.Sprintf("Hive sending %d peer addresses to %v. req.Id: %v, req.Key: %v", len(addrs), req.from, req.Id, req.Key.Log())) - - peersData := &peersMsgData{ - Peers: addrs, - Key: req.Key, - Id: req.Id, - } - peersData.setTimeout(req.timeout) - req.from.peers(peersData) +// savePeers, savePeer implement persistence callback/ +func (h *Hive) savePeers() error { + var peers []*BzzAddr + h.Kademlia.EachAddr(nil, 256, func(pa *BzzAddr, i int) bool { + if pa == nil { + log.Warn(fmt.Sprintf("empty addr: %v", i)) + return true } + log.Trace("saving peer", "peer", pa) + peers = append(peers, pa) + return true + }) + if err := h.Store.Put("peers", peers); err != nil { + return fmt.Errorf("could not save peers: %v", err) } -} - -func (self *Hive) String() string { - return self.kad.String() + return nil } diff --git a/swarm/network/hive_test.go b/swarm/network/hive_test.go new file mode 100644 index 0000000000..fea4347ead --- /dev/null +++ b/swarm/network/hive_test.go @@ -0,0 +1,155 @@ +// 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 network + +import ( + "io/ioutil" + "os" + "testing" + "time" + + 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) { + // setup + addr := RandomAddr() // tested peers peer address + to := NewKademlia(addr.OAddr, NewKadParams()) + pp := NewHive(params, to, store) // hive + + return newBzzBaseTester(t, n, addr, DiscoverySpec, pp.Run), pp +} + +// 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) + + node := s.Nodes[0] + raddr := NewAddr(node) + pp.Register(raddr) + + // start the hive + err := pp.Start(s.Server) + if err != nil { + t.Fatal(err) + } + defer pp.Stop() + + // 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 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) { + + dir, err := ioutil.TempDir("", "hive_test_store") + if err != nil { + panic(err) + } + defer os.RemoveAll(dir) + + store, err := state.NewDBStore(dir) //start the hive with an empty dbstore + if err != nil { + t.Fatal(err) + } + + params := NewHiveParams() + s, pp := newHiveTester(t, params, 5, store) + + peers := make(map[string]bool) + for _, node := range s.Nodes { + raddr := NewAddr(node) + pp.Register(raddr) + peers[raddr.String()] = true + } + + // start and stop the hive + // the known peers should be saved upon stopping + err = pp.Start(s.Server) + if err != nil { + t.Fatal(err) + } + pp.Stop() + store.Close() + + // start the hive with an empty dbstore + persistedStore, err := state.NewDBStore(dir) + if err != nil { + t.Fatal(err) + } + + s1, pp := newHiveTester(t, params, 0, persistedStore) + + // 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) 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.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/swarm/network/kademlia.go b/swarm/network/kademlia.go new file mode 100644 index 0000000000..304f9cd778 --- /dev/null +++ b/swarm/network/kademlia.go @@ -0,0 +1,919 @@ +// Copyright 2017 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 network + +import ( + "bytes" + "fmt" + "math/rand" + "strings" + "sync" + "time" + + "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" +) + +/* + +Taking the proximity order relative to a fix point x classifies the points in +the space (n byte long byte sequences) into bins. Items in each are at +most half as distant from x as items in the previous bin. Given a sample of +uniformly distributed items (a hash function over arbitrary sequence) the +proximity scale maps onto series of subsets with cardinalities on a negative +exponential scale. + +It also has the property that any two item belonging to the same bin are at +most half as distant from each other as they are from x. + +If we think of random sample of items in the bins as connections in a network of +interconnected nodes then relative proximity can serve as the basis for local +decisions for graph traversal where the task is to find a route between two +points. Since in every hop, the finite distance halves, there is +a guaranteed constant maximum limit on the number of hops needed to reach one +node from the other. +*/ + +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 + 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 `json:"-"` +} + +// NewKadParams returns a params struct with default values +func NewKadParams() *KadParams { + return &KadParams{ + MaxProxDisplay: 16, + NeighbourhoodSize: 2, + MinBinSize: 2, + MaxBinSize: 4, + RetryInterval: 4200000000, // 4.2 sec + MaxRetries: 42, + RetryExponent: 2, + } +} + +// Kademlia is a table of live peers and a db of known peers (node records) +type Kademlia struct { + lock sync.RWMutex + *KadParams // Kademlia configuration parameters + base []byte // immutable baseaddress of the table + addrs *pot.Pot // pots container for known peer addresses + conns *pot.Pot // pots container for live peer connections + depth uint8 // stores the last current depth of saturation + nDepth int // stores the last neighbourhood depth + nDepthC chan int // returned by DepthC function to signal neighbourhood depth change + addrCountC chan int // returned by AddrCountC function to signal peer count change +} + +// NewKademlia creates a Kademlia table for base address addr +// with parameters as in params +// if params is nil, it uses default values +func NewKademlia(addr []byte, params *KadParams) *Kademlia { + if params == nil { + params = NewKadParams() + } + return &Kademlia{ + base: addr, + KadParams: params, + addrs: pot.NewPot(nil, 0), + conns: pot.NewPot(nil, 0), + } +} + +// entry represents a Kademlia table entry (an extension of BzzAddr) +type entry struct { + *BzzAddr + conn *Peer + seenAt time.Time + retries int +} + +// newEntry creates a kademlia peer from a *Peer +func newEntry(p *BzzAddr) *entry { + return &entry{ + BzzAddr: p, + seenAt: time.Now(), + } +} + +// Label is a short tag for the entry for debug +func Label(e *entry) string { + return fmt.Sprintf("%s (%d)", e.Hex()[:4], e.retries) +} + +// Hex is the hexadecimal serialisation of the entry address +func (e *entry) Hex() string { + return fmt.Sprintf("%x", e.Address()) +} + +// Register enters each address as kademlia peer record into the +// database of known peer addresses +func (k *Kademlia) Register(peers ...*BzzAddr) error { + k.lock.Lock() + 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 { + // if not found + if v == nil { + log.Trace("registering new peer", "addr", p) + // insert new offline peer into conns + return newEntry(p) + } + + 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 { + known++ + } + size++ + } + // send new address count value only if there are new addresses + if k.addrCountC != nil && size-known > 0 { + k.addrCountC <- k.addrs.Size() + } + + k.sendNeighbourhoodDepthChange() + return nil +} + +// 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() + 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) + } + lastPO = po + 1 + // past radius, depth is surely passed + if po >= radius { + pastDepth = true + } + // 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 + }) + // 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) + } + // all PO bins are saturated, ie., minsize >= k.MinBinSize, no peer suggested + if len(saturation) == 0 { + return nil, 0, 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 + } + 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 + } + } + // 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 + }) + } + + if uint8(saturationDepth) < k.depth { + k.depth = uint8(saturationDepth) + return suggestedPeer, saturationDepth, true + } + return suggestedPeer, 0, false +} + +// On inserts the peer as a kademlia peer into the live peers +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 { + // if not found live + if v == nil { + ins = true + // insert new online peer into conns + return p + } + // found among live peers, do nothing + return v + }) + if ins && !p.BzzPeer.LightNode { + 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 { + return a + }) + // send new address count value only if the peer is inserted + if k.addrCountC != nil { + k.addrCountC <- k.addrs.Size() + } + } + log.Trace(k.string()) + // calculate if depth of saturation changed + depth := uint8(k.saturation()) + var changed bool + if depth != k.depth { + changed = true + k.depth = depth + } + k.sendNeighbourhoodDepthChange() + return k.depth, changed +} + +// NeighbourhoodDepthC returns the channel that sends a new kademlia +// 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() + if k.nDepthC == nil { + k.nDepthC = make(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() { + // nDepthC is initialized when NeighbourhoodDepthC is called and returned by it. + // 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 := depthForPot(k.conns, k.NeighbourhoodSize, k.base) + if nDepth != k.nDepth { + k.nDepth = nDepth + k.nDepthC <- nDepth + } + } +} + +// AddrCountC returns the channel that sends a new +// address count value on each change. +// 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 { + // v cannot be nil, must check otherwise we overwrite entry + if v == nil { + panic(fmt.Sprintf("connected peer not found %v", p)) + } + del = true + return newEntry(p.BzzAddr) + }) + } else { + del = true + } + + if del { + k.conns, _, _, _ = pot.Swap(k.conns, p, Pof, func(_ pot.Val) pot.Val { + // v cannot be nil, but no need to check + return nil + }) + // send new address count value only if the peer is deleted + if k.addrCountC != nil { + k.addrCountC <- k.addrs.Size() + } + k.sendNeighbourhoodDepthChange() + } +} + +func (k *Kademlia) ListKnown() []*BzzAddr { + res := []*BzzAddr{} + + 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) { + 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) { + if len(base) == 0 { + base = k.base + } + k.conns.EachNeighbour(base, Pof, func(val pot.Val, po int) bool { + if po > o { + return true + } + return f(val.(*Peer), po) + }) +} + +// EachAddr called with (base, po, f) is an iterator applying f to each known peer +// 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) { + 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) { + if len(base) == 0 { + base = k.base + } + k.addrs.EachNeighbour(base, Pof, func(val pot.Val, po int) bool { + if po > o { + return true + } + return f(val.(*entry).BzzAddr, po) + }) +} + +// 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 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++ + + // 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 + } + 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 +} + +// callable decides if an address entry represents a callable peer +func (k *Kademlia) callable(e *entry) bool { + // not callable if peer is live or exceeded maxRetries + if e.conn != nil || e.retries > k.MaxRetries { + return false + } + // calculate the allowed number of retries based on time lapsed since last seen + timeAgo := int64(time.Since(e.seenAt)) + div := int64(k.RetryExponent) + div += (150000 - rand.Int63n(300000)) * div / 1000000 + var retries int + for delta := timeAgo; delta > k.RetryInterval; delta /= div { + retries++ + } + // this is never called concurrently, so safe to increment + // peer can be retried again + if retries < e.retries { + log.Trace(fmt.Sprintf("%08x: %v long time since last try (at %v) needed before retry %v, wait only warrants %v", k.BaseAddr()[:4], e, timeAgo, e.retries, retries)) + return false + } + // function to sanction or prevent suggesting a peer + if k.Reachable != nil && !k.Reachable(e.BzzAddr) { + log.Trace(fmt.Sprintf("%08x: peer %v is temporarily not callable", k.BaseAddr()[:4], e)) + return false + } + e.retries++ + log.Trace(fmt.Sprintf("%08x: peer %v is callable", k.BaseAddr()[:4], e)) + + return true +} + +// BaseAddr return the kademlia base address +func (k *Kademlia) BaseAddr() []byte { + return k.base +} + +// String returns kademlia table + kaddb table displayed with ascii +func (k *Kademlia) String() string { + k.lock.RLock() + defer k.lock.RUnlock() + return k.string() +} + +// string returns kademlia table + kaddb table displayed with ascii +// caller must hold the lock +func (k *Kademlia) string() string { + wsrow := " " + 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), 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 := 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) 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) bool { + e := val.(*Peer) + row = append(row, fmt.Sprintf("%x", e.Address()[:2])) + rowlen++ + return rowlen < 4 + }) + r := strings.Join(row, " ") + r = r + wsrow + liverows[po] = r[:31] + return true + }) + + 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 + } + if size < 0 { + panic("wtf") + } + row := []string{fmt.Sprintf("%2d", size)} + // we are displaying live peers too + f(func(val pot.Val) bool { + e := val.(*entry) + row = append(row, Label(e)) + rowlen++ + return rowlen < 4 + }) + peersrows[po] = strings.Join(row, " ") + return true + }) + + for i := 0; i < k.MaxProxDisplay; i++ { + if i == depth { + rows = append(rows, fmt.Sprintf("============ DEPTH: %d ==========================================", i)) + } + left := liverows[i] + right := peersrows[i] + if len(left) == 0 { + left = " 0 " + } + if len(right) == 0 { + right = " 0" + } + rows = append(rows, fmt.Sprintf("%03d %v | %v", i, left, right)) + } + rows = append(rows, "=========================================================================") + return "\n" + strings.Join(rows, "\n") +} + +// PeerPot keeps info about expected nearest neighbours +// used for testing only +// TODO move to separate testing tools file +type PeerPot struct { + 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 +// 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) + } + ppmap := make(map[string]*PeerPot) + + // generate an allknowing source of truth for connections + // for every kademlia passed + for i, a := range addrs { + + // actual kademlia depth + depth := depthForPot(np, neighbourhoodSize, a) + + // all nn-peers + var nns [][]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 + } + // 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]++ + } + return true + }) + + log.Trace(fmt.Sprintf("%x PeerPotMap NNS: %s, peersPerBin", addrs[i][:4], LogAddrs(nns))) + ppmap[common.Bytes2Hex(a)] = &PeerPot{ + NNSet: nns, + PeersPerBin: peersPerBin, + } + } + return ppmap +} + +// 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 + 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++ + if po >= radius { + return false + } + return prev == po && size >= k.MinBinSize + }) + if prev < 0 { + return 0 + } + return prev +} + +// 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 + } + unsaturatedBins := make([]int, 0) + k.conns.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val) bool) bool) bool { + + if po >= depth { + return false + } + 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 + }) + + // 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 addrs { + pk := common.Bytes2Hex(p) + if pm[pk] { + gots++ + } else { + 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) + } + } + return gots == len(peers), gots, culprits +} + +// Health state of the Kademlia +// used for testing only +type Health struct { + 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 +} + +// 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) GetHealthInfo(pp *PeerPot) *Health { + k.lock.RLock() + defer k.lock.RUnlock() + 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(), + } +} + +// 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/swarm/network/kademlia/address.go b/swarm/network/kademlia/address.go deleted file mode 100644 index 4c38a846f9..0000000000 --- a/swarm/network/kademlia/address.go +++ /dev/null @@ -1,173 +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 kademlia - -import ( - "fmt" - "math/rand" - "strings" - - "github.com/ethereum/go-ethereum/common" -) - -type Address common.Hash - -func (a Address) String() string { - return fmt.Sprintf("%x", a[:]) -} - -func (a *Address) MarshalJSON() (out []byte, err error) { - return []byte(`"` + a.String() + `"`), nil -} - -func (a *Address) UnmarshalJSON(value []byte) error { - *a = Address(common.HexToHash(string(value[1 : len(value)-1]))) - return nil -} - -// the string form of the binary representation of an address (only first 8 bits) -func (a Address) Bin() string { - var bs []string - for _, b := range a[:] { - bs = append(bs, fmt.Sprintf("%08b", b)) - } - return strings.Join(bs, "") -} - -/* -Proximity(x, y) 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 Address) (ret int) { - for i := 0; i < len(one); i++ { - oxo := one[i] ^ other[i] - for j := 0; j < 8; j++ { - if (oxo>>uint8(7-j))&0x01 != 0 { - return i*8 + j - } - } - } - return len(one) * 8 -} - -// Address.ProxCmp compares the distances a->target and b->target. -// Returns -1 if a is closer to target, 1 if b is closer to target -// and 0 if they are equal. -func (target Address) ProxCmp(a, b Address) int { - for i := range target { - da := a[i] ^ target[i] - db := b[i] ^ target[i] - if da > db { - return 1 - } else if da < db { - return -1 - } - } - return 0 -} - -// randomAddressAt(address, prox) generates a random address -// at proximity order prox relative to address -// if prox is negative a random address is generated -func RandomAddressAt(self Address, prox int) (addr Address) { - addr = self - var pos int - if prox >= 0 { - pos = prox / 8 - trans := prox % 8 - transbytea := byte(0) - for j := 0; j <= trans; j++ { - transbytea |= 1 << uint8(7-j) - } - flipbyte := byte(1 << uint8(7-trans)) - transbyteb := transbytea ^ byte(255) - randbyte := byte(rand.Intn(255)) - addr[pos] = ((addr[pos] & transbytea) ^ flipbyte) | randbyte&transbyteb - } - for i := pos + 1; i < len(addr); i++ { - addr[i] = byte(rand.Intn(255)) - } - - return -} - -// KeyRange(a0, a1, proxLimit) returns the address inclusive address -// range that contain addresses closer to one than other -func KeyRange(one, other Address, proxLimit int) (start, stop Address) { - prox := proximity(one, other) - if prox >= proxLimit { - prox = proxLimit - } - start = CommonBitsAddrByte(one, other, byte(0x00), prox) - stop = CommonBitsAddrByte(one, other, byte(0xff), prox) - return -} - -func CommonBitsAddrF(self, other Address, f func() byte, p int) (addr Address) { - prox := proximity(self, other) - var pos int - if p <= prox { - prox = p - } - pos = prox / 8 - addr = self - trans := byte(prox % 8) - var transbytea byte - if p > prox { - transbytea = byte(0x7f) - } else { - transbytea = byte(0xff) - } - transbytea >>= trans - transbyteb := transbytea ^ byte(0xff) - addrpos := addr[pos] - addrpos &= transbyteb - if p > prox { - addrpos ^= byte(0x80 >> trans) - } - addrpos |= transbytea & f() - addr[pos] = addrpos - for i := pos + 1; i < len(addr); i++ { - addr[i] = f() - } - - return -} - -func CommonBitsAddr(self, other Address, prox int) (addr Address) { - return CommonBitsAddrF(self, other, func() byte { return byte(rand.Intn(255)) }, prox) -} - -func CommonBitsAddrByte(self, other Address, b byte, prox int) (addr Address) { - return CommonBitsAddrF(self, other, func() byte { return b }, prox) -} - -// randomAddressAt() generates a random address -func RandomAddress() Address { - return RandomAddressAt(Address{}, -1) -} diff --git a/swarm/network/kademlia/address_test.go b/swarm/network/kademlia/address_test.go deleted file mode 100644 index c062c8eafb..0000000000 --- a/swarm/network/kademlia/address_test.go +++ /dev/null @@ -1,96 +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 kademlia - -import ( - "math/rand" - "reflect" - "testing" - - "github.com/ethereum/go-ethereum/common" -) - -func (Address) Generate(rand *rand.Rand, size int) reflect.Value { - var id Address - for i := 0; i < len(id); i++ { - id[i] = byte(uint8(rand.Intn(255))) - } - return reflect.ValueOf(id) -} - -func TestCommonBitsAddrF(t *testing.T) { - a := Address(common.HexToHash("0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")) - b := Address(common.HexToHash("0x8123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")) - c := Address(common.HexToHash("0x4123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")) - d := Address(common.HexToHash("0x0023456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")) - e := Address(common.HexToHash("0x01A3456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")) - ab := CommonBitsAddrF(a, b, func() byte { return byte(0x00) }, 10) - expab := Address(common.HexToHash("0x8000000000000000000000000000000000000000000000000000000000000000")) - - if ab != expab { - t.Fatalf("%v != %v", ab, expab) - } - ac := CommonBitsAddrF(a, c, func() byte { return byte(0x00) }, 10) - expac := Address(common.HexToHash("0x4000000000000000000000000000000000000000000000000000000000000000")) - - if ac != expac { - t.Fatalf("%v != %v", ac, expac) - } - ad := CommonBitsAddrF(a, d, func() byte { return byte(0x00) }, 10) - expad := Address(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000")) - - if ad != expad { - t.Fatalf("%v != %v", ad, expad) - } - ae := CommonBitsAddrF(a, e, func() byte { return byte(0x00) }, 10) - expae := Address(common.HexToHash("0x0180000000000000000000000000000000000000000000000000000000000000")) - - if ae != expae { - t.Fatalf("%v != %v", ae, expae) - } - acf := CommonBitsAddrF(a, c, func() byte { return byte(0xff) }, 10) - expacf := Address(common.HexToHash("0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) - - if acf != expacf { - t.Fatalf("%v != %v", acf, expacf) - } - aeo := CommonBitsAddrF(a, e, func() byte { return byte(0x00) }, 2) - expaeo := Address(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000")) - - if aeo != expaeo { - t.Fatalf("%v != %v", aeo, expaeo) - } - aep := CommonBitsAddrF(a, e, func() byte { return byte(0xff) }, 2) - expaep := Address(common.HexToHash("0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) - - if aep != expaep { - t.Fatalf("%v != %v", aep, expaep) - } - -} - -func TestRandomAddressAt(t *testing.T) { - var a Address - for i := 0; i < 100; i++ { - a = RandomAddress() - prox := rand.Intn(255) - b := RandomAddressAt(a, prox) - if proximity(a, b) != prox { - t.Fatalf("incorrect address prox(%v, %v) == %v (expected %v)", a, b, proximity(a, b), prox) - } - } -} diff --git a/swarm/network/kademlia/kaddb.go b/swarm/network/kademlia/kaddb.go deleted file mode 100644 index b37ced5ba0..0000000000 --- a/swarm/network/kademlia/kaddb.go +++ /dev/null @@ -1,350 +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 kademlia - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "os" - "sync" - "time" - - "github.com/ethereum/go-ethereum/log" -) - -type NodeData interface { - json.Marshaler - json.Unmarshaler -} - -// allow inactive peers under -type NodeRecord struct { - Addr Address // address of node - Url string // Url, used to connect to node - After time.Time // next call after time - Seen time.Time // last connected at time - Meta *json.RawMessage // arbitrary metadata saved for a peer - - node Node -} - -func (self *NodeRecord) setSeen() { - t := time.Now() - self.Seen = t - self.After = t -} - -func (self *NodeRecord) String() string { - return fmt.Sprintf("<%v>", self.Addr) -} - -// persisted node record database () -type KadDb struct { - Address Address - Nodes [][]*NodeRecord - index map[Address]*NodeRecord - cursors []int - lock sync.RWMutex - purgeInterval time.Duration - initialRetryInterval time.Duration - connRetryExp int -} - -func newKadDb(addr Address, params *KadParams) *KadDb { - return &KadDb{ - Address: addr, - Nodes: make([][]*NodeRecord, params.MaxProx+1), // overwritten by load - cursors: make([]int, params.MaxProx+1), - index: make(map[Address]*NodeRecord), - purgeInterval: params.PurgeInterval, - initialRetryInterval: params.InitialRetryInterval, - connRetryExp: params.ConnRetryExp, - } -} - -func (self *KadDb) findOrCreate(index int, a Address, url string) *NodeRecord { - defer self.lock.Unlock() - self.lock.Lock() - - record, found := self.index[a] - if !found { - record = &NodeRecord{ - Addr: a, - Url: url, - } - log.Info(fmt.Sprintf("add new record %v to kaddb", record)) - // insert in kaddb - self.index[a] = record - self.Nodes[index] = append(self.Nodes[index], record) - } else { - log.Info(fmt.Sprintf("found record %v in kaddb", record)) - } - // update last seen time - record.setSeen() - // update with url in case IP/port changes - record.Url = url - return record -} - -// add adds node records to kaddb (persisted node record db) -func (self *KadDb) add(nrs []*NodeRecord, proximityBin func(Address) int) { - defer self.lock.Unlock() - self.lock.Lock() - var n int - var nodes []*NodeRecord - for _, node := range nrs { - _, found := self.index[node.Addr] - if !found && node.Addr != self.Address { - node.setSeen() - self.index[node.Addr] = node - index := proximityBin(node.Addr) - dbcursor := self.cursors[index] - nodes = self.Nodes[index] - // this is inefficient for allocation, need to just append then shift - newnodes := make([]*NodeRecord, len(nodes)+1) - copy(newnodes[:], nodes[:dbcursor]) - newnodes[dbcursor] = node - copy(newnodes[dbcursor+1:], nodes[dbcursor:]) - log.Trace(fmt.Sprintf("new nodes: %v, nodes: %v", newnodes, nodes)) - self.Nodes[index] = newnodes - n++ - } - } - if n > 0 { - log.Debug(fmt.Sprintf("%d/%d node records (new/known)", n, len(nrs))) - } -} - -/* -next return one node record with the highest priority for desired -connection. -This is used to pick candidates for live nodes that are most wanted for -a higly connected low centrality network structure for Swarm which best suits -for a Kademlia-style routing. - -* Starting as naive node with empty db, this implements Kademlia bootstrapping -* As a mature node, it fills short lines. All on demand. - -The candidate is chosen using the following strategy: -We check for missing online nodes in the buckets for 1 upto Max BucketSize rounds. -On each round we proceed from the low to high proximity order buckets. -If the number of active nodes (=connected peers) is < rounds, then start looking -for a known candidate. To determine if there is a candidate to recommend the -kaddb node record database row corresponding to the bucket is checked. - -If the row cursor is on position i, the ith element in the row is chosen. -If the record is scheduled not to be retried before NOW, the next element is taken. -If the record is scheduled to be retried, it is set as checked, scheduled for -checking and is returned. The time of the next check is in X (duration) such that -X = ConnRetryExp * delta where delta is the time past since the last check and -ConnRetryExp is constant obsoletion factor. (Note that when node records are added -from peer messages, they are marked as checked and placed at the cursor, ie. -given priority over older entries). Entries which were checked more than -purgeInterval ago are deleted from the kaddb row. If no candidate is found after -a full round of checking the next bucket up is considered. If no candidate is -found when we reach the maximum-proximity bucket, the next round starts. - -node record a is more favoured to b a > b iff a is a passive node (record of -offline past peer) -|proxBin(a)| < |proxBin(b)| -|| (proxBin(a) < proxBin(b) && |proxBin(a)| == |proxBin(b)|) -|| (proxBin(a) == proxBin(b) && lastChecked(a) < lastChecked(b)) - - -The second argument returned names the first missing slot found -*/ -func (self *KadDb) findBest(maxBinSize int, binSize func(int) int) (node *NodeRecord, need bool, proxLimit int) { - // return nil, proxLimit indicates that all buckets are filled - defer self.lock.Unlock() - self.lock.Lock() - - var interval time.Duration - var found bool - var purge []bool - var delta time.Duration - var cursor int - var count int - var after time.Time - - // iterate over columns maximum bucketsize times - for rounds := 1; rounds <= maxBinSize; rounds++ { - ROUND: - // iterate over rows from PO 0 upto MaxProx - for po, dbrow := range self.Nodes { - // if row has rounds connected peers, then take the next - if binSize(po) >= rounds { - continue ROUND - } - if !need { - // set proxlimit to the PO where the first missing slot is found - proxLimit = po - need = true - } - purge = make([]bool, len(dbrow)) - - // there is a missing slot - finding a node to connect to - // select a node record from the relavant kaddb row (of identical prox order) - ROW: - for cursor = self.cursors[po]; !found && count < len(dbrow); cursor = (cursor + 1) % len(dbrow) { - count++ - node = dbrow[cursor] - - // skip already connected nodes - if node.node != nil { - log.Debug(fmt.Sprintf("kaddb record %v (PO%03d:%d/%d) already connected", node.Addr, po, cursor, len(dbrow))) - continue ROW - } - - // if node is scheduled to connect - if node.After.After(time.Now()) { - log.Debug(fmt.Sprintf("kaddb record %v (PO%03d:%d) skipped. seen at %v (%v ago), scheduled at %v", node.Addr, po, cursor, node.Seen, delta, node.After)) - continue ROW - } - - delta = time.Since(node.Seen) - if delta < self.initialRetryInterval { - delta = self.initialRetryInterval - } - if delta > self.purgeInterval { - // remove node - purge[cursor] = true - log.Debug(fmt.Sprintf("kaddb record %v (PO%03d:%d) unreachable since %v. Removed", node.Addr, po, cursor, node.Seen)) - continue ROW - } - - log.Debug(fmt.Sprintf("kaddb record %v (PO%03d:%d) ready to be tried. seen at %v (%v ago), scheduled at %v", node.Addr, po, cursor, node.Seen, delta, node.After)) - - // scheduling next check - interval = delta * time.Duration(self.connRetryExp) - after = time.Now().Add(interval) - - log.Debug(fmt.Sprintf("kaddb record %v (PO%03d:%d) selected as candidate connection %v. seen at %v (%v ago), selectable since %v, retry after %v (in %v)", node.Addr, po, cursor, rounds, node.Seen, delta, node.After, after, interval)) - node.After = after - found = true - } // ROW - self.cursors[po] = cursor - self.delete(po, purge) - if found { - return node, need, proxLimit - } - } // ROUND - } // ROUNDS - - return nil, need, proxLimit -} - -// deletes the noderecords of a kaddb row corresponding to the indexes -// caller must hold the dblock -// the call is unsafe, no index checks -func (self *KadDb) delete(row int, purge []bool) { - var nodes []*NodeRecord - dbrow := self.Nodes[row] - for i, del := range purge { - if i == self.cursors[row] { - //reset cursor - self.cursors[row] = len(nodes) - } - // delete the entry to be purged - if del { - delete(self.index, dbrow[i].Addr) - continue - } - // otherwise append to new list - nodes = append(nodes, dbrow[i]) - } - self.Nodes[row] = nodes -} - -// save persists kaddb on disk (written to file on path in json format. -func (self *KadDb) save(path string, cb func(*NodeRecord, Node)) error { - defer self.lock.Unlock() - self.lock.Lock() - - var n int - - for _, b := range self.Nodes { - for _, node := range b { - n++ - node.After = time.Now() - node.Seen = time.Now() - if cb != nil { - cb(node, node.node) - } - } - } - - data, err := json.MarshalIndent(self, "", " ") - if err != nil { - return err - } - err = ioutil.WriteFile(path, data, os.ModePerm) - if err != nil { - log.Warn(fmt.Sprintf("unable to save kaddb with %v nodes to %v: %v", n, path, err)) - } else { - log.Info(fmt.Sprintf("saved kaddb with %v nodes to %v", n, path)) - } - return err -} - -// Load(path) loads the node record database (kaddb) from file on path. -func (self *KadDb) load(path string, cb func(*NodeRecord, Node) error) (err error) { - defer self.lock.Unlock() - self.lock.Lock() - - var data []byte - data, err = ioutil.ReadFile(path) - if err != nil { - return - } - - err = json.Unmarshal(data, self) - if err != nil { - return - } - var n int - var purge []bool - for po, b := range self.Nodes { - purge = make([]bool, len(b)) - ROW: - for i, node := range b { - if cb != nil { - err = cb(node, node.node) - if err != nil { - purge[i] = true - continue ROW - } - } - n++ - if node.After.IsZero() { - node.After = time.Now() - } - self.index[node.Addr] = node - } - self.delete(po, purge) - } - log.Info(fmt.Sprintf("loaded kaddb with %v nodes from %v", n, path)) - - return -} - -// accessor for KAD offline db count -func (self *KadDb) count() int { - defer self.lock.Unlock() - self.lock.Lock() - return len(self.index) -} diff --git a/swarm/network/kademlia/kademlia.go b/swarm/network/kademlia/kademlia.go deleted file mode 100644 index 0abc42a19c..0000000000 --- a/swarm/network/kademlia/kademlia.go +++ /dev/null @@ -1,428 +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 kademlia - -import ( - "fmt" - "sort" - "strings" - "sync" - "time" - - "github.com/ethereum/go-ethereum/log" -) - -const ( - bucketSize = 4 - proxBinSize = 2 - maxProx = 8 - connRetryExp = 2 - maxPeers = 100 -) - -var ( - purgeInterval = 42 * time.Hour - initialRetryInterval = 42 * time.Millisecond - maxIdleInterval = 42 * 1000 * time.Millisecond - // maxIdleInterval = 42 * 10 0 * time.Millisecond -) - -type KadParams struct { - // adjustable parameters - MaxProx int - ProxBinSize int - BucketSize int - PurgeInterval time.Duration - InitialRetryInterval time.Duration - MaxIdleInterval time.Duration - ConnRetryExp int -} - -func NewDefaultKadParams() *KadParams { - return &KadParams{ - MaxProx: maxProx, - ProxBinSize: proxBinSize, - BucketSize: bucketSize, - PurgeInterval: purgeInterval, - InitialRetryInterval: initialRetryInterval, - MaxIdleInterval: maxIdleInterval, - ConnRetryExp: connRetryExp, - } -} - -// Kademlia is a table of active nodes -type Kademlia struct { - addr Address // immutable baseaddress of the table - *KadParams // Kademlia configuration parameters - proxLimit int // state, the PO of the first row of the most proximate bin - proxSize int // state, the number of peers in the most proximate bin - count int // number of active peers (w live connection) - buckets [][]Node // the actual bins - db *KadDb // kaddb, node record database - lock sync.RWMutex // mutex to access buckets -} - -type Node interface { - Addr() Address - Url() string - LastActive() time.Time - Drop() -} - -// public constructor -// add is the base address of the table -// params is KadParams configuration -func New(addr Address, params *KadParams) *Kademlia { - buckets := make([][]Node, params.MaxProx+1) - return &Kademlia{ - addr: addr, - KadParams: params, - buckets: buckets, - db: newKadDb(addr, params), - } -} - -// accessor for KAD base address -func (self *Kademlia) Addr() Address { - return self.addr -} - -// accessor for KAD active node count -func (self *Kademlia) Count() int { - defer self.lock.Unlock() - self.lock.Lock() - return self.count -} - -// accessor for KAD active node count -func (self *Kademlia) DBCount() int { - return self.db.count() -} - -// On is the entry point called when a new nodes is added -// unsafe in that node is not checked to be already active node (to be called once) -func (self *Kademlia) On(node Node, cb func(*NodeRecord, Node) error) (err error) { - log.Debug(fmt.Sprintf("%v", self)) - defer self.lock.Unlock() - self.lock.Lock() - - index := self.proximityBin(node.Addr()) - record := self.db.findOrCreate(index, node.Addr(), node.Url()) - - if cb != nil { - err = cb(record, node) - log.Trace(fmt.Sprintf("cb(%v, %v) ->%v", record, node, err)) - if err != nil { - return fmt.Errorf("unable to add node %v, callback error: %v", node.Addr(), err) - } - log.Debug(fmt.Sprintf("add node record %v with node %v", record, node)) - } - - // insert in kademlia table of active nodes - bucket := self.buckets[index] - // if bucket is full insertion replaces the worst node - // TODO: give priority to peers with active traffic - if len(bucket) < self.BucketSize { // >= allows us to add peers beyond the bucketsize limitation - self.buckets[index] = append(bucket, node) - log.Debug(fmt.Sprintf("add node %v to table", node)) - self.setProxLimit(index, true) - record.node = node - self.count++ - return nil - } - - // always rotate peers - idle := self.MaxIdleInterval - var pos int - var replaced Node - for i, p := range bucket { - idleInt := time.Since(p.LastActive()) - if idleInt > idle { - idle = idleInt - pos = i - replaced = p - } - } - if replaced == nil { - log.Debug(fmt.Sprintf("all peers wanted, PO%03d bucket full", index)) - return fmt.Errorf("bucket full") - } - log.Debug(fmt.Sprintf("node %v replaced by %v (idle for %v > %v)", replaced, node, idle, self.MaxIdleInterval)) - replaced.Drop() - // actually replace in the row. When off(node) is called, the peer is no longer in the row - bucket[pos] = node - // there is no change in bucket cardinalities so no prox limit adjustment is needed - record.node = node - self.count++ - return nil - -} - -// Off is the called when a node is taken offline (from the protocol main loop exit) -func (self *Kademlia) Off(node Node, cb func(*NodeRecord, Node)) (err error) { - self.lock.Lock() - defer self.lock.Unlock() - - index := self.proximityBin(node.Addr()) - bucket := self.buckets[index] - for i := 0; i < len(bucket); i++ { - if node.Addr() == bucket[i].Addr() { - self.buckets[index] = append(bucket[:i], bucket[(i+1):]...) - self.setProxLimit(index, false) - break - } - } - - record := self.db.index[node.Addr()] - // callback on remove - if cb != nil { - cb(record, record.node) - } - record.node = nil - self.count-- - log.Debug(fmt.Sprintf("remove node %v from table, population now is %v", node, self.count)) - - return -} - -// proxLimit is dynamically adjusted so that -// 1) there is no empty buckets in bin < proxLimit and -// 2) the sum of all items are the minimum possible but higher than ProxBinSize -// adjust Prox (proxLimit and proxSize after an insertion/removal of nodes) -// caller holds the lock -func (self *Kademlia) setProxLimit(r int, on bool) { - // if the change is outside the core (PO lower) - // and the change does not leave a bucket empty then - // no adjustment needed - if r < self.proxLimit && len(self.buckets[r]) > 0 { - return - } - // if on=a node was added, then r must be within prox limit so increment cardinality - if on { - self.proxSize++ - curr := len(self.buckets[self.proxLimit]) - // if now core is big enough without the furthest bucket, then contract - // this can result in more than one bucket change - for self.proxSize >= self.ProxBinSize+curr && curr > 0 { - self.proxSize -= curr - self.proxLimit++ - curr = len(self.buckets[self.proxLimit]) - - log.Trace(fmt.Sprintf("proxbin contraction (size: %v, limit: %v, bin: %v)", self.proxSize, self.proxLimit, r)) - } - return - } - // otherwise - if r >= self.proxLimit { - self.proxSize-- - } - // expand core by lowering prox limit until hit zero or cover the empty bucket or reached target cardinality - for (self.proxSize < self.ProxBinSize || r < self.proxLimit) && - self.proxLimit > 0 { - // - self.proxLimit-- - self.proxSize += len(self.buckets[self.proxLimit]) - log.Trace(fmt.Sprintf("proxbin expansion (size: %v, limit: %v, bin: %v)", self.proxSize, self.proxLimit, r)) - } -} - -/* -returns the list of nodes belonging to the same proximity bin -as the target. The most proximate bin will be the union of the bins between -proxLimit and MaxProx. -*/ -func (self *Kademlia) FindClosest(target Address, max int) []Node { - self.lock.Lock() - defer self.lock.Unlock() - - r := nodesByDistance{ - target: target, - } - - po := self.proximityBin(target) - index := po - step := 1 - log.Trace(fmt.Sprintf("serving %v nodes at %v (PO%02d)", max, index, po)) - - // if max is set to 0, just want a full bucket, dynamic number - min := max - // set limit to max - limit := max - if max == 0 { - min = 1 - limit = maxPeers - } - - var n int - for index >= 0 { - // add entire bucket - for _, p := range self.buckets[index] { - r.push(p, limit) - n++ - } - // terminate if index reached the bottom or enough peers > min - log.Trace(fmt.Sprintf("add %v -> %v (PO%02d, PO%03d)", len(self.buckets[index]), n, index, po)) - if n >= min && (step < 0 || max == 0) { - break - } - // reach top most non-empty PO bucket, turn around - if index == self.MaxProx { - index = po - step = -1 - } - index += step - } - log.Trace(fmt.Sprintf("serve %d (<=%d) nodes for target lookup %v (PO%03d)", n, max, target, po)) - return r.nodes -} - -func (self *Kademlia) Suggest() (*NodeRecord, bool, int) { - defer self.lock.RUnlock() - self.lock.RLock() - return self.db.findBest(self.BucketSize, func(i int) int { return len(self.buckets[i]) }) -} - -// adds node records to kaddb (persisted node record db) -func (self *Kademlia) Add(nrs []*NodeRecord) { - self.db.add(nrs, self.proximityBin) -} - -// nodesByDistance is a list of nodes, ordered by distance to target. -type nodesByDistance struct { - nodes []Node - target Address -} - -func sortedByDistanceTo(target Address, slice []Node) bool { - var last Address - for i, node := range slice { - if i > 0 { - if target.ProxCmp(node.Addr(), last) < 0 { - return false - } - } - last = node.Addr() - } - return true -} - -// push(node, max) adds the given node to the list, keeping the total size -// below max elements. -func (h *nodesByDistance) push(node Node, max int) { - // returns the firt index ix such that func(i) returns true - ix := sort.Search(len(h.nodes), func(i int) bool { - return h.target.ProxCmp(h.nodes[i].Addr(), node.Addr()) >= 0 - }) - - if len(h.nodes) < max { - h.nodes = append(h.nodes, node) - } - if ix < len(h.nodes) { - copy(h.nodes[ix+1:], h.nodes[ix:]) - h.nodes[ix] = node - } -} - -/* -Taking the proximity order relative to a fix point x classifies the points in -the space (n byte long byte sequences) into bins. Items in each are at -most half as distant from x as items in the previous bin. Given a sample of -uniformly distributed items (a hash function over arbitrary sequence) the -proximity scale maps onto series of subsets with cardinalities on a negative -exponential scale. - -It also has the property that any two item belonging to the same bin are at -most half as distant from each other as they are from x. - -If we think of random sample of items in the bins as connections in a network of interconnected nodes than relative proximity can serve as the basis for local -decisions for graph traversal where the task is to find a route between two -points. Since in every hop, the finite distance halves, there is -a guaranteed constant maximum limit on the number of hops needed to reach one -node from the other. -*/ - -func (self *Kademlia) proximityBin(other Address) (ret int) { - ret = proximity(self.addr, other) - if ret > self.MaxProx { - ret = self.MaxProx - } - return -} - -// provides keyrange for chunk db iteration -func (self *Kademlia) KeyRange(other Address) (start, stop Address) { - defer self.lock.RUnlock() - self.lock.RLock() - return KeyRange(self.addr, other, self.proxLimit) -} - -// save persists kaddb on disk (written to file on path in json format. -func (self *Kademlia) Save(path string, cb func(*NodeRecord, Node)) error { - return self.db.save(path, cb) -} - -// Load(path) loads the node record database (kaddb) from file on path. -func (self *Kademlia) Load(path string, cb func(*NodeRecord, Node) error) (err error) { - return self.db.load(path, cb) -} - -// kademlia table + kaddb table displayed with ascii -func (self *Kademlia) String() string { - defer self.lock.RUnlock() - self.lock.RLock() - defer self.db.lock.RUnlock() - self.db.lock.RLock() - - var rows []string - rows = append(rows, "=========================================================================") - rows = append(rows, fmt.Sprintf("%v KΛÐΞMLIΛ hive: queen's address: %v", time.Now().UTC().Format(time.UnixDate), self.addr.String()[:6])) - rows = append(rows, fmt.Sprintf("population: %d (%d), proxLimit: %d, proxSize: %d", self.count, len(self.db.index), self.proxLimit, self.proxSize)) - rows = append(rows, fmt.Sprintf("MaxProx: %d, ProxBinSize: %d, BucketSize: %d", self.MaxProx, self.ProxBinSize, self.BucketSize)) - - for i, bucket := range self.buckets { - - if i == self.proxLimit { - rows = append(rows, fmt.Sprintf("============ PROX LIMIT: %d ==========================================", i)) - } - row := []string{fmt.Sprintf("%03d", i), fmt.Sprintf("%2d", len(bucket))} - var k int - c := self.db.cursors[i] - for ; k < len(bucket); k++ { - p := bucket[(c+k)%len(bucket)] - row = append(row, p.Addr().String()[:6]) - if k == 4 { - break - } - } - for ; k < 4; k++ { - row = append(row, " ") - } - row = append(row, fmt.Sprintf("| %2d %2d", len(self.db.Nodes[i]), self.db.cursors[i])) - - for j, p := range self.db.Nodes[i] { - row = append(row, p.Addr.String()[:6]) - if j == 3 { - break - } - } - rows = append(rows, strings.Join(row, " ")) - if i == self.MaxProx { - } - } - rows = append(rows, "=========================================================================") - return strings.Join(rows, "\n") -} diff --git a/swarm/network/kademlia/kademlia_test.go b/swarm/network/kademlia/kademlia_test.go deleted file mode 100644 index 88858908a4..0000000000 --- a/swarm/network/kademlia/kademlia_test.go +++ /dev/null @@ -1,392 +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 kademlia - -import ( - "fmt" - "math" - "math/rand" - "os" - "path/filepath" - "reflect" - "testing" - "testing/quick" - "time" -) - -var ( - quickrand = rand.New(rand.NewSource(time.Now().Unix())) - quickcfgFindClosest = &quick.Config{MaxCount: 50, Rand: quickrand} - quickcfgBootStrap = &quick.Config{MaxCount: 100, Rand: quickrand} -) - -type testNode struct { - addr Address -} - -func (n *testNode) String() string { - return fmt.Sprintf("%x", n.addr[:]) -} - -func (n *testNode) Addr() Address { - return n.addr -} - -func (n *testNode) Drop() { -} - -func (n *testNode) Url() string { - return "" -} - -func (n *testNode) LastActive() time.Time { - return time.Now() -} - -func TestOn(t *testing.T) { - addr, ok1 := gen(Address{}, quickrand).(Address) - other, ok2 := gen(Address{}, quickrand).(Address) - if !ok1 || !ok2 { - t.Errorf("oops") - } - kad := New(addr, NewDefaultKadParams()) - err := kad.On(&testNode{addr: other}, nil) - _ = err -} - -func TestBootstrap(t *testing.T) { - - test := func(test *bootstrapTest) bool { - // for any node kad.le, Target and N - params := NewDefaultKadParams() - params.MaxProx = test.MaxProx - params.BucketSize = test.BucketSize - params.ProxBinSize = test.BucketSize - kad := New(test.Self, params) - var err error - - for p := 0; p < 9; p++ { - var nrs []*NodeRecord - n := math.Pow(float64(2), float64(7-p)) - for i := 0; i < int(n); i++ { - addr := RandomAddressAt(test.Self, p) - nrs = append(nrs, &NodeRecord{ - Addr: addr, - }) - } - kad.Add(nrs) - } - - node := &testNode{test.Self} - - n := 0 - for n < 100 { - err = kad.On(node, nil) - if err != nil { - t.Fatalf("backend not accepting node: %v", err) - } - - record, need, _ := kad.Suggest() - if !need { - break - } - n++ - if record == nil { - continue - } - node = &testNode{record.Addr} - } - exp := test.BucketSize * (test.MaxProx + 1) - if kad.Count() != exp { - t.Errorf("incorrect number of peers, expected %d, got %d\n%v", exp, kad.Count(), kad) - return false - } - return true - } - if err := quick.Check(test, quickcfgBootStrap); err != nil { - t.Error(err) - } - -} - -func TestFindClosest(t *testing.T) { - - test := func(test *FindClosestTest) bool { - // for any node kad.le, Target and N - params := NewDefaultKadParams() - params.MaxProx = 7 - kad := New(test.Self, params) - var err error - for _, node := range test.All { - err = kad.On(node, nil) - if err != nil && err.Error() != "bucket full" { - t.Fatalf("backend not accepting node: %v", err) - } - } - - if len(test.All) == 0 || test.N == 0 { - return true - } - nodes := kad.FindClosest(test.Target, test.N) - - // check that the number of results is min(N, kad.len) - wantN := test.N - if tlen := kad.Count(); tlen < test.N { - wantN = tlen - } - - if len(nodes) != wantN { - t.Errorf("wrong number of nodes: got %d, want %d", len(nodes), wantN) - return false - } - - if hasDuplicates(nodes) { - t.Errorf("result contains duplicates") - return false - } - - if !sortedByDistanceTo(test.Target, nodes) { - t.Errorf("result is not sorted by distance to target") - return false - } - - // check that the result nodes have minimum distance to target. - farthestResult := nodes[len(nodes)-1].Addr() - for i, b := range kad.buckets { - for j, n := range b { - if contains(nodes, n.Addr()) { - continue // don't run the check below for nodes in result - } - if test.Target.ProxCmp(n.Addr(), farthestResult) < 0 { - _ = i * j - t.Errorf("kad.le contains node that is closer to target but it's not in result") - return false - } - } - } - return true - } - if err := quick.Check(test, quickcfgFindClosest); err != nil { - t.Error(err) - } -} - -type proxTest struct { - add bool - index int - addr Address -} - -var ( - addresses []Address -) - -func TestProxAdjust(t *testing.T) { - r := rand.New(rand.NewSource(time.Now().UnixNano())) - self := gen(Address{}, r).(Address) - params := NewDefaultKadParams() - params.MaxProx = 7 - kad := New(self, params) - - var err error - for i := 0; i < 100; i++ { - a := gen(Address{}, r).(Address) - addresses = append(addresses, a) - err = kad.On(&testNode{addr: a}, nil) - if err != nil && err.Error() != "bucket full" { - t.Fatalf("backend not accepting node: %v", err) - } - if !kad.proxCheck(t) { - return - } - } - test := func(test *proxTest) bool { - node := &testNode{test.addr} - if test.add { - kad.On(node, nil) - } else { - kad.Off(node, nil) - } - return kad.proxCheck(t) - } - if err := quick.Check(test, quickcfgFindClosest); err != nil { - t.Error(err) - } -} - -func TestSaveLoad(t *testing.T) { - r := rand.New(rand.NewSource(time.Now().UnixNano())) - addresses := gen([]Address{}, r).([]Address) - self := RandomAddress() - params := NewDefaultKadParams() - params.MaxProx = 7 - kad := New(self, params) - - var err error - - for _, a := range addresses { - err = kad.On(&testNode{addr: a}, nil) - if err != nil && err.Error() != "bucket full" { - t.Fatalf("backend not accepting node: %v", err) - } - } - nodes := kad.FindClosest(self, 100) - - path := filepath.Join(os.TempDir(), "bzz-kad-test-save-load.peers") - err = kad.Save(path, nil) - if err != nil && err.Error() != "bucket full" { - t.Fatalf("unepected error saving kaddb: %v", err) - } - kad = New(self, params) - err = kad.Load(path, nil) - if err != nil && err.Error() != "bucket full" { - t.Fatalf("unepected error loading kaddb: %v", err) - } - for _, b := range kad.db.Nodes { - for _, node := range b { - err = kad.On(&testNode{node.Addr}, nil) - if err != nil && err.Error() != "bucket full" { - t.Fatalf("backend not accepting node: %v", err) - } - } - } - loadednodes := kad.FindClosest(self, 100) - for i, node := range loadednodes { - if nodes[i].Addr() != node.Addr() { - t.Errorf("node mismatch at %d/%d: %v != %v", i, len(nodes), nodes[i].Addr(), node.Addr()) - } - } -} - -func (self *Kademlia) proxCheck(t *testing.T) bool { - var sum int - for i, b := range self.buckets { - l := len(b) - // if we are in the high prox multibucket - if i >= self.proxLimit { - sum += l - } else if l == 0 { - t.Errorf("bucket %d empty, yet proxLimit is %d\n%v", len(b), self.proxLimit, self) - return false - } - } - // check if merged high prox bucket does not exceed size - if sum > 0 { - if sum != self.proxSize { - t.Errorf("proxSize incorrect, expected %v, got %v", sum, self.proxSize) - return false - } - last := len(self.buckets[self.proxLimit]) - if last > 0 && sum >= self.ProxBinSize+last { - t.Errorf("proxLimit %v incorrect, redundant non-empty bucket %d added to proxBin with %v (target %v)\n%v", self.proxLimit, last, sum-last, self.ProxBinSize, self) - return false - } - if self.proxLimit > 0 && sum < self.ProxBinSize { - t.Errorf("proxLimit %v incorrect. proxSize %v is less than target %v, yet there is more peers", self.proxLimit, sum, self.ProxBinSize) - return false - } - } - return true -} - -type bootstrapTest struct { - MaxProx int - BucketSize int - Self Address -} - -func (*bootstrapTest) Generate(rand *rand.Rand, size int) reflect.Value { - t := &bootstrapTest{ - Self: gen(Address{}, rand).(Address), - MaxProx: 5 + rand.Intn(2), - BucketSize: rand.Intn(3) + 1, - } - return reflect.ValueOf(t) -} - -type FindClosestTest struct { - Self Address - Target Address - All []Node - N int -} - -func (c FindClosestTest) String() string { - return fmt.Sprintf("A: %064x\nT: %064x\n(%d)\n", c.Self[:], c.Target[:], c.N) -} - -func (*FindClosestTest) Generate(rand *rand.Rand, size int) reflect.Value { - t := &FindClosestTest{ - Self: gen(Address{}, rand).(Address), - Target: gen(Address{}, rand).(Address), - N: rand.Intn(bucketSize), - } - for _, a := range gen([]Address{}, rand).([]Address) { - t.All = append(t.All, &testNode{addr: a}) - } - return reflect.ValueOf(t) -} - -func (*proxTest) Generate(rand *rand.Rand, size int) reflect.Value { - var add bool - if rand.Intn(1) == 0 { - add = true - } - var t *proxTest - if add { - t = &proxTest{ - addr: gen(Address{}, rand).(Address), - add: add, - } - } else { - t = &proxTest{ - index: rand.Intn(len(addresses)), - add: add, - } - } - return reflect.ValueOf(t) -} - -func hasDuplicates(slice []Node) bool { - seen := make(map[Address]bool) - for _, node := range slice { - if seen[node.Addr()] { - return true - } - seen[node.Addr()] = true - } - return false -} - -func contains(nodes []Node, addr Address) bool { - for _, n := range nodes { - if n.Addr() == addr { - return true - } - } - return false -} - -// gen wraps quick.Value so it's easier to use. -// it generates a random value of the given value's type. -func gen(typ interface{}, rand *rand.Rand) interface{} { - v, ok := quick.Value(reflect.TypeOf(typ), rand) - if !ok { - panic(fmt.Sprintf("couldn't generate random value of type %T", typ)) - } - return v.Interface() -} diff --git a/swarm/network/kademlia_test.go b/swarm/network/kademlia_test.go new file mode 100644 index 0000000000..b4663eee5e --- /dev/null +++ b/swarm/network/kademlia_test.go @@ -0,0 +1,562 @@ +// 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 network + +import ( + "fmt" + "os" + "testing" + "time" + + "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" +) + +func init() { + h := log.LvlFilterHandler(log.LvlWarn, log.StreamHandler(os.Stderr, log.TerminalFormat(true))) + log.Root().SetHandler(h) +} + +func testKadPeerAddr(s string) *BzzAddr { + a := pot.NewAddressFromString(s) + return &BzzAddr{OAddr: a, UAddr: a} +} + +func newTestKademliaParams() *KadParams { + params := NewKadParams() + 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 &testKademlia{ + Kademlia: NewKademlia(base, newTestKademliaParams()), + t: t, + } +} + +func (tk *testKademlia) newTestKadPeer(s string, lightNode bool) *Peer { + return NewPeer(&BzzPeer{BzzAddr: testKadPeerAddr(s), LightNode: lightNode}, tk.Kademlia) +} + +func (tk *testKademlia) On(ons ...string) { + for _, s := range ons { + tk.Kademlia.On(tk.newTestKadPeer(s, false)) + } +} + +func (tk *testKademlia) Off(offs ...string) { + for _, s := range offs { + tk.Kademlia.Off(tk.newTestKadPeer(s, false)) + } +} + +func (tk *testKademlia) Register(regs ...string) { + var as []*BzzAddr + for _, s := range regs { + as = append(as, testKadPeerAddr(s)) + } + err := tk.Kademlia.Register(as...) + if err != nil { + panic(err.Error()) + } +} + +// 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 { + tk.t.Fatalf("incorrect peer address suggested. expected %v, got %v", expAddr, binStr(addr)) + } + if depth != expDepth { + tk.t.Fatalf("incorrect saturation depth suggested. expected %v, got %v", expDepth, depth) + } + if changed != expChanged { + tk.t.Fatalf("expected depth change = %v, got %v", expChanged, changed) + } +} + +func binStr(a *BzzAddr) string { + if a == nil { + return "" + } + return pot.ToBin(a.Address())[:8] +} + +func TestSuggestPeerFindPeers(t *testing.T) { + tk := newTestKademlia(t, "00000000") + tk.On("00100000") + tk.checkSuggestPeer("", 0, false) + + tk.On("00010000") + tk.checkSuggestPeer("", 0, false) + + tk.On("10000000", "10000001") + tk.checkSuggestPeer("", 0, false) + + tk.On("01000000") + tk.Off("10000001") + tk.checkSuggestPeer("10000001", 0, true) + + tk.On("00100001") + tk.Off("01000000") + tk.checkSuggestPeer("01000000", 0, false) + + // second time disconnected peer not callable + // with reasonably set Interval + tk.checkSuggestPeer("", 0, false) + + // on and off again, peer callable again + tk.On("01000000") + tk.Off("01000000") + tk.checkSuggestPeer("01000000", 0, false) + + tk.On("01000000", "10000001") + tk.checkSuggestPeer("", 0, false) + + tk.Register("00010001") + tk.checkSuggestPeer("00010001", 0, false) + + tk.On("00010001") + tk.Off("01000000") + tk.checkSuggestPeer("01000000", 0, false) + + tk.On("01000000") + tk.checkSuggestPeer("", 0, false) + + tk.Register("01000001") + tk.checkSuggestPeer("01000001", 0, false) + + tk.On("01000001") + tk.checkSuggestPeer("", 0, false) + + tk.Register("10000010", "01000010", "00100010") + tk.checkSuggestPeer("", 0, false) + + tk.Register("00010010") + tk.checkSuggestPeer("00010010", 0, false) + + tk.Off("00100001") + tk.checkSuggestPeer("00100010", 2, true) + + tk.Off("01000001") + tk.checkSuggestPeer("01000010", 1, true) + + tk.checkSuggestPeer("01000001", 0, false) + tk.checkSuggestPeer("00100001", 0, false) + tk.checkSuggestPeer("", 0, false) + + 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) { + tk := newTestKademlia(t, "00000000") + // peer added to kademlia + tk.On("01000000") + // peer should be in the address book + if tk.addrs.Size() != 1 { + t.Fatal("known peer addresses should contain 1 entry") + } + // peer should be among live connections + if tk.conns.Size() != 1 { + t.Fatal("live peers should contain 1 entry") + } + // remove peer from kademlia + tk.Off("01000000") + // peer should be in the address book + if tk.addrs.Size() != 1 { + t.Fatal("known peer addresses should contain 1 entry") + } + // peer should not be among live connections + 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) { + tk := newTestKademlia(t, "00000000") + // light node peer added to kademlia + tk.Kademlia.On(tk.newTestKadPeer("01000000", true)) + // peer should not be in the address book + if tk.addrs.Size() != 0 { + t.Fatal("known peer addresses should contain 0 entry") + } + // peer should be among live connections + if tk.conns.Size() != 1 { + t.Fatal("live peers should contain 1 entry") + } + // remove peer from kademlia + tk.Kademlia.Off(tk.newTestKadPeer("01000000", true)) + // peer should not be in the address book + if tk.addrs.Size() != 0 { + t.Fatal("known peer addresses should contain 0 entry") + } + // peer should not be among live connections + if tk.conns.Size() != 0 { + t.Fatal("live peers should contain 0 entry") + } +} + +func TestSuggestPeerRetries(t *testing.T) { + tk := newTestKademlia(t, "00000000") + tk.RetryInterval = int64(300 * time.Millisecond) // cycle + tk.MaxRetries = 50 + tk.RetryExponent = 2 + sleep := func(n int) { + ts := tk.RetryInterval + for i := 1; i < n; i++ { + ts *= int64(tk.RetryExponent) + } + time.Sleep(time.Duration(ts)) + } + + tk.Register("01000000") + tk.On("00000001", "00000010") + tk.checkSuggestPeer("01000000", 0, false) + + tk.checkSuggestPeer("", 0, false) + + sleep(1) + tk.checkSuggestPeer("01000000", 0, false) + + tk.checkSuggestPeer("", 0, false) + + sleep(1) + tk.checkSuggestPeer("01000000", 0, false) + + tk.checkSuggestPeer("", 0, false) + + sleep(2) + tk.checkSuggestPeer("01000000", 0, false) + + tk.checkSuggestPeer("", 0, false) + + sleep(2) + tk.checkSuggestPeer("", 0, false) +} + +func TestKademliaHiveString(t *testing.T) { + 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) + } +} + +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[:])), + }, + } + return NewPeer(bp, kad) +} diff --git a/swarm/network/messages.go b/swarm/network/messages.go deleted file mode 100644 index d920def959..0000000000 --- a/swarm/network/messages.go +++ /dev/null @@ -1,308 +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 network - -import ( - "fmt" - "net" - "time" - - "github.com/ethereum/go-ethereum/contracts/chequebook" - "github.com/ethereum/go-ethereum/p2p/discover" - "github.com/ethereum/go-ethereum/swarm/network/kademlia" - "github.com/ethereum/go-ethereum/swarm/services/swap" - "github.com/ethereum/go-ethereum/swarm/storage" -) - -/* -BZZ protocol Message Types and Message Data Types -*/ - -// bzz protocol message codes -const ( - statusMsg = iota // 0x01 - storeRequestMsg // 0x02 - retrieveRequestMsg // 0x03 - peersMsg // 0x04 - syncRequestMsg // 0x05 - deliveryRequestMsg // 0x06 - unsyncedKeysMsg // 0x07 - paymentMsg // 0x08 -) - -/* - Handshake - -* Version: 8 byte integer version of the protocol -* ID: arbitrary byte sequence client identifier human readable -* Addr: the address advertised by the node, format similar to DEVp2p wire protocol -* Swap: info for the swarm accounting protocol -* NetworkID: 8 byte integer network identifier -* Caps: swarm-specific capabilities, format identical to devp2p -* SyncState: syncronisation state (db iterator key and address space etc) persisted about the peer - -*/ -type statusMsgData struct { - Version uint64 - ID string - Addr *peerAddr - Swap *swap.SwapProfile - NetworkId uint64 -} - -func (self *statusMsgData) String() string { - return fmt.Sprintf("Status: Version: %v, ID: %v, Addr: %v, Swap: %v, NetworkId: %v", self.Version, self.ID, self.Addr, self.Swap, self.NetworkId) -} - -/* - store requests are forwarded to the peers in their kademlia proximity bin - if they are distant - if they are within our storage radius or have any incentive to store it - then attach your nodeID to the metadata - if the storage request is sufficiently close (within our proxLimit, i. e., the - last row of the routing table) -*/ -type storeRequestMsgData struct { - Key storage.Key // hash of datasize | data - SData []byte // the actual chunk Data - // optional - Id uint64 // request ID. if delivery, the ID is retrieve request ID - requestTimeout *time.Time // expiry for forwarding - [not serialised][not currently used] - storageTimeout *time.Time // expiry of content - [not serialised][not currently used] - from *peer // [not serialised] protocol registers the requester -} - -func (self storeRequestMsgData) String() string { - var from string - if self.from == nil { - from = "self" - } else { - from = self.from.Addr().String() - } - end := len(self.SData) - if len(self.SData) > 10 { - end = 10 - } - return fmt.Sprintf("from: %v, Key: %v; ID: %v, requestTimeout: %v, storageTimeout: %v, SData %x", from, self.Key, self.Id, self.requestTimeout, self.storageTimeout, self.SData[:end]) -} - -/* -Retrieve request - -Timeout in milliseconds. Note that zero timeout retrieval requests do not request forwarding, but prompt for a peers message response. therefore they serve also -as messages to retrieve peers. - -MaxSize specifies the maximum size that the peer will accept. This is useful in -particular if we allow storage and delivery of multichunk payload representing -the entire or partial subtree unfolding from the requested root key. -So when only interested in limited part of a stream (infinite trees) or only -testing chunk availability etc etc, we can indicate it by limiting the size here. - -Request ID can be newly generated or kept from the request originator. -If request ID Is missing or zero, the request is handled as a lookup only -prompting a peers response but not launching a search. Lookup requests are meant -to be used to bootstrap kademlia tables. - -In the special case that the key is the zero value as well, the remote peer's -address is assumed (the message is to be handled as a self lookup request). -The response is a PeersMsg with the peers in the kademlia proximity bin -corresponding to the address. -*/ - -type retrieveRequestMsgData struct { - Key storage.Key // target Key address of chunk to be retrieved - Id uint64 // request id, request is a lookup if missing or zero - MaxSize uint64 // maximum size of delivery accepted - MaxPeers uint64 // maximum number of peers returned - Timeout uint64 // the longest time we are expecting a response - timeout *time.Time // [not serialied] - from *peer // -} - -func (self *retrieveRequestMsgData) String() string { - var from string - if self.from == nil { - from = "ourselves" - } else { - from = self.from.Addr().String() - } - var target []byte - if len(self.Key) > 3 { - target = self.Key[:4] - } - return fmt.Sprintf("from: %v, Key: %x; ID: %v, MaxSize: %v, MaxPeers: %d", from, target, self.Id, self.MaxSize, self.MaxPeers) -} - -// lookups are encoded by missing request ID -func (self *retrieveRequestMsgData) isLookup() bool { - return self.Id == 0 -} - -// sets timeout fields -func (self *retrieveRequestMsgData) setTimeout(t *time.Time) { - self.timeout = t - if t != nil { - self.Timeout = uint64(t.UnixNano()) - } else { - self.Timeout = 0 - } -} - -func (self *retrieveRequestMsgData) getTimeout() (t *time.Time) { - if self.Timeout > 0 && self.timeout == nil { - timeout := time.Unix(int64(self.Timeout), 0) - t = &timeout - self.timeout = t - } - return -} - -// peerAddr is sent in StatusMsg as part of the handshake -type peerAddr struct { - IP net.IP - Port uint16 - ID []byte // the 64 byte NodeID (ECDSA Public Key) - Addr kademlia.Address -} - -// peerAddr pretty prints as enode -func (self *peerAddr) String() string { - var nodeid discover.NodeID - copy(nodeid[:], self.ID) - return discover.NewNode(nodeid, self.IP, 0, self.Port).String() -} - -/* -peers Msg is one response to retrieval; it is always encouraged after a retrieval -request to respond with a list of peers in the same kademlia proximity bin. -The encoding of a peer is identical to that in the devp2p base protocol peers -messages: [IP, Port, NodeID] -note that a node's DPA address is not the NodeID but the hash of the NodeID. - -Timeout serves to indicate whether the responder is forwarding the query within -the timeout or not. - -NodeID serves as the owner of payment contracts and signer of proofs of transfer. - -The Key is the target (if response to a retrieval request) or missing (zero value) -peers address (hash of NodeID) if retrieval request was a self lookup. - -Peers message is requested by retrieval requests with a missing or zero value request ID -*/ -type peersMsgData struct { - Peers []*peerAddr // - Timeout uint64 // - timeout *time.Time // indicate whether responder is expected to deliver content - Key storage.Key // present if a response to a retrieval request - Id uint64 // present if a response to a retrieval request - from *peer -} - -// peers msg pretty printer -func (self *peersMsgData) String() string { - var from string - if self.from == nil { - from = "ourselves" - } else { - from = self.from.Addr().String() - } - var target []byte - if len(self.Key) > 3 { - target = self.Key[:4] - } - return fmt.Sprintf("from: %v, Key: %x; ID: %v, Peers: %v", from, target, self.Id, self.Peers) -} - -func (self *peersMsgData) setTimeout(t *time.Time) { - self.timeout = t - if t != nil { - self.Timeout = uint64(t.UnixNano()) - } else { - self.Timeout = 0 - } -} - -/* -syncRequest - -is sent after the handshake to initiate syncing -the syncState of the remote node is persisted in kaddb and set on the -peer/protocol instance when the node is registered by hive as online{ -*/ - -type syncRequestMsgData struct { - SyncState *syncState `rlp:"nil"` -} - -func (self *syncRequestMsgData) String() string { - return fmt.Sprintf("%v", self.SyncState) -} - -/* -deliveryRequest - -is sent once a batch of sync keys is filtered. The ones not found are -sent as a list of syncReuest (hash, priority) in the Deliver field. -When the source receives the sync request it continues to iterate -and fetch at most N items as yet unsynced. -At the same time responds with deliveries of the items. -*/ -type deliveryRequestMsgData struct { - Deliver []*syncRequest -} - -func (self *deliveryRequestMsgData) String() string { - return fmt.Sprintf("sync request for new chunks\ndelivery request for %v chunks", len(self.Deliver)) -} - -/* -unsyncedKeys - -is sent first after the handshake if SyncState iterator brings up hundreds, thousands? -and subsequently sent as a response to deliveryRequestMsgData. - -Syncing is the iterative process of exchanging unsyncedKeys and deliveryRequestMsgs -both ways. - -State contains the sync state sent by the source. When the source receives the -sync state it continues to iterate and fetch at most N items as yet unsynced. -At the same time responds with deliveries of the items. -*/ -type unsyncedKeysMsgData struct { - Unsynced []*syncRequest - State *syncState -} - -func (self *unsyncedKeysMsgData) String() string { - return fmt.Sprintf("sync: keys of %d new chunks (state %v) => synced: %v", len(self.Unsynced), self.State, self.State.Synced) -} - -/* -payment - -is sent when the swap balance is tilted in favour of the remote peer -and in absolute units exceeds the PayAt parameter in the remote peer's profile -*/ - -type paymentMsgData struct { - Units uint // units actually paid for (checked against amount by swap) - Promise *chequebook.Cheque // payment with cheque -} - -func (self *paymentMsgData) String() string { - return fmt.Sprintf("payment for %d units: %v", self.Units, self.Promise) -} diff --git a/swarm/network/networkid_test.go b/swarm/network/networkid_test.go new file mode 100644 index 0000000000..9d47cf9f6a --- /dev/null +++ b/swarm/network/networkid_test.go @@ -0,0 +1,263 @@ +// 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 network + +import ( + "bytes" + "context" + "flag" + "fmt" + "math/rand" + "strings" + "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" + "github.com/ethereum/go-ethereum/p2p/simulations/adapters" + "github.com/ethereum/go-ethereum/rpc" +) + +var ( + currentNetworkID int + cnt int + nodeMap map[int][]enode.ID + kademlias map[enode.ID]*Kademlia +) + +const ( + NumberOfNets = 4 + MaxTimeout = 15 * time.Second +) + +func init() { + flag.Parse() + rand.Seed(time.Now().Unix()) +} + +/* +Run the network ID test. +The test creates one simulations.Network instance, +a number of nodes, then connects nodes with each other in this network. + +Each node gets a network ID assigned according to the number of networks. +Having more network IDs is just arbitrary in order to exclude +false positives. + +Nodes should only connect with other nodes with the same network ID. +After the setup phase, the test checks on each node if it has the +expected node connections (excluding those not sharing the network ID). +*/ +func TestNetworkID(t *testing.T) { + log.Debug("Start test") + //arbitrarily set the number of nodes. It could be any number + numNodes := 24 + //the nodeMap maps all nodes (slice value) with the same network ID (key) + nodeMap = make(map[int][]enode.ID) + //set up the network and connect nodes + net, err := setupNetwork(numNodes) + if err != nil { + t.Fatalf("Error setting up network: %v", err) + } + //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)) + //...check that their size of the kademlia is of the expected size + //the assumption is that it should be the size of the group minus 1 (the node itself) + for _, node := range netIDGroup { + 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 { + found := false + for _, nd := range netIDGroup { + if bytes.Equal(kademlias[nd].BaseAddr(), addr.Address()) { + found = true + } + } + if !found { + t.Fatalf("Expected node not found for node %s", node.String()) + } + return true + }) + } + } + log.Info("Test terminated successfully") +} + +// setup simulated network with bzz/discovery and pss services. +// connects nodes in a circle +// if allowRaw is set, omission of builtin pss encryption is enabled (see PssParams) +func setupNetwork(numnodes int) (net *simulations.Network, err error) { + log.Debug("Setting up network") + quitC := make(chan struct{}) + errc := make(chan error) + nodes := make([]*simulations.Node, numnodes) + if numnodes < 16 { + return nil, fmt.Errorf("Minimum sixteen nodes in network") + } + adapter := adapters.NewSimAdapter(newServices()) + //create the network + net = simulations.NewNetwork(adapter, &simulations.NetworkConfig{ + ID: "NetworkIdTestNet", + DefaultService: "bzz", + }) + log.Debug("Creating networks and nodes") + + var connCount int + + //create nodes and connect them to each other + for i := 0; i < numnodes; i++ { + log.Trace("iteration: ", "i", i) + nodeconf := adapters.RandomNodeConfig() + nodes[i], err = net.NewNodeWithConfig(nodeconf) + if err != nil { + return nil, fmt.Errorf("error creating node %d: %v", i, err) + } + err = net.Start(nodes[i].ID()) + if err != nil { + return nil, fmt.Errorf("error starting node %d: %v", i, err) + } + client, err := nodes[i].Client() + if err != nil { + 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) + defer watchCancel() + watchSubscriptionEvents(ctx, nodes[i].ID(), client, errc, quitC) + //on every iteration we connect to all previous ones + for k := i - 1; k >= 0; k-- { + connCount++ + log.Debug(fmt.Sprintf("Connecting node %d with node %d; connection count is %d", i, k, connCount)) + err = net.Connect(nodes[i].ID(), nodes[k].ID()) + if err != nil { + if !strings.Contains(err.Error(), "already connected") { + return nil, fmt.Errorf("error connecting nodes: %v", err) + } + } + } + } + //now wait until the number of expected subscriptions has been finished + //`watchSubscriptionEvents` will write with a `nil` value to errc + for err := range errc { + if err != nil { + return nil, err + } + //`nil` received, decrement count + connCount-- + log.Trace("count down", "cnt", connCount) + //all subscriptions received + if connCount == 0 { + close(quitC) + break + } + } + log.Debug("Network setup phase terminated") + return net, nil +} + +func newServices() adapters.Services { + kademlias = make(map[enode.ID]*Kademlia) + kademlia := func(id enode.ID) *Kademlia { + if k, ok := kademlias[id]; ok { + return k + } + params := NewKadParams() + params.NeighbourhoodSize = 2 + params.MaxBinSize = 3 + params.MinBinSize = 1 + params.MaxRetries = 1000 + params.RetryExponent = 2 + params.RetryInterval = 1000000 + kademlias[id] = NewKademlia(id[:], params) + return kademlias[id] + } + return adapters.Services{ + "bzz": func(ctx *adapters.ServiceContext) (node.Service, error) { + addr := NewAddr(ctx.Config.Node()) + hp := NewHiveParams() + hp.Discovery = false + cnt++ + //assign the network ID + currentNetworkID = cnt % NumberOfNets + if ok := nodeMap[currentNetworkID]; ok == nil { + nodeMap[currentNetworkID] = make([]enode.ID, 0) + } + //add this node to the group sharing the same network ID + nodeMap[currentNetworkID] = append(nodeMap[currentNetworkID], ctx.Config.ID) + log.Debug("current network ID:", "id", currentNetworkID) + config := &BzzConfig{ + OverlayAddr: addr.Over(), + UnderlayAddr: addr.Under(), + HiveParams: hp, + NetworkID: uint64(currentNetworkID), + } + return NewBzz(config, kademlia(ctx.Config.ID), nil, nil, nil), nil + }, + } +} + +func watchSubscriptionEvents(ctx context.Context, id enode.ID, client *rpc.Client, errc chan error, quitC chan struct{}) { + events := make(chan *p2p.PeerEvent) + sub, err := client.Subscribe(context.Background(), "admin", events, "peerEvents") + if err != nil { + log.Error(err.Error()) + errc <- fmt.Errorf("error getting peer events for node %v: %s", id, err) + return + } + go func() { + defer func() { + sub.Unsubscribe() + log.Trace("watch subscription events: unsubscribe", "id", id) + }() + + for { + select { + case <-quitC: + return + case <-ctx.Done(): + select { + case errc <- ctx.Err(): + case <-quitC: + } + return + case e := <-events: + if e.Type == p2p.PeerEventTypeAdd { + errc <- nil + } + case err := <-sub.Err(): + if err != nil { + select { + case errc <- fmt.Errorf("error getting peer events for node %v: %v", id, err): + case <-quitC: + } + return + } + } + } + }() +} diff --git a/swarm/network/priorityqueue/priorityqueue.go b/swarm/network/priorityqueue/priorityqueue.go new file mode 100644 index 0000000000..5385026054 --- /dev/null +++ b/swarm/network/priorityqueue/priorityqueue.go @@ -0,0 +1,109 @@ +// 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 priority_queue implement a channel based priority queue +// over arbitrary types. It provides an +// an autopop loop applying a function to the items always respecting +// their priority. The structure is only quasi consistent ie., if a lower +// priority item is autopopped, it is guaranteed that there was a point +// when no higher priority item was present, ie. it is not guaranteed +// that there was any point where the lower priority item was present +// but the higher was not + +package priorityqueue + +import ( + "context" + "errors" + + "github.com/ethereum/go-ethereum/log" +) + +var ( + ErrContention = errors.New("contention") + + errBadPriority = errors.New("bad priority") + + wakey = struct{}{} +) + +// PriorityQueue is the basic structure +type PriorityQueue struct { + Queues []chan interface{} + wakeup chan struct{} +} + +// New is the constructor for PriorityQueue +func New(n int, l int) *PriorityQueue { + var queues = make([]chan interface{}, n) + for i := range queues { + queues[i] = make(chan interface{}, l) + } + return &PriorityQueue{ + Queues: queues, + wakeup: make(chan struct{}, 1), + } +} + +// Run is a forever loop popping items from the queues +func (pq *PriorityQueue) Run(ctx context.Context, f func(interface{})) { + top := len(pq.Queues) - 1 + p := top +READ: + for { + q := pq.Queues[p] + select { + case <-ctx.Done(): + return + case x := <-q: + log.Trace("priority.queue f(x)", "p", p, "len(Queues[p])", len(pq.Queues[p])) + f(x) + p = top + default: + if p > 0 { + p-- + log.Trace("priority.queue p > 0", "p", p) + continue READ + } + p = top + select { + case <-ctx.Done(): + return + case <-pq.wakeup: + log.Trace("priority.queue wakeup", "p", p) + } + } + } +} + +// Push pushes an item to the appropriate queue specified in the priority argument +// if context is given it waits until either the item is pushed or the Context aborts +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])) + select { + case pq.Queues[p] <- x: + default: + return ErrContention + } + select { + case pq.wakeup <- wakey: + default: + } + return nil +} diff --git a/swarm/network/priorityqueue/priorityqueue_test.go b/swarm/network/priorityqueue/priorityqueue_test.go new file mode 100644 index 0000000000..ed8b575c20 --- /dev/null +++ b/swarm/network/priorityqueue/priorityqueue_test.go @@ -0,0 +1,97 @@ +// 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 priorityqueue + +import ( + "context" + "sync" + "testing" +) + +func TestPriorityQueue(t *testing.T) { + var results []string + wg := sync.WaitGroup{} + pq := New(3, 2) + wg.Add(1) + go pq.Run(context.Background(), func(v interface{}) { + results = append(results, v.(string)) + wg.Done() + }) + pq.Push("2.0", 2) + wg.Wait() + if results[0] != "2.0" { + t.Errorf("expected first result %q, got %q", "2.0", results[0]) + } + +Loop: + for i, tc := range []struct { + priorities []int + values []string + results []string + errors []error + }{ + { + priorities: []int{0}, + values: []string{""}, + results: []string{""}, + }, + { + priorities: []int{0, 1}, + values: []string{"0.0", "1.0"}, + results: []string{"1.0", "0.0"}, + }, + { + priorities: []int{1, 0}, + values: []string{"1.0", "0.0"}, + results: []string{"1.0", "0.0"}, + }, + { + priorities: []int{0, 1, 1}, + values: []string{"0.0", "1.0", "1.1"}, + results: []string{"1.0", "1.1", "0.0"}, + }, + { + priorities: []int{0, 0, 0}, + values: []string{"0.0", "0.0", "0.1"}, + errors: []error{nil, nil, ErrContention}, + }, + } { + var results []string + wg := sync.WaitGroup{} + pq := New(3, 2) + wg.Add(len(tc.values)) + for j, value := range tc.values { + err := pq.Push(value, tc.priorities[j]) + if tc.errors != nil && err != tc.errors[j] { + t.Errorf("expected push error %v, got %v", tc.errors[j], err) + continue Loop + } + if err != nil { + continue Loop + } + } + go pq.Run(context.Background(), func(v interface{}) { + results = append(results, v.(string)) + wg.Done() + }) + wg.Wait() + for k, result := range tc.results { + if results[k] != result { + t.Errorf("test case %v: expected %v element %q, got %q", i, k, result, results[k]) + } + } + } +} diff --git a/swarm/network/protocol.go b/swarm/network/protocol.go index a418c1dbbd..6f8eadad2a 100644 --- a/swarm/network/protocol.go +++ b/swarm/network/protocol.go @@ -16,495 +16,374 @@ package network -/* -bzz implements the swarm wire protocol [bzz] (sister of eth and shh) -the protocol instance is launched on each peer by the network layer if the -bzz protocol handler is registered on the p2p server. - -The bzz protocol component speaks the bzz protocol -* handle the protocol handshake -* register peers in the KΛÐΞMLIΛ table via the hive logistic manager -* dispatch to hive for handling the DHT logic -* encode and decode requests for storage and retrieval -* handle sync protocol messages via the syncer -* talks the SWAP payment protocol (swap accounting is done within NetStore) -*/ - import ( + "context" "errors" "fmt" "net" - "strconv" + "sync" "time" - "github.com/ethereum/go-ethereum/contracts/chequebook" - "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/p2p" - bzzswap "github.com/ethereum/go-ethereum/swarm/services/swap" - "github.com/ethereum/go-ethereum/swarm/services/swap/swap" - "github.com/ethereum/go-ethereum/swarm/storage" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/protocols" + "github.com/ethereum/go-ethereum/rpc" + "github.com/ethereum/go-ethereum/swarm/log" + "github.com/ethereum/go-ethereum/swarm/state" ) const ( - Version = 0 - ProtocolLength = uint64(8) - ProtocolMaxMsgSize = 10 * 1024 * 1024 - NetworkId = 3 + DefaultNetworkID = 3 + // timeout for waiting + bzzHandshakeTimeout = 3000 * time.Millisecond ) -// bzz represents the swarm wire protocol -// an instance is running on each peer -type bzz struct { - storage StorageHandler // handler storage/retrieval related requests coming via the bzz wire protocol - hive *Hive // the logistic manager, peerPool, routing service and peer handler - dbAccess *DbAccess // access to db storage counter and iterator for syncing - requestDb *storage.LDBDatabase // db to persist backlog of deliveries to aid syncing - remoteAddr *peerAddr // remote peers address - peer *p2p.Peer // the p2p peer object - rw p2p.MsgReadWriter // messageReadWriter to send messages to - backend chequebook.Backend - lastActive time.Time - NetworkId uint64 - - swap *swap.Swap // swap instance for the peer connection - swapParams *bzzswap.SwapParams // swap settings both local and remote - swapEnabled bool // flag to enable SWAP (will be set via Caps in handshake) - syncEnabled bool // flag to enable SYNC (will be set via Caps in handshake) - syncer *syncer // syncer instance for the peer connection - syncParams *SyncParams // syncer params - syncState *syncState // outgoing syncronisation state (contains reference to remote peers db counter) +// BzzSpec is the spec of the generic swarm handshake +var BzzSpec = &protocols.Spec{ + Name: "bzz", + Version: 8, + MaxMsgSize: 10 * 1024 * 1024, + Messages: []interface{}{ + HandshakeMsg{}, + }, } -// interface type for handler of storage/retrieval related requests coming -// via the bzz wire protocol -// messages: UnsyncedKeys, DeliveryRequest, StoreRequest, RetrieveRequest -type StorageHandler interface { - HandleUnsyncedKeysMsg(req *unsyncedKeysMsgData, p *peer) error - HandleDeliveryRequestMsg(req *deliveryRequestMsgData, p *peer) error - HandleStoreRequestMsg(req *storeRequestMsgData, p *peer) - HandleRetrieveRequestMsg(req *retrieveRequestMsgData, p *peer) +// DiscoverySpec is the spec for the bzz discovery subprotocols +var DiscoverySpec = &protocols.Spec{ + Name: "hive", + Version: 8, + MaxMsgSize: 10 * 1024 * 1024, + Messages: []interface{}{ + peersMsg{}, + subPeersMsg{}, + }, } -/* -main entrypoint, wrappers starting a server that will run the bzz protocol -use this constructor to attach the protocol ("class") to server caps -This is done by node.Node#Register(func(node.ServiceContext) (Service, error)) -Service implements Protocols() which is an array of protocol constructors -at node startup the protocols are initialised -the Dev p2p layer then calls Run(p *p2p.Peer, rw p2p.MsgReadWriter) error -on each peer connection -The Run function of the Bzz protocol class creates a bzz instance -which will represent the peer for the swarm hive and all peer-aware components -*/ -func Bzz(cloud StorageHandler, backend chequebook.Backend, hive *Hive, dbaccess *DbAccess, sp *bzzswap.SwapParams, sy *SyncParams, networkId uint64) (p2p.Protocol, error) { +// BzzConfig captures the config params used by the hive +type BzzConfig struct { + OverlayAddr []byte // base address of the overlay network + UnderlayAddr []byte // node's underlay address + HiveParams *HiveParams + NetworkID uint64 + LightNode bool + BootnodeMode bool +} - // a single global request db is created for all peer connections - // this is to persist delivery backlog and aid syncronisation - requestDb, err := storage.NewLDBDatabase(sy.RequestDbPath) - if err != nil { - return p2p.Protocol{}, fmt.Errorf("error setting up request db: %v", err) +// Bzz is the swarm protocol bundle +type Bzz struct { + *Hive + NetworkID uint64 + LightNode bool + localAddr *BzzAddr + mtx sync.Mutex + handshakes map[enode.ID]*HandshakeMsg + streamerSpec *protocols.Spec + streamerRun func(*BzzPeer) error +} + +// NewBzz is the swarm protocol constructor +// arguments +// * bzz config +// * overlay driver +// * peer store +func NewBzz(config *BzzConfig, kad *Kademlia, store state.Store, streamerSpec *protocols.Spec, streamerRun func(*BzzPeer) error) *Bzz { + bzz := &Bzz{ + Hive: NewHive(config.HiveParams, kad, store), + NetworkID: config.NetworkID, + LightNode: config.LightNode, + localAddr: &BzzAddr{config.OverlayAddr, config.UnderlayAddr}, + handshakes: make(map[enode.ID]*HandshakeMsg), + streamerRun: streamerRun, + streamerSpec: streamerSpec, } - if networkId == 0 { - networkId = NetworkId + + if config.BootnodeMode { + bzz.streamerRun = nil + bzz.streamerSpec = nil } - return p2p.Protocol{ - Name: "bzz", - Version: Version, - Length: ProtocolLength, - Run: func(p *p2p.Peer, rw p2p.MsgReadWriter) error { - return run(requestDb, cloud, backend, hive, dbaccess, sp, sy, networkId, p, rw) + + return bzz +} + +// UpdateLocalAddr updates underlayaddress of the running node +func (b *Bzz) UpdateLocalAddr(byteaddr []byte) *BzzAddr { + b.localAddr = b.localAddr.Update(&BzzAddr{ + UAddr: byteaddr, + OAddr: b.localAddr.OAddr, + }) + return b.localAddr +} + +// NodeInfo returns the node's overlay address +func (b *Bzz) NodeInfo() interface{} { + return b.localAddr.Address() +} + +// Protocols return the protocols swarm offers +// Bzz implements the node.Service interface +// * handshake/hive +// * discovery +func (b *Bzz) Protocols() []p2p.Protocol { + protocol := []p2p.Protocol{ + { + Name: BzzSpec.Name, + Version: BzzSpec.Version, + Length: BzzSpec.Length(), + Run: b.runBzz, + NodeInfo: b.NodeInfo, }, - }, nil + { + Name: DiscoverySpec.Name, + Version: DiscoverySpec.Version, + Length: DiscoverySpec.Length(), + Run: b.RunProtocol(DiscoverySpec, b.Hive.Run), + NodeInfo: b.Hive.NodeInfo, + PeerInfo: b.Hive.PeerInfo, + }, + } + if b.streamerSpec != nil && b.streamerRun != nil { + protocol = append(protocol, p2p.Protocol{ + Name: b.streamerSpec.Name, + Version: b.streamerSpec.Version, + Length: b.streamerSpec.Length(), + Run: b.RunProtocol(b.streamerSpec, b.streamerRun), + }) + } + return protocol } -/* -the main protocol loop that - * does the handshake by exchanging statusMsg - * if peer is valid and accepted, registers with the hive - * then enters into a forever loop handling incoming messages - * storage and retrieval related queries coming via bzz are dispatched to StorageHandler - * peer-related messages are dispatched to the hive - * payment related messages are relayed to SWAP service - * on disconnect, unregister the peer in the hive (note RemovePeer in the post-disconnect hook) - * whenever the loop terminates, the peer will disconnect with Subprotocol error - * whenever handlers return an error the loop terminates -*/ -func run(requestDb *storage.LDBDatabase, depo StorageHandler, backend chequebook.Backend, hive *Hive, dbaccess *DbAccess, sp *bzzswap.SwapParams, sy *SyncParams, networkId uint64, p *p2p.Peer, rw p2p.MsgReadWriter) (err error) { +// APIs returns the APIs offered by bzz +// * hive +// Bzz implements the node.Service interface +func (b *Bzz) APIs() []rpc.API { + return []rpc.API{{ + Namespace: "hive", + Version: "3.0", + Service: b.Hive, + }} +} - self := &bzz{ - storage: depo, - backend: backend, - hive: hive, - dbAccess: dbaccess, - requestDb: requestDb, - peer: p, - rw: rw, - swapParams: sp, - syncParams: sy, - swapEnabled: hive.swapEnabled, - syncEnabled: true, - NetworkId: networkId, - } +// RunProtocol is a wrapper for swarm subprotocols +// returns a p2p protocol run function that can be assigned to p2p.Protocol#Run field +// arguments: +// * p2p protocol spec +// * run function taking BzzPeer as argument +// this run function is meant to block for the duration of the protocol session +// on return the session is terminated and the peer is disconnected +// the protocol waits for the bzz handshake is negotiated +// the overlay address on the BzzPeer is set from the remote handshake +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.GetOrCreateHandshake(p.ID()) + defer b.removeHandshake(p.ID()) + select { + case <-handshake.done: + case <-time.After(bzzHandshakeTimeout): + return fmt.Errorf("%08x: %s protocol timeout waiting for handshake on %08x", b.BaseAddr()[:4], spec.Name, p.ID().Bytes()[:4]) + } + if handshake.err != nil { + return fmt.Errorf("%08x: %s protocol closed: %v", b.BaseAddr()[:4], spec.Name, handshake.err) + } + // the handshake has succeeded so construct the BzzPeer and run the protocol + peer := &BzzPeer{ + Peer: protocols.NewPeer(p, rw, spec), + BzzAddr: handshake.peerAddr, + lastActive: time.Now(), + LightNode: handshake.LightNode, + } - // handle handshake - err = self.handleStatus() - if err != nil { - return err + log.Debug("peer created", "addr", handshake.peerAddr.String()) + + return run(peer) } +} + +// performHandshake implements the negotiation of the bzz handshake +// shared among swarm subprotocols +func (b *Bzz) performHandshake(p *protocols.Peer, handshake *HandshakeMsg) error { + ctx, cancel := context.WithTimeout(context.Background(), bzzHandshakeTimeout) defer func() { - // if the handler loop exits, the peer is disconnecting - // deregister the peer in the hive - self.hive.removePeer(&peer{bzz: self}) - if self.syncer != nil { - self.syncer.stop() // quits request db and delivery loops, save requests - } - if self.swap != nil { - self.swap.Stop() // quits chequebox autocash etc - } + close(handshake.done) + cancel() }() - - // the main forever loop that handles incoming requests - for { - if self.hive.blockRead { - log.Warn(fmt.Sprintf("Cannot read network")) - time.Sleep(100 * time.Millisecond) - continue - } - err = self.handle() - if err != nil { - return - } + rsh, err := p.Handshake(ctx, handshake, b.checkHandshake) + if err != nil { + handshake.err = err + return err } + handshake.peerAddr = rsh.(*HandshakeMsg).Addr + handshake.LightNode = rsh.(*HandshakeMsg).LightNode + return nil } -// TODO: may need to implement protocol drop only? don't want to kick off the peer -// if they are useful for other protocols -func (self *bzz) Drop() { - self.peer.Disconnect(p2p.DiscSubprotocolError) -} +// 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.GetOrCreateHandshake(p.ID()) + if !<-handshake.init { + return fmt.Errorf("%08x: bzz already started on peer %08x", b.localAddr.Over()[:4], p.ID().Bytes()[:4]) + } + close(handshake.init) + defer b.removeHandshake(p.ID()) + peer := protocols.NewPeer(p, rw, BzzSpec) + err := b.performHandshake(peer, handshake) + if err != nil { + log.Warn(fmt.Sprintf("%08x: handshake failed with remote peer %08x: %v", b.localAddr.Over()[:4], p.ID().Bytes()[:4], err)) -// one cycle of the main forever loop that handles and dispatches incoming messages -func (self *bzz) handle() error { - msg, err := self.rw.ReadMsg() - log.Debug(fmt.Sprintf("<- %v", msg)) + return err + } + // fail if we get another handshake + msg, err := rw.ReadMsg() if err != nil { return err } - if msg.Size > ProtocolMaxMsgSize { - return fmt.Errorf("message too long: %v > %v", msg.Size, ProtocolMaxMsgSize) + msg.Discard() + return errors.New("received multiple handshakes") +} + +// BzzPeer is the bzz protocol view of a protocols.Peer (itself an extension of p2p.Peer) +// implements the Peer interface and all interfaces Peer implements: Addr, OverlayPeer +type BzzPeer struct { + *protocols.Peer // represents the connection for online peers + *BzzAddr // remote address -> implements Addr interface = protocols.Peer + lastActive time.Time // time is updated whenever mutexes are releasing + LightNode bool +} + +func NewBzzPeer(p *protocols.Peer) *BzzPeer { + return &BzzPeer{Peer: p, BzzAddr: NewAddr(p.Node())} +} + +// 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 + // into the struct and provide ID(). The protocols.Peer version is faster, ensure it + // gets used. + return p.Peer.ID() +} + +/* + Handshake + +* Version: 8 byte integer version of the protocol +* NetworkID: 8 byte integer network identifier +* Addr: the address advertised by the node including underlay and overlay connecctions +*/ +type HandshakeMsg struct { + Version uint64 + NetworkID uint64 + Addr *BzzAddr + LightNode bool + + // peerAddr is the address received in the peer handshake + peerAddr *BzzAddr + + init chan bool + done chan struct{} + err error +} + +// String pretty prints the handshake +func (bh *HandshakeMsg) String() string { + return fmt.Sprintf("Handshake: Version: %v, NetworkID: %v, Addr: %v, LightNode: %v, peerAddr: %v", bh.Version, bh.NetworkID, bh.Addr, bh.LightNode, bh.peerAddr) +} + +// Perform initiates the handshake and validates the remote handshake message +func (b *Bzz) checkHandshake(hs interface{}) error { + rhs := hs.(*HandshakeMsg) + if rhs.NetworkID != b.NetworkID { + return fmt.Errorf("network id mismatch %d (!= %d)", rhs.NetworkID, b.NetworkID) } - // make sure that the payload has been fully consumed - defer msg.Discard() - - switch msg.Code { - - case statusMsg: - // no extra status message allowed. The one needed already handled by - // handleStatus - log.Debug(fmt.Sprintf("Status message: %v", msg)) - return errors.New("extra status message") - - case storeRequestMsg: - // store requests are dispatched to netStore - var req storeRequestMsgData - if err := msg.Decode(&req); err != nil { - return fmt.Errorf("<- %v: %v", msg, err) - } - if n := len(req.SData); n < 9 { - return fmt.Errorf("<- %v: Data too short (%v)", msg, n) - } - // last Active time is set only when receiving chunks - self.lastActive = time.Now() - log.Trace(fmt.Sprintf("incoming store request: %s", req.String())) - // swap accounting is done within forwarding - self.storage.HandleStoreRequestMsg(&req, &peer{bzz: self}) - - case retrieveRequestMsg: - // retrieve Requests are dispatched to netStore - var req retrieveRequestMsgData - if err := msg.Decode(&req); err != nil { - return fmt.Errorf("<- %v: %v", msg, err) - } - req.from = &peer{bzz: self} - // if request is lookup and not to be delivered - if req.isLookup() { - log.Trace(fmt.Sprintf("self lookup for %v: responding with peers only...", req.from)) - } else if req.Key == nil { - return fmt.Errorf("protocol handler: req.Key == nil || req.Timeout == nil") - } else { - // swap accounting is done within netStore - self.storage.HandleRetrieveRequestMsg(&req, &peer{bzz: self}) - } - // direct response with peers, TODO: sort this out - self.hive.peers(&req) - - case peersMsg: - // response to lookups and immediate response to retrieve requests - // dispatches new peer data to the hive that adds them to KADDB - var req peersMsgData - if err := msg.Decode(&req); err != nil { - return fmt.Errorf("<- %v: %v", msg, err) - } - req.from = &peer{bzz: self} - log.Trace(fmt.Sprintf("<- peer addresses: %v", req)) - self.hive.HandlePeersMsg(&req, &peer{bzz: self}) - - case syncRequestMsg: - var req syncRequestMsgData - if err := msg.Decode(&req); err != nil { - return fmt.Errorf("<- %v: %v", msg, err) - } - log.Debug(fmt.Sprintf("<- sync request: %v", req)) - self.lastActive = time.Now() - self.sync(req.SyncState) - - case unsyncedKeysMsg: - // coming from parent node offering - var req unsyncedKeysMsgData - if err := msg.Decode(&req); err != nil { - return fmt.Errorf("<- %v: %v", msg, err) - } - log.Debug(fmt.Sprintf("<- unsynced keys : %s", req.String())) - err := self.storage.HandleUnsyncedKeysMsg(&req, &peer{bzz: self}) - self.lastActive = time.Now() - if err != nil { - return fmt.Errorf("<- %v: %v", msg, err) - } - - case deliveryRequestMsg: - // response to syncKeysMsg hashes filtered not existing in db - // also relays the last synced state to the source - var req deliveryRequestMsgData - if err := msg.Decode(&req); err != nil { - return fmt.Errorf("<-msg %v: %v", msg, err) - } - log.Debug(fmt.Sprintf("<- delivery request: %s", req.String())) - err := self.storage.HandleDeliveryRequestMsg(&req, &peer{bzz: self}) - self.lastActive = time.Now() - if err != nil { - return fmt.Errorf("<- %v: %v", msg, err) - } - - case paymentMsg: - // swap protocol message for payment, Units paid for, Cheque paid with - if self.swapEnabled { - var req paymentMsgData - if err := msg.Decode(&req); err != nil { - return fmt.Errorf("<- %v: %v", msg, err) - } - log.Debug(fmt.Sprintf("<- payment: %s", req.String())) - self.swap.Receive(int(req.Units), req.Promise) - } - - default: - // no other message is allowed - return fmt.Errorf("invalid message code: %v", msg.Code) + if rhs.Version != uint64(BzzSpec.Version) { + return fmt.Errorf("version mismatch %d (!= %d)", rhs.Version, BzzSpec.Version) } return nil } -func (self *bzz) handleStatus() (err error) { +// removeHandshake removes handshake for peer with peerID +// from the bzz handshake store +func (b *Bzz) removeHandshake(peerID enode.ID) { + b.mtx.Lock() + defer b.mtx.Unlock() + delete(b.handshakes, peerID) +} - handshake := &statusMsgData{ - Version: uint64(Version), - ID: "honey", - Addr: self.selfAddr(), - NetworkId: self.NetworkId, - Swap: &bzzswap.SwapProfile{ - Profile: self.swapParams.Profile, - PayProfile: self.swapParams.PayProfile, - }, - } - - err = p2p.Send(self.rw, statusMsg, handshake) - if err != nil { - return err - } - - // read and handle remote status - var msg p2p.Msg - msg, err = self.rw.ReadMsg() - if err != nil { - return err - } - - if msg.Code != statusMsg { - return fmt.Errorf("first msg has code %x (!= %x)", msg.Code, statusMsg) - } - - if msg.Size > ProtocolMaxMsgSize { - return fmt.Errorf("message too long: %v > %v", msg.Size, ProtocolMaxMsgSize) - } - - var status statusMsgData - if err := msg.Decode(&status); err != nil { - return fmt.Errorf("<- %v: %v", msg, err) - } - - if status.NetworkId != self.NetworkId { - return fmt.Errorf("network id mismatch: %d (!= %d)", status.NetworkId, self.NetworkId) - } - - if Version != status.Version { - return fmt.Errorf("protocol version mismatch: %d (!= %d)", status.Version, Version) - } - - self.remoteAddr = self.peerAddr(status.Addr) - log.Trace(fmt.Sprintf("self: advertised IP: %v, peer advertised: %v, local address: %v\npeer: advertised IP: %v, remote address: %v\n", self.selfAddr(), self.remoteAddr, self.peer.LocalAddr(), status.Addr.IP, self.peer.RemoteAddr())) - - if self.swapEnabled { - // set remote profile for accounting - self.swap, err = bzzswap.NewSwap(self.swapParams, status.Swap, self.backend, self) - if err != nil { - return err +// GetHandshake returns the bzz handhake that the remote peer with peerID sent +func (b *Bzz) GetOrCreateHandshake(peerID enode.ID) (*HandshakeMsg, bool) { + b.mtx.Lock() + defer b.mtx.Unlock() + handshake, found := b.handshakes[peerID] + if !found { + handshake = &HandshakeMsg{ + Version: uint64(BzzSpec.Version), + NetworkID: b.NetworkID, + Addr: b.localAddr, + LightNode: b.LightNode, + init: make(chan bool, 1), + done: make(chan struct{}), } + // when handhsake is first created for a remote peer + // it is initialised with the init + handshake.init <- true + b.handshakes[peerID] = handshake } - log.Info(fmt.Sprintf("Peer %08x is capable (%d/%d)", self.remoteAddr.Addr[:4], status.Version, status.NetworkId)) - err = self.hive.addPeer(&peer{bzz: self}) + 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 err + return enode.ID{} } - - // hive sets syncstate so sync should start after node added - log.Info(fmt.Sprintf("syncronisation request sent with %v", self.syncState)) - self.syncRequest() - - return nil + return n.ID() } -func (self *bzz) sync(state *syncState) error { - // syncer setup - if self.syncer != nil { - return errors.New("sync request can only be sent once") - } +// Update updates the underlay address of a peer record +func (a *BzzAddr) Update(na *BzzAddr) *BzzAddr { + return &BzzAddr{a.OAddr, na.UAddr} +} - cnt := self.dbAccess.counter() - remoteaddr := self.remoteAddr.Addr - start, stop := self.hive.kad.KeyRange(remoteaddr) +// String pretty prints the address +func (a *BzzAddr) String() string { + return fmt.Sprintf("%x <%s>", a.OAddr, a.UAddr) +} - // an explicitly received nil syncstate disables syncronisation - if state == nil { - self.syncEnabled = false - log.Warn(fmt.Sprintf("syncronisation disabled for peer %v", self)) - state = &syncState{DbSyncState: &storage.DbSyncState{}, Synced: true} - } else { - state.synced = make(chan bool) - state.SessionAt = cnt - if storage.IsZeroKey(state.Stop) && state.Synced { - state.Start = storage.Key(start[:]) - state.Stop = storage.Key(stop[:]) - } - log.Debug(fmt.Sprintf("syncronisation requested by peer %v at state %v", self, state)) - } - var err error - self.syncer, err = newSyncer( - self.requestDb, - storage.Key(remoteaddr[:]), - self.dbAccess, - self.unsyncedKeys, self.store, - self.syncParams, state, func() bool { return self.syncEnabled }, - ) +// RandomAddr is a utility method generating an address from a public key +func RandomAddr() *BzzAddr { + key, err := crypto.GenerateKey() if err != nil { - return nil + panic("unable to generate key") } - log.Trace(fmt.Sprintf("syncer set for peer %v", self)) - return nil + node := enode.NewV4(&key.PublicKey, net.IP{127, 0, 0, 1}, 30303, 30303) + return NewAddr(node) } -func (self *bzz) String() string { - return self.remoteAddr.String() -} - -// repair reported address if IP missing -func (self *bzz) peerAddr(base *peerAddr) *peerAddr { - if base.IP.IsUnspecified() { - host, _, _ := net.SplitHostPort(self.peer.RemoteAddr().String()) - base.IP = net.ParseIP(host) - } - return base -} - -// returns self advertised node connection info (listening address w enodes) -// IP will get repaired on the other end if missing -// or resolved via ID by discovery at dialout -func (self *bzz) selfAddr() *peerAddr { - id := self.hive.id - host, port, _ := net.SplitHostPort(self.hive.listenAddr()) - intport, _ := strconv.Atoi(port) - addr := &peerAddr{ - Addr: self.hive.addr, - ID: id[:], - IP: net.ParseIP(host), - Port: uint16(intport), - } - return addr -} - -// outgoing messages -// send retrieveRequestMsg -func (self *bzz) retrieve(req *retrieveRequestMsgData) error { - return self.send(retrieveRequestMsg, req) -} - -// send storeRequestMsg -func (self *bzz) store(req *storeRequestMsgData) error { - return self.send(storeRequestMsg, req) -} - -func (self *bzz) syncRequest() error { - req := &syncRequestMsgData{} - if self.hive.syncEnabled { - log.Debug(fmt.Sprintf("syncronisation request to peer %v at state %v", self, self.syncState)) - req.SyncState = self.syncState - } - if self.syncState == nil { - log.Warn(fmt.Sprintf("syncronisation disabled for peer %v at state %v", self, self.syncState)) - } - return self.send(syncRequestMsg, req) -} - -// queue storeRequestMsg in request db -func (self *bzz) deliveryRequest(reqs []*syncRequest) error { - req := &deliveryRequestMsgData{ - Deliver: reqs, - } - return self.send(deliveryRequestMsg, req) -} - -// batch of syncRequests to send off -func (self *bzz) unsyncedKeys(reqs []*syncRequest, state *syncState) error { - req := &unsyncedKeysMsgData{ - Unsynced: reqs, - State: state, - } - return self.send(unsyncedKeysMsg, req) -} - -// send paymentMsg -func (self *bzz) Pay(units int, promise swap.Promise) { - req := &paymentMsgData{uint(units), promise.(*chequebook.Cheque)} - self.payment(req) -} - -// send paymentMsg -func (self *bzz) payment(req *paymentMsgData) error { - return self.send(paymentMsg, req) -} - -// sends peersMsg -func (self *bzz) peers(req *peersMsgData) error { - return self.send(peersMsg, req) -} - -func (self *bzz) send(msg uint64, data interface{}) error { - if self.hive.blockWrite { - return fmt.Errorf("network write blocked") - } - log.Trace(fmt.Sprintf("-> %v: %v (%T) to %v", msg, data, data, self)) - err := p2p.Send(self.rw, msg, data) - if err != nil { - self.Drop() - } - return err +// 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/swarm/network/protocol_test.go b/swarm/network/protocol_test.go index 988d0ac923..64ce7ba4ab 100644 --- a/swarm/network/protocol_test.go +++ b/swarm/network/protocol_test.go @@ -1,4 +1,4 @@ -// Copyright 2014 The go-ethereum Authors +// 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 @@ -15,3 +15,239 @@ // along with the go-ethereum library. If not, see . package network + +import ( + "flag" + "fmt" + "os" + "testing" + "time" + + "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" + p2ptest "github.com/ethereum/go-ethereum/p2p/testing" +) + +const ( + TestProtocolVersion = 8 + TestProtocolNetworkID = 3 +) + +var ( + loglevel = flag.Int("loglevel", 2, "verbosity of logs") +) + +func init() { + flag.Parse() + log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) +} + +func HandshakeMsgExchange(lhs, rhs *HandshakeMsg, id enode.ID) []p2ptest.Exchange { + return []p2ptest.Exchange{ + { + Expects: []p2ptest.Expect{ + { + Code: 0, + Msg: lhs, + Peer: id, + }, + }, + }, + { + Triggers: []p2ptest.Trigger{ + { + Code: 0, + Msg: rhs, + Peer: id, + }, + }, + }, + } +} + +func newBzzBaseTester(t *testing.T, n int, addr *BzzAddr, spec *protocols.Spec, run func(*BzzPeer) error) *bzzTester { + cs := make(map[string]chan bool) + + srv := func(p *BzzPeer) error { + defer func() { + if cs[p.ID().String()] != nil { + close(cs[p.ID().String()]) + } + }() + return run(p) + } + + protocol := func(p *p2p.Peer, rw p2p.MsgReadWriter) error { + return srv(&BzzPeer{Peer: protocols.NewPeer(p, rw, spec), BzzAddr: NewAddr(p.Node())}) + } + + s := p2ptest.NewProtocolTester(addr.ID(), n, protocol) + + for _, node := range s.Nodes { + cs[node.ID().String()] = make(chan bool) + } + + return &bzzTester{ + addr: addr, + ProtocolTester: s, + cs: cs, + } +} + +type bzzTester struct { + *p2ptest.ProtocolTester + addr *BzzAddr + cs map[string]chan bool + bzz *Bzz +} + +func newBzz(addr *BzzAddr, lightNode bool) *Bzz { + config := &BzzConfig{ + OverlayAddr: addr.Over(), + UnderlayAddr: addr.Under(), + HiveParams: NewHiveParams(), + NetworkID: DefaultNetworkID, + LightNode: lightNode, + } + kad := NewKademlia(addr.OAddr, NewKadParams()) + bzz := NewBzz(config, kad, nil, nil, nil) + return bzz +} + +func newBzzHandshakeTester(n int, addr *BzzAddr, lightNode bool) *bzzTester { + bzz := newBzz(addr, lightNode) + pt := p2ptest.NewProtocolTester(addr.ID(), n, bzz.runBzz) + + return &bzzTester{ + addr: addr, + ProtocolTester: pt, + bzz: bzz, + } +} + +// should test handshakes in one exchange? parallelisation +func (s *bzzTester) testHandshake(lhs, rhs *HandshakeMsg, disconnects ...*p2ptest.Disconnect) error { + if err := s.TestExchanges(HandshakeMsgExchange(lhs, rhs, rhs.Addr.ID())...); err != nil { + return err + } + + if len(disconnects) > 0 { + return s.TestDisconnected(disconnects...) + } + + // If we don't expect disconnect, ensure peers remain connected + err := s.TestDisconnected(&p2ptest.Disconnect{ + Peer: s.Nodes[0].ID(), + Error: nil, + }) + + if err == nil { + return fmt.Errorf("Unexpected peer disconnect") + } + + if err.Error() != "timed out waiting for peers to disconnect" { + return err + } + + return nil +} + +func correctBzzHandshake(addr *BzzAddr, lightNode bool) *HandshakeMsg { + return &HandshakeMsg{ + Version: TestProtocolVersion, + NetworkID: TestProtocolNetworkID, + Addr: addr, + LightNode: lightNode, + } +} + +func TestBzzHandshakeNetworkIDMismatch(t *testing.T) { + lightNode := false + addr := RandomAddr() + s := newBzzHandshakeTester(1, addr, lightNode) + node := s.Nodes[0] + + err := s.testHandshake( + correctBzzHandshake(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)")}, + ) + + if err != nil { + t.Fatal(err) + } +} + +func TestBzzHandshakeVersionMismatch(t *testing.T) { + lightNode := false + addr := RandomAddr() + s := newBzzHandshakeTester(1, addr, lightNode) + node := s.Nodes[0] + + err := s.testHandshake( + correctBzzHandshake(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)}, + ) + + if err != nil { + t.Fatal(err) + } +} + +func TestBzzHandshakeSuccess(t *testing.T) { + lightNode := false + addr := RandomAddr() + s := newBzzHandshakeTester(1, addr, lightNode) + node := s.Nodes[0] + + err := s.testHandshake( + correctBzzHandshake(addr, lightNode), + &HandshakeMsg{Version: TestProtocolVersion, NetworkID: TestProtocolNetworkID, Addr: NewAddr(node)}, + ) + + if err != nil { + t.Fatal(err) + } +} + +func TestBzzHandshakeLightNode(t *testing.T) { + var lightNodeTests = []struct { + name string + lightNode bool + }{ + {"on", true}, + {"off", false}, + } + + for _, test := range lightNodeTests { + t.Run(test.name, func(t *testing.T) { + randomAddr := RandomAddr() + pt := newBzzHandshakeTester(1, randomAddr, false) + + node := pt.Nodes[0] + addr := NewAddr(node) + + err := pt.testHandshake( + correctBzzHandshake(randomAddr, false), + &HandshakeMsg{Version: TestProtocolVersion, NetworkID: TestProtocolNetworkID, Addr: addr, LightNode: test.lightNode}, + ) + + if err != nil { + t.Fatal(err) + } + + 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/swarm/network/simulation/bucket.go b/swarm/network/simulation/bucket.go new file mode 100644 index 0000000000..49a1f43091 --- /dev/null +++ b/swarm/network/simulation/bucket.go @@ -0,0 +1,79 @@ +// 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 "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 particular node. +func (s *Simulation) NodeItem(id enode.ID, key interface{}) (value interface{}, ok bool) { + s.mu.Lock() + defer s.mu.Unlock() + + if _, ok := s.buckets[id]; !ok { + return nil, false + } + return s.buckets[id].Load(key) +} + +// SetNodeItem sets a new item associated with the node with provided NodeID. +// Buckets should be used to avoid managing separate simulation global state. +func (s *Simulation) SetNodeItem(id enode.ID, key interface{}, value interface{}) { + s.mu.Lock() + defer s.mu.Unlock() + + s.buckets[id].Store(key, value) +} + +// NodesItems returns a map of items from all nodes that are all set under the +// same BucketKey. +func (s *Simulation) NodesItems(key interface{}) (values map[enode.ID]interface{}) { + s.mu.RLock() + defer s.mu.RUnlock() + + ids := s.NodeIDs() + values = make(map[enode.ID]interface{}, len(ids)) + for _, id := range ids { + if _, ok := s.buckets[id]; !ok { + continue + } + if v, ok := s.buckets[id].Load(key); ok { + values[id] = v + } + } + return values +} + +// UpNodesItems returns a map of items with the same BucketKey from all nodes that are up. +func (s *Simulation) UpNodesItems(key interface{}) (values map[enode.ID]interface{}) { + s.mu.RLock() + defer s.mu.RUnlock() + + ids := s.UpNodeIDs() + values = make(map[enode.ID]interface{}) + for _, id := range ids { + if _, ok := s.buckets[id]; !ok { + continue + } + if v, ok := s.buckets[id].Load(key); ok { + values[id] = v + } + } + return values +} diff --git a/swarm/network/simulation/bucket_test.go b/swarm/network/simulation/bucket_test.go new file mode 100644 index 0000000000..2273d35a29 --- /dev/null +++ b/swarm/network/simulation/bucket_test.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 simulation + +import ( + "sync" + "testing" + + "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/p2p/simulations/adapters" +) + +// 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. +func TestServiceBucket(t *testing.T) { + testKey := "Key" + testValue := "Value" + + sim := New(map[string]ServiceFunc{ + "noop": func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) { + b.Store(testKey, testValue+ctx.Config.ID.String()) + return newNoopService(), nil, nil + }, + }) + defer sim.Close() + + id1, err := sim.AddNode() + if err != nil { + t.Fatal(err) + } + + id2, err := sim.AddNode() + if err != nil { + t.Fatal(err) + } + + t.Run("ServiceFunc bucket Store", func(t *testing.T) { + v, ok := sim.NodeItem(id1, testKey) + if !ok { + t.Fatal("bucket item not found") + } + s, ok := v.(string) + if !ok { + t.Fatal("bucket item value is not string") + } + if s != testValue+id1.String() { + t.Fatalf("expected %q, got %q", testValue+id1.String(), s) + } + + v, ok = sim.NodeItem(id2, testKey) + if !ok { + t.Fatal("bucket item not found") + } + s, ok = v.(string) + if !ok { + t.Fatal("bucket item value is not string") + } + if s != testValue+id2.String() { + t.Fatalf("expected %q, got %q", testValue+id2.String(), s) + } + }) + + customKey := "anotherKey" + customValue := "anotherValue" + + t.Run("SetNodeItem", func(t *testing.T) { + sim.SetNodeItem(id1, customKey, customValue) + + v, ok := sim.NodeItem(id1, customKey) + if !ok { + t.Fatal("bucket item not found") + } + s, ok := v.(string) + if !ok { + t.Fatal("bucket item value is not string") + } + if s != customValue { + t.Fatalf("expected %q, got %q", customValue, s) + } + + _, ok = sim.NodeItem(id2, customKey) + if ok { + t.Fatal("bucket item should not be found") + } + }) + + if err := sim.StopNode(id2); err != nil { + t.Fatal(err) + } + + t.Run("UpNodesItems", func(t *testing.T) { + items := sim.UpNodesItems(testKey) + + v, ok := items[id1] + if !ok { + t.Errorf("node 1 item not found") + } + s, ok := v.(string) + if !ok { + t.Fatal("node 1 item value is not string") + } + if s != testValue+id1.String() { + t.Fatalf("expected %q, got %q", testValue+id1.String(), s) + } + + _, ok = items[id2] + if ok { + t.Errorf("node 2 item should not be found") + } + }) + + t.Run("NodeItems", func(t *testing.T) { + items := sim.NodesItems(testKey) + + v, ok := items[id1] + if !ok { + t.Errorf("node 1 item not found") + } + s, ok := v.(string) + if !ok { + t.Fatal("node 1 item value is not string") + } + if s != testValue+id1.String() { + t.Fatalf("expected %q, got %q", testValue+id1.String(), s) + } + + v, ok = items[id2] + if !ok { + t.Errorf("node 2 item not found") + } + s, ok = v.(string) + if !ok { + t.Fatal("node 1 item value is not string") + } + if s != testValue+id2.String() { + t.Fatalf("expected %q, got %q", testValue+id2.String(), s) + } + }) +} diff --git a/swarm/network/simulation/events.go b/swarm/network/simulation/events.go new file mode 100644 index 0000000000..d73c3af4ee --- /dev/null +++ b/swarm/network/simulation/events.go @@ -0,0 +1,217 @@ +// 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 ( + "context" + "sync" + + "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 *simulations.Event + // Error is the error that may have happened during event watching. + Error error +} + +// PeerEventsFilter defines a filter on PeerEvents to exclude messages with +// defined properties. Use PeerEventsFilter methods to set required options. +type PeerEventsFilter struct { + eventType simulations.EventType + + connUp *bool + + msgReceive *bool + protocol *string + msgCode *uint64 +} + +// NewPeerEventsFilter returns a new PeerEventsFilter instance. +func NewPeerEventsFilter() *PeerEventsFilter { + return &PeerEventsFilter{} +} + +// 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 +} + +// PeerEvents returns a channel of events that are captured by admin peerEvents +// subscription nodes with provided NodeIDs. Additional filters can be set to ignore +// events that are not relevant. +func (s *Simulation) PeerEvents(ctx context.Context, ids []enode.ID, filters ...*PeerEventsFilter) <-chan PeerEvent { + eventC := make(chan PeerEvent) + + // wait group to make sure all subscriptions to admin peerEvents are established + // before this function returns. + var subsWG sync.WaitGroup + for _, id := range ids { + s.shutdownWG.Add(1) + subsWG.Add(1) + go func(id enode.ID) { + defer s.shutdownWG.Done() + + events := make(chan *simulations.Event) + sub := s.Net.Events().Subscribe(events) + defer sub.Unsubscribe() + + subsWG.Done() + + for { + select { + case <-ctx.Done(): + if err := ctx.Err(); err != nil { + select { + case eventC <- PeerEvent{NodeID: id, Error: err}: + case <-s.Done(): + } + } + return + 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.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.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 + } + } + 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 + } + } + if match { + select { + case eventC <- PeerEvent{NodeID: id, PeerID: peerID, Event: e}: + case <-ctx.Done(): + if err := ctx.Err(); err != nil { + select { + case eventC <- PeerEvent{NodeID: id, PeerID: peerID, Error: err}: + case <-s.Done(): + } + } + return + case <-s.Done(): + return + } + } + case err := <-sub.Err(): + if err != nil { + select { + case eventC <- PeerEvent{NodeID: id, Error: err}: + case <-ctx.Done(): + if err := ctx.Err(); err != nil { + select { + case eventC <- PeerEvent{NodeID: id, Error: err}: + case <-s.Done(): + } + } + return + case <-s.Done(): + return + } + } + } + } + }(id) + } + + // wait all subscriptions + subsWG.Wait() + return eventC +} diff --git a/swarm/network/simulation/events_test.go b/swarm/network/simulation/events_test.go new file mode 100644 index 0000000000..529844816f --- /dev/null +++ b/swarm/network/simulation/events_test.go @@ -0,0 +1,107 @@ +// 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 ( + "context" + "sync" + "testing" + "time" +) + +// TestPeerEvents creates simulation, adds two nodes, +// register for peer events, connects nodes in a chain +// and waits for the number of connection events to +// be received. +func TestPeerEvents(t *testing.T) { + sim := New(noopServiceFuncMap) + defer sim.Close() + + _, err := sim.AddNodes(2) + if err != nil { + t.Fatal(err) + } + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + events := sim.PeerEvents(ctx, sim.NodeIDs()) + + // two nodes -> two connection events + expectedEventCount := 2 + + var wg sync.WaitGroup + wg.Add(expectedEventCount) + + go func() { + for e := range events { + if e.Error != nil { + if e.Error == context.Canceled { + return + } + t.Error(e.Error) + continue + } + wg.Done() + } + }() + + err = sim.Net.ConnectNodesChain(sim.NodeIDs()) + if err != nil { + t.Fatal(err) + } + + wg.Wait() +} + +func TestPeerEventsTimeout(t *testing.T) { + sim := New(noopServiceFuncMap) + defer sim.Close() + + _, err := sim.AddNodes(2) + if err != nil { + t.Fatal(err) + } + + ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) + defer cancel() + 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 { + return + } + if e.Error == context.DeadlineExceeded { + close(done) + return + } else { + errC <- e.Error + } + } + }() + + select { + case <-time.After(time.Second): + t.Fatal("no context deadline received") + case err := <-errC: + t.Fatal(err) + case <-done: + // all good, context deadline detected + } +} diff --git a/swarm/network/simulation/example_test.go b/swarm/network/simulation/example_test.go new file mode 100644 index 0000000000..9d14929795 --- /dev/null +++ b/swarm/network/simulation/example_test.go @@ -0,0 +1,141 @@ +// 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_test + +import ( + "context" + "fmt" + "sync" + "time" + + "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" + "github.com/ethereum/go-ethereum/swarm/network/simulation" +) + +// 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 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()) + hp := network.NewHiveParams() + hp.Discovery = false + config := &network.BzzConfig{ + OverlayAddr: addr.Over(), + UnderlayAddr: addr.Under(), + HiveParams: hp, + } + kad := network.NewKademlia(addr.Over(), network.NewKadParams()) + // store kademlia in node's bucket under BucketKeyKademlia + // so that it can be found by WaitTillHealthy method. + b.Store(simulation.BucketKeyKademlia, kad) + return network.NewBzz(config, kad, nil, nil, nil), nil, nil + }, + }) + defer sim.Close() + + _, err := sim.AddNodesAndConnectRing(10) + if err != nil { + // handle error properly... + panic(err) + } + + ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + defer cancel() + ill, err := sim.WaitTillHealthy(ctx) + if err != nil { + // inspect the latest detected not healthy kademlias + for id, kad := range ill { + fmt.Println("Node", id) + fmt.Println(kad.String()) + } + // handle error... + } + + // continue with the test + +} + +// Watch all peer events in the simulation network, buy receiving from a channel. +func ExampleSimulation_PeerEvents() { + sim := simulation.New(nil) + defer sim.Close() + + events := sim.PeerEvents(context.Background(), sim.NodeIDs()) + + go func() { + for e := range events { + if e.Error != nil { + log.Error("peer event", "err", e.Error) + continue + } + log.Info("peer event", "node", e.NodeID, "peer", e.PeerID, "type", e.Event.Type) + } + }() +} + +// Detect when a nodes drop a peer. +func ExampleSimulation_PeerEvents_disconnections() { + sim := simulation.New(nil) + defer sim.Close() + + disconnections := sim.PeerEvents( + context.Background(), + sim.NodeIDs(), + simulation.NewPeerEventsFilter().Drop(), + ) + + go func() { + for d := range disconnections { + if d.Error != nil { + log.Error("peer drop", "err", d.Error) + continue + } + log.Warn("peer drop", "node", d.NodeID, "peer", d.PeerID) + } + }() +} + +// Watch multiple types of events or messages. In this case, they differ only +// by MsgCode, but filters can be set for different types or protocols, too. +func ExampleSimulation_PeerEvents_multipleFilters() { + sim := simulation.New(nil) + defer sim.Close() + + msgs := sim.PeerEvents( + context.Background(), + sim.NodeIDs(), + // Watch when bzz messages 1 and 4 are received. + simulation.NewPeerEventsFilter().ReceivedMessages().Protocol("bzz").MsgCode(1), + simulation.NewPeerEventsFilter().ReceivedMessages().Protocol("bzz").MsgCode(4), + ) + + go func() { + for m := range msgs { + if m.Error != nil { + log.Error("bzz message", "err", m.Error) + continue + } + log.Info("bzz message", "node", m.NodeID, "peer", m.PeerID) + } + }() +} diff --git a/swarm/network/simulation/http.go b/swarm/network/simulation/http.go new file mode 100644 index 0000000000..69ae3baec2 --- /dev/null +++ b/swarm/network/simulation/http.go @@ -0,0 +1,68 @@ +// 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 ( + "fmt" + "net/http" + + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/p2p/simulations" +) + +// Package defaults. +var ( + DefaultHTTPSimAddr = ":8888" +) + +//WithServer implements the builder pattern constructor for Simulation to +//start with a HTTP server +func (s *Simulation) WithServer(addr string) *Simulation { + //assign default addr if nothing provided + if addr == "" { + addr = DefaultHTTPSimAddr + } + log.Info(fmt.Sprintf("Initializing simulation server on %s...", addr)) + //initialize the HTTP server + s.handler = simulations.NewServer(s.Net) + s.runC = make(chan struct{}) + //add swarm specific routes to the HTTP server + s.addSimulationRoutes() + s.httpSrv = &http.Server{ + Addr: addr, + Handler: s.handler, + } + go func() { + err := s.httpSrv.ListenAndServe() + if err != nil { + log.Error("Error starting the HTTP server", "error", err) + } + }() + return s +} + +//register additional HTTP routes +func (s *Simulation) addSimulationRoutes() { + s.handler.POST("/runsim", s.RunSimulation) +} + +// RunSimulation is the actual POST endpoint runner +func (s *Simulation) RunSimulation(w http.ResponseWriter, req *http.Request) { + log.Debug("RunSimulation endpoint running") + s.runC <- struct{}{} + w.WriteHeader(http.StatusOK) +} diff --git a/swarm/network/simulation/http_test.go b/swarm/network/simulation/http_test.go new file mode 100644 index 0000000000..dffd03a032 --- /dev/null +++ b/swarm/network/simulation/http_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 simulation + +import ( + "context" + "fmt" + "net/http" + "sync" + "testing" + "time" + + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/p2p/simulations/adapters" +) + +func TestSimulationWithHTTPServer(t *testing.T) { + log.Debug("Init simulation") + + ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) + defer cancel() + + sim := New( + map[string]ServiceFunc{ + "noop": func(_ *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) { + return newNoopService(), nil, nil + }, + }).WithServer(DefaultHTTPSimAddr) + defer sim.Close() + log.Debug("Done.") + + _, err := sim.AddNode() + if err != nil { + t.Fatal(err) + } + + log.Debug("Starting sim round and let it time out...") + //first test that running without sending to the channel will actually + //block the simulation, so let it time out + result := sim.Run(ctx, func(ctx context.Context, sim *Simulation) error { + log.Debug("Just start the sim without any action and wait for the timeout") + //ensure with a Sleep that simulation doesn't terminate before the timeout + time.Sleep(2 * time.Second) + return nil + }) + + if result.Error != nil { + if result.Error.Error() == "context deadline exceeded" { + log.Debug("Expected timeout error received") + } else { + t.Fatal(result.Error) + } + } + + //now run it again and send the expected signal on the waiting channel, + //then close the simulation + log.Debug("Starting sim round and wait for frontend signal...") + //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() + 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 + time.Sleep(2 * time.Second) + return nil + }) + if result.Error != nil { + t.Fatal(result.Error) + } + if err := <-errC; err != nil { + t.Fatal(err) + } + log.Debug("Test terminated successfully") +} + +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 + + 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 { + errC <- fmt.Errorf("Request failed: %v", err) + return + } + log.Debug("Signal sent") + if resp.StatusCode != http.StatusOK { + errC <- fmt.Errorf("err %s", resp.Status) + return + } + errC <- resp.Body.Close() +} diff --git a/swarm/network/simulation/kademlia.go b/swarm/network/simulation/kademlia.go new file mode 100644 index 0000000000..a3419c03f8 --- /dev/null +++ b/swarm/network/simulation/kademlia.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 simulation + +import ( + "context" + "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/swarm/network" +) + +// BucketKeyKademlia is the key to be used for storing the kademlia +// 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. +// 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(s.neighbourhoodSize, addrs) + + // Wait for healthy Kademlia on every node before checking files + ticker := time.NewTicker(200 * time.Millisecond) + defer ticker.Stop() + + ill = make(map[enode.ID]*network.Kademlia) + for { + select { + case <-ctx.Done(): + return ill, ctx.Err() + case <-ticker.C: + for k := range ill { + delete(ill, k) + } + 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.GetHealthInfo(pp) + //print info + log.Debug(k.String()) + 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 + } + } + if len(ill) == 0 { + return nil, nil + } + } + } +} + +// kademlias returns all Kademlia instances that are set +// 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) + if !ok { + continue + } + ks[id] = k + } + return ks +} diff --git a/swarm/network/simulation/kademlia_test.go b/swarm/network/simulation/kademlia_test.go new file mode 100644 index 0000000000..4cfcecd8ef --- /dev/null +++ b/swarm/network/simulation/kademlia_test.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 simulation + +import ( + "context" + "sync" + "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) { + + 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 = discovery + config := &network.BzzConfig{ + OverlayAddr: addr.Over(), + UnderlayAddr: addr.Under(), + HiveParams: hp, + } + kad := network.NewKademlia(addr.Over(), network.NewKadParams()) + // store kademlia in node's bucket under BucketKeyKademlia + // so that it can be found by WaitTillHealthy method. + b.Store(BucketKeyKademlia, kad) + return network.NewBzz(config, kad, nil, nil, nil), nil, nil + }, + } +} diff --git a/swarm/network/simulation/node.go b/swarm/network/simulation/node.go new file mode 100644 index 0000000000..4c3834de30 --- /dev/null +++ b/swarm/network/simulation/node.go @@ -0,0 +1,309 @@ +// 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 ( + "encoding/json" + "errors" + "io/ioutil" + "math/rand" + "os" + "time" + + "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/p2p/simulations/adapters" +) + +// NodeIDs returns NodeIDs for all nodes in the network. +func (s *Simulation) NodeIDs() (ids []enode.ID) { + nodes := s.Net.GetNodes() + ids = make([]enode.ID, len(nodes)) + for i, node := range nodes { + ids[i] = node.ID() + } + return ids +} + +// UpNodeIDs returns NodeIDs for nodes that are up in the network. +func (s *Simulation) UpNodeIDs() (ids []enode.ID) { + nodes := s.Net.GetNodes() + for _, node := range nodes { + if node.Up() { + ids = append(ids, node.ID()) + } + } + return ids +} + +// DownNodeIDs returns NodeIDs for nodes that are stopped in the network. +func (s *Simulation) DownNodeIDs() (ids []enode.ID) { + nodes := s.Net.GetNodes() + for _, node := range nodes { + if !node.Up() { + ids = append(ids, node.ID()) + } + } + return ids +} + +// AddNodeOption defines the option that can be passed +// to Simulation.AddNode method. +type AddNodeOption func(*adapters.NodeConfig) + +// AddNodeWithMsgEvents sets the EnableMsgEvents option +// to NodeConfig. +func AddNodeWithMsgEvents(enable bool) AddNodeOption { + return func(o *adapters.NodeConfig) { + o.EnableMsgEvents = enable + } +} + +// AddNodeWithService specifies a service that should be +// started on a node. This option can be repeated as variadic +// argument toe AddNode and other add node related methods. +// If AddNodeWithService is not specified, all services will be started. +func AddNodeWithService(serviceName string) AddNodeOption { + return func(o *adapters.NodeConfig) { + o.Services = append(o.Services, serviceName) + } +} + +// AddNode creates a new node with random configuration, +// applies provided options to the config and adds the node to network. +// By default all services will be started on a node. If one or more +// AddNodeWithService option are provided, only specified services will be started. +func (s *Simulation) AddNode(opts ...AddNodeOption) (id enode.ID, err error) { + conf := adapters.RandomNodeConfig() + for _, o := range opts { + o(conf) + } + if len(conf.Services) == 0 { + conf.Services = s.serviceNames + } + node, err := s.Net.NewNodeWithConfig(conf) + if err != nil { + return id, err + } + return node.ID(), s.Net.Start(node.ID()) +} + +// AddNodes creates new nodes with random configurations, +// applies provided options to the config and adds nodes to network. +func (s *Simulation) AddNodes(count int, opts ...AddNodeOption) (ids []enode.ID, err error) { + ids = make([]enode.ID, 0, count) + for i := 0; i < count; i++ { + id, err := s.AddNode(opts...) + if err != nil { + return nil, err + } + ids = append(ids, id) + } + return ids, nil +} + +// AddNodesAndConnectFull is a helpper method that combines +// AddNodes and ConnectNodesFull. Only new nodes will be connected. +func (s *Simulation) AddNodesAndConnectFull(count int, opts ...AddNodeOption) (ids []enode.ID, err error) { + if count < 2 { + return nil, errors.New("count of nodes must be at least 2") + } + ids, err = s.AddNodes(count, opts...) + if err != nil { + return nil, err + } + err = s.Net.ConnectNodesFull(ids) + if err != nil { + return nil, err + } + return ids, nil +} + +// AddNodesAndConnectChain is a helpper method that combines +// AddNodes and ConnectNodesChain. The chain will be continued from the last +// added node, if there is one in simulation using ConnectToLastNode method. +func (s *Simulation) AddNodesAndConnectChain(count int, opts ...AddNodeOption) (ids []enode.ID, err error) { + if count < 2 { + return nil, errors.New("count of nodes must be at least 2") + } + id, err := s.AddNode(opts...) + if err != nil { + return nil, err + } + err = s.Net.ConnectToLastNode(id) + if err != nil { + return nil, err + } + ids, err = s.AddNodes(count-1, opts...) + if err != nil { + return nil, err + } + ids = append([]enode.ID{id}, ids...) + err = s.Net.ConnectNodesChain(ids) + if err != nil { + return nil, err + } + return ids, nil +} + +// AddNodesAndConnectRing is a helpper method that combines +// AddNodes and ConnectNodesRing. +func (s *Simulation) AddNodesAndConnectRing(count int, opts ...AddNodeOption) (ids []enode.ID, err error) { + if count < 2 { + return nil, errors.New("count of nodes must be at least 2") + } + ids, err = s.AddNodes(count, opts...) + if err != nil { + return nil, err + } + err = s.Net.ConnectNodesRing(ids) + if err != nil { + return nil, err + } + return ids, nil +} + +// AddNodesAndConnectStar is a helpper method that combines +// AddNodes and ConnectNodesStar. +func (s *Simulation) AddNodesAndConnectStar(count int, opts ...AddNodeOption) (ids []enode.ID, err error) { + if count < 2 { + return nil, errors.New("count of nodes must be at least 2") + } + ids, err = s.AddNodes(count, opts...) + if err != nil { + return nil, err + } + 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 { + 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) + } + }() + jsonbyte, err := ioutil.ReadAll(f) + if err != nil { + return err + } + var snap simulations.Snapshot + err = json.Unmarshal(jsonbyte, &snap) + if 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 i := range snap.Nodes { + snap.Nodes[i].Node.Config.EnableMsgEvents = true + snap.Nodes[i].Node.Config.Services = s.serviceNames + for _, o := range opts { + 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 { + return err + } + log.Info("Snapshot loaded") + return nil +} + +// StartNode starts a node by NodeID. +func (s *Simulation) StartNode(id enode.ID) (err error) { + return s.Net.Start(id) +} + +// StartRandomNode starts a random node. +func (s *Simulation) StartRandomNode() (id enode.ID, err error) { + n := s.Net.GetRandomDownNode() + if n == nil { + return id, ErrNodeNotFound + } + 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) + for i := 0; i < count; i++ { + n := s.Net.GetRandomDownNode() + if n == nil { + return nil, ErrNodeNotFound + } + err = s.Net.Start(n.ID()) + if err != nil { + return nil, err + } + ids = append(ids, n.ID()) + } + return ids, nil +} + +// StopNode stops a node by NodeID. +func (s *Simulation) StopNode(id enode.ID) (err error) { + return s.Net.Stop(id) +} + +// StopRandomNode stops a random node. +func (s *Simulation) StopRandomNode() (id enode.ID, err error) { + n := s.Net.GetRandomUpNode() + if n == nil { + return id, ErrNodeNotFound + } + 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) + for i := 0; i < count; i++ { + n := s.Net.GetRandomUpNode() + if n == nil { + return nil, ErrNodeNotFound + } + err = s.Net.Stop(n.ID()) + if err != nil { + return nil, err + } + ids = append(ids, n.ID()) + } + return ids, nil +} + +// seed the random generator for Simulation.randomNode. +func init() { + rand.Seed(time.Now().UnixNano()) +} diff --git a/swarm/network/simulation/node_test.go b/swarm/network/simulation/node_test.go new file mode 100644 index 0000000000..bae5afb260 --- /dev/null +++ b/swarm/network/simulation/node_test.go @@ -0,0 +1,444 @@ +// 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 ( + "context" + "fmt" + "sync" + "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" + "github.com/ethereum/go-ethereum/p2p/simulations/adapters" + "github.com/ethereum/go-ethereum/swarm/network" +) + +func TestUpDownNodeIDs(t *testing.T) { + sim := New(noopServiceFuncMap) + defer sim.Close() + + ids, err := sim.AddNodes(10) + if err != nil { + t.Fatal(err) + } + + gotIDs := sim.NodeIDs() + + if !equalNodeIDs(ids, gotIDs) { + t.Error("returned nodes are not equal to added ones") + } + + stoppedIDs, err := sim.StopRandomNodes(3) + if err != nil { + t.Fatal(err) + } + + gotIDs = sim.UpNodeIDs() + + for _, id := range gotIDs { + if !sim.Net.GetNode(id).Up() { + t.Errorf("node %s should not be down", id) + } + } + + if !equalNodeIDs(ids, append(gotIDs, stoppedIDs...)) { + t.Error("returned nodes are not equal to added ones") + } + + gotIDs = sim.DownNodeIDs() + + for _, id := range gotIDs { + if sim.Net.GetNode(id).Up() { + t.Errorf("node %s should not be up", id) + } + } + + if !equalNodeIDs(stoppedIDs, gotIDs) { + t.Error("returned nodes are not equal to the stopped ones") + } +} + +func equalNodeIDs(one, other []enode.ID) bool { + if len(one) != len(other) { + return false + } + var count int + for _, a := range one { + var found bool + for _, b := range other { + if a == b { + found = true + break + } + } + if found { + count++ + } else { + return false + } + } + return count == len(one) +} + +func TestAddNode(t *testing.T) { + sim := New(noopServiceFuncMap) + defer sim.Close() + + id, err := sim.AddNode() + if err != nil { + t.Fatal(err) + } + + n := sim.Net.GetNode(id) + if n == nil { + t.Fatal("node not found") + } + + if !n.Up() { + t.Error("node not started") + } +} + +func TestAddNodeWithMsgEvents(t *testing.T) { + sim := New(noopServiceFuncMap) + defer sim.Close() + + id, err := sim.AddNode(AddNodeWithMsgEvents(true)) + if err != nil { + t.Fatal(err) + } + + if !sim.Net.GetNode(id).Config.EnableMsgEvents { + t.Error("EnableMsgEvents is false") + } + + id, err = sim.AddNode(AddNodeWithMsgEvents(false)) + if err != nil { + t.Fatal(err) + } + + if sim.Net.GetNode(id).Config.EnableMsgEvents { + t.Error("EnableMsgEvents is true") + } +} + +func TestAddNodeWithService(t *testing.T) { + sim := New(map[string]ServiceFunc{ + "noop1": noopServiceFunc, + "noop2": noopServiceFunc, + }) + defer sim.Close() + + id, err := sim.AddNode(AddNodeWithService("noop1")) + 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 should not be found on node") + } +} + +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() + + nodesCount := 12 + + ids, err := sim.AddNodes(nodesCount) + if err != nil { + t.Fatal(err) + } + + count := len(ids) + if count != nodesCount { + t.Errorf("expected %v nodes, got %v", nodesCount, count) + } + + count = len(sim.Net.GetNodes()) + if count != nodesCount { + t.Errorf("expected %v nodes, got %v", nodesCount, count) + } +} + +func TestAddNodesAndConnectFull(t *testing.T) { + sim := New(noopServiceFuncMap) + defer sim.Close() + + n := 12 + + ids, err := sim.AddNodesAndConnectFull(n) + if err != nil { + t.Fatal(err) + } + + simulations.VerifyFull(t, sim.Net, ids) +} + +func TestAddNodesAndConnectChain(t *testing.T) { + sim := New(noopServiceFuncMap) + defer sim.Close() + + _, err := sim.AddNodesAndConnectChain(12) + if err != nil { + t.Fatal(err) + } + + // add another set of nodes to test + // if two chains are connected + _, err = sim.AddNodesAndConnectChain(7) + if err != nil { + t.Fatal(err) + } + + simulations.VerifyChain(t, sim.Net, sim.UpNodeIDs()) +} + +func TestAddNodesAndConnectRing(t *testing.T) { + sim := New(noopServiceFuncMap) + defer sim.Close() + + ids, err := sim.AddNodesAndConnectRing(12) + if err != nil { + t.Fatal(err) + } + + simulations.VerifyRing(t, sim.Net, ids) +} + +func TestAddNodesAndConnectStar(t *testing.T) { + sim := New(noopServiceFuncMap) + defer sim.Close() + + ids, err := sim.AddNodesAndConnectStar(12) + if err != nil { + t.Fatal(err) + } + + simulations.VerifyStar(t, sim.Net, ids, 0) +} + +//To test that uploading a snapshot works +func TestUploadSnapshot(t *testing.T) { + log.Debug("Creating simulation") + s := New(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 + config := &network.BzzConfig{ + OverlayAddr: addr.Over(), + UnderlayAddr: addr.Under(), + HiveParams: hp, + } + kad := network.NewKademlia(addr.Over(), network.NewKadParams()) + return network.NewBzz(config, kad, nil, nil, nil), nil, nil + }, + }) + defer s.Close() + + nodeCount := 16 + log.Debug("Uploading snapshot") + err := s.UploadSnapshot(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") + nodes := sim.UpNodeIDs() + if len(nodes) != nodeCount { + t.Fatal("Simulation network node number doesn't match snapshot node number") + } + return nil + }) + log.Debug("Done.") +} + +func TestStartStopNode(t *testing.T) { + sim := New(noopServiceFuncMap) + defer sim.Close() + + id, err := sim.AddNode() + if err != nil { + t.Fatal(err) + } + + n := sim.Net.GetNode(id) + if n == nil { + t.Fatal("node not found") + } + if !n.Up() { + t.Error("node not started") + } + + err = sim.StopNode(id) + if err != nil { + t.Fatal(err) + } + if n.Up() { + t.Error("node not stopped") + } + + waitForPeerEventPropagation() + + err = sim.StartNode(id) + if err != nil { + t.Fatal(err) + } + if !n.Up() { + t.Error("node not started") + } +} + +func TestStartStopRandomNode(t *testing.T) { + sim := New(noopServiceFuncMap) + defer sim.Close() + + _, err := sim.AddNodes(3) + if err != nil { + t.Fatal(err) + } + + id, err := sim.StopRandomNode() + if err != nil { + t.Fatal(err) + } + + n := sim.Net.GetNode(id) + if n == nil { + t.Fatal("node not found") + } + if n.Up() { + t.Error("node not stopped") + } + + id2, err := sim.StopRandomNode() + if err != nil { + t.Fatal(err) + } + + waitForPeerEventPropagation() + + idStarted, err := sim.StartRandomNode() + if err != nil { + t.Fatal(err) + } + + if idStarted != id && idStarted != id2 { + t.Error("unexpected started node ID") + } +} + +func TestStartStopRandomNodes(t *testing.T) { + sim := New(noopServiceFuncMap) + defer sim.Close() + + _, err := sim.AddNodes(10) + if err != nil { + t.Fatal(err) + } + + ids, err := sim.StopRandomNodes(3) + if err != nil { + t.Fatal(err) + } + + for _, id := range ids { + n := sim.Net.GetNode(id) + if n == nil { + t.Fatal("node not found") + } + if n.Up() { + t.Error("node not stopped") + } + } + + waitForPeerEventPropagation() + + ids, err = sim.StartRandomNodes(2) + if err != nil { + t.Fatal(err) + } + + for _, id := range ids { + n := sim.Net.GetNode(id) + if n == nil { + t.Fatal("node not found") + } + 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/swarm/network/simulation/service.go b/swarm/network/simulation/service.go new file mode 100644 index 0000000000..0ac8149a94 --- /dev/null +++ b/swarm/network/simulation/service.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 simulation + +import ( + "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/simulations/adapters" +) + +// Service returns a single Service by name on a particular node +// with provided id. +func (s *Simulation) Service(name string, id enode.ID) node.Service { + simNode, ok := s.Net.GetNode(id).Node.(*adapters.SimNode) + if !ok { + return nil + } + services := simNode.ServiceMap() + if len(services) == 0 { + return nil + } + return services[name] +} + +// 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.Net.GetRandomUpNode().Node.(*adapters.SimNode) + if n == nil { + return nil + } + return n.Service(name) +} + +// Services returns all services with a provided name +// from nodes that are up. +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() { + continue + } + simNode, ok := node.Node.(*adapters.SimNode) + if !ok { + continue + } + services[node.ID()] = simNode.Service(name) + } + return services +} diff --git a/rpc/utils_test.go b/swarm/network/simulation/service_test.go similarity index 57% rename from rpc/utils_test.go rename to swarm/network/simulation/service_test.go index e0e063f607..23b0d86f24 100644 --- a/rpc/utils_test.go +++ b/swarm/network/simulation/service_test.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,30 +14,33 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package rpc +package simulation 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) - } +func TestService(t *testing.T) { + sim := New(noopServiceFuncMap) + defer sim.Close() - 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)) - } + id, err := sim.AddNode() + if err != nil { + t.Fatal(err) + } - 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]) - } - } + _, ok := sim.Service("noop", id).(*noopService) + if !ok { + t.Fatalf("service is not of %T type", &noopService{}) + } + + _, ok = sim.RandomService("noop").(*noopService) + if !ok { + t.Fatalf("service is not of %T type", &noopService{}) + } + + _, ok = sim.Services("noop")[id].(*noopService) + if !ok { + t.Fatalf("service is not of %T type", &noopService{}) } } diff --git a/swarm/network/simulation/simulation.go b/swarm/network/simulation/simulation.go new file mode 100644 index 0000000000..e18d19a67c --- /dev/null +++ b/swarm/network/simulation/simulation.go @@ -0,0 +1,215 @@ +// 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 ( + "context" + "errors" + "net/http" + "sync" + "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" + "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") +) + +// Simulation provides methods on network, nodes and services +// to manage them. +type Simulation struct { + // Net is exposed as a way to access lower level functionalities + // of p2p/simulations.Network. + Net *simulations.Network + + 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 + runC chan struct{} //channel where frontend signals it is ready +} + +// ServiceFunc is used in New to declare new service constructor. +// The first argument provides ServiceContext from the adapters package +// giving for example the access to NodeID. Second argument is the sync.Map +// where all "global" state related to the service should be kept. +// All cleanups needed for constructed service and any other constructed +// objects should ne provided in a single returned cleanup function. +// Returned cleanup function will be called by Close function +// 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 +// 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{}), + 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) + 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) + } + s.buckets[ctx.Config.ID] = b + return service, nil + } + } + + s.Net = simulations.NewNetwork( + adapters.NewTCPAdapter(adapterServices), + &simulations.NetworkConfig{ID: "0"}, + ) + + return s +} + +// RunFunc is the function that will be called +// on Simulation.Run method call. +type RunFunc func(context.Context, *Simulation) error + +// Result is the returned value of Simulation.Run method. +type Result struct { + Duration time.Duration + Error error +} + +// Run calls the RunFunc function while taking care of +// cancellation provided through the Context. +func (s *Simulation) Run(ctx context.Context, f RunFunc) (r Result) { + //if the option is set to run a HTTP server with the simulation, + //init the server and start it + start := time.Now() + if s.httpSrv != nil { + log.Info("Waiting for frontend to be ready...(send POST /runsim to HTTP server)") + //wait for the frontend to connect + select { + case <-s.runC: + case <-ctx.Done(): + return Result{ + Duration: time.Since(start), + Error: ctx.Err(), + } + } + log.Info("Received signal from frontend - starting simulation run.") + } + errc := make(chan error) + quit := make(chan struct{}) + defer close(quit) + go func() { + select { + case errc <- f(ctx, s): + case <-quit: + } + }() + var err error + select { + case <-ctx.Done(): + err = ctx.Err() + case err = <-errc: + } + return Result{ + Duration: time.Since(start), + Error: err, + } +} + +// Maximal number of parallel calls to cleanup functions on +// Simulation.Close. +var maxParallelCleanups = 10 + +// Close calls all cleanup functions that are returned by +// ServiceFunc, waits for all of them to finish and other +// functions that explicitly block shutdownWG +// (like Simulation.PeerEvents) and shuts down the network +// at the end. It is used to clean all resources from the +// simulation. +func (s *Simulation) Close() { + close(s.done) + + sem := make(chan struct{}, maxParallelCleanups) + s.mu.RLock() + cleanupFuncs := make([]func(), len(s.cleanupFuncs)) + for i, f := range s.cleanupFuncs { + if f != nil { + cleanupFuncs[i] = f + } + } + s.mu.RUnlock() + var cleanupWG sync.WaitGroup + for _, cleanup := range cleanupFuncs { + cleanupWG.Add(1) + sem <- struct{}{} + go func(cleanup func()) { + defer cleanupWG.Done() + defer func() { <-sem }() + + cleanup() + }(cleanup) + } + cleanupWG.Wait() + + if s.httpSrv != nil { + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + defer cancel() + err := s.httpSrv.Shutdown(ctx) + if err != nil { + log.Error("Error shutting down HTTP server!", "err", err) + } + close(s.runC) + } + + s.shutdownWG.Wait() + s.Net.Shutdown() +} + +// Done returns a channel that is closed when the simulation +// is closed by Close method. It is useful for signaling termination +// of all possible goroutines that are created within the test. +func (s *Simulation) Done() <-chan struct{} { + return s.done +} diff --git a/swarm/network/simulation/simulation_test.go b/swarm/network/simulation/simulation_test.go new file mode 100644 index 0000000000..1d0338f593 --- /dev/null +++ b/swarm/network/simulation/simulation_test.go @@ -0,0 +1,203 @@ +// 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 ( + "context" + "errors" + "flag" + "sync" + "testing" + "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/mattn/go-colorable" +) + +var ( + loglevel = flag.Int("loglevel", 2, "verbosity of logs") +) + +func init() { + flag.Parse() + log.PrintOrigins(true) + log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true)))) +} + +// TestRun tests if Run method calls RunFunc and if it handles context properly. +func TestRun(t *testing.T) { + sim := New(noopServiceFuncMap) + defer sim.Close() + + t.Run("call", func(t *testing.T) { + expect := "something" + var got string + r := sim.Run(context.Background(), func(ctx context.Context, sim *Simulation) error { + got = expect + return nil + }) + + if r.Error != nil { + t.Errorf("unexpected error: %v", r.Error) + } + if got != expect { + t.Errorf("expected %q, got %q", expect, got) + } + }) + + t.Run("cancellation", func(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond) + defer cancel() + + r := sim.Run(ctx, func(ctx context.Context, sim *Simulation) error { + time.Sleep(time.Second) + return nil + }) + + if r.Error != context.DeadlineExceeded { + t.Errorf("unexpected error: %v", r.Error) + } + }) + + t.Run("context value and duration", func(t *testing.T) { + ctx := context.WithValue(context.Background(), "hey", "there") + sleep := 50 * time.Millisecond + + r := sim.Run(ctx, func(ctx context.Context, sim *Simulation) error { + if ctx.Value("hey") != "there" { + return errors.New("expected context value not passed") + } + time.Sleep(sleep) + return nil + }) + + if r.Error != nil { + t.Errorf("unexpected error: %v", r.Error) + } + if r.Duration < sleep { + t.Errorf("reported run duration less then expected: %s", r.Duration) + } + }) +} + +// TestClose tests are Close method triggers all close functions and are all nodes not up anymore. +func TestClose(t *testing.T) { + var mu sync.Mutex + var cleanupCount int + + sleep := 50 * time.Millisecond + + sim := New(map[string]ServiceFunc{ + "noop": func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) { + return newNoopService(), func() { + time.Sleep(sleep) + mu.Lock() + defer mu.Unlock() + cleanupCount++ + }, nil + }, + }) + + nodeCount := 30 + + _, err := sim.AddNodes(nodeCount) + if err != nil { + t.Fatal(err) + } + + var upNodeCount int + for _, n := range sim.Net.GetNodes() { + if n.Up() { + upNodeCount++ + } + } + if upNodeCount != nodeCount { + t.Errorf("all nodes should be up, insted only %v are up", upNodeCount) + } + + sim.Close() + + if cleanupCount != nodeCount { + t.Errorf("number of cleanups expected %v, got %v", nodeCount, cleanupCount) + } + + upNodeCount = 0 + for _, n := range sim.Net.GetNodes() { + if n.Up() { + upNodeCount++ + } + } + if upNodeCount != 0 { + t.Errorf("all nodes should be down, insted %v are up", upNodeCount) + } +} + +// TestDone checks if Close method triggers the closing of done channel. +func TestDone(t *testing.T) { + sim := New(noopServiceFuncMap) + sleep := 50 * time.Millisecond + timeout := 2 * time.Second + + start := time.Now() + go func() { + time.Sleep(sleep) + sim.Close() + }() + + select { + case <-time.After(timeout): + t.Error("done channel closing timed out") + case <-sim.Done(): + if d := time.Since(start); d < sleep { + t.Errorf("done channel closed sooner then expected: %s", d) + } + } +} + +// a helper map for usual services that do not do anything +var noopServiceFuncMap = map[string]ServiceFunc{ + "noop": noopServiceFunc, +} + +// a helper function for most basic noop service +func noopServiceFunc(_ *adapters.ServiceContext, _ *sync.Map) (node.Service, func(), error) { + return newNoopService(), nil, nil +} + +func newNoopService() node.Service { + return &noopService{} +} + +// 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 +} + +// NoopService2 is the service that does not do anything +// but implements node.Service interface. +type noopService2 struct { + simulations.NoopService +} + +type noopService struct { + simulations.NoopService +} diff --git a/core/vm/vm_jit_fake.go b/swarm/network/simulations/discovery/discovery.go similarity index 91% rename from core/vm/vm_jit_fake.go rename to swarm/network/simulations/discovery/discovery.go index 44b60abf6f..a6ff5fd45e 100644 --- a/core/vm/vm_jit_fake.go +++ b/swarm/network/simulations/discovery/discovery.go @@ -1,4 +1,4 @@ -// Copyright 2015 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,6 +14,4 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// +build !evmjit - -package vm +package discovery diff --git a/swarm/network/simulations/discovery/discovery_test.go b/swarm/network/simulations/discovery/discovery_test.go new file mode 100644 index 0000000000..99a0c77224 --- /dev/null +++ b/swarm/network/simulations/discovery/discovery_test.go @@ -0,0 +1,536 @@ +// 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 discovery + +import ( + "context" + "flag" + "fmt" + "io/ioutil" + "os" + "path" + "strings" + "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" + "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" + "github.com/ethereum/go-ethereum/swarm/state" + colorable "github.com/mattn/go-colorable" +) + +// serviceName is used with the exec adapter so the exec'd binary knows which +// service to execute +const serviceName = "discovery" +const testNeighbourhoodSize = 2 +const discoveryPersistenceDatadir = "discovery_persistence_test_store" + +var discoveryPersistencePath = path.Join(os.TempDir(), discoveryPersistenceDatadir) +var discoveryEnabled = true +var persistenceEnabled = false + +var services = adapters.Services{ + serviceName: newService, +} + +func cleanDbStores() error { + entries, err := ioutil.ReadDir(os.TempDir()) + if err != nil { + return err + } + + for _, f := range entries { + if strings.HasPrefix(f.Name(), discoveryPersistenceDatadir) { + os.RemoveAll(path.Join(os.TempDir(), f.Name())) + } + } + return nil + +} + +func getDbStore(nodeID string) (*state.DBStore, error) { + if _, err := os.Stat(discoveryPersistencePath + "_" + nodeID); os.IsNotExist(err) { + log.Info(fmt.Sprintf("directory for nodeID %s does not exist. creating...", nodeID)) + ioutil.TempDir("", discoveryPersistencePath+"_"+nodeID) + } + log.Info(fmt.Sprintf("opening storage directory for nodeID %s", nodeID)) + store, err := state.NewDBStore(discoveryPersistencePath + "_" + nodeID) + if err != nil { + return nil, err + } + return store, nil +} + +var ( + 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 + // 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(!*rawlog)))) +} + +// Benchmarks to test the average time it takes for an N-node ring +// to full a healthy kademlia topology +func BenchmarkDiscovery_8_1(b *testing.B) { benchmarkDiscovery(b, 8, 1) } +func BenchmarkDiscovery_16_1(b *testing.B) { benchmarkDiscovery(b, 16, 1) } +func BenchmarkDiscovery_32_1(b *testing.B) { benchmarkDiscovery(b, 32, 1) } +func BenchmarkDiscovery_64_1(b *testing.B) { benchmarkDiscovery(b, 64, 1) } +func BenchmarkDiscovery_128_1(b *testing.B) { benchmarkDiscovery(b, 128, 1) } +func BenchmarkDiscovery_256_1(b *testing.B) { benchmarkDiscovery(b, 256, 1) } + +func BenchmarkDiscovery_8_2(b *testing.B) { benchmarkDiscovery(b, 8, 2) } +func BenchmarkDiscovery_16_2(b *testing.B) { benchmarkDiscovery(b, 16, 2) } +func BenchmarkDiscovery_32_2(b *testing.B) { benchmarkDiscovery(b, 32, 2) } +func BenchmarkDiscovery_64_2(b *testing.B) { benchmarkDiscovery(b, 64, 2) } +func BenchmarkDiscovery_128_2(b *testing.B) { benchmarkDiscovery(b, 128, 2) } +func BenchmarkDiscovery_256_2(b *testing.B) { benchmarkDiscovery(b, 256, 2) } + +func BenchmarkDiscovery_8_4(b *testing.B) { benchmarkDiscovery(b, 8, 4) } +func BenchmarkDiscovery_16_4(b *testing.B) { benchmarkDiscovery(b, 16, 4) } +func BenchmarkDiscovery_32_4(b *testing.B) { benchmarkDiscovery(b, 32, 4) } +func BenchmarkDiscovery_64_4(b *testing.B) { benchmarkDiscovery(b, 64, 4) } +func BenchmarkDiscovery_128_4(b *testing.B) { benchmarkDiscovery(b, 128, 4) } +func BenchmarkDiscovery_256_4(b *testing.B) { benchmarkDiscovery(b, 256, 4) } + +func TestDiscoverySimulationExecAdapter(t *testing.T) { + testDiscoverySimulationExecAdapter(t, *nodeCount, *initCount) +} + +func testDiscoverySimulationExecAdapter(t *testing.T, nodes, conns int) { + baseDir, err := ioutil.TempDir("", "swarm-test") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(baseDir) + testDiscoverySimulation(t, nodes, conns, adapters.NewExecAdapter(baseDir)) +} + +func TestDiscoverySimulationSimAdapter(t *testing.T) { + testDiscoverySimulationSimAdapter(t, *nodeCount, *initCount) +} + +func TestDiscoveryPersistenceSimulationSimAdapter(t *testing.T) { + testDiscoveryPersistenceSimulationSimAdapter(t, *nodeCount, *initCount) +} + +func testDiscoveryPersistenceSimulationSimAdapter(t *testing.T, nodes, conns int) { + testDiscoveryPersistenceSimulation(t, nodes, conns, adapters.NewSimAdapter(services)) +} + +func testDiscoverySimulationSimAdapter(t *testing.T, nodes, conns int) { + testDiscoverySimulation(t, nodes, conns, adapters.NewSimAdapter(services)) +} + +func testDiscoverySimulation(t *testing.T, nodes, conns int, adapter adapters.NodeAdapter) { + startedAt := time.Now() + result, err := discoverySimulation(nodes, conns, adapter) + if err != nil { + t.Fatalf("Setting up simulation failed: %v", err) + } + if result.Error != nil { + t.Fatalf("Simulation failed: %s", result.Error) + } + t.Logf("Simulation with %d nodes passed in %s", nodes, result.FinishedAt.Sub(result.StartedAt)) + var min, max time.Duration + var sum int + for _, pass := range result.Passes { + duration := pass.Sub(result.StartedAt) + if sum == 0 || duration < min { + min = duration + } + if duration > max { + max = duration + } + sum += int(duration.Nanoseconds()) + } + t.Logf("Min: %s, Max: %s, Average: %s", min, max, time.Duration(sum/len(result.Passes))*time.Nanosecond) + finishedAt := time.Now() + t.Logf("Setup: %s, shutdown: %s", result.StartedAt.Sub(startedAt), finishedAt.Sub(result.FinishedAt)) +} + +func testDiscoveryPersistenceSimulation(t *testing.T, nodes, conns int, adapter adapters.NodeAdapter) map[int][]byte { + persistenceEnabled = true + discoveryEnabled = true + + result, err := discoveryPersistenceSimulation(nodes, conns, adapter) + + if err != nil { + t.Fatalf("Setting up simulation failed: %v", err) + } + if result.Error != nil { + t.Fatalf("Simulation failed: %s", result.Error) + } + t.Logf("Simulation with %d nodes passed in %s", nodes, result.FinishedAt.Sub(result.StartedAt)) + // set the discovery and persistence flags again to default so other + // tests will not be affected + discoveryEnabled = true + persistenceEnabled = false + return nil +} + +func benchmarkDiscovery(b *testing.B, nodes, conns int) { + for i := 0; i < b.N; i++ { + result, err := discoverySimulation(nodes, conns, adapters.NewSimAdapter(services)) + if err != nil { + b.Fatalf("setting up simulation failed: %v", err) + } + if result.Error != nil { + b.Logf("simulation failed: %s", result.Error) + } + } +} + +func discoverySimulation(nodes, conns int, adapter adapters.NodeAdapter) (*simulations.StepResult, error) { + // create network + net := simulations.NewNetwork(adapter, &simulations.NetworkConfig{ + ID: "0", + DefaultService: serviceName, + }) + defer net.Shutdown() + trigger := make(chan enode.ID) + ids := make([]enode.ID, nodes) + for i := 0; i < nodes; i++ { + conf := adapters.RandomNodeConfig() + node, err := net.NewNodeWithConfig(conf) + if err != nil { + return nil, fmt.Errorf("error starting node: %s", err) + } + if err := net.Start(node.ID()); err != nil { + return nil, fmt.Errorf("error starting node %s: %s", node.ID().TerminalString(), err) + } + if err := triggerChecks(trigger, net, node.ID()); err != nil { + return nil, fmt.Errorf("error triggering checks for node %s: %s", node.ID().TerminalString(), err) + } + ids[i] = node.ID() + } + + // run a simulation which connects the 10 nodes in a ring and waits + // for full peer discovery + var addrs [][]byte + action := func(ctx context.Context) error { + return nil + } + for i := range ids { + // collect the overlay addresses, to + addrs = append(addrs, ids[i].Bytes()) + } + 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(network.NewKadParams().NeighbourhoodSize, addrs) + check := func(ctx context.Context, id enode.ID) (bool, error) { + select { + case <-ctx.Done(): + return false, ctx.Err() + default: + } + + node := net.GetNode(id) + if node == nil { + return false, fmt.Errorf("unknown node: %s", id) + } + client, err := node.Client() + if err != nil { + return false, fmt.Errorf("error getting node client: %s", err) + } + + healthy := &network.Health{} + 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: 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 + // 128 nodes ~ + timeout := 300 * time.Second + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + result := simulations.NewSimulation(net).Run(ctx, &simulations.Step{ + Action: action, + Trigger: trigger, + Expect: &simulations.Expectation{ + Nodes: ids, + Check: check, + }, + }) + if result.Error != nil { + return result, nil + } + return result, nil +} + +func discoveryPersistenceSimulation(nodes, conns int, adapter adapters.NodeAdapter) (*simulations.StepResult, error) { + cleanDbStores() + defer cleanDbStores() + + // create network + net := simulations.NewNetwork(adapter, &simulations.NetworkConfig{ + ID: "0", + DefaultService: serviceName, + }) + defer net.Shutdown() + trigger := make(chan enode.ID) + ids := make([]enode.ID, nodes) + var addrs [][]byte + + for i := 0; i < nodes; i++ { + conf := adapters.RandomNodeConfig() + node, err := net.NewNodeWithConfig(conf) + if err != nil { + panic(err) + } + if err != nil { + return nil, fmt.Errorf("error starting node: %s", err) + } + if err := net.Start(node.ID()); err != nil { + return nil, fmt.Errorf("error starting node %s: %s", node.ID().TerminalString(), err) + } + 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() + + addrs = append(addrs, a) + } + + // run a simulation which connects the 10 nodes in a ring and waits + // for full peer discovery + + var restartTime time.Time + + action := func(ctx context.Context) error { + ticker := time.NewTicker(500 * time.Millisecond) + + for range ticker.C { + isHealthy := true + for _, id := range ids { + //call Healthy RPC + node := net.GetNode(id) + if node == nil { + return fmt.Errorf("unknown node: %s", id) + } + client, err := node.Client() + if err != nil { + return fmt.Errorf("error getting node client: %s", err) + } + healthy := &network.Health{} + addr := id.String() + 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.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 + } + } + if isHealthy { + break + } + } + ticker.Stop() + + log.Info("reached healthy kademlia. starting to shutdown nodes.") + shutdownStarted := time.Now() + // stop all ids, then start them again + for _, id := range ids { + node := net.GetNode(id) + + if err := net.Stop(node.ID()); err != nil { + return fmt.Errorf("error stopping node %s: %s", node.ID().TerminalString(), err) + } + } + log.Info(fmt.Sprintf("shutting down nodes took: %s", time.Since(shutdownStarted))) + persistenceEnabled = true + discoveryEnabled = false + restartTime = time.Now() + for _, id := range ids { + node := net.GetNode(id) + if err := net.Start(node.ID()); err != nil { + return fmt.Errorf("error starting node %s: %s", node.ID().TerminalString(), err) + } + if err := triggerChecks(trigger, net, node.ID()); err != nil { + return fmt.Errorf("error triggering checks for node %s: %s", node.ID().TerminalString(), err) + } + } + + log.Info(fmt.Sprintf("restarting nodes took: %s", time.Since(restartTime))) + + return nil + } + 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) { + select { + case <-ctx.Done(): + return false, ctx.Err() + default: + } + + node := net.GetNode(id) + if node == nil { + return false, fmt.Errorf("unknown node: %s", id) + } + client, err := node.Client() + if err != nil { + return false, fmt.Errorf("error getting node client: %s", err) + } + healthy := &network.Health{} + 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", id, healthy.ConnectNN, healthy.KnowNN)) + + return healthy.KnowNN && healthy.ConnectNN, nil + } + + // 64 nodes ~ 1min + // 128 nodes ~ + timeout := 300 * time.Second + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + result := simulations.NewSimulation(net).Run(ctx, &simulations.Step{ + Action: action, + Trigger: trigger, + Expect: &simulations.Expectation{ + Nodes: ids, + Check: check, + }, + }) + if result.Error != nil { + return result, nil + } + + return result, nil +} + +// triggerChecks triggers a simulation step check whenever a peer is added or +// removed from the given node, and also every second to avoid a race between +// peer events and kademlia becoming healthy +func triggerChecks(trigger chan enode.ID, net *simulations.Network, id enode.ID) error { + node := net.GetNode(id) + if node == nil { + return fmt.Errorf("unknown node: %s", id) + } + client, err := node.Client() + if err != nil { + return err + } + events := make(chan *p2p.PeerEvent) + sub, err := client.Subscribe(context.Background(), "admin", events, "peerEvents") + if err != nil { + return fmt.Errorf("error getting peer events for node %v: %s", id, err) + } + go func() { + defer sub.Unsubscribe() + + tick := time.NewTicker(time.Second) + defer tick.Stop() + + for { + select { + case <-events: + trigger <- id + case <-tick.C: + trigger <- id + case err := <-sub.Err(): + if err != nil { + log.Error(fmt.Sprintf("error getting peer events for node %v", id), "err", err) + } + return + } + } + }() + return nil +} + +func newService(ctx *adapters.ServiceContext) (node.Service, error) { + addr := network.NewAddr(ctx.Config.Node()) + + kp := network.NewKadParams() + kp.NeighbourhoodSize = testNeighbourhoodSize + + if ctx.Config.Reachable != nil { + kp.Reachable = func(o *network.BzzAddr) bool { + return ctx.Config.Reachable(o.ID()) + } + } + kad := network.NewKademlia(addr.Over(), kp) + hp := network.NewHiveParams() + hp.KeepAliveInterval = time.Duration(200) * time.Millisecond + hp.Discovery = discoveryEnabled + + log.Info(fmt.Sprintf("discovery for nodeID %s is %t", ctx.Config.ID.String(), hp.Discovery)) + + config := &network.BzzConfig{ + OverlayAddr: addr.Over(), + UnderlayAddr: addr.Under(), + HiveParams: hp, + } + + if persistenceEnabled { + log.Info(fmt.Sprintf("persistence enabled for nodeID %s", ctx.Config.ID.String())) + store, err := getDbStore(ctx.Config.ID.String()) + if err != nil { + return nil, err + } + return network.NewBzz(config, kad, store, nil, nil), nil + } + + return network.NewBzz(config, kad, nil, nil, nil), nil +} diff --git a/swarm/network/simulations/discovery/snapshot.json b/swarm/network/simulations/discovery/snapshot.json new file mode 100755 index 0000000000..f7f400eb67 --- /dev/null +++ b/swarm/network/simulations/discovery/snapshot.json @@ -0,0 +1 @@ +{"nodes":[{"node":{"config":null,"up":false}},{"node":{"config":null,"up":false}},{"node":{"config":null,"up":false}},{"node":{"config":null,"up":false}},{"node":{"config":null,"up":false}},{"node":{"config":null,"up":false}},{"node":{"config":null,"up":false}},{"node":{"config":null,"up":false}},{"node":{"config":null,"up":false}},{"node":{"config":null,"up":false}}],"conns":[{"one":"c04a0c47cb0c522ecf28d8841e93721e73f58790b30e92382816a4b453be2988","other":"d9283e5247a18d6564b3581217e9f4d9c93a4359944894c00bb2b22c690faadc","up":true},{"one":"dd99c11abe2abae112d64d902b96fe0c75243ea67eca759a2769058a30cc0e77","other":"c04a0c47cb0c522ecf28d8841e93721e73f58790b30e92382816a4b453be2988","up":true},{"one":"4f5dad2aa4f26ac5a23d4fbcc807296b474eab77761db6594debd60ef4287aed","other":"dd99c11abe2abae112d64d902b96fe0c75243ea67eca759a2769058a30cc0e77","up":true},{"one":"4f47f4e176d1c9f78d9a7e19723689ffe2a0603004a3d4506a2349e55a56fc17","other":"4f5dad2aa4f26ac5a23d4fbcc807296b474eab77761db6594debd60ef4287aed","up":true},{"one":"20b6a1be2cb8f966151682350e029d4f8da8ee92de10a2a1cb1727d110acebfa","other":"4f47f4e176d1c9f78d9a7e19723689ffe2a0603004a3d4506a2349e55a56fc17","up":true},{"one":"50cb92e77710582fa9cbee7a54cf25c95fd27d8d54b13ba5520a50139c309a22","other":"20b6a1be2cb8f966151682350e029d4f8da8ee92de10a2a1cb1727d110acebfa","up":true},{"one":"319dc901f99940f1339c540bc36fbabb10a96d326b13b9d7f53e7496980e2996","other":"50cb92e77710582fa9cbee7a54cf25c95fd27d8d54b13ba5520a50139c309a22","up":true},{"one":"dc285b6436a8bfd4d2e586d478b18d3fe7b705ce0b4fb27a651adcf6d27984f1","other":"319dc901f99940f1339c540bc36fbabb10a96d326b13b9d7f53e7496980e2996","up":true},{"one":"974dbe511377280f945a53a194b4bb397875b10b1ecb119a92425bbb16db68f1","other":"dc285b6436a8bfd4d2e586d478b18d3fe7b705ce0b4fb27a651adcf6d27984f1","up":true},{"one":"d9283e5247a18d6564b3581217e9f4d9c93a4359944894c00bb2b22c690faadc","other":"974dbe511377280f945a53a194b4bb397875b10b1ecb119a92425bbb16db68f1","up":true}]} \ No newline at end of file diff --git a/swarm/network/simulations/overlay.go b/swarm/network/simulations/overlay.go new file mode 100644 index 0000000000..63938809e4 --- /dev/null +++ b/swarm/network/simulations/overlay.go @@ -0,0 +1,144 @@ +// 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 . + +// You can run this simulation using +// +// go run ./swarm/network/simulations/overlay.go +package main + +import ( + "flag" + "fmt" + "net/http" + "runtime" + "sync" + "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" + "github.com/ethereum/go-ethereum/p2p/simulations/adapters" + "github.com/ethereum/go-ethereum/swarm/network" + "github.com/ethereum/go-ethereum/swarm/state" + colorable "github.com/mattn/go-colorable" +) + +var ( + noDiscovery = flag.Bool("no-discovery", false, "disable discovery (useful if you want to load a snapshot)") + vmodule = flag.String("vmodule", "", "log filters for logger via Vmodule") + verbosity = flag.Int("verbosity", 0, "log filters for logger via Vmodule") + httpSimPort = 8888 +) + +func init() { + flag.Parse() + //initialize the logger + //this is a demonstration on how to use Vmodule for filtering logs + //provide -vmodule as param, and comma-separated values, e.g.: + //-vmodule overlay_test.go=4,simulations=3 + //above examples sets overlay_test.go logs to level 4, while packages ending with "simulations" to 3 + if *vmodule != "" { + //only enable the pattern matching handler if the flag has been provided + glogger := log.NewGlogHandler(log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true))) + if *verbosity > 0 { + glogger.Verbosity(log.Lvl(*verbosity)) + } + glogger.Vmodule(*vmodule) + log.Root().SetHandler(glogger) + } +} + +type Simulation struct { + mtx sync.Mutex + stores map[enode.ID]state.Store +} + +func NewSimulation() *Simulation { + return &Simulation{ + stores: make(map[enode.ID]state.Store), + } +} + +func (s *Simulation) NewService(ctx *adapters.ServiceContext) (node.Service, error) { + node := ctx.Config.Node() + s.mtx.Lock() + store, ok := s.stores[node.ID()] + if !ok { + store = state.NewInmemoryStore() + s.stores[node.ID()] = store + } + s.mtx.Unlock() + + addr := network.NewAddr(node) + + kp := network.NewKadParams() + kp.NeighbourhoodSize = 2 + kp.MaxBinSize = 4 + kp.MinBinSize = 1 + kp.MaxRetries = 1000 + kp.RetryExponent = 2 + kp.RetryInterval = 1000000 + kad := network.NewKademlia(addr.Over(), kp) + hp := network.NewHiveParams() + hp.Discovery = !*noDiscovery + hp.KeepAliveInterval = 300 * time.Millisecond + + config := &network.BzzConfig{ + OverlayAddr: addr.Over(), + UnderlayAddr: addr.Under(), + HiveParams: hp, + } + + return network.NewBzz(config, kad, store, nil, nil), nil +} + +//create the simulation network +func newSimulationNetwork() *simulations.Network { + + s := NewSimulation() + services := adapters.Services{ + "overlay": s.NewService, + } + adapter := adapters.NewSimAdapter(services) + simNetwork := simulations.NewNetwork(adapter, &simulations.NetworkConfig{ + DefaultService: "overlay", + }) + return simNetwork +} + +//return a new http server +func newOverlaySim(sim *simulations.Network) *simulations.Server { + return simulations.NewServer(sim) +} + +// var server +func main() { + //cpu optimization + runtime.GOMAXPROCS(runtime.NumCPU()) + //run the sim + runOverlaySim() +} + +func runOverlaySim() { + //create the simulation network + net := newSimulationNetwork() + //create a http server with it + sim := newOverlaySim(net) + log.Info(fmt.Sprintf("starting simulation server on 0.0.0.0:%d...", httpSimPort)) + //start the HTTP server + http.ListenAndServe(fmt.Sprintf(":%d", httpSimPort), sim) +} diff --git a/swarm/network/simulations/overlay_test.go b/swarm/network/simulations/overlay_test.go new file mode 100644 index 0000000000..e024e2b123 --- /dev/null +++ b/swarm/network/simulations/overlay_test.go @@ -0,0 +1,194 @@ +// 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 main + +import ( + "context" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "net/http/httptest" + "net/url" + "testing" + "time" + + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/simulations" + "github.com/ethereum/go-ethereum/swarm/log" +) + +var ( + nodeCount = 10 +) + +//This test is used to test the overlay simulation. +//As the simulation is executed via a main, it is easily missed on changes +//An automated test will prevent that +//The test just connects to the simulations, starts the network, +//starts the mocker, gets the number of nodes, and stops it again. +//It also provides a documentation on the steps needed by frontends +//to use the simulations +func TestOverlaySim(t *testing.T) { + //start the simulation + log.Info("Start simulation backend") + //get the simulation networ; needed to subscribe for up events + net := newSimulationNetwork() + //create the overlay simulation + sim := newOverlaySim(net) + //create a http test server with it + srv := httptest.NewServer(sim) + defer srv.Close() + + log.Debug("Http simulation server started. Start simulation network") + //start the simulation network (initialization of simulation) + resp, err := http.Post(srv.URL+"/start", "application/json", nil) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + t.Fatalf("Expected Status Code %d, got %d", http.StatusOK, resp.StatusCode) + } + + log.Debug("Start mocker") + //start the mocker, needs a node count and an ID + resp, err = http.PostForm(srv.URL+"/mocker/start", + url.Values{ + "node-count": {fmt.Sprintf("%d", nodeCount)}, + "mocker-type": {simulations.GetMockerList()[0]}, + }) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + reason, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + t.Fatalf("Expected Status Code %d, got %d, response body %s", http.StatusOK, resp.StatusCode, string(reason)) + } + + //variables needed to wait for nodes being up + var upCount int + trigger := make(chan enode.ID) + + //wait for all nodes to be up + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + //start watching node up events... + go watchSimEvents(net, ctx, trigger) + + //...and wait until all expected up events (nodeCount) have been received +LOOP: + for { + select { + case <-trigger: + //new node up event received, increase counter + upCount++ + //all expected node up events received + if upCount == nodeCount { + break LOOP + } + case <-ctx.Done(): + t.Fatalf("Timed out waiting for up events") + } + + } + + //at this point we can query the server + log.Info("Get number of nodes") + //get the number of nodes + resp, err = http.Get(srv.URL + "/nodes") + 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) + if err != nil { + t.Fatal(err) + } + + //unmarshal number of nodes from JSON response + var nodesArr []simulations.Node + err = json.Unmarshal(b, &nodesArr) + if err != nil { + t.Fatal(err) + } + + //check if number of nodes received is same as sent + if len(nodesArr) != nodeCount { + t.Fatal(fmt.Errorf("Expected %d number of nodes, got %d", nodeCount, len(nodesArr))) + } + + //need to let it run for a little while, otherwise stopping it immediately can crash due running nodes + //wanting to connect to already stopped nodes + time.Sleep(1 * time.Second) + + log.Info("Stop the network") + //stop the network + resp, err = http.Post(srv.URL+"/stop", "application/json", nil) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + t.Fatalf("err %s", resp.Status) + } + + log.Info("Reset the network") + //reset the network (removes all nodes and connections) + resp, err = http.Post(srv.URL+"/reset", "application/json", nil) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + t.Fatalf("err %s", resp.Status) + } +} + +//watch for events so we know when all nodes are up +func watchSimEvents(net *simulations.Network, ctx context.Context, trigger chan enode.ID) { + events := make(chan *simulations.Event) + sub := net.Events().Subscribe(events) + defer sub.Unsubscribe() + + for { + select { + case ev := <-events: + //only catch node up events + if ev.Type == simulations.EventTypeNode { + if ev.Node.Up() { + log.Debug("got node up event", "event", ev, "node", ev.Node.Config.ID) + select { + case trigger <- ev.Node.Config.ID: + case <-ctx.Done(): + return + } + } + } + case <-ctx.Done(): + return + } + } +} diff --git a/swarm/network/stream/common_test.go b/swarm/network/stream/common_test.go new file mode 100644 index 0000000000..ec29e16e33 --- /dev/null +++ b/swarm/network/stream/common_test.go @@ -0,0 +1,376 @@ +// 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 stream + +import ( + "context" + "errors" + "flag" + "fmt" + "io" + "io/ioutil" + "math/rand" + "os" + "strings" + "sync" + "sync/atomic" + "time" + + "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/state" + "github.com/ethereum/go-ethereum/swarm/storage" + mockmem "github.com/ethereum/go-ethereum/swarm/storage/mock/mem" + "github.com/ethereum/go-ethereum/swarm/testutil" + colorable "github.com/mattn/go-colorable" +) + +var ( + loglevel = flag.Int("loglevel", 2, "verbosity of logs") + nodes = flag.Int("nodes", 0, "number of nodes") + chunks = flag.Int("chunks", 0, "number of chunks") + useMockStore = flag.Bool("mockstore", false, "disabled mock store (default: enabled)") + longrunning = flag.Bool("longrunning", false, "do run long-running tests") + + bucketKeyDB = simulation.BucketKey("db") + bucketKeyStore = simulation.BucketKey("store") + bucketKeyFileStore = simulation.BucketKey("filestore") + bucketKeyNetStore = simulation.BucketKey("netstore") + bucketKeyDelivery = simulation.BucketKey("delivery") + bucketKeyRegistry = simulation.BucketKey("registry") + + chunkSize = 4096 + pof = network.Pof +) + +func init() { + flag.Parse() + rand.Seed(time.Now().UnixNano()) + + log.PrintOrigins(true) + log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true)))) +} + +// 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 { + return nil, nil, nil, nil, err + } + + netStore.NewNetFetcherFunc = network.NewFetcherFactory(delivery.RequestFromPeers, true).New + + return addr, netStore, delivery, cleanup, nil +} + +// 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()) + + // temp datadir + datadir, err := ioutil.TempDir("", "streamer") + if err != nil { + return nil, nil, nil, nil, err + } + removeDataDir := func() { + os.RemoveAll(datadir) + } + + params := storage.NewDefaultLocalStoreParams() + params.Init(datadir) + params.BaseKey = addr.Over() + + localStore, err := storage.NewTestLocalStoreForAddr(params) + if err != nil { + removeDataDir() + return nil, nil, nil, nil, err + } + + netStore, err := storage.NewNetStore(localStore, nil) + if err != nil { + 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, nil) + teardown := func() { + streamer.Close() + removeDataDir() + } + protocolTester := p2ptest.NewProtocolTester(addr.ID(), 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") + } + + return protocolTester, streamer, localStore, teardown, nil +} + +func waitForPeers(streamer *Registry, timeout time.Duration, expectedPeers int) error { + ticker := time.NewTicker(10 * time.Millisecond) + timeoutTimer := time.NewTimer(timeout) + for { + select { + case <-ticker.C: + if streamer.peersCount() >= expectedPeers { + return nil + } + case <-timeoutTimer.C: + return errors.New("timeout") + } + } +} + +type roundRobinStore struct { + index uint32 + stores []storage.ChunkStore +} + +func newRoundRobinStore(stores ...storage.ChunkStore) *roundRobinStore { + return &roundRobinStore{ + stores: stores, + } +} + +// 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") +} + +func (rrs *roundRobinStore) Put(ctx context.Context, chunk storage.Chunk) error { + i := atomic.AddUint32(&rrs.index, 1) + idx := int(i) % len(rrs.stores) + return rrs.stores[idx].Put(ctx, chunk) +} + +func (rrs *roundRobinStore) Close() { + for _, store := range rrs.stores { + store.Close() + } +} + +func readAll(fileStore *storage.FileStore, hash []byte) (int64, error) { + r, _ := fileStore.Retrieve(context.TODO(), hash) + buf := make([]byte, 1024) + var n int + var total int64 + var err error + for (total == 0 || n > 0) && err == nil { + n, err = r.ReadAt(buf, total) + total += int64(n) + } + if err != nil && err != io.EOF { + return total, err + } + return total, nil +} + +func uploadFilesToNodes(sim *simulation.Simulation) ([]storage.Address, []string, error) { + nodes := sim.UpNodeIDs() + nodeCnt := len(nodes) + log.Debug(fmt.Sprintf("Uploading %d files to nodes", nodeCnt)) + //array holding generated files + rfiles := make([]string, nodeCnt) + //array holding the root hashes of the files + rootAddrs := make([]storage.Address, nodeCnt) + + var err error + //for every node, generate a file and upload + for i, id := range nodes { + item, ok := sim.NodeItem(id, bucketKeyFileStore) + if !ok { + return nil, nil, fmt.Errorf("Error accessing localstore") + } + fileStore := item.(*storage.FileStore) + //generate a file + rfiles[i], err = generateRandomFile() + if err != nil { + return nil, nil, err + } + //store it (upload it) on the FileStore + ctx := context.TODO() + rk, wait, err := fileStore.Store(ctx, strings.NewReader(rfiles[i]), int64(len(rfiles[i])), false) + log.Debug("Uploaded random string file to node") + if err != nil { + return nil, nil, err + } + err = wait(ctx) + if err != nil { + return nil, nil, err + } + rootAddrs[i] = rk + } + return rootAddrs, rfiles, nil +} + +//generate a random file (string) +func generateRandomFile() (string, error) { + //generate a random file size between minFileSize and maxFileSize + fileSize := rand.Intn(maxFileSize-minFileSize) + minFileSize + log.Debug(fmt.Sprintf("Generated file with filesize %d kB", fileSize)) + b := testutil.RandomBytes(1, fileSize*1024) + return string(b), nil +} + +//create a local store for the given node +func createTestLocalStorageForID(id enode.ID, addr *network.BzzAddr) (storage.ChunkStore, string, error) { + var datadir string + var err error + datadir, err = ioutil.TempDir("", fmt.Sprintf("syncer-test-%s", id.TerminalString())) + if err != nil { + return nil, "", err + } + var store storage.ChunkStore + params := storage.NewDefaultLocalStoreParams() + params.ChunkDbPath = datadir + params.BaseKey = addr.Over() + store, err = storage.NewTestLocalStoreForAddr(params) + if err != nil { + os.RemoveAll(datadir) + return nil, "", err + } + 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/swarm/network/stream/delivery.go b/swarm/network/stream/delivery.go new file mode 100644 index 0000000000..02c5f222c5 --- /dev/null +++ b/swarm/network/stream/delivery.go @@ -0,0 +1,291 @@ +// 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 stream + +import ( + "context" + "errors" + "fmt" + + "github.com/ethereum/go-ethereum/metrics" + "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/spancontext" + "github.com/ethereum/go-ethereum/swarm/storage" + "github.com/ethereum/go-ethereum/swarm/tracing" + opentracing "github.com/opentracing/opentracing-go" +) + +const ( + swarmChunkServerStreamName = "RETRIEVE_REQUEST" + deliveryCap = 32 +) + +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) +) + +type Delivery struct { + chunkStore storage.SyncChunkStore + kad *network.Kademlia + getPeer func(enode.ID) *Peer +} + +func NewDelivery(kad *network.Kademlia, chunkStore storage.SyncChunkStore) *Delivery { + return &Delivery{ + chunkStore: chunkStore, + kad: kad, + } +} + +// SwarmChunkServer implements Server +type SwarmChunkServer struct { + deliveryC chan []byte + batchC chan []byte + chunkStore storage.ChunkStore + currentLen uint64 + quit chan struct{} +} + +// NewSwarmChunkServer is SwarmChunkServer constructor +func NewSwarmChunkServer(chunkStore storage.ChunkStore) *SwarmChunkServer { + s := &SwarmChunkServer{ + deliveryC: make(chan []byte, deliveryCap), + batchC: make(chan []byte), + chunkStore: chunkStore, + quit: make(chan struct{}), + } + go s.processDeliveries() + return s +} + +// processDeliveries handles delivered chunk hashes +func (s *SwarmChunkServer) processDeliveries() { + var hashes []byte + var batchC chan []byte + for { + select { + case <-s.quit: + return + case hash := <-s.deliveryC: + hashes = append(hashes, hash...) + batchC = s.batchC + case batchC <- hashes: + hashes = nil + batchC = nil + } + } +} + +// SessionIndex returns zero in all cases for SwarmChunkServer. +func (s *SwarmChunkServer) SessionIndex() (uint64, error) { + return 0, nil +} + +// SetNextBatch +func (s *SwarmChunkServer) SetNextBatch(_, _ uint64) (hashes []byte, from uint64, to uint64, proof *HandoverProof, err error) { + select { + case hashes = <-s.batchC: + case <-s.quit: + return + } + + from = s.currentLen + s.currentLen += uint64(len(hashes)) + to = s.currentLen + return +} + +// Close needs to be called on a stream server +func (s *SwarmChunkServer) Close() { + close(s.quit) +} + +// GetData retrives chunk data from db store +func (s *SwarmChunkServer) GetData(ctx context.Context, key []byte) ([]byte, error) { + chunk, err := s.chunkStore.Get(ctx, storage.Address(key)) + if err != nil { + return nil, err + } + return chunk.Data(), nil +} + +// RetrieveRequestMsg is the protocol msg for chunk retrieve requests +type RetrieveRequestMsg struct { + Addr storage.Address + SkipCheck bool + HopCount uint8 +} + +func (d *Delivery) handleRetrieveRequestMsg(ctx context.Context, sp *Peer, req *RetrieveRequestMsg) error { + log.Trace("received request", "peer", sp.ID(), "hash", req.Addr) + handleRetrieveRequestMsgCount.Inc(1) + + var osp opentracing.Span + ctx, osp = spancontext.StartSpan( + ctx, + "stream.handle.retrieve") + + s, err := sp.getServer(NewStream(swarmChunkServerStreamName, "", true)) + if err != nil { + return err + } + streamer := s.Server.(*SwarmChunkServer) + + var cancel func() + // TODO: do something with this hardcoded timeout, maybe use TTL in the future + ctx = context.WithValue(ctx, "peer", sp.ID().String()) + ctx = context.WithValue(ctx, "hopcount", req.HopCount) + ctx, cancel = context.WithTimeout(ctx, network.RequestTimeout) + + go func() { + select { + case <-ctx.Done(): + case <-streamer.quit: + } + cancel() + }() + + go func() { + defer osp.Finish() + chunk, err := d.chunkStore.Get(ctx, req.Addr) + if err != nil { + 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 + err = sp.Deliver(ctx, chunk, s.priority, syncing) + if err != nil { + log.Warn("ERROR in handleRetrieveRequestMsg", "err", err) + } + return + } + select { + case streamer.deliveryC <- chunk.Address()[:]: + case <-streamer.quit: + } + + }() + + return nil +} + +//Chunk delivery always uses the same message type.... +type ChunkDeliveryMsg struct { + Addr storage.Address + SData []byte // the stored chunk Data (incl size) + peer *Peer // set in handleChunkDeliveryMsg +} + +//...but swap accounting needs to disambiguate if it is a delivery for syncing or for retrieval +//as it decides based on message type if it needs to account for this message or not + +//defines a chunk delivery for retrieval (with accounting) +type ChunkDeliveryMsgRetrieval ChunkDeliveryMsg + +//defines a chunk delivery for syncing (without accounting) +type ChunkDeliveryMsgSyncing ChunkDeliveryMsg + +// chunk delivery msg is response to retrieverequest msg +func (d *Delivery) handleChunkDeliveryMsg(ctx context.Context, sp *Peer, req *ChunkDeliveryMsg) error { + + 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) + + go func() { + if span != nil { + defer span.(opentracing.Span).Finish() + } + + req.peer = sp + err := d.chunkStore.Put(ctx, storage.NewChunk(req.Addr, req.SData)) + if err != nil { + if err == storage.ErrChunkInvalid { + // we removed this log because it spams the logs + // TODO: Enable this log line + // log.Warn("invalid chunk delivered", "peer", sp.ID(), "chunk", req.Addr, ) + req.peer.Drop(err) + } + } + }() + return nil +} + +// 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 + spID := req.Source + + if spID != nil { + sp = d.getPeer(*spID) + if sp == nil { + 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) bool { + id := p.ID() + if p.LightNode { + // skip light nodes + return true + } + if req.SkipPeer(id.String()) { + log.Trace("Delivery.RequestFromPeers: skip peer", "peer id", id) + 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 { + return true + } + spID = &id + return false + }) + if sp == nil { + return nil, nil, errors.New("no peer found") + } + } + + // 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)) + err := sp.SendPriority(ctx, &RetrieveRequestMsg{ + Addr: req.Addr, + SkipCheck: req.SkipCheck, + HopCount: req.HopCount, + }, Top) + if err != nil { + return nil, nil, err + } + requestFromPeersEachCount.Inc(1) + + return spID, sp.quit, nil +} diff --git a/swarm/network/stream/delivery_test.go b/swarm/network/stream/delivery_test.go new file mode 100644 index 0000000000..50b7881504 --- /dev/null +++ b/swarm/network/stream/delivery_test.go @@ -0,0 +1,734 @@ +// 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 stream + +import ( + "bytes" + "context" + "errors" + "fmt" + "sync" + "testing" + "time" + + "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/protocols" + "github.com/ethereum/go-ethereum/p2p/simulations/adapters" + p2ptest "github.com/ethereum/go-ethereum/p2p/testing" + "github.com/ethereum/go-ethereum/swarm/log" + "github.com/ethereum/go-ethereum/swarm/network" + pq "github.com/ethereum/go-ethereum/swarm/network/priorityqueue" + "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" +) + +//Tests initializing a retrieve request +func TestStreamerRetrieveRequest(t *testing.T) { + regOpts := &RegistryOptions{ + Retrieval: RetrievalClientOnly, + Syncing: SyncingDisabled, + } + tester, streamer, _, teardown, err := newStreamerTester(regOpts) + if err != nil { + t.Fatal(err) + } + defer teardown() + + node := tester.Nodes[0] + + ctx := context.Background() + req := network.NewRequest( + storage.Address(hash0[:]), + true, + &sync.Map{}, + ) + streamer.delivery.RequestFromPeers(ctx, req) + + stream := NewStream(swarmChunkServerStreamName, "", true) + + err = tester.TestExchanges(p2ptest.Exchange{ + Label: "RetrieveRequestMsg", + Expects: []p2ptest.Expect{ + { //start expecting a subscription for RETRIEVE_REQUEST due to `RetrievalClientOnly` + Code: 4, + Msg: &SubscribeMsg{ + Stream: stream, + History: nil, + Priority: Top, + }, + Peer: node.ID(), + }, + { //expect a retrieve request message for the given hash + Code: 5, + Msg: &RetrieveRequestMsg{ + Addr: hash0[:], + SkipCheck: true, + }, + Peer: node.ID(), + }, + }, + }) + + if err != nil { + t.Fatalf("Expected no error, got %v", err) + } +} + +//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(&RegistryOptions{ + Retrieval: RetrievalEnabled, + Syncing: SyncingDisabled, //do no syncing + }) + if err != nil { + t.Fatal(err) + } + defer teardown() + + node := tester.Nodes[0] + + chunk := storage.NewChunk(storage.Address(hash0[:]), nil) + + peer := streamer.getPeer(node.ID()) + + stream := NewStream(swarmChunkServerStreamName, "", true) + //simulate pre-subscription to RETRIEVE_REQUEST stream on peer + peer.handleSubscribeMsg(context.TODO(), &SubscribeMsg{ + Stream: stream, + History: nil, + Priority: Top, + }) + + //test the exchange + err = tester.TestExchanges(p2ptest.Exchange{ + Expects: []p2ptest.Expect{ + { //first expect a subscription to the RETRIEVE_REQUEST stream + Code: 4, + Msg: &SubscribeMsg{ + Stream: stream, + History: nil, + Priority: Top, + }, + Peer: node.ID(), + }, + }, + }, p2ptest.Exchange{ + Label: "RetrieveRequestMsg", + Triggers: []p2ptest.Trigger{ + { //then the actual RETRIEVE_REQUEST.... + Code: 5, + Msg: &RetrieveRequestMsg{ + Addr: chunk.Address()[:], + }, + Peer: node.ID(), + }, + }, + Expects: []p2ptest.Expect{ + { //to which the peer responds with offered hashes + Code: 1, + Msg: &OfferedHashesMsg{ + HandoverProof: nil, + Hashes: nil, + From: 0, + To: 0, + }, + Peer: node.ID(), + }, + }, + }) + + //should fail with a timeout as the peer we are requesting + //the chunk from does not have the chunk + expectedError := `exchange #1 "RetrieveRequestMsg": timed out` + if err == nil || err.Error() != expectedError { + t.Fatalf("Expected error %v, got %v", expectedError, err) + } +} + +// 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(&RegistryOptions{ + Retrieval: RetrievalEnabled, + Syncing: SyncingDisabled, + }) + if err != nil { + t.Fatal(err) + } + defer teardown() + + node := tester.Nodes[0] + + peer := streamer.getPeer(node.ID()) + + stream := NewStream(swarmChunkServerStreamName, "", true) + + peer.handleSubscribeMsg(context.TODO(), &SubscribeMsg{ + Stream: stream, + History: nil, + Priority: Top, + }) + + hash := storage.Address(hash0[:]) + chunk := storage.NewChunk(hash, hash) + err = localStore.Put(context.TODO(), chunk) + if err != nil { + t.Fatalf("Expected no err got %v", err) + } + + err = tester.TestExchanges(p2ptest.Exchange{ + Expects: []p2ptest.Expect{ + { + Code: 4, + Msg: &SubscribeMsg{ + Stream: stream, + History: nil, + Priority: Top, + }, + Peer: node.ID(), + }, + }, + }, p2ptest.Exchange{ + Label: "RetrieveRequestMsg", + Triggers: []p2ptest.Trigger{ + { + Code: 5, + Msg: &RetrieveRequestMsg{ + Addr: hash, + }, + Peer: node.ID(), + }, + }, + Expects: []p2ptest.Expect{ + { + Code: 1, + Msg: &OfferedHashesMsg{ + HandoverProof: &HandoverProof{ + Handover: &Handover{}, + }, + Hashes: hash, + From: 0, + // TODO: why is this 32??? + To: 32, + Stream: stream, + }, + Peer: node.ID(), + }, + }, + }) + + if err != nil { + t.Fatal(err) + } + + hash = storage.Address(hash1[:]) + chunk = storage.NewChunk(hash, hash1[:]) + err = localStore.Put(context.TODO(), chunk) + if err != nil { + t.Fatalf("Expected no err got %v", err) + } + + err = tester.TestExchanges(p2ptest.Exchange{ + Label: "RetrieveRequestMsg", + Triggers: []p2ptest.Trigger{ + { + Code: 5, + Msg: &RetrieveRequestMsg{ + Addr: hash, + SkipCheck: true, + }, + Peer: node.ID(), + }, + }, + Expects: []p2ptest.Expect{ + { + Code: 6, + Msg: &ChunkDeliveryMsg{ + Addr: hash, + SData: hash, + }, + Peer: node.ID(), + }, + }, + }) + + if err != nil { + t.Fatal(err) + } +} + +// if there is one peer in the Kademlia, RequestFromPeers should return it +func TestRequestFromPeers(t *testing.T) { + dummyPeerID := enode.HexID("3431c3939e1ee2a6345e976a8234f9870152d64879f30bc272a074f6859e75e8") + + addr := network.RandomAddr() + to := network.NewKademlia(addr.OAddr, network.NewKadParams()) + delivery := NewDelivery(to, nil) + protocolsPeer := protocols.NewPeer(p2p.NewPeer(dummyPeerID, "dummy", nil), nil, nil) + peer := network.NewPeer(&network.BzzPeer{ + BzzAddr: network.RandomAddr(), + LightNode: false, + Peer: protocolsPeer, + }, to) + to.On(peer) + 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, + pq: pq.New(int(PriorityQueue), PriorityQueueCap), + streamer: r, + } + r.setPeer(sp) + req := network.NewRequest( + storage.Address(hash0[:]), + true, + &sync.Map{}, + ) + ctx := context.Background() + id, _, err := delivery.RequestFromPeers(ctx, req) + + if err != nil { + t.Fatal(err) + } + if *id != dummyPeerID { + t.Fatalf("Expected an id, got %v", id) + } +} + +// RequestFromPeers should not return light nodes +func TestRequestFromPeersWithLightNode(t *testing.T) { + dummyPeerID := enode.HexID("3431c3939e1ee2a6345e976a8234f9870152d64879f30bc272a074f6859e75e8") + + addr := network.RandomAddr() + to := network.NewKademlia(addr.OAddr, network.NewKadParams()) + delivery := NewDelivery(to, nil) + + protocolsPeer := protocols.NewPeer(p2p.NewPeer(dummyPeerID, "dummy", nil), nil, nil) + // setting up a lightnode + peer := network.NewPeer(&network.BzzPeer{ + BzzAddr: network.RandomAddr(), + LightNode: true, + Peer: protocolsPeer, + }, to) + to.On(peer) + 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, + pq: pq.New(int(PriorityQueue), PriorityQueueCap), + streamer: r, + } + r.setPeer(sp) + + req := network.NewRequest( + storage.Address(hash0[:]), + true, + &sync.Map{}, + ) + + ctx := context.Background() + // making a request which should return with "no peer found" + _, _, err := delivery.RequestFromPeers(ctx, req) + + expectedError := "no peer found" + if err.Error() != expectedError { + t.Fatalf("expected '%v', got %v", expectedError, err) + } +} + +func TestStreamerDownstreamChunkDeliveryMsgExchange(t *testing.T) { + tester, streamer, localStore, teardown, err := newStreamerTester(&RegistryOptions{ + Retrieval: RetrievalDisabled, + Syncing: SyncingDisabled, + }) + if err != nil { + t.Fatal(err) + } + defer teardown() + + streamer.RegisterClientFunc("foo", func(p *Peer, t string, live bool) (Client, error) { + return &testClient{ + t: t, + }, nil + }) + + node := tester.Nodes[0] + + //subscribe to custom stream + stream := NewStream("foo", "", true) + err = streamer.Subscribe(node.ID(), stream, NewRange(5, 8), Top) + if err != nil { + t.Fatalf("Expected no error, got %v", err) + } + + chunkKey := hash0[:] + chunkData := hash1[:] + + err = tester.TestExchanges(p2ptest.Exchange{ + Label: "Subscribe message", + Expects: []p2ptest.Expect{ + { //first expect subscription to the custom stream... + Code: 4, + Msg: &SubscribeMsg{ + Stream: stream, + History: NewRange(5, 8), + Priority: Top, + }, + Peer: node.ID(), + }, + }, + }, + p2ptest.Exchange{ + Label: "ChunkDelivery message", + Triggers: []p2ptest.Trigger{ + { //...then trigger a chunk delivery for the given chunk from peer in order for + //local node to get the chunk delivered + Code: 6, + Msg: &ChunkDeliveryMsg{ + Addr: chunkKey, + SData: chunkData, + }, + Peer: node.ID(), + }, + }, + }) + + if err != nil { + t.Fatalf("Expected no error, got %v", err) + } + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + defer cancel() + + // wait for the chunk to get stored + storedChunk, err := localStore.Get(ctx, chunkKey) + for err != nil { + select { + case <-ctx.Done(): + t.Fatalf("Chunk is not in localstore after timeout, err: %v", err) + default: + } + storedChunk, err = localStore.Get(ctx, chunkKey) + time.Sleep(50 * time.Millisecond) + } + + if err != nil { + t.Fatalf("Expected no error, got %v", err) + } + + if !bytes.Equal(storedChunk.Data(), chunkData) { + t.Fatal("Retrieved chunk has different data than original") + } + +} + +func TestDeliveryFromNodes(t *testing.T) { + 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, 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 + } + + 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 { + t.Fatal(err) + } + + 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) + } + }) +} + +func BenchmarkDeliveryFromNodesWithoutCheck(b *testing.B) { + for chunks := 32; chunks <= 128; chunks *= 2 { + for i := 2; i < 32; i *= 2 { + b.Run( + fmt.Sprintf("nodes=%v,chunks=%v", i, chunks), + func(b *testing.B) { + benchmarkDeliveryFromNodes(b, i, chunks, true) + }, + ) + } + } +} + +func BenchmarkDeliveryFromNodesWithCheck(b *testing.B) { + for chunks := 32; chunks <= 128; chunks *= 2 { + for i := 2; i < 32; i *= 2 { + b.Run( + fmt.Sprintf("nodes=%v,chunks=%v", i, chunks), + func(b *testing.B) { + benchmarkDeliveryFromNodes(b, i, chunks, false) + }, + ) + } + } +} + +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) { + addr, netStore, delivery, clean, err := newNetStoreAndDelivery(ctx, bucket) + if err != nil { + return nil, nil, err + } + + r := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), &RegistryOptions{ + SkipCheck: skipCheck, + Syncing: SyncingDisabled, + Retrieval: RetrievalDisabled, + SyncUpdateDelay: 0, + }, nil) + bucket.Store(bucketKeyRegistry, r) + + cleanup = func() { + r.Close() + clean() + } + + return r, cleanup, nil + }, + }) + defer sim.Close() + + log.Info("Initializing test config") + _, err := sim.AddNodesAndConnectChain(nodes) + if err != nil { + b.Fatal(err) + } + + 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 { + return errors.New("No filestore") + } + remoteFileStore := item.(*storage.FileStore) + + pivotNode := nodeIDs[0] + item, ok = sim.NodeItem(pivotNode, bucketKeyNetStore) + if !ok { + return errors.New("No filestore") + } + netStore := item.(*storage.NetStore) + + if _, err := sim.WaitTillHealthy(ctx); err != nil { + return err + } + + disconnected := watchDisconnections(ctx, sim) + defer func() { + if err != nil && disconnected.bool() { + err = errors.New("disconnect events received") + } + }() + // benchmark loop + b.ResetTimer() + b.StopTimer() + Loop: + for i := 0; i < b.N; i++ { + // uploading chunkCount random chunks to the last node + hashes := make([]storage.Address, chunkCount) + for i := 0; i < chunkCount; i++ { + // create actual size real chunks + ctx := context.TODO() + hash, wait, err := remoteFileStore.Store(ctx, testutil.RandomReader(i, chunkSize), int64(chunkSize), false) + if err != nil { + return fmt.Errorf("store: %v", err) + } + // wait until all chunks stored + err = wait(ctx) + if err != nil { + return fmt.Errorf("wait store: %v", err) + } + // collect the hashes + hashes[i] = hash + } + // now benchmark the actual retrieval + // netstore.Get is called for each hash in a go routine and errors are collected + b.StartTimer() + errs := make(chan error) + for _, hash := range hashes { + go func(h storage.Address) { + _, err := netStore.Get(ctx, h) + log.Warn("test check netstore get", "hash", h, "err", err) + errs <- err + }(hash) + } + // count and report retrieval errors + // if there are misses then chunk timeout is too low for the distance and volume (?) + var total, misses int + for err := range errs { + if err != nil { + log.Warn(err.Error()) + misses++ + } + total++ + if total == chunkCount { + break + } + } + b.StopTimer() + + if misses > 0 { + err = fmt.Errorf("%v chunk not found out of %v", misses, total) + break Loop + } + } + return err + }) + if result.Error != nil { + b.Fatal(result.Error) + } + +} diff --git a/swarm/network/stream/intervals/dbstore_test.go b/swarm/network/stream/intervals/dbstore_test.go new file mode 100644 index 0000000000..6716e593ab --- /dev/null +++ b/swarm/network/stream/intervals/dbstore_test.go @@ -0,0 +1,42 @@ +// 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 intervals + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/ethereum/go-ethereum/swarm/state" +) + +// TestDBStore tests basic functionality of DBStore. +func TestDBStore(t *testing.T) { + dir, err := ioutil.TempDir("", "intervals_test_db_store") + if err != nil { + panic(err) + } + defer os.RemoveAll(dir) + + store, err := state.NewDBStore(dir) + if err != nil { + t.Fatal(err) + } + defer store.Close() + + testStore(t, store) +} diff --git a/swarm/network/stream/intervals/intervals.go b/swarm/network/stream/intervals/intervals.go new file mode 100644 index 0000000000..562c3df9ae --- /dev/null +++ b/swarm/network/stream/intervals/intervals.go @@ -0,0 +1,206 @@ +// 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 intervals + +import ( + "bytes" + "fmt" + "strconv" + "sync" +) + +// Intervals store a list of intervals. Its purpose is to provide +// methods to add new intervals and retrieve missing intervals that +// need to be added. +// It may be used in synchronization of streaming data to persist +// retrieved data ranges between sessions. +type Intervals struct { + start uint64 + ranges [][2]uint64 + mu sync.RWMutex +} + +// New creates a new instance of Intervals. +// Start argument limits the lower bound of intervals. +// No range bellow start bound will be added by Add method or +// returned by Next method. This limit may be used for +// tracking "live" synchronization, where the sync session +// starts from a specific value, and if "live" sync intervals +// need to be merged with historical ones, it can be safely done. +func NewIntervals(start uint64) *Intervals { + return &Intervals{ + start: start, + } +} + +// Add adds a new range to intervals. Range start and end are values +// are both inclusive. +func (i *Intervals) Add(start, end uint64) { + i.mu.Lock() + defer i.mu.Unlock() + + i.add(start, end) +} + +func (i *Intervals) add(start, end uint64) { + if start < i.start { + start = i.start + } + if end < i.start { + return + } + minStartJ := -1 + maxEndJ := -1 + j := 0 + for ; j < len(i.ranges); j++ { + if minStartJ < 0 { + if (start <= i.ranges[j][0] && end+1 >= i.ranges[j][0]) || (start <= i.ranges[j][1]+1 && end+1 >= i.ranges[j][1]) { + if i.ranges[j][0] < start { + start = i.ranges[j][0] + } + minStartJ = j + } + } + if (start <= i.ranges[j][1] && end+1 >= i.ranges[j][1]) || (start <= i.ranges[j][0] && end+1 >= i.ranges[j][0]) { + if i.ranges[j][1] > end { + end = i.ranges[j][1] + } + maxEndJ = j + } + if end+1 <= i.ranges[j][0] { + break + } + } + if minStartJ < 0 && maxEndJ < 0 { + i.ranges = append(i.ranges[:j], append([][2]uint64{{start, end}}, i.ranges[j:]...)...) + return + } + if minStartJ >= 0 { + i.ranges[minStartJ][0] = start + } + if maxEndJ >= 0 { + i.ranges[maxEndJ][1] = end + } + if minStartJ >= 0 && maxEndJ >= 0 && minStartJ != maxEndJ { + i.ranges[maxEndJ][0] = start + i.ranges = append(i.ranges[:minStartJ], i.ranges[maxEndJ:]...) + } +} + +// Merge adds all the intervals from the m Interval to current one. +func (i *Intervals) Merge(m *Intervals) { + m.mu.RLock() + defer m.mu.RUnlock() + i.mu.Lock() + defer i.mu.Unlock() + + for _, r := range m.ranges { + i.add(r[0], r[1]) + } +} + +// Next returns the first range interval that is not fulfilled. Returned +// start and end values are both inclusive, meaning that the whole range +// including start and end need to be added in order to full the gap +// in intervals. +// Returned value for end is 0 if the next interval is after the whole +// range that is stored in Intervals. Zero end value represents no limit +// on the next interval length. +func (i *Intervals) Next() (start, end uint64) { + i.mu.RLock() + defer i.mu.RUnlock() + + l := len(i.ranges) + if l == 0 { + return i.start, 0 + } + if i.ranges[0][0] != i.start { + return i.start, i.ranges[0][0] - 1 + } + if l == 1 { + return i.ranges[0][1] + 1, 0 + } + return i.ranges[0][1] + 1, i.ranges[1][0] - 1 +} + +// Last returns the value that is at the end of the last interval. +func (i *Intervals) Last() (end uint64) { + i.mu.RLock() + defer i.mu.RUnlock() + + l := len(i.ranges) + if l == 0 { + return 0 + } + return i.ranges[l-1][1] +} + +// String returns a descriptive representation of range intervals +// in [] notation, as a list of two element vectors. +func (i *Intervals) String() string { + return fmt.Sprint(i.ranges) +} + +// MarshalBinary encodes Intervals parameters into a semicolon separated list. +// The first element in the list is base36-encoded start value. The following +// elements are two base36-encoded value ranges separated by comma. +func (i *Intervals) MarshalBinary() (data []byte, err error) { + d := make([][]byte, len(i.ranges)+1) + d[0] = []byte(strconv.FormatUint(i.start, 36)) + for j := range i.ranges { + r := i.ranges[j] + d[j+1] = []byte(strconv.FormatUint(r[0], 36) + "," + strconv.FormatUint(r[1], 36)) + } + return bytes.Join(d, []byte(";")), nil +} + +// UnmarshalBinary decodes data according to the Intervals.MarshalBinary format. +func (i *Intervals) UnmarshalBinary(data []byte) (err error) { + d := bytes.Split(data, []byte(";")) + l := len(d) + if l == 0 { + return nil + } + if l >= 1 { + i.start, err = strconv.ParseUint(string(d[0]), 36, 64) + if err != nil { + return err + } + } + if l == 1 { + return nil + } + + i.ranges = make([][2]uint64, 0, l-1) + for j := 1; j < l; j++ { + r := bytes.SplitN(d[j], []byte(","), 2) + if len(r) < 2 { + return fmt.Errorf("range %d has less then 2 elements", j) + } + start, err := strconv.ParseUint(string(r[0]), 36, 64) + if err != nil { + return fmt.Errorf("parsing the first element in range %d: %v", j, err) + } + end, err := strconv.ParseUint(string(r[1]), 36, 64) + if err != nil { + return fmt.Errorf("parsing the second element in range %d: %v", j, err) + } + i.ranges = append(i.ranges, [2]uint64{start, end}) + } + + return nil +} diff --git a/swarm/network/stream/intervals/intervals_test.go b/swarm/network/stream/intervals/intervals_test.go new file mode 100644 index 0000000000..b5212f0d91 --- /dev/null +++ b/swarm/network/stream/intervals/intervals_test.go @@ -0,0 +1,395 @@ +// 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 intervals + +import "testing" + +// Test tests Interval methods Add, Next and Last for various +// initial state. +func Test(t *testing.T) { + for i, tc := range []struct { + startLimit uint64 + initial [][2]uint64 + start uint64 + end uint64 + expected string + nextStart uint64 + nextEnd uint64 + last uint64 + }{ + { + initial: nil, + start: 0, + end: 0, + expected: "[[0 0]]", + nextStart: 1, + nextEnd: 0, + last: 0, + }, + { + initial: nil, + start: 0, + end: 10, + expected: "[[0 10]]", + nextStart: 11, + nextEnd: 0, + last: 10, + }, + { + initial: nil, + start: 5, + end: 15, + expected: "[[5 15]]", + nextStart: 0, + nextEnd: 4, + last: 15, + }, + { + initial: [][2]uint64{{0, 0}}, + start: 0, + end: 0, + expected: "[[0 0]]", + nextStart: 1, + nextEnd: 0, + last: 0, + }, + { + initial: [][2]uint64{{0, 0}}, + start: 5, + end: 15, + expected: "[[0 0] [5 15]]", + nextStart: 1, + nextEnd: 4, + last: 15, + }, + { + initial: [][2]uint64{{5, 15}}, + start: 5, + end: 15, + expected: "[[5 15]]", + nextStart: 0, + nextEnd: 4, + last: 15, + }, + { + initial: [][2]uint64{{5, 15}}, + start: 5, + end: 20, + expected: "[[5 20]]", + nextStart: 0, + nextEnd: 4, + last: 20, + }, + { + initial: [][2]uint64{{5, 15}}, + start: 10, + end: 20, + expected: "[[5 20]]", + nextStart: 0, + nextEnd: 4, + last: 20, + }, + { + initial: [][2]uint64{{5, 15}}, + start: 0, + end: 20, + expected: "[[0 20]]", + nextStart: 21, + nextEnd: 0, + last: 20, + }, + { + initial: [][2]uint64{{5, 15}}, + start: 2, + end: 10, + expected: "[[2 15]]", + nextStart: 0, + nextEnd: 1, + last: 15, + }, + { + initial: [][2]uint64{{5, 15}}, + start: 2, + end: 4, + expected: "[[2 15]]", + nextStart: 0, + nextEnd: 1, + last: 15, + }, + { + initial: [][2]uint64{{5, 15}}, + start: 2, + end: 5, + expected: "[[2 15]]", + nextStart: 0, + nextEnd: 1, + last: 15, + }, + { + initial: [][2]uint64{{5, 15}}, + start: 2, + end: 3, + expected: "[[2 3] [5 15]]", + nextStart: 0, + nextEnd: 1, + last: 15, + }, + { + initial: [][2]uint64{{5, 15}}, + start: 2, + end: 4, + expected: "[[2 15]]", + nextStart: 0, + nextEnd: 1, + last: 15, + }, + { + initial: [][2]uint64{{0, 1}, {5, 15}}, + start: 2, + end: 4, + expected: "[[0 15]]", + nextStart: 16, + nextEnd: 0, + last: 15, + }, + { + initial: [][2]uint64{{0, 5}, {15, 20}}, + start: 2, + end: 10, + expected: "[[0 10] [15 20]]", + nextStart: 11, + nextEnd: 14, + last: 20, + }, + { + initial: [][2]uint64{{0, 5}, {15, 20}}, + start: 8, + end: 18, + expected: "[[0 5] [8 20]]", + nextStart: 6, + nextEnd: 7, + last: 20, + }, + { + initial: [][2]uint64{{0, 5}, {15, 20}}, + start: 2, + end: 17, + expected: "[[0 20]]", + nextStart: 21, + nextEnd: 0, + last: 20, + }, + { + initial: [][2]uint64{{0, 5}, {15, 20}}, + start: 2, + end: 25, + expected: "[[0 25]]", + nextStart: 26, + nextEnd: 0, + last: 25, + }, + { + initial: [][2]uint64{{0, 5}, {15, 20}}, + start: 5, + end: 14, + expected: "[[0 20]]", + nextStart: 21, + nextEnd: 0, + last: 20, + }, + { + initial: [][2]uint64{{0, 5}, {15, 20}}, + start: 6, + end: 14, + expected: "[[0 20]]", + nextStart: 21, + nextEnd: 0, + last: 20, + }, + { + initial: [][2]uint64{{0, 5}, {15, 20}, {30, 40}}, + start: 6, + end: 29, + expected: "[[0 40]]", + nextStart: 41, + nextEnd: 0, + last: 40, + }, + { + initial: [][2]uint64{{0, 5}, {15, 20}, {30, 40}, {50, 60}}, + start: 3, + end: 55, + expected: "[[0 60]]", + nextStart: 61, + nextEnd: 0, + last: 60, + }, + { + initial: [][2]uint64{{0, 5}, {15, 20}, {30, 40}, {50, 60}}, + start: 21, + end: 49, + expected: "[[0 5] [15 60]]", + nextStart: 6, + nextEnd: 14, + last: 60, + }, + { + initial: [][2]uint64{{0, 5}, {15, 20}, {30, 40}, {50, 60}}, + start: 0, + end: 100, + expected: "[[0 100]]", + nextStart: 101, + nextEnd: 0, + last: 100, + }, + { + startLimit: 100, + initial: nil, + start: 0, + end: 0, + expected: "[]", + nextStart: 100, + nextEnd: 0, + last: 0, + }, + { + startLimit: 100, + initial: nil, + start: 20, + end: 30, + expected: "[]", + nextStart: 100, + nextEnd: 0, + last: 0, + }, + { + startLimit: 100, + initial: nil, + start: 50, + end: 100, + expected: "[[100 100]]", + nextStart: 101, + nextEnd: 0, + last: 100, + }, + { + startLimit: 100, + initial: nil, + start: 50, + end: 110, + expected: "[[100 110]]", + nextStart: 111, + nextEnd: 0, + last: 110, + }, + { + startLimit: 100, + initial: nil, + start: 120, + end: 130, + expected: "[[120 130]]", + nextStart: 100, + nextEnd: 119, + last: 130, + }, + { + startLimit: 100, + initial: nil, + start: 120, + end: 130, + expected: "[[120 130]]", + nextStart: 100, + nextEnd: 119, + last: 130, + }, + } { + intervals := NewIntervals(tc.startLimit) + intervals.ranges = tc.initial + intervals.Add(tc.start, tc.end) + got := intervals.String() + if got != tc.expected { + t.Errorf("interval #%d: expected %s, got %s", i, tc.expected, got) + } + nextStart, nextEnd := intervals.Next() + if nextStart != tc.nextStart { + t.Errorf("interval #%d, expected next start %d, got %d", i, tc.nextStart, nextStart) + } + if nextEnd != tc.nextEnd { + t.Errorf("interval #%d, expected next end %d, got %d", i, tc.nextEnd, nextEnd) + } + last := intervals.Last() + if last != tc.last { + t.Errorf("interval #%d, expected last %d, got %d", i, tc.last, last) + } + } +} + +func TestMerge(t *testing.T) { + for i, tc := range []struct { + initial [][2]uint64 + merge [][2]uint64 + expected string + }{ + { + initial: nil, + merge: nil, + expected: "[]", + }, + { + initial: [][2]uint64{{10, 20}}, + merge: nil, + expected: "[[10 20]]", + }, + { + initial: nil, + merge: [][2]uint64{{15, 25}}, + expected: "[[15 25]]", + }, + { + initial: [][2]uint64{{0, 100}}, + merge: [][2]uint64{{150, 250}}, + expected: "[[0 100] [150 250]]", + }, + { + initial: [][2]uint64{{0, 100}}, + merge: [][2]uint64{{101, 250}}, + expected: "[[0 250]]", + }, + { + initial: [][2]uint64{{0, 10}, {30, 40}}, + merge: [][2]uint64{{20, 25}, {41, 50}}, + expected: "[[0 10] [20 25] [30 50]]", + }, + { + initial: [][2]uint64{{0, 5}, {15, 20}, {30, 40}, {50, 60}}, + merge: [][2]uint64{{6, 25}}, + expected: "[[0 25] [30 40] [50 60]]", + }, + } { + intervals := NewIntervals(0) + intervals.ranges = tc.initial + m := NewIntervals(0) + m.ranges = tc.merge + + intervals.Merge(m) + + got := intervals.String() + if got != tc.expected { + t.Errorf("interval #%d: expected %s, got %s", i, tc.expected, got) + } + } +} diff --git a/swarm/network/stream/intervals/store_test.go b/swarm/network/stream/intervals/store_test.go new file mode 100644 index 0000000000..a36814b717 --- /dev/null +++ b/swarm/network/stream/intervals/store_test.go @@ -0,0 +1,77 @@ +// 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 intervals + +import ( + "testing" + + "github.com/ethereum/go-ethereum/swarm/state" +) + +// TestInmemoryStore tests basic functionality of InmemoryStore. +func TestInmemoryStore(t *testing.T) { + testStore(t, state.NewInmemoryStore()) +} + +// testStore is a helper function to test various Store implementations. +func testStore(t *testing.T, s state.Store) { + key1 := "key1" + i1 := NewIntervals(0) + i1.Add(10, 20) + if err := s.Put(key1, i1); err != nil { + t.Fatal(err) + } + i := &Intervals{} + err := s.Get(key1, i) + if err != nil { + t.Fatal(err) + } + if i.String() != i1.String() { + t.Errorf("expected interval %s, got %s", i1, i) + } + + key2 := "key2" + i2 := NewIntervals(0) + i2.Add(10, 20) + if err := s.Put(key2, i2); err != nil { + t.Fatal(err) + } + err = s.Get(key2, i) + if err != nil { + t.Fatal(err) + } + if i.String() != i2.String() { + t.Errorf("expected interval %s, got %s", i2, i) + } + + if err := s.Delete(key1); err != nil { + t.Fatal(err) + } + if err := s.Get(key1, i); err != state.ErrNotFound { + t.Errorf("expected error %v, got %s", state.ErrNotFound, err) + } + if err := s.Get(key2, i); err != nil { + t.Errorf("expected error %v, got %s", nil, err) + } + + if err := s.Delete(key2); err != nil { + t.Fatal(err) + } + if err := s.Get(key2, i); err != state.ErrNotFound { + t.Errorf("expected error %v, got %s", state.ErrNotFound, err) + } +} diff --git a/swarm/network/stream/intervals_test.go b/swarm/network/stream/intervals_test.go new file mode 100644 index 0000000000..009a941ef4 --- /dev/null +++ b/swarm/network/stream/intervals_test.go @@ -0,0 +1,362 @@ +// 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 stream + +import ( + "context" + "encoding/binary" + "errors" + "fmt" + "sync" + "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" + "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" +) + +func TestIntervalsLive(t *testing.T) { + testIntervals(t, true, nil, false) + testIntervals(t, true, nil, true) +} + +func TestIntervalsHistory(t *testing.T) { + testIntervals(t, false, NewRange(9, 26), false) + testIntervals(t, false, NewRange(9, 26), true) +} + +func TestIntervalsLiveAndHistory(t *testing.T) { + testIntervals(t, true, NewRange(9, 26), false) + testIntervals(t, true, NewRange(9, 26), true) +} + +func testIntervals(t *testing.T, live bool, history *Range, skipCheck bool) { + + nodes := 2 + chunkCount := dataChunkCount + externalStreamName := "externalStream" + externalStreamSessionAt := uint64(50) + externalStreamMaxKeys := uint64(100) + + sim := simulation.New(map[string]simulation.ServiceFunc{ + "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 + } + + 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) { + return newTestExternalClient(netStore), nil + }) + r.RegisterServerFunc(externalStreamName, func(p *Peer, t string, live bool) (Server, error) { + return newTestExternalServer(t, externalStreamSessionAt, externalStreamMaxKeys, nil), nil + }) + + 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 { + t.Fatal(err) + } + + ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) + defer cancel() + + if _, err := sim.WaitTillHealthy(ctx); err != nil { + t.Fatal(err) + } + + result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) (err error) { + nodeIDs := sim.UpNodeIDs() + storer := nodeIDs[0] + checker := nodeIDs[1] + + item, ok := sim.NodeItem(storer, bucketKeyFileStore) + if !ok { + return fmt.Errorf("No filestore") + } + fileStore := item.(*storage.FileStore) + + size := chunkCount * chunkSize + + _, wait, err := fileStore.Store(ctx, testutil.RandomReader(1, size), int64(size), false) + if err != nil { + return fmt.Errorf("store: %v", err) + } + err = wait(ctx) + if err != nil { + return fmt.Errorf("wait store: %v", err) + } + + item, ok = sim.NodeItem(checker, bucketKeyRegistry) + if !ok { + return fmt.Errorf("No registry") + } + registry := item.(*Registry) + + liveErrC := make(chan error) + historyErrC := make(chan error) + + err = registry.Subscribe(storer, NewStream(externalStreamName, "", live), history, Top) + if err != nil { + return err + } + + disconnected := watchDisconnections(ctx, sim) + defer func() { + if err != nil && disconnected.bool() { + err = errors.New("disconnect events received") + } + }() + + go func() { + if !live { + close(liveErrC) + return + } + + var err error + defer func() { + liveErrC <- err + }() + + // live stream + var liveHashesChan chan []byte + liveHashesChan, err = getHashes(ctx, registry, storer, NewStream(externalStreamName, "", true)) + if err != nil { + log.Error("get hashes", "err", err) + return + } + i := externalStreamSessionAt + + // we have subscribed, enable notifications + err = enableNotifications(registry, storer, NewStream(externalStreamName, "", true)) + if err != nil { + return + } + + for { + select { + case hash := <-liveHashesChan: + h := binary.BigEndian.Uint64(hash) + if h != i { + err = fmt.Errorf("expected live hash %d, got %d", i, h) + return + } + i++ + if i > externalStreamMaxKeys { + return + } + case <-ctx.Done(): + return + } + } + }() + + go func() { + if live && history == nil { + close(historyErrC) + return + } + + var err error + defer func() { + historyErrC <- err + }() + + // history stream + var historyHashesChan chan []byte + historyHashesChan, err = getHashes(ctx, registry, storer, NewStream(externalStreamName, "", false)) + if err != nil { + log.Error("get hashes", "err", err) + return + } + + var i uint64 + historyTo := externalStreamMaxKeys + if history != nil { + i = history.From + if history.To != 0 { + historyTo = history.To + } + } + + // we have subscribed, enable notifications + err = enableNotifications(registry, storer, NewStream(externalStreamName, "", false)) + if err != nil { + return + } + + for { + select { + case hash := <-historyHashesChan: + h := binary.BigEndian.Uint64(hash) + if h != i { + err = fmt.Errorf("expected history hash %d, got %d", i, h) + return + } + i++ + if i > historyTo { + return + } + case <-ctx.Done(): + return + } + } + }() + + if err := <-liveErrC; err != nil { + return err + } + if err := <-historyErrC; err != nil { + return err + } + + return nil + }) + + if result.Error != nil { + t.Fatal(result.Error) + } +} + +func getHashes(ctx context.Context, r *Registry, peerID enode.ID, s Stream) (chan []byte, error) { + peer := r.getPeer(peerID) + + client, err := peer.getClient(ctx, s) + if err != nil { + return nil, err + } + + c := client.Client.(*testExternalClient) + + return c.hashes, nil +} + +func enableNotifications(r *Registry, peerID enode.ID, s Stream) error { + peer := r.getPeer(peerID) + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + client, err := peer.getClient(ctx, s) + if err != nil { + return err + } + + close(client.Client.(*testExternalClient).enableNotificationsC) + + return nil +} + +type testExternalClient struct { + hashes chan []byte + store storage.SyncChunkStore + enableNotificationsC chan struct{} +} + +func newTestExternalClient(store storage.SyncChunkStore) *testExternalClient { + return &testExternalClient{ + hashes: make(chan []byte), + store: store, + enableNotificationsC: make(chan struct{}), + } +} + +func (c *testExternalClient) NeedData(ctx context.Context, hash []byte) func(context.Context) error { + wait := c.store.FetchFunc(ctx, storage.Address(hash)) + if wait == nil { + return nil + } + select { + case c.hashes <- hash: + case <-ctx.Done(): + log.Warn("testExternalClient NeedData context", "err", ctx.Err()) + return func(_ context.Context) error { + return ctx.Err() + } + } + return wait +} + +func (c *testExternalClient) BatchDone(Stream, uint64, []byte, []byte) func() (*TakeoverProof, error) { + return nil +} + +func (c *testExternalClient) Close() {} + +type testExternalServer struct { + t string + keyFunc func(key []byte, index uint64) + sessionAt uint64 + maxKeys uint64 +} + +func newTestExternalServer(t string, sessionAt, maxKeys uint64, keyFunc func(key []byte, index uint64)) *testExternalServer { + if keyFunc == nil { + keyFunc = binary.BigEndian.PutUint64 + } + return &testExternalServer{ + t: t, + keyFunc: keyFunc, + sessionAt: sessionAt, + maxKeys: maxKeys, + } +} + +func (s *testExternalServer) SessionIndex() (uint64, error) { + return s.sessionAt, nil +} + +func (s *testExternalServer) SetNextBatch(from uint64, to uint64) ([]byte, uint64, uint64, *HandoverProof, error) { + if to > s.maxKeys { + to = s.maxKeys + } + b := make([]byte, HashSize*(to-from+1)) + for i := from; i <= to; i++ { + s.keyFunc(b[(i-from)*HashSize:(i-from+1)*HashSize], i) + } + return b, from, to, nil, nil +} + +func (s *testExternalServer) GetData(context.Context, []byte) ([]byte, error) { + return make([]byte, 4096), nil +} + +func (s *testExternalServer) Close() {} diff --git a/swarm/network/stream/lightnode_test.go b/swarm/network/stream/lightnode_test.go new file mode 100644 index 0000000000..501660fab4 --- /dev/null +++ b/swarm/network/stream/lightnode_test.go @@ -0,0 +1,214 @@ +// 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 stream + +import ( + "testing" + + p2ptest "github.com/ethereum/go-ethereum/p2p/testing" +) + +// This test checks the default behavior of the server, that is +// when it is serving Retrieve requests. +func TestLigthnodeRetrieveRequestWithRetrieve(t *testing.T) { + registryOptions := &RegistryOptions{ + Retrieval: RetrievalClientOnly, + Syncing: SyncingDisabled, + } + tester, _, _, teardown, err := newStreamerTester(registryOptions) + if err != nil { + t.Fatal(err) + } + defer teardown() + + node := tester.Nodes[0] + + stream := NewStream(swarmChunkServerStreamName, "", false) + + err = tester.TestExchanges(p2ptest.Exchange{ + Label: "SubscribeMsg", + Triggers: []p2ptest.Trigger{ + { + Code: 4, + Msg: &SubscribeMsg{ + Stream: stream, + }, + Peer: node.ID(), + }, + }, + }) + if err != nil { + t.Fatalf("Got %v", err) + } + + err = tester.TestDisconnected(&p2ptest.Disconnect{Peer: node.ID()}) + if err == nil || err.Error() != "timed out waiting for peers to disconnect" { + t.Fatalf("Expected no disconnect, got %v", err) + } +} + +// This test checks the Lightnode behavior of server, when serving Retrieve +// requests are disabled +func TestLigthnodeRetrieveRequestWithoutRetrieve(t *testing.T) { + registryOptions := &RegistryOptions{ + Retrieval: RetrievalDisabled, + Syncing: SyncingDisabled, + } + tester, _, _, teardown, err := newStreamerTester(registryOptions) + if err != nil { + t.Fatal(err) + } + defer teardown() + + node := tester.Nodes[0] + + stream := NewStream(swarmChunkServerStreamName, "", false) + + err = tester.TestExchanges( + p2ptest.Exchange{ + Label: "SubscribeMsg", + Triggers: []p2ptest.Trigger{ + { + Code: 4, + Msg: &SubscribeMsg{ + Stream: stream, + }, + Peer: node.ID(), + }, + }, + Expects: []p2ptest.Expect{ + { + Code: 7, + Msg: &SubscribeErrorMsg{ + Error: "stream RETRIEVE_REQUEST not registered", + }, + Peer: node.ID(), + }, + }, + }) + if err != nil { + t.Fatalf("Got %v", err) + } +} + +// This test checks the default behavior of the server, that is +// when syncing is enabled. +func TestLigthnodeRequestSubscriptionWithSync(t *testing.T) { + registryOptions := &RegistryOptions{ + Retrieval: RetrievalDisabled, + Syncing: SyncingRegisterOnly, + } + tester, _, _, teardown, err := newStreamerTester(registryOptions) + if err != nil { + t.Fatal(err) + } + defer teardown() + + node := tester.Nodes[0] + + syncStream := NewStream("SYNC", FormatSyncBinKey(1), false) + + err = tester.TestExchanges( + p2ptest.Exchange{ + Label: "RequestSubscription", + Triggers: []p2ptest.Trigger{ + { + Code: 8, + Msg: &RequestSubscriptionMsg{ + Stream: syncStream, + }, + Peer: node.ID(), + }, + }, + Expects: []p2ptest.Expect{ + { + Code: 4, + Msg: &SubscribeMsg{ + Stream: syncStream, + }, + Peer: node.ID(), + }, + }, + }) + + if err != nil { + t.Fatalf("Got %v", err) + } +} + +// This test checks the Lightnode behavior of the server, that is +// when syncing is disabled. +func TestLigthnodeRequestSubscriptionWithoutSync(t *testing.T) { + registryOptions := &RegistryOptions{ + Retrieval: RetrievalDisabled, + Syncing: SyncingDisabled, + } + tester, _, _, teardown, err := newStreamerTester(registryOptions) + if err != nil { + t.Fatal(err) + } + defer teardown() + + node := tester.Nodes[0] + + syncStream := NewStream("SYNC", FormatSyncBinKey(1), false) + + err = tester.TestExchanges(p2ptest.Exchange{ + Label: "RequestSubscription", + Triggers: []p2ptest.Trigger{ + { + Code: 8, + Msg: &RequestSubscriptionMsg{ + Stream: syncStream, + }, + Peer: node.ID(), + }, + }, + Expects: []p2ptest.Expect{ + { + Code: 7, + Msg: &SubscribeErrorMsg{ + Error: "stream SYNC not registered", + }, + Peer: node.ID(), + }, + }, + }, p2ptest.Exchange{ + Label: "RequestSubscription", + Triggers: []p2ptest.Trigger{ + { + Code: 4, + Msg: &SubscribeMsg{ + Stream: syncStream, + }, + Peer: node.ID(), + }, + }, + Expects: []p2ptest.Expect{ + { + Code: 7, + Msg: &SubscribeErrorMsg{ + Error: "stream SYNC not registered", + }, + Peer: node.ID(), + }, + }, + }) + + if err != nil { + t.Fatalf("Got %v", err) + } +} diff --git a/swarm/network/stream/messages.go b/swarm/network/stream/messages.go new file mode 100644 index 0000000000..b293724cc7 --- /dev/null +++ b/swarm/network/stream/messages.go @@ -0,0 +1,405 @@ +// 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 stream + +import ( + "context" + "fmt" + "time" + + "github.com/ethereum/go-ethereum/metrics" + "github.com/ethereum/go-ethereum/swarm/log" + bv "github.com/ethereum/go-ethereum/swarm/network/bitvector" + "github.com/ethereum/go-ethereum/swarm/spancontext" + "github.com/ethereum/go-ethereum/swarm/storage" + "github.com/opentracing/opentracing-go" +) + +var syncBatchTimeout = 30 * time.Second + +// Stream defines a unique stream identifier. +type Stream struct { + // Name is used for Client and Server functions identification. + Name string + // Key is the name of specific stream data. + Key string + // Live defines whether the stream delivers only new data + // for the specific stream. + Live bool +} + +func NewStream(name string, key string, live bool) Stream { + return Stream{ + Name: name, + Key: key, + Live: live, + } +} + +// String return a stream id based on all Stream fields. +func (s Stream) String() string { + t := "h" + if s.Live { + t = "l" + } + return fmt.Sprintf("%s|%s|%s", s.Name, s.Key, t) +} + +// SubcribeMsg is the protocol msg for requesting a stream(section) +type SubscribeMsg struct { + Stream Stream + History *Range `rlp:"nil"` + Priority uint8 // delivered on priority channel +} + +// RequestSubscriptionMsg is the protocol msg for a node to request subscription to a +// specific stream +type RequestSubscriptionMsg struct { + Stream Stream + History *Range `rlp:"nil"` + Priority uint8 // delivered on priority channel +} + +func (p *Peer) handleRequestSubscription(ctx context.Context, req *RequestSubscriptionMsg) (err error) { + log.Debug(fmt.Sprintf("handleRequestSubscription: streamer %s to subscribe to %s with stream %s", p.streamer.addr, p.ID(), req.Stream)) + if err = p.streamer.Subscribe(p.ID(), req.Stream, req.History, req.Priority); err != nil { + // The error will be sent as a subscribe error message + // and will not be returned as it will prevent any new message + // exchange between peers over p2p. Instead, error will be returned + // only if there is one from sending subscribe error message. + err = p.Send(ctx, SubscribeErrorMsg{ + Error: err.Error(), + }) + } + return err +} + +func (p *Peer) handleSubscribeMsg(ctx context.Context, req *SubscribeMsg) (err error) { + metrics.GetOrRegisterCounter("peer.handlesubscribemsg", nil).Inc(1) + + defer func() { + if err != nil { + // The error will be sent as a subscribe error message + // and will not be returned as it will prevent any new message + // exchange between peers over p2p. Instead, error will be returned + // only if there is one from sending subscribe error message. + err = p.Send(context.TODO(), SubscribeErrorMsg{ + Error: err.Error(), + }) + } + }() + + log.Debug("received subscription", "from", p.streamer.addr, "peer", p.ID(), "stream", req.Stream, "history", req.History) + + f, err := p.streamer.GetServerFunc(req.Stream.Name) + if err != nil { + return err + } + + s, err := f(p, req.Stream.Key, req.Stream.Live) + if err != nil { + return err + } + os, err := p.setServer(req.Stream, s, req.Priority) + if err != nil { + return err + } + + var from uint64 + var to uint64 + if !req.Stream.Live && req.History != nil { + from = req.History.From + to = req.History.To + } + + go func() { + if err := p.SendOfferedHashes(os, from, to); err != nil { + log.Warn("SendOfferedHashes error", "peer", p.ID().TerminalString(), "err", err) + } + }() + + if req.Stream.Live && req.History != nil { + // subscribe to the history stream + s, err := f(p, req.Stream.Key, false) + if err != nil { + return err + } + + os, err := p.setServer(getHistoryStream(req.Stream), s, getHistoryPriority(req.Priority)) + if err != nil { + return err + } + go func() { + if err := p.SendOfferedHashes(os, req.History.From, req.History.To); err != nil { + log.Warn("SendOfferedHashes error", "peer", p.ID().TerminalString(), "err", err) + } + }() + } + + return nil +} + +type SubscribeErrorMsg struct { + Error string +} + +func (p *Peer) handleSubscribeErrorMsg(req *SubscribeErrorMsg) (err error) { + //TODO the error should be channeled to whoever calls the subscribe + return fmt.Errorf("subscribe to peer %s: %v", p.ID(), req.Error) +} + +type UnsubscribeMsg struct { + Stream Stream +} + +func (p *Peer) handleUnsubscribeMsg(req *UnsubscribeMsg) error { + return p.removeServer(req.Stream) +} + +type QuitMsg struct { + Stream Stream +} + +func (p *Peer) handleQuitMsg(req *QuitMsg) error { + return p.removeClient(req.Stream) +} + +// OfferedHashesMsg is the protocol msg for offering to hand over a +// stream section +type OfferedHashesMsg struct { + Stream Stream // name of Stream + From, To uint64 // peer and db-specific entry count + Hashes []byte // stream of hashes (128) + *HandoverProof // HandoverProof +} + +// String pretty prints OfferedHashesMsg +func (m OfferedHashesMsg) String() string { + return fmt.Sprintf("Stream '%v' [%v-%v] (%v)", m.Stream, m.From, m.To, len(m.Hashes)/HashSize) +} + +// handleOfferedHashesMsg protocol msg handler calls the incoming streamer interface +// Filter method +func (p *Peer) handleOfferedHashesMsg(ctx context.Context, req *OfferedHashesMsg) error { + metrics.GetOrRegisterCounter("peer.handleofferedhashes", nil).Inc(1) + + var sp opentracing.Span + ctx, sp = spancontext.StartSpan( + ctx, + "handle.offered.hashes") + defer sp.Finish() + + c, _, err := p.getOrSetClient(req.Stream, req.From, req.To) + if err != nil { + return err + } + + hashes := req.Hashes + lenHashes := len(hashes) + if lenHashes%HashSize != 0 { + return fmt.Errorf("error invalid hashes length (len: %v)", lenHashes) + } + + want, err := bv.New(lenHashes / HashSize) + if err != nil { + return fmt.Errorf("error initiaising bitvector of length %v: %v", lenHashes/HashSize, err) + } + + ctr := 0 + errC := make(chan error) + ctx, cancel := context.WithTimeout(ctx, syncBatchTimeout) + + ctx = context.WithValue(ctx, "source", p.ID().String()) + for i := 0; i < lenHashes; i += HashSize { + hash := hashes[i : i+HashSize] + + if wait := c.NeedData(ctx, hash); wait != nil { + ctr++ + want.Set(i/HashSize, true) + // create request and wait until the chunk data arrives and is stored + go func(w func(context.Context) error) { + select { + case errC <- w(ctx): + case <-ctx.Done(): + } + }(wait) + } + } + + go func() { + defer cancel() + for i := 0; i < ctr; i++ { + select { + case err := <-errC: + if err != nil { + log.Debug("client.handleOfferedHashesMsg() error waiting for chunk, dropping peer", "peer", p.ID(), "err", err) + p.Drop(err) + return + } + case <-ctx.Done(): + log.Debug("client.handleOfferedHashesMsg() context done", "ctx.Err()", ctx.Err()) + return + case <-c.quit: + log.Debug("client.handleOfferedHashesMsg() quit") + return + } + } + select { + case c.next <- c.batchDone(p, req, hashes): + case <-c.quit: + log.Debug("client.handleOfferedHashesMsg() quit") + case <-ctx.Done(): + log.Debug("client.handleOfferedHashesMsg() context done", "ctx.Err()", ctx.Err()) + } + }() + // only send wantedKeysMsg if all missing chunks of the previous batch arrived + // except + if c.stream.Live { + c.sessionAt = req.From + } + from, to := c.nextBatch(req.To + 1) + log.Trace("set next batch", "peer", p.ID(), "stream", req.Stream, "from", req.From, "to", req.To, "addr", p.streamer.addr) + if from == to { + return nil + } + + msg := &WantedHashesMsg{ + Stream: req.Stream, + Want: want.Bytes(), + From: from, + To: to, + } + go func() { + log.Trace("sending want batch", "peer", p.ID(), "stream", msg.Stream, "from", msg.From, "to", msg.To) + select { + case err := <-c.next: + if err != nil { + log.Warn("c.next error dropping peer", "err", err) + p.Drop(err) + return + } + case <-c.quit: + log.Debug("client.handleOfferedHashesMsg() quit") + return + case <-ctx.Done(): + log.Debug("client.handleOfferedHashesMsg() context done", "ctx.Err()", ctx.Err()) + return + } + log.Trace("sending want batch", "peer", p.ID(), "stream", msg.Stream, "from", msg.From, "to", msg.To) + err := p.SendPriority(ctx, msg, c.priority) + if err != nil { + log.Warn("SendPriority error", "err", err) + } + }() + return nil +} + +// WantedHashesMsg is the protocol msg data for signaling which hashes +// offered in OfferedHashesMsg downstream peer actually wants sent over +type WantedHashesMsg struct { + Stream Stream + Want []byte // bitvector indicating which keys of the batch needed + From, To uint64 // next interval offset - empty if not to be continued +} + +// String pretty prints WantedHashesMsg +func (m WantedHashesMsg) String() string { + return fmt.Sprintf("Stream '%v', Want: %x, Next: [%v-%v]", m.Stream, m.Want, m.From, m.To) +} + +// handleWantedHashesMsg protocol msg handler +// * sends the next batch of unsynced keys +// * sends the actual data chunks as per WantedHashesMsg +func (p *Peer) handleWantedHashesMsg(ctx context.Context, req *WantedHashesMsg) error { + metrics.GetOrRegisterCounter("peer.handlewantedhashesmsg", nil).Inc(1) + + log.Trace("received wanted batch", "peer", p.ID(), "stream", req.Stream, "from", req.From, "to", req.To) + s, err := p.getServer(req.Stream) + if err != nil { + return err + } + hashes := s.currentBatch + // 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", "peer", p.ID().TerminalString(), "err", err) + } + }() + // go p.SendOfferedHashes(s, req.From, req.To) + l := len(hashes) / HashSize + + log.Trace("wanted batch length", "peer", p.ID(), "stream", req.Stream, "from", req.From, "to", req.To, "lenhashes", len(hashes), "l", l) + want, err := bv.NewFromBytes(req.Want, l) + if err != nil { + return fmt.Errorf("error initiaising bitvector of length %v: %v", l, err) + } + for i := 0; i < l; i++ { + if want.Get(i) { + metrics.GetOrRegisterCounter("peer.handlewantedhashesmsg.actualget", nil).Inc(1) + + hash := hashes[i*HashSize : (i+1)*HashSize] + data, err := s.GetData(ctx, hash) + if err != nil { + return fmt.Errorf("handleWantedHashesMsg get data %x: %v", hash, err) + } + chunk := storage.NewChunk(hash, data) + syncing := true + if err := p.Deliver(ctx, chunk, s.priority, syncing); err != nil { + return err + } + } + } + return nil +} + +// Handover represents a statement that the upstream peer hands over the stream section +type Handover struct { + Stream Stream // name of stream + Start, End uint64 // index of hashes + Root []byte // Root hash for indexed segment inclusion proofs +} + +// HandoverProof represents a signed statement that the upstream peer handed over the stream section +type HandoverProof struct { + Sig []byte // Sign(Hash(Serialisation(Handover))) + *Handover +} + +// Takeover represents a statement that downstream peer took over (stored all data) +// handed over +type Takeover Handover + +// TakeoverProof represents a signed statement that the downstream peer took over +// the stream section +type TakeoverProof struct { + Sig []byte // Sign(Hash(Serialisation(Takeover))) + *Takeover +} + +// TakeoverProofMsg is the protocol msg sent by downstream peer +type TakeoverProofMsg TakeoverProof + +// String pretty prints TakeoverProofMsg +func (m TakeoverProofMsg) String() string { + return fmt.Sprintf("Stream: '%v' [%v-%v], Root: %x, Sig: %x", m.Stream, m.Start, m.End, m.Root, m.Sig) +} + +func (p *Peer) handleTakeoverProofMsg(ctx context.Context, req *TakeoverProofMsg) error { + _, err := p.getServer(req.Stream) + // store the strongest takeoverproof for the stream in streamer + return err +} diff --git a/swarm/network/stream/peer.go b/swarm/network/stream/peer.go new file mode 100644 index 0000000000..1d3868a66b --- /dev/null +++ b/swarm/network/stream/peer.go @@ -0,0 +1,421 @@ +// 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 stream + +import ( + "context" + "errors" + "fmt" + "sync" + "time" + + "github.com/ethereum/go-ethereum/metrics" + "github.com/ethereum/go-ethereum/p2p/protocols" + "github.com/ethereum/go-ethereum/swarm/log" + pq "github.com/ethereum/go-ethereum/swarm/network/priorityqueue" + "github.com/ethereum/go-ethereum/swarm/network/stream/intervals" + "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" +) + +type notFoundError struct { + t string + s Stream +} + +func newNotFoundError(t string, s Stream) *notFoundError { + return ¬FoundError{t: t, s: s} +} + +func (e *notFoundError) Error() string { + return fmt.Sprintf("%s not found for stream %q", e.t, e.s) +} + +// ErrMaxPeerServers will be returned if peer server limit is reached. +// It will be sent in the SubscribeErrorMsg. +var ErrMaxPeerServers = errors.New("max peer servers") + +// Peer is the Peer extension for the streaming protocol +type Peer struct { + *protocols.Peer + streamer *Registry + pq *pq.PriorityQueue + serverMu sync.RWMutex + clientMu sync.RWMutex // protects both clients and clientParams + servers map[Stream]*server + clients map[Stream]*client + // clientParams map keeps required client arguments + // that are set on Registry.Subscribe and used + // on creating a new client in offered hashes handler. + clientParams map[Stream]*clientParams + quit chan struct{} +} + +type WrappedPriorityMsg struct { + Context context.Context + Msg interface{} +} + +// NewPeer is the constructor for Peer +func NewPeer(peer *protocols.Peer, streamer *Registry) *Peer { + p := &Peer{ + Peer: peer, + pq: pq.New(int(PriorityQueue), PriorityQueueCap), + streamer: streamer, + servers: make(map[Stream]*server), + clients: make(map[Stream]*client), + clientParams: make(map[Stream]*clientParams), + quit: make(chan struct{}), + } + ctx, cancel := context.WithCancel(context.Background()) + go p.pq.Run(ctx, func(i interface{}) { + wmsg := i.(WrappedPriorityMsg) + err := p.Send(wmsg.Context, wmsg.Msg) + if err != nil { + log.Error("Message send error, dropping peer", "peer", p.ID(), "err", err) + p.Drop(err) + } + }) + + // basic monitoring for pq contention + go func(pq *pq.PriorityQueue) { + ticker := time.NewTicker(5 * time.Second) + defer ticker.Stop() + for { + select { + case <-ticker.C: + var lenMaxi int + var capMaxi int + for k := range pq.Queues { + if lenMaxi < len(pq.Queues[k]) { + lenMaxi = len(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(lenMaxi)) + metrics.GetOrRegisterGauge(fmt.Sprintf("pq_cap_%s", p.ID().TerminalString()), nil).Update(int64(capMaxi)) + case <-p.quit: + return + } + } + }(p.pq) + + go func() { + <-p.quit + + cancel() + }() + return p +} + +// 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 msg interface{} + + spanName := "send.chunk.delivery" + + //we send different types of messages if delivery is for syncing or retrievals, + //even if handling and content of the message are the same, + //because swap accounting decides which messages need accounting based on the message type + if syncing { + msg = &ChunkDeliveryMsgSyncing{ + Addr: chunk.Address(), + SData: chunk.Data(), + } + spanName += ".syncing" + } else { + msg = &ChunkDeliveryMsgRetrieval{ + Addr: chunk.Address(), + SData: chunk.Data(), + } + spanName += ".retrieval" + } + + 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()) + 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) + } + return err +} + +// SendOfferedHashes sends OfferedHashesMsg protocol msg +func (p *Peer) SendOfferedHashes(s *server, f, t uint64) error { + var sp opentracing.Span + ctx, sp := spancontext.StartSpan( + context.TODO(), + "send.offered.hashes", + ) + defer sp.Finish() + + hashes, from, to, proof, err := s.setNextBatch(f, t) + if err != nil { + return err + } + // true only when quitting + if len(hashes) == 0 { + return nil + } + if proof == nil { + proof = &HandoverProof{ + Handover: &Handover{}, + } + } + s.currentBatch = hashes + msg := &OfferedHashesMsg{ + HandoverProof: proof, + Hashes: hashes, + From: from, + To: to, + 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) +} + +func (p *Peer) getServer(s Stream) (*server, error) { + p.serverMu.RLock() + defer p.serverMu.RUnlock() + + server := p.servers[s] + if server == nil { + return nil, newNotFoundError("server", s) + } + return server, nil +} + +func (p *Peer) setServer(s Stream, o Server, priority uint8) (*server, error) { + p.serverMu.Lock() + defer p.serverMu.Unlock() + + if p.servers[s] != nil { + return nil, fmt.Errorf("server %s already registered", s) + } + + if p.streamer.maxPeerServers > 0 && len(p.servers) >= p.streamer.maxPeerServers { + return nil, ErrMaxPeerServers + } + + sessionIndex, err := o.SessionIndex() + if err != nil { + return nil, err + } + os := &server{ + Server: o, + stream: s, + priority: priority, + sessionIndex: sessionIndex, + } + p.servers[s] = os + return os, nil +} + +func (p *Peer) removeServer(s Stream) error { + p.serverMu.Lock() + defer p.serverMu.Unlock() + + server, ok := p.servers[s] + if !ok { + return newNotFoundError("server", s) + } + server.Close() + delete(p.servers, s) + return nil +} + +func (p *Peer) getClient(ctx context.Context, s Stream) (c *client, err error) { + var params *clientParams + func() { + p.clientMu.RLock() + defer p.clientMu.RUnlock() + + c = p.clients[s] + if c != nil { + return + } + params = p.clientParams[s] + }() + if c != nil { + return c, nil + } + + if params != nil { + //debug.PrintStack() + if err := params.waitClient(ctx); err != nil { + return nil, err + } + } + + p.clientMu.RLock() + defer p.clientMu.RUnlock() + + c = p.clients[s] + if c != nil { + return c, nil + } + return nil, newNotFoundError("client", s) +} + +func (p *Peer) getOrSetClient(s Stream, from, to uint64) (c *client, created bool, err error) { + p.clientMu.Lock() + defer p.clientMu.Unlock() + + c = p.clients[s] + if c != nil { + return c, false, nil + } + + f, err := p.streamer.GetClientFunc(s.Name) + if err != nil { + return nil, false, err + } + + is, err := f(p, s.Key, s.Live) + if err != nil { + return nil, false, err + } + + cp, err := p.getClientParams(s) + if err != nil { + return nil, false, err + } + defer func() { + if err == nil { + if err := p.removeClientParams(s); err != nil { + log.Error("stream set client: remove client params", "stream", s, "peer", p, "err", err) + } + } + }() + + intervalsKey := peerStreamIntervalsKey(p, s) + if s.Live { + // try to find previous history and live intervals and merge live into history + historyKey := peerStreamIntervalsKey(p, NewStream(s.Name, s.Key, false)) + historyIntervals := &intervals.Intervals{} + err := p.streamer.intervalsStore.Get(historyKey, historyIntervals) + switch err { + case nil: + liveIntervals := &intervals.Intervals{} + err := p.streamer.intervalsStore.Get(intervalsKey, liveIntervals) + switch err { + case nil: + historyIntervals.Merge(liveIntervals) + if err := p.streamer.intervalsStore.Put(historyKey, historyIntervals); err != nil { + log.Error("stream set client: put history intervals", "stream", s, "peer", p, "err", err) + } + case state.ErrNotFound: + default: + log.Error("stream set client: get live intervals", "stream", s, "peer", p, "err", err) + } + case state.ErrNotFound: + default: + log.Error("stream set client: get history intervals", "stream", s, "peer", p, "err", err) + } + } + + if err := p.streamer.intervalsStore.Put(intervalsKey, intervals.NewIntervals(from)); err != nil { + return nil, false, err + } + + next := make(chan error, 1) + c = &client{ + Client: is, + stream: s, + priority: cp.priority, + to: cp.to, + next: next, + quit: make(chan struct{}), + intervalsStore: p.streamer.intervalsStore, + intervalsKey: intervalsKey, + } + p.clients[s] = c + cp.clientCreated() // unblock all possible getClient calls that are waiting + next <- nil // this is to allow wantedKeysMsg before first batch arrives + return c, true, nil +} + +func (p *Peer) removeClient(s Stream) error { + p.clientMu.Lock() + defer p.clientMu.Unlock() + + client, ok := p.clients[s] + if !ok { + return newNotFoundError("client", s) + } + client.close() + delete(p.clients, s) + return nil +} + +func (p *Peer) setClientParams(s Stream, params *clientParams) error { + p.clientMu.Lock() + defer p.clientMu.Unlock() + + if p.clients[s] != nil { + return fmt.Errorf("client %s already exists", s) + } + if p.clientParams[s] != nil { + return fmt.Errorf("client params %s already set", s) + } + p.clientParams[s] = params + return nil +} + +func (p *Peer) getClientParams(s Stream) (*clientParams, error) { + params := p.clientParams[s] + if params == nil { + return nil, fmt.Errorf("client params '%v' not provided to peer %v", s, p.ID()) + } + return params, nil +} + +func (p *Peer) removeClientParams(s Stream) error { + _, ok := p.clientParams[s] + if !ok { + return newNotFoundError("client params", s) + } + delete(p.clientParams, s) + return nil +} + +func (p *Peer) close() { + for _, s := range p.servers { + s.Close() + } +} diff --git a/swarm/network/stream/snapshot_retrieval_test.go b/swarm/network/stream/snapshot_retrieval_test.go new file mode 100644 index 0000000000..2fdf8e9e37 --- /dev/null +++ b/swarm/network/stream/snapshot_retrieval_test.go @@ -0,0 +1,324 @@ +// 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 stream + +import ( + "context" + "fmt" + "sync" + "testing" + "time" + + "github.com/ethereum/go-ethereum/swarm/testutil" + + "github.com/ethereum/go-ethereum/node" + "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/simulation" + "github.com/ethereum/go-ethereum/swarm/state" + "github.com/ethereum/go-ethereum/swarm/storage" +) + +//constants for random file generation +const ( + minFileSize = 2 + maxFileSize = 40 +) + +//This test is a retrieval test for nodes. +//A configurable number of nodes can be +//provided to the test. +//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 { + nodeCount = []int{*nodes} + } else { + nodeCount = []int{16} + + if *longrunning { + nodeCount = append(nodeCount, 32, 64) + } else if testutil.RaceEnabled { + nodeCount = []int{4} + } + + } + + for _, nc := range nodeCount { + if err := runFileRetrievalTest(nc); err != nil { + t.Error(err) + } + } +} + +//This test is a retrieval test for nodes. +//One node is randomly selected to be the pivot node. +//A configurable number of chunks and nodes can be +//provided to the test, the number of chunks is uploaded +//to the pivot node and other nodes try to retrieve the chunk(s). +//Number of chunks and nodes can be provided via commandline too. +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(t, *chunks, *nodes) + if err != nil { + t.Fatal(err) + } + } else { + nodeCnt := []int{16} + chnkCnt := []int{32} + + if *longrunning { + nodeCnt = []int{16, 32, 64} + chnkCnt = []int{4, 32, 256} + } else if testutil.RaceEnabled { + nodeCnt = []int{4} + chnkCnt = []int{4} + } + + for _, n := range nodeCnt { + for _, c := range chnkCnt { + 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": 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 + } + + syncUpdateDelay := 1 * time.Second + if *longrunning { + syncUpdateDelay = 3 * time.Second + } + + r := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), &RegistryOptions{ + Retrieval: RetrievalEnabled, + Syncing: SyncingAutoSubscribe, + SyncUpdateDelay: syncUpdateDelay, + }, nil) + + cleanup = func() { + r.Close() + clean() + } + + return r, cleanup, nil + }, +} + +/* +The test loads a snapshot file to construct the swarm network, +assuming that the snapshot file identifies a healthy +kademlia network. Nevertheless a health check runs in the +simulation's `action` function. + +The snapshot should have 'streamer' in its service list. +*/ +func runFileRetrievalTest(nodeCount int) error { + sim := simulation.New(retrievalSimServiceMap) + defer sim.Close() + + log.Info("Initializing test config", "node count", nodeCount) + + 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 + } + + ctx, cancelSimRun := context.WithTimeout(context.Background(), 3*time.Minute) + defer cancelSimRun() + + log.Info("Starting simulation") + + 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 + } + + //an array for the random files + var randomFiles []string + //channel to signal when the upload has finished + //uploadFinished := make(chan struct{}) + //channel to trigger new node checks + + conf.hashes, randomFiles, err = uploadFilesToNodes(sim) + if err != nil { + return err + } + if _, err := sim.WaitTillHealthy(ctx); 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. + REPEAT: + for { + for _, id := range nodeIDs { + //for each expected file, check if it is in the local store + item, ok := sim.NodeItem(id, bucketKeyFileStore) + if !ok { + return fmt.Errorf("No filestore") + } + fileStore := item.(*storage.FileStore) + //check all chunks + for i, hash := range conf.hashes { + reader, _ := fileStore.Retrieve(context.TODO(), hash) + //check that we can read the file size and that it corresponds to the generated file size + if s, err := reader.Size(ctx, nil); err != nil || s != int64(len(randomFiles[i])) { + log.Debug("Retrieve error", "err", err, "hash", hash, "nodeId", id) + time.Sleep(500 * time.Millisecond) + continue REPEAT + } + log.Debug(fmt.Sprintf("File with root hash %x successfully retrieved", hash)) + } + } + return nil + } + }) + + log.Info("Simulation terminated") + + if result.Error != nil { + return result.Error + } + + return nil +} + +/* +The test generates the given number of chunks. + +The test loads a snapshot file to construct the swarm network, +assuming that the snapshot file identifies a healthy +kademlia network. Nevertheless a health check runs in the +simulation's `action` function. + +The snapshot should have 'streamer' in its service list. +*/ +func runRetrievalTest(t *testing.T, chunkCount int, nodeCount int) error { + t.Helper() + sim := simulation.New(retrievalSimServiceMap) + defer sim.Close() + + 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 + } + + ctx := context.Background() + 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 + } + + //this is the node selected for upload + 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) + if err != nil { + return err + } + if _, err := sim.WaitTillHealthy(ctx); err != nil { + return err + } + + // 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 + //check on the node's FileStore (netstore) + item, ok := sim.NodeItem(id, bucketKeyFileStore) + if !ok { + return fmt.Errorf("No filestore") + } + fileStore := item.(*storage.FileStore) + //check all chunks + for _, hash := range conf.hashes { + reader, _ := fileStore.Retrieve(context.TODO(), hash) + //check that we can read the chunk size and that it corresponds to the generated chunk size + if s, err := reader.Size(ctx, nil); err != nil || s != int64(chunkSize) { + log.Debug("Retrieve error", "err", err, "hash", hash, "nodeId", id, "size", s) + time.Sleep(500 * time.Millisecond) + continue REPEAT + } + log.Debug(fmt.Sprintf("Chunk with root hash %x successfully retrieved", hash)) + } + } + // all nodes and files found, exit loop and return without error + return nil + } + }) + + if result.Error != nil { + return result.Error + } + + return nil +} diff --git a/swarm/network/stream/snapshot_sync_test.go b/swarm/network/stream/snapshot_sync_test.go new file mode 100644 index 0000000000..9737ec0a54 --- /dev/null +++ b/swarm/network/stream/snapshot_sync_test.go @@ -0,0 +1,321 @@ +// 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 stream + +import ( + "context" + "errors" + "fmt" + "os" + "runtime" + "sync" + "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/enode" + "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" + "github.com/ethereum/go-ethereum/swarm/pot" + "github.com/ethereum/go-ethereum/swarm/state" + "github.com/ethereum/go-ethereum/swarm/storage" + "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" +) + +type synctestConfig struct { + addrs [][]byte + hashes []storage.Address + idToChunksMap map[enode.ID][]int + //chunksToNodesMap map[string][]int + addrToIDMap map[string]enode.ID +} + +const ( + // EventTypeNode is the type of event emitted when a node is either + // created, started or stopped + EventTypeChunkCreated simulations.EventType = "chunkCreated" + EventTypeChunkOffered simulations.EventType = "chunkOffered" + EventTypeChunkWanted simulations.EventType = "chunkWanted" + EventTypeChunkDelivered simulations.EventType = "chunkDelivered" + EventTypeChunkArrived simulations.EventType = "chunkArrived" + EventTypeSimTerminated simulations.EventType = "simTerminated" +) + +// Tests in this file should not request chunks from peers. +// This function will panic indicating that there is a problem if request has been made. +func dummyRequestFromPeers(_ context.Context, req *network.Request) (*enode.ID, chan struct{}, error) { + panic(fmt.Sprintf("unexpected request: address %s, source %s", req.Addr.String(), req.Source.String())) +} + +//This test is a syncing test for nodes. +//One node is randomly selected to be the pivot node. +//A configurable number of chunks and nodes can be +//provided to the test, the number of chunks is uploaded +//to the pivot node, and we check that nodes get the chunks +//they are expected to store based on the syncing protocol. +//Number of chunks and nodes can be provided via commandline too. +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 { + chunkCounts := []int{4, 32} + nodeCounts := []int{32, 16} + + //if the `longrunning` flag has been provided + //run more test combinations + if *longrunning { + chunkCounts = []int{64, 128} + nodeCounts = []int{32, 64} + } + + 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": 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 + } + + store := state.NewInmemoryStore() + + r := NewRegistry(addr.ID(), delivery, netStore, store, &RegistryOptions{ + Retrieval: RetrievalDisabled, + Syncing: SyncingAutoSubscribe, + SyncUpdateDelay: 3 * time.Second, + }, nil) + + bucket.Store(bucketKeyRegistry, r) + + cleanup = func() { + r.Close() + clean() + } + + return r, cleanup, nil + }, +} + +func testSyncingViaGlobalSync(t *testing.T, chunkCount int, nodeCount int) { + sim := simulation.New(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[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 { + t.Fatal(err) + } + + ctx, cancelSimRun := context.WithTimeout(context.Background(), 2*time.Minute) + defer cancelSimRun() + + if _, err := sim.WaitTillHealthy(ctx); err != nil { + t.Fatal(err) + } + + result := runSim(conf, ctx, sim, chunkCount) + + if result.Error != nil { + t.Fatal(result.Error) + } + log.Info("Simulation ended") +} + +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) (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 + 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 + } + + //get the node at that index + //this is the node selected for upload + 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) + if err != nil { + return err + } + for _, h := range hashes { + evt := &simulations.Event{ + Type: EventTypeChunkCreated, + Node: sim.Net.GetNode(node.ID()), + Data: h.String(), + } + sim.Net.Events().Send(evt) + } + conf.hashes = append(conf.hashes, hashes...) + mapKeysToNodes(conf) + + // File retrieval check is repeated until all uploaded files are retrieved from all nodes + // or until the timeout is reached. + var globalStore mock.GlobalStorer + if *useMockStore { + globalStore = mockmem.NewGlobalStore() + } + 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 + } + evt := &simulations.Event{ + Type: EventTypeChunkArrived, + Node: sim.Net.GetNode(id), + Data: chunk.String(), + } + sim.Net.Events().Send(evt) + log.Debug(fmt.Sprintf("Chunk %s IS FOUND for id %s", chunk, id)) + } + } + return nil + } + }) +} + +//map chunk keys to addresses which are responsible +func mapKeysToNodes(conf *synctestConfig) { + nodemap := make(map[string][]int) + //build a pot for chunk hashes + np := pot.NewPot(nil, 0) + indexmap := make(map[string]int) + for i, a := range conf.addrs { + indexmap[string(a)] = i + np, _, _ = pot.Add(np, a, pof) + } + + 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)) + for i := 0; i < len(conf.hashes); i++ { + var a []byte + np.EachNeighbour([]byte(conf.hashes[i]), pof, func(val pot.Val, po int) bool { + // take the first address + a = val.([]byte) + return false + }) + + nns := ppmap[common.Bytes2Hex(a)].NNSet + nns = append(nns, a) + + for _, p := range nns { + nodemap[string(p)] = append(nodemap[string(p)], i) + } + } + for addr, chunks := range nodemap { + //this selects which chunks are expected to be found with the given node + conf.idToChunksMap[conf.addrToIDMap[addr]] = chunks + } + log.Debug(fmt.Sprintf("Map of expected chunks by ID: %v", conf.idToChunksMap)) +} + +//upload a file(chunks) to a single local node store +func uploadFileToSingleNodeStore(id enode.ID, chunkCount int, lstore *storage.LocalStore) ([]storage.Address, error) { + log.Debug(fmt.Sprintf("Uploading to node id: %s", id)) + fileStore := storage.NewFileStore(lstore, storage.NewFileStoreParams()) + size := chunkSize + var rootAddrs []storage.Address + for i := 0; i < chunkCount; i++ { + rk, wait, err := fileStore.Store(context.TODO(), testutil.RandomReader(i, size), int64(size), false) + if err != nil { + return nil, err + } + err = wait(context.TODO()) + if err != nil { + return nil, err + } + rootAddrs = append(rootAddrs, (rk)) + } + + return rootAddrs, nil +} diff --git a/swarm/network/stream/stream.go b/swarm/network/stream/stream.go new file mode 100644 index 0000000000..c7c489152a --- /dev/null +++ b/swarm/network/stream/stream.go @@ -0,0 +1,999 @@ +// 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 stream + +import ( + "context" + "errors" + "fmt" + "math" + "reflect" + "sync" + "time" + + "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/rpc" + "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/state" + "github.com/ethereum/go-ethereum/swarm/storage" +) + +const ( + Low uint8 = iota + Mid + High + Top + PriorityQueue = 4 // number of priority queues - Low, Mid, High, Top + PriorityQueueCap = 4096 // queue capacity + HashSize = 32 +) + +// Enumerate options for syncing and retrieval +type SyncingOption int +type RetrievalOption int + +// Syncing options +const ( + // Syncing disabled + SyncingDisabled SyncingOption = iota + // Register the client and the server but not subscribe + SyncingRegisterOnly + // 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) + 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 + RetrievalClientOnly + // 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 + api *API + skipCheck bool + clientMu sync.RWMutex + serverMu sync.RWMutex + peersMu sync.RWMutex + serverFuncs map[string]func(*Peer, string, bool) (Server, error) + clientFuncs map[string]func(*Peer, string, bool) (Client, error) + peers map[enode.ID]*Peer + delivery *Delivery + intervalsStore state.Store + 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 + 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, balance protocols.Balance) *Registry { + if options == nil { + options = &RegistryOptions{} + } + if options.SyncUpdateDelay <= 0 { + options.SyncUpdateDelay = 15 * time.Second + } + // check if retrieval has been disabled + retrieval := options.Retrieval != RetrievalDisabled + + quit := make(chan struct{}) + + streamer := &Registry{ + addr: localID, + skipCheck: options.SkipCheck, + serverFuncs: make(map[string]func(*Peer, string, bool) (Server, error)), + clientFuncs: make(map[string]func(*Peer, string, bool) (Client, error)), + peers: make(map[enode.ID]*Peer), + delivery: delivery, + 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 options.Retrieval == RetrievalEnabled { + streamer.RegisterServerFunc(swarmChunkServerStreamName, func(_ *Peer, _ string, live bool) (Server, error) { + if !live { + return nil, errors.New("only live retrieval requests supported") + } + return NewSwarmChunkServer(delivery.chunkStore), nil + }) + } + + // 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 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 options.Syncing == SyncingAutoSubscribe { + // latestIntC function ensures that + // - receiving from the in chan is not blocked by processing inside the for loop + // - the latest int value is delivered to the loop after the processing is done + // In context of NeighbourhoodDepthC: + // after the syncing is done updating inside the loop, we do not need to update on the intermediate + // depth changes, only to the latest one + latestIntC := func(in <-chan int) <-chan int { + out := make(chan int, 1) + + go func() { + defer close(out) + + for { + select { + case i, ok := <-in: + if !ok { + return + } + select { + case <-out: + default: + } + out <- i + case <-quit: + return + } + } + }() + + 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 + // 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() + + for depth := range depthC { + log.Debug("Kademlia neighbourhood depth change", "depth", depth) + + // Prevent too early sync subscriptions by waiting until there are no + // new peers connecting. Sync streams updating will be done after no + // peers are connected for at least SyncUpdateDelay period. + timer := time.NewTimer(options.SyncUpdateDelay) + // Hard limit to sync update delay, preventing long delays + // on a very dynamic network + maxTimer := time.NewTimer(3 * time.Minute) + loop: + for { + select { + case <-maxTimer.C: + // force syncing update when a hard timeout is reached + log.Trace("Sync subscriptions update on hard timeout") + // request for syncing subscription to new peers + streamer.updateSyncing() + break loop + case <-timer.C: + // start syncing as no new peers has been added to kademlia + // for some time + log.Trace("Sync subscriptions update") + // request for syncing subscription to new peers + streamer.updateSyncing() + break loop + case size := <-addressBookSizeC: + log.Trace("Kademlia address book size changed on depth change", "size", size) + // new peers has been added to kademlia, + // reset the timer to prevent early sync subscriptions + if !timer.Stop() { + <-timer.C + } + timer.Reset(options.SyncUpdateDelay) + case <-quit: + break loop + } + } + timer.Stop() + maxTimer.Stop() + } + }() + } + + 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() + defer r.clientMu.Unlock() + + r.clientFuncs[stream] = f +} + +// RegisterServer registers an outgoing streamer constructor +func (r *Registry) RegisterServerFunc(stream string, f func(*Peer, string, bool) (Server, error)) { + r.serverMu.Lock() + defer r.serverMu.Unlock() + + r.serverFuncs[stream] = f +} + +// GetClient accessor for incoming streamer constructors +func (r *Registry) GetClientFunc(stream string) (func(*Peer, string, bool) (Client, error), error) { + r.clientMu.RLock() + defer r.clientMu.RUnlock() + + f := r.clientFuncs[stream] + if f == nil { + return nil, fmt.Errorf("stream %v not registered", stream) + } + return f, nil +} + +// GetServer accessor for incoming streamer constructors +func (r *Registry) GetServerFunc(stream string) (func(*Peer, string, bool) (Server, error), error) { + r.serverMu.RLock() + defer r.serverMu.RUnlock() + + f := r.serverFuncs[stream] + if f == nil { + return nil, fmt.Errorf("stream %v not registered", stream) + } + return f, nil +} + +func (r *Registry) RequestSubscription(peerId enode.ID, s Stream, h *Range, prio uint8) error { + // check if the stream is registered + if _, err := r.GetServerFunc(s.Name); err != nil { + return err + } + + peer := r.getPeer(peerId) + if peer == nil { + return fmt.Errorf("peer not found %v", peerId) + } + + if _, err := peer.getServer(s); err != nil { + if e, ok := err.(*notFoundError); ok && e.t == "server" { + // request subscription only if the server for this stream is not created + log.Debug("RequestSubscription ", "peer", peerId, "stream", s, "history", h) + return peer.Send(context.TODO(), &RequestSubscriptionMsg{ + Stream: s, + History: h, + Priority: prio, + }) + } + return err + } + log.Trace("RequestSubscription: already subscribed", "peer", peerId, "stream", s, "history", h) + return nil +} + +// Subscribe initiates the streamer +func (r *Registry) Subscribe(peerId enode.ID, s Stream, h *Range, priority uint8) error { + // check if the stream is registered + if _, err := r.GetClientFunc(s.Name); err != nil { + return err + } + + peer := r.getPeer(peerId) + if peer == nil { + return fmt.Errorf("peer not found %v", peerId) + } + + var to uint64 + if !s.Live && h != nil { + to = h.To + } + + err := peer.setClientParams(s, newClientParams(priority, to)) + if err != nil { + return err + } + if s.Live && h != nil { + if err := peer.setClientParams( + getHistoryStream(s), + newClientParams(getHistoryPriority(priority), h.To), + ); err != nil { + return err + } + } + + msg := &SubscribeMsg{ + Stream: s, + History: h, + Priority: priority, + } + log.Debug("Subscribe ", "peer", peerId, "stream", s, "history", h) + + return peer.SendPriority(context.TODO(), msg, priority) +} + +func (r *Registry) Unsubscribe(peerId enode.ID, s Stream) error { + peer := r.getPeer(peerId) + if peer == nil { + return fmt.Errorf("peer not found %v", peerId) + } + + msg := &UnsubscribeMsg{ + Stream: s, + } + log.Debug("Unsubscribe ", "peer", peerId, "stream", s) + + if err := peer.Send(context.TODO(), msg); err != nil { + return err + } + return peer.removeClient(s) +} + +// Quit sends the QuitMsg to the peer to remove the +// stream peer client and terminate the streaming. +func (r *Registry) Quit(peerId enode.ID, s Stream) error { + peer := r.getPeer(peerId) + if peer == nil { + log.Debug("stream quit: peer not found", "peer", peerId, "stream", s) + // if the peer is not found, abort the request + return nil + } + + msg := &QuitMsg{ + Stream: s, + } + log.Debug("Quit ", "peer", peerId, "stream", s) + + return peer.Send(context.TODO(), msg) +} + +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() +} + +func (r *Registry) getPeer(peerId enode.ID) *Peer { + r.peersMu.RLock() + defer r.peersMu.RUnlock() + + return r.peers[peerId] +} + +func (r *Registry) setPeer(peer *Peer) { + r.peersMu.Lock() + r.peers[peer.ID()] = peer + metrics.GetOrRegisterGauge("registry.peers", nil).Update(int64(len(r.peers))) + r.peersMu.Unlock() +} + +func (r *Registry) deletePeer(peer *Peer) { + r.peersMu.Lock() + delete(r.peers, peer.ID()) + metrics.GetOrRegisterGauge("registry.peers", nil).Update(int64(len(r.peers))) + r.peersMu.Unlock() +} + +func (r *Registry) peersCount() (c int) { + r.peersMu.Lock() + c = len(r.peers) + r.peersMu.Unlock() + return +} + +// Run protocol run function +func (r *Registry) Run(p *network.BzzPeer) error { + sp := NewPeer(p.Peer, r) + r.setPeer(sp) + defer r.deletePeer(sp) + defer close(sp.quit) + defer sp.close() + + if r.autoRetrieval && !p.LightNode { + err := r.Subscribe(p.ID(), NewStream(swarmChunkServerStreamName, "", true), nil, Top) + if err != nil { + return err + } + } + + return sp.Run(sp.HandleMsg) +} + +// updateSyncing subscribes to SYNC streams by iterating over the +// kademlia connections and bins. If there are existing SYNC streams +// and they are no longer required after iteration, request to Quit +// them will be send to appropriate peers. +func (r *Registry) updateSyncing() { + kad := r.delivery.kad + // map of all SYNC streams for all peers + // used at the and of the function to remove servers + // that are not needed anymore + subs := make(map[enode.ID]map[Stream]struct{}) + r.peersMu.RLock() + for id, peer := range r.peers { + peer.serverMu.RLock() + for stream := range peer.servers { + if stream.Name == "SYNC" { + if _, ok := subs[id]; !ok { + subs[id] = make(map[Stream]struct{}) + } + subs[id][stream] = struct{}{} + } + } + peer.serverMu.RUnlock() + } + r.peersMu.RUnlock() + + // start requesting subscriptions from peers + r.requestPeerSubscriptions(kad, subs) + + // remove SYNC servers that do not need to be subscribed + for id, streams := range subs { + if len(streams) == 0 { + continue + } + peer := r.getPeer(id) + if peer == nil { + continue + } + for stream := range streams { + log.Debug("Remove sync server", "peer", id, "stream", stream) + err := r.Quit(peer.ID(), stream) + if err != nil && err != p2p.ErrShuttingDown { + log.Error("quit", "err", err, "peer", peer.ID(), "stream", stream) + } + } + } +} + +// 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, r.spec) + bp := network.NewBzzPeer(peer) + np := network.NewPeer(bp, r.delivery.kad) + r.delivery.kad.On(np) + defer r.delivery.kad.Off(np) + return r.Run(bp) +} + +// 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: + return p.handleSubscribeMsg(ctx, msg) + + case *SubscribeErrorMsg: + return p.handleSubscribeErrorMsg(msg) + + case *UnsubscribeMsg: + return p.handleUnsubscribeMsg(msg) + + case *OfferedHashesMsg: + return p.handleOfferedHashesMsg(ctx, msg) + + case *TakeoverProofMsg: + return p.handleTakeoverProofMsg(ctx, msg) + + case *WantedHashesMsg: + return p.handleWantedHashesMsg(ctx, msg) + + case *ChunkDeliveryMsgRetrieval: + // 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 + return p.streamer.delivery.handleChunkDeliveryMsg(ctx, p, ((*ChunkDeliveryMsg)(msg))) + + case *RetrieveRequestMsg: + return p.streamer.delivery.handleRetrieveRequestMsg(ctx, p, msg) + + case *RequestSubscriptionMsg: + return p.handleRequestSubscription(ctx, msg) + + case *QuitMsg: + return p.handleQuitMsg(msg) + + default: + return fmt.Errorf("unknown message type: %T", msg) + } +} + +type server struct { + Server + stream Stream + priority uint8 + currentBatch []byte + sessionIndex uint64 +} + +// setNextBatch adjusts passed interval based on session index and whether +// stream is live or history. It calls Server SetNextBatch with adjusted +// interval and returns batch hashes and their interval. +func (s *server) setNextBatch(from, to uint64) ([]byte, uint64, uint64, *HandoverProof, error) { + if s.stream.Live { + if from == 0 { + from = s.sessionIndex + } + if to <= from || from >= s.sessionIndex { + to = math.MaxUint64 + } + } else { + if (to < from && to != 0) || from > s.sessionIndex { + return nil, 0, 0, nil, nil + } + if to == 0 || to > s.sessionIndex { + to = s.sessionIndex + } + } + return s.SetNextBatch(from, to) +} + +// Server interface for outgoing peer Streamer +type Server interface { + // SessionIndex is called when a server is initialized + // to get the current cursor state of the stream data. + // Based on this index, live and history stream intervals + // will be adjusted before calling SetNextBatch. + SessionIndex() (uint64, error) + SetNextBatch(uint64, uint64) (hashes []byte, from uint64, to uint64, proof *HandoverProof, err error) + GetData(context.Context, []byte) ([]byte, error) + Close() +} + +type client struct { + Client + stream Stream + priority uint8 + sessionAt uint64 + to uint64 + next chan error + quit chan struct{} + + intervalsKey string + intervalsStore state.Store +} + +func peerStreamIntervalsKey(p *Peer, s Stream) string { + return p.ID().String() + s.String() +} + +func (c *client) AddInterval(start, end uint64) (err error) { + i := &intervals.Intervals{} + 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) { + i := &intervals.Intervals{} + err = c.intervalsStore.Get(c.intervalsKey, i) + if err != nil { + return 0, 0, err + } + start, end = i.Next() + return start, end, nil +} + +// Client interface for incoming peer Streamer +type Client interface { + NeedData(context.Context, []byte) func(context.Context) error + BatchDone(Stream, uint64, []byte, []byte) func() (*TakeoverProof, error) + Close() +} + +func (c *client) nextBatch(from uint64) (nextFrom uint64, nextTo uint64) { + if c.to > 0 && from >= c.to { + return 0, 0 + } + if c.stream.Live { + return from, 0 + } else if from >= c.sessionAt { + if c.to > 0 { + return from, c.to + } + return from, math.MaxUint64 + } + nextFrom, nextTo, err := c.NextInterval() + if err != nil { + log.Error("next intervals", "stream", c.stream) + return + } + if nextTo > c.to { + nextTo = c.to + } + if nextTo == 0 { + nextTo = c.sessionAt + } + return +} + +func (c *client) batchDone(p *Peer, req *OfferedHashesMsg, hashes []byte) error { + if tf := c.BatchDone(req.Stream, req.From, hashes, req.Root); tf != nil { + tp, err := tf() + if err != nil { + return err + } + + if err := p.SendPriority(context.TODO(), tp, c.priority); err != nil { + return err + } + if c.to > 0 && tp.Takeover.End >= c.to { + return p.streamer.Unsubscribe(p.Peer.ID(), req.Stream) + } + return nil + } + return c.AddInterval(req.From, req.To) +} + +func (c *client) close() { + select { + case <-c.quit: + default: + close(c.quit) + } + c.Close() +} + +// clientParams store parameters for the new client +// between a subscription and initial offered hashes request handling. +type clientParams struct { + priority uint8 + to uint64 + // signal when the client is created + clientCreatedC chan struct{} +} + +func newClientParams(priority uint8, to uint64) *clientParams { + return &clientParams{ + priority: priority, + to: to, + clientCreatedC: make(chan struct{}), + } +} + +func (c *clientParams) waitClient(ctx context.Context) error { + select { + case <-ctx.Done(): + return ctx.Err() + case <-c.clientCreatedC: + return nil + } +} + +func (c *clientParams) clientCreated() { + close(c.clientCreatedC) +} + +// 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: r.spec.Name, + Version: r.spec.Version, + Length: r.spec.Length(), + Run: r.runProtocol, + }, + } +} + +func (r *Registry) APIs() []rpc.API { + return []rpc.API{ + { + Namespace: "stream", + Version: "3.0", + Service: r.api, + Public: true, + }, + } +} + +func (r *Registry) Start(server *p2p.Server) error { + log.Info("Streamer started") + return nil +} + +func (r *Registry) Stop() error { + return nil +} + +type Range struct { + From, To uint64 +} + +func NewRange(from, to uint64) *Range { + return &Range{ + From: from, + To: to, + } +} + +func (r *Range) String() string { + return fmt.Sprintf("%v-%v", r.From, r.To) +} + +func getHistoryPriority(priority uint8) uint8 { + if priority == 0 { + return 0 + } + return priority - 1 +} + +func getHistoryStream(s Stream) Stream { + return NewStream(s.Name, s.Key, false) +} + +type API struct { + streamer *Registry +} + +func NewAPI(r *Registry) *API { + return &API{ + streamer: r, + } +} + +func (api *API) SubscribeStream(peerId enode.ID, s Stream, history *Range, priority uint8) error { + return api.streamer.Subscribe(peerId, s, history, priority) +} + +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/swarm/network/stream/streamer_test.go b/swarm/network/stream/streamer_test.go new file mode 100644 index 0000000000..56e5e89032 --- /dev/null +++ b/swarm/network/stream/streamer_test.go @@ -0,0 +1,1369 @@ +// 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 stream + +import ( + "bytes" + "context" + "errors" + "fmt" + "os" + "strconv" + "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/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(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) + if err == nil || err.Error() != "stream foo not registered" { + t.Fatalf("Expected error %v, got %v", "stream foo not registered", err) + } +} + +func TestStreamerRequestSubscription(t *testing.T) { + 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) + if err == nil || err.Error() != "stream foo not registered" { + t.Fatalf("Expected error %v, got %v", "stream foo not registered", err) + } +} + +var ( + hash0 = sha3.Sum256([]byte{0}) + hash1 = sha3.Sum256([]byte{1}) + hash2 = sha3.Sum256([]byte{2}) + hashesTmp = append(hash0[:], hash1[:]...) + hashes = append(hashesTmp, hash2[:]...) + corruptHashes = append(hashes[:40]) +) + +type testClient struct { + t string + wait0 chan bool + wait2 chan bool + batchDone chan bool + receivedHashes map[string][]byte +} + +func newTestClient(t string) *testClient { + return &testClient{ + t: t, + wait0: make(chan bool), + wait2: make(chan bool), + batchDone: make(chan bool), + receivedHashes: make(map[string][]byte), + } +} + +func (self *testClient) NeedData(ctx context.Context, hash []byte) func(context.Context) error { + self.receivedHashes[string(hash)] = hash + if bytes.Equal(hash, hash0[:]) { + return func(context.Context) error { + <-self.wait0 + return nil + } + } else if bytes.Equal(hash, hash2[:]) { + return func(context.Context) error { + <-self.wait2 + return nil + } + } + return nil +} + +func (self *testClient) BatchDone(Stream, uint64, []byte, []byte) func() (*TakeoverProof, error) { + close(self.batchDone) + return nil +} + +func (self *testClient) Close() {} + +type testServer struct { + t string + sessionIndex uint64 +} + +func newTestServer(t string, sessionIndex uint64) *testServer { + return &testServer{ + t: t, + sessionIndex: sessionIndex, + } +} + +func (s *testServer) SessionIndex() (uint64, error) { + return s.sessionIndex, nil +} + +func (self *testServer) SetNextBatch(from uint64, to uint64) ([]byte, uint64, uint64, *HandoverProof, error) { + return make([]byte, HashSize), from + 1, to + 1, nil, nil +} + +func (self *testServer) GetData(context.Context, []byte) ([]byte, error) { + return nil, nil +} + +func (self *testServer) Close() { +} + +func TestStreamerDownstreamSubscribeUnsubscribeMsgExchange(t *testing.T) { + 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 + }) + + node := tester.Nodes[0] + + stream := NewStream("foo", "", true) + err = streamer.Subscribe(node.ID(), stream, NewRange(5, 8), Top) + if err != nil { + t.Fatalf("Expected no error, got %v", err) + } + + err = tester.TestExchanges( + p2ptest.Exchange{ + Label: "Subscribe message", + Expects: []p2ptest.Expect{ + { + Code: 4, + Msg: &SubscribeMsg{ + Stream: stream, + History: NewRange(5, 8), + Priority: Top, + }, + Peer: node.ID(), + }, + }, + }, + // trigger OfferedHashesMsg to actually create the client + p2ptest.Exchange{ + Label: "OfferedHashes message", + Triggers: []p2ptest.Trigger{ + { + Code: 1, + Msg: &OfferedHashesMsg{ + HandoverProof: &HandoverProof{ + Handover: &Handover{}, + }, + Hashes: hashes, + From: 5, + To: 8, + Stream: stream, + }, + Peer: node.ID(), + }, + }, + Expects: []p2ptest.Expect{ + { + Code: 2, + Msg: &WantedHashesMsg{ + Stream: stream, + Want: []byte{5}, + From: 9, + To: 0, + }, + Peer: node.ID(), + }, + }, + }, + ) + if err != nil { + t.Fatal(err) + } + + err = streamer.Unsubscribe(node.ID(), stream) + if err != nil { + t.Fatalf("Expected no error, got %v", err) + } + + err = tester.TestExchanges(p2ptest.Exchange{ + Label: "Unsubscribe message", + Expects: []p2ptest.Expect{ + { + Code: 0, + Msg: &UnsubscribeMsg{ + Stream: stream, + }, + Peer: node.ID(), + }, + }, + }) + + if err != nil { + t.Fatal(err) + } +} + +func TestStreamerUpstreamSubscribeUnsubscribeMsgExchange(t *testing.T) { + tester, streamer, _, teardown, err := newStreamerTester(nil) + if err != nil { + t.Fatal(err) + } + defer teardown() + + stream := NewStream("foo", "", false) + + streamer.RegisterServerFunc("foo", func(p *Peer, t string, live bool) (Server, error) { + return newTestServer(t, 10), nil + }) + + node := tester.Nodes[0] + + err = tester.TestExchanges(p2ptest.Exchange{ + Label: "Subscribe message", + Triggers: []p2ptest.Trigger{ + { + Code: 4, + Msg: &SubscribeMsg{ + Stream: stream, + History: NewRange(5, 8), + Priority: Top, + }, + Peer: node.ID(), + }, + }, + Expects: []p2ptest.Expect{ + { + Code: 1, + Msg: &OfferedHashesMsg{ + Stream: stream, + HandoverProof: &HandoverProof{ + Handover: &Handover{}, + }, + Hashes: make([]byte, HashSize), + From: 6, + To: 9, + }, + Peer: node.ID(), + }, + }, + }) + + if err != nil { + t.Fatal(err) + } + + err = tester.TestExchanges(p2ptest.Exchange{ + Label: "unsubscribe message", + Triggers: []p2ptest.Trigger{ + { + Code: 0, + Msg: &UnsubscribeMsg{ + Stream: stream, + }, + Peer: node.ID(), + }, + }, + }) + + if err != nil { + t.Fatal(err) + } +} + +func TestStreamerUpstreamSubscribeUnsubscribeMsgExchangeLive(t *testing.T) { + tester, streamer, _, teardown, err := newStreamerTester(nil) + if err != nil { + t.Fatal(err) + } + defer teardown() + + stream := NewStream("foo", "", true) + + streamer.RegisterServerFunc("foo", func(p *Peer, t string, live bool) (Server, error) { + return newTestServer(t, 0), nil + }) + + node := tester.Nodes[0] + + err = tester.TestExchanges(p2ptest.Exchange{ + Label: "Subscribe message", + Triggers: []p2ptest.Trigger{ + { + Code: 4, + Msg: &SubscribeMsg{ + Stream: stream, + Priority: Top, + }, + Peer: node.ID(), + }, + }, + Expects: []p2ptest.Expect{ + { + Code: 1, + Msg: &OfferedHashesMsg{ + Stream: stream, + HandoverProof: &HandoverProof{ + Handover: &Handover{}, + }, + Hashes: make([]byte, HashSize), + From: 1, + To: 0, + }, + Peer: node.ID(), + }, + }, + }) + + if err != nil { + t.Fatal(err) + } + + err = tester.TestExchanges(p2ptest.Exchange{ + Label: "unsubscribe message", + Triggers: []p2ptest.Trigger{ + { + Code: 0, + Msg: &UnsubscribeMsg{ + Stream: stream, + }, + Peer: node.ID(), + }, + }, + }) + + if err != nil { + t.Fatal(err) + } +} + +func TestStreamerUpstreamSubscribeErrorMsgExchange(t *testing.T) { + 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 + }) + + stream := NewStream("bar", "", true) + + node := tester.Nodes[0] + + err = tester.TestExchanges(p2ptest.Exchange{ + Label: "Subscribe message", + Triggers: []p2ptest.Trigger{ + { + Code: 4, + Msg: &SubscribeMsg{ + Stream: stream, + History: NewRange(5, 8), + Priority: Top, + }, + Peer: node.ID(), + }, + }, + Expects: []p2ptest.Expect{ + { + Code: 7, + Msg: &SubscribeErrorMsg{ + Error: "stream bar not registered", + }, + Peer: node.ID(), + }, + }, + }) + + if err != nil { + t.Fatal(err) + } +} + +func TestStreamerUpstreamSubscribeLiveAndHistory(t *testing.T) { + tester, streamer, _, teardown, err := newStreamerTester(nil) + if err != nil { + t.Fatal(err) + } + defer teardown() + + stream := NewStream("foo", "", true) + + streamer.RegisterServerFunc("foo", func(p *Peer, t string, live bool) (Server, error) { + return newTestServer(t, 10), nil + }) + + node := tester.Nodes[0] + + err = tester.TestExchanges(p2ptest.Exchange{ + Label: "Subscribe message", + Triggers: []p2ptest.Trigger{ + { + Code: 4, + Msg: &SubscribeMsg{ + Stream: stream, + History: NewRange(5, 8), + Priority: Top, + }, + Peer: node.ID(), + }, + }, + Expects: []p2ptest.Expect{ + { + Code: 1, + Msg: &OfferedHashesMsg{ + Stream: NewStream("foo", "", false), + HandoverProof: &HandoverProof{ + Handover: &Handover{}, + }, + Hashes: make([]byte, HashSize), + From: 6, + To: 9, + }, + Peer: node.ID(), + }, + { + Code: 1, + Msg: &OfferedHashesMsg{ + Stream: stream, + HandoverProof: &HandoverProof{ + Handover: &Handover{}, + }, + From: 11, + To: 0, + Hashes: make([]byte, HashSize), + }, + Peer: node.ID(), + }, + }, + }) + + if err != nil { + t.Fatal(err) + } +} + +func TestStreamerDownstreamCorruptHashesMsgExchange(t *testing.T) { + tester, streamer, _, teardown, err := newStreamerTester(nil) + if err != nil { + t.Fatal(err) + } + defer teardown() + + stream := NewStream("foo", "", true) + + var tc *testClient + + streamer.RegisterClientFunc("foo", func(p *Peer, t string, live bool) (Client, error) { + tc = newTestClient(t) + return tc, nil + }) + + node := tester.Nodes[0] + + err = streamer.Subscribe(node.ID(), stream, NewRange(5, 8), Top) + if err != nil { + t.Fatalf("Expected no error, got %v", err) + } + + err = tester.TestExchanges(p2ptest.Exchange{ + Label: "Subscribe message", + Expects: []p2ptest.Expect{ + { + Code: 4, + Msg: &SubscribeMsg{ + Stream: stream, + History: NewRange(5, 8), + Priority: Top, + }, + Peer: node.ID(), + }, + }, + }, + p2ptest.Exchange{ + Label: "Corrupt offered hash message", + Triggers: []p2ptest.Trigger{ + { + Code: 1, + Msg: &OfferedHashesMsg{ + HandoverProof: &HandoverProof{ + Handover: &Handover{}, + }, + Hashes: corruptHashes, + From: 5, + To: 8, + Stream: stream, + }, + Peer: node.ID(), + }, + }, + }) + if err != nil { + t.Fatal(err) + } + + expectedError := errors.New("Message handler error: (msg code 1): error invalid hashes length (len: 40)") + if err := tester.TestDisconnected(&p2ptest.Disconnect{Peer: node.ID(), Error: expectedError}); err != nil { + t.Fatal(err) + } +} + +func TestStreamerDownstreamOfferedHashesMsgExchange(t *testing.T) { + tester, streamer, _, teardown, err := newStreamerTester(nil) + if err != nil { + t.Fatal(err) + } + defer teardown() + + stream := NewStream("foo", "", true) + + var tc *testClient + + streamer.RegisterClientFunc("foo", func(p *Peer, t string, live bool) (Client, error) { + tc = newTestClient(t) + return tc, nil + }) + + node := tester.Nodes[0] + + err = streamer.Subscribe(node.ID(), stream, NewRange(5, 8), Top) + if err != nil { + t.Fatalf("Expected no error, got %v", err) + } + + err = tester.TestExchanges(p2ptest.Exchange{ + Label: "Subscribe message", + Expects: []p2ptest.Expect{ + { + Code: 4, + Msg: &SubscribeMsg{ + Stream: stream, + History: NewRange(5, 8), + Priority: Top, + }, + Peer: node.ID(), + }, + }, + }, + p2ptest.Exchange{ + Label: "WantedHashes message", + Triggers: []p2ptest.Trigger{ + { + Code: 1, + Msg: &OfferedHashesMsg{ + HandoverProof: &HandoverProof{ + Handover: &Handover{}, + }, + Hashes: hashes, + From: 5, + To: 8, + Stream: stream, + }, + Peer: node.ID(), + }, + }, + Expects: []p2ptest.Expect{ + { + Code: 2, + Msg: &WantedHashesMsg{ + Stream: stream, + Want: []byte{5}, + From: 9, + To: 0, + }, + Peer: node.ID(), + }, + }, + }) + if err != nil { + t.Fatal(err) + } + + if len(tc.receivedHashes) != 3 { + t.Fatalf("Expected number of received hashes %v, got %v", 3, len(tc.receivedHashes)) + } + + close(tc.wait0) + + timeout := time.NewTimer(100 * time.Millisecond) + defer timeout.Stop() + + select { + case <-tc.batchDone: + t.Fatal("batch done early") + case <-timeout.C: + } + + close(tc.wait2) + + timeout2 := time.NewTimer(10000 * time.Millisecond) + defer timeout2.Stop() + + select { + case <-tc.batchDone: + case <-timeout2.C: + t.Fatal("timeout waiting batchdone call") + } + +} + +func TestStreamerRequestSubscriptionQuitMsgExchange(t *testing.T) { + 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 + }) + + node := tester.Nodes[0] + + stream := NewStream("foo", "", true) + err = streamer.RequestSubscription(node.ID(), stream, NewRange(5, 8), Top) + if err != nil { + t.Fatalf("Expected no error, got %v", err) + } + + err = tester.TestExchanges( + p2ptest.Exchange{ + Label: "RequestSubscription message", + Expects: []p2ptest.Expect{ + { + Code: 8, + Msg: &RequestSubscriptionMsg{ + Stream: stream, + History: NewRange(5, 8), + Priority: Top, + }, + Peer: node.ID(), + }, + }, + }, + p2ptest.Exchange{ + Label: "Subscribe message", + Triggers: []p2ptest.Trigger{ + { + Code: 4, + Msg: &SubscribeMsg{ + Stream: stream, + History: NewRange(5, 8), + Priority: Top, + }, + Peer: node.ID(), + }, + }, + Expects: []p2ptest.Expect{ + { + Code: 1, + Msg: &OfferedHashesMsg{ + Stream: NewStream("foo", "", false), + HandoverProof: &HandoverProof{ + Handover: &Handover{}, + }, + Hashes: make([]byte, HashSize), + From: 6, + To: 9, + }, + Peer: node.ID(), + }, + { + Code: 1, + Msg: &OfferedHashesMsg{ + Stream: stream, + HandoverProof: &HandoverProof{ + Handover: &Handover{}, + }, + From: 11, + To: 0, + Hashes: make([]byte, HashSize), + }, + Peer: node.ID(), + }, + }, + }, + ) + if err != nil { + t.Fatal(err) + } + + err = streamer.Quit(node.ID(), stream) + if err != nil { + t.Fatalf("Expected no error, got %v", err) + } + + err = tester.TestExchanges(p2ptest.Exchange{ + Label: "Quit message", + Expects: []p2ptest.Expect{ + { + Code: 9, + Msg: &QuitMsg{ + Stream: stream, + }, + Peer: node.ID(), + }, + }, + }) + + if err != nil { + t.Fatal(err) + } + + historyStream := getHistoryStream(stream) + + err = streamer.Quit(node.ID(), historyStream) + if err != nil { + t.Fatalf("Expected no error, got %v", err) + } + + err = tester.TestExchanges(p2ptest.Exchange{ + Label: "Quit message", + Expects: []p2ptest.Expect{ + { + Code: 9, + Msg: &QuitMsg{ + Stream: historyStream, + }, + Peer: node.ID(), + }, + }, + }) + + if err != nil { + t.Fatal(err) + } +} + +// TestMaxPeerServersWithUnsubscribe creates a registry with a limited +// number of stream servers, and performs a test with subscriptions and +// unsubscriptions, checking if unsubscriptions will remove streams, +// leaving place for new streams. +func TestMaxPeerServersWithUnsubscribe(t *testing.T) { + var maxPeerServers = 6 + tester, streamer, _, teardown, err := newStreamerTester(&RegistryOptions{ + Retrieval: RetrievalDisabled, + Syncing: SyncingDisabled, + MaxPeerServers: maxPeerServers, + }) + 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 + }) + + node := tester.Nodes[0] + + for i := 0; i < maxPeerServers+10; i++ { + stream := NewStream("foo", strconv.Itoa(i), true) + + err = tester.TestExchanges(p2ptest.Exchange{ + Label: "Subscribe message", + Triggers: []p2ptest.Trigger{ + { + Code: 4, + Msg: &SubscribeMsg{ + Stream: stream, + Priority: Top, + }, + Peer: node.ID(), + }, + }, + Expects: []p2ptest.Expect{ + { + Code: 1, + Msg: &OfferedHashesMsg{ + Stream: stream, + HandoverProof: &HandoverProof{ + Handover: &Handover{}, + }, + Hashes: make([]byte, HashSize), + From: 1, + To: 0, + }, + Peer: node.ID(), + }, + }, + }) + + if err != nil { + t.Fatal(err) + } + + err = tester.TestExchanges(p2ptest.Exchange{ + Label: "unsubscribe message", + Triggers: []p2ptest.Trigger{ + { + Code: 0, + Msg: &UnsubscribeMsg{ + Stream: stream, + }, + Peer: node.ID(), + }, + }, + }) + + if err != nil { + t.Fatal(err) + } + } +} + +// TestMaxPeerServersWithoutUnsubscribe creates a registry with a limited +// number of stream servers, and performs subscriptions to detect subscriptions +// error message exchange. +func TestMaxPeerServersWithoutUnsubscribe(t *testing.T) { + var maxPeerServers = 6 + tester, streamer, _, teardown, err := newStreamerTester(&RegistryOptions{ + MaxPeerServers: maxPeerServers, + }) + 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 + }) + + node := tester.Nodes[0] + + for i := 0; i < maxPeerServers+10; i++ { + stream := NewStream("foo", strconv.Itoa(i), true) + + if i >= maxPeerServers { + err = tester.TestExchanges(p2ptest.Exchange{ + Label: "Subscribe message", + Triggers: []p2ptest.Trigger{ + { + Code: 4, + Msg: &SubscribeMsg{ + Stream: stream, + Priority: Top, + }, + Peer: node.ID(), + }, + }, + Expects: []p2ptest.Expect{ + { + Code: 7, + Msg: &SubscribeErrorMsg{ + Error: ErrMaxPeerServers.Error(), + }, + Peer: node.ID(), + }, + }, + }) + + if err != nil { + t.Fatal(err) + } + continue + } + + err = tester.TestExchanges(p2ptest.Exchange{ + Label: "Subscribe message", + Triggers: []p2ptest.Trigger{ + { + Code: 4, + Msg: &SubscribeMsg{ + Stream: stream, + Priority: Top, + }, + Peer: node.ID(), + }, + }, + Expects: []p2ptest.Expect{ + { + Code: 1, + Msg: &OfferedHashesMsg{ + Stream: stream, + HandoverProof: &HandoverProof{ + Handover: &Handover{}, + }, + Hashes: make([]byte, HashSize), + From: 1, + To: 0, + }, + Peer: node.ID(), + }, + }, + }) + + if err != nil { + t.Fatal(err) + } + } +} + +//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 { + 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() + + // upload a snapshot + err := sim.UploadSnapshot(fmt.Sprintf("testing/snapshot_%d.json", nodeCount)) + if err != nil { + t.Fatal(err) + } + + // setup the filter for SubscribeMsg + msgs := sim.PeerEvents( + context.Background(), + sim.NodeIDs(), + simulation.NewPeerEventsFilter().ReceivedMessages().Protocol("stream").MsgCode(subscribeMsgCode), + ) + + // 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 := time.Duration(nodeCount/16) * time.Second + if *longrunning { + waitDuration = syncUpdateDelay + } + 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() + if realCount != emc { + return fmt.Errorf("Real subscriptions and expected amount don't match; real: %d, expected: %d", realCount, 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/swarm/network/stream/syncer.go b/swarm/network/stream/syncer.go new file mode 100644 index 0000000000..5f03dcff77 --- /dev/null +++ b/swarm/network/stream/syncer.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 stream + +import ( + "context" + "strconv" + "time" + + "github.com/ethereum/go-ethereum/metrics" + "github.com/ethereum/go-ethereum/swarm/log" + "github.com/ethereum/go-ethereum/swarm/storage" +) + +const ( + BatchSize = 128 +) + +// SwarmSyncerServer implements an Server for history syncing on bins +// offered streams: +// * live request delivery with or without checkback +// * (live/non-live historical) chunk syncing per proximity bin +type SwarmSyncerServer struct { + po uint8 + store storage.SyncChunkStore + quit chan struct{} +} + +// NewSwarmSyncerServer is constructor for SwarmSyncerServer +func NewSwarmSyncerServer(po uint8, syncChunkStore storage.SyncChunkStore) (*SwarmSyncerServer, error) { + return &SwarmSyncerServer{ + po: po, + store: syncChunkStore, + quit: make(chan struct{}), + }, nil +} + +func RegisterSwarmSyncerServer(streamer *Registry, syncChunkStore storage.SyncChunkStore) { + streamer.RegisterServerFunc("SYNC", func(_ *Peer, t string, _ bool) (Server, error) { + po, err := ParseSyncBinKey(t) + if err != nil { + return nil, err + } + return NewSwarmSyncerServer(po, syncChunkStore) + }) + // streamer.RegisterServerFunc(stream, func(p *Peer) (Server, error) { + // return NewOutgoingProvableSwarmSyncer(po, db) + // }) +} + +// Close needs to be called on a stream server +func (s *SwarmSyncerServer) Close() { + close(s.quit) +} + +// GetData retrieves the actual chunk from netstore +func (s *SwarmSyncerServer) GetData(ctx context.Context, key []byte) ([]byte, error) { + chunk, err := s.store.Get(ctx, storage.Address(key)) + if err != nil { + return nil, err + } + return chunk.Data(), nil +} + +// SessionIndex returns current storage bin (po) index. +func (s *SwarmSyncerServer) SessionIndex() (uint64, error) { + return s.store.BinIndex(s.po), nil +} + +// GetBatch retrieves the next batch of hashes from the dbstore +func (s *SwarmSyncerServer) SetNextBatch(from, to uint64) ([]byte, uint64, uint64, *HandoverProof, error) { + var batch []byte + i := 0 + + var ticker *time.Ticker + defer func() { + if ticker != nil { + ticker.Stop() + } + }() + var wait bool + for { + if wait { + if ticker == nil { + ticker = time.NewTicker(1000 * time.Millisecond) + } + select { + case <-ticker.C: + case <-s.quit: + return nil, 0, 0, nil, nil + } + } + + 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 + return i < BatchSize + }) + if err != nil { + return nil, 0, 0, nil, err + } + if len(batch) > 0 { + break + } + wait = true + } + + log.Trace("Swarm syncer offer batch", "po", s.po, "len", i, "from", from, "to", to, "current store count", s.store.BinIndex(s.po)) + return batch, from, to, nil, nil +} + +// SwarmSyncerClient +type SwarmSyncerClient struct { + store storage.SyncChunkStore + peer *Peer + stream Stream +} + +// NewSwarmSyncerClient is a contructor for provable data exchange syncer +func NewSwarmSyncerClient(p *Peer, store storage.SyncChunkStore, stream Stream) (*SwarmSyncerClient, error) { + return &SwarmSyncerClient{ + store: store, + peer: p, + stream: stream, + }, nil +} + +// // NewIncomingProvableSwarmSyncer is a contructor for provable data exchange syncer +// func NewIncomingProvableSwarmSyncer(po int, priority int, index uint64, sessionAt uint64, intervals []uint64, sessionRoot storage.Address, chunker *storage.PyramidChunker, store storage.ChunkStore, p Peer) *SwarmSyncerClient { +// retrieveC := make(storage.Chunk, chunksCap) +// RunChunkRequestor(p, retrieveC) +// storeC := make(storage.Chunk, chunksCap) +// RunChunkStorer(store, storeC) +// s := &SwarmSyncerClient{ +// po: po, +// priority: priority, +// sessionAt: sessionAt, +// start: index, +// end: index, +// nextC: make(chan struct{}, 1), +// intervals: intervals, +// sessionRoot: sessionRoot, +// sessionReader: chunker.Join(sessionRoot, retrieveC), +// retrieveC: retrieveC, +// storeC: storeC, +// } +// return s +// } + +// // StartSyncing is called on the Peer to start the syncing process +// // the idea is that it is called only after kademlia is close to healthy +// func StartSyncing(s *Streamer, peerId enode.ID, po uint8, nn bool) { +// lastPO := po +// if nn { +// lastPO = maxPO +// } +// +// for i := po; i <= lastPO; i++ { +// s.Subscribe(peerId, "SYNC", newSyncLabel("LIVE", po), 0, 0, High, true) +// s.Subscribe(peerId, "SYNC", newSyncLabel("HISTORY", po), 0, 0, Mid, false) +// } +// } + +// RegisterSwarmSyncerClient registers the client constructor function for +// to handle incoming sync streams +func RegisterSwarmSyncerClient(streamer *Registry, store storage.SyncChunkStore) { + streamer.RegisterClientFunc("SYNC", func(p *Peer, t string, live bool) (Client, error) { + return NewSwarmSyncerClient(p, store, NewStream("SYNC", t, live)) + }) +} + +// NeedData +func (s *SwarmSyncerClient) NeedData(ctx context.Context, key []byte) (wait func(context.Context) error) { + return s.store.FetchFunc(ctx, key) +} + +// BatchDone +func (s *SwarmSyncerClient) BatchDone(stream Stream, from uint64, hashes []byte, root []byte) func() (*TakeoverProof, error) { + // TODO: reenable this with putter/getter refactored code + // if s.chunker != nil { + // return func() (*TakeoverProof, error) { return s.TakeoverProof(stream, from, hashes, root) } + // } + return nil +} + +func (s *SwarmSyncerClient) Close() {} + +// base for parsing and formating sync bin key +// it must be 2 <= base <= 36 +const syncBinKeyBase = 36 + +// FormatSyncBinKey returns a string representation of +// Kademlia bin number to be used as key for SYNC stream. +func FormatSyncBinKey(bin uint8) string { + return strconv.FormatUint(uint64(bin), syncBinKeyBase) +} + +// ParseSyncBinKey parses the string representation +// and returns the Kademlia bin number. +func ParseSyncBinKey(s string) (uint8, error) { + bin, err := strconv.ParseUint(s, syncBinKeyBase, 8) + if err != nil { + return 0, err + } + return uint8(bin), nil +} diff --git a/swarm/network/stream/syncer_test.go b/swarm/network/stream/syncer_test.go new file mode 100644 index 0000000000..07586714e1 --- /dev/null +++ b/swarm/network/stream/syncer_test.go @@ -0,0 +1,355 @@ +// 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 stream + +import ( + "context" + "errors" + "fmt" + "io/ioutil" + "math" + "os" + "sync" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/node" + "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/storage/mock" + "github.com/ethereum/go-ethereum/swarm/testutil" +) + +const dataChunkCount = 200 + +func TestSyncerSimulation(t *testing.T) { + 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 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() + + datadir, err = ioutil.TempDir("", "localMockStore-"+id.TerminalString()) + if err != nil { + return nil, "", err + } + params.Init(datadir) + params.BaseKey = addr.Over() + lstore, err = storage.NewLocalStore(params, mockStore) + if err != nil { + return nil, "", err + } + return lstore, datadir, nil +} + +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) { + addr := network.NewAddr(ctx.Config.Node()) + //hack to put addresses in same space + addr.OAddr[0] = byte(0) + + 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, err + } + store, err = state.NewDBStore(dir) + if err != nil { + return nil, nil, err + } + } else { + store = state.NewInmemoryStore() + } + + r := NewRegistry(addr.ID(), delivery, netStore, store, &RegistryOptions{ + Retrieval: RetrievalDisabled, + Syncing: SyncingAutoSubscribe, + SkipCheck: skipCheck, + }, nil) + + cleanup = func() { + r.Close() + clean() + if dir != "" { + os.RemoveAll(dir) + } + } + + return r, cleanup, nil + }, + }) + defer sim.Close() + + // create context for simulation run + timeout := 30 * time.Second + ctx, cancel := context.WithTimeout(context.Background(), timeout) + // defer cancel should come before defer simulation teardown + defer cancel() + + _, err := sim.AddNodesAndConnectChain(nodes) + if err != nil { + t.Fatal(err) + } + result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) (err error) { + nodeIDs := sim.UpNodeIDs() + + nodeIndex := make(map[enode.ID]int) + for i, id := range nodeIDs { + nodeIndex[id] = i + } + + disconnected := watchDisconnections(ctx, sim) + defer func() { + if err != nil && disconnected.bool() { + err = errors.New("disconnect events received") + } + }() + + // each node Subscribes to each other's swarmChunkServerStreamName + for j := 0; j < nodes-1; j++ { + id := nodeIDs[j] + client, err := sim.Net.GetNode(id).Client() + if err != nil { + 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) + if err != nil { + return err + } + if j > 0 || nodes == 2 { + item, ok := sim.NodeItem(nodeIDs[j], bucketKeyFileStore) + if !ok { + return fmt.Errorf("No filestore") + } + fileStore := item.(*storage.FileStore) + size := chunkCount * chunkSize + _, wait, err := fileStore.Store(ctx, testutil.RandomReader(j, size), int64(size), false) + if err != nil { + return fmt.Errorf("fileStore.Store: %v", err) + } + wait(ctx) + } + } + // here we distribute chunks of a random file into stores 1...nodes + // collect hashes in po 1 bin for each node + hashes := make([][]storage.Address, nodes) + totalHashes := 0 + hashCounts := make([]int, nodes) + for i := nodes - 1; i >= 0; i-- { + if i < nodes-1 { + hashCounts[i] = hashCounts[i+1] + } + item, ok := sim.NodeItem(nodeIDs[i], bucketKeyDB) + if !ok { + return fmt.Errorf("No DB") + } + netStore := item.(*storage.NetStore) + netStore.Iterator(0, math.MaxUint64, po, func(addr storage.Address, index uint64) bool { + hashes[i] = append(hashes[i], addr) + totalHashes++ + hashCounts[i]++ + return true + }) + } + var total, found int + for _, node := range nodeIDs { + i := nodeIndex[node] + + for j := i; j < nodes; j++ { + total += len(hashes[j]) + for _, key := range hashes[j] { + item, ok := sim.NodeItem(nodeIDs[j], bucketKeyDB) + if !ok { + return fmt.Errorf("No DB") + } + db := item.(*storage.NetStore) + _, err := db.Get(ctx, key) + if err == nil { + found++ + } + } + } + log.Debug("sync check", "node", node, "index", i, "bin", po, "found", found, "total", total) + } + if total == found && total > 0 { + return nil + } + return fmt.Errorf("Total not equallying found: total is %d", total) + }) + + if result.Error != nil { + 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/swarm/network/stream/testing/snapshot_128.json b/swarm/network/stream/testing/snapshot_128.json new file mode 100644 index 0000000000..d25fa51c01 --- /dev/null +++ b/swarm/network/stream/testing/snapshot_128.json @@ -0,0 +1 @@ +{"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/swarm/network/stream/testing/snapshot_16.json b/swarm/network/stream/testing/snapshot_16.json new file mode 100644 index 0000000000..e209f568f6 --- /dev/null +++ b/swarm/network/stream/testing/snapshot_16.json @@ -0,0 +1 @@ +{"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/swarm/network/stream/testing/snapshot_256.json b/swarm/network/stream/testing/snapshot_256.json new file mode 100644 index 0000000000..5e400d9245 --- /dev/null +++ b/swarm/network/stream/testing/snapshot_256.json @@ -0,0 +1 @@ +{"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/swarm/network/stream/testing/snapshot_32.json b/swarm/network/stream/testing/snapshot_32.json new file mode 100644 index 0000000000..527474d0aa --- /dev/null +++ b/swarm/network/stream/testing/snapshot_32.json @@ -0,0 +1 @@ +{"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/swarm/network/stream/testing/snapshot_4.json b/swarm/network/stream/testing/snapshot_4.json new file mode 100644 index 0000000000..81afb03f11 --- /dev/null +++ b/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/swarm/network/stream/testing/snapshot_64.json b/swarm/network/stream/testing/snapshot_64.json new file mode 100644 index 0000000000..715485564a --- /dev/null +++ b/swarm/network/stream/testing/snapshot_64.json @@ -0,0 +1 @@ +{"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/swarm/network/stream/visualized_snapshot_sync_sim_test.go b/swarm/network/stream/visualized_snapshot_sync_sim_test.go new file mode 100644 index 0000000000..5a54ad0a8c --- /dev/null +++ b/swarm/network/stream/visualized_snapshot_sync_sim_test.go @@ -0,0 +1,342 @@ +// 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 ( + "bytes" + "context" + "errors" + "fmt" + "io" + "sync" + "testing" + "time" + + "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/protocols" + "github.com/ethereum/go-ethereum/p2p/simulations" + "github.com/ethereum/go-ethereum/p2p/simulations/adapters" + "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/swarm/log" + "github.com/ethereum/go-ethereum/swarm/network/simulation" + "github.com/ethereum/go-ethereum/swarm/state" + "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 +} + +//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) + } + + //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) (err error) { + disconnected := watchDisconnections(ctx, sim) + defer func() { + if err != nil { + if yes, ok := disconnected.Load().(bool); ok && yes { + err = errors.New("disconnect events received") + } + } + }() + + //check on the node's FileStore (netstore) + id := sim.Net.GetRandomUpNode().ID() + item, ok := sim.NodeItem(id, bucketKeyFileStore) + if !ok { + return errors.New("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) { + //define a wrapper object to be able to pass around data + wrapper := &netWrapper{} + + 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 + } + + r := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), &RegistryOptions{ + Retrieval: RetrievalDisabled, + Syncing: SyncingAutoSubscribe, + SyncUpdateDelay: 3 * time.Second, + }, nil) + + tr := &testRegistry{ + Registry: r, + w: wrapper, + } + + bucket.Store(bucketKeyRegistry, tr) + + cleanup = func() { + tr.Close() + clean() + } + + return tr, cleanup, nil + }, + }).WithServer(":8888") //start with the HTTP server + + nodeCount, chunkCount, sim := setupSim(simServiceMap) + defer sim.Close() + + log.Info(fmt.Sprintf("Running the simulation with %d nodes and %d chunks", nodeCount, chunkCount)) + log.Info("Initializing test config") + + 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) + //pass the network to the wrapper object + wrapper.setNetwork(sim.Net) + err := sim.UploadSnapshot(fmt.Sprintf("testing/snapshot_%d.json", nodeCount)) + if err != nil { + panic(err) + } + + //run the sim + result := runSim(conf, ctx, sim, chunkCount) + + //send terminated event + evt := &simulations.Event{ + Type: EventTypeSimTerminated, + Control: false, + } + go sim.Net.Events().Send(evt) + + if result.Error != nil { + panic(result.Error) + } + log.Info("Simulation ended") +} + +//testRegistry embeds registry +//it allows to replace the protocol run function +type testRegistry struct { + *Registry + w *netWrapper +} + +//Protocols replaces the protocol's run function +func (tr *testRegistry) Protocols() []p2p.Protocol { + regProto := tr.Registry.Protocols() + //set the `stream` protocol's run function with the testRegistry's one + regProto[0].Run = tr.runProto + return regProto +} + +//runProto is the new overwritten protocol's run function for this test +func (tr *testRegistry) runProto(p *p2p.Peer, rw p2p.MsgReadWriter) error { + //create a custom rw message ReadWriter + testRw := &testMsgReadWriter{ + MsgReadWriter: rw, + Peer: p, + w: tr.w, + Registry: tr.Registry, + } + //now run the actual upper layer `Registry`'s protocol function + return tr.runProtocol(p, testRw) +} + +//testMsgReadWriter is a custom rw +//it will allow us to re-use the message twice +type testMsgReadWriter struct { + *Registry + p2p.MsgReadWriter + *p2p.Peer + w *netWrapper +} + +//netWrapper wrapper object so we can pass data around +type netWrapper struct { + net *simulations.Network +} + +//set the network to the wrapper for later use (used inside the custom rw) +func (w *netWrapper) setNetwork(n *simulations.Network) { + w.net = n +} + +//get he network from the wrapper (used inside the custom rw) +func (w *netWrapper) getNetwork() *simulations.Network { + return w.net +} + +// ReadMsg reads a message from the underlying MsgReadWriter and emits a +// "message received" event +//we do this because we are interested in the Payload of the message for custom use +//in this test, but messages can only be consumed once (stream io.Reader) +func (ev *testMsgReadWriter) ReadMsg() (p2p.Msg, error) { + //read the message from the underlying rw + msg, err := ev.MsgReadWriter.ReadMsg() + if err != nil { + return msg, err + } + + //don't do anything with message codes we actually are not needing/reading + subCodes := []uint64{1, 2, 10} + found := false + for _, c := range subCodes { + if c == msg.Code { + found = true + } + } + //just return if not a msg code we are interested in + if !found { + return msg, nil + } + + //we use a io.TeeReader so that we can read the message twice + //the Payload is a io.Reader, so if we read from it, the actual protocol handler + //cannot access it anymore. + //But we need that handler to be able to consume the message as normal, + //as if we would not do anything here with that message + var buf bytes.Buffer + tee := io.TeeReader(msg.Payload, &buf) + + mcp := &p2p.Msg{ + Code: msg.Code, + Size: msg.Size, + ReceivedAt: msg.ReceivedAt, + Payload: tee, + } + //assign the copy for later use + msg.Payload = &buf + + //now let's look into the message + var wmsg protocols.WrappedMsg + err = mcp.Decode(&wmsg) + if err != nil { + log.Error(err.Error()) + return msg, err + } + //create a new message from the code + val, ok := ev.Registry.GetSpec().NewMsg(mcp.Code) + if !ok { + return msg, errors.New(fmt.Sprintf("Invalid message code: %v", msg.Code)) + } + //decode it + if err := rlp.DecodeBytes(wmsg.Payload, val); err != nil { + return msg, errors.New(fmt.Sprintf("Decoding error <= %v: %v", msg, err)) + } + //now for every message type we are interested in, create a custom event and send it + var evt *simulations.Event + switch val := val.(type) { + case *OfferedHashesMsg: + evt = &simulations.Event{ + Type: EventTypeChunkOffered, + Node: ev.w.getNetwork().GetNode(ev.ID()), + Control: false, + Data: val.Hashes, + } + case *WantedHashesMsg: + evt = &simulations.Event{ + Type: EventTypeChunkWanted, + Node: ev.w.getNetwork().GetNode(ev.ID()), + Control: false, + } + case *ChunkDeliveryMsgSyncing: + evt = &simulations.Event{ + Type: EventTypeChunkDelivered, + Node: ev.w.getNetwork().GetNode(ev.ID()), + Control: false, + Data: val.Addr.String(), + } + } + if evt != nil { + //send custom event to feed; frontend will listen to it and display + ev.w.getNetwork().Events().Send(evt) + } + return msg, nil +} diff --git a/swarm/network/syncdb.go b/swarm/network/syncdb.go deleted file mode 100644 index 88b4b68dd0..0000000000 --- a/swarm/network/syncdb.go +++ /dev/null @@ -1,389 +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 network - -import ( - "encoding/binary" - "fmt" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/swarm/storage" - "github.com/syndtr/goleveldb/leveldb" - "github.com/syndtr/goleveldb/leveldb/iterator" -) - -const counterKeyPrefix = 0x01 - -/* -syncDb is a queueing service for outgoing deliveries. -One instance per priority queue for each peer - -a syncDb instance maintains an in-memory buffer (of capacity bufferSize) -once its in-memory buffer is full it switches to persisting in db -and dbRead iterator iterates through the items keeping their order -once the db read catches up (there is no more items in the db) then -it switches back to in-memory buffer. - -when syncdb is stopped all items in the buffer are saved to the db -*/ -type syncDb struct { - start []byte // this syncdb starting index in requestdb - key storage.Key // remote peers address key - counterKey []byte // db key to persist counter - priority uint // priotity High|Medium|Low - buffer chan interface{} // incoming request channel - db *storage.LDBDatabase // underlying db (TODO should be interface) - done chan bool // chan to signal goroutines finished quitting - quit chan bool // chan to signal quitting to goroutines - total, dbTotal int // counts for one session - batch chan chan int // channel for batch requests - dbBatchSize uint // number of items before batch is saved -} - -// constructor needs a shared request db (leveldb) -// priority is used in the index key -// uses a buffer and a leveldb for persistent storage -// bufferSize, dbBatchSize are config parameters -func newSyncDb(db *storage.LDBDatabase, key storage.Key, priority uint, bufferSize, dbBatchSize uint, deliver func(interface{}, chan bool) bool) *syncDb { - start := make([]byte, 42) - start[1] = byte(priorities - priority) - copy(start[2:34], key) - - counterKey := make([]byte, 34) - counterKey[0] = counterKeyPrefix - copy(counterKey[1:], start[1:34]) - - syncdb := &syncDb{ - start: start, - key: key, - counterKey: counterKey, - priority: priority, - buffer: make(chan interface{}, bufferSize), - db: db, - done: make(chan bool), - quit: make(chan bool), - batch: make(chan chan int), - dbBatchSize: dbBatchSize, - } - log.Trace(fmt.Sprintf("syncDb[peer: %v, priority: %v] - initialised", key.Log(), priority)) - - // starts the main forever loop reading from buffer - go syncdb.bufferRead(deliver) - return syncdb -} - -/* -bufferRead is a forever iterator loop that takes care of delivering -outgoing store requests reads from incoming buffer - -its argument is the deliver function taking the item as first argument -and a quit channel as second. -Closing of this channel is supposed to abort all waiting for delivery -(typically network write) - -The iteration switches between 2 modes, -* buffer mode reads the in-memory buffer and delivers the items directly -* db mode reads from the buffer and writes to the db, parallelly another -routine is started that reads from the db and delivers items - -If there is buffer contention in buffer mode (slow network, high upload volume) -syncdb switches to db mode and starts dbRead -Once db backlog is delivered, it reverts back to in-memory buffer - -It is automatically started when syncdb is initialised. - -It saves the buffer to db upon receiving quit signal. syncDb#stop() -*/ -func (self *syncDb) bufferRead(deliver func(interface{}, chan bool) bool) { - var buffer, db chan interface{} // channels representing the two read modes - var more bool - var req interface{} - var entry *syncDbEntry - var inBatch, inDb int - batch := new(leveldb.Batch) - var dbSize chan int - quit := self.quit - counterValue := make([]byte, 8) - - // counter is used for keeping the items in order, persisted to db - // start counter where db was at, 0 if not found - data, err := self.db.Get(self.counterKey) - var counter uint64 - if err == nil { - counter = binary.BigEndian.Uint64(data) - log.Trace(fmt.Sprintf("syncDb[%v/%v] - counter read from db at %v", self.key.Log(), self.priority, counter)) - } else { - log.Trace(fmt.Sprintf("syncDb[%v/%v] - counter starts at %v", self.key.Log(), self.priority, counter)) - } - -LOOP: - for { - // waiting for item next in the buffer, or quit signal or batch request - select { - // buffer only closes when writing to db - case req = <-buffer: - // deliver request : this is blocking on network write so - // it is passed the quit channel as argument, so that it returns - // if syncdb is stopped. In this case we need to save the item to the db - more = deliver(req, self.quit) - if !more { - log.Debug(fmt.Sprintf("syncDb[%v/%v] quit: switching to db. session tally (db/total): %v/%v", self.key.Log(), self.priority, self.dbTotal, self.total)) - // received quit signal, save request currently waiting delivery - // by switching to db mode and closing the buffer - buffer = nil - db = self.buffer - close(db) - quit = nil // needs to block the quit case in select - break // break from select, this item will be written to the db - } - self.total++ - log.Trace(fmt.Sprintf("syncDb[%v/%v] deliver (db/total): %v/%v", self.key.Log(), self.priority, self.dbTotal, self.total)) - // by the time deliver returns, there were new writes to the buffer - // if buffer contention is detected, switch to db mode which drains - // the buffer so no process will block on pushing store requests - if len(buffer) == cap(buffer) { - log.Debug(fmt.Sprintf("syncDb[%v/%v] buffer full %v: switching to db. session tally (db/total): %v/%v", self.key.Log(), self.priority, cap(buffer), self.dbTotal, self.total)) - buffer = nil - db = self.buffer - } - continue LOOP - - // incoming entry to put into db - case req, more = <-db: - if !more { - // only if quit is called, saved all the buffer - binary.BigEndian.PutUint64(counterValue, counter) - batch.Put(self.counterKey, counterValue) // persist counter in batch - self.writeSyncBatch(batch) // save batch - log.Trace(fmt.Sprintf("syncDb[%v/%v] quitting: save current batch to db", self.key.Log(), self.priority)) - break LOOP - } - self.dbTotal++ - self.total++ - // otherwise break after select - case dbSize = <-self.batch: - // explicit request for batch - if inBatch == 0 && quit != nil { - // there was no writes since the last batch so db depleted - // switch to buffer mode - log.Debug(fmt.Sprintf("syncDb[%v/%v] empty db: switching to buffer", self.key.Log(), self.priority)) - db = nil - buffer = self.buffer - dbSize <- 0 // indicates to 'caller' that batch has been written - inDb = 0 - continue LOOP - } - binary.BigEndian.PutUint64(counterValue, counter) - batch.Put(self.counterKey, counterValue) - log.Debug(fmt.Sprintf("syncDb[%v/%v] write batch %v/%v - %x - %x", self.key.Log(), self.priority, inBatch, counter, self.counterKey, counterValue)) - batch = self.writeSyncBatch(batch) - dbSize <- inBatch // indicates to 'caller' that batch has been written - inBatch = 0 - continue LOOP - - // closing syncDb#quit channel is used to signal to all goroutines to quit - case <-quit: - // need to save backlog, so switch to db mode - db = self.buffer - buffer = nil - quit = nil - log.Trace(fmt.Sprintf("syncDb[%v/%v] quitting: save buffer to db", self.key.Log(), self.priority)) - close(db) - continue LOOP - } - - // only get here if we put req into db - entry, err = self.newSyncDbEntry(req, counter) - if err != nil { - log.Warn(fmt.Sprintf("syncDb[%v/%v] saving request %v (#%v/%v) failed: %v", self.key.Log(), self.priority, req, inBatch, inDb, err)) - continue LOOP - } - batch.Put(entry.key, entry.val) - log.Trace(fmt.Sprintf("syncDb[%v/%v] to batch %v '%v' (#%v/%v/%v)", self.key.Log(), self.priority, req, entry, inBatch, inDb, counter)) - // if just switched to db mode and not quitting, then launch dbRead - // in a parallel go routine to send deliveries from db - if inDb == 0 && quit != nil { - log.Trace(fmt.Sprintf("syncDb[%v/%v] start dbRead", self.key.Log(), self.priority)) - go self.dbRead(true, counter, deliver) - } - inDb++ - inBatch++ - counter++ - // need to save the batch if it gets too large (== dbBatchSize) - if inBatch%int(self.dbBatchSize) == 0 { - batch = self.writeSyncBatch(batch) - } - } - log.Info(fmt.Sprintf("syncDb[%v:%v]: saved %v keys (saved counter at %v)", self.key.Log(), self.priority, inBatch, counter)) - close(self.done) -} - -// writes the batch to the db and returns a new batch object -func (self *syncDb) writeSyncBatch(batch *leveldb.Batch) *leveldb.Batch { - err := self.db.Write(batch) - if err != nil { - log.Warn(fmt.Sprintf("syncDb[%v/%v] saving batch to db failed: %v", self.key.Log(), self.priority, err)) - return batch - } - return new(leveldb.Batch) -} - -// abstract type for db entries (TODO could be a feature of Receipts) -type syncDbEntry struct { - key, val []byte -} - -func (self syncDbEntry) String() string { - return fmt.Sprintf("key: %x, value: %x", self.key, self.val) -} - -/* - dbRead is iterating over store requests to be sent over to the peer - this is mainly to prevent crashes due to network output buffer contention (???) - as well as to make syncronisation resilient to disconnects - the messages are supposed to be sent in the p2p priority queue. - - the request DB is shared between peers, but domains for each syncdb - are disjoint. dbkeys (42 bytes) are structured: - * 0: 0x00 (0x01 reserved for counter key) - * 1: priorities - priority (so that high priority can be replayed first) - * 2-33: peers address - * 34-41: syncdb counter to preserve order (this field is missing for the counter key) - - values (40 bytes) are: - * 0-31: key - * 32-39: request id - -dbRead needs a boolean to indicate if on first round all the historical -record is synced. Second argument to indicate current db counter -The third is the function to apply -*/ -func (self *syncDb) dbRead(useBatches bool, counter uint64, fun func(interface{}, chan bool) bool) { - key := make([]byte, 42) - copy(key, self.start) - binary.BigEndian.PutUint64(key[34:], counter) - var batches, n, cnt, total int - var more bool - var entry *syncDbEntry - var it iterator.Iterator - var del *leveldb.Batch - batchSizes := make(chan int) - - for { - // if useBatches is false, cnt is not set - if useBatches { - // this could be called before all cnt items sent out - // so that loop is not blocking while delivering - // only relevant if cnt is large - select { - case self.batch <- batchSizes: - case <-self.quit: - return - } - // wait for the write to finish and get the item count in the next batch - cnt = <-batchSizes - batches++ - if cnt == 0 { - // empty - return - } - } - it = self.db.NewIterator() - it.Seek(key) - if !it.Valid() { - copy(key, self.start) - useBatches = true - continue - } - del = new(leveldb.Batch) - log.Trace(fmt.Sprintf("syncDb[%v/%v]: new iterator: %x (batch %v, count %v)", self.key.Log(), self.priority, key, batches, cnt)) - - for n = 0; !useBatches || n < cnt; it.Next() { - copy(key, it.Key()) - if len(key) == 0 || key[0] != 0 { - copy(key, self.start) - useBatches = true - break - } - val := make([]byte, 40) - copy(val, it.Value()) - entry = &syncDbEntry{key, val} - // log.Trace(fmt.Sprintf("syncDb[%v/%v] - %v, batches: %v, total: %v, session total from db: %v/%v", self.key.Log(), self.priority, self.key.Log(), batches, total, self.dbTotal, self.total)) - more = fun(entry, self.quit) - if !more { - // quit received when waiting to deliver entry, the entry will not be deleted - log.Trace(fmt.Sprintf("syncDb[%v/%v] batch %v quit after %v/%v items", self.key.Log(), self.priority, batches, n, cnt)) - break - } - // since subsequent batches of the same db session are indexed incrementally - // deleting earlier batches can be delayed and parallelised - // this could be batch delete when db is idle (but added complexity esp when quitting) - del.Delete(key) - n++ - total++ - } - log.Debug(fmt.Sprintf("syncDb[%v/%v] - db session closed, batches: %v, total: %v, session total from db: %v/%v", self.key.Log(), self.priority, batches, total, self.dbTotal, self.total)) - self.db.Write(del) // this could be async called only when db is idle - it.Release() - } -} - -// -func (self *syncDb) stop() { - close(self.quit) - <-self.done -} - -// calculate a dbkey for the request, for the db to work -// see syncdb for db key structure -// polimorphic: accepted types, see syncer#addRequest -func (self *syncDb) newSyncDbEntry(req interface{}, counter uint64) (entry *syncDbEntry, err error) { - var key storage.Key - var chunk *storage.Chunk - var id uint64 - var ok bool - var sreq *storeRequestMsgData - - if key, ok = req.(storage.Key); ok { - id = generateId() - } else if chunk, ok = req.(*storage.Chunk); ok { - key = chunk.Key - id = generateId() - } else if sreq, ok = req.(*storeRequestMsgData); ok { - key = sreq.Key - id = sreq.Id - } else if entry, ok = req.(*syncDbEntry); !ok { - return nil, fmt.Errorf("type not allowed: %v (%T)", req, req) - } - - // order by peer > priority > seqid - // value is request id if exists - if entry == nil { - dbkey := make([]byte, 42) - dbval := make([]byte, 40) - - // encode key - copy(dbkey[:], self.start[:34]) // db peer - binary.BigEndian.PutUint64(dbkey[34:], counter) - // encode value - copy(dbval, key[:]) - binary.BigEndian.PutUint64(dbval[32:], id) - - entry = &syncDbEntry{dbkey, dbval} - } - return -} diff --git a/swarm/network/syncdb_test.go b/swarm/network/syncdb_test.go deleted file mode 100644 index be21d156f9..0000000000 --- a/swarm/network/syncdb_test.go +++ /dev/null @@ -1,222 +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 network - -import ( - "bytes" - "fmt" - "io/ioutil" - "os" - "path/filepath" - "testing" - "time" - - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/swarm/storage" -) - -func init() { - log.Root().SetHandler(log.LvlFilterHandler(log.LvlCrit, log.StreamHandler(os.Stderr, log.TerminalFormat(false)))) -} - -type testSyncDb struct { - *syncDb - c int - t *testing.T - fromDb chan bool - delivered [][]byte - sent []int - dbdir string - at int -} - -func newTestSyncDb(priority, bufferSize, batchSize int, dbdir string, t *testing.T) *testSyncDb { - if len(dbdir) == 0 { - tmp, err := ioutil.TempDir(os.TempDir(), "syncdb-test") - if err != nil { - t.Fatalf("unable to create temporary direcory %v: %v", tmp, err) - } - dbdir = tmp - } - db, err := storage.NewLDBDatabase(filepath.Join(dbdir, "requestdb")) - if err != nil { - t.Fatalf("unable to create db: %v", err) - } - self := &testSyncDb{ - fromDb: make(chan bool), - dbdir: dbdir, - t: t, - } - h := crypto.Keccak256Hash([]byte{0}) - key := storage.Key(h[:]) - self.syncDb = newSyncDb(db, key, uint(priority), uint(bufferSize), uint(batchSize), self.deliver) - // kick off db iterator right away, if no items on db this will allow - // reading from the buffer - return self - -} - -func (self *testSyncDb) close() { - self.db.Close() - os.RemoveAll(self.dbdir) -} - -func (self *testSyncDb) push(n int) { - for i := 0; i < n; i++ { - self.buffer <- storage.Key(crypto.Keccak256([]byte{byte(self.c)})) - self.sent = append(self.sent, self.c) - self.c++ - } - log.Debug(fmt.Sprintf("pushed %v requests", n)) -} - -func (self *testSyncDb) draindb() { - it := self.db.NewIterator() - defer it.Release() - for { - it.Seek(self.start) - if !it.Valid() { - return - } - k := it.Key() - if len(k) == 0 || k[0] == 1 { - return - } - it.Release() - it = self.db.NewIterator() - } -} - -func (self *testSyncDb) deliver(req interface{}, quit chan bool) bool { - _, db := req.(*syncDbEntry) - key, _, _, _, err := parseRequest(req) - if err != nil { - self.t.Fatalf("unexpected error of key %v: %v", key, err) - } - self.delivered = append(self.delivered, key) - select { - case self.fromDb <- db: - return true - case <-quit: - return false - } -} - -func (self *testSyncDb) expect(n int, db bool) { - var ok bool - // for n items - for i := 0; i < n; i++ { - ok = <-self.fromDb - if self.at+1 > len(self.delivered) { - self.t.Fatalf("expected %v, got %v", self.at+1, len(self.delivered)) - } - if len(self.sent) > self.at && !bytes.Equal(crypto.Keccak256([]byte{byte(self.sent[self.at])}), self.delivered[self.at]) { - self.t.Fatalf("expected delivery %v/%v/%v to be hash of %v, from db: %v = %v", i, n, self.at, self.sent[self.at], ok, db) - log.Debug(fmt.Sprintf("%v/%v/%v to be hash of %v, from db: %v = %v", i, n, self.at, self.sent[self.at], ok, db)) - } - if !ok && db { - self.t.Fatalf("expected delivery %v/%v/%v from db", i, n, self.at) - } - if ok && !db { - self.t.Fatalf("expected delivery %v/%v/%v from cache", i, n, self.at) - } - self.at++ - } -} - -func TestSyncDb(t *testing.T) { - t.Skip("fails randomly on all platforms") - - priority := High - bufferSize := 5 - batchSize := 2 * bufferSize - s := newTestSyncDb(priority, bufferSize, batchSize, "", t) - defer s.close() - defer s.stop() - s.dbRead(false, 0, s.deliver) - s.draindb() - - s.push(4) - s.expect(1, false) - // 3 in buffer - time.Sleep(100 * time.Millisecond) - s.push(3) - // push over limit - s.expect(1, false) - // one popped from the buffer, then contention detected - s.expect(4, true) - s.push(4) - s.expect(5, true) - // depleted db, switch back to buffer - s.draindb() - s.push(5) - s.expect(4, false) - s.push(3) - s.expect(4, false) - // buffer depleted - time.Sleep(100 * time.Millisecond) - s.push(6) - s.expect(1, false) - // push into buffer full, switch to db - s.expect(5, true) - s.draindb() - s.push(1) - s.expect(1, false) -} - -func TestSaveSyncDb(t *testing.T) { - amount := 30 - priority := High - bufferSize := amount - batchSize := 10 - s := newTestSyncDb(priority, bufferSize, batchSize, "", t) - go s.dbRead(false, 0, s.deliver) - s.push(amount) - s.stop() - s.db.Close() - - s = newTestSyncDb(priority, bufferSize, batchSize, s.dbdir, t) - go s.dbRead(false, 0, s.deliver) - s.expect(amount, true) - for i, key := range s.delivered { - expKey := crypto.Keccak256([]byte{byte(i)}) - if !bytes.Equal(key, expKey) { - t.Fatalf("delivery %v expected to be key %x, got %x", i, expKey, key) - } - } - s.push(amount) - s.expect(amount, false) - for i := amount; i < 2*amount; i++ { - key := s.delivered[i] - expKey := crypto.Keccak256([]byte{byte(i - amount)}) - if !bytes.Equal(key, expKey) { - t.Fatalf("delivery %v expected to be key %x, got %x", i, expKey, key) - } - } - s.stop() - s.db.Close() - - s = newTestSyncDb(priority, bufferSize, batchSize, s.dbdir, t) - defer s.close() - defer s.stop() - - go s.dbRead(false, 0, s.deliver) - s.push(1) - s.expect(1, false) - -} diff --git a/swarm/network/syncer.go b/swarm/network/syncer.go deleted file mode 100644 index 6d729fcb9e..0000000000 --- a/swarm/network/syncer.go +++ /dev/null @@ -1,781 +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 network - -import ( - "encoding/binary" - "encoding/json" - "fmt" - "path/filepath" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/swarm/storage" -) - -// syncer parameters (global, not peer specific) default values -const ( - requestDbBatchSize = 512 // size of batch before written to request db - keyBufferSize = 1024 // size of buffer for unsynced keys - syncBatchSize = 128 // maximum batchsize for outgoing requests - syncBufferSize = 128 // size of buffer for delivery requests - syncCacheSize = 1024 // cache capacity to store request queue in memory -) - -// priorities -const ( - Low = iota // 0 - Medium // 1 - High // 2 - priorities // 3 number of priority levels -) - -// request types -const ( - DeliverReq = iota // 0 - PushReq // 1 - PropagateReq // 2 - HistoryReq // 3 - BacklogReq // 4 -) - -// json serialisable struct to record the syncronisation state between 2 peers -type syncState struct { - *storage.DbSyncState // embeds the following 4 fields: - // Start Key // lower limit of address space - // Stop Key // upper limit of address space - // First uint64 // counter taken from last sync state - // Last uint64 // counter of remote peer dbStore at the time of last connection - SessionAt uint64 // set at the time of connection - LastSeenAt uint64 // set at the time of connection - Latest storage.Key // cursor of dbstore when last (continuously set by syncer) - Synced bool // true iff Sync is done up to the last disconnect - synced chan bool // signal that sync stage finished -} - -// wrapper of db-s to provide mockable custom local chunk store access to syncer -type DbAccess struct { - db *storage.DbStore - loc *storage.LocalStore -} - -func NewDbAccess(loc *storage.LocalStore) *DbAccess { - return &DbAccess{loc.DbStore.(*storage.DbStore), loc} -} - -// to obtain the chunks from key or request db entry only -func (self *DbAccess) get(key storage.Key) (*storage.Chunk, error) { - return self.loc.Get(key) -} - -// current storage counter of chunk db -func (self *DbAccess) counter() uint64 { - return self.db.Counter() -} - -// implemented by dbStoreSyncIterator -type keyIterator interface { - Next() storage.Key -} - -// generator function for iteration by address range and storage counter -func (self *DbAccess) iterator(s *syncState) keyIterator { - it, err := self.db.NewSyncIterator(*(s.DbSyncState)) - if err != nil { - return nil - } - return keyIterator(it) -} - -func (self syncState) String() string { - if self.Synced { - return fmt.Sprintf( - "session started at: %v, last seen at: %v, latest key: %v", - self.SessionAt, self.LastSeenAt, - self.Latest.Log(), - ) - } else { - return fmt.Sprintf( - "address: %v-%v, index: %v-%v, session started at: %v, last seen at: %v, latest key: %v", - self.Start.Log(), self.Stop.Log(), - self.First, self.Last, - self.SessionAt, self.LastSeenAt, - self.Latest.Log(), - ) - } -} - -// syncer parameters (global, not peer specific) -type SyncParams struct { - RequestDbPath string // path for request db (leveldb) - RequestDbBatchSize uint // nuber of items before batch is saved to requestdb - KeyBufferSize uint // size of key buffer - SyncBatchSize uint // maximum batchsize for outgoing requests - SyncBufferSize uint // size of buffer for - SyncCacheSize uint // cache capacity to store request queue in memory - SyncPriorities []uint // list of priority levels for req types 0-3 - SyncModes []bool // list of sync modes for for req types 0-3 -} - -// constructor with default values -func NewDefaultSyncParams() *SyncParams { - return &SyncParams{ - RequestDbBatchSize: requestDbBatchSize, - KeyBufferSize: keyBufferSize, - SyncBufferSize: syncBufferSize, - SyncBatchSize: syncBatchSize, - SyncCacheSize: syncCacheSize, - SyncPriorities: []uint{High, Medium, Medium, Low, Low}, - SyncModes: []bool{true, true, true, true, false}, - } -} - -//this can only finally be set after all config options (file, cmd line, env vars) -//have been evaluated -func (self *SyncParams) Init(path string) { - self.RequestDbPath = filepath.Join(path, "requests") -} - -// syncer is the agent that manages content distribution/storage replication/chunk storeRequest forwarding -type syncer struct { - *SyncParams // sync parameters - syncF func() bool // if syncing is needed - key storage.Key // remote peers address key - state *syncState // sync state for our dbStore - syncStates chan *syncState // different stages of sync - deliveryRequest chan bool // one of two triggers needed to send unsyncedKeys - newUnsyncedKeys chan bool // one of two triggers needed to send unsynced keys - quit chan bool // signal to quit loops - - // DB related fields - dbAccess *DbAccess // access to dbStore - - // native fields - queues [priorities]*syncDb // in-memory cache / queues for sync reqs - keys [priorities]chan interface{} // buffer for unsynced keys - deliveries [priorities]chan *storeRequestMsgData // delivery - - // bzz protocol instance outgoing message callbacks (mockable for testing) - unsyncedKeys func([]*syncRequest, *syncState) error // send unsyncedKeysMsg - store func(*storeRequestMsgData) error // send storeRequestMsg -} - -// a syncer instance is linked to each peer connection -// constructor is called from protocol after successful handshake -// the returned instance is attached to the peer and can be called -// by the forwarder -func newSyncer( - db *storage.LDBDatabase, remotekey storage.Key, - dbAccess *DbAccess, - unsyncedKeys func([]*syncRequest, *syncState) error, - store func(*storeRequestMsgData) error, - params *SyncParams, - state *syncState, - syncF func() bool, -) (*syncer, error) { - - syncBufferSize := params.SyncBufferSize - keyBufferSize := params.KeyBufferSize - dbBatchSize := params.RequestDbBatchSize - - self := &syncer{ - syncF: syncF, - key: remotekey, - dbAccess: dbAccess, - syncStates: make(chan *syncState, 20), - deliveryRequest: make(chan bool, 1), - newUnsyncedKeys: make(chan bool, 1), - SyncParams: params, - state: state, - quit: make(chan bool), - unsyncedKeys: unsyncedKeys, - store: store, - } - - // initialising - for i := 0; i < priorities; i++ { - self.keys[i] = make(chan interface{}, keyBufferSize) - self.deliveries[i] = make(chan *storeRequestMsgData) - // initialise a syncdb instance for each priority queue - self.queues[i] = newSyncDb(db, remotekey, uint(i), syncBufferSize, dbBatchSize, self.deliver(uint(i))) - } - log.Info(fmt.Sprintf("syncer started: %v", state)) - // launch chunk delivery service - go self.syncDeliveries() - // launch sync task manager - if self.syncF() { - go self.sync() - } - // process unsynced keys to broadcast - go self.syncUnsyncedKeys() - - return self, nil -} - -// metadata serialisation -func encodeSync(state *syncState) (*json.RawMessage, error) { - data, err := json.MarshalIndent(state, "", " ") - if err != nil { - return nil, err - } - meta := json.RawMessage(data) - return &meta, nil -} - -func decodeSync(meta *json.RawMessage) (*syncState, error) { - if meta == nil { - return nil, fmt.Errorf("unable to deserialise sync state from ") - } - data := []byte(*(meta)) - if len(data) == 0 { - return nil, fmt.Errorf("unable to deserialise sync state from ") - } - state := &syncState{DbSyncState: &storage.DbSyncState{}} - err := json.Unmarshal(data, state) - return state, err -} - -/* - sync implements the syncing script - * first all items left in the request Db are replayed - * type = StaleSync - * Mode: by default once again via confirmation roundtrip - * Priority: the items are replayed as the proirity specified for StaleSync - * but within the order respects earlier priority level of request - * after all items are consumed for a priority level, the the respective - queue for delivery requests is open (this way new reqs not written to db) - (TODO: this should be checked) - * the sync state provided by the remote peer is used to sync history - * all the backlog from earlier (aborted) syncing is completed starting from latest - * if Last < LastSeenAt then all items in between then process all - backlog from upto last disconnect - * if Last > 0 && - - sync is called from the syncer constructor and is not supposed to be used externally -*/ -func (self *syncer) sync() { - state := self.state - // sync finished - defer close(self.syncStates) - - // 0. first replay stale requests from request db - if state.SessionAt == 0 { - log.Debug(fmt.Sprintf("syncer[%v]: nothing to sync", self.key.Log())) - return - } - log.Debug(fmt.Sprintf("syncer[%v]: start replaying stale requests from request db", self.key.Log())) - for p := priorities - 1; p >= 0; p-- { - self.queues[p].dbRead(false, 0, self.replay()) - } - log.Debug(fmt.Sprintf("syncer[%v]: done replaying stale requests from request db", self.key.Log())) - - // unless peer is synced sync unfinished history beginning on - if !state.Synced { - start := state.Start - - if !storage.IsZeroKey(state.Latest) { - // 1. there is unfinished earlier sync - state.Start = state.Latest - log.Debug(fmt.Sprintf("syncer[%v]: start syncronising backlog (unfinished sync: %v)", self.key.Log(), state)) - // blocks while the entire history upto state is synced - self.syncState(state) - if state.Last < state.SessionAt { - state.First = state.Last + 1 - } - } - state.Latest = storage.ZeroKey - state.Start = start - // 2. sync up to last disconnect1 - if state.First < state.LastSeenAt { - state.Last = state.LastSeenAt - log.Debug(fmt.Sprintf("syncer[%v]: start syncronising history upto last disconnect at %v: %v", self.key.Log(), state.LastSeenAt, state)) - self.syncState(state) - state.First = state.LastSeenAt - } - state.Latest = storage.ZeroKey - - } else { - // synchronisation starts at end of last session - state.First = state.LastSeenAt - } - - // 3. sync up to current session start - // if there have been new chunks since last session - if state.LastSeenAt < state.SessionAt { - state.Last = state.SessionAt - log.Debug(fmt.Sprintf("syncer[%v]: start syncronising history since last disconnect at %v up until session start at %v: %v", self.key.Log(), state.LastSeenAt, state.SessionAt, state)) - // blocks until state syncing is finished - self.syncState(state) - } - log.Info(fmt.Sprintf("syncer[%v]: syncing all history complete", self.key.Log())) - -} - -// wait till syncronised block uptil state is synced -func (self *syncer) syncState(state *syncState) { - self.syncStates <- state - select { - case <-state.synced: - case <-self.quit: - } -} - -// stop quits both request processor and saves the request cache to disk -func (self *syncer) stop() { - close(self.quit) - log.Trace(fmt.Sprintf("syncer[%v]: stop and save sync request db backlog", self.key.Log())) - for _, db := range self.queues { - db.stop() - } -} - -// rlp serialisable sync request -type syncRequest struct { - Key storage.Key - Priority uint -} - -func (self *syncRequest) String() string { - return fmt.Sprintf("", self.Key.Log(), self.Priority) -} - -func (self *syncer) newSyncRequest(req interface{}, p int) (*syncRequest, error) { - key, _, _, _, err := parseRequest(req) - // TODO: if req has chunk, it should be put in a cache - // create - if err != nil { - return nil, err - } - return &syncRequest{key, uint(p)}, nil -} - -// serves historical items from the DB -// * read is on demand, blocking unless history channel is read -// * accepts sync requests (syncStates) to create new db iterator -// * closes the channel one iteration finishes -func (self *syncer) syncHistory(state *syncState) chan interface{} { - var n uint - history := make(chan interface{}) - log.Debug(fmt.Sprintf("syncer[%v]: syncing history between %v - %v for chunk addresses %v - %v", self.key.Log(), state.First, state.Last, state.Start, state.Stop)) - it := self.dbAccess.iterator(state) - if it != nil { - go func() { - // signal end of the iteration ended - defer close(history) - IT: - for { - key := it.Next() - if key == nil { - break IT - } - select { - // blocking until history channel is read from - case history <- key: - n++ - log.Trace(fmt.Sprintf("syncer[%v]: history: %v (%v keys)", self.key.Log(), key.Log(), n)) - state.Latest = key - case <-self.quit: - return - } - } - log.Debug(fmt.Sprintf("syncer[%v]: finished syncing history between %v - %v for chunk addresses %v - %v (at %v) (chunks = %v)", self.key.Log(), state.First, state.Last, state.Start, state.Stop, state.Latest, n)) - }() - } - return history -} - -// triggers key syncronisation -func (self *syncer) sendUnsyncedKeys() { - select { - case self.deliveryRequest <- true: - default: - } -} - -// assembles a new batch of unsynced keys -// * keys are drawn from the key buffers in order of priority queue -// * if the queues of priority for History (HistoryReq) or higher are depleted, -// historical data is used so historical items are lower priority within -// their priority group. -// * Order of historical data is unspecified -func (self *syncer) syncUnsyncedKeys() { - // send out new - var unsynced []*syncRequest - var more, justSynced bool - var keyCount, historyCnt int - var history chan interface{} - - priority := High - keys := self.keys[priority] - var newUnsyncedKeys, deliveryRequest chan bool - keyCounts := make([]int, priorities) - histPrior := self.SyncPriorities[HistoryReq] - syncStates := self.syncStates - state := self.state - -LOOP: - for { - - var req interface{} - // select the highest priority channel to read from - // keys channels are buffered so the highest priority ones - // are checked first - integrity can only be guaranteed if writing - // is locked while selecting - if priority != High || len(keys) == 0 { - // selection is not needed if the High priority queue has items - keys = nil - PRIORITIES: - for priority = High; priority >= 0; priority-- { - // the first priority channel that is non-empty will be assigned to keys - if len(self.keys[priority]) > 0 { - log.Trace(fmt.Sprintf("syncer[%v]: reading request with priority %v", self.key.Log(), priority)) - keys = self.keys[priority] - break PRIORITIES - } - log.Trace(fmt.Sprintf("syncer[%v/%v]: queue: [%v, %v, %v]", self.key.Log(), priority, len(self.keys[High]), len(self.keys[Medium]), len(self.keys[Low]))) - // if the input queue is empty on this level, resort to history if there is any - if uint(priority) == histPrior && history != nil { - log.Trace(fmt.Sprintf("syncer[%v]: reading history for %v", self.key.Log(), self.key)) - keys = history - break PRIORITIES - } - } - } - - // if peer ready to receive but nothing to send - if keys == nil && deliveryRequest == nil { - // if no items left and switch to waiting mode - log.Trace(fmt.Sprintf("syncer[%v]: buffers consumed. Waiting", self.key.Log())) - newUnsyncedKeys = self.newUnsyncedKeys - } - - // send msg iff - // * peer is ready to receive keys AND ( - // * all queues and history are depleted OR - // * batch full OR - // * all history have been consumed, synced) - if deliveryRequest == nil && - (justSynced || - len(unsynced) > 0 && keys == nil || - len(unsynced) == int(self.SyncBatchSize)) { - justSynced = false - // listen to requests - deliveryRequest = self.deliveryRequest - newUnsyncedKeys = nil // not care about data until next req comes in - // set sync to current counter - // (all nonhistorical outgoing traffic sheduled and persisted - state.LastSeenAt = self.dbAccess.counter() - state.Latest = storage.ZeroKey - log.Trace(fmt.Sprintf("syncer[%v]: sending %v", self.key.Log(), unsynced)) - // send the unsynced keys - stateCopy := *state - err := self.unsyncedKeys(unsynced, &stateCopy) - if err != nil { - log.Warn(fmt.Sprintf("syncer[%v]: unable to send unsynced keys: %v", self.key.Log(), err)) - } - self.state = state - log.Debug(fmt.Sprintf("syncer[%v]: --> %v keys sent: (total: %v (%v), history: %v), sent sync state: %v", self.key.Log(), len(unsynced), keyCounts, keyCount, historyCnt, stateCopy)) - unsynced = nil - keys = nil - } - - // process item and add it to the batch - select { - case <-self.quit: - break LOOP - case req, more = <-keys: - if keys == history && !more { - log.Trace(fmt.Sprintf("syncer[%v]: syncing history segment complete", self.key.Log())) - // history channel is closed, waiting for new state (called from sync()) - syncStates = self.syncStates - state.Synced = true // this signals that the current segment is complete - select { - case state.synced <- false: - case <-self.quit: - break LOOP - } - justSynced = true - history = nil - } - case <-deliveryRequest: - log.Trace(fmt.Sprintf("syncer[%v]: peer ready to receive", self.key.Log())) - - // this 1 cap channel can wake up the loop - // signaling that peer is ready to receive unsynced Keys - // the channel is set to nil any further writes will be ignored - deliveryRequest = nil - - case <-newUnsyncedKeys: - log.Trace(fmt.Sprintf("syncer[%v]: new unsynced keys available", self.key.Log())) - // this 1 cap channel can wake up the loop - // signals that data is available to send if peer is ready to receive - newUnsyncedKeys = nil - keys = self.keys[High] - - case state, more = <-syncStates: - // this resets the state - if !more { - state = self.state - log.Trace(fmt.Sprintf("syncer[%v]: (priority %v) syncing complete upto %v)", self.key.Log(), priority, state)) - state.Synced = true - syncStates = nil - } else { - log.Trace(fmt.Sprintf("syncer[%v]: (priority %v) syncing history upto %v priority %v)", self.key.Log(), priority, state, histPrior)) - state.Synced = false - history = self.syncHistory(state) - // only one history at a time, only allow another one once the - // history channel is closed - syncStates = nil - } - } - if req == nil { - continue LOOP - } - - log.Trace(fmt.Sprintf("syncer[%v]: (priority %v) added to unsynced keys: %v", self.key.Log(), priority, req)) - keyCounts[priority]++ - keyCount++ - if keys == history { - log.Trace(fmt.Sprintf("syncer[%v]: (priority %v) history item %v (synced = %v)", self.key.Log(), priority, req, state.Synced)) - historyCnt++ - } - if sreq, err := self.newSyncRequest(req, priority); err == nil { - // extract key from req - log.Trace(fmt.Sprintf("syncer[%v]: (priority %v): request %v (synced = %v)", self.key.Log(), priority, req, state.Synced)) - unsynced = append(unsynced, sreq) - } else { - log.Warn(fmt.Sprintf("syncer[%v]: (priority %v): error creating request for %v: %v)", self.key.Log(), priority, req, err)) - } - - } -} - -// delivery loop -// takes into account priority, send store Requests with chunk (delivery) -// idle blocking if no new deliveries in any of the queues -func (self *syncer) syncDeliveries() { - var req *storeRequestMsgData - p := High - var deliveries chan *storeRequestMsgData - var msg *storeRequestMsgData - var err error - var c = [priorities]int{} - var n = [priorities]int{} - var total, success uint - - for { - deliveries = self.deliveries[p] - select { - case req = <-deliveries: - n[p]++ - c[p]++ - default: - if p == Low { - // blocking, depletion on all channels, no preference for priority - select { - case req = <-self.deliveries[High]: - n[High]++ - case req = <-self.deliveries[Medium]: - n[Medium]++ - case req = <-self.deliveries[Low]: - n[Low]++ - case <-self.quit: - return - } - p = High - } else { - p-- - continue - } - } - total++ - msg, err = self.newStoreRequestMsgData(req) - if err != nil { - log.Warn(fmt.Sprintf("syncer[%v]: failed to create store request for %v: %v", self.key.Log(), req, err)) - } else { - err = self.store(msg) - if err != nil { - log.Warn(fmt.Sprintf("syncer[%v]: failed to deliver %v: %v", self.key.Log(), req, err)) - } else { - success++ - log.Trace(fmt.Sprintf("syncer[%v]: %v successfully delivered", self.key.Log(), req)) - } - } - if total%self.SyncBatchSize == 0 { - log.Debug(fmt.Sprintf("syncer[%v]: deliver Total: %v, Success: %v, High: %v/%v, Medium: %v/%v, Low %v/%v", self.key.Log(), total, success, c[High], n[High], c[Medium], n[Medium], c[Low], n[Low])) - } - } -} - -/* - addRequest handles requests for delivery - it accepts 4 types: - - * storeRequestMsgData: coming from netstore propagate response - * chunk: coming from forwarding (questionable: id?) - * key: from incoming syncRequest - * syncDbEntry: key,id encoded in db - - If sync mode is on for the type of request, then - it sends the request to the keys queue of the correct priority - channel buffered with capacity (SyncBufferSize) - - If sync mode is off then, requests are directly sent to deliveries -*/ -func (self *syncer) addRequest(req interface{}, ty int) { - // retrieve priority for request type name int8 - - priority := self.SyncPriorities[ty] - // sync mode for this type ON - if self.syncF() || ty == DeliverReq { - if self.SyncModes[ty] { - self.addKey(req, priority, self.quit) - } else { - self.addDelivery(req, priority, self.quit) - } - } -} - -// addKey queues sync request for sync confirmation with given priority -// ie the key will go out in an unsyncedKeys message -func (self *syncer) addKey(req interface{}, priority uint, quit chan bool) bool { - select { - case self.keys[priority] <- req: - // this wakes up the unsynced keys loop if idle - select { - case self.newUnsyncedKeys <- true: - default: - } - return true - case <-quit: - return false - } -} - -// addDelivery queues delivery request for with given priority -// ie the chunk will be delivered ASAP mod priority queueing handled by syncdb -// requests are persisted across sessions for correct sync -func (self *syncer) addDelivery(req interface{}, priority uint, quit chan bool) bool { - select { - case self.queues[priority].buffer <- req: - return true - case <-quit: - return false - } -} - -// doDelivery delivers the chunk for the request with given priority -// without queuing -func (self *syncer) doDelivery(req interface{}, priority uint, quit chan bool) bool { - msgdata, err := self.newStoreRequestMsgData(req) - if err != nil { - log.Warn(fmt.Sprintf("unable to deliver request %v: %v", msgdata, err)) - return false - } - select { - case self.deliveries[priority] <- msgdata: - return true - case <-quit: - return false - } -} - -// returns the delivery function for given priority -// passed on to syncDb -func (self *syncer) deliver(priority uint) func(req interface{}, quit chan bool) bool { - return func(req interface{}, quit chan bool) bool { - return self.doDelivery(req, priority, quit) - } -} - -// returns the replay function passed on to syncDb -// depending on sync mode settings for BacklogReq, -// re play of request db backlog sends items via confirmation -// or directly delivers -func (self *syncer) replay() func(req interface{}, quit chan bool) bool { - sync := self.SyncModes[BacklogReq] - priority := self.SyncPriorities[BacklogReq] - // sync mode for this type ON - if sync { - return func(req interface{}, quit chan bool) bool { - return self.addKey(req, priority, quit) - } - } else { - return func(req interface{}, quit chan bool) bool { - return self.doDelivery(req, priority, quit) - } - - } -} - -// given a request, extends it to a full storeRequestMsgData -// polimorphic: see addRequest for the types accepted -func (self *syncer) newStoreRequestMsgData(req interface{}) (*storeRequestMsgData, error) { - - key, id, chunk, sreq, err := parseRequest(req) - if err != nil { - return nil, err - } - - if sreq == nil { - if chunk == nil { - var err error - chunk, err = self.dbAccess.get(key) - if err != nil { - return nil, err - } - } - - sreq = &storeRequestMsgData{ - Id: id, - Key: chunk.Key, - SData: chunk.SData, - } - } - - return sreq, nil -} - -// parse request types and extracts, key, id, chunk, request if available -// does not do chunk lookup ! -func parseRequest(req interface{}) (storage.Key, uint64, *storage.Chunk, *storeRequestMsgData, error) { - var key storage.Key - var entry *syncDbEntry - var chunk *storage.Chunk - var id uint64 - var ok bool - var sreq *storeRequestMsgData - var err error - - if key, ok = req.(storage.Key); ok { - id = generateId() - - } else if entry, ok = req.(*syncDbEntry); ok { - id = binary.BigEndian.Uint64(entry.val[32:]) - key = storage.Key(entry.val[:32]) - - } else if chunk, ok = req.(*storage.Chunk); ok { - key = chunk.Key - id = generateId() - - } else if sreq, ok = req.(*storeRequestMsgData); ok { - key = sreq.Key - } else { - err = fmt.Errorf("type not allowed: %v (%T)", req, req) - } - - return key, id, chunk, sreq, err -} diff --git a/swarm/network_test.go b/swarm/network_test.go new file mode 100644 index 0000000000..3221b852b6 --- /dev/null +++ b/swarm/network_test.go @@ -0,0 +1,528 @@ +// 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 swarm + +import ( + "context" + "flag" + "fmt" + "io/ioutil" + "math/rand" + "os" + "sync" + "sync/atomic" + "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" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/simulations/adapters" + "github.com/ethereum/go-ethereum/swarm/api" + "github.com/ethereum/go-ethereum/swarm/network/simulation" + "github.com/ethereum/go-ethereum/swarm/storage" + "github.com/mattn/go-colorable" +) + +var ( + loglevel = flag.Int("loglevel", 2, "verbosity of logs") + longrunning = flag.Bool("longrunning", false, "do run long-running tests") + waitKademlia = flag.Bool("waitkademlia", false, "wait for healthy kademlia before checking files availability") +) + +func init() { + rand.Seed(time.Now().UnixNano()) + + flag.Parse() + + log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true)))) +} + +// TestSwarmNetwork runs a series of test simulations with +// static and dynamic Swarm nodes in network simulation, by +// uploading files to every node and retrieving them. +func TestSwarmNetwork(t *testing.T) { + var tests = []testSwarmNetworkCase{ + { + name: "10_nodes", + steps: []testSwarmNetworkStep{ + { + nodeCount: 10, + }, + }, + options: &testSwarmNetworkOptions{ + Timeout: 45 * time.Second, + }, + }, + { + name: "10_nodes_skip_check", + steps: []testSwarmNetworkStep{ + { + nodeCount: 10, + }, + }, + options: &testSwarmNetworkOptions{ + Timeout: 45 * time.Second, + 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{ + { + nodeCount: 50, + }, + }, + options: &testSwarmNetworkOptions{ + Timeout: 3 * time.Minute, + }, + }, + { + name: "50_nodes_skip_check", + steps: []testSwarmNetworkStep{ + { + nodeCount: 50, + }, + }, + options: &testSwarmNetworkOptions{ + Timeout: 3 * time.Minute, + SkipCheck: true, + }, + }, + { + name: "inc_node_count", + steps: []testSwarmNetworkStep{ + { + nodeCount: 2, + }, + { + nodeCount: 5, + }, + { + nodeCount: 10, + }, + }, + options: &testSwarmNetworkOptions{ + Timeout: 90 * time.Second, + }, + }, + { + name: "dec_node_count", + steps: []testSwarmNetworkStep{ + { + nodeCount: 10, + }, + { + nodeCount: 6, + }, + { + nodeCount: 3, + }, + }, + options: &testSwarmNetworkOptions{ + Timeout: 90 * time.Second, + }, + }, + { + name: "inc_dec_node_count", + steps: []testSwarmNetworkStep{ + { + nodeCount: 3, + }, + { + nodeCount: 5, + }, + { + nodeCount: 25, + }, + { + nodeCount: 10, + }, + { + nodeCount: 4, + }, + }, + options: &testSwarmNetworkOptions{ + Timeout: 5 * time.Minute, + }, + }, + { + name: "inc_dec_node_count_skip_check", + steps: []testSwarmNetworkStep{ + { + nodeCount: 3, + }, + { + nodeCount: 5, + }, + { + nodeCount: 25, + }, + { + nodeCount: 10, + }, + { + nodeCount: 4, + }, + }, + options: &testSwarmNetworkOptions{ + Timeout: 5 * time.Minute, + SkipCheck: true, + }, + }, + } +} + +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. +type file struct { + addr storage.Address + data string + nodeID enode.ID +} + +// check represents a reference to a file that is retrieved +// from a particular node. +type check struct { + key string + nodeID enode.ID +} + +// testSwarmNetwork is a helper function used for testing different +// static and dynamic Swarm network simulations. +// It is responsible for: +// - Setting up a Swarm network simulation, and updates the number of nodes within the network on every step according to steps. +// - Uploading a unique file to every node on every step. +// - 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) + } + + sim := simulation.New(map[string]simulation.ServiceFunc{ + "swarm": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { + config := api.NewConfig() + + dir, err := ioutil.TempDir("", "swarm-network-test-node") + if err != nil { + return nil, nil, err + } + cleanup = func() { + err := os.RemoveAll(dir) + if err != nil { + log.Error("cleaning up swarm temp dir", "err", err) + } + } + + config.Path = dir + + privkey, err := crypto.GenerateKey() + if err != nil { + return nil, cleanup, err + } + + config.Init(privkey) + config.DeliverySkipCheck = o.SkipCheck + config.Port = "" + + swarm, err := NewSwarm(config, nil) + if err != nil { + return nil, cleanup, err + } + bucket.Store(simulation.BucketKeyKademlia, swarm.bzz.Hive.Kademlia) + log.Info("new swarm", "bzzKey", config.BzzKey, "baseAddr", fmt.Sprintf("%x", swarm.bzz.BaseAddr())) + return swarm, cleanup, nil + }, + }) + defer sim.Close() + + ctx := context.Background() + if o.Timeout > 0 { + var cancel context.CancelFunc + ctx, cancel = context.WithTimeout(ctx, o.Timeout) + defer cancel() + } + + files := make([]file, 0) + + for i, step := range steps { + log.Debug("test sync step", "n", i+1, "nodes", step.nodeCount) + + change := step.nodeCount - len(sim.UpNodeIDs()) + + if change > 0 { + _, err := sim.AddNodesAndConnectChain(change) + if err != nil { + t.Fatal(err) + } + } else if change < 0 { + _, err := sim.StopRandomNodes(-change) + if err != nil { + t.Fatal(err) + } + } else { + t.Logf("step %v: no change in nodes", i) + continue + } + + var checkStatusM sync.Map + var nodeStatusM sync.Map + var totalFoundCount uint64 + + result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) error { + nodeIDs := sim.UpNodeIDs() + rand.Shuffle(len(nodeIDs), func(i, j int) { + nodeIDs[i], nodeIDs[j] = nodeIDs[j], nodeIDs[i] + }) + for _, id := range nodeIDs { + key, data, err := uploadFile(sim.Service("swarm", id).(*Swarm)) + if err != nil { + return err + } + log.Trace("file uploaded", "node", id, "key", key.String()) + files = append(files, file{ + addr: key, + data: data, + nodeID: id, + }) + } + + if *waitKademlia { + if _, err := sim.WaitTillHealthy(ctx); err != nil { + return err + } + } + + // File retrieval check is repeated until all uploaded files are retrieved from all nodes + // or until the timeout is reached. + for { + if retrieve(sim, files, &checkStatusM, &nodeStatusM, &totalFoundCount) == 0 { + return nil + } + } + }) + + if result.Error != nil { + t.Fatal(result.Error) + } + log.Debug("done: test sync step", "n", i+1, "nodes", step.nodeCount) + } +} + +// uploadFile, uploads a short file to the swarm instance +// using the api.Put method. +func uploadFile(swarm *Swarm) (storage.Address, string, error) { + b := make([]byte, 8) + _, err := rand.Read(b) + if err != nil { + return nil, "", err + } + // File data is very short, but it is ensured that its + // uniqueness is very certain. + data := fmt.Sprintf("test content %s %x", time.Now().Round(0), b) + ctx := context.TODO() + k, wait, err := swarm.api.Put(ctx, data, "text/plain", false) + if err != nil { + return nil, "", err + } + if wait != nil { + err = wait(ctx) + } + return k, data, err +} + +// retrieve is the function that is used for checking the availability of +// uploaded files in testSwarmNetwork test helper function. +func retrieve( + sim *simulation.Simulation, + files []file, + checkStatusM *sync.Map, + nodeStatusM *sync.Map, + totalFoundCount *uint64, +) (missing uint64) { + rand.Shuffle(len(files), func(i, j int) { + files[i], files[j] = files[j], files[i] + }) + + var totalWg sync.WaitGroup + errc := make(chan error) + + nodeIDs := sim.UpNodeIDs() + + totalCheckCount := len(nodeIDs) * len(files) + + for _, id := range nodeIDs { + if _, ok := nodeStatusM.Load(id); ok { + continue + } + start := time.Now() + var checkCount uint64 + var foundCount uint64 + + totalWg.Add(1) + + var wg sync.WaitGroup + + swarm := sim.Service("swarm", id).(*Swarm) + for _, f := range files { + + checkKey := check{ + key: f.addr.String(), + nodeID: id, + } + if n, ok := checkStatusM.Load(checkKey); ok && n.(int) == 0 { + continue + } + + checkCount++ + wg.Add(1) + go func(f file, id enode.ID) { + defer wg.Done() + + log.Debug("api get: check file", "node", id.String(), "key", f.addr.String(), "total files found", atomic.LoadUint64(totalFoundCount)) + + r, _, _, _, err := swarm.api.Get(context.TODO(), api.NOOPDecrypt, f.addr, "/") + if err != nil { + errc <- fmt.Errorf("api get: node %s, key %s, kademlia %s: %v", id, f.addr, swarm.bzz.Hive, err) + return + } + d, err := ioutil.ReadAll(r) + if err != nil { + errc <- fmt.Errorf("api get: read response: node %s, key %s: kademlia %s: %v", id, f.addr, swarm.bzz.Hive, err) + return + } + data := string(d) + if data != f.data { + errc <- fmt.Errorf("file contend missmatch: node %s, key %s, expected %q, got %q", id, f.addr, f.data, data) + return + } + checkStatusM.Store(checkKey, 0) + atomic.AddUint64(&foundCount, 1) + log.Info("api get: file found", "node", id.String(), "key", f.addr.String(), "content", data, "files found", atomic.LoadUint64(&foundCount)) + }(f, id) + } + + go func(id enode.ID) { + defer totalWg.Done() + wg.Wait() + + atomic.AddUint64(totalFoundCount, foundCount) + + if foundCount == checkCount { + log.Info("all files are found for node", "id", id.String(), "duration", time.Since(start)) + nodeStatusM.Store(id, 0) + return + } + log.Debug("files missing for node", "id", id.String(), "check", checkCount, "found", foundCount) + }(id) + + } + + go func() { + totalWg.Wait() + close(errc) + }() + + var errCount int + for err := range errc { + if err != nil { + errCount++ + } + log.Warn(err.Error()) + } + + log.Info("check stats", "total check count", totalCheckCount, "total files found", atomic.LoadUint64(totalFoundCount), "total errors", errCount) + + return uint64(totalCheckCount) - atomic.LoadUint64(totalFoundCount) +} diff --git a/swarm/pot/address.go b/swarm/pot/address.go new file mode 100644 index 0000000000..91cada2e88 --- /dev/null +++ b/swarm/pot/address.go @@ -0,0 +1,210 @@ +// Copyright 2017 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 pot see doc.go +package pot + +import ( + "encoding/binary" + "fmt" + "math/rand" + "strconv" + "strings" + + "github.com/ethereum/go-ethereum/common" +) + +var ( + zerosBin = Address{}.Bin() +) + +// Address is an alias for common.Hash +type Address common.Hash + +// NewAddressFromBytes constructs an Address from a byte slice +func NewAddressFromBytes(b []byte) Address { + h := common.Hash{} + copy(h[:], b) + return Address(h) +} + +func (a Address) String() string { + return fmt.Sprintf("%x", a[:]) +} + +// MarshalJSON Address serialisation +func (a *Address) MarshalJSON() (out []byte, err error) { + return []byte(`"` + a.String() + `"`), nil +} + +// UnmarshalJSON Address deserialisation +func (a *Address) UnmarshalJSON(value []byte) error { + *a = Address(common.HexToHash(string(value[1 : len(value)-1]))) + return nil +} + +// Bin returns the string form of the binary representation of an address (only first 8 bits) +func (a Address) Bin() string { + return ToBin(a[:]) +} + +// ToBin converts a byteslice to the string binary representation +func ToBin(a []byte) string { + var bs []string + for _, b := range a { + bs = append(bs, fmt.Sprintf("%08b", b)) + } + return strings.Join(bs, "") +} + +// Bytes returns the Address as a byte slice +func (a Address) Bytes() []byte { + return a[:] +} + +// ProxCmp compares the distances a->target and b->target. +// Returns -1 if a is closer to target, 1 if b is closer to target +// and 0 if they are equal. +func ProxCmp(a, x, y interface{}) int { + return proxCmp(ToBytes(a), ToBytes(x), ToBytes(y)) +} + +func proxCmp(a, x, y []byte) int { + for i := range a { + dx := x[i] ^ a[i] + dy := y[i] ^ a[i] + if dx > dy { + return 1 + } else if dx < dy { + return -1 + } + } + return 0 +} + +// RandomAddressAt (address, prox) generates a random address +// at proximity order prox relative to address +// if prox is negative a random address is generated +func RandomAddressAt(self Address, prox int) (addr Address) { + addr = self + pos := -1 + if prox >= 0 { + pos = prox / 8 + trans := prox % 8 + transbytea := byte(0) + for j := 0; j <= trans; j++ { + transbytea |= 1 << uint8(7-j) + } + flipbyte := byte(1 << uint8(7-trans)) + transbyteb := transbytea ^ byte(255) + randbyte := byte(rand.Intn(255)) + addr[pos] = ((addr[pos] & transbytea) ^ flipbyte) | randbyte&transbyteb + } + for i := pos + 1; i < len(addr); i++ { + addr[i] = byte(rand.Intn(255)) + } + + return +} + +// RandomAddress generates a random address +func RandomAddress() Address { + return RandomAddressAt(Address{}, -1) +} + +// NewAddressFromString creates a byte slice from a string in binary representation +func NewAddressFromString(s string) []byte { + ha := [32]byte{} + + t := s + zerosBin[:len(zerosBin)-len(s)] + for i := 0; i < 4; i++ { + n, err := strconv.ParseUint(t[i*64:(i+1)*64], 2, 64) + if err != nil { + panic("wrong format: " + err.Error()) + } + binary.BigEndian.PutUint64(ha[i*8:(i+1)*8], n) + } + return ha[:] +} + +// BytesAddress is an interface for elements addressable by a byte slice +type BytesAddress interface { + Address() []byte +} + +// ToBytes turns the Val into bytes +func ToBytes(v Val) []byte { + if v == nil { + return nil + } + b, ok := v.([]byte) + if !ok { + ba, ok := v.(BytesAddress) + if !ok { + panic(fmt.Sprintf("unsupported value type %T", v)) + } + b = ba.Address() + } + return b +} + +// DefaultPof returns a proximity order comparison operator function +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) + if po >= max { + eq = true + po = max + } + return po, eq + } +} + +// 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] { + continue + } + oxo := one[i] ^ other[i] + start := 0 + if i == pos/8 { + start = pos % 8 + } + for j := start; j < 8; j++ { + if (oxo>>uint8(7-j))&0x01 != 0 { + return i*8 + j, false + } + } + } + return len(one) * 8, true +} + +// Label displays the node's key in binary format +func Label(v Val) string { + if v == nil { + return "" + } + if s, ok := v.(fmt.Stringer); ok { + return s.String() + } + if b, ok := v.([]byte); ok { + return ToBin(b) + } + panic(fmt.Sprintf("unsupported value type %T", v)) +} diff --git a/swarm/pot/doc.go b/swarm/pot/doc.go new file mode 100644 index 0000000000..cb6faea57b --- /dev/null +++ b/swarm/pot/doc.go @@ -0,0 +1,83 @@ +// Copyright 2017 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 pot (proximity order tree) implements a container similar to a binary tree. +The elements are generic Val interface types. + +Each fork in the trie is itself a value. Values of the subtree contained under +a node all share the same order when compared to other elements in the tree. + +Example of proximity order is the length of the common prefix over bitvectors. +(which is equivalent to the reverse rank of order of magnitude of the MSB first X +OR distance over finite set of integers). + +Methods take a comparison operator (pof, proximity order function) to compare two +value types. The default pof assumes Val to be or project to a byte slice using +the reverse rank on the MSB first XOR logarithmic distance. + +If the address space if limited, equality is defined as the maximum proximity order. + +The container offers applicative (functional) style methods on PO trees: +* adding/removing en element +* swap (value based add/remove) +* merging two PO trees (union) + +as well as iterator accessors that respect proximity order + +When synchronicity of membership if not 100% requirement (e.g. used as a database +of network connections), applicative structures have the advantage that nodes +are immutable therefore manipulation does not need locking allowing for +concurrent retrievals. +For the use case where the entire container is supposed to allow changes by +concurrent routines, + +Pot +* retrieval, insertion and deletion by key involves log(n) pointer lookups +* for any item retrieval (defined as common prefix on the binary key) +* provide synchronous iterators respecting proximity ordering wrt any item +* provide asynchronous iterator (for parallel execution of operations) over n items +* allows cheap iteration over ranges +* asymmetric concurrent merge (union) + +Note: +* as is, union only makes sense for set representations since which of two values +with equal keys survives is random +* intersection is not implemented +* simple get accessor is not implemented (but derivable from EachNeighbour) + +Pinned value on the node implies no need to copy keys of the item type. + +Note that +* the same set of values allows for a large number of alternative +POT representations. +* values on the top are accessed faster than lower ones and the steps needed to +retrieve items has a logarithmic distribution. + +As a consequence one can organise the tree so that items that need faster access +are torwards the top. In particular for any subset where popularity has a power +distriution that is independent of proximity order (content addressed storage of +chunks), it is in principle possible to create a pot where the steps needed to +access an item is inversely proportional to its popularity. +Such organisation is not implemented as yet. + +TODO: +* overwrite-style merge +* intersection +* access frequency based optimisations + +*/ +package pot diff --git a/swarm/pot/pot.go b/swarm/pot/pot.go new file mode 100644 index 0000000000..7e3967f3f9 --- /dev/null +++ b/swarm/pot/pot.go @@ -0,0 +1,787 @@ +// Copyright 2017 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 pot see doc.go +package pot + +import ( + "fmt" + "sync" +) + +const ( + maxkeylen = 256 +) + +// Pot is the node type (same for root, branching node and leaf) +type Pot struct { + pin Val + bins []*Pot + size int + po int +} + +// Val is the element type for Pots +type Val interface{} + +// Pof is the proximity order comparison operator function +type Pof func(Val, Val, int) (int, bool) + +// NewPot constructor. Requires a value of type Val to pin +// and po to point to a span in the Val key +// The pinned item counts towards the size +func NewPot(v Val, po int) *Pot { + var size int + if v != nil { + size++ + } + return &Pot{ + pin: v, + po: po, + size: size, + } +} + +// Pin returns the pinned element (key) of the Pot +func (t *Pot) Pin() Val { + return t.pin +} + +// Size returns the number of values in the Pot +func (t *Pot) Size() int { + if t == nil { + return 0 + } + return t.size +} + +// Add inserts a new value into the Pot and +// returns the proximity order of v and a boolean +// indicating if the item was found +// Add called on (t, v) returns a new Pot that contains all the elements of t +// plus the value v, using the applicative add +// the second return value is the proximity order of the inserted element +// the third is boolean indicating if the item was found +func Add(t *Pot, val Val, pof Pof) (*Pot, int, bool) { + return add(t, val, pof) +} + +func (t *Pot) clone() *Pot { + return &Pot{ + pin: t.pin, + size: t.size, + po: t.po, + bins: t.bins, + } +} + +func add(t *Pot, val Val, pof Pof) (*Pot, int, bool) { + var r *Pot + if t == nil || t.pin == nil { + r = t.clone() + r.pin = val + r.size++ + return r, 0, false + } + po, found := pof(t.pin, val, t.po) + if found { + r = t.clone() + r.pin = val + return r, po, true + } + + var p *Pot + var i, j int + size := t.size + for i < len(t.bins) { + n := t.bins[i] + if n.po == po { + p, _, found = add(n, val, pof) + if !found { + size++ + } + j++ + break + } + if n.po > po { + break + } + i++ + j++ + } + if p == nil { + size++ + p = &Pot{ + pin: val, + size: 1, + po: po, + } + } + + bins := append([]*Pot{}, t.bins[:i]...) + bins = append(bins, p) + bins = append(bins, t.bins[j:]...) + r = &Pot{ + pin: t.pin, + size: size, + po: t.po, + bins: bins, + } + + return r, po, 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) +} + +func remove(t *Pot, val Val, pof Pof) (r *Pot, po int, found bool) { + size := t.size + po, found = pof(t.pin, val, t.po) + if found { + size-- + if size == 0 { + return &Pot{}, po, true + } + i := len(t.bins) - 1 + last := t.bins[i] + r = &Pot{ + pin: last.pin, + bins: append(t.bins[:i], last.bins...), + size: size, + po: t.po, + } + return r, t.po, true + } + + var p *Pot + var i, j int + for i < len(t.bins) { + n := t.bins[i] + if n.po == po { + p, po, found = remove(n, val, pof) + if found { + size-- + } + j++ + break + } + if n.po > po { + return t, po, false + } + i++ + j++ + } + bins := t.bins[:i] + if p != nil && p.pin != nil { + bins = append(bins, p) + } + bins = append(bins, t.bins[j:]...) + r = &Pot{ + pin: t.pin, + size: size, + po: t.po, + bins: bins, + } + return r, po, found +} + +// Swap called on (k, f) looks up the item at k +// and applies the function f to the value v at k or to nil if the item is not found +// if f(v) returns nil, the element is removed +// if f(v) returns v' <> v then v' is inserted into the Pot +// if (v) == v the Pot is not changed +// it panics if Pof(f(v), k) show that v' and v are not key-equal +func Swap(t *Pot, k Val, pof Pof, f func(v Val) Val) (r *Pot, po int, found bool, change bool) { + var val Val + if t.pin == nil { + val = f(nil) + if val == nil { + return nil, 0, false, false + } + return NewPot(val, t.po), 0, false, true + } + size := t.size + po, found = pof(k, t.pin, t.po) + if found { + val = f(t.pin) + // remove element + if val == nil { + size-- + if size == 0 { + r = &Pot{ + po: t.po, + } + // return empty pot + return r, po, true, true + } + // actually remove pin, by merging last bin + i := len(t.bins) - 1 + last := t.bins[i] + r = &Pot{ + pin: last.pin, + bins: append(t.bins[:i], last.bins...), + size: size, + po: t.po, + } + return r, po, true, true + } + // element found but no change + if val == t.pin { + return t, po, true, false + } + // actually modify the pinned element, but no change in structure + r = t.clone() + r.pin = val + return r, po, true, true + } + + // recursive step + var p *Pot + n, i := t.getPos(po) + if n != nil { + p, po, found, change = Swap(n, k, pof, f) + // recursive no change + if !change { + return t, po, found, false + } + // recursive change + bins := append([]*Pot{}, t.bins[:i]...) + if p.size == 0 { + size-- + } else { + size += p.size - n.size + bins = append(bins, p) + } + i++ + if i < len(t.bins) { + bins = append(bins, t.bins[i:]...) + } + r = t.clone() + r.bins = bins + r.size = size + return r, po, found, true + } + // key does not exist + val = f(nil) + if val == nil { + // and it should not be created + return t, po, false, false + } + // otherwise check val if equal to k + if _, eq := pof(val, k, po); !eq { + panic("invalid value") + } + /// + size++ + p = &Pot{ + pin: val, + size: 1, + po: po, + } + + bins := append([]*Pot{}, t.bins[:i]...) + bins = append(bins, p) + if i < len(t.bins) { + bins = append(bins, t.bins[i:]...) + } + r = t.clone() + r.bins = bins + r.size = size + return r, po, found, true +} + +// Union called on (t0, t1, pof) returns the union of t0 and t1 +// calculates the union using the applicative union +// the second return value is the number of common elements +func Union(t0, t1 *Pot, pof Pof) (*Pot, int) { + return union(t0, t1, pof) +} + +func union(t0, t1 *Pot, pof Pof) (*Pot, int) { + if t0 == nil || t0.size == 0 { + return t1, 0 + } + if t1 == nil || t1.size == 0 { + return t0, 0 + } + var pin Val + var bins []*Pot + var mis []int + wg := &sync.WaitGroup{} + wg.Add(1) + pin0 := t0.pin + pin1 := t1.pin + bins0 := t0.bins + bins1 := t1.bins + var i0, i1 int + var common int + + po, eq := pof(pin0, pin1, 0) + + for { + l0 := len(bins0) + l1 := len(bins1) + var n0, n1 *Pot + var p0, p1 int + var a0, a1 bool + + for { + + if !a0 && i0 < l0 && bins0[i0] != nil && bins0[i0].po <= po { + n0 = bins0[i0] + p0 = n0.po + a0 = p0 == po + } else { + a0 = true + } + + if !a1 && i1 < l1 && bins1[i1] != nil && bins1[i1].po <= po { + n1 = bins1[i1] + p1 = n1.po + a1 = p1 == po + } else { + a1 = true + } + if a0 && a1 { + break + } + + switch { + case (p0 < p1 || a1) && !a0: + bins = append(bins, n0) + i0++ + n0 = nil + case (p1 < p0 || a0) && !a1: + bins = append(bins, n1) + i1++ + n1 = nil + case p1 < po: + bl := len(bins) + bins = append(bins, nil) + ml := len(mis) + mis = append(mis, 0) + // wg.Add(1) + // go func(b, m int, m0, m1 *Pot) { + // defer wg.Done() + // bins[b], mis[m] = union(m0, m1, pof) + // }(bl, ml, n0, n1) + bins[bl], mis[ml] = union(n0, n1, pof) + i0++ + i1++ + n0 = nil + n1 = nil + } + } + + if eq { + common++ + pin = pin1 + break + } + + i := i0 + if len(bins0) > i && bins0[i].po == po { + i++ + } + var size0 int + for _, n := range bins0[i:] { + size0 += n.size + } + np := &Pot{ + pin: pin0, + bins: bins0[i:], + size: size0 + 1, + po: po, + } + + bins2 := []*Pot{np} + if n0 == nil { + pin0 = pin1 + po = maxkeylen + 1 + eq = true + common-- + + } else { + bins2 = append(bins2, n0.bins...) + pin0 = pin1 + pin1 = n0.pin + po, eq = pof(pin0, pin1, n0.po) + + } + bins0 = bins1 + bins1 = bins2 + i0 = i1 + i1 = 0 + + } + + wg.Done() + wg.Wait() + for _, c := range mis { + common += c + } + n := &Pot{ + pin: pin, + bins: bins, + size: t0.size + t1.size - common, + po: t0.po, + } + return n, common +} + +// 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) +} + +// 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 + } + for _, n := range t.bins { + if !n.each(f) { + return false + } + } + 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) 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) bool) bool) bool) { + if t == nil || t.size == 0 { + return + } + spr, _ := pof(t.pin, val, t.po) + _, lim := t.getPos(spr) + var size int + var n *Pot + for i := 0; i < lim; i++ { + n = t.bins[i] + size += n.size + if n.po < po { + continue + } + if !f(n.po, n.size, n.each) { + return + } + } + if lim == len(t.bins) { + if spr >= po { + f(spr, 1, func(g func(Val) bool) bool { + return g(t.pin) + }) + } + return + } + + n = t.bins[lim] + + spo := spr + if n.po == spr { + spo++ + size += n.size + } + if spr >= po { + if !f(spr, t.size-size, func(g func(Val) bool) bool { + return t.eachFrom(func(v Val) bool { + return g(v) + }, spo) + }) { + return + } + } + if n.po == spr { + n.eachBin(val, pof, po, f) + } + +} + +// EachNeighbour is a synchronous iterator over neighbours of any target val +// the order of elements retrieved reflect proximity order to the target +// TODO: add maximum proxbin to start range of iteration +func (t *Pot) EachNeighbour(val Val, pof Pof, f func(Val, int) bool) bool { + return t.eachNeighbour(val, pof, f) +} + +func (t *Pot) eachNeighbour(val Val, pof Pof, f func(Val, int) bool) bool { + if t == nil || t.size == 0 { + return false + } + var next bool + l := len(t.bins) + var n *Pot + ir := l + il := l + po, eq := pof(t.pin, val, t.po) + if !eq { + n, il = t.getPos(po) + if n != nil { + next = n.eachNeighbour(val, pof, f) + if !next { + return false + } + ir = il + } else { + ir = il - 1 + } + } + + next = f(t.pin, po) + if !next { + return false + } + + for i := l - 1; i > ir; i-- { + next = t.bins[i].each(func(v Val) bool { + return f(v, po) + }) + if !next { + return false + } + } + + for i := il - 1; i >= 0; i-- { + n := t.bins[i] + next = n.each(func(v Val) bool { + return f(v, n.po) + }) + if !next { + return false + } + } + return true +} + +// EachNeighbourAsync called on (val, max, maxPos, f, wait) is an asynchronous iterator +// over elements not closer than maxPos wrt val. +// val does not need to be match an element of the Pot, but if it does, and +// maxPos is keylength than it is included in the iteration +// Calls to f are parallelised, the order of calls is undefined. +// proximity order is respected in that there is no element in the Pot that +// is not visited if a closer node is visited. +// The iteration is finished when max number of nearest nodes is visited +// or if the entire there are no nodes not closer than maxPos that is not visited +// if wait is true, the iterator returns only if all calls to f are finished +// TODO: implement minPos for proper prox range iteration +func (t *Pot) EachNeighbourAsync(val Val, pof Pof, max int, maxPos int, f func(Val, int), wait bool) { + if max > t.size { + max = t.size + } + var wg *sync.WaitGroup + if wait { + wg = &sync.WaitGroup{} + } + t.eachNeighbourAsync(val, pof, max, maxPos, f, wg) + if wait { + wg.Wait() + } +} + +func (t *Pot) eachNeighbourAsync(val Val, pof Pof, max int, maxPos int, f func(Val, int), wg *sync.WaitGroup) (extra int) { + l := len(t.bins) + + po, eq := pof(t.pin, val, t.po) + + // if po is too close, set the pivot branch (pom) to maxPos + pom := po + if pom > maxPos { + pom = maxPos + } + n, il := t.getPos(pom) + ir := il + // if pivot branch exists and po is not too close, iterate on the pivot branch + if pom == po { + if n != nil { + + m := n.size + if max < m { + m = max + } + max -= m + + extra = n.eachNeighbourAsync(val, pof, m, maxPos, f, wg) + + } else { + if !eq { + ir-- + } + } + } else { + extra++ + max-- + if n != nil { + il++ + } + // before checking max, add up the extra elements + // on the close branches that are skipped (if po is too close) + for i := l - 1; i >= il; i-- { + s := t.bins[i] + m := s.size + if max < m { + m = max + } + max -= m + extra += m + } + } + + var m int + if pom == po { + + m, max, extra = need(1, max, extra) + if m <= 0 { + return + } + + if wg != nil { + wg.Add(1) + } + go func() { + if wg != nil { + defer wg.Done() + } + f(t.pin, po) + }() + + // otherwise iterats + for i := l - 1; i > ir; i-- { + n := t.bins[i] + + m, max, extra = need(n.size, max, extra) + if m <= 0 { + return + } + + if wg != nil { + wg.Add(m) + } + go func(pn *Pot, pm int) { + pn.each(func(v Val) bool { + if wg != nil { + defer wg.Done() + } + f(v, po) + pm-- + return pm > 0 + }) + }(n, m) + + } + } + + // iterate branches that are farther tham pom with their own po + for i := il - 1; i >= 0; i-- { + n := t.bins[i] + // the first time max is less than the size of the entire branch + // wait for the pivot thread to release extra elements + m, max, extra = need(n.size, max, extra) + if m <= 0 { + return + } + + if wg != nil { + wg.Add(m) + } + go func(pn *Pot, pm int) { + pn.each(func(v Val) bool { + if wg != nil { + defer wg.Done() + } + f(v, pn.po) + pm-- + return pm > 0 + }) + }(n, m) + + } + return max + extra +} + +// getPos called on (n) returns the forking node at PO n and its index if it exists +// otherwise nil +// caller is supposed to hold the lock +func (t *Pot) getPos(po int) (n *Pot, i int) { + for i, n = range t.bins { + if po > n.po { + continue + } + if po < n.po { + return nil, i + } + return n, i + } + return nil, len(t.bins) +} + +// need called on (m, max, extra) uses max m out of extra, and then max +// if needed, returns the adjusted counts +func need(m, max, extra int) (int, int, int) { + if m <= extra { + return m, max, extra - m + } + max += extra - m + if max <= 0 { + return m + max, 0, 0 + } + return m, max, 0 +} + +func (t *Pot) String() string { + return t.sstring("") +} + +func (t *Pot) sstring(indent string) string { + if t == nil { + return "" + } + var s string + indent += " " + s += fmt.Sprintf("%v%v (%v) %v \n", indent, t.pin, t.po, t.size) + for _, n := range t.bins { + s += fmt.Sprintf("%v%v\n", indent, n.sstring(indent)) + } + return s +} diff --git a/swarm/pot/pot_test.go b/swarm/pot/pot_test.go new file mode 100644 index 0000000000..83d604919f --- /dev/null +++ b/swarm/pot/pot_test.go @@ -0,0 +1,741 @@ +// Copyright 2017 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 pot + +import ( + "errors" + "fmt" + "math/rand" + "runtime" + "sync" + "testing" + "time" + + "github.com/ethereum/go-ethereum/swarm/log" +) + +const ( + maxEachNeighbourTests = 420 + maxEachNeighbour = 420 + maxSwap = 420 + maxSwapTests = 420 +) + +// func init() { +// log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(false)))) +// } + +type testAddr struct { + a []byte + i int +} + +func newTestAddr(s string, i int) *testAddr { + return &testAddr{NewAddressFromString(s), i} +} + +func (a *testAddr) Address() []byte { + return a.a +} + +func (a *testAddr) String() string { + return Label(a.a) +} + +func randomTestAddr(n int, i int) *testAddr { + v := RandomAddress().Bin()[:n] + return newTestAddr(v, i) +} + +func randomtestAddr(n int, i int) *testAddr { + v := RandomAddress().Bin()[:n] + return newTestAddr(v, i) +} + +func indexes(t *Pot) (i []int) { + t.Each(func(v Val) bool { + a := v.(*testAddr) + i = append(i, a.i) + return true + }) + return i +} + +func testAdd(t *Pot, pof Pof, j int, values ...string) (_ *Pot, n int, f bool) { + for i, val := range values { + t, n, f = Add(t, newTestAddr(val, i+j), pof) + } + 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) + // Pin set correctly + exp := "00111100" + got := Label(n.Pin())[:8] + if got != exp { + t.Fatalf("incorrect pinned value. Expected %v, got %v", exp, got) + } + // check size + goti := n.Size() + expi := 1 + if goti != expi { + t.Fatalf("incorrect number of elements in Pot. Expected %v, got %v", expi, goti) + } + + n, _, _ = testAdd(n, pof, 1, "01111100", "00111100", "01111100", "00011100") + // check size + goti = n.Size() + expi = 3 + 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 = "[3 4 2]" + if got != exp { + t.Fatalf("incorrect indexes in iteration over Pot. Expected %v, got %v", exp, got) + } +} + +func TestPotRemove(t *testing.T) { + pof := DefaultPof(8) + n := NewPot(newTestAddr("00111100", 0), 0) + n, _, _ = Remove(n, newTestAddr("00111100", 0), pof) + exp := "" + got := Label(n.Pin()) + if got != exp { + t.Fatalf("incorrect pinned value. Expected %v, got %v", exp, got) + } + n, _, _ = testAdd(n, pof, 1, "00000000", "01111100", "00111100", "00011100") + n, _, _ = Remove(n, newTestAddr("00111100", 0), pof) + goti := n.Size() + expi := 3 + 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 = "[2 4 1]" + if got != exp { + t.Fatalf("incorrect indexes in iteration over Pot. Expected %v, got %v", exp, got) + } + 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 indexes in iteration over Pot. Expected %v, got %v", exp, got) + } + 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) { + for i := 0; i < maxSwapTests; i++ { + alen := maxkeylen + pof := DefaultPof(alen) + max := rand.Intn(maxSwap) + + n := NewPot(nil, 0) + var m []*testAddr + var found bool + for j := 0; j < 2*max; { + v := randomtestAddr(alen, j) + n, _, found = Add(n, v, pof) + if !found { + m = append(m, v) + j++ + } + } + k := make(map[string]*testAddr) + for j := 0; j < max; { + v := randomtestAddr(alen, 1) + _, found := k[Label(v)] + if !found { + k[Label(v)] = v + j++ + } + } + for _, v := range k { + m = append(m, v) + } + f := func(v Val) Val { + tv := v.(*testAddr) + if tv.i < max { + return nil + } + tv.i = 0 + return v + } + for _, val := range m { + n, _, _, _ = Swap(n, val, pof, func(v Val) Val { + if v == nil { + return val + } + return f(v) + }) + } + sum := 0 + n.Each(func(v Val) bool { + if v == nil { + return true + } + sum++ + tv := v.(*testAddr) + if tv.i > 1 { + t.Fatalf("item value incorrect, expected 0, got %v", tv.i) + } + return true + }) + if sum != 2*max { + t.Fatalf("incorrect number of elements. expected %v, got %v", 2*max, sum) + } + if sum != n.Size() { + t.Fatalf("incorrect size. expected %v, got %v", sum, n.Size()) + } + } +} + +func checkPo(val Val, pof Pof) func(Val, int) error { + return func(v Val, po int) error { + // check the po + exp, _ := pof(val, v, 0) + if po != exp { + return fmt.Errorf("incorrect prox order for item %v in neighbour iteration for %v. Expected %v, got %v", v, val, exp, po) + } + return nil + } +} + +func checkOrder(val Val) func(Val, int) error { + po := maxkeylen + return func(v Val, p int) error { + if po < p { + return fmt.Errorf("incorrect order for item %v in neighbour iteration for %v. PO %v > %v (previous max)", v, val, p, po) + } + po = p + return nil + } +} + +func checkValues(m map[string]bool, val Val) func(Val, int) error { + return func(v Val, po int) error { + duplicate, ok := m[Label(v)] + if !ok { + return fmt.Errorf("alien value %v", v) + } + if duplicate { + return fmt.Errorf("duplicate value returned: %v", v) + } + m[Label(v)] = true + return nil + } +} + +var errNoCount = errors.New("not count") + +func testPotEachNeighbour(n *Pot, pof Pof, val Val, expCount int, fs ...func(Val, int) error) error { + var err error + var count int + n.EachNeighbour(val, pof, func(v Val, po int) bool { + for _, f := range fs { + err = f(v, po) + if err != nil { + return err.Error() == errNoCount.Error() + } + } + count++ + return count != expCount + }) + if err == nil && count < expCount { + return fmt.Errorf("not enough neighbours returned, expected %v, got %v", expCount, count) + } + return err +} + +const ( + mergeTestCount = 5 + mergeTestChoose = 5 +) + +func TestPotMergeCommon(t *testing.T) { + vs := make([]*testAddr, mergeTestCount) + for i := 0; i < maxEachNeighbourTests; i++ { + alen := maxkeylen + pof := DefaultPof(alen) + + for j := 0; j < len(vs); j++ { + vs[j] = randomtestAddr(alen, j) + } + max0 := rand.Intn(mergeTestChoose) + 1 + max1 := rand.Intn(mergeTestChoose) + 1 + n0 := NewPot(nil, 0) + n1 := NewPot(nil, 0) + log.Trace(fmt.Sprintf("round %v: %v - %v", i, max0, max1)) + m := make(map[string]bool) + var found bool + for j := 0; j < max0; { + r := rand.Intn(max0) + v := vs[r] + n0, _, found = Add(n0, v, pof) + if !found { + m[Label(v)] = false + j++ + } + } + expAdded := 0 + + for j := 0; j < max1; { + r := rand.Intn(max1) + v := vs[r] + n1, _, found = Add(n1, v, pof) + if !found { + j++ + } + _, found = m[Label(v)] + if !found { + expAdded++ + m[Label(v)] = false + } + } + if i < 6 { + continue + } + expSize := len(m) + log.Trace(fmt.Sprintf("%v-0: pin: %v, size: %v", i, n0.Pin(), max0)) + log.Trace(fmt.Sprintf("%v-1: pin: %v, size: %v", i, n1.Pin(), max1)) + log.Trace(fmt.Sprintf("%v: merged tree size: %v, newly added: %v", i, expSize, expAdded)) + n, common := Union(n0, n1, pof) + added := n1.Size() - common + size := n.Size() + + if expSize != size { + t.Fatalf("%v: incorrect number of elements in merged pot, expected %v, got %v\n%v", i, expSize, size, n) + } + if expAdded != added { + t.Fatalf("%v: incorrect number of added elements in merged pot, expected %v, got %v", i, expAdded, added) + } + if !checkDuplicates(n) { + t.Fatalf("%v: merged pot contains duplicates: \n%v", i, n) + } + for k := range m { + _, _, found = Add(n, newTestAddr(k, 0), pof) + if !found { + t.Fatalf("%v: merged pot (size:%v, added: %v) missing element %v", i, size, added, k) + } + } + } +} + +func TestPotMergeScale(t *testing.T) { + for i := 0; i < maxEachNeighbourTests; i++ { + alen := maxkeylen + pof := DefaultPof(alen) + max0 := rand.Intn(maxEachNeighbour) + 1 + max1 := rand.Intn(maxEachNeighbour) + 1 + n0 := NewPot(nil, 0) + n1 := NewPot(nil, 0) + log.Trace(fmt.Sprintf("round %v: %v - %v", i, max0, max1)) + m := make(map[string]bool) + var found bool + for j := 0; j < max0; { + v := randomtestAddr(alen, j) + n0, _, found = Add(n0, v, pof) + if !found { + m[Label(v)] = false + j++ + } + } + expAdded := 0 + + for j := 0; j < max1; { + v := randomtestAddr(alen, j) + n1, _, found = Add(n1, v, pof) + if !found { + j++ + } + _, found = m[Label(v)] + if !found { + expAdded++ + m[Label(v)] = false + } + } + if i < 6 { + continue + } + expSize := len(m) + log.Trace(fmt.Sprintf("%v-0: pin: %v, size: %v", i, n0.Pin(), max0)) + log.Trace(fmt.Sprintf("%v-1: pin: %v, size: %v", i, n1.Pin(), max1)) + log.Trace(fmt.Sprintf("%v: merged tree size: %v, newly added: %v", i, expSize, expAdded)) + n, common := Union(n0, n1, pof) + added := n1.Size() - common + size := n.Size() + + if expSize != size { + t.Fatalf("%v: incorrect number of elements in merged pot, expected %v, got %v", i, expSize, size) + } + if expAdded != added { + t.Fatalf("%v: incorrect number of added elements in merged pot, expected %v, got %v", i, expAdded, added) + } + if !checkDuplicates(n) { + t.Fatalf("%v: merged pot contains duplicates", i) + } + for k := range m { + _, _, found = Add(n, newTestAddr(k, 0), pof) + if !found { + t.Fatalf("%v: merged pot (size:%v, added: %v) missing element %v", i, size, added, k) + } + } + } +} + +func checkDuplicates(t *Pot) bool { + po := -1 + for _, c := range t.bins { + if c == nil { + return false + } + if c.po <= po || !checkDuplicates(c) { + return false + } + po = c.po + } + return true +} + +func TestPotEachNeighbourSync(t *testing.T) { + for i := 0; i < maxEachNeighbourTests; i++ { + alen := maxkeylen + pof := DefaultPof(maxkeylen) + max := rand.Intn(maxEachNeighbour/2) + maxEachNeighbour/2 + pin := randomTestAddr(alen, 0) + n := NewPot(pin, 0) + m := make(map[string]bool) + m[Label(pin)] = false + for j := 1; j <= max; j++ { + v := randomTestAddr(alen, j) + n, _, _ = Add(n, v, pof) + m[Label(v)] = false + } + + size := n.Size() + if size < 2 { + continue + } + count := rand.Intn(size/2) + size/2 + val := randomTestAddr(alen, max+1) + log.Trace(fmt.Sprintf("%v: pin: %v, size: %v, val: %v, count: %v", i, n.Pin(), size, val, count)) + err := testPotEachNeighbour(n, pof, val, count, checkPo(val, pof), checkOrder(val), checkValues(m, val)) + if err != nil { + t.Fatal(err) + } + minPoFound := alen + maxPoNotFound := 0 + for k, found := range m { + po, _ := pof(val, newTestAddr(k, 0), 0) + if found { + if po < minPoFound { + minPoFound = po + } + } else { + if po > maxPoNotFound { + maxPoNotFound = po + } + } + } + if minPoFound < maxPoNotFound { + t.Fatalf("incorrect neighbours returned: found one with PO %v < there was one not found with PO %v", minPoFound, maxPoNotFound) + } + } +} + +func TestPotEachNeighbourAsync(t *testing.T) { + for i := 0; i < maxEachNeighbourTests; i++ { + max := rand.Intn(maxEachNeighbour/2) + maxEachNeighbour/2 + alen := maxkeylen + pof := DefaultPof(alen) + n := NewPot(randomTestAddr(alen, 0), 0) + size := 1 + var found bool + for j := 1; j <= max; j++ { + v := randomTestAddr(alen, j) + n, _, found = Add(n, v, pof) + if !found { + size++ + } + } + if size != n.Size() { + t.Fatal(n) + } + if size < 2 { + continue + } + count := rand.Intn(size/2) + size/2 + val := randomTestAddr(alen, max+1) + + mu := sync.Mutex{} + m := make(map[string]bool) + maxPos := rand.Intn(alen) + log.Trace(fmt.Sprintf("%v: pin: %v, size: %v, val: %v, count: %v, maxPos: %v", i, n.Pin(), size, val, count, maxPos)) + msize := 0 + remember := func(v Val, po int) error { + if po > maxPos { + return errNoCount + } + m[Label(v)] = true + msize++ + return nil + } + if i == 0 { + continue + } + testPotEachNeighbour(n, pof, val, count, remember) + d := 0 + forget := func(v Val, po int) { + mu.Lock() + defer mu.Unlock() + d++ + delete(m, Label(v)) + } + + n.EachNeighbourAsync(val, pof, count, maxPos, forget, true) + if d != msize { + t.Fatalf("incorrect number of neighbour calls in async iterator. expected %v, got %v", msize, d) + } + if len(m) != 0 { + t.Fatalf("incorrect neighbour calls in async iterator. %v items missed:\n%v", len(m), n) + } + } +} + +func benchmarkEachNeighbourSync(t *testing.B, max, count int, d time.Duration) { + t.ReportAllocs() + alen := maxkeylen + pof := DefaultPof(alen) + pin := randomTestAddr(alen, 0) + n := NewPot(pin, 0) + var found bool + for j := 1; j <= max; { + v := randomTestAddr(alen, j) + n, _, found = Add(n, v, pof) + if !found { + j++ + } + } + t.ResetTimer() + for i := 0; i < t.N; i++ { + val := randomTestAddr(alen, max+1) + m := 0 + n.EachNeighbour(val, pof, func(v Val, po int) bool { + time.Sleep(d) + m++ + return m != count + }) + } + t.StopTimer() + stats := new(runtime.MemStats) + runtime.ReadMemStats(stats) +} + +func benchmarkEachNeighbourAsync(t *testing.B, max, count int, d time.Duration) { + t.ReportAllocs() + alen := maxkeylen + pof := DefaultPof(alen) + pin := randomTestAddr(alen, 0) + n := NewPot(pin, 0) + var found bool + for j := 1; j <= max; { + v := randomTestAddr(alen, j) + n, _, found = Add(n, v, pof) + if !found { + j++ + } + } + t.ResetTimer() + for i := 0; i < t.N; i++ { + val := randomTestAddr(alen, max+1) + n.EachNeighbourAsync(val, pof, count, alen, func(v Val, po int) { + time.Sleep(d) + }, true) + } + t.StopTimer() + stats := new(runtime.MemStats) + runtime.ReadMemStats(stats) +} + +func BenchmarkEachNeighbourSync_3_1_0(t *testing.B) { + benchmarkEachNeighbourSync(t, 1000, 10, 1*time.Microsecond) +} +func BenchmarkEachNeighboursAsync_3_1_0(t *testing.B) { + benchmarkEachNeighbourAsync(t, 1000, 10, 1*time.Microsecond) +} +func BenchmarkEachNeighbourSync_3_2_0(t *testing.B) { + benchmarkEachNeighbourSync(t, 1000, 100, 1*time.Microsecond) +} +func BenchmarkEachNeighboursAsync_3_2_0(t *testing.B) { + benchmarkEachNeighbourAsync(t, 1000, 100, 1*time.Microsecond) +} +func BenchmarkEachNeighbourSync_3_3_0(t *testing.B) { + benchmarkEachNeighbourSync(t, 1000, 1000, 1*time.Microsecond) +} +func BenchmarkEachNeighboursAsync_3_3_0(t *testing.B) { + benchmarkEachNeighbourAsync(t, 1000, 1000, 1*time.Microsecond) +} + +func BenchmarkEachNeighbourSync_3_1_1(t *testing.B) { + benchmarkEachNeighbourSync(t, 1000, 10, 2*time.Microsecond) +} +func BenchmarkEachNeighboursAsync_3_1_1(t *testing.B) { + benchmarkEachNeighbourAsync(t, 1000, 10, 2*time.Microsecond) +} +func BenchmarkEachNeighbourSync_3_2_1(t *testing.B) { + benchmarkEachNeighbourSync(t, 1000, 100, 2*time.Microsecond) +} +func BenchmarkEachNeighboursAsync_3_2_1(t *testing.B) { + benchmarkEachNeighbourAsync(t, 1000, 100, 2*time.Microsecond) +} +func BenchmarkEachNeighbourSync_3_3_1(t *testing.B) { + benchmarkEachNeighbourSync(t, 1000, 1000, 2*time.Microsecond) +} +func BenchmarkEachNeighboursAsync_3_3_1(t *testing.B) { + benchmarkEachNeighbourAsync(t, 1000, 1000, 2*time.Microsecond) +} + +func BenchmarkEachNeighbourSync_3_1_2(t *testing.B) { + benchmarkEachNeighbourSync(t, 1000, 10, 4*time.Microsecond) +} +func BenchmarkEachNeighboursAsync_3_1_2(t *testing.B) { + benchmarkEachNeighbourAsync(t, 1000, 10, 4*time.Microsecond) +} +func BenchmarkEachNeighbourSync_3_2_2(t *testing.B) { + benchmarkEachNeighbourSync(t, 1000, 100, 4*time.Microsecond) +} +func BenchmarkEachNeighboursAsync_3_2_2(t *testing.B) { + benchmarkEachNeighbourAsync(t, 1000, 100, 4*time.Microsecond) +} +func BenchmarkEachNeighbourSync_3_3_2(t *testing.B) { + benchmarkEachNeighbourSync(t, 1000, 1000, 4*time.Microsecond) +} +func BenchmarkEachNeighboursAsync_3_3_2(t *testing.B) { + benchmarkEachNeighbourAsync(t, 1000, 1000, 4*time.Microsecond) +} + +func BenchmarkEachNeighbourSync_3_1_3(t *testing.B) { + benchmarkEachNeighbourSync(t, 1000, 10, 8*time.Microsecond) +} +func BenchmarkEachNeighboursAsync_3_1_3(t *testing.B) { + benchmarkEachNeighbourAsync(t, 1000, 10, 8*time.Microsecond) +} +func BenchmarkEachNeighbourSync_3_2_3(t *testing.B) { + benchmarkEachNeighbourSync(t, 1000, 100, 8*time.Microsecond) +} +func BenchmarkEachNeighboursAsync_3_2_3(t *testing.B) { + benchmarkEachNeighbourAsync(t, 1000, 100, 8*time.Microsecond) +} +func BenchmarkEachNeighbourSync_3_3_3(t *testing.B) { + benchmarkEachNeighbourSync(t, 1000, 1000, 8*time.Microsecond) +} +func BenchmarkEachNeighboursAsync_3_3_3(t *testing.B) { + benchmarkEachNeighbourAsync(t, 1000, 1000, 8*time.Microsecond) +} + +func BenchmarkEachNeighbourSync_3_1_4(t *testing.B) { + benchmarkEachNeighbourSync(t, 1000, 10, 16*time.Microsecond) +} +func BenchmarkEachNeighboursAsync_3_1_4(t *testing.B) { + benchmarkEachNeighbourAsync(t, 1000, 10, 16*time.Microsecond) +} +func BenchmarkEachNeighbourSync_3_2_4(t *testing.B) { + benchmarkEachNeighbourSync(t, 1000, 100, 16*time.Microsecond) +} +func BenchmarkEachNeighboursAsync_3_2_4(t *testing.B) { + benchmarkEachNeighbourAsync(t, 1000, 100, 16*time.Microsecond) +} +func BenchmarkEachNeighbourSync_3_3_4(t *testing.B) { + benchmarkEachNeighbourSync(t, 1000, 1000, 16*time.Microsecond) +} +func BenchmarkEachNeighboursAsync_3_3_4(t *testing.B) { + benchmarkEachNeighbourAsync(t, 1000, 1000, 16*time.Microsecond) +} diff --git a/swarm/pss/ARCHITECTURE.md b/swarm/pss/ARCHITECTURE.md new file mode 100644 index 0000000000..279e895ab7 --- /dev/null +++ b/swarm/pss/ARCHITECTURE.md @@ -0,0 +1,144 @@ +# Postal Service over Swarm + +Pss provides devp2p functionality for swarm nodes without the need for a direct tcp connection between them. + +Messages are encapsulated in a devp2p message structure `PssMsg`. These capsules are forwarded from node to node using ordinary tcp devp2p until they reach their destination: The node or nodes who can successfully decrypt the message. + +| Layer | Contents | +|-----------|-----------------| +| PssMsg: | Address, Expiry | +| Envelope: | Topic | +| Payload: | e(data) | + +Routing of messages is done using swarm's own kademlia routing. Optionally routing can be turned off, forcing the message to be sent to all peers, similar to the behavior of the whisper protocol. + +Pss is intended for messages of limited size, typically a couple of Kbytes at most. The messages themselves can be anything at all; complex data structures or non-descript byte sequences. + +For the current state and roadmap of pss development please see https://github.com/ethersphere/swarm/wiki/swarm-dev-progress. + +Please report issues on https://github.com/ethersphere/go-ethereum + +Feel free to ask questions in https://gitter.im/ethersphere/pss + +## STATUS OF THIS DOCUMENT + +`pss` is under active development, and the first implementation is yet to be merged to the Ethereum main branch. Expect things to change. + +## CORE INTERFACES + +The pss core provides low level control of key handling and message exchange. + +### TOPICS + +An encrypted envelope of a pss message always contains a Topic. This is pss' way of determining which message handlers to dispatch messages to. The topic of a message is only visible for the node(s) who can decrypt the message. + +This "topic" is not like the subject of an email message, but a hash-like arbitrary 4 byte value. A valid topic can be generated using the `pss_*ToTopic` API methods. + +### IDENTITY AND ENCRYPTION + +Pss aims to achieve perfect darkness. That means that the minimum requirement for two nodes to communicate using pss is a shared secret. This secret can be an arbitrary byte slice, or a ECDSA keypair. The end recipient of a message is defined as the node that can successfully decrypt that message using stored keys. + +A node's public key is derived from the private key passed to the `pss` constructor. Pss (currently) has no PKI. + +Peer keys can manually be added to the pss node through its API calls `pss_setPeerPublicKey` and `pss_setSymmetricKey`. Keys are always coupled with a topic, and the keys will only be valid for these topics. + +### CONNECTIONS + +A "connection" in pss is a purely virtual construct. There is no mechanisms in place to ensure that the remote peer actually is there. In fact, "adding" a peer involves merely the node's opinion that the peer is there. It may issue messages to that remote peer to a directly connected peer, which in turn passes it on. But if it is not present on the network - or if there is no route to it - the message will never reach its destination through mere forwarding. + +Since pss itself never requires a confirmation from a peer of whether a message is received or not, one could argue that pss shows `UDP`-like behavior. + +It is also important to note that if the wrong (partial) address is set for a particular key/topic combination, the message may never reach that peer. The further left in the address byte slice the error lies, the less likely it is that delivery will occur. + + +### EXCHANGE + +Message exchange in `pss` *requires* end-to-end encryption. + +The API methods `pss_sendSym` and `pss_sendAsym` sends an arbitrary byte slice with a specific topic to a pss peer using the respective encryption scheme. The key passed to the send method must be associated with a topic in the pss key store prior to sending, or the send method will fail. + +Return values from the send methods do *not* indicate whether the message was successfully delivered to the pss peer. It *only* indicates whether or not the message could be passed on to the network. If the message could not be forwarded to any peers, the method will fail. + +Keep in mind that symmetric encryption is less resource-intensive than asymmetric encryption. The former should be used for nodes with high message volumes. + +## EXTENSIONS + +### HANDSHAKE + +Pss offers an optional Diffie-Hellman handshake mechanism. Handshake functionality is activated per topic, and can be deactivated per topic even while the node is running. + +Handshakes are activated in the code implementation of the node by running `SetHandshakeController()` on the pss node instance BEFORE starting the node service. The methods exposed by the HandshakeController's API gives the possibility to initiate, remove and check the state of handshakes and associated keys. + +See the `HandshakeAPI` section in `godoc` for details. + +### DEVP2P PROTOCOLS + +The `Protocol` convenience structure is provided to mimic devp2p-type protocols over pss. In theory this makes it possible to reuse protocol code written for devp2p with a minimum of effort. + +#### OUTGOING CONNECTIONS + +In order to message a peer using this layer, a `Protocol` object must first be instantiated. When this is done, peers can be added using the protocol's `AddPeer()` method. The peer's key/topic combination must be in the pss key store before the peer can be aded. + +Adding a peer in effect "runs" the protocol on that peer, and adds an internal mapping between a topic and that peer, and enables sending and receiving messages using the usual io-construct of devp2p. It does not actually *transmit* anything to the peer, it merely represents the node's opinion that a connection with the peer exists. (See CONNECTION above). + +#### INCOMING CONNECTIONS + +An incoming connection is nothing more than an actual PssMsg appearing with a certain Topic. If a Handler has been registered to that Topic, the message will be passed to it. This constitutes a "new" connection if: + +- The pss node never called AddPeer with this combination of remote peer address and topic, and + +- The pss node never received a PssMsg from this remote peer with this specific Topic before. + +If it is a "new" connection, the protocol will be "run" on the remote peer, as if the peer was added via the API. + +As with the `AddPeer()` method, the key/topic of the originating peer must exist in the pss key store. + +#### TOPICS IN DEVP2P + +The `ProtocolTopic()` method should be used to determine the correct topic to use for a pss `Protocol` instance. + +## EXAMPLES + +Coming. Please refer to the tests for now. + +## PSS INTERNALS + +Pss implements the node.Service interface. It depends on a working kademlia overlay for routing. + +### DECRYPTION + +When processing an incoming message, `pss` detects whether it is encrypted symmetrically or asymmetrically. + +When decrypting symmetrically, `pss` iterates through all stored keys, and attempts to decrypt with each key in order. + +pss keeps a *cache* of these keys. The cache will only store a certain amount of keys, and the iterator will return keys in the order of most recently used key first. Abandoned keys will be garbage collected. + +### ROUTING + +(please refer to swarm kademlia routing for an explanation of the routing algorithm used for pss) + +`pss` uses *address hinting* for routing. The address hint is an arbitrary-length MSB byte slice of the peer's swarm overlay address. It can be the whole address, part of the address, or even an empty byte slice. The slice will be matched to the MSB slice of the same length of all devp2p peers in the routing stage. + +If an empty byte slice is passed, all devp2p peers will match the address hint, and the message will be forwarded to everyone. This is equivalent to `whisper` routing, and makes it difficult to perform traffic analysis based on who messages are forwarded to. + +A node will also forward to everyone if the address hint provided is in its proximity bin, both to provide saturation to increase chances of delivery, and also for recipient obfuscation to thwart traffic analysis attacks. The recipient node(s) will always forward to all its peers. + +### CACHING + +pss implements a simple caching mechanism for messages, using the swarm FileStore for storage of the messages and generation of the digest keys used in the cache table. The caching is intended to alleviate the following: + +- save messages so that they can be delivered later if the recipient was not online at the time of sending. + +- drop an identical message to the same recipient if received within a given time interval + +- prevent backwards routing of messages + +the latter may occur if only one entry is in the receiving node's kademlia, or if the proximity of the current node recipient hinted by the address is so close that the message will be forwarded to everyone. In these cases the forwarder will be provided as the "nearest node" to the final recipient. The cache keeps the address of who the message was forwarded from, and if the cache lookup matches, the message will be dropped. + +### DEVP2P PROTOCOLS + +When implementing devp2p protocols, topics are derived from protocols' name and version. The Protocol provides a generic Handler that be passed to Pss.Register. This makes it possible to use the same message handler code for pss that is used for directly connected peers in devp2p. + +Under the hood, pss implements its own MsgReadWriter, which bridges MsgReadWriter.WriteMsg with Pss.SendRaw, and deftly adds an InjectMsg method which pipes incoming messages to appear on the MsgReadWriter.ReadMsg channel. + + diff --git a/swarm/pss/README.md b/swarm/pss/README.md new file mode 100644 index 0000000000..aea871251f --- /dev/null +++ b/swarm/pss/README.md @@ -0,0 +1,318 @@ +# Postal Services over Swarm + +`pss` enables message relay over swarm. This means nodes can send messages to each other without being directly connected with each other, while taking advantage of the efficient routing algorithms that swarm uses for transporting and storing data. + +### CONTENTS + +* Status of this document +* Core concepts +* Caveat +* Examples +* API + * Retrieve node information + * Receive messages + * Send messages using public key encryption + * Send messages using symmetric encryption + * Querying peer keys + * Handshakes + +### STATUS OF THIS DOCUMENT + +`pss` is under active development, and the first implementation is yet to be merged to the Ethereum main branch. Expect things to change. + +Details on swarm routing and encryption schemes out of scope of this document. + +Please refer to [ARCHITECTURE.md](ARCHITECTURE.md) for in-depth topics concerning `pss`. + +## CORE CONCEPTS + +Three things are required to send a `pss` message: + +1. Encryption key +2. Topic +3. Message payload + +Encryption key can be a public key or a 32 byte symmetric key. It must be coupled with a peer address in the node prior to sending. + +Topic is the initial 4 bytes of a hash value. + +Message payload is an arbitrary byte slice of data. + +Upon sending the message it is encrypted and passed on from peer to peer. Any node along the route that can successfully decrypt the message is regarded as a recipient. Recipients continue to pass on the message to their peers, to make traffic analysis attacks more difficult. + +The Address that is coupled with the encryption keys are used for routing the message. This does *not* need to be a full addresses; the network will route the message to the best of its ability with the information that is available. If *no* address is given (zero-length byte slice), routing is effectively deactivated, and the message is passed to all peers by all peers. + +## CAVEAT + +`pss` connectivity resembles UDP. This means there is no delivery guarantee for a message. Furthermore there is no strict definition of what a connection between two nodes communicating via `pss` is. Reception acknowledgements and keepalive-schemes is the responsibility of the application. + +Due to the inherent properties of the `swarm` routing algorithm, a node may receive the same message more than once. Message deduplication *cannot be guaranteed* by `pss`, and must be handled in the application layer to ensure predictable results. + +## EXAMPLES + +The code tutorial [p2p programming in go-ethereum](https://github.com/nolash/go-ethereum-p2p-demo) by [@nolash](https://github.com/nolash) provides step-by-step code examples for usage of `pss` API with `go-ethereum` nodes. + +A quite unpolished example using `javascript` is available here: [https://github.com/nolash/pss-js/tree/withcrypt](https://github.com/nolash/pss-js/tree/withcrypt) + +## API + +The `pss` API is available through IPC and Websockets. There is currently no `web3.js` implementation, as this does not support message subscription. + +For `golang` clients, please use the `rpc.Client` provided by the `go-ethereum` repository. The return values may have special types in `golang`. Please refer to `godoc` for details. + +### RETRIEVE NODE INFORMATION + +#### pss_getPublicKey + +Retrieves the public key of the node, in hex format + +``` +parameters: +none + +returns: +1. publickey (hex) +``` + +#### pss_baseAddr + +Retrieves the swarm overlay address of the node, in hex format + +``` +parameters: +none + +returns: +1. swarm overlay address (hex) +``` + +#### pss_stringToTopic + +Creates a deterministic 4 byte topic value from input, returned in hex format + +``` +parameters: +1. topic string (string) + +returns: +1. pss topic (hex) +``` + +### RECEIVE MESSAGES + +#### pss_subscribe + +Creates a subscription. Received messages with matching topic will be passed to subscription client. + +``` +parameters: +1. string("receive") +2. topic (4 bytes in hex) + +returns: +1. subscription handle `base64(byte)` `rpc.ClientSubscription` +``` + +In `golang` as special method is used: + +`rpc.Client.Subscribe(context.Context, "pss", chan pss.APIMsg, "receive", pss.Topic)` + +Incoming messages are encapsulated in an object (`pss.APIMsg` in `golang`) with the following members: + +``` +1. Msg (hex) - the message payload +2. Asymmetric (bool) - true if message used public key encryption +3. Key (string) - the encryption key used +``` + +### SEND MESSAGE USING PUBLIC KEY ENCRYPTION + +#### pss_setPeerPublicKey + +Register a peer's public key. This is done once for every topic that will be used with the peer. Address can be anything from 0 to 32 bytes inclusive of the peer's swarm overlay address. + +``` +parameters: +1. public key of peer (hex) +2. topic (4 bytes in hex) +3. address of peer (hex) + +returns: +none +``` + +#### pss_sendAsym + +Encrypts the message using the provided public key, and signs it using the node's private key. It then wraps it in an envelope containing the topic, and sends it to the network. + +``` +parameters: +1. public key of peer (hex) +2. topic (4 bytes in hex) +3. message (hex) + +returns: +none +``` + +### SEND MESSAGE USING SYMMETRIC ENCRYPTION + +#### pss_setSymmetricKey + +Register a symmetric key shared with a peer. This is done once for every topic that will be used with the peer. Address can be anything from 0 to 32 bytes inclusive of the peer's swarm overlay address. + +If the fourth parameter is false, the key will *not* be added to the list of symmetric keys used for decryption attempts. + +``` +parameters: +1. symmetric key (hex) +2. topic (4 bytes in hex) +3. address of peer (hex) +4. use for decryption (bool) + +returns: +1. symmetric key id (string) +``` + +#### pss_sendSym + +Encrypts the message using the provided symmetric key, wraps it in an envelope containing the topic, and sends it to the network. + +``` +parameters: +1. symmetric key id (string) +2. topic (4 bytes in hex) +3. message (hex) + +returns: +none +``` + +### QUERY PEER KEYS + +#### pss_GetSymmetricAddressHint + +Return the swarm overlay address associated with the peer registered with the given symmetric key and topic combination. + +``` +parameters: +1. topic (4 bytes in hex) +2. symmetric key id (string) + +returns: +1. peer address (hex) +``` + +#### pss_GetAsymmetricAddressHint + +Return the swarm overlay address associated with the peer registered with the given symmetric key and topic combination. + +``` +parameters: +1. topic (4 bytes in hex) +2. public key in hex form (string) + +returns: +1. peer address (hex) +``` + +### HANDSHAKES + +Convenience implementation of Diffie-Hellman handshakes using ephemeral symmetric keys. Peers keep separate sets of keys for incoming and outgoing communications. + +*This functionality is an optional feature in `pss`. It is compiled in by default, but can be omitted by providing the `nopsshandshake` build tag.* + +#### pss_addHandshake + +Activate handshake functionality on the specified topic. + +``` +parameters: +1. topic (4 bytes in hex) + +returns: +none +``` + +#### pss_removeHandshake + +Remove handshake functionality on the specified topic. + +``` +parameters: +1. topic (4 bytes in hex) + +returns: +none +``` + +#### pss_handshake + +Instantiate handshake with peer, refreshing symmetric encryption keys. + +If parameter 3 is false, the returned array will be empty. + +``` +parameters: +1. public key of peer in hex format (string) +2. topic (4 bytes in hex) +3. block calls until keys are received (bool) +4. flush existing incoming keys (bool) + +returns: +1. list of symmetric keys (string[]) +``` + +#### pss_getHandshakeKeys + +Get valid symmetric encryption keys for a specified peer and topic. + +parameters: +1. public key of peer in hex format (string) +2. topic (4 bytes in hex) +3. include keys for incoming messages (bool) +4. include keys for outgoing messages (bool) + +returns: +1. list of symmetric keys (string[]) + +#### pss_getHandshakeKeyCapacity + +Get amount of remaining messages the specified key is valid for. + +``` +parameters: +1. symmetric key id (string) + +returns: +1. number of messages (uint16) +``` + +#### pss_getHandshakePublicKey + +Get the peer's public key associated with the specified symmetric key. + +``` +parameters: +1. symmetric key id (string) + +returns: +1. Associated public key in hex format (string) +``` + +#### pss_releaseHandshakeKey + +Invalidate the specified key. + +Normally, the key will be kept for a grace period to allow for decryption of delayed messages. If instant removal is set, this grace period is omitted, and the key removed instantaneously. + +``` +parameters: +1. public key of peer in hex format (string) +2. topic (4 bytes in hex) +3. symmetric key id to release (string) +4. remove keys instantly (bool) + +returns: +1. whether key was successfully removed (bool) +``` diff --git a/swarm/pss/api.go b/swarm/pss/api.go new file mode 100644 index 0000000000..4556d7b7c4 --- /dev/null +++ b/swarm/pss/api.go @@ -0,0 +1,195 @@ +// 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 pss + +import ( + "context" + "errors" + "fmt" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/rpc" + "github.com/ethereum/go-ethereum/swarm/log" +) + +// Wrapper for receiving pss messages when using the pss API +// providing access to sender of message +type APIMsg struct { + Msg hexutil.Bytes + Asymmetric bool + Key string +} + +// Additional public methods accessible through API for pss +type API struct { + *Pss +} + +func NewAPI(ps *Pss) *API { + return &API{Pss: ps} +} + +// Creates a new subscription for the caller. Enables external handling of incoming messages. +// +// A new handler is registered in pss for the supplied topic +// +// 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, raw bool, prox bool) (*rpc.Subscription, error) { + notifier, supported := rpc.NotifierFromContext(ctx) + if !supported { + return nil, fmt.Errorf("Subscribe not supported") + } + + psssub := notifier.CreateSubscription() + + hndlr := NewHandler(func(msg []byte, p *p2p.Peer, asymmetric bool, keyid string) error { + apimsg := &APIMsg{ + Msg: hexutil.Bytes(msg), + Asymmetric: asymmetric, + Key: keyid, + } + if err := notifier.Notify(psssub.ID, apimsg); err != nil { + 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, hndlr) + go func() { + defer deregf() + select { + case err := <-psssub.Err(): + log.Warn(fmt.Sprintf("caught subscription error in pss sub topic %x: %v", topic, err)) + case <-notifier.Closed(): + log.Warn(fmt.Sprintf("rpc sub notifier closed")) + } + }() + + return psssub, nil +} + +func (pssapi *API) GetAddress(topic Topic, asymmetric bool, key string) (PssAddress, error) { + var addr PssAddress + if asymmetric { + peer, ok := pssapi.Pss.pubKeyPool[key][topic] + if !ok { + return nil, fmt.Errorf("pubkey/topic pair %x/%x doesn't exist", key, topic) + } + addr = peer.address + } else { + peer, ok := pssapi.Pss.symKeyPool[key][topic] + if !ok { + return nil, fmt.Errorf("symkey/topic pair %x/%x doesn't exist", key, topic) + } + addr = peer.address + + } + return addr, nil +} + +// Retrieves the node's base address in hex form +func (pssapi *API) BaseAddr() (PssAddress, error) { + return PssAddress(pssapi.Pss.BaseAddr()), nil +} + +// Retrieves the node's public key in hex form +func (pssapi *API) GetPublicKey() (keybytes hexutil.Bytes) { + key := pssapi.Pss.PublicKey() + keybytes = crypto.FromECDSAPub(key) + return keybytes +} + +// Set Public key to associate with a particular Pss peer +func (pssapi *API) SetPeerPublicKey(pubkey hexutil.Bytes, topic Topic, addr PssAddress) error { + pk, err := crypto.UnmarshalPubkey(pubkey) + if err != nil { + return fmt.Errorf("Cannot unmarshal pubkey: %x", pubkey) + } + err = pssapi.Pss.SetPeerPublicKey(pk, topic, addr) + if err != nil { + return fmt.Errorf("Invalid key: %x", pk) + } + return nil +} + +func (pssapi *API) GetSymmetricKey(symkeyid string) (hexutil.Bytes, error) { + symkey, err := pssapi.Pss.GetSymmetricKey(symkeyid) + return hexutil.Bytes(symkey), err +} + +func (pssapi *API) GetSymmetricAddressHint(topic Topic, symkeyid string) (PssAddress, error) { + 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 +} + +func (pssapi *API) StringToTopic(topicstring string) (Topic, error) { + topicbytes := BytesToTopic([]byte(topicstring)) + if topicbytes == rawTopic { + return rawTopic, errors.New("Topic string hashes to 0x00000000 and cannot be used") + } + return topicbytes, nil +} + +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 + +} + +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/swarm/pss/client/client.go b/swarm/pss/client/client.go new file mode 100644 index 0000000000..5ee387aa79 --- /dev/null +++ b/swarm/pss/client/client.go @@ -0,0 +1,352 @@ +// 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 !noclient,!noprotocol + +package client + +import ( + "context" + "errors" + "fmt" + "sync" + "time" + + "github.com/ethereum/go-ethereum/common/hexutil" + "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/rpc" + "github.com/ethereum/go-ethereum/swarm/log" + "github.com/ethereum/go-ethereum/swarm/pss" +) + +const ( + handshakeRetryTimeout = 1000 + handshakeRetryCount = 3 +) + +// The pss client provides devp2p emulation over pss RPC API, +// giving access to pss methods from a different process +type Client struct { + BaseAddrHex string + + // peers + peerPool map[pss.Topic]map[string]*pssRPCRW + protos map[pss.Topic]*p2p.Protocol + + // rpc connections + rpc *rpc.Client + subs []*rpc.ClientSubscription + + // channels + topicsC chan []byte + quitC chan struct{} + + poolMu sync.Mutex +} + +// implements p2p.MsgReadWriter +type pssRPCRW struct { + *Client + topic string + msgC chan []byte + addr pss.PssAddress + pubKeyId string + lastSeen time.Time + closed bool +} + +func (c *Client) newpssRPCRW(pubkeyid string, addr pss.PssAddress, topicobj pss.Topic) (*pssRPCRW, error) { + topic := topicobj.String() + err := c.rpc.Call(nil, "pss_setPeerPublicKey", pubkeyid, topic, hexutil.Encode(addr[:])) + if err != nil { + return nil, fmt.Errorf("setpeer %s %s: %v", topic, pubkeyid, err) + } + return &pssRPCRW{ + Client: c, + topic: topic, + msgC: make(chan []byte), + addr: addr, + pubKeyId: pubkeyid, + }, nil +} + +func (rw *pssRPCRW) ReadMsg() (p2p.Msg, error) { + msg := <-rw.msgC + log.Trace("pssrpcrw read", "msg", msg) + pmsg, err := pss.ToP2pMsg(msg) + if err != nil { + return p2p.Msg{}, err + } + + return pmsg, nil +} + +// If only one message slot left +// then new is requested through handshake +// if buffer is empty, handshake request blocks until return +// after which pointer is changed to first new key in buffer +// will fail if: +// - any api calls fail +// - handshake retries are exhausted without reply, +// - send fails +func (rw *pssRPCRW) WriteMsg(msg p2p.Msg) error { + log.Trace("got writemsg pssclient", "msg", msg) + if rw.closed { + return fmt.Errorf("connection closed") + } + rlpdata := make([]byte, msg.Size) + msg.Payload.Read(rlpdata) + pmsg, err := rlp.EncodeToBytes(pss.ProtocolMsg{ + Code: msg.Code, + Size: msg.Size, + Payload: rlpdata, + }) + if err != nil { + return err + } + + // Get the keys we have + var symkeyids []string + err = rw.Client.rpc.Call(&symkeyids, "pss_getHandshakeKeys", rw.pubKeyId, rw.topic, false, true) + if err != nil { + return err + } + + // Check the capacity of the first key + var symkeycap uint16 + if len(symkeyids) > 0 { + err = rw.Client.rpc.Call(&symkeycap, "pss_getHandshakeKeyCapacity", symkeyids[0]) + if err != nil { + return err + } + } + + err = rw.Client.rpc.Call(nil, "pss_sendSym", symkeyids[0], rw.topic, hexutil.Encode(pmsg)) + if err != nil { + return err + } + + // If this is the last message it is valid for, initiate new handshake + if symkeycap == 1 { + var retries int + var sync bool + // if it's the only remaining key, make sure we don't continue until we have new ones for further writes + if len(symkeyids) == 1 { + sync = true + } + // initiate handshake + _, err := rw.handshake(retries, sync, false) + if err != nil { + log.Warn("failing", "err", err) + return err + } + } + return nil +} + +// retry and synchronicity wrapper for handshake api call +// returns first new symkeyid upon successful execution +func (rw *pssRPCRW) handshake(retries int, sync bool, flush bool) (string, error) { + + var symkeyids []string + var i int + // request new keys + // if the key buffer was depleted, make this as a blocking call and try several times before giving up + for i = 0; i < 1+retries; i++ { + log.Debug("handshake attempt pssrpcrw", "pubkeyid", rw.pubKeyId, "topic", rw.topic, "sync", sync) + err := rw.Client.rpc.Call(&symkeyids, "pss_handshake", rw.pubKeyId, rw.topic, sync, flush) + if err == nil { + var keyid string + if sync { + keyid = symkeyids[0] + } + return keyid, nil + } + if i-1+retries > 1 { + time.Sleep(time.Millisecond * handshakeRetryTimeout) + } + } + + return "", fmt.Errorf("handshake failed after %d attempts", i) +} + +// Custom constructor +// +// Provides direct access to the rpc object +func NewClient(rpcurl string) (*Client, error) { + rpcclient, err := rpc.Dial(rpcurl) + if err != nil { + return nil, err + } + + client, err := NewClientWithRPC(rpcclient) + if err != nil { + return nil, err + } + return client, nil +} + +// Main constructor +// +// The 'rpcclient' parameter allows passing a in-memory rpc client to act as the remote websocket RPC. +func NewClientWithRPC(rpcclient *rpc.Client) (*Client, error) { + client := newClient() + client.rpc = rpcclient + err := client.rpc.Call(&client.BaseAddrHex, "pss_baseAddr") + if err != nil { + return nil, fmt.Errorf("cannot get pss node baseaddress: %v", err) + } + return client, nil +} + +func newClient() (client *Client) { + client = &Client{ + quitC: make(chan struct{}), + peerPool: make(map[pss.Topic]map[string]*pssRPCRW), + protos: make(map[pss.Topic]*p2p.Protocol), + } + return +} + +// Mounts a new devp2p protcool on the pss connection +// +// the protocol is aliased as a "pss topic" +// uses normal devp2p send and incoming message handler routines from the p2p/protocols package +// +// when an incoming message is received from a peer that is not yet known to the client, +// this peer object is instantiated, and the protocol is run on it. +func (c *Client) RunProtocol(ctx context.Context, proto *p2p.Protocol) error { + topicobj := pss.BytesToTopic([]byte(fmt.Sprintf("%s:%d", proto.Name, proto.Version))) + 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, false, false) + if err != nil { + return fmt.Errorf("pss event subscription failed: %v", err) + } + c.subs = append(c.subs, sub) + err = c.rpc.Call(nil, "pss_addHandshake", topichex) + if err != nil { + return fmt.Errorf("pss handshake activation failed: %v", err) + } + + // dispatch incoming messages + go func() { + for { + select { + case msg := <-msgC: + // we only allow sym msgs here + if msg.Asymmetric { + continue + } + // we get passed the symkeyid + // need the symkey itself to resolve to peer's pubkey + var pubkeyid string + err = c.rpc.Call(&pubkeyid, "pss_getHandshakePublicKey", msg.Key) + if err != nil || pubkeyid == "" { + log.Trace("proto err or no pubkey", "err", err, "symkeyid", msg.Key) + continue + } + // if we don't have the peer on this protocol already, create it + // this is more or less the same as AddPssPeer, less the handshake initiation + if c.peerPool[topicobj][pubkeyid] == nil { + var addrhex string + err := c.rpc.Call(&addrhex, "pss_getAddress", topichex, false, msg.Key) + if err != nil { + log.Trace(err.Error()) + continue + } + addrbytes, err := hexutil.Decode(addrhex) + if err != nil { + log.Trace(err.Error()) + break + } + addr := pss.PssAddress(addrbytes) + rw, err := c.newpssRPCRW(pubkeyid, addr, topicobj) + if err != nil { + break + } + c.peerPool[topicobj][pubkeyid] = rw + p := p2p.NewPeer(enode.ID{}, fmt.Sprintf("%v", addr), []p2p.Cap{}) + go proto.Run(p, c.peerPool[topicobj][pubkeyid]) + } + go func() { + c.peerPool[topicobj][pubkeyid].msgC <- msg.Msg + }() + case <-c.quitC: + return + } + } + }() + + c.protos[topicobj] = proto + return nil +} + +// Always call this to ensure that we exit cleanly +func (c *Client) Close() error { + for _, s := range c.subs { + s.Unsubscribe() + } + return nil +} + +// Add a pss peer (public key) and run the protocol on it +// +// client.RunProtocol with matching topic must have been +// run prior to adding the peer, or this method will +// return an error. +// +// The key must exist in the key store of the pss node +// before the peer is added. The method will return an error +// if it is not. +func (c *Client) AddPssPeer(pubkeyid string, addr []byte, spec *protocols.Spec) error { + topic := pss.ProtocolTopic(spec) + if c.peerPool[topic] == nil { + return errors.New("addpeer on unset topic") + } + if c.peerPool[topic][pubkeyid] == nil { + rw, err := c.newpssRPCRW(pubkeyid, addr, topic) + if err != nil { + return err + } + _, err = rw.handshake(handshakeRetryCount, true, true) + if err != nil { + return err + } + c.poolMu.Lock() + c.peerPool[topic][pubkeyid] = rw + c.poolMu.Unlock() + p := p2p.NewPeer(enode.ID{}, fmt.Sprintf("%v", addr), []p2p.Cap{}) + go c.protos[topic].Run(p, c.peerPool[topic][pubkeyid]) + } + return nil +} + +// Remove a pss peer +// +// TODO: underlying cleanup +func (c *Client) RemovePssPeer(pubkeyid string, spec *protocols.Spec) { + log.Debug("closing pss client peer", "pubkey", pubkeyid, "protoname", spec.Name, "protoversion", spec.Version) + c.poolMu.Lock() + defer c.poolMu.Unlock() + topic := pss.ProtocolTopic(spec) + c.peerPool[topic][pubkeyid].closed = true + delete(c.peerPool[topic], pubkeyid) +} diff --git a/swarm/pss/client/client_test.go b/swarm/pss/client/client_test.go new file mode 100644 index 0000000000..1bd340cf04 --- /dev/null +++ b/swarm/pss/client/client_test.go @@ -0,0 +1,287 @@ +// 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 client + +import ( + "bytes" + "context" + "flag" + "fmt" + "math/rand" + "os" + "testing" + "time" + + "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" + "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/pss" + "github.com/ethereum/go-ethereum/swarm/state" + whisper "github.com/ethereum/go-ethereum/whisper/whisperv6" +) + +type protoCtrl struct { + C chan bool + protocol *pss.Protocol + run func(*p2p.Peer, p2p.MsgReadWriter) error +} + +var ( + debugdebugflag = flag.Bool("vv", false, "veryverbose") + debugflag = flag.Bool("v", false, "verbose") + w *whisper.Whisper + wapi *whisper.PublicWhisperAPI + // custom logging + psslogmain log.Logger + pssprotocols map[string]*protoCtrl + sendLimit = uint16(256) +) + +var services = newServices() + +func init() { + flag.Parse() + rand.Seed(time.Now().Unix()) + + adapters.RegisterServices(services) + + 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) + h := log.CallerFileHandler(hf) + log.Root().SetHandler(h) + + w = whisper.New(&whisper.DefaultConfig) + wapi = whisper.NewPublicWhisperAPI(w) + + pssprotocols = make(map[string]*protoCtrl) +} + +// ping pong exchange across one expired symkey +func TestClientHandshake(t *testing.T) { + sendLimit = 3 + + clients, err := setupNetwork(2) + if err != nil { + t.Fatal(err) + } + + lpsc, err := NewClientWithRPC(clients[0]) + if err != nil { + t.Fatal(err) + } + rpsc, err := NewClientWithRPC(clients[1]) + if err != nil { + t.Fatal(err) + } + lpssping := &pss.Ping{ + OutC: make(chan bool), + InC: make(chan bool), + Pong: false, + } + rpssping := &pss.Ping{ + OutC: make(chan bool), + InC: make(chan bool), + Pong: false, + } + lproto := pss.NewPingProtocol(lpssping) + rproto := pss.NewPingProtocol(rpssping) + + ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) + defer cancel() + err = lpsc.RunProtocol(ctx, lproto) + if err != nil { + t.Fatal(err) + } + err = rpsc.RunProtocol(ctx, rproto) + if err != nil { + t.Fatal(err) + } + topic := pss.PingTopic.String() + + var loaddr string + err = clients[0].Call(&loaddr, "pss_baseAddr") + if err != nil { + t.Fatalf("rpc get node 1 baseaddr fail: %v", err) + } + var roaddr string + err = clients[1].Call(&roaddr, "pss_baseAddr") + if err != nil { + t.Fatalf("rpc get node 2 baseaddr fail: %v", err) + } + + var lpubkey string + err = clients[0].Call(&lpubkey, "pss_getPublicKey") + if err != nil { + t.Fatalf("rpc get node 1 pubkey fail: %v", err) + } + var rpubkey string + err = clients[1].Call(&rpubkey, "pss_getPublicKey") + if err != nil { + t.Fatalf("rpc get node 2 pubkey fail: %v", err) + } + + err = clients[0].Call(nil, "pss_setPeerPublicKey", rpubkey, topic, roaddr) + if err != nil { + t.Fatal(err) + } + err = clients[1].Call(nil, "pss_setPeerPublicKey", lpubkey, topic, loaddr) + if err != nil { + t.Fatal(err) + } + + time.Sleep(time.Second) + + roaddrbytes, err := hexutil.Decode(roaddr) + if err != nil { + t.Fatal(err) + } + err = lpsc.AddPssPeer(rpubkey, roaddrbytes, pss.PingProtocol) + if err != nil { + t.Fatal(err) + } + + time.Sleep(time.Second) + + for i := uint16(0); i <= sendLimit; i++ { + lpssping.OutC <- false + got := <-rpssping.InC + log.Warn("ok", "idx", i, "got", got) + time.Sleep(time.Second) + } + + rw := lpsc.peerPool[pss.PingTopic][rpubkey] + lpsc.RemovePssPeer(rpubkey, pss.PingProtocol) + if err := rw.WriteMsg(p2p.Msg{ + Size: 3, + Payload: bytes.NewReader([]byte("foo")), + }); err == nil { + t.Fatalf("expected error on write") + } +} + +func setupNetwork(numnodes int) (clients []*rpc.Client, err error) { + nodes := make([]*simulations.Node, numnodes) + clients = make([]*rpc.Client, numnodes) + if numnodes < 2 { + return nil, fmt.Errorf("Minimum two nodes in network") + } + adapter := adapters.NewSimAdapter(services) + net := simulations.NewNetwork(adapter, &simulations.NetworkConfig{ + ID: "0", + DefaultService: "bzz", + }) + for i := 0; i < numnodes; i++ { + nodeconf := adapters.RandomNodeConfig() + nodeconf.Services = []string{"bzz", "pss"} + nodes[i], err = net.NewNodeWithConfig(nodeconf) + if err != nil { + return nil, fmt.Errorf("error creating node 1: %v", err) + } + err = net.Start(nodes[i].ID()) + if err != nil { + return nil, fmt.Errorf("error starting node 1: %v", err) + } + if i > 0 { + err = net.Connect(nodes[i].ID(), nodes[i-1].ID()) + if err != nil { + return nil, fmt.Errorf("error connecting nodes: %v", err) + } + } + clients[i], err = nodes[i].Client() + if err != nil { + return nil, fmt.Errorf("create node 1 rpc client fail: %v", err) + } + } + if numnodes > 2 { + err = net.Connect(nodes[0].ID(), nodes[len(nodes)-1].ID()) + if err != nil { + return nil, fmt.Errorf("error connecting first and last nodes") + } + } + return clients, nil +} + +func newServices() adapters.Services { + stateStore := state.NewInmemoryStore() + kademlias := make(map[enode.ID]*network.Kademlia) + kademlia := func(id enode.ID) *network.Kademlia { + if k, ok := kademlias[id]; ok { + return k + } + params := network.NewKadParams() + params.NeighbourhoodSize = 2 + params.MaxBinSize = 3 + params.MinBinSize = 1 + params.MaxRetries = 1000 + params.RetryExponent = 2 + params.RetryInterval = 1000000 + kademlias[id] = network.NewKademlia(id[:], params) + return kademlias[id] + } + return adapters.Services{ + "pss": func(ctx *adapters.ServiceContext) (node.Service, error) { + ctxlocal, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + keys, err := wapi.NewKeyPair(ctxlocal) + if err != nil { + return nil, err + } + privkey, err := w.GetPrivateKey(keys) + if err != nil { + return nil, err + } + psparams := pss.NewPssParams().WithPrivateKey(privkey) + pskad := kademlia(ctx.Config.ID) + ps, err := pss.NewPss(pskad, psparams) + if err != nil { + return nil, err + } + pshparams := pss.NewHandshakeParams() + pshparams.SymKeySendLimit = sendLimit + err = pss.SetHandshakeController(ps, pshparams) + if err != nil { + return nil, fmt.Errorf("handshake controller fail: %v", err) + } + return ps, nil + }, + "bzz": func(ctx *adapters.ServiceContext) (node.Service, error) { + addr := network.NewAddr(ctx.Config.Node()) + 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), stateStore, nil, nil), nil + }, + } +} diff --git a/swarm/pss/client/doc.go b/swarm/pss/client/doc.go new file mode 100644 index 0000000000..080af45a9a --- /dev/null +++ b/swarm/pss/client/doc.go @@ -0,0 +1,96 @@ +// 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 . + +// simple abstraction for implementing pss functionality +// +// the pss client library aims to simplify usage of the p2p.protocols package over pss +// +// IO is performed using the ordinary p2p.MsgReadWriter interface, which transparently communicates with a pss node via RPC using websockets as transport layer, using methods in the PssAPI class in the swarm/pss package +// +// +// Minimal-ish usage example (requires a running pss node with websocket RPC): +// +// +// import ( +// "context" +// "fmt" +// "os" +// pss "github.com/ethereum/go-ethereum/swarm/pss/client" +// "github.com/ethereum/go-ethereum/p2p/protocols" +// "github.com/ethereum/go-ethereum/p2p" +// "github.com/ethereum/go-ethereum/swarm/pot" +// "github.com/ethereum/go-ethereum/swarm/log" +// ) +// +// type FooMsg struct { +// Bar int +// } +// +// +// func fooHandler (msg interface{}) error { +// foomsg, ok := msg.(*FooMsg) +// if ok { +// log.Debug("Yay, just got a message", "msg", foomsg) +// } +// return errors.New(fmt.Sprintf("Unknown message")) +// } +// +// spec := &protocols.Spec{ +// Name: "foo", +// Version: 1, +// MaxMsgSize: 1024, +// Messages: []interface{}{ +// FooMsg{}, +// }, +// } +// +// proto := &p2p.Protocol{ +// Name: spec.Name, +// Version: spec.Version, +// Length: uint64(len(spec.Messages)), +// Run: func(p *p2p.Peer, rw p2p.MsgReadWriter) error { +// pp := protocols.NewPeer(p, rw, spec) +// return pp.Run(fooHandler) +// }, +// } +// +// func implementation() { +// cfg := pss.NewClientConfig() +// psc := pss.NewClient(context.Background(), nil, cfg) +// err := psc.Start() +// if err != nil { +// log.Crit("can't start pss client") +// os.Exit(1) +// } +// +// log.Debug("connected to pss node", "bzz addr", psc.BaseAddr) +// +// err = psc.RunProtocol(proto) +// if err != nil { +// log.Crit("can't start protocol on pss websocket") +// os.Exit(1) +// } +// +// addr := pot.RandomAddress() // should be a real address, of course +// psc.AddPssPeer(addr, spec) +// +// // use the protocol for something +// +// psc.Stop() +// } +// +// BUG(test): TestIncoming test times out due to deadlock issues in the swarm hive +package client diff --git a/swarm/pss/doc.go b/swarm/pss/doc.go new file mode 100644 index 0000000000..462c82aaad --- /dev/null +++ b/swarm/pss/doc.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 . + +// Pss provides devp2p functionality for swarm nodes without the need for a direct tcp connection between them. +// +// Messages are encapsulated in a devp2p message structure `PssMsg`. These capsules are forwarded from node to node using ordinary tcp devp2p until it reaches its destination: The node or nodes who can successfully decrypt the message. +// +// Routing of messages is done using swarm's own kademlia routing. Optionally routing can be turned off, forcing the message to be sent to all peers, similar to the behavior of the whisper protocol. +// +// Pss is intended for messages of limited size, typically a couple of Kbytes at most. The messages themselves can be anything at all; complex data structures or non-descript byte sequences. +// +// Documentation can be found in the README file. +// +// For the current state and roadmap of pss development please see https://github.com/ethersphere/swarm/wiki/swarm-dev-progress. +// +// Please report issues on https://github.com/ethersphere/go-ethereum +// +// Feel free to ask questions in https://gitter.im/ethersphere/pss +// +// TOPICS +// +// An encrypted envelope of a pss messages always contains a Topic. This is pss' way of determining what action to take on the message. The topic is only visible for the node(s) who can decrypt the message. +// +// This "topic" is not like the subject of an email message, but a hash-like arbitrary 4 byte value. A valid topic can be generated using the `pss_*ToTopic` API methods. +// +// IDENTITY IN PSS +// +// Pss aims to achieve perfect darkness. That means that the minimum requirement for two nodes to communicate using pss is a shared secret. This secret can be an arbitrary byte slice, or a ECDSA keypair. +// +// Peer keys can manually be added to the pss node through its API calls `pss_setPeerPublicKey` and `pss_setSymmetricKey`. Keys are always coupled with a topic, and the keys will only be valid for these topics. +// +// CONNECTIONS +// +// A "connection" in pss is a purely virtual construct. There is no mechanisms in place to ensure that the remote peer actually is there. In fact, "adding" a peer involves merely the node's opinion that the peer is there. It may issue messages to that remote peer to a directly connected peer, which in turn passes it on. But if it is not present on the network - or if there is no route to it - the message will never reach its destination through mere forwarding. +// +// When implementing the devp2p protocol stack, the "adding" of a remote peer is a prerequisite for the side actually initiating the protocol communication. Adding a peer in effect "runs" the protocol on that peer, and adds an internal mapping between a topic and that peer. It also enables sending and receiving messages using the main io-construct in devp2p - the p2p.MsgReadWriter. +// +// Under the hood, pss implements its own MsgReadWriter, which bridges MsgReadWriter.WriteMsg with Pss.SendRaw, and deftly adds an InjectMsg method which pipes incoming messages to appear on the MsgReadWriter.ReadMsg channel. +// +// An incoming connection is nothing more than an actual PssMsg appearing with a certain Topic. If a Handler har been registered to that Topic, the message will be passed to it. This constitutes a "new" connection if: +// +// - The pss node never called AddPeer with this combination of remote peer address and topic, and +// +// - The pss node never received a PssMsg from this remote peer with this specific Topic before. +// +// If it is a "new" connection, the protocol will be "run" on the remote peer, in the same manner as if it was pre-emptively added. +// +package pss diff --git a/swarm/pss/forwarding_test.go b/swarm/pss/forwarding_test.go new file mode 100644 index 0000000000..746d4dc404 --- /dev/null +++ b/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/swarm/pss/handshake.go b/swarm/pss/handshake.go new file mode 100644 index 0000000000..ec3bffa30a --- /dev/null +++ b/swarm/pss/handshake.go @@ -0,0 +1,592 @@ +// 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 !nopsshandshake + +package pss + +import ( + "context" + "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/p2p" + "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/rpc" + "github.com/ethereum/go-ethereum/swarm/log" +) + +const ( + IsActiveHandshake = true +) + +var ( + ctrlSingleton *HandshakeController +) + +const ( + defaultSymKeyRequestTimeout = 1000 * 8 // max wait ms to receive a response to a handshake symkey request + defaultSymKeyExpiryTimeout = 1000 * 10 // ms to wait before allowing garbage collection of an expired symkey + defaultSymKeySendLimit = 256 // amount of messages a symkey is valid for + defaultSymKeyCapacity = 4 // max number of symkeys to store/send simultaneously +) + +// symmetric key exchange message payload +type handshakeMsg struct { + From []byte + Limit uint16 + Keys [][]byte + Request uint8 + Topic Topic +} + +// internal representation of an individual symmetric key +type handshakeKey struct { + symKeyID *string + pubKeyID *string + limit uint16 + count uint16 + expiredAt time.Time +} + +// container for all in- and outgoing keys +// for one particular peer (public key) and topic +type handshake struct { + outKeys []handshakeKey + inKeys []handshakeKey +} + +// Initialization parameters for the HandshakeController +// +// SymKeyRequestExpiry: Timeout for waiting for a handshake reply +// (default 8000 ms) +// +// SymKeySendLimit: Amount of messages symmetric keys issues by +// this node is valid for (default 256) +// +// SymKeyCapacity: Ideal (and maximum) amount of symmetric keys +// held per direction per peer (default 4) +type HandshakeParams struct { + SymKeyRequestTimeout time.Duration + SymKeyExpiryTimeout time.Duration + SymKeySendLimit uint16 + SymKeyCapacity uint8 +} + +// Sane defaults for HandshakeController initialization +func NewHandshakeParams() *HandshakeParams { + return &HandshakeParams{ + SymKeyRequestTimeout: defaultSymKeyRequestTimeout * time.Millisecond, + SymKeyExpiryTimeout: defaultSymKeyExpiryTimeout * time.Millisecond, + SymKeySendLimit: defaultSymKeySendLimit, + SymKeyCapacity: defaultSymKeyCapacity, + } +} + +// Singleton object enabling semi-automatic Diffie-Hellman +// exchange of ephemeral symmetric keys +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 + symKeySendLimit uint16 + symKeyCapacity uint8 + symKeyIndex map[string]*handshakeKey + handshakes map[string]map[Topic]*handshake + deregisterFuncs map[Topic]func() +} + +// Attach HandshakeController to pss node +// +// Must be called before starting the pss node service +func SetHandshakeController(pss *Pss, params *HandshakeParams) error { + ctrl := &HandshakeController{ + pss: pss, + keyC: make(map[string]chan []string), + symKeyRequestTimeout: params.SymKeyRequestTimeout, + symKeyExpiryTimeout: params.SymKeyExpiryTimeout, + symKeySendLimit: params.SymKeySendLimit, + symKeyCapacity: params.SymKeyCapacity, + symKeyIndex: make(map[string]*handshakeKey), + handshakes: make(map[string]map[Topic]*handshake), + deregisterFuncs: make(map[Topic]func()), + } + api := &HandshakeAPI{ + namespace: "pss", + ctrl: ctrl, + } + pss.addAPI(rpc.API{ + Namespace: api.namespace, + Version: "0.2", + Service: api, + Public: true, + }) + ctrlSingleton = ctrl + return nil +} + +// Return all unexpired symmetric keys from store by +// peer (public key), topic and specified direction +func (ctl *HandshakeController) validKeys(pubkeyid string, topic *Topic, in bool) (validkeys []*string) { + ctl.lock.Lock() + defer ctl.lock.Unlock() + now := time.Now() + if _, ok := ctl.handshakes[pubkeyid]; !ok { + return []*string{} + } else if _, ok := ctl.handshakes[pubkeyid][*topic]; !ok { + return []*string{} + } + var keystore *[]handshakeKey + if in { + keystore = &(ctl.handshakes[pubkeyid][*topic].inKeys) + } else { + keystore = &(ctl.handshakes[pubkeyid][*topic].outKeys) + } + + for _, key := range *keystore { + if key.limit <= key.count { + ctl.releaseKeyNoLock(*key.symKeyID, topic) + } else if !key.expiredAt.IsZero() && key.expiredAt.Before(now) { + ctl.releaseKeyNoLock(*key.symKeyID, topic) + } else { + validkeys = append(validkeys, key.symKeyID) + } + } + return +} + +// Add all given symmetric keys with validity limits to store by +// peer (public key), topic and specified direction +func (ctl *HandshakeController) updateKeys(pubkeyid string, topic *Topic, in bool, symkeyids []string, limit uint16) { + ctl.lock.Lock() + defer ctl.lock.Unlock() + if _, ok := ctl.handshakes[pubkeyid]; !ok { + ctl.handshakes[pubkeyid] = make(map[Topic]*handshake) + + } + if ctl.handshakes[pubkeyid][*topic] == nil { + ctl.handshakes[pubkeyid][*topic] = &handshake{} + } + var keystore *[]handshakeKey + expire := time.Now() + if in { + keystore = &(ctl.handshakes[pubkeyid][*topic].inKeys) + } else { + keystore = &(ctl.handshakes[pubkeyid][*topic].outKeys) + expire = expire.Add(time.Millisecond * ctl.symKeyExpiryTimeout) + } + for _, storekey := range *keystore { + storekey.expiredAt = expire + } + for i := 0; i < len(symkeyids); i++ { + storekey := handshakeKey{ + symKeyID: &symkeyids[i], + pubKeyID: &pubkeyid, + 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]) + } +} + +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 + } + ctl.symKeyIndex[symkeyid].expiredAt = time.Now() + log.Debug("handshake release", "symkeyid", symkeyid) + return true +} + +// Checks all symmetric keys in given direction(s) by +// specified peer (public key) and topic for expiry. +// Expired means: +// - expiry timestamp is set, and grace period is exceeded +// - message validity limit is reached +func (ctl *HandshakeController) cleanHandshake(pubkeyid string, topic *Topic, in bool, out bool) int { + ctl.lock.Lock() + defer ctl.lock.Unlock() + var deletecount int + var deletes []string + now := time.Now() + handshake := ctl.handshakes[pubkeyid][*topic] + log.Debug("handshake clean", "pubkey", pubkeyid, "topic", topic) + if in { + for i, key := range handshake.inKeys { + if key.expiredAt.Before(now) || (key.expiredAt.IsZero() && key.limit <= key.count) { + log.Trace("handshake in clean remove", "symkeyid", *key.symKeyID) + deletes = append(deletes, *key.symKeyID) + handshake.inKeys[deletecount] = handshake.inKeys[i] + deletecount++ + } + } + handshake.inKeys = handshake.inKeys[:len(handshake.inKeys)-deletecount] + } + if out { + deletecount = 0 + for i, key := range handshake.outKeys { + if key.expiredAt.Before(now) && (key.expiredAt.IsZero() && key.limit <= key.count) { + log.Trace("handshake out clean remove", "symkeyid", *key.symKeyID) + deletes = append(deletes, *key.symKeyID) + handshake.outKeys[deletecount] = handshake.outKeys[i] + deletecount++ + } + } + handshake.outKeys = handshake.outKeys[:len(handshake.outKeys)-deletecount] + } + for _, keyid := range deletes { + delete(ctl.symKeyIndex, keyid) + ctl.pss.symKeyPool[keyid][*topic].protected = false + } + return len(deletes) +} + +// Runs cleanHandshake() on all peers and topics +func (ctl *HandshakeController) clean() { + peerpubkeys := ctl.handshakes + for pubkeyid, peertopics := range peerpubkeys { + for topic := range peertopics { + ctl.cleanHandshake(pubkeyid, &topic, true, true) + } + } +} + +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 +// 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 { + 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 nil + } + 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 +} + +// Handle incoming key exchange message +// Add keys received from peer to store +// and enerate and send the amount of keys requested by peer +// +// TODO: +// - flood guard +// - keylength check +// - update address hint if: +// 1) leftmost bytes in new address do not match stored +// 2) else, if new address is longer +func (ctl *HandshakeController) handleKeys(pubkeyid string, keymsg *handshakeMsg) error { + // new keys from peer + if len(keymsg.Keys) > 0 { + log.Debug("received handshake keys", "pubkeyid", pubkeyid, "from", keymsg.From, "count", len(keymsg.Keys)) + var sendsymkeyids []string + for _, key := range keymsg.Keys { + sendsymkey := make([]byte, len(key)) + copy(sendsymkey, key) + sendsymkeyid, err := ctl.pss.setSymmetricKey(sendsymkey, keymsg.Topic, PssAddress(keymsg.From), false, false) + if err != nil { + return err + } + sendsymkeyids = append(sendsymkeyids, sendsymkeyid) + } + if len(sendsymkeyids) > 0 { + ctl.updateKeys(pubkeyid, &keymsg.Topic, false, sendsymkeyids, keymsg.Limit) + + ctl.alertHandshake(pubkeyid, sendsymkeyids) + } + } + + // peer request for keys + if keymsg.Request > 0 { + _, err := ctl.sendKey(pubkeyid, &keymsg.Topic, keymsg.Request) + if err != nil { + return err + } + } + + return nil +} + +// Send key exchange to peer (public key) valid for `topic` +// Will send number of keys specified by `keycount` with +// validity limits specified in `msglimit` +// If number of valid outgoing keys is less than the ideal/max +// amount, a request is sent for the amount of keys to make up +// the difference +func (ctl *HandshakeController) sendKey(pubkeyid string, topic *Topic, keycount uint8) ([]string, error) { + + var requestcount uint8 + 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 { + to = psp.address + } + + recvkeys := make([][]byte, keycount) + recvkeyids := make([]string, keycount) + ctl.lock.Lock() + if _, ok := ctl.handshakes[pubkeyid]; !ok { + ctl.handshakes[pubkeyid] = make(map[Topic]*handshake) + } + ctl.lock.Unlock() + + // check if buffer is not full + outkeys := ctl.validKeys(pubkeyid, topic, false) + if len(outkeys) < int(ctl.symKeyCapacity) { + //requestcount = uint8(self.symKeyCapacity - uint8(len(outkeys))) + requestcount = ctl.symKeyCapacity + } + // return if there's nothing to be accomplished + if requestcount == 0 && keycount == 0 { + return []string{}, nil + } + + // generate new keys to send + for i := 0; i < len(recvkeyids); i++ { + var err error + recvkeyids[i], err = ctl.pss.GenerateSymmetricKey(*topic, to, true) + if err != nil { + return []string{}, fmt.Errorf("set receive symkey fail (pubkey %x topic %x): %v", pubkeyid, topic, err) + } + recvkeys[i], err = ctl.pss.GetSymmetricKey(recvkeyids[i]) + if err != nil { + return []string{}, fmt.Errorf("GET Generated outgoing symkey fail (pubkey %x topic %x): %v", pubkeyid, topic, err) + } + } + ctl.updateKeys(pubkeyid, topic, true, recvkeyids, ctl.symKeySendLimit) + + // encode and send the message + recvkeymsg := &handshakeMsg{ + From: ctl.pss.BaseAddr(), + Keys: recvkeys, + Request: requestcount, + Limit: ctl.symKeySendLimit, + Topic: *topic, + } + log.Debug("sending our symkeys", "pubkey", pubkeyid, "symkeys", recvkeyids, "limit", ctl.symKeySendLimit, "requestcount", requestcount, "keycount", len(recvkeys)) + recvkeybytes, err := rlp.EncodeToBytes(recvkeymsg) + if err != nil { + return []string{}, fmt.Errorf("rlp keymsg encode fail: %v", err) + } + // if the send fails it means this public key is not registered for this particular address AND topic + err = ctl.pss.SendAsym(pubkeyid, *topic, recvkeybytes) + if err != nil { + return []string{}, fmt.Errorf("Send symkey failed: %v", err) + } + return recvkeyids, nil +} + +// 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 + close(ctl.keyC[pubkeyid]) + delete(ctl.keyC, pubkeyid) + } + return nil + } + if _, ok := ctl.keyC[pubkeyid]; !ok { + ctl.keyC[pubkeyid] = make(chan []string) + } + return ctl.keyC[pubkeyid] +} + +type HandshakeAPI struct { + namespace string + ctrl *HandshakeController +} + +// Initiate a handshake session for a peer (public key) and topic +// combination. +// +// If `sync` is set, the call will block until keys are received from peer, +// or if the handshake request times out +// +// If `flush` is set, the max amount of keys will be sent to the peer +// regardless of how many valid keys that currently exist in the store. +// +// Returns list of symmetric key ids that can be passed to pss.GetSymmetricKey() +// for retrieval of the symmetric key bytes themselves. +// +// Fails if the incoming symmetric key store is already full (and `flush` is false), +// or if the underlying key dispatcher fails +func (api *HandshakeAPI) Handshake(pubkeyid string, topic Topic, sync bool, flush bool) (keys []string, err error) { + var hsc chan []string + var keycount uint8 + if flush { + keycount = api.ctrl.symKeyCapacity + } else { + validkeys := api.ctrl.validKeys(pubkeyid, &topic, false) + keycount = api.ctrl.symKeyCapacity - uint8(len(validkeys)) + } + if keycount == 0 { + return keys, errors.New("Incoming symmetric key store is already full") + } + if sync { + hsc = api.ctrl.alertHandshake(pubkeyid, []string{}) + } + _, err = api.ctrl.sendKey(pubkeyid, &topic, keycount) + if err != nil { + return keys, err + } + if sync { + ctx, cancel := context.WithTimeout(context.Background(), api.ctrl.symKeyRequestTimeout) + defer cancel() + select { + case keys = <-hsc: + log.Trace("sync handshake response receive", "key", keys) + case <-ctx.Done(): + return []string{}, errors.New("timeout") + } + } + return keys, nil +} + +// Activate handshake functionality on a topic +func (api *HandshakeAPI) AddHandshake(topic Topic) error { + api.ctrl.deregisterFuncs[topic] = api.ctrl.pss.Register(&topic, NewHandler(api.ctrl.handler)) + return nil +} + +// Deactivate handshake functionality on a topic +func (api *HandshakeAPI) RemoveHandshake(topic *Topic) error { + if _, ok := api.ctrl.deregisterFuncs[*topic]; ok { + api.ctrl.deregisterFuncs[*topic]() + } + return nil +} + +// Returns all valid symmetric keys in store per peer (public key) +// and topic. +// +// The `in` and `out` parameters indicate for which direction(s) +// symmetric keys will be returned. +// If both are false, no keys (and no error) will be returned. +func (api *HandshakeAPI) GetHandshakeKeys(pubkeyid string, topic Topic, in bool, out bool) (keys []string, err error) { + if in { + for _, inkey := range api.ctrl.validKeys(pubkeyid, &topic, true) { + keys = append(keys, *inkey) + } + } + if out { + for _, outkey := range api.ctrl.validKeys(pubkeyid, &topic, false) { + keys = append(keys, *outkey) + } + } + return keys, nil +} + +// 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.getSymKey(symkeyid) + if storekey == nil { + return 0, fmt.Errorf("invalid symkey id %s", symkeyid) + } + return storekey.limit - storekey.count, nil +} + +// 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.getSymKey(symkeyid) + if storekey == nil { + return "", fmt.Errorf("invalid symkey id %s", symkeyid) + } + return *storekey.pubKeyID, nil +} + +// Manually expire the given symkey +// +// If `flush` is set, garbage collection will be performed before returning. +// +// Returns true on successful removal, false otherwise +func (api *HandshakeAPI) ReleaseHandshakeKey(pubkeyid string, topic Topic, symkeyid string, flush bool) (removed bool, err error) { + removed = api.ctrl.releaseKey(symkeyid, &topic) + if removed && flush { + api.ctrl.cleanHandshake(pubkeyid, &topic, true, true) + } + return +} + +// Send symmetric message under the handshake scheme +// +// Overloads the pss.SendSym() API call, adding symmetric key usage count +// 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 otherErr := api.ctrl.registerSymKeyUse(symkeyid); otherErr != nil { + return otherErr + } + return err +} diff --git a/p2p/simulations/adapters/state.go b/swarm/pss/handshake_none.go similarity index 67% rename from p2p/simulations/adapters/state.go rename to swarm/pss/handshake_none.go index 8b1dfef904..a09674be39 100644 --- a/p2p/simulations/adapters/state.go +++ b/swarm/pss/handshake_none.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 @@ -13,23 +13,15 @@ // // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package adapters -type SimStateStore struct { - m map[string][]byte -} +// +build nopsshandshake -func (self *SimStateStore) Load(s string) ([]byte, error) { - return self.m[s], nil -} +package pss -func (self *SimStateStore) Save(s string, data []byte) error { - self.m[s] = data +const ( + IsActiveHandshake = false +) + +func NewHandshakeParams() interface{} { return nil } - -func NewSimStateStore() *SimStateStore { - return &SimStateStore{ - make(map[string][]byte), - } -} diff --git a/swarm/pss/handshake_test.go b/swarm/pss/handshake_test.go new file mode 100644 index 0000000000..f4effc022d --- /dev/null +++ b/swarm/pss/handshake_test.go @@ -0,0 +1,264 @@ +// 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 pss + +import ( + "strconv" + "strings" + "testing" + "time" + + "github.com/ethereum/go-ethereum/swarm/log" +) + +// asymmetrical key exchange between two directly connected peers +// full address, partial address (8 bytes) and empty address +func TestHandshake(t *testing.T) { + t.Run("32", testHandshake) + t.Run("8", testHandshake) + t.Run("0", testHandshake) +} + +func testHandshake(t *testing.T) { + + // how much of the address we will use + useHandshake = true + var addrsize int64 + var err error + addrsizestring := strings.Split(t.Name(), "/") + addrsize, _ = strconv.ParseInt(addrsizestring[1], 10, 0) + + // set up two nodes directly connected + // (we are not testing pss routing here) + clients, err := setupNetwork(2, true) + if err != nil { + t.Fatal(err) + } + + var topic string + err = clients[0].Call(&topic, "pss_stringToTopic", "foo:42") + if err != nil { + t.Fatal(err) + } + + var loaddr string + err = clients[0].Call(&loaddr, "pss_baseAddr") + if err != nil { + t.Fatalf("rpc get node 1 baseaddr fail: %v", err) + } + // "0x" = 2 bytes + addrsize address bytes which in hex is 2x length + loaddr = loaddr[:2+(addrsize*2)] + var roaddr string + err = clients[1].Call(&roaddr, "pss_baseAddr") + if err != nil { + t.Fatalf("rpc get node 2 baseaddr fail: %v", err) + } + roaddr = roaddr[:2+(addrsize*2)] + log.Debug("addresses", "left", loaddr, "right", roaddr) + + // retrieve public key from pss instance + // set this public key reciprocally + var lpubkey string + err = clients[0].Call(&lpubkey, "pss_getPublicKey") + if err != nil { + t.Fatalf("rpc get node 1 pubkey fail: %v", err) + } + var rpubkey string + err = clients[1].Call(&rpubkey, "pss_getPublicKey") + if err != nil { + t.Fatalf("rpc get node 2 pubkey fail: %v", err) + } + + time.Sleep(time.Millisecond * 1000) // replace with hive healthy code + + // give each node its peer's public key + err = clients[0].Call(nil, "pss_setPeerPublicKey", rpubkey, topic, roaddr) + if err != nil { + t.Fatal(err) + } + err = clients[1].Call(nil, "pss_setPeerPublicKey", lpubkey, topic, loaddr) + if err != nil { + t.Fatal(err) + } + + // perform the handshake + // after this each side will have defaultSymKeyBufferCapacity symkeys each for in- and outgoing messages: + // L -> request 4 keys -> R + // L <- send 4 keys, request 4 keys <- R + // L -> send 4 keys -> R + // the call will fill the array with symkeys L needs for sending to R + err = clients[0].Call(nil, "pss_addHandshake", topic) + if err != nil { + t.Fatal(err) + } + err = clients[1].Call(nil, "pss_addHandshake", topic) + if err != nil { + t.Fatal(err) + } + + var lhsendsymkeyids []string + err = clients[0].Call(&lhsendsymkeyids, "pss_handshake", rpubkey, topic, true, true) + if err != nil { + t.Fatal(err) + } + + // make sure the r-node gets its keys + time.Sleep(time.Second) + + // check if we have 6 outgoing keys stored, and they match what was received from R + var lsendsymkeyids []string + err = clients[0].Call(&lsendsymkeyids, "pss_getHandshakeKeys", rpubkey, topic, false, true) + if err != nil { + t.Fatal(err) + } + m := 0 + for _, hid := range lhsendsymkeyids { + for _, lid := range lsendsymkeyids { + if lid == hid { + m++ + } + } + } + if m != defaultSymKeyCapacity { + t.Fatalf("buffer size mismatch, expected %d, have %d: %v", defaultSymKeyCapacity, m, lsendsymkeyids) + } + + // check if in- and outgoing keys on l-node and r-node match up and are in opposite categories (l recv = r send, l send = r recv) + var rsendsymkeyids []string + err = clients[1].Call(&rsendsymkeyids, "pss_getHandshakeKeys", lpubkey, topic, false, true) + if err != nil { + t.Fatal(err) + } + var lrecvsymkeyids []string + err = clients[0].Call(&lrecvsymkeyids, "pss_getHandshakeKeys", rpubkey, topic, true, false) + if err != nil { + t.Fatal(err) + } + var rrecvsymkeyids []string + err = clients[1].Call(&rrecvsymkeyids, "pss_getHandshakeKeys", lpubkey, topic, true, false) + if err != nil { + t.Fatal(err) + } + + // get outgoing symkeys in byte form from both sides + var lsendsymkeys []string + for _, id := range lsendsymkeyids { + var key string + err = clients[0].Call(&key, "pss_getSymmetricKey", id) + if err != nil { + t.Fatal(err) + } + lsendsymkeys = append(lsendsymkeys, key) + } + var rsendsymkeys []string + for _, id := range rsendsymkeyids { + var key string + err = clients[1].Call(&key, "pss_getSymmetricKey", id) + if err != nil { + t.Fatal(err) + } + rsendsymkeys = append(rsendsymkeys, key) + } + + // get incoming symkeys in byte form from both sides and compare + var lrecvsymkeys []string + for _, id := range lrecvsymkeyids { + var key string + err = clients[0].Call(&key, "pss_getSymmetricKey", id) + if err != nil { + t.Fatal(err) + } + match := false + for _, otherkey := range rsendsymkeys { + if otherkey == key { + match = true + } + } + if !match { + t.Fatalf("no match right send for left recv key %s", id) + } + lrecvsymkeys = append(lrecvsymkeys, key) + } + var rrecvsymkeys []string + for _, id := range rrecvsymkeyids { + var key string + err = clients[1].Call(&key, "pss_getSymmetricKey", id) + if err != nil { + t.Fatal(err) + } + match := false + for _, otherkey := range lsendsymkeys { + if otherkey == key { + match = true + } + } + if !match { + t.Fatalf("no match left send for right recv key %s", id) + } + rrecvsymkeys = append(rrecvsymkeys, key) + } + + // send new handshake request, should send no keys + err = clients[0].Call(nil, "pss_handshake", rpubkey, topic, false) + if err == nil { + t.Fatal("expected full symkey buffer error") + } + + // expire one key, send new handshake request + err = clients[0].Call(nil, "pss_releaseHandshakeKey", rpubkey, topic, lsendsymkeyids[0], true) + if err != nil { + t.Fatalf("release left send key %s fail: %v", lsendsymkeyids[0], err) + } + + var newlhsendkeyids []string + + // send new handshake request, should now receive one key + // check that it is not in previous right recv key array + err = clients[0].Call(&newlhsendkeyids, "pss_handshake", rpubkey, topic, true, false) + if err != nil { + t.Fatalf("handshake send fail: %v", err) + } else if len(newlhsendkeyids) != defaultSymKeyCapacity { + t.Fatalf("wrong receive count, expected 1, got %d", len(newlhsendkeyids)) + } + + var newlrecvsymkey string + err = clients[0].Call(&newlrecvsymkey, "pss_getSymmetricKey", newlhsendkeyids[0]) + if err != nil { + t.Fatal(err) + } + var rmatchsymkeyid *string + for i, id := range rrecvsymkeyids { + var key string + err = clients[1].Call(&key, "pss_getSymmetricKey", id) + if err != nil { + t.Fatal(err) + } + if newlrecvsymkey == key { + rmatchsymkeyid = &rrecvsymkeyids[i] + } + } + if rmatchsymkeyid != nil { + t.Fatalf("right sent old key id %s in second handshake", *rmatchsymkeyid) + } + + // clean the pss core keystore. Should clean the key released earlier + var cleancount int + clients[0].Call(&cleancount, "psstest_clean") + if cleancount > 1 { + t.Fatalf("pss clean count mismatch; expected 1, got %d", cleancount) + } +} diff --git a/swarm/pss/keystore.go b/swarm/pss/keystore.go new file mode 100644 index 0000000000..5c44cb2453 --- /dev/null +++ b/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/swarm/pss/notify/notify.go b/swarm/pss/notify/notify.go new file mode 100644 index 0000000000..e9d40dc321 --- /dev/null +++ b/swarm/pss/notify/notify.go @@ -0,0 +1,394 @@ +package notify + +import ( + "crypto/ecdsa" + "fmt" + "sync" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/swarm/log" + "github.com/ethereum/go-ethereum/swarm/pss" +) + +const ( + // sent from requester to updater to request start of notifications + MsgCodeStart = iota + + // sent from updater to requester, contains a notification plus a new symkey to replace the old + MsgCodeNotifyWithKey + + // sent from updater to requester, contains a notification + MsgCodeNotify + + // sent from requester to updater to request stop of notifications (currently unused) + MsgCodeStop + MsgCodeMax +) + +const ( + DefaultAddressLength = 1 + symKeyLength = 32 // this should be gotten from source +) + +var ( + // control topic is used before symmetric key issuance completes + controlTopic = pss.Topic{0x00, 0x00, 0x00, 0x01} +) + +// when code is MsgCodeStart, Payload is address +// when code is MsgCodeNotifyWithKey, Payload is notification | symkey +// when code is MsgCodeNotify, Payload is notification +// when code is MsgCodeStop, Payload is address +type Msg struct { + Code byte + Name []byte + Payload []byte + namestring string +} + +// NewMsg creates a new notification message object +func NewMsg(code byte, name string, payload []byte) *Msg { + return &Msg{ + Code: code, + Name: []byte(name), + Payload: payload, + namestring: name, + } +} + +// NewMsgFromPayload decodes a serialized message payload into a new notification message object +func NewMsgFromPayload(payload []byte) (*Msg, error) { + msg := &Msg{} + err := rlp.DecodeBytes(payload, msg) + if err != nil { + return nil, err + } + msg.namestring = string(msg.Name) + return msg, nil +} + +// a notifier has one sendBin entry for each address space it sends messages to +type sendBin struct { + address pss.PssAddress + symKeyId string + count int +} + +// represents a single notification service +// only subscription address bins that match the address of a notification client have entries. +type notifier struct { + bins map[string]*sendBin + topic pss.Topic // identifies the resource for pss receiver + threshold int // amount of address bytes used in bins + updateC <-chan []byte + quitC chan struct{} +} + +func (n *notifier) removeSubscription() { + n.quitC <- struct{}{} +} + +// represents an individual subscription made by a public key at a specific address/neighborhood +type subscription struct { + pubkeyId string + address pss.PssAddress + handler func(string, []byte) error +} + +// Controller is the interface to control, add and remove notification services and subscriptions +type Controller struct { + pss *pss.Pss + notifiers map[string]*notifier + subscriptions map[string]*subscription + mu sync.Mutex +} + +// NewController creates a new Controller object +func NewController(ps *pss.Pss) *Controller { + ctrl := &Controller{ + pss: ps, + notifiers: make(map[string]*notifier), + subscriptions: make(map[string]*subscription), + } + ctrl.pss.Register(&controlTopic, pss.NewHandler(ctrl.Handler)) + return ctrl +} + +// IsActive is used to check if a notification service exists for a specified id string +// Returns true if exists, false if not +func (c *Controller) IsActive(name string) bool { + c.mu.Lock() + defer c.mu.Unlock() + return c.isActive(name) +} + +func (c *Controller) isActive(name string) bool { + _, ok := c.notifiers[name] + return ok +} + +// Subscribe is used by a client to request notifications from a notification service provider +// It will create a MsgCodeStart message and send asymmetrically to the provider using its public key and routing address +// The handler function is a callback that will be called when notifications are received +// Fails if the request pss cannot be sent or if the update message could not be serialized +func (c *Controller) Subscribe(name string, pubkey *ecdsa.PublicKey, address pss.PssAddress, handler func(string, []byte) error) error { + c.mu.Lock() + defer c.mu.Unlock() + msg := NewMsg(MsgCodeStart, name, c.pss.BaseAddr()) + c.pss.SetPeerPublicKey(pubkey, controlTopic, address) + pubkeyId := hexutil.Encode(crypto.FromECDSAPub(pubkey)) + smsg, err := rlp.EncodeToBytes(msg) + if err != nil { + return err + } + err = c.pss.SendAsym(pubkeyId, controlTopic, smsg) + if err != nil { + return err + } + c.subscriptions[name] = &subscription{ + pubkeyId: pubkeyId, + address: address, + handler: handler, + } + return nil +} + +// Unsubscribe, perhaps unsurprisingly, undoes the effects of Subscribe +// Fails if the subscription does not exist, if the request pss cannot be sent or if the update message could not be serialized +func (c *Controller) Unsubscribe(name string) error { + c.mu.Lock() + defer c.mu.Unlock() + sub, ok := c.subscriptions[name] + if !ok { + return fmt.Errorf("Unknown subscription '%s'", name) + } + msg := NewMsg(MsgCodeStop, name, sub.address) + smsg, err := rlp.EncodeToBytes(msg) + if err != nil { + return err + } + err = c.pss.SendAsym(sub.pubkeyId, controlTopic, smsg) + if err != nil { + return err + } + delete(c.subscriptions, name) + return nil +} + +// NewNotifier is used by a notification service provider to create a new notification service +// It takes a name as identifier for the resource, a threshold indicating the granularity of the subscription address bin +// It then starts an event loop which listens to the supplied update channel and executes notifications on channel receives +// Fails if a notifier already is registered on the name +//func (c *Controller) NewNotifier(name string, threshold int, contentFunc func(string) ([]byte, error)) error { +func (c *Controller) NewNotifier(name string, threshold int, updateC <-chan []byte) (func(), error) { + c.mu.Lock() + if c.isActive(name) { + c.mu.Unlock() + return nil, fmt.Errorf("Notification service %s already exists in controller", name) + } + quitC := make(chan struct{}) + c.notifiers[name] = ¬ifier{ + bins: make(map[string]*sendBin), + topic: pss.BytesToTopic([]byte(name)), + threshold: threshold, + updateC: updateC, + quitC: quitC, + //contentFunc: contentFunc, + } + c.mu.Unlock() + go func() { + for { + select { + case <-quitC: + return + case data := <-updateC: + c.notify(name, data) + } + } + }() + + return c.notifiers[name].removeSubscription, nil +} + +// RemoveNotifier is used to stop a notification service. +// It cancels the event loop listening to the notification provider's update channel +func (c *Controller) RemoveNotifier(name string) error { + c.mu.Lock() + defer c.mu.Unlock() + currentNotifier, ok := c.notifiers[name] + if !ok { + return fmt.Errorf("Unknown notification service %s", name) + } + currentNotifier.removeSubscription() + delete(c.notifiers, name) + return nil +} + +// Notify is called by a notification service provider to issue a new notification +// It takes the name of the notification service and the data to be sent. +// It fails if a notifier with this name does not exist or if data could not be serialized +// Note that it does NOT fail on failure to send a message +func (c *Controller) notify(name string, data []byte) error { + c.mu.Lock() + defer c.mu.Unlock() + if !c.isActive(name) { + return fmt.Errorf("Notification service %s doesn't exist", name) + } + msg := NewMsg(MsgCodeNotify, name, data) + smsg, err := rlp.EncodeToBytes(msg) + if err != nil { + return err + } + for _, m := range c.notifiers[name].bins { + log.Debug("sending pss notify", "name", name, "addr", fmt.Sprintf("%x", m.address), "topic", fmt.Sprintf("%x", c.notifiers[name].topic), "data", data) + go func(m *sendBin) { + err = c.pss.SendSym(m.symKeyId, c.notifiers[name].topic, smsg) + if err != nil { + log.Warn("Failed to send notify to addr %x: %v", m.address, err) + } + }(m) + } + return nil +} + +// check if we already have the bin +// if we do, retrieve the symkey from it and increment the count +// if we dont make a new symkey and a new bin entry +func (c *Controller) addToBin(ntfr *notifier, address []byte) (symKeyId string, pssAddress pss.PssAddress, err error) { + + // parse the address from the message and truncate if longer than our bins threshold + if len(address) > ntfr.threshold { + address = address[:ntfr.threshold] + } + + pssAddress = pss.PssAddress(address) + hexAddress := fmt.Sprintf("%x", address) + currentBin, ok := ntfr.bins[hexAddress] + if ok { + currentBin.count++ + symKeyId = currentBin.symKeyId + } else { + symKeyId, err = c.pss.GenerateSymmetricKey(ntfr.topic, pssAddress, false) + if err != nil { + return "", nil, err + } + ntfr.bins[hexAddress] = &sendBin{ + address: address, + symKeyId: symKeyId, + count: 1, + } + } + return symKeyId, pssAddress, nil +} + +func (c *Controller) handleStartMsg(msg *Msg, keyid string) (err error) { + + keyidbytes, err := hexutil.Decode(keyid) + if err != nil { + return err + } + pubkey, err := crypto.UnmarshalPubkey(keyidbytes) + if err != nil { + return err + } + + // if name is not registered for notifications we will not react + currentNotifier, ok := c.notifiers[msg.namestring] + if !ok { + return fmt.Errorf("Subscribe attempted on unknown resource '%s'", msg.namestring) + } + + // add to or open new bin + symKeyId, pssAddress, err := c.addToBin(currentNotifier, msg.Payload) + if err != nil { + return err + } + + // add to address book for send initial notify + symkey, err := c.pss.GetSymmetricKey(symKeyId) + if err != nil { + return err + } + err = c.pss.SetPeerPublicKey(pubkey, controlTopic, pssAddress) + if err != nil { + return err + } + + // TODO this is set to zero-length byte pending decision on protocol for initial message, whether it should include message or not, and how to trigger the initial message so that current state of Swarm feed is sent upon subscription + notify := []byte{} + replyMsg := NewMsg(MsgCodeNotifyWithKey, msg.namestring, make([]byte, len(notify)+symKeyLength)) + copy(replyMsg.Payload, notify) + copy(replyMsg.Payload[len(notify):], symkey) + sReplyMsg, err := rlp.EncodeToBytes(replyMsg) + if err != nil { + return err + } + return c.pss.SendAsym(keyid, controlTopic, sReplyMsg) +} + +func (c *Controller) handleNotifyWithKeyMsg(msg *Msg) error { + symkey := msg.Payload[len(msg.Payload)-symKeyLength:] + topic := pss.BytesToTopic(msg.Name) + + // \TODO keep track of and add actual address + updaterAddr := pss.PssAddress([]byte{}) + 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]) +} + +func (c *Controller) handleStopMsg(msg *Msg) error { + // if name is not registered for notifications we will not react + currentNotifier, ok := c.notifiers[msg.namestring] + if !ok { + return fmt.Errorf("Unsubscribe attempted on unknown resource '%s'", msg.namestring) + } + + // parse the address from the message and truncate if longer than our bins' address length threshold + address := msg.Payload + if len(msg.Payload) > currentNotifier.threshold { + address = address[:currentNotifier.threshold] + } + + // remove the entry from the bin if it exists, and remove the bin if it's the last remaining one + hexAddress := fmt.Sprintf("%x", address) + currentBin, ok := currentNotifier.bins[hexAddress] + if !ok { + return fmt.Errorf("found no active bin for address %s", hexAddress) + } + currentBin.count-- + if currentBin.count == 0 { // if no more clients in this bin, remove it + delete(currentNotifier.bins, hexAddress) + } + return nil +} + +// Handler is the pss topic handler to be used to process notification service messages +// It should be registered in the pss of both to any notification service provides and clients using the service +func (c *Controller) Handler(smsg []byte, p *p2p.Peer, asymmetric bool, keyid string) error { + c.mu.Lock() + defer c.mu.Unlock() + log.Debug("notify controller handler", "keyid", keyid) + + // see if the message is valid + msg, err := NewMsgFromPayload(smsg) + if err != nil { + return err + } + + switch msg.Code { + case MsgCodeStart: + return c.handleStartMsg(msg, keyid) + case MsgCodeNotifyWithKey: + return c.handleNotifyWithKeyMsg(msg) + case MsgCodeNotify: + return c.subscriptions[msg.namestring].handler(msg.namestring, msg.Payload) + case MsgCodeStop: + return c.handleStopMsg(msg) + } + + return fmt.Errorf("Invalid message code: %d", msg.Code) +} diff --git a/swarm/pss/notify/notify_test.go b/swarm/pss/notify/notify_test.go new file mode 100644 index 0000000000..cda069b9e1 --- /dev/null +++ b/swarm/pss/notify/notify_test.go @@ -0,0 +1,265 @@ +package notify + +import ( + "bytes" + "context" + "flag" + "fmt" + "os" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/crypto" + "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" + "github.com/ethereum/go-ethereum/swarm/pss" + "github.com/ethereum/go-ethereum/swarm/state" + whisper "github.com/ethereum/go-ethereum/whisper/whisperv6" +) + +var ( + loglevel = flag.Int("l", 3, "loglevel") + psses map[string]*pss.Pss + w *whisper.Whisper + wapi *whisper.PublicWhisperAPI +) + +func init() { + flag.Parse() + hs := log.StreamHandler(os.Stderr, log.TerminalFormat(true)) + hf := log.LvlFilterHandler(log.Lvl(*loglevel), hs) + h := log.CallerFileHandler(hf) + log.Root().SetHandler(h) + + w = whisper.New(&whisper.DefaultConfig) + wapi = whisper.NewPublicWhisperAPI(w) + psses = make(map[string]*pss.Pss) +} + +// Creates a client node and notifier node +// Client sends pss notifications requests +// notifier sends initial notification with symmetric key, and +// second notification symmetrically encrypted +func TestStart(t *testing.T) { + adapter := adapters.NewSimAdapter(newServices(false)) + net := simulations.NewNetwork(adapter, &simulations.NetworkConfig{ + ID: "0", + DefaultService: "bzz", + }) + defer net.Shutdown() + leftNodeConf := adapters.RandomNodeConfig() + leftNodeConf.Services = []string{"bzz", "pss"} + leftNode, err := net.NewNodeWithConfig(leftNodeConf) + if err != nil { + t.Fatal(err) + } + err = net.Start(leftNode.ID()) + if err != nil { + t.Fatal(err) + } + + rightNodeConf := adapters.RandomNodeConfig() + rightNodeConf.Services = []string{"bzz", "pss"} + rightNode, err := net.NewNodeWithConfig(rightNodeConf) + if err != nil { + t.Fatal(err) + } + err = net.Start(rightNode.ID()) + if err != nil { + t.Fatal(err) + } + + err = net.Connect(rightNode.ID(), leftNode.ID()) + if err != nil { + t.Fatal(err) + } + + leftRpc, err := leftNode.Client() + if err != nil { + t.Fatal(err) + } + + rightRpc, err := rightNode.Client() + if err != nil { + t.Fatal(err) + } + + var leftAddr string + err = leftRpc.Call(&leftAddr, "pss_baseAddr") + if err != nil { + t.Fatal(err) + } + + var rightAddr string + err = rightRpc.Call(&rightAddr, "pss_baseAddr") + if err != nil { + t.Fatal(err) + } + + var leftPub string + err = leftRpc.Call(&leftPub, "pss_getPublicKey") + if err != nil { + t.Fatal(err) + } + + var rightPub string + err = rightRpc.Call(&rightPub, "pss_getPublicKey") + if err != nil { + t.Fatal(err) + } + + rsrcName := "foo.eth" + rsrcTopic := pss.BytesToTopic([]byte(rsrcName)) + + // wait for kademlia table to populate + time.Sleep(time.Second) + + 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, false, false) + if err != nil { + t.Fatal(err) + } + defer rightSub.Unsubscribe() + + updateC := make(chan []byte) + var updateMsg []byte + ctrlClient := NewController(psses[rightPub]) + ctrlNotifier := NewController(psses[leftPub]) + ctrlNotifier.NewNotifier("foo.eth", 2, updateC) + + pubkeybytes, err := hexutil.Decode(leftPub) + if err != nil { + t.Fatal(err) + } + pubkey, err := crypto.UnmarshalPubkey(pubkeybytes) + if err != nil { + t.Fatal(err) + } + addrbytes, err := hexutil.Decode(leftAddr) + 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(copyOfUpdateMsg, b) { + ctrlClientError <- fmt.Errorf("unexpected result in client handler: '%s':'%x'", s, b) + } else { + 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()) + } + + dMsg, err := NewMsgFromPayload(inMsg.Msg) + if err != nil { + t.Fatal(err) + } + if dMsg.namestring != rsrcName { + t.Fatalf("expected name '%s', got '%s'", rsrcName, dMsg.namestring) + } + if !bytes.Equal(dMsg.Payload[:len(updateMsg)], updateMsg) { + t.Fatalf("expected payload first %d bytes '%x', got '%x'", len(updateMsg), updateMsg, dMsg.Payload[:len(updateMsg)]) + } + if len(updateMsg)+symKeyLength != len(dMsg.Payload) { + t.Fatalf("expected payload length %d, have %d", len(updateMsg)+symKeyLength, len(dMsg.Payload)) + } + + rightSubUpdate, err := rightRpc.Subscribe(ctx, "pss", rmsgC, "receive", rsrcTopic, false, false) + if err != nil { + t.Fatal(err) + } + defer rightSubUpdate.Unsubscribe() + + updateMsg = []byte("plugh") + updateC <- updateMsg + select { + case inMsg = <-rmsgC: + case <-ctx.Done(): + log.Error("timed out waiting for msg", "topic", fmt.Sprintf("%x", rsrcTopic)) + t.Fatal(ctx.Err()) + } + dMsg, err = NewMsgFromPayload(inMsg.Msg) + if err != nil { + t.Fatal(err) + } + if dMsg.namestring != rsrcName { + t.Fatalf("expected name %s, got %s", rsrcName, dMsg.namestring) + } + if !bytes.Equal(dMsg.Payload, updateMsg) { + t.Fatalf("expected payload '%x', got '%x'", updateMsg, dMsg.Payload) + } + +} + +func newServices(allowRaw bool) adapters.Services { + stateStore := state.NewInmemoryStore() + kademlias := make(map[enode.ID]*network.Kademlia) + kademlia := func(id enode.ID) *network.Kademlia { + if k, ok := kademlias[id]; ok { + return k + } + params := network.NewKadParams() + params.NeighbourhoodSize = 2 + params.MaxBinSize = 3 + params.MinBinSize = 1 + params.MaxRetries = 1000 + params.RetryExponent = 2 + params.RetryInterval = 1000000 + kademlias[id] = network.NewKademlia(id[:], params) + return kademlias[id] + } + return adapters.Services{ + "pss": func(ctx *adapters.ServiceContext) (node.Service, error) { + ctxlocal, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + keys, err := wapi.NewKeyPair(ctxlocal) + if err != nil { + return nil, err + } + privkey, err := w.GetPrivateKey(keys) + if err != nil { + return nil, err + } + pssp := pss.NewPssParams().WithPrivateKey(privkey) + pssp.MsgTTL = time.Second * 30 + pssp.AllowRaw = allowRaw + pskad := kademlia(ctx.Config.ID) + ps, err := pss.NewPss(pskad, pssp) + if err != nil { + return nil, err + } + //psses[common.ToHex(crypto.FromECDSAPub(&privkey.PublicKey))] = ps + psses[hexutil.Encode(crypto.FromECDSAPub(&privkey.PublicKey))] = ps + return ps, nil + }, + "bzz": func(ctx *adapters.ServiceContext) (node.Service, error) { + addr := network.NewAddr(ctx.Config.Node()) + 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), stateStore, nil, nil), nil + }, + } +} diff --git a/swarm/pss/ping.go b/swarm/pss/ping.go new file mode 100644 index 0000000000..ff635f40a4 --- /dev/null +++ b/swarm/pss/ping.go @@ -0,0 +1,97 @@ +// 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 !nopssprotocol,!nopssping + +package pss + +import ( + "context" + "errors" + "time" + + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/p2p/protocols" + "github.com/ethereum/go-ethereum/swarm/log" +) + +// Generic ping protocol implementation for +// pss devp2p protocol emulation +type PingMsg struct { + Created time.Time + Pong bool // set if message is pong reply +} + +type Ping struct { + Pong bool // toggle pong reply upon ping receive + OutC chan bool // trigger ping + InC chan bool // optional, report back to calling code +} + +func (p *Ping) pingHandler(ctx context.Context, msg interface{}) error { + var pingmsg *PingMsg + var ok bool + if pingmsg, ok = msg.(*PingMsg); !ok { + return errors.New("invalid msg") + } + log.Debug("ping handler", "msg", pingmsg, "outc", p.OutC) + if p.InC != nil { + p.InC <- pingmsg.Pong + } + if p.Pong && !pingmsg.Pong { + p.OutC <- true + } + return nil +} + +var PingProtocol = &protocols.Spec{ + Name: "psstest", + Version: 1, + MaxMsgSize: 1024, + Messages: []interface{}{ + PingMsg{}, + }, +} + +var PingTopic = ProtocolTopic(PingProtocol) + +func NewPingProtocol(ping *Ping) *p2p.Protocol { + return &p2p.Protocol{ + Name: PingProtocol.Name, + Version: PingProtocol.Version, + Length: uint64(PingProtocol.MaxMsgSize), + Run: func(p *p2p.Peer, rw p2p.MsgReadWriter) error { + quitC := make(chan struct{}) + pp := protocols.NewPeer(p, rw, PingProtocol) + log.Trace("running pss vprotocol", "peer", p, "outc", ping.OutC) + go func() { + for { + select { + case ispong := <-ping.OutC: + pp.Send(context.TODO(), &PingMsg{ + Created: time.Now(), + Pong: ispong, + }) + case <-quitC: + } + } + }() + err := pp.Run(ping.pingHandler) + quitC <- struct{}{} + return err + }, + } +} diff --git a/swarm/pss/protocol.go b/swarm/pss/protocol.go new file mode 100644 index 0000000000..7f186f6153 --- /dev/null +++ b/swarm/pss/protocol.go @@ -0,0 +1,283 @@ +// 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 !nopssprotocol + +package pss + +import ( + "bytes" + "fmt" + "sync" + "time" + + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/p2p/protocols" + "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/swarm/log" +) + +const ( + IsActiveProtocol = true +) + +// Convenience wrapper for devp2p protocol messages for transport over pss +type ProtocolMsg struct { + Code uint64 + Size uint32 + Payload []byte + ReceivedAt time.Time +} + +// Creates a ProtocolMsg +func NewProtocolMsg(code uint64, msg interface{}) ([]byte, error) { + + rlpdata, err := rlp.EncodeToBytes(msg) + if err != nil { + return nil, err + } + + // TODO verify that nested structs cannot be used in rlp + smsg := &ProtocolMsg{ + Code: code, + Size: uint32(len(rlpdata)), + Payload: rlpdata, + } + + return rlp.EncodeToBytes(smsg) +} + +// Protocol options to be passed to a new Protocol instance +// +// The parameters specify which encryption schemes to allow +type ProtocolParams struct { + Asymmetric bool + Symmetric bool +} + +// PssReadWriter bridges pss send/receive with devp2p protocol send/receive +// +// Implements p2p.MsgReadWriter +type PssReadWriter struct { + *Pss + LastActive time.Time + rw chan p2p.Msg + spec *protocols.Spec + topic *Topic + sendFunc func(string, Topic, []byte) error + key string + closed bool +} + +// Implements p2p.MsgReader +func (prw *PssReadWriter) ReadMsg() (p2p.Msg, error) { + msg := <-prw.rw + log.Trace(fmt.Sprintf("pssrw readmsg: %v", msg)) + return msg, nil +} + +// Implements p2p.MsgWriter +func (prw *PssReadWriter) WriteMsg(msg p2p.Msg) error { + log.Trace("pssrw writemsg", "msg", msg) + if prw.closed { + return fmt.Errorf("connection closed") + } + rlpdata := make([]byte, msg.Size) + msg.Payload.Read(rlpdata) + pmsg, err := rlp.EncodeToBytes(ProtocolMsg{ + Code: msg.Code, + Size: msg.Size, + Payload: rlpdata, + }) + if err != nil { + return err + } + return prw.sendFunc(prw.key, *prw.topic, pmsg) +} + +// Injects a p2p.Msg into the MsgReadWriter, so that it appears on the associated p2p.MsgReader +func (prw *PssReadWriter) injectMsg(msg p2p.Msg) error { + log.Trace(fmt.Sprintf("pssrw injectmsg: %v", msg)) + prw.rw <- msg + return nil +} + +// Convenience object for emulation devp2p over pss +type Protocol struct { + *Pss + proto *p2p.Protocol + topic *Topic + spec *protocols.Spec + pubKeyRWPool map[string]p2p.MsgReadWriter + symKeyRWPool map[string]p2p.MsgReadWriter + Asymmetric bool + Symmetric bool + RWPoolMu sync.Mutex +} + +// Activates devp2p emulation over a specific pss topic +// +// One or both encryption schemes must be specified. If +// only one is specified, the protocol will not be valid +// for the other, and will make the message handler +// return errors +func RegisterProtocol(ps *Pss, topic *Topic, spec *protocols.Spec, targetprotocol *p2p.Protocol, options *ProtocolParams) (*Protocol, error) { + if !options.Asymmetric && !options.Symmetric { + return nil, fmt.Errorf("specify at least one of asymmetric or symmetric messaging mode") + } + pp := &Protocol{ + Pss: ps, + proto: targetprotocol, + topic: topic, + spec: spec, + pubKeyRWPool: make(map[string]p2p.MsgReadWriter), + symKeyRWPool: make(map[string]p2p.MsgReadWriter), + Asymmetric: options.Asymmetric, + Symmetric: options.Symmetric, + } + return pp, nil +} + +// Generic handler for incoming messages over devp2p emulation +// +// To be passed to pss.Register() +// +// Will run the protocol on a new incoming peer, provided that +// the encryption key of the message has a match in the internal +// pss keypool +// +// Fails if protocol is not valid for the message encryption scheme, +// if adding a new peer fails, or if the message is not a serialized +// p2p.Msg (which it always will be if it is sent from this object). +func (p *Protocol) Handle(msg []byte, peer *p2p.Peer, asymmetric bool, keyid string) error { + var vrw *PssReadWriter + if p.Asymmetric != asymmetric && p.Symmetric == !asymmetric { + return fmt.Errorf("invalid protocol encryption") + } else if (!p.isActiveSymKey(keyid, *p.topic) && !asymmetric) || + (!p.isActiveAsymKey(keyid, *p.topic) && asymmetric) { + + rw, err := p.AddPeer(peer, *p.topic, asymmetric, keyid) + if err != nil { + return err + } else if rw == nil { + return fmt.Errorf("handle called on nil MsgReadWriter for new key " + keyid) + } + vrw = rw.(*PssReadWriter) + } + + pmsg, err := ToP2pMsg(msg) + if err != nil { + return fmt.Errorf("could not decode pssmsg") + } + if asymmetric { + if p.pubKeyRWPool[keyid] == nil { + return fmt.Errorf("handle called on nil MsgReadWriter for key " + keyid) + } + vrw = p.pubKeyRWPool[keyid].(*PssReadWriter) + } else { + if p.symKeyRWPool[keyid] == nil { + return fmt.Errorf("handle called on nil MsgReadWriter for key " + keyid) + } + vrw = p.symKeyRWPool[keyid].(*PssReadWriter) + } + vrw.injectMsg(pmsg) + return nil +} + +// check if (peer) symmetric key is currently registered with this topic +func (p *Protocol) isActiveSymKey(key string, topic Topic) bool { + return p.symKeyRWPool[key] != nil +} + +// check if (peer) asymmetric key is currently registered with this topic +func (p *Protocol) isActiveAsymKey(key string, topic Topic) bool { + return p.pubKeyRWPool[key] != nil +} + +// Creates a serialized (non-buffered) version of a p2p.Msg, used in the specialized internal p2p.MsgReadwriter implementations +func ToP2pMsg(msg []byte) (p2p.Msg, error) { + payload := &ProtocolMsg{} + if err := rlp.DecodeBytes(msg, payload); err != nil { + return p2p.Msg{}, fmt.Errorf("pss protocol handler unable to decode payload as p2p message: %v", err) + } + + return p2p.Msg{ + Code: payload.Code, + Size: uint32(len(payload.Payload)), + ReceivedAt: time.Now(), + Payload: bytes.NewBuffer(payload.Payload), + }, nil +} + +// Runs an emulated pss Protocol on the specified peer, +// linked to a specific topic +// `key` and `asymmetric` specifies what encryption key +// to link the peer to. +// The key must exist in the pss store prior to adding the peer. +func (p *Protocol) AddPeer(peer *p2p.Peer, topic Topic, asymmetric bool, key string) (p2p.MsgReadWriter, error) { + rw := &PssReadWriter{ + Pss: p.Pss, + rw: make(chan p2p.Msg), + spec: p.spec, + topic: p.topic, + key: key, + } + if asymmetric { + rw.sendFunc = p.Pss.SendAsym + } else { + rw.sendFunc = p.Pss.SendSym + } + if asymmetric { + if !p.Pss.isPubKeyStored(key) { + return nil, fmt.Errorf("asym key does not exist: %s", key) + } + p.RWPoolMu.Lock() + p.pubKeyRWPool[key] = rw + p.RWPoolMu.Unlock() + } else { + if !p.Pss.isSymKeyStored(key) { + return nil, fmt.Errorf("symkey does not exist: %s", key) + } + p.RWPoolMu.Lock() + p.symKeyRWPool[key] = rw + p.RWPoolMu.Unlock() + } + go func() { + err := p.proto.Run(peer, rw) + log.Warn(fmt.Sprintf("pss vprotocol quit on %v topic %v: %v", peer, topic, err)) + }() + return rw, nil +} + +func (p *Protocol) RemovePeer(asymmetric bool, key string) { + log.Debug("closing pss peer", "asym", asymmetric, "key", key) + p.RWPoolMu.Lock() + defer p.RWPoolMu.Unlock() + if asymmetric { + rw := p.pubKeyRWPool[key].(*PssReadWriter) + rw.closed = true + delete(p.pubKeyRWPool, key) + } else { + rw := p.symKeyRWPool[key].(*PssReadWriter) + rw.closed = true + delete(p.symKeyRWPool, key) + } +} + +// Uniform translation of protocol specifiers to topic +func ProtocolTopic(spec *protocols.Spec) Topic { + return BytesToTopic([]byte(fmt.Sprintf("%s:%d", spec.Name, spec.Version))) +} diff --git a/swarm/pss/protocol_none.go b/swarm/pss/protocol_none.go new file mode 100644 index 0000000000..c92be3f902 --- /dev/null +++ b/swarm/pss/protocol_none.go @@ -0,0 +1,23 @@ +// 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 nopssprotocol + +package pss + +const ( + IsActiveProtocol = false +) diff --git a/swarm/pss/protocol_test.go b/swarm/pss/protocol_test.go new file mode 100644 index 0000000000..520c48a202 --- /dev/null +++ b/swarm/pss/protocol_test.go @@ -0,0 +1,164 @@ +// 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 pss + +import ( + "bytes" + "context" + "fmt" + "strconv" + "strings" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/swarm/log" +) + +type protoCtrl struct { + C chan bool + protocol *Protocol + run func(*p2p.Peer, p2p.MsgReadWriter) error +} + +// simple ping pong protocol test for the pss devp2p emulation +func TestProtocol(t *testing.T) { + t.Run("32", testProtocol) + t.Run("8", testProtocol) + t.Run("0", testProtocol) +} + +func testProtocol(t *testing.T) { + + // address hint size + var addrsize int64 + paramstring := strings.Split(t.Name(), "/") + addrsize, _ = strconv.ParseInt(paramstring[1], 10, 0) + log.Info("protocol test", "addrsize", addrsize) + + topic := PingTopic.String() + + clients, err := setupNetwork(2, false) + if err != nil { + t.Fatal(err) + } + var loaddrhex string + err = clients[0].Call(&loaddrhex, "pss_baseAddr") + if err != nil { + t.Fatalf("rpc get node 1 baseaddr fail: %v", err) + } + loaddrhex = loaddrhex[:2+(addrsize*2)] + var roaddrhex string + err = clients[1].Call(&roaddrhex, "pss_baseAddr") + if err != nil { + t.Fatalf("rpc get node 2 baseaddr fail: %v", err) + } + roaddrhex = roaddrhex[:2+(addrsize*2)] + lnodeinfo := &p2p.NodeInfo{} + err = clients[0].Call(&lnodeinfo, "admin_nodeInfo") + if err != nil { + t.Fatalf("rpc nodeinfo node 11 fail: %v", err) + } + + var lpubkey string + err = clients[0].Call(&lpubkey, "pss_getPublicKey") + if err != nil { + t.Fatalf("rpc get node 1 pubkey fail: %v", err) + } + var rpubkey string + err = clients[1].Call(&rpubkey, "pss_getPublicKey") + if err != nil { + t.Fatalf("rpc get node 2 pubkey fail: %v", err) + } + + time.Sleep(time.Millisecond * 1000) // replace with hive healthy code + + 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, false, false) + if err != nil { + t.Fatal(err) + } + defer lsub.Unsubscribe() + 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, false, false) + if err != nil { + t.Fatal(err) + } + defer rsub.Unsubscribe() + + // set reciprocal public keys + err = clients[0].Call(nil, "pss_setPeerPublicKey", rpubkey, topic, roaddrhex) + if err != nil { + t.Fatal(err) + } + err = clients[1].Call(nil, "pss_setPeerPublicKey", lpubkey, topic, loaddrhex) + if err != nil { + t.Fatal(err) + } + + // add right peer's public key as protocol peer on left + p := p2p.NewPeer(enode.ID{}, fmt.Sprintf("%x", common.FromHex(loaddrhex)), []p2p.Cap{}) + _, err = pssprotocols[lnodeinfo.ID].protocol.AddPeer(p, PingTopic, true, rpubkey) + if err != nil { + t.Fatal(err) + } + + // sends ping asym, checks delivery + pssprotocols[lnodeinfo.ID].C <- false + select { + case <-lmsgC: + log.Debug("lnode ok") + case cerr := <-lctx.Done(): + t.Fatalf("test message timed out: %v", cerr) + return + } + select { + case <-rmsgC: + log.Debug("rnode ok") + case cerr := <-lctx.Done(): + t.Fatalf("test message timed out: %v", cerr) + } + + // sends ping asym, checks delivery + pssprotocols[lnodeinfo.ID].C <- false + select { + case <-lmsgC: + log.Debug("lnode ok") + case cerr := <-lctx.Done(): + t.Fatalf("test message timed out: %v", cerr) + } + select { + case <-rmsgC: + log.Debug("rnode ok") + case cerr := <-lctx.Done(): + t.Fatalf("test message timed out: %v", cerr) + } + rw := pssprotocols[lnodeinfo.ID].protocol.pubKeyRWPool[rpubkey] + pssprotocols[lnodeinfo.ID].protocol.RemovePeer(true, rpubkey) + if err := rw.WriteMsg(p2p.Msg{ + Size: 3, + Payload: bytes.NewReader([]byte("foo")), + }); err == nil { + t.Fatalf("expected error on write") + } +} diff --git a/swarm/pss/pss.go b/swarm/pss/pss.go new file mode 100644 index 0000000000..0a8d757d8a --- /dev/null +++ b/swarm/pss/pss.go @@ -0,0 +1,860 @@ +// 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 pss + +import ( + "bytes" + "context" + "crypto/ecdsa" + "crypto/rand" + "errors" + "fmt" + "hash" + "sync" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "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/rpc" + "github.com/ethereum/go-ethereum/swarm/log" + "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/whisperv6" + "golang.org/x/crypto/sha3" +) + +const ( + defaultPaddingByteSize = 16 + DefaultMsgTTL = time.Second * 120 + defaultDigestCacheTTL = time.Second * 10 + defaultSymKeyCacheCapacity = 512 + digestLength = 32 // byte length of digest used for pss cache (currently same as swarm chunk hash) + defaultWhisperWorkTime = 3 + defaultWhisperPoW = 0.0000000001 + defaultMaxMsgSize = 1024 * 1024 + defaultCleanInterval = time.Second * 60 * 10 + defaultOutboxCapacity = 100000 + pssProtocolName = "pss" + pssVersion = 2 + hasherCount = 8 +) + +var ( + addressLength = len(pot.Address{}) +) + +// cache is used for preventing backwards routing +// will also be instrumental in flood guard mechanism +// and mailbox implementation +type pssCacheEntry struct { + expiresAt time.Time +} + +// abstraction to enable access to p2p.protocols.Peer.Send +type senderPeer interface { + Info() *p2p.PeerInfo + ID() enode.ID + Address() []byte + Send(context.Context, interface{}) error +} + +// per-key peer related information +// member `protected` prevents garbage collection of the instance +type pssPeer struct { + lastSeen time.Time + address PssAddress + protected bool +} + +// Pss configuration parameters +type PssParams struct { + MsgTTL time.Duration + CacheTTL time.Duration + privateKey *ecdsa.PrivateKey + SymKeyCacheCapacity int + AllowRaw bool // If true, enables sending and receiving messages without builtin pss encryption +} + +// Sane defaults for Pss +func NewPssParams() *PssParams { + return &PssParams{ + MsgTTL: DefaultMsgTTL, + CacheTTL: defaultDigestCacheTTL, + SymKeyCacheCapacity: defaultSymKeyCacheCapacity, + } +} + +func (params *PssParams) WithPrivateKey(privatekey *ecdsa.PrivateKey) *PssParams { + params.privateKey = privatekey + return params +} + +// Toplevel pss object, takes care of message sending, receiving, decryption and encryption, message handler dispatchers and message forwarding. +// +// Implements node.Service +type Pss struct { + *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 + fwdPoolMu sync.RWMutex + fwdCache map[pssDigest]pssCacheEntry // checksum of unique fields from pssmsg mapped to expiry, cache to determine whether to drop msg + fwdCacheMu sync.RWMutex + cacheTTL time.Duration // how long to keep messages in fwdCache (not implemented) + msgTTL time.Duration + paddingByteSize int + capstring string + outbox chan *PssMsg + + // message handling + 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{} +} + +func (p *Pss) String() string { + return fmt.Sprintf("pss: addr %x, pubkey %v", p.BaseAddr(), common.ToHex(crypto.FromECDSAPub(&p.privateKey.PublicKey))) +} + +// Creates a new Pss instance. +// +// In addition to params, it takes a swarm network Kademlia +// and a FileStore storage for message cache storage. +func NewPss(k *network.Kademlia, params *PssParams) (*Pss, error) { + if params.privateKey == nil { + return nil, errors.New("missing private key for pss") + } + cap := p2p.Cap{ + Name: pssProtocolName, + Version: pssVersion, + } + ps := &Pss{ + Kademlia: k, + KeyStore: loadKeyStore(), + + privateKey: params.privateKey, + quitC: make(chan struct{}), + + fwdPool: make(map[string]*protocols.Peer), + fwdCache: make(map[pssDigest]pssCacheEntry), + cacheTTL: params.CacheTTL, + msgTTL: params.MsgTTL, + paddingByteSize: defaultPaddingByteSize, + capstring: cap.String(), + outbox: make(chan *PssMsg, defaultOutboxCapacity), + + handlers: make(map[Topic]map[*handler]bool), + topicHandlerCaps: make(map[Topic]*handlerCaps), + + hashPool: sync.Pool{ + New: func() interface{} { + return sha3.NewLegacyKeccak256() + }, + }, + } + + for i := 0; i < hasherCount; i++ { + hashfunc := storage.MakeHashFunc(storage.DefaultHash)() + ps.hashPool.Put(hashfunc) + } + + return ps, nil +} + +///////////////////////////////////////////////////////////////////// +// SECTION: node.Service interface +///////////////////////////////////////////////////////////////////// + +func (p *Pss) Start(srv *p2p.Server) error { + go func() { + ticker := time.NewTicker(defaultCleanInterval) + cacheTicker := time.NewTicker(p.cacheTTL) + defer ticker.Stop() + defer cacheTicker.Stop() + for { + select { + case <-cacheTicker.C: + p.cleanFwdCache() + case <-ticker.C: + p.cleanKeys() + case <-p.quitC: + return + } + } + }() + go func() { + for { + select { + case msg := <-p.outbox: + err := p.forward(msg) + if err != nil { + log.Error(err.Error()) + metrics.GetOrRegisterCounter("pss.forward.err", nil).Inc(1) + } + case <-p.quitC: + return + } + } + }() + log.Info("Started Pss") + log.Info("Loaded EC keys", "pubkey", common.ToHex(crypto.FromECDSAPub(p.PublicKey())), "secp256", common.ToHex(crypto.CompressPubkey(p.PublicKey()))) + return nil +} + +func (p *Pss) Stop() error { + log.Info("Pss shutting down") + close(p.quitC) + return nil +} + +var pssSpec = &protocols.Spec{ + Name: pssProtocolName, + Version: pssVersion, + MaxMsgSize: defaultMaxMsgSize, + Messages: []interface{}{ + PssMsg{}, + }, +} + +func (p *Pss) Protocols() []p2p.Protocol { + return []p2p.Protocol{ + { + Name: pssSpec.Name, + Version: pssSpec.Version, + Length: pssSpec.Length(), + Run: p.Run, + }, + } +} + +func (p *Pss) Run(peer *p2p.Peer, rw p2p.MsgReadWriter) error { + pp := protocols.NewPeer(peer, rw, pssSpec) + p.fwdPoolMu.Lock() + p.fwdPool[peer.Info().ID] = pp + p.fwdPoolMu.Unlock() + return pp.Run(p.handlePssMsg) +} + +func (p *Pss) APIs() []rpc.API { + apis := []rpc.API{ + { + Namespace: "pss", + Version: "1.0", + Service: NewAPI(p), + Public: true, + }, + } + apis = append(apis, p.auxAPIs...) + return apis +} + +// add API methods to the pss API +// must be run before node is started +func (p *Pss) addAPI(api rpc.API) { + p.auxAPIs = append(p.auxAPIs, api) +} + +// Returns the swarm Kademlia address of the pss node +func (p *Pss) BaseAddr() []byte { + return p.Kademlia.BaseAddr() +} + +// Returns the pss node's public key +func (p *Pss) PublicKey() *ecdsa.PublicKey { + return &p.privateKey.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 +// topic specified will be passed to the given Handler function. +// +// There may be an arbitrary number of handler functions per topic. +// +// Returns a deregister function which needs to be called to +// deregister the handler, +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) + p.handlers[*topic] = handlers + log.Debug("registered handler", "capabilities", hndlr.caps) + } + 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, hndlr *handler) { + p.handlersMu.Lock() + defer p.handlersMu.Unlock() + handlers := p.handlers[*topic] + 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, hndlr) +} + +// Filters incoming messages for processing or forwarding. +// Check if address partially matches +// If yes, it CAN be for us, and we process it +// 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)) + return nil + } + if p.checkFwdCache(pssmsg) { + log.Trace("pss relay block-cache match (process)", "from", common.ToHex(p.Kademlia.BaseAddr()), "to", (common.ToHex(pssmsg.To))) + return nil + } + p.addFwdCache(pssmsg) + + 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 was for someone else :'( ... 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()), "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, 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 asymmetric bool + var keyid string + var keyFunc func(envelope *whisper.Envelope) (*whisper.ReceivedMessage, string, PssAddress, error) + + envelope := pssmsg.Payload + psstopic := Topic(envelope.Topic) + + if raw { + payload = pssmsg.Payload.Data + } else { + if pssmsg.isSym() { + keyFunc = p.processSym + } else { + asymmetric = true + keyFunc = p.processAsym + } + + recvmsg, keyid, from, err = keyFunc(envelope) + if err != nil { + return errors.New("Decryption failed") + } + payload = recvmsg.Payload + } + + if len(pssmsg.To) < addressLength { + if err := p.enqueue(pssmsg); err != nil { + return err + } + } + p.executeHandlers(psstopic, payload, from, raw, prox, asymmetric, keyid) + + return nil +} + +// 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 _, 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 failed", "err", err) + } + } +} + +// will return false if using partial address +func (p *Pss) isSelfRecipient(msg *PssMsg) bool { + return bytes.Equal(msg.To, p.Kademlia.BaseAddr()) +} + +// test match of leftmost bytes in given message to node's Kademlia address +func (p *Pss) isSelfPossibleRecipient(msg *PssMsg, prox bool) bool { + local := p.Kademlia.BaseAddr() + + // 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)]) { + + return true + } else if !prox { + return false + } + + depth := p.Kademlia.NeighbourhoodDepth() + po, _ := network.Pof(p.Kademlia.BaseAddr(), msg.To, 0) + log.Trace("selfpossible", "po", po, "depth", depth) + + return depth <= po +} + +///////////////////////////////////////////////////////////////////// +// SECTION: Message sending +///////////////////////////////////////////////////////////////////// + +func (p *Pss) enqueue(msg *PssMsg) error { + select { + case p.outbox <- msg: + return nil + default: + } + + metrics.GetOrRegisterCounter("pss.enqueue.outbox.full", nil).Inc(1) + return errors.New("outbox full") +} + +// Send a raw message (any encryption is responsibility of calling client) +// +// Will fail if raw messages are disallowed +func (p *Pss) SendRaw(address PssAddress, topic Topic, msg []byte) error { + if err := validateAddress(address); err != nil { + return err + } + pssMsgParams := &msgParams{ + raw: true, + } + payload := &whisper.Envelope{ + Data: msg, + Topic: whisper.TopicType(topic), + } + pssMsg := newPssMsg(pssMsgParams) + pssMsg.To = address + pssMsg.Expire = uint32(time.Now().Add(p.msgTTL).Unix()) + pssMsg.Payload = payload + p.addFwdCache(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 +// +// Fails if the key id does not match any of the stored symmetric keys +func (p *Pss) SendSym(symkeyid string, topic Topic, msg []byte) error { + symkey, err := p.GetSymmetricKey(symkeyid) + if err != nil { + return fmt.Errorf("missing valid send symkey %s: %v", symkeyid, err) + } + psp, ok := p.getPeerSym(symkeyid, topic) + if !ok { + return fmt.Errorf("invalid topic '%s' for symkey '%s'", topic.String(), symkeyid) + } + return p.send(psp.address, topic, msg, false, symkey) +} + +// Send a message using asymmetric encryption +// +// Fails if the key id does not match any in of the stored public keys +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) + } + psp, ok := p.getPeerPub(pubkeyid, topic) + if !ok { + return fmt.Errorf("invalid topic '%s' for pubkey '%s'", topic.String(), pubkeyid) + } + return p.send(psp.address, topic, msg, true, common.FromHex(pubkeyid)) +} + +// Send is payload agnostic, and will accept any byte slice as payload +// It generates an whisper envelope for the specified recipient and topic, +// and wraps the message payload in it. +// TODO: Implement proper message padding +func (p *Pss) send(to []byte, topic Topic, msg []byte, asymmetric bool, key []byte) error { + metrics.GetOrRegisterCounter("pss.send", nil).Inc(1) + + if key == nil || bytes.Equal(key, []byte{}) { + return fmt.Errorf("Zero length key passed to pss send") + } + padding := make([]byte, p.paddingByteSize) + c, err := rand.Read(padding) + if err != nil { + return err + } else if c < p.paddingByteSize { + return fmt.Errorf("invalid padding length: %d", c) + } + wparams := &whisper.MessageParams{ + TTL: defaultWhisperTTL, + Src: p.privateKey, + Topic: whisper.TopicType(topic), + WorkTime: defaultWhisperWorkTime, + PoW: defaultWhisperPoW, + Payload: msg, + Padding: padding, + } + if asymmetric { + pk, err := crypto.UnmarshalPubkey(key) + if err != nil { + return fmt.Errorf("Cannot unmarshal pubkey: %x", key) + } + wparams.Dst = pk + } else { + wparams.KeySym = key + } + // set up outgoing message container, which does encryption and envelope wrapping + woutmsg, err := whisper.NewSentMessage(wparams) + if err != nil { + return fmt.Errorf("failed to generate whisper message encapsulation: %v", err) + } + // performs encryption. + // Does NOT perform / performs negligible PoW due to very low difficulty setting + // after this the message is ready for sending + envelope, err := woutmsg.Wrap(wparams) + if err != nil { + return fmt.Errorf("failed to perform whisper encryption: %v", err) + } + log.Trace("pssmsg whisper done", "env", envelope, "wparams payload", common.ToHex(wparams.Payload), "to", common.ToHex(to), "asym", asymmetric, "key", common.ToHex(key)) + + // prepare for devp2p transport + pssMsgParams := &msgParams{ + sym: !asymmetric, + } + pssMsg := newPssMsg(pssMsgParams) + pssMsg.To = to + pssMsg.Expire = uint32(time.Now().Add(p.msgTTL).Unix()) + pssMsg.Payload = envelope + 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 +} + +// 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() + + // 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 + + // 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 + } + } + 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 { + metrics.GetOrRegisterCounter("pss.forward.enqueue.error", nil).Inc(1) + log.Error(err.Error()) + return err + } + } + + // cache the message + p.addFwdCache(msg) + return nil +} + +///////////////////////////////////////////////////////////////////// +// SECTION: Caching +///////////////////////////////////////////////////////////////////// + +// cleanFwdCache is used to periodically remove expired entries from the forward cache +func (p *Pss) cleanFwdCache() { + metrics.GetOrRegisterCounter("pss.cleanfwdcache", nil).Inc(1) + p.fwdCacheMu.Lock() + defer p.fwdCacheMu.Unlock() + for k, v := range p.fwdCache { + if v.expiresAt.Before(time.Now()) { + delete(p.fwdCache, k) + } + } +} + +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) + + var entry pssCacheEntry + var ok bool + + p.fwdCacheMu.Lock() + defer p.fwdCacheMu.Unlock() + + digest := p.digest(msg) + if entry, ok = p.fwdCache[digest]; !ok { + entry = pssCacheEntry{} + } + entry.expiresAt = time.Now().Add(p.cacheTTL) + p.fwdCache[digest] = entry + return nil +} + +// check if message is in the cache +func (p *Pss) checkFwdCache(msg *PssMsg) bool { + p.fwdCacheMu.Lock() + defer p.fwdCacheMu.Unlock() + + digest := p.digest(msg) + entry, ok := p.fwdCache[digest] + if ok { + if entry.expiresAt.After(time.Now()) { + log.Trace("unexpired cache", "digest", fmt.Sprintf("%x", digest)) + metrics.GetOrRegisterCounter("pss.checkfwdcache.unexpired", nil).Inc(1) + return true + } + metrics.GetOrRegisterCounter("pss.checkfwdcache.expired", nil).Inc(1) + } + return false +} + +// Digest of message +func (p *Pss) digest(msg *PssMsg) pssDigest { + 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) + 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/swarm/pss/pss_test.go b/swarm/pss/pss_test.go new file mode 100644 index 0000000000..ea7a591b1e --- /dev/null +++ b/swarm/pss/pss_test.go @@ -0,0 +1,2092 @@ +// 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 pss + +import ( + "bytes" + "context" + "crypto/ecdsa" + "encoding/binary" + "encoding/hex" + "encoding/json" + "flag" + "fmt" + "io/ioutil" + "math/rand" + "os" + "strconv" + "strings" + "sync" + "testing" + "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/node" + "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/p2p/simulations" + "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/whisperv6" +) + +var ( + 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() { + flag.Parse() + rand.Seed(time.Now().Unix()) + + adapters.RegisterServices(newServices(false)) + initTest() +} + +func initTest() { + initOnce.Do( + func() { + psslogmain = log.New("psslog", "*") + hs := log.StreamHandler(os.Stderr, log.TerminalFormat(true)) + hf := log.LvlFilterHandler(log.Lvl(*loglevel), hs) + h := log.CallerFileHandler(hf) + log.Root().SetHandler(h) + + w = whisper.New(&whisper.DefaultConfig) + wapi = whisper.NewPublicWhisperAPI(w) + + pssprotocols = make(map[string]*protoCtrl) + }, + ) +} + +// test that topic conversion functions give predictable results +func TestTopic(t *testing.T) { + + api := &API{} + + topicstr := strings.Join([]string{PingProtocol.Name, strconv.Itoa(int(PingProtocol.Version))}, ":") + + // bytestotopic is the authoritative topic conversion source + topicobj := BytesToTopic([]byte(topicstr)) + + // string to topic and bytes to topic must match + topicapiobj, _ := api.StringToTopic(topicstr) + if topicobj != topicapiobj { + t.Fatalf("bytes and string topic conversion mismatch; %s != %s", topicobj, topicapiobj) + } + + // string representation of topichex + topichex := topicobj.String() + + // protocoltopic wrapper on pingtopic should be same as topicstring + // check that it matches + pingtopichex := PingTopic.String() + if topichex != pingtopichex { + t.Fatalf("protocol topic conversion mismatch; %s != %s", topichex, pingtopichex) + } + + // json marshal of topic + topicjsonout, err := topicobj.MarshalJSON() + if err != nil { + t.Fatal(err) + } + if string(topicjsonout)[1:len(topicjsonout)-1] != topichex { + t.Fatalf("topic json marshal mismatch; %s != \"%s\"", topicjsonout, topichex) + } + + // json unmarshal of topic + var topicjsonin Topic + topicjsonin.UnmarshalJSON(topicjsonout) + if topicjsonin != topicobj { + t.Fatalf("topic json unmarshal mismatch: %x != %x", topicjsonin, topicobj) + } +} + +// test bit packing of message control flags +func TestMsgParams(t *testing.T) { + var ctrl byte + ctrl |= pssControlRaw + p := newMsgParamsFromBytes([]byte{ctrl}) + m := newPssMsg(p) + if !m.isRaw() || m.isSym() { + t.Fatal("expected raw=true and sym=false") + } + ctrl |= pssControlSym + p = newMsgParamsFromBytes([]byte{ctrl}) + m = newPssMsg(p) + if !m.isRaw() || !m.isSym() { + t.Fatal("expected raw=true and sym=true") + } + ctrl &= 0xff &^ pssControlRaw + p = newMsgParamsFromBytes([]byte{ctrl}) + m = newPssMsg(p) + if m.isRaw() || !m.isSym() { + t.Fatal("expected raw=false and sym=true") + } +} + +// test if we can insert into cache, match items with cache and cache expiry +func TestCache(t *testing.T) { + var err error + to, _ := hex.DecodeString("08090a0b0c0d0e0f1011121314150001020304050607161718191a1b1c1d1e1f") + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + keys, err := wapi.NewKeyPair(ctx) + privkey, err := w.GetPrivateKey(keys) + if err != nil { + t.Fatal(err) + } + ps := newTestPss(privkey, nil, nil) + defer ps.Stop() + pp := NewPssParams().WithPrivateKey(privkey) + data := []byte("foo") + datatwo := []byte("bar") + datathree := []byte("baz") + wparams := &whisper.MessageParams{ + TTL: defaultWhisperTTL, + Src: privkey, + Dst: &privkey.PublicKey, + Topic: whisper.TopicType(PingTopic), + WorkTime: defaultWhisperWorkTime, + PoW: defaultWhisperPoW, + Payload: data, + } + woutmsg, err := whisper.NewSentMessage(wparams) + env, err := woutmsg.Wrap(wparams) + msg := &PssMsg{ + Payload: env, + To: to, + } + wparams.Payload = datatwo + woutmsg, err = whisper.NewSentMessage(wparams) + envtwo, err := woutmsg.Wrap(wparams) + msgtwo := &PssMsg{ + Payload: envtwo, + To: to, + } + wparams.Payload = datathree + woutmsg, err = whisper.NewSentMessage(wparams) + envthree, err := woutmsg.Wrap(wparams) + msgthree := &PssMsg{ + Payload: envthree, + To: to, + } + + digest := ps.digest(msg) + if err != nil { + t.Fatalf("could not store cache msgone: %v", err) + } + digesttwo := ps.digest(msgtwo) + if err != nil { + t.Fatalf("could not store cache msgtwo: %v", err) + } + digestthree := ps.digest(msgthree) + if err != nil { + t.Fatalf("could not store cache msgthree: %v", err) + } + + if digest == digesttwo { + t.Fatalf("different msgs return same hash: %d", digesttwo) + } + + // check the cache + err = ps.addFwdCache(msg) + if err != nil { + t.Fatalf("write to pss expire cache failed: %v", err) + } + + if !ps.checkFwdCache(msg) { + t.Fatalf("message %v should have EXPIRE record in cache but checkCache returned false", msg) + } + + if ps.checkFwdCache(msgtwo) { + t.Fatalf("message %v should NOT have EXPIRE record in cache but checkCache returned true", msgtwo) + } + + time.Sleep(pp.CacheTTL + 1*time.Second) + err = ps.addFwdCache(msgthree) + if err != nil { + t.Fatalf("write to pss expire cache failed: %v", err) + } + + if ps.checkFwdCache(msg) { + t.Fatalf("message %v should have expired from cache but checkCache returned true", msg) + } + + if _, ok := ps.fwdCache[digestthree]; !ok { + t.Fatalf("unexpired message should be in the cache: %v", digestthree) + } + + if _, ok := ps.fwdCache[digesttwo]; ok { + t.Fatalf("expired message should have been cleared from the cache: %v", digesttwo) + } +} + +// matching of address hints; whether a message could be or is for the node +func TestAddressMatch(t *testing.T) { + + localaddr := network.RandomAddr().Over() + copy(localaddr[:8], []byte("deadbeef")) + remoteaddr := []byte("feedbeef") + kadparams := network.NewKadParams() + kad := network.NewKademlia(localaddr, kadparams) + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + keys, err := wapi.NewKeyPair(ctx) + if err != nil { + t.Fatalf("Could not generate private key: %v", err) + } + privkey, err := w.GetPrivateKey(keys) + pssp := NewPssParams().WithPrivateKey(privkey) + ps, err := NewPss(kad, pssp) + if err != nil { + t.Fatal(err.Error()) + } + + pssmsg := &PssMsg{ + To: remoteaddr, + } + + // differ from first byte + if ps.isSelfRecipient(pssmsg) { + t.Fatalf("isSelfRecipient true but %x != %x", remoteaddr, localaddr) + } + if ps.isSelfPossibleRecipient(pssmsg, false) { + t.Fatalf("isSelfPossibleRecipient true but %x != %x", remoteaddr[:8], localaddr[:8]) + } + + // 8 first bytes same + copy(remoteaddr[:4], localaddr[:4]) + if ps.isSelfRecipient(pssmsg) { + t.Fatalf("isSelfRecipient true but %x != %x", remoteaddr, localaddr) + } + if !ps.isSelfPossibleRecipient(pssmsg, false) { + t.Fatalf("isSelfPossibleRecipient false but %x == %x", remoteaddr[:8], localaddr[:8]) + } + + // all bytes same + pssmsg.To = localaddr + if !ps.isSelfRecipient(pssmsg) { + t.Fatalf("isSelfRecipient false but %x == %x", remoteaddr, localaddr) + } + 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") + } +} + +// 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 + privkey, err := crypto.GenerateKey() + if err != nil { + t.Fatal(err.Error()) + } + + addr := make([]byte, 32) + addr[0] = 0x01 + ps := newTestPss(privkey, network.NewKademlia(addr, network.NewKadParams()), NewPssParams()) + defer ps.Stop() + + // message should pass + 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()) + } + tmr := time.NewTimer(time.Millisecond * 100) + var outmsg *PssMsg + select { + case outmsg = <-ps.outbox: + case <-tmr.C: + default: + } + if outmsg != nil { + t.Fatalf("expected outbox empty after full address on msg, but had message %s", msg) + } + + // message should pass and queue due to partial length + msg.To = addr[0:1] + msg.Payload.Data = []byte{0x78, 0x79, 0x80, 0x80, 0x79} + if err := ps.handlePssMsg(context.TODO(), msg); err != nil { + t.Fatal(err.Error()) + } + tmr.Reset(time.Millisecond * 100) + outmsg = nil + select { + case outmsg = <-ps.outbox: + case <-tmr.C: + } + if outmsg == nil { + t.Fatal("expected message in outbox on encrypt fail, but empty") + } + outmsg = nil + select { + case outmsg = <-ps.outbox: + default: + } + if outmsg != nil { + t.Fatalf("expected only one queued message but also had message %v", msg) + } + + // full address mismatch should put message in queue + msg.To[0] = 0xff + if err := ps.handlePssMsg(context.TODO(), msg); err != nil { + t.Fatal(err.Error()) + } + tmr.Reset(time.Millisecond * 10) + outmsg = nil + select { + case outmsg = <-ps.outbox: + case <-tmr.C: + } + if outmsg == nil { + t.Fatal("expected message in outbox on address mismatch, but empty") + } + outmsg = nil + select { + case outmsg = <-ps.outbox: + default: + } + if outmsg != nil { + t.Fatalf("expected only one queued message but also had message %v", msg) + } + + // expired message should be dropped + msg.Expire = uint32(time.Now().Add(-time.Second).Unix()) + if err := ps.handlePssMsg(context.TODO(), msg); err != nil { + t.Fatal(err.Error()) + } + tmr.Reset(time.Millisecond * 10) + outmsg = nil + select { + case outmsg = <-ps.outbox: + case <-tmr.C: + default: + } + if outmsg != nil { + t.Fatalf("expected empty queue but have message %v", msg) + } + + // invalid message should return error + fckedupmsg := &struct { + pssMsg *PssMsg + }{ + pssMsg: &PssMsg{}, + } + if err := ps.handlePssMsg(context.TODO(), fckedupmsg); err == nil { + t.Fatalf("expected error from processMsg but error nil") + } + + // outbox full should return error + msg.Expire = uint32(time.Now().Add(time.Second * 60).Unix()) + for i := 0; i < defaultOutboxCapacity; i++ { + ps.outbox <- msg + } + msg.Payload.Data = []byte{0x62, 0x61, 0x72} + err = ps.handlePssMsg(context.TODO(), msg) + if err == nil { + t.Fatal("expected error when mailbox full, but was nil") + } +} + +// set and generate pubkeys and symkeys +func TestKeys(t *testing.T) { + // make our key and init pss with it + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + ourkeys, err := wapi.NewKeyPair(ctx) + if err != nil { + t.Fatalf("create 'our' key fail") + } + ctx, cancel2 := context.WithTimeout(context.Background(), time.Second) + defer cancel2() + theirkeys, err := wapi.NewKeyPair(ctx) + if err != nil { + t.Fatalf("create 'their' key fail") + } + ourprivkey, err := w.GetPrivateKey(ourkeys) + if err != nil { + t.Fatalf("failed to retrieve 'our' private key") + } + theirprivkey, err := w.GetPrivateKey(theirkeys) + if err != nil { + 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) + 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) + if err != nil { + t.Fatalf("failed to set 'our' incoming symmetric key") + } + + // get the key back from whisper, check that it's still the same + outkeyback, err := ps.w.GetSymKey(outkeyid) + if err != nil { + t.Fatalf(err.Error()) + } + inkey, err := ps.w.GetSymKey(inkeyid) + if err != nil { + t.Fatalf(err.Error()) + } + if !bytes.Equal(outkeyback, outkey) { + t.Fatalf("passed outgoing symkey doesnt equal stored: %x / %x", outkey, outkeyback) + } + + t.Logf("symout: %v", outkeyback) + t.Logf("symin: %v", inkey) + + // check that the key is stored in the peerpool + psp := ps.symKeyPool[inkeyid][topicobj] + 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() + if err != nil { + t.Fatal(err) + } + ps := newTestPss(privkey, nil, nil) + defer ps.Stop() + + peeraddr := network.RandomAddr().Over() + topicaddr := make(map[Topic]PssAddress) + topicaddr[Topic{0x13}] = peeraddr + topicaddr[Topic{0x2a}] = peeraddr[:16] + topicaddr[Topic{0x02, 0x9a}] = []byte{} + + remoteprivkey, err := crypto.GenerateKey() + if err != nil { + t.Fatal(err) + } + remotepubkeybytes := crypto.FromECDSAPub(&remoteprivkey.PublicKey) + remotepubkeyhex := common.ToHex(remotepubkeybytes) + + pssapi := NewAPI(ps) + + for to, a := range topicaddr { + err = pssapi.SetPeerPublicKey(remotepubkeybytes, to, a) + if err != nil { + t.Fatal(err) + } + } + + intopic, err := pssapi.GetPeerTopics(remotepubkeyhex) + if err != nil { + t.Fatal(err) + } + +OUTER: + for _, tnew := range intopic { + for torig, addr := range topicaddr { + if bytes.Equal(torig[:], tnew[:]) { + inaddr, err := pssapi.GetPeerAddress(remotepubkeyhex, torig) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(addr, inaddr) { + t.Fatalf("Address mismatch for topic %x; got %x, expected %x", torig, inaddr, addr) + } + delete(topicaddr, torig) + continue OUTER + } + } + t.Fatalf("received topic %x did not match any existing topics", tnew) + } + + if len(topicaddr) != 0 { + t.Fatalf("%d topics were not matched", len(topicaddr)) + } +} + +// forwarding should skip peers that do not have matching pss capabilities +func TestPeerCapabilityMismatch(t *testing.T) { + + // create privkey for forwarder node + privkey, err := crypto.GenerateKey() + if err != nil { + t.Fatal(err) + } + + // initialize kad + baseaddr := network.RandomAddr() + kad := network.NewKademlia((baseaddr).Over(), network.NewKadParams()) + rw := &p2p.MsgPipeRW{} + + // one peer has a mismatching version of pss + wrongpssaddr := network.RandomAddr() + wrongpsscap := p2p.Cap{ + Name: pssProtocolName, + Version: 0, + } + nid := enode.ID{0x01} + wrongpsspeer := network.NewPeer(&network.BzzPeer{ + Peer: protocols.NewPeer(p2p.NewPeer(nid, common.ToHex(wrongpssaddr.Over()), []p2p.Cap{wrongpsscap}), rw, nil), + BzzAddr: &network.BzzAddr{OAddr: wrongpssaddr.Over(), UAddr: nil}, + }, kad) + + // one peer doesn't even have pss (boo!) + nopssaddr := network.RandomAddr() + nopsscap := p2p.Cap{ + Name: "nopss", + Version: 1, + } + nid = enode.ID{0x02} + nopsspeer := network.NewPeer(&network.BzzPeer{ + Peer: protocols.NewPeer(p2p.NewPeer(nid, common.ToHex(nopssaddr.Over()), []p2p.Cap{nopsscap}), rw, nil), + BzzAddr: &network.BzzAddr{OAddr: nopssaddr.Over(), UAddr: nil}, + }, kad) + + // add peers to kademlia and activate them + // it's safe so don't check errors + kad.Register(wrongpsspeer.BzzAddr) + kad.On(wrongpsspeer) + kad.Register(nopsspeer.BzzAddr) + kad.On(nopsspeer) + + // create pss + pssmsg := &PssMsg{ + To: []byte{}, + Expire: uint32(time.Now().Add(time.Second).Unix()), + 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 + ps.forward(pssmsg) + +} + +// 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) + t.Run("0", testSendRaw) +} + +func testSendRaw(t *testing.T) { + + var addrsize int64 + var err error + + paramstring := strings.Split(t.Name(), "/") + + addrsize, _ = strconv.ParseInt(paramstring[1], 10, 0) + log.Info("raw send test", "addrsize", addrsize) + + clients, err := setupNetwork(2, true) + if err != nil { + t.Fatal(err) + } + + topic := "0xdeadbeef" + + var loaddrhex string + err = clients[0].Call(&loaddrhex, "pss_baseAddr") + if err != nil { + t.Fatalf("rpc get node 1 baseaddr fail: %v", err) + } + loaddrhex = loaddrhex[:2+(addrsize*2)] + var roaddrhex string + err = clients[1].Call(&roaddrhex, "pss_baseAddr") + if err != nil { + t.Fatalf("rpc get node 2 baseaddr fail: %v", err) + } + roaddrhex = roaddrhex[:2+(addrsize*2)] + + time.Sleep(time.Millisecond * 500) + + // at this point we've verified that symkeys are saved and match on each peer + // now try sending symmetrically encrypted message, both directions + 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, 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, 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, hexutil.Encode(lmsg)) + if err != nil { + t.Fatal(err) + } + select { + case recvmsg := <-lmsgC: + if !bytes.Equal(recvmsg.Msg, lmsg) { + t.Fatalf("node 1 received payload mismatch: expected %v, got %v", lmsg, recvmsg) + } + case cerr := <-lctx.Done(): + t.Fatalf("test message (left) timed out: %v", cerr) + } + rmsg := []byte("xyzzy") + err = clients[0].Call(nil, "pss_sendRaw", roaddrhex, topic, hexutil.Encode(rmsg)) + if err != nil { + t.Fatal(err) + } + select { + case recvmsg := <-rmsgC: + if !bytes.Equal(recvmsg.Msg, rmsg) { + t.Fatalf("node 2 received payload mismatch: expected %x, got %v", rmsg, recvmsg.Msg) + } + case cerr := <-rctx.Done(): + t.Fatalf("test message (right) timed out: %v", cerr) + } +} + +// send symmetrically encrypted message between two directly connected peers +func TestSendSym(t *testing.T) { + t.Run("32", testSendSym) + t.Run("8", testSendSym) + t.Run("0", testSendSym) +} + +func testSendSym(t *testing.T) { + + // address hint size + var addrsize int64 + var err error + paramstring := strings.Split(t.Name(), "/") + addrsize, _ = strconv.ParseInt(paramstring[1], 10, 0) + log.Info("sym send test", "addrsize", addrsize) + + clients, err := setupNetwork(2, false) + if err != nil { + t.Fatal(err) + } + + var topic string + err = clients[0].Call(&topic, "pss_stringToTopic", "foo:42") + if err != nil { + t.Fatal(err) + } + + var loaddrhex string + err = clients[0].Call(&loaddrhex, "pss_baseAddr") + if err != nil { + t.Fatalf("rpc get node 1 baseaddr fail: %v", err) + } + loaddrhex = loaddrhex[:2+(addrsize*2)] + var roaddrhex string + err = clients[1].Call(&roaddrhex, "pss_baseAddr") + if err != nil { + t.Fatalf("rpc get node 2 baseaddr fail: %v", err) + } + roaddrhex = roaddrhex[:2+(addrsize*2)] + + // retrieve public key from pss instance + // set this public key reciprocally + var lpubkeyhex string + err = clients[0].Call(&lpubkeyhex, "pss_getPublicKey") + if err != nil { + t.Fatalf("rpc get node 1 pubkey fail: %v", err) + } + var rpubkeyhex string + err = clients[1].Call(&rpubkeyhex, "pss_getPublicKey") + if err != nil { + t.Fatalf("rpc get node 2 pubkey fail: %v", err) + } + + time.Sleep(time.Millisecond * 500) + + // at this point we've verified that symkeys are saved and match on each peer + // now try sending symmetrically encrypted message, both directions + 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, 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, false, false) + log.Trace("rsub", "id", rsub) + defer rsub.Unsubscribe() + + lrecvkey := network.RandomAddr().Over() + rrecvkey := network.RandomAddr().Over() + + var lkeyids [2]string + var rkeyids [2]string + + // manually set reciprocal symkeys + err = clients[0].Call(&lkeyids, "psstest_setSymKeys", rpubkeyhex, lrecvkey, rrecvkey, defaultSymKeySendLimit, topic, roaddrhex) + if err != nil { + t.Fatal(err) + } + err = clients[1].Call(&rkeyids, "psstest_setSymKeys", lpubkeyhex, rrecvkey, lrecvkey, defaultSymKeySendLimit, topic, loaddrhex) + if err != nil { + t.Fatal(err) + } + + // send and verify delivery + lmsg := []byte("plugh") + err = clients[1].Call(nil, "pss_sendSym", rkeyids[1], topic, hexutil.Encode(lmsg)) + if err != nil { + t.Fatal(err) + } + select { + case recvmsg := <-lmsgC: + if !bytes.Equal(recvmsg.Msg, lmsg) { + t.Fatalf("node 1 received payload mismatch: expected %v, got %v", lmsg, recvmsg) + } + case cerr := <-lctx.Done(): + t.Fatalf("test message timed out: %v", cerr) + } + rmsg := []byte("xyzzy") + err = clients[0].Call(nil, "pss_sendSym", lkeyids[1], topic, hexutil.Encode(rmsg)) + if err != nil { + t.Fatal(err) + } + select { + case recvmsg := <-rmsgC: + if !bytes.Equal(recvmsg.Msg, rmsg) { + t.Fatalf("node 2 received payload mismatch: expected %x, got %v", rmsg, recvmsg.Msg) + } + case cerr := <-rctx.Done(): + t.Fatalf("test message timed out: %v", cerr) + } +} + +// send asymmetrically encrypted message between two directly connected peers +func TestSendAsym(t *testing.T) { + t.Run("32", testSendAsym) + t.Run("8", testSendAsym) + t.Run("0", testSendAsym) +} + +func testSendAsym(t *testing.T) { + + // address hint size + var addrsize int64 + var err error + paramstring := strings.Split(t.Name(), "/") + addrsize, _ = strconv.ParseInt(paramstring[1], 10, 0) + log.Info("asym send test", "addrsize", addrsize) + + clients, err := setupNetwork(2, false) + if err != nil { + t.Fatal(err) + } + + var topic string + err = clients[0].Call(&topic, "pss_stringToTopic", "foo:42") + if err != nil { + t.Fatal(err) + } + + time.Sleep(time.Millisecond * 250) + + var loaddrhex string + err = clients[0].Call(&loaddrhex, "pss_baseAddr") + if err != nil { + t.Fatalf("rpc get node 1 baseaddr fail: %v", err) + } + loaddrhex = loaddrhex[:2+(addrsize*2)] + var roaddrhex string + err = clients[1].Call(&roaddrhex, "pss_baseAddr") + if err != nil { + t.Fatalf("rpc get node 2 baseaddr fail: %v", err) + } + roaddrhex = roaddrhex[:2+(addrsize*2)] + + // retrieve public key from pss instance + // set this public key reciprocally + var lpubkey string + err = clients[0].Call(&lpubkey, "pss_getPublicKey") + if err != nil { + t.Fatalf("rpc get node 1 pubkey fail: %v", err) + } + var rpubkey string + err = clients[1].Call(&rpubkey, "pss_getPublicKey") + if err != nil { + t.Fatalf("rpc get node 2 pubkey fail: %v", err) + } + + time.Sleep(time.Millisecond * 500) // replace with hive healthy code + + 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, 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, false, false) + log.Trace("rsub", "id", rsub) + defer rsub.Unsubscribe() + + // store reciprocal public keys + err = clients[0].Call(nil, "pss_setPeerPublicKey", rpubkey, topic, roaddrhex) + if err != nil { + t.Fatal(err) + } + err = clients[1].Call(nil, "pss_setPeerPublicKey", lpubkey, topic, loaddrhex) + if err != nil { + t.Fatal(err) + } + + // send and verify delivery + rmsg := []byte("xyzzy") + err = clients[0].Call(nil, "pss_sendAsym", rpubkey, topic, hexutil.Encode(rmsg)) + if err != nil { + t.Fatal(err) + } + select { + case recvmsg := <-rmsgC: + if !bytes.Equal(recvmsg.Msg, rmsg) { + t.Fatalf("node 2 received payload mismatch: expected %v, got %v", rmsg, recvmsg.Msg) + } + case cerr := <-rctx.Done(): + t.Fatalf("test message timed out: %v", cerr) + } + lmsg := []byte("plugh") + err = clients[1].Call(nil, "pss_sendAsym", lpubkey, topic, hexutil.Encode(lmsg)) + if err != nil { + t.Fatal(err) + } + select { + case recvmsg := <-lmsgC: + if !bytes.Equal(recvmsg.Msg, lmsg) { + t.Fatalf("node 1 received payload mismatch: expected %v, got %v", lmsg, recvmsg.Msg) + } + case cerr := <-lctx.Done(): + t.Fatalf("test message timed out: %v", cerr) + } +} + +type Job struct { + Msg []byte + SendNode enode.ID + RecvNode enode.ID +} + +func worker(id int, jobs <-chan Job, rpcs map[enode.ID]*rpc.Client, pubkeys map[enode.ID]string, topic string) { + for j := range jobs { + rpcs[j.SendNode].Call(nil, "pss_sendAsym", pubkeys[j.RecvNode], topic, hexutil.Encode(j.Msg)) + } +} + +func TestNetwork(t *testing.T) { + t.Run("16/1000/4/sim", testNetwork) +} + +// params in run name: +// nodes/msgs/addrbytes/adaptertype +// if adaptertype is exec uses execadapter, simadapter otherwise +func TestNetwork2000(t *testing.T) { + if !*longrunning { + t.Skip("run with --longrunning flag to run extensive network tests") + } + t.Run("3/2000/4/sim", testNetwork) + t.Run("4/2000/4/sim", testNetwork) + t.Run("8/2000/4/sim", testNetwork) + t.Run("16/2000/4/sim", testNetwork) +} + +func TestNetwork5000(t *testing.T) { + if !*longrunning { + t.Skip("run with --longrunning flag to run extensive network tests") + } + t.Run("3/5000/4/sim", testNetwork) + t.Run("4/5000/4/sim", testNetwork) + t.Run("8/5000/4/sim", testNetwork) + t.Run("16/5000/4/sim", testNetwork) +} + +func TestNetwork10000(t *testing.T) { + if !*longrunning { + t.Skip("run with --longrunning flag to run extensive network tests") + } + t.Run("3/10000/4/sim", testNetwork) + t.Run("4/10000/4/sim", testNetwork) + t.Run("8/10000/4/sim", testNetwork) +} + +func testNetwork(t *testing.T) { + paramstring := strings.Split(t.Name(), "/") + nodecount, _ := strconv.ParseInt(paramstring[1], 10, 0) + msgcount, _ := strconv.ParseInt(paramstring[2], 10, 0) + addrsize, _ := strconv.ParseInt(paramstring[3], 10, 0) + adapter := paramstring[4] + + log.Info("network test", "nodecount", nodecount, "msgcount", msgcount, "addrhintsize", addrsize) + + nodes := make([]enode.ID, nodecount) + bzzaddrs := make(map[enode.ID]string, nodecount) + rpcs := make(map[enode.ID]*rpc.Client, nodecount) + pubkeys := make(map[enode.ID]string, nodecount) + + sentmsgs := make([][]byte, msgcount) + recvmsgs := make([]bool, msgcount) + nodemsgcount := make(map[enode.ID]int, nodecount) + + trigger := make(chan enode.ID) + + var a adapters.NodeAdapter + if adapter == "exec" { + dirname, err := ioutil.TempDir(".", "") + if err != nil { + t.Fatal(err) + } + a = adapters.NewExecAdapter(dirname) + } else if adapter == "tcp" { + a = adapters.NewTCPAdapter(newServices(false)) + } else if adapter == "sim" { + a = adapters.NewSimAdapter(newServices(false)) + } + net := simulations.NewNetwork(a, &simulations.NetworkConfig{ + ID: "0", + }) + defer net.Shutdown() + + f, err := os.Open(fmt.Sprintf("testdata/snapshot_%d.json", nodecount)) + if err != nil { + t.Fatal(err) + } + jsonbyte, err := ioutil.ReadAll(f) + if err != nil { + t.Fatal(err) + } + var snap simulations.Snapshot + err = json.Unmarshal(jsonbyte, &snap) + if err != nil { + t.Fatal(err) + } + err = net.Load(&snap) + if err != nil { + //TODO: Fix p2p simulation framework to not crash when loading 32-nodes + //t.Fatal(err) + } + + time.Sleep(1 * time.Second) + + triggerChecks := func(trigger chan enode.ID, id enode.ID, rpcclient *rpc.Client, topic string) error { + msgC := make(chan APIMsg) + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + sub, err := rpcclient.Subscribe(ctx, "pss", msgC, "receive", topic, false, false) + if err != nil { + t.Fatal(err) + } + go func() { + defer sub.Unsubscribe() + for { + select { + case recvmsg := <-msgC: + idx, _ := binary.Uvarint(recvmsg.Msg) + if !recvmsgs[idx] { + log.Debug("msg recv", "idx", idx, "id", id) + recvmsgs[idx] = true + trigger <- id + } + case <-sub.Err(): + return + } + } + }() + return nil + } + + var topic string + for i, nod := range net.GetNodes() { + nodes[i] = nod.ID() + rpcs[nodes[i]], err = nod.Client() + if err != nil { + t.Fatal(err) + } + if topic == "" { + err = rpcs[nodes[i]].Call(&topic, "pss_stringToTopic", "foo:42") + if err != nil { + t.Fatal(err) + } + } + var pubkey string + err = rpcs[nodes[i]].Call(&pubkey, "pss_getPublicKey") + if err != nil { + t.Fatal(err) + } + pubkeys[nod.ID()] = pubkey + var addrhex string + err = rpcs[nodes[i]].Call(&addrhex, "pss_baseAddr") + if err != nil { + t.Fatal(err) + } + bzzaddrs[nodes[i]] = addrhex + err = triggerChecks(trigger, nodes[i], rpcs[nodes[i]], topic) + if err != nil { + t.Fatal(err) + } + } + + time.Sleep(1 * time.Second) + + // setup workers + jobs := make(chan Job, 10) + for w := 1; w <= 10; w++ { + go worker(w, jobs, rpcs, pubkeys, topic) + } + + time.Sleep(1 * time.Second) + + for i := 0; i < int(msgcount); i++ { + sendnodeidx := rand.Intn(int(nodecount)) + recvnodeidx := rand.Intn(int(nodecount - 1)) + if recvnodeidx >= sendnodeidx { + recvnodeidx++ + } + nodemsgcount[nodes[recvnodeidx]]++ + sentmsgs[i] = make([]byte, 8) + c := binary.PutUvarint(sentmsgs[i], uint64(i)) + if c == 0 { + t.Fatal("0 byte message") + } + if err != nil { + t.Fatal(err) + } + err = rpcs[nodes[sendnodeidx]].Call(nil, "pss_setPeerPublicKey", pubkeys[nodes[recvnodeidx]], topic, bzzaddrs[nodes[recvnodeidx]]) + if err != nil { + t.Fatal(err) + } + + jobs <- Job{ + Msg: sentmsgs[i], + SendNode: nodes[sendnodeidx], + RecvNode: nodes[recvnodeidx], + } + } + + finalmsgcount := 0 + ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second) + defer cancel() +outer: + for i := 0; i < int(msgcount); i++ { + select { + case id := <-trigger: + nodemsgcount[id]-- + finalmsgcount++ + case <-ctx.Done(): + log.Warn("timeout") + break outer + } + } + + for i, msg := range recvmsgs { + if !msg { + log.Debug("missing message", "idx", i) + } + } + t.Logf("%d of %d messages received", finalmsgcount, msgcount) + + if finalmsgcount != int(msgcount) { + t.Fatalf("%d messages were not received", int(msgcount)-finalmsgcount) + } + +} + +// check that in a network of a -> b -> c -> a +// a doesn't receive a sent message twice +func TestDeduplication(t *testing.T) { + var err error + + clients, err := setupNetwork(3, false) + if err != nil { + t.Fatal(err) + } + + var addrsize = 32 + var loaddrhex string + err = clients[0].Call(&loaddrhex, "pss_baseAddr") + if err != nil { + t.Fatalf("rpc get node 1 baseaddr fail: %v", err) + } + loaddrhex = loaddrhex[:2+(addrsize*2)] + var roaddrhex string + err = clients[1].Call(&roaddrhex, "pss_baseAddr") + if err != nil { + t.Fatalf("rpc get node 2 baseaddr fail: %v", err) + } + roaddrhex = roaddrhex[:2+(addrsize*2)] + var xoaddrhex string + err = clients[2].Call(&xoaddrhex, "pss_baseAddr") + if err != nil { + t.Fatalf("rpc get node 3 baseaddr fail: %v", err) + } + xoaddrhex = xoaddrhex[:2+(addrsize*2)] + + log.Info("peer", "l", loaddrhex, "r", roaddrhex, "x", xoaddrhex) + + var topic string + err = clients[0].Call(&topic, "pss_stringToTopic", "foo:42") + if err != nil { + t.Fatal(err) + } + + time.Sleep(time.Millisecond * 250) + + // retrieve public key from pss instance + // set this public key reciprocally + var rpubkey string + err = clients[1].Call(&rpubkey, "pss_getPublicKey") + if err != nil { + t.Fatalf("rpc get receivenode pubkey fail: %v", err) + } + + time.Sleep(time.Millisecond * 500) // replace with hive healthy code + + 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, false, false) + log.Trace("rsub", "id", rsub) + defer rsub.Unsubscribe() + + // store public key for recipient + // zero-length address means forward to all + // we have just two peers, they will be in proxbin, and will both receive + err = clients[0].Call(nil, "pss_setPeerPublicKey", rpubkey, topic, "0x") + if err != nil { + t.Fatal(err) + } + + // send and verify delivery + rmsg := []byte("xyzzy") + err = clients[0].Call(nil, "pss_sendAsym", rpubkey, topic, hexutil.Encode(rmsg)) + if err != nil { + t.Fatal(err) + } + + var receivedok bool +OUTER: + for { + select { + case <-rmsgC: + if receivedok { + t.Fatalf("duplicate message received") + } + receivedok = true + case <-rctx.Done(): + break OUTER + } + } + if !receivedok { + t.Fatalf("message did not arrive") + } +} + +// symmetric send performance with varying message sizes +func BenchmarkSymkeySend(b *testing.B) { + b.Run(fmt.Sprintf("%d", 256), benchmarkSymKeySend) + b.Run(fmt.Sprintf("%d", 1024), benchmarkSymKeySend) + b.Run(fmt.Sprintf("%d", 1024*1024), benchmarkSymKeySend) + b.Run(fmt.Sprintf("%d", 1024*1024*10), benchmarkSymKeySend) + b.Run(fmt.Sprintf("%d", 1024*1024*100), benchmarkSymKeySend) +} + +func benchmarkSymKeySend(b *testing.B) { + msgsizestring := strings.Split(b.Name(), "/") + if len(msgsizestring) != 2 { + b.Fatalf("benchmark called without msgsize param") + } + msgsize, err := strconv.ParseInt(msgsizestring[1], 10, 0) + if err != nil { + b.Fatalf("benchmark called with invalid msgsize param '%s': %v", msgsizestring[1], err) + } + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + 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) + if err != nil { + b.Fatalf("could not generate symkey: %v", err) + } + symkey, err := ps.w.GetSymKey(symkeyid) + if err != nil { + b.Fatalf("could not retrieve symkey: %v", err) + } + ps.SetSymmetricKey(symkey, topic, to, false) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + ps.SendSym(symkeyid, topic, msg) + } +} + +// asymmetric send performance with varying message sizes +func BenchmarkAsymkeySend(b *testing.B) { + b.Run(fmt.Sprintf("%d", 256), benchmarkAsymKeySend) + b.Run(fmt.Sprintf("%d", 1024), benchmarkAsymKeySend) + b.Run(fmt.Sprintf("%d", 1024*1024), benchmarkAsymKeySend) + b.Run(fmt.Sprintf("%d", 1024*1024*10), benchmarkAsymKeySend) + b.Run(fmt.Sprintf("%d", 1024*1024*100), benchmarkAsymKeySend) +} + +func benchmarkAsymKeySend(b *testing.B) { + msgsizestring := strings.Split(b.Name(), "/") + if len(msgsizestring) != 2 { + b.Fatalf("benchmark called without msgsize param") + } + msgsize, err := strconv.ParseInt(msgsizestring[1], 10, 0) + if err != nil { + b.Fatalf("benchmark called with invalid msgsize param '%s': %v", msgsizestring[1], err) + } + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + 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) + b.ResetTimer() + for i := 0; i < b.N; i++ { + ps.SendAsym(common.ToHex(crypto.FromECDSAPub(&privkey.PublicKey)), topic, msg) + } +} +func BenchmarkSymkeyBruteforceChangeaddr(b *testing.B) { + for i := 100; i < 100000; i = i * 10 { + for j := 32; j < 10000; j = j * 8 { + b.Run(fmt.Sprintf("%d/%d", i, j), benchmarkSymkeyBruteforceChangeaddr) + } + //b.Run(fmt.Sprintf("%d", i), benchmarkSymkeyBruteforceChangeaddr) + } +} + +// decrypt performance using symkey cache, worst case +// (decrypt key always last in cache) +func benchmarkSymkeyBruteforceChangeaddr(b *testing.B) { + keycountstring := strings.Split(b.Name(), "/") + cachesize := int64(0) + var ps *Pss + if len(keycountstring) < 2 { + b.Fatalf("benchmark called without count param") + } + keycount, err := strconv.ParseInt(keycountstring[1], 10, 0) + if err != nil { + b.Fatalf("benchmark called with invalid count param '%s': %v", keycountstring[1], err) + } + if len(keycountstring) == 3 { + cachesize, err = strconv.ParseInt(keycountstring[2], 10, 0) + if err != nil { + b.Fatalf("benchmark called with invalid cachesize '%s': %v", keycountstring[2], err) + } + } + pssmsgs := make([]*PssMsg, 0, keycount) + var keyid string + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + keys, err := wapi.NewKeyPair(ctx) + privkey, err := w.GetPrivateKey(keys) + if cachesize > 0 { + ps = newTestPss(privkey, nil, &PssParams{SymKeyCacheCapacity: int(cachesize)}) + } 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) + if err != nil { + b.Fatalf("cant generate symkey #%d: %v", i, err) + } + symkey, err := ps.w.GetSymKey(keyid) + if err != nil { + b.Fatalf("could not retrieve symkey %s: %v", keyid, err) + } + wparams := &whisper.MessageParams{ + TTL: defaultWhisperTTL, + KeySym: symkey, + Topic: whisper.TopicType(topic), + WorkTime: defaultWhisperWorkTime, + PoW: defaultWhisperPoW, + Payload: []byte("xyzzy"), + Padding: []byte("1234567890abcdef"), + } + woutmsg, err := whisper.NewSentMessage(wparams) + if err != nil { + b.Fatalf("could not create whisper message: %v", err) + } + env, err := woutmsg.Wrap(wparams) + if err != nil { + b.Fatalf("could not generate whisper envelope: %v", err) + } + ps.Register(&topic, &handler{ + f: noopHandlerFunc, + }) + pssmsgs = append(pssmsgs, &PssMsg{ + To: to, + Payload: env, + }) + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + if err := ps.process(pssmsgs[len(pssmsgs)-(i%len(pssmsgs))-1], false, false); err != nil { + b.Fatalf("pss processing failed: %v", err) + } + } +} + +func BenchmarkSymkeyBruteforceSameaddr(b *testing.B) { + for i := 100; i < 100000; i = i * 10 { + for j := 32; j < 10000; j = j * 8 { + b.Run(fmt.Sprintf("%d/%d", i, j), benchmarkSymkeyBruteforceSameaddr) + } + } +} + +// decrypt performance using symkey cache, best case +// (decrypt key always first in cache) +func benchmarkSymkeyBruteforceSameaddr(b *testing.B) { + var keyid string + var ps *Pss + cachesize := int64(0) + keycountstring := strings.Split(b.Name(), "/") + if len(keycountstring) < 2 { + b.Fatalf("benchmark called without count param") + } + keycount, err := strconv.ParseInt(keycountstring[1], 10, 0) + if err != nil { + b.Fatalf("benchmark called with invalid count param '%s': %v", keycountstring[1], err) + } + if len(keycountstring) == 3 { + cachesize, err = strconv.ParseInt(keycountstring[2], 10, 0) + if err != nil { + b.Fatalf("benchmark called with invalid cachesize '%s': %v", keycountstring[2], err) + } + } + addr := make([]PssAddress, keycount) + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + keys, err := wapi.NewKeyPair(ctx) + privkey, err := w.GetPrivateKey(keys) + if cachesize > 0 { + ps = newTestPss(privkey, nil, &PssParams{SymKeyCacheCapacity: int(cachesize)}) + } 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) + if err != nil { + b.Fatalf("cant generate symkey #%d: %v", i, err) + } + + } + symkey, err := ps.w.GetSymKey(keyid) + if err != nil { + b.Fatalf("could not retrieve symkey %s: %v", keyid, err) + } + wparams := &whisper.MessageParams{ + TTL: defaultWhisperTTL, + KeySym: symkey, + Topic: whisper.TopicType(topic), + WorkTime: defaultWhisperWorkTime, + PoW: defaultWhisperPoW, + Payload: []byte("xyzzy"), + Padding: []byte("1234567890abcdef"), + } + woutmsg, err := whisper.NewSentMessage(wparams) + if err != nil { + b.Fatalf("could not create whisper message: %v", err) + } + env, err := woutmsg.Wrap(wparams) + if err != nil { + b.Fatalf("could not generate whisper envelope: %v", err) + } + 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, false, false); err != nil { + b.Fatalf("pss processing failed: %v", err) + } + } +} + +// setup simulated network with bzz/discovery and pss services. +// connects nodes in a circle +// if allowRaw is set, omission of builtin pss encryption is enabled (see PssParams) +func setupNetwork(numnodes int, allowRaw bool) (clients []*rpc.Client, err error) { + nodes := make([]*simulations.Node, numnodes) + clients = make([]*rpc.Client, numnodes) + if numnodes < 2 { + return nil, fmt.Errorf("Minimum two nodes in network") + } + adapter := adapters.NewSimAdapter(newServices(allowRaw)) + net := simulations.NewNetwork(adapter, &simulations.NetworkConfig{ + ID: "0", + DefaultService: "bzz", + }) + for i := 0; i < numnodes; i++ { + nodeconf := adapters.RandomNodeConfig() + nodeconf.Services = []string{"bzz", pssProtocolName} + nodes[i], err = net.NewNodeWithConfig(nodeconf) + if err != nil { + return nil, fmt.Errorf("error creating node 1: %v", err) + } + err = net.Start(nodes[i].ID()) + if err != nil { + return nil, fmt.Errorf("error starting node 1: %v", err) + } + if i > 0 { + err = net.Connect(nodes[i].ID(), nodes[i-1].ID()) + if err != nil { + return nil, fmt.Errorf("error connecting nodes: %v", err) + } + } + clients[i], err = nodes[i].Client() + if err != nil { + return nil, fmt.Errorf("create node 1 rpc client fail: %v", err) + } + } + if numnodes > 2 { + err = net.Connect(nodes[0].ID(), nodes[len(nodes)-1].ID()) + if err != nil { + return nil, fmt.Errorf("error connecting first and last nodes") + } + } + return clients, nil +} + +func newServices(allowRaw bool) adapters.Services { + stateStore := state.NewInmemoryStore() + kademlias := make(map[enode.ID]*network.Kademlia) + kademlia := func(id enode.ID) *network.Kademlia { + if k, ok := kademlias[id]; ok { + return k + } + params := network.NewKadParams() + params.NeighbourhoodSize = 2 + params.MaxBinSize = 3 + params.MinBinSize = 1 + params.MaxRetries = 1000 + params.RetryExponent = 2 + params.RetryInterval = 1000000 + kademlias[id] = network.NewKademlia(id[:], params) + return kademlias[id] + } + return adapters.Services{ + pssProtocolName: func(ctx *adapters.ServiceContext) (node.Service, error) { + // execadapter does not exec init() + initTest() + + ctxlocal, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + keys, err := wapi.NewKeyPair(ctxlocal) + privkey, err := w.GetPrivateKey(keys) + pssp := NewPssParams().WithPrivateKey(privkey) + pssp.AllowRaw = allowRaw + pskad := kademlia(ctx.Config.ID) + ps, err := NewPss(pskad, pssp) + if err != nil { + return nil, err + } + + ping := &Ping{ + OutC: make(chan bool), + Pong: true, + } + p2pp := NewPingProtocol(ping) + pp, err := RegisterProtocol(ps, &PingTopic, PingProtocol, p2pp, &ProtocolParams{Asymmetric: true}) + if err != nil { + return nil, err + } + if useHandshake { + SetHandshakeController(ps, NewHandshakeParams()) + } + ps.Register(&PingTopic, &handler{ + f: pp.Handle, + caps: &handlerCaps{ + raw: true, + }, + }) + ps.addAPI(rpc.API{ + Namespace: "psstest", + Version: "0.3", + Service: NewAPITest(ps), + Public: false, + }) + if err != nil { + log.Error("Couldnt register pss protocol", "err", err) + os.Exit(1) + } + pssprotocols[ctx.Config.ID.String()] = &protoCtrl{ + C: ping.OutC, + protocol: pp, + run: p2pp.Run, + } + return ps, nil + }, + "bzz": func(ctx *adapters.ServiceContext) (node.Service, error) { + addr := network.NewAddr(ctx.Config.Node()) + 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), stateStore, nil, nil), nil + }, + } +} + +func newTestPss(privkey *ecdsa.PrivateKey, kad *network.Kademlia, ppextra *PssParams) *Pss { + nid := enode.PubkeyToIDV4(&privkey.PublicKey) + // set up routing if kademlia is not passed to us + if kad == nil { + kp := network.NewKadParams() + kp.NeighbourhoodSize = 3 + kad = network.NewKademlia(nid[:], kp) + } + + // create pss + pp := NewPssParams().WithPrivateKey(privkey) + if ppextra != nil { + pp.SymKeyCacheCapacity = ppextra.SymKeyCacheCapacity + } + ps, err := NewPss(kad, pp) + if err != nil { + return nil + } + ps.Start(nil) + + return ps +} + +// API calls for test/development use +type APITest struct { + *Pss +} + +func NewAPITest(ps *Pss) *APITest { + return &APITest{Pss: ps} +} + +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, PssAddress(to), false) + if err != nil { + return [2]string{}, err + } + return [2]string{recvsymkeyid, sendsymkeyid}, nil +} + +func (apitest *APITest) Clean() (int, error) { + return apitest.Pss.cleanKeys(), nil +} diff --git a/swarm/pss/testdata/snapshot_128.json b/swarm/pss/testdata/snapshot_128.json new file mode 100644 index 0000000000..8e1bc88b38 --- /dev/null +++ b/swarm/pss/testdata/snapshot_128.json @@ -0,0 +1 @@ +{"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/swarm/pss/testdata/snapshot_16.json b/swarm/pss/testdata/snapshot_16.json new file mode 100644 index 0000000000..b6a7bf8115 --- /dev/null +++ b/swarm/pss/testdata/snapshot_16.json @@ -0,0 +1 @@ +{"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/swarm/pss/testdata/snapshot_2.json b/swarm/pss/testdata/snapshot_2.json new file mode 100644 index 0000000000..8be6e0dc2b --- /dev/null +++ b/swarm/pss/testdata/snapshot_2.json @@ -0,0 +1 @@ +{"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/swarm/pss/testdata/snapshot_256.json b/swarm/pss/testdata/snapshot_256.json new file mode 100644 index 0000000000..936956bec4 --- /dev/null +++ b/swarm/pss/testdata/snapshot_256.json @@ -0,0 +1 @@ +{"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/swarm/pss/testdata/snapshot_3.json b/swarm/pss/testdata/snapshot_3.json new file mode 100644 index 0000000000..15ed45bcfe --- /dev/null +++ b/swarm/pss/testdata/snapshot_3.json @@ -0,0 +1 @@ +{"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/swarm/pss/testdata/snapshot_32.json b/swarm/pss/testdata/snapshot_32.json new file mode 100644 index 0000000000..05a40b2b82 --- /dev/null +++ b/swarm/pss/testdata/snapshot_32.json @@ -0,0 +1 @@ +{"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/swarm/pss/testdata/snapshot_4.json b/swarm/pss/testdata/snapshot_4.json new file mode 100644 index 0000000000..9296cad0b9 --- /dev/null +++ b/swarm/pss/testdata/snapshot_4.json @@ -0,0 +1 @@ +{"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/swarm/pss/testdata/snapshot_64.json b/swarm/pss/testdata/snapshot_64.json new file mode 100644 index 0000000000..cd3d5593fb --- /dev/null +++ b/swarm/pss/testdata/snapshot_64.json @@ -0,0 +1 @@ +{"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/swarm/pss/testdata/snapshot_8.json b/swarm/pss/testdata/snapshot_8.json new file mode 100644 index 0000000000..53fe4f96b9 --- /dev/null +++ b/swarm/pss/testdata/snapshot_8.json @@ -0,0 +1 @@ +{"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/swarm/pss/types.go b/swarm/pss/types.go new file mode 100644 index 0000000000..2ce1f5cfb0 --- /dev/null +++ b/swarm/pss/types.go @@ -0,0 +1,217 @@ +// 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 pss + +import ( + "encoding/json" + "fmt" + "sync" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "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/whisperv6" +) + +const ( + defaultWhisperTTL = 6000 +) + +const ( + pssControlSym = 1 + pssControlRaw = 1 << 1 +) + +var ( + topicHashMutex = sync.Mutex{} + topicHashFunc = storage.MakeHashFunc("SHA256")() + rawTopic = Topic{} +) + +// Topic is the PSS encapsulation of the Whisper topic type +type Topic whisper.TopicType + +func (t *Topic) String() string { + return hexutil.Encode(t[:]) +} + +// MarshalJSON implements the json.Marshaler interface +func (t Topic) MarshalJSON() (b []byte, err error) { + return json.Marshal(t.String()) +} + +// MarshalJSON implements the json.Marshaler interface +func (t *Topic) UnmarshalJSON(input []byte) error { + topicbytes, err := hexutil.Decode(string(input[1 : len(input)-1])) + if err != nil { + return err + } + copy(t[:], topicbytes) + return nil +} + +// PssAddress is an alias for []byte. It represents a variable length address +type PssAddress []byte + +// MarshalJSON implements the json.Marshaler interface +func (a PssAddress) MarshalJSON() ([]byte, error) { + return json.Marshal(hexutil.Encode(a[:])) +} + +// UnmarshalJSON implements the json.Marshaler interface +func (a *PssAddress) UnmarshalJSON(input []byte) error { + b, err := hexutil.Decode(string(input[1 : len(input)-1])) + if err != nil { + return err + } + for _, bb := range b { + *a = append(*a, bb) + } + return nil +} + +// holds the digest of a message used for caching +type pssDigest [digestLength]byte + +// conceals bitwise operations on the control flags byte +type msgParams struct { + raw bool + sym bool +} + +func newMsgParamsFromBytes(paramBytes []byte) *msgParams { + if len(paramBytes) != 1 { + return nil + } + return &msgParams{ + raw: paramBytes[0]&pssControlRaw > 0, + sym: paramBytes[0]&pssControlSym > 0, + } +} + +func (m *msgParams) Bytes() (paramBytes []byte) { + var b byte + if m.raw { + b |= pssControlRaw + } + if m.sym { + b |= pssControlSym + } + paramBytes = append(paramBytes, b) + return paramBytes +} + +// PssMsg encapsulates messages transported over pss. +type PssMsg struct { + To []byte + Control []byte + Expire uint32 + Payload *whisper.Envelope +} + +func newPssMsg(param *msgParams) *PssMsg { + return &PssMsg{ + Control: param.Bytes(), + } +} + +// message is flagged as raw / external encryption +func (msg *PssMsg) isRaw() bool { + return msg.Control[0]&pssControlRaw > 0 +} + +// message is flagged as symmetrically encrypted +func (msg *PssMsg) isSym() bool { + return msg.Control[0]&pssControlSym > 0 +} + +// serializes the message for use in cache +func (msg *PssMsg) serialize() []byte { + rlpdata, _ := rlp.EncodeToBytes(struct { + To []byte + Payload *whisper.Envelope + }{ + To: msg.To, + Payload: msg.Payload, + }) + return rlpdata +} + +// String representation of PssMsg +func (msg *PssMsg) String() string { + return fmt.Sprintf("PssMsg: Recipient: %x", common.ToHex(msg.To)) +} + +// Signature for a message handler function for a PssMsg +// Implementations of this type are passed to Pss.Register together with a topic, +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 +type stateStore struct { + values map[string][]byte +} + +func (store *stateStore) Load(key string) ([]byte, error) { + return nil, nil +} + +func (store *stateStore) Save(key string, v []byte) error { + return nil +} + +// BytesToTopic hashes an arbitrary length byte slice and truncates it to the length of a topic, using only the first bytes of the digest +func BytesToTopic(b []byte) Topic { + topicHashMutex.Lock() + defer topicHashMutex.Unlock() + topicHashFunc.Reset() + topicHashFunc.Write(b) + return Topic(whisper.BytesToTopic(topicHashFunc.Sum(nil))) +} diff --git a/swarm/pss/writeup.md b/swarm/pss/writeup.md new file mode 100644 index 0000000000..af731fe7fd --- /dev/null +++ b/swarm/pss/writeup.md @@ -0,0 +1,125 @@ +## PSS tests failures explanation + +This document aims to explain the changes in https://github.com/ethersphere/go-ethereum/pull/126 and how those changes affect the pss_test.go TestNetwork tests. + +### Problem + +When running the TestNetwork test, execution sometimes: + +* deadlocks +* panics +* failures with wrong result, such as: + +``` +$ go test -v ./swarm/pss -cpu 4 -run TestNetwork +``` + +``` +--- FAIL: TestNetwork (68.13s) + --- FAIL: TestNetwork/3/10/4/sim (68.13s) + pss_test.go:697: 7 of 10 messages received + pss_test.go:700: 3 messages were not received +FAIL +``` + +Moreover execution almost always deadlocks with `sim` adapter, and `sock` adapter (when buffer is low), but is mostly stable with `exec` and `tcp` adapters. + +### Findings and Fixes + +#### 1. Addressing panics + +Panics were caused due to concurrent map read/writes and unsynchronised access to shared memory by multiple goroutines. This is visible when running the test with the `-race` flag. + +``` +go test -race -v ./swarm/pss -cpu 4 -run TestNetwork + + 1 ================== + 2 WARNING: DATA RACE + 3 Read at 0x00c424d456a0 by goroutine 1089: + 4 github.com/ethereum/go-ethereum/swarm/pss.(*Pss).forward.func1() + 5 /Users/nonsense/code/src/github.com/ethereum/go-ethereum/swarm/pss/pss.go:654 +0x44f + 6 github.com/ethereum/go-ethereum/swarm/network.(*Kademlia).eachConn.func1() + 7 /Users/nonsense/code/src/github.com/ethereum/go-ethereum/swarm/network/kademlia.go:350 +0xc9 + 8 github.com/ethereum/go-ethereum/pot.(*Pot).eachNeighbour.func1() + 9 /Users/nonsense/code/src/github.com/ethereum/go-ethereum/pot/pot.go:599 +0x59 + ... + + 28 + 29 Previous write at 0x00c424d456a0 by goroutine 829: + 30 github.com/ethereum/go-ethereum/swarm/pss.(*Pss).Run() + 31 /Users/nonsense/code/src/github.com/ethereum/go-ethereum/swarm/pss/pss.go:192 +0x16a + 32 github.com/ethereum/go-ethereum/swarm/pss.(*Pss).Run-fm() + 33 /Users/nonsense/code/src/github.com/ethereum/go-ethereum/swarm/pss/pss.go:185 +0x63 + 34 github.com/ethereum/go-ethereum/p2p.(*Peer).startProtocols.func1() + 35 /Users/nonsense/code/src/github.com/ethereum/go-ethereum/p2p/peer.go:347 +0x8b + ... +``` + +##### Current solution + +Adding a mutex around all shared data. + +#### 2. Failures with wrong result + +The validation phase of the TestNetwork test is done using an RPC subscription: + +``` + ... + triggerChecks := func(trigger chan enode.ID, id enode.ID, rpcclient *rpc.Client) error { + msgC := make(chan APIMsg) + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + sub, err := rpcclient.Subscribe(ctx, "pss", msgC, "receive", hextopic) + ... +``` + +By design the RPC uses a subscription buffer with a max length. When this length is reached, the subscription is dropped. The current config value is not suitable for stress tests. + +##### Current solution + +Increase the max length of the RPC subscription buffer. + +``` +const ( + // Subscriptions are removed when the subscriber cannot keep up. + // + // This can be worked around by supplying a channel with sufficiently sized buffer, + // but this can be inconvenient and hard to explain in the docs. Another issue with + // buffered channels is that the buffer is static even though it might not be needed + // most of the time. + // + // The approach taken here is to maintain a per-subscription linked list buffer + // shrinks on demand. If the buffer reaches the size below, the subscription is + // dropped. + maxClientSubscriptionBuffer = 20000 +) +``` + +#### 3. Deadlocks + +Deadlocks are triggered when using: +* `sim` adapter - synchronous, unbuffered channel +* `sock` adapter - asynchronous, buffered channel (when using a 1K buffer) + +No deadlocks were triggered when using: +* `tcp` adapter - asynchronous, buffered channel +* `exec` adapter - asynchronous, buffered channel + +Ultimately the deadlocks happen due to blocking `pp.Send()` call at: + + // attempt to send the message + err := pp.Send(msg) + if err != nil { + log.Debug(fmt.Sprintf("%v: failed forwarding: %v", sendMsg, err)) + return true + } + + `p2p` request handling is synchronous (as discussed at https://github.com/ethersphere/go-ethereum/issues/130), `pss` is also synchronous, therefore if two nodes happen to be processing a request, while at the same time waiting for response on `pp.Send(msg)`, deadlock occurs. + + `pp.Send(msg)` is only blocking when the underlying adapter is blocking (read `sim` or `sock`) or the buffer of the connection is full. + +##### Current solution + +Make no assumption on the undelying connection, and call `pp.Send` asynchronously in a go-routine. + +Alternatively, get rid of the `sim` and `sock` adapters, and use `tcp` adapter for testing. diff --git a/swarm/sctx/sctx.go b/swarm/sctx/sctx.go new file mode 100644 index 0000000000..fb7d35b000 --- /dev/null +++ b/swarm/sctx/sctx.go @@ -0,0 +1,20 @@ +package sctx + +import "context" + +type ( + HTTPRequestIDKey struct{} + requestHostKey struct{} +) + +func SetHost(ctx context.Context, domain string) context.Context { + return context.WithValue(ctx, requestHostKey{}, domain) +} + +func GetHost(ctx context.Context) string { + v, ok := ctx.Value(requestHostKey{}).(string) + if ok { + return v + } + return "" +} diff --git a/swarm/services/swap/swap.go b/swarm/services/swap/swap.go index 1f9b22b904..91fa54fcf0 100644 --- a/swarm/services/swap/swap.go +++ b/swarm/services/swap/swap.go @@ -19,6 +19,7 @@ package swap import ( "context" "crypto/ecdsa" + "errors" "fmt" "math/big" "os" @@ -32,7 +33,7 @@ import ( "github.com/ethereum/go-ethereum/contracts/chequebook/contract" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/swarm/log" "github.com/ethereum/go-ethereum/swarm/services/swap/swap" ) @@ -59,16 +60,19 @@ const ( chequebookDeployDelay = 1 * time.Second // delay between retries ) -type SwapParams struct { +// LocalProfile combines a PayProfile with *swap.Params +type LocalProfile struct { *swap.Params *PayProfile } -type SwapProfile struct { +// RemoteProfile combines a PayProfile with *swap.Profile +type RemoteProfile struct { *swap.Profile *PayProfile } +// PayProfile is a container for relevant chequebook and beneficiary options type PayProfile struct { PublicKey string // check against signature of promise Contract common.Address // address of chequebook contract @@ -80,9 +84,9 @@ type PayProfile struct { lock sync.RWMutex } -//create params with default values -func NewDefaultSwapParams() *SwapParams { - return &SwapParams{ +// NewDefaultSwapParams create params with default values +func NewDefaultSwapParams() *LocalProfile { + return &LocalProfile{ PayProfile: &PayProfile{}, Params: &swap.Params{ Profile: &swap.Profile{ @@ -102,12 +106,12 @@ func NewDefaultSwapParams() *SwapParams { } } -//this can only finally be set after all config options (file, cmd line, env vars) -//have been evaluated -func (self *SwapParams) Init(contract common.Address, prvkey *ecdsa.PrivateKey) { +// Init this can only finally be set after all config options (file, cmd line, env vars) +// have been evaluated +func (lp *LocalProfile) Init(contract common.Address, prvkey *ecdsa.PrivateKey) { pubkey := &prvkey.PublicKey - self.PayProfile = &PayProfile{ + lp.PayProfile = &PayProfile{ PublicKey: common.ToHex(crypto.FromECDSAPub(pubkey)), Contract: contract, Beneficiary: crypto.PubkeyToAddress(*pubkey), @@ -117,7 +121,7 @@ func (self *SwapParams) Init(contract common.Address, prvkey *ecdsa.PrivateKey) } } -// swap constructor, parameters +// NewSwap constructor, parameters // * global chequebook, assume deployed service and // * the balance is at buffer. // swap.Add(n) called in netstore @@ -125,8 +129,7 @@ func (self *SwapParams) Init(contract common.Address, prvkey *ecdsa.PrivateKey) // OR sending cheques. // n < 0 called when receiving chunks = receiving delivery responses // OR receiving cheques. - -func NewSwap(local *SwapParams, remote *SwapProfile, backend chequebook.Backend, proto swap.Protocol) (self *swap.Swap, err error) { +func NewSwap(localProfile *LocalProfile, remoteProfile *RemoteProfile, backend chequebook.Backend, proto swap.Protocol) (swapInstance *swap.Swap, err error) { var ( ctx = context.TODO() ok bool @@ -134,26 +137,31 @@ func NewSwap(local *SwapParams, remote *SwapProfile, backend chequebook.Backend, out *chequebook.Outbox ) - // check if remote chequebook is valid + remotekey, err := crypto.UnmarshalPubkey(common.FromHex(remoteProfile.PublicKey)) + if err != nil { + return nil, errors.New("invalid remote public key") + } + + // check if remoteProfile chequebook is valid // insolvent chequebooks suicide so will signal as invalid // TODO: monitoring a chequebooks events - ok, err = chequebook.ValidateCode(ctx, backend, remote.Contract) + ok, err = chequebook.ValidateCode(ctx, backend, remoteProfile.Contract) if !ok { - log.Info(fmt.Sprintf("invalid contract %v for peer %v: %v)", remote.Contract.Hex()[:8], proto, err)) + log.Info(fmt.Sprintf("invalid contract %v for peer %v: %v)", remoteProfile.Contract.Hex()[:8], proto, err)) } else { - // remote contract valid, create inbox - in, err = chequebook.NewInbox(local.privateKey, remote.Contract, local.Beneficiary, crypto.ToECDSAPub(common.FromHex(remote.PublicKey)), backend) + // remoteProfile contract valid, create inbox + in, err = chequebook.NewInbox(localProfile.privateKey, remoteProfile.Contract, localProfile.Beneficiary, remotekey, backend) if err != nil { - log.Warn(fmt.Sprintf("unable to set up inbox for chequebook contract %v for peer %v: %v)", remote.Contract.Hex()[:8], proto, err)) + log.Warn(fmt.Sprintf("unable to set up inbox for chequebook contract %v for peer %v: %v)", remoteProfile.Contract.Hex()[:8], proto, err)) } } - // check if local chequebook contract is valid - ok, err = chequebook.ValidateCode(ctx, backend, local.Contract) + // check if localProfile chequebook contract is valid + ok, err = chequebook.ValidateCode(ctx, backend, localProfile.Contract) if !ok { - log.Warn(fmt.Sprintf("unable to set up outbox for peer %v: chequebook contract (owner: %v): %v)", proto, local.owner.Hex(), err)) + log.Warn(fmt.Sprintf("unable to set up outbox for peer %v: chequebook contract (owner: %v): %v)", proto, localProfile.owner.Hex(), err)) } else { - out = chequebook.NewOutbox(local.Chequebook(), remote.Beneficiary) + out = chequebook.NewOutbox(localProfile.Chequebook(), remoteProfile.Beneficiary) } pm := swap.Payment{ @@ -162,20 +170,20 @@ func NewSwap(local *SwapParams, remote *SwapProfile, backend chequebook.Backend, Buys: out != nil, Sells: in != nil, } - self, err = swap.New(local.Params, pm, proto) + swapInstance, err = swap.New(localProfile.Params, pm, proto) if err != nil { return } - // remote profile given (first) in handshake - self.SetRemote(remote.Profile) + // remoteProfile profile given (first) in handshake + swapInstance.SetRemote(remoteProfile.Profile) var buy, sell string - if self.Buys { - buy = "purchase from peer enabled at " + remote.SellAt.String() + " wei/chunk" + if swapInstance.Buys { + buy = "purchase from peer enabled at " + remoteProfile.SellAt.String() + " wei/chunk" } else { buy = "purchase from peer disabled" } - if self.Sells { - sell = "selling to peer enabled at " + local.SellAt.String() + " wei/chunk" + if swapInstance.Sells { + sell = "selling to peer enabled at " + localProfile.SellAt.String() + " wei/chunk" } else { sell = "selling to peer disabled" } @@ -184,66 +192,69 @@ func NewSwap(local *SwapParams, remote *SwapProfile, backend chequebook.Backend, return } -func (self *SwapParams) Chequebook() *chequebook.Chequebook { - defer self.lock.Unlock() - self.lock.Lock() - return self.chbook +// Chequebook get's chequebook from the localProfile +func (lp *LocalProfile) Chequebook() *chequebook.Chequebook { + defer lp.lock.Unlock() + lp.lock.Lock() + return lp.chbook } -func (self *SwapParams) PrivateKey() *ecdsa.PrivateKey { - return self.privateKey +// PrivateKey accessor +func (lp *LocalProfile) PrivateKey() *ecdsa.PrivateKey { + return lp.privateKey } -// func (self *SwapParams) PublicKey() *ecdsa.PublicKey { +// func (self *LocalProfile) PublicKey() *ecdsa.PublicKey { // return self.publicKey // } -func (self *SwapParams) SetKey(prvkey *ecdsa.PrivateKey) { - self.privateKey = prvkey - self.publicKey = &prvkey.PublicKey +// SetKey set's private and public key on localProfile +func (lp *LocalProfile) SetKey(prvkey *ecdsa.PrivateKey) { + lp.privateKey = prvkey + lp.publicKey = &prvkey.PublicKey } -// setChequebook(path, backend) wraps the -// chequebook initialiser and sets up autoDeposit to cover spending. -func (self *SwapParams) SetChequebook(ctx context.Context, backend chequebook.Backend, path string) error { - self.lock.Lock() - contract := self.Contract - self.lock.Unlock() +// SetChequebook wraps the chequebook initialiser and sets up autoDeposit to cover spending. +func (lp *LocalProfile) SetChequebook(ctx context.Context, backend chequebook.Backend, path string) error { + lp.lock.Lock() + swapContract := lp.Contract + lp.lock.Unlock() - valid, err := chequebook.ValidateCode(ctx, backend, contract) + valid, err := chequebook.ValidateCode(ctx, backend, swapContract) if err != nil { return err } else if valid { - return self.newChequebookFromContract(path, backend) + return lp.newChequebookFromContract(path, backend) } - return self.deployChequebook(ctx, backend, path) + return lp.deployChequebook(ctx, backend, path) } -func (self *SwapParams) deployChequebook(ctx context.Context, backend chequebook.Backend, path string) error { - opts := bind.NewKeyedTransactor(self.privateKey) - opts.Value = self.AutoDepositBuffer +// deployChequebook deploys the localProfile Chequebook +func (lp *LocalProfile) deployChequebook(ctx context.Context, backend chequebook.Backend, path string) error { + opts := bind.NewKeyedTransactor(lp.privateKey) + opts.Value = lp.AutoDepositBuffer opts.Context = ctx log.Info(fmt.Sprintf("Deploying new chequebook (owner: %v)", opts.From.Hex())) - contract, err := deployChequebookLoop(opts, backend) + address, err := deployChequebookLoop(opts, backend) if err != nil { log.Error(fmt.Sprintf("unable to deploy new chequebook: %v", err)) return err } - log.Info(fmt.Sprintf("new chequebook deployed at %v (owner: %v)", contract.Hex(), opts.From.Hex())) + log.Info(fmt.Sprintf("new chequebook deployed at %v (owner: %v)", address.Hex(), opts.From.Hex())) // need to save config at this point - self.lock.Lock() - self.Contract = contract - err = self.newChequebookFromContract(path, backend) - self.lock.Unlock() + lp.lock.Lock() + lp.Contract = address + err = lp.newChequebookFromContract(path, backend) + lp.lock.Unlock() if err != nil { log.Warn(fmt.Sprintf("error initialising cheque book (owner: %v): %v", opts.From.Hex(), err)) } return err } -// repeatedly tries to deploy a chequebook. +// deployChequebookLoop repeatedly tries to deploy a chequebook. func deployChequebookLoop(opts *bind.TransactOpts, backend chequebook.Backend) (addr common.Address, err error) { var tx *types.Transaction for try := 0; try < chequebookDeployRetries; try++ { @@ -263,28 +274,28 @@ func deployChequebookLoop(opts *bind.TransactOpts, backend chequebook.Backend) ( return addr, err } -// initialise the chequebook from a persisted json file or create a new one +// newChequebookFromContract - initialise the chequebook from a persisted json file or create a new one // caller holds the lock -func (self *SwapParams) newChequebookFromContract(path string, backend chequebook.Backend) error { - hexkey := common.Bytes2Hex(self.Contract.Bytes()) +func (lp *LocalProfile) newChequebookFromContract(path string, backend chequebook.Backend) error { + hexkey := common.Bytes2Hex(lp.Contract.Bytes()) err := os.MkdirAll(filepath.Join(path, "chequebooks"), os.ModePerm) if err != nil { return fmt.Errorf("unable to create directory for chequebooks: %v", err) } chbookpath := filepath.Join(path, "chequebooks", hexkey+".json") - self.chbook, err = chequebook.LoadChequebook(chbookpath, self.privateKey, backend, true) + lp.chbook, err = chequebook.LoadChequebook(chbookpath, lp.privateKey, backend, true) if err != nil { - self.chbook, err = chequebook.NewChequebook(chbookpath, self.Contract, self.privateKey, backend) + lp.chbook, err = chequebook.NewChequebook(chbookpath, lp.Contract, lp.privateKey, backend) if err != nil { - log.Warn(fmt.Sprintf("unable to initialise chequebook (owner: %v): %v", self.owner.Hex(), err)) - return fmt.Errorf("unable to initialise chequebook (owner: %v): %v", self.owner.Hex(), err) + log.Warn(fmt.Sprintf("unable to initialise chequebook (owner: %v): %v", lp.owner.Hex(), err)) + return fmt.Errorf("unable to initialise chequebook (owner: %v): %v", lp.owner.Hex(), err) } } - self.chbook.AutoDeposit(self.AutoDepositInterval, self.AutoDepositThreshold, self.AutoDepositBuffer) - log.Info(fmt.Sprintf("auto deposit ON for %v -> %v: interval = %v, threshold = %v, buffer = %v)", crypto.PubkeyToAddress(*(self.publicKey)).Hex()[:8], self.Contract.Hex()[:8], self.AutoDepositInterval, self.AutoDepositThreshold, self.AutoDepositBuffer)) + lp.chbook.AutoDeposit(lp.AutoDepositInterval, lp.AutoDepositThreshold, lp.AutoDepositBuffer) + log.Info(fmt.Sprintf("auto deposit ON for %v -> %v: interval = %v, threshold = %v, buffer = %v)", crypto.PubkeyToAddress(*(lp.publicKey)).Hex()[:8], lp.Contract.Hex()[:8], lp.AutoDepositInterval, lp.AutoDepositThreshold, lp.AutoDepositBuffer)) return nil } diff --git a/swarm/services/swap/swap/swap.go b/swarm/services/swap/swap/swap.go index a78f1f0e2a..0afca9ab30 100644 --- a/swarm/services/swap/swap/swap.go +++ b/swarm/services/swap/swap/swap.go @@ -22,14 +22,14 @@ import ( "sync" "time" - "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/swarm/log" ) // SwAP Swarm Accounting Protocol with // Swift Automatic Payments // a peer to peer micropayment system -// public swap profile +// Profile - public swap profile // public parameters for SWAP, serializable config struct passed in handshake type Profile struct { BuyAt *big.Int // accepted max price for chunk @@ -55,34 +55,33 @@ type Params struct { *Strategy } -// Promise -// 3rd party Provable Promise of Payment +// Promise - 3rd party Provable Promise of Payment // issued by outPayment -// serialisable to send with Protocol +// serializable to send with Protocol type Promise interface{} -// interface for the peer protocol for testing or external alternative payment +// Protocol interface for the peer protocol for testing or external alternative payment type Protocol interface { Pay(int, Promise) // units, payment proof Drop() String() string } -// interface for the (delayed) ougoing payment system with autodeposit +// OutPayment interface for the (delayed) outgoing payment system with auto-deposit type OutPayment interface { Issue(amount *big.Int) (promise Promise, err error) AutoDeposit(interval time.Duration, threshold, buffer *big.Int) Stop() } -// interface for the (delayed) incoming payment system with autocash +// InPayment interface for the (delayed) incoming payment system with autocash type InPayment interface { Receive(promise Promise) (*big.Int, error) AutoCash(cashInterval time.Duration, maxUncashed *big.Int) Stop() } -// swap is the swarm accounting protocol instance +// Swap is the swarm accounting protocol instance // * pairwise accounting and payments type Swap struct { lock sync.Mutex // mutex for balance access @@ -93,160 +92,161 @@ type Swap struct { Payment } +// Payment handlers type Payment struct { Out OutPayment // outgoing payment handler In InPayment // incoming payment handler Buys, Sells bool } -// swap constructor -func New(local *Params, pm Payment, proto Protocol) (self *Swap, err error) { +// New - swap constructor +func New(local *Params, pm Payment, proto Protocol) (swap *Swap, err error) { - self = &Swap{ + swap = &Swap{ local: local, Payment: pm, proto: proto, } - self.SetParams(local) + swap.SetParams(local) return } -// entry point for setting remote swap profile (e.g from handshake or other message) -func (self *Swap) SetRemote(remote *Profile) { - defer self.lock.Unlock() - self.lock.Lock() +// SetRemote - entry point for setting remote swap profile (e.g from handshake or other message) +func (swap *Swap) SetRemote(remote *Profile) { + defer swap.lock.Unlock() + swap.lock.Lock() - self.remote = remote - if self.Sells && (remote.BuyAt.Sign() <= 0 || self.local.SellAt.Sign() <= 0 || remote.BuyAt.Cmp(self.local.SellAt) < 0) { - self.Out.Stop() - self.Sells = false + swap.remote = remote + if swap.Sells && (remote.BuyAt.Sign() <= 0 || swap.local.SellAt.Sign() <= 0 || remote.BuyAt.Cmp(swap.local.SellAt) < 0) { + swap.Out.Stop() + swap.Sells = false } - if self.Buys && (remote.SellAt.Sign() <= 0 || self.local.BuyAt.Sign() <= 0 || self.local.BuyAt.Cmp(self.remote.SellAt) < 0) { - self.In.Stop() - self.Buys = false + if swap.Buys && (remote.SellAt.Sign() <= 0 || swap.local.BuyAt.Sign() <= 0 || swap.local.BuyAt.Cmp(swap.remote.SellAt) < 0) { + swap.In.Stop() + swap.Buys = false } - log.Debug(fmt.Sprintf("<%v> remote profile set: pay at: %v, drop at: %v, buy at: %v, sell at: %v", self.proto, remote.PayAt, remote.DropAt, remote.BuyAt, remote.SellAt)) + log.Debug(fmt.Sprintf("<%v> remote profile set: pay at: %v, drop at: %v, buy at: %v, sell at: %v", swap.proto, remote.PayAt, remote.DropAt, remote.BuyAt, remote.SellAt)) } -// to set strategy dynamically -func (self *Swap) SetParams(local *Params) { - defer self.lock.Unlock() - self.lock.Lock() - self.local = local - self.setParams(local) +// SetParams - to set strategy dynamically +func (swap *Swap) SetParams(local *Params) { + defer swap.lock.Unlock() + swap.lock.Lock() + swap.local = local + swap.setParams(local) } -// caller holds the lock +// setParams - caller holds the lock +func (swap *Swap) setParams(local *Params) { -func (self *Swap) setParams(local *Params) { - - if self.Sells { - self.In.AutoCash(local.AutoCashInterval, local.AutoCashThreshold) - log.Info(fmt.Sprintf("<%v> set autocash to every %v, max uncashed limit: %v", self.proto, local.AutoCashInterval, local.AutoCashThreshold)) + if swap.Sells { + swap.In.AutoCash(local.AutoCashInterval, local.AutoCashThreshold) + log.Info(fmt.Sprintf("<%v> set autocash to every %v, max uncashed limit: %v", swap.proto, local.AutoCashInterval, local.AutoCashThreshold)) } else { - log.Info(fmt.Sprintf("<%v> autocash off (not selling)", self.proto)) + log.Info(fmt.Sprintf("<%v> autocash off (not selling)", swap.proto)) } - if self.Buys { - self.Out.AutoDeposit(local.AutoDepositInterval, local.AutoDepositThreshold, local.AutoDepositBuffer) - log.Info(fmt.Sprintf("<%v> set autodeposit to every %v, pay at: %v, buffer: %v", self.proto, local.AutoDepositInterval, local.AutoDepositThreshold, local.AutoDepositBuffer)) + if swap.Buys { + swap.Out.AutoDeposit(local.AutoDepositInterval, local.AutoDepositThreshold, local.AutoDepositBuffer) + log.Info(fmt.Sprintf("<%v> set autodeposit to every %v, pay at: %v, buffer: %v", swap.proto, local.AutoDepositInterval, local.AutoDepositThreshold, local.AutoDepositBuffer)) } else { - log.Info(fmt.Sprintf("<%v> autodeposit off (not buying)", self.proto)) + log.Info(fmt.Sprintf("<%v> autodeposit off (not buying)", swap.proto)) } } -// Add(n) +// Add (n) // n > 0 called when promised/provided n units of service // n < 0 called when used/requested n units of service -func (self *Swap) Add(n int) error { - defer self.lock.Unlock() - self.lock.Lock() - self.balance += n - if !self.Sells && self.balance > 0 { - log.Trace(fmt.Sprintf("<%v> remote peer cannot have debt (balance: %v)", self.proto, self.balance)) - self.proto.Drop() - return fmt.Errorf("[SWAP] <%v> remote peer cannot have debt (balance: %v)", self.proto, self.balance) +func (swap *Swap) Add(n int) error { + defer swap.lock.Unlock() + swap.lock.Lock() + swap.balance += n + if !swap.Sells && swap.balance > 0 { + log.Trace(fmt.Sprintf("<%v> remote peer cannot have debt (balance: %v)", swap.proto, swap.balance)) + swap.proto.Drop() + return fmt.Errorf("[SWAP] <%v> remote peer cannot have debt (balance: %v)", swap.proto, swap.balance) } - if !self.Buys && self.balance < 0 { - log.Trace(fmt.Sprintf("<%v> we cannot have debt (balance: %v)", self.proto, self.balance)) - return fmt.Errorf("[SWAP] <%v> we cannot have debt (balance: %v)", self.proto, self.balance) + if !swap.Buys && swap.balance < 0 { + log.Trace(fmt.Sprintf("<%v> we cannot have debt (balance: %v)", swap.proto, swap.balance)) + return fmt.Errorf("[SWAP] <%v> we cannot have debt (balance: %v)", swap.proto, swap.balance) } - if self.balance >= int(self.local.DropAt) { - log.Trace(fmt.Sprintf("<%v> remote peer has too much debt (balance: %v, disconnect threshold: %v)", self.proto, self.balance, self.local.DropAt)) - self.proto.Drop() - return fmt.Errorf("[SWAP] <%v> remote peer has too much debt (balance: %v, disconnect threshold: %v)", self.proto, self.balance, self.local.DropAt) - } else if self.balance <= -int(self.remote.PayAt) { - self.send() + if swap.balance >= int(swap.local.DropAt) { + log.Trace(fmt.Sprintf("<%v> remote peer has too much debt (balance: %v, disconnect threshold: %v)", swap.proto, swap.balance, swap.local.DropAt)) + swap.proto.Drop() + return fmt.Errorf("[SWAP] <%v> remote peer has too much debt (balance: %v, disconnect threshold: %v)", swap.proto, swap.balance, swap.local.DropAt) + } else if swap.balance <= -int(swap.remote.PayAt) { + swap.send() } return nil } -func (self *Swap) Balance() int { - defer self.lock.Unlock() - self.lock.Lock() - return self.balance +// Balance accessor +func (swap *Swap) Balance() int { + defer swap.lock.Unlock() + swap.lock.Lock() + return swap.balance } -// send(units) is called when payment is due +// send (units) is called when payment is due // In case of insolvency no promise is issued and sent, safe against fraud // No return value: no error = payment is opportunistic = hang in till dropped -func (self *Swap) send() { - if self.local.BuyAt != nil && self.balance < 0 { - amount := big.NewInt(int64(-self.balance)) - amount.Mul(amount, self.remote.SellAt) - promise, err := self.Out.Issue(amount) +func (swap *Swap) send() { + if swap.local.BuyAt != nil && swap.balance < 0 { + amount := big.NewInt(int64(-swap.balance)) + amount.Mul(amount, swap.remote.SellAt) + promise, err := swap.Out.Issue(amount) if err != nil { - log.Warn(fmt.Sprintf("<%v> cannot issue cheque (amount: %v, channel: %v): %v", self.proto, amount, self.Out, err)) + log.Warn(fmt.Sprintf("<%v> cannot issue cheque (amount: %v, channel: %v): %v", swap.proto, amount, swap.Out, err)) } else { - log.Warn(fmt.Sprintf("<%v> cheque issued (amount: %v, channel: %v)", self.proto, amount, self.Out)) - self.proto.Pay(-self.balance, promise) - self.balance = 0 + log.Warn(fmt.Sprintf("<%v> cheque issued (amount: %v, channel: %v)", swap.proto, amount, swap.Out)) + swap.proto.Pay(-swap.balance, promise) + swap.balance = 0 } } } -// receive(units, promise) is called by the protocol when a payment msg is received +// Receive (units, promise) is called by the protocol when a payment msg is received // returns error if promise is invalid. -func (self *Swap) Receive(units int, promise Promise) error { +func (swap *Swap) Receive(units int, promise Promise) error { if units <= 0 { return fmt.Errorf("invalid units: %v <= 0", units) } price := new(big.Int).SetInt64(int64(units)) - price.Mul(price, self.local.SellAt) + price.Mul(price, swap.local.SellAt) - amount, err := self.In.Receive(promise) + amount, err := swap.In.Receive(promise) if err != nil { err = fmt.Errorf("invalid promise: %v", err) } else if price.Cmp(amount) != 0 { // verify amount = units * unit sale price - return fmt.Errorf("invalid amount: %v = %v * %v (units sent in msg * agreed sale unit price) != %v (signed in cheque)", price, units, self.local.SellAt, amount) + return fmt.Errorf("invalid amount: %v = %v * %v (units sent in msg * agreed sale unit price) != %v (signed in cheque)", price, units, swap.local.SellAt, amount) } if err != nil { - log.Trace(fmt.Sprintf("<%v> invalid promise (amount: %v, channel: %v): %v", self.proto, amount, self.In, err)) + log.Trace(fmt.Sprintf("<%v> invalid promise (amount: %v, channel: %v): %v", swap.proto, amount, swap.In, err)) return err } // credit remote peer with units - self.Add(-units) - log.Trace(fmt.Sprintf("<%v> received promise (amount: %v, channel: %v): %v", self.proto, amount, self.In, promise)) + swap.Add(-units) + log.Trace(fmt.Sprintf("<%v> received promise (amount: %v, channel: %v): %v", swap.proto, amount, swap.In, promise)) return nil } -// stop() causes autocash loop to terminate. +// Stop causes autocash loop to terminate. // Called after protocol handle loop terminates. -func (self *Swap) Stop() { - defer self.lock.Unlock() - self.lock.Lock() - if self.Buys { - self.Out.Stop() +func (swap *Swap) Stop() { + defer swap.lock.Unlock() + swap.lock.Lock() + if swap.Buys { + swap.Out.Stop() } - if self.Sells { - self.In.Stop() + if swap.Sells { + swap.In.Stop() } } diff --git a/swarm/services/swap/swap/swap_test.go b/swarm/services/swap/swap/swap_test.go index 222e0770f3..d0e34f8a54 100644 --- a/swarm/services/swap/swap/swap_test.go +++ b/swarm/services/swap/swap/swap_test.go @@ -34,20 +34,20 @@ type testPromise struct { amount *big.Int } -func (self *testInPayment) Receive(promise Promise) (*big.Int, error) { +func (test *testInPayment) Receive(promise Promise) (*big.Int, error) { p := promise.(*testPromise) - self.received = append(self.received, p) + test.received = append(test.received, p) return p.amount, nil } -func (self *testInPayment) AutoCash(interval time.Duration, limit *big.Int) { - self.autocashInterval = interval - self.autocashLimit = limit +func (test *testInPayment) AutoCash(interval time.Duration, limit *big.Int) { + test.autocashInterval = interval + test.autocashLimit = limit } -func (self *testInPayment) Cash() (string, error) { return "", nil } +func (test *testInPayment) Cash() (string, error) { return "", nil } -func (self *testInPayment) Stop() {} +func (test *testInPayment) Stop() {} type testOutPayment struct { deposits []*big.Int @@ -56,22 +56,22 @@ type testOutPayment struct { autodepositBuffer *big.Int } -func (self *testOutPayment) Issue(amount *big.Int) (promise Promise, err error) { +func (test *testOutPayment) Issue(amount *big.Int) (promise Promise, err error) { return &testPromise{amount}, nil } -func (self *testOutPayment) Deposit(amount *big.Int) (string, error) { - self.deposits = append(self.deposits, amount) +func (test *testOutPayment) Deposit(amount *big.Int) (string, error) { + test.deposits = append(test.deposits, amount) return "", nil } -func (self *testOutPayment) AutoDeposit(interval time.Duration, threshold, buffer *big.Int) { - self.autodepositInterval = interval - self.autodepositThreshold = threshold - self.autodepositBuffer = buffer +func (test *testOutPayment) AutoDeposit(interval time.Duration, threshold, buffer *big.Int) { + test.autodepositInterval = interval + test.autodepositThreshold = threshold + test.autodepositBuffer = buffer } -func (self *testOutPayment) Stop() {} +func (test *testOutPayment) Stop() {} type testProtocol struct { drop bool @@ -79,18 +79,18 @@ type testProtocol struct { promises []*testPromise } -func (self *testProtocol) Drop() { - self.drop = true +func (test *testProtocol) Drop() { + test.drop = true } -func (self *testProtocol) String() string { +func (test *testProtocol) String() string { return "" } -func (self *testProtocol) Pay(amount int, promise Promise) { +func (test *testProtocol) Pay(amount int, promise Promise) { p := promise.(*testPromise) - self.promises = append(self.promises, p) - self.amounts = append(self.amounts, amount) + test.promises = append(test.promises, p) + test.amounts = append(test.amounts, amount) } func TestSwap(t *testing.T) { diff --git a/swarm/shed/db.go b/swarm/shed/db.go new file mode 100644 index 0000000000..6f6b164501 --- /dev/null +++ b/swarm/shed/db.go @@ -0,0 +1,309 @@ +// 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 +} + +// 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/swarm/shed/db_test.go b/swarm/shed/db_test.go new file mode 100644 index 0000000000..4e8276f746 --- /dev/null +++ b/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/swarm/shed/example_store_test.go b/swarm/shed/example_store_test.go new file mode 100644 index 0000000000..9a83855e70 --- /dev/null +++ b/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/swarm/shed/field_string.go b/swarm/shed/field_string.go new file mode 100644 index 0000000000..a7e8f0c754 --- /dev/null +++ b/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/swarm/shed/field_string_test.go b/swarm/shed/field_string_test.go new file mode 100644 index 0000000000..4215075bca --- /dev/null +++ b/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/swarm/shed/field_struct.go b/swarm/shed/field_struct.go new file mode 100644 index 0000000000..90daee7fc4 --- /dev/null +++ b/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/swarm/shed/field_struct_test.go b/swarm/shed/field_struct_test.go new file mode 100644 index 0000000000..cc0be01863 --- /dev/null +++ b/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/swarm/shed/field_uint64.go b/swarm/shed/field_uint64.go new file mode 100644 index 0000000000..0417583ac3 --- /dev/null +++ b/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/swarm/shed/field_uint64_test.go b/swarm/shed/field_uint64_test.go new file mode 100644 index 0000000000..9462b56dd1 --- /dev/null +++ b/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/swarm/shed/index.go b/swarm/shed/index.go new file mode 100644 index 0000000000..d02bf1a004 --- /dev/null +++ b/swarm/shed/index.go @@ -0,0 +1,381 @@ +// 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 +} + +// 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/swarm/shed/index_test.go b/swarm/shed/index_test.go new file mode 100644 index 0000000000..489f001bd6 --- /dev/null +++ b/swarm/shed/index_test.go @@ -0,0 +1,927 @@ +// 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 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("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/swarm/shed/schema.go b/swarm/shed/schema.go new file mode 100644 index 0000000000..cfb7c6d642 --- /dev/null +++ b/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/swarm/shed/schema_test.go b/swarm/shed/schema_test.go new file mode 100644 index 0000000000..a0c1838c8b --- /dev/null +++ b/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/swarm/spancontext/spancontext.go b/swarm/spancontext/spancontext.go new file mode 100644 index 0000000000..2cb9f82f7c --- /dev/null +++ b/swarm/spancontext/spancontext.go @@ -0,0 +1,49 @@ +package spancontext + +import ( + "context" + + opentracing "github.com/opentracing/opentracing-go" +) + +func WithContext(ctx context.Context, sctx opentracing.SpanContext) context.Context { + return context.WithValue(ctx, "span_context", sctx) +} + +func FromContext(ctx context.Context) opentracing.SpanContext { + sctx, ok := ctx.Value("span_context").(opentracing.SpanContext) + if ok { + return sctx + } + + return nil +} + +func StartSpan(ctx context.Context, name string) (context.Context, opentracing.Span) { + tracer := opentracing.GlobalTracer() + + sctx := FromContext(ctx) + + var sp opentracing.Span + if sctx != nil { + sp = tracer.StartSpan( + name, + opentracing.ChildOf(sctx)) + } else { + sp = tracer.StartSpan(name) + } + + nctx := context.WithValue(ctx, "span_context", sp.Context()) + + return nctx, sp +} + +func StartSpanFrom(name string, sctx opentracing.SpanContext) opentracing.Span { + tracer := opentracing.GlobalTracer() + + sp := tracer.StartSpan( + name, + opentracing.ChildOf(sctx)) + + return sp +} diff --git a/swarm/state/dbstore.go b/swarm/state/dbstore.go new file mode 100644 index 0000000000..1b541e7854 --- /dev/null +++ b/swarm/state/dbstore.go @@ -0,0 +1,111 @@ +// 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" + "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") + +// 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 { + db *leveldb.DB +} + +// NewDBStore creates a new instance of DBStore. +func NewDBStore(path string) (s *DBStore, err error) { + db, err := leveldb.OpenFile(path, nil) + if err != nil { + return nil, err + } + return &DBStore{ + db: db, + }, 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 +func (s *DBStore) Get(key string, i interface{}) (err error) { + has, err := s.db.Has([]byte(key), nil) + if err != nil || !has { + return ErrNotFound + } + + data, err := s.db.Get([]byte(key), nil) + if err == leveldb.ErrNotFound { + return ErrNotFound + } + + unmarshaler, ok := i.(encoding.BinaryUnmarshaler) + if !ok { + return json.Unmarshal(data, i) + } + return unmarshaler.UnmarshalBinary(data) +} + +// Put stores an object that implements Binary for a specific key. +func (s *DBStore) Put(key string, i interface{}) (err error) { + var bytes []byte + 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) +} + +// Delete removes entries stored under a specific key. +func (s *DBStore) Delete(key string) (err error) { + return s.db.Delete([]byte(key), nil) +} + +// Close releases the resources used by the underlying LevelDB. +func (s *DBStore) Close() error { + return s.db.Close() +} diff --git a/swarm/state/dbstore_test.go b/swarm/state/dbstore_test.go new file mode 100644 index 0000000000..f7098956d0 --- /dev/null +++ b/swarm/state/dbstore_test.go @@ -0,0 +1,125 @@ +// 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 ( + "bytes" + "errors" + "io/ioutil" + "os" + "strings" + "testing" +) + +var ErrInvalidArraySize = errors.New("invalid byte array size") +var ErrInvalidValuePersisted = errors.New("invalid value was persisted to the db") + +type SerializingType struct { + key string + value string +} + +func (st *SerializingType) MarshalBinary() (data []byte, err error) { + d := []byte(strings.Join([]string{st.key, st.value}, ";")) + + return d, nil +} + +func (st *SerializingType) UnmarshalBinary(data []byte) (err error) { + d := bytes.Split(data, []byte(";")) + l := len(d) + if l == 0 { + return ErrInvalidArraySize + } + if l == 2 { + keyLen := len(d[0]) + st.key = string(d[0][:keyLen]) + + valLen := len(d[1]) + st.value = string(d[1][:valLen]) + } + + return nil +} + +// TestDBStore tests basic functionality of DBStore. +func TestDBStore(t *testing.T) { + dir, err := ioutil.TempDir("", "db_store_test") + if err != nil { + panic(err) + } + defer os.RemoveAll(dir) + + store, err := NewDBStore(dir) + if err != nil { + t.Fatal(err) + } + + testStore(t, store) + + store.Close() + + persistedStore, err := NewDBStore(dir) + if err != nil { + t.Fatal(err) + } + defer persistedStore.Close() + + testPersistedStore(t, persistedStore) +} + +func testStore(t *testing.T, store Store) { + ser := &SerializingType{key: "key1", value: "value1"} + jsonify := []string{"a", "b", "c"} + + err := store.Put(ser.key, ser) + if err != nil { + t.Fatal(err) + } + + err = store.Put("key2", jsonify) + if err != nil { + t.Fatal(err) + } + +} + +func testPersistedStore(t *testing.T, store Store) { + ser := &SerializingType{} + + err := store.Get("key1", ser) + if err != nil { + t.Fatal(err) + } + + if ser.key != "key1" || ser.value != "value1" { + t.Fatal(ErrInvalidValuePersisted) + } + + as := []string{} + err = store.Get("key2", &as) + if err != nil { + t.Fatal(err) + } + + if len(as) != 3 { + t.Fatalf("serialized array did not match expectation") + } + if as[0] != "a" || as[1] != "b" || as[2] != "c" { + t.Fatalf("elements serialized did not match expected values") + } +} diff --git a/swarm/storage/chunker.go b/swarm/storage/chunker.go index 98cd6e75ea..5b36b477e0 100644 --- a/swarm/storage/chunker.go +++ b/swarm/storage/chunker.go @@ -13,16 +13,23 @@ // // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . - package storage import ( + "context" "encoding/binary" "errors" "fmt" "io" "sync" "time" + + "github.com/ethereum/go-ethereum/metrics" + "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" + olog "github.com/opentracing/opentracing-go/log" ) /* @@ -58,129 +65,210 @@ 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") - errOperationTimedOut = errors.New("operation timed out") -) +type ChunkerParams struct { + chunkSize int64 + hashSize int64 +} + +type SplitterParams struct { + ChunkerParams + reader io.Reader + putter Putter + addr Address +} + +type TreeSplitterParams struct { + SplitterParams + size int64 +} + +type JoinerParams struct { + ChunkerParams + addr Address + getter Getter + // TODO: there is a bug, so depth can only be 0 today, see: https://github.com/ethersphere/go-ethereum/issues/344 + depth int + ctx context.Context +} type TreeChunker struct { + ctx context.Context + branches int64 - hashFunc SwarmHasher + dataSize int64 + data io.Reader // calculated + addr Address + depth int hashSize int64 // self.hashFunc.New().Size() chunkSize int64 // hashSize* branches workerCount int64 // the number of worker routines used workerLock sync.RWMutex // lock for the worker count + jobC chan *hashJob + wg *sync.WaitGroup + putter Putter + getter Getter + errC chan error + quitC chan bool } -func NewTreeChunker(params *ChunkerParams) (self *TreeChunker) { - self = &TreeChunker{} - self.hashFunc = MakeHashFunc(params.Hash) - self.branches = params.Branches - self.hashSize = int64(self.hashFunc().Size()) - self.chunkSize = self.hashSize * self.branches - self.workerCount = 0 +/* + Join reconstructs original content based on a root key. + When joining, the caller gets returned a Lazy SectionReader, which is + seekable and implements on-demand fetching of chunks as and where it is read. + New chunks to retrieve are coming from the getter, which the caller provides. + If an error is encountered during joining, it appears as a reader error. + The SectionReader. + As a result, partial reads from a document are possible even if other parts + are corrupt or lost. + The chunks are not meant to be validated by the chunker when joining. This + is because it is left to the DPA to decide which sources are trusted. +*/ +func TreeJoin(ctx context.Context, addr Address, getter Getter, depth int) *LazyChunkReader { + jp := &JoinerParams{ + ChunkerParams: ChunkerParams{ + chunkSize: chunk.DefaultSize, + hashSize: int64(len(addr)), + }, + addr: addr, + getter: getter, + depth: depth, + ctx: ctx, + } - return + return NewTreeJoiner(jp).Join(ctx) } -// func (self *TreeChunker) KeySize() int64 { -// return self.hashSize -// } +/* + When splitting, data is given as a SectionReader, and the key is a hashSize long byte slice (Key), the root hash of the entire content will fill this once processing finishes. + New chunks to store are store using the putter which the caller provides. +*/ +func TreeSplit(ctx context.Context, data io.Reader, size int64, putter Putter) (k Address, wait func(context.Context) error, err error) { + tsp := &TreeSplitterParams{ + SplitterParams: SplitterParams{ + ChunkerParams: ChunkerParams{ + chunkSize: chunk.DefaultSize, + hashSize: putter.RefSize(), + }, + reader: data, + putter: putter, + }, + size: size, + } + return NewTreeSplitter(tsp).Split(ctx) +} -// String() for pretty printing -func (self *Chunk) String() string { - return fmt.Sprintf("Key: %v TreeSize: %v Chunksize: %v", self.Key.Log(), self.Size, len(self.SData)) +func NewTreeJoiner(params *JoinerParams) *TreeChunker { + tc := &TreeChunker{} + tc.hashSize = params.hashSize + tc.branches = params.chunkSize / params.hashSize + tc.addr = params.addr + tc.getter = params.getter + tc.depth = params.depth + tc.chunkSize = params.chunkSize + tc.workerCount = 0 + tc.jobC = make(chan *hashJob, 2*ChunkProcessors) + tc.wg = &sync.WaitGroup{} + tc.errC = make(chan error) + tc.quitC = make(chan bool) + + tc.ctx = params.ctx + + return tc +} + +func NewTreeSplitter(params *TreeSplitterParams) *TreeChunker { + tc := &TreeChunker{} + tc.data = params.reader + tc.dataSize = params.size + tc.hashSize = params.hashSize + tc.branches = params.chunkSize / params.hashSize + tc.addr = params.addr + tc.chunkSize = params.chunkSize + tc.putter = params.putter + tc.workerCount = 0 + tc.jobC = make(chan *hashJob, 2*ChunkProcessors) + tc.wg = &sync.WaitGroup{} + tc.errC = make(chan error) + tc.quitC = make(chan bool) + + return tc } type hashJob struct { - key Key + key Address chunk []byte size int64 parentWg *sync.WaitGroup } -func (self *TreeChunker) incrementWorkerCount() { - self.workerLock.Lock() - defer self.workerLock.Unlock() - self.workerCount += 1 +func (tc *TreeChunker) incrementWorkerCount() { + tc.workerLock.Lock() + defer tc.workerLock.Unlock() + tc.workerCount += 1 } -func (self *TreeChunker) getWorkerCount() int64 { - self.workerLock.RLock() - defer self.workerLock.RUnlock() - return self.workerCount +func (tc *TreeChunker) getWorkerCount() int64 { + tc.workerLock.RLock() + defer tc.workerLock.RUnlock() + return tc.workerCount } -func (self *TreeChunker) decrementWorkerCount() { - self.workerLock.Lock() - defer self.workerLock.Unlock() - self.workerCount -= 1 +func (tc *TreeChunker) decrementWorkerCount() { + tc.workerLock.Lock() + defer tc.workerLock.Unlock() + tc.workerCount -= 1 } -func (self *TreeChunker) Split(data io.Reader, size int64, chunkC chan *Chunk, swg, wwg *sync.WaitGroup) (Key, error) { - if self.chunkSize <= 0 { +func (tc *TreeChunker) Split(ctx context.Context) (k Address, wait func(context.Context) error, err error) { + if tc.chunkSize <= 0 { panic("chunker must be initialised") } - jobC := make(chan *hashJob, 2*ChunkProcessors) - wg := &sync.WaitGroup{} - errC := make(chan error) - quitC := make(chan bool) - - // wwg = workers waitgroup keeps track of hashworkers spawned by this split call - if wwg != nil { - wwg.Add(1) - } - - self.incrementWorkerCount() - go self.hashWorker(jobC, chunkC, errC, quitC, swg, wwg) + tc.runWorker(ctx) depth := 0 - treeSize := self.chunkSize + treeSize := tc.chunkSize // takes lowest depth such that chunksize*HashCount^(depth+1) > size // power series, will find the order of magnitude of the data size in base hashCount or numbers of levels of branching in the resulting tree. - for ; treeSize < size; treeSize *= self.branches { + for ; treeSize < tc.dataSize; treeSize *= tc.branches { depth++ } - key := make([]byte, self.hashFunc().Size()) + key := make([]byte, tc.hashSize) // this waitgroup member is released after the root hash is calculated - wg.Add(1) + tc.wg.Add(1) //launch actual recursive function passing the waitgroups - go self.split(depth, treeSize/self.branches, key, data, size, jobC, chunkC, errC, quitC, wg, swg, wwg) + go tc.split(ctx, depth, treeSize/tc.branches, key, tc.dataSize, tc.wg) // closes internal error channel if all subprocesses in the workgroup finished go func() { // waiting for all threads to finish - wg.Wait() - // if storage waitgroup is non-nil, we wait for storage to finish too - if swg != nil { - swg.Wait() - } - close(errC) + tc.wg.Wait() + close(tc.errC) }() - defer close(quitC) + defer close(tc.quitC) + defer tc.putter.Close() select { - case err := <-errC: + case err := <-tc.errC: if err != nil { - return nil, err + return nil, nil, err } - case <-time.NewTimer(splitTimeout).C: - return nil, errOperationTimedOut + case <-ctx.Done(): + return nil, nil, ctx.Err() } - return key, nil + return key, tc.putter.Wait, nil } -func (self *TreeChunker) split(depth int, treeSize int64, key Key, data io.Reader, size int64, jobC chan *hashJob, chunkC chan *Chunk, errC chan error, quitC chan bool, parentWg, swg, wwg *sync.WaitGroup) { +func (tc *TreeChunker) split(ctx context.Context, depth int, treeSize int64, addr Address, size int64, parentWg *sync.WaitGroup) { // for depth > 0 && size < treeSize { - treeSize /= self.branches + treeSize /= tc.branches depth-- } @@ -190,16 +278,16 @@ func (self *TreeChunker) split(depth int, treeSize int64, key Key, data io.Reade binary.LittleEndian.PutUint64(chunkData[0:8], uint64(size)) var readBytes int64 for readBytes < size { - n, err := data.Read(chunkData[8+readBytes:]) + n, err := tc.data.Read(chunkData[8+readBytes:]) readBytes += int64(n) if err != nil && !(err == io.EOF && readBytes == size) { - errC <- err + tc.errC <- err return } } select { - case jobC <- &hashJob{key, chunkData, size, parentWg}: - case <-quitC: + case tc.jobC <- &hashJob{addr, chunkData, size, parentWg}: + case <-tc.quitC: } return } @@ -207,7 +295,7 @@ func (self *TreeChunker) split(depth int, treeSize int64, key Key, data io.Reade // intermediate chunk containing child nodes hashes branchCnt := (size + treeSize - 1) / treeSize - var chunk = make([]byte, branchCnt*self.hashSize+8) + var chunk = make([]byte, branchCnt*tc.hashSize+8) var pos, i int64 binary.LittleEndian.PutUint64(chunk[0:8], uint64(size)) @@ -222,10 +310,10 @@ func (self *TreeChunker) split(depth int, treeSize int64, key Key, data io.Reade secSize = treeSize } // the hash of that data - subTreeKey := chunk[8+i*self.hashSize : 8+(i+1)*self.hashSize] + subTreeAddress := chunk[8+i*tc.hashSize : 8+(i+1)*tc.hashSize] childrenWg.Add(1) - self.split(depth-1, treeSize/self.branches, subTreeKey, data, secSize, jobC, chunkC, errC, quitC, childrenWg, swg, wwg) + tc.split(ctx, depth-1, treeSize/tc.branches, subTreeAddress, secSize, childrenWg) i++ pos += treeSize @@ -235,128 +323,128 @@ func (self *TreeChunker) split(depth int, treeSize int64, key Key, data io.Reade // go func() { childrenWg.Wait() - worker := self.getWorkerCount() - if int64(len(jobC)) > worker && worker < ChunkProcessors { - if wwg != nil { - wwg.Add(1) - } - self.incrementWorkerCount() - go self.hashWorker(jobC, chunkC, errC, quitC, swg, wwg) + worker := tc.getWorkerCount() + if int64(len(tc.jobC)) > worker && worker < ChunkProcessors { + tc.runWorker(ctx) } select { - case jobC <- &hashJob{key, chunk, size, parentWg}: - case <-quitC: + case tc.jobC <- &hashJob{addr, chunk, size, parentWg}: + case <-tc.quitC: } } -func (self *TreeChunker) hashWorker(jobC chan *hashJob, chunkC chan *Chunk, errC chan error, quitC chan bool, swg, wwg *sync.WaitGroup) { - defer self.decrementWorkerCount() +func (tc *TreeChunker) runWorker(ctx context.Context) { + tc.incrementWorkerCount() + go func() { + defer tc.decrementWorkerCount() + for { + select { - hasher := self.hashFunc() - if wwg != nil { - defer wwg.Done() - } - for { - select { + case job, ok := <-tc.jobC: + if !ok { + return + } - case job, ok := <-jobC: - if !ok { + h, err := tc.putter.Put(ctx, job.chunk) + if err != nil { + tc.errC <- err + return + } + copy(job.key, h) + job.parentWg.Done() + case <-tc.quitC: return } - // now we got the hashes in the chunk, then hash the chunks - self.hashChunk(hasher, job, chunkC, swg) - case <-quitC: - return } - } -} - -// The treeChunkers own Hash hashes together -// - the size (of the subtree encoded in the Chunk) -// - the Chunk, ie. the contents read from the input reader -func (self *TreeChunker) hashChunk(hasher SwarmHash, job *hashJob, chunkC chan *Chunk, swg *sync.WaitGroup) { - hasher.ResetWithLength(job.chunk[:8]) // 8 bytes of length - hasher.Write(job.chunk[8:]) // minus 8 []byte length - h := hasher.Sum(nil) - - newChunk := &Chunk{ - Key: h, - SData: job.chunk, - Size: job.size, - wg: swg, - } - - // report hash of this chunk one level up (keys corresponds to the proper subslice of the parent chunk) - copy(job.key, h) - // send off new chunk to storage - if chunkC != nil { - if swg != nil { - swg.Add(1) - } - } - job.parentWg.Done() - - if chunkC != nil { - chunkC <- newChunk - } -} - -func (self *TreeChunker) Append(key Key, data io.Reader, chunkC chan *Chunk, swg, wwg *sync.WaitGroup) (Key, error) { - return nil, errAppendOppNotSuported + }() } // LazyChunkReader implements LazySectionReader type LazyChunkReader struct { - key Key // root key - chunkC chan *Chunk // chunk channel to send retrieve requests on - chunk *Chunk // size of the entire subtree - off int64 // offset - chunkSize int64 // inherit from chunker - branches int64 // inherit from chunker - hashSize int64 // inherit from chunker + ctx context.Context + addr Address // root address + chunkData ChunkData + off int64 // offset + chunkSize int64 // inherit from chunker + branches int64 // inherit from chunker + hashSize int64 // inherit from chunker + depth int + getter Getter } -// implements the Joiner interface -func (self *TreeChunker) Join(key Key, chunkC chan *Chunk) LazySectionReader { +func (tc *TreeChunker) Join(ctx context.Context) *LazyChunkReader { return &LazyChunkReader{ - key: key, - chunkC: chunkC, - chunkSize: self.chunkSize, - branches: self.branches, - hashSize: self.hashSize, + addr: tc.addr, + chunkSize: tc.chunkSize, + branches: tc.branches, + hashSize: tc.hashSize, + depth: tc.depth, + getter: tc.getter, + ctx: tc.ctx, } } +func (r *LazyChunkReader) Context() context.Context { + return r.ctx +} + // Size is meant to be called on the LazySectionReader -func (self *LazyChunkReader) Size(quitC chan bool) (n int64, err error) { - if self.chunk != nil { - return self.chunk.Size, nil - } - chunk := retrieve(self.key, self.chunkC, quitC) - if chunk == nil { - select { - case <-quitC: - return 0, errors.New("aborted") - default: - return 0, fmt.Errorf("root chunk not found for %v", self.key.Hex()) +func (r *LazyChunkReader) Size(ctx context.Context, quitC chan bool) (n int64, err error) { + metrics.GetOrRegisterCounter("lazychunkreader.size", nil).Inc(1) + + var sp opentracing.Span + var cctx context.Context + cctx, sp = spancontext.StartSpan( + ctx, + "lcr.size") + defer sp.Finish() + + 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 } - self.chunk = chunk - return chunk.Size, nil + + s := r.chunkData.Size() + log.Debug("lazychunkreader.size", "key", r.addr, "size", s) + + return int64(s), nil } // read at can be called numerous times // concurrent reads are allowed // Size() needs to be called synchronously on the LazyChunkReader first -func (self *LazyChunkReader) ReadAt(b []byte, off int64) (read int, err error) { +func (r *LazyChunkReader) ReadAt(b []byte, off int64) (read int, err error) { + metrics.GetOrRegisterCounter("lazychunkreader.readat", nil).Inc(1) + + var sp opentracing.Span + var cctx context.Context + cctx, sp = spancontext.StartSpan( + r.ctx, + "lcr.read") + defer sp.Finish() + + defer func() { + sp.LogFields( + olog.Int("off", int(off)), + olog.Int("read", read)) + }() + // this is correct, a swarm doc cannot be zero length, so no EOF is expected if len(b) == 0 { return 0, nil } quitC := make(chan bool) - size, err := self.Size(quitC) + size, err := r.Size(cctx, quitC) if err != nil { + log.Debug("lazychunkreader.readat.size", "size", size, "err", err) return 0, err } @@ -366,13 +454,18 @@ func (self *LazyChunkReader) ReadAt(b []byte, off int64) (read int, err error) { var treeSize int64 var depth int // calculate depth and max treeSize - treeSize = self.chunkSize - for ; treeSize < size; treeSize *= self.branches { + treeSize = r.chunkSize + for ; treeSize < size; treeSize *= r.branches { depth++ } wg := sync.WaitGroup{} + length := int64(len(b)) + for d := 0; d < r.depth; d++ { + off *= r.chunkSize + length *= r.chunkSize + } wg.Add(1) - go self.join(b, off, off+int64(len(b)), depth, treeSize/self.branches, self.chunk, &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) @@ -380,35 +473,33 @@ func (self *LazyChunkReader) ReadAt(b []byte, off int64) (read int, err error) { err = <-errC if err != nil { + log.Debug("lazychunkreader.readat.errc", "err", err) close(quitC) - return 0, err } if off+int64(len(b)) >= size { - return len(b), io.EOF + log.Debug("lazychunkreader.readat.return at end", "size", size, "off", off) + return int(size - off), io.EOF } + log.Debug("lazychunkreader.readat.errc", "buff", len(b)) return len(b), nil } -func (self *LazyChunkReader) join(b []byte, off int64, eoff int64, depth int, treeSize int64, chunk *Chunk, 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() - // return NewDPA(&LocalStore{}) - - // chunk.Size = int64(binary.LittleEndian.Uint64(chunk.SData[0:8])) - // find appropriate block level - for chunk.Size < treeSize && depth > 0 { - treeSize /= self.branches + for chunkData.Size() < uint64(treeSize) && depth > r.depth { + treeSize /= r.branches depth-- } // leaf chunk found - if depth == 0 { - extra := 8 + eoff - int64(len(chunk.SData)) + if depth == r.depth { + extra := 8 + eoff - int64(len(chunkData)) if extra > 0 { eoff -= extra } - copy(b, chunk.SData[8+off:8+eoff]) + copy(b, chunkData[8+off:8+eoff]) return // simply give back the chunks reader for content chunks } @@ -416,9 +507,14 @@ func (self *LazyChunkReader) join(b []byte, off int64, eoff int64, depth int, tr start := off / treeSize end := (eoff + treeSize - 1) / treeSize + // last non-leaf chunk can be shorter than default chunk size, let's not read it further then its end + currentBranches := int64(len(chunkData)-8) / r.hashSize + if end > currentBranches { + end = currentBranches + } + wg := &sync.WaitGroup{} defer wg.Wait() - for i := start; i < end; i++ { soff := i * treeSize roff := soff @@ -435,11 +531,22 @@ func (self *LazyChunkReader) join(b []byte, off int64, eoff int64, depth int, tr } wg.Add(1) go func(j int64) { - childKey := chunk.SData[8+j*self.hashSize : 8+(j+1)*self.hashSize] - chunk := retrieve(childKey, self.chunkC, quitC) - if chunk == nil { + childAddress := chunkData[8+j*r.hashSize : 8+(j+1)*r.hashSize] + startTime := time.Now() + chunkData, err := r.getter.Get(ctx, Reference(childAddress)) + if err != nil { + metrics.GetOrRegisterResettingTimer("lcr.getter.get.err", nil).UpdateSince(startTime) + log.Debug("lazychunkreader.join", "key", fmt.Sprintf("%x", childAddress), "err", err) select { - case errC <- fmt.Errorf("chunk %v-%v not found", off, off+treeSize): + 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): case <-quitC: } return @@ -447,73 +554,60 @@ func (self *LazyChunkReader) join(b []byte, off int64, eoff int64, depth int, tr if soff < off { soff = off } - self.join(b[soff-off:seoff-off], soff-roff, seoff-roff, depth-1, treeSize/self.branches, chunk, 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 } -// the helper method submits chunks for a key to a oueue (DPA) and -// block until they time out or arrive -// abort if quitC is readable -func retrieve(key Key, chunkC chan *Chunk, quitC chan bool) *Chunk { - chunk := &Chunk{ - Key: key, - C: make(chan bool), // close channel to signal data delivery - } - // submit chunk for retrieval - select { - case chunkC <- chunk: // submit retrieval request, someone should be listening on the other side (or we will time out globally) - case <-quitC: - return nil - } - // waiting for the chunk retrieval - select { // chunk.Size = int64(binary.LittleEndian.Uint64(chunk.SData[0:8])) - - case <-quitC: - // this is how we control process leakage (quitC is closed once join is finished (after timeout)) - return nil - case <-chunk.C: // bells are ringing, data have been delivered - } - if len(chunk.SData) == 0 { - return nil // chunk.Size = int64(binary.LittleEndian.Uint64(chunk.SData[0:8])) - - } - return chunk -} - // Read keeps a cursor so cannot be called simulateously, see ReadAt -func (self *LazyChunkReader) Read(b []byte) (read int, err error) { - read, err = self.ReadAt(b, self.off) +func (r *LazyChunkReader) Read(b []byte) (read int, err error) { + log.Debug("lazychunkreader.read", "key", r.addr) + metrics.GetOrRegisterCounter("lazychunkreader.read", nil).Inc(1) - self.off += int64(read) - return + read, err = r.ReadAt(b, r.off) + if err != nil && err != io.EOF { + log.Debug("lazychunkreader.readat", "read", read, "err", err) + metrics.GetOrRegisterCounter("lazychunkreader.read.err", nil).Inc(1) + } + + metrics.GetOrRegisterCounter("lazychunkreader.read.bytes", nil).Inc(int64(read)) + + r.off += int64(read) + return read, err } // completely analogous to standard SectionReader implementation var errWhence = errors.New("Seek: invalid whence") var errOffset = errors.New("Seek: invalid offset") -func (s *LazyChunkReader) Seek(offset int64, whence int) (int64, error) { +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: return 0, errWhence case 0: offset += 0 case 1: - offset += s.off + offset += r.off case 2: - if s.chunk == nil { //seek from the end requires rootchunk for size. call Size first - _, err := s.Size(nil) + + if r.chunkData == nil { //seek from the end requires rootchunk for size. call Size first + _, err := r.Size(cctx, nil) if err != nil { return 0, fmt.Errorf("can't get size: %v", err) } } - offset += s.chunk.Size + offset += int64(r.chunkData.Size()) } if offset < 0 { return 0, errOffset } - s.off = offset + r.off = offset return offset, nil } diff --git a/swarm/storage/chunker_test.go b/swarm/storage/chunker_test.go index 6b828970b6..9a12594443 100644 --- a/swarm/storage/chunker_test.go +++ b/swarm/storage/chunker_test.go @@ -18,16 +18,14 @@ package storage import ( "bytes" - "crypto/rand" + "context" "encoding/binary" - "errors" "fmt" "io" - "sync" "testing" - "time" - "github.com/ethereum/go-ethereum/crypto/sha3" + "github.com/ethereum/go-ethereum/swarm/testutil" + "golang.org/x/crypto/sha3" ) /* @@ -41,134 +39,15 @@ type test interface { type chunkerTester struct { inputs map[uint64][]byte - chunks map[string]*Chunk t test } -func (self *chunkerTester) Split(chunker Splitter, data io.Reader, size int64, chunkC chan *Chunk, swg *sync.WaitGroup, expectedError error) (key Key, err error) { - // reset - self.chunks = make(map[string]*Chunk) - - if self.inputs == nil { - self.inputs = make(map[uint64][]byte) - } - - quitC := make(chan bool) - timeout := time.After(600 * time.Second) - if chunkC != nil { - go func() error { - for { - select { - case <-timeout: - return errors.New("Split timeout error") - case <-quitC: - return nil - case chunk := <-chunkC: - // self.chunks = append(self.chunks, chunk) - self.chunks[chunk.Key.String()] = chunk - if chunk.wg != nil { - chunk.wg.Done() - } - } - - } - }() - } - - key, err = chunker.Split(data, size, chunkC, swg, nil) - if err != nil && expectedError == nil { - err = fmt.Errorf("Split error: %v", err) - } - - if chunkC != nil { - if swg != nil { - swg.Wait() - } - close(quitC) - } - return key, err +func newTestHasherStore(store ChunkStore, hash string) *hasherStore { + return NewHasherStore(store, MakeHashFunc(hash), false) } -func (self *chunkerTester) Append(chunker Splitter, rootKey Key, data io.Reader, chunkC chan *Chunk, swg *sync.WaitGroup, expectedError error) (key Key, err error) { - quitC := make(chan bool) - timeout := time.After(60 * time.Second) - if chunkC != nil { - go func() error { - for { - select { - case <-timeout: - return errors.New("Append timeout error") - case <-quitC: - return nil - case chunk := <-chunkC: - if chunk != nil { - stored, success := self.chunks[chunk.Key.String()] - if !success { - // Requesting data - self.chunks[chunk.Key.String()] = chunk - if chunk.wg != nil { - chunk.wg.Done() - } - } else { - // getting data - chunk.SData = stored.SData - chunk.Size = int64(binary.LittleEndian.Uint64(chunk.SData[0:8])) - close(chunk.C) - } - } - } - } - }() - } - - key, err = chunker.Append(rootKey, data, chunkC, swg, nil) - if err != nil && expectedError == nil { - err = fmt.Errorf("Append error: %v", err) - } - - if chunkC != nil { - if swg != nil { - swg.Wait() - } - close(quitC) - } - return key, err -} - -func (self *chunkerTester) Join(chunker Chunker, key Key, c int, chunkC chan *Chunk, quitC chan bool) LazySectionReader { - // reset but not the chunks - - reader := chunker.Join(key, chunkC) - - timeout := time.After(600 * time.Second) - i := 0 - go func() error { - for { - select { - case <-timeout: - return errors.New("Join timeout error") - case chunk, ok := <-chunkC: - if !ok { - close(quitC) - return nil - } - // this just mocks the behaviour of a chunk store retrieval - stored, success := self.chunks[chunk.Key.String()] - if !success { - return errors.New("Not found") - } - chunk.SData = stored.SData - chunk.Size = int64(binary.LittleEndian.Uint64(chunk.SData[0:8])) - close(chunk.C) - i++ - } - } - }() - return reader -} - -func testRandomBrokenData(splitter Splitter, n int, tester *chunkerTester) { - data := io.LimitReader(rand.Reader, int64(n)) +func testRandomBrokenData(n int, tester *chunkerTester) { + data := testutil.RandomReader(1, n) brokendata := brokenLimitReader(data, n, n/2) buf := make([]byte, n) @@ -177,47 +56,55 @@ func testRandomBrokenData(splitter Splitter, n int, tester *chunkerTester) { tester.t.Fatalf("Broken reader is not broken, hence broken. Returns: %v", err) } - data = io.LimitReader(rand.Reader, int64(n)) + data = testutil.RandomReader(2, n) brokendata = brokenLimitReader(data, n, n/2) - chunkC := make(chan *Chunk, 1000) - swg := &sync.WaitGroup{} + putGetter := newTestHasherStore(NewMapChunkStore(), SHA3Hash) expectedError := fmt.Errorf("Broken reader") - key, err := tester.Split(splitter, brokendata, int64(n), chunkC, swg, expectedError) + ctx := context.Background() + key, _, err := TreeSplit(ctx, brokendata, int64(n), putGetter) if err == nil || err.Error() != expectedError.Error() { tester.t.Fatalf("Not receiving the correct error! Expected %v, received %v", expectedError, err) } - tester.t.Logf(" Key = %v\n", key) + tester.t.Logf(" Address = %v\n", key) } -func testRandomData(splitter Splitter, n int, tester *chunkerTester) Key { +func testRandomData(usePyramid bool, hash string, n int, tester *chunkerTester) Address { if tester.inputs == nil { tester.inputs = make(map[uint64][]byte) } input, found := tester.inputs[uint64(n)] var data io.Reader if !found { - data, input = testDataReaderAndSlice(n) + input = testutil.RandomBytes(1, n) + data = bytes.NewReader(input) tester.inputs[uint64(n)] = input } else { data = io.LimitReader(bytes.NewReader(input), int64(n)) } - chunkC := make(chan *Chunk, 1000) - swg := &sync.WaitGroup{} + putGetter := newTestHasherStore(NewMapChunkStore(), hash) - key, err := tester.Split(splitter, data, int64(n), chunkC, swg, nil) + var addr Address + var wait func(context.Context) error + var err error + ctx := context.TODO() + if usePyramid { + addr, wait, err = PyramidSplit(ctx, data, putGetter, putGetter) + } else { + addr, wait, err = TreeSplit(ctx, data, int64(n), putGetter) + } + if err != nil { + tester.t.Fatalf(err.Error()) + } + tester.t.Logf(" Address = %v\n", addr) + err = wait(ctx) if err != nil { tester.t.Fatalf(err.Error()) } - tester.t.Logf(" Key = %v\n", key) - chunkC = make(chan *Chunk, 1000) - quitC := make(chan bool) - - chunker := NewTreeChunker(NewChunkerParams()) - reader := tester.Join(chunker, key, 0, chunkC, quitC) + reader := TreeJoin(ctx, addr, putGetter, 0) output := make([]byte, n) r, err := reader.Read(output) if r != n || err != io.EOF { @@ -228,70 +115,22 @@ func testRandomData(splitter Splitter, n int, tester *chunkerTester) Key { tester.t.Fatalf("input and output mismatch\n IN: %v\nOUT: %v\n", input, output) } } - close(chunkC) - <-quitC - return key -} - -func testRandomDataAppend(splitter Splitter, n, m int, tester *chunkerTester) { - if tester.inputs == nil { - tester.inputs = make(map[uint64][]byte) - } - input, found := tester.inputs[uint64(n)] - var data io.Reader - if !found { - data, input = testDataReaderAndSlice(n) - tester.inputs[uint64(n)] = input - } else { - data = io.LimitReader(bytes.NewReader(input), int64(n)) + // testing partial read + for i := 1; i < n; i += 10000 { + readableLength := n - i + r, err := reader.ReadAt(output, int64(i)) + if r != readableLength || err != io.EOF { + tester.t.Fatalf("readAt error with offset %v read: %v n = %v err = %v\n", i, r, readableLength, err) + } + if input != nil { + if !bytes.Equal(output[:readableLength], input[i:]) { + tester.t.Fatalf("input and output mismatch\n IN: %v\nOUT: %v\n", input[i:], output[:readableLength]) + } + } } - chunkC := make(chan *Chunk, 1000) - swg := &sync.WaitGroup{} - - key, err := tester.Split(splitter, data, int64(n), chunkC, swg, nil) - if err != nil { - tester.t.Fatalf(err.Error()) - } - tester.t.Logf(" Key = %v\n", key) - - //create a append data stream - appendInput, found := tester.inputs[uint64(m)] - var appendData io.Reader - if !found { - appendData, appendInput = testDataReaderAndSlice(m) - tester.inputs[uint64(m)] = appendInput - } else { - appendData = io.LimitReader(bytes.NewReader(appendInput), int64(m)) - } - - chunkC = make(chan *Chunk, 1000) - swg = &sync.WaitGroup{} - - newKey, err := tester.Append(splitter, key, appendData, chunkC, swg, nil) - if err != nil { - tester.t.Fatalf(err.Error()) - } - tester.t.Logf(" NewKey = %v\n", newKey) - - chunkC = make(chan *Chunk, 1000) - quitC := make(chan bool) - - chunker := NewTreeChunker(NewChunkerParams()) - reader := tester.Join(chunker, newKey, 0, chunkC, quitC) - newOutput := make([]byte, n+m) - r, err := reader.Read(newOutput) - if r != (n + m) { - tester.t.Fatalf("read error read: %v n = %v err = %v\n", r, n, err) - } - - newInput := append(input, appendInput...) - if !bytes.Equal(newOutput, newInput) { - tester.t.Fatalf("input and output mismatch\n IN: %v\nOUT: %v\n", newInput, newOutput) - } - - close(chunkC) + return addr } func TestSha3ForCorrectness(t *testing.T) { @@ -303,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) @@ -328,118 +167,163 @@ func TestDataAppend(t *testing.T) { appendSizes := []int{4095, 4096, 4097, 1, 1, 1, 8191, 8192, 8193, 9000, 3000, 5000} tester := &chunkerTester{t: t} - chunker := NewPyramidChunker(NewChunkerParams()) - for i, s := range sizes { - testRandomDataAppend(chunker, s, appendSizes[i], tester) + for i := range sizes { + n := sizes[i] + m := appendSizes[i] + if tester.inputs == nil { + tester.inputs = make(map[uint64][]byte) + } + input, found := tester.inputs[uint64(n)] + var data io.Reader + if !found { + input = testutil.RandomBytes(i, n) + data = bytes.NewReader(input) + tester.inputs[uint64(n)] = input + } else { + data = io.LimitReader(bytes.NewReader(input), int64(n)) + } + + store := NewMapChunkStore() + putGetter := newTestHasherStore(store, SHA3Hash) + + ctx := context.TODO() + addr, wait, err := PyramidSplit(ctx, data, putGetter, putGetter) + if err != nil { + tester.t.Fatalf(err.Error()) + } + err = wait(ctx) + if err != nil { + tester.t.Fatalf(err.Error()) + } + //create a append data stream + appendInput, found := tester.inputs[uint64(m)] + var appendData io.Reader + if !found { + appendInput = testutil.RandomBytes(i, m) + appendData = bytes.NewReader(appendInput) + tester.inputs[uint64(m)] = appendInput + } else { + appendData = io.LimitReader(bytes.NewReader(appendInput), int64(m)) + } + + putGetter = newTestHasherStore(store, SHA3Hash) + newAddr, wait, err := PyramidAppend(ctx, addr, appendData, putGetter, putGetter) + if err != nil { + tester.t.Fatalf(err.Error()) + } + err = wait(ctx) + if err != nil { + tester.t.Fatalf(err.Error()) + } + + reader := TreeJoin(ctx, newAddr, putGetter, 0) + newOutput := make([]byte, n+m) + r, err := reader.Read(newOutput) + if r != (n + m) { + tester.t.Fatalf("read error read: %v n = %v m = %v err = %v\n", r, n, m, err) + } + + newInput := append(input, appendInput...) + if !bytes.Equal(newOutput, newInput) { + tester.t.Fatalf("input and output mismatch\n IN: %v\nOUT: %v\n", newInput, newOutput) + } } } func TestRandomData(t *testing.T) { - sizes := []int{1, 60, 83, 179, 253, 1024, 4095, 4096, 4097, 8191, 8192, 8193, 12287, 12288, 12289, 123456, 2345678} + // This test can validate files up to a relatively short length, as tree chunker slows down drastically. + // Validation of longer files is done by TestLocalStoreAndRetrieve in swarm package. + //sizes := []int{1, 60, 83, 179, 253, 1024, 4095, 4096, 4097, 8191, 8192, 8193, 12287, 12288, 12289, 524288, 524288 + 1, 524288 + 4097, 7 * 524288, 7*524288 + 1, 7*524288 + 4097} + sizes := []int{1, 60, 83, 179, 253, 1024, 4095, 4097, 8191, 8192, 12288, 12289, 524288} tester := &chunkerTester{t: t} - chunker := NewTreeChunker(NewChunkerParams()) - pyramid := NewPyramidChunker(NewChunkerParams()) for _, s := range sizes { - treeChunkerKey := testRandomData(chunker, s, tester) - pyramidChunkerKey := testRandomData(pyramid, s, tester) - if treeChunkerKey.String() != pyramidChunkerKey.String() { - tester.t.Fatalf("tree chunker and pyramid chunker key mismatch for size %v\n TC: %v\n PC: %v\n", s, treeChunkerKey.String(), pyramidChunkerKey.String()) + treeChunkerAddress := testRandomData(false, SHA3Hash, s, tester) + pyramidChunkerAddress := testRandomData(true, SHA3Hash, s, tester) + if treeChunkerAddress.String() != pyramidChunkerAddress.String() { + tester.t.Fatalf("tree chunker and pyramid chunker key mismatch for size %v\n TC: %v\n PC: %v\n", s, treeChunkerAddress.String(), pyramidChunkerAddress.String()) } } - cp := NewChunkerParams() - cp.Hash = BMTHash - chunker = NewTreeChunker(cp) - pyramid = NewPyramidChunker(cp) for _, s := range sizes { - treeChunkerKey := testRandomData(chunker, s, tester) - pyramidChunkerKey := testRandomData(pyramid, s, tester) - if treeChunkerKey.String() != pyramidChunkerKey.String() { - tester.t.Fatalf("tree chunker BMT and pyramid chunker BMT key mismatch for size %v \n TC: %v\n PC: %v\n", s, treeChunkerKey.String(), pyramidChunkerKey.String()) + treeChunkerAddress := testRandomData(false, BMTHash, s, tester) + pyramidChunkerAddress := testRandomData(true, BMTHash, s, tester) + if treeChunkerAddress.String() != pyramidChunkerAddress.String() { + tester.t.Fatalf("tree chunker and pyramid chunker key mismatch for size %v\n TC: %v\n PC: %v\n", s, treeChunkerAddress.String(), pyramidChunkerAddress.String()) } } - } func TestRandomBrokenData(t *testing.T) { sizes := []int{1, 60, 83, 179, 253, 1024, 4095, 4096, 4097, 8191, 8192, 8193, 12287, 12288, 12289, 123456, 2345678} tester := &chunkerTester{t: t} - chunker := NewTreeChunker(NewChunkerParams()) for _, s := range sizes { - testRandomBrokenData(chunker, s, tester) + testRandomBrokenData(s, tester) } } func benchReadAll(reader LazySectionReader) { - size, _ := reader.Size(nil) + size, _ := reader.Size(context.TODO(), nil) output := make([]byte, 1000) for pos := int64(0); pos < size; pos += 1000 { reader.ReadAt(output, pos) } } -func benchmarkJoin(n int, t *testing.B) { +func benchmarkSplitJoin(n int, t *testing.B) { t.ReportAllocs() for i := 0; i < t.N; i++ { - chunker := NewTreeChunker(NewChunkerParams()) - tester := &chunkerTester{t: t} - data := testDataReader(n) + data := testutil.RandomReader(i, n) - chunkC := make(chan *Chunk, 1000) - swg := &sync.WaitGroup{} - - key, err := tester.Split(chunker, data, int64(n), chunkC, swg, nil) + putGetter := newTestHasherStore(NewMapChunkStore(), SHA3Hash) + ctx := context.TODO() + key, wait, err := PyramidSplit(ctx, data, putGetter, putGetter) if err != nil { - tester.t.Fatalf(err.Error()) + t.Fatalf(err.Error()) } - chunkC = make(chan *Chunk, 1000) - quitC := make(chan bool) - reader := tester.Join(chunker, key, i, chunkC, quitC) + err = wait(ctx) + if err != nil { + t.Fatalf(err.Error()) + } + reader := TreeJoin(ctx, key, putGetter, 0) benchReadAll(reader) - close(chunkC) - <-quitC } } func benchmarkSplitTreeSHA3(n int, t *testing.B) { t.ReportAllocs() for i := 0; i < t.N; i++ { - chunker := NewTreeChunker(NewChunkerParams()) - tester := &chunkerTester{t: t} - data := testDataReader(n) - _, err := tester.Split(chunker, data, int64(n), nil, nil, nil) + data := testutil.RandomReader(i, n) + putGetter := newTestHasherStore(&FakeChunkStore{}, SHA3Hash) + + ctx := context.Background() + _, wait, err := TreeSplit(ctx, data, int64(n), putGetter) if err != nil { - tester.t.Fatalf(err.Error()) + t.Fatalf(err.Error()) } + err = wait(ctx) + if err != nil { + t.Fatalf(err.Error()) + } + } } func benchmarkSplitTreeBMT(n int, t *testing.B) { t.ReportAllocs() for i := 0; i < t.N; i++ { - cp := NewChunkerParams() - cp.Hash = BMTHash - chunker := NewTreeChunker(cp) - tester := &chunkerTester{t: t} - data := testDataReader(n) - _, err := tester.Split(chunker, data, int64(n), nil, nil, nil) - if err != nil { - tester.t.Fatalf(err.Error()) - } - } -} + data := testutil.RandomReader(i, n) + putGetter := newTestHasherStore(&FakeChunkStore{}, BMTHash) -func benchmarkSplitPyramidSHA3(n int, t *testing.B) { - t.ReportAllocs() - for i := 0; i < t.N; i++ { - splitter := NewPyramidChunker(NewChunkerParams()) - tester := &chunkerTester{t: t} - data := testDataReader(n) - _, err := tester.Split(splitter, data, int64(n), nil, nil, nil) + ctx := context.Background() + _, wait, err := TreeSplit(ctx, data, int64(n), putGetter) if err != nil { - tester.t.Fatalf(err.Error()) + t.Fatalf(err.Error()) + } + err = wait(ctx) + if err != nil { + t.Fatalf(err.Error()) } } } @@ -447,52 +331,78 @@ func benchmarkSplitPyramidSHA3(n int, t *testing.B) { func benchmarkSplitPyramidBMT(n int, t *testing.B) { t.ReportAllocs() for i := 0; i < t.N; i++ { - cp := NewChunkerParams() - cp.Hash = BMTHash - splitter := NewPyramidChunker(cp) - tester := &chunkerTester{t: t} - data := testDataReader(n) - _, err := tester.Split(splitter, data, int64(n), nil, nil, nil) + data := testutil.RandomReader(i, n) + putGetter := newTestHasherStore(&FakeChunkStore{}, BMTHash) + + ctx := context.Background() + _, wait, err := PyramidSplit(ctx, data, putGetter, putGetter) if err != nil { - tester.t.Fatalf(err.Error()) + t.Fatalf(err.Error()) + } + err = wait(ctx) + if err != nil { + t.Fatalf(err.Error()) } } } -func benchmarkAppendPyramid(n, m int, t *testing.B) { +func benchmarkSplitPyramidSHA3(n int, t *testing.B) { t.ReportAllocs() for i := 0; i < t.N; i++ { - chunker := NewPyramidChunker(NewChunkerParams()) - tester := &chunkerTester{t: t} - data := testDataReader(n) - data1 := testDataReader(m) + data := testutil.RandomReader(i, n) + putGetter := newTestHasherStore(&FakeChunkStore{}, SHA3Hash) - chunkC := make(chan *Chunk, 1000) - swg := &sync.WaitGroup{} - key, err := tester.Split(chunker, data, int64(n), chunkC, swg, nil) + ctx := context.Background() + _, wait, err := PyramidSplit(ctx, data, putGetter, putGetter) if err != nil { - tester.t.Fatalf(err.Error()) + t.Fatalf(err.Error()) } - - chunkC = make(chan *Chunk, 1000) - swg = &sync.WaitGroup{} - - _, err = tester.Append(chunker, key, data1, chunkC, swg, nil) + err = wait(ctx) if err != nil { - tester.t.Fatalf(err.Error()) + t.Fatalf(err.Error()) } - - close(chunkC) } } -func BenchmarkJoin_2(t *testing.B) { benchmarkJoin(100, t) } -func BenchmarkJoin_3(t *testing.B) { benchmarkJoin(1000, t) } -func BenchmarkJoin_4(t *testing.B) { benchmarkJoin(10000, t) } -func BenchmarkJoin_5(t *testing.B) { benchmarkJoin(100000, t) } -func BenchmarkJoin_6(t *testing.B) { benchmarkJoin(1000000, t) } -func BenchmarkJoin_7(t *testing.B) { benchmarkJoin(10000000, t) } -func BenchmarkJoin_8(t *testing.B) { benchmarkJoin(100000000, t) } +func benchmarkSplitAppendPyramid(n, m int, t *testing.B) { + t.ReportAllocs() + for i := 0; i < t.N; i++ { + data := testutil.RandomReader(i, n) + data1 := testutil.RandomReader(t.N+i, m) + + store := NewMapChunkStore() + putGetter := newTestHasherStore(store, SHA3Hash) + + ctx := context.Background() + key, wait, err := PyramidSplit(ctx, data, putGetter, putGetter) + if err != nil { + t.Fatalf(err.Error()) + } + err = wait(ctx) + if err != nil { + t.Fatalf(err.Error()) + } + + putGetter = newTestHasherStore(store, SHA3Hash) + _, wait, err = PyramidAppend(ctx, key, data1, putGetter, putGetter) + if err != nil { + t.Fatalf(err.Error()) + } + err = wait(ctx) + if err != nil { + t.Fatalf(err.Error()) + } + } +} + +func BenchmarkSplitJoin_2(t *testing.B) { benchmarkSplitJoin(100, t) } +func BenchmarkSplitJoin_3(t *testing.B) { benchmarkSplitJoin(1000, t) } +func BenchmarkSplitJoin_4(t *testing.B) { benchmarkSplitJoin(10000, t) } +func BenchmarkSplitJoin_5(t *testing.B) { benchmarkSplitJoin(100000, t) } +func BenchmarkSplitJoin_6(t *testing.B) { benchmarkSplitJoin(1000000, t) } +func BenchmarkSplitJoin_7(t *testing.B) { benchmarkSplitJoin(10000000, t) } + +// func BenchmarkSplitJoin_8(t *testing.B) { benchmarkJoin(100000000, t) } func BenchmarkSplitTreeSHA3_2(t *testing.B) { benchmarkSplitTreeSHA3(100, t) } func BenchmarkSplitTreeSHA3_2h(t *testing.B) { benchmarkSplitTreeSHA3(500, t) } @@ -503,7 +413,8 @@ func BenchmarkSplitTreeSHA3_4h(t *testing.B) { benchmarkSplitTreeSHA3(50000, t) func BenchmarkSplitTreeSHA3_5(t *testing.B) { benchmarkSplitTreeSHA3(100000, t) } func BenchmarkSplitTreeSHA3_6(t *testing.B) { benchmarkSplitTreeSHA3(1000000, t) } func BenchmarkSplitTreeSHA3_7(t *testing.B) { benchmarkSplitTreeSHA3(10000000, t) } -func BenchmarkSplitTreeSHA3_8(t *testing.B) { benchmarkSplitTreeSHA3(100000000, t) } + +// func BenchmarkSplitTreeSHA3_8(t *testing.B) { benchmarkSplitTreeSHA3(100000000, t) } func BenchmarkSplitTreeBMT_2(t *testing.B) { benchmarkSplitTreeBMT(100, t) } func BenchmarkSplitTreeBMT_2h(t *testing.B) { benchmarkSplitTreeBMT(500, t) } @@ -514,7 +425,8 @@ func BenchmarkSplitTreeBMT_4h(t *testing.B) { benchmarkSplitTreeBMT(50000, t) } func BenchmarkSplitTreeBMT_5(t *testing.B) { benchmarkSplitTreeBMT(100000, t) } func BenchmarkSplitTreeBMT_6(t *testing.B) { benchmarkSplitTreeBMT(1000000, t) } func BenchmarkSplitTreeBMT_7(t *testing.B) { benchmarkSplitTreeBMT(10000000, t) } -func BenchmarkSplitTreeBMT_8(t *testing.B) { benchmarkSplitTreeBMT(100000000, t) } + +// func BenchmarkSplitTreeBMT_8(t *testing.B) { benchmarkSplitTreeBMT(100000000, t) } func BenchmarkSplitPyramidSHA3_2(t *testing.B) { benchmarkSplitPyramidSHA3(100, t) } func BenchmarkSplitPyramidSHA3_2h(t *testing.B) { benchmarkSplitPyramidSHA3(500, t) } @@ -525,7 +437,8 @@ func BenchmarkSplitPyramidSHA3_4h(t *testing.B) { benchmarkSplitPyramidSHA3(5000 func BenchmarkSplitPyramidSHA3_5(t *testing.B) { benchmarkSplitPyramidSHA3(100000, t) } func BenchmarkSplitPyramidSHA3_6(t *testing.B) { benchmarkSplitPyramidSHA3(1000000, t) } func BenchmarkSplitPyramidSHA3_7(t *testing.B) { benchmarkSplitPyramidSHA3(10000000, t) } -func BenchmarkSplitPyramidSHA3_8(t *testing.B) { benchmarkSplitPyramidSHA3(100000000, t) } + +// func BenchmarkSplitPyramidSHA3_8(t *testing.B) { benchmarkSplitPyramidSHA3(100000000, t) } func BenchmarkSplitPyramidBMT_2(t *testing.B) { benchmarkSplitPyramidBMT(100, t) } func BenchmarkSplitPyramidBMT_2h(t *testing.B) { benchmarkSplitPyramidBMT(500, t) } @@ -536,17 +449,19 @@ func BenchmarkSplitPyramidBMT_4h(t *testing.B) { benchmarkSplitPyramidBMT(50000, func BenchmarkSplitPyramidBMT_5(t *testing.B) { benchmarkSplitPyramidBMT(100000, t) } func BenchmarkSplitPyramidBMT_6(t *testing.B) { benchmarkSplitPyramidBMT(1000000, t) } func BenchmarkSplitPyramidBMT_7(t *testing.B) { benchmarkSplitPyramidBMT(10000000, t) } -func BenchmarkSplitPyramidBMT_8(t *testing.B) { benchmarkSplitPyramidBMT(100000000, t) } -func BenchmarkAppendPyramid_2(t *testing.B) { benchmarkAppendPyramid(100, 1000, t) } -func BenchmarkAppendPyramid_2h(t *testing.B) { benchmarkAppendPyramid(500, 1000, t) } -func BenchmarkAppendPyramid_3(t *testing.B) { benchmarkAppendPyramid(1000, 1000, t) } -func BenchmarkAppendPyramid_4(t *testing.B) { benchmarkAppendPyramid(10000, 1000, t) } -func BenchmarkAppendPyramid_4h(t *testing.B) { benchmarkAppendPyramid(50000, 1000, t) } -func BenchmarkAppendPyramid_5(t *testing.B) { benchmarkAppendPyramid(1000000, 1000, t) } -func BenchmarkAppendPyramid_6(t *testing.B) { benchmarkAppendPyramid(1000000, 1000, t) } -func BenchmarkAppendPyramid_7(t *testing.B) { benchmarkAppendPyramid(10000000, 1000, t) } -func BenchmarkAppendPyramid_8(t *testing.B) { benchmarkAppendPyramid(100000000, 1000, t) } +// func BenchmarkSplitPyramidBMT_8(t *testing.B) { benchmarkSplitPyramidBMT(100000000, t) } + +func BenchmarkSplitAppendPyramid_2(t *testing.B) { benchmarkSplitAppendPyramid(100, 1000, t) } +func BenchmarkSplitAppendPyramid_2h(t *testing.B) { benchmarkSplitAppendPyramid(500, 1000, t) } +func BenchmarkSplitAppendPyramid_3(t *testing.B) { benchmarkSplitAppendPyramid(1000, 1000, t) } +func BenchmarkSplitAppendPyramid_4(t *testing.B) { benchmarkSplitAppendPyramid(10000, 1000, t) } +func BenchmarkSplitAppendPyramid_4h(t *testing.B) { benchmarkSplitAppendPyramid(50000, 1000, t) } +func BenchmarkSplitAppendPyramid_5(t *testing.B) { benchmarkSplitAppendPyramid(1000000, 1000, t) } +func BenchmarkSplitAppendPyramid_6(t *testing.B) { benchmarkSplitAppendPyramid(1000000, 1000, t) } +func BenchmarkSplitAppendPyramid_7(t *testing.B) { benchmarkSplitAppendPyramid(10000000, 1000, t) } + +// func BenchmarkAppendPyramid_8(t *testing.B) { benchmarkAppendPyramid(100000000, 1000, t) } // go test -timeout 20m -cpu 4 -bench=./swarm/storage -run no // If you dont add the timeout argument above .. the benchmark will timeout and dump diff --git a/swarm/storage/common_test.go b/swarm/storage/common_test.go index cd4c2ef139..c4d187b622 100644 --- a/swarm/storage/common_test.go +++ b/swarm/storage/common_test.go @@ -18,15 +18,32 @@ package storage import ( "bytes" - "crypto/rand" + "context" + "flag" "fmt" "io" + "io/ioutil" + "os" "sync" "testing" + "time" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/swarm/chunk" + "github.com/mattn/go-colorable" ) +var ( + loglevel = flag.Int("loglevel", 3, "verbosity of logs") + getTimeout = 30 * time.Second +) + +func init() { + flag.Parse() + log.PrintOrigins(true) + log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true)))) +} + type brokenLimitedReader struct { lr io.Reader errAt int @@ -42,75 +59,230 @@ func brokenLimitReader(data io.Reader, size int, errAt int) *brokenLimitedReader } } -func testDataReader(l int) (r io.Reader) { - return io.LimitReader(rand.Reader, int64(l)) +func newLDBStore(t *testing.T) (*LDBStore, func()) { + dir, err := ioutil.TempDir("", "bzz-storage-test") + if err != nil { + t.Fatal(err) + } + log.Trace("memstore.tempdir", "dir", dir) + + ldbparams := NewLDBStoreParams(NewDefaultStoreParams(), dir) + db, err := NewLDBStore(ldbparams) + if err != nil { + t.Fatal(err) + } + + cleanup := func() { + db.Close() + err := os.RemoveAll(dir) + if err != nil { + t.Fatal(err) + } + } + + return db, cleanup } -func (self *brokenLimitedReader) Read(buf []byte) (int, error) { - if self.off+len(buf) > self.errAt { +func mputRandomChunks(store ChunkStore, n int) ([]Chunk, error) { + return mput(store, n, GenerateRandomChunk) +} + +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(), 1*time.Minute) + defer cancel() + for i := int64(0); i < int64(n); i++ { + chunk := f(chunk.DefaultSize) + go func() { + select { + case errc <- store.Put(ctx, chunk): + case <-ctx.Done(): + } + }() + hs = append(hs, chunk) + } + + // wait for all chunks to be stored + for i := 0; i < n; i++ { + err := <-errc + if err != nil { + return nil, err + } + } + return hs, nil +} + +func mget(store ChunkStore, hs []Address, f func(h Address, chunk Chunk) error) error { + wg := sync.WaitGroup{} + wg.Add(len(hs)) + errc := make(chan error) + + for _, k := range hs { + go func(h Address) { + defer wg.Done() + // TODO: write timeout with context + chunk, err := store.Get(context.TODO(), h) + if err != nil { + errc <- err + return + } + if f != nil { + err = f(h, chunk) + if err != nil { + errc <- err + return + } + } + }(k) + } + go func() { + wg.Wait() + close(errc) + }() + var err error + timeout := 20 * time.Second + select { + case err = <-errc: + case <-time.NewTimer(timeout).C: + err = fmt.Errorf("timed out after %v", timeout) + } + return err +} + +func (r *brokenLimitedReader) Read(buf []byte) (int, error) { + if r.off+len(buf) > r.errAt { return 0, fmt.Errorf("Broken reader") } - self.off += len(buf) - return self.lr.Read(buf) + r.off += len(buf) + return r.lr.Read(buf) } -func testDataReaderAndSlice(l int) (r io.Reader, slice []byte) { - slice = make([]byte, l) - if _, err := rand.Read(slice); err != nil { - panic("rand error") +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) } - r = io.LimitReader(bytes.NewReader(slice), int64(l)) - return -} - -func testStore(m ChunkStore, l int64, branches int64, t *testing.T) { - - chunkC := make(chan *Chunk) - go func() { - for chunk := range chunkC { - m.Put(chunk) - if chunk.wg != nil { - chunk.wg.Done() - } - } - }() - chunker := NewTreeChunker(&ChunkerParams{ - Branches: branches, - Hash: SHA3Hash, - }) - swg := &sync.WaitGroup{} - key, _ := chunker.Split(rand.Reader, l, chunkC, swg, nil) - swg.Wait() - close(chunkC) - chunkC = make(chan *Chunk) - - quit := make(chan bool) - - go func() { - for ch := range chunkC { - go func(chunk *Chunk) { - storedChunk, err := m.Get(chunk.Key) - if err == notFound { - log.Trace(fmt.Sprintf("chunk '%v' not found", chunk.Key.Log())) - } else if err != nil { - log.Trace(fmt.Sprintf("error retrieving chunk %v: %v", chunk.Key.Log(), err)) - } else { - chunk.SData = storedChunk.SData - chunk.Size = storedChunk.Size - } - log.Trace(fmt.Sprintf("chunk '%v' not found", chunk.Key.Log())) - close(chunk.C) - }(ch) - } - close(quit) - }() - r := chunker.Join(key, chunkC) - - b := make([]byte, l) - n, err := r.ReadAt(b, 0) - if err != io.EOF { - t.Fatalf("read error (%v/%v) %v", n, l, err) + err = mget(m, chunkAddresses(chunks), nil) + if err != nil { + t.Fatalf("testStore failed: %v", err) } - close(chunkC) - <-quit +} + +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) + } + f := func(h Address, chunk Chunk) error { + if !bytes.Equal(h, chunk.Address()) { + return fmt.Errorf("key does not match retrieved chunk Address") + } + hasher := MakeHashFunc(DefaultHash)() + 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") + } + return nil + } + err = mget(m, chunkAddresses(chunks), f) + if err != nil { + t.Fatalf("testStore failed: %v", err) + } +} + +func benchmarkStorePut(store ChunkStore, n int, b *testing.B) { + chunks := make([]Chunk, n) + i := 0 + f := func(dataSize int64) Chunk { + chunk := GenerateRandomChunk(dataSize) + chunks[i] = chunk + i++ + return chunk + } + + mput(store, n, f) + + f = func(dataSize int64) Chunk { + chunk := chunks[i] + i++ + return chunk + } + + b.ReportAllocs() + b.ResetTimer() + + for j := 0; j < b.N; j++ { + i = 0 + mput(store, n, f) + } +} + +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) + } + b.ReportAllocs() + b.ResetTimer() + addrs := chunkAddresses(chunks) + for i := 0; i < b.N; i++ { + err := mget(store, addrs, nil) + if err != nil { + b.Fatalf("mget failed: %v", err) + } + } +} + +// MapChunkStore is a very simple ChunkStore implementation to store chunks in a map in memory. +type MapChunkStore struct { + chunks map[string]Chunk + mu sync.RWMutex +} + +func NewMapChunkStore() *MapChunkStore { + return &MapChunkStore{ + chunks: make(map[string]Chunk), + } +} + +func (m *MapChunkStore) Put(_ context.Context, ch Chunk) error { + m.mu.Lock() + defer m.mu.Unlock() + m.chunks[ch.Address().Hex()] = ch + return nil +} + +func (m *MapChunkStore) Get(_ context.Context, ref Address) (Chunk, error) { + m.mu.RLock() + defer m.mu.RUnlock() + chunk := m.chunks[ref.Hex()] + if chunk == nil { + return nil, ErrChunkNotFound + } + 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() { +} + +func chunkAddresses(chunks []Chunk) []Address { + addrs := make([]Address, len(chunks)) + for i, ch := range chunks { + addrs[i] = ch.Address() + } + return addrs } diff --git a/swarm/storage/database.go b/swarm/storage/database.go index 2532490cc9..12367b9051 100644 --- a/swarm/storage/database.go +++ b/swarm/storage/database.go @@ -20,9 +20,7 @@ package storage // no need for queueing/caching import ( - "fmt" - - "github.com/ethereum/go-ethereum/compression/rle" + "github.com/ethereum/go-ethereum/metrics" "github.com/syndtr/goleveldb/leveldb" "github.com/syndtr/goleveldb/leveldb/iterator" "github.com/syndtr/goleveldb/leveldb/opt" @@ -31,8 +29,7 @@ import ( const openFileLimit = 128 type LDBDatabase struct { - db *leveldb.DB - comp bool + db *leveldb.DB } func NewLDBDatabase(file string) (*LDBDatabase, error) { @@ -42,58 +39,44 @@ func NewLDBDatabase(file string) (*LDBDatabase, error) { return nil, err } - database := &LDBDatabase{db: db, comp: false} + database := &LDBDatabase{db: db} return database, nil } -func (self *LDBDatabase) Put(key []byte, value []byte) { - if self.comp { - value = rle.Compress(value) - } +func (db *LDBDatabase) Put(key []byte, value []byte) error { + metrics.GetOrRegisterCounter("ldbdatabase.put", nil).Inc(1) - err := self.db.Put(key, value, nil) - if err != nil { - fmt.Println("Error put", err) - } + return db.db.Put(key, value, nil) } -func (self *LDBDatabase) Get(key []byte) ([]byte, error) { - dat, err := self.db.Get(key, nil) +func (db *LDBDatabase) Get(key []byte) ([]byte, error) { + metrics.GetOrRegisterCounter("ldbdatabase.get", nil).Inc(1) + + dat, err := db.db.Get(key, nil) if err != nil { return nil, err } - - if self.comp { - return rle.Decompress(dat) - } - return dat, nil } -func (self *LDBDatabase) Delete(key []byte) error { - return self.db.Delete(key, nil) +func (db *LDBDatabase) Delete(key []byte) error { + return db.db.Delete(key, nil) } -func (self *LDBDatabase) LastKnownTD() []byte { - data, _ := self.Get([]byte("LTD")) +func (db *LDBDatabase) NewIterator() iterator.Iterator { + metrics.GetOrRegisterCounter("ldbdatabase.newiterator", nil).Inc(1) - if len(data) == 0 { - data = []byte{0x0} - } - - return data + return db.db.NewIterator(nil, nil) } -func (self *LDBDatabase) NewIterator() iterator.Iterator { - return self.db.NewIterator(nil, nil) +func (db *LDBDatabase) Write(batch *leveldb.Batch) error { + metrics.GetOrRegisterCounter("ldbdatabase.write", nil).Inc(1) + + return db.db.Write(batch, nil) } -func (self *LDBDatabase) Write(batch *leveldb.Batch) error { - return self.db.Write(batch, nil) -} - -func (self *LDBDatabase) Close() { +func (db *LDBDatabase) Close() { // Close the leveldb database - self.db.Close() + db.db.Close() } diff --git a/swarm/storage/dbstore.go b/swarm/storage/dbstore.go deleted file mode 100644 index 46a5c16ccc..0000000000 --- a/swarm/storage/dbstore.go +++ /dev/null @@ -1,592 +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 . - -// disk storage layer for the package bzz -// DbStore implements the ChunkStore interface and is used by the DPA as -// persistent storage of chunks -// it implements purging based on access count allowing for external control of -// max capacity - -package storage - -import ( - "archive/tar" - "bytes" - "encoding/binary" - "encoding/hex" - "fmt" - "io" - "io/ioutil" - "sync" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rlp" - "github.com/syndtr/goleveldb/leveldb" - "github.com/syndtr/goleveldb/leveldb/iterator" -) - -const ( - defaultDbCapacity = 5000000 - defaultRadius = 0 // not yet used - - gcArraySize = 10000 - gcArrayFreeRatio = 0.1 - - // key prefixes for leveldb storage - kpIndex = 0 - kpData = 1 -) - -var ( - keyAccessCnt = []byte{2} - keyEntryCnt = []byte{3} - keyDataIdx = []byte{4} - keyGCPos = []byte{5} -) - -type gcItem struct { - idx uint64 - value uint64 - idxKey []byte -} - -type DbStore struct { - db *LDBDatabase - - // this should be stored in db, accessed transactionally - entryCnt, accessCnt, dataIdx, capacity uint64 - - gcPos, gcStartPos []byte - gcArray []*gcItem - - hashfunc SwarmHasher - - lock sync.Mutex -} - -func NewDbStore(path string, hash SwarmHasher, capacity uint64, radius int) (s *DbStore, err error) { - s = new(DbStore) - - s.hashfunc = hash - - s.db, err = NewLDBDatabase(path) - if err != nil { - return - } - - s.setCapacity(capacity) - - s.gcStartPos = make([]byte, 1) - s.gcStartPos[0] = kpIndex - s.gcArray = make([]*gcItem, gcArraySize) - - data, _ := s.db.Get(keyEntryCnt) - s.entryCnt = BytesToU64(data) - data, _ = s.db.Get(keyAccessCnt) - s.accessCnt = BytesToU64(data) - data, _ = s.db.Get(keyDataIdx) - s.dataIdx = BytesToU64(data) - s.gcPos, _ = s.db.Get(keyGCPos) - if s.gcPos == nil { - s.gcPos = s.gcStartPos - } - return -} - -type dpaDBIndex struct { - Idx uint64 - Access uint64 -} - -func BytesToU64(data []byte) uint64 { - if len(data) < 8 { - return 0 - } - return binary.LittleEndian.Uint64(data) -} - -func U64ToBytes(val uint64) []byte { - data := make([]byte, 8) - binary.LittleEndian.PutUint64(data, val) - return data -} - -func getIndexGCValue(index *dpaDBIndex) uint64 { - return index.Access -} - -func (s *DbStore) updateIndexAccess(index *dpaDBIndex) { - index.Access = s.accessCnt -} - -func getIndexKey(hash Key) []byte { - HashSize := len(hash) - key := make([]byte, HashSize+1) - key[0] = 0 - copy(key[1:], hash[:]) - return key -} - -func getDataKey(idx uint64) []byte { - key := make([]byte, 9) - key[0] = 1 - binary.BigEndian.PutUint64(key[1:9], idx) - - return key -} - -func encodeIndex(index *dpaDBIndex) []byte { - data, _ := rlp.EncodeToBytes(index) - return data -} - -func encodeData(chunk *Chunk) []byte { - return chunk.SData -} - -func decodeIndex(data []byte, index *dpaDBIndex) { - dec := rlp.NewStream(bytes.NewReader(data), 0) - dec.Decode(index) -} - -func decodeData(data []byte, chunk *Chunk) { - chunk.SData = data - chunk.Size = int64(binary.LittleEndian.Uint64(data[0:8])) -} - -func gcListPartition(list []*gcItem, left int, right int, pivotIndex int) int { - pivotValue := list[pivotIndex].value - dd := list[pivotIndex] - list[pivotIndex] = list[right] - list[right] = dd - storeIndex := left - for i := left; i < right; i++ { - if list[i].value < pivotValue { - dd = list[storeIndex] - list[storeIndex] = list[i] - list[i] = dd - storeIndex++ - } - } - dd = list[storeIndex] - list[storeIndex] = list[right] - list[right] = dd - return storeIndex -} - -func gcListSelect(list []*gcItem, left int, right int, n int) int { - if left == right { - return left - } - pivotIndex := (left + right) / 2 - pivotIndex = gcListPartition(list, left, right, pivotIndex) - if n == pivotIndex { - return n - } else { - if n < pivotIndex { - return gcListSelect(list, left, pivotIndex-1, n) - } else { - return gcListSelect(list, pivotIndex+1, right, n) - } - } -} - -func (s *DbStore) collectGarbage(ratio float32) { - it := s.db.NewIterator() - it.Seek(s.gcPos) - if it.Valid() { - s.gcPos = it.Key() - } else { - s.gcPos = nil - } - gcnt := 0 - - for (gcnt < gcArraySize) && (uint64(gcnt) < s.entryCnt) { - - if (s.gcPos == nil) || (s.gcPos[0] != kpIndex) { - it.Seek(s.gcStartPos) - if it.Valid() { - s.gcPos = it.Key() - } else { - s.gcPos = nil - } - } - - if (s.gcPos == nil) || (s.gcPos[0] != kpIndex) { - break - } - - gci := new(gcItem) - gci.idxKey = s.gcPos - var index dpaDBIndex - decodeIndex(it.Value(), &index) - gci.idx = index.Idx - // the smaller, the more likely to be gc'd - gci.value = getIndexGCValue(&index) - s.gcArray[gcnt] = gci - gcnt++ - it.Next() - if it.Valid() { - s.gcPos = it.Key() - } else { - s.gcPos = nil - } - } - it.Release() - - cutidx := gcListSelect(s.gcArray, 0, gcnt-1, int(float32(gcnt)*ratio)) - cutval := s.gcArray[cutidx].value - - // fmt.Print(gcnt, " ", s.entryCnt, " ") - - // actual gc - for i := 0; i < gcnt; i++ { - if s.gcArray[i].value <= cutval { - s.delete(s.gcArray[i].idx, s.gcArray[i].idxKey) - } - } - - // fmt.Println(s.entryCnt) - - s.db.Put(keyGCPos, s.gcPos) -} - -// Export writes all chunks from the store to a tar archive, returning the -// number of chunks written. -func (s *DbStore) Export(out io.Writer) (int64, error) { - tw := tar.NewWriter(out) - defer tw.Close() - - it := s.db.NewIterator() - defer it.Release() - var count int64 - for ok := it.Seek([]byte{kpIndex}); ok; ok = it.Next() { - key := it.Key() - if (key == nil) || (key[0] != kpIndex) { - break - } - - var index dpaDBIndex - decodeIndex(it.Value(), &index) - - data, err := s.db.Get(getDataKey(index.Idx)) - if err != nil { - log.Warn(fmt.Sprintf("Chunk %x found but could not be accessed: %v", key[:], err)) - continue - } - - hdr := &tar.Header{ - Name: hex.EncodeToString(key[1:]), - Mode: 0644, - Size: int64(len(data)), - } - if err := tw.WriteHeader(hdr); err != nil { - return count, err - } - if _, err := tw.Write(data); err != nil { - return count, err - } - count++ - } - - return count, nil -} - -// Import reads chunks into the store from a tar archive, returning the number -// of chunks read. -func (s *DbStore) Import(in io.Reader) (int64, error) { - tr := tar.NewReader(in) - - var count int64 - for { - hdr, err := tr.Next() - if err == io.EOF { - break - } else if err != nil { - return count, err - } - - if len(hdr.Name) != 64 { - log.Warn("ignoring non-chunk file", "name", hdr.Name) - continue - } - - key, err := hex.DecodeString(hdr.Name) - if err != nil { - log.Warn("ignoring invalid chunk file", "name", hdr.Name, "err", err) - continue - } - - data, err := ioutil.ReadAll(tr) - if err != nil { - return count, err - } - - s.Put(&Chunk{Key: key, SData: data}) - count++ - } - - return count, nil -} - -func (s *DbStore) Cleanup() { - //Iterates over the database and checks that there are no faulty chunks - it := s.db.NewIterator() - startPosition := []byte{kpIndex} - it.Seek(startPosition) - var key []byte - var errorsFound, total int - for it.Valid() { - key = it.Key() - if (key == nil) || (key[0] != kpIndex) { - break - } - total++ - var index dpaDBIndex - decodeIndex(it.Value(), &index) - - data, err := s.db.Get(getDataKey(index.Idx)) - if err != nil { - log.Warn(fmt.Sprintf("Chunk %x found but could not be accessed: %v", key[:], err)) - s.delete(index.Idx, getIndexKey(key[1:])) - errorsFound++ - } else { - hasher := s.hashfunc() - hasher.Write(data) - hash := hasher.Sum(nil) - if !bytes.Equal(hash, key[1:]) { - log.Warn(fmt.Sprintf("Found invalid chunk. Hash mismatch. hash=%x, key=%x", hash, key[:])) - s.delete(index.Idx, getIndexKey(key[1:])) - errorsFound++ - } - } - it.Next() - } - it.Release() - log.Warn(fmt.Sprintf("Found %v errors out of %v entries", errorsFound, total)) -} - -func (s *DbStore) delete(idx uint64, idxKey []byte) { - batch := new(leveldb.Batch) - batch.Delete(idxKey) - batch.Delete(getDataKey(idx)) - s.entryCnt-- - batch.Put(keyEntryCnt, U64ToBytes(s.entryCnt)) - s.db.Write(batch) -} - -func (s *DbStore) Counter() uint64 { - s.lock.Lock() - defer s.lock.Unlock() - return s.dataIdx -} - -func (s *DbStore) Put(chunk *Chunk) { - s.lock.Lock() - defer s.lock.Unlock() - - ikey := getIndexKey(chunk.Key) - var index dpaDBIndex - - if s.tryAccessIdx(ikey, &index) { - if chunk.dbStored != nil { - close(chunk.dbStored) - } - log.Trace(fmt.Sprintf("Storing to DB: chunk already exists, only update access")) - return // already exists, only update access - } - - data := encodeData(chunk) - //data := ethutil.Encode([]interface{}{entry}) - - if s.entryCnt >= s.capacity { - s.collectGarbage(gcArrayFreeRatio) - } - - batch := new(leveldb.Batch) - - batch.Put(getDataKey(s.dataIdx), data) - - index.Idx = s.dataIdx - s.updateIndexAccess(&index) - - idata := encodeIndex(&index) - batch.Put(ikey, idata) - - batch.Put(keyEntryCnt, U64ToBytes(s.entryCnt)) - s.entryCnt++ - batch.Put(keyDataIdx, U64ToBytes(s.dataIdx)) - s.dataIdx++ - batch.Put(keyAccessCnt, U64ToBytes(s.accessCnt)) - s.accessCnt++ - - s.db.Write(batch) - if chunk.dbStored != nil { - close(chunk.dbStored) - } - log.Trace(fmt.Sprintf("DbStore.Put: %v. db storage counter: %v ", chunk.Key.Log(), s.dataIdx)) -} - -// try to find index; if found, update access cnt and return true -func (s *DbStore) tryAccessIdx(ikey []byte, index *dpaDBIndex) bool { - idata, err := s.db.Get(ikey) - if err != nil { - return false - } - decodeIndex(idata, index) - - batch := new(leveldb.Batch) - - batch.Put(keyAccessCnt, U64ToBytes(s.accessCnt)) - s.accessCnt++ - s.updateIndexAccess(index) - idata = encodeIndex(index) - batch.Put(ikey, idata) - - s.db.Write(batch) - - return true -} - -func (s *DbStore) Get(key Key) (chunk *Chunk, err error) { - s.lock.Lock() - defer s.lock.Unlock() - - var index dpaDBIndex - - if s.tryAccessIdx(getIndexKey(key), &index) { - var data []byte - data, err = s.db.Get(getDataKey(index.Idx)) - if err != nil { - log.Trace(fmt.Sprintf("DBStore: Chunk %v found but could not be accessed: %v", key.Log(), err)) - s.delete(index.Idx, getIndexKey(key)) - return - } - - hasher := s.hashfunc() - hasher.Write(data) - hash := hasher.Sum(nil) - if !bytes.Equal(hash, key) { - s.delete(index.Idx, getIndexKey(key)) - log.Warn("Invalid Chunk in Database. Please repair with command: 'swarm cleandb'") - } - - chunk = &Chunk{ - Key: key, - } - decodeData(data, chunk) - } else { - err = notFound - } - - return - -} - -func (s *DbStore) updateAccessCnt(key Key) { - - s.lock.Lock() - defer s.lock.Unlock() - - var index dpaDBIndex - s.tryAccessIdx(getIndexKey(key), &index) // result_chn == nil, only update access cnt - -} - -func (s *DbStore) setCapacity(c uint64) { - - s.lock.Lock() - defer s.lock.Unlock() - - s.capacity = c - - if s.entryCnt > c { - ratio := float32(1.01) - float32(c)/float32(s.entryCnt) - if ratio < gcArrayFreeRatio { - ratio = gcArrayFreeRatio - } - if ratio > 1 { - ratio = 1 - } - for s.entryCnt > c { - s.collectGarbage(ratio) - } - } -} - -func (s *DbStore) Close() { - s.db.Close() -} - -// describes a section of the DbStore representing the unsynced -// domain relevant to a peer -// Start - Stop designate a continuous area Keys in an address space -// typically the addresses closer to us than to the peer but not closer -// another closer peer in between -// From - To designates a time interval typically from the last disconnect -// till the latest connection (real time traffic is relayed) -type DbSyncState struct { - Start, Stop Key - First, Last uint64 -} - -// implements the syncer iterator interface -// iterates by storage index (~ time of storage = first entry to db) -type dbSyncIterator struct { - it iterator.Iterator - DbSyncState -} - -// initialises a sync iterator from a syncToken (passed in with the handshake) -func (self *DbStore) NewSyncIterator(state DbSyncState) (si *dbSyncIterator, err error) { - if state.First > state.Last { - return nil, fmt.Errorf("no entries found") - } - si = &dbSyncIterator{ - it: self.db.NewIterator(), - DbSyncState: state, - } - si.it.Seek(getIndexKey(state.Start)) - return si, nil -} - -// walk the area from Start to Stop and returns items within time interval -// First to Last -func (self *dbSyncIterator) Next() (key Key) { - for self.it.Valid() { - dbkey := self.it.Key() - if dbkey[0] != 0 { - break - } - key = Key(make([]byte, len(dbkey)-1)) - copy(key[:], dbkey[1:]) - if bytes.Compare(key[:], self.Start) <= 0 { - self.it.Next() - continue - } - if bytes.Compare(key[:], self.Stop) > 0 { - break - } - var index dpaDBIndex - decodeIndex(self.it.Value(), &index) - self.it.Next() - if (index.Idx >= self.First) && (index.Idx < self.Last) { - return - } - } - self.it.Release() - return nil -} diff --git a/swarm/storage/dbstore_test.go b/swarm/storage/dbstore_test.go deleted file mode 100644 index dd165b5768..0000000000 --- a/swarm/storage/dbstore_test.go +++ /dev/null @@ -1,191 +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 storage - -import ( - "bytes" - "io/ioutil" - "testing" - - "github.com/ethereum/go-ethereum/common" -) - -func initDbStore(t *testing.T) *DbStore { - dir, err := ioutil.TempDir("", "bzz-storage-test") - if err != nil { - t.Fatal(err) - } - m, err := NewDbStore(dir, MakeHashFunc(SHA3Hash), defaultDbCapacity, defaultRadius) - if err != nil { - t.Fatal("can't create store:", err) - } - return m -} - -func testDbStore(l int64, branches int64, t *testing.T) { - m := initDbStore(t) - defer m.Close() - testStore(m, l, branches, t) -} - -func TestDbStore128_0x1000000(t *testing.T) { - testDbStore(0x1000000, 128, t) -} - -func TestDbStore128_10000_(t *testing.T) { - testDbStore(10000, 128, t) -} - -func TestDbStore128_1000_(t *testing.T) { - testDbStore(1000, 128, t) -} - -func TestDbStore128_100_(t *testing.T) { - testDbStore(100, 128, t) -} - -func TestDbStore2_100_(t *testing.T) { - testDbStore(100, 2, t) -} - -func TestDbStoreNotFound(t *testing.T) { - m := initDbStore(t) - defer m.Close() - _, err := m.Get(ZeroKey) - if err != notFound { - t.Errorf("Expected notFound, got %v", err) - } -} - -func TestDbStoreSyncIterator(t *testing.T) { - m := initDbStore(t) - defer m.Close() - keys := []Key{ - Key(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000000")), - Key(common.Hex2Bytes("4000000000000000000000000000000000000000000000000000000000000000")), - Key(common.Hex2Bytes("5000000000000000000000000000000000000000000000000000000000000000")), - Key(common.Hex2Bytes("3000000000000000000000000000000000000000000000000000000000000000")), - Key(common.Hex2Bytes("2000000000000000000000000000000000000000000000000000000000000000")), - Key(common.Hex2Bytes("1000000000000000000000000000000000000000000000000000000000000000")), - } - for _, key := range keys { - m.Put(NewChunk(key, nil)) - } - it, err := m.NewSyncIterator(DbSyncState{ - Start: Key(common.Hex2Bytes("1000000000000000000000000000000000000000000000000000000000000000")), - Stop: Key(common.Hex2Bytes("4000000000000000000000000000000000000000000000000000000000000000")), - First: 2, - Last: 4, - }) - if err != nil { - t.Fatalf("unexpected error creating NewSyncIterator") - } - - var chunk Key - var res []Key - for { - chunk = it.Next() - if chunk == nil { - break - } - res = append(res, chunk) - } - if len(res) != 1 { - t.Fatalf("Expected 1 chunk, got %v: %v", len(res), res) - } - if !bytes.Equal(res[0][:], keys[3]) { - t.Fatalf("Expected %v chunk, got %v", keys[3], res[0]) - } - - if err != nil { - t.Fatalf("unexpected error creating NewSyncIterator") - } - - it, err = m.NewSyncIterator(DbSyncState{ - Start: Key(common.Hex2Bytes("1000000000000000000000000000000000000000000000000000000000000000")), - Stop: Key(common.Hex2Bytes("5000000000000000000000000000000000000000000000000000000000000000")), - First: 2, - Last: 4, - }) - - res = nil - for { - chunk = it.Next() - if chunk == nil { - break - } - res = append(res, chunk) - } - if len(res) != 2 { - t.Fatalf("Expected 2 chunk, got %v: %v", len(res), res) - } - if !bytes.Equal(res[0][:], keys[3]) { - t.Fatalf("Expected %v chunk, got %v", keys[3], res[0]) - } - if !bytes.Equal(res[1][:], keys[2]) { - t.Fatalf("Expected %v chunk, got %v", keys[2], res[1]) - } - - if err != nil { - t.Fatalf("unexpected error creating NewSyncIterator") - } - - it, _ = m.NewSyncIterator(DbSyncState{ - Start: Key(common.Hex2Bytes("1000000000000000000000000000000000000000000000000000000000000000")), - Stop: Key(common.Hex2Bytes("4000000000000000000000000000000000000000000000000000000000000000")), - First: 2, - Last: 5, - }) - res = nil - for { - chunk = it.Next() - if chunk == nil { - break - } - res = append(res, chunk) - } - if len(res) != 2 { - t.Fatalf("Expected 2 chunk, got %v", len(res)) - } - if !bytes.Equal(res[0][:], keys[4]) { - t.Fatalf("Expected %v chunk, got %v", keys[4], res[0]) - } - if !bytes.Equal(res[1][:], keys[3]) { - t.Fatalf("Expected %v chunk, got %v", keys[3], res[1]) - } - - it, _ = m.NewSyncIterator(DbSyncState{ - Start: Key(common.Hex2Bytes("2000000000000000000000000000000000000000000000000000000000000000")), - Stop: Key(common.Hex2Bytes("4000000000000000000000000000000000000000000000000000000000000000")), - First: 2, - Last: 5, - }) - res = nil - for { - chunk = it.Next() - if chunk == nil { - break - } - res = append(res, chunk) - } - if len(res) != 1 { - t.Fatalf("Expected 1 chunk, got %v", len(res)) - } - if !bytes.Equal(res[0][:], keys[3]) { - t.Fatalf("Expected %v chunk, got %v", keys[3], res[0]) - } -} diff --git a/swarm/storage/dpa.go b/swarm/storage/dpa.go deleted file mode 100644 index 44a2669f12..0000000000 --- a/swarm/storage/dpa.go +++ /dev/null @@ -1,241 +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 storage - -import ( - "errors" - "fmt" - "io" - "sync" - "time" - - "github.com/ethereum/go-ethereum/log" -) - -/* -DPA provides the client API entrypoints Store and Retrieve to store and retrieve -It can store anything that has a byte slice representation, so files or serialised objects etc. - -Storage: DPA calls the Chunker to segment the input datastream of any size to a merkle hashed tree of chunks. The key of the root block is returned to the client. - -Retrieval: given the key of the root block, the DPA retrieves the block chunks and reconstructs the original data and passes it back as a lazy reader. A lazy reader is a reader with on-demand delayed processing, i.e. the chunks needed to reconstruct a large file are only fetched and processed if that particular part of the document is actually read. - -As the chunker produces chunks, DPA dispatches them to its own chunk store -implementation for storage or retrieval. -*/ - -const ( - storeChanCapacity = 100 - retrieveChanCapacity = 100 - singletonSwarmDbCapacity = 50000 - singletonSwarmCacheCapacity = 500 - maxStoreProcesses = 8 - maxRetrieveProcesses = 8 -) - -var ( - notFound = errors.New("not found") -) - -type DPA struct { - ChunkStore - storeC chan *Chunk - retrieveC chan *Chunk - Chunker Chunker - - lock sync.Mutex - running bool - quitC chan bool -} - -// for testing locally -func NewLocalDPA(datadir string) (*DPA, error) { - - hash := MakeHashFunc("SHA256") - - dbStore, err := NewDbStore(datadir, hash, singletonSwarmDbCapacity, 0) - if err != nil { - return nil, err - } - - return NewDPA(&LocalStore{ - NewMemStore(dbStore, singletonSwarmCacheCapacity), - dbStore, - }, NewChunkerParams()), nil -} - -func NewDPA(store ChunkStore, params *ChunkerParams) *DPA { - chunker := NewTreeChunker(params) - return &DPA{ - Chunker: chunker, - ChunkStore: store, - } -} - -// 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. -func (self *DPA) Retrieve(key Key) LazySectionReader { - return self.Chunker.Join(key, self.retrieveC) -} - -// Public API. Main entry point for document storage directly. Used by the -// FS-aware API and httpaccess -func (self *DPA) Store(data io.Reader, size int64, swg *sync.WaitGroup, wwg *sync.WaitGroup) (key Key, err error) { - return self.Chunker.Split(data, size, self.storeC, swg, wwg) -} - -func (self *DPA) Start() { - self.lock.Lock() - defer self.lock.Unlock() - if self.running { - return - } - self.running = true - self.retrieveC = make(chan *Chunk, retrieveChanCapacity) - self.storeC = make(chan *Chunk, storeChanCapacity) - self.quitC = make(chan bool) - self.storeLoop() - self.retrieveLoop() -} - -func (self *DPA) Stop() { - self.lock.Lock() - defer self.lock.Unlock() - if !self.running { - return - } - self.running = false - close(self.quitC) -} - -// retrieveLoop dispatches the parallel chunk retrieval requests received on the -// retrieve channel to its ChunkStore (NetStore or LocalStore) -func (self *DPA) retrieveLoop() { - for i := 0; i < maxRetrieveProcesses; i++ { - go self.retrieveWorker() - } - log.Trace(fmt.Sprintf("dpa: retrieve loop spawning %v workers", maxRetrieveProcesses)) -} - -func (self *DPA) retrieveWorker() { - for chunk := range self.retrieveC { - log.Trace(fmt.Sprintf("dpa: retrieve loop : chunk %v", chunk.Key.Log())) - storedChunk, err := self.Get(chunk.Key) - if err == notFound { - log.Trace(fmt.Sprintf("chunk %v not found", chunk.Key.Log())) - } else if err != nil { - log.Trace(fmt.Sprintf("error retrieving chunk %v: %v", chunk.Key.Log(), err)) - } else { - chunk.SData = storedChunk.SData - chunk.Size = storedChunk.Size - } - close(chunk.C) - - select { - case <-self.quitC: - return - default: - } - } -} - -// storeLoop dispatches the parallel chunk store request processors -// received on the store channel to its ChunkStore (NetStore or LocalStore) -func (self *DPA) storeLoop() { - for i := 0; i < maxStoreProcesses; i++ { - go self.storeWorker() - } - log.Trace(fmt.Sprintf("dpa: store spawning %v workers", maxStoreProcesses)) -} - -func (self *DPA) storeWorker() { - - for chunk := range self.storeC { - self.Put(chunk) - if chunk.wg != nil { - log.Trace(fmt.Sprintf("dpa: store processor %v", chunk.Key.Log())) - chunk.wg.Done() - - } - select { - case <-self.quitC: - return - default: - } - } -} - -// DpaChunkStore implements the ChunkStore interface, -// this chunk access layer assumed 2 chunk stores -// local storage eg. LocalStore and network storage eg., NetStore -// access by calling network is blocking with a timeout - -type dpaChunkStore struct { - n int - localStore ChunkStore - netStore ChunkStore -} - -func NewDpaChunkStore(localStore, netStore ChunkStore) *dpaChunkStore { - return &dpaChunkStore{0, localStore, netStore} -} - -// Get is the entrypoint for local retrieve requests -// waits for response or times out -func (self *dpaChunkStore) Get(key Key) (chunk *Chunk, err error) { - chunk, err = self.netStore.Get(key) - // timeout := time.Now().Add(searchTimeout) - if chunk.SData != nil { - log.Trace(fmt.Sprintf("DPA.Get: %v found locally, %d bytes", key.Log(), len(chunk.SData))) - return - } - // TODO: use self.timer time.Timer and reset with defer disableTimer - timer := time.After(searchTimeout) - select { - case <-timer: - log.Trace(fmt.Sprintf("DPA.Get: %v request time out ", key.Log())) - err = notFound - case <-chunk.Req.C: - log.Trace(fmt.Sprintf("DPA.Get: %v retrieved, %d bytes (%p)", key.Log(), len(chunk.SData), chunk)) - } - return -} - -// Put is the entrypoint for local store requests coming from storeLoop -func (self *dpaChunkStore) Put(entry *Chunk) { - chunk, err := self.localStore.Get(entry.Key) - if err != nil { - log.Trace(fmt.Sprintf("DPA.Put: %v new chunk. call netStore.Put", entry.Key.Log())) - chunk = entry - } else if chunk.SData == nil { - log.Trace(fmt.Sprintf("DPA.Put: %v request entry found", entry.Key.Log())) - chunk.SData = entry.SData - chunk.Size = entry.Size - } else { - log.Trace(fmt.Sprintf("DPA.Put: %v chunk already known", entry.Key.Log())) - return - } - // from this point on the storage logic is the same with network storage requests - log.Trace(fmt.Sprintf("DPA.Put %v: %v", self.n, chunk.Key.Log())) - self.n++ - self.netStore.Put(chunk) -} - -// Close chunk store -func (self *dpaChunkStore) Close() {} diff --git a/swarm/storage/dpa_test.go b/swarm/storage/dpa_test.go deleted file mode 100644 index a23b9efebe..0000000000 --- a/swarm/storage/dpa_test.go +++ /dev/null @@ -1,143 +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 storage - -import ( - "bytes" - "io" - "io/ioutil" - "os" - "sync" - "testing" -) - -const testDataSize = 0x1000000 - -func TestDPArandom(t *testing.T) { - dbStore := initDbStore(t) - dbStore.setCapacity(50000) - memStore := NewMemStore(dbStore, defaultCacheCapacity) - localStore := &LocalStore{ - memStore, - dbStore, - } - chunker := NewTreeChunker(NewChunkerParams()) - dpa := &DPA{ - Chunker: chunker, - ChunkStore: localStore, - } - dpa.Start() - defer dpa.Stop() - defer os.RemoveAll("/tmp/bzz") - - reader, slice := testDataReaderAndSlice(testDataSize) - wg := &sync.WaitGroup{} - key, err := dpa.Store(reader, testDataSize, wg, nil) - if err != nil { - t.Errorf("Store error: %v", err) - } - wg.Wait() - resultReader := dpa.Retrieve(key) - resultSlice := make([]byte, len(slice)) - n, err := resultReader.ReadAt(resultSlice, 0) - if err != io.EOF { - t.Errorf("Retrieve error: %v", err) - } - if n != len(slice) { - t.Errorf("Slice size error got %d, expected %d.", n, len(slice)) - } - if !bytes.Equal(slice, resultSlice) { - t.Errorf("Comparison error.") - } - ioutil.WriteFile("/tmp/slice.bzz.16M", slice, 0666) - ioutil.WriteFile("/tmp/result.bzz.16M", resultSlice, 0666) - localStore.memStore = NewMemStore(dbStore, defaultCacheCapacity) - resultReader = dpa.Retrieve(key) - for i := range resultSlice { - resultSlice[i] = 0 - } - n, err = resultReader.ReadAt(resultSlice, 0) - if err != io.EOF { - t.Errorf("Retrieve error after removing memStore: %v", err) - } - if n != len(slice) { - t.Errorf("Slice size error after removing memStore got %d, expected %d.", n, len(slice)) - } - if !bytes.Equal(slice, resultSlice) { - t.Errorf("Comparison error after removing memStore.") - } -} - -func TestDPA_capacity(t *testing.T) { - dbStore := initDbStore(t) - memStore := NewMemStore(dbStore, defaultCacheCapacity) - localStore := &LocalStore{ - memStore, - dbStore, - } - memStore.setCapacity(0) - chunker := NewTreeChunker(NewChunkerParams()) - dpa := &DPA{ - Chunker: chunker, - ChunkStore: localStore, - } - dpa.Start() - reader, slice := testDataReaderAndSlice(testDataSize) - wg := &sync.WaitGroup{} - key, err := dpa.Store(reader, testDataSize, wg, nil) - if err != nil { - t.Errorf("Store error: %v", err) - } - wg.Wait() - resultReader := dpa.Retrieve(key) - resultSlice := make([]byte, len(slice)) - n, err := resultReader.ReadAt(resultSlice, 0) - if err != io.EOF { - t.Errorf("Retrieve error: %v", err) - } - if n != len(slice) { - t.Errorf("Slice size error got %d, expected %d.", n, len(slice)) - } - if !bytes.Equal(slice, resultSlice) { - t.Errorf("Comparison error.") - } - // Clear memStore - memStore.setCapacity(0) - // check whether it is, indeed, empty - dpa.ChunkStore = memStore - resultReader = dpa.Retrieve(key) - if _, err = resultReader.ReadAt(resultSlice, 0); err == nil { - t.Errorf("Was able to read %d bytes from an empty memStore.", len(slice)) - } - // check how it works with localStore - dpa.ChunkStore = localStore - // localStore.dbStore.setCapacity(0) - resultReader = dpa.Retrieve(key) - for i := range resultSlice { - resultSlice[i] = 0 - } - n, err = resultReader.ReadAt(resultSlice, 0) - if err != io.EOF { - t.Errorf("Retrieve error after clearing memStore: %v", err) - } - if n != len(slice) { - t.Errorf("Slice size error after clearing memStore got %d, expected %d.", n, len(slice)) - } - if !bytes.Equal(slice, resultSlice) { - t.Errorf("Comparison error after clearing memStore.") - } -} diff --git a/swarm/storage/encryption/encryption.go b/swarm/storage/encryption/encryption.go new file mode 100644 index 0000000000..6fbdab062b --- /dev/null +++ b/swarm/storage/encryption/encryption.go @@ -0,0 +1,152 @@ +// 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 encryption + +import ( + "crypto/rand" + "encoding/binary" + "fmt" + "hash" + "sync" +) + +const KeyLength = 32 + +type Key []byte + +type Encryption interface { + Encrypt(data []byte) ([]byte, error) + Decrypt(data []byte) ([]byte, error) +} + +type encryption struct { + key Key // the encryption key (hashSize bytes long) + keyLen int // length of the key = length of blockcipher block + padding int // encryption will pad the data upto this if > 0 + initCtr uint32 // initial counter used for counter mode blockcipher + hashFunc func() hash.Hash // hasher constructor function +} + +// New constructs a new encryptor/decryptor +func New(key Key, padding int, initCtr uint32, hashFunc func() hash.Hash) *encryption { + return &encryption{ + key: key, + keyLen: len(key), + padding: padding, + initCtr: initCtr, + hashFunc: hashFunc, + } +} + +// Encrypt encrypts the data and does padding if specified +func (e *encryption) Encrypt(data []byte) ([]byte, error) { + length := len(data) + outLength := length + isFixedPadding := e.padding > 0 + if isFixedPadding { + if length > e.padding { + return nil, fmt.Errorf("Data length longer than padding, data length %v padding %v", length, e.padding) + } + outLength = e.padding + } + out := make([]byte, outLength) + e.transform(data, out) + return out, nil +} + +// Decrypt decrypts the data, if padding was used caller must know original length and truncate +func (e *encryption) Decrypt(data []byte) ([]byte, error) { + length := len(data) + if e.padding > 0 && length != e.padding { + return nil, fmt.Errorf("Data length different than padding, data length %v padding %v", length, e.padding) + } + out := make([]byte, length) + e.transform(data, out) + return out, nil +} + +// +func (e *encryption) transform(in, out []byte) { + inLength := len(in) + wg := sync.WaitGroup{} + wg.Add((inLength-1)/e.keyLen + 1) + for i := 0; i < inLength; i += e.keyLen { + l := min(e.keyLen, inLength-i) + // call transformations per segment (asyncronously) + go func(i int, x, y []byte) { + defer wg.Done() + e.Transcrypt(i, x, y) + }(i/e.keyLen, in[i:i+l], out[i:i+l]) + } + // pad the rest if out is longer + pad(out[inLength:]) + wg.Wait() +} + +// used for segmentwise transformation +// if in is shorter than out, padding is used +func (e *encryption) Transcrypt(i int, in []byte, out []byte) { + // first hash key with counter (initial counter + i) + hasher := e.hashFunc() + hasher.Write(e.key) + + ctrBytes := make([]byte, 4) + binary.LittleEndian.PutUint32(ctrBytes, uint32(i)+e.initCtr) + hasher.Write(ctrBytes) + + ctrHash := hasher.Sum(nil) + hasher.Reset() + + // second round of hashing for selective disclosure + hasher.Write(ctrHash) + segmentKey := hasher.Sum(nil) + hasher.Reset() + + // XOR bytes uptil length of in (out must be at least as long) + inLength := len(in) + for j := 0; j < inLength; j++ { + out[j] = in[j] ^ segmentKey[j] + } + // insert padding if out is longer + pad(out[inLength:]) +} + +func pad(b []byte) { + l := len(b) + for total := 0; total < l; { + read, _ := rand.Read(b[total:]) + total += read + } +} + +// GenerateRandomKey generates a random key of length l +func GenerateRandomKey(l int) Key { + key := make([]byte, l) + var total int + for total < l { + read, _ := rand.Read(key[total:]) + total += read + } + return key +} + +func min(x, y int) int { + if x < y { + return x + } + return y +} diff --git a/swarm/storage/encryption/encryption_test.go b/swarm/storage/encryption/encryption_test.go new file mode 100644 index 0000000000..3b4f8a4e36 --- /dev/null +++ b/swarm/storage/encryption/encryption_test.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 encryption + +import ( + "bytes" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/swarm/testutil" + "golang.org/x/crypto/sha3" +) + +var expectedTransformedHex = "352187af3a843decc63ceca6cb01ea39dbcf77caf0a8f705f5c30d557044ceec9392b94a79376f1e5c10cd0c0f2a98e5353bf22b3ea4fdac6677ee553dec192e3db64e179d0474e96088fb4abd2babd67de123fb398bdf84d818f7bda2c1ab60b3ea0e0569ae54aa969658eb4844e6960d2ff44d7c087ee3aaffa1c0ee5df7e50b615f7ad90190f022934ad5300c7d1809bfe71a11cc04cece5274eb97a5f20350630522c1dbb7cebaf4f97f84e03f5cfd88f2b48880b25d12f4d5e75c150f704ef6b46c72e07db2b705ac3644569dccd22fd8f964f6ef787fda63c46759af334e6f665f70eac775a7017acea49f3c7696151cb1b9434fa4ac27fb803921ffb5ec58dafa168098d7d5b97e384be3384cf5bc235c3d887fef89fe76c0065f9b8d6ad837b442340d9e797b46ef5709ea3358bc415df11e4830de986ef0f1c418ffdcc80e9a3cda9bea0ab5676c0d4240465c43ba527e3b4ea50b4f6255b510e5d25774a75449b0bd71e56c537ade4fcf0f4d63c99ae1dbb5a844971e2c19941b8facfcfc8ee3056e7cb3c7114c5357e845b52f7103cb6e00d2308c37b12baa5b769e1cc7b00fc06f2d16e70cc27a82cb9c1a4e40cb0d43907f73df2c9db44f1b51a6b0bc6d09f77ac3be14041fae3f9df2da42df43ae110904f9ecee278030185254d7c6e918a5512024d047f77a992088cb3190a6587aa54d0c7231c1cd2e455e0d4c07f74bece68e29cd8ba0190c0bcfb26d24634af5d91a81ef5d4dd3d614836ce942ddbf7bb1399317f4c03faa675f325f18324bf9433844bfe5c4cc04130c8d5c329562b7cd66e72f7355de8f5375a72202971613c32bd7f3fcdcd51080758cd1d0a46dbe8f0374381dbc359f5864250c63dde8131cbd7c98ae2b0147d6ea4bf65d1443d511b18e6d608bbb46ac036353b4c51df306a10a6f6939c38629a5c18aaf89cac04bd3ad5156e6b92011c88341cb08551bab0a89e6a46538f5af33b86121dba17e3a434c273f385cd2e8cb90bdd32747d8425d929ccbd9b0815c73325988855549a8489dfd047daf777aaa3099e54cf997175a5d9e1edfe363e3b68c70e02f6bf4fcde6a0f3f7d0e7e98bde1a72ae8b6cd27b32990680cc4a04fc467f41c5adcaddabfc71928a3f6872c360c1d765260690dd28b269864c8e380d9c92ef6b89b0094c8f9bb22608b4156381b19b920e9583c9616ce5693b4d2a6c689f02e6a91584a8e501e107403d2689dd0045269dd9946c0e969fb656a3b39d84a798831f5f9290f163eb2f97d3ae25071324e95e2256d9c1e56eb83c26397855323edc202d56ad05894333b7f0ed3c1e4734782eb8bd5477242fd80d7a89b12866f85cfae476322f032465d6b1253993033fccd4723530630ab97a1566460af9c90c9da843c229406e65f3fa578bd6bf04dee9b6153807ddadb8ceefc5c601a8ab26023c67b1ab1e8e0f29ce94c78c308005a781853e7a2e0e51738939a657c987b5e611f32f47b5ff461c52e63e0ea390515a8e1f5393dae54ea526934b5f310b76e3fa050e40718cb4c8a20e58946d6ee1879f08c52764422fe542b3240e75eccb7aa75b1f8a651e37a3bc56b0932cdae0e985948468db1f98eb4b77b82081ea25d8a762db00f7898864984bd80e2f3f35f236bf57291dec28f550769943bcfb6f884b7687589b673642ef7fe5d7d5a87d3eca5017f83ccb9a3310520474479464cb3f433440e7e2f1e28c0aef700a45848573409e7ab66e0cfd4fe5d2147ace81bc65fd8891f6245cd69246bbf5c27830e5ab882dd1d02aba34ff6ca9af88df00fd602892f02fedbdc65dedec203faf3f8ff4a97314e0ddb58b9ab756a61a562597f4088b445fcc3b28a708ca7b1485dcd791b779fbf2b3ef1ec5c6205f595fbe45a02105034147e5a146089c200a49dae33ae051a08ea5f974a21540aaeffa7f9d9e3d35478016fb27b871036eb27217a5b834b461f535752fb5f1c8dded3ae14ce3a2ef6639e2fe41939e3509e46e347a95d50b2080f1ba42c804b290ddc912c952d1cec3f2661369f738feacc0dbf1ea27429c644e45f9e26f30c341acd34c7519b2a1663e334621691e810767e9918c2c547b2e23cce915f97d26aac8d0d2fcd3edb7986ad4e2b8a852edebad534cb6c0e9f0797d3563e5409d7e068e48356c67ce519246cd9c560e881453df97cbba562018811e6cf8c327f399d1d1253ab47a19f4a0ccc7c6d86a9603e0551da310ea595d71305c4aad96819120a92cdbaf1f77ec8df9cc7c838c0d4de1e8692dd81da38268d1d71324bcffdafbe5122e4b81828e021e936d83ae8021eac592aa52cd296b5ce392c7173d622f8e07d18f59bb1b08ba15211af6703463b09b593af3c37735296816d9f2e7a369354a5374ea3955e14ca8ac56d5bfe4aef7a21bd825d6ae85530bee5d2aaaa4914981b3dfdb2e92ec2a27c83d74b59e84ff5c056f7d8945745f2efc3dcf28f288c6cd8383700fb2312f7001f24dd40015e436ae23e052fe9070ea9535b9c989898a9bda3d5382cf10e432fae6ccf0c825b3e6436edd3a9f8846e5606f8563931b5f29ba407c5236e5730225dda211a8504ec1817bc935e1fd9a532b648c502df302ed2063aed008fd5676131ac9e95998e9447b02bd29d77e38fcfd2959f2de929b31970335eb2a74348cc6918bc35b9bf749eab0fe304c946cd9e1ca284e6853c42646e60b6b39e0d3fb3c260abfc5c1b4ca3c3770f344118ca7c7f5c1ad1f123f8f369cd60afc3cdb3e9e81968c5c9fa7c8b014ffe0508dd4f0a2a976d5d1ca8fc9ad7a237d92cfe7b41413d934d6e142824b252699397e48e4bac4e91ebc10602720684bd0863773c548f9a2f9724245e47b129ecf65afd7252aac48c8a8d6fd3d888af592a01fb02dc71ed7538a700d3d16243e4621e0fcf9f8ed2b4e11c9fa9a95338bb1dac74a7d9bc4eb8cbf900b634a2a56469c00f5994e4f0934bdb947640e6d67e47d0b621aacd632bfd3c800bd7d93bd329f494a90e06ed51535831bd6e07ac1b4b11434ef3918fa9511813a002913f33f836454798b8d1787fea9a4c4743ba091ed192ed92f4d33e43a226bf9503e1a83a16dd340b3cbbf38af6db0d99201da8de529b4225f3d2fa2aad6621afc6c79ef3537720591edfc681ae6d00ede53ed724fc71b23b90d2e9b7158aaee98d626a4fe029107df2cb5f90147e07ebe423b1519d848af18af365c71bfd0665db46be493bbe99b79a188de0cf3594aef2299f0324075bdce9eb0b87bc29d62401ba4fd6ae48b1ba33261b5b845279becf38ee03e3dc5c45303321c5fac96fd02a3ad8c9e3b02127b320501333c9e6360440d1ad5e64a6239501502dde1a49c9abe33b66098458eee3d611bb06ffcd234a1b9aef4af5021cd61f0de6789f822ee116b5078aae8c129e8391d8987500d322b58edd1595dc570b57341f2df221b94a96ab7fbcf32a8ca9684196455694024623d7ed49f7d66e8dd453c0bae50e0d8b34377b22d0ece059e2c385dfc70b9089fcd27577c51f4d870b5738ee2b68c361a67809c105c7848b68860a829f29930857a9f9d40b14fd2384ac43bafdf43c0661103794c4bd07d1cfdd4681b6aeaefad53d4c1473359bcc5a83b09189352e5bb9a7498dd0effb89c35aad26954551f8b0621374b449bf515630bd3974dca982279733470fdd059aa9c3df403d8f22b38c4709c82d8f12b888e22990350490e16179caf406293cc9e65f116bafcbe96af132f679877061107a2f690a82a8cb46eea57a90abd23798c5937c6fe6b17be3f9bfa01ce117d2c268181b9095bf49f395fea07ca03838de0588c5e2db633e836d64488c1421e653ea52d810d096048c092d0da6e02fa6613890219f51a76148c8588c2487b171a28f17b7a299204874af0131725d793481333be5f08e86ca837a226850b0c1060891603bfecf9e55cddd22c0dbb28d495342d9cc3de8409f72e52a0115141cffe755c74f061c1a770428ccb0ae59536ee6fc074fbfc6cacb51a549d327527e20f8407477e60355863f1153f9ce95641198663c968874e7fdb29407bd771d94fdda8180cbb0358f5874738db705924b8cbe0cd5e1484aeb64542fe8f38667b7c34baf818c63b1e18440e9fba575254d063fd49f24ef26432f4eb323f3836972dca87473e3e9bb26dc3be236c3aae6bc8a6da567442309da0e8450e242fc9db836e2964f2c76a3b80a2c677979882dda7d7ebf62c93664018bcf4ec431fe6b403d49b3b36618b9c07c2d0d4569cb8d52223903debc72ec113955b206c34f1ae5300990ccfc0180f47d91afdb542b6312d12aeff7e19c645dc0b9fe6e3288e9539f6d5870f99882df187bfa6d24d179dfd1dac22212c8b5339f7171a3efc15b760fed8f68538bc5cbd845c2d1ab41f3a6c692820653eaef7930c02fbe6061d93805d73decdbb945572a7c44ed0241982a6e4d2d730898f82b3d9877cb7bca41cc6dcee67aa0c3d6db76f0b0a708ace0031113e48429de5d886c10e9200f68f32263a2fbf44a5992c2459fda7b8796ba796e3a0804fc25992ed2c9a5fe0580a6b809200ecde6caa0364b58be11564dcb9a616766dd7906db5636ee708b0204f38d309466d8d4a162965dd727e29f5a6c133e9b4ed5bafe803e479f9b2a7640c942c4a40b14ac7dc9828546052761a070f6404008f1ec3605836339c3da95a00b4fd81b2cabf88b51d2087d5b83e8c5b69bf96d8c72cbd278dad3bbb42b404b436f84ad688a22948adf60a81090f1e904291503c16e9f54b05fc76c881a5f95f0e732949e95d3f1bae2d3652a14fe0dda2d68879604657171856ef72637def2a96ac47d7b3fe86eb3198f5e0e626f06be86232305f2ae79ffcd2725e48208f9d8d63523f81915acc957563ab627cd6bc68c2a37d59fb0ed77a90aa9d085d6914a8ebada22a2c2d471b5163aeddd799d90fbb10ed6851ace2c4af504b7d572686700a59d6db46d5e42bb83f8e0c0ffe1dfa6582cc0b34c921ff6e85e83188d24906d5c08bb90069639e713051b3102b53e6f703e8210017878add5df68e6f2b108de279c5490e9eef5590185c4a1c744d4e00d244e1245a8805bd30407b1bc488db44870ccfd75a8af104df78efa2fb7ba31f048a263efdb3b63271fff4922bece9a71187108f65744a24f4947dc556b7440cb4fa45d296bb7f724588d1f245125b21ea063500029bd49650237f53899daf1312809552c81c5827341263cc807a29fe84746170cdfa1ff3838399a5645319bcaff674bb70efccdd88b3d3bb2f2d98111413585dc5d5bd5168f43b3f55e58972a5b2b9b3733febf02f931bd436648cb617c3794841aab961fe41277ab07812e1d3bc4ff6f4350a3e615bfba08c3b9480ef57904d3a16f7e916345202e3f93d11f7a7305170cb8c4eb9ac88ace8bbd1f377bdd5855d3162d6723d4435e84ce529b8f276a8927915ac759a0d04e5ca4a9d3da6291f0333b475df527e99fe38f7a4082662e8125936640c26dd1d17cf284ce6e2b17777a05aa0574f7793a6a062cc6f7263f7ab126b4528a17becfdec49ac0f7d8705aa1704af97fb861faa8a466161b2b5c08a5bacc79fe8500b913d65c8d3c52d1fd52d2ab2c9f52196e712455619c1cd3e0f391b274487944240e2ed8858dd0823c801094310024ae3fe4dd1cf5a2b6487b42cc5937bbafb193ee331d87e378258963d49b9da90899bbb4b88e79f78e866b0213f4719f67da7bcc2fce073c01e87c62ea3cdbcd589cfc41281f2f4c757c742d6d1e" + +var hashFunc = sha3.NewLegacyKeccak256 +var testKey Key + +func init() { + var err error + testKey, err = hexutil.Decode("0x8abf1502f557f15026716030fb6384792583daf39608a3cd02ff2f47e9bc6e49") + if err != nil { + panic(err.Error()) + } +} + +func TestEncryptDataLongerThanPadding(t *testing.T) { + enc := New(testKey, 4095, uint32(0), hashFunc) + + data := make([]byte, 4096) + + expectedError := "Data length longer than padding, data length 4096 padding 4095" + + _, err := enc.Encrypt(data) + if err == nil || err.Error() != expectedError { + t.Fatalf("Expected error \"%v\" got \"%v\"", expectedError, err) + } +} + +func TestEncryptDataZeroPadding(t *testing.T) { + enc := New(testKey, 0, uint32(0), hashFunc) + + data := make([]byte, 2048) + + encrypted, err := enc.Encrypt(data) + if err != nil { + t.Fatalf("Expected no error got %v", err) + } + if len(encrypted) != 2048 { + t.Fatalf("Encrypted data length expected \"%v\" got %v", 2048, len(encrypted)) + } +} + +func TestEncryptDataLengthEqualsPadding(t *testing.T) { + enc := New(testKey, 4096, uint32(0), hashFunc) + + data := make([]byte, 4096) + + encrypted, err := enc.Encrypt(data) + if err != nil { + t.Fatalf("Expected no error got %v", err) + } + encryptedHex := common.Bytes2Hex(encrypted) + expectedTransformed := common.Hex2Bytes(expectedTransformedHex) + + if !bytes.Equal(encrypted, expectedTransformed) { + t.Fatalf("Expected %v got %v", expectedTransformedHex, encryptedHex) + } +} + +func TestEncryptDataLengthSmallerThanPadding(t *testing.T) { + enc := New(testKey, 4096, uint32(0), hashFunc) + + data := make([]byte, 4080) + + encrypted, err := enc.Encrypt(data) + if err != nil { + t.Fatalf("Expected no error got %v", err) + } + if len(encrypted) != 4096 { + t.Fatalf("Encrypted data length expected %v got %v", 4096, len(encrypted)) + } +} + +func TestEncryptDataCounterNonZero(t *testing.T) { + // TODO +} + +func TestDecryptDataLengthNotEqualsPadding(t *testing.T) { + enc := New(testKey, 4096, uint32(0), hashFunc) + + data := make([]byte, 4097) + + expectedError := "Data length different than padding, data length 4097 padding 4096" + + _, err := enc.Decrypt(data) + if err == nil || err.Error() != expectedError { + t.Fatalf("Expected error \"%v\" got \"%v\"", expectedError, err) + } +} + +func TestEncryptDecryptIsIdentity(t *testing.T) { + testEncryptDecryptIsIdentity(t, 2048, 0, 2048, 32) + testEncryptDecryptIsIdentity(t, 4096, 0, 4096, 32) + testEncryptDecryptIsIdentity(t, 4096, 0, 1000, 32) + testEncryptDecryptIsIdentity(t, 32, 10, 32, 32) +} + +func testEncryptDecryptIsIdentity(t *testing.T, padding int, initCtr uint32, dataLength int, keyLength int) { + key := GenerateRandomKey(keyLength) + enc := New(key, padding, initCtr, hashFunc) + + data := testutil.RandomBytes(1, dataLength) + + encrypted, err := enc.Encrypt(data) + if err != nil { + t.Fatalf("Expected no error got %v", err) + } + + decrypted, err := enc.Decrypt(encrypted) + if err != nil { + t.Fatalf("Expected no error got %v", err) + } + if len(decrypted) != padding { + t.Fatalf("Expected decrypted data length %v got %v", padding, len(decrypted)) + } + + // we have to remove the extra bytes which were randomly added to fill until padding + if len(data) < padding { + decrypted = decrypted[:len(data)] + } + + if !bytes.Equal(data, decrypted) { + t.Fatalf("Expected decrypted %v got %v", common.Bytes2Hex(data), common.Bytes2Hex(decrypted)) + } +} diff --git a/swarm/storage/error.go b/swarm/storage/error.go new file mode 100644 index 0000000000..1e412e55ce --- /dev/null +++ b/swarm/storage/error.go @@ -0,0 +1,36 @@ +// 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 storage + +import "github.com/ethereum/go-ethereum/swarm/chunk" + +const ( + ErrInit = iota + ErrNotFound + ErrUnauthorized + ErrInvalidValue + ErrDataOverflow + ErrNothingToReturn + ErrInvalidSignature + ErrNotSynced +) + +// Errors are the same as the ones in chunk package for backward compatibility. +var ( + ErrChunkNotFound = chunk.ErrChunkNotFound + ErrChunkInvalid = chunk.ErrChunkNotFound +) diff --git a/event/filter/generic_filter.go b/swarm/storage/feed/binaryserializer.go similarity index 52% rename from event/filter/generic_filter.go rename to swarm/storage/feed/binaryserializer.go index d679b8bfa8..4e4f67a094 100644 --- a/event/filter/generic_filter.go +++ b/swarm/storage/feed/binaryserializer.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,35 +14,31 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package filter +package feed -type Generic struct { - Str1, Str2, Str3 string - Data map[string]struct{} +import "github.com/ethereum/go-ethereum/common/hexutil" - Fn func(data interface{}) +type binarySerializer interface { + binaryPut(serializedData []byte) error + binaryLength() int + binaryGet(serializedData []byte) error } -// self = registered, f = incoming -func (self Generic) Compare(f Filter) bool { - var strMatch, dataMatch = true, true - - filter := f.(Generic) - if (len(self.Str1) > 0 && filter.Str1 != self.Str1) || - (len(self.Str2) > 0 && filter.Str2 != self.Str2) || - (len(self.Str3) > 0 && filter.Str3 != self.Str3) { - strMatch = false - } - - for k := range self.Data { - if _, ok := filter.Data[k]; !ok { - return false - } - } - - return strMatch && dataMatch +// Values interface represents a string key-value store +// useful for building query strings +type Values interface { + Get(key string) string + Set(key, value string) } -func (self Generic) Trigger(data interface{}) { - self.Fn(data) +type valueSerializer interface { + FromValues(values Values) error + AppendValues(values Values) +} + +// Hex serializes the structure and converts it to a hex string +func Hex(bin binarySerializer) string { + b := make([]byte, bin.binaryLength()) + bin.binaryPut(b) + return hexutil.Encode(b) } diff --git a/swarm/storage/feed/binaryserializer_test.go b/swarm/storage/feed/binaryserializer_test.go new file mode 100644 index 0000000000..37828d1c94 --- /dev/null +++ b/swarm/storage/feed/binaryserializer_test.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 feed + +import ( + "encoding/json" + "reflect" + "testing" + + "github.com/ethereum/go-ethereum/common/hexutil" +) + +// KV mocks a key value store +type KV map[string]string + +func (kv KV) Get(key string) string { + return kv[key] +} +func (kv KV) Set(key, value string) { + kv[key] = value +} + +func compareByteSliceToExpectedHex(t *testing.T, variableName string, actualValue []byte, expectedHex string) { + if hexutil.Encode(actualValue) != expectedHex { + t.Fatalf("%s: Expected %s to be %s, got %s", t.Name(), variableName, expectedHex, hexutil.Encode(actualValue)) + } +} + +func testBinarySerializerRecovery(t *testing.T, bin binarySerializer, expectedHex string) { + name := reflect.TypeOf(bin).Elem().Name() + serialized := make([]byte, bin.binaryLength()) + if err := bin.binaryPut(serialized); err != nil { + t.Fatalf("%s.binaryPut error when trying to serialize structure: %s", name, err) + } + + compareByteSliceToExpectedHex(t, name, serialized, expectedHex) + + recovered := reflect.New(reflect.TypeOf(bin).Elem()).Interface().(binarySerializer) + if err := recovered.binaryGet(serialized); err != nil { + t.Fatalf("%s.binaryGet error when trying to deserialize structure: %s", name, err) + } + + if !reflect.DeepEqual(bin, recovered) { + t.Fatalf("Expected that the recovered %s equals the marshalled %s", name, name) + } + + serializedWrongLength := make([]byte, 1) + copy(serializedWrongLength[:], serialized) + if err := recovered.binaryGet(serializedWrongLength); err == nil { + t.Fatalf("Expected %s.binaryGet to fail since data is too small", name) + } +} + +func testBinarySerializerLengthCheck(t *testing.T, bin binarySerializer) { + name := reflect.TypeOf(bin).Elem().Name() + // make a slice that is too small to contain the metadata + serialized := make([]byte, bin.binaryLength()-1) + + if err := bin.binaryPut(serialized); err == nil { + t.Fatalf("Expected %s.binaryPut to fail, since target slice is too small", name) + } +} + +func testValueSerializer(t *testing.T, v valueSerializer, expected KV) { + name := reflect.TypeOf(v).Elem().Name() + kv := make(KV) + + v.AppendValues(kv) + if !reflect.DeepEqual(expected, kv) { + expj, _ := json.Marshal(expected) + gotj, _ := json.Marshal(kv) + t.Fatalf("Expected %s.AppendValues to return %s, got %s", name, string(expj), string(gotj)) + } + + recovered := reflect.New(reflect.TypeOf(v).Elem()).Interface().(valueSerializer) + err := recovered.FromValues(kv) + if err != nil { + t.Fatal(err) + } + + if !reflect.DeepEqual(recovered, v) { + t.Fatalf("Expected recovered %s to be the same", name) + } +} diff --git a/swarm/storage/feed/cacheentry.go b/swarm/storage/feed/cacheentry.go new file mode 100644 index 0000000000..be42008e99 --- /dev/null +++ b/swarm/storage/feed/cacheentry.go @@ -0,0 +1,48 @@ +// 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 feed + +import ( + "bytes" + "context" + "time" + + "github.com/ethereum/go-ethereum/swarm/storage" +) + +const ( + hasherCount = 8 + feedsHashAlgorithm = storage.SHA3Hash + defaultRetrieveTimeout = 100 * time.Millisecond +) + +// cacheEntry caches the last known update of a specific Swarm feed. +type cacheEntry struct { + Update + *bytes.Reader + lastKey storage.Address +} + +// implements storage.LazySectionReader +func (r *cacheEntry) Size(ctx context.Context, _ chan bool) (int64, error) { + return int64(len(r.Update.data)), nil +} + +//returns the feed's topic +func (r *cacheEntry) Topic() Topic { + return r.Feed.Topic +} diff --git a/swarm/storage/feed/doc.go b/swarm/storage/feed/doc.go new file mode 100644 index 0000000000..1f07948f21 --- /dev/null +++ b/swarm/storage/feed/doc.go @@ -0,0 +1,43 @@ +/* +Package feeds defines Swarm Feeds. + +Swarm Feeds allows a user to build an update feed about a particular topic +without resorting to ENS on each update. +The update scheme is built on swarm chunks with chunk keys following +a predictable, versionable pattern. + +A Feed is tied to a unique identifier that is deterministically generated out of +the chosen topic. + +A Feed is defined as the series of updates of a specific user about a particular topic + +Actual data updates are also made in the form of swarm chunks. The keys +of the updates are the hash of a concatenation of properties as follows: + +updateAddr = H(Feed, Epoch ID) +where H is the SHA3 hash function +Feed is the combination of Topic and the user address +Epoch ID is a time slot. See the lookup package for more information. + +A user looking up a the latest update in a Feed only needs to know the Topic +and the other user's address. + +The Feed Update data is: +updatedata = Feed|Epoch|data + +The full update data that goes in the chunk payload is: +updatedata|sign(updatedata) + +Structure Summary: + +Request: Feed Update with signature + Update: headers + data + Header: Protocol version and reserved for future use placeholders + ID: Information about how to locate a specific update + Feed: Represents a user's series of publications about a specific Topic + Topic: Item that the updates are about + User: User who updates the Feed + Epoch: time slot where the update is stored + +*/ +package feed diff --git a/swarm/storage/feed/error.go b/swarm/storage/feed/error.go new file mode 100644 index 0000000000..206ba3316f --- /dev/null +++ b/swarm/storage/feed/error.go @@ -0,0 +1,73 @@ +// 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 feed + +import ( + "fmt" +) + +const ( + ErrInit = iota + ErrNotFound + ErrIO + ErrUnauthorized + ErrInvalidValue + ErrDataOverflow + ErrNothingToReturn + ErrCorruptData + ErrInvalidSignature + ErrNotSynced + ErrPeriodDepth + ErrCnt +) + +// Error is a the typed error object used for Swarm feeds +type Error struct { + code int + err string +} + +// Error implements the error interface +func (e *Error) Error() string { + return e.err +} + +// Code returns the error code +// Error codes are enumerated in the error.go file within the feeds package +func (e *Error) Code() int { + return e.code +} + +// NewError creates a new Swarm feeds Error object with the specified code and custom error message +func NewError(code int, s string) error { + if code < 0 || code >= ErrCnt { + panic("no such error code!") + } + r := &Error{ + err: s, + } + switch code { + case ErrNotFound, ErrIO, ErrUnauthorized, ErrInvalidValue, ErrDataOverflow, ErrNothingToReturn, ErrInvalidSignature, ErrNotSynced, ErrPeriodDepth, ErrCorruptData: + r.code = code + } + return r +} + +// NewErrorf is a convenience version of NewError that incorporates printf-style formatting +func NewErrorf(code int, format string, args ...interface{}) error { + return NewError(code, fmt.Sprintf(format, args...)) +} diff --git a/swarm/storage/feed/feed.go b/swarm/storage/feed/feed.go new file mode 100644 index 0000000000..b6ea665a6f --- /dev/null +++ b/swarm/storage/feed/feed.go @@ -0,0 +1,125 @@ +// 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 feed + +import ( + "hash" + "unsafe" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/swarm/storage" +) + +// Feed represents a particular user's stream of updates on a topic +type Feed struct { + Topic Topic `json:"topic"` + User common.Address `json:"user"` +} + +// Feed layout: +// TopicLength bytes +// userAddr common.AddressLength bytes +const feedLength = TopicLength + common.AddressLength + +// mapKey calculates a unique id for this feed. Used by the cache map in `Handler` +func (f *Feed) mapKey() uint64 { + serializedData := make([]byte, feedLength) + f.binaryPut(serializedData) + hasher := hashPool.Get().(hash.Hash) + defer hashPool.Put(hasher) + hasher.Reset() + hasher.Write(serializedData) + hash := hasher.Sum(nil) + return *(*uint64)(unsafe.Pointer(&hash[0])) +} + +// binaryPut serializes this feed instance into the provided slice +func (f *Feed) binaryPut(serializedData []byte) error { + if len(serializedData) != feedLength { + return NewErrorf(ErrInvalidValue, "Incorrect slice size to serialize feed. Expected %d, got %d", feedLength, len(serializedData)) + } + var cursor int + copy(serializedData[cursor:cursor+TopicLength], f.Topic[:TopicLength]) + cursor += TopicLength + + copy(serializedData[cursor:cursor+common.AddressLength], f.User[:]) + cursor += common.AddressLength + + return nil +} + +// binaryLength returns the expected size of this structure when serialized +func (f *Feed) binaryLength() int { + return feedLength +} + +// binaryGet restores the current instance from the information contained in the passed slice +func (f *Feed) binaryGet(serializedData []byte) error { + if len(serializedData) != feedLength { + return NewErrorf(ErrInvalidValue, "Incorrect slice size to read feed. Expected %d, got %d", feedLength, len(serializedData)) + } + + var cursor int + copy(f.Topic[:], serializedData[cursor:cursor+TopicLength]) + cursor += TopicLength + + copy(f.User[:], serializedData[cursor:cursor+common.AddressLength]) + cursor += common.AddressLength + + return nil +} + +// Hex serializes the feed to a hex string +func (f *Feed) Hex() string { + serializedData := make([]byte, feedLength) + f.binaryPut(serializedData) + return hexutil.Encode(serializedData) +} + +// FromValues deserializes this instance from a string key-value store +// useful to parse query strings +func (f *Feed) FromValues(values Values) (err error) { + topic := values.Get("topic") + if topic != "" { + if err := f.Topic.FromHex(values.Get("topic")); err != nil { + return err + } + } else { // see if the user set name and relatedcontent + name := values.Get("name") + relatedContent, _ := hexutil.Decode(values.Get("relatedcontent")) + if len(relatedContent) > 0 { + if len(relatedContent) < storage.AddressLength { + return NewErrorf(ErrInvalidValue, "relatedcontent field must be a hex-encoded byte array exactly %d bytes long", storage.AddressLength) + } + relatedContent = relatedContent[:storage.AddressLength] + } + f.Topic, err = NewTopic(name, relatedContent) + if err != nil { + return err + } + } + f.User = common.HexToAddress(values.Get("user")) + return nil +} + +// AppendValues serializes this structure into the provided string key-value store +// useful to build query strings +func (f *Feed) AppendValues(values Values) { + values.Set("topic", f.Topic.Hex()) + values.Set("user", f.User.Hex()) +} diff --git a/swarm/api/testapi.go b/swarm/storage/feed/feed_test.go similarity index 58% rename from swarm/api/testapi.go rename to swarm/storage/feed/feed_test.go index 6631196c17..6a575594f4 100644 --- a/swarm/api/testapi.go +++ b/swarm/storage/feed/feed_test.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 @@ -13,34 +13,24 @@ // // 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 feed import ( - "github.com/ethereum/go-ethereum/swarm/network" + "testing" ) -type Control struct { - api *Api - hive *network.Hive +func getTestFeed() *Feed { + topic, _ := NewTopic("world news report, every hour", nil) + return &Feed{ + Topic: topic, + User: newCharlieSigner().Address(), + } } -func NewControl(api *Api, hive *network.Hive) *Control { - return &Control{api, hive} +func TestFeedSerializerDeserializer(t *testing.T) { + testBinarySerializerRecovery(t, getTestFeed(), "0x776f726c64206e657773207265706f72742c20657665727920686f7572000000876a8936a7cd0b79ef0735ad0896c1afe278781c") } -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 (self *Control) Hive() string { - return self.hive.String() +func TestFeedSerializerLengthCheck(t *testing.T) { + testBinarySerializerLengthCheck(t, getTestFeed()) } diff --git a/swarm/storage/feed/handler.go b/swarm/storage/feed/handler.go new file mode 100644 index 0000000000..063d3e92a3 --- /dev/null +++ b/swarm/storage/feed/handler.go @@ -0,0 +1,291 @@ +// 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 . + +// Handler is the API for feeds +// It enables creating, updating, syncing and retrieving feed updates and their data +package feed + +import ( + "bytes" + "context" + "fmt" + "sync" + + "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup" + + "github.com/ethereum/go-ethereum/swarm/log" + "github.com/ethereum/go-ethereum/swarm/storage" +) + +type Handler struct { + chunkStore *storage.NetStore + HashSize int + cache map[uint64]*cacheEntry + cacheLock sync.RWMutex +} + +// HandlerParams pass parameters to the Handler constructor NewHandler +// Signer and TimestampProvider are mandatory parameters +type HandlerParams struct { +} + +// hashPool contains a pool of ready hashers +var hashPool sync.Pool + +// init initializes the package and hashPool +func init() { + hashPool = sync.Pool{ + New: func() interface{} { + return storage.MakeHashFunc(feedsHashAlgorithm)() + }, + } +} + +// NewHandler creates a new Swarm feeds API +func NewHandler(params *HandlerParams) *Handler { + fh := &Handler{ + cache: make(map[uint64]*cacheEntry), + } + + for i := 0; i < hasherCount; i++ { + hashfunc := storage.MakeHashFunc(feedsHashAlgorithm)() + if fh.HashSize == 0 { + fh.HashSize = hashfunc.Size() + } + hashPool.Put(hashfunc) + } + + return fh +} + +// SetStore sets the store backend for the Swarm feeds API +func (h *Handler) SetStore(store *storage.NetStore) { + h.chunkStore = store +} + +// 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(chunk storage.Chunk) bool { + if len(chunk.Data()) < minimumSignedUpdateLength { + return false + } + + // check if it is a properly formatted update chunk with + // valid signature and proof of ownership of the feed it is trying + // to update + + // First, deserialize the chunk + var r Request + if err := r.fromChunk(chunk); err != nil { + log.Debug("Invalid feed update chunk", "addr", chunk.Address(), "err", err) + return false + } + + // Verify signatures and that the signer actually owns the feed + // If it fails, it means either the signature is not valid, data is corrupted + // or someone is trying to update someone else's feed. + if err := r.Verify(); err != nil { + log.Debug("Invalid feed update signature", "err", err) + return false + } + + return true +} + +// GetContent retrieves the data payload of the last synced update of the feed +func (h *Handler) GetContent(feed *Feed) (storage.Address, []byte, error) { + if feed == nil { + return nil, nil, NewError(ErrInvalidValue, "feed is nil") + } + feedUpdate := h.get(feed) + if feedUpdate == nil { + return nil, nil, NewError(ErrNotFound, "feed update not cached") + } + return feedUpdate.lastKey, feedUpdate.data, nil +} + +// NewRequest prepares a Request structure with all the necessary information to +// just add the desired data and sign it. +// The resulting structure can then be signed and passed to Handler.Update to be verified and sent +func (h *Handler) NewRequest(ctx context.Context, feed *Feed) (request *Request, err error) { + if feed == nil { + return nil, NewError(ErrInvalidValue, "feed cannot be nil") + } + + now := TimestampProvider.Now().Time + request = new(Request) + request.Header.Version = ProtocolVersion + + query := NewQueryLatest(feed, lookup.NoClue) + + feedUpdate, err := h.Lookup(ctx, query) + if err != nil { + if err.(*Error).code != ErrNotFound { + return nil, err + } + // not finding updates means that there is a network error + // or that the feed really does not have updates + } + + request.Feed = *feed + + // if we already have an update, then find next epoch + if feedUpdate != nil { + request.Epoch = lookup.GetNextEpoch(feedUpdate.Epoch, now) + } else { + request.Epoch = lookup.GetFirstEpoch(now) + } + + return request, nil +} + +// Lookup retrieves a specific or latest feed update +// Lookup works differently depending on the configuration of `query` +// See the `query` documentation and helper functions: +// `NewQueryLatest` and `NewQuery` +func (h *Handler) Lookup(ctx context.Context, query *Query) (*cacheEntry, error) { + + timeLimit := query.TimeLimit + if timeLimit == 0 { // if time limit is set to zero, the user wants to get the latest update + timeLimit = TimestampProvider.Now().Time + } + + if query.Hint == lookup.NoClue { // try to use our cache + entry := h.get(&query.Feed) + if entry != nil && entry.Epoch.Time <= timeLimit { // avoid bad hints + query.Hint = entry.Epoch + } + } + + // we can't look for anything without a store + if h.chunkStore == nil { + return nil, NewError(ErrInit, "Call Handler.SetStore() before performing lookups") + } + + var id ID + id.Feed = query.Feed + var readCount int + + // Invoke the lookup engine. + // The callback will be called every time the lookup algorithm needs to guess + requestPtr, err := lookup.Lookup(timeLimit, query.Hint, func(epoch lookup.Epoch, now uint64) (interface{}, error) { + readCount++ + id.Epoch = epoch + ctx, cancel := context.WithTimeout(ctx, defaultRetrieveTimeout) + defer cancel() + + chunk, err := h.chunkStore.Get(ctx, id.Addr()) + if err != nil { // TODO: check for catastrophic errors other than chunk not found + return nil, nil + } + + var request Request + if err := request.fromChunk(chunk); err != nil { + return nil, nil + } + if request.Time <= timeLimit { + return &request, nil + } + return nil, nil + }) + if err != nil { + return nil, err + } + + log.Info(fmt.Sprintf("Feed lookup finished in %d lookups", readCount)) + + request, _ := requestPtr.(*Request) + if request == nil { + return nil, NewError(ErrNotFound, "no feed updates found") + } + return h.updateCache(request) + +} + +// update feed updates cache with specified content +func (h *Handler) updateCache(request *Request) (*cacheEntry, error) { + + updateAddr := request.Addr() + log.Trace("feed cache update", "topic", request.Topic.Hex(), "updateaddr", updateAddr, "epoch time", request.Epoch.Time, "epoch level", request.Epoch.Level) + + feedUpdate := h.get(&request.Feed) + if feedUpdate == nil { + feedUpdate = &cacheEntry{} + h.set(&request.Feed, feedUpdate) + } + + // update our rsrcs entry map + feedUpdate.lastKey = updateAddr + feedUpdate.Update = request.Update + feedUpdate.Reader = bytes.NewReader(feedUpdate.data) + return feedUpdate, nil +} + +// Update publishes a feed update +// Note that a feed update cannot span chunks, and thus has a MAX NET LENGTH 4096, INCLUDING update header data and signature. +// This results in a max payload of `maxUpdateDataLength` (check update.go for more details) +// An error will be returned if the total length of the chunk payload will exceed this limit. +// Update can only check if the caller is trying to overwrite the very last known version, otherwise it just puts the update +// on the network. +func (h *Handler) Update(ctx context.Context, r *Request) (updateAddr storage.Address, err error) { + + // we can't update anything without a store + if h.chunkStore == nil { + return nil, NewError(ErrInit, "Call Handler.SetStore() before updating") + } + + feedUpdate := h.get(&r.Feed) + if feedUpdate != nil && feedUpdate.Epoch.Equals(r.Epoch) { // This is the only cheap check we can do for sure + return nil, NewError(ErrInvalidValue, "A former update in this epoch is already known to exist") + } + + chunk, err := r.toChunk() // Serialize the update into a chunk. Fails if data is too big + if err != nil { + return nil, err + } + + // send the chunk + h.chunkStore.Put(ctx, chunk) + log.Trace("feed update", "updateAddr", r.idAddr, "epoch time", r.Epoch.Time, "epoch level", r.Epoch.Level, "data", chunk.Data()) + // update our feed updates map cache entry if the new update is older than the one we have, if we have it. + if feedUpdate != nil && r.Epoch.After(feedUpdate.Epoch) { + feedUpdate.Epoch = r.Epoch + feedUpdate.data = make([]byte, len(r.data)) + feedUpdate.lastKey = r.idAddr + copy(feedUpdate.data, r.data) + feedUpdate.Reader = bytes.NewReader(feedUpdate.data) + } + + return r.idAddr, nil +} + +// Retrieves the feed update cache value for the given nameHash +func (h *Handler) get(feed *Feed) *cacheEntry { + mapKey := feed.mapKey() + h.cacheLock.RLock() + defer h.cacheLock.RUnlock() + feedUpdate := h.cache[mapKey] + return feedUpdate +} + +// Sets the feed update cache value for the given feed +func (h *Handler) set(feed *Feed, feedUpdate *cacheEntry) { + mapKey := feed.mapKey() + h.cacheLock.Lock() + defer h.cacheLock.Unlock() + h.cache[mapKey] = feedUpdate +} diff --git a/swarm/storage/feed/handler_test.go b/swarm/storage/feed/handler_test.go new file mode 100644 index 0000000000..2f8a524535 --- /dev/null +++ b/swarm/storage/feed/handler_test.go @@ -0,0 +1,506 @@ +// 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 feed + +import ( + "bytes" + "context" + "flag" + "fmt" + "io/ioutil" + "os" + "testing" + "time" + + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/swarm/chunk" + "github.com/ethereum/go-ethereum/swarm/storage" + "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup" +) + +var ( + loglevel = flag.Int("loglevel", 3, "loglevel") + startTime = Timestamp{ + Time: uint64(4200), + } + cleanF func() + subtopicName = "føø.bar" +) + +func init() { + flag.Parse() + log.Root().SetHandler(log.CallerFileHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(os.Stderr, log.TerminalFormat(true))))) +} + +// simulated timeProvider +type fakeTimeProvider struct { + currentTime uint64 +} + +func (f *fakeTimeProvider) Tick() { + f.currentTime++ +} + +func (f *fakeTimeProvider) Set(time uint64) { + f.currentTime = time +} + +func (f *fakeTimeProvider) FastForward(offset uint64) { + f.currentTime += offset +} + +func (f *fakeTimeProvider) Now() Timestamp { + return Timestamp{ + Time: f.currentTime, + } +} + +// make updates and retrieve them based on periods and versions +func TestFeedsHandler(t *testing.T) { + + // make fake timeProvider + clock := &fakeTimeProvider{ + currentTime: startTime.Time, // clock starts at t=4200 + } + + // signer containing private key + signer := newAliceSigner() + + feedsHandler, datadir, teardownTest, err := setupTest(clock, signer) + if err != nil { + t.Fatal(err) + } + defer teardownTest() + + // create a new feed + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + topic, _ := NewTopic("Mess with Swarm feeds code and see what ghost catches you", nil) + fd := Feed{ + Topic: topic, + User: signer.Address(), + } + + // data for updates: + updates := []string{ + "blinky", // t=4200 + "pinky", // t=4242 + "inky", // t=4284 + "clyde", // t=4285 + } + + request := NewFirstRequest(fd.Topic) // this timestamps the update at t = 4200 (start time) + chunkAddress := make(map[string]storage.Address) + data := []byte(updates[0]) + request.SetData(data) + if err := request.Sign(signer); err != nil { + t.Fatal(err) + } + chunkAddress[updates[0]], err = feedsHandler.Update(ctx, request) + if err != nil { + t.Fatal(err) + } + + // move the clock ahead 21 seconds + clock.FastForward(21) // t=4221 + + request, err = feedsHandler.NewRequest(ctx, &request.Feed) // this timestamps the update at t = 4221 + if err != nil { + t.Fatal(err) + } + if request.Epoch.Base() != 0 || request.Epoch.Level != lookup.HighestLevel-1 { + t.Fatalf("Suggested epoch BaseTime should be 0 and Epoch level should be %d", lookup.HighestLevel-1) + } + + request.Epoch.Level = lookup.HighestLevel // force level 25 instead of 24 to make it fail + data = []byte(updates[1]) + request.SetData(data) + if err := request.Sign(signer); err != nil { + t.Fatal(err) + } + chunkAddress[updates[1]], err = feedsHandler.Update(ctx, request) + if err == nil { + t.Fatal("Expected update to fail since an update in this epoch already exists") + } + + // move the clock ahead 21 seconds + clock.FastForward(21) // t=4242 + request, err = feedsHandler.NewRequest(ctx, &request.Feed) + if err != nil { + t.Fatal(err) + } + request.SetData(data) + if err := request.Sign(signer); err != nil { + t.Fatal(err) + } + chunkAddress[updates[1]], err = feedsHandler.Update(ctx, request) + if err != nil { + t.Fatal(err) + } + + // move the clock ahead 42 seconds + clock.FastForward(42) // t=4284 + request, err = feedsHandler.NewRequest(ctx, &request.Feed) + if err != nil { + t.Fatal(err) + } + data = []byte(updates[2]) + request.SetData(data) + if err := request.Sign(signer); err != nil { + t.Fatal(err) + } + chunkAddress[updates[2]], err = feedsHandler.Update(ctx, request) + if err != nil { + t.Fatal(err) + } + + // move the clock ahead 1 second + clock.FastForward(1) // t=4285 + request, err = feedsHandler.NewRequest(ctx, &request.Feed) + if err != nil { + t.Fatal(err) + } + if request.Epoch.Base() != 0 || request.Epoch.Level != 22 { + t.Fatalf("Expected epoch base time to be %d, got %d. Expected epoch level to be %d, got %d", 0, request.Epoch.Base(), 22, request.Epoch.Level) + } + data = []byte(updates[3]) + request.SetData(data) + + if err := request.Sign(signer); err != nil { + t.Fatal(err) + } + chunkAddress[updates[3]], err = feedsHandler.Update(ctx, request) + if err != nil { + t.Fatal(err) + } + + time.Sleep(time.Second) + feedsHandler.Close() + + // check we can retrieve the updates after close + clock.FastForward(2000) // t=6285 + + feedParams := &HandlerParams{} + + feedsHandler2, err := NewTestHandler(datadir, feedParams) + if err != nil { + t.Fatal(err) + } + + update2, err := feedsHandler2.Lookup(ctx, NewQueryLatest(&request.Feed, lookup.NoClue)) + if err != nil { + t.Fatal(err) + } + + // last update should be "clyde" + if !bytes.Equal(update2.data, []byte(updates[len(updates)-1])) { + t.Fatalf("feed update data was %v, expected %v", string(update2.data), updates[len(updates)-1]) + } + if update2.Level != 22 { + t.Fatalf("feed update epoch level was %d, expected 22", update2.Level) + } + if update2.Base() != 0 { + t.Fatalf("feed update epoch base time was %d, expected 0", update2.Base()) + } + log.Debug("Latest lookup", "epoch base time", update2.Base(), "epoch level", update2.Level, "data", update2.data) + + // specific point in time + update, err := feedsHandler2.Lookup(ctx, NewQuery(&request.Feed, 4284, lookup.NoClue)) + if err != nil { + t.Fatal(err) + } + // check data + if !bytes.Equal(update.data, []byte(updates[2])) { + t.Fatalf("feed update data (historical) was %v, expected %v", string(update2.data), updates[2]) + } + log.Debug("Historical lookup", "epoch base time", update2.Base(), "epoch level", update2.Level, "data", update2.data) + + // beyond the first should yield an error + update, err = feedsHandler2.Lookup(ctx, NewQuery(&request.Feed, startTime.Time-1, lookup.NoClue)) + if err == nil { + t.Fatalf("expected previous to fail, returned epoch %s data %v", update.Epoch.String(), update.data) + } + +} + +const Day = 60 * 60 * 24 +const Year = Day * 365 +const Month = Day * 30 + +func generateData(x uint64) []byte { + return []byte(fmt.Sprintf("%d", x)) +} + +func TestSparseUpdates(t *testing.T) { + + // make fake timeProvider + timeProvider := &fakeTimeProvider{ + currentTime: startTime.Time, + } + + // signer containing private key + signer := newAliceSigner() + + rh, datadir, teardownTest, err := setupTest(timeProvider, signer) + if err != nil { + t.Fatal(err) + } + defer teardownTest() + defer os.RemoveAll(datadir) + + // create a new feed + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + topic, _ := NewTopic("Very slow updates", nil) + fd := Feed{ + Topic: topic, + User: signer.Address(), + } + + // publish one update every 5 years since Unix 0 until today + today := uint64(1533799046) + var epoch lookup.Epoch + var lastUpdateTime uint64 + for T := uint64(0); T < today; T += 5 * Year { + request := NewFirstRequest(fd.Topic) + request.Epoch = lookup.GetNextEpoch(epoch, T) + request.data = generateData(T) // this generates some data that depends on T, so we can check later + request.Sign(signer) + if err != nil { + t.Fatal(err) + } + + if _, err := rh.Update(ctx, request); err != nil { + t.Fatal(err) + } + epoch = request.Epoch + lastUpdateTime = T + } + + query := NewQuery(&fd, today, lookup.NoClue) + + _, err = rh.Lookup(ctx, query) + if err != nil { + t.Fatal(err) + } + + _, content, err := rh.GetContent(&fd) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(generateData(lastUpdateTime), content) { + t.Fatalf("Expected to recover last written value %d, got %s", lastUpdateTime, string(content)) + } + + // lookup the closest update to 35*Year + 6* Month (~ June 2005): + // it should find the update we put on 35*Year, since we were updating every 5 years. + + query.TimeLimit = 35*Year + 6*Month + + _, err = rh.Lookup(ctx, query) + if err != nil { + t.Fatal(err) + } + + _, content, err = rh.GetContent(&fd) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(generateData(35*Year), content) { + t.Fatalf("Expected to recover %d, got %s", 35*Year, string(content)) + } +} + +func TestValidator(t *testing.T) { + + // make fake timeProvider + timeProvider := &fakeTimeProvider{ + currentTime: startTime.Time, + } + + // signer containing private key. Alice will be the good girl + signer := newAliceSigner() + + // set up sim timeProvider + rh, _, teardownTest, err := setupTest(timeProvider, signer) + if err != nil { + t.Fatal(err) + } + defer teardownTest() + + // create new feed + topic, _ := NewTopic(subtopicName, nil) + fd := Feed{ + Topic: topic, + User: signer.Address(), + } + mr := NewFirstRequest(fd.Topic) + + // chunk with address + data := []byte("foo") + mr.SetData(data) + if err := mr.Sign(signer); err != nil { + t.Fatalf("sign fail: %v", err) + } + + chunk, err := mr.toChunk() + if err != nil { + t.Fatal(err) + } + if !rh.Validate(chunk) { + t.Fatal("Chunk validator fail on update chunk") + } + + address := chunk.Address() + // mess with the address + address[0] = 11 + address[15] = 99 + + if rh.Validate(storage.NewChunk(address, chunk.Data())) { + t.Fatal("Expected Validate to fail with false chunk address") + } +} + +// tests that the content address validator correctly checks the data +// tests that feed update chunks are passed through content address validator +// there is some redundancy in this test as it also tests content addressed chunks, +// which should be evaluated as invalid chunks by this validator +func TestValidatorInStore(t *testing.T) { + + // make fake timeProvider + TimestampProvider = &fakeTimeProvider{ + currentTime: startTime.Time, + } + + // signer containing private key + signer := newAliceSigner() + + // set up localstore + datadir, err := ioutil.TempDir("", "storage-testfeedsvalidator") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(datadir) + + handlerParams := storage.NewDefaultLocalStoreParams() + handlerParams.Init(datadir) + store, err := storage.NewLocalStore(handlerParams, nil) + if err != nil { + t.Fatal(err) + } + + // set up Swarm feeds handler and add is as a validator to the localstore + fhParams := &HandlerParams{} + fh := NewHandler(fhParams) + store.Validators = append(store.Validators, fh) + + // create content addressed chunks, one good, one faulty + chunks := storage.GenerateRandomChunks(chunk.DefaultSize, 2) + goodChunk := chunks[0] + badChunk := storage.NewChunk(chunks[1].Address(), goodChunk.Data()) + + topic, _ := NewTopic("xyzzy", nil) + fd := Feed{ + Topic: topic, + User: signer.Address(), + } + + // create a feed update chunk with correct publickey + id := ID{ + Epoch: lookup.Epoch{Time: 42, + Level: 1, + }, + Feed: fd, + } + + updateAddr := id.Addr() + data := []byte("bar") + + r := new(Request) + r.idAddr = updateAddr + r.Update.ID = id + r.data = data + + r.Sign(signer) + + uglyChunk, err := r.toChunk() + if err != nil { + t.Fatal(err) + } + + // put the chunks in the store and check their error status + err = store.Put(context.Background(), goodChunk) + if err == nil { + t.Fatal("expected error on good content address chunk with feed update validator only, but got nil") + } + err = store.Put(context.Background(), badChunk) + if err == nil { + t.Fatal("expected error on bad content address chunk with feed update validator only, but got nil") + } + err = store.Put(context.Background(), uglyChunk) + if err != nil { + t.Fatalf("expected no error on feed update chunk with feed update validator only, but got: %s", err) + } +} + +// create rpc and feeds Handler +func setupTest(timeProvider timestampProvider, signer Signer) (fh *TestHandler, datadir string, teardown func(), err error) { + + var fsClean func() + var rpcClean func() + cleanF = func() { + if fsClean != nil { + fsClean() + } + if rpcClean != nil { + rpcClean() + } + } + + // temp datadir + datadir, err = ioutil.TempDir("", "fh") + if err != nil { + return nil, "", nil, err + } + fsClean = func() { + os.RemoveAll(datadir) + } + + TimestampProvider = timeProvider + fhParams := &HandlerParams{} + fh, err = NewTestHandler(datadir, fhParams) + return fh, datadir, cleanF, err +} + +func newAliceSigner() *GenericSigner { + privKey, _ := crypto.HexToECDSA("deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef") + return NewGenericSigner(privKey) +} + +func newBobSigner() *GenericSigner { + privKey, _ := crypto.HexToECDSA("accedeaccedeaccedeaccedeaccedeaccedeaccedeaccedeaccedeaccedecaca") + return NewGenericSigner(privKey) +} + +func newCharlieSigner() *GenericSigner { + privKey, _ := crypto.HexToECDSA("facadefacadefacadefacadefacadefacadefacadefacadefacadefacadefaca") + return NewGenericSigner(privKey) +} diff --git a/swarm/storage/feed/id.go b/swarm/storage/feed/id.go new file mode 100644 index 0000000000..7e17743c11 --- /dev/null +++ b/swarm/storage/feed/id.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 feed + +import ( + "fmt" + "hash" + "strconv" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup" + + "github.com/ethereum/go-ethereum/swarm/storage" +) + +// ID uniquely identifies an update on the network. +type ID struct { + Feed `json:"feed"` + lookup.Epoch `json:"epoch"` +} + +// ID layout: +// Feed feedLength bytes +// Epoch EpochLength +const idLength = feedLength + lookup.EpochLength + +// Addr calculates the feed update chunk address corresponding to this ID +func (u *ID) Addr() (updateAddr storage.Address) { + serializedData := make([]byte, idLength) + var cursor int + u.Feed.binaryPut(serializedData[cursor : cursor+feedLength]) + cursor += feedLength + + eid := u.Epoch.ID() + copy(serializedData[cursor:cursor+lookup.EpochLength], eid[:]) + + hasher := hashPool.Get().(hash.Hash) + defer hashPool.Put(hasher) + hasher.Reset() + hasher.Write(serializedData) + return hasher.Sum(nil) +} + +// binaryPut serializes this instance into the provided slice +func (u *ID) binaryPut(serializedData []byte) error { + if len(serializedData) != idLength { + return NewErrorf(ErrInvalidValue, "Incorrect slice size to serialize ID. Expected %d, got %d", idLength, len(serializedData)) + } + var cursor int + if err := u.Feed.binaryPut(serializedData[cursor : cursor+feedLength]); err != nil { + return err + } + cursor += feedLength + + epochBytes, err := u.Epoch.MarshalBinary() + if err != nil { + return err + } + copy(serializedData[cursor:cursor+lookup.EpochLength], epochBytes[:]) + cursor += lookup.EpochLength + + return nil +} + +// binaryLength returns the expected size of this structure when serialized +func (u *ID) binaryLength() int { + return idLength +} + +// binaryGet restores the current instance from the information contained in the passed slice +func (u *ID) binaryGet(serializedData []byte) error { + if len(serializedData) != idLength { + return NewErrorf(ErrInvalidValue, "Incorrect slice size to read ID. Expected %d, got %d", idLength, len(serializedData)) + } + + var cursor int + if err := u.Feed.binaryGet(serializedData[cursor : cursor+feedLength]); err != nil { + return err + } + cursor += feedLength + + if err := u.Epoch.UnmarshalBinary(serializedData[cursor : cursor+lookup.EpochLength]); err != nil { + return err + } + cursor += lookup.EpochLength + + return nil +} + +// FromValues deserializes this instance from a string key-value store +// useful to parse query strings +func (u *ID) FromValues(values Values) error { + level, _ := strconv.ParseUint(values.Get("level"), 10, 32) + u.Epoch.Level = uint8(level) + u.Epoch.Time, _ = strconv.ParseUint(values.Get("time"), 10, 64) + + if u.Feed.User == (common.Address{}) { + return u.Feed.FromValues(values) + } + return nil +} + +// AppendValues serializes this structure into the provided string key-value store +// useful to build query strings +func (u *ID) AppendValues(values Values) { + values.Set("level", fmt.Sprintf("%d", u.Epoch.Level)) + values.Set("time", fmt.Sprintf("%d", u.Epoch.Time)) + u.Feed.AppendValues(values) +} diff --git a/swarm/storage/feed/id_test.go b/swarm/storage/feed/id_test.go new file mode 100644 index 0000000000..e561ff9b46 --- /dev/null +++ b/swarm/storage/feed/id_test.go @@ -0,0 +1,28 @@ +package feed + +import ( + "testing" + + "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup" +) + +func getTestID() *ID { + return &ID{ + Feed: *getTestFeed(), + Epoch: lookup.GetFirstEpoch(1000), + } +} + +func TestIDAddr(t *testing.T) { + id := getTestID() + updateAddr := id.Addr() + compareByteSliceToExpectedHex(t, "updateAddr", updateAddr, "0x8b24583ec293e085f4c78aaee66d1bc5abfb8b4233304d14a349afa57af2a783") +} + +func TestIDSerializer(t *testing.T) { + testBinarySerializerRecovery(t, getTestID(), "0x776f726c64206e657773207265706f72742c20657665727920686f7572000000876a8936a7cd0b79ef0735ad0896c1afe278781ce803000000000019") +} + +func TestIDLengthCheck(t *testing.T) { + testBinarySerializerLengthCheck(t, getTestID()) +} diff --git a/swarm/storage/feed/lookup/epoch.go b/swarm/storage/feed/lookup/epoch.go new file mode 100644 index 0000000000..bafe954779 --- /dev/null +++ b/swarm/storage/feed/lookup/epoch.go @@ -0,0 +1,91 @@ +// 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 lookup + +import ( + "encoding/binary" + "errors" + "fmt" +) + +// Epoch represents a time slot at a particular frequency level +type Epoch struct { + Time uint64 `json:"time"` // Time stores the time at which the update or lookup takes place + Level uint8 `json:"level"` // Level indicates the frequency level as the exponent of a power of 2 +} + +// EpochID is a unique identifier for an Epoch, based on its level and base time. +type EpochID [8]byte + +// EpochLength stores the serialized binary length of an Epoch +const EpochLength = 8 + +// MaxTime contains the highest possible time value an Epoch can handle +const MaxTime uint64 = (1 << 56) - 1 + +// Base returns the base time of the Epoch +func (e *Epoch) Base() uint64 { + return getBaseTime(e.Time, e.Level) +} + +// ID Returns the unique identifier of this epoch +func (e *Epoch) ID() EpochID { + base := e.Base() + var id EpochID + binary.LittleEndian.PutUint64(id[:], base) + id[7] = e.Level + return id +} + +// MarshalBinary implements the encoding.BinaryMarshaller interface +func (e *Epoch) MarshalBinary() (data []byte, err error) { + b := make([]byte, 8) + binary.LittleEndian.PutUint64(b[:], e.Time) + b[7] = e.Level + return b, nil +} + +// UnmarshalBinary implements the encoding.BinaryUnmarshaller interface +func (e *Epoch) UnmarshalBinary(data []byte) error { + if len(data) != EpochLength { + return errors.New("Invalid data unmarshalling Epoch") + } + b := make([]byte, 8) + copy(b, data) + e.Level = b[7] + b[7] = 0 + e.Time = binary.LittleEndian.Uint64(b) + return nil +} + +// After returns true if this epoch occurs later or exactly at the other epoch. +func (e *Epoch) After(epoch Epoch) bool { + if e.Time == epoch.Time { + return e.Level < epoch.Level + } + return e.Time >= epoch.Time +} + +// Equals compares two epochs and returns true if they refer to the same time period. +func (e *Epoch) Equals(epoch Epoch) bool { + return e.Level == epoch.Level && e.Base() == epoch.Base() +} + +// String implements the Stringer interface. +func (e *Epoch) String() string { + return fmt.Sprintf("Epoch{Time:%d, Level:%d}", e.Time, e.Level) +} diff --git a/swarm/storage/feed/lookup/epoch_test.go b/swarm/storage/feed/lookup/epoch_test.go new file mode 100644 index 0000000000..0629f3d1df --- /dev/null +++ b/swarm/storage/feed/lookup/epoch_test.go @@ -0,0 +1,57 @@ +package lookup_test + +import ( + "testing" + + "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup" +) + +func TestMarshallers(t *testing.T) { + + for i := uint64(1); i < lookup.MaxTime; i *= 3 { + e := lookup.Epoch{ + Time: i, + Level: uint8(i % 20), + } + b, err := e.MarshalBinary() + if err != nil { + t.Fatal(err) + } + var e2 lookup.Epoch + if err := e2.UnmarshalBinary(b); err != nil { + t.Fatal(err) + } + if e != e2 { + t.Fatal("Expected unmarshalled epoch to be equal to marshalled onet.Fatal(err)") + } + } + +} + +func TestAfter(t *testing.T) { + a := lookup.Epoch{ + Time: 5, + Level: 3, + } + b := lookup.Epoch{ + Time: 6, + Level: 3, + } + c := lookup.Epoch{ + Time: 6, + Level: 4, + } + + if !b.After(a) { + t.Fatal("Expected 'after' to be true, got false") + } + + if b.After(b) { + t.Fatal("Expected 'after' to be false when both epochs are identical, got true") + } + + if !b.After(c) { + t.Fatal("Expected 'after' to be true when both epochs have the same time but the level is lower in the first one, but got false") + } + +} diff --git a/swarm/storage/feed/lookup/lookup.go b/swarm/storage/feed/lookup/lookup.go new file mode 100644 index 0000000000..2f862d81c4 --- /dev/null +++ b/swarm/storage/feed/lookup/lookup.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 lookup defines feed lookup algorithms and provides tools to place updates +so they can be found +*/ +package lookup + +const maxuint64 = ^uint64(0) + +// LowestLevel establishes the frequency resolution of the lookup algorithm as a power of 2. +const LowestLevel uint8 = 0 // default is 0 (1 second) + +// HighestLevel sets the lowest frequency the algorithm will operate at, as a power of 2. +// 25 -> 2^25 equals to roughly one year. +const HighestLevel = 25 // default is 25 (~1 year) + +// DefaultLevel sets what level will be chosen to search when there is no hint +const DefaultLevel = HighestLevel + +//Algorithm is the function signature of a lookup algorithm +type Algorithm func(now uint64, hint Epoch, read ReadFunc) (value interface{}, err error) + +// Lookup finds the update with the highest timestamp that is smaller or equal than 'now' +// It takes a hint which should be the epoch where the last known update was +// If you don't know in what epoch the last update happened, simply submit lookup.NoClue +// read() will be called on each lookup attempt +// Returns an error only if read() returns an error +// Returns nil if an update was not found +var Lookup Algorithm = FluzCapacitorAlgorithm + +// ReadFunc is a handler called by Lookup each time it attempts to find a value +// It should return if a value is not found +// It should return if a value is found, but its timestamp is higher than "now" +// It should only return an error in case the handler wants to stop the +// lookup process entirely. +type ReadFunc func(epoch Epoch, now uint64) (interface{}, error) + +// NoClue is a hint that can be provided when the Lookup caller does not have +// a clue about where the last update may be +var NoClue = Epoch{} + +// getBaseTime returns the epoch base time of the given +// time and level +func getBaseTime(t uint64, level uint8) uint64 { + return t & (maxuint64 << level) +} + +// Hint creates a hint based only on the last known update time +func Hint(last uint64) Epoch { + return Epoch{ + Time: last, + Level: DefaultLevel, + } +} + +// GetNextLevel returns the frequency level a next update should be placed at, provided where +// the last update was and what time it is now. +// This is the first nonzero bit of the XOR of 'last' and 'now', counting from the highest significant bit +// but limited to not return a level that is smaller than the last-1 +func GetNextLevel(last Epoch, now uint64) uint8 { + // First XOR the last epoch base time with the current clock. + // This will set all the common most significant bits to zero. + mix := (last.Base() ^ now) + + // Then, make sure we stop the below loop before one level below the current, by setting + // that level's bit to 1. + // If the next level is lower than the current one, it must be exactly level-1 and not lower. + mix |= (1 << (last.Level - 1)) + + // if the last update was more than 2^highestLevel seconds ago, choose the highest level + if mix > (maxuint64 >> (64 - HighestLevel - 1)) { + return HighestLevel + } + + // set up a mask to scan for nonzero bits, starting at the highest level + mask := uint64(1 << (HighestLevel)) + + for i := uint8(HighestLevel); i > LowestLevel; i-- { + if mix&mask != 0 { // if we find a nonzero bit, this is the level the next update should be at. + return i + } + mask = mask >> 1 // move our bit one position to the right + } + return 0 +} + +// GetNextEpoch returns the epoch where the next update should be located +// according to where the previous update was +// and what time it is now. +func GetNextEpoch(last Epoch, now uint64) Epoch { + if last == NoClue { + return GetFirstEpoch(now) + } + level := GetNextLevel(last, now) + return Epoch{ + Level: level, + Time: now, + } +} + +// GetFirstEpoch returns the epoch where the first update should be located +// based on what time it is now. +func GetFirstEpoch(now uint64) Epoch { + return Epoch{Level: HighestLevel, Time: now} +} + +var worstHint = Epoch{Time: 0, Level: 63} + +// FluzCapacitorAlgorithm works by narrowing the epoch search area if an update is found +// going back and forth in time +// First, it will attempt to find an update where it should be now if the hint was +// really the last update. If that lookup fails, then the last update must be either the hint itself +// or the epochs right below. If however, that lookup succeeds, then the update must be +// that one or within the epochs right below. +// see the guide for a more graphical representation +func FluzCapacitorAlgorithm(now uint64, hint Epoch, read ReadFunc) (value interface{}, err error) { + var lastFound interface{} + var epoch Epoch + if hint == NoClue { + hint = worstHint + } + + t := now + + for { + epoch = GetNextEpoch(hint, t) + value, err = read(epoch, now) + if err != nil { + return nil, err + } + if value != nil { + lastFound = value + if epoch.Level == LowestLevel || epoch.Equals(hint) { + return value, nil + } + hint = epoch + continue + } + if epoch.Base() == hint.Base() { + if lastFound != nil { + return lastFound, nil + } + // we have reached the hint itself + if hint == worstHint { + return nil, nil + } + // check it out + value, err = read(hint, now) + if err != nil { + return nil, err + } + if value != nil { + return value, nil + } + // bad hint. + epoch = hint + hint = worstHint + } + base := epoch.Base() + if base == 0 { + return nil, nil + } + t = base - 1 + } +} diff --git a/swarm/storage/feed/lookup/lookup_test.go b/swarm/storage/feed/lookup/lookup_test.go new file mode 100644 index 0000000000..4652feacfc --- /dev/null +++ b/swarm/storage/feed/lookup/lookup_test.go @@ -0,0 +1,414 @@ +// 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 lookup_test + +import ( + "fmt" + "math/rand" + "testing" + + "github.com/ethereum/go-ethereum/swarm/log" + "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup" +) + +type Data struct { + Payload uint64 + Time uint64 +} + +type Store map[lookup.EpochID]*Data + +func write(store Store, epoch lookup.Epoch, value *Data) { + log.Debug("Write: %d-%d, value='%d'\n", epoch.Base(), epoch.Level, value.Payload) + store[epoch.ID()] = value +} + +func update(store Store, last lookup.Epoch, now uint64, value *Data) lookup.Epoch { + epoch := lookup.GetNextEpoch(last, now) + + write(store, epoch, value) + + return epoch +} + +const Day = 60 * 60 * 24 +const Year = Day * 365 +const Month = Day * 30 + +func makeReadFunc(store Store, counter *int) lookup.ReadFunc { + return func(epoch lookup.Epoch, now uint64) (interface{}, error) { + *counter++ + data := store[epoch.ID()] + var valueStr string + if data != nil { + valueStr = fmt.Sprintf("%d", data.Payload) + } + log.Debug("Read: %d-%d, value='%s'\n", epoch.Base(), epoch.Level, valueStr) + if data != nil && data.Time <= now { + return data, nil + } + return nil, nil + } +} + +func TestLookup(t *testing.T) { + + store := make(Store) + readCount := 0 + readFunc := makeReadFunc(store, &readCount) + + // write an update every month for 12 months 3 years ago and then silence for two years + now := uint64(1533799046) + var epoch lookup.Epoch + + var lastData *Data + for i := uint64(0); i < 12; i++ { + t := uint64(now - Year*3 + i*Month) + data := Data{ + Payload: t, //our "payload" will be the timestamp itself. + Time: t, + } + epoch = update(store, epoch, t, &data) + lastData = &data + } + + // try to get the last value + + value, err := lookup.Lookup(now, lookup.NoClue, readFunc) + if err != nil { + t.Fatal(err) + } + + readCountWithoutHint := readCount + + if value != lastData { + t.Fatalf("Expected lookup to return the last written value: %v. Got %v", lastData, value) + } + + // reset the read count for the next test + readCount = 0 + // Provide a hint to get a faster lookup. In particular, we give the exact location of the last update + value, err = lookup.Lookup(now, epoch, readFunc) + if err != nil { + t.Fatal(err) + } + + if value != lastData { + t.Fatalf("Expected lookup to return the last written value: %v. Got %v", lastData, value) + } + + if readCount > readCountWithoutHint { + t.Fatalf("Expected lookup to complete with fewer or same reads than %d since we provided a hint. Did %d reads.", readCountWithoutHint, readCount) + } + + // try to get an intermediate value + // if we look for a value in now - Year*3 + 6*Month, we should get that value + // Since the "payload" is the timestamp itself, we can check this. + + expectedTime := now - Year*3 + 6*Month + + value, err = lookup.Lookup(expectedTime, lookup.NoClue, readFunc) + if err != nil { + t.Fatal(err) + } + + data, ok := value.(*Data) + + if !ok { + t.Fatal("Expected value to contain data") + } + + if data.Time != expectedTime { + t.Fatalf("Expected value timestamp to be %d, got %d", data.Time, expectedTime) + } + +} + +func TestOneUpdateAt0(t *testing.T) { + + store := make(Store) + readCount := 0 + + readFunc := makeReadFunc(store, &readCount) + now := uint64(1533903729) + + var epoch lookup.Epoch + data := Data{ + Payload: 79, + Time: 0, + } + update(store, epoch, 0, &data) + + value, err := lookup.Lookup(now, lookup.NoClue, readFunc) + if err != nil { + t.Fatal(err) + } + if value != &data { + t.Fatalf("Expected lookup to return the last written value: %v. Got %v", data, value) + } +} + +// Tests the update is found even when a bad hint is given +func TestBadHint(t *testing.T) { + + store := make(Store) + readCount := 0 + + readFunc := makeReadFunc(store, &readCount) + now := uint64(1533903729) + + var epoch lookup.Epoch + data := Data{ + Payload: 79, + Time: 0, + } + + // place an update for t=1200 + update(store, epoch, 1200, &data) + + // come up with some evil hint + badHint := lookup.Epoch{ + Level: 18, + Time: 1200000000, + } + + value, err := lookup.Lookup(now, badHint, readFunc) + if err != nil { + t.Fatal(err) + } + if value != &data { + t.Fatalf("Expected lookup to return the last written value: %v. Got %v", data, value) + } +} + +func TestLookupFail(t *testing.T) { + + store := make(Store) + readCount := 0 + + readFunc := makeReadFunc(store, &readCount) + now := uint64(1533903729) + + // don't write anything and try to look up. + // we're testing we don't get stuck in a loop + + value, err := lookup.Lookup(now, lookup.NoClue, readFunc) + if err != nil { + t.Fatal(err) + } + if value != nil { + t.Fatal("Expected value to be nil, since the update should've failed") + } + + expectedReads := now/(1< readCountWithoutHint { + t.Fatalf("Expected lookup to complete with fewer or equal reads than %d since we provided a hint. Did %d reads.", readCountWithoutHint, readCount) + } + + for i := uint64(0); i <= 994; i++ { + T := uint64(now - 1000 + i) // update every second for the last 1000 seconds + value, err := lookup.Lookup(T, lookup.NoClue, readFunc) + if err != nil { + t.Fatal(err) + } + data, _ := value.(*Data) + if data == nil { + t.Fatalf("Expected lookup to return %d, got nil", T) + } + if data.Payload != T { + t.Fatalf("Expected lookup to return %d, got %d", T, data.Time) + } + } +} + +func TestSparseUpdates(t *testing.T) { + + store := make(Store) + readCount := 0 + readFunc := makeReadFunc(store, &readCount) + + // write an update every 5 years 3 times starting in Jan 1st 1970 and then silence + + now := uint64(1533799046) + var epoch lookup.Epoch + + var lastData *Data + for i := uint64(0); i < 5; i++ { + T := uint64(Year * 5 * i) // write an update every 5 years 3 times starting in Jan 1st 1970 and then silence + data := Data{ + Payload: T, //our "payload" will be the timestamp itself. + Time: T, + } + epoch = update(store, epoch, T, &data) + lastData = &data + } + + // try to get the last value + + value, err := lookup.Lookup(now, lookup.NoClue, readFunc) + if err != nil { + t.Fatal(err) + } + + readCountWithoutHint := readCount + + if value != lastData { + t.Fatalf("Expected lookup to return the last written value: %v. Got %v", lastData, value) + } + + // reset the read count for the next test + readCount = 0 + // Provide a hint to get a faster lookup. In particular, we give the exact location of the last update + value, err = lookup.Lookup(now, epoch, readFunc) + if err != nil { + t.Fatal(err) + } + + if value != lastData { + t.Fatalf("Expected lookup to return the last written value: %v. Got %v", lastData, value) + } + + if readCount > readCountWithoutHint { + t.Fatalf("Expected lookup to complete with fewer reads than %d since we provided a hint. Did %d reads.", readCountWithoutHint, readCount) + } + +} + +// testG will hold precooked test results +// fields are abbreviated to reduce the size of the literal below +type testG struct { + e lookup.Epoch // last + n uint64 // next level + x uint8 // expected result +} + +// test cases +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) { + + // First, test well-known cases + last := lookup.Epoch{ + Time: 1533799046, + Level: 5, + } + + level := lookup.GetNextLevel(last, last.Time) + expected := uint8(4) + if level != expected { + t.Fatalf("Expected GetNextLevel to return %d for same-time updates at a nonzero level, got %d", expected, level) + } + + level = lookup.GetNextLevel(last, last.Time+(1< lookup.HighestLevel { + v = 0 + } + now = last.Time + uint64(rand.Intn(1<. + +package feed + +import ( + "fmt" + "strconv" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup" +) + +// Query is used to specify constraints when performing an update lookup +// TimeLimit indicates an upper bound for the search. Set to 0 for "now" +type Query struct { + Feed + Hint lookup.Epoch + TimeLimit uint64 +} + +// FromValues deserializes this instance from a string key-value store +// useful to parse query strings +func (q *Query) FromValues(values Values) error { + time, _ := strconv.ParseUint(values.Get("time"), 10, 64) + q.TimeLimit = time + + level, _ := strconv.ParseUint(values.Get("hint.level"), 10, 32) + q.Hint.Level = uint8(level) + q.Hint.Time, _ = strconv.ParseUint(values.Get("hint.time"), 10, 64) + if q.Feed.User == (common.Address{}) { + return q.Feed.FromValues(values) + } + return nil +} + +// AppendValues serializes this structure into the provided string key-value store +// useful to build query strings +func (q *Query) AppendValues(values Values) { + if q.TimeLimit != 0 { + values.Set("time", fmt.Sprintf("%d", q.TimeLimit)) + } + if q.Hint.Level != 0 { + values.Set("hint.level", fmt.Sprintf("%d", q.Hint.Level)) + } + if q.Hint.Time != 0 { + values.Set("hint.time", fmt.Sprintf("%d", q.Hint.Time)) + } + q.Feed.AppendValues(values) +} + +// NewQuery constructs an Query structure to find updates on or before `time` +// if time == 0, the latest update will be looked up +func NewQuery(feed *Feed, time uint64, hint lookup.Epoch) *Query { + return &Query{ + TimeLimit: time, + Feed: *feed, + Hint: hint, + } +} + +// NewQueryLatest generates lookup parameters that look for the latest update to a feed +func NewQueryLatest(feed *Feed, hint lookup.Epoch) *Query { + return NewQuery(feed, 0, hint) +} diff --git a/swarm/storage/feed/query_test.go b/swarm/storage/feed/query_test.go new file mode 100644 index 0000000000..9fa5e29800 --- /dev/null +++ b/swarm/storage/feed/query_test.go @@ -0,0 +1,38 @@ +// 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 feed + +import ( + "testing" +) + +func getTestQuery() *Query { + id := getTestID() + return &Query{ + TimeLimit: 5000, + Feed: id.Feed, + Hint: id.Epoch, + } +} + +func TestQueryValues(t *testing.T) { + var expected = KV{"hint.level": "25", "hint.time": "1000", "time": "5000", "topic": "0x776f726c64206e657773207265706f72742c20657665727920686f7572000000", "user": "0x876A8936A7Cd0b79Ef0735AD0896c1AFe278781c"} + + query := getTestQuery() + testValueSerializer(t, query, expected) + +} diff --git a/swarm/storage/feed/request.go b/swarm/storage/feed/request.go new file mode 100644 index 0000000000..dd91a7cf45 --- /dev/null +++ b/swarm/storage/feed/request.go @@ -0,0 +1,286 @@ +// 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 feed + +import ( + "bytes" + "encoding/json" + "hash" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/swarm/storage" + "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup" +) + +// Request represents a request to sign or signed feed update message +type Request struct { + Update // actual content that will be put on the chunk, less signature + Signature *Signature + idAddr storage.Address // cached chunk address for the update (not serialized, for internal use) + binaryData []byte // cached serialized data (does not get serialized again!, for efficiency/internal use) +} + +// updateRequestJSON represents a JSON-serialized UpdateRequest +type updateRequestJSON struct { + ID + ProtocolVersion uint8 `json:"protocolVersion"` + Data string `json:"data,omitempty"` + Signature string `json:"signature,omitempty"` +} + +// Request layout +// Update bytes +// SignatureLength bytes +const minimumSignedUpdateLength = minimumUpdateDataLength + signatureLength + +// NewFirstRequest returns a ready to sign request to publish a first feed update +func NewFirstRequest(topic Topic) *Request { + + request := new(Request) + + // get the current time + now := TimestampProvider.Now().Time + request.Epoch = lookup.GetFirstEpoch(now) + request.Feed.Topic = topic + request.Header.Version = ProtocolVersion + + return request +} + +// SetData stores the payload data the feed update will be updated with +func (r *Request) SetData(data []byte) { + r.data = data + r.Signature = nil +} + +// IsUpdate returns true if this request models a signed update or otherwise it is a signature request +func (r *Request) IsUpdate() bool { + return r.Signature != nil +} + +// Verify checks that signatures are valid +func (r *Request) Verify() (err error) { + if len(r.data) == 0 { + return NewError(ErrInvalidValue, "Update does not contain data") + } + if r.Signature == nil { + return NewError(ErrInvalidSignature, "Missing signature field") + } + + digest, err := r.GetDigest() + if err != nil { + return err + } + + // get the address of the signer (which also checks that it's a valid signature) + r.Feed.User, err = getUserAddr(digest, *r.Signature) + if err != nil { + return err + } + + // check that the lookup information contained in the chunk matches the updateAddr (chunk search key) + // that was used to retrieve this chunk + // if this validation fails, someone forged a chunk. + if !bytes.Equal(r.idAddr, r.Addr()) { + return NewError(ErrInvalidSignature, "Signature address does not match with update user address") + } + + return nil +} + +// Sign executes the signature to validate the update message +func (r *Request) Sign(signer Signer) error { + r.Feed.User = signer.Address() + r.binaryData = nil //invalidate serialized data + digest, err := r.GetDigest() // computes digest and serializes into .binaryData + if err != nil { + return err + } + + signature, err := signer.Sign(digest) + if err != nil { + return err + } + + // Although the Signer interface returns the public address of the signer, + // recover it from the signature to see if they match + userAddr, err := getUserAddr(digest, signature) + if err != nil { + return NewError(ErrInvalidSignature, "Error verifying signature") + } + + if userAddr != signer.Address() { // sanity check to make sure the Signer is declaring the same address used to sign! + return NewError(ErrInvalidSignature, "Signer address does not match update user address") + } + + r.Signature = &signature + r.idAddr = r.Addr() + return nil +} + +// GetDigest creates the feed update digest used in signatures +// the serialized payload is cached in .binaryData +func (r *Request) GetDigest() (result common.Hash, err error) { + hasher := hashPool.Get().(hash.Hash) + defer hashPool.Put(hasher) + hasher.Reset() + dataLength := r.Update.binaryLength() + if r.binaryData == nil { + r.binaryData = make([]byte, dataLength+signatureLength) + if err := r.Update.binaryPut(r.binaryData[:dataLength]); err != nil { + return result, err + } + } + hasher.Write(r.binaryData[:dataLength]) //everything except the signature. + + return common.BytesToHash(hasher.Sum(nil)), nil +} + +// create an update chunk. +func (r *Request) toChunk() (storage.Chunk, error) { + + // Check that the update is signed and serialized + // For efficiency, data is serialized during signature and cached in + // the binaryData field when computing the signature digest in .getDigest() + if r.Signature == nil || r.binaryData == nil { + return nil, NewError(ErrInvalidSignature, "toChunk called without a valid signature or payload data. Call .Sign() first.") + } + + updateLength := r.Update.binaryLength() + + // signature is the last item in the chunk data + copy(r.binaryData[updateLength:], r.Signature[:]) + + chunk := storage.NewChunk(r.idAddr, r.binaryData) + return chunk, nil +} + +// fromChunk populates this structure from chunk data. It does not verify the signature is valid. +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 + } + + // Extract the signature + var signature *Signature + cursor := r.Update.binaryLength() + sigdata := chunkdata[cursor : cursor+signatureLength] + if len(sigdata) > 0 { + signature = &Signature{} + copy(signature[:], sigdata) + } + + r.Signature = signature + r.idAddr = chunk.Address() + r.binaryData = chunkdata + + return nil + +} + +// FromValues deserializes this instance from a string key-value store +// useful to parse query strings +func (r *Request) FromValues(values Values, data []byte) error { + signatureBytes, err := hexutil.Decode(values.Get("signature")) + if err != nil { + r.Signature = nil + } else { + if len(signatureBytes) != signatureLength { + return NewError(ErrInvalidSignature, "Incorrect signature length") + } + r.Signature = new(Signature) + copy(r.Signature[:], signatureBytes) + } + err = r.Update.FromValues(values, data) + if err != nil { + return err + } + r.idAddr = r.Addr() + return err +} + +// AppendValues serializes this structure into the provided string key-value store +// useful to build query strings +func (r *Request) AppendValues(values Values) []byte { + if r.Signature != nil { + values.Set("signature", hexutil.Encode(r.Signature[:])) + } + return r.Update.AppendValues(values) +} + +// fromJSON takes an update request JSON and populates an UpdateRequest +func (r *Request) fromJSON(j *updateRequestJSON) error { + + r.ID = j.ID + r.Header.Version = j.ProtocolVersion + + var err error + if j.Data != "" { + r.data, err = hexutil.Decode(j.Data) + if err != nil { + return NewError(ErrInvalidValue, "Cannot decode data") + } + } + + if j.Signature != "" { + sigBytes, err := hexutil.Decode(j.Signature) + if err != nil || len(sigBytes) != signatureLength { + return NewError(ErrInvalidSignature, "Cannot decode signature") + } + r.Signature = new(Signature) + r.idAddr = r.Addr() + copy(r.Signature[:], sigBytes) + } + return nil +} + +// UnmarshalJSON takes a JSON structure stored in a byte array and populates the Request object +// Implements json.Unmarshaler interface +func (r *Request) UnmarshalJSON(rawData []byte) error { + var requestJSON updateRequestJSON + if err := json.Unmarshal(rawData, &requestJSON); err != nil { + return err + } + return r.fromJSON(&requestJSON) +} + +// MarshalJSON takes an update request and encodes it as a JSON structure into a byte array +// Implements json.Marshaler interface +func (r *Request) MarshalJSON() (rawData []byte, err error) { + var signatureString, dataString string + if r.Signature != nil { + signatureString = hexutil.Encode(r.Signature[:]) + } + if r.data != nil { + dataString = hexutil.Encode(r.data) + } + + requestJSON := &updateRequestJSON{ + ID: r.ID, + ProtocolVersion: r.Header.Version, + Data: dataString, + Signature: signatureString, + } + + return json.Marshal(requestJSON) +} diff --git a/swarm/storage/feed/request_test.go b/swarm/storage/feed/request_test.go new file mode 100644 index 0000000000..c30158fddf --- /dev/null +++ b/swarm/storage/feed/request_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 feed + +import ( + "bytes" + "encoding/binary" + "encoding/json" + "fmt" + "reflect" + "testing" + + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/swarm/storage" + "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup" +) + +func areEqualJSON(s1, s2 string) (bool, error) { + //credit for the trick: turtlemonvh https://gist.github.com/turtlemonvh/e4f7404e28387fadb8ad275a99596f67 + var o1 interface{} + var o2 interface{} + + err := json.Unmarshal([]byte(s1), &o1) + if err != nil { + return false, fmt.Errorf("Error mashalling string 1 :: %s", err.Error()) + } + err = json.Unmarshal([]byte(s2), &o2) + if err != nil { + return false, fmt.Errorf("Error mashalling string 2 :: %s", err.Error()) + } + + return reflect.DeepEqual(o1, o2), nil +} + +// TestEncodingDecodingUpdateRequests ensures that requests are serialized properly +// while also checking cryptographically that only the owner of a feed can update it. +func TestEncodingDecodingUpdateRequests(t *testing.T) { + + charlie := newCharlieSigner() //Charlie + bob := newBobSigner() //Bob + + // Create a feed to our good guy Charlie's name + topic, _ := NewTopic("a good topic name", nil) + firstRequest := NewFirstRequest(topic) + firstRequest.User = charlie.Address() + + // We now encode the create message to simulate we send it over the wire + messageRawData, err := firstRequest.MarshalJSON() + if err != nil { + t.Fatalf("Error encoding first feed update request: %s", err) + } + + // ... the message arrives and is decoded... + var recoveredFirstRequest Request + if err := recoveredFirstRequest.UnmarshalJSON(messageRawData); err != nil { + t.Fatalf("Error decoding first feed update request: %s", err) + } + + // ... but verification should fail because it is not signed! + if err := recoveredFirstRequest.Verify(); err == nil { + t.Fatal("Expected Verify to fail since the message is not signed") + } + + // We now assume that the feed ypdate was created and propagated. + + const expectedSignature = "0x7235b27a68372ddebcf78eba48543fa460864b0b0e99cb533fcd3664820e603312d29426dd00fb39628f5299480a69bf6e462838d78de49ce0704c754c9deb2601" + const expectedJSON = `{"feed":{"topic":"0x6120676f6f6420746f706963206e616d65000000000000000000000000000000","user":"0x876a8936a7cd0b79ef0735ad0896c1afe278781c"},"epoch":{"time":1000,"level":1},"protocolVersion":0,"data":"0x5468697320686f75722773207570646174653a20537761726d2039392e3020686173206265656e2072656c656173656421"}` + + //Put together an unsigned update request that we will serialize to send it to the signer. + data := []byte("This hour's update: Swarm 99.0 has been released!") + request := &Request{ + Update: Update{ + ID: ID{ + Epoch: lookup.Epoch{ + Time: 1000, + Level: 1, + }, + Feed: firstRequest.Update.Feed, + }, + data: data, + }, + } + + messageRawData, err = request.MarshalJSON() + if err != nil { + t.Fatalf("Error encoding update request: %s", err) + } + + equalJSON, err := areEqualJSON(string(messageRawData), expectedJSON) + if err != nil { + t.Fatalf("Error decoding update request JSON: %s", err) + } + if !equalJSON { + t.Fatalf("Received a different JSON message. Expected %s, got %s", expectedJSON, string(messageRawData)) + } + + // now the encoded message messageRawData is sent over the wire and arrives to the signer + + //Attempt to extract an UpdateRequest out of the encoded message + var recoveredRequest Request + if err := recoveredRequest.UnmarshalJSON(messageRawData); err != nil { + t.Fatalf("Error decoding update request: %s", err) + } + + //sign the request and see if it matches our predefined signature above. + if err := recoveredRequest.Sign(charlie); err != nil { + t.Fatalf("Error signing request: %s", err) + } + + compareByteSliceToExpectedHex(t, "signature", recoveredRequest.Signature[:], expectedSignature) + + // mess with the signature and see what happens. To alter the signature, we briefly decode it as JSON + // to alter the signature field. + var j updateRequestJSON + if err := json.Unmarshal([]byte(expectedJSON), &j); err != nil { + t.Fatal("Error unmarshalling test json, check expectedJSON constant") + } + j.Signature = "Certainly not a signature" + corruptMessage, _ := json.Marshal(j) // encode the message with the bad signature + var corruptRequest Request + if err = corruptRequest.UnmarshalJSON(corruptMessage); err == nil { + t.Fatal("Expected DecodeUpdateRequest to fail when trying to interpret a corrupt message with an invalid signature") + } + + // Now imagine Bob wants to create an update of his own about the same feed, + // signing a message with his private key + if err := request.Sign(bob); err != nil { + t.Fatalf("Error signing: %s", err) + } + + // Now Bob encodes the message to send it over the wire... + messageRawData, err = request.MarshalJSON() + if err != nil { + t.Fatalf("Error encoding message:%s", err) + } + + // ... the message arrives to our Swarm node and it is decoded. + recoveredRequest = Request{} + if err := recoveredRequest.UnmarshalJSON(messageRawData); err != nil { + t.Fatalf("Error decoding message:%s", err) + } + + // Before checking what happened with Bob's update, let's see what would happen if we mess + // with the signature big time to see if Verify catches it + savedSignature := *recoveredRequest.Signature // save the signature for later + binary.LittleEndian.PutUint64(recoveredRequest.Signature[5:], 556845463424) // write some random data to break the signature + if err = recoveredRequest.Verify(); err == nil { + t.Fatal("Expected Verify to fail on corrupt signature") + } + + // restore the Bob's signature from corruption + *recoveredRequest.Signature = savedSignature + + // Now the signature is not corrupt + if err = recoveredRequest.Verify(); err != nil { + t.Fatal(err) + } + + // Reuse object and sign with our friend Charlie's private key + if err := recoveredRequest.Sign(charlie); err != nil { + t.Fatalf("Error signing with the correct private key: %s", err) + } + + // And now, Verify should work since this update now belongs to Charlie + if err = recoveredRequest.Verify(); err != nil { + t.Fatalf("Error verifying that Charlie, can sign a reused request object:%s", err) + } + + // mess with the lookup key to make sure Verify fails: + recoveredRequest.Time = 77999 // this will alter the lookup key + if err = recoveredRequest.Verify(); err == nil { + t.Fatalf("Expected Verify to fail since the lookup key has been altered") + } +} + +func getTestRequest() *Request { + return &Request{ + Update: *getTestFeedUpdate(), + } +} + +func TestUpdateChunkSerializationErrorChecking(t *testing.T) { + + // Test that parseUpdate fails if the chunk is too small + var r Request + 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) + } + + r = *getTestRequest() + + _, err := r.toChunk() + if err == nil { + t.Fatal("Expected request.toChunk to fail when there is no data") + } + r.data = []byte("Al bien hacer jamás le falta premio") // put some arbitrary length data + _, err = r.toChunk() + if err == nil { + t.Fatal("expected request.toChunk to fail when there is no signature") + } + + charlie := newCharlieSigner() + if err := r.Sign(charlie); err != nil { + t.Fatalf("error signing:%s", err) + } + + chunk, err := r.toChunk() + if err != nil { + t.Fatalf("error creating update chunk:%s", err) + } + + compareByteSliceToExpectedHex(t, "chunk", chunk.Data(), "0x0000000000000000776f726c64206e657773207265706f72742c20657665727920686f7572000000876a8936a7cd0b79ef0735ad0896c1afe278781ce803000000000019416c206269656e206861636572206a616dc3a173206c652066616c7461207072656d696f5a0ffe0bc27f207cd5b00944c8b9cee93e08b89b5ada777f123ac535189333f174a6a4ca2f43a92c4a477a49d774813c36ce8288552c58e6205b0ac35d0507eb00") + + var recovered Request + recovered.fromChunk(chunk) + if !reflect.DeepEqual(recovered, r) { + t.Fatal("Expected recovered feed update request to equal the original one") + } +} + +// check that signature address matches update signer address +func TestReverse(t *testing.T) { + + epoch := lookup.Epoch{ + Time: 7888, + Level: 6, + } + + // make fake timeProvider + timeProvider := &fakeTimeProvider{ + currentTime: startTime.Time, + } + + // signer containing private key + signer := newAliceSigner() + + // set up rpc and create feeds handler + _, _, teardownTest, err := setupTest(timeProvider, signer) + if err != nil { + t.Fatal(err) + } + defer teardownTest() + + topic, _ := NewTopic("Cervantes quotes", nil) + fd := Feed{ + Topic: topic, + User: signer.Address(), + } + + data := []byte("Donde una puerta se cierra, otra se abre") + + request := new(Request) + request.Feed = fd + request.Epoch = epoch + request.data = data + + // generate a chunk key for this request + key := request.Addr() + + if err = request.Sign(signer); err != nil { + t.Fatal(err) + } + + chunk, err := request.toChunk() + if err != nil { + t.Fatal(err) + } + + // check that we can recover the owner account from the update chunk's signature + var checkUpdate Request + if err := checkUpdate.fromChunk(chunk); err != nil { + t.Fatal(err) + } + checkdigest, err := checkUpdate.GetDigest() + if err != nil { + t.Fatal(err) + } + recoveredAddr, err := getUserAddr(checkdigest, *checkUpdate.Signature) + if err != nil { + t.Fatalf("Retrieve address from signature fail: %v", err) + } + originalAddr := crypto.PubkeyToAddress(signer.PrivKey.PublicKey) + + // check that the metadata retrieved from the chunk matches what we gave it + if recoveredAddr != originalAddr { + t.Fatalf("addresses dont match: %x != %x", originalAddr, recoveredAddr) + } + + if !bytes.Equal(key[:], chunk.Address()[:]) { + t.Fatalf("Expected chunk key '%x', was '%x'", key, chunk.Address()) + } + if epoch != checkUpdate.Epoch { + t.Fatalf("Expected epoch to be '%s', was '%s'", epoch.String(), checkUpdate.Epoch.String()) + } + if !bytes.Equal(data, checkUpdate.data) { + t.Fatalf("Expected data '%x', was '%x'", data, checkUpdate.data) + } +} diff --git a/swarm/storage/feed/sign.go b/swarm/storage/feed/sign.go new file mode 100644 index 0000000000..5f0ea0b33c --- /dev/null +++ b/swarm/storage/feed/sign.go @@ -0,0 +1,75 @@ +// 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 feed + +import ( + "crypto/ecdsa" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" +) + +const signatureLength = 65 + +// Signature is an alias for a static byte array with the size of a signature +type Signature [signatureLength]byte + +// Signer signs feed update payloads +type Signer interface { + Sign(common.Hash) (Signature, error) + Address() common.Address +} + +// GenericSigner implements the Signer interface +// It is the vanilla signer that probably should be used in most cases +type GenericSigner struct { + PrivKey *ecdsa.PrivateKey + address common.Address +} + +// NewGenericSigner builds a signer that will sign everything with the provided private key +func NewGenericSigner(privKey *ecdsa.PrivateKey) *GenericSigner { + return &GenericSigner{ + PrivKey: privKey, + address: crypto.PubkeyToAddress(privKey.PublicKey), + } +} + +// Sign signs the supplied data +// It wraps the ethereum crypto.Sign() method +func (s *GenericSigner) Sign(data common.Hash) (signature Signature, err error) { + signaturebytes, err := crypto.Sign(data.Bytes(), s.PrivKey) + if err != nil { + return + } + copy(signature[:], signaturebytes) + return +} + +// Address returns the public key of the signer's private key +func (s *GenericSigner) Address() common.Address { + return s.address +} + +// getUserAddr extracts the address of the feed update signer +func getUserAddr(digest common.Hash, signature Signature) (common.Address, error) { + pub, err := crypto.SigToPub(digest.Bytes(), signature[:]) + if err != nil { + return common.Address{}, err + } + return crypto.PubkeyToAddress(*pub), nil +} diff --git a/swarm/storage/feed/testutil.go b/swarm/storage/feed/testutil.go new file mode 100644 index 0000000000..caa39d9ffc --- /dev/null +++ b/swarm/storage/feed/testutil.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 feed + +import ( + "context" + "fmt" + "path/filepath" + "sync" + + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/swarm/storage" +) + +const ( + testDbDirName = "feeds" +) + +type TestHandler struct { + *Handler +} + +func (t *TestHandler) Close() { + t.chunkStore.Close() +} + +type mockNetFetcher struct{} + +func (m *mockNetFetcher) Request(hopCount uint8) { +} +func (m *mockNetFetcher) Offer(source *enode.ID) { +} + +func newFakeNetFetcher(context.Context, storage.Address, *sync.Map) storage.NetFetcher { + return &mockNetFetcher{} +} + +// NewTestHandler creates Handler object to be used for testing purposes. +func NewTestHandler(datadir string, params *HandlerParams) (*TestHandler, error) { + path := filepath.Join(datadir, testDbDirName) + fh := NewHandler(params) + localstoreparams := storage.NewDefaultLocalStoreParams() + localstoreparams.Init(path) + localStore, err := storage.NewLocalStore(localstoreparams, nil) + if err != nil { + return nil, fmt.Errorf("localstore create fail, path %s: %v", path, err) + } + localStore.Validators = append(localStore.Validators, storage.NewContentAddressValidator(storage.MakeHashFunc(feedsHashAlgorithm))) + localStore.Validators = append(localStore.Validators, fh) + netStore, err := storage.NewNetStore(localStore, nil) + if err != nil { + return nil, err + } + netStore.NewNetFetcherFunc = newFakeNetFetcher + fh.SetStore(netStore) + return &TestHandler{fh}, nil +} diff --git a/swarm/storage/feed/timestampprovider.go b/swarm/storage/feed/timestampprovider.go new file mode 100644 index 0000000000..fb60cea9c3 --- /dev/null +++ b/swarm/storage/feed/timestampprovider.go @@ -0,0 +1,62 @@ +// 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 feed + +import ( + "encoding/json" + "time" +) + +// TimestampProvider sets the time source of the feeds package +var TimestampProvider timestampProvider = NewDefaultTimestampProvider() + +// Timestamp encodes a point in time as a Unix epoch +type Timestamp struct { + Time uint64 `json:"time"` // Unix epoch timestamp, in seconds +} + +// timestampProvider interface describes a source of timestamp information +type timestampProvider interface { + Now() Timestamp // returns the current timestamp information +} + +// UnmarshalJSON implements the json.Unmarshaller interface +func (t *Timestamp) UnmarshalJSON(data []byte) error { + return json.Unmarshal(data, &t.Time) +} + +// MarshalJSON implements the json.Marshaller interface +func (t *Timestamp) MarshalJSON() ([]byte, error) { + return json.Marshal(t.Time) +} + +// DefaultTimestampProvider is a TimestampProvider that uses system time +// as time source +type DefaultTimestampProvider struct { +} + +// NewDefaultTimestampProvider creates a system clock based timestamp provider +func NewDefaultTimestampProvider() *DefaultTimestampProvider { + return &DefaultTimestampProvider{} +} + +// Now returns the current time according to this provider +func (dtp *DefaultTimestampProvider) Now() Timestamp { + return Timestamp{ + Time: uint64(time.Now().Unix()), + } +} diff --git a/swarm/storage/feed/topic.go b/swarm/storage/feed/topic.go new file mode 100644 index 0000000000..43a7b4ba4c --- /dev/null +++ b/swarm/storage/feed/topic.go @@ -0,0 +1,105 @@ +// 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 feed + +import ( + "bytes" + "encoding/json" + "fmt" + + "github.com/ethereum/go-ethereum/common/bitutil" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/swarm/storage" +) + +// TopicLength establishes the max length of a topic string +const TopicLength = storage.AddressLength + +// Topic represents what a feed is about +type Topic [TopicLength]byte + +// ErrTopicTooLong is returned when creating a topic with a name/related content too long +var ErrTopicTooLong = fmt.Errorf("Topic is too long. Max length is %d", TopicLength) + +// NewTopic creates a new topic from a provided name and "related content" byte array, +// merging the two together. +// If relatedContent or name are longer than TopicLength, they will be truncated and an error returned +// name can be an empty string +// relatedContent can be nil +func NewTopic(name string, relatedContent []byte) (topic Topic, err error) { + if relatedContent != nil { + contentLength := len(relatedContent) + if contentLength > TopicLength { + contentLength = TopicLength + err = ErrTopicTooLong + } + copy(topic[:], relatedContent[:contentLength]) + } + nameBytes := []byte(name) + nameLength := len(nameBytes) + if nameLength > TopicLength { + nameLength = TopicLength + err = ErrTopicTooLong + } + bitutil.XORBytes(topic[:], topic[:], nameBytes[:nameLength]) + return topic, err +} + +// Hex will return the topic encoded as an hex string +func (t *Topic) Hex() string { + return hexutil.Encode(t[:]) +} + +// FromHex will parse a hex string into this Topic instance +func (t *Topic) FromHex(hex string) error { + bytes, err := hexutil.Decode(hex) + if err != nil || len(bytes) != len(t) { + return NewErrorf(ErrInvalidValue, "Cannot decode topic") + } + copy(t[:], bytes) + return nil +} + +// Name will try to extract the topic name out of the Topic +func (t *Topic) Name(relatedContent []byte) string { + nameBytes := *t + if relatedContent != nil { + contentLength := len(relatedContent) + if contentLength > TopicLength { + contentLength = TopicLength + } + bitutil.XORBytes(nameBytes[:], t[:], relatedContent[:contentLength]) + } + z := bytes.IndexByte(nameBytes[:], 0) + if z < 0 { + z = TopicLength + } + return string(nameBytes[:z]) + +} + +// UnmarshalJSON implements the json.Unmarshaller interface +func (t *Topic) UnmarshalJSON(data []byte) error { + var hex string + json.Unmarshal(data, &hex) + return t.FromHex(hex) +} + +// MarshalJSON implements the json.Marshaller interface +func (t *Topic) MarshalJSON() ([]byte, error) { + return json.Marshal(t.Hex()) +} diff --git a/swarm/storage/feed/topic_test.go b/swarm/storage/feed/topic_test.go new file mode 100644 index 0000000000..0403204f7f --- /dev/null +++ b/swarm/storage/feed/topic_test.go @@ -0,0 +1,50 @@ +package feed + +import ( + "testing" + + "github.com/ethereum/go-ethereum/common/hexutil" +) + +func TestTopic(t *testing.T) { + related, _ := hexutil.Decode("0xabcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789") + topicName := "test-topic" + topic, _ := NewTopic(topicName, related) + hex := topic.Hex() + expectedHex := "0xdfa89c750e3108f9c2aeef0123456789abcdef0123456789abcdef0123456789" + if hex != expectedHex { + t.Fatalf("Expected %s, got %s", expectedHex, hex) + } + + var topic2 Topic + topic2.FromHex(hex) + if topic2 != topic { + t.Fatal("Expected recovered topic to be equal to original one") + } + + if topic2.Name(related) != topicName { + t.Fatal("Retrieved name does not match") + } + + bytes, err := topic2.MarshalJSON() + if err != nil { + t.Fatal(err) + } + expectedJSON := `"0xdfa89c750e3108f9c2aeef0123456789abcdef0123456789abcdef0123456789"` + equal, err := areEqualJSON(expectedJSON, string(bytes)) + if err != nil { + t.Fatal(err) + } + if !equal { + t.Fatalf("Expected JSON to be %s, got %s", expectedJSON, string(bytes)) + } + + err = topic2.UnmarshalJSON(bytes) + if err != nil { + t.Fatal(err) + } + if topic2 != topic { + t.Fatal("Expected recovered topic to be equal to original one") + } + +} diff --git a/swarm/storage/feed/update.go b/swarm/storage/feed/update.go new file mode 100644 index 0000000000..21c004ca42 --- /dev/null +++ b/swarm/storage/feed/update.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 feed + +import ( + "fmt" + "strconv" + + "github.com/ethereum/go-ethereum/swarm/chunk" +) + +// ProtocolVersion defines the current version of the protocol that will be included in each update message +const ProtocolVersion uint8 = 0 + +const headerLength = 8 + +// Header defines a update message header including a protocol version byte +type Header struct { + Version uint8 // Protocol version + Padding [headerLength - 1]uint8 // reserved for future use +} + +// Update encapsulates the information sent as part of a feed update +type Update struct { + Header Header // + ID // Feed Update identifying information + data []byte // actual data payload +} + +const minimumUpdateDataLength = idLength + headerLength + 1 + +//MaxUpdateDataLength indicates the maximum payload size for a feed update +const MaxUpdateDataLength = chunk.DefaultSize - signatureLength - idLength - headerLength + +// binaryPut serializes the feed update information into the given slice +func (r *Update) binaryPut(serializedData []byte) error { + datalength := len(r.data) + if datalength == 0 { + return NewError(ErrInvalidValue, "a feed update must contain data") + } + + if datalength > MaxUpdateDataLength { + return NewErrorf(ErrInvalidValue, "feed update data is too big (length=%d). Max length=%d", datalength, MaxUpdateDataLength) + } + + if len(serializedData) != r.binaryLength() { + return NewErrorf(ErrInvalidValue, "slice passed to putBinary must be of exact size. Expected %d bytes", r.binaryLength()) + } + + var cursor int + // serialize Header + serializedData[cursor] = r.Header.Version + copy(serializedData[cursor+1:headerLength], r.Header.Padding[:headerLength-1]) + cursor += headerLength + + // serialize ID + if err := r.ID.binaryPut(serializedData[cursor : cursor+idLength]); err != nil { + return err + } + cursor += idLength + + // add the data + copy(serializedData[cursor:], r.data) + cursor += datalength + + return nil +} + +// binaryLength returns the expected number of bytes this structure will take to encode +func (r *Update) binaryLength() int { + return idLength + headerLength + len(r.data) +} + +// binaryGet populates this instance from the information contained in the passed byte slice +func (r *Update) binaryGet(serializedData []byte) error { + if len(serializedData) < minimumUpdateDataLength { + return NewErrorf(ErrNothingToReturn, "chunk less than %d bytes cannot be a feed update chunk", minimumUpdateDataLength) + } + dataLength := len(serializedData) - idLength - headerLength + // at this point we can be satisfied that we have the correct data length to read + + var cursor int + + // deserialize Header + r.Header.Version = serializedData[cursor] // extract the protocol version + copy(r.Header.Padding[:headerLength-1], serializedData[cursor+1:headerLength]) // extract the padding + cursor += headerLength + + if err := r.ID.binaryGet(serializedData[cursor : cursor+idLength]); err != nil { + return err + } + cursor += idLength + + data := serializedData[cursor : cursor+dataLength] + cursor += dataLength + + // now that all checks have passed, copy data into structure + r.data = make([]byte, dataLength) + copy(r.data, data) + + return nil + +} + +// FromValues deserializes this instance from a string key-value store +// useful to parse query strings +func (r *Update) FromValues(values Values, data []byte) error { + r.data = data + version, _ := strconv.ParseUint(values.Get("protocolVersion"), 10, 32) + r.Header.Version = uint8(version) + return r.ID.FromValues(values) +} + +// AppendValues serializes this structure into the provided string key-value store +// useful to build query strings +func (r *Update) AppendValues(values Values) []byte { + r.ID.AppendValues(values) + values.Set("protocolVersion", fmt.Sprintf("%d", r.Header.Version)) + return r.data +} diff --git a/swarm/storage/feed/update_test.go b/swarm/storage/feed/update_test.go new file mode 100644 index 0000000000..24c09b3617 --- /dev/null +++ b/swarm/storage/feed/update_test.go @@ -0,0 +1,50 @@ +// 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 feed + +import ( + "testing" +) + +func getTestFeedUpdate() *Update { + return &Update{ + ID: *getTestID(), + data: []byte("El que lee mucho y anda mucho, ve mucho y sabe mucho"), + } +} + +func TestUpdateSerializer(t *testing.T) { + testBinarySerializerRecovery(t, getTestFeedUpdate(), "0x0000000000000000776f726c64206e657773207265706f72742c20657665727920686f7572000000876a8936a7cd0b79ef0735ad0896c1afe278781ce803000000000019456c20717565206c6565206d7563686f207920616e6461206d7563686f2c207665206d7563686f20792073616265206d7563686f") +} + +func TestUpdateLengthCheck(t *testing.T) { + testBinarySerializerLengthCheck(t, getTestFeedUpdate()) + // Test fail if update is too big + update := getTestFeedUpdate() + update.data = make([]byte, MaxUpdateDataLength+100) + serialized := make([]byte, update.binaryLength()) + if err := update.binaryPut(serialized); err == nil { + t.Fatal("Expected update.binaryPut to fail since update is too big") + } + + // test fail if data is empty or nil + update.data = nil + serialized = make([]byte, update.binaryLength()) + if err := update.binaryPut(serialized); err == nil { + t.Fatal("Expected update.binaryPut to fail since data is empty") + } +} diff --git a/swarm/storage/filestore.go b/swarm/storage/filestore.go new file mode 100644 index 0000000000..0bad944ee9 --- /dev/null +++ b/swarm/storage/filestore.go @@ -0,0 +1,146 @@ +// 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 storage + +import ( + "context" + "io" + "sort" + "sync" +) + +/* +FileStore provides the client API entrypoints Store and Retrieve to store and retrieve +It can store anything that has a byte slice representation, so files or serialised objects etc. + +Storage: FileStore calls the Chunker to segment the input datastream of any size to a merkle hashed tree of chunks. The key of the root block is returned to the client. + +Retrieval: given the key of the root block, the FileStore retrieves the block chunks and reconstructs the original data and passes it back as a lazy reader. A lazy reader is a reader with on-demand delayed processing, i.e. the chunks needed to reconstruct a large file are only fetched and processed if that particular part of the document is actually read. + +As the chunker produces chunks, FileStore dispatches them to its own chunk store +implementation for storage or retrieval. +*/ + +const ( + defaultLDBCapacity = 5000000 // capacity for LevelDB, by default 5*10^6*4096 bytes == 20GB + defaultCacheCapacity = 10000 // capacity for in-memory chunks' cache + defaultChunkRequestsCacheCapacity = 5000000 // capacity for container holding outgoing requests for chunks. should be set to LevelDB capacity +) + +type FileStore struct { + ChunkStore + hashFunc SwarmHasher +} + +type FileStoreParams struct { + Hash string +} + +func NewFileStoreParams() *FileStoreParams { + return &FileStoreParams{ + Hash: DefaultHash, + } +} + +// for testing locally +func NewLocalFileStore(datadir string, basekey []byte) (*FileStore, error) { + params := NewDefaultLocalStoreParams() + params.Init(datadir) + localStore, err := NewLocalStore(params, nil) + if err != nil { + return nil, err + } + localStore.Validators = append(localStore.Validators, NewContentAddressValidator(MakeHashFunc(DefaultHash))) + return NewFileStore(localStore, NewFileStoreParams()), nil +} + +func NewFileStore(store ChunkStore, params *FileStoreParams) *FileStore { + hashFunc := MakeHashFunc(params.Hash) + return &FileStore{ + ChunkStore: store, + hashFunc: hashFunc, + } +} + +// 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. +// It returns a reader with the chunk data and whether the content was encrypted +func (f *FileStore) Retrieve(ctx context.Context, addr Address) (reader *LazyChunkReader, isEncrypted bool) { + isEncrypted = len(addr) > f.hashFunc().Size() + getter := NewHasherStore(f.ChunkStore, f.hashFunc, isEncrypted) + reader = TreeJoin(ctx, addr, getter, 0) + return +} + +// 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) + return PyramidSplit(ctx, data, putter, putter) +} + +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/swarm/storage/filestore_test.go b/swarm/storage/filestore_test.go new file mode 100644 index 0000000000..06c4be1d78 --- /dev/null +++ b/swarm/storage/filestore_test.go @@ -0,0 +1,207 @@ +// 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 storage + +import ( + "bytes" + "context" + "io" + "io/ioutil" + "os" + "testing" + + "github.com/ethereum/go-ethereum/swarm/testutil" +) + +const testDataSize = 0x0001000 + +func TestFileStorerandom(t *testing.T) { + testFileStoreRandom(false, t) + testFileStoreRandom(true, t) +} + +func testFileStoreRandom(toEncrypt bool, t *testing.T) { + tdb, cleanup, err := newTestDbStore(false, false) + defer cleanup() + if err != nil { + t.Fatalf("init dbStore failed: %v", err) + } + db := tdb.LDBStore + db.setCapacity(50000) + memStore := NewMemStore(NewDefaultStoreParams(), db) + localStore := &LocalStore{ + memStore: memStore, + DbStore: db, + } + + fileStore := NewFileStore(localStore, NewFileStoreParams()) + defer os.RemoveAll("/tmp/bzz") + + slice := testutil.RandomBytes(1, testDataSize) + ctx := context.TODO() + key, wait, err := fileStore.Store(ctx, bytes.NewReader(slice), testDataSize, toEncrypt) + if err != nil { + t.Fatalf("Store error: %v", err) + } + err = wait(ctx) + if err != nil { + t.Fatalf("Store waitt error: %v", err.Error()) + } + resultReader, isEncrypted := fileStore.Retrieve(context.TODO(), key) + if isEncrypted != toEncrypt { + t.Fatalf("isEncrypted expected %v got %v", toEncrypt, isEncrypted) + } + resultSlice := make([]byte, testDataSize) + n, err := resultReader.ReadAt(resultSlice, 0) + if err != io.EOF { + t.Fatalf("Retrieve error: %v", err) + } + if n != testDataSize { + t.Fatalf("Slice size error got %d, expected %d.", n, testDataSize) + } + if !bytes.Equal(slice, resultSlice) { + t.Fatalf("Comparison error.") + } + ioutil.WriteFile("/tmp/slice.bzz.16M", slice, 0666) + ioutil.WriteFile("/tmp/result.bzz.16M", resultSlice, 0666) + localStore.memStore = NewMemStore(NewDefaultStoreParams(), db) + resultReader, isEncrypted = fileStore.Retrieve(context.TODO(), key) + if isEncrypted != toEncrypt { + t.Fatalf("isEncrypted expected %v got %v", toEncrypt, isEncrypted) + } + for i := range resultSlice { + resultSlice[i] = 0 + } + n, err = resultReader.ReadAt(resultSlice, 0) + if err != io.EOF { + t.Fatalf("Retrieve error after removing memStore: %v", err) + } + if n != len(slice) { + t.Fatalf("Slice size error after removing memStore got %d, expected %d.", n, len(slice)) + } + if !bytes.Equal(slice, resultSlice) { + t.Fatalf("Comparison error after removing memStore.") + } +} + +func TestFileStoreCapacity(t *testing.T) { + testFileStoreCapacity(false, t) + testFileStoreCapacity(true, t) +} + +func testFileStoreCapacity(toEncrypt bool, 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()) + slice := testutil.RandomBytes(1, testDataSize) + ctx := context.TODO() + key, wait, err := fileStore.Store(ctx, bytes.NewReader(slice), testDataSize, toEncrypt) + if err != nil { + t.Errorf("Store error: %v", err) + } + err = wait(ctx) + if err != nil { + t.Fatalf("Store error: %v", err) + } + resultReader, isEncrypted := fileStore.Retrieve(context.TODO(), key) + if isEncrypted != toEncrypt { + t.Fatalf("isEncrypted expected %v got %v", toEncrypt, isEncrypted) + } + resultSlice := make([]byte, len(slice)) + n, err := resultReader.ReadAt(resultSlice, 0) + if err != io.EOF { + t.Fatalf("Retrieve error: %v", err) + } + if n != len(slice) { + t.Fatalf("Slice size error got %d, expected %d.", n, len(slice)) + } + if !bytes.Equal(slice, resultSlice) { + t.Fatalf("Comparison error.") + } + // Clear memStore + memStore.setCapacity(0) + // check whether it is, indeed, empty + fileStore.ChunkStore = memStore + resultReader, isEncrypted = fileStore.Retrieve(context.TODO(), key) + if isEncrypted != toEncrypt { + t.Fatalf("isEncrypted expected %v got %v", toEncrypt, isEncrypted) + } + if _, err = resultReader.ReadAt(resultSlice, 0); err == nil { + t.Fatalf("Was able to read %d bytes from an empty memStore.", len(slice)) + } + // check how it works with localStore + fileStore.ChunkStore = localStore + // localStore.dbStore.setCapacity(0) + resultReader, isEncrypted = fileStore.Retrieve(context.TODO(), key) + if isEncrypted != toEncrypt { + t.Fatalf("isEncrypted expected %v got %v", toEncrypt, isEncrypted) + } + for i := range resultSlice { + resultSlice[i] = 0 + } + n, err = resultReader.ReadAt(resultSlice, 0) + if err != io.EOF { + t.Fatalf("Retrieve error after clearing memStore: %v", err) + } + if n != len(slice) { + t.Fatalf("Slice size error after clearing memStore got %d, expected %d.", n, len(slice)) + } + if !bytes.Equal(slice, resultSlice) { + 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/swarm/storage/hasherstore.go b/swarm/storage/hasherstore.go new file mode 100644 index 0000000000..345ce7430a --- /dev/null +++ b/swarm/storage/hasherstore.go @@ -0,0 +1,263 @@ +// 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 storage + +import ( + "context" + "fmt" + "sync/atomic" + + "github.com/ethereum/go-ethereum/swarm/chunk" + "github.com/ethereum/go-ethereum/swarm/storage/encryption" + "golang.org/x/crypto/sha3" +) + +type hasherStore struct { + store ChunkStore + toEncrypt bool + hashFunc SwarmHasher + hashSize int // content hash size + refSize int64 // reference size (content hash + possibly encryption key) + errC chan error // global error channel + doneC chan struct{} // closed by Close() call to indicate that count is the final number of chunks + quitC chan struct{} // closed to quit unterminated routines + // nrChunks is used with atomic functions + // it is required to be at the end of the struct to ensure 64bit alignment for arm architecture + // see: https://golang.org/pkg/sync/atomic/#pkg-note-BUG + nrChunks uint64 // number of chunks to store +} + +// NewHasherStore creates a hasherStore object, which implements Putter and Getter interfaces. +// With the HasherStore you can put and get chunk data (which is just []byte) into a ChunkStore +// and the hasherStore will take core of encryption/decryption of data if necessary +func NewHasherStore(store ChunkStore, hashFunc SwarmHasher, toEncrypt bool) *hasherStore { + hashSize := hashFunc().Size() + refSize := int64(hashSize) + if toEncrypt { + refSize += encryption.KeyLength + } + + h := &hasherStore{ + store: store, + toEncrypt: toEncrypt, + hashFunc: hashFunc, + hashSize: hashSize, + refSize: refSize, + errC: make(chan error), + doneC: make(chan struct{}), + quitC: make(chan struct{}), + } + + return h +} + +// Put stores the chunkData into the ChunkStore of the hasherStore and returns the reference. +// If hasherStore has a chunkEncryption object, the data will be encrypted. +// Asynchronous function, the data will not necessarily be stored when it returns. +func (h *hasherStore) Put(ctx context.Context, chunkData ChunkData) (Reference, error) { + c := chunkData + var encryptionKey encryption.Key + if h.toEncrypt { + var err error + c, encryptionKey, err = h.encryptChunkData(chunkData) + if err != nil { + return nil, err + } + } + chunk := h.createChunk(c) + h.storeChunk(ctx, chunk) + + return Reference(append(chunk.Address(), encryptionKey...)), nil +} + +// Get returns data of the chunk with the given reference (retrieved from the ChunkStore of hasherStore). +// If the data is encrypted and the reference contains an encryption key, it will be decrypted before +// return. +func (h *hasherStore) Get(ctx context.Context, ref Reference) (ChunkData, error) { + addr, encryptionKey, err := parseReference(ref, h.hashSize) + if err != nil { + return nil, err + } + + chunk, err := h.store.Get(ctx, addr) + if err != nil { + return nil, err + } + + chunkData := ChunkData(chunk.Data()) + toDecrypt := (encryptionKey != nil) + if toDecrypt { + var err error + chunkData, err = h.decryptChunkData(chunkData, encryptionKey) + if err != nil { + return nil, err + } + } + return chunkData, nil +} + +// Close indicates that no more chunks will be put with the hasherStore, so the Wait +// function can return when all the previously put chunks has been stored. +func (h *hasherStore) Close() { + close(h.doneC) +} + +// Wait returns when +// 1) the Close() function has been called and +// 2) all the chunks which has been Put has been stored +func (h *hasherStore) Wait(ctx context.Context) error { + defer close(h.quitC) + var nrStoredChunks uint64 // number of stored chunks + var done bool + doneC := h.doneC + for { + select { + // if context is done earlier, just return with the error + case <-ctx.Done(): + return ctx.Err() + // doneC is closed if all chunks have been submitted, from then we just wait until all of them are also stored + case <-doneC: + done = true + doneC = nil + // a chunk has been stored, if err is nil, then successfully, so increase the stored chunk counter + case err := <-h.errC: + if err != nil { + return err + } + nrStoredChunks++ + } + // if all the chunks have been submitted and all of them are stored, then we can return + if done { + if nrStoredChunks >= atomic.LoadUint64(&h.nrChunks) { + return nil + } + } + } +} + +func (h *hasherStore) createHash(chunkData ChunkData) Address { + hasher := h.hashFunc() + hasher.ResetWithLength(chunkData[:8]) // 8 bytes of length + hasher.Write(chunkData[8:]) // minus 8 []byte length + return hasher.Sum(nil) +} + +func (h *hasherStore) createChunk(chunkData ChunkData) Chunk { + hash := h.createHash(chunkData) + chunk := NewChunk(hash, chunkData) + return chunk +} + +func (h *hasherStore) encryptChunkData(chunkData ChunkData) (ChunkData, encryption.Key, error) { + if len(chunkData) < 8 { + return nil, nil, fmt.Errorf("Invalid ChunkData, min length 8 got %v", len(chunkData)) + } + + key, encryptedSpan, encryptedData, err := h.encrypt(chunkData) + if err != nil { + return nil, nil, err + } + c := make(ChunkData, len(encryptedSpan)+len(encryptedData)) + copy(c[:8], encryptedSpan) + copy(c[8:], encryptedData) + return c, key, nil +} + +func (h *hasherStore) decryptChunkData(chunkData ChunkData, encryptionKey encryption.Key) (ChunkData, error) { + if len(chunkData) < 8 { + return nil, fmt.Errorf("Invalid ChunkData, min length 8 got %v", len(chunkData)) + } + + decryptedSpan, decryptedData, err := h.decrypt(chunkData, encryptionKey) + if err != nil { + return nil, err + } + + // removing extra bytes which were just added for padding + length := ChunkData(decryptedSpan).Size() + for length > chunk.DefaultSize { + length = length + (chunk.DefaultSize - 1) + length = length / chunk.DefaultSize + length *= uint64(h.refSize) + } + + c := make(ChunkData, length+8) + copy(c[:8], decryptedSpan) + copy(c[8:], decryptedData[:length]) + + return c, nil +} + +func (h *hasherStore) RefSize() int64 { + return h.refSize +} + +func (h *hasherStore) encrypt(chunkData ChunkData) (encryption.Key, []byte, []byte, error) { + key := encryption.GenerateRandomKey(encryption.KeyLength) + encryptedSpan, err := h.newSpanEncryption(key).Encrypt(chunkData[:8]) + if err != nil { + return nil, nil, nil, err + } + encryptedData, err := h.newDataEncryption(key).Encrypt(chunkData[8:]) + if err != nil { + return nil, nil, nil, err + } + return key, encryptedSpan, encryptedData, nil +} + +func (h *hasherStore) decrypt(chunkData ChunkData, key encryption.Key) ([]byte, []byte, error) { + encryptedSpan, err := h.newSpanEncryption(key).Encrypt(chunkData[:8]) + if err != nil { + return nil, nil, err + } + encryptedData, err := h.newDataEncryption(key).Encrypt(chunkData[8:]) + if err != nil { + return nil, nil, err + } + return encryptedSpan, encryptedData, nil +} + +func (h *hasherStore) newSpanEncryption(key encryption.Key) encryption.Encryption { + 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(chunk.DefaultSize), 0, sha3.NewLegacyKeccak256) +} + +func (h *hasherStore) storeChunk(ctx context.Context, chunk Chunk) { + atomic.AddUint64(&h.nrChunks, 1) + go func() { + select { + case h.errC <- h.store.Put(ctx, chunk): + case <-h.quitC: + } + }() +} + +func parseReference(ref Reference, hashSize int) (Address, encryption.Key, error) { + encryptedRefLength := hashSize + encryption.KeyLength + switch len(ref) { + case AddressLength: + return Address(ref), nil, nil + case encryptedRefLength: + encKeyIdx := len(ref) - encryption.KeyLength + return Address(ref[:encKeyIdx]), encryption.Key(ref[encKeyIdx:]), nil + default: + return nil, nil, fmt.Errorf("Invalid reference length, expected %v or %v got %v", hashSize, encryptedRefLength, len(ref)) + } +} diff --git a/swarm/storage/hasherstore_test.go b/swarm/storage/hasherstore_test.go new file mode 100644 index 0000000000..22cf98d0e8 --- /dev/null +++ b/swarm/storage/hasherstore_test.go @@ -0,0 +1,124 @@ +// 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 storage + +import ( + "bytes" + "context" + "testing" + + "github.com/ethereum/go-ethereum/swarm/storage/encryption" + + "github.com/ethereum/go-ethereum/common" +) + +func TestHasherStore(t *testing.T) { + var tests = []struct { + chunkLength int + toEncrypt bool + }{ + {10, false}, + {100, false}, + {1000, false}, + {4096, false}, + {10, true}, + {100, true}, + {1000, true}, + {4096, true}, + } + + for _, tt := range tests { + chunkStore := NewMapChunkStore() + hasherStore := NewHasherStore(chunkStore, MakeHashFunc(DefaultHash), tt.toEncrypt) + + // Put two random chunks into the hasherStore + chunkData1 := GenerateRandomChunk(int64(tt.chunkLength)).Data() + ctx, cancel := context.WithTimeout(context.Background(), getTimeout) + defer cancel() + key1, err := hasherStore.Put(ctx, chunkData1) + if err != nil { + t.Fatalf("Expected no error got \"%v\"", err) + } + + chunkData2 := GenerateRandomChunk(int64(tt.chunkLength)).Data() + key2, err := hasherStore.Put(ctx, chunkData2) + if err != nil { + t.Fatalf("Expected no error got \"%v\"", err) + } + + hasherStore.Close() + + // Wait until chunks are really stored + err = hasherStore.Wait(ctx) + if err != nil { + t.Fatalf("Expected no error got \"%v\"", err) + } + + // Get the first chunk + retrievedChunkData1, err := hasherStore.Get(ctx, key1) + if err != nil { + t.Fatalf("Expected no error, got \"%v\"", err) + } + + // Retrieved data should be same as the original + if !bytes.Equal(chunkData1, retrievedChunkData1) { + t.Fatalf("Expected retrieved chunk data %v, got %v", common.Bytes2Hex(chunkData1), common.Bytes2Hex(retrievedChunkData1)) + } + + // Get the second chunk + retrievedChunkData2, err := hasherStore.Get(ctx, key2) + if err != nil { + t.Fatalf("Expected no error, got \"%v\"", err) + } + + // Retrieved data should be same as the original + if !bytes.Equal(chunkData2, retrievedChunkData2) { + t.Fatalf("Expected retrieved chunk data %v, got %v", common.Bytes2Hex(chunkData2), common.Bytes2Hex(retrievedChunkData2)) + } + + hash1, encryptionKey1, err := parseReference(key1, hasherStore.hashSize) + if err != nil { + t.Fatalf("Expected no error, got \"%v\"", err) + } + + if tt.toEncrypt { + if encryptionKey1 == nil { + t.Fatal("Expected non-nil encryption key, got nil") + } else if len(encryptionKey1) != encryption.KeyLength { + t.Fatalf("Expected encryption key length %v, got %v", encryption.KeyLength, len(encryptionKey1)) + } + } + if !tt.toEncrypt && encryptionKey1 != nil { + t.Fatalf("Expected nil encryption key, got key with length %v", len(encryptionKey1)) + } + + // Check if chunk data in store is encrypted or not + chunkInStore, err := chunkStore.Get(ctx, hash1) + if err != nil { + t.Fatalf("Expected no error got \"%v\"", err) + } + + chunkDataInStore := chunkInStore.Data() + + if tt.toEncrypt && bytes.Equal(chunkData1, chunkDataInStore) { + t.Fatalf("Chunk expected to be encrypted but it is stored without encryption") + } + if !tt.toEncrypt && !bytes.Equal(chunkData1, chunkDataInStore) { + t.Fatalf("Chunk expected to be not encrypted but stored content is different. Expected %v got %v", common.Bytes2Hex(chunkData1), common.Bytes2Hex(chunkDataInStore)) + } + } +} diff --git a/swarm/storage/ldbstore.go b/swarm/storage/ldbstore.go new file mode 100644 index 0000000000..766a9e031b --- /dev/null +++ b/swarm/storage/ldbstore.go @@ -0,0 +1,1079 @@ +// 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 . + +// disk storage layer for the package bzz +// DbStore implements the ChunkStore interface and is used by the FileStore as +// persistent storage of chunks +// it implements purging based on access count allowing for external control of +// max capacity + +package storage + +import ( + "archive/tar" + "bytes" + "context" + "encoding/binary" + "encoding/hex" + "errors" + "fmt" + "io" + "io/ioutil" + "sync" + + "github.com/ethereum/go-ethereum/metrics" + "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/swarm/log" + "github.com/ethereum/go-ethereum/swarm/storage/mock" + "github.com/syndtr/goleveldb/leveldb" +) + +const ( + defaultGCRatio = 10 + defaultMaxGCRound = 10000 + defaultMaxGCBatch = 5000 + + wEntryCnt = 1 << 0 + wIndexCnt = 1 << 1 + wAccessCnt = 1 << 2 +) + +var ( + dbEntryCount = metrics.NewRegisteredCounter("ldbstore.entryCnt", nil) +) + +var ( + keyIndex = byte(0) + keyAccessCnt = []byte{2} + keyEntryCnt = []byte{3} + keyDataIdx = []byte{4} + keyData = byte(6) + keyDistanceCnt = byte(7) + keySchema = []byte{8} + keyGCIdx = byte(9) // access to chunk data index, used by garbage collection in ascending order from first entry +) + +var ( + ErrDBClosed = errors.New("LDBStore closed") +) + +type LDBStoreParams struct { + *StoreParams + Path string + Po func(Address) uint8 +} + +// NewLDBStoreParams constructs LDBStoreParams with the specified values. +func NewLDBStoreParams(storeparams *StoreParams, path string) *LDBStoreParams { + return &LDBStoreParams{ + StoreParams: storeparams, + Path: path, + Po: func(k Address) (ret uint8) { return uint8(Proximity(storeparams.BaseKey, k[:])) }, + } +} + +type garbage struct { + maxRound int // maximum number of chunks to delete in one garbage collection round + maxBatch int // maximum number of chunks to delete in one db request batch + ratio int // 1/x ratio to calculate the number of chunks to gc on a low capacity db + count int // number of chunks deleted in running round + target int // number of chunks to delete in running round + batch *dbBatch // the delete batch + runC chan struct{} // struct in chan means gc is NOT running +} + +type LDBStore struct { + db *LDBDatabase + + // this should be stored in db, accessed transactionally + entryCnt uint64 // number of items in the LevelDB + accessCnt uint64 // ever-accumulating number increased every time we read/access an entry + dataIdx uint64 // similar to entryCnt, but we only increment it + capacity uint64 + bucketCnt []uint64 + + hashfunc SwarmHasher + po func(Address) uint8 + + batchesC chan struct{} + closed bool + batch *dbBatch + lock sync.RWMutex + quit chan struct{} + gc *garbage + + // Functions encodeDataFunc is used to bypass + // the default functionality of DbStore with + // mock.NodeStore for testing purposes. + encodeDataFunc func(chunk Chunk) []byte + // If getDataFunc is defined, it will be used for + // retrieving the chunk data instead from the local + // LevelDB database. + getDataFunc func(key Address) (data []byte, err error) +} + +type dbBatch struct { + *leveldb.Batch + err error + c chan struct{} +} + +func newBatch() *dbBatch { + return &dbBatch{Batch: new(leveldb.Batch), c: make(chan struct{})} +} + +// TODO: Instead of passing the distance function, just pass the address from which distances are calculated +// to avoid the appearance of a pluggable distance metric and opportunities of bugs associated with providing +// a function different from the one that is actually used. +func NewLDBStore(params *LDBStoreParams) (s *LDBStore, err error) { + s = new(LDBStore) + s.hashfunc = params.Hash + s.quit = make(chan struct{}) + + s.batchesC = make(chan struct{}, 1) + go s.writeBatches() + s.batch = newBatch() + // associate encodeData with default functionality + s.encodeDataFunc = encodeData + + s.db, err = NewLDBDatabase(params.Path) + if err != nil { + return nil, err + } + + s.po = params.Po + s.setCapacity(params.DbCapacity) + + s.bucketCnt = make([]uint64, 0x100) + for i := 0; i < 0x100; i++ { + k := make([]byte, 2) + k[0] = keyDistanceCnt + k[1] = uint8(i) + cnt, _ := s.db.Get(k) + s.bucketCnt[i] = BytesToU64(cnt) + } + data, _ := s.db.Get(keyEntryCnt) + s.entryCnt = BytesToU64(data) + data, _ = s.db.Get(keyAccessCnt) + s.accessCnt = BytesToU64(data) + data, _ = s.db.Get(keyDataIdx) + s.dataIdx = BytesToU64(data) + + // set up garbage collection + s.gc = &garbage{ + maxBatch: defaultMaxGCBatch, + maxRound: defaultMaxGCRound, + ratio: defaultGCRatio, + } + + s.gc.runC = make(chan struct{}, 1) + s.gc.runC <- struct{}{} + + return s, nil +} + +// MarkAccessed increments the access counter as a best effort for a chunk, so +// the chunk won't get garbage collected. +func (s *LDBStore) MarkAccessed(addr Address) { + s.lock.Lock() + defer s.lock.Unlock() + + if s.closed { + return + } + + proximity := s.po(addr) + s.tryAccessIdx(addr, proximity) +} + +// initialize and set values for processing of gc round +func (s *LDBStore) startGC(c int) { + + s.gc.count = 0 + // calculate the target number of deletions + if c >= s.gc.maxRound { + s.gc.target = s.gc.maxRound + } else { + s.gc.target = c / s.gc.ratio + } + s.gc.batch = newBatch() + log.Debug("startgc", "requested", c, "target", s.gc.target) +} + +// NewMockDbStore creates a new instance of DbStore with +// mockStore set to a provided value. If mockStore argument is nil, +// this function behaves exactly as NewDbStore. +func NewMockDbStore(params *LDBStoreParams, mockStore *mock.NodeStore) (s *LDBStore, err error) { + s, err = NewLDBStore(params) + if err != nil { + return nil, err + } + + // replace put and get with mock store functionality + if mockStore != nil { + s.encodeDataFunc = newMockEncodeDataFunc(mockStore) + s.getDataFunc = newMockGetDataFunc(mockStore) + } + return +} + +type dpaDBIndex struct { + Idx uint64 + Access uint64 +} + +func BytesToU64(data []byte) uint64 { + if len(data) < 8 { + return 0 + } + return binary.BigEndian.Uint64(data) +} + +func U64ToBytes(val uint64) []byte { + data := make([]byte, 8) + binary.BigEndian.PutUint64(data, val) + return data +} + +func getIndexKey(hash Address) []byte { + hashSize := len(hash) + key := make([]byte, hashSize+1) + key[0] = keyIndex + copy(key[1:], hash[:]) + return key +} + +func getDataKey(idx uint64, po uint8) []byte { + key := make([]byte, 10) + key[0] = keyData + key[1] = po + binary.BigEndian.PutUint64(key[2:], idx) + + return key +} + +func getGCIdxKey(index *dpaDBIndex) []byte { + key := make([]byte, 9) + key[0] = keyGCIdx + binary.BigEndian.PutUint64(key[1:], index.Access) + return key +} + +func getGCIdxValue(index *dpaDBIndex, po uint8, addr Address) []byte { + val := make([]byte, 41) // po = 1, index.Index = 8, Address = 32 + val[0] = po + binary.BigEndian.PutUint64(val[1:], index.Idx) + copy(val[9:], addr) + return val +} + +func parseIdxKey(key []byte) (byte, []byte) { + return key[0], key[1:] +} + +func parseGCIdxEntry(accessCnt []byte, val []byte) (index *dpaDBIndex, po uint8, addr Address) { + index = &dpaDBIndex{ + Idx: binary.BigEndian.Uint64(val[1:]), + Access: binary.BigEndian.Uint64(accessCnt), + } + po = val[0] + addr = val[9:] + return +} + +func encodeIndex(index *dpaDBIndex) []byte { + data, _ := rlp.EncodeToBytes(index) + return data +} + +func encodeData(chunk Chunk) []byte { + // Always create a new underlying array for the returned byte slice. + // The chunk.Address array may be used in the returned slice which + // may be changed later in the code or by the LevelDB, resulting + // that the Address is changed as well. + return append(append([]byte{}, chunk.Address()[:]...), chunk.Data()...) +} + +func decodeIndex(data []byte, index *dpaDBIndex) error { + dec := rlp.NewStream(bytes.NewReader(data), 0) + return dec.Decode(index) +} + +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: + default: + return nil + } + + s.lock.Lock() + entryCnt := s.entryCnt + s.lock.Unlock() + + metrics.GetOrRegisterCounter("ldbstore.collectgarbage", nil).Inc(1) + + // calculate the amount of chunks to collect and reset counter + s.startGC(int(entryCnt)) + log.Debug("collectGarbage", "target", s.gc.target, "entryCnt", entryCnt) + + for s.gc.count < s.gc.target { + it := s.db.NewIterator() + ok := it.Seek([]byte{keyGCIdx}) + var singleIterationCount int + + // every batch needs a lock so we avoid entries changing accessidx in the meantime + s.lock.Lock() + for ; ok && (singleIterationCount < s.gc.maxBatch); ok = it.Next() { + + // quit if no more access index keys + itkey := it.Key() + if (itkey == nil) || (itkey[0] != keyGCIdx) { + break + } + + // get chunk data entry from access index + val := it.Value() + index, po, hash := parseGCIdxEntry(itkey[1:], val) + keyIdx := make([]byte, 33) + keyIdx[0] = keyIndex + copy(keyIdx[1:], hash) + + // add delete operation to batch + s.delete(s.gc.batch.Batch, index, keyIdx, po) + singleIterationCount++ + s.gc.count++ + log.Trace("garbage collect enqueued chunk for deletion", "key", hash) + + // break if target is not on max garbage batch boundary + if s.gc.count >= s.gc.target { + break + } + } + + s.writeBatch(s.gc.batch, wEntryCnt) + log.Trace("garbage collect batch done", "batch", singleIterationCount, "total", s.gc.count) + s.lock.Unlock() + it.Release() + } + + metrics.GetOrRegisterCounter("ldbstore.collectgarbage.delete", nil).Inc(int64(s.gc.count)) + log.Debug("garbage collect done", "c", s.gc.count) + s.gc.runC <- struct{}{} + + return nil +} + +// Export writes all chunks from the store to a tar archive, returning the +// number of chunks written. +func (s *LDBStore) Export(out io.Writer) (int64, error) { + tw := tar.NewWriter(out) + defer tw.Close() + + it := s.db.NewIterator() + defer it.Release() + var count int64 + for ok := it.Seek([]byte{keyIndex}); ok; ok = it.Next() { + key := it.Key() + if (key == nil) || (key[0] != keyIndex) { + break + } + + var index dpaDBIndex + + hash := key[1:] + decodeIndex(it.Value(), &index) + po := s.po(hash) + datakey := getDataKey(index.Idx, po) + log.Trace("store.export", "dkey", fmt.Sprintf("%x", datakey), "dataidx", index.Idx, "po", po) + data, err := s.db.Get(datakey) + if err != nil { + log.Warn(fmt.Sprintf("Chunk %x found but could not be accessed: %v", key, err)) + continue + } + + hdr := &tar.Header{ + Name: hex.EncodeToString(hash), + Mode: 0644, + Size: int64(len(data)), + } + if err := tw.WriteHeader(hdr); err != nil { + return count, err + } + if _, err := tw.Write(data); err != nil { + return count, err + } + count++ + } + + return count, nil +} + +// of chunks read. +func (s *LDBStore) Import(in io.Reader) (int64, error) { + tr := tar.NewReader(in) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + countC := make(chan int64) + errC := make(chan error) + var count int64 + go func() { + for { + hdr, err := tr.Next() + if err == io.EOF { + break + } else if err != nil { + select { + case errC <- err: + case <-ctx.Done(): + } + } + + if len(hdr.Name) != 64 { + log.Warn("ignoring non-chunk file", "name", hdr.Name) + continue + } + + keybytes, err := hex.DecodeString(hdr.Name) + if err != nil { + log.Warn("ignoring invalid chunk file", "name", hdr.Name, "err", err) + continue + } + + data, err := ioutil.ReadAll(tr) + if err != nil { + select { + case errC <- err: + case <-ctx.Done(): + } + } + key := Address(keybytes) + chunk := NewChunk(key, data[32:]) + + go func() { + select { + case errC <- s.Put(ctx, chunk): + case <-ctx.Done(): + } + }() + + count++ + } + countC <- count + }() + + // wait for all chunks to be stored + i := int64(0) + var total int64 + for { + select { + case err := <-errC: + if err != nil { + return count, err + } + i++ + case total = <-countC: + case <-ctx.Done(): + return i, ctx.Err() + } + if total > 0 && i == total { + return total, nil + } + } +} + +// Cleanup iterates over the database and deletes chunks if they pass the `f` condition +func (s *LDBStore) Cleanup(f func(Chunk) bool) { + var errorsFound, removed, total int + + it := s.db.NewIterator() + defer it.Release() + for ok := it.Seek([]byte{keyIndex}); ok; ok = it.Next() { + key := it.Key() + if (key == nil) || (key[0] != keyIndex) { + break + } + total++ + var index dpaDBIndex + err := decodeIndex(it.Value(), &index) + if err != nil { + log.Warn("Cannot decode") + errorsFound++ + continue + } + hash := key[1:] + po := s.po(hash) + datakey := getDataKey(index.Idx, po) + data, err := s.db.Get(datakey) + if err != nil { + found := false + + // 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 { + found = true + break + } + } + + if !found { + log.Warn(fmt.Sprintf("Chunk %x found but count not be accessed with any po", key)) + errorsFound++ + continue + } + } + + ck := data[:32] + c, err := decodeData(ck, data) + if err != nil { + log.Error("decodeData error", "err", err) + continue + } + + 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(sdata), "size", cs) + s.deleteNow(&index, getIndexKey(key[1:]), po) + removed++ + errorsFound++ + } + } + + log.Warn(fmt.Sprintf("Found %v errors out of %v entries. Removed %v chunks.", errorsFound, total, removed)) +} + +// CleanGCIndex rebuilds the garbage collector index from scratch, while +// removing inconsistent elements, e.g., indices with missing data chunks. +// WARN: it's a pretty heavy, long running function. +func (s *LDBStore) CleanGCIndex() error { + s.lock.Lock() + defer s.lock.Unlock() + + batch := leveldb.Batch{} + + var okEntryCount uint64 + var totalEntryCount uint64 + + // throw out all gc indices, we will rebuild from cleaned index + it := s.db.NewIterator() + it.Seek([]byte{keyGCIdx}) + var gcDeletes int + for it.Valid() { + rowType, _ := parseIdxKey(it.Key()) + if rowType != keyGCIdx { + break + } + batch.Delete(it.Key()) + gcDeletes++ + it.Next() + } + log.Debug("gc", "deletes", gcDeletes) + if err := s.db.Write(&batch); err != nil { + return err + } + 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 { + poKey[1] = uint8(i) + if poPtr == 0 { + batch.Delete(poKey[:]) + } else { + var idxCount [8]byte + binary.BigEndian.PutUint64(idxCount[:], poPtr) + batch.Put(poKey[:], idxCount[:]) + } + } + + // if you made it this far your harddisk has survived. Congratulations + return s.db.Write(&batch) +} + +// Delete is removes a chunk and updates indices. +// Is thread safe +func (s *LDBStore) Delete(addr Address) error { + s.lock.Lock() + defer s.lock.Unlock() + + ikey := getIndexKey(addr) + + idata, err := s.db.Get(ikey) + if err != nil { + return err + } + + var idx dpaDBIndex + decodeIndex(idata, &idx) + proximity := s.po(addr) + return s.deleteNow(&idx, ikey, proximity) +} + +// executes one delete operation immediately +// see *LDBStore.delete +func (s *LDBStore) deleteNow(idx *dpaDBIndex, idxKey []byte, po uint8) error { + batch := new(leveldb.Batch) + s.delete(batch, idx, idxKey, po) + return s.db.Write(batch) +} + +// adds a delete chunk operation to the provided batch +// if called directly, decrements entrycount regardless if the chunk exists upon deletion. Risk of wrap to max uint64 +func (s *LDBStore) delete(batch *leveldb.Batch, idx *dpaDBIndex, idxKey []byte, po uint8) { + metrics.GetOrRegisterCounter("ldbstore.delete", nil).Inc(1) + + gcIdxKey := getGCIdxKey(idx) + batch.Delete(gcIdxKey) + dataKey := getDataKey(idx.Idx, po) + batch.Delete(dataKey) + batch.Delete(idxKey) + s.entryCnt-- + dbEntryCount.Dec(1) + cntKey := make([]byte, 2) + cntKey[0] = keyDistanceCnt + cntKey[1] = po + batch.Put(keyEntryCnt, U64ToBytes(s.entryCnt)) + batch.Put(cntKey, U64ToBytes(s.bucketCnt[po])) +} + +func (s *LDBStore) BinIndex(po uint8) uint64 { + s.lock.RLock() + defer s.lock.RUnlock() + return s.bucketCnt[po] +} + +// 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 +func (s *LDBStore) Put(ctx context.Context, chunk Chunk) error { + metrics.GetOrRegisterCounter("ldbstore.put", nil).Inc(1) + log.Trace("ldbstore.put", "key", chunk.Address()) + + ikey := getIndexKey(chunk.Address()) + var index dpaDBIndex + + po := s.po(chunk.Address()) + + s.lock.Lock() + + if s.closed { + s.lock.Unlock() + return ErrDBClosed + } + batch := s.batch + + log.Trace("ldbstore.put: s.db.Get", "key", chunk.Address(), "ikey", fmt.Sprintf("%x", ikey)) + _, err := s.db.Get(ikey) + if err != nil { + s.doPut(chunk, &index, po) + } + idata := encodeIndex(&index) + s.batch.Put(ikey, idata) + + // add the access-chunkindex index for garbage collection + gcIdxKey := getGCIdxKey(&index) + gcIdxData := getGCIdxValue(&index, po, chunk.Address()) + s.batch.Put(gcIdxKey, gcIdxData) + s.lock.Unlock() + + select { + case s.batchesC <- struct{}{}: + default: + } + + select { + case <-batch.c: + return batch.err + case <-ctx.Done(): + return ctx.Err() + } +} + +// force putting into db, does not check or update necessary indices +func (s *LDBStore) doPut(chunk Chunk, index *dpaDBIndex, po uint8) { + data := s.encodeDataFunc(chunk) + dkey := getDataKey(s.dataIdx, po) + s.batch.Put(dkey, data) + index.Idx = s.dataIdx + s.bucketCnt[po] = s.dataIdx + s.entryCnt++ + dbEntryCount.Inc(1) + s.dataIdx++ + index.Access = s.accessCnt + s.accessCnt++ + cntKey := make([]byte, 2) + cntKey[0] = keyDistanceCnt + cntKey[1] = po + s.batch.Put(cntKey, U64ToBytes(s.bucketCnt[po])) +} + +func (s *LDBStore) writeBatches() { + for { + select { + case <-s.quit: + log.Debug("DbStore: quit batch write loop") + return + case <-s.batchesC: + err := s.writeCurrentBatch() + if err != nil { + log.Debug("DbStore: quit batch write loop", "err", err.Error()) + return + } + } + } + +} + +func (s *LDBStore) writeCurrentBatch() error { + s.lock.Lock() + defer s.lock.Unlock() + b := s.batch + l := b.Len() + if l == 0 { + return nil + } + s.batch = newBatch() + b.err = s.writeBatch(b, wEntryCnt|wAccessCnt|wIndexCnt) + close(b.c) + if s.entryCnt >= s.capacity { + go s.collectGarbage() + } + return nil +} + +// must be called non concurrently +func (s *LDBStore) writeBatch(b *dbBatch, wFlag uint8) error { + if wFlag&wEntryCnt > 0 { + b.Put(keyEntryCnt, U64ToBytes(s.entryCnt)) + } + if wFlag&wIndexCnt > 0 { + b.Put(keyDataIdx, U64ToBytes(s.dataIdx)) + } + if wFlag&wAccessCnt > 0 { + b.Put(keyAccessCnt, U64ToBytes(s.accessCnt)) + } + l := b.Len() + if err := s.db.Write(b.Batch); err != nil { + return fmt.Errorf("unable to write batch: %v", err) + } + log.Trace(fmt.Sprintf("batch write (%d entries)", l)) + return nil +} + +// newMockEncodeDataFunc returns a function that stores the chunk data +// to a mock store to bypass the default functionality encodeData. +// The constructed function always returns the nil data, as DbStore does +// not need to store the data, but still need to create the index. +func newMockEncodeDataFunc(mockStore *mock.NodeStore) func(chunk Chunk) []byte { + return func(chunk Chunk) []byte { + if err := mockStore.Put(chunk.Address(), encodeData(chunk)); err != nil { + log.Error(fmt.Sprintf("%T: Chunk %v put: %v", mockStore, chunk.Address().Log(), err)) + } + return chunk.Address()[:] + } +} + +// tryAccessIdx tries to find index entry. If found then increments the access +// count for garbage collection and returns the index entry and true for found, +// otherwise returns nil and false. +func (s *LDBStore) tryAccessIdx(addr Address, po uint8) (*dpaDBIndex, bool) { + ikey := getIndexKey(addr) + idata, err := s.db.Get(ikey) + if err != nil { + return nil, false + } + + index := new(dpaDBIndex) + decodeIndex(idata, index) + oldGCIdxKey := getGCIdxKey(index) + s.batch.Put(keyAccessCnt, U64ToBytes(s.accessCnt)) + index.Access = s.accessCnt + idata = encodeIndex(index) + s.accessCnt++ + s.batch.Put(ikey, idata) + newGCIdxKey := getGCIdxKey(index) + newGCIdxData := getGCIdxValue(index, po, ikey[1:]) + s.batch.Delete(oldGCIdxKey) + s.batch.Put(newGCIdxKey, newGCIdxData) + select { + case s.batchesC <- struct{}{}: + default: + } + return index, true +} + +// GetSchema is returning the current named schema of the datastore as read from LevelDB +func (s *LDBStore) GetSchema() (string, error) { + s.lock.Lock() + defer s.lock.Unlock() + + data, err := s.db.Get(keySchema) + if err != nil { + if err == leveldb.ErrNotFound { + return DbSchemaNone, nil + } + return "", err + } + + return string(data), nil +} + +// PutSchema is saving a named schema to the LevelDB datastore +func (s *LDBStore) PutSchema(schema string) error { + s.lock.Lock() + defer s.lock.Unlock() + + return s.db.Put(keySchema, []byte(schema)) +} + +// Get retrieves the chunk matching the provided key from the database. +// If the chunk entry does not exist, it returns an error +// Updates access count and is thread safe +func (s *LDBStore) Get(_ context.Context, addr Address) (chunk Chunk, err error) { + metrics.GetOrRegisterCounter("ldbstore.get", nil).Inc(1) + log.Trace("ldbstore.get", "key", addr) + + s.lock.Lock() + defer s.lock.Unlock() + 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) { + if s.closed { + return nil, ErrDBClosed + } + proximity := s.po(addr) + index, found := s.tryAccessIdx(addr, proximity) + if found { + var data []byte + if s.getDataFunc != nil { + // if getDataFunc is defined, use it to retrieve the chunk data + log.Trace("ldbstore.get retrieve with getDataFunc", "key", addr) + data, err = s.getDataFunc(addr) + if err != nil { + return + } + } else { + // default DbStore functionality to retrieve chunk data + datakey := getDataKey(index.Idx, proximity) + data, err = s.db.Get(datakey) + log.Trace("ldbstore.get retrieve", "key", addr, "indexkey", index.Idx, "datakey", fmt.Sprintf("%x", datakey), "proximity", proximity) + 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 + } + } + + return decodeData(addr, data) + } else { + err = ErrChunkNotFound + } + + return +} + +// newMockGetFunc returns a function that reads chunk data from +// the mock database, which is used as the value for DbStore.getFunc +// to bypass the default functionality of DbStore with a mock store. +func newMockGetDataFunc(mockStore *mock.NodeStore) func(addr Address) (data []byte, err error) { + return func(addr Address) (data []byte, err error) { + data, err = mockStore.Get(addr) + if err == mock.ErrNotFound { + // preserve ErrChunkNotFound error + err = ErrChunkNotFound + } + return data, err + } +} + +func (s *LDBStore) setCapacity(c uint64) { + s.lock.Lock() + defer s.lock.Unlock() + + s.capacity = c + + for s.entryCnt > c { + s.collectGarbage() + } +} + +func (s *LDBStore) Close() { + close(s.quit) + s.lock.Lock() + s.closed = true + s.lock.Unlock() + // force writing out current batch + s.writeCurrentBatch() + s.db.Close() +} + +// SyncIterator(start, stop, po, f) calls f on each hash of a bin po from start to stop +func (s *LDBStore) SyncIterator(since uint64, until uint64, po uint8, f func(Address, uint64) bool) error { + metrics.GetOrRegisterCounter("ldbstore.synciterator", nil).Inc(1) + + sincekey := getDataKey(since, po) + untilkey := getDataKey(until, po) + it := s.db.NewIterator() + defer it.Release() + + for ok := it.Seek(sincekey); ok; ok = it.Next() { + metrics.GetOrRegisterCounter("ldbstore.synciterator.seek", nil).Inc(1) + + dbkey := it.Key() + if dbkey[0] != keyData || dbkey[1] != po || bytes.Compare(untilkey, dbkey) < 0 { + break + } + key := make([]byte, 32) + val := it.Value() + copy(key, val[:32]) + if !f(Address(key), binary.BigEndian.Uint64(dbkey[2:])) { + break + } + } + return it.Error() +} diff --git a/swarm/storage/ldbstore_test.go b/swarm/storage/ldbstore_test.go new file mode 100644 index 0000000000..d17bd7d0e4 --- /dev/null +++ b/swarm/storage/ldbstore_test.go @@ -0,0 +1,777 @@ +// 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 storage + +import ( + "bytes" + "context" + "encoding/binary" + "fmt" + "io/ioutil" + "os" + "strconv" + "strings" + "testing" + + "github.com/ethereum/go-ethereum/common" + "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" +) + +type testDbStore struct { + *LDBStore + dir string +} + +func newTestDbStore(mock bool, trusted bool) (*testDbStore, func(), error) { + dir, err := ioutil.TempDir("", "bzz-storage-test") + if err != nil { + return nil, func() {}, err + } + + var db *LDBStore + storeparams := NewDefaultStoreParams() + params := NewLDBStoreParams(storeparams, dir) + params.Po = testPoFunc + + if mock { + globalStore := mem.NewGlobalStore() + addr := common.HexToAddress("0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed") + mockStore := globalStore.NewNodeStore(addr) + + db, err = NewMockDbStore(params, mockStore) + } else { + db, err = NewLDBStore(params) + } + + cleanup := func() { + if db != nil { + db.Close() + } + err = os.RemoveAll(dir) + if err != nil { + panic(fmt.Sprintf("db cleanup failed: %v", err)) + } + } + + return &testDbStore{db, dir}, cleanup, err +} + +func testPoFunc(k Address) (ret uint8) { + basekey := make([]byte, 32) + return uint8(Proximity(basekey, k[:])) +} + +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, 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, t) +} + +func TestMarkAccessed(t *testing.T) { + db, cleanup, err := newTestDbStore(false, true) + defer cleanup() + if err != nil { + t.Fatalf("init dbStore failed: %v", err) + } + + h := GenerateRandomChunk(chunk.DefaultSize) + + db.Put(context.Background(), h) + + var index dpaDBIndex + addr := h.Address() + idxk := getIndexKey(addr) + + idata, err := db.db.Get(idxk) + if err != nil { + t.Fatal(err) + } + decodeIndex(idata, &index) + + if index.Access != 0 { + t.Fatalf("Expected the access index to be %d, but it is %d", 0, index.Access) + } + + db.MarkAccessed(addr) + db.writeCurrentBatch() + + idata, err = db.db.Get(idxk) + if err != nil { + t.Fatal(err) + } + decodeIndex(idata, &index) + + if index.Access != 1 { + t.Fatalf("Expected the access index to be %d, but it is %d", 1, index.Access) + } + +} + +func TestDbStoreRandom_1(t *testing.T) { + testDbStoreRandom(1, false, t) +} + +func TestDbStoreCorrect_1(t *testing.T) { + testDbStoreCorrect(1, false, t) +} + +func TestDbStoreRandom_1k(t *testing.T) { + testDbStoreRandom(1000, false, t) +} + +func TestDbStoreCorrect_1k(t *testing.T) { + testDbStoreCorrect(1000, false, t) +} + +func TestMockDbStoreRandom_1(t *testing.T) { + testDbStoreRandom(1, true, t) +} + +func TestMockDbStoreCorrect_1(t *testing.T) { + testDbStoreCorrect(1, true, t) +} + +func TestMockDbStoreRandom_1k(t *testing.T) { + testDbStoreRandom(1000, true, t) +} + +func TestMockDbStoreCorrect_1k(t *testing.T) { + testDbStoreCorrect(1000, true, t) +} + +func testDbStoreNotFound(t *testing.T, mock bool) { + db, cleanup, err := newTestDbStore(mock, false) + defer cleanup() + if err != nil { + t.Fatalf("init dbStore failed: %v", err) + } + + _, err = db.Get(context.TODO(), ZeroAddr) + if err != ErrChunkNotFound { + t.Errorf("Expected ErrChunkNotFound, got %v", err) + } +} + +func TestDbStoreNotFound(t *testing.T) { + testDbStoreNotFound(t, false) +} +func TestMockDbStoreNotFound(t *testing.T) { + testDbStoreNotFound(t, true) +} + +func testIterator(t *testing.T, mock bool) { + var i int + var poc uint + chunkcount := 32 + chunkkeys := NewAddressCollection(chunkcount) + chunkkeysResults := NewAddressCollection(chunkcount) + + db, cleanup, err := newTestDbStore(mock, false) + defer cleanup() + if err != nil { + t.Fatalf("init dbStore failed: %v", err) + } + + chunks := GenerateRandomChunks(chunk.DefaultSize, chunkcount) + + for i = 0; i < len(chunks); i++ { + chunkkeys[i] = chunks[i].Address() + err := db.Put(context.TODO(), chunks[i]) + if err != nil { + t.Fatalf("dbStore.Put failed: %v", err) + } + } + + for i = 0; i < len(chunkkeys); i++ { + log.Trace(fmt.Sprintf("Chunk array pos %d/%d: '%v'", i, chunkcount, chunkkeys[i])) + } + i = 0 + 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))) + chunkkeysResults[n] = k + i++ + return true + }) + if err != nil { + t.Fatalf("Iterator call failed: %v", err) + } + } + + for i = 0; i < chunkcount; 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]) + } + } + +} + +func TestIterator(t *testing.T) { + testIterator(t, false) +} +func TestMockIterator(t *testing.T) { + testIterator(t, true) +} + +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, 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, b) +} + +func BenchmarkDbStorePut_500(b *testing.B) { + benchmarkDbStorePut(500, false, b) +} + +func BenchmarkDbStoreGet_500(b *testing.B) { + benchmarkDbStoreGet(500, false, b) +} + +func BenchmarkMockDbStorePut_500(b *testing.B) { + benchmarkDbStorePut(500, 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 +// retrieve them, provided we don't hit the garbage collection +func TestLDBStoreWithoutCollectGarbage(t *testing.T) { + capacity := 50 + n := 10 + + ldb, cleanup := newLDBStore(t) + ldb.setCapacity(uint64(capacity)) + defer cleanup() + + chunks, err := mputRandomChunks(ldb, n) + if err != nil { + t.Fatal(err.Error()) + } + + log.Info("ldbstore", "entrycnt", ldb.entryCnt, "accesscnt", ldb.accessCnt) + + for _, ch := range chunks { + ret, err := ldb.Get(context.TODO(), ch.Address()) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(ret.Data(), ch.Data()) { + t.Fatal("expected to get the same data back, but got smth else") + } + } + + if ldb.entryCnt != uint64(n) { + t.Fatalf("expected entryCnt to be equal to %v, but got %v", n, ldb.entryCnt) + } + + if ldb.accessCnt != uint64(2*n) { + t.Fatalf("expected accessCnt to be equal to %v, but got %v", 2*n, ldb.accessCnt) + } +} + +// TestLDBStoreCollectGarbage tests that we can put more chunks than LevelDB's capacity, and +// retrieve only some of them, because garbage collection must have partially cleared the store +// Also tests that we can delete chunks and that we can trigger garbage collection +func TestLDBStoreCollectGarbage(t *testing.T) { + + // below max ronud + 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 = 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 = initialCap + 500 + t.Run(fmt.Sprintf("A/%d/%d", cap, cap*4), testLDBStoreCollectGarbage) + t.Run(fmt.Sprintf("B/%d/%d", cap, cap*4), testLDBStoreRemoveThenCollectGarbage) + +} + +func testLDBStoreCollectGarbage(t *testing.T) { + params := strings.Split(t.Name(), "/") + capacity, err := strconv.Atoi(params[2]) + if err != nil { + t.Fatal(err) + } + n, err := strconv.Atoi(params[3]) + if err != nil { + t.Fatal(err) + } + + ldb, cleanup := newLDBStore(t) + ldb.setCapacity(uint64(capacity)) + defer cleanup() + + // retrieve the gc round target count for the db capacity + ldb.startGC(capacity) + roundTarget := ldb.gc.target + + // split put counts to gc target count threshold, and wait for gc to finish in between + var allChunks []Chunk + remaining := n + for remaining > 0 { + var putCount int + if remaining < roundTarget { + putCount = remaining + } else { + putCount = roundTarget + } + remaining -= putCount + 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() + + waitGc(ldb) + } + + // attempt gets on all put chunks + var missing int + for _, ch := range allChunks { + ret, err := ldb.Get(context.TODO(), ch.Address()) + if err == ErrChunkNotFound || err == ldberrors.ErrNotFound { + missing++ + continue + } + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(ret.Data(), ch.Data()) { + t.Fatal("expected to get the same data back, but got smth else") + } + + log.Trace("got back chunk", "chunk", ret) + } + + // all surplus chunks should be missing + expectMissing := roundTarget + (((n - capacity) / roundTarget) * roundTarget) + if missing != expectMissing { + t.Fatalf("gc failure: expected to miss %v chunks, but only %v are actually missing", expectMissing, missing) + } + + log.Info("ldbstore", "total", n, "missing", missing, "entrycnt", ldb.entryCnt, "accesscnt", ldb.accessCnt) +} + +// TestLDBStoreAddRemove tests that we can put and then delete a given chunk +func TestLDBStoreAddRemove(t *testing.T) { + ldb, cleanup := newLDBStore(t) + ldb.setCapacity(200) + defer cleanup() + + n := 100 + chunks, err := mputRandomChunks(ldb, n) + if err != nil { + t.Fatalf(err.Error()) + } + + for i := 0; i < n; i++ { + // delete all even index chunks + if i%2 == 0 { + ldb.Delete(chunks[i].Address()) + } + } + + log.Info("ldbstore", "entrycnt", ldb.entryCnt, "accesscnt", ldb.accessCnt) + + for i := 0; i < n; i++ { + ret, err := ldb.Get(context.TODO(), chunks[i].Address()) + + if i%2 == 0 { + // expect even chunks to be missing + if err == nil { + t.Fatal("expected chunk to be missing, but got no error") + } + } else { + // expect odd chunks to be retrieved successfully + if err != nil { + t.Fatalf("expected no error, but got %s", err) + } + + if !bytes.Equal(ret.Data(), chunks[i].Data()) { + t.Fatal("expected to get the same data back, but got smth else") + } + } + } +} + +func testLDBStoreRemoveThenCollectGarbage(t *testing.T) { + t.Skip("flaky with -race flag") + + params := strings.Split(t.Name(), "/") + capacity, err := strconv.Atoi(params[2]) + if err != nil { + t.Fatal(err) + } + n, err := strconv.Atoi(params[3]) + if err != nil { + t.Fatal(err) + } + + ldb, cleanup := newLDBStore(t) + defer cleanup() + ldb.setCapacity(uint64(capacity)) + + // put capacity count number of chunks + chunks := make([]Chunk, n) + for i := 0; i < n; i++ { + c := GenerateRandomChunk(chunk.DefaultSize) + chunks[i] = c + log.Trace("generate random chunk", "idx", i, "chunk", c) + } + + for i := 0; i < n; i++ { + err := ldb.Put(context.TODO(), chunks[i]) + if err != nil { + t.Fatal(err) + } + } + + waitGc(ldb) + + // delete all chunks + // (only count the ones actually deleted, the rest will have been gc'd) + deletes := 0 + for i := 0; i < n; i++ { + if ldb.Delete(chunks[i].Address()) == nil { + deletes++ + } + } + + log.Info("ldbstore", "entrycnt", ldb.entryCnt, "accesscnt", ldb.accessCnt) + + if ldb.entryCnt != 0 { + t.Fatalf("ldb.entrCnt expected 0 got %v", ldb.entryCnt) + } + + // the manual deletes will have increased accesscnt, so we need to add this when we verify the current count + expAccessCnt := uint64(n) + if ldb.accessCnt != expAccessCnt { + t.Fatalf("ldb.accessCnt expected %v got %v", expAccessCnt, ldb.accessCnt) + } + + // retrieve the gc round target count for the db capacity + ldb.startGC(capacity) + roundTarget := ldb.gc.target + + remaining := n + var puts int + for remaining > 0 { + var putCount int + if remaining < roundTarget { + putCount = remaining + } else { + putCount = roundTarget + } + 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-- + } + + waitGc(ldb) + } + + // expect first surplus chunks to be missing, because they have the smallest access value + expectMissing := roundTarget + (((n - capacity) / roundTarget) * roundTarget) + for i := 0; i < expectMissing; i++ { + _, err := ldb.Get(context.TODO(), chunks[i].Address()) + if err == nil { + t.Fatalf("expected surplus chunk %d to be missing, but got no error", i) + } + } + + // expect last chunks to be present, as they have the largest access value + for i := expectMissing; i < n; i++ { + ret, err := ldb.Get(context.TODO(), chunks[i].Address()) + if err != nil { + t.Fatalf("chunk %v: expected no error, but got %s", i, err) + } + if !bytes.Equal(ret.Data(), chunks[i].Data()) { + t.Fatal("expected to get the same data back, but got smth else") + } + } +} + +// TestLDBStoreCollectGarbageAccessUnlikeIndex tests garbage collection where accesscount differs from indexcount +func TestLDBStoreCollectGarbageAccessUnlikeIndex(t *testing.T) { + + capacity := defaultMaxGCRound / 100 * 2 + n := capacity - 1 + + ldb, cleanup := newLDBStore(t) + ldb.setCapacity(uint64(capacity)) + defer cleanup() + + chunks, err := mputRandomChunks(ldb, n) + if err != nil { + t.Fatal(err.Error()) + } + log.Info("ldbstore", "entrycnt", ldb.entryCnt, "accesscnt", ldb.accessCnt) + + // set first added capacity/2 chunks to highest accesscount + for i := 0; i < capacity/2; i++ { + _, err := ldb.Get(context.TODO(), chunks[i].Address()) + if err != nil { + t.Fatalf("fail add chunk #%d - %s: %v", i, chunks[i].Address(), err) + } + } + _, err = mputRandomChunks(ldb, 2) + if err != nil { + t.Fatal(err.Error()) + } + + // wait for garbage collection to kick in on the responsible actor + waitGc(ldb) + + var missing int + for i, ch := range chunks[2 : capacity/2] { + ret, err := ldb.Get(context.TODO(), ch.Address()) + if err == ErrChunkNotFound || err == ldberrors.ErrNotFound { + t.Fatalf("fail find chunk #%d - %s: %v", i, ch.Address(), err) + } + + if !bytes.Equal(ret.Data(), ch.Data()) { + t.Fatal("expected to get the same data back, but got smth else") + } + log.Trace("got back chunk", "chunk", ret) + } + + log.Info("ldbstore", "total", n, "missing", missing, "entrycnt", ldb.entryCnt, "accesscnt", ldb.accessCnt) +} + +func TestCleanIndex(t *testing.T) { + capacity := 5000 + n := 3 + + ldb, cleanup := newLDBStore(t) + ldb.setCapacity(uint64(capacity)) + defer cleanup() + + chunks, err := mputRandomChunks(ldb, n) + if err != nil { + t.Fatal(err) + } + + // remove the data of the first chunk + po := ldb.po(chunks[0].Address()[:]) + dataKey := make([]byte, 10) + dataKey[0] = keyData + dataKey[1] = byte(po) + // dataKey[2:10] = first chunk has storageIdx 0 on [2:10] + if _, err := ldb.db.Get(dataKey); err != nil { + t.Fatal(err) + } + if err := ldb.db.Delete(dataKey); err != nil { + t.Fatal(err) + } + + // remove the gc index row for the first chunk + gcFirstCorrectKey := make([]byte, 9) + gcFirstCorrectKey[0] = keyGCIdx + if err := ldb.db.Delete(gcFirstCorrectKey); err != nil { + t.Fatal(err) + } + + // warp the gc data of the second chunk + // this data should be correct again after the clean + gcSecondCorrectKey := make([]byte, 9) + gcSecondCorrectKey[0] = keyGCIdx + binary.BigEndian.PutUint64(gcSecondCorrectKey[1:], uint64(1)) + gcSecondCorrectVal, err := ldb.db.Get(gcSecondCorrectKey) + if err != nil { + t.Fatal(err) + } + warpedGCVal := make([]byte, len(gcSecondCorrectVal)+1) + copy(warpedGCVal[1:], gcSecondCorrectVal) + if err := ldb.db.Delete(gcSecondCorrectKey); err != nil { + t.Fatal(err) + } + if err := ldb.db.Put(gcSecondCorrectKey, warpedGCVal); err != nil { + t.Fatal(err) + } + + if err := ldb.CleanGCIndex(); err != nil { + t.Fatal(err) + } + + // the index without corresponding data should have been deleted + idxKey := make([]byte, 33) + idxKey[0] = keyIndex + copy(idxKey[1:], chunks[0].Address()) + if _, err := ldb.db.Get(idxKey); err == nil { + t.Fatalf("expected chunk 0 idx to be pruned: %v", idxKey) + } + + // the two other indices should be present + copy(idxKey[1:], chunks[1].Address()) + if _, err := ldb.db.Get(idxKey); err != nil { + t.Fatalf("expected chunk 1 idx to be present: %v", idxKey) + } + + copy(idxKey[1:], chunks[2].Address()) + if _, err := ldb.db.Get(idxKey); err != nil { + t.Fatalf("expected chunk 2 idx to be present: %v", idxKey) + } + + // first gc index should still be gone + if _, err := ldb.db.Get(gcFirstCorrectKey); err == nil { + t.Fatalf("expected gc 0 idx to be pruned: %v", idxKey) + } + + // second gc index should still be fixed + if _, err := ldb.db.Get(gcSecondCorrectKey); err != nil { + t.Fatalf("expected gc 1 idx to be present: %v", idxKey) + } + + // third gc index should be unchanged + binary.BigEndian.PutUint64(gcSecondCorrectKey[1:], uint64(2)) + if _, err := ldb.db.Get(gcSecondCorrectKey); err != nil { + t.Fatalf("expected gc 2 idx to be present: %v", idxKey) + } + + c, err := ldb.db.Get(keyEntryCnt) + if err != nil { + t.Fatalf("expected gc 2 idx to be present: %v", idxKey) + } + + // entrycount should now be one less + entryCount := binary.BigEndian.Uint64(c) + if entryCount != 2 { + t.Fatalf("expected entrycnt to be 2, was %d", c) + } + + // the chunks might accidentally be in the same bin + // if so that bin counter will now be 2 - the highest added index. + // if not, the total of them will be 3 + poBins := []uint8{ldb.po(chunks[1].Address()), ldb.po(chunks[2].Address())} + if poBins[0] == poBins[1] { + poBins = poBins[:1] + } + + var binTotal uint64 + var currentBin [2]byte + currentBin[0] = keyDistanceCnt + if len(poBins) == 1 { + currentBin[1] = poBins[0] + c, err := ldb.db.Get(currentBin[:]) + if err != nil { + t.Fatalf("expected gc 2 idx to be present: %v", idxKey) + } + binCount := binary.BigEndian.Uint64(c) + if binCount != 2 { + t.Fatalf("expected entrycnt to be 2, was %d", binCount) + } + } else { + for _, bin := range poBins { + currentBin[1] = bin + c, err := ldb.db.Get(currentBin[:]) + if err != nil { + t.Fatalf("expected gc 2 idx to be present: %v", idxKey) + } + binCount := binary.BigEndian.Uint64(c) + binTotal += binCount + + } + if binTotal != 3 { + 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) + } +} + +// 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/swarm/storage/localstore.go b/swarm/storage/localstore.go index b442e6cc54..a8f6f037f6 100644 --- a/swarm/storage/localstore.go +++ b/swarm/storage/localstore.go @@ -17,61 +17,235 @@ package storage import ( - "encoding/binary" + "context" + "path/filepath" + "sync" + + "github.com/ethereum/go-ethereum/metrics" + "github.com/ethereum/go-ethereum/swarm/log" + "github.com/ethereum/go-ethereum/swarm/storage/mock" ) +type LocalStoreParams struct { + *StoreParams + ChunkDbPath string + Validators []ChunkValidator `toml:"-"` +} + +func NewDefaultLocalStoreParams() *LocalStoreParams { + return &LocalStoreParams{ + StoreParams: NewDefaultStoreParams(), + } +} + +//this can only finally be set after all config options (file, cmd line, env vars) +//have been evaluated +func (p *LocalStoreParams) Init(path string) { + if p.ChunkDbPath == "" { + p.ChunkDbPath = filepath.Join(path, "chunks") + } +} + // LocalStore is a combination of inmemory db over a disk persisted db // implements a Get/Put with fallback (caching) logic using any 2 ChunkStores type LocalStore struct { - memStore ChunkStore - DbStore ChunkStore + Validators []ChunkValidator + memStore *MemStore + DbStore *LDBStore + mu sync.Mutex } // This constructor uses MemStore and DbStore as components -func NewLocalStore(hash SwarmHasher, params *StoreParams) (*LocalStore, error) { - dbStore, err := NewDbStore(params.ChunkDbPath, hash, params.DbCapacity, params.Radius) +func NewLocalStore(params *LocalStoreParams, mockStore *mock.NodeStore) (*LocalStore, error) { + ldbparams := NewLDBStoreParams(params.StoreParams, params.ChunkDbPath) + dbStore, err := NewMockDbStore(ldbparams, mockStore) if err != nil { return nil, err } return &LocalStore{ - memStore: NewMemStore(dbStore, params.CacheCapacity), - DbStore: dbStore, + memStore: NewMemStore(params.StoreParams, dbStore), + DbStore: dbStore, + Validators: params.Validators, }, nil } -// LocalStore is itself a chunk store -// unsafe, in that the data is not integrity checked -func (self *LocalStore) Put(chunk *Chunk) { - chunk.dbStored = make(chan bool) - self.memStore.Put(chunk) - if chunk.wg != nil { - chunk.wg.Add(1) +func NewTestLocalStoreForAddr(params *LocalStoreParams) (*LocalStore, error) { + ldbparams := NewLDBStoreParams(params.StoreParams, params.ChunkDbPath) + dbStore, err := NewLDBStore(ldbparams) + if err != nil { + return nil, err } - go func() { - self.DbStore.Put(chunk) - if chunk.wg != nil { - chunk.wg.Done() + localStore := &LocalStore{ + memStore: NewMemStore(params.StoreParams, dbStore), + DbStore: dbStore, + Validators: params.Validators, + } + return localStore, nil +} + +// isValid returns true if chunk passes any of the LocalStore Validators. +// isValid also returns true if LocalStore has no Validators. +func (ls *LocalStore) isValid(chunk Chunk) bool { + // by default chunks are valid. if we have 0 validators, then all chunks are valid. + valid := true + + // 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); valid { + break } - }() + } + return valid +} + +// Put is responsible for doing validation and storage of the chunk +// by using configured ChunkValidators, MemStore and LDBStore. +// If the chunk is not valid, its GetErrored function will +// return ErrChunkInvalid. +// This method will check if the chunk is already in the MemStore +// and it will return it if it is. If there is an error from +// the MemStore.Get, it will be returned by calling GetErrored +// on the chunk. +// This method is responsible for closing Chunk.ReqC channel +// when the chunk is stored in memstore. +// After the LDBStore.Put, it is ensured that the MemStore +// contains the chunk with the same data, but nil ReqC channel. +func (ls *LocalStore) Put(ctx context.Context, chunk Chunk) error { + if !ls.isValid(chunk) { + return ErrChunkInvalid + } + + log.Trace("localstore.put", "key", chunk.Address()) + ls.mu.Lock() + defer ls.mu.Unlock() + + _, err := ls.memStore.Get(ctx, chunk.Address()) + if err == nil { + return nil + } + if err != nil && err != ErrChunkNotFound { + return err + } + ls.memStore.Put(ctx, chunk) + err = ls.DbStore.Put(ctx, chunk) + 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 // ChunkStores are remote and can have long latency -func (self *LocalStore) Get(key Key) (chunk *Chunk, err error) { - chunk, err = self.memStore.Get(key) - if err == nil { - return - } - chunk, err = self.DbStore.Get(key) - if err != nil { - return - } - chunk.Size = int64(binary.LittleEndian.Uint64(chunk.SData[0:8])) - self.memStore.Put(chunk) - return +func (ls *LocalStore) Get(ctx context.Context, addr Address) (chunk Chunk, err error) { + ls.mu.Lock() + defer ls.mu.Unlock() + + return ls.get(ctx, addr) } -// Close local store -func (self *LocalStore) Close() {} +func (ls *LocalStore) get(ctx context.Context, addr Address) (chunk Chunk, err error) { + chunk, err = ls.memStore.Get(ctx, addr) + + if err != nil && err != ErrChunkNotFound { + metrics.GetOrRegisterCounter("localstore.get.error", nil).Inc(1) + return nil, err + } + + if err == nil { + metrics.GetOrRegisterCounter("localstore.get.cachehit", nil).Inc(1) + go ls.DbStore.MarkAccessed(addr) + return chunk, nil + } + + metrics.GetOrRegisterCounter("localstore.get.cachemiss", nil).Inc(1) + chunk, err = ls.DbStore.Get(ctx, addr) + if err != nil { + metrics.GetOrRegisterCounter("localstore.get.error", nil).Inc(1) + return nil, err + } + + ls.memStore.Put(ctx, chunk) + return chunk, nil +} + +func (ls *LocalStore) FetchFunc(ctx context.Context, addr Address) func(context.Context) error { + ls.mu.Lock() + defer ls.mu.Unlock() + + _, err := ls.get(ctx, addr) + if err == nil { + return nil + } + return func(context.Context) error { + return err + } +} + +func (ls *LocalStore) BinIndex(po uint8) uint64 { + return ls.DbStore.BinIndex(po) +} + +func (ls *LocalStore) Iterator(from uint64, to uint64, po uint8, f func(Address, uint64) bool) error { + return ls.DbStore.SyncIterator(from, to, po, f) +} + +// Close the local store +func (ls *LocalStore) Close() { + ls.DbStore.Close() +} + +// 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 { + log.Error(err.Error()) + return err + } + + if actualDbSchema == CurrentDbSchema { + return nil + } + + log.Debug("running migrations for", "schema", actualDbSchema, "runtime-schema", CurrentDbSchema) + + if actualDbSchema == DbSchemaNone { + ls.migrateFromNoneToPurity() + actualDbSchema = DbSchemaPurity + } + + if err := ls.DbStore.PutSchema(actualDbSchema); err != nil { + return err + } + + if actualDbSchema == DbSchemaPurity { + if err := ls.migrateFromPurityToHalloween(); err != nil { + return err + } + actualDbSchema = DbSchemaHalloween + } + + if err := ls.DbStore.PutSchema(actualDbSchema); err != nil { + return err + } + return nil +} + +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 { + return !ls.isValid(c) + }) +} + +func (ls *LocalStore) migrateFromPurityToHalloween() error { + return ls.DbStore.CleanGCIndex() +} diff --git a/swarm/storage/localstore/doc.go b/swarm/storage/localstore/doc.go new file mode 100644 index 0000000000..98f6fc40aa --- /dev/null +++ b/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/swarm/storage/localstore/gc.go b/swarm/storage/localstore/gc.go new file mode 100644 index 0000000000..ebaba2d8f3 --- /dev/null +++ b/swarm/storage/localstore/gc.go @@ -0,0 +1,306 @@ +// 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 . + +/* +Counting number of items in garbage collection index + +The number of items in garbage collection index is not the same as the number of +chunks in retrieval index (total number of stored chunks). Chunk can be garbage +collected only when it is set to a synced state by ModSetSync, and only then can +be counted into garbage collection size, which determines whether a number of +chunk should be removed from the storage by the garbage collection. This opens a +possibility that the storage size exceeds the limit if files are locally +uploaded and the node is not connected to other nodes or there is a problem with +syncing. + +Tracking of garbage collection size (gcSize) is focused on performance. Key +points: + + 1. counting the number of key/value pairs in LevelDB takes around 0.7s for 1e6 + on a very fast ssd (unacceptable long time in reality) + 2. locking leveldb batch writes with a global mutex (serial batch writes) is + not acceptable, we should use locking per chunk address + +Because of point 1. we cannot count the number of items in garbage collection +index in New constructor as it could last very long for realistic scenarios +where limit is 5e6 and nodes are running on slower hdd disks or cloud providers +with low IOPS. + +Point 2. is a performance optimization to allow parallel batch writes with +getters, putters and setters. Every single batch that they create contain only +information related to a single chunk, no relations with other chunks or shared +statistical data (like gcSize). This approach avoids race conditions on writing +batches in parallel, but creates a problem of synchronizing statistical data +values like gcSize. With global mutex lock, any data could be written by any +batch, but would not use utilize the full potential of leveldb parallel writes. + +To mitigate this two problems, the implementation of counting and persisting +gcSize is split into two parts. One is the in-memory value (gcSize) that is fast +to read and write with a dedicated mutex (gcSizeMu) if the batch which adds or +removes items from garbage collection index is successful. The second part is +the reliable persistence of this value to leveldb database, as storedGCSize +field. This database field is saved by writeGCSizeWorker and writeGCSize +functions when in-memory gcSize variable is changed, but no too often to avoid +very frequent database writes. This database writes are triggered by +writeGCSizeTrigger when a call is made to function incGCSize. Trigger ensures +that no database writes are done only when gcSize is changed (contrary to a +simpler periodic writes or checks). A backoff of 10s in writeGCSizeWorker +ensures that no frequent batch writes are made. Saving the storedGCSize on +database Close function ensures that in-memory gcSize is persisted when database +is closed. + +This persistence must be resilient to failures like panics. For this purpose, a +collection of hashes that are added to the garbage collection index, but still +not persisted to storedGCSize, must be tracked to count them in when DB is +constructed again with New function after the failure (swarm node restarts). On +every batch write that adds a new item to garbage collection index, the same +hash is added to gcUncountedHashesIndex. This ensures that there is a persisted +information which hashes were added to the garbage collection index. But, when +the storedGCSize is saved by writeGCSize function, this values are removed in +the same batch in which storedGCSize is changed to ensure consistency. When the +panic happen, or database Close method is not saved. The database storage +contains all information to reliably and efficiently get the correct number of +items in garbage collection index. This is performed in the New function when +all hashes in gcUncountedHashesIndex are counted, added to the storedGCSize and +saved to the disk before the database is constructed again. Index +gcUncountedHashesIndex is acting as dirty bit for recovery that provides +information what needs to be corrected. With a simple dirty bit, the whole +garbage collection index should me counted on recovery instead only the items in +gcUncountedHashesIndex. Because of the triggering mechanizm of writeGCSizeWorker +and relatively short backoff time, the number of hashes in +gcUncountedHashesIndex should be low and it should take a very short time to +recover from the previous failure. If there was no failure and +gcUncountedHashesIndex is empty, which is the usual case, New function will take +the minimal time to return. +*/ + +package localstore + +import ( + "time" + + "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 int64 = 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 int64, done bool, err error) { + batch := new(leveldb.Batch) + target := db.gcTarget() + + done = true + err = db.gcIndex.Iterate(func(item shed.Item) (stop bool, err error) { + // protect parallel updates + unlock, err := db.lockAddr(item.Address) + if err != nil { + return false, err + } + defer unlock() + + gcSize := db.getGCSize() + 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 + } + + err = db.shed.WriteBatch(batch) + if err != nil { + return 0, false, err + } + // batch is written, decrement gcSize + db.incGCSize(-collectedCount) + 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 int64) { + return int64(float64(db.capacity) * gcTargetRatio) +} + +// incGCSize increments gcSize by the provided number. +// If count is negative, it will decrement gcSize. +func (db *DB) incGCSize(count int64) { + if count == 0 { + return + } + + db.gcSizeMu.Lock() + new := db.gcSize + count + db.gcSize = new + db.gcSizeMu.Unlock() + + select { + case db.writeGCSizeTrigger <- struct{}{}: + default: + } + if new >= db.capacity { + db.triggerGarbageCollection() + } +} + +// getGCSize returns gcSize value by locking it +// with gcSizeMu mutex. +func (db *DB) getGCSize() (count int64) { + db.gcSizeMu.RLock() + count = db.gcSize + db.gcSizeMu.RUnlock() + return count +} + +// triggerGarbageCollection signals collectGarbageWorker +// to call collectGarbage. +func (db *DB) triggerGarbageCollection() { + select { + case db.collectGarbageTrigger <- struct{}{}: + case <-db.close: + default: + } +} + +// writeGCSizeWorker writes gcSize on trigger event +// and waits writeGCSizeDelay after each write. +// It implements a linear backoff with delay of +// writeGCSizeDelay duration to avoid very frequent +// database operations. +func (db *DB) writeGCSizeWorker() { + defer close(db.writeGCSizeWorkerDone) + + for { + select { + case <-db.writeGCSizeTrigger: + err := db.writeGCSize(db.getGCSize()) + if err != nil { + log.Error("localstore write gc size", "err", err) + } + // Wait some time before writing gc size in the next + // iteration. This prevents frequent I/O operations. + select { + case <-time.After(10 * time.Second): + case <-db.close: + return + } + case <-db.close: + return + } + } +} + +// writeGCSize stores the number of items in gcIndex. +// It removes all hashes from gcUncountedHashesIndex +// not to include them on the next DB initialization +// (New function) when gcSize is counted. +func (db *DB) writeGCSize(gcSize int64) (err error) { + const maxBatchSize = 1000 + + batch := new(leveldb.Batch) + db.storedGCSize.PutInBatch(batch, uint64(gcSize)) + batchSize := 1 + + // use only one iterator as it acquires its snapshot + // not to remove hashes from index that are added + // after stored gc size is written + err = db.gcUncountedHashesIndex.Iterate(func(item shed.Item) (stop bool, err error) { + db.gcUncountedHashesIndex.DeleteInBatch(batch, item) + batchSize++ + if batchSize >= maxBatchSize { + err = db.shed.WriteBatch(batch) + if err != nil { + return false, err + } + batch.Reset() + batchSize = 0 + } + return false, nil + }, nil) + if err != nil { + return err + } + return db.shed.WriteBatch(batch) +} + +// 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 int64) diff --git a/swarm/storage/localstore/gc_test.go b/swarm/storage/localstore/gc_test.go new file mode 100644 index 0000000000..c2ad774d3b --- /dev/null +++ b/swarm/storage/localstore/gc_test.go @@ -0,0 +1,373 @@ +// 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 int64) { 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 int64) + defer setTestHookCollectGarbage(func(collectedCount int64) { + 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 := db.getGCSize() + 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 int64) + defer setTestHookCollectGarbage(func(collectedCount int64) { + 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 int64 + for { + select { + case c := <-testHookCollectGarbageChan: + totalCollectedCount += c + case <-time.After(10 * time.Second): + t.Error("collect garbage timeout") + } + gcSize := db.getGCSize() + if gcSize == gcTarget { + break + } + } + + wantTotalCollectedCount := int64(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) + } + } + + // DB.Close writes gc size to disk, so + // Instead calling Close, simulate database shutdown + // without it. + close(db.close) + db.updateGCWG.Wait() + err = db.shed.Close() + if 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)) + + t.Run("gc uncounted hashes index count", newItemsCountTest(db.gcUncountedHashesIndex, 0)) +} + +// setTestHookCollectGarbage sets testHookCollectGarbage and +// returns a function that will reset it to the +// value before the change. +func setTestHookCollectGarbage(h func(collectedCount int64)) (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 int64)) { 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(_ int64) { + 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(_ int64) { + 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/swarm/storage/localstore/index_test.go b/swarm/storage/localstore/index_test.go new file mode 100644 index 0000000000..cf19e4f6cd --- /dev/null +++ b/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/swarm/storage/localstore/localstore.go b/swarm/storage/localstore/localstore.go new file mode 100644 index 0000000000..a66130fd30 --- /dev/null +++ b/swarm/storage/localstore/localstore.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 ( + "encoding/binary" + "encoding/hex" + "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 int64 = 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 + // field that stores number of intems in gc index + storedGCSize shed.Uint64Field + + // 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 + // index that stores hashes that are not + // counted in and saved to storedGCSize + gcUncountedHashesIndex shed.Index + + // number of elements in garbage collection index + // it must be always read by getGCSize and + // set with incGCSize which are locking gcSizeMu + gcSize int64 + gcSizeMu sync.RWMutex + // garbage collection is triggered when gcSize exceeds + // the capacity value + capacity int64 + + // triggers garbage collection event loop + collectGarbageTrigger chan struct{} + // triggers write gc size event loop + writeGCSizeTrigger 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 + + addressLocks sync.Map + + // 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{} + writeGCSizeWorkerDone 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 int64 + // 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, + // channels collectGarbageTrigger and writeGCSizeTrigger + // need 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), + writeGCSizeTrigger: make(chan struct{}, 1), + close: make(chan struct{}), + collectGarbageWorkerDone: make(chan struct{}), + writeGCSizeWorkerDone: 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.storedGCSize, 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 + } + // gc uncounted hashes index keeps hashes that are in gc index + // but not counted in and saved to storedGCSize + db.gcUncountedHashesIndex, err = db.shed.NewIndex("Hash->nil", 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) { + return nil, nil + }, + DecodeValue: func(keyItem shed.Item, value []byte) (e shed.Item, err error) { + return e, nil + }, + }) + if err != nil { + return nil, err + } + + // count number of elements in garbage collection index + gcSize, err := db.storedGCSize.Get() + if err != nil { + return nil, err + } + // get number of uncounted hashes + gcUncountedSize, err := db.gcUncountedHashesIndex.Count() + if err != nil { + return nil, err + } + gcSize += uint64(gcUncountedSize) + // remove uncounted hashes from the index and + // save the total gcSize after uncounted hashes are removed + err = db.writeGCSize(int64(gcSize)) + if err != nil { + return nil, err + } + db.incGCSize(int64(gcSize)) + + // start worker to write gc size + go db.writeGCSizeWorker() + // 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 and gc size write workers to + // return before closing the shed + timeout := time.After(5 * time.Second) + select { + case <-db.collectGarbageWorkerDone: + case <-timeout: + log.Error("localstore: collect garbage worker did not return after db close") + } + select { + case <-db.writeGCSizeWorkerDone: + case <-timeout: + log.Error("localstore: write gc size worker did not return after db close") + } + + if err := db.writeGCSize(db.getGCSize()); err != nil { + log.Error("localstore: write gc size", "err", err) + } + 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)) +} + +var ( + // Maximal time for lockAddr to wait until it + // returns error. + addressLockTimeout = 3 * time.Second + // duration between two lock checks in lockAddr. + addressLockCheckDelay = 30 * time.Microsecond +) + +// lockAddr sets the lock on a particular address +// using addressLocks sync.Map and returns unlock function. +// If the address is locked this function will check it +// in a for loop for addressLockTimeout time, after which +// it will return ErrAddressLockTimeout error. +func (db *DB) lockAddr(addr chunk.Address) (unlock func(), err error) { + start := time.Now() + lockKey := hex.EncodeToString(addr) + for { + _, loaded := db.addressLocks.LoadOrStore(lockKey, struct{}{}) + if !loaded { + break + } + time.Sleep(addressLockCheckDelay) + if time.Since(start) > addressLockTimeout { + return nil, ErrAddressLockTimeout + } + } + return func() { db.addressLocks.Delete(lockKey) }, nil +} + +// 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/swarm/storage/localstore/localstore_test.go b/swarm/storage/localstore/localstore_test.go new file mode 100644 index 0000000000..d106241733 --- /dev/null +++ b/swarm/storage/localstore/localstore_test.go @@ -0,0 +1,535 @@ +// 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" + "strconv" + "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) + } +} + +// BenchmarkNew measures the time that New function +// needs to initialize and count the number of key/value +// pairs in GC index. +// This benchmark generates a number of chunks, uploads them, +// sets them to synced state for them to enter the GC index, +// and measures the execution time of New function by creating +// new databases with the same data directory. +// +// This benchmark takes significant amount of time. +// +// Measurements on MacBook Pro (Retina, 15-inch, Mid 2014) show +// that New function executes around 1s for database with 1M chunks. +// +// # go test -benchmem -run=none github.com/ethereum/go-ethereum/swarm/storage/localstore -bench BenchmarkNew -v -timeout 20m +// goos: darwin +// goarch: amd64 +// pkg: github.com/ethereum/go-ethereum/swarm/storage/localstore +// BenchmarkNew/1000-8 200 11672414 ns/op 9570960 B/op 10008 allocs/op +// BenchmarkNew/10000-8 100 14890609 ns/op 10490118 B/op 7759 allocs/op +// BenchmarkNew/100000-8 20 58334080 ns/op 17763157 B/op 22978 allocs/op +// BenchmarkNew/1000000-8 2 748595153 ns/op 45297404 B/op 253242 allocs/op +// PASS +func BenchmarkNew(b *testing.B) { + if testing.Short() { + b.Skip("skipping benchmark in short mode") + } + for _, count := range []int{ + 1000, + 10000, + 100000, + 1000000, + } { + b.Run(strconv.Itoa(count), func(b *testing.B) { + dir, err := ioutil.TempDir("", "localstore-new-benchmark") + if err != nil { + b.Fatal(err) + } + defer os.RemoveAll(dir) + baseKey := make([]byte, 32) + if _, err := rand.Read(baseKey); err != nil { + b.Fatal(err) + } + db, err := New(dir, baseKey, nil) + if err != nil { + b.Fatal(err) + } + defer db.Close() + uploader := db.NewPutter(ModePutUpload) + syncer := db.NewSetter(ModeSetSync) + for i := 0; i < count; i++ { + chunk := generateTestRandomChunk() + err := uploader.Put(chunk) + if err != nil { + b.Fatal(err) + } + err = syncer.Set(chunk.Address()) + if err != nil { + b.Fatal(err) + } + } + err = db.Close() + if err != nil { + b.Fatal(err) + } + b.ResetTimer() + + for n := 0; n < b.N; n++ { + b.StartTimer() + db, err := New(dir, baseKey, nil) + b.StopTimer() + + if err != nil { + b.Fatal(err) + } + err = db.Close() + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +// 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 int64 + err := db.gcIndex.Iterate(func(item shed.Item) (stop bool, err error) { + want++ + return + }, nil) + if err != nil { + t.Fatal(err) + } + got := db.getGCSize() + 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/swarm/storage/localstore/mode_get.go b/swarm/storage/localstore/mode_get.go new file mode 100644 index 0000000000..9640cd27e1 --- /dev/null +++ b/swarm/storage/localstore/mode_get.go @@ -0,0 +1,154 @@ +// 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) { + unlock, err := db.lockAddr(item.Address) + if err != nil { + return err + } + defer 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/swarm/storage/localstore/mode_get_test.go b/swarm/storage/localstore/mode_get_test.go new file mode 100644 index 0000000000..28a70ee0cc --- /dev/null +++ b/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/swarm/storage/localstore/mode_put.go b/swarm/storage/localstore/mode_put.go new file mode 100644 index 0000000000..81df435351 --- /dev/null +++ b/swarm/storage/localstore/mode_put.go @@ -0,0 +1,160 @@ +// 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 + unlock, err := db.lockAddr(item.Address) + if err != nil { + return err + } + defer 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) + db.gcUncountedHashesIndex.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.shed.WriteBatch(batch) + if err != nil { + return err + } + if gcSizeChange != 0 { + db.incGCSize(gcSizeChange) + } + if triggerPullFeed { + db.triggerPullSubscriptions(db.po(item.Address)) + } + if triggerPushFeed { + db.triggerPushSubscriptions() + } + return nil +} diff --git a/swarm/storage/localstore/mode_put_test.go b/swarm/storage/localstore/mode_put_test.go new file mode 100644 index 0000000000..8ecae1d2e9 --- /dev/null +++ b/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/swarm/storage/localstore/mode_set.go b/swarm/storage/localstore/mode_set.go new file mode 100644 index 0000000000..a7c9875fed --- /dev/null +++ b/swarm/storage/localstore/mode_set.go @@ -0,0 +1,205 @@ +// 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 + unlock, err := db.lockAddr(addr) + if err != nil { + return err + } + defer 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) + db.gcUncountedHashesIndex.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) + db.gcUncountedHashesIndex.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) + db.gcUncountedHashesIndex.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.shed.WriteBatch(batch) + if err != nil { + return err + } + if gcSizeChange != 0 { + db.incGCSize(gcSizeChange) + } + if triggerPullFeed { + db.triggerPullSubscriptions(db.po(item.Address)) + } + return nil +} diff --git a/swarm/storage/localstore/mode_set_test.go b/swarm/storage/localstore/mode_set_test.go new file mode 100644 index 0000000000..674aaabecd --- /dev/null +++ b/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/swarm/storage/localstore/retrieval_index_test.go b/swarm/storage/localstore/retrieval_index_test.go new file mode 100644 index 0000000000..b08790124b --- /dev/null +++ b/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/swarm/storage/localstore/subscription_pull.go b/swarm/storage/localstore/subscription_pull.go new file mode 100644 index 0000000000..0b96102e35 --- /dev/null +++ b/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/swarm/storage/localstore/subscription_pull_test.go b/swarm/storage/localstore/subscription_pull_test.go new file mode 100644 index 0000000000..d5ddae02b9 --- /dev/null +++ b/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/swarm/storage/localstore/subscription_push.go b/swarm/storage/localstore/subscription_push.go new file mode 100644 index 0000000000..5cbc2eb6ff --- /dev/null +++ b/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/swarm/storage/localstore/subscription_push_test.go b/swarm/storage/localstore/subscription_push_test.go new file mode 100644 index 0000000000..30fb98eb21 --- /dev/null +++ b/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/swarm/storage/localstore_test.go b/swarm/storage/localstore_test.go new file mode 100644 index 0000000000..fcadcefa0b --- /dev/null +++ b/swarm/storage/localstore_test.go @@ -0,0 +1,244 @@ +// 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 storage + +import ( + "context" + "io/ioutil" + "os" + "testing" + "time" + + "github.com/ethereum/go-ethereum/swarm/chunk" +) + +var ( + hashfunc = MakeHashFunc(DefaultHash) +) + +// tests that the content address validator correctly checks the data +// tests that feed update chunks are passed through content address validator +// the test checking the resouce update validator internal correctness is found in storage/feeds/handler_test.go +func TestValidator(t *testing.T) { + // set up localstore + datadir, err := ioutil.TempDir("", "storage-testvalidator") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(datadir) + + params := NewDefaultLocalStoreParams() + params.Init(datadir) + store, err := NewLocalStore(params, nil) + if err != nil { + t.Fatal(err) + } + + // check puts with no validators, both succeed + chunks := GenerateRandomChunks(259, 2) + goodChunk := chunks[0] + badChunk := chunks[1] + copy(badChunk.Data(), goodChunk.Data()) + + errs := putChunks(store, goodChunk, badChunk) + if errs[0] != nil { + t.Fatalf("expected no error on good content address chunk in spite of no validation, but got: %s", err) + } + if errs[1] != nil { + t.Fatalf("expected no error on bad content address chunk in spite of no validation, but got: %s", err) + } + + // add content address validator and check puts + // bad should fail, good should pass + store.Validators = append(store.Validators, NewContentAddressValidator(hashfunc)) + chunks = GenerateRandomChunks(chunk.DefaultSize, 2) + goodChunk = chunks[0] + badChunk = chunks[1] + copy(badChunk.Data(), goodChunk.Data()) + + errs = putChunks(store, goodChunk, badChunk) + if errs[0] != nil { + t.Fatalf("expected no error on good content address chunk with content address validator only, but got: %s", err) + } + if errs[1] == nil { + t.Fatal("expected error on bad content address chunk with content address validator only, but got nil") + } + + // append a validator that always denies + // bad should fail, good should pass, + var negV boolTestValidator + store.Validators = append(store.Validators, negV) + + chunks = GenerateRandomChunks(chunk.DefaultSize, 2) + goodChunk = chunks[0] + badChunk = chunks[1] + copy(badChunk.Data(), goodChunk.Data()) + + errs = putChunks(store, goodChunk, badChunk) + if errs[0] != nil { + t.Fatalf("expected no error on good content address chunk with content address validator only, but got: %s", err) + } + if errs[1] == nil { + t.Fatal("expected error on bad content address chunk with content address validator only, but got nil") + } + + // append a validator that always approves + // all shall pass + var posV boolTestValidator = true + store.Validators = append(store.Validators, posV) + + chunks = GenerateRandomChunks(chunk.DefaultSize, 2) + goodChunk = chunks[0] + badChunk = chunks[1] + copy(badChunk.Data(), goodChunk.Data()) + + errs = putChunks(store, goodChunk, badChunk) + if errs[0] != nil { + t.Fatalf("expected no error on good content address chunk with content address validator only, but got: %s", err) + } + if errs[1] != nil { + t.Fatalf("expected no error on bad content address chunk in spite of no validation, but got: %s", err) + } + +} + +type boolTestValidator bool + +func (self boolTestValidator) Validate(chunk Chunk) bool { + return bool(self) +} + +// putChunks adds chunks to localstore +// It waits for receive on the stored channel +// It logs but does not fail on delivery error +func putChunks(store *LocalStore, chunks ...Chunk) []error { + i := 0 + f := func(n int64) Chunk { + chunk := chunks[i] + i++ + return chunk + } + _, errs := put(store, len(chunks), f) + return errs +} + +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(chunk.DefaultSize) + err := store.Put(context.TODO(), chunk) + errs = append(errs, err) + hs = append(hs, chunk.Address()) + } + return hs, errs +} + +// TestGetFrequentlyAccessedChunkWontGetGarbageCollected tests that the most +// frequently accessed chunk is not garbage collected from LDBStore, i.e., +// from disk when we are at the capacity and garbage collector runs. For that +// we start putting random chunks into the DB while continuously accessing the +// chunk we care about then check if we can still retrieve it from disk. +func TestGetFrequentlyAccessedChunkWontGetGarbageCollected(t *testing.T) { + ldbCap := defaultGCRatio + store, cleanup := setupLocalStore(t, ldbCap) + defer cleanup() + + var chunks []Chunk + for i := 0; i < ldbCap; i++ { + chunks = append(chunks, GenerateRandomChunk(chunk.DefaultSize)) + } + + mostAccessed := chunks[0].Address() + for _, chunk := range chunks { + if err := store.Put(context.Background(), chunk); err != nil { + t.Fatal(err) + } + + if _, err := store.Get(context.Background(), mostAccessed); err != nil { + t.Fatal(err) + } + // Add time for MarkAccessed() to be able to finish in a separate Goroutine + time.Sleep(1 * time.Millisecond) + } + + store.DbStore.collectGarbage() + if _, err := store.DbStore.Get(context.Background(), mostAccessed); err != nil { + t.Logf("most frequntly accessed chunk not found on disk (key: %v)", mostAccessed) + t.Fatal(err) + } + +} + +func setupLocalStore(t *testing.T, ldbCap int) (ls *LocalStore, cleanup func()) { + t.Helper() + + var err error + datadir, err := ioutil.TempDir("", "storage") + if err != nil { + t.Fatal(err) + } + + params := &LocalStoreParams{ + StoreParams: NewStoreParams(uint64(ldbCap), uint(ldbCap), nil, nil), + } + params.Init(datadir) + + store, err := NewLocalStore(params, nil) + if err != nil { + _ = os.RemoveAll(datadir) + t.Fatal(err) + } + + cleanup = func() { + store.Close() + _ = os.RemoveAll(datadir) + } + + 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/swarm/storage/memstore.go b/swarm/storage/memstore.go index 3cb25ac625..611ac3bc51 100644 --- a/swarm/storage/memstore.go +++ b/swarm/storage/memstore.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 @@ -19,302 +19,74 @@ package storage import ( - "fmt" - "sync" + "context" - "github.com/ethereum/go-ethereum/log" -) - -const ( - memTreeLW = 2 // log2(subtree count) of the subtrees - memTreeFLW = 14 // log2(subtree count) of the root layer - dbForceUpdateAccessCnt = 1000 - defaultCacheCapacity = 5000 + lru "github.com/hashicorp/golang-lru" ) type MemStore struct { - memtree *memTree - entryCnt, capacity uint // stored entries - accessCnt uint64 // access counter; oldest is thrown away when full - dbAccessCnt uint64 - dbStore *DbStore - lock sync.Mutex + cache *lru.Cache + disabled bool } -/* -a hash prefix subtree containing subtrees or one storage entry (but never both) - -- access[0] stores the smallest (oldest) access count value in this subtree -- if it contains more subtrees and its subtree count is at least 4, access[1:2] - stores the smallest access count in the first and second halves of subtrees - (so that access[0] = min(access[1], access[2]) -- likewise, if subtree count is at least 8, - access[1] = min(access[3], access[4]) - access[2] = min(access[5], access[6]) - (access[] is a binary tree inside the multi-bit leveled hash tree) -*/ - -func NewMemStore(d *DbStore, capacity uint) (m *MemStore) { - m = &MemStore{} - m.memtree = newMemTree(memTreeFLW, nil, 0) - m.dbStore = d - m.setCapacity(capacity) - return -} - -type memTree struct { - subtree []*memTree - parent *memTree - parentIdx uint - - bits uint // log2(subtree count) - width uint // subtree count - - entry *Chunk // if subtrees are present, entry should be nil - lastDBaccess uint64 - access []uint64 -} - -func newMemTree(b uint, parent *memTree, pidx uint) (node *memTree) { - node = new(memTree) - node.bits = b - node.width = 1 << b - node.subtree = make([]*memTree, node.width) - node.access = make([]uint64, node.width-1) - node.parent = parent - node.parentIdx = pidx - if parent != nil { - parent.subtree[pidx] = node - } - - return node -} - -func (node *memTree) updateAccess(a uint64) { - aidx := uint(0) - var aa uint64 - oa := node.access[0] - for node.access[aidx] == oa { - node.access[aidx] = a - if aidx > 0 { - aa = node.access[((aidx-1)^1)+1] - aidx = (aidx - 1) >> 1 - } else { - pidx := node.parentIdx - node = node.parent - if node == nil { - return - } - nn := node.subtree[pidx^1] - if nn != nil { - aa = nn.access[0] - } else { - aa = 0 - } - aidx = (node.width + pidx - 2) >> 1 - } - - if (aa != 0) && (aa < a) { - a = aa - } - } -} - -func (s *MemStore) setCapacity(c uint) { - s.lock.Lock() - defer s.lock.Unlock() - - for c < s.entryCnt { - s.removeOldest() - } - s.capacity = c -} - -// entry (not its copy) is going to be in MemStore -func (s *MemStore) Put(entry *Chunk) { - if s.capacity == 0 { - return - } - - s.lock.Lock() - defer s.lock.Unlock() - - if s.entryCnt >= s.capacity { - s.removeOldest() - } - - s.accessCnt++ - - node := s.memtree - bitpos := uint(0) - for node.entry == nil { - l := entry.Key.bits(bitpos, node.bits) - st := node.subtree[l] - if st == nil { - st = newMemTree(memTreeLW, node, l) - bitpos += node.bits - node = st - break - } - bitpos += node.bits - node = st - } - - if node.entry != nil { - - if node.entry.Key.isEqual(entry.Key) { - node.updateAccess(s.accessCnt) - if entry.SData == nil { - entry.Size = node.entry.Size - entry.SData = node.entry.SData - } - if entry.Req == nil { - entry.Req = node.entry.Req - } - entry.C = node.entry.C - node.entry = entry - return - } - - for node.entry != nil { - - l := node.entry.Key.bits(bitpos, node.bits) - st := node.subtree[l] - if st == nil { - st = newMemTree(memTreeLW, node, l) - } - st.entry = node.entry - node.entry = nil - st.updateAccess(node.access[0]) - - l = entry.Key.bits(bitpos, node.bits) - st = node.subtree[l] - if st == nil { - st = newMemTree(memTreeLW, node, l) - } - bitpos += node.bits - node = st - +//NewMemStore is instantiating a MemStore cache keeping all frequently requested +//chunks in the `cache` LRU cache. +func NewMemStore(params *StoreParams, _ *LDBStore) (m *MemStore) { + if params.CacheCapacity == 0 { + return &MemStore{ + disabled: true, } } - node.entry = entry - node.lastDBaccess = s.dbAccessCnt - node.updateAccess(s.accessCnt) - s.entryCnt++ -} - -func (s *MemStore) Get(hash Key) (chunk *Chunk, err error) { - s.lock.Lock() - defer s.lock.Unlock() - - node := s.memtree - bitpos := uint(0) - for node.entry == nil { - l := hash.bits(bitpos, node.bits) - st := node.subtree[l] - if st == nil { - return nil, notFound - } - bitpos += node.bits - node = st + c, err := lru.New(int(params.CacheCapacity)) + if err != nil { + panic(err) } - if node.entry.Key.isEqual(hash) { - s.accessCnt++ - node.updateAccess(s.accessCnt) - chunk = node.entry - if s.dbAccessCnt-node.lastDBaccess > dbForceUpdateAccessCnt { - s.dbAccessCnt++ - node.lastDBaccess = s.dbAccessCnt - if s.dbStore != nil { - s.dbStore.updateAccessCnt(hash) - } - } + return &MemStore{ + cache: c, + } +} + +// 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 + } + + c, ok := m.cache.Get(string(addr)) + if !ok { + return nil, ErrChunkNotFound + } + return c.(Chunk), nil +} + +func (m *MemStore) Put(_ context.Context, c Chunk) error { + if m.disabled { + return nil + } + + m.cache.Add(string(c.Address()), c) + return nil +} + +func (m *MemStore) setCapacity(n int) { + if n <= 0 { + m.disabled = true } else { - err = notFound - } - - return -} - -func (s *MemStore) removeOldest() { - node := s.memtree - - for node.entry == nil { - - aidx := uint(0) - av := node.access[aidx] - - for aidx < node.width/2-1 { - if av == node.access[aidx*2+1] { - node.access[aidx] = node.access[aidx*2+2] - aidx = aidx*2 + 1 - } else if av == node.access[aidx*2+2] { - node.access[aidx] = node.access[aidx*2+1] - aidx = aidx*2 + 2 - } else { - panic(nil) - } - } - pidx := aidx*2 + 2 - node.width - if (node.subtree[pidx] != nil) && (av == node.subtree[pidx].access[0]) { - if node.subtree[pidx+1] != nil { - node.access[aidx] = node.subtree[pidx+1].access[0] - } else { - node.access[aidx] = 0 - } - } else if (node.subtree[pidx+1] != nil) && (av == node.subtree[pidx+1].access[0]) { - if node.subtree[pidx] != nil { - node.access[aidx] = node.subtree[pidx].access[0] - } else { - node.access[aidx] = 0 - } - pidx++ - } else { - panic(nil) + c, err := lru.New(n) + if err != nil { + panic(err) } - //fmt.Println(pidx) - node = node.subtree[pidx] - - } - - if node.entry.dbStored != nil { - log.Trace(fmt.Sprintf("Memstore Clean: Waiting for chunk %v to be saved", node.entry.Key.Log())) - <-node.entry.dbStored - log.Trace(fmt.Sprintf("Memstore Clean: Chunk %v saved to DBStore. Ready to clear from mem.", node.entry.Key.Log())) - } else { - log.Trace(fmt.Sprintf("Memstore Clean: Chunk %v already in DB. Ready to delete.", node.entry.Key.Log())) - } - - if node.entry.SData != nil { - node.entry = nil - s.entryCnt-- - } - - node.access[0] = 0 - - //--- - - aidx := uint(0) - for { - aa := node.access[aidx] - if aidx > 0 { - aidx = (aidx - 1) >> 1 - } else { - pidx := node.parentIdx - node = node.parent - if node == nil { - return - } - aidx = (node.width + pidx - 2) >> 1 - } - if (aa != 0) && ((aa < node.access[aidx]) || (node.access[aidx] == 0)) { - node.access[aidx] = aa + *m = MemStore{ + cache: c, } } } -// Close memstore func (s *MemStore) Close() {} diff --git a/swarm/storage/memstore_test.go b/swarm/storage/memstore_test.go index 2e0ab535af..8aaf486a7b 100644 --- a/swarm/storage/memstore_test.go +++ b/swarm/storage/memstore_test.go @@ -17,34 +17,142 @@ package storage import ( + "context" "testing" + + "github.com/ethereum/go-ethereum/swarm/log" ) -func testMemStore(l int64, branches int64, t *testing.T) { - m := NewMemStore(nil, defaultCacheCapacity) - testStore(m, l, branches, t) +func newTestMemStore() *MemStore { + storeparams := NewDefaultStoreParams() + return NewMemStore(storeparams, nil) } -func TestMemStore128_10000(t *testing.T) { - testMemStore(10000, 128, t) +func testMemStoreRandom(n int, t *testing.T) { + m := newTestMemStore() + defer m.Close() + testStoreRandom(m, n, t) } -func TestMemStore128_1000(t *testing.T) { - testMemStore(1000, 128, t) +func testMemStoreCorrect(n int, t *testing.T) { + m := newTestMemStore() + defer m.Close() + testStoreCorrect(m, n, t) } -func TestMemStore128_100(t *testing.T) { - testMemStore(100, 128, t) +func TestMemStoreRandom_1(t *testing.T) { + testMemStoreRandom(1, t) } -func TestMemStore2_100(t *testing.T) { - testMemStore(100, 2, t) +func TestMemStoreCorrect_1(t *testing.T) { + testMemStoreCorrect(1, t) +} + +func TestMemStoreRandom_1k(t *testing.T) { + testMemStoreRandom(1000, t) +} + +func TestMemStoreCorrect_1k(t *testing.T) { + testMemStoreCorrect(100, t) } func TestMemStoreNotFound(t *testing.T) { - m := NewMemStore(nil, defaultCacheCapacity) - _, err := m.Get(ZeroKey) - if err != notFound { - t.Errorf("Expected notFound, got %v", err) + m := newTestMemStore() + defer m.Close() + + _, err := m.Get(context.TODO(), ZeroAddr) + if err != ErrChunkNotFound { + t.Errorf("Expected ErrChunkNotFound, got %v", err) + } +} + +func benchmarkMemStorePut(n int, b *testing.B) { + m := newTestMemStore() + defer m.Close() + benchmarkStorePut(m, n, b) +} + +func benchmarkMemStoreGet(n int, b *testing.B) { + m := newTestMemStore() + defer m.Close() + benchmarkStoreGet(m, n, b) +} + +func BenchmarkMemStorePut_500(b *testing.B) { + benchmarkMemStorePut(500, b) +} + +func BenchmarkMemStoreGet_500(b *testing.B) { + benchmarkMemStoreGet(500, b) +} + +func TestMemStoreAndLDBStore(t *testing.T) { + ldb, cleanup := newLDBStore(t) + ldb.setCapacity(4000) + defer cleanup() + + cacheCap := 200 + memStore := NewMemStore(NewStoreParams(4000, 200, nil, nil), nil) + + tests := []struct { + n int // number of chunks to push to memStore + chunkSize int64 // size of chunk (by default in Swarm - 4096) + }{ + { + n: 1, + chunkSize: 4096, + }, + { + n: 101, + chunkSize: 4096, + }, + { + n: 501, + chunkSize: 4096, + }, + { + n: 1100, + chunkSize: 4096, + }, + } + + for i, tt := range tests { + log.Info("running test", "idx", i, "tt", tt) + var chunks []Chunk + + for i := 0; i < tt.n; i++ { + c := GenerateRandomChunk(tt.chunkSize) + chunks = append(chunks, c) + } + + for i := 0; i < tt.n; i++ { + err := ldb.Put(context.TODO(), chunks[i]) + if err != nil { + t.Fatal(err) + } + err = memStore.Put(context.TODO(), chunks[i]) + if err != nil { + t.Fatal(err) + } + + if got := memStore.cache.Len(); got > cacheCap { + t.Fatalf("expected to get cache capacity less than %v, but got %v", cacheCap, got) + } + + } + + for i := 0; i < tt.n; i++ { + _, err := memStore.Get(context.TODO(), chunks[i].Address()) + if err != nil { + if err == ErrChunkNotFound { + _, err := ldb.Get(context.TODO(), chunks[i].Address()) + if err != nil { + t.Fatalf("couldn't get chunk %v from ldb, got error: %v", i, err) + } + } else { + t.Fatalf("got error from memstore: %v", err) + } + } + } } } diff --git a/swarm/storage/mock/db/db.go b/swarm/storage/mock/db/db.go new file mode 100644 index 0000000000..313a61b43e --- /dev/null +++ b/swarm/storage/mock/db/db.go @@ -0,0 +1,476 @@ +// 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 db implements a mock store that keeps all chunk data in LevelDB database. +package db + +import ( + "archive/tar" + "bytes" + "encoding/json" + "errors" + "fmt" + "io" + "io/ioutil" + "sync" + "time" + + "github.com/syndtr/goleveldb/leveldb" + "github.com/syndtr/goleveldb/leveldb/util" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/swarm/storage/mock" +) + +// GlobalStore contains the LevelDB database that is storing +// chunk data for all swarm nodes. +// Closing the GlobalStore with Close method is required to +// 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. +func NewGlobalStore(path string) (s *GlobalStore, err error) { + db, err := leveldb.OpenFile(path, nil) + if err != nil { + return nil, err + } + return &GlobalStore{ + db: db, + }, nil +} + +// Close releases the resources used by the underlying LevelDB. +func (s *GlobalStore) Close() error { + return s.db.Close() +} + +// NewNodeStore returns a new instance of NodeStore that retrieves and stores +// chunk data only for a node with address addr. +func (s *GlobalStore) NewNodeStore(addr common.Address) *mock.NodeStore { + return mock.NewNodeStore(addr, s) +} + +// 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(indexForHashesPerNode(addr, key), nil) + if err != nil { + return nil, mock.ErrNotFound + } + if !has { + return nil, mock.ErrNotFound + } + data, err = s.db.Get(indexDataKey(key), nil) + if err == leveldb.ErrNotFound { + err = mock.ErrNotFound + } + return +} + +// 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(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(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) { + tr := tar.NewReader(r) + + for { + hdr, err := tr.Next() + if err != nil { + if err == io.EOF { + break + } + return n, err + } + + data, err := ioutil.ReadAll(tr) + if err != nil { + return n, err + } + + var c mock.ExportedChunk + if err = json.Unmarshal(data, &c); err != nil { + return n, err + } + + key := common.Hex2Bytes(hdr.Name) + + batch := new(leveldb.Batch) + for _, addr := range c.Addrs { + 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), c.Data) + + if err = s.db.Write(batch, nil); err != nil { + return n, err + } + + n++ + } + return n, err +} + +// Export writes to a writer a tar archive with all chunk data from +// the store. It returns the number fo chunks exported and an error. +func (s *GlobalStore) Export(w io.Writer) (n int, err error) { + tw := tar.NewWriter(w) + defer tw.Close() + + buf := bytes.NewBuffer(make([]byte, 0, 1024)) + encoder := json.NewEncoder(buf) + + 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() error { + hexKey := currentKey + + data, err := snap.Get(indexDataKey(common.Hex2Bytes(hexKey)), nil) + if err != nil { + return fmt.Errorf("get data %s: %v", hexKey, err) + } + + buf.Reset() + if err = encoder.Encode(mock.ExportedChunk{ + Addrs: addrs, + Data: data, + }); err != nil { + return err + } + + d := buf.Bytes() + hdr := &tar.Header{ + Name: hexKey, + Mode: 0644, + Size: int64(len(d)), + } + if err := tw.WriteHeader(hdr); err != nil { + return err + } + if _, err := tw.Write(d); err != nil { + return err + } + n++ + return nil + } + + for iter.Next() { + k := bytes.TrimPrefix(iter.Key(), []byte{indexForHashesByNodePrefix}) + i := bytes.Index(k, []byte{keyTermByte}) + if i < 0 { + continue + } + hexKey := string(k[:i]) + + if currentKey == "" { + currentKey = hexKey + } + + if hexKey != currentKey { + if err = saveChunk(); err != nil { + return n, err + } + + addrs = addrs[:0] + } + + currentKey = hexKey + addrs = append(addrs, common.BytesToAddress(k[i+1:])) + } + + if len(addrs) > 0 { + if err = saveChunk(); err != nil { + return n, err + } + } + + return n, iter.Error() +} + +var ( + // 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") +) + +// 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 +} + +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...) +} + +// 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/swarm/storage/mock/db/db_test.go b/swarm/storage/mock/db/db_test.go new file mode 100644 index 0000000000..efbf942f68 --- /dev/null +++ b/swarm/storage/mock/db/db_test.go @@ -0,0 +1,75 @@ +// 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 db + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/ethereum/go-ethereum/swarm/storage/mock/test" +) + +// TestDBStore is running a test.MockStore tests +// using test.MockStore function. +func TestDBStore(t *testing.T) { + 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) { + store1, cleanup := newTestStore(t) + defer cleanup() + + 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/swarm/storage/mock/explorer/explorer.go b/swarm/storage/mock/explorer/explorer.go new file mode 100644 index 0000000000..8fffff8fde --- /dev/null +++ b/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/swarm/storage/mock/explorer/explorer_test.go b/swarm/storage/mock/explorer/explorer_test.go new file mode 100644 index 0000000000..be26684266 --- /dev/null +++ b/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/swarm/storage/mock/explorer/headers_test.go b/swarm/storage/mock/explorer/headers_test.go new file mode 100644 index 0000000000..5b8e05ffde --- /dev/null +++ b/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/swarm/storage/mock/explorer/swagger.yaml b/swarm/storage/mock/explorer/swagger.yaml new file mode 100644 index 0000000000..2c014e927e --- /dev/null +++ b/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/swarm/storage/mock/mem/mem.go b/swarm/storage/mock/mem/mem.go new file mode 100644 index 0000000000..38bf098df4 --- /dev/null +++ b/swarm/storage/mock/mem/mem.go @@ -0,0 +1,385 @@ +// 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 mem implements a mock store that keeps all chunk data in memory. +// While it can be used for testing on smaller scales, the main purpose of this +// package is to provide the simplest reference implementation of a mock store. +package mem + +import ( + "archive/tar" + "bytes" + "encoding/json" + "io" + "io/ioutil" + "sort" + "sync" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/swarm/storage/mock" +) + +// GlobalStore stores all chunk data and also keys and node addresses relations. +// It implements mock.GlobalStore interface. +type GlobalStore struct { + // 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{ + 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), + } +} + +// NewNodeStore returns a new instance of NodeStore that retrieves and stores +// chunk data only for a node with address addr. +func (s *GlobalStore) NewNodeStore(addr common.Address) *mock.NodeStore { + return mock.NewNodeStore(addr, s) +} + +// 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.RLock() + defer s.mu.RUnlock() + + if _, has := s.nodeKeyIndex(addr, key); !has { + return nil, mock.ErrNotFound + } + + data, ok := s.data[string(key)] + if !ok { + return nil, mock.ErrNotFound + } + return data, nil +} + +// Put saves the chunk data for node with address addr. +func (s *GlobalStore) Put(addr common.Address, key []byte, data []byte) error { + s.mu.Lock() + defer s.mu.Unlock() + + 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 + } + + 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) (yes bool) { + s.mu.RLock() + defer s.mu.RUnlock() + + _, 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. +// It returns the number of chunks imported and an error. +func (s *GlobalStore) Import(r io.Reader) (n int, err error) { + s.mu.Lock() + defer s.mu.Unlock() + + tr := tar.NewReader(r) + + for { + hdr, err := tr.Next() + if err != nil { + if err == io.EOF { + break + } + return n, err + } + + data, err := ioutil.ReadAll(tr) + if err != nil { + return n, err + } + + var c mock.ExportedChunk + if err = json.Unmarshal(data, &c); err != nil { + return n, err + } + + 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 + } + } + 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 +} + +// 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.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.keyNodes { + buf.Reset() + if err = encoder.Encode(mock.ExportedChunk{ + Addrs: addrs, + Data: s.data[key], + }); err != nil { + return n, err + } + + data := buf.Bytes() + hdr := &tar.Header{ + Name: common.Bytes2Hex([]byte(key)), + Mode: 0644, + Size: int64(len(data)), + } + if err := tw.WriteHeader(hdr); err != nil { + return n, err + } + if _, err := tw.Write(data); err != nil { + return n, err + } + n++ + } + return n, err +} diff --git a/swarm/storage/mock/mem/mem_test.go b/swarm/storage/mock/mem/mem_test.go new file mode 100644 index 0000000000..d39aaef454 --- /dev/null +++ b/swarm/storage/mock/mem/mem_test.go @@ -0,0 +1,42 @@ +// 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 mem + +import ( + "testing" + + "github.com/ethereum/go-ethereum/swarm/storage/mock/test" +) + +// TestGlobalStore is running test for a GlobalStore +// using test.MockStore function. +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. +func TestImportExport(t *testing.T) { + test.ImportExport(t, NewGlobalStore(), NewGlobalStore(), 100) +} diff --git a/swarm/storage/mock/mock.go b/swarm/storage/mock/mock.go new file mode 100644 index 0000000000..586112a98b --- /dev/null +++ b/swarm/storage/mock/mock.go @@ -0,0 +1,142 @@ +// 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 mock defines types that are used by different implementations +// of mock storages. +// +// Implementations of mock storages are located in directories +// under this package: +// +// - db - LevelDB backend +// - mem - in memory map backend +// - rpc - RPC client that can connect to other backends +// +// Mock storages can implement Importer and Exporter interfaces +// for importing and exporting all chunk data that they contain. +// The exported file is a tar archive with all files named by +// hexadecimal representations of chunk keys and with content +// with JSON-encoded ExportedChunk structure. Exported format +// should be preserved across all mock store implementations. +package mock + +import ( + "errors" + "io" + + "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") + +// NodeStore holds the node address and a reference to the GlobalStore +// in order to access and store chunk data only for one node. +type NodeStore struct { + store GlobalStorer + addr common.Address +} + +// NewNodeStore creates a new instance of NodeStore that keeps +// chunk data using GlobalStorer with a provided address. +func NewNodeStore(addr common.Address, store GlobalStorer) *NodeStore { + return &NodeStore{ + store: store, + addr: addr, + } +} + +// Get returns chunk data for a key for a node that has the address +// provided on NodeStore initialization. +func (n *NodeStore) Get(key []byte) (data []byte, err error) { + return n.store.Get(n.addr, key) +} + +// Put saves chunk data for a key for a node that has the address +// provided on NodeStore initialization. +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 +// for swarm nodes and to track and validate chunks. +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 { + Import(r io.Reader) (n int, err error) +} + +// Exporter defines method for exporting mock store data +// to a tar archive. +type Exporter interface { + Export(w io.Writer) (n int, err error) +} + +// ExportedChunk is the structure that is saved in tar archive for +// each chunk as JSON-encoded bytes. +type ExportedChunk struct { + Data []byte `json:"d"` + Addrs []common.Address `json:"a"` +} diff --git a/swarm/storage/mock/rpc/rpc.go b/swarm/storage/mock/rpc/rpc.go new file mode 100644 index 0000000000..8150ccff13 --- /dev/null +++ b/swarm/storage/mock/rpc/rpc.go @@ -0,0 +1,114 @@ +// 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 implements an RPC client that connect to a centralized mock store. +// Centralazied mock store can be any other mock store implementation that is +// registered to Ethereum RPC server under mockStore name. Methods that defines +// mock.GlobalStore are the same that are used by RPC. Example: +// +// server := rpc.NewServer() +// server.RegisterName("mockStore", mem.NewGlobalStore()) +package rpc + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/rpc" + "github.com/ethereum/go-ethereum/swarm/log" + "github.com/ethereum/go-ethereum/swarm/storage/mock" +) + +// GlobalStore is rpc.Client that connects to a centralized mock store. +// Closing GlobalStore instance is required to release RPC client resources. +type GlobalStore struct { + client *rpc.Client +} + +// NewGlobalStore creates a new instance of GlobalStore. +func NewGlobalStore(client *rpc.Client) *GlobalStore { + return &GlobalStore{ + client: client, + } +} + +// Close closes RPC client. +func (s *GlobalStore) Close() error { + s.client.Close() + return nil +} + +// NewNodeStore returns a new instance of NodeStore that retrieves and stores +// chunk data only for a node with address addr. +func (s *GlobalStore) NewNodeStore(addr common.Address) *mock.NodeStore { + return mock.NewNodeStore(addr, s) +} + +// Get calls a Get method to RPC server. +func (s *GlobalStore) Get(addr common.Address, key []byte) (data []byte, err error) { + err = s.client.Call(&data, "mockStore_get", addr, key) + if err != nil && err.Error() == "not found" { + // pass the mock package value of error instead an rpc error + return data, mock.ErrNotFound + } + return data, err +} + +// Put calls a Put method to RPC server. +func (s *GlobalStore) Put(addr common.Address, key []byte, data []byte) error { + err := s.client.Call(nil, "mockStore_put", addr, key, data) + 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 + if err := s.client.Call(&has, "mockStore_hasKey", addr, key); err != nil { + log.Error(fmt.Sprintf("mock store HasKey: addr %s, key %064x: %v", addr, key, err)) + return 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) { + 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/swarm/storage/mock/rpc/rpc_test.go b/swarm/storage/mock/rpc/rpc_test.go new file mode 100644 index 0000000000..6c46523558 --- /dev/null +++ b/swarm/storage/mock/rpc/rpc_test.go @@ -0,0 +1,64 @@ +// 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 ( + "testing" + + "github.com/ethereum/go-ethereum/rpc" + "github.com/ethereum/go-ethereum/swarm/storage/mock/mem" + "github.com/ethereum/go-ethereum/swarm/storage/mock/test" +) + +// 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() + if err := server.RegisterName("mockStore", serverStore); err != nil { + t.Fatal(err) + } + + store := NewGlobalStore(rpc.DialInProc(server)) + return store, func() { + if err := store.Close(); err != nil { + t.Error(err) + } + } +} diff --git a/swarm/storage/mock/test/test.go b/swarm/storage/mock/test/test.go new file mode 100644 index 0000000000..cc837f0b77 --- /dev/null +++ b/swarm/storage/mock/test/test.go @@ -0,0 +1,362 @@ +// 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 test provides functions that are used for testing +// GlobalStorer implementations. +package test + +import ( + "bytes" + "encoding/binary" + "fmt" + "io" + "strconv" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/swarm/storage" + "github.com/ethereum/go-ethereum/swarm/storage/mock" +) + +// MockStore creates NodeStore instances from provided GlobalStorer, +// each one with a unique address, stores different chunks on them +// and checks if they are retrievable or not on all nodes. +// Attribute n defines the number of NodeStores that will be created. +func MockStore(t *testing.T, globalStore mock.GlobalStorer, n int) { + t.Run("GlobalStore", func(t *testing.T) { + addrs := make([]common.Address, n) + for i := 0; i < n; i++ { + addrs[i] = common.HexToAddress(strconv.FormatInt(int64(i)+1, 16)) + } + + 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)) + data = append(data, make([]byte, 4096-len(data))...) + globalStore.Put(addr, chunkAddr, data) + + for _, cAddr := range addrs { + cData, err := globalStore.Get(cAddr, chunkAddr) + if cAddr == addr { + if err != nil { + t.Fatalf("get data from store %s key %s: %v", cAddr.Hex(), chunkAddr.Hex(), err) + } + if !bytes.Equal(data, cData) { + t.Fatalf("data on store %s: expected %x, got %x", cAddr.Hex(), data, cData) + } + if !globalStore.HasKey(cAddr, chunkAddr) { + t.Fatalf("expected key %s on global store for node %s, but it was not found", chunkAddr.Hex(), cAddr.Hex()) + } + } else { + if err != mock.ErrNotFound { + t.Fatalf("expected error from store %s: %v, got %v", cAddr.Hex(), mock.ErrNotFound, err) + } + if len(cData) > 0 { + t.Fatalf("data on store %s: expected nil, got %x", cAddr.Hex(), cData) + } + if globalStore.HasKey(cAddr, chunkAddr) { + t.Fatalf("not expected key %s on global store for node %s, but it was found", chunkAddr.Hex(), cAddr.Hex()) + } + } + } + } + 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) { + nodes := make(map[common.Address]*mock.NodeStore) + for i := 0; i < n; i++ { + addr := common.HexToAddress(strconv.FormatInt(int64(i)+1, 16)) + nodes[addr] = globalStore.NewNodeStore(addr) + } + + i := 0 + for addr, store := range nodes { + i++ + chunkAddr := storage.Address(append(addr[:], []byte(fmt.Sprintf("%x", i))...)) + data := []byte(strconv.FormatInt(int64(i)+1, 16)) + data = append(data, make([]byte, 4096-len(data))...) + store.Put(chunkAddr, data) + + for cAddr, cStore := range nodes { + cData, err := cStore.Get(chunkAddr) + if cAddr == addr { + if err != nil { + t.Fatalf("get data from store %s key %s: %v", cAddr.Hex(), chunkAddr.Hex(), err) + } + if !bytes.Equal(data, cData) { + t.Fatalf("data on store %s: expected %x, got %x", cAddr.Hex(), data, cData) + } + if !globalStore.HasKey(cAddr, chunkAddr) { + t.Fatalf("expected key %s on global store for node %s, but it was not found", chunkAddr.Hex(), cAddr.Hex()) + } + } else { + if err != mock.ErrNotFound { + t.Fatalf("expected error from store %s: %v, got %v", cAddr.Hex(), mock.ErrNotFound, err) + } + if len(cData) > 0 { + t.Fatalf("data on store %s: expected nil, got %x", cAddr.Hex(), cData) + } + if globalStore.HasKey(cAddr, chunkAddr) { + t.Fatalf("not expected key %s on global store for node %s, but it was found", chunkAddr.Hex(), cAddr.Hex()) + } + } + } + } + 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) { + exporter, ok := outStore.(mock.Exporter) + if !ok { + t.Fatal("outStore does not implement mock.Exporter") + } + importer, ok := inStore.(mock.Importer) + if !ok { + t.Fatal("inStore does not implement mock.Importer") + } + addrs := make([]common.Address, n) + for i := 0; i < n; i++ { + addrs[i] = common.HexToAddress(strconv.FormatInt(int64(i)+1, 16)) + } + + 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)) + data = append(data, make([]byte, 4096-len(data))...) + outStore.Put(addr, chunkAddr, data) + } + + r, w := io.Pipe() + defer r.Close() + + exportErrChan := make(chan error) + go func() { + defer w.Close() + + _, 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)) + data = append(data, make([]byte, 4096-len(data))...) + for _, cAddr := range addrs { + cData, err := inStore.Get(cAddr, chunkAddr) + if cAddr == addr { + if err != nil { + t.Fatalf("get data from store %s key %s: %v", cAddr.Hex(), chunkAddr.Hex(), err) + } + if !bytes.Equal(data, cData) { + t.Fatalf("data on store %s: expected %x, got %x", cAddr.Hex(), data, cData) + } + if !inStore.HasKey(cAddr, chunkAddr) { + t.Fatalf("expected key %s on global store for node %s, but it was not found", chunkAddr.Hex(), cAddr.Hex()) + } + } else { + if err != mock.ErrNotFound { + t.Fatalf("expected error from store %s: %v, got %v", cAddr.Hex(), mock.ErrNotFound, err) + } + if len(cData) > 0 { + t.Fatalf("data on store %s: expected nil, got %x", cAddr.Hex(), cData) + } + if inStore.HasKey(cAddr, chunkAddr) { + t.Fatalf("not expected key %s on global store for node %s, but it was found", chunkAddr.Hex(), cAddr.Hex()) + } + } + } + } +} diff --git a/swarm/storage/netstore.go b/swarm/storage/netstore.go index 5d4f17deb1..8a44f51a88 100644 --- a/swarm/storage/netstore.go +++ b/swarm/storage/netstore.go @@ -17,125 +17,316 @@ package storage import ( + "context" + "encoding/hex" "fmt" - "path/filepath" + "sync" + "sync/atomic" "time" - "github.com/ethereum/go-ethereum/log" + "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" + + lru "github.com/hashicorp/golang-lru" ) -/* -NetStore is a cloud storage access abstaction layer for swarm -it contains the shared logic of network served chunk store/retrieval requests -both local (coming from DPA api) and remote (coming from peers via bzz protocol) -it implements the ChunkStore interface and embeds LocalStore +type ( + NewNetFetcherFunc func(ctx context.Context, addr Address, peers *sync.Map) NetFetcher +) -It is called by the bzz protocol instances via Depo (the store/retrieve request handler) -a protocol instance is running on each peer, so this is heavily parallelised. -NetStore falls back to a backend (CloudStorage interface) -implemented by bzz/network/forwarder. forwarder or IPFS or IPΞS -*/ +type NetFetcher interface { + Request(hopCount uint8) + Offer(source *enode.ID) +} + +// NetStore is an extension of local storage +// it implements the ChunkStore interface +// on request it initiates remote cloud retrieval using a fetcher +// fetchers are unique to a chunk and are stored in fetchers LRU memory cache +// fetchFuncFactory is a factory object to create a fetch function for a specific chunk address type NetStore struct { - hashfunc SwarmHasher - localStore *LocalStore - cloud CloudStore + mu sync.Mutex + store SyncChunkStore + fetchers *lru.Cache + NewNetFetcherFunc NewNetFetcherFunc + closeC chan struct{} } -// backend engine for cloud store -// It can be aggregate dispatching to several parallel implementations: -// bzz/network/forwarder. forwarder or IPFS or IPΞS -type CloudStore interface { - Store(*Chunk) - Deliver(*Chunk) - Retrieve(*Chunk) -} +var fetcherTimeout = 2 * time.Minute // timeout to cancel the fetcher even if requests are coming in -type StoreParams struct { - ChunkDbPath string - DbCapacity uint64 - CacheCapacity uint - Radius int -} - -//create params with default values -func NewDefaultStoreParams() (self *StoreParams) { - return &StoreParams{ - DbCapacity: defaultDbCapacity, - CacheCapacity: defaultCacheCapacity, - Radius: defaultRadius, +// NewNetStore creates a new NetStore object using the given local store. newFetchFunc is a +// constructor function that can create a fetch function for a specific chunk address. +func NewNetStore(store SyncChunkStore, nnf NewNetFetcherFunc) (*NetStore, error) { + fetchers, err := lru.New(defaultChunkRequestsCacheCapacity) + if err != nil { + return nil, err } -} - -//this can only finally be set after all config options (file, cmd line, env vars) -//have been evaluated -func (self *StoreParams) Init(path string) { - self.ChunkDbPath = filepath.Join(path, "chunks") -} - -// netstore contructor, takes path argument that is used to initialise dbStore, -// the persistent (disk) storage component of LocalStore -// the second argument is the hive, the connection/logistics manager for the node -func NewNetStore(hash SwarmHasher, lstore *LocalStore, cloud CloudStore, params *StoreParams) *NetStore { return &NetStore{ - hashfunc: hash, - localStore: lstore, - cloud: cloud, + store: store, + fetchers: fetchers, + NewNetFetcherFunc: nnf, + closeC: make(chan struct{}), + }, nil +} + +// Put stores a chunk in localstore, and delivers to all requestor peers using the fetcher stored in +// the fetchers cache +func (n *NetStore) Put(ctx context.Context, ch Chunk) error { + n.mu.Lock() + defer n.mu.Unlock() + + // put to the chunk to the store, there should be no error + err := n.store.Put(ctx, ch) + if err != nil { + return err + } + + // 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) + if f := n.getFetcher(ch.Address()); f != nil { + f.deliver(ctx, ch) + } + return nil +} + +// Get retrieves the chunk from the NetStore DPA synchronously. +// It calls NetStore.get, and if the chunk is not in local Storage +// it calls fetch with the request, which blocks until the chunk +// arrived or context is done +func (n *NetStore) Get(rctx context.Context, ref Address) (Chunk, error) { + chunk, fetch, err := n.get(rctx, ref) + if err != nil { + return nil, err + } + if chunk != nil { + return chunk, nil + } + return fetch(rctx) +} + +func (n *NetStore) BinIndex(po uint8) uint64 { + return n.store.BinIndex(po) +} + +func (n *NetStore) Iterator(from uint64, to uint64, po uint8, f func(Address, uint64) bool) error { + return n.store.Iterator(from, to, po, f) +} + +// FetchFunc returns nil if the store contains the given address. Otherwise it returns a wait function, +// which returns after the chunk is available or the context is done +func (n *NetStore) FetchFunc(ctx context.Context, ref Address) func(context.Context) error { + chunk, fetch, _ := n.get(ctx, ref) + if chunk != nil { + return nil + } + return func(ctx context.Context) error { + _, err := fetch(ctx) + return err } } -const ( - // maximum number of peers that a retrieved message is delivered to - requesterCount = 3 -) +// Close chunk store +func (n *NetStore) Close() { + close(n.closeC) + n.store.Close() -var ( - // timeout interval before retrieval is timed out - searchTimeout = 3 * time.Second -) + 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() -// store logic common to local and network chunk store requests -// ~ unsafe put in localdb no check if exists no extra copy no hash validation -// the chunk is forced to propagate (Cloud.Store) even if locally found! -// caller needs to make sure if that is wanted -func (self *NetStore) Put(entry *Chunk) { - self.localStore.Put(entry) - - // handle deliveries - if entry.Req != nil { - log.Trace(fmt.Sprintf("NetStore.Put: localStore.Put %v hit existing request...delivering", entry.Key.Log())) - // closing C signals to other routines (local requests) - // that the chunk is has been retrieved - close(entry.Req.C) - // deliver the chunk to requesters upstream - go self.cloud.Deliver(entry) - } else { - log.Trace(fmt.Sprintf("NetStore.Put: localStore.Put %v stored locally", entry.Key.Log())) - // handle propagating store requests - // go self.cloud.Store(entry) - go self.cloud.Store(entry) - } -} - -// retrieve logic common for local and network chunk retrieval requests -func (self *NetStore) Get(key Key) (*Chunk, error) { - var err error - chunk, err := self.localStore.Get(key) - if err == nil { - if chunk.Req == nil { - log.Trace(fmt.Sprintf("NetStore.Get: %v found locally", key)) - } else { - log.Trace(fmt.Sprintf("NetStore.Get: %v hit on an existing request", key)) - // no need to launch again + select { + case <-fetch.deliveredC: + case <-fetch.cancelledC: + } + }(fetch) + } } - return chunk, err } - // no data and no request status - log.Trace(fmt.Sprintf("NetStore.Get: %v not found locally. open new request", key)) - chunk = NewChunk(key, newRequestStatus(key)) - self.localStore.memStore.Put(chunk) - go self.cloud.Retrieve(chunk) - return chunk, nil + wg.Wait() } -// Close netstore -func (self *NetStore) Close() {} +// get attempts at retrieving the chunk from LocalStore +// If it is not found then using getOrCreateFetcher: +// 1. Either there is already a fetcher to retrieve it +// 2. A new fetcher is created and saved in the fetchers cache +// From here on, all Get will hit on this fetcher until the chunk is delivered +// or all fetcher contexts are done. +// It returns a chunk, a fetcher function and an error +// If chunk is nil, the returned fetch function needs to be called with a context to return the chunk. +func (n *NetStore) get(ctx context.Context, ref Address) (Chunk, func(context.Context) (Chunk, error), error) { + n.mu.Lock() + defer n.mu.Unlock() + + chunk, err := n.store.Get(ctx, ref) + if err != nil { + if err != ErrChunkNotFound { + 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(ctx, ref) + // If the caller needs the chunk, it has to use the returned fetch function to get it + return nil, f.Fetch, nil + } + + 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(ctx context.Context, ref Address) *fetcher { + if f := n.getFetcher(ref); f != nil { + return f + } + + // 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 + cctx, cancel := context.WithTimeout(ctx, fetcherTimeout) + // destroy is called when all requests finish + destroy := func() { + // remove fetcher from fetchers + n.fetchers.Remove(key) + // stop fetcher by cancelling context called when + // all requests cancelled/timedout or chunk is delivered + cancel() + } + // peers always stores all the peers which have an active request for the chunk. It is shared + // between fetcher and the NewFetchFunc function. It is needed by the NewFetchFunc because + // the peers which requested the chunk should not be requested to deliver it. + peers := &sync.Map{} + + cctx, sp := spancontext.StartSpan( + cctx, + "netstore.fetcher", + ) + fetcher := newFetcher(sp, ref, n.NewNetFetcherFunc(cctx, ref, peers), destroy, peers, n.closeC) + n.fetchers.Add(key, fetcher) + + return fetcher +} + +// getFetcher retrieves the fetcher for the given address from the fetchers cache if it exists, +// otherwise it returns nil +func (n *NetStore) getFetcher(ref Address) *fetcher { + key := hex.EncodeToString(ref) + f, ok := n.fetchers.Get(key) + if ok { + return f.(*fetcher) + } + return nil +} + +// RequestsCacheLen returns the current number of outgoing requests stored in the cache +func (n *NetStore) RequestsCacheLen() int { + return n.fetchers.Len() +} + +// 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 + span opentracing.Span // measure retrieve time per chunk +} + +// newFetcher creates a new fetcher object for the fiven addr. fetch is the function which actually +// does the retrieval (in non-test cases this is coming from the network package). cancel function is +// called either +// 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(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, + deliveredC: make(chan struct{}), + deliverOnce: &sync.Once{}, + cancelledC: closeC, + netFetcher: nf, + cancel: func() { + cancelOnce.Do(func() { + cancel() + }) + }, + peers: peers, + span: span, + } +} + +// Fetch fetches the chunk synchronously, it is called by NetStore.Get is the chunk is not available +// locally. +func (f *fetcher) Fetch(rctx context.Context) (Chunk, error) { + atomic.AddInt32(&f.requestCnt, 1) + defer func() { + // if all the requests are done the fetcher can be cancelled + 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 + // has been delivered + peer := rctx.Value("peer") + if peer != nil { + f.peers.Store(peer, time.Now()) + defer f.peers.Delete(peer) + } + + // If there is a source in the context then it is an offer, otherwise a request + sourceIF := rctx.Value("source") + + hopCount, _ := rctx.Value("hopcount").(uint8) + + if sourceIF != nil { + var source enode.ID + if err := source.UnmarshalText([]byte(sourceIF.(string))); err != nil { + return nil, err + } + f.netFetcher.Offer(&source) + } else { + f.netFetcher.Request(hopCount) + } + + // wait until either the chunk is delivered or the context is done + select { + case <-rctx.Done(): + return nil, rctx.Err() + case <-f.deliveredC: + return f.chunk, nil + case <-f.cancelledC: + return nil, fmt.Errorf("fetcher cancelled") + } +} + +// deliver is called by NetStore.Put to notify all pending requests +func (f *fetcher) deliver(ctx context.Context, ch Chunk) { + f.deliverOnce.Do(func() { + f.chunk = ch + // closing the deliveredC channel will terminate ongoing requests + close(f.deliveredC) + }) +} diff --git a/swarm/storage/netstore_test.go b/swarm/storage/netstore_test.go new file mode 100644 index 0000000000..6538776259 --- /dev/null +++ b/swarm/storage/netstore_test.go @@ -0,0 +1,692 @@ +// 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 storage + +import ( + "bytes" + "context" + "crypto/rand" + "errors" + "fmt" + "io/ioutil" + "sync" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/swarm/chunk" +) + +var sourcePeerID = enode.HexID("99d8594b52298567d2ca3f4c441a5ba0140ee9245e26460d01102a52773c73b9") + +type mockNetFetcher struct { + peers *sync.Map + sources []*enode.ID + peersPerRequest [][]Address + requestCalled bool + offerCalled bool + quit <-chan struct{} + ctx context.Context + hopCounts []uint8 + mu sync.Mutex +} + +func (m *mockNetFetcher) Offer(source *enode.ID) { + m.offerCalled = true + m.sources = append(m.sources, source) +} + +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 { + peers = append(peers, common.FromHex(key.(string))) + return true + }) + m.peersPerRequest = append(m.peersPerRequest, peers) + m.hopCounts = append(m.hopCounts, hopCount) +} + +type mockNetFetchFuncFactory struct { + fetcher *mockNetFetcher +} + +func (m *mockNetFetchFuncFactory) newMockNetFetcher(ctx context.Context, _ Address, peers *sync.Map) NetFetcher { + m.fetcher.peers = peers + m.fetcher.quit = ctx.Done() + m.fetcher.ctx = ctx + return m.fetcher +} + +func mustNewNetStore(t *testing.T) *NetStore { + netStore, _ := mustNewNetStoreWithFetcher(t) + return netStore +} + +func mustNewNetStoreWithFetcher(t *testing.T) (*NetStore, *mockNetFetcher) { + t.Helper() + + datadir, err := ioutil.TempDir("", "netstore") + if err != nil { + t.Fatal(err) + } + naddr := make([]byte, 32) + params := NewDefaultLocalStoreParams() + params.Init(datadir) + params.BaseKey = naddr + localStore, err := NewTestLocalStoreForAddr(params) + if err != nil { + t.Fatal(err) + } + + fetcher := &mockNetFetcher{} + mockNetFetchFuncFactory := &mockNetFetchFuncFactory{ + fetcher: fetcher, + } + netStore, err := NewNetStore(localStore, mockNetFetchFuncFactory.newMockNetFetcher) + if err != nil { + t.Fatal(err) + } + return netStore, fetcher +} + +// TestNetStoreGetAndPut tests calling NetStore.Get which is blocked until the same chunk is Put. +// After the Put there should no active fetchers, and the context created for the fetcher should +// be cancelled. +func TestNetStoreGetAndPut(t *testing.T) { + netStore, fetcher := mustNewNetStoreWithFetcher(t) + + 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 { + putErrC <- errors.New("Expected netStore to use a fetcher for the Get call") + return + } + + err := netStore.Put(ctx, chunk) + if err != nil { + putErrC <- fmt.Errorf("Expected no err got %v", err) + return + } + + putErrC <- nil + }() + + close(c) + recChunk, err := netStore.Get(ctx, chunk.Address()) // this is blocked until the Put above is done + 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") + } + // the chunk is already available locally, so there should be no active fetchers waiting for it + if netStore.fetchers.Len() != 0 { + t.Fatal("Expected netStore to remove the fetcher after delivery") + } + + // A fetcher was created when the Get was called (and the chunk was not available). The chunk + // was delivered with the Put call, so the fetcher should be cancelled now. + select { + case <-fetcher.ctx.Done(): + default: + t.Fatal("Expected fetcher context to be cancelled") + } + +} + +// TestNetStoreGetAndPut tests calling NetStore.Put and then NetStore.Get. +// After the Put the chunk is available locally, so the Get can just retrieve it from LocalStore, +// there is no need to create fetchers. +func TestNetStoreGetAfterPut(t *testing.T) { + netStore, fetcher := mustNewNetStoreWithFetcher(t) + + chunk := GenerateRandomChunk(chunk.DefaultSize) + + ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) + defer cancel() + + // First we Put the chunk, so the chunk will be available locally + err := netStore.Put(ctx, chunk) + if err != nil { + t.Fatalf("Expected no err got %v", err) + } + + // Get should retrieve the chunk from LocalStore, without creating fetcher + recChunk, err := netStore.Get(ctx, chunk.Address()) + if err != nil { + t.Fatalf("Expected no err got %v", 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") + } + // no fetcher offer or request should be created for a locally available chunk + if fetcher.offerCalled || fetcher.requestCalled { + t.Fatal("NetFetcher.offerCalled or requestCalled not expected to be called") + } + // no fetchers should be created for a locally available chunk + if netStore.fetchers.Len() != 0 { + t.Fatal("Expected netStore to not have fetcher") + } + +} + +// TestNetStoreGetTimeout tests a Get call for an unavailable chunk and waits for timeout +func TestNetStoreGetTimeout(t *testing.T) { + netStore, fetcher := mustNewNetStoreWithFetcher(t) + + 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 { + fetcherErrC <- errors.New("Expected netStore to use a fetcher for the Get call") + return + } + + fetcherErrC <- nil + }() + + close(c) + // We call Get on this chunk, which is not in LocalStore. We don't Put it at all, so there will + // be a timeout + _, err := netStore.Get(ctx, chunk.Address()) + + // Check if the timeout happened + if err != context.DeadlineExceeded { + 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") + } + + // Check if the fetcher context has been cancelled after the timeout + select { + case <-fetcher.ctx.Done(): + default: + t.Fatal("Expected fetcher context to be cancelled") + } +} + +// TestNetStoreGetCancel tests a Get call for an unavailable chunk, then cancels the context and checks +// the errors +func TestNetStoreGetCancel(t *testing.T) { + netStore, fetcher := mustNewNetStoreWithFetcher(t) + + 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 { + 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) + } + + // A fetcher was created, check if it has been removed after cancel + if netStore.fetchers.Len() != 0 { + t.Fatal("Expected netStore to remove the fetcher after cancel") + } + + // Check if the fetcher context has been cancelled after the request context cancel + select { + case <-fetcher.ctx.Done(): + default: + t.Fatal("Expected fetcher context to be cancelled") + } +} + +// TestNetStoreMultipleGetAndPut tests four Get calls for the same unavailable chunk. The chunk is +// delivered with a Put, we have to make sure all Get calls return, and they use a single fetcher +// for the chunk retrieval +func TestNetStoreMultipleGetAndPut(t *testing.T) { + netStore, fetcher := mustNewNetStoreWithFetcher(t) + + 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 { + putErrC <- errors.New("Expected netStore to use one fetcher for all Get calls") + return + } + err := netStore.Put(ctx, chunk) + if err != nil { + 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. + errC := make(chan error) + for i := 0; i < count; i++ { + go func() { + recChunk, err := netStore.Get(ctx, chunk.Address()) + if err != nil { + errC <- fmt.Errorf("Expected no err got %v", err) + } + if !bytes.Equal(recChunk.Address(), chunk.Address()) || !bytes.Equal(recChunk.Data(), chunk.Data()) { + errC <- errors.New("Different chunk received than what was put") + } + errC <- nil + }() + } + + 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 + 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 + if netStore.fetchers.Len() != 0 { + t.Fatal("Expected netStore to remove the fetcher after delivery") + } + + // A fetcher was created, check if it has been removed after delivery + select { + case <-fetcher.ctx.Done(): + default: + t.Fatal("Expected fetcher context to be cancelled") + } + +} + +// TestNetStoreFetchFuncTimeout tests a FetchFunc call for an unavailable chunk and waits for timeout +func TestNetStoreFetchFuncTimeout(t *testing.T) { + netStore, fetcher := mustNewNetStoreWithFetcher(t) + + chunk := GenerateRandomChunk(chunk.DefaultSize) + + ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond) + defer cancel() + + // FetchFunc is called for an unavaible chunk, so the returned wait function should not be nil + wait := netStore.FetchFunc(ctx, chunk.Address()) + if wait == nil { + t.Fatal("Expected wait function to be not nil") + } + + // There should an active fetcher for the chunk after the FetchFunc call + if netStore.fetchers.Len() != 1 || netStore.getFetcher(chunk.Address()) == nil { + t.Fatalf("Expected netStore to have one fetcher for the requested chunk") + } + + // wait function should timeout because we don't deliver the chunk with a Put + err := wait(ctx) + if err != context.DeadlineExceeded { + t.Fatalf("Expected context.DeadLineExceeded err got %v", err) + } + + // the fetcher should be removed after timeout + if netStore.fetchers.Len() != 0 { + t.Fatal("Expected netStore to remove the fetcher after timeout") + } + + // the fetcher context should be cancelled after timeout + select { + case <-fetcher.ctx.Done(): + default: + t.Fatal("Expected fetcher context to be cancelled") + } +} + +// TestNetStoreFetchFuncAfterPut tests that the FetchFunc should return nil for a locally available chunk +func TestNetStoreFetchFuncAfterPut(t *testing.T) { + netStore := mustNewNetStore(t) + + chunk := GenerateRandomChunk(chunk.DefaultSize) + + ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) + defer cancel() + + // We deliver the created the chunk with a Put + err := netStore.Put(ctx, chunk) + if err != nil { + t.Fatalf("Expected no err got %v", err) + } + + // FetchFunc should return nil, because the chunk is available locally, no need to fetch it + wait := netStore.FetchFunc(ctx, chunk.Address()) + if wait != nil { + t.Fatal("Expected wait to be nil") + } + + // No fetchers should be created at all + if netStore.fetchers.Len() != 0 { + t.Fatal("Expected netStore to not have fetcher") + } +} + +// TestNetStoreGetCallsRequest tests if Get created a request on the NetFetcher for an unavailable chunk +func TestNetStoreGetCallsRequest(t *testing.T) { + netStore, fetcher := mustNewNetStoreWithFetcher(t) + + chunk := GenerateRandomChunk(chunk.DefaultSize) + + ctx := context.WithValue(context.Background(), "hopcount", uint8(5)) + ctx, cancel := context.WithTimeout(ctx, 200*time.Millisecond) + defer cancel() + + // We call get for a not available chunk, it will timeout because the chunk is not delivered + _, err := netStore.Get(ctx, chunk.Address()) + + if err != context.DeadlineExceeded { + t.Fatalf("Expected context.DeadlineExceeded err got %v", err) + } + + // NetStore should call NetFetcher.Request and wait for the chunk + if !fetcher.requestCalled { + t.Fatal("Expected NetFetcher.Request to be called") + } + + if fetcher.hopCounts[0] != 5 { + t.Fatalf("Expected NetFetcher.Request be called with hopCount 5, got %v", fetcher.hopCounts[0]) + } +} + +// TestNetStoreGetCallsOffer tests if Get created a request on the NetFetcher for an unavailable chunk +// in case of a source peer provided in the context. +func TestNetStoreGetCallsOffer(t *testing.T) { + netStore, fetcher := mustNewNetStoreWithFetcher(t) + + 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()) + ctx, cancel := context.WithTimeout(ctx, 200*time.Millisecond) + defer cancel() + + // We call get for a not available chunk, it will timeout because the chunk is not delivered + _, err := netStore.Get(ctx, chunk.Address()) + + if err != context.DeadlineExceeded { + t.Fatalf("Expect error %v got %v", context.DeadlineExceeded, err) + } + + // NetStore should call NetFetcher.Offer with the source peer + if !fetcher.offerCalled { + t.Fatal("Expected NetFetcher.Request to be called") + } + + if len(fetcher.sources) != 1 { + t.Fatalf("Expected fetcher sources length 1 got %v", len(fetcher.sources)) + } + + if fetcher.sources[0].String() != sourcePeerID.String() { + t.Fatalf("Expected fetcher source %v got %v", sourcePeerID, fetcher.sources[0]) + } + +} + +// TestNetStoreFetcherCountPeers tests multiple NetStore.Get calls with peer in the context. +// There is no Put call, so the Get calls timeout +func TestNetStoreFetcherCountPeers(t *testing.T) { + + netStore, fetcher := mustNewNetStoreWithFetcher(t) + + addr := randomAddr() + peers := []string{randomAddr().Hex(), randomAddr().Hex(), randomAddr().Hex()} + + ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) + defer cancel() + errC := make(chan error) + nrGets := 3 + + // Call Get 3 times with a peer in context + for i := 0; i < nrGets; i++ { + peer := peers[i] + go func() { + ctx := context.WithValue(ctx, "peer", peer) + _, err := netStore.Get(ctx, addr) + errC <- err + }() + } + + // All 3 Get calls should timeout + for i := 0; i < nrGets; i++ { + err := <-errC + if err != context.DeadlineExceeded { + t.Fatalf("Expected \"%v\" error got \"%v\"", context.DeadlineExceeded, err) + } + } + + // fetcher should be closed after timeout + select { + case <-fetcher.quit: + case <-time.After(3 * time.Second): + t.Fatalf("mockNetFetcher not closed after timeout") + } + + // All 3 peers should be given to NetFetcher after the 3 Get calls + if len(fetcher.peersPerRequest) != nrGets { + t.Fatalf("Expected 3 got %v", len(fetcher.peersPerRequest)) + } + + for i, peers := range fetcher.peersPerRequest { + if len(peers) < i+1 { + t.Fatalf("Expected at least %v got %v", i+1, len(peers)) + } + } +} + +// TestNetStoreFetchFuncCalledMultipleTimes calls the wait function given by FetchFunc three times, +// and checks there is still exactly one fetcher for one chunk. Afthe chunk is delivered, it checks +// if the fetcher is closed. +func TestNetStoreFetchFuncCalledMultipleTimes(t *testing.T) { + netStore, fetcher := mustNewNetStoreWithFetcher(t) + + chunk := GenerateRandomChunk(chunk.DefaultSize) + + ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) + defer cancel() + + // FetchFunc should return a non-nil wait function, because the chunk is not available + wait := netStore.FetchFunc(ctx, chunk.Address()) + if wait == nil { + t.Fatal("Expected wait function to be not nil") + } + + // There should be exactly one fetcher for the chunk + if netStore.fetchers.Len() != 1 || netStore.getFetcher(chunk.Address()) == nil { + t.Fatalf("Expected netStore to have one fetcher for the requested chunk") + } + + // Call wait three times in parallel + count := 3 + errC := make(chan error) + for i := 0; i < count; i++ { + go func() { + errC <- wait(ctx) + }() + } + + // sleep a little so the wait functions are called above + time.Sleep(100 * time.Millisecond) + + // there should be still only one fetcher, because all wait calls are for the same chunk + if netStore.fetchers.Len() != 1 || netStore.getFetcher(chunk.Address()) == nil { + t.Fatal("Expected netStore to have one fetcher for the requested chunk") + } + + // Deliver the chunk with a Put + err := netStore.Put(ctx, chunk) + if err != nil { + t.Fatalf("Expected no err got %v", err) + } + + // wait until all wait calls return (because the chunk is delivered) + 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 { + t.Fatal("Expected netStore to remove the fetcher after delivery") + } + + // The context for the fetcher should be cancelled after delivery + select { + case <-fetcher.ctx.Done(): + default: + t.Fatal("Expected fetcher context to be cancelled") + } +} + +// TestNetStoreFetcherLifeCycleWithTimeout is similar to TestNetStoreFetchFuncCalledMultipleTimes, +// the only difference is that we don't deilver the chunk, just wait for timeout +func TestNetStoreFetcherLifeCycleWithTimeout(t *testing.T) { + netStore, fetcher := mustNewNetStoreWithFetcher(t) + + chunk := GenerateRandomChunk(chunk.DefaultSize) + + ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) + defer cancel() + + // FetchFunc should return a non-nil wait function, because the chunk is not available + wait := netStore.FetchFunc(ctx, chunk.Address()) + if wait == nil { + t.Fatal("Expected wait function to be not nil") + } + + // There should be exactly one fetcher for the chunk + if netStore.fetchers.Len() != 1 || netStore.getFetcher(chunk.Address()) == nil { + t.Fatalf("Expected netStore to have one fetcher for the requested chunk") + } + + // Call wait three times in parallel + count := 3 + errC := make(chan error) + for i := 0; i < count; i++ { + go func() { + rctx, rcancel := context.WithTimeout(context.Background(), 100*time.Millisecond) + defer rcancel() + err := wait(rctx) + if err != context.DeadlineExceeded { + errC <- fmt.Errorf("Expected err %v got %v", context.DeadlineExceeded, err) + return + } + errC <- nil + }() + } + + // wait until all wait calls timeout + 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 { + t.Fatal("Expected netStore to remove the fetcher after delivery") + } + + // The context for the fetcher should be cancelled after timeout + select { + case <-fetcher.ctx.Done(): + default: + t.Fatal("Expected fetcher context to be cancelled") + } +} + +func randomAddr() Address { + addr := make([]byte, 32) + rand.Read(addr) + return Address(addr) +} diff --git a/swarm/storage/pyramid.go b/swarm/storage/pyramid.go index 19d493405a..281bbe9fe3 100644 --- a/swarm/storage/pyramid.go +++ b/swarm/storage/pyramid.go @@ -17,11 +17,16 @@ package storage import ( + "context" "encoding/binary" "errors" "io" + "io/ioutil" "sync" "time" + + "github.com/ethereum/go-ethereum/swarm/chunk" + "github.com/ethereum/go-ethereum/swarm/log" ) /* @@ -52,7 +57,7 @@ import ( When certain no of data chunks are created (defaultBranches), a signal is sent to create a tree entry. When the level 0 tree entries reaches certain threshold (defaultBranches), another signal is sent to a tree entry one level up.. and so on... until only the data is exhausted AND only one - tree entry is present in certain level. The key of tree entry is given out as the rootKey of the file. + tree entry is present in certain level. The key of tree entry is given out as the rootAddress of the file. */ @@ -62,28 +67,43 @@ var ( ) const ( - ChunkProcessors = 8 - DefaultBranches int64 = 128 - splitTimeout = time.Minute * 5 + ChunkProcessors = 8 + splitTimeout = time.Minute * 5 ) -const ( - DataChunk = 0 - TreeChunk = 1 -) - -type ChunkerParams struct { - Branches int64 - Hash string +type PyramidSplitterParams struct { + SplitterParams + getter Getter } -func NewChunkerParams() *ChunkerParams { - return &ChunkerParams{ - Branches: DefaultBranches, - Hash: SHA3Hash, +func NewPyramidSplitterParams(addr Address, reader io.Reader, putter Putter, getter Getter, chunkSize int64) *PyramidSplitterParams { + hashSize := putter.RefSize() + return &PyramidSplitterParams{ + SplitterParams: SplitterParams{ + ChunkerParams: ChunkerParams{ + chunkSize: chunkSize, + hashSize: hashSize, + }, + reader: reader, + putter: putter, + addr: addr, + }, + getter: getter, } } +/* + When splitting, data is given as a SectionReader, and the key is a hashSize long byte slice (Address), the root hash of the entire content will fill this once processing finishes. + 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, 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, chunk.DefaultSize)).Append(ctx) +} + // Entry to create a tree node type TreeEntry struct { level int @@ -109,264 +129,249 @@ func NewTreeEntry(pyramid *PyramidChunker) *TreeEntry { // Used by the hash processor to create a data/tree chunk and send to storage type chunkJob struct { - key Key - chunk []byte - size int64 - parentWg *sync.WaitGroup - chunkType int // used to identify the tree related chunks for debugging - chunkLvl int // leaf-1 is level 0 and goes upwards until it reaches root + key Address + chunk []byte + parentWg *sync.WaitGroup } type PyramidChunker struct { - hashFunc SwarmHasher chunkSize int64 hashSize int64 branches int64 + reader io.Reader + putter Putter + getter Getter + key Address workerCount int64 workerLock sync.RWMutex + jobC chan *chunkJob + wg *sync.WaitGroup + errC chan error + quitC chan bool + rootAddress []byte + chunkLevel [][]*TreeEntry } -func NewPyramidChunker(params *ChunkerParams) (self *PyramidChunker) { - self = &PyramidChunker{} - self.hashFunc = MakeHashFunc(params.Hash) - self.branches = params.Branches - self.hashSize = int64(self.hashFunc().Size()) - self.chunkSize = self.hashSize * self.branches - self.workerCount = 0 +func NewPyramidSplitter(params *PyramidSplitterParams) (pc *PyramidChunker) { + pc = &PyramidChunker{} + pc.reader = params.reader + pc.hashSize = params.hashSize + pc.branches = params.chunkSize / pc.hashSize + pc.chunkSize = pc.hashSize * pc.branches + pc.putter = params.putter + pc.getter = params.getter + pc.key = params.addr + pc.workerCount = 0 + pc.jobC = make(chan *chunkJob, 2*ChunkProcessors) + pc.wg = &sync.WaitGroup{} + pc.errC = make(chan error) + pc.quitC = make(chan bool) + pc.rootAddress = make([]byte, pc.hashSize) + pc.chunkLevel = make([][]*TreeEntry, pc.branches) return } -func (self *PyramidChunker) Join(key Key, chunkC chan *Chunk) LazySectionReader { +func (pc *PyramidChunker) Join(addr Address, getter Getter, depth int) LazySectionReader { return &LazyChunkReader{ - key: key, - chunkC: chunkC, - chunkSize: self.chunkSize, - branches: self.branches, - hashSize: self.hashSize, + addr: addr, + depth: depth, + chunkSize: pc.chunkSize, + branches: pc.branches, + hashSize: pc.hashSize, + getter: getter, } } -func (self *PyramidChunker) incrementWorkerCount() { - self.workerLock.Lock() - defer self.workerLock.Unlock() - self.workerCount += 1 +func (pc *PyramidChunker) incrementWorkerCount() { + pc.workerLock.Lock() + defer pc.workerLock.Unlock() + pc.workerCount += 1 } -func (self *PyramidChunker) getWorkerCount() int64 { - self.workerLock.Lock() - defer self.workerLock.Unlock() - return self.workerCount +func (pc *PyramidChunker) getWorkerCount() int64 { + pc.workerLock.Lock() + defer pc.workerLock.Unlock() + return pc.workerCount } -func (self *PyramidChunker) decrementWorkerCount() { - self.workerLock.Lock() - defer self.workerLock.Unlock() - self.workerCount -= 1 +func (pc *PyramidChunker) decrementWorkerCount() { + pc.workerLock.Lock() + defer pc.workerLock.Unlock() + pc.workerCount -= 1 } -func (self *PyramidChunker) Split(data io.Reader, size int64, chunkC chan *Chunk, storageWG, processorWG *sync.WaitGroup) (Key, error) { - jobC := make(chan *chunkJob, 2*ChunkProcessors) - wg := &sync.WaitGroup{} - errC := make(chan error) - quitC := make(chan bool) - rootKey := make([]byte, self.hashSize) - chunkLevel := make([][]*TreeEntry, self.branches) - - wg.Add(1) - go self.prepareChunks(false, chunkLevel, data, rootKey, quitC, wg, jobC, processorWG, chunkC, errC, storageWG) +func (pc *PyramidChunker) Split(ctx context.Context) (k Address, wait func(context.Context) error, err error) { + pc.wg.Add(1) + pc.prepareChunks(ctx, false) // closes internal error channel if all subprocesses in the workgroup finished go func() { // waiting for all chunks to finish - wg.Wait() + pc.wg.Wait() - // if storage waitgroup is non-nil, we wait for storage to finish too - if storageWG != nil { - storageWG.Wait() - } //We close errC here because this is passed down to 8 parallel routines underneath. // if a error happens in one of them.. that particular routine raises error... // once they all complete successfully, the control comes back and we can safely close this here. - close(errC) + close(pc.errC) }() - defer close(quitC) + defer close(pc.quitC) + defer pc.putter.Close() select { - case err := <-errC: + case err := <-pc.errC: if err != nil { - return nil, err + return nil, nil, err } - case <-time.NewTimer(splitTimeout).C: + case <-ctx.Done(): + _ = pc.putter.Wait(ctx) //??? + return nil, nil, ctx.Err() } - return rootKey, nil + return pc.rootAddress, pc.putter.Wait, nil } -func (self *PyramidChunker) Append(key Key, data io.Reader, chunkC chan *Chunk, storageWG, processorWG *sync.WaitGroup) (Key, error) { - quitC := make(chan bool) - rootKey := make([]byte, self.hashSize) - chunkLevel := make([][]*TreeEntry, self.branches) - +func (pc *PyramidChunker) Append(ctx context.Context) (k Address, wait func(context.Context) error, err error) { // Load the right most unfinished tree chunks in every level - self.loadTree(chunkLevel, key, chunkC, quitC) + pc.loadTree(ctx) - jobC := make(chan *chunkJob, 2*ChunkProcessors) - wg := &sync.WaitGroup{} - errC := make(chan error) - - wg.Add(1) - go self.prepareChunks(true, chunkLevel, data, rootKey, quitC, wg, jobC, processorWG, chunkC, errC, storageWG) + pc.wg.Add(1) + pc.prepareChunks(ctx, true) // closes internal error channel if all subprocesses in the workgroup finished go func() { // waiting for all chunks to finish - wg.Wait() + pc.wg.Wait() - // if storage waitgroup is non-nil, we wait for storage to finish too - if storageWG != nil { - storageWG.Wait() - } - close(errC) + close(pc.errC) }() - defer close(quitC) + defer close(pc.quitC) + defer pc.putter.Close() select { - case err := <-errC: + case err := <-pc.errC: if err != nil { - return nil, err + return nil, nil, err } case <-time.NewTimer(splitTimeout).C: } - return rootKey, nil + + return pc.rootAddress, pc.putter.Wait, nil } -func (self *PyramidChunker) processor(id int64, jobC chan *chunkJob, chunkC chan *Chunk, errC chan error, quitC chan bool, swg, wwg *sync.WaitGroup) { - defer self.decrementWorkerCount() - - hasher := self.hashFunc() - if wwg != nil { - defer wwg.Done() - } +func (pc *PyramidChunker) processor(ctx context.Context, id int64) { + defer pc.decrementWorkerCount() for { select { - case job, ok := <-jobC: + case job, ok := <-pc.jobC: if !ok { return } - self.processChunk(id, hasher, job, chunkC, swg) - case <-quitC: + pc.processChunk(ctx, id, job) + case <-pc.quitC: return } } } -func (self *PyramidChunker) processChunk(id int64, hasher SwarmHash, job *chunkJob, chunkC chan *Chunk, swg *sync.WaitGroup) { - hasher.ResetWithLength(job.chunk[:8]) // 8 bytes of length - hasher.Write(job.chunk[8:]) // minus 8 []byte length - h := hasher.Sum(nil) - - newChunk := &Chunk{ - Key: h, - SData: job.chunk, - Size: job.size, - wg: swg, +func (pc *PyramidChunker) processChunk(ctx context.Context, id int64, job *chunkJob) { + ref, err := pc.putter.Put(ctx, job.chunk) + if err != nil { + select { + case pc.errC <- err: + case <-pc.quitC: + } } // report hash of this chunk one level up (keys corresponds to the proper subslice of the parent chunk) - copy(job.key, h) + copy(job.key, ref) // send off new chunk to storage - if chunkC != nil { - if swg != nil { - swg.Add(1) - } - } job.parentWg.Done() - - if chunkC != nil { - chunkC <- newChunk - } } -func (self *PyramidChunker) loadTree(chunkLevel [][]*TreeEntry, key Key, chunkC chan *Chunk, quitC chan bool) error { +func (pc *PyramidChunker) loadTree(ctx context.Context) error { // Get the root chunk to get the total size - chunk := retrieve(key, chunkC, quitC) - if chunk == nil { + chunkData, err := pc.getter.Get(ctx, Reference(pc.key)) + if err != nil { return errLoadingTreeRootChunk } + chunkSize := int64(chunkData.Size()) + log.Trace("pyramid.chunker: root chunk", "chunk.Size", chunkSize, "pc.chunkSize", pc.chunkSize) //if data size is less than a chunk... add a parent with update as pending - if chunk.Size <= self.chunkSize { + if chunkSize <= pc.chunkSize { newEntry := &TreeEntry{ level: 0, branchCount: 1, - subtreeSize: uint64(chunk.Size), - chunk: make([]byte, self.chunkSize+8), - key: make([]byte, self.hashSize), + subtreeSize: uint64(chunkSize), + chunk: make([]byte, pc.chunkSize+8), + key: make([]byte, pc.hashSize), index: 0, updatePending: true, } - copy(newEntry.chunk[8:], chunk.Key) - chunkLevel[0] = append(chunkLevel[0], newEntry) + copy(newEntry.chunk[8:], pc.key) + pc.chunkLevel[0] = append(pc.chunkLevel[0], newEntry) return nil } var treeSize int64 var depth int - treeSize = self.chunkSize - for ; treeSize < chunk.Size; treeSize *= self.branches { + treeSize = pc.chunkSize + for ; treeSize < chunkSize; treeSize *= pc.branches { depth++ } + log.Trace("pyramid.chunker", "depth", depth) // Add the root chunk entry - branchCount := int64(len(chunk.SData)-8) / self.hashSize + branchCount := int64(len(chunkData)-8) / pc.hashSize newEntry := &TreeEntry{ level: depth - 1, branchCount: branchCount, - subtreeSize: uint64(chunk.Size), - chunk: chunk.SData, - key: key, + subtreeSize: uint64(chunkSize), + chunk: chunkData, + key: pc.key, index: 0, updatePending: true, } - chunkLevel[depth-1] = append(chunkLevel[depth-1], newEntry) + pc.chunkLevel[depth-1] = append(pc.chunkLevel[depth-1], newEntry) // Add the rest of the tree for lvl := depth - 1; lvl >= 1; lvl-- { //TODO(jmozah): instead of loading finished branches and then trim in the end, //avoid loading them in the first place - for _, ent := range chunkLevel[lvl] { - branchCount = int64(len(ent.chunk)-8) / self.hashSize + for _, ent := range pc.chunkLevel[lvl] { + branchCount = int64(len(ent.chunk)-8) / pc.hashSize for i := int64(0); i < branchCount; i++ { - key := ent.chunk[8+(i*self.hashSize) : 8+((i+1)*self.hashSize)] - newChunk := retrieve(key, chunkC, quitC) - if newChunk == nil { + key := ent.chunk[8+(i*pc.hashSize) : 8+((i+1)*pc.hashSize)] + newChunkData, err := pc.getter.Get(ctx, Reference(key)) + if err != nil { return errLoadingTreeChunk } - bewBranchCount := int64(len(newChunk.SData)-8) / self.hashSize + newChunkSize := newChunkData.Size() + bewBranchCount := int64(len(newChunkData)-8) / pc.hashSize newEntry := &TreeEntry{ level: lvl - 1, branchCount: bewBranchCount, - subtreeSize: uint64(newChunk.Size), - chunk: newChunk.SData, + subtreeSize: newChunkSize, + chunk: newChunkData, key: key, index: 0, updatePending: true, } - chunkLevel[lvl-1] = append(chunkLevel[lvl-1], newEntry) + pc.chunkLevel[lvl-1] = append(pc.chunkLevel[lvl-1], newEntry) } // We need to get only the right most unfinished branch.. so trim all finished branches - if int64(len(chunkLevel[lvl-1])) >= self.branches { - chunkLevel[lvl-1] = nil + if int64(len(pc.chunkLevel[lvl-1])) >= pc.branches { + pc.chunkLevel[lvl-1] = nil } } } @@ -374,29 +379,24 @@ func (self *PyramidChunker) loadTree(chunkLevel [][]*TreeEntry, key Key, chunkC return nil } -func (self *PyramidChunker) prepareChunks(isAppend bool, chunkLevel [][]*TreeEntry, data io.Reader, rootKey []byte, quitC chan bool, wg *sync.WaitGroup, jobC chan *chunkJob, processorWG *sync.WaitGroup, chunkC chan *Chunk, errC chan error, storageWG *sync.WaitGroup) { - defer wg.Done() +func (pc *PyramidChunker) prepareChunks(ctx context.Context, isAppend bool) { + defer pc.wg.Done() chunkWG := &sync.WaitGroup{} - totalDataSize := 0 - // processorWG keeps track of workers spawned for hashing chunks - if processorWG != nil { - processorWG.Add(1) - } + pc.incrementWorkerCount() - self.incrementWorkerCount() - go self.processor(self.workerCount, jobC, chunkC, errC, quitC, storageWG, processorWG) + go pc.processor(ctx, pc.workerCount) - parent := NewTreeEntry(self) - var unFinishedChunk *Chunk + parent := NewTreeEntry(pc) + var unfinishedChunkData ChunkData + var unfinishedChunkSize uint64 - if isAppend && len(chunkLevel[0]) != 0 { + if isAppend && len(pc.chunkLevel[0]) != 0 { + lastIndex := len(pc.chunkLevel[0]) - 1 + ent := pc.chunkLevel[0][lastIndex] - lastIndex := len(chunkLevel[0]) - 1 - ent := chunkLevel[0][lastIndex] - - if ent.branchCount < self.branches { + if ent.branchCount < pc.branches { parent = &TreeEntry{ level: 0, branchCount: ent.branchCount, @@ -408,104 +408,132 @@ func (self *PyramidChunker) prepareChunks(isAppend bool, chunkLevel [][]*TreeEnt } lastBranch := parent.branchCount - 1 - lastKey := parent.chunk[8+lastBranch*self.hashSize : 8+(lastBranch+1)*self.hashSize] + lastAddress := parent.chunk[8+lastBranch*pc.hashSize : 8+(lastBranch+1)*pc.hashSize] - unFinishedChunk = retrieve(lastKey, chunkC, quitC) - if unFinishedChunk.Size < self.chunkSize { - - parent.subtreeSize = parent.subtreeSize - uint64(unFinishedChunk.Size) + var err error + unfinishedChunkData, err = pc.getter.Get(ctx, lastAddress) + if err != nil { + pc.errC <- err + } + unfinishedChunkSize = unfinishedChunkData.Size() + if unfinishedChunkSize < uint64(pc.chunkSize) { + parent.subtreeSize = parent.subtreeSize - unfinishedChunkSize parent.branchCount = parent.branchCount - 1 } else { - unFinishedChunk = nil + unfinishedChunkData = nil } } } for index := 0; ; index++ { - - var n int var err error - chunkData := make([]byte, self.chunkSize+8) - if unFinishedChunk != nil { - copy(chunkData, unFinishedChunk.SData) - n, err = data.Read(chunkData[8+unFinishedChunk.Size:]) - n += int(unFinishedChunk.Size) - unFinishedChunk = nil - } else { - n, err = data.Read(chunkData[8:]) + chunkData := make([]byte, pc.chunkSize+8) + + var readBytes int + + if unfinishedChunkData != nil { + copy(chunkData, unfinishedChunkData) + readBytes += int(unfinishedChunkSize) + unfinishedChunkData = nil + log.Trace("pyramid.chunker: found unfinished chunk", "readBytes", readBytes) } - totalDataSize += n + var res []byte + res, err = ioutil.ReadAll(io.LimitReader(pc.reader, int64(len(chunkData)-(8+readBytes)))) + + // hack for ioutil.ReadAll: + // a successful call to ioutil.ReadAll returns err == nil, not err == EOF, whereas we + // want to propagate the io.EOF error + if len(res) == 0 && err == nil { + err = io.EOF + } + copy(chunkData[8+readBytes:], res) + + readBytes += len(res) + log.Trace("pyramid.chunker: copied all data", "readBytes", readBytes) + if err != nil { if err == io.EOF || err == io.ErrUnexpectedEOF { - if parent.branchCount == 1 { + + pc.cleanChunkLevels() + + // Check if we are appending or the chunk is the only one. + if parent.branchCount == 1 && (pc.depth() == 0 || isAppend) { // Data is exactly one chunk.. pick the last chunk key as root chunkWG.Wait() - lastChunksKey := parent.chunk[8 : 8+self.hashSize] - copy(rootKey, lastChunksKey) + lastChunksAddress := parent.chunk[8 : 8+pc.hashSize] + copy(pc.rootAddress, lastChunksAddress) break } } else { - close(quitC) + close(pc.quitC) break } } // Data ended in chunk boundary.. just signal to start bulding tree - if n == 0 { - self.buildTree(isAppend, chunkLevel, parent, chunkWG, jobC, quitC, true, rootKey) + if readBytes == 0 { + pc.buildTree(isAppend, parent, chunkWG, true, nil) break } else { - - pkey := self.enqueueDataChunk(chunkData, uint64(n), parent, chunkWG, jobC, quitC) + pkey := pc.enqueueDataChunk(chunkData, uint64(readBytes), parent, chunkWG) // update tree related parent data structures - parent.subtreeSize += uint64(n) + parent.subtreeSize += uint64(readBytes) parent.branchCount++ // Data got exhausted... signal to send any parent tree related chunks - if int64(n) < self.chunkSize { + if int64(readBytes) < pc.chunkSize { + + pc.cleanChunkLevels() // only one data chunk .. so dont add any parent chunk if parent.branchCount <= 1 { chunkWG.Wait() - copy(rootKey, pkey) + + if isAppend || pc.depth() == 0 { + // No need to build the tree if the depth is 0 + // or we are appending. + // Just use the last key. + copy(pc.rootAddress, pkey) + } else { + // We need to build the tree and and provide the lonely + // chunk key to replace the last tree chunk key. + pc.buildTree(isAppend, parent, chunkWG, true, pkey) + } break } - self.buildTree(isAppend, chunkLevel, parent, chunkWG, jobC, quitC, true, rootKey) + pc.buildTree(isAppend, parent, chunkWG, true, nil) break } - if parent.branchCount == self.branches { - self.buildTree(isAppend, chunkLevel, parent, chunkWG, jobC, quitC, false, rootKey) - parent = NewTreeEntry(self) + if parent.branchCount == pc.branches { + pc.buildTree(isAppend, parent, chunkWG, false, nil) + parent = NewTreeEntry(pc) } } - workers := self.getWorkerCount() - if int64(len(jobC)) > workers && workers < ChunkProcessors { - if processorWG != nil { - processorWG.Add(1) - } - self.incrementWorkerCount() - go self.processor(self.workerCount, jobC, chunkC, errC, quitC, storageWG, processorWG) + workers := pc.getWorkerCount() + if int64(len(pc.jobC)) > workers && workers < ChunkProcessors { + pc.incrementWorkerCount() + go pc.processor(ctx, pc.workerCount) } } } -func (self *PyramidChunker) buildTree(isAppend bool, chunkLevel [][]*TreeEntry, ent *TreeEntry, chunkWG *sync.WaitGroup, jobC chan *chunkJob, quitC chan bool, last bool, rootKey []byte) { +func (pc *PyramidChunker) buildTree(isAppend bool, ent *TreeEntry, chunkWG *sync.WaitGroup, last bool, lonelyChunkKey []byte) { chunkWG.Wait() - self.enqueueTreeChunk(chunkLevel, ent, chunkWG, jobC, quitC, last) + pc.enqueueTreeChunk(ent, chunkWG, last) compress := false - endLvl := self.branches - for lvl := int64(0); lvl < self.branches; lvl++ { - lvlCount := int64(len(chunkLevel[lvl])) - if lvlCount >= self.branches { + endLvl := pc.branches + for lvl := int64(0); lvl < pc.branches; lvl++ { + lvlCount := int64(len(pc.chunkLevel[lvl])) + if lvlCount >= pc.branches { endLvl = lvl + 1 compress = true break @@ -521,42 +549,42 @@ func (self *PyramidChunker) buildTree(isAppend bool, chunkLevel [][]*TreeEntry, for lvl := int64(ent.level); lvl < endLvl; lvl++ { - lvlCount := int64(len(chunkLevel[lvl])) + lvlCount := int64(len(pc.chunkLevel[lvl])) if lvlCount == 1 && last { - copy(rootKey, chunkLevel[lvl][0].key) + copy(pc.rootAddress, pc.chunkLevel[lvl][0].key) return } - for startCount := int64(0); startCount < lvlCount; startCount += self.branches { + for startCount := int64(0); startCount < lvlCount; startCount += pc.branches { - endCount := startCount + self.branches + endCount := startCount + pc.branches if endCount > lvlCount { endCount = lvlCount } var nextLvlCount int64 var tempEntry *TreeEntry - if len(chunkLevel[lvl+1]) > 0 { - nextLvlCount = int64(len(chunkLevel[lvl+1]) - 1) - tempEntry = chunkLevel[lvl+1][nextLvlCount] + if len(pc.chunkLevel[lvl+1]) > 0 { + nextLvlCount = int64(len(pc.chunkLevel[lvl+1]) - 1) + tempEntry = pc.chunkLevel[lvl+1][nextLvlCount] } if isAppend && tempEntry != nil && tempEntry.updatePending { updateEntry := &TreeEntry{ level: int(lvl + 1), branchCount: 0, subtreeSize: 0, - chunk: make([]byte, self.chunkSize+8), - key: make([]byte, self.hashSize), + chunk: make([]byte, pc.chunkSize+8), + key: make([]byte, pc.hashSize), index: int(nextLvlCount), updatePending: true, } for index := int64(0); index < lvlCount; index++ { updateEntry.branchCount++ - updateEntry.subtreeSize += chunkLevel[lvl][index].subtreeSize - copy(updateEntry.chunk[8+(index*self.hashSize):8+((index+1)*self.hashSize)], chunkLevel[lvl][index].key[:self.hashSize]) + updateEntry.subtreeSize += pc.chunkLevel[lvl][index].subtreeSize + copy(updateEntry.chunk[8+(index*pc.hashSize):8+((index+1)*pc.hashSize)], pc.chunkLevel[lvl][index].key[:pc.hashSize]) } - self.enqueueTreeChunk(chunkLevel, updateEntry, chunkWG, jobC, quitC, last) + pc.enqueueTreeChunk(updateEntry, chunkWG, last) } else { @@ -565,21 +593,27 @@ func (self *PyramidChunker) buildTree(isAppend bool, chunkLevel [][]*TreeEntry, level: int(lvl + 1), branchCount: noOfBranches, subtreeSize: 0, - chunk: make([]byte, (noOfBranches*self.hashSize)+8), - key: make([]byte, self.hashSize), + chunk: make([]byte, (noOfBranches*pc.hashSize)+8), + key: make([]byte, pc.hashSize), index: int(nextLvlCount), updatePending: false, } index := int64(0) for i := startCount; i < endCount; i++ { - entry := chunkLevel[lvl][i] + entry := pc.chunkLevel[lvl][i] newEntry.subtreeSize += entry.subtreeSize - copy(newEntry.chunk[8+(index*self.hashSize):8+((index+1)*self.hashSize)], entry.key[:self.hashSize]) + copy(newEntry.chunk[8+(index*pc.hashSize):8+((index+1)*pc.hashSize)], entry.key[:pc.hashSize]) index++ } + // Lonely chunk key is the key of the last chunk that is only one on the last branch. + // In this case, ignore the its tree chunk key and replace it with the lonely chunk key. + if lonelyChunkKey != nil { + // Overwrite the last tree chunk key with the lonely data chunk key. + copy(newEntry.chunk[int64(len(newEntry.chunk))-pc.hashSize:], lonelyChunkKey[:pc.hashSize]) + } - self.enqueueTreeChunk(chunkLevel, newEntry, chunkWG, jobC, quitC, last) + pc.enqueueTreeChunk(newEntry, chunkWG, last) } @@ -588,15 +622,15 @@ func (self *PyramidChunker) buildTree(isAppend bool, chunkLevel [][]*TreeEntry, if !isAppend { chunkWG.Wait() if compress { - chunkLevel[lvl] = nil + pc.chunkLevel[lvl] = nil } } } } -func (self *PyramidChunker) enqueueTreeChunk(chunkLevel [][]*TreeEntry, ent *TreeEntry, chunkWG *sync.WaitGroup, jobC chan *chunkJob, quitC chan bool, last bool) { - if ent != nil { +func (pc *PyramidChunker) enqueueTreeChunk(ent *TreeEntry, chunkWG *sync.WaitGroup, last bool) { + if ent != nil && ent.branchCount > 0 { // wait for data chunks to get over before processing the tree chunk if last { @@ -604,34 +638,57 @@ func (self *PyramidChunker) enqueueTreeChunk(chunkLevel [][]*TreeEntry, ent *Tre } binary.LittleEndian.PutUint64(ent.chunk[:8], ent.subtreeSize) - ent.key = make([]byte, self.hashSize) + ent.key = make([]byte, pc.hashSize) chunkWG.Add(1) select { - case jobC <- &chunkJob{ent.key, ent.chunk[:ent.branchCount*self.hashSize+8], int64(ent.subtreeSize), chunkWG, TreeChunk, 0}: - case <-quitC: + case pc.jobC <- &chunkJob{ent.key, ent.chunk[:ent.branchCount*pc.hashSize+8], chunkWG}: + case <-pc.quitC: } // Update or append based on weather it is a new entry or being reused if ent.updatePending { chunkWG.Wait() - chunkLevel[ent.level][ent.index] = ent + pc.chunkLevel[ent.level][ent.index] = ent } else { - chunkLevel[ent.level] = append(chunkLevel[ent.level], ent) + pc.chunkLevel[ent.level] = append(pc.chunkLevel[ent.level], ent) } } } -func (self *PyramidChunker) enqueueDataChunk(chunkData []byte, size uint64, parent *TreeEntry, chunkWG *sync.WaitGroup, jobC chan *chunkJob, quitC chan bool) Key { +func (pc *PyramidChunker) enqueueDataChunk(chunkData []byte, size uint64, parent *TreeEntry, chunkWG *sync.WaitGroup) Address { binary.LittleEndian.PutUint64(chunkData[:8], size) - pkey := parent.chunk[8+parent.branchCount*self.hashSize : 8+(parent.branchCount+1)*self.hashSize] + pkey := parent.chunk[8+parent.branchCount*pc.hashSize : 8+(parent.branchCount+1)*pc.hashSize] chunkWG.Add(1) select { - case jobC <- &chunkJob{pkey, chunkData[:size+8], int64(size), chunkWG, DataChunk, -1}: - case <-quitC: + case pc.jobC <- &chunkJob{pkey, chunkData[:size+8], chunkWG}: + case <-pc.quitC: } return pkey } + +// depth returns the number of chunk levels. +// It is used to detect if there is only one data chunk +// left for the last branch. +func (pc *PyramidChunker) depth() (d int) { + for _, l := range pc.chunkLevel { + if l == nil { + return + } + d++ + } + return +} + +// cleanChunkLevels removes gaps (nil levels) between chunk levels +// that are not nil. +func (pc *PyramidChunker) cleanChunkLevels() { + for i, l := range pc.chunkLevel { + if l == nil { + pc.chunkLevel = append(pc.chunkLevel[:i], append(pc.chunkLevel[i+1:], nil)...) + } + } +} diff --git a/swarm/storage/schema.go b/swarm/storage/schema.go new file mode 100644 index 0000000000..91847ca0f9 --- /dev/null +++ b/swarm/storage/schema.go @@ -0,0 +1,17 @@ +package storage + +// The DB schema we want to use. The actual/current DB schema might differ +// until migrations are run. +const CurrentDbSchema = DbSchemaHalloween + +// There was a time when we had no schema at all. +const DbSchemaNone = "" + +// "purity" is the first formal schema of LevelDB we release together with Swarm 0.3.5 +const DbSchemaPurity = "purity" + +// "halloween" is here because we had a screw in the garbage collector index. +// Because of that we had to rebuild the GC index to get rid of erroneous +// entries and that takes a long time. This schema is used for bookkeeping, +// so rebuild index will run just once. +const DbSchemaHalloween = "halloween" diff --git a/swarm/storage/swarmhasher.go b/swarm/storage/swarmhasher.go index 38b86373c5..fae03f0c72 100644 --- a/swarm/storage/swarmhasher.go +++ b/swarm/storage/swarmhasher.go @@ -21,8 +21,9 @@ import ( ) const ( - BMTHash = "BMT" - SHA3Hash = "SHA3" // http://golang.org/pkg/hash/#Hash + BMTHash = "BMT" + SHA3Hash = "SHA3" // http://golang.org/pkg/hash/#Hash + DefaultHash = BMTHash ) type SwarmHash interface { @@ -34,7 +35,7 @@ type HashWithLength struct { hash.Hash } -func (self *HashWithLength) ResetWithLength(length []byte) { - self.Reset() - self.Write(length) +func (h *HashWithLength) ResetWithLength(length []byte) { + h.Reset() + h.Write(length) } diff --git a/swarm/storage/types.go b/swarm/storage/types.go index d35f1f9294..2f39685b42 100644 --- a/swarm/storage/types.go +++ b/swarm/storage/types.go @@ -18,222 +18,98 @@ package storage import ( "bytes" + "context" "crypto" - "fmt" - "hash" + "crypto/rand" + "encoding/binary" "io" - "sync" - "github.com/ethereum/go-ethereum/bmt" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto/sha3" + "github.com/ethereum/go-ethereum/swarm/bmt" + "github.com/ethereum/go-ethereum/swarm/chunk" + "golang.org/x/crypto/sha3" ) -type Hasher func() hash.Hash +// 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 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 Key []byte +// Proximity is the same as chunk.Proximity for backward compatibility. +var Proximity = chunk.Proximity -func (x Key) Size() uint { - return uint(len(x)) -} - -func (x Key) isEqual(y Key) bool { - return bytes.Equal(x, y) -} - -func (h Key) bits(i, j uint) uint { - ii := i >> 3 - jj := i & 7 - if ii >= h.Size() { - return 0 - } - - if jj+j <= 8 { - return uint((h[ii] >> jj) & ((1 << j) - 1)) - } - - res := uint(h[ii] >> jj) - jj = 8 - jj - j -= jj - for j != 0 { - ii++ - if j < 8 { - res += uint(h[ii]&((1< chunk.DefaultSize+8 { + // log.Error("invalid chunk size", "chunk", addr.Hex(), "size", l) + return false + } + + hasher := v.Hasher() + hasher.ResetWithLength(data[:8]) + hasher.Write(data[8:]) + hash := hasher.Sum(nil) + + 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() +} + +// SyncChunkStore is a ChunkStore which supports syncing +type SyncChunkStore interface { + ChunkStore + BinIndex(po uint8) uint64 + Iterator(from uint64, to uint64, po uint8, f func(Address, uint64) bool) error + FetchFunc(ctx context.Context, ref Address) func(context.Context) error +} + +// FakeChunkStore doesn't store anything, just implements the ChunkStore interface +// It can be used to inject into a hasherStore if you don't want to actually store data just do the +// hashing +type FakeChunkStore struct { +} + +// Put doesn't store anything it is just here to implement ChunkStore +func (f *FakeChunkStore) Put(_ context.Context, ch Chunk) error { + return nil +} + +// 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") +} + +// Close doesn't store anything it is just here to implement ChunkStore +func (f *FakeChunkStore) Close() { } diff --git a/swarm/swap/swap.go b/swarm/swap/swap.go new file mode 100644 index 0000000000..5d636dc205 --- /dev/null +++ b/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/swarm/swap/swap_test.go b/swarm/swap/swap_test.go new file mode 100644 index 0000000000..f2e3ba168a --- /dev/null +++ b/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/swarm/swarm.go b/swarm/swarm.go index 3be3660b58..b4b08c5c54 100644 --- a/swarm/swarm.go +++ b/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 @@ -21,141 +21,318 @@ import ( "context" "crypto/ecdsa" "fmt" + "io" + "math/big" "net" + "path/filepath" + "strings" + "time" + "unicode" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/contracts/chequebook" "github.com/ethereum/go-ethereum/contracts/ens" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/discover" + "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" "github.com/ethereum/go-ethereum/swarm/api" httpapi "github.com/ethereum/go-ethereum/swarm/api/http" "github.com/ethereum/go-ethereum/swarm/fuse" + "github.com/ethereum/go-ethereum/swarm/log" "github.com/ethereum/go-ethereum/swarm/network" + "github.com/ethereum/go-ethereum/swarm/network/stream" + "github.com/ethereum/go-ethereum/swarm/pss" + "github.com/ethereum/go-ethereum/swarm/state" "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 ( + updateGaugesPeriod = 5 * time.Second + startCounter = metrics.NewRegisteredCounter("stack,start", nil) + stopCounter = metrics.NewRegisteredCounter("stack,stop", nil) + uptimeGauge = metrics.NewRegisteredGauge("stack.uptime", nil) + requestsCacheGauge = metrics.NewRegisteredGauge("storage.cache.requests.size", nil) ) // 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 - dbAccess *network.DbAccess // access to local chunk db iterator and storage counter - storage storage.ChunkStore // internal access to storage, common interface to cloud storage backends - dpa *storage.DPA // distributed preimage archive, the local API to the storage with document level storage/retrieval support - depo network.StorageHandler // remote request handler, interface between bzz protocol and the storage - cloud storage.CloudStore // procurement, cloud storage backend (can multi-cloud) - hive *network.Hive // the logistic manager - backend chequebook.Backend // simple blockchain Backend - privateKey *ecdsa.PrivateKey - corsString string - swapEnabled bool - lstore *storage.LocalStore // local store, needs to store for releasing resources after node stopped - sfs *fuse.SwarmFS // need this to cleanup all the active mounts on node exit + 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 - PrvKey *ecdsa.PrivateKey -} - -func (self *Swarm) API() *SwarmAPI { - return &SwarmAPI{ - Api: self.api, - Backend: self.backend, - PrvKey: self.privateKey, - } -} - -// creates a new swarm service instance +// NewSwarm creates a new swarm service instance // implements node.Service -func NewSwarm(ctx *node.ServiceContext, backend chequebook.Backend, ensClient *ethclient.Client, config *api.Config, swapEnabled, syncEnabled bool, cors string) (self *Swarm, err error) { - if bytes.Equal(common.FromHex(config.PublicKey), storage.ZeroKey) { +// 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") } - if bytes.Equal(common.FromHex(config.BzzKey), storage.ZeroKey) { + if bytes.Equal(common.FromHex(config.BzzKey), storage.ZeroAddr) { return nil, fmt.Errorf("empty bzz key") } - self = &Swarm{ - config: config, - swapEnabled: swapEnabled, - backend: backend, - privateKey: config.Swap.PrivateKey(), - corsString: cors, + var backend chequebook.Backend + if config.SwapAPI != "" && config.SwapEnabled { + log.Info("connecting to SWAP API", "url", config.SwapAPI) + backend, err = ethclient.Dial(config.SwapAPI) + if err != nil { + return nil, fmt.Errorf("error connecting to SWAP API %s: %s", config.SwapAPI, err) + } } - log.Debug(fmt.Sprintf("Setting up Swarm service components")) - hash := storage.MakeHashFunc(config.ChunkerParams.Hash) - self.lstore, err = storage.NewLocalStore(hash, config.StoreParams) + self = &Swarm{ + 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, + BootnodeMode: config.BootnodeMode, + } + + self.stateStore, err = state.NewDBStore(filepath.Join(config.Path, "state-store.db")) if err != nil { return } - // setup local store - log.Debug(fmt.Sprintf("Set up local storage")) - - self.dbAccess = network.NewDbAccess(self.lstore) - log.Debug(fmt.Sprintf("Set up local db access (iterator/counter)")) - - // set up the kademlia hive - self.hive = network.NewHive( - common.HexToHash(self.config.BzzKey), // key to hive (kademlia base address) - config.HiveParams, // configuration parameters - swapEnabled, // SWAP enabled - syncEnabled, // syncronisation enabled - ) - log.Debug(fmt.Sprintf("Set up swarm network with Kademlia hive")) - - // setup cloud storage backend - self.cloud = network.NewForwarder(self.hive) - log.Debug(fmt.Sprintf("-> set swarm forwarder as cloud storage backend")) - - // setup cloud storage internal access layer - self.storage = storage.NewNetStore(hash, self.lstore, self.cloud, config.StoreParams) - log.Debug(fmt.Sprintf("-> swarm net store shared access layer to Swarm Chunk Store")) - - // set up Depo (storage handler = cloud storage access layer for incoming remote requests) - self.depo = network.NewDepo(hash, self.lstore, self.storage) - log.Debug(fmt.Sprintf("-> REmote Access to CHunks")) - - // set up DPA, the cloud storage local access layer - dpaChunkStore := storage.NewDpaChunkStore(self.lstore, self.storage) - log.Debug(fmt.Sprintf("-> Local Access to Swarm")) - // Swarm Hash Merklised Chunking for Arbitrary-length Document/File storage - self.dpa = storage.NewDPA(dpaChunkStore, self.config.ChunkerParams) - log.Debug(fmt.Sprintf("-> Content Store API")) - // set up high level api - transactOpts := bind.NewKeyedTransactor(self.privateKey) + var resolver *api.MultiResolver + if len(config.EnsAPIs) > 0 { + opts := []api.MultiResolverOption{} + for _, c := range config.EnsAPIs { + tld, endpoint, addr := parseEnsAPIAddress(c) + r, err := newEnsClient(endpoint, addr, config, self.privateKey) + if err != nil { + return nil, err + } + opts = append(opts, api.MultiResolverOptionWithResolver(r, tld)) - if ensClient == nil { - log.Warn("No ENS, please specify non-empty --ens-api to use domain name resolution") - } else { - self.dns, err = ens.NewENS(transactOpts, config.EnsRoot, ensClient) + } + resolver = api.NewMultiResolver(opts...) + self.dns = resolver + } + + lstore, err := storage.NewLocalStore(config.LocalStoreParams, mockStore) + if err != nil { + return nil, err + } + + self.netStore, err = storage.NewNetStore(lstore, nil) + if err != nil { + return nil, err + } + + to := network.NewKademlia( + common.FromHex(config.BzzKey), + network.NewKadParams(), + ) + delivery := stream.NewDelivery(to, self.netStore) + self.netStore.NewNetFetcherFunc = network.NewFetcherFactory(delivery.RequestFromPeers, config.DeliverySkipCheck).New + + 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")) } - log.Debug(fmt.Sprintf("-> Swarm Domain Name Registrar @ address %v", config.EnsRoot.Hex())) - self.api = api.NewApi(self.dpa, self.dns) - // Manifests for Smart Hosting - log.Debug(fmt.Sprintf("-> Web3 virtual server API")) + var nodeID enode.ID + if err := nodeID.UnmarshalText([]byte(config.NodeID)); err != nil { + return nil, err + } + + syncing := stream.SyncingAutoSubscribe + if !config.SyncEnabled || config.LightNodeEnabled { + syncing = stream.SyncingDisabled + } + + retrieval := stream.RetrievalEnabled + if config.LightNodeEnabled { + retrieval = stream.RetrievalClientOnly + } + + registryOptions := &stream.RegistryOptions{ + SkipCheck: config.DeliverySkipCheck, + Syncing: syncing, + Retrieval: retrieval, + SyncUpdateDelay: config.SyncUpdateDelay, + MaxPeerServers: config.MaxStreamPeerServers, + } + 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) + + var feedsHandler *feed.Handler + fhParams := &feed.HandlerParams{} + + feedsHandler = feed.NewHandler(fhParams) + feedsHandler.SetStore(self.netStore) + + lstore.Validators = []storage.ChunkValidator{ + storage.NewContentAddressValidator(storage.MakeHashFunc(storage.DefaultHash)), + feedsHandler, + } + + err = lstore.Migrate() + if err != nil { + return nil, err + } + + log.Debug("Setup local storage") + + 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) + if err != nil { + return nil, err + } + if pss.IsActiveHandshake { + pss.SetHandshakeController(self.ps, pss.NewHandshakeParams()) + } + + self.api = api.NewAPI(self.fileStore, self.dns, feedsHandler, self.privateKey) self.sfs = fuse.NewSwarmFS(self.api) - log.Debug("-> Initializing Fuse file system") + log.Debug("Initialized FUSE filesystem") return self, nil } +// parseEnsAPIAddress parses string according to format +// [tld:][contract-addr@]url and returns ENSClientConfig structure +// with endpoint, contract address and TLD. +func parseEnsAPIAddress(s string) (tld, endpoint string, addr common.Address) { + isAllLetterString := func(s string) bool { + for _, r := range s { + if !unicode.IsLetter(r) { + return false + } + } + return true + } + endpoint = s + if i := strings.Index(endpoint, ":"); i > 0 { + if isAllLetterString(endpoint[:i]) && len(endpoint) > i+2 && endpoint[i+1:i+3] != "//" { + tld = endpoint[:i] + endpoint = endpoint[i+1:] + } + } + if i := strings.Index(endpoint, "@"); i > 0 { + addr = common.HexToAddress(endpoint[:i]) + endpoint = endpoint[i+1:] + } + return +} + +// ensClient provides functionality for api.ResolveValidator +type ensClient struct { + *ens.ENS + *ethclient.Client +} + +// newEnsClient creates a new ENS client for that is a consumer of +// a ENS API on a specific endpoint. It is used as a helper function +// for creating multiple resolvers in NewSwarm function. +func newEnsClient(endpoint string, addr common.Address, config *api.Config, privkey *ecdsa.PrivateKey) (*ensClient, error) { + log.Info("connecting to ENS API", "url", endpoint) + client, err := rpc.Dial(endpoint) + if err != nil { + return nil, fmt.Errorf("error connecting to ENS API %s: %s", endpoint, err) + } + ethClient := ethclient.NewClient(client) + + ensRoot := config.EnsRoot + if addr != (common.Address{}) { + ensRoot = addr + } else { + a, err := detectEnsAddr(client) + if err == nil { + ensRoot = a + } else { + log.Warn(fmt.Sprintf("could not determine ENS contract address, using default %s", ensRoot), "err", err) + } + } + transactOpts := bind.NewKeyedTransactor(privkey) + dns, err := ens.NewENS(transactOpts, ensRoot, ethClient) + if err != nil { + return nil, err + } + log.Debug(fmt.Sprintf("-> Swarm Domain Name Registrar %v @ address %v", endpoint, ensRoot.Hex())) + return &ensClient{ + ENS: dns, + Client: ethClient, + }, err +} + +// detectEnsAddr determines the ENS contract address by getting both the +// version and genesis hash using the client and matching them to either +// mainnet or testnet addresses +func detectEnsAddr(client *rpc.Client) (common.Address, error) { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + var version string + if err := client.CallContext(ctx, &version, "net_version"); err != nil { + return common.Address{}, err + } + + block, err := ethclient.NewClient(client).BlockByNumber(ctx, big.NewInt(0)) + if err != nil { + return common.Address{}, err + } + + switch { + + case version == "1" && block.Hash() == params.MainnetGenesisHash: + log.Info("using Mainnet ENS contract address", "addr", ens.MainNetAddress) + return ens.MainNetAddress, nil + + case version == "3" && block.Hash() == params.TestnetGenesisHash: + log.Info("using Testnet ENS contract address", "addr", ens.TestNetAddress) + return ens.TestNetAddress, nil + + default: + return common.Address{}, fmt.Errorf("unknown version and genesis hash: %s %s", version, block.Hash()) + } +} + /* Start is called when the stack is started * starts the network kademlia hive peer management @@ -167,168 +344,204 @@ 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 { - connectPeer := func(url string) error { - node, err := discover.ParseNode(url) - if err != nil { - return fmt.Errorf("invalid node URL: %v", err) - } - srv.AddPeer(node) - return nil - } +func (s *Swarm) Start(srv *p2p.Server) error { + startTime := time.Now() + + s.tracerClose = tracing.Closer + + // update uaddr to correct enode + 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.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.Warn(fmt.Sprintf("Starting Swarm service")) - self.hive.Start( - discover.PubkeyID(&srv.PrivateKey.PublicKey), - func() string { return srv.ListenAddr }, - connectPeer, - ) - log.Info(fmt.Sprintf("Swarm network started on bzz address: %v", self.hive.Addr())) + log.Info("Starting bzz service") - self.dpa.Start() - log.Debug(fmt.Sprintf("Swarm DPA started")) + 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", s.bzz.Hive.BaseAddr())) - // start swarm http proxy server - if self.config.Port != "" { - addr := net.JoinHostPort(self.config.ListenAddr, self.config.Port) - go httpapi.StartHttpServer(self.api, &httpapi.ServerConfig{ - Addr: addr, - CorsString: self.corsString, - }) - log.Info(fmt.Sprintf("Swarm http proxy started on %v", addr)) - - if self.corsString != "" { - log.Debug(fmt.Sprintf("Swarm http proxy started with corsdomain: %v", self.corsString)) - } + if s.ps != nil { + s.ps.Start(srv) } + // start swarm http proxy server + if s.config.Port != "" { + addr := net.JoinHostPort(s.config.ListenAddr, s.config.Port) + server := httpapi.NewServer(s.api, s.config.Cors) + + if s.config.Cors != "" { + log.Debug("Swarm HTTP proxy CORS headers", "allowedOrigins", s.config.Cors) + } + + log.Debug("Starting Swarm HTTP proxy", "port", s.config.Port) + go func() { + err := server.ListenAndServe(addr) + if err != nil { + log.Error("Could not start Swarm HTTP proxy", "err", err.Error()) + } + }() + } + + 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) + s.streamer.Start(srv) return nil } // implements the node.Service interface // stops all component services. -func (self *Swarm) Stop() error { - self.dpa.Stop() - err := self.hive.Stop() - if ch := self.config.Swap.Chequebook(); ch != nil { +func (s *Swarm) Stop() error { + if s.tracerClose != nil { + err := s.tracerClose.Close() + tracing.FinishSpans() + if err != nil { + return err + } + } + + if s.ps != nil { + s.ps.Stop() + } + if ch := s.config.Swap.Chequebook(); ch != nil { ch.Stop() ch.Save() } - - if self.lstore != nil { - self.lstore.DbStore.Close() + if s.swap != nil { + s.swap.Close() + } + if s.accountingMetrics != nil { + s.accountingMetrics.Close() + } + if s.netStore != nil { + s.netStore.Close() + } + s.sfs.Stop() + stopCounter.Inc(1) + 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 + } } - self.sfs.Stop() return err } -// implements the node.Service interface -func (self *Swarm) Protocols() []p2p.Protocol { - proto, err := network.Bzz(self.depo, self.backend, self.hive, self.dbAccess, self.config.Swap, self.config.SyncParams, self.config.NetworkId) - if err != nil { - return nil +// 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 s.ps != nil { + protos = append(protos, s.ps.Protocols()...) + } } - return []p2p.Protocol{proto} + return } // implements node.Service -// Apis returns the RPC Api descriptors the Swarm implementation offers -func (self *Swarm) APIs() []rpc.API { - return []rpc.API{ +// APIs returns the RPC API descriptors the Swarm implementation offers +func (s *Swarm) APIs() []rpc.API { + + apis := []rpc.API{ // public APIs { Namespace: "bzz", - Version: "0.1", - Service: &Info{self.config, chequebook.ContractParams}, + Version: "3.0", + Service: &Info{s.config, chequebook.ContractParams}, Public: true, }, // admin APIs { Namespace: "bzz", - Version: "0.1", - Service: api.NewControl(self.api, self.hive), + Version: "3.0", + 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, }, - // storage APIs - // DEPRECATED: Use the HTTP API instead { - Namespace: "bzz", - Version: "0.1", - Service: api.NewStorage(self.api), - Public: true, - }, - { - Namespace: "bzz", - Version: "0.1", - Service: api.NewFileSystem(self.api), + Namespace: "accounting", + Version: protocols.AccountingVersion, + Service: protocols.NewAccountingApi(s.accountingMetrics), Public: false, }, - // {Namespace, Version, api.NewAdmin(self), false}, } -} -func (self *Swarm) Api() *api.Api { - return self.api + apis = append(apis, s.bzz.APIs()...) + + if s.ps != nil { + apis = append(apis, s.ps.APIs()...) + } + + return apis } // 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())) - self.hive.DropAll() + log.Info(fmt.Sprintf("new chequebook set (%v): saving config file, resetting all connections in the hive", s.config.Swap.Contract.Hex())) return nil } -// Local swarm without netStore -func NewLocalSwarm(datadir, port string) (self *Swarm, err error) { - - prvKey, err := crypto.GenerateKey() - if err != nil { - return - } - - config := api.NewDefaultConfig() - config.Path = datadir - config.Init(prvKey) - config.Port = port - - dpa, err := storage.NewLocalDPA(datadir) - if err != nil { - return - } - - self = &Swarm{ - api: api.NewApi(dpa, nil), - config: config, - } - - return +// 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 @@ -337,6 +550,6 @@ type Info struct { *chequebook.Params } -func (self *Info) Info() *Info { - return self +func (s *Info) Info() *Info { + return s } diff --git a/swarm/swarm_test.go b/swarm/swarm_test.go new file mode 100644 index 0000000000..d85eb91185 --- /dev/null +++ b/swarm/swarm_test.go @@ -0,0 +1,375 @@ +// Copyright 2017 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 swarm + +import ( + "context" + "encoding/hex" + "io/ioutil" + "math/rand" + "os" + "path" + "runtime" + "strings" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/rpc" + "github.com/ethereum/go-ethereum/swarm/api" +) + +// TestNewSwarm validates Swarm fields in repsect to the provided configuration. +func TestNewSwarm(t *testing.T) { + dir, err := ioutil.TempDir("", "swarm") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + // a simple rpc endpoint for testing dialing + ipcEndpoint := path.Join(dir, "TestSwarm.ipc") + + // windows namedpipes are not on filesystem but on NPFS + if runtime.GOOS == "windows" { + b := make([]byte, 8) + rand.Read(b) + ipcEndpoint = `\\.\pipe\TestSwarm-` + hex.EncodeToString(b) + } + + _, server, err := rpc.StartIPCEndpoint(ipcEndpoint, nil) + if err != nil { + t.Error(err) + } + defer server.Stop() + + for _, tc := range []struct { + name string + configure func(*api.Config) + check func(*testing.T, *Swarm, *api.Config) + }{ + { + name: "defaults", + configure: nil, + check: func(t *testing.T, s *Swarm, config *api.Config) { + if s.config != config { + t.Error("config is not the same object") + } + if s.backend != nil { + t.Error("backend is not nil") + } + if s.privateKey == nil { + t.Error("private key is not set") + } + if !s.config.HiveParams.Discovery { + t.Error("config.HiveParams.Discovery is false, must be true regardless the configuration") + } + if s.dns != nil { + t.Error("dns initialized, but it should not be") + } + if s.netStore == nil { + t.Error("netStore not initialized") + } + if s.streamer == nil { + t.Error("streamer not initialized") + } + if s.fileStore == nil { + t.Error("fileStore not initialized") + } + if s.bzz == nil { + t.Error("bzz not initialized") + } + if s.ps == nil { + t.Error("pss not initialized") + } + if s.api == nil { + t.Error("api not initialized") + } + if s.sfs == nil { + t.Error("swarm filesystem not initialized") + } + }, + }, + { + name: "with swap", + configure: func(config *api.Config) { + config.SwapAPI = ipcEndpoint + config.SwapEnabled = true + }, + check: func(t *testing.T, s *Swarm, _ *api.Config) { + if s.backend == nil { + t.Error("backend is nil") + } + }, + }, + { + name: "with swap disabled", + configure: func(config *api.Config) { + config.SwapAPI = ipcEndpoint + config.SwapEnabled = false + }, + check: func(t *testing.T, s *Swarm, _ *api.Config) { + if s.backend != nil { + t.Error("backend is not nil") + } + }, + }, + { + name: "with swap enabled and api endpoint blank", + configure: func(config *api.Config) { + config.SwapAPI = "" + config.SwapEnabled = true + }, + check: func(t *testing.T, s *Swarm, _ *api.Config) { + if s.backend != nil { + t.Error("backend is not nil") + } + }, + }, + { + name: "ens", + configure: func(config *api.Config) { + config.EnsAPIs = []string{ + "http://127.0.0.1:8888", + } + }, + check: func(t *testing.T, s *Swarm, _ *api.Config) { + if s.dns == nil { + t.Error("dns is not initialized") + } + }, + }, + } { + t.Run(tc.name, func(t *testing.T) { + config := api.NewConfig() + + dir, err := ioutil.TempDir("", "swarm") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + config.Path = dir + + privkey, err := crypto.GenerateKey() + if err != nil { + t.Fatal(err) + } + + config.Init(privkey) + + if tc.configure != nil { + tc.configure(config) + } + + s, err := NewSwarm(config, nil) + if err != nil { + t.Fatal(err) + } + + if tc.check != nil { + tc.check(t, s, config) + } + }) + } +} + +func TestParseEnsAPIAddress(t *testing.T) { + for _, x := range []struct { + description string + value string + tld string + endpoint string + addr common.Address + }{ + { + description: "IPC endpoint", + value: "/data/testnet/geth.ipc", + endpoint: "/data/testnet/geth.ipc", + }, + { + description: "HTTP endpoint", + value: "http://127.0.0.1:1234", + endpoint: "http://127.0.0.1:1234", + }, + { + description: "WS endpoint", + value: "ws://127.0.0.1:1234", + endpoint: "ws://127.0.0.1:1234", + }, + { + description: "IPC Endpoint and TLD", + value: "test:/data/testnet/geth.ipc", + endpoint: "/data/testnet/geth.ipc", + tld: "test", + }, + { + description: "HTTP endpoint and TLD", + value: "test:http://127.0.0.1:1234", + endpoint: "http://127.0.0.1:1234", + tld: "test", + }, + { + description: "WS endpoint and TLD", + value: "test:ws://127.0.0.1:1234", + endpoint: "ws://127.0.0.1:1234", + tld: "test", + }, + { + description: "IPC Endpoint and contract address", + value: "314159265dD8dbb310642f98f50C066173C1259b@/data/testnet/geth.ipc", + endpoint: "/data/testnet/geth.ipc", + addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), + }, + { + description: "HTTP endpoint and contract address", + value: "314159265dD8dbb310642f98f50C066173C1259b@http://127.0.0.1:1234", + endpoint: "http://127.0.0.1:1234", + addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), + }, + { + description: "WS endpoint and contract address", + value: "314159265dD8dbb310642f98f50C066173C1259b@ws://127.0.0.1:1234", + endpoint: "ws://127.0.0.1:1234", + addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), + }, + { + description: "IPC Endpoint, TLD and contract address", + value: "test:314159265dD8dbb310642f98f50C066173C1259b@/data/testnet/geth.ipc", + endpoint: "/data/testnet/geth.ipc", + addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), + tld: "test", + }, + { + description: "HTTP endpoint, TLD and contract address", + value: "eth:314159265dD8dbb310642f98f50C066173C1259b@http://127.0.0.1:1234", + endpoint: "http://127.0.0.1:1234", + addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), + tld: "eth", + }, + { + description: "WS endpoint, TLD and contract address", + value: "eth:314159265dD8dbb310642f98f50C066173C1259b@ws://127.0.0.1:1234", + endpoint: "ws://127.0.0.1:1234", + addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), + tld: "eth", + }, + } { + t.Run(x.description, func(t *testing.T) { + tld, endpoint, addr := parseEnsAPIAddress(x.value) + if endpoint != x.endpoint { + t.Errorf("expected Endpoint %q, got %q", x.endpoint, endpoint) + } + if addr != x.addr { + t.Errorf("expected ContractAddress %q, got %q", x.addr.String(), addr.String()) + } + if tld != x.tld { + t.Errorf("expected TLD %q, got %q", x.tld, tld) + } + }) + } +} + +// TestLocalStoreAndRetrieve runs multiple tests where different size files are uploaded +// to a single Swarm instance using API Store and checked against the content returned +// by API Retrieve function. +// +// This test is intended to validate functionality of chunker store and join functions +// and their intergartion into Swarm, without comparing results with ones produced by +// another chunker implementation, as it is done in swarm/storage tests. +func TestLocalStoreAndRetrieve(t *testing.T) { + config := api.NewConfig() + + dir, err := ioutil.TempDir("", "node") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + config.Path = dir + + privkey, err := crypto.GenerateKey() + if err != nil { + t.Fatal(err) + } + + config.Init(privkey) + + swarm, err := NewSwarm(config, nil) + if err != nil { + t.Fatal(err) + } + + // by default, test only the lonely chunk cases + sizes := []int{1, 60, 4097, 524288 + 1, 7*524288 + 1} + + if *longrunning { + // test broader set of cases if -longruning flag is set + sizes = append(sizes, 83, 179, 253, 1024, 4095, 4096, 8191, 8192, 8193, 12287, 12288, 12289, 123456, 2345678, 67298391, 524288, 524288+4096, 524288+4097, 7*524288, 7*524288+4096, 7*524288+4097, 128*524288+1, 128*524288, 128*524288+4096, 128*524288+4097, 816778334) + } + for _, n := range sizes { + testLocalStoreAndRetrieve(t, swarm, n, true) + testLocalStoreAndRetrieve(t, swarm, n, false) + } +} + +// testLocalStoreAndRetrieve is using a single Swarm instance, to upload +// a file of length n with optional random data using API Store function, +// and checks the output of API Retrieve function on the same instance. +// This is a regression test for issue +// https://github.com/ethersphere/go-ethereum/issues/639 +// where pyramid chunker did not split correctly files with lengths that +// are edge cases for chunk and tree parameters, depending whether there +// is a tree chunk with only one data chunk and how the compress functionality +// changed the tree. +func testLocalStoreAndRetrieve(t *testing.T, swarm *Swarm, n int, randomData bool) { + slice := make([]byte, n) + if randomData { + rand.Seed(time.Now().UnixNano()) + rand.Read(slice) + } + dataPut := string(slice) + + ctx := context.TODO() + k, wait, err := swarm.api.Store(ctx, strings.NewReader(dataPut), int64(len(dataPut)), false) + if err != nil { + t.Fatal(err) + } + if wait != nil { + err = wait(ctx) + if err != nil { + t.Fatal(err) + } + } + + r, _ := swarm.api.Retrieve(context.TODO(), k) + + d, err := ioutil.ReadAll(r) + if err != nil { + t.Fatal(err) + } + dataGet := string(d) + + if len(dataPut) != len(dataGet) { + t.Fatalf("data not matched: length expected %v, got %v", len(dataPut), len(dataGet)) + } else { + if dataPut != dataGet { + t.Fatal("data not matched") + } + } +} diff --git a/swarm/testutil/file.go b/swarm/testutil/file.go new file mode 100644 index 0000000000..70732aa92e --- /dev/null +++ b/swarm/testutil/file.go @@ -0,0 +1,65 @@ +// Copyright 2017 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 testutil + +import ( + "bytes" + "io" + "io/ioutil" + "math/rand" + "os" + "strings" + "testing" +) + +// TempFileWithContent is a helper function that creates a temp file that contains the following string content then closes the file handle +// it returns the complete file path +func TempFileWithContent(t *testing.T, content string) string { + tempFile, err := ioutil.TempFile("", "swarm-temp-file") + if err != nil { + t.Fatal(err) + } + + _, err = io.Copy(tempFile, strings.NewReader(content)) + if err != nil { + os.RemoveAll(tempFile.Name()) + t.Fatal(err) + } + if err = tempFile.Close(); err != nil { + t.Fatal(err) + } + return tempFile.Name() +} + +// RandomBytes returns pseudo-random deterministic result +// because test fails must be reproducible +func RandomBytes(seed, length int) []byte { + b := make([]byte, length) + reader := rand.New(rand.NewSource(int64(seed))) + for n := 0; n < length; { + read, err := reader.Read(b[n:]) + if err != nil { + panic(err) + } + n += read + } + return b +} + +func RandomReader(seed, length int) *bytes.Reader { + return bytes.NewReader(RandomBytes(seed, length)) +} diff --git a/swarm/testutil/http.go b/swarm/testutil/http.go deleted file mode 100644 index f2922fab00..0000000000 --- a/swarm/testutil/http.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2017 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 testutil - -import ( - "io/ioutil" - "net/http/httptest" - "os" - "testing" - - "github.com/ethereum/go-ethereum/swarm/api" - httpapi "github.com/ethereum/go-ethereum/swarm/api/http" - "github.com/ethereum/go-ethereum/swarm/storage" -) - -func NewTestSwarmServer(t *testing.T) *TestSwarmServer { - dir, err := ioutil.TempDir("", "swarm-storage-test") - if err != nil { - t.Fatal(err) - } - storeparams := &storage.StoreParams{ - ChunkDbPath: dir, - DbCapacity: 5000000, - CacheCapacity: 5000, - Radius: 0, - } - localStore, err := storage.NewLocalStore(storage.MakeHashFunc("SHA3"), storeparams) - if err != nil { - os.RemoveAll(dir) - t.Fatal(err) - } - chunker := storage.NewTreeChunker(storage.NewChunkerParams()) - dpa := &storage.DPA{ - Chunker: chunker, - ChunkStore: localStore, - } - dpa.Start() - a := api.NewApi(dpa, nil) - srv := httptest.NewServer(httpapi.NewServer(a)) - return &TestSwarmServer{ - Server: srv, - Dpa: dpa, - dir: dir, - } -} - -type TestSwarmServer struct { - *httptest.Server - - Dpa *storage.DPA - dir string -} - -func (t *TestSwarmServer) Close() { - t.Server.Close() - t.Dpa.Stop() - os.RemoveAll(t.dir) -} diff --git a/swarm/testutil/norace.go b/swarm/testutil/norace.go new file mode 100644 index 0000000000..bc652184bb --- /dev/null +++ b/swarm/testutil/norace.go @@ -0,0 +1,26 @@ +// 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 . + +// +build !race + +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/swarm/testutil/race.go b/swarm/testutil/race.go new file mode 100644 index 0000000000..08aa279ae3 --- /dev/null +++ b/swarm/testutil/race.go @@ -0,0 +1,23 @@ +// 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 . + +// +build race + +package testutil + +// RaceEnabled is true when -race flag is provided to the go tool. +// See norace.go for more. +const RaceEnabled = true diff --git a/swarm/tracing/tracing.go b/swarm/tracing/tracing.go new file mode 100644 index 0000000000..55875464b9 --- /dev/null +++ b/swarm/tracing/tracing.go @@ -0,0 +1,173 @@ +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 turns tracing on for the current swarm instance + Enabled bool = false + store = spanStore{} +) + +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 +) + +var ( + TracingFlag = cli.BoolFlag{ + Name: TracingEnabledFlag, + Usage: "Enable tracing", + } + TracingEndpointFlag = cli.StringFlag{ + Name: "tracing.endpoint", + Usage: "Tracing endpoint", + Value: "0.0.0.0:6831", + } + TracingSvcFlag = cli.StringFlag{ + Name: "tracing.svc", + Usage: "Tracing service name", + Value: "swarm", + } +) + +// Flags holds all command-line flags required for tracing collection. +var Flags = []cli.Flag{ + TracingFlag, + TracingEndpointFlag, + TracingSvcFlag, +} + +// Init enables or disables the open tracing system. +func init() { + for _, arg := range os.Args { + if flag := strings.TrimLeft(arg, "-"); flag == TracingEnabledFlag { + Enabled = true + } + } +} + +func Setup(ctx *cli.Context) { + if Enabled { + log.Info("Enabling opentracing") + var ( + endpoint = ctx.GlobalString(TracingEndpointFlag.Name) + svc = ctx.GlobalString(TracingSvcFlag.Name) + ) + + Closer = initTracer(endpoint, svc) + } +} + +func initTracer(endpoint, svc string) (closer io.Closer) { + // Sample configuration for testing. Use constant sampling to sample every trace + // and enable LogSpan to log every span via configured Logger. + cfg := jaegercfg.Configuration{ + Sampler: &jaegercfg.SamplerConfig{ + Type: jaeger.SamplerTypeConst, + Param: 1, + }, + Reporter: &jaegercfg.ReporterConfig{ + LogSpans: true, + BufferFlushInterval: 1 * time.Second, + LocalAgentHostPort: endpoint, + }, + } + + // Example logger and metrics factory. Use github.com/uber/jaeger-client-go/log + // and github.com/uber/jaeger-lib/metrics respectively to bind to real logging and metrics + // frameworks. + //jLogger := jaegerlog.StdLogger + //jMetricsFactory := metrics.NullFactory + + // Initialize tracer with a logger and a metrics factory + closer, err := cfg.InitGlobalTracer( + svc, + //jaegercfg.Logger(jLogger), + //jaegercfg.Metrics(jMetricsFactory), + //jaegercfg.Observer(rpcmetrics.NewObserver(jMetricsFactory, rpcmetrics.DefaultNameNormalizer)), + ) + if err != nil { + log.Error("Could not initialize Jaeger tracer", "err", err) + } + + 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/swarm/version/version.go b/swarm/version/version.go new file mode 100644 index 0000000000..ff54bdf113 --- /dev/null +++ b/swarm/version/version.go @@ -0,0 +1,67 @@ +// 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 version + +import ( + "fmt" +) + +const ( + 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. +var Version = func() string { + return fmt.Sprintf("%d.%d.%d", VersionMajor, VersionMinor, VersionPatch) +}() + +// VersionWithMeta holds the textual version string including the metadata. +var VersionWithMeta = func() string { + v := Version + if VersionMeta != "" { + v += "-" + VersionMeta + } + 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 +func ArchiveVersion(gitCommit string) string { + vsn := Version + if VersionMeta != "stable" { + vsn += "-" + VersionMeta + } + if len(gitCommit) >= 8 { + vsn += "-" + gitCommit[:8] + } + return vsn +} + +func VersionWithCommit(gitCommit string) string { + vsn := Version + if len(gitCommit) >= 8 { + vsn += "-" + gitCommit[:8] + } + return vsn +} diff --git a/tests/block_test.go b/tests/block_test.go index 669d3ca08a..711a3f8695 100644 --- a/tests/block_test.go +++ b/tests/block_test.go @@ -30,11 +30,19 @@ func TestBlockchain(t *testing.T) { bt.skipLoad(`^bcForgedTest/bcForkUncle\.json`) bt.skipLoad(`^bcMultiChainTest/(ChainAtoChainB_blockorder|CallContractFromNotBestBlock)`) bt.skipLoad(`^bcTotalDifficultyTest/(lotsOfLeafs|lotsOfBranches|sideChainWithMoreTransactions)`) - // Constantinople is not implemented yet. - bt.skipLoad(`(?i)(constantinople)`) + // Slow tests + bt.slow(`^bcExploitTest/DelegateCallSpam.json`) + bt.slow(`^bcExploitTest/ShanghaiLove.json`) + bt.slow(`^bcExploitTest/SuicideIssue.json`) + bt.slow(`^bcForkStressTest/`) + bt.slow(`^bcGasPricerTest/RPC_API_Test.json`) + bt.slow(`^bcWalletTest/`) - // Still failing tests - bt.skipLoad(`^bcWalletTest.*_Byzantium$`) + // Still failing tests that we need to look into + //bt.fails(`^bcStateTests/suicideThenCheckBalance.json/suicideThenCheckBalance_Constantinople`, "TODO: investigate") + //bt.fails(`^bcStateTests/suicideStorageCheckVCreate2.json/suicideStorageCheckVCreate2_Constantinople`, "TODO: investigate") + //bt.fails(`^bcStateTests/suicideStorageCheckVCreate.json/suicideStorageCheckVCreate_Constantinople`, "TODO: investigate") + //bt.fails(`^bcStateTests/suicideStorageCheck.json/suicideStorageCheck_Constantinople`, "TODO: investigate") bt.walk(t, blockTestDir, func(t *testing.T, name string, test *BlockTest) { if err := bt.checkFailure(t, name, test.Run()); err != nil { diff --git a/tests/block_test_util.go b/tests/block_test_util.go index 4bfd6433f5..9fa69bf4ed 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -27,6 +27,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" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" @@ -42,17 +43,19 @@ type BlockTest struct { json btJSON } +// UnmarshalJSON implements json.Unmarshaler interface. func (t *BlockTest) UnmarshalJSON(in []byte) error { return json.Unmarshal(in, &t.json) } type btJSON struct { - Blocks []btBlock `json:"blocks"` - Genesis btHeader `json:"genesisBlockHeader"` - Pre core.GenesisAlloc `json:"pre"` - Post core.GenesisAlloc `json:"postState"` - BestBlock common.UnprefixedHash `json:"lastblockhash"` - Network string `json:"network"` + Blocks []btBlock `json:"blocks"` + Genesis btHeader `json:"genesisBlockHeader"` + Pre core.GenesisAlloc `json:"pre"` + Post core.GenesisAlloc `json:"postState"` + BestBlock common.UnprefixedHash `json:"lastblockhash"` + Network string `json:"network"` + SealEngine string `json:"sealEngine"` } type btBlock struct { @@ -98,19 +101,24 @@ func (t *BlockTest) Run() error { } // import pre accounts & construct test genesis block & state root - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() gblock, err := t.genesis(config).Commit(db) if err != nil { return err } if gblock.Hash() != t.json.Genesis.Hash { - return fmt.Errorf("genesis block hash doesn't match test: computed=%x, test=%x\n", gblock.Hash().Bytes()[:6], t.json.Genesis.Hash[:6]) + return fmt.Errorf("genesis block hash doesn't match test: computed=%x, test=%x", gblock.Hash().Bytes()[:6], t.json.Genesis.Hash[:6]) } if gblock.Root() != t.json.Genesis.StateRoot { return fmt.Errorf("genesis block state root does not match test: computed=%x, test=%x", gblock.Root().Bytes()[:6], t.json.Genesis.StateRoot[:6]) } - - chain, err := core.NewBlockChain(db, config, ethash.NewShared(), vm.Config{}) + var engine consensus.Engine + if t.json.SealEngine == "NoProof" { + engine = ethash.NewFaker() + } else { + engine = ethash.NewShared() + } + chain, err := core.NewBlockChain(db, &core.CacheConfig{TrieCleanLimit: 0}, config, engine, vm.Config{}, nil) if err != nil { return err } diff --git a/tests/difficulty_test.go b/tests/difficulty_test.go index a449b1cfa6..fde9db3ad4 100644 --- a/tests/difficulty_test.go +++ b/tests/difficulty_test.go @@ -13,14 +13,12 @@ // // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// package tests import ( - "testing" - "math/big" + "testing" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/params" @@ -28,7 +26,7 @@ import ( var ( mainnetChainConfig = params.ChainConfig{ - ChainId: big.NewInt(1), + ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(1150000), DAOForkBlock: big.NewInt(1920000), DAOForkSupport: true, @@ -72,6 +70,9 @@ func TestDifficulty(t *testing.T) { dt.config("Frontier", *params.TestnetChainConfig) dt.config("MainNetwork", mainnetChainConfig) dt.config("CustomMainNetwork", mainnetChainConfig) + dt.config("Constantinople", params.ChainConfig{ + ConstantinopleBlock: big.NewInt(0), + }) dt.config("difficulty.json", mainnetChainConfig) dt.walk(t, difficultyTestDir, func(t *testing.T, name string, test *DifficultyTest) { diff --git a/tests/difficulty_test_util.go b/tests/difficulty_test_util.go index 7541477933..00d699cf75 100644 --- a/tests/difficulty_test_util.go +++ b/tests/difficulty_test_util.go @@ -13,7 +13,6 @@ // // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// package tests diff --git a/tests/init.go b/tests/init.go index 9e884efe39..188cdffe9d 100644 --- a/tests/init.go +++ b/tests/init.go @@ -1,4 +1,4 @@ -// Copyright 2017 The go-ethereum Authors +// 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 @@ -23,29 +23,29 @@ import ( "github.com/ethereum/go-ethereum/params" ) -// This table defines supported forks and their chain config. +// Forks table defines supported forks and their chain config. var Forks = map[string]*params.ChainConfig{ "Frontier": { - ChainId: big.NewInt(1), + ChainID: big.NewInt(1), }, "Homestead": { - ChainId: big.NewInt(1), + ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(0), }, "EIP150": { - ChainId: big.NewInt(1), + ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(0), EIP150Block: big.NewInt(0), }, "EIP158": { - ChainId: big.NewInt(1), + ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(0), EIP150Block: big.NewInt(0), EIP155Block: big.NewInt(0), EIP158Block: big.NewInt(0), }, "Byzantium": { - ChainId: big.NewInt(1), + ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(0), EIP150Block: big.NewInt(0), EIP155Block: big.NewInt(0), @@ -53,29 +53,60 @@ var Forks = map[string]*params.ChainConfig{ DAOForkBlock: big.NewInt(0), ByzantiumBlock: big.NewInt(0), }, + "Constantinople": { + 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(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), + ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(5), }, "HomesteadToEIP150At5": { - ChainId: big.NewInt(1), + ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(0), EIP150Block: big.NewInt(5), }, "HomesteadToDaoAt5": { - ChainId: big.NewInt(1), + ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(0), DAOForkBlock: big.NewInt(5), DAOForkSupport: true, }, "EIP158ToByzantiumAt5": { - ChainId: big.NewInt(1), + ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(0), EIP150Block: big.NewInt(0), EIP155Block: big.NewInt(0), 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/tests/init_test.go b/tests/init_test.go index ebb0d32c34..053cbd6fcd 100644 --- a/tests/init_test.go +++ b/tests/init_test.go @@ -1,4 +1,4 @@ -// Copyright 2015 The go-ethereum Authors +// Copyright 2017 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 @@ -25,6 +25,7 @@ import ( "path/filepath" "reflect" "regexp" + "runtime" "sort" "strings" "testing" @@ -42,7 +43,7 @@ var ( difficultyTestDir = filepath.Join(baseDir, "BasicTests") ) -func readJson(reader io.Reader, value interface{}) error { +func readJSON(reader io.Reader, value interface{}) error { data, err := ioutil.ReadAll(reader) if err != nil { return fmt.Errorf("error reading JSON file: %v", err) @@ -57,14 +58,14 @@ func readJson(reader io.Reader, value interface{}) error { return nil } -func readJsonFile(fn string, value interface{}) error { +func readJSONFile(fn string, value interface{}) error { file, err := os.Open(fn) if err != nil { return err } defer file.Close() - err = readJson(file, value) + err = readJSON(file, value) if err != nil { return fmt.Errorf("%s in file %s", err.Error(), fn) } @@ -90,7 +91,8 @@ type testMatcher struct { configpat []testConfig failpat []testFailure skiploadpat []*regexp.Regexp - skipshortpat []*regexp.Regexp + slowpat []*regexp.Regexp + whitelistpat *regexp.Regexp } type testConfig struct { @@ -104,8 +106,8 @@ type testFailure struct { } // skipShortMode skips tests matching when the -short flag is used. -func (tm *testMatcher) skipShortMode(pattern string) { - tm.skipshortpat = append(tm.skipshortpat, regexp.MustCompile(pattern)) +func (tm *testMatcher) slow(pattern string) { + tm.slowpat = append(tm.slowpat, regexp.MustCompile(pattern)) } // skipLoad skips JSON loading of tests matching the pattern. @@ -121,6 +123,10 @@ func (tm *testMatcher) fails(pattern string, reason string) { tm.failpat = append(tm.failpat, testFailure{regexp.MustCompile(pattern), reason}) } +func (tm *testMatcher) whitelist(pattern string) { + tm.whitelistpat = regexp.MustCompile(pattern) +} + // config defines chain config for tests matching the pattern. func (tm *testMatcher) config(pattern string, cfg params.ChainConfig) { tm.configpat = append(tm.configpat, testConfig{regexp.MustCompile(pattern), cfg}) @@ -128,11 +134,15 @@ func (tm *testMatcher) config(pattern string, cfg params.ChainConfig) { // findSkip matches name against test skip patterns. func (tm *testMatcher) findSkip(name string) (reason string, skipload bool) { - if testing.Short() { - for _, re := range tm.skipshortpat { - if re.MatchString(name) { + isWin32 := runtime.GOARCH == "386" && runtime.GOOS == "windows" + for _, re := range tm.slowpat { + if re.MatchString(name) { + if testing.Short() { return "skipped in -short mode", false } + if isWin32 { + return "skipped on 32bit windows", false + } } } for _, re := range tm.skiploadpat { @@ -169,9 +179,8 @@ func (tm *testMatcher) checkFailure(t *testing.T, name string, err error) error if err != nil { t.Logf("error: %v", err) return nil - } else { - return fmt.Errorf("test succeeded unexpectedly") } + return fmt.Errorf("test succeeded unexpectedly") } return err } @@ -209,11 +218,16 @@ func (tm *testMatcher) runTestFile(t *testing.T, path, name string, runTest inte if r, _ := tm.findSkip(name); r != "" { t.Skip(r) } + if tm.whitelistpat != nil { + if !tm.whitelistpat.MatchString(name) { + t.Skip("Skipped by whitelist") + } + } t.Parallel() // Load the file as map[string]. m := makeMapFromTestFunc(runTest) - if err := readJsonFile(path, m.Addr().Interface()); err != nil { + if err := readJSONFile(path, m.Addr().Interface()); err != nil { t.Fatal(err) } diff --git a/tests/rlp_test_util.go b/tests/rlp_test_util.go index 58ef8a6428..9069ec55a1 100644 --- a/tests/rlp_test_util.go +++ b/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/tests/state_test.go b/tests/state_test.go index 100c776c1a..8b69da91f2 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 The go-ethereum Authors +// 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 @@ -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" ) @@ -30,20 +33,25 @@ func TestState(t *testing.T) { st := new(testMatcher) // Long tests: - st.skipShortMode(`^stQuadraticComplexityTest/`) + st.slow(`^stAttackTest/ContractCreationSpam`) + st.slow(`^stBadOpcode/badOpcodes`) + st.slow(`^stPreCompiledContracts/modexp`) + st.slow(`^stQuadraticComplexityTest/`) + st.slow(`^stStaticCall/static_Call50000`) + st.slow(`^stStaticCall/static_Return50000`) + st.slow(`^stStaticCall/static_Call1MB`) + st.slow(`^stSystemOperationsTest/CallRecursiveBomb`) + st.slow(`^stTransactionTest/Opcodes_TransactionInit`) // Broken tests: 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/RevertPrefoundEmptyOOG\.json/EIP158`, "bug in test") - st.fails(`^stRevertTest/RevertPrecompiledTouch\.json/Byzantium`, "bug in test") - st.fails(`^stRevertTest/RevertPrefoundEmptyOOG\.json/Byzantium`, "bug in test") - st.fails(`^stRandom2/randomStatetest64[45]\.json/(EIP150|Frontier|Homestead)/.*`, "known bug #15119") - st.fails(`^stCreateTest/TransactionCollisionToEmpty\.json/EIP158/2`, "known bug ") - st.fails(`^stCreateTest/TransactionCollisionToEmpty\.json/EIP158/3`, "known bug ") - st.fails(`^stCreateTest/TransactionCollisionToEmpty\.json/Byzantium/2`, "known bug ") - st.fails(`^stCreateTest/TransactionCollisionToEmpty\.json/Byzantium/3`, "known bug ") + 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() { @@ -51,9 +59,6 @@ func TestState(t *testing.T) { key := fmt.Sprintf("%s/%d", subtest.Fork, subtest.Index) name := name + "/" + key t.Run(key, func(t *testing.T) { - if subtest.Fork == "Constantinople" { - t.Skip("constantinople not supported yet") - } withTrace(t, test.gasLimit(subtest), func(vmconfig vm.Config) error { _, err := test.Run(subtest, vmconfig) return st.checkFailure(t, name, err) @@ -66,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 } @@ -76,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/tests/state_test_util.go b/tests/state_test_util.go index 78c05b0245..436284196d 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -1,4 +1,4 @@ -// Copyright 2017 The go-ethereum Authors +// 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 @@ -31,10 +31,10 @@ import ( "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. @@ -125,9 +125,8 @@ func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config) (*state.StateD if !ok { return nil, UnsupportedForkError{subtest.Fork} } - block, _ := t.genesis(config).ToBlock() - db, _ := ethdb.NewMemDatabase() - statedb := MakePreState(db, t.json.Pre) + block := t.genesis(config).ToBlock(nil) + statedb := MakePreState(ethdb.NewMemDatabase(), t.json.Pre) post := t.json.Post[subtest.Fork][subtest.Index] msg, err := t.json.Tx.toMessage(post) @@ -144,13 +143,24 @@ func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config) (*state.StateD if _, _, _, err := core.ApplyMessage(evm, msg, gaspool); err != nil { statedb.RevertToSnapshot(snapshot) } - if logs := rlpHash(statedb.Logs()); logs != common.Hash(post.Logs) { - return statedb, fmt.Errorf("post state logs hash mismatch: got %x, want %x", logs, post.Logs) - } - root, _ := statedb.CommitTo(db, config.IsEIP158(block.Number())) + // Commit block + statedb.Commit(config.IsEIP158(block.Number())) + // Add 0-value mining reward. This only makes a difference in the cases + // where + // - the coinbase suicided, or + // - there are only 'bad' transactions, which aren't executed. In those cases, + // the coinbase gets no txfee, so isn't created, and thus needs to be touched + statedb.AddBalance(block.Coinbase(), new(big.Int)) + // And _now_ get the state root + root := statedb.IntermediateRoot(config.IsEIP158(block.Number())) + // N.B: We need to do this in a two-step process, because the first Commit takes care + // of suicides, and we need to touch the coinbase _after_ it has potentially suicided. if root != common.Hash(post.Root) { return statedb, fmt.Errorf("post state root mismatch: got %x, want %x", root, post.Root) } + if logs := rlpHash(statedb.Logs()); logs != common.Hash(post.Logs) { + return statedb, fmt.Errorf("post state logs hash mismatch: got %x, want %x", logs, post.Logs) + } return statedb, nil } @@ -170,7 +180,7 @@ func MakePreState(db ethdb.Database, accounts core.GenesisAlloc) *state.StateDB } } // Commit and re-open to start with a clean state. - root, _ := statedb.CommitTo(db, false) + root, _ := statedb.Commit(false) statedb, _ = state.New(root, sdb) return statedb } @@ -238,7 +248,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/tests/testdata b/tests/testdata index 2bb0c3da3b..6b85703b56 160000 --- a/tests/testdata +++ b/tests/testdata @@ -1 +1 @@ -Subproject commit 2bb0c3da3bbb15c528bcef2a7e5ac4bd73f81f87 +Subproject commit 6b85703b568f4456582a00665d8a3e5c3b20b484 diff --git a/tests/transaction_test.go b/tests/transaction_test.go index c743996c2a..42ad81877e 100644 --- a/tests/transaction_test.go +++ b/tests/transaction_test.go @@ -35,7 +35,7 @@ func TestTransaction(t *testing.T) { EIP150Block: big.NewInt(0), EIP155Block: big.NewInt(0), EIP158Block: big.NewInt(0), - ChainId: big.NewInt(1), + ChainID: big.NewInt(1), }) txt.config(`^Byzantium/`, params.ChainConfig{ HomesteadBlock: big.NewInt(0), diff --git a/tests/transaction_test_util.go b/tests/transaction_test_util.go index 2028d2a278..8c3dac088c 100644 --- a/tests/transaction_test_util.go +++ b/tests/transaction_test_util.go @@ -72,9 +72,8 @@ func (tt *TransactionTest) Run(config *params.ChainConfig) error { if err := rlp.DecodeBytes(tt.json.RLP, tx); err != nil { if tt.json.Transaction == nil { return nil - } else { - return fmt.Errorf("RLP decoding failed: %v", err) } + return fmt.Errorf("RLP decoding failed: %v", err) } // Check sender derivation. signer := types.MakeSigner(config, new(big.Int).SetUint64(uint64(tt.json.BlockNumber))) diff --git a/tests/vm_test.go b/tests/vm_test.go index c9f5e225e9..441483dffa 100644 --- a/tests/vm_test.go +++ b/tests/vm_test.go @@ -25,13 +25,9 @@ import ( func TestVM(t *testing.T) { t.Parallel() vmt := new(testMatcher) + vmt.slow("^vmPerformance") vmt.fails("^vmSystemOperationsTest.json/createNameRegistrator$", "fails without parallel execution") - vmt.skipLoad(`^vmInputLimits(Light)?.json`) // log format broken - - vmt.skipShortMode("^vmPerformanceTest.json") - vmt.skipShortMode("^vmInputLimits(Light)?.json") - vmt.walk(t, vmTestDir, func(t *testing.T, name string, test *VMTest) { withTrace(t, test.json.Exec.GasLimit, func(vmconfig vm.Config) error { return vmt.checkFailure(t, name, test.Run(vmconfig)) diff --git a/tests/vm_test_util.go b/tests/vm_test_util.go index b365167a69..cb81c5b94e 100644 --- a/tests/vm_test_util.go +++ b/tests/vm_test_util.go @@ -79,8 +79,7 @@ type vmExecMarshaling struct { } func (t *VMTest) Run(vmconfig vm.Config) error { - db, _ := ethdb.NewMemDatabase() - statedb := MakePreState(db, t.json.Pre) + statedb := MakePreState(ethdb.NewMemDatabase(), t.json.Pre) ret, gasRemaining, err := t.exec(statedb, vmconfig) if t.json.GasRemaining == nil { diff --git a/trie/database.go b/trie/database.go new file mode 100644 index 0000000000..958823eb8d --- /dev/null +++ b/trie/database.go @@ -0,0 +1,838 @@ +// 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 trie + +import ( + "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" + "github.com/ethereum/go-ethereum/metrics" + "github.com/ethereum/go-ethereum/rlp" +) + +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) + + memcacheGCTimeTimer = metrics.NewRegisteredResettingTimer("trie/memcache/gc/time", nil) + memcacheGCNodesMeter = metrics.NewRegisteredMeter("trie/memcache/gc/nodes", nil) + memcacheGCSizeMeter = metrics.NewRegisteredMeter("trie/memcache/gc/size", nil) + + memcacheCommitTimeTimer = metrics.NewRegisteredResettingTimer("trie/memcache/commit/time", nil) + memcacheCommitNodesMeter = metrics.NewRegisteredMeter("trie/memcache/commit/nodes", nil) + memcacheCommitSizeMeter = metrics.NewRegisteredMeter("trie/memcache/commit/size", nil) +) + +// secureKeyPrefix is the database key prefix used to store trie node preimages. +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. +type Database struct { + diskdb ethdb.Database // Persistent storage for matured trie nodes + + 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 + + gctime time.Duration // Time spent on garbage collection since last commit + gcnodes uint64 // Nodes garbage collected since last commit + gcsize common.StorageSize // Data storage garbage collected since last commit + + flushtime time.Duration // Time spent on data flushing since last commit + flushnodes uint64 // Nodes flushed since last commit + flushsize common.StorageSize // Data storage flushed since last commit + + dirtiesSize common.StorageSize // Storage size of the dirty node cache (exc. flushlist) + preimagesSize common.StorageSize // Storage size of the preimages cache + + lock sync.RWMutex +} + +// rawNode is a simple binary blob used to differentiate between collapsed trie +// nodes and already encoded RLP binary blobs (while at the same time store them +// in the same cache fields). +type rawNode []byte + +func (n rawNode) canUnload(uint16, uint16) bool { panic("this should never end up in a live trie") } +func (n rawNode) cache() (hashNode, bool) { panic("this should never end up in a live trie") } +func (n rawNode) fstring(ind string) string { panic("this should never end up in a live trie") } + +// rawFullNode represents only the useful data content of a full node, with the +// caches and flags stripped out to minimize its data storage. This type honors +// the same RLP encoding as the original parent. +type rawFullNode [17]node + +func (n rawFullNode) canUnload(uint16, uint16) bool { panic("this should never end up in a live trie") } +func (n rawFullNode) cache() (hashNode, bool) { panic("this should never end up in a live trie") } +func (n rawFullNode) fstring(ind string) string { panic("this should never end up in a live trie") } + +func (n rawFullNode) EncodeRLP(w io.Writer) error { + var nodes [17]node + + for i, child := range n { + if child != nil { + nodes[i] = child + } else { + nodes[i] = nilValueNode + } + } + return rlp.Encode(w, nodes) +} + +// rawShortNode represents only the useful data content of a short node, with the +// caches and flags stripped out to minimize its data storage. This type honors +// the same RLP encoding as the original parent. +type rawShortNode struct { + Key []byte + Val node +} + +func (n rawShortNode) canUnload(uint16, uint16) bool { panic("this should never end up in a live trie") } +func (n rawShortNode) cache() (hashNode, bool) { panic("this should never end up in a live trie") } +func (n rawShortNode) fstring(ind string) string { panic("this should never end up in a live trie") } + +// cachedNode is all the information we know about a single cached node in the +// memory database write layer. +type cachedNode struct { + node node // Cached collapsed trie node, or raw rlp data + size uint16 // Byte size of the useful cached data + + 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 + flushNext common.Hash // Next node in the flush-list +} + +// rlp returns the raw rlp encoded blob of the cached node, either directly from +// the cache, or by regenerating it from the collapsed node. +func (n *cachedNode) rlp() []byte { + if node, ok := n.node.(rawNode); ok { + return node + } + blob, err := rlp.EncodeToBytes(n.node) + if err != nil { + panic(err) + } + return blob +} + +// 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 { + if node, ok := n.node.(rawNode); ok { + return mustDecodeNode(hash[:], node, cachegen) + } + return expandNode(hash[:], n.node, cachegen) +} + +// childs returns all the tracked children of this node, both the implicit ones +// from inside the node as well as the explicit ones from outside the node. +func (n *cachedNode) childs() []common.Hash { + children := make([]common.Hash, 0, 16) + for child := range n.children { + children = append(children, child) + } + if _, ok := n.node.(rawNode); !ok { + gatherChildren(n.node, &children) + } + return children +} + +// gatherChildren traverses the node hierarchy of a collapsed storage node and +// retrieves all the hashnode children. +func gatherChildren(n node, children *[]common.Hash) { + switch n := n.(type) { + case *rawShortNode: + gatherChildren(n.Val, children) + + case rawFullNode: + for i := 0; i < 16; i++ { + gatherChildren(n[i], children) + } + case hashNode: + *children = append(*children, common.BytesToHash(n)) + + case valueNode, nil: + + default: + panic(fmt.Sprintf("unknown node type: %T", n)) + } +} + +// simplifyNode traverses the hierarchy of an expanded memory node and discards +// all the internal caches, returning a node that only contains the raw data. +func simplifyNode(n node) node { + switch n := n.(type) { + case *shortNode: + // Short nodes discard the flags and cascade + return &rawShortNode{Key: n.Key, Val: simplifyNode(n.Val)} + + case *fullNode: + // Full nodes discard the flags and cascade + node := rawFullNode(n.Children) + for i := 0; i < len(node); i++ { + if node[i] != nil { + node[i] = simplifyNode(node[i]) + } + } + return node + + case valueNode, hashNode, rawNode: + return n + + default: + panic(fmt.Sprintf("unknown node type: %T", n)) + } +} + +// 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 { + 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), + flags: nodeFlag{ + hash: hash, + gen: cachegen, + }, + } + + case rawFullNode: + // Full nodes need child expansion + 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) + } + } + return node + + case valueNode, hashNode: + return n + + default: + panic(fmt.Sprintf("unknown node type: %T", n)) + } +} + +// NewDatabase creates a new trie database to store ephemeral trie content before +// 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.Database) *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.Database, 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, + }) + } + return &Database{ + diskdb: diskdb, + 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 { + return db.diskdb +} + +// InsertBlob writes a new reference tracked blob to the memory database if it's +// yet unknown. This method should only be used for non-trie nodes that require +// reference counting, since trie nodes are garbage collected directly through +// their embedded children. +func (db *Database) InsertBlob(hash common.Hash, blob []byte) { + db.lock.Lock() + defer db.lock.Unlock() + + db.insert(hash, blob, rawNode(blob)) +} + +// insert inserts a collapsed trie node into the memory database. This method is +// a more generic version of InsertBlob, supporting both raw blob insertions as +// well ex trie node insertions. The blob must always be specified to allow proper +// size tracking. +func (db *Database) insert(hash common.Hash, blob []byte, node node) { + // If the node's already cached, skip + if _, ok := db.dirties[hash]; ok { + return + } + // Create the cached entry for this node + entry := &cachedNode{ + node: simplifyNode(node), + size: uint16(len(blob)), + flushPrev: db.newest, + } + for _, child := range entry.childs() { + if c := db.dirties[child]; c != nil { + c.parents++ + } + } + db.dirties[hash] = entry + + // Update the flush-list endpoints + if db.oldest == (common.Hash{}) { + db.oldest, db.newest = hash, hash + } else { + db.dirties[db.newest].flushNext, db.newest = hash, hash + } + db.dirtiesSize += common.StorageSize(common.HashLength + entry.size) +} + +// insertPreimage writes a new trie node pre-image to the memory database if it's +// yet unknown. The method will make a copy of the slice. +// +// Note, this method assumes that the database's lock is held! +func (db *Database) insertPreimage(hash common.Hash, preimage []byte) { + if _, ok := db.preimages[hash]; ok { + return + } + db.preimages[hash] = common.CopyBytes(preimage) + db.preimagesSize += common.StorageSize(common.HashLength + len(preimage)) +} + +// 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 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, cachegen) + } + } + // Retrieve the node from the dirty cache if available + db.lock.RLock() + dirty := db.dirties[hash] + db.lock.RUnlock() + + if dirty != nil { + return dirty.obj(hash, cachegen) + } + // Content unavailable in memory, attempt to retrieve from disk + enc, err := db.diskdb.Get(hash[:]) + if err != nil || enc == nil { + return nil + } + if db.cleans != nil { + db.cleans.Set(string(hash[:]), enc) + memcacheCleanMissMeter.Mark(1) + memcacheCleanWriteMeter.Mark(int64(len(enc))) + } + return mustDecodeNode(hash[:], enc, cachegen) +} + +// 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 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() + dirty := db.dirties[hash] + db.lock.RUnlock() + + if dirty != nil { + return dirty.rlp(), nil + } + // Content unavailable in memory, attempt to retrieve from disk + 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 +// found cached, the method queries the persistent database for the content. +func (db *Database) preimage(hash common.Hash) ([]byte, error) { + // Retrieve the node from cache if available + db.lock.RLock() + preimage := db.preimages[hash] + db.lock.RUnlock() + + if preimage != nil { + return preimage, nil + } + // Content unavailable in memory, attempt to retrieve from disk + return db.diskdb.Get(db.secureKey(hash[:])) +} + +// secureKey returns the database key for the preimage of key, as an ephemeral +// buffer. The caller must not hold onto the return value because it will become +// invalid on the next call. +func (db *Database) secureKey(key []byte) []byte { + buf := append(db.seckeybuf[:0], secureKeyPrefix...) + buf = append(buf, key...) + return buf +} + +// Nodes retrieves the hashes of all the nodes cached within the memory database. +// This method is extremely expensive and should only be used to validate internal +// states in test code. +func (db *Database) Nodes() []common.Hash { + db.lock.RLock() + defer db.lock.RUnlock() + + 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) + } + } + return hashes +} + +// 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.reference(child, parent) +} + +// 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.dirties[child] + if !ok { + return + } + // If the reference already exists, only duplicate for roots + 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.dirties[parent].children[child]++ +} + +// Dereference removes an existing reference from a root node. +func (db *Database) Dereference(root common.Hash) { + // Sanity check to ensure that the meta-root is not removed + if root == (common.Hash{}) { + log.Error("Attempted to dereference the trie cache meta root") + return + } + db.lock.Lock() + defer db.lock.Unlock() + + nodes, storage, start := len(db.dirties), db.dirtiesSize, time.Now() + db.dereference(root, common.Hash{}) + + 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.dirtiesSize)) + memcacheGCNodesMeter.Mark(int64(nodes - len(db.dirties))) + + 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.dirties[parent] + + if node.children != nil && node.children[child] > 0 { + node.children[child]-- + if node.children[child] == 0 { + delete(node.children, child) + } + } + // If the child does not exist, it's a previously committed node. + node, ok := db.dirties[child] + if !ok { + return + } + // If there are no more references to the child, delete it and cascade + if node.parents > 0 { + // This is a special cornercase where a node loaded from disk (i.e. not in the + // memcache any more) gets reinjected as a new node (short node split into full, + // then reverted into short), causing a cached node to have no parents. That is + // no problem in itself, but don't make maxint parents out of it. + node.parents-- + } + if node.parents == 0 { + // Remove the node from the flush-list + switch child { + case db.oldest: + db.oldest = node.flushNext + db.dirties[node.flushNext].flushPrev = common.Hash{} + case db.newest: + db.newest = node.flushPrev + db.dirties[node.flushPrev].flushNext = common.Hash{} + default: + 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.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. +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.dirties), db.dirtiesSize, time.Now() + batch := db.diskdb.NewBatch() + + // 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.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. + flushPreimages := db.preimagesSize > 4*1024*1024 + if flushPreimages { + 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() + } + } + } + // Keep committing nodes from the flush-list until we're below allowance + oldest := db.oldest + for size > limit && oldest != (common.Hash{}) { + // Fetch the oldest referenced node and push into the batch + 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() + } + // Iterate to the next flush item, or abort if the size cap was achieved. Size + // is the total size, including both the useful cached data (hash -> blob), as + // well as the flushlist metadata (2*hash). When flushing items from the cache, + // we need to reduce both. + size -= common.StorageSize(3*common.HashLength + int(node.size)) + oldest = node.flushNext + } + // 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() + + if flushPreimages { + db.preimages = make(map[common.Hash][]byte) + db.preimagesSize = 0 + } + for db.oldest != oldest { + node := db.dirties[db.oldest] + delete(db.dirties, db.oldest) + db.oldest = node.flushNext + + db.dirtiesSize -= common.StorageSize(common.HashLength + int(node.size)) + } + if db.oldest != (common.Hash{}) { + db.dirties[db.oldest].flushPrev = common.Hash{} + } + 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.dirtiesSize)) + memcacheFlushNodesMeter.Mark(int64(nodes - len(db.dirties))) + + 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. +// +// As a side effect, all pre-images accumulated up to this point are also written. +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() + + // Move all of the accumulated preimages into a write batch + 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() + } + } + // Move the trie itself into the batch, flushing if enough data is accumulated + nodes, storage := len(db.dirties), db.dirtiesSize + if err := db.commit(node, batch); err != nil { + log.Error("Failed to commit trie from trie database", "err", err) + db.lock.RUnlock() + return err + } + // Write batch ready, unlock for readers during persistence + 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 + db.lock.Lock() + defer db.lock.Unlock() + + db.preimages = make(map[common.Hash][]byte) + db.preimagesSize = 0 + + db.uncache(node) + + memcacheCommitTimeTimer.Update(time.Since(start)) + 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.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 + db.flushnodes, db.flushsize, db.flushtime = 0, 0, 0 + + return nil +} + +// commit is the private locked version of Commit. +func (db *Database) commit(hash common.Hash, batch ethdb.Batch) error { + // If the node does not exist, it's a previously committed node + node, ok := db.dirties[hash] + if !ok { + return nil + } + for _, child := range node.childs() { + if err := db.commit(child, batch); err != nil { + return err + } + } + if err := batch.Put(hash[:], node.rlp()); err != nil { + return err + } + // If we've reached an optimal batch size, commit and start over + if batch.ValueSize() >= ethdb.IdealBatchSize { + if err := batch.Write(); err != nil { + return err + } + batch.Reset() + } + 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) { + // If the node does not exist, we're done on this path + node, ok := db.dirties[hash] + if !ok { + return + } + // Node still exists, remove it from the flush-list + switch hash { + case db.oldest: + db.oldest = node.flushNext + db.dirties[node.flushNext].flushPrev = common.Hash{} + case db.newest: + db.newest = node.flushPrev + db.dirties[node.flushPrev].flushNext = common.Hash{} + default: + db.dirties[node.flushPrev].flushNext = node.flushNext + 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) + } + delete(db.dirties, hash) + db.dirtiesSize -= common.StorageSize(common.HashLength + int(node.size)) +} + +// Size returns the current storage size of the memory cache in front of the +// persistent database layer. +func (db *Database) Size() (common.StorageSize, common.StorageSize) { + db.lock.RLock() + defer db.lock.RUnlock() + + // 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.dirties) - 1) * 2 * common.HashLength) + return db.dirtiesSize + flushlistSize, db.preimagesSize +} + +// verifyIntegrity is a debug method to iterate over the entire trie stored in +// memory and check whether every node is reachable from the meta root. The goal +// is to find any errors that might cause memory leaks and or trie nodes to go +// missing. +// +// This method is extremely CPU and memory intensive, only use when must. +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.dirties[common.Hash{}].children { + db.accumulate(child, reachable) + } + // Find any unreachable but cached 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)) + } + } + if len(unreachable) != 0 { + panic(fmt.Sprintf("trie cache memory leak: %v", unreachable)) + } +} + +// accumulate iterates over the trie defined by hash and accumulates all the +// 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.dirties[hash] + if !ok { + return + } + reachable[hash] = struct{}{} + + // Iterate over all the children and accumulate them too + for _, child := range node.childs() { + db.accumulate(child, reachable) + } +} diff --git a/trie/encoding.go b/trie/encoding.go index e96a786e40..1955a3e664 100644 --- a/trie/encoding.go +++ b/trie/encoding.go @@ -52,11 +52,13 @@ func hexToCompact(hex []byte) []byte { } func compactToHex(compact []byte) []byte { + if len(compact) == 0 { + return compact + } base := keybytesToHex(compact) - base = base[:len(base)-1] - // apply terminator flag - if base[0] >= 2 { - base = append(base, 16) + // delete terminator flag + if base[0] < 2 { + base = base[:len(base)-1] } // apply odd flag chop := 2 - base[0]&1 @@ -83,7 +85,7 @@ func hexToKeybytes(hex []byte) []byte { if len(hex)&1 != 0 { panic("can't convert hex key of odd length") } - key := make([]byte, (len(hex)+1)/2) + key := make([]byte, len(hex)/2) decodeNibbles(hex, key) return key } diff --git a/trie/hasher.go b/trie/hasher.go index 4719aabf62..9d6756b6f4 100644 --- a/trie/hasher.go +++ b/trie/hasher.go @@ -17,31 +17,54 @@ package trie import ( - "bytes" "hash" "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 *bytes.Buffer - sha hash.Hash - cachegen, cachelimit uint16 + tmp sliceBuffer + sha keccakState + cachegen uint16 + cachelimit uint16 + onleaf LeafCallback } -// hashers live in a global pool. +// keccakState wraps sha3.state. In addition to the usual hash methods, it also supports +// Read to get a variable amount of data from the hash state. Read is faster than Sum +// because it doesn't copy the internal state, but also modifies the internal state. +type keccakState interface { + hash.Hash + Read([]byte) (int, error) +} + +type sliceBuffer []byte + +func (b *sliceBuffer) Write(data []byte) (n int, err error) { + *b = append(*b, data...) + return len(data), nil +} + +func (b *sliceBuffer) Reset() { + *b = (*b)[:0] +} + +// hashers live in a global db. var hasherPool = sync.Pool{ New: func() interface{} { - return &hasher{tmp: new(bytes.Buffer), sha: sha3.NewKeccak256()} + return &hasher{ + tmp: make(sliceBuffer, 0, 550), // cap is as large as a full fullNode. + sha: sha3.NewLegacyKeccak256().(keccakState), + } }, } -func newHasher(cachegen, cachelimit uint16) *hasher { +func newHasher(cachegen, cachelimit uint16, onleaf LeafCallback) *hasher { h := hasherPool.Get().(*hasher) - h.cachegen, h.cachelimit = cachegen, cachelimit + h.cachegen, h.cachelimit, h.onleaf = cachegen, cachelimit, onleaf return h } @@ -51,7 +74,7 @@ func returnHasherToPool(h *hasher) { // hash collapses a node down into a hash node, also returning a copy of the // original node initialized with the computed hash to replace the original one. -func (h *hasher) hash(n node, db DatabaseWriter, force bool) (node, node, error) { +func (h *hasher) hash(n node, db *Database, force bool) (node, node, error) { // If we're not storing the node, just hashing, use available cached data if hash, dirty := n.cache(); hash != nil { if db == nil { @@ -98,7 +121,7 @@ func (h *hasher) hash(n node, db DatabaseWriter, force bool) (node, node, error) // hashChildren replaces the children of a node with their hashes if the encoded // size of the child is larger than a hash, returning the collapsed node as well // as a replacement for the original node with the child hashes cached in. -func (h *hasher) hashChildren(original node, db DatabaseWriter) (node, node, error) { +func (h *hasher) hashChildren(original node, db *Database) (node, node, error) { var err error switch n := original.(type) { @@ -114,9 +137,6 @@ func (h *hasher) hashChildren(original node, db DatabaseWriter) (node, node, err return original, original, err } } - if collapsed.Val == nil { - collapsed.Val = valueNode(nil) // Ensure that nil children are encoded as empty strings. - } return collapsed, cached, nil case *fullNode: @@ -129,14 +149,9 @@ func (h *hasher) hashChildren(original node, db DatabaseWriter) (node, node, err if err != nil { return original, original, err } - } else { - collapsed.Children[i] = valueNode(nil) // Ensure that nil children are encoded as empty strings. } } cached.Children[16] = n.Children[16] - if collapsed.Children[16] == nil { - collapsed.Children[16] = valueNode(nil) - } return collapsed, cached, nil default: @@ -145,29 +160,59 @@ func (h *hasher) hashChildren(original node, db DatabaseWriter) (node, node, err } } -func (h *hasher) store(n node, db DatabaseWriter, force bool) (node, error) { +// store hashes the node n and if we have a storage layer specified, it writes +// the key/value pair to it and tracks any node->child references as well as any +// node->external trie references. +func (h *hasher) store(n node, db *Database, force bool) (node, error) { // Don't store hashes or empty nodes. if _, isHash := n.(hashNode); n == nil || isHash { return n, nil } // Generate the RLP encoding of the node h.tmp.Reset() - if err := rlp.Encode(h.tmp, n); err != nil { + if err := rlp.Encode(&h.tmp, n); err != nil { panic("encode error: " + err.Error()) } - - if h.tmp.Len() < 32 && !force { + if len(h.tmp) < 32 && !force { return n, nil // Nodes smaller than 32 bytes are stored inside their parent } // Larger nodes are replaced by their hash and stored in the database. hash, _ := n.cache() if hash == nil { - h.sha.Reset() - h.sha.Write(h.tmp.Bytes()) - hash = hashNode(h.sha.Sum(nil)) + hash = h.makeHashNode(h.tmp) } + if db != nil { - return hash, db.Put(hash, h.tmp.Bytes()) + // We are pooling the trie nodes into an intermediate memory cache + hash := common.BytesToHash(hash) + + db.lock.Lock() + db.insert(hash, h.tmp, n) + db.lock.Unlock() + + // Track external references from account->storage trie + if h.onleaf != nil { + switch n := n.(type) { + case *shortNode: + if child, ok := n.Val.(valueNode); ok { + h.onleaf(child, hash) + } + case *fullNode: + for i := 0; i < 16; i++ { + if child, ok := n.Children[i].(valueNode); ok { + h.onleaf(child, hash) + } + } + } + } } return hash, nil } + +func (h *hasher) makeHashNode(data []byte) hashNode { + n := make(hashNode, h.sha.Size()) + h.sha.Reset() + h.sha.Write(data) + h.sha.Read(n) + return n +} diff --git a/trie/iterator.go b/trie/iterator.go index 76146c0d64..77f1681665 100644 --- a/trie/iterator.go +++ b/trie/iterator.go @@ -22,6 +22,7 @@ import ( "errors" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/rlp" ) // Iterator is a key-value trie iterator that traverses a Trie. @@ -55,31 +56,50 @@ func (it *Iterator) Next() bool { return false } +// Prove generates the Merkle proof for the leaf node the iterator is currently +// positioned on. +func (it *Iterator) Prove() [][]byte { + return it.nodeIt.LeafProof() +} + // NodeIterator is an iterator to traverse the trie pre-order. type NodeIterator interface { // Next moves the iterator to the next node. If the parameter is false, any child // nodes will be skipped. Next(bool) bool + // Error returns the error status of the iterator. Error() error // Hash returns the hash of the current node. Hash() common.Hash + // Parent returns the hash of the parent of the current node. The hash may be the one // grandparent if the immediate parent is an internal node with no hash. Parent() common.Hash + // Path returns the hex-encoded path to the current node. // Callers must not retain references to the return value after calling Next. // For leaf nodes, the last element of the path is the 'terminator symbol' 0x10. Path() []byte // Leaf returns true iff the current node is a leaf node. - // LeafBlob, LeafKey return the contents and key of the leaf node. These - // method panic if the iterator is not positioned at a leaf. - // Callers must not retain references to their return value after calling Next Leaf() bool - LeafBlob() []byte + + // LeafKey returns the key of the leaf. The method panics if the iterator is not + // positioned at a leaf. Callers must not retain references to the value after + // calling Next. LeafKey() []byte + + // LeafBlob returns the content of the leaf. The method panics if the iterator + // is not positioned at a leaf. Callers must not retain references to the value + // after calling Next. + LeafBlob() []byte + + // LeafProof returns the Merkle proof of the leaf. The method panics if the + // iterator is not positioned at a leaf. Callers must not retain references + // to the value after calling Next. + LeafProof() [][]byte } // nodeIteratorState represents the iteration state at one particular node of the @@ -99,8 +119,8 @@ type nodeIterator struct { err error // Failure set in case of an internal error in the iterator } -// iteratorEnd is stored in nodeIterator.err when iteration is done. -var iteratorEnd = errors.New("end of iteration") +// errIteratorEnd is stored in nodeIterator.err when iteration is done. +var errIteratorEnd = errors.New("end of iteration") // seekError is stored in nodeIterator.err if the initial seek has failed. type seekError struct { @@ -139,6 +159,15 @@ func (it *nodeIterator) Leaf() bool { return hasTerm(it.path) } +func (it *nodeIterator) LeafKey() []byte { + if len(it.stack) > 0 { + if _, ok := it.stack[len(it.stack)-1].node.(valueNode); ok { + return hexToKeybytes(it.path) + } + } + panic("not at leaf") +} + func (it *nodeIterator) LeafBlob() []byte { if len(it.stack) > 0 { if node, ok := it.stack[len(it.stack)-1].node.(valueNode); ok { @@ -148,10 +177,24 @@ func (it *nodeIterator) LeafBlob() []byte { panic("not at leaf") } -func (it *nodeIterator) LeafKey() []byte { +func (it *nodeIterator) LeafProof() [][]byte { if len(it.stack) > 0 { if _, ok := it.stack[len(it.stack)-1].node.(valueNode); ok { - return hexToKeybytes(it.path) + hasher := newHasher(0, 0, nil) + defer returnHasherToPool(hasher) + + proofs := make([][]byte, 0, len(it.stack)) + + for i, item := range it.stack[:len(it.stack)-1] { + // Gather nodes that end up as hash nodes (or the root) + node, _, _ := hasher.hashChildren(item.node, nil) + hashed, _ := hasher.store(node, nil, false) + if _, ok := hashed.(hashNode); ok || i == 0 { + enc, _ := rlp.EncodeToBytes(node) + proofs = append(proofs, enc) + } + } + return proofs } } panic("not at leaf") @@ -162,7 +205,7 @@ func (it *nodeIterator) Path() []byte { } func (it *nodeIterator) Error() error { - if it.err == iteratorEnd { + if it.err == errIteratorEnd { return nil } if seek, ok := it.err.(seekError); ok { @@ -176,7 +219,7 @@ func (it *nodeIterator) Error() error { // sets the Error field to the encountered failure. If `descend` is false, // skips iterating over any subnodes of the current node. func (it *nodeIterator) Next(descend bool) bool { - if it.err == iteratorEnd { + if it.err == errIteratorEnd { return false } if seek, ok := it.err.(seekError); ok { @@ -201,8 +244,8 @@ func (it *nodeIterator) seek(prefix []byte) error { // Move forward until we're just before the closest match to key. for { state, parentIndex, path, err := it.peek(bytes.HasPrefix(key, it.path)) - if err == iteratorEnd { - return iteratorEnd + if err == errIteratorEnd { + return errIteratorEnd } else if err != nil { return seekError{prefix, err} } else if bytes.Compare(path, key) >= 0 { @@ -246,7 +289,7 @@ func (it *nodeIterator) peek(descend bool) (*nodeIteratorState, *int, []byte, er // No more child nodes, move back up. it.pop() } - return nil, nil, nil, iteratorEnd + return nil, nil, nil, errIteratorEnd } func (st *nodeIteratorState) resolve(tr *Trie, path []byte) error { @@ -303,7 +346,7 @@ func (it *nodeIterator) push(state *nodeIteratorState, parentIndex *int, path [] it.path = path it.stack = append(it.stack, state) if parentIndex != nil { - *parentIndex += 1 + *parentIndex++ } } @@ -361,12 +404,16 @@ func (it *differenceIterator) Leaf() bool { return it.b.Leaf() } +func (it *differenceIterator) LeafKey() []byte { + return it.b.LeafKey() +} + func (it *differenceIterator) LeafBlob() []byte { return it.b.LeafBlob() } -func (it *differenceIterator) LeafKey() []byte { - return it.b.LeafKey() +func (it *differenceIterator) LeafProof() [][]byte { + return it.b.LeafProof() } func (it *differenceIterator) Path() []byte { @@ -380,7 +427,7 @@ func (it *differenceIterator) Next(bool) bool { if !it.b.Next(true) { return false } - it.count += 1 + it.count++ if it.eof { // a has reached eof, so we just return all elements from b @@ -395,7 +442,7 @@ func (it *differenceIterator) Next(bool) bool { it.eof = true return true } - it.count += 1 + it.count++ case 1: // b is before a return true @@ -405,12 +452,12 @@ func (it *differenceIterator) Next(bool) bool { if !it.b.Next(hasHash) { return false } - it.count += 1 + it.count++ if !it.a.Next(hasHash) { it.eof = true return true } - it.count += 1 + it.count++ } } } @@ -464,12 +511,16 @@ func (it *unionIterator) Leaf() bool { return (*it.items)[0].Leaf() } +func (it *unionIterator) LeafKey() []byte { + return (*it.items)[0].LeafKey() +} + func (it *unionIterator) LeafBlob() []byte { return (*it.items)[0].LeafBlob() } -func (it *unionIterator) LeafKey() []byte { - return (*it.items)[0].LeafKey() +func (it *unionIterator) LeafProof() [][]byte { + return (*it.items)[0].LeafProof() } func (it *unionIterator) Path() []byte { @@ -504,17 +555,15 @@ func (it *unionIterator) Next(descend bool) bool { skipped := heap.Pop(it.items).(NodeIterator) // Skip the whole subtree if the nodes have hashes; otherwise just skip this node if skipped.Next(skipped.Hash() == common.Hash{}) { - it.count += 1 + it.count++ // If there are more elements, push the iterator back on the heap heap.Push(it.items, skipped) } } - if least.Next(descend) { - it.count += 1 + it.count++ heap.Push(it.items, least) } - return len(*it.items) > 0 } diff --git a/trie/iterator_test.go b/trie/iterator_test.go index 4808d8b0c6..4f633b195f 100644 --- a/trie/iterator_test.go +++ b/trie/iterator_test.go @@ -42,7 +42,7 @@ func TestIterator(t *testing.T) { all[val.k] = val.v trie.Update([]byte(val.k), []byte(val.v)) } - trie.Commit() + trie.Commit(nil) found := make(map[string]string) it := NewIterator(trie.NodeIterator(nil)) @@ -109,11 +109,18 @@ func TestNodeIteratorCoverage(t *testing.T) { } // Cross check the hashes and the database itself for hash := range hashes { - if _, err := db.Get(hash.Bytes()); err != nil { + if _, err := db.Node(hash); err != nil { t.Errorf("failed to retrieve reported node %x: %v", hash, err) } } - for _, key := range db.(*ethdb.MemDatabase).Keys() { + 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() { if _, ok := hashes[common.BytesToHash(key)]; !ok { t.Errorf("state entry not reported %x", key) } @@ -191,13 +198,13 @@ func TestDifferenceIterator(t *testing.T) { for _, val := range testdata1 { triea.Update([]byte(val.k), []byte(val.v)) } - triea.Commit() + triea.Commit(nil) trieb := newEmpty() for _, val := range testdata2 { trieb.Update([]byte(val.k), []byte(val.v)) } - trieb.Commit() + trieb.Commit(nil) found := make(map[string]string) di, _ := NewDifferenceIterator(triea.NodeIterator(nil), trieb.NodeIterator(nil)) @@ -227,13 +234,13 @@ func TestUnionIterator(t *testing.T) { for _, val := range testdata1 { triea.Update([]byte(val.k), []byte(val.v)) } - triea.Commit() + triea.Commit(nil) trieb := newEmpty() for _, val := range testdata2 { trieb.Update([]byte(val.k), []byte(val.v)) } - trieb.Commit() + trieb.Commit(nil) di, _ := NewUnionIterator([]NodeIterator{triea.NodeIterator(nil), trieb.NodeIterator(nil)}) it := NewIterator(di) @@ -278,43 +285,75 @@ func TestIteratorNoDups(t *testing.T) { } // This test checks that nodeIterator.Next can be retried after inserting missing trie nodes. -func TestIteratorContinueAfterError(t *testing.T) { - db, _ := ethdb.NewMemDatabase() - tr, _ := New(common.Hash{}, db) +func TestIteratorContinueAfterErrorDisk(t *testing.T) { testIteratorContinueAfterError(t, false) } +func TestIteratorContinueAfterErrorMemonly(t *testing.T) { testIteratorContinueAfterError(t, true) } + +func testIteratorContinueAfterError(t *testing.T, memonly bool) { + diskdb := ethdb.NewMemDatabase() + triedb := NewDatabase(diskdb) + + tr, _ := New(common.Hash{}, triedb) for _, val := range testdata1 { tr.Update([]byte(val.k), []byte(val.v)) } - tr.Commit() + tr.Commit(nil) + if !memonly { + triedb.Commit(tr.Hash(), true) + } wantNodeCount := checkIteratorNoDups(t, tr.NodeIterator(nil), nil) - keys := db.Keys() - t.Log("node count", wantNodeCount) + var ( + diskKeys [][]byte + memKeys []common.Hash + ) + if memonly { + memKeys = triedb.Nodes() + } else { + diskKeys = diskdb.Keys() + } for i := 0; i < 20; i++ { // Create trie that will load all nodes from DB. - tr, _ := New(tr.Hash(), db) + tr, _ := New(tr.Hash(), triedb) // Remove a random node from the database. It can't be the root node // because that one is already loaded. - var rkey []byte + var ( + rkey common.Hash + rval []byte + robj *cachedNode + ) for { - if rkey = keys[rand.Intn(len(keys))]; !bytes.Equal(rkey, tr.Hash().Bytes()) { + if memonly { + rkey = memKeys[rand.Intn(len(memKeys))] + } else { + copy(rkey[:], diskKeys[rand.Intn(len(diskKeys))]) + } + if rkey != tr.Hash() { break } } - rval, _ := db.Get(rkey) - db.Delete(rkey) - + if memonly { + robj = triedb.dirties[rkey] + delete(triedb.dirties, rkey) + } else { + rval, _ = diskdb.Get(rkey[:]) + diskdb.Delete(rkey[:]) + } // Iterate until the error is hit. seen := make(map[string]bool) it := tr.NodeIterator(nil) checkIteratorNoDups(t, it, seen) missing, ok := it.Error().(*MissingNodeError) - if !ok || !bytes.Equal(missing.NodeHash[:], rkey) { + if !ok || missing.NodeHash != rkey { t.Fatal("didn't hit missing node, got", it.Error()) } // Add the node back and continue iteration. - db.Put(rkey, rval) + if memonly { + triedb.dirties[rkey] = robj + } else { + diskdb.Put(rkey[:], rval) + } checkIteratorNoDups(t, it, seen) if it.Error() != nil { t.Fatal("unexpected error", it.Error()) @@ -328,21 +367,41 @@ func TestIteratorContinueAfterError(t *testing.T) { // Similar to the test above, this one checks that failure to create nodeIterator at a // certain key prefix behaves correctly when Next is called. The expectation is that Next // should retry seeking before returning true for the first time. -func TestIteratorContinueAfterSeekError(t *testing.T) { +func TestIteratorContinueAfterSeekErrorDisk(t *testing.T) { + testIteratorContinueAfterSeekError(t, false) +} +func TestIteratorContinueAfterSeekErrorMemonly(t *testing.T) { + testIteratorContinueAfterSeekError(t, true) +} + +func testIteratorContinueAfterSeekError(t *testing.T, memonly bool) { // Commit test trie to db, then remove the node containing "bars". - db, _ := ethdb.NewMemDatabase() - ctr, _ := New(common.Hash{}, db) + diskdb := ethdb.NewMemDatabase() + triedb := NewDatabase(diskdb) + + ctr, _ := New(common.Hash{}, triedb) for _, val := range testdata1 { ctr.Update([]byte(val.k), []byte(val.v)) } - root, _ := ctr.Commit() + root, _ := ctr.Commit(nil) + if !memonly { + triedb.Commit(root, true) + } barNodeHash := common.HexToHash("05041990364eb72fcb1127652ce40d8bab765f2bfe53225b1170d276cc101c2e") - barNode, _ := db.Get(barNodeHash[:]) - db.Delete(barNodeHash[:]) - + var ( + barNodeBlob []byte + barNodeObj *cachedNode + ) + if memonly { + barNodeObj = triedb.dirties[barNodeHash] + delete(triedb.dirties, barNodeHash) + } else { + barNodeBlob, _ = diskdb.Get(barNodeHash[:]) + diskdb.Delete(barNodeHash[:]) + } // Create a new iterator that seeks to "bars". Seeking can't proceed because // the node is missing. - tr, _ := New(root, db) + tr, _ := New(root, triedb) it := tr.NodeIterator([]byte("bars")) missing, ok := it.Error().(*MissingNodeError) if !ok { @@ -350,10 +409,12 @@ func TestIteratorContinueAfterSeekError(t *testing.T) { } else if missing.NodeHash != barNodeHash { t.Fatal("wrong node missing") } - // Reinsert the missing node. - db.Put(barNodeHash[:], barNode[:]) - + if memonly { + triedb.dirties[barNodeHash] = barNodeObj + } else { + diskdb.Put(barNodeHash[:], barNodeBlob) + } // Check that iteration produces the right set of values. if err := checkIteratorOrder(testdata1[2:], NewIterator(it)); err != nil { t.Fatal(err) diff --git a/trie/node.go b/trie/node.go index a7697fc0c6..1fafb7a538 100644 --- a/trie/node.go +++ b/trie/node.go @@ -47,9 +47,22 @@ type ( valueNode []byte ) +// nilValueNode is used when collapsing internal trie nodes for hashing, since +// unset children need to serialize correctly. +var nilValueNode = valueNode(nil) + // EncodeRLP encodes a full node into the consensus RLP format. func (n *fullNode) EncodeRLP(w io.Writer) error { - return rlp.Encode(w, n.Children) + var nodes [17]node + + for i, child := range &n.Children { + if child != nil { + nodes[i] = child + } else { + nodes[i] = nilValueNode + } + } + return rlp.Encode(w, nodes) } func (n *fullNode) copy() *fullNode { copy := *n; return © } @@ -85,7 +98,7 @@ func (n valueNode) String() string { return n.fstring("") } func (n *fullNode) fstring(ind string) string { resp := fmt.Sprintf("[\n%s ", ind) - for i, node := range n.Children { + for i, node := range &n.Children { if node == nil { resp += fmt.Sprintf("%s: ", indices[i]) } else { @@ -123,17 +136,17 @@ func decodeNode(hash, buf []byte, cachegen uint16) (node, error) { } switch c, _ := rlp.CountValues(elems); c { case 2: - n, err := decodeShort(hash, buf, elems, cachegen) + n, err := decodeShort(hash, elems, cachegen) return n, wrapError(err, "short") case 17: - n, err := decodeFull(hash, buf, elems, cachegen) + n, err := decodeFull(hash, elems, cachegen) return n, wrapError(err, "full") default: return nil, fmt.Errorf("invalid number of list elements: %v", c) } } -func decodeShort(hash, buf, elems []byte, cachegen uint16) (node, error) { +func decodeShort(hash, elems []byte, cachegen uint16) (node, error) { kbuf, rest, err := rlp.SplitString(elems) if err != nil { return nil, err @@ -155,7 +168,7 @@ func decodeShort(hash, buf, elems []byte, cachegen uint16) (node, error) { return &shortNode{key, r, flag}, nil } -func decodeFull(hash, buf, elems []byte, cachegen uint16) (*fullNode, error) { +func decodeFull(hash, elems []byte, cachegen uint16) (*fullNode, error) { n := &fullNode{flags: nodeFlag{hash: hash, gen: cachegen}} for i := 0; i < 16; i++ { cld, rest, err := decodeRef(elems, cachegen) diff --git a/trie/proof.go b/trie/proof.go index 5e886a2598..1334bde970 100644 --- a/trie/proof.go +++ b/trie/proof.go @@ -22,23 +22,22 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" ) -// 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. +// 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 node), ending with the node that proves the -// absence of the key. -func (t *Trie) Prove(key []byte, fromLevel uint, proofDb DatabaseWriter) 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 *Trie) Prove(key []byte, fromLevel uint, proofDb ethdb.Putter) 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) { @@ -66,7 +65,9 @@ func (t *Trie) Prove(key []byte, fromLevel uint, proofDb DatabaseWriter) error { panic(fmt.Sprintf("%T: invalid node: %v", tn, tn)) } } - hasher := newHasher(0, 0) + hasher := newHasher(0, 0, 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. @@ -89,32 +90,42 @@ func (t *Trie) Prove(key []byte, fromLevel uint, proofDb DatabaseWriter) error { return nil } -// 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, err error, nodes int) { +// 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 node), ending +// with the node that proves the absence of the key. +func (t *SecureTrie) Prove(key []byte, fromLevel uint, proofDb ethdb.Putter) 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) { key = keybytesToHex(key) - wantHash := rootHash[:] + wantHash := rootHash for i := 0; ; i++ { - buf, _ := proofDb.Get(wantHash) + buf, _ := proofDb.Get(wantHash[:]) if buf == nil { - return nil, fmt.Errorf("proof node %d (hash %064x) missing", i, wantHash[:]), i + return nil, i, fmt.Errorf("proof node %d (hash %064x) missing", i, wantHash) } - n, err := decodeNode(wantHash, buf, 0) + n, err := decodeNode(wantHash[:], buf, 0) if err != nil { - return nil, fmt.Errorf("bad proof node %d: %v", i, err), i + return nil, i, fmt.Errorf("bad proof node %d: %v", i, err) } keyrest, cld := get(n, key) switch cld := cld.(type) { case nil: // The trie doesn't contain the key. - return nil, nil, i + return nil, i, nil case hashNode: key = keyrest - wantHash = cld + copy(wantHash[:], cld) case valueNode: - return cld, nil, i + 1 + return cld, i + 1, nil } } } diff --git a/trie/proof_test.go b/trie/proof_test.go index fff313d7fd..996f874781 100644 --- a/trie/proof_test.go +++ b/trie/proof_test.go @@ -32,20 +32,46 @@ func init() { mrand.Seed(time.Now().Unix()) } +// 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 + + // Create a direct trie based Merkle prover + provers = append(provers, func(key []byte) *ethdb.MemDatabase { + proof := ethdb.NewMemDatabase() + 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() + if it := NewIterator(trie.NodeIterator(key)); it.Next() && bytes.Equal(key, it.Key) { + for _, p := range it.Prove() { + proof.Put(crypto.Keccak256(p), p) + } + } + return proof + }) + return provers +} + func TestProof(t *testing.T) { trie, vals := randomTrie(500) root := trie.Hash() - for _, kv := range vals { - proofs, _ := ethdb.NewMemDatabase() - if trie.Prove(kv.k, 0, proofs) != nil { - t.Fatalf("missing key %x while constructing proof", kv.k) - } - val, err, _ := VerifyProof(root, kv.k, proofs) - if err != nil { - t.Fatalf("VerifyProof error for key %x: %v\nraw proof: %v", kv.k, err, proofs) - } - if !bytes.Equal(val, kv.v) { - t.Fatalf("VerifyProof returned wrong value for key %x: got %x, want %x", kv.k, val, kv.v) + for i, prover := range makeProvers(trie) { + for _, kv := range vals { + proof := prover(kv.k) + if proof == nil { + t.Fatalf("prover %d: missing key %x while constructing proof", i, kv.k) + } + val, _, err := VerifyProof(root, kv.k, proof) + if err != nil { + t.Fatalf("prover %d: failed to verify proof for key %x: %v\nraw proof: %x", i, kv.k, err, proof) + } + if !bytes.Equal(val, kv.v) { + t.Fatalf("prover %d: verified value mismatch for key %x: have %x, want %x", i, kv.k, val, kv.v) + } } } } @@ -53,37 +79,66 @@ func TestProof(t *testing.T) { func TestOneElementProof(t *testing.T) { trie := new(Trie) updateString(trie, "k", "v") - proofs, _ := ethdb.NewMemDatabase() - trie.Prove([]byte("k"), 0, proofs) - if len(proofs.Keys()) != 1 { - t.Error("proof should have one element") - } - val, err, _ := VerifyProof(trie.Hash(), []byte("k"), proofs) - if err != nil { - t.Fatalf("VerifyProof error: %v\nproof hashes: %v", err, proofs.Keys()) - } - if !bytes.Equal(val, []byte("v")) { - t.Fatalf("VerifyProof returned wrong value: got %x, want 'k'", val) + for i, prover := range makeProvers(trie) { + proof := prover([]byte("k")) + if proof == nil { + t.Fatalf("prover %d: nil proof", i) + } + if proof.Len() != 1 { + t.Errorf("prover %d: proof should have one element", i) + } + val, _, err := VerifyProof(trie.Hash(), []byte("k"), proof) + if err != nil { + t.Fatalf("prover %d: failed to verify proof: %v\nraw proof: %x", i, err, proof) + } + if !bytes.Equal(val, []byte("v")) { + t.Fatalf("prover %d: verified value mismatch: have %x, want 'k'", i, val) + } } } -func TestVerifyBadProof(t *testing.T) { +func TestBadProof(t *testing.T) { trie, vals := randomTrie(800) root := trie.Hash() - for _, kv := range vals { - proofs, _ := ethdb.NewMemDatabase() - trie.Prove(kv.k, 0, proofs) - if len(proofs.Keys()) == 0 { - t.Fatal("zero length proof") + for i, prover := range makeProvers(trie) { + for _, kv := range vals { + proof := prover(kv.k) + if proof == nil { + t.Fatalf("prover %d: nil proof", i) + } + key := proof.Keys()[mrand.Intn(proof.Len())] + val, _ := proof.Get(key) + proof.Delete(key) + + mutateByte(val) + proof.Put(crypto.Keccak256(val), val) + + if _, _, err := VerifyProof(root, kv.k, proof); err == nil { + t.Fatalf("prover %d: expected proof to fail for key %x", i, kv.k) + } } - keys := proofs.Keys() - key := keys[mrand.Intn(len(keys))] - node, _ := proofs.Get(key) - proofs.Delete(key) - mutateByte(node) - proofs.Put(crypto.Keccak256(node), node) - if _, err, _ := VerifyProof(root, kv.k, proofs); err == nil { - t.Fatalf("expected proof to fail for key %x", kv.k) + } +} + +// Tests that missing keys can also be proven. The test explicitly uses a single +// entry trie and checks for missing keys both before and after the single entry. +func TestMissingKeyProof(t *testing.T) { + trie := new(Trie) + updateString(trie, "k", "v") + + for i, key := range []string{"a", "j", "l", "z"} { + proof := ethdb.NewMemDatabase() + trie.Prove([]byte(key), 0, proof) + + if proof.Len() != 1 { + t.Errorf("test %d: proof should have one element", i) + } + val, _, err := VerifyProof(trie.Hash(), []byte(key), proof) + if err != nil { + t.Fatalf("test %d: failed to verify proof: %v\nraw proof: %x", i, err, proof) + } + if val != nil { + t.Fatalf("test %d: verified value mismatch: have %x, want nil", i, val) } } } @@ -109,7 +164,7 @@ func BenchmarkProve(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { kv := vals[keys[i%len(keys)]] - proofs, _ := ethdb.NewMemDatabase() + proofs := ethdb.NewMemDatabase() if trie.Prove(kv.k, 0, proofs); len(proofs.Keys()) == 0 { b.Fatalf("zero length proof for %x", kv.k) } @@ -123,7 +178,7 @@ func BenchmarkVerifyProof(b *testing.B) { var proofs []*ethdb.MemDatabase for k := range vals { keys = append(keys, k) - proof, _ := ethdb.NewMemDatabase() + proof := ethdb.NewMemDatabase() trie.Prove([]byte(k), 0, proof) proofs = append(proofs, proof) } @@ -131,7 +186,7 @@ func BenchmarkVerifyProof(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { im := i % len(keys) - if _, err, _ := VerifyProof(root, []byte(keys[im]), proofs[im]); err != nil { + if _, _, err := VerifyProof(root, []byte(keys[im]), proofs[im]); err != nil { b.Fatalf("key %x: %v", keys[im], err) } } diff --git a/trie/secure_trie.go b/trie/secure_trie.go index 20c303f31c..6a50cfd5a6 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -23,10 +23,6 @@ import ( "github.com/ethereum/go-ethereum/log" ) -var secureKeyPrefix = []byte("secure-key-") - -const secureKeyLength = 11 + 32 // Length of the above prefix + 32byte hash - // SecureTrie wraps a trie with key hashing. In a secure trie, all // access operations hash the key using keccak256. This prevents // calling code from creating long chains of nodes that @@ -39,25 +35,25 @@ const secureKeyLength = 11 + 32 // Length of the above prefix + 32byte hash // SecureTrie is not safe for concurrent use. type SecureTrie struct { trie Trie - hashKeyBuf [secureKeyLength]byte - secKeyBuf [200]byte + hashKeyBuf [common.HashLength]byte secKeyCache map[string][]byte secKeyCacheOwner *SecureTrie // Pointer to self, replace the key cache on mismatch } -// NewSecure creates a trie with an existing root node from db. +// NewSecure creates a trie with an existing root node from a backing database +// and optional intermediate in-memory node pool. // // If root is the zero hash or the sha3 hash of an empty string, the // trie is initially empty. Otherwise, New will panic if db is nil // and returns MissingNodeError if the root node cannot be found. // -// Accessing the trie loads nodes from db on demand. +// Accessing the trie loads nodes from the database or node pool on demand. // 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, cachelimit uint16) (*SecureTrie, error) { if db == nil { - panic("NewSecure called with nil database") + panic("trie.NewSecure called without a database") } trie, err := New(root, db) if err != nil { @@ -135,7 +131,7 @@ func (t *SecureTrie) GetKey(shaKey []byte) []byte { if key, ok := t.getSecKeyCache()[string(shaKey)]; ok { return key } - key, _ := t.trie.db.Get(t.secKey(shaKey)) + key, _ := t.trie.db.preimage(common.BytesToHash(shaKey)) return key } @@ -144,18 +140,34 @@ func (t *SecureTrie) GetKey(shaKey []byte) []byte { // // Committing flushes nodes from memory. Subsequent Get calls will load nodes // from the database. -func (t *SecureTrie) Commit() (root common.Hash, err error) { - return t.CommitTo(t.trie.db) +func (t *SecureTrie) Commit(onleaf LeafCallback) (root common.Hash, err error) { + // Write all the pre-images to the actual disk database + if len(t.getSecKeyCache()) > 0 { + t.trie.db.lock.Lock() + for hk, key := range t.secKeyCache { + t.trie.db.insertPreimage(common.BytesToHash([]byte(hk)), key) + } + t.trie.db.lock.Unlock() + + t.secKeyCache = make(map[string][]byte) + } + // Commit the trie to its intermediate node database + return t.trie.Commit(onleaf) } +// Hash returns the root hash of SecureTrie. It does not write to the +// database and can be used even if the trie doesn't have one. 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 return &cpy @@ -167,38 +179,11 @@ func (t *SecureTrie) NodeIterator(start []byte) NodeIterator { return t.trie.NodeIterator(start) } -// CommitTo writes all nodes and the secure hash pre-images to the given database. -// Nodes are stored with their sha3 hash as the key. -// -// Committing flushes nodes from memory. Subsequent Get calls will load nodes from -// the trie's database. Calling code must ensure that the changes made to db are -// written back to the trie's attached database before using the trie. -func (t *SecureTrie) CommitTo(db DatabaseWriter) (root common.Hash, err error) { - if len(t.getSecKeyCache()) > 0 { - for hk, key := range t.secKeyCache { - if err := db.Put(t.secKey([]byte(hk)), key); err != nil { - return common.Hash{}, err - } - } - t.secKeyCache = make(map[string][]byte) - } - return t.trie.CommitTo(db) -} - -// secKey returns the database key for the preimage of key, as an ephemeral buffer. -// 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) secKey(key []byte) []byte { - buf := append(t.secKeyBuf[:0], secureKeyPrefix...) - buf = append(buf, key...) - return buf -} - // hashKey returns the hash of key as an ephemeral buffer. // 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) + h := newHasher(0, 0, nil) h.sha.Reset() h.sha.Write(key) buf := h.sha.Sum(t.hashKeyBuf[:0]) diff --git a/trie/secure_trie_test.go b/trie/secure_trie_test.go index d74102e2a2..d16d999684 100644 --- a/trie/secure_trie_test.go +++ b/trie/secure_trie_test.go @@ -28,16 +28,16 @@ import ( ) func newEmptySecure() *SecureTrie { - db, _ := ethdb.NewMemDatabase() - trie, _ := NewSecure(common.Hash{}, db, 0) + trie, _ := NewSecure(common.Hash{}, NewDatabase(ethdb.NewMemDatabase()), 0) return trie } // makeTestSecureTrie creates a large enough secure trie for testing. -func makeTestSecureTrie() (ethdb.Database, *SecureTrie, map[string][]byte) { +func makeTestSecureTrie() (*Database, *SecureTrie, map[string][]byte) { // Create an empty trie - db, _ := ethdb.NewMemDatabase() - trie, _ := NewSecure(common.Hash{}, db, 0) + triedb := NewDatabase(ethdb.NewMemDatabase()) + + trie, _ := NewSecure(common.Hash{}, triedb, 0) // Fill it with some arbitrary data content := make(map[string][]byte) @@ -58,10 +58,10 @@ func makeTestSecureTrie() (ethdb.Database, *SecureTrie, map[string][]byte) { trie.Update(key, val) } } - trie.Commit() + trie.Commit(nil) // Return the generated trie - return db, trie, content + return triedb, trie, content } func TestSecureDelete(t *testing.T) { @@ -137,7 +137,7 @@ func TestSecureTrieConcurrency(t *testing.T) { tries[index].Update(key, val) } } - tries[index].Commit() + tries[index].Commit(nil) }(i) } // Wait for all threads to finish diff --git a/trie/sync.go b/trie/sync.go index fea10051f4..44f5087b9f 100644 --- a/trie/sync.go +++ b/trie/sync.go @@ -21,7 +21,8 @@ import ( "fmt" "github.com/ethereum/go-ethereum/common" - "gopkg.in/karalabe/cookiejar.v2/collections/prque" + "github.com/ethereum/go-ethereum/common/prque" + "github.com/ethereum/go-ethereum/ethdb" ) // ErrNotRequested is returned by the trie sync when it's requested to process a @@ -42,7 +43,7 @@ type request struct { depth int // Depth level within the trie the node is located to prioritise DFS deps int // Number of dependencies before allowed to commit this node - callback TrieSyncLeafCallback // Callback to invoke if a leaf node it reached on this branch + callback LeafCallback // Callback to invoke if a leaf node it reached on this branch } // SyncResult is a simple list to return missing nodes along with their request @@ -67,35 +68,30 @@ func newSyncMemBatch() *syncMemBatch { } } -// TrieSyncLeafCallback is a callback type invoked when a trie sync reaches a -// leaf node. It's used by state syncing to check if the leaf node requires some -// further data syncing. -type TrieSyncLeafCallback func(leaf []byte, parent common.Hash) error - -// TrieSync is the main state trie synchronisation scheduler, which provides yet +// Sync is the main state trie synchronisation scheduler, which provides yet // unknown trie hashes to retrieve, accepts node data associated with said hashes // and reconstructs the trie step by step until all is done. -type TrieSync struct { +type Sync struct { database DatabaseReader // Persistent database to check for existing entries - membatch *syncMemBatch // Memory buffer to avoid frequest database writes + 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 } -// NewTrieSync creates a new trie data download scheduler. -func NewTrieSync(root common.Hash, database DatabaseReader, callback TrieSyncLeafCallback) *TrieSync { - ts := &TrieSync{ +// NewSync creates a new trie data download scheduler. +func NewSync(root common.Hash, database DatabaseReader, callback LeafCallback) *Sync { + ts := &Sync{ database: database, membatch: newSyncMemBatch(), requests: make(map[common.Hash]*request), - queue: prque.New(), + queue: prque.New(nil), } ts.AddSubTrie(root, 0, common.Hash{}, callback) return ts } // AddSubTrie registers a new trie to the sync code, rooted at the designated parent. -func (s *TrieSync) AddSubTrie(root common.Hash, depth int, parent common.Hash, callback TrieSyncLeafCallback) { +func (s *Sync) AddSubTrie(root common.Hash, depth int, parent common.Hash, callback LeafCallback) { // Short circuit if the trie is empty or already known if root == emptyRoot { return @@ -130,7 +126,7 @@ func (s *TrieSync) AddSubTrie(root common.Hash, depth int, parent common.Hash, c // interpreted as a trie node, but rather accepted and stored into the database // as is. This method's goal is to support misc state metadata retrievals (e.g. // contract code). -func (s *TrieSync) AddRawEntry(hash common.Hash, depth int, parent common.Hash) { +func (s *Sync) AddRawEntry(hash common.Hash, depth int, parent common.Hash) { // Short circuit if the entry is empty or already known if hash == emptyState { return @@ -160,8 +156,8 @@ func (s *TrieSync) AddRawEntry(hash common.Hash, depth int, parent common.Hash) } // Missing retrieves the known missing nodes from the trie for retrieval. -func (s *TrieSync) Missing(max int) []common.Hash { - requests := []common.Hash{} +func (s *Sync) Missing(max int) []common.Hash { + var requests []common.Hash for !s.queue.Empty() && (max == 0 || len(requests) < max) { requests = append(requests, s.queue.PopItem().(common.Hash)) } @@ -171,7 +167,7 @@ func (s *TrieSync) Missing(max int) []common.Hash { // Process injects a batch of retrieved trie nodes data, returning if something // was committed to the database and also the index of an entry if processing of // it failed. -func (s *TrieSync) Process(results []SyncResult) (bool, int, error) { +func (s *Sync) Process(results []SyncResult) (bool, int, error) { committed := false for i, item := range results { @@ -216,8 +212,8 @@ func (s *TrieSync) Process(results []SyncResult) (bool, int, error) { } // Commit flushes the data stored in the internal membatch out to persistent -// storage, returning th enumber of items written and any occurred error. -func (s *TrieSync) Commit(dbw DatabaseWriter) (int, error) { +// storage, returning the number of items written and any occurred error. +func (s *Sync) Commit(dbw ethdb.Putter) (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 { @@ -232,33 +228,33 @@ func (s *TrieSync) Commit(dbw DatabaseWriter) (int, error) { } // Pending returns the number of state entries currently pending for download. -func (s *TrieSync) Pending() int { +func (s *Sync) Pending() int { return len(s.requests) } // schedule inserts a new state retrieval request into the fetch queue. If there // is already a pending request for this node, the new request will be discarded // and only a parent reference added to the old one. -func (s *TrieSync) schedule(req *request) { +func (s *Sync) schedule(req *request) { // If we're already requesting this node, add a new reference and stop if old, ok := s.requests[req.hash]; ok { old.parents = append(old.parents, req.parents...) return } // Schedule the request for future retrieval - s.queue.Push(req.hash, float32(req.depth)) + s.queue.Push(req.hash, int64(req.depth)) s.requests[req.hash] = req } // children retrieves all the missing children of a state trie entry for future // retrieval scheduling. -func (s *TrieSync) children(req *request, object node) ([]*request, error) { +func (s *Sync) children(req *request, object node) ([]*request, error) { // Gather all the children of the node, irrelevant whether known or not type child struct { node node depth int } - children := []child{} + var children []child switch node := (object).(type) { case *shortNode: @@ -314,7 +310,7 @@ func (s *TrieSync) children(req *request, object node) ([]*request, error) { // commit finalizes a retrieval request and stores it into the membatch. If any // of the referencing parent requests complete due to this commit, they are also // committed themselves. -func (s *TrieSync) commit(req *request) (err error) { +func (s *Sync) commit(req *request) (err error) { // Write the node content to the membatch s.membatch.batch[req.hash] = req.data s.membatch.order = append(s.membatch.order, req.hash) diff --git a/trie/sync_test.go b/trie/sync_test.go index ec16a25bd9..ff15baa52c 100644 --- a/trie/sync_test.go +++ b/trie/sync_test.go @@ -25,10 +25,10 @@ import ( ) // makeTestTrie create a sample test trie to test node-wise reconstruction. -func makeTestTrie() (ethdb.Database, *Trie, map[string][]byte) { +func makeTestTrie() (*Database, *Trie, map[string][]byte) { // Create an empty trie - db, _ := ethdb.NewMemDatabase() - trie, _ := New(common.Hash{}, db) + triedb := NewDatabase(ethdb.NewMemDatabase()) + trie, _ := New(common.Hash{}, triedb) // Fill it with some arbitrary data content := make(map[string][]byte) @@ -49,15 +49,15 @@ func makeTestTrie() (ethdb.Database, *Trie, map[string][]byte) { trie.Update(key, val) } } - trie.Commit() + trie.Commit(nil) // Return the generated trie - return db, trie, content + return triedb, trie, content } // checkTrieContents cross references a reconstructed trie with an expected data // content map. -func checkTrieContents(t *testing.T, db Database, root []byte, content map[string][]byte) { +func checkTrieContents(t *testing.T, db *Database, root []byte, content map[string][]byte) { // Check root availability and trie contents trie, err := New(common.BytesToHash(root), db) if err != nil { @@ -74,7 +74,7 @@ func checkTrieContents(t *testing.T, db Database, root []byte, content map[strin } // checkTrieConsistency checks that all nodes in a trie are indeed present. -func checkTrieConsistency(db Database, root common.Hash) error { +func checkTrieConsistency(db *Database, root common.Hash) error { // Create and iterate a trie rooted in a subnode trie, err := New(root, db) if err != nil { @@ -87,13 +87,14 @@ func checkTrieConsistency(db Database, root common.Hash) error { } // Tests that an empty trie is not scheduled for syncing. -func TestEmptyTrieSync(t *testing.T) { - emptyA, _ := New(common.Hash{}, nil) - emptyB, _ := New(emptyRoot, nil) +func TestEmptySync(t *testing.T) { + dbA := NewDatabase(ethdb.NewMemDatabase()) + dbB := NewDatabase(ethdb.NewMemDatabase()) + emptyA, _ := New(common.Hash{}, dbA) + emptyB, _ := New(emptyRoot, dbB) for i, trie := range []*Trie{emptyA, emptyB} { - db, _ := ethdb.NewMemDatabase() - if req := NewTrieSync(common.BytesToHash(trie.Root()), db, nil).Missing(1); len(req) != 0 { + if req := NewSync(trie.Hash(), ethdb.NewMemDatabase(), nil).Missing(1); len(req) != 0 { t.Errorf("test %d: content requested for empty trie: %v", i, req) } } @@ -101,22 +102,23 @@ func TestEmptyTrieSync(t *testing.T) { // Tests that given a root hash, a trie can sync iteratively on a single thread, // requesting retrieval tasks and returning all of them in one go. -func TestIterativeTrieSyncIndividual(t *testing.T) { testIterativeTrieSync(t, 1) } -func TestIterativeTrieSyncBatched(t *testing.T) { testIterativeTrieSync(t, 100) } +func TestIterativeSyncIndividual(t *testing.T) { testIterativeSync(t, 1) } +func TestIterativeSyncBatched(t *testing.T) { testIterativeSync(t, 100) } -func testIterativeTrieSync(t *testing.T, batch int) { +func testIterativeSync(t *testing.T, batch int) { // Create a random trie to copy srcDb, srcTrie, srcData := makeTestTrie() // Create a destination trie and sync with the scheduler - dstDb, _ := ethdb.NewMemDatabase() - sched := NewTrieSync(common.BytesToHash(srcTrie.Root()), dstDb, nil) + diskdb := ethdb.NewMemDatabase() + triedb := NewDatabase(diskdb) + sched := NewSync(srcTrie.Hash(), diskdb, nil) queue := append([]common.Hash{}, sched.Missing(batch)...) for len(queue) > 0 { results := make([]SyncResult, len(queue)) for i, hash := range queue { - data, err := srcDb.Get(hash.Bytes()) + data, err := srcDb.Node(hash) if err != nil { t.Fatalf("failed to retrieve node data for %x: %v", hash, err) } @@ -125,31 +127,32 @@ func testIterativeTrieSync(t *testing.T, batch int) { if _, index, err := sched.Process(results); err != nil { t.Fatalf("failed to process result #%d: %v", index, err) } - if index, err := sched.Commit(dstDb); err != nil { + if index, err := sched.Commit(diskdb); err != nil { t.Fatalf("failed to commit data #%d: %v", index, err) } queue = append(queue[:0], sched.Missing(batch)...) } // Cross check that the two tries are in sync - checkTrieContents(t, dstDb, srcTrie.Root(), srcData) + checkTrieContents(t, triedb, srcTrie.Root(), srcData) } // Tests that the trie scheduler can correctly reconstruct the state even if only // partial results are returned, and the others sent only later. -func TestIterativeDelayedTrieSync(t *testing.T) { +func TestIterativeDelayedSync(t *testing.T) { // Create a random trie to copy srcDb, srcTrie, srcData := makeTestTrie() // Create a destination trie and sync with the scheduler - dstDb, _ := ethdb.NewMemDatabase() - sched := NewTrieSync(common.BytesToHash(srcTrie.Root()), dstDb, nil) + diskdb := ethdb.NewMemDatabase() + triedb := NewDatabase(diskdb) + sched := NewSync(srcTrie.Hash(), diskdb, nil) queue := append([]common.Hash{}, sched.Missing(10000)...) for len(queue) > 0 { // Sync only half of the scheduled nodes results := make([]SyncResult, len(queue)/2+1) for i, hash := range queue[:len(results)] { - data, err := srcDb.Get(hash.Bytes()) + data, err := srcDb.Node(hash) if err != nil { t.Fatalf("failed to retrieve node data for %x: %v", hash, err) } @@ -158,28 +161,29 @@ func TestIterativeDelayedTrieSync(t *testing.T) { if _, index, err := sched.Process(results); err != nil { t.Fatalf("failed to process result #%d: %v", index, err) } - if index, err := sched.Commit(dstDb); err != nil { + if index, err := sched.Commit(diskdb); err != nil { t.Fatalf("failed to commit data #%d: %v", index, err) } queue = append(queue[len(results):], sched.Missing(10000)...) } // Cross check that the two tries are in sync - checkTrieContents(t, dstDb, srcTrie.Root(), srcData) + checkTrieContents(t, triedb, srcTrie.Root(), srcData) } // Tests that given a root hash, a trie can sync iteratively on a single thread, // requesting retrieval tasks and returning all of them in one go, however in a // random order. -func TestIterativeRandomTrieSyncIndividual(t *testing.T) { testIterativeRandomTrieSync(t, 1) } -func TestIterativeRandomTrieSyncBatched(t *testing.T) { testIterativeRandomTrieSync(t, 100) } +func TestIterativeRandomSyncIndividual(t *testing.T) { testIterativeRandomSync(t, 1) } +func TestIterativeRandomSyncBatched(t *testing.T) { testIterativeRandomSync(t, 100) } -func testIterativeRandomTrieSync(t *testing.T, batch int) { +func testIterativeRandomSync(t *testing.T, batch int) { // Create a random trie to copy srcDb, srcTrie, srcData := makeTestTrie() // Create a destination trie and sync with the scheduler - dstDb, _ := ethdb.NewMemDatabase() - sched := NewTrieSync(common.BytesToHash(srcTrie.Root()), dstDb, nil) + diskdb := ethdb.NewMemDatabase() + triedb := NewDatabase(diskdb) + sched := NewSync(srcTrie.Hash(), diskdb, nil) queue := make(map[common.Hash]struct{}) for _, hash := range sched.Missing(batch) { @@ -189,7 +193,7 @@ func testIterativeRandomTrieSync(t *testing.T, batch int) { // Fetch all the queued nodes in a random order results := make([]SyncResult, 0, len(queue)) for hash := range queue { - data, err := srcDb.Get(hash.Bytes()) + data, err := srcDb.Node(hash) if err != nil { t.Fatalf("failed to retrieve node data for %x: %v", hash, err) } @@ -199,7 +203,7 @@ func testIterativeRandomTrieSync(t *testing.T, batch int) { if _, index, err := sched.Process(results); err != nil { t.Fatalf("failed to process result #%d: %v", index, err) } - if index, err := sched.Commit(dstDb); err != nil { + if index, err := sched.Commit(diskdb); err != nil { t.Fatalf("failed to commit data #%d: %v", index, err) } queue = make(map[common.Hash]struct{}) @@ -208,18 +212,19 @@ func testIterativeRandomTrieSync(t *testing.T, batch int) { } } // Cross check that the two tries are in sync - checkTrieContents(t, dstDb, srcTrie.Root(), srcData) + checkTrieContents(t, triedb, srcTrie.Root(), srcData) } // Tests that the trie scheduler can correctly reconstruct the state even if only // partial results are returned (Even those randomly), others sent only later. -func TestIterativeRandomDelayedTrieSync(t *testing.T) { +func TestIterativeRandomDelayedSync(t *testing.T) { // Create a random trie to copy srcDb, srcTrie, srcData := makeTestTrie() // Create a destination trie and sync with the scheduler - dstDb, _ := ethdb.NewMemDatabase() - sched := NewTrieSync(common.BytesToHash(srcTrie.Root()), dstDb, nil) + diskdb := ethdb.NewMemDatabase() + triedb := NewDatabase(diskdb) + sched := NewSync(srcTrie.Hash(), diskdb, nil) queue := make(map[common.Hash]struct{}) for _, hash := range sched.Missing(10000) { @@ -229,7 +234,7 @@ func TestIterativeRandomDelayedTrieSync(t *testing.T) { // Sync only half of the scheduled nodes, even those in random order results := make([]SyncResult, 0, len(queue)/2+1) for hash := range queue { - data, err := srcDb.Get(hash.Bytes()) + data, err := srcDb.Node(hash) if err != nil { t.Fatalf("failed to retrieve node data for %x: %v", hash, err) } @@ -243,7 +248,7 @@ func TestIterativeRandomDelayedTrieSync(t *testing.T) { if _, index, err := sched.Process(results); err != nil { t.Fatalf("failed to process result #%d: %v", index, err) } - if index, err := sched.Commit(dstDb); err != nil { + if index, err := sched.Commit(diskdb); err != nil { t.Fatalf("failed to commit data #%d: %v", index, err) } for _, result := range results { @@ -254,18 +259,19 @@ func TestIterativeRandomDelayedTrieSync(t *testing.T) { } } // Cross check that the two tries are in sync - checkTrieContents(t, dstDb, srcTrie.Root(), srcData) + checkTrieContents(t, triedb, srcTrie.Root(), srcData) } // Tests that a trie sync will not request nodes multiple times, even if they // have such references. -func TestDuplicateAvoidanceTrieSync(t *testing.T) { +func TestDuplicateAvoidanceSync(t *testing.T) { // Create a random trie to copy srcDb, srcTrie, srcData := makeTestTrie() // Create a destination trie and sync with the scheduler - dstDb, _ := ethdb.NewMemDatabase() - sched := NewTrieSync(common.BytesToHash(srcTrie.Root()), dstDb, nil) + diskdb := ethdb.NewMemDatabase() + triedb := NewDatabase(diskdb) + sched := NewSync(srcTrie.Hash(), diskdb, nil) queue := append([]common.Hash{}, sched.Missing(0)...) requested := make(map[common.Hash]struct{}) @@ -273,7 +279,7 @@ func TestDuplicateAvoidanceTrieSync(t *testing.T) { for len(queue) > 0 { results := make([]SyncResult, len(queue)) for i, hash := range queue { - data, err := srcDb.Get(hash.Bytes()) + data, err := srcDb.Node(hash) if err != nil { t.Fatalf("failed to retrieve node data for %x: %v", hash, err) } @@ -287,32 +293,33 @@ func TestDuplicateAvoidanceTrieSync(t *testing.T) { if _, index, err := sched.Process(results); err != nil { t.Fatalf("failed to process result #%d: %v", index, err) } - if index, err := sched.Commit(dstDb); err != nil { + if index, err := sched.Commit(diskdb); err != nil { t.Fatalf("failed to commit data #%d: %v", index, err) } queue = append(queue[:0], sched.Missing(0)...) } // Cross check that the two tries are in sync - checkTrieContents(t, dstDb, srcTrie.Root(), srcData) + checkTrieContents(t, triedb, srcTrie.Root(), srcData) } // Tests that at any point in time during a sync, only complete sub-tries are in // the database. -func TestIncompleteTrieSync(t *testing.T) { +func TestIncompleteSync(t *testing.T) { // Create a random trie to copy srcDb, srcTrie, _ := makeTestTrie() // Create a destination trie and sync with the scheduler - dstDb, _ := ethdb.NewMemDatabase() - sched := NewTrieSync(common.BytesToHash(srcTrie.Root()), dstDb, nil) + diskdb := ethdb.NewMemDatabase() + 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 results := make([]SyncResult, len(queue)) for i, hash := range queue { - data, err := srcDb.Get(hash.Bytes()) + data, err := srcDb.Node(hash) if err != nil { t.Fatalf("failed to retrieve node data for %x: %v", hash, err) } @@ -322,7 +329,7 @@ func TestIncompleteTrieSync(t *testing.T) { if _, index, err := sched.Process(results); err != nil { t.Fatalf("failed to process result #%d: %v", index, err) } - if index, err := sched.Commit(dstDb); err != nil { + if index, err := sched.Commit(diskdb); err != nil { t.Fatalf("failed to commit data #%d: %v", index, err) } for _, result := range results { @@ -330,7 +337,7 @@ func TestIncompleteTrieSync(t *testing.T) { } // Check that all known sub-tries in the synced trie are complete for _, root := range added { - if err := checkTrieConsistency(dstDb, root); err != nil { + if err := checkTrieConsistency(triedb, root); err != nil { t.Fatalf("trie inconsistent: %v", err) } } @@ -340,12 +347,12 @@ func TestIncompleteTrieSync(t *testing.T) { // Sanity check that removing any node from the database is detected for _, node := range added[1:] { key := node.Bytes() - value, _ := dstDb.Get(key) + value, _ := diskdb.Get(key) - dstDb.Delete(key) - if err := checkTrieConsistency(dstDb, added[0]); err == nil { + diskdb.Delete(key) + if err := checkTrieConsistency(triedb, added[0]); err == nil { t.Fatalf("trie inconsistency not caught, missing: %x", key) } - dstDb.Put(key, value) + diskdb.Put(key, value) } } diff --git a/trie/trie.go b/trie/trie.go index 8fe98d8351..af424d4ac6 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -22,16 +22,17 @@ import ( "fmt" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto/sha3" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" - "github.com/rcrowley/go-metrics" + "github.com/ethereum/go-ethereum/metrics" ) var ( - // This is the known root hash of an empty trie. + // emptyRoot is the known root hash of an empty trie. emptyRoot = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") - // This is the known hash of an empty state trie entry. - emptyState common.Hash + + // emptyState is the known hash of an empty state trie entry. + emptyState = crypto.Keccak256Hash(nil) ) var ( @@ -53,29 +54,10 @@ func CacheUnloads() int64 { return cacheUnloadCounter.Count() } -func init() { - sha3.NewKeccak256().Sum(emptyState[:0]) -} - -// Database must be implemented by backing stores for the trie. -type Database interface { - DatabaseReader - DatabaseWriter -} - -// DatabaseReader wraps the Get method of a backing store for the trie. -type DatabaseReader interface { - Get(key []byte) (value []byte, err error) - Has(key []byte) (bool, error) -} - -// DatabaseWriter wraps the Put method of a backing store for the trie. -type DatabaseWriter interface { - // Put stores the mapping key->value in the database. - // Implementations must not hold onto the value bytes, the trie - // will reuse the slice across calls to Put. - Put(key, value []byte) error -} +// 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. +type LeafCallback func(leaf []byte, parent common.Hash) error // Trie is a Merkle Patricia Trie. // The zero value is an empty trie with no database. @@ -83,9 +65,8 @@ type DatabaseWriter interface { // // Trie is not safe for concurrent use. type Trie struct { - root node - db Database - originalRoot common.Hash + db *Database + root node // Cache generation values. // cachegen increases by one with each commit operation. @@ -111,12 +92,14 @@ func (t *Trie) newFlag() nodeFlag { // trie is initially empty and does not require a database. Otherwise, // New will panic if db is nil and returns a MissingNodeError if root does // not exist in the database. Accessing the trie loads nodes from db on demand. -func New(root common.Hash, db Database) (*Trie, error) { - trie := &Trie{db: db, originalRoot: root} - if (root != common.Hash{}) && root != emptyRoot { - if db == nil { - panic("trie.New: cannot use existing root without a database") - } +func New(root common.Hash, db *Database) (*Trie, error) { + if db == nil { + panic("trie.New called without a database") + } + trie := &Trie{ + db: db, + } + if root != (common.Hash{}) && root != emptyRoot { rootnode, err := trie.resolveHash(root[:], nil) if err != nil { return nil, err @@ -371,7 +354,7 @@ func (t *Trie) delete(n node, prefix, key []byte) (bool, node, error) { // value that is left in n or -2 if n contains at least two // values. pos := -1 - for i, cld := range n.Children { + for i, cld := range &n.Children { if cld != nil { if pos == -1 { pos = i @@ -447,12 +430,11 @@ func (t *Trie) resolve(n node, prefix []byte) (node, error) { func (t *Trie) resolveHash(n hashNode, prefix []byte) (node, error) { cacheMissCounter.Inc(1) - enc, err := t.db.Get(n) - if err != nil || enc == nil { - return nil, &MissingNodeError{NodeHash: common.BytesToHash(n), Path: prefix} + hash := common.BytesToHash(n) + if node := t.db.node(hash, t.cachegen); node != nil { + return node, nil } - dec := mustDecodeNode(n, enc, t.cachegen) - return dec, nil + return nil, &MissingNodeError{NodeHash: hash, Path: prefix} } // Root returns the root hash of the trie. @@ -462,32 +444,18 @@ 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 { - hash, cached, _ := t.hashRoot(nil) + hash, cached, _ := t.hashRoot(nil, nil) t.root = cached return common.BytesToHash(hash.(hashNode)) } -// Commit writes all nodes to the trie's database. -// Nodes are stored with their sha3 hash as the key. -// -// Committing flushes nodes from memory. -// Subsequent Get calls will load nodes from the database. -func (t *Trie) Commit() (root common.Hash, err error) { +// Commit writes all nodes to the trie's memory database, tracking the internal +// and external (for account tries) references. +func (t *Trie) Commit(onleaf LeafCallback) (root common.Hash, err error) { if t.db == nil { - panic("Commit called on trie with nil database") + panic("commit called on trie with nil database") } - return t.CommitTo(t.db) -} - -// CommitTo writes all nodes to the given database. -// Nodes are stored with their sha3 hash as the key. -// -// Committing flushes nodes from memory. Subsequent Get calls will -// load nodes from the trie's database. Calling code must ensure that -// the changes made to db are written back to the trie's attached -// database before using the trie. -func (t *Trie) CommitTo(db DatabaseWriter) (root common.Hash, err error) { - hash, cached, err := t.hashRoot(db) + hash, cached, err := t.hashRoot(t.db, onleaf) if err != nil { return common.Hash{}, err } @@ -496,11 +464,11 @@ func (t *Trie) CommitTo(db DatabaseWriter) (root common.Hash, err error) { return common.BytesToHash(hash.(hashNode)), nil } -func (t *Trie) hashRoot(db DatabaseWriter) (node, node, error) { +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) + h := newHasher(t.cachegen, t.cachelimit, onleaf) defer returnHasherToPool(h) return h.hash(t.root, db, true) } diff --git a/trie/trie_test.go b/trie/trie_test.go index 1e28c3bc48..4d84aa96cf 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -43,8 +43,7 @@ func init() { // Used for testing func newEmpty() *Trie { - db, _ := ethdb.NewMemDatabase() - trie, _ := New(common.Hash{}, db) + trie, _ := New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase())) return trie } @@ -68,8 +67,7 @@ func TestNull(t *testing.T) { } func TestMissingRoot(t *testing.T) { - db, _ := ethdb.NewMemDatabase() - trie, err := New(common.HexToHash("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"), db) + trie, err := New(common.HexToHash("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"), NewDatabase(ethdb.NewMemDatabase())) if trie != nil { t.Error("New returned non-nil trie for invalid root") } @@ -78,70 +76,75 @@ func TestMissingRoot(t *testing.T) { } } -func TestMissingNode(t *testing.T) { - db, _ := ethdb.NewMemDatabase() - trie, _ := New(common.Hash{}, db) +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() + triedb := NewDatabase(diskdb) + + trie, _ := New(common.Hash{}, triedb) updateString(trie, "120000", "qwerqwerqwerqwerqwerqwerqwerqwer") updateString(trie, "123456", "asdfasdfasdfasdfasdfasdfasdfasdf") - root, _ := trie.Commit() + root, _ := trie.Commit(nil) + if !memonly { + triedb.Commit(root, true) + } - trie, _ = New(root, db) + trie, _ = New(root, triedb) _, err := trie.TryGet([]byte("120000")) if err != nil { t.Errorf("Unexpected error: %v", err) } - - trie, _ = New(root, db) + trie, _ = New(root, triedb) _, err = trie.TryGet([]byte("120099")) if err != nil { t.Errorf("Unexpected error: %v", err) } - - trie, _ = New(root, db) + trie, _ = New(root, triedb) _, err = trie.TryGet([]byte("123456")) if err != nil { t.Errorf("Unexpected error: %v", err) } - - trie, _ = New(root, db) + trie, _ = New(root, triedb) err = trie.TryUpdate([]byte("120099"), []byte("zxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcv")) if err != nil { t.Errorf("Unexpected error: %v", err) } - - trie, _ = New(root, db) + trie, _ = New(root, triedb) err = trie.TryDelete([]byte("123456")) if err != nil { t.Errorf("Unexpected error: %v", err) } - db.Delete(common.FromHex("e1d943cc8f061a0c0b98162830b970395ac9315654824bf21b73b891365262f9")) + hash := common.HexToHash("0xe1d943cc8f061a0c0b98162830b970395ac9315654824bf21b73b891365262f9") + if memonly { + delete(triedb.dirties, hash) + } else { + diskdb.Delete(hash[:]) + } - trie, _ = New(root, db) + trie, _ = New(root, triedb) _, err = trie.TryGet([]byte("120000")) if _, ok := err.(*MissingNodeError); !ok { t.Errorf("Wrong error: %v", err) } - - trie, _ = New(root, db) + trie, _ = New(root, triedb) _, err = trie.TryGet([]byte("120099")) if _, ok := err.(*MissingNodeError); !ok { t.Errorf("Wrong error: %v", err) } - - trie, _ = New(root, db) + trie, _ = New(root, triedb) _, err = trie.TryGet([]byte("123456")) if err != nil { t.Errorf("Unexpected error: %v", err) } - - trie, _ = New(root, db) + trie, _ = New(root, triedb) err = trie.TryUpdate([]byte("120099"), []byte("zxcv")) if _, ok := err.(*MissingNodeError); !ok { t.Errorf("Wrong error: %v", err) } - - trie, _ = New(root, db) + trie, _ = New(root, triedb) err = trie.TryDelete([]byte("123456")) if _, ok := err.(*MissingNodeError); !ok { t.Errorf("Wrong error: %v", err) @@ -165,7 +168,7 @@ func TestInsert(t *testing.T) { updateString(trie, "A", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") exp = common.HexToHash("d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab") - root, err := trie.Commit() + root, err := trie.Commit(nil) if err != nil { t.Fatalf("commit error: %v", err) } @@ -194,7 +197,7 @@ func TestGet(t *testing.T) { if i == 1 { return } - trie.Commit() + trie.Commit(nil) } } @@ -263,7 +266,7 @@ func TestReplication(t *testing.T) { for _, val := range vals { updateString(trie, val.k, val.v) } - exp, err := trie.Commit() + exp, err := trie.Commit(nil) if err != nil { t.Fatalf("commit error: %v", err) } @@ -278,7 +281,7 @@ func TestReplication(t *testing.T) { t.Errorf("trie2 doesn't have %q => %q", kv.k, kv.v) } } - hash, err := trie2.Commit() + hash, err := trie2.Commit(nil) if err != nil { t.Fatalf("commit error: %v", err) } @@ -314,7 +317,7 @@ func TestLargeValue(t *testing.T) { } type countingDB struct { - Database + ethdb.Database gets map[string]int } @@ -332,21 +335,23 @@ func TestCacheUnload(t *testing.T) { 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() + + 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, gets: make(map[string]int)} - trie, _ = New(root, db) + diskdb := &countingDB{Database: trie.db.diskdb, gets: make(map[string]int)} + triedb := NewDatabase(diskdb) + trie, _ = New(root, triedb) trie.SetCacheLimit(5) for i := 0; i < 12; i++ { getString(trie, key1) - trie.Commit() + trie.Commit(nil) } - // Check that it got loaded two times. - for dbkey, count := range db.gets { + for dbkey, count := range diskdb.gets { if count != 2 { t.Errorf("db key %x loaded %d times, want %d times", []byte(dbkey), count, 2) } @@ -407,8 +412,9 @@ func (randTest) Generate(r *rand.Rand, size int) reflect.Value { } func runRandTest(rt randTest) bool { - db, _ := ethdb.NewMemDatabase() - tr, _ := New(common.Hash{}, db) + triedb := NewDatabase(ethdb.NewMemDatabase()) + + tr, _ := New(common.Hash{}, triedb) values := make(map[string]string) // tracks content of the trie for i, step := range rt { @@ -426,23 +432,23 @@ func runRandTest(rt randTest) bool { rt[i].err = fmt.Errorf("mismatch for key 0x%x, got 0x%x want 0x%x", step.key, v, want) } case opCommit: - _, rt[i].err = tr.Commit() + _, rt[i].err = tr.Commit(nil) case opHash: tr.Hash() case opReset: - hash, err := tr.Commit() + hash, err := tr.Commit(nil) if err != nil { rt[i].err = err return false } - newtr, err := New(hash, db) + newtr, err := New(hash, triedb) if err != nil { rt[i].err = err return false } tr = newtr case opItercheckhash: - checktr, _ := New(common.Hash{}, nil) + checktr, _ := New(common.Hash{}, triedb) it := NewIterator(tr.NodeIterator(nil)) for it.Next() { checktr.Update(it.Key, it.Value) @@ -524,7 +530,7 @@ func benchGet(b *testing.B, commit bool) { } binary.LittleEndian.PutUint64(k, benchElemCount/2) if commit { - trie.Commit() + trie.Commit(nil) } b.ResetTimer() @@ -534,7 +540,7 @@ func benchGet(b *testing.B, commit bool) { b.StopTimer() if commit { - ldb := trie.db.(*ethdb.LDBDatabase) + ldb := trie.db.diskdb.(*ethdb.LDBDatabase) ldb.Close() os.RemoveAll(ldb.Path()) } @@ -585,16 +591,16 @@ func BenchmarkHash(b *testing.B) { trie.Hash() } -func tempDB() (string, Database) { +func tempDB() (string, *Database) { dir, err := ioutil.TempDir("", "trie-bench") if err != nil { panic(fmt.Sprintf("can't create temporary directory: %v", err)) } - db, err := ethdb.NewLDBDatabase(dir, 256, 0) + diskdb, err := ethdb.NewLDBDatabase(dir, 256, 0) if err != nil { panic(fmt.Sprintf("can't create temporary database: %v", err)) } - return dir, db + return dir, NewDatabase(diskdb) } func getString(trie *Trie, k string) []byte { @@ -608,3 +614,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, 1) + } +} diff --git a/vendor/github.com/Azure/azure-storage-go/LICENSE b/vendor/github.com/Azure/azure-pipeline-go/LICENSE similarity index 98% rename from vendor/github.com/Azure/azure-storage-go/LICENSE rename to vendor/github.com/Azure/azure-pipeline-go/LICENSE index 21071075c2..d1ca00f20a 100644 --- a/vendor/github.com/Azure/azure-storage-go/LICENSE +++ b/vendor/github.com/Azure/azure-pipeline-go/LICENSE @@ -18,4 +18,4 @@ 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 + SOFTWARE \ No newline at end of file diff --git a/vendor/github.com/Azure/azure-pipeline-go/pipeline/core.go b/vendor/github.com/Azure/azure-pipeline-go/pipeline/core.go new file mode 100755 index 0000000000..0dde81d728 --- /dev/null +++ b/vendor/github.com/Azure/azure-pipeline-go/pipeline/core.go @@ -0,0 +1,255 @@ +package pipeline + +import ( + "context" + "net" + "net/http" + "os" + "time" +) + +// The Factory interface represents an object that can create its Policy object. Each HTTP request sent +// requires that this Factory create a new instance of its Policy object. +type Factory interface { + New(next Policy, po *PolicyOptions) Policy +} + +// FactoryFunc is an adapter that allows the use of an ordinary function as a Factory interface. +type FactoryFunc func(next Policy, po *PolicyOptions) PolicyFunc + +// New calls f(next,po). +func (f FactoryFunc) New(next Policy, po *PolicyOptions) Policy { + return f(next, po) +} + +// The Policy interface represents a mutable Policy object created by a Factory. The object can mutate/process +// the HTTP request and then forward it on to the next Policy object in the linked-list. The returned +// Response goes backward through the linked-list for additional processing. +// NOTE: Request is passed by value so changes do not change the caller's version of +// the request. However, Request has some fields that reference mutable objects (not strings). +// These references are copied; a deep copy is not performed. Specifically, this means that +// you should avoid modifying the objects referred to by these fields: URL, Header, Body, +// GetBody, TransferEncoding, Form, MultipartForm, Trailer, TLS, Cancel, and Response. +type Policy interface { + Do(ctx context.Context, request Request) (Response, error) +} + +// PolicyFunc is an adapter that allows the use of an ordinary function as a Policy interface. +type PolicyFunc func(ctx context.Context, request Request) (Response, error) + +// Do calls f(ctx, request). +func (f PolicyFunc) Do(ctx context.Context, request Request) (Response, error) { + return f(ctx, request) +} + +// Options configures a Pipeline's behavior. +type Options struct { + HTTPSender Factory // If sender is nil, then the pipeline's default client is used to send the HTTP requests. + Log LogOptions +} + +// LogLevel tells a logger the minimum level to log. When code reports a log entry, +// the LogLevel indicates the level of the log entry. The logger only records entries +// whose level is at least the level it was told to log. See the Log* constants. +// For example, if a logger is configured with LogError, then LogError, LogPanic, +// and LogFatal entries will be logged; lower level entries are ignored. +type LogLevel uint32 + +const ( + // LogNone tells a logger not to log any entries passed to it. + LogNone LogLevel = iota + + // LogFatal tells a logger to log all LogFatal entries passed to it. + LogFatal + + // LogPanic tells a logger to log all LogPanic and LogFatal entries passed to it. + LogPanic + + // LogError tells a logger to log all LogError, LogPanic and LogFatal entries passed to it. + LogError + + // LogWarning tells a logger to log all LogWarning, LogError, LogPanic and LogFatal entries passed to it. + LogWarning + + // LogInfo tells a logger to log all LogInfo, LogWarning, LogError, LogPanic and LogFatal entries passed to it. + LogInfo + + // LogDebug tells a logger to log all LogDebug, LogInfo, LogWarning, LogError, LogPanic and LogFatal entries passed to it. + LogDebug +) + +// LogOptions configures the pipeline's logging mechanism & level filtering. +type LogOptions struct { + Log func(level LogLevel, message string) + + // ShouldLog is called periodically allowing you to return whether the specified LogLevel should be logged or not. + // An application can return different values over the its lifetime; this allows the application to dynamically + // alter what is logged. NOTE: This method can be called by multiple goroutines simultaneously so make sure + // you implement it in a goroutine-safe way. If nil, nothing is logged (the equivalent of returning LogNone). + // Usually, the function will be implemented simply like this: return level <= LogWarning + ShouldLog func(level LogLevel) bool +} + +type pipeline struct { + factories []Factory + options Options +} + +// The Pipeline interface represents an ordered list of Factory objects and an object implementing the HTTPSender interface. +// You construct a Pipeline by calling the pipeline.NewPipeline function. To send an HTTP request, call pipeline.NewRequest +// and then call Pipeline's Do method passing a context, the request, and a method-specific Factory (or nil). Passing a +// method-specific Factory allows this one call to Do to inject a Policy into the linked-list. The policy is injected where +// the MethodFactoryMarker (see the pipeline.MethodFactoryMarker function) is in the slice of Factory objects. +// +// When Do is called, the Pipeline object asks each Factory object to construct its Policy object and adds each Policy to a linked-list. +// THen, Do sends the Context and Request through all the Policy objects. The final Policy object sends the request over the network +// (via the HTTPSender object passed to NewPipeline) and the response is returned backwards through all the Policy objects. +// Since Pipeline and Factory objects are goroutine-safe, you typically create 1 Pipeline object and reuse it to make many HTTP requests. +type Pipeline interface { + Do(ctx context.Context, methodFactory Factory, request Request) (Response, error) +} + +// NewPipeline creates a new goroutine-safe Pipeline object from the slice of Factory objects and the specified options. +func NewPipeline(factories []Factory, o Options) Pipeline { + if o.HTTPSender == nil { + o.HTTPSender = newDefaultHTTPClientFactory() + } + if o.Log.Log == nil { + o.Log.Log = func(LogLevel, string) {} // No-op logger + } + return &pipeline{factories: factories, options: o} +} + +// Do is called for each and every HTTP request. It tells each Factory to create its own (mutable) Policy object +// replacing a MethodFactoryMarker factory (if it exists) with the methodFactory passed in. Then, the Context and Request +// are sent through the pipeline of Policy objects (which can transform the Request's URL/query parameters/headers) and +// ultimately sends the transformed HTTP request over the network. +func (p *pipeline) Do(ctx context.Context, methodFactory Factory, request Request) (Response, error) { + response, err := p.newPolicies(methodFactory).Do(ctx, request) + request.close() + return response, err +} + +func (p *pipeline) newPolicies(methodFactory Factory) Policy { + // The last Policy is the one that actually sends the request over the wire and gets the response. + // It is overridable via the Options' HTTPSender field. + po := &PolicyOptions{pipeline: p} // One object shared by all policy objects + next := p.options.HTTPSender.New(nil, po) + + // Walk over the slice of Factory objects in reverse (from wire to API) + markers := 0 + for i := len(p.factories) - 1; i >= 0; i-- { + factory := p.factories[i] + if _, ok := factory.(methodFactoryMarker); ok { + markers++ + if markers > 1 { + panic("MethodFactoryMarker can only appear once in the pipeline") + } + if methodFactory != nil { + // Replace MethodFactoryMarker with passed-in methodFactory + next = methodFactory.New(next, po) + } + } else { + // Use the slice's Factory to construct its Policy + next = factory.New(next, po) + } + } + + // Each Factory has created its Policy + if markers == 0 && methodFactory != nil { + panic("Non-nil methodFactory requires MethodFactoryMarker in the pipeline") + } + return next // Return head of the Policy object linked-list +} + +// A PolicyOptions represents optional information that can be used by a node in the +// linked-list of Policy objects. A PolicyOptions is passed to the Factory's New method +// which passes it (if desired) to the Policy object it creates. Today, the Policy object +// uses the options to perform logging. But, in the future, this could be used for more. +type PolicyOptions struct { + pipeline *pipeline +} + +// ShouldLog returns true if the specified log level should be logged. +func (po *PolicyOptions) ShouldLog(level LogLevel) bool { + if po.pipeline.options.Log.ShouldLog != nil { + return po.pipeline.options.Log.ShouldLog(level) + } + return false +} + +// Log logs a string to the Pipeline's Logger. +func (po *PolicyOptions) Log(level LogLevel, msg string) { + if !po.ShouldLog(level) { + return // Short circuit message formatting if we're not logging it + } + + // We are logging it, ensure trailing newline + if len(msg) == 0 || msg[len(msg)-1] != '\n' { + msg += "\n" // Ensure trailing newline + } + po.pipeline.options.Log.Log(level, msg) + + // If logger doesn't handle fatal/panic, we'll do it here. + if level == LogFatal { + os.Exit(1) + } else if level == LogPanic { + panic(msg) + } +} + +var pipelineHTTPClient = newDefaultHTTPClient() + +func newDefaultHTTPClient() *http.Client { + // We want the Transport to have a large connection pool + return &http.Client{ + Transport: &http.Transport{ + Proxy: http.ProxyFromEnvironment, + // We use Dial instead of DialContext as DialContext has been reported to cause slower performance. + Dial /*Context*/ : (&net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + DualStack: true, + }).Dial, /*Context*/ + MaxIdleConns: 0, // No limit + MaxIdleConnsPerHost: 100, + IdleConnTimeout: 90 * time.Second, + TLSHandshakeTimeout: 10 * time.Second, + ExpectContinueTimeout: 1 * time.Second, + DisableKeepAlives: false, + DisableCompression: false, + MaxResponseHeaderBytes: 0, + //ResponseHeaderTimeout: time.Duration{}, + //ExpectContinueTimeout: time.Duration{}, + }, + } +} + +// newDefaultHTTPClientFactory creates a DefaultHTTPClientPolicyFactory object that sends HTTP requests to a Go's default http.Client. +func newDefaultHTTPClientFactory() Factory { + return FactoryFunc(func(next Policy, po *PolicyOptions) PolicyFunc { + return func(ctx context.Context, request Request) (Response, error) { + r, err := pipelineHTTPClient.Do(request.WithContext(ctx)) + if err != nil { + err = NewError(err, "HTTP request failed") + } + return NewHTTPResponse(r), err + } + }) +} + +var mfm = methodFactoryMarker{} // Singleton + +// MethodFactoryMarker returns a special marker Factory object. When Pipeline's Do method is called, any +// MethodMarkerFactory object is replaced with the specified methodFactory object. If nil is passed fro Do's +// methodFactory parameter, then the MethodFactoryMarker is ignored as the linked-list of Policy objects is created. +func MethodFactoryMarker() Factory { + return mfm +} + +type methodFactoryMarker struct { +} + +func (methodFactoryMarker) New(next Policy, po *PolicyOptions) Policy { + panic("methodFactoryMarker policy should have been replaced with a method policy") +} diff --git a/vendor/github.com/Azure/azure-pipeline-go/pipeline/defaultlog_syslog.go b/vendor/github.com/Azure/azure-pipeline-go/pipeline/defaultlog_syslog.go new file mode 100755 index 0000000000..d0bb774076 --- /dev/null +++ b/vendor/github.com/Azure/azure-pipeline-go/pipeline/defaultlog_syslog.go @@ -0,0 +1,33 @@ +// +build !windows,!nacl,!plan9 + +package pipeline + +import ( + "log" + "log/syslog" +) + +// ForceLog should rarely be used. It forceable logs an entry to the +// Windows Event Log (on Windows) or to the SysLog (on Linux) +func ForceLog(level LogLevel, msg string) { + if defaultLogger == nil { + return // Return fast if we failed to create the logger. + } + // We are logging it, ensure trailing newline + if len(msg) == 0 || msg[len(msg)-1] != '\n' { + msg += "\n" // Ensure trailing newline + } + switch level { + case LogFatal: + defaultLogger.Fatal(msg) + case LogPanic: + defaultLogger.Panic(msg) + case LogError, LogWarning, LogInfo: + defaultLogger.Print(msg) + } +} + +var defaultLogger = func() *log.Logger { + l, _ := syslog.NewLogger(syslog.LOG_USER|syslog.LOG_WARNING, log.LstdFlags) + return l +}() diff --git a/vendor/github.com/Azure/azure-pipeline-go/pipeline/defaultlog_windows.go b/vendor/github.com/Azure/azure-pipeline-go/pipeline/defaultlog_windows.go new file mode 100755 index 0000000000..cb67398995 --- /dev/null +++ b/vendor/github.com/Azure/azure-pipeline-go/pipeline/defaultlog_windows.go @@ -0,0 +1,61 @@ +package pipeline + +import ( + "os" + "syscall" + "unsafe" +) + +// ForceLog should rarely be used. It forceable logs an entry to the +// Windows Event Log (on Windows) or to the SysLog (on Linux) +func ForceLog(level LogLevel, msg string) { + var el eventType + switch level { + case LogError, LogFatal, LogPanic: + el = elError + case LogWarning: + el = elWarning + case LogInfo: + el = elInfo + } + // We are logging it, ensure trailing newline + if len(msg) == 0 || msg[len(msg)-1] != '\n' { + msg += "\n" // Ensure trailing newline + } + reportEvent(el, 0, msg) +} + +type eventType int16 + +const ( + elSuccess eventType = 0 + elError eventType = 1 + elWarning eventType = 2 + elInfo eventType = 4 +) + +var reportEvent = func() func(eventType eventType, eventID int32, msg string) { + advAPI32 := syscall.MustLoadDLL("AdvAPI32.dll") + registerEventSource := advAPI32.MustFindProc("RegisterEventSourceW") + + sourceName, _ := os.Executable() + sourceNameUTF16, _ := syscall.UTF16PtrFromString(sourceName) + handle, _, lastErr := registerEventSource.Call(uintptr(0), uintptr(unsafe.Pointer(sourceNameUTF16))) + if lastErr == nil { // On error, logging is a no-op + return func(eventType eventType, eventID int32, msg string) {} + } + reportEvent := advAPI32.MustFindProc("ReportEventW") + return func(eventType eventType, eventID int32, msg string) { + s, _ := syscall.UTF16PtrFromString(msg) + _, _, _ = reportEvent.Call( + uintptr(handle), // HANDLE hEventLog + uintptr(eventType), // WORD wType + uintptr(0), // WORD wCategory + uintptr(eventID), // DWORD dwEventID + uintptr(0), // PSID lpUserSid + uintptr(1), // WORD wNumStrings + uintptr(0), // DWORD dwDataSize + uintptr(unsafe.Pointer(&s)), // LPCTSTR *lpStrings + uintptr(0)) // LPVOID lpRawData + } +}() diff --git a/vendor/github.com/Azure/azure-pipeline-go/pipeline/doc.go b/vendor/github.com/Azure/azure-pipeline-go/pipeline/doc.go new file mode 100755 index 0000000000..b5ab05f4de --- /dev/null +++ b/vendor/github.com/Azure/azure-pipeline-go/pipeline/doc.go @@ -0,0 +1,161 @@ +// Copyright 2017 Microsoft Corporation. All rights reserved. +// Use of this source code is governed by an MIT +// license that can be found in the LICENSE file. + +/* +Package pipeline implements an HTTP request/response middleware pipeline whose +policy objects mutate an HTTP request's URL, query parameters, and/or headers before +the request is sent over the wire. + +Not all policy objects mutate an HTTP request; some policy objects simply impact the +flow of requests/responses by performing operations such as logging, retry policies, +timeouts, failure injection, and deserialization of response payloads. + +Implementing the Policy Interface + +To implement a policy, define a struct that implements the pipeline.Policy interface's Do method. Your Do +method is called when an HTTP request wants to be sent over the network. Your Do method can perform any +operation(s) it desires. For example, it can log the outgoing request, mutate the URL, headers, and/or query +parameters, inject a failure, etc. Your Do method must then forward the HTTP request to next Policy object +in a linked-list ensuring that the remaining Policy objects perform their work. Ultimately, the last Policy +object sends the HTTP request over the network (by calling the HTTPSender's Do method). + +When an HTTP response comes back, each Policy object in the linked-list gets a chance to process the response +(in reverse order). The Policy object can log the response, retry the operation if due to a transient failure +or timeout, deserialize the response body, etc. Ultimately, the last Policy object returns the HTTP response +to the code that initiated the original HTTP request. + +Here is a template for how to define a pipeline.Policy object: + + type myPolicy struct { + node PolicyNode + // TODO: Add configuration/setting fields here (if desired)... + } + + func (p *myPolicy) Do(ctx context.Context, request pipeline.Request) (pipeline.Response, error) { + // TODO: Mutate/process the HTTP request here... + response, err := p.node.Do(ctx, request) // Forward HTTP request to next Policy & get HTTP response + // TODO: Mutate/process the HTTP response here... + return response, err // Return response/error to previous Policy + } + +Implementing the Factory Interface + +Each Policy struct definition requires a factory struct definition that implements the pipeline.Factory interface's New +method. The New method is called when application code wants to initiate a new HTTP request. Factory's New method is +passed a pipeline.PolicyNode object which contains a reference to the owning pipeline.Pipeline object (discussed later) and +a reference to the next Policy object in the linked list. The New method should create its corresponding Policy object +passing it the PolicyNode and any other configuration/settings fields appropriate for the specific Policy object. + +Here is a template for how to define a pipeline.Policy object: + + // NOTE: Once created & initialized, Factory objects should be goroutine-safe (ex: immutable); + // this allows reuse (efficient use of memory) and makes these objects usable by multiple goroutines concurrently. + type myPolicyFactory struct { + // TODO: Add any configuration/setting fields if desired... + } + + func (f *myPolicyFactory) New(node pipeline.PolicyNode) Policy { + return &myPolicy{node: node} // TODO: Also initialize any configuration/setting fields here (if desired)... + } + +Using your Factory and Policy objects via a Pipeline + +To use the Factory and Policy objects, an application constructs a slice of Factory objects and passes +this slice to the pipeline.NewPipeline function. + + func NewPipeline(factories []pipeline.Factory, sender pipeline.HTTPSender) Pipeline + +This function also requires an object implementing the HTTPSender interface. For simple scenarios, +passing nil for HTTPSender causes a standard Go http.Client object to be created and used to actually +send the HTTP response over the network. For more advanced scenarios, you can pass your own HTTPSender +object in. This allows sharing of http.Client objects or the use of custom-configured http.Client objects +or other objects that can simulate the network requests for testing purposes. + +Now that you have a pipeline.Pipeline object, you can create a pipeline.Request object (which is a simple +wrapper around Go's standard http.Request object) and pass it to Pipeline's Do method along with passing a +context.Context for cancelling the HTTP request (if desired). + + type Pipeline interface { + Do(ctx context.Context, methodFactory pipeline.Factory, request pipeline.Request) (pipeline.Response, error) + } + +Do iterates over the slice of Factory objects and tells each one to create its corresponding +Policy object. After the linked-list of Policy objects have been created, Do calls the first +Policy object passing it the Context & HTTP request parameters. These parameters now flow through +all the Policy objects giving each object a chance to look at and/or mutate the HTTP request. +The last Policy object sends the message over the network. + +When the network operation completes, the HTTP response and error return values pass +back through the same Policy objects in reverse order. Most Policy objects ignore the +response/error but some log the result, retry the operation (depending on the exact +reason the operation failed), or deserialize the response's body. Your own Policy +objects can do whatever they like when processing outgoing requests or incoming responses. + +Note that after an I/O request runs to completion, the Policy objects for that request +are garbage collected. However, Pipeline object (like Factory objects) are goroutine-safe allowing +them to be created once and reused over many I/O operations. This allows for efficient use of +memory and also makes them safely usable by multiple goroutines concurrently. + +Inserting a Method-Specific Factory into the Linked-List of Policy Objects + +While Pipeline and Factory objects can be reused over many different operations, it is +common to have special behavior for a specific operation/method. For example, a method +may need to deserialize the response's body to an instance of a specific data type. +To accommodate this, the Pipeline's Do method takes an additional method-specific +Factory object. The Do method tells this Factory to create a Policy object and +injects this method-specific Policy object into the linked-list of Policy objects. + +When creating a Pipeline object, the slice of Factory objects passed must have 1 +(and only 1) entry marking where the method-specific Factory should be injected. +The Factory marker is obtained by calling the pipeline.MethodFactoryMarker() function: + + func MethodFactoryMarker() pipeline.Factory + +Creating an HTTP Request Object + +The HTTP request object passed to Pipeline's Do method is not Go's http.Request struct. +Instead, it is a pipeline.Request struct which is a simple wrapper around Go's standard +http.Request. You create a pipeline.Request object by calling the pipeline.NewRequest function: + + func NewRequest(method string, url url.URL, options pipeline.RequestOptions) (request pipeline.Request, err error) + +To this function, you must pass a pipeline.RequestOptions that looks like this: + + type RequestOptions struct { + // The readable and seekable stream to be sent to the server as the request's body. + Body io.ReadSeeker + + // The callback method (if not nil) to be invoked to report progress as the stream is uploaded in the HTTP request. + Progress ProgressReceiver + } + +The method and struct ensure that the request's body stream is a read/seekable stream. +A seekable stream is required so that upon retry, the final Policy object can seek +the stream back to the beginning before retrying the network request and re-uploading the +body. In addition, you can associate a ProgressReceiver callback function which will be +invoked periodically to report progress while bytes are being read from the body stream +and sent over the network. + +Processing the HTTP Response + +When an HTTP response comes in from the network, a reference to Go's http.Response struct is +embedded in a struct that implements the pipeline.Response interface: + + type Response interface { + Response() *http.Response + } + +This interface is returned through all the Policy objects. Each Policy object can call the Response +interface's Response method to examine (or mutate) the embedded http.Response object. + +A Policy object can internally define another struct (implementing the pipeline.Response interface) +that embeds an http.Response and adds additional fields and return this structure to other Policy +objects. This allows a Policy object to deserialize the body to some other struct and return the +original http.Response and the additional struct back through the Policy chain. Other Policy objects +can see the Response but cannot see the additional struct with the deserialized body. After all the +Policy objects have returned, the pipeline.Response interface is returned by Pipeline's Do method. +The caller of this method can perform a type assertion attempting to get back to the struct type +really returned by the Policy object. If the type assertion is successful, the caller now has +access to both the http.Response and the deserialized struct object.*/ +package pipeline diff --git a/vendor/github.com/Azure/azure-pipeline-go/pipeline/error.go b/vendor/github.com/Azure/azure-pipeline-go/pipeline/error.go new file mode 100755 index 0000000000..fd008364d6 --- /dev/null +++ b/vendor/github.com/Azure/azure-pipeline-go/pipeline/error.go @@ -0,0 +1,121 @@ +package pipeline + +import ( + "fmt" + "runtime" +) + +type causer interface { + Cause() error +} + +// ErrorNode can be an embedded field in a private error object. This field +// adds Program Counter support and a 'cause' (reference to a preceding error). +// When initializing a error type with this embedded field, initialize the +// ErrorNode field by calling ErrorNode{}.Initialize(cause). +type ErrorNode struct { + pc uintptr // Represents a Program Counter that you can get symbols for. + cause error // Refers to the preceding error (or nil) +} + +// Error returns a string with the PC's symbols or "" if the PC is invalid. +// When defining a new error type, have its Error method call this one passing +// it the string representation of the error. +func (e *ErrorNode) Error(msg string) string { + s := "" + if fn := runtime.FuncForPC(e.pc); fn != nil { + file, line := fn.FileLine(e.pc) + s = fmt.Sprintf("-> %v, %v:%v\n", fn.Name(), file, line) + } + s += msg + "\n\n" + if e.cause != nil { + s += e.cause.Error() + "\n" + } + return s +} + +// Cause returns the error that preceded this error. +func (e *ErrorNode) Cause() error { return e.cause } + +// Temporary returns true if the error occurred due to a temporary condition. +func (e ErrorNode) Temporary() bool { + type temporary interface { + Temporary() bool + } + + for err := e.cause; err != nil; { + if t, ok := err.(temporary); ok { + return t.Temporary() + } + + if cause, ok := err.(causer); ok { + err = cause.Cause() + } else { + err = nil + } + } + return false +} + +// Timeout returns true if the error occurred due to time expiring. +func (e ErrorNode) Timeout() bool { + type timeout interface { + Timeout() bool + } + + for err := e.cause; err != nil; { + if t, ok := err.(timeout); ok { + return t.Timeout() + } + + if cause, ok := err.(causer); ok { + err = cause.Cause() + } else { + err = nil + } + } + return false +} + +// Initialize is used to initialize an embedded ErrorNode field. +// It captures the caller's program counter and saves the cause (preceding error). +// To initialize the field, use "ErrorNode{}.Initialize(cause, 3)". A callersToSkip +// value of 3 is very common; but, depending on your code nesting, you may need +// a different value. +func (ErrorNode) Initialize(cause error, callersToSkip int) ErrorNode { + // Get the PC of Initialize method's caller. + pc := [1]uintptr{} + _ = runtime.Callers(callersToSkip, pc[:]) + return ErrorNode{pc: pc[0], cause: cause} +} + +// Cause walks all the preceding errors and return the originating error. +func Cause(err error) error { + for err != nil { + cause, ok := err.(causer) + if !ok { + break + } + err = cause.Cause() + } + return err +} + +// NewError creates a simple string error (like Error.New). But, this +// error also captures the caller's Program Counter and the preceding error. +func NewError(cause error, msg string) error { + return &pcError{ + ErrorNode: ErrorNode{}.Initialize(cause, 3), + msg: msg, + } +} + +// pcError is a simple string error (like error.New) with an ErrorNode (PC & cause). +type pcError struct { + ErrorNode + msg string +} + +// Error satisfies the error interface. It shows the error with Program Counter +// symbols and calls Error on the preceding error so you can see the full error chain. +func (e *pcError) Error() string { return e.ErrorNode.Error(e.msg) } diff --git a/vendor/github.com/Azure/azure-pipeline-go/pipeline/progress.go b/vendor/github.com/Azure/azure-pipeline-go/pipeline/progress.go new file mode 100755 index 0000000000..efa3c8ed06 --- /dev/null +++ b/vendor/github.com/Azure/azure-pipeline-go/pipeline/progress.go @@ -0,0 +1,82 @@ +package pipeline + +import "io" + +// ********** The following is common between the request body AND the response body. + +// ProgressReceiver defines the signature of a callback function invoked as progress is reported. +type ProgressReceiver func(bytesTransferred int64) + +// ********** The following are specific to the request body (a ReadSeekCloser) + +// This struct is used when sending a body to the network +type requestBodyProgress struct { + requestBody io.ReadSeeker // Seeking is required to support retries + pr ProgressReceiver +} + +// NewRequestBodyProgress adds progress reporting to an HTTP request's body stream. +func NewRequestBodyProgress(requestBody io.ReadSeeker, pr ProgressReceiver) io.ReadSeeker { + if pr == nil { + panic("pr must not be nil") + } + return &requestBodyProgress{requestBody: requestBody, pr: pr} +} + +// Read reads a block of data from an inner stream and reports progress +func (rbp *requestBodyProgress) Read(p []byte) (n int, err error) { + n, err = rbp.requestBody.Read(p) + if err != nil { + return + } + // Invokes the user's callback method to report progress + position, err := rbp.requestBody.Seek(0, io.SeekCurrent) + if err != nil { + panic(err) + } + rbp.pr(position) + return +} + +func (rbp *requestBodyProgress) Seek(offset int64, whence int) (offsetFromStart int64, err error) { + return rbp.requestBody.Seek(offset, whence) +} + +// requestBodyProgress supports Close but the underlying stream may not; if it does, Close will close it. +func (rbp *requestBodyProgress) Close() error { + if c, ok := rbp.requestBody.(io.Closer); ok { + return c.Close() + } + return nil +} + +// ********** The following are specific to the response body (a ReadCloser) + +// This struct is used when sending a body to the network +type responseBodyProgress struct { + responseBody io.ReadCloser + pr ProgressReceiver + offset int64 +} + +// NewResponseBodyProgress adds progress reporting to an HTTP response's body stream. +func NewResponseBodyProgress(responseBody io.ReadCloser, pr ProgressReceiver) io.ReadCloser { + if pr == nil { + panic("pr must not be nil") + } + return &responseBodyProgress{responseBody: responseBody, pr: pr, offset: 0} +} + +// Read reads a block of data from an inner stream and reports progress +func (rbp *responseBodyProgress) Read(p []byte) (n int, err error) { + n, err = rbp.responseBody.Read(p) + rbp.offset += int64(n) + + // Invokes the user's callback method to report progress + rbp.pr(rbp.offset) + return +} + +func (rbp *responseBodyProgress) Close() error { + return rbp.responseBody.Close() +} diff --git a/vendor/github.com/Azure/azure-pipeline-go/pipeline/request.go b/vendor/github.com/Azure/azure-pipeline-go/pipeline/request.go new file mode 100755 index 0000000000..1fbe72bd4d --- /dev/null +++ b/vendor/github.com/Azure/azure-pipeline-go/pipeline/request.go @@ -0,0 +1,147 @@ +package pipeline + +import ( + "io" + "net/http" + "net/url" + "strconv" +) + +// Request is a thin wrapper over an http.Request. The wrapper provides several helper methods. +type Request struct { + *http.Request +} + +// NewRequest initializes a new HTTP request object with any desired options. +func NewRequest(method string, url url.URL, body io.ReadSeeker) (request Request, err error) { + // Note: the url is passed by value so that any pipeline operations that modify it do so on a copy. + + // This code to construct an http.Request is copied from http.NewRequest(); we intentionally omitted removeEmptyPort for now. + request.Request = &http.Request{ + Method: method, + URL: &url, + Proto: "HTTP/1.1", + ProtoMajor: 1, + ProtoMinor: 1, + Header: make(http.Header), + Host: url.Host, + } + + if body != nil { + err = request.SetBody(body) + } + return +} + +// SetBody sets the body and content length, assumes body is not nil. +func (r Request) SetBody(body io.ReadSeeker) error { + size, err := body.Seek(0, io.SeekEnd) + if err != nil { + return err + } + + body.Seek(0, io.SeekStart) + r.ContentLength = size + r.Header["Content-Length"] = []string{strconv.FormatInt(size, 10)} + + if size != 0 { + r.Body = &retryableRequestBody{body: body} + r.GetBody = func() (io.ReadCloser, error) { + _, err := body.Seek(0, io.SeekStart) + if err != nil { + return nil, err + } + return r.Body, nil + } + } else { + // in case the body is an empty stream, we need to use http.NoBody to explicitly provide no content + r.Body = http.NoBody + r.GetBody = func() (io.ReadCloser, error) { + return http.NoBody, nil + } + + // close the user-provided empty body + if c, ok := body.(io.Closer); ok { + c.Close() + } + } + + return nil +} + +// Copy makes a copy of an http.Request. Specifically, it makes a deep copy +// of its Method, URL, Host, Proto(Major/Minor), Header. ContentLength, Close, +// RemoteAddr, RequestURI. Copy makes a shallow copy of the Body, GetBody, TLS, +// Cancel, Response, and ctx fields. Copy panics if any of these fields are +// not nil: TransferEncoding, Form, PostForm, MultipartForm, or Trailer. +func (r Request) Copy() Request { + if r.TransferEncoding != nil || r.Form != nil || r.PostForm != nil || r.MultipartForm != nil || r.Trailer != nil { + panic("Can't make a deep copy of the http.Request because at least one of the following is not nil:" + + "TransferEncoding, Form, PostForm, MultipartForm, or Trailer.") + } + copy := *r.Request // Copy the request + urlCopy := *(r.Request.URL) // Copy the URL + copy.URL = &urlCopy + copy.Header = http.Header{} // Copy the header + for k, vs := range r.Header { + for _, value := range vs { + copy.Header.Add(k, value) + } + } + return Request{Request: ©} // Return the copy +} + +func (r Request) close() error { + if r.Body != nil && r.Body != http.NoBody { + c, ok := r.Body.(*retryableRequestBody) + if !ok { + panic("unexpected request body type (should be *retryableReadSeekerCloser)") + } + return c.realClose() + } + return nil +} + +// RewindBody seeks the request's Body stream back to the beginning so it can be resent when retrying an operation. +func (r Request) RewindBody() error { + if r.Body != nil && r.Body != http.NoBody { + s, ok := r.Body.(io.Seeker) + if !ok { + panic("unexpected request body type (should be io.Seeker)") + } + + // Reset the stream back to the beginning + _, err := s.Seek(0, io.SeekStart) + return err + } + return nil +} + +// ********** The following type/methods implement the retryableRequestBody (a ReadSeekCloser) + +// This struct is used when sending a body to the network +type retryableRequestBody struct { + body io.ReadSeeker // Seeking is required to support retries +} + +// Read reads a block of data from an inner stream and reports progress +func (b *retryableRequestBody) Read(p []byte) (n int, err error) { + return b.body.Read(p) +} + +func (b *retryableRequestBody) Seek(offset int64, whence int) (offsetFromStart int64, err error) { + return b.body.Seek(offset, whence) +} + +func (b *retryableRequestBody) Close() error { + // We don't want the underlying transport to close the request body on transient failures so this is a nop. + // The pipeline closes the request body upon success. + return nil +} + +func (b *retryableRequestBody) realClose() error { + if c, ok := b.body.(io.Closer); ok { + return c.Close() + } + return nil +} diff --git a/vendor/github.com/Azure/azure-pipeline-go/pipeline/response.go b/vendor/github.com/Azure/azure-pipeline-go/pipeline/response.go new file mode 100755 index 0000000000..f2dc164821 --- /dev/null +++ b/vendor/github.com/Azure/azure-pipeline-go/pipeline/response.go @@ -0,0 +1,74 @@ +package pipeline + +import ( + "bytes" + "fmt" + "net/http" + "sort" + "strings" +) + +// The Response interface exposes an http.Response object as it returns through the pipeline of Policy objects. +// This ensures that Policy objects have access to the HTTP response. However, the object this interface encapsulates +// might be a struct with additional fields that is created by a Policy object (typically a method-specific Factory). +// The method that injected the method-specific Factory gets this returned Response and performs a type assertion +// to the expected struct and returns the struct to its caller. +type Response interface { + Response() *http.Response +} + +// This is the default struct that has the http.Response. +// A method can replace this struct with its own struct containing an http.Response +// field and any other additional fields. +type httpResponse struct { + response *http.Response +} + +// NewHTTPResponse is typically called by a Policy object to return a Response object. +func NewHTTPResponse(response *http.Response) Response { + return &httpResponse{response: response} +} + +// This method satisfies the public Response interface's Response method +func (r httpResponse) Response() *http.Response { + return r.response +} + +// WriteRequestWithResponse appends a formatted HTTP request into a Buffer. If request and/or err are +// not nil, then these are also written into the Buffer. +func WriteRequestWithResponse(b *bytes.Buffer, request *http.Request, response *http.Response, err error) { + // Write the request into the buffer. + fmt.Fprint(b, " "+request.Method+" "+request.URL.String()+"\n") + writeHeader(b, request.Header) + if response != nil { + fmt.Fprintln(b, " --------------------------------------------------------------------------------") + fmt.Fprint(b, " RESPONSE Status: "+response.Status+"\n") + writeHeader(b, response.Header) + } + if err != nil { + fmt.Fprintln(b, " --------------------------------------------------------------------------------") + fmt.Fprint(b, " ERROR:\n"+err.Error()+"\n") + } +} + +// formatHeaders appends an HTTP request's or response's header into a Buffer. +func writeHeader(b *bytes.Buffer, header map[string][]string) { + if len(header) == 0 { + b.WriteString(" (no headers)\n") + return + } + keys := make([]string, 0, len(header)) + // Alphabetize the headers + for k := range header { + keys = append(keys, k) + } + sort.Strings(keys) + for _, k := range keys { + // Redact the value of any Authorization header to prevent security information from persisting in logs + value := interface{}("REDACTED") + if !strings.EqualFold(k, "Authorization") { + value = header[k] + } + fmt.Fprintf(b, " %s: %+v\n", k, value) + } +} diff --git a/vendor/github.com/Azure/azure-pipeline-go/pipeline/version.go b/vendor/github.com/Azure/azure-pipeline-go/pipeline/version.go new file mode 100644 index 0000000000..c4bb62d810 --- /dev/null +++ b/vendor/github.com/Azure/azure-pipeline-go/pipeline/version.go @@ -0,0 +1,9 @@ +package pipeline + +const ( + // UserAgent is the string to be used in the user agent string when making requests. + UserAgent = "azure-pipeline-go/" + Version + + // Version is the semantic version (see http://semver.org) of the pipeline package. + Version = "0.1.0" +) diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/access_conditions.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/access_conditions.go new file mode 100644 index 0000000000..c7432e41c3 --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/access_conditions.go @@ -0,0 +1,67 @@ +package azblob + +import ( + "time" +) + +// HTTPAccessConditions identifies standard HTTP access conditions which you optionally set. +type HTTPAccessConditions struct { + IfModifiedSince time.Time + IfUnmodifiedSince time.Time + IfMatch ETag + IfNoneMatch ETag +} + +// pointers is for internal infrastructure. It returns the fields as pointers. +func (ac HTTPAccessConditions) pointers() (ims *time.Time, ius *time.Time, ime *ETag, inme *ETag) { + if !ac.IfModifiedSince.IsZero() { + ims = &ac.IfModifiedSince + } + if !ac.IfUnmodifiedSince.IsZero() { + ius = &ac.IfUnmodifiedSince + } + if ac.IfMatch != ETagNone { + ime = &ac.IfMatch + } + if ac.IfNoneMatch != ETagNone { + inme = &ac.IfNoneMatch + } + return +} + +// ContainerAccessConditions identifies container-specific access conditions which you optionally set. +type ContainerAccessConditions struct { + HTTPAccessConditions + LeaseAccessConditions +} + +// BlobAccessConditions identifies blob-specific access conditions which you optionally set. +type BlobAccessConditions struct { + HTTPAccessConditions + LeaseAccessConditions + AppendBlobAccessConditions + PageBlobAccessConditions +} + +// LeaseAccessConditions identifies lease access conditions for a container or blob which you optionally set. +type LeaseAccessConditions struct { + LeaseID string +} + +// pointers is for internal infrastructure. It returns the fields as pointers. +func (ac LeaseAccessConditions) pointers() (leaseID *string) { + if ac.LeaseID != "" { + leaseID = &ac.LeaseID + } + return +} + +/* +// getInt32 is for internal infrastructure. It is used with access condition values where +// 0 (the default setting) is meaningful. The library interprets 0 as do not send the header +// and the privately-storage field in the access condition object is stored as +1 higher than desired. +// THis method returns true, if the value is > 0 (explicitly set) and the stored value - 1 (the set desired value). +func getInt32(value int32) (bool, int32) { + return value > 0, value - 1 +} +*/ diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/atomicmorph.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/atomicmorph.go new file mode 100644 index 0000000000..385b0458b3 --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/atomicmorph.go @@ -0,0 +1,79 @@ +package azblob + +import "sync/atomic" + +// AtomicMorpherInt32 identifies a method passed to and invoked by the AtomicMorphInt32 function. +// The AtomicMorpher callback is passed a startValue and based on this value it returns +// what the new value should be and the result that AtomicMorph should return to its caller. +type AtomicMorpherInt32 func(startVal int32) (val int32, morphResult interface{}) + +// AtomicMorph atomically morphs target in to new value (and result) as indicated bythe AtomicMorpher callback function. +func AtomicMorphInt32(target *int32, morpher AtomicMorpherInt32) interface{} { + if target == nil || morpher == nil { + panic("target and morpher mut not be nil") + } + for { + currentVal := atomic.LoadInt32(target) + desiredVal, morphResult := morpher(currentVal) + if atomic.CompareAndSwapInt32(target, currentVal, desiredVal) { + return morphResult + } + } +} + +// AtomicMorpherUint32 identifies a method passed to and invoked by the AtomicMorph function. +// The AtomicMorpher callback is passed a startValue and based on this value it returns +// what the new value should be and the result that AtomicMorph should return to its caller. +type AtomicMorpherUint32 func(startVal uint32) (val uint32, morphResult interface{}) + +// AtomicMorph atomically morphs target in to new value (and result) as indicated bythe AtomicMorpher callback function. +func AtomicMorphUint32(target *uint32, morpher AtomicMorpherUint32) interface{} { + if target == nil || morpher == nil { + panic("target and morpher mut not be nil") + } + for { + currentVal := atomic.LoadUint32(target) + desiredVal, morphResult := morpher(currentVal) + if atomic.CompareAndSwapUint32(target, currentVal, desiredVal) { + return morphResult + } + } +} + +// AtomicMorpherUint64 identifies a method passed to and invoked by the AtomicMorphUint64 function. +// The AtomicMorpher callback is passed a startValue and based on this value it returns +// what the new value should be and the result that AtomicMorph should return to its caller. +type AtomicMorpherInt64 func(startVal int64) (val int64, morphResult interface{}) + +// AtomicMorph atomically morphs target in to new value (and result) as indicated bythe AtomicMorpher callback function. +func AtomicMorphInt64(target *int64, morpher AtomicMorpherInt64) interface{} { + if target == nil || morpher == nil { + panic("target and morpher mut not be nil") + } + for { + currentVal := atomic.LoadInt64(target) + desiredVal, morphResult := morpher(currentVal) + if atomic.CompareAndSwapInt64(target, currentVal, desiredVal) { + return morphResult + } + } +} + +// AtomicMorpherUint64 identifies a method passed to and invoked by the AtomicMorphUint64 function. +// The AtomicMorpher callback is passed a startValue and based on this value it returns +// what the new value should be and the result that AtomicMorph should return to its caller. +type AtomicMorpherUint64 func(startVal uint64) (val uint64, morphResult interface{}) + +// AtomicMorph atomically morphs target in to new value (and result) as indicated bythe AtomicMorpher callback function. +func AtomicMorphUint64(target *uint64, morpher AtomicMorpherUint64) interface{} { + if target == nil || morpher == nil { + panic("target and morpher mut not be nil") + } + for { + currentVal := atomic.LoadUint64(target) + desiredVal, morphResult := morpher(currentVal) + if atomic.CompareAndSwapUint64(target, currentVal, desiredVal) { + return morphResult + } + } +} diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/highlevel.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/highlevel.go new file mode 100644 index 0000000000..aa022826bb --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/highlevel.go @@ -0,0 +1,510 @@ +package azblob + +import ( + "context" + "encoding/base64" + "fmt" + "io" + "net/http" + + "bytes" + "os" + "sync" + "time" + + "github.com/Azure/azure-pipeline-go/pipeline" +) + +// CommonResponseHeaders returns the headers common to all blob REST API responses. +type CommonResponse interface { + // ETag returns the value for header ETag. + ETag() ETag + + // LastModified returns the value for header Last-Modified. + LastModified() time.Time + + // RequestID returns the value for header x-ms-request-id. + RequestID() string + + // Date returns the value for header Date. + Date() time.Time + + // Version returns the value for header x-ms-version. + Version() string + + // Response returns the raw HTTP response object. + Response() *http.Response +} + +// UploadToBlockBlobOptions identifies options used by the UploadBufferToBlockBlob and UploadFileToBlockBlob functions. +type UploadToBlockBlobOptions struct { + // BlockSize specifies the block size to use; the default (and maximum size) is BlockBlobMaxStageBlockBytes. + BlockSize int64 + + // Progress is a function that is invoked periodically as bytes are sent to the BlockBlobURL. + Progress pipeline.ProgressReceiver + + // BlobHTTPHeaders indicates the HTTP headers to be associated with the blob. + BlobHTTPHeaders BlobHTTPHeaders + + // Metadata indicates the metadata to be associated with the blob when PutBlockList is called. + Metadata Metadata + + // AccessConditions indicates the access conditions for the block blob. + AccessConditions BlobAccessConditions + + // Parallelism indicates the maximum number of blocks to upload in parallel (0=default) + Parallelism uint16 +} + +// UploadBufferToBlockBlob uploads a buffer in blocks to a block blob. +func UploadBufferToBlockBlob(ctx context.Context, b []byte, + blockBlobURL BlockBlobURL, o UploadToBlockBlobOptions) (CommonResponse, error) { + + // Validate parameters and set defaults + if o.BlockSize < 0 || o.BlockSize > BlockBlobMaxUploadBlobBytes { + panic(fmt.Sprintf("BlockSize option must be > 0 and <= %d", BlockBlobMaxUploadBlobBytes)) + } + if o.BlockSize == 0 { + o.BlockSize = BlockBlobMaxUploadBlobBytes // Default if unspecified + } + size := int64(len(b)) + + if size <= BlockBlobMaxUploadBlobBytes { + // If the size can fit in 1 Upload call, do it this way + var body io.ReadSeeker = bytes.NewReader(b) + if o.Progress != nil { + body = pipeline.NewRequestBodyProgress(body, o.Progress) + } + return blockBlobURL.Upload(ctx, body, o.BlobHTTPHeaders, o.Metadata, o.AccessConditions) + } + + var numBlocks = uint16(((size - 1) / o.BlockSize) + 1) + if numBlocks > BlockBlobMaxBlocks { + panic(fmt.Sprintf("The buffer's size is too big or the BlockSize is too small; the number of blocks must be <= %d", BlockBlobMaxBlocks)) + } + + blockIDList := make([]string, numBlocks) // Base-64 encoded block IDs + progress := int64(0) + progressLock := &sync.Mutex{} + + err := doBatchTransfer(ctx, batchTransferOptions{ + operationName: "UploadBufferToBlockBlob", + transferSize: size, + chunkSize: o.BlockSize, + parallelism: o.Parallelism, + operation: func(offset int64, count int64) error { + // This function is called once per block. + // It is passed this block's offset within the buffer and its count of bytes + // Prepare to read the proper block/section of the buffer + var body io.ReadSeeker = bytes.NewReader(b[offset : offset+count]) + blockNum := offset / o.BlockSize + if o.Progress != nil { + blockProgress := int64(0) + body = pipeline.NewRequestBodyProgress(body, + func(bytesTransferred int64) { + diff := bytesTransferred - blockProgress + blockProgress = bytesTransferred + progressLock.Lock() // 1 goroutine at a time gets a progress report + progress += diff + o.Progress(progress) + progressLock.Unlock() + }) + } + + // Block IDs are unique values to avoid issue if 2+ clients are uploading blocks + // at the same time causing PutBlockList to get a mix of blocks from all the clients. + blockIDList[blockNum] = base64.StdEncoding.EncodeToString(newUUID().bytes()) + _, err := blockBlobURL.StageBlock(ctx, blockIDList[blockNum], body, o.AccessConditions.LeaseAccessConditions) + return err + }, + }) + if err != nil { + return nil, err + } + // All put blocks were successful, call Put Block List to finalize the blob + return blockBlobURL.CommitBlockList(ctx, blockIDList, o.BlobHTTPHeaders, o.Metadata, o.AccessConditions) +} + +// UploadFileToBlockBlob uploads a file in blocks to a block blob. +func UploadFileToBlockBlob(ctx context.Context, file *os.File, + blockBlobURL BlockBlobURL, o UploadToBlockBlobOptions) (CommonResponse, error) { + + stat, err := file.Stat() + if err != nil { + return nil, err + } + m := mmf{} // Default to an empty slice; used for 0-size file + if stat.Size() != 0 { + m, err = newMMF(file, false, 0, int(stat.Size())) + if err != nil { + return nil, err + } + defer m.unmap() + } + return UploadBufferToBlockBlob(ctx, m, blockBlobURL, o) +} + +/////////////////////////////////////////////////////////////////////////////// + + +const BlobDefaultDownloadBlockSize = int64(4 * 1024 * 1024) // 4MB + +// DownloadFromAzureFileOptions identifies options used by the DownloadAzureFileToBuffer and DownloadAzureFileToFile functions. +type DownloadFromBlobOptions struct { + // BlockSize specifies the block size to use for each parallel download; the default size is BlobDefaultDownloadBlockSize. + BlockSize int64 + + // Progress is a function that is invoked periodically as bytes are received. + Progress pipeline.ProgressReceiver + + // AccessConditions indicates the access conditions used when making HTTP GET requests against the blob. + AccessConditions BlobAccessConditions + + // Parallelism indicates the maximum number of blocks to download in parallel (0=default) + Parallelism uint16 + + // RetryReaderOptionsPerBlock is used when downloading each block. + RetryReaderOptionsPerBlock RetryReaderOptions +} + +// downloadAzureFileToBuffer downloads an Azure file to a buffer with parallel. +func downloadBlobToBuffer(ctx context.Context, blobURL BlobURL, offset int64, count int64, + ac BlobAccessConditions, b []byte, o DownloadFromBlobOptions, + initialDownloadResponse *DownloadResponse) error { + // Validate parameters, and set defaults. + if o.BlockSize < 0 { + panic("BlockSize option must be >= 0") + } + if o.BlockSize == 0 { + o.BlockSize = BlobDefaultDownloadBlockSize + } + + if offset < 0 { + panic("offset option must be >= 0") + } + + if count < 0 { + panic("count option must be >= 0") + } + + if count == CountToEnd { // If size not specified, calculate it + if initialDownloadResponse != nil { + count = initialDownloadResponse.ContentLength() - offset // if we have the length, use it + } else { + // If we don't have the length at all, get it + dr, err := blobURL.Download(ctx, 0, CountToEnd, ac, false) + if err != nil { + return err + } + count = dr.ContentLength() - offset + } + } + + if int64(len(b)) < count { + panic(fmt.Errorf("the buffer's size should be equal to or larger than the request count of bytes: %d", count)) + } + + // Prepare and do parallel download. + progress := int64(0) + progressLock := &sync.Mutex{} + + err := doBatchTransfer(ctx, batchTransferOptions{ + operationName: "downloadBlobToBuffer", + transferSize: count, + chunkSize: o.BlockSize, + parallelism: o.Parallelism, + operation: func(chunkStart int64, count int64) error { + dr, err := blobURL.Download(ctx, chunkStart+ offset, count, ac, false) + body := dr.Body(o.RetryReaderOptionsPerBlock) + if o.Progress != nil { + rangeProgress := int64(0) + body = pipeline.NewResponseBodyProgress( + body, + func(bytesTransferred int64) { + diff := bytesTransferred - rangeProgress + rangeProgress = bytesTransferred + progressLock.Lock() + progress += diff + o.Progress(progress) + progressLock.Unlock() + }) + } + _, err = io.ReadFull(body, b[chunkStart:chunkStart+count]) + body.Close() + return err + }, + }) + if err != nil { + return err + } + return nil +} + +// DownloadAzureFileToBuffer downloads an Azure file to a buffer with parallel. +// Offset and count are optional, pass 0 for both to download the entire blob. +func DownloadBlobToBuffer(ctx context.Context, blobURL BlobURL, offset int64, count int64, + ac BlobAccessConditions, b []byte, o DownloadFromBlobOptions) error { + return downloadBlobToBuffer(ctx, blobURL, offset, count, ac, b, o, nil) +} + +// DownloadBlobToFile downloads an Azure file to a local file. +// The file would be truncated if the size doesn't match. +// Offset and count are optional, pass 0 for both to download the entire blob. +func DownloadBlobToFile(ctx context.Context, blobURL BlobURL, offset int64, count int64, + ac BlobAccessConditions, file *os.File, o DownloadFromBlobOptions) error { + // 1. Validate parameters. + if file == nil { + panic("file must not be nil") + } + + // 2. Calculate the size of the destination file + var size int64 + + if count == CountToEnd { + // Try to get Azure file's size + props, err := blobURL.GetProperties(ctx, ac) + if err != nil { + return err + } + size = props.ContentLength() - offset + } else { + size = count + } + + // 3. Compare and try to resize local file's size if it doesn't match Azure file's size. + stat, err := file.Stat() + if err != nil { + return err + } + if stat.Size() != size { + if err = file.Truncate(size); err != nil { + return err + } + } + + if size > 0 { + // 4. Set mmap and call DownloadAzureFileToBuffer. + m, err := newMMF(file, true, 0, int(size)) + if err != nil { + return err + } + defer m.unmap() + return downloadBlobToBuffer(ctx, blobURL, offset, size, ac, m, o, nil) + } else { // if the blob's size is 0, there is no need in downloading it + return nil + } +} + + +/////////////////////////////////////////////////////////////////////////////// + +// BatchTransferOptions identifies options used by doBatchTransfer. +type batchTransferOptions struct { + transferSize int64 + chunkSize int64 + parallelism uint16 + operation func(offset int64, chunkSize int64) error + operationName string +} + +// doBatchTransfer helps to execute operations in a batch manner. +func doBatchTransfer(ctx context.Context, o batchTransferOptions) error { + // Prepare and do parallel operations. + numChunks := uint16(((o.transferSize - 1) / o.chunkSize) + 1) + operationChannel := make(chan func() error, o.parallelism) // Create the channel that release 'parallelism' goroutines concurrently + operationResponseChannel := make(chan error, numChunks) // Holds each response + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + // Create the goroutines that process each operation (in parallel). + if o.parallelism == 0 { + o.parallelism = 5 // default parallelism + } + for g := uint16(0); g < o.parallelism; g++ { + //grIndex := g + go func() { + for f := range operationChannel { + //fmt.Printf("[%s] gr-%d start action\n", o.operationName, grIndex) + err := f() + operationResponseChannel <- err + //fmt.Printf("[%s] gr-%d end action\n", o.operationName, grIndex) + } + }() + } + + // Add each chunk's operation to the channel. + for chunkNum := uint16(0); chunkNum < numChunks; chunkNum++ { + curChunkSize := o.chunkSize + + if chunkNum == numChunks-1 { // Last chunk + curChunkSize = o.transferSize - (int64(chunkNum) * o.chunkSize) // Remove size of all transferred chunks from total + } + offset := int64(chunkNum) * o.chunkSize + + operationChannel <- func() error { + return o.operation(offset, curChunkSize) + } + } + close(operationChannel) + + // Wait for the operations to complete. + for chunkNum := uint16(0); chunkNum < numChunks; chunkNum++ { + responseError := <-operationResponseChannel + if responseError != nil { + cancel() // As soon as any operation fails, cancel all remaining operation calls + return responseError // No need to process anymore responses + } + } + return nil +} + +//////////////////////////////////////////////////////////////////////////////////////////////// + +type UploadStreamToBlockBlobOptions struct { + BufferSize int + MaxBuffers int + BlobHTTPHeaders BlobHTTPHeaders + Metadata Metadata + AccessConditions BlobAccessConditions +} + +func UploadStreamToBlockBlob(ctx context.Context, reader io.Reader, blockBlobURL BlockBlobURL, + o UploadStreamToBlockBlobOptions) (CommonResponse, error) { + result, err := uploadStream(ctx, reader, + UploadStreamOptions{BufferSize: o.BufferSize, MaxBuffers: o.MaxBuffers}, + &uploadStreamToBlockBlobOptions{b: blockBlobURL, o: o, blockIDPrefix: newUUID()}) + return result.(CommonResponse), err +} + +type uploadStreamToBlockBlobOptions struct { + b BlockBlobURL + o UploadStreamToBlockBlobOptions + blockIDPrefix uuid // UUID used with all blockIDs + maxBlockNum uint32 // defaults to 0 + firstBlock []byte // Used only if maxBlockNum is 0 +} + +func (t *uploadStreamToBlockBlobOptions) start(ctx context.Context) (interface{}, error) { + return nil, nil +} + +func (t *uploadStreamToBlockBlobOptions) chunk(ctx context.Context, num uint32, buffer []byte) error { + if num == 0 && len(buffer) < t.o.BufferSize { + // If whole payload fits in 1 block, don't stage it; End will upload it with 1 I/O operation + t.firstBlock = buffer + return nil + } + // Else, upload a staged block... + AtomicMorphUint32(&t.maxBlockNum, func(startVal uint32) (val uint32, morphResult interface{}) { + // Atomically remember (in t.numBlocks) the maximum block num we've ever seen + if startVal < num { + return num, nil + } + return startVal, nil + }) + blockID := newUuidBlockID(t.blockIDPrefix).WithBlockNumber(num).ToBase64() + _, err := t.b.StageBlock(ctx, blockID, bytes.NewReader(buffer), LeaseAccessConditions{}) + return err +} + +func (t *uploadStreamToBlockBlobOptions) end(ctx context.Context) (interface{}, error) { + if t.maxBlockNum == 0 { + // If whole payload fits in 1 block (block #0), upload it with 1 I/O operation + return t.b.Upload(ctx, bytes.NewReader(t.firstBlock), + t.o.BlobHTTPHeaders, t.o.Metadata, t.o.AccessConditions) + } + // Multiple blocks staged, commit them all now + blockID := newUuidBlockID(t.blockIDPrefix) + blockIDs := make([]string, t.maxBlockNum + 1) + for bn := uint32(0); bn <= t.maxBlockNum; bn++ { + blockIDs[bn] = blockID.WithBlockNumber(bn).ToBase64() + } + return t.b.CommitBlockList(ctx, blockIDs, t.o.BlobHTTPHeaders, t.o.Metadata, t.o.AccessConditions) +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +type iTransfer interface { + start(ctx context.Context) (interface{}, error) + chunk(ctx context.Context, num uint32, buffer []byte) error + end(ctx context.Context) (interface{}, error) +} + +type UploadStreamOptions struct { + MaxBuffers int + BufferSize int +} + +func uploadStream(ctx context.Context, reader io.Reader, o UploadStreamOptions, t iTransfer) (interface{}, error) { + ctx, cancel := context.WithCancel(ctx) // New context so that any failure cancels everything + defer cancel() + wg := sync.WaitGroup{} // Used to know when all outgoing messages have finished processing + type OutgoingMsg struct { + chunkNum uint32 + buffer []byte + } + + // Create a channel to hold the buffers usable for incoming datsa + incoming := make(chan []byte, o.MaxBuffers) + outgoing := make(chan OutgoingMsg, o.MaxBuffers) // Channel holding outgoing buffers + if result, err := t.start(ctx); err != nil { + return result, err + } + + numBuffers := 0 // The number of buffers & out going goroutines created so far + injectBuffer := func() { + // For each Buffer, create it and a goroutine to upload it + incoming <- make([]byte, o.BufferSize) // Add the new buffer to the incoming channel so this goroutine can from the reader into it + numBuffers++ + go func() { + for outgoingMsg := range outgoing { + // Upload the outgoing buffer + err := t.chunk(ctx, outgoingMsg.chunkNum, outgoingMsg.buffer) + wg.Done() // Indicate this buffer was sent + if nil != err { + cancel() + } + incoming <- outgoingMsg.buffer // The goroutine reading from the stream can use reuse this buffer now + } + }() + } + injectBuffer() // Create our 1st buffer & outgoing goroutine + + // This goroutine grabs a buffer, reads from the stream into the buffer, + // and inserts the buffer into the outgoing channel to be uploaded + for c := uint32(0); true; c++ { // Iterate once per chunk + var buffer []byte + if numBuffers < o.MaxBuffers { + select { + // We're not at max buffers, see if a previously-created buffer is available + case buffer = <-incoming: + break + default: + // No buffer available; inject a new buffer & go routine to process it + injectBuffer() + buffer = <-incoming // Grab the just-injected buffer + } + } else { + // We are at max buffers, block until we get to reuse one + buffer = <-incoming + } + n, err := io.ReadFull(reader, buffer) + if err != nil { + buffer = buffer[:n] // Make slice match the # of read bytes + } + if len(buffer) > 0 { + // Buffer not empty, upload it + wg.Add(1) // We're posting a buffer to be sent + outgoing <- OutgoingMsg{chunkNum: c, buffer: buffer} + } + if err != nil { // The reader is done, no more outgoing buffers + break + } + } + // NOTE: Don't close the incoming channel because the outgoing goroutines post buffers into it when they are done + close(outgoing) // Make all the outgoing goroutines terminate when this channel is empty + wg.Wait() // Wait for all pending outgoing messages to complete + // After all blocks uploaded, commit them to the blob & return the result + return t.end(ctx) +} diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/parsing_urls.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/parsing_urls.go new file mode 100644 index 0000000000..e797a59c0b --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/parsing_urls.go @@ -0,0 +1,111 @@ +package azblob + +import ( + "net/url" + "strings" +) + +const ( + snapshot = "snapshot" + SnapshotTimeFormat = "2006-01-02T15:04:05.0000000Z07:00" +) + +// A BlobURLParts object represents the components that make up an Azure Storage Container/Blob URL. You parse an +// existing URL into its parts by calling NewBlobURLParts(). You construct a URL from parts by calling URL(). +// NOTE: Changing any SAS-related field requires computing a new SAS signature. +type BlobURLParts struct { + Scheme string // Ex: "https://" + Host string // Ex: "account.blob.core.windows.net" + ContainerName string // "" if no container + BlobName string // "" if no blob + Snapshot string // "" if not a snapshot + SAS SASQueryParameters + UnparsedParams string +} + +// NewBlobURLParts parses a URL initializing BlobURLParts' fields including any SAS-related & snapshot query parameters. Any other +// query parameters remain in the UnparsedParams field. This method overwrites all fields in the BlobURLParts object. +func NewBlobURLParts(u url.URL) BlobURLParts { + up := BlobURLParts{ + Scheme: u.Scheme, + Host: u.Host, + } + + // Find the container & blob names (if any) + if u.Path != "" { + path := u.Path + if path[0] == '/' { + path = path[1:] // If path starts with a slash, remove it + } + + // Find the next slash (if it exists) + containerEndIndex := strings.Index(path, "/") + if containerEndIndex == -1 { // Slash not found; path has container name & no blob name + up.ContainerName = path + } else { + up.ContainerName = path[:containerEndIndex] // The container name is the part between the slashes + up.BlobName = path[containerEndIndex+1:] // The blob name is after the container slash + } + } + + // Convert the query parameters to a case-sensitive map & trim whitespace + paramsMap := u.Query() + + up.Snapshot = "" // Assume no snapshot + if snapshotStr, ok := caseInsensitiveValues(paramsMap).Get(snapshot); ok { + up.Snapshot = snapshotStr[0] + // If we recognized the query parameter, remove it from the map + delete(paramsMap, snapshot) + } + up.SAS = newSASQueryParameters(paramsMap, true) + up.UnparsedParams = paramsMap.Encode() + return up +} + +type caseInsensitiveValues url.Values // map[string][]string +func (values caseInsensitiveValues) Get(key string) ([]string, bool) { + key = strings.ToLower(key) + for k, v := range values { + if strings.ToLower(k) == key { + return v, true + } + } + return []string{}, false +} + +// URL returns a URL object whose fields are initialized from the BlobURLParts fields. The URL's RawQuery +// field contains the SAS, snapshot, and unparsed query parameters. +func (up BlobURLParts) URL() url.URL { + path := "" + // Concatenate container & blob names (if they exist) + if up.ContainerName != "" { + path += "/" + up.ContainerName + if up.BlobName != "" { + path += "/" + up.BlobName + } + } + + rawQuery := up.UnparsedParams + + // Concatenate blob snapshot query parameter (if it exists) + if up.Snapshot != "" { + if len(rawQuery) > 0 { + rawQuery += "&" + } + rawQuery += snapshot + "=" + up.Snapshot + } + sas := up.SAS.Encode() + if sas != "" { + if len(rawQuery) > 0 { + rawQuery += "&" + } + rawQuery += sas + } + u := url.URL{ + Scheme: up.Scheme, + Host: up.Host, + Path: path, + RawQuery: rawQuery, + } + return u +} diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/sas_service.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/sas_service.go new file mode 100644 index 0000000000..d0b12bc17a --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/sas_service.go @@ -0,0 +1,206 @@ +package azblob + +import ( + "bytes" + "fmt" + "strings" + "time" +) + +// BlobSASSignatureValues is used to generate a Shared Access Signature (SAS) for an Azure Storage container or blob. +type BlobSASSignatureValues struct { + Version string `param:"sv"` // If not specified, this defaults to SASVersion + Protocol SASProtocol `param:"spr"` // See the SASProtocol* constants + StartTime time.Time `param:"st"` // Not specified if IsZero + ExpiryTime time.Time `param:"se"` // Not specified if IsZero + Permissions string `param:"sp"` // Create by initializing a ContainerSASPermissions or BlobSASPermissions and then call String() + IPRange IPRange `param:"sip"` + Identifier string `param:"si"` + ContainerName string + BlobName string // Use "" to create a Container SAS + CacheControl string // rscc + ContentDisposition string // rscd + ContentEncoding string // rsce + ContentLanguage string // rscl + ContentType string // rsct +} + +// NewSASQueryParameters uses an account's shared key credential to sign this signature values to produce +// the proper SAS query parameters. +func (v BlobSASSignatureValues) NewSASQueryParameters(sharedKeyCredential *SharedKeyCredential) SASQueryParameters { + if sharedKeyCredential == nil { + panic("sharedKeyCredential can't be nil") + } + + resource := "c" + if v.BlobName == "" { + // Make sure the permission characters are in the correct order + perms := &ContainerSASPermissions{} + if err := perms.Parse(v.Permissions); err != nil { + panic(err) + } + v.Permissions = perms.String() + } else { + resource = "b" + // Make sure the permission characters are in the correct order + perms := &BlobSASPermissions{} + if err := perms.Parse(v.Permissions); err != nil { + panic(err) + } + v.Permissions = perms.String() + } + if v.Version == "" { + v.Version = SASVersion + } + startTime, expiryTime := FormatTimesForSASSigning(v.StartTime, v.ExpiryTime) + + // String to sign: http://msdn.microsoft.com/en-us/library/azure/dn140255.aspx + stringToSign := strings.Join([]string{ + v.Permissions, + startTime, + expiryTime, + getCanonicalName(sharedKeyCredential.AccountName(), v.ContainerName, v.BlobName), + v.Identifier, + v.IPRange.String(), + string(v.Protocol), + v.Version, + v.CacheControl, // rscc + v.ContentDisposition, // rscd + v.ContentEncoding, // rsce + v.ContentLanguage, // rscl + v.ContentType}, // rsct + "\n") + signature := sharedKeyCredential.ComputeHMACSHA256(stringToSign) + + p := SASQueryParameters{ + // Common SAS parameters + version: v.Version, + protocol: v.Protocol, + startTime: v.StartTime, + expiryTime: v.ExpiryTime, + permissions: v.Permissions, + ipRange: v.IPRange, + + // Container/Blob-specific SAS parameters + resource: resource, + identifier: v.Identifier, + + // Calculated SAS signature + signature: signature, + } + return p +} + +// getCanonicalName computes the canonical name for a container or blob resource for SAS signing. +func getCanonicalName(account string, containerName string, blobName string) string { + // Container: "/blob/account/containername" + // Blob: "/blob/account/containername/blobname" + elements := []string{"/blob/", account, "/", containerName} + if blobName != "" { + elements = append(elements, "/", strings.Replace(blobName, "\\", "/", -1)) + } + return strings.Join(elements, "") +} + +// The ContainerSASPermissions type simplifies creating the permissions string for an Azure Storage container SAS. +// Initialize an instance of this type and then call its String method to set BlobSASSignatureValues's Permissions field. +type ContainerSASPermissions struct { + Read, Add, Create, Write, Delete, List bool +} + +// String produces the SAS permissions string for an Azure Storage container. +// Call this method to set BlobSASSignatureValues's Permissions field. +func (p ContainerSASPermissions) String() string { + var b bytes.Buffer + if p.Read { + b.WriteRune('r') + } + if p.Add { + b.WriteRune('a') + } + if p.Create { + b.WriteRune('c') + } + if p.Write { + b.WriteRune('w') + } + if p.Delete { + b.WriteRune('d') + } + if p.List { + b.WriteRune('l') + } + return b.String() +} + +// Parse initializes the ContainerSASPermissions's fields from a string. +func (p *ContainerSASPermissions) Parse(s string) error { + *p = ContainerSASPermissions{} // Clear the flags + for _, r := range s { + switch r { + case 'r': + p.Read = true + case 'a': + p.Add = true + case 'c': + p.Create = true + case 'w': + p.Write = true + case 'd': + p.Delete = true + case 'l': + p.List = true + default: + return fmt.Errorf("Invalid permission: '%v'", r) + } + } + return nil +} + +// The BlobSASPermissions type simplifies creating the permissions string for an Azure Storage blob SAS. +// Initialize an instance of this type and then call its String method to set BlobSASSignatureValues's Permissions field. +type BlobSASPermissions struct{ Read, Add, Create, Write, Delete bool } + +// String produces the SAS permissions string for an Azure Storage blob. +// Call this method to set BlobSASSignatureValues's Permissions field. +func (p BlobSASPermissions) String() string { + var b bytes.Buffer + if p.Read { + b.WriteRune('r') + } + if p.Add { + b.WriteRune('a') + } + if p.Create { + b.WriteRune('c') + } + if p.Write { + b.WriteRune('w') + } + if p.Delete { + b.WriteRune('d') + } + return b.String() +} + +// Parse initializes the BlobSASPermissions's fields from a string. +func (p *BlobSASPermissions) Parse(s string) error { + *p = BlobSASPermissions{} // Clear the flags + for _, r := range s { + switch r { + case 'r': + p.Read = true + case 'a': + p.Add = true + case 'c': + p.Create = true + case 'w': + p.Write = true + case 'd': + p.Delete = true + default: + return fmt.Errorf("Invalid permission: '%v'", r) + } + } + return nil +} diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/service_codes_blob.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/service_codes_blob.go new file mode 100644 index 0000000000..d260f8aee5 --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/service_codes_blob.go @@ -0,0 +1,195 @@ +package azblob + +// https://docs.microsoft.com/en-us/rest/api/storageservices/blob-service-error-codes + +// ServiceCode values indicate a service failure. +const ( + // ServiceCodeAppendPositionConditionNotMet means the append position condition specified was not met. + ServiceCodeAppendPositionConditionNotMet ServiceCodeType = "AppendPositionConditionNotMet" + + // ServiceCodeBlobAlreadyExists means the specified blob already exists. + ServiceCodeBlobAlreadyExists ServiceCodeType = "BlobAlreadyExists" + + // ServiceCodeBlobNotFound means the specified blob does not exist. + ServiceCodeBlobNotFound ServiceCodeType = "BlobNotFound" + + // ServiceCodeBlobOverwritten means the blob has been recreated since the previous snapshot was taken. + ServiceCodeBlobOverwritten ServiceCodeType = "BlobOverwritten" + + // ServiceCodeBlobTierInadequateForContentLength means the specified blob tier size limit cannot be less than content length. + ServiceCodeBlobTierInadequateForContentLength ServiceCodeType = "BlobTierInadequateForContentLength" + + // ServiceCodeBlockCountExceedsLimit means the committed block count cannot exceed the maximum limit of 50,000 blocks + // or that the uncommitted block count cannot exceed the maximum limit of 100,000 blocks. + ServiceCodeBlockCountExceedsLimit ServiceCodeType = "BlockCountExceedsLimit" + + // ServiceCodeBlockListTooLong means the block list may not contain more than 50,000 blocks. + ServiceCodeBlockListTooLong ServiceCodeType = "BlockListTooLong" + + // ServiceCodeCannotChangeToLowerTier means that a higher blob tier has already been explicitly set. + ServiceCodeCannotChangeToLowerTier ServiceCodeType = "CannotChangeToLowerTier" + + // ServiceCodeCannotVerifyCopySource means that the service could not verify the copy source within the specified time. + // Examine the HTTP status code and message for more information about the failure. + ServiceCodeCannotVerifyCopySource ServiceCodeType = "CannotVerifyCopySource" + + // ServiceCodeContainerAlreadyExists means the specified container already exists. + ServiceCodeContainerAlreadyExists ServiceCodeType = "ContainerAlreadyExists" + + // ServiceCodeContainerBeingDeleted means the specified container is being deleted. + ServiceCodeContainerBeingDeleted ServiceCodeType = "ContainerBeingDeleted" + + // ServiceCodeContainerDisabled means the specified container has been disabled by the administrator. + ServiceCodeContainerDisabled ServiceCodeType = "ContainerDisabled" + + // ServiceCodeContainerNotFound means the specified container does not exist. + ServiceCodeContainerNotFound ServiceCodeType = "ContainerNotFound" + + // ServiceCodeContentLengthLargerThanTierLimit means the blob's content length cannot exceed its tier limit. + ServiceCodeContentLengthLargerThanTierLimit ServiceCodeType = "ContentLengthLargerThanTierLimit" + + // ServiceCodeCopyAcrossAccountsNotSupported means the copy source account and destination account must be the same. + ServiceCodeCopyAcrossAccountsNotSupported ServiceCodeType = "CopyAcrossAccountsNotSupported" + + // ServiceCodeCopyIDMismatch means the specified copy ID did not match the copy ID for the pending copy operation. + ServiceCodeCopyIDMismatch ServiceCodeType = "CopyIdMismatch" + + // ServiceCodeFeatureVersionMismatch means the type of blob in the container is unrecognized by this version or + // that the operation for AppendBlob requires at least version 2015-02-21. + ServiceCodeFeatureVersionMismatch ServiceCodeType = "FeatureVersionMismatch" + + // ServiceCodeIncrementalCopyBlobMismatch means the specified source blob is different than the copy source of the existing incremental copy blob. + ServiceCodeIncrementalCopyBlobMismatch ServiceCodeType = "IncrementalCopyBlobMismatch" + + // ServiceCodeIncrementalCopyOfEralierVersionSnapshotNotAllowed means the specified snapshot is earlier than the last snapshot copied into the incremental copy blob. + ServiceCodeIncrementalCopyOfEralierVersionSnapshotNotAllowed ServiceCodeType = "IncrementalCopyOfEralierVersionSnapshotNotAllowed" + + // ServiceCodeIncrementalCopySourceMustBeSnapshot means the source for incremental copy request must be a snapshot. + ServiceCodeIncrementalCopySourceMustBeSnapshot ServiceCodeType = "IncrementalCopySourceMustBeSnapshot" + + // ServiceCodeInfiniteLeaseDurationRequired means the lease ID matched, but the specified lease must be an infinite-duration lease. + ServiceCodeInfiniteLeaseDurationRequired ServiceCodeType = "InfiniteLeaseDurationRequired" + + // ServiceCodeInvalidBlobOrBlock means the specified blob or block content is invalid. + ServiceCodeInvalidBlobOrBlock ServiceCodeType = "InvalidBlobOrBlock" + + // ServiceCodeInvalidBlobType means the blob type is invalid for this operation. + ServiceCodeInvalidBlobType ServiceCodeType = "InvalidBlobType" + + // ServiceCodeInvalidBlockID means the specified block ID is invalid. The block ID must be Base64-encoded. + ServiceCodeInvalidBlockID ServiceCodeType = "InvalidBlockId" + + // ServiceCodeInvalidBlockList means the specified block list is invalid. + ServiceCodeInvalidBlockList ServiceCodeType = "InvalidBlockList" + + // ServiceCodeInvalidOperation means an invalid operation against a blob snapshot. + ServiceCodeInvalidOperation ServiceCodeType = "InvalidOperation" + + // ServiceCodeInvalidPageRange means the page range specified is invalid. + ServiceCodeInvalidPageRange ServiceCodeType = "InvalidPageRange" + + // ServiceCodeInvalidSourceBlobType means the copy source blob type is invalid for this operation. + ServiceCodeInvalidSourceBlobType ServiceCodeType = "InvalidSourceBlobType" + + // ServiceCodeInvalidSourceBlobURL means the source URL for incremental copy request must be valid Azure Storage blob URL. + ServiceCodeInvalidSourceBlobURL ServiceCodeType = "InvalidSourceBlobUrl" + + // ServiceCodeInvalidVersionForPageBlobOperation means that all operations on page blobs require at least version 2009-09-19. + ServiceCodeInvalidVersionForPageBlobOperation ServiceCodeType = "InvalidVersionForPageBlobOperation" + + // ServiceCodeLeaseAlreadyPresent means there is already a lease present. + ServiceCodeLeaseAlreadyPresent ServiceCodeType = "LeaseAlreadyPresent" + + // ServiceCodeLeaseAlreadyBroken means the lease has already been broken and cannot be broken again. + ServiceCodeLeaseAlreadyBroken ServiceCodeType = "LeaseAlreadyBroken" + + // ServiceCodeLeaseIDMismatchWithBlobOperation means the lease ID specified did not match the lease ID for the blob. + ServiceCodeLeaseIDMismatchWithBlobOperation ServiceCodeType = "LeaseIdMismatchWithBlobOperation" + + // ServiceCodeLeaseIDMismatchWithContainerOperation means the lease ID specified did not match the lease ID for the container. + ServiceCodeLeaseIDMismatchWithContainerOperation ServiceCodeType = "LeaseIdMismatchWithContainerOperation" + + // ServiceCodeLeaseIDMismatchWithLeaseOperation means the lease ID specified did not match the lease ID for the blob/container. + ServiceCodeLeaseIDMismatchWithLeaseOperation ServiceCodeType = "LeaseIdMismatchWithLeaseOperation" + + // ServiceCodeLeaseIDMissing means there is currently a lease on the blob/container and no lease ID was specified in the request. + ServiceCodeLeaseIDMissing ServiceCodeType = "LeaseIdMissing" + + // ServiceCodeLeaseIsBreakingAndCannotBeAcquired means the lease ID matched, but the lease is currently in breaking state and cannot be acquired until it is broken. + ServiceCodeLeaseIsBreakingAndCannotBeAcquired ServiceCodeType = "LeaseIsBreakingAndCannotBeAcquired" + + // ServiceCodeLeaseIsBreakingAndCannotBeChanged means the lease ID matched, but the lease is currently in breaking state and cannot be changed. + ServiceCodeLeaseIsBreakingAndCannotBeChanged ServiceCodeType = "LeaseIsBreakingAndCannotBeChanged" + + // ServiceCodeLeaseIsBrokenAndCannotBeRenewed means the lease ID matched, but the lease has been broken explicitly and cannot be renewed. + ServiceCodeLeaseIsBrokenAndCannotBeRenewed ServiceCodeType = "LeaseIsBrokenAndCannotBeRenewed" + + // ServiceCodeLeaseLost means a lease ID was specified, but the lease for the blob/container has expired. + ServiceCodeLeaseLost ServiceCodeType = "LeaseLost" + + // ServiceCodeLeaseNotPresentWithBlobOperation means there is currently no lease on the blob. + ServiceCodeLeaseNotPresentWithBlobOperation ServiceCodeType = "LeaseNotPresentWithBlobOperation" + + // ServiceCodeLeaseNotPresentWithContainerOperation means there is currently no lease on the container. + ServiceCodeLeaseNotPresentWithContainerOperation ServiceCodeType = "LeaseNotPresentWithContainerOperation" + + // ServiceCodeLeaseNotPresentWithLeaseOperation means there is currently no lease on the blob/container. + ServiceCodeLeaseNotPresentWithLeaseOperation ServiceCodeType = "LeaseNotPresentWithLeaseOperation" + + // ServiceCodeMaxBlobSizeConditionNotMet means the max blob size condition specified was not met. + ServiceCodeMaxBlobSizeConditionNotMet ServiceCodeType = "MaxBlobSizeConditionNotMet" + + // ServiceCodeNoPendingCopyOperation means there is currently no pending copy operation. + ServiceCodeNoPendingCopyOperation ServiceCodeType = "NoPendingCopyOperation" + + // ServiceCodeOperationNotAllowedOnIncrementalCopyBlob means the specified operation is not allowed on an incremental copy blob. + ServiceCodeOperationNotAllowedOnIncrementalCopyBlob ServiceCodeType = "OperationNotAllowedOnIncrementalCopyBlob" + + // ServiceCodePendingCopyOperation means there is currently a pending copy operation. + ServiceCodePendingCopyOperation ServiceCodeType = "PendingCopyOperation" + + // ServiceCodePreviousSnapshotCannotBeNewer means the prevsnapshot query parameter value cannot be newer than snapshot query parameter value. + ServiceCodePreviousSnapshotCannotBeNewer ServiceCodeType = "PreviousSnapshotCannotBeNewer" + + // ServiceCodePreviousSnapshotNotFound means the previous snapshot is not found. + ServiceCodePreviousSnapshotNotFound ServiceCodeType = "PreviousSnapshotNotFound" + + // ServiceCodePreviousSnapshotOperationNotSupported means that differential Get Page Ranges is not supported on the previous snapshot. + ServiceCodePreviousSnapshotOperationNotSupported ServiceCodeType = "PreviousSnapshotOperationNotSupported" + + // ServiceCodeSequenceNumberConditionNotMet means the sequence number condition specified was not met. + ServiceCodeSequenceNumberConditionNotMet ServiceCodeType = "SequenceNumberConditionNotMet" + + // ServiceCodeSequenceNumberIncrementTooLarge means the sequence number increment cannot be performed because it would result in overflow of the sequence number. + ServiceCodeSequenceNumberIncrementTooLarge ServiceCodeType = "SequenceNumberIncrementTooLarge" + + // ServiceCodeSnapshotCountExceeded means the snapshot count against this blob has been exceeded. + ServiceCodeSnapshotCountExceeded ServiceCodeType = "SnapshotCountExceeded" + + // ServiceCodeSnaphotOperationRateExceeded means the rate of snapshot operations against this blob has been exceeded. + ServiceCodeSnaphotOperationRateExceeded ServiceCodeType = "SnaphotOperationRateExceeded" + + // ServiceCodeSnapshotsPresent means this operation is not permitted while the blob has snapshots. + ServiceCodeSnapshotsPresent ServiceCodeType = "SnapshotsPresent" + + // ServiceCodeSourceConditionNotMet means the source condition specified using HTTP conditional header(s) is not met. + ServiceCodeSourceConditionNotMet ServiceCodeType = "SourceConditionNotMet" + + // ServiceCodeSystemInUse means this blob is in use by the system. + ServiceCodeSystemInUse ServiceCodeType = "SystemInUse" + + // ServiceCodeTargetConditionNotMet means the target condition specified using HTTP conditional header(s) is not met. + ServiceCodeTargetConditionNotMet ServiceCodeType = "TargetConditionNotMet" + + // ServiceCodeUnauthorizedBlobOverwrite means this request is not authorized to perform blob overwrites. + ServiceCodeUnauthorizedBlobOverwrite ServiceCodeType = "UnauthorizedBlobOverwrite" + + // ServiceCodeBlobBeingRehydrated means this operation is not permitted because the blob is being rehydrated. + ServiceCodeBlobBeingRehydrated ServiceCodeType = "BlobBeingRehydrated" + + // ServiceCodeBlobArchived means this operation is not permitted on an archived blob. + ServiceCodeBlobArchived ServiceCodeType = "BlobArchived" + + // ServiceCodeBlobNotArchived means this blob is currently not in the archived state. + ServiceCodeBlobNotArchived ServiceCodeType = "BlobNotArchived" +) diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/url_append_blob.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/url_append_blob.go new file mode 100644 index 0000000000..b8711f5a1c --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/url_append_blob.go @@ -0,0 +1,112 @@ +package azblob + +import ( + "context" + "io" + "net/url" + + "github.com/Azure/azure-pipeline-go/pipeline" +) + +const ( + // AppendBlobMaxAppendBlockBytes indicates the maximum number of bytes that can be sent in a call to AppendBlock. + AppendBlobMaxAppendBlockBytes = 4 * 1024 * 1024 // 4MB + + // AppendBlobMaxBlocks indicates the maximum number of blocks allowed in an append blob. + AppendBlobMaxBlocks = 50000 +) + +// AppendBlobURL defines a set of operations applicable to append blobs. +type AppendBlobURL struct { + BlobURL + abClient appendBlobClient +} + +// NewAppendBlobURL creates an AppendBlobURL object using the specified URL and request policy pipeline. +func NewAppendBlobURL(url url.URL, p pipeline.Pipeline) AppendBlobURL { + blobClient := newBlobClient(url, p) + abClient := newAppendBlobClient(url, p) + return AppendBlobURL{BlobURL: BlobURL{blobClient: blobClient}, abClient: abClient} +} + +// WithPipeline creates a new AppendBlobURL object identical to the source but with the specific request policy pipeline. +func (ab AppendBlobURL) WithPipeline(p pipeline.Pipeline) AppendBlobURL { + return NewAppendBlobURL(ab.blobClient.URL(), p) +} + +// WithSnapshot creates a new AppendBlobURL object identical to the source but with the specified snapshot timestamp. +// Pass "" to remove the snapshot returning a URL to the base blob. +func (ab AppendBlobURL) WithSnapshot(snapshot string) AppendBlobURL { + p := NewBlobURLParts(ab.URL()) + p.Snapshot = snapshot + return NewAppendBlobURL(p.URL(), ab.blobClient.Pipeline()) +} + +// Create creates a 0-length append blob. Call AppendBlock to append data to an append blob. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob. +func (ab AppendBlobURL) Create(ctx context.Context, h BlobHTTPHeaders, metadata Metadata, ac BlobAccessConditions) (*AppendBlobCreateResponse, error) { + ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch := ac.HTTPAccessConditions.pointers() + return ab.abClient.Create(ctx, 0, nil, + &h.ContentType, &h.ContentEncoding, &h.ContentLanguage, h.ContentMD5, + &h.CacheControl, metadata, ac.LeaseAccessConditions.pointers(), &h.ContentDisposition, + ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, nil) +} + +// AppendBlock writes a stream to a new block of data to the end of the existing append blob. +// This method panics if the stream is not at position 0. +// Note that the http client closes the body stream after the request is sent to the service. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/append-block. +func (ab AppendBlobURL) AppendBlock(ctx context.Context, body io.ReadSeeker, ac BlobAccessConditions) (*AppendBlobAppendBlockResponse, error) { + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.HTTPAccessConditions.pointers() + ifAppendPositionEqual, ifMaxSizeLessThanOrEqual := ac.AppendBlobAccessConditions.pointers() + return ab.abClient.AppendBlock(ctx, body, validateSeekableStreamAt0AndGetCount(body), nil, + ac.LeaseAccessConditions.pointers(), + ifMaxSizeLessThanOrEqual, ifAppendPositionEqual, + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) +} + +// AppendBlobAccessConditions identifies append blob-specific access conditions which you optionally set. +type AppendBlobAccessConditions struct { + // IfAppendPositionEqual ensures that the AppendBlock operation succeeds + // only if the append position is equal to a value. + // IfAppendPositionEqual=0 means no 'IfAppendPositionEqual' header specified. + // IfAppendPositionEqual>0 means 'IfAppendPositionEqual' header specified with its value + // IfAppendPositionEqual==-1 means IfAppendPositionEqual' header specified with a value of 0 + IfAppendPositionEqual int64 + + // IfMaxSizeLessThanOrEqual ensures that the AppendBlock operation succeeds + // only if the append blob's size is less than or equal to a value. + // IfMaxSizeLessThanOrEqual=0 means no 'IfMaxSizeLessThanOrEqual' header specified. + // IfMaxSizeLessThanOrEqual>0 means 'IfMaxSizeLessThanOrEqual' header specified with its value + // IfMaxSizeLessThanOrEqual==-1 means 'IfMaxSizeLessThanOrEqual' header specified with a value of 0 + IfMaxSizeLessThanOrEqual int64 +} + +// pointers is for internal infrastructure. It returns the fields as pointers. +func (ac AppendBlobAccessConditions) pointers() (iape *int64, imsltoe *int64) { + if ac.IfAppendPositionEqual < -1 { + panic("IfAppendPositionEqual can't be less than -1") + } + if ac.IfMaxSizeLessThanOrEqual < -1 { + panic("IfMaxSizeLessThanOrEqual can't be less than -1") + } + var zero int64 // defaults to 0 + switch ac.IfAppendPositionEqual { + case -1: + iape = &zero + case 0: + iape = nil + default: + iape = &ac.IfAppendPositionEqual + } + + switch ac.IfMaxSizeLessThanOrEqual { + case -1: + imsltoe = &zero + case 0: + imsltoe = nil + default: + imsltoe = &ac.IfMaxSizeLessThanOrEqual + } + return +} diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/url_blob.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/url_blob.go new file mode 100644 index 0000000000..96d85cbfd8 --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/url_blob.go @@ -0,0 +1,222 @@ +package azblob + +import ( + "context" + "net/url" + + "github.com/Azure/azure-pipeline-go/pipeline" +) + +// A BlobURL represents a URL to an Azure Storage blob; the blob may be a block blob, append blob, or page blob. +type BlobURL struct { + blobClient blobClient +} + +// NewBlobURL creates a BlobURL object using the specified URL and request policy pipeline. +func NewBlobURL(url url.URL, p pipeline.Pipeline) BlobURL { + if p == nil { + panic("p can't be nil") + } + blobClient := newBlobClient(url, p) + return BlobURL{blobClient: blobClient} +} + +// URL returns the URL endpoint used by the BlobURL object. +func (b BlobURL) URL() url.URL { + return b.blobClient.URL() +} + +// String returns the URL as a string. +func (b BlobURL) String() string { + u := b.URL() + return u.String() +} + +// WithPipeline creates a new BlobURL object identical to the source but with the specified request policy pipeline. +func (b BlobURL) WithPipeline(p pipeline.Pipeline) BlobURL { + if p == nil { + panic("p can't be nil") + } + return NewBlobURL(b.blobClient.URL(), p) +} + +// WithSnapshot creates a new BlobURL object identical to the source but with the specified snapshot timestamp. +// Pass "" to remove the snapshot returning a URL to the base blob. +func (b BlobURL) WithSnapshot(snapshot string) BlobURL { + p := NewBlobURLParts(b.URL()) + p.Snapshot = snapshot + return NewBlobURL(p.URL(), b.blobClient.Pipeline()) +} + +// ToAppendBlobURL creates an AppendBlobURL using the source's URL and pipeline. +func (b BlobURL) ToAppendBlobURL() AppendBlobURL { + return NewAppendBlobURL(b.URL(), b.blobClient.Pipeline()) +} + +// ToBlockBlobURL creates a BlockBlobURL using the source's URL and pipeline. +func (b BlobURL) ToBlockBlobURL() BlockBlobURL { + return NewBlockBlobURL(b.URL(), b.blobClient.Pipeline()) +} + +// ToPageBlobURL creates a PageBlobURL using the source's URL and pipeline. +func (b BlobURL) ToPageBlobURL() PageBlobURL { + return NewPageBlobURL(b.URL(), b.blobClient.Pipeline()) +} + +// DownloadBlob reads a range of bytes from a blob. The response also includes the blob's properties and metadata. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/get-blob. +func (b BlobURL) Download(ctx context.Context, offset int64, count int64, ac BlobAccessConditions, rangeGetContentMD5 bool) (*DownloadResponse, error) { + var xRangeGetContentMD5 *bool + if rangeGetContentMD5 { + xRangeGetContentMD5 = &rangeGetContentMD5 + } + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.HTTPAccessConditions.pointers() + dr, err := b.blobClient.Download(ctx, nil, nil, + httpRange{offset: offset, count: count}.pointers(), + ac.LeaseAccessConditions.pointers(), xRangeGetContentMD5, + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) + if err != nil { + return nil, err + } + return &DownloadResponse{ + b: b, + r: dr, + ctx: ctx, + getInfo: HTTPGetterInfo{Offset: offset, Count: count, ETag: dr.ETag()}, + }, err +} + +// DeleteBlob marks the specified blob or snapshot for deletion. The blob is later deleted during garbage collection. +// Note that deleting a blob also deletes all its snapshots. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/delete-blob. +func (b BlobURL) Delete(ctx context.Context, deleteOptions DeleteSnapshotsOptionType, ac BlobAccessConditions) (*BlobDeleteResponse, error) { + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.HTTPAccessConditions.pointers() + return b.blobClient.Delete(ctx, nil, nil, ac.LeaseAccessConditions.pointers(), deleteOptions, + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) +} + +// Undelete restores the contents and metadata of a soft-deleted blob and any associated soft-deleted snapshots. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/undelete-blob. +func (b BlobURL) Undelete(ctx context.Context) (*BlobUndeleteResponse, error) { + return b.blobClient.Undelete(ctx, nil, nil) +} + +// SetTier operation sets the tier on a blob. The operation is allowed on a page +// blob in a premium storage account and on a block blob in a blob storage account (locally +// redundant storage only). A premium page blob's tier determines the allowed size, IOPS, and +// bandwidth of the blob. A block blob's tier determines Hot/Cool/Archive storage type. This operation +// does not update the blob's ETag. +// For detailed information about block blob level tiering see https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-storage-tiers. +func (b BlobURL) SetTier(ctx context.Context, tier AccessTierType) (*BlobSetTierResponse, error) { + return b.blobClient.SetTier(ctx, tier, nil, nil) +} + +// GetBlobProperties returns the blob's properties. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/get-blob-properties. +func (b BlobURL) GetProperties(ctx context.Context, ac BlobAccessConditions) (*BlobGetPropertiesResponse, error) { + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.HTTPAccessConditions.pointers() + return b.blobClient.GetProperties(ctx, nil, nil, ac.LeaseAccessConditions.pointers(), + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) +} + +// SetBlobHTTPHeaders changes a blob's HTTP headers. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/set-blob-properties. +func (b BlobURL) SetHTTPHeaders(ctx context.Context, h BlobHTTPHeaders, ac BlobAccessConditions) (*BlobSetHTTPHeadersResponse, error) { + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.HTTPAccessConditions.pointers() + return b.blobClient.SetHTTPHeaders(ctx, nil, + &h.CacheControl, &h.ContentType, h.ContentMD5, &h.ContentEncoding, &h.ContentLanguage, + ac.LeaseAccessConditions.pointers(), ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, + &h.ContentDisposition, nil) +} + +// SetBlobMetadata changes a blob's metadata. +// https://docs.microsoft.com/rest/api/storageservices/set-blob-metadata. +func (b BlobURL) SetMetadata(ctx context.Context, metadata Metadata, ac BlobAccessConditions) (*BlobSetMetadataResponse, error) { + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.HTTPAccessConditions.pointers() + return b.blobClient.SetMetadata(ctx, nil, metadata, ac.LeaseAccessConditions.pointers(), + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) +} + +// CreateSnapshot creates a read-only snapshot of a blob. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/snapshot-blob. +func (b BlobURL) CreateSnapshot(ctx context.Context, metadata Metadata, ac BlobAccessConditions) (*BlobCreateSnapshotResponse, error) { + // CreateSnapshot does NOT panic if the user tries to create a snapshot using a URL that already has a snapshot query parameter + // because checking this would be a performance hit for a VERY unusual path and I don't think the common case should suffer this + // performance hit. + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.HTTPAccessConditions.pointers() + return b.blobClient.CreateSnapshot(ctx, nil, metadata, ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, ac.LeaseAccessConditions.pointers(), nil) +} + +// AcquireLease acquires a lease on the blob for write and delete operations. The lease duration must be between +// 15 to 60 seconds, or infinite (-1). +// For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-blob. +func (b BlobURL) AcquireLease(ctx context.Context, proposedID string, duration int32, ac HTTPAccessConditions) (*BlobAcquireLeaseResponse, error) { + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.pointers() + return b.blobClient.AcquireLease(ctx, nil, &duration, &proposedID, + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) +} + +// RenewLease renews the blob's previously-acquired lease. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-blob. +func (b BlobURL) RenewLease(ctx context.Context, leaseID string, ac HTTPAccessConditions) (*BlobRenewLeaseResponse, error) { + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.pointers() + return b.blobClient.RenewLease(ctx, leaseID, nil, + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) +} + +// ReleaseLease releases the blob's previously-acquired lease. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-blob. +func (b BlobURL) ReleaseLease(ctx context.Context, leaseID string, ac HTTPAccessConditions) (*BlobReleaseLeaseResponse, error) { + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.pointers() + return b.blobClient.ReleaseLease(ctx, leaseID, nil, + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) +} + +// BreakLease breaks the blob's previously-acquired lease (if it exists). Pass the LeaseBreakDefault (-1) +// constant to break a fixed-duration lease when it expires or an infinite lease immediately. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-blob. +func (b BlobURL) BreakLease(ctx context.Context, breakPeriodInSeconds int32, ac HTTPAccessConditions) (*BlobBreakLeaseResponse, error) { + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.pointers() + return b.blobClient.BreakLease(ctx, nil, leasePeriodPointer(breakPeriodInSeconds), + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) +} + +// ChangeLease changes the blob's lease ID. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-blob. +func (b BlobURL) ChangeLease(ctx context.Context, leaseID string, proposedID string, ac HTTPAccessConditions) (*BlobChangeLeaseResponse, error) { + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.pointers() + return b.blobClient.ChangeLease(ctx, leaseID, proposedID, + nil, ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) +} + +// LeaseBreakNaturally tells ContainerURL's or BlobURL's BreakLease method to break the lease using service semantics. +const LeaseBreakNaturally = -1 + +func leasePeriodPointer(period int32) (p *int32) { + if period != LeaseBreakNaturally { + p = &period + } + return nil +} + +// StartCopyFromURL copies the data at the source URL to a blob. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/copy-blob. +func (b BlobURL) StartCopyFromURL(ctx context.Context, source url.URL, metadata Metadata, srcac BlobAccessConditions, dstac BlobAccessConditions) (*BlobStartCopyFromURLResponse, error) { + srcIfModifiedSince, srcIfUnmodifiedSince, srcIfMatchETag, srcIfNoneMatchETag := srcac.HTTPAccessConditions.pointers() + dstIfModifiedSince, dstIfUnmodifiedSince, dstIfMatchETag, dstIfNoneMatchETag := dstac.HTTPAccessConditions.pointers() + srcLeaseID := srcac.LeaseAccessConditions.pointers() + dstLeaseID := dstac.LeaseAccessConditions.pointers() + + return b.blobClient.StartCopyFromURL(ctx, source.String(), nil, metadata, + srcIfModifiedSince, srcIfUnmodifiedSince, + srcIfMatchETag, srcIfNoneMatchETag, + dstIfModifiedSince, dstIfUnmodifiedSince, + dstIfMatchETag, dstIfNoneMatchETag, + dstLeaseID, srcLeaseID, nil) +} + +// AbortCopyFromURL stops a pending copy that was previously started and leaves a destination blob with 0 length and metadata. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/abort-copy-blob. +func (b BlobURL) AbortCopyFromURL(ctx context.Context, copyID string, ac LeaseAccessConditions) (*BlobAbortCopyFromURLResponse, error) { + return b.blobClient.AbortCopyFromURL(ctx, copyID, nil, ac.pointers(), nil) +} diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/url_block_blob.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/url_block_blob.go new file mode 100644 index 0000000000..ec70285587 --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/url_block_blob.go @@ -0,0 +1,157 @@ +package azblob + +import ( + "context" + "io" + "net/url" + + "encoding/base64" + "encoding/binary" + + "github.com/Azure/azure-pipeline-go/pipeline" +) + +const ( + // BlockBlobMaxPutBlobBytes indicates the maximum number of bytes that can be sent in a call to Upload. + BlockBlobMaxUploadBlobBytes = 256 * 1024 * 1024 // 256MB + + // BlockBlobMaxStageBlockBytes indicates the maximum number of bytes that can be sent in a call to StageBlock. + BlockBlobMaxStageBlockBytes = 100 * 1024 * 1024 // 100MB + + // BlockBlobMaxBlocks indicates the maximum number of blocks allowed in a block blob. + BlockBlobMaxBlocks = 50000 +) + +// BlockBlobURL defines a set of operations applicable to block blobs. +type BlockBlobURL struct { + BlobURL + bbClient blockBlobClient +} + +// NewBlockBlobURL creates a BlockBlobURL object using the specified URL and request policy pipeline. +func NewBlockBlobURL(url url.URL, p pipeline.Pipeline) BlockBlobURL { + if p == nil { + panic("p can't be nil") + } + blobClient := newBlobClient(url, p) + bbClient := newBlockBlobClient(url, p) + return BlockBlobURL{BlobURL: BlobURL{blobClient: blobClient}, bbClient: bbClient} +} + +// WithPipeline creates a new BlockBlobURL object identical to the source but with the specific request policy pipeline. +func (bb BlockBlobURL) WithPipeline(p pipeline.Pipeline) BlockBlobURL { + return NewBlockBlobURL(bb.blobClient.URL(), p) +} + +// WithSnapshot creates a new BlockBlobURL object identical to the source but with the specified snapshot timestamp. +// Pass "" to remove the snapshot returning a URL to the base blob. +func (bb BlockBlobURL) WithSnapshot(snapshot string) BlockBlobURL { + p := NewBlobURLParts(bb.URL()) + p.Snapshot = snapshot + return NewBlockBlobURL(p.URL(), bb.blobClient.Pipeline()) +} + +// Upload creates a new block blob or overwrites an existing block blob. +// Updating an existing block blob overwrites any existing metadata on the blob. Partial updates are not +// supported with Upload; the content of the existing blob is overwritten with the new content. To +// perform a partial update of a block blob, use StageBlock and CommitBlockList. +// This method panics if the stream is not at position 0. +// Note that the http client closes the body stream after the request is sent to the service. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob. +func (bb BlockBlobURL) Upload(ctx context.Context, body io.ReadSeeker, h BlobHTTPHeaders, metadata Metadata, ac BlobAccessConditions) (*BlockBlobUploadResponse, error) { + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.HTTPAccessConditions.pointers() + return bb.bbClient.Upload(ctx, body, validateSeekableStreamAt0AndGetCount(body), nil, + &h.ContentType, &h.ContentEncoding, &h.ContentLanguage, h.ContentMD5, + &h.CacheControl, metadata, ac.LeaseAccessConditions.pointers(), + &h.ContentDisposition, ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, + nil) +} + +// StageBlock uploads the specified block to the block blob's "staging area" to be later committed by a call to CommitBlockList. +// Note that the http client closes the body stream after the request is sent to the service. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-block. +func (bb BlockBlobURL) StageBlock(ctx context.Context, base64BlockID string, body io.ReadSeeker, ac LeaseAccessConditions) (*BlockBlobStageBlockResponse, error) { + return bb.bbClient.StageBlock(ctx, base64BlockID, validateSeekableStreamAt0AndGetCount(body), body, nil, ac.pointers(), nil) +} + +// StageBlockFromURL copies the specified block from a source URL to the block blob's "staging area" to be later committed by a call to CommitBlockList. +// If count is CountToEnd (0), then data is read from specified offset to the end. +// For more information, see https://docs.microsoft.com/en-us/rest/api/storageservices/put-block-from-url. +func (bb BlockBlobURL) StageBlockFromURL(ctx context.Context, base64BlockID string, sourceURL url.URL, offset int64, count int64, ac LeaseAccessConditions) (*BlockBlobStageBlockFromURLResponse, error) { + sourceURLStr := sourceURL.String() + return bb.bbClient.StageBlockFromURL(ctx, base64BlockID, 0, &sourceURLStr, httpRange{offset: offset, count: count}.pointers(), nil, nil, ac.pointers(), nil) +} + +// CommitBlockList writes a blob by specifying the list of block IDs that make up the blob. +// In order to be written as part of a blob, a block must have been successfully written +// to the server in a prior PutBlock operation. You can call PutBlockList to update a blob +// by uploading only those blocks that have changed, then committing the new and existing +// blocks together. Any blocks not specified in the block list and permanently deleted. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-block-list. +func (bb BlockBlobURL) CommitBlockList(ctx context.Context, base64BlockIDs []string, h BlobHTTPHeaders, + metadata Metadata, ac BlobAccessConditions) (*BlockBlobCommitBlockListResponse, error) { + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.HTTPAccessConditions.pointers() + return bb.bbClient.CommitBlockList(ctx, BlockLookupList{Latest: base64BlockIDs}, nil, + &h.CacheControl, &h.ContentType, &h.ContentEncoding, &h.ContentLanguage, h.ContentMD5, + metadata, ac.LeaseAccessConditions.pointers(), &h.ContentDisposition, + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) +} + +// GetBlockList returns the list of blocks that have been uploaded as part of a block blob using the specified block list filter. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/get-block-list. +func (bb BlockBlobURL) GetBlockList(ctx context.Context, listType BlockListType, ac LeaseAccessConditions) (*BlockList, error) { + return bb.bbClient.GetBlockList(ctx, listType, nil, nil, ac.pointers(), nil) +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +type BlockID [64]byte + +func (blockID BlockID) ToBase64() string { + return base64.StdEncoding.EncodeToString(blockID[:]) +} + +func (blockID *BlockID) FromBase64(s string) error { + *blockID = BlockID{} // Zero out the block ID + _, err := base64.StdEncoding.Decode(blockID[:], ([]byte)(s)) + return err +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +type uuidBlockID BlockID + +func (ubi uuidBlockID) UUID() uuid { + u := uuid{} + copy(u[:], ubi[:len(u)]) + return u +} + +func (ubi uuidBlockID) Number() uint32 { + return binary.BigEndian.Uint32(ubi[len(uuid{}):]) +} + +func newUuidBlockID(u uuid) uuidBlockID { + ubi := uuidBlockID{} // Create a new uuidBlockID + copy(ubi[:len(u)], u[:]) // Copy the specified UUID into it + // Block number defaults to 0 + return ubi +} + +func (ubi *uuidBlockID) SetUUID(u uuid) *uuidBlockID { + copy(ubi[:len(u)], u[:]) + return ubi +} + +func (ubi uuidBlockID) WithBlockNumber(blockNumber uint32) uuidBlockID { + binary.BigEndian.PutUint32(ubi[len(uuid{}):], blockNumber) // Put block number after UUID + return ubi // Return the passed-in copy +} + +func (ubi uuidBlockID) ToBase64() string { + return BlockID(ubi).ToBase64() +} + +func (ubi *uuidBlockID) FromBase64(s string) error { + return (*BlockID)(ubi).FromBase64(s) +} diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/url_container.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/url_container.go new file mode 100644 index 0000000000..0fad9f0767 --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/url_container.go @@ -0,0 +1,300 @@ +package azblob + +import ( + "bytes" + "context" + "fmt" + "net/url" + + "github.com/Azure/azure-pipeline-go/pipeline" +) + +// A ContainerURL represents a URL to the Azure Storage container allowing you to manipulate its blobs. +type ContainerURL struct { + client containerClient +} + +// NewContainerURL creates a ContainerURL object using the specified URL and request policy pipeline. +func NewContainerURL(url url.URL, p pipeline.Pipeline) ContainerURL { + if p == nil { + panic("p can't be nil") + } + client := newContainerClient(url, p) + return ContainerURL{client: client} +} + +// URL returns the URL endpoint used by the ContainerURL object. +func (c ContainerURL) URL() url.URL { + return c.client.URL() +} + +// String returns the URL as a string. +func (c ContainerURL) String() string { + u := c.URL() + return u.String() +} + +// WithPipeline creates a new ContainerURL object identical to the source but with the specified request policy pipeline. +func (c ContainerURL) WithPipeline(p pipeline.Pipeline) ContainerURL { + return NewContainerURL(c.URL(), p) +} + +// NewBlobURL creates a new BlobURL object by concatenating blobName to the end of +// ContainerURL's URL. The new BlobURL uses the same request policy pipeline as the ContainerURL. +// To change the pipeline, create the BlobURL and then call its WithPipeline method passing in the +// desired pipeline object. Or, call this package's NewBlobURL instead of calling this object's +// NewBlobURL method. +func (c ContainerURL) NewBlobURL(blobName string) BlobURL { + blobURL := appendToURLPath(c.URL(), blobName) + return NewBlobURL(blobURL, c.client.Pipeline()) +} + +// NewAppendBlobURL creates a new AppendBlobURL object by concatenating blobName to the end of +// ContainerURL's URL. The new AppendBlobURL uses the same request policy pipeline as the ContainerURL. +// To change the pipeline, create the AppendBlobURL and then call its WithPipeline method passing in the +// desired pipeline object. Or, call this package's NewAppendBlobURL instead of calling this object's +// NewAppendBlobURL method. +func (c ContainerURL) NewAppendBlobURL(blobName string) AppendBlobURL { + blobURL := appendToURLPath(c.URL(), blobName) + return NewAppendBlobURL(blobURL, c.client.Pipeline()) +} + +// NewBlockBlobURL creates a new BlockBlobURL object by concatenating blobName to the end of +// ContainerURL's URL. The new BlockBlobURL uses the same request policy pipeline as the ContainerURL. +// To change the pipeline, create the BlockBlobURL and then call its WithPipeline method passing in the +// desired pipeline object. Or, call this package's NewBlockBlobURL instead of calling this object's +// NewBlockBlobURL method. +func (c ContainerURL) NewBlockBlobURL(blobName string) BlockBlobURL { + blobURL := appendToURLPath(c.URL(), blobName) + return NewBlockBlobURL(blobURL, c.client.Pipeline()) +} + +// NewPageBlobURL creates a new PageBlobURL object by concatenating blobName to the end of +// ContainerURL's URL. The new PageBlobURL uses the same request policy pipeline as the ContainerURL. +// To change the pipeline, create the PageBlobURL and then call its WithPipeline method passing in the +// desired pipeline object. Or, call this package's NewPageBlobURL instead of calling this object's +// NewPageBlobURL method. +func (c ContainerURL) NewPageBlobURL(blobName string) PageBlobURL { + blobURL := appendToURLPath(c.URL(), blobName) + return NewPageBlobURL(blobURL, c.client.Pipeline()) +} + +// Create creates a new container within a storage account. If a container with the same name already exists, the operation fails. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/create-container. +func (c ContainerURL) Create(ctx context.Context, metadata Metadata, publicAccessType PublicAccessType) (*ContainerCreateResponse, error) { + return c.client.Create(ctx, nil, metadata, publicAccessType, nil) +} + +// Delete marks the specified container for deletion. The container and any blobs contained within it are later deleted during garbage collection. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/delete-container. +func (c ContainerURL) Delete(ctx context.Context, ac ContainerAccessConditions) (*ContainerDeleteResponse, error) { + if ac.IfMatch != ETagNone || ac.IfNoneMatch != ETagNone { + panic("the IfMatch and IfNoneMatch access conditions must have their default values because they are ignored by the service") + } + + ifModifiedSince, ifUnmodifiedSince, _, _ := ac.HTTPAccessConditions.pointers() + return c.client.Delete(ctx, nil, ac.LeaseAccessConditions.pointers(), + ifModifiedSince, ifUnmodifiedSince, nil) +} + +// GetProperties returns the container's properties. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/get-container-metadata. +func (c ContainerURL) GetProperties(ctx context.Context, ac LeaseAccessConditions) (*ContainerGetPropertiesResponse, error) { + // NOTE: GetMetadata actually calls GetProperties internally because GetProperties returns the metadata AND the properties. + // This allows us to not expose a GetProperties method at all simplifying the API. + return c.client.GetProperties(ctx, nil, ac.pointers(), nil) +} + +// SetMetadata sets the container's metadata. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/set-container-metadata. +func (c ContainerURL) SetMetadata(ctx context.Context, metadata Metadata, ac ContainerAccessConditions) (*ContainerSetMetadataResponse, error) { + if !ac.IfUnmodifiedSince.IsZero() || ac.IfMatch != ETagNone || ac.IfNoneMatch != ETagNone { + panic("the IfUnmodifiedSince, IfMatch, and IfNoneMatch must have their default values because they are ignored by the blob service") + } + ifModifiedSince, _, _, _ := ac.HTTPAccessConditions.pointers() + return c.client.SetMetadata(ctx, nil, ac.LeaseAccessConditions.pointers(), metadata, ifModifiedSince, nil) +} + +// GetAccessPolicy returns the container's access policy. The access policy indicates whether container's blobs may be accessed publicly. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/get-container-acl. +func (c ContainerURL) GetAccessPolicy(ctx context.Context, ac LeaseAccessConditions) (*SignedIdentifiers, error) { + return c.client.GetAccessPolicy(ctx, nil, ac.pointers(), nil) +} + +// The AccessPolicyPermission type simplifies creating the permissions string for a container's access policy. +// Initialize an instance of this type and then call its String method to set AccessPolicy's Permission field. +type AccessPolicyPermission struct { + Read, Add, Create, Write, Delete, List bool +} + +// String produces the access policy permission string for an Azure Storage container. +// Call this method to set AccessPolicy's Permission field. +func (p AccessPolicyPermission) String() string { + var b bytes.Buffer + if p.Read { + b.WriteRune('r') + } + if p.Add { + b.WriteRune('a') + } + if p.Create { + b.WriteRune('c') + } + if p.Write { + b.WriteRune('w') + } + if p.Delete { + b.WriteRune('d') + } + if p.List { + b.WriteRune('l') + } + return b.String() +} + +// Parse initializes the AccessPolicyPermission's fields from a string. +func (p *AccessPolicyPermission) Parse(s string) error { + *p = AccessPolicyPermission{} // Clear the flags + for _, r := range s { + switch r { + case 'r': + p.Read = true + case 'a': + p.Add = true + case 'c': + p.Create = true + case 'w': + p.Write = true + case 'd': + p.Delete = true + case 'l': + p.List = true + default: + return fmt.Errorf("invalid permission: '%v'", r) + } + } + return nil +} + +// SetAccessPolicy sets the container's permissions. The access policy indicates whether blobs in a container may be accessed publicly. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/set-container-acl. +func (c ContainerURL) SetAccessPolicy(ctx context.Context, accessType PublicAccessType, si []SignedIdentifier, + ac ContainerAccessConditions) (*ContainerSetAccessPolicyResponse, error) { + if ac.IfMatch != ETagNone || ac.IfNoneMatch != ETagNone { + panic("the IfMatch and IfNoneMatch access conditions must have their default values because they are ignored by the service") + } + ifModifiedSince, ifUnmodifiedSince, _, _ := ac.HTTPAccessConditions.pointers() + return c.client.SetAccessPolicy(ctx, si, nil, ac.LeaseAccessConditions.pointers(), + accessType, ifModifiedSince, ifUnmodifiedSince, nil) +} + +// AcquireLease acquires a lease on the container for delete operations. The lease duration must be between 15 to 60 seconds, or infinite (-1). +// For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-container. +func (c ContainerURL) AcquireLease(ctx context.Context, proposedID string, duration int32, ac HTTPAccessConditions) (*ContainerAcquireLeaseResponse, error) { + ifModifiedSince, ifUnmodifiedSince, _, _ := ac.pointers() + return c.client.AcquireLease(ctx, nil, &duration, &proposedID, + ifModifiedSince, ifUnmodifiedSince, nil) +} + +// RenewLease renews the container's previously-acquired lease. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-container. +func (c ContainerURL) RenewLease(ctx context.Context, leaseID string, ac HTTPAccessConditions) (*ContainerRenewLeaseResponse, error) { + ifModifiedSince, ifUnmodifiedSince, _, _ := ac.pointers() + return c.client.RenewLease(ctx, leaseID, nil, ifModifiedSince, ifUnmodifiedSince, nil) +} + +// ReleaseLease releases the container's previously-acquired lease. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-container. +func (c ContainerURL) ReleaseLease(ctx context.Context, leaseID string, ac HTTPAccessConditions) (*ContainerReleaseLeaseResponse, error) { + ifModifiedSince, ifUnmodifiedSince, _, _ := ac.pointers() + return c.client.ReleaseLease(ctx, leaseID, nil, ifModifiedSince, ifUnmodifiedSince, nil) +} + +// BreakLease breaks the container's previously-acquired lease (if it exists). +// For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-container. +func (c ContainerURL) BreakLease(ctx context.Context, period int32, ac HTTPAccessConditions) (*ContainerBreakLeaseResponse, error) { + ifModifiedSince, ifUnmodifiedSince, _, _ := ac.pointers() + return c.client.BreakLease(ctx, nil, leasePeriodPointer(period), ifModifiedSince, ifUnmodifiedSince, nil) +} + +// ChangeLease changes the container's lease ID. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-container. +func (c ContainerURL) ChangeLease(ctx context.Context, leaseID string, proposedID string, ac HTTPAccessConditions) (*ContainerChangeLeaseResponse, error) { + ifModifiedSince, ifUnmodifiedSince, _, _ := ac.pointers() + return c.client.ChangeLease(ctx, leaseID, proposedID, nil, ifModifiedSince, ifUnmodifiedSince, nil) +} + +// ListBlobsFlatSegment returns a single segment of blobs starting from the specified Marker. Use an empty +// Marker to start enumeration from the beginning. Blob names are returned in lexicographic order. +// After getting a segment, process it, and then call ListBlobsFlatSegment again (passing the the +// previously-returned Marker) to get the next segment. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/list-blobs. +func (c ContainerURL) ListBlobsFlatSegment(ctx context.Context, marker Marker, o ListBlobsSegmentOptions) (*ListBlobsFlatSegmentResponse, error) { + prefix, include, maxResults := o.pointers() + return c.client.ListBlobFlatSegment(ctx, prefix, marker.val, maxResults, include, nil, nil) +} + +// ListBlobsHierarchySegment returns a single segment of blobs starting from the specified Marker. Use an empty +// Marker to start enumeration from the beginning. Blob names are returned in lexicographic order. +// After getting a segment, process it, and then call ListBlobsHierarchicalSegment again (passing the the +// previously-returned Marker) to get the next segment. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/list-blobs. +func (c ContainerURL) ListBlobsHierarchySegment(ctx context.Context, marker Marker, delimiter string, o ListBlobsSegmentOptions) (*ListBlobsHierarchySegmentResponse, error) { + if o.Details.Snapshots { + panic("snapshots are not supported in this listing operation") + } + prefix, include, maxResults := o.pointers() + return c.client.ListBlobHierarchySegment(ctx, delimiter, prefix, marker.val, maxResults, include, nil, nil) +} + +// ListBlobsSegmentOptions defines options available when calling ListBlobs. +type ListBlobsSegmentOptions struct { + Details BlobListingDetails // No IncludeType header is produced if "" + Prefix string // No Prefix header is produced if "" + + // SetMaxResults sets the maximum desired results you want the service to return. Note, the + // service may return fewer results than requested. + // MaxResults=0 means no 'MaxResults' header specified. + MaxResults int32 +} + +func (o *ListBlobsSegmentOptions) pointers() (prefix *string, include []ListBlobsIncludeItemType, maxResults *int32) { + if o.Prefix != "" { + prefix = &o.Prefix + } + include = o.Details.slice() + if o.MaxResults != 0 { + if o.MaxResults < 0 { + panic("MaxResults must be >= 0") + } + maxResults = &o.MaxResults + } + return +} + +// BlobListingDetails indicates what additional information the service should return with each blob. +type BlobListingDetails struct { + Copy, Metadata, Snapshots, UncommittedBlobs, Deleted bool +} + +// string produces the Include query parameter's value. +func (d *BlobListingDetails) slice() []ListBlobsIncludeItemType { + items := []ListBlobsIncludeItemType{} + // NOTE: Multiple strings MUST be appended in alphabetic order or signing the string for authentication fails! + if d.Copy { + items = append(items, ListBlobsIncludeItemCopy) + } + if d.Deleted { + items = append(items, ListBlobsIncludeItemDeleted) + } + if d.Metadata { + items = append(items, ListBlobsIncludeItemMetadata) + } + if d.Snapshots { + items = append(items, ListBlobsIncludeItemSnapshots) + } + if d.UncommittedBlobs { + items = append(items, ListBlobsIncludeItemUncommittedblobs) + } + return items +} diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/url_page_blob.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/url_page_blob.go new file mode 100644 index 0000000000..fa87ef8527 --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/url_page_blob.go @@ -0,0 +1,236 @@ +package azblob + +import ( + "context" + "fmt" + "io" + "net/url" + "strconv" + + "github.com/Azure/azure-pipeline-go/pipeline" +) + +const ( + // PageBlobPageBytes indicates the number of bytes in a page (512). + PageBlobPageBytes = 512 + + // PageBlobMaxPutPagesBytes indicates the maximum number of bytes that can be sent in a call to PutPage. + PageBlobMaxUploadPagesBytes = 4 * 1024 * 1024 // 4MB +) + +// PageBlobURL defines a set of operations applicable to page blobs. +type PageBlobURL struct { + BlobURL + pbClient pageBlobClient +} + +// NewPageBlobURL creates a PageBlobURL object using the specified URL and request policy pipeline. +func NewPageBlobURL(url url.URL, p pipeline.Pipeline) PageBlobURL { + if p == nil { + panic("p can't be nil") + } + blobClient := newBlobClient(url, p) + pbClient := newPageBlobClient(url, p) + return PageBlobURL{BlobURL: BlobURL{blobClient: blobClient}, pbClient: pbClient} +} + +// WithPipeline creates a new PageBlobURL object identical to the source but with the specific request policy pipeline. +func (pb PageBlobURL) WithPipeline(p pipeline.Pipeline) PageBlobURL { + return NewPageBlobURL(pb.blobClient.URL(), p) +} + +// WithSnapshot creates a new PageBlobURL object identical to the source but with the specified snapshot timestamp. +// Pass "" to remove the snapshot returning a URL to the base blob. +func (pb PageBlobURL) WithSnapshot(snapshot string) PageBlobURL { + p := NewBlobURLParts(pb.URL()) + p.Snapshot = snapshot + return NewPageBlobURL(p.URL(), pb.blobClient.Pipeline()) +} + +// CreatePageBlob creates a page blob of the specified length. Call PutPage to upload data data to a page blob. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob. +func (pb PageBlobURL) Create(ctx context.Context, size int64, sequenceNumber int64, h BlobHTTPHeaders, metadata Metadata, ac BlobAccessConditions) (*PageBlobCreateResponse, error) { + if sequenceNumber < 0 { + panic("sequenceNumber must be greater than or equal to 0") + } + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.HTTPAccessConditions.pointers() + return pb.pbClient.Create(ctx, 0, nil, + &h.ContentType, &h.ContentEncoding, &h.ContentLanguage, h.ContentMD5, &h.CacheControl, + metadata, ac.LeaseAccessConditions.pointers(), + &h.ContentDisposition, ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, &size, &sequenceNumber, nil) +} + +// UploadPages writes 1 or more pages to the page blob. The start offset and the stream size must be a multiple of 512 bytes. +// This method panics if the stream is not at position 0. +// Note that the http client closes the body stream after the request is sent to the service. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-page. +func (pb PageBlobURL) UploadPages(ctx context.Context, offset int64, body io.ReadSeeker, ac BlobAccessConditions) (*PageBlobUploadPagesResponse, error) { + count := validateSeekableStreamAt0AndGetCount(body) + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.HTTPAccessConditions.pointers() + ifSequenceNumberLessThanOrEqual, ifSequenceNumberLessThan, ifSequenceNumberEqual := ac.PageBlobAccessConditions.pointers() + return pb.pbClient.UploadPages(ctx, body, count, nil, + PageRange{Start: offset, End: offset + count - 1}.pointers(), + ac.LeaseAccessConditions.pointers(), + ifSequenceNumberLessThanOrEqual, ifSequenceNumberLessThan, ifSequenceNumberEqual, + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) +} + +// ClearPages frees the specified pages from the page blob. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-page. +func (pb PageBlobURL) ClearPages(ctx context.Context, offset int64, count int64, ac BlobAccessConditions) (*PageBlobClearPagesResponse, error) { + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.HTTPAccessConditions.pointers() + ifSequenceNumberLessThanOrEqual, ifSequenceNumberLessThan, ifSequenceNumberEqual := ac.PageBlobAccessConditions.pointers() + return pb.pbClient.ClearPages(ctx, 0, nil, + PageRange{Start: offset, End: offset + count - 1}.pointers(), + ac.LeaseAccessConditions.pointers(), + ifSequenceNumberLessThanOrEqual, ifSequenceNumberLessThan, + ifSequenceNumberEqual, ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) +} + +// GetPageRanges returns the list of valid page ranges for a page blob or snapshot of a page blob. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/get-page-ranges. +func (pb PageBlobURL) GetPageRanges(ctx context.Context, offset int64, count int64, ac BlobAccessConditions) (*PageList, error) { + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.HTTPAccessConditions.pointers() + return pb.pbClient.GetPageRanges(ctx, nil, nil, + httpRange{offset: offset, count: count}.pointers(), + ac.LeaseAccessConditions.pointers(), + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) +} + +// GetPageRangesDiff gets the collection of page ranges that differ between a specified snapshot and this page blob. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/get-page-ranges. +func (pb PageBlobURL) GetPageRangesDiff(ctx context.Context, offset int64, count int64, prevSnapshot string, ac BlobAccessConditions) (*PageList, error) { + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.HTTPAccessConditions.pointers() + return pb.pbClient.GetPageRangesDiff(ctx, nil, nil, &prevSnapshot, + httpRange{offset: offset, count: count}.pointers(), + ac.LeaseAccessConditions.pointers(), + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, + nil) +} + +// Resize resizes the page blob to the specified size (which must be a multiple of 512). +// For more information, see https://docs.microsoft.com/rest/api/storageservices/set-blob-properties. +func (pb PageBlobURL) Resize(ctx context.Context, size int64, ac BlobAccessConditions) (*PageBlobResizeResponse, error) { + if size%PageBlobPageBytes != 0 { + panic("Size must be a multiple of PageBlobPageBytes (512)") + } + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.HTTPAccessConditions.pointers() + return pb.pbClient.Resize(ctx, size, nil, ac.LeaseAccessConditions.pointers(), + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) +} + +// SetSequenceNumber sets the page blob's sequence number. +func (pb PageBlobURL) UpdateSequenceNumber(ctx context.Context, action SequenceNumberActionType, sequenceNumber int64, + ac BlobAccessConditions) (*PageBlobUpdateSequenceNumberResponse, error) { + if sequenceNumber < 0 { + panic("sequenceNumber must be greater than or equal to 0") + } + sn := &sequenceNumber + if action == SequenceNumberActionIncrement { + sn = nil + } + ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch := ac.HTTPAccessConditions.pointers() + return pb.pbClient.UpdateSequenceNumber(ctx, action, nil, + ac.LeaseAccessConditions.pointers(), ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, + sn, nil) +} + +// StartIncrementalCopy begins an operation to start an incremental copy from one page blob's snapshot to this page blob. +// The snapshot is copied such that only the differential changes between the previously copied snapshot are transferred to the destination. +// The copied snapshots are complete copies of the original snapshot and can be read or copied from as usual. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/incremental-copy-blob and +// https://docs.microsoft.com/en-us/azure/virtual-machines/windows/incremental-snapshots. +func (pb PageBlobURL) StartCopyIncremental(ctx context.Context, source url.URL, snapshot string, ac BlobAccessConditions) (*PageBlobCopyIncrementalResponse, error) { + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.HTTPAccessConditions.pointers() + qp := source.Query() + qp.Set("snapshot", snapshot) + source.RawQuery = qp.Encode() + return pb.pbClient.CopyIncremental(ctx, source.String(), nil, nil, + ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) +} + +func (pr PageRange) pointers() *string { + if pr.Start < 0 { + panic("PageRange's Start value must be greater than or equal to 0") + } + if pr.End <= 0 { + panic("PageRange's End value must be greater than 0") + } + if pr.Start%PageBlobPageBytes != 0 { + panic("PageRange's Start value must be a multiple of 512") + } + if pr.End%PageBlobPageBytes != (PageBlobPageBytes - 1) { + panic("PageRange's End value must be 1 less than a multiple of 512") + } + if pr.End <= pr.Start { + panic("PageRange's End value must be after the start") + } + endOffset := strconv.FormatInt(int64(pr.End), 10) + asString := fmt.Sprintf("bytes=%v-%s", pr.Start, endOffset) + return &asString +} + +// PageBlobAccessConditions identifies page blob-specific access conditions which you optionally set. +type PageBlobAccessConditions struct { + // IfSequenceNumberLessThan ensures that the page blob operation succeeds + // only if the blob's sequence number is less than a value. + // IfSequenceNumberLessThan=0 means no 'IfSequenceNumberLessThan' header specified. + // IfSequenceNumberLessThan>0 means 'IfSequenceNumberLessThan' header specified with its value + // IfSequenceNumberLessThan==-1 means 'IfSequenceNumberLessThan' header specified with a value of 0 + IfSequenceNumberLessThan int64 + + // IfSequenceNumberLessThanOrEqual ensures that the page blob operation succeeds + // only if the blob's sequence number is less than or equal to a value. + // IfSequenceNumberLessThanOrEqual=0 means no 'IfSequenceNumberLessThanOrEqual' header specified. + // IfSequenceNumberLessThanOrEqual>0 means 'IfSequenceNumberLessThanOrEqual' header specified with its value + // IfSequenceNumberLessThanOrEqual=-1 means 'IfSequenceNumberLessThanOrEqual' header specified with a value of 0 + IfSequenceNumberLessThanOrEqual int64 + + // IfSequenceNumberEqual ensures that the page blob operation succeeds + // only if the blob's sequence number is equal to a value. + // IfSequenceNumberEqual=0 means no 'IfSequenceNumberEqual' header specified. + // IfSequenceNumberEqual>0 means 'IfSequenceNumberEqual' header specified with its value + // IfSequenceNumberEqual=-1 means 'IfSequenceNumberEqual' header specified with a value of 0 + IfSequenceNumberEqual int64 +} + +// pointers is for internal infrastructure. It returns the fields as pointers. +func (ac PageBlobAccessConditions) pointers() (snltoe *int64, snlt *int64, sne *int64) { + if ac.IfSequenceNumberLessThan < -1 { + panic("Ifsequencenumberlessthan can't be less than -1") + } + if ac.IfSequenceNumberLessThanOrEqual < -1 { + panic("IfSequenceNumberLessThanOrEqual can't be less than -1") + } + if ac.IfSequenceNumberEqual < -1 { + panic("IfSequenceNumberEqual can't be less than -1") + } + + var zero int64 // Defaults to 0 + switch ac.IfSequenceNumberLessThan { + case -1: + snlt = &zero + case 0: + snlt = nil + default: + snlt = &ac.IfSequenceNumberLessThan + } + + switch ac.IfSequenceNumberLessThanOrEqual { + case -1: + snltoe = &zero + case 0: + snltoe = nil + default: + snltoe = &ac.IfSequenceNumberLessThanOrEqual + } + switch ac.IfSequenceNumberEqual { + case -1: + sne = &zero + case 0: + sne = nil + default: + sne = &ac.IfSequenceNumberEqual + } + return +} diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/url_service.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/url_service.go new file mode 100644 index 0000000000..d49a20846b --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/url_service.go @@ -0,0 +1,140 @@ +package azblob + +import ( + "context" + "net/url" + "strings" + + "github.com/Azure/azure-pipeline-go/pipeline" +) + +const ( + // ContainerNameRoot is the special Azure Storage name used to identify a storage account's root container. + ContainerNameRoot = "$root" + + // ContainerNameLogs is the special Azure Storage name used to identify a storage account's logs container. + ContainerNameLogs = "$logs" +) + +// A ServiceURL represents a URL to the Azure Storage Blob service allowing you to manipulate blob containers. +type ServiceURL struct { + client serviceClient +} + +// NewServiceURL creates a ServiceURL object using the specified URL and request policy pipeline. +func NewServiceURL(primaryURL url.URL, p pipeline.Pipeline) ServiceURL { + if p == nil { + panic("p can't be nil") + } + client := newServiceClient(primaryURL, p) + return ServiceURL{client: client} +} + +// URL returns the URL endpoint used by the ServiceURL object. +func (s ServiceURL) URL() url.URL { + return s.client.URL() +} + +// String returns the URL as a string. +func (s ServiceURL) String() string { + u := s.URL() + return u.String() +} + +// WithPipeline creates a new ServiceURL object identical to the source but with the specified request policy pipeline. +func (s ServiceURL) WithPipeline(p pipeline.Pipeline) ServiceURL { + return NewServiceURL(s.URL(), p) +} + +// NewContainerURL creates a new ContainerURL object by concatenating containerName to the end of +// ServiceURL's URL. The new ContainerURL uses the same request policy pipeline as the ServiceURL. +// To change the pipeline, create the ContainerURL and then call its WithPipeline method passing in the +// desired pipeline object. Or, call this package's NewContainerURL instead of calling this object's +// NewContainerURL method. +func (s ServiceURL) NewContainerURL(containerName string) ContainerURL { + containerURL := appendToURLPath(s.URL(), containerName) + return NewContainerURL(containerURL, s.client.Pipeline()) +} + +// appendToURLPath appends a string to the end of a URL's path (prefixing the string with a '/' if required) +func appendToURLPath(u url.URL, name string) url.URL { + // e.g. "https://ms.com/a/b/?k1=v1&k2=v2#f" + // When you call url.Parse() this is what you'll get: + // Scheme: "https" + // Opaque: "" + // User: nil + // Host: "ms.com" + // Path: "/a/b/" This should start with a / and it might or might not have a trailing slash + // RawPath: "" + // ForceQuery: false + // RawQuery: "k1=v1&k2=v2" + // Fragment: "f" + if len(u.Path) == 0 || u.Path[len(u.Path)-1] != '/' { + u.Path += "/" // Append "/" to end before appending name + } + u.Path += name + return u +} + +// ListContainersFlatSegment returns a single segment of containers starting from the specified Marker. Use an empty +// Marker to start enumeration from the beginning. Container names are returned in lexicographic order. +// After getting a segment, process it, and then call ListContainersFlatSegment again (passing the the +// previously-returned Marker) to get the next segment. For more information, see +// https://docs.microsoft.com/rest/api/storageservices/list-containers2. +func (s ServiceURL) ListContainersSegment(ctx context.Context, marker Marker, o ListContainersSegmentOptions) (*ListContainersResponse, error) { + prefix, include, maxResults := o.pointers() + return s.client.ListContainersSegment(ctx, prefix, marker.val, maxResults, include, nil, nil) +} + +// ListContainersOptions defines options available when calling ListContainers. +type ListContainersSegmentOptions struct { + Detail ListContainersDetail // No IncludeType header is produced if "" + Prefix string // No Prefix header is produced if "" + MaxResults int32 // 0 means unspecified + // TODO: update swagger to generate this type? +} + +func (o *ListContainersSegmentOptions) pointers() (prefix *string, include ListContainersIncludeType, maxResults *int32) { + if o.Prefix != "" { + prefix = &o.Prefix + } + if o.MaxResults != 0 { + if o.MaxResults < 0 { + panic("MaxResults must be >= 0") + } + maxResults = &o.MaxResults + } + include = ListContainersIncludeType(o.Detail.string()) + return +} + +// ListContainersFlatDetail indicates what additional information the service should return with each container. +type ListContainersDetail struct { + // Tells the service whether to return metadata for each container. + Metadata bool +} + +// string produces the Include query parameter's value. +func (d *ListContainersDetail) string() string { + items := make([]string, 0, 1) + // NOTE: Multiple strings MUST be appended in alphabetic order or signing the string for authentication fails! + if d.Metadata { + items = append(items, string(ListContainersIncludeMetadata)) + } + if len(items) > 0 { + return strings.Join(items, ",") + } + return string(ListContainersIncludeNone) +} + +func (bsu ServiceURL) GetProperties(ctx context.Context) (*StorageServiceProperties, error) { + return bsu.client.GetProperties(ctx, nil, nil) +} + +func (bsu ServiceURL) SetProperties(ctx context.Context, properties StorageServiceProperties) (*ServiceSetPropertiesResponse, error) { + return bsu.client.SetProperties(ctx, properties, nil, nil) +} + +func (bsu ServiceURL) GetStatistics(ctx context.Context) (*StorageServiceStats, error) { + return bsu.client.GetStatistics(ctx, nil, nil) +} diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/version.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/version.go new file mode 100644 index 0000000000..8a8926bd33 --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/version.go @@ -0,0 +1,3 @@ +package azblob + +const serviceLibVersion = "0.1" diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_credential_anonymous.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_credential_anonymous.go new file mode 100644 index 0000000000..a81987d54a --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_credential_anonymous.go @@ -0,0 +1,55 @@ +package azblob + +import ( + "context" + + "github.com/Azure/azure-pipeline-go/pipeline" +) + +// Credential represent any credential type; it is used to create a credential policy Factory. +type Credential interface { + pipeline.Factory + credentialMarker() +} + +type credentialFunc pipeline.FactoryFunc + +func (f credentialFunc) New(next pipeline.Policy, po *pipeline.PolicyOptions) pipeline.Policy { + return f(next, po) +} + +// credentialMarker is a package-internal method that exists just to satisfy the Credential interface. +func (credentialFunc) credentialMarker() {} + +////////////////////////////// + +// NewAnonymousCredential creates an anonymous credential for use with HTTP(S) requests that read public resource +// or for use with Shared Access Signatures (SAS). +func NewAnonymousCredential() Credential { + return anonymousCredentialFactory +} + +var anonymousCredentialFactory Credential = &anonymousCredentialPolicyFactory{} // Singleton + +// anonymousCredentialPolicyFactory is the credential's policy factory. +type anonymousCredentialPolicyFactory struct { +} + +// New creates a credential policy object. +func (f *anonymousCredentialPolicyFactory) New(next pipeline.Policy, po *pipeline.PolicyOptions) pipeline.Policy { + return &anonymousCredentialPolicy{next: next} +} + +// credentialMarker is a package-internal method that exists just to satisfy the Credential interface. +func (*anonymousCredentialPolicyFactory) credentialMarker() {} + +// anonymousCredentialPolicy is the credential's policy object. +type anonymousCredentialPolicy struct { + next pipeline.Policy +} + +// Do implements the credential's policy interface. +func (p anonymousCredentialPolicy) Do(ctx context.Context, request pipeline.Request) (pipeline.Response, error) { + // For anonymous credentials, this is effectively a no-op + return p.next.Do(ctx, request) +} diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_credential_shared_key.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_credential_shared_key.go new file mode 100644 index 0000000000..51da162779 --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_credential_shared_key.go @@ -0,0 +1,187 @@ +package azblob + +import ( + "bytes" + "context" + "crypto/hmac" + "crypto/sha256" + "encoding/base64" + "net/http" + "net/url" + "sort" + "strings" + "time" + + "github.com/Azure/azure-pipeline-go/pipeline" +) + +// NewSharedKeyCredential creates an immutable SharedKeyCredential containing the +// storage account's name and either its primary or secondary key. +func NewSharedKeyCredential(accountName, accountKey string) *SharedKeyCredential { + bytes, err := base64.StdEncoding.DecodeString(accountKey) + if err != nil { + panic(err) + } + return &SharedKeyCredential{accountName: accountName, accountKey: bytes} +} + +// SharedKeyCredential contains an account's name and its primary or secondary key. +// It is immutable making it shareable and goroutine-safe. +type SharedKeyCredential struct { + // Only the NewSharedKeyCredential method should set these; all other methods should treat them as read-only + accountName string + accountKey []byte +} + +// AccountName returns the Storage account's name. +func (f SharedKeyCredential) AccountName() string { + return f.accountName +} + +// New creates a credential policy object. +func (f *SharedKeyCredential) New(next pipeline.Policy, po *pipeline.PolicyOptions) pipeline.Policy { + return pipeline.PolicyFunc(func(ctx context.Context, request pipeline.Request) (pipeline.Response, error) { + // Add a x-ms-date header if it doesn't already exist + if d := request.Header.Get(headerXmsDate); d == "" { + request.Header[headerXmsDate] = []string{time.Now().UTC().Format(http.TimeFormat)} + } + stringToSign := f.buildStringToSign(request) + signature := f.ComputeHMACSHA256(stringToSign) + authHeader := strings.Join([]string{"SharedKey ", f.accountName, ":", signature}, "") + request.Header[headerAuthorization] = []string{authHeader} + + response, err := next.Do(ctx, request) + if err != nil && response != nil && response.Response() != nil && response.Response().StatusCode == http.StatusForbidden { + // Service failed to authenticate request, log it + po.Log(pipeline.LogError, "===== HTTP Forbidden status, String-to-Sign:\n"+stringToSign+"\n===============================\n") + } + return response, err + }) +} + +// credentialMarker is a package-internal method that exists just to satisfy the Credential interface. +func (*SharedKeyCredential) credentialMarker() {} + +// Constants ensuring that header names are correctly spelled and consistently cased. +const ( + headerAuthorization = "Authorization" + headerCacheControl = "Cache-Control" + headerContentEncoding = "Content-Encoding" + headerContentDisposition = "Content-Disposition" + headerContentLanguage = "Content-Language" + headerContentLength = "Content-Length" + headerContentMD5 = "Content-MD5" + headerContentType = "Content-Type" + headerDate = "Date" + headerIfMatch = "If-Match" + headerIfModifiedSince = "If-Modified-Since" + headerIfNoneMatch = "If-None-Match" + headerIfUnmodifiedSince = "If-Unmodified-Since" + headerRange = "Range" + headerUserAgent = "User-Agent" + headerXmsDate = "x-ms-date" + headerXmsVersion = "x-ms-version" +) + +// ComputeHMACSHA256 generates a hash signature for an HTTP request or for a SAS. +func (f *SharedKeyCredential) ComputeHMACSHA256(message string) (base64String string) { + h := hmac.New(sha256.New, f.accountKey) + h.Write([]byte(message)) + return base64.StdEncoding.EncodeToString(h.Sum(nil)) +} + +func (f *SharedKeyCredential) buildStringToSign(request pipeline.Request) string { + // https://docs.microsoft.com/en-us/rest/api/storageservices/authentication-for-the-azure-storage-services + headers := request.Header + contentLength := headers.Get(headerContentLength) + if contentLength == "0" { + contentLength = "" + } + + stringToSign := strings.Join([]string{ + request.Method, + headers.Get(headerContentEncoding), + headers.Get(headerContentLanguage), + contentLength, + headers.Get(headerContentMD5), + headers.Get(headerContentType), + "", // Empty date because x-ms-date is expected (as per web page above) + headers.Get(headerIfModifiedSince), + headers.Get(headerIfMatch), + headers.Get(headerIfNoneMatch), + headers.Get(headerIfUnmodifiedSince), + headers.Get(headerRange), + buildCanonicalizedHeader(headers), + f.buildCanonicalizedResource(request.URL), + }, "\n") + return stringToSign +} + +func buildCanonicalizedHeader(headers http.Header) string { + cm := map[string][]string{} + for k, v := range headers { + headerName := strings.TrimSpace(strings.ToLower(k)) + if strings.HasPrefix(headerName, "x-ms-") { + cm[headerName] = v // NOTE: the value must not have any whitespace around it. + } + } + if len(cm) == 0 { + return "" + } + + keys := make([]string, 0, len(cm)) + for key := range cm { + keys = append(keys, key) + } + sort.Strings(keys) + ch := bytes.NewBufferString("") + for i, key := range keys { + if i > 0 { + ch.WriteRune('\n') + } + ch.WriteString(key) + ch.WriteRune(':') + ch.WriteString(strings.Join(cm[key], ",")) + } + return string(ch.Bytes()) +} + +func (f *SharedKeyCredential) buildCanonicalizedResource(u *url.URL) string { + // https://docs.microsoft.com/en-us/rest/api/storageservices/authentication-for-the-azure-storage-services + cr := bytes.NewBufferString("/") + cr.WriteString(f.accountName) + + if len(u.Path) > 0 { + // Any portion of the CanonicalizedResource string that is derived from + // the resource's URI should be encoded exactly as it is in the URI. + // -- https://msdn.microsoft.com/en-gb/library/azure/dd179428.aspx + cr.WriteString(u.EscapedPath()) + } else { + // a slash is required to indicate the root path + cr.WriteString("/") + } + + // params is a map[string][]string; param name is key; params values is []string + params, err := url.ParseQuery(u.RawQuery) // Returns URL decoded values + if err != nil { + panic(err) + } + + if len(params) > 0 { // There is at least 1 query parameter + paramNames := []string{} // We use this to sort the parameter key names + for paramName := range params { + paramNames = append(paramNames, paramName) // paramNames must be lowercase + } + sort.Strings(paramNames) + + for _, paramName := range paramNames { + paramValues := params[paramName] + sort.Strings(paramValues) + + // Join the sorted key values separated by ',' + // Then prepend "keyName:"; then add this string to the buffer + cr.WriteString("\n" + paramName + ":" + strings.Join(paramValues, ",")) + } + } + return string(cr.Bytes()) +} diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_credential_token.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_credential_token.go new file mode 100644 index 0000000000..d7f925d398 --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_credential_token.go @@ -0,0 +1,126 @@ +package azblob + +import ( + "context" + "sync/atomic" + + "runtime" + "sync" + "time" + + "github.com/Azure/azure-pipeline-go/pipeline" +) + +// TokenCredential represents a token credential (which is also a pipeline.Factory). +type TokenCredential interface { + Credential + Token() string + SetToken(newToken string) +} + +// NewTokenCredential creates a token credential for use with role-based access control (RBAC) access to Azure Storage +// resources. You initialize the TokenCredential with an initial token value. If you pass a non-nil value for +// tokenRefresher, then the function you pass will be called immediately (so it can refresh and change the +// TokenCredential's token value by calling SetToken; your tokenRefresher function must return a time.Duration +// indicating how long the TokenCredential object should wait before calling your tokenRefresher function again. +func NewTokenCredential(initialToken string, tokenRefresher func(credential TokenCredential) time.Duration) TokenCredential { + tc := &tokenCredential{} + tc.SetToken(initialToken) // We dont' set it above to guarantee atomicity + if tokenRefresher == nil { + return tc // If no callback specified, return the simple tokenCredential + } + + tcwr := &tokenCredentialWithRefresh{token: tc} + tcwr.token.startRefresh(tokenRefresher) + runtime.SetFinalizer(tcwr, func(deadTC *tokenCredentialWithRefresh) { + deadTC.token.stopRefresh() + deadTC.token = nil // Sanity (not really required) + }) + return tcwr +} + +// tokenCredentialWithRefresh is a wrapper over a token credential. +// When this wrapper object gets GC'd, it stops the tokenCredential's timer +// which allows the tokenCredential object to also be GC'd. +type tokenCredentialWithRefresh struct { + token *tokenCredential +} + +// credentialMarker is a package-internal method that exists just to satisfy the Credential interface. +func (*tokenCredentialWithRefresh) credentialMarker() {} + +// Token returns the current token value +func (f *tokenCredentialWithRefresh) Token() string { return f.token.Token() } + +// SetToken changes the current token value +func (f *tokenCredentialWithRefresh) SetToken(token string) { f.token.SetToken(token) } + +// New satisfies pipeline.Factory's New method creating a pipeline policy object. +func (f *tokenCredentialWithRefresh) New(next pipeline.Policy, po *pipeline.PolicyOptions) pipeline.Policy { + return f.token.New(next, po) +} + +/////////////////////////////////////////////////////////////////////////////// + +// tokenCredential is a pipeline.Factory is the credential's policy factory. +type tokenCredential struct { + token atomic.Value + + // The members below are only used if the user specified a tokenRefresher callback function. + timer *time.Timer + tokenRefresher func(c TokenCredential) time.Duration + lock sync.Mutex + stopped bool +} + +// credentialMarker is a package-internal method that exists just to satisfy the Credential interface. +func (*tokenCredential) credentialMarker() {} + +// Token returns the current token value +func (f *tokenCredential) Token() string { return f.token.Load().(string) } + +// SetToken changes the current token value +func (f *tokenCredential) SetToken(token string) { f.token.Store(token) } + +// startRefresh calls refresh which immediately calls tokenRefresher +// and then starts a timer to call tokenRefresher in the future. +func (f *tokenCredential) startRefresh(tokenRefresher func(c TokenCredential) time.Duration) { + f.tokenRefresher = tokenRefresher + f.stopped = false // In case user calls StartRefresh, StopRefresh, & then StartRefresh again + f.refresh() +} + +// refresh calls the user's tokenRefresher so they can refresh the token (by +// calling SetToken) and then starts another time (based on the returned duration) +// in order to refresh the token again in the future. +func (f *tokenCredential) refresh() { + d := f.tokenRefresher(f) // Invoke the user's refresh callback outside of the lock + f.lock.Lock() + if !f.stopped { + f.timer = time.AfterFunc(d, f.refresh) + } + f.lock.Unlock() +} + +// stopRefresh stops any pending timer and sets stopped field to true to prevent +// any new timer from starting. +// NOTE: Stopping the timer allows the GC to destroy the tokenCredential object. +func (f *tokenCredential) stopRefresh() { + f.lock.Lock() + f.stopped = true + if f.timer != nil { + f.timer.Stop() + } + f.lock.Unlock() +} + +// New satisfies pipeline.Factory's New method creating a pipeline policy object. +func (f *tokenCredential) New(next pipeline.Policy, po *pipeline.PolicyOptions) pipeline.Policy { + return pipeline.PolicyFunc(func(ctx context.Context, request pipeline.Request) (pipeline.Response, error) { + if request.URL.Scheme != "https" { + panic("Token credentials require a URL using the https protocol scheme.") + } + request.Header[headerAuthorization] = []string{"Bearer " + f.Token()} + return next.Do(ctx, request) + }) +} diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_mmf_unix.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_mmf_unix.go new file mode 100644 index 0000000000..b6c668ac64 --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_mmf_unix.go @@ -0,0 +1,27 @@ +// +build linux darwin freebsd + +package azblob + +import ( + "os" + "syscall" +) + +type mmf []byte + +func newMMF(file *os.File, writable bool, offset int64, length int) (mmf, error) { + prot, flags := syscall.PROT_READ, syscall.MAP_SHARED // Assume read-only + if writable { + prot, flags = syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED + } + addr, err := syscall.Mmap(int(file.Fd()), offset, length, prot, flags) + return mmf(addr), err +} + +func (m *mmf) unmap() { + err := syscall.Munmap(*m) + *m = nil + if err != nil { + panic(err) + } +} diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_mmf_windows.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_mmf_windows.go new file mode 100644 index 0000000000..1a6e83dad9 --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_mmf_windows.go @@ -0,0 +1,38 @@ +package azblob + +import ( + "os" + "reflect" + "syscall" + "unsafe" +) + +type mmf []byte + +func newMMF(file *os.File, writable bool, offset int64, length int) (mmf, error) { + prot, access := uint32(syscall.PAGE_READONLY), uint32(syscall.FILE_MAP_READ) // Assume read-only + if writable { + prot, access = uint32(syscall.PAGE_READWRITE), uint32(syscall.FILE_MAP_WRITE) + } + hMMF, errno := syscall.CreateFileMapping(syscall.Handle(file.Fd()), nil, prot, uint32(int64(length)>>32), uint32(int64(length)&0xffffffff), nil) + if hMMF == 0 { + return nil, os.NewSyscallError("CreateFileMapping", errno) + } + defer syscall.CloseHandle(hMMF) + addr, errno := syscall.MapViewOfFile(hMMF, access, uint32(offset>>32), uint32(offset&0xffffffff), uintptr(length)) + m := mmf{} + h := (*reflect.SliceHeader)(unsafe.Pointer(&m)) + h.Data = addr + h.Len = length + h.Cap = h.Len + return m, nil +} + +func (m *mmf) unmap() { + addr := uintptr(unsafe.Pointer(&(([]byte)(*m)[0]))) + *m = mmf{} + err := syscall.UnmapViewOfFile(addr) + if err != nil { + panic(err) + } +} diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_pipeline.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_pipeline.go new file mode 100644 index 0000000000..af5fcd6c7f --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_pipeline.go @@ -0,0 +1,46 @@ +package azblob + +import ( + "github.com/Azure/azure-pipeline-go/pipeline" +) + +// PipelineOptions is used to configure a request policy pipeline's retry policy and logging. +type PipelineOptions struct { + // Log configures the pipeline's logging infrastructure indicating what information is logged and where. + Log pipeline.LogOptions + + // Retry configures the built-in retry policy behavior. + Retry RetryOptions + + // RequestLog configures the built-in request logging policy. + RequestLog RequestLogOptions + + // Telemetry configures the built-in telemetry policy behavior. + Telemetry TelemetryOptions +} + +// NewPipeline creates a Pipeline using the specified credentials and options. +func NewPipeline(c Credential, o PipelineOptions) pipeline.Pipeline { + if c == nil { + panic("c can't be nil") + } + + // Closest to API goes first; closest to the wire goes last + f := []pipeline.Factory{ + NewTelemetryPolicyFactory(o.Telemetry), + NewUniqueRequestIDPolicyFactory(), + NewRetryPolicyFactory(o.Retry), + } + + if _, ok := c.(*anonymousCredentialPolicyFactory); !ok { + // For AnonymousCredential, we optimize out the policy factory since it doesn't do anything + // NOTE: The credential's policy factory must appear close to the wire so it can sign any + // changes made by other factories (like UniqueRequestIDPolicyFactory) + f = append(f, c) + } + f = append(f, + pipeline.MethodFactoryMarker(), // indicates at what stage in the pipeline the method factory is invoked + NewRequestLogPolicyFactory(o.RequestLog)) + + return pipeline.NewPipeline(f, pipeline.Options{HTTPSender: nil, Log: o.Log}) +} diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_policy_request_log.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_policy_request_log.go new file mode 100644 index 0000000000..23d559eb7c --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_policy_request_log.go @@ -0,0 +1,150 @@ +package azblob + +import ( + "bytes" + "context" + "fmt" + "net/http" + "net/url" + "runtime" + "strings" + "time" + + "github.com/Azure/azure-pipeline-go/pipeline" +) + +// RequestLogOptions configures the retry policy's behavior. +type RequestLogOptions struct { + // LogWarningIfTryOverThreshold logs a warning if a tried operation takes longer than the specified + // duration (-1=no logging; 0=default threshold). + LogWarningIfTryOverThreshold time.Duration +} + +func (o RequestLogOptions) defaults() RequestLogOptions { + if o.LogWarningIfTryOverThreshold == 0 { + // It would be good to relate this to https://azure.microsoft.com/en-us/support/legal/sla/storage/v1_2/ + // But this monitors the time to get the HTTP response; NOT the time to download the response body. + o.LogWarningIfTryOverThreshold = 3 * time.Second // Default to 3 seconds + } + return o +} + +// NewRequestLogPolicyFactory creates a RequestLogPolicyFactory object configured using the specified options. +func NewRequestLogPolicyFactory(o RequestLogOptions) pipeline.Factory { + o = o.defaults() // Force defaults to be calculated + return pipeline.FactoryFunc(func(next pipeline.Policy, po *pipeline.PolicyOptions) pipeline.PolicyFunc { + // These variables are per-policy; shared by multiple calls to Do + var try int32 + operationStart := time.Now() // If this is the 1st try, record the operation state time + return func(ctx context.Context, request pipeline.Request) (response pipeline.Response, err error) { + try++ // The first try is #1 (not #0) + + // Log the outgoing request as informational + if po.ShouldLog(pipeline.LogInfo) { + b := &bytes.Buffer{} + fmt.Fprintf(b, "==> OUTGOING REQUEST (Try=%d)\n", try) + pipeline.WriteRequestWithResponse(b, prepareRequestForLogging(request), nil, nil) + po.Log(pipeline.LogInfo, b.String()) + } + + // Set the time for this particular retry operation and then Do the operation. + tryStart := time.Now() + response, err = next.Do(ctx, request) // Make the request + tryEnd := time.Now() + tryDuration := tryEnd.Sub(tryStart) + opDuration := tryEnd.Sub(operationStart) + + logLevel, forceLog := pipeline.LogInfo, false // Default logging information + + // If the response took too long, we'll upgrade to warning. + if o.LogWarningIfTryOverThreshold > 0 && tryDuration > o.LogWarningIfTryOverThreshold { + // Log a warning if the try duration exceeded the specified threshold + logLevel, forceLog = pipeline.LogWarning, true + } + + if err == nil { // We got a response from the service + sc := response.Response().StatusCode + if ((sc >= 400 && sc <= 499) && sc != http.StatusNotFound && sc != http.StatusConflict && sc != http.StatusPreconditionFailed && sc != http.StatusRequestedRangeNotSatisfiable) || (sc >= 500 && sc <= 599) { + logLevel, forceLog = pipeline.LogError, true // Promote to Error any 4xx (except those listed is an error) or any 5xx + } else { + // For other status codes, we leave the level as is. + } + } else { // This error did not get an HTTP response from the service; upgrade the severity to Error + logLevel, forceLog = pipeline.LogError, true + } + + if shouldLog := po.ShouldLog(logLevel); forceLog || shouldLog { + // We're going to log this; build the string to log + b := &bytes.Buffer{} + slow := "" + if o.LogWarningIfTryOverThreshold > 0 && tryDuration > o.LogWarningIfTryOverThreshold { + slow = fmt.Sprintf("[SLOW >%v]", o.LogWarningIfTryOverThreshold) + } + fmt.Fprintf(b, "==> REQUEST/RESPONSE (Try=%d/%v%s, OpTime=%v) -- ", try, tryDuration, slow, opDuration) + if err != nil { // This HTTP request did not get a response from the service + fmt.Fprint(b, "REQUEST ERROR\n") + } else { + if logLevel == pipeline.LogError { + fmt.Fprint(b, "RESPONSE STATUS CODE ERROR\n") + } else { + fmt.Fprint(b, "RESPONSE SUCCESSFULLY RECEIVED\n") + } + } + + pipeline.WriteRequestWithResponse(b, prepareRequestForLogging(request), response.Response(), err) + if logLevel <= pipeline.LogError { + b.Write(stack()) // For errors (or lower levels), we append the stack trace (an expensive operation) + } + msg := b.String() + + if forceLog { + pipeline.ForceLog(logLevel, msg) + } + if shouldLog { + po.Log(logLevel, msg) + } + } + return response, err + } + }) +} + +func redactSigQueryParam(rawQuery string) (bool, string) { + rawQuery = strings.ToLower(rawQuery) // lowercase the string so we can look for ?sig= and &sig= + sigFound := strings.Contains(rawQuery, "?sig=") + if !sigFound { + sigFound = strings.Contains(rawQuery, "&sig=") + if !sigFound { + return sigFound, rawQuery // [?|&]sig= not found; return same rawQuery passed in (no memory allocation) + } + } + // [?|&]sig= found, redact its value + values, _ := url.ParseQuery(rawQuery) + for name := range values { + if strings.EqualFold(name, "sig") { + values[name] = []string{"REDACTED"} + } + } + return sigFound, values.Encode() +} + +func prepareRequestForLogging(request pipeline.Request) *http.Request { + req := request + if sigFound, rawQuery := redactSigQueryParam(req.URL.RawQuery); sigFound { + // Make copy so we don't destroy the query parameters we actually need to send in the request + req = request.Copy() + req.Request.URL.RawQuery = rawQuery + } + return req.Request +} + +func stack() []byte { + buf := make([]byte, 1024) + for { + n := runtime.Stack(buf, false) + if n < len(buf) { + return buf[:n] + } + buf = make([]byte, 2*len(buf)) + } +} diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_policy_retry.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_policy_retry.go new file mode 100644 index 0000000000..4c885ea1aa --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_policy_retry.go @@ -0,0 +1,318 @@ +package azblob + +import ( + "context" + "math/rand" + "net" + "net/http" + "strconv" + "time" + + "github.com/Azure/azure-pipeline-go/pipeline" + "io/ioutil" + "io" +) + +// RetryPolicy tells the pipeline what kind of retry policy to use. See the RetryPolicy* constants. +type RetryPolicy int32 + +const ( + // RetryPolicyExponential tells the pipeline to use an exponential back-off retry policy + RetryPolicyExponential RetryPolicy = 0 + + // RetryPolicyFixed tells the pipeline to use a fixed back-off retry policy + RetryPolicyFixed RetryPolicy = 1 +) + +// RetryOptions configures the retry policy's behavior. +type RetryOptions struct { + // Policy tells the pipeline what kind of retry policy to use. See the RetryPolicy* constants.\ + // A value of zero means that you accept our default policy. + Policy RetryPolicy + + // MaxTries specifies the maximum number of attempts an operation will be tried before producing an error (0=default). + // A value of zero means that you accept our default policy. A value of 1 means 1 try and no retries. + MaxTries int32 + + // TryTimeout indicates the maximum time allowed for any single try of an HTTP request. + // A value of zero means that you accept our default timeout. NOTE: When transferring large amounts + // of data, the default TryTimeout will probably not be sufficient. You should override this value + // based on the bandwidth available to the host machine and proximity to the Storage service. A good + // starting point may be something like (60 seconds per MB of anticipated-payload-size). + TryTimeout time.Duration + + // RetryDelay specifies the amount of delay to use before retrying an operation (0=default). + // When RetryPolicy is specified as RetryPolicyExponential, the delay increases exponentially + // with each retry up to a maximum specified by MaxRetryDelay. + // If you specify 0, then you must also specify 0 for MaxRetryDelay. + // If you specify RetryDelay, then you must also specify MaxRetryDelay, and MaxRetryDelay should be + // equal to or greater than RetryDelay. + RetryDelay time.Duration + + // MaxRetryDelay specifies the maximum delay allowed before retrying an operation (0=default). + // If you specify 0, then you must also specify 0 for RetryDelay. + MaxRetryDelay time.Duration + + // RetryReadsFromSecondaryHost specifies whether the retry policy should retry a read operation against another host. + // If RetryReadsFromSecondaryHost is "" (the default) then operations are not retried against another host. + // NOTE: Before setting this field, make sure you understand the issues around reading stale & potentially-inconsistent + // data at this webpage: https://docs.microsoft.com/en-us/azure/storage/common/storage-designing-ha-apps-with-ragrs + RetryReadsFromSecondaryHost string // Comment this our for non-Blob SDKs +} + +func (o RetryOptions) retryReadsFromSecondaryHost() string { + return o.RetryReadsFromSecondaryHost // This is for the Blob SDK only + //return "" // This is for non-blob SDKs +} + +func (o RetryOptions) defaults() RetryOptions { + if o.Policy != RetryPolicyExponential && o.Policy != RetryPolicyFixed { + panic("RetryPolicy must be RetryPolicyExponential or RetryPolicyFixed") + } + if o.MaxTries < 0 { + panic("MaxTries must be >= 0") + } + if o.TryTimeout < 0 || o.RetryDelay < 0 || o.MaxRetryDelay < 0 { + panic("TryTimeout, RetryDelay, and MaxRetryDelay must all be >= 0") + } + if o.RetryDelay > o.MaxRetryDelay { + panic("RetryDelay must be <= MaxRetryDelay") + } + if (o.RetryDelay == 0 && o.MaxRetryDelay != 0) || (o.RetryDelay != 0 && o.MaxRetryDelay == 0) { + panic("Both RetryDelay and MaxRetryDelay must be 0 or neither can be 0") + } + + IfDefault := func(current *time.Duration, desired time.Duration) { + if *current == time.Duration(0) { + *current = desired + } + } + + // Set defaults if unspecified + if o.MaxTries == 0 { + o.MaxTries = 4 + } + switch o.Policy { + case RetryPolicyExponential: + IfDefault(&o.TryTimeout, 1*time.Minute) + IfDefault(&o.RetryDelay, 4*time.Second) + IfDefault(&o.MaxRetryDelay, 120*time.Second) + + case RetryPolicyFixed: + IfDefault(&o.TryTimeout, 1*time.Minute) + IfDefault(&o.RetryDelay, 30*time.Second) + IfDefault(&o.MaxRetryDelay, 120*time.Second) + } + return o +} + +func (o RetryOptions) calcDelay(try int32) time.Duration { // try is >=1; never 0 + pow := func(number int64, exponent int32) int64 { // pow is nested helper function + var result int64 = 1 + for n := int32(0); n < exponent; n++ { + result *= number + } + return result + } + + delay := time.Duration(0) + switch o.Policy { + case RetryPolicyExponential: + delay = time.Duration(pow(2, try-1)-1) * o.RetryDelay + + case RetryPolicyFixed: + if try > 1 { // Any try after the 1st uses the fixed delay + delay = o.RetryDelay + } + } + + // Introduce some jitter: [0.0, 1.0) / 2 = [0.0, 0.5) + 0.8 = [0.8, 1.3) + delay = time.Duration(delay.Seconds() * (rand.Float64()/2 + 0.8) * float64(time.Second)) // NOTE: We want math/rand; not crypto/rand + if delay > o.MaxRetryDelay { + delay = o.MaxRetryDelay + } + return delay +} + +// NewRetryPolicyFactory creates a RetryPolicyFactory object configured using the specified options. +func NewRetryPolicyFactory(o RetryOptions) pipeline.Factory { + o = o.defaults() // Force defaults to be calculated + return pipeline.FactoryFunc(func(next pipeline.Policy, po *pipeline.PolicyOptions) pipeline.PolicyFunc { + return func(ctx context.Context, request pipeline.Request) (response pipeline.Response, err error) { + // Before each try, we'll select either the primary or secondary URL. + primaryTry := int32(0) // This indicates how many tries we've attempted against the primary DC + + // We only consider retrying against a secondary if we have a read request (GET/HEAD) AND this policy has a Secondary URL it can use + considerSecondary := (request.Method == http.MethodGet || request.Method == http.MethodHead) && o.retryReadsFromSecondaryHost() != "" + + // Exponential retry algorithm: ((2 ^ attempt) - 1) * delay * random(0.8, 1.2) + // When to retry: connection failure or temporary/timeout. NOTE: StorageError considers HTTP 500/503 as temporary & is therefore retryable + // If using a secondary: + // Even tries go against primary; odd tries go against the secondary + // For a primary wait ((2 ^ primaryTries - 1) * delay * random(0.8, 1.2) + // If secondary gets a 404, don't fail, retry but future retries are only against the primary + // When retrying against a secondary, ignore the retry count and wait (.1 second * random(0.8, 1.2)) + for try := int32(1); try <= o.MaxTries; try++ { + logf("\n=====> Try=%d\n", try) + + // Determine which endpoint to try. It's primary if there is no secondary or if it is an add # attempt. + tryingPrimary := !considerSecondary || (try%2 == 1) + // Select the correct host and delay + if tryingPrimary { + primaryTry++ + delay := o.calcDelay(primaryTry) + logf("Primary try=%d, Delay=%v\n", primaryTry, delay) + time.Sleep(delay) // The 1st try returns 0 delay + } else { + delay := time.Second * time.Duration(rand.Float32()/2+0.8) + logf("Secondary try=%d, Delay=%v\n", try-primaryTry, delay) + time.Sleep(delay) // Delay with some jitter before trying secondary + } + + // Clone the original request to ensure that each try starts with the original (unmutated) request. + requestCopy := request.Copy() + + // For each try, seek to the beginning of the Body stream. We do this even for the 1st try because + // the stream may not be at offset 0 when we first get it and we want the same behavior for the + // 1st try as for additional tries. + if err = requestCopy.RewindBody(); err != nil { + panic(err) + } + if !tryingPrimary { + requestCopy.Request.URL.Host = o.retryReadsFromSecondaryHost() + } + + // Set the server-side timeout query parameter "timeout=[seconds]" + timeout := int32(o.TryTimeout.Seconds()) // Max seconds per try + if deadline, ok := ctx.Deadline(); ok { // If user's ctx has a deadline, make the timeout the smaller of the two + t := int32(deadline.Sub(time.Now()).Seconds()) // Duration from now until user's ctx reaches its deadline + logf("MaxTryTimeout=%d secs, TimeTilDeadline=%d sec\n", timeout, t) + if t < timeout { + timeout = t + } + if timeout < 0 { + timeout = 0 // If timeout ever goes negative, set it to zero; this happen while debugging + } + logf("TryTimeout adjusted to=%d sec\n", timeout) + } + q := requestCopy.Request.URL.Query() + q.Set("timeout", strconv.Itoa(int(timeout+1))) // Add 1 to "round up" + requestCopy.Request.URL.RawQuery = q.Encode() + logf("Url=%s\n", requestCopy.Request.URL.String()) + + // Set the time for this particular retry operation and then Do the operation. + tryCtx, tryCancel := context.WithTimeout(ctx, time.Second*time.Duration(timeout)) + //requestCopy.Body = &deadlineExceededReadCloser{r: requestCopy.Request.Body} + response, err = next.Do(tryCtx, requestCopy) // Make the request + /*err = improveDeadlineExceeded(err) + if err == nil { + response.Response().Body = &deadlineExceededReadCloser{r: response.Response().Body} + }*/ + logf("Err=%v, response=%v\n", err, response) + + action := "" // This MUST get changed within the switch code below + switch { + case ctx.Err() != nil: + action = "NoRetry: Op timeout" + case !tryingPrimary && response != nil && response.Response().StatusCode == http.StatusNotFound: + // If attempt was against the secondary & it returned a StatusNotFound (404), then + // the resource was not found. This may be due to replication delay. So, in this + // case, we'll never try the secondary again for this operation. + considerSecondary = false + action = "Retry: Secondary URL returned 404" + case err != nil: + // NOTE: Protocol Responder returns non-nil if REST API returns invalid status code for the invoked operation + if netErr, ok := err.(net.Error); ok && (netErr.Temporary() || netErr.Timeout()) { + action = "Retry: net.Error and Temporary() or Timeout()" + } else { + action = "NoRetry: unrecognized error" + } + default: + action = "NoRetry: successful HTTP request" // no error + } + + logf("Action=%s\n", action) + // fmt.Println(action + "\n") // This is where we could log the retry operation; action is why we're retrying + if action[0] != 'R' { // Retry only if action starts with 'R' + if err != nil { + tryCancel() // If we're returning an error, cancel this current/last per-retry timeout context + } else { + // TODO: Right now, we've decided to leak the per-try Context until the user's Context is canceled. + // Another option is that we wrap the last per-try context in a body and overwrite the Response's Body field with our wrapper. + // So, when the user closes the Body, the our per-try context gets closed too. + // Another option, is that the Last Policy do this wrapping for a per-retry context (not for the user's context) + _ = tryCancel // So, for now, we don't call cancel: cancel() + } + break // Don't retry + } + if response != nil && response.Response() != nil && response.Response().Body != nil { + // If we're going to retry and we got a previous response, then flush its body to avoid leaking its TCP connection + body := response.Response().Body + io.Copy(ioutil.Discard, body) + body.Close() + } + // If retrying, cancel the current per-try timeout context + tryCancel() + } + return response, err // Not retryable or too many retries; return the last response/error + } + }) +} + +// According to https://github.com/golang/go/wiki/CompilerOptimizations, the compiler will inline this method and hopefully optimize all calls to it away +var logf = func(format string, a ...interface{}) {} + +// Use this version to see the retry method's code path (import "fmt") +//var logf = fmt.Printf + +/* +type deadlineExceededReadCloser struct { + r io.ReadCloser +} + +func (r *deadlineExceededReadCloser) Read(p []byte) (int, error) { + n, err := 0, io.EOF + if r.r != nil { + n, err = r.r.Read(p) + } + return n, improveDeadlineExceeded(err) +} +func (r *deadlineExceededReadCloser) Seek(offset int64, whence int) (int64, error) { + // For an HTTP request, the ReadCloser MUST also implement seek + // For an HTTP response, Seek MUST not be called (or this will panic) + o, err := r.r.(io.Seeker).Seek(offset, whence) + return o, improveDeadlineExceeded(err) +} +func (r *deadlineExceededReadCloser) Close() error { + if c, ok := r.r.(io.Closer); ok { + c.Close() + } + return nil +} + +// timeoutError is the internal struct that implements our richer timeout error. +type deadlineExceeded struct { + responseError +} + +var _ net.Error = (*deadlineExceeded)(nil) // Ensure deadlineExceeded implements the net.Error interface at compile time + +// improveDeadlineExceeded creates a timeoutError object that implements the error interface IF cause is a context.DeadlineExceeded error. +func improveDeadlineExceeded(cause error) error { + // If cause is not DeadlineExceeded, return the same error passed in. + if cause != context.DeadlineExceeded { + return cause + } + // Else, convert DeadlineExceeded to our timeoutError which gives a richer string message + return &deadlineExceeded{ + responseError: responseError{ + ErrorNode: pipeline.ErrorNode{}.Initialize(cause, 3), + }, + } +} + +// Error implements the error interface's Error method to return a string representation of the error. +func (e *deadlineExceeded) Error() string { + return e.ErrorNode.Error("context deadline exceeded; when creating a pipeline, consider increasing RetryOptions' TryTimeout field") +} +*/ diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_policy_telemetry.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_policy_telemetry.go new file mode 100644 index 0000000000..608e1051ca --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_policy_telemetry.go @@ -0,0 +1,51 @@ +package azblob + +import ( + "bytes" + "context" + "fmt" + "os" + "runtime" + + "github.com/Azure/azure-pipeline-go/pipeline" +) + +// TelemetryOptions configures the telemetry policy's behavior. +type TelemetryOptions struct { + // Value is a string prepended to each request's User-Agent and sent to the service. + // The service records the user-agent in logs for diagnostics and tracking of client requests. + Value string +} + +// NewTelemetryPolicyFactory creates a factory that can create telemetry policy objects +// which add telemetry information to outgoing HTTP requests. +func NewTelemetryPolicyFactory(o TelemetryOptions) pipeline.Factory { + b := &bytes.Buffer{} + b.WriteString(o.Value) + if b.Len() > 0 { + b.WriteRune(' ') + } + fmt.Fprintf(b, "Azure-Storage/%s %s", serviceLibVersion, platformInfo) + telemetryValue := b.String() + + return pipeline.FactoryFunc(func(next pipeline.Policy, po *pipeline.PolicyOptions) pipeline.PolicyFunc { + return func(ctx context.Context, request pipeline.Request) (pipeline.Response, error) { + request.Header.Set("User-Agent", telemetryValue) + return next.Do(ctx, request) + } + }) +} + +// NOTE: the ONLY function that should write to this variable is this func +var platformInfo = func() string { + // Azure-Storage/version (runtime; os type and version)” + // Azure-Storage/1.4.0 (NODE-VERSION v4.5.0; Windows_NT 10.0.14393)' + operatingSystem := runtime.GOOS // Default OS string + switch operatingSystem { + case "windows": + operatingSystem = os.Getenv("OS") // Get more specific OS information + case "linux": // accept default OS info + case "freebsd": // accept default OS info + } + return fmt.Sprintf("(%s; %s)", runtime.Version(), operatingSystem) +}() diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_policy_unique_request_id.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_policy_unique_request_id.go new file mode 100644 index 0000000000..a75c7d1d2e --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_policy_unique_request_id.go @@ -0,0 +1,24 @@ +package azblob + +import ( + "context" + + "github.com/Azure/azure-pipeline-go/pipeline" +) + +// NewUniqueRequestIDPolicyFactory creates a UniqueRequestIDPolicyFactory object +// that sets the request's x-ms-client-request-id header if it doesn't already exist. +func NewUniqueRequestIDPolicyFactory() pipeline.Factory { + return pipeline.FactoryFunc(func(next pipeline.Policy, po *pipeline.PolicyOptions) pipeline.PolicyFunc { + // This is Policy's Do method: + return func(ctx context.Context, request pipeline.Request) (pipeline.Response, error) { + id := request.Header.Get(xMsClientRequestID) + if id == "" { // Add a unique request ID if the caller didn't specify one already + request.Header.Set(xMsClientRequestID, newUUID().String()) + } + return next.Do(ctx, request) + } + }) +} + +const xMsClientRequestID = "x-ms-client-request-id" diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_retry_reader.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_retry_reader.go new file mode 100644 index 0000000000..42724efa52 --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_retry_reader.go @@ -0,0 +1,122 @@ +package azblob + +import ( + "context" + "io" + "net" + "net/http" +) + +const CountToEnd = 0 + +// HTTPGetter is a function type that refers to a method that performs an HTTP GET operation. +type HTTPGetter func(ctx context.Context, i HTTPGetterInfo) (*http.Response, error) + +// HTTPGetterInfo is passed to an HTTPGetter function passing it parameters +// that should be used to make an HTTP GET request. +type HTTPGetterInfo struct { + // Offset specifies the start offset that should be used when + // creating the HTTP GET request's Range header + Offset int64 + + // Count specifies the count of bytes that should be used to calculate + // the end offset when creating the HTTP GET request's Range header + Count int64 + + // ETag specifies the resource's etag that should be used when creating + // the HTTP GET request's If-Match header + ETag ETag +} + +// RetryReaderOptions contains properties which can help to decide when to do retry. +type RetryReaderOptions struct { + // MaxRetryRequests specifies the maximum number of HTTP GET requests that will be made + // while reading from a RetryReader. A value of zero means that no additional HTTP + // GET requests will be made. + MaxRetryRequests int + doInjectError bool + doInjectErrorRound int +} + +// retryReader implements io.ReaderCloser methods. +// retryReader tries to read from response, and if there is retriable network error +// returned during reading, it will retry according to retry reader option through executing +// user defined action with provided data to get a new response, and continue the overall reading process +// through reading from the new response. +type retryReader struct { + ctx context.Context + response *http.Response + info HTTPGetterInfo + countWasBounded bool + o RetryReaderOptions + getter HTTPGetter +} + +// NewRetryReader creates a retry reader. +func NewRetryReader(ctx context.Context, initialResponse *http.Response, + info HTTPGetterInfo, o RetryReaderOptions, getter HTTPGetter) io.ReadCloser { + if getter == nil { + panic("getter must not be nil") + } + if info.Count < 0 { + panic("info.Count must be >= 0") + } + if o.MaxRetryRequests < 0 { + panic("o.MaxRetryRequests must be >= 0") + } + return &retryReader{ctx: ctx, getter: getter, info: info, countWasBounded: info.Count != CountToEnd, response: initialResponse, o: o} +} + +func (s *retryReader) Read(p []byte) (n int, err error) { + for try := 0; ; try++ { + //fmt.Println(try) // Comment out for debugging. + if s.countWasBounded && s.info.Count == CountToEnd { + // User specified an original count and the remaining bytes are 0, return 0, EOF + return 0, io.EOF + } + + if s.response == nil { // We don't have a response stream to read from, try to get one. + response, err := s.getter(s.ctx, s.info) + if err != nil { + return 0, err + } + // Successful GET; this is the network stream we'll read from. + s.response = response + } + n, err := s.response.Body.Read(p) // Read from the stream + + // Injection mechanism for testing. + if s.o.doInjectError && try == s.o.doInjectErrorRound { + err = &net.DNSError{IsTemporary: true} + } + + // We successfully read data or end EOF. + if err == nil || err == io.EOF { + s.info.Offset += int64(n) // Increments the start offset in case we need to make a new HTTP request in the future + if s.info.Count != CountToEnd { + s.info.Count -= int64(n) // Decrement the count in case we need to make a new HTTP request in the future + } + return n, err // Return the return to the caller + } + s.Close() // Error, close stream + s.response = nil // Our stream is no longer good + + // Check the retry count and error code, and decide whether to retry. + if try >= s.o.MaxRetryRequests { + return n, err // All retries exhausted + } + + if netErr, ok := err.(net.Error); ok && (netErr.Timeout() || netErr.Temporary()) { + continue + // Loop around and try to get and read from new stream. + } + return n, err // Not retryable, just return + } +} + +func (s *retryReader) Close() error { + if s.response != nil && s.response.Body != nil { + return s.response.Body.Close() + } + return nil +} diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_sas_account.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_sas_account.go new file mode 100644 index 0000000000..8b51193f6a --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_sas_account.go @@ -0,0 +1,217 @@ +package azblob + +import ( + "bytes" + "fmt" + "strings" + "time" +) + +// AccountSASSignatureValues is used to generate a Shared Access Signature (SAS) for an Azure Storage account. +// For more information, see https://docs.microsoft.com/rest/api/storageservices/constructing-an-account-sas +type AccountSASSignatureValues struct { + Version string `param:"sv"` // If not specified, this defaults to SASVersion + Protocol SASProtocol `param:"spr"` // See the SASProtocol* constants + StartTime time.Time `param:"st"` // Not specified if IsZero + ExpiryTime time.Time `param:"se"` // Not specified if IsZero + Permissions string `param:"sp"` // Create by initializing a AccountSASPermissions and then call String() + IPRange IPRange `param:"sip"` + Services string `param:"ss"` // Create by initializing AccountSASServices and then call String() + ResourceTypes string `param:"srt"` // Create by initializing AccountSASResourceTypes and then call String() +} + +// NewSASQueryParameters uses an account's shared key credential to sign this signature values to produce +// the proper SAS query parameters. +func (v AccountSASSignatureValues) NewSASQueryParameters(sharedKeyCredential *SharedKeyCredential) SASQueryParameters { + // https://docs.microsoft.com/en-us/rest/api/storageservices/Constructing-an-Account-SAS + if v.ExpiryTime.IsZero() || v.Permissions == "" || v.ResourceTypes == "" || v.Services == "" { + panic("Account SAS is missing at least one of these: ExpiryTime, Permissions, Service, or ResourceType") + } + if v.Version == "" { + v.Version = SASVersion + } + perms := &AccountSASPermissions{} + if err := perms.Parse(v.Permissions); err != nil { + panic(err) + } + v.Permissions = perms.String() + + startTime, expiryTime := FormatTimesForSASSigning(v.StartTime, v.ExpiryTime) + + stringToSign := strings.Join([]string{ + sharedKeyCredential.AccountName(), + v.Permissions, + v.Services, + v.ResourceTypes, + startTime, + expiryTime, + v.IPRange.String(), + string(v.Protocol), + v.Version, + ""}, // That right, the account SAS requires a terminating extra newline + "\n") + + signature := sharedKeyCredential.ComputeHMACSHA256(stringToSign) + p := SASQueryParameters{ + // Common SAS parameters + version: v.Version, + protocol: v.Protocol, + startTime: v.StartTime, + expiryTime: v.ExpiryTime, + permissions: v.Permissions, + ipRange: v.IPRange, + + // Account-specific SAS parameters + services: v.Services, + resourceTypes: v.ResourceTypes, + + // Calculated SAS signature + signature: signature, + } + return p +} + +// The AccountSASPermissions type simplifies creating the permissions string for an Azure Storage Account SAS. +// Initialize an instance of this type and then call its String method to set AccountSASSignatureValues's Permissions field. +type AccountSASPermissions struct { + Read, Write, Delete, List, Add, Create, Update, Process bool +} + +// String produces the SAS permissions string for an Azure Storage account. +// Call this method to set AccountSASSignatureValues's Permissions field. +func (p AccountSASPermissions) String() string { + var buffer bytes.Buffer + if p.Read { + buffer.WriteRune('r') + } + if p.Write { + buffer.WriteRune('w') + } + if p.Delete { + buffer.WriteRune('d') + } + if p.List { + buffer.WriteRune('l') + } + if p.Add { + buffer.WriteRune('a') + } + if p.Create { + buffer.WriteRune('c') + } + if p.Update { + buffer.WriteRune('u') + } + if p.Process { + buffer.WriteRune('p') + } + return buffer.String() +} + +// Parse initializes the AccountSASPermissions's fields from a string. +func (p *AccountSASPermissions) Parse(s string) error { + *p = AccountSASPermissions{} // Clear out the flags + for _, r := range s { + switch r { + case 'r': + p.Read = true + case 'w': + p.Write = true + case 'd': + p.Delete = true + case 'l': + p.List = true + case 'a': + p.Add = true + case 'c': + p.Create = true + case 'u': + p.Update = true + case 'p': + p.Process = true + default: + return fmt.Errorf("Invalid permission character: '%v'", r) + } + } + return nil +} + +// The AccountSASServices type simplifies creating the services string for an Azure Storage Account SAS. +// Initialize an instance of this type and then call its String method to set AccountSASSignatureValues's Services field. +type AccountSASServices struct { + Blob, Queue, File bool +} + +// String produces the SAS services string for an Azure Storage account. +// Call this method to set AccountSASSignatureValues's Services field. +func (s AccountSASServices) String() string { + var buffer bytes.Buffer + if s.Blob { + buffer.WriteRune('b') + } + if s.Queue { + buffer.WriteRune('q') + } + if s.File { + buffer.WriteRune('f') + } + return buffer.String() +} + +// Parse initializes the AccountSASServices' fields from a string. +func (a *AccountSASServices) Parse(s string) error { + *a = AccountSASServices{} // Clear out the flags + for _, r := range s { + switch r { + case 'b': + a.Blob = true + case 'q': + a.Queue = true + case 'f': + a.File = true + default: + return fmt.Errorf("Invalid service character: '%v'", r) + } + } + return nil +} + +// The AccountSASResourceTypes type simplifies creating the resource types string for an Azure Storage Account SAS. +// Initialize an instance of this type and then call its String method to set AccountSASSignatureValues's ResourceTypes field. +type AccountSASResourceTypes struct { + Service, Container, Object bool +} + +// String produces the SAS resource types string for an Azure Storage account. +// Call this method to set AccountSASSignatureValues's ResourceTypes field. +func (rt AccountSASResourceTypes) String() string { + var buffer bytes.Buffer + if rt.Service { + buffer.WriteRune('s') + } + if rt.Container { + buffer.WriteRune('c') + } + if rt.Object { + buffer.WriteRune('o') + } + return buffer.String() +} + +// Parse initializes the AccountSASResourceType's fields from a string. +func (rt *AccountSASResourceTypes) Parse(s string) error { + *rt = AccountSASResourceTypes{} // Clear out the flags + for _, r := range s { + switch r { + case 's': + rt.Service = true + case 'q': + rt.Container = true + case 'o': + rt.Object = true + default: + return fmt.Errorf("Invalid resource type: '%v'", r) + } + } + return nil +} diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_sas_query_params.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_sas_query_params.go new file mode 100644 index 0000000000..db10171e75 --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_sas_query_params.go @@ -0,0 +1,211 @@ +package azblob + +import ( + "net" + "net/url" + "strings" + "time" +) + +// SASVersion indicates the SAS version. +const SASVersion = ServiceVersion + +type SASProtocol string + +const ( + // SASProtocolHTTPS can be specified for a SAS protocol + SASProtocolHTTPS SASProtocol = "https" + + // SASProtocolHTTPSandHTTP can be specified for a SAS protocol + SASProtocolHTTPSandHTTP SASProtocol = "https,http" +) + +// FormatTimesForSASSigning converts a time.Time to a snapshotTimeFormat string suitable for a +// SASField's StartTime or ExpiryTime fields. Returns "" if value.IsZero(). +func FormatTimesForSASSigning(startTime, expiryTime time.Time) (string, string) { + ss := "" + if !startTime.IsZero() { + ss = startTime.Format(SASTimeFormat) // "yyyy-MM-ddTHH:mm:ssZ" + } + se := "" + if !expiryTime.IsZero() { + se = expiryTime.Format(SASTimeFormat) // "yyyy-MM-ddTHH:mm:ssZ" + } + return ss, se +} + +// SASTimeFormat represents the format of a SAS start or expiry time. Use it when formatting/parsing a time.Time. +const SASTimeFormat = "2006-01-02T15:04:05Z" //"2017-07-27T00:00:00Z" // ISO 8601 + +// https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-a-service-sas + +// A SASQueryParameters object represents the components that make up an Azure Storage SAS' query parameters. +// You parse a map of query parameters into its fields by calling NewSASQueryParameters(). You add the components +// to a query parameter map by calling AddToValues(). +// NOTE: Changing any field requires computing a new SAS signature using a XxxSASSignatureValues type. +// +// This type defines the components used by all Azure Storage resources (Containers, Blobs, Files, & Queues). +type SASQueryParameters struct { + // All members are immutable or values so copies of this struct are goroutine-safe. + version string `param:"sv"` + services string `param:"ss"` + resourceTypes string `param:"srt"` + protocol SASProtocol `param:"spr"` + startTime time.Time `param:"st"` + expiryTime time.Time `param:"se"` + ipRange IPRange `param:"sip"` + identifier string `param:"si"` + resource string `param:"sr"` + permissions string `param:"sp"` + signature string `param:"sig"` +} + +func (p *SASQueryParameters) Version() string { + return p.version +} + +func (p *SASQueryParameters) Services() string { + return p.services +} +func (p *SASQueryParameters) ResourceTypes() string { + return p.resourceTypes +} +func (p *SASQueryParameters) Protocol() SASProtocol { + return p.protocol +} +func (p *SASQueryParameters) StartTime() time.Time { + return p.startTime +} +func (p *SASQueryParameters) ExpiryTime() time.Time { + return p.expiryTime +} + +func (p *SASQueryParameters) IPRange() IPRange { + return p.ipRange +} + +func (p *SASQueryParameters) Identifier() string { + return p.identifier +} + +func (p *SASQueryParameters) Resource() string { + return p.resource +} +func (p *SASQueryParameters) Permissions() string { + return p.permissions +} + +func (p *SASQueryParameters) Signature() string { + return p.signature +} + +// IPRange represents a SAS IP range's start IP and (optionally) end IP. +type IPRange struct { + Start net.IP // Not specified if length = 0 + End net.IP // Not specified if length = 0 +} + +// String returns a string representation of an IPRange. +func (ipr *IPRange) String() string { + if len(ipr.Start) == 0 { + return "" + } + start := ipr.Start.String() + if len(ipr.End) == 0 { + return start + } + return start + "-" + ipr.End.String() +} + +// NewSASQueryParameters creates and initializes a SASQueryParameters object based on the +// query parameter map's passed-in values. If deleteSASParametersFromValues is true, +// all SAS-related query parameters are removed from the passed-in map. If +// deleteSASParametersFromValues is false, the map passed-in map is unaltered. +func newSASQueryParameters(values url.Values, deleteSASParametersFromValues bool) SASQueryParameters { + p := SASQueryParameters{} + for k, v := range values { + val := v[0] + isSASKey := true + switch strings.ToLower(k) { + case "sv": + p.version = val + case "ss": + p.services = val + case "srt": + p.resourceTypes = val + case "spr": + p.protocol = SASProtocol(val) + case "st": + p.startTime, _ = time.Parse(SASTimeFormat, val) + case "se": + p.expiryTime, _ = time.Parse(SASTimeFormat, val) + case "sip": + dashIndex := strings.Index(val, "-") + if dashIndex == -1 { + p.ipRange.Start = net.ParseIP(val) + } else { + p.ipRange.Start = net.ParseIP(val[:dashIndex]) + p.ipRange.End = net.ParseIP(val[dashIndex+1:]) + } + case "si": + p.identifier = val + case "sr": + p.resource = val + case "sp": + p.permissions = val + case "sig": + p.signature = val + default: + isSASKey = false // We didn't recognize the query parameter + } + if isSASKey && deleteSASParametersFromValues { + delete(values, k) + } + } + return p +} + +// AddToValues adds the SAS components to the specified query parameters map. +func (p *SASQueryParameters) addToValues(v url.Values) url.Values { + if p.version != "" { + v.Add("sv", p.version) + } + if p.services != "" { + v.Add("ss", p.services) + } + if p.resourceTypes != "" { + v.Add("srt", p.resourceTypes) + } + if p.protocol != "" { + v.Add("spr", string(p.protocol)) + } + if !p.startTime.IsZero() { + v.Add("st", p.startTime.Format(SASTimeFormat)) + } + if !p.expiryTime.IsZero() { + v.Add("se", p.expiryTime.Format(SASTimeFormat)) + } + if len(p.ipRange.Start) > 0 { + v.Add("sip", p.ipRange.String()) + } + if p.identifier != "" { + v.Add("si", p.identifier) + } + if p.resource != "" { + v.Add("sr", p.resource) + } + if p.permissions != "" { + v.Add("sp", p.permissions) + } + if p.signature != "" { + v.Add("sig", p.signature) + } + return v +} + +// Encode encodes the SAS query parameters into URL encoded form sorted by key. +func (p *SASQueryParameters) Encode() string { + v := url.Values{} + p.addToValues(v) + return v.Encode() +} diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_service_codes_common.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_service_codes_common.go new file mode 100644 index 0000000000..765beb2415 --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_service_codes_common.go @@ -0,0 +1,131 @@ +package azblob + +// https://docs.microsoft.com/en-us/rest/api/storageservices/common-rest-api-error-codes + +const ( + // ServiceCodeNone is the default value. It indicates that the error was related to the service or that the service didn't return a code. + ServiceCodeNone ServiceCodeType = "" + + // ServiceCodeAccountAlreadyExists means the specified account already exists. + ServiceCodeAccountAlreadyExists ServiceCodeType = "AccountAlreadyExists" + + // ServiceCodeAccountBeingCreated means the specified account is in the process of being created (403). + ServiceCodeAccountBeingCreated ServiceCodeType = "AccountBeingCreated" + + // ServiceCodeAccountIsDisabled means the specified account is disabled (403). + ServiceCodeAccountIsDisabled ServiceCodeType = "AccountIsDisabled" + + // ServiceCodeAuthenticationFailed means the server failed to authenticate the request. Make sure the value of the Authorization header is formed correctly including the signature (403). + ServiceCodeAuthenticationFailed ServiceCodeType = "AuthenticationFailed" + + // ServiceCodeConditionHeadersNotSupported means the condition headers are not supported (400). + ServiceCodeConditionHeadersNotSupported ServiceCodeType = "ConditionHeadersNotSupported" + + // ServiceCodeConditionNotMet means the condition specified in the conditional header(s) was not met for a read/write operation (304/412). + ServiceCodeConditionNotMet ServiceCodeType = "ConditionNotMet" + + // ServiceCodeEmptyMetadataKey means the key for one of the metadata key-value pairs is empty (400). + ServiceCodeEmptyMetadataKey ServiceCodeType = "EmptyMetadataKey" + + // ServiceCodeInsufficientAccountPermissions means read operations are currently disabled or Write operations are not allowed or The account being accessed does not have sufficient permissions to execute this operation (403). + ServiceCodeInsufficientAccountPermissions ServiceCodeType = "InsufficientAccountPermissions" + + // ServiceCodeInternalError means the server encountered an internal error. Please retry the request (500). + ServiceCodeInternalError ServiceCodeType = "InternalError" + + // ServiceCodeInvalidAuthenticationInfo means the authentication information was not provided in the correct format. Verify the value of Authorization header (400). + ServiceCodeInvalidAuthenticationInfo ServiceCodeType = "InvalidAuthenticationInfo" + + // ServiceCodeInvalidHeaderValue means the value provided for one of the HTTP headers was not in the correct format (400). + ServiceCodeInvalidHeaderValue ServiceCodeType = "InvalidHeaderValue" + + // ServiceCodeInvalidHTTPVerb means the HTTP verb specified was not recognized by the server (400). + ServiceCodeInvalidHTTPVerb ServiceCodeType = "InvalidHttpVerb" + + // ServiceCodeInvalidInput means one of the request inputs is not valid (400). + ServiceCodeInvalidInput ServiceCodeType = "InvalidInput" + + // ServiceCodeInvalidMd5 means the MD5 value specified in the request is invalid. The MD5 value must be 128 bits and Base64-encoded (400). + ServiceCodeInvalidMd5 ServiceCodeType = "InvalidMd5" + + // ServiceCodeInvalidMetadata means the specified metadata is invalid. It includes characters that are not permitted (400). + ServiceCodeInvalidMetadata ServiceCodeType = "InvalidMetadata" + + // ServiceCodeInvalidQueryParameterValue means an invalid value was specified for one of the query parameters in the request URI (400). + ServiceCodeInvalidQueryParameterValue ServiceCodeType = "InvalidQueryParameterValue" + + // ServiceCodeInvalidRange means the range specified is invalid for the current size of the resource (416). + ServiceCodeInvalidRange ServiceCodeType = "InvalidRange" + + // ServiceCodeInvalidResourceName means the specified resource name contains invalid characters (400). + ServiceCodeInvalidResourceName ServiceCodeType = "InvalidResourceName" + + // ServiceCodeInvalidURI means the requested URI does not represent any resource on the server (400). + ServiceCodeInvalidURI ServiceCodeType = "InvalidUri" + + // ServiceCodeInvalidXMLDocument means the specified XML is not syntactically valid (400). + ServiceCodeInvalidXMLDocument ServiceCodeType = "InvalidXmlDocument" + + // ServiceCodeInvalidXMLNodeValue means the value provided for one of the XML nodes in the request body was not in the correct format (400). + ServiceCodeInvalidXMLNodeValue ServiceCodeType = "InvalidXmlNodeValue" + + // ServiceCodeMd5Mismatch means the MD5 value specified in the request did not match the MD5 value calculated by the server (400). + ServiceCodeMd5Mismatch ServiceCodeType = "Md5Mismatch" + + // ServiceCodeMetadataTooLarge means the size of the specified metadata exceeds the maximum size permitted (400). + ServiceCodeMetadataTooLarge ServiceCodeType = "MetadataTooLarge" + + // ServiceCodeMissingContentLengthHeader means the Content-Length header was not specified (411). + ServiceCodeMissingContentLengthHeader ServiceCodeType = "MissingContentLengthHeader" + + // ServiceCodeMissingRequiredQueryParameter means a required query parameter was not specified for this request (400). + ServiceCodeMissingRequiredQueryParameter ServiceCodeType = "MissingRequiredQueryParameter" + + // ServiceCodeMissingRequiredHeader means a required HTTP header was not specified (400). + ServiceCodeMissingRequiredHeader ServiceCodeType = "MissingRequiredHeader" + + // ServiceCodeMissingRequiredXMLNode means a required XML node was not specified in the request body (400). + ServiceCodeMissingRequiredXMLNode ServiceCodeType = "MissingRequiredXmlNode" + + // ServiceCodeMultipleConditionHeadersNotSupported means multiple condition headers are not supported (400). + ServiceCodeMultipleConditionHeadersNotSupported ServiceCodeType = "MultipleConditionHeadersNotSupported" + + // ServiceCodeOperationTimedOut means the operation could not be completed within the permitted time (500). + ServiceCodeOperationTimedOut ServiceCodeType = "OperationTimedOut" + + // ServiceCodeOutOfRangeInput means one of the request inputs is out of range (400). + ServiceCodeOutOfRangeInput ServiceCodeType = "OutOfRangeInput" + + // ServiceCodeOutOfRangeQueryParameterValue means a query parameter specified in the request URI is outside the permissible range (400). + ServiceCodeOutOfRangeQueryParameterValue ServiceCodeType = "OutOfRangeQueryParameterValue" + + // ServiceCodeRequestBodyTooLarge means the size of the request body exceeds the maximum size permitted (413). + ServiceCodeRequestBodyTooLarge ServiceCodeType = "RequestBodyTooLarge" + + // ServiceCodeResourceTypeMismatch means the specified resource type does not match the type of the existing resource (409). + ServiceCodeResourceTypeMismatch ServiceCodeType = "ResourceTypeMismatch" + + // ServiceCodeRequestURLFailedToParse means the url in the request could not be parsed (400). + ServiceCodeRequestURLFailedToParse ServiceCodeType = "RequestUrlFailedToParse" + + // ServiceCodeResourceAlreadyExists means the specified resource already exists (409). + ServiceCodeResourceAlreadyExists ServiceCodeType = "ResourceAlreadyExists" + + // ServiceCodeResourceNotFound means the specified resource does not exist (404). + ServiceCodeResourceNotFound ServiceCodeType = "ResourceNotFound" + + // ServiceCodeServerBusy means the server is currently unable to receive requests. Please retry your request or Ingress/egress is over the account limit or operations per second is over the account limit (503). + ServiceCodeServerBusy ServiceCodeType = "ServerBusy" + + // ServiceCodeUnsupportedHeader means one of the HTTP headers specified in the request is not supported (400). + ServiceCodeUnsupportedHeader ServiceCodeType = "UnsupportedHeader" + + // ServiceCodeUnsupportedXMLNode means one of the XML nodes specified in the request body is not supported (400). + ServiceCodeUnsupportedXMLNode ServiceCodeType = "UnsupportedXmlNode" + + // ServiceCodeUnsupportedQueryParameter means one of the query parameters specified in the request URI is not supported (400). + ServiceCodeUnsupportedQueryParameter ServiceCodeType = "UnsupportedQueryParameter" + + // ServiceCodeUnsupportedHTTPVerb means the resource doesn't support the specified HTTP verb (405). + ServiceCodeUnsupportedHTTPVerb ServiceCodeType = "UnsupportedHttpVerb" +) diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_storage_error.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_storage_error.go new file mode 100644 index 0000000000..03178b247a --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_storage_error.go @@ -0,0 +1,110 @@ +package azblob + +import ( + "bytes" + "encoding/xml" + "fmt" + "net/http" + "sort" + + "github.com/Azure/azure-pipeline-go/pipeline" +) + +func init() { + // wire up our custom error handling constructor + responseErrorFactory = newStorageError +} + +// ServiceCodeType is a string identifying a storage service error. +// For more information, see https://docs.microsoft.com/en-us/rest/api/storageservices/status-and-error-codes2 +type ServiceCodeType string + +// StorageError identifies a responder-generated network or response parsing error. +type StorageError interface { + // ResponseError implements error's Error(), net.Error's Temporary() and Timeout() methods & Response(). + ResponseError + + // ServiceCode returns a service error code. Your code can use this to make error recovery decisions. + ServiceCode() ServiceCodeType +} + +// storageError is the internal struct that implements the public StorageError interface. +type storageError struct { + responseError + serviceCode ServiceCodeType + details map[string]string +} + +// newStorageError creates an error object that implements the error interface. +func newStorageError(cause error, response *http.Response, description string) error { + return &storageError{ + responseError: responseError{ + ErrorNode: pipeline.ErrorNode{}.Initialize(cause, 3), + response: response, + description: description, + }, + } +} + +// ServiceCode returns service-error information. The caller may examine these values but should not modify any of them. +func (e *storageError) ServiceCode() ServiceCodeType { return e.serviceCode } + +// Error implements the error interface's Error method to return a string representation of the error. +func (e *storageError) Error() string { + b := &bytes.Buffer{} + fmt.Fprintf(b, "===== RESPONSE ERROR (ServiceCode=%s) =====\n", e.serviceCode) + fmt.Fprintf(b, "Description=%s, Details: ", e.description) + if len(e.details) == 0 { + b.WriteString("(none)\n") + } else { + b.WriteRune('\n') + keys := make([]string, 0, len(e.details)) + // Alphabetize the details + for k := range e.details { + keys = append(keys, k) + } + sort.Strings(keys) + for _, k := range keys { + fmt.Fprintf(b, " %s: %+v\n", k, e.details[k]) + } + } + req := pipeline.Request{Request: e.response.Request}.Copy() // Make a copy of the response's request + pipeline.WriteRequestWithResponse(b, prepareRequestForLogging(req), e.response, nil) + return e.ErrorNode.Error(b.String()) +} + +// Temporary returns true if the error occurred due to a temporary condition (including an HTTP status of 500 or 503). +func (e *storageError) Temporary() bool { + if e.response != nil { + if (e.response.StatusCode == http.StatusInternalServerError) || (e.response.StatusCode == http.StatusServiceUnavailable) { + return true + } + } + return e.ErrorNode.Temporary() +} + +// UnmarshalXML performs custom unmarshalling of XML-formatted Azure storage request errors. +func (e *storageError) UnmarshalXML(d *xml.Decoder, start xml.StartElement) (err error) { + tokName := "" + var t xml.Token + for t, err = d.Token(); err == nil; t, err = d.Token() { + switch tt := t.(type) { + case xml.StartElement: + tokName = tt.Name.Local + break + case xml.CharData: + switch tokName { + case "Code": + e.serviceCode = ServiceCodeType(tt) + case "Message": + e.description = string(tt) + default: + if e.details == nil { + e.details = map[string]string{} + } + e.details[tokName] = string(tt) + } + } + } + return nil +} diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_util_validate.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_util_validate.go new file mode 100644 index 0000000000..001a21c696 --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_util_validate.go @@ -0,0 +1,61 @@ +package azblob + +import ( + "errors" + "fmt" + "io" + "strconv" +) + +// httpRange defines a range of bytes within an HTTP resource, starting at offset and +// ending at offset+count. A zero-value httpRange indicates the entire resource. An httpRange +// which has an offset but na zero value count indicates from the offset to the resource's end. +type httpRange struct { + offset int64 + count int64 +} + +func (r httpRange) pointers() *string { + if r.offset == 0 && r.count == 0 { // Do common case first for performance + return nil // No specified range + } + if r.offset < 0 { + panic("The range offset must be >= 0") + } + if r.count < 0 { + panic("The range count must be >= 0") + } + endOffset := "" // if count == 0 + if r.count > 0 { + endOffset = strconv.FormatInt((r.offset+r.count)-1, 10) + } + dataRange := fmt.Sprintf("bytes=%v-%s", r.offset, endOffset) + return &dataRange +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +func validateSeekableStreamAt0AndGetCount(body io.ReadSeeker) int64 { + if body == nil { // nil body's are "logically" seekable to 0 and are 0 bytes long + return 0 + } + validateSeekableStreamAt0(body) + count, err := body.Seek(0, io.SeekEnd) + if err != nil { + panic("failed to seek stream") + } + body.Seek(0, io.SeekStart) + return count +} + +func validateSeekableStreamAt0(body io.ReadSeeker) { + if body == nil { // nil body's are "logically" seekable to 0 + return + } + if pos, err := body.Seek(0, io.SeekCurrent); pos != 0 || err != nil { + if err != nil { + panic(err) + } + panic(errors.New("stream must be set to position 0")) + } +} diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_uuid.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_uuid.go new file mode 100644 index 0000000000..1fc7e89cf2 --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zc_uuid.go @@ -0,0 +1,80 @@ +package azblob + +import ( + "crypto/rand" + "fmt" + "strconv" +) + +// The UUID reserved variants. +const ( + reservedNCS byte = 0x80 + reservedRFC4122 byte = 0x40 + reservedMicrosoft byte = 0x20 + reservedFuture byte = 0x00 +) + +// A UUID representation compliant with specification in RFC 4122 document. +type uuid [16]byte + +// NewUUID returns a new uuid using RFC 4122 algorithm. +func newUUID() (u uuid) { + u = uuid{} + // Set all bits to randomly (or pseudo-randomly) chosen values. + _, err := rand.Read(u[:]) + if err != nil { + panic("ran.Read failed") + } + u[8] = (u[8] | reservedRFC4122) & 0x7F // u.setVariant(ReservedRFC4122) + + var version byte = 4 + u[6] = (u[6] & 0xF) | (version << 4) // u.setVersion(4) + return +} + +// String returns an unparsed version of the generated UUID sequence. +func (u uuid) String() string { + return fmt.Sprintf("%x-%x-%x-%x-%x", u[0:4], u[4:6], u[6:8], u[8:10], u[10:]) +} + +// ParseUUID parses a string formatted as "003020100-0504-0706-0809-0a0b0c0d0e0f" +// or "{03020100-0504-0706-0809-0a0b0c0d0e0f}" into a UUID. +func parseUUID(uuidStr string) uuid { + char := func(hexString string) byte { + i, _ := strconv.ParseUint(hexString, 16, 8) + return byte(i) + } + if uuidStr[0] == '{' { + uuidStr = uuidStr[1:] // Skip over the '{' + } + // 03020100 - 05 04 - 07 06 - 08 09 - 0a 0b 0c 0d 0e 0f + // 1 11 1 11 11 1 12 22 2 22 22 22 33 33 33 + // 01234567 8 90 12 3 45 67 8 90 12 3 45 67 89 01 23 45 + uuidVal := uuid{ + char(uuidStr[0:2]), + char(uuidStr[2:4]), + char(uuidStr[4:6]), + char(uuidStr[6:8]), + + char(uuidStr[9:11]), + char(uuidStr[11:13]), + + char(uuidStr[14:16]), + char(uuidStr[16:18]), + + char(uuidStr[19:21]), + char(uuidStr[21:23]), + + char(uuidStr[24:26]), + char(uuidStr[26:28]), + char(uuidStr[28:30]), + char(uuidStr[30:32]), + char(uuidStr[32:34]), + char(uuidStr[34:36]), + } + return uuidVal +} + +func (u uuid) bytes() []byte { + return u[:] +} diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zt_doc.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zt_doc.go new file mode 100644 index 0000000000..6b3779c0e9 --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zt_doc.go @@ -0,0 +1,89 @@ +// Copyright 2017 Microsoft Corporation. All rights reserved. +// Use of this source code is governed by an MIT +// license that can be found in the LICENSE file. + +/* +Package azblob allows you to manipulate Azure Storage containers and blobs objects. + +URL Types + +The most common types you'll work with are the XxxURL types. The methods of these types make requests +against the Azure Storage Service. + + - ServiceURL's methods perform operations on a storage account. + - ContainerURL's methods perform operations on an account's container. + - BlockBlobURL's methods perform operations on a container's block blob. + - AppendBlobURL's methods perform operations on a container's append blob. + - PageBlobURL's methods perform operations on a container's page blob. + - BlobURL's methods perform operations on a container's blob regardless of the blob's type. + +Internally, each XxxURL object contains a URL and a request pipeline. The URL indicates the endpoint where each HTTP +request is sent and the pipeline indicates how the outgoing HTTP request and incoming HTTP response is processed. +The pipeline specifies things like retry policies, logging, deserialization of HTTP response payloads, and more. + +Pipelines are threadsafe and may be shared by multiple XxxURL objects. When you create a ServiceURL, you pass +an initial pipeline. When you call ServiceURL's NewContainerURL method, the new ContainerURL object has its own +URL but it shares the same pipeline as the parent ServiceURL object. + +To work with a blob, call one of ContainerURL's 4 NewXxxBlobURL methods depending on how you want to treat the blob. +To treat the blob as a block blob, append blob, or page blob, call NewBlockBlobURL, NewAppendBlobURL, or NewPageBlobURL +respectively. These three types are all identical except for the methods they expose; each type exposes the methods +relevant to the type of blob represented. If you're not sure how you want to treat a blob, you can call NewBlobURL; +this returns an object whose methods are relevant to any kind of blob. When you call ContainerURL's NewXxxBlobURL, +the new XxxBlobURL object has its own URL but it shares the same pipeline as the parent ContainerURL object. You +can easily switch between blob types (method sets) by calling a ToXxxBlobURL method. + +If you'd like to use a different pipeline with a ServiceURL, ContainerURL, or XxxBlobURL object, then call the XxxURL +object's WithPipeline method passing in the desired pipeline. The WithPipeline methods create a new XxxURL object +with the same URL as the original but with the specified pipeline. + +Note that XxxURL objects use little memory, are goroutine-safe, and many objects share the same pipeline. This means that +XxxURL objects share a lot of system resources making them very efficient. + +All of XxxURL's methods that make HTTP requests return rich error handling information so you can discern network failures, +transient failures, timeout failures, service failures, etc. See the StorageError interface for more information and an +example of how to do deal with errors. + +URL and Shared Access Signature Manipulation + +The library includes a BlobURLParts type for deconstructing and reconstructing URLs. And you can use the following types +for generating and parsing Shared Access Signature (SAS) + - Use the AccountSASSignatureValues type to create a SAS for a storage account. + - Use the BlobSASSignatureValues type to create a SAS for a container or blob. + - Use the SASQueryParameters type to turn signature values in to query parameres or to parse query parameters. + +To generate a SAS, you must use the SharedKeyCredential type. + +Credentials + +When creating a request pipeline, you must specify one of this package's credential types. + - Call the NewAnonymousCredential function for requests that contain a Shared Access Signature (SAS). + - Call the NewSharedKeyCredential function (with an account name & key) to access any account resources. You must also use this + to generate Shared Access Signatures. + +HTTP Request Policy Factories + +This package defines several request policy factories for use with the pipeline package. +Most applications will not use these factories directly; instead, the NewPipeline +function creates these factories, initializes them (via the PipelineOptions type) +and returns a pipeline object for use by the XxxURL objects. + +However, for advanced scenarios, developers can access these policy factories directly +and even create their own and then construct their own pipeline in order to affect HTTP +requests and responses performed by the XxxURL objects. For example, developers can +introduce their own logging, random failures, request recording & playback for fast +testing, HTTP request pacing, alternate retry mechanisms, metering, metrics, etc. The +possibilities are endless! + +Below are the request pipeline policy factory functions that are provided with this +package: + - NewRetryPolicyFactory Enables rich retry semantics for failed HTTP requests. + - NewRequestLogPolicyFactory Enables rich logging support for HTTP requests/responses & failures. + - NewTelemetryPolicyFactory Enables simple modification of the HTTP request's User-Agent header so each request reports the SDK version & language/runtime making the requests. + - NewUniqueRequestIDPolicyFactory Adds a x-ms-client-request-id header with a unique UUID value to an HTTP request to help with diagnosing failures. + +Also, note that all the NewXxxCredential functions return request policy factory objects which get injected into the pipeline. +*/ +package azblob + +// TokenCredential Use this to access resources using Role-Based Access Control (RBAC). diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_append_blob.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_append_blob.go new file mode 100644 index 0000000000..8f3dc99349 --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_append_blob.go @@ -0,0 +1,234 @@ +package azblob + +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +import ( + "context" + "encoding/base64" + "github.com/Azure/azure-pipeline-go/pipeline" + "io" + "io/ioutil" + "net/http" + "net/url" + "strconv" + "time" +) + +// appendBlobClient is the client for the AppendBlob methods of the Azblob service. +type appendBlobClient struct { + managementClient +} + +// newAppendBlobClient creates an instance of the appendBlobClient client. +func newAppendBlobClient(url url.URL, p pipeline.Pipeline) appendBlobClient { + return appendBlobClient{newManagementClient(url, p)} +} + +// AppendBlock the Append Block operation commits a new block of data to the end of an existing append blob. The Append +// Block operation is permitted only if the blob was created with x-ms-blob-type set to AppendBlob. Append Block is +// supported only on version 2015-02-21 version or later. +// +// body is initial data body will be closed upon successful return. Callers should ensure closure when receiving an +// error.contentLength is the length of the request. timeout is the timeout parameter is expressed in seconds. For more +// information, see Setting +// Timeouts for Blob Service Operations. leaseID is if specified, the operation only succeeds if the container's +// lease is active and matches this ID. maxSize is optional conditional header. The max length in bytes permitted for +// the append blob. If the Append Block operation would cause the blob to exceed that limit or if the blob size is +// already greater than the value specified in this header, the request will fail with MaxBlobSizeConditionNotMet error +// (HTTP status code 412 - Precondition Failed). appendPosition is optional conditional header, used only for the +// Append Block operation. A number indicating the byte offset to compare. Append Block will succeed only if the append +// position is equal to this number. If it is not, the request will fail with the AppendPositionConditionNotMet error +// (HTTP status code 412 - Precondition Failed). ifModifiedSince is specify this header value to operate only on a blob +// if it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate +// only on a blob if it has not been modified since the specified date/time. ifMatches is specify an ETag value to +// operate only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a +// matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded +// in the analytics logs when storage analytics logging is enabled. +func (client appendBlobClient) AppendBlock(ctx context.Context, body io.ReadSeeker, contentLength int64, timeout *int32, leaseID *string, maxSize *int64, appendPosition *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*AppendBlobAppendBlockResponse, error) { + if err := validate([]validation{ + {targetValue: body, + constraints: []constraint{{target: "body", name: null, rule: true, chain: nil}}}, + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.appendBlockPreparer(body, contentLength, timeout, leaseID, maxSize, appendPosition, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.appendBlockResponder}, req) + if err != nil { + return nil, err + } + return resp.(*AppendBlobAppendBlockResponse), err +} + +// appendBlockPreparer prepares the AppendBlock request. +func (client appendBlobClient) appendBlockPreparer(body io.ReadSeeker, contentLength int64, timeout *int32, leaseID *string, maxSize *int64, appendPosition *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("PUT", client.url, body) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("comp", "appendblock") + req.URL.RawQuery = params.Encode() + req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10)) + if leaseID != nil { + req.Header.Set("x-ms-lease-id", *leaseID) + } + if maxSize != nil { + req.Header.Set("x-ms-blob-condition-maxsize", strconv.FormatInt(*maxSize, 10)) + } + if appendPosition != nil { + req.Header.Set("x-ms-blob-condition-appendpos", strconv.FormatInt(*appendPosition, 10)) + } + if ifModifiedSince != nil { + req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifUnmodifiedSince != nil { + req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifMatches != nil { + req.Header.Set("If-Match", string(*ifMatches)) + } + if ifNoneMatch != nil { + req.Header.Set("If-None-Match", string(*ifNoneMatch)) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + return req, nil +} + +// appendBlockResponder handles the response to the AppendBlock request. +func (client appendBlobClient) appendBlockResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK, http.StatusCreated) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &AppendBlobAppendBlockResponse{rawResponse: resp.Response()}, err +} + +// Create the Create Append Blob operation creates a new append blob. +// +// contentLength is the length of the request. timeout is the timeout parameter is expressed in seconds. For more +// information, see Setting +// Timeouts for Blob Service Operations. blobContentType is optional. Sets the blob's content type. If specified, +// this property is stored with the blob and returned with a read request. blobContentEncoding is optional. Sets the +// blob's content encoding. If specified, this property is stored with the blob and returned with a read request. +// blobContentLanguage is optional. Set the blob's content language. If specified, this property is stored with the +// blob and returned with a read request. blobContentMD5 is optional. An MD5 hash of the blob content. Note that this +// hash is not validated, as the hashes for the individual blocks were validated when each was uploaded. +// blobCacheControl is optional. Sets the blob's cache control. If specified, this property is stored with the blob and +// returned with a read request. metadata is optional. Specifies a user-defined name-value pair associated with the +// blob. If no name-value pairs are specified, the operation will copy the metadata from the source blob or file to the +// destination blob. If one or more name-value pairs are specified, the destination blob is created with the specified +// metadata, and metadata is not copied from the source blob or file. Note that beginning with version 2009-09-19, +// metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing Containers, Blobs, and +// Metadata for more information. leaseID is if specified, the operation only succeeds if the container's lease is +// active and matches this ID. blobContentDisposition is optional. Sets the blob's Content-Disposition header. +// ifModifiedSince is specify this header value to operate only on a blob if it has been modified since the specified +// date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if it has not been modified +// since the specified date/time. ifMatches is specify an ETag value to operate only on blobs with a matching value. +// ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. requestID is provides a +// client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage +// analytics logging is enabled. +func (client appendBlobClient) Create(ctx context.Context, contentLength int64, timeout *int32, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*AppendBlobCreateResponse, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}, + {targetValue: metadata, + constraints: []constraint{{target: "metadata", name: null, rule: false, + chain: []constraint{{target: "metadata", name: pattern, rule: `^[a-zA-Z]+$`, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.createPreparer(contentLength, timeout, blobContentType, blobContentEncoding, blobContentLanguage, blobContentMD5, blobCacheControl, metadata, leaseID, blobContentDisposition, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.createResponder}, req) + if err != nil { + return nil, err + } + return resp.(*AppendBlobCreateResponse), err +} + +// createPreparer prepares the Create request. +func (client appendBlobClient) createPreparer(contentLength int64, timeout *int32, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("PUT", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + req.URL.RawQuery = params.Encode() + req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10)) + if blobContentType != nil { + req.Header.Set("x-ms-blob-content-type", *blobContentType) + } + if blobContentEncoding != nil { + req.Header.Set("x-ms-blob-content-encoding", *blobContentEncoding) + } + if blobContentLanguage != nil { + req.Header.Set("x-ms-blob-content-language", *blobContentLanguage) + } + if blobContentMD5 != nil { + req.Header.Set("x-ms-blob-content-md5", base64.StdEncoding.EncodeToString(blobContentMD5)) + } + if blobCacheControl != nil { + req.Header.Set("x-ms-blob-cache-control", *blobCacheControl) + } + if metadata != nil { + for k, v := range metadata { + req.Header.Set("x-ms-meta-"+k, v) + } + } + if leaseID != nil { + req.Header.Set("x-ms-lease-id", *leaseID) + } + if blobContentDisposition != nil { + req.Header.Set("x-ms-blob-content-disposition", *blobContentDisposition) + } + if ifModifiedSince != nil { + req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifUnmodifiedSince != nil { + req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifMatches != nil { + req.Header.Set("If-Match", string(*ifMatches)) + } + if ifNoneMatch != nil { + req.Header.Set("If-None-Match", string(*ifNoneMatch)) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + req.Header.Set("x-ms-blob-type", "AppendBlob") + return req, nil +} + +// createResponder handles the response to the Create request. +func (client appendBlobClient) createResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK, http.StatusCreated) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &AppendBlobCreateResponse{rawResponse: resp.Response()}, err +} diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_blob.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_blob.go new file mode 100644 index 0000000000..b2f8eac665 --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_blob.go @@ -0,0 +1,1233 @@ +package azblob + +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +import ( + "context" + "encoding/base64" + "io" + "io/ioutil" + "net/http" + "net/url" + "strconv" + "time" + + "github.com/Azure/azure-pipeline-go/pipeline" +) + +// blobClient is the client for the Blob methods of the Azblob service. +type blobClient struct { + managementClient +} + +// newBlobClient creates an instance of the blobClient client. +func newBlobClient(url url.URL, p pipeline.Pipeline) blobClient { + return blobClient{newManagementClient(url, p)} +} + +// AbortCopyFromURL the Abort Copy From URL operation aborts a pending Copy From URL operation, and leaves a +// destination blob with zero length and full metadata. +// +// copyID is the copy identifier provided in the x-ms-copy-id header of the original Copy Blob operation. timeout is +// the timeout parameter is expressed in seconds. For more information, see Setting +// Timeouts for Blob Service Operations. leaseID is if specified, the operation only succeeds if the container's +// lease is active and matches this ID. requestID is provides a client-generated, opaque value with a 1 KB character +// limit that is recorded in the analytics logs when storage analytics logging is enabled. +func (client blobClient) AbortCopyFromURL(ctx context.Context, copyID string, timeout *int32, leaseID *string, requestID *string) (*BlobAbortCopyFromURLResponse, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.abortCopyFromURLPreparer(copyID, timeout, leaseID, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.abortCopyFromURLResponder}, req) + if err != nil { + return nil, err + } + return resp.(*BlobAbortCopyFromURLResponse), err +} + +// abortCopyFromURLPreparer prepares the AbortCopyFromURL request. +func (client blobClient) abortCopyFromURLPreparer(copyID string, timeout *int32, leaseID *string, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("PUT", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + params.Set("copyid", copyID) + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("comp", "copy") + req.URL.RawQuery = params.Encode() + if leaseID != nil { + req.Header.Set("x-ms-lease-id", *leaseID) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + req.Header.Set("x-ms-copy-action", "abort") + return req, nil +} + +// abortCopyFromURLResponder handles the response to the AbortCopyFromURL request. +func (client blobClient) abortCopyFromURLResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK, http.StatusNoContent) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &BlobAbortCopyFromURLResponse{rawResponse: resp.Response()}, err +} + +// AcquireLease [Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete +// operations +// +// timeout is the timeout parameter is expressed in seconds. For more information, see Setting +// Timeouts for Blob Service Operations. duration is specifies the duration of the lease, in seconds, or negative +// one (-1) for a lease that never expires. A non-infinite lease can be between 15 and 60 seconds. A lease duration +// cannot be changed using renew or change. proposedLeaseID is proposed lease ID, in a GUID string format. The Blob +// service returns 400 (Invalid request) if the proposed lease ID is not in the correct format. See Guid Constructor +// (String) for a list of valid GUID string formats. ifModifiedSince is specify this header value to operate only on a +// blob if it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to +// operate only on a blob if it has not been modified since the specified date/time. ifMatches is specify an ETag value +// to operate only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs +// without a matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is +// recorded in the analytics logs when storage analytics logging is enabled. +func (client blobClient) AcquireLease(ctx context.Context, timeout *int32, duration *int32, proposedLeaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*BlobAcquireLeaseResponse, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.acquireLeasePreparer(timeout, duration, proposedLeaseID, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.acquireLeaseResponder}, req) + if err != nil { + return nil, err + } + return resp.(*BlobAcquireLeaseResponse), err +} + +// acquireLeasePreparer prepares the AcquireLease request. +func (client blobClient) acquireLeasePreparer(timeout *int32, duration *int32, proposedLeaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("PUT", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("comp", "lease") + req.URL.RawQuery = params.Encode() + if duration != nil { + req.Header.Set("x-ms-lease-duration", strconv.FormatInt(int64(*duration), 10)) + } + if proposedLeaseID != nil { + req.Header.Set("x-ms-proposed-lease-id", *proposedLeaseID) + } + if ifModifiedSince != nil { + req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifUnmodifiedSince != nil { + req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifMatches != nil { + req.Header.Set("If-Match", string(*ifMatches)) + } + if ifNoneMatch != nil { + req.Header.Set("If-None-Match", string(*ifNoneMatch)) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + req.Header.Set("x-ms-lease-action", "acquire") + return req, nil +} + +// acquireLeaseResponder handles the response to the AcquireLease request. +func (client blobClient) acquireLeaseResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK, http.StatusCreated) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &BlobAcquireLeaseResponse{rawResponse: resp.Response()}, err +} + +// BreakLease [Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete +// operations +// +// timeout is the timeout parameter is expressed in seconds. For more information, see Setting +// Timeouts for Blob Service Operations. breakPeriod is for a break operation, proposed duration the lease should +// continue before it is broken, in seconds, between 0 and 60. This break period is only used if it is shorter than the +// time remaining on the lease. If longer, the time remaining on the lease is used. A new lease will not be available +// before the break period has expired, but the lease may be held for longer than the break period. If this header does +// not appear with a break operation, a fixed-duration lease breaks after the remaining lease period elapses, and an +// infinite lease breaks immediately. ifModifiedSince is specify this header value to operate only on a blob if it has +// been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a +// blob if it has not been modified since the specified date/time. ifMatches is specify an ETag value to operate only +// on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching +// value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded in the +// analytics logs when storage analytics logging is enabled. +func (client blobClient) BreakLease(ctx context.Context, timeout *int32, breakPeriod *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*BlobBreakLeaseResponse, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.breakLeasePreparer(timeout, breakPeriod, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.breakLeaseResponder}, req) + if err != nil { + return nil, err + } + return resp.(*BlobBreakLeaseResponse), err +} + +// breakLeasePreparer prepares the BreakLease request. +func (client blobClient) breakLeasePreparer(timeout *int32, breakPeriod *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("PUT", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("comp", "lease") + req.URL.RawQuery = params.Encode() + if breakPeriod != nil { + req.Header.Set("x-ms-lease-break-period", strconv.FormatInt(int64(*breakPeriod), 10)) + } + if ifModifiedSince != nil { + req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifUnmodifiedSince != nil { + req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifMatches != nil { + req.Header.Set("If-Match", string(*ifMatches)) + } + if ifNoneMatch != nil { + req.Header.Set("If-None-Match", string(*ifNoneMatch)) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + req.Header.Set("x-ms-lease-action", "break") + return req, nil +} + +// breakLeaseResponder handles the response to the BreakLease request. +func (client blobClient) breakLeaseResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK, http.StatusAccepted) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &BlobBreakLeaseResponse{rawResponse: resp.Response()}, err +} + +// ChangeLease [Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete +// operations +// +// leaseID is if specified, the operation only succeeds if the container's lease is active and matches this ID. +// proposedLeaseID is proposed lease ID, in a GUID string format. The Blob service returns 400 (Invalid request) if the +// proposed lease ID is not in the correct format. See Guid Constructor (String) for a list of valid GUID string +// formats. timeout is the timeout parameter is expressed in seconds. For more information, see Setting +// Timeouts for Blob Service Operations. ifModifiedSince is specify this header value to operate only on a blob if +// it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only +// on a blob if it has not been modified since the specified date/time. ifMatches is specify an ETag value to operate +// only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a +// matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded +// in the analytics logs when storage analytics logging is enabled. +func (client blobClient) ChangeLease(ctx context.Context, leaseID string, proposedLeaseID string, timeout *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*BlobChangeLeaseResponse, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.changeLeasePreparer(leaseID, proposedLeaseID, timeout, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.changeLeaseResponder}, req) + if err != nil { + return nil, err + } + return resp.(*BlobChangeLeaseResponse), err +} + +// changeLeasePreparer prepares the ChangeLease request. +func (client blobClient) changeLeasePreparer(leaseID string, proposedLeaseID string, timeout *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("PUT", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("comp", "lease") + req.URL.RawQuery = params.Encode() + req.Header.Set("x-ms-lease-id", leaseID) + req.Header.Set("x-ms-proposed-lease-id", proposedLeaseID) + if ifModifiedSince != nil { + req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifUnmodifiedSince != nil { + req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifMatches != nil { + req.Header.Set("If-Match", string(*ifMatches)) + } + if ifNoneMatch != nil { + req.Header.Set("If-None-Match", string(*ifNoneMatch)) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + req.Header.Set("x-ms-lease-action", "change") + return req, nil +} + +// changeLeaseResponder handles the response to the ChangeLease request. +func (client blobClient) changeLeaseResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &BlobChangeLeaseResponse{rawResponse: resp.Response()}, err +} + +// CreateSnapshot the Create Snapshot operation creates a read-only snapshot of a blob +// +// timeout is the timeout parameter is expressed in seconds. For more information, see Setting +// Timeouts for Blob Service Operations. metadata is optional. Specifies a user-defined name-value pair associated +// with the blob. If no name-value pairs are specified, the operation will copy the metadata from the source blob or +// file to the destination blob. If one or more name-value pairs are specified, the destination blob is created with +// the specified metadata, and metadata is not copied from the source blob or file. Note that beginning with version +// 2009-09-19, metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing +// Containers, Blobs, and Metadata for more information. ifModifiedSince is specify this header value to operate only +// on a blob if it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to +// operate only on a blob if it has not been modified since the specified date/time. ifMatches is specify an ETag value +// to operate only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs +// without a matching value. leaseID is if specified, the operation only succeeds if the container's lease is active +// and matches this ID. requestID is provides a client-generated, opaque value with a 1 KB character limit that is +// recorded in the analytics logs when storage analytics logging is enabled. +func (client blobClient) CreateSnapshot(ctx context.Context, timeout *int32, metadata map[string]string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, leaseID *string, requestID *string) (*BlobCreateSnapshotResponse, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}, + {targetValue: metadata, + constraints: []constraint{{target: "metadata", name: null, rule: false, + chain: []constraint{{target: "metadata", name: pattern, rule: `^[a-zA-Z]+$`, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.createSnapshotPreparer(timeout, metadata, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, leaseID, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.createSnapshotResponder}, req) + if err != nil { + return nil, err + } + return resp.(*BlobCreateSnapshotResponse), err +} + +// createSnapshotPreparer prepares the CreateSnapshot request. +func (client blobClient) createSnapshotPreparer(timeout *int32, metadata map[string]string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, leaseID *string, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("PUT", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("comp", "snapshot") + req.URL.RawQuery = params.Encode() + if metadata != nil { + for k, v := range metadata { + req.Header.Set("x-ms-meta-"+k, v) + } + } + if ifModifiedSince != nil { + req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifUnmodifiedSince != nil { + req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifMatches != nil { + req.Header.Set("If-Match", string(*ifMatches)) + } + if ifNoneMatch != nil { + req.Header.Set("If-None-Match", string(*ifNoneMatch)) + } + if leaseID != nil { + req.Header.Set("x-ms-lease-id", *leaseID) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + return req, nil +} + +// createSnapshotResponder handles the response to the CreateSnapshot request. +func (client blobClient) createSnapshotResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK, http.StatusCreated) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &BlobCreateSnapshotResponse{rawResponse: resp.Response()}, err +} + +// Delete if the storage account's soft delete feature is disabled then, when a blob is deleted, it is permanently +// removed from the storage account. If the storage account's soft delete feature is enabled, then, when a blob is +// deleted, it is marked for deletion and becomes inaccessible immediately. However, the blob service retains the blob +// or snapshot for the number of days specified by the DeleteRetentionPolicy section of [Storage service properties] +// (Set-Blob-Service-Properties.md). After the specified number of days has passed, the blob's data is permanently +// removed from the storage account. Note that you continue to be charged for the soft-deleted blob's storage until it +// is permanently removed. Use the List Blobs API and specify the "include=deleted" query parameter to discover which +// blobs and snapshots have been soft deleted. You can then use the Undelete Blob API to restore a soft-deleted blob. +// All other operations on a soft-deleted blob or snapshot causes the service to return an HTTP status code of 404 +// (ResourceNotFound). +// +// snapshot is the snapshot parameter is an opaque DateTime value that, when present, specifies the blob snapshot to +// retrieve. For more information on working with blob snapshots, see Creating +// a Snapshot of a Blob. timeout is the timeout parameter is expressed in seconds. For more information, see Setting +// Timeouts for Blob Service Operations. leaseID is if specified, the operation only succeeds if the container's +// lease is active and matches this ID. deleteSnapshots is required if the blob has associated snapshots. Specify one +// of the following two options: include: Delete the base blob and all of its snapshots. only: Delete only the blob's +// snapshots and not the blob itself ifModifiedSince is specify this header value to operate only on a blob if it has +// been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a +// blob if it has not been modified since the specified date/time. ifMatches is specify an ETag value to operate only +// on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching +// value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded in the +// analytics logs when storage analytics logging is enabled. +func (client blobClient) Delete(ctx context.Context, snapshot *string, timeout *int32, leaseID *string, deleteSnapshots DeleteSnapshotsOptionType, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*BlobDeleteResponse, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.deletePreparer(snapshot, timeout, leaseID, deleteSnapshots, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.deleteResponder}, req) + if err != nil { + return nil, err + } + return resp.(*BlobDeleteResponse), err +} + +// deletePreparer prepares the Delete request. +func (client blobClient) deletePreparer(snapshot *string, timeout *int32, leaseID *string, deleteSnapshots DeleteSnapshotsOptionType, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("DELETE", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if snapshot != nil && len(*snapshot) > 0 { + params.Set("snapshot", *snapshot) + } + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + req.URL.RawQuery = params.Encode() + if leaseID != nil { + req.Header.Set("x-ms-lease-id", *leaseID) + } + if deleteSnapshots != DeleteSnapshotsOptionNone { + req.Header.Set("x-ms-delete-snapshots", string(deleteSnapshots)) + } + if ifModifiedSince != nil { + req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifUnmodifiedSince != nil { + req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifMatches != nil { + req.Header.Set("If-Match", string(*ifMatches)) + } + if ifNoneMatch != nil { + req.Header.Set("If-None-Match", string(*ifNoneMatch)) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + return req, nil +} + +// deleteResponder handles the response to the Delete request. +func (client blobClient) deleteResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK, http.StatusAccepted) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &BlobDeleteResponse{rawResponse: resp.Response()}, err +} + +// Download the Download operation reads or downloads a blob from the system, including its metadata and properties. +// You can also call Download to read a snapshot. +// +// snapshot is the snapshot parameter is an opaque DateTime value that, when present, specifies the blob snapshot to +// retrieve. For more information on working with blob snapshots, see Creating +// a Snapshot of a Blob. timeout is the timeout parameter is expressed in seconds. For more information, see Setting +// Timeouts for Blob Service Operations. rangeParameter is return only the bytes of the blob in the specified +// range. leaseID is if specified, the operation only succeeds if the container's lease is active and matches this ID. +// rangeGetContentMD5 is when set to true and specified together with the Range, the service returns the MD5 hash for +// the range, as long as the range is less than or equal to 4 MB in size. ifModifiedSince is specify this header value +// to operate only on a blob if it has been modified since the specified date/time. ifUnmodifiedSince is specify this +// header value to operate only on a blob if it has not been modified since the specified date/time. ifMatches is +// specify an ETag value to operate only on blobs with a matching value. ifNoneMatch is specify an ETag value to +// operate only on blobs without a matching value. requestID is provides a client-generated, opaque value with a 1 KB +// character limit that is recorded in the analytics logs when storage analytics logging is enabled. +func (client blobClient) Download(ctx context.Context, snapshot *string, timeout *int32, rangeParameter *string, leaseID *string, rangeGetContentMD5 *bool, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*downloadResponse, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.downloadPreparer(snapshot, timeout, rangeParameter, leaseID, rangeGetContentMD5, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.downloadResponder}, req) + if err != nil { + return nil, err + } + return resp.(*downloadResponse), err +} + +// downloadPreparer prepares the Download request. +func (client blobClient) downloadPreparer(snapshot *string, timeout *int32, rangeParameter *string, leaseID *string, rangeGetContentMD5 *bool, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("GET", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if snapshot != nil && len(*snapshot) > 0 { + params.Set("snapshot", *snapshot) + } + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + req.URL.RawQuery = params.Encode() + if rangeParameter != nil { + req.Header.Set("x-ms-range", *rangeParameter) + } + if leaseID != nil { + req.Header.Set("x-ms-lease-id", *leaseID) + } + if rangeGetContentMD5 != nil { + req.Header.Set("x-ms-range-get-content-md5", strconv.FormatBool(*rangeGetContentMD5)) + } + if ifModifiedSince != nil { + req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifUnmodifiedSince != nil { + req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifMatches != nil { + req.Header.Set("If-Match", string(*ifMatches)) + } + if ifNoneMatch != nil { + req.Header.Set("If-None-Match", string(*ifNoneMatch)) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + return req, nil +} + +// downloadResponder handles the response to the Download request. +func (client blobClient) downloadResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK, http.StatusPartialContent) + if resp == nil { + return nil, err + } + return &downloadResponse{rawResponse: resp.Response()}, err +} + +// GetProperties the Get Properties operation returns all user-defined metadata, standard HTTP properties, and system +// properties for the blob. It does not return the content of the blob. +// +// snapshot is the snapshot parameter is an opaque DateTime value that, when present, specifies the blob snapshot to +// retrieve. For more information on working with blob snapshots, see Creating +// a Snapshot of a Blob. timeout is the timeout parameter is expressed in seconds. For more information, see Setting +// Timeouts for Blob Service Operations. leaseID is if specified, the operation only succeeds if the container's +// lease is active and matches this ID. ifModifiedSince is specify this header value to operate only on a blob if it +// has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a +// blob if it has not been modified since the specified date/time. ifMatches is specify an ETag value to operate only +// on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching +// value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded in the +// analytics logs when storage analytics logging is enabled. +func (client blobClient) GetProperties(ctx context.Context, snapshot *string, timeout *int32, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*BlobGetPropertiesResponse, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.getPropertiesPreparer(snapshot, timeout, leaseID, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.getPropertiesResponder}, req) + if err != nil { + return nil, err + } + return resp.(*BlobGetPropertiesResponse), err +} + +// getPropertiesPreparer prepares the GetProperties request. +func (client blobClient) getPropertiesPreparer(snapshot *string, timeout *int32, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("HEAD", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if snapshot != nil && len(*snapshot) > 0 { + params.Set("snapshot", *snapshot) + } + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + req.URL.RawQuery = params.Encode() + if leaseID != nil { + req.Header.Set("x-ms-lease-id", *leaseID) + } + if ifModifiedSince != nil { + req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifUnmodifiedSince != nil { + req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifMatches != nil { + req.Header.Set("If-Match", string(*ifMatches)) + } + if ifNoneMatch != nil { + req.Header.Set("If-None-Match", string(*ifNoneMatch)) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + return req, nil +} + +// getPropertiesResponder handles the response to the GetProperties request. +func (client blobClient) getPropertiesResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &BlobGetPropertiesResponse{rawResponse: resp.Response()}, err +} + +// ReleaseLease [Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete +// operations +// +// leaseID is if specified, the operation only succeeds if the container's lease is active and matches this ID. timeout +// is the timeout parameter is expressed in seconds. For more information, see Setting +// Timeouts for Blob Service Operations. ifModifiedSince is specify this header value to operate only on a blob if +// it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only +// on a blob if it has not been modified since the specified date/time. ifMatches is specify an ETag value to operate +// only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a +// matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded +// in the analytics logs when storage analytics logging is enabled. +func (client blobClient) ReleaseLease(ctx context.Context, leaseID string, timeout *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*BlobReleaseLeaseResponse, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.releaseLeasePreparer(leaseID, timeout, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.releaseLeaseResponder}, req) + if err != nil { + return nil, err + } + return resp.(*BlobReleaseLeaseResponse), err +} + +// releaseLeasePreparer prepares the ReleaseLease request. +func (client blobClient) releaseLeasePreparer(leaseID string, timeout *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("PUT", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("comp", "lease") + req.URL.RawQuery = params.Encode() + req.Header.Set("x-ms-lease-id", leaseID) + if ifModifiedSince != nil { + req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifUnmodifiedSince != nil { + req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifMatches != nil { + req.Header.Set("If-Match", string(*ifMatches)) + } + if ifNoneMatch != nil { + req.Header.Set("If-None-Match", string(*ifNoneMatch)) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + req.Header.Set("x-ms-lease-action", "release") + return req, nil +} + +// releaseLeaseResponder handles the response to the ReleaseLease request. +func (client blobClient) releaseLeaseResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &BlobReleaseLeaseResponse{rawResponse: resp.Response()}, err +} + +// RenewLease [Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete +// operations +// +// leaseID is if specified, the operation only succeeds if the container's lease is active and matches this ID. timeout +// is the timeout parameter is expressed in seconds. For more information, see Setting +// Timeouts for Blob Service Operations. ifModifiedSince is specify this header value to operate only on a blob if +// it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only +// on a blob if it has not been modified since the specified date/time. ifMatches is specify an ETag value to operate +// only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a +// matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded +// in the analytics logs when storage analytics logging is enabled. +func (client blobClient) RenewLease(ctx context.Context, leaseID string, timeout *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*BlobRenewLeaseResponse, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.renewLeasePreparer(leaseID, timeout, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.renewLeaseResponder}, req) + if err != nil { + return nil, err + } + return resp.(*BlobRenewLeaseResponse), err +} + +// renewLeasePreparer prepares the RenewLease request. +func (client blobClient) renewLeasePreparer(leaseID string, timeout *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("PUT", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("comp", "lease") + req.URL.RawQuery = params.Encode() + req.Header.Set("x-ms-lease-id", leaseID) + if ifModifiedSince != nil { + req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifUnmodifiedSince != nil { + req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifMatches != nil { + req.Header.Set("If-Match", string(*ifMatches)) + } + if ifNoneMatch != nil { + req.Header.Set("If-None-Match", string(*ifNoneMatch)) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + req.Header.Set("x-ms-lease-action", "renew") + return req, nil +} + +// renewLeaseResponder handles the response to the RenewLease request. +func (client blobClient) renewLeaseResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &BlobRenewLeaseResponse{rawResponse: resp.Response()}, err +} + +// SetHTTPHeaders the Set HTTP Headers operation sets system properties on the blob +// +// timeout is the timeout parameter is expressed in seconds. For more information, see Setting +// Timeouts for Blob Service Operations. blobCacheControl is optional. Sets the blob's cache control. If specified, +// this property is stored with the blob and returned with a read request. blobContentType is optional. Sets the blob's +// content type. If specified, this property is stored with the blob and returned with a read request. blobContentMD5 +// is optional. An MD5 hash of the blob content. Note that this hash is not validated, as the hashes for the individual +// blocks were validated when each was uploaded. blobContentEncoding is optional. Sets the blob's content encoding. If +// specified, this property is stored with the blob and returned with a read request. blobContentLanguage is optional. +// Set the blob's content language. If specified, this property is stored with the blob and returned with a read +// request. leaseID is if specified, the operation only succeeds if the container's lease is active and matches this +// ID. ifModifiedSince is specify this header value to operate only on a blob if it has been modified since the +// specified date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if it has not been +// modified since the specified date/time. ifMatches is specify an ETag value to operate only on blobs with a matching +// value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. +// blobContentDisposition is optional. Sets the blob's Content-Disposition header. requestID is provides a +// client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage +// analytics logging is enabled. +func (client blobClient) SetHTTPHeaders(ctx context.Context, timeout *int32, blobCacheControl *string, blobContentType *string, blobContentMD5 []byte, blobContentEncoding *string, blobContentLanguage *string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, blobContentDisposition *string, requestID *string) (*BlobSetHTTPHeadersResponse, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.setHTTPHeadersPreparer(timeout, blobCacheControl, blobContentType, blobContentMD5, blobContentEncoding, blobContentLanguage, leaseID, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, blobContentDisposition, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.setHTTPHeadersResponder}, req) + if err != nil { + return nil, err + } + return resp.(*BlobSetHTTPHeadersResponse), err +} + +// setHTTPHeadersPreparer prepares the SetHTTPHeaders request. +func (client blobClient) setHTTPHeadersPreparer(timeout *int32, blobCacheControl *string, blobContentType *string, blobContentMD5 []byte, blobContentEncoding *string, blobContentLanguage *string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, blobContentDisposition *string, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("PUT", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("comp", "properties") + req.URL.RawQuery = params.Encode() + if blobCacheControl != nil { + req.Header.Set("x-ms-blob-cache-control", *blobCacheControl) + } + if blobContentType != nil { + req.Header.Set("x-ms-blob-content-type", *blobContentType) + } + if blobContentMD5 != nil { + req.Header.Set("x-ms-blob-content-md5", base64.StdEncoding.EncodeToString(blobContentMD5)) + } + if blobContentEncoding != nil { + req.Header.Set("x-ms-blob-content-encoding", *blobContentEncoding) + } + if blobContentLanguage != nil { + req.Header.Set("x-ms-blob-content-language", *blobContentLanguage) + } + if leaseID != nil { + req.Header.Set("x-ms-lease-id", *leaseID) + } + if ifModifiedSince != nil { + req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifUnmodifiedSince != nil { + req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifMatches != nil { + req.Header.Set("If-Match", string(*ifMatches)) + } + if ifNoneMatch != nil { + req.Header.Set("If-None-Match", string(*ifNoneMatch)) + } + if blobContentDisposition != nil { + req.Header.Set("x-ms-blob-content-disposition", *blobContentDisposition) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + return req, nil +} + +// setHTTPHeadersResponder handles the response to the SetHTTPHeaders request. +func (client blobClient) setHTTPHeadersResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &BlobSetHTTPHeadersResponse{rawResponse: resp.Response()}, err +} + +// SetMetadata the Set Blob Metadata operation sets user-defined metadata for the specified blob as one or more +// name-value pairs +// +// timeout is the timeout parameter is expressed in seconds. For more information, see Setting +// Timeouts for Blob Service Operations. metadata is optional. Specifies a user-defined name-value pair associated +// with the blob. If no name-value pairs are specified, the operation will copy the metadata from the source blob or +// file to the destination blob. If one or more name-value pairs are specified, the destination blob is created with +// the specified metadata, and metadata is not copied from the source blob or file. Note that beginning with version +// 2009-09-19, metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing +// Containers, Blobs, and Metadata for more information. leaseID is if specified, the operation only succeeds if the +// container's lease is active and matches this ID. ifModifiedSince is specify this header value to operate only on a +// blob if it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to +// operate only on a blob if it has not been modified since the specified date/time. ifMatches is specify an ETag value +// to operate only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs +// without a matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is +// recorded in the analytics logs when storage analytics logging is enabled. +func (client blobClient) SetMetadata(ctx context.Context, timeout *int32, metadata map[string]string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*BlobSetMetadataResponse, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}, + {targetValue: metadata, + constraints: []constraint{{target: "metadata", name: null, rule: false, + chain: []constraint{{target: "metadata", name: pattern, rule: `^[a-zA-Z]+$`, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.setMetadataPreparer(timeout, metadata, leaseID, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.setMetadataResponder}, req) + if err != nil { + return nil, err + } + return resp.(*BlobSetMetadataResponse), err +} + +// setMetadataPreparer prepares the SetMetadata request. +func (client blobClient) setMetadataPreparer(timeout *int32, metadata map[string]string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("PUT", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("comp", "metadata") + req.URL.RawQuery = params.Encode() + if metadata != nil { + for k, v := range metadata { + req.Header.Set("x-ms-meta-"+k, v) + } + } + if leaseID != nil { + req.Header.Set("x-ms-lease-id", *leaseID) + } + if ifModifiedSince != nil { + req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifUnmodifiedSince != nil { + req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifMatches != nil { + req.Header.Set("If-Match", string(*ifMatches)) + } + if ifNoneMatch != nil { + req.Header.Set("If-None-Match", string(*ifNoneMatch)) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + return req, nil +} + +// setMetadataResponder handles the response to the SetMetadata request. +func (client blobClient) setMetadataResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &BlobSetMetadataResponse{rawResponse: resp.Response()}, err +} + +// SetTier the Set Tier operation sets the tier on a blob. The operation is allowed on a page blob in a premium storage +// account and on a block blob in a blob storage account (locally redundant storage only). A premium page blob's tier +// determines the allowed size, IOPS, and bandwidth of the blob. A block blob's tier determines Hot/Cool/Archive +// storage type. This operation does not update the blob's ETag. +// +// tier is indicates the tier to be set on the blob. timeout is the timeout parameter is expressed in seconds. For more +// information, see Setting +// Timeouts for Blob Service Operations. requestID is provides a client-generated, opaque value with a 1 KB +// character limit that is recorded in the analytics logs when storage analytics logging is enabled. +func (client blobClient) SetTier(ctx context.Context, tier AccessTierType, timeout *int32, requestID *string) (*BlobSetTierResponse, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.setTierPreparer(tier, timeout, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.setTierResponder}, req) + if err != nil { + return nil, err + } + return resp.(*BlobSetTierResponse), err +} + +// setTierPreparer prepares the SetTier request. +func (client blobClient) setTierPreparer(tier AccessTierType, timeout *int32, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("PUT", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("comp", "tier") + req.URL.RawQuery = params.Encode() + req.Header.Set("x-ms-access-tier", string(tier)) + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + return req, nil +} + +// setTierResponder handles the response to the SetTier request. +func (client blobClient) setTierResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK, http.StatusAccepted) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &BlobSetTierResponse{rawResponse: resp.Response()}, err +} + +// StartCopyFromURL the Start Copy From URL operation copies a blob or an internet resource to a new blob. +// +// copySource is specifies the name of the source page blob snapshot. This value is a URL of up to 2 KB in length that +// specifies a page blob snapshot. The value should be URL-encoded as it would appear in a request URI. The source blob +// must either be public or must be authenticated via a shared access signature. timeout is the timeout parameter is +// expressed in seconds. For more information, see Setting +// Timeouts for Blob Service Operations. metadata is optional. Specifies a user-defined name-value pair associated +// with the blob. If no name-value pairs are specified, the operation will copy the metadata from the source blob or +// file to the destination blob. If one or more name-value pairs are specified, the destination blob is created with +// the specified metadata, and metadata is not copied from the source blob or file. Note that beginning with version +// 2009-09-19, metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing +// Containers, Blobs, and Metadata for more information. sourceIfModifiedSince is specify this header value to operate +// only on a blob if it has been modified since the specified date/time. sourceIfUnmodifiedSince is specify this header +// value to operate only on a blob if it has not been modified since the specified date/time. sourceIfMatches is +// specify an ETag value to operate only on blobs with a matching value. sourceIfNoneMatch is specify an ETag value to +// operate only on blobs without a matching value. ifModifiedSince is specify this header value to operate only on a +// blob if it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to +// operate only on a blob if it has not been modified since the specified date/time. ifMatches is specify an ETag value +// to operate only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs +// without a matching value. leaseID is if specified, the operation only succeeds if the container's lease is active +// and matches this ID. sourceLeaseID is specify this header to perform the operation only if the lease ID given +// matches the active lease ID of the source blob. requestID is provides a client-generated, opaque value with a 1 KB +// character limit that is recorded in the analytics logs when storage analytics logging is enabled. +func (client blobClient) StartCopyFromURL(ctx context.Context, copySource string, timeout *int32, metadata map[string]string, sourceIfModifiedSince *time.Time, sourceIfUnmodifiedSince *time.Time, sourceIfMatches *ETag, sourceIfNoneMatch *ETag, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, leaseID *string, sourceLeaseID *string, requestID *string) (*BlobStartCopyFromURLResponse, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}, + {targetValue: metadata, + constraints: []constraint{{target: "metadata", name: null, rule: false, + chain: []constraint{{target: "metadata", name: pattern, rule: `^[a-zA-Z]+$`, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.startCopyFromURLPreparer(copySource, timeout, metadata, sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatches, sourceIfNoneMatch, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, leaseID, sourceLeaseID, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.startCopyFromURLResponder}, req) + if err != nil { + return nil, err + } + return resp.(*BlobStartCopyFromURLResponse), err +} + +// startCopyFromURLPreparer prepares the StartCopyFromURL request. +func (client blobClient) startCopyFromURLPreparer(copySource string, timeout *int32, metadata map[string]string, sourceIfModifiedSince *time.Time, sourceIfUnmodifiedSince *time.Time, sourceIfMatches *ETag, sourceIfNoneMatch *ETag, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, leaseID *string, sourceLeaseID *string, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("PUT", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + req.URL.RawQuery = params.Encode() + if metadata != nil { + for k, v := range metadata { + req.Header.Set("x-ms-meta-"+k, v) + } + } + if sourceIfModifiedSince != nil { + req.Header.Set("x-ms-source-if-modified-since", (*sourceIfModifiedSince).In(gmt).Format(time.RFC1123)) + } + if sourceIfUnmodifiedSince != nil { + req.Header.Set("x-ms-source-if-unmodified-since", (*sourceIfUnmodifiedSince).In(gmt).Format(time.RFC1123)) + } + if sourceIfMatches != nil { + req.Header.Set("x-ms-source-if-match", string(*sourceIfMatches)) + } + if sourceIfNoneMatch != nil { + req.Header.Set("x-ms-source-if-none-match", string(*sourceIfNoneMatch)) + } + if ifModifiedSince != nil { + req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifUnmodifiedSince != nil { + req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifMatches != nil { + req.Header.Set("If-Match", string(*ifMatches)) + } + if ifNoneMatch != nil { + req.Header.Set("If-None-Match", string(*ifNoneMatch)) + } + req.Header.Set("x-ms-copy-source", copySource) + if leaseID != nil { + req.Header.Set("x-ms-lease-id", *leaseID) + } + if sourceLeaseID != nil { + req.Header.Set("x-ms-source-lease-id", *sourceLeaseID) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + return req, nil +} + +// startCopyFromURLResponder handles the response to the StartCopyFromURL request. +func (client blobClient) startCopyFromURLResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK, http.StatusAccepted) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &BlobStartCopyFromURLResponse{rawResponse: resp.Response()}, err +} + +// Undelete undelete a blob that was previously soft deleted +// +// timeout is the timeout parameter is expressed in seconds. For more information, see Setting +// Timeouts for Blob Service Operations. requestID is provides a client-generated, opaque value with a 1 KB +// character limit that is recorded in the analytics logs when storage analytics logging is enabled. +func (client blobClient) Undelete(ctx context.Context, timeout *int32, requestID *string) (*BlobUndeleteResponse, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.undeletePreparer(timeout, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.undeleteResponder}, req) + if err != nil { + return nil, err + } + return resp.(*BlobUndeleteResponse), err +} + +// undeletePreparer prepares the Undelete request. +func (client blobClient) undeletePreparer(timeout *int32, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("PUT", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("comp", "undelete") + req.URL.RawQuery = params.Encode() + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + return req, nil +} + +// undeleteResponder handles the response to the Undelete request. +func (client blobClient) undeleteResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &BlobUndeleteResponse{rawResponse: resp.Response()}, err +} diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_block_blob.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_block_blob.go new file mode 100644 index 0000000000..4e75dcea33 --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_block_blob.go @@ -0,0 +1,498 @@ +package azblob + +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +import ( + "bytes" + "context" + "encoding/base64" + "encoding/xml" + "github.com/Azure/azure-pipeline-go/pipeline" + "io" + "io/ioutil" + "net/http" + "net/url" + "strconv" + "time" +) + +// blockBlobClient is the client for the BlockBlob methods of the Azblob service. +type blockBlobClient struct { + managementClient +} + +// newBlockBlobClient creates an instance of the blockBlobClient client. +func newBlockBlobClient(url url.URL, p pipeline.Pipeline) blockBlobClient { + return blockBlobClient{newManagementClient(url, p)} +} + +// CommitBlockList the Commit Block List operation writes a blob by specifying the list of block IDs that make up the +// blob. In order to be written as part of a blob, a block must have been successfully written to the server in a prior +// Put Block operation. You can call Put Block List to update a blob by uploading only those blocks that have changed, +// then committing the new and existing blocks together. You can do this by specifying whether to commit a block from +// the committed block list or from the uncommitted block list, or to commit the most recently uploaded version of the +// block, whichever list it may belong to. +// +// timeout is the timeout parameter is expressed in seconds. For more information, see Setting +// Timeouts for Blob Service Operations. blobCacheControl is optional. Sets the blob's cache control. If specified, +// this property is stored with the blob and returned with a read request. blobContentType is optional. Sets the blob's +// content type. If specified, this property is stored with the blob and returned with a read request. +// blobContentEncoding is optional. Sets the blob's content encoding. If specified, this property is stored with the +// blob and returned with a read request. blobContentLanguage is optional. Set the blob's content language. If +// specified, this property is stored with the blob and returned with a read request. blobContentMD5 is optional. An +// MD5 hash of the blob content. Note that this hash is not validated, as the hashes for the individual blocks were +// validated when each was uploaded. metadata is optional. Specifies a user-defined name-value pair associated with the +// blob. If no name-value pairs are specified, the operation will copy the metadata from the source blob or file to the +// destination blob. If one or more name-value pairs are specified, the destination blob is created with the specified +// metadata, and metadata is not copied from the source blob or file. Note that beginning with version 2009-09-19, +// metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing Containers, Blobs, and +// Metadata for more information. leaseID is if specified, the operation only succeeds if the container's lease is +// active and matches this ID. blobContentDisposition is optional. Sets the blob's Content-Disposition header. +// ifModifiedSince is specify this header value to operate only on a blob if it has been modified since the specified +// date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if it has not been modified +// since the specified date/time. ifMatches is specify an ETag value to operate only on blobs with a matching value. +// ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. requestID is provides a +// client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage +// analytics logging is enabled. +func (client blockBlobClient) CommitBlockList(ctx context.Context, blocks BlockLookupList, timeout *int32, blobCacheControl *string, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, metadata map[string]string, leaseID *string, blobContentDisposition *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*BlockBlobCommitBlockListResponse, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}, + {targetValue: metadata, + constraints: []constraint{{target: "metadata", name: null, rule: false, + chain: []constraint{{target: "metadata", name: pattern, rule: `^[a-zA-Z]+$`, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.commitBlockListPreparer(blocks, timeout, blobCacheControl, blobContentType, blobContentEncoding, blobContentLanguage, blobContentMD5, metadata, leaseID, blobContentDisposition, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.commitBlockListResponder}, req) + if err != nil { + return nil, err + } + return resp.(*BlockBlobCommitBlockListResponse), err +} + +// commitBlockListPreparer prepares the CommitBlockList request. +func (client blockBlobClient) commitBlockListPreparer(blocks BlockLookupList, timeout *int32, blobCacheControl *string, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, metadata map[string]string, leaseID *string, blobContentDisposition *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("PUT", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("comp", "blocklist") + req.URL.RawQuery = params.Encode() + if blobCacheControl != nil { + req.Header.Set("x-ms-blob-cache-control", *blobCacheControl) + } + if blobContentType != nil { + req.Header.Set("x-ms-blob-content-type", *blobContentType) + } + if blobContentEncoding != nil { + req.Header.Set("x-ms-blob-content-encoding", *blobContentEncoding) + } + if blobContentLanguage != nil { + req.Header.Set("x-ms-blob-content-language", *blobContentLanguage) + } + if blobContentMD5 != nil { + req.Header.Set("x-ms-blob-content-md5", base64.StdEncoding.EncodeToString(blobContentMD5)) + } + if metadata != nil { + for k, v := range metadata { + req.Header.Set("x-ms-meta-"+k, v) + } + } + if leaseID != nil { + req.Header.Set("x-ms-lease-id", *leaseID) + } + if blobContentDisposition != nil { + req.Header.Set("x-ms-blob-content-disposition", *blobContentDisposition) + } + if ifModifiedSince != nil { + req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifUnmodifiedSince != nil { + req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifMatches != nil { + req.Header.Set("If-Match", string(*ifMatches)) + } + if ifNoneMatch != nil { + req.Header.Set("If-None-Match", string(*ifNoneMatch)) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + b, err := xml.Marshal(blocks) + if err != nil { + return req, pipeline.NewError(err, "failed to marshal request body") + } + req.Header.Set("Content-Type", "application/xml") + err = req.SetBody(bytes.NewReader(b)) + if err != nil { + return req, pipeline.NewError(err, "failed to set request body") + } + return req, nil +} + +// commitBlockListResponder handles the response to the CommitBlockList request. +func (client blockBlobClient) commitBlockListResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK, http.StatusCreated) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &BlockBlobCommitBlockListResponse{rawResponse: resp.Response()}, err +} + +// GetBlockList the Get Block List operation retrieves the list of blocks that have been uploaded as part of a block +// blob +// +// listType is specifies whether to return the list of committed blocks, the list of uncommitted blocks, or both lists +// together. snapshot is the snapshot parameter is an opaque DateTime value that, when present, specifies the blob +// snapshot to retrieve. For more information on working with blob snapshots, see Creating +// a Snapshot of a Blob. timeout is the timeout parameter is expressed in seconds. For more information, see Setting +// Timeouts for Blob Service Operations. leaseID is if specified, the operation only succeeds if the container's +// lease is active and matches this ID. requestID is provides a client-generated, opaque value with a 1 KB character +// limit that is recorded in the analytics logs when storage analytics logging is enabled. +func (client blockBlobClient) GetBlockList(ctx context.Context, listType BlockListType, snapshot *string, timeout *int32, leaseID *string, requestID *string) (*BlockList, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.getBlockListPreparer(listType, snapshot, timeout, leaseID, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.getBlockListResponder}, req) + if err != nil { + return nil, err + } + return resp.(*BlockList), err +} + +// getBlockListPreparer prepares the GetBlockList request. +func (client blockBlobClient) getBlockListPreparer(listType BlockListType, snapshot *string, timeout *int32, leaseID *string, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("GET", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if snapshot != nil && len(*snapshot) > 0 { + params.Set("snapshot", *snapshot) + } + params.Set("blocklisttype", string(listType)) + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("comp", "blocklist") + req.URL.RawQuery = params.Encode() + if leaseID != nil { + req.Header.Set("x-ms-lease-id", *leaseID) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + return req, nil +} + +// getBlockListResponder handles the response to the GetBlockList request. +func (client blockBlobClient) getBlockListResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK) + if resp == nil { + return nil, err + } + result := &BlockList{rawResponse: resp.Response()} + if err != nil { + return result, err + } + defer resp.Response().Body.Close() + b, err := ioutil.ReadAll(resp.Response().Body) + if err != nil { + return result, NewResponseError(err, resp.Response(), "failed to read response body") + } + if len(b) > 0 { + b = removeBOM(b) + err = xml.Unmarshal(b, result) + if err != nil { + return result, NewResponseError(err, resp.Response(), "failed to unmarshal response body") + } + } + return result, nil +} + +// StageBlock the Stage Block operation creates a new block to be committed as part of a blob +// +// blockID is a valid Base64 string value that identifies the block. Prior to encoding, the string must be less than or +// equal to 64 bytes in size. For a given blob, the length of the value specified for the blockid parameter must be the +// same size for each block. contentLength is the length of the request. body is initial data body will be closed upon +// successful return. Callers should ensure closure when receiving an error.timeout is the timeout parameter is +// expressed in seconds. For more information, see Setting +// Timeouts for Blob Service Operations. leaseID is if specified, the operation only succeeds if the container's +// lease is active and matches this ID. requestID is provides a client-generated, opaque value with a 1 KB character +// limit that is recorded in the analytics logs when storage analytics logging is enabled. +func (client blockBlobClient) StageBlock(ctx context.Context, blockID string, contentLength int64, body io.ReadSeeker, timeout *int32, leaseID *string, requestID *string) (*BlockBlobStageBlockResponse, error) { + if err := validate([]validation{ + {targetValue: body, + constraints: []constraint{{target: "body", name: null, rule: true, chain: nil}}}, + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.stageBlockPreparer(blockID, contentLength, body, timeout, leaseID, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.stageBlockResponder}, req) + if err != nil { + return nil, err + } + return resp.(*BlockBlobStageBlockResponse), err +} + +// stageBlockPreparer prepares the StageBlock request. +func (client blockBlobClient) stageBlockPreparer(blockID string, contentLength int64, body io.ReadSeeker, timeout *int32, leaseID *string, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("PUT", client.url, body) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + params.Set("blockid", blockID) + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("comp", "block") + req.URL.RawQuery = params.Encode() + req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10)) + if leaseID != nil { + req.Header.Set("x-ms-lease-id", *leaseID) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + return req, nil +} + +// stageBlockResponder handles the response to the StageBlock request. +func (client blockBlobClient) stageBlockResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK, http.StatusCreated) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &BlockBlobStageBlockResponse{rawResponse: resp.Response()}, err +} + +// StageBlockFromURL the Stage Block operation creates a new block to be committed as part of a blob where the contents +// are read from a URL. +// +// blockID is a valid Base64 string value that identifies the block. Prior to encoding, the string must be less than or +// equal to 64 bytes in size. For a given blob, the length of the value specified for the blockid parameter must be the +// same size for each block. contentLength is the length of the request. sourceURL is specifiy an URL to the copy +// source. sourceRange is bytes of source data in the specified range. sourceContentMD5 is specify the md5 calculated +// for the range of bytes that must be read from the copy source. timeout is the timeout parameter is expressed in +// seconds. For more information, see Setting +// Timeouts for Blob Service Operations. leaseID is if specified, the operation only succeeds if the container's +// lease is active and matches this ID. requestID is provides a client-generated, opaque value with a 1 KB character +// limit that is recorded in the analytics logs when storage analytics logging is enabled. +func (client blockBlobClient) StageBlockFromURL(ctx context.Context, blockID string, contentLength int64, sourceURL *string, sourceRange *string, sourceContentMD5 []byte, timeout *int32, leaseID *string, requestID *string) (*BlockBlobStageBlockFromURLResponse, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.stageBlockFromURLPreparer(blockID, contentLength, sourceURL, sourceRange, sourceContentMD5, timeout, leaseID, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.stageBlockFromURLResponder}, req) + if err != nil { + return nil, err + } + return resp.(*BlockBlobStageBlockFromURLResponse), err +} + +// stageBlockFromURLPreparer prepares the StageBlockFromURL request. +func (client blockBlobClient) stageBlockFromURLPreparer(blockID string, contentLength int64, sourceURL *string, sourceRange *string, sourceContentMD5 []byte, timeout *int32, leaseID *string, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("PUT", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + params.Set("blockid", blockID) + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("comp", "block") + req.URL.RawQuery = params.Encode() + req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10)) + if sourceURL != nil { + req.Header.Set("x-ms-copy-source", *sourceURL) + } + if sourceRange != nil { + req.Header.Set("x-ms-source-range", *sourceRange) + } + if sourceContentMD5 != nil { + req.Header.Set("x-ms-source-content-md5", base64.StdEncoding.EncodeToString(sourceContentMD5)) + } + if leaseID != nil { + req.Header.Set("x-ms-lease-id", *leaseID) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + return req, nil +} + +// stageBlockFromURLResponder handles the response to the StageBlockFromURL request. +func (client blockBlobClient) stageBlockFromURLResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK, http.StatusCreated) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &BlockBlobStageBlockFromURLResponse{rawResponse: resp.Response()}, err +} + +// Upload the Upload Block Blob operation updates the content of an existing block blob. Updating an existing block +// blob overwrites any existing metadata on the blob. Partial updates are not supported with Put Blob; the content of +// the existing blob is overwritten with the content of the new blob. To perform a partial update of the content of a +// block blob, use the Put Block List operation. +// +// body is initial data body will be closed upon successful return. Callers should ensure closure when receiving an +// error.contentLength is the length of the request. timeout is the timeout parameter is expressed in seconds. For more +// information, see Setting +// Timeouts for Blob Service Operations. blobContentType is optional. Sets the blob's content type. If specified, +// this property is stored with the blob and returned with a read request. blobContentEncoding is optional. Sets the +// blob's content encoding. If specified, this property is stored with the blob and returned with a read request. +// blobContentLanguage is optional. Set the blob's content language. If specified, this property is stored with the +// blob and returned with a read request. blobContentMD5 is optional. An MD5 hash of the blob content. Note that this +// hash is not validated, as the hashes for the individual blocks were validated when each was uploaded. +// blobCacheControl is optional. Sets the blob's cache control. If specified, this property is stored with the blob and +// returned with a read request. metadata is optional. Specifies a user-defined name-value pair associated with the +// blob. If no name-value pairs are specified, the operation will copy the metadata from the source blob or file to the +// destination blob. If one or more name-value pairs are specified, the destination blob is created with the specified +// metadata, and metadata is not copied from the source blob or file. Note that beginning with version 2009-09-19, +// metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing Containers, Blobs, and +// Metadata for more information. leaseID is if specified, the operation only succeeds if the container's lease is +// active and matches this ID. blobContentDisposition is optional. Sets the blob's Content-Disposition header. +// ifModifiedSince is specify this header value to operate only on a blob if it has been modified since the specified +// date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if it has not been modified +// since the specified date/time. ifMatches is specify an ETag value to operate only on blobs with a matching value. +// ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. requestID is provides a +// client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage +// analytics logging is enabled. +func (client blockBlobClient) Upload(ctx context.Context, body io.ReadSeeker, contentLength int64, timeout *int32, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*BlockBlobUploadResponse, error) { + if err := validate([]validation{ + {targetValue: body, + constraints: []constraint{{target: "body", name: null, rule: true, chain: nil}}}, + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}, + {targetValue: metadata, + constraints: []constraint{{target: "metadata", name: null, rule: false, + chain: []constraint{{target: "metadata", name: pattern, rule: `^[a-zA-Z]+$`, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.uploadPreparer(body, contentLength, timeout, blobContentType, blobContentEncoding, blobContentLanguage, blobContentMD5, blobCacheControl, metadata, leaseID, blobContentDisposition, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.uploadResponder}, req) + if err != nil { + return nil, err + } + return resp.(*BlockBlobUploadResponse), err +} + +// uploadPreparer prepares the Upload request. +func (client blockBlobClient) uploadPreparer(body io.ReadSeeker, contentLength int64, timeout *int32, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("PUT", client.url, body) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + req.URL.RawQuery = params.Encode() + req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10)) + if blobContentType != nil { + req.Header.Set("x-ms-blob-content-type", *blobContentType) + } + if blobContentEncoding != nil { + req.Header.Set("x-ms-blob-content-encoding", *blobContentEncoding) + } + if blobContentLanguage != nil { + req.Header.Set("x-ms-blob-content-language", *blobContentLanguage) + } + if blobContentMD5 != nil { + req.Header.Set("x-ms-blob-content-md5", base64.StdEncoding.EncodeToString(blobContentMD5)) + } + if blobCacheControl != nil { + req.Header.Set("x-ms-blob-cache-control", *blobCacheControl) + } + if metadata != nil { + for k, v := range metadata { + req.Header.Set("x-ms-meta-"+k, v) + } + } + if leaseID != nil { + req.Header.Set("x-ms-lease-id", *leaseID) + } + if blobContentDisposition != nil { + req.Header.Set("x-ms-blob-content-disposition", *blobContentDisposition) + } + if ifModifiedSince != nil { + req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifUnmodifiedSince != nil { + req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifMatches != nil { + req.Header.Set("If-Match", string(*ifMatches)) + } + if ifNoneMatch != nil { + req.Header.Set("If-None-Match", string(*ifNoneMatch)) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + req.Header.Set("x-ms-blob-type", "BlockBlob") + return req, nil +} + +// uploadResponder handles the response to the Upload request. +func (client blockBlobClient) uploadResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK, http.StatusCreated) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &BlockBlobUploadResponse{rawResponse: resp.Response()}, err +} diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_client.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_client.go new file mode 100644 index 0000000000..b42a79b157 --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_client.go @@ -0,0 +1,38 @@ +package azblob + +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +import ( + "github.com/Azure/azure-pipeline-go/pipeline" + "net/url" +) + +const ( + // ServiceVersion specifies the version of the operations used in this package. + ServiceVersion = "2018-03-28" +) + +// managementClient is the base client for Azblob. +type managementClient struct { + url url.URL + p pipeline.Pipeline +} + +// newManagementClient creates an instance of the managementClient client. +func newManagementClient(url url.URL, p pipeline.Pipeline) managementClient { + return managementClient{ + url: url, + p: p, + } +} + +// URL returns a copy of the URL for this client. +func (mc managementClient) URL() url.URL { + return mc.url +} + +// Pipeline returns the pipeline for this client. +func (mc managementClient) Pipeline() pipeline.Pipeline { + return mc.p +} diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_container.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_container.go new file mode 100644 index 0000000000..3e744fcbed --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_container.go @@ -0,0 +1,1006 @@ +package azblob + +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +import ( + "bytes" + "context" + "encoding/xml" + "io" + "io/ioutil" + "net/http" + "net/url" + "strconv" + "time" + + "github.com/Azure/azure-pipeline-go/pipeline" +) + +// containerClient is the client for the Container methods of the Azblob service. +type containerClient struct { + managementClient +} + +// newContainerClient creates an instance of the containerClient client. +func newContainerClient(url url.URL, p pipeline.Pipeline) containerClient { + return containerClient{newManagementClient(url, p)} +} + +// AcquireLease [Update] establishes and manages a lock on a container for delete operations. The lock duration can be +// 15 to 60 seconds, or can be infinite +// +// timeout is the timeout parameter is expressed in seconds. For more information, see Setting +// Timeouts for Blob Service Operations. duration is specifies the duration of the lease, in seconds, or negative +// one (-1) for a lease that never expires. A non-infinite lease can be between 15 and 60 seconds. A lease duration +// cannot be changed using renew or change. proposedLeaseID is proposed lease ID, in a GUID string format. The Blob +// service returns 400 (Invalid request) if the proposed lease ID is not in the correct format. See Guid Constructor +// (String) for a list of valid GUID string formats. ifModifiedSince is specify this header value to operate only on a +// blob if it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to +// operate only on a blob if it has not been modified since the specified date/time. requestID is provides a +// client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage +// analytics logging is enabled. +func (client containerClient) AcquireLease(ctx context.Context, timeout *int32, duration *int32, proposedLeaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, requestID *string) (*ContainerAcquireLeaseResponse, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.acquireLeasePreparer(timeout, duration, proposedLeaseID, ifModifiedSince, ifUnmodifiedSince, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.acquireLeaseResponder}, req) + if err != nil { + return nil, err + } + return resp.(*ContainerAcquireLeaseResponse), err +} + +// acquireLeasePreparer prepares the AcquireLease request. +func (client containerClient) acquireLeasePreparer(timeout *int32, duration *int32, proposedLeaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("PUT", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("comp", "lease") + params.Set("restype", "container") + req.URL.RawQuery = params.Encode() + if duration != nil { + req.Header.Set("x-ms-lease-duration", strconv.FormatInt(int64(*duration), 10)) + } + if proposedLeaseID != nil { + req.Header.Set("x-ms-proposed-lease-id", *proposedLeaseID) + } + if ifModifiedSince != nil { + req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifUnmodifiedSince != nil { + req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + req.Header.Set("x-ms-lease-action", "acquire") + return req, nil +} + +// acquireLeaseResponder handles the response to the AcquireLease request. +func (client containerClient) acquireLeaseResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK, http.StatusCreated) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &ContainerAcquireLeaseResponse{rawResponse: resp.Response()}, err +} + +// BreakLease [Update] establishes and manages a lock on a container for delete operations. The lock duration can be 15 +// to 60 seconds, or can be infinite +// +// timeout is the timeout parameter is expressed in seconds. For more information, see Setting +// Timeouts for Blob Service Operations. breakPeriod is for a break operation, proposed duration the lease should +// continue before it is broken, in seconds, between 0 and 60. This break period is only used if it is shorter than the +// time remaining on the lease. If longer, the time remaining on the lease is used. A new lease will not be available +// before the break period has expired, but the lease may be held for longer than the break period. If this header does +// not appear with a break operation, a fixed-duration lease breaks after the remaining lease period elapses, and an +// infinite lease breaks immediately. ifModifiedSince is specify this header value to operate only on a blob if it has +// been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a +// blob if it has not been modified since the specified date/time. requestID is provides a client-generated, opaque +// value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. +func (client containerClient) BreakLease(ctx context.Context, timeout *int32, breakPeriod *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, requestID *string) (*ContainerBreakLeaseResponse, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.breakLeasePreparer(timeout, breakPeriod, ifModifiedSince, ifUnmodifiedSince, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.breakLeaseResponder}, req) + if err != nil { + return nil, err + } + return resp.(*ContainerBreakLeaseResponse), err +} + +// breakLeasePreparer prepares the BreakLease request. +func (client containerClient) breakLeasePreparer(timeout *int32, breakPeriod *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("PUT", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("comp", "lease") + params.Set("restype", "container") + req.URL.RawQuery = params.Encode() + if breakPeriod != nil { + req.Header.Set("x-ms-lease-break-period", strconv.FormatInt(int64(*breakPeriod), 10)) + } + if ifModifiedSince != nil { + req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifUnmodifiedSince != nil { + req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + req.Header.Set("x-ms-lease-action", "break") + return req, nil +} + +// breakLeaseResponder handles the response to the BreakLease request. +func (client containerClient) breakLeaseResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK, http.StatusAccepted) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &ContainerBreakLeaseResponse{rawResponse: resp.Response()}, err +} + +// ChangeLease [Update] establishes and manages a lock on a container for delete operations. The lock duration can be +// 15 to 60 seconds, or can be infinite +// +// leaseID is if specified, the operation only succeeds if the container's lease is active and matches this ID. +// proposedLeaseID is proposed lease ID, in a GUID string format. The Blob service returns 400 (Invalid request) if the +// proposed lease ID is not in the correct format. See Guid Constructor (String) for a list of valid GUID string +// formats. timeout is the timeout parameter is expressed in seconds. For more information, see Setting +// Timeouts for Blob Service Operations. ifModifiedSince is specify this header value to operate only on a blob if +// it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only +// on a blob if it has not been modified since the specified date/time. requestID is provides a client-generated, +// opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is +// enabled. +func (client containerClient) ChangeLease(ctx context.Context, leaseID string, proposedLeaseID string, timeout *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, requestID *string) (*ContainerChangeLeaseResponse, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.changeLeasePreparer(leaseID, proposedLeaseID, timeout, ifModifiedSince, ifUnmodifiedSince, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.changeLeaseResponder}, req) + if err != nil { + return nil, err + } + return resp.(*ContainerChangeLeaseResponse), err +} + +// changeLeasePreparer prepares the ChangeLease request. +func (client containerClient) changeLeasePreparer(leaseID string, proposedLeaseID string, timeout *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("PUT", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("comp", "lease") + params.Set("restype", "container") + req.URL.RawQuery = params.Encode() + req.Header.Set("x-ms-lease-id", leaseID) + req.Header.Set("x-ms-proposed-lease-id", proposedLeaseID) + if ifModifiedSince != nil { + req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifUnmodifiedSince != nil { + req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + req.Header.Set("x-ms-lease-action", "change") + return req, nil +} + +// changeLeaseResponder handles the response to the ChangeLease request. +func (client containerClient) changeLeaseResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &ContainerChangeLeaseResponse{rawResponse: resp.Response()}, err +} + +// Create creates a new container under the specified account. If the container with the same name already exists, the +// operation fails +// +// timeout is the timeout parameter is expressed in seconds. For more information, see Setting +// Timeouts for Blob Service Operations. metadata is optional. Specifies a user-defined name-value pair associated +// with the blob. If no name-value pairs are specified, the operation will copy the metadata from the source blob or +// file to the destination blob. If one or more name-value pairs are specified, the destination blob is created with +// the specified metadata, and metadata is not copied from the source blob or file. Note that beginning with version +// 2009-09-19, metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing +// Containers, Blobs, and Metadata for more information. access is specifies whether data in the container may be +// accessed publicly and the level of access requestID is provides a client-generated, opaque value with a 1 KB +// character limit that is recorded in the analytics logs when storage analytics logging is enabled. +func (client containerClient) Create(ctx context.Context, timeout *int32, metadata map[string]string, access PublicAccessType, requestID *string) (*ContainerCreateResponse, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}, + {targetValue: metadata, + constraints: []constraint{{target: "metadata", name: null, rule: false, + chain: []constraint{{target: "metadata", name: pattern, rule: `^[a-zA-Z]+$`, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.createPreparer(timeout, metadata, access, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.createResponder}, req) + if err != nil { + return nil, err + } + return resp.(*ContainerCreateResponse), err +} + +// createPreparer prepares the Create request. +func (client containerClient) createPreparer(timeout *int32, metadata map[string]string, access PublicAccessType, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("PUT", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("restype", "container") + req.URL.RawQuery = params.Encode() + if metadata != nil { + for k, v := range metadata { + req.Header.Set("x-ms-meta-"+k, v) + } + } + if access != PublicAccessNone { + req.Header.Set("x-ms-blob-public-access", string(access)) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + return req, nil +} + +// createResponder handles the response to the Create request. +func (client containerClient) createResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK, http.StatusCreated) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &ContainerCreateResponse{rawResponse: resp.Response()}, err +} + +// Delete operation marks the specified container for deletion. The container and any blobs contained within it are +// later deleted during garbage collection +// +// timeout is the timeout parameter is expressed in seconds. For more information, see Setting +// Timeouts for Blob Service Operations. leaseID is if specified, the operation only succeeds if the container's +// lease is active and matches this ID. ifModifiedSince is specify this header value to operate only on a blob if it +// has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a +// blob if it has not been modified since the specified date/time. requestID is provides a client-generated, opaque +// value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. +func (client containerClient) Delete(ctx context.Context, timeout *int32, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, requestID *string) (*ContainerDeleteResponse, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.deletePreparer(timeout, leaseID, ifModifiedSince, ifUnmodifiedSince, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.deleteResponder}, req) + if err != nil { + return nil, err + } + return resp.(*ContainerDeleteResponse), err +} + +// deletePreparer prepares the Delete request. +func (client containerClient) deletePreparer(timeout *int32, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("DELETE", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("restype", "container") + req.URL.RawQuery = params.Encode() + if leaseID != nil { + req.Header.Set("x-ms-lease-id", *leaseID) + } + if ifModifiedSince != nil { + req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifUnmodifiedSince != nil { + req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + return req, nil +} + +// deleteResponder handles the response to the Delete request. +func (client containerClient) deleteResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK, http.StatusAccepted) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &ContainerDeleteResponse{rawResponse: resp.Response()}, err +} + +// GetAccessPolicy gets the permissions for the specified container. The permissions indicate whether container data +// may be accessed publicly. +// +// timeout is the timeout parameter is expressed in seconds. For more information, see Setting +// Timeouts for Blob Service Operations. leaseID is if specified, the operation only succeeds if the container's +// lease is active and matches this ID. requestID is provides a client-generated, opaque value with a 1 KB character +// limit that is recorded in the analytics logs when storage analytics logging is enabled. +func (client containerClient) GetAccessPolicy(ctx context.Context, timeout *int32, leaseID *string, requestID *string) (*SignedIdentifiers, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.getAccessPolicyPreparer(timeout, leaseID, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.getAccessPolicyResponder}, req) + if err != nil { + return nil, err + } + return resp.(*SignedIdentifiers), err +} + +// getAccessPolicyPreparer prepares the GetAccessPolicy request. +func (client containerClient) getAccessPolicyPreparer(timeout *int32, leaseID *string, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("GET", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("restype", "container") + params.Set("comp", "acl") + req.URL.RawQuery = params.Encode() + if leaseID != nil { + req.Header.Set("x-ms-lease-id", *leaseID) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + return req, nil +} + +// getAccessPolicyResponder handles the response to the GetAccessPolicy request. +func (client containerClient) getAccessPolicyResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK) + if resp == nil { + return nil, err + } + result := &SignedIdentifiers{rawResponse: resp.Response()} + if err != nil { + return result, err + } + defer resp.Response().Body.Close() + b, err := ioutil.ReadAll(resp.Response().Body) + if err != nil { + return result, NewResponseError(err, resp.Response(), "failed to read response body") + } + if len(b) > 0 { + b = removeBOM(b) + err = xml.Unmarshal(b, result) + if err != nil { + return result, NewResponseError(err, resp.Response(), "failed to unmarshal response body") + } + } + return result, nil +} + +// GetProperties returns all user-defined metadata and system properties for the specified container. The data returned +// does not include the container's list of blobs +// +// timeout is the timeout parameter is expressed in seconds. For more information, see Setting +// Timeouts for Blob Service Operations. leaseID is if specified, the operation only succeeds if the container's +// lease is active and matches this ID. requestID is provides a client-generated, opaque value with a 1 KB character +// limit that is recorded in the analytics logs when storage analytics logging is enabled. +func (client containerClient) GetProperties(ctx context.Context, timeout *int32, leaseID *string, requestID *string) (*ContainerGetPropertiesResponse, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.getPropertiesPreparer(timeout, leaseID, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.getPropertiesResponder}, req) + if err != nil { + return nil, err + } + return resp.(*ContainerGetPropertiesResponse), err +} + +// getPropertiesPreparer prepares the GetProperties request. +func (client containerClient) getPropertiesPreparer(timeout *int32, leaseID *string, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("GET", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("restype", "container") + req.URL.RawQuery = params.Encode() + if leaseID != nil { + req.Header.Set("x-ms-lease-id", *leaseID) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + return req, nil +} + +// getPropertiesResponder handles the response to the GetProperties request. +func (client containerClient) getPropertiesResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &ContainerGetPropertiesResponse{rawResponse: resp.Response()}, err +} + +// ListBlobFlatSegment [Update] The List Blobs operation returns a list of the blobs under the specified container +// +// prefix is filters the results to return only containers whose name begins with the specified prefix. marker is a +// string value that identifies the portion of the list of containers to be returned with the next listing operation. +// The operation returns the NextMarker value within the response body if the listing operation did not return all +// containers remaining to be listed with the current page. The NextMarker value can be used as the value for the +// marker parameter in a subsequent call to request the next page of list items. The marker value is opaque to the +// client. maxresults is specifies the maximum number of containers to return. If the request does not specify +// maxresults, or specifies a value greater than 5000, the server will return up to 5000 items. Note that if the +// listing operation crosses a partition boundary, then the service will return a continuation token for retrieving the +// remainder of the results. For this reason, it is possible that the service will return fewer results than specified +// by maxresults, or than the default of 5000. include is include this parameter to specify one or more datasets to +// include in the response. timeout is the timeout parameter is expressed in seconds. For more information, see Setting +// Timeouts for Blob Service Operations. requestID is provides a client-generated, opaque value with a 1 KB +// character limit that is recorded in the analytics logs when storage analytics logging is enabled. +func (client containerClient) ListBlobFlatSegment(ctx context.Context, prefix *string, marker *string, maxresults *int32, include []ListBlobsIncludeItemType, timeout *int32, requestID *string) (*ListBlobsFlatSegmentResponse, error) { + if err := validate([]validation{ + {targetValue: maxresults, + constraints: []constraint{{target: "maxresults", name: null, rule: false, + chain: []constraint{{target: "maxresults", name: inclusiveMinimum, rule: 1, chain: nil}}}}}, + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.listBlobFlatSegmentPreparer(prefix, marker, maxresults, include, timeout, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.listBlobFlatSegmentResponder}, req) + if err != nil { + return nil, err + } + return resp.(*ListBlobsFlatSegmentResponse), err +} + +// listBlobFlatSegmentPreparer prepares the ListBlobFlatSegment request. +func (client containerClient) listBlobFlatSegmentPreparer(prefix *string, marker *string, maxresults *int32, include []ListBlobsIncludeItemType, timeout *int32, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("GET", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if prefix != nil && len(*prefix) > 0 { + params.Set("prefix", *prefix) + } + if marker != nil && len(*marker) > 0 { + params.Set("marker", *marker) + } + if maxresults != nil { + params.Set("maxresults", strconv.FormatInt(int64(*maxresults), 10)) + } + if include != nil && len(include) > 0 { + params.Set("include", joinConst(include, ",")) + } + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("restype", "container") + params.Set("comp", "list") + req.URL.RawQuery = params.Encode() + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + return req, nil +} + +// listBlobFlatSegmentResponder handles the response to the ListBlobFlatSegment request. +func (client containerClient) listBlobFlatSegmentResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK) + if resp == nil { + return nil, err + } + result := &ListBlobsFlatSegmentResponse{rawResponse: resp.Response()} + if err != nil { + return result, err + } + defer resp.Response().Body.Close() + b, err := ioutil.ReadAll(resp.Response().Body) + if err != nil { + return result, NewResponseError(err, resp.Response(), "failed to read response body") + } + if len(b) > 0 { + b = removeBOM(b) + err = xml.Unmarshal(b, result) + if err != nil { + return result, NewResponseError(err, resp.Response(), "failed to unmarshal response body") + } + } + return result, nil +} + +// ListBlobHierarchySegment [Update] The List Blobs operation returns a list of the blobs under the specified container +// +// delimiter is when the request includes this parameter, the operation returns a BlobPrefix element in the response +// body that acts as a placeholder for all blobs whose names begin with the same substring up to the appearance of the +// delimiter character. The delimiter may be a single character or a string. prefix is filters the results to return +// only containers whose name begins with the specified prefix. marker is a string value that identifies the portion of +// the list of containers to be returned with the next listing operation. The operation returns the NextMarker value +// within the response body if the listing operation did not return all containers remaining to be listed with the +// current page. The NextMarker value can be used as the value for the marker parameter in a subsequent call to request +// the next page of list items. The marker value is opaque to the client. maxresults is specifies the maximum number of +// containers to return. If the request does not specify maxresults, or specifies a value greater than 5000, the server +// will return up to 5000 items. Note that if the listing operation crosses a partition boundary, then the service will +// return a continuation token for retrieving the remainder of the results. For this reason, it is possible that the +// service will return fewer results than specified by maxresults, or than the default of 5000. include is include this +// parameter to specify one or more datasets to include in the response. timeout is the timeout parameter is expressed +// in seconds. For more information, see Setting +// Timeouts for Blob Service Operations. requestID is provides a client-generated, opaque value with a 1 KB +// character limit that is recorded in the analytics logs when storage analytics logging is enabled. +func (client containerClient) ListBlobHierarchySegment(ctx context.Context, delimiter string, prefix *string, marker *string, maxresults *int32, include []ListBlobsIncludeItemType, timeout *int32, requestID *string) (*ListBlobsHierarchySegmentResponse, error) { + if err := validate([]validation{ + {targetValue: maxresults, + constraints: []constraint{{target: "maxresults", name: null, rule: false, + chain: []constraint{{target: "maxresults", name: inclusiveMinimum, rule: 1, chain: nil}}}}}, + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.listBlobHierarchySegmentPreparer(delimiter, prefix, marker, maxresults, include, timeout, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.listBlobHierarchySegmentResponder}, req) + if err != nil { + return nil, err + } + return resp.(*ListBlobsHierarchySegmentResponse), err +} + +// listBlobHierarchySegmentPreparer prepares the ListBlobHierarchySegment request. +func (client containerClient) listBlobHierarchySegmentPreparer(delimiter string, prefix *string, marker *string, maxresults *int32, include []ListBlobsIncludeItemType, timeout *int32, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("GET", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if prefix != nil && len(*prefix) > 0 { + params.Set("prefix", *prefix) + } + params.Set("delimiter", delimiter) + if marker != nil && len(*marker) > 0 { + params.Set("marker", *marker) + } + if maxresults != nil { + params.Set("maxresults", strconv.FormatInt(int64(*maxresults), 10)) + } + if include != nil && len(include) > 0 { + params.Set("include", joinConst(include, ",")) + } + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("restype", "container") + params.Set("comp", "list") + req.URL.RawQuery = params.Encode() + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + return req, nil +} + +// listBlobHierarchySegmentResponder handles the response to the ListBlobHierarchySegment request. +func (client containerClient) listBlobHierarchySegmentResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK) + if resp == nil { + return nil, err + } + result := &ListBlobsHierarchySegmentResponse{rawResponse: resp.Response()} + if err != nil { + return result, err + } + defer resp.Response().Body.Close() + b, err := ioutil.ReadAll(resp.Response().Body) + if err != nil { + return result, NewResponseError(err, resp.Response(), "failed to read response body") + } + if len(b) > 0 { + b = removeBOM(b) + err = xml.Unmarshal(b, result) + if err != nil { + return result, NewResponseError(err, resp.Response(), "failed to unmarshal response body") + } + } + return result, nil +} + +// ReleaseLease [Update] establishes and manages a lock on a container for delete operations. The lock duration can be +// 15 to 60 seconds, or can be infinite +// +// leaseID is if specified, the operation only succeeds if the container's lease is active and matches this ID. timeout +// is the timeout parameter is expressed in seconds. For more information, see Setting +// Timeouts for Blob Service Operations. ifModifiedSince is specify this header value to operate only on a blob if +// it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only +// on a blob if it has not been modified since the specified date/time. requestID is provides a client-generated, +// opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is +// enabled. +func (client containerClient) ReleaseLease(ctx context.Context, leaseID string, timeout *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, requestID *string) (*ContainerReleaseLeaseResponse, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.releaseLeasePreparer(leaseID, timeout, ifModifiedSince, ifUnmodifiedSince, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.releaseLeaseResponder}, req) + if err != nil { + return nil, err + } + return resp.(*ContainerReleaseLeaseResponse), err +} + +// releaseLeasePreparer prepares the ReleaseLease request. +func (client containerClient) releaseLeasePreparer(leaseID string, timeout *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("PUT", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("comp", "lease") + params.Set("restype", "container") + req.URL.RawQuery = params.Encode() + req.Header.Set("x-ms-lease-id", leaseID) + if ifModifiedSince != nil { + req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifUnmodifiedSince != nil { + req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + req.Header.Set("x-ms-lease-action", "release") + return req, nil +} + +// releaseLeaseResponder handles the response to the ReleaseLease request. +func (client containerClient) releaseLeaseResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &ContainerReleaseLeaseResponse{rawResponse: resp.Response()}, err +} + +// RenewLease [Update] establishes and manages a lock on a container for delete operations. The lock duration can be 15 +// to 60 seconds, or can be infinite +// +// leaseID is if specified, the operation only succeeds if the container's lease is active and matches this ID. timeout +// is the timeout parameter is expressed in seconds. For more information, see Setting +// Timeouts for Blob Service Operations. ifModifiedSince is specify this header value to operate only on a blob if +// it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only +// on a blob if it has not been modified since the specified date/time. requestID is provides a client-generated, +// opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is +// enabled. +func (client containerClient) RenewLease(ctx context.Context, leaseID string, timeout *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, requestID *string) (*ContainerRenewLeaseResponse, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.renewLeasePreparer(leaseID, timeout, ifModifiedSince, ifUnmodifiedSince, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.renewLeaseResponder}, req) + if err != nil { + return nil, err + } + return resp.(*ContainerRenewLeaseResponse), err +} + +// renewLeasePreparer prepares the RenewLease request. +func (client containerClient) renewLeasePreparer(leaseID string, timeout *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("PUT", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("comp", "lease") + params.Set("restype", "container") + req.URL.RawQuery = params.Encode() + req.Header.Set("x-ms-lease-id", leaseID) + if ifModifiedSince != nil { + req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifUnmodifiedSince != nil { + req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + req.Header.Set("x-ms-lease-action", "renew") + return req, nil +} + +// renewLeaseResponder handles the response to the RenewLease request. +func (client containerClient) renewLeaseResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &ContainerRenewLeaseResponse{rawResponse: resp.Response()}, err +} + +// SetAccessPolicy sets the permissions for the specified container. The permissions indicate whether blobs in a +// container may be accessed publicly. +// +// containerACL is the acls for the container timeout is the timeout parameter is expressed in seconds. For more +// information, see Setting +// Timeouts for Blob Service Operations. leaseID is if specified, the operation only succeeds if the container's +// lease is active and matches this ID. access is specifies whether data in the container may be accessed publicly and +// the level of access ifModifiedSince is specify this header value to operate only on a blob if it has been modified +// since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if it has +// not been modified since the specified date/time. requestID is provides a client-generated, opaque value with a 1 KB +// character limit that is recorded in the analytics logs when storage analytics logging is enabled. +func (client containerClient) SetAccessPolicy(ctx context.Context, containerACL []SignedIdentifier, timeout *int32, leaseID *string, access PublicAccessType, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, requestID *string) (*ContainerSetAccessPolicyResponse, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.setAccessPolicyPreparer(containerACL, timeout, leaseID, access, ifModifiedSince, ifUnmodifiedSince, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.setAccessPolicyResponder}, req) + if err != nil { + return nil, err + } + return resp.(*ContainerSetAccessPolicyResponse), err +} + +// setAccessPolicyPreparer prepares the SetAccessPolicy request. +func (client containerClient) setAccessPolicyPreparer(containerACL []SignedIdentifier, timeout *int32, leaseID *string, access PublicAccessType, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("PUT", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("restype", "container") + params.Set("comp", "acl") + req.URL.RawQuery = params.Encode() + if leaseID != nil { + req.Header.Set("x-ms-lease-id", *leaseID) + } + if access != PublicAccessNone { + req.Header.Set("x-ms-blob-public-access", string(access)) + } + if ifModifiedSince != nil { + req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifUnmodifiedSince != nil { + req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + b, err := xml.Marshal(SignedIdentifiers{Items: containerACL}) + if err != nil { + return req, pipeline.NewError(err, "failed to marshal request body") + } + req.Header.Set("Content-Type", "application/xml") + err = req.SetBody(bytes.NewReader(b)) + if err != nil { + return req, pipeline.NewError(err, "failed to set request body") + } + return req, nil +} + +// setAccessPolicyResponder handles the response to the SetAccessPolicy request. +func (client containerClient) setAccessPolicyResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &ContainerSetAccessPolicyResponse{rawResponse: resp.Response()}, err +} + +// SetMetadata operation sets one or more user-defined name-value pairs for the specified container. +// +// timeout is the timeout parameter is expressed in seconds. For more information, see Setting +// Timeouts for Blob Service Operations. leaseID is if specified, the operation only succeeds if the container's +// lease is active and matches this ID. metadata is optional. Specifies a user-defined name-value pair associated with +// the blob. If no name-value pairs are specified, the operation will copy the metadata from the source blob or file to +// the destination blob. If one or more name-value pairs are specified, the destination blob is created with the +// specified metadata, and metadata is not copied from the source blob or file. Note that beginning with version +// 2009-09-19, metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing +// Containers, Blobs, and Metadata for more information. ifModifiedSince is specify this header value to operate only +// on a blob if it has been modified since the specified date/time. requestID is provides a client-generated, opaque +// value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. +func (client containerClient) SetMetadata(ctx context.Context, timeout *int32, leaseID *string, metadata map[string]string, ifModifiedSince *time.Time, requestID *string) (*ContainerSetMetadataResponse, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}, + {targetValue: metadata, + constraints: []constraint{{target: "metadata", name: null, rule: false, + chain: []constraint{{target: "metadata", name: pattern, rule: `^[a-zA-Z]+$`, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.setMetadataPreparer(timeout, leaseID, metadata, ifModifiedSince, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.setMetadataResponder}, req) + if err != nil { + return nil, err + } + return resp.(*ContainerSetMetadataResponse), err +} + +// setMetadataPreparer prepares the SetMetadata request. +func (client containerClient) setMetadataPreparer(timeout *int32, leaseID *string, metadata map[string]string, ifModifiedSince *time.Time, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("PUT", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("restype", "container") + params.Set("comp", "metadata") + req.URL.RawQuery = params.Encode() + if leaseID != nil { + req.Header.Set("x-ms-lease-id", *leaseID) + } + if metadata != nil { + for k, v := range metadata { + req.Header.Set("x-ms-meta-"+k, v) + } + } + if ifModifiedSince != nil { + req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + return req, nil +} + +// setMetadataResponder handles the response to the SetMetadata request. +func (client containerClient) setMetadataResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &ContainerSetMetadataResponse{rawResponse: resp.Response()}, err +} diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_models.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_models.go new file mode 100644 index 0000000000..3d8114ae6b --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_models.go @@ -0,0 +1,4501 @@ +package azblob + +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +import ( + "encoding/base64" + "encoding/xml" + "io" + "net/http" + "reflect" + "strconv" + "strings" + "time" + "unsafe" +) + +// ETag is an entity tag. +type ETag string + +const ( + // ETagNone represents an empty entity tag. + ETagNone ETag = "" + + // ETagAny matches any entity tag. + ETagAny ETag = "*" +) + +// Metadata contains metadata key/value pairs. +type Metadata map[string]string + +const mdPrefix = "x-ms-meta-" + +const mdPrefixLen = len(mdPrefix) + +// UnmarshalXML implements the xml.Unmarshaler interface for Metadata. +func (md *Metadata) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + tokName := "" + for t, err := d.Token(); err == nil; t, err = d.Token() { + switch tt := t.(type) { + case xml.StartElement: + tokName = strings.ToLower(tt.Name.Local) + break + case xml.CharData: + if *md == nil { + *md = Metadata{} + } + (*md)[tokName] = string(tt) + break + } + } + return nil +} + +// Marker represents an opaque value used in paged responses. +type Marker struct { + val *string +} + +// NotDone returns true if the list enumeration should be started or is not yet complete. Specifically, NotDone returns true +// for a just-initialized (zero value) Marker indicating that you should make an initial request to get a result portion from +// the service. NotDone also returns true whenever the service returns an interim result portion. NotDone returns false only +// after the service has returned the final result portion. +func (m Marker) NotDone() bool { + return m.val == nil || *m.val != "" +} + +// UnmarshalXML implements the xml.Unmarshaler interface for Marker. +func (m *Marker) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + var out string + err := d.DecodeElement(&out, &start) + m.val = &out + return err +} + +// concatenates a slice of const values with the specified separator between each item +func joinConst(s interface{}, sep string) string { + v := reflect.ValueOf(s) + if v.Kind() != reflect.Slice && v.Kind() != reflect.Array { + panic("s wasn't a slice or array") + } + ss := make([]string, 0, v.Len()) + for i := 0; i < v.Len(); i++ { + ss = append(ss, v.Index(i).String()) + } + return strings.Join(ss, sep) +} + +// AccessTierType enumerates the values for access tier type. +type AccessTierType string + +const ( + // AccessTierArchive ... + AccessTierArchive AccessTierType = "Archive" + // AccessTierCool ... + AccessTierCool AccessTierType = "Cool" + // AccessTierHot ... + AccessTierHot AccessTierType = "Hot" + // AccessTierNone represents an empty AccessTierType. + AccessTierNone AccessTierType = "" + // AccessTierP10 ... + AccessTierP10 AccessTierType = "P10" + // AccessTierP20 ... + AccessTierP20 AccessTierType = "P20" + // AccessTierP30 ... + AccessTierP30 AccessTierType = "P30" + // AccessTierP4 ... + AccessTierP4 AccessTierType = "P4" + // AccessTierP40 ... + AccessTierP40 AccessTierType = "P40" + // AccessTierP50 ... + AccessTierP50 AccessTierType = "P50" + // AccessTierP6 ... + AccessTierP6 AccessTierType = "P6" +) + +// PossibleAccessTierTypeValues returns an array of possible values for the AccessTierType const type. +func PossibleAccessTierTypeValues() []AccessTierType { + return []AccessTierType{AccessTierArchive, AccessTierCool, AccessTierHot, AccessTierNone, AccessTierP10, AccessTierP20, AccessTierP30, AccessTierP4, AccessTierP40, AccessTierP50, AccessTierP6} +} + +// ArchiveStatusType enumerates the values for archive status type. +type ArchiveStatusType string + +const ( + // ArchiveStatusNone represents an empty ArchiveStatusType. + ArchiveStatusNone ArchiveStatusType = "" + // ArchiveStatusRehydratePendingToCool ... + ArchiveStatusRehydratePendingToCool ArchiveStatusType = "rehydrate-pending-to-cool" + // ArchiveStatusRehydratePendingToHot ... + ArchiveStatusRehydratePendingToHot ArchiveStatusType = "rehydrate-pending-to-hot" +) + +// PossibleArchiveStatusTypeValues returns an array of possible values for the ArchiveStatusType const type. +func PossibleArchiveStatusTypeValues() []ArchiveStatusType { + return []ArchiveStatusType{ArchiveStatusNone, ArchiveStatusRehydratePendingToCool, ArchiveStatusRehydratePendingToHot} +} + +// BlobType enumerates the values for blob type. +type BlobType string + +const ( + // BlobAppendBlob ... + BlobAppendBlob BlobType = "AppendBlob" + // BlobBlockBlob ... + BlobBlockBlob BlobType = "BlockBlob" + // BlobNone represents an empty BlobType. + BlobNone BlobType = "" + // BlobPageBlob ... + BlobPageBlob BlobType = "PageBlob" +) + +// PossibleBlobTypeValues returns an array of possible values for the BlobType const type. +func PossibleBlobTypeValues() []BlobType { + return []BlobType{BlobAppendBlob, BlobBlockBlob, BlobNone, BlobPageBlob} +} + +// BlockListType enumerates the values for block list type. +type BlockListType string + +const ( + // BlockListAll ... + BlockListAll BlockListType = "all" + // BlockListCommitted ... + BlockListCommitted BlockListType = "committed" + // BlockListNone represents an empty BlockListType. + BlockListNone BlockListType = "" + // BlockListUncommitted ... + BlockListUncommitted BlockListType = "uncommitted" +) + +// PossibleBlockListTypeValues returns an array of possible values for the BlockListType const type. +func PossibleBlockListTypeValues() []BlockListType { + return []BlockListType{BlockListAll, BlockListCommitted, BlockListNone, BlockListUncommitted} +} + +// CopyStatusType enumerates the values for copy status type. +type CopyStatusType string + +const ( + // CopyStatusAborted ... + CopyStatusAborted CopyStatusType = "aborted" + // CopyStatusFailed ... + CopyStatusFailed CopyStatusType = "failed" + // CopyStatusNone represents an empty CopyStatusType. + CopyStatusNone CopyStatusType = "" + // CopyStatusPending ... + CopyStatusPending CopyStatusType = "pending" + // CopyStatusSuccess ... + CopyStatusSuccess CopyStatusType = "success" +) + +// PossibleCopyStatusTypeValues returns an array of possible values for the CopyStatusType const type. +func PossibleCopyStatusTypeValues() []CopyStatusType { + return []CopyStatusType{CopyStatusAborted, CopyStatusFailed, CopyStatusNone, CopyStatusPending, CopyStatusSuccess} +} + +// DeleteSnapshotsOptionType enumerates the values for delete snapshots option type. +type DeleteSnapshotsOptionType string + +const ( + // DeleteSnapshotsOptionInclude ... + DeleteSnapshotsOptionInclude DeleteSnapshotsOptionType = "include" + // DeleteSnapshotsOptionNone represents an empty DeleteSnapshotsOptionType. + DeleteSnapshotsOptionNone DeleteSnapshotsOptionType = "" + // DeleteSnapshotsOptionOnly ... + DeleteSnapshotsOptionOnly DeleteSnapshotsOptionType = "only" +) + +// PossibleDeleteSnapshotsOptionTypeValues returns an array of possible values for the DeleteSnapshotsOptionType const type. +func PossibleDeleteSnapshotsOptionTypeValues() []DeleteSnapshotsOptionType { + return []DeleteSnapshotsOptionType{DeleteSnapshotsOptionInclude, DeleteSnapshotsOptionNone, DeleteSnapshotsOptionOnly} +} + +// GeoReplicationStatusType enumerates the values for geo replication status type. +type GeoReplicationStatusType string + +const ( + // GeoReplicationStatusBootstrap ... + GeoReplicationStatusBootstrap GeoReplicationStatusType = "bootstrap" + // GeoReplicationStatusLive ... + GeoReplicationStatusLive GeoReplicationStatusType = "live" + // GeoReplicationStatusNone represents an empty GeoReplicationStatusType. + GeoReplicationStatusNone GeoReplicationStatusType = "" + // GeoReplicationStatusUnavailable ... + GeoReplicationStatusUnavailable GeoReplicationStatusType = "unavailable" +) + +// PossibleGeoReplicationStatusTypeValues returns an array of possible values for the GeoReplicationStatusType const type. +func PossibleGeoReplicationStatusTypeValues() []GeoReplicationStatusType { + return []GeoReplicationStatusType{GeoReplicationStatusBootstrap, GeoReplicationStatusLive, GeoReplicationStatusNone, GeoReplicationStatusUnavailable} +} + +// LeaseDurationType enumerates the values for lease duration type. +type LeaseDurationType string + +const ( + // LeaseDurationFixed ... + LeaseDurationFixed LeaseDurationType = "fixed" + // LeaseDurationInfinite ... + LeaseDurationInfinite LeaseDurationType = "infinite" + // LeaseDurationNone represents an empty LeaseDurationType. + LeaseDurationNone LeaseDurationType = "" +) + +// PossibleLeaseDurationTypeValues returns an array of possible values for the LeaseDurationType const type. +func PossibleLeaseDurationTypeValues() []LeaseDurationType { + return []LeaseDurationType{LeaseDurationFixed, LeaseDurationInfinite, LeaseDurationNone} +} + +// LeaseStateType enumerates the values for lease state type. +type LeaseStateType string + +const ( + // LeaseStateAvailable ... + LeaseStateAvailable LeaseStateType = "available" + // LeaseStateBreaking ... + LeaseStateBreaking LeaseStateType = "breaking" + // LeaseStateBroken ... + LeaseStateBroken LeaseStateType = "broken" + // LeaseStateExpired ... + LeaseStateExpired LeaseStateType = "expired" + // LeaseStateLeased ... + LeaseStateLeased LeaseStateType = "leased" + // LeaseStateNone represents an empty LeaseStateType. + LeaseStateNone LeaseStateType = "" +) + +// PossibleLeaseStateTypeValues returns an array of possible values for the LeaseStateType const type. +func PossibleLeaseStateTypeValues() []LeaseStateType { + return []LeaseStateType{LeaseStateAvailable, LeaseStateBreaking, LeaseStateBroken, LeaseStateExpired, LeaseStateLeased, LeaseStateNone} +} + +// LeaseStatusType enumerates the values for lease status type. +type LeaseStatusType string + +const ( + // LeaseStatusLocked ... + LeaseStatusLocked LeaseStatusType = "locked" + // LeaseStatusNone represents an empty LeaseStatusType. + LeaseStatusNone LeaseStatusType = "" + // LeaseStatusUnlocked ... + LeaseStatusUnlocked LeaseStatusType = "unlocked" +) + +// PossibleLeaseStatusTypeValues returns an array of possible values for the LeaseStatusType const type. +func PossibleLeaseStatusTypeValues() []LeaseStatusType { + return []LeaseStatusType{LeaseStatusLocked, LeaseStatusNone, LeaseStatusUnlocked} +} + +// ListBlobsIncludeItemType enumerates the values for list blobs include item type. +type ListBlobsIncludeItemType string + +const ( + // ListBlobsIncludeItemCopy ... + ListBlobsIncludeItemCopy ListBlobsIncludeItemType = "copy" + // ListBlobsIncludeItemDeleted ... + ListBlobsIncludeItemDeleted ListBlobsIncludeItemType = "deleted" + // ListBlobsIncludeItemMetadata ... + ListBlobsIncludeItemMetadata ListBlobsIncludeItemType = "metadata" + // ListBlobsIncludeItemNone represents an empty ListBlobsIncludeItemType. + ListBlobsIncludeItemNone ListBlobsIncludeItemType = "" + // ListBlobsIncludeItemSnapshots ... + ListBlobsIncludeItemSnapshots ListBlobsIncludeItemType = "snapshots" + // ListBlobsIncludeItemUncommittedblobs ... + ListBlobsIncludeItemUncommittedblobs ListBlobsIncludeItemType = "uncommittedblobs" +) + +// PossibleListBlobsIncludeItemTypeValues returns an array of possible values for the ListBlobsIncludeItemType const type. +func PossibleListBlobsIncludeItemTypeValues() []ListBlobsIncludeItemType { + return []ListBlobsIncludeItemType{ListBlobsIncludeItemCopy, ListBlobsIncludeItemDeleted, ListBlobsIncludeItemMetadata, ListBlobsIncludeItemNone, ListBlobsIncludeItemSnapshots, ListBlobsIncludeItemUncommittedblobs} +} + +// ListContainersIncludeType enumerates the values for list containers include type. +type ListContainersIncludeType string + +const ( + // ListContainersIncludeMetadata ... + ListContainersIncludeMetadata ListContainersIncludeType = "metadata" + // ListContainersIncludeNone represents an empty ListContainersIncludeType. + ListContainersIncludeNone ListContainersIncludeType = "" +) + +// PossibleListContainersIncludeTypeValues returns an array of possible values for the ListContainersIncludeType const type. +func PossibleListContainersIncludeTypeValues() []ListContainersIncludeType { + return []ListContainersIncludeType{ListContainersIncludeMetadata, ListContainersIncludeNone} +} + +// PublicAccessType enumerates the values for public access type. +type PublicAccessType string + +const ( + // PublicAccessBlob ... + PublicAccessBlob PublicAccessType = "blob" + // PublicAccessContainer ... + PublicAccessContainer PublicAccessType = "container" + // PublicAccessNone represents an empty PublicAccessType. + PublicAccessNone PublicAccessType = "" +) + +// PossiblePublicAccessTypeValues returns an array of possible values for the PublicAccessType const type. +func PossiblePublicAccessTypeValues() []PublicAccessType { + return []PublicAccessType{PublicAccessBlob, PublicAccessContainer, PublicAccessNone} +} + +// SequenceNumberActionType enumerates the values for sequence number action type. +type SequenceNumberActionType string + +const ( + // SequenceNumberActionIncrement ... + SequenceNumberActionIncrement SequenceNumberActionType = "increment" + // SequenceNumberActionMax ... + SequenceNumberActionMax SequenceNumberActionType = "max" + // SequenceNumberActionNone represents an empty SequenceNumberActionType. + SequenceNumberActionNone SequenceNumberActionType = "" + // SequenceNumberActionUpdate ... + SequenceNumberActionUpdate SequenceNumberActionType = "update" +) + +// PossibleSequenceNumberActionTypeValues returns an array of possible values for the SequenceNumberActionType const type. +func PossibleSequenceNumberActionTypeValues() []SequenceNumberActionType { + return []SequenceNumberActionType{SequenceNumberActionIncrement, SequenceNumberActionMax, SequenceNumberActionNone, SequenceNumberActionUpdate} +} + +// StorageErrorCodeType enumerates the values for storage error code type. +type StorageErrorCodeType string + +const ( + // StorageErrorCodeAccountAlreadyExists ... + StorageErrorCodeAccountAlreadyExists StorageErrorCodeType = "AccountAlreadyExists" + // StorageErrorCodeAccountBeingCreated ... + StorageErrorCodeAccountBeingCreated StorageErrorCodeType = "AccountBeingCreated" + // StorageErrorCodeAccountIsDisabled ... + StorageErrorCodeAccountIsDisabled StorageErrorCodeType = "AccountIsDisabled" + // StorageErrorCodeAppendPositionConditionNotMet ... + StorageErrorCodeAppendPositionConditionNotMet StorageErrorCodeType = "AppendPositionConditionNotMet" + // StorageErrorCodeAuthenticationFailed ... + StorageErrorCodeAuthenticationFailed StorageErrorCodeType = "AuthenticationFailed" + // StorageErrorCodeBlobAlreadyExists ... + StorageErrorCodeBlobAlreadyExists StorageErrorCodeType = "BlobAlreadyExists" + // StorageErrorCodeBlobArchived ... + StorageErrorCodeBlobArchived StorageErrorCodeType = "BlobArchived" + // StorageErrorCodeBlobBeingRehydrated ... + StorageErrorCodeBlobBeingRehydrated StorageErrorCodeType = "BlobBeingRehydrated" + // StorageErrorCodeBlobNotArchived ... + StorageErrorCodeBlobNotArchived StorageErrorCodeType = "BlobNotArchived" + // StorageErrorCodeBlobNotFound ... + StorageErrorCodeBlobNotFound StorageErrorCodeType = "BlobNotFound" + // StorageErrorCodeBlobOverwritten ... + StorageErrorCodeBlobOverwritten StorageErrorCodeType = "BlobOverwritten" + // StorageErrorCodeBlobTierInadequateForContentLength ... + StorageErrorCodeBlobTierInadequateForContentLength StorageErrorCodeType = "BlobTierInadequateForContentLength" + // StorageErrorCodeBlockCountExceedsLimit ... + StorageErrorCodeBlockCountExceedsLimit StorageErrorCodeType = "BlockCountExceedsLimit" + // StorageErrorCodeBlockListTooLong ... + StorageErrorCodeBlockListTooLong StorageErrorCodeType = "BlockListTooLong" + // StorageErrorCodeCannotChangeToLowerTier ... + StorageErrorCodeCannotChangeToLowerTier StorageErrorCodeType = "CannotChangeToLowerTier" + // StorageErrorCodeCannotVerifyCopySource ... + StorageErrorCodeCannotVerifyCopySource StorageErrorCodeType = "CannotVerifyCopySource" + // StorageErrorCodeConditionHeadersNotSupported ... + StorageErrorCodeConditionHeadersNotSupported StorageErrorCodeType = "ConditionHeadersNotSupported" + // StorageErrorCodeConditionNotMet ... + StorageErrorCodeConditionNotMet StorageErrorCodeType = "ConditionNotMet" + // StorageErrorCodeContainerAlreadyExists ... + StorageErrorCodeContainerAlreadyExists StorageErrorCodeType = "ContainerAlreadyExists" + // StorageErrorCodeContainerBeingDeleted ... + StorageErrorCodeContainerBeingDeleted StorageErrorCodeType = "ContainerBeingDeleted" + // StorageErrorCodeContainerDisabled ... + StorageErrorCodeContainerDisabled StorageErrorCodeType = "ContainerDisabled" + // StorageErrorCodeContainerNotFound ... + StorageErrorCodeContainerNotFound StorageErrorCodeType = "ContainerNotFound" + // StorageErrorCodeContentLengthLargerThanTierLimit ... + StorageErrorCodeContentLengthLargerThanTierLimit StorageErrorCodeType = "ContentLengthLargerThanTierLimit" + // StorageErrorCodeCopyAcrossAccountsNotSupported ... + StorageErrorCodeCopyAcrossAccountsNotSupported StorageErrorCodeType = "CopyAcrossAccountsNotSupported" + // StorageErrorCodeCopyIDMismatch ... + StorageErrorCodeCopyIDMismatch StorageErrorCodeType = "CopyIdMismatch" + // StorageErrorCodeEmptyMetadataKey ... + StorageErrorCodeEmptyMetadataKey StorageErrorCodeType = "EmptyMetadataKey" + // StorageErrorCodeFeatureVersionMismatch ... + StorageErrorCodeFeatureVersionMismatch StorageErrorCodeType = "FeatureVersionMismatch" + // StorageErrorCodeIncrementalCopyBlobMismatch ... + StorageErrorCodeIncrementalCopyBlobMismatch StorageErrorCodeType = "IncrementalCopyBlobMismatch" + // StorageErrorCodeIncrementalCopyOfEralierVersionSnapshotNotAllowed ... + StorageErrorCodeIncrementalCopyOfEralierVersionSnapshotNotAllowed StorageErrorCodeType = "IncrementalCopyOfEralierVersionSnapshotNotAllowed" + // StorageErrorCodeIncrementalCopySourceMustBeSnapshot ... + StorageErrorCodeIncrementalCopySourceMustBeSnapshot StorageErrorCodeType = "IncrementalCopySourceMustBeSnapshot" + // StorageErrorCodeInfiniteLeaseDurationRequired ... + StorageErrorCodeInfiniteLeaseDurationRequired StorageErrorCodeType = "InfiniteLeaseDurationRequired" + // StorageErrorCodeInsufficientAccountPermissions ... + StorageErrorCodeInsufficientAccountPermissions StorageErrorCodeType = "InsufficientAccountPermissions" + // StorageErrorCodeInternalError ... + StorageErrorCodeInternalError StorageErrorCodeType = "InternalError" + // StorageErrorCodeInvalidAuthenticationInfo ... + StorageErrorCodeInvalidAuthenticationInfo StorageErrorCodeType = "InvalidAuthenticationInfo" + // StorageErrorCodeInvalidBlobOrBlock ... + StorageErrorCodeInvalidBlobOrBlock StorageErrorCodeType = "InvalidBlobOrBlock" + // StorageErrorCodeInvalidBlobTier ... + StorageErrorCodeInvalidBlobTier StorageErrorCodeType = "InvalidBlobTier" + // StorageErrorCodeInvalidBlobType ... + StorageErrorCodeInvalidBlobType StorageErrorCodeType = "InvalidBlobType" + // StorageErrorCodeInvalidBlockID ... + StorageErrorCodeInvalidBlockID StorageErrorCodeType = "InvalidBlockId" + // StorageErrorCodeInvalidBlockList ... + StorageErrorCodeInvalidBlockList StorageErrorCodeType = "InvalidBlockList" + // StorageErrorCodeInvalidHeaderValue ... + StorageErrorCodeInvalidHeaderValue StorageErrorCodeType = "InvalidHeaderValue" + // StorageErrorCodeInvalidHTTPVerb ... + StorageErrorCodeInvalidHTTPVerb StorageErrorCodeType = "InvalidHttpVerb" + // StorageErrorCodeInvalidInput ... + StorageErrorCodeInvalidInput StorageErrorCodeType = "InvalidInput" + // StorageErrorCodeInvalidMd5 ... + StorageErrorCodeInvalidMd5 StorageErrorCodeType = "InvalidMd5" + // StorageErrorCodeInvalidMetadata ... + StorageErrorCodeInvalidMetadata StorageErrorCodeType = "InvalidMetadata" + // StorageErrorCodeInvalidOperation ... + StorageErrorCodeInvalidOperation StorageErrorCodeType = "InvalidOperation" + // StorageErrorCodeInvalidPageRange ... + StorageErrorCodeInvalidPageRange StorageErrorCodeType = "InvalidPageRange" + // StorageErrorCodeInvalidQueryParameterValue ... + StorageErrorCodeInvalidQueryParameterValue StorageErrorCodeType = "InvalidQueryParameterValue" + // StorageErrorCodeInvalidRange ... + StorageErrorCodeInvalidRange StorageErrorCodeType = "InvalidRange" + // StorageErrorCodeInvalidResourceName ... + StorageErrorCodeInvalidResourceName StorageErrorCodeType = "InvalidResourceName" + // StorageErrorCodeInvalidSourceBlobType ... + StorageErrorCodeInvalidSourceBlobType StorageErrorCodeType = "InvalidSourceBlobType" + // StorageErrorCodeInvalidSourceBlobURL ... + StorageErrorCodeInvalidSourceBlobURL StorageErrorCodeType = "InvalidSourceBlobUrl" + // StorageErrorCodeInvalidURI ... + StorageErrorCodeInvalidURI StorageErrorCodeType = "InvalidUri" + // StorageErrorCodeInvalidVersionForPageBlobOperation ... + StorageErrorCodeInvalidVersionForPageBlobOperation StorageErrorCodeType = "InvalidVersionForPageBlobOperation" + // StorageErrorCodeInvalidXMLDocument ... + StorageErrorCodeInvalidXMLDocument StorageErrorCodeType = "InvalidXmlDocument" + // StorageErrorCodeInvalidXMLNodeValue ... + StorageErrorCodeInvalidXMLNodeValue StorageErrorCodeType = "InvalidXmlNodeValue" + // StorageErrorCodeLeaseAlreadyBroken ... + StorageErrorCodeLeaseAlreadyBroken StorageErrorCodeType = "LeaseAlreadyBroken" + // StorageErrorCodeLeaseAlreadyPresent ... + StorageErrorCodeLeaseAlreadyPresent StorageErrorCodeType = "LeaseAlreadyPresent" + // StorageErrorCodeLeaseIDMismatchWithBlobOperation ... + StorageErrorCodeLeaseIDMismatchWithBlobOperation StorageErrorCodeType = "LeaseIdMismatchWithBlobOperation" + // StorageErrorCodeLeaseIDMismatchWithContainerOperation ... + StorageErrorCodeLeaseIDMismatchWithContainerOperation StorageErrorCodeType = "LeaseIdMismatchWithContainerOperation" + // StorageErrorCodeLeaseIDMismatchWithLeaseOperation ... + StorageErrorCodeLeaseIDMismatchWithLeaseOperation StorageErrorCodeType = "LeaseIdMismatchWithLeaseOperation" + // StorageErrorCodeLeaseIDMissing ... + StorageErrorCodeLeaseIDMissing StorageErrorCodeType = "LeaseIdMissing" + // StorageErrorCodeLeaseIsBreakingAndCannotBeAcquired ... + StorageErrorCodeLeaseIsBreakingAndCannotBeAcquired StorageErrorCodeType = "LeaseIsBreakingAndCannotBeAcquired" + // StorageErrorCodeLeaseIsBreakingAndCannotBeChanged ... + StorageErrorCodeLeaseIsBreakingAndCannotBeChanged StorageErrorCodeType = "LeaseIsBreakingAndCannotBeChanged" + // StorageErrorCodeLeaseIsBrokenAndCannotBeRenewed ... + StorageErrorCodeLeaseIsBrokenAndCannotBeRenewed StorageErrorCodeType = "LeaseIsBrokenAndCannotBeRenewed" + // StorageErrorCodeLeaseLost ... + StorageErrorCodeLeaseLost StorageErrorCodeType = "LeaseLost" + // StorageErrorCodeLeaseNotPresentWithBlobOperation ... + StorageErrorCodeLeaseNotPresentWithBlobOperation StorageErrorCodeType = "LeaseNotPresentWithBlobOperation" + // StorageErrorCodeLeaseNotPresentWithContainerOperation ... + StorageErrorCodeLeaseNotPresentWithContainerOperation StorageErrorCodeType = "LeaseNotPresentWithContainerOperation" + // StorageErrorCodeLeaseNotPresentWithLeaseOperation ... + StorageErrorCodeLeaseNotPresentWithLeaseOperation StorageErrorCodeType = "LeaseNotPresentWithLeaseOperation" + // StorageErrorCodeMaxBlobSizeConditionNotMet ... + StorageErrorCodeMaxBlobSizeConditionNotMet StorageErrorCodeType = "MaxBlobSizeConditionNotMet" + // StorageErrorCodeMd5Mismatch ... + StorageErrorCodeMd5Mismatch StorageErrorCodeType = "Md5Mismatch" + // StorageErrorCodeMetadataTooLarge ... + StorageErrorCodeMetadataTooLarge StorageErrorCodeType = "MetadataTooLarge" + // StorageErrorCodeMissingContentLengthHeader ... + StorageErrorCodeMissingContentLengthHeader StorageErrorCodeType = "MissingContentLengthHeader" + // StorageErrorCodeMissingRequiredHeader ... + StorageErrorCodeMissingRequiredHeader StorageErrorCodeType = "MissingRequiredHeader" + // StorageErrorCodeMissingRequiredQueryParameter ... + StorageErrorCodeMissingRequiredQueryParameter StorageErrorCodeType = "MissingRequiredQueryParameter" + // StorageErrorCodeMissingRequiredXMLNode ... + StorageErrorCodeMissingRequiredXMLNode StorageErrorCodeType = "MissingRequiredXmlNode" + // StorageErrorCodeMultipleConditionHeadersNotSupported ... + StorageErrorCodeMultipleConditionHeadersNotSupported StorageErrorCodeType = "MultipleConditionHeadersNotSupported" + // StorageErrorCodeNone represents an empty StorageErrorCodeType. + StorageErrorCodeNone StorageErrorCodeType = "" + // StorageErrorCodeNoPendingCopyOperation ... + StorageErrorCodeNoPendingCopyOperation StorageErrorCodeType = "NoPendingCopyOperation" + // StorageErrorCodeOperationNotAllowedOnIncrementalCopyBlob ... + StorageErrorCodeOperationNotAllowedOnIncrementalCopyBlob StorageErrorCodeType = "OperationNotAllowedOnIncrementalCopyBlob" + // StorageErrorCodeOperationTimedOut ... + StorageErrorCodeOperationTimedOut StorageErrorCodeType = "OperationTimedOut" + // StorageErrorCodeOutOfRangeInput ... + StorageErrorCodeOutOfRangeInput StorageErrorCodeType = "OutOfRangeInput" + // StorageErrorCodeOutOfRangeQueryParameterValue ... + StorageErrorCodeOutOfRangeQueryParameterValue StorageErrorCodeType = "OutOfRangeQueryParameterValue" + // StorageErrorCodePendingCopyOperation ... + StorageErrorCodePendingCopyOperation StorageErrorCodeType = "PendingCopyOperation" + // StorageErrorCodePreviousSnapshotCannotBeNewer ... + StorageErrorCodePreviousSnapshotCannotBeNewer StorageErrorCodeType = "PreviousSnapshotCannotBeNewer" + // StorageErrorCodePreviousSnapshotNotFound ... + StorageErrorCodePreviousSnapshotNotFound StorageErrorCodeType = "PreviousSnapshotNotFound" + // StorageErrorCodePreviousSnapshotOperationNotSupported ... + StorageErrorCodePreviousSnapshotOperationNotSupported StorageErrorCodeType = "PreviousSnapshotOperationNotSupported" + // StorageErrorCodeRequestBodyTooLarge ... + StorageErrorCodeRequestBodyTooLarge StorageErrorCodeType = "RequestBodyTooLarge" + // StorageErrorCodeRequestURLFailedToParse ... + StorageErrorCodeRequestURLFailedToParse StorageErrorCodeType = "RequestUrlFailedToParse" + // StorageErrorCodeResourceAlreadyExists ... + StorageErrorCodeResourceAlreadyExists StorageErrorCodeType = "ResourceAlreadyExists" + // StorageErrorCodeResourceNotFound ... + StorageErrorCodeResourceNotFound StorageErrorCodeType = "ResourceNotFound" + // StorageErrorCodeResourceTypeMismatch ... + StorageErrorCodeResourceTypeMismatch StorageErrorCodeType = "ResourceTypeMismatch" + // StorageErrorCodeSequenceNumberConditionNotMet ... + StorageErrorCodeSequenceNumberConditionNotMet StorageErrorCodeType = "SequenceNumberConditionNotMet" + // StorageErrorCodeSequenceNumberIncrementTooLarge ... + StorageErrorCodeSequenceNumberIncrementTooLarge StorageErrorCodeType = "SequenceNumberIncrementTooLarge" + // StorageErrorCodeServerBusy ... + StorageErrorCodeServerBusy StorageErrorCodeType = "ServerBusy" + // StorageErrorCodeSnaphotOperationRateExceeded ... + StorageErrorCodeSnaphotOperationRateExceeded StorageErrorCodeType = "SnaphotOperationRateExceeded" + // StorageErrorCodeSnapshotCountExceeded ... + StorageErrorCodeSnapshotCountExceeded StorageErrorCodeType = "SnapshotCountExceeded" + // StorageErrorCodeSnapshotsPresent ... + StorageErrorCodeSnapshotsPresent StorageErrorCodeType = "SnapshotsPresent" + // StorageErrorCodeSourceConditionNotMet ... + StorageErrorCodeSourceConditionNotMet StorageErrorCodeType = "SourceConditionNotMet" + // StorageErrorCodeSystemInUse ... + StorageErrorCodeSystemInUse StorageErrorCodeType = "SystemInUse" + // StorageErrorCodeTargetConditionNotMet ... + StorageErrorCodeTargetConditionNotMet StorageErrorCodeType = "TargetConditionNotMet" + // StorageErrorCodeUnauthorizedBlobOverwrite ... + StorageErrorCodeUnauthorizedBlobOverwrite StorageErrorCodeType = "UnauthorizedBlobOverwrite" + // StorageErrorCodeUnsupportedHeader ... + StorageErrorCodeUnsupportedHeader StorageErrorCodeType = "UnsupportedHeader" + // StorageErrorCodeUnsupportedHTTPVerb ... + StorageErrorCodeUnsupportedHTTPVerb StorageErrorCodeType = "UnsupportedHttpVerb" + // StorageErrorCodeUnsupportedQueryParameter ... + StorageErrorCodeUnsupportedQueryParameter StorageErrorCodeType = "UnsupportedQueryParameter" + // StorageErrorCodeUnsupportedXMLNode ... + StorageErrorCodeUnsupportedXMLNode StorageErrorCodeType = "UnsupportedXmlNode" +) + +// PossibleStorageErrorCodeTypeValues returns an array of possible values for the StorageErrorCodeType const type. +func PossibleStorageErrorCodeTypeValues() []StorageErrorCodeType { + return []StorageErrorCodeType{StorageErrorCodeAccountAlreadyExists, StorageErrorCodeAccountBeingCreated, StorageErrorCodeAccountIsDisabled, StorageErrorCodeAppendPositionConditionNotMet, StorageErrorCodeAuthenticationFailed, StorageErrorCodeBlobAlreadyExists, StorageErrorCodeBlobArchived, StorageErrorCodeBlobBeingRehydrated, StorageErrorCodeBlobNotArchived, StorageErrorCodeBlobNotFound, StorageErrorCodeBlobOverwritten, StorageErrorCodeBlobTierInadequateForContentLength, StorageErrorCodeBlockCountExceedsLimit, StorageErrorCodeBlockListTooLong, StorageErrorCodeCannotChangeToLowerTier, StorageErrorCodeCannotVerifyCopySource, StorageErrorCodeConditionHeadersNotSupported, StorageErrorCodeConditionNotMet, StorageErrorCodeContainerAlreadyExists, StorageErrorCodeContainerBeingDeleted, StorageErrorCodeContainerDisabled, StorageErrorCodeContainerNotFound, StorageErrorCodeContentLengthLargerThanTierLimit, StorageErrorCodeCopyAcrossAccountsNotSupported, StorageErrorCodeCopyIDMismatch, StorageErrorCodeEmptyMetadataKey, StorageErrorCodeFeatureVersionMismatch, StorageErrorCodeIncrementalCopyBlobMismatch, StorageErrorCodeIncrementalCopyOfEralierVersionSnapshotNotAllowed, StorageErrorCodeIncrementalCopySourceMustBeSnapshot, StorageErrorCodeInfiniteLeaseDurationRequired, StorageErrorCodeInsufficientAccountPermissions, StorageErrorCodeInternalError, StorageErrorCodeInvalidAuthenticationInfo, StorageErrorCodeInvalidBlobOrBlock, StorageErrorCodeInvalidBlobTier, StorageErrorCodeInvalidBlobType, StorageErrorCodeInvalidBlockID, StorageErrorCodeInvalidBlockList, StorageErrorCodeInvalidHeaderValue, StorageErrorCodeInvalidHTTPVerb, StorageErrorCodeInvalidInput, StorageErrorCodeInvalidMd5, StorageErrorCodeInvalidMetadata, StorageErrorCodeInvalidOperation, StorageErrorCodeInvalidPageRange, StorageErrorCodeInvalidQueryParameterValue, StorageErrorCodeInvalidRange, StorageErrorCodeInvalidResourceName, StorageErrorCodeInvalidSourceBlobType, StorageErrorCodeInvalidSourceBlobURL, StorageErrorCodeInvalidURI, StorageErrorCodeInvalidVersionForPageBlobOperation, StorageErrorCodeInvalidXMLDocument, StorageErrorCodeInvalidXMLNodeValue, StorageErrorCodeLeaseAlreadyBroken, StorageErrorCodeLeaseAlreadyPresent, StorageErrorCodeLeaseIDMismatchWithBlobOperation, StorageErrorCodeLeaseIDMismatchWithContainerOperation, StorageErrorCodeLeaseIDMismatchWithLeaseOperation, StorageErrorCodeLeaseIDMissing, StorageErrorCodeLeaseIsBreakingAndCannotBeAcquired, StorageErrorCodeLeaseIsBreakingAndCannotBeChanged, StorageErrorCodeLeaseIsBrokenAndCannotBeRenewed, StorageErrorCodeLeaseLost, StorageErrorCodeLeaseNotPresentWithBlobOperation, StorageErrorCodeLeaseNotPresentWithContainerOperation, StorageErrorCodeLeaseNotPresentWithLeaseOperation, StorageErrorCodeMaxBlobSizeConditionNotMet, StorageErrorCodeMd5Mismatch, StorageErrorCodeMetadataTooLarge, StorageErrorCodeMissingContentLengthHeader, StorageErrorCodeMissingRequiredHeader, StorageErrorCodeMissingRequiredQueryParameter, StorageErrorCodeMissingRequiredXMLNode, StorageErrorCodeMultipleConditionHeadersNotSupported, StorageErrorCodeNone, StorageErrorCodeNoPendingCopyOperation, StorageErrorCodeOperationNotAllowedOnIncrementalCopyBlob, StorageErrorCodeOperationTimedOut, StorageErrorCodeOutOfRangeInput, StorageErrorCodeOutOfRangeQueryParameterValue, StorageErrorCodePendingCopyOperation, StorageErrorCodePreviousSnapshotCannotBeNewer, StorageErrorCodePreviousSnapshotNotFound, StorageErrorCodePreviousSnapshotOperationNotSupported, StorageErrorCodeRequestBodyTooLarge, StorageErrorCodeRequestURLFailedToParse, StorageErrorCodeResourceAlreadyExists, StorageErrorCodeResourceNotFound, StorageErrorCodeResourceTypeMismatch, StorageErrorCodeSequenceNumberConditionNotMet, StorageErrorCodeSequenceNumberIncrementTooLarge, StorageErrorCodeServerBusy, StorageErrorCodeSnaphotOperationRateExceeded, StorageErrorCodeSnapshotCountExceeded, StorageErrorCodeSnapshotsPresent, StorageErrorCodeSourceConditionNotMet, StorageErrorCodeSystemInUse, StorageErrorCodeTargetConditionNotMet, StorageErrorCodeUnauthorizedBlobOverwrite, StorageErrorCodeUnsupportedHeader, StorageErrorCodeUnsupportedHTTPVerb, StorageErrorCodeUnsupportedQueryParameter, StorageErrorCodeUnsupportedXMLNode} +} + +// AccessPolicy - An Access policy +type AccessPolicy struct { + // Start - the date-time the policy is active + Start time.Time `xml:"Start"` + // Expiry - the date-time the policy expires + Expiry time.Time `xml:"Expiry"` + // Permission - the permissions for the acl policy + Permission string `xml:"Permission"` +} + +// MarshalXML implements the xml.Marshaler interface for AccessPolicy. +func (ap AccessPolicy) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + if reflect.TypeOf((*AccessPolicy)(nil)).Elem().Size() != reflect.TypeOf((*accessPolicy)(nil)).Elem().Size() { + panic("size mismatch between AccessPolicy and accessPolicy") + } + ap2 := (*accessPolicy)(unsafe.Pointer(&ap)) + return e.EncodeElement(*ap2, start) +} + +// UnmarshalXML implements the xml.Unmarshaler interface for AccessPolicy. +func (ap *AccessPolicy) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + if reflect.TypeOf((*AccessPolicy)(nil)).Elem().Size() != reflect.TypeOf((*accessPolicy)(nil)).Elem().Size() { + panic("size mismatch between AccessPolicy and accessPolicy") + } + ap2 := (*accessPolicy)(unsafe.Pointer(ap)) + return d.DecodeElement(ap2, &start) +} + +// AppendBlobAppendBlockResponse ... +type AppendBlobAppendBlockResponse struct { + rawResponse *http.Response +} + +// Response returns the raw HTTP response object. +func (ababr AppendBlobAppendBlockResponse) Response() *http.Response { + return ababr.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (ababr AppendBlobAppendBlockResponse) StatusCode() int { + return ababr.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (ababr AppendBlobAppendBlockResponse) Status() string { + return ababr.rawResponse.Status +} + +// BlobAppendOffset returns the value for header x-ms-blob-append-offset. +func (ababr AppendBlobAppendBlockResponse) BlobAppendOffset() string { + return ababr.rawResponse.Header.Get("x-ms-blob-append-offset") +} + +// BlobCommittedBlockCount returns the value for header x-ms-blob-committed-block-count. +func (ababr AppendBlobAppendBlockResponse) BlobCommittedBlockCount() int32 { + s := ababr.rawResponse.Header.Get("x-ms-blob-committed-block-count") + if s == "" { + return -1 + } + i, err := strconv.ParseInt(s, 10, 32) + if err != nil { + panic(err) + } + return int32(i) +} + +// ContentMD5 returns the value for header Content-MD5. +func (ababr AppendBlobAppendBlockResponse) ContentMD5() []byte { + s := ababr.rawResponse.Header.Get("Content-MD5") + if s == "" { + return nil + } + b, err := base64.StdEncoding.DecodeString(s) + if err != nil { + panic(err) + } + return b +} + +// Date returns the value for header Date. +func (ababr AppendBlobAppendBlockResponse) Date() time.Time { + s := ababr.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (ababr AppendBlobAppendBlockResponse) ErrorCode() string { + return ababr.rawResponse.Header.Get("x-ms-error-code") +} + +// ETag returns the value for header ETag. +func (ababr AppendBlobAppendBlockResponse) ETag() ETag { + return ETag(ababr.rawResponse.Header.Get("ETag")) +} + +// LastModified returns the value for header Last-Modified. +func (ababr AppendBlobAppendBlockResponse) LastModified() time.Time { + s := ababr.rawResponse.Header.Get("Last-Modified") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// RequestID returns the value for header x-ms-request-id. +func (ababr AppendBlobAppendBlockResponse) RequestID() string { + return ababr.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (ababr AppendBlobAppendBlockResponse) Version() string { + return ababr.rawResponse.Header.Get("x-ms-version") +} + +// AppendBlobCreateResponse ... +type AppendBlobCreateResponse struct { + rawResponse *http.Response +} + +// Response returns the raw HTTP response object. +func (abcr AppendBlobCreateResponse) Response() *http.Response { + return abcr.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (abcr AppendBlobCreateResponse) StatusCode() int { + return abcr.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (abcr AppendBlobCreateResponse) Status() string { + return abcr.rawResponse.Status +} + +// ContentMD5 returns the value for header Content-MD5. +func (abcr AppendBlobCreateResponse) ContentMD5() []byte { + s := abcr.rawResponse.Header.Get("Content-MD5") + if s == "" { + return nil + } + b, err := base64.StdEncoding.DecodeString(s) + if err != nil { + panic(err) + } + return b +} + +// Date returns the value for header Date. +func (abcr AppendBlobCreateResponse) Date() time.Time { + s := abcr.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (abcr AppendBlobCreateResponse) ErrorCode() string { + return abcr.rawResponse.Header.Get("x-ms-error-code") +} + +// ETag returns the value for header ETag. +func (abcr AppendBlobCreateResponse) ETag() ETag { + return ETag(abcr.rawResponse.Header.Get("ETag")) +} + +// IsServerEncrypted returns the value for header x-ms-request-server-encrypted. +func (abcr AppendBlobCreateResponse) IsServerEncrypted() string { + return abcr.rawResponse.Header.Get("x-ms-request-server-encrypted") +} + +// LastModified returns the value for header Last-Modified. +func (abcr AppendBlobCreateResponse) LastModified() time.Time { + s := abcr.rawResponse.Header.Get("Last-Modified") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// RequestID returns the value for header x-ms-request-id. +func (abcr AppendBlobCreateResponse) RequestID() string { + return abcr.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (abcr AppendBlobCreateResponse) Version() string { + return abcr.rawResponse.Header.Get("x-ms-version") +} + +// BlobAbortCopyFromURLResponse ... +type BlobAbortCopyFromURLResponse struct { + rawResponse *http.Response +} + +// Response returns the raw HTTP response object. +func (bacfur BlobAbortCopyFromURLResponse) Response() *http.Response { + return bacfur.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (bacfur BlobAbortCopyFromURLResponse) StatusCode() int { + return bacfur.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (bacfur BlobAbortCopyFromURLResponse) Status() string { + return bacfur.rawResponse.Status +} + +// Date returns the value for header Date. +func (bacfur BlobAbortCopyFromURLResponse) Date() time.Time { + s := bacfur.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (bacfur BlobAbortCopyFromURLResponse) ErrorCode() string { + return bacfur.rawResponse.Header.Get("x-ms-error-code") +} + +// RequestID returns the value for header x-ms-request-id. +func (bacfur BlobAbortCopyFromURLResponse) RequestID() string { + return bacfur.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (bacfur BlobAbortCopyFromURLResponse) Version() string { + return bacfur.rawResponse.Header.Get("x-ms-version") +} + +// BlobAcquireLeaseResponse ... +type BlobAcquireLeaseResponse struct { + rawResponse *http.Response +} + +// Response returns the raw HTTP response object. +func (balr BlobAcquireLeaseResponse) Response() *http.Response { + return balr.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (balr BlobAcquireLeaseResponse) StatusCode() int { + return balr.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (balr BlobAcquireLeaseResponse) Status() string { + return balr.rawResponse.Status +} + +// Date returns the value for header Date. +func (balr BlobAcquireLeaseResponse) Date() time.Time { + s := balr.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (balr BlobAcquireLeaseResponse) ErrorCode() string { + return balr.rawResponse.Header.Get("x-ms-error-code") +} + +// ETag returns the value for header ETag. +func (balr BlobAcquireLeaseResponse) ETag() ETag { + return ETag(balr.rawResponse.Header.Get("ETag")) +} + +// LastModified returns the value for header Last-Modified. +func (balr BlobAcquireLeaseResponse) LastModified() time.Time { + s := balr.rawResponse.Header.Get("Last-Modified") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// LeaseID returns the value for header x-ms-lease-id. +func (balr BlobAcquireLeaseResponse) LeaseID() string { + return balr.rawResponse.Header.Get("x-ms-lease-id") +} + +// RequestID returns the value for header x-ms-request-id. +func (balr BlobAcquireLeaseResponse) RequestID() string { + return balr.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (balr BlobAcquireLeaseResponse) Version() string { + return balr.rawResponse.Header.Get("x-ms-version") +} + +// BlobBreakLeaseResponse ... +type BlobBreakLeaseResponse struct { + rawResponse *http.Response +} + +// Response returns the raw HTTP response object. +func (bblr BlobBreakLeaseResponse) Response() *http.Response { + return bblr.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (bblr BlobBreakLeaseResponse) StatusCode() int { + return bblr.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (bblr BlobBreakLeaseResponse) Status() string { + return bblr.rawResponse.Status +} + +// Date returns the value for header Date. +func (bblr BlobBreakLeaseResponse) Date() time.Time { + s := bblr.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (bblr BlobBreakLeaseResponse) ErrorCode() string { + return bblr.rawResponse.Header.Get("x-ms-error-code") +} + +// ETag returns the value for header ETag. +func (bblr BlobBreakLeaseResponse) ETag() ETag { + return ETag(bblr.rawResponse.Header.Get("ETag")) +} + +// LastModified returns the value for header Last-Modified. +func (bblr BlobBreakLeaseResponse) LastModified() time.Time { + s := bblr.rawResponse.Header.Get("Last-Modified") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// LeaseTime returns the value for header x-ms-lease-time. +func (bblr BlobBreakLeaseResponse) LeaseTime() int32 { + s := bblr.rawResponse.Header.Get("x-ms-lease-time") + if s == "" { + return -1 + } + i, err := strconv.ParseInt(s, 10, 32) + if err != nil { + panic(err) + } + return int32(i) +} + +// RequestID returns the value for header x-ms-request-id. +func (bblr BlobBreakLeaseResponse) RequestID() string { + return bblr.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (bblr BlobBreakLeaseResponse) Version() string { + return bblr.rawResponse.Header.Get("x-ms-version") +} + +// BlobChangeLeaseResponse ... +type BlobChangeLeaseResponse struct { + rawResponse *http.Response +} + +// Response returns the raw HTTP response object. +func (bclr BlobChangeLeaseResponse) Response() *http.Response { + return bclr.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (bclr BlobChangeLeaseResponse) StatusCode() int { + return bclr.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (bclr BlobChangeLeaseResponse) Status() string { + return bclr.rawResponse.Status +} + +// Date returns the value for header Date. +func (bclr BlobChangeLeaseResponse) Date() time.Time { + s := bclr.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (bclr BlobChangeLeaseResponse) ErrorCode() string { + return bclr.rawResponse.Header.Get("x-ms-error-code") +} + +// ETag returns the value for header ETag. +func (bclr BlobChangeLeaseResponse) ETag() ETag { + return ETag(bclr.rawResponse.Header.Get("ETag")) +} + +// LastModified returns the value for header Last-Modified. +func (bclr BlobChangeLeaseResponse) LastModified() time.Time { + s := bclr.rawResponse.Header.Get("Last-Modified") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// LeaseID returns the value for header x-ms-lease-id. +func (bclr BlobChangeLeaseResponse) LeaseID() string { + return bclr.rawResponse.Header.Get("x-ms-lease-id") +} + +// RequestID returns the value for header x-ms-request-id. +func (bclr BlobChangeLeaseResponse) RequestID() string { + return bclr.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (bclr BlobChangeLeaseResponse) Version() string { + return bclr.rawResponse.Header.Get("x-ms-version") +} + +// BlobCreateSnapshotResponse ... +type BlobCreateSnapshotResponse struct { + rawResponse *http.Response +} + +// Response returns the raw HTTP response object. +func (bcsr BlobCreateSnapshotResponse) Response() *http.Response { + return bcsr.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (bcsr BlobCreateSnapshotResponse) StatusCode() int { + return bcsr.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (bcsr BlobCreateSnapshotResponse) Status() string { + return bcsr.rawResponse.Status +} + +// Date returns the value for header Date. +func (bcsr BlobCreateSnapshotResponse) Date() time.Time { + s := bcsr.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (bcsr BlobCreateSnapshotResponse) ErrorCode() string { + return bcsr.rawResponse.Header.Get("x-ms-error-code") +} + +// ETag returns the value for header ETag. +func (bcsr BlobCreateSnapshotResponse) ETag() ETag { + return ETag(bcsr.rawResponse.Header.Get("ETag")) +} + +// LastModified returns the value for header Last-Modified. +func (bcsr BlobCreateSnapshotResponse) LastModified() time.Time { + s := bcsr.rawResponse.Header.Get("Last-Modified") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// RequestID returns the value for header x-ms-request-id. +func (bcsr BlobCreateSnapshotResponse) RequestID() string { + return bcsr.rawResponse.Header.Get("x-ms-request-id") +} + +// Snapshot returns the value for header x-ms-snapshot. +func (bcsr BlobCreateSnapshotResponse) Snapshot() string { + return bcsr.rawResponse.Header.Get("x-ms-snapshot") +} + +// Version returns the value for header x-ms-version. +func (bcsr BlobCreateSnapshotResponse) Version() string { + return bcsr.rawResponse.Header.Get("x-ms-version") +} + +// BlobDeleteResponse ... +type BlobDeleteResponse struct { + rawResponse *http.Response +} + +// Response returns the raw HTTP response object. +func (bdr BlobDeleteResponse) Response() *http.Response { + return bdr.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (bdr BlobDeleteResponse) StatusCode() int { + return bdr.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (bdr BlobDeleteResponse) Status() string { + return bdr.rawResponse.Status +} + +// Date returns the value for header Date. +func (bdr BlobDeleteResponse) Date() time.Time { + s := bdr.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (bdr BlobDeleteResponse) ErrorCode() string { + return bdr.rawResponse.Header.Get("x-ms-error-code") +} + +// RequestID returns the value for header x-ms-request-id. +func (bdr BlobDeleteResponse) RequestID() string { + return bdr.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (bdr BlobDeleteResponse) Version() string { + return bdr.rawResponse.Header.Get("x-ms-version") +} + +// BlobFlatList ... +type BlobFlatList struct { + BlobItems []BlobItem `xml:"Blob"` +} + +// BlobGetPropertiesResponse ... +type BlobGetPropertiesResponse struct { + rawResponse *http.Response +} + +// NewMetadata returns user-defined key/value pairs. +func (bgpr BlobGetPropertiesResponse) NewMetadata() Metadata { + md := Metadata{} + for k, v := range bgpr.rawResponse.Header { + if len(k) > mdPrefixLen { + if prefix := k[0:mdPrefixLen]; strings.EqualFold(prefix, mdPrefix) { + md[strings.ToLower(k[mdPrefixLen:])] = v[0] + } + } + } + return md +} + +// Response returns the raw HTTP response object. +func (bgpr BlobGetPropertiesResponse) Response() *http.Response { + return bgpr.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (bgpr BlobGetPropertiesResponse) StatusCode() int { + return bgpr.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (bgpr BlobGetPropertiesResponse) Status() string { + return bgpr.rawResponse.Status +} + +// AcceptRanges returns the value for header Accept-Ranges. +func (bgpr BlobGetPropertiesResponse) AcceptRanges() string { + return bgpr.rawResponse.Header.Get("Accept-Ranges") +} + +// AccessTier returns the value for header x-ms-access-tier. +func (bgpr BlobGetPropertiesResponse) AccessTier() string { + return bgpr.rawResponse.Header.Get("x-ms-access-tier") +} + +// AccessTierInferred returns the value for header x-ms-access-tier-inferred. +func (bgpr BlobGetPropertiesResponse) AccessTierInferred() string { + return bgpr.rawResponse.Header.Get("x-ms-access-tier-inferred") +} + +// ArchiveStatus returns the value for header x-ms-archive-status. +func (bgpr BlobGetPropertiesResponse) ArchiveStatus() string { + return bgpr.rawResponse.Header.Get("x-ms-archive-status") +} + +// BlobCommittedBlockCount returns the value for header x-ms-blob-committed-block-count. +func (bgpr BlobGetPropertiesResponse) BlobCommittedBlockCount() int32 { + s := bgpr.rawResponse.Header.Get("x-ms-blob-committed-block-count") + if s == "" { + return -1 + } + i, err := strconv.ParseInt(s, 10, 32) + if err != nil { + panic(err) + } + return int32(i) +} + +// BlobSequenceNumber returns the value for header x-ms-blob-sequence-number. +func (bgpr BlobGetPropertiesResponse) BlobSequenceNumber() int64 { + s := bgpr.rawResponse.Header.Get("x-ms-blob-sequence-number") + if s == "" { + return -1 + } + i, err := strconv.ParseInt(s, 10, 64) + if err != nil { + panic(err) + } + return i +} + +// BlobType returns the value for header x-ms-blob-type. +func (bgpr BlobGetPropertiesResponse) BlobType() BlobType { + return BlobType(bgpr.rawResponse.Header.Get("x-ms-blob-type")) +} + +// CacheControl returns the value for header Cache-Control. +func (bgpr BlobGetPropertiesResponse) CacheControl() string { + return bgpr.rawResponse.Header.Get("Cache-Control") +} + +// ContentDisposition returns the value for header Content-Disposition. +func (bgpr BlobGetPropertiesResponse) ContentDisposition() string { + return bgpr.rawResponse.Header.Get("Content-Disposition") +} + +// ContentEncoding returns the value for header Content-Encoding. +func (bgpr BlobGetPropertiesResponse) ContentEncoding() string { + return bgpr.rawResponse.Header.Get("Content-Encoding") +} + +// ContentLanguage returns the value for header Content-Language. +func (bgpr BlobGetPropertiesResponse) ContentLanguage() string { + return bgpr.rawResponse.Header.Get("Content-Language") +} + +// ContentLength returns the value for header Content-Length. +func (bgpr BlobGetPropertiesResponse) ContentLength() int64 { + s := bgpr.rawResponse.Header.Get("Content-Length") + if s == "" { + return -1 + } + i, err := strconv.ParseInt(s, 10, 64) + if err != nil { + panic(err) + } + return i +} + +// ContentMD5 returns the value for header Content-MD5. +func (bgpr BlobGetPropertiesResponse) ContentMD5() []byte { + s := bgpr.rawResponse.Header.Get("Content-MD5") + if s == "" { + return nil + } + b, err := base64.StdEncoding.DecodeString(s) + if err != nil { + panic(err) + } + return b +} + +// ContentType returns the value for header Content-Type. +func (bgpr BlobGetPropertiesResponse) ContentType() string { + return bgpr.rawResponse.Header.Get("Content-Type") +} + +// CopyCompletionTime returns the value for header x-ms-copy-completion-time. +func (bgpr BlobGetPropertiesResponse) CopyCompletionTime() time.Time { + s := bgpr.rawResponse.Header.Get("x-ms-copy-completion-time") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// CopyID returns the value for header x-ms-copy-id. +func (bgpr BlobGetPropertiesResponse) CopyID() string { + return bgpr.rawResponse.Header.Get("x-ms-copy-id") +} + +// CopyProgress returns the value for header x-ms-copy-progress. +func (bgpr BlobGetPropertiesResponse) CopyProgress() string { + return bgpr.rawResponse.Header.Get("x-ms-copy-progress") +} + +// CopySource returns the value for header x-ms-copy-source. +func (bgpr BlobGetPropertiesResponse) CopySource() string { + return bgpr.rawResponse.Header.Get("x-ms-copy-source") +} + +// CopyStatus returns the value for header x-ms-copy-status. +func (bgpr BlobGetPropertiesResponse) CopyStatus() CopyStatusType { + return CopyStatusType(bgpr.rawResponse.Header.Get("x-ms-copy-status")) +} + +// CopyStatusDescription returns the value for header x-ms-copy-status-description. +func (bgpr BlobGetPropertiesResponse) CopyStatusDescription() string { + return bgpr.rawResponse.Header.Get("x-ms-copy-status-description") +} + +// Date returns the value for header Date. +func (bgpr BlobGetPropertiesResponse) Date() time.Time { + s := bgpr.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// DestinationSnapshot returns the value for header x-ms-copy-destination-snapshot. +func (bgpr BlobGetPropertiesResponse) DestinationSnapshot() string { + return bgpr.rawResponse.Header.Get("x-ms-copy-destination-snapshot") +} + +// ErrorCode returns the value for header x-ms-error-code. +func (bgpr BlobGetPropertiesResponse) ErrorCode() string { + return bgpr.rawResponse.Header.Get("x-ms-error-code") +} + +// ETag returns the value for header ETag. +func (bgpr BlobGetPropertiesResponse) ETag() ETag { + return ETag(bgpr.rawResponse.Header.Get("ETag")) +} + +// IsIncrementalCopy returns the value for header x-ms-incremental-copy. +func (bgpr BlobGetPropertiesResponse) IsIncrementalCopy() string { + return bgpr.rawResponse.Header.Get("x-ms-incremental-copy") +} + +// IsServerEncrypted returns the value for header x-ms-server-encrypted. +func (bgpr BlobGetPropertiesResponse) IsServerEncrypted() string { + return bgpr.rawResponse.Header.Get("x-ms-server-encrypted") +} + +// LastModified returns the value for header Last-Modified. +func (bgpr BlobGetPropertiesResponse) LastModified() time.Time { + s := bgpr.rawResponse.Header.Get("Last-Modified") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// LeaseDuration returns the value for header x-ms-lease-duration. +func (bgpr BlobGetPropertiesResponse) LeaseDuration() LeaseDurationType { + return LeaseDurationType(bgpr.rawResponse.Header.Get("x-ms-lease-duration")) +} + +// LeaseState returns the value for header x-ms-lease-state. +func (bgpr BlobGetPropertiesResponse) LeaseState() LeaseStateType { + return LeaseStateType(bgpr.rawResponse.Header.Get("x-ms-lease-state")) +} + +// LeaseStatus returns the value for header x-ms-lease-status. +func (bgpr BlobGetPropertiesResponse) LeaseStatus() LeaseStatusType { + return LeaseStatusType(bgpr.rawResponse.Header.Get("x-ms-lease-status")) +} + +// RequestID returns the value for header x-ms-request-id. +func (bgpr BlobGetPropertiesResponse) RequestID() string { + return bgpr.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (bgpr BlobGetPropertiesResponse) Version() string { + return bgpr.rawResponse.Header.Get("x-ms-version") +} + +// BlobHierarchyList ... +type BlobHierarchyList struct { + BlobPrefixes []BlobPrefix `xml:"BlobPrefix"` + BlobItems []BlobItem `xml:"Blob"` +} + +// BlobItem - An Azure Storage blob +type BlobItem struct { + Name string `xml:"Name"` + Deleted bool `xml:"Deleted"` + Snapshot string `xml:"Snapshot"` + Properties BlobProperties `xml:"Properties"` + Metadata Metadata `xml:"Metadata"` +} + +// BlobPrefix ... +type BlobPrefix struct { + Name string `xml:"Name"` +} + +// BlobProperties - Properties of a blob +type BlobProperties struct { + LastModified time.Time `xml:"Last-Modified"` + Etag ETag `xml:"Etag"` + // ContentLength - Size in bytes + ContentLength *int64 `xml:"Content-Length"` + ContentType *string `xml:"Content-Type"` + ContentEncoding *string `xml:"Content-Encoding"` + ContentLanguage *string `xml:"Content-Language"` + ContentMD5 []byte `xml:"Content-MD5"` + ContentDisposition *string `xml:"Content-Disposition"` + CacheControl *string `xml:"Cache-Control"` + BlobSequenceNumber *int64 `xml:"x-ms-blob-sequence-number"` + // BlobType - Possible values include: 'BlobBlockBlob', 'BlobPageBlob', 'BlobAppendBlob', 'BlobNone' + BlobType BlobType `xml:"BlobType"` + // LeaseStatus - Possible values include: 'LeaseStatusLocked', 'LeaseStatusUnlocked', 'LeaseStatusNone' + LeaseStatus LeaseStatusType `xml:"LeaseStatus"` + // LeaseState - Possible values include: 'LeaseStateAvailable', 'LeaseStateLeased', 'LeaseStateExpired', 'LeaseStateBreaking', 'LeaseStateBroken', 'LeaseStateNone' + LeaseState LeaseStateType `xml:"LeaseState"` + // LeaseDuration - Possible values include: 'LeaseDurationInfinite', 'LeaseDurationFixed', 'LeaseDurationNone' + LeaseDuration LeaseDurationType `xml:"LeaseDuration"` + CopyID *string `xml:"CopyId"` + // CopyStatus - Possible values include: 'CopyStatusPending', 'CopyStatusSuccess', 'CopyStatusAborted', 'CopyStatusFailed', 'CopyStatusNone' + CopyStatus CopyStatusType `xml:"CopyStatus"` + CopySource *string `xml:"CopySource"` + CopyProgress *string `xml:"CopyProgress"` + CopyCompletionTime *time.Time `xml:"CopyCompletionTime"` + CopyStatusDescription *string `xml:"CopyStatusDescription"` + ServerEncrypted *bool `xml:"ServerEncrypted"` + IncrementalCopy *bool `xml:"IncrementalCopy"` + DestinationSnapshot *string `xml:"DestinationSnapshot"` + DeletedTime *time.Time `xml:"DeletedTime"` + RemainingRetentionDays *int32 `xml:"RemainingRetentionDays"` + // AccessTier - Possible values include: 'AccessTierP4', 'AccessTierP6', 'AccessTierP10', 'AccessTierP20', 'AccessTierP30', 'AccessTierP40', 'AccessTierP50', 'AccessTierHot', 'AccessTierCool', 'AccessTierArchive', 'AccessTierNone' + AccessTier AccessTierType `xml:"AccessTier"` + AccessTierInferred *bool `xml:"AccessTierInferred"` + // ArchiveStatus - Possible values include: 'ArchiveStatusRehydratePendingToHot', 'ArchiveStatusRehydratePendingToCool', 'ArchiveStatusNone' + ArchiveStatus ArchiveStatusType `xml:"ArchiveStatus"` +} + +// MarshalXML implements the xml.Marshaler interface for BlobProperties. +func (bp BlobProperties) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + if reflect.TypeOf((*BlobProperties)(nil)).Elem().Size() != reflect.TypeOf((*blobProperties)(nil)).Elem().Size() { + panic("size mismatch between BlobProperties and blobProperties") + } + bp2 := (*blobProperties)(unsafe.Pointer(&bp)) + return e.EncodeElement(*bp2, start) +} + +// UnmarshalXML implements the xml.Unmarshaler interface for BlobProperties. +func (bp *BlobProperties) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + if reflect.TypeOf((*BlobProperties)(nil)).Elem().Size() != reflect.TypeOf((*blobProperties)(nil)).Elem().Size() { + panic("size mismatch between BlobProperties and blobProperties") + } + bp2 := (*blobProperties)(unsafe.Pointer(bp)) + return d.DecodeElement(bp2, &start) +} + +// BlobReleaseLeaseResponse ... +type BlobReleaseLeaseResponse struct { + rawResponse *http.Response +} + +// Response returns the raw HTTP response object. +func (brlr BlobReleaseLeaseResponse) Response() *http.Response { + return brlr.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (brlr BlobReleaseLeaseResponse) StatusCode() int { + return brlr.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (brlr BlobReleaseLeaseResponse) Status() string { + return brlr.rawResponse.Status +} + +// Date returns the value for header Date. +func (brlr BlobReleaseLeaseResponse) Date() time.Time { + s := brlr.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (brlr BlobReleaseLeaseResponse) ErrorCode() string { + return brlr.rawResponse.Header.Get("x-ms-error-code") +} + +// ETag returns the value for header ETag. +func (brlr BlobReleaseLeaseResponse) ETag() ETag { + return ETag(brlr.rawResponse.Header.Get("ETag")) +} + +// LastModified returns the value for header Last-Modified. +func (brlr BlobReleaseLeaseResponse) LastModified() time.Time { + s := brlr.rawResponse.Header.Get("Last-Modified") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// RequestID returns the value for header x-ms-request-id. +func (brlr BlobReleaseLeaseResponse) RequestID() string { + return brlr.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (brlr BlobReleaseLeaseResponse) Version() string { + return brlr.rawResponse.Header.Get("x-ms-version") +} + +// BlobRenewLeaseResponse ... +type BlobRenewLeaseResponse struct { + rawResponse *http.Response +} + +// Response returns the raw HTTP response object. +func (brlr BlobRenewLeaseResponse) Response() *http.Response { + return brlr.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (brlr BlobRenewLeaseResponse) StatusCode() int { + return brlr.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (brlr BlobRenewLeaseResponse) Status() string { + return brlr.rawResponse.Status +} + +// Date returns the value for header Date. +func (brlr BlobRenewLeaseResponse) Date() time.Time { + s := brlr.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (brlr BlobRenewLeaseResponse) ErrorCode() string { + return brlr.rawResponse.Header.Get("x-ms-error-code") +} + +// ETag returns the value for header ETag. +func (brlr BlobRenewLeaseResponse) ETag() ETag { + return ETag(brlr.rawResponse.Header.Get("ETag")) +} + +// LastModified returns the value for header Last-Modified. +func (brlr BlobRenewLeaseResponse) LastModified() time.Time { + s := brlr.rawResponse.Header.Get("Last-Modified") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// LeaseID returns the value for header x-ms-lease-id. +func (brlr BlobRenewLeaseResponse) LeaseID() string { + return brlr.rawResponse.Header.Get("x-ms-lease-id") +} + +// RequestID returns the value for header x-ms-request-id. +func (brlr BlobRenewLeaseResponse) RequestID() string { + return brlr.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (brlr BlobRenewLeaseResponse) Version() string { + return brlr.rawResponse.Header.Get("x-ms-version") +} + +// BlobSetHTTPHeadersResponse ... +type BlobSetHTTPHeadersResponse struct { + rawResponse *http.Response +} + +// Response returns the raw HTTP response object. +func (bshhr BlobSetHTTPHeadersResponse) Response() *http.Response { + return bshhr.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (bshhr BlobSetHTTPHeadersResponse) StatusCode() int { + return bshhr.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (bshhr BlobSetHTTPHeadersResponse) Status() string { + return bshhr.rawResponse.Status +} + +// BlobSequenceNumber returns the value for header x-ms-blob-sequence-number. +func (bshhr BlobSetHTTPHeadersResponse) BlobSequenceNumber() int64 { + s := bshhr.rawResponse.Header.Get("x-ms-blob-sequence-number") + if s == "" { + return -1 + } + i, err := strconv.ParseInt(s, 10, 64) + if err != nil { + panic(err) + } + return i +} + +// Date returns the value for header Date. +func (bshhr BlobSetHTTPHeadersResponse) Date() time.Time { + s := bshhr.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (bshhr BlobSetHTTPHeadersResponse) ErrorCode() string { + return bshhr.rawResponse.Header.Get("x-ms-error-code") +} + +// ETag returns the value for header ETag. +func (bshhr BlobSetHTTPHeadersResponse) ETag() ETag { + return ETag(bshhr.rawResponse.Header.Get("ETag")) +} + +// LastModified returns the value for header Last-Modified. +func (bshhr BlobSetHTTPHeadersResponse) LastModified() time.Time { + s := bshhr.rawResponse.Header.Get("Last-Modified") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// RequestID returns the value for header x-ms-request-id. +func (bshhr BlobSetHTTPHeadersResponse) RequestID() string { + return bshhr.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (bshhr BlobSetHTTPHeadersResponse) Version() string { + return bshhr.rawResponse.Header.Get("x-ms-version") +} + +// BlobSetMetadataResponse ... +type BlobSetMetadataResponse struct { + rawResponse *http.Response +} + +// Response returns the raw HTTP response object. +func (bsmr BlobSetMetadataResponse) Response() *http.Response { + return bsmr.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (bsmr BlobSetMetadataResponse) StatusCode() int { + return bsmr.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (bsmr BlobSetMetadataResponse) Status() string { + return bsmr.rawResponse.Status +} + +// Date returns the value for header Date. +func (bsmr BlobSetMetadataResponse) Date() time.Time { + s := bsmr.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (bsmr BlobSetMetadataResponse) ErrorCode() string { + return bsmr.rawResponse.Header.Get("x-ms-error-code") +} + +// ETag returns the value for header ETag. +func (bsmr BlobSetMetadataResponse) ETag() ETag { + return ETag(bsmr.rawResponse.Header.Get("ETag")) +} + +// IsServerEncrypted returns the value for header x-ms-request-server-encrypted. +func (bsmr BlobSetMetadataResponse) IsServerEncrypted() string { + return bsmr.rawResponse.Header.Get("x-ms-request-server-encrypted") +} + +// LastModified returns the value for header Last-Modified. +func (bsmr BlobSetMetadataResponse) LastModified() time.Time { + s := bsmr.rawResponse.Header.Get("Last-Modified") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// RequestID returns the value for header x-ms-request-id. +func (bsmr BlobSetMetadataResponse) RequestID() string { + return bsmr.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (bsmr BlobSetMetadataResponse) Version() string { + return bsmr.rawResponse.Header.Get("x-ms-version") +} + +// BlobSetTierResponse ... +type BlobSetTierResponse struct { + rawResponse *http.Response +} + +// Response returns the raw HTTP response object. +func (bstr BlobSetTierResponse) Response() *http.Response { + return bstr.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (bstr BlobSetTierResponse) StatusCode() int { + return bstr.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (bstr BlobSetTierResponse) Status() string { + return bstr.rawResponse.Status +} + +// ErrorCode returns the value for header x-ms-error-code. +func (bstr BlobSetTierResponse) ErrorCode() string { + return bstr.rawResponse.Header.Get("x-ms-error-code") +} + +// RequestID returns the value for header x-ms-request-id. +func (bstr BlobSetTierResponse) RequestID() string { + return bstr.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (bstr BlobSetTierResponse) Version() string { + return bstr.rawResponse.Header.Get("x-ms-version") +} + +// BlobStartCopyFromURLResponse ... +type BlobStartCopyFromURLResponse struct { + rawResponse *http.Response +} + +// Response returns the raw HTTP response object. +func (bscfur BlobStartCopyFromURLResponse) Response() *http.Response { + return bscfur.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (bscfur BlobStartCopyFromURLResponse) StatusCode() int { + return bscfur.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (bscfur BlobStartCopyFromURLResponse) Status() string { + return bscfur.rawResponse.Status +} + +// CopyID returns the value for header x-ms-copy-id. +func (bscfur BlobStartCopyFromURLResponse) CopyID() string { + return bscfur.rawResponse.Header.Get("x-ms-copy-id") +} + +// CopyStatus returns the value for header x-ms-copy-status. +func (bscfur BlobStartCopyFromURLResponse) CopyStatus() CopyStatusType { + return CopyStatusType(bscfur.rawResponse.Header.Get("x-ms-copy-status")) +} + +// Date returns the value for header Date. +func (bscfur BlobStartCopyFromURLResponse) Date() time.Time { + s := bscfur.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (bscfur BlobStartCopyFromURLResponse) ErrorCode() string { + return bscfur.rawResponse.Header.Get("x-ms-error-code") +} + +// ETag returns the value for header ETag. +func (bscfur BlobStartCopyFromURLResponse) ETag() ETag { + return ETag(bscfur.rawResponse.Header.Get("ETag")) +} + +// LastModified returns the value for header Last-Modified. +func (bscfur BlobStartCopyFromURLResponse) LastModified() time.Time { + s := bscfur.rawResponse.Header.Get("Last-Modified") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// RequestID returns the value for header x-ms-request-id. +func (bscfur BlobStartCopyFromURLResponse) RequestID() string { + return bscfur.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (bscfur BlobStartCopyFromURLResponse) Version() string { + return bscfur.rawResponse.Header.Get("x-ms-version") +} + +// BlobUndeleteResponse ... +type BlobUndeleteResponse struct { + rawResponse *http.Response +} + +// Response returns the raw HTTP response object. +func (bur BlobUndeleteResponse) Response() *http.Response { + return bur.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (bur BlobUndeleteResponse) StatusCode() int { + return bur.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (bur BlobUndeleteResponse) Status() string { + return bur.rawResponse.Status +} + +// Date returns the value for header Date. +func (bur BlobUndeleteResponse) Date() time.Time { + s := bur.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (bur BlobUndeleteResponse) ErrorCode() string { + return bur.rawResponse.Header.Get("x-ms-error-code") +} + +// RequestID returns the value for header x-ms-request-id. +func (bur BlobUndeleteResponse) RequestID() string { + return bur.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (bur BlobUndeleteResponse) Version() string { + return bur.rawResponse.Header.Get("x-ms-version") +} + +// Block - Represents a single block in a block blob. It describes the block's ID and size. +type Block struct { + // Name - The base64 encoded block ID. + Name string `xml:"Name"` + // Size - The block size in bytes. + Size int32 `xml:"Size"` +} + +// BlockBlobCommitBlockListResponse ... +type BlockBlobCommitBlockListResponse struct { + rawResponse *http.Response +} + +// Response returns the raw HTTP response object. +func (bbcblr BlockBlobCommitBlockListResponse) Response() *http.Response { + return bbcblr.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (bbcblr BlockBlobCommitBlockListResponse) StatusCode() int { + return bbcblr.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (bbcblr BlockBlobCommitBlockListResponse) Status() string { + return bbcblr.rawResponse.Status +} + +// ContentMD5 returns the value for header Content-MD5. +func (bbcblr BlockBlobCommitBlockListResponse) ContentMD5() []byte { + s := bbcblr.rawResponse.Header.Get("Content-MD5") + if s == "" { + return nil + } + b, err := base64.StdEncoding.DecodeString(s) + if err != nil { + panic(err) + } + return b +} + +// Date returns the value for header Date. +func (bbcblr BlockBlobCommitBlockListResponse) Date() time.Time { + s := bbcblr.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (bbcblr BlockBlobCommitBlockListResponse) ErrorCode() string { + return bbcblr.rawResponse.Header.Get("x-ms-error-code") +} + +// ETag returns the value for header ETag. +func (bbcblr BlockBlobCommitBlockListResponse) ETag() ETag { + return ETag(bbcblr.rawResponse.Header.Get("ETag")) +} + +// IsServerEncrypted returns the value for header x-ms-request-server-encrypted. +func (bbcblr BlockBlobCommitBlockListResponse) IsServerEncrypted() string { + return bbcblr.rawResponse.Header.Get("x-ms-request-server-encrypted") +} + +// LastModified returns the value for header Last-Modified. +func (bbcblr BlockBlobCommitBlockListResponse) LastModified() time.Time { + s := bbcblr.rawResponse.Header.Get("Last-Modified") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// RequestID returns the value for header x-ms-request-id. +func (bbcblr BlockBlobCommitBlockListResponse) RequestID() string { + return bbcblr.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (bbcblr BlockBlobCommitBlockListResponse) Version() string { + return bbcblr.rawResponse.Header.Get("x-ms-version") +} + +// BlockBlobStageBlockFromURLResponse ... +type BlockBlobStageBlockFromURLResponse struct { + rawResponse *http.Response +} + +// Response returns the raw HTTP response object. +func (bbsbfur BlockBlobStageBlockFromURLResponse) Response() *http.Response { + return bbsbfur.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (bbsbfur BlockBlobStageBlockFromURLResponse) StatusCode() int { + return bbsbfur.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (bbsbfur BlockBlobStageBlockFromURLResponse) Status() string { + return bbsbfur.rawResponse.Status +} + +// ContentMD5 returns the value for header Content-MD5. +func (bbsbfur BlockBlobStageBlockFromURLResponse) ContentMD5() []byte { + s := bbsbfur.rawResponse.Header.Get("Content-MD5") + if s == "" { + return nil + } + b, err := base64.StdEncoding.DecodeString(s) + if err != nil { + panic(err) + } + return b +} + +// Date returns the value for header Date. +func (bbsbfur BlockBlobStageBlockFromURLResponse) Date() time.Time { + s := bbsbfur.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (bbsbfur BlockBlobStageBlockFromURLResponse) ErrorCode() string { + return bbsbfur.rawResponse.Header.Get("x-ms-error-code") +} + +// IsServerEncrypted returns the value for header x-ms-request-server-encrypted. +func (bbsbfur BlockBlobStageBlockFromURLResponse) IsServerEncrypted() string { + return bbsbfur.rawResponse.Header.Get("x-ms-request-server-encrypted") +} + +// RequestID returns the value for header x-ms-request-id. +func (bbsbfur BlockBlobStageBlockFromURLResponse) RequestID() string { + return bbsbfur.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (bbsbfur BlockBlobStageBlockFromURLResponse) Version() string { + return bbsbfur.rawResponse.Header.Get("x-ms-version") +} + +// BlockBlobStageBlockResponse ... +type BlockBlobStageBlockResponse struct { + rawResponse *http.Response +} + +// Response returns the raw HTTP response object. +func (bbsbr BlockBlobStageBlockResponse) Response() *http.Response { + return bbsbr.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (bbsbr BlockBlobStageBlockResponse) StatusCode() int { + return bbsbr.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (bbsbr BlockBlobStageBlockResponse) Status() string { + return bbsbr.rawResponse.Status +} + +// ContentMD5 returns the value for header Content-MD5. +func (bbsbr BlockBlobStageBlockResponse) ContentMD5() []byte { + s := bbsbr.rawResponse.Header.Get("Content-MD5") + if s == "" { + return nil + } + b, err := base64.StdEncoding.DecodeString(s) + if err != nil { + panic(err) + } + return b +} + +// Date returns the value for header Date. +func (bbsbr BlockBlobStageBlockResponse) Date() time.Time { + s := bbsbr.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (bbsbr BlockBlobStageBlockResponse) ErrorCode() string { + return bbsbr.rawResponse.Header.Get("x-ms-error-code") +} + +// IsServerEncrypted returns the value for header x-ms-request-server-encrypted. +func (bbsbr BlockBlobStageBlockResponse) IsServerEncrypted() string { + return bbsbr.rawResponse.Header.Get("x-ms-request-server-encrypted") +} + +// RequestID returns the value for header x-ms-request-id. +func (bbsbr BlockBlobStageBlockResponse) RequestID() string { + return bbsbr.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (bbsbr BlockBlobStageBlockResponse) Version() string { + return bbsbr.rawResponse.Header.Get("x-ms-version") +} + +// BlockBlobUploadResponse ... +type BlockBlobUploadResponse struct { + rawResponse *http.Response +} + +// Response returns the raw HTTP response object. +func (bbur BlockBlobUploadResponse) Response() *http.Response { + return bbur.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (bbur BlockBlobUploadResponse) StatusCode() int { + return bbur.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (bbur BlockBlobUploadResponse) Status() string { + return bbur.rawResponse.Status +} + +// ContentMD5 returns the value for header Content-MD5. +func (bbur BlockBlobUploadResponse) ContentMD5() []byte { + s := bbur.rawResponse.Header.Get("Content-MD5") + if s == "" { + return nil + } + b, err := base64.StdEncoding.DecodeString(s) + if err != nil { + panic(err) + } + return b +} + +// Date returns the value for header Date. +func (bbur BlockBlobUploadResponse) Date() time.Time { + s := bbur.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (bbur BlockBlobUploadResponse) ErrorCode() string { + return bbur.rawResponse.Header.Get("x-ms-error-code") +} + +// ETag returns the value for header ETag. +func (bbur BlockBlobUploadResponse) ETag() ETag { + return ETag(bbur.rawResponse.Header.Get("ETag")) +} + +// IsServerEncrypted returns the value for header x-ms-request-server-encrypted. +func (bbur BlockBlobUploadResponse) IsServerEncrypted() string { + return bbur.rawResponse.Header.Get("x-ms-request-server-encrypted") +} + +// LastModified returns the value for header Last-Modified. +func (bbur BlockBlobUploadResponse) LastModified() time.Time { + s := bbur.rawResponse.Header.Get("Last-Modified") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// RequestID returns the value for header x-ms-request-id. +func (bbur BlockBlobUploadResponse) RequestID() string { + return bbur.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (bbur BlockBlobUploadResponse) Version() string { + return bbur.rawResponse.Header.Get("x-ms-version") +} + +// BlockList ... +type BlockList struct { + rawResponse *http.Response + CommittedBlocks []Block `xml:"CommittedBlocks>Block"` + UncommittedBlocks []Block `xml:"UncommittedBlocks>Block"` +} + +// Response returns the raw HTTP response object. +func (bl BlockList) Response() *http.Response { + return bl.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (bl BlockList) StatusCode() int { + return bl.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (bl BlockList) Status() string { + return bl.rawResponse.Status +} + +// BlobContentLength returns the value for header x-ms-blob-content-length. +func (bl BlockList) BlobContentLength() int64 { + s := bl.rawResponse.Header.Get("x-ms-blob-content-length") + if s == "" { + return -1 + } + i, err := strconv.ParseInt(s, 10, 64) + if err != nil { + panic(err) + } + return i +} + +// ContentType returns the value for header Content-Type. +func (bl BlockList) ContentType() string { + return bl.rawResponse.Header.Get("Content-Type") +} + +// Date returns the value for header Date. +func (bl BlockList) Date() time.Time { + s := bl.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (bl BlockList) ErrorCode() string { + return bl.rawResponse.Header.Get("x-ms-error-code") +} + +// ETag returns the value for header ETag. +func (bl BlockList) ETag() ETag { + return ETag(bl.rawResponse.Header.Get("ETag")) +} + +// LastModified returns the value for header Last-Modified. +func (bl BlockList) LastModified() time.Time { + s := bl.rawResponse.Header.Get("Last-Modified") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// RequestID returns the value for header x-ms-request-id. +func (bl BlockList) RequestID() string { + return bl.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (bl BlockList) Version() string { + return bl.rawResponse.Header.Get("x-ms-version") +} + +// BlockLookupList ... +type BlockLookupList struct { + // XMLName is used for marshalling and is subject to removal in a future release. + XMLName xml.Name `xml:"BlockList"` + Committed []string `xml:"Committed"` + Uncommitted []string `xml:"Uncommitted"` + Latest []string `xml:"Latest"` +} + +// ClearRange ... +type ClearRange struct { + Start int64 `xml:"Start"` + End int64 `xml:"End"` +} + +// ContainerAcquireLeaseResponse ... +type ContainerAcquireLeaseResponse struct { + rawResponse *http.Response +} + +// Response returns the raw HTTP response object. +func (calr ContainerAcquireLeaseResponse) Response() *http.Response { + return calr.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (calr ContainerAcquireLeaseResponse) StatusCode() int { + return calr.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (calr ContainerAcquireLeaseResponse) Status() string { + return calr.rawResponse.Status +} + +// Date returns the value for header Date. +func (calr ContainerAcquireLeaseResponse) Date() time.Time { + s := calr.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (calr ContainerAcquireLeaseResponse) ErrorCode() string { + return calr.rawResponse.Header.Get("x-ms-error-code") +} + +// ETag returns the value for header ETag. +func (calr ContainerAcquireLeaseResponse) ETag() ETag { + return ETag(calr.rawResponse.Header.Get("ETag")) +} + +// LastModified returns the value for header Last-Modified. +func (calr ContainerAcquireLeaseResponse) LastModified() time.Time { + s := calr.rawResponse.Header.Get("Last-Modified") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// LeaseID returns the value for header x-ms-lease-id. +func (calr ContainerAcquireLeaseResponse) LeaseID() string { + return calr.rawResponse.Header.Get("x-ms-lease-id") +} + +// RequestID returns the value for header x-ms-request-id. +func (calr ContainerAcquireLeaseResponse) RequestID() string { + return calr.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (calr ContainerAcquireLeaseResponse) Version() string { + return calr.rawResponse.Header.Get("x-ms-version") +} + +// ContainerBreakLeaseResponse ... +type ContainerBreakLeaseResponse struct { + rawResponse *http.Response +} + +// Response returns the raw HTTP response object. +func (cblr ContainerBreakLeaseResponse) Response() *http.Response { + return cblr.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (cblr ContainerBreakLeaseResponse) StatusCode() int { + return cblr.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (cblr ContainerBreakLeaseResponse) Status() string { + return cblr.rawResponse.Status +} + +// Date returns the value for header Date. +func (cblr ContainerBreakLeaseResponse) Date() time.Time { + s := cblr.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (cblr ContainerBreakLeaseResponse) ErrorCode() string { + return cblr.rawResponse.Header.Get("x-ms-error-code") +} + +// ETag returns the value for header ETag. +func (cblr ContainerBreakLeaseResponse) ETag() ETag { + return ETag(cblr.rawResponse.Header.Get("ETag")) +} + +// LastModified returns the value for header Last-Modified. +func (cblr ContainerBreakLeaseResponse) LastModified() time.Time { + s := cblr.rawResponse.Header.Get("Last-Modified") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// LeaseTime returns the value for header x-ms-lease-time. +func (cblr ContainerBreakLeaseResponse) LeaseTime() int32 { + s := cblr.rawResponse.Header.Get("x-ms-lease-time") + if s == "" { + return -1 + } + i, err := strconv.ParseInt(s, 10, 32) + if err != nil { + panic(err) + } + return int32(i) +} + +// RequestID returns the value for header x-ms-request-id. +func (cblr ContainerBreakLeaseResponse) RequestID() string { + return cblr.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (cblr ContainerBreakLeaseResponse) Version() string { + return cblr.rawResponse.Header.Get("x-ms-version") +} + +// ContainerChangeLeaseResponse ... +type ContainerChangeLeaseResponse struct { + rawResponse *http.Response +} + +// Response returns the raw HTTP response object. +func (cclr ContainerChangeLeaseResponse) Response() *http.Response { + return cclr.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (cclr ContainerChangeLeaseResponse) StatusCode() int { + return cclr.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (cclr ContainerChangeLeaseResponse) Status() string { + return cclr.rawResponse.Status +} + +// Date returns the value for header Date. +func (cclr ContainerChangeLeaseResponse) Date() time.Time { + s := cclr.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (cclr ContainerChangeLeaseResponse) ErrorCode() string { + return cclr.rawResponse.Header.Get("x-ms-error-code") +} + +// ETag returns the value for header ETag. +func (cclr ContainerChangeLeaseResponse) ETag() ETag { + return ETag(cclr.rawResponse.Header.Get("ETag")) +} + +// LastModified returns the value for header Last-Modified. +func (cclr ContainerChangeLeaseResponse) LastModified() time.Time { + s := cclr.rawResponse.Header.Get("Last-Modified") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// LeaseID returns the value for header x-ms-lease-id. +func (cclr ContainerChangeLeaseResponse) LeaseID() string { + return cclr.rawResponse.Header.Get("x-ms-lease-id") +} + +// RequestID returns the value for header x-ms-request-id. +func (cclr ContainerChangeLeaseResponse) RequestID() string { + return cclr.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (cclr ContainerChangeLeaseResponse) Version() string { + return cclr.rawResponse.Header.Get("x-ms-version") +} + +// ContainerCreateResponse ... +type ContainerCreateResponse struct { + rawResponse *http.Response +} + +// Response returns the raw HTTP response object. +func (ccr ContainerCreateResponse) Response() *http.Response { + return ccr.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (ccr ContainerCreateResponse) StatusCode() int { + return ccr.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (ccr ContainerCreateResponse) Status() string { + return ccr.rawResponse.Status +} + +// Date returns the value for header Date. +func (ccr ContainerCreateResponse) Date() time.Time { + s := ccr.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (ccr ContainerCreateResponse) ErrorCode() string { + return ccr.rawResponse.Header.Get("x-ms-error-code") +} + +// ETag returns the value for header ETag. +func (ccr ContainerCreateResponse) ETag() ETag { + return ETag(ccr.rawResponse.Header.Get("ETag")) +} + +// LastModified returns the value for header Last-Modified. +func (ccr ContainerCreateResponse) LastModified() time.Time { + s := ccr.rawResponse.Header.Get("Last-Modified") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// RequestID returns the value for header x-ms-request-id. +func (ccr ContainerCreateResponse) RequestID() string { + return ccr.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (ccr ContainerCreateResponse) Version() string { + return ccr.rawResponse.Header.Get("x-ms-version") +} + +// ContainerDeleteResponse ... +type ContainerDeleteResponse struct { + rawResponse *http.Response +} + +// Response returns the raw HTTP response object. +func (cdr ContainerDeleteResponse) Response() *http.Response { + return cdr.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (cdr ContainerDeleteResponse) StatusCode() int { + return cdr.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (cdr ContainerDeleteResponse) Status() string { + return cdr.rawResponse.Status +} + +// Date returns the value for header Date. +func (cdr ContainerDeleteResponse) Date() time.Time { + s := cdr.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (cdr ContainerDeleteResponse) ErrorCode() string { + return cdr.rawResponse.Header.Get("x-ms-error-code") +} + +// RequestID returns the value for header x-ms-request-id. +func (cdr ContainerDeleteResponse) RequestID() string { + return cdr.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (cdr ContainerDeleteResponse) Version() string { + return cdr.rawResponse.Header.Get("x-ms-version") +} + +// ContainerGetPropertiesResponse ... +type ContainerGetPropertiesResponse struct { + rawResponse *http.Response +} + +// NewMetadata returns user-defined key/value pairs. +func (cgpr ContainerGetPropertiesResponse) NewMetadata() Metadata { + md := Metadata{} + for k, v := range cgpr.rawResponse.Header { + if len(k) > mdPrefixLen { + if prefix := k[0:mdPrefixLen]; strings.EqualFold(prefix, mdPrefix) { + md[strings.ToLower(k[mdPrefixLen:])] = v[0] + } + } + } + return md +} + +// Response returns the raw HTTP response object. +func (cgpr ContainerGetPropertiesResponse) Response() *http.Response { + return cgpr.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (cgpr ContainerGetPropertiesResponse) StatusCode() int { + return cgpr.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (cgpr ContainerGetPropertiesResponse) Status() string { + return cgpr.rawResponse.Status +} + +// BlobPublicAccess returns the value for header x-ms-blob-public-access. +func (cgpr ContainerGetPropertiesResponse) BlobPublicAccess() PublicAccessType { + return PublicAccessType(cgpr.rawResponse.Header.Get("x-ms-blob-public-access")) +} + +// Date returns the value for header Date. +func (cgpr ContainerGetPropertiesResponse) Date() time.Time { + s := cgpr.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (cgpr ContainerGetPropertiesResponse) ErrorCode() string { + return cgpr.rawResponse.Header.Get("x-ms-error-code") +} + +// ETag returns the value for header ETag. +func (cgpr ContainerGetPropertiesResponse) ETag() ETag { + return ETag(cgpr.rawResponse.Header.Get("ETag")) +} + +// LastModified returns the value for header Last-Modified. +func (cgpr ContainerGetPropertiesResponse) LastModified() time.Time { + s := cgpr.rawResponse.Header.Get("Last-Modified") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// LeaseDuration returns the value for header x-ms-lease-duration. +func (cgpr ContainerGetPropertiesResponse) LeaseDuration() LeaseDurationType { + return LeaseDurationType(cgpr.rawResponse.Header.Get("x-ms-lease-duration")) +} + +// LeaseState returns the value for header x-ms-lease-state. +func (cgpr ContainerGetPropertiesResponse) LeaseState() LeaseStateType { + return LeaseStateType(cgpr.rawResponse.Header.Get("x-ms-lease-state")) +} + +// LeaseStatus returns the value for header x-ms-lease-status. +func (cgpr ContainerGetPropertiesResponse) LeaseStatus() LeaseStatusType { + return LeaseStatusType(cgpr.rawResponse.Header.Get("x-ms-lease-status")) +} + +// RequestID returns the value for header x-ms-request-id. +func (cgpr ContainerGetPropertiesResponse) RequestID() string { + return cgpr.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (cgpr ContainerGetPropertiesResponse) Version() string { + return cgpr.rawResponse.Header.Get("x-ms-version") +} + +// ContainerItem - An Azure Storage container +type ContainerItem struct { + Name string `xml:"Name"` + Properties ContainerProperties `xml:"Properties"` + Metadata Metadata `xml:"Metadata"` +} + +// ContainerProperties - Properties of a container +type ContainerProperties struct { + LastModified time.Time `xml:"Last-Modified"` + Etag ETag `xml:"Etag"` + // LeaseStatus - Possible values include: 'LeaseStatusLocked', 'LeaseStatusUnlocked', 'LeaseStatusNone' + LeaseStatus LeaseStatusType `xml:"LeaseStatus"` + // LeaseState - Possible values include: 'LeaseStateAvailable', 'LeaseStateLeased', 'LeaseStateExpired', 'LeaseStateBreaking', 'LeaseStateBroken', 'LeaseStateNone' + LeaseState LeaseStateType `xml:"LeaseState"` + // LeaseDuration - Possible values include: 'LeaseDurationInfinite', 'LeaseDurationFixed', 'LeaseDurationNone' + LeaseDuration LeaseDurationType `xml:"LeaseDuration"` + // PublicAccess - Possible values include: 'PublicAccessContainer', 'PublicAccessBlob', 'PublicAccessNone' + PublicAccess PublicAccessType `xml:"PublicAccess"` +} + +// MarshalXML implements the xml.Marshaler interface for ContainerProperties. +func (cp ContainerProperties) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + if reflect.TypeOf((*ContainerProperties)(nil)).Elem().Size() != reflect.TypeOf((*containerProperties)(nil)).Elem().Size() { + panic("size mismatch between ContainerProperties and containerProperties") + } + cp2 := (*containerProperties)(unsafe.Pointer(&cp)) + return e.EncodeElement(*cp2, start) +} + +// UnmarshalXML implements the xml.Unmarshaler interface for ContainerProperties. +func (cp *ContainerProperties) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + if reflect.TypeOf((*ContainerProperties)(nil)).Elem().Size() != reflect.TypeOf((*containerProperties)(nil)).Elem().Size() { + panic("size mismatch between ContainerProperties and containerProperties") + } + cp2 := (*containerProperties)(unsafe.Pointer(cp)) + return d.DecodeElement(cp2, &start) +} + +// ContainerReleaseLeaseResponse ... +type ContainerReleaseLeaseResponse struct { + rawResponse *http.Response +} + +// Response returns the raw HTTP response object. +func (crlr ContainerReleaseLeaseResponse) Response() *http.Response { + return crlr.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (crlr ContainerReleaseLeaseResponse) StatusCode() int { + return crlr.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (crlr ContainerReleaseLeaseResponse) Status() string { + return crlr.rawResponse.Status +} + +// Date returns the value for header Date. +func (crlr ContainerReleaseLeaseResponse) Date() time.Time { + s := crlr.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (crlr ContainerReleaseLeaseResponse) ErrorCode() string { + return crlr.rawResponse.Header.Get("x-ms-error-code") +} + +// ETag returns the value for header ETag. +func (crlr ContainerReleaseLeaseResponse) ETag() ETag { + return ETag(crlr.rawResponse.Header.Get("ETag")) +} + +// LastModified returns the value for header Last-Modified. +func (crlr ContainerReleaseLeaseResponse) LastModified() time.Time { + s := crlr.rawResponse.Header.Get("Last-Modified") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// RequestID returns the value for header x-ms-request-id. +func (crlr ContainerReleaseLeaseResponse) RequestID() string { + return crlr.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (crlr ContainerReleaseLeaseResponse) Version() string { + return crlr.rawResponse.Header.Get("x-ms-version") +} + +// ContainerRenewLeaseResponse ... +type ContainerRenewLeaseResponse struct { + rawResponse *http.Response +} + +// Response returns the raw HTTP response object. +func (crlr ContainerRenewLeaseResponse) Response() *http.Response { + return crlr.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (crlr ContainerRenewLeaseResponse) StatusCode() int { + return crlr.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (crlr ContainerRenewLeaseResponse) Status() string { + return crlr.rawResponse.Status +} + +// Date returns the value for header Date. +func (crlr ContainerRenewLeaseResponse) Date() time.Time { + s := crlr.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (crlr ContainerRenewLeaseResponse) ErrorCode() string { + return crlr.rawResponse.Header.Get("x-ms-error-code") +} + +// ETag returns the value for header ETag. +func (crlr ContainerRenewLeaseResponse) ETag() ETag { + return ETag(crlr.rawResponse.Header.Get("ETag")) +} + +// LastModified returns the value for header Last-Modified. +func (crlr ContainerRenewLeaseResponse) LastModified() time.Time { + s := crlr.rawResponse.Header.Get("Last-Modified") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// LeaseID returns the value for header x-ms-lease-id. +func (crlr ContainerRenewLeaseResponse) LeaseID() string { + return crlr.rawResponse.Header.Get("x-ms-lease-id") +} + +// RequestID returns the value for header x-ms-request-id. +func (crlr ContainerRenewLeaseResponse) RequestID() string { + return crlr.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (crlr ContainerRenewLeaseResponse) Version() string { + return crlr.rawResponse.Header.Get("x-ms-version") +} + +// ContainerSetAccessPolicyResponse ... +type ContainerSetAccessPolicyResponse struct { + rawResponse *http.Response +} + +// Response returns the raw HTTP response object. +func (csapr ContainerSetAccessPolicyResponse) Response() *http.Response { + return csapr.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (csapr ContainerSetAccessPolicyResponse) StatusCode() int { + return csapr.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (csapr ContainerSetAccessPolicyResponse) Status() string { + return csapr.rawResponse.Status +} + +// Date returns the value for header Date. +func (csapr ContainerSetAccessPolicyResponse) Date() time.Time { + s := csapr.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (csapr ContainerSetAccessPolicyResponse) ErrorCode() string { + return csapr.rawResponse.Header.Get("x-ms-error-code") +} + +// ETag returns the value for header ETag. +func (csapr ContainerSetAccessPolicyResponse) ETag() ETag { + return ETag(csapr.rawResponse.Header.Get("ETag")) +} + +// LastModified returns the value for header Last-Modified. +func (csapr ContainerSetAccessPolicyResponse) LastModified() time.Time { + s := csapr.rawResponse.Header.Get("Last-Modified") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// RequestID returns the value for header x-ms-request-id. +func (csapr ContainerSetAccessPolicyResponse) RequestID() string { + return csapr.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (csapr ContainerSetAccessPolicyResponse) Version() string { + return csapr.rawResponse.Header.Get("x-ms-version") +} + +// ContainerSetMetadataResponse ... +type ContainerSetMetadataResponse struct { + rawResponse *http.Response +} + +// Response returns the raw HTTP response object. +func (csmr ContainerSetMetadataResponse) Response() *http.Response { + return csmr.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (csmr ContainerSetMetadataResponse) StatusCode() int { + return csmr.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (csmr ContainerSetMetadataResponse) Status() string { + return csmr.rawResponse.Status +} + +// Date returns the value for header Date. +func (csmr ContainerSetMetadataResponse) Date() time.Time { + s := csmr.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (csmr ContainerSetMetadataResponse) ErrorCode() string { + return csmr.rawResponse.Header.Get("x-ms-error-code") +} + +// ETag returns the value for header ETag. +func (csmr ContainerSetMetadataResponse) ETag() ETag { + return ETag(csmr.rawResponse.Header.Get("ETag")) +} + +// LastModified returns the value for header Last-Modified. +func (csmr ContainerSetMetadataResponse) LastModified() time.Time { + s := csmr.rawResponse.Header.Get("Last-Modified") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// RequestID returns the value for header x-ms-request-id. +func (csmr ContainerSetMetadataResponse) RequestID() string { + return csmr.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (csmr ContainerSetMetadataResponse) Version() string { + return csmr.rawResponse.Header.Get("x-ms-version") +} + +// CorsRule - CORS is an HTTP feature that enables a web application running under one domain to access +// resources in another domain. Web browsers implement a security restriction known as same-origin policy that +// prevents a web page from calling APIs in a different domain; CORS provides a secure way to allow one domain +// (the origin domain) to call APIs in another domain +type CorsRule struct { + // AllowedOrigins - The origin domains that are permitted to make a request against the storage service via CORS. The origin domain is the domain from which the request originates. Note that the origin must be an exact case-sensitive match with the origin that the user age sends to the service. You can also use the wildcard character '*' to allow all origin domains to make requests via CORS. + AllowedOrigins string `xml:"AllowedOrigins"` + // AllowedMethods - The methods (HTTP request verbs) that the origin domain may use for a CORS request. (comma separated) + AllowedMethods string `xml:"AllowedMethods"` + // AllowedHeaders - the request headers that the origin domain may specify on the CORS request. + AllowedHeaders string `xml:"AllowedHeaders"` + // ExposedHeaders - The response headers that may be sent in the response to the CORS request and exposed by the browser to the request issuer + ExposedHeaders string `xml:"ExposedHeaders"` + // MaxAgeInSeconds - The maximum amount time that a browser should cache the preflight OPTIONS request. + MaxAgeInSeconds int32 `xml:"MaxAgeInSeconds"` +} + +// downloadResponse ... +type downloadResponse struct { + rawResponse *http.Response +} + +// NewMetadata returns user-defined key/value pairs. +func (dr downloadResponse) NewMetadata() Metadata { + md := Metadata{} + for k, v := range dr.rawResponse.Header { + if len(k) > mdPrefixLen { + if prefix := k[0:mdPrefixLen]; strings.EqualFold(prefix, mdPrefix) { + md[strings.ToLower(k[mdPrefixLen:])] = v[0] + } + } + } + return md +} + +// Response returns the raw HTTP response object. +func (dr downloadResponse) Response() *http.Response { + return dr.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (dr downloadResponse) StatusCode() int { + return dr.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (dr downloadResponse) Status() string { + return dr.rawResponse.Status +} + +// Body returns the raw HTTP response object's Body. +func (dr downloadResponse) Body() io.ReadCloser { + return dr.rawResponse.Body +} + +// AcceptRanges returns the value for header Accept-Ranges. +func (dr downloadResponse) AcceptRanges() string { + return dr.rawResponse.Header.Get("Accept-Ranges") +} + +// BlobCommittedBlockCount returns the value for header x-ms-blob-committed-block-count. +func (dr downloadResponse) BlobCommittedBlockCount() int32 { + s := dr.rawResponse.Header.Get("x-ms-blob-committed-block-count") + if s == "" { + return -1 + } + i, err := strconv.ParseInt(s, 10, 32) + if err != nil { + panic(err) + } + return int32(i) +} + +// BlobContentMD5 returns the value for header x-ms-blob-content-md5. +func (dr downloadResponse) BlobContentMD5() []byte { + s := dr.rawResponse.Header.Get("x-ms-blob-content-md5") + if s == "" { + return nil + } + b, err := base64.StdEncoding.DecodeString(s) + if err != nil { + panic(err) + } + return b +} + +// BlobSequenceNumber returns the value for header x-ms-blob-sequence-number. +func (dr downloadResponse) BlobSequenceNumber() int64 { + s := dr.rawResponse.Header.Get("x-ms-blob-sequence-number") + if s == "" { + return -1 + } + i, err := strconv.ParseInt(s, 10, 64) + if err != nil { + panic(err) + } + return i +} + +// BlobType returns the value for header x-ms-blob-type. +func (dr downloadResponse) BlobType() BlobType { + return BlobType(dr.rawResponse.Header.Get("x-ms-blob-type")) +} + +// CacheControl returns the value for header Cache-Control. +func (dr downloadResponse) CacheControl() string { + return dr.rawResponse.Header.Get("Cache-Control") +} + +// ContentDisposition returns the value for header Content-Disposition. +func (dr downloadResponse) ContentDisposition() string { + return dr.rawResponse.Header.Get("Content-Disposition") +} + +// ContentEncoding returns the value for header Content-Encoding. +func (dr downloadResponse) ContentEncoding() string { + return dr.rawResponse.Header.Get("Content-Encoding") +} + +// ContentLanguage returns the value for header Content-Language. +func (dr downloadResponse) ContentLanguage() string { + return dr.rawResponse.Header.Get("Content-Language") +} + +// ContentLength returns the value for header Content-Length. +func (dr downloadResponse) ContentLength() int64 { + s := dr.rawResponse.Header.Get("Content-Length") + if s == "" { + return -1 + } + i, err := strconv.ParseInt(s, 10, 64) + if err != nil { + panic(err) + } + return i +} + +// ContentMD5 returns the value for header Content-MD5. +func (dr downloadResponse) ContentMD5() []byte { + s := dr.rawResponse.Header.Get("Content-MD5") + if s == "" { + return nil + } + b, err := base64.StdEncoding.DecodeString(s) + if err != nil { + panic(err) + } + return b +} + +// ContentRange returns the value for header Content-Range. +func (dr downloadResponse) ContentRange() string { + return dr.rawResponse.Header.Get("Content-Range") +} + +// ContentType returns the value for header Content-Type. +func (dr downloadResponse) ContentType() string { + return dr.rawResponse.Header.Get("Content-Type") +} + +// CopyCompletionTime returns the value for header x-ms-copy-completion-time. +func (dr downloadResponse) CopyCompletionTime() time.Time { + s := dr.rawResponse.Header.Get("x-ms-copy-completion-time") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// CopyID returns the value for header x-ms-copy-id. +func (dr downloadResponse) CopyID() string { + return dr.rawResponse.Header.Get("x-ms-copy-id") +} + +// CopyProgress returns the value for header x-ms-copy-progress. +func (dr downloadResponse) CopyProgress() string { + return dr.rawResponse.Header.Get("x-ms-copy-progress") +} + +// CopySource returns the value for header x-ms-copy-source. +func (dr downloadResponse) CopySource() string { + return dr.rawResponse.Header.Get("x-ms-copy-source") +} + +// CopyStatus returns the value for header x-ms-copy-status. +func (dr downloadResponse) CopyStatus() CopyStatusType { + return CopyStatusType(dr.rawResponse.Header.Get("x-ms-copy-status")) +} + +// CopyStatusDescription returns the value for header x-ms-copy-status-description. +func (dr downloadResponse) CopyStatusDescription() string { + return dr.rawResponse.Header.Get("x-ms-copy-status-description") +} + +// Date returns the value for header Date. +func (dr downloadResponse) Date() time.Time { + s := dr.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (dr downloadResponse) ErrorCode() string { + return dr.rawResponse.Header.Get("x-ms-error-code") +} + +// ETag returns the value for header ETag. +func (dr downloadResponse) ETag() ETag { + return ETag(dr.rawResponse.Header.Get("ETag")) +} + +// IsServerEncrypted returns the value for header x-ms-server-encrypted. +func (dr downloadResponse) IsServerEncrypted() string { + return dr.rawResponse.Header.Get("x-ms-server-encrypted") +} + +// LastModified returns the value for header Last-Modified. +func (dr downloadResponse) LastModified() time.Time { + s := dr.rawResponse.Header.Get("Last-Modified") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// LeaseDuration returns the value for header x-ms-lease-duration. +func (dr downloadResponse) LeaseDuration() LeaseDurationType { + return LeaseDurationType(dr.rawResponse.Header.Get("x-ms-lease-duration")) +} + +// LeaseState returns the value for header x-ms-lease-state. +func (dr downloadResponse) LeaseState() LeaseStateType { + return LeaseStateType(dr.rawResponse.Header.Get("x-ms-lease-state")) +} + +// LeaseStatus returns the value for header x-ms-lease-status. +func (dr downloadResponse) LeaseStatus() LeaseStatusType { + return LeaseStatusType(dr.rawResponse.Header.Get("x-ms-lease-status")) +} + +// RequestID returns the value for header x-ms-request-id. +func (dr downloadResponse) RequestID() string { + return dr.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (dr downloadResponse) Version() string { + return dr.rawResponse.Header.Get("x-ms-version") +} + +// GeoReplication ... +type GeoReplication struct { + // Status - The status of the secondary location. Possible values include: 'GeoReplicationStatusLive', 'GeoReplicationStatusBootstrap', 'GeoReplicationStatusUnavailable', 'GeoReplicationStatusNone' + Status GeoReplicationStatusType `xml:"Status"` + // LastSyncTime - A GMT date/time value, to the second. All primary writes preceding this value are guaranteed to be available for read operations at the secondary. Primary writes after this point in time may or may not be available for reads. + LastSyncTime time.Time `xml:"LastSyncTime"` +} + +// MarshalXML implements the xml.Marshaler interface for GeoReplication. +func (gr GeoReplication) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + if reflect.TypeOf((*GeoReplication)(nil)).Elem().Size() != reflect.TypeOf((*geoReplication)(nil)).Elem().Size() { + panic("size mismatch between GeoReplication and geoReplication") + } + gr2 := (*geoReplication)(unsafe.Pointer(&gr)) + return e.EncodeElement(*gr2, start) +} + +// UnmarshalXML implements the xml.Unmarshaler interface for GeoReplication. +func (gr *GeoReplication) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + if reflect.TypeOf((*GeoReplication)(nil)).Elem().Size() != reflect.TypeOf((*geoReplication)(nil)).Elem().Size() { + panic("size mismatch between GeoReplication and geoReplication") + } + gr2 := (*geoReplication)(unsafe.Pointer(gr)) + return d.DecodeElement(gr2, &start) +} + +// ListBlobsFlatSegmentResponse - An enumeration of blobs +type ListBlobsFlatSegmentResponse struct { + rawResponse *http.Response + // XMLName is used for marshalling and is subject to removal in a future release. + XMLName xml.Name `xml:"EnumerationResults"` + ServiceEndpoint string `xml:"ServiceEndpoint,attr"` + ContainerName string `xml:"ContainerName,attr"` + Prefix string `xml:"Prefix"` + Marker string `xml:"Marker"` + MaxResults int32 `xml:"MaxResults"` + Delimiter string `xml:"Delimiter"` + Segment BlobFlatList `xml:"Blobs"` + NextMarker Marker `xml:"NextMarker"` +} + +// Response returns the raw HTTP response object. +func (lbfsr ListBlobsFlatSegmentResponse) Response() *http.Response { + return lbfsr.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (lbfsr ListBlobsFlatSegmentResponse) StatusCode() int { + return lbfsr.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (lbfsr ListBlobsFlatSegmentResponse) Status() string { + return lbfsr.rawResponse.Status +} + +// ContentType returns the value for header Content-Type. +func (lbfsr ListBlobsFlatSegmentResponse) ContentType() string { + return lbfsr.rawResponse.Header.Get("Content-Type") +} + +// Date returns the value for header Date. +func (lbfsr ListBlobsFlatSegmentResponse) Date() time.Time { + s := lbfsr.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (lbfsr ListBlobsFlatSegmentResponse) ErrorCode() string { + return lbfsr.rawResponse.Header.Get("x-ms-error-code") +} + +// RequestID returns the value for header x-ms-request-id. +func (lbfsr ListBlobsFlatSegmentResponse) RequestID() string { + return lbfsr.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (lbfsr ListBlobsFlatSegmentResponse) Version() string { + return lbfsr.rawResponse.Header.Get("x-ms-version") +} + +// ListBlobsHierarchySegmentResponse - An enumeration of blobs +type ListBlobsHierarchySegmentResponse struct { + rawResponse *http.Response + // XMLName is used for marshalling and is subject to removal in a future release. + XMLName xml.Name `xml:"EnumerationResults"` + ServiceEndpoint string `xml:"ServiceEndpoint,attr"` + ContainerName string `xml:"ContainerName,attr"` + Prefix string `xml:"Prefix"` + Marker string `xml:"Marker"` + MaxResults int32 `xml:"MaxResults"` + Delimiter string `xml:"Delimiter"` + Segment BlobHierarchyList `xml:"Blobs"` + NextMarker Marker `xml:"NextMarker"` +} + +// Response returns the raw HTTP response object. +func (lbhsr ListBlobsHierarchySegmentResponse) Response() *http.Response { + return lbhsr.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (lbhsr ListBlobsHierarchySegmentResponse) StatusCode() int { + return lbhsr.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (lbhsr ListBlobsHierarchySegmentResponse) Status() string { + return lbhsr.rawResponse.Status +} + +// ContentType returns the value for header Content-Type. +func (lbhsr ListBlobsHierarchySegmentResponse) ContentType() string { + return lbhsr.rawResponse.Header.Get("Content-Type") +} + +// Date returns the value for header Date. +func (lbhsr ListBlobsHierarchySegmentResponse) Date() time.Time { + s := lbhsr.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (lbhsr ListBlobsHierarchySegmentResponse) ErrorCode() string { + return lbhsr.rawResponse.Header.Get("x-ms-error-code") +} + +// RequestID returns the value for header x-ms-request-id. +func (lbhsr ListBlobsHierarchySegmentResponse) RequestID() string { + return lbhsr.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (lbhsr ListBlobsHierarchySegmentResponse) Version() string { + return lbhsr.rawResponse.Header.Get("x-ms-version") +} + +// ListContainersResponse - An enumeration of containers +type ListContainersResponse struct { + rawResponse *http.Response + // XMLName is used for marshalling and is subject to removal in a future release. + XMLName xml.Name `xml:"EnumerationResults"` + ServiceEndpoint string `xml:"ServiceEndpoint,attr"` + Prefix string `xml:"Prefix"` + Marker *string `xml:"Marker"` + MaxResults int32 `xml:"MaxResults"` + ContainerItems []ContainerItem `xml:"Containers>Container"` + NextMarker Marker `xml:"NextMarker"` +} + +// Response returns the raw HTTP response object. +func (lcr ListContainersResponse) Response() *http.Response { + return lcr.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (lcr ListContainersResponse) StatusCode() int { + return lcr.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (lcr ListContainersResponse) Status() string { + return lcr.rawResponse.Status +} + +// ErrorCode returns the value for header x-ms-error-code. +func (lcr ListContainersResponse) ErrorCode() string { + return lcr.rawResponse.Header.Get("x-ms-error-code") +} + +// RequestID returns the value for header x-ms-request-id. +func (lcr ListContainersResponse) RequestID() string { + return lcr.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (lcr ListContainersResponse) Version() string { + return lcr.rawResponse.Header.Get("x-ms-version") +} + +// Logging - Azure Analytics Logging settings. +type Logging struct { + // Version - The version of Storage Analytics to configure. + Version string `xml:"Version"` + // Delete - Indicates whether all delete requests should be logged. + Delete bool `xml:"Delete"` + // Read - Indicates whether all read requests should be logged. + Read bool `xml:"Read"` + // Write - Indicates whether all write requests should be logged. + Write bool `xml:"Write"` + RetentionPolicy RetentionPolicy `xml:"RetentionPolicy"` +} + +// Metrics ... +type Metrics struct { + // Version - The version of Storage Analytics to configure. + Version *string `xml:"Version"` + // Enabled - Indicates whether metrics are enabled for the Blob service. + Enabled bool `xml:"Enabled"` + // IncludeAPIs - Indicates whether metrics should generate summary statistics for called API operations. + IncludeAPIs *bool `xml:"IncludeAPIs"` + RetentionPolicy *RetentionPolicy `xml:"RetentionPolicy"` +} + +// PageBlobClearPagesResponse ... +type PageBlobClearPagesResponse struct { + rawResponse *http.Response +} + +// Response returns the raw HTTP response object. +func (pbcpr PageBlobClearPagesResponse) Response() *http.Response { + return pbcpr.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (pbcpr PageBlobClearPagesResponse) StatusCode() int { + return pbcpr.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (pbcpr PageBlobClearPagesResponse) Status() string { + return pbcpr.rawResponse.Status +} + +// BlobSequenceNumber returns the value for header x-ms-blob-sequence-number. +func (pbcpr PageBlobClearPagesResponse) BlobSequenceNumber() int64 { + s := pbcpr.rawResponse.Header.Get("x-ms-blob-sequence-number") + if s == "" { + return -1 + } + i, err := strconv.ParseInt(s, 10, 64) + if err != nil { + panic(err) + } + return i +} + +// ContentMD5 returns the value for header Content-MD5. +func (pbcpr PageBlobClearPagesResponse) ContentMD5() []byte { + s := pbcpr.rawResponse.Header.Get("Content-MD5") + if s == "" { + return nil + } + b, err := base64.StdEncoding.DecodeString(s) + if err != nil { + panic(err) + } + return b +} + +// Date returns the value for header Date. +func (pbcpr PageBlobClearPagesResponse) Date() time.Time { + s := pbcpr.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (pbcpr PageBlobClearPagesResponse) ErrorCode() string { + return pbcpr.rawResponse.Header.Get("x-ms-error-code") +} + +// ETag returns the value for header ETag. +func (pbcpr PageBlobClearPagesResponse) ETag() ETag { + return ETag(pbcpr.rawResponse.Header.Get("ETag")) +} + +// LastModified returns the value for header Last-Modified. +func (pbcpr PageBlobClearPagesResponse) LastModified() time.Time { + s := pbcpr.rawResponse.Header.Get("Last-Modified") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// RequestID returns the value for header x-ms-request-id. +func (pbcpr PageBlobClearPagesResponse) RequestID() string { + return pbcpr.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (pbcpr PageBlobClearPagesResponse) Version() string { + return pbcpr.rawResponse.Header.Get("x-ms-version") +} + +// PageBlobCopyIncrementalResponse ... +type PageBlobCopyIncrementalResponse struct { + rawResponse *http.Response +} + +// Response returns the raw HTTP response object. +func (pbcir PageBlobCopyIncrementalResponse) Response() *http.Response { + return pbcir.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (pbcir PageBlobCopyIncrementalResponse) StatusCode() int { + return pbcir.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (pbcir PageBlobCopyIncrementalResponse) Status() string { + return pbcir.rawResponse.Status +} + +// CopyID returns the value for header x-ms-copy-id. +func (pbcir PageBlobCopyIncrementalResponse) CopyID() string { + return pbcir.rawResponse.Header.Get("x-ms-copy-id") +} + +// CopyStatus returns the value for header x-ms-copy-status. +func (pbcir PageBlobCopyIncrementalResponse) CopyStatus() CopyStatusType { + return CopyStatusType(pbcir.rawResponse.Header.Get("x-ms-copy-status")) +} + +// Date returns the value for header Date. +func (pbcir PageBlobCopyIncrementalResponse) Date() time.Time { + s := pbcir.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (pbcir PageBlobCopyIncrementalResponse) ErrorCode() string { + return pbcir.rawResponse.Header.Get("x-ms-error-code") +} + +// ETag returns the value for header ETag. +func (pbcir PageBlobCopyIncrementalResponse) ETag() ETag { + return ETag(pbcir.rawResponse.Header.Get("ETag")) +} + +// LastModified returns the value for header Last-Modified. +func (pbcir PageBlobCopyIncrementalResponse) LastModified() time.Time { + s := pbcir.rawResponse.Header.Get("Last-Modified") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// RequestID returns the value for header x-ms-request-id. +func (pbcir PageBlobCopyIncrementalResponse) RequestID() string { + return pbcir.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (pbcir PageBlobCopyIncrementalResponse) Version() string { + return pbcir.rawResponse.Header.Get("x-ms-version") +} + +// PageBlobCreateResponse ... +type PageBlobCreateResponse struct { + rawResponse *http.Response +} + +// Response returns the raw HTTP response object. +func (pbcr PageBlobCreateResponse) Response() *http.Response { + return pbcr.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (pbcr PageBlobCreateResponse) StatusCode() int { + return pbcr.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (pbcr PageBlobCreateResponse) Status() string { + return pbcr.rawResponse.Status +} + +// ContentMD5 returns the value for header Content-MD5. +func (pbcr PageBlobCreateResponse) ContentMD5() []byte { + s := pbcr.rawResponse.Header.Get("Content-MD5") + if s == "" { + return nil + } + b, err := base64.StdEncoding.DecodeString(s) + if err != nil { + panic(err) + } + return b +} + +// Date returns the value for header Date. +func (pbcr PageBlobCreateResponse) Date() time.Time { + s := pbcr.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (pbcr PageBlobCreateResponse) ErrorCode() string { + return pbcr.rawResponse.Header.Get("x-ms-error-code") +} + +// ETag returns the value for header ETag. +func (pbcr PageBlobCreateResponse) ETag() ETag { + return ETag(pbcr.rawResponse.Header.Get("ETag")) +} + +// IsServerEncrypted returns the value for header x-ms-request-server-encrypted. +func (pbcr PageBlobCreateResponse) IsServerEncrypted() string { + return pbcr.rawResponse.Header.Get("x-ms-request-server-encrypted") +} + +// LastModified returns the value for header Last-Modified. +func (pbcr PageBlobCreateResponse) LastModified() time.Time { + s := pbcr.rawResponse.Header.Get("Last-Modified") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// RequestID returns the value for header x-ms-request-id. +func (pbcr PageBlobCreateResponse) RequestID() string { + return pbcr.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (pbcr PageBlobCreateResponse) Version() string { + return pbcr.rawResponse.Header.Get("x-ms-version") +} + +// PageBlobResizeResponse ... +type PageBlobResizeResponse struct { + rawResponse *http.Response +} + +// Response returns the raw HTTP response object. +func (pbrr PageBlobResizeResponse) Response() *http.Response { + return pbrr.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (pbrr PageBlobResizeResponse) StatusCode() int { + return pbrr.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (pbrr PageBlobResizeResponse) Status() string { + return pbrr.rawResponse.Status +} + +// BlobSequenceNumber returns the value for header x-ms-blob-sequence-number. +func (pbrr PageBlobResizeResponse) BlobSequenceNumber() int64 { + s := pbrr.rawResponse.Header.Get("x-ms-blob-sequence-number") + if s == "" { + return -1 + } + i, err := strconv.ParseInt(s, 10, 64) + if err != nil { + panic(err) + } + return i +} + +// Date returns the value for header Date. +func (pbrr PageBlobResizeResponse) Date() time.Time { + s := pbrr.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (pbrr PageBlobResizeResponse) ErrorCode() string { + return pbrr.rawResponse.Header.Get("x-ms-error-code") +} + +// ETag returns the value for header ETag. +func (pbrr PageBlobResizeResponse) ETag() ETag { + return ETag(pbrr.rawResponse.Header.Get("ETag")) +} + +// LastModified returns the value for header Last-Modified. +func (pbrr PageBlobResizeResponse) LastModified() time.Time { + s := pbrr.rawResponse.Header.Get("Last-Modified") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// RequestID returns the value for header x-ms-request-id. +func (pbrr PageBlobResizeResponse) RequestID() string { + return pbrr.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (pbrr PageBlobResizeResponse) Version() string { + return pbrr.rawResponse.Header.Get("x-ms-version") +} + +// PageBlobUpdateSequenceNumberResponse ... +type PageBlobUpdateSequenceNumberResponse struct { + rawResponse *http.Response +} + +// Response returns the raw HTTP response object. +func (pbusnr PageBlobUpdateSequenceNumberResponse) Response() *http.Response { + return pbusnr.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (pbusnr PageBlobUpdateSequenceNumberResponse) StatusCode() int { + return pbusnr.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (pbusnr PageBlobUpdateSequenceNumberResponse) Status() string { + return pbusnr.rawResponse.Status +} + +// BlobSequenceNumber returns the value for header x-ms-blob-sequence-number. +func (pbusnr PageBlobUpdateSequenceNumberResponse) BlobSequenceNumber() int64 { + s := pbusnr.rawResponse.Header.Get("x-ms-blob-sequence-number") + if s == "" { + return -1 + } + i, err := strconv.ParseInt(s, 10, 64) + if err != nil { + panic(err) + } + return i +} + +// Date returns the value for header Date. +func (pbusnr PageBlobUpdateSequenceNumberResponse) Date() time.Time { + s := pbusnr.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (pbusnr PageBlobUpdateSequenceNumberResponse) ErrorCode() string { + return pbusnr.rawResponse.Header.Get("x-ms-error-code") +} + +// ETag returns the value for header ETag. +func (pbusnr PageBlobUpdateSequenceNumberResponse) ETag() ETag { + return ETag(pbusnr.rawResponse.Header.Get("ETag")) +} + +// LastModified returns the value for header Last-Modified. +func (pbusnr PageBlobUpdateSequenceNumberResponse) LastModified() time.Time { + s := pbusnr.rawResponse.Header.Get("Last-Modified") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// RequestID returns the value for header x-ms-request-id. +func (pbusnr PageBlobUpdateSequenceNumberResponse) RequestID() string { + return pbusnr.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (pbusnr PageBlobUpdateSequenceNumberResponse) Version() string { + return pbusnr.rawResponse.Header.Get("x-ms-version") +} + +// PageBlobUploadPagesResponse ... +type PageBlobUploadPagesResponse struct { + rawResponse *http.Response +} + +// Response returns the raw HTTP response object. +func (pbupr PageBlobUploadPagesResponse) Response() *http.Response { + return pbupr.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (pbupr PageBlobUploadPagesResponse) StatusCode() int { + return pbupr.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (pbupr PageBlobUploadPagesResponse) Status() string { + return pbupr.rawResponse.Status +} + +// BlobSequenceNumber returns the value for header x-ms-blob-sequence-number. +func (pbupr PageBlobUploadPagesResponse) BlobSequenceNumber() int64 { + s := pbupr.rawResponse.Header.Get("x-ms-blob-sequence-number") + if s == "" { + return -1 + } + i, err := strconv.ParseInt(s, 10, 64) + if err != nil { + panic(err) + } + return i +} + +// ContentMD5 returns the value for header Content-MD5. +func (pbupr PageBlobUploadPagesResponse) ContentMD5() []byte { + s := pbupr.rawResponse.Header.Get("Content-MD5") + if s == "" { + return nil + } + b, err := base64.StdEncoding.DecodeString(s) + if err != nil { + panic(err) + } + return b +} + +// Date returns the value for header Date. +func (pbupr PageBlobUploadPagesResponse) Date() time.Time { + s := pbupr.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (pbupr PageBlobUploadPagesResponse) ErrorCode() string { + return pbupr.rawResponse.Header.Get("x-ms-error-code") +} + +// ETag returns the value for header ETag. +func (pbupr PageBlobUploadPagesResponse) ETag() ETag { + return ETag(pbupr.rawResponse.Header.Get("ETag")) +} + +// IsServerEncrypted returns the value for header x-ms-request-server-encrypted. +func (pbupr PageBlobUploadPagesResponse) IsServerEncrypted() string { + return pbupr.rawResponse.Header.Get("x-ms-request-server-encrypted") +} + +// LastModified returns the value for header Last-Modified. +func (pbupr PageBlobUploadPagesResponse) LastModified() time.Time { + s := pbupr.rawResponse.Header.Get("Last-Modified") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// RequestID returns the value for header x-ms-request-id. +func (pbupr PageBlobUploadPagesResponse) RequestID() string { + return pbupr.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (pbupr PageBlobUploadPagesResponse) Version() string { + return pbupr.rawResponse.Header.Get("x-ms-version") +} + +// PageList - the list of pages +type PageList struct { + rawResponse *http.Response + PageRange []PageRange `xml:"PageRange"` + ClearRange []ClearRange `xml:"ClearRange"` +} + +// Response returns the raw HTTP response object. +func (pl PageList) Response() *http.Response { + return pl.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (pl PageList) StatusCode() int { + return pl.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (pl PageList) Status() string { + return pl.rawResponse.Status +} + +// BlobContentLength returns the value for header x-ms-blob-content-length. +func (pl PageList) BlobContentLength() int64 { + s := pl.rawResponse.Header.Get("x-ms-blob-content-length") + if s == "" { + return -1 + } + i, err := strconv.ParseInt(s, 10, 64) + if err != nil { + panic(err) + } + return i +} + +// Date returns the value for header Date. +func (pl PageList) Date() time.Time { + s := pl.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (pl PageList) ErrorCode() string { + return pl.rawResponse.Header.Get("x-ms-error-code") +} + +// ETag returns the value for header ETag. +func (pl PageList) ETag() ETag { + return ETag(pl.rawResponse.Header.Get("ETag")) +} + +// LastModified returns the value for header Last-Modified. +func (pl PageList) LastModified() time.Time { + s := pl.rawResponse.Header.Get("Last-Modified") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// RequestID returns the value for header x-ms-request-id. +func (pl PageList) RequestID() string { + return pl.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (pl PageList) Version() string { + return pl.rawResponse.Header.Get("x-ms-version") +} + +// PageRange ... +type PageRange struct { + Start int64 `xml:"Start"` + End int64 `xml:"End"` +} + +// RetentionPolicy - the retention policy +type RetentionPolicy struct { + // Enabled - Indicates whether a retention policy is enabled for the storage service + Enabled bool `xml:"Enabled"` + // Days - Indicates the number of days that metrics or logging or soft-deleted data should be retained. All data older than this value will be deleted + Days *int32 `xml:"Days"` +} + +// ServiceSetPropertiesResponse ... +type ServiceSetPropertiesResponse struct { + rawResponse *http.Response +} + +// Response returns the raw HTTP response object. +func (sspr ServiceSetPropertiesResponse) Response() *http.Response { + return sspr.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (sspr ServiceSetPropertiesResponse) StatusCode() int { + return sspr.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (sspr ServiceSetPropertiesResponse) Status() string { + return sspr.rawResponse.Status +} + +// ErrorCode returns the value for header x-ms-error-code. +func (sspr ServiceSetPropertiesResponse) ErrorCode() string { + return sspr.rawResponse.Header.Get("x-ms-error-code") +} + +// RequestID returns the value for header x-ms-request-id. +func (sspr ServiceSetPropertiesResponse) RequestID() string { + return sspr.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (sspr ServiceSetPropertiesResponse) Version() string { + return sspr.rawResponse.Header.Get("x-ms-version") +} + +// SignedIdentifier - signed identifier +type SignedIdentifier struct { + // ID - a unique id + ID string `xml:"Id"` + // AccessPolicy - The access policy + AccessPolicy AccessPolicy `xml:"AccessPolicy"` +} + +// SignedIdentifiers ... +type SignedIdentifiers struct { + rawResponse *http.Response + Items []SignedIdentifier `xml:"SignedIdentifier"` +} + +// Response returns the raw HTTP response object. +func (si SignedIdentifiers) Response() *http.Response { + return si.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (si SignedIdentifiers) StatusCode() int { + return si.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (si SignedIdentifiers) Status() string { + return si.rawResponse.Status +} + +// BlobPublicAccess returns the value for header x-ms-blob-public-access. +func (si SignedIdentifiers) BlobPublicAccess() PublicAccessType { + return PublicAccessType(si.rawResponse.Header.Get("x-ms-blob-public-access")) +} + +// Date returns the value for header Date. +func (si SignedIdentifiers) Date() time.Time { + s := si.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (si SignedIdentifiers) ErrorCode() string { + return si.rawResponse.Header.Get("x-ms-error-code") +} + +// ETag returns the value for header ETag. +func (si SignedIdentifiers) ETag() ETag { + return ETag(si.rawResponse.Header.Get("ETag")) +} + +// LastModified returns the value for header Last-Modified. +func (si SignedIdentifiers) LastModified() time.Time { + s := si.rawResponse.Header.Get("Last-Modified") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// RequestID returns the value for header x-ms-request-id. +func (si SignedIdentifiers) RequestID() string { + return si.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (si SignedIdentifiers) Version() string { + return si.rawResponse.Header.Get("x-ms-version") +} + +// StorageServiceProperties - Storage Service Properties. +type StorageServiceProperties struct { + rawResponse *http.Response + // Logging - Azure Analytics Logging settings + Logging *Logging `xml:"Logging"` + // HourMetrics - A summary of request statistics grouped by API in hourly aggregates for blobs + HourMetrics *Metrics `xml:"HourMetrics"` + // MinuteMetrics - a summary of request statistics grouped by API in minute aggregates for blobs + MinuteMetrics *Metrics `xml:"MinuteMetrics"` + // Cors - The set of CORS rules. + Cors []CorsRule `xml:"Cors>CorsRule"` + // DefaultServiceVersion - The default version to use for requests to the Blob service if an incoming request's version is not specified. Possible values include version 2008-10-27 and all more recent versions + DefaultServiceVersion *string `xml:"DefaultServiceVersion"` + // DeleteRetentionPolicy - The Delete Retention Policy for the service + DeleteRetentionPolicy *RetentionPolicy `xml:"DeleteRetentionPolicy"` +} + +// Response returns the raw HTTP response object. +func (ssp StorageServiceProperties) Response() *http.Response { + return ssp.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (ssp StorageServiceProperties) StatusCode() int { + return ssp.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (ssp StorageServiceProperties) Status() string { + return ssp.rawResponse.Status +} + +// ErrorCode returns the value for header x-ms-error-code. +func (ssp StorageServiceProperties) ErrorCode() string { + return ssp.rawResponse.Header.Get("x-ms-error-code") +} + +// RequestID returns the value for header x-ms-request-id. +func (ssp StorageServiceProperties) RequestID() string { + return ssp.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (ssp StorageServiceProperties) Version() string { + return ssp.rawResponse.Header.Get("x-ms-version") +} + +// StorageServiceStats - Stats for the storage service. +type StorageServiceStats struct { + rawResponse *http.Response + // GeoReplication - Geo-Replication information for the Secondary Storage Service + GeoReplication *GeoReplication `xml:"GeoReplication"` +} + +// Response returns the raw HTTP response object. +func (sss StorageServiceStats) Response() *http.Response { + return sss.rawResponse +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (sss StorageServiceStats) StatusCode() int { + return sss.rawResponse.StatusCode +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (sss StorageServiceStats) Status() string { + return sss.rawResponse.Status +} + +// Date returns the value for header Date. +func (sss StorageServiceStats) Date() time.Time { + s := sss.rawResponse.Header.Get("Date") + if s == "" { + return time.Time{} + } + t, err := time.Parse(time.RFC1123, s) + if err != nil { + panic(err) + } + return t +} + +// ErrorCode returns the value for header x-ms-error-code. +func (sss StorageServiceStats) ErrorCode() string { + return sss.rawResponse.Header.Get("x-ms-error-code") +} + +// RequestID returns the value for header x-ms-request-id. +func (sss StorageServiceStats) RequestID() string { + return sss.rawResponse.Header.Get("x-ms-request-id") +} + +// Version returns the value for header x-ms-version. +func (sss StorageServiceStats) Version() string { + return sss.rawResponse.Header.Get("x-ms-version") +} + +const ( + rfc3339Format = "2006-01-02T15:04:05.0000000Z07:00" +) + +// used to convert times from UTC to GMT before sending across the wire +var gmt = time.FixedZone("GMT", 0) + +// internal type used for marshalling time in RFC1123 format +type timeRFC1123 struct { + time.Time +} + +// MarshalText implements the encoding.TextMarshaler interface for timeRFC1123. +func (t timeRFC1123) MarshalText() ([]byte, error) { + return []byte(t.Format(time.RFC1123)), nil +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface for timeRFC1123. +func (t *timeRFC1123) UnmarshalText(data []byte) (err error) { + t.Time, err = time.Parse(time.RFC1123, string(data)) + return +} + +// internal type used for marshalling time in RFC3339 format +type timeRFC3339 struct { + time.Time +} + +// MarshalText implements the encoding.TextMarshaler interface for timeRFC3339. +func (t timeRFC3339) MarshalText() ([]byte, error) { + return []byte(t.Format(rfc3339Format)), nil +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface for timeRFC3339. +func (t *timeRFC3339) UnmarshalText(data []byte) (err error) { + t.Time, err = time.Parse(rfc3339Format, string(data)) + return +} + +// internal type used for marshalling +type accessPolicy struct { + Start timeRFC3339 `xml:"Start"` + Expiry timeRFC3339 `xml:"Expiry"` + Permission string `xml:"Permission"` +} + +// internal type used for marshalling +type blobProperties struct { + LastModified timeRFC1123 `xml:"Last-Modified"` + Etag ETag `xml:"Etag"` + ContentLength *int64 `xml:"Content-Length"` + ContentType *string `xml:"Content-Type"` + ContentEncoding *string `xml:"Content-Encoding"` + ContentLanguage *string `xml:"Content-Language"` + ContentMD5 []byte `xml:"Content-MD5"` + ContentDisposition *string `xml:"Content-Disposition"` + CacheControl *string `xml:"Cache-Control"` + BlobSequenceNumber *int64 `xml:"x-ms-blob-sequence-number"` + BlobType BlobType `xml:"BlobType"` + LeaseStatus LeaseStatusType `xml:"LeaseStatus"` + LeaseState LeaseStateType `xml:"LeaseState"` + LeaseDuration LeaseDurationType `xml:"LeaseDuration"` + CopyID *string `xml:"CopyId"` + CopyStatus CopyStatusType `xml:"CopyStatus"` + CopySource *string `xml:"CopySource"` + CopyProgress *string `xml:"CopyProgress"` + CopyCompletionTime *timeRFC1123 `xml:"CopyCompletionTime"` + CopyStatusDescription *string `xml:"CopyStatusDescription"` + ServerEncrypted *bool `xml:"ServerEncrypted"` + IncrementalCopy *bool `xml:"IncrementalCopy"` + DestinationSnapshot *string `xml:"DestinationSnapshot"` + DeletedTime *timeRFC1123 `xml:"DeletedTime"` + RemainingRetentionDays *int32 `xml:"RemainingRetentionDays"` + AccessTier AccessTierType `xml:"AccessTier"` + AccessTierInferred *bool `xml:"AccessTierInferred"` + ArchiveStatus ArchiveStatusType `xml:"ArchiveStatus"` +} + +// internal type used for marshalling +type containerProperties struct { + LastModified timeRFC1123 `xml:"Last-Modified"` + Etag ETag `xml:"Etag"` + LeaseStatus LeaseStatusType `xml:"LeaseStatus"` + LeaseState LeaseStateType `xml:"LeaseState"` + LeaseDuration LeaseDurationType `xml:"LeaseDuration"` + PublicAccess PublicAccessType `xml:"PublicAccess"` +} + +// internal type used for marshalling +type geoReplication struct { + Status GeoReplicationStatusType `xml:"Status"` + LastSyncTime timeRFC1123 `xml:"LastSyncTime"` +} diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_page_blob.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_page_blob.go new file mode 100644 index 0000000000..ce6507080e --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_page_blob.go @@ -0,0 +1,794 @@ +package azblob + +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +import ( + "context" + "encoding/base64" + "encoding/xml" + "github.com/Azure/azure-pipeline-go/pipeline" + "io" + "io/ioutil" + "net/http" + "net/url" + "strconv" + "time" +) + +// pageBlobClient is the client for the PageBlob methods of the Azblob service. +type pageBlobClient struct { + managementClient +} + +// newPageBlobClient creates an instance of the pageBlobClient client. +func newPageBlobClient(url url.URL, p pipeline.Pipeline) pageBlobClient { + return pageBlobClient{newManagementClient(url, p)} +} + +// ClearPages the Clear Pages operation clears a set of pages from a page blob +// +// contentLength is the length of the request. timeout is the timeout parameter is expressed in seconds. For more +// information, see Setting +// Timeouts for Blob Service Operations. rangeParameter is return only the bytes of the blob in the specified +// range. leaseID is if specified, the operation only succeeds if the container's lease is active and matches this ID. +// ifSequenceNumberLessThanOrEqualTo is specify this header value to operate only on a blob if it has a sequence number +// less than or equal to the specified. ifSequenceNumberLessThan is specify this header value to operate only on a blob +// if it has a sequence number less than the specified. ifSequenceNumberEqualTo is specify this header value to operate +// only on a blob if it has the specified sequence number. ifModifiedSince is specify this header value to operate only +// on a blob if it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to +// operate only on a blob if it has not been modified since the specified date/time. ifMatches is specify an ETag value +// to operate only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs +// without a matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is +// recorded in the analytics logs when storage analytics logging is enabled. +func (client pageBlobClient) ClearPages(ctx context.Context, contentLength int64, timeout *int32, rangeParameter *string, leaseID *string, ifSequenceNumberLessThanOrEqualTo *int64, ifSequenceNumberLessThan *int64, ifSequenceNumberEqualTo *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*PageBlobClearPagesResponse, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.clearPagesPreparer(contentLength, timeout, rangeParameter, leaseID, ifSequenceNumberLessThanOrEqualTo, ifSequenceNumberLessThan, ifSequenceNumberEqualTo, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.clearPagesResponder}, req) + if err != nil { + return nil, err + } + return resp.(*PageBlobClearPagesResponse), err +} + +// clearPagesPreparer prepares the ClearPages request. +func (client pageBlobClient) clearPagesPreparer(contentLength int64, timeout *int32, rangeParameter *string, leaseID *string, ifSequenceNumberLessThanOrEqualTo *int64, ifSequenceNumberLessThan *int64, ifSequenceNumberEqualTo *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("PUT", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("comp", "page") + req.URL.RawQuery = params.Encode() + req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10)) + if rangeParameter != nil { + req.Header.Set("x-ms-range", *rangeParameter) + } + if leaseID != nil { + req.Header.Set("x-ms-lease-id", *leaseID) + } + if ifSequenceNumberLessThanOrEqualTo != nil { + req.Header.Set("x-ms-if-sequence-number-le", strconv.FormatInt(*ifSequenceNumberLessThanOrEqualTo, 10)) + } + if ifSequenceNumberLessThan != nil { + req.Header.Set("x-ms-if-sequence-number-lt", strconv.FormatInt(*ifSequenceNumberLessThan, 10)) + } + if ifSequenceNumberEqualTo != nil { + req.Header.Set("x-ms-if-sequence-number-eq", strconv.FormatInt(*ifSequenceNumberEqualTo, 10)) + } + if ifModifiedSince != nil { + req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifUnmodifiedSince != nil { + req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifMatches != nil { + req.Header.Set("If-Match", string(*ifMatches)) + } + if ifNoneMatch != nil { + req.Header.Set("If-None-Match", string(*ifNoneMatch)) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + req.Header.Set("x-ms-page-write", "clear") + return req, nil +} + +// clearPagesResponder handles the response to the ClearPages request. +func (client pageBlobClient) clearPagesResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK, http.StatusCreated) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &PageBlobClearPagesResponse{rawResponse: resp.Response()}, err +} + +// CopyIncremental the Copy Incremental operation copies a snapshot of the source page blob to a destination page blob. +// The snapshot is copied such that only the differential changes between the previously copied snapshot are +// transferred to the destination. The copied snapshots are complete copies of the original snapshot and can be read or +// copied from as usual. This API is supported since REST version 2016-05-31. +// +// copySource is specifies the name of the source page blob snapshot. This value is a URL of up to 2 KB in length that +// specifies a page blob snapshot. The value should be URL-encoded as it would appear in a request URI. The source blob +// must either be public or must be authenticated via a shared access signature. timeout is the timeout parameter is +// expressed in seconds. For more information, see Setting +// Timeouts for Blob Service Operations. metadata is optional. Specifies a user-defined name-value pair associated +// with the blob. If no name-value pairs are specified, the operation will copy the metadata from the source blob or +// file to the destination blob. If one or more name-value pairs are specified, the destination blob is created with +// the specified metadata, and metadata is not copied from the source blob or file. Note that beginning with version +// 2009-09-19, metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing +// Containers, Blobs, and Metadata for more information. ifModifiedSince is specify this header value to operate only +// on a blob if it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to +// operate only on a blob if it has not been modified since the specified date/time. ifMatches is specify an ETag value +// to operate only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs +// without a matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is +// recorded in the analytics logs when storage analytics logging is enabled. +func (client pageBlobClient) CopyIncremental(ctx context.Context, copySource string, timeout *int32, metadata map[string]string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*PageBlobCopyIncrementalResponse, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}, + {targetValue: metadata, + constraints: []constraint{{target: "metadata", name: null, rule: false, + chain: []constraint{{target: "metadata", name: pattern, rule: `^[a-zA-Z]+$`, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.copyIncrementalPreparer(copySource, timeout, metadata, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.copyIncrementalResponder}, req) + if err != nil { + return nil, err + } + return resp.(*PageBlobCopyIncrementalResponse), err +} + +// copyIncrementalPreparer prepares the CopyIncremental request. +func (client pageBlobClient) copyIncrementalPreparer(copySource string, timeout *int32, metadata map[string]string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("PUT", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("comp", "incrementalcopy") + req.URL.RawQuery = params.Encode() + if metadata != nil { + for k, v := range metadata { + req.Header.Set("x-ms-meta-"+k, v) + } + } + if ifModifiedSince != nil { + req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifUnmodifiedSince != nil { + req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifMatches != nil { + req.Header.Set("If-Match", string(*ifMatches)) + } + if ifNoneMatch != nil { + req.Header.Set("If-None-Match", string(*ifNoneMatch)) + } + req.Header.Set("x-ms-copy-source", copySource) + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + return req, nil +} + +// copyIncrementalResponder handles the response to the CopyIncremental request. +func (client pageBlobClient) copyIncrementalResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK, http.StatusAccepted) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &PageBlobCopyIncrementalResponse{rawResponse: resp.Response()}, err +} + +// Create the Create operation creates a new page blob. +// +// contentLength is the length of the request. timeout is the timeout parameter is expressed in seconds. For more +// information, see Setting +// Timeouts for Blob Service Operations. blobContentType is optional. Sets the blob's content type. If specified, +// this property is stored with the blob and returned with a read request. blobContentEncoding is optional. Sets the +// blob's content encoding. If specified, this property is stored with the blob and returned with a read request. +// blobContentLanguage is optional. Set the blob's content language. If specified, this property is stored with the +// blob and returned with a read request. blobContentMD5 is optional. An MD5 hash of the blob content. Note that this +// hash is not validated, as the hashes for the individual blocks were validated when each was uploaded. +// blobCacheControl is optional. Sets the blob's cache control. If specified, this property is stored with the blob and +// returned with a read request. metadata is optional. Specifies a user-defined name-value pair associated with the +// blob. If no name-value pairs are specified, the operation will copy the metadata from the source blob or file to the +// destination blob. If one or more name-value pairs are specified, the destination blob is created with the specified +// metadata, and metadata is not copied from the source blob or file. Note that beginning with version 2009-09-19, +// metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing Containers, Blobs, and +// Metadata for more information. leaseID is if specified, the operation only succeeds if the container's lease is +// active and matches this ID. blobContentDisposition is optional. Sets the blob's Content-Disposition header. +// ifModifiedSince is specify this header value to operate only on a blob if it has been modified since the specified +// date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if it has not been modified +// since the specified date/time. ifMatches is specify an ETag value to operate only on blobs with a matching value. +// ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. blobContentLength is this +// header specifies the maximum size for the page blob, up to 1 TB. The page blob size must be aligned to a 512-byte +// boundary. blobSequenceNumber is set for page blobs only. The sequence number is a user-controlled value that you can +// use to track requests. The value of the sequence number must be between 0 and 2^63 - 1. requestID is provides a +// client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage +// analytics logging is enabled. +func (client pageBlobClient) Create(ctx context.Context, contentLength int64, timeout *int32, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, blobContentLength *int64, blobSequenceNumber *int64, requestID *string) (*PageBlobCreateResponse, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}, + {targetValue: metadata, + constraints: []constraint{{target: "metadata", name: null, rule: false, + chain: []constraint{{target: "metadata", name: pattern, rule: `^[a-zA-Z]+$`, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.createPreparer(contentLength, timeout, blobContentType, blobContentEncoding, blobContentLanguage, blobContentMD5, blobCacheControl, metadata, leaseID, blobContentDisposition, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, blobContentLength, blobSequenceNumber, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.createResponder}, req) + if err != nil { + return nil, err + } + return resp.(*PageBlobCreateResponse), err +} + +// createPreparer prepares the Create request. +func (client pageBlobClient) createPreparer(contentLength int64, timeout *int32, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, blobContentLength *int64, blobSequenceNumber *int64, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("PUT", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + req.URL.RawQuery = params.Encode() + req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10)) + if blobContentType != nil { + req.Header.Set("x-ms-blob-content-type", *blobContentType) + } + if blobContentEncoding != nil { + req.Header.Set("x-ms-blob-content-encoding", *blobContentEncoding) + } + if blobContentLanguage != nil { + req.Header.Set("x-ms-blob-content-language", *blobContentLanguage) + } + if blobContentMD5 != nil { + req.Header.Set("x-ms-blob-content-md5", base64.StdEncoding.EncodeToString(blobContentMD5)) + } + if blobCacheControl != nil { + req.Header.Set("x-ms-blob-cache-control", *blobCacheControl) + } + if metadata != nil { + for k, v := range metadata { + req.Header.Set("x-ms-meta-"+k, v) + } + } + if leaseID != nil { + req.Header.Set("x-ms-lease-id", *leaseID) + } + if blobContentDisposition != nil { + req.Header.Set("x-ms-blob-content-disposition", *blobContentDisposition) + } + if ifModifiedSince != nil { + req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifUnmodifiedSince != nil { + req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifMatches != nil { + req.Header.Set("If-Match", string(*ifMatches)) + } + if ifNoneMatch != nil { + req.Header.Set("If-None-Match", string(*ifNoneMatch)) + } + if blobContentLength != nil { + req.Header.Set("x-ms-blob-content-length", strconv.FormatInt(*blobContentLength, 10)) + } + if blobSequenceNumber != nil { + req.Header.Set("x-ms-blob-sequence-number", strconv.FormatInt(*blobSequenceNumber, 10)) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + req.Header.Set("x-ms-blob-type", "PageBlob") + return req, nil +} + +// createResponder handles the response to the Create request. +func (client pageBlobClient) createResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK, http.StatusCreated) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &PageBlobCreateResponse{rawResponse: resp.Response()}, err +} + +// GetPageRanges the Get Page Ranges operation returns the list of valid page ranges for a page blob or snapshot of a +// page blob +// +// snapshot is the snapshot parameter is an opaque DateTime value that, when present, specifies the blob snapshot to +// retrieve. For more information on working with blob snapshots, see Creating +// a Snapshot of a Blob. timeout is the timeout parameter is expressed in seconds. For more information, see Setting +// Timeouts for Blob Service Operations. rangeParameter is return only the bytes of the blob in the specified +// range. leaseID is if specified, the operation only succeeds if the container's lease is active and matches this ID. +// ifModifiedSince is specify this header value to operate only on a blob if it has been modified since the specified +// date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if it has not been modified +// since the specified date/time. ifMatches is specify an ETag value to operate only on blobs with a matching value. +// ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. requestID is provides a +// client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage +// analytics logging is enabled. +func (client pageBlobClient) GetPageRanges(ctx context.Context, snapshot *string, timeout *int32, rangeParameter *string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*PageList, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.getPageRangesPreparer(snapshot, timeout, rangeParameter, leaseID, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.getPageRangesResponder}, req) + if err != nil { + return nil, err + } + return resp.(*PageList), err +} + +// getPageRangesPreparer prepares the GetPageRanges request. +func (client pageBlobClient) getPageRangesPreparer(snapshot *string, timeout *int32, rangeParameter *string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("GET", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if snapshot != nil && len(*snapshot) > 0 { + params.Set("snapshot", *snapshot) + } + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("comp", "pagelist") + req.URL.RawQuery = params.Encode() + if rangeParameter != nil { + req.Header.Set("x-ms-range", *rangeParameter) + } + if leaseID != nil { + req.Header.Set("x-ms-lease-id", *leaseID) + } + if ifModifiedSince != nil { + req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifUnmodifiedSince != nil { + req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifMatches != nil { + req.Header.Set("If-Match", string(*ifMatches)) + } + if ifNoneMatch != nil { + req.Header.Set("If-None-Match", string(*ifNoneMatch)) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + return req, nil +} + +// getPageRangesResponder handles the response to the GetPageRanges request. +func (client pageBlobClient) getPageRangesResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK) + if resp == nil { + return nil, err + } + result := &PageList{rawResponse: resp.Response()} + if err != nil { + return result, err + } + defer resp.Response().Body.Close() + b, err := ioutil.ReadAll(resp.Response().Body) + if err != nil { + return result, NewResponseError(err, resp.Response(), "failed to read response body") + } + if len(b) > 0 { + b = removeBOM(b) + err = xml.Unmarshal(b, result) + if err != nil { + return result, NewResponseError(err, resp.Response(), "failed to unmarshal response body") + } + } + return result, nil +} + +// GetPageRangesDiff [Update] The Get Page Ranges Diff operation returns the list of valid page ranges for a page blob +// that were changed between target blob and previous snapshot. +// +// snapshot is the snapshot parameter is an opaque DateTime value that, when present, specifies the blob snapshot to +// retrieve. For more information on working with blob snapshots, see Creating +// a Snapshot of a Blob. timeout is the timeout parameter is expressed in seconds. For more information, see Setting +// Timeouts for Blob Service Operations. prevsnapshot is optional in version 2015-07-08 and newer. The prevsnapshot +// parameter is a DateTime value that specifies that the response will contain only pages that were changed between +// target blob and previous snapshot. Changed pages include both updated and cleared pages. The target blob may be a +// snapshot, as long as the snapshot specified by prevsnapshot is the older of the two. Note that incremental snapshots +// are currently supported only for blobs created on or after January 1, 2016. rangeParameter is return only the bytes +// of the blob in the specified range. leaseID is if specified, the operation only succeeds if the container's lease is +// active and matches this ID. ifModifiedSince is specify this header value to operate only on a blob if it has been +// modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if +// it has not been modified since the specified date/time. ifMatches is specify an ETag value to operate only on blobs +// with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. +// requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics +// logs when storage analytics logging is enabled. +func (client pageBlobClient) GetPageRangesDiff(ctx context.Context, snapshot *string, timeout *int32, prevsnapshot *string, rangeParameter *string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*PageList, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.getPageRangesDiffPreparer(snapshot, timeout, prevsnapshot, rangeParameter, leaseID, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.getPageRangesDiffResponder}, req) + if err != nil { + return nil, err + } + return resp.(*PageList), err +} + +// getPageRangesDiffPreparer prepares the GetPageRangesDiff request. +func (client pageBlobClient) getPageRangesDiffPreparer(snapshot *string, timeout *int32, prevsnapshot *string, rangeParameter *string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("GET", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if snapshot != nil && len(*snapshot) > 0 { + params.Set("snapshot", *snapshot) + } + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + if prevsnapshot != nil && len(*prevsnapshot) > 0 { + params.Set("prevsnapshot", *prevsnapshot) + } + params.Set("comp", "pagelist") + req.URL.RawQuery = params.Encode() + if rangeParameter != nil { + req.Header.Set("x-ms-range", *rangeParameter) + } + if leaseID != nil { + req.Header.Set("x-ms-lease-id", *leaseID) + } + if ifModifiedSince != nil { + req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifUnmodifiedSince != nil { + req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifMatches != nil { + req.Header.Set("If-Match", string(*ifMatches)) + } + if ifNoneMatch != nil { + req.Header.Set("If-None-Match", string(*ifNoneMatch)) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + return req, nil +} + +// getPageRangesDiffResponder handles the response to the GetPageRangesDiff request. +func (client pageBlobClient) getPageRangesDiffResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK) + if resp == nil { + return nil, err + } + result := &PageList{rawResponse: resp.Response()} + if err != nil { + return result, err + } + defer resp.Response().Body.Close() + b, err := ioutil.ReadAll(resp.Response().Body) + if err != nil { + return result, NewResponseError(err, resp.Response(), "failed to read response body") + } + if len(b) > 0 { + b = removeBOM(b) + err = xml.Unmarshal(b, result) + if err != nil { + return result, NewResponseError(err, resp.Response(), "failed to unmarshal response body") + } + } + return result, nil +} + +// Resize resize the Blob +// +// blobContentLength is this header specifies the maximum size for the page blob, up to 1 TB. The page blob size must +// be aligned to a 512-byte boundary. timeout is the timeout parameter is expressed in seconds. For more information, +// see Setting +// Timeouts for Blob Service Operations. leaseID is if specified, the operation only succeeds if the container's +// lease is active and matches this ID. ifModifiedSince is specify this header value to operate only on a blob if it +// has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a +// blob if it has not been modified since the specified date/time. ifMatches is specify an ETag value to operate only +// on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching +// value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded in the +// analytics logs when storage analytics logging is enabled. +func (client pageBlobClient) Resize(ctx context.Context, blobContentLength int64, timeout *int32, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*PageBlobResizeResponse, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.resizePreparer(blobContentLength, timeout, leaseID, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.resizeResponder}, req) + if err != nil { + return nil, err + } + return resp.(*PageBlobResizeResponse), err +} + +// resizePreparer prepares the Resize request. +func (client pageBlobClient) resizePreparer(blobContentLength int64, timeout *int32, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("PUT", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("comp", "properties") + req.URL.RawQuery = params.Encode() + if leaseID != nil { + req.Header.Set("x-ms-lease-id", *leaseID) + } + if ifModifiedSince != nil { + req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifUnmodifiedSince != nil { + req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifMatches != nil { + req.Header.Set("If-Match", string(*ifMatches)) + } + if ifNoneMatch != nil { + req.Header.Set("If-None-Match", string(*ifNoneMatch)) + } + req.Header.Set("x-ms-blob-content-length", strconv.FormatInt(blobContentLength, 10)) + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + return req, nil +} + +// resizeResponder handles the response to the Resize request. +func (client pageBlobClient) resizeResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &PageBlobResizeResponse{rawResponse: resp.Response()}, err +} + +// UpdateSequenceNumber update the sequence number of the blob +// +// sequenceNumberAction is required if the x-ms-blob-sequence-number header is set for the request. This property +// applies to page blobs only. This property indicates how the service should modify the blob's sequence number timeout +// is the timeout parameter is expressed in seconds. For more information, see Setting +// Timeouts for Blob Service Operations. leaseID is if specified, the operation only succeeds if the container's +// lease is active and matches this ID. ifModifiedSince is specify this header value to operate only on a blob if it +// has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a +// blob if it has not been modified since the specified date/time. ifMatches is specify an ETag value to operate only +// on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching +// value. blobSequenceNumber is set for page blobs only. The sequence number is a user-controlled value that you can +// use to track requests. The value of the sequence number must be between 0 and 2^63 - 1. requestID is provides a +// client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage +// analytics logging is enabled. +func (client pageBlobClient) UpdateSequenceNumber(ctx context.Context, sequenceNumberAction SequenceNumberActionType, timeout *int32, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, blobSequenceNumber *int64, requestID *string) (*PageBlobUpdateSequenceNumberResponse, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.updateSequenceNumberPreparer(sequenceNumberAction, timeout, leaseID, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, blobSequenceNumber, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.updateSequenceNumberResponder}, req) + if err != nil { + return nil, err + } + return resp.(*PageBlobUpdateSequenceNumberResponse), err +} + +// updateSequenceNumberPreparer prepares the UpdateSequenceNumber request. +func (client pageBlobClient) updateSequenceNumberPreparer(sequenceNumberAction SequenceNumberActionType, timeout *int32, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, blobSequenceNumber *int64, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("PUT", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("comp", "properties") + req.URL.RawQuery = params.Encode() + if leaseID != nil { + req.Header.Set("x-ms-lease-id", *leaseID) + } + if ifModifiedSince != nil { + req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifUnmodifiedSince != nil { + req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifMatches != nil { + req.Header.Set("If-Match", string(*ifMatches)) + } + if ifNoneMatch != nil { + req.Header.Set("If-None-Match", string(*ifNoneMatch)) + } + req.Header.Set("x-ms-sequence-number-action", string(sequenceNumberAction)) + if blobSequenceNumber != nil { + req.Header.Set("x-ms-blob-sequence-number", strconv.FormatInt(*blobSequenceNumber, 10)) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + return req, nil +} + +// updateSequenceNumberResponder handles the response to the UpdateSequenceNumber request. +func (client pageBlobClient) updateSequenceNumberResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &PageBlobUpdateSequenceNumberResponse{rawResponse: resp.Response()}, err +} + +// UploadPages the Upload Pages operation writes a range of pages to a page blob +// +// body is initial data body will be closed upon successful return. Callers should ensure closure when receiving an +// error.contentLength is the length of the request. timeout is the timeout parameter is expressed in seconds. For more +// information, see Setting +// Timeouts for Blob Service Operations. rangeParameter is return only the bytes of the blob in the specified +// range. leaseID is if specified, the operation only succeeds if the container's lease is active and matches this ID. +// ifSequenceNumberLessThanOrEqualTo is specify this header value to operate only on a blob if it has a sequence number +// less than or equal to the specified. ifSequenceNumberLessThan is specify this header value to operate only on a blob +// if it has a sequence number less than the specified. ifSequenceNumberEqualTo is specify this header value to operate +// only on a blob if it has the specified sequence number. ifModifiedSince is specify this header value to operate only +// on a blob if it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to +// operate only on a blob if it has not been modified since the specified date/time. ifMatches is specify an ETag value +// to operate only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs +// without a matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is +// recorded in the analytics logs when storage analytics logging is enabled. +func (client pageBlobClient) UploadPages(ctx context.Context, body io.ReadSeeker, contentLength int64, timeout *int32, rangeParameter *string, leaseID *string, ifSequenceNumberLessThanOrEqualTo *int64, ifSequenceNumberLessThan *int64, ifSequenceNumberEqualTo *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*PageBlobUploadPagesResponse, error) { + if err := validate([]validation{ + {targetValue: body, + constraints: []constraint{{target: "body", name: null, rule: true, chain: nil}}}, + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.uploadPagesPreparer(body, contentLength, timeout, rangeParameter, leaseID, ifSequenceNumberLessThanOrEqualTo, ifSequenceNumberLessThan, ifSequenceNumberEqualTo, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.uploadPagesResponder}, req) + if err != nil { + return nil, err + } + return resp.(*PageBlobUploadPagesResponse), err +} + +// uploadPagesPreparer prepares the UploadPages request. +func (client pageBlobClient) uploadPagesPreparer(body io.ReadSeeker, contentLength int64, timeout *int32, rangeParameter *string, leaseID *string, ifSequenceNumberLessThanOrEqualTo *int64, ifSequenceNumberLessThan *int64, ifSequenceNumberEqualTo *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("PUT", client.url, body) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("comp", "page") + req.URL.RawQuery = params.Encode() + req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10)) + if rangeParameter != nil { + req.Header.Set("x-ms-range", *rangeParameter) + } + if leaseID != nil { + req.Header.Set("x-ms-lease-id", *leaseID) + } + if ifSequenceNumberLessThanOrEqualTo != nil { + req.Header.Set("x-ms-if-sequence-number-le", strconv.FormatInt(*ifSequenceNumberLessThanOrEqualTo, 10)) + } + if ifSequenceNumberLessThan != nil { + req.Header.Set("x-ms-if-sequence-number-lt", strconv.FormatInt(*ifSequenceNumberLessThan, 10)) + } + if ifSequenceNumberEqualTo != nil { + req.Header.Set("x-ms-if-sequence-number-eq", strconv.FormatInt(*ifSequenceNumberEqualTo, 10)) + } + if ifModifiedSince != nil { + req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifUnmodifiedSince != nil { + req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) + } + if ifMatches != nil { + req.Header.Set("If-Match", string(*ifMatches)) + } + if ifNoneMatch != nil { + req.Header.Set("If-None-Match", string(*ifNoneMatch)) + } + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + req.Header.Set("x-ms-page-write", "update") + return req, nil +} + +// uploadPagesResponder handles the response to the UploadPages request. +func (client pageBlobClient) uploadPagesResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK, http.StatusCreated) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &PageBlobUploadPagesResponse{rawResponse: resp.Response()}, err +} diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_responder_policy.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_responder_policy.go new file mode 100644 index 0000000000..2f391d7312 --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_responder_policy.go @@ -0,0 +1,74 @@ +package azblob + +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +import ( + "bytes" + "context" + "encoding/xml" + "github.com/Azure/azure-pipeline-go/pipeline" + "io/ioutil" +) + +type responder func(resp pipeline.Response) (result pipeline.Response, err error) + +// ResponderPolicyFactory is a Factory capable of creating a responder pipeline. +type responderPolicyFactory struct { + responder responder +} + +// New creates a responder policy factory. +func (arpf responderPolicyFactory) New(next pipeline.Policy, po *pipeline.PolicyOptions) pipeline.Policy { + return responderPolicy{next: next, responder: arpf.responder} +} + +type responderPolicy struct { + next pipeline.Policy + responder responder +} + +// Do sends the request to the service and validates/deserializes the HTTP response. +func (arp responderPolicy) Do(ctx context.Context, request pipeline.Request) (pipeline.Response, error) { + resp, err := arp.next.Do(ctx, request) + if err != nil { + return resp, err + } + return arp.responder(resp) +} + +// validateResponse checks an HTTP response's status code against a legal set of codes. +// If the response code is not legal, then validateResponse reads all of the response's body +// (containing error information) and returns a response error. +func validateResponse(resp pipeline.Response, successStatusCodes ...int) error { + if resp == nil { + return NewResponseError(nil, nil, "nil response") + } + responseCode := resp.Response().StatusCode + for _, i := range successStatusCodes { + if i == responseCode { + return nil + } + } + // only close the body in the failure case. in the + // success case responders will close the body as required. + defer resp.Response().Body.Close() + b, err := ioutil.ReadAll(resp.Response().Body) + if err != nil { + return NewResponseError(err, resp.Response(), "failed to read response body") + } + // the service code, description and details will be populated during unmarshalling + responseError := NewResponseError(nil, resp.Response(), resp.Response().Status) + if len(b) > 0 { + if err = xml.Unmarshal(b, &responseError); err != nil { + return NewResponseError(err, resp.Response(), "failed to unmarshal response body") + } + } + return responseError +} + +// removes any BOM from the byte slice +func removeBOM(b []byte) []byte { + // UTF8 + return bytes.TrimPrefix(b, []byte("\xef\xbb\xbf")) +} diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_response_error.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_response_error.go new file mode 100644 index 0000000000..3dcc75bb52 --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_response_error.go @@ -0,0 +1,95 @@ +package azblob + +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +import ( + "bytes" + "fmt" + "github.com/Azure/azure-pipeline-go/pipeline" + "net" + "net/http" +) + +// if you want to provide custom error handling set this variable to your constructor function +var responseErrorFactory func(cause error, response *http.Response, description string) error + +// ResponseError identifies a responder-generated network or response parsing error. +type ResponseError interface { + // Error exposes the Error(), Temporary() and Timeout() methods. + net.Error // Includes the Go error interface + // Response returns the HTTP response. You may examine this but you should not modify it. + Response() *http.Response +} + +// NewResponseError creates an error object that implements the error interface. +func NewResponseError(cause error, response *http.Response, description string) error { + if responseErrorFactory != nil { + return responseErrorFactory(cause, response, description) + } + return &responseError{ + ErrorNode: pipeline.ErrorNode{}.Initialize(cause, 3), + response: response, + description: description, + } +} + +// responseError is the internal struct that implements the public ResponseError interface. +type responseError struct { + pipeline.ErrorNode // This is embedded so that responseError "inherits" Error, Temporary, Timeout, and Cause + response *http.Response + description string +} + +// Error implements the error interface's Error method to return a string representation of the error. +func (e *responseError) Error() string { + b := &bytes.Buffer{} + fmt.Fprintf(b, "===== RESPONSE ERROR (Code=%v) =====\n", e.response.StatusCode) + fmt.Fprintf(b, "Status=%s, Description: %s\n", e.response.Status, e.description) + s := b.String() + return e.ErrorNode.Error(s) +} + +// Response implements the ResponseError interface's method to return the HTTP response. +func (e *responseError) Response() *http.Response { + return e.response +} + +// RFC7807 PROBLEM ------------------------------------------------------------------------------------ +// RFC7807Problem ... This type can be publicly embedded in another type that wants to add additional members. +/*type RFC7807Problem struct { + // Mandatory: A (relative) URI reference identifying the problem type (it MAY refer to human-readable documentation). + typeURI string // Should default to "about:blank" + // Optional: Short, human-readable summary (maybe localized). + title string + // Optional: HTTP status code generated by the origin server + status int + // Optional: Human-readable explanation for this problem occurance. + // Should help client correct the problem. Clients should NOT parse this string. + detail string + // Optional: A (relative) URI identifying this specific problem occurence (it may or may not be dereferenced). + instance string +} +// NewRFC7807Problem ... +func NewRFC7807Problem(typeURI string, status int, titleFormat string, a ...interface{}) error { + return &RFC7807Problem{ + typeURI: typeURI, + status: status, + title: fmt.Sprintf(titleFormat, a...), + } +} +// Error returns the error information as a string. +func (e *RFC7807Problem) Error() string { + return e.title +} +// TypeURI ... +func (e *RFC7807Problem) TypeURI() string { + if e.typeURI == "" { + e.typeURI = "about:blank" + } + return e.typeURI +} +// Members ... +func (e *RFC7807Problem) Members() (status int, title, detail, instance string) { + return e.status, e.title, e.detail, e.instance +}*/ diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_service.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_service.go new file mode 100644 index 0000000000..76f235e159 --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_service.go @@ -0,0 +1,350 @@ +package azblob + +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +import ( + "bytes" + "context" + "encoding/xml" + "github.com/Azure/azure-pipeline-go/pipeline" + "io" + "io/ioutil" + "net/http" + "net/url" + "strconv" +) + +// serviceClient is the client for the Service methods of the Azblob service. +type serviceClient struct { + managementClient +} + +// newServiceClient creates an instance of the serviceClient client. +func newServiceClient(url url.URL, p pipeline.Pipeline) serviceClient { + return serviceClient{newManagementClient(url, p)} +} + +// GetProperties gets the properties of a storage account's Blob service, including properties for Storage Analytics +// and CORS (Cross-Origin Resource Sharing) rules. +// +// timeout is the timeout parameter is expressed in seconds. For more information, see Setting +// Timeouts for Blob Service Operations. requestID is provides a client-generated, opaque value with a 1 KB +// character limit that is recorded in the analytics logs when storage analytics logging is enabled. +func (client serviceClient) GetProperties(ctx context.Context, timeout *int32, requestID *string) (*StorageServiceProperties, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.getPropertiesPreparer(timeout, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.getPropertiesResponder}, req) + if err != nil { + return nil, err + } + return resp.(*StorageServiceProperties), err +} + +// getPropertiesPreparer prepares the GetProperties request. +func (client serviceClient) getPropertiesPreparer(timeout *int32, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("GET", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("restype", "service") + params.Set("comp", "properties") + req.URL.RawQuery = params.Encode() + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + return req, nil +} + +// getPropertiesResponder handles the response to the GetProperties request. +func (client serviceClient) getPropertiesResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK) + if resp == nil { + return nil, err + } + result := &StorageServiceProperties{rawResponse: resp.Response()} + if err != nil { + return result, err + } + defer resp.Response().Body.Close() + b, err := ioutil.ReadAll(resp.Response().Body) + if err != nil { + return result, NewResponseError(err, resp.Response(), "failed to read response body") + } + if len(b) > 0 { + b = removeBOM(b) + err = xml.Unmarshal(b, result) + if err != nil { + return result, NewResponseError(err, resp.Response(), "failed to unmarshal response body") + } + } + return result, nil +} + +// GetStatistics retrieves statistics related to replication for the Blob service. It is only available on the +// secondary location endpoint when read-access geo-redundant replication is enabled for the storage account. +// +// timeout is the timeout parameter is expressed in seconds. For more information, see Setting +// Timeouts for Blob Service Operations. requestID is provides a client-generated, opaque value with a 1 KB +// character limit that is recorded in the analytics logs when storage analytics logging is enabled. +func (client serviceClient) GetStatistics(ctx context.Context, timeout *int32, requestID *string) (*StorageServiceStats, error) { + if err := validate([]validation{ + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.getStatisticsPreparer(timeout, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.getStatisticsResponder}, req) + if err != nil { + return nil, err + } + return resp.(*StorageServiceStats), err +} + +// getStatisticsPreparer prepares the GetStatistics request. +func (client serviceClient) getStatisticsPreparer(timeout *int32, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("GET", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("restype", "service") + params.Set("comp", "stats") + req.URL.RawQuery = params.Encode() + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + return req, nil +} + +// getStatisticsResponder handles the response to the GetStatistics request. +func (client serviceClient) getStatisticsResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK) + if resp == nil { + return nil, err + } + result := &StorageServiceStats{rawResponse: resp.Response()} + if err != nil { + return result, err + } + defer resp.Response().Body.Close() + b, err := ioutil.ReadAll(resp.Response().Body) + if err != nil { + return result, NewResponseError(err, resp.Response(), "failed to read response body") + } + if len(b) > 0 { + b = removeBOM(b) + err = xml.Unmarshal(b, result) + if err != nil { + return result, NewResponseError(err, resp.Response(), "failed to unmarshal response body") + } + } + return result, nil +} + +// ListContainersSegment the List Containers Segment operation returns a list of the containers under the specified +// account +// +// prefix is filters the results to return only containers whose name begins with the specified prefix. marker is a +// string value that identifies the portion of the list of containers to be returned with the next listing operation. +// The operation returns the NextMarker value within the response body if the listing operation did not return all +// containers remaining to be listed with the current page. The NextMarker value can be used as the value for the +// marker parameter in a subsequent call to request the next page of list items. The marker value is opaque to the +// client. maxresults is specifies the maximum number of containers to return. If the request does not specify +// maxresults, or specifies a value greater than 5000, the server will return up to 5000 items. Note that if the +// listing operation crosses a partition boundary, then the service will return a continuation token for retrieving the +// remainder of the results. For this reason, it is possible that the service will return fewer results than specified +// by maxresults, or than the default of 5000. include is include this parameter to specify that the container's +// metadata be returned as part of the response body. timeout is the timeout parameter is expressed in seconds. For +// more information, see Setting +// Timeouts for Blob Service Operations. requestID is provides a client-generated, opaque value with a 1 KB +// character limit that is recorded in the analytics logs when storage analytics logging is enabled. +func (client serviceClient) ListContainersSegment(ctx context.Context, prefix *string, marker *string, maxresults *int32, include ListContainersIncludeType, timeout *int32, requestID *string) (*ListContainersResponse, error) { + if err := validate([]validation{ + {targetValue: maxresults, + constraints: []constraint{{target: "maxresults", name: null, rule: false, + chain: []constraint{{target: "maxresults", name: inclusiveMinimum, rule: 1, chain: nil}}}}}, + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.listContainersSegmentPreparer(prefix, marker, maxresults, include, timeout, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.listContainersSegmentResponder}, req) + if err != nil { + return nil, err + } + return resp.(*ListContainersResponse), err +} + +// listContainersSegmentPreparer prepares the ListContainersSegment request. +func (client serviceClient) listContainersSegmentPreparer(prefix *string, marker *string, maxresults *int32, include ListContainersIncludeType, timeout *int32, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("GET", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if prefix != nil && len(*prefix) > 0 { + params.Set("prefix", *prefix) + } + if marker != nil && len(*marker) > 0 { + params.Set("marker", *marker) + } + if maxresults != nil { + params.Set("maxresults", strconv.FormatInt(int64(*maxresults), 10)) + } + if include != ListContainersIncludeNone { + params.Set("include", string(include)) + } + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("comp", "list") + req.URL.RawQuery = params.Encode() + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + return req, nil +} + +// listContainersSegmentResponder handles the response to the ListContainersSegment request. +func (client serviceClient) listContainersSegmentResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK) + if resp == nil { + return nil, err + } + result := &ListContainersResponse{rawResponse: resp.Response()} + if err != nil { + return result, err + } + defer resp.Response().Body.Close() + b, err := ioutil.ReadAll(resp.Response().Body) + if err != nil { + return result, NewResponseError(err, resp.Response(), "failed to read response body") + } + if len(b) > 0 { + b = removeBOM(b) + err = xml.Unmarshal(b, result) + if err != nil { + return result, NewResponseError(err, resp.Response(), "failed to unmarshal response body") + } + } + return result, nil +} + +// SetProperties sets properties for a storage account's Blob service endpoint, including properties for Storage +// Analytics and CORS (Cross-Origin Resource Sharing) rules +// +// storageServiceProperties is the StorageService properties. timeout is the timeout parameter is expressed in seconds. +// For more information, see Setting +// Timeouts for Blob Service Operations. requestID is provides a client-generated, opaque value with a 1 KB +// character limit that is recorded in the analytics logs when storage analytics logging is enabled. +func (client serviceClient) SetProperties(ctx context.Context, storageServiceProperties StorageServiceProperties, timeout *int32, requestID *string) (*ServiceSetPropertiesResponse, error) { + if err := validate([]validation{ + {targetValue: storageServiceProperties, + constraints: []constraint{{target: "storageServiceProperties.Logging", name: null, rule: false, + chain: []constraint{{target: "storageServiceProperties.Logging.RetentionPolicy", name: null, rule: true, + chain: []constraint{{target: "storageServiceProperties.Logging.RetentionPolicy.Days", name: null, rule: false, + chain: []constraint{{target: "storageServiceProperties.Logging.RetentionPolicy.Days", name: inclusiveMinimum, rule: 1, chain: nil}}}, + }}, + }}, + {target: "storageServiceProperties.HourMetrics", name: null, rule: false, + chain: []constraint{{target: "storageServiceProperties.HourMetrics.RetentionPolicy", name: null, rule: false, + chain: []constraint{{target: "storageServiceProperties.HourMetrics.RetentionPolicy.Days", name: null, rule: false, + chain: []constraint{{target: "storageServiceProperties.HourMetrics.RetentionPolicy.Days", name: inclusiveMinimum, rule: 1, chain: nil}}}, + }}, + }}, + {target: "storageServiceProperties.MinuteMetrics", name: null, rule: false, + chain: []constraint{{target: "storageServiceProperties.MinuteMetrics.RetentionPolicy", name: null, rule: false, + chain: []constraint{{target: "storageServiceProperties.MinuteMetrics.RetentionPolicy.Days", name: null, rule: false, + chain: []constraint{{target: "storageServiceProperties.MinuteMetrics.RetentionPolicy.Days", name: inclusiveMinimum, rule: 1, chain: nil}}}, + }}, + }}, + {target: "storageServiceProperties.DeleteRetentionPolicy", name: null, rule: false, + chain: []constraint{{target: "storageServiceProperties.DeleteRetentionPolicy.Days", name: null, rule: false, + chain: []constraint{{target: "storageServiceProperties.DeleteRetentionPolicy.Days", name: inclusiveMinimum, rule: 1, chain: nil}}}, + }}}}, + {targetValue: timeout, + constraints: []constraint{{target: "timeout", name: null, rule: false, + chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { + return nil, err + } + req, err := client.setPropertiesPreparer(storageServiceProperties, timeout, requestID) + if err != nil { + return nil, err + } + resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.setPropertiesResponder}, req) + if err != nil { + return nil, err + } + return resp.(*ServiceSetPropertiesResponse), err +} + +// setPropertiesPreparer prepares the SetProperties request. +func (client serviceClient) setPropertiesPreparer(storageServiceProperties StorageServiceProperties, timeout *int32, requestID *string) (pipeline.Request, error) { + req, err := pipeline.NewRequest("PUT", client.url, nil) + if err != nil { + return req, pipeline.NewError(err, "failed to create request") + } + params := req.URL.Query() + if timeout != nil { + params.Set("timeout", strconv.FormatInt(int64(*timeout), 10)) + } + params.Set("restype", "service") + params.Set("comp", "properties") + req.URL.RawQuery = params.Encode() + req.Header.Set("x-ms-version", ServiceVersion) + if requestID != nil { + req.Header.Set("x-ms-client-request-id", *requestID) + } + b, err := xml.Marshal(storageServiceProperties) + if err != nil { + return req, pipeline.NewError(err, "failed to marshal request body") + } + req.Header.Set("Content-Type", "application/xml") + err = req.SetBody(bytes.NewReader(b)) + if err != nil { + return req, pipeline.NewError(err, "failed to set request body") + } + return req, nil +} + +// setPropertiesResponder handles the response to the SetProperties request. +func (client serviceClient) setPropertiesResponder(resp pipeline.Response) (pipeline.Response, error) { + err := validateResponse(resp, http.StatusOK, http.StatusAccepted) + if resp == nil { + return nil, err + } + io.Copy(ioutil.Discard, resp.Response().Body) + resp.Response().Body.Close() + return &ServiceSetPropertiesResponse{rawResponse: resp.Response()}, err +} diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_validation.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_validation.go new file mode 100644 index 0000000000..98a2614e60 --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_validation.go @@ -0,0 +1,367 @@ +package azblob + +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +import ( + "fmt" + "github.com/Azure/azure-pipeline-go/pipeline" + "reflect" + "regexp" + "strings" +) + +// Constraint stores constraint name, target field name +// Rule and chain validations. +type constraint struct { + // Target field name for validation. + target string + + // Constraint name e.g. minLength, MaxLength, Pattern, etc. + name string + + // Rule for constraint e.g. greater than 10, less than 5 etc. + rule interface{} + + // Chain validations for struct type + chain []constraint +} + +// Validation stores parameter-wise validation. +type validation struct { + targetValue interface{} + constraints []constraint +} + +// Constraint list +const ( + empty = "Empty" + null = "Null" + readOnly = "ReadOnly" + pattern = "Pattern" + maxLength = "MaxLength" + minLength = "MinLength" + maxItems = "MaxItems" + minItems = "MinItems" + multipleOf = "MultipleOf" + uniqueItems = "UniqueItems" + inclusiveMaximum = "InclusiveMaximum" + exclusiveMaximum = "ExclusiveMaximum" + exclusiveMinimum = "ExclusiveMinimum" + inclusiveMinimum = "InclusiveMinimum" +) + +// Validate method validates constraints on parameter +// passed in validation array. +func validate(m []validation) error { + for _, item := range m { + v := reflect.ValueOf(item.targetValue) + for _, constraint := range item.constraints { + var err error + switch v.Kind() { + case reflect.Ptr: + err = validatePtr(v, constraint) + case reflect.String: + err = validateString(v, constraint) + case reflect.Struct: + err = validateStruct(v, constraint) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + err = validateInt(v, constraint) + case reflect.Float32, reflect.Float64: + err = validateFloat(v, constraint) + case reflect.Array, reflect.Slice, reflect.Map: + err = validateArrayMap(v, constraint) + default: + err = createError(v, constraint, fmt.Sprintf("unknown type %v", v.Kind())) + } + if err != nil { + return err + } + } + } + return nil +} + +func validateStruct(x reflect.Value, v constraint, name ...string) error { + //Get field name from target name which is in format a.b.c + s := strings.Split(v.target, ".") + f := x.FieldByName(s[len(s)-1]) + if isZero(f) { + return createError(x, v, fmt.Sprintf("field %q doesn't exist", v.target)) + } + err := validate([]validation{ + { + targetValue: getInterfaceValue(f), + constraints: []constraint{v}, + }, + }) + return err +} + +func validatePtr(x reflect.Value, v constraint) error { + if v.name == readOnly { + if !x.IsNil() { + return createError(x.Elem(), v, "readonly parameter; must send as nil or empty in request") + } + return nil + } + if x.IsNil() { + return checkNil(x, v) + } + if v.chain != nil { + return validate([]validation{ + { + targetValue: getInterfaceValue(x.Elem()), + constraints: v.chain, + }, + }) + } + return nil +} + +func validateInt(x reflect.Value, v constraint) error { + i := x.Int() + r, ok := v.rule.(int) + if !ok { + return createError(x, v, fmt.Sprintf("rule must be integer value for %v constraint; got: %v", v.name, v.rule)) + } + switch v.name { + case multipleOf: + if i%int64(r) != 0 { + return createError(x, v, fmt.Sprintf("value must be a multiple of %v", r)) + } + case exclusiveMinimum: + if i <= int64(r) { + return createError(x, v, fmt.Sprintf("value must be greater than %v", r)) + } + case exclusiveMaximum: + if i >= int64(r) { + return createError(x, v, fmt.Sprintf("value must be less than %v", r)) + } + case inclusiveMinimum: + if i < int64(r) { + return createError(x, v, fmt.Sprintf("value must be greater than or equal to %v", r)) + } + case inclusiveMaximum: + if i > int64(r) { + return createError(x, v, fmt.Sprintf("value must be less than or equal to %v", r)) + } + default: + return createError(x, v, fmt.Sprintf("constraint %v is not applicable for type integer", v.name)) + } + return nil +} + +func validateFloat(x reflect.Value, v constraint) error { + f := x.Float() + r, ok := v.rule.(float64) + if !ok { + return createError(x, v, fmt.Sprintf("rule must be float value for %v constraint; got: %v", v.name, v.rule)) + } + switch v.name { + case exclusiveMinimum: + if f <= r { + return createError(x, v, fmt.Sprintf("value must be greater than %v", r)) + } + case exclusiveMaximum: + if f >= r { + return createError(x, v, fmt.Sprintf("value must be less than %v", r)) + } + case inclusiveMinimum: + if f < r { + return createError(x, v, fmt.Sprintf("value must be greater than or equal to %v", r)) + } + case inclusiveMaximum: + if f > r { + return createError(x, v, fmt.Sprintf("value must be less than or equal to %v", r)) + } + default: + return createError(x, v, fmt.Sprintf("constraint %s is not applicable for type float", v.name)) + } + return nil +} + +func validateString(x reflect.Value, v constraint) error { + s := x.String() + switch v.name { + case empty: + if len(s) == 0 { + return checkEmpty(x, v) + } + case pattern: + reg, err := regexp.Compile(v.rule.(string)) + if err != nil { + return createError(x, v, err.Error()) + } + if !reg.MatchString(s) { + return createError(x, v, fmt.Sprintf("value doesn't match pattern %v", v.rule)) + } + case maxLength: + if _, ok := v.rule.(int); !ok { + return createError(x, v, fmt.Sprintf("rule must be integer value for %v constraint; got: %v", v.name, v.rule)) + } + if len(s) > v.rule.(int) { + return createError(x, v, fmt.Sprintf("value length must be less than %v", v.rule)) + } + case minLength: + if _, ok := v.rule.(int); !ok { + return createError(x, v, fmt.Sprintf("rule must be integer value for %v constraint; got: %v", v.name, v.rule)) + } + if len(s) < v.rule.(int) { + return createError(x, v, fmt.Sprintf("value length must be greater than %v", v.rule)) + } + case readOnly: + if len(s) > 0 { + return createError(reflect.ValueOf(s), v, "readonly parameter; must send as nil or empty in request") + } + default: + return createError(x, v, fmt.Sprintf("constraint %s is not applicable to string type", v.name)) + } + if v.chain != nil { + return validate([]validation{ + { + targetValue: getInterfaceValue(x), + constraints: v.chain, + }, + }) + } + return nil +} + +func validateArrayMap(x reflect.Value, v constraint) error { + switch v.name { + case null: + if x.IsNil() { + return checkNil(x, v) + } + case empty: + if x.IsNil() || x.Len() == 0 { + return checkEmpty(x, v) + } + case maxItems: + if _, ok := v.rule.(int); !ok { + return createError(x, v, fmt.Sprintf("rule must be integer for %v constraint; got: %v", v.name, v.rule)) + } + if x.Len() > v.rule.(int) { + return createError(x, v, fmt.Sprintf("maximum item limit is %v; got: %v", v.rule, x.Len())) + } + case minItems: + if _, ok := v.rule.(int); !ok { + return createError(x, v, fmt.Sprintf("rule must be integer for %v constraint; got: %v", v.name, v.rule)) + } + if x.Len() < v.rule.(int) { + return createError(x, v, fmt.Sprintf("minimum item limit is %v; got: %v", v.rule, x.Len())) + } + case uniqueItems: + if x.Kind() == reflect.Array || x.Kind() == reflect.Slice { + if !checkForUniqueInArray(x) { + return createError(x, v, fmt.Sprintf("all items in parameter %q must be unique; got:%v", v.target, x)) + } + } else if x.Kind() == reflect.Map { + if !checkForUniqueInMap(x) { + return createError(x, v, fmt.Sprintf("all items in parameter %q must be unique; got:%v", v.target, x)) + } + } else { + return createError(x, v, fmt.Sprintf("type must be array, slice or map for constraint %v; got: %v", v.name, x.Kind())) + } + case readOnly: + if x.Len() != 0 { + return createError(x, v, "readonly parameter; must send as nil or empty in request") + } + case pattern: + reg, err := regexp.Compile(v.rule.(string)) + if err != nil { + return createError(x, v, err.Error()) + } + keys := x.MapKeys() + for _, k := range keys { + if !reg.MatchString(k.String()) { + return createError(k, v, fmt.Sprintf("map key doesn't match pattern %v", v.rule)) + } + } + default: + return createError(x, v, fmt.Sprintf("constraint %v is not applicable to array, slice and map type", v.name)) + } + if v.chain != nil { + return validate([]validation{ + { + targetValue: getInterfaceValue(x), + constraints: v.chain, + }, + }) + } + return nil +} + +func checkNil(x reflect.Value, v constraint) error { + if _, ok := v.rule.(bool); !ok { + return createError(x, v, fmt.Sprintf("rule must be bool value for %v constraint; got: %v", v.name, v.rule)) + } + if v.rule.(bool) { + return createError(x, v, "value can not be null; required parameter") + } + return nil +} + +func checkEmpty(x reflect.Value, v constraint) error { + if _, ok := v.rule.(bool); !ok { + return createError(x, v, fmt.Sprintf("rule must be bool value for %v constraint; got: %v", v.name, v.rule)) + } + if v.rule.(bool) { + return createError(x, v, "value can not be null or empty; required parameter") + } + return nil +} + +func checkForUniqueInArray(x reflect.Value) bool { + if x == reflect.Zero(reflect.TypeOf(x)) || x.Len() == 0 { + return false + } + arrOfInterface := make([]interface{}, x.Len()) + for i := 0; i < x.Len(); i++ { + arrOfInterface[i] = x.Index(i).Interface() + } + m := make(map[interface{}]bool) + for _, val := range arrOfInterface { + if m[val] { + return false + } + m[val] = true + } + return true +} + +func checkForUniqueInMap(x reflect.Value) bool { + if x == reflect.Zero(reflect.TypeOf(x)) || x.Len() == 0 { + return false + } + mapOfInterface := make(map[interface{}]interface{}, x.Len()) + keys := x.MapKeys() + for _, k := range keys { + mapOfInterface[k.Interface()] = x.MapIndex(k).Interface() + } + m := make(map[interface{}]bool) + for _, val := range mapOfInterface { + if m[val] { + return false + } + m[val] = true + } + return true +} + +func getInterfaceValue(x reflect.Value) interface{} { + if x.Kind() == reflect.Invalid { + return nil + } + return x.Interface() +} + +func isZero(x interface{}) bool { + return x == reflect.Zero(reflect.TypeOf(x)).Interface() +} + +func createError(x reflect.Value, v constraint, message string) error { + return pipeline.NewError(nil, fmt.Sprintf("validation failed: parameter=%s constraint=%s value=%#v details: %s", + v.target, v.name, getInterfaceValue(x), message)) +} diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_version.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_version.go new file mode 100644 index 0000000000..760271a421 --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_generated_version.go @@ -0,0 +1,14 @@ +package azblob + +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +// UserAgent returns the UserAgent string to use when sending http.Requests. +func UserAgent() string { + return "Azure-SDK-For-Go/0.0.0 azblob/2018-03-28" +} + +// Version returns the semantic version (see http://semver.org) of the client. +func Version() string { + return "0.0.0" +} diff --git a/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_response_helpers.go b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_response_helpers.go new file mode 100644 index 0000000000..b4f058b674 --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/zz_response_helpers.go @@ -0,0 +1,242 @@ +package azblob + +import ( + "context" + "io" + "net/http" + "time" +) + +// BlobHTTPHeaders contains read/writeable blob properties. +type BlobHTTPHeaders struct { + ContentType string + ContentMD5 []byte + ContentEncoding string + ContentLanguage string + ContentDisposition string + CacheControl string +} + +// NewHTTPHeaders returns the user-modifiable properties for this blob. +func (bgpr BlobGetPropertiesResponse) NewHTTPHeaders() BlobHTTPHeaders { + return BlobHTTPHeaders{ + ContentType: bgpr.ContentType(), + ContentEncoding: bgpr.ContentEncoding(), + ContentLanguage: bgpr.ContentLanguage(), + ContentDisposition: bgpr.ContentDisposition(), + CacheControl: bgpr.CacheControl(), + ContentMD5: bgpr.ContentMD5(), + } +} + +/////////////////////////////////////////////////////////////////////////////// + +// NewHTTPHeaders returns the user-modifiable properties for this blob. +func (dr downloadResponse) NewHTTPHeaders() BlobHTTPHeaders { + return BlobHTTPHeaders{ + ContentType: dr.ContentType(), + ContentEncoding: dr.ContentEncoding(), + ContentLanguage: dr.ContentLanguage(), + ContentDisposition: dr.ContentDisposition(), + CacheControl: dr.CacheControl(), + ContentMD5: dr.ContentMD5(), + } +} + +/////////////////////////////////////////////////////////////////////////////// + +// DownloadResponse wraps AutoRest generated downloadResponse and helps to provide info for retry. +type DownloadResponse struct { + r *downloadResponse + ctx context.Context + b BlobURL + getInfo HTTPGetterInfo +} + +// Body constructs new RetryReader stream for reading data. If a connection failes +// while reading, it will make additional requests to reestablish a connection and +// continue reading. Specifying a RetryReaderOption's with MaxRetryRequests set to 0 +// (the default), returns the original response body and no retries will be performed. +func (r *DownloadResponse) Body(o RetryReaderOptions) io.ReadCloser { + if o.MaxRetryRequests == 0 { // No additional retries + return r.Response().Body + } + return NewRetryReader(r.ctx, r.Response(), r.getInfo, o, + func(ctx context.Context, getInfo HTTPGetterInfo) (*http.Response, error) { + resp, err := r.b.Download(ctx, getInfo.Offset, getInfo.Count, + BlobAccessConditions{ + HTTPAccessConditions: HTTPAccessConditions{IfMatch: getInfo.ETag}, + }, + false) + if err != nil { + return nil, err + } + return resp.Response(), err + }, + ) +} + +// Response returns the raw HTTP response object. +func (r DownloadResponse) Response() *http.Response { + return r.r.Response() +} + +// NewHTTPHeaders returns the user-modifiable properties for this blob. +func (r DownloadResponse) NewHTTPHeaders() BlobHTTPHeaders { + return r.r.NewHTTPHeaders() +} + +// BlobContentMD5 returns the value for header x-ms-blob-content-md5. +func (r DownloadResponse) BlobContentMD5() []byte { + return r.r.BlobContentMD5() +} + +// ContentMD5 returns the value for header Content-MD5. +func (r DownloadResponse) ContentMD5() []byte { + return r.r.ContentMD5() +} + +// StatusCode returns the HTTP status code of the response, e.g. 200. +func (r DownloadResponse) StatusCode() int { + return r.r.StatusCode() +} + +// Status returns the HTTP status message of the response, e.g. "200 OK". +func (r DownloadResponse) Status() string { + return r.r.Status() +} + +// AcceptRanges returns the value for header Accept-Ranges. +func (r DownloadResponse) AcceptRanges() string { + return r.r.AcceptRanges() +} + +// BlobCommittedBlockCount returns the value for header x-ms-blob-committed-block-count. +func (r DownloadResponse) BlobCommittedBlockCount() int32 { + return r.r.BlobCommittedBlockCount() +} + +// BlobSequenceNumber returns the value for header x-ms-blob-sequence-number. +func (r DownloadResponse) BlobSequenceNumber() int64 { + return r.r.BlobSequenceNumber() +} + +// BlobType returns the value for header x-ms-blob-type. +func (r DownloadResponse) BlobType() BlobType { + return r.r.BlobType() +} + +// CacheControl returns the value for header Cache-Control. +func (r DownloadResponse) CacheControl() string { + return r.r.CacheControl() +} + +// ContentDisposition returns the value for header Content-Disposition. +func (r DownloadResponse) ContentDisposition() string { + return r.r.ContentDisposition() +} + +// ContentEncoding returns the value for header Content-Encoding. +func (r DownloadResponse) ContentEncoding() string { + return r.r.ContentEncoding() +} + +// ContentLanguage returns the value for header Content-Language. +func (r DownloadResponse) ContentLanguage() string { + return r.r.ContentLanguage() +} + +// ContentLength returns the value for header Content-Length. +func (r DownloadResponse) ContentLength() int64 { + return r.r.ContentLength() +} + +// ContentRange returns the value for header Content-Range. +func (r DownloadResponse) ContentRange() string { + return r.r.ContentRange() +} + +// ContentType returns the value for header Content-Type. +func (r DownloadResponse) ContentType() string { + return r.r.ContentType() +} + +// CopyCompletionTime returns the value for header x-ms-copy-completion-time. +func (r DownloadResponse) CopyCompletionTime() time.Time { + return r.r.CopyCompletionTime() +} + +// CopyID returns the value for header x-ms-copy-id. +func (r DownloadResponse) CopyID() string { + return r.r.CopyID() +} + +// CopyProgress returns the value for header x-ms-copy-progress. +func (r DownloadResponse) CopyProgress() string { + return r.r.CopyProgress() +} + +// CopySource returns the value for header x-ms-copy-source. +func (r DownloadResponse) CopySource() string { + return r.r.CopySource() +} + +// CopyStatus returns the value for header x-ms-copy-status. +func (r DownloadResponse) CopyStatus() CopyStatusType { + return r.r.CopyStatus() +} + +// CopyStatusDescription returns the value for header x-ms-copy-status-description. +func (r DownloadResponse) CopyStatusDescription() string { + return r.r.CopyStatusDescription() +} + +// Date returns the value for header Date. +func (r DownloadResponse) Date() time.Time { + return r.r.Date() +} + +// ETag returns the value for header ETag. +func (r DownloadResponse) ETag() ETag { + return r.r.ETag() +} + +// IsServerEncrypted returns the value for header x-ms-server-encrypted. +func (r DownloadResponse) IsServerEncrypted() string { + return r.r.IsServerEncrypted() +} + +// LastModified returns the value for header Last-Modified. +func (r DownloadResponse) LastModified() time.Time { + return r.r.LastModified() +} + +// LeaseDuration returns the value for header x-ms-lease-duration. +func (r DownloadResponse) LeaseDuration() LeaseDurationType { + return r.r.LeaseDuration() +} + +// LeaseState returns the value for header x-ms-lease-state. +func (r DownloadResponse) LeaseState() LeaseStateType { + return r.r.LeaseState() +} + +// LeaseStatus returns the value for header x-ms-lease-status. +func (r DownloadResponse) LeaseStatus() LeaseStatusType { + return r.r.LeaseStatus() +} + +// RequestID returns the value for header x-ms-request-id. +func (r DownloadResponse) RequestID() string { + return r.r.RequestID() +} + +// Version returns the value for header x-ms-version. +func (r DownloadResponse) Version() string { + return r.r.Version() +} + +// NewMetadata returns user-defined key/value pairs. +func (r DownloadResponse) NewMetadata() Metadata { + return r.r.NewMetadata() +} diff --git a/vendor/github.com/Azure/azure-storage-blob-go/LICENSE b/vendor/github.com/Azure/azure-storage-blob-go/LICENSE new file mode 100644 index 0000000000..d1ca00f20a --- /dev/null +++ b/vendor/github.com/Azure/azure-storage-blob-go/LICENSE @@ -0,0 +1,21 @@ + MIT License + + Copyright (c) Microsoft Corporation. All rights reserved. + + 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 \ No newline at end of file diff --git a/vendor/github.com/Azure/azure-storage-go/README.md b/vendor/github.com/Azure/azure-storage-go/README.md deleted file mode 100644 index f4af7bf399..0000000000 --- a/vendor/github.com/Azure/azure-storage-go/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Azure Storage SDK for Go -[![GoDoc](https://godoc.org/github.com/Azure/azure-storage-go?status.svg)](https://godoc.org/github.com/Azure/azure-storage-go) [![Build Status](https://travis-ci.org/Azure/azure-storage-go.svg?branch=master)](https://travis-ci.org/Azure/azure-storage-go) [![Go Report Card](https://goreportcard.com/badge/github.com/Azure/azure-storage-go)](https://goreportcard.com/report/github.com/Azure/azure-storage-go) - -The `github.com/Azure/azure-sdk-for-go/storage` package is used to perform operations in Azure Storage Service. To manage your storage accounts (Azure Resource Manager / ARM), use the [github.com/Azure/azure-sdk-for-go/arm/storage](../arm/storage) package. For your classic storage accounts (Azure Service Management / ASM), use [github.com/Azure/azure-sdk-for-go/management/storageservice](../management/storageservice) package. - -This package includes support for [Azure Storage Emulator](https://azure.microsoft.com/documentation/articles/storage-use-emulator/) - -# Contributing - -This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. diff --git a/vendor/github.com/Azure/azure-storage-go/authorization.go b/vendor/github.com/Azure/azure-storage-go/authorization.go deleted file mode 100644 index 89a0d0b3cd..0000000000 --- a/vendor/github.com/Azure/azure-storage-go/authorization.go +++ /dev/null @@ -1,223 +0,0 @@ -// Package storage provides clients for Microsoft Azure Storage Services. -package storage - -import ( - "bytes" - "fmt" - "net/url" - "sort" - "strings" -) - -// See: https://docs.microsoft.com/rest/api/storageservices/fileservices/authentication-for-the-azure-storage-services - -type authentication string - -const ( - sharedKey authentication = "sharedKey" - sharedKeyForTable authentication = "sharedKeyTable" - sharedKeyLite authentication = "sharedKeyLite" - sharedKeyLiteForTable authentication = "sharedKeyLiteTable" - - // headers - headerAuthorization = "Authorization" - headerContentLength = "Content-Length" - headerDate = "Date" - headerXmsDate = "x-ms-date" - headerXmsVersion = "x-ms-version" - headerContentEncoding = "Content-Encoding" - headerContentLanguage = "Content-Language" - headerContentType = "Content-Type" - headerContentMD5 = "Content-MD5" - headerIfModifiedSince = "If-Modified-Since" - headerIfMatch = "If-Match" - headerIfNoneMatch = "If-None-Match" - headerIfUnmodifiedSince = "If-Unmodified-Since" - headerRange = "Range" -) - -func (c *Client) addAuthorizationHeader(verb, url string, headers map[string]string, auth authentication) (map[string]string, error) { - authHeader, err := c.getSharedKey(verb, url, headers, auth) - if err != nil { - return nil, err - } - headers[headerAuthorization] = authHeader - return headers, nil -} - -func (c *Client) getSharedKey(verb, url string, headers map[string]string, auth authentication) (string, error) { - canRes, err := c.buildCanonicalizedResource(url, auth) - if err != nil { - return "", err - } - - canString, err := buildCanonicalizedString(verb, headers, canRes, auth) - if err != nil { - return "", err - } - return c.createAuthorizationHeader(canString, auth), nil -} - -func (c *Client) buildCanonicalizedResource(uri string, auth authentication) (string, error) { - errMsg := "buildCanonicalizedResource error: %s" - u, err := url.Parse(uri) - if err != nil { - return "", fmt.Errorf(errMsg, err.Error()) - } - - cr := bytes.NewBufferString("/") - cr.WriteString(c.getCanonicalizedAccountName()) - - if len(u.Path) > 0 { - // Any portion of the CanonicalizedResource string that is derived from - // the resource's URI should be encoded exactly as it is in the URI. - // -- https://msdn.microsoft.com/en-gb/library/azure/dd179428.aspx - cr.WriteString(u.EscapedPath()) - } - - params, err := url.ParseQuery(u.RawQuery) - if err != nil { - return "", fmt.Errorf(errMsg, err.Error()) - } - - // See https://github.com/Azure/azure-storage-net/blob/master/Lib/Common/Core/Util/AuthenticationUtility.cs#L277 - if auth == sharedKey { - if len(params) > 0 { - cr.WriteString("\n") - - keys := []string{} - for key := range params { - keys = append(keys, key) - } - sort.Strings(keys) - - completeParams := []string{} - for _, key := range keys { - if len(params[key]) > 1 { - sort.Strings(params[key]) - } - - completeParams = append(completeParams, fmt.Sprintf("%s:%s", key, strings.Join(params[key], ","))) - } - cr.WriteString(strings.Join(completeParams, "\n")) - } - } else { - // search for "comp" parameter, if exists then add it to canonicalizedresource - if v, ok := params["comp"]; ok { - cr.WriteString("?comp=" + v[0]) - } - } - - return string(cr.Bytes()), nil -} - -func (c *Client) getCanonicalizedAccountName() string { - // since we may be trying to access a secondary storage account, we need to - // remove the -secondary part of the storage name - return strings.TrimSuffix(c.accountName, "-secondary") -} - -func buildCanonicalizedString(verb string, headers map[string]string, canonicalizedResource string, auth authentication) (string, error) { - contentLength := headers[headerContentLength] - if contentLength == "0" { - contentLength = "" - } - date := headers[headerDate] - if v, ok := headers[headerXmsDate]; ok { - if auth == sharedKey || auth == sharedKeyLite { - date = "" - } else { - date = v - } - } - var canString string - switch auth { - case sharedKey: - canString = strings.Join([]string{ - verb, - headers[headerContentEncoding], - headers[headerContentLanguage], - contentLength, - headers[headerContentMD5], - headers[headerContentType], - date, - headers[headerIfModifiedSince], - headers[headerIfMatch], - headers[headerIfNoneMatch], - headers[headerIfUnmodifiedSince], - headers[headerRange], - buildCanonicalizedHeader(headers), - canonicalizedResource, - }, "\n") - case sharedKeyForTable: - canString = strings.Join([]string{ - verb, - headers[headerContentMD5], - headers[headerContentType], - date, - canonicalizedResource, - }, "\n") - case sharedKeyLite: - canString = strings.Join([]string{ - verb, - headers[headerContentMD5], - headers[headerContentType], - date, - buildCanonicalizedHeader(headers), - canonicalizedResource, - }, "\n") - case sharedKeyLiteForTable: - canString = strings.Join([]string{ - date, - canonicalizedResource, - }, "\n") - default: - return "", fmt.Errorf("%s authentication is not supported yet", auth) - } - return canString, nil -} - -func buildCanonicalizedHeader(headers map[string]string) string { - cm := make(map[string]string) - - for k, v := range headers { - headerName := strings.TrimSpace(strings.ToLower(k)) - if strings.HasPrefix(headerName, "x-ms-") { - cm[headerName] = v - } - } - - if len(cm) == 0 { - return "" - } - - keys := []string{} - for key := range cm { - keys = append(keys, key) - } - - sort.Strings(keys) - - ch := bytes.NewBufferString("") - - for _, key := range keys { - ch.WriteString(key) - ch.WriteRune(':') - ch.WriteString(cm[key]) - ch.WriteRune('\n') - } - - return strings.TrimSuffix(string(ch.Bytes()), "\n") -} - -func (c *Client) createAuthorizationHeader(canonicalizedString string, auth authentication) string { - signature := c.computeHmac256(canonicalizedString) - var key string - switch auth { - case sharedKey, sharedKeyForTable: - key = "SharedKey" - case sharedKeyLite, sharedKeyLiteForTable: - key = "SharedKeyLite" - } - return fmt.Sprintf("%s %s:%s", key, c.getCanonicalizedAccountName(), signature) -} diff --git a/vendor/github.com/Azure/azure-storage-go/blob.go b/vendor/github.com/Azure/azure-storage-go/blob.go deleted file mode 100644 index 636efc662d..0000000000 --- a/vendor/github.com/Azure/azure-storage-go/blob.go +++ /dev/null @@ -1,1130 +0,0 @@ -package storage - -import ( - "bytes" - "encoding/xml" - "errors" - "fmt" - "io" - "net/http" - "net/url" - "strconv" - "strings" - "time" -) - -// A Blob is an entry in BlobListResponse. -type Blob struct { - Name string `xml:"Name"` - Properties BlobProperties `xml:"Properties"` - Metadata BlobMetadata `xml:"Metadata"` -} - -// BlobMetadata is a set of custom name/value pairs. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd179404.aspx -type BlobMetadata map[string]string - -type blobMetadataEntries struct { - Entries []blobMetadataEntry `xml:",any"` -} -type blobMetadataEntry struct { - XMLName xml.Name - Value string `xml:",chardata"` -} - -// UnmarshalXML converts the xml:Metadata into Metadata map -func (bm *BlobMetadata) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { - var entries blobMetadataEntries - if err := d.DecodeElement(&entries, &start); err != nil { - return err - } - for _, entry := range entries.Entries { - if *bm == nil { - *bm = make(BlobMetadata) - } - (*bm)[strings.ToLower(entry.XMLName.Local)] = entry.Value - } - return nil -} - -// MarshalXML implements the xml.Marshaler interface. It encodes -// metadata name/value pairs as they would appear in an Azure -// ListBlobs response. -func (bm BlobMetadata) MarshalXML(enc *xml.Encoder, start xml.StartElement) error { - entries := make([]blobMetadataEntry, 0, len(bm)) - for k, v := range bm { - entries = append(entries, blobMetadataEntry{ - XMLName: xml.Name{Local: http.CanonicalHeaderKey(k)}, - Value: v, - }) - } - return enc.EncodeElement(blobMetadataEntries{ - Entries: entries, - }, start) -} - -// BlobProperties contains various properties of a blob -// returned in various endpoints like ListBlobs or GetBlobProperties. -type BlobProperties struct { - LastModified string `xml:"Last-Modified"` - Etag string `xml:"Etag"` - ContentMD5 string `xml:"Content-MD5"` - ContentLength int64 `xml:"Content-Length"` - ContentType string `xml:"Content-Type"` - ContentEncoding string `xml:"Content-Encoding"` - CacheControl string `xml:"Cache-Control"` - ContentLanguage string `xml:"Cache-Language"` - BlobType BlobType `xml:"x-ms-blob-blob-type"` - SequenceNumber int64 `xml:"x-ms-blob-sequence-number"` - CopyID string `xml:"CopyId"` - CopyStatus string `xml:"CopyStatus"` - CopySource string `xml:"CopySource"` - CopyProgress string `xml:"CopyProgress"` - CopyCompletionTime string `xml:"CopyCompletionTime"` - CopyStatusDescription string `xml:"CopyStatusDescription"` - LeaseStatus string `xml:"LeaseStatus"` - LeaseState string `xml:"LeaseState"` -} - -// BlobHeaders contains various properties of a blob and is an entry -// in SetBlobProperties -type BlobHeaders struct { - ContentMD5 string `header:"x-ms-blob-content-md5"` - ContentLanguage string `header:"x-ms-blob-content-language"` - ContentEncoding string `header:"x-ms-blob-content-encoding"` - ContentType string `header:"x-ms-blob-content-type"` - CacheControl string `header:"x-ms-blob-cache-control"` -} - -// BlobType defines the type of the Azure Blob. -type BlobType string - -// Types of page blobs -const ( - BlobTypeBlock BlobType = "BlockBlob" - BlobTypePage BlobType = "PageBlob" - BlobTypeAppend BlobType = "AppendBlob" -) - -// PageWriteType defines the type updates that are going to be -// done on the page blob. -type PageWriteType string - -// Types of operations on page blobs -const ( - PageWriteTypeUpdate PageWriteType = "update" - PageWriteTypeClear PageWriteType = "clear" -) - -const ( - blobCopyStatusPending = "pending" - blobCopyStatusSuccess = "success" - blobCopyStatusAborted = "aborted" - blobCopyStatusFailed = "failed" -) - -// lease constants. -const ( - leaseHeaderPrefix = "x-ms-lease-" - headerLeaseID = "x-ms-lease-id" - leaseAction = "x-ms-lease-action" - leaseBreakPeriod = "x-ms-lease-break-period" - leaseDuration = "x-ms-lease-duration" - leaseProposedID = "x-ms-proposed-lease-id" - leaseTime = "x-ms-lease-time" - - acquireLease = "acquire" - renewLease = "renew" - changeLease = "change" - releaseLease = "release" - breakLease = "break" -) - -// BlockListType is used to filter out types of blocks in a Get Blocks List call -// for a block blob. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd179400.aspx for all -// block types. -type BlockListType string - -// Filters for listing blocks in block blobs -const ( - BlockListTypeAll BlockListType = "all" - BlockListTypeCommitted BlockListType = "committed" - BlockListTypeUncommitted BlockListType = "uncommitted" -) - -// Maximum sizes (per REST API) for various concepts -const ( - MaxBlobBlockSize = 100 * 1024 * 1024 - MaxBlobPageSize = 4 * 1024 * 1024 -) - -// BlockStatus defines states a block for a block blob can -// be in. -type BlockStatus string - -// List of statuses that can be used to refer to a block in a block list -const ( - BlockStatusUncommitted BlockStatus = "Uncommitted" - BlockStatusCommitted BlockStatus = "Committed" - BlockStatusLatest BlockStatus = "Latest" -) - -// Block is used to create Block entities for Put Block List -// call. -type Block struct { - ID string - Status BlockStatus -} - -// BlockListResponse contains the response fields from Get Block List call. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd179400.aspx -type BlockListResponse struct { - XMLName xml.Name `xml:"BlockList"` - CommittedBlocks []BlockResponse `xml:"CommittedBlocks>Block"` - UncommittedBlocks []BlockResponse `xml:"UncommittedBlocks>Block"` -} - -// BlockResponse contains the block information returned -// in the GetBlockListCall. -type BlockResponse struct { - Name string `xml:"Name"` - Size int64 `xml:"Size"` -} - -// GetPageRangesResponse contains the response fields from -// Get Page Ranges call. -// -// See https://msdn.microsoft.com/en-us/library/azure/ee691973.aspx -type GetPageRangesResponse struct { - XMLName xml.Name `xml:"PageList"` - PageList []PageRange `xml:"PageRange"` -} - -// PageRange contains information about a page of a page blob from -// Get Pages Range call. -// -// See https://msdn.microsoft.com/en-us/library/azure/ee691973.aspx -type PageRange struct { - Start int64 `xml:"Start"` - End int64 `xml:"End"` -} - -var ( - errBlobCopyAborted = errors.New("storage: blob copy is aborted") - errBlobCopyIDMismatch = errors.New("storage: blob copy id is a mismatch") -) - -// BlobExists returns true if a blob with given name exists on the specified -// container of the storage account. -func (b BlobStorageClient) BlobExists(container, name string) (bool, error) { - uri := b.client.getEndpoint(blobServiceName, pathForBlob(container, name), url.Values{}) - headers := b.client.getStandardHeaders() - resp, err := b.client.exec(http.MethodHead, uri, headers, nil, b.auth) - if resp != nil { - defer readAndCloseBody(resp.body) - if resp.statusCode == http.StatusOK || resp.statusCode == http.StatusNotFound { - return resp.statusCode == http.StatusOK, nil - } - } - return false, err -} - -// GetBlobURL gets the canonical URL to the blob with the specified name in the -// specified container. If name is not specified, the canonical URL for the entire -// container is obtained. -// This method does not create a publicly accessible URL if the blob or container -// is private and this method does not check if the blob exists. -func (b BlobStorageClient) GetBlobURL(container, name string) string { - if container == "" { - container = "$root" - } - return b.client.getEndpoint(blobServiceName, pathForResource(container, name), url.Values{}) -} - -// GetBlob returns a stream to read the blob. Caller must call Close() the -// reader to close on the underlying connection. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd179440.aspx -func (b BlobStorageClient) GetBlob(container, name string) (io.ReadCloser, error) { - resp, err := b.getBlobRange(container, name, "", nil) - if err != nil { - return nil, err - } - - if err := checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil { - return nil, err - } - return resp.body, nil -} - -// GetBlobRange reads the specified range of a blob to a stream. The bytesRange -// string must be in a format like "0-", "10-100" as defined in HTTP 1.1 spec. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd179440.aspx -func (b BlobStorageClient) GetBlobRange(container, name, bytesRange string, extraHeaders map[string]string) (io.ReadCloser, error) { - resp, err := b.getBlobRange(container, name, bytesRange, extraHeaders) - if err != nil { - return nil, err - } - - if err := checkRespCode(resp.statusCode, []int{http.StatusPartialContent}); err != nil { - return nil, err - } - return resp.body, nil -} - -func (b BlobStorageClient) getBlobRange(container, name, bytesRange string, extraHeaders map[string]string) (*storageResponse, error) { - uri := b.client.getEndpoint(blobServiceName, pathForBlob(container, name), url.Values{}) - - extraHeaders = b.client.protectUserAgent(extraHeaders) - headers := b.client.getStandardHeaders() - if bytesRange != "" { - headers["Range"] = fmt.Sprintf("bytes=%s", bytesRange) - } - - for k, v := range extraHeaders { - headers[k] = v - } - - resp, err := b.client.exec(http.MethodGet, uri, headers, nil, b.auth) - if err != nil { - return nil, err - } - return resp, err -} - -// leasePut is common PUT code for the various acquire/release/break etc functions. -func (b BlobStorageClient) leaseCommonPut(container string, name string, headers map[string]string, expectedStatus int) (http.Header, error) { - params := url.Values{"comp": {"lease"}} - uri := b.client.getEndpoint(blobServiceName, pathForBlob(container, name), params) - - resp, err := b.client.exec(http.MethodPut, uri, headers, nil, b.auth) - if err != nil { - return nil, err - } - defer readAndCloseBody(resp.body) - - if err := checkRespCode(resp.statusCode, []int{expectedStatus}); err != nil { - return nil, err - } - - return resp.headers, nil -} - -// SnapshotBlob creates a snapshot for a blob as per https://msdn.microsoft.com/en-us/library/azure/ee691971.aspx -func (b BlobStorageClient) SnapshotBlob(container string, name string, timeout int, extraHeaders map[string]string) (snapshotTimestamp *time.Time, err error) { - extraHeaders = b.client.protectUserAgent(extraHeaders) - headers := b.client.getStandardHeaders() - params := url.Values{"comp": {"snapshot"}} - - if timeout > 0 { - params.Add("timeout", strconv.Itoa(timeout)) - } - - for k, v := range extraHeaders { - headers[k] = v - } - - uri := b.client.getEndpoint(blobServiceName, pathForBlob(container, name), params) - resp, err := b.client.exec(http.MethodPut, uri, headers, nil, b.auth) - if err != nil || resp == nil { - return nil, err - } - - defer readAndCloseBody(resp.body) - - if err := checkRespCode(resp.statusCode, []int{http.StatusCreated}); err != nil { - return nil, err - } - - snapshotResponse := resp.headers.Get(http.CanonicalHeaderKey("x-ms-snapshot")) - if snapshotResponse != "" { - snapshotTimestamp, err := time.Parse(time.RFC3339, snapshotResponse) - if err != nil { - return nil, err - } - - return &snapshotTimestamp, nil - } - - return nil, errors.New("Snapshot not created") -} - -// AcquireLease creates a lease for a blob as per https://msdn.microsoft.com/en-us/library/azure/ee691972.aspx -// returns leaseID acquired -// In API Versions starting on 2012-02-12, the minimum leaseTimeInSeconds is 15, the maximum -// non-infinite leaseTimeInSeconds is 60. To specify an infinite lease, provide the value -1. -func (b BlobStorageClient) AcquireLease(container string, name string, leaseTimeInSeconds int, proposedLeaseID string) (returnedLeaseID string, err error) { - headers := b.client.getStandardHeaders() - headers[leaseAction] = acquireLease - - if leaseTimeInSeconds == -1 { - // Do nothing, but don't trigger the following clauses. - } else if leaseTimeInSeconds > 60 || b.client.apiVersion < "2012-02-12" { - leaseTimeInSeconds = 60 - } else if leaseTimeInSeconds < 15 { - leaseTimeInSeconds = 15 - } - - headers[leaseDuration] = strconv.Itoa(leaseTimeInSeconds) - - if proposedLeaseID != "" { - headers[leaseProposedID] = proposedLeaseID - } - - respHeaders, err := b.leaseCommonPut(container, name, headers, http.StatusCreated) - if err != nil { - return "", err - } - - returnedLeaseID = respHeaders.Get(http.CanonicalHeaderKey(headerLeaseID)) - - if returnedLeaseID != "" { - return returnedLeaseID, nil - } - - return "", errors.New("LeaseID not returned") -} - -// BreakLease breaks the lease for a blob as per https://msdn.microsoft.com/en-us/library/azure/ee691972.aspx -// Returns the timeout remaining in the lease in seconds -func (b BlobStorageClient) BreakLease(container string, name string) (breakTimeout int, err error) { - headers := b.client.getStandardHeaders() - headers[leaseAction] = breakLease - return b.breakLeaseCommon(container, name, headers) -} - -// BreakLeaseWithBreakPeriod breaks the lease for a blob as per https://msdn.microsoft.com/en-us/library/azure/ee691972.aspx -// breakPeriodInSeconds is used to determine how long until new lease can be created. -// Returns the timeout remaining in the lease in seconds -func (b BlobStorageClient) BreakLeaseWithBreakPeriod(container string, name string, breakPeriodInSeconds int) (breakTimeout int, err error) { - headers := b.client.getStandardHeaders() - headers[leaseAction] = breakLease - headers[leaseBreakPeriod] = strconv.Itoa(breakPeriodInSeconds) - return b.breakLeaseCommon(container, name, headers) -} - -// breakLeaseCommon is common code for both version of BreakLease (with and without break period) -func (b BlobStorageClient) breakLeaseCommon(container string, name string, headers map[string]string) (breakTimeout int, err error) { - - respHeaders, err := b.leaseCommonPut(container, name, headers, http.StatusAccepted) - if err != nil { - return 0, err - } - - breakTimeoutStr := respHeaders.Get(http.CanonicalHeaderKey(leaseTime)) - if breakTimeoutStr != "" { - breakTimeout, err = strconv.Atoi(breakTimeoutStr) - if err != nil { - return 0, err - } - } - - return breakTimeout, nil -} - -// ChangeLease changes a lease ID for a blob as per https://msdn.microsoft.com/en-us/library/azure/ee691972.aspx -// Returns the new LeaseID acquired -func (b BlobStorageClient) ChangeLease(container string, name string, currentLeaseID string, proposedLeaseID string) (newLeaseID string, err error) { - headers := b.client.getStandardHeaders() - headers[leaseAction] = changeLease - headers[headerLeaseID] = currentLeaseID - headers[leaseProposedID] = proposedLeaseID - - respHeaders, err := b.leaseCommonPut(container, name, headers, http.StatusOK) - if err != nil { - return "", err - } - - newLeaseID = respHeaders.Get(http.CanonicalHeaderKey(headerLeaseID)) - if newLeaseID != "" { - return newLeaseID, nil - } - - return "", errors.New("LeaseID not returned") -} - -// ReleaseLease releases the lease for a blob as per https://msdn.microsoft.com/en-us/library/azure/ee691972.aspx -func (b BlobStorageClient) ReleaseLease(container string, name string, currentLeaseID string) error { - headers := b.client.getStandardHeaders() - headers[leaseAction] = releaseLease - headers[headerLeaseID] = currentLeaseID - - _, err := b.leaseCommonPut(container, name, headers, http.StatusOK) - if err != nil { - return err - } - - return nil -} - -// RenewLease renews the lease for a blob as per https://msdn.microsoft.com/en-us/library/azure/ee691972.aspx -func (b BlobStorageClient) RenewLease(container string, name string, currentLeaseID string) error { - headers := b.client.getStandardHeaders() - headers[leaseAction] = renewLease - headers[headerLeaseID] = currentLeaseID - - _, err := b.leaseCommonPut(container, name, headers, http.StatusOK) - if err != nil { - return err - } - - return nil -} - -// GetBlobProperties provides various information about the specified -// blob. See https://msdn.microsoft.com/en-us/library/azure/dd179394.aspx -func (b BlobStorageClient) GetBlobProperties(container, name string) (*BlobProperties, error) { - uri := b.client.getEndpoint(blobServiceName, pathForBlob(container, name), url.Values{}) - - headers := b.client.getStandardHeaders() - resp, err := b.client.exec(http.MethodHead, uri, headers, nil, b.auth) - if err != nil { - return nil, err - } - defer readAndCloseBody(resp.body) - - if err = checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil { - return nil, err - } - - var contentLength int64 - contentLengthStr := resp.headers.Get("Content-Length") - if contentLengthStr != "" { - contentLength, err = strconv.ParseInt(contentLengthStr, 0, 64) - if err != nil { - return nil, err - } - } - - var sequenceNum int64 - sequenceNumStr := resp.headers.Get("x-ms-blob-sequence-number") - if sequenceNumStr != "" { - sequenceNum, err = strconv.ParseInt(sequenceNumStr, 0, 64) - if err != nil { - return nil, err - } - } - - return &BlobProperties{ - LastModified: resp.headers.Get("Last-Modified"), - Etag: resp.headers.Get("Etag"), - ContentMD5: resp.headers.Get("Content-MD5"), - ContentLength: contentLength, - ContentEncoding: resp.headers.Get("Content-Encoding"), - ContentType: resp.headers.Get("Content-Type"), - CacheControl: resp.headers.Get("Cache-Control"), - ContentLanguage: resp.headers.Get("Content-Language"), - SequenceNumber: sequenceNum, - CopyCompletionTime: resp.headers.Get("x-ms-copy-completion-time"), - CopyStatusDescription: resp.headers.Get("x-ms-copy-status-description"), - CopyID: resp.headers.Get("x-ms-copy-id"), - CopyProgress: resp.headers.Get("x-ms-copy-progress"), - CopySource: resp.headers.Get("x-ms-copy-source"), - CopyStatus: resp.headers.Get("x-ms-copy-status"), - BlobType: BlobType(resp.headers.Get("x-ms-blob-type")), - LeaseStatus: resp.headers.Get("x-ms-lease-status"), - LeaseState: resp.headers.Get("x-ms-lease-state"), - }, nil -} - -// SetBlobProperties replaces the BlobHeaders for the specified blob. -// -// Some keys may be converted to Camel-Case before sending. All keys -// are returned in lower case by GetBlobProperties. HTTP header names -// are case-insensitive so case munging should not matter to other -// applications either. -// -// See https://msdn.microsoft.com/en-us/library/azure/ee691966.aspx -func (b BlobStorageClient) SetBlobProperties(container, name string, blobHeaders BlobHeaders) error { - params := url.Values{"comp": {"properties"}} - uri := b.client.getEndpoint(blobServiceName, pathForBlob(container, name), params) - headers := b.client.getStandardHeaders() - - extraHeaders := headersFromStruct(blobHeaders) - - for k, v := range extraHeaders { - headers[k] = v - } - - resp, err := b.client.exec(http.MethodPut, uri, headers, nil, b.auth) - if err != nil { - return err - } - defer readAndCloseBody(resp.body) - - return checkRespCode(resp.statusCode, []int{http.StatusOK}) -} - -// SetBlobMetadata replaces the metadata for the specified blob. -// -// Some keys may be converted to Camel-Case before sending. All keys -// are returned in lower case by GetBlobMetadata. HTTP header names -// are case-insensitive so case munging should not matter to other -// applications either. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd179414.aspx -func (b BlobStorageClient) SetBlobMetadata(container, name string, metadata map[string]string, extraHeaders map[string]string) error { - params := url.Values{"comp": {"metadata"}} - uri := b.client.getEndpoint(blobServiceName, pathForBlob(container, name), params) - metadata = b.client.protectUserAgent(metadata) - extraHeaders = b.client.protectUserAgent(extraHeaders) - headers := b.client.getStandardHeaders() - for k, v := range metadata { - headers[userDefinedMetadataHeaderPrefix+k] = v - } - - for k, v := range extraHeaders { - headers[k] = v - } - - resp, err := b.client.exec(http.MethodPut, uri, headers, nil, b.auth) - if err != nil { - return err - } - defer readAndCloseBody(resp.body) - - return checkRespCode(resp.statusCode, []int{http.StatusOK}) -} - -// GetBlobMetadata returns all user-defined metadata for the specified blob. -// -// All metadata keys will be returned in lower case. (HTTP header -// names are case-insensitive.) -// -// See https://msdn.microsoft.com/en-us/library/azure/dd179414.aspx -func (b BlobStorageClient) GetBlobMetadata(container, name string) (map[string]string, error) { - params := url.Values{"comp": {"metadata"}} - uri := b.client.getEndpoint(blobServiceName, pathForBlob(container, name), params) - headers := b.client.getStandardHeaders() - - resp, err := b.client.exec(http.MethodGet, uri, headers, nil, b.auth) - if err != nil { - return nil, err - } - defer readAndCloseBody(resp.body) - - if err := checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil { - return nil, err - } - - metadata := make(map[string]string) - for k, v := range resp.headers { - // Can't trust CanonicalHeaderKey() to munge case - // reliably. "_" is allowed in identifiers: - // https://msdn.microsoft.com/en-us/library/azure/dd179414.aspx - // https://msdn.microsoft.com/library/aa664670(VS.71).aspx - // http://tools.ietf.org/html/rfc7230#section-3.2 - // ...but "_" is considered invalid by - // CanonicalMIMEHeaderKey in - // https://golang.org/src/net/textproto/reader.go?s=14615:14659#L542 - // so k can be "X-Ms-Meta-Foo" or "x-ms-meta-foo_bar". - k = strings.ToLower(k) - if len(v) == 0 || !strings.HasPrefix(k, strings.ToLower(userDefinedMetadataHeaderPrefix)) { - continue - } - // metadata["foo"] = content of the last X-Ms-Meta-Foo header - k = k[len(userDefinedMetadataHeaderPrefix):] - metadata[k] = v[len(v)-1] - } - return metadata, nil -} - -// CreateBlockBlob initializes an empty block blob with no blocks. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd179451.aspx -func (b BlobStorageClient) CreateBlockBlob(container, name string) error { - return b.CreateBlockBlobFromReader(container, name, 0, nil, nil) -} - -// CreateBlockBlobFromReader initializes a block blob using data from -// reader. Size must be the number of bytes read from reader. To -// create an empty blob, use size==0 and reader==nil. -// -// The API rejects requests with size > 256 MiB (but this limit is not -// checked by the SDK). To write a larger blob, use CreateBlockBlob, -// PutBlock, and PutBlockList. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd179451.aspx -func (b BlobStorageClient) CreateBlockBlobFromReader(container, name string, size uint64, blob io.Reader, extraHeaders map[string]string) error { - path := fmt.Sprintf("%s/%s", container, name) - uri := b.client.getEndpoint(blobServiceName, path, url.Values{}) - extraHeaders = b.client.protectUserAgent(extraHeaders) - headers := b.client.getStandardHeaders() - headers["x-ms-blob-type"] = string(BlobTypeBlock) - headers["Content-Length"] = fmt.Sprintf("%d", size) - - for k, v := range extraHeaders { - headers[k] = v - } - - resp, err := b.client.exec(http.MethodPut, uri, headers, blob, b.auth) - if err != nil { - return err - } - defer readAndCloseBody(resp.body) - return checkRespCode(resp.statusCode, []int{http.StatusCreated}) -} - -// PutBlock saves the given data chunk to the specified block blob with -// given ID. -// -// The API rejects chunks larger than 100 MB (but this limit is not -// checked by the SDK). -// -// See https://msdn.microsoft.com/en-us/library/azure/dd135726.aspx -func (b BlobStorageClient) PutBlock(container, name, blockID string, chunk []byte) error { - return b.PutBlockWithLength(container, name, blockID, uint64(len(chunk)), bytes.NewReader(chunk), nil) -} - -// PutBlockWithLength saves the given data stream of exactly specified size to -// the block blob with given ID. It is an alternative to PutBlocks where data -// comes as stream but the length is known in advance. -// -// The API rejects requests with size > 100 MB (but this limit is not -// checked by the SDK). -// -// See https://msdn.microsoft.com/en-us/library/azure/dd135726.aspx -func (b BlobStorageClient) PutBlockWithLength(container, name, blockID string, size uint64, blob io.Reader, extraHeaders map[string]string) error { - uri := b.client.getEndpoint(blobServiceName, pathForBlob(container, name), url.Values{"comp": {"block"}, "blockid": {blockID}}) - extraHeaders = b.client.protectUserAgent(extraHeaders) - headers := b.client.getStandardHeaders() - headers["x-ms-blob-type"] = string(BlobTypeBlock) - headers["Content-Length"] = fmt.Sprintf("%v", size) - - for k, v := range extraHeaders { - headers[k] = v - } - - resp, err := b.client.exec(http.MethodPut, uri, headers, blob, b.auth) - if err != nil { - return err - } - - defer readAndCloseBody(resp.body) - return checkRespCode(resp.statusCode, []int{http.StatusCreated}) -} - -// PutBlockList saves list of blocks to the specified block blob. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd179467.aspx -func (b BlobStorageClient) PutBlockList(container, name string, blocks []Block) error { - blockListXML := prepareBlockListRequest(blocks) - - uri := b.client.getEndpoint(blobServiceName, pathForBlob(container, name), url.Values{"comp": {"blocklist"}}) - headers := b.client.getStandardHeaders() - headers["Content-Length"] = fmt.Sprintf("%v", len(blockListXML)) - - resp, err := b.client.exec(http.MethodPut, uri, headers, strings.NewReader(blockListXML), b.auth) - if err != nil { - return err - } - defer readAndCloseBody(resp.body) - return checkRespCode(resp.statusCode, []int{http.StatusCreated}) -} - -// GetBlockList retrieves list of blocks in the specified block blob. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd179400.aspx -func (b BlobStorageClient) GetBlockList(container, name string, blockType BlockListType) (BlockListResponse, error) { - params := url.Values{"comp": {"blocklist"}, "blocklisttype": {string(blockType)}} - uri := b.client.getEndpoint(blobServiceName, pathForBlob(container, name), params) - headers := b.client.getStandardHeaders() - - var out BlockListResponse - resp, err := b.client.exec(http.MethodGet, uri, headers, nil, b.auth) - if err != nil { - return out, err - } - defer resp.body.Close() - - err = xmlUnmarshal(resp.body, &out) - return out, err -} - -// PutPageBlob initializes an empty page blob with specified name and maximum -// size in bytes (size must be aligned to a 512-byte boundary). A page blob must -// be created using this method before writing pages. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd179451.aspx -func (b BlobStorageClient) PutPageBlob(container, name string, size int64, extraHeaders map[string]string) error { - path := fmt.Sprintf("%s/%s", container, name) - uri := b.client.getEndpoint(blobServiceName, path, url.Values{}) - extraHeaders = b.client.protectUserAgent(extraHeaders) - headers := b.client.getStandardHeaders() - headers["x-ms-blob-type"] = string(BlobTypePage) - headers["x-ms-blob-content-length"] = fmt.Sprintf("%v", size) - - for k, v := range extraHeaders { - headers[k] = v - } - - resp, err := b.client.exec(http.MethodPut, uri, headers, nil, b.auth) - if err != nil { - return err - } - defer readAndCloseBody(resp.body) - - return checkRespCode(resp.statusCode, []int{http.StatusCreated}) -} - -// PutPage writes a range of pages to a page blob or clears the given range. -// In case of 'clear' writes, given chunk is discarded. Ranges must be aligned -// with 512-byte boundaries and chunk must be of size multiplies by 512. -// -// See https://msdn.microsoft.com/en-us/library/ee691975.aspx -func (b BlobStorageClient) PutPage(container, name string, startByte, endByte int64, writeType PageWriteType, chunk []byte, extraHeaders map[string]string) error { - path := fmt.Sprintf("%s/%s", container, name) - uri := b.client.getEndpoint(blobServiceName, path, url.Values{"comp": {"page"}}) - extraHeaders = b.client.protectUserAgent(extraHeaders) - headers := b.client.getStandardHeaders() - headers["x-ms-blob-type"] = string(BlobTypePage) - headers["x-ms-page-write"] = string(writeType) - headers["x-ms-range"] = fmt.Sprintf("bytes=%v-%v", startByte, endByte) - for k, v := range extraHeaders { - headers[k] = v - } - var contentLength int64 - var data io.Reader - if writeType == PageWriteTypeClear { - contentLength = 0 - data = bytes.NewReader([]byte{}) - } else { - contentLength = int64(len(chunk)) - data = bytes.NewReader(chunk) - } - headers["Content-Length"] = fmt.Sprintf("%v", contentLength) - - resp, err := b.client.exec(http.MethodPut, uri, headers, data, b.auth) - if err != nil { - return err - } - defer readAndCloseBody(resp.body) - - return checkRespCode(resp.statusCode, []int{http.StatusCreated}) -} - -// GetPageRanges returns the list of valid page ranges for a page blob. -// -// See https://msdn.microsoft.com/en-us/library/azure/ee691973.aspx -func (b BlobStorageClient) GetPageRanges(container, name string) (GetPageRangesResponse, error) { - path := fmt.Sprintf("%s/%s", container, name) - uri := b.client.getEndpoint(blobServiceName, path, url.Values{"comp": {"pagelist"}}) - headers := b.client.getStandardHeaders() - - var out GetPageRangesResponse - resp, err := b.client.exec(http.MethodGet, uri, headers, nil, b.auth) - if err != nil { - return out, err - } - defer resp.body.Close() - - if err = checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil { - return out, err - } - err = xmlUnmarshal(resp.body, &out) - return out, err -} - -// PutAppendBlob initializes an empty append blob with specified name. An -// append blob must be created using this method before appending blocks. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd179451.aspx -func (b BlobStorageClient) PutAppendBlob(container, name string, extraHeaders map[string]string) error { - path := fmt.Sprintf("%s/%s", container, name) - uri := b.client.getEndpoint(blobServiceName, path, url.Values{}) - extraHeaders = b.client.protectUserAgent(extraHeaders) - headers := b.client.getStandardHeaders() - headers["x-ms-blob-type"] = string(BlobTypeAppend) - - for k, v := range extraHeaders { - headers[k] = v - } - - resp, err := b.client.exec(http.MethodPut, uri, headers, nil, b.auth) - if err != nil { - return err - } - defer readAndCloseBody(resp.body) - - return checkRespCode(resp.statusCode, []int{http.StatusCreated}) -} - -// AppendBlock appends a block to an append blob. -// -// See https://msdn.microsoft.com/en-us/library/azure/mt427365.aspx -func (b BlobStorageClient) AppendBlock(container, name string, chunk []byte, extraHeaders map[string]string) error { - path := fmt.Sprintf("%s/%s", container, name) - uri := b.client.getEndpoint(blobServiceName, path, url.Values{"comp": {"appendblock"}}) - extraHeaders = b.client.protectUserAgent(extraHeaders) - headers := b.client.getStandardHeaders() - headers["x-ms-blob-type"] = string(BlobTypeAppend) - headers["Content-Length"] = fmt.Sprintf("%v", len(chunk)) - - for k, v := range extraHeaders { - headers[k] = v - } - - resp, err := b.client.exec(http.MethodPut, uri, headers, bytes.NewReader(chunk), b.auth) - if err != nil { - return err - } - defer readAndCloseBody(resp.body) - - return checkRespCode(resp.statusCode, []int{http.StatusCreated}) -} - -// CopyBlob starts a blob copy operation and waits for the operation to -// complete. sourceBlob parameter must be a canonical URL to the blob (can be -// obtained using GetBlobURL method.) There is no SLA on blob copy and therefore -// this helper method works faster on smaller files. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd894037.aspx -func (b BlobStorageClient) CopyBlob(container, name, sourceBlob string) error { - copyID, err := b.StartBlobCopy(container, name, sourceBlob) - if err != nil { - return err - } - - return b.WaitForBlobCopy(container, name, copyID) -} - -// StartBlobCopy starts a blob copy operation. -// sourceBlob parameter must be a canonical URL to the blob (can be -// obtained using GetBlobURL method.) -// -// See https://msdn.microsoft.com/en-us/library/azure/dd894037.aspx -func (b BlobStorageClient) StartBlobCopy(container, name, sourceBlob string) (string, error) { - uri := b.client.getEndpoint(blobServiceName, pathForBlob(container, name), url.Values{}) - - headers := b.client.getStandardHeaders() - headers["x-ms-copy-source"] = sourceBlob - - resp, err := b.client.exec(http.MethodPut, uri, headers, nil, b.auth) - if err != nil { - return "", err - } - defer readAndCloseBody(resp.body) - - if err := checkRespCode(resp.statusCode, []int{http.StatusAccepted, http.StatusCreated}); err != nil { - return "", err - } - - copyID := resp.headers.Get("x-ms-copy-id") - if copyID == "" { - return "", errors.New("Got empty copy id header") - } - return copyID, nil -} - -// AbortBlobCopy aborts a BlobCopy which has already been triggered by the StartBlobCopy function. -// copyID is generated from StartBlobCopy function. -// currentLeaseID is required IF the destination blob has an active lease on it. -// As defined in https://msdn.microsoft.com/en-us/library/azure/jj159098.aspx -func (b BlobStorageClient) AbortBlobCopy(container, name, copyID, currentLeaseID string, timeout int) error { - params := url.Values{"comp": {"copy"}, "copyid": {copyID}} - if timeout > 0 { - params.Add("timeout", strconv.Itoa(timeout)) - } - - uri := b.client.getEndpoint(blobServiceName, pathForBlob(container, name), params) - headers := b.client.getStandardHeaders() - headers["x-ms-copy-action"] = "abort" - - if currentLeaseID != "" { - headers[headerLeaseID] = currentLeaseID - } - - resp, err := b.client.exec(http.MethodPut, uri, headers, nil, b.auth) - if err != nil { - return err - } - defer readAndCloseBody(resp.body) - - if err := checkRespCode(resp.statusCode, []int{http.StatusNoContent}); err != nil { - return err - } - - return nil -} - -// WaitForBlobCopy loops until a BlobCopy operation is completed (or fails with error) -func (b BlobStorageClient) WaitForBlobCopy(container, name, copyID string) error { - for { - props, err := b.GetBlobProperties(container, name) - if err != nil { - return err - } - - if props.CopyID != copyID { - return errBlobCopyIDMismatch - } - - switch props.CopyStatus { - case blobCopyStatusSuccess: - return nil - case blobCopyStatusPending: - continue - case blobCopyStatusAborted: - return errBlobCopyAborted - case blobCopyStatusFailed: - return fmt.Errorf("storage: blob copy failed. Id=%s Description=%s", props.CopyID, props.CopyStatusDescription) - default: - return fmt.Errorf("storage: unhandled blob copy status: '%s'", props.CopyStatus) - } - } -} - -// DeleteBlob deletes the given blob from the specified container. -// If the blob does not exists at the time of the Delete Blob operation, it -// returns error. See https://msdn.microsoft.com/en-us/library/azure/dd179413.aspx -func (b BlobStorageClient) DeleteBlob(container, name string, extraHeaders map[string]string) error { - resp, err := b.deleteBlob(container, name, extraHeaders) - if err != nil { - return err - } - defer readAndCloseBody(resp.body) - return checkRespCode(resp.statusCode, []int{http.StatusAccepted}) -} - -// DeleteBlobIfExists deletes the given blob from the specified container If the -// blob is deleted with this call, returns true. Otherwise returns false. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd179413.aspx -func (b BlobStorageClient) DeleteBlobIfExists(container, name string, extraHeaders map[string]string) (bool, error) { - resp, err := b.deleteBlob(container, name, extraHeaders) - if resp != nil { - defer readAndCloseBody(resp.body) - if resp.statusCode == http.StatusAccepted || resp.statusCode == http.StatusNotFound { - return resp.statusCode == http.StatusAccepted, nil - } - } - return false, err -} - -func (b BlobStorageClient) deleteBlob(container, name string, extraHeaders map[string]string) (*storageResponse, error) { - uri := b.client.getEndpoint(blobServiceName, pathForBlob(container, name), url.Values{}) - extraHeaders = b.client.protectUserAgent(extraHeaders) - headers := b.client.getStandardHeaders() - for k, v := range extraHeaders { - headers[k] = v - } - - return b.client.exec(http.MethodDelete, uri, headers, nil, b.auth) -} - -// helper method to construct the path to a blob given its container and blob -// name -func pathForBlob(container, name string) string { - return fmt.Sprintf("/%s/%s", container, name) -} - -// helper method to construct the path to either a blob or container -func pathForResource(container, name string) string { - if len(name) > 0 { - return fmt.Sprintf("/%s/%s", container, name) - } - return fmt.Sprintf("/%s", container) -} - -// GetBlobSASURIWithSignedIPAndProtocol creates an URL to the specified blob which contains the Shared -// Access Signature with specified permissions and expiration time. Also includes signedIPRange and allowed protocols. -// If old API version is used but no signedIP is passed (ie empty string) then this should still work. -// We only populate the signedIP when it non-empty. -// -// See https://msdn.microsoft.com/en-us/library/azure/ee395415.aspx -func (b BlobStorageClient) GetBlobSASURIWithSignedIPAndProtocol(container, name string, expiry time.Time, permissions string, signedIPRange string, HTTPSOnly bool) (string, error) { - var ( - signedPermissions = permissions - blobURL = b.GetBlobURL(container, name) - ) - canonicalizedResource, err := b.client.buildCanonicalizedResource(blobURL, b.auth) - if err != nil { - return "", err - } - - // "The canonicalizedresouce portion of the string is a canonical path to the signed resource. - // It must include the service name (blob, table, queue or file) for version 2015-02-21 or - // later, the storage account name, and the resource name, and must be URL-decoded. - // -- https://msdn.microsoft.com/en-us/library/azure/dn140255.aspx - - // We need to replace + with %2b first to avoid being treated as a space (which is correct for query strings, but not the path component). - canonicalizedResource = strings.Replace(canonicalizedResource, "+", "%2b", -1) - canonicalizedResource, err = url.QueryUnescape(canonicalizedResource) - if err != nil { - return "", err - } - - signedExpiry := expiry.UTC().Format(time.RFC3339) - - //If blob name is missing, resource is a container - signedResource := "c" - if len(name) > 0 { - signedResource = "b" - } - - protocols := "https,http" - if HTTPSOnly { - protocols = "https" - } - stringToSign, err := blobSASStringToSign(b.client.apiVersion, canonicalizedResource, signedExpiry, signedPermissions, signedIPRange, protocols) - if err != nil { - return "", err - } - - sig := b.client.computeHmac256(stringToSign) - sasParams := url.Values{ - "sv": {b.client.apiVersion}, - "se": {signedExpiry}, - "sr": {signedResource}, - "sp": {signedPermissions}, - "sig": {sig}, - } - - if b.client.apiVersion >= "2015-04-05" { - sasParams.Add("spr", protocols) - if signedIPRange != "" { - sasParams.Add("sip", signedIPRange) - } - } - - sasURL, err := url.Parse(blobURL) - if err != nil { - return "", err - } - sasURL.RawQuery = sasParams.Encode() - return sasURL.String(), nil -} - -// GetBlobSASURI creates an URL to the specified blob which contains the Shared -// Access Signature with specified permissions and expiration time. -// -// See https://msdn.microsoft.com/en-us/library/azure/ee395415.aspx -func (b BlobStorageClient) GetBlobSASURI(container, name string, expiry time.Time, permissions string) (string, error) { - url, err := b.GetBlobSASURIWithSignedIPAndProtocol(container, name, expiry, permissions, "", false) - return url, err -} - -func blobSASStringToSign(signedVersion, canonicalizedResource, signedExpiry, signedPermissions string, signedIP string, protocols string) (string, error) { - var signedStart, signedIdentifier, rscc, rscd, rsce, rscl, rsct string - - if signedVersion >= "2015-02-21" { - canonicalizedResource = "/blob" + canonicalizedResource - } - - // https://msdn.microsoft.com/en-us/library/azure/dn140255.aspx#Anchor_12 - if signedVersion >= "2015-04-05" { - return fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s", signedPermissions, signedStart, signedExpiry, canonicalizedResource, signedIdentifier, signedIP, protocols, signedVersion, rscc, rscd, rsce, rscl, rsct), nil - } - - // reference: http://msdn.microsoft.com/en-us/library/azure/dn140255.aspx - if signedVersion >= "2013-08-15" { - return fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s", signedPermissions, signedStart, signedExpiry, canonicalizedResource, signedIdentifier, signedVersion, rscc, rscd, rsce, rscl, rsct), nil - } - - return "", errors.New("storage: not implemented SAS for versions earlier than 2013-08-15") -} diff --git a/vendor/github.com/Azure/azure-storage-go/blobserviceclient.go b/vendor/github.com/Azure/azure-storage-go/blobserviceclient.go deleted file mode 100644 index e5911ac81b..0000000000 --- a/vendor/github.com/Azure/azure-storage-go/blobserviceclient.go +++ /dev/null @@ -1,92 +0,0 @@ -package storage - -import ( - "fmt" - "net/http" - "net/url" -) - -// BlobStorageClient contains operations for Microsoft Azure Blob Storage -// Service. -type BlobStorageClient struct { - client Client - auth authentication -} - -// GetServiceProperties gets the properties of your storage account's blob service. -// See: https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/get-blob-service-properties -func (b *BlobStorageClient) GetServiceProperties() (*ServiceProperties, error) { - return b.client.getServiceProperties(blobServiceName, b.auth) -} - -// SetServiceProperties sets the properties of your storage account's blob service. -// See: https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/set-blob-service-properties -func (b *BlobStorageClient) SetServiceProperties(props ServiceProperties) error { - return b.client.setServiceProperties(props, blobServiceName, b.auth) -} - -// ListContainersParameters defines the set of customizable parameters to make a -// List Containers call. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd179352.aspx -type ListContainersParameters struct { - Prefix string - Marker string - Include string - MaxResults uint - Timeout uint -} - -// GetContainerReference returns a Container object for the specified container name. -func (b BlobStorageClient) GetContainerReference(name string) Container { - return Container{ - bsc: &b, - Name: name, - } -} - -// ListContainers returns the list of containers in a storage account along with -// pagination token and other response details. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd179352.aspx -func (b BlobStorageClient) ListContainers(params ListContainersParameters) (*ContainerListResponse, error) { - q := mergeParams(params.getParameters(), url.Values{"comp": {"list"}}) - uri := b.client.getEndpoint(blobServiceName, "", q) - headers := b.client.getStandardHeaders() - - var out ContainerListResponse - resp, err := b.client.exec(http.MethodGet, uri, headers, nil, b.auth) - if err != nil { - return nil, err - } - defer resp.body.Close() - err = xmlUnmarshal(resp.body, &out) - - // assign our client to the newly created Container objects - for i := range out.Containers { - out.Containers[i].bsc = &b - } - return &out, err -} - -func (p ListContainersParameters) getParameters() url.Values { - out := url.Values{} - - if p.Prefix != "" { - out.Set("prefix", p.Prefix) - } - if p.Marker != "" { - out.Set("marker", p.Marker) - } - if p.Include != "" { - out.Set("include", p.Include) - } - if p.MaxResults != 0 { - out.Set("maxresults", fmt.Sprintf("%v", p.MaxResults)) - } - if p.Timeout != 0 { - out.Set("timeout", fmt.Sprintf("%v", p.Timeout)) - } - - return out -} diff --git a/vendor/github.com/Azure/azure-storage-go/client.go b/vendor/github.com/Azure/azure-storage-go/client.go deleted file mode 100644 index 9ddbf08aee..0000000000 --- a/vendor/github.com/Azure/azure-storage-go/client.go +++ /dev/null @@ -1,479 +0,0 @@ -// Package storage provides clients for Microsoft Azure Storage Services. -package storage - -import ( - "bytes" - "encoding/base64" - "encoding/json" - "encoding/xml" - "errors" - "fmt" - "io" - "io/ioutil" - "net/http" - "net/url" - "runtime" - "strconv" - "strings" - - "github.com/Azure/go-autorest/autorest/azure" -) - -const ( - // DefaultBaseURL is the domain name used for storage requests in the - // public cloud when a default client is created. - DefaultBaseURL = "core.windows.net" - - // DefaultAPIVersion is the Azure Storage API version string used when a - // basic client is created. - DefaultAPIVersion = "2016-05-31" - - defaultUseHTTPS = true - - // StorageEmulatorAccountName is the fixed storage account used by Azure Storage Emulator - StorageEmulatorAccountName = "devstoreaccount1" - - // StorageEmulatorAccountKey is the the fixed storage account used by Azure Storage Emulator - StorageEmulatorAccountKey = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==" - - blobServiceName = "blob" - tableServiceName = "table" - queueServiceName = "queue" - fileServiceName = "file" - - storageEmulatorBlob = "127.0.0.1:10000" - storageEmulatorTable = "127.0.0.1:10002" - storageEmulatorQueue = "127.0.0.1:10001" - - userAgentHeader = "User-Agent" -) - -// Client is the object that needs to be constructed to perform -// operations on the storage account. -type Client struct { - // HTTPClient is the http.Client used to initiate API - // requests. If it is nil, http.DefaultClient is used. - HTTPClient *http.Client - - accountName string - accountKey []byte - useHTTPS bool - UseSharedKeyLite bool - baseURL string - apiVersion string - userAgent string -} - -type storageResponse struct { - statusCode int - headers http.Header - body io.ReadCloser -} - -type odataResponse struct { - storageResponse - odata odataErrorMessage -} - -// AzureStorageServiceError contains fields of the error response from -// Azure Storage Service REST API. See https://msdn.microsoft.com/en-us/library/azure/dd179382.aspx -// Some fields might be specific to certain calls. -type AzureStorageServiceError struct { - Code string `xml:"Code"` - Message string `xml:"Message"` - AuthenticationErrorDetail string `xml:"AuthenticationErrorDetail"` - QueryParameterName string `xml:"QueryParameterName"` - QueryParameterValue string `xml:"QueryParameterValue"` - Reason string `xml:"Reason"` - StatusCode int - RequestID string -} - -type odataErrorMessageMessage struct { - Lang string `json:"lang"` - Value string `json:"value"` -} - -type odataErrorMessageInternal struct { - Code string `json:"code"` - Message odataErrorMessageMessage `json:"message"` -} - -type odataErrorMessage struct { - Err odataErrorMessageInternal `json:"odata.error"` -} - -// UnexpectedStatusCodeError is returned when a storage service responds with neither an error -// nor with an HTTP status code indicating success. -type UnexpectedStatusCodeError struct { - allowed []int - got int -} - -func (e UnexpectedStatusCodeError) Error() string { - s := func(i int) string { return fmt.Sprintf("%d %s", i, http.StatusText(i)) } - - got := s(e.got) - expected := []string{} - for _, v := range e.allowed { - expected = append(expected, s(v)) - } - return fmt.Sprintf("storage: status code from service response is %s; was expecting %s", got, strings.Join(expected, " or ")) -} - -// Got is the actual status code returned by Azure. -func (e UnexpectedStatusCodeError) Got() int { - return e.got -} - -// NewBasicClient constructs a Client with given storage service name and -// key. -func NewBasicClient(accountName, accountKey string) (Client, error) { - if accountName == StorageEmulatorAccountName { - return NewEmulatorClient() - } - return NewClient(accountName, accountKey, DefaultBaseURL, DefaultAPIVersion, defaultUseHTTPS) -} - -// NewBasicClientOnSovereignCloud constructs a Client with given storage service name and -// key in the referenced cloud. -func NewBasicClientOnSovereignCloud(accountName, accountKey string, env azure.Environment) (Client, error) { - if accountName == StorageEmulatorAccountName { - return NewEmulatorClient() - } - return NewClient(accountName, accountKey, env.StorageEndpointSuffix, DefaultAPIVersion, defaultUseHTTPS) -} - -//NewEmulatorClient contructs a Client intended to only work with Azure -//Storage Emulator -func NewEmulatorClient() (Client, error) { - return NewClient(StorageEmulatorAccountName, StorageEmulatorAccountKey, DefaultBaseURL, DefaultAPIVersion, false) -} - -// NewClient constructs a Client. This should be used if the caller wants -// to specify whether to use HTTPS, a specific REST API version or a custom -// storage endpoint than Azure Public Cloud. -func NewClient(accountName, accountKey, blobServiceBaseURL, apiVersion string, useHTTPS bool) (Client, error) { - var c Client - if accountName == "" { - return c, fmt.Errorf("azure: account name required") - } else if accountKey == "" { - return c, fmt.Errorf("azure: account key required") - } else if blobServiceBaseURL == "" { - return c, fmt.Errorf("azure: base storage service url required") - } - - key, err := base64.StdEncoding.DecodeString(accountKey) - if err != nil { - return c, fmt.Errorf("azure: malformed storage account key: %v", err) - } - - c = Client{ - accountName: accountName, - accountKey: key, - useHTTPS: useHTTPS, - baseURL: blobServiceBaseURL, - apiVersion: apiVersion, - UseSharedKeyLite: false, - } - c.userAgent = c.getDefaultUserAgent() - return c, nil -} - -func (c Client) getDefaultUserAgent() string { - return fmt.Sprintf("Go/%s (%s-%s) Azure-SDK-For-Go/%s storage-dataplane/%s", - runtime.Version(), - runtime.GOARCH, - runtime.GOOS, - sdkVersion, - c.apiVersion, - ) -} - -// AddToUserAgent adds an extension to the current user agent -func (c *Client) AddToUserAgent(extension string) error { - if extension != "" { - c.userAgent = fmt.Sprintf("%s %s", c.userAgent, extension) - return nil - } - return fmt.Errorf("Extension was empty, User Agent stayed as %s", c.userAgent) -} - -// protectUserAgent is used in funcs that include extraheaders as a parameter. -// It prevents the User-Agent header to be overwritten, instead if it happens to -// be present, it gets added to the current User-Agent. Use it before getStandardHeaders -func (c *Client) protectUserAgent(extraheaders map[string]string) map[string]string { - if v, ok := extraheaders[userAgentHeader]; ok { - c.AddToUserAgent(v) - delete(extraheaders, userAgentHeader) - } - return extraheaders -} - -func (c Client) getBaseURL(service string) string { - scheme := "http" - if c.useHTTPS { - scheme = "https" - } - host := "" - if c.accountName == StorageEmulatorAccountName { - switch service { - case blobServiceName: - host = storageEmulatorBlob - case tableServiceName: - host = storageEmulatorTable - case queueServiceName: - host = storageEmulatorQueue - } - } else { - host = fmt.Sprintf("%s.%s.%s", c.accountName, service, c.baseURL) - } - - u := &url.URL{ - Scheme: scheme, - Host: host} - return u.String() -} - -func (c Client) getEndpoint(service, path string, params url.Values) string { - u, err := url.Parse(c.getBaseURL(service)) - if err != nil { - // really should not be happening - panic(err) - } - - // API doesn't accept path segments not starting with '/' - if !strings.HasPrefix(path, "/") { - path = fmt.Sprintf("/%v", path) - } - - if c.accountName == StorageEmulatorAccountName { - path = fmt.Sprintf("/%v%v", StorageEmulatorAccountName, path) - } - - u.Path = path - u.RawQuery = params.Encode() - return u.String() -} - -// GetBlobService returns a BlobStorageClient which can operate on the blob -// service of the storage account. -func (c Client) GetBlobService() BlobStorageClient { - b := BlobStorageClient{ - client: c, - } - b.client.AddToUserAgent(blobServiceName) - b.auth = sharedKey - if c.UseSharedKeyLite { - b.auth = sharedKeyLite - } - return b -} - -// GetQueueService returns a QueueServiceClient which can operate on the queue -// service of the storage account. -func (c Client) GetQueueService() QueueServiceClient { - q := QueueServiceClient{ - client: c, - } - q.client.AddToUserAgent(queueServiceName) - q.auth = sharedKey - if c.UseSharedKeyLite { - q.auth = sharedKeyLite - } - return q -} - -// GetTableService returns a TableServiceClient which can operate on the table -// service of the storage account. -func (c Client) GetTableService() TableServiceClient { - t := TableServiceClient{ - client: c, - } - t.client.AddToUserAgent(tableServiceName) - t.auth = sharedKeyForTable - if c.UseSharedKeyLite { - t.auth = sharedKeyLiteForTable - } - return t -} - -// GetFileService returns a FileServiceClient which can operate on the file -// service of the storage account. -func (c Client) GetFileService() FileServiceClient { - f := FileServiceClient{ - client: c, - } - f.client.AddToUserAgent(fileServiceName) - f.auth = sharedKey - if c.UseSharedKeyLite { - f.auth = sharedKeyLite - } - return f -} - -func (c Client) getStandardHeaders() map[string]string { - return map[string]string{ - userAgentHeader: c.userAgent, - "x-ms-version": c.apiVersion, - "x-ms-date": currentTimeRfc1123Formatted(), - } -} - -func (c Client) exec(verb, url string, headers map[string]string, body io.Reader, auth authentication) (*storageResponse, error) { - headers, err := c.addAuthorizationHeader(verb, url, headers, auth) - if err != nil { - return nil, err - } - - req, err := http.NewRequest(verb, url, body) - if err != nil { - return nil, errors.New("azure/storage: error creating request: " + err.Error()) - } - - if clstr, ok := headers["Content-Length"]; ok { - // content length header is being signed, but completely ignored by golang. - // instead we have to use the ContentLength property on the request struct - // (see https://golang.org/src/net/http/request.go?s=18140:18370#L536 and - // https://golang.org/src/net/http/transfer.go?s=1739:2467#L49) - req.ContentLength, err = strconv.ParseInt(clstr, 10, 64) - if err != nil { - return nil, err - } - } - for k, v := range headers { - req.Header.Add(k, v) - } - - httpClient := c.HTTPClient - if httpClient == nil { - httpClient = http.DefaultClient - } - resp, err := httpClient.Do(req) - if err != nil { - return nil, err - } - - statusCode := resp.StatusCode - if statusCode >= 400 && statusCode <= 505 { - var respBody []byte - respBody, err = readAndCloseBody(resp.Body) - if err != nil { - return nil, err - } - - requestID := resp.Header.Get("x-ms-request-id") - if len(respBody) == 0 { - // no error in response body, might happen in HEAD requests - err = serviceErrFromStatusCode(resp.StatusCode, resp.Status, requestID) - } else { - // response contains storage service error object, unmarshal - storageErr, errIn := serviceErrFromXML(respBody, resp.StatusCode, requestID) - if err != nil { // error unmarshaling the error response - err = errIn - } - err = storageErr - } - return &storageResponse{ - statusCode: resp.StatusCode, - headers: resp.Header, - body: ioutil.NopCloser(bytes.NewReader(respBody)), /* restore the body */ - }, err - } - - return &storageResponse{ - statusCode: resp.StatusCode, - headers: resp.Header, - body: resp.Body}, nil -} - -func (c Client) execInternalJSON(verb, url string, headers map[string]string, body io.Reader, auth authentication) (*odataResponse, error) { - headers, err := c.addAuthorizationHeader(verb, url, headers, auth) - if err != nil { - return nil, err - } - - req, err := http.NewRequest(verb, url, body) - for k, v := range headers { - req.Header.Add(k, v) - } - - httpClient := c.HTTPClient - if httpClient == nil { - httpClient = http.DefaultClient - } - - resp, err := httpClient.Do(req) - if err != nil { - return nil, err - } - - respToRet := &odataResponse{} - respToRet.body = resp.Body - respToRet.statusCode = resp.StatusCode - respToRet.headers = resp.Header - - statusCode := resp.StatusCode - if statusCode >= 400 && statusCode <= 505 { - var respBody []byte - respBody, err = readAndCloseBody(resp.Body) - if err != nil { - return nil, err - } - - if len(respBody) == 0 { - // no error in response body, might happen in HEAD requests - err = serviceErrFromStatusCode(resp.StatusCode, resp.Status, resp.Header.Get("x-ms-request-id")) - return respToRet, err - } - // try unmarshal as odata.error json - err = json.Unmarshal(respBody, &respToRet.odata) - return respToRet, err - } - - return respToRet, nil -} - -func readAndCloseBody(body io.ReadCloser) ([]byte, error) { - defer body.Close() - out, err := ioutil.ReadAll(body) - if err == io.EOF { - err = nil - } - return out, err -} - -func serviceErrFromXML(body []byte, statusCode int, requestID string) (AzureStorageServiceError, error) { - var storageErr AzureStorageServiceError - if err := xml.Unmarshal(body, &storageErr); err != nil { - return storageErr, err - } - storageErr.StatusCode = statusCode - storageErr.RequestID = requestID - return storageErr, nil -} - -func serviceErrFromStatusCode(code int, status string, requestID string) AzureStorageServiceError { - return AzureStorageServiceError{ - StatusCode: code, - Code: status, - RequestID: requestID, - Message: "no response body was available for error status code", - } -} - -func (e AzureStorageServiceError) Error() string { - return fmt.Sprintf("storage: service returned error: StatusCode=%d, ErrorCode=%s, ErrorMessage=%s, RequestId=%s, QueryParameterName=%s, QueryParameterValue=%s", - e.StatusCode, e.Code, e.Message, e.RequestID, e.QueryParameterName, e.QueryParameterValue) -} - -// checkRespCode returns UnexpectedStatusError if the given response code is not -// one of the allowed status codes; otherwise nil. -func checkRespCode(respCode int, allowed []int) error { - for _, v := range allowed { - if respCode == v { - return nil - } - } - return UnexpectedStatusCodeError{allowed, respCode} -} diff --git a/vendor/github.com/Azure/azure-storage-go/container.go b/vendor/github.com/Azure/azure-storage-go/container.go deleted file mode 100644 index f064239674..0000000000 --- a/vendor/github.com/Azure/azure-storage-go/container.go +++ /dev/null @@ -1,376 +0,0 @@ -package storage - -import ( - "encoding/xml" - "errors" - "fmt" - "io" - "net/http" - "net/url" - "strconv" - "time" -) - -// Container represents an Azure container. -type Container struct { - bsc *BlobStorageClient - Name string `xml:"Name"` - Properties ContainerProperties `xml:"Properties"` -} - -func (c *Container) buildPath() string { - return fmt.Sprintf("/%s", c.Name) -} - -// ContainerProperties contains various properties of a container returned from -// various endpoints like ListContainers. -type ContainerProperties struct { - LastModified string `xml:"Last-Modified"` - Etag string `xml:"Etag"` - LeaseStatus string `xml:"LeaseStatus"` - LeaseState string `xml:"LeaseState"` - LeaseDuration string `xml:"LeaseDuration"` -} - -// ContainerListResponse contains the response fields from -// ListContainers call. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd179352.aspx -type ContainerListResponse struct { - XMLName xml.Name `xml:"EnumerationResults"` - Xmlns string `xml:"xmlns,attr"` - Prefix string `xml:"Prefix"` - Marker string `xml:"Marker"` - NextMarker string `xml:"NextMarker"` - MaxResults int64 `xml:"MaxResults"` - Containers []Container `xml:"Containers>Container"` -} - -// BlobListResponse contains the response fields from ListBlobs call. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd135734.aspx -type BlobListResponse struct { - XMLName xml.Name `xml:"EnumerationResults"` - Xmlns string `xml:"xmlns,attr"` - Prefix string `xml:"Prefix"` - Marker string `xml:"Marker"` - NextMarker string `xml:"NextMarker"` - MaxResults int64 `xml:"MaxResults"` - Blobs []Blob `xml:"Blobs>Blob"` - - // BlobPrefix is used to traverse blobs as if it were a file system. - // It is returned if ListBlobsParameters.Delimiter is specified. - // The list here can be thought of as "folders" that may contain - // other folders or blobs. - BlobPrefixes []string `xml:"Blobs>BlobPrefix>Name"` - - // Delimiter is used to traverse blobs as if it were a file system. - // It is returned if ListBlobsParameters.Delimiter is specified. - Delimiter string `xml:"Delimiter"` -} - -// ListBlobsParameters defines the set of customizable -// parameters to make a List Blobs call. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd135734.aspx -type ListBlobsParameters struct { - Prefix string - Delimiter string - Marker string - Include string - MaxResults uint - Timeout uint -} - -func (p ListBlobsParameters) getParameters() url.Values { - out := url.Values{} - - if p.Prefix != "" { - out.Set("prefix", p.Prefix) - } - if p.Delimiter != "" { - out.Set("delimiter", p.Delimiter) - } - if p.Marker != "" { - out.Set("marker", p.Marker) - } - if p.Include != "" { - out.Set("include", p.Include) - } - if p.MaxResults != 0 { - out.Set("maxresults", fmt.Sprintf("%v", p.MaxResults)) - } - if p.Timeout != 0 { - out.Set("timeout", fmt.Sprintf("%v", p.Timeout)) - } - - return out -} - -// ContainerAccessType defines the access level to the container from a public -// request. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd179468.aspx and "x-ms- -// blob-public-access" header. -type ContainerAccessType string - -// Access options for containers -const ( - ContainerAccessTypePrivate ContainerAccessType = "" - ContainerAccessTypeBlob ContainerAccessType = "blob" - ContainerAccessTypeContainer ContainerAccessType = "container" -) - -// ContainerAccessPolicy represents each access policy in the container ACL. -type ContainerAccessPolicy struct { - ID string - StartTime time.Time - ExpiryTime time.Time - CanRead bool - CanWrite bool - CanDelete bool -} - -// ContainerPermissions represents the container ACLs. -type ContainerPermissions struct { - AccessType ContainerAccessType - AccessPolicies []ContainerAccessPolicy -} - -// ContainerAccessHeader references header used when setting/getting container ACL -const ( - ContainerAccessHeader string = "x-ms-blob-public-access" -) - -// Create creates a blob container within the storage account -// with given name and access level. Returns error if container already exists. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd179468.aspx -func (c *Container) Create() error { - resp, err := c.create() - if err != nil { - return err - } - defer readAndCloseBody(resp.body) - return checkRespCode(resp.statusCode, []int{http.StatusCreated}) -} - -// CreateIfNotExists creates a blob container if it does not exist. Returns -// true if container is newly created or false if container already exists. -func (c *Container) CreateIfNotExists() (bool, error) { - resp, err := c.create() - if resp != nil { - defer readAndCloseBody(resp.body) - if resp.statusCode == http.StatusCreated || resp.statusCode == http.StatusConflict { - return resp.statusCode == http.StatusCreated, nil - } - } - return false, err -} - -func (c *Container) create() (*storageResponse, error) { - uri := c.bsc.client.getEndpoint(blobServiceName, c.buildPath(), url.Values{"restype": {"container"}}) - headers := c.bsc.client.getStandardHeaders() - return c.bsc.client.exec(http.MethodPut, uri, headers, nil, c.bsc.auth) -} - -// Exists returns true if a container with given name exists -// on the storage account, otherwise returns false. -func (c *Container) Exists() (bool, error) { - uri := c.bsc.client.getEndpoint(blobServiceName, c.buildPath(), url.Values{"restype": {"container"}}) - headers := c.bsc.client.getStandardHeaders() - - resp, err := c.bsc.client.exec(http.MethodHead, uri, headers, nil, c.bsc.auth) - if resp != nil { - defer readAndCloseBody(resp.body) - if resp.statusCode == http.StatusOK || resp.statusCode == http.StatusNotFound { - return resp.statusCode == http.StatusOK, nil - } - } - return false, err -} - -// SetPermissions sets up container permissions as per https://msdn.microsoft.com/en-us/library/azure/dd179391.aspx -func (c *Container) SetPermissions(permissions ContainerPermissions, timeout int, leaseID string) error { - params := url.Values{ - "restype": {"container"}, - "comp": {"acl"}, - } - - if timeout > 0 { - params.Add("timeout", strconv.Itoa(timeout)) - } - - uri := c.bsc.client.getEndpoint(blobServiceName, c.buildPath(), params) - headers := c.bsc.client.getStandardHeaders() - if permissions.AccessType != "" { - headers[ContainerAccessHeader] = string(permissions.AccessType) - } - - if leaseID != "" { - headers[headerLeaseID] = leaseID - } - - body, length, err := generateContainerACLpayload(permissions.AccessPolicies) - headers["Content-Length"] = strconv.Itoa(length) - - resp, err := c.bsc.client.exec(http.MethodPut, uri, headers, body, c.bsc.auth) - if err != nil { - return err - } - defer readAndCloseBody(resp.body) - - if err := checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil { - return errors.New("Unable to set permissions") - } - - return nil -} - -// GetPermissions gets the container permissions as per https://msdn.microsoft.com/en-us/library/azure/dd179469.aspx -// If timeout is 0 then it will not be passed to Azure -// leaseID will only be passed to Azure if populated -func (c *Container) GetPermissions(timeout int, leaseID string) (*ContainerPermissions, error) { - params := url.Values{ - "restype": {"container"}, - "comp": {"acl"}, - } - - if timeout > 0 { - params.Add("timeout", strconv.Itoa(timeout)) - } - - uri := c.bsc.client.getEndpoint(blobServiceName, c.buildPath(), params) - headers := c.bsc.client.getStandardHeaders() - - if leaseID != "" { - headers[headerLeaseID] = leaseID - } - - resp, err := c.bsc.client.exec(http.MethodGet, uri, headers, nil, c.bsc.auth) - if err != nil { - return nil, err - } - defer resp.body.Close() - - var ap AccessPolicy - err = xmlUnmarshal(resp.body, &ap.SignedIdentifiersList) - if err != nil { - return nil, err - } - return buildAccessPolicy(ap, &resp.headers), nil -} - -func buildAccessPolicy(ap AccessPolicy, headers *http.Header) *ContainerPermissions { - // containerAccess. Blob, Container, empty - containerAccess := headers.Get(http.CanonicalHeaderKey(ContainerAccessHeader)) - permissions := ContainerPermissions{ - AccessType: ContainerAccessType(containerAccess), - AccessPolicies: []ContainerAccessPolicy{}, - } - - for _, policy := range ap.SignedIdentifiersList.SignedIdentifiers { - capd := ContainerAccessPolicy{ - ID: policy.ID, - StartTime: policy.AccessPolicy.StartTime, - ExpiryTime: policy.AccessPolicy.ExpiryTime, - } - capd.CanRead = updatePermissions(policy.AccessPolicy.Permission, "r") - capd.CanWrite = updatePermissions(policy.AccessPolicy.Permission, "w") - capd.CanDelete = updatePermissions(policy.AccessPolicy.Permission, "d") - - permissions.AccessPolicies = append(permissions.AccessPolicies, capd) - } - return &permissions -} - -// Delete deletes the container with given name on the storage -// account. If the container does not exist returns error. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd179408.aspx -func (c *Container) Delete() error { - resp, err := c.delete() - if err != nil { - return err - } - defer readAndCloseBody(resp.body) - return checkRespCode(resp.statusCode, []int{http.StatusAccepted}) -} - -// DeleteIfExists deletes the container with given name on the storage -// account if it exists. Returns true if container is deleted with this call, or -// false if the container did not exist at the time of the Delete Container -// operation. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd179408.aspx -func (c *Container) DeleteIfExists() (bool, error) { - resp, err := c.delete() - if resp != nil { - defer readAndCloseBody(resp.body) - if resp.statusCode == http.StatusAccepted || resp.statusCode == http.StatusNotFound { - return resp.statusCode == http.StatusAccepted, nil - } - } - return false, err -} - -func (c *Container) delete() (*storageResponse, error) { - uri := c.bsc.client.getEndpoint(blobServiceName, c.buildPath(), url.Values{"restype": {"container"}}) - headers := c.bsc.client.getStandardHeaders() - return c.bsc.client.exec(http.MethodDelete, uri, headers, nil, c.bsc.auth) -} - -// ListBlobs returns an object that contains list of blobs in the container, -// pagination token and other information in the response of List Blobs call. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd135734.aspx -func (c *Container) ListBlobs(params ListBlobsParameters) (BlobListResponse, error) { - q := mergeParams(params.getParameters(), url.Values{ - "restype": {"container"}, - "comp": {"list"}}, - ) - uri := c.bsc.client.getEndpoint(blobServiceName, c.buildPath(), q) - headers := c.bsc.client.getStandardHeaders() - - var out BlobListResponse - resp, err := c.bsc.client.exec(http.MethodGet, uri, headers, nil, c.bsc.auth) - if err != nil { - return out, err - } - defer resp.body.Close() - - err = xmlUnmarshal(resp.body, &out) - return out, err -} - -func generateContainerACLpayload(policies []ContainerAccessPolicy) (io.Reader, int, error) { - sil := SignedIdentifiers{ - SignedIdentifiers: []SignedIdentifier{}, - } - for _, capd := range policies { - permission := capd.generateContainerPermissions() - signedIdentifier := convertAccessPolicyToXMLStructs(capd.ID, capd.StartTime, capd.ExpiryTime, permission) - sil.SignedIdentifiers = append(sil.SignedIdentifiers, signedIdentifier) - } - return xmlMarshal(sil) -} - -func (capd *ContainerAccessPolicy) generateContainerPermissions() (permissions string) { - // generate the permissions string (rwd). - // still want the end user API to have bool flags. - permissions = "" - - if capd.CanRead { - permissions += "r" - } - - if capd.CanWrite { - permissions += "w" - } - - if capd.CanDelete { - permissions += "d" - } - - return permissions -} diff --git a/vendor/github.com/Azure/azure-storage-go/directory.go b/vendor/github.com/Azure/azure-storage-go/directory.go deleted file mode 100644 index d27e62079a..0000000000 --- a/vendor/github.com/Azure/azure-storage-go/directory.go +++ /dev/null @@ -1,217 +0,0 @@ -package storage - -import ( - "encoding/xml" - "net/http" - "net/url" -) - -// Directory represents a directory on a share. -type Directory struct { - fsc *FileServiceClient - Metadata map[string]string - Name string `xml:"Name"` - parent *Directory - Properties DirectoryProperties - share *Share -} - -// DirectoryProperties contains various properties of a directory. -type DirectoryProperties struct { - LastModified string `xml:"Last-Modified"` - Etag string `xml:"Etag"` -} - -// ListDirsAndFilesParameters defines the set of customizable parameters to -// make a List Files and Directories call. -// -// See https://msdn.microsoft.com/en-us/library/azure/dn166980.aspx -type ListDirsAndFilesParameters struct { - Marker string - MaxResults uint - Timeout uint -} - -// DirsAndFilesListResponse contains the response fields from -// a List Files and Directories call. -// -// See https://msdn.microsoft.com/en-us/library/azure/dn166980.aspx -type DirsAndFilesListResponse struct { - XMLName xml.Name `xml:"EnumerationResults"` - Xmlns string `xml:"xmlns,attr"` - Marker string `xml:"Marker"` - MaxResults int64 `xml:"MaxResults"` - Directories []Directory `xml:"Entries>Directory"` - Files []File `xml:"Entries>File"` - NextMarker string `xml:"NextMarker"` -} - -// builds the complete directory path for this directory object. -func (d *Directory) buildPath() string { - path := "" - current := d - for current.Name != "" { - path = "/" + current.Name + path - current = current.parent - } - return d.share.buildPath() + path -} - -// Create this directory in the associated share. -// If a directory with the same name already exists, the operation fails. -// -// See https://msdn.microsoft.com/en-us/library/azure/dn166993.aspx -func (d *Directory) Create() error { - // if this is the root directory exit early - if d.parent == nil { - return nil - } - - headers, err := d.fsc.createResource(d.buildPath(), resourceDirectory, nil, mergeMDIntoExtraHeaders(d.Metadata, nil), []int{http.StatusCreated}) - if err != nil { - return err - } - - d.updateEtagAndLastModified(headers) - return nil -} - -// CreateIfNotExists creates this directory under the associated share if the -// directory does not exists. Returns true if the directory is newly created or -// false if the directory already exists. -// -// See https://msdn.microsoft.com/en-us/library/azure/dn166993.aspx -func (d *Directory) CreateIfNotExists() (bool, error) { - // if this is the root directory exit early - if d.parent == nil { - return false, nil - } - - resp, err := d.fsc.createResourceNoClose(d.buildPath(), resourceDirectory, nil, nil) - if resp != nil { - defer readAndCloseBody(resp.body) - if resp.statusCode == http.StatusCreated || resp.statusCode == http.StatusConflict { - if resp.statusCode == http.StatusCreated { - d.updateEtagAndLastModified(resp.headers) - return true, nil - } - - return false, d.FetchAttributes() - } - } - - return false, err -} - -// Delete removes this directory. It must be empty in order to be deleted. -// If the directory does not exist the operation fails. -// -// See https://msdn.microsoft.com/en-us/library/azure/dn166969.aspx -func (d *Directory) Delete() error { - return d.fsc.deleteResource(d.buildPath(), resourceDirectory) -} - -// DeleteIfExists removes this directory if it exists. -// -// See https://msdn.microsoft.com/en-us/library/azure/dn166969.aspx -func (d *Directory) DeleteIfExists() (bool, error) { - resp, err := d.fsc.deleteResourceNoClose(d.buildPath(), resourceDirectory) - if resp != nil { - defer readAndCloseBody(resp.body) - if resp.statusCode == http.StatusAccepted || resp.statusCode == http.StatusNotFound { - return resp.statusCode == http.StatusAccepted, nil - } - } - return false, err -} - -// Exists returns true if this directory exists. -func (d *Directory) Exists() (bool, error) { - exists, headers, err := d.fsc.resourceExists(d.buildPath(), resourceDirectory) - if exists { - d.updateEtagAndLastModified(headers) - } - return exists, err -} - -// FetchAttributes retrieves metadata for this directory. -func (d *Directory) FetchAttributes() error { - headers, err := d.fsc.getResourceHeaders(d.buildPath(), compNone, resourceDirectory, http.MethodHead) - if err != nil { - return err - } - - d.updateEtagAndLastModified(headers) - d.Metadata = getMetadataFromHeaders(headers) - - return nil -} - -// GetDirectoryReference returns a child Directory object for this directory. -func (d *Directory) GetDirectoryReference(name string) *Directory { - return &Directory{ - fsc: d.fsc, - Name: name, - parent: d, - share: d.share, - } -} - -// GetFileReference returns a child File object for this directory. -func (d *Directory) GetFileReference(name string) *File { - return &File{ - fsc: d.fsc, - Name: name, - parent: d, - share: d.share, - } -} - -// ListDirsAndFiles returns a list of files and directories under this directory. -// It also contains a pagination token and other response details. -// -// See https://msdn.microsoft.com/en-us/library/azure/dn166980.aspx -func (d *Directory) ListDirsAndFiles(params ListDirsAndFilesParameters) (*DirsAndFilesListResponse, error) { - q := mergeParams(params.getParameters(), getURLInitValues(compList, resourceDirectory)) - - resp, err := d.fsc.listContent(d.buildPath(), q, nil) - if err != nil { - return nil, err - } - - defer resp.body.Close() - var out DirsAndFilesListResponse - err = xmlUnmarshal(resp.body, &out) - return &out, err -} - -// SetMetadata replaces the metadata for this directory. -// -// Some keys may be converted to Camel-Case before sending. All keys -// are returned in lower case by GetDirectoryMetadata. HTTP header names -// are case-insensitive so case munging should not matter to other -// applications either. -// -// See https://msdn.microsoft.com/en-us/library/azure/mt427370.aspx -func (d *Directory) SetMetadata() error { - headers, err := d.fsc.setResourceHeaders(d.buildPath(), compMetadata, resourceDirectory, mergeMDIntoExtraHeaders(d.Metadata, nil)) - if err != nil { - return err - } - - d.updateEtagAndLastModified(headers) - return nil -} - -// updates Etag and last modified date -func (d *Directory) updateEtagAndLastModified(headers http.Header) { - d.Properties.Etag = headers.Get("Etag") - d.Properties.LastModified = headers.Get("Last-Modified") -} - -// URL gets the canonical URL to this directory. -// This method does not create a publicly accessible URL if the directory -// is private and this method does not check if the directory exists. -func (d *Directory) URL() string { - return d.fsc.client.getEndpoint(fileServiceName, d.buildPath(), url.Values{}) -} diff --git a/vendor/github.com/Azure/azure-storage-go/file.go b/vendor/github.com/Azure/azure-storage-go/file.go deleted file mode 100644 index e4901a1144..0000000000 --- a/vendor/github.com/Azure/azure-storage-go/file.go +++ /dev/null @@ -1,412 +0,0 @@ -package storage - -import ( - "errors" - "fmt" - "io" - "io/ioutil" - "net/http" - "net/url" - "strconv" -) - -const fourMB = uint64(4194304) -const oneTB = uint64(1099511627776) - -// File represents a file on a share. -type File struct { - fsc *FileServiceClient - Metadata map[string]string - Name string `xml:"Name"` - parent *Directory - Properties FileProperties `xml:"Properties"` - share *Share - FileCopyProperties FileCopyState -} - -// FileProperties contains various properties of a file. -type FileProperties struct { - CacheControl string `header:"x-ms-cache-control"` - Disposition string `header:"x-ms-content-disposition"` - Encoding string `header:"x-ms-content-encoding"` - Etag string - Language string `header:"x-ms-content-language"` - LastModified string - Length uint64 `xml:"Content-Length"` - MD5 string `header:"x-ms-content-md5"` - Type string `header:"x-ms-content-type"` -} - -// FileCopyState contains various properties of a file copy operation. -type FileCopyState struct { - CompletionTime string - ID string `header:"x-ms-copy-id"` - Progress string - Source string - Status string `header:"x-ms-copy-status"` - StatusDesc string -} - -// FileStream contains file data returned from a call to GetFile. -type FileStream struct { - Body io.ReadCloser - ContentMD5 string -} - -// FileRequestOptions will be passed to misc file operations. -// Currently just Timeout (in seconds) but will expand. -type FileRequestOptions struct { - Timeout uint // timeout duration in seconds. -} - -// getParameters, construct parameters for FileRequestOptions. -// currently only timeout, but expecting to grow as functionality fills out. -func (p FileRequestOptions) getParameters() url.Values { - out := url.Values{} - - if p.Timeout != 0 { - out.Set("timeout", fmt.Sprintf("%v", p.Timeout)) - } - - return out -} - -// FileRanges contains a list of file range information for a file. -// -// See https://msdn.microsoft.com/en-us/library/azure/dn166984.aspx -type FileRanges struct { - ContentLength uint64 - LastModified string - ETag string - FileRanges []FileRange `xml:"Range"` -} - -// FileRange contains range information for a file. -// -// See https://msdn.microsoft.com/en-us/library/azure/dn166984.aspx -type FileRange struct { - Start uint64 `xml:"Start"` - End uint64 `xml:"End"` -} - -func (fr FileRange) String() string { - return fmt.Sprintf("bytes=%d-%d", fr.Start, fr.End) -} - -// builds the complete file path for this file object -func (f *File) buildPath() string { - return f.parent.buildPath() + "/" + f.Name -} - -// ClearRange releases the specified range of space in a file. -// -// See https://msdn.microsoft.com/en-us/library/azure/dn194276.aspx -func (f *File) ClearRange(fileRange FileRange) error { - headers, err := f.modifyRange(nil, fileRange, nil) - if err != nil { - return err - } - - f.updateEtagAndLastModified(headers) - return nil -} - -// Create creates a new file or replaces an existing one. -// -// See https://msdn.microsoft.com/en-us/library/azure/dn194271.aspx -func (f *File) Create(maxSize uint64) error { - if maxSize > oneTB { - return fmt.Errorf("max file size is 1TB") - } - - extraHeaders := map[string]string{ - "x-ms-content-length": strconv.FormatUint(maxSize, 10), - "x-ms-type": "file", - } - - headers, err := f.fsc.createResource(f.buildPath(), resourceFile, nil, mergeMDIntoExtraHeaders(f.Metadata, extraHeaders), []int{http.StatusCreated}) - if err != nil { - return err - } - - f.Properties.Length = maxSize - f.updateEtagAndLastModified(headers) - return nil -} - -// CopyFile operation copied a file/blob from the sourceURL to the path provided. -// -// See https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/copy-file -func (f *File) CopyFile(sourceURL string, options *FileRequestOptions) error { - extraHeaders := map[string]string{ - "x-ms-type": "file", - "x-ms-copy-source": sourceURL, - } - - var parameters url.Values - if options != nil { - parameters = options.getParameters() - } - - headers, err := f.fsc.createResource(f.buildPath(), resourceFile, parameters, mergeMDIntoExtraHeaders(f.Metadata, extraHeaders), []int{http.StatusAccepted}) - if err != nil { - return err - } - - f.updateEtagLastModifiedAndCopyHeaders(headers) - return nil -} - -// Delete immediately removes this file from the storage account. -// -// See https://msdn.microsoft.com/en-us/library/azure/dn689085.aspx -func (f *File) Delete() error { - return f.fsc.deleteResource(f.buildPath(), resourceFile) -} - -// DeleteIfExists removes this file if it exists. -// -// See https://msdn.microsoft.com/en-us/library/azure/dn689085.aspx -func (f *File) DeleteIfExists() (bool, error) { - resp, err := f.fsc.deleteResourceNoClose(f.buildPath(), resourceFile) - if resp != nil { - defer readAndCloseBody(resp.body) - if resp.statusCode == http.StatusAccepted || resp.statusCode == http.StatusNotFound { - return resp.statusCode == http.StatusAccepted, nil - } - } - return false, err -} - -// DownloadRangeToStream operation downloads the specified range of this file with optional MD5 hash. -// -// See https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/get-file -func (f *File) DownloadRangeToStream(fileRange FileRange, getContentMD5 bool) (fs FileStream, err error) { - if getContentMD5 && isRangeTooBig(fileRange) { - return fs, fmt.Errorf("must specify a range less than or equal to 4MB when getContentMD5 is true") - } - - extraHeaders := map[string]string{ - "Range": fileRange.String(), - } - if getContentMD5 == true { - extraHeaders["x-ms-range-get-content-md5"] = "true" - } - - resp, err := f.fsc.getResourceNoClose(f.buildPath(), compNone, resourceFile, http.MethodGet, extraHeaders) - if err != nil { - return fs, err - } - - if err = checkRespCode(resp.statusCode, []int{http.StatusOK, http.StatusPartialContent}); err != nil { - resp.body.Close() - return fs, err - } - - fs.Body = resp.body - if getContentMD5 { - fs.ContentMD5 = resp.headers.Get("Content-MD5") - } - return fs, nil -} - -// Exists returns true if this file exists. -func (f *File) Exists() (bool, error) { - exists, headers, err := f.fsc.resourceExists(f.buildPath(), resourceFile) - if exists { - f.updateEtagAndLastModified(headers) - f.updateProperties(headers) - } - return exists, err -} - -// FetchAttributes updates metadata and properties for this file. -func (f *File) FetchAttributes() error { - headers, err := f.fsc.getResourceHeaders(f.buildPath(), compNone, resourceFile, http.MethodHead) - if err != nil { - return err - } - - f.updateEtagAndLastModified(headers) - f.updateProperties(headers) - f.Metadata = getMetadataFromHeaders(headers) - return nil -} - -// returns true if the range is larger than 4MB -func isRangeTooBig(fileRange FileRange) bool { - if fileRange.End-fileRange.Start > fourMB { - return true - } - - return false -} - -// ListRanges returns the list of valid ranges for this file. -// -// See https://msdn.microsoft.com/en-us/library/azure/dn166984.aspx -func (f *File) ListRanges(listRange *FileRange) (*FileRanges, error) { - params := url.Values{"comp": {"rangelist"}} - - // add optional range to list - var headers map[string]string - if listRange != nil { - headers = make(map[string]string) - headers["Range"] = listRange.String() - } - - resp, err := f.fsc.listContent(f.buildPath(), params, headers) - if err != nil { - return nil, err - } - - defer resp.body.Close() - var cl uint64 - cl, err = strconv.ParseUint(resp.headers.Get("x-ms-content-length"), 10, 64) - if err != nil { - ioutil.ReadAll(resp.body) - return nil, err - } - - var out FileRanges - out.ContentLength = cl - out.ETag = resp.headers.Get("ETag") - out.LastModified = resp.headers.Get("Last-Modified") - - err = xmlUnmarshal(resp.body, &out) - return &out, err -} - -// modifies a range of bytes in this file -func (f *File) modifyRange(bytes io.Reader, fileRange FileRange, contentMD5 *string) (http.Header, error) { - if err := f.fsc.checkForStorageEmulator(); err != nil { - return nil, err - } - if fileRange.End < fileRange.Start { - return nil, errors.New("the value for rangeEnd must be greater than or equal to rangeStart") - } - if bytes != nil && isRangeTooBig(fileRange) { - return nil, errors.New("range cannot exceed 4MB in size") - } - - uri := f.fsc.client.getEndpoint(fileServiceName, f.buildPath(), url.Values{"comp": {"range"}}) - - // default to clear - write := "clear" - cl := uint64(0) - - // if bytes is not nil then this is an update operation - if bytes != nil { - write = "update" - cl = (fileRange.End - fileRange.Start) + 1 - } - - extraHeaders := map[string]string{ - "Content-Length": strconv.FormatUint(cl, 10), - "Range": fileRange.String(), - "x-ms-write": write, - } - - if contentMD5 != nil { - extraHeaders["Content-MD5"] = *contentMD5 - } - - headers := mergeHeaders(f.fsc.client.getStandardHeaders(), extraHeaders) - resp, err := f.fsc.client.exec(http.MethodPut, uri, headers, bytes, f.fsc.auth) - if err != nil { - return nil, err - } - defer readAndCloseBody(resp.body) - return resp.headers, checkRespCode(resp.statusCode, []int{http.StatusCreated}) -} - -// SetMetadata replaces the metadata for this file. -// -// Some keys may be converted to Camel-Case before sending. All keys -// are returned in lower case by GetFileMetadata. HTTP header names -// are case-insensitive so case munging should not matter to other -// applications either. -// -// See https://msdn.microsoft.com/en-us/library/azure/dn689097.aspx -func (f *File) SetMetadata() error { - headers, err := f.fsc.setResourceHeaders(f.buildPath(), compMetadata, resourceFile, mergeMDIntoExtraHeaders(f.Metadata, nil)) - if err != nil { - return err - } - - f.updateEtagAndLastModified(headers) - return nil -} - -// SetProperties sets system properties on this file. -// -// Some keys may be converted to Camel-Case before sending. All keys -// are returned in lower case by SetFileProperties. HTTP header names -// are case-insensitive so case munging should not matter to other -// applications either. -// -// See https://msdn.microsoft.com/en-us/library/azure/dn166975.aspx -func (f *File) SetProperties() error { - headers, err := f.fsc.setResourceHeaders(f.buildPath(), compProperties, resourceFile, headersFromStruct(f.Properties)) - if err != nil { - return err - } - - f.updateEtagAndLastModified(headers) - return nil -} - -// updates Etag and last modified date -func (f *File) updateEtagAndLastModified(headers http.Header) { - f.Properties.Etag = headers.Get("Etag") - f.Properties.LastModified = headers.Get("Last-Modified") -} - -// updates Etag, last modified date and x-ms-copy-id -func (f *File) updateEtagLastModifiedAndCopyHeaders(headers http.Header) { - f.Properties.Etag = headers.Get("Etag") - f.Properties.LastModified = headers.Get("Last-Modified") - f.FileCopyProperties.ID = headers.Get("X-Ms-Copy-Id") - f.FileCopyProperties.Status = headers.Get("X-Ms-Copy-Status") -} - -// updates file properties from the specified HTTP header -func (f *File) updateProperties(header http.Header) { - size, err := strconv.ParseUint(header.Get("Content-Length"), 10, 64) - if err == nil { - f.Properties.Length = size - } - - f.updateEtagAndLastModified(header) - f.Properties.CacheControl = header.Get("Cache-Control") - f.Properties.Disposition = header.Get("Content-Disposition") - f.Properties.Encoding = header.Get("Content-Encoding") - f.Properties.Language = header.Get("Content-Language") - f.Properties.MD5 = header.Get("Content-MD5") - f.Properties.Type = header.Get("Content-Type") -} - -// URL gets the canonical URL to this file. -// This method does not create a publicly accessible URL if the file -// is private and this method does not check if the file exists. -func (f *File) URL() string { - return f.fsc.client.getEndpoint(fileServiceName, f.buildPath(), url.Values{}) -} - -// WriteRange writes a range of bytes to this file with an optional MD5 hash of the content. -// Note that the length of bytes must match (rangeEnd - rangeStart) + 1 with a maximum size of 4MB. -// -// See https://msdn.microsoft.com/en-us/library/azure/dn194276.aspx -func (f *File) WriteRange(bytes io.Reader, fileRange FileRange, contentMD5 *string) error { - if bytes == nil { - return errors.New("bytes cannot be nil") - } - - headers, err := f.modifyRange(bytes, fileRange, contentMD5) - if err != nil { - return err - } - - f.updateEtagAndLastModified(headers) - return nil -} diff --git a/vendor/github.com/Azure/azure-storage-go/fileserviceclient.go b/vendor/github.com/Azure/azure-storage-go/fileserviceclient.go deleted file mode 100644 index d68bd7f64e..0000000000 --- a/vendor/github.com/Azure/azure-storage-go/fileserviceclient.go +++ /dev/null @@ -1,375 +0,0 @@ -package storage - -import ( - "encoding/xml" - "fmt" - "net/http" - "net/url" - "strings" -) - -// FileServiceClient contains operations for Microsoft Azure File Service. -type FileServiceClient struct { - client Client - auth authentication -} - -// ListSharesParameters defines the set of customizable parameters to make a -// List Shares call. -// -// See https://msdn.microsoft.com/en-us/library/azure/dn167009.aspx -type ListSharesParameters struct { - Prefix string - Marker string - Include string - MaxResults uint - Timeout uint -} - -// ShareListResponse contains the response fields from -// ListShares call. -// -// See https://msdn.microsoft.com/en-us/library/azure/dn167009.aspx -type ShareListResponse struct { - XMLName xml.Name `xml:"EnumerationResults"` - Xmlns string `xml:"xmlns,attr"` - Prefix string `xml:"Prefix"` - Marker string `xml:"Marker"` - NextMarker string `xml:"NextMarker"` - MaxResults int64 `xml:"MaxResults"` - Shares []Share `xml:"Shares>Share"` -} - -type compType string - -const ( - compNone compType = "" - compList compType = "list" - compMetadata compType = "metadata" - compProperties compType = "properties" - compRangeList compType = "rangelist" -) - -func (ct compType) String() string { - return string(ct) -} - -type resourceType string - -const ( - resourceDirectory resourceType = "directory" - resourceFile resourceType = "" - resourceShare resourceType = "share" -) - -func (rt resourceType) String() string { - return string(rt) -} - -func (p ListSharesParameters) getParameters() url.Values { - out := url.Values{} - - if p.Prefix != "" { - out.Set("prefix", p.Prefix) - } - if p.Marker != "" { - out.Set("marker", p.Marker) - } - if p.Include != "" { - out.Set("include", p.Include) - } - if p.MaxResults != 0 { - out.Set("maxresults", fmt.Sprintf("%v", p.MaxResults)) - } - if p.Timeout != 0 { - out.Set("timeout", fmt.Sprintf("%v", p.Timeout)) - } - - return out -} - -func (p ListDirsAndFilesParameters) getParameters() url.Values { - out := url.Values{} - - if p.Marker != "" { - out.Set("marker", p.Marker) - } - if p.MaxResults != 0 { - out.Set("maxresults", fmt.Sprintf("%v", p.MaxResults)) - } - if p.Timeout != 0 { - out.Set("timeout", fmt.Sprintf("%v", p.Timeout)) - } - - return out -} - -// returns url.Values for the specified types -func getURLInitValues(comp compType, res resourceType) url.Values { - values := url.Values{} - if comp != compNone { - values.Set("comp", comp.String()) - } - if res != resourceFile { - values.Set("restype", res.String()) - } - return values -} - -// GetShareReference returns a Share object for the specified share name. -func (f FileServiceClient) GetShareReference(name string) Share { - return Share{ - fsc: &f, - Name: name, - Properties: ShareProperties{ - Quota: -1, - }, - } -} - -// ListShares returns the list of shares in a storage account along with -// pagination token and other response details. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd179352.aspx -func (f FileServiceClient) ListShares(params ListSharesParameters) (*ShareListResponse, error) { - q := mergeParams(params.getParameters(), url.Values{"comp": {"list"}}) - - var out ShareListResponse - resp, err := f.listContent("", q, nil) - if err != nil { - return nil, err - } - defer resp.body.Close() - err = xmlUnmarshal(resp.body, &out) - - // assign our client to the newly created Share objects - for i := range out.Shares { - out.Shares[i].fsc = &f - } - return &out, err -} - -// GetServiceProperties gets the properties of your storage account's file service. -// File service does not support logging -// See: https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/get-file-service-properties -func (f *FileServiceClient) GetServiceProperties() (*ServiceProperties, error) { - return f.client.getServiceProperties(fileServiceName, f.auth) -} - -// SetServiceProperties sets the properties of your storage account's file service. -// File service does not support logging -// See: https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/set-file-service-properties -func (f *FileServiceClient) SetServiceProperties(props ServiceProperties) error { - return f.client.setServiceProperties(props, fileServiceName, f.auth) -} - -// retrieves directory or share content -func (f FileServiceClient) listContent(path string, params url.Values, extraHeaders map[string]string) (*storageResponse, error) { - if err := f.checkForStorageEmulator(); err != nil { - return nil, err - } - - uri := f.client.getEndpoint(fileServiceName, path, params) - extraHeaders = f.client.protectUserAgent(extraHeaders) - headers := mergeHeaders(f.client.getStandardHeaders(), extraHeaders) - - resp, err := f.client.exec(http.MethodGet, uri, headers, nil, f.auth) - if err != nil { - return nil, err - } - - if err = checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil { - readAndCloseBody(resp.body) - return nil, err - } - - return resp, nil -} - -// returns true if the specified resource exists -func (f FileServiceClient) resourceExists(path string, res resourceType) (bool, http.Header, error) { - if err := f.checkForStorageEmulator(); err != nil { - return false, nil, err - } - - uri := f.client.getEndpoint(fileServiceName, path, getURLInitValues(compNone, res)) - headers := f.client.getStandardHeaders() - - resp, err := f.client.exec(http.MethodHead, uri, headers, nil, f.auth) - if resp != nil { - defer readAndCloseBody(resp.body) - if resp.statusCode == http.StatusOK || resp.statusCode == http.StatusNotFound { - return resp.statusCode == http.StatusOK, resp.headers, nil - } - } - return false, nil, err -} - -// creates a resource depending on the specified resource type -func (f FileServiceClient) createResource(path string, res resourceType, urlParams url.Values, extraHeaders map[string]string, expectedResponseCodes []int) (http.Header, error) { - resp, err := f.createResourceNoClose(path, res, urlParams, extraHeaders) - if err != nil { - return nil, err - } - defer readAndCloseBody(resp.body) - return resp.headers, checkRespCode(resp.statusCode, expectedResponseCodes) -} - -// creates a resource depending on the specified resource type, doesn't close the response body -func (f FileServiceClient) createResourceNoClose(path string, res resourceType, urlParams url.Values, extraHeaders map[string]string) (*storageResponse, error) { - if err := f.checkForStorageEmulator(); err != nil { - return nil, err - } - - values := getURLInitValues(compNone, res) - combinedParams := mergeParams(values, urlParams) - uri := f.client.getEndpoint(fileServiceName, path, combinedParams) - extraHeaders = f.client.protectUserAgent(extraHeaders) - headers := mergeHeaders(f.client.getStandardHeaders(), extraHeaders) - - return f.client.exec(http.MethodPut, uri, headers, nil, f.auth) -} - -// returns HTTP header data for the specified directory or share -func (f FileServiceClient) getResourceHeaders(path string, comp compType, res resourceType, verb string) (http.Header, error) { - resp, err := f.getResourceNoClose(path, comp, res, verb, nil) - if err != nil { - return nil, err - } - defer readAndCloseBody(resp.body) - - if err = checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil { - return nil, err - } - - return resp.headers, nil -} - -// gets the specified resource, doesn't close the response body -func (f FileServiceClient) getResourceNoClose(path string, comp compType, res resourceType, verb string, extraHeaders map[string]string) (*storageResponse, error) { - if err := f.checkForStorageEmulator(); err != nil { - return nil, err - } - - params := getURLInitValues(comp, res) - uri := f.client.getEndpoint(fileServiceName, path, params) - extraHeaders = f.client.protectUserAgent(extraHeaders) - headers := mergeHeaders(f.client.getStandardHeaders(), extraHeaders) - - return f.client.exec(verb, uri, headers, nil, f.auth) -} - -// deletes the resource and returns the response -func (f FileServiceClient) deleteResource(path string, res resourceType) error { - resp, err := f.deleteResourceNoClose(path, res) - if err != nil { - return err - } - defer readAndCloseBody(resp.body) - return checkRespCode(resp.statusCode, []int{http.StatusAccepted}) -} - -// deletes the resource and returns the response, doesn't close the response body -func (f FileServiceClient) deleteResourceNoClose(path string, res resourceType) (*storageResponse, error) { - if err := f.checkForStorageEmulator(); err != nil { - return nil, err - } - - values := getURLInitValues(compNone, res) - uri := f.client.getEndpoint(fileServiceName, path, values) - return f.client.exec(http.MethodDelete, uri, f.client.getStandardHeaders(), nil, f.auth) -} - -// merges metadata into extraHeaders and returns extraHeaders -func mergeMDIntoExtraHeaders(metadata, extraHeaders map[string]string) map[string]string { - if metadata == nil && extraHeaders == nil { - return nil - } - if extraHeaders == nil { - extraHeaders = make(map[string]string) - } - for k, v := range metadata { - extraHeaders[userDefinedMetadataHeaderPrefix+k] = v - } - return extraHeaders -} - -// merges extraHeaders into headers and returns headers -func mergeHeaders(headers, extraHeaders map[string]string) map[string]string { - for k, v := range extraHeaders { - headers[k] = v - } - return headers -} - -// sets extra header data for the specified resource -func (f FileServiceClient) setResourceHeaders(path string, comp compType, res resourceType, extraHeaders map[string]string) (http.Header, error) { - if err := f.checkForStorageEmulator(); err != nil { - return nil, err - } - - params := getURLInitValues(comp, res) - uri := f.client.getEndpoint(fileServiceName, path, params) - extraHeaders = f.client.protectUserAgent(extraHeaders) - headers := mergeHeaders(f.client.getStandardHeaders(), extraHeaders) - - resp, err := f.client.exec(http.MethodPut, uri, headers, nil, f.auth) - if err != nil { - return nil, err - } - defer readAndCloseBody(resp.body) - - return resp.headers, checkRespCode(resp.statusCode, []int{http.StatusOK}) -} - -// gets metadata for the specified resource -func (f FileServiceClient) getMetadata(path string, res resourceType) (map[string]string, error) { - if err := f.checkForStorageEmulator(); err != nil { - return nil, err - } - - headers, err := f.getResourceHeaders(path, compMetadata, res, http.MethodGet) - if err != nil { - return nil, err - } - - return getMetadataFromHeaders(headers), nil -} - -// returns a map of custom metadata values from the specified HTTP header -func getMetadataFromHeaders(header http.Header) map[string]string { - metadata := make(map[string]string) - for k, v := range header { - // Can't trust CanonicalHeaderKey() to munge case - // reliably. "_" is allowed in identifiers: - // https://msdn.microsoft.com/en-us/library/azure/dd179414.aspx - // https://msdn.microsoft.com/library/aa664670(VS.71).aspx - // http://tools.ietf.org/html/rfc7230#section-3.2 - // ...but "_" is considered invalid by - // CanonicalMIMEHeaderKey in - // https://golang.org/src/net/textproto/reader.go?s=14615:14659#L542 - // so k can be "X-Ms-Meta-Foo" or "x-ms-meta-foo_bar". - k = strings.ToLower(k) - if len(v) == 0 || !strings.HasPrefix(k, strings.ToLower(userDefinedMetadataHeaderPrefix)) { - continue - } - // metadata["foo"] = content of the last X-Ms-Meta-Foo header - k = k[len(userDefinedMetadataHeaderPrefix):] - metadata[k] = v[len(v)-1] - } - - if len(metadata) == 0 { - return nil - } - - return metadata -} - -//checkForStorageEmulator determines if the client is setup for use with -//Azure Storage Emulator, and returns a relevant error -func (f FileServiceClient) checkForStorageEmulator() error { - if f.client.accountName == StorageEmulatorAccountName { - return fmt.Errorf("Error: File service is not currently supported by Azure Storage Emulator") - } - return nil -} diff --git a/vendor/github.com/Azure/azure-storage-go/glide.lock b/vendor/github.com/Azure/azure-storage-go/glide.lock deleted file mode 100644 index 5d3ce83618..0000000000 --- a/vendor/github.com/Azure/azure-storage-go/glide.lock +++ /dev/null @@ -1,14 +0,0 @@ -hash: a97c0c90fe4d23bbd8e5745431f633e75530bb611131b786d76b8e1763bce85e -updated: 2017-02-23T09:58:57.3701584-08:00 -imports: -- name: github.com/Azure/go-autorest - version: ec5f4903f77ed9927ac95b19ab8e44ada64c1356 - subpackages: - - autorest/azure - - autorest - - autorest/date -- name: github.com/dgrijalva/jwt-go - version: 2268707a8f0843315e2004ee4f1d021dc08baedf -testImports: -- name: gopkg.in/check.v1 - version: 20d25e2804050c1cd24a7eea1e7a6447dd0e74ec diff --git a/vendor/github.com/Azure/azure-storage-go/glide.yaml b/vendor/github.com/Azure/azure-storage-go/glide.yaml deleted file mode 100644 index e6783b7741..0000000000 --- a/vendor/github.com/Azure/azure-storage-go/glide.yaml +++ /dev/null @@ -1,4 +0,0 @@ -package: github.com/Azure/azure-sdk-for-go-storage -import: [] -testImport: -- package: gopkg.in/check.v1 diff --git a/vendor/github.com/Azure/azure-storage-go/queue.go b/vendor/github.com/Azure/azure-storage-go/queue.go deleted file mode 100644 index 4031410aeb..0000000000 --- a/vendor/github.com/Azure/azure-storage-go/queue.go +++ /dev/null @@ -1,339 +0,0 @@ -package storage - -import ( - "encoding/xml" - "fmt" - "net/http" - "net/url" - "strconv" - "strings" -) - -const ( - // casing is per Golang's http.Header canonicalizing the header names. - approximateMessagesCountHeader = "X-Ms-Approximate-Messages-Count" - userDefinedMetadataHeaderPrefix = "X-Ms-Meta-" -) - -func pathForQueue(queue string) string { return fmt.Sprintf("/%s", queue) } -func pathForQueueMessages(queue string) string { return fmt.Sprintf("/%s/messages", queue) } -func pathForMessage(queue, name string) string { return fmt.Sprintf("/%s/messages/%s", queue, name) } - -type putMessageRequest struct { - XMLName xml.Name `xml:"QueueMessage"` - MessageText string `xml:"MessageText"` -} - -// PutMessageParameters is the set of options can be specified for Put Messsage -// operation. A zero struct does not use any preferences for the request. -type PutMessageParameters struct { - VisibilityTimeout int - MessageTTL int -} - -func (p PutMessageParameters) getParameters() url.Values { - out := url.Values{} - if p.VisibilityTimeout != 0 { - out.Set("visibilitytimeout", strconv.Itoa(p.VisibilityTimeout)) - } - if p.MessageTTL != 0 { - out.Set("messagettl", strconv.Itoa(p.MessageTTL)) - } - return out -} - -// GetMessagesParameters is the set of options can be specified for Get -// Messsages operation. A zero struct does not use any preferences for the -// request. -type GetMessagesParameters struct { - NumOfMessages int - VisibilityTimeout int -} - -func (p GetMessagesParameters) getParameters() url.Values { - out := url.Values{} - if p.NumOfMessages != 0 { - out.Set("numofmessages", strconv.Itoa(p.NumOfMessages)) - } - if p.VisibilityTimeout != 0 { - out.Set("visibilitytimeout", strconv.Itoa(p.VisibilityTimeout)) - } - return out -} - -// PeekMessagesParameters is the set of options can be specified for Peek -// Messsage operation. A zero struct does not use any preferences for the -// request. -type PeekMessagesParameters struct { - NumOfMessages int -} - -func (p PeekMessagesParameters) getParameters() url.Values { - out := url.Values{"peekonly": {"true"}} // Required for peek operation - if p.NumOfMessages != 0 { - out.Set("numofmessages", strconv.Itoa(p.NumOfMessages)) - } - return out -} - -// UpdateMessageParameters is the set of options can be specified for Update Messsage -// operation. A zero struct does not use any preferences for the request. -type UpdateMessageParameters struct { - PopReceipt string - VisibilityTimeout int -} - -func (p UpdateMessageParameters) getParameters() url.Values { - out := url.Values{} - if p.PopReceipt != "" { - out.Set("popreceipt", p.PopReceipt) - } - if p.VisibilityTimeout != 0 { - out.Set("visibilitytimeout", strconv.Itoa(p.VisibilityTimeout)) - } - return out -} - -// GetMessagesResponse represents a response returned from Get Messages -// operation. -type GetMessagesResponse struct { - XMLName xml.Name `xml:"QueueMessagesList"` - QueueMessagesList []GetMessageResponse `xml:"QueueMessage"` -} - -// GetMessageResponse represents a QueueMessage object returned from Get -// Messages operation response. -type GetMessageResponse struct { - MessageID string `xml:"MessageId"` - InsertionTime string `xml:"InsertionTime"` - ExpirationTime string `xml:"ExpirationTime"` - PopReceipt string `xml:"PopReceipt"` - TimeNextVisible string `xml:"TimeNextVisible"` - DequeueCount int `xml:"DequeueCount"` - MessageText string `xml:"MessageText"` -} - -// PeekMessagesResponse represents a response returned from Get Messages -// operation. -type PeekMessagesResponse struct { - XMLName xml.Name `xml:"QueueMessagesList"` - QueueMessagesList []PeekMessageResponse `xml:"QueueMessage"` -} - -// PeekMessageResponse represents a QueueMessage object returned from Peek -// Messages operation response. -type PeekMessageResponse struct { - MessageID string `xml:"MessageId"` - InsertionTime string `xml:"InsertionTime"` - ExpirationTime string `xml:"ExpirationTime"` - DequeueCount int `xml:"DequeueCount"` - MessageText string `xml:"MessageText"` -} - -// QueueMetadataResponse represents user defined metadata and queue -// properties on a specific queue. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd179384.aspx -type QueueMetadataResponse struct { - ApproximateMessageCount int - UserDefinedMetadata map[string]string -} - -// SetMetadata operation sets user-defined metadata on the specified queue. -// Metadata is associated with the queue as name-value pairs. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd179348.aspx -func (c QueueServiceClient) SetMetadata(name string, metadata map[string]string) error { - uri := c.client.getEndpoint(queueServiceName, pathForQueue(name), url.Values{"comp": []string{"metadata"}}) - metadata = c.client.protectUserAgent(metadata) - headers := c.client.getStandardHeaders() - for k, v := range metadata { - headers[userDefinedMetadataHeaderPrefix+k] = v - } - - resp, err := c.client.exec(http.MethodPut, uri, headers, nil, c.auth) - if err != nil { - return err - } - defer readAndCloseBody(resp.body) - - return checkRespCode(resp.statusCode, []int{http.StatusNoContent}) -} - -// GetMetadata operation retrieves user-defined metadata and queue -// properties on the specified queue. Metadata is associated with -// the queue as name-values pairs. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd179384.aspx -// -// Because the way Golang's http client (and http.Header in particular) -// canonicalize header names, the returned metadata names would always -// be all lower case. -func (c QueueServiceClient) GetMetadata(name string) (QueueMetadataResponse, error) { - qm := QueueMetadataResponse{} - qm.UserDefinedMetadata = make(map[string]string) - uri := c.client.getEndpoint(queueServiceName, pathForQueue(name), url.Values{"comp": []string{"metadata"}}) - headers := c.client.getStandardHeaders() - resp, err := c.client.exec(http.MethodGet, uri, headers, nil, c.auth) - if err != nil { - return qm, err - } - defer readAndCloseBody(resp.body) - - for k, v := range resp.headers { - if len(v) != 1 { - return qm, fmt.Errorf("Unexpected number of values (%d) in response header '%s'", len(v), k) - } - - value := v[0] - - if k == approximateMessagesCountHeader { - qm.ApproximateMessageCount, err = strconv.Atoi(value) - if err != nil { - return qm, fmt.Errorf("Unexpected value in response header '%s': '%s' ", k, value) - } - } else if strings.HasPrefix(k, userDefinedMetadataHeaderPrefix) { - name := strings.TrimPrefix(k, userDefinedMetadataHeaderPrefix) - qm.UserDefinedMetadata[strings.ToLower(name)] = value - } - } - - return qm, checkRespCode(resp.statusCode, []int{http.StatusOK}) -} - -// CreateQueue operation creates a queue under the given account. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd179342.aspx -func (c QueueServiceClient) CreateQueue(name string) error { - uri := c.client.getEndpoint(queueServiceName, pathForQueue(name), url.Values{}) - headers := c.client.getStandardHeaders() - resp, err := c.client.exec(http.MethodPut, uri, headers, nil, c.auth) - if err != nil { - return err - } - defer readAndCloseBody(resp.body) - return checkRespCode(resp.statusCode, []int{http.StatusCreated}) -} - -// DeleteQueue operation permanently deletes the specified queue. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd179436.aspx -func (c QueueServiceClient) DeleteQueue(name string) error { - uri := c.client.getEndpoint(queueServiceName, pathForQueue(name), url.Values{}) - resp, err := c.client.exec(http.MethodDelete, uri, c.client.getStandardHeaders(), nil, c.auth) - if err != nil { - return err - } - defer readAndCloseBody(resp.body) - return checkRespCode(resp.statusCode, []int{http.StatusNoContent}) -} - -// QueueExists returns true if a queue with given name exists. -func (c QueueServiceClient) QueueExists(name string) (bool, error) { - uri := c.client.getEndpoint(queueServiceName, pathForQueue(name), url.Values{"comp": {"metadata"}}) - resp, err := c.client.exec(http.MethodGet, uri, c.client.getStandardHeaders(), nil, c.auth) - if resp != nil && (resp.statusCode == http.StatusOK || resp.statusCode == http.StatusNotFound) { - return resp.statusCode == http.StatusOK, nil - } - - return false, err -} - -// PutMessage operation adds a new message to the back of the message queue. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd179346.aspx -func (c QueueServiceClient) PutMessage(queue string, message string, params PutMessageParameters) error { - uri := c.client.getEndpoint(queueServiceName, pathForQueueMessages(queue), params.getParameters()) - req := putMessageRequest{MessageText: message} - body, nn, err := xmlMarshal(req) - if err != nil { - return err - } - headers := c.client.getStandardHeaders() - headers["Content-Length"] = strconv.Itoa(nn) - resp, err := c.client.exec(http.MethodPost, uri, headers, body, c.auth) - if err != nil { - return err - } - defer readAndCloseBody(resp.body) - return checkRespCode(resp.statusCode, []int{http.StatusCreated}) -} - -// ClearMessages operation deletes all messages from the specified queue. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd179454.aspx -func (c QueueServiceClient) ClearMessages(queue string) error { - uri := c.client.getEndpoint(queueServiceName, pathForQueueMessages(queue), url.Values{}) - resp, err := c.client.exec(http.MethodDelete, uri, c.client.getStandardHeaders(), nil, c.auth) - if err != nil { - return err - } - defer readAndCloseBody(resp.body) - return checkRespCode(resp.statusCode, []int{http.StatusNoContent}) -} - -// GetMessages operation retrieves one or more messages from the front of the -// queue. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd179474.aspx -func (c QueueServiceClient) GetMessages(queue string, params GetMessagesParameters) (GetMessagesResponse, error) { - var r GetMessagesResponse - uri := c.client.getEndpoint(queueServiceName, pathForQueueMessages(queue), params.getParameters()) - resp, err := c.client.exec(http.MethodGet, uri, c.client.getStandardHeaders(), nil, c.auth) - if err != nil { - return r, err - } - defer resp.body.Close() - err = xmlUnmarshal(resp.body, &r) - return r, err -} - -// PeekMessages retrieves one or more messages from the front of the queue, but -// does not alter the visibility of the message. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd179472.aspx -func (c QueueServiceClient) PeekMessages(queue string, params PeekMessagesParameters) (PeekMessagesResponse, error) { - var r PeekMessagesResponse - uri := c.client.getEndpoint(queueServiceName, pathForQueueMessages(queue), params.getParameters()) - resp, err := c.client.exec(http.MethodGet, uri, c.client.getStandardHeaders(), nil, c.auth) - if err != nil { - return r, err - } - defer resp.body.Close() - err = xmlUnmarshal(resp.body, &r) - return r, err -} - -// DeleteMessage operation deletes the specified message. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd179347.aspx -func (c QueueServiceClient) DeleteMessage(queue, messageID, popReceipt string) error { - uri := c.client.getEndpoint(queueServiceName, pathForMessage(queue, messageID), url.Values{ - "popreceipt": {popReceipt}}) - resp, err := c.client.exec(http.MethodDelete, uri, c.client.getStandardHeaders(), nil, c.auth) - if err != nil { - return err - } - defer readAndCloseBody(resp.body) - return checkRespCode(resp.statusCode, []int{http.StatusNoContent}) -} - -// UpdateMessage operation deletes the specified message. -// -// See https://msdn.microsoft.com/en-us/library/azure/hh452234.aspx -func (c QueueServiceClient) UpdateMessage(queue string, messageID string, message string, params UpdateMessageParameters) error { - uri := c.client.getEndpoint(queueServiceName, pathForMessage(queue, messageID), params.getParameters()) - req := putMessageRequest{MessageText: message} - body, nn, err := xmlMarshal(req) - if err != nil { - return err - } - headers := c.client.getStandardHeaders() - headers["Content-Length"] = fmt.Sprintf("%d", nn) - resp, err := c.client.exec(http.MethodPut, uri, headers, body, c.auth) - if err != nil { - return err - } - defer readAndCloseBody(resp.body) - return checkRespCode(resp.statusCode, []int{http.StatusNoContent}) -} diff --git a/vendor/github.com/Azure/azure-storage-go/queueserviceclient.go b/vendor/github.com/Azure/azure-storage-go/queueserviceclient.go deleted file mode 100644 index c26141339b..0000000000 --- a/vendor/github.com/Azure/azure-storage-go/queueserviceclient.go +++ /dev/null @@ -1,20 +0,0 @@ -package storage - -// QueueServiceClient contains operations for Microsoft Azure Queue Storage -// Service. -type QueueServiceClient struct { - client Client - auth authentication -} - -// GetServiceProperties gets the properties of your storage account's queue service. -// See: https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/get-queue-service-properties -func (c *QueueServiceClient) GetServiceProperties() (*ServiceProperties, error) { - return c.client.getServiceProperties(queueServiceName, c.auth) -} - -// SetServiceProperties sets the properties of your storage account's queue service. -// See: https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/set-queue-service-properties -func (c *QueueServiceClient) SetServiceProperties(props ServiceProperties) error { - return c.client.setServiceProperties(props, queueServiceName, c.auth) -} diff --git a/vendor/github.com/Azure/azure-storage-go/share.go b/vendor/github.com/Azure/azure-storage-go/share.go deleted file mode 100644 index e190097ea5..0000000000 --- a/vendor/github.com/Azure/azure-storage-go/share.go +++ /dev/null @@ -1,186 +0,0 @@ -package storage - -import ( - "fmt" - "net/http" - "net/url" - "strconv" -) - -// Share represents an Azure file share. -type Share struct { - fsc *FileServiceClient - Name string `xml:"Name"` - Properties ShareProperties `xml:"Properties"` - Metadata map[string]string -} - -// ShareProperties contains various properties of a share. -type ShareProperties struct { - LastModified string `xml:"Last-Modified"` - Etag string `xml:"Etag"` - Quota int `xml:"Quota"` -} - -// builds the complete path for this share object. -func (s *Share) buildPath() string { - return fmt.Sprintf("/%s", s.Name) -} - -// Create this share under the associated account. -// If a share with the same name already exists, the operation fails. -// -// See https://msdn.microsoft.com/en-us/library/azure/dn167008.aspx -func (s *Share) Create() error { - headers, err := s.fsc.createResource(s.buildPath(), resourceShare, nil, mergeMDIntoExtraHeaders(s.Metadata, nil), []int{http.StatusCreated}) - if err != nil { - return err - } - - s.updateEtagAndLastModified(headers) - return nil -} - -// CreateIfNotExists creates this share under the associated account if -// it does not exist. Returns true if the share is newly created or false if -// the share already exists. -// -// See https://msdn.microsoft.com/en-us/library/azure/dn167008.aspx -func (s *Share) CreateIfNotExists() (bool, error) { - resp, err := s.fsc.createResourceNoClose(s.buildPath(), resourceShare, nil, nil) - if resp != nil { - defer readAndCloseBody(resp.body) - if resp.statusCode == http.StatusCreated || resp.statusCode == http.StatusConflict { - if resp.statusCode == http.StatusCreated { - s.updateEtagAndLastModified(resp.headers) - return true, nil - } - return false, s.FetchAttributes() - } - } - - return false, err -} - -// Delete marks this share for deletion. The share along with any files -// and directories contained within it are later deleted during garbage -// collection. If the share does not exist the operation fails -// -// See https://msdn.microsoft.com/en-us/library/azure/dn689090.aspx -func (s *Share) Delete() error { - return s.fsc.deleteResource(s.buildPath(), resourceShare) -} - -// DeleteIfExists operation marks this share for deletion if it exists. -// -// See https://msdn.microsoft.com/en-us/library/azure/dn689090.aspx -func (s *Share) DeleteIfExists() (bool, error) { - resp, err := s.fsc.deleteResourceNoClose(s.buildPath(), resourceShare) - if resp != nil { - defer readAndCloseBody(resp.body) - if resp.statusCode == http.StatusAccepted || resp.statusCode == http.StatusNotFound { - return resp.statusCode == http.StatusAccepted, nil - } - } - return false, err -} - -// Exists returns true if this share already exists -// on the storage account, otherwise returns false. -func (s *Share) Exists() (bool, error) { - exists, headers, err := s.fsc.resourceExists(s.buildPath(), resourceShare) - if exists { - s.updateEtagAndLastModified(headers) - s.updateQuota(headers) - } - return exists, err -} - -// FetchAttributes retrieves metadata and properties for this share. -func (s *Share) FetchAttributes() error { - headers, err := s.fsc.getResourceHeaders(s.buildPath(), compNone, resourceShare, http.MethodHead) - if err != nil { - return err - } - - s.updateEtagAndLastModified(headers) - s.updateQuota(headers) - s.Metadata = getMetadataFromHeaders(headers) - - return nil -} - -// GetRootDirectoryReference returns a Directory object at the root of this share. -func (s *Share) GetRootDirectoryReference() *Directory { - return &Directory{ - fsc: s.fsc, - share: s, - } -} - -// ServiceClient returns the FileServiceClient associated with this share. -func (s *Share) ServiceClient() *FileServiceClient { - return s.fsc -} - -// SetMetadata replaces the metadata for this share. -// -// Some keys may be converted to Camel-Case before sending. All keys -// are returned in lower case by GetShareMetadata. HTTP header names -// are case-insensitive so case munging should not matter to other -// applications either. -// -// See https://msdn.microsoft.com/en-us/library/azure/dd179414.aspx -func (s *Share) SetMetadata() error { - headers, err := s.fsc.setResourceHeaders(s.buildPath(), compMetadata, resourceShare, mergeMDIntoExtraHeaders(s.Metadata, nil)) - if err != nil { - return err - } - - s.updateEtagAndLastModified(headers) - return nil -} - -// SetProperties sets system properties for this share. -// -// Some keys may be converted to Camel-Case before sending. All keys -// are returned in lower case by SetShareProperties. HTTP header names -// are case-insensitive so case munging should not matter to other -// applications either. -// -// See https://msdn.microsoft.com/en-us/library/azure/mt427368.aspx -func (s *Share) SetProperties() error { - if s.Properties.Quota < 1 || s.Properties.Quota > 5120 { - return fmt.Errorf("invalid value %v for quota, valid values are [1, 5120]", s.Properties.Quota) - } - - headers, err := s.fsc.setResourceHeaders(s.buildPath(), compProperties, resourceShare, map[string]string{ - "x-ms-share-quota": strconv.Itoa(s.Properties.Quota), - }) - if err != nil { - return err - } - - s.updateEtagAndLastModified(headers) - return nil -} - -// updates Etag and last modified date -func (s *Share) updateEtagAndLastModified(headers http.Header) { - s.Properties.Etag = headers.Get("Etag") - s.Properties.LastModified = headers.Get("Last-Modified") -} - -// updates quota value -func (s *Share) updateQuota(headers http.Header) { - quota, err := strconv.Atoi(headers.Get("x-ms-share-quota")) - if err == nil { - s.Properties.Quota = quota - } -} - -// URL gets the canonical URL to this share. This method does not create a publicly accessible -// URL if the share is private and this method does not check if the share exists. -func (s *Share) URL() string { - return s.fsc.client.getEndpoint(fileServiceName, s.buildPath(), url.Values{}) -} diff --git a/vendor/github.com/Azure/azure-storage-go/storagepolicy.go b/vendor/github.com/Azure/azure-storage-go/storagepolicy.go deleted file mode 100644 index bee1c31ad6..0000000000 --- a/vendor/github.com/Azure/azure-storage-go/storagepolicy.go +++ /dev/null @@ -1,47 +0,0 @@ -package storage - -import ( - "strings" - "time" -) - -// AccessPolicyDetailsXML has specifics about an access policy -// annotated with XML details. -type AccessPolicyDetailsXML struct { - StartTime time.Time `xml:"Start"` - ExpiryTime time.Time `xml:"Expiry"` - Permission string `xml:"Permission"` -} - -// SignedIdentifier is a wrapper for a specific policy -type SignedIdentifier struct { - ID string `xml:"Id"` - AccessPolicy AccessPolicyDetailsXML `xml:"AccessPolicy"` -} - -// SignedIdentifiers part of the response from GetPermissions call. -type SignedIdentifiers struct { - SignedIdentifiers []SignedIdentifier `xml:"SignedIdentifier"` -} - -// AccessPolicy is the response type from the GetPermissions call. -type AccessPolicy struct { - SignedIdentifiersList SignedIdentifiers `xml:"SignedIdentifiers"` -} - -// convertAccessPolicyToXMLStructs converts between AccessPolicyDetails which is a struct better for API usage to the -// AccessPolicy struct which will get converted to XML. -func convertAccessPolicyToXMLStructs(id string, startTime time.Time, expiryTime time.Time, permissions string) SignedIdentifier { - return SignedIdentifier{ - ID: id, - AccessPolicy: AccessPolicyDetailsXML{ - StartTime: startTime.UTC().Round(time.Second), - ExpiryTime: expiryTime.UTC().Round(time.Second), - Permission: permissions, - }, - } -} - -func updatePermissions(permissions, permission string) bool { - return strings.Contains(permissions, permission) -} diff --git a/vendor/github.com/Azure/azure-storage-go/storageservice.go b/vendor/github.com/Azure/azure-storage-go/storageservice.go deleted file mode 100644 index 817560b782..0000000000 --- a/vendor/github.com/Azure/azure-storage-go/storageservice.go +++ /dev/null @@ -1,118 +0,0 @@ -package storage - -import ( - "fmt" - "net/http" - "net/url" -) - -// ServiceProperties represents the storage account service properties -type ServiceProperties struct { - Logging *Logging - HourMetrics *Metrics - MinuteMetrics *Metrics - Cors *Cors -} - -// Logging represents the Azure Analytics Logging settings -type Logging struct { - Version string - Delete bool - Read bool - Write bool - RetentionPolicy *RetentionPolicy -} - -// RetentionPolicy indicates if retention is enabled and for how many days -type RetentionPolicy struct { - Enabled bool - Days *int -} - -// Metrics provide request statistics. -type Metrics struct { - Version string - Enabled bool - IncludeAPIs *bool - RetentionPolicy *RetentionPolicy -} - -// Cors includes all the CORS rules -type Cors struct { - CorsRule []CorsRule -} - -// CorsRule includes all settings for a Cors rule -type CorsRule struct { - AllowedOrigins string - AllowedMethods string - MaxAgeInSeconds int - ExposedHeaders string - AllowedHeaders string -} - -func (c Client) getServiceProperties(service string, auth authentication) (*ServiceProperties, error) { - query := url.Values{ - "restype": {"service"}, - "comp": {"properties"}, - } - uri := c.getEndpoint(service, "", query) - headers := c.getStandardHeaders() - - resp, err := c.exec(http.MethodGet, uri, headers, nil, auth) - if err != nil { - return nil, err - } - defer resp.body.Close() - - if err := checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil { - return nil, err - } - - var out ServiceProperties - err = xmlUnmarshal(resp.body, &out) - if err != nil { - return nil, err - } - - return &out, nil -} - -func (c Client) setServiceProperties(props ServiceProperties, service string, auth authentication) error { - query := url.Values{ - "restype": {"service"}, - "comp": {"properties"}, - } - uri := c.getEndpoint(service, "", query) - - // Ideally, StorageServiceProperties would be the output struct - // This is to avoid golint stuttering, while generating the correct XML - type StorageServiceProperties struct { - Logging *Logging - HourMetrics *Metrics - MinuteMetrics *Metrics - Cors *Cors - } - input := StorageServiceProperties{ - Logging: props.Logging, - HourMetrics: props.HourMetrics, - MinuteMetrics: props.MinuteMetrics, - Cors: props.Cors, - } - - body, length, err := xmlMarshal(input) - if err != nil { - return err - } - - headers := c.getStandardHeaders() - headers["Content-Length"] = fmt.Sprintf("%v", length) - - resp, err := c.exec(http.MethodPut, uri, headers, body, auth) - if err != nil { - return err - } - defer readAndCloseBody(resp.body) - - return checkRespCode(resp.statusCode, []int{http.StatusAccepted}) -} diff --git a/vendor/github.com/Azure/azure-storage-go/table.go b/vendor/github.com/Azure/azure-storage-go/table.go deleted file mode 100644 index 4123746e50..0000000000 --- a/vendor/github.com/Azure/azure-storage-go/table.go +++ /dev/null @@ -1,254 +0,0 @@ -package storage - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "net/http" - "net/url" - "strconv" - "time" -) - -// AzureTable is the typedef of the Azure Table name -type AzureTable string - -const ( - tablesURIPath = "/Tables" -) - -type createTableRequest struct { - TableName string `json:"TableName"` -} - -// TableAccessPolicy are used for SETTING table policies -type TableAccessPolicy struct { - ID string - StartTime time.Time - ExpiryTime time.Time - CanRead bool - CanAppend bool - CanUpdate bool - CanDelete bool -} - -func pathForTable(table AzureTable) string { return fmt.Sprintf("%s", table) } - -func (c *TableServiceClient) getStandardHeaders() map[string]string { - return map[string]string{ - "x-ms-version": "2015-02-21", - "x-ms-date": currentTimeRfc1123Formatted(), - "Accept": "application/json;odata=nometadata", - "Accept-Charset": "UTF-8", - "Content-Type": "application/json", - userAgentHeader: c.client.userAgent, - } -} - -// QueryTables returns the tables created in the -// *TableServiceClient storage account. -func (c *TableServiceClient) QueryTables() ([]AzureTable, error) { - uri := c.client.getEndpoint(tableServiceName, tablesURIPath, url.Values{}) - - headers := c.getStandardHeaders() - headers["Content-Length"] = "0" - - resp, err := c.client.execInternalJSON(http.MethodGet, uri, headers, nil, c.auth) - if err != nil { - return nil, err - } - defer resp.body.Close() - - if err := checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil { - ioutil.ReadAll(resp.body) - return nil, err - } - - buf := new(bytes.Buffer) - if _, err := buf.ReadFrom(resp.body); err != nil { - return nil, err - } - - var respArray queryTablesResponse - if err := json.Unmarshal(buf.Bytes(), &respArray); err != nil { - return nil, err - } - - s := make([]AzureTable, len(respArray.TableName)) - for i, elem := range respArray.TableName { - s[i] = AzureTable(elem.TableName) - } - - return s, nil -} - -// CreateTable creates the table given the specific -// name. This function fails if the name is not compliant -// with the specification or the tables already exists. -func (c *TableServiceClient) CreateTable(table AzureTable) error { - uri := c.client.getEndpoint(tableServiceName, tablesURIPath, url.Values{}) - - headers := c.getStandardHeaders() - - req := createTableRequest{TableName: string(table)} - buf := new(bytes.Buffer) - - if err := json.NewEncoder(buf).Encode(req); err != nil { - return err - } - - headers["Content-Length"] = fmt.Sprintf("%d", buf.Len()) - - resp, err := c.client.execInternalJSON(http.MethodPost, uri, headers, buf, c.auth) - - if err != nil { - return err - } - defer readAndCloseBody(resp.body) - - if err := checkRespCode(resp.statusCode, []int{http.StatusCreated}); err != nil { - return err - } - - return nil -} - -// DeleteTable deletes the table given the specific -// name. This function fails if the table is not present. -// Be advised: DeleteTable deletes all the entries -// that may be present. -func (c *TableServiceClient) DeleteTable(table AzureTable) error { - uri := c.client.getEndpoint(tableServiceName, tablesURIPath, url.Values{}) - uri += fmt.Sprintf("('%s')", string(table)) - - headers := c.getStandardHeaders() - - headers["Content-Length"] = "0" - - resp, err := c.client.execInternalJSON(http.MethodDelete, uri, headers, nil, c.auth) - - if err != nil { - return err - } - defer readAndCloseBody(resp.body) - - if err := checkRespCode(resp.statusCode, []int{http.StatusNoContent}); err != nil { - return err - - } - return nil -} - -// SetTablePermissions sets up table ACL permissions as per REST details https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Set-Table-ACL -func (c *TableServiceClient) SetTablePermissions(table AzureTable, policies []TableAccessPolicy, timeout uint) (err error) { - params := url.Values{"comp": {"acl"}} - - if timeout > 0 { - params.Add("timeout", fmt.Sprint(timeout)) - } - - uri := c.client.getEndpoint(tableServiceName, string(table), params) - headers := c.client.getStandardHeaders() - - body, length, err := generateTableACLPayload(policies) - if err != nil { - return err - } - headers["Content-Length"] = fmt.Sprintf("%v", length) - - resp, err := c.client.execInternalJSON(http.MethodPut, uri, headers, body, c.auth) - if err != nil { - return err - } - defer readAndCloseBody(resp.body) - - if err := checkRespCode(resp.statusCode, []int{http.StatusNoContent}); err != nil { - return err - } - return nil -} - -func generateTableACLPayload(policies []TableAccessPolicy) (io.Reader, int, error) { - sil := SignedIdentifiers{ - SignedIdentifiers: []SignedIdentifier{}, - } - for _, tap := range policies { - permission := generateTablePermissions(&tap) - signedIdentifier := convertAccessPolicyToXMLStructs(tap.ID, tap.StartTime, tap.ExpiryTime, permission) - sil.SignedIdentifiers = append(sil.SignedIdentifiers, signedIdentifier) - } - return xmlMarshal(sil) -} - -// GetTablePermissions gets the table ACL permissions, as per REST details https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/get-table-acl -func (c *TableServiceClient) GetTablePermissions(table AzureTable, timeout int) (permissionResponse []TableAccessPolicy, err error) { - params := url.Values{"comp": {"acl"}} - - if timeout > 0 { - params.Add("timeout", strconv.Itoa(timeout)) - } - - uri := c.client.getEndpoint(tableServiceName, string(table), params) - headers := c.client.getStandardHeaders() - resp, err := c.client.execInternalJSON(http.MethodGet, uri, headers, nil, c.auth) - if err != nil { - return nil, err - } - defer resp.body.Close() - - if err = checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil { - ioutil.ReadAll(resp.body) - return nil, err - } - - var ap AccessPolicy - err = xmlUnmarshal(resp.body, &ap.SignedIdentifiersList) - if err != nil { - return nil, err - } - out := updateTableAccessPolicy(ap) - return out, nil -} - -func updateTableAccessPolicy(ap AccessPolicy) []TableAccessPolicy { - out := []TableAccessPolicy{} - for _, policy := range ap.SignedIdentifiersList.SignedIdentifiers { - tap := TableAccessPolicy{ - ID: policy.ID, - StartTime: policy.AccessPolicy.StartTime, - ExpiryTime: policy.AccessPolicy.ExpiryTime, - } - tap.CanRead = updatePermissions(policy.AccessPolicy.Permission, "r") - tap.CanAppend = updatePermissions(policy.AccessPolicy.Permission, "a") - tap.CanUpdate = updatePermissions(policy.AccessPolicy.Permission, "u") - tap.CanDelete = updatePermissions(policy.AccessPolicy.Permission, "d") - - out = append(out, tap) - } - return out -} - -func generateTablePermissions(tap *TableAccessPolicy) (permissions string) { - // generate the permissions string (raud). - // still want the end user API to have bool flags. - permissions = "" - - if tap.CanRead { - permissions += "r" - } - - if tap.CanAppend { - permissions += "a" - } - - if tap.CanUpdate { - permissions += "u" - } - - if tap.CanDelete { - permissions += "d" - } - return permissions -} diff --git a/vendor/github.com/Azure/azure-storage-go/table_entities.go b/vendor/github.com/Azure/azure-storage-go/table_entities.go deleted file mode 100644 index 36413a0cff..0000000000 --- a/vendor/github.com/Azure/azure-storage-go/table_entities.go +++ /dev/null @@ -1,354 +0,0 @@ -package storage - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "net/http" - "net/url" - "reflect" -) - -// Annotating as secure for gas scanning -/* #nosec */ -const ( - partitionKeyNode = "PartitionKey" - rowKeyNode = "RowKey" - tag = "table" - tagIgnore = "-" - continuationTokenPartitionKeyHeader = "X-Ms-Continuation-Nextpartitionkey" - continuationTokenRowHeader = "X-Ms-Continuation-Nextrowkey" - maxTopParameter = 1000 -) - -type queryTablesResponse struct { - TableName []struct { - TableName string `json:"TableName"` - } `json:"value"` -} - -const ( - tableOperationTypeInsert = iota - tableOperationTypeUpdate = iota - tableOperationTypeMerge = iota - tableOperationTypeInsertOrReplace = iota - tableOperationTypeInsertOrMerge = iota -) - -type tableOperation int - -// TableEntity interface specifies -// the functions needed to support -// marshaling and unmarshaling into -// Azure Tables. The struct must only contain -// simple types because Azure Tables do not -// support hierarchy. -type TableEntity interface { - PartitionKey() string - RowKey() string - SetPartitionKey(string) error - SetRowKey(string) error -} - -// ContinuationToken is an opaque (ie not useful to inspect) -// struct that Get... methods can return if there are more -// entries to be returned than the ones already -// returned. Just pass it to the same function to continue -// receiving the remaining entries. -type ContinuationToken struct { - NextPartitionKey string - NextRowKey string -} - -type getTableEntriesResponse struct { - Elements []map[string]interface{} `json:"value"` -} - -// QueryTableEntities queries the specified table and returns the unmarshaled -// entities of type retType. -// top parameter limits the returned entries up to top. Maximum top -// allowed by Azure API is 1000. In case there are more than top entries to be -// returned the function will return a non nil *ContinuationToken. You can call the -// same function again passing the received ContinuationToken as previousContToken -// parameter in order to get the following entries. The query parameter -// is the odata query. To retrieve all the entries pass the empty string. -// The function returns a pointer to a TableEntity slice, the *ContinuationToken -// if there are more entries to be returned and an error in case something went -// wrong. -// -// Example: -// entities, cToken, err = tSvc.QueryTableEntities("table", cToken, reflect.TypeOf(entity), 20, "") -func (c *TableServiceClient) QueryTableEntities(tableName AzureTable, previousContToken *ContinuationToken, retType reflect.Type, top int, query string) ([]TableEntity, *ContinuationToken, error) { - if top > maxTopParameter { - return nil, nil, fmt.Errorf("top accepts at maximum %d elements. Requested %d instead", maxTopParameter, top) - } - - uri := c.client.getEndpoint(tableServiceName, pathForTable(tableName), url.Values{}) - uri += fmt.Sprintf("?$top=%d", top) - if query != "" { - uri += fmt.Sprintf("&$filter=%s", url.QueryEscape(query)) - } - - if previousContToken != nil { - uri += fmt.Sprintf("&NextPartitionKey=%s&NextRowKey=%s", previousContToken.NextPartitionKey, previousContToken.NextRowKey) - } - - headers := c.getStandardHeaders() - - headers["Content-Length"] = "0" - - resp, err := c.client.execInternalJSON(http.MethodGet, uri, headers, nil, c.auth) - - if err != nil { - return nil, nil, err - } - - contToken := extractContinuationTokenFromHeaders(resp.headers) - - defer resp.body.Close() - - if err = checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil { - return nil, contToken, err - } - - retEntries, err := deserializeEntity(retType, resp.body) - if err != nil { - return nil, contToken, err - } - - return retEntries, contToken, nil -} - -// InsertEntity inserts an entity in the specified table. -// The function fails if there is an entity with the same -// PartitionKey and RowKey in the table. -func (c *TableServiceClient) InsertEntity(table AzureTable, entity TableEntity) error { - sc, err := c.execTable(table, entity, false, http.MethodPost) - if err != nil { - return err - } - - return checkRespCode(sc, []int{http.StatusCreated}) -} - -func (c *TableServiceClient) execTable(table AzureTable, entity TableEntity, specifyKeysInURL bool, method string) (int, error) { - uri := c.client.getEndpoint(tableServiceName, pathForTable(table), url.Values{}) - if specifyKeysInURL { - uri += fmt.Sprintf("(PartitionKey='%s',RowKey='%s')", url.QueryEscape(entity.PartitionKey()), url.QueryEscape(entity.RowKey())) - } - - headers := c.getStandardHeaders() - - var buf bytes.Buffer - - if err := injectPartitionAndRowKeys(entity, &buf); err != nil { - return 0, err - } - - headers["Content-Length"] = fmt.Sprintf("%d", buf.Len()) - - resp, err := c.client.execInternalJSON(method, uri, headers, &buf, c.auth) - - if err != nil { - return 0, err - } - - defer resp.body.Close() - - return resp.statusCode, nil -} - -// UpdateEntity updates the contents of an entity with the -// one passed as parameter. The function fails if there is no entity -// with the same PartitionKey and RowKey in the table. -func (c *TableServiceClient) UpdateEntity(table AzureTable, entity TableEntity) error { - sc, err := c.execTable(table, entity, true, http.MethodPut) - if err != nil { - return err - } - - return checkRespCode(sc, []int{http.StatusNoContent}) -} - -// MergeEntity merges the contents of an entity with the -// one passed as parameter. -// The function fails if there is no entity -// with the same PartitionKey and RowKey in the table. -func (c *TableServiceClient) MergeEntity(table AzureTable, entity TableEntity) error { - sc, err := c.execTable(table, entity, true, "MERGE") - if err != nil { - return err - } - - return checkRespCode(sc, []int{http.StatusNoContent}) -} - -// DeleteEntityWithoutCheck deletes the entity matching by -// PartitionKey and RowKey. There is no check on IfMatch -// parameter so the entity is always deleted. -// The function fails if there is no entity -// with the same PartitionKey and RowKey in the table. -func (c *TableServiceClient) DeleteEntityWithoutCheck(table AzureTable, entity TableEntity) error { - return c.DeleteEntity(table, entity, "*") -} - -// DeleteEntity deletes the entity matching by -// PartitionKey, RowKey and ifMatch field. -// The function fails if there is no entity -// with the same PartitionKey and RowKey in the table or -// the ifMatch is different. -func (c *TableServiceClient) DeleteEntity(table AzureTable, entity TableEntity, ifMatch string) error { - uri := c.client.getEndpoint(tableServiceName, pathForTable(table), url.Values{}) - uri += fmt.Sprintf("(PartitionKey='%s',RowKey='%s')", url.QueryEscape(entity.PartitionKey()), url.QueryEscape(entity.RowKey())) - - headers := c.getStandardHeaders() - - headers["Content-Length"] = "0" - headers["If-Match"] = ifMatch - - resp, err := c.client.execInternalJSON(http.MethodDelete, uri, headers, nil, c.auth) - - if err != nil { - return err - } - defer resp.body.Close() - - if err := checkRespCode(resp.statusCode, []int{http.StatusNoContent}); err != nil { - return err - } - - return nil -} - -// InsertOrReplaceEntity inserts an entity in the specified table -// or replaced the existing one. -func (c *TableServiceClient) InsertOrReplaceEntity(table AzureTable, entity TableEntity) error { - sc, err := c.execTable(table, entity, true, http.MethodPut) - if err != nil { - return err - } - - return checkRespCode(sc, []int{http.StatusNoContent}) -} - -// InsertOrMergeEntity inserts an entity in the specified table -// or merges the existing one. -func (c *TableServiceClient) InsertOrMergeEntity(table AzureTable, entity TableEntity) error { - sc, err := c.execTable(table, entity, true, "MERGE") - if err != nil { - return err - } - - return checkRespCode(sc, []int{http.StatusNoContent}) -} - -func injectPartitionAndRowKeys(entity TableEntity, buf *bytes.Buffer) error { - if err := json.NewEncoder(buf).Encode(entity); err != nil { - return err - } - - dec := make(map[string]interface{}) - if err := json.NewDecoder(buf).Decode(&dec); err != nil { - return err - } - - // Inject PartitionKey and RowKey - dec[partitionKeyNode] = entity.PartitionKey() - dec[rowKeyNode] = entity.RowKey() - - // Remove tagged fields - // The tag is defined in the const section - // This is useful to avoid storing the PartitionKey and RowKey twice. - numFields := reflect.ValueOf(entity).Elem().NumField() - for i := 0; i < numFields; i++ { - f := reflect.ValueOf(entity).Elem().Type().Field(i) - - if f.Tag.Get(tag) == tagIgnore { - // we must look for its JSON name in the dictionary - // as the user can rename it using a tag - jsonName := f.Name - if f.Tag.Get("json") != "" { - jsonName = f.Tag.Get("json") - } - delete(dec, jsonName) - } - } - - buf.Reset() - - if err := json.NewEncoder(buf).Encode(&dec); err != nil { - return err - } - - return nil -} - -func deserializeEntity(retType reflect.Type, reader io.Reader) ([]TableEntity, error) { - buf := new(bytes.Buffer) - - var ret getTableEntriesResponse - if err := json.NewDecoder(reader).Decode(&ret); err != nil { - return nil, err - } - - tEntries := make([]TableEntity, len(ret.Elements)) - - for i, entry := range ret.Elements { - - buf.Reset() - if err := json.NewEncoder(buf).Encode(entry); err != nil { - return nil, err - } - - dec := make(map[string]interface{}) - if err := json.NewDecoder(buf).Decode(&dec); err != nil { - return nil, err - } - - var pKey, rKey string - // strip pk and rk - for key, val := range dec { - switch key { - case partitionKeyNode: - pKey = val.(string) - case rowKeyNode: - rKey = val.(string) - } - } - - delete(dec, partitionKeyNode) - delete(dec, rowKeyNode) - - buf.Reset() - if err := json.NewEncoder(buf).Encode(dec); err != nil { - return nil, err - } - - // Create a empty retType instance - tEntries[i] = reflect.New(retType.Elem()).Interface().(TableEntity) - // Popolate it with the values - if err := json.NewDecoder(buf).Decode(&tEntries[i]); err != nil { - return nil, err - } - - // Reset PartitionKey and RowKey - if err := tEntries[i].SetPartitionKey(pKey); err != nil { - return nil, err - } - if err := tEntries[i].SetRowKey(rKey); err != nil { - return nil, err - } - } - - return tEntries, nil -} - -func extractContinuationTokenFromHeaders(h http.Header) *ContinuationToken { - ct := ContinuationToken{h.Get(continuationTokenPartitionKeyHeader), h.Get(continuationTokenRowHeader)} - - if ct.NextPartitionKey != "" && ct.NextRowKey != "" { - return &ct - } - return nil -} diff --git a/vendor/github.com/Azure/azure-storage-go/tableserviceclient.go b/vendor/github.com/Azure/azure-storage-go/tableserviceclient.go deleted file mode 100644 index ee5e0a8671..0000000000 --- a/vendor/github.com/Azure/azure-storage-go/tableserviceclient.go +++ /dev/null @@ -1,20 +0,0 @@ -package storage - -// TableServiceClient contains operations for Microsoft Azure Table Storage -// Service. -type TableServiceClient struct { - client Client - auth authentication -} - -// GetServiceProperties gets the properties of your storage account's table service. -// See: https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/get-table-service-properties -func (c *TableServiceClient) GetServiceProperties() (*ServiceProperties, error) { - return c.client.getServiceProperties(tableServiceName, c.auth) -} - -// SetServiceProperties sets the properties of your storage account's table service. -// See: https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/set-table-service-properties -func (c *TableServiceClient) SetServiceProperties(props ServiceProperties) error { - return c.client.setServiceProperties(props, tableServiceName, c.auth) -} diff --git a/vendor/github.com/Azure/azure-storage-go/util.go b/vendor/github.com/Azure/azure-storage-go/util.go deleted file mode 100644 index 57ca1b6d93..0000000000 --- a/vendor/github.com/Azure/azure-storage-go/util.go +++ /dev/null @@ -1,85 +0,0 @@ -package storage - -import ( - "bytes" - "crypto/hmac" - "crypto/sha256" - "encoding/base64" - "encoding/xml" - "fmt" - "io" - "io/ioutil" - "net/http" - "net/url" - "reflect" - "time" -) - -func (c Client) computeHmac256(message string) string { - h := hmac.New(sha256.New, c.accountKey) - h.Write([]byte(message)) - return base64.StdEncoding.EncodeToString(h.Sum(nil)) -} - -func currentTimeRfc1123Formatted() string { - return timeRfc1123Formatted(time.Now().UTC()) -} - -func timeRfc1123Formatted(t time.Time) string { - return t.Format(http.TimeFormat) -} - -func mergeParams(v1, v2 url.Values) url.Values { - out := url.Values{} - for k, v := range v1 { - out[k] = v - } - for k, v := range v2 { - vals, ok := out[k] - if ok { - vals = append(vals, v...) - out[k] = vals - } else { - out[k] = v - } - } - return out -} - -func prepareBlockListRequest(blocks []Block) string { - s := `` - for _, v := range blocks { - s += fmt.Sprintf("<%s>%s", v.Status, v.ID, v.Status) - } - s += `` - return s -} - -func xmlUnmarshal(body io.Reader, v interface{}) error { - data, err := ioutil.ReadAll(body) - if err != nil { - return err - } - return xml.Unmarshal(data, v) -} - -func xmlMarshal(v interface{}) (io.Reader, int, error) { - b, err := xml.Marshal(v) - if err != nil { - return nil, 0, err - } - return bytes.NewReader(b), len(b), nil -} - -func headersFromStruct(v interface{}) map[string]string { - headers := make(map[string]string) - value := reflect.ValueOf(v) - for i := 0; i < value.NumField(); i++ { - key := value.Type().Field(i).Tag.Get("header") - val := value.Field(i).String() - if key != "" && val != "" { - headers[key] = val - } - } - return headers -} diff --git a/vendor/github.com/Azure/azure-storage-go/version.go b/vendor/github.com/Azure/azure-storage-go/version.go deleted file mode 100644 index c25fe33713..0000000000 --- a/vendor/github.com/Azure/azure-storage-go/version.go +++ /dev/null @@ -1,5 +0,0 @@ -package storage - -var ( - sdkVersion = "0.1.0" -) diff --git a/vendor/github.com/Azure/go-autorest/autorest/autorest.go b/vendor/github.com/Azure/go-autorest/autorest/autorest.go deleted file mode 100644 index 51f1c4bbca..0000000000 --- a/vendor/github.com/Azure/go-autorest/autorest/autorest.go +++ /dev/null @@ -1,115 +0,0 @@ -/* -Package autorest implements an HTTP request pipeline suitable for use across multiple go-routines -and provides the shared routines relied on by AutoRest (see https://github.com/Azure/autorest/) -generated Go code. - -The package breaks sending and responding to HTTP requests into three phases: Preparing, Sending, -and Responding. A typical pattern is: - - req, err := Prepare(&http.Request{}, - token.WithAuthorization()) - - resp, err := Send(req, - WithLogging(logger), - DoErrorIfStatusCode(http.StatusInternalServerError), - DoCloseIfError(), - DoRetryForAttempts(5, time.Second)) - - err = Respond(resp, - ByDiscardingBody(), - ByClosing()) - -Each phase relies on decorators to modify and / or manage processing. Decorators may first modify -and then pass the data along, pass the data first and then modify the result, or wrap themselves -around passing the data (such as a logger might do). Decorators run in the order provided. For -example, the following: - - req, err := Prepare(&http.Request{}, - WithBaseURL("https://microsoft.com/"), - WithPath("a"), - WithPath("b"), - WithPath("c")) - -will set the URL to: - - https://microsoft.com/a/b/c - -Preparers and Responders may be shared and re-used (assuming the underlying decorators support -sharing and re-use). Performant use is obtained by creating one or more Preparers and Responders -shared among multiple go-routines, and a single Sender shared among multiple sending go-routines, -all bound together by means of input / output channels. - -Decorators hold their passed state within a closure (such as the path components in the example -above). Be careful to share Preparers and Responders only in a context where such held state -applies. For example, it may not make sense to share a Preparer that applies a query string from a -fixed set of values. Similarly, sharing a Responder that reads the response body into a passed -struct (e.g., ByUnmarshallingJson) is likely incorrect. - -Lastly, the Swagger specification (https://swagger.io) that drives AutoRest -(https://github.com/Azure/autorest/) precisely defines two date forms: date and date-time. The -github.com/Azure/go-autorest/autorest/date package provides time.Time derivations to ensure -correct parsing and formatting. - -Errors raised by autorest objects and methods will conform to the autorest.Error interface. - -See the included examples for more detail. For details on the suggested use of this package by -generated clients, see the Client described below. -*/ -package autorest - -import ( - "net/http" - "time" -) - -const ( - // HeaderLocation specifies the HTTP Location header. - HeaderLocation = "Location" - - // HeaderRetryAfter specifies the HTTP Retry-After header. - HeaderRetryAfter = "Retry-After" -) - -// ResponseHasStatusCode returns true if the status code in the HTTP Response is in the passed set -// and false otherwise. -func ResponseHasStatusCode(resp *http.Response, codes ...int) bool { - return containsInt(codes, resp.StatusCode) -} - -// GetLocation retrieves the URL from the Location header of the passed response. -func GetLocation(resp *http.Response) string { - return resp.Header.Get(HeaderLocation) -} - -// GetRetryAfter extracts the retry delay from the Retry-After header of the passed response. If -// the header is absent or is malformed, it will return the supplied default delay time.Duration. -func GetRetryAfter(resp *http.Response, defaultDelay time.Duration) time.Duration { - retry := resp.Header.Get(HeaderRetryAfter) - if retry == "" { - return defaultDelay - } - - d, err := time.ParseDuration(retry + "s") - if err != nil { - return defaultDelay - } - - return d -} - -// NewPollingRequest allocates and returns a new http.Request to poll for the passed response. -func NewPollingRequest(resp *http.Response, cancel <-chan struct{}) (*http.Request, error) { - location := GetLocation(resp) - if location == "" { - return nil, NewErrorWithResponse("autorest", "NewPollingRequest", resp, "Location header missing from response that requires polling") - } - - req, err := Prepare(&http.Request{Cancel: cancel}, - AsGet(), - WithBaseURL(location)) - if err != nil { - return nil, NewErrorWithError(err, "autorest", "NewPollingRequest", nil, "Failure creating poll request to %s", location) - } - - return req, nil -} diff --git a/vendor/github.com/Azure/go-autorest/autorest/azure/async.go b/vendor/github.com/Azure/go-autorest/autorest/azure/async.go deleted file mode 100644 index 6e076981f2..0000000000 --- a/vendor/github.com/Azure/go-autorest/autorest/azure/async.go +++ /dev/null @@ -1,308 +0,0 @@ -package azure - -import ( - "bytes" - "fmt" - "io/ioutil" - "net/http" - "strings" - "time" - - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/date" -) - -const ( - headerAsyncOperation = "Azure-AsyncOperation" -) - -const ( - methodDelete = "DELETE" - methodPatch = "PATCH" - methodPost = "POST" - methodPut = "PUT" - methodGet = "GET" - - operationInProgress string = "InProgress" - operationCanceled string = "Canceled" - operationFailed string = "Failed" - operationSucceeded string = "Succeeded" -) - -// DoPollForAsynchronous returns a SendDecorator that polls if the http.Response is for an Azure -// long-running operation. It will delay between requests for the duration specified in the -// RetryAfter header or, if the header is absent, the passed delay. Polling may be canceled by -// closing the optional channel on the http.Request. -func DoPollForAsynchronous(delay time.Duration) autorest.SendDecorator { - return func(s autorest.Sender) autorest.Sender { - return autorest.SenderFunc(func(r *http.Request) (resp *http.Response, err error) { - resp, err = s.Do(r) - if err != nil { - return resp, err - } - pollingCodes := []int{http.StatusAccepted, http.StatusCreated, http.StatusOK} - if !autorest.ResponseHasStatusCode(resp, pollingCodes...) { - return resp, nil - } - - ps := pollingState{} - for err == nil { - err = updatePollingState(resp, &ps) - if err != nil { - break - } - if ps.hasTerminated() { - if !ps.hasSucceeded() { - err = ps - } - break - } - - r, err = newPollingRequest(resp, ps) - if err != nil { - return resp, err - } - - delay = autorest.GetRetryAfter(resp, delay) - resp, err = autorest.SendWithSender(s, r, - autorest.AfterDelay(delay)) - } - - return resp, err - }) - } -} - -func getAsyncOperation(resp *http.Response) string { - return resp.Header.Get(http.CanonicalHeaderKey(headerAsyncOperation)) -} - -func hasSucceeded(state string) bool { - return state == operationSucceeded -} - -func hasTerminated(state string) bool { - switch state { - case operationCanceled, operationFailed, operationSucceeded: - return true - default: - return false - } -} - -func hasFailed(state string) bool { - return state == operationFailed -} - -type provisioningTracker interface { - state() string - hasSucceeded() bool - hasTerminated() bool -} - -type operationResource struct { - // Note: - // The specification states services should return the "id" field. However some return it as - // "operationId". - ID string `json:"id"` - OperationID string `json:"operationId"` - Name string `json:"name"` - Status string `json:"status"` - Properties map[string]interface{} `json:"properties"` - OperationError ServiceError `json:"error"` - StartTime date.Time `json:"startTime"` - EndTime date.Time `json:"endTime"` - PercentComplete float64 `json:"percentComplete"` -} - -func (or operationResource) state() string { - return or.Status -} - -func (or operationResource) hasSucceeded() bool { - return hasSucceeded(or.state()) -} - -func (or operationResource) hasTerminated() bool { - return hasTerminated(or.state()) -} - -type provisioningProperties struct { - ProvisioningState string `json:"provisioningState"` -} - -type provisioningStatus struct { - Properties provisioningProperties `json:"properties,omitempty"` - ProvisioningError ServiceError `json:"error,omitempty"` -} - -func (ps provisioningStatus) state() string { - return ps.Properties.ProvisioningState -} - -func (ps provisioningStatus) hasSucceeded() bool { - return hasSucceeded(ps.state()) -} - -func (ps provisioningStatus) hasTerminated() bool { - return hasTerminated(ps.state()) -} - -func (ps provisioningStatus) hasProvisioningError() bool { - return ps.ProvisioningError != ServiceError{} -} - -type pollingResponseFormat string - -const ( - usesOperationResponse pollingResponseFormat = "OperationResponse" - usesProvisioningStatus pollingResponseFormat = "ProvisioningStatus" - formatIsUnknown pollingResponseFormat = "" -) - -type pollingState struct { - responseFormat pollingResponseFormat - uri string - state string - code string - message string -} - -func (ps pollingState) hasSucceeded() bool { - return hasSucceeded(ps.state) -} - -func (ps pollingState) hasTerminated() bool { - return hasTerminated(ps.state) -} - -func (ps pollingState) hasFailed() bool { - return hasFailed(ps.state) -} - -func (ps pollingState) Error() string { - return fmt.Sprintf("Long running operation terminated with status '%s': Code=%q Message=%q", ps.state, ps.code, ps.message) -} - -// updatePollingState maps the operation status -- retrieved from either a provisioningState -// field, the status field of an OperationResource, or inferred from the HTTP status code -- -// into a well-known states. Since the process begins from the initial request, the state -// always comes from either a the provisioningState returned or is inferred from the HTTP -// status code. Subsequent requests will read an Azure OperationResource object if the -// service initially returned the Azure-AsyncOperation header. The responseFormat field notes -// the expected response format. -func updatePollingState(resp *http.Response, ps *pollingState) error { - // Determine the response shape - // -- The first response will always be a provisioningStatus response; only the polling requests, - // depending on the header returned, may be something otherwise. - var pt provisioningTracker - if ps.responseFormat == usesOperationResponse { - pt = &operationResource{} - } else { - pt = &provisioningStatus{} - } - - // If this is the first request (that is, the polling response shape is unknown), determine how - // to poll and what to expect - if ps.responseFormat == formatIsUnknown { - req := resp.Request - if req == nil { - return autorest.NewError("azure", "updatePollingState", "Azure Polling Error - Original HTTP request is missing") - } - - // Prefer the Azure-AsyncOperation header - ps.uri = getAsyncOperation(resp) - if ps.uri != "" { - ps.responseFormat = usesOperationResponse - } else { - ps.responseFormat = usesProvisioningStatus - } - - // Else, use the Location header - if ps.uri == "" { - ps.uri = autorest.GetLocation(resp) - } - - // Lastly, requests against an existing resource, use the last request URI - if ps.uri == "" { - m := strings.ToUpper(req.Method) - if m == methodPatch || m == methodPut || m == methodGet { - ps.uri = req.URL.String() - } - } - } - - // Read and interpret the response (saving the Body in case no polling is necessary) - b := &bytes.Buffer{} - err := autorest.Respond(resp, - autorest.ByCopying(b), - autorest.ByUnmarshallingJSON(pt), - autorest.ByClosing()) - resp.Body = ioutil.NopCloser(b) - if err != nil { - return err - } - - // Interpret the results - // -- Terminal states apply regardless - // -- Unknown states are per-service inprogress states - // -- Otherwise, infer state from HTTP status code - if pt.hasTerminated() { - ps.state = pt.state() - } else if pt.state() != "" { - ps.state = operationInProgress - } else { - switch resp.StatusCode { - case http.StatusAccepted: - ps.state = operationInProgress - - case http.StatusNoContent, http.StatusCreated, http.StatusOK: - ps.state = operationSucceeded - - default: - ps.state = operationFailed - } - } - - if ps.state == operationInProgress && ps.uri == "" { - return autorest.NewError("azure", "updatePollingState", "Azure Polling Error - Unable to obtain polling URI for %s %s", resp.Request.Method, resp.Request.URL) - } - - // For failed operation, check for error code and message in - // -- Operation resource - // -- Response - // -- Otherwise, Unknown - if ps.hasFailed() { - if ps.responseFormat == usesOperationResponse { - or := pt.(*operationResource) - ps.code = or.OperationError.Code - ps.message = or.OperationError.Message - } else { - p := pt.(*provisioningStatus) - if p.hasProvisioningError() { - ps.code = p.ProvisioningError.Code - ps.message = p.ProvisioningError.Message - } else { - ps.code = "Unknown" - ps.message = "None" - } - } - } - return nil -} - -func newPollingRequest(resp *http.Response, ps pollingState) (*http.Request, error) { - req := resp.Request - if req == nil { - return nil, autorest.NewError("azure", "newPollingRequest", "Azure Polling Error - Original HTTP request is missing") - } - - reqPoll, err := autorest.Prepare(&http.Request{Cancel: req.Cancel}, - autorest.AsGet(), - autorest.WithBaseURL(ps.uri)) - if err != nil { - return nil, autorest.NewErrorWithError(err, "azure", "newPollingRequest", nil, "Failure creating poll request to %s", ps.uri) - } - - return reqPoll, nil -} diff --git a/vendor/github.com/Azure/go-autorest/autorest/azure/azure.go b/vendor/github.com/Azure/go-autorest/autorest/azure/azure.go deleted file mode 100644 index 3f4d13421a..0000000000 --- a/vendor/github.com/Azure/go-autorest/autorest/azure/azure.go +++ /dev/null @@ -1,180 +0,0 @@ -/* -Package azure provides Azure-specific implementations used with AutoRest. - -See the included examples for more detail. -*/ -package azure - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "net/http" - "strconv" - - "github.com/Azure/go-autorest/autorest" -) - -const ( - // HeaderClientID is the Azure extension header to set a user-specified request ID. - HeaderClientID = "x-ms-client-request-id" - - // HeaderReturnClientID is the Azure extension header to set if the user-specified request ID - // should be included in the response. - HeaderReturnClientID = "x-ms-return-client-request-id" - - // HeaderRequestID is the Azure extension header of the service generated request ID returned - // in the response. - HeaderRequestID = "x-ms-request-id" -) - -// ServiceError encapsulates the error response from an Azure service. -type ServiceError struct { - Code string `json:"code"` - Message string `json:"message"` - Details *[]interface{} `json:"details"` -} - -func (se ServiceError) Error() string { - if se.Details != nil { - d, err := json.Marshal(*(se.Details)) - if err != nil { - return fmt.Sprintf("Code=%q Message=%q Details=%v", se.Code, se.Message, *se.Details) - } - return fmt.Sprintf("Code=%q Message=%q Details=%v", se.Code, se.Message, string(d)) - } - return fmt.Sprintf("Code=%q Message=%q", se.Code, se.Message) -} - -// RequestError describes an error response returned by Azure service. -type RequestError struct { - autorest.DetailedError - - // The error returned by the Azure service. - ServiceError *ServiceError `json:"error"` - - // The request id (from the x-ms-request-id-header) of the request. - RequestID string -} - -// Error returns a human-friendly error message from service error. -func (e RequestError) Error() string { - return fmt.Sprintf("autorest/azure: Service returned an error. Status=%v %v", - e.StatusCode, e.ServiceError) -} - -// IsAzureError returns true if the passed error is an Azure Service error; false otherwise. -func IsAzureError(e error) bool { - _, ok := e.(*RequestError) - return ok -} - -// NewErrorWithError creates a new Error conforming object from the -// passed packageType, method, statusCode of the given resp (UndefinedStatusCode -// if resp is nil), message, and original error. message is treated as a format -// string to which the optional args apply. -func NewErrorWithError(original error, packageType string, method string, resp *http.Response, message string, args ...interface{}) RequestError { - if v, ok := original.(*RequestError); ok { - return *v - } - - statusCode := autorest.UndefinedStatusCode - if resp != nil { - statusCode = resp.StatusCode - } - return RequestError{ - DetailedError: autorest.DetailedError{ - Original: original, - PackageType: packageType, - Method: method, - StatusCode: statusCode, - Message: fmt.Sprintf(message, args...), - }, - } -} - -// WithReturningClientID returns a PrepareDecorator that adds an HTTP extension header of -// x-ms-client-request-id whose value is the passed, undecorated UUID (e.g., -// "0F39878C-5F76-4DB8-A25D-61D2C193C3CA"). It also sets the x-ms-return-client-request-id -// header to true such that UUID accompanies the http.Response. -func WithReturningClientID(uuid string) autorest.PrepareDecorator { - preparer := autorest.CreatePreparer( - WithClientID(uuid), - WithReturnClientID(true)) - - return func(p autorest.Preparer) autorest.Preparer { - return autorest.PreparerFunc(func(r *http.Request) (*http.Request, error) { - r, err := p.Prepare(r) - if err != nil { - return r, err - } - return preparer.Prepare(r) - }) - } -} - -// WithClientID returns a PrepareDecorator that adds an HTTP extension header of -// x-ms-client-request-id whose value is passed, undecorated UUID (e.g., -// "0F39878C-5F76-4DB8-A25D-61D2C193C3CA"). -func WithClientID(uuid string) autorest.PrepareDecorator { - return autorest.WithHeader(HeaderClientID, uuid) -} - -// WithReturnClientID returns a PrepareDecorator that adds an HTTP extension header of -// x-ms-return-client-request-id whose boolean value indicates if the value of the -// x-ms-client-request-id header should be included in the http.Response. -func WithReturnClientID(b bool) autorest.PrepareDecorator { - return autorest.WithHeader(HeaderReturnClientID, strconv.FormatBool(b)) -} - -// ExtractClientID extracts the client identifier from the x-ms-client-request-id header set on the -// http.Request sent to the service (and returned in the http.Response) -func ExtractClientID(resp *http.Response) string { - return autorest.ExtractHeaderValue(HeaderClientID, resp) -} - -// ExtractRequestID extracts the Azure server generated request identifier from the -// x-ms-request-id header. -func ExtractRequestID(resp *http.Response) string { - return autorest.ExtractHeaderValue(HeaderRequestID, resp) -} - -// WithErrorUnlessStatusCode returns a RespondDecorator that emits an -// azure.RequestError by reading the response body unless the response HTTP status code -// is among the set passed. -// -// If there is a chance service may return responses other than the Azure error -// format and the response cannot be parsed into an error, a decoding error will -// be returned containing the response body. In any case, the Responder will -// return an error if the status code is not satisfied. -// -// If this Responder returns an error, the response body will be replaced with -// an in-memory reader, which needs no further closing. -func WithErrorUnlessStatusCode(codes ...int) autorest.RespondDecorator { - return func(r autorest.Responder) autorest.Responder { - return autorest.ResponderFunc(func(resp *http.Response) error { - err := r.Respond(resp) - if err == nil && !autorest.ResponseHasStatusCode(resp, codes...) { - var e RequestError - defer resp.Body.Close() - - // Copy and replace the Body in case it does not contain an error object. - // This will leave the Body available to the caller. - b, decodeErr := autorest.CopyAndDecode(autorest.EncodedAsJSON, resp.Body, &e) - resp.Body = ioutil.NopCloser(&b) - if decodeErr != nil { - return fmt.Errorf("autorest/azure: error response cannot be parsed: %q error: %v", b.String(), decodeErr) - } else if e.ServiceError == nil { - e.ServiceError = &ServiceError{Code: "Unknown", Message: "Unknown service error"} - } - - e.RequestID = ExtractRequestID(resp) - if e.StatusCode == nil { - e.StatusCode = resp.StatusCode - } - err = &e - } - return err - }) - } -} diff --git a/vendor/github.com/Azure/go-autorest/autorest/azure/config.go b/vendor/github.com/Azure/go-autorest/autorest/azure/config.go deleted file mode 100644 index bea30b0d67..0000000000 --- a/vendor/github.com/Azure/go-autorest/autorest/azure/config.go +++ /dev/null @@ -1,13 +0,0 @@ -package azure - -import ( - "net/url" -) - -// OAuthConfig represents the endpoints needed -// in OAuth operations -type OAuthConfig struct { - AuthorizeEndpoint url.URL - TokenEndpoint url.URL - DeviceCodeEndpoint url.URL -} diff --git a/vendor/github.com/Azure/go-autorest/autorest/azure/devicetoken.go b/vendor/github.com/Azure/go-autorest/autorest/azure/devicetoken.go deleted file mode 100644 index e1d5498a80..0000000000 --- a/vendor/github.com/Azure/go-autorest/autorest/azure/devicetoken.go +++ /dev/null @@ -1,193 +0,0 @@ -package azure - -/* - This file is largely based on rjw57/oauth2device's code, with the follow differences: - * scope -> resource, and only allow a single one - * receive "Message" in the DeviceCode struct and show it to users as the prompt - * azure-xplat-cli has the following behavior that this emulates: - - does not send client_secret during the token exchange - - sends resource again in the token exchange request -*/ - -import ( - "fmt" - "net/http" - "net/url" - "time" - - "github.com/Azure/go-autorest/autorest" -) - -const ( - logPrefix = "autorest/azure/devicetoken:" -) - -var ( - // ErrDeviceGeneric represents an unknown error from the token endpoint when using device flow - ErrDeviceGeneric = fmt.Errorf("%s Error while retrieving OAuth token: Unknown Error", logPrefix) - - // ErrDeviceAccessDenied represents an access denied error from the token endpoint when using device flow - ErrDeviceAccessDenied = fmt.Errorf("%s Error while retrieving OAuth token: Access Denied", logPrefix) - - // ErrDeviceAuthorizationPending represents the server waiting on the user to complete the device flow - ErrDeviceAuthorizationPending = fmt.Errorf("%s Error while retrieving OAuth token: Authorization Pending", logPrefix) - - // ErrDeviceCodeExpired represents the server timing out and expiring the code during device flow - ErrDeviceCodeExpired = fmt.Errorf("%s Error while retrieving OAuth token: Code Expired", logPrefix) - - // ErrDeviceSlowDown represents the service telling us we're polling too often during device flow - ErrDeviceSlowDown = fmt.Errorf("%s Error while retrieving OAuth token: Slow Down", logPrefix) - - errCodeSendingFails = "Error occurred while sending request for Device Authorization Code" - errCodeHandlingFails = "Error occurred while handling response from the Device Endpoint" - errTokenSendingFails = "Error occurred while sending request with device code for a token" - errTokenHandlingFails = "Error occurred while handling response from the Token Endpoint (during device flow)" -) - -// DeviceCode is the object returned by the device auth endpoint -// It contains information to instruct the user to complete the auth flow -type DeviceCode struct { - DeviceCode *string `json:"device_code,omitempty"` - UserCode *string `json:"user_code,omitempty"` - VerificationURL *string `json:"verification_url,omitempty"` - ExpiresIn *int64 `json:"expires_in,string,omitempty"` - Interval *int64 `json:"interval,string,omitempty"` - - Message *string `json:"message"` // Azure specific - Resource string // store the following, stored when initiating, used when exchanging - OAuthConfig OAuthConfig - ClientID string -} - -// TokenError is the object returned by the token exchange endpoint -// when something is amiss -type TokenError struct { - Error *string `json:"error,omitempty"` - ErrorCodes []int `json:"error_codes,omitempty"` - ErrorDescription *string `json:"error_description,omitempty"` - Timestamp *string `json:"timestamp,omitempty"` - TraceID *string `json:"trace_id,omitempty"` -} - -// DeviceToken is the object return by the token exchange endpoint -// It can either look like a Token or an ErrorToken, so put both here -// and check for presence of "Error" to know if we are in error state -type deviceToken struct { - Token - TokenError -} - -// InitiateDeviceAuth initiates a device auth flow. It returns a DeviceCode -// that can be used with CheckForUserCompletion or WaitForUserCompletion. -func InitiateDeviceAuth(client *autorest.Client, oauthConfig OAuthConfig, clientID, resource string) (*DeviceCode, error) { - req, _ := autorest.Prepare( - &http.Request{}, - autorest.AsPost(), - autorest.AsFormURLEncoded(), - autorest.WithBaseURL(oauthConfig.DeviceCodeEndpoint.String()), - autorest.WithFormData(url.Values{ - "client_id": []string{clientID}, - "resource": []string{resource}, - }), - ) - - resp, err := autorest.SendWithSender(client, req) - if err != nil { - return nil, fmt.Errorf("%s %s: %s", logPrefix, errCodeSendingFails, err) - } - - var code DeviceCode - err = autorest.Respond( - resp, - autorest.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&code), - autorest.ByClosing()) - if err != nil { - return nil, fmt.Errorf("%s %s: %s", logPrefix, errCodeHandlingFails, err) - } - - code.ClientID = clientID - code.Resource = resource - code.OAuthConfig = oauthConfig - - return &code, nil -} - -// CheckForUserCompletion takes a DeviceCode and checks with the Azure AD OAuth endpoint -// to see if the device flow has: been completed, timed out, or otherwise failed -func CheckForUserCompletion(client *autorest.Client, code *DeviceCode) (*Token, error) { - req, _ := autorest.Prepare( - &http.Request{}, - autorest.AsPost(), - autorest.AsFormURLEncoded(), - autorest.WithBaseURL(code.OAuthConfig.TokenEndpoint.String()), - autorest.WithFormData(url.Values{ - "client_id": []string{code.ClientID}, - "code": []string{*code.DeviceCode}, - "grant_type": []string{OAuthGrantTypeDeviceCode}, - "resource": []string{code.Resource}, - }), - ) - - resp, err := autorest.SendWithSender(client, req) - if err != nil { - return nil, fmt.Errorf("%s %s: %s", logPrefix, errTokenSendingFails, err) - } - - var token deviceToken - err = autorest.Respond( - resp, - autorest.WithErrorUnlessStatusCode(http.StatusOK, http.StatusBadRequest), - autorest.ByUnmarshallingJSON(&token), - autorest.ByClosing()) - if err != nil { - return nil, fmt.Errorf("%s %s: %s", logPrefix, errTokenHandlingFails, err) - } - - if token.Error == nil { - return &token.Token, nil - } - - switch *token.Error { - case "authorization_pending": - return nil, ErrDeviceAuthorizationPending - case "slow_down": - return nil, ErrDeviceSlowDown - case "access_denied": - return nil, ErrDeviceAccessDenied - case "code_expired": - return nil, ErrDeviceCodeExpired - default: - return nil, ErrDeviceGeneric - } -} - -// WaitForUserCompletion calls CheckForUserCompletion repeatedly until a token is granted or an error state occurs. -// This prevents the user from looping and checking against 'ErrDeviceAuthorizationPending'. -func WaitForUserCompletion(client *autorest.Client, code *DeviceCode) (*Token, error) { - intervalDuration := time.Duration(*code.Interval) * time.Second - waitDuration := intervalDuration - - for { - token, err := CheckForUserCompletion(client, code) - - if err == nil { - return token, nil - } - - switch err { - case ErrDeviceSlowDown: - waitDuration += waitDuration - case ErrDeviceAuthorizationPending: - // noop - default: // everything else is "fatal" to us - return nil, err - } - - if waitDuration > (intervalDuration * 3) { - return nil, fmt.Errorf("%s Error waiting for user to complete device flow. Server told us to slow_down too much", logPrefix) - } - - time.Sleep(waitDuration) - } -} diff --git a/vendor/github.com/Azure/go-autorest/autorest/azure/environments.go b/vendor/github.com/Azure/go-autorest/autorest/azure/environments.go deleted file mode 100644 index 4701b43764..0000000000 --- a/vendor/github.com/Azure/go-autorest/autorest/azure/environments.go +++ /dev/null @@ -1,167 +0,0 @@ -package azure - -import ( - "fmt" - "net/url" - "strings" -) - -const ( - activeDirectoryAPIVersion = "1.0" -) - -var environments = map[string]Environment{ - "AZURECHINACLOUD": ChinaCloud, - "AZUREGERMANCLOUD": GermanCloud, - "AZUREPUBLICCLOUD": PublicCloud, - "AZUREUSGOVERNMENTCLOUD": USGovernmentCloud, -} - -// Environment represents a set of endpoints for each of Azure's Clouds. -type Environment struct { - Name string `json:"name"` - ManagementPortalURL string `json:"managementPortalURL"` - PublishSettingsURL string `json:"publishSettingsURL"` - ServiceManagementEndpoint string `json:"serviceManagementEndpoint"` - ResourceManagerEndpoint string `json:"resourceManagerEndpoint"` - ActiveDirectoryEndpoint string `json:"activeDirectoryEndpoint"` - GalleryEndpoint string `json:"galleryEndpoint"` - KeyVaultEndpoint string `json:"keyVaultEndpoint"` - GraphEndpoint string `json:"graphEndpoint"` - StorageEndpointSuffix string `json:"storageEndpointSuffix"` - SQLDatabaseDNSSuffix string `json:"sqlDatabaseDNSSuffix"` - TrafficManagerDNSSuffix string `json:"trafficManagerDNSSuffix"` - KeyVaultDNSSuffix string `json:"keyVaultDNSSuffix"` - ServiceBusEndpointSuffix string `json:"serviceBusEndpointSuffix"` - ServiceManagementVMDNSSuffix string `json:"serviceManagementVMDNSSuffix"` - ResourceManagerVMDNSSuffix string `json:"resourceManagerVMDNSSuffix"` - ContainerRegistryDNSSuffix string `json:"containerRegistryDNSSuffix"` -} - -var ( - // PublicCloud is the default public Azure cloud environment - PublicCloud = Environment{ - Name: "AzurePublicCloud", - ManagementPortalURL: "https://manage.windowsazure.com/", - PublishSettingsURL: "https://manage.windowsazure.com/publishsettings/index", - ServiceManagementEndpoint: "https://management.core.windows.net/", - ResourceManagerEndpoint: "https://management.azure.com/", - ActiveDirectoryEndpoint: "https://login.microsoftonline.com/", - GalleryEndpoint: "https://gallery.azure.com/", - KeyVaultEndpoint: "https://vault.azure.net/", - GraphEndpoint: "https://graph.windows.net/", - StorageEndpointSuffix: "core.windows.net", - SQLDatabaseDNSSuffix: "database.windows.net", - TrafficManagerDNSSuffix: "trafficmanager.net", - KeyVaultDNSSuffix: "vault.azure.net", - ServiceBusEndpointSuffix: "servicebus.azure.com", - ServiceManagementVMDNSSuffix: "cloudapp.net", - ResourceManagerVMDNSSuffix: "cloudapp.azure.com", - ContainerRegistryDNSSuffix: "azurecr.io", - } - - // USGovernmentCloud is the cloud environment for the US Government - USGovernmentCloud = Environment{ - Name: "AzureUSGovernmentCloud", - ManagementPortalURL: "https://manage.windowsazure.us/", - PublishSettingsURL: "https://manage.windowsazure.us/publishsettings/index", - ServiceManagementEndpoint: "https://management.core.usgovcloudapi.net/", - ResourceManagerEndpoint: "https://management.usgovcloudapi.net/", - ActiveDirectoryEndpoint: "https://login.microsoftonline.com/", - GalleryEndpoint: "https://gallery.usgovcloudapi.net/", - KeyVaultEndpoint: "https://vault.usgovcloudapi.net/", - GraphEndpoint: "https://graph.usgovcloudapi.net/", - StorageEndpointSuffix: "core.usgovcloudapi.net", - SQLDatabaseDNSSuffix: "database.usgovcloudapi.net", - TrafficManagerDNSSuffix: "usgovtrafficmanager.net", - KeyVaultDNSSuffix: "vault.usgovcloudapi.net", - ServiceBusEndpointSuffix: "servicebus.usgovcloudapi.net", - ServiceManagementVMDNSSuffix: "usgovcloudapp.net", - ResourceManagerVMDNSSuffix: "cloudapp.windowsazure.us", - ContainerRegistryDNSSuffix: "azurecr.io", - } - - // ChinaCloud is the cloud environment operated in China - ChinaCloud = Environment{ - Name: "AzureChinaCloud", - ManagementPortalURL: "https://manage.chinacloudapi.com/", - PublishSettingsURL: "https://manage.chinacloudapi.com/publishsettings/index", - ServiceManagementEndpoint: "https://management.core.chinacloudapi.cn/", - ResourceManagerEndpoint: "https://management.chinacloudapi.cn/", - ActiveDirectoryEndpoint: "https://login.chinacloudapi.cn/", - GalleryEndpoint: "https://gallery.chinacloudapi.cn/", - KeyVaultEndpoint: "https://vault.azure.cn/", - GraphEndpoint: "https://graph.chinacloudapi.cn/", - StorageEndpointSuffix: "core.chinacloudapi.cn", - SQLDatabaseDNSSuffix: "database.chinacloudapi.cn", - TrafficManagerDNSSuffix: "trafficmanager.cn", - KeyVaultDNSSuffix: "vault.azure.cn", - ServiceBusEndpointSuffix: "servicebus.chinacloudapi.net", - ServiceManagementVMDNSSuffix: "chinacloudapp.cn", - ResourceManagerVMDNSSuffix: "cloudapp.azure.cn", - ContainerRegistryDNSSuffix: "azurecr.io", - } - - // GermanCloud is the cloud environment operated in Germany - GermanCloud = Environment{ - Name: "AzureGermanCloud", - ManagementPortalURL: "http://portal.microsoftazure.de/", - PublishSettingsURL: "https://manage.microsoftazure.de/publishsettings/index", - ServiceManagementEndpoint: "https://management.core.cloudapi.de/", - ResourceManagerEndpoint: "https://management.microsoftazure.de/", - ActiveDirectoryEndpoint: "https://login.microsoftonline.de/", - GalleryEndpoint: "https://gallery.cloudapi.de/", - KeyVaultEndpoint: "https://vault.microsoftazure.de/", - GraphEndpoint: "https://graph.cloudapi.de/", - StorageEndpointSuffix: "core.cloudapi.de", - SQLDatabaseDNSSuffix: "database.cloudapi.de", - TrafficManagerDNSSuffix: "azuretrafficmanager.de", - KeyVaultDNSSuffix: "vault.microsoftazure.de", - ServiceBusEndpointSuffix: "servicebus.cloudapi.de", - ServiceManagementVMDNSSuffix: "azurecloudapp.de", - ResourceManagerVMDNSSuffix: "cloudapp.microsoftazure.de", - ContainerRegistryDNSSuffix: "azurecr.io", - } -) - -// EnvironmentFromName returns an Environment based on the common name specified -func EnvironmentFromName(name string) (Environment, error) { - name = strings.ToUpper(name) - env, ok := environments[name] - if !ok { - return env, fmt.Errorf("autorest/azure: There is no cloud environment matching the name %q", name) - } - return env, nil -} - -// OAuthConfigForTenant returns an OAuthConfig with tenant specific urls -func (env Environment) OAuthConfigForTenant(tenantID string) (*OAuthConfig, error) { - return OAuthConfigForTenant(env.ActiveDirectoryEndpoint, tenantID) -} - -// OAuthConfigForTenant returns an OAuthConfig with tenant specific urls for target cloud auth endpoint -func OAuthConfigForTenant(activeDirectoryEndpoint, tenantID string) (*OAuthConfig, error) { - template := "%s/oauth2/%s?api-version=%s" - u, err := url.Parse(activeDirectoryEndpoint) - if err != nil { - return nil, err - } - authorizeURL, err := u.Parse(fmt.Sprintf(template, tenantID, "authorize", activeDirectoryAPIVersion)) - if err != nil { - return nil, err - } - tokenURL, err := u.Parse(fmt.Sprintf(template, tenantID, "token", activeDirectoryAPIVersion)) - if err != nil { - return nil, err - } - deviceCodeURL, err := u.Parse(fmt.Sprintf(template, tenantID, "devicecode", activeDirectoryAPIVersion)) - if err != nil { - return nil, err - } - - return &OAuthConfig{ - AuthorizeEndpoint: *authorizeURL, - TokenEndpoint: *tokenURL, - DeviceCodeEndpoint: *deviceCodeURL, - }, nil -} diff --git a/vendor/github.com/Azure/go-autorest/autorest/azure/persist.go b/vendor/github.com/Azure/go-autorest/autorest/azure/persist.go deleted file mode 100644 index d5cf62ddc7..0000000000 --- a/vendor/github.com/Azure/go-autorest/autorest/azure/persist.go +++ /dev/null @@ -1,59 +0,0 @@ -package azure - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "os" - "path/filepath" -) - -// LoadToken restores a Token object from a file located at 'path'. -func LoadToken(path string) (*Token, error) { - file, err := os.Open(path) - if err != nil { - return nil, fmt.Errorf("failed to open file (%s) while loading token: %v", path, err) - } - defer file.Close() - - var token Token - - dec := json.NewDecoder(file) - if err = dec.Decode(&token); err != nil { - return nil, fmt.Errorf("failed to decode contents of file (%s) into Token representation: %v", path, err) - } - return &token, nil -} - -// SaveToken persists an oauth token at the given location on disk. -// It moves the new file into place so it can safely be used to replace an existing file -// that maybe accessed by multiple processes. -func SaveToken(path string, mode os.FileMode, token Token) error { - dir := filepath.Dir(path) - err := os.MkdirAll(dir, os.ModePerm) - if err != nil { - return fmt.Errorf("failed to create directory (%s) to store token in: %v", dir, err) - } - - newFile, err := ioutil.TempFile(dir, "token") - if err != nil { - return fmt.Errorf("failed to create the temp file to write the token: %v", err) - } - tempPath := newFile.Name() - - if err := json.NewEncoder(newFile).Encode(token); err != nil { - return fmt.Errorf("failed to encode token to file (%s) while saving token: %v", tempPath, err) - } - if err := newFile.Close(); err != nil { - return fmt.Errorf("failed to close temp file %s: %v", tempPath, err) - } - - // Atomic replace to avoid multi-writer file corruptions - if err := os.Rename(tempPath, path); err != nil { - return fmt.Errorf("failed to move temporary token to desired output location. src=%s dst=%s: %v", tempPath, path, err) - } - if err := os.Chmod(path, mode); err != nil { - return fmt.Errorf("failed to chmod the token file %s: %v", path, err) - } - return nil -} diff --git a/vendor/github.com/Azure/go-autorest/autorest/azure/token.go b/vendor/github.com/Azure/go-autorest/autorest/azure/token.go deleted file mode 100644 index cfcd030114..0000000000 --- a/vendor/github.com/Azure/go-autorest/autorest/azure/token.go +++ /dev/null @@ -1,363 +0,0 @@ -package azure - -import ( - "crypto/rand" - "crypto/rsa" - "crypto/sha1" - "crypto/x509" - "encoding/base64" - "fmt" - "net/http" - "net/url" - "strconv" - "time" - - "github.com/Azure/go-autorest/autorest" - "github.com/dgrijalva/jwt-go" -) - -const ( - defaultRefresh = 5 * time.Minute - tokenBaseDate = "1970-01-01T00:00:00Z" - - // OAuthGrantTypeDeviceCode is the "grant_type" identifier used in device flow - OAuthGrantTypeDeviceCode = "device_code" - - // OAuthGrantTypeClientCredentials is the "grant_type" identifier used in credential flows - OAuthGrantTypeClientCredentials = "client_credentials" - - // OAuthGrantTypeRefreshToken is the "grant_type" identifier used in refresh token flows - OAuthGrantTypeRefreshToken = "refresh_token" -) - -var expirationBase time.Time - -func init() { - expirationBase, _ = time.Parse(time.RFC3339, tokenBaseDate) -} - -// TokenRefreshCallback is the type representing callbacks that will be called after -// a successful token refresh -type TokenRefreshCallback func(Token) error - -// Token encapsulates the access token used to authorize Azure requests. -type Token struct { - AccessToken string `json:"access_token"` - RefreshToken string `json:"refresh_token"` - - ExpiresIn string `json:"expires_in"` - ExpiresOn string `json:"expires_on"` - NotBefore string `json:"not_before"` - - Resource string `json:"resource"` - Type string `json:"token_type"` -} - -// Expires returns the time.Time when the Token expires. -func (t Token) Expires() time.Time { - s, err := strconv.Atoi(t.ExpiresOn) - if err != nil { - s = -3600 - } - return expirationBase.Add(time.Duration(s) * time.Second).UTC() -} - -// IsExpired returns true if the Token is expired, false otherwise. -func (t Token) IsExpired() bool { - return t.WillExpireIn(0) -} - -// WillExpireIn returns true if the Token will expire after the passed time.Duration interval -// from now, false otherwise. -func (t Token) WillExpireIn(d time.Duration) bool { - return !t.Expires().After(time.Now().Add(d)) -} - -// WithAuthorization returns a PrepareDecorator that adds an HTTP Authorization header whose -// value is "Bearer " followed by the AccessToken of the Token. -func (t *Token) WithAuthorization() autorest.PrepareDecorator { - return func(p autorest.Preparer) autorest.Preparer { - return autorest.PreparerFunc(func(r *http.Request) (*http.Request, error) { - return (autorest.WithBearerAuthorization(t.AccessToken)(p)).Prepare(r) - }) - } -} - -// ServicePrincipalNoSecret represents a secret type that contains no secret -// meaning it is not valid for fetching a fresh token. This is used by Manual -type ServicePrincipalNoSecret struct { -} - -// SetAuthenticationValues is a method of the interface ServicePrincipalSecret -// It only returns an error for the ServicePrincipalNoSecret type -func (noSecret *ServicePrincipalNoSecret) SetAuthenticationValues(spt *ServicePrincipalToken, v *url.Values) error { - return fmt.Errorf("Manually created ServicePrincipalToken does not contain secret material to retrieve a new access token") -} - -// ServicePrincipalSecret is an interface that allows various secret mechanism to fill the form -// that is submitted when acquiring an oAuth token. -type ServicePrincipalSecret interface { - SetAuthenticationValues(spt *ServicePrincipalToken, values *url.Values) error -} - -// ServicePrincipalTokenSecret implements ServicePrincipalSecret for client_secret type authorization. -type ServicePrincipalTokenSecret struct { - ClientSecret string -} - -// SetAuthenticationValues is a method of the interface ServicePrincipalSecret. -// It will populate the form submitted during oAuth Token Acquisition using the client_secret. -func (tokenSecret *ServicePrincipalTokenSecret) SetAuthenticationValues(spt *ServicePrincipalToken, v *url.Values) error { - v.Set("client_secret", tokenSecret.ClientSecret) - return nil -} - -// ServicePrincipalCertificateSecret implements ServicePrincipalSecret for generic RSA cert auth with signed JWTs. -type ServicePrincipalCertificateSecret struct { - Certificate *x509.Certificate - PrivateKey *rsa.PrivateKey -} - -// SignJwt returns the JWT signed with the certificate's private key. -func (secret *ServicePrincipalCertificateSecret) SignJwt(spt *ServicePrincipalToken) (string, error) { - hasher := sha1.New() - _, err := hasher.Write(secret.Certificate.Raw) - if err != nil { - return "", err - } - - thumbprint := base64.URLEncoding.EncodeToString(hasher.Sum(nil)) - - // The jti (JWT ID) claim provides a unique identifier for the JWT. - jti := make([]byte, 20) - _, err = rand.Read(jti) - if err != nil { - return "", err - } - - token := jwt.New(jwt.SigningMethodRS256) - token.Header["x5t"] = thumbprint - token.Claims = jwt.MapClaims{ - "aud": spt.oauthConfig.TokenEndpoint.String(), - "iss": spt.clientID, - "sub": spt.clientID, - "jti": base64.URLEncoding.EncodeToString(jti), - "nbf": time.Now().Unix(), - "exp": time.Now().Add(time.Hour * 24).Unix(), - } - - signedString, err := token.SignedString(secret.PrivateKey) - return signedString, err -} - -// SetAuthenticationValues is a method of the interface ServicePrincipalSecret. -// It will populate the form submitted during oAuth Token Acquisition using a JWT signed with a certificate. -func (secret *ServicePrincipalCertificateSecret) SetAuthenticationValues(spt *ServicePrincipalToken, v *url.Values) error { - jwt, err := secret.SignJwt(spt) - if err != nil { - return err - } - - v.Set("client_assertion", jwt) - v.Set("client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer") - return nil -} - -// ServicePrincipalToken encapsulates a Token created for a Service Principal. -type ServicePrincipalToken struct { - Token - - secret ServicePrincipalSecret - oauthConfig OAuthConfig - clientID string - resource string - autoRefresh bool - refreshWithin time.Duration - sender autorest.Sender - - refreshCallbacks []TokenRefreshCallback -} - -// NewServicePrincipalTokenWithSecret create a ServicePrincipalToken using the supplied ServicePrincipalSecret implementation. -func NewServicePrincipalTokenWithSecret(oauthConfig OAuthConfig, id string, resource string, secret ServicePrincipalSecret, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) { - spt := &ServicePrincipalToken{ - oauthConfig: oauthConfig, - secret: secret, - clientID: id, - resource: resource, - autoRefresh: true, - refreshWithin: defaultRefresh, - sender: &http.Client{}, - refreshCallbacks: callbacks, - } - return spt, nil -} - -// NewServicePrincipalTokenFromManualToken creates a ServicePrincipalToken using the supplied token -func NewServicePrincipalTokenFromManualToken(oauthConfig OAuthConfig, clientID string, resource string, token Token, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) { - spt, err := NewServicePrincipalTokenWithSecret( - oauthConfig, - clientID, - resource, - &ServicePrincipalNoSecret{}, - callbacks...) - if err != nil { - return nil, err - } - - spt.Token = token - - return spt, nil -} - -// NewServicePrincipalToken creates a ServicePrincipalToken from the supplied Service Principal -// credentials scoped to the named resource. -func NewServicePrincipalToken(oauthConfig OAuthConfig, clientID string, secret string, resource string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) { - return NewServicePrincipalTokenWithSecret( - oauthConfig, - clientID, - resource, - &ServicePrincipalTokenSecret{ - ClientSecret: secret, - }, - callbacks..., - ) -} - -// NewServicePrincipalTokenFromCertificate create a ServicePrincipalToken from the supplied pkcs12 bytes. -func NewServicePrincipalTokenFromCertificate(oauthConfig OAuthConfig, clientID string, certificate *x509.Certificate, privateKey *rsa.PrivateKey, resource string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) { - return NewServicePrincipalTokenWithSecret( - oauthConfig, - clientID, - resource, - &ServicePrincipalCertificateSecret{ - PrivateKey: privateKey, - Certificate: certificate, - }, - callbacks..., - ) -} - -// EnsureFresh will refresh the token if it will expire within the refresh window (as set by -// RefreshWithin). -func (spt *ServicePrincipalToken) EnsureFresh() error { - if spt.WillExpireIn(spt.refreshWithin) { - return spt.Refresh() - } - return nil -} - -// InvokeRefreshCallbacks calls any TokenRefreshCallbacks that were added to the SPT during initialization -func (spt *ServicePrincipalToken) InvokeRefreshCallbacks(token Token) error { - if spt.refreshCallbacks != nil { - for _, callback := range spt.refreshCallbacks { - err := callback(spt.Token) - if err != nil { - return autorest.NewErrorWithError(err, - "azure.ServicePrincipalToken", "InvokeRefreshCallbacks", nil, "A TokenRefreshCallback handler returned an error") - } - } - } - return nil -} - -// Refresh obtains a fresh token for the Service Principal. -func (spt *ServicePrincipalToken) Refresh() error { - return spt.refreshInternal(spt.resource) -} - -// RefreshExchange refreshes the token, but for a different resource. -func (spt *ServicePrincipalToken) RefreshExchange(resource string) error { - return spt.refreshInternal(resource) -} - -func (spt *ServicePrincipalToken) refreshInternal(resource string) error { - v := url.Values{} - v.Set("client_id", spt.clientID) - v.Set("resource", resource) - - if spt.RefreshToken != "" { - v.Set("grant_type", OAuthGrantTypeRefreshToken) - v.Set("refresh_token", spt.RefreshToken) - } else { - v.Set("grant_type", OAuthGrantTypeClientCredentials) - err := spt.secret.SetAuthenticationValues(spt, &v) - if err != nil { - return err - } - } - - req, _ := autorest.Prepare(&http.Request{}, - autorest.AsPost(), - autorest.AsFormURLEncoded(), - autorest.WithBaseURL(spt.oauthConfig.TokenEndpoint.String()), - autorest.WithFormData(v)) - - resp, err := autorest.SendWithSender(spt.sender, req) - if err != nil { - return autorest.NewErrorWithError(err, - "azure.ServicePrincipalToken", "Refresh", resp, "Failure sending request for Service Principal %s", - spt.clientID) - } - - var newToken Token - err = autorest.Respond(resp, - autorest.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&newToken), - autorest.ByClosing()) - if err != nil { - return autorest.NewErrorWithError(err, - "azure.ServicePrincipalToken", "Refresh", resp, "Failure handling response to Service Principal %s request", - spt.clientID) - } - - spt.Token = newToken - - err = spt.InvokeRefreshCallbacks(newToken) - if err != nil { - // its already wrapped inside InvokeRefreshCallbacks - return err - } - - return nil -} - -// SetAutoRefresh enables or disables automatic refreshing of stale tokens. -func (spt *ServicePrincipalToken) SetAutoRefresh(autoRefresh bool) { - spt.autoRefresh = autoRefresh -} - -// SetRefreshWithin sets the interval within which if the token will expire, EnsureFresh will -// refresh the token. -func (spt *ServicePrincipalToken) SetRefreshWithin(d time.Duration) { - spt.refreshWithin = d - return -} - -// SetSender sets the autorest.Sender used when obtaining the Service Principal token. An -// undecorated http.Client is used by default. -func (spt *ServicePrincipalToken) SetSender(s autorest.Sender) { - spt.sender = s -} - -// WithAuthorization returns a PrepareDecorator that adds an HTTP Authorization header whose -// value is "Bearer " followed by the AccessToken of the ServicePrincipalToken. -// -// By default, the token will automatically refresh if nearly expired (as determined by the -// RefreshWithin interval). Use the AutoRefresh method to enable or disable automatically refreshing -// tokens. -func (spt *ServicePrincipalToken) WithAuthorization() autorest.PrepareDecorator { - return func(p autorest.Preparer) autorest.Preparer { - return autorest.PreparerFunc(func(r *http.Request) (*http.Request, error) { - if spt.autoRefresh { - err := spt.EnsureFresh() - if err != nil { - return r, autorest.NewErrorWithError(err, - "azure.ServicePrincipalToken", "WithAuthorization", nil, "Failed to refresh Service Principal Token for request to %s", - r.URL) - } - } - return (autorest.WithBearerAuthorization(spt.AccessToken)(p)).Prepare(r) - }) - } -} diff --git a/vendor/github.com/Azure/go-autorest/autorest/client.go b/vendor/github.com/Azure/go-autorest/autorest/client.go deleted file mode 100644 index b5f94b5c3c..0000000000 --- a/vendor/github.com/Azure/go-autorest/autorest/client.go +++ /dev/null @@ -1,235 +0,0 @@ -package autorest - -import ( - "bytes" - "fmt" - "io" - "io/ioutil" - "log" - "net/http" - "net/http/cookiejar" - "runtime" - "time" -) - -const ( - // DefaultPollingDelay is a reasonable delay between polling requests. - DefaultPollingDelay = 60 * time.Second - - // DefaultPollingDuration is a reasonable total polling duration. - DefaultPollingDuration = 15 * time.Minute - - // DefaultRetryAttempts is number of attempts for retry status codes (5xx). - DefaultRetryAttempts = 3 -) - -var ( - // defaultUserAgent builds a string containing the Go version, system archityecture and OS, - // and the go-autorest version. - defaultUserAgent = fmt.Sprintf("Go/%s (%s-%s) go-autorest/%s", - runtime.Version(), - runtime.GOARCH, - runtime.GOOS, - Version(), - ) - - statusCodesForRetry = []int{ - http.StatusRequestTimeout, // 408 - http.StatusInternalServerError, // 500 - http.StatusBadGateway, // 502 - http.StatusServiceUnavailable, // 503 - http.StatusGatewayTimeout, // 504 - } -) - -const ( - requestFormat = `HTTP Request Begin =================================================== -%s -===================================================== HTTP Request End -` - responseFormat = `HTTP Response Begin =================================================== -%s -===================================================== HTTP Response End -` -) - -// Response serves as the base for all responses from generated clients. It provides access to the -// last http.Response. -type Response struct { - *http.Response `json:"-"` -} - -// LoggingInspector implements request and response inspectors that log the full request and -// response to a supplied log. -type LoggingInspector struct { - Logger *log.Logger -} - -// WithInspection returns a PrepareDecorator that emits the http.Request to the supplied logger. The -// body is restored after being emitted. -// -// Note: Since it reads the entire Body, this decorator should not be used where body streaming is -// important. It is best used to trace JSON or similar body values. -func (li LoggingInspector) WithInspection() PrepareDecorator { - return func(p Preparer) Preparer { - return PreparerFunc(func(r *http.Request) (*http.Request, error) { - var body, b bytes.Buffer - - defer r.Body.Close() - - r.Body = ioutil.NopCloser(io.TeeReader(r.Body, &body)) - if err := r.Write(&b); err != nil { - return nil, fmt.Errorf("Failed to write response: %v", err) - } - - li.Logger.Printf(requestFormat, b.String()) - - r.Body = ioutil.NopCloser(&body) - return p.Prepare(r) - }) - } -} - -// ByInspecting returns a RespondDecorator that emits the http.Response to the supplied logger. The -// body is restored after being emitted. -// -// Note: Since it reads the entire Body, this decorator should not be used where body streaming is -// important. It is best used to trace JSON or similar body values. -func (li LoggingInspector) ByInspecting() RespondDecorator { - return func(r Responder) Responder { - return ResponderFunc(func(resp *http.Response) error { - var body, b bytes.Buffer - defer resp.Body.Close() - resp.Body = ioutil.NopCloser(io.TeeReader(resp.Body, &body)) - if err := resp.Write(&b); err != nil { - return fmt.Errorf("Failed to write response: %v", err) - } - - li.Logger.Printf(responseFormat, b.String()) - - resp.Body = ioutil.NopCloser(&body) - return r.Respond(resp) - }) - } -} - -// Client is the base for autorest generated clients. It provides default, "do nothing" -// implementations of an Authorizer, RequestInspector, and ResponseInspector. It also returns the -// standard, undecorated http.Client as a default Sender. -// -// Generated clients should also use Error (see NewError and NewErrorWithError) for errors and -// return responses that compose with Response. -// -// Most customization of generated clients is best achieved by supplying a custom Authorizer, custom -// RequestInspector, and / or custom ResponseInspector. Users may log requests, implement circuit -// breakers (see https://msdn.microsoft.com/en-us/library/dn589784.aspx) or otherwise influence -// sending the request by providing a decorated Sender. -type Client struct { - Authorizer Authorizer - Sender Sender - RequestInspector PrepareDecorator - ResponseInspector RespondDecorator - - // PollingDelay sets the polling frequency used in absence of a Retry-After HTTP header - PollingDelay time.Duration - - // PollingDuration sets the maximum polling time after which an error is returned. - PollingDuration time.Duration - - // RetryAttempts sets the default number of retry attempts for client. - RetryAttempts int - - // RetryDuration sets the delay duration for retries. - RetryDuration time.Duration - - // UserAgent, if not empty, will be set as the HTTP User-Agent header on all requests sent - // through the Do method. - UserAgent string - - Jar http.CookieJar -} - -// NewClientWithUserAgent returns an instance of a Client with the UserAgent set to the passed -// string. -func NewClientWithUserAgent(ua string) Client { - c := Client{ - PollingDelay: DefaultPollingDelay, - PollingDuration: DefaultPollingDuration, - RetryAttempts: DefaultRetryAttempts, - RetryDuration: 30 * time.Second, - UserAgent: defaultUserAgent, - } - c.AddToUserAgent(ua) - return c -} - -// AddToUserAgent adds an extension to the current user agent -func (c *Client) AddToUserAgent(extension string) error { - if extension != "" { - c.UserAgent = fmt.Sprintf("%s %s", c.UserAgent, extension) - return nil - } - return fmt.Errorf("Extension was empty, User Agent stayed as %s", c.UserAgent) -} - -// Do implements the Sender interface by invoking the active Sender after applying authorization. -// If Sender is not set, it uses a new instance of http.Client. In both cases it will, if UserAgent -// is set, apply set the User-Agent header. -func (c Client) Do(r *http.Request) (*http.Response, error) { - if r.UserAgent() == "" { - r, _ = Prepare(r, - WithUserAgent(c.UserAgent)) - } - r, err := Prepare(r, - c.WithInspection(), - c.WithAuthorization()) - if err != nil { - return nil, NewErrorWithError(err, "autorest/Client", "Do", nil, "Preparing request failed") - } - resp, err := SendWithSender(c.sender(), r, - DoRetryForStatusCodes(c.RetryAttempts, c.RetryDuration, statusCodesForRetry...)) - Respond(resp, - c.ByInspecting()) - return resp, err -} - -// sender returns the Sender to which to send requests. -func (c Client) sender() Sender { - if c.Sender == nil { - j, _ := cookiejar.New(nil) - return &http.Client{Jar: j} - } - return c.Sender -} - -// WithAuthorization is a convenience method that returns the WithAuthorization PrepareDecorator -// from the current Authorizer. If not Authorizer is set, it uses the NullAuthorizer. -func (c Client) WithAuthorization() PrepareDecorator { - return c.authorizer().WithAuthorization() -} - -// authorizer returns the Authorizer to use. -func (c Client) authorizer() Authorizer { - if c.Authorizer == nil { - return NullAuthorizer{} - } - return c.Authorizer -} - -// WithInspection is a convenience method that passes the request to the supplied RequestInspector, -// if present, or returns the WithNothing PrepareDecorator otherwise. -func (c Client) WithInspection() PrepareDecorator { - if c.RequestInspector == nil { - return WithNothing() - } - return c.RequestInspector -} - -// ByInspecting is a convenience method that passes the response to the supplied ResponseInspector, -// if present, or returns the ByIgnoring RespondDecorator otherwise. -func (c Client) ByInspecting() RespondDecorator { - if c.ResponseInspector == nil { - return ByIgnoring() - } - return c.ResponseInspector -} diff --git a/vendor/github.com/Azure/go-autorest/autorest/date/date.go b/vendor/github.com/Azure/go-autorest/autorest/date/date.go deleted file mode 100644 index 80ca60e9b0..0000000000 --- a/vendor/github.com/Azure/go-autorest/autorest/date/date.go +++ /dev/null @@ -1,82 +0,0 @@ -/* -Package date provides time.Time derivatives that conform to the Swagger.io (https://swagger.io/) -defined date formats: Date and DateTime. Both types may, in most cases, be used in lieu of -time.Time types. And both convert to time.Time through a ToTime method. -*/ -package date - -import ( - "fmt" - "time" -) - -const ( - fullDate = "2006-01-02" - fullDateJSON = `"2006-01-02"` - dateFormat = "%04d-%02d-%02d" - jsonFormat = `"%04d-%02d-%02d"` -) - -// Date defines a type similar to time.Time but assumes a layout of RFC3339 full-date (i.e., -// 2006-01-02). -type Date struct { - time.Time -} - -// ParseDate create a new Date from the passed string. -func ParseDate(date string) (d Date, err error) { - return parseDate(date, fullDate) -} - -func parseDate(date string, format string) (Date, error) { - d, err := time.Parse(format, date) - return Date{Time: d}, err -} - -// MarshalBinary preserves the Date as a byte array conforming to RFC3339 full-date (i.e., -// 2006-01-02). -func (d Date) MarshalBinary() ([]byte, error) { - return d.MarshalText() -} - -// UnmarshalBinary reconstitutes a Date saved as a byte array conforming to RFC3339 full-date (i.e., -// 2006-01-02). -func (d *Date) UnmarshalBinary(data []byte) error { - return d.UnmarshalText(data) -} - -// MarshalJSON preserves the Date as a JSON string conforming to RFC3339 full-date (i.e., -// 2006-01-02). -func (d Date) MarshalJSON() (json []byte, err error) { - return []byte(fmt.Sprintf(jsonFormat, d.Year(), d.Month(), d.Day())), nil -} - -// UnmarshalJSON reconstitutes the Date from a JSON string conforming to RFC3339 full-date (i.e., -// 2006-01-02). -func (d *Date) UnmarshalJSON(data []byte) (err error) { - d.Time, err = time.Parse(fullDateJSON, string(data)) - return err -} - -// MarshalText preserves the Date as a byte array conforming to RFC3339 full-date (i.e., -// 2006-01-02). -func (d Date) MarshalText() (text []byte, err error) { - return []byte(fmt.Sprintf(dateFormat, d.Year(), d.Month(), d.Day())), nil -} - -// UnmarshalText reconstitutes a Date saved as a byte array conforming to RFC3339 full-date (i.e., -// 2006-01-02). -func (d *Date) UnmarshalText(data []byte) (err error) { - d.Time, err = time.Parse(fullDate, string(data)) - return err -} - -// String returns the Date formatted as an RFC3339 full-date string (i.e., 2006-01-02). -func (d Date) String() string { - return fmt.Sprintf(dateFormat, d.Year(), d.Month(), d.Day()) -} - -// ToTime returns a Date as a time.Time -func (d Date) ToTime() time.Time { - return d.Time -} diff --git a/vendor/github.com/Azure/go-autorest/autorest/date/time.go b/vendor/github.com/Azure/go-autorest/autorest/date/time.go deleted file mode 100644 index c1af629634..0000000000 --- a/vendor/github.com/Azure/go-autorest/autorest/date/time.go +++ /dev/null @@ -1,89 +0,0 @@ -package date - -import ( - "regexp" - "time" -) - -// Azure reports time in UTC but it doesn't include the 'Z' time zone suffix in some cases. -const ( - azureUtcFormatJSON = `"2006-01-02T15:04:05.999999999"` - azureUtcFormat = "2006-01-02T15:04:05.999999999" - rfc3339JSON = `"` + time.RFC3339Nano + `"` - rfc3339 = time.RFC3339Nano - tzOffsetRegex = `(Z|z|\+|-)(\d+:\d+)*"*$` -) - -// Time defines a type similar to time.Time but assumes a layout of RFC3339 date-time (i.e., -// 2006-01-02T15:04:05Z). -type Time struct { - time.Time -} - -// MarshalBinary preserves the Time as a byte array conforming to RFC3339 date-time (i.e., -// 2006-01-02T15:04:05Z). -func (t Time) MarshalBinary() ([]byte, error) { - return t.Time.MarshalText() -} - -// UnmarshalBinary reconstitutes a Time saved as a byte array conforming to RFC3339 date-time -// (i.e., 2006-01-02T15:04:05Z). -func (t *Time) UnmarshalBinary(data []byte) error { - return t.UnmarshalText(data) -} - -// MarshalJSON preserves the Time as a JSON string conforming to RFC3339 date-time (i.e., -// 2006-01-02T15:04:05Z). -func (t Time) MarshalJSON() (json []byte, err error) { - return t.Time.MarshalJSON() -} - -// UnmarshalJSON reconstitutes the Time from a JSON string conforming to RFC3339 date-time -// (i.e., 2006-01-02T15:04:05Z). -func (t *Time) UnmarshalJSON(data []byte) (err error) { - timeFormat := azureUtcFormatJSON - match, err := regexp.Match(tzOffsetRegex, data) - if err != nil { - return err - } else if match { - timeFormat = rfc3339JSON - } - t.Time, err = ParseTime(timeFormat, string(data)) - return err -} - -// MarshalText preserves the Time as a byte array conforming to RFC3339 date-time (i.e., -// 2006-01-02T15:04:05Z). -func (t Time) MarshalText() (text []byte, err error) { - return t.Time.MarshalText() -} - -// UnmarshalText reconstitutes a Time saved as a byte array conforming to RFC3339 date-time -// (i.e., 2006-01-02T15:04:05Z). -func (t *Time) UnmarshalText(data []byte) (err error) { - timeFormat := azureUtcFormat - match, err := regexp.Match(tzOffsetRegex, data) - if err != nil { - return err - } else if match { - timeFormat = rfc3339 - } - t.Time, err = ParseTime(timeFormat, string(data)) - return err -} - -// String returns the Time formatted as an RFC3339 date-time string (i.e., -// 2006-01-02T15:04:05Z). -func (t Time) String() string { - // Note: time.Time.String does not return an RFC3339 compliant string, time.Time.MarshalText does. - b, err := t.MarshalText() - if err != nil { - return "" - } - return string(b) -} - -// ToTime returns a Time as a time.Time -func (t Time) ToTime() time.Time { - return t.Time -} diff --git a/vendor/github.com/Azure/go-autorest/autorest/date/timerfc1123.go b/vendor/github.com/Azure/go-autorest/autorest/date/timerfc1123.go deleted file mode 100644 index 11995fb9f2..0000000000 --- a/vendor/github.com/Azure/go-autorest/autorest/date/timerfc1123.go +++ /dev/null @@ -1,86 +0,0 @@ -package date - -import ( - "errors" - "time" -) - -const ( - rfc1123JSON = `"` + time.RFC1123 + `"` - rfc1123 = time.RFC1123 -) - -// TimeRFC1123 defines a type similar to time.Time but assumes a layout of RFC1123 date-time (i.e., -// Mon, 02 Jan 2006 15:04:05 MST). -type TimeRFC1123 struct { - time.Time -} - -// UnmarshalJSON reconstitutes the Time from a JSON string conforming to RFC1123 date-time -// (i.e., Mon, 02 Jan 2006 15:04:05 MST). -func (t *TimeRFC1123) UnmarshalJSON(data []byte) (err error) { - t.Time, err = ParseTime(rfc1123JSON, string(data)) - if err != nil { - return err - } - return nil -} - -// MarshalJSON preserves the Time as a JSON string conforming to RFC1123 date-time (i.e., -// Mon, 02 Jan 2006 15:04:05 MST). -func (t TimeRFC1123) MarshalJSON() ([]byte, error) { - if y := t.Year(); y < 0 || y >= 10000 { - return nil, errors.New("Time.MarshalJSON: year outside of range [0,9999]") - } - b := []byte(t.Format(rfc1123JSON)) - return b, nil -} - -// MarshalText preserves the Time as a byte array conforming to RFC1123 date-time (i.e., -// Mon, 02 Jan 2006 15:04:05 MST). -func (t TimeRFC1123) MarshalText() ([]byte, error) { - if y := t.Year(); y < 0 || y >= 10000 { - return nil, errors.New("Time.MarshalText: year outside of range [0,9999]") - } - - b := []byte(t.Format(rfc1123)) - return b, nil -} - -// UnmarshalText reconstitutes a Time saved as a byte array conforming to RFC1123 date-time -// (i.e., Mon, 02 Jan 2006 15:04:05 MST). -func (t *TimeRFC1123) UnmarshalText(data []byte) (err error) { - t.Time, err = ParseTime(rfc1123, string(data)) - if err != nil { - return err - } - return nil -} - -// MarshalBinary preserves the Time as a byte array conforming to RFC1123 date-time (i.e., -// Mon, 02 Jan 2006 15:04:05 MST). -func (t TimeRFC1123) MarshalBinary() ([]byte, error) { - return t.MarshalText() -} - -// UnmarshalBinary reconstitutes a Time saved as a byte array conforming to RFC1123 date-time -// (i.e., Mon, 02 Jan 2006 15:04:05 MST). -func (t *TimeRFC1123) UnmarshalBinary(data []byte) error { - return t.UnmarshalText(data) -} - -// ToTime returns a Time as a time.Time -func (t TimeRFC1123) ToTime() time.Time { - return t.Time -} - -// String returns the Time formatted as an RFC1123 date-time string (i.e., -// Mon, 02 Jan 2006 15:04:05 MST). -func (t TimeRFC1123) String() string { - // Note: time.Time.String does not return an RFC1123 compliant string, time.Time.MarshalText does. - b, err := t.MarshalText() - if err != nil { - return "" - } - return string(b) -} diff --git a/vendor/github.com/Azure/go-autorest/autorest/date/utility.go b/vendor/github.com/Azure/go-autorest/autorest/date/utility.go deleted file mode 100644 index 207b1a240a..0000000000 --- a/vendor/github.com/Azure/go-autorest/autorest/date/utility.go +++ /dev/null @@ -1,11 +0,0 @@ -package date - -import ( - "strings" - "time" -) - -// ParseTime to parse Time string to specified format. -func ParseTime(format string, t string) (d time.Time, err error) { - return time.Parse(format, strings.ToUpper(t)) -} diff --git a/vendor/github.com/Azure/go-autorest/autorest/error.go b/vendor/github.com/Azure/go-autorest/autorest/error.go deleted file mode 100644 index 4bcb8f27b2..0000000000 --- a/vendor/github.com/Azure/go-autorest/autorest/error.go +++ /dev/null @@ -1,80 +0,0 @@ -package autorest - -import ( - "fmt" - "net/http" -) - -const ( - // UndefinedStatusCode is used when HTTP status code is not available for an error. - UndefinedStatusCode = 0 -) - -// DetailedError encloses a error with details of the package, method, and associated HTTP -// status code (if any). -type DetailedError struct { - Original error - - // PackageType is the package type of the object emitting the error. For types, the value - // matches that produced the the '%T' format specifier of the fmt package. For other elements, - // such as functions, it is just the package name (e.g., "autorest"). - PackageType string - - // Method is the name of the method raising the error. - Method string - - // StatusCode is the HTTP Response StatusCode (if non-zero) that led to the error. - StatusCode interface{} - - // Message is the error message. - Message string - - // Service Error is the response body of failed API in bytes - ServiceError []byte -} - -// NewError creates a new Error conforming object from the passed packageType, method, and -// message. message is treated as a format string to which the optional args apply. -func NewError(packageType string, method string, message string, args ...interface{}) DetailedError { - return NewErrorWithError(nil, packageType, method, nil, message, args...) -} - -// NewErrorWithResponse creates a new Error conforming object from the passed -// packageType, method, statusCode of the given resp (UndefinedStatusCode if -// resp is nil), and message. message is treated as a format string to which the -// optional args apply. -func NewErrorWithResponse(packageType string, method string, resp *http.Response, message string, args ...interface{}) DetailedError { - return NewErrorWithError(nil, packageType, method, resp, message, args...) -} - -// NewErrorWithError creates a new Error conforming object from the -// passed packageType, method, statusCode of the given resp (UndefinedStatusCode -// if resp is nil), message, and original error. message is treated as a format -// string to which the optional args apply. -func NewErrorWithError(original error, packageType string, method string, resp *http.Response, message string, args ...interface{}) DetailedError { - if v, ok := original.(DetailedError); ok { - return v - } - - statusCode := UndefinedStatusCode - if resp != nil { - statusCode = resp.StatusCode - } - - return DetailedError{ - Original: original, - PackageType: packageType, - Method: method, - StatusCode: statusCode, - Message: fmt.Sprintf(message, args...), - } -} - -// Error returns a formatted containing all available details (i.e., PackageType, Method, -// StatusCode, Message, and original error (if any)). -func (e DetailedError) Error() string { - if e.Original == nil { - return fmt.Sprintf("%s#%s: %s: StatusCode=%d", e.PackageType, e.Method, e.Message, e.StatusCode) - } - return fmt.Sprintf("%s#%s: %s: StatusCode=%d -- Original Error: %v", e.PackageType, e.Method, e.Message, e.StatusCode, e.Original) -} diff --git a/vendor/github.com/Azure/go-autorest/autorest/preparer.go b/vendor/github.com/Azure/go-autorest/autorest/preparer.go deleted file mode 100644 index c9deb261a1..0000000000 --- a/vendor/github.com/Azure/go-autorest/autorest/preparer.go +++ /dev/null @@ -1,443 +0,0 @@ -package autorest - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "mime/multipart" - "net/http" - "net/url" - "strings" -) - -const ( - mimeTypeJSON = "application/json" - mimeTypeFormPost = "application/x-www-form-urlencoded" - - headerAuthorization = "Authorization" - headerContentType = "Content-Type" - headerUserAgent = "User-Agent" -) - -// Preparer is the interface that wraps the Prepare method. -// -// Prepare accepts and possibly modifies an http.Request (e.g., adding Headers). Implementations -// must ensure to not share or hold per-invocation state since Preparers may be shared and re-used. -type Preparer interface { - Prepare(*http.Request) (*http.Request, error) -} - -// PreparerFunc is a method that implements the Preparer interface. -type PreparerFunc func(*http.Request) (*http.Request, error) - -// Prepare implements the Preparer interface on PreparerFunc. -func (pf PreparerFunc) Prepare(r *http.Request) (*http.Request, error) { - return pf(r) -} - -// PrepareDecorator takes and possibly decorates, by wrapping, a Preparer. Decorators may affect the -// http.Request and pass it along or, first, pass the http.Request along then affect the result. -type PrepareDecorator func(Preparer) Preparer - -// CreatePreparer creates, decorates, and returns a Preparer. -// Without decorators, the returned Preparer returns the passed http.Request unmodified. -// Preparers are safe to share and re-use. -func CreatePreparer(decorators ...PrepareDecorator) Preparer { - return DecoratePreparer( - Preparer(PreparerFunc(func(r *http.Request) (*http.Request, error) { return r, nil })), - decorators...) -} - -// DecoratePreparer accepts a Preparer and a, possibly empty, set of PrepareDecorators, which it -// applies to the Preparer. Decorators are applied in the order received, but their affect upon the -// request depends on whether they are a pre-decorator (change the http.Request and then pass it -// along) or a post-decorator (pass the http.Request along and alter it on return). -func DecoratePreparer(p Preparer, decorators ...PrepareDecorator) Preparer { - for _, decorate := range decorators { - p = decorate(p) - } - return p -} - -// Prepare accepts an http.Request and a, possibly empty, set of PrepareDecorators. -// It creates a Preparer from the decorators which it then applies to the passed http.Request. -func Prepare(r *http.Request, decorators ...PrepareDecorator) (*http.Request, error) { - if r == nil { - return nil, NewError("autorest", "Prepare", "Invoked without an http.Request") - } - return CreatePreparer(decorators...).Prepare(r) -} - -// WithNothing returns a "do nothing" PrepareDecorator that makes no changes to the passed -// http.Request. -func WithNothing() PrepareDecorator { - return func(p Preparer) Preparer { - return PreparerFunc(func(r *http.Request) (*http.Request, error) { - return p.Prepare(r) - }) - } -} - -// WithHeader returns a PrepareDecorator that sets the specified HTTP header of the http.Request to -// the passed value. It canonicalizes the passed header name (via http.CanonicalHeaderKey) before -// adding the header. -func WithHeader(header string, value string) PrepareDecorator { - return func(p Preparer) Preparer { - return PreparerFunc(func(r *http.Request) (*http.Request, error) { - r, err := p.Prepare(r) - if err == nil { - if r.Header == nil { - r.Header = make(http.Header) - } - r.Header.Set(http.CanonicalHeaderKey(header), value) - } - return r, err - }) - } -} - -// WithBearerAuthorization returns a PrepareDecorator that adds an HTTP Authorization header whose -// value is "Bearer " followed by the supplied token. -func WithBearerAuthorization(token string) PrepareDecorator { - return WithHeader(headerAuthorization, fmt.Sprintf("Bearer %s", token)) -} - -// AsContentType returns a PrepareDecorator that adds an HTTP Content-Type header whose value -// is the passed contentType. -func AsContentType(contentType string) PrepareDecorator { - return WithHeader(headerContentType, contentType) -} - -// WithUserAgent returns a PrepareDecorator that adds an HTTP User-Agent header whose value is the -// passed string. -func WithUserAgent(ua string) PrepareDecorator { - return WithHeader(headerUserAgent, ua) -} - -// AsFormURLEncoded returns a PrepareDecorator that adds an HTTP Content-Type header whose value is -// "application/x-www-form-urlencoded". -func AsFormURLEncoded() PrepareDecorator { - return AsContentType(mimeTypeFormPost) -} - -// AsJSON returns a PrepareDecorator that adds an HTTP Content-Type header whose value is -// "application/json". -func AsJSON() PrepareDecorator { - return AsContentType(mimeTypeJSON) -} - -// WithMethod returns a PrepareDecorator that sets the HTTP method of the passed request. The -// decorator does not validate that the passed method string is a known HTTP method. -func WithMethod(method string) PrepareDecorator { - return func(p Preparer) Preparer { - return PreparerFunc(func(r *http.Request) (*http.Request, error) { - r.Method = method - return p.Prepare(r) - }) - } -} - -// AsDelete returns a PrepareDecorator that sets the HTTP method to DELETE. -func AsDelete() PrepareDecorator { return WithMethod("DELETE") } - -// AsGet returns a PrepareDecorator that sets the HTTP method to GET. -func AsGet() PrepareDecorator { return WithMethod("GET") } - -// AsHead returns a PrepareDecorator that sets the HTTP method to HEAD. -func AsHead() PrepareDecorator { return WithMethod("HEAD") } - -// AsOptions returns a PrepareDecorator that sets the HTTP method to OPTIONS. -func AsOptions() PrepareDecorator { return WithMethod("OPTIONS") } - -// AsPatch returns a PrepareDecorator that sets the HTTP method to PATCH. -func AsPatch() PrepareDecorator { return WithMethod("PATCH") } - -// AsPost returns a PrepareDecorator that sets the HTTP method to POST. -func AsPost() PrepareDecorator { return WithMethod("POST") } - -// AsPut returns a PrepareDecorator that sets the HTTP method to PUT. -func AsPut() PrepareDecorator { return WithMethod("PUT") } - -// WithBaseURL returns a PrepareDecorator that populates the http.Request with a url.URL constructed -// from the supplied baseUrl. -func WithBaseURL(baseURL string) PrepareDecorator { - return func(p Preparer) Preparer { - return PreparerFunc(func(r *http.Request) (*http.Request, error) { - r, err := p.Prepare(r) - if err == nil { - var u *url.URL - if u, err = url.Parse(baseURL); err != nil { - return r, err - } - if u.Scheme == "" { - err = fmt.Errorf("autorest: No scheme detected in URL %s", baseURL) - } - if err == nil { - r.URL = u - } - } - return r, err - }) - } -} - -// WithCustomBaseURL returns a PrepareDecorator that replaces brace-enclosed keys within the -// request base URL (i.e., http.Request.URL) with the corresponding values from the passed map. -func WithCustomBaseURL(baseURL string, urlParameters map[string]interface{}) PrepareDecorator { - parameters := ensureValueStrings(urlParameters) - for key, value := range parameters { - baseURL = strings.Replace(baseURL, "{"+key+"}", value, -1) - } - return WithBaseURL(baseURL) -} - -// WithFormData returns a PrepareDecoratore that "URL encodes" (e.g., bar=baz&foo=quux) into the -// http.Request body. -func WithFormData(v url.Values) PrepareDecorator { - return func(p Preparer) Preparer { - return PreparerFunc(func(r *http.Request) (*http.Request, error) { - r, err := p.Prepare(r) - if err == nil { - s := v.Encode() - r.ContentLength = int64(len(s)) - r.Body = ioutil.NopCloser(strings.NewReader(s)) - } - return r, err - }) - } -} - -// WithMultiPartFormData returns a PrepareDecoratore that "URL encodes" (e.g., bar=baz&foo=quux) form parameters -// into the http.Request body. -func WithMultiPartFormData(formDataParameters map[string]interface{}) PrepareDecorator { - return func(p Preparer) Preparer { - return PreparerFunc(func(r *http.Request) (*http.Request, error) { - r, err := p.Prepare(r) - if err == nil { - var body bytes.Buffer - writer := multipart.NewWriter(&body) - for key, value := range formDataParameters { - if rc, ok := value.(io.ReadCloser); ok { - var fd io.Writer - if fd, err = writer.CreateFormFile(key, key); err != nil { - return r, err - } - if _, err = io.Copy(fd, rc); err != nil { - return r, err - } - } else { - if err = writer.WriteField(key, ensureValueString(value)); err != nil { - return r, err - } - } - } - if err = writer.Close(); err != nil { - return r, err - } - if r.Header == nil { - r.Header = make(http.Header) - } - r.Header.Set(http.CanonicalHeaderKey(headerContentType), writer.FormDataContentType()) - r.Body = ioutil.NopCloser(bytes.NewReader(body.Bytes())) - r.ContentLength = int64(body.Len()) - return r, err - } - return r, err - }) - } -} - -// WithFile returns a PrepareDecorator that sends file in request body. -func WithFile(f io.ReadCloser) PrepareDecorator { - return func(p Preparer) Preparer { - return PreparerFunc(func(r *http.Request) (*http.Request, error) { - r, err := p.Prepare(r) - if err == nil { - b, err := ioutil.ReadAll(f) - if err != nil { - return r, err - } - r.Body = ioutil.NopCloser(bytes.NewReader(b)) - r.ContentLength = int64(len(b)) - } - return r, err - }) - } -} - -// WithBool returns a PrepareDecorator that encodes the passed bool into the body of the request -// and sets the Content-Length header. -func WithBool(v bool) PrepareDecorator { - return WithString(fmt.Sprintf("%v", v)) -} - -// WithFloat32 returns a PrepareDecorator that encodes the passed float32 into the body of the -// request and sets the Content-Length header. -func WithFloat32(v float32) PrepareDecorator { - return WithString(fmt.Sprintf("%v", v)) -} - -// WithFloat64 returns a PrepareDecorator that encodes the passed float64 into the body of the -// request and sets the Content-Length header. -func WithFloat64(v float64) PrepareDecorator { - return WithString(fmt.Sprintf("%v", v)) -} - -// WithInt32 returns a PrepareDecorator that encodes the passed int32 into the body of the request -// and sets the Content-Length header. -func WithInt32(v int32) PrepareDecorator { - return WithString(fmt.Sprintf("%v", v)) -} - -// WithInt64 returns a PrepareDecorator that encodes the passed int64 into the body of the request -// and sets the Content-Length header. -func WithInt64(v int64) PrepareDecorator { - return WithString(fmt.Sprintf("%v", v)) -} - -// WithString returns a PrepareDecorator that encodes the passed string into the body of the request -// and sets the Content-Length header. -func WithString(v string) PrepareDecorator { - return func(p Preparer) Preparer { - return PreparerFunc(func(r *http.Request) (*http.Request, error) { - r, err := p.Prepare(r) - if err == nil { - r.ContentLength = int64(len(v)) - r.Body = ioutil.NopCloser(strings.NewReader(v)) - } - return r, err - }) - } -} - -// WithJSON returns a PrepareDecorator that encodes the data passed as JSON into the body of the -// request and sets the Content-Length header. -func WithJSON(v interface{}) PrepareDecorator { - return func(p Preparer) Preparer { - return PreparerFunc(func(r *http.Request) (*http.Request, error) { - r, err := p.Prepare(r) - if err == nil { - b, err := json.Marshal(v) - if err == nil { - r.ContentLength = int64(len(b)) - r.Body = ioutil.NopCloser(bytes.NewReader(b)) - } - } - return r, err - }) - } -} - -// WithPath returns a PrepareDecorator that adds the supplied path to the request URL. If the path -// is absolute (that is, it begins with a "/"), it replaces the existing path. -func WithPath(path string) PrepareDecorator { - return func(p Preparer) Preparer { - return PreparerFunc(func(r *http.Request) (*http.Request, error) { - r, err := p.Prepare(r) - if err == nil { - if r.URL == nil { - return r, NewError("autorest", "WithPath", "Invoked with a nil URL") - } - if r.URL, err = parseURL(r.URL, path); err != nil { - return r, err - } - } - return r, err - }) - } -} - -// WithEscapedPathParameters returns a PrepareDecorator that replaces brace-enclosed keys within the -// request path (i.e., http.Request.URL.Path) with the corresponding values from the passed map. The -// values will be escaped (aka URL encoded) before insertion into the path. -func WithEscapedPathParameters(path string, pathParameters map[string]interface{}) PrepareDecorator { - parameters := escapeValueStrings(ensureValueStrings(pathParameters)) - return func(p Preparer) Preparer { - return PreparerFunc(func(r *http.Request) (*http.Request, error) { - r, err := p.Prepare(r) - if err == nil { - if r.URL == nil { - return r, NewError("autorest", "WithEscapedPathParameters", "Invoked with a nil URL") - } - for key, value := range parameters { - path = strings.Replace(path, "{"+key+"}", value, -1) - } - if r.URL, err = parseURL(r.URL, path); err != nil { - return r, err - } - } - return r, err - }) - } -} - -// WithPathParameters returns a PrepareDecorator that replaces brace-enclosed keys within the -// request path (i.e., http.Request.URL.Path) with the corresponding values from the passed map. -func WithPathParameters(path string, pathParameters map[string]interface{}) PrepareDecorator { - parameters := ensureValueStrings(pathParameters) - return func(p Preparer) Preparer { - return PreparerFunc(func(r *http.Request) (*http.Request, error) { - r, err := p.Prepare(r) - if err == nil { - if r.URL == nil { - return r, NewError("autorest", "WithPathParameters", "Invoked with a nil URL") - } - for key, value := range parameters { - path = strings.Replace(path, "{"+key+"}", value, -1) - } - - if r.URL, err = parseURL(r.URL, path); err != nil { - return r, err - } - } - return r, err - }) - } -} - -func parseURL(u *url.URL, path string) (*url.URL, error) { - p := strings.TrimRight(u.String(), "/") - if !strings.HasPrefix(path, "/") { - path = "/" + path - } - return url.Parse(p + path) -} - -// WithQueryParameters returns a PrepareDecorators that encodes and applies the query parameters -// given in the supplied map (i.e., key=value). -func WithQueryParameters(queryParameters map[string]interface{}) PrepareDecorator { - parameters := ensureValueStrings(queryParameters) - return func(p Preparer) Preparer { - return PreparerFunc(func(r *http.Request) (*http.Request, error) { - r, err := p.Prepare(r) - if err == nil { - if r.URL == nil { - return r, NewError("autorest", "WithQueryParameters", "Invoked with a nil URL") - } - v := r.URL.Query() - for key, value := range parameters { - v.Add(key, value) - } - r.URL.RawQuery = createQuery(v) - } - return r, err - }) - } -} - -// Authorizer is the interface that provides a PrepareDecorator used to supply request -// authorization. Most often, the Authorizer decorator runs last so it has access to the full -// state of the formed HTTP request. -type Authorizer interface { - WithAuthorization() PrepareDecorator -} - -// NullAuthorizer implements a default, "do nothing" Authorizer. -type NullAuthorizer struct{} - -// WithAuthorization returns a PrepareDecorator that does nothing. -func (na NullAuthorizer) WithAuthorization() PrepareDecorator { - return WithNothing() -} diff --git a/vendor/github.com/Azure/go-autorest/autorest/responder.go b/vendor/github.com/Azure/go-autorest/autorest/responder.go deleted file mode 100644 index 87f71e5854..0000000000 --- a/vendor/github.com/Azure/go-autorest/autorest/responder.go +++ /dev/null @@ -1,236 +0,0 @@ -package autorest - -import ( - "bytes" - "encoding/json" - "encoding/xml" - "fmt" - "io" - "io/ioutil" - "net/http" - "strings" -) - -// Responder is the interface that wraps the Respond method. -// -// Respond accepts and reacts to an http.Response. Implementations must ensure to not share or hold -// state since Responders may be shared and re-used. -type Responder interface { - Respond(*http.Response) error -} - -// ResponderFunc is a method that implements the Responder interface. -type ResponderFunc func(*http.Response) error - -// Respond implements the Responder interface on ResponderFunc. -func (rf ResponderFunc) Respond(r *http.Response) error { - return rf(r) -} - -// RespondDecorator takes and possibly decorates, by wrapping, a Responder. Decorators may react to -// the http.Response and pass it along or, first, pass the http.Response along then react. -type RespondDecorator func(Responder) Responder - -// CreateResponder creates, decorates, and returns a Responder. Without decorators, the returned -// Responder returns the passed http.Response unmodified. Responders may or may not be safe to share -// and re-used: It depends on the applied decorators. For example, a standard decorator that closes -// the response body is fine to share whereas a decorator that reads the body into a passed struct -// is not. -// -// To prevent memory leaks, ensure that at least one Responder closes the response body. -func CreateResponder(decorators ...RespondDecorator) Responder { - return DecorateResponder( - Responder(ResponderFunc(func(r *http.Response) error { return nil })), - decorators...) -} - -// DecorateResponder accepts a Responder and a, possibly empty, set of RespondDecorators, which it -// applies to the Responder. Decorators are applied in the order received, but their affect upon the -// request depends on whether they are a pre-decorator (react to the http.Response and then pass it -// along) or a post-decorator (pass the http.Response along and then react). -func DecorateResponder(r Responder, decorators ...RespondDecorator) Responder { - for _, decorate := range decorators { - r = decorate(r) - } - return r -} - -// Respond accepts an http.Response and a, possibly empty, set of RespondDecorators. -// It creates a Responder from the decorators it then applies to the passed http.Response. -func Respond(r *http.Response, decorators ...RespondDecorator) error { - if r == nil { - return nil - } - return CreateResponder(decorators...).Respond(r) -} - -// ByIgnoring returns a RespondDecorator that ignores the passed http.Response passing it unexamined -// to the next RespondDecorator. -func ByIgnoring() RespondDecorator { - return func(r Responder) Responder { - return ResponderFunc(func(resp *http.Response) error { - return r.Respond(resp) - }) - } -} - -// ByCopying copies the contents of the http.Response Body into the passed bytes.Buffer as -// the Body is read. -func ByCopying(b *bytes.Buffer) RespondDecorator { - return func(r Responder) Responder { - return ResponderFunc(func(resp *http.Response) error { - err := r.Respond(resp) - if err == nil && resp != nil && resp.Body != nil { - resp.Body = TeeReadCloser(resp.Body, b) - } - return err - }) - } -} - -// ByDiscardingBody returns a RespondDecorator that first invokes the passed Responder after which -// it copies the remaining bytes (if any) in the response body to ioutil.Discard. Since the passed -// Responder is invoked prior to discarding the response body, the decorator may occur anywhere -// within the set. -func ByDiscardingBody() RespondDecorator { - return func(r Responder) Responder { - return ResponderFunc(func(resp *http.Response) error { - err := r.Respond(resp) - if err == nil && resp != nil && resp.Body != nil { - if _, err := io.Copy(ioutil.Discard, resp.Body); err != nil { - return fmt.Errorf("Error discarding the response body: %v", err) - } - } - return err - }) - } -} - -// ByClosing returns a RespondDecorator that first invokes the passed Responder after which it -// closes the response body. Since the passed Responder is invoked prior to closing the response -// body, the decorator may occur anywhere within the set. -func ByClosing() RespondDecorator { - return func(r Responder) Responder { - return ResponderFunc(func(resp *http.Response) error { - err := r.Respond(resp) - if resp != nil && resp.Body != nil { - if err := resp.Body.Close(); err != nil { - return fmt.Errorf("Error closing the response body: %v", err) - } - } - return err - }) - } -} - -// ByClosingIfError returns a RespondDecorator that first invokes the passed Responder after which -// it closes the response if the passed Responder returns an error and the response body exists. -func ByClosingIfError() RespondDecorator { - return func(r Responder) Responder { - return ResponderFunc(func(resp *http.Response) error { - err := r.Respond(resp) - if err != nil && resp != nil && resp.Body != nil { - if err := resp.Body.Close(); err != nil { - return fmt.Errorf("Error closing the response body: %v", err) - } - } - return err - }) - } -} - -// ByUnmarshallingJSON returns a RespondDecorator that decodes a JSON document returned in the -// response Body into the value pointed to by v. -func ByUnmarshallingJSON(v interface{}) RespondDecorator { - return func(r Responder) Responder { - return ResponderFunc(func(resp *http.Response) error { - err := r.Respond(resp) - if err == nil { - b, errInner := ioutil.ReadAll(resp.Body) - // Some responses might include a BOM, remove for successful unmarshalling - b = bytes.TrimPrefix(b, []byte("\xef\xbb\xbf")) - if errInner != nil { - err = fmt.Errorf("Error occurred reading http.Response#Body - Error = '%v'", errInner) - } else if len(strings.Trim(string(b), " ")) > 0 { - errInner = json.Unmarshal(b, v) - if errInner != nil { - err = fmt.Errorf("Error occurred unmarshalling JSON - Error = '%v' JSON = '%s'", errInner, string(b)) - } - } - } - return err - }) - } -} - -// ByUnmarshallingXML returns a RespondDecorator that decodes a XML document returned in the -// response Body into the value pointed to by v. -func ByUnmarshallingXML(v interface{}) RespondDecorator { - return func(r Responder) Responder { - return ResponderFunc(func(resp *http.Response) error { - err := r.Respond(resp) - if err == nil { - b, errInner := ioutil.ReadAll(resp.Body) - if errInner != nil { - err = fmt.Errorf("Error occurred reading http.Response#Body - Error = '%v'", errInner) - } else { - errInner = xml.Unmarshal(b, v) - if errInner != nil { - err = fmt.Errorf("Error occurred unmarshalling Xml - Error = '%v' Xml = '%s'", errInner, string(b)) - } - } - } - return err - }) - } -} - -// WithErrorUnlessStatusCode returns a RespondDecorator that emits an error unless the response -// StatusCode is among the set passed. On error, response body is fully read into a buffer and -// presented in the returned error, as well as in the response body. -func WithErrorUnlessStatusCode(codes ...int) RespondDecorator { - return func(r Responder) Responder { - return ResponderFunc(func(resp *http.Response) error { - err := r.Respond(resp) - if err == nil && !ResponseHasStatusCode(resp, codes...) { - derr := NewErrorWithResponse("autorest", "WithErrorUnlessStatusCode", resp, "%v %v failed with %s", - resp.Request.Method, - resp.Request.URL, - resp.Status) - if resp.Body != nil { - defer resp.Body.Close() - b, _ := ioutil.ReadAll(resp.Body) - derr.ServiceError = b - resp.Body = ioutil.NopCloser(bytes.NewReader(b)) - } - err = derr - } - return err - }) - } -} - -// WithErrorUnlessOK returns a RespondDecorator that emits an error if the response StatusCode is -// anything other than HTTP 200. -func WithErrorUnlessOK() RespondDecorator { - return WithErrorUnlessStatusCode(http.StatusOK) -} - -// ExtractHeader extracts all values of the specified header from the http.Response. It returns an -// empty string slice if the passed http.Response is nil or the header does not exist. -func ExtractHeader(header string, resp *http.Response) []string { - if resp != nil && resp.Header != nil { - return resp.Header[http.CanonicalHeaderKey(header)] - } - return nil -} - -// ExtractHeaderValue extracts the first value of the specified header from the http.Response. It -// returns an empty string if the passed http.Response is nil or the header does not exist. -func ExtractHeaderValue(header string, resp *http.Response) string { - h := ExtractHeader(header, resp) - if len(h) > 0 { - return h[0] - } - return "" -} diff --git a/vendor/github.com/Azure/go-autorest/autorest/sender.go b/vendor/github.com/Azure/go-autorest/autorest/sender.go deleted file mode 100644 index 9c0697815b..0000000000 --- a/vendor/github.com/Azure/go-autorest/autorest/sender.go +++ /dev/null @@ -1,270 +0,0 @@ -package autorest - -import ( - "bytes" - "fmt" - "io/ioutil" - "log" - "math" - "net/http" - "time" -) - -// Sender is the interface that wraps the Do method to send HTTP requests. -// -// The standard http.Client conforms to this interface. -type Sender interface { - Do(*http.Request) (*http.Response, error) -} - -// SenderFunc is a method that implements the Sender interface. -type SenderFunc func(*http.Request) (*http.Response, error) - -// Do implements the Sender interface on SenderFunc. -func (sf SenderFunc) Do(r *http.Request) (*http.Response, error) { - return sf(r) -} - -// SendDecorator takes and possibily decorates, by wrapping, a Sender. Decorators may affect the -// http.Request and pass it along or, first, pass the http.Request along then react to the -// http.Response result. -type SendDecorator func(Sender) Sender - -// CreateSender creates, decorates, and returns, as a Sender, the default http.Client. -func CreateSender(decorators ...SendDecorator) Sender { - return DecorateSender(&http.Client{}, decorators...) -} - -// DecorateSender accepts a Sender and a, possibly empty, set of SendDecorators, which is applies to -// the Sender. Decorators are applied in the order received, but their affect upon the request -// depends on whether they are a pre-decorator (change the http.Request and then pass it along) or a -// post-decorator (pass the http.Request along and react to the results in http.Response). -func DecorateSender(s Sender, decorators ...SendDecorator) Sender { - for _, decorate := range decorators { - s = decorate(s) - } - return s -} - -// Send sends, by means of the default http.Client, the passed http.Request, returning the -// http.Response and possible error. It also accepts a, possibly empty, set of SendDecorators which -// it will apply the http.Client before invoking the Do method. -// -// Send is a convenience method and not recommended for production. Advanced users should use -// SendWithSender, passing and sharing their own Sender (e.g., instance of http.Client). -// -// Send will not poll or retry requests. -func Send(r *http.Request, decorators ...SendDecorator) (*http.Response, error) { - return SendWithSender(&http.Client{}, r, decorators...) -} - -// SendWithSender sends the passed http.Request, through the provided Sender, returning the -// http.Response and possible error. It also accepts a, possibly empty, set of SendDecorators which -// it will apply the http.Client before invoking the Do method. -// -// SendWithSender will not poll or retry requests. -func SendWithSender(s Sender, r *http.Request, decorators ...SendDecorator) (*http.Response, error) { - return DecorateSender(s, decorators...).Do(r) -} - -// AfterDelay returns a SendDecorator that delays for the passed time.Duration before -// invoking the Sender. The delay may be terminated by closing the optional channel on the -// http.Request. If canceled, no further Senders are invoked. -func AfterDelay(d time.Duration) SendDecorator { - return func(s Sender) Sender { - return SenderFunc(func(r *http.Request) (*http.Response, error) { - if !DelayForBackoff(d, 0, r.Cancel) { - return nil, fmt.Errorf("autorest: AfterDelay canceled before full delay") - } - return s.Do(r) - }) - } -} - -// AsIs returns a SendDecorator that invokes the passed Sender without modifying the http.Request. -func AsIs() SendDecorator { - return func(s Sender) Sender { - return SenderFunc(func(r *http.Request) (*http.Response, error) { - return s.Do(r) - }) - } -} - -// DoCloseIfError returns a SendDecorator that first invokes the passed Sender after which -// it closes the response if the passed Sender returns an error and the response body exists. -func DoCloseIfError() SendDecorator { - return func(s Sender) Sender { - return SenderFunc(func(r *http.Request) (*http.Response, error) { - resp, err := s.Do(r) - if err != nil { - Respond(resp, ByDiscardingBody(), ByClosing()) - } - return resp, err - }) - } -} - -// DoErrorIfStatusCode returns a SendDecorator that emits an error if the response StatusCode is -// among the set passed. Since these are artificial errors, the response body may still require -// closing. -func DoErrorIfStatusCode(codes ...int) SendDecorator { - return func(s Sender) Sender { - return SenderFunc(func(r *http.Request) (*http.Response, error) { - resp, err := s.Do(r) - if err == nil && ResponseHasStatusCode(resp, codes...) { - err = NewErrorWithResponse("autorest", "DoErrorIfStatusCode", resp, "%v %v failed with %s", - resp.Request.Method, - resp.Request.URL, - resp.Status) - } - return resp, err - }) - } -} - -// DoErrorUnlessStatusCode returns a SendDecorator that emits an error unless the response -// StatusCode is among the set passed. Since these are artificial errors, the response body -// may still require closing. -func DoErrorUnlessStatusCode(codes ...int) SendDecorator { - return func(s Sender) Sender { - return SenderFunc(func(r *http.Request) (*http.Response, error) { - resp, err := s.Do(r) - if err == nil && !ResponseHasStatusCode(resp, codes...) { - err = NewErrorWithResponse("autorest", "DoErrorUnlessStatusCode", resp, "%v %v failed with %s", - resp.Request.Method, - resp.Request.URL, - resp.Status) - } - return resp, err - }) - } -} - -// DoPollForStatusCodes returns a SendDecorator that polls if the http.Response contains one of the -// passed status codes. It expects the http.Response to contain a Location header providing the -// URL at which to poll (using GET) and will poll until the time passed is equal to or greater than -// the supplied duration. It will delay between requests for the duration specified in the -// RetryAfter header or, if the header is absent, the passed delay. Polling may be canceled by -// closing the optional channel on the http.Request. -func DoPollForStatusCodes(duration time.Duration, delay time.Duration, codes ...int) SendDecorator { - return func(s Sender) Sender { - return SenderFunc(func(r *http.Request) (resp *http.Response, err error) { - resp, err = s.Do(r) - - if err == nil && ResponseHasStatusCode(resp, codes...) { - r, err = NewPollingRequest(resp, r.Cancel) - - for err == nil && ResponseHasStatusCode(resp, codes...) { - Respond(resp, - ByDiscardingBody(), - ByClosing()) - resp, err = SendWithSender(s, r, - AfterDelay(GetRetryAfter(resp, delay))) - } - } - - return resp, err - }) - } -} - -// DoRetryForAttempts returns a SendDecorator that retries a failed request for up to the specified -// number of attempts, exponentially backing off between requests using the supplied backoff -// time.Duration (which may be zero). Retrying may be canceled by closing the optional channel on -// the http.Request. -func DoRetryForAttempts(attempts int, backoff time.Duration) SendDecorator { - return func(s Sender) Sender { - return SenderFunc(func(r *http.Request) (resp *http.Response, err error) { - for attempt := 0; attempt < attempts; attempt++ { - resp, err = s.Do(r) - if err == nil { - return resp, err - } - DelayForBackoff(backoff, attempt, r.Cancel) - } - return resp, err - }) - } -} - -// DoRetryForStatusCodes returns a SendDecorator that retries for specified statusCodes for up to the specified -// number of attempts, exponentially backing off between requests using the supplied backoff -// time.Duration (which may be zero). Retrying may be canceled by closing the optional channel on -// the http.Request. -func DoRetryForStatusCodes(attempts int, backoff time.Duration, codes ...int) SendDecorator { - return func(s Sender) Sender { - return SenderFunc(func(r *http.Request) (resp *http.Response, err error) { - b := []byte{} - if r.Body != nil { - b, err = ioutil.ReadAll(r.Body) - if err != nil { - return resp, err - } - } - - // Increment to add the first call (attempts denotes number of retries) - attempts++ - for attempt := 0; attempt < attempts; attempt++ { - r.Body = ioutil.NopCloser(bytes.NewBuffer(b)) - resp, err = s.Do(r) - if err != nil || !ResponseHasStatusCode(resp, codes...) { - return resp, err - } - DelayForBackoff(backoff, attempt, r.Cancel) - } - return resp, err - }) - } -} - -// DoRetryForDuration returns a SendDecorator that retries the request until the total time is equal -// to or greater than the specified duration, exponentially backing off between requests using the -// supplied backoff time.Duration (which may be zero). Retrying may be canceled by closing the -// optional channel on the http.Request. -func DoRetryForDuration(d time.Duration, backoff time.Duration) SendDecorator { - return func(s Sender) Sender { - return SenderFunc(func(r *http.Request) (resp *http.Response, err error) { - end := time.Now().Add(d) - for attempt := 0; time.Now().Before(end); attempt++ { - resp, err = s.Do(r) - if err == nil { - return resp, err - } - DelayForBackoff(backoff, attempt, r.Cancel) - } - return resp, err - }) - } -} - -// WithLogging returns a SendDecorator that implements simple before and after logging of the -// request. -func WithLogging(logger *log.Logger) SendDecorator { - return func(s Sender) Sender { - return SenderFunc(func(r *http.Request) (*http.Response, error) { - logger.Printf("Sending %s %s", r.Method, r.URL) - resp, err := s.Do(r) - if err != nil { - logger.Printf("%s %s received error '%v'", r.Method, r.URL, err) - } else { - logger.Printf("%s %s received %s", r.Method, r.URL, resp.Status) - } - return resp, err - }) - } -} - -// DelayForBackoff invokes time.After for the supplied backoff duration raised to the power of -// passed attempt (i.e., an exponential backoff delay). Backoff duration is in seconds and can set -// to zero for no delay. The delay may be canceled by closing the passed channel. If terminated early, -// returns false. -// Note: Passing attempt 1 will result in doubling "backoff" duration. Treat this as a zero-based attempt -// count. -func DelayForBackoff(backoff time.Duration, attempt int, cancel <-chan struct{}) bool { - select { - case <-time.After(time.Duration(backoff.Seconds()*math.Pow(2, float64(attempt))) * time.Second): - return true - case <-cancel: - return false - } -} diff --git a/vendor/github.com/Azure/go-autorest/autorest/utility.go b/vendor/github.com/Azure/go-autorest/autorest/utility.go deleted file mode 100644 index 78067148b2..0000000000 --- a/vendor/github.com/Azure/go-autorest/autorest/utility.go +++ /dev/null @@ -1,178 +0,0 @@ -package autorest - -import ( - "bytes" - "encoding/json" - "encoding/xml" - "fmt" - "io" - "net/url" - "reflect" - "sort" - "strings" -) - -// EncodedAs is a series of constants specifying various data encodings -type EncodedAs string - -const ( - // EncodedAsJSON states that data is encoded as JSON - EncodedAsJSON EncodedAs = "JSON" - - // EncodedAsXML states that data is encoded as Xml - EncodedAsXML EncodedAs = "XML" -) - -// Decoder defines the decoding method json.Decoder and xml.Decoder share -type Decoder interface { - Decode(v interface{}) error -} - -// NewDecoder creates a new decoder appropriate to the passed encoding. -// encodedAs specifies the type of encoding and r supplies the io.Reader containing the -// encoded data. -func NewDecoder(encodedAs EncodedAs, r io.Reader) Decoder { - if encodedAs == EncodedAsJSON { - return json.NewDecoder(r) - } else if encodedAs == EncodedAsXML { - return xml.NewDecoder(r) - } - return nil -} - -// CopyAndDecode decodes the data from the passed io.Reader while making a copy. Having a copy -// is especially useful if there is a chance the data will fail to decode. -// encodedAs specifies the expected encoding, r provides the io.Reader to the data, and v -// is the decoding destination. -func CopyAndDecode(encodedAs EncodedAs, r io.Reader, v interface{}) (bytes.Buffer, error) { - b := bytes.Buffer{} - return b, NewDecoder(encodedAs, io.TeeReader(r, &b)).Decode(v) -} - -// TeeReadCloser returns a ReadCloser that writes to w what it reads from rc. -// It utilizes io.TeeReader to copy the data read and has the same behavior when reading. -// Further, when it is closed, it ensures that rc is closed as well. -func TeeReadCloser(rc io.ReadCloser, w io.Writer) io.ReadCloser { - return &teeReadCloser{rc, io.TeeReader(rc, w)} -} - -type teeReadCloser struct { - rc io.ReadCloser - r io.Reader -} - -func (t *teeReadCloser) Read(p []byte) (int, error) { - return t.r.Read(p) -} - -func (t *teeReadCloser) Close() error { - return t.rc.Close() -} - -func containsInt(ints []int, n int) bool { - for _, i := range ints { - if i == n { - return true - } - } - return false -} - -func escapeValueStrings(m map[string]string) map[string]string { - for key, value := range m { - m[key] = url.QueryEscape(value) - } - return m -} - -func ensureValueStrings(mapOfInterface map[string]interface{}) map[string]string { - mapOfStrings := make(map[string]string) - for key, value := range mapOfInterface { - mapOfStrings[key] = ensureValueString(value) - } - return mapOfStrings -} - -func ensureValueString(value interface{}) string { - if value == nil { - return "" - } - switch v := value.(type) { - case string: - return v - case []byte: - return string(v) - default: - return fmt.Sprintf("%v", v) - } -} - -// MapToValues method converts map[string]interface{} to url.Values. -func MapToValues(m map[string]interface{}) url.Values { - v := url.Values{} - for key, value := range m { - x := reflect.ValueOf(value) - if x.Kind() == reflect.Array || x.Kind() == reflect.Slice { - for i := 0; i < x.Len(); i++ { - v.Add(key, ensureValueString(x.Index(i))) - } - } else { - v.Add(key, ensureValueString(value)) - } - } - return v -} - -// String method converts interface v to string. If interface is a list, it -// joins list elements using separator. -func String(v interface{}, sep ...string) string { - if len(sep) > 0 { - return ensureValueString(strings.Join(v.([]string), sep[0])) - } - return ensureValueString(v) -} - -// Encode method encodes url path and query parameters. -func Encode(location string, v interface{}, sep ...string) string { - s := String(v, sep...) - switch strings.ToLower(location) { - case "path": - return pathEscape(s) - case "query": - return queryEscape(s) - default: - return s - } -} - -func pathEscape(s string) string { - return strings.Replace(url.QueryEscape(s), "+", "%20", -1) -} - -func queryEscape(s string) string { - return url.QueryEscape(s) -} - -// This method is same as Encode() method of "net/url" go package, -// except it does not encode the query parameters because they -// already come encoded. It formats values map in query format (bar=foo&a=b). -func createQuery(v url.Values) string { - var buf bytes.Buffer - keys := make([]string, 0, len(v)) - for k := range v { - keys = append(keys, k) - } - sort.Strings(keys) - for _, k := range keys { - vs := v[k] - prefix := url.QueryEscape(k) + "=" - for _, v := range vs { - if buf.Len() > 0 { - buf.WriteByte('&') - } - buf.WriteString(prefix) - buf.WriteString(v) - } - } - return buf.String() -} diff --git a/vendor/github.com/Azure/go-autorest/autorest/version.go b/vendor/github.com/Azure/go-autorest/autorest/version.go deleted file mode 100644 index 7a0bf9c9ff..0000000000 --- a/vendor/github.com/Azure/go-autorest/autorest/version.go +++ /dev/null @@ -1,23 +0,0 @@ -package autorest - -import ( - "fmt" -) - -const ( - major = "7" - minor = "3" - patch = "0" - tag = "" - semVerFormat = "%s.%s.%s%s" -) - -var version string - -// Version returns the semantic version (see http://semver.org). -func Version() string { - if version == "" { - version = fmt.Sprintf(semVerFormat, major, minor, patch, tag) - } - return version -} diff --git a/vendor/github.com/allegro/bigcache/LICENSE b/vendor/github.com/allegro/bigcache/LICENSE new file mode 100644 index 0000000000..8dada3edaf --- /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 0000000000..c23f7f36ce --- /dev/null +++ b/vendor/github.com/allegro/bigcache/README.md @@ -0,0 +1,150 @@ +# 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, or because delete was called. A bitmask representing the reason will be returned. + // Default value is nil which means no callback and it prevents from unwrapping the oldest entry. + OnRemove: nil, + // OnRemoveWithReason is a callback fired when the oldest entry is removed because of its expiration time or no space left + // for the new entry, or because delete was called. A constant representing the reason will be passed through. + // Default value is nil which means no callback and it prevents from unwrapping the oldest entry. + // Ignored if OnRemove is specified. + OnRemoveWithReason: 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 3000000 569 ns/op 202 B/op 3 allocs/op +BenchmarkConcurrentMapSet-8 1000000 1592 ns/op 347 B/op 8 allocs/op +BenchmarkFreeCacheSet-8 3000000 775 ns/op 355 B/op 2 allocs/op +BenchmarkBigCacheSet-8 3000000 640 ns/op 303 B/op 2 allocs/op +BenchmarkMapGet-8 5000000 407 ns/op 24 B/op 1 allocs/op +BenchmarkConcurrentMapGet-8 3000000 558 ns/op 24 B/op 2 allocs/op +BenchmarkFreeCacheGet-8 2000000 682 ns/op 136 B/op 2 allocs/op +BenchmarkBigCacheGet-8 3000000 512 ns/op 152 B/op 4 allocs/op +BenchmarkBigCacheSetParallel-8 10000000 225 ns/op 313 B/op 3 allocs/op +BenchmarkFreeCacheSetParallel-8 10000000 218 ns/op 341 B/op 3 allocs/op +BenchmarkConcurrentMapSetParallel-8 5000000 318 ns/op 200 B/op 6 allocs/op +BenchmarkBigCacheGetParallel-8 20000000 178 ns/op 152 B/op 4 allocs/op +BenchmarkFreeCacheGetParallel-8 20000000 295 ns/op 136 B/op 3 allocs/op +BenchmarkConcurrentMapGetParallel-8 10000000 237 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 0000000000..b3879264ac --- /dev/null +++ b/vendor/github.com/allegro/bigcache/bigcache.go @@ -0,0 +1,202 @@ +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 take place on byte arrays, +// 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 + close chan struct{} +} + +// RemoveReason is a value used to signal to the user why a particular key was removed in the OnRemove callback. +type RemoveReason uint32 + +const ( + // Expired means the key is past its LifeWindow. + Expired RemoveReason = iota + // NoSpace means the key is the oldest and the cache size was at its maximum when Set was called, or the + // entry exceeded the maximum shard size. + NoSpace + // Deleted means Delete was called and this key was removed as a result. + Deleted +) + +// 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()), + close: make(chan struct{}), + } + + var onRemove func(wrappedEntry []byte, reason RemoveReason) + if config.OnRemove != nil { + onRemove = cache.providedOnRemove + } else if config.OnRemoveWithReason != nil { + onRemove = cache.providedOnRemoveWithReason + } else { + onRemove = cache.notProvidedOnRemove + } + + for i := 0; i < config.Shards; i++ { + cache.shards[i] = initNewShard(config, onRemove, clock) + } + + if config.CleanWindow > 0 { + go func() { + ticker := time.NewTicker(config.CleanWindow) + defer ticker.Stop() + for { + select { + case t := <-ticker.C: + cache.cleanUp(uint64(t.Unix())) + case <-cache.close: + return + } + } + }() + } + + return cache, nil +} + +// Close is used to signal a shutdown of the cache when you are done with it. +// This allows the cleaning goroutines to exit and ensures references are not +// kept to the cache preventing GC of the entire cache. +func (c *BigCache) Close() error { + close(c.close) + return nil +} + +// Get reads entry for the key. +// It returns an ErrEntryNotFound 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 +} + +// Capacity returns amount of bytes store in the cache. +func (c *BigCache) Capacity() int { + var len int + for _, shard := range c.shards { + len += shard.capacity() + } + 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(reason RemoveReason) error) bool { + oldestTimestamp := readTimestampFromEntry(oldestEntry) + if currentTimestamp-oldestTimestamp > c.lifeWindow { + evict(Expired) + 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, reason RemoveReason) { + c.config.OnRemove(readKeyFromEntry(wrappedEntry), readEntry(wrappedEntry)) +} + +func (c *BigCache) providedOnRemoveWithReason(wrappedEntry []byte, reason RemoveReason) { + if c.config.onRemoveFilter == 0 || (1< 0 { + c.config.OnRemoveWithReason(readKeyFromEntry(wrappedEntry), readEntry(wrappedEntry), reason) + } +} + +func (c *BigCache) notProvidedOnRemove(wrappedEntry []byte, reason RemoveReason) { +} diff --git a/vendor/github.com/allegro/bigcache/bytes.go b/vendor/github.com/allegro/bigcache/bytes.go new file mode 100644 index 0000000000..3944bfe135 --- /dev/null +++ b/vendor/github.com/allegro/bigcache/bytes.go @@ -0,0 +1,14 @@ +// +build !appengine + +package bigcache + +import ( + "reflect" + "unsafe" +) + +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)) +} diff --git a/vendor/github.com/allegro/bigcache/bytes_appengine.go b/vendor/github.com/allegro/bigcache/bytes_appengine.go new file mode 100644 index 0000000000..3892f3b54f --- /dev/null +++ b/vendor/github.com/allegro/bigcache/bytes_appengine.go @@ -0,0 +1,7 @@ +// +build appengine + +package bigcache + +func bytesToString(b []byte) string { + return string(b) +} diff --git a/vendor/github.com/allegro/bigcache/clock.go b/vendor/github.com/allegro/bigcache/clock.go new file mode 100644 index 0000000000..f8b535e133 --- /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 0000000000..9654143ab1 --- /dev/null +++ b/vendor/github.com/allegro/bigcache/config.go @@ -0,0 +1,86 @@ +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, or because delete was called. + // Default value is nil which means no callback and it prevents from unwrapping the oldest entry. + OnRemove func(key string, entry []byte) + // OnRemoveWithReason is a callback fired when the oldest entry is removed because of its expiration time or no space left + // for the new entry, or because delete was called. A constant representing the reason will be passed through. + // Default value is nil which means no callback and it prevents from unwrapping the oldest entry. + // Ignored if OnRemove is specified. + OnRemoveWithReason func(key string, entry []byte, reason RemoveReason) + + onRemoveFilter int + + // 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 +} + +// OnRemoveFilterSet sets which remove reasons will trigger a call to OnRemoveWithReason. +// Filtering out reasons prevents bigcache from unwrapping them, which saves cpu. +func (c Config) OnRemoveFilterSet(reasons ...RemoveReason) Config { + c.onRemoveFilter = 0 + for i := range reasons { + c.onRemoveFilter |= 1 << uint(reasons[i]) + } + + return c +} diff --git a/vendor/github.com/allegro/bigcache/encoding.go b/vendor/github.com/allegro/bigcache/encoding.go new file mode 100644 index 0000000000..4d434e5dce --- /dev/null +++ b/vendor/github.com/allegro/bigcache/encoding.go @@ -0,0 +1,62 @@ +package bigcache + +import ( + "encoding/binary" +) + +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 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/entry_not_found_error.go b/vendor/github.com/allegro/bigcache/entry_not_found_error.go new file mode 100644 index 0000000000..051a712307 --- /dev/null +++ b/vendor/github.com/allegro/bigcache/entry_not_found_error.go @@ -0,0 +1,6 @@ +package bigcache + +import "errors" + +// ErrEntryNotFound is an error type struct which is returned when entry was not found for provided key +var ErrEntryNotFound = errors.New("Entry not found") diff --git a/vendor/github.com/allegro/bigcache/fnv.go b/vendor/github.com/allegro/bigcache/fnv.go new file mode 100644 index 0000000000..188c9aa6dc --- /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/hash.go b/vendor/github.com/allegro/bigcache/hash.go new file mode 100644 index 0000000000..5f8ade774d --- /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/iterator.go b/vendor/github.com/allegro/bigcache/iterator.go new file mode 100644 index 0000000000..70b98d9004 --- /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/logger.go b/vendor/github.com/allegro/bigcache/logger.go new file mode 100644 index 0000000000..50e84abc80 --- /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 0000000000..bda7374031 --- /dev/null +++ b/vendor/github.com/allegro/bigcache/queue/bytes_queue.go @@ -0,0 +1,238 @@ +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 +) + +var ( + errEmptyQueue = &queueError{"Empty queue"} + errInvalidIndex = &queueError{"Index must be greater than zero. Invalid index."} + errIndexOutOfBounds = &queueError{"Index out of range"} +) + +// 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 +} + +// CheckGet checks if an entry can be read from index +func (q *BytesQueue) CheckGet(index int) error { + return q.peekCheckErr(index) +} + +// 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 +} + +// peekCheckErr is identical to peek, but does not actually return any data +func (q *BytesQueue) peekCheckErr(index int) error { + + if q.count == 0 { + return errEmptyQueue + } + + if index <= 0 { + return errInvalidIndex + } + + if index+headerEntrySize >= len(q.array) { + return errIndexOutOfBounds + } + return nil +} + +func (q *BytesQueue) peek(index int) ([]byte, int, error) { + + if q.count == 0 { + return nil, 0, errEmptyQueue + } + + if index <= 0 { + return nil, 0, errInvalidIndex + } + + if index+headerEntrySize >= len(q.array) { + return nil, 0, errIndexOutOfBounds + } + + 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/shard.go b/vendor/github.com/allegro/bigcache/shard.go new file mode 100644 index 0000000000..a31094ff38 --- /dev/null +++ b/vendor/github.com/allegro/bigcache/shard.go @@ -0,0 +1,259 @@ +package bigcache + +import ( + "fmt" + "sync" + "sync/atomic" + + "github.com/allegro/bigcache/queue" +) + +type onRemoveCallback func(wrappedEntry []byte, reason RemoveReason) + +type cacheShard struct { + hashmap map[uint64]uint32 + entries queue.BytesQueue + lock sync.RWMutex + entryBuffer []byte + onRemove onRemoveCallback + + isVerbose bool + logger Logger + clock clock + lifeWindow uint64 + + stats Stats +} + +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, ErrEntryNotFound + } + + 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, ErrEntryNotFound + } + entry := readEntry(wrappedEntry) + s.lock.RUnlock() + s.hit() + return entry, 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(NoSpace) != nil { + s.lock.Unlock() + return fmt.Errorf("entry is bigger than max shard size") + } + } +} + +func (s *cacheShard) del(key string, hashedKey uint64) error { + // Optimistic pre-check using only readlock + s.lock.RLock() + itemIndex := s.hashmap[hashedKey] + + if itemIndex == 0 { + s.lock.RUnlock() + s.delmiss() + return ErrEntryNotFound + } + + if err := s.entries.CheckGet(int(itemIndex)); err != nil { + s.lock.RUnlock() + s.delmiss() + return err + } + s.lock.RUnlock() + + s.lock.Lock() + { + // After obtaining the writelock, we need to read the same again, + // since the data delivered earlier may be stale now + itemIndex = s.hashmap[hashedKey] + + if itemIndex == 0 { + s.lock.Unlock() + s.delmiss() + return ErrEntryNotFound + } + + wrappedEntry, err := s.entries.Get(int(itemIndex)) + if err != nil { + s.lock.Unlock() + s.delmiss() + return err + } + + delete(s.hashmap, hashedKey) + s.onRemove(wrappedEntry, Deleted) + resetKeyFromEntry(wrappedEntry) + } + s.lock.Unlock() + + s.delhit() + return nil +} + +func (s *cacheShard) onEvict(oldestEntry []byte, currentTimestamp uint64, evict func(reason RemoveReason) error) bool { + oldestTimestamp := readTimestampFromEntry(oldestEntry) + if currentTimestamp-oldestTimestamp > s.lifeWindow { + evict(Expired) + 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) { + s.lock.RLock() + defer s.lock.RUnlock() + return s.entries.Peek() +} + +func (s *cacheShard) getEntry(index int) ([]byte, error) { + s.lock.RLock() + entry, err := s.entries.Get(index) + s.lock.RUnlock() + + return entry, err +} + +func (s *cacheShard) copyKeys() (keys []uint32, next int) { + s.lock.RLock() + keys = make([]uint32, len(s.hashmap)) + + for _, index := range s.hashmap { + keys[next] = index + next++ + } + + s.lock.RUnlock() + return keys, next +} + +func (s *cacheShard) removeOldestEntry(reason RemoveReason) error { + oldest, err := s.entries.Pop() + if err == nil { + hash := readHashFromEntry(oldest) + delete(s.hashmap, hash) + s.onRemove(oldest, reason) + 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) capacity() int { + s.lock.RLock() + res := s.entries.Capacity() + 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 0000000000..07157132a2 --- /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 0000000000..ca1df79b93 --- /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/log/term/LICENSE b/vendor/github.com/codahale/hdrhistogram/LICENSE similarity index 96% rename from log/term/LICENSE rename to vendor/github.com/codahale/hdrhistogram/LICENSE index f090cb42f3..f9835c241f 100644 --- a/log/term/LICENSE +++ b/vendor/github.com/codahale/hdrhistogram/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2014 Simon Eskildsen +Copyright (c) 2014 Coda Hale Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/github.com/codahale/hdrhistogram/README.md b/vendor/github.com/codahale/hdrhistogram/README.md new file mode 100644 index 0000000000..614b197c3d --- /dev/null +++ b/vendor/github.com/codahale/hdrhistogram/README.md @@ -0,0 +1,15 @@ +hdrhistogram +============ + +[![Build Status](https://travis-ci.org/codahale/hdrhistogram.png?branch=master)](https://travis-ci.org/codahale/hdrhistogram) + +A pure Go implementation of the [HDR Histogram](https://github.com/HdrHistogram/HdrHistogram). + +> A Histogram that supports recording and analyzing sampled data value counts +> across a configurable integer value range with configurable value precision +> within the range. Value precision is expressed as the number of significant +> digits in the value recording, and provides control over value quantization +> behavior across the value range and the subsequent value resolution at any +> given level. + +For documentation, check [godoc](http://godoc.org/github.com/codahale/hdrhistogram). diff --git a/vendor/github.com/codahale/hdrhistogram/hdr.go b/vendor/github.com/codahale/hdrhistogram/hdr.go new file mode 100644 index 0000000000..c97842926d --- /dev/null +++ b/vendor/github.com/codahale/hdrhistogram/hdr.go @@ -0,0 +1,564 @@ +// Package hdrhistogram provides an implementation of Gil Tene's HDR Histogram +// data structure. The HDR Histogram allows for fast and accurate analysis of +// the extreme ranges of data with non-normal distributions, like latency. +package hdrhistogram + +import ( + "fmt" + "math" +) + +// A Bracket is a part of a cumulative distribution. +type Bracket struct { + Quantile float64 + Count, ValueAt int64 +} + +// A Snapshot is an exported view of a Histogram, useful for serializing them. +// A Histogram can be constructed from it by passing it to Import. +type Snapshot struct { + LowestTrackableValue int64 + HighestTrackableValue int64 + SignificantFigures int64 + Counts []int64 +} + +// A Histogram is a lossy data structure used to record the distribution of +// non-normally distributed data (like latency) with a high degree of accuracy +// and a bounded degree of precision. +type Histogram struct { + lowestTrackableValue int64 + highestTrackableValue int64 + unitMagnitude int64 + significantFigures int64 + subBucketHalfCountMagnitude int32 + subBucketHalfCount int32 + subBucketMask int64 + subBucketCount int32 + bucketCount int32 + countsLen int32 + totalCount int64 + counts []int64 +} + +// New returns a new Histogram instance capable of tracking values in the given +// range and with the given amount of precision. +func New(minValue, maxValue int64, sigfigs int) *Histogram { + if sigfigs < 1 || 5 < sigfigs { + panic(fmt.Errorf("sigfigs must be [1,5] (was %d)", sigfigs)) + } + + largestValueWithSingleUnitResolution := 2 * math.Pow10(sigfigs) + subBucketCountMagnitude := int32(math.Ceil(math.Log2(float64(largestValueWithSingleUnitResolution)))) + + subBucketHalfCountMagnitude := subBucketCountMagnitude + if subBucketHalfCountMagnitude < 1 { + subBucketHalfCountMagnitude = 1 + } + subBucketHalfCountMagnitude-- + + unitMagnitude := int32(math.Floor(math.Log2(float64(minValue)))) + if unitMagnitude < 0 { + unitMagnitude = 0 + } + + subBucketCount := int32(math.Pow(2, float64(subBucketHalfCountMagnitude)+1)) + + subBucketHalfCount := subBucketCount / 2 + subBucketMask := int64(subBucketCount-1) << uint(unitMagnitude) + + // determine exponent range needed to support the trackable value with no + // overflow: + smallestUntrackableValue := int64(subBucketCount) << uint(unitMagnitude) + bucketsNeeded := int32(1) + for smallestUntrackableValue < maxValue { + smallestUntrackableValue <<= 1 + bucketsNeeded++ + } + + bucketCount := bucketsNeeded + countsLen := (bucketCount + 1) * (subBucketCount / 2) + + return &Histogram{ + lowestTrackableValue: minValue, + highestTrackableValue: maxValue, + unitMagnitude: int64(unitMagnitude), + significantFigures: int64(sigfigs), + subBucketHalfCountMagnitude: subBucketHalfCountMagnitude, + subBucketHalfCount: subBucketHalfCount, + subBucketMask: subBucketMask, + subBucketCount: subBucketCount, + bucketCount: bucketCount, + countsLen: countsLen, + totalCount: 0, + counts: make([]int64, countsLen), + } +} + +// ByteSize returns an estimate of the amount of memory allocated to the +// histogram in bytes. +// +// N.B.: This does not take into account the overhead for slices, which are +// small, constant, and specific to the compiler version. +func (h *Histogram) ByteSize() int { + return 6*8 + 5*4 + len(h.counts)*8 +} + +// Merge merges the data stored in the given histogram with the receiver, +// returning the number of recorded values which had to be dropped. +func (h *Histogram) Merge(from *Histogram) (dropped int64) { + i := from.rIterator() + for i.next() { + v := i.valueFromIdx + c := i.countAtIdx + + if h.RecordValues(v, c) != nil { + dropped += c + } + } + + return +} + +// TotalCount returns total number of values recorded. +func (h *Histogram) TotalCount() int64 { + return h.totalCount +} + +// Max returns the approximate maximum recorded value. +func (h *Histogram) Max() int64 { + var max int64 + i := h.iterator() + for i.next() { + if i.countAtIdx != 0 { + max = i.highestEquivalentValue + } + } + return h.highestEquivalentValue(max) +} + +// Min returns the approximate minimum recorded value. +func (h *Histogram) Min() int64 { + var min int64 + i := h.iterator() + for i.next() { + if i.countAtIdx != 0 && min == 0 { + min = i.highestEquivalentValue + break + } + } + return h.lowestEquivalentValue(min) +} + +// Mean returns the approximate arithmetic mean of the recorded values. +func (h *Histogram) Mean() float64 { + if h.totalCount == 0 { + return 0 + } + var total int64 + i := h.iterator() + for i.next() { + if i.countAtIdx != 0 { + total += i.countAtIdx * h.medianEquivalentValue(i.valueFromIdx) + } + } + return float64(total) / float64(h.totalCount) +} + +// StdDev returns the approximate standard deviation of the recorded values. +func (h *Histogram) StdDev() float64 { + if h.totalCount == 0 { + return 0 + } + + mean := h.Mean() + geometricDevTotal := 0.0 + + i := h.iterator() + for i.next() { + if i.countAtIdx != 0 { + dev := float64(h.medianEquivalentValue(i.valueFromIdx)) - mean + geometricDevTotal += (dev * dev) * float64(i.countAtIdx) + } + } + + return math.Sqrt(geometricDevTotal / float64(h.totalCount)) +} + +// Reset deletes all recorded values and restores the histogram to its original +// state. +func (h *Histogram) Reset() { + h.totalCount = 0 + for i := range h.counts { + h.counts[i] = 0 + } +} + +// RecordValue records the given value, returning an error if the value is out +// of range. +func (h *Histogram) RecordValue(v int64) error { + return h.RecordValues(v, 1) +} + +// RecordCorrectedValue records the given value, correcting for stalls in the +// recording process. This only works for processes which are recording values +// at an expected interval (e.g., doing jitter analysis). Processes which are +// recording ad-hoc values (e.g., latency for incoming requests) can't take +// advantage of this. +func (h *Histogram) RecordCorrectedValue(v, expectedInterval int64) error { + if err := h.RecordValue(v); err != nil { + return err + } + + if expectedInterval <= 0 || v <= expectedInterval { + return nil + } + + missingValue := v - expectedInterval + for missingValue >= expectedInterval { + if err := h.RecordValue(missingValue); err != nil { + return err + } + missingValue -= expectedInterval + } + + return nil +} + +// RecordValues records n occurrences of the given value, returning an error if +// the value is out of range. +func (h *Histogram) RecordValues(v, n int64) error { + idx := h.countsIndexFor(v) + if idx < 0 || int(h.countsLen) <= idx { + return fmt.Errorf("value %d is too large to be recorded", v) + } + h.counts[idx] += n + h.totalCount += n + + return nil +} + +// ValueAtQuantile returns the recorded value at the given quantile (0..100). +func (h *Histogram) ValueAtQuantile(q float64) int64 { + if q > 100 { + q = 100 + } + + total := int64(0) + countAtPercentile := int64(((q / 100) * float64(h.totalCount)) + 0.5) + + i := h.iterator() + for i.next() { + total += i.countAtIdx + if total >= countAtPercentile { + return h.highestEquivalentValue(i.valueFromIdx) + } + } + + return 0 +} + +// CumulativeDistribution returns an ordered list of brackets of the +// distribution of recorded values. +func (h *Histogram) CumulativeDistribution() []Bracket { + var result []Bracket + + i := h.pIterator(1) + for i.next() { + result = append(result, Bracket{ + Quantile: i.percentile, + Count: i.countToIdx, + ValueAt: i.highestEquivalentValue, + }) + } + + return result +} + +// SignificantFigures returns the significant figures used to create the +// histogram +func (h *Histogram) SignificantFigures() int64 { + return h.significantFigures +} + +// LowestTrackableValue returns the lower bound on values that will be added +// to the histogram +func (h *Histogram) LowestTrackableValue() int64 { + return h.lowestTrackableValue +} + +// HighestTrackableValue returns the upper bound on values that will be added +// to the histogram +func (h *Histogram) HighestTrackableValue() int64 { + return h.highestTrackableValue +} + +// Histogram bar for plotting +type Bar struct { + From, To, Count int64 +} + +// Pretty print as csv for easy plotting +func (b Bar) String() string { + return fmt.Sprintf("%v, %v, %v\n", b.From, b.To, b.Count) +} + +// Distribution returns an ordered list of bars of the +// distribution of recorded values, counts can be normalized to a probability +func (h *Histogram) Distribution() (result []Bar) { + i := h.iterator() + for i.next() { + result = append(result, Bar{ + Count: i.countAtIdx, + From: h.lowestEquivalentValue(i.valueFromIdx), + To: i.highestEquivalentValue, + }) + } + + return result +} + +// Equals returns true if the two Histograms are equivalent, false if not. +func (h *Histogram) Equals(other *Histogram) bool { + switch { + case + h.lowestTrackableValue != other.lowestTrackableValue, + h.highestTrackableValue != other.highestTrackableValue, + h.unitMagnitude != other.unitMagnitude, + h.significantFigures != other.significantFigures, + h.subBucketHalfCountMagnitude != other.subBucketHalfCountMagnitude, + h.subBucketHalfCount != other.subBucketHalfCount, + h.subBucketMask != other.subBucketMask, + h.subBucketCount != other.subBucketCount, + h.bucketCount != other.bucketCount, + h.countsLen != other.countsLen, + h.totalCount != other.totalCount: + return false + default: + for i, c := range h.counts { + if c != other.counts[i] { + return false + } + } + } + return true +} + +// Export returns a snapshot view of the Histogram. This can be later passed to +// Import to construct a new Histogram with the same state. +func (h *Histogram) Export() *Snapshot { + return &Snapshot{ + LowestTrackableValue: h.lowestTrackableValue, + HighestTrackableValue: h.highestTrackableValue, + SignificantFigures: h.significantFigures, + Counts: append([]int64(nil), h.counts...), // copy + } +} + +// Import returns a new Histogram populated from the Snapshot data (which the +// caller must stop accessing). +func Import(s *Snapshot) *Histogram { + h := New(s.LowestTrackableValue, s.HighestTrackableValue, int(s.SignificantFigures)) + h.counts = s.Counts + totalCount := int64(0) + for i := int32(0); i < h.countsLen; i++ { + countAtIndex := h.counts[i] + if countAtIndex > 0 { + totalCount += countAtIndex + } + } + h.totalCount = totalCount + return h +} + +func (h *Histogram) iterator() *iterator { + return &iterator{ + h: h, + subBucketIdx: -1, + } +} + +func (h *Histogram) rIterator() *rIterator { + return &rIterator{ + iterator: iterator{ + h: h, + subBucketIdx: -1, + }, + } +} + +func (h *Histogram) pIterator(ticksPerHalfDistance int32) *pIterator { + return &pIterator{ + iterator: iterator{ + h: h, + subBucketIdx: -1, + }, + ticksPerHalfDistance: ticksPerHalfDistance, + } +} + +func (h *Histogram) sizeOfEquivalentValueRange(v int64) int64 { + bucketIdx := h.getBucketIndex(v) + subBucketIdx := h.getSubBucketIdx(v, bucketIdx) + adjustedBucket := bucketIdx + if subBucketIdx >= h.subBucketCount { + adjustedBucket++ + } + return int64(1) << uint(h.unitMagnitude+int64(adjustedBucket)) +} + +func (h *Histogram) valueFromIndex(bucketIdx, subBucketIdx int32) int64 { + return int64(subBucketIdx) << uint(int64(bucketIdx)+h.unitMagnitude) +} + +func (h *Histogram) lowestEquivalentValue(v int64) int64 { + bucketIdx := h.getBucketIndex(v) + subBucketIdx := h.getSubBucketIdx(v, bucketIdx) + return h.valueFromIndex(bucketIdx, subBucketIdx) +} + +func (h *Histogram) nextNonEquivalentValue(v int64) int64 { + return h.lowestEquivalentValue(v) + h.sizeOfEquivalentValueRange(v) +} + +func (h *Histogram) highestEquivalentValue(v int64) int64 { + return h.nextNonEquivalentValue(v) - 1 +} + +func (h *Histogram) medianEquivalentValue(v int64) int64 { + return h.lowestEquivalentValue(v) + (h.sizeOfEquivalentValueRange(v) >> 1) +} + +func (h *Histogram) getCountAtIndex(bucketIdx, subBucketIdx int32) int64 { + return h.counts[h.countsIndex(bucketIdx, subBucketIdx)] +} + +func (h *Histogram) countsIndex(bucketIdx, subBucketIdx int32) int32 { + bucketBaseIdx := (bucketIdx + 1) << uint(h.subBucketHalfCountMagnitude) + offsetInBucket := subBucketIdx - h.subBucketHalfCount + return bucketBaseIdx + offsetInBucket +} + +func (h *Histogram) getBucketIndex(v int64) int32 { + pow2Ceiling := bitLen(v | h.subBucketMask) + return int32(pow2Ceiling - int64(h.unitMagnitude) - + int64(h.subBucketHalfCountMagnitude+1)) +} + +func (h *Histogram) getSubBucketIdx(v int64, idx int32) int32 { + return int32(v >> uint(int64(idx)+int64(h.unitMagnitude))) +} + +func (h *Histogram) countsIndexFor(v int64) int { + bucketIdx := h.getBucketIndex(v) + subBucketIdx := h.getSubBucketIdx(v, bucketIdx) + return int(h.countsIndex(bucketIdx, subBucketIdx)) +} + +type iterator struct { + h *Histogram + bucketIdx, subBucketIdx int32 + countAtIdx, countToIdx, valueFromIdx int64 + highestEquivalentValue int64 +} + +func (i *iterator) next() bool { + if i.countToIdx >= i.h.totalCount { + return false + } + + // increment bucket + i.subBucketIdx++ + if i.subBucketIdx >= i.h.subBucketCount { + i.subBucketIdx = i.h.subBucketHalfCount + i.bucketIdx++ + } + + if i.bucketIdx >= i.h.bucketCount { + return false + } + + i.countAtIdx = i.h.getCountAtIndex(i.bucketIdx, i.subBucketIdx) + i.countToIdx += i.countAtIdx + i.valueFromIdx = i.h.valueFromIndex(i.bucketIdx, i.subBucketIdx) + i.highestEquivalentValue = i.h.highestEquivalentValue(i.valueFromIdx) + + return true +} + +type rIterator struct { + iterator + countAddedThisStep int64 +} + +func (r *rIterator) next() bool { + for r.iterator.next() { + if r.countAtIdx != 0 { + r.countAddedThisStep = r.countAtIdx + return true + } + } + return false +} + +type pIterator struct { + iterator + seenLastValue bool + ticksPerHalfDistance int32 + percentileToIteratorTo float64 + percentile float64 +} + +func (p *pIterator) next() bool { + if !(p.countToIdx < p.h.totalCount) { + if p.seenLastValue { + return false + } + + p.seenLastValue = true + p.percentile = 100 + + return true + } + + if p.subBucketIdx == -1 && !p.iterator.next() { + return false + } + + var done = false + for !done { + currentPercentile := (100.0 * float64(p.countToIdx)) / float64(p.h.totalCount) + if p.countAtIdx != 0 && p.percentileToIteratorTo <= currentPercentile { + p.percentile = p.percentileToIteratorTo + halfDistance := math.Trunc(math.Pow(2, math.Trunc(math.Log2(100.0/(100.0-p.percentileToIteratorTo)))+1)) + percentileReportingTicks := float64(p.ticksPerHalfDistance) * halfDistance + p.percentileToIteratorTo += 100.0 / percentileReportingTicks + return true + } + done = !p.iterator.next() + } + + return true +} + +func bitLen(x int64) (n int64) { + for ; x >= 0x8000; x >>= 16 { + n += 16 + } + if x >= 0x80 { + x >>= 8 + n += 8 + } + if x >= 0x8 { + x >>= 4 + n += 4 + } + if x >= 0x2 { + x >>= 2 + n += 2 + } + if x >= 0x1 { + n++ + } + return +} diff --git a/vendor/github.com/codahale/hdrhistogram/window.go b/vendor/github.com/codahale/hdrhistogram/window.go new file mode 100644 index 0000000000..dc43612a4b --- /dev/null +++ b/vendor/github.com/codahale/hdrhistogram/window.go @@ -0,0 +1,45 @@ +package hdrhistogram + +// A WindowedHistogram combines histograms to provide windowed statistics. +type WindowedHistogram struct { + idx int + h []Histogram + m *Histogram + + Current *Histogram +} + +// NewWindowed creates a new WindowedHistogram with N underlying histograms with +// the given parameters. +func NewWindowed(n int, minValue, maxValue int64, sigfigs int) *WindowedHistogram { + w := WindowedHistogram{ + idx: -1, + h: make([]Histogram, n), + m: New(minValue, maxValue, sigfigs), + } + + for i := range w.h { + w.h[i] = *New(minValue, maxValue, sigfigs) + } + w.Rotate() + + return &w +} + +// Merge returns a histogram which includes the recorded values from all the +// sections of the window. +func (w *WindowedHistogram) Merge() *Histogram { + w.m.Reset() + for _, h := range w.h { + w.m.Merge(&h) + } + return w.m +} + +// Rotate resets the oldest histogram and rotates it to be used as the current +// histogram. +func (w *WindowedHistogram) Rotate() { + w.idx++ + w.Current = &w.h[w.idx%len(w.h)] + w.Current.Reset() +} diff --git a/vendor/github.com/deckarep/golang-set/LICENSE b/vendor/github.com/deckarep/golang-set/LICENSE new file mode 100644 index 0000000000..b5768f89cf --- /dev/null +++ b/vendor/github.com/deckarep/golang-set/LICENSE @@ -0,0 +1,22 @@ +Open Source Initiative OSI - The MIT License (MIT):Licensing + +The MIT License (MIT) +Copyright (c) 2013 Ralph Caraveo (deckarep@gmail.com) + +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. \ No newline at end of file diff --git a/vendor/github.com/deckarep/golang-set/README.md b/vendor/github.com/deckarep/golang-set/README.md new file mode 100644 index 0000000000..c3b50b2c5c --- /dev/null +++ b/vendor/github.com/deckarep/golang-set/README.md @@ -0,0 +1,95 @@ +[![Build Status](https://travis-ci.org/deckarep/golang-set.svg?branch=master)](https://travis-ci.org/deckarep/golang-set) +[![Go Report Card](https://goreportcard.com/badge/github.com/deckarep/golang-set)](https://goreportcard.com/report/github.com/deckarep/golang-set) +[![GoDoc](https://godoc.org/github.com/deckarep/golang-set?status.svg)](http://godoc.org/github.com/deckarep/golang-set) + +## golang-set + + +The missing set collection for the Go language. Until Go has sets built-in...use this. + +Coming from Python one of the things I miss is the superbly wonderful set collection. This is my attempt to mimic the primary features of the set from Python. +You can of course argue that there is no need for a set in Go, otherwise the creators would have added one to the standard library. To those I say simply ignore this repository +and carry-on and to the rest that find this useful please contribute in helping me make it better by: + +* Helping to make more idiomatic improvements to the code. +* Helping to increase the performance of it. ~~(So far, no attempt has been made, but since it uses a map internally, I expect it to be mostly performant.)~~ +* Helping to make the unit-tests more robust and kick-ass. +* Helping to fill in the [documentation.](http://godoc.org/github.com/deckarep/golang-set) +* Simply offering feedback and suggestions. (Positive, constructive feedback is appreciated.) + +I have to give some credit for helping seed the idea with this post on [stackoverflow.](http://programmers.stackexchange.com/questions/177428/sets-data-structure-in-golang) + +*Update* - as of 3/9/2014, you can use a compile-time generic version of this package in the [gen](http://clipperhouse.github.io/gen/) framework. This framework allows you to use the golang-set in a completely generic and type-safe way by allowing you to generate a supporting .go file based on your custom types. + +## Features (as of 9/22/2014) + +* a CartesianProduct() method has been added with unit-tests: [Read more about the cartesian product](http://en.wikipedia.org/wiki/Cartesian_product) + +## Features (as of 9/15/2014) + +* a PowerSet() method has been added with unit-tests: [Read more about the Power set](http://en.wikipedia.org/wiki/Power_set) + +## Features (as of 4/22/2014) + +* One common interface to both implementations +* Two set implementations to choose from + * a thread-safe implementation designed for concurrent use + * a non-thread-safe implementation designed for performance +* 75 benchmarks for both implementations +* 35 unit tests for both implementations +* 14 concurrent tests for the thread-safe implementation + + + +Please see the unit test file for additional usage examples. The Python set documentation will also do a better job than I can of explaining how a set typically [works.](http://docs.python.org/2/library/sets.html) Please keep in mind +however that the Python set is a built-in type and supports additional features and syntax that make it awesome. + +## Examples but not exhaustive: + +```go +requiredClasses := mapset.NewSet() +requiredClasses.Add("Cooking") +requiredClasses.Add("English") +requiredClasses.Add("Math") +requiredClasses.Add("Biology") + +scienceSlice := []interface{}{"Biology", "Chemistry"} +scienceClasses := mapset.NewSetFromSlice(scienceSlice) + +electiveClasses := mapset.NewSet() +electiveClasses.Add("Welding") +electiveClasses.Add("Music") +electiveClasses.Add("Automotive") + +bonusClasses := mapset.NewSet() +bonusClasses.Add("Go Programming") +bonusClasses.Add("Python Programming") + +//Show me all the available classes I can take +allClasses := requiredClasses.Union(scienceClasses).Union(electiveClasses).Union(bonusClasses) +fmt.Println(allClasses) //Set{Cooking, English, Math, Chemistry, Welding, Biology, Music, Automotive, Go Programming, Python Programming} + + +//Is cooking considered a science class? +fmt.Println(scienceClasses.Contains("Cooking")) //false + +//Show me all classes that are not science classes, since I hate science. +fmt.Println(allClasses.Difference(scienceClasses)) //Set{Music, Automotive, Go Programming, Python Programming, Cooking, English, Math, Welding} + +//Which science classes are also required classes? +fmt.Println(scienceClasses.Intersect(requiredClasses)) //Set{Biology} + +//How many bonus classes do you offer? +fmt.Println(bonusClasses.Cardinality()) //2 + +//Do you have the following classes? Welding, Automotive and English? +fmt.Println(allClasses.IsSuperset(mapset.NewSetFromSlice([]interface{}{"Welding", "Automotive", "English"}))) //true +``` + +Thanks! + +-Ralph + +[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/deckarep/golang-set/trend.png)](https://bitdeli.com/free "Bitdeli Badge") + +[![Analytics](https://ga-beacon.appspot.com/UA-42584447-2/deckarep/golang-set)](https://github.com/igrigorik/ga-beacon) diff --git a/vendor/github.com/deckarep/golang-set/iterator.go b/vendor/github.com/deckarep/golang-set/iterator.go new file mode 100644 index 0000000000..9dfecade42 --- /dev/null +++ b/vendor/github.com/deckarep/golang-set/iterator.go @@ -0,0 +1,58 @@ +/* +Open Source Initiative OSI - The MIT License (MIT):Licensing + +The MIT License (MIT) +Copyright (c) 2013 Ralph Caraveo (deckarep@gmail.com) + +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 mapset + +// Iterator defines an iterator over a Set, its C channel can be used to range over the Set's +// elements. +type Iterator struct { + C <-chan interface{} + stop chan struct{} +} + +// Stop stops the Iterator, no further elements will be received on C, C will be closed. +func (i *Iterator) Stop() { + // Allows for Stop() to be called multiple times + // (close() panics when called on already closed channel) + defer func() { + recover() + }() + + close(i.stop) + + // Exhaust any remaining elements. + for range i.C { + } +} + +// newIterator returns a new Iterator instance together with its item and stop channels. +func newIterator() (*Iterator, chan<- interface{}, <-chan struct{}) { + itemChan := make(chan interface{}) + stopChan := make(chan struct{}) + return &Iterator{ + C: itemChan, + stop: stopChan, + }, itemChan, stopChan +} diff --git a/vendor/github.com/deckarep/golang-set/set.go b/vendor/github.com/deckarep/golang-set/set.go new file mode 100644 index 0000000000..29eb2e5a22 --- /dev/null +++ b/vendor/github.com/deckarep/golang-set/set.go @@ -0,0 +1,217 @@ +/* +Open Source Initiative OSI - The MIT License (MIT):Licensing + +The MIT License (MIT) +Copyright (c) 2013 Ralph Caraveo (deckarep@gmail.com) + +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 mapset implements a simple and generic set collection. +// Items stored within it are unordered and unique. It supports +// typical set operations: membership testing, intersection, union, +// difference, symmetric difference and cloning. +// +// Package mapset provides two implementations of the Set +// interface. The default implementation is safe for concurrent +// access, but a non-thread-safe implementation is also provided for +// programs that can benefit from the slight speed improvement and +// that can enforce mutual exclusion through other means. +package mapset + +// Set is the primary interface provided by the mapset package. It +// represents an unordered set of data and a large number of +// operations that can be applied to that set. +type Set interface { + // Adds an element to the set. Returns whether + // the item was added. + Add(i interface{}) bool + + // Returns the number of elements in the set. + Cardinality() int + + // Removes all elements from the set, leaving + // the empty set. + Clear() + + // Returns a clone of the set using the same + // implementation, duplicating all keys. + Clone() Set + + // Returns whether the given items + // are all in the set. + Contains(i ...interface{}) bool + + // Returns the difference between this set + // and other. The returned set will contain + // all elements of this set that are not also + // elements of other. + // + // Note that the argument to Difference + // must be of the same type as the receiver + // of the method. Otherwise, Difference will + // panic. + Difference(other Set) Set + + // Determines if two sets are equal to each + // other. If they have the same cardinality + // and contain the same elements, they are + // considered equal. The order in which + // the elements were added is irrelevant. + // + // Note that the argument to Equal must be + // of the same type as the receiver of the + // method. Otherwise, Equal will panic. + Equal(other Set) bool + + // Returns a new set containing only the elements + // that exist only in both sets. + // + // Note that the argument to Intersect + // must be of the same type as the receiver + // of the method. Otherwise, Intersect will + // panic. + Intersect(other Set) Set + + // Determines if every element in this set is in + // the other set but the two sets are not equal. + // + // Note that the argument to IsProperSubset + // must be of the same type as the receiver + // of the method. Otherwise, IsProperSubset + // will panic. + IsProperSubset(other Set) bool + + // Determines if every element in the other set + // is in this set but the two sets are not + // equal. + // + // Note that the argument to IsSuperset + // must be of the same type as the receiver + // of the method. Otherwise, IsSuperset will + // panic. + IsProperSuperset(other Set) bool + + // Determines if every element in this set is in + // the other set. + // + // Note that the argument to IsSubset + // must be of the same type as the receiver + // of the method. Otherwise, IsSubset will + // panic. + IsSubset(other Set) bool + + // Determines if every element in the other set + // is in this set. + // + // Note that the argument to IsSuperset + // must be of the same type as the receiver + // of the method. Otherwise, IsSuperset will + // panic. + IsSuperset(other Set) bool + + // Iterates over elements and executes the passed func against each element. + // If passed func returns true, stop iteration at the time. + Each(func(interface{}) bool) + + // Returns a channel of elements that you can + // range over. + Iter() <-chan interface{} + + // Returns an Iterator object that you can + // use to range over the set. + Iterator() *Iterator + + // Remove a single element from the set. + Remove(i interface{}) + + // Provides a convenient string representation + // of the current state of the set. + String() string + + // Returns a new set with all elements which are + // in either this set or the other set but not in both. + // + // Note that the argument to SymmetricDifference + // must be of the same type as the receiver + // of the method. Otherwise, SymmetricDifference + // will panic. + SymmetricDifference(other Set) Set + + // Returns a new set with all elements in both sets. + // + // Note that the argument to Union must be of the + + // same type as the receiver of the method. + // Otherwise, IsSuperset will panic. + Union(other Set) Set + + // Pop removes and returns an arbitrary item from the set. + Pop() interface{} + + // Returns all subsets of a given set (Power Set). + PowerSet() Set + + // Returns the Cartesian Product of two sets. + CartesianProduct(other Set) Set + + // Returns the members of the set as a slice. + ToSlice() []interface{} +} + +// NewSet creates and returns a reference to an empty set. Operations +// on the resulting set are thread-safe. +func NewSet(s ...interface{}) Set { + set := newThreadSafeSet() + for _, item := range s { + set.Add(item) + } + return &set +} + +// NewSetWith creates and returns a new set with the given elements. +// Operations on the resulting set are thread-safe. +func NewSetWith(elts ...interface{}) Set { + return NewSetFromSlice(elts) +} + +// NewSetFromSlice creates and returns a reference to a set from an +// existing slice. Operations on the resulting set are thread-safe. +func NewSetFromSlice(s []interface{}) Set { + a := NewSet(s...) + return a +} + +// NewThreadUnsafeSet creates and returns a reference to an empty set. +// Operations on the resulting set are not thread-safe. +func NewThreadUnsafeSet() Set { + set := newThreadUnsafeSet() + return &set +} + +// NewThreadUnsafeSetFromSlice creates and returns a reference to a +// set from an existing slice. Operations on the resulting set are +// not thread-safe. +func NewThreadUnsafeSetFromSlice(s []interface{}) Set { + a := NewThreadUnsafeSet() + for _, item := range s { + a.Add(item) + } + return a +} diff --git a/vendor/github.com/deckarep/golang-set/threadsafe.go b/vendor/github.com/deckarep/golang-set/threadsafe.go new file mode 100644 index 0000000000..002e06af1f --- /dev/null +++ b/vendor/github.com/deckarep/golang-set/threadsafe.go @@ -0,0 +1,277 @@ +/* +Open Source Initiative OSI - The MIT License (MIT):Licensing + +The MIT License (MIT) +Copyright (c) 2013 Ralph Caraveo (deckarep@gmail.com) + +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 mapset + +import "sync" + +type threadSafeSet struct { + s threadUnsafeSet + sync.RWMutex +} + +func newThreadSafeSet() threadSafeSet { + return threadSafeSet{s: newThreadUnsafeSet()} +} + +func (set *threadSafeSet) Add(i interface{}) bool { + set.Lock() + ret := set.s.Add(i) + set.Unlock() + return ret +} + +func (set *threadSafeSet) Contains(i ...interface{}) bool { + set.RLock() + ret := set.s.Contains(i...) + set.RUnlock() + return ret +} + +func (set *threadSafeSet) IsSubset(other Set) bool { + o := other.(*threadSafeSet) + + set.RLock() + o.RLock() + + ret := set.s.IsSubset(&o.s) + set.RUnlock() + o.RUnlock() + return ret +} + +func (set *threadSafeSet) IsProperSubset(other Set) bool { + o := other.(*threadSafeSet) + + set.RLock() + defer set.RUnlock() + o.RLock() + defer o.RUnlock() + + return set.s.IsProperSubset(&o.s) +} + +func (set *threadSafeSet) IsSuperset(other Set) bool { + return other.IsSubset(set) +} + +func (set *threadSafeSet) IsProperSuperset(other Set) bool { + return other.IsProperSubset(set) +} + +func (set *threadSafeSet) Union(other Set) Set { + o := other.(*threadSafeSet) + + set.RLock() + o.RLock() + + unsafeUnion := set.s.Union(&o.s).(*threadUnsafeSet) + ret := &threadSafeSet{s: *unsafeUnion} + set.RUnlock() + o.RUnlock() + return ret +} + +func (set *threadSafeSet) Intersect(other Set) Set { + o := other.(*threadSafeSet) + + set.RLock() + o.RLock() + + unsafeIntersection := set.s.Intersect(&o.s).(*threadUnsafeSet) + ret := &threadSafeSet{s: *unsafeIntersection} + set.RUnlock() + o.RUnlock() + return ret +} + +func (set *threadSafeSet) Difference(other Set) Set { + o := other.(*threadSafeSet) + + set.RLock() + o.RLock() + + unsafeDifference := set.s.Difference(&o.s).(*threadUnsafeSet) + ret := &threadSafeSet{s: *unsafeDifference} + set.RUnlock() + o.RUnlock() + return ret +} + +func (set *threadSafeSet) SymmetricDifference(other Set) Set { + o := other.(*threadSafeSet) + + set.RLock() + o.RLock() + + unsafeDifference := set.s.SymmetricDifference(&o.s).(*threadUnsafeSet) + ret := &threadSafeSet{s: *unsafeDifference} + set.RUnlock() + o.RUnlock() + return ret +} + +func (set *threadSafeSet) Clear() { + set.Lock() + set.s = newThreadUnsafeSet() + set.Unlock() +} + +func (set *threadSafeSet) Remove(i interface{}) { + set.Lock() + delete(set.s, i) + set.Unlock() +} + +func (set *threadSafeSet) Cardinality() int { + set.RLock() + defer set.RUnlock() + return len(set.s) +} + +func (set *threadSafeSet) Each(cb func(interface{}) bool) { + set.RLock() + for elem := range set.s { + if cb(elem) { + break + } + } + set.RUnlock() +} + +func (set *threadSafeSet) Iter() <-chan interface{} { + ch := make(chan interface{}) + go func() { + set.RLock() + + for elem := range set.s { + ch <- elem + } + close(ch) + set.RUnlock() + }() + + return ch +} + +func (set *threadSafeSet) Iterator() *Iterator { + iterator, ch, stopCh := newIterator() + + go func() { + set.RLock() + L: + for elem := range set.s { + select { + case <-stopCh: + break L + case ch <- elem: + } + } + close(ch) + set.RUnlock() + }() + + return iterator +} + +func (set *threadSafeSet) Equal(other Set) bool { + o := other.(*threadSafeSet) + + set.RLock() + o.RLock() + + ret := set.s.Equal(&o.s) + set.RUnlock() + o.RUnlock() + return ret +} + +func (set *threadSafeSet) Clone() Set { + set.RLock() + + unsafeClone := set.s.Clone().(*threadUnsafeSet) + ret := &threadSafeSet{s: *unsafeClone} + set.RUnlock() + return ret +} + +func (set *threadSafeSet) String() string { + set.RLock() + ret := set.s.String() + set.RUnlock() + return ret +} + +func (set *threadSafeSet) PowerSet() Set { + set.RLock() + ret := set.s.PowerSet() + set.RUnlock() + return ret +} + +func (set *threadSafeSet) Pop() interface{} { + set.Lock() + defer set.Unlock() + return set.s.Pop() +} + +func (set *threadSafeSet) CartesianProduct(other Set) Set { + o := other.(*threadSafeSet) + + set.RLock() + o.RLock() + + unsafeCartProduct := set.s.CartesianProduct(&o.s).(*threadUnsafeSet) + ret := &threadSafeSet{s: *unsafeCartProduct} + set.RUnlock() + o.RUnlock() + return ret +} + +func (set *threadSafeSet) ToSlice() []interface{} { + keys := make([]interface{}, 0, set.Cardinality()) + set.RLock() + for elem := range set.s { + keys = append(keys, elem) + } + set.RUnlock() + return keys +} + +func (set *threadSafeSet) MarshalJSON() ([]byte, error) { + set.RLock() + b, err := set.s.MarshalJSON() + set.RUnlock() + + return b, err +} + +func (set *threadSafeSet) UnmarshalJSON(p []byte) error { + set.RLock() + err := set.s.UnmarshalJSON(p) + set.RUnlock() + + return err +} diff --git a/vendor/github.com/deckarep/golang-set/threadunsafe.go b/vendor/github.com/deckarep/golang-set/threadunsafe.go new file mode 100644 index 0000000000..10bdd46f15 --- /dev/null +++ b/vendor/github.com/deckarep/golang-set/threadunsafe.go @@ -0,0 +1,337 @@ +/* +Open Source Initiative OSI - The MIT License (MIT):Licensing + +The MIT License (MIT) +Copyright (c) 2013 Ralph Caraveo (deckarep@gmail.com) + +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 mapset + +import ( + "bytes" + "encoding/json" + "fmt" + "reflect" + "strings" +) + +type threadUnsafeSet map[interface{}]struct{} + +// An OrderedPair represents a 2-tuple of values. +type OrderedPair struct { + First interface{} + Second interface{} +} + +func newThreadUnsafeSet() threadUnsafeSet { + return make(threadUnsafeSet) +} + +// Equal says whether two 2-tuples contain the same values in the same order. +func (pair *OrderedPair) Equal(other OrderedPair) bool { + if pair.First == other.First && + pair.Second == other.Second { + return true + } + + return false +} + +func (set *threadUnsafeSet) Add(i interface{}) bool { + _, found := (*set)[i] + if found { + return false //False if it existed already + } + + (*set)[i] = struct{}{} + return true +} + +func (set *threadUnsafeSet) Contains(i ...interface{}) bool { + for _, val := range i { + if _, ok := (*set)[val]; !ok { + return false + } + } + return true +} + +func (set *threadUnsafeSet) IsSubset(other Set) bool { + _ = other.(*threadUnsafeSet) + for elem := range *set { + if !other.Contains(elem) { + return false + } + } + return true +} + +func (set *threadUnsafeSet) IsProperSubset(other Set) bool { + return set.IsSubset(other) && !set.Equal(other) +} + +func (set *threadUnsafeSet) IsSuperset(other Set) bool { + return other.IsSubset(set) +} + +func (set *threadUnsafeSet) IsProperSuperset(other Set) bool { + return set.IsSuperset(other) && !set.Equal(other) +} + +func (set *threadUnsafeSet) Union(other Set) Set { + o := other.(*threadUnsafeSet) + + unionedSet := newThreadUnsafeSet() + + for elem := range *set { + unionedSet.Add(elem) + } + for elem := range *o { + unionedSet.Add(elem) + } + return &unionedSet +} + +func (set *threadUnsafeSet) Intersect(other Set) Set { + o := other.(*threadUnsafeSet) + + intersection := newThreadUnsafeSet() + // loop over smaller set + if set.Cardinality() < other.Cardinality() { + for elem := range *set { + if other.Contains(elem) { + intersection.Add(elem) + } + } + } else { + for elem := range *o { + if set.Contains(elem) { + intersection.Add(elem) + } + } + } + return &intersection +} + +func (set *threadUnsafeSet) Difference(other Set) Set { + _ = other.(*threadUnsafeSet) + + difference := newThreadUnsafeSet() + for elem := range *set { + if !other.Contains(elem) { + difference.Add(elem) + } + } + return &difference +} + +func (set *threadUnsafeSet) SymmetricDifference(other Set) Set { + _ = other.(*threadUnsafeSet) + + aDiff := set.Difference(other) + bDiff := other.Difference(set) + return aDiff.Union(bDiff) +} + +func (set *threadUnsafeSet) Clear() { + *set = newThreadUnsafeSet() +} + +func (set *threadUnsafeSet) Remove(i interface{}) { + delete(*set, i) +} + +func (set *threadUnsafeSet) Cardinality() int { + return len(*set) +} + +func (set *threadUnsafeSet) Each(cb func(interface{}) bool) { + for elem := range *set { + if cb(elem) { + break + } + } +} + +func (set *threadUnsafeSet) Iter() <-chan interface{} { + ch := make(chan interface{}) + go func() { + for elem := range *set { + ch <- elem + } + close(ch) + }() + + return ch +} + +func (set *threadUnsafeSet) Iterator() *Iterator { + iterator, ch, stopCh := newIterator() + + go func() { + L: + for elem := range *set { + select { + case <-stopCh: + break L + case ch <- elem: + } + } + close(ch) + }() + + return iterator +} + +func (set *threadUnsafeSet) Equal(other Set) bool { + _ = other.(*threadUnsafeSet) + + if set.Cardinality() != other.Cardinality() { + return false + } + for elem := range *set { + if !other.Contains(elem) { + return false + } + } + return true +} + +func (set *threadUnsafeSet) Clone() Set { + clonedSet := newThreadUnsafeSet() + for elem := range *set { + clonedSet.Add(elem) + } + return &clonedSet +} + +func (set *threadUnsafeSet) String() string { + items := make([]string, 0, len(*set)) + + for elem := range *set { + items = append(items, fmt.Sprintf("%v", elem)) + } + return fmt.Sprintf("Set{%s}", strings.Join(items, ", ")) +} + +// String outputs a 2-tuple in the form "(A, B)". +func (pair OrderedPair) String() string { + return fmt.Sprintf("(%v, %v)", pair.First, pair.Second) +} + +func (set *threadUnsafeSet) Pop() interface{} { + for item := range *set { + delete(*set, item) + return item + } + return nil +} + +func (set *threadUnsafeSet) PowerSet() Set { + powSet := NewThreadUnsafeSet() + nullset := newThreadUnsafeSet() + powSet.Add(&nullset) + + for es := range *set { + u := newThreadUnsafeSet() + j := powSet.Iter() + for er := range j { + p := newThreadUnsafeSet() + if reflect.TypeOf(er).Name() == "" { + k := er.(*threadUnsafeSet) + for ek := range *(k) { + p.Add(ek) + } + } else { + p.Add(er) + } + p.Add(es) + u.Add(&p) + } + + powSet = powSet.Union(&u) + } + + return powSet +} + +func (set *threadUnsafeSet) CartesianProduct(other Set) Set { + o := other.(*threadUnsafeSet) + cartProduct := NewThreadUnsafeSet() + + for i := range *set { + for j := range *o { + elem := OrderedPair{First: i, Second: j} + cartProduct.Add(elem) + } + } + + return cartProduct +} + +func (set *threadUnsafeSet) ToSlice() []interface{} { + keys := make([]interface{}, 0, set.Cardinality()) + for elem := range *set { + keys = append(keys, elem) + } + + return keys +} + +// MarshalJSON creates a JSON array from the set, it marshals all elements +func (set *threadUnsafeSet) MarshalJSON() ([]byte, error) { + items := make([]string, 0, set.Cardinality()) + + for elem := range *set { + b, err := json.Marshal(elem) + if err != nil { + return nil, err + } + + items = append(items, string(b)) + } + + return []byte(fmt.Sprintf("[%s]", strings.Join(items, ","))), nil +} + +// UnmarshalJSON recreates a set from a JSON array, it only decodes +// primitive types. Numbers are decoded as json.Number. +func (set *threadUnsafeSet) UnmarshalJSON(b []byte) error { + var i []interface{} + + d := json.NewDecoder(bytes.NewReader(b)) + d.UseNumber() + err := d.Decode(&i) + if err != nil { + return err + } + + for _, v := range i { + switch t := v.(type) { + case []interface{}, map[string]interface{}: + continue + default: + set.Add(t) + } + } + + return nil +} diff --git a/vendor/github.com/docker/docker/pkg/reexec/command_linux.go b/vendor/github.com/docker/docker/pkg/reexec/command_linux.go index 34ae2a9dcd..efea71794f 100644 --- a/vendor/github.com/docker/docker/pkg/reexec/command_linux.go +++ b/vendor/github.com/docker/docker/pkg/reexec/command_linux.go @@ -1,10 +1,10 @@ -// +build linux - -package reexec +package reexec // import "github.com/docker/docker/pkg/reexec" import ( "os/exec" "syscall" + + "golang.org/x/sys/unix" ) // Self returns the path to the current process's binary. @@ -22,7 +22,7 @@ func Command(args ...string) *exec.Cmd { Path: Self(), Args: args, SysProcAttr: &syscall.SysProcAttr{ - Pdeathsig: syscall.SIGTERM, + Pdeathsig: unix.SIGTERM, }, } } diff --git a/vendor/github.com/docker/docker/pkg/reexec/command_unix.go b/vendor/github.com/docker/docker/pkg/reexec/command_unix.go index 778a720e3b..ceaabbdeee 100644 --- a/vendor/github.com/docker/docker/pkg/reexec/command_unix.go +++ b/vendor/github.com/docker/docker/pkg/reexec/command_unix.go @@ -1,6 +1,6 @@ -// +build freebsd solaris darwin +// +build freebsd darwin -package reexec +package reexec // import "github.com/docker/docker/pkg/reexec" import ( "os/exec" diff --git a/vendor/github.com/docker/docker/pkg/reexec/command_unsupported.go b/vendor/github.com/docker/docker/pkg/reexec/command_unsupported.go index 76edd82427..e7eed24240 100644 --- a/vendor/github.com/docker/docker/pkg/reexec/command_unsupported.go +++ b/vendor/github.com/docker/docker/pkg/reexec/command_unsupported.go @@ -1,12 +1,16 @@ -// +build !linux,!windows,!freebsd,!solaris,!darwin +// +build !linux,!windows,!freebsd,!darwin -package reexec +package reexec // import "github.com/docker/docker/pkg/reexec" import ( "os/exec" ) -// Command is unsupported on operating systems apart from Linux, Windows, Solaris and Darwin. +func Self() string { + return "" +} + +// Command is unsupported on operating systems apart from Linux, Windows, and Darwin. func Command(args ...string) *exec.Cmd { return nil } diff --git a/vendor/github.com/docker/docker/pkg/reexec/command_windows.go b/vendor/github.com/docker/docker/pkg/reexec/command_windows.go index ca871c4227..438226890f 100644 --- a/vendor/github.com/docker/docker/pkg/reexec/command_windows.go +++ b/vendor/github.com/docker/docker/pkg/reexec/command_windows.go @@ -1,6 +1,4 @@ -// +build windows - -package reexec +package reexec // import "github.com/docker/docker/pkg/reexec" import ( "os/exec" diff --git a/vendor/github.com/docker/docker/pkg/reexec/reexec.go b/vendor/github.com/docker/docker/pkg/reexec/reexec.go index c56671d919..f8ccddd599 100644 --- a/vendor/github.com/docker/docker/pkg/reexec/reexec.go +++ b/vendor/github.com/docker/docker/pkg/reexec/reexec.go @@ -1,4 +1,4 @@ -package reexec +package reexec // import "github.com/docker/docker/pkg/reexec" import ( "fmt" diff --git a/vendor/github.com/elastic/gosigar/CHANGELOG.md b/vendor/github.com/elastic/gosigar/CHANGELOG.md index 12695e10ef..45262e7b8d 100644 --- a/vendor/github.com/elastic/gosigar/CHANGELOG.md +++ b/vendor/github.com/elastic/gosigar/CHANGELOG.md @@ -8,10 +8,21 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Fixed +- Added missing runtime import for FreeBSD. #104 + ### Changed ### Deprecated +## [0.9.0] + +### Added +- Added support for huge TLB pages on Linux #97 +- Added support for big endian platform #100 + +### Fixed +- Add missing method for OpenBSD #99 + ## [0.8.0] ### Added diff --git a/vendor/github.com/elastic/gosigar/README.md b/vendor/github.com/elastic/gosigar/README.md index 2482620a83..ecdfc1c3c5 100644 --- a/vendor/github.com/elastic/gosigar/README.md +++ b/vendor/github.com/elastic/gosigar/README.md @@ -26,6 +26,7 @@ The features vary by operating system. | FDUsage | X | | | | X | | FileSystemList | X | X | X | X | X | | FileSystemUsage | X | X | X | X | X | +| HugeTLBPages | X | | | | | | LoadAverage | X | X | | X | X | | Mem | X | X | X | X | X | | ProcArgs | X | X | X | | X | diff --git a/vendor/github.com/elastic/gosigar/concrete_sigar.go b/vendor/github.com/elastic/gosigar/concrete_sigar.go index 685aa6dedd..e3ee80a980 100644 --- a/vendor/github.com/elastic/gosigar/concrete_sigar.go +++ b/vendor/github.com/elastic/gosigar/concrete_sigar.go @@ -62,6 +62,12 @@ func (c *ConcreteSigar) GetSwap() (Swap, error) { return s, err } +func (c *ConcreteSigar) GetHugeTLBPages() (HugeTLBPages, error) { + p := HugeTLBPages{} + err := p.Get() + return p, err +} + func (c *ConcreteSigar) GetFileSystemUsage(path string) (FileSystemUsage, error) { f := FileSystemUsage{} err := f.Get(path) diff --git a/vendor/github.com/elastic/gosigar/sigar_darwin.go b/vendor/github.com/elastic/gosigar/sigar_darwin.go index f989f51608..a90b998c2e 100644 --- a/vendor/github.com/elastic/gosigar/sigar_darwin.go +++ b/vendor/github.com/elastic/gosigar/sigar_darwin.go @@ -91,6 +91,10 @@ func (self *Swap) Get() error { return nil } +func (self *HugeTLBPages) Get() error { + return ErrNotImplemented{runtime.GOOS} +} + func (self *Cpu) Get() error { var count C.mach_msg_type_number_t = C.HOST_CPU_LOAD_INFO_COUNT var cpuload C.host_cpu_load_info_data_t diff --git a/vendor/github.com/elastic/gosigar/sigar_freebsd.go b/vendor/github.com/elastic/gosigar/sigar_freebsd.go index 602b4a0aad..9b2af639b6 100644 --- a/vendor/github.com/elastic/gosigar/sigar_freebsd.go +++ b/vendor/github.com/elastic/gosigar/sigar_freebsd.go @@ -4,6 +4,7 @@ package gosigar import ( "io/ioutil" + "runtime" "strconv" "strings" "unsafe" @@ -97,6 +98,10 @@ func (self *ProcFDUsage) Get(pid int) error { return nil } +func (self *HugeTLBPages) Get() error { + return ErrNotImplemented{runtime.GOOS} +} + func parseCpuStat(self *Cpu, line string) error { fields := strings.Fields(line) diff --git a/vendor/github.com/elastic/gosigar/sigar_interface.go b/vendor/github.com/elastic/gosigar/sigar_interface.go index a956af604a..df79ae08d2 100644 --- a/vendor/github.com/elastic/gosigar/sigar_interface.go +++ b/vendor/github.com/elastic/gosigar/sigar_interface.go @@ -26,6 +26,7 @@ type Sigar interface { GetLoadAverage() (LoadAverage, error) GetMem() (Mem, error) GetSwap() (Swap, error) + GetHugeTLBPages(HugeTLBPages, error) GetFileSystemUsage(string) (FileSystemUsage, error) GetFDUsage() (FDUsage, error) GetRusage(who int) (Rusage, error) @@ -82,6 +83,15 @@ type Swap struct { Free uint64 } +type HugeTLBPages struct { + Total uint64 + Free uint64 + Reserved uint64 + Surplus uint64 + DefaultSize uint64 + TotalAllocatedSize uint64 +} + type CpuList struct { List []Cpu } diff --git a/vendor/github.com/elastic/gosigar/sigar_linux.go b/vendor/github.com/elastic/gosigar/sigar_linux.go index cb1d3525b5..09f2e30b2f 100644 --- a/vendor/github.com/elastic/gosigar/sigar_linux.go +++ b/vendor/github.com/elastic/gosigar/sigar_linux.go @@ -45,6 +45,30 @@ func (self *FDUsage) Get() error { }) } +func (self *HugeTLBPages) Get() error { + table, err := parseMeminfo() + if err != nil { + return err + } + + self.Total, _ = table["HugePages_Total"] + self.Free, _ = table["HugePages_Free"] + self.Reserved, _ = table["HugePages_Rsvd"] + self.Surplus, _ = table["HugePages_Surp"] + self.DefaultSize, _ = table["Hugepagesize"] + + if totalSize, found := table["Hugetlb"]; found { + self.TotalAllocatedSize = totalSize + } else { + // If Hugetlb is not present, or huge pages of different sizes + // are used, this figure can be unaccurate. + // TODO (jsoriano): Extract information from /sys/kernel/mm/hugepages too + self.TotalAllocatedSize = (self.Total - self.Free + self.Reserved) * self.DefaultSize + } + + return nil +} + func (self *ProcFDUsage) Get(pid int) error { err := readFile(procFileName(pid, "limits"), func(line string) bool { if strings.HasPrefix(line, "Max open files") { diff --git a/vendor/github.com/elastic/gosigar/sigar_linux_common.go b/vendor/github.com/elastic/gosigar/sigar_linux_common.go index 8e5e7856f6..7ca6497622 100644 --- a/vendor/github.com/elastic/gosigar/sigar_linux_common.go +++ b/vendor/github.com/elastic/gosigar/sigar_linux_common.go @@ -379,12 +379,16 @@ func parseMeminfo() (map[string]uint64, error) { return true // skip on errors } - num := strings.TrimLeft(fields[1], " ") - val, err := strtoull(strings.Fields(num)[0]) + valueUnit := strings.Fields(fields[1]) + value, err := strtoull(valueUnit[0]) if err != nil { return true // skip on errors } - table[fields[0]] = val * 1024 //in bytes + + if len(valueUnit) > 1 && valueUnit[1] == "kB" { + value *= 1024 + } + table[fields[0]] = value return true }) @@ -420,8 +424,18 @@ func procFileName(pid int, name string) string { return Procd + "/" + strconv.Itoa(pid) + "/" + name } -func readProcFile(pid int, name string) ([]byte, error) { +func readProcFile(pid int, name string) (content []byte, err error) { path := procFileName(pid, name) + + // Panics have been reported when reading proc files, let's recover and + // report the path if this happens + // See https://github.com/elastic/beats/issues/6692 + defer func() { + if r := recover(); r != nil { + content = nil + err = fmt.Errorf("recovered panic when reading proc file '%s': %v", path, r) + } + }() contents, err := ioutil.ReadFile(path) if err != nil { diff --git a/vendor/github.com/elastic/gosigar/sigar_openbsd.go b/vendor/github.com/elastic/gosigar/sigar_openbsd.go index 4f1383a6ba..e4371b8b68 100644 --- a/vendor/github.com/elastic/gosigar/sigar_openbsd.go +++ b/vendor/github.com/elastic/gosigar/sigar_openbsd.go @@ -294,6 +294,10 @@ func (self *Swap) Get() error { return nil } +func (self *HugeTLBPages) Get() error { + return ErrNotImplemented{runtime.GOOS} +} + func (self *Cpu) Get() error { load := [C.CPUSTATES]C.long{C.CP_USER, C.CP_NICE, C.CP_SYS, C.CP_INTR, C.CP_IDLE} @@ -381,6 +385,10 @@ func (self *ProcFDUsage) Get(pid int) error { return ErrNotImplemented{runtime.GOOS} } +func (self *Rusage) Get(pid int) error { + return ErrNotImplemented{runtime.GOOS} +} + func fillCpu(cpu *Cpu, load [C.CPUSTATES]C.long) { cpu.User = uint64(load[0]) cpu.Nice = uint64(load[1]) diff --git a/vendor/github.com/elastic/gosigar/sigar_stub.go b/vendor/github.com/elastic/gosigar/sigar_stub.go index 0b858f1c0c..de9565aec4 100644 --- a/vendor/github.com/elastic/gosigar/sigar_stub.go +++ b/vendor/github.com/elastic/gosigar/sigar_stub.go @@ -22,6 +22,10 @@ func (s *Swap) Get() error { return ErrNotImplemented{runtime.GOOS} } +func (s *HugeTLBPages) Get() error { + return ErrNotImplemented{runtime.GOOS} +} + func (f *FDUsage) Get() error { return ErrNotImplemented{runtime.GOOS} } diff --git a/vendor/github.com/elastic/gosigar/sigar_windows.go b/vendor/github.com/elastic/gosigar/sigar_windows.go index 0cdf928d16..c2b54d8d7f 100644 --- a/vendor/github.com/elastic/gosigar/sigar_windows.go +++ b/vendor/github.com/elastic/gosigar/sigar_windows.go @@ -120,6 +120,10 @@ func (self *Swap) Get() error { return nil } +func (self *HugeTLBPages) Get() error { + return ErrNotImplemented{runtime.GOOS} +} + func (self *Cpu) Get() error { idle, kernel, user, err := windows.GetSystemTimes() if err != nil { diff --git a/vendor/github.com/fjl/memsize/LICENSE b/vendor/github.com/fjl/memsize/LICENSE new file mode 100644 index 0000000000..8b80456419 --- /dev/null +++ b/vendor/github.com/fjl/memsize/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Felix Lange + +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/fjl/memsize/bitmap.go b/vendor/github.com/fjl/memsize/bitmap.go new file mode 100644 index 0000000000..47799ea8d3 --- /dev/null +++ b/vendor/github.com/fjl/memsize/bitmap.go @@ -0,0 +1,119 @@ +package memsize + +import ( + "math/bits" +) + +const ( + uintptrBits = 32 << (uint64(^uintptr(0)) >> 63) + uintptrBytes = uintptrBits / 8 + bmBlockRange = 1 * 1024 * 1024 // bytes covered by bmBlock + bmBlockWords = bmBlockRange / uintptrBits +) + +// bitmap is a sparse bitmap. +type bitmap struct { + blocks map[uintptr]*bmBlock +} + +func newBitmap() *bitmap { + return &bitmap{make(map[uintptr]*bmBlock)} +} + +// markRange sets n consecutive bits starting at addr. +func (b *bitmap) markRange(addr, n uintptr) { + for end := addr + n; addr < end; { + block, baddr := b.block(addr) + for i := baddr; i < bmBlockRange && addr < end; i++ { + block.mark(i) + addr++ + } + } +} + +// isMarked returns the value of the bit at the given address. +func (b *bitmap) isMarked(addr uintptr) bool { + block, baddr := b.block(addr) + return block.isMarked(baddr) +} + +// countRange returns the number of set bits in the range (addr,addr+n). +func (b *bitmap) countRange(addr, n uintptr) uintptr { + c := uintptr(0) + for end := addr + n; addr < end; { + block, baddr := b.block(addr) + bend := uintptr(bmBlockRange - 1) + if baddr+(end-addr) < bmBlockRange { + bend = baddr + (end - addr) + } + c += uintptr(block.count(baddr, bend)) + // Move addr to next block. + addr += bmBlockRange - baddr + } + return c +} + +// block finds the block corresponding to the given memory address. +// It also returns the block's starting address. +func (b *bitmap) block(addr uintptr) (*bmBlock, uintptr) { + index := addr / bmBlockRange + block := b.blocks[index] + if block == nil { + block = new(bmBlock) + b.blocks[index] = block + } + return block, addr % bmBlockRange +} + +// size returns the sum of the byte sizes of all blocks. +func (b *bitmap) size() uintptr { + return uintptr(len(b.blocks)) * bmBlockWords * uintptrBytes +} + +// utilization returns the mean percentage of one bits across all blocks. +func (b *bitmap) utilization() float32 { + var avg float32 + for _, block := range b.blocks { + avg += float32(block.count(0, bmBlockRange-1)) / float32(bmBlockRange) + } + return avg / float32(len(b.blocks)) +} + +// bmBlock is a bitmap block. +type bmBlock [bmBlockWords]uintptr + +// mark sets the i'th bit to one. +func (b *bmBlock) mark(i uintptr) { + b[i/uintptrBits] |= 1 << (i % uintptrBits) +} + +// isMarked returns the value of the i'th bit. +func (b *bmBlock) isMarked(i uintptr) bool { + return (b[i/uintptrBits] & (1 << (i % uintptrBits))) != 0 +} + +// count returns the number of set bits in the range (start,end). +func (b *bmBlock) count(start, end uintptr) (count int) { + br := b[start/uintptrBits : end/uintptrBits+1] + for i, w := range br { + if i == 0 { + w &= blockmask(start) + } + if i == len(br)-1 { + w &^= blockmask(end) + } + count += onesCountPtr(w) + } + return count +} + +func blockmask(x uintptr) uintptr { + return ^uintptr(0) << (x % uintptrBits) +} + +func onesCountPtr(x uintptr) int { + if uintptrBits == 64 { + return bits.OnesCount64(uint64(x)) + } + return bits.OnesCount32(uint32(x)) +} diff --git a/vendor/github.com/fjl/memsize/doc.go b/vendor/github.com/fjl/memsize/doc.go new file mode 100644 index 0000000000..640cfba5eb --- /dev/null +++ b/vendor/github.com/fjl/memsize/doc.go @@ -0,0 +1,16 @@ +/* +Package memsize computes the size of your object graph. + +So you made a spiffy algorithm and it works really well, but geez it's using +way too much memory. Where did it all go? memsize to the rescue! + +To get started, find a value that references all your objects and scan it. +This traverses the graph, counting sizes per type. + + sizes := memsize.Scan(myValue) + fmt.Println(sizes.Total) + +memsize can handle cycles just fine and tracks both private and public struct fields. +Unfortunately function closures cannot be inspected in any way. +*/ +package memsize diff --git a/vendor/github.com/fjl/memsize/memsize.go b/vendor/github.com/fjl/memsize/memsize.go new file mode 100644 index 0000000000..2664e87c46 --- /dev/null +++ b/vendor/github.com/fjl/memsize/memsize.go @@ -0,0 +1,243 @@ +package memsize + +import ( + "bytes" + "fmt" + "reflect" + "sort" + "strings" + "text/tabwriter" + "unsafe" +) + +// Scan traverses all objects reachable from v and counts how much memory +// is used per type. The value must be a non-nil pointer to any value. +func Scan(v interface{}) Sizes { + rv := reflect.ValueOf(v) + if rv.Kind() != reflect.Ptr || rv.IsNil() { + panic("value to scan must be non-nil pointer") + } + + stopTheWorld("memsize scan") + defer startTheWorld() + + ctx := newContext() + ctx.scan(invalidAddr, rv, false) + ctx.s.BitmapSize = ctx.seen.size() + ctx.s.BitmapUtilization = ctx.seen.utilization() + return *ctx.s +} + +// Sizes is the result of a scan. +type Sizes struct { + Total uintptr + ByType map[reflect.Type]*TypeSize + // Internal stats (for debugging) + BitmapSize uintptr + BitmapUtilization float32 +} + +type TypeSize struct { + Total uintptr + Count uintptr +} + +func newSizes() *Sizes { + return &Sizes{ByType: make(map[reflect.Type]*TypeSize)} +} + +// Report returns a human-readable report. +func (s Sizes) Report() string { + type typLine struct { + name string + count uintptr + total uintptr + } + tab := []typLine{{"ALL", 0, s.Total}} + for _, typ := range s.ByType { + tab[0].count += typ.Count + } + maxname := 0 + for typ, s := range s.ByType { + line := typLine{typ.String(), s.Count, s.Total} + tab = append(tab, line) + if len(line.name) > maxname { + maxname = len(line.name) + } + } + sort.Slice(tab, func(i, j int) bool { return tab[i].total > tab[j].total }) + + buf := new(bytes.Buffer) + w := tabwriter.NewWriter(buf, 0, 0, 0, ' ', tabwriter.AlignRight) + for _, line := range tab { + namespace := strings.Repeat(" ", maxname-len(line.name)) + fmt.Fprintf(w, "%s%s\t %v\t %s\t\n", line.name, namespace, line.count, HumanSize(line.total)) + } + w.Flush() + return buf.String() +} + +// addValue is called during scan and adds the memory of given object. +func (s *Sizes) addValue(v reflect.Value, size uintptr) { + s.Total += size + rs := s.ByType[v.Type()] + if rs == nil { + rs = new(TypeSize) + s.ByType[v.Type()] = rs + } + rs.Total += size + rs.Count++ +} + +type context struct { + // We track previously scanned objects to prevent infinite loops + // when scanning cycles and to prevent counting objects more than once. + seen *bitmap + tc typCache + s *Sizes +} + +func newContext() *context { + return &context{seen: newBitmap(), tc: make(typCache), s: newSizes()} +} + +// scan walks all objects below v, determining their size. All scan* functions return the +// amount of 'extra' memory (e.g. slice data) that is referenced by the object. +func (c *context) scan(addr address, v reflect.Value, add bool) (extraSize uintptr) { + size := v.Type().Size() + var marked uintptr + if addr.valid() { + marked = c.seen.countRange(uintptr(addr), size) + if marked == size { + return 0 // Skip if we have already seen the whole object. + } + c.seen.markRange(uintptr(addr), size) + } + // fmt.Printf("%v: %v ⮑ (marked %d)\n", addr, v.Type(), marked) + if c.tc.needScan(v.Type()) { + extraSize = c.scanContent(addr, v) + } + // fmt.Printf("%v: %v %d (add %v, size %d, marked %d, extra %d)\n", addr, v.Type(), size+extraSize, add, v.Type().Size(), marked, extraSize) + if add { + size -= marked + size += extraSize + c.s.addValue(v, size) + } + return extraSize +} + +func (c *context) scanContent(addr address, v reflect.Value) uintptr { + switch v.Kind() { + case reflect.Array: + return c.scanArray(addr, v) + case reflect.Chan: + return c.scanChan(v) + case reflect.Func: + // can't do anything here + return 0 + case reflect.Interface: + return c.scanInterface(v) + case reflect.Map: + return c.scanMap(v) + case reflect.Ptr: + if !v.IsNil() { + c.scan(address(v.Pointer()), v.Elem(), true) + } + return 0 + case reflect.Slice: + return c.scanSlice(v) + case reflect.String: + return uintptr(v.Len()) + case reflect.Struct: + return c.scanStruct(addr, v) + default: + unhandledKind(v.Kind()) + return 0 + } +} + +func (c *context) scanChan(v reflect.Value) uintptr { + etyp := v.Type().Elem() + extra := uintptr(0) + if c.tc.needScan(etyp) { + // Scan the channel buffer. This is unsafe but doesn't race because + // the world is stopped during scan. + hchan := unsafe.Pointer(v.Pointer()) + for i := uint(0); i < uint(v.Cap()); i++ { + addr := chanbuf(hchan, i) + elem := reflect.NewAt(etyp, addr).Elem() + extra += c.scanContent(address(addr), elem) + } + } + return uintptr(v.Cap())*etyp.Size() + extra +} + +func (c *context) scanStruct(base address, v reflect.Value) uintptr { + extra := uintptr(0) + for i := 0; i < v.NumField(); i++ { + f := v.Type().Field(i) + if c.tc.needScan(f.Type) { + addr := base.addOffset(f.Offset) + extra += c.scanContent(addr, v.Field(i)) + } + } + return extra +} + +func (c *context) scanArray(addr address, v reflect.Value) uintptr { + esize := v.Type().Elem().Size() + extra := uintptr(0) + for i := 0; i < v.Len(); i++ { + extra += c.scanContent(addr, v.Index(i)) + addr = addr.addOffset(esize) + } + return extra +} + +func (c *context) scanSlice(v reflect.Value) uintptr { + slice := v.Slice(0, v.Cap()) + esize := slice.Type().Elem().Size() + base := slice.Pointer() + // Add size of the unscanned portion of the backing array to extra. + blen := uintptr(slice.Len()) * esize + marked := c.seen.countRange(base, blen) + extra := blen - marked + c.seen.markRange(uintptr(base), blen) + if c.tc.needScan(slice.Type().Elem()) { + // Elements may contain pointers, scan them individually. + addr := address(base) + for i := 0; i < slice.Len(); i++ { + extra += c.scanContent(addr, slice.Index(i)) + addr = addr.addOffset(esize) + } + } + return extra +} + +func (c *context) scanMap(v reflect.Value) uintptr { + var ( + typ = v.Type() + len = uintptr(v.Len()) + extra = uintptr(0) + ) + if c.tc.needScan(typ.Key()) || c.tc.needScan(typ.Elem()) { + for _, k := range v.MapKeys() { + extra += c.scan(invalidAddr, k, false) + extra += c.scan(invalidAddr, v.MapIndex(k), false) + } + } + return len*typ.Key().Size() + len*typ.Elem().Size() + extra +} + +func (c *context) scanInterface(v reflect.Value) uintptr { + elem := v.Elem() + if !elem.IsValid() { + return 0 // nil interface + } + c.scan(invalidAddr, elem, false) + if !c.tc.isPointer(elem.Type()) { + // Account for non-pointer size of the value. + return elem.Type().Size() + } + return 0 +} diff --git a/vendor/github.com/fjl/memsize/memsizeui/template.go b/vendor/github.com/fjl/memsize/memsizeui/template.go new file mode 100644 index 0000000000..b60fe6ba54 --- /dev/null +++ b/vendor/github.com/fjl/memsize/memsizeui/template.go @@ -0,0 +1,106 @@ +package memsizeui + +import ( + "html/template" + "strconv" + "sync" + + "github.com/fjl/memsize" +) + +var ( + base *template.Template // the "base" template + baseInitOnce sync.Once +) + +func baseInit() { + base = template.Must(template.New("base").Parse(` + + + + memsize + + + + {{template "content" .}} + +`)) + + base.Funcs(template.FuncMap{ + "quote": strconv.Quote, + "humansize": memsize.HumanSize, + }) + + template.Must(base.New("rootbuttons").Parse(` +Overview +{{- range $root := .Roots -}} +
+ +
+{{- end -}}`)) +} + +func contentTemplate(source string) *template.Template { + baseInitOnce.Do(baseInit) + t := template.Must(base.Clone()) + template.Must(t.New("content").Parse(source)) + return t +} + +var rootTemplate = contentTemplate(` +

Memsize

+{{template "rootbuttons" .}} +
+

Reports

+ +`) + +var notFoundTemplate = contentTemplate(` +

{{.Data}}

+{{template "rootbuttons" .}} +`) + +var reportTemplate = contentTemplate(` +{{- $report := .Data -}} +

Memsize Report {{$report.ID}}

+
+ Overview + +
+
+Root: {{quote $report.RootName}}
+Date: {{$report.Date}}
+Duration: {{$report.Duration}}
+Bitmap Size: {{$report.Sizes.BitmapSize | humansize}}
+Bitmap Utilization: {{$report.Sizes.BitmapUtilization}}
+
+
+
+{{$report.Sizes.Report}}
+
+`) diff --git a/vendor/github.com/fjl/memsize/memsizeui/ui.go b/vendor/github.com/fjl/memsize/memsizeui/ui.go new file mode 100644 index 0000000000..c48fc53f7f --- /dev/null +++ b/vendor/github.com/fjl/memsize/memsizeui/ui.go @@ -0,0 +1,153 @@ +package memsizeui + +import ( + "bytes" + "fmt" + "html/template" + "net/http" + "reflect" + "sort" + "strings" + "sync" + "time" + + "github.com/fjl/memsize" +) + +type Handler struct { + init sync.Once + mux http.ServeMux + mu sync.Mutex + reports map[int]Report + roots map[string]interface{} + reportID int +} + +type Report struct { + ID int + Date time.Time + Duration time.Duration + RootName string + Sizes memsize.Sizes +} + +type templateInfo struct { + Roots []string + Reports map[int]Report + PathDepth int + Data interface{} +} + +func (ti *templateInfo) Link(path ...string) string { + prefix := strings.Repeat("../", ti.PathDepth) + return prefix + strings.Join(path, "") +} + +func (h *Handler) Add(name string, v interface{}) { + rv := reflect.ValueOf(v) + if rv.Kind() != reflect.Ptr || rv.IsNil() { + panic("root must be non-nil pointer") + } + h.mu.Lock() + if h.roots == nil { + h.roots = make(map[string]interface{}) + } + h.roots[name] = v + h.mu.Unlock() +} + +func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + h.init.Do(func() { + h.reports = make(map[int]Report) + h.mux.HandleFunc("/", h.handleRoot) + h.mux.HandleFunc("/scan", h.handleScan) + h.mux.HandleFunc("/report/", h.handleReport) + }) + h.mux.ServeHTTP(w, r) +} + +func (h *Handler) templateInfo(r *http.Request, data interface{}) *templateInfo { + h.mu.Lock() + roots := make([]string, 0, len(h.roots)) + for name := range h.roots { + roots = append(roots, name) + } + h.mu.Unlock() + sort.Strings(roots) + + return &templateInfo{ + Roots: roots, + Reports: h.reports, + PathDepth: strings.Count(r.URL.Path, "/") - 1, + Data: data, + } +} + +func (h *Handler) handleRoot(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/" { + http.NotFound(w, r) + return + } + serveHTML(w, rootTemplate, http.StatusOK, h.templateInfo(r, nil)) +} + +func (h *Handler) handleScan(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "invalid HTTP method, want POST", http.StatusMethodNotAllowed) + return + } + ti := h.templateInfo(r, "Unknown root") + id, ok := h.scan(r.URL.Query().Get("root")) + if !ok { + serveHTML(w, notFoundTemplate, http.StatusNotFound, ti) + return + } + w.Header().Add("Location", ti.Link(fmt.Sprintf("report/%d", id))) + w.WriteHeader(http.StatusSeeOther) +} + +func (h *Handler) handleReport(w http.ResponseWriter, r *http.Request) { + var id int + fmt.Sscan(strings.TrimPrefix(r.URL.Path, "/report/"), &id) + h.mu.Lock() + report, ok := h.reports[id] + h.mu.Unlock() + + if !ok { + serveHTML(w, notFoundTemplate, http.StatusNotFound, h.templateInfo(r, "Report not found")) + } else { + serveHTML(w, reportTemplate, http.StatusOK, h.templateInfo(r, report)) + } +} + +func (h *Handler) scan(root string) (int, bool) { + h.mu.Lock() + defer h.mu.Unlock() + + val, ok := h.roots[root] + if !ok { + return 0, false + } + id := h.reportID + start := time.Now() + sizes := memsize.Scan(val) + h.reports[id] = Report{ + ID: id, + RootName: root, + Date: start.Truncate(1 * time.Second), + Duration: time.Since(start), + Sizes: sizes, + } + h.reportID++ + return id, true +} + +func serveHTML(w http.ResponseWriter, tpl *template.Template, status int, ti *templateInfo) { + w.Header().Set("content-type", "text/html") + var buf bytes.Buffer + if err := tpl.Execute(&buf, ti); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + buf.WriteTo(w) +} diff --git a/vendor/github.com/fjl/memsize/runtimefunc.go b/vendor/github.com/fjl/memsize/runtimefunc.go new file mode 100644 index 0000000000..912a3e768d --- /dev/null +++ b/vendor/github.com/fjl/memsize/runtimefunc.go @@ -0,0 +1,14 @@ +package memsize + +import "unsafe" + +var _ = unsafe.Pointer(nil) + +//go:linkname stopTheWorld runtime.stopTheWorld +func stopTheWorld(reason string) + +//go:linkname startTheWorld runtime.startTheWorld +func startTheWorld() + +//go:linkname chanbuf runtime.chanbuf +func chanbuf(ch unsafe.Pointer, i uint) unsafe.Pointer diff --git a/vendor/github.com/fjl/memsize/runtimefunc.s b/vendor/github.com/fjl/memsize/runtimefunc.s new file mode 100644 index 0000000000..a091e2fa72 --- /dev/null +++ b/vendor/github.com/fjl/memsize/runtimefunc.s @@ -0,0 +1 @@ +// This file is required to make stub function declarations work. diff --git a/vendor/github.com/fjl/memsize/type.go b/vendor/github.com/fjl/memsize/type.go new file mode 100644 index 0000000000..5d6f59e9ff --- /dev/null +++ b/vendor/github.com/fjl/memsize/type.go @@ -0,0 +1,119 @@ +package memsize + +import ( + "fmt" + "reflect" +) + +// address is a memory location. +// +// Code dealing with uintptr is oblivious to the zero address. +// Code dealing with address is not: it treats the zero address +// as invalid. Offsetting an invalid address doesn't do anything. +// +// This distinction is useful because there are objects that we can't +// get the pointer to. +type address uintptr + +const invalidAddr = address(0) + +func (a address) valid() bool { + return a != 0 +} + +func (a address) addOffset(off uintptr) address { + if !a.valid() { + return invalidAddr + } + return a + address(off) +} + +func (a address) String() string { + if uintptrBits == 32 { + return fmt.Sprintf("%#0.8x", uintptr(a)) + } + return fmt.Sprintf("%#0.16x", uintptr(a)) +} + +type typCache map[reflect.Type]typInfo + +type typInfo struct { + isPointer bool + needScan bool +} + +// isPointer returns true for pointer-ish values. The notion of +// pointer includes everything but plain values, i.e. slices, maps +// channels, interfaces are 'pointer', too. +func (tc *typCache) isPointer(typ reflect.Type) bool { + return tc.info(typ).isPointer +} + +// needScan reports whether a value of the type needs to be scanned +// recursively because it may contain pointers. +func (tc *typCache) needScan(typ reflect.Type) bool { + return tc.info(typ).needScan +} + +func (tc *typCache) info(typ reflect.Type) typInfo { + info, found := (*tc)[typ] + switch { + case found: + return info + case isPointer(typ): + info = typInfo{true, true} + default: + info = typInfo{false, tc.checkNeedScan(typ)} + } + (*tc)[typ] = info + return info +} + +func (tc *typCache) checkNeedScan(typ reflect.Type) bool { + switch k := typ.Kind(); k { + case reflect.Struct: + // Structs don't need scan if none of their fields need it. + for i := 0; i < typ.NumField(); i++ { + if tc.needScan(typ.Field(i).Type) { + return true + } + } + case reflect.Array: + // Arrays don't need scan if their element type doesn't. + return tc.needScan(typ.Elem()) + } + return false +} + +func isPointer(typ reflect.Type) bool { + k := typ.Kind() + switch { + case k <= reflect.Complex128: + return false + case k == reflect.Array: + return false + case k >= reflect.Chan && k <= reflect.String: + return true + case k == reflect.Struct || k == reflect.UnsafePointer: + return false + default: + unhandledKind(k) + return false + } +} + +func unhandledKind(k reflect.Kind) { + panic("unhandled kind " + k.String()) +} + +// HumanSize formats the given number of bytes as a readable string. +func HumanSize(bytes uintptr) string { + switch { + case bytes < 1024: + return fmt.Sprintf("%d B", bytes) + case bytes < 1024*1024: + return fmt.Sprintf("%.3f KB", float64(bytes)/1024) + default: + return fmt.Sprintf("%.3f MB", float64(bytes)/1024/1024) + } +} diff --git a/vendor/github.com/graph-gophers/graphql-go/Gopkg.lock b/vendor/github.com/graph-gophers/graphql-go/Gopkg.lock new file mode 100644 index 0000000000..4574275c5d --- /dev/null +++ b/vendor/github.com/graph-gophers/graphql-go/Gopkg.lock @@ -0,0 +1,25 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + name = "github.com/opentracing/opentracing-go" + packages = [ + ".", + "ext", + "log" + ] + revision = "1949ddbfd147afd4d964a9f00b24eb291e0e7c38" + version = "v1.0.2" + +[[projects]] + branch = "master" + name = "golang.org/x/net" + packages = ["context"] + revision = "f5dfe339be1d06f81b22525fe34671ee7d2c8904" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "f417062128566756a9360b1c13ada79bdeeb6bab1f53ee9147a3328d95c1653f" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/vendor/github.com/graph-gophers/graphql-go/Gopkg.toml b/vendor/github.com/graph-gophers/graphql-go/Gopkg.toml new file mode 100644 index 0000000000..62b9367998 --- /dev/null +++ b/vendor/github.com/graph-gophers/graphql-go/Gopkg.toml @@ -0,0 +1,10 @@ +# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html +# for detailed Gopkg.toml documentation. + +[[constraint]] + name = "github.com/opentracing/opentracing-go" + version = "1.0.2" + +[prune] + go-tests = true + unused-packages = true diff --git a/vendor/github.com/graph-gophers/graphql-go/LICENSE b/vendor/github.com/graph-gophers/graphql-go/LICENSE new file mode 100644 index 0000000000..3907cecacf --- /dev/null +++ b/vendor/github.com/graph-gophers/graphql-go/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2016 Richard Musiol. All rights reserved. + +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. + +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. diff --git a/vendor/github.com/graph-gophers/graphql-go/README.md b/vendor/github.com/graph-gophers/graphql-go/README.md new file mode 100644 index 0000000000..ef4b4639b5 --- /dev/null +++ b/vendor/github.com/graph-gophers/graphql-go/README.md @@ -0,0 +1,100 @@ +# graphql-go [![Sourcegraph](https://sourcegraph.com/github.com/graph-gophers/graphql-go/-/badge.svg)](https://sourcegraph.com/github.com/graph-gophers/graphql-go?badge) [![Build Status](https://semaphoreci.com/api/v1/graph-gophers/graphql-go/branches/master/badge.svg)](https://semaphoreci.com/graph-gophers/graphql-go) [![GoDoc](https://godoc.org/github.com/graph-gophers/graphql-go?status.svg)](https://godoc.org/github.com/graph-gophers/graphql-go) + +

+ +The goal of this project is to provide full support of the [GraphQL draft specification](https://facebook.github.io/graphql/draft) with a set of idiomatic, easy to use Go packages. + +While still under heavy development (`internal` APIs are almost certainly subject to change), this library is +safe for production use. + +## Features + +- minimal API +- support for `context.Context` +- support for the `OpenTracing` standard +- schema type-checking against resolvers +- resolvers are matched to the schema based on method sets (can resolve a GraphQL schema with a Go interface or Go struct). +- handles panics in resolvers +- parallel execution of resolvers + +## Roadmap + +We're trying out the GitHub Project feature to manage `graphql-go`'s [development roadmap](https://github.com/graph-gophers/graphql-go/projects/1). +Feedback is welcome and appreciated. + +## (Some) Documentation + +### Basic Sample + +```go +package main + +import ( + "log" + "net/http" + + graphql "github.com/graph-gophers/graphql-go" + "github.com/graph-gophers/graphql-go/relay" +) + +type query struct{} + +func (_ *query) Hello() string { return "Hello, world!" } + +func main() { + s := ` + schema { + query: Query + } + type Query { + hello: String! + } + ` + schema := graphql.MustParseSchema(s, &query{}) + http.Handle("/query", &relay.Handler{Schema: schema}) + log.Fatal(http.ListenAndServe(":8080", nil)) +} +``` + +To test: +```sh +$ curl -XPOST -d '{"query": "{ hello }"}' localhost:8080/query +``` + +### Resolvers + +A resolver must have one method for each field of the GraphQL type it resolves. The method name has to be [exported](https://golang.org/ref/spec#Exported_identifiers) and match the field's name in a non-case-sensitive way. + +The method has up to two arguments: + +- Optional `context.Context` argument. +- Mandatory `*struct { ... }` argument if the corresponding GraphQL field has arguments. The names of the struct fields have to be [exported](https://golang.org/ref/spec#Exported_identifiers) and have to match the names of the GraphQL arguments in a non-case-sensitive way. + +The method has up to two results: + +- The GraphQL field's value as determined by the resolver. +- Optional `error` result. + +Example for a simple resolver method: + +```go +func (r *helloWorldResolver) Hello() string { + return "Hello world!" +} +``` + +The following signature is also allowed: + +```go +func (r *helloWorldResolver) Hello(ctx context.Context) (string, error) { + return "Hello world!", nil +} +``` + +### Community Examples + +[tonyghita/graphql-go-example](https://github.com/tonyghita/graphql-go-example) - A more "productionized" version of the Star Wars API example given in this repository. + +[deltaskelta/graphql-go-pets-example](https://github.com/deltaskelta/graphql-go-pets-example) - graphql-go resolving against a sqlite database + +[OscarYuen/go-graphql-starter](https://github.com/OscarYuen/go-graphql-starter) - a starter application integrated with dataloader, psql and basic authentication diff --git a/vendor/github.com/graph-gophers/graphql-go/errors/errors.go b/vendor/github.com/graph-gophers/graphql-go/errors/errors.go new file mode 100644 index 0000000000..fdfa62024d --- /dev/null +++ b/vendor/github.com/graph-gophers/graphql-go/errors/errors.go @@ -0,0 +1,41 @@ +package errors + +import ( + "fmt" +) + +type QueryError struct { + Message string `json:"message"` + Locations []Location `json:"locations,omitempty"` + Path []interface{} `json:"path,omitempty"` + Rule string `json:"-"` + ResolverError error `json:"-"` +} + +type Location struct { + Line int `json:"line"` + Column int `json:"column"` +} + +func (a Location) Before(b Location) bool { + return a.Line < b.Line || (a.Line == b.Line && a.Column < b.Column) +} + +func Errorf(format string, a ...interface{}) *QueryError { + return &QueryError{ + Message: fmt.Sprintf(format, a...), + } +} + +func (err *QueryError) Error() string { + if err == nil { + return "" + } + str := fmt.Sprintf("graphql: %s", err.Message) + for _, loc := range err.Locations { + str += fmt.Sprintf(" (line %d, column %d)", loc.Line, loc.Column) + } + return str +} + +var _ error = &QueryError{} diff --git a/vendor/github.com/graph-gophers/graphql-go/graphql.go b/vendor/github.com/graph-gophers/graphql-go/graphql.go new file mode 100644 index 0000000000..06ffd45997 --- /dev/null +++ b/vendor/github.com/graph-gophers/graphql-go/graphql.go @@ -0,0 +1,205 @@ +package graphql + +import ( + "context" + "fmt" + + "encoding/json" + + "github.com/graph-gophers/graphql-go/errors" + "github.com/graph-gophers/graphql-go/internal/common" + "github.com/graph-gophers/graphql-go/internal/exec" + "github.com/graph-gophers/graphql-go/internal/exec/resolvable" + "github.com/graph-gophers/graphql-go/internal/exec/selected" + "github.com/graph-gophers/graphql-go/internal/query" + "github.com/graph-gophers/graphql-go/internal/schema" + "github.com/graph-gophers/graphql-go/internal/validation" + "github.com/graph-gophers/graphql-go/introspection" + "github.com/graph-gophers/graphql-go/log" + "github.com/graph-gophers/graphql-go/trace" +) + +// ParseSchema parses a GraphQL schema and attaches the given root resolver. It returns an error if +// the Go type signature of the resolvers does not match the schema. If nil is passed as the +// resolver, then the schema can not be executed, but it may be inspected (e.g. with ToJSON). +func ParseSchema(schemaString string, resolver interface{}, opts ...SchemaOpt) (*Schema, error) { + s := &Schema{ + schema: schema.New(), + maxParallelism: 10, + tracer: trace.OpenTracingTracer{}, + validationTracer: trace.NoopValidationTracer{}, + logger: &log.DefaultLogger{}, + } + for _, opt := range opts { + opt(s) + } + + if err := s.schema.Parse(schemaString); err != nil { + return nil, err + } + + if resolver != nil { + r, err := resolvable.ApplyResolver(s.schema, resolver) + if err != nil { + return nil, err + } + s.res = r + } + + return s, nil +} + +// MustParseSchema calls ParseSchema and panics on error. +func MustParseSchema(schemaString string, resolver interface{}, opts ...SchemaOpt) *Schema { + s, err := ParseSchema(schemaString, resolver, opts...) + if err != nil { + panic(err) + } + return s +} + +// Schema represents a GraphQL schema with an optional resolver. +type Schema struct { + schema *schema.Schema + res *resolvable.Schema + + maxDepth int + maxParallelism int + tracer trace.Tracer + validationTracer trace.ValidationTracer + logger log.Logger +} + +// SchemaOpt is an option to pass to ParseSchema or MustParseSchema. +type SchemaOpt func(*Schema) + +// MaxDepth specifies the maximum field nesting depth in a query. The default is 0 which disables max depth checking. +func MaxDepth(n int) SchemaOpt { + return func(s *Schema) { + s.maxDepth = n + } +} + +// MaxParallelism specifies the maximum number of resolvers per request allowed to run in parallel. The default is 10. +func MaxParallelism(n int) SchemaOpt { + return func(s *Schema) { + s.maxParallelism = n + } +} + +// Tracer is used to trace queries and fields. It defaults to trace.OpenTracingTracer. +func Tracer(tracer trace.Tracer) SchemaOpt { + return func(s *Schema) { + s.tracer = tracer + } +} + +// ValidationTracer is used to trace validation errors. It defaults to trace.NoopValidationTracer. +func ValidationTracer(tracer trace.ValidationTracer) SchemaOpt { + return func(s *Schema) { + s.validationTracer = tracer + } +} + +// Logger is used to log panics during query execution. It defaults to exec.DefaultLogger. +func Logger(logger log.Logger) SchemaOpt { + return func(s *Schema) { + s.logger = logger + } +} + +// Response represents a typical response of a GraphQL server. It may be encoded to JSON directly or +// it may be further processed to a custom response type, for example to include custom error data. +// Errors are intentionally serialized first based on the advice in https://github.com/facebook/graphql/commit/7b40390d48680b15cb93e02d46ac5eb249689876#diff-757cea6edf0288677a9eea4cfc801d87R107 +type Response struct { + Errors []*errors.QueryError `json:"errors,omitempty"` + Data json.RawMessage `json:"data,omitempty"` + Extensions map[string]interface{} `json:"extensions,omitempty"` +} + +// Validate validates the given query with the schema. +func (s *Schema) Validate(queryString string) []*errors.QueryError { + doc, qErr := query.Parse(queryString) + if qErr != nil { + return []*errors.QueryError{qErr} + } + + return validation.Validate(s.schema, doc, s.maxDepth) +} + +// Exec executes the given query with the schema's resolver. It panics if the schema was created +// without a resolver. If the context get cancelled, no further resolvers will be called and a +// the context error will be returned as soon as possible (not immediately). +func (s *Schema) Exec(ctx context.Context, queryString string, operationName string, variables map[string]interface{}) *Response { + if s.res == nil { + panic("schema created without resolver, can not exec") + } + return s.exec(ctx, queryString, operationName, variables, s.res) +} + +func (s *Schema) exec(ctx context.Context, queryString string, operationName string, variables map[string]interface{}, res *resolvable.Schema) *Response { + doc, qErr := query.Parse(queryString) + if qErr != nil { + return &Response{Errors: []*errors.QueryError{qErr}} + } + + validationFinish := s.validationTracer.TraceValidation() + errs := validation.Validate(s.schema, doc, s.maxDepth) + validationFinish(errs) + if len(errs) != 0 { + return &Response{Errors: errs} + } + + op, err := getOperation(doc, operationName) + if err != nil { + return &Response{Errors: []*errors.QueryError{errors.Errorf("%s", err)}} + } + + r := &exec.Request{ + Request: selected.Request{ + Doc: doc, + Vars: variables, + Schema: s.schema, + }, + Limiter: make(chan struct{}, s.maxParallelism), + Tracer: s.tracer, + Logger: s.logger, + } + varTypes := make(map[string]*introspection.Type) + for _, v := range op.Vars { + t, err := common.ResolveType(v.Type, s.schema.Resolve) + if err != nil { + return &Response{Errors: []*errors.QueryError{err}} + } + varTypes[v.Name.Name] = introspection.WrapType(t) + } + traceCtx, finish := s.tracer.TraceQuery(ctx, queryString, operationName, variables, varTypes) + data, errs := r.Execute(traceCtx, res, op) + finish(errs) + + return &Response{ + Data: data, + Errors: errs, + } +} + +func getOperation(document *query.Document, operationName string) (*query.Operation, error) { + if len(document.Operations) == 0 { + return nil, fmt.Errorf("no operations in query document") + } + + if operationName == "" { + if len(document.Operations) > 1 { + return nil, fmt.Errorf("more than one operation in query document and no operation name given") + } + for _, op := range document.Operations { + return op, nil // return the one and only operation + } + } + + op := document.Operations.Get(operationName) + if op == nil { + return nil, fmt.Errorf("no operation with name %q", operationName) + } + return op, nil +} diff --git a/vendor/github.com/graph-gophers/graphql-go/id.go b/vendor/github.com/graph-gophers/graphql-go/id.go new file mode 100644 index 0000000000..52771c413b --- /dev/null +++ b/vendor/github.com/graph-gophers/graphql-go/id.go @@ -0,0 +1,30 @@ +package graphql + +import ( + "errors" + "strconv" +) + +// ID represents GraphQL's "ID" scalar type. A custom type may be used instead. +type ID string + +func (ID) ImplementsGraphQLType(name string) bool { + return name == "ID" +} + +func (id *ID) UnmarshalGraphQL(input interface{}) error { + var err error + switch input := input.(type) { + case string: + *id = ID(input) + case int32: + *id = ID(strconv.Itoa(int(input))) + default: + err = errors.New("wrong type") + } + return err +} + +func (id ID) MarshalJSON() ([]byte, error) { + return strconv.AppendQuote(nil, string(id)), nil +} diff --git a/vendor/github.com/graph-gophers/graphql-go/internal/common/directive.go b/vendor/github.com/graph-gophers/graphql-go/internal/common/directive.go new file mode 100644 index 0000000000..62dca47f81 --- /dev/null +++ b/vendor/github.com/graph-gophers/graphql-go/internal/common/directive.go @@ -0,0 +1,32 @@ +package common + +type Directive struct { + Name Ident + Args ArgumentList +} + +func ParseDirectives(l *Lexer) DirectiveList { + var directives DirectiveList + for l.Peek() == '@' { + l.ConsumeToken('@') + d := &Directive{} + d.Name = l.ConsumeIdentWithLoc() + d.Name.Loc.Column-- + if l.Peek() == '(' { + d.Args = ParseArguments(l) + } + directives = append(directives, d) + } + return directives +} + +type DirectiveList []*Directive + +func (l DirectiveList) Get(name string) *Directive { + for _, d := range l { + if d.Name.Name == name { + return d + } + } + return nil +} diff --git a/vendor/github.com/graph-gophers/graphql-go/internal/common/lexer.go b/vendor/github.com/graph-gophers/graphql-go/internal/common/lexer.go new file mode 100644 index 0000000000..a38fcbaf70 --- /dev/null +++ b/vendor/github.com/graph-gophers/graphql-go/internal/common/lexer.go @@ -0,0 +1,161 @@ +package common + +import ( + "fmt" + "strings" + "text/scanner" + + "github.com/graph-gophers/graphql-go/errors" +) + +type syntaxError string + +type Lexer struct { + sc *scanner.Scanner + next rune + descComment string +} + +type Ident struct { + Name string + Loc errors.Location +} + +func NewLexer(s string) *Lexer { + sc := &scanner.Scanner{ + Mode: scanner.ScanIdents | scanner.ScanInts | scanner.ScanFloats | scanner.ScanStrings, + } + sc.Init(strings.NewReader(s)) + + return &Lexer{sc: sc} +} + +func (l *Lexer) CatchSyntaxError(f func()) (errRes *errors.QueryError) { + defer func() { + if err := recover(); err != nil { + if err, ok := err.(syntaxError); ok { + errRes = errors.Errorf("syntax error: %s", err) + errRes.Locations = []errors.Location{l.Location()} + return + } + panic(err) + } + }() + + f() + return +} + +func (l *Lexer) Peek() rune { + return l.next +} + +// Consume whitespace and tokens equivalent to whitespace (e.g. commas and comments). +// +// Consumed comment characters will build the description for the next type or field encountered. +// The description is available from `DescComment()`, and will be reset every time `Consume()` is +// executed. +func (l *Lexer) Consume() { + l.descComment = "" + for { + l.next = l.sc.Scan() + + if l.next == ',' { + // Similar to white space and line terminators, commas (',') are used to improve the + // legibility of source text and separate lexical tokens but are otherwise syntactically and + // semantically insignificant within GraphQL documents. + // + // http://facebook.github.io/graphql/draft/#sec-Insignificant-Commas + continue + } + + if l.next == '#' { + // GraphQL source documents may contain single-line comments, starting with the '#' marker. + // + // A comment can contain any Unicode code point except `LineTerminator` so a comment always + // consists of all code points starting with the '#' character up to but not including the + // line terminator. + + l.consumeComment() + continue + } + + break + } +} + +func (l *Lexer) ConsumeIdent() string { + name := l.sc.TokenText() + l.ConsumeToken(scanner.Ident) + return name +} + +func (l *Lexer) ConsumeIdentWithLoc() Ident { + loc := l.Location() + name := l.sc.TokenText() + l.ConsumeToken(scanner.Ident) + return Ident{name, loc} +} + +func (l *Lexer) ConsumeKeyword(keyword string) { + if l.next != scanner.Ident || l.sc.TokenText() != keyword { + l.SyntaxError(fmt.Sprintf("unexpected %q, expecting %q", l.sc.TokenText(), keyword)) + } + l.Consume() +} + +func (l *Lexer) ConsumeLiteral() *BasicLit { + lit := &BasicLit{Type: l.next, Text: l.sc.TokenText()} + l.Consume() + return lit +} + +func (l *Lexer) ConsumeToken(expected rune) { + if l.next != expected { + l.SyntaxError(fmt.Sprintf("unexpected %q, expecting %s", l.sc.TokenText(), scanner.TokenString(expected))) + } + l.Consume() +} + +func (l *Lexer) DescComment() string { + return l.descComment +} + +func (l *Lexer) SyntaxError(message string) { + panic(syntaxError(message)) +} + +func (l *Lexer) Location() errors.Location { + return errors.Location{ + Line: l.sc.Line, + Column: l.sc.Column, + } +} + +// consumeComment consumes all characters from `#` to the first encountered line terminator. +// The characters are appended to `l.descComment`. +func (l *Lexer) consumeComment() { + if l.next != '#' { + return + } + + // TODO: count and trim whitespace so we can dedent any following lines. + if l.sc.Peek() == ' ' { + l.sc.Next() + } + + if l.descComment != "" { + // TODO: use a bytes.Buffer or strings.Builder instead of this. + l.descComment += "\n" + } + + for { + next := l.sc.Next() + if next == '\r' || next == '\n' || next == scanner.EOF { + break + } + + // TODO: use a bytes.Buffer or strings.Build instead of this. + l.descComment += string(next) + } +} diff --git a/vendor/github.com/graph-gophers/graphql-go/internal/common/literals.go b/vendor/github.com/graph-gophers/graphql-go/internal/common/literals.go new file mode 100644 index 0000000000..e7bbe2638e --- /dev/null +++ b/vendor/github.com/graph-gophers/graphql-go/internal/common/literals.go @@ -0,0 +1,206 @@ +package common + +import ( + "strconv" + "strings" + "text/scanner" + + "github.com/graph-gophers/graphql-go/errors" +) + +type Literal interface { + Value(vars map[string]interface{}) interface{} + String() string + Location() errors.Location +} + +type BasicLit struct { + Type rune + Text string + Loc errors.Location +} + +func (lit *BasicLit) Value(vars map[string]interface{}) interface{} { + switch lit.Type { + case scanner.Int: + value, err := strconv.ParseInt(lit.Text, 10, 32) + if err != nil { + panic(err) + } + return int32(value) + + case scanner.Float: + value, err := strconv.ParseFloat(lit.Text, 64) + if err != nil { + panic(err) + } + return value + + case scanner.String: + value, err := strconv.Unquote(lit.Text) + if err != nil { + panic(err) + } + return value + + case scanner.Ident: + switch lit.Text { + case "true": + return true + case "false": + return false + default: + return lit.Text + } + + default: + panic("invalid literal") + } +} + +func (lit *BasicLit) String() string { + return lit.Text +} + +func (lit *BasicLit) Location() errors.Location { + return lit.Loc +} + +type ListLit struct { + Entries []Literal + Loc errors.Location +} + +func (lit *ListLit) Value(vars map[string]interface{}) interface{} { + entries := make([]interface{}, len(lit.Entries)) + for i, entry := range lit.Entries { + entries[i] = entry.Value(vars) + } + return entries +} + +func (lit *ListLit) String() string { + entries := make([]string, len(lit.Entries)) + for i, entry := range lit.Entries { + entries[i] = entry.String() + } + return "[" + strings.Join(entries, ", ") + "]" +} + +func (lit *ListLit) Location() errors.Location { + return lit.Loc +} + +type ObjectLit struct { + Fields []*ObjectLitField + Loc errors.Location +} + +type ObjectLitField struct { + Name Ident + Value Literal +} + +func (lit *ObjectLit) Value(vars map[string]interface{}) interface{} { + fields := make(map[string]interface{}, len(lit.Fields)) + for _, f := range lit.Fields { + fields[f.Name.Name] = f.Value.Value(vars) + } + return fields +} + +func (lit *ObjectLit) String() string { + entries := make([]string, 0, len(lit.Fields)) + for _, f := range lit.Fields { + entries = append(entries, f.Name.Name+": "+f.Value.String()) + } + return "{" + strings.Join(entries, ", ") + "}" +} + +func (lit *ObjectLit) Location() errors.Location { + return lit.Loc +} + +type NullLit struct { + Loc errors.Location +} + +func (lit *NullLit) Value(vars map[string]interface{}) interface{} { + return nil +} + +func (lit *NullLit) String() string { + return "null" +} + +func (lit *NullLit) Location() errors.Location { + return lit.Loc +} + +type Variable struct { + Name string + Loc errors.Location +} + +func (v Variable) Value(vars map[string]interface{}) interface{} { + return vars[v.Name] +} + +func (v Variable) String() string { + return "$" + v.Name +} + +func (v *Variable) Location() errors.Location { + return v.Loc +} + +func ParseLiteral(l *Lexer, constOnly bool) Literal { + loc := l.Location() + switch l.Peek() { + case '$': + if constOnly { + l.SyntaxError("variable not allowed") + panic("unreachable") + } + l.ConsumeToken('$') + return &Variable{l.ConsumeIdent(), loc} + + case scanner.Int, scanner.Float, scanner.String, scanner.Ident: + lit := l.ConsumeLiteral() + if lit.Type == scanner.Ident && lit.Text == "null" { + return &NullLit{loc} + } + lit.Loc = loc + return lit + case '-': + l.ConsumeToken('-') + lit := l.ConsumeLiteral() + lit.Text = "-" + lit.Text + lit.Loc = loc + return lit + case '[': + l.ConsumeToken('[') + var list []Literal + for l.Peek() != ']' { + list = append(list, ParseLiteral(l, constOnly)) + } + l.ConsumeToken(']') + return &ListLit{list, loc} + + case '{': + l.ConsumeToken('{') + var fields []*ObjectLitField + for l.Peek() != '}' { + name := l.ConsumeIdentWithLoc() + l.ConsumeToken(':') + value := ParseLiteral(l, constOnly) + fields = append(fields, &ObjectLitField{name, value}) + } + l.ConsumeToken('}') + return &ObjectLit{fields, loc} + + default: + l.SyntaxError("invalid value") + panic("unreachable") + } +} diff --git a/vendor/github.com/graph-gophers/graphql-go/internal/common/types.go b/vendor/github.com/graph-gophers/graphql-go/internal/common/types.go new file mode 100644 index 0000000000..a20ca30906 --- /dev/null +++ b/vendor/github.com/graph-gophers/graphql-go/internal/common/types.go @@ -0,0 +1,80 @@ +package common + +import ( + "github.com/graph-gophers/graphql-go/errors" +) + +type Type interface { + Kind() string + String() string +} + +type List struct { + OfType Type +} + +type NonNull struct { + OfType Type +} + +type TypeName struct { + Ident +} + +func (*List) Kind() string { return "LIST" } +func (*NonNull) Kind() string { return "NON_NULL" } +func (*TypeName) Kind() string { panic("TypeName needs to be resolved to actual type") } + +func (t *List) String() string { return "[" + t.OfType.String() + "]" } +func (t *NonNull) String() string { return t.OfType.String() + "!" } +func (*TypeName) String() string { panic("TypeName needs to be resolved to actual type") } + +func ParseType(l *Lexer) Type { + t := parseNullType(l) + if l.Peek() == '!' { + l.ConsumeToken('!') + return &NonNull{OfType: t} + } + return t +} + +func parseNullType(l *Lexer) Type { + if l.Peek() == '[' { + l.ConsumeToken('[') + ofType := ParseType(l) + l.ConsumeToken(']') + return &List{OfType: ofType} + } + + return &TypeName{Ident: l.ConsumeIdentWithLoc()} +} + +type Resolver func(name string) Type + +func ResolveType(t Type, resolver Resolver) (Type, *errors.QueryError) { + switch t := t.(type) { + case *List: + ofType, err := ResolveType(t.OfType, resolver) + if err != nil { + return nil, err + } + return &List{OfType: ofType}, nil + case *NonNull: + ofType, err := ResolveType(t.OfType, resolver) + if err != nil { + return nil, err + } + return &NonNull{OfType: ofType}, nil + case *TypeName: + refT := resolver(t.Name) + if refT == nil { + err := errors.Errorf("Unknown type %q.", t.Name) + err.Rule = "KnownTypeNames" + err.Locations = []errors.Location{t.Loc} + return nil, err + } + return refT, nil + default: + return t, nil + } +} diff --git a/vendor/github.com/graph-gophers/graphql-go/internal/common/values.go b/vendor/github.com/graph-gophers/graphql-go/internal/common/values.go new file mode 100644 index 0000000000..fcd456abfa --- /dev/null +++ b/vendor/github.com/graph-gophers/graphql-go/internal/common/values.go @@ -0,0 +1,78 @@ +package common + +import ( + "github.com/graph-gophers/graphql-go/errors" +) + +// http://facebook.github.io/graphql/draft/#InputValueDefinition +type InputValue struct { + Name Ident + Type Type + Default Literal + Desc string + Loc errors.Location + TypeLoc errors.Location +} + +type InputValueList []*InputValue + +func (l InputValueList) Get(name string) *InputValue { + for _, v := range l { + if v.Name.Name == name { + return v + } + } + return nil +} + +func ParseInputValue(l *Lexer) *InputValue { + p := &InputValue{} + p.Loc = l.Location() + p.Desc = l.DescComment() + p.Name = l.ConsumeIdentWithLoc() + l.ConsumeToken(':') + p.TypeLoc = l.Location() + p.Type = ParseType(l) + if l.Peek() == '=' { + l.ConsumeToken('=') + p.Default = ParseLiteral(l, true) + } + return p +} + +type Argument struct { + Name Ident + Value Literal +} + +type ArgumentList []Argument + +func (l ArgumentList) Get(name string) (Literal, bool) { + for _, arg := range l { + if arg.Name.Name == name { + return arg.Value, true + } + } + return nil, false +} + +func (l ArgumentList) MustGet(name string) Literal { + value, ok := l.Get(name) + if !ok { + panic("argument not found") + } + return value +} + +func ParseArguments(l *Lexer) ArgumentList { + var args ArgumentList + l.ConsumeToken('(') + for l.Peek() != ')' { + name := l.ConsumeIdentWithLoc() + l.ConsumeToken(':') + value := ParseLiteral(l, false) + args = append(args, Argument{Name: name, Value: value}) + } + l.ConsumeToken(')') + return args +} diff --git a/vendor/github.com/graph-gophers/graphql-go/internal/exec/exec.go b/vendor/github.com/graph-gophers/graphql-go/internal/exec/exec.go new file mode 100644 index 0000000000..e6cca7448d --- /dev/null +++ b/vendor/github.com/graph-gophers/graphql-go/internal/exec/exec.go @@ -0,0 +1,305 @@ +package exec + +import ( + "bytes" + "context" + "encoding/json" + "reflect" + "sync" + + "github.com/graph-gophers/graphql-go/errors" + "github.com/graph-gophers/graphql-go/internal/common" + "github.com/graph-gophers/graphql-go/internal/exec/resolvable" + "github.com/graph-gophers/graphql-go/internal/exec/selected" + "github.com/graph-gophers/graphql-go/internal/query" + "github.com/graph-gophers/graphql-go/internal/schema" + "github.com/graph-gophers/graphql-go/log" + "github.com/graph-gophers/graphql-go/trace" +) + +type Request struct { + selected.Request + Limiter chan struct{} + Tracer trace.Tracer + Logger log.Logger +} + +func (r *Request) handlePanic(ctx context.Context) { + if value := recover(); value != nil { + r.Logger.LogPanic(ctx, value) + r.AddError(makePanicError(value)) + } +} + +func makePanicError(value interface{}) *errors.QueryError { + return errors.Errorf("graphql: panic occurred: %v", value) +} + +func (r *Request) Execute(ctx context.Context, s *resolvable.Schema, op *query.Operation) ([]byte, []*errors.QueryError) { + var out bytes.Buffer + func() { + defer r.handlePanic(ctx) + sels := selected.ApplyOperation(&r.Request, s, op) + r.execSelections(ctx, sels, nil, s.Resolver, &out, op.Type == query.Mutation) + }() + + if err := ctx.Err(); err != nil { + return nil, []*errors.QueryError{errors.Errorf("%s", err)} + } + + return out.Bytes(), r.Errs +} + +type fieldToExec struct { + field *selected.SchemaField + sels []selected.Selection + resolver reflect.Value + out *bytes.Buffer +} + +func (r *Request) execSelections(ctx context.Context, sels []selected.Selection, path *pathSegment, resolver reflect.Value, out *bytes.Buffer, serially bool) { + async := !serially && selected.HasAsyncSel(sels) + + var fields []*fieldToExec + collectFieldsToResolve(sels, resolver, &fields, make(map[string]*fieldToExec)) + + if async { + var wg sync.WaitGroup + wg.Add(len(fields)) + for _, f := range fields { + go func(f *fieldToExec) { + defer wg.Done() + defer r.handlePanic(ctx) + f.out = new(bytes.Buffer) + execFieldSelection(ctx, r, f, &pathSegment{path, f.field.Alias}, true) + }(f) + } + wg.Wait() + } + + out.WriteByte('{') + for i, f := range fields { + if i > 0 { + out.WriteByte(',') + } + out.WriteByte('"') + out.WriteString(f.field.Alias) + out.WriteByte('"') + out.WriteByte(':') + if async { + out.Write(f.out.Bytes()) + continue + } + f.out = out + execFieldSelection(ctx, r, f, &pathSegment{path, f.field.Alias}, false) + } + out.WriteByte('}') +} + +func collectFieldsToResolve(sels []selected.Selection, resolver reflect.Value, fields *[]*fieldToExec, fieldByAlias map[string]*fieldToExec) { + for _, sel := range sels { + switch sel := sel.(type) { + case *selected.SchemaField: + field, ok := fieldByAlias[sel.Alias] + if !ok { // validation already checked for conflict (TODO) + field = &fieldToExec{field: sel, resolver: resolver} + fieldByAlias[sel.Alias] = field + *fields = append(*fields, field) + } + field.sels = append(field.sels, sel.Sels...) + + case *selected.TypenameField: + sf := &selected.SchemaField{ + Field: resolvable.MetaFieldTypename, + Alias: sel.Alias, + FixedResult: reflect.ValueOf(typeOf(sel, resolver)), + } + *fields = append(*fields, &fieldToExec{field: sf, resolver: resolver}) + + case *selected.TypeAssertion: + out := resolver.Method(sel.MethodIndex).Call(nil) + if !out[1].Bool() { + continue + } + collectFieldsToResolve(sel.Sels, out[0], fields, fieldByAlias) + + default: + panic("unreachable") + } + } +} + +func typeOf(tf *selected.TypenameField, resolver reflect.Value) string { + if len(tf.TypeAssertions) == 0 { + return tf.Name + } + for name, a := range tf.TypeAssertions { + out := resolver.Method(a.MethodIndex).Call(nil) + if out[1].Bool() { + return name + } + } + return "" +} + +func execFieldSelection(ctx context.Context, r *Request, f *fieldToExec, path *pathSegment, applyLimiter bool) { + if applyLimiter { + r.Limiter <- struct{}{} + } + + var result reflect.Value + var err *errors.QueryError + + traceCtx, finish := r.Tracer.TraceField(ctx, f.field.TraceLabel, f.field.TypeName, f.field.Name, !f.field.Async, f.field.Args) + defer func() { + finish(err) + }() + + err = func() (err *errors.QueryError) { + defer func() { + if panicValue := recover(); panicValue != nil { + r.Logger.LogPanic(ctx, panicValue) + err = makePanicError(panicValue) + err.Path = path.toSlice() + } + }() + + if f.field.FixedResult.IsValid() { + result = f.field.FixedResult + return nil + } + + if err := traceCtx.Err(); err != nil { + return errors.Errorf("%s", err) // don't execute any more resolvers if context got cancelled + } + + var in []reflect.Value + if f.field.HasContext { + in = append(in, reflect.ValueOf(traceCtx)) + } + if f.field.ArgsPacker != nil { + in = append(in, f.field.PackedArgs) + } + callOut := f.resolver.Method(f.field.MethodIndex).Call(in) + result = callOut[0] + if f.field.HasError && !callOut[1].IsNil() { + resolverErr := callOut[1].Interface().(error) + err := errors.Errorf("%s", resolverErr) + err.Path = path.toSlice() + err.ResolverError = resolverErr + return err + } + return nil + }() + + if applyLimiter { + <-r.Limiter + } + + if err != nil { + r.AddError(err) + f.out.WriteString("null") // TODO handle non-nil + return + } + + r.execSelectionSet(traceCtx, f.sels, f.field.Type, path, result, f.out) +} + +func (r *Request) execSelectionSet(ctx context.Context, sels []selected.Selection, typ common.Type, path *pathSegment, resolver reflect.Value, out *bytes.Buffer) { + t, nonNull := unwrapNonNull(typ) + switch t := t.(type) { + case *schema.Object, *schema.Interface, *schema.Union: + // a reflect.Value of a nil interface will show up as an Invalid value + if resolver.Kind() == reflect.Invalid || ((resolver.Kind() == reflect.Ptr || resolver.Kind() == reflect.Interface) && resolver.IsNil()) { + if nonNull { + panic(errors.Errorf("got nil for non-null %q", t)) + } + out.WriteString("null") + return + } + + r.execSelections(ctx, sels, path, resolver, out, false) + return + } + + if !nonNull { + if resolver.IsNil() { + out.WriteString("null") + return + } + resolver = resolver.Elem() + } + + switch t := t.(type) { + case *common.List: + l := resolver.Len() + + if selected.HasAsyncSel(sels) { + var wg sync.WaitGroup + wg.Add(l) + entryouts := make([]bytes.Buffer, l) + for i := 0; i < l; i++ { + go func(i int) { + defer wg.Done() + defer r.handlePanic(ctx) + r.execSelectionSet(ctx, sels, t.OfType, &pathSegment{path, i}, resolver.Index(i), &entryouts[i]) + }(i) + } + wg.Wait() + + out.WriteByte('[') + for i, entryout := range entryouts { + if i > 0 { + out.WriteByte(',') + } + out.Write(entryout.Bytes()) + } + out.WriteByte(']') + return + } + + out.WriteByte('[') + for i := 0; i < l; i++ { + if i > 0 { + out.WriteByte(',') + } + r.execSelectionSet(ctx, sels, t.OfType, &pathSegment{path, i}, resolver.Index(i), out) + } + out.WriteByte(']') + + case *schema.Scalar: + v := resolver.Interface() + data, err := json.Marshal(v) + if err != nil { + panic(errors.Errorf("could not marshal %v: %s", v, err)) + } + out.Write(data) + + case *schema.Enum: + out.WriteByte('"') + out.WriteString(resolver.String()) + out.WriteByte('"') + + default: + panic("unreachable") + } +} + +func unwrapNonNull(t common.Type) (common.Type, bool) { + if nn, ok := t.(*common.NonNull); ok { + return nn.OfType, true + } + return t, false +} + +type pathSegment struct { + parent *pathSegment + value interface{} +} + +func (p *pathSegment) toSlice() []interface{} { + if p == nil { + return nil + } + return append(p.parent.toSlice(), p.value) +} diff --git a/vendor/github.com/graph-gophers/graphql-go/internal/exec/packer/packer.go b/vendor/github.com/graph-gophers/graphql-go/internal/exec/packer/packer.go new file mode 100644 index 0000000000..22706bcd1f --- /dev/null +++ b/vendor/github.com/graph-gophers/graphql-go/internal/exec/packer/packer.go @@ -0,0 +1,371 @@ +package packer + +import ( + "fmt" + "math" + "reflect" + "strings" + + "github.com/graph-gophers/graphql-go/errors" + "github.com/graph-gophers/graphql-go/internal/common" + "github.com/graph-gophers/graphql-go/internal/schema" +) + +type packer interface { + Pack(value interface{}) (reflect.Value, error) +} + +type Builder struct { + packerMap map[typePair]*packerMapEntry + structPackers []*StructPacker +} + +type typePair struct { + graphQLType common.Type + resolverType reflect.Type +} + +type packerMapEntry struct { + packer packer + targets []*packer +} + +func NewBuilder() *Builder { + return &Builder{ + packerMap: make(map[typePair]*packerMapEntry), + } +} + +func (b *Builder) Finish() error { + for _, entry := range b.packerMap { + for _, target := range entry.targets { + *target = entry.packer + } + } + + for _, p := range b.structPackers { + p.defaultStruct = reflect.New(p.structType).Elem() + for _, f := range p.fields { + if defaultVal := f.field.Default; defaultVal != nil { + v, err := f.fieldPacker.Pack(defaultVal.Value(nil)) + if err != nil { + return err + } + p.defaultStruct.FieldByIndex(f.fieldIndex).Set(v) + } + } + } + + return nil +} + +func (b *Builder) assignPacker(target *packer, schemaType common.Type, reflectType reflect.Type) error { + k := typePair{schemaType, reflectType} + ref, ok := b.packerMap[k] + if !ok { + ref = &packerMapEntry{} + b.packerMap[k] = ref + var err error + ref.packer, err = b.makePacker(schemaType, reflectType) + if err != nil { + return err + } + } + ref.targets = append(ref.targets, target) + return nil +} + +func (b *Builder) makePacker(schemaType common.Type, reflectType reflect.Type) (packer, error) { + t, nonNull := unwrapNonNull(schemaType) + if !nonNull { + if reflectType.Kind() != reflect.Ptr { + return nil, fmt.Errorf("%s is not a pointer", reflectType) + } + elemType := reflectType.Elem() + addPtr := true + if _, ok := t.(*schema.InputObject); ok { + elemType = reflectType // keep pointer for input objects + addPtr = false + } + elem, err := b.makeNonNullPacker(t, elemType) + if err != nil { + return nil, err + } + return &nullPacker{ + elemPacker: elem, + valueType: reflectType, + addPtr: addPtr, + }, nil + } + + return b.makeNonNullPacker(t, reflectType) +} + +func (b *Builder) makeNonNullPacker(schemaType common.Type, reflectType reflect.Type) (packer, error) { + if u, ok := reflect.New(reflectType).Interface().(Unmarshaler); ok { + if !u.ImplementsGraphQLType(schemaType.String()) { + return nil, fmt.Errorf("can not unmarshal %s into %s", schemaType, reflectType) + } + return &unmarshalerPacker{ + ValueType: reflectType, + }, nil + } + + switch t := schemaType.(type) { + case *schema.Scalar: + return &ValuePacker{ + ValueType: reflectType, + }, nil + + case *schema.Enum: + if reflectType.Kind() != reflect.String { + return nil, fmt.Errorf("wrong type, expected %s", reflect.String) + } + return &ValuePacker{ + ValueType: reflectType, + }, nil + + case *schema.InputObject: + e, err := b.MakeStructPacker(t.Values, reflectType) + if err != nil { + return nil, err + } + return e, nil + + case *common.List: + if reflectType.Kind() != reflect.Slice { + return nil, fmt.Errorf("expected slice, got %s", reflectType) + } + p := &listPacker{ + sliceType: reflectType, + } + if err := b.assignPacker(&p.elem, t.OfType, reflectType.Elem()); err != nil { + return nil, err + } + return p, nil + + case *schema.Object, *schema.Interface, *schema.Union: + return nil, fmt.Errorf("type of kind %s can not be used as input", t.Kind()) + + default: + panic("unreachable") + } +} + +func (b *Builder) MakeStructPacker(values common.InputValueList, typ reflect.Type) (*StructPacker, error) { + structType := typ + usePtr := false + if typ.Kind() == reflect.Ptr { + structType = typ.Elem() + usePtr = true + } + if structType.Kind() != reflect.Struct { + return nil, fmt.Errorf("expected struct or pointer to struct, got %s", typ) + } + + var fields []*structPackerField + for _, v := range values { + fe := &structPackerField{field: v} + fx := func(n string) bool { + return strings.EqualFold(stripUnderscore(n), stripUnderscore(v.Name.Name)) + } + + sf, ok := structType.FieldByNameFunc(fx) + if !ok { + return nil, fmt.Errorf("missing argument %q", v.Name) + } + if sf.PkgPath != "" { + return nil, fmt.Errorf("field %q must be exported", sf.Name) + } + fe.fieldIndex = sf.Index + + ft := v.Type + if v.Default != nil { + ft, _ = unwrapNonNull(ft) + ft = &common.NonNull{OfType: ft} + } + + if err := b.assignPacker(&fe.fieldPacker, ft, sf.Type); err != nil { + return nil, fmt.Errorf("field %q: %s", sf.Name, err) + } + + fields = append(fields, fe) + } + + p := &StructPacker{ + structType: structType, + usePtr: usePtr, + fields: fields, + } + b.structPackers = append(b.structPackers, p) + return p, nil +} + +type StructPacker struct { + structType reflect.Type + usePtr bool + defaultStruct reflect.Value + fields []*structPackerField +} + +type structPackerField struct { + field *common.InputValue + fieldIndex []int + fieldPacker packer +} + +func (p *StructPacker) Pack(value interface{}) (reflect.Value, error) { + if value == nil { + return reflect.Value{}, errors.Errorf("got null for non-null") + } + + values := value.(map[string]interface{}) + v := reflect.New(p.structType) + v.Elem().Set(p.defaultStruct) + for _, f := range p.fields { + if value, ok := values[f.field.Name.Name]; ok { + packed, err := f.fieldPacker.Pack(value) + if err != nil { + return reflect.Value{}, err + } + v.Elem().FieldByIndex(f.fieldIndex).Set(packed) + } + } + if !p.usePtr { + return v.Elem(), nil + } + return v, nil +} + +type listPacker struct { + sliceType reflect.Type + elem packer +} + +func (e *listPacker) Pack(value interface{}) (reflect.Value, error) { + list, ok := value.([]interface{}) + if !ok { + list = []interface{}{value} + } + + v := reflect.MakeSlice(e.sliceType, len(list), len(list)) + for i := range list { + packed, err := e.elem.Pack(list[i]) + if err != nil { + return reflect.Value{}, err + } + v.Index(i).Set(packed) + } + return v, nil +} + +type nullPacker struct { + elemPacker packer + valueType reflect.Type + addPtr bool +} + +func (p *nullPacker) Pack(value interface{}) (reflect.Value, error) { + if value == nil { + return reflect.Zero(p.valueType), nil + } + + v, err := p.elemPacker.Pack(value) + if err != nil { + return reflect.Value{}, err + } + + if p.addPtr { + ptr := reflect.New(p.valueType.Elem()) + ptr.Elem().Set(v) + return ptr, nil + } + + return v, nil +} + +type ValuePacker struct { + ValueType reflect.Type +} + +func (p *ValuePacker) Pack(value interface{}) (reflect.Value, error) { + if value == nil { + return reflect.Value{}, errors.Errorf("got null for non-null") + } + + coerced, err := unmarshalInput(p.ValueType, value) + if err != nil { + return reflect.Value{}, fmt.Errorf("could not unmarshal %#v (%T) into %s: %s", value, value, p.ValueType, err) + } + return reflect.ValueOf(coerced), nil +} + +type unmarshalerPacker struct { + ValueType reflect.Type +} + +func (p *unmarshalerPacker) Pack(value interface{}) (reflect.Value, error) { + if value == nil { + return reflect.Value{}, errors.Errorf("got null for non-null") + } + + v := reflect.New(p.ValueType) + if err := v.Interface().(Unmarshaler).UnmarshalGraphQL(value); err != nil { + return reflect.Value{}, err + } + return v.Elem(), nil +} + +type Unmarshaler interface { + ImplementsGraphQLType(name string) bool + UnmarshalGraphQL(input interface{}) error +} + +func unmarshalInput(typ reflect.Type, input interface{}) (interface{}, error) { + if reflect.TypeOf(input) == typ { + return input, nil + } + + switch typ.Kind() { + case reflect.Int32: + switch input := input.(type) { + case int: + if input < math.MinInt32 || input > math.MaxInt32 { + return nil, fmt.Errorf("not a 32-bit integer") + } + return int32(input), nil + case float64: + coerced := int32(input) + if input < math.MinInt32 || input > math.MaxInt32 || float64(coerced) != input { + return nil, fmt.Errorf("not a 32-bit integer") + } + return coerced, nil + } + + case reflect.Float64: + switch input := input.(type) { + case int32: + return float64(input), nil + case int: + return float64(input), nil + } + + case reflect.String: + if reflect.TypeOf(input).ConvertibleTo(typ) { + return reflect.ValueOf(input).Convert(typ).Interface(), nil + } + } + + return nil, fmt.Errorf("incompatible type") +} + +func unwrapNonNull(t common.Type) (common.Type, bool) { + if nn, ok := t.(*common.NonNull); ok { + return nn.OfType, true + } + return t, false +} + +func stripUnderscore(s string) string { + return strings.Replace(s, "_", "", -1) +} diff --git a/vendor/github.com/graph-gophers/graphql-go/internal/exec/resolvable/meta.go b/vendor/github.com/graph-gophers/graphql-go/internal/exec/resolvable/meta.go new file mode 100644 index 0000000000..826c823484 --- /dev/null +++ b/vendor/github.com/graph-gophers/graphql-go/internal/exec/resolvable/meta.go @@ -0,0 +1,58 @@ +package resolvable + +import ( + "fmt" + "reflect" + + "github.com/graph-gophers/graphql-go/internal/common" + "github.com/graph-gophers/graphql-go/internal/schema" + "github.com/graph-gophers/graphql-go/introspection" +) + +var MetaSchema *Object +var MetaType *Object + +func init() { + var err error + b := newBuilder(schema.Meta) + + metaSchema := schema.Meta.Types["__Schema"].(*schema.Object) + MetaSchema, err = b.makeObjectExec(metaSchema.Name, metaSchema.Fields, nil, false, reflect.TypeOf(&introspection.Schema{})) + if err != nil { + panic(err) + } + + metaType := schema.Meta.Types["__Type"].(*schema.Object) + MetaType, err = b.makeObjectExec(metaType.Name, metaType.Fields, nil, false, reflect.TypeOf(&introspection.Type{})) + if err != nil { + panic(err) + } + + if err := b.finish(); err != nil { + panic(err) + } +} + +var MetaFieldTypename = Field{ + Field: schema.Field{ + Name: "__typename", + Type: &common.NonNull{OfType: schema.Meta.Types["String"]}, + }, + TraceLabel: fmt.Sprintf("GraphQL field: __typename"), +} + +var MetaFieldSchema = Field{ + Field: schema.Field{ + Name: "__schema", + Type: schema.Meta.Types["__Schema"], + }, + TraceLabel: fmt.Sprintf("GraphQL field: __schema"), +} + +var MetaFieldType = Field{ + Field: schema.Field{ + Name: "__type", + Type: schema.Meta.Types["__Type"], + }, + TraceLabel: fmt.Sprintf("GraphQL field: __type"), +} diff --git a/vendor/github.com/graph-gophers/graphql-go/internal/exec/resolvable/resolvable.go b/vendor/github.com/graph-gophers/graphql-go/internal/exec/resolvable/resolvable.go new file mode 100644 index 0000000000..3e5d9e44d9 --- /dev/null +++ b/vendor/github.com/graph-gophers/graphql-go/internal/exec/resolvable/resolvable.go @@ -0,0 +1,331 @@ +package resolvable + +import ( + "context" + "fmt" + "reflect" + "strings" + + "github.com/graph-gophers/graphql-go/internal/common" + "github.com/graph-gophers/graphql-go/internal/exec/packer" + "github.com/graph-gophers/graphql-go/internal/schema" +) + +type Schema struct { + schema.Schema + Query Resolvable + Mutation Resolvable + Resolver reflect.Value +} + +type Resolvable interface { + isResolvable() +} + +type Object struct { + Name string + Fields map[string]*Field + TypeAssertions map[string]*TypeAssertion +} + +type Field struct { + schema.Field + TypeName string + MethodIndex int + HasContext bool + HasError bool + ArgsPacker *packer.StructPacker + ValueExec Resolvable + TraceLabel string +} + +type TypeAssertion struct { + MethodIndex int + TypeExec Resolvable +} + +type List struct { + Elem Resolvable +} + +type Scalar struct{} + +func (*Object) isResolvable() {} +func (*List) isResolvable() {} +func (*Scalar) isResolvable() {} + +func ApplyResolver(s *schema.Schema, resolver interface{}) (*Schema, error) { + b := newBuilder(s) + + var query, mutation Resolvable + + if t, ok := s.EntryPoints["query"]; ok { + if err := b.assignExec(&query, t, reflect.TypeOf(resolver)); err != nil { + return nil, err + } + } + + if t, ok := s.EntryPoints["mutation"]; ok { + if err := b.assignExec(&mutation, t, reflect.TypeOf(resolver)); err != nil { + return nil, err + } + } + + if err := b.finish(); err != nil { + return nil, err + } + + return &Schema{ + Schema: *s, + Resolver: reflect.ValueOf(resolver), + Query: query, + Mutation: mutation, + }, nil +} + +type execBuilder struct { + schema *schema.Schema + resMap map[typePair]*resMapEntry + packerBuilder *packer.Builder +} + +type typePair struct { + graphQLType common.Type + resolverType reflect.Type +} + +type resMapEntry struct { + exec Resolvable + targets []*Resolvable +} + +func newBuilder(s *schema.Schema) *execBuilder { + return &execBuilder{ + schema: s, + resMap: make(map[typePair]*resMapEntry), + packerBuilder: packer.NewBuilder(), + } +} + +func (b *execBuilder) finish() error { + for _, entry := range b.resMap { + for _, target := range entry.targets { + *target = entry.exec + } + } + + return b.packerBuilder.Finish() +} + +func (b *execBuilder) assignExec(target *Resolvable, t common.Type, resolverType reflect.Type) error { + k := typePair{t, resolverType} + ref, ok := b.resMap[k] + if !ok { + ref = &resMapEntry{} + b.resMap[k] = ref + var err error + ref.exec, err = b.makeExec(t, resolverType) + if err != nil { + return err + } + } + ref.targets = append(ref.targets, target) + return nil +} + +func (b *execBuilder) makeExec(t common.Type, resolverType reflect.Type) (Resolvable, error) { + var nonNull bool + t, nonNull = unwrapNonNull(t) + + switch t := t.(type) { + case *schema.Object: + return b.makeObjectExec(t.Name, t.Fields, nil, nonNull, resolverType) + + case *schema.Interface: + return b.makeObjectExec(t.Name, t.Fields, t.PossibleTypes, nonNull, resolverType) + + case *schema.Union: + return b.makeObjectExec(t.Name, nil, t.PossibleTypes, nonNull, resolverType) + } + + if !nonNull { + if resolverType.Kind() != reflect.Ptr { + return nil, fmt.Errorf("%s is not a pointer", resolverType) + } + resolverType = resolverType.Elem() + } + + switch t := t.(type) { + case *schema.Scalar: + return makeScalarExec(t, resolverType) + + case *schema.Enum: + return &Scalar{}, nil + + case *common.List: + if resolverType.Kind() != reflect.Slice { + return nil, fmt.Errorf("%s is not a slice", resolverType) + } + e := &List{} + if err := b.assignExec(&e.Elem, t.OfType, resolverType.Elem()); err != nil { + return nil, err + } + return e, nil + + default: + panic("invalid type: " + t.String()) + } +} + +func makeScalarExec(t *schema.Scalar, resolverType reflect.Type) (Resolvable, error) { + implementsType := false + switch r := reflect.New(resolverType).Interface().(type) { + case *int32: + implementsType = (t.Name == "Int") + case *float64: + implementsType = (t.Name == "Float") + case *string: + implementsType = (t.Name == "String") + case *bool: + implementsType = (t.Name == "Boolean") + case packer.Unmarshaler: + implementsType = r.ImplementsGraphQLType(t.Name) + } + if !implementsType { + return nil, fmt.Errorf("can not use %s as %s", resolverType, t.Name) + } + return &Scalar{}, nil +} + +func (b *execBuilder) makeObjectExec(typeName string, fields schema.FieldList, possibleTypes []*schema.Object, nonNull bool, resolverType reflect.Type) (*Object, error) { + if !nonNull { + if resolverType.Kind() != reflect.Ptr && resolverType.Kind() != reflect.Interface { + return nil, fmt.Errorf("%s is not a pointer or interface", resolverType) + } + } + + methodHasReceiver := resolverType.Kind() != reflect.Interface + + Fields := make(map[string]*Field) + for _, f := range fields { + methodIndex := findMethod(resolverType, f.Name) + if methodIndex == -1 { + hint := "" + if findMethod(reflect.PtrTo(resolverType), f.Name) != -1 { + hint = " (hint: the method exists on the pointer type)" + } + return nil, fmt.Errorf("%s does not resolve %q: missing method for field %q%s", resolverType, typeName, f.Name, hint) + } + + m := resolverType.Method(methodIndex) + fe, err := b.makeFieldExec(typeName, f, m, methodIndex, methodHasReceiver) + if err != nil { + return nil, fmt.Errorf("%s\n\treturned by (%s).%s", err, resolverType, m.Name) + } + Fields[f.Name] = fe + } + + typeAssertions := make(map[string]*TypeAssertion) + for _, impl := range possibleTypes { + methodIndex := findMethod(resolverType, "To"+impl.Name) + if methodIndex == -1 { + return nil, fmt.Errorf("%s does not resolve %q: missing method %q to convert to %q", resolverType, typeName, "To"+impl.Name, impl.Name) + } + if resolverType.Method(methodIndex).Type.NumOut() != 2 { + return nil, fmt.Errorf("%s does not resolve %q: method %q should return a value and a bool indicating success", resolverType, typeName, "To"+impl.Name) + } + a := &TypeAssertion{ + MethodIndex: methodIndex, + } + if err := b.assignExec(&a.TypeExec, impl, resolverType.Method(methodIndex).Type.Out(0)); err != nil { + return nil, err + } + typeAssertions[impl.Name] = a + } + + return &Object{ + Name: typeName, + Fields: Fields, + TypeAssertions: typeAssertions, + }, nil +} + +var contextType = reflect.TypeOf((*context.Context)(nil)).Elem() +var errorType = reflect.TypeOf((*error)(nil)).Elem() + +func (b *execBuilder) makeFieldExec(typeName string, f *schema.Field, m reflect.Method, methodIndex int, methodHasReceiver bool) (*Field, error) { + in := make([]reflect.Type, m.Type.NumIn()) + for i := range in { + in[i] = m.Type.In(i) + } + if methodHasReceiver { + in = in[1:] // first parameter is receiver + } + + hasContext := len(in) > 0 && in[0] == contextType + if hasContext { + in = in[1:] + } + + var argsPacker *packer.StructPacker + if len(f.Args) > 0 { + if len(in) == 0 { + return nil, fmt.Errorf("must have parameter for field arguments") + } + var err error + argsPacker, err = b.packerBuilder.MakeStructPacker(f.Args, in[0]) + if err != nil { + return nil, err + } + in = in[1:] + } + + if len(in) > 0 { + return nil, fmt.Errorf("too many parameters") + } + + if m.Type.NumOut() > 2 { + return nil, fmt.Errorf("too many return values") + } + + hasError := m.Type.NumOut() == 2 + if hasError { + if m.Type.Out(1) != errorType { + return nil, fmt.Errorf(`must have "error" as its second return value`) + } + } + + fe := &Field{ + Field: *f, + TypeName: typeName, + MethodIndex: methodIndex, + HasContext: hasContext, + ArgsPacker: argsPacker, + HasError: hasError, + TraceLabel: fmt.Sprintf("GraphQL field: %s.%s", typeName, f.Name), + } + if err := b.assignExec(&fe.ValueExec, f.Type, m.Type.Out(0)); err != nil { + return nil, err + } + return fe, nil +} + +func findMethod(t reflect.Type, name string) int { + for i := 0; i < t.NumMethod(); i++ { + if strings.EqualFold(stripUnderscore(name), stripUnderscore(t.Method(i).Name)) { + return i + } + } + return -1 +} + +func unwrapNonNull(t common.Type) (common.Type, bool) { + if nn, ok := t.(*common.NonNull); ok { + return nn.OfType, true + } + return t, false +} + +func stripUnderscore(s string) string { + return strings.Replace(s, "_", "", -1) +} diff --git a/vendor/github.com/graph-gophers/graphql-go/internal/exec/selected/selected.go b/vendor/github.com/graph-gophers/graphql-go/internal/exec/selected/selected.go new file mode 100644 index 0000000000..aed079b671 --- /dev/null +++ b/vendor/github.com/graph-gophers/graphql-go/internal/exec/selected/selected.go @@ -0,0 +1,238 @@ +package selected + +import ( + "fmt" + "reflect" + "sync" + + "github.com/graph-gophers/graphql-go/errors" + "github.com/graph-gophers/graphql-go/internal/common" + "github.com/graph-gophers/graphql-go/internal/exec/packer" + "github.com/graph-gophers/graphql-go/internal/exec/resolvable" + "github.com/graph-gophers/graphql-go/internal/query" + "github.com/graph-gophers/graphql-go/internal/schema" + "github.com/graph-gophers/graphql-go/introspection" +) + +type Request struct { + Schema *schema.Schema + Doc *query.Document + Vars map[string]interface{} + Mu sync.Mutex + Errs []*errors.QueryError +} + +func (r *Request) AddError(err *errors.QueryError) { + r.Mu.Lock() + r.Errs = append(r.Errs, err) + r.Mu.Unlock() +} + +func ApplyOperation(r *Request, s *resolvable.Schema, op *query.Operation) []Selection { + var obj *resolvable.Object + switch op.Type { + case query.Query: + obj = s.Query.(*resolvable.Object) + case query.Mutation: + obj = s.Mutation.(*resolvable.Object) + } + return applySelectionSet(r, obj, op.Selections) +} + +type Selection interface { + isSelection() +} + +type SchemaField struct { + resolvable.Field + Alias string + Args map[string]interface{} + PackedArgs reflect.Value + Sels []Selection + Async bool + FixedResult reflect.Value +} + +type TypeAssertion struct { + resolvable.TypeAssertion + Sels []Selection +} + +type TypenameField struct { + resolvable.Object + Alias string +} + +func (*SchemaField) isSelection() {} +func (*TypeAssertion) isSelection() {} +func (*TypenameField) isSelection() {} + +func applySelectionSet(r *Request, e *resolvable.Object, sels []query.Selection) (flattenedSels []Selection) { + for _, sel := range sels { + switch sel := sel.(type) { + case *query.Field: + field := sel + if skipByDirective(r, field.Directives) { + continue + } + + switch field.Name.Name { + case "__typename": + flattenedSels = append(flattenedSels, &TypenameField{ + Object: *e, + Alias: field.Alias.Name, + }) + + case "__schema": + flattenedSels = append(flattenedSels, &SchemaField{ + Field: resolvable.MetaFieldSchema, + Alias: field.Alias.Name, + Sels: applySelectionSet(r, resolvable.MetaSchema, field.Selections), + Async: true, + FixedResult: reflect.ValueOf(introspection.WrapSchema(r.Schema)), + }) + + case "__type": + p := packer.ValuePacker{ValueType: reflect.TypeOf("")} + v, err := p.Pack(field.Arguments.MustGet("name").Value(r.Vars)) + if err != nil { + r.AddError(errors.Errorf("%s", err)) + return nil + } + + t, ok := r.Schema.Types[v.String()] + if !ok { + return nil + } + + flattenedSels = append(flattenedSels, &SchemaField{ + Field: resolvable.MetaFieldType, + Alias: field.Alias.Name, + Sels: applySelectionSet(r, resolvable.MetaType, field.Selections), + Async: true, + FixedResult: reflect.ValueOf(introspection.WrapType(t)), + }) + + default: + fe := e.Fields[field.Name.Name] + + var args map[string]interface{} + var packedArgs reflect.Value + if fe.ArgsPacker != nil { + args = make(map[string]interface{}) + for _, arg := range field.Arguments { + args[arg.Name.Name] = arg.Value.Value(r.Vars) + } + var err error + packedArgs, err = fe.ArgsPacker.Pack(args) + if err != nil { + r.AddError(errors.Errorf("%s", err)) + return + } + } + + fieldSels := applyField(r, fe.ValueExec, field.Selections) + flattenedSels = append(flattenedSels, &SchemaField{ + Field: *fe, + Alias: field.Alias.Name, + Args: args, + PackedArgs: packedArgs, + Sels: fieldSels, + Async: fe.HasContext || fe.ArgsPacker != nil || fe.HasError || HasAsyncSel(fieldSels), + }) + } + + case *query.InlineFragment: + frag := sel + if skipByDirective(r, frag.Directives) { + continue + } + flattenedSels = append(flattenedSels, applyFragment(r, e, &frag.Fragment)...) + + case *query.FragmentSpread: + spread := sel + if skipByDirective(r, spread.Directives) { + continue + } + flattenedSels = append(flattenedSels, applyFragment(r, e, &r.Doc.Fragments.Get(spread.Name.Name).Fragment)...) + + default: + panic("invalid type") + } + } + return +} + +func applyFragment(r *Request, e *resolvable.Object, frag *query.Fragment) []Selection { + if frag.On.Name != "" && frag.On.Name != e.Name { + a, ok := e.TypeAssertions[frag.On.Name] + if !ok { + panic(fmt.Errorf("%q does not implement %q", frag.On, e.Name)) // TODO proper error handling + } + + return []Selection{&TypeAssertion{ + TypeAssertion: *a, + Sels: applySelectionSet(r, a.TypeExec.(*resolvable.Object), frag.Selections), + }} + } + return applySelectionSet(r, e, frag.Selections) +} + +func applyField(r *Request, e resolvable.Resolvable, sels []query.Selection) []Selection { + switch e := e.(type) { + case *resolvable.Object: + return applySelectionSet(r, e, sels) + case *resolvable.List: + return applyField(r, e.Elem, sels) + case *resolvable.Scalar: + return nil + default: + panic("unreachable") + } +} + +func skipByDirective(r *Request, directives common.DirectiveList) bool { + if d := directives.Get("skip"); d != nil { + p := packer.ValuePacker{ValueType: reflect.TypeOf(false)} + v, err := p.Pack(d.Args.MustGet("if").Value(r.Vars)) + if err != nil { + r.AddError(errors.Errorf("%s", err)) + } + if err == nil && v.Bool() { + return true + } + } + + if d := directives.Get("include"); d != nil { + p := packer.ValuePacker{ValueType: reflect.TypeOf(false)} + v, err := p.Pack(d.Args.MustGet("if").Value(r.Vars)) + if err != nil { + r.AddError(errors.Errorf("%s", err)) + } + if err == nil && !v.Bool() { + return true + } + } + + return false +} + +func HasAsyncSel(sels []Selection) bool { + for _, sel := range sels { + switch sel := sel.(type) { + case *SchemaField: + if sel.Async { + return true + } + case *TypeAssertion: + if HasAsyncSel(sel.Sels) { + return true + } + case *TypenameField: + // sync + default: + panic("unreachable") + } + } + return false +} diff --git a/vendor/github.com/graph-gophers/graphql-go/internal/query/query.go b/vendor/github.com/graph-gophers/graphql-go/internal/query/query.go new file mode 100644 index 0000000000..faba4d2ade --- /dev/null +++ b/vendor/github.com/graph-gophers/graphql-go/internal/query/query.go @@ -0,0 +1,234 @@ +package query + +import ( + "fmt" + "text/scanner" + + "github.com/graph-gophers/graphql-go/errors" + "github.com/graph-gophers/graphql-go/internal/common" +) + +type Document struct { + Operations OperationList + Fragments FragmentList +} + +type OperationList []*Operation + +func (l OperationList) Get(name string) *Operation { + for _, f := range l { + if f.Name.Name == name { + return f + } + } + return nil +} + +type FragmentList []*FragmentDecl + +func (l FragmentList) Get(name string) *FragmentDecl { + for _, f := range l { + if f.Name.Name == name { + return f + } + } + return nil +} + +type Operation struct { + Type OperationType + Name common.Ident + Vars common.InputValueList + Selections []Selection + Directives common.DirectiveList + Loc errors.Location +} + +type OperationType string + +const ( + Query OperationType = "QUERY" + Mutation = "MUTATION" + Subscription = "SUBSCRIPTION" +) + +type Fragment struct { + On common.TypeName + Selections []Selection +} + +type FragmentDecl struct { + Fragment + Name common.Ident + Directives common.DirectiveList + Loc errors.Location +} + +type Selection interface { + isSelection() +} + +type Field struct { + Alias common.Ident + Name common.Ident + Arguments common.ArgumentList + Directives common.DirectiveList + Selections []Selection + SelectionSetLoc errors.Location +} + +type InlineFragment struct { + Fragment + Directives common.DirectiveList + Loc errors.Location +} + +type FragmentSpread struct { + Name common.Ident + Directives common.DirectiveList + Loc errors.Location +} + +func (Field) isSelection() {} +func (InlineFragment) isSelection() {} +func (FragmentSpread) isSelection() {} + +func Parse(queryString string) (*Document, *errors.QueryError) { + l := common.NewLexer(queryString) + + var doc *Document + err := l.CatchSyntaxError(func() { doc = parseDocument(l) }) + if err != nil { + return nil, err + } + + return doc, nil +} + +func parseDocument(l *common.Lexer) *Document { + d := &Document{} + l.Consume() + for l.Peek() != scanner.EOF { + if l.Peek() == '{' { + op := &Operation{Type: Query, Loc: l.Location()} + op.Selections = parseSelectionSet(l) + d.Operations = append(d.Operations, op) + continue + } + + loc := l.Location() + switch x := l.ConsumeIdent(); x { + case "query": + op := parseOperation(l, Query) + op.Loc = loc + d.Operations = append(d.Operations, op) + + case "mutation": + d.Operations = append(d.Operations, parseOperation(l, Mutation)) + + case "subscription": + d.Operations = append(d.Operations, parseOperation(l, Subscription)) + + case "fragment": + frag := parseFragment(l) + frag.Loc = loc + d.Fragments = append(d.Fragments, frag) + + default: + l.SyntaxError(fmt.Sprintf(`unexpected %q, expecting "fragment"`, x)) + } + } + return d +} + +func parseOperation(l *common.Lexer, opType OperationType) *Operation { + op := &Operation{Type: opType} + op.Name.Loc = l.Location() + if l.Peek() == scanner.Ident { + op.Name = l.ConsumeIdentWithLoc() + } + op.Directives = common.ParseDirectives(l) + if l.Peek() == '(' { + l.ConsumeToken('(') + for l.Peek() != ')' { + loc := l.Location() + l.ConsumeToken('$') + iv := common.ParseInputValue(l) + iv.Loc = loc + op.Vars = append(op.Vars, iv) + } + l.ConsumeToken(')') + } + op.Selections = parseSelectionSet(l) + return op +} + +func parseFragment(l *common.Lexer) *FragmentDecl { + f := &FragmentDecl{} + f.Name = l.ConsumeIdentWithLoc() + l.ConsumeKeyword("on") + f.On = common.TypeName{Ident: l.ConsumeIdentWithLoc()} + f.Directives = common.ParseDirectives(l) + f.Selections = parseSelectionSet(l) + return f +} + +func parseSelectionSet(l *common.Lexer) []Selection { + var sels []Selection + l.ConsumeToken('{') + for l.Peek() != '}' { + sels = append(sels, parseSelection(l)) + } + l.ConsumeToken('}') + return sels +} + +func parseSelection(l *common.Lexer) Selection { + if l.Peek() == '.' { + return parseSpread(l) + } + return parseField(l) +} + +func parseField(l *common.Lexer) *Field { + f := &Field{} + f.Alias = l.ConsumeIdentWithLoc() + f.Name = f.Alias + if l.Peek() == ':' { + l.ConsumeToken(':') + f.Name = l.ConsumeIdentWithLoc() + } + if l.Peek() == '(' { + f.Arguments = common.ParseArguments(l) + } + f.Directives = common.ParseDirectives(l) + if l.Peek() == '{' { + f.SelectionSetLoc = l.Location() + f.Selections = parseSelectionSet(l) + } + return f +} + +func parseSpread(l *common.Lexer) Selection { + loc := l.Location() + l.ConsumeToken('.') + l.ConsumeToken('.') + l.ConsumeToken('.') + + f := &InlineFragment{Loc: loc} + if l.Peek() == scanner.Ident { + ident := l.ConsumeIdentWithLoc() + if ident.Name != "on" { + fs := &FragmentSpread{ + Name: ident, + Loc: loc, + } + fs.Directives = common.ParseDirectives(l) + return fs + } + f.On = common.TypeName{Ident: l.ConsumeIdentWithLoc()} + } + f.Directives = common.ParseDirectives(l) + f.Selections = parseSelectionSet(l) + return f +} diff --git a/vendor/github.com/graph-gophers/graphql-go/internal/schema/meta.go b/vendor/github.com/graph-gophers/graphql-go/internal/schema/meta.go new file mode 100644 index 0000000000..b48bf7acf2 --- /dev/null +++ b/vendor/github.com/graph-gophers/graphql-go/internal/schema/meta.go @@ -0,0 +1,190 @@ +package schema + +var Meta *Schema + +func init() { + Meta = &Schema{} // bootstrap + Meta = New() + if err := Meta.Parse(metaSrc); err != nil { + panic(err) + } +} + +var metaSrc = ` + # The ` + "`" + `Int` + "`" + ` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1. + scalar Int + + # The ` + "`" + `Float` + "`" + ` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point). + scalar Float + + # The ` + "`" + `String` + "`" + ` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text. + scalar String + + # The ` + "`" + `Boolean` + "`" + ` scalar type represents ` + "`" + `true` + "`" + ` or ` + "`" + `false` + "`" + `. + scalar Boolean + + # The ` + "`" + `ID` + "`" + ` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as ` + "`" + `"4"` + "`" + `) or integer (such as ` + "`" + `4` + "`" + `) input value will be accepted as an ID. + scalar ID + + # Directs the executor to include this field or fragment only when the ` + "`" + `if` + "`" + ` argument is true. + directive @include( + # Included when true. + if: Boolean! + ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT + + # Directs the executor to skip this field or fragment when the ` + "`" + `if` + "`" + ` argument is true. + directive @skip( + # Skipped when true. + if: Boolean! + ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT + + # Marks an element of a GraphQL schema as no longer supported. + directive @deprecated( + # Explains why this element was deprecated, usually also including a suggestion + # for how to access supported similar data. Formatted in + # [Markdown](https://daringfireball.net/projects/markdown/). + reason: String = "No longer supported" + ) on FIELD_DEFINITION | ENUM_VALUE + + # A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document. + # + # In some cases, you need to provide options to alter GraphQL's execution behavior + # in ways field arguments will not suffice, such as conditionally including or + # skipping a field. Directives provide this by describing additional information + # to the executor. + type __Directive { + name: String! + description: String + locations: [__DirectiveLocation!]! + args: [__InputValue!]! + } + + # A Directive can be adjacent to many parts of the GraphQL language, a + # __DirectiveLocation describes one such possible adjacencies. + enum __DirectiveLocation { + # Location adjacent to a query operation. + QUERY + # Location adjacent to a mutation operation. + MUTATION + # Location adjacent to a subscription operation. + SUBSCRIPTION + # Location adjacent to a field. + FIELD + # Location adjacent to a fragment definition. + FRAGMENT_DEFINITION + # Location adjacent to a fragment spread. + FRAGMENT_SPREAD + # Location adjacent to an inline fragment. + INLINE_FRAGMENT + # Location adjacent to a schema definition. + SCHEMA + # Location adjacent to a scalar definition. + SCALAR + # Location adjacent to an object type definition. + OBJECT + # Location adjacent to a field definition. + FIELD_DEFINITION + # Location adjacent to an argument definition. + ARGUMENT_DEFINITION + # Location adjacent to an interface definition. + INTERFACE + # Location adjacent to a union definition. + UNION + # Location adjacent to an enum definition. + ENUM + # Location adjacent to an enum value definition. + ENUM_VALUE + # Location adjacent to an input object type definition. + INPUT_OBJECT + # Location adjacent to an input object field definition. + INPUT_FIELD_DEFINITION + } + + # One possible value for a given Enum. Enum values are unique values, not a + # placeholder for a string or numeric value. However an Enum value is returned in + # a JSON response as a string. + type __EnumValue { + name: String! + description: String + isDeprecated: Boolean! + deprecationReason: String + } + + # Object and Interface types are described by a list of Fields, each of which has + # a name, potentially a list of arguments, and a return type. + type __Field { + name: String! + description: String + args: [__InputValue!]! + type: __Type! + isDeprecated: Boolean! + deprecationReason: String + } + + # Arguments provided to Fields or Directives and the input fields of an + # InputObject are represented as Input Values which describe their type and + # optionally a default value. + type __InputValue { + name: String! + description: String + type: __Type! + # A GraphQL-formatted string representing the default value for this input value. + defaultValue: String + } + + # A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all + # available types and directives on the server, as well as the entry points for + # query, mutation, and subscription operations. + type __Schema { + # A list of all types supported by this server. + types: [__Type!]! + # The type that query operations will be rooted at. + queryType: __Type! + # If this server supports mutation, the type that mutation operations will be rooted at. + mutationType: __Type + # If this server support subscription, the type that subscription operations will be rooted at. + subscriptionType: __Type + # A list of all directives supported by this server. + directives: [__Directive!]! + } + + # The fundamental unit of any GraphQL Schema is the type. There are many kinds of + # types in GraphQL as represented by the ` + "`" + `__TypeKind` + "`" + ` enum. + # + # Depending on the kind of a type, certain fields describe information about that + # type. Scalar types provide no information beyond a name and description, while + # Enum types provide their values. Object and Interface types provide the fields + # they describe. Abstract types, Union and Interface, provide the Object types + # possible at runtime. List and NonNull types compose other types. + type __Type { + kind: __TypeKind! + name: String + description: String + fields(includeDeprecated: Boolean = false): [__Field!] + interfaces: [__Type!] + possibleTypes: [__Type!] + enumValues(includeDeprecated: Boolean = false): [__EnumValue!] + inputFields: [__InputValue!] + ofType: __Type + } + + # An enum describing what kind of type a given ` + "`" + `__Type` + "`" + ` is. + enum __TypeKind { + # Indicates this type is a scalar. + SCALAR + # Indicates this type is an object. ` + "`" + `fields` + "`" + ` and ` + "`" + `interfaces` + "`" + ` are valid fields. + OBJECT + # Indicates this type is an interface. ` + "`" + `fields` + "`" + ` and ` + "`" + `possibleTypes` + "`" + ` are valid fields. + INTERFACE + # Indicates this type is a union. ` + "`" + `possibleTypes` + "`" + ` is a valid field. + UNION + # Indicates this type is an enum. ` + "`" + `enumValues` + "`" + ` is a valid field. + ENUM + # Indicates this type is an input object. ` + "`" + `inputFields` + "`" + ` is a valid field. + INPUT_OBJECT + # Indicates this type is a list. ` + "`" + `ofType` + "`" + ` is a valid field. + LIST + # Indicates this type is a non-null. ` + "`" + `ofType` + "`" + ` is a valid field. + NON_NULL + } +` diff --git a/vendor/github.com/graph-gophers/graphql-go/internal/schema/schema.go b/vendor/github.com/graph-gophers/graphql-go/internal/schema/schema.go new file mode 100644 index 0000000000..e549f17c07 --- /dev/null +++ b/vendor/github.com/graph-gophers/graphql-go/internal/schema/schema.go @@ -0,0 +1,570 @@ +package schema + +import ( + "fmt" + "text/scanner" + + "github.com/graph-gophers/graphql-go/errors" + "github.com/graph-gophers/graphql-go/internal/common" +) + +// Schema represents a GraphQL service's collective type system capabilities. +// A schema is defined in terms of the types and directives it supports as well as the root +// operation types for each kind of operation: `query`, `mutation`, and `subscription`. +// +// For a more formal definition, read the relevant section in the specification: +// +// http://facebook.github.io/graphql/draft/#sec-Schema +type Schema struct { + // EntryPoints determines the place in the type system where `query`, `mutation`, and + // `subscription` operations begin. + // + // http://facebook.github.io/graphql/draft/#sec-Root-Operation-Types + // + // NOTE: The specification refers to this concept as "Root Operation Types". + // TODO: Rename the `EntryPoints` field to `RootOperationTypes` to align with spec terminology. + EntryPoints map[string]NamedType + + // Types are the fundamental unit of any GraphQL schema. + // There are six kinds of named types, and two wrapping types. + // + // http://facebook.github.io/graphql/draft/#sec-Types + Types map[string]NamedType + + // TODO: Type extensions? + // http://facebook.github.io/graphql/draft/#sec-Type-Extensions + + // Directives are used to annotate various parts of a GraphQL document as an indicator that they + // should be evaluated differently by a validator, executor, or client tool such as a code + // generator. + // + // http://facebook.github.io/graphql/draft/#sec-Type-System.Directives + Directives map[string]*DirectiveDecl + + entryPointNames map[string]string + objects []*Object + unions []*Union + enums []*Enum +} + +// Resolve a named type in the schema by its name. +func (s *Schema) Resolve(name string) common.Type { + return s.Types[name] +} + +// NamedType represents a type with a name. +// +// http://facebook.github.io/graphql/draft/#NamedType +type NamedType interface { + common.Type + TypeName() string + Description() string +} + +// Scalar types represent primitive leaf values (e.g. a string or an integer) in a GraphQL type +// system. +// +// GraphQL responses take the form of a hierarchical tree; the leaves on these trees are GraphQL +// scalars. +// +// http://facebook.github.io/graphql/draft/#sec-Scalars +type Scalar struct { + Name string + Desc string + // TODO: Add a list of directives? +} + +// Object types represent a list of named fields, each of which yield a value of a specific type. +// +// GraphQL queries are hierarchical and composed, describing a tree of information. +// While Scalar types describe the leaf values of these hierarchical types, Objects describe the +// intermediate levels. +// +// http://facebook.github.io/graphql/draft/#sec-Objects +type Object struct { + Name string + Interfaces []*Interface + Fields FieldList + Desc string + // TODO: Add a list of directives? + + interfaceNames []string +} + +// Interface types represent a list of named fields and their arguments. +// +// GraphQL objects can then implement these interfaces which requires that the object type will +// define all fields defined by those interfaces. +// +// http://facebook.github.io/graphql/draft/#sec-Interfaces +type Interface struct { + Name string + PossibleTypes []*Object + Fields FieldList // NOTE: the spec refers to this as `FieldsDefinition`. + Desc string + // TODO: Add a list of directives? +} + +// Union types represent objects that could be one of a list of GraphQL object types, but provides no +// guaranteed fields between those types. +// +// They also differ from interfaces in that object types declare what interfaces they implement, but +// are not aware of what unions contain them. +// +// http://facebook.github.io/graphql/draft/#sec-Unions +type Union struct { + Name string + PossibleTypes []*Object // NOTE: the spec refers to this as `UnionMemberTypes`. + Desc string + // TODO: Add a list of directives? + + typeNames []string +} + +// Enum types describe a set of possible values. +// +// Like scalar types, Enum types also represent leaf values in a GraphQL type system. +// +// http://facebook.github.io/graphql/draft/#sec-Enums +type Enum struct { + Name string + Values []*EnumValue // NOTE: the spec refers to this as `EnumValuesDefinition`. + Desc string + // TODO: Add a list of directives? +} + +// EnumValue types are unique values that may be serialized as a string: the name of the +// represented value. +// +// http://facebook.github.io/graphql/draft/#EnumValueDefinition +type EnumValue struct { + Name string + Directives common.DirectiveList + Desc string + // TODO: Add a list of directives? +} + +// InputObject types define a set of input fields; the input fields are either scalars, enums, or +// other input objects. +// +// This allows arguments to accept arbitrarily complex structs. +// +// http://facebook.github.io/graphql/draft/#sec-Input-Objects +type InputObject struct { + Name string + Desc string + Values common.InputValueList + // TODO: Add a list of directives? +} + +// FieldsList is a list of an Object's Fields. +// +// http://facebook.github.io/graphql/draft/#FieldsDefinition +type FieldList []*Field + +// Get iterates over the field list, returning a pointer-to-Field when the field name matches the +// provided `name` argument. +// Returns nil when no field was found by that name. +func (l FieldList) Get(name string) *Field { + for _, f := range l { + if f.Name == name { + return f + } + } + return nil +} + +// Names returns a string slice of the field names in the FieldList. +func (l FieldList) Names() []string { + names := make([]string, len(l)) + for i, f := range l { + names[i] = f.Name + } + return names +} + +// http://facebook.github.io/graphql/draft/#sec-Type-System.Directives +type DirectiveDecl struct { + Name string + Desc string + Locs []string + Args common.InputValueList +} + +func (*Scalar) Kind() string { return "SCALAR" } +func (*Object) Kind() string { return "OBJECT" } +func (*Interface) Kind() string { return "INTERFACE" } +func (*Union) Kind() string { return "UNION" } +func (*Enum) Kind() string { return "ENUM" } +func (*InputObject) Kind() string { return "INPUT_OBJECT" } + +func (t *Scalar) String() string { return t.Name } +func (t *Object) String() string { return t.Name } +func (t *Interface) String() string { return t.Name } +func (t *Union) String() string { return t.Name } +func (t *Enum) String() string { return t.Name } +func (t *InputObject) String() string { return t.Name } + +func (t *Scalar) TypeName() string { return t.Name } +func (t *Object) TypeName() string { return t.Name } +func (t *Interface) TypeName() string { return t.Name } +func (t *Union) TypeName() string { return t.Name } +func (t *Enum) TypeName() string { return t.Name } +func (t *InputObject) TypeName() string { return t.Name } + +func (t *Scalar) Description() string { return t.Desc } +func (t *Object) Description() string { return t.Desc } +func (t *Interface) Description() string { return t.Desc } +func (t *Union) Description() string { return t.Desc } +func (t *Enum) Description() string { return t.Desc } +func (t *InputObject) Description() string { return t.Desc } + +// Field is a conceptual function which yields values. +// http://facebook.github.io/graphql/draft/#FieldDefinition +type Field struct { + Name string + Args common.InputValueList // NOTE: the spec refers to this as `ArgumentsDefinition`. + Type common.Type + Directives common.DirectiveList + Desc string +} + +// New initializes an instance of Schema. +func New() *Schema { + s := &Schema{ + entryPointNames: make(map[string]string), + Types: make(map[string]NamedType), + Directives: make(map[string]*DirectiveDecl), + } + for n, t := range Meta.Types { + s.Types[n] = t + } + for n, d := range Meta.Directives { + s.Directives[n] = d + } + return s +} + +// Parse the schema string. +func (s *Schema) Parse(schemaString string) error { + l := common.NewLexer(schemaString) + + err := l.CatchSyntaxError(func() { parseSchema(s, l) }) + if err != nil { + return err + } + + for _, t := range s.Types { + if err := resolveNamedType(s, t); err != nil { + return err + } + } + for _, d := range s.Directives { + for _, arg := range d.Args { + t, err := common.ResolveType(arg.Type, s.Resolve) + if err != nil { + return err + } + arg.Type = t + } + } + + s.EntryPoints = make(map[string]NamedType) + for key, name := range s.entryPointNames { + t, ok := s.Types[name] + if !ok { + if !ok { + return errors.Errorf("type %q not found", name) + } + } + s.EntryPoints[key] = t + } + + for _, obj := range s.objects { + obj.Interfaces = make([]*Interface, len(obj.interfaceNames)) + for i, intfName := range obj.interfaceNames { + t, ok := s.Types[intfName] + if !ok { + return errors.Errorf("interface %q not found", intfName) + } + intf, ok := t.(*Interface) + if !ok { + return errors.Errorf("type %q is not an interface", intfName) + } + obj.Interfaces[i] = intf + intf.PossibleTypes = append(intf.PossibleTypes, obj) + } + } + + for _, union := range s.unions { + union.PossibleTypes = make([]*Object, len(union.typeNames)) + for i, name := range union.typeNames { + t, ok := s.Types[name] + if !ok { + return errors.Errorf("object type %q not found", name) + } + obj, ok := t.(*Object) + if !ok { + return errors.Errorf("type %q is not an object", name) + } + union.PossibleTypes[i] = obj + } + } + + for _, enum := range s.enums { + for _, value := range enum.Values { + if err := resolveDirectives(s, value.Directives); err != nil { + return err + } + } + } + + return nil +} + +func resolveNamedType(s *Schema, t NamedType) error { + switch t := t.(type) { + case *Object: + for _, f := range t.Fields { + if err := resolveField(s, f); err != nil { + return err + } + } + case *Interface: + for _, f := range t.Fields { + if err := resolveField(s, f); err != nil { + return err + } + } + case *InputObject: + if err := resolveInputObject(s, t.Values); err != nil { + return err + } + } + return nil +} + +func resolveField(s *Schema, f *Field) error { + t, err := common.ResolveType(f.Type, s.Resolve) + if err != nil { + return err + } + f.Type = t + if err := resolveDirectives(s, f.Directives); err != nil { + return err + } + return resolveInputObject(s, f.Args) +} + +func resolveDirectives(s *Schema, directives common.DirectiveList) error { + for _, d := range directives { + dirName := d.Name.Name + dd, ok := s.Directives[dirName] + if !ok { + return errors.Errorf("directive %q not found", dirName) + } + for _, arg := range d.Args { + if dd.Args.Get(arg.Name.Name) == nil { + return errors.Errorf("invalid argument %q for directive %q", arg.Name.Name, dirName) + } + } + for _, arg := range dd.Args { + if _, ok := d.Args.Get(arg.Name.Name); !ok { + d.Args = append(d.Args, common.Argument{Name: arg.Name, Value: arg.Default}) + } + } + } + return nil +} + +func resolveInputObject(s *Schema, values common.InputValueList) error { + for _, v := range values { + t, err := common.ResolveType(v.Type, s.Resolve) + if err != nil { + return err + } + v.Type = t + } + return nil +} + +func parseSchema(s *Schema, l *common.Lexer) { + l.Consume() + + for l.Peek() != scanner.EOF { + desc := l.DescComment() + switch x := l.ConsumeIdent(); x { + + case "schema": + l.ConsumeToken('{') + for l.Peek() != '}' { + name := l.ConsumeIdent() + l.ConsumeToken(':') + typ := l.ConsumeIdent() + s.entryPointNames[name] = typ + } + l.ConsumeToken('}') + + case "type": + obj := parseObjectDef(l) + obj.Desc = desc + s.Types[obj.Name] = obj + s.objects = append(s.objects, obj) + + case "interface": + iface := parseInterfaceDef(l) + iface.Desc = desc + s.Types[iface.Name] = iface + + case "union": + union := parseUnionDef(l) + union.Desc = desc + s.Types[union.Name] = union + s.unions = append(s.unions, union) + + case "enum": + enum := parseEnumDef(l) + enum.Desc = desc + s.Types[enum.Name] = enum + s.enums = append(s.enums, enum) + + case "input": + input := parseInputDef(l) + input.Desc = desc + s.Types[input.Name] = input + + case "scalar": + name := l.ConsumeIdent() + s.Types[name] = &Scalar{Name: name, Desc: desc} + + case "directive": + directive := parseDirectiveDef(l) + directive.Desc = desc + s.Directives[directive.Name] = directive + + default: + // TODO: Add support for type extensions. + l.SyntaxError(fmt.Sprintf(`unexpected %q, expecting "schema", "type", "enum", "interface", "union", "input", "scalar" or "directive"`, x)) + } + } +} + +func parseObjectDef(l *common.Lexer) *Object { + object := &Object{Name: l.ConsumeIdent()} + + if l.Peek() == scanner.Ident { + l.ConsumeKeyword("implements") + + for l.Peek() != '{' { + if l.Peek() == '&' { + l.ConsumeToken('&') + } + + object.interfaceNames = append(object.interfaceNames, l.ConsumeIdent()) + } + } + + l.ConsumeToken('{') + object.Fields = parseFieldsDef(l) + l.ConsumeToken('}') + + return object +} + +func parseInterfaceDef(l *common.Lexer) *Interface { + i := &Interface{Name: l.ConsumeIdent()} + + l.ConsumeToken('{') + i.Fields = parseFieldsDef(l) + l.ConsumeToken('}') + + return i +} + +func parseUnionDef(l *common.Lexer) *Union { + union := &Union{Name: l.ConsumeIdent()} + + l.ConsumeToken('=') + union.typeNames = []string{l.ConsumeIdent()} + for l.Peek() == '|' { + l.ConsumeToken('|') + union.typeNames = append(union.typeNames, l.ConsumeIdent()) + } + + return union +} + +func parseInputDef(l *common.Lexer) *InputObject { + i := &InputObject{} + i.Name = l.ConsumeIdent() + l.ConsumeToken('{') + for l.Peek() != '}' { + i.Values = append(i.Values, common.ParseInputValue(l)) + } + l.ConsumeToken('}') + return i +} + +func parseEnumDef(l *common.Lexer) *Enum { + enum := &Enum{Name: l.ConsumeIdent()} + + l.ConsumeToken('{') + for l.Peek() != '}' { + v := &EnumValue{ + Desc: l.DescComment(), + Name: l.ConsumeIdent(), + Directives: common.ParseDirectives(l), + } + + enum.Values = append(enum.Values, v) + } + l.ConsumeToken('}') + return enum +} + +func parseDirectiveDef(l *common.Lexer) *DirectiveDecl { + l.ConsumeToken('@') + d := &DirectiveDecl{Name: l.ConsumeIdent()} + + if l.Peek() == '(' { + l.ConsumeToken('(') + for l.Peek() != ')' { + v := common.ParseInputValue(l) + d.Args = append(d.Args, v) + } + l.ConsumeToken(')') + } + + l.ConsumeKeyword("on") + + for { + loc := l.ConsumeIdent() + d.Locs = append(d.Locs, loc) + if l.Peek() != '|' { + break + } + l.ConsumeToken('|') + } + return d +} + +func parseFieldsDef(l *common.Lexer) FieldList { + var fields FieldList + for l.Peek() != '}' { + f := &Field{} + f.Desc = l.DescComment() + f.Name = l.ConsumeIdent() + if l.Peek() == '(' { + l.ConsumeToken('(') + for l.Peek() != ')' { + f.Args = append(f.Args, common.ParseInputValue(l)) + } + l.ConsumeToken(')') + } + l.ConsumeToken(':') + f.Type = common.ParseType(l) + f.Directives = common.ParseDirectives(l) + fields = append(fields, f) + } + return fields +} diff --git a/vendor/github.com/graph-gophers/graphql-go/internal/validation/suggestion.go b/vendor/github.com/graph-gophers/graphql-go/internal/validation/suggestion.go new file mode 100644 index 0000000000..9702b5f529 --- /dev/null +++ b/vendor/github.com/graph-gophers/graphql-go/internal/validation/suggestion.go @@ -0,0 +1,71 @@ +package validation + +import ( + "fmt" + "sort" + "strconv" + "strings" +) + +func makeSuggestion(prefix string, options []string, input string) string { + var selected []string + distances := make(map[string]int) + for _, opt := range options { + distance := levenshteinDistance(input, opt) + threshold := max(len(input)/2, max(len(opt)/2, 1)) + if distance < threshold { + selected = append(selected, opt) + distances[opt] = distance + } + } + + if len(selected) == 0 { + return "" + } + sort.Slice(selected, func(i, j int) bool { + return distances[selected[i]] < distances[selected[j]] + }) + + parts := make([]string, len(selected)) + for i, opt := range selected { + parts[i] = strconv.Quote(opt) + } + if len(parts) > 1 { + parts[len(parts)-1] = "or " + parts[len(parts)-1] + } + return fmt.Sprintf(" %s %s?", prefix, strings.Join(parts, ", ")) +} + +func levenshteinDistance(s1, s2 string) int { + column := make([]int, len(s1)+1) + for y := range s1 { + column[y+1] = y + 1 + } + for x, rx := range s2 { + column[0] = x + 1 + lastdiag := x + for y, ry := range s1 { + olddiag := column[y+1] + if rx != ry { + lastdiag++ + } + column[y+1] = min(column[y+1]+1, min(column[y]+1, lastdiag)) + lastdiag = olddiag + } + } + return column[len(s1)] +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} diff --git a/vendor/github.com/graph-gophers/graphql-go/internal/validation/validation.go b/vendor/github.com/graph-gophers/graphql-go/internal/validation/validation.go new file mode 100644 index 0000000000..94ad5ca7fb --- /dev/null +++ b/vendor/github.com/graph-gophers/graphql-go/internal/validation/validation.go @@ -0,0 +1,909 @@ +package validation + +import ( + "fmt" + "math" + "reflect" + "strconv" + "strings" + "text/scanner" + + "github.com/graph-gophers/graphql-go/errors" + "github.com/graph-gophers/graphql-go/internal/common" + "github.com/graph-gophers/graphql-go/internal/query" + "github.com/graph-gophers/graphql-go/internal/schema" +) + +type varSet map[*common.InputValue]struct{} + +type selectionPair struct{ a, b query.Selection } + +type fieldInfo struct { + sf *schema.Field + parent schema.NamedType +} + +type context struct { + schema *schema.Schema + doc *query.Document + errs []*errors.QueryError + opErrs map[*query.Operation][]*errors.QueryError + usedVars map[*query.Operation]varSet + fieldMap map[*query.Field]fieldInfo + overlapValidated map[selectionPair]struct{} + maxDepth int +} + +func (c *context) addErr(loc errors.Location, rule string, format string, a ...interface{}) { + c.addErrMultiLoc([]errors.Location{loc}, rule, format, a...) +} + +func (c *context) addErrMultiLoc(locs []errors.Location, rule string, format string, a ...interface{}) { + c.errs = append(c.errs, &errors.QueryError{ + Message: fmt.Sprintf(format, a...), + Locations: locs, + Rule: rule, + }) +} + +type opContext struct { + *context + ops []*query.Operation +} + +func newContext(s *schema.Schema, doc *query.Document, maxDepth int) *context { + return &context{ + schema: s, + doc: doc, + opErrs: make(map[*query.Operation][]*errors.QueryError), + usedVars: make(map[*query.Operation]varSet), + fieldMap: make(map[*query.Field]fieldInfo), + overlapValidated: make(map[selectionPair]struct{}), + maxDepth: maxDepth, + } +} + +func Validate(s *schema.Schema, doc *query.Document, maxDepth int) []*errors.QueryError { + c := newContext(s, doc, maxDepth) + + opNames := make(nameSet) + fragUsedBy := make(map[*query.FragmentDecl][]*query.Operation) + for _, op := range doc.Operations { + c.usedVars[op] = make(varSet) + opc := &opContext{c, []*query.Operation{op}} + + // Check if max depth is exceeded, if it's set. If max depth is exceeded, + // don't continue to validate the document and exit early. + if validateMaxDepth(opc, op.Selections, 1) { + return c.errs + } + + if op.Name.Name == "" && len(doc.Operations) != 1 { + c.addErr(op.Loc, "LoneAnonymousOperation", "This anonymous operation must be the only defined operation.") + } + if op.Name.Name != "" { + validateName(c, opNames, op.Name, "UniqueOperationNames", "operation") + } + + validateDirectives(opc, string(op.Type), op.Directives) + + varNames := make(nameSet) + for _, v := range op.Vars { + validateName(c, varNames, v.Name, "UniqueVariableNames", "variable") + + t := resolveType(c, v.Type) + if !canBeInput(t) { + c.addErr(v.TypeLoc, "VariablesAreInputTypes", "Variable %q cannot be non-input type %q.", "$"+v.Name.Name, t) + } + + if v.Default != nil { + validateLiteral(opc, v.Default) + + if t != nil { + if nn, ok := t.(*common.NonNull); ok { + c.addErr(v.Default.Location(), "DefaultValuesOfCorrectType", "Variable %q of type %q is required and will not use the default value. Perhaps you meant to use type %q.", "$"+v.Name.Name, t, nn.OfType) + } + + if ok, reason := validateValueType(opc, v.Default, t); !ok { + c.addErr(v.Default.Location(), "DefaultValuesOfCorrectType", "Variable %q of type %q has invalid default value %s.\n%s", "$"+v.Name.Name, t, v.Default, reason) + } + } + } + } + + var entryPoint schema.NamedType + switch op.Type { + case query.Query: + entryPoint = s.EntryPoints["query"] + case query.Mutation: + entryPoint = s.EntryPoints["mutation"] + case query.Subscription: + entryPoint = s.EntryPoints["subscription"] + default: + panic("unreachable") + } + + validateSelectionSet(opc, op.Selections, entryPoint) + + fragUsed := make(map[*query.FragmentDecl]struct{}) + markUsedFragments(c, op.Selections, fragUsed) + for frag := range fragUsed { + fragUsedBy[frag] = append(fragUsedBy[frag], op) + } + } + + fragNames := make(nameSet) + fragVisited := make(map[*query.FragmentDecl]struct{}) + for _, frag := range doc.Fragments { + opc := &opContext{c, fragUsedBy[frag]} + + validateName(c, fragNames, frag.Name, "UniqueFragmentNames", "fragment") + validateDirectives(opc, "FRAGMENT_DEFINITION", frag.Directives) + + t := unwrapType(resolveType(c, &frag.On)) + // continue even if t is nil + if t != nil && !canBeFragment(t) { + c.addErr(frag.On.Loc, "FragmentsOnCompositeTypes", "Fragment %q cannot condition on non composite type %q.", frag.Name.Name, t) + continue + } + + validateSelectionSet(opc, frag.Selections, t) + + if _, ok := fragVisited[frag]; !ok { + detectFragmentCycle(c, frag.Selections, fragVisited, nil, map[string]int{frag.Name.Name: 0}) + } + } + + for _, frag := range doc.Fragments { + if len(fragUsedBy[frag]) == 0 { + c.addErr(frag.Loc, "NoUnusedFragments", "Fragment %q is never used.", frag.Name.Name) + } + } + + for _, op := range doc.Operations { + c.errs = append(c.errs, c.opErrs[op]...) + + opUsedVars := c.usedVars[op] + for _, v := range op.Vars { + if _, ok := opUsedVars[v]; !ok { + opSuffix := "" + if op.Name.Name != "" { + opSuffix = fmt.Sprintf(" in operation %q", op.Name.Name) + } + c.addErr(v.Loc, "NoUnusedVariables", "Variable %q is never used%s.", "$"+v.Name.Name, opSuffix) + } + } + } + + return c.errs +} + +// validates the query doesn't go deeper than maxDepth (if set). Returns whether +// or not query validated max depth to avoid excessive recursion. +func validateMaxDepth(c *opContext, sels []query.Selection, depth int) bool { + // maxDepth checking is turned off when maxDepth is 0 + if c.maxDepth == 0 { + return false + } + + exceededMaxDepth := false + + for _, sel := range sels { + switch sel := sel.(type) { + case *query.Field: + if depth > c.maxDepth { + exceededMaxDepth = true + c.addErr(sel.Alias.Loc, "MaxDepthExceeded", "Field %q has depth %d that exceeds max depth %d", sel.Name.Name, depth, c.maxDepth) + continue + } + exceededMaxDepth = exceededMaxDepth || validateMaxDepth(c, sel.Selections, depth+1) + case *query.InlineFragment: + // Depth is not checked because inline fragments resolve to other fields which are checked. + // Depth is not incremented because inline fragments have the same depth as neighboring fields + exceededMaxDepth = exceededMaxDepth || validateMaxDepth(c, sel.Selections, depth) + case *query.FragmentSpread: + // Depth is not checked because fragments resolve to other fields which are checked. + frag := c.doc.Fragments.Get(sel.Name.Name) + if frag == nil { + // In case of unknown fragment (invalid request), ignore max depth evaluation + c.addErr(sel.Loc, "MaxDepthEvaluationError", "Unknown fragment %q. Unable to evaluate depth.", sel.Name.Name) + continue + } + // Depth is not incremented because fragments have the same depth as surrounding fields + exceededMaxDepth = exceededMaxDepth || validateMaxDepth(c, frag.Selections, depth) + } + } + + return exceededMaxDepth +} + +func validateSelectionSet(c *opContext, sels []query.Selection, t schema.NamedType) { + for _, sel := range sels { + validateSelection(c, sel, t) + } + + for i, a := range sels { + for _, b := range sels[i+1:] { + c.validateOverlap(a, b, nil, nil) + } + } +} + +func validateSelection(c *opContext, sel query.Selection, t schema.NamedType) { + switch sel := sel.(type) { + case *query.Field: + validateDirectives(c, "FIELD", sel.Directives) + + fieldName := sel.Name.Name + var f *schema.Field + switch fieldName { + case "__typename": + f = &schema.Field{ + Name: "__typename", + Type: c.schema.Types["String"], + } + case "__schema": + f = &schema.Field{ + Name: "__schema", + Type: c.schema.Types["__Schema"], + } + case "__type": + f = &schema.Field{ + Name: "__type", + Args: common.InputValueList{ + &common.InputValue{ + Name: common.Ident{Name: "name"}, + Type: &common.NonNull{OfType: c.schema.Types["String"]}, + }, + }, + Type: c.schema.Types["__Type"], + } + default: + f = fields(t).Get(fieldName) + if f == nil && t != nil { + suggestion := makeSuggestion("Did you mean", fields(t).Names(), fieldName) + c.addErr(sel.Alias.Loc, "FieldsOnCorrectType", "Cannot query field %q on type %q.%s", fieldName, t, suggestion) + } + } + c.fieldMap[sel] = fieldInfo{sf: f, parent: t} + + validateArgumentLiterals(c, sel.Arguments) + if f != nil { + validateArgumentTypes(c, sel.Arguments, f.Args, sel.Alias.Loc, + func() string { return fmt.Sprintf("field %q of type %q", fieldName, t) }, + func() string { return fmt.Sprintf("Field %q", fieldName) }, + ) + } + + var ft common.Type + if f != nil { + ft = f.Type + sf := hasSubfields(ft) + if sf && sel.Selections == nil { + c.addErr(sel.Alias.Loc, "ScalarLeafs", "Field %q of type %q must have a selection of subfields. Did you mean \"%s { ... }\"?", fieldName, ft, fieldName) + } + if !sf && sel.Selections != nil { + c.addErr(sel.SelectionSetLoc, "ScalarLeafs", "Field %q must not have a selection since type %q has no subfields.", fieldName, ft) + } + } + if sel.Selections != nil { + validateSelectionSet(c, sel.Selections, unwrapType(ft)) + } + + case *query.InlineFragment: + validateDirectives(c, "INLINE_FRAGMENT", sel.Directives) + if sel.On.Name != "" { + fragTyp := unwrapType(resolveType(c.context, &sel.On)) + if fragTyp != nil && !compatible(t, fragTyp) { + c.addErr(sel.Loc, "PossibleFragmentSpreads", "Fragment cannot be spread here as objects of type %q can never be of type %q.", t, fragTyp) + } + t = fragTyp + // continue even if t is nil + } + if t != nil && !canBeFragment(t) { + c.addErr(sel.On.Loc, "FragmentsOnCompositeTypes", "Fragment cannot condition on non composite type %q.", t) + return + } + validateSelectionSet(c, sel.Selections, unwrapType(t)) + + case *query.FragmentSpread: + validateDirectives(c, "FRAGMENT_SPREAD", sel.Directives) + frag := c.doc.Fragments.Get(sel.Name.Name) + if frag == nil { + c.addErr(sel.Name.Loc, "KnownFragmentNames", "Unknown fragment %q.", sel.Name.Name) + return + } + fragTyp := c.schema.Types[frag.On.Name] + if !compatible(t, fragTyp) { + c.addErr(sel.Loc, "PossibleFragmentSpreads", "Fragment %q cannot be spread here as objects of type %q can never be of type %q.", frag.Name.Name, t, fragTyp) + } + + default: + panic("unreachable") + } +} + +func compatible(a, b common.Type) bool { + for _, pta := range possibleTypes(a) { + for _, ptb := range possibleTypes(b) { + if pta == ptb { + return true + } + } + } + return false +} + +func possibleTypes(t common.Type) []*schema.Object { + switch t := t.(type) { + case *schema.Object: + return []*schema.Object{t} + case *schema.Interface: + return t.PossibleTypes + case *schema.Union: + return t.PossibleTypes + default: + return nil + } +} + +func markUsedFragments(c *context, sels []query.Selection, fragUsed map[*query.FragmentDecl]struct{}) { + for _, sel := range sels { + switch sel := sel.(type) { + case *query.Field: + if sel.Selections != nil { + markUsedFragments(c, sel.Selections, fragUsed) + } + + case *query.InlineFragment: + markUsedFragments(c, sel.Selections, fragUsed) + + case *query.FragmentSpread: + frag := c.doc.Fragments.Get(sel.Name.Name) + if frag == nil { + return + } + + if _, ok := fragUsed[frag]; ok { + return + } + fragUsed[frag] = struct{}{} + markUsedFragments(c, frag.Selections, fragUsed) + + default: + panic("unreachable") + } + } +} + +func detectFragmentCycle(c *context, sels []query.Selection, fragVisited map[*query.FragmentDecl]struct{}, spreadPath []*query.FragmentSpread, spreadPathIndex map[string]int) { + for _, sel := range sels { + detectFragmentCycleSel(c, sel, fragVisited, spreadPath, spreadPathIndex) + } +} + +func detectFragmentCycleSel(c *context, sel query.Selection, fragVisited map[*query.FragmentDecl]struct{}, spreadPath []*query.FragmentSpread, spreadPathIndex map[string]int) { + switch sel := sel.(type) { + case *query.Field: + if sel.Selections != nil { + detectFragmentCycle(c, sel.Selections, fragVisited, spreadPath, spreadPathIndex) + } + + case *query.InlineFragment: + detectFragmentCycle(c, sel.Selections, fragVisited, spreadPath, spreadPathIndex) + + case *query.FragmentSpread: + frag := c.doc.Fragments.Get(sel.Name.Name) + if frag == nil { + return + } + + spreadPath = append(spreadPath, sel) + if i, ok := spreadPathIndex[frag.Name.Name]; ok { + cyclePath := spreadPath[i:] + via := "" + if len(cyclePath) > 1 { + names := make([]string, len(cyclePath)-1) + for i, frag := range cyclePath[:len(cyclePath)-1] { + names[i] = frag.Name.Name + } + via = " via " + strings.Join(names, ", ") + } + + locs := make([]errors.Location, len(cyclePath)) + for i, frag := range cyclePath { + locs[i] = frag.Loc + } + c.addErrMultiLoc(locs, "NoFragmentCycles", "Cannot spread fragment %q within itself%s.", frag.Name.Name, via) + return + } + + if _, ok := fragVisited[frag]; ok { + return + } + fragVisited[frag] = struct{}{} + + spreadPathIndex[frag.Name.Name] = len(spreadPath) + detectFragmentCycle(c, frag.Selections, fragVisited, spreadPath, spreadPathIndex) + delete(spreadPathIndex, frag.Name.Name) + + default: + panic("unreachable") + } +} + +func (c *context) validateOverlap(a, b query.Selection, reasons *[]string, locs *[]errors.Location) { + if a == b { + return + } + + if _, ok := c.overlapValidated[selectionPair{a, b}]; ok { + return + } + c.overlapValidated[selectionPair{a, b}] = struct{}{} + c.overlapValidated[selectionPair{b, a}] = struct{}{} + + switch a := a.(type) { + case *query.Field: + switch b := b.(type) { + case *query.Field: + if b.Alias.Loc.Before(a.Alias.Loc) { + a, b = b, a + } + if reasons2, locs2 := c.validateFieldOverlap(a, b); len(reasons2) != 0 { + locs2 = append(locs2, a.Alias.Loc, b.Alias.Loc) + if reasons == nil { + c.addErrMultiLoc(locs2, "OverlappingFieldsCanBeMerged", "Fields %q conflict because %s. Use different aliases on the fields to fetch both if this was intentional.", a.Alias.Name, strings.Join(reasons2, " and ")) + return + } + for _, r := range reasons2 { + *reasons = append(*reasons, fmt.Sprintf("subfields %q conflict because %s", a.Alias.Name, r)) + } + *locs = append(*locs, locs2...) + } + + case *query.InlineFragment: + for _, sel := range b.Selections { + c.validateOverlap(a, sel, reasons, locs) + } + + case *query.FragmentSpread: + if frag := c.doc.Fragments.Get(b.Name.Name); frag != nil { + for _, sel := range frag.Selections { + c.validateOverlap(a, sel, reasons, locs) + } + } + + default: + panic("unreachable") + } + + case *query.InlineFragment: + for _, sel := range a.Selections { + c.validateOverlap(sel, b, reasons, locs) + } + + case *query.FragmentSpread: + if frag := c.doc.Fragments.Get(a.Name.Name); frag != nil { + for _, sel := range frag.Selections { + c.validateOverlap(sel, b, reasons, locs) + } + } + + default: + panic("unreachable") + } +} + +func (c *context) validateFieldOverlap(a, b *query.Field) ([]string, []errors.Location) { + if a.Alias.Name != b.Alias.Name { + return nil, nil + } + + if asf := c.fieldMap[a].sf; asf != nil { + if bsf := c.fieldMap[b].sf; bsf != nil { + if !typesCompatible(asf.Type, bsf.Type) { + return []string{fmt.Sprintf("they return conflicting types %s and %s", asf.Type, bsf.Type)}, nil + } + } + } + + at := c.fieldMap[a].parent + bt := c.fieldMap[b].parent + if at == nil || bt == nil || at == bt { + if a.Name.Name != b.Name.Name { + return []string{fmt.Sprintf("%s and %s are different fields", a.Name.Name, b.Name.Name)}, nil + } + + if argumentsConflict(a.Arguments, b.Arguments) { + return []string{"they have differing arguments"}, nil + } + } + + var reasons []string + var locs []errors.Location + for _, a2 := range a.Selections { + for _, b2 := range b.Selections { + c.validateOverlap(a2, b2, &reasons, &locs) + } + } + return reasons, locs +} + +func argumentsConflict(a, b common.ArgumentList) bool { + if len(a) != len(b) { + return true + } + for _, argA := range a { + valB, ok := b.Get(argA.Name.Name) + if !ok || !reflect.DeepEqual(argA.Value.Value(nil), valB.Value(nil)) { + return true + } + } + return false +} + +func fields(t common.Type) schema.FieldList { + switch t := t.(type) { + case *schema.Object: + return t.Fields + case *schema.Interface: + return t.Fields + default: + return nil + } +} + +func unwrapType(t common.Type) schema.NamedType { + if t == nil { + return nil + } + for { + switch t2 := t.(type) { + case schema.NamedType: + return t2 + case *common.List: + t = t2.OfType + case *common.NonNull: + t = t2.OfType + default: + panic("unreachable") + } + } +} + +func resolveType(c *context, t common.Type) common.Type { + t2, err := common.ResolveType(t, c.schema.Resolve) + if err != nil { + c.errs = append(c.errs, err) + } + return t2 +} + +func validateDirectives(c *opContext, loc string, directives common.DirectiveList) { + directiveNames := make(nameSet) + for _, d := range directives { + dirName := d.Name.Name + validateNameCustomMsg(c.context, directiveNames, d.Name, "UniqueDirectivesPerLocation", func() string { + return fmt.Sprintf("The directive %q can only be used once at this location.", dirName) + }) + + validateArgumentLiterals(c, d.Args) + + dd, ok := c.schema.Directives[dirName] + if !ok { + c.addErr(d.Name.Loc, "KnownDirectives", "Unknown directive %q.", dirName) + continue + } + + locOK := false + for _, allowedLoc := range dd.Locs { + if loc == allowedLoc { + locOK = true + break + } + } + if !locOK { + c.addErr(d.Name.Loc, "KnownDirectives", "Directive %q may not be used on %s.", dirName, loc) + } + + validateArgumentTypes(c, d.Args, dd.Args, d.Name.Loc, + func() string { return fmt.Sprintf("directive %q", "@"+dirName) }, + func() string { return fmt.Sprintf("Directive %q", "@"+dirName) }, + ) + } +} + +type nameSet map[string]errors.Location + +func validateName(c *context, set nameSet, name common.Ident, rule string, kind string) { + validateNameCustomMsg(c, set, name, rule, func() string { + return fmt.Sprintf("There can be only one %s named %q.", kind, name.Name) + }) +} + +func validateNameCustomMsg(c *context, set nameSet, name common.Ident, rule string, msg func() string) { + if loc, ok := set[name.Name]; ok { + c.addErrMultiLoc([]errors.Location{loc, name.Loc}, rule, msg()) + return + } + set[name.Name] = name.Loc +} + +func validateArgumentTypes(c *opContext, args common.ArgumentList, argDecls common.InputValueList, loc errors.Location, owner1, owner2 func() string) { + for _, selArg := range args { + arg := argDecls.Get(selArg.Name.Name) + if arg == nil { + c.addErr(selArg.Name.Loc, "KnownArgumentNames", "Unknown argument %q on %s.", selArg.Name.Name, owner1()) + continue + } + value := selArg.Value + if ok, reason := validateValueType(c, value, arg.Type); !ok { + c.addErr(value.Location(), "ArgumentsOfCorrectType", "Argument %q has invalid value %s.\n%s", arg.Name.Name, value, reason) + } + } + for _, decl := range argDecls { + if _, ok := decl.Type.(*common.NonNull); ok { + if _, ok := args.Get(decl.Name.Name); !ok { + c.addErr(loc, "ProvidedNonNullArguments", "%s argument %q of type %q is required but not provided.", owner2(), decl.Name.Name, decl.Type) + } + } + } +} + +func validateArgumentLiterals(c *opContext, args common.ArgumentList) { + argNames := make(nameSet) + for _, arg := range args { + validateName(c.context, argNames, arg.Name, "UniqueArgumentNames", "argument") + validateLiteral(c, arg.Value) + } +} + +func validateLiteral(c *opContext, l common.Literal) { + switch l := l.(type) { + case *common.ObjectLit: + fieldNames := make(nameSet) + for _, f := range l.Fields { + validateName(c.context, fieldNames, f.Name, "UniqueInputFieldNames", "input field") + validateLiteral(c, f.Value) + } + case *common.ListLit: + for _, entry := range l.Entries { + validateLiteral(c, entry) + } + case *common.Variable: + for _, op := range c.ops { + v := op.Vars.Get(l.Name) + if v == nil { + byOp := "" + if op.Name.Name != "" { + byOp = fmt.Sprintf(" by operation %q", op.Name.Name) + } + c.opErrs[op] = append(c.opErrs[op], &errors.QueryError{ + Message: fmt.Sprintf("Variable %q is not defined%s.", "$"+l.Name, byOp), + Locations: []errors.Location{l.Loc, op.Loc}, + Rule: "NoUndefinedVariables", + }) + continue + } + c.usedVars[op][v] = struct{}{} + } + } +} + +func validateValueType(c *opContext, v common.Literal, t common.Type) (bool, string) { + if v, ok := v.(*common.Variable); ok { + for _, op := range c.ops { + if v2 := op.Vars.Get(v.Name); v2 != nil { + t2, err := common.ResolveType(v2.Type, c.schema.Resolve) + if _, ok := t2.(*common.NonNull); !ok && v2.Default != nil { + t2 = &common.NonNull{OfType: t2} + } + if err == nil && !typeCanBeUsedAs(t2, t) { + c.addErrMultiLoc([]errors.Location{v2.Loc, v.Loc}, "VariablesInAllowedPosition", "Variable %q of type %q used in position expecting type %q.", "$"+v.Name, t2, t) + } + } + } + return true, "" + } + + if nn, ok := t.(*common.NonNull); ok { + if isNull(v) { + return false, fmt.Sprintf("Expected %q, found null.", t) + } + t = nn.OfType + } + if isNull(v) { + return true, "" + } + + switch t := t.(type) { + case *schema.Scalar, *schema.Enum: + if lit, ok := v.(*common.BasicLit); ok { + if validateBasicLit(lit, t) { + return true, "" + } + } + + case *common.List: + list, ok := v.(*common.ListLit) + if !ok { + return validateValueType(c, v, t.OfType) // single value instead of list + } + for i, entry := range list.Entries { + if ok, reason := validateValueType(c, entry, t.OfType); !ok { + return false, fmt.Sprintf("In element #%d: %s", i, reason) + } + } + return true, "" + + case *schema.InputObject: + v, ok := v.(*common.ObjectLit) + if !ok { + return false, fmt.Sprintf("Expected %q, found not an object.", t) + } + for _, f := range v.Fields { + name := f.Name.Name + iv := t.Values.Get(name) + if iv == nil { + return false, fmt.Sprintf("In field %q: Unknown field.", name) + } + if ok, reason := validateValueType(c, f.Value, iv.Type); !ok { + return false, fmt.Sprintf("In field %q: %s", name, reason) + } + } + for _, iv := range t.Values { + found := false + for _, f := range v.Fields { + if f.Name.Name == iv.Name.Name { + found = true + break + } + } + if !found { + if _, ok := iv.Type.(*common.NonNull); ok && iv.Default == nil { + return false, fmt.Sprintf("In field %q: Expected %q, found null.", iv.Name.Name, iv.Type) + } + } + } + return true, "" + } + + return false, fmt.Sprintf("Expected type %q, found %s.", t, v) +} + +func validateBasicLit(v *common.BasicLit, t common.Type) bool { + switch t := t.(type) { + case *schema.Scalar: + switch t.Name { + case "Int": + if v.Type != scanner.Int { + return false + } + f, err := strconv.ParseFloat(v.Text, 64) + if err != nil { + panic(err) + } + return f >= math.MinInt32 && f <= math.MaxInt32 + case "Float": + return v.Type == scanner.Int || v.Type == scanner.Float + case "String": + return v.Type == scanner.String + case "Boolean": + return v.Type == scanner.Ident && (v.Text == "true" || v.Text == "false") + case "ID": + return v.Type == scanner.Int || v.Type == scanner.String + default: + //TODO: Type-check against expected type by Unmarshalling + return true + } + + case *schema.Enum: + if v.Type != scanner.Ident { + return false + } + for _, option := range t.Values { + if option.Name == v.Text { + return true + } + } + return false + } + + return false +} + +func canBeFragment(t common.Type) bool { + switch t.(type) { + case *schema.Object, *schema.Interface, *schema.Union: + return true + default: + return false + } +} + +func canBeInput(t common.Type) bool { + switch t := t.(type) { + case *schema.InputObject, *schema.Scalar, *schema.Enum: + return true + case *common.List: + return canBeInput(t.OfType) + case *common.NonNull: + return canBeInput(t.OfType) + default: + return false + } +} + +func hasSubfields(t common.Type) bool { + switch t := t.(type) { + case *schema.Object, *schema.Interface, *schema.Union: + return true + case *common.List: + return hasSubfields(t.OfType) + case *common.NonNull: + return hasSubfields(t.OfType) + default: + return false + } +} + +func isLeaf(t common.Type) bool { + switch t.(type) { + case *schema.Scalar, *schema.Enum: + return true + default: + return false + } +} + +func isNull(lit interface{}) bool { + _, ok := lit.(*common.NullLit) + return ok +} + +func typesCompatible(a, b common.Type) bool { + al, aIsList := a.(*common.List) + bl, bIsList := b.(*common.List) + if aIsList || bIsList { + return aIsList && bIsList && typesCompatible(al.OfType, bl.OfType) + } + + ann, aIsNN := a.(*common.NonNull) + bnn, bIsNN := b.(*common.NonNull) + if aIsNN || bIsNN { + return aIsNN && bIsNN && typesCompatible(ann.OfType, bnn.OfType) + } + + if isLeaf(a) || isLeaf(b) { + return a == b + } + + return true +} + +func typeCanBeUsedAs(t, as common.Type) bool { + nnT, okT := t.(*common.NonNull) + if okT { + t = nnT.OfType + } + + nnAs, okAs := as.(*common.NonNull) + if okAs { + as = nnAs.OfType + if !okT { + return false // nullable can not be used as non-null + } + } + + if t == as { + return true + } + + if lT, ok := t.(*common.List); ok { + if lAs, ok := as.(*common.List); ok { + return typeCanBeUsedAs(lT.OfType, lAs.OfType) + } + } + return false +} diff --git a/vendor/github.com/graph-gophers/graphql-go/introspection.go b/vendor/github.com/graph-gophers/graphql-go/introspection.go new file mode 100644 index 0000000000..7e515cf25f --- /dev/null +++ b/vendor/github.com/graph-gophers/graphql-go/introspection.go @@ -0,0 +1,117 @@ +package graphql + +import ( + "context" + "encoding/json" + + "github.com/graph-gophers/graphql-go/internal/exec/resolvable" + "github.com/graph-gophers/graphql-go/introspection" +) + +// Inspect allows inspection of the given schema. +func (s *Schema) Inspect() *introspection.Schema { + return introspection.WrapSchema(s.schema) +} + +// ToJSON encodes the schema in a JSON format used by tools like Relay. +func (s *Schema) ToJSON() ([]byte, error) { + result := s.exec(context.Background(), introspectionQuery, "", nil, &resolvable.Schema{ + Query: &resolvable.Object{}, + Schema: *s.schema, + }) + if len(result.Errors) != 0 { + panic(result.Errors[0]) + } + return json.MarshalIndent(result.Data, "", "\t") +} + +var introspectionQuery = ` + query { + __schema { + queryType { name } + mutationType { name } + subscriptionType { name } + types { + ...FullType + } + directives { + name + description + locations + args { + ...InputValue + } + } + } + } + fragment FullType on __Type { + kind + name + description + fields(includeDeprecated: true) { + name + description + args { + ...InputValue + } + type { + ...TypeRef + } + isDeprecated + deprecationReason + } + inputFields { + ...InputValue + } + interfaces { + ...TypeRef + } + enumValues(includeDeprecated: true) { + name + description + isDeprecated + deprecationReason + } + possibleTypes { + ...TypeRef + } + } + fragment InputValue on __InputValue { + name + description + type { ...TypeRef } + defaultValue + } + fragment TypeRef on __Type { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + } + } + } + } + } + } + } + } +` diff --git a/vendor/github.com/graph-gophers/graphql-go/introspection/introspection.go b/vendor/github.com/graph-gophers/graphql-go/introspection/introspection.go new file mode 100644 index 0000000000..2f4acad0a6 --- /dev/null +++ b/vendor/github.com/graph-gophers/graphql-go/introspection/introspection.go @@ -0,0 +1,313 @@ +package introspection + +import ( + "sort" + + "github.com/graph-gophers/graphql-go/internal/common" + "github.com/graph-gophers/graphql-go/internal/schema" +) + +type Schema struct { + schema *schema.Schema +} + +// WrapSchema is only used internally. +func WrapSchema(schema *schema.Schema) *Schema { + return &Schema{schema} +} + +func (r *Schema) Types() []*Type { + var names []string + for name := range r.schema.Types { + names = append(names, name) + } + sort.Strings(names) + + l := make([]*Type, len(names)) + for i, name := range names { + l[i] = &Type{r.schema.Types[name]} + } + return l +} + +func (r *Schema) Directives() []*Directive { + var names []string + for name := range r.schema.Directives { + names = append(names, name) + } + sort.Strings(names) + + l := make([]*Directive, len(names)) + for i, name := range names { + l[i] = &Directive{r.schema.Directives[name]} + } + return l +} + +func (r *Schema) QueryType() *Type { + t, ok := r.schema.EntryPoints["query"] + if !ok { + return nil + } + return &Type{t} +} + +func (r *Schema) MutationType() *Type { + t, ok := r.schema.EntryPoints["mutation"] + if !ok { + return nil + } + return &Type{t} +} + +func (r *Schema) SubscriptionType() *Type { + t, ok := r.schema.EntryPoints["subscription"] + if !ok { + return nil + } + return &Type{t} +} + +type Type struct { + typ common.Type +} + +// WrapType is only used internally. +func WrapType(typ common.Type) *Type { + return &Type{typ} +} + +func (r *Type) Kind() string { + return r.typ.Kind() +} + +func (r *Type) Name() *string { + if named, ok := r.typ.(schema.NamedType); ok { + name := named.TypeName() + return &name + } + return nil +} + +func (r *Type) Description() *string { + if named, ok := r.typ.(schema.NamedType); ok { + desc := named.Description() + if desc == "" { + return nil + } + return &desc + } + return nil +} + +func (r *Type) Fields(args *struct{ IncludeDeprecated bool }) *[]*Field { + var fields schema.FieldList + switch t := r.typ.(type) { + case *schema.Object: + fields = t.Fields + case *schema.Interface: + fields = t.Fields + default: + return nil + } + + var l []*Field + for _, f := range fields { + if d := f.Directives.Get("deprecated"); d == nil || args.IncludeDeprecated { + l = append(l, &Field{f}) + } + } + return &l +} + +func (r *Type) Interfaces() *[]*Type { + t, ok := r.typ.(*schema.Object) + if !ok { + return nil + } + + l := make([]*Type, len(t.Interfaces)) + for i, intf := range t.Interfaces { + l[i] = &Type{intf} + } + return &l +} + +func (r *Type) PossibleTypes() *[]*Type { + var possibleTypes []*schema.Object + switch t := r.typ.(type) { + case *schema.Interface: + possibleTypes = t.PossibleTypes + case *schema.Union: + possibleTypes = t.PossibleTypes + default: + return nil + } + + l := make([]*Type, len(possibleTypes)) + for i, intf := range possibleTypes { + l[i] = &Type{intf} + } + return &l +} + +func (r *Type) EnumValues(args *struct{ IncludeDeprecated bool }) *[]*EnumValue { + t, ok := r.typ.(*schema.Enum) + if !ok { + return nil + } + + var l []*EnumValue + for _, v := range t.Values { + if d := v.Directives.Get("deprecated"); d == nil || args.IncludeDeprecated { + l = append(l, &EnumValue{v}) + } + } + return &l +} + +func (r *Type) InputFields() *[]*InputValue { + t, ok := r.typ.(*schema.InputObject) + if !ok { + return nil + } + + l := make([]*InputValue, len(t.Values)) + for i, v := range t.Values { + l[i] = &InputValue{v} + } + return &l +} + +func (r *Type) OfType() *Type { + switch t := r.typ.(type) { + case *common.List: + return &Type{t.OfType} + case *common.NonNull: + return &Type{t.OfType} + default: + return nil + } +} + +type Field struct { + field *schema.Field +} + +func (r *Field) Name() string { + return r.field.Name +} + +func (r *Field) Description() *string { + if r.field.Desc == "" { + return nil + } + return &r.field.Desc +} + +func (r *Field) Args() []*InputValue { + l := make([]*InputValue, len(r.field.Args)) + for i, v := range r.field.Args { + l[i] = &InputValue{v} + } + return l +} + +func (r *Field) Type() *Type { + return &Type{r.field.Type} +} + +func (r *Field) IsDeprecated() bool { + return r.field.Directives.Get("deprecated") != nil +} + +func (r *Field) DeprecationReason() *string { + d := r.field.Directives.Get("deprecated") + if d == nil { + return nil + } + reason := d.Args.MustGet("reason").Value(nil).(string) + return &reason +} + +type InputValue struct { + value *common.InputValue +} + +func (r *InputValue) Name() string { + return r.value.Name.Name +} + +func (r *InputValue) Description() *string { + if r.value.Desc == "" { + return nil + } + return &r.value.Desc +} + +func (r *InputValue) Type() *Type { + return &Type{r.value.Type} +} + +func (r *InputValue) DefaultValue() *string { + if r.value.Default == nil { + return nil + } + s := r.value.Default.String() + return &s +} + +type EnumValue struct { + value *schema.EnumValue +} + +func (r *EnumValue) Name() string { + return r.value.Name +} + +func (r *EnumValue) Description() *string { + if r.value.Desc == "" { + return nil + } + return &r.value.Desc +} + +func (r *EnumValue) IsDeprecated() bool { + return r.value.Directives.Get("deprecated") != nil +} + +func (r *EnumValue) DeprecationReason() *string { + d := r.value.Directives.Get("deprecated") + if d == nil { + return nil + } + reason := d.Args.MustGet("reason").Value(nil).(string) + return &reason +} + +type Directive struct { + directive *schema.DirectiveDecl +} + +func (r *Directive) Name() string { + return r.directive.Name +} + +func (r *Directive) Description() *string { + if r.directive.Desc == "" { + return nil + } + return &r.directive.Desc +} + +func (r *Directive) Locations() []string { + return r.directive.Locs +} + +func (r *Directive) Args() []*InputValue { + l := make([]*InputValue, len(r.directive.Args)) + for i, v := range r.directive.Args { + l[i] = &InputValue{v} + } + return l +} diff --git a/vendor/github.com/graph-gophers/graphql-go/log/log.go b/vendor/github.com/graph-gophers/graphql-go/log/log.go new file mode 100644 index 0000000000..25569af7ca --- /dev/null +++ b/vendor/github.com/graph-gophers/graphql-go/log/log.go @@ -0,0 +1,23 @@ +package log + +import ( + "context" + "log" + "runtime" +) + +// Logger is the interface used to log panics that occur during query execution. It is settable via graphql.ParseSchema +type Logger interface { + LogPanic(ctx context.Context, value interface{}) +} + +// DefaultLogger is the default logger used to log panics that occur during query execution +type DefaultLogger struct{} + +// LogPanic is used to log recovered panic values that occur during query execution +func (l *DefaultLogger) LogPanic(_ context.Context, value interface{}) { + const size = 64 << 10 + buf := make([]byte, size) + buf = buf[:runtime.Stack(buf, false)] + log.Printf("graphql: panic occurred: %v\n%s", value, buf) +} diff --git a/vendor/github.com/graph-gophers/graphql-go/relay/relay.go b/vendor/github.com/graph-gophers/graphql-go/relay/relay.go new file mode 100644 index 0000000000..78e4dfdd51 --- /dev/null +++ b/vendor/github.com/graph-gophers/graphql-go/relay/relay.go @@ -0,0 +1,70 @@ +package relay + +import ( + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "net/http" + "strings" + + graphql "github.com/graph-gophers/graphql-go" +) + +func MarshalID(kind string, spec interface{}) graphql.ID { + d, err := json.Marshal(spec) + if err != nil { + panic(fmt.Errorf("relay.MarshalID: %s", err)) + } + return graphql.ID(base64.URLEncoding.EncodeToString(append([]byte(kind+":"), d...))) +} + +func UnmarshalKind(id graphql.ID) string { + s, err := base64.URLEncoding.DecodeString(string(id)) + if err != nil { + return "" + } + i := strings.IndexByte(string(s), ':') + if i == -1 { + return "" + } + return string(s[:i]) +} + +func UnmarshalSpec(id graphql.ID, v interface{}) error { + s, err := base64.URLEncoding.DecodeString(string(id)) + if err != nil { + return err + } + i := strings.IndexByte(string(s), ':') + if i == -1 { + return errors.New("invalid graphql.ID") + } + return json.Unmarshal([]byte(s[i+1:]), v) +} + +type Handler struct { + Schema *graphql.Schema +} + +func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + var params struct { + Query string `json:"query"` + OperationName string `json:"operationName"` + Variables map[string]interface{} `json:"variables"` + } + if err := json.NewDecoder(r.Body).Decode(¶ms); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + response := h.Schema.Exec(r.Context(), params.Query, params.OperationName, params.Variables) + responseJSON, err := json.Marshal(response) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json") + w.Write(responseJSON) +} diff --git a/vendor/github.com/graph-gophers/graphql-go/time.go b/vendor/github.com/graph-gophers/graphql-go/time.go new file mode 100644 index 0000000000..829c502275 --- /dev/null +++ b/vendor/github.com/graph-gophers/graphql-go/time.go @@ -0,0 +1,51 @@ +package graphql + +import ( + "encoding/json" + "fmt" + "time" +) + +// Time is a custom GraphQL type to represent an instant in time. It has to be added to a schema +// via "scalar Time" since it is not a predeclared GraphQL type like "ID". +type Time struct { + time.Time +} + +// ImplementsGraphQLType maps this custom Go type +// to the graphql scalar type in the schema. +func (Time) ImplementsGraphQLType(name string) bool { + return name == "Time" +} + +// UnmarshalGraphQL is a custom unmarshaler for Time +// +// This function will be called whenever you use the +// time scalar as an input +func (t *Time) UnmarshalGraphQL(input interface{}) error { + switch input := input.(type) { + case time.Time: + t.Time = input + return nil + case string: + var err error + t.Time, err = time.Parse(time.RFC3339, input) + return err + case int: + t.Time = time.Unix(int64(input), 0) + return nil + case float64: + t.Time = time.Unix(int64(input), 0) + return nil + default: + return fmt.Errorf("wrong type") + } +} + +// MarshalJSON is a custom marshaler for Time +// +// This function will be called whenever you +// query for fields that use the Time type +func (t Time) MarshalJSON() ([]byte, error) { + return json.Marshal(t.Time) +} diff --git a/vendor/github.com/graph-gophers/graphql-go/trace/trace.go b/vendor/github.com/graph-gophers/graphql-go/trace/trace.go new file mode 100644 index 0000000000..68b856ae71 --- /dev/null +++ b/vendor/github.com/graph-gophers/graphql-go/trace/trace.go @@ -0,0 +1,80 @@ +package trace + +import ( + "context" + "fmt" + + "github.com/graph-gophers/graphql-go/errors" + "github.com/graph-gophers/graphql-go/introspection" + opentracing "github.com/opentracing/opentracing-go" + "github.com/opentracing/opentracing-go/ext" + "github.com/opentracing/opentracing-go/log" +) + +type TraceQueryFinishFunc func([]*errors.QueryError) +type TraceFieldFinishFunc func(*errors.QueryError) + +type Tracer interface { + TraceQuery(ctx context.Context, queryString string, operationName string, variables map[string]interface{}, varTypes map[string]*introspection.Type) (context.Context, TraceQueryFinishFunc) + TraceField(ctx context.Context, label, typeName, fieldName string, trivial bool, args map[string]interface{}) (context.Context, TraceFieldFinishFunc) +} + +type OpenTracingTracer struct{} + +func (OpenTracingTracer) TraceQuery(ctx context.Context, queryString string, operationName string, variables map[string]interface{}, varTypes map[string]*introspection.Type) (context.Context, TraceQueryFinishFunc) { + span, spanCtx := opentracing.StartSpanFromContext(ctx, "GraphQL request") + span.SetTag("graphql.query", queryString) + + if operationName != "" { + span.SetTag("graphql.operationName", operationName) + } + + if len(variables) != 0 { + span.LogFields(log.Object("graphql.variables", variables)) + } + + return spanCtx, func(errs []*errors.QueryError) { + if len(errs) > 0 { + msg := errs[0].Error() + if len(errs) > 1 { + msg += fmt.Sprintf(" (and %d more errors)", len(errs)-1) + } + ext.Error.Set(span, true) + span.SetTag("graphql.error", msg) + } + span.Finish() + } +} + +func (OpenTracingTracer) TraceField(ctx context.Context, label, typeName, fieldName string, trivial bool, args map[string]interface{}) (context.Context, TraceFieldFinishFunc) { + if trivial { + return ctx, noop + } + + span, spanCtx := opentracing.StartSpanFromContext(ctx, label) + span.SetTag("graphql.type", typeName) + span.SetTag("graphql.field", fieldName) + for name, value := range args { + span.SetTag("graphql.args."+name, value) + } + + return spanCtx, func(err *errors.QueryError) { + if err != nil { + ext.Error.Set(span, true) + span.SetTag("graphql.error", err.Error()) + } + span.Finish() + } +} + +func noop(*errors.QueryError) {} + +type NoopTracer struct{} + +func (NoopTracer) TraceQuery(ctx context.Context, queryString string, operationName string, variables map[string]interface{}, varTypes map[string]*introspection.Type) (context.Context, TraceQueryFinishFunc) { + return ctx, func(errs []*errors.QueryError) {} +} + +func (NoopTracer) TraceField(ctx context.Context, label, typeName, fieldName string, trivial bool, args map[string]interface{}) (context.Context, TraceFieldFinishFunc) { + return ctx, func(err *errors.QueryError) {} +} diff --git a/vendor/github.com/graph-gophers/graphql-go/trace/validation_trace.go b/vendor/github.com/graph-gophers/graphql-go/trace/validation_trace.go new file mode 100644 index 0000000000..e223f0fdbc --- /dev/null +++ b/vendor/github.com/graph-gophers/graphql-go/trace/validation_trace.go @@ -0,0 +1,17 @@ +package trace + +import ( + "github.com/graph-gophers/graphql-go/errors" +) + +type TraceValidationFinishFunc = TraceQueryFinishFunc + +type ValidationTracer interface { + TraceValidation() TraceValidationFinishFunc +} + +type NoopValidationTracer struct{} + +func (NoopValidationTracer) TraceValidation() TraceValidationFinishFunc { + return func(errs []*errors.QueryError) {} +} diff --git a/vendor/gopkg.in/fatih/set.v0/LICENSE.md b/vendor/github.com/influxdata/influxdb/LICENSE similarity index 96% rename from vendor/gopkg.in/fatih/set.v0/LICENSE.md rename to vendor/github.com/influxdata/influxdb/LICENSE index 25fdaf639d..63cef79ba6 100644 --- a/vendor/gopkg.in/fatih/set.v0/LICENSE.md +++ b/vendor/github.com/influxdata/influxdb/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013 Fatih Arslan +Copyright (c) 2013-2016 Errplane Inc. 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 diff --git a/vendor/github.com/influxdata/influxdb/LICENSE_OF_DEPENDENCIES.md b/vendor/github.com/influxdata/influxdb/LICENSE_OF_DEPENDENCIES.md new file mode 100644 index 0000000000..ea6fc69f30 --- /dev/null +++ b/vendor/github.com/influxdata/influxdb/LICENSE_OF_DEPENDENCIES.md @@ -0,0 +1,62 @@ +- # List +- bootstrap 3.3.5 [MIT LICENSE](https://github.com/twbs/bootstrap/blob/master/LICENSE) +- collectd.org [ISC LICENSE](https://github.com/collectd/go-collectd/blob/master/LICENSE) +- github.com/BurntSushi/toml [MIT LICENSE](https://github.com/BurntSushi/toml/blob/master/COPYING) +- github.com/RoaringBitmap/roaring [APACHE LICENSE](https://github.com/RoaringBitmap/roaring/blob/master/LICENSE) +- github.com/beorn7/perks [MIT LICENSE](https://github.com/beorn7/perks/blob/master/LICENSE) +- github.com/bmizerany/pat [MIT LICENSE](https://github.com/bmizerany/pat#license) +- github.com/boltdb/bolt [MIT LICENSE](https://github.com/boltdb/bolt/blob/master/LICENSE) +- github.com/cespare/xxhash [MIT LICENSE](https://github.com/cespare/xxhash/blob/master/LICENSE.txt) +- github.com/clarkduvall/hyperloglog [MIT LICENSE](https://github.com/clarkduvall/hyperloglog/blob/master/LICENSE) +- github.com/davecgh/go-spew/spew [ISC LICENSE](https://github.com/davecgh/go-spew/blob/master/LICENSE) +- github.com/dgrijalva/jwt-go [MIT LICENSE](https://github.com/dgrijalva/jwt-go/blob/master/LICENSE) +- github.com/dgryski/go-bits [MIT LICENSE](https://github.com/dgryski/go-bits/blob/master/LICENSE) +- github.com/dgryski/go-bitstream [MIT LICENSE](https://github.com/dgryski/go-bitstream/blob/master/LICENSE) +- github.com/glycerine/go-unsnap-stream [MIT LICENSE](https://github.com/glycerine/go-unsnap-stream/blob/master/LICENSE) +- github.com/gogo/protobuf/proto [BSD LICENSE](https://github.com/gogo/protobuf/blob/master/LICENSE) +- github.com/golang/protobuf [BSD LICENSE](https://github.com/golang/protobuf/blob/master/LICENSE) +- github.com/golang/snappy [BSD LICENSE](https://github.com/golang/snappy/blob/master/LICENSE) +- github.com/google/go-cmp [BSD LICENSE](https://github.com/google/go-cmp/blob/master/LICENSE) +- github.com/influxdata/influxql [MIT LICENSE](https://github.com/influxdata/influxql/blob/master/LICENSE) +- github.com/influxdata/usage-client [MIT LICENSE](https://github.com/influxdata/usage-client/blob/master/LICENSE.txt) +- github.com/influxdata/yamux [MOZILLA PUBLIC LICENSE](https://github.com/influxdata/yamux/blob/master/LICENSE) +- github.com/influxdata/yarpc [MIT LICENSE](https://github.com/influxdata/yarpc/blob/master/LICENSE) +- github.com/jsternberg/zap-logfmt [MIT LICENSE](https://github.com/jsternberg/zap-logfmt/blob/master/LICENSE) +- github.com/jwilder/encoding [MIT LICENSE](https://github.com/jwilder/encoding/blob/master/LICENSE) +- github.com/mattn/go-isatty [MIT LICENSE](https://github.com/mattn/go-isatty/blob/master/LICENSE) +- github.com/matttproud/golang_protobuf_extensions [APACHE LICENSE](https://github.com/matttproud/golang_protobuf_extensions/blob/master/LICENSE) +- github.com/opentracing/opentracing-go [MIT LICENSE](https://github.com/opentracing/opentracing-go/blob/master/LICENSE) +- github.com/paulbellamy/ratecounter [MIT LICENSE](https://github.com/paulbellamy/ratecounter/blob/master/LICENSE) +- github.com/peterh/liner [MIT LICENSE](https://github.com/peterh/liner/blob/master/COPYING) +- github.com/philhofer/fwd [MIT LICENSE](https://github.com/philhofer/fwd/blob/master/LICENSE.md) +- github.com/prometheus/client_golang [MIT LICENSE](https://github.com/prometheus/client_golang/blob/master/LICENSE) +- github.com/prometheus/client_model [MIT LICENSE](https://github.com/prometheus/client_model/blob/master/LICENSE) +- github.com/prometheus/common [APACHE LICENSE](https://github.com/prometheus/common/blob/master/LICENSE) +- github.com/prometheus/procfs [APACHE LICENSE](https://github.com/prometheus/procfs/blob/master/LICENSE) +- github.com/rakyll/statik [APACHE LICENSE](https://github.com/rakyll/statik/blob/master/LICENSE) +- github.com/retailnext/hllpp [BSD LICENSE](https://github.com/retailnext/hllpp/blob/master/LICENSE) +- github.com/tinylib/msgp [MIT LICENSE](https://github.com/tinylib/msgp/blob/master/LICENSE) +- go.uber.org/atomic [MIT LICENSE](https://github.com/uber-go/atomic/blob/master/LICENSE.txt) +- go.uber.org/multierr [MIT LICENSE](https://github.com/uber-go/multierr/blob/master/LICENSE.txt) +- go.uber.org/zap [MIT LICENSE](https://github.com/uber-go/zap/blob/master/LICENSE.txt) +- golang.org/x/crypto [BSD LICENSE](https://github.com/golang/crypto/blob/master/LICENSE) +- golang.org/x/net [BSD LICENSE](https://github.com/golang/net/blob/master/LICENSE) +- golang.org/x/sys [BSD LICENSE](https://github.com/golang/sys/blob/master/LICENSE) +- golang.org/x/text [BSD LICENSE](https://github.com/golang/text/blob/master/LICENSE) +- golang.org/x/time [BSD LICENSE](https://github.com/golang/time/blob/master/LICENSE) +- jquery 2.1.4 [MIT LICENSE](https://github.com/jquery/jquery/blob/master/LICENSE.txt) +- github.com/xlab/treeprint [MIT LICENSE](https://github.com/xlab/treeprint/blob/master/LICENSE) + + + + + + + + + + + + + + diff --git a/vendor/github.com/influxdata/influxdb/client/README.md b/vendor/github.com/influxdata/influxdb/client/README.md new file mode 100644 index 0000000000..773a111228 --- /dev/null +++ b/vendor/github.com/influxdata/influxdb/client/README.md @@ -0,0 +1,306 @@ +# InfluxDB Client + +[![GoDoc](https://godoc.org/github.com/influxdata/influxdb?status.svg)](http://godoc.org/github.com/influxdata/influxdb/client/v2) + +## Description + +**NOTE:** The Go client library now has a "v2" version, with the old version +being deprecated. The new version can be imported at +`import "github.com/influxdata/influxdb/client/v2"`. It is not backwards-compatible. + +A Go client library written and maintained by the **InfluxDB** team. +This package provides convenience functions to read and write time series data. +It uses the HTTP protocol to communicate with your **InfluxDB** cluster. + + +## Getting Started + +### Connecting To Your Database + +Connecting to an **InfluxDB** database is straightforward. You will need a host +name, a port and the cluster user credentials if applicable. The default port is +8086. You can customize these settings to your specific installation via the +**InfluxDB** configuration file. + +Though not necessary for experimentation, you may want to create a new user +and authenticate the connection to your database. + +For more information please check out the +[Admin Docs](https://docs.influxdata.com/influxdb/latest/administration/). + +For the impatient, you can create a new admin user _bubba_ by firing off the +[InfluxDB CLI](https://github.com/influxdata/influxdb/blob/master/cmd/influx/main.go). + +```shell +influx +> create user bubba with password 'bumblebeetuna' +> grant all privileges to bubba +``` + +And now for good measure set the credentials in you shell environment. +In the example below we will use $INFLUX_USER and $INFLUX_PWD + +Now with the administrivia out of the way, let's connect to our database. + +NOTE: If you've opted out of creating a user, you can omit Username and Password in +the configuration below. + +```go +package main + +import ( + "log" + "time" + + "github.com/influxdata/influxdb/client/v2" +) + +const ( + MyDB = "square_holes" + username = "bubba" + password = "bumblebeetuna" +) + + +func main() { + // Create a new HTTPClient + c, err := client.NewHTTPClient(client.HTTPConfig{ + Addr: "http://localhost:8086", + Username: username, + Password: password, + }) + if err != nil { + log.Fatal(err) + } + + // Create a new point batch + bp, err := client.NewBatchPoints(client.BatchPointsConfig{ + Database: MyDB, + Precision: "s", + }) + if err != nil { + log.Fatal(err) + } + + // Create a point and add to batch + tags := map[string]string{"cpu": "cpu-total"} + fields := map[string]interface{}{ + "idle": 10.1, + "system": 53.3, + "user": 46.6, + } + + pt, err := client.NewPoint("cpu_usage", tags, fields, time.Now()) + if err != nil { + log.Fatal(err) + } + bp.AddPoint(pt) + + // Write the batch + if err := c.Write(bp); err != nil { + log.Fatal(err) + } +} + +``` + +### Inserting Data + +Time series data aka *points* are written to the database using batch inserts. +The mechanism is to create one or more points and then create a batch aka +*batch points* and write these to a given database and series. A series is a +combination of a measurement (time/values) and a set of tags. + +In this sample we will create a batch of a 1,000 points. Each point has a time and +a single value as well as 2 tags indicating a shape and color. We write these points +to a database called _square_holes_ using a measurement named _shapes_. + +NOTE: You can specify a RetentionPolicy as part of the batch points. If not +provided InfluxDB will use the database _default_ retention policy. + +```go + +func writePoints(clnt client.Client) { + sampleSize := 1000 + + bp, err := client.NewBatchPoints(client.BatchPointsConfig{ + Database: "systemstats", + Precision: "us", + }) + if err != nil { + log.Fatal(err) + } + + rand.Seed(time.Now().UnixNano()) + for i := 0; i < sampleSize; i++ { + regions := []string{"us-west1", "us-west2", "us-west3", "us-east1"} + tags := map[string]string{ + "cpu": "cpu-total", + "host": fmt.Sprintf("host%d", rand.Intn(1000)), + "region": regions[rand.Intn(len(regions))], + } + + idle := rand.Float64() * 100.0 + fields := map[string]interface{}{ + "idle": idle, + "busy": 100.0 - idle, + } + + pt, err := client.NewPoint( + "cpu_usage", + tags, + fields, + time.Now(), + ) + if err != nil { + log.Fatal(err) + } + bp.AddPoint(pt) + } + + if err := clnt.Write(bp); err != nil { + log.Fatal(err) + } +} +``` + +#### Uint64 Support + +The `uint64` data type is supported if your server is version `1.4.0` or +greater. To write a data point as an unsigned integer, you must insert +the point as `uint64`. You cannot use `uint` or any of the other +derivatives because previous versions of the client have supported +writing those types as an integer. + +### Querying Data + +One nice advantage of using **InfluxDB** the ability to query your data using familiar +SQL constructs. In this example we can create a convenience function to query the database +as follows: + +```go +// queryDB convenience function to query the database +func queryDB(clnt client.Client, cmd string) (res []client.Result, err error) { + q := client.Query{ + Command: cmd, + Database: MyDB, + } + if response, err := clnt.Query(q); err == nil { + if response.Error() != nil { + return res, response.Error() + } + res = response.Results + } else { + return res, err + } + return res, nil +} +``` + +#### Creating a Database + +```go +_, err := queryDB(clnt, fmt.Sprintf("CREATE DATABASE %s", MyDB)) +if err != nil { + log.Fatal(err) +} +``` + +#### Count Records + +```go +q := fmt.Sprintf("SELECT count(%s) FROM %s", "value", MyMeasurement) +res, err := queryDB(clnt, q) +if err != nil { + log.Fatal(err) +} +count := res[0].Series[0].Values[0][1] +log.Printf("Found a total of %v records\n", count) +``` + +#### Find the last 10 _shapes_ records + +```go +q := fmt.Sprintf("SELECT * FROM %s LIMIT %d", MyMeasurement, 10) +res, err = queryDB(clnt, q) +if err != nil { + log.Fatal(err) +} + +for i, row := range res[0].Series[0].Values { + t, err := time.Parse(time.RFC3339, row[0].(string)) + if err != nil { + log.Fatal(err) + } + val := row[1].(string) + log.Printf("[%2d] %s: %s\n", i, t.Format(time.Stamp), val) +} +``` + +### Using the UDP Client + +The **InfluxDB** client also supports writing over UDP. + +```go +func WriteUDP() { + // Make client + c, err := client.NewUDPClient("localhost:8089") + if err != nil { + panic(err.Error()) + } + + // Create a new point batch + bp, _ := client.NewBatchPoints(client.BatchPointsConfig{ + Precision: "s", + }) + + // Create a point and add to batch + tags := map[string]string{"cpu": "cpu-total"} + fields := map[string]interface{}{ + "idle": 10.1, + "system": 53.3, + "user": 46.6, + } + pt, err := client.NewPoint("cpu_usage", tags, fields, time.Now()) + if err != nil { + panic(err.Error()) + } + bp.AddPoint(pt) + + // Write the batch + c.Write(bp) +} +``` + +### Point Splitting + +The UDP client now supports splitting single points that exceed the configured +payload size. The logic for processing each point is listed here, starting with +an empty payload. + +1. If adding the point to the current (non-empty) payload would exceed the + configured size, send the current payload. Otherwise, add it to the current + payload. +1. If the point is smaller than the configured size, add it to the payload. +1. If the point has no timestamp, just try to send the entire point as a single + UDP payload, and process the next point. +1. Since the point has a timestamp, re-use the existing measurement name, + tagset, and timestamp and create multiple new points by splitting up the + fields. The per-point length will be kept close to the configured size, + staying under it if possible. This does mean that one large field, maybe a + long string, could be sent as a larger-than-configured payload. + +The above logic attempts to respect configured payload sizes, but not sacrifice +any data integrity. Points without a timestamp can't be split, as that may +cause fields to have differing timestamps when processed by the server. + +## Go Docs + +Please refer to +[http://godoc.org/github.com/influxdata/influxdb/client/v2](http://godoc.org/github.com/influxdata/influxdb/client/v2) +for documentation. + +## See Also + +You can also examine how the client library is used by the +[InfluxDB CLI](https://github.com/influxdata/influxdb/blob/master/cmd/influx/main.go). diff --git a/vendor/github.com/influxdata/influxdb/client/influxdb.go b/vendor/github.com/influxdata/influxdb/client/influxdb.go new file mode 100644 index 0000000000..98d362d50a --- /dev/null +++ b/vendor/github.com/influxdata/influxdb/client/influxdb.go @@ -0,0 +1,840 @@ +// Package client implements a now-deprecated client for InfluxDB; +// use github.com/influxdata/influxdb/client/v2 instead. +package client // import "github.com/influxdata/influxdb/client" + +import ( + "bytes" + "context" + "crypto/tls" + "encoding/json" + "errors" + "fmt" + "io" + "io/ioutil" + "net" + "net/http" + "net/url" + "strconv" + "strings" + "time" + + "github.com/influxdata/influxdb/models" +) + +const ( + // DefaultHost is the default host used to connect to an InfluxDB instance + DefaultHost = "localhost" + + // DefaultPort is the default port used to connect to an InfluxDB instance + DefaultPort = 8086 + + // DefaultTimeout is the default connection timeout used to connect to an InfluxDB instance + DefaultTimeout = 0 +) + +// Query is used to send a command to the server. Both Command and Database are required. +type Query struct { + Command string + Database string + + // Chunked tells the server to send back chunked responses. This places + // less load on the server by sending back chunks of the response rather + // than waiting for the entire response all at once. + Chunked bool + + // ChunkSize sets the maximum number of rows that will be returned per + // chunk. Chunks are either divided based on their series or if they hit + // the chunk size limit. + // + // Chunked must be set to true for this option to be used. + ChunkSize int +} + +// ParseConnectionString will parse a string to create a valid connection URL +func ParseConnectionString(path string, ssl bool) (url.URL, error) { + var host string + var port int + + h, p, err := net.SplitHostPort(path) + if err != nil { + if path == "" { + host = DefaultHost + } else { + host = path + } + // If they didn't specify a port, always use the default port + port = DefaultPort + } else { + host = h + port, err = strconv.Atoi(p) + if err != nil { + return url.URL{}, fmt.Errorf("invalid port number %q: %s\n", path, err) + } + } + + u := url.URL{ + Scheme: "http", + } + if ssl { + u.Scheme = "https" + } + + u.Host = net.JoinHostPort(host, strconv.Itoa(port)) + + return u, nil +} + +// Config is used to specify what server to connect to. +// URL: The URL of the server connecting to. +// Username/Password are optional. They will be passed via basic auth if provided. +// UserAgent: If not provided, will default "InfluxDBClient", +// Timeout: If not provided, will default to 0 (no timeout) +type Config struct { + URL url.URL + UnixSocket string + Username string + Password string + UserAgent string + Timeout time.Duration + Precision string + WriteConsistency string + UnsafeSsl bool +} + +// NewConfig will create a config to be used in connecting to the client +func NewConfig() Config { + return Config{ + Timeout: DefaultTimeout, + } +} + +// Client is used to make calls to the server. +type Client struct { + url url.URL + unixSocket string + username string + password string + httpClient *http.Client + userAgent string + precision string +} + +const ( + // ConsistencyOne requires at least one data node acknowledged a write. + ConsistencyOne = "one" + + // ConsistencyAll requires all data nodes to acknowledge a write. + ConsistencyAll = "all" + + // ConsistencyQuorum requires a quorum of data nodes to acknowledge a write. + ConsistencyQuorum = "quorum" + + // ConsistencyAny allows for hinted hand off, potentially no write happened yet. + ConsistencyAny = "any" +) + +// NewClient will instantiate and return a connected client to issue commands to the server. +func NewClient(c Config) (*Client, error) { + tlsConfig := &tls.Config{ + InsecureSkipVerify: c.UnsafeSsl, + } + + tr := &http.Transport{ + TLSClientConfig: tlsConfig, + } + + if c.UnixSocket != "" { + // No need for compression in local communications. + tr.DisableCompression = true + + tr.DialContext = func(_ context.Context, _, _ string) (net.Conn, error) { + return net.Dial("unix", c.UnixSocket) + } + } + + client := Client{ + url: c.URL, + unixSocket: c.UnixSocket, + username: c.Username, + password: c.Password, + httpClient: &http.Client{Timeout: c.Timeout, Transport: tr}, + userAgent: c.UserAgent, + precision: c.Precision, + } + if client.userAgent == "" { + client.userAgent = "InfluxDBClient" + } + return &client, nil +} + +// SetAuth will update the username and passwords +func (c *Client) SetAuth(u, p string) { + c.username = u + c.password = p +} + +// SetPrecision will update the precision +func (c *Client) SetPrecision(precision string) { + c.precision = precision +} + +// Query sends a command to the server and returns the Response +func (c *Client) Query(q Query) (*Response, error) { + return c.QueryContext(context.Background(), q) +} + +// QueryContext sends a command to the server and returns the Response +// It uses a context that can be cancelled by the command line client +func (c *Client) QueryContext(ctx context.Context, q Query) (*Response, error) { + u := c.url + + u.Path = "query" + values := u.Query() + values.Set("q", q.Command) + values.Set("db", q.Database) + if q.Chunked { + values.Set("chunked", "true") + if q.ChunkSize > 0 { + values.Set("chunk_size", strconv.Itoa(q.ChunkSize)) + } + } + if c.precision != "" { + values.Set("epoch", c.precision) + } + u.RawQuery = values.Encode() + + req, err := http.NewRequest("POST", u.String(), nil) + if err != nil { + return nil, err + } + req.Header.Set("User-Agent", c.userAgent) + if c.username != "" { + req.SetBasicAuth(c.username, c.password) + } + + req = req.WithContext(ctx) + + resp, err := c.httpClient.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var response Response + if q.Chunked { + cr := NewChunkedResponse(resp.Body) + for { + r, err := cr.NextResponse() + if err != nil { + // If we got an error while decoding the response, send that back. + return nil, err + } + + if r == nil { + break + } + + response.Results = append(response.Results, r.Results...) + if r.Err != nil { + response.Err = r.Err + break + } + } + } else { + dec := json.NewDecoder(resp.Body) + dec.UseNumber() + if err := dec.Decode(&response); err != nil { + // Ignore EOF errors if we got an invalid status code. + if !(err == io.EOF && resp.StatusCode != http.StatusOK) { + return nil, err + } + } + } + + // If we don't have an error in our json response, and didn't get StatusOK, + // then send back an error. + if resp.StatusCode != http.StatusOK && response.Error() == nil { + return &response, fmt.Errorf("received status code %d from server", resp.StatusCode) + } + return &response, nil +} + +// Write takes BatchPoints and allows for writing of multiple points with defaults +// If successful, error is nil and Response is nil +// If an error occurs, Response may contain additional information if populated. +func (c *Client) Write(bp BatchPoints) (*Response, error) { + u := c.url + u.Path = "write" + + var b bytes.Buffer + for _, p := range bp.Points { + err := checkPointTypes(p) + if err != nil { + return nil, err + } + if p.Raw != "" { + if _, err := b.WriteString(p.Raw); err != nil { + return nil, err + } + } else { + for k, v := range bp.Tags { + if p.Tags == nil { + p.Tags = make(map[string]string, len(bp.Tags)) + } + p.Tags[k] = v + } + + if _, err := b.WriteString(p.MarshalString()); err != nil { + return nil, err + } + } + + if err := b.WriteByte('\n'); err != nil { + return nil, err + } + } + + req, err := http.NewRequest("POST", u.String(), &b) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "") + req.Header.Set("User-Agent", c.userAgent) + if c.username != "" { + req.SetBasicAuth(c.username, c.password) + } + + precision := bp.Precision + if precision == "" { + precision = "ns" + } + + params := req.URL.Query() + params.Set("db", bp.Database) + params.Set("rp", bp.RetentionPolicy) + params.Set("precision", precision) + params.Set("consistency", bp.WriteConsistency) + req.URL.RawQuery = params.Encode() + + resp, err := c.httpClient.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var response Response + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + if resp.StatusCode != http.StatusNoContent && resp.StatusCode != http.StatusOK { + var err = fmt.Errorf(string(body)) + response.Err = err + return &response, err + } + + return nil, nil +} + +// WriteLineProtocol takes a string with line returns to delimit each write +// If successful, error is nil and Response is nil +// If an error occurs, Response may contain additional information if populated. +func (c *Client) WriteLineProtocol(data, database, retentionPolicy, precision, writeConsistency string) (*Response, error) { + u := c.url + u.Path = "write" + + r := strings.NewReader(data) + + req, err := http.NewRequest("POST", u.String(), r) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "") + req.Header.Set("User-Agent", c.userAgent) + if c.username != "" { + req.SetBasicAuth(c.username, c.password) + } + params := req.URL.Query() + params.Set("db", database) + params.Set("rp", retentionPolicy) + params.Set("precision", precision) + params.Set("consistency", writeConsistency) + req.URL.RawQuery = params.Encode() + + resp, err := c.httpClient.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var response Response + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + if resp.StatusCode != http.StatusNoContent && resp.StatusCode != http.StatusOK { + err := fmt.Errorf(string(body)) + response.Err = err + return &response, err + } + + return nil, nil +} + +// Ping will check to see if the server is up +// Ping returns how long the request took, the version of the server it connected to, and an error if one occurred. +func (c *Client) Ping() (time.Duration, string, error) { + now := time.Now() + u := c.url + u.Path = "ping" + + req, err := http.NewRequest("GET", u.String(), nil) + if err != nil { + return 0, "", err + } + req.Header.Set("User-Agent", c.userAgent) + if c.username != "" { + req.SetBasicAuth(c.username, c.password) + } + + resp, err := c.httpClient.Do(req) + if err != nil { + return 0, "", err + } + defer resp.Body.Close() + + version := resp.Header.Get("X-Influxdb-Version") + return time.Since(now), version, nil +} + +// Structs + +// Message represents a user message. +type Message struct { + Level string `json:"level,omitempty"` + Text string `json:"text,omitempty"` +} + +// Result represents a resultset returned from a single statement. +type Result struct { + Series []models.Row + Messages []*Message + Err error +} + +// MarshalJSON encodes the result into JSON. +func (r *Result) MarshalJSON() ([]byte, error) { + // Define a struct that outputs "error" as a string. + var o struct { + Series []models.Row `json:"series,omitempty"` + Messages []*Message `json:"messages,omitempty"` + Err string `json:"error,omitempty"` + } + + // Copy fields to output struct. + o.Series = r.Series + o.Messages = r.Messages + if r.Err != nil { + o.Err = r.Err.Error() + } + + return json.Marshal(&o) +} + +// UnmarshalJSON decodes the data into the Result struct +func (r *Result) UnmarshalJSON(b []byte) error { + var o struct { + Series []models.Row `json:"series,omitempty"` + Messages []*Message `json:"messages,omitempty"` + Err string `json:"error,omitempty"` + } + + dec := json.NewDecoder(bytes.NewBuffer(b)) + dec.UseNumber() + err := dec.Decode(&o) + if err != nil { + return err + } + r.Series = o.Series + r.Messages = o.Messages + if o.Err != "" { + r.Err = errors.New(o.Err) + } + return nil +} + +// Response represents a list of statement results. +type Response struct { + Results []Result + Err error +} + +// MarshalJSON encodes the response into JSON. +func (r *Response) MarshalJSON() ([]byte, error) { + // Define a struct that outputs "error" as a string. + var o struct { + Results []Result `json:"results,omitempty"` + Err string `json:"error,omitempty"` + } + + // Copy fields to output struct. + o.Results = r.Results + if r.Err != nil { + o.Err = r.Err.Error() + } + + return json.Marshal(&o) +} + +// UnmarshalJSON decodes the data into the Response struct +func (r *Response) UnmarshalJSON(b []byte) error { + var o struct { + Results []Result `json:"results,omitempty"` + Err string `json:"error,omitempty"` + } + + dec := json.NewDecoder(bytes.NewBuffer(b)) + dec.UseNumber() + err := dec.Decode(&o) + if err != nil { + return err + } + r.Results = o.Results + if o.Err != "" { + r.Err = errors.New(o.Err) + } + return nil +} + +// Error returns the first error from any statement. +// Returns nil if no errors occurred on any statements. +func (r *Response) Error() error { + if r.Err != nil { + return r.Err + } + for _, result := range r.Results { + if result.Err != nil { + return result.Err + } + } + return nil +} + +// duplexReader reads responses and writes it to another writer while +// satisfying the reader interface. +type duplexReader struct { + r io.Reader + w io.Writer +} + +func (r *duplexReader) Read(p []byte) (n int, err error) { + n, err = r.r.Read(p) + if err == nil { + r.w.Write(p[:n]) + } + return n, err +} + +// ChunkedResponse represents a response from the server that +// uses chunking to stream the output. +type ChunkedResponse struct { + dec *json.Decoder + duplex *duplexReader + buf bytes.Buffer +} + +// NewChunkedResponse reads a stream and produces responses from the stream. +func NewChunkedResponse(r io.Reader) *ChunkedResponse { + resp := &ChunkedResponse{} + resp.duplex = &duplexReader{r: r, w: &resp.buf} + resp.dec = json.NewDecoder(resp.duplex) + resp.dec.UseNumber() + return resp +} + +// NextResponse reads the next line of the stream and returns a response. +func (r *ChunkedResponse) NextResponse() (*Response, error) { + var response Response + if err := r.dec.Decode(&response); err != nil { + if err == io.EOF { + return nil, nil + } + // A decoding error happened. This probably means the server crashed + // and sent a last-ditch error message to us. Ensure we have read the + // entirety of the connection to get any remaining error text. + io.Copy(ioutil.Discard, r.duplex) + return nil, errors.New(strings.TrimSpace(r.buf.String())) + } + r.buf.Reset() + return &response, nil +} + +// Point defines the fields that will be written to the database +// Measurement, Time, and Fields are required +// Precision can be specified if the time is in epoch format (integer). +// Valid values for Precision are n, u, ms, s, m, and h +type Point struct { + Measurement string + Tags map[string]string + Time time.Time + Fields map[string]interface{} + Precision string + Raw string +} + +// MarshalJSON will format the time in RFC3339Nano +// Precision is also ignored as it is only used for writing, not reading +// Or another way to say it is we always send back in nanosecond precision +func (p *Point) MarshalJSON() ([]byte, error) { + point := struct { + Measurement string `json:"measurement,omitempty"` + Tags map[string]string `json:"tags,omitempty"` + Time string `json:"time,omitempty"` + Fields map[string]interface{} `json:"fields,omitempty"` + Precision string `json:"precision,omitempty"` + }{ + Measurement: p.Measurement, + Tags: p.Tags, + Fields: p.Fields, + Precision: p.Precision, + } + // Let it omit empty if it's really zero + if !p.Time.IsZero() { + point.Time = p.Time.UTC().Format(time.RFC3339Nano) + } + return json.Marshal(&point) +} + +// MarshalString renders string representation of a Point with specified +// precision. The default precision is nanoseconds. +func (p *Point) MarshalString() string { + pt, err := models.NewPoint(p.Measurement, models.NewTags(p.Tags), p.Fields, p.Time) + if err != nil { + return "# ERROR: " + err.Error() + " " + p.Measurement + } + if p.Precision == "" || p.Precision == "ns" || p.Precision == "n" { + return pt.String() + } + return pt.PrecisionString(p.Precision) +} + +// UnmarshalJSON decodes the data into the Point struct +func (p *Point) UnmarshalJSON(b []byte) error { + var normal struct { + Measurement string `json:"measurement"` + Tags map[string]string `json:"tags"` + Time time.Time `json:"time"` + Precision string `json:"precision"` + Fields map[string]interface{} `json:"fields"` + } + var epoch struct { + Measurement string `json:"measurement"` + Tags map[string]string `json:"tags"` + Time *int64 `json:"time"` + Precision string `json:"precision"` + Fields map[string]interface{} `json:"fields"` + } + + if err := func() error { + var err error + dec := json.NewDecoder(bytes.NewBuffer(b)) + dec.UseNumber() + if err = dec.Decode(&epoch); err != nil { + return err + } + // Convert from epoch to time.Time, but only if Time + // was actually set. + var ts time.Time + if epoch.Time != nil { + ts, err = EpochToTime(*epoch.Time, epoch.Precision) + if err != nil { + return err + } + } + p.Measurement = epoch.Measurement + p.Tags = epoch.Tags + p.Time = ts + p.Precision = epoch.Precision + p.Fields = normalizeFields(epoch.Fields) + return nil + }(); err == nil { + return nil + } + + dec := json.NewDecoder(bytes.NewBuffer(b)) + dec.UseNumber() + if err := dec.Decode(&normal); err != nil { + return err + } + normal.Time = SetPrecision(normal.Time, normal.Precision) + p.Measurement = normal.Measurement + p.Tags = normal.Tags + p.Time = normal.Time + p.Precision = normal.Precision + p.Fields = normalizeFields(normal.Fields) + + return nil +} + +// Remove any notion of json.Number +func normalizeFields(fields map[string]interface{}) map[string]interface{} { + newFields := map[string]interface{}{} + + for k, v := range fields { + switch v := v.(type) { + case json.Number: + jv, e := v.Float64() + if e != nil { + panic(fmt.Sprintf("unable to convert json.Number to float64: %s", e)) + } + newFields[k] = jv + default: + newFields[k] = v + } + } + return newFields +} + +// BatchPoints is used to send batched data in a single write. +// Database and Points are required +// If no retention policy is specified, it will use the databases default retention policy. +// If tags are specified, they will be "merged" with all points. If a point already has that tag, it will be ignored. +// If time is specified, it will be applied to any point with an empty time. +// Precision can be specified if the time is in epoch format (integer). +// Valid values for Precision are n, u, ms, s, m, and h +type BatchPoints struct { + Points []Point `json:"points,omitempty"` + Database string `json:"database,omitempty"` + RetentionPolicy string `json:"retentionPolicy,omitempty"` + Tags map[string]string `json:"tags,omitempty"` + Time time.Time `json:"time,omitempty"` + Precision string `json:"precision,omitempty"` + WriteConsistency string `json:"-"` +} + +// UnmarshalJSON decodes the data into the BatchPoints struct +func (bp *BatchPoints) UnmarshalJSON(b []byte) error { + var normal struct { + Points []Point `json:"points"` + Database string `json:"database"` + RetentionPolicy string `json:"retentionPolicy"` + Tags map[string]string `json:"tags"` + Time time.Time `json:"time"` + Precision string `json:"precision"` + } + var epoch struct { + Points []Point `json:"points"` + Database string `json:"database"` + RetentionPolicy string `json:"retentionPolicy"` + Tags map[string]string `json:"tags"` + Time *int64 `json:"time"` + Precision string `json:"precision"` + } + + if err := func() error { + var err error + if err = json.Unmarshal(b, &epoch); err != nil { + return err + } + // Convert from epoch to time.Time + var ts time.Time + if epoch.Time != nil { + ts, err = EpochToTime(*epoch.Time, epoch.Precision) + if err != nil { + return err + } + } + bp.Points = epoch.Points + bp.Database = epoch.Database + bp.RetentionPolicy = epoch.RetentionPolicy + bp.Tags = epoch.Tags + bp.Time = ts + bp.Precision = epoch.Precision + return nil + }(); err == nil { + return nil + } + + if err := json.Unmarshal(b, &normal); err != nil { + return err + } + normal.Time = SetPrecision(normal.Time, normal.Precision) + bp.Points = normal.Points + bp.Database = normal.Database + bp.RetentionPolicy = normal.RetentionPolicy + bp.Tags = normal.Tags + bp.Time = normal.Time + bp.Precision = normal.Precision + + return nil +} + +// utility functions + +// Addr provides the current url as a string of the server the client is connected to. +func (c *Client) Addr() string { + if c.unixSocket != "" { + return c.unixSocket + } + return c.url.String() +} + +// checkPointTypes ensures no unsupported types are submitted to influxdb, returning error if they are found. +func checkPointTypes(p Point) error { + for _, v := range p.Fields { + switch v.(type) { + case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64, bool, string, nil: + return nil + default: + return fmt.Errorf("unsupported point type: %T", v) + } + } + return nil +} + +// helper functions + +// EpochToTime takes a unix epoch time and uses precision to return back a time.Time +func EpochToTime(epoch int64, precision string) (time.Time, error) { + if precision == "" { + precision = "s" + } + var t time.Time + switch precision { + case "h": + t = time.Unix(0, epoch*int64(time.Hour)) + case "m": + t = time.Unix(0, epoch*int64(time.Minute)) + case "s": + t = time.Unix(0, epoch*int64(time.Second)) + case "ms": + t = time.Unix(0, epoch*int64(time.Millisecond)) + case "u": + t = time.Unix(0, epoch*int64(time.Microsecond)) + case "n": + t = time.Unix(0, epoch) + default: + return time.Time{}, fmt.Errorf("Unknown precision %q", precision) + } + return t, nil +} + +// SetPrecision will round a time to the specified precision +func SetPrecision(t time.Time, precision string) time.Time { + switch precision { + case "n": + case "u": + return t.Round(time.Microsecond) + case "ms": + return t.Round(time.Millisecond) + case "s": + return t.Round(time.Second) + case "m": + return t.Round(time.Minute) + case "h": + return t.Round(time.Hour) + } + return t +} diff --git a/vendor/github.com/influxdata/influxdb/client/v2/client.go b/vendor/github.com/influxdata/influxdb/client/v2/client.go new file mode 100644 index 0000000000..77d44f2b34 --- /dev/null +++ b/vendor/github.com/influxdata/influxdb/client/v2/client.go @@ -0,0 +1,635 @@ +// Package client (v2) is the current official Go client for InfluxDB. +package client // import "github.com/influxdata/influxdb/client/v2" + +import ( + "bytes" + "crypto/tls" + "encoding/json" + "errors" + "fmt" + "io" + "io/ioutil" + "mime" + "net/http" + "net/url" + "strconv" + "strings" + "time" + + "github.com/influxdata/influxdb/models" +) + +// HTTPConfig is the config data needed to create an HTTP Client. +type HTTPConfig struct { + // Addr should be of the form "http://host:port" + // or "http://[ipv6-host%zone]:port". + Addr string + + // Username is the influxdb username, optional. + Username string + + // Password is the influxdb password, optional. + Password string + + // UserAgent is the http User Agent, defaults to "InfluxDBClient". + UserAgent string + + // Timeout for influxdb writes, defaults to no timeout. + Timeout time.Duration + + // InsecureSkipVerify gets passed to the http client, if true, it will + // skip https certificate verification. Defaults to false. + InsecureSkipVerify bool + + // TLSConfig allows the user to set their own TLS config for the HTTP + // Client. If set, this option overrides InsecureSkipVerify. + TLSConfig *tls.Config +} + +// BatchPointsConfig is the config data needed to create an instance of the BatchPoints struct. +type BatchPointsConfig struct { + // Precision is the write precision of the points, defaults to "ns". + Precision string + + // Database is the database to write points to. + Database string + + // RetentionPolicy is the retention policy of the points. + RetentionPolicy string + + // Write consistency is the number of servers required to confirm write. + WriteConsistency string +} + +// Client is a client interface for writing & querying the database. +type Client interface { + // Ping checks that status of cluster, and will always return 0 time and no + // error for UDP clients. + Ping(timeout time.Duration) (time.Duration, string, error) + + // Write takes a BatchPoints object and writes all Points to InfluxDB. + Write(bp BatchPoints) error + + // Query makes an InfluxDB Query on the database. This will fail if using + // the UDP client. + Query(q Query) (*Response, error) + + // Close releases any resources a Client may be using. + Close() error +} + +// NewHTTPClient returns a new Client from the provided config. +// Client is safe for concurrent use by multiple goroutines. +func NewHTTPClient(conf HTTPConfig) (Client, error) { + if conf.UserAgent == "" { + conf.UserAgent = "InfluxDBClient" + } + + u, err := url.Parse(conf.Addr) + if err != nil { + return nil, err + } else if u.Scheme != "http" && u.Scheme != "https" { + m := fmt.Sprintf("Unsupported protocol scheme: %s, your address"+ + " must start with http:// or https://", u.Scheme) + return nil, errors.New(m) + } + + tr := &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: conf.InsecureSkipVerify, + }, + } + if conf.TLSConfig != nil { + tr.TLSClientConfig = conf.TLSConfig + } + return &client{ + url: *u, + username: conf.Username, + password: conf.Password, + useragent: conf.UserAgent, + httpClient: &http.Client{ + Timeout: conf.Timeout, + Transport: tr, + }, + transport: tr, + }, nil +} + +// Ping will check to see if the server is up with an optional timeout on waiting for leader. +// Ping returns how long the request took, the version of the server it connected to, and an error if one occurred. +func (c *client) Ping(timeout time.Duration) (time.Duration, string, error) { + now := time.Now() + u := c.url + u.Path = "ping" + + req, err := http.NewRequest("GET", u.String(), nil) + if err != nil { + return 0, "", err + } + + req.Header.Set("User-Agent", c.useragent) + + if c.username != "" { + req.SetBasicAuth(c.username, c.password) + } + + if timeout > 0 { + params := req.URL.Query() + params.Set("wait_for_leader", fmt.Sprintf("%.0fs", timeout.Seconds())) + req.URL.RawQuery = params.Encode() + } + + resp, err := c.httpClient.Do(req) + if err != nil { + return 0, "", err + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return 0, "", err + } + + if resp.StatusCode != http.StatusNoContent { + var err = fmt.Errorf(string(body)) + return 0, "", err + } + + version := resp.Header.Get("X-Influxdb-Version") + return time.Since(now), version, nil +} + +// Close releases the client's resources. +func (c *client) Close() error { + c.transport.CloseIdleConnections() + return nil +} + +// client is safe for concurrent use as the fields are all read-only +// once the client is instantiated. +type client struct { + // N.B - if url.UserInfo is accessed in future modifications to the + // methods on client, you will need to syncronise access to url. + url url.URL + username string + password string + useragent string + httpClient *http.Client + transport *http.Transport +} + +// BatchPoints is an interface into a batched grouping of points to write into +// InfluxDB together. BatchPoints is NOT thread-safe, you must create a separate +// batch for each goroutine. +type BatchPoints interface { + // AddPoint adds the given point to the Batch of points. + AddPoint(p *Point) + // AddPoints adds the given points to the Batch of points. + AddPoints(ps []*Point) + // Points lists the points in the Batch. + Points() []*Point + + // Precision returns the currently set precision of this Batch. + Precision() string + // SetPrecision sets the precision of this batch. + SetPrecision(s string) error + + // Database returns the currently set database of this Batch. + Database() string + // SetDatabase sets the database of this Batch. + SetDatabase(s string) + + // WriteConsistency returns the currently set write consistency of this Batch. + WriteConsistency() string + // SetWriteConsistency sets the write consistency of this Batch. + SetWriteConsistency(s string) + + // RetentionPolicy returns the currently set retention policy of this Batch. + RetentionPolicy() string + // SetRetentionPolicy sets the retention policy of this Batch. + SetRetentionPolicy(s string) +} + +// NewBatchPoints returns a BatchPoints interface based on the given config. +func NewBatchPoints(conf BatchPointsConfig) (BatchPoints, error) { + if conf.Precision == "" { + conf.Precision = "ns" + } + if _, err := time.ParseDuration("1" + conf.Precision); err != nil { + return nil, err + } + bp := &batchpoints{ + database: conf.Database, + precision: conf.Precision, + retentionPolicy: conf.RetentionPolicy, + writeConsistency: conf.WriteConsistency, + } + return bp, nil +} + +type batchpoints struct { + points []*Point + database string + precision string + retentionPolicy string + writeConsistency string +} + +func (bp *batchpoints) AddPoint(p *Point) { + bp.points = append(bp.points, p) +} + +func (bp *batchpoints) AddPoints(ps []*Point) { + bp.points = append(bp.points, ps...) +} + +func (bp *batchpoints) Points() []*Point { + return bp.points +} + +func (bp *batchpoints) Precision() string { + return bp.precision +} + +func (bp *batchpoints) Database() string { + return bp.database +} + +func (bp *batchpoints) WriteConsistency() string { + return bp.writeConsistency +} + +func (bp *batchpoints) RetentionPolicy() string { + return bp.retentionPolicy +} + +func (bp *batchpoints) SetPrecision(p string) error { + if _, err := time.ParseDuration("1" + p); err != nil { + return err + } + bp.precision = p + return nil +} + +func (bp *batchpoints) SetDatabase(db string) { + bp.database = db +} + +func (bp *batchpoints) SetWriteConsistency(wc string) { + bp.writeConsistency = wc +} + +func (bp *batchpoints) SetRetentionPolicy(rp string) { + bp.retentionPolicy = rp +} + +// Point represents a single data point. +type Point struct { + pt models.Point +} + +// NewPoint returns a point with the given timestamp. If a timestamp is not +// given, then data is sent to the database without a timestamp, in which case +// the server will assign local time upon reception. NOTE: it is recommended to +// send data with a timestamp. +func NewPoint( + name string, + tags map[string]string, + fields map[string]interface{}, + t ...time.Time, +) (*Point, error) { + var T time.Time + if len(t) > 0 { + T = t[0] + } + + pt, err := models.NewPoint(name, models.NewTags(tags), fields, T) + if err != nil { + return nil, err + } + return &Point{ + pt: pt, + }, nil +} + +// String returns a line-protocol string of the Point. +func (p *Point) String() string { + return p.pt.String() +} + +// PrecisionString returns a line-protocol string of the Point, +// with the timestamp formatted for the given precision. +func (p *Point) PrecisionString(precison string) string { + return p.pt.PrecisionString(precison) +} + +// Name returns the measurement name of the point. +func (p *Point) Name() string { + return string(p.pt.Name()) +} + +// Tags returns the tags associated with the point. +func (p *Point) Tags() map[string]string { + return p.pt.Tags().Map() +} + +// Time return the timestamp for the point. +func (p *Point) Time() time.Time { + return p.pt.Time() +} + +// UnixNano returns timestamp of the point in nanoseconds since Unix epoch. +func (p *Point) UnixNano() int64 { + return p.pt.UnixNano() +} + +// Fields returns the fields for the point. +func (p *Point) Fields() (map[string]interface{}, error) { + return p.pt.Fields() +} + +// NewPointFrom returns a point from the provided models.Point. +func NewPointFrom(pt models.Point) *Point { + return &Point{pt: pt} +} + +func (c *client) Write(bp BatchPoints) error { + var b bytes.Buffer + + for _, p := range bp.Points() { + if _, err := b.WriteString(p.pt.PrecisionString(bp.Precision())); err != nil { + return err + } + + if err := b.WriteByte('\n'); err != nil { + return err + } + } + + u := c.url + u.Path = "write" + req, err := http.NewRequest("POST", u.String(), &b) + if err != nil { + return err + } + req.Header.Set("Content-Type", "") + req.Header.Set("User-Agent", c.useragent) + if c.username != "" { + req.SetBasicAuth(c.username, c.password) + } + + params := req.URL.Query() + params.Set("db", bp.Database()) + params.Set("rp", bp.RetentionPolicy()) + params.Set("precision", bp.Precision()) + params.Set("consistency", bp.WriteConsistency()) + req.URL.RawQuery = params.Encode() + + resp, err := c.httpClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + + if resp.StatusCode != http.StatusNoContent && resp.StatusCode != http.StatusOK { + var err = fmt.Errorf(string(body)) + return err + } + + return nil +} + +// Query defines a query to send to the server. +type Query struct { + Command string + Database string + Precision string + Chunked bool + ChunkSize int + Parameters map[string]interface{} +} + +// NewQuery returns a query object. +// The database and precision arguments can be empty strings if they are not needed for the query. +func NewQuery(command, database, precision string) Query { + return Query{ + Command: command, + Database: database, + Precision: precision, + Parameters: make(map[string]interface{}), + } +} + +// NewQueryWithParameters returns a query object. +// The database and precision arguments can be empty strings if they are not needed for the query. +// parameters is a map of the parameter names used in the command to their values. +func NewQueryWithParameters(command, database, precision string, parameters map[string]interface{}) Query { + return Query{ + Command: command, + Database: database, + Precision: precision, + Parameters: parameters, + } +} + +// Response represents a list of statement results. +type Response struct { + Results []Result + Err string `json:"error,omitempty"` +} + +// Error returns the first error from any statement. +// It returns nil if no errors occurred on any statements. +func (r *Response) Error() error { + if r.Err != "" { + return fmt.Errorf(r.Err) + } + for _, result := range r.Results { + if result.Err != "" { + return fmt.Errorf(result.Err) + } + } + return nil +} + +// Message represents a user message. +type Message struct { + Level string + Text string +} + +// Result represents a resultset returned from a single statement. +type Result struct { + Series []models.Row + Messages []*Message + Err string `json:"error,omitempty"` +} + +// Query sends a command to the server and returns the Response. +func (c *client) Query(q Query) (*Response, error) { + u := c.url + u.Path = "query" + + jsonParameters, err := json.Marshal(q.Parameters) + + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", u.String(), nil) + if err != nil { + return nil, err + } + + req.Header.Set("Content-Type", "") + req.Header.Set("User-Agent", c.useragent) + + if c.username != "" { + req.SetBasicAuth(c.username, c.password) + } + + params := req.URL.Query() + params.Set("q", q.Command) + params.Set("db", q.Database) + params.Set("params", string(jsonParameters)) + if q.Chunked { + params.Set("chunked", "true") + if q.ChunkSize > 0 { + params.Set("chunk_size", strconv.Itoa(q.ChunkSize)) + } + } + + if q.Precision != "" { + params.Set("epoch", q.Precision) + } + req.URL.RawQuery = params.Encode() + + resp, err := c.httpClient.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + // If we lack a X-Influxdb-Version header, then we didn't get a response from influxdb + // but instead some other service. If the error code is also a 500+ code, then some + // downstream loadbalancer/proxy/etc had an issue and we should report that. + if resp.Header.Get("X-Influxdb-Version") == "" && resp.StatusCode >= http.StatusInternalServerError { + body, err := ioutil.ReadAll(resp.Body) + if err != nil || len(body) == 0 { + return nil, fmt.Errorf("received status code %d from downstream server", resp.StatusCode) + } + + return nil, fmt.Errorf("received status code %d from downstream server, with response body: %q", resp.StatusCode, body) + } + + // If we get an unexpected content type, then it is also not from influx direct and therefore + // we want to know what we received and what status code was returned for debugging purposes. + if cType, _, _ := mime.ParseMediaType(resp.Header.Get("Content-Type")); cType != "application/json" { + // Read up to 1kb of the body to help identify downstream errors and limit the impact of things + // like downstream serving a large file + body, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1024)) + if err != nil || len(body) == 0 { + return nil, fmt.Errorf("expected json response, got empty body, with status: %v", resp.StatusCode) + } + + return nil, fmt.Errorf("expected json response, got %q, with status: %v and response body: %q", cType, resp.StatusCode, body) + } + + var response Response + if q.Chunked { + cr := NewChunkedResponse(resp.Body) + for { + r, err := cr.NextResponse() + if err != nil { + // If we got an error while decoding the response, send that back. + return nil, err + } + + if r == nil { + break + } + + response.Results = append(response.Results, r.Results...) + if r.Err != "" { + response.Err = r.Err + break + } + } + } else { + dec := json.NewDecoder(resp.Body) + dec.UseNumber() + decErr := dec.Decode(&response) + + // ignore this error if we got an invalid status code + if decErr != nil && decErr.Error() == "EOF" && resp.StatusCode != http.StatusOK { + decErr = nil + } + // If we got a valid decode error, send that back + if decErr != nil { + return nil, fmt.Errorf("unable to decode json: received status code %d err: %s", resp.StatusCode, decErr) + } + } + + // If we don't have an error in our json response, and didn't get statusOK + // then send back an error + if resp.StatusCode != http.StatusOK && response.Error() == nil { + return &response, fmt.Errorf("received status code %d from server", resp.StatusCode) + } + return &response, nil +} + +// duplexReader reads responses and writes it to another writer while +// satisfying the reader interface. +type duplexReader struct { + r io.Reader + w io.Writer +} + +func (r *duplexReader) Read(p []byte) (n int, err error) { + n, err = r.r.Read(p) + if err == nil { + r.w.Write(p[:n]) + } + return n, err +} + +// ChunkedResponse represents a response from the server that +// uses chunking to stream the output. +type ChunkedResponse struct { + dec *json.Decoder + duplex *duplexReader + buf bytes.Buffer +} + +// NewChunkedResponse reads a stream and produces responses from the stream. +func NewChunkedResponse(r io.Reader) *ChunkedResponse { + resp := &ChunkedResponse{} + resp.duplex = &duplexReader{r: r, w: &resp.buf} + resp.dec = json.NewDecoder(resp.duplex) + resp.dec.UseNumber() + return resp +} + +// NextResponse reads the next line of the stream and returns a response. +func (r *ChunkedResponse) NextResponse() (*Response, error) { + var response Response + + if err := r.dec.Decode(&response); err != nil { + if err == io.EOF { + return nil, nil + } + // A decoding error happened. This probably means the server crashed + // and sent a last-ditch error message to us. Ensure we have read the + // entirety of the connection to get any remaining error text. + io.Copy(ioutil.Discard, r.duplex) + return nil, errors.New(strings.TrimSpace(r.buf.String())) + } + + r.buf.Reset() + return &response, nil +} diff --git a/vendor/github.com/influxdata/influxdb/client/v2/udp.go b/vendor/github.com/influxdata/influxdb/client/v2/udp.go new file mode 100644 index 0000000000..779a28b33f --- /dev/null +++ b/vendor/github.com/influxdata/influxdb/client/v2/udp.go @@ -0,0 +1,112 @@ +package client + +import ( + "fmt" + "io" + "net" + "time" +) + +const ( + // UDPPayloadSize is a reasonable default payload size for UDP packets that + // could be travelling over the internet. + UDPPayloadSize = 512 +) + +// UDPConfig is the config data needed to create a UDP Client. +type UDPConfig struct { + // Addr should be of the form "host:port" + // or "[ipv6-host%zone]:port". + Addr string + + // PayloadSize is the maximum size of a UDP client message, optional + // Tune this based on your network. Defaults to UDPPayloadSize. + PayloadSize int +} + +// NewUDPClient returns a client interface for writing to an InfluxDB UDP +// service from the given config. +func NewUDPClient(conf UDPConfig) (Client, error) { + var udpAddr *net.UDPAddr + udpAddr, err := net.ResolveUDPAddr("udp", conf.Addr) + if err != nil { + return nil, err + } + + conn, err := net.DialUDP("udp", nil, udpAddr) + if err != nil { + return nil, err + } + + payloadSize := conf.PayloadSize + if payloadSize == 0 { + payloadSize = UDPPayloadSize + } + + return &udpclient{ + conn: conn, + payloadSize: payloadSize, + }, nil +} + +// Close releases the udpclient's resources. +func (uc *udpclient) Close() error { + return uc.conn.Close() +} + +type udpclient struct { + conn io.WriteCloser + payloadSize int +} + +func (uc *udpclient) Write(bp BatchPoints) error { + var b = make([]byte, 0, uc.payloadSize) // initial buffer size, it will grow as needed + var d, _ = time.ParseDuration("1" + bp.Precision()) + + var delayedError error + + var checkBuffer = func(n int) { + if len(b) > 0 && len(b)+n > uc.payloadSize { + if _, err := uc.conn.Write(b); err != nil { + delayedError = err + } + b = b[:0] + } + } + + for _, p := range bp.Points() { + p.pt.Round(d) + pointSize := p.pt.StringSize() + 1 // include newline in size + //point := p.pt.RoundedString(d) + "\n" + + checkBuffer(pointSize) + + if p.Time().IsZero() || pointSize <= uc.payloadSize { + b = p.pt.AppendString(b) + b = append(b, '\n') + continue + } + + points := p.pt.Split(uc.payloadSize - 1) // account for newline character + for _, sp := range points { + checkBuffer(sp.StringSize() + 1) + b = sp.AppendString(b) + b = append(b, '\n') + } + } + + if len(b) > 0 { + if _, err := uc.conn.Write(b); err != nil { + return err + } + } + return delayedError +} + +func (uc *udpclient) Query(q Query) (*Response, error) { + return nil, fmt.Errorf("Querying via UDP is not supported") +} + +func (uc *udpclient) Ping(timeout time.Duration) (time.Duration, string, error) { + return 0, "", nil +} diff --git a/vendor/github.com/influxdata/influxdb/models/consistency.go b/vendor/github.com/influxdata/influxdb/models/consistency.go new file mode 100644 index 0000000000..2a3269bca1 --- /dev/null +++ b/vendor/github.com/influxdata/influxdb/models/consistency.go @@ -0,0 +1,48 @@ +package models + +import ( + "errors" + "strings" +) + +// ConsistencyLevel represent a required replication criteria before a write can +// be returned as successful. +// +// The consistency level is handled in open-source InfluxDB but only applicable to clusters. +type ConsistencyLevel int + +const ( + // ConsistencyLevelAny allows for hinted handoff, potentially no write happened yet. + ConsistencyLevelAny ConsistencyLevel = iota + + // ConsistencyLevelOne requires at least one data node acknowledged a write. + ConsistencyLevelOne + + // ConsistencyLevelQuorum requires a quorum of data nodes to acknowledge a write. + ConsistencyLevelQuorum + + // ConsistencyLevelAll requires all data nodes to acknowledge a write. + ConsistencyLevelAll +) + +var ( + // ErrInvalidConsistencyLevel is returned when parsing the string version + // of a consistency level. + ErrInvalidConsistencyLevel = errors.New("invalid consistency level") +) + +// ParseConsistencyLevel converts a consistency level string to the corresponding ConsistencyLevel const. +func ParseConsistencyLevel(level string) (ConsistencyLevel, error) { + switch strings.ToLower(level) { + case "any": + return ConsistencyLevelAny, nil + case "one": + return ConsistencyLevelOne, nil + case "quorum": + return ConsistencyLevelQuorum, nil + case "all": + return ConsistencyLevelAll, nil + default: + return 0, ErrInvalidConsistencyLevel + } +} diff --git a/vendor/github.com/influxdata/influxdb/models/inline_fnv.go b/vendor/github.com/influxdata/influxdb/models/inline_fnv.go new file mode 100644 index 0000000000..eec1ae8b01 --- /dev/null +++ b/vendor/github.com/influxdata/influxdb/models/inline_fnv.go @@ -0,0 +1,32 @@ +package models // import "github.com/influxdata/influxdb/models" + +// from stdlib hash/fnv/fnv.go +const ( + prime64 = 1099511628211 + offset64 = 14695981039346656037 +) + +// InlineFNV64a is an alloc-free port of the standard library's fnv64a. +// See https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function. +type InlineFNV64a uint64 + +// NewInlineFNV64a returns a new instance of InlineFNV64a. +func NewInlineFNV64a() InlineFNV64a { + return offset64 +} + +// Write adds data to the running hash. +func (s *InlineFNV64a) Write(data []byte) (int, error) { + hash := uint64(*s) + for _, c := range data { + hash ^= uint64(c) + hash *= prime64 + } + *s = InlineFNV64a(hash) + return len(data), nil +} + +// Sum64 returns the uint64 of the current resulting hash. +func (s *InlineFNV64a) Sum64() uint64 { + return uint64(*s) +} diff --git a/vendor/github.com/influxdata/influxdb/models/inline_strconv_parse.go b/vendor/github.com/influxdata/influxdb/models/inline_strconv_parse.go new file mode 100644 index 0000000000..8db4837384 --- /dev/null +++ b/vendor/github.com/influxdata/influxdb/models/inline_strconv_parse.go @@ -0,0 +1,44 @@ +package models // import "github.com/influxdata/influxdb/models" + +import ( + "reflect" + "strconv" + "unsafe" +) + +// parseIntBytes is a zero-alloc wrapper around strconv.ParseInt. +func parseIntBytes(b []byte, base int, bitSize int) (i int64, err error) { + s := unsafeBytesToString(b) + return strconv.ParseInt(s, base, bitSize) +} + +// parseUintBytes is a zero-alloc wrapper around strconv.ParseUint. +func parseUintBytes(b []byte, base int, bitSize int) (i uint64, err error) { + s := unsafeBytesToString(b) + return strconv.ParseUint(s, base, bitSize) +} + +// parseFloatBytes is a zero-alloc wrapper around strconv.ParseFloat. +func parseFloatBytes(b []byte, bitSize int) (float64, error) { + s := unsafeBytesToString(b) + return strconv.ParseFloat(s, bitSize) +} + +// parseBoolBytes is a zero-alloc wrapper around strconv.ParseBool. +func parseBoolBytes(b []byte) (bool, error) { + return strconv.ParseBool(unsafeBytesToString(b)) +} + +// unsafeBytesToString converts a []byte to a string without a heap allocation. +// +// It is unsafe, and is intended to prepare input to short-lived functions +// that require strings. +func unsafeBytesToString(in []byte) string { + src := *(*reflect.SliceHeader)(unsafe.Pointer(&in)) + dst := reflect.StringHeader{ + Data: src.Data, + Len: src.Len, + } + s := *(*string)(unsafe.Pointer(&dst)) + return s +} diff --git a/vendor/github.com/influxdata/influxdb/models/points.go b/vendor/github.com/influxdata/influxdb/models/points.go new file mode 100644 index 0000000000..ad80a816bf --- /dev/null +++ b/vendor/github.com/influxdata/influxdb/models/points.go @@ -0,0 +1,2337 @@ +// Package models implements basic objects used throughout the TICK stack. +package models // import "github.com/influxdata/influxdb/models" + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + "io" + "math" + "sort" + "strconv" + "strings" + "time" + + "github.com/influxdata/influxdb/pkg/escape" +) + +var ( + measurementEscapeCodes = map[byte][]byte{ + ',': []byte(`\,`), + ' ': []byte(`\ `), + } + + tagEscapeCodes = map[byte][]byte{ + ',': []byte(`\,`), + ' ': []byte(`\ `), + '=': []byte(`\=`), + } + + // ErrPointMustHaveAField is returned when operating on a point that does not have any fields. + ErrPointMustHaveAField = errors.New("point without fields is unsupported") + + // ErrInvalidNumber is returned when a number is expected but not provided. + ErrInvalidNumber = errors.New("invalid number") + + // ErrInvalidPoint is returned when a point cannot be parsed correctly. + ErrInvalidPoint = errors.New("point is invalid") +) + +const ( + // MaxKeyLength is the largest allowed size of the combined measurement and tag keys. + MaxKeyLength = 65535 +) + +// enableUint64Support will enable uint64 support if set to true. +var enableUint64Support = false + +// EnableUintSupport manually enables uint support for the point parser. +// This function will be removed in the future and only exists for unit tests during the +// transition. +func EnableUintSupport() { + enableUint64Support = true +} + +// Point defines the values that will be written to the database. +type Point interface { + // Name return the measurement name for the point. + Name() []byte + + // SetName updates the measurement name for the point. + SetName(string) + + // Tags returns the tag set for the point. + Tags() Tags + + // AddTag adds or replaces a tag value for a point. + AddTag(key, value string) + + // SetTags replaces the tags for the point. + SetTags(tags Tags) + + // HasTag returns true if the tag exists for the point. + HasTag(tag []byte) bool + + // Fields returns the fields for the point. + Fields() (Fields, error) + + // Time return the timestamp for the point. + Time() time.Time + + // SetTime updates the timestamp for the point. + SetTime(t time.Time) + + // UnixNano returns the timestamp of the point as nanoseconds since Unix epoch. + UnixNano() int64 + + // HashID returns a non-cryptographic checksum of the point's key. + HashID() uint64 + + // Key returns the key (measurement joined with tags) of the point. + Key() []byte + + // String returns a string representation of the point. If there is a + // timestamp associated with the point then it will be specified with the default + // precision of nanoseconds. + String() string + + // MarshalBinary returns a binary representation of the point. + MarshalBinary() ([]byte, error) + + // PrecisionString returns a string representation of the point. If there + // is a timestamp associated with the point then it will be specified in the + // given unit. + PrecisionString(precision string) string + + // RoundedString returns a string representation of the point. If there + // is a timestamp associated with the point, then it will be rounded to the + // given duration. + RoundedString(d time.Duration) string + + // Split will attempt to return multiple points with the same timestamp whose + // string representations are no longer than size. Points with a single field or + // a point without a timestamp may exceed the requested size. + Split(size int) []Point + + // Round will round the timestamp of the point to the given duration. + Round(d time.Duration) + + // StringSize returns the length of the string that would be returned by String(). + StringSize() int + + // AppendString appends the result of String() to the provided buffer and returns + // the result, potentially reducing string allocations. + AppendString(buf []byte) []byte + + // FieldIterator retuns a FieldIterator that can be used to traverse the + // fields of a point without constructing the in-memory map. + FieldIterator() FieldIterator +} + +// FieldType represents the type of a field. +type FieldType int + +const ( + // Integer indicates the field's type is integer. + Integer FieldType = iota + + // Float indicates the field's type is float. + Float + + // Boolean indicates the field's type is boolean. + Boolean + + // String indicates the field's type is string. + String + + // Empty is used to indicate that there is no field. + Empty + + // Unsigned indicates the field's type is an unsigned integer. + Unsigned +) + +// FieldIterator provides a low-allocation interface to iterate through a point's fields. +type FieldIterator interface { + // Next indicates whether there any fields remaining. + Next() bool + + // FieldKey returns the key of the current field. + FieldKey() []byte + + // Type returns the FieldType of the current field. + Type() FieldType + + // StringValue returns the string value of the current field. + StringValue() string + + // IntegerValue returns the integer value of the current field. + IntegerValue() (int64, error) + + // UnsignedValue returns the unsigned value of the current field. + UnsignedValue() (uint64, error) + + // BooleanValue returns the boolean value of the current field. + BooleanValue() (bool, error) + + // FloatValue returns the float value of the current field. + FloatValue() (float64, error) + + // Reset resets the iterator to its initial state. + Reset() +} + +// Points represents a sortable list of points by timestamp. +type Points []Point + +// Len implements sort.Interface. +func (a Points) Len() int { return len(a) } + +// Less implements sort.Interface. +func (a Points) Less(i, j int) bool { return a[i].Time().Before(a[j].Time()) } + +// Swap implements sort.Interface. +func (a Points) Swap(i, j int) { a[i], a[j] = a[j], a[i] } + +// point is the default implementation of Point. +type point struct { + time time.Time + + // text encoding of measurement and tags + // key must always be stored sorted by tags, if the original line was not sorted, + // we need to resort it + key []byte + + // text encoding of field data + fields []byte + + // text encoding of timestamp + ts []byte + + // cached version of parsed fields from data + cachedFields map[string]interface{} + + // cached version of parsed name from key + cachedName string + + // cached version of parsed tags + cachedTags Tags + + it fieldIterator +} + +// type assertions +var ( + _ Point = (*point)(nil) + _ FieldIterator = (*point)(nil) +) + +const ( + // the number of characters for the largest possible int64 (9223372036854775807) + maxInt64Digits = 19 + + // the number of characters for the smallest possible int64 (-9223372036854775808) + minInt64Digits = 20 + + // the number of characters for the largest possible uint64 (18446744073709551615) + maxUint64Digits = 20 + + // the number of characters required for the largest float64 before a range check + // would occur during parsing + maxFloat64Digits = 25 + + // the number of characters required for smallest float64 before a range check occur + // would occur during parsing + minFloat64Digits = 27 +) + +// ParsePoints returns a slice of Points from a text representation of a point +// with each point separated by newlines. If any points fail to parse, a non-nil error +// will be returned in addition to the points that parsed successfully. +func ParsePoints(buf []byte) ([]Point, error) { + return ParsePointsWithPrecision(buf, time.Now().UTC(), "n") +} + +// ParsePointsString is identical to ParsePoints but accepts a string. +func ParsePointsString(buf string) ([]Point, error) { + return ParsePoints([]byte(buf)) +} + +// ParseKey returns the measurement name and tags from a point. +// +// NOTE: to minimize heap allocations, the returned Tags will refer to subslices of buf. +// This can have the unintended effect preventing buf from being garbage collected. +func ParseKey(buf []byte) (string, Tags) { + meas, tags := ParseKeyBytes(buf) + return string(meas), tags +} + +func ParseKeyBytes(buf []byte) ([]byte, Tags) { + // Ignore the error because scanMeasurement returns "missing fields" which we ignore + // when just parsing a key + state, i, _ := scanMeasurement(buf, 0) + + var tags Tags + if state == tagKeyState { + tags = parseTags(buf) + // scanMeasurement returns the location of the comma if there are tags, strip that off + return buf[:i-1], tags + } + return buf[:i], tags +} + +func ParseTags(buf []byte) Tags { + return parseTags(buf) +} + +func ParseName(buf []byte) ([]byte, error) { + // Ignore the error because scanMeasurement returns "missing fields" which we ignore + // when just parsing a key + state, i, _ := scanMeasurement(buf, 0) + if state == tagKeyState { + return buf[:i-1], nil + } + return buf[:i], nil +} + +// ParsePointsWithPrecision is similar to ParsePoints, but allows the +// caller to provide a precision for time. +// +// NOTE: to minimize heap allocations, the returned Points will refer to subslices of buf. +// This can have the unintended effect preventing buf from being garbage collected. +func ParsePointsWithPrecision(buf []byte, defaultTime time.Time, precision string) ([]Point, error) { + points := make([]Point, 0, bytes.Count(buf, []byte{'\n'})+1) + var ( + pos int + block []byte + failed []string + ) + for pos < len(buf) { + pos, block = scanLine(buf, pos) + pos++ + + if len(block) == 0 { + continue + } + + // lines which start with '#' are comments + start := skipWhitespace(block, 0) + + // If line is all whitespace, just skip it + if start >= len(block) { + continue + } + + if block[start] == '#' { + continue + } + + // strip the newline if one is present + if block[len(block)-1] == '\n' { + block = block[:len(block)-1] + } + + pt, err := parsePoint(block[start:], defaultTime, precision) + if err != nil { + failed = append(failed, fmt.Sprintf("unable to parse '%s': %v", string(block[start:]), err)) + } else { + points = append(points, pt) + } + + } + if len(failed) > 0 { + return points, fmt.Errorf("%s", strings.Join(failed, "\n")) + } + return points, nil + +} + +func parsePoint(buf []byte, defaultTime time.Time, precision string) (Point, error) { + // scan the first block which is measurement[,tag1=value1,tag2=value=2...] + pos, key, err := scanKey(buf, 0) + if err != nil { + return nil, err + } + + // measurement name is required + if len(key) == 0 { + return nil, fmt.Errorf("missing measurement") + } + + if len(key) > MaxKeyLength { + return nil, fmt.Errorf("max key length exceeded: %v > %v", len(key), MaxKeyLength) + } + + // scan the second block is which is field1=value1[,field2=value2,...] + pos, fields, err := scanFields(buf, pos) + if err != nil { + return nil, err + } + + // at least one field is required + if len(fields) == 0 { + return nil, fmt.Errorf("missing fields") + } + + var maxKeyErr error + walkFields(fields, func(k, v []byte) bool { + if sz := seriesKeySize(key, k); sz > MaxKeyLength { + maxKeyErr = fmt.Errorf("max key length exceeded: %v > %v", sz, MaxKeyLength) + return false + } + return true + }) + + if maxKeyErr != nil { + return nil, maxKeyErr + } + + // scan the last block which is an optional integer timestamp + pos, ts, err := scanTime(buf, pos) + if err != nil { + return nil, err + } + + pt := &point{ + key: key, + fields: fields, + ts: ts, + } + + if len(ts) == 0 { + pt.time = defaultTime + pt.SetPrecision(precision) + } else { + ts, err := parseIntBytes(ts, 10, 64) + if err != nil { + return nil, err + } + pt.time, err = SafeCalcTime(ts, precision) + if err != nil { + return nil, err + } + + // Determine if there are illegal non-whitespace characters after the + // timestamp block. + for pos < len(buf) { + if buf[pos] != ' ' { + return nil, ErrInvalidPoint + } + pos++ + } + } + return pt, nil +} + +// GetPrecisionMultiplier will return a multiplier for the precision specified. +func GetPrecisionMultiplier(precision string) int64 { + d := time.Nanosecond + switch precision { + case "u": + d = time.Microsecond + case "ms": + d = time.Millisecond + case "s": + d = time.Second + case "m": + d = time.Minute + case "h": + d = time.Hour + } + return int64(d) +} + +// scanKey scans buf starting at i for the measurement and tag portion of the point. +// It returns the ending position and the byte slice of key within buf. If there +// are tags, they will be sorted if they are not already. +func scanKey(buf []byte, i int) (int, []byte, error) { + start := skipWhitespace(buf, i) + + i = start + + // Determines whether the tags are sort, assume they are + sorted := true + + // indices holds the indexes within buf of the start of each tag. For example, + // a buf of 'cpu,host=a,region=b,zone=c' would have indices slice of [4,11,20] + // which indicates that the first tag starts at buf[4], seconds at buf[11], and + // last at buf[20] + indices := make([]int, 100) + + // tracks how many commas we've seen so we know how many values are indices. + // Since indices is an arbitrarily large slice, + // we need to know how many values in the buffer are in use. + commas := 0 + + // First scan the Point's measurement. + state, i, err := scanMeasurement(buf, i) + if err != nil { + return i, buf[start:i], err + } + + // Optionally scan tags if needed. + if state == tagKeyState { + i, commas, indices, err = scanTags(buf, i, indices) + if err != nil { + return i, buf[start:i], err + } + } + + // Now we know where the key region is within buf, and the location of tags, we + // need to determine if duplicate tags exist and if the tags are sorted. This iterates + // over the list comparing each tag in the sequence with each other. + for j := 0; j < commas-1; j++ { + // get the left and right tags + _, left := scanTo(buf[indices[j]:indices[j+1]-1], 0, '=') + _, right := scanTo(buf[indices[j+1]:indices[j+2]-1], 0, '=') + + // If left is greater than right, the tags are not sorted. We do not have to + // continue because the short path no longer works. + // If the tags are equal, then there are duplicate tags, and we should abort. + // If the tags are not sorted, this pass may not find duplicate tags and we + // need to do a more exhaustive search later. + if cmp := bytes.Compare(left, right); cmp > 0 { + sorted = false + break + } else if cmp == 0 { + return i, buf[start:i], fmt.Errorf("duplicate tags") + } + } + + // If the tags are not sorted, then sort them. This sort is inline and + // uses the tag indices we created earlier. The actual buffer is not sorted, the + // indices are using the buffer for value comparison. After the indices are sorted, + // the buffer is reconstructed from the sorted indices. + if !sorted && commas > 0 { + // Get the measurement name for later + measurement := buf[start : indices[0]-1] + + // Sort the indices + indices := indices[:commas] + insertionSort(0, commas, buf, indices) + + // Create a new key using the measurement and sorted indices + b := make([]byte, len(buf[start:i])) + pos := copy(b, measurement) + for _, i := range indices { + b[pos] = ',' + pos++ + _, v := scanToSpaceOr(buf, i, ',') + pos += copy(b[pos:], v) + } + + // Check again for duplicate tags now that the tags are sorted. + for j := 0; j < commas-1; j++ { + // get the left and right tags + _, left := scanTo(buf[indices[j]:], 0, '=') + _, right := scanTo(buf[indices[j+1]:], 0, '=') + + // If the tags are equal, then there are duplicate tags, and we should abort. + // If the tags are not sorted, this pass may not find duplicate tags and we + // need to do a more exhaustive search later. + if bytes.Equal(left, right) { + return i, b, fmt.Errorf("duplicate tags") + } + } + + return i, b, nil + } + + return i, buf[start:i], nil +} + +// The following constants allow us to specify which state to move to +// next, when scanning sections of a Point. +const ( + tagKeyState = iota + tagValueState + fieldsState +) + +// scanMeasurement examines the measurement part of a Point, returning +// the next state to move to, and the current location in the buffer. +func scanMeasurement(buf []byte, i int) (int, int, error) { + // Check first byte of measurement, anything except a comma is fine. + // It can't be a space, since whitespace is stripped prior to this + // function call. + if i >= len(buf) || buf[i] == ',' { + return -1, i, fmt.Errorf("missing measurement") + } + + for { + i++ + if i >= len(buf) { + // cpu + return -1, i, fmt.Errorf("missing fields") + } + + if buf[i-1] == '\\' { + // Skip character (it's escaped). + continue + } + + // Unescaped comma; move onto scanning the tags. + if buf[i] == ',' { + return tagKeyState, i + 1, nil + } + + // Unescaped space; move onto scanning the fields. + if buf[i] == ' ' { + // cpu value=1.0 + return fieldsState, i, nil + } + } +} + +// scanTags examines all the tags in a Point, keeping track of and +// returning the updated indices slice, number of commas and location +// in buf where to start examining the Point fields. +func scanTags(buf []byte, i int, indices []int) (int, int, []int, error) { + var ( + err error + commas int + state = tagKeyState + ) + + for { + switch state { + case tagKeyState: + // Grow our indices slice if we have too many tags. + if commas >= len(indices) { + newIndics := make([]int, cap(indices)*2) + copy(newIndics, indices) + indices = newIndics + } + indices[commas] = i + commas++ + + i, err = scanTagsKey(buf, i) + state = tagValueState // tag value always follows a tag key + case tagValueState: + state, i, err = scanTagsValue(buf, i) + case fieldsState: + indices[commas] = i + 1 + return i, commas, indices, nil + } + + if err != nil { + return i, commas, indices, err + } + } +} + +// scanTagsKey scans each character in a tag key. +func scanTagsKey(buf []byte, i int) (int, error) { + // First character of the key. + if i >= len(buf) || buf[i] == ' ' || buf[i] == ',' || buf[i] == '=' { + // cpu,{'', ' ', ',', '='} + return i, fmt.Errorf("missing tag key") + } + + // Examine each character in the tag key until we hit an unescaped + // equals (the tag value), or we hit an error (i.e., unescaped + // space or comma). + for { + i++ + + // Either we reached the end of the buffer or we hit an + // unescaped comma or space. + if i >= len(buf) || + ((buf[i] == ' ' || buf[i] == ',') && buf[i-1] != '\\') { + // cpu,tag{'', ' ', ','} + return i, fmt.Errorf("missing tag value") + } + + if buf[i] == '=' && buf[i-1] != '\\' { + // cpu,tag= + return i + 1, nil + } + } +} + +// scanTagsValue scans each character in a tag value. +func scanTagsValue(buf []byte, i int) (int, int, error) { + // Tag value cannot be empty. + if i >= len(buf) || buf[i] == ',' || buf[i] == ' ' { + // cpu,tag={',', ' '} + return -1, i, fmt.Errorf("missing tag value") + } + + // Examine each character in the tag value until we hit an unescaped + // comma (move onto next tag key), an unescaped space (move onto + // fields), or we error out. + for { + i++ + if i >= len(buf) { + // cpu,tag=value + return -1, i, fmt.Errorf("missing fields") + } + + // An unescaped equals sign is an invalid tag value. + if buf[i] == '=' && buf[i-1] != '\\' { + // cpu,tag={'=', 'fo=o'} + return -1, i, fmt.Errorf("invalid tag format") + } + + if buf[i] == ',' && buf[i-1] != '\\' { + // cpu,tag=foo, + return tagKeyState, i + 1, nil + } + + // cpu,tag=foo value=1.0 + // cpu, tag=foo\= value=1.0 + if buf[i] == ' ' && buf[i-1] != '\\' { + return fieldsState, i, nil + } + } +} + +func insertionSort(l, r int, buf []byte, indices []int) { + for i := l + 1; i < r; i++ { + for j := i; j > l && less(buf, indices, j, j-1); j-- { + indices[j], indices[j-1] = indices[j-1], indices[j] + } + } +} + +func less(buf []byte, indices []int, i, j int) bool { + // This grabs the tag names for i & j, it ignores the values + _, a := scanTo(buf, indices[i], '=') + _, b := scanTo(buf, indices[j], '=') + return bytes.Compare(a, b) < 0 +} + +// scanFields scans buf, starting at i for the fields section of a point. It returns +// the ending position and the byte slice of the fields within buf. +func scanFields(buf []byte, i int) (int, []byte, error) { + start := skipWhitespace(buf, i) + i = start + quoted := false + + // tracks how many '=' we've seen + equals := 0 + + // tracks how many commas we've seen + commas := 0 + + for { + // reached the end of buf? + if i >= len(buf) { + break + } + + // escaped characters? + if buf[i] == '\\' && i+1 < len(buf) { + i += 2 + continue + } + + // If the value is quoted, scan until we get to the end quote + // Only quote values in the field value since quotes are not significant + // in the field key + if buf[i] == '"' && equals > commas { + quoted = !quoted + i++ + continue + } + + // If we see an =, ensure that there is at least on char before and after it + if buf[i] == '=' && !quoted { + equals++ + + // check for "... =123" but allow "a\ =123" + if buf[i-1] == ' ' && buf[i-2] != '\\' { + return i, buf[start:i], fmt.Errorf("missing field key") + } + + // check for "...a=123,=456" but allow "a=123,a\,=456" + if buf[i-1] == ',' && buf[i-2] != '\\' { + return i, buf[start:i], fmt.Errorf("missing field key") + } + + // check for "... value=" + if i+1 >= len(buf) { + return i, buf[start:i], fmt.Errorf("missing field value") + } + + // check for "... value=,value2=..." + if buf[i+1] == ',' || buf[i+1] == ' ' { + return i, buf[start:i], fmt.Errorf("missing field value") + } + + if isNumeric(buf[i+1]) || buf[i+1] == '-' || buf[i+1] == 'N' || buf[i+1] == 'n' { + var err error + i, err = scanNumber(buf, i+1) + if err != nil { + return i, buf[start:i], err + } + continue + } + // If next byte is not a double-quote, the value must be a boolean + if buf[i+1] != '"' { + var err error + i, _, err = scanBoolean(buf, i+1) + if err != nil { + return i, buf[start:i], err + } + continue + } + } + + if buf[i] == ',' && !quoted { + commas++ + } + + // reached end of block? + if buf[i] == ' ' && !quoted { + break + } + i++ + } + + if quoted { + return i, buf[start:i], fmt.Errorf("unbalanced quotes") + } + + // check that all field sections had key and values (e.g. prevent "a=1,b" + if equals == 0 || commas != equals-1 { + return i, buf[start:i], fmt.Errorf("invalid field format") + } + + return i, buf[start:i], nil +} + +// scanTime scans buf, starting at i for the time section of a point. It +// returns the ending position and the byte slice of the timestamp within buf +// and and error if the timestamp is not in the correct numeric format. +func scanTime(buf []byte, i int) (int, []byte, error) { + start := skipWhitespace(buf, i) + i = start + + for { + // reached the end of buf? + if i >= len(buf) { + break + } + + // Reached end of block or trailing whitespace? + if buf[i] == '\n' || buf[i] == ' ' { + break + } + + // Handle negative timestamps + if i == start && buf[i] == '-' { + i++ + continue + } + + // Timestamps should be integers, make sure they are so we don't need + // to actually parse the timestamp until needed. + if buf[i] < '0' || buf[i] > '9' { + return i, buf[start:i], fmt.Errorf("bad timestamp") + } + i++ + } + return i, buf[start:i], nil +} + +func isNumeric(b byte) bool { + return (b >= '0' && b <= '9') || b == '.' +} + +// scanNumber returns the end position within buf, start at i after +// scanning over buf for an integer, or float. It returns an +// error if a invalid number is scanned. +func scanNumber(buf []byte, i int) (int, error) { + start := i + var isInt, isUnsigned bool + + // Is negative number? + if i < len(buf) && buf[i] == '-' { + i++ + // There must be more characters now, as just '-' is illegal. + if i == len(buf) { + return i, ErrInvalidNumber + } + } + + // how many decimal points we've see + decimal := false + + // indicates the number is float in scientific notation + scientific := false + + for { + if i >= len(buf) { + break + } + + if buf[i] == ',' || buf[i] == ' ' { + break + } + + if buf[i] == 'i' && i > start && !(isInt || isUnsigned) { + isInt = true + i++ + continue + } else if buf[i] == 'u' && i > start && !(isInt || isUnsigned) { + isUnsigned = true + i++ + continue + } + + if buf[i] == '.' { + // Can't have more than 1 decimal (e.g. 1.1.1 should fail) + if decimal { + return i, ErrInvalidNumber + } + decimal = true + } + + // `e` is valid for floats but not as the first char + if i > start && (buf[i] == 'e' || buf[i] == 'E') { + scientific = true + i++ + continue + } + + // + and - are only valid at this point if they follow an e (scientific notation) + if (buf[i] == '+' || buf[i] == '-') && (buf[i-1] == 'e' || buf[i-1] == 'E') { + i++ + continue + } + + // NaN is an unsupported value + if i+2 < len(buf) && (buf[i] == 'N' || buf[i] == 'n') { + return i, ErrInvalidNumber + } + + if !isNumeric(buf[i]) { + return i, ErrInvalidNumber + } + i++ + } + + if (isInt || isUnsigned) && (decimal || scientific) { + return i, ErrInvalidNumber + } + + numericDigits := i - start + if isInt { + numericDigits-- + } + if decimal { + numericDigits-- + } + if buf[start] == '-' { + numericDigits-- + } + + if numericDigits == 0 { + return i, ErrInvalidNumber + } + + // It's more common that numbers will be within min/max range for their type but we need to prevent + // out or range numbers from being parsed successfully. This uses some simple heuristics to decide + // if we should parse the number to the actual type. It does not do it all the time because it incurs + // extra allocations and we end up converting the type again when writing points to disk. + if isInt { + // Make sure the last char is an 'i' for integers (e.g. 9i10 is not valid) + if buf[i-1] != 'i' { + return i, ErrInvalidNumber + } + // Parse the int to check bounds the number of digits could be larger than the max range + // We subtract 1 from the index to remove the `i` from our tests + if len(buf[start:i-1]) >= maxInt64Digits || len(buf[start:i-1]) >= minInt64Digits { + if _, err := parseIntBytes(buf[start:i-1], 10, 64); err != nil { + return i, fmt.Errorf("unable to parse integer %s: %s", buf[start:i-1], err) + } + } + } else if isUnsigned { + // Return an error if uint64 support has not been enabled. + if !enableUint64Support { + return i, ErrInvalidNumber + } + // Make sure the last char is a 'u' for unsigned + if buf[i-1] != 'u' { + return i, ErrInvalidNumber + } + // Make sure the first char is not a '-' for unsigned + if buf[start] == '-' { + return i, ErrInvalidNumber + } + // Parse the uint to check bounds the number of digits could be larger than the max range + // We subtract 1 from the index to remove the `u` from our tests + if len(buf[start:i-1]) >= maxUint64Digits { + if _, err := parseUintBytes(buf[start:i-1], 10, 64); err != nil { + return i, fmt.Errorf("unable to parse unsigned %s: %s", buf[start:i-1], err) + } + } + } else { + // Parse the float to check bounds if it's scientific or the number of digits could be larger than the max range + if scientific || len(buf[start:i]) >= maxFloat64Digits || len(buf[start:i]) >= minFloat64Digits { + if _, err := parseFloatBytes(buf[start:i], 10); err != nil { + return i, fmt.Errorf("invalid float") + } + } + } + + return i, nil +} + +// scanBoolean returns the end position within buf, start at i after +// scanning over buf for boolean. Valid values for a boolean are +// t, T, true, TRUE, f, F, false, FALSE. It returns an error if a invalid boolean +// is scanned. +func scanBoolean(buf []byte, i int) (int, []byte, error) { + start := i + + if i < len(buf) && (buf[i] != 't' && buf[i] != 'f' && buf[i] != 'T' && buf[i] != 'F') { + return i, buf[start:i], fmt.Errorf("invalid boolean") + } + + i++ + for { + if i >= len(buf) { + break + } + + if buf[i] == ',' || buf[i] == ' ' { + break + } + i++ + } + + // Single char bool (t, T, f, F) is ok + if i-start == 1 { + return i, buf[start:i], nil + } + + // length must be 4 for true or TRUE + if (buf[start] == 't' || buf[start] == 'T') && i-start != 4 { + return i, buf[start:i], fmt.Errorf("invalid boolean") + } + + // length must be 5 for false or FALSE + if (buf[start] == 'f' || buf[start] == 'F') && i-start != 5 { + return i, buf[start:i], fmt.Errorf("invalid boolean") + } + + // Otherwise + valid := false + switch buf[start] { + case 't': + valid = bytes.Equal(buf[start:i], []byte("true")) + case 'f': + valid = bytes.Equal(buf[start:i], []byte("false")) + case 'T': + valid = bytes.Equal(buf[start:i], []byte("TRUE")) || bytes.Equal(buf[start:i], []byte("True")) + case 'F': + valid = bytes.Equal(buf[start:i], []byte("FALSE")) || bytes.Equal(buf[start:i], []byte("False")) + } + + if !valid { + return i, buf[start:i], fmt.Errorf("invalid boolean") + } + + return i, buf[start:i], nil + +} + +// skipWhitespace returns the end position within buf, starting at i after +// scanning over spaces in tags. +func skipWhitespace(buf []byte, i int) int { + for i < len(buf) { + if buf[i] != ' ' && buf[i] != '\t' && buf[i] != 0 { + break + } + i++ + } + return i +} + +// scanLine returns the end position in buf and the next line found within +// buf. +func scanLine(buf []byte, i int) (int, []byte) { + start := i + quoted := false + fields := false + + // tracks how many '=' and commas we've seen + // this duplicates some of the functionality in scanFields + equals := 0 + commas := 0 + for { + // reached the end of buf? + if i >= len(buf) { + break + } + + // skip past escaped characters + if buf[i] == '\\' && i+2 < len(buf) { + i += 2 + continue + } + + if buf[i] == ' ' { + fields = true + } + + // If we see a double quote, makes sure it is not escaped + if fields { + if !quoted && buf[i] == '=' { + i++ + equals++ + continue + } else if !quoted && buf[i] == ',' { + i++ + commas++ + continue + } else if buf[i] == '"' && equals > commas { + i++ + quoted = !quoted + continue + } + } + + if buf[i] == '\n' && !quoted { + break + } + + i++ + } + + return i, buf[start:i] +} + +// scanTo returns the end position in buf and the next consecutive block +// of bytes, starting from i and ending with stop byte, where stop byte +// has not been escaped. +// +// If there are leading spaces, they are skipped. +func scanTo(buf []byte, i int, stop byte) (int, []byte) { + start := i + for { + // reached the end of buf? + if i >= len(buf) { + break + } + + // Reached unescaped stop value? + if buf[i] == stop && (i == 0 || buf[i-1] != '\\') { + break + } + i++ + } + + return i, buf[start:i] +} + +// scanTo returns the end position in buf and the next consecutive block +// of bytes, starting from i and ending with stop byte. If there are leading +// spaces, they are skipped. +func scanToSpaceOr(buf []byte, i int, stop byte) (int, []byte) { + start := i + if buf[i] == stop || buf[i] == ' ' { + return i, buf[start:i] + } + + for { + i++ + if buf[i-1] == '\\' { + continue + } + + // reached the end of buf? + if i >= len(buf) { + return i, buf[start:i] + } + + // reached end of block? + if buf[i] == stop || buf[i] == ' ' { + return i, buf[start:i] + } + } +} + +func scanTagValue(buf []byte, i int) (int, []byte) { + start := i + for { + if i >= len(buf) { + break + } + + if buf[i] == ',' && buf[i-1] != '\\' { + break + } + i++ + } + if i > len(buf) { + return i, nil + } + return i, buf[start:i] +} + +func scanFieldValue(buf []byte, i int) (int, []byte) { + start := i + quoted := false + for i < len(buf) { + // Only escape char for a field value is a double-quote and backslash + if buf[i] == '\\' && i+1 < len(buf) && (buf[i+1] == '"' || buf[i+1] == '\\') { + i += 2 + continue + } + + // Quoted value? (e.g. string) + if buf[i] == '"' { + i++ + quoted = !quoted + continue + } + + if buf[i] == ',' && !quoted { + break + } + i++ + } + return i, buf[start:i] +} + +func EscapeMeasurement(in []byte) []byte { + for b, esc := range measurementEscapeCodes { + in = bytes.Replace(in, []byte{b}, esc, -1) + } + return in +} + +func unescapeMeasurement(in []byte) []byte { + for b, esc := range measurementEscapeCodes { + in = bytes.Replace(in, esc, []byte{b}, -1) + } + return in +} + +func escapeTag(in []byte) []byte { + for b, esc := range tagEscapeCodes { + if bytes.IndexByte(in, b) != -1 { + in = bytes.Replace(in, []byte{b}, esc, -1) + } + } + return in +} + +func unescapeTag(in []byte) []byte { + if bytes.IndexByte(in, '\\') == -1 { + return in + } + + for b, esc := range tagEscapeCodes { + if bytes.IndexByte(in, b) != -1 { + in = bytes.Replace(in, esc, []byte{b}, -1) + } + } + return in +} + +// escapeStringFieldReplacer replaces double quotes and backslashes +// with the same character preceded by a backslash. +// As of Go 1.7 this benchmarked better in allocations and CPU time +// compared to iterating through a string byte-by-byte and appending to a new byte slice, +// calling strings.Replace twice, and better than (*Regex).ReplaceAllString. +var escapeStringFieldReplacer = strings.NewReplacer(`"`, `\"`, `\`, `\\`) + +// EscapeStringField returns a copy of in with any double quotes or +// backslashes with escaped values. +func EscapeStringField(in string) string { + return escapeStringFieldReplacer.Replace(in) +} + +// unescapeStringField returns a copy of in with any escaped double-quotes +// or backslashes unescaped. +func unescapeStringField(in string) string { + if strings.IndexByte(in, '\\') == -1 { + return in + } + + var out []byte + i := 0 + for { + if i >= len(in) { + break + } + // unescape backslashes + if in[i] == '\\' && i+1 < len(in) && in[i+1] == '\\' { + out = append(out, '\\') + i += 2 + continue + } + // unescape double-quotes + if in[i] == '\\' && i+1 < len(in) && in[i+1] == '"' { + out = append(out, '"') + i += 2 + continue + } + out = append(out, in[i]) + i++ + + } + return string(out) +} + +// NewPoint returns a new point with the given measurement name, tags, fields and timestamp. If +// an unsupported field value (NaN) or out of range time is passed, this function returns an error. +func NewPoint(name string, tags Tags, fields Fields, t time.Time) (Point, error) { + key, err := pointKey(name, tags, fields, t) + if err != nil { + return nil, err + } + + return &point{ + key: key, + time: t, + fields: fields.MarshalBinary(), + }, nil +} + +// pointKey checks some basic requirements for valid points, and returns the +// key, along with an possible error. +func pointKey(measurement string, tags Tags, fields Fields, t time.Time) ([]byte, error) { + if len(fields) == 0 { + return nil, ErrPointMustHaveAField + } + + if !t.IsZero() { + if err := CheckTime(t); err != nil { + return nil, err + } + } + + for key, value := range fields { + switch value := value.(type) { + case float64: + // Ensure the caller validates and handles invalid field values + if math.IsNaN(value) { + return nil, fmt.Errorf("NaN is an unsupported value for field %s", key) + } + case float32: + // Ensure the caller validates and handles invalid field values + if math.IsNaN(float64(value)) { + return nil, fmt.Errorf("NaN is an unsupported value for field %s", key) + } + } + if len(key) == 0 { + return nil, fmt.Errorf("all fields must have non-empty names") + } + } + + key := MakeKey([]byte(measurement), tags) + for field := range fields { + sz := seriesKeySize(key, []byte(field)) + if sz > MaxKeyLength { + return nil, fmt.Errorf("max key length exceeded: %v > %v", sz, MaxKeyLength) + } + } + + return key, nil +} + +func seriesKeySize(key, field []byte) int { + // 4 is the length of the tsm1.fieldKeySeparator constant. It's inlined here to avoid a circular + // dependency. + return len(key) + 4 + len(field) +} + +// NewPointFromBytes returns a new Point from a marshalled Point. +func NewPointFromBytes(b []byte) (Point, error) { + p := &point{} + if err := p.UnmarshalBinary(b); err != nil { + return nil, err + } + + // This does some basic validation to ensure there are fields and they + // can be unmarshalled as well. + iter := p.FieldIterator() + var hasField bool + for iter.Next() { + if len(iter.FieldKey()) == 0 { + continue + } + hasField = true + switch iter.Type() { + case Float: + _, err := iter.FloatValue() + if err != nil { + return nil, fmt.Errorf("unable to unmarshal field %s: %s", string(iter.FieldKey()), err) + } + case Integer: + _, err := iter.IntegerValue() + if err != nil { + return nil, fmt.Errorf("unable to unmarshal field %s: %s", string(iter.FieldKey()), err) + } + case Unsigned: + _, err := iter.UnsignedValue() + if err != nil { + return nil, fmt.Errorf("unable to unmarshal field %s: %s", string(iter.FieldKey()), err) + } + case String: + // Skip since this won't return an error + case Boolean: + _, err := iter.BooleanValue() + if err != nil { + return nil, fmt.Errorf("unable to unmarshal field %s: %s", string(iter.FieldKey()), err) + } + } + } + + if !hasField { + return nil, ErrPointMustHaveAField + } + + return p, nil +} + +// MustNewPoint returns a new point with the given measurement name, tags, fields and timestamp. If +// an unsupported field value (NaN) is passed, this function panics. +func MustNewPoint(name string, tags Tags, fields Fields, time time.Time) Point { + pt, err := NewPoint(name, tags, fields, time) + if err != nil { + panic(err.Error()) + } + return pt +} + +// Key returns the key (measurement joined with tags) of the point. +func (p *point) Key() []byte { + return p.key +} + +func (p *point) name() []byte { + _, name := scanTo(p.key, 0, ',') + return name +} + +func (p *point) Name() []byte { + return escape.Unescape(p.name()) +} + +// SetName updates the measurement name for the point. +func (p *point) SetName(name string) { + p.cachedName = "" + p.key = MakeKey([]byte(name), p.Tags()) +} + +// Time return the timestamp for the point. +func (p *point) Time() time.Time { + return p.time +} + +// SetTime updates the timestamp for the point. +func (p *point) SetTime(t time.Time) { + p.time = t +} + +// Round will round the timestamp of the point to the given duration. +func (p *point) Round(d time.Duration) { + p.time = p.time.Round(d) +} + +// Tags returns the tag set for the point. +func (p *point) Tags() Tags { + if p.cachedTags != nil { + return p.cachedTags + } + p.cachedTags = parseTags(p.key) + return p.cachedTags +} + +func (p *point) HasTag(tag []byte) bool { + if len(p.key) == 0 { + return false + } + + var exists bool + walkTags(p.key, func(key, value []byte) bool { + if bytes.Equal(tag, key) { + exists = true + return false + } + return true + }) + + return exists +} + +func walkTags(buf []byte, fn func(key, value []byte) bool) { + if len(buf) == 0 { + return + } + + pos, name := scanTo(buf, 0, ',') + + // it's an empty key, so there are no tags + if len(name) == 0 { + return + } + + hasEscape := bytes.IndexByte(buf, '\\') != -1 + i := pos + 1 + var key, value []byte + for { + if i >= len(buf) { + break + } + i, key = scanTo(buf, i, '=') + i, value = scanTagValue(buf, i+1) + + if len(value) == 0 { + continue + } + + if hasEscape { + if !fn(unescapeTag(key), unescapeTag(value)) { + return + } + } else { + if !fn(key, value) { + return + } + } + + i++ + } +} + +// walkFields walks each field key and value via fn. If fn returns false, the iteration +// is stopped. The values are the raw byte slices and not the converted types. +func walkFields(buf []byte, fn func(key, value []byte) bool) { + var i int + var key, val []byte + for len(buf) > 0 { + i, key = scanTo(buf, 0, '=') + buf = buf[i+1:] + i, val = scanFieldValue(buf, 0) + buf = buf[i:] + if !fn(key, val) { + break + } + + // slice off comma + if len(buf) > 0 { + buf = buf[1:] + } + } +} + +func parseTags(buf []byte) Tags { + if len(buf) == 0 { + return nil + } + + tags := make(Tags, bytes.Count(buf, []byte(","))) + p := 0 + walkTags(buf, func(key, value []byte) bool { + tags[p].Key = key + tags[p].Value = value + p++ + return true + }) + return tags +} + +// MakeKey creates a key for a set of tags. +func MakeKey(name []byte, tags Tags) []byte { + // unescape the name and then re-escape it to avoid double escaping. + // The key should always be stored in escaped form. + return append(EscapeMeasurement(unescapeMeasurement(name)), tags.HashKey()...) +} + +// SetTags replaces the tags for the point. +func (p *point) SetTags(tags Tags) { + p.key = MakeKey(p.Name(), tags) + p.cachedTags = tags +} + +// AddTag adds or replaces a tag value for a point. +func (p *point) AddTag(key, value string) { + tags := p.Tags() + tags = append(tags, Tag{Key: []byte(key), Value: []byte(value)}) + sort.Sort(tags) + p.cachedTags = tags + p.key = MakeKey(p.Name(), tags) +} + +// Fields returns the fields for the point. +func (p *point) Fields() (Fields, error) { + if p.cachedFields != nil { + return p.cachedFields, nil + } + cf, err := p.unmarshalBinary() + if err != nil { + return nil, err + } + p.cachedFields = cf + return p.cachedFields, nil +} + +// SetPrecision will round a time to the specified precision. +func (p *point) SetPrecision(precision string) { + switch precision { + case "n": + case "u": + p.SetTime(p.Time().Truncate(time.Microsecond)) + case "ms": + p.SetTime(p.Time().Truncate(time.Millisecond)) + case "s": + p.SetTime(p.Time().Truncate(time.Second)) + case "m": + p.SetTime(p.Time().Truncate(time.Minute)) + case "h": + p.SetTime(p.Time().Truncate(time.Hour)) + } +} + +// String returns the string representation of the point. +func (p *point) String() string { + if p.Time().IsZero() { + return string(p.Key()) + " " + string(p.fields) + } + return string(p.Key()) + " " + string(p.fields) + " " + strconv.FormatInt(p.UnixNano(), 10) +} + +// AppendString appends the string representation of the point to buf. +func (p *point) AppendString(buf []byte) []byte { + buf = append(buf, p.key...) + buf = append(buf, ' ') + buf = append(buf, p.fields...) + + if !p.time.IsZero() { + buf = append(buf, ' ') + buf = strconv.AppendInt(buf, p.UnixNano(), 10) + } + + return buf +} + +// StringSize returns the length of the string that would be returned by String(). +func (p *point) StringSize() int { + size := len(p.key) + len(p.fields) + 1 + + if !p.time.IsZero() { + digits := 1 // even "0" has one digit + t := p.UnixNano() + if t < 0 { + // account for negative sign, then negate + digits++ + t = -t + } + for t > 9 { // already accounted for one digit + digits++ + t /= 10 + } + size += digits + 1 // digits and a space + } + + return size +} + +// MarshalBinary returns a binary representation of the point. +func (p *point) MarshalBinary() ([]byte, error) { + if len(p.fields) == 0 { + return nil, ErrPointMustHaveAField + } + + tb, err := p.time.MarshalBinary() + if err != nil { + return nil, err + } + + b := make([]byte, 8+len(p.key)+len(p.fields)+len(tb)) + i := 0 + + binary.BigEndian.PutUint32(b[i:], uint32(len(p.key))) + i += 4 + + i += copy(b[i:], p.key) + + binary.BigEndian.PutUint32(b[i:i+4], uint32(len(p.fields))) + i += 4 + + i += copy(b[i:], p.fields) + + copy(b[i:], tb) + return b, nil +} + +// UnmarshalBinary decodes a binary representation of the point into a point struct. +func (p *point) UnmarshalBinary(b []byte) error { + var n int + + // Read key length. + if len(b) < 4 { + return io.ErrShortBuffer + } + n, b = int(binary.BigEndian.Uint32(b[:4])), b[4:] + + // Read key. + if len(b) < n { + return io.ErrShortBuffer + } + p.key, b = b[:n], b[n:] + + // Read fields length. + if len(b) < 4 { + return io.ErrShortBuffer + } + n, b = int(binary.BigEndian.Uint32(b[:4])), b[4:] + + // Read fields. + if len(b) < n { + return io.ErrShortBuffer + } + p.fields, b = b[:n], b[n:] + + // Read timestamp. + if err := p.time.UnmarshalBinary(b); err != nil { + return err + } + return nil +} + +// PrecisionString returns a string representation of the point. If there +// is a timestamp associated with the point then it will be specified in the +// given unit. +func (p *point) PrecisionString(precision string) string { + if p.Time().IsZero() { + return fmt.Sprintf("%s %s", p.Key(), string(p.fields)) + } + return fmt.Sprintf("%s %s %d", p.Key(), string(p.fields), + p.UnixNano()/GetPrecisionMultiplier(precision)) +} + +// RoundedString returns a string representation of the point. If there +// is a timestamp associated with the point, then it will be rounded to the +// given duration. +func (p *point) RoundedString(d time.Duration) string { + if p.Time().IsZero() { + return fmt.Sprintf("%s %s", p.Key(), string(p.fields)) + } + return fmt.Sprintf("%s %s %d", p.Key(), string(p.fields), + p.time.Round(d).UnixNano()) +} + +func (p *point) unmarshalBinary() (Fields, error) { + iter := p.FieldIterator() + fields := make(Fields, 8) + for iter.Next() { + if len(iter.FieldKey()) == 0 { + continue + } + switch iter.Type() { + case Float: + v, err := iter.FloatValue() + if err != nil { + return nil, fmt.Errorf("unable to unmarshal field %s: %s", string(iter.FieldKey()), err) + } + fields[string(iter.FieldKey())] = v + case Integer: + v, err := iter.IntegerValue() + if err != nil { + return nil, fmt.Errorf("unable to unmarshal field %s: %s", string(iter.FieldKey()), err) + } + fields[string(iter.FieldKey())] = v + case Unsigned: + v, err := iter.UnsignedValue() + if err != nil { + return nil, fmt.Errorf("unable to unmarshal field %s: %s", string(iter.FieldKey()), err) + } + fields[string(iter.FieldKey())] = v + case String: + fields[string(iter.FieldKey())] = iter.StringValue() + case Boolean: + v, err := iter.BooleanValue() + if err != nil { + return nil, fmt.Errorf("unable to unmarshal field %s: %s", string(iter.FieldKey()), err) + } + fields[string(iter.FieldKey())] = v + } + } + return fields, nil +} + +// HashID returns a non-cryptographic checksum of the point's key. +func (p *point) HashID() uint64 { + h := NewInlineFNV64a() + h.Write(p.key) + sum := h.Sum64() + return sum +} + +// UnixNano returns the timestamp of the point as nanoseconds since Unix epoch. +func (p *point) UnixNano() int64 { + return p.Time().UnixNano() +} + +// Split will attempt to return multiple points with the same timestamp whose +// string representations are no longer than size. Points with a single field or +// a point without a timestamp may exceed the requested size. +func (p *point) Split(size int) []Point { + if p.time.IsZero() || p.StringSize() <= size { + return []Point{p} + } + + // key string, timestamp string, spaces + size -= len(p.key) + len(strconv.FormatInt(p.time.UnixNano(), 10)) + 2 + + var points []Point + var start, cur int + + for cur < len(p.fields) { + end, _ := scanTo(p.fields, cur, '=') + end, _ = scanFieldValue(p.fields, end+1) + + if cur > start && end-start > size { + points = append(points, &point{ + key: p.key, + time: p.time, + fields: p.fields[start : cur-1], + }) + start = cur + } + + cur = end + 1 + } + + points = append(points, &point{ + key: p.key, + time: p.time, + fields: p.fields[start:], + }) + + return points +} + +// Tag represents a single key/value tag pair. +type Tag struct { + Key []byte + Value []byte +} + +// NewTag returns a new Tag. +func NewTag(key, value []byte) Tag { + return Tag{ + Key: key, + Value: value, + } +} + +// Size returns the size of the key and value. +func (t Tag) Size() int { return len(t.Key) + len(t.Value) } + +// Clone returns a shallow copy of Tag. +// +// Tags associated with a Point created by ParsePointsWithPrecision will hold references to the byte slice that was parsed. +// Use Clone to create a Tag with new byte slices that do not refer to the argument to ParsePointsWithPrecision. +func (t Tag) Clone() Tag { + other := Tag{ + Key: make([]byte, len(t.Key)), + Value: make([]byte, len(t.Value)), + } + + copy(other.Key, t.Key) + copy(other.Value, t.Value) + + return other +} + +// String returns the string reprsentation of the tag. +func (t *Tag) String() string { + var buf bytes.Buffer + buf.WriteByte('{') + buf.WriteString(string(t.Key)) + buf.WriteByte(' ') + buf.WriteString(string(t.Value)) + buf.WriteByte('}') + return buf.String() +} + +// Tags represents a sorted list of tags. +type Tags []Tag + +// NewTags returns a new Tags from a map. +func NewTags(m map[string]string) Tags { + if len(m) == 0 { + return nil + } + a := make(Tags, 0, len(m)) + for k, v := range m { + a = append(a, NewTag([]byte(k), []byte(v))) + } + sort.Sort(a) + return a +} + +// Keys returns the list of keys for a tag set. +func (a Tags) Keys() []string { + if len(a) == 0 { + return nil + } + keys := make([]string, len(a)) + for i, tag := range a { + keys[i] = string(tag.Key) + } + return keys +} + +// Values returns the list of values for a tag set. +func (a Tags) Values() []string { + if len(a) == 0 { + return nil + } + values := make([]string, len(a)) + for i, tag := range a { + values[i] = string(tag.Value) + } + return values +} + +// String returns the string representation of the tags. +func (a Tags) String() string { + var buf bytes.Buffer + buf.WriteByte('[') + for i := range a { + buf.WriteString(a[i].String()) + if i < len(a)-1 { + buf.WriteByte(' ') + } + } + buf.WriteByte(']') + return buf.String() +} + +// Size returns the number of bytes needed to store all tags. Note, this is +// the number of bytes needed to store all keys and values and does not account +// for data structures or delimiters for example. +func (a Tags) Size() int { + var total int + for _, t := range a { + total += t.Size() + } + return total +} + +// Clone returns a copy of the slice where the elements are a result of calling `Clone` on the original elements +// +// Tags associated with a Point created by ParsePointsWithPrecision will hold references to the byte slice that was parsed. +// Use Clone to create Tags with new byte slices that do not refer to the argument to ParsePointsWithPrecision. +func (a Tags) Clone() Tags { + if len(a) == 0 { + return nil + } + + others := make(Tags, len(a)) + for i := range a { + others[i] = a[i].Clone() + } + + return others +} + +func (a Tags) Len() int { return len(a) } +func (a Tags) Less(i, j int) bool { return bytes.Compare(a[i].Key, a[j].Key) == -1 } +func (a Tags) Swap(i, j int) { a[i], a[j] = a[j], a[i] } + +// Equal returns true if a equals other. +func (a Tags) Equal(other Tags) bool { + if len(a) != len(other) { + return false + } + for i := range a { + if !bytes.Equal(a[i].Key, other[i].Key) || !bytes.Equal(a[i].Value, other[i].Value) { + return false + } + } + return true +} + +// CompareTags returns -1 if a < b, 1 if a > b, and 0 if a == b. +func CompareTags(a, b Tags) int { + // Compare each key & value until a mismatch. + for i := 0; i < len(a) && i < len(b); i++ { + if cmp := bytes.Compare(a[i].Key, b[i].Key); cmp != 0 { + return cmp + } + if cmp := bytes.Compare(a[i].Value, b[i].Value); cmp != 0 { + return cmp + } + } + + // If all tags are equal up to this point then return shorter tagset. + if len(a) < len(b) { + return -1 + } else if len(a) > len(b) { + return 1 + } + + // All tags are equal. + return 0 +} + +// Get returns the value for a key. +func (a Tags) Get(key []byte) []byte { + // OPTIMIZE: Use sort.Search if tagset is large. + + for _, t := range a { + if bytes.Equal(t.Key, key) { + return t.Value + } + } + return nil +} + +// GetString returns the string value for a string key. +func (a Tags) GetString(key string) string { + return string(a.Get([]byte(key))) +} + +// Set sets the value for a key. +func (a *Tags) Set(key, value []byte) { + for i, t := range *a { + if bytes.Equal(t.Key, key) { + (*a)[i].Value = value + return + } + } + *a = append(*a, Tag{Key: key, Value: value}) + sort.Sort(*a) +} + +// SetString sets the string value for a string key. +func (a *Tags) SetString(key, value string) { + a.Set([]byte(key), []byte(value)) +} + +// Delete removes a tag by key. +func (a *Tags) Delete(key []byte) { + for i, t := range *a { + if bytes.Equal(t.Key, key) { + copy((*a)[i:], (*a)[i+1:]) + (*a)[len(*a)-1] = Tag{} + *a = (*a)[:len(*a)-1] + return + } + } +} + +// Map returns a map representation of the tags. +func (a Tags) Map() map[string]string { + m := make(map[string]string, len(a)) + for _, t := range a { + m[string(t.Key)] = string(t.Value) + } + return m +} + +// Merge merges the tags combining the two. If both define a tag with the +// same key, the merged value overwrites the old value. +// A new map is returned. +func (a Tags) Merge(other map[string]string) Tags { + merged := make(map[string]string, len(a)+len(other)) + for _, t := range a { + merged[string(t.Key)] = string(t.Value) + } + for k, v := range other { + merged[k] = v + } + return NewTags(merged) +} + +// HashKey hashes all of a tag's keys. +func (a Tags) HashKey() []byte { + // Empty maps marshal to empty bytes. + if len(a) == 0 { + return nil + } + + // Type invariant: Tags are sorted + + escaped := make(Tags, 0, len(a)) + sz := 0 + for _, t := range a { + ek := escapeTag(t.Key) + ev := escapeTag(t.Value) + + if len(ev) > 0 { + escaped = append(escaped, Tag{Key: ek, Value: ev}) + sz += len(ek) + len(ev) + } + } + + sz += len(escaped) + (len(escaped) * 2) // separators + + // Generate marshaled bytes. + b := make([]byte, sz) + buf := b + idx := 0 + for _, k := range escaped { + buf[idx] = ',' + idx++ + copy(buf[idx:idx+len(k.Key)], k.Key) + idx += len(k.Key) + buf[idx] = '=' + idx++ + copy(buf[idx:idx+len(k.Value)], k.Value) + idx += len(k.Value) + } + return b[:idx] +} + +// CopyTags returns a shallow copy of tags. +func CopyTags(a Tags) Tags { + other := make(Tags, len(a)) + copy(other, a) + return other +} + +// DeepCopyTags returns a deep copy of tags. +func DeepCopyTags(a Tags) Tags { + // Calculate size of keys/values in bytes. + var n int + for _, t := range a { + n += len(t.Key) + len(t.Value) + } + + // Build single allocation for all key/values. + buf := make([]byte, n) + + // Copy tags to new set. + other := make(Tags, len(a)) + for i, t := range a { + copy(buf, t.Key) + other[i].Key, buf = buf[:len(t.Key)], buf[len(t.Key):] + + copy(buf, t.Value) + other[i].Value, buf = buf[:len(t.Value)], buf[len(t.Value):] + } + + return other +} + +// Fields represents a mapping between a Point's field names and their +// values. +type Fields map[string]interface{} + +// FieldIterator retuns a FieldIterator that can be used to traverse the +// fields of a point without constructing the in-memory map. +func (p *point) FieldIterator() FieldIterator { + p.Reset() + return p +} + +type fieldIterator struct { + start, end int + key, keybuf []byte + valueBuf []byte + fieldType FieldType +} + +// Next indicates whether there any fields remaining. +func (p *point) Next() bool { + p.it.start = p.it.end + if p.it.start >= len(p.fields) { + return false + } + + p.it.end, p.it.key = scanTo(p.fields, p.it.start, '=') + if escape.IsEscaped(p.it.key) { + p.it.keybuf = escape.AppendUnescaped(p.it.keybuf[:0], p.it.key) + p.it.key = p.it.keybuf + } + + p.it.end, p.it.valueBuf = scanFieldValue(p.fields, p.it.end+1) + p.it.end++ + + if len(p.it.valueBuf) == 0 { + p.it.fieldType = Empty + return true + } + + c := p.it.valueBuf[0] + + if c == '"' { + p.it.fieldType = String + return true + } + + if strings.IndexByte(`0123456789-.nNiIu`, c) >= 0 { + if p.it.valueBuf[len(p.it.valueBuf)-1] == 'i' { + p.it.fieldType = Integer + p.it.valueBuf = p.it.valueBuf[:len(p.it.valueBuf)-1] + } else if p.it.valueBuf[len(p.it.valueBuf)-1] == 'u' { + p.it.fieldType = Unsigned + p.it.valueBuf = p.it.valueBuf[:len(p.it.valueBuf)-1] + } else { + p.it.fieldType = Float + } + return true + } + + // to keep the same behavior that currently exists, default to boolean + p.it.fieldType = Boolean + return true +} + +// FieldKey returns the key of the current field. +func (p *point) FieldKey() []byte { + return p.it.key +} + +// Type returns the FieldType of the current field. +func (p *point) Type() FieldType { + return p.it.fieldType +} + +// StringValue returns the string value of the current field. +func (p *point) StringValue() string { + return unescapeStringField(string(p.it.valueBuf[1 : len(p.it.valueBuf)-1])) +} + +// IntegerValue returns the integer value of the current field. +func (p *point) IntegerValue() (int64, error) { + n, err := parseIntBytes(p.it.valueBuf, 10, 64) + if err != nil { + return 0, fmt.Errorf("unable to parse integer value %q: %v", p.it.valueBuf, err) + } + return n, nil +} + +// UnsignedValue returns the unsigned value of the current field. +func (p *point) UnsignedValue() (uint64, error) { + n, err := parseUintBytes(p.it.valueBuf, 10, 64) + if err != nil { + return 0, fmt.Errorf("unable to parse unsigned value %q: %v", p.it.valueBuf, err) + } + return n, nil +} + +// BooleanValue returns the boolean value of the current field. +func (p *point) BooleanValue() (bool, error) { + b, err := parseBoolBytes(p.it.valueBuf) + if err != nil { + return false, fmt.Errorf("unable to parse bool value %q: %v", p.it.valueBuf, err) + } + return b, nil +} + +// FloatValue returns the float value of the current field. +func (p *point) FloatValue() (float64, error) { + f, err := parseFloatBytes(p.it.valueBuf, 64) + if err != nil { + return 0, fmt.Errorf("unable to parse floating point value %q: %v", p.it.valueBuf, err) + } + return f, nil +} + +// Reset resets the iterator to its initial state. +func (p *point) Reset() { + p.it.fieldType = Empty + p.it.key = nil + p.it.valueBuf = nil + p.it.start = 0 + p.it.end = 0 +} + +// MarshalBinary encodes all the fields to their proper type and returns the binary +// represenation +// NOTE: uint64 is specifically not supported due to potential overflow when we decode +// again later to an int64 +// NOTE2: uint is accepted, and may be 64 bits, and is for some reason accepted... +func (p Fields) MarshalBinary() []byte { + var b []byte + keys := make([]string, 0, len(p)) + + for k := range p { + keys = append(keys, k) + } + + // Not really necessary, can probably be removed. + sort.Strings(keys) + + for i, k := range keys { + if i > 0 { + b = append(b, ',') + } + b = appendField(b, k, p[k]) + } + + return b +} + +func appendField(b []byte, k string, v interface{}) []byte { + b = append(b, []byte(escape.String(k))...) + b = append(b, '=') + + // check popular types first + switch v := v.(type) { + case float64: + b = strconv.AppendFloat(b, v, 'f', -1, 64) + case int64: + b = strconv.AppendInt(b, v, 10) + b = append(b, 'i') + case string: + b = append(b, '"') + b = append(b, []byte(EscapeStringField(v))...) + b = append(b, '"') + case bool: + b = strconv.AppendBool(b, v) + case int32: + b = strconv.AppendInt(b, int64(v), 10) + b = append(b, 'i') + case int16: + b = strconv.AppendInt(b, int64(v), 10) + b = append(b, 'i') + case int8: + b = strconv.AppendInt(b, int64(v), 10) + b = append(b, 'i') + case int: + b = strconv.AppendInt(b, int64(v), 10) + b = append(b, 'i') + case uint64: + b = strconv.AppendUint(b, v, 10) + b = append(b, 'u') + case uint32: + b = strconv.AppendInt(b, int64(v), 10) + b = append(b, 'i') + case uint16: + b = strconv.AppendInt(b, int64(v), 10) + b = append(b, 'i') + case uint8: + b = strconv.AppendInt(b, int64(v), 10) + b = append(b, 'i') + case uint: + // TODO: 'uint' should be converted to writing as an unsigned integer, + // but we cannot since that would break backwards compatibility. + b = strconv.AppendInt(b, int64(v), 10) + b = append(b, 'i') + case float32: + b = strconv.AppendFloat(b, float64(v), 'f', -1, 32) + case []byte: + b = append(b, v...) + case nil: + // skip + default: + // Can't determine the type, so convert to string + b = append(b, '"') + b = append(b, []byte(EscapeStringField(fmt.Sprintf("%v", v)))...) + b = append(b, '"') + + } + + return b +} + +type byteSlices [][]byte + +func (a byteSlices) Len() int { return len(a) } +func (a byteSlices) Less(i, j int) bool { return bytes.Compare(a[i], a[j]) == -1 } +func (a byteSlices) Swap(i, j int) { a[i], a[j] = a[j], a[i] } diff --git a/vendor/github.com/influxdata/influxdb/models/rows.go b/vendor/github.com/influxdata/influxdb/models/rows.go new file mode 100644 index 0000000000..c087a4882d --- /dev/null +++ b/vendor/github.com/influxdata/influxdb/models/rows.go @@ -0,0 +1,62 @@ +package models + +import ( + "sort" +) + +// Row represents a single row returned from the execution of a statement. +type Row struct { + Name string `json:"name,omitempty"` + Tags map[string]string `json:"tags,omitempty"` + Columns []string `json:"columns,omitempty"` + Values [][]interface{} `json:"values,omitempty"` + Partial bool `json:"partial,omitempty"` +} + +// SameSeries returns true if r contains values for the same series as o. +func (r *Row) SameSeries(o *Row) bool { + return r.tagsHash() == o.tagsHash() && r.Name == o.Name +} + +// tagsHash returns a hash of tag key/value pairs. +func (r *Row) tagsHash() uint64 { + h := NewInlineFNV64a() + keys := r.tagsKeys() + for _, k := range keys { + h.Write([]byte(k)) + h.Write([]byte(r.Tags[k])) + } + return h.Sum64() +} + +// tagKeys returns a sorted list of tag keys. +func (r *Row) tagsKeys() []string { + a := make([]string, 0, len(r.Tags)) + for k := range r.Tags { + a = append(a, k) + } + sort.Strings(a) + return a +} + +// Rows represents a collection of rows. Rows implements sort.Interface. +type Rows []*Row + +// Len implements sort.Interface. +func (p Rows) Len() int { return len(p) } + +// Less implements sort.Interface. +func (p Rows) Less(i, j int) bool { + // Sort by name first. + if p[i].Name != p[j].Name { + return p[i].Name < p[j].Name + } + + // Sort by tag set hash. Tags don't have a meaningful sort order so we + // just compute a hash and sort by that instead. This allows the tests + // to receive rows in a predictable order every time. + return p[i].tagsHash() < p[j].tagsHash() +} + +// Swap implements sort.Interface. +func (p Rows) Swap(i, j int) { p[i], p[j] = p[j], p[i] } diff --git a/vendor/github.com/influxdata/influxdb/models/statistic.go b/vendor/github.com/influxdata/influxdb/models/statistic.go new file mode 100644 index 0000000000..553e9d09fb --- /dev/null +++ b/vendor/github.com/influxdata/influxdb/models/statistic.go @@ -0,0 +1,42 @@ +package models + +// Statistic is the representation of a statistic used by the monitoring service. +type Statistic struct { + Name string `json:"name"` + Tags map[string]string `json:"tags"` + Values map[string]interface{} `json:"values"` +} + +// NewStatistic returns an initialized Statistic. +func NewStatistic(name string) Statistic { + return Statistic{ + Name: name, + Tags: make(map[string]string), + Values: make(map[string]interface{}), + } +} + +// StatisticTags is a map that can be merged with others without causing +// mutations to either map. +type StatisticTags map[string]string + +// Merge creates a new map containing the merged contents of tags and t. +// If both tags and the receiver map contain the same key, the value in tags +// is used in the resulting map. +// +// Merge always returns a usable map. +func (t StatisticTags) Merge(tags map[string]string) map[string]string { + // Add everything in tags to the result. + out := make(map[string]string, len(tags)) + for k, v := range tags { + out[k] = v + } + + // Only add values from t that don't appear in tags. + for k, v := range t { + if _, ok := tags[k]; !ok { + out[k] = v + } + } + return out +} diff --git a/vendor/github.com/influxdata/influxdb/models/time.go b/vendor/github.com/influxdata/influxdb/models/time.go new file mode 100644 index 0000000000..e98f2cb336 --- /dev/null +++ b/vendor/github.com/influxdata/influxdb/models/time.go @@ -0,0 +1,74 @@ +package models + +// Helper time methods since parsing time can easily overflow and we only support a +// specific time range. + +import ( + "fmt" + "math" + "time" +) + +const ( + // MinNanoTime is the minumum time that can be represented. + // + // 1677-09-21 00:12:43.145224194 +0000 UTC + // + // The two lowest minimum integers are used as sentinel values. The + // minimum value needs to be used as a value lower than any other value for + // comparisons and another separate value is needed to act as a sentinel + // default value that is unusable by the user, but usable internally. + // Because these two values need to be used for a special purpose, we do + // not allow users to write points at these two times. + MinNanoTime = int64(math.MinInt64) + 2 + + // MaxNanoTime is the maximum time that can be represented. + // + // 2262-04-11 23:47:16.854775806 +0000 UTC + // + // The highest time represented by a nanosecond needs to be used for an + // exclusive range in the shard group, so the maximum time needs to be one + // less than the possible maximum number of nanoseconds representable by an + // int64 so that we don't lose a point at that one time. + MaxNanoTime = int64(math.MaxInt64) - 1 +) + +var ( + minNanoTime = time.Unix(0, MinNanoTime).UTC() + maxNanoTime = time.Unix(0, MaxNanoTime).UTC() + + // ErrTimeOutOfRange gets returned when time is out of the representable range using int64 nanoseconds since the epoch. + ErrTimeOutOfRange = fmt.Errorf("time outside range %d - %d", MinNanoTime, MaxNanoTime) +) + +// SafeCalcTime safely calculates the time given. Will return error if the time is outside the +// supported range. +func SafeCalcTime(timestamp int64, precision string) (time.Time, error) { + mult := GetPrecisionMultiplier(precision) + if t, ok := safeSignedMult(timestamp, mult); ok { + tme := time.Unix(0, t).UTC() + return tme, CheckTime(tme) + } + + return time.Time{}, ErrTimeOutOfRange +} + +// CheckTime checks that a time is within the safe range. +func CheckTime(t time.Time) error { + if t.Before(minNanoTime) || t.After(maxNanoTime) { + return ErrTimeOutOfRange + } + return nil +} + +// Perform the multiplication and check to make sure it didn't overflow. +func safeSignedMult(a, b int64) (int64, bool) { + if a == 0 || b == 0 || a == 1 || b == 1 { + return a * b, true + } + if a == MinNanoTime || b == MaxNanoTime { + return 0, false + } + c := a * b + return c, c/b == a +} diff --git a/vendor/github.com/influxdata/influxdb/models/uint_support.go b/vendor/github.com/influxdata/influxdb/models/uint_support.go new file mode 100644 index 0000000000..18d1ca06e2 --- /dev/null +++ b/vendor/github.com/influxdata/influxdb/models/uint_support.go @@ -0,0 +1,7 @@ +// +build uint uint64 + +package models + +func init() { + EnableUintSupport() +} diff --git a/vendor/github.com/influxdata/influxdb/pkg/escape/bytes.go b/vendor/github.com/influxdata/influxdb/pkg/escape/bytes.go new file mode 100644 index 0000000000..f3b31f42d3 --- /dev/null +++ b/vendor/github.com/influxdata/influxdb/pkg/escape/bytes.go @@ -0,0 +1,115 @@ +// Package escape contains utilities for escaping parts of InfluxQL +// and InfluxDB line protocol. +package escape // import "github.com/influxdata/influxdb/pkg/escape" + +import ( + "bytes" + "strings" +) + +// Codes is a map of bytes to be escaped. +var Codes = map[byte][]byte{ + ',': []byte(`\,`), + '"': []byte(`\"`), + ' ': []byte(`\ `), + '=': []byte(`\=`), +} + +// Bytes escapes characters on the input slice, as defined by Codes. +func Bytes(in []byte) []byte { + for b, esc := range Codes { + in = bytes.Replace(in, []byte{b}, esc, -1) + } + return in +} + +const escapeChars = `," =` + +// IsEscaped returns whether b has any escaped characters, +// i.e. whether b seems to have been processed by Bytes. +func IsEscaped(b []byte) bool { + for len(b) > 0 { + i := bytes.IndexByte(b, '\\') + if i < 0 { + return false + } + + if i+1 < len(b) && strings.IndexByte(escapeChars, b[i+1]) >= 0 { + return true + } + b = b[i+1:] + } + return false +} + +// AppendUnescaped appends the unescaped version of src to dst +// and returns the resulting slice. +func AppendUnescaped(dst, src []byte) []byte { + var pos int + for len(src) > 0 { + next := bytes.IndexByte(src[pos:], '\\') + if next < 0 || pos+next+1 >= len(src) { + return append(dst, src...) + } + + if pos+next+1 < len(src) && strings.IndexByte(escapeChars, src[pos+next+1]) >= 0 { + if pos+next > 0 { + dst = append(dst, src[:pos+next]...) + } + src = src[pos+next+1:] + pos = 0 + } else { + pos += next + 1 + } + } + + return dst +} + +// Unescape returns a new slice containing the unescaped version of in. +func Unescape(in []byte) []byte { + if len(in) == 0 { + return nil + } + + if bytes.IndexByte(in, '\\') == -1 { + return in + } + + i := 0 + inLen := len(in) + + // The output size will be no more than inLen. Preallocating the + // capacity of the output is faster and uses less memory than + // letting append() do its own (over)allocation. + out := make([]byte, 0, inLen) + + for { + if i >= inLen { + break + } + if in[i] == '\\' && i+1 < inLen { + switch in[i+1] { + case ',': + out = append(out, ',') + i += 2 + continue + case '"': + out = append(out, '"') + i += 2 + continue + case ' ': + out = append(out, ' ') + i += 2 + continue + case '=': + out = append(out, '=') + i += 2 + continue + } + } + out = append(out, in[i]) + i += 1 + } + return out +} diff --git a/vendor/github.com/influxdata/influxdb/pkg/escape/strings.go b/vendor/github.com/influxdata/influxdb/pkg/escape/strings.go new file mode 100644 index 0000000000..db98033b0d --- /dev/null +++ b/vendor/github.com/influxdata/influxdb/pkg/escape/strings.go @@ -0,0 +1,21 @@ +package escape + +import "strings" + +var ( + escaper = strings.NewReplacer(`,`, `\,`, `"`, `\"`, ` `, `\ `, `=`, `\=`) + unescaper = strings.NewReplacer(`\,`, `,`, `\"`, `"`, `\ `, ` `, `\=`, `=`) +) + +// UnescapeString returns unescaped version of in. +func UnescapeString(in string) string { + if strings.IndexByte(in, '\\') == -1 { + return in + } + return unescaper.Replace(in) +} + +// String returns the escaped version of in. +func String(in string) string { + return escaper.Replace(in) +} diff --git a/vendor/github.com/karalabe/hid/appveyor.yml b/vendor/github.com/karalabe/hid/appveyor.yml index f43958747c..84b3c95ff7 100644 --- a/vendor/github.com/karalabe/hid/appveyor.yml +++ b/vendor/github.com/karalabe/hid/appveyor.yml @@ -22,8 +22,8 @@ environment: install: - rmdir C:\go /s /q - - appveyor DownloadFile https://storage.googleapis.com/golang/go1.8.windows-%GOARCH%.zip - - 7z x go1.8.windows-%GOARCH%.zip -y -oC:\ > NUL + - appveyor DownloadFile https://storage.googleapis.com/golang/go1.10.1.windows-%GOARCH%.zip + - 7z x go1.10.1.windows-%GOARCH%.zip -y -oC:\ > NUL - go version - gcc --version diff --git a/vendor/github.com/karalabe/hid/hid_disabled.go b/vendor/github.com/karalabe/hid/hid_disabled.go index 1f40263791..0f266ba58a 100644 --- a/vendor/github.com/karalabe/hid/hid_disabled.go +++ b/vendor/github.com/karalabe/hid/hid_disabled.go @@ -36,7 +36,7 @@ func (info DeviceInfo) Open() (*Device, error) { // Close releases the HID USB device handle. On platforms that this file implements // the method is just a noop. -func (dev *Device) Close() {} +func (dev *Device) Close() error { return nil } // Write sends an output report to a HID device. On platforms that this file // implements the method just returns an error. diff --git a/vendor/github.com/karalabe/hid/hid_enabled.go b/vendor/github.com/karalabe/hid/hid_enabled.go index 419273be6a..e95e5792d9 100644 --- a/vendor/github.com/karalabe/hid/hid_enabled.go +++ b/vendor/github.com/karalabe/hid/hid_enabled.go @@ -41,6 +41,7 @@ package hid #endif */ import "C" + import ( "errors" "runtime" @@ -57,11 +58,6 @@ import ( // > "subsequent calls will cause the hid manager to release previously enumerated devices" var enumerateLock sync.Mutex -func init() { - // Initialize the HIDAPI library - C.hid_init() -} - // Supported returns whether this platform is supported by the HID library or not. // The goal of this method is to allow programatically handling platforms that do // not support USB HID and not having to fall back to build constraints. @@ -113,6 +109,9 @@ func Enumerate(vendorID uint16, productID uint16) []DeviceInfo { // Open connects to an HID device by its path name. func (info DeviceInfo) Open() (*Device, error) { + enumerateLock.Lock() + defer enumerateLock.Unlock() + path := C.CString(info.Path) defer C.free(unsafe.Pointer(path)) @@ -135,7 +134,7 @@ type Device struct { } // Close releases the HID USB device handle. -func (dev *Device) Close() { +func (dev *Device) Close() error { dev.lock.Lock() defer dev.lock.Unlock() @@ -143,6 +142,7 @@ func (dev *Device) Close() { C.hid_close(dev.device) dev.device = nil } + return nil } // Write sends an output report to a HID device. diff --git a/vendor/github.com/mattn/go-colorable/README.md b/vendor/github.com/mattn/go-colorable/README.md index e84226a735..56729a92ca 100644 --- a/vendor/github.com/mattn/go-colorable/README.md +++ b/vendor/github.com/mattn/go-colorable/README.md @@ -1,5 +1,10 @@ # go-colorable +[![Godoc Reference](https://godoc.org/github.com/mattn/go-colorable?status.svg)](http://godoc.org/github.com/mattn/go-colorable) +[![Build Status](https://travis-ci.org/mattn/go-colorable.svg?branch=master)](https://travis-ci.org/mattn/go-colorable) +[![Coverage Status](https://coveralls.io/repos/github/mattn/go-colorable/badge.svg?branch=master)](https://coveralls.io/github/mattn/go-colorable?branch=master) +[![Go Report Card](https://goreportcard.com/badge/mattn/go-colorable)](https://goreportcard.com/report/mattn/go-colorable) + Colorable writer for windows. For example, most of logger packages doesn't show colors on windows. (I know we can do it with ansicon. But I don't want.) diff --git a/vendor/github.com/mattn/go-colorable/colorable_others.go b/vendor/github.com/mattn/go-colorable/colorable_others.go index a7fe19a8ca..887f203dc7 100644 --- a/vendor/github.com/mattn/go-colorable/colorable_others.go +++ b/vendor/github.com/mattn/go-colorable/colorable_others.go @@ -1,10 +1,13 @@ // +build !windows +// +build !appengine package colorable import ( "io" "os" + + _ "github.com/mattn/go-isatty" ) // NewColorable return new instance of Writer which handle escape sequence. diff --git a/vendor/github.com/mattn/go-colorable/colorable_windows.go b/vendor/github.com/mattn/go-colorable/colorable_windows.go index 628ad904e5..404e10ca02 100644 --- a/vendor/github.com/mattn/go-colorable/colorable_windows.go +++ b/vendor/github.com/mattn/go-colorable/colorable_windows.go @@ -1,3 +1,6 @@ +// +build windows +// +build !appengine + package colorable import ( @@ -26,6 +29,15 @@ const ( backgroundMask = (backgroundRed | backgroundBlue | backgroundGreen | backgroundIntensity) ) +const ( + genericRead = 0x80000000 + genericWrite = 0x40000000 +) + +const ( + consoleTextmodeBuffer = 0x1 +) + type wchar uint16 type short int16 type dword uint32 @@ -65,14 +77,18 @@ var ( procFillConsoleOutputAttribute = kernel32.NewProc("FillConsoleOutputAttribute") procGetConsoleCursorInfo = kernel32.NewProc("GetConsoleCursorInfo") procSetConsoleCursorInfo = kernel32.NewProc("SetConsoleCursorInfo") + procSetConsoleTitle = kernel32.NewProc("SetConsoleTitleW") + procCreateConsoleScreenBuffer = kernel32.NewProc("CreateConsoleScreenBuffer") ) +// Writer provide colorable Writer to the console type Writer struct { - out io.Writer - handle syscall.Handle - lastbuf bytes.Buffer - oldattr word - oldpos coord + out io.Writer + handle syscall.Handle + althandle syscall.Handle + oldattr word + oldpos coord + rest bytes.Buffer } // NewColorable return new instance of Writer which handle escape sequence from File. @@ -86,9 +102,8 @@ func NewColorable(file *os.File) io.Writer { handle := syscall.Handle(file.Fd()) procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) return &Writer{out: file, handle: handle, oldattr: csbi.attributes, oldpos: coord{0, 0}} - } else { - return file } + return file } // NewColorableStdout return new instance of Writer which handle escape sequence for stdout. @@ -360,20 +375,65 @@ var color256 = map[int]int{ 255: 0xeeeeee, } +// `\033]0;TITLESTR\007` +func doTitleSequence(er *bytes.Reader) error { + var c byte + var err error + + c, err = er.ReadByte() + if err != nil { + return err + } + if c != '0' && c != '2' { + return nil + } + c, err = er.ReadByte() + if err != nil { + return err + } + if c != ';' { + return nil + } + title := make([]byte, 0, 80) + for { + c, err = er.ReadByte() + if err != nil { + return err + } + if c == 0x07 || c == '\n' { + break + } + title = append(title, c) + } + if len(title) > 0 { + title8, err := syscall.UTF16PtrFromString(string(title)) + if err == nil { + procSetConsoleTitle.Call(uintptr(unsafe.Pointer(title8))) + } + } + return nil +} + // Write write data on console func (w *Writer) Write(data []byte) (n int, err error) { var csbi consoleScreenBufferInfo procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) - er := bytes.NewReader(data) + handle := w.handle + + var er *bytes.Reader + if w.rest.Len() > 0 { + var rest bytes.Buffer + w.rest.WriteTo(&rest) + w.rest.Reset() + rest.Write(data) + er = bytes.NewReader(rest.Bytes()) + } else { + er = bytes.NewReader(data) + } var bw [1]byte loop: for { - r1, _, err := procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) - if r1 == 0 { - break loop - } - c1, err := er.ReadByte() if err != nil { break loop @@ -385,155 +445,202 @@ loop: } c2, err := er.ReadByte() if err != nil { - w.lastbuf.WriteByte(c1) break loop } - if c2 != 0x5b { - w.lastbuf.WriteByte(c1) - w.lastbuf.WriteByte(c2) + + switch c2 { + case '>': + continue + case ']': + w.rest.WriteByte(c1) + w.rest.WriteByte(c2) + er.WriteTo(&w.rest) + if bytes.IndexByte(w.rest.Bytes(), 0x07) == -1 { + break loop + } + er = bytes.NewReader(w.rest.Bytes()[2:]) + err := doTitleSequence(er) + if err != nil { + break loop + } + w.rest.Reset() + continue + // https://github.com/mattn/go-colorable/issues/27 + case '7': + procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + w.oldpos = csbi.cursorPosition + continue + case '8': + procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&w.oldpos))) + continue + case 0x5b: + // execute part after switch + default: continue } + w.rest.WriteByte(c1) + w.rest.WriteByte(c2) + er.WriteTo(&w.rest) + var buf bytes.Buffer var m byte - for { - c, err := er.ReadByte() - if err != nil { - w.lastbuf.WriteByte(c1) - w.lastbuf.WriteByte(c2) - w.lastbuf.Write(buf.Bytes()) - break loop - } + for i, c := range w.rest.Bytes()[2:] { if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' { m = c + er = bytes.NewReader(w.rest.Bytes()[2+i+1:]) + w.rest.Reset() break } buf.Write([]byte(string(c))) } + if m == 0 { + break loop + } - var csbi consoleScreenBufferInfo switch m { case 'A': n, err = strconv.Atoi(buf.String()) if err != nil { continue } - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) csbi.cursorPosition.y -= short(n) - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) case 'B': n, err = strconv.Atoi(buf.String()) if err != nil { continue } - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) csbi.cursorPosition.y += short(n) - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) case 'C': n, err = strconv.Atoi(buf.String()) if err != nil { continue } - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) - csbi.cursorPosition.x -= short(n) - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + csbi.cursorPosition.x += short(n) + procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) case 'D': n, err = strconv.Atoi(buf.String()) if err != nil { continue } - if n, err = strconv.Atoi(buf.String()); err == nil { - var csbi consoleScreenBufferInfo - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) - csbi.cursorPosition.x += short(n) - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + csbi.cursorPosition.x -= short(n) + if csbi.cursorPosition.x < 0 { + csbi.cursorPosition.x = 0 } + procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) case 'E': n, err = strconv.Atoi(buf.String()) if err != nil { continue } - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) csbi.cursorPosition.x = 0 csbi.cursorPosition.y += short(n) - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) case 'F': n, err = strconv.Atoi(buf.String()) if err != nil { continue } - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) csbi.cursorPosition.x = 0 csbi.cursorPosition.y -= short(n) - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) case 'G': n, err = strconv.Atoi(buf.String()) if err != nil { continue } - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) csbi.cursorPosition.x = short(n - 1) - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) - case 'H': - token := strings.Split(buf.String(), ";") - if len(token) != 2 { - continue + procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + case 'H', 'f': + procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + if buf.Len() > 0 { + token := strings.Split(buf.String(), ";") + switch len(token) { + case 1: + n1, err := strconv.Atoi(token[0]) + if err != nil { + continue + } + csbi.cursorPosition.y = short(n1 - 1) + case 2: + n1, err := strconv.Atoi(token[0]) + if err != nil { + continue + } + n2, err := strconv.Atoi(token[1]) + if err != nil { + continue + } + csbi.cursorPosition.x = short(n2 - 1) + csbi.cursorPosition.y = short(n1 - 1) + } + } else { + csbi.cursorPosition.y = 0 } - n1, err := strconv.Atoi(token[0]) - if err != nil { - continue - } - n2, err := strconv.Atoi(token[1]) - if err != nil { - continue - } - csbi.cursorPosition.x = short(n2 - 1) - csbi.cursorPosition.y = short(n1 - 1) - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) case 'J': - n, err := strconv.Atoi(buf.String()) - if err != nil { - continue + n := 0 + if buf.Len() > 0 { + n, err = strconv.Atoi(buf.String()) + if err != nil { + continue + } } - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + var count, written dword var cursor coord + procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) switch n { case 0: cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y} + count = dword(csbi.size.x) - dword(csbi.cursorPosition.x) + dword(csbi.size.y-csbi.cursorPosition.y)*dword(csbi.size.x) case 1: cursor = coord{x: csbi.window.left, y: csbi.window.top} + count = dword(csbi.size.x) - dword(csbi.cursorPosition.x) + dword(csbi.window.top-csbi.cursorPosition.y)*dword(csbi.size.x) case 2: cursor = coord{x: csbi.window.left, y: csbi.window.top} + count = dword(csbi.size.x) - dword(csbi.cursorPosition.x) + dword(csbi.size.y-csbi.cursorPosition.y)*dword(csbi.size.x) } - var count, written dword - count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.size.y-csbi.cursorPosition.y)*csbi.size.x) - procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) - procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) + procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) + procFillConsoleOutputAttribute.Call(uintptr(handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) case 'K': - n, err := strconv.Atoi(buf.String()) - if err != nil { - continue + n := 0 + if buf.Len() > 0 { + n, err = strconv.Atoi(buf.String()) + if err != nil { + continue + } } - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) var cursor coord + var count, written dword switch n { case 0: cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y} + count = dword(csbi.size.x - csbi.cursorPosition.x) case 1: - cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y} + cursor = coord{x: csbi.window.left, y: csbi.cursorPosition.y} + count = dword(csbi.size.x - csbi.cursorPosition.x) case 2: - cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y} + cursor = coord{x: csbi.window.left, y: csbi.cursorPosition.y} + count = dword(csbi.size.x) } - var count, written dword - count = dword(csbi.size.x - csbi.cursorPosition.x) - procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) - procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) + procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) + procFillConsoleOutputAttribute.Call(uintptr(handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) case 'm': - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) attr := csbi.attributes cs := buf.String() if cs == "" { - procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(w.oldattr)) + procSetConsoleTextAttribute.Call(uintptr(handle), uintptr(w.oldattr)) continue } token := strings.Split(cs, ";") @@ -547,7 +654,7 @@ loop: attr |= foregroundIntensity case n == 7: attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4) - case 22 == n || n == 25 || n == 25: + case n == 22 || n == 25: attr |= foregroundIntensity case n == 27: attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4) @@ -572,6 +679,21 @@ loop: attr |= n256foreAttr[n256] i += 2 } + } else if len(token) == 5 && token[i+1] == "2" { + var r, g, b int + r, _ = strconv.Atoi(token[i+2]) + g, _ = strconv.Atoi(token[i+3]) + b, _ = strconv.Atoi(token[i+4]) + i += 4 + if r > 127 { + attr |= foregroundRed + } + if g > 127 { + attr |= foregroundGreen + } + if b > 127 { + attr |= foregroundBlue + } } else { attr = attr & (w.oldattr & backgroundMask) } @@ -599,6 +721,21 @@ loop: attr |= n256backAttr[n256] i += 2 } + } else if len(token) == 5 && token[i+1] == "2" { + var r, g, b int + r, _ = strconv.Atoi(token[i+2]) + g, _ = strconv.Atoi(token[i+3]) + b, _ = strconv.Atoi(token[i+4]) + i += 4 + if r > 127 { + attr |= backgroundRed + } + if g > 127 { + attr |= backgroundGreen + } + if b > 127 { + attr |= backgroundBlue + } } else { attr = attr & (w.oldattr & foregroundMask) } @@ -630,33 +767,56 @@ loop: attr |= backgroundBlue } } - procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(attr)) + procSetConsoleTextAttribute.Call(uintptr(handle), uintptr(attr)) } } case 'h': + var ci consoleCursorInfo cs := buf.String() - if cs == "?25" { - var ci consoleCursorInfo - procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) + if cs == "5>" { + procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) + ci.visible = 0 + procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) + } else if cs == "?25" { + procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) ci.visible = 1 - procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) + procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) + } else if cs == "?1049" { + if w.althandle == 0 { + h, _, _ := procCreateConsoleScreenBuffer.Call(uintptr(genericRead|genericWrite), 0, 0, uintptr(consoleTextmodeBuffer), 0, 0) + w.althandle = syscall.Handle(h) + if w.althandle != 0 { + handle = w.althandle + } + } } case 'l': + var ci consoleCursorInfo cs := buf.String() - if cs == "?25" { - var ci consoleCursorInfo - procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) + if cs == "5>" { + procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) + ci.visible = 1 + procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) + } else if cs == "?25" { + procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) ci.visible = 0 - procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) + procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) + } else if cs == "?1049" { + if w.althandle != 0 { + syscall.CloseHandle(w.althandle) + w.althandle = 0 + handle = w.handle + } } case 's': - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) w.oldpos = csbi.cursorPosition case 'u': - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&w.oldpos))) + procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&w.oldpos))) } } - return len(data) - w.lastbuf.Len(), nil + + return len(data), nil } type consoleColor struct { @@ -700,22 +860,22 @@ func (c consoleColor) backgroundAttr() (attr word) { } var color16 = []consoleColor{ - consoleColor{0x000000, false, false, false, false}, - consoleColor{0x000080, false, false, true, false}, - consoleColor{0x008000, false, true, false, false}, - consoleColor{0x008080, false, true, true, false}, - consoleColor{0x800000, true, false, false, false}, - consoleColor{0x800080, true, false, true, false}, - consoleColor{0x808000, true, true, false, false}, - consoleColor{0xc0c0c0, true, true, true, false}, - consoleColor{0x808080, false, false, false, true}, - consoleColor{0x0000ff, false, false, true, true}, - consoleColor{0x00ff00, false, true, false, true}, - consoleColor{0x00ffff, false, true, true, true}, - consoleColor{0xff0000, true, false, false, true}, - consoleColor{0xff00ff, true, false, true, true}, - consoleColor{0xffff00, true, true, false, true}, - consoleColor{0xffffff, true, true, true, true}, + {0x000000, false, false, false, false}, + {0x000080, false, false, true, false}, + {0x008000, false, true, false, false}, + {0x008080, false, true, true, false}, + {0x800000, true, false, false, false}, + {0x800080, true, false, true, false}, + {0x808000, true, true, false, false}, + {0xc0c0c0, true, true, true, false}, + {0x808080, false, false, false, true}, + {0x0000ff, false, false, true, true}, + {0x00ff00, false, true, false, true}, + {0x00ffff, false, true, true, true}, + {0xff0000, true, false, false, true}, + {0xff00ff, true, false, true, true}, + {0xffff00, true, true, false, true}, + {0xffffff, true, true, true, true}, } type hsv struct { diff --git a/vendor/github.com/mattn/go-colorable/noncolorable.go b/vendor/github.com/mattn/go-colorable/noncolorable.go index ca588c78ac..9721e16f4b 100644 --- a/vendor/github.com/mattn/go-colorable/noncolorable.go +++ b/vendor/github.com/mattn/go-colorable/noncolorable.go @@ -7,8 +7,7 @@ import ( // NonColorable hold writer but remove escape sequence. type NonColorable struct { - out io.Writer - lastbuf bytes.Buffer + out io.Writer } // NewNonColorable return new instance of Writer which remove escape sequence from Writer. @@ -33,12 +32,9 @@ loop: } c2, err := er.ReadByte() if err != nil { - w.lastbuf.WriteByte(c1) break loop } if c2 != 0x5b { - w.lastbuf.WriteByte(c1) - w.lastbuf.WriteByte(c2) continue } @@ -46,9 +42,6 @@ loop: for { c, err := er.ReadByte() if err != nil { - w.lastbuf.WriteByte(c1) - w.lastbuf.WriteByte(c2) - w.lastbuf.Write(buf.Bytes()) break loop } if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' { @@ -57,5 +50,6 @@ loop: buf.Write([]byte(string(c))) } } - return len(data) - w.lastbuf.Len(), nil + + return len(data), nil } diff --git a/vendor/github.com/mattn/go-isatty/README.md b/vendor/github.com/mattn/go-isatty/README.md index 8e4365f45e..1e69004bb0 100644 --- a/vendor/github.com/mattn/go-isatty/README.md +++ b/vendor/github.com/mattn/go-isatty/README.md @@ -1,6 +1,9 @@ # go-isatty -[![Build Status](https://travis-ci.org/mattn/go-isatty.svg?branch=master)](https://travis-ci.org/mattn/go-isatty) [![Coverage Status](https://coveralls.io/repos/github/mattn/go-isatty/badge.svg?branch=master)](https://coveralls.io/github/mattn/go-isatty?branch=master) +[![Godoc Reference](https://godoc.org/github.com/mattn/go-isatty?status.svg)](http://godoc.org/github.com/mattn/go-isatty) +[![Build Status](https://travis-ci.org/mattn/go-isatty.svg?branch=master)](https://travis-ci.org/mattn/go-isatty) +[![Coverage Status](https://coveralls.io/repos/github/mattn/go-isatty/badge.svg?branch=master)](https://coveralls.io/github/mattn/go-isatty?branch=master) +[![Go Report Card](https://goreportcard.com/badge/mattn/go-isatty)](https://goreportcard.com/report/mattn/go-isatty) isatty for golang diff --git a/vendor/github.com/mattn/go-isatty/isatty_appengine.go b/vendor/github.com/mattn/go-isatty/isatty_appengine.go deleted file mode 100644 index 83c588773c..0000000000 --- a/vendor/github.com/mattn/go-isatty/isatty_appengine.go +++ /dev/null @@ -1,9 +0,0 @@ -// +build appengine - -package isatty - -// IsTerminal returns true if the file descriptor is terminal which -// is always false on on appengine classic which is a sandboxed PaaS. -func IsTerminal(fd uintptr) bool { - return false -} diff --git a/vendor/github.com/mattn/go-isatty/isatty_bsd.go b/vendor/github.com/mattn/go-isatty/isatty_bsd.go index 42f2514d13..07e93039db 100644 --- a/vendor/github.com/mattn/go-isatty/isatty_bsd.go +++ b/vendor/github.com/mattn/go-isatty/isatty_bsd.go @@ -16,3 +16,9 @@ func IsTerminal(fd uintptr) bool { _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) return err == 0 } + +// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2 +// terminal. This is also always false on this environment. +func IsCygwinTerminal(fd uintptr) bool { + return false +} diff --git a/vendor/github.com/mattn/go-isatty/isatty_linux.go b/vendor/github.com/mattn/go-isatty/isatty_linux.go index 9d24bac1db..1f4002617a 100644 --- a/vendor/github.com/mattn/go-isatty/isatty_linux.go +++ b/vendor/github.com/mattn/go-isatty/isatty_linux.go @@ -1,5 +1,5 @@ // +build linux -// +build !appengine +// +build !appengine,!ppc64,!ppc64le package isatty @@ -16,3 +16,9 @@ func IsTerminal(fd uintptr) bool { _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) return err == 0 } + +// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2 +// terminal. This is also always false on this environment. +func IsCygwinTerminal(fd uintptr) bool { + return false +} diff --git a/vendor/github.com/mattn/go-isatty/isatty_linux_ppc64x.go b/vendor/github.com/mattn/go-isatty/isatty_linux_ppc64x.go new file mode 100644 index 0000000000..bb7d3c4224 --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/isatty_linux_ppc64x.go @@ -0,0 +1,25 @@ +// +build linux +// +build ppc64 ppc64le + +package isatty + +import ( + "unsafe" + + syscall "golang.org/x/sys/unix" +) + +const ioctlReadTermios = syscall.TCGETS + +// IsTerminal return true if the file descriptor is terminal. +func IsTerminal(fd uintptr) bool { + var termios syscall.Termios + _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) + return err == 0 +} + +// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2 +// terminal. This is also always false on this environment. +func IsCygwinTerminal(fd uintptr) bool { + return false +} diff --git a/vendor/github.com/mattn/go-isatty/isatty_not_windows.go b/vendor/github.com/mattn/go-isatty/isatty_not_windows.go deleted file mode 100644 index 616832d23e..0000000000 --- a/vendor/github.com/mattn/go-isatty/isatty_not_windows.go +++ /dev/null @@ -1,9 +0,0 @@ -// +build !windows appengine - -package isatty - -// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2 -// terminal. This is also always false on this environment. -func IsCygwinTerminal(fd uintptr) bool { - return false -} diff --git a/vendor/github.com/mattn/go-isatty/isatty_others.go b/vendor/github.com/mattn/go-isatty/isatty_others.go new file mode 100644 index 0000000000..f02849c56f --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/isatty_others.go @@ -0,0 +1,15 @@ +// +build appengine js + +package isatty + +// IsTerminal returns true if the file descriptor is terminal which +// is always false on js and appengine classic which is a sandboxed PaaS. +func IsTerminal(fd uintptr) bool { + return false +} + +// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2 +// terminal. This is also always false on this environment. +func IsCygwinTerminal(fd uintptr) bool { + return false +} diff --git a/vendor/github.com/mattn/go-isatty/isatty_solaris.go b/vendor/github.com/mattn/go-isatty/isatty_solaris.go index 1f0c6bf53d..bdd5c79a07 100644 --- a/vendor/github.com/mattn/go-isatty/isatty_solaris.go +++ b/vendor/github.com/mattn/go-isatty/isatty_solaris.go @@ -14,3 +14,9 @@ func IsTerminal(fd uintptr) bool { err := unix.IoctlSetTermio(int(fd), unix.TCGETA, &termio) return err == nil } + +// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2 +// terminal. This is also always false on this environment. +func IsCygwinTerminal(fd uintptr) bool { + return false +} diff --git a/vendor/github.com/mattn/go-runewidth/runewidth.go b/vendor/github.com/mattn/go-runewidth/runewidth.go index 2164497ad9..82568a1bb9 100644 --- a/vendor/github.com/mattn/go-runewidth/runewidth.go +++ b/vendor/github.com/mattn/go-runewidth/runewidth.go @@ -1,13 +1,24 @@ package runewidth +import "os" + var ( // EastAsianWidth will be set true if the current locale is CJK - EastAsianWidth = IsEastAsian() + EastAsianWidth bool // DefaultCondition is a condition in current locale DefaultCondition = &Condition{EastAsianWidth} ) +func init() { + env := os.Getenv("RUNEWIDTH_EASTASIAN") + if env == "" { + EastAsianWidth = IsEastAsian() + } else { + EastAsianWidth = env == "1" + } +} + type interval struct { first rune last rune @@ -55,6 +66,7 @@ var private = table{ var nonprint = table{ {0x0000, 0x001F}, {0x007F, 0x009F}, {0x00AD, 0x00AD}, {0x070F, 0x070F}, {0x180B, 0x180E}, {0x200B, 0x200F}, + {0x2028, 0x2029}, {0x202A, 0x202E}, {0x206A, 0x206F}, {0xD800, 0xDFFF}, {0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFB}, {0xFFFE, 0xFFFF}, } diff --git a/vendor/github.com/mohae/deepcopy/LICENSE b/vendor/github.com/mohae/deepcopy/LICENSE new file mode 100644 index 0000000000..419673f005 --- /dev/null +++ b/vendor/github.com/mohae/deepcopy/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Joel + +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/mohae/deepcopy/README.md b/vendor/github.com/mohae/deepcopy/README.md new file mode 100644 index 0000000000..f81841885b --- /dev/null +++ b/vendor/github.com/mohae/deepcopy/README.md @@ -0,0 +1,8 @@ +deepCopy +======== +[![GoDoc](https://godoc.org/github.com/mohae/deepcopy?status.svg)](https://godoc.org/github.com/mohae/deepcopy)[![Build Status](https://travis-ci.org/mohae/deepcopy.png)](https://travis-ci.org/mohae/deepcopy) + +DeepCopy makes deep copies of things: unexported field values are not copied. + +## Usage + cpy := deepcopy.Copy(orig) diff --git a/vendor/github.com/mohae/deepcopy/deepcopy.go b/vendor/github.com/mohae/deepcopy/deepcopy.go new file mode 100644 index 0000000000..ba763ad091 --- /dev/null +++ b/vendor/github.com/mohae/deepcopy/deepcopy.go @@ -0,0 +1,125 @@ +// deepcopy makes deep copies of things. A standard copy will copy the +// pointers: deep copy copies the values pointed to. Unexported field +// values are not copied. +// +// Copyright (c)2014-2016, Joel Scoble (github.com/mohae), all rights reserved. +// License: MIT, for more details check the included LICENSE file. +package deepcopy + +import ( + "reflect" + "time" +) + +// Interface for delegating copy process to type +type Interface interface { + DeepCopy() interface{} +} + +// Iface is an alias to Copy; this exists for backwards compatibility reasons. +func Iface(iface interface{}) interface{} { + return Copy(iface) +} + +// Copy creates a deep copy of whatever is passed to it and returns the copy +// in an interface{}. The returned value will need to be asserted to the +// correct type. +func Copy(src interface{}) interface{} { + if src == nil { + return nil + } + + // Make the interface a reflect.Value + original := reflect.ValueOf(src) + + // Make a copy of the same type as the original. + cpy := reflect.New(original.Type()).Elem() + + // Recursively copy the original. + copyRecursive(original, cpy) + + // Return the copy as an interface. + return cpy.Interface() +} + +// copyRecursive does the actual copying of the interface. It currently has +// limited support for what it can handle. Add as needed. +func copyRecursive(original, cpy reflect.Value) { + // check for implement deepcopy.Interface + if original.CanInterface() { + if copier, ok := original.Interface().(Interface); ok { + cpy.Set(reflect.ValueOf(copier.DeepCopy())) + return + } + } + + // handle according to original's Kind + switch original.Kind() { + case reflect.Ptr: + // Get the actual value being pointed to. + originalValue := original.Elem() + + // if it isn't valid, return. + if !originalValue.IsValid() { + return + } + cpy.Set(reflect.New(originalValue.Type())) + copyRecursive(originalValue, cpy.Elem()) + + case reflect.Interface: + // If this is a nil, don't do anything + if original.IsNil() { + return + } + // Get the value for the interface, not the pointer. + originalValue := original.Elem() + + // Get the value by calling Elem(). + copyValue := reflect.New(originalValue.Type()).Elem() + copyRecursive(originalValue, copyValue) + cpy.Set(copyValue) + + case reflect.Struct: + t, ok := original.Interface().(time.Time) + if ok { + cpy.Set(reflect.ValueOf(t)) + return + } + // Go through each field of the struct and copy it. + for i := 0; i < original.NumField(); i++ { + // The Type's StructField for a given field is checked to see if StructField.PkgPath + // is set to determine if the field is exported or not because CanSet() returns false + // for settable fields. I'm not sure why. -mohae + if original.Type().Field(i).PkgPath != "" { + continue + } + copyRecursive(original.Field(i), cpy.Field(i)) + } + + case reflect.Slice: + if original.IsNil() { + return + } + // Make a new slice and copy each element. + cpy.Set(reflect.MakeSlice(original.Type(), original.Len(), original.Cap())) + for i := 0; i < original.Len(); i++ { + copyRecursive(original.Index(i), cpy.Index(i)) + } + + case reflect.Map: + if original.IsNil() { + return + } + cpy.Set(reflect.MakeMap(original.Type())) + for _, key := range original.MapKeys() { + originalValue := original.MapIndex(key) + copyValue := reflect.New(originalValue.Type()).Elem() + copyRecursive(originalValue, copyValue) + copyKey := Copy(key.Interface()) + cpy.SetMapIndex(reflect.ValueOf(copyKey), copyValue) + } + + default: + cpy.Set(original) + } +} diff --git a/vendor/github.com/naoina/toml/encode.go b/vendor/github.com/naoina/toml/encode.go index ae6bfd575f..15602f005a 100644 --- a/vendor/github.com/naoina/toml/encode.go +++ b/vendor/github.com/naoina/toml/encode.go @@ -61,20 +61,26 @@ func (cfg *Config) NewEncoder(w io.Writer) *Encoder { // Encode writes the TOML of v to the stream. // See the documentation for Marshal for details about the conversion of Go values to TOML. func (e *Encoder) Encode(v interface{}) error { - rv := reflect.ValueOf(v) + var ( + buf = &tableBuf{typ: ast.TableTypeNormal} + rv = reflect.ValueOf(v) + err error + ) + for rv.Kind() == reflect.Ptr { if rv.IsNil() { return &marshalNilError{rv.Type()} } rv = rv.Elem() } - buf := &tableBuf{typ: ast.TableTypeNormal} - var err error + switch rv.Kind() { case reflect.Struct: err = buf.structFields(e.cfg, rv) case reflect.Map: err = buf.mapFields(e.cfg, rv) + case reflect.Interface: + return e.Encode(rv.Interface()) default: err = &marshalTableError{rv.Type()} } diff --git a/vendor/github.com/naoina/toml/parse.go b/vendor/github.com/naoina/toml/parse.go index e6f95001e5..de9108566b 100644 --- a/vendor/github.com/naoina/toml/parse.go +++ b/vendor/github.com/naoina/toml/parse.go @@ -97,6 +97,7 @@ type toml struct { currentTable *ast.Table s string key string + tableKeys []string val ast.Value arr *array stack []*stack @@ -180,12 +181,12 @@ func (p *tomlParser) SetArray(begin, end int) { } func (p *toml) SetTable(buf []rune, begin, end int) { - p.setTable(p.table, buf, begin, end) + rawName := string(buf[begin:end]) + p.setTable(p.table, rawName, p.tableKeys) + p.tableKeys = nil } -func (p *toml) setTable(parent *ast.Table, buf []rune, begin, end int) { - name := string(buf[begin:end]) - names := splitTableKey(name) +func (p *toml) setTable(parent *ast.Table, name string, names []string) { parent, err := p.lookupTable(parent, names[:len(names)-1]) if err != nil { p.Error(err) @@ -230,12 +231,12 @@ func (p *tomlParser) SetTableString(begin, end int) { } func (p *toml) SetArrayTable(buf []rune, begin, end int) { - p.setArrayTable(p.table, buf, begin, end) + rawName := string(buf[begin:end]) + p.setArrayTable(p.table, rawName, p.tableKeys) + p.tableKeys = nil } -func (p *toml) setArrayTable(parent *ast.Table, buf []rune, begin, end int) { - name := string(buf[begin:end]) - names := splitTableKey(name) +func (p *toml) setArrayTable(parent *ast.Table, name string, names []string) { parent, err := p.lookupTable(parent, names[:len(names)-1]) if err != nil { p.Error(err) @@ -260,11 +261,11 @@ func (p *toml) setArrayTable(parent *ast.Table, buf []rune, begin, end int) { func (p *toml) StartInlineTable() { p.skip = false p.stack = append(p.stack, &stack{p.key, p.currentTable}) - buf := []rune(p.key) + names := []string{p.key} if p.arr == nil { - p.setTable(p.currentTable, buf, 0, len(buf)) + p.setTable(p.currentTable, names[0], names) } else { - p.setArrayTable(p.currentTable, buf, 0, len(buf)) + p.setArrayTable(p.currentTable, names[0], names) } } @@ -282,6 +283,13 @@ func (p *toml) AddLineCount(i int) { func (p *toml) SetKey(buf []rune, begin, end int) { p.key = string(buf[begin:end]) + if len(p.key) > 0 && p.key[0] == '"' { + p.key = p.unquote(p.key) + } +} + +func (p *toml) AddTableKey() { + p.tableKeys = append(p.tableKeys, p.key) } func (p *toml) AddKeyValue() { @@ -352,25 +360,3 @@ func (p *toml) lookupTable(t *ast.Table, keys []string) (*ast.Table, error) { } return t, nil } - -func splitTableKey(tk string) []string { - key := make([]byte, 0, 1) - keys := make([]string, 0, 1) - inQuote := false - for i := 0; i < len(tk); i++ { - k := tk[i] - switch { - case k == tableSeparator && !inQuote: - keys = append(keys, string(key)) - key = key[:0] // reuse buffer. - case k == '"': - inQuote = !inQuote - case (k == ' ' || k == '\t') && !inQuote: - // skip. - default: - key = append(key, k) - } - } - keys = append(keys, string(key)) - return keys -} diff --git a/vendor/github.com/naoina/toml/parse.peg b/vendor/github.com/naoina/toml/parse.peg index da31dae309..860ada3732 100644 --- a/vendor/github.com/naoina/toml/parse.peg +++ b/vendor/github.com/naoina/toml/parse.peg @@ -29,7 +29,7 @@ key <- bareKey / quotedKey bareKey <- <[0-9A-Za-z\-_]+> { p.SetKey(p.buffer, begin, end) } -quotedKey <- '"' '"' { p.SetKey(p.buffer, begin-1, end+1) } +quotedKey <- < '"' basicChar* '"' > { p.SetKey(p.buffer, begin, end) } val <- ( { p.SetTime(begin, end) } @@ -55,7 +55,9 @@ inlineTable <- ( inlineTableKeyValues <- (keyval inlineTableValSep?)* -tableKey <- key (tableKeySep key)* +tableKey <- tableKeyComp (tableKeySep tableKeyComp)* + +tableKeyComp <- key { p.AddTableKey() } tableKeySep <- ws '.' ws @@ -117,7 +119,7 @@ timeNumoffset <- [\-+] timeHour ':' timeMinute timeOffset <- 'Z' / timeNumoffset partialTime <- timeHour ':' timeMinute ':' timeSecond timeSecfrac? fullDate <- dateFullYear '-' dateMonth '-' dateMDay -fullTime <- partialTime timeOffset +fullTime <- partialTime timeOffset? datetime <- (fullDate ('T' fullTime)?) / partialTime digit <- [0-9] diff --git a/vendor/github.com/naoina/toml/parse.peg.go b/vendor/github.com/naoina/toml/parse.peg.go index d7de73b19c..fa377b19bd 100644 --- a/vendor/github.com/naoina/toml/parse.peg.go +++ b/vendor/github.com/naoina/toml/parse.peg.go @@ -31,6 +31,7 @@ const ( ruleinlineTable ruleinlineTableKeyValues ruletableKey + ruletableKeyComp ruletableKeySep ruleinlineTableValSep ruleinteger @@ -99,6 +100,7 @@ const ( ruleAction22 ruleAction23 ruleAction24 + ruleAction25 ) var rul3s = [...]string{ @@ -120,6 +122,7 @@ var rul3s = [...]string{ "inlineTable", "inlineTableKeyValues", "tableKey", + "tableKeyComp", "tableKeySep", "inlineTableValSep", "integer", @@ -188,6 +191,7 @@ var rul3s = [...]string{ "Action22", "Action23", "Action24", + "Action25", } type token32 struct { @@ -304,7 +308,7 @@ type tomlParser struct { Buffer string buffer []rune - rules [86]func() bool + rules [88]func() bool parse func(rule ...int) error reset func() Pretty bool @@ -409,7 +413,7 @@ func (p *tomlParser) Execute() { case ruleAction5: p.SetKey(p.buffer, begin, end) case ruleAction6: - p.SetKey(p.buffer, begin-1, end+1) + p.SetKey(p.buffer, begin, end) case ruleAction7: p.SetTime(begin, end) case ruleAction8: @@ -431,21 +435,23 @@ func (p *tomlParser) Execute() { case ruleAction16: p.EndInlineTable() case ruleAction17: - p.SetBasicString(p.buffer, begin, end) + p.AddTableKey() case ruleAction18: - p.SetMultilineString() + p.SetBasicString(p.buffer, begin, end) case ruleAction19: - p.AddMultilineBasicBody(p.buffer, begin, end) + p.SetMultilineString() case ruleAction20: - p.SetLiteralString(p.buffer, begin, end) + p.AddMultilineBasicBody(p.buffer, begin, end) case ruleAction21: - p.SetMultilineLiteralString(p.buffer, begin, end) + p.SetLiteralString(p.buffer, begin, end) case ruleAction22: - p.StartArray() + p.SetMultilineLiteralString(p.buffer, begin, end) case ruleAction23: - p.AddArrayVal() + p.StartArray() case ruleAction24: p.AddArrayVal() + case ruleAction25: + p.AddArrayVal() } } @@ -1069,15 +1075,12 @@ func (p *tomlParser) Init() { position, tokenIndex = position72, tokenIndex72 { position81 := position - if buffer[position] != rune('"') { - goto l70 - } - position++ { position82 := position - if !_rules[rulebasicChar]() { + if buffer[position] != rune('"') { goto l70 } + position++ l83: { position84, tokenIndex84 := position, tokenIndex @@ -1088,12 +1091,12 @@ func (p *tomlParser) Init() { l84: position, tokenIndex = position84, tokenIndex84 } + if buffer[position] != rune('"') { + goto l70 + } + position++ add(rulePegText, position82) } - if buffer[position] != rune('"') { - goto l70 - } - position++ { add(ruleAction6, position) } @@ -1110,7 +1113,7 @@ func (p *tomlParser) Init() { }, /* 8 bareKey <- <(<((&('_') '_') | (&('-') '-') | (&('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') [a-z]) | (&('0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9') [0-9]) | (&('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') [A-Z]))+> Action5)> */ nil, - /* 9 quotedKey <- <('"' '"' Action6)> */ + /* 9 quotedKey <- <(<('"' basicChar* '"')> Action6)> */ nil, /* 10 val <- <(( Action7) / ( Action8) / ((&('{') inlineTable) | (&('[') ( Action12)) | (&('f' | 't') ( Action11)) | (&('"' | '\'') ( Action10)) | (&('+' | '-' | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9') ( Action9))))> */ func() bool { @@ -1177,49 +1180,56 @@ func (p *tomlParser) Init() { goto l101 } { - position104 := position + position104, tokenIndex104 := position, tokenIndex { - position105, tokenIndex105 := position, tokenIndex - if buffer[position] != rune('Z') { - goto l106 - } - position++ - goto l105 - l106: - position, tokenIndex = position105, tokenIndex105 + position106 := position { - position107 := position - { - position108, tokenIndex108 := position, tokenIndex - if buffer[position] != rune('-') { - goto l109 - } - position++ + position107, tokenIndex107 := position, tokenIndex + if buffer[position] != rune('Z') { goto l108 - l109: - position, tokenIndex = position108, tokenIndex108 - if buffer[position] != rune('+') { - goto l101 - } - position++ - } - l108: - if !_rules[ruletimeHour]() { - goto l101 - } - if buffer[position] != rune(':') { - goto l101 } position++ - if !_rules[ruletimeMinute]() { - goto l101 + goto l107 + l108: + position, tokenIndex = position107, tokenIndex107 + { + position109 := position + { + position110, tokenIndex110 := position, tokenIndex + if buffer[position] != rune('-') { + goto l111 + } + position++ + goto l110 + l111: + position, tokenIndex = position110, tokenIndex110 + if buffer[position] != rune('+') { + goto l104 + } + position++ + } + l110: + if !_rules[ruletimeHour]() { + goto l104 + } + if buffer[position] != rune(':') { + goto l104 + } + position++ + if !_rules[ruletimeMinute]() { + goto l104 + } + add(ruletimeNumoffset, position109) } - add(ruletimeNumoffset, position107) } + l107: + add(ruletimeOffset, position106) } - l105: - add(ruletimeOffset, position104) + goto l105 + l104: + position, tokenIndex = position104, tokenIndex104 } + l105: add(rulefullTime, position103) } goto l102 @@ -1246,33 +1256,20 @@ func (p *tomlParser) Init() { l91: position, tokenIndex = position90, tokenIndex90 { - position112 := position + position114 := position { - position113 := position + position115 := position if !_rules[ruleinteger]() { - goto l111 + goto l113 } { - position114, tokenIndex114 := position, tokenIndex + position116, tokenIndex116 := position, tokenIndex if !_rules[rulefrac]() { - goto l115 - } - { - position116, tokenIndex116 := position, tokenIndex - if !_rules[ruleexp]() { - goto l116 - } goto l117 - l116: - position, tokenIndex = position116, tokenIndex116 } - l117: - goto l114 - l115: - position, tokenIndex = position114, tokenIndex114 { position118, tokenIndex118 := position, tokenIndex - if !_rules[rulefrac]() { + if !_rules[ruleexp]() { goto l118 } goto l119 @@ -1280,26 +1277,39 @@ func (p *tomlParser) Init() { position, tokenIndex = position118, tokenIndex118 } l119: + goto l116 + l117: + position, tokenIndex = position116, tokenIndex116 + { + position120, tokenIndex120 := position, tokenIndex + if !_rules[rulefrac]() { + goto l120 + } + goto l121 + l120: + position, tokenIndex = position120, tokenIndex120 + } + l121: if !_rules[ruleexp]() { - goto l111 + goto l113 } } - l114: - add(rulefloat, position113) + l116: + add(rulefloat, position115) } - add(rulePegText, position112) + add(rulePegText, position114) } { add(ruleAction8, position) } goto l90 - l111: + l113: position, tokenIndex = position90, tokenIndex90 { switch buffer[position] { case '{': { - position122 := position + position124 := position if buffer[position] != rune('{') { goto l88 } @@ -1311,39 +1321,39 @@ func (p *tomlParser) Init() { goto l88 } { - position124 := position - l125: + position126 := position + l127: { - position126, tokenIndex126 := position, tokenIndex + position128, tokenIndex128 := position, tokenIndex if !_rules[rulekeyval]() { - goto l126 + goto l128 } { - position127, tokenIndex127 := position, tokenIndex + position129, tokenIndex129 := position, tokenIndex { - position129 := position + position131 := position if !_rules[rulews]() { - goto l127 + goto l129 } if buffer[position] != rune(',') { - goto l127 + goto l129 } position++ if !_rules[rulews]() { - goto l127 + goto l129 } - add(ruleinlineTableValSep, position129) + add(ruleinlineTableValSep, position131) } - goto l128 - l127: - position, tokenIndex = position127, tokenIndex127 + goto l130 + l129: + position, tokenIndex = position129, tokenIndex129 } + l130: + goto l127 l128: - goto l125 - l126: - position, tokenIndex = position126, tokenIndex126 + position, tokenIndex = position128, tokenIndex128 } - add(ruleinlineTableKeyValues, position124) + add(ruleinlineTableKeyValues, position126) } if !_rules[rulews]() { goto l88 @@ -1355,58 +1365,39 @@ func (p *tomlParser) Init() { { add(ruleAction16, position) } - add(ruleinlineTable, position122) + add(ruleinlineTable, position124) } break case '[': { - position131 := position + position133 := position { - position132 := position + position134 := position if buffer[position] != rune('[') { goto l88 } position++ { - add(ruleAction22, position) + add(ruleAction23, position) } if !_rules[rulewsnl]() { goto l88 } { - position134, tokenIndex134 := position, tokenIndex + position136, tokenIndex136 := position, tokenIndex { - position136 := position + position138 := position if !_rules[ruleval]() { - goto l134 + goto l136 } { - add(ruleAction23, position) + add(ruleAction24, position) } - l138: + l140: { - position139, tokenIndex139 := position, tokenIndex + position141, tokenIndex141 := position, tokenIndex if !_rules[rulewsnl]() { - goto l139 - } - { - position140, tokenIndex140 := position, tokenIndex - if !_rules[rulecomment]() { - goto l140 - } goto l141 - l140: - position, tokenIndex = position140, tokenIndex140 - } - l141: - if !_rules[rulewsnl]() { - goto l139 - } - if !_rules[rulearraySep]() { - goto l139 - } - if !_rules[rulewsnl]() { - goto l139 } { position142, tokenIndex142 := position, tokenIndex @@ -1419,37 +1410,43 @@ func (p *tomlParser) Init() { } l143: if !_rules[rulewsnl]() { - goto l139 + goto l141 } - if !_rules[ruleval]() { - goto l139 + if !_rules[rulearraySep]() { + goto l141 + } + if !_rules[rulewsnl]() { + goto l141 } { - add(ruleAction24, position) - } - goto l138 - l139: - position, tokenIndex = position139, tokenIndex139 - } - if !_rules[rulewsnl]() { - goto l134 - } - { - position145, tokenIndex145 := position, tokenIndex - if !_rules[rulearraySep]() { + position144, tokenIndex144 := position, tokenIndex + if !_rules[rulecomment]() { + goto l144 + } goto l145 + l144: + position, tokenIndex = position144, tokenIndex144 } - goto l146 l145: - position, tokenIndex = position145, tokenIndex145 + if !_rules[rulewsnl]() { + goto l141 + } + if !_rules[ruleval]() { + goto l141 + } + { + add(ruleAction25, position) + } + goto l140 + l141: + position, tokenIndex = position141, tokenIndex141 } - l146: if !_rules[rulewsnl]() { - goto l134 + goto l136 } { position147, tokenIndex147 := position, tokenIndex - if !_rules[rulecomment]() { + if !_rules[rulearraySep]() { goto l147 } goto l148 @@ -1457,13 +1454,26 @@ func (p *tomlParser) Init() { position, tokenIndex = position147, tokenIndex147 } l148: - add(rulearrayValues, position136) + if !_rules[rulewsnl]() { + goto l136 + } + { + position149, tokenIndex149 := position, tokenIndex + if !_rules[rulecomment]() { + goto l149 + } + goto l150 + l149: + position, tokenIndex = position149, tokenIndex149 + } + l150: + add(rulearrayValues, position138) } - goto l135 - l134: - position, tokenIndex = position134, tokenIndex134 + goto l137 + l136: + position, tokenIndex = position136, tokenIndex136 } - l135: + l137: if !_rules[rulewsnl]() { goto l88 } @@ -1471,9 +1481,9 @@ func (p *tomlParser) Init() { goto l88 } position++ - add(rulearray, position132) + add(rulearray, position134) } - add(rulePegText, position131) + add(rulePegText, position133) } { add(ruleAction12, position) @@ -1481,30 +1491,30 @@ func (p *tomlParser) Init() { break case 'f', 't': { - position150 := position + position152 := position { - position151 := position + position153 := position { - position152, tokenIndex152 := position, tokenIndex + position154, tokenIndex154 := position, tokenIndex if buffer[position] != rune('t') { - goto l153 + goto l155 } position++ if buffer[position] != rune('r') { - goto l153 + goto l155 } position++ if buffer[position] != rune('u') { - goto l153 + goto l155 } position++ if buffer[position] != rune('e') { - goto l153 + goto l155 } position++ - goto l152 - l153: - position, tokenIndex = position152, tokenIndex152 + goto l154 + l155: + position, tokenIndex = position154, tokenIndex154 if buffer[position] != rune('f') { goto l88 } @@ -1526,10 +1536,10 @@ func (p *tomlParser) Init() { } position++ } - l152: - add(ruleboolean, position151) + l154: + add(ruleboolean, position153) } - add(rulePegText, position150) + add(rulePegText, position152) } { add(ruleAction11, position) @@ -1537,278 +1547,278 @@ func (p *tomlParser) Init() { break case '"', '\'': { - position155 := position + position157 := position { - position156 := position + position158 := position { - position157, tokenIndex157 := position, tokenIndex + position159, tokenIndex159 := position, tokenIndex { - position159 := position + position161 := position if buffer[position] != rune('\'') { - goto l158 + goto l160 } position++ if buffer[position] != rune('\'') { - goto l158 + goto l160 } position++ if buffer[position] != rune('\'') { - goto l158 + goto l160 } position++ { - position160 := position + position162 := position { - position161 := position - l162: + position163 := position + l164: { - position163, tokenIndex163 := position, tokenIndex + position165, tokenIndex165 := position, tokenIndex { - position164, tokenIndex164 := position, tokenIndex + position166, tokenIndex166 := position, tokenIndex if buffer[position] != rune('\'') { - goto l164 + goto l166 } position++ if buffer[position] != rune('\'') { - goto l164 + goto l166 } position++ if buffer[position] != rune('\'') { - goto l164 + goto l166 } position++ - goto l163 - l164: - position, tokenIndex = position164, tokenIndex164 + goto l165 + l166: + position, tokenIndex = position166, tokenIndex166 } { - position165, tokenIndex165 := position, tokenIndex + position167, tokenIndex167 := position, tokenIndex { - position167 := position + position169 := position { - position168, tokenIndex168 := position, tokenIndex + position170, tokenIndex170 := position, tokenIndex if buffer[position] != rune('\t') { - goto l169 + goto l171 } position++ - goto l168 - l169: - position, tokenIndex = position168, tokenIndex168 + goto l170 + l171: + position, tokenIndex = position170, tokenIndex170 if c := buffer[position]; c < rune(' ') || c > rune('\U0010ffff') { - goto l166 + goto l168 } position++ } - l168: - add(rulemlLiteralChar, position167) + l170: + add(rulemlLiteralChar, position169) } - goto l165 - l166: - position, tokenIndex = position165, tokenIndex165 + goto l167 + l168: + position, tokenIndex = position167, tokenIndex167 if !_rules[rulenewline]() { - goto l163 + goto l165 } } + l167: + goto l164 l165: - goto l162 - l163: - position, tokenIndex = position163, tokenIndex163 + position, tokenIndex = position165, tokenIndex165 } - add(rulemlLiteralBody, position161) + add(rulemlLiteralBody, position163) } - add(rulePegText, position160) + add(rulePegText, position162) } if buffer[position] != rune('\'') { - goto l158 + goto l160 } position++ if buffer[position] != rune('\'') { - goto l158 + goto l160 } position++ if buffer[position] != rune('\'') { - goto l158 + goto l160 } position++ { - add(ruleAction21, position) + add(ruleAction22, position) } - add(rulemlLiteralString, position159) + add(rulemlLiteralString, position161) } - goto l157 - l158: - position, tokenIndex = position157, tokenIndex157 + goto l159 + l160: + position, tokenIndex = position159, tokenIndex159 { - position172 := position + position174 := position if buffer[position] != rune('\'') { - goto l171 + goto l173 } position++ { - position173 := position - l174: + position175 := position + l176: { - position175, tokenIndex175 := position, tokenIndex + position177, tokenIndex177 := position, tokenIndex { - position176 := position + position178 := position { switch buffer[position] { case '\t': if buffer[position] != rune('\t') { - goto l175 + goto l177 } position++ break case ' ', '!', '"', '#', '$', '%', '&': if c := buffer[position]; c < rune(' ') || c > rune('&') { - goto l175 + goto l177 } position++ break default: if c := buffer[position]; c < rune('(') || c > rune('\U0010ffff') { - goto l175 + goto l177 } position++ break } } - add(ruleliteralChar, position176) + add(ruleliteralChar, position178) } - goto l174 - l175: - position, tokenIndex = position175, tokenIndex175 + goto l176 + l177: + position, tokenIndex = position177, tokenIndex177 } - add(rulePegText, position173) + add(rulePegText, position175) } if buffer[position] != rune('\'') { - goto l171 + goto l173 } position++ { - add(ruleAction20, position) + add(ruleAction21, position) } - add(ruleliteralString, position172) + add(ruleliteralString, position174) } - goto l157 - l171: - position, tokenIndex = position157, tokenIndex157 + goto l159 + l173: + position, tokenIndex = position159, tokenIndex159 { - position180 := position + position182 := position if buffer[position] != rune('"') { - goto l179 + goto l181 } position++ if buffer[position] != rune('"') { - goto l179 + goto l181 } position++ if buffer[position] != rune('"') { - goto l179 + goto l181 } position++ { - position181 := position - l182: + position183 := position + l184: { - position183, tokenIndex183 := position, tokenIndex + position185, tokenIndex185 := position, tokenIndex { - position184, tokenIndex184 := position, tokenIndex + position186, tokenIndex186 := position, tokenIndex { - position186 := position + position188 := position { - position187, tokenIndex187 := position, tokenIndex + position189, tokenIndex189 := position, tokenIndex if !_rules[rulebasicChar]() { - goto l188 + goto l190 } - goto l187 - l188: - position, tokenIndex = position187, tokenIndex187 + goto l189 + l190: + position, tokenIndex = position189, tokenIndex189 if !_rules[rulenewline]() { - goto l185 + goto l187 } } - l187: - add(rulePegText, position186) + l189: + add(rulePegText, position188) } { - add(ruleAction19, position) + add(ruleAction20, position) } - goto l184 - l185: - position, tokenIndex = position184, tokenIndex184 + goto l186 + l187: + position, tokenIndex = position186, tokenIndex186 if !_rules[ruleescape]() { - goto l183 + goto l185 } if !_rules[rulenewline]() { - goto l183 + goto l185 } if !_rules[rulewsnl]() { - goto l183 + goto l185 } } - l184: - goto l182 - l183: - position, tokenIndex = position183, tokenIndex183 + l186: + goto l184 + l185: + position, tokenIndex = position185, tokenIndex185 } - add(rulemlBasicBody, position181) + add(rulemlBasicBody, position183) } if buffer[position] != rune('"') { - goto l179 + goto l181 } position++ if buffer[position] != rune('"') { - goto l179 + goto l181 } position++ if buffer[position] != rune('"') { - goto l179 + goto l181 } position++ + { + add(ruleAction19, position) + } + add(rulemlBasicString, position182) + } + goto l159 + l181: + position, tokenIndex = position159, tokenIndex159 + { + position193 := position + { + position194 := position + if buffer[position] != rune('"') { + goto l88 + } + position++ + l195: + { + position196, tokenIndex196 := position, tokenIndex + if !_rules[rulebasicChar]() { + goto l196 + } + goto l195 + l196: + position, tokenIndex = position196, tokenIndex196 + } + if buffer[position] != rune('"') { + goto l88 + } + position++ + add(rulePegText, position194) + } { add(ruleAction18, position) } - add(rulemlBasicString, position180) - } - goto l157 - l179: - position, tokenIndex = position157, tokenIndex157 - { - position191 := position - { - position192 := position - if buffer[position] != rune('"') { - goto l88 - } - position++ - l193: - { - position194, tokenIndex194 := position, tokenIndex - if !_rules[rulebasicChar]() { - goto l194 - } - goto l193 - l194: - position, tokenIndex = position194, tokenIndex194 - } - if buffer[position] != rune('"') { - goto l88 - } - position++ - add(rulePegText, position192) - } - { - add(ruleAction17, position) - } - add(rulebasicString, position191) + add(rulebasicString, position193) } } - l157: - add(rulestring, position156) + l159: + add(rulestring, position158) } - add(rulePegText, position155) + add(rulePegText, position157) } { add(ruleAction10, position) @@ -1816,11 +1826,11 @@ func (p *tomlParser) Init() { break default: { - position197 := position + position199 := position if !_rules[ruleinteger]() { goto l88 } - add(rulePegText, position197) + add(rulePegText, position199) } { add(ruleAction9, position) @@ -1848,708 +1858,728 @@ func (p *tomlParser) Init() { nil, /* 15 inlineTableKeyValues <- <(keyval inlineTableValSep?)*> */ nil, - /* 16 tableKey <- <(key (tableKeySep key)*)> */ + /* 16 tableKey <- <(tableKeyComp (tableKeySep tableKeyComp)*)> */ func() bool { - position204, tokenIndex204 := position, tokenIndex + position206, tokenIndex206 := position, tokenIndex { - position205 := position - if !_rules[rulekey]() { - goto l204 + position207 := position + if !_rules[ruletableKeyComp]() { + goto l206 } - l206: + l208: { - position207, tokenIndex207 := position, tokenIndex + position209, tokenIndex209 := position, tokenIndex { - position208 := position + position210 := position if !_rules[rulews]() { - goto l207 + goto l209 } if buffer[position] != rune('.') { - goto l207 + goto l209 } position++ if !_rules[rulews]() { - goto l207 + goto l209 } - add(ruletableKeySep, position208) + add(ruletableKeySep, position210) } - if !_rules[rulekey]() { - goto l207 + if !_rules[ruletableKeyComp]() { + goto l209 } - goto l206 - l207: - position, tokenIndex = position207, tokenIndex207 + goto l208 + l209: + position, tokenIndex = position209, tokenIndex209 } - add(ruletableKey, position205) + add(ruletableKey, position207) } return true - l204: - position, tokenIndex = position204, tokenIndex204 + l206: + position, tokenIndex = position206, tokenIndex206 return false }, - /* 17 tableKeySep <- <(ws '.' ws)> */ - nil, - /* 18 inlineTableValSep <- <(ws ',' ws)> */ - nil, - /* 19 integer <- <(('-' / '+')? int)> */ + /* 17 tableKeyComp <- <(key Action17)> */ func() bool { position211, tokenIndex211 := position, tokenIndex { position212 := position - { - position213, tokenIndex213 := position, tokenIndex - { - position215, tokenIndex215 := position, tokenIndex - if buffer[position] != rune('-') { - goto l216 - } - position++ - goto l215 - l216: - position, tokenIndex = position215, tokenIndex215 - if buffer[position] != rune('+') { - goto l213 - } - position++ - } - l215: - goto l214 - l213: - position, tokenIndex = position213, tokenIndex213 + if !_rules[rulekey]() { + goto l211 } - l214: { - position217 := position - { - position218, tokenIndex218 := position, tokenIndex - if c := buffer[position]; c < rune('1') || c > rune('9') { - goto l219 - } - position++ - { - position222, tokenIndex222 := position, tokenIndex - if !_rules[ruledigit]() { - goto l223 - } - goto l222 - l223: - position, tokenIndex = position222, tokenIndex222 - if buffer[position] != rune('_') { - goto l219 - } - position++ - if !_rules[ruledigit]() { - goto l219 - } - } - l222: - l220: - { - position221, tokenIndex221 := position, tokenIndex - { - position224, tokenIndex224 := position, tokenIndex - if !_rules[ruledigit]() { - goto l225 - } - goto l224 - l225: - position, tokenIndex = position224, tokenIndex224 - if buffer[position] != rune('_') { - goto l221 - } - position++ - if !_rules[ruledigit]() { - goto l221 - } - } - l224: - goto l220 - l221: - position, tokenIndex = position221, tokenIndex221 - } - goto l218 - l219: - position, tokenIndex = position218, tokenIndex218 - if !_rules[ruledigit]() { - goto l211 - } - } - l218: - add(ruleint, position217) + add(ruleAction17, position) } - add(ruleinteger, position212) + add(ruletableKeyComp, position212) } return true l211: position, tokenIndex = position211, tokenIndex211 return false }, - /* 20 int <- <(([1-9] (digit / ('_' digit))+) / digit)> */ + /* 18 tableKeySep <- <(ws '.' ws)> */ nil, - /* 21 float <- <(integer ((frac exp?) / (frac? exp)))> */ + /* 19 inlineTableValSep <- <(ws ',' ws)> */ nil, - /* 22 frac <- <('.' digit (digit / ('_' digit))*)> */ + /* 20 integer <- <(('-' / '+')? int)> */ func() bool { - position228, tokenIndex228 := position, tokenIndex + position216, tokenIndex216 := position, tokenIndex { - position229 := position + position217 := position + { + position218, tokenIndex218 := position, tokenIndex + { + position220, tokenIndex220 := position, tokenIndex + if buffer[position] != rune('-') { + goto l221 + } + position++ + goto l220 + l221: + position, tokenIndex = position220, tokenIndex220 + if buffer[position] != rune('+') { + goto l218 + } + position++ + } + l220: + goto l219 + l218: + position, tokenIndex = position218, tokenIndex218 + } + l219: + { + position222 := position + { + position223, tokenIndex223 := position, tokenIndex + if c := buffer[position]; c < rune('1') || c > rune('9') { + goto l224 + } + position++ + { + position227, tokenIndex227 := position, tokenIndex + if !_rules[ruledigit]() { + goto l228 + } + goto l227 + l228: + position, tokenIndex = position227, tokenIndex227 + if buffer[position] != rune('_') { + goto l224 + } + position++ + if !_rules[ruledigit]() { + goto l224 + } + } + l227: + l225: + { + position226, tokenIndex226 := position, tokenIndex + { + position229, tokenIndex229 := position, tokenIndex + if !_rules[ruledigit]() { + goto l230 + } + goto l229 + l230: + position, tokenIndex = position229, tokenIndex229 + if buffer[position] != rune('_') { + goto l226 + } + position++ + if !_rules[ruledigit]() { + goto l226 + } + } + l229: + goto l225 + l226: + position, tokenIndex = position226, tokenIndex226 + } + goto l223 + l224: + position, tokenIndex = position223, tokenIndex223 + if !_rules[ruledigit]() { + goto l216 + } + } + l223: + add(ruleint, position222) + } + add(ruleinteger, position217) + } + return true + l216: + position, tokenIndex = position216, tokenIndex216 + return false + }, + /* 21 int <- <(([1-9] (digit / ('_' digit))+) / digit)> */ + nil, + /* 22 float <- <(integer ((frac exp?) / (frac? exp)))> */ + nil, + /* 23 frac <- <('.' digit (digit / ('_' digit))*)> */ + func() bool { + position233, tokenIndex233 := position, tokenIndex + { + position234 := position if buffer[position] != rune('.') { - goto l228 + goto l233 } position++ if !_rules[ruledigit]() { - goto l228 + goto l233 } - l230: - { - position231, tokenIndex231 := position, tokenIndex - { - position232, tokenIndex232 := position, tokenIndex - if !_rules[ruledigit]() { - goto l233 - } - goto l232 - l233: - position, tokenIndex = position232, tokenIndex232 - if buffer[position] != rune('_') { - goto l231 - } - position++ - if !_rules[ruledigit]() { - goto l231 - } - } - l232: - goto l230 - l231: - position, tokenIndex = position231, tokenIndex231 - } - add(rulefrac, position229) - } - return true - l228: - position, tokenIndex = position228, tokenIndex228 - return false - }, - /* 23 exp <- <(('e' / 'E') ('-' / '+')? digit (digit / ('_' digit))*)> */ - func() bool { - position234, tokenIndex234 := position, tokenIndex - { - position235 := position + l235: { position236, tokenIndex236 := position, tokenIndex - if buffer[position] != rune('e') { - goto l237 - } - position++ - goto l236 - l237: - position, tokenIndex = position236, tokenIndex236 - if buffer[position] != rune('E') { - goto l234 - } - position++ - } - l236: - { - position238, tokenIndex238 := position, tokenIndex { - position240, tokenIndex240 := position, tokenIndex - if buffer[position] != rune('-') { - goto l241 - } - position++ - goto l240 - l241: - position, tokenIndex = position240, tokenIndex240 - if buffer[position] != rune('+') { + position237, tokenIndex237 := position, tokenIndex + if !_rules[ruledigit]() { goto l238 } + goto l237 + l238: + position, tokenIndex = position237, tokenIndex237 + if buffer[position] != rune('_') { + goto l236 + } position++ + if !_rules[ruledigit]() { + goto l236 + } } - l240: - goto l239 - l238: - position, tokenIndex = position238, tokenIndex238 + l237: + goto l235 + l236: + position, tokenIndex = position236, tokenIndex236 } - l239: - if !_rules[ruledigit]() { - goto l234 + add(rulefrac, position234) + } + return true + l233: + position, tokenIndex = position233, tokenIndex233 + return false + }, + /* 24 exp <- <(('e' / 'E') ('-' / '+')? digit (digit / ('_' digit))*)> */ + func() bool { + position239, tokenIndex239 := position, tokenIndex + { + position240 := position + { + position241, tokenIndex241 := position, tokenIndex + if buffer[position] != rune('e') { + goto l242 + } + position++ + goto l241 + l242: + position, tokenIndex = position241, tokenIndex241 + if buffer[position] != rune('E') { + goto l239 + } + position++ } - l242: + l241: { position243, tokenIndex243 := position, tokenIndex { - position244, tokenIndex244 := position, tokenIndex - if !_rules[ruledigit]() { - goto l245 + position245, tokenIndex245 := position, tokenIndex + if buffer[position] != rune('-') { + goto l246 } - goto l244 - l245: - position, tokenIndex = position244, tokenIndex244 - if buffer[position] != rune('_') { + position++ + goto l245 + l246: + position, tokenIndex = position245, tokenIndex245 + if buffer[position] != rune('+') { goto l243 } position++ - if !_rules[ruledigit]() { - goto l243 - } } - l244: - goto l242 + l245: + goto l244 l243: position, tokenIndex = position243, tokenIndex243 } - add(ruleexp, position235) + l244: + if !_rules[ruledigit]() { + goto l239 + } + l247: + { + position248, tokenIndex248 := position, tokenIndex + { + position249, tokenIndex249 := position, tokenIndex + if !_rules[ruledigit]() { + goto l250 + } + goto l249 + l250: + position, tokenIndex = position249, tokenIndex249 + if buffer[position] != rune('_') { + goto l248 + } + position++ + if !_rules[ruledigit]() { + goto l248 + } + } + l249: + goto l247 + l248: + position, tokenIndex = position248, tokenIndex248 + } + add(ruleexp, position240) } return true - l234: - position, tokenIndex = position234, tokenIndex234 + l239: + position, tokenIndex = position239, tokenIndex239 return false }, - /* 24 string <- <(mlLiteralString / literalString / mlBasicString / basicString)> */ + /* 25 string <- <(mlLiteralString / literalString / mlBasicString / basicString)> */ nil, - /* 25 basicString <- <(<('"' basicChar* '"')> Action17)> */ + /* 26 basicString <- <(<('"' basicChar* '"')> Action18)> */ nil, - /* 26 basicChar <- <(basicUnescaped / escaped)> */ + /* 27 basicChar <- <(basicUnescaped / escaped)> */ func() bool { - position248, tokenIndex248 := position, tokenIndex + position253, tokenIndex253 := position, tokenIndex { - position249 := position + position254 := position { - position250, tokenIndex250 := position, tokenIndex + position255, tokenIndex255 := position, tokenIndex { - position252 := position + position257 := position { switch buffer[position] { case ' ', '!': if c := buffer[position]; c < rune(' ') || c > rune('!') { - goto l251 + goto l256 } position++ break case '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', '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', '[': if c := buffer[position]; c < rune('#') || c > rune('[') { - goto l251 + goto l256 } position++ break default: if c := buffer[position]; c < rune(']') || c > rune('\U0010ffff') { - goto l251 + goto l256 } position++ break } } - add(rulebasicUnescaped, position252) + add(rulebasicUnescaped, position257) } - goto l250 - l251: - position, tokenIndex = position250, tokenIndex250 + goto l255 + l256: + position, tokenIndex = position255, tokenIndex255 { - position254 := position + position259 := position if !_rules[ruleescape]() { - goto l248 + goto l253 } { switch buffer[position] { case 'U': if buffer[position] != rune('U') { - goto l248 + goto l253 } position++ if !_rules[rulehexQuad]() { - goto l248 + goto l253 } if !_rules[rulehexQuad]() { - goto l248 + goto l253 } break case 'u': if buffer[position] != rune('u') { - goto l248 + goto l253 } position++ if !_rules[rulehexQuad]() { - goto l248 + goto l253 } break case '\\': if buffer[position] != rune('\\') { - goto l248 + goto l253 } position++ break case '/': if buffer[position] != rune('/') { - goto l248 + goto l253 } position++ break case '"': if buffer[position] != rune('"') { - goto l248 + goto l253 } position++ break case 'r': if buffer[position] != rune('r') { - goto l248 + goto l253 } position++ break case 'f': if buffer[position] != rune('f') { - goto l248 + goto l253 } position++ break case 'n': if buffer[position] != rune('n') { - goto l248 + goto l253 } position++ break case 't': if buffer[position] != rune('t') { - goto l248 + goto l253 } position++ break default: if buffer[position] != rune('b') { - goto l248 + goto l253 } position++ break } } - add(ruleescaped, position254) + add(ruleescaped, position259) } } - l250: - add(rulebasicChar, position249) + l255: + add(rulebasicChar, position254) } return true - l248: - position, tokenIndex = position248, tokenIndex248 + l253: + position, tokenIndex = position253, tokenIndex253 return false }, - /* 27 escaped <- <(escape ((&('U') ('U' hexQuad hexQuad)) | (&('u') ('u' hexQuad)) | (&('\\') '\\') | (&('/') '/') | (&('"') '"') | (&('r') 'r') | (&('f') 'f') | (&('n') 'n') | (&('t') 't') | (&('b') 'b')))> */ + /* 28 escaped <- <(escape ((&('U') ('U' hexQuad hexQuad)) | (&('u') ('u' hexQuad)) | (&('\\') '\\') | (&('/') '/') | (&('"') '"') | (&('r') 'r') | (&('f') 'f') | (&('n') 'n') | (&('t') 't') | (&('b') 'b')))> */ nil, - /* 28 basicUnescaped <- <((&(' ' | '!') [ -!]) | (&('#' | '$' | '%' | '&' | '\'' | '(' | ')' | '*' | '+' | ',' | '-' | '.' | '/' | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | ':' | ';' | '<' | '=' | '>' | '?' | '@' | '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' | '[') [#-[]) | (&(']' | '^' | '_' | '`' | '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' | '{' | '|' | '}' | '~' | '\u007f' | '\u0080' | '\u0081' | '\u0082' | '\u0083' | '\u0084' | '\u0085' | '\u0086' | '\u0087' | '\u0088' | '\u0089' | '\u008a' | '\u008b' | '\u008c' | '\u008d' | '\u008e' | '\u008f' | '\u0090' | '\u0091' | '\u0092' | '\u0093' | '\u0094' | '\u0095' | '\u0096' | '\u0097' | '\u0098' | '\u0099' | '\u009a' | '\u009b' | '\u009c' | '\u009d' | '\u009e' | '\u009f' | '\u00a0' | '¡' | '¢' | '£' | '¤' | '¥' | '¦' | '§' | '¨' | '©' | 'ª' | '«' | '¬' | '\u00ad' | '®' | '¯' | '°' | '±' | '²' | '³' | '´' | 'µ' | '¶' | '·' | '¸' | '¹' | 'º' | '»' | '¼' | '½' | '¾' | '¿' | 'À' | 'Á' | 'Â' | 'Ã' | 'Ä' | 'Å' | 'Æ' | 'Ç' | 'È' | 'É' | 'Ê' | 'Ë' | 'Ì' | 'Í' | 'Î' | 'Ï' | 'Ð' | 'Ñ' | 'Ò' | 'Ó' | 'Ô' | 'Õ' | 'Ö' | '×' | 'Ø' | 'Ù' | 'Ú' | 'Û' | 'Ü' | 'Ý' | 'Þ' | 'ß' | 'à' | 'á' | 'â' | 'ã' | 'ä' | 'å' | 'æ' | 'ç' | 'è' | 'é' | 'ê' | 'ë' | 'ì' | 'í' | 'î' | 'ï' | 'ð' | 'ñ' | 'ò' | 'ó' | 'ô' | 'õ' | 'ö' | '÷' | 'ø' | 'ù' | 'ú' | 'û' | 'ü' | 'ý' | 'þ' | 'ÿ') []-\U0010ffff]))> */ + /* 29 basicUnescaped <- <((&(' ' | '!') [ -!]) | (&('#' | '$' | '%' | '&' | '\'' | '(' | ')' | '*' | '+' | ',' | '-' | '.' | '/' | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | ':' | ';' | '<' | '=' | '>' | '?' | '@' | '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' | '[') [#-[]) | (&(']' | '^' | '_' | '`' | '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' | '{' | '|' | '}' | '~' | '\u007f' | '\u0080' | '\u0081' | '\u0082' | '\u0083' | '\u0084' | '\u0085' | '\u0086' | '\u0087' | '\u0088' | '\u0089' | '\u008a' | '\u008b' | '\u008c' | '\u008d' | '\u008e' | '\u008f' | '\u0090' | '\u0091' | '\u0092' | '\u0093' | '\u0094' | '\u0095' | '\u0096' | '\u0097' | '\u0098' | '\u0099' | '\u009a' | '\u009b' | '\u009c' | '\u009d' | '\u009e' | '\u009f' | '\u00a0' | '¡' | '¢' | '£' | '¤' | '¥' | '¦' | '§' | '¨' | '©' | 'ª' | '«' | '¬' | '\u00ad' | '®' | '¯' | '°' | '±' | '²' | '³' | '´' | 'µ' | '¶' | '·' | '¸' | '¹' | 'º' | '»' | '¼' | '½' | '¾' | '¿' | 'À' | 'Á' | 'Â' | 'Ã' | 'Ä' | 'Å' | 'Æ' | 'Ç' | 'È' | 'É' | 'Ê' | 'Ë' | 'Ì' | 'Í' | 'Î' | 'Ï' | 'Ð' | 'Ñ' | 'Ò' | 'Ó' | 'Ô' | 'Õ' | 'Ö' | '×' | 'Ø' | 'Ù' | 'Ú' | 'Û' | 'Ü' | 'Ý' | 'Þ' | 'ß' | 'à' | 'á' | 'â' | 'ã' | 'ä' | 'å' | 'æ' | 'ç' | 'è' | 'é' | 'ê' | 'ë' | 'ì' | 'í' | 'î' | 'ï' | 'ð' | 'ñ' | 'ò' | 'ó' | 'ô' | 'õ' | 'ö' | '÷' | 'ø' | 'ù' | 'ú' | 'û' | 'ü' | 'ý' | 'þ' | 'ÿ') []-\U0010ffff]))> */ nil, - /* 29 escape <- <'\\'> */ + /* 30 escape <- <'\\'> */ func() bool { - position258, tokenIndex258 := position, tokenIndex + position263, tokenIndex263 := position, tokenIndex { - position259 := position + position264 := position if buffer[position] != rune('\\') { - goto l258 + goto l263 } position++ - add(ruleescape, position259) + add(ruleescape, position264) } return true - l258: - position, tokenIndex = position258, tokenIndex258 + l263: + position, tokenIndex = position263, tokenIndex263 return false }, - /* 30 mlBasicString <- <('"' '"' '"' mlBasicBody ('"' '"' '"') Action18)> */ + /* 31 mlBasicString <- <('"' '"' '"' mlBasicBody ('"' '"' '"') Action19)> */ nil, - /* 31 mlBasicBody <- <((<(basicChar / newline)> Action19) / (escape newline wsnl))*> */ + /* 32 mlBasicBody <- <((<(basicChar / newline)> Action20) / (escape newline wsnl))*> */ nil, - /* 32 literalString <- <('\'' '\'' Action20)> */ + /* 33 literalString <- <('\'' '\'' Action21)> */ nil, - /* 33 literalChar <- <((&('\t') '\t') | (&(' ' | '!' | '"' | '#' | '$' | '%' | '&') [ -&]) | (&('(' | ')' | '*' | '+' | ',' | '-' | '.' | '/' | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | ':' | ';' | '<' | '=' | '>' | '?' | '@' | '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' | '[' | '\\' | ']' | '^' | '_' | '`' | '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' | '{' | '|' | '}' | '~' | '\u007f' | '\u0080' | '\u0081' | '\u0082' | '\u0083' | '\u0084' | '\u0085' | '\u0086' | '\u0087' | '\u0088' | '\u0089' | '\u008a' | '\u008b' | '\u008c' | '\u008d' | '\u008e' | '\u008f' | '\u0090' | '\u0091' | '\u0092' | '\u0093' | '\u0094' | '\u0095' | '\u0096' | '\u0097' | '\u0098' | '\u0099' | '\u009a' | '\u009b' | '\u009c' | '\u009d' | '\u009e' | '\u009f' | '\u00a0' | '¡' | '¢' | '£' | '¤' | '¥' | '¦' | '§' | '¨' | '©' | 'ª' | '«' | '¬' | '\u00ad' | '®' | '¯' | '°' | '±' | '²' | '³' | '´' | 'µ' | '¶' | '·' | '¸' | '¹' | 'º' | '»' | '¼' | '½' | '¾' | '¿' | 'À' | 'Á' | 'Â' | 'Ã' | 'Ä' | 'Å' | 'Æ' | 'Ç' | 'È' | 'É' | 'Ê' | 'Ë' | 'Ì' | 'Í' | 'Î' | 'Ï' | 'Ð' | 'Ñ' | 'Ò' | 'Ó' | 'Ô' | 'Õ' | 'Ö' | '×' | 'Ø' | 'Ù' | 'Ú' | 'Û' | 'Ü' | 'Ý' | 'Þ' | 'ß' | 'à' | 'á' | 'â' | 'ã' | 'ä' | 'å' | 'æ' | 'ç' | 'è' | 'é' | 'ê' | 'ë' | 'ì' | 'í' | 'î' | 'ï' | 'ð' | 'ñ' | 'ò' | 'ó' | 'ô' | 'õ' | 'ö' | '÷' | 'ø' | 'ù' | 'ú' | 'û' | 'ü' | 'ý' | 'þ' | 'ÿ') [(-\U0010ffff]))> */ + /* 34 literalChar <- <((&('\t') '\t') | (&(' ' | '!' | '"' | '#' | '$' | '%' | '&') [ -&]) | (&('(' | ')' | '*' | '+' | ',' | '-' | '.' | '/' | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | ':' | ';' | '<' | '=' | '>' | '?' | '@' | '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' | '[' | '\\' | ']' | '^' | '_' | '`' | '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' | '{' | '|' | '}' | '~' | '\u007f' | '\u0080' | '\u0081' | '\u0082' | '\u0083' | '\u0084' | '\u0085' | '\u0086' | '\u0087' | '\u0088' | '\u0089' | '\u008a' | '\u008b' | '\u008c' | '\u008d' | '\u008e' | '\u008f' | '\u0090' | '\u0091' | '\u0092' | '\u0093' | '\u0094' | '\u0095' | '\u0096' | '\u0097' | '\u0098' | '\u0099' | '\u009a' | '\u009b' | '\u009c' | '\u009d' | '\u009e' | '\u009f' | '\u00a0' | '¡' | '¢' | '£' | '¤' | '¥' | '¦' | '§' | '¨' | '©' | 'ª' | '«' | '¬' | '\u00ad' | '®' | '¯' | '°' | '±' | '²' | '³' | '´' | 'µ' | '¶' | '·' | '¸' | '¹' | 'º' | '»' | '¼' | '½' | '¾' | '¿' | 'À' | 'Á' | 'Â' | 'Ã' | 'Ä' | 'Å' | 'Æ' | 'Ç' | 'È' | 'É' | 'Ê' | 'Ë' | 'Ì' | 'Í' | 'Î' | 'Ï' | 'Ð' | 'Ñ' | 'Ò' | 'Ó' | 'Ô' | 'Õ' | 'Ö' | '×' | 'Ø' | 'Ù' | 'Ú' | 'Û' | 'Ü' | 'Ý' | 'Þ' | 'ß' | 'à' | 'á' | 'â' | 'ã' | 'ä' | 'å' | 'æ' | 'ç' | 'è' | 'é' | 'ê' | 'ë' | 'ì' | 'í' | 'î' | 'ï' | 'ð' | 'ñ' | 'ò' | 'ó' | 'ô' | 'õ' | 'ö' | '÷' | 'ø' | 'ù' | 'ú' | 'û' | 'ü' | 'ý' | 'þ' | 'ÿ') [(-\U0010ffff]))> */ nil, - /* 34 mlLiteralString <- <('\'' '\'' '\'' ('\'' '\'' '\'') Action21)> */ + /* 35 mlLiteralString <- <('\'' '\'' '\'' ('\'' '\'' '\'') Action22)> */ nil, - /* 35 mlLiteralBody <- <(!('\'' '\'' '\'') (mlLiteralChar / newline))*> */ + /* 36 mlLiteralBody <- <(!('\'' '\'' '\'') (mlLiteralChar / newline))*> */ nil, - /* 36 mlLiteralChar <- <('\t' / [ -\U0010ffff])> */ + /* 37 mlLiteralChar <- <('\t' / [ -\U0010ffff])> */ nil, - /* 37 hexdigit <- <((&('a' | 'b' | 'c' | 'd' | 'e' | 'f') [a-f]) | (&('A' | 'B' | 'C' | 'D' | 'E' | 'F') [A-F]) | (&('0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9') [0-9]))> */ + /* 38 hexdigit <- <((&('a' | 'b' | 'c' | 'd' | 'e' | 'f') [a-f]) | (&('A' | 'B' | 'C' | 'D' | 'E' | 'F') [A-F]) | (&('0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9') [0-9]))> */ func() bool { - position267, tokenIndex267 := position, tokenIndex + position272, tokenIndex272 := position, tokenIndex { - position268 := position + position273 := position { switch buffer[position] { case 'a', 'b', 'c', 'd', 'e', 'f': if c := buffer[position]; c < rune('a') || c > rune('f') { - goto l267 + goto l272 } position++ break case 'A', 'B', 'C', 'D', 'E', 'F': if c := buffer[position]; c < rune('A') || c > rune('F') { - goto l267 + goto l272 } position++ break default: if c := buffer[position]; c < rune('0') || c > rune('9') { - goto l267 + goto l272 } position++ break } } - add(rulehexdigit, position268) + add(rulehexdigit, position273) } return true - l267: - position, tokenIndex = position267, tokenIndex267 + l272: + position, tokenIndex = position272, tokenIndex272 return false }, - /* 38 hexQuad <- <(hexdigit hexdigit hexdigit hexdigit)> */ + /* 39 hexQuad <- <(hexdigit hexdigit hexdigit hexdigit)> */ func() bool { - position270, tokenIndex270 := position, tokenIndex + position275, tokenIndex275 := position, tokenIndex { - position271 := position + position276 := position if !_rules[rulehexdigit]() { - goto l270 + goto l275 } if !_rules[rulehexdigit]() { - goto l270 + goto l275 } if !_rules[rulehexdigit]() { - goto l270 + goto l275 } if !_rules[rulehexdigit]() { - goto l270 + goto l275 } - add(rulehexQuad, position271) + add(rulehexQuad, position276) } return true - l270: - position, tokenIndex = position270, tokenIndex270 + l275: + position, tokenIndex = position275, tokenIndex275 return false }, - /* 39 boolean <- <(('t' 'r' 'u' 'e') / ('f' 'a' 'l' 's' 'e'))> */ + /* 40 boolean <- <(('t' 'r' 'u' 'e') / ('f' 'a' 'l' 's' 'e'))> */ nil, - /* 40 dateFullYear <- */ + /* 41 dateFullYear <- */ nil, - /* 41 dateMonth <- */ + /* 42 dateMonth <- */ nil, - /* 42 dateMDay <- */ + /* 43 dateMDay <- */ nil, - /* 43 timeHour <- */ + /* 44 timeHour <- */ func() bool { - position276, tokenIndex276 := position, tokenIndex + position281, tokenIndex281 := position, tokenIndex { - position277 := position + position282 := position if !_rules[ruledigitDual]() { - goto l276 + goto l281 } - add(ruletimeHour, position277) + add(ruletimeHour, position282) } return true - l276: - position, tokenIndex = position276, tokenIndex276 + l281: + position, tokenIndex = position281, tokenIndex281 return false }, - /* 44 timeMinute <- */ + /* 45 timeMinute <- */ func() bool { - position278, tokenIndex278 := position, tokenIndex + position283, tokenIndex283 := position, tokenIndex { - position279 := position + position284 := position if !_rules[ruledigitDual]() { - goto l278 + goto l283 } - add(ruletimeMinute, position279) + add(ruletimeMinute, position284) } return true - l278: - position, tokenIndex = position278, tokenIndex278 + l283: + position, tokenIndex = position283, tokenIndex283 return false }, - /* 45 timeSecond <- */ + /* 46 timeSecond <- */ nil, - /* 46 timeSecfrac <- <('.' digit+)> */ + /* 47 timeSecfrac <- <('.' digit+)> */ nil, - /* 47 timeNumoffset <- <(('-' / '+') timeHour ':' timeMinute)> */ + /* 48 timeNumoffset <- <(('-' / '+') timeHour ':' timeMinute)> */ nil, - /* 48 timeOffset <- <('Z' / timeNumoffset)> */ + /* 49 timeOffset <- <('Z' / timeNumoffset)> */ nil, - /* 49 partialTime <- <(timeHour ':' timeMinute ':' timeSecond timeSecfrac?)> */ + /* 50 partialTime <- <(timeHour ':' timeMinute ':' timeSecond timeSecfrac?)> */ func() bool { - position284, tokenIndex284 := position, tokenIndex + position289, tokenIndex289 := position, tokenIndex { - position285 := position + position290 := position if !_rules[ruletimeHour]() { - goto l284 + goto l289 } if buffer[position] != rune(':') { - goto l284 + goto l289 } position++ if !_rules[ruletimeMinute]() { - goto l284 + goto l289 } if buffer[position] != rune(':') { - goto l284 + goto l289 } position++ { - position286 := position + position291 := position if !_rules[ruledigitDual]() { - goto l284 + goto l289 } - add(ruletimeSecond, position286) + add(ruletimeSecond, position291) } { - position287, tokenIndex287 := position, tokenIndex + position292, tokenIndex292 := position, tokenIndex { - position289 := position + position294 := position if buffer[position] != rune('.') { - goto l287 + goto l292 } position++ if !_rules[ruledigit]() { - goto l287 + goto l292 } - l290: + l295: { - position291, tokenIndex291 := position, tokenIndex + position296, tokenIndex296 := position, tokenIndex if !_rules[ruledigit]() { - goto l291 + goto l296 } - goto l290 - l291: - position, tokenIndex = position291, tokenIndex291 + goto l295 + l296: + position, tokenIndex = position296, tokenIndex296 } - add(ruletimeSecfrac, position289) + add(ruletimeSecfrac, position294) } - goto l288 - l287: - position, tokenIndex = position287, tokenIndex287 + goto l293 + l292: + position, tokenIndex = position292, tokenIndex292 } - l288: - add(rulepartialTime, position285) + l293: + add(rulepartialTime, position290) } return true - l284: - position, tokenIndex = position284, tokenIndex284 + l289: + position, tokenIndex = position289, tokenIndex289 return false }, - /* 50 fullDate <- <(dateFullYear '-' dateMonth '-' dateMDay)> */ + /* 51 fullDate <- <(dateFullYear '-' dateMonth '-' dateMDay)> */ nil, - /* 51 fullTime <- <(partialTime timeOffset)> */ + /* 52 fullTime <- <(partialTime timeOffset?)> */ nil, - /* 52 datetime <- <((fullDate ('T' fullTime)?) / partialTime)> */ + /* 53 datetime <- <((fullDate ('T' fullTime)?) / partialTime)> */ nil, - /* 53 digit <- <[0-9]> */ + /* 54 digit <- <[0-9]> */ func() bool { - position295, tokenIndex295 := position, tokenIndex + position300, tokenIndex300 := position, tokenIndex { - position296 := position + position301 := position if c := buffer[position]; c < rune('0') || c > rune('9') { - goto l295 + goto l300 } position++ - add(ruledigit, position296) + add(ruledigit, position301) } return true - l295: - position, tokenIndex = position295, tokenIndex295 + l300: + position, tokenIndex = position300, tokenIndex300 return false }, - /* 54 digitDual <- <(digit digit)> */ - func() bool { - position297, tokenIndex297 := position, tokenIndex - { - position298 := position - if !_rules[ruledigit]() { - goto l297 - } - if !_rules[ruledigit]() { - goto l297 - } - add(ruledigitDual, position298) - } - return true - l297: - position, tokenIndex = position297, tokenIndex297 - return false - }, - /* 55 digitQuad <- <(digitDual digitDual)> */ - nil, - /* 56 array <- <('[' Action22 wsnl arrayValues? wsnl ']')> */ - nil, - /* 57 arrayValues <- <(val Action23 (wsnl comment? wsnl arraySep wsnl comment? wsnl val Action24)* wsnl arraySep? wsnl comment?)> */ - nil, - /* 58 arraySep <- <','> */ + /* 55 digitDual <- <(digit digit)> */ func() bool { position302, tokenIndex302 := position, tokenIndex { position303 := position - if buffer[position] != rune(',') { + if !_rules[ruledigit]() { goto l302 } - position++ - add(rulearraySep, position303) + if !_rules[ruledigit]() { + goto l302 + } + add(ruledigitDual, position303) } return true l302: position, tokenIndex = position302, tokenIndex302 return false }, - /* 60 Action0 <- <{ _ = buffer }> */ + /* 56 digitQuad <- <(digitDual digitDual)> */ + nil, + /* 57 array <- <('[' Action23 wsnl arrayValues? wsnl ']')> */ + nil, + /* 58 arrayValues <- <(val Action24 (wsnl comment? wsnl arraySep wsnl comment? wsnl val Action25)* wsnl arraySep? wsnl comment?)> */ + nil, + /* 59 arraySep <- <','> */ + func() bool { + position307, tokenIndex307 := position, tokenIndex + { + position308 := position + if buffer[position] != rune(',') { + goto l307 + } + position++ + add(rulearraySep, position308) + } + return true + l307: + position, tokenIndex = position307, tokenIndex307 + return false + }, + /* 61 Action0 <- <{ _ = buffer }> */ nil, nil, - /* 62 Action1 <- <{ p.SetTableString(begin, end) }> */ + /* 63 Action1 <- <{ p.SetTableString(begin, end) }> */ nil, - /* 63 Action2 <- <{ p.AddLineCount(end - begin) }> */ + /* 64 Action2 <- <{ p.AddLineCount(end - begin) }> */ nil, - /* 64 Action3 <- <{ p.AddLineCount(end - begin) }> */ + /* 65 Action3 <- <{ p.AddLineCount(end - begin) }> */ nil, - /* 65 Action4 <- <{ p.AddKeyValue() }> */ + /* 66 Action4 <- <{ p.AddKeyValue() }> */ nil, - /* 66 Action5 <- <{ p.SetKey(p.buffer, begin, end) }> */ + /* 67 Action5 <- <{ p.SetKey(p.buffer, begin, end) }> */ nil, - /* 67 Action6 <- <{ p.SetKey(p.buffer, begin-1, end+1) }> */ + /* 68 Action6 <- <{ p.SetKey(p.buffer, begin, end) }> */ nil, - /* 68 Action7 <- <{ p.SetTime(begin, end) }> */ + /* 69 Action7 <- <{ p.SetTime(begin, end) }> */ nil, - /* 69 Action8 <- <{ p.SetFloat64(begin, end) }> */ + /* 70 Action8 <- <{ p.SetFloat64(begin, end) }> */ nil, - /* 70 Action9 <- <{ p.SetInt64(begin, end) }> */ + /* 71 Action9 <- <{ p.SetInt64(begin, end) }> */ nil, - /* 71 Action10 <- <{ p.SetString(begin, end) }> */ + /* 72 Action10 <- <{ p.SetString(begin, end) }> */ nil, - /* 72 Action11 <- <{ p.SetBool(begin, end) }> */ + /* 73 Action11 <- <{ p.SetBool(begin, end) }> */ nil, - /* 73 Action12 <- <{ p.SetArray(begin, end) }> */ + /* 74 Action12 <- <{ p.SetArray(begin, end) }> */ nil, - /* 74 Action13 <- <{ p.SetTable(p.buffer, begin, end) }> */ + /* 75 Action13 <- <{ p.SetTable(p.buffer, begin, end) }> */ nil, - /* 75 Action14 <- <{ p.SetArrayTable(p.buffer, begin, end) }> */ + /* 76 Action14 <- <{ p.SetArrayTable(p.buffer, begin, end) }> */ nil, - /* 76 Action15 <- <{ p.StartInlineTable() }> */ + /* 77 Action15 <- <{ p.StartInlineTable() }> */ nil, - /* 77 Action16 <- <{ p.EndInlineTable() }> */ + /* 78 Action16 <- <{ p.EndInlineTable() }> */ nil, - /* 78 Action17 <- <{ p.SetBasicString(p.buffer, begin, end) }> */ + /* 79 Action17 <- <{ p.AddTableKey() }> */ nil, - /* 79 Action18 <- <{ p.SetMultilineString() }> */ + /* 80 Action18 <- <{ p.SetBasicString(p.buffer, begin, end) }> */ nil, - /* 80 Action19 <- <{ p.AddMultilineBasicBody(p.buffer, begin, end) }> */ + /* 81 Action19 <- <{ p.SetMultilineString() }> */ nil, - /* 81 Action20 <- <{ p.SetLiteralString(p.buffer, begin, end) }> */ + /* 82 Action20 <- <{ p.AddMultilineBasicBody(p.buffer, begin, end) }> */ nil, - /* 82 Action21 <- <{ p.SetMultilineLiteralString(p.buffer, begin, end) }> */ + /* 83 Action21 <- <{ p.SetLiteralString(p.buffer, begin, end) }> */ nil, - /* 83 Action22 <- <{ p.StartArray() }> */ + /* 84 Action22 <- <{ p.SetMultilineLiteralString(p.buffer, begin, end) }> */ nil, - /* 84 Action23 <- <{ p.AddArrayVal() }> */ + /* 85 Action23 <- <{ p.StartArray() }> */ nil, - /* 85 Action24 <- <{ p.AddArrayVal() }> */ + /* 86 Action24 <- <{ p.AddArrayVal() }> */ + nil, + /* 87 Action25 <- <{ p.AddArrayVal() }> */ nil, } p.rules = _rules diff --git a/vendor/github.com/opentracing/opentracing-go/CHANGELOG.md b/vendor/github.com/opentracing/opentracing-go/CHANGELOG.md new file mode 100644 index 0000000000..1fc9fdf7f3 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/CHANGELOG.md @@ -0,0 +1,14 @@ +Changes by Version +================== + +1.1.0 (unreleased) +------------------- + +- Deprecate InitGlobalTracer() in favor of SetGlobalTracer() + + +1.0.0 (2016-09-26) +------------------- + +- This release implements OpenTracing Specification 1.0 (http://opentracing.io/spec) + diff --git a/vendor/github.com/Azure/go-autorest/LICENSE b/vendor/github.com/opentracing/opentracing-go/LICENSE similarity index 94% rename from vendor/github.com/Azure/go-autorest/LICENSE rename to vendor/github.com/opentracing/opentracing-go/LICENSE index b9d6a27ea9..f0027349e8 100644 --- a/vendor/github.com/Azure/go-autorest/LICENSE +++ b/vendor/github.com/opentracing/opentracing-go/LICENSE @@ -1,4 +1,3 @@ - Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -176,7 +175,18 @@ END OF TERMS AND CONDITIONS - Copyright 2015 Microsoft Corporation + 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 2016 The OpenTracing Authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/vendor/github.com/opentracing/opentracing-go/Makefile b/vendor/github.com/opentracing/opentracing-go/Makefile new file mode 100644 index 0000000000..d49a5c0d44 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/Makefile @@ -0,0 +1,32 @@ +PACKAGES := . ./mocktracer/... ./ext/... + +.DEFAULT_GOAL := test-and-lint + +.PHONE: test-and-lint + +test-and-lint: test lint + +.PHONY: test +test: + go test -v -cover -race ./... + +cover: + @rm -rf cover-all.out + $(foreach pkg, $(PACKAGES), $(MAKE) cover-pkg PKG=$(pkg) || true;) + @grep mode: cover.out > coverage.out + @cat cover-all.out >> coverage.out + go tool cover -html=coverage.out -o cover.html + @rm -rf cover.out cover-all.out coverage.out + +cover-pkg: + go test -coverprofile cover.out $(PKG) + @grep -v mode: cover.out >> cover-all.out + +.PHONY: lint +lint: + go fmt ./... + golint ./... + @# Run again with magic to exit non-zero if golint outputs anything. + @! (golint ./... | read dummy) + go vet ./... + diff --git a/vendor/github.com/opentracing/opentracing-go/README.md b/vendor/github.com/opentracing/opentracing-go/README.md new file mode 100644 index 0000000000..007ee237c8 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/README.md @@ -0,0 +1,171 @@ +[![Gitter chat](http://img.shields.io/badge/gitter-join%20chat%20%E2%86%92-brightgreen.svg)](https://gitter.im/opentracing/public) [![Build Status](https://travis-ci.org/opentracing/opentracing-go.svg?branch=master)](https://travis-ci.org/opentracing/opentracing-go) [![GoDoc](https://godoc.org/github.com/opentracing/opentracing-go?status.svg)](http://godoc.org/github.com/opentracing/opentracing-go) +[![Sourcegraph Badge](https://sourcegraph.com/github.com/opentracing/opentracing-go/-/badge.svg)](https://sourcegraph.com/github.com/opentracing/opentracing-go?badge) + +# OpenTracing API for Go + +This package is a Go platform API for OpenTracing. + +## Required Reading + +In order to understand the Go platform API, one must first be familiar with the +[OpenTracing project](http://opentracing.io) and +[terminology](http://opentracing.io/documentation/pages/spec.html) more specifically. + +## API overview for those adding instrumentation + +Everyday consumers of this `opentracing` package really only need to worry +about a couple of key abstractions: the `StartSpan` function, the `Span` +interface, and binding a `Tracer` at `main()`-time. Here are code snippets +demonstrating some important use cases. + +#### Singleton initialization + +The simplest starting point is `./default_tracer.go`. As early as possible, call + +```go + import "github.com/opentracing/opentracing-go" + import ".../some_tracing_impl" + + func main() { + opentracing.SetGlobalTracer( + // tracing impl specific: + some_tracing_impl.New(...), + ) + ... + } +``` + +#### Non-Singleton initialization + +If you prefer direct control to singletons, manage ownership of the +`opentracing.Tracer` implementation explicitly. + +#### Creating a Span given an existing Go `context.Context` + +If you use `context.Context` in your application, OpenTracing's Go library will +happily rely on it for `Span` propagation. To start a new (blocking child) +`Span`, you can use `StartSpanFromContext`. + +```go + func xyz(ctx context.Context, ...) { + ... + span, ctx := opentracing.StartSpanFromContext(ctx, "operation_name") + defer span.Finish() + span.LogFields( + log.String("event", "soft error"), + log.String("type", "cache timeout"), + log.Int("waited.millis", 1500)) + ... + } +``` + +#### Starting an empty trace by creating a "root span" + +It's always possible to create a "root" `Span` with no parent or other causal +reference. + +```go + func xyz() { + ... + sp := opentracing.StartSpan("operation_name") + defer sp.Finish() + ... + } +``` + +#### Creating a (child) Span given an existing (parent) Span + +```go + func xyz(parentSpan opentracing.Span, ...) { + ... + sp := opentracing.StartSpan( + "operation_name", + opentracing.ChildOf(parentSpan.Context())) + defer sp.Finish() + ... + } +``` + +#### Serializing to the wire + +```go + func makeSomeRequest(ctx context.Context) ... { + if span := opentracing.SpanFromContext(ctx); span != nil { + httpClient := &http.Client{} + httpReq, _ := http.NewRequest("GET", "http://myservice/", nil) + + // Transmit the span's TraceContext as HTTP headers on our + // outbound request. + opentracing.GlobalTracer().Inject( + span.Context(), + opentracing.HTTPHeaders, + opentracing.HTTPHeadersCarrier(httpReq.Header)) + + resp, err := httpClient.Do(httpReq) + ... + } + ... + } +``` + +#### Deserializing from the wire + +```go + http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { + var serverSpan opentracing.Span + appSpecificOperationName := ... + wireContext, err := opentracing.GlobalTracer().Extract( + opentracing.HTTPHeaders, + opentracing.HTTPHeadersCarrier(req.Header)) + if err != nil { + // Optionally record something about err here + } + + // Create the span referring to the RPC client if available. + // If wireContext == nil, a root span will be created. + serverSpan = opentracing.StartSpan( + appSpecificOperationName, + ext.RPCServerOption(wireContext)) + + defer serverSpan.Finish() + + ctx := opentracing.ContextWithSpan(context.Background(), serverSpan) + ... + } +``` + +#### Conditionally capture a field using `log.Noop` + +In some situations, you may want to dynamically decide whether or not +to log a field. For example, you may want to capture additional data, +such as a customer ID, in non-production environments: + +```go + func Customer(order *Order) log.Field { + if os.Getenv("ENVIRONMENT") == "dev" { + return log.String("customer", order.Customer.ID) + } + return log.Noop() + } +``` + +#### Goroutine-safety + +The entire public API is goroutine-safe and does not require external +synchronization. + +## API pointers for those implementing a tracing system + +Tracing system implementors may be able to reuse or copy-paste-modify the `basictracer` package, found [here](https://github.com/opentracing/basictracer-go). In particular, see `basictracer.New(...)`. + +## API compatibility + +For the time being, "mild" backwards-incompatible changes may be made without changing the major version number. As OpenTracing and `opentracing-go` mature, backwards compatibility will become more of a priority. + +## Tracer test suite + +A test suite is available in the [harness](https://godoc.org/github.com/opentracing/opentracing-go/harness) package that can assist Tracer implementors to assert that their Tracer is working correctly. + +## Licensing + +[Apache 2.0 License](./LICENSE). diff --git a/vendor/github.com/opentracing/opentracing-go/ext/tags.go b/vendor/github.com/opentracing/opentracing-go/ext/tags.go new file mode 100644 index 0000000000..8800129a23 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/ext/tags.go @@ -0,0 +1,210 @@ +package ext + +import opentracing "github.com/opentracing/opentracing-go" + +// These constants define common tag names recommended for better portability across +// tracing systems and languages/platforms. +// +// The tag names are defined as typed strings, so that in addition to the usual use +// +// span.setTag(TagName, value) +// +// they also support value type validation via this additional syntax: +// +// TagName.Set(span, value) +// +var ( + ////////////////////////////////////////////////////////////////////// + // SpanKind (client/server or producer/consumer) + ////////////////////////////////////////////////////////////////////// + + // SpanKind hints at relationship between spans, e.g. client/server + SpanKind = spanKindTagName("span.kind") + + // SpanKindRPCClient marks a span representing the client-side of an RPC + // or other remote call + SpanKindRPCClientEnum = SpanKindEnum("client") + SpanKindRPCClient = opentracing.Tag{Key: string(SpanKind), Value: SpanKindRPCClientEnum} + + // SpanKindRPCServer marks a span representing the server-side of an RPC + // or other remote call + SpanKindRPCServerEnum = SpanKindEnum("server") + SpanKindRPCServer = opentracing.Tag{Key: string(SpanKind), Value: SpanKindRPCServerEnum} + + // SpanKindProducer marks a span representing the producer-side of a + // message bus + SpanKindProducerEnum = SpanKindEnum("producer") + SpanKindProducer = opentracing.Tag{Key: string(SpanKind), Value: SpanKindProducerEnum} + + // SpanKindConsumer marks a span representing the consumer-side of a + // message bus + SpanKindConsumerEnum = SpanKindEnum("consumer") + SpanKindConsumer = opentracing.Tag{Key: string(SpanKind), Value: SpanKindConsumerEnum} + + ////////////////////////////////////////////////////////////////////// + // Component name + ////////////////////////////////////////////////////////////////////// + + // Component is a low-cardinality identifier of the module, library, + // or package that is generating a span. + Component = stringTagName("component") + + ////////////////////////////////////////////////////////////////////// + // Sampling hint + ////////////////////////////////////////////////////////////////////// + + // SamplingPriority determines the priority of sampling this Span. + SamplingPriority = uint16TagName("sampling.priority") + + ////////////////////////////////////////////////////////////////////// + // Peer tags. These tags can be emitted by either client-side of + // server-side to describe the other side/service in a peer-to-peer + // communications, like an RPC call. + ////////////////////////////////////////////////////////////////////// + + // PeerService records the service name of the peer. + PeerService = stringTagName("peer.service") + + // PeerAddress records the address name of the peer. This may be a "ip:port", + // a bare "hostname", a FQDN or even a database DSN substring + // like "mysql://username@127.0.0.1:3306/dbname" + PeerAddress = stringTagName("peer.address") + + // PeerHostname records the host name of the peer + PeerHostname = stringTagName("peer.hostname") + + // PeerHostIPv4 records IP v4 host address of the peer + PeerHostIPv4 = ipv4Tag("peer.ipv4") + + // PeerHostIPv6 records IP v6 host address of the peer + PeerHostIPv6 = stringTagName("peer.ipv6") + + // PeerPort records port number of the peer + PeerPort = uint16TagName("peer.port") + + ////////////////////////////////////////////////////////////////////// + // HTTP Tags + ////////////////////////////////////////////////////////////////////// + + // HTTPUrl should be the URL of the request being handled in this segment + // of the trace, in standard URI format. The protocol is optional. + HTTPUrl = stringTagName("http.url") + + // HTTPMethod is the HTTP method of the request, and is case-insensitive. + HTTPMethod = stringTagName("http.method") + + // HTTPStatusCode is the numeric HTTP status code (200, 404, etc) of the + // HTTP response. + HTTPStatusCode = uint16TagName("http.status_code") + + ////////////////////////////////////////////////////////////////////// + // DB Tags + ////////////////////////////////////////////////////////////////////// + + // DBInstance is database instance name. + DBInstance = stringTagName("db.instance") + + // DBStatement is a database statement for the given database type. + // It can be a query or a prepared statement (i.e., before substitution). + DBStatement = stringTagName("db.statement") + + // DBType is a database type. For any SQL database, "sql". + // For others, the lower-case database category, e.g. "redis" + DBType = stringTagName("db.type") + + // DBUser is a username for accessing database. + DBUser = stringTagName("db.user") + + ////////////////////////////////////////////////////////////////////// + // Message Bus Tag + ////////////////////////////////////////////////////////////////////// + + // MessageBusDestination is an address at which messages can be exchanged + MessageBusDestination = stringTagName("message_bus.destination") + + ////////////////////////////////////////////////////////////////////// + // Error Tag + ////////////////////////////////////////////////////////////////////// + + // Error indicates that operation represented by the span resulted in an error. + Error = boolTagName("error") +) + +// --- + +// SpanKindEnum represents common span types +type SpanKindEnum string + +type spanKindTagName string + +// Set adds a string tag to the `span` +func (tag spanKindTagName) Set(span opentracing.Span, value SpanKindEnum) { + span.SetTag(string(tag), value) +} + +type rpcServerOption struct { + clientContext opentracing.SpanContext +} + +func (r rpcServerOption) Apply(o *opentracing.StartSpanOptions) { + if r.clientContext != nil { + opentracing.ChildOf(r.clientContext).Apply(o) + } + SpanKindRPCServer.Apply(o) +} + +// RPCServerOption returns a StartSpanOption appropriate for an RPC server span +// with `client` representing the metadata for the remote peer Span if available. +// In case client == nil, due to the client not being instrumented, this RPC +// server span will be a root span. +func RPCServerOption(client opentracing.SpanContext) opentracing.StartSpanOption { + return rpcServerOption{client} +} + +// --- + +type stringTagName string + +// Set adds a string tag to the `span` +func (tag stringTagName) Set(span opentracing.Span, value string) { + span.SetTag(string(tag), value) +} + +// --- + +type uint32TagName string + +// Set adds a uint32 tag to the `span` +func (tag uint32TagName) Set(span opentracing.Span, value uint32) { + span.SetTag(string(tag), value) +} + +// --- + +type uint16TagName string + +// Set adds a uint16 tag to the `span` +func (tag uint16TagName) Set(span opentracing.Span, value uint16) { + span.SetTag(string(tag), value) +} + +// --- + +type boolTagName string + +// Add adds a bool tag to the `span` +func (tag boolTagName) Set(span opentracing.Span, value bool) { + span.SetTag(string(tag), value) +} + +type ipv4Tag string + +// Set adds IP v4 host address of the peer as an uint32 value to the `span`, keep this for backward and zipkin compatibility +func (tag ipv4Tag) Set(span opentracing.Span, value uint32) { + span.SetTag(string(tag), value) +} + +// SetString records IP v4 host address of the peer as a .-separated tuple to the `span`. E.g., "127.0.0.1" +func (tag ipv4Tag) SetString(span opentracing.Span, value string) { + span.SetTag(string(tag), value) +} diff --git a/vendor/github.com/opentracing/opentracing-go/globaltracer.go b/vendor/github.com/opentracing/opentracing-go/globaltracer.go new file mode 100644 index 0000000000..8c8e793ff2 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/globaltracer.go @@ -0,0 +1,32 @@ +package opentracing + +var ( + globalTracer Tracer = NoopTracer{} +) + +// SetGlobalTracer sets the [singleton] opentracing.Tracer returned by +// GlobalTracer(). Those who use GlobalTracer (rather than directly manage an +// opentracing.Tracer instance) should call SetGlobalTracer as early as +// possible in main(), prior to calling the `StartSpan` global func below. +// Prior to calling `SetGlobalTracer`, any Spans started via the `StartSpan` +// (etc) globals are noops. +func SetGlobalTracer(tracer Tracer) { + globalTracer = tracer +} + +// GlobalTracer returns the global singleton `Tracer` implementation. +// Before `SetGlobalTracer()` is called, the `GlobalTracer()` is a noop +// implementation that drops all data handed to it. +func GlobalTracer() Tracer { + return globalTracer +} + +// StartSpan defers to `Tracer.StartSpan`. See `GlobalTracer()`. +func StartSpan(operationName string, opts ...StartSpanOption) Span { + return globalTracer.StartSpan(operationName, opts...) +} + +// InitGlobalTracer is deprecated. Please use SetGlobalTracer. +func InitGlobalTracer(tracer Tracer) { + SetGlobalTracer(tracer) +} diff --git a/vendor/github.com/opentracing/opentracing-go/gocontext.go b/vendor/github.com/opentracing/opentracing-go/gocontext.go new file mode 100644 index 0000000000..05a62e70b1 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/gocontext.go @@ -0,0 +1,54 @@ +package opentracing + +import "context" + +type contextKey struct{} + +var activeSpanKey = contextKey{} + +// ContextWithSpan returns a new `context.Context` that holds a reference to +// `span`'s SpanContext. +func ContextWithSpan(ctx context.Context, span Span) context.Context { + return context.WithValue(ctx, activeSpanKey, span) +} + +// SpanFromContext returns the `Span` previously associated with `ctx`, or +// `nil` if no such `Span` could be found. +// +// NOTE: context.Context != SpanContext: the former is Go's intra-process +// context propagation mechanism, and the latter houses OpenTracing's per-Span +// identity and baggage information. +func SpanFromContext(ctx context.Context) Span { + val := ctx.Value(activeSpanKey) + if sp, ok := val.(Span); ok { + return sp + } + return nil +} + +// StartSpanFromContext starts and returns a Span with `operationName`, using +// any Span found within `ctx` as a ChildOfRef. If no such parent could be +// found, StartSpanFromContext creates a root (parentless) Span. +// +// The second return value is a context.Context object built around the +// returned Span. +// +// Example usage: +// +// SomeFunction(ctx context.Context, ...) { +// sp, ctx := opentracing.StartSpanFromContext(ctx, "SomeFunction") +// defer sp.Finish() +// ... +// } +func StartSpanFromContext(ctx context.Context, operationName string, opts ...StartSpanOption) (Span, context.Context) { + return startSpanFromContextWithTracer(ctx, GlobalTracer(), operationName, opts...) +} + +// startSpanFromContextWithTracer is factored out for testing purposes. +func startSpanFromContextWithTracer(ctx context.Context, tracer Tracer, operationName string, opts ...StartSpanOption) (Span, context.Context) { + if parentSpan := SpanFromContext(ctx); parentSpan != nil { + opts = append(opts, ChildOf(parentSpan.Context())) + } + span := tracer.StartSpan(operationName, opts...) + return span, ContextWithSpan(ctx, span) +} diff --git a/vendor/github.com/opentracing/opentracing-go/log/field.go b/vendor/github.com/opentracing/opentracing-go/log/field.go new file mode 100644 index 0000000000..50feea341a --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/log/field.go @@ -0,0 +1,269 @@ +package log + +import ( + "fmt" + "math" +) + +type fieldType int + +const ( + stringType fieldType = iota + boolType + intType + int32Type + uint32Type + int64Type + uint64Type + float32Type + float64Type + errorType + objectType + lazyLoggerType + noopType +) + +// Field instances are constructed via LogBool, LogString, and so on. +// Tracing implementations may then handle them via the Field.Marshal +// method. +// +// "heavily influenced by" (i.e., partially stolen from) +// https://github.com/uber-go/zap +type Field struct { + key string + fieldType fieldType + numericVal int64 + stringVal string + interfaceVal interface{} +} + +// String adds a string-valued key:value pair to a Span.LogFields() record +func String(key, val string) Field { + return Field{ + key: key, + fieldType: stringType, + stringVal: val, + } +} + +// Bool adds a bool-valued key:value pair to a Span.LogFields() record +func Bool(key string, val bool) Field { + var numericVal int64 + if val { + numericVal = 1 + } + return Field{ + key: key, + fieldType: boolType, + numericVal: numericVal, + } +} + +// Int adds an int-valued key:value pair to a Span.LogFields() record +func Int(key string, val int) Field { + return Field{ + key: key, + fieldType: intType, + numericVal: int64(val), + } +} + +// Int32 adds an int32-valued key:value pair to a Span.LogFields() record +func Int32(key string, val int32) Field { + return Field{ + key: key, + fieldType: int32Type, + numericVal: int64(val), + } +} + +// Int64 adds an int64-valued key:value pair to a Span.LogFields() record +func Int64(key string, val int64) Field { + return Field{ + key: key, + fieldType: int64Type, + numericVal: val, + } +} + +// Uint32 adds a uint32-valued key:value pair to a Span.LogFields() record +func Uint32(key string, val uint32) Field { + return Field{ + key: key, + fieldType: uint32Type, + numericVal: int64(val), + } +} + +// Uint64 adds a uint64-valued key:value pair to a Span.LogFields() record +func Uint64(key string, val uint64) Field { + return Field{ + key: key, + fieldType: uint64Type, + numericVal: int64(val), + } +} + +// Float32 adds a float32-valued key:value pair to a Span.LogFields() record +func Float32(key string, val float32) Field { + return Field{ + key: key, + fieldType: float32Type, + numericVal: int64(math.Float32bits(val)), + } +} + +// Float64 adds a float64-valued key:value pair to a Span.LogFields() record +func Float64(key string, val float64) Field { + return Field{ + key: key, + fieldType: float64Type, + numericVal: int64(math.Float64bits(val)), + } +} + +// Error adds an error with the key "error" to a Span.LogFields() record +func Error(err error) Field { + return Field{ + key: "error", + fieldType: errorType, + interfaceVal: err, + } +} + +// Object adds an object-valued key:value pair to a Span.LogFields() record +func Object(key string, obj interface{}) Field { + return Field{ + key: key, + fieldType: objectType, + interfaceVal: obj, + } +} + +// LazyLogger allows for user-defined, late-bound logging of arbitrary data +type LazyLogger func(fv Encoder) + +// Lazy adds a LazyLogger to a Span.LogFields() record; the tracing +// implementation will call the LazyLogger function at an indefinite time in +// the future (after Lazy() returns). +func Lazy(ll LazyLogger) Field { + return Field{ + fieldType: lazyLoggerType, + interfaceVal: ll, + } +} + +// Noop creates a no-op log field that should be ignored by the tracer. +// It can be used to capture optional fields, for example those that should +// only be logged in non-production environment: +// +// func customerField(order *Order) log.Field { +// if os.Getenv("ENVIRONMENT") == "dev" { +// return log.String("customer", order.Customer.ID) +// } +// return log.Noop() +// } +// +// span.LogFields(log.String("event", "purchase"), customerField(order)) +// +func Noop() Field { + return Field{ + fieldType: noopType, + } +} + +// Encoder allows access to the contents of a Field (via a call to +// Field.Marshal). +// +// Tracer implementations typically provide an implementation of Encoder; +// OpenTracing callers typically do not need to concern themselves with it. +type Encoder interface { + EmitString(key, value string) + EmitBool(key string, value bool) + EmitInt(key string, value int) + EmitInt32(key string, value int32) + EmitInt64(key string, value int64) + EmitUint32(key string, value uint32) + EmitUint64(key string, value uint64) + EmitFloat32(key string, value float32) + EmitFloat64(key string, value float64) + EmitObject(key string, value interface{}) + EmitLazyLogger(value LazyLogger) +} + +// Marshal passes a Field instance through to the appropriate +// field-type-specific method of an Encoder. +func (lf Field) Marshal(visitor Encoder) { + switch lf.fieldType { + case stringType: + visitor.EmitString(lf.key, lf.stringVal) + case boolType: + visitor.EmitBool(lf.key, lf.numericVal != 0) + case intType: + visitor.EmitInt(lf.key, int(lf.numericVal)) + case int32Type: + visitor.EmitInt32(lf.key, int32(lf.numericVal)) + case int64Type: + visitor.EmitInt64(lf.key, int64(lf.numericVal)) + case uint32Type: + visitor.EmitUint32(lf.key, uint32(lf.numericVal)) + case uint64Type: + visitor.EmitUint64(lf.key, uint64(lf.numericVal)) + case float32Type: + visitor.EmitFloat32(lf.key, math.Float32frombits(uint32(lf.numericVal))) + case float64Type: + visitor.EmitFloat64(lf.key, math.Float64frombits(uint64(lf.numericVal))) + case errorType: + if err, ok := lf.interfaceVal.(error); ok { + visitor.EmitString(lf.key, err.Error()) + } else { + visitor.EmitString(lf.key, "") + } + case objectType: + visitor.EmitObject(lf.key, lf.interfaceVal) + case lazyLoggerType: + visitor.EmitLazyLogger(lf.interfaceVal.(LazyLogger)) + case noopType: + // intentionally left blank + } +} + +// Key returns the field's key. +func (lf Field) Key() string { + return lf.key +} + +// Value returns the field's value as interface{}. +func (lf Field) Value() interface{} { + switch lf.fieldType { + case stringType: + return lf.stringVal + case boolType: + return lf.numericVal != 0 + case intType: + return int(lf.numericVal) + case int32Type: + return int32(lf.numericVal) + case int64Type: + return int64(lf.numericVal) + case uint32Type: + return uint32(lf.numericVal) + case uint64Type: + return uint64(lf.numericVal) + case float32Type: + return math.Float32frombits(uint32(lf.numericVal)) + case float64Type: + return math.Float64frombits(uint64(lf.numericVal)) + case errorType, objectType, lazyLoggerType: + return lf.interfaceVal + case noopType: + return nil + default: + return nil + } +} + +// String returns a string representation of the key and value. +func (lf Field) String() string { + return fmt.Sprint(lf.key, ":", lf.Value()) +} diff --git a/vendor/github.com/opentracing/opentracing-go/log/util.go b/vendor/github.com/opentracing/opentracing-go/log/util.go new file mode 100644 index 0000000000..3832feb5ce --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/log/util.go @@ -0,0 +1,54 @@ +package log + +import "fmt" + +// InterleavedKVToFields converts keyValues a la Span.LogKV() to a Field slice +// a la Span.LogFields(). +func InterleavedKVToFields(keyValues ...interface{}) ([]Field, error) { + if len(keyValues)%2 != 0 { + return nil, fmt.Errorf("non-even keyValues len: %d", len(keyValues)) + } + fields := make([]Field, len(keyValues)/2) + for i := 0; i*2 < len(keyValues); i++ { + key, ok := keyValues[i*2].(string) + if !ok { + return nil, fmt.Errorf( + "non-string key (pair #%d): %T", + i, keyValues[i*2]) + } + switch typedVal := keyValues[i*2+1].(type) { + case bool: + fields[i] = Bool(key, typedVal) + case string: + fields[i] = String(key, typedVal) + case int: + fields[i] = Int(key, typedVal) + case int8: + fields[i] = Int32(key, int32(typedVal)) + case int16: + fields[i] = Int32(key, int32(typedVal)) + case int32: + fields[i] = Int32(key, typedVal) + case int64: + fields[i] = Int64(key, typedVal) + case uint: + fields[i] = Uint64(key, uint64(typedVal)) + case uint64: + fields[i] = Uint64(key, typedVal) + case uint8: + fields[i] = Uint32(key, uint32(typedVal)) + case uint16: + fields[i] = Uint32(key, uint32(typedVal)) + case uint32: + fields[i] = Uint32(key, typedVal) + case float32: + fields[i] = Float32(key, typedVal) + case float64: + fields[i] = Float64(key, typedVal) + default: + // When in doubt, coerce to a string + fields[i] = String(key, fmt.Sprint(typedVal)) + } + } + return fields, nil +} diff --git a/vendor/github.com/opentracing/opentracing-go/noop.go b/vendor/github.com/opentracing/opentracing-go/noop.go new file mode 100644 index 0000000000..0d32f692c4 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/noop.go @@ -0,0 +1,64 @@ +package opentracing + +import "github.com/opentracing/opentracing-go/log" + +// A NoopTracer is a trivial, minimum overhead implementation of Tracer +// for which all operations are no-ops. +// +// The primary use of this implementation is in libraries, such as RPC +// frameworks, that make tracing an optional feature controlled by the +// end user. A no-op implementation allows said libraries to use it +// as the default Tracer and to write instrumentation that does +// not need to keep checking if the tracer instance is nil. +// +// For the same reason, the NoopTracer is the default "global" tracer +// (see GlobalTracer and SetGlobalTracer functions). +// +// WARNING: NoopTracer does not support baggage propagation. +type NoopTracer struct{} + +type noopSpan struct{} +type noopSpanContext struct{} + +var ( + defaultNoopSpanContext = noopSpanContext{} + defaultNoopSpan = noopSpan{} + defaultNoopTracer = NoopTracer{} +) + +const ( + emptyString = "" +) + +// noopSpanContext: +func (n noopSpanContext) ForeachBaggageItem(handler func(k, v string) bool) {} + +// noopSpan: +func (n noopSpan) Context() SpanContext { return defaultNoopSpanContext } +func (n noopSpan) SetBaggageItem(key, val string) Span { return defaultNoopSpan } +func (n noopSpan) BaggageItem(key string) string { return emptyString } +func (n noopSpan) SetTag(key string, value interface{}) Span { return n } +func (n noopSpan) LogFields(fields ...log.Field) {} +func (n noopSpan) LogKV(keyVals ...interface{}) {} +func (n noopSpan) Finish() {} +func (n noopSpan) FinishWithOptions(opts FinishOptions) {} +func (n noopSpan) SetOperationName(operationName string) Span { return n } +func (n noopSpan) Tracer() Tracer { return defaultNoopTracer } +func (n noopSpan) LogEvent(event string) {} +func (n noopSpan) LogEventWithPayload(event string, payload interface{}) {} +func (n noopSpan) Log(data LogData) {} + +// StartSpan belongs to the Tracer interface. +func (n NoopTracer) StartSpan(operationName string, opts ...StartSpanOption) Span { + return defaultNoopSpan +} + +// Inject belongs to the Tracer interface. +func (n NoopTracer) Inject(sp SpanContext, format interface{}, carrier interface{}) error { + return nil +} + +// Extract belongs to the Tracer interface. +func (n NoopTracer) Extract(format interface{}, carrier interface{}) (SpanContext, error) { + return nil, ErrSpanContextNotFound +} diff --git a/vendor/github.com/opentracing/opentracing-go/propagation.go b/vendor/github.com/opentracing/opentracing-go/propagation.go new file mode 100644 index 0000000000..0dd466a373 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/propagation.go @@ -0,0 +1,176 @@ +package opentracing + +import ( + "errors" + "net/http" +) + +/////////////////////////////////////////////////////////////////////////////// +// CORE PROPAGATION INTERFACES: +/////////////////////////////////////////////////////////////////////////////// + +var ( + // ErrUnsupportedFormat occurs when the `format` passed to Tracer.Inject() or + // Tracer.Extract() is not recognized by the Tracer implementation. + ErrUnsupportedFormat = errors.New("opentracing: Unknown or unsupported Inject/Extract format") + + // ErrSpanContextNotFound occurs when the `carrier` passed to + // Tracer.Extract() is valid and uncorrupted but has insufficient + // information to extract a SpanContext. + ErrSpanContextNotFound = errors.New("opentracing: SpanContext not found in Extract carrier") + + // ErrInvalidSpanContext errors occur when Tracer.Inject() is asked to + // operate on a SpanContext which it is not prepared to handle (for + // example, since it was created by a different tracer implementation). + ErrInvalidSpanContext = errors.New("opentracing: SpanContext type incompatible with tracer") + + // ErrInvalidCarrier errors occur when Tracer.Inject() or Tracer.Extract() + // implementations expect a different type of `carrier` than they are + // given. + ErrInvalidCarrier = errors.New("opentracing: Invalid Inject/Extract carrier") + + // ErrSpanContextCorrupted occurs when the `carrier` passed to + // Tracer.Extract() is of the expected type but is corrupted. + ErrSpanContextCorrupted = errors.New("opentracing: SpanContext data corrupted in Extract carrier") +) + +/////////////////////////////////////////////////////////////////////////////// +// BUILTIN PROPAGATION FORMATS: +/////////////////////////////////////////////////////////////////////////////// + +// BuiltinFormat is used to demarcate the values within package `opentracing` +// that are intended for use with the Tracer.Inject() and Tracer.Extract() +// methods. +type BuiltinFormat byte + +const ( + // Binary represents SpanContexts as opaque binary data. + // + // For Tracer.Inject(): the carrier must be an `io.Writer`. + // + // For Tracer.Extract(): the carrier must be an `io.Reader`. + Binary BuiltinFormat = iota + + // TextMap represents SpanContexts as key:value string pairs. + // + // Unlike HTTPHeaders, the TextMap format does not restrict the key or + // value character sets in any way. + // + // For Tracer.Inject(): the carrier must be a `TextMapWriter`. + // + // For Tracer.Extract(): the carrier must be a `TextMapReader`. + TextMap + + // HTTPHeaders represents SpanContexts as HTTP header string pairs. + // + // Unlike TextMap, the HTTPHeaders format requires that the keys and values + // be valid as HTTP headers as-is (i.e., character casing may be unstable + // and special characters are disallowed in keys, values should be + // URL-escaped, etc). + // + // For Tracer.Inject(): the carrier must be a `TextMapWriter`. + // + // For Tracer.Extract(): the carrier must be a `TextMapReader`. + // + // See HTTPHeadersCarrier for an implementation of both TextMapWriter + // and TextMapReader that defers to an http.Header instance for storage. + // For example, Inject(): + // + // carrier := opentracing.HTTPHeadersCarrier(httpReq.Header) + // err := span.Tracer().Inject( + // span.Context(), opentracing.HTTPHeaders, carrier) + // + // Or Extract(): + // + // carrier := opentracing.HTTPHeadersCarrier(httpReq.Header) + // clientContext, err := tracer.Extract( + // opentracing.HTTPHeaders, carrier) + // + HTTPHeaders +) + +// TextMapWriter is the Inject() carrier for the TextMap builtin format. With +// it, the caller can encode a SpanContext for propagation as entries in a map +// of unicode strings. +type TextMapWriter interface { + // Set a key:value pair to the carrier. Multiple calls to Set() for the + // same key leads to undefined behavior. + // + // NOTE: The backing store for the TextMapWriter may contain data unrelated + // to SpanContext. As such, Inject() and Extract() implementations that + // call the TextMapWriter and TextMapReader interfaces must agree on a + // prefix or other convention to distinguish their own key:value pairs. + Set(key, val string) +} + +// TextMapReader is the Extract() carrier for the TextMap builtin format. With it, +// the caller can decode a propagated SpanContext as entries in a map of +// unicode strings. +type TextMapReader interface { + // ForeachKey returns TextMap contents via repeated calls to the `handler` + // function. If any call to `handler` returns a non-nil error, ForeachKey + // terminates and returns that error. + // + // NOTE: The backing store for the TextMapReader may contain data unrelated + // to SpanContext. As such, Inject() and Extract() implementations that + // call the TextMapWriter and TextMapReader interfaces must agree on a + // prefix or other convention to distinguish their own key:value pairs. + // + // The "foreach" callback pattern reduces unnecessary copying in some cases + // and also allows implementations to hold locks while the map is read. + ForeachKey(handler func(key, val string) error) error +} + +// TextMapCarrier allows the use of regular map[string]string +// as both TextMapWriter and TextMapReader. +type TextMapCarrier map[string]string + +// ForeachKey conforms to the TextMapReader interface. +func (c TextMapCarrier) ForeachKey(handler func(key, val string) error) error { + for k, v := range c { + if err := handler(k, v); err != nil { + return err + } + } + return nil +} + +// Set implements Set() of opentracing.TextMapWriter +func (c TextMapCarrier) Set(key, val string) { + c[key] = val +} + +// HTTPHeadersCarrier satisfies both TextMapWriter and TextMapReader. +// +// Example usage for server side: +// +// carrier := opentracing.HTTPHeadersCarrier(httpReq.Header) +// clientContext, err := tracer.Extract(opentracing.HTTPHeaders, carrier) +// +// Example usage for client side: +// +// carrier := opentracing.HTTPHeadersCarrier(httpReq.Header) +// err := tracer.Inject( +// span.Context(), +// opentracing.HTTPHeaders, +// carrier) +// +type HTTPHeadersCarrier http.Header + +// Set conforms to the TextMapWriter interface. +func (c HTTPHeadersCarrier) Set(key, val string) { + h := http.Header(c) + h.Add(key, val) +} + +// ForeachKey conforms to the TextMapReader interface. +func (c HTTPHeadersCarrier) ForeachKey(handler func(key, val string) error) error { + for k, vals := range c { + for _, v := range vals { + if err := handler(k, v); err != nil { + return err + } + } + } + return nil +} diff --git a/vendor/github.com/opentracing/opentracing-go/span.go b/vendor/github.com/opentracing/opentracing-go/span.go new file mode 100644 index 0000000000..0d3fb53418 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/span.go @@ -0,0 +1,189 @@ +package opentracing + +import ( + "time" + + "github.com/opentracing/opentracing-go/log" +) + +// SpanContext represents Span state that must propagate to descendant Spans and across process +// boundaries (e.g., a tuple). +type SpanContext interface { + // ForeachBaggageItem grants access to all baggage items stored in the + // SpanContext. + // The handler function will be called for each baggage key/value pair. + // The ordering of items is not guaranteed. + // + // The bool return value indicates if the handler wants to continue iterating + // through the rest of the baggage items; for example if the handler is trying to + // find some baggage item by pattern matching the name, it can return false + // as soon as the item is found to stop further iterations. + ForeachBaggageItem(handler func(k, v string) bool) +} + +// Span represents an active, un-finished span in the OpenTracing system. +// +// Spans are created by the Tracer interface. +type Span interface { + // Sets the end timestamp and finalizes Span state. + // + // With the exception of calls to Context() (which are always allowed), + // Finish() must be the last call made to any span instance, and to do + // otherwise leads to undefined behavior. + Finish() + // FinishWithOptions is like Finish() but with explicit control over + // timestamps and log data. + FinishWithOptions(opts FinishOptions) + + // Context() yields the SpanContext for this Span. Note that the return + // value of Context() is still valid after a call to Span.Finish(), as is + // a call to Span.Context() after a call to Span.Finish(). + Context() SpanContext + + // Sets or changes the operation name. + // + // Returns a reference to this Span for chaining. + SetOperationName(operationName string) Span + + // Adds a tag to the span. + // + // If there is a pre-existing tag set for `key`, it is overwritten. + // + // Tag values can be numeric types, strings, or bools. The behavior of + // other tag value types is undefined at the OpenTracing level. If a + // tracing system does not know how to handle a particular value type, it + // may ignore the tag, but shall not panic. + // + // Returns a reference to this Span for chaining. + SetTag(key string, value interface{}) Span + + // LogFields is an efficient and type-checked way to record key:value + // logging data about a Span, though the programming interface is a little + // more verbose than LogKV(). Here's an example: + // + // span.LogFields( + // log.String("event", "soft error"), + // log.String("type", "cache timeout"), + // log.Int("waited.millis", 1500)) + // + // Also see Span.FinishWithOptions() and FinishOptions.BulkLogData. + LogFields(fields ...log.Field) + + // LogKV is a concise, readable way to record key:value logging data about + // a Span, though unfortunately this also makes it less efficient and less + // type-safe than LogFields(). Here's an example: + // + // span.LogKV( + // "event", "soft error", + // "type", "cache timeout", + // "waited.millis", 1500) + // + // For LogKV (as opposed to LogFields()), the parameters must appear as + // key-value pairs, like + // + // span.LogKV(key1, val1, key2, val2, key3, val3, ...) + // + // The keys must all be strings. The values may be strings, numeric types, + // bools, Go error instances, or arbitrary structs. + // + // (Note to implementors: consider the log.InterleavedKVToFields() helper) + LogKV(alternatingKeyValues ...interface{}) + + // SetBaggageItem sets a key:value pair on this Span and its SpanContext + // that also propagates to descendants of this Span. + // + // SetBaggageItem() enables powerful functionality given a full-stack + // opentracing integration (e.g., arbitrary application data from a mobile + // app can make it, transparently, all the way into the depths of a storage + // system), and with it some powerful costs: use this feature with care. + // + // IMPORTANT NOTE #1: SetBaggageItem() will only propagate baggage items to + // *future* causal descendants of the associated Span. + // + // IMPORTANT NOTE #2: Use this thoughtfully and with care. Every key and + // value is copied into every local *and remote* child of the associated + // Span, and that can add up to a lot of network and cpu overhead. + // + // Returns a reference to this Span for chaining. + SetBaggageItem(restrictedKey, value string) Span + + // Gets the value for a baggage item given its key. Returns the empty string + // if the value isn't found in this Span. + BaggageItem(restrictedKey string) string + + // Provides access to the Tracer that created this Span. + Tracer() Tracer + + // Deprecated: use LogFields or LogKV + LogEvent(event string) + // Deprecated: use LogFields or LogKV + LogEventWithPayload(event string, payload interface{}) + // Deprecated: use LogFields or LogKV + Log(data LogData) +} + +// LogRecord is data associated with a single Span log. Every LogRecord +// instance must specify at least one Field. +type LogRecord struct { + Timestamp time.Time + Fields []log.Field +} + +// FinishOptions allows Span.FinishWithOptions callers to override the finish +// timestamp and provide log data via a bulk interface. +type FinishOptions struct { + // FinishTime overrides the Span's finish time, or implicitly becomes + // time.Now() if FinishTime.IsZero(). + // + // FinishTime must resolve to a timestamp that's >= the Span's StartTime + // (per StartSpanOptions). + FinishTime time.Time + + // LogRecords allows the caller to specify the contents of many LogFields() + // calls with a single slice. May be nil. + // + // None of the LogRecord.Timestamp values may be .IsZero() (i.e., they must + // be set explicitly). Also, they must be >= the Span's start timestamp and + // <= the FinishTime (or time.Now() if FinishTime.IsZero()). Otherwise the + // behavior of FinishWithOptions() is undefined. + // + // If specified, the caller hands off ownership of LogRecords at + // FinishWithOptions() invocation time. + // + // If specified, the (deprecated) BulkLogData must be nil or empty. + LogRecords []LogRecord + + // BulkLogData is DEPRECATED. + BulkLogData []LogData +} + +// LogData is DEPRECATED +type LogData struct { + Timestamp time.Time + Event string + Payload interface{} +} + +// ToLogRecord converts a deprecated LogData to a non-deprecated LogRecord +func (ld *LogData) ToLogRecord() LogRecord { + var literalTimestamp time.Time + if ld.Timestamp.IsZero() { + literalTimestamp = time.Now() + } else { + literalTimestamp = ld.Timestamp + } + rval := LogRecord{ + Timestamp: literalTimestamp, + } + if ld.Payload == nil { + rval.Fields = []log.Field{ + log.String("event", ld.Event), + } + } else { + rval.Fields = []log.Field{ + log.String("event", ld.Event), + log.Object("payload", ld.Payload), + } + } + return rval +} diff --git a/vendor/github.com/opentracing/opentracing-go/tracer.go b/vendor/github.com/opentracing/opentracing-go/tracer.go new file mode 100644 index 0000000000..7bca1f7367 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/tracer.go @@ -0,0 +1,305 @@ +package opentracing + +import "time" + +// Tracer is a simple, thin interface for Span creation and SpanContext +// propagation. +type Tracer interface { + + // Create, start, and return a new Span with the given `operationName` and + // incorporate the given StartSpanOption `opts`. (Note that `opts` borrows + // from the "functional options" pattern, per + // http://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis) + // + // A Span with no SpanReference options (e.g., opentracing.ChildOf() or + // opentracing.FollowsFrom()) becomes the root of its own trace. + // + // Examples: + // + // var tracer opentracing.Tracer = ... + // + // // The root-span case: + // sp := tracer.StartSpan("GetFeed") + // + // // The vanilla child span case: + // sp := tracer.StartSpan( + // "GetFeed", + // opentracing.ChildOf(parentSpan.Context())) + // + // // All the bells and whistles: + // sp := tracer.StartSpan( + // "GetFeed", + // opentracing.ChildOf(parentSpan.Context()), + // opentracing.Tag{"user_agent", loggedReq.UserAgent}, + // opentracing.StartTime(loggedReq.Timestamp), + // ) + // + StartSpan(operationName string, opts ...StartSpanOption) Span + + // Inject() takes the `sm` SpanContext instance and injects it for + // propagation within `carrier`. The actual type of `carrier` depends on + // the value of `format`. + // + // OpenTracing defines a common set of `format` values (see BuiltinFormat), + // and each has an expected carrier type. + // + // Other packages may declare their own `format` values, much like the keys + // used by `context.Context` (see + // https://godoc.org/golang.org/x/net/context#WithValue). + // + // Example usage (sans error handling): + // + // carrier := opentracing.HTTPHeadersCarrier(httpReq.Header) + // err := tracer.Inject( + // span.Context(), + // opentracing.HTTPHeaders, + // carrier) + // + // NOTE: All opentracing.Tracer implementations MUST support all + // BuiltinFormats. + // + // Implementations may return opentracing.ErrUnsupportedFormat if `format` + // is not supported by (or not known by) the implementation. + // + // Implementations may return opentracing.ErrInvalidCarrier or any other + // implementation-specific error if the format is supported but injection + // fails anyway. + // + // See Tracer.Extract(). + Inject(sm SpanContext, format interface{}, carrier interface{}) error + + // Extract() returns a SpanContext instance given `format` and `carrier`. + // + // OpenTracing defines a common set of `format` values (see BuiltinFormat), + // and each has an expected carrier type. + // + // Other packages may declare their own `format` values, much like the keys + // used by `context.Context` (see + // https://godoc.org/golang.org/x/net/context#WithValue). + // + // Example usage (with StartSpan): + // + // + // carrier := opentracing.HTTPHeadersCarrier(httpReq.Header) + // clientContext, err := tracer.Extract(opentracing.HTTPHeaders, carrier) + // + // // ... assuming the ultimate goal here is to resume the trace with a + // // server-side Span: + // var serverSpan opentracing.Span + // if err == nil { + // span = tracer.StartSpan( + // rpcMethodName, ext.RPCServerOption(clientContext)) + // } else { + // span = tracer.StartSpan(rpcMethodName) + // } + // + // + // NOTE: All opentracing.Tracer implementations MUST support all + // BuiltinFormats. + // + // Return values: + // - A successful Extract returns a SpanContext instance and a nil error + // - If there was simply no SpanContext to extract in `carrier`, Extract() + // returns (nil, opentracing.ErrSpanContextNotFound) + // - If `format` is unsupported or unrecognized, Extract() returns (nil, + // opentracing.ErrUnsupportedFormat) + // - If there are more fundamental problems with the `carrier` object, + // Extract() may return opentracing.ErrInvalidCarrier, + // opentracing.ErrSpanContextCorrupted, or implementation-specific + // errors. + // + // See Tracer.Inject(). + Extract(format interface{}, carrier interface{}) (SpanContext, error) +} + +// StartSpanOptions allows Tracer.StartSpan() callers and implementors a +// mechanism to override the start timestamp, specify Span References, and make +// a single Tag or multiple Tags available at Span start time. +// +// StartSpan() callers should look at the StartSpanOption interface and +// implementations available in this package. +// +// Tracer implementations can convert a slice of `StartSpanOption` instances +// into a `StartSpanOptions` struct like so: +// +// func StartSpan(opName string, opts ...opentracing.StartSpanOption) { +// sso := opentracing.StartSpanOptions{} +// for _, o := range opts { +// o.Apply(&sso) +// } +// ... +// } +// +type StartSpanOptions struct { + // Zero or more causal references to other Spans (via their SpanContext). + // If empty, start a "root" Span (i.e., start a new trace). + References []SpanReference + + // StartTime overrides the Span's start time, or implicitly becomes + // time.Now() if StartTime.IsZero(). + StartTime time.Time + + // Tags may have zero or more entries; the restrictions on map values are + // identical to those for Span.SetTag(). May be nil. + // + // If specified, the caller hands off ownership of Tags at + // StartSpan() invocation time. + Tags map[string]interface{} +} + +// StartSpanOption instances (zero or more) may be passed to Tracer.StartSpan. +// +// StartSpanOption borrows from the "functional options" pattern, per +// http://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis +type StartSpanOption interface { + Apply(*StartSpanOptions) +} + +// SpanReferenceType is an enum type describing different categories of +// relationships between two Spans. If Span-2 refers to Span-1, the +// SpanReferenceType describes Span-1 from Span-2's perspective. For example, +// ChildOfRef means that Span-1 created Span-2. +// +// NOTE: Span-1 and Span-2 do *not* necessarily depend on each other for +// completion; e.g., Span-2 may be part of a background job enqueued by Span-1, +// or Span-2 may be sitting in a distributed queue behind Span-1. +type SpanReferenceType int + +const ( + // ChildOfRef refers to a parent Span that caused *and* somehow depends + // upon the new child Span. Often (but not always), the parent Span cannot + // finish until the child Span does. + // + // An timing diagram for a ChildOfRef that's blocked on the new Span: + // + // [-Parent Span---------] + // [-Child Span----] + // + // See http://opentracing.io/spec/ + // + // See opentracing.ChildOf() + ChildOfRef SpanReferenceType = iota + + // FollowsFromRef refers to a parent Span that does not depend in any way + // on the result of the new child Span. For instance, one might use + // FollowsFromRefs to describe pipeline stages separated by queues, + // or a fire-and-forget cache insert at the tail end of a web request. + // + // A FollowsFromRef Span is part of the same logical trace as the new Span: + // i.e., the new Span is somehow caused by the work of its FollowsFromRef. + // + // All of the following could be valid timing diagrams for children that + // "FollowFrom" a parent. + // + // [-Parent Span-] [-Child Span-] + // + // + // [-Parent Span--] + // [-Child Span-] + // + // + // [-Parent Span-] + // [-Child Span-] + // + // See http://opentracing.io/spec/ + // + // See opentracing.FollowsFrom() + FollowsFromRef +) + +// SpanReference is a StartSpanOption that pairs a SpanReferenceType and a +// referenced SpanContext. See the SpanReferenceType documentation for +// supported relationships. If SpanReference is created with +// ReferencedContext==nil, it has no effect. Thus it allows for a more concise +// syntax for starting spans: +// +// sc, _ := tracer.Extract(someFormat, someCarrier) +// span := tracer.StartSpan("operation", opentracing.ChildOf(sc)) +// +// The `ChildOf(sc)` option above will not panic if sc == nil, it will just +// not add the parent span reference to the options. +type SpanReference struct { + Type SpanReferenceType + ReferencedContext SpanContext +} + +// Apply satisfies the StartSpanOption interface. +func (r SpanReference) Apply(o *StartSpanOptions) { + if r.ReferencedContext != nil { + o.References = append(o.References, r) + } +} + +// ChildOf returns a StartSpanOption pointing to a dependent parent span. +// If sc == nil, the option has no effect. +// +// See ChildOfRef, SpanReference +func ChildOf(sc SpanContext) SpanReference { + return SpanReference{ + Type: ChildOfRef, + ReferencedContext: sc, + } +} + +// FollowsFrom returns a StartSpanOption pointing to a parent Span that caused +// the child Span but does not directly depend on its result in any way. +// If sc == nil, the option has no effect. +// +// See FollowsFromRef, SpanReference +func FollowsFrom(sc SpanContext) SpanReference { + return SpanReference{ + Type: FollowsFromRef, + ReferencedContext: sc, + } +} + +// StartTime is a StartSpanOption that sets an explicit start timestamp for the +// new Span. +type StartTime time.Time + +// Apply satisfies the StartSpanOption interface. +func (t StartTime) Apply(o *StartSpanOptions) { + o.StartTime = time.Time(t) +} + +// Tags are a generic map from an arbitrary string key to an opaque value type. +// The underlying tracing system is responsible for interpreting and +// serializing the values. +type Tags map[string]interface{} + +// Apply satisfies the StartSpanOption interface. +func (t Tags) Apply(o *StartSpanOptions) { + if o.Tags == nil { + o.Tags = make(map[string]interface{}) + } + for k, v := range t { + o.Tags[k] = v + } +} + +// Tag may be passed as a StartSpanOption to add a tag to new spans, +// or its Set method may be used to apply the tag to an existing Span, +// for example: +// +// tracer.StartSpan("opName", Tag{"Key", value}) +// +// or +// +// Tag{"key", value}.Set(span) +type Tag struct { + Key string + Value interface{} +} + +// Apply satisfies the StartSpanOption interface. +func (t Tag) Apply(o *StartSpanOptions) { + if o.Tags == nil { + o.Tags = make(map[string]interface{}) + } + o.Tags[t.Key] = t.Value +} + +// Set applies the tag to an existing Span. +func (t Tag) Set(s Span) { + s.SetTag(t.Key, t.Value) +} diff --git a/vendor/github.com/peterh/liner/fallbackinput.go b/vendor/github.com/peterh/liner/fallbackinput.go index d9eb79d9e0..043fb33218 100644 --- a/vendor/github.com/peterh/liner/fallbackinput.go +++ b/vendor/github.com/peterh/liner/fallbackinput.go @@ -55,3 +55,5 @@ func (n noopMode) ApplyMode() error { func TerminalMode() (ModeApplier, error) { return noopMode{}, nil } + +const cursorColumn = true diff --git a/vendor/github.com/peterh/liner/go.mod b/vendor/github.com/peterh/liner/go.mod new file mode 100644 index 0000000000..6804de36f5 --- /dev/null +++ b/vendor/github.com/peterh/liner/go.mod @@ -0,0 +1,3 @@ +module github.com/peterh/liner + +require github.com/mattn/go-runewidth v0.0.3 diff --git a/vendor/github.com/peterh/liner/go.sum b/vendor/github.com/peterh/liner/go.sum new file mode 100644 index 0000000000..1c1891604c --- /dev/null +++ b/vendor/github.com/peterh/liner/go.sum @@ -0,0 +1,2 @@ +github.com/mattn/go-runewidth v0.0.3 h1:a+kO+98RDGEfo6asOGMmpodZq4FNtnGP54yps8BzLR4= +github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= diff --git a/vendor/github.com/peterh/liner/input.go b/vendor/github.com/peterh/liner/input.go index 95dd5d1435..e04e772253 100644 --- a/vendor/github.com/peterh/liner/input.go +++ b/vendor/github.com/peterh/liner/input.go @@ -264,9 +264,9 @@ func (s *State) readNext() (interface{}, error) { return pageUp, nil case 6: return pageDown, nil - case 7: + case 1, 7: return home, nil - case 8: + case 4, 8: return end, nil case 15: return f5, nil @@ -328,6 +328,9 @@ func (s *State) readNext() (interface{}, error) { case 'b': s.pending = s.pending[:0] // escape code complete return altB, nil + case 'd': + s.pending = s.pending[:0] // escape code complete + return altD, nil case 'f': s.pending = s.pending[:0] // escape code complete return altF, nil diff --git a/vendor/github.com/peterh/liner/input_windows.go b/vendor/github.com/peterh/liner/input_windows.go index a48eb0f1d2..36e95161ad 100644 --- a/vendor/github.com/peterh/liner/input_windows.go +++ b/vendor/github.com/peterh/liner/input_windows.go @@ -4,6 +4,7 @@ import ( "bufio" "os" "syscall" + "unicode/utf16" "unsafe" ) @@ -103,7 +104,7 @@ type key_event_record struct { RepeatCount uint16 VirtualKeyCode uint16 VirtualScanCode uint16 - Char int16 + Char uint16 ControlKeyState uint32 } @@ -111,6 +112,7 @@ type key_event_record struct { // what golint suggests) const ( vk_tab = 0x09 + vk_menu = 0x12 // ALT key vk_prior = 0x21 vk_next = 0x22 vk_end = 0x23 @@ -134,6 +136,7 @@ const ( vk_f11 = 0x7a vk_f12 = 0x7b bKey = 0x42 + dKey = 0x44 fKey = 0x46 yKey = 0x59 ) @@ -174,6 +177,8 @@ func (s *State) readNext() (interface{}, error) { var rv uint32 prv := uintptr(unsafe.Pointer(&rv)) + var surrogate uint16 + for { ok, _, err := procReadConsoleInput.Call(uintptr(s.handle), pbuf, 1, prv) @@ -184,9 +189,6 @@ func (s *State) readNext() (interface{}, error) { if input.eventType == window_buffer_size_event { xy := (*coord)(unsafe.Pointer(&input.blob[0])) s.columns = int(xy.x) - if s.columns > 1 { - s.columns-- - } return winch, nil } if input.eventType != key_event { @@ -194,6 +196,17 @@ func (s *State) readNext() (interface{}, error) { } ke := (*key_event_record)(unsafe.Pointer(&input.blob[0])) if ke.KeyDown == 0 { + if ke.VirtualKeyCode == vk_menu && ke.Char > 0 { + // paste of unicode (eg. via ALT-numpad) + if surrogate > 0 { + return utf16.DecodeRune(rune(surrogate), rune(ke.Char)), nil + } else if utf16.IsSurrogate(rune(ke.Char)) { + surrogate = ke.Char + continue + } else { + return rune(ke.Char), nil + } + } continue } @@ -202,6 +215,9 @@ func (s *State) readNext() (interface{}, error) { } else if ke.VirtualKeyCode == bKey && (ke.ControlKeyState&modKeys == leftAltPressed || ke.ControlKeyState&modKeys == rightAltPressed) { s.key = altB + } else if ke.VirtualKeyCode == dKey && (ke.ControlKeyState&modKeys == leftAltPressed || + ke.ControlKeyState&modKeys == rightAltPressed) { + s.key = altD } else if ke.VirtualKeyCode == fKey && (ke.ControlKeyState&modKeys == leftAltPressed || ke.ControlKeyState&modKeys == rightAltPressed) { s.key = altF @@ -209,7 +225,14 @@ func (s *State) readNext() (interface{}, error) { ke.ControlKeyState&modKeys == rightAltPressed) { s.key = altY } else if ke.Char > 0 { - s.key = rune(ke.Char) + if surrogate > 0 { + s.key = utf16.DecodeRune(rune(surrogate), rune(ke.Char)) + } else if utf16.IsSurrogate(rune(ke.Char)) { + surrogate = ke.Char + continue + } else { + s.key = rune(ke.Char) + } } else { switch ke.VirtualKeyCode { case vk_prior: @@ -337,3 +360,5 @@ func TerminalMode() (ModeApplier, error) { } return mode, err } + +const cursorColumn = true diff --git a/vendor/github.com/peterh/liner/line.go b/vendor/github.com/peterh/liner/line.go index d61f0696b0..076a195c43 100644 --- a/vendor/github.com/peterh/liner/line.go +++ b/vendor/github.com/peterh/liner/line.go @@ -40,6 +40,7 @@ const ( f11 f12 altB + altD altF altY shiftTab @@ -112,6 +113,10 @@ func (s *State) refreshSingleLine(prompt []rune, buf []rune, pos int) error { pLen := countGlyphs(prompt) bLen := countGlyphs(buf) + // on some OS / terminals extra column is needed to place the cursor char + if cursorColumn { + bLen++ + } pos = countGlyphs(buf[:pos]) if pLen+bLen < s.columns { _, err = fmt.Print(string(buf)) @@ -162,6 +167,14 @@ func (s *State) refreshSingleLine(prompt []rune, buf []rune, pos int) error { func (s *State) refreshMultiLine(prompt []rune, buf []rune, pos int) error { promptColumns := countMultiLineGlyphs(prompt, s.columns, 0) totalColumns := countMultiLineGlyphs(buf, s.columns, promptColumns) + // on some OS / terminals extra column is needed to place the cursor char + // if cursorColumn { + // totalColumns++ + // } + + // it looks like Multiline mode always assume that a cursor need an extra column, + // and always emit a newline if we are at the screen end, so no worarounds needed there + totalRows := (totalColumns + s.columns - 1) / s.columns maxRows := s.maxRows if totalRows > s.maxRows { @@ -583,7 +596,7 @@ func (s *State) Prompt(prompt string) (string, error) { // PromptWithSuggestion displays prompt and an editable text with cursor at // given position. The cursor will be set to the end of the line if given position -// is negative or greater than length of text. Returns a line of user input, not +// is negative or greater than length of text (in runes). Returns a line of user input, not // including a trailing newline character. An io.EOF error is returned if the user // signals end-of-file by pressing Ctrl-D. func (s *State) PromptWithSuggestion(prompt string, text string, pos int) (string, error) { @@ -618,8 +631,8 @@ func (s *State) PromptWithSuggestion(prompt string, text string, pos int) (strin defer s.stopPrompt() - if pos < 0 || len(text) < pos { - pos = len(text) + if pos < 0 || len(line) < pos { + pos = len(line) } if len(line) > 0 { err := s.refresh(p, line, pos) @@ -969,6 +982,35 @@ mainLoop: pos = 0 case end: // End of line pos = len(line) + case altD: // Delete next word + if pos == len(line) { + fmt.Print(beep) + break + } + // Remove whitespace to the right + var buf []rune // Store the deleted chars in a buffer + for { + if pos == len(line) || !unicode.IsSpace(line[pos]) { + break + } + buf = append(buf, line[pos]) + line = append(line[:pos], line[pos+1:]...) + } + // Remove non-whitespace to the right + for { + if pos == len(line) || unicode.IsSpace(line[pos]) { + break + } + buf = append(buf, line[pos]) + line = append(line[:pos], line[pos+1:]...) + } + // Save the result on the killRing + if killAction > 0 { + s.addToKillRing(buf, 2) // Add in prepend mode + } else { + s.addToKillRing(buf, 0) // Add in normal mode + } + killAction = 2 // Mark that there was some killing case winch: // Window change if s.multiLineMode { if s.maxRows-s.cursorRows > 0 { diff --git a/vendor/github.com/peterh/liner/output.go b/vendor/github.com/peterh/liner/output.go index 6d83d4ebfd..db0641cfe0 100644 --- a/vendor/github.com/peterh/liner/output.go +++ b/vendor/github.com/peterh/liner/output.go @@ -56,9 +56,6 @@ func (s *State) getColumns() bool { return false } s.columns = int(ws.col) - if cursorColumn && s.columns > 1 { - s.columns-- - } return true } diff --git a/vendor/github.com/peterh/liner/output_windows.go b/vendor/github.com/peterh/liner/output_windows.go index 63c9c5d757..45cd978c96 100644 --- a/vendor/github.com/peterh/liner/output_windows.go +++ b/vendor/github.com/peterh/liner/output_windows.go @@ -69,8 +69,4 @@ func (s *State) getColumns() { var sbi consoleScreenBufferInfo procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi))) s.columns = int(sbi.dwSize.x) - if s.columns > 1 { - // Windows 10 needs a spare column for the cursor - s.columns-- - } } diff --git a/vendor/github.com/peterh/liner/width.go b/vendor/github.com/peterh/liner/width.go index 42e8999834..0395f3a8be 100644 --- a/vendor/github.com/peterh/liner/width.go +++ b/vendor/github.com/peterh/liner/width.go @@ -1,6 +1,10 @@ package liner -import "unicode" +import ( + "unicode" + + "github.com/mattn/go-runewidth" +) // These character classes are mostly zero width (when combined). // A few might not be, depending on the user's font. Fixing this @@ -13,13 +17,6 @@ var zeroWidth = []*unicode.RangeTable{ unicode.Cf, } -var doubleWidth = []*unicode.RangeTable{ - unicode.Han, - unicode.Hangul, - unicode.Hiragana, - unicode.Katakana, -} - // countGlyphs considers zero-width characters to be zero glyphs wide, // and members of Chinese, Japanese, and Korean scripts to be 2 glyphs wide. func countGlyphs(s []rune) int { @@ -31,13 +28,7 @@ func countGlyphs(s []rune) int { continue } - switch { - case unicode.IsOneOf(zeroWidth, r): - case unicode.IsOneOf(doubleWidth, r): - n += 2 - default: - n++ - } + n += runewidth.RuneWidth(r) } return n } @@ -49,17 +40,17 @@ func countMultiLineGlyphs(s []rune, columns int, start int) int { n++ continue } - switch { - case unicode.IsOneOf(zeroWidth, r): - case unicode.IsOneOf(doubleWidth, r): + switch runewidth.RuneWidth(r) { + case 0: + case 1: + n++ + case 2: n += 2 // no room for a 2-glyphs-wide char in the ending // so skip a column and display it at the beginning if n%columns == 1 { n++ } - default: - n++ } } return n diff --git a/vendor/github.com/rcrowley/go-metrics/json.go b/vendor/github.com/rcrowley/go-metrics/json.go deleted file mode 100644 index 2fdcbcfbf1..0000000000 --- a/vendor/github.com/rcrowley/go-metrics/json.go +++ /dev/null @@ -1,87 +0,0 @@ -package metrics - -import ( - "encoding/json" - "io" - "time" -) - -// MarshalJSON returns a byte slice containing a JSON representation of all -// the metrics in the Registry. -func (r *StandardRegistry) MarshalJSON() ([]byte, error) { - data := make(map[string]map[string]interface{}) - r.Each(func(name string, i interface{}) { - values := make(map[string]interface{}) - switch metric := i.(type) { - case Counter: - values["count"] = metric.Count() - case Gauge: - values["value"] = metric.Value() - case GaugeFloat64: - values["value"] = metric.Value() - case Healthcheck: - values["error"] = nil - metric.Check() - if err := metric.Error(); nil != err { - values["error"] = metric.Error().Error() - } - case Histogram: - h := metric.Snapshot() - ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) - values["count"] = h.Count() - values["min"] = h.Min() - values["max"] = h.Max() - values["mean"] = h.Mean() - values["stddev"] = h.StdDev() - values["median"] = ps[0] - values["75%"] = ps[1] - values["95%"] = ps[2] - values["99%"] = ps[3] - values["99.9%"] = ps[4] - case Meter: - m := metric.Snapshot() - values["count"] = m.Count() - values["1m.rate"] = m.Rate1() - values["5m.rate"] = m.Rate5() - values["15m.rate"] = m.Rate15() - values["mean.rate"] = m.RateMean() - case Timer: - t := metric.Snapshot() - ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) - values["count"] = t.Count() - values["min"] = t.Min() - values["max"] = t.Max() - values["mean"] = t.Mean() - values["stddev"] = t.StdDev() - values["median"] = ps[0] - values["75%"] = ps[1] - values["95%"] = ps[2] - values["99%"] = ps[3] - values["99.9%"] = ps[4] - values["1m.rate"] = t.Rate1() - values["5m.rate"] = t.Rate5() - values["15m.rate"] = t.Rate15() - values["mean.rate"] = t.RateMean() - } - data[name] = values - }) - return json.Marshal(data) -} - -// WriteJSON writes metrics from the given registry periodically to the -// specified io.Writer as JSON. -func WriteJSON(r Registry, d time.Duration, w io.Writer) { - for _ = range time.Tick(d) { - WriteJSONOnce(r, w) - } -} - -// WriteJSONOnce writes metrics from the given registry to the specified -// io.Writer as JSON. -func WriteJSONOnce(r Registry, w io.Writer) { - json.NewEncoder(w).Encode(r) -} - -func (p *PrefixedRegistry) MarshalJSON() ([]byte, error) { - return json.Marshal(p.underlying) -} diff --git a/vendor/github.com/rcrowley/go-metrics/metrics.go b/vendor/github.com/rcrowley/go-metrics/metrics.go deleted file mode 100644 index b97a49ed12..0000000000 --- a/vendor/github.com/rcrowley/go-metrics/metrics.go +++ /dev/null @@ -1,13 +0,0 @@ -// Go port of Coda Hale's Metrics library -// -// -// -// Coda Hale's original work: -package metrics - -// UseNilMetrics is checked by the constructor functions for all of the -// 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 UseNilMetrics bool = false diff --git a/vendor/github.com/rjeczalik/notify/README.md b/vendor/github.com/rjeczalik/notify/README.md index 02a5f32908..ad743b2a24 100644 --- a/vendor/github.com/rjeczalik/notify/README.md +++ b/vendor/github.com/rjeczalik/notify/README.md @@ -19,3 +19,4 @@ Filesystem event notification library on steroids. (under active development) - [github.com/cortesi/devd](https://github.com/cortesi/devd) - [github.com/cortesi/modd](https://github.com/cortesi/modd) - [github.com/syncthing/syncthing-inotify](https://github.com/syncthing/syncthing-inotify) +- [github.com/OrlovEvgeny/TinyJPG](https://github.com/OrlovEvgeny/TinyJPG) diff --git a/vendor/github.com/rjeczalik/notify/appveyor.yml b/vendor/github.com/rjeczalik/notify/appveyor.yml index a495bd7c73..a0bdc37a38 100644 --- a/vendor/github.com/rjeczalik/notify/appveyor.yml +++ b/vendor/github.com/rjeczalik/notify/appveyor.yml @@ -7,16 +7,20 @@ clone_folder: c:\projects\src\github.com\rjeczalik\notify environment: PATH: c:\projects\bin;%PATH% GOPATH: c:\projects - NOTIFY_TIMEOUT: 5s + NOTIFY_TIMEOUT: 10s + GOVERSION: 1.10.3 install: + - rmdir c:\go /s /q + - appveyor DownloadFile https://storage.googleapis.com/golang/go%GOVERSION%.windows-amd64.zip + - 7z x go%GOVERSION%.windows-amd64.zip -y -oC:\ > NUL + + - cd %APPVEYOR_BUILD_FOLDER% - go version - - go get -v -t ./... build_script: - - go tool vet -all . - go build ./... - - go test -v -timeout 60s -race ./... + - go test -v -timeout 120s -race ./... test: off diff --git a/vendor/github.com/rjeczalik/notify/debug_debug.go b/vendor/github.com/rjeczalik/notify/debug_debug.go index 6fca891ab3..9d234cedda 100644 --- a/vendor/github.com/rjeczalik/notify/debug_debug.go +++ b/vendor/github.com/rjeczalik/notify/debug_debug.go @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2015 The Notify Authors. All rights reserved. +// Copyright (c) 2014-2018 The Notify Authors. All rights reserved. // Use of this source code is governed by the MIT license that can be // found in the LICENSE file. @@ -6,4 +6,4 @@ package notify -var debugTag bool = true +var debugTag = true diff --git a/vendor/github.com/rjeczalik/notify/debug_nodebug.go b/vendor/github.com/rjeczalik/notify/debug_nodebug.go index be391a2769..9ebf880d88 100644 --- a/vendor/github.com/rjeczalik/notify/debug_nodebug.go +++ b/vendor/github.com/rjeczalik/notify/debug_nodebug.go @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2015 The Notify Authors. All rights reserved. +// Copyright (c) 2014-2018 The Notify Authors. All rights reserved. // Use of this source code is governed by the MIT license that can be // found in the LICENSE file. @@ -6,4 +6,4 @@ package notify -var debugTag bool = false +var debugTag = false diff --git a/vendor/github.com/rjeczalik/notify/watcher_fsevents_cgo.go b/vendor/github.com/rjeczalik/notify/watcher_fsevents_cgo.go index 2248a1b129..cf0416c37e 100644 --- a/vendor/github.com/rjeczalik/notify/watcher_fsevents_cgo.go +++ b/vendor/github.com/rjeczalik/notify/watcher_fsevents_cgo.go @@ -48,7 +48,7 @@ var wg sync.WaitGroup // used to wait until the runloop starts // started and is ready via the wg. It also serves purpose of a dummy source, // thanks to it the runloop does not return as it also has at least one source // registered. -var source = C.CFRunLoopSourceCreate(refZero, 0, &C.CFRunLoopSourceContext{ +var source = C.CFRunLoopSourceCreate(C.kCFAllocatorDefault, 0, &C.CFRunLoopSourceContext{ perform: (C.CFRunLoopPerformCallBack)(C.gosource), }) @@ -90,6 +90,10 @@ func gostream(_, info uintptr, n C.size_t, paths, flags, ids uintptr) { if n == 0 { return } + fn := streamFuncs.get(info) + if fn == nil { + return + } ev := make([]FSEvent, 0, int(n)) for i := uintptr(0); i < uintptr(n); i++ { switch flags := *(*uint32)(unsafe.Pointer((flags + i*offflag))); { @@ -104,7 +108,7 @@ func gostream(_, info uintptr, n C.size_t, paths, flags, ids uintptr) { } } - streamFuncs.get(info)(ev) + fn(ev) } // StreamFunc is a callback called when stream receives file events. @@ -162,8 +166,8 @@ func (s *stream) Start() error { return nil } wg.Wait() - p := C.CFStringCreateWithCStringNoCopy(refZero, C.CString(s.path), C.kCFStringEncodingUTF8, refZero) - path := C.CFArrayCreate(refZero, (*unsafe.Pointer)(unsafe.Pointer(&p)), 1, nil) + p := C.CFStringCreateWithCStringNoCopy(C.kCFAllocatorDefault, C.CString(s.path), C.kCFStringEncodingUTF8, C.kCFAllocatorDefault) + path := C.CFArrayCreate(C.kCFAllocatorDefault, (*unsafe.Pointer)(unsafe.Pointer(&p)), 1, nil) ctx := C.FSEventStreamContext{} ref := C.EventStreamCreate(&ctx, C.uintptr_t(s.info), path, C.FSEventStreamEventId(atomic.LoadUint64(&since)), latency, flags) if ref == nilstream { diff --git a/vendor/github.com/rjeczalik/notify/watcher_fsevents_go1.10.go b/vendor/github.com/rjeczalik/notify/watcher_fsevents_go1.10.go deleted file mode 100644 index 0edd3782f5..0000000000 --- a/vendor/github.com/rjeczalik/notify/watcher_fsevents_go1.10.go +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2017 The Notify Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -// +build darwin,!kqueue,go1.10 - -package notify - -const refZero = 0 diff --git a/vendor/github.com/rjeczalik/notify/watcher_fsevents_go1.9.go b/vendor/github.com/rjeczalik/notify/watcher_fsevents_go1.9.go deleted file mode 100644 index b81c3c1859..0000000000 --- a/vendor/github.com/rjeczalik/notify/watcher_fsevents_go1.9.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) 2017 The Notify Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -// +build darwin,!kqueue,cgo,!go1.10 - -package notify - -/* -#include -*/ -import "C" - -var refZero = (*C.struct___CFAllocator)(nil) diff --git a/vendor/github.com/rjeczalik/notify/watcher_notimplemented.go b/vendor/github.com/rjeczalik/notify/watcher_notimplemented.go new file mode 100644 index 0000000000..bb0672fd88 --- /dev/null +++ b/vendor/github.com/rjeczalik/notify/watcher_notimplemented.go @@ -0,0 +1,15 @@ +// Copyright (c) 2014-2018 The Notify Authors. All rights reserved. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +// +build !darwin,!linux,!freebsd,!dragonfly,!netbsd,!openbsd,!windows +// +build !kqueue,!solaris + +package notify + +import "errors" + +// newWatcher stub. +func newWatcher(chan<- EventInfo) watcher { + return watcherStub{errors.New("notify: not implemented")} +} diff --git a/vendor/github.com/rjeczalik/notify/watcher_readdcw.go b/vendor/github.com/rjeczalik/notify/watcher_readdcw.go index 1494fcd799..b69811a690 100644 --- a/vendor/github.com/rjeczalik/notify/watcher_readdcw.go +++ b/vendor/github.com/rjeczalik/notify/watcher_readdcw.go @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2015 The Notify Authors. All rights reserved. +// Copyright (c) 2014-2018 The Notify Authors. All rights reserved. // Use of this source code is governed by the MIT license that can be // found in the LICENSE file. @@ -22,7 +22,7 @@ import ( const readBufferSize = 4096 // Since all operations which go through the Windows completion routine are done -// asynchronously, filter may set one of the constants belor. They were defined +// asynchronously, filter may set one of the constants below. They were defined // in order to distinguish whether current folder should be re-registered in // ReadDirectoryChangesW function or some control operations need to be executed. const ( @@ -109,8 +109,13 @@ func (g *grip) register(cph syscall.Handle) (err error) { // buffer. Directory changes that occur between calls to this function are added // to the buffer and then, returned with the next call. func (g *grip) readDirChanges() error { + handle := syscall.Handle(atomic.LoadUintptr((*uintptr)(&g.handle))) + if handle == syscall.InvalidHandle { + return nil // Handle was closed. + } + return syscall.ReadDirectoryChanges( - g.handle, + handle, &g.buffer[0], uint32(unsafe.Sizeof(g.buffer)), g.recursive, @@ -220,12 +225,27 @@ func (wd *watched) updateGrip(idx int, cph syscall.Handle, reset bool, // returned from the operating system kernel. func (wd *watched) closeHandle() (err error) { for _, g := range wd.digrip { - if g != nil && g.handle != syscall.InvalidHandle { - switch suberr := syscall.CloseHandle(g.handle); { - case suberr == nil: - g.handle = syscall.InvalidHandle - case err == nil: - err = suberr + if g == nil { + continue + } + + for { + handle := syscall.Handle(atomic.LoadUintptr((*uintptr)(&g.handle))) + if handle == syscall.InvalidHandle { + break // Already closed. + } + + e := syscall.CloseHandle(handle) + if e != nil && err == nil { + err = e + } + + // Set invalid handle even when CloseHandle fails. This will leak + // the handle but, since we can't close it anyway, there won't be + // any difference. + if atomic.CompareAndSwapUintptr((*uintptr)(&g.handle), + (uintptr)(handle), (uintptr)(syscall.InvalidHandle)) { + break } } } @@ -272,50 +292,49 @@ func (r *readdcw) RecursiveWatch(path string, event Event) error { // watch inserts a directory to the group of watched folders. If watched folder // already exists, function tries to rewatch it with new filters(NOT VALID). Moreover, // watch starts the main event loop goroutine when called for the first time. -func (r *readdcw) watch(path string, event Event, recursive bool) (err error) { +func (r *readdcw) watch(path string, event Event, recursive bool) error { if event&^(All|fileNotifyChangeAll) != 0 { return errors.New("notify: unknown event") } + r.Lock() - wd, ok := r.m[path] - r.Unlock() - if !ok { - if err = r.lazyinit(); err != nil { - return - } - r.Lock() - defer r.Unlock() - if wd, ok = r.m[path]; ok { - dbgprint("watch: exists already") - return - } - if wd, err = newWatched(r.cph, uint32(event), recursive, path); err != nil { - return - } - r.m[path] = wd - dbgprint("watch: new watch added") - } else { - dbgprint("watch: exists already") + defer r.Unlock() + + if wd, ok := r.m[path]; ok { + dbgprint("watch: already exists") + wd.filter &^= stateUnwatch + return nil } + + if err := r.lazyinit(); err != nil { + return err + } + + wd, err := newWatched(r.cph, uint32(event), recursive, path) + if err != nil { + return err + } + + r.m[path] = wd + dbgprint("watch: new watch added") + return nil } -// lazyinit creates an I/O completion port and starts the main event processing -// loop. This method uses Double-Checked Locking optimization. +// lazyinit creates an I/O completion port and starts the main event loop. func (r *readdcw) lazyinit() (err error) { invalid := uintptr(syscall.InvalidHandle) + if atomic.LoadUintptr((*uintptr)(&r.cph)) == invalid { - r.Lock() - defer r.Unlock() - if atomic.LoadUintptr((*uintptr)(&r.cph)) == invalid { - cph := syscall.InvalidHandle - if cph, err = syscall.CreateIoCompletionPort(cph, 0, 0, 0); err != nil { - return - } - r.cph, r.start = cph, true - go r.loop() + cph := syscall.InvalidHandle + if cph, err = syscall.CreateIoCompletionPort(cph, 0, 0, 0); err != nil { + return } + + r.cph, r.start = cph, true + go r.loop() } + return } @@ -364,6 +383,7 @@ func (r *readdcw) loopstate(overEx *overlappedEx) { overEx.parent.parent.recreate(r.cph) case stateUnwatch: dbgprint("loopstate unwatch") + overEx.parent.parent.closeHandle() delete(r.m, syscall.UTF16ToString(overEx.parent.pathw)) case stateCPClose: default: @@ -495,27 +515,30 @@ func (r *readdcw) RecursiveUnwatch(path string) error { // TODO : pknap func (r *readdcw) unwatch(path string) (err error) { var wd *watched + r.Lock() defer r.Unlock() if wd, err = r.nonStateWatchedLocked(path); err != nil { return } + wd.filter |= stateUnwatch - if err = wd.closeHandle(); err != nil { - wd.filter &^= stateUnwatch - return - } + dbgprint("unwatch: set unwatch state") + if _, attrErr := syscall.GetFileAttributes(&wd.pathw[0]); attrErr != nil { for _, g := range wd.digrip { - if g != nil { - dbgprint("unwatch: posting") - if err = syscall.PostQueuedCompletionStatus(r.cph, 0, 0, (*syscall.Overlapped)(unsafe.Pointer(g.ovlapped))); err != nil { - wd.filter &^= stateUnwatch - return - } + if g == nil { + continue + } + + dbgprint("unwatch: posting") + if err = syscall.PostQueuedCompletionStatus(r.cph, 0, 0, (*syscall.Overlapped)(unsafe.Pointer(g.ovlapped))); err != nil { + wd.filter &^= stateUnwatch + return } } } + return } diff --git a/vendor/github.com/rjeczalik/notify/watcher_stub.go b/vendor/github.com/rjeczalik/notify/watcher_stub.go index 68b9c135b0..9b284ddc85 100644 --- a/vendor/github.com/rjeczalik/notify/watcher_stub.go +++ b/vendor/github.com/rjeczalik/notify/watcher_stub.go @@ -1,23 +1,13 @@ -// Copyright (c) 2014-2015 The Notify Authors. All rights reserved. +// Copyright (c) 2014-2018 The Notify Authors. All rights reserved. // Use of this source code is governed by the MIT license that can be // found in the LICENSE file. -// +build !darwin,!linux,!freebsd,!dragonfly,!netbsd,!openbsd,!windows -// +build !kqueue,!solaris - package notify -import "errors" - -type stub struct{ error } - -// newWatcher stub. -func newWatcher(chan<- EventInfo) watcher { - return stub{errors.New("notify: not implemented")} -} +type watcherStub struct{ error } // Following methods implement notify.watcher interface. -func (s stub) Watch(string, Event) error { return s } -func (s stub) Rewatch(string, Event, Event) error { return s } -func (s stub) Unwatch(string) (err error) { return s } -func (s stub) Close() error { return s } +func (s watcherStub) Watch(string, Event) error { return s } +func (s watcherStub) Rewatch(string, Event, Event) error { return s } +func (s watcherStub) Unwatch(string) (err error) { return s } +func (s watcherStub) Close() error { return s } diff --git a/vendor/github.com/rjeczalik/notify/watcher_trigger.go b/vendor/github.com/rjeczalik/notify/watcher_trigger.go index 78151f909b..1ebe04829e 100644 --- a/vendor/github.com/rjeczalik/notify/watcher_trigger.go +++ b/vendor/github.com/rjeczalik/notify/watcher_trigger.go @@ -106,7 +106,8 @@ func newWatcher(c chan<- EventInfo) watcher { } t.t = newTrigger(t.pthLkp) if err := t.t.Init(); err != nil { - panic(err) + t.Close() + return watcherStub{fmt.Errorf("failed setting up watcher: %v", err)} } go t.monitor() return t diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/cache/cache.go b/vendor/github.com/syndtr/goleveldb/leveldb/cache/cache.go index c5940b232c..c36ad32359 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/cache/cache.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/cache/cache.go @@ -331,7 +331,6 @@ func (r *Cache) delete(n *Node) bool { return deleted } } - return false } // Nodes returns number of 'cache node' in the map. diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/comparer/bytes_comparer.go b/vendor/github.com/syndtr/goleveldb/leveldb/comparer/bytes_comparer.go index 14dddf88dd..abf9fb65c7 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/comparer/bytes_comparer.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/comparer/bytes_comparer.go @@ -29,7 +29,7 @@ func (bytesComparer) Separator(dst, a, b []byte) []byte { // Do not shorten if one string is a prefix of the other } else if c := a[i]; c < 0xff && c+1 < b[i] { dst = append(dst, a[:i+1]...) - dst[i]++ + dst[len(dst)-1]++ return dst } return nil @@ -39,7 +39,7 @@ func (bytesComparer) Successor(dst, b []byte) []byte { for i, c := range b { if c != 0xff { dst = append(dst, b[:i+1]...) - dst[i]++ + dst[len(dst)-1]++ return dst } } diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/comparer/comparer.go b/vendor/github.com/syndtr/goleveldb/leveldb/comparer/comparer.go index 14a28f16fc..2c522db23b 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/comparer/comparer.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/comparer/comparer.go @@ -36,7 +36,7 @@ type Comparer interface { // by any users of this package. Name() string - // Bellow are advanced functions used used to reduce the space requirements + // Bellow are advanced functions used to reduce the space requirements // for internal data structures such as index blocks. // Separator appends a sequence of bytes x to dst such that a <= x && x < b, diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/db.go b/vendor/github.com/syndtr/goleveldb/leveldb/db.go index ea5595eb3a..0de5ffe8d7 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/db.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/db.go @@ -35,6 +35,7 @@ type DB struct { // 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. @@ -181,7 +182,7 @@ func Open(stor storage.Storage, o *opt.Options) (db *DB, err error) { err = s.recover() if err != nil { - if !os.IsNotExist(err) || s.o.GetErrorIfMissing() { + if !os.IsNotExist(err) || s.o.GetErrorIfMissing() || s.o.GetReadOnly() { return } err = s.create() @@ -467,7 +468,7 @@ func recoverTable(s *session, o *opt.Options) error { } // Commit. - return s.commit(rec) + return s.commit(rec, false) } func (db *DB) recoverJournal() error { @@ -537,7 +538,7 @@ func (db *DB) recoverJournal() error { rec.setJournalNum(fd.Num) rec.setSeqNum(db.seq) - if err := db.s.commit(rec); err != nil { + if err := db.s.commit(rec, false); err != nil { fr.Close() return err } @@ -616,7 +617,7 @@ func (db *DB) recoverJournal() error { // Commit. rec.setJournalNum(db.journalFd.Num) rec.setSeqNum(db.seq) - if err := db.s.commit(rec); err != nil { + if err := db.s.commit(rec, false); err != nil { // Close journal on error. if db.journal != nil { db.journal.Close() @@ -871,6 +872,10 @@ func (db *DB) Has(key []byte, ro *opt.ReadOptions) (ret bool, err error) { // DB. And a nil Range.Limit is treated as a key after all keys in // the DB. // +// WARNING: Any slice returned by interator (e.g. slice returned by calling +// Iterator.Key() or Iterator.Key() methods), its content should not be modified +// unless noted otherwise. +// // The iterator must be released after use, by calling Release method. // // Also read Iterator documentation of the leveldb/iterator package. @@ -906,6 +911,8 @@ 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 @@ -950,18 +957,35 @@ func (db *DB) GetProperty(name string) (value string, err error) { value = "Compactions\n" + " Level | Tables | Size(MB) | Time(sec) | Read(MB) | Write(MB)\n" + "-------+------------+---------------+---------------+---------------+---------------\n" + var totalTables int + var totalSize, totalRead, totalWrite int64 + var totalDuration time.Duration for level, tables := range v.levels { duration, read, write := db.compStats.getStat(level) if len(tables) == 0 && duration == 0 { continue } + totalTables += len(tables) + totalSize += tables.size() + totalRead += read + totalWrite += write + totalDuration += duration value += fmt.Sprintf(" %3d | %10d | %13.5f | %13.5f | %13.5f | %13.5f\n", level, len(tables), float64(tables.size())/1048576.0, duration.Seconds(), float64(read)/1048576.0, float64(write)/1048576.0) } + value += "-------+------------+---------------+---------------+---------------+---------------\n" + value += fmt.Sprintf(" Total | %10d | %13.5f | %13.5f | %13.5f | %13.5f\n", + totalTables, float64(totalSize)/1048576.0, totalDuration.Seconds(), + float64(totalRead)/1048576.0, float64(totalWrite)/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)) - value = fmt.Sprintf("DelayN:%d Delay:%s", writeDelayN, writeDelay) + 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) @@ -990,6 +1014,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 Sizes + LevelTablesCounts []int + LevelRead Sizes + LevelWrite Sizes + 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 b6563e87e4..56f3632a7d 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/db_compaction.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/db_compaction.go @@ -260,7 +260,7 @@ func (db *DB) compactionCommit(name string, rec *sessionRecord) { db.compCommitLk.Lock() defer db.compCommitLk.Unlock() // Defer is necessary. db.compactionTransactFunc(name+"@commit", func(cnt *compactionTransactCounter) error { - return db.s.commit(rec) + return db.s.commit(rec, true) }, nil) } @@ -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 non-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 + waitQ []cCmd + ) defer func() { if x := recover(); x != nil { @@ -774,9 +787,9 @@ func (db *DB) tCompaction() { panic(x) } } - for i := range ackQ { - 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 +808,20 @@ func (db *DB) tCompaction() { return default: } - } else { - for i := range ackQ { - ackQ[i].ack(nil) - ackQ[i] = nil + // 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] } - ackQ = ackQ[:0] + } else { + 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 +834,14 @@ func (db *DB) tCompaction() { if x != nil { switch cmd := x.(type) { case cAuto: - ackQ = append(ackQ, x) + if cmd.ackC != nil { + // Check the write pause state before caching it. + if db.resumeWrite() { + x.ack(nil) + } else { + waitQ = append(waitQ, x) + } + } case cRange: x.ack(db.tableRangeCompaction(cmd.level, cmd.min, cmd.max)) default: diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/db_snapshot.go b/vendor/github.com/syndtr/goleveldb/leveldb/db_snapshot.go index 2c69d2e531..c2ad70c847 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/db_snapshot.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/db_snapshot.go @@ -142,6 +142,10 @@ func (snap *Snapshot) Has(key []byte, ro *opt.ReadOptions) (ret bool, err error) // DB. And a nil Range.Limit is treated as a key after all keys in // the DB. // +// WARNING: Any slice returned by interator (e.g. slice returned by calling +// Iterator.Key() or Iterator.Value() methods), its content should not be +// modified unless noted otherwise. +// // The iterator must be released after use, by calling Release method. // Releasing the snapshot doesn't mean releasing the iterator too, the // iterator would be still valid until released. diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/db_transaction.go b/vendor/github.com/syndtr/goleveldb/leveldb/db_transaction.go index b8f7e7d21d..f145b64fbb 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/db_transaction.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/db_transaction.go @@ -69,6 +69,10 @@ func (tr *Transaction) Has(key []byte, ro *opt.ReadOptions) (bool, error) { // DB. And a nil Range.Limit is treated as a key after all keys in // the DB. // +// WARNING: Any slice returned by interator (e.g. slice returned by calling +// Iterator.Key() or Iterator.Key() methods), its content should not be modified +// unless noted otherwise. +// // The iterator must be released after use, by calling Release method. // // Also read Iterator documentation of the leveldb/iterator package. @@ -205,7 +209,7 @@ func (tr *Transaction) Commit() error { tr.stats.startTimer() var cerr error for retry := 0; retry < 3; retry++ { - cerr = tr.db.s.commit(&tr.rec) + cerr = tr.db.s.commit(&tr.rec, false) if cerr != nil { tr.db.logf("transaction@commit error R·%d %q", retry, cerr) select { diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/db_util.go b/vendor/github.com/syndtr/goleveldb/leveldb/db_util.go index 7ecd960d2c..3f0654894b 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/db_util.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/db_util.go @@ -84,7 +84,7 @@ func (db *DB) checkAndCleanFiles() error { var mfds []storage.FileDesc for num, present := range tmap { if !present { - mfds = append(mfds, storage.FileDesc{storage.TypeTable, num}) + mfds = append(mfds, storage.FileDesc{Type: storage.TypeTable, Num: num}) db.logf("db@janitor table missing @%d", num) } } diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/db_write.go b/vendor/github.com/syndtr/goleveldb/leveldb/db_write.go index 31f4bc5efc..db0c1bece1 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/db_write.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/db_write.go @@ -89,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 } diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/iterator/iter.go b/vendor/github.com/syndtr/goleveldb/leveldb/iterator/iter.go index 3b55532746..96fb0f6859 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/iterator/iter.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/iterator/iter.go @@ -40,11 +40,11 @@ type IteratorSeeker interface { Seek(key []byte) bool // Next moves the iterator to the next key/value pair. - // It returns whether the iterator is exhausted. + // It returns false if the iterator is exhausted. Next() bool // Prev moves the iterator to the previous key/value pair. - // It returns whether the iterator is exhausted. + // It returns false if the iterator is exhausted. Prev() bool } @@ -88,7 +88,7 @@ type Iterator interface { // its contents may change on the next call to any 'seeks method'. Key() []byte - // Value returns the key of the current key/value pair, or nil if done. + // 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 any 'seeks method'. Value() []byte diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/memdb/memdb.go b/vendor/github.com/syndtr/goleveldb/leveldb/memdb/memdb.go index 18a19ed424..b661c08a93 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/memdb/memdb.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/memdb/memdb.go @@ -329,7 +329,7 @@ func (p *DB) Delete(key []byte) error { h := p.nodeData[node+nHeight] for i, n := range p.prevNode[:h] { - m := n + 4 + i + m := n + nNext + i p.nodeData[m] = p.nodeData[p.nodeData[m]+nNext+i] } diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/opt/options.go b/vendor/github.com/syndtr/goleveldb/leveldb/opt/options.go index 44e7d9adce..528b164233 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/opt/options.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/opt/options.go @@ -158,6 +158,12 @@ type Options struct { // The default value is 8MiB. BlockCacheCapacity int + // BlockCacheEvictRemoved allows enable forced-eviction on cached block belonging + // to removed 'sorted table'. + // + // The default if false. + BlockCacheEvictRemoved bool + // BlockRestartInterval is the number of keys between restart points for // delta encoding of keys. // @@ -384,6 +390,13 @@ func (o *Options) GetBlockCacheCapacity() int { return o.BlockCacheCapacity } +func (o *Options) GetBlockCacheEvictRemoved() bool { + if o == nil { + return false + } + return o.BlockCacheEvictRemoved +} + func (o *Options) GetBlockRestartInterval() int { if o == nil || o.BlockRestartInterval <= 0 { return DefaultBlockRestartInterval diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/session.go b/vendor/github.com/syndtr/goleveldb/leveldb/session.go index ad68a87039..1bec34c4c3 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), } @@ -180,19 +180,19 @@ func (s *session) recover() (err error) { } s.manifestFd = fd - s.setVersion(staging.finish()) + s.setVersion(staging.finish(false)) s.setNextFileNum(rec.nextFileNum) s.recordCommited(rec) return nil } // Commit session; need external synchronization. -func (s *session) commit(r *sessionRecord) (err error) { +func (s *session) commit(r *sessionRecord, trivial bool) (err error) { v := s.version() defer v.release() // spawn new version based on current version - nv := v.spawn(r) + nv := v.spawn(r, trivial) if s.manifest == nil { // manifest journal writer not yet created, create one diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/session_util.go b/vendor/github.com/syndtr/goleveldb/leveldb/session_util.go index 92328933cc..40cb2cf957 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/session_util.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/session_util.go @@ -36,7 +36,7 @@ func (s *session) logf(format string, v ...interface{}) { s.stor.Log(fmt.Sprintf func (s *session) newTemp() storage.FileDesc { num := atomic.AddInt64(&s.stTempFileNum, 1) - 1 - return storage.FileDesc{storage.TypeTemp, num} + return storage.FileDesc{Type: storage.TypeTemp, Num: num} } func (s *session) addFileRef(fd storage.FileDesc, ref int) int { @@ -190,7 +190,7 @@ func (s *session) recordCommited(rec *sessionRecord) { // Create a new manifest file; need external synchronization. func (s *session) newManifest(rec *sessionRecord, v *version) (err error) { - fd := storage.FileDesc{storage.TypeManifest, s.allocFileNum()} + fd := storage.FileDesc{Type: storage.TypeManifest, Num: s.allocFileNum()} writer, err := s.stor.Create(fd) if err != nil { return 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 0000000000..d45fb5dfeb --- /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 1189decac6..9ba71fd6d1 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 bab62bfcee..b829798012 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_unix.go b/vendor/github.com/syndtr/goleveldb/leveldb/storage/file_storage_unix.go index 7e29915379..d75f66a9ef 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 9b0421f035..838f1bee1b 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/storage.go b/vendor/github.com/syndtr/goleveldb/leveldb/storage/storage.go index c16bce6b66..4e4a724258 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 81d18a531e..518e1db1cd 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/table.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/table.go @@ -78,7 +78,7 @@ func newTableFile(fd storage.FileDesc, size int64, imin, imax internalKey) *tFil } func tableFileFromRecord(r atRecord) *tFile { - return newTableFile(storage.FileDesc{storage.TypeTable, r.num}, r.size, r.imin, r.imax) + return newTableFile(storage.FileDesc{Type: storage.TypeTable, Num: r.num}, r.size, r.imin, r.imax) } // tFiles hold multiple tFile. @@ -150,6 +150,14 @@ func (tf tFiles) searchMax(icmp *iComparer, ikey internalKey) int { }) } +// Searches smallest index of tables whose its file number +// is smaller than the given number. +func (tf tFiles) searchNumLess(num int64) int { + return sort.Search(len(tf), func(i int) bool { + return tf[i].fd.Num < num + }) +} + // Returns true if given key range overlaps with one or more // tables key range. If unsorted is true then binary search will not be used. func (tf tFiles) overlaps(icmp *iComparer, umin, umax []byte, unsorted bool) bool { @@ -290,16 +298,17 @@ func (x *tFilesSortByNum) Less(i, j int) bool { // Table operations. type tOps struct { - s *session - noSync bool - cache *cache.Cache - bcache *cache.Cache - bpool *util.BufferPool + s *session + noSync bool + evictRemoved bool + cache *cache.Cache + bcache *cache.Cache + bpool *util.BufferPool } // Creates an empty table and returns table writer. func (t *tOps) create() (*tWriter, error) { - fd := storage.FileDesc{storage.TypeTable, t.s.allocFileNum()} + fd := storage.FileDesc{Type: storage.TypeTable, Num: t.s.allocFileNum()} fw, err := t.s.stor.Create(fd) if err != nil { return nil, err @@ -422,7 +431,7 @@ func (t *tOps) remove(f *tFile) { } else { t.s.logf("table@remove removed @%d", f.fd.Num) } - if t.bcache != nil { + if t.evictRemoved && t.bcache != nil { t.bcache.EvictNS(uint64(f.fd.Num)) } }) @@ -451,7 +460,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) } @@ -459,11 +468,12 @@ func newTableOps(s *session) *tOps { bpool = util.NewBufferPool(s.o.GetBlockSize() + 5) } return &tOps{ - s: s, - noSync: s.o.GetNoSync(), - cache: cache.NewCache(cacher), - bcache: bcache, - bpool: bpool, + s: s, + noSync: s.o.GetNoSync(), + evictRemoved: s.o.GetBlockCacheEvictRemoved(), + cache: cache.NewCache(cacher), + bcache: bcache, + bpool: bpool, } } diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/util.go b/vendor/github.com/syndtr/goleveldb/leveldb/util.go index e572a329e9..0e2b519e5c 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/leveldb/util/util.go b/vendor/github.com/syndtr/goleveldb/leveldb/util/util.go index f35976865b..80614afc58 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/util/util.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/util/util.go @@ -19,7 +19,7 @@ var ( // Releaser is the interface that wraps the basic Release method. type Releaser interface { // Release releases associated resources. Release should always success - // and can be called multipe times without causing error. + // and can be called multiple times without causing error. Release() } diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/version.go b/vendor/github.com/syndtr/goleveldb/leveldb/version.go index 73f272af5f..51361e5d80 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/version.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/version.go @@ -273,10 +273,10 @@ func (v *version) newStaging() *versionStaging { } // Spawn a new version based on this version. -func (v *version) spawn(r *sessionRecord) *version { +func (v *version) spawn(r *sessionRecord, trivial bool) *version { staging := v.newStaging() staging.commit(r) - return staging.finish() + return staging.finish(trivial) } func (v *version) fillRecord(r *sessionRecord) { @@ -446,7 +446,7 @@ func (p *versionStaging) commit(r *sessionRecord) { } } -func (p *versionStaging) finish() *version { +func (p *versionStaging) finish(trivial bool) *version { // Build new version. nv := newVersion(p.base.s) numLevel := len(p.levels) @@ -463,6 +463,12 @@ func (p *versionStaging) finish() *version { if level < len(p.levels) { scratch := p.levels[level] + // Short circuit if there is no change at all. + if len(scratch.added) == 0 && len(scratch.deleted) == 0 { + nv.levels[level] = baseTabels + continue + } + var nt tFiles // Prealloc list if possible. if n := len(baseTabels) + len(scratch.added) - len(scratch.deleted); n > 0 { @@ -480,6 +486,41 @@ func (p *versionStaging) finish() *version { nt = append(nt, t) } + // Avoid resort if only files in this level are deleted + if len(scratch.added) == 0 { + nv.levels[level] = nt + continue + } + + // For normal table compaction, one compaction will only involve two levels + // of files. And the new files generated after merging the source level and + // source+1 level related files can be inserted as a whole into source+1 level + // without any overlap with the other source+1 files. + // + // When the amount of data maintained by leveldb is large, the number of files + // per level will be very large. While qsort is very inefficient for sorting + // already ordered arrays. Therefore, for the normal table compaction, we use + // binary search here to find the insert index to insert a batch of new added + // files directly instead of using qsort. + if trivial && len(scratch.added) > 0 { + added := make(tFiles, 0, len(scratch.added)) + for _, r := range scratch.added { + added = append(added, tableFileFromRecord(r)) + } + if level == 0 { + added.sortByNum() + index := nt.searchNumLess(added[len(added)-1].fd.Num) + nt = append(nt[:index], append(added, nt[index:]...)...) + } else { + added.sortByKey(p.base.s.icmp) + _, amax := added.getRange(p.base.s.icmp) + index := nt.searchMin(p.base.s.icmp, amax) + nt = append(nt[:index], append(added, nt[index:]...)...) + } + nv.levels[level] = nt + continue + } + // New tables. for _, r := range scratch.added { nt = append(nt, tableFileFromRecord(r)) diff --git a/vendor/github.com/uber/jaeger-client-go/CHANGELOG.md b/vendor/github.com/uber/jaeger-client-go/CHANGELOG.md new file mode 100644 index 0000000000..28e2c24255 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/CHANGELOG.md @@ -0,0 +1,186 @@ +Changes by Version +================== + +2.15.0 (unreleased) +------------------- + +- nothing yet + + +2.14.0 (2018-04-30) +------------------- + +- Support throttling for debug traces (#274) +- Remove dependency on Apache Thrift (#303) +- Remove dependency on tchannel (#295) (#294) +- Test with Go 1.9 (#298) + + +2.13.0 (2018-04-15) +------------------- + +- Use value receiver for config.NewTracer() (#283) +- Lock span during jaeger thrift conversion (#273) +- Fix the RemotelyControlledSampler so that it terminates go-routine on Close() (#260) +- Added support for client configuration via env vars (#275) +- Allow overriding sampler in the Config (#270) + + +2.12.0 (2018-03-14) +------------------- + +- Use lock when retrieving span.Context() (#268) +- Add Configuration support for custom Injector and Extractor (#263) + + +2.11.2 (2018-01-12) +------------------- + +- Add Gopkg.toml to allow using the lib with `dep` + + +2.11.1 (2018-01-03) +------------------- + +- Do not enqueue spans after Reporter is closed (#235, #245) +- Change default flush interval to 1sec (#243) + + +2.11.0 (2017-11-27) +------------------- + +- Normalize metric names and tags to be compatible with Prometheus (#222) + + +2.10.0 (2017-11-14) +------------------- + +- Support custom tracing headers (#176) +- Add BaggageRestrictionManager (#178) and RemoteBaggageRestrictionManager (#182) +- Do not coerce baggage keys to lower case (#196) +- Log span name when span cannot be reported (#198) +- Add option to enable gen128Bit for tracer (#193) and allow custom generator for high bits of trace ID (#219) + + +2.9.0 (2017-07-29) +------------------ + +- Pin thrift <= 0.10 (#179) +- Introduce a parallel interface ContribObserver (#159) + + +2.8.0 (2017-07-05) +------------------ + +- Drop `jaeger.` prefix from `jaeger.hostname` process-level tag +- Add options to set tracer tags + + +2.7.0 (2017-06-21) +------------------ + +- Fix rate limiter balance [#135](https://github.com/uber/jaeger-client-go/pull/135) [#140](https://github.com/uber/jaeger-client-go/pull/140) +- Default client to send Jaeger.thrift [#147](https://github.com/uber/jaeger-client-go/pull/147) +- Save baggage in span [#153](https://github.com/uber/jaeger-client-go/pull/153) +- Move reporter.queueLength to the top of the struct to guarantee 64bit alignment [#158](https://github.com/uber/jaeger-client-go/pull/158) +- Support HTTP transport with jaeger.thrift [#161](https://github.com/uber/jaeger-client-go/pull/161) + + +2.6.0 (2017-03-28) +------------------ + +- Add config option to initialize RPC Metrics feature + + +2.5.0 (2017-03-23) +------------------ + +- Split request latency metric by success/failure [#123](https://github.com/uber/jaeger-client-go/pull/123) +- Add mutex to adaptive sampler and fix race condition [#124](https://github.com/uber/jaeger-client-go/pull/124) +- Fix rate limiter panic [#125](https://github.com/uber/jaeger-client-go/pull/125) + + +2.4.0 (2017-03-21) +------------------ + +- Remove `_ms` suffix from request latency metric name [#121](https://github.com/uber/jaeger-client-go/pull/121) +- Rename all metrics to "request" and "http_request" and use tags for other dimensions [#121](https://github.com/uber/jaeger-client-go/pull/121) + + +2.3.0 (2017-03-20) +------------------ + +- Make Span type public to allow access to non-std methods for testing [#117](https://github.com/uber/jaeger-client-go/pull/117) +- Add a structured way to extract traces for logging with zap [#118](https://github.com/uber/jaeger-client-go/pull/118) + + +2.2.1 (2017-03-14) +------------------ + +- Fix panic caused by updating the remote sampler from adaptive sampler to any other sampler type (https://github.com/uber/jaeger-client-go/pull/111) + + +2.2.0 (2017-03-10) +------------------ + +- Introduce Observer and SpanObserver (https://github.com/uber/jaeger-client-go/pull/94) +- Add RPC metrics emitter as Observer/SpanObserver (https://github.com/uber/jaeger-client-go/pull/103) + + +2.1.2 (2017-02-27) +------------------- + +- Fix leaky bucket bug (https://github.com/uber/jaeger-client-go/pull/99) +- Fix zap logger Infof (https://github.com/uber/jaeger-client-go/pull/100) +- Add tracer initialization godoc examples + + +2.1.1 (2017-02-21) +------------------- + +- Fix inefficient usage of zap.Logger + + +2.1.0 (2017-02-17) +------------------- + +- Add adapter for zap.Logger (https://github.com/uber-go/zap) +- Move logging API to ./log/ package + + +2.0.0 (2017-02-08) +------------------- + +- Support Adaptive Sampling +- Support 128bit Trace IDs +- Change trace/span IDs from uint64 to strong types TraceID and SpanID +- Add Zipkin HTTP B3 Propagation format support #72 +- Rip out existing metrics and use github.com/uber/jaeger-lib/metrics +- Change API for tracer, reporter, sampler initialization + + +1.6.0 (2016-10-14) +------------------- + +- Add Zipkin HTTP transport +- Support external baggage via jaeger-baggage header +- Unpin Thrift version, keep to master + + +1.5.1 (2016-09-27) +------------------- + +- Relax dependency on opentracing to ^1 + + +1.5.0 (2016-09-27) +------------------- + +- Upgrade to opentracing-go 1.0 +- Support KV logging for Spans + + +1.4.0 (2016-09-14) +------------------- + +- Support debug traces via HTTP header "jaeger-debug-id" diff --git a/vendor/github.com/uber/jaeger-client-go/CONTRIBUTING.md b/vendor/github.com/uber/jaeger-client-go/CONTRIBUTING.md new file mode 100644 index 0000000000..7cf014a51e --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/CONTRIBUTING.md @@ -0,0 +1,170 @@ +# How to Contribute to Jaeger + +We'd love your help! + +Jaeger is [Apache 2.0 licensed](LICENSE) and accepts contributions via GitHub +pull requests. This document outlines some of the conventions on development +workflow, commit message formatting, contact points and other resources to make +it easier to get your contribution accepted. + +We gratefully welcome improvements to documentation as well as to code. + +# Certificate of Origin + +By contributing to this project you agree to the [Developer Certificate of +Origin](https://developercertificate.org/) (DCO). This document was created +by the Linux Kernel community and is a simple statement that you, as a +contributor, have the legal right to make the contribution. See the [DCO](DCO) +file for details. + +## Getting Started + +This library uses [glide](https://github.com/Masterminds/glide) to manage dependencies. + +To get started, make sure you clone the Git repository into the correct location +`github.com/uber/jaeger-client-go` relative to `$GOPATH`: + +``` +mkdir -p $GOPATH/src/github.com/uber +cd $GOPATH/src/github.com/uber +git clone git@github.com:jaegertracing/jaeger-client-go.git jaeger-client-go +cd jaeger-client-go +``` + +Then install dependencies and run the tests: + +``` +git submodule update --init --recursive +glide install +make test +``` + +## Imports grouping + +This projects follows the following pattern for grouping imports in Go files: + * imports from standard library + * imports from other projects + * imports from `jaeger-client-go` project + +For example: + +```go +import ( + "fmt" + + "github.com/uber/jaeger-lib/metrics" + "go.uber.org/zap" + + "github.com/uber/jaeger-client-go/config" +) +``` + +## Making A Change + +*Before making any significant changes, please [open an +issue](https://github.com/jaegertracing/jaeger-client-go/issues).* Discussing your proposed +changes ahead of time will make the contribution process smooth for everyone. + +Once we've discussed your changes and you've got your code ready, make sure +that tests are passing (`make test` or `make cover`) and open your PR. Your +pull request is most likely to be accepted if it: + +* Includes tests for new functionality. +* Follows the guidelines in [Effective + Go](https://golang.org/doc/effective_go.html) and the [Go team's common code + review comments](https://github.com/golang/go/wiki/CodeReviewComments). +* Has a [good commit message](https://chris.beams.io/posts/git-commit/): + * Separate subject from body with a blank line + * Limit the subject line to 50 characters + * Capitalize the subject line + * Do not end the subject line with a period + * Use the imperative mood in the subject line + * Wrap the body at 72 characters + * Use the body to explain _what_ and _why_ instead of _how_ +* Each commit must be signed by the author ([see below](#sign-your-work)). + +## License + +By contributing your code, you agree to license your contribution under the terms +of the [Apache License](LICENSE). + +If you are adding a new file it should have a header like below. The easiest +way to add such header is to run `make fmt`. + +``` +// Copyright (c) 2017 The Jaeger Authors. +// +// 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. +``` + +## Sign your work + +The sign-off is a simple line at the end of the explanation for the +patch, which certifies that you wrote it or otherwise have the right to +pass it on as an open-source patch. The rules are pretty simple: if you +can certify the below (from +[developercertificate.org](http://developercertificate.org/)): + +``` +Developer Certificate of Origin +Version 1.1 + +Copyright (C) 2004, 2006 The Linux Foundation and its contributors. +660 York Street, Suite 102, +San Francisco, CA 94110 USA + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. +``` + +then you just add a line to every git commit message: + + Signed-off-by: Joe Smith + +using your real name (sorry, no pseudonyms or anonymous contributions.) + +You can add the sign off when creating the git commit via `git commit -s`. + +If you want this to be automatic you can set up some aliases: + +``` +git config --add alias.amend "commit -s --amend" +git config --add alias.c "commit -s" +``` diff --git a/vendor/github.com/uber/jaeger-client-go/DCO b/vendor/github.com/uber/jaeger-client-go/DCO new file mode 100644 index 0000000000..068953d4bd --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/DCO @@ -0,0 +1,37 @@ +Developer Certificate of Origin +Version 1.1 + +Copyright (C) 2004, 2006 The Linux Foundation and its contributors. +660 York Street, Suite 102, +San Francisco, CA 94110 USA + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. + diff --git a/vendor/github.com/uber/jaeger-client-go/Gopkg.lock b/vendor/github.com/uber/jaeger-client-go/Gopkg.lock new file mode 100644 index 0000000000..ec054c6ed6 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/Gopkg.lock @@ -0,0 +1,164 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + branch = "master" + name = "github.com/beorn7/perks" + packages = ["quantile"] + revision = "3a771d992973f24aa725d07868b467d1ddfceafb" + +[[projects]] + branch = "master" + name = "github.com/codahale/hdrhistogram" + packages = ["."] + revision = "3a0bb77429bd3a61596f5e8a3172445844342120" + +[[projects]] + branch = "master" + name = "github.com/crossdock/crossdock-go" + packages = [ + ".", + "assert", + "require" + ] + revision = "049aabb0122b03bc9bd30cab8f3f91fb60166361" + +[[projects]] + name = "github.com/davecgh/go-spew" + packages = ["spew"] + revision = "346938d642f2ec3594ed81d874461961cd0faa76" + version = "v1.1.0" + +[[projects]] + name = "github.com/golang/protobuf" + packages = ["proto"] + revision = "925541529c1fa6821df4e44ce2723319eb2be768" + version = "v1.0.0" + +[[projects]] + name = "github.com/matttproud/golang_protobuf_extensions" + packages = ["pbutil"] + revision = "3247c84500bff8d9fb6d579d800f20b3e091582c" + version = "v1.0.0" + +[[projects]] + name = "github.com/opentracing/opentracing-go" + packages = [ + ".", + "ext", + "log" + ] + revision = "1949ddbfd147afd4d964a9f00b24eb291e0e7c38" + version = "v1.0.2" + +[[projects]] + name = "github.com/pkg/errors" + packages = ["."] + revision = "645ef00459ed84a119197bfb8d8205042c6df63d" + version = "v0.8.0" + +[[projects]] + name = "github.com/pmezard/go-difflib" + packages = ["difflib"] + revision = "792786c7400a136282c1664665ae0a8db921c6c2" + version = "v1.0.0" + +[[projects]] + name = "github.com/prometheus/client_golang" + packages = ["prometheus"] + revision = "c5b7fccd204277076155f10851dad72b76a49317" + version = "v0.8.0" + +[[projects]] + branch = "master" + name = "github.com/prometheus/client_model" + packages = ["go"] + revision = "99fa1f4be8e564e8a6b613da7fa6f46c9edafc6c" + +[[projects]] + branch = "master" + name = "github.com/prometheus/common" + packages = [ + "expfmt", + "internal/bitbucket.org/ww/goautoneg", + "model" + ] + revision = "d811d2e9bf898806ecfb6ef6296774b13ffc314c" + +[[projects]] + branch = "master" + name = "github.com/prometheus/procfs" + packages = [ + ".", + "internal/util", + "nfs", + "xfs" + ] + revision = "8b1c2da0d56deffdbb9e48d4414b4e674bd8083e" + +[[projects]] + name = "github.com/stretchr/testify" + packages = [ + "assert", + "require", + "suite" + ] + revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71" + version = "v1.2.1" + +[[projects]] + name = "github.com/uber-go/atomic" + packages = ["."] + revision = "8474b86a5a6f79c443ce4b2992817ff32cf208b8" + version = "v1.3.1" + +[[projects]] + name = "github.com/uber/jaeger-lib" + packages = [ + "metrics", + "metrics/prometheus", + "metrics/testutils" + ] + revision = "4267858c0679cd4e47cefed8d7f70fd386cfb567" + version = "v1.4.0" + +[[projects]] + name = "go.uber.org/atomic" + packages = ["."] + revision = "54f72d32435d760d5604f17a82e2435b28dc4ba5" + version = "v1.3.0" + +[[projects]] + name = "go.uber.org/multierr" + packages = ["."] + revision = "3c4937480c32f4c13a875a1829af76c98ca3d40a" + version = "v1.1.0" + +[[projects]] + name = "go.uber.org/zap" + packages = [ + ".", + "buffer", + "internal/bufferpool", + "internal/color", + "internal/exit", + "zapcore" + ] + revision = "eeedf312bc6c57391d84767a4cd413f02a917974" + version = "v1.8.0" + +[[projects]] + branch = "master" + name = "golang.org/x/net" + packages = [ + "context", + "context/ctxhttp" + ] + revision = "5f9ae10d9af5b1c89ae6904293b14b064d4ada23" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "f9dcfaf37a785c5dac1e20c29605eda29a83ba9c6f8842e92960dc94c8c4ff80" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/vendor/github.com/uber/jaeger-client-go/Gopkg.toml b/vendor/github.com/uber/jaeger-client-go/Gopkg.toml new file mode 100644 index 0000000000..baf7a6bdf7 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/Gopkg.toml @@ -0,0 +1,27 @@ +[[constraint]] + name = "github.com/crossdock/crossdock-go" + branch = "master" + +[[constraint]] + name = "github.com/opentracing/opentracing-go" + version = "^1" + +[[constraint]] + name = "github.com/prometheus/client_golang" + version = "0.8.0" + +[[constraint]] + name = "github.com/stretchr/testify" + version = "^1.1.3" + +[[constraint]] + name = "github.com/uber-go/atomic" + version = "^1" + +[[constraint]] + name = "github.com/uber/jaeger-lib" + version = "^1.3" + +[[constraint]] + name = "go.uber.org/zap" + version = "^1" diff --git a/vendor/github.com/uber/jaeger-client-go/LICENSE b/vendor/github.com/uber/jaeger-client-go/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/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/uber/jaeger-client-go/Makefile b/vendor/github.com/uber/jaeger-client-go/Makefile new file mode 100644 index 0000000000..601cc65148 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/Makefile @@ -0,0 +1,117 @@ +PROJECT_ROOT=github.com/uber/jaeger-client-go +PACKAGES := $(shell glide novendor | grep -v -e ./thrift-gen/... -e ./thrift/...) +# all .go files that don't exist in hidden directories +ALL_SRC := $(shell find . -name "*.go" | grep -v -e vendor -e thrift-gen -e ./thrift/ \ + -e ".*/\..*" \ + -e ".*/_.*" \ + -e ".*/mocks.*") + +-include crossdock/rules.mk + +export GO15VENDOREXPERIMENT=1 + +RACE=-race +GOTEST=go test -v $(RACE) +GOLINT=golint +GOVET=go vet +GOFMT=gofmt +FMT_LOG=fmt.log +LINT_LOG=lint.log + +THRIFT_VER=0.9.3 +THRIFT_IMG=thrift:$(THRIFT_VER) +THRIFT=docker run -v "${PWD}:/data" $(THRIFT_IMG) thrift +THRIFT_GO_ARGS=thrift_import="github.com/apache/thrift/lib/go/thrift" +THRIFT_GEN_DIR=thrift-gen + +PASS=$(shell printf "\033[32mPASS\033[0m") +FAIL=$(shell printf "\033[31mFAIL\033[0m") +COLORIZE=sed ''/PASS/s//$(PASS)/'' | sed ''/FAIL/s//$(FAIL)/'' + +.DEFAULT_GOAL := test-and-lint + +.PHONY: test-and-lint +test-and-lint: test fmt lint + +.PHONY: test +test: + bash -c "set -e; set -o pipefail; $(GOTEST) $(PACKAGES) | $(COLORIZE)" + +.PHONY: fmt +fmt: + $(GOFMT) -e -s -l -w $(ALL_SRC) + ./scripts/updateLicenses.sh + +.PHONY: lint +lint: + $(GOVET) $(PACKAGES) + @cat /dev/null > $(LINT_LOG) + @$(foreach pkg, $(PACKAGES), $(GOLINT) $(pkg) | grep -v crossdock/thrift >> $(LINT_LOG) || true;) + @[ ! -s "$(LINT_LOG)" ] || (echo "Lint Failures" | cat - $(LINT_LOG) && false) + @$(GOFMT) -e -s -l $(ALL_SRC) > $(FMT_LOG) + ./scripts/updateLicenses.sh >> $(FMT_LOG) + @[ ! -s "$(FMT_LOG)" ] || (echo "go fmt or license check failures, run 'make fmt'" | cat - $(FMT_LOG) && false) + + +.PHONY: install +install: + glide --version || go get github.com/Masterminds/glide +ifeq ($(USE_DEP),true) + dep ensure +else + glide install +endif + + +.PHONY: cover +cover: + ./scripts/cover.sh $(shell go list $(PACKAGES)) + go tool cover -html=cover.out -o cover.html + + +# This is not part of the regular test target because we don't want to slow it +# down. +.PHONY: test-examples +test-examples: + make -C examples + +# TODO at the moment we're not generating tchan_*.go files +thrift: idl-submodule thrift-image + $(THRIFT) -o /data --gen go:$(THRIFT_GO_ARGS) --out /data/$(THRIFT_GEN_DIR) /data/idl/thrift/agent.thrift + $(THRIFT) -o /data --gen go:$(THRIFT_GO_ARGS) --out /data/$(THRIFT_GEN_DIR) /data/idl/thrift/sampling.thrift + $(THRIFT) -o /data --gen go:$(THRIFT_GO_ARGS) --out /data/$(THRIFT_GEN_DIR) /data/idl/thrift/jaeger.thrift + $(THRIFT) -o /data --gen go:$(THRIFT_GO_ARGS) --out /data/$(THRIFT_GEN_DIR) /data/idl/thrift/zipkincore.thrift + $(THRIFT) -o /data --gen go:$(THRIFT_GO_ARGS) --out /data/$(THRIFT_GEN_DIR) /data/idl/thrift/baggage.thrift + $(THRIFT) -o /data --gen go:$(THRIFT_GO_ARGS) --out /data/crossdock/thrift/ /data/idl/thrift/crossdock/tracetest.thrift + sed -i '' 's|"zipkincore"|"$(PROJECT_ROOT)/thrift-gen/zipkincore"|g' $(THRIFT_GEN_DIR)/agent/*.go + sed -i '' 's|"jaeger"|"$(PROJECT_ROOT)/thrift-gen/jaeger"|g' $(THRIFT_GEN_DIR)/agent/*.go + sed -i '' 's|"github.com/apache/thrift/lib/go/thrift"|"github.com/uber/jaeger-client-go/thrift"|g' \ + $(THRIFT_GEN_DIR)/*/*.go crossdock/thrift/tracetest/*.go + rm -rf thrift-gen/*/*-remote + rm -rf crossdock/thrift/*/*-remote + rm -rf thrift-gen/jaeger/collector.go + +idl-submodule: + git submodule init + git submodule update + +thrift-image: + $(THRIFT) -version + +.PHONY: install-dep-ci +install-dep-ci: + - curl -L -s https://github.com/golang/dep/releases/download/v0.3.2/dep-linux-amd64 -o $$GOPATH/bin/dep + - chmod +x $$GOPATH/bin/dep + +.PHONY: install-ci +install-ci: install-dep-ci install + go get github.com/wadey/gocovmerge + go get github.com/mattn/goveralls + go get golang.org/x/tools/cmd/cover + go get github.com/golang/lint/golint + +.PHONY: test-ci +test-ci: + @./scripts/cover.sh $(shell go list $(PACKAGES)) + make lint + diff --git a/vendor/github.com/uber/jaeger-client-go/README.md b/vendor/github.com/uber/jaeger-client-go/README.md new file mode 100644 index 0000000000..16b04454e1 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/README.md @@ -0,0 +1,260 @@ +[![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov] [![OpenTracing 1.0 Enabled][ot-img]][ot-url] + +# Jaeger Bindings for Go OpenTracing API + +Instrumentation library that implements an +[OpenTracing](http://opentracing.io) Tracer for Jaeger (https://jaegertracing.io). + +**IMPORTANT**: The library's import path is based on its original location under `github.com/uber`. Do not try to import it as `github.com/jaegertracing`, it will not compile. We might revisit this in the next major release. + * :white_check_mark: `import "github.com/uber/jaeger-client-go"` + * :x: `import "github.com/jaegertracing/jaeger-client-go"` + +## How to Contribute + +Please see [CONTRIBUTING.md](CONTRIBUTING.md). + +## Installation + +We recommended using a dependency manager like [glide](https://github.com/Masterminds/glide) +and [semantic versioning](http://semver.org/) when including this library into an application. +For example, Jaeger backend imports this library like this: + +```yaml +- package: github.com/uber/jaeger-client-go + version: ^2.7.0 +``` + +If you instead want to use the latest version in `master`, you can pull it via `go get`. +Note that during `go get` you may see build errors due to incompatible dependencies, which is why +we recommend using semantic versions for dependencies. The error may be fixed by running +`make install` (it will install `glide` if you don't have it): + +```shell +go get -u github.com/uber/jaeger-client-go/ +cd $GOPATH/src/github.com/uber/jaeger-client-go/ +git submodule update --init --recursive +make install +``` + +## Initialization + +See tracer initialization examples in [godoc](https://godoc.org/github.com/uber/jaeger-client-go/config#pkg-examples) +and [config/example_test.go](./config/example_test.go). + +### Environment variables + +The tracer can be initialized with values coming from environment variables. None of the env vars are required +and all of them can be overriden via direct setting of the property on the configuration object. + +Property| Description +--- | --- +JAEGER_SERVICE_NAME | The service name +JAEGER_AGENT_HOST | The hostname for communicating with agent via UDP +JAEGER_AGENT_PORT | The port for communicating with agent via UDP +JAEGER_REPORTER_LOG_SPANS | Whether the reporter should also log the spans +JAEGER_REPORTER_MAX_QUEUE_SIZE | The reporter's maximum queue size +JAEGER_REPORTER_FLUSH_INTERVAL | The reporter's flush interval (ms) +JAEGER_SAMPLER_TYPE | The sampler type +JAEGER_SAMPLER_PARAM | The sampler parameter (number) +JAEGER_SAMPLER_MANAGER_HOST_PORT | The host name and port when using the remote controlled sampler +JAEGER_SAMPLER_MAX_OPERATIONS | The maximum number of operations that the sampler will keep track of +JAEGER_SAMPLER_REFRESH_INTERVAL | How often the remotely controlled sampler will poll jaeger-agent for the appropriate sampling strategy +JAEGER_TAGS | A comma separated list of `name = value` tracer level tags, which get added to all reported spans. The value can also refer to an environment variable using the format `${envVarName:default}`, where the `:default` is optional, and identifies a value to be used if the environment variable cannot be found +JAEGER_DISABLED | Whether the tracer is disabled or not. If true, the default `opentracing.NoopTracer` is used. +JAEGER_RPC_METRICS | Whether to store RPC metrics + +### Closing the tracer via `io.Closer` + +The constructor function for Jaeger Tracer returns the tracer itself and an `io.Closer` instance. +It is recommended to structure your `main()` so that it calls the `Close()` function on the closer +before exiting, e.g. + +```go +tracer, closer, err := cfg.NewTracer(...) +defer closer.Close() +``` + +This is especially useful for command-line tools that enable tracing, as well as +for the long-running apps that support graceful shutdown. For example, if your deployment +system sends SIGTERM instead of killing the process and you trap that signal to do a graceful +exit, then having `defer closer.Closer()` ensures that all buffered spans are flushed. + +### Metrics & Monitoring + +The tracer emits a number of different metrics, defined in +[metrics.go](metrics.go). The monitoring backend is expected to support +tag-based metric names, e.g. instead of `statsd`-style string names +like `counters.my-service.jaeger.spans.started.sampled`, the metrics +are defined by a short name and a collection of key/value tags, for +example: `name:jaeger.traces, state:started, sampled:y`. See [metrics.go](./metrics.go) +file for the full list and descriptions of emitted metrics. + +The monitoring backend is represented by the `metrics.Factory` interface from package +[`"github.com/uber/jaeger-lib/metrics"`](https://github.com/jaegertracing/jaeger-lib/tree/master/metrics). An implementation +of that interface can be passed as an option to either the Configuration object or the Tracer +constructor, for example: + +```go +import ( + "github.com/uber/jaeger-client-go/config" + "github.com/uber/jaeger-lib/metrics/prometheus" +) + + metricsFactory := prometheus.New() + tracer, closer, err := config.Configuration{ + ServiceName: "your-service-name", + }.NewTracer( + config.Metrics(metricsFactory), + ) +``` + +By default, a no-op `metrics.NullFactory` is used. + +### Logging + +The tracer can be configured with an optional logger, which will be +used to log communication errors, or log spans if a logging reporter +option is specified in the configuration. The logging API is abstracted +by the [Logger](logger.go) interface. A logger instance implementing +this interface can be set on the `Config` object before calling the +`New` method. + +Besides the [zap](https://github.com/uber-go/zap) implementation +bundled with this package there is also a [go-kit](https://github.com/go-kit/kit) +one in the [jaeger-lib](https://github.com/jaegertracing/jaeger-lib) repository. + +## Instrumentation for Tracing + +Since this tracer is fully compliant with OpenTracing API 1.0, +all code instrumentation should only use the API itself, as described +in the [opentracing-go](https://github.com/opentracing/opentracing-go) documentation. + +## Features + +### Reporters + +A "reporter" is a component that receives the finished spans and reports +them to somewhere. Under normal circumstances, the Tracer +should use the default `RemoteReporter`, which sends the spans out of +process via configurable "transport". For testing purposes, one can +use an `InMemoryReporter` that accumulates spans in a buffer and +allows to retrieve them for later verification. Also available are +`NullReporter`, a no-op reporter that does nothing, a `LoggingReporter` +which logs all finished spans using their `String()` method, and a +`CompositeReporter` that can be used to combine more than one reporter +into one, e.g. to attach a logging reporter to the main remote reporter. + +### Span Reporting Transports + +The remote reporter uses "transports" to actually send the spans out +of process. Currently the supported transports include: + * [Jaeger Thrift](https://github.com/jaegertracing/jaeger-idl/blob/master/thrift/agent.thrift) over UDP or HTTP, + * [Zipkin Thrift](https://github.com/jaegertracing/jaeger-idl/blob/master/thrift/zipkincore.thrift) over HTTP. + +### Sampling + +The tracer does not record all spans, but only those that have the +sampling bit set in the `flags`. When a new trace is started and a new +unique ID is generated, a sampling decision is made whether this trace +should be sampled. The sampling decision is propagated to all downstream +calls via the `flags` field of the trace context. The following samplers +are available: + 1. `RemotelyControlledSampler` uses one of the other simpler samplers + and periodically updates it by polling an external server. This + allows dynamic control of the sampling strategies. + 1. `ConstSampler` always makes the same sampling decision for all + trace IDs. it can be configured to either sample all traces, or + to sample none. + 1. `ProbabilisticSampler` uses a fixed sampling rate as a probability + for a given trace to be sampled. The actual decision is made by + comparing the trace ID with a random number multiplied by the + sampling rate. + 1. `RateLimitingSampler` can be used to allow only a certain fixed + number of traces to be sampled per second. + +### Baggage Injection + +The OpenTracing spec allows for [baggage][baggage], which are key value pairs that are added +to the span context and propagated throughout the trace. An external process can inject baggage +by setting the special HTTP Header `jaeger-baggage` on a request: + +```sh +curl -H "jaeger-baggage: key1=value1, key2=value2" http://myhost.com +``` + +Baggage can also be programatically set inside your service: + +```go +if span := opentracing.SpanFromContext(ctx); span != nil { + span.SetBaggageItem("key", "value") +} +``` + +Another service downstream of that can retrieve the baggage in a similar way: + +```go +if span := opentracing.SpanFromContext(ctx); span != nil { + val := span.BaggageItem("key") + println(val) +} +``` + +### Debug Traces (Forced Sampling) + +#### Programmatically + +The OpenTracing API defines a `sampling.priority` standard tag that +can be used to affect the sampling of a span and its children: + +```go +import ( + "github.com/opentracing/opentracing-go" + "github.com/opentracing/opentracing-go/ext" +) + +span := opentracing.SpanFromContext(ctx) +ext.SamplingPriority.Set(span, 1) +``` + +#### Via HTTP Headers + +Jaeger Tracer also understands a special HTTP Header `jaeger-debug-id`, +which can be set in the incoming request, e.g. + +```sh +curl -H "jaeger-debug-id: some-correlation-id" http://myhost.com +``` + +When Jaeger sees this header in the request that otherwise has no +tracing context, it ensures that the new trace started for this +request will be sampled in the "debug" mode (meaning it should survive +all downsampling that might happen in the collection pipeline), and the +root span will have a tag as if this statement was executed: + +```go +span.SetTag("jaeger-debug-id", "some-correlation-id") +``` + +This allows using Jaeger UI to find the trace by this tag. + +### Zipkin HTTP B3 compatible header propagation + +Jaeger Tracer supports Zipkin B3 Propagation HTTP headers, which are used +by a lot of Zipkin tracers. This means that you can use Jaeger in conjunction with e.g. [these OpenZipkin tracers](https://github.com/openzipkin). + +However it is not the default propagation format, see [here](zipkin/README.md#NewZipkinB3HTTPHeaderPropagator) how to set it up. + +## License + +[Apache 2.0 License](LICENSE). + + +[doc-img]: https://godoc.org/github.com/uber/jaeger-client-go?status.svg +[doc]: https://godoc.org/github.com/uber/jaeger-client-go +[ci-img]: https://travis-ci.org/jaegertracing/jaeger-client-go.svg?branch=master +[ci]: https://travis-ci.org/jaegertracing/jaeger-client-go +[cov-img]: https://codecov.io/gh/jaegertracing/jaeger-client-go/branch/master/graph/badge.svg +[cov]: https://codecov.io/gh/jaegertracing/jaeger-client-go +[ot-img]: https://img.shields.io/badge/OpenTracing--1.0-enabled-blue.svg +[ot-url]: http://opentracing.io +[baggage]: https://github.com/opentracing/specification/blob/master/specification.md#set-a-baggage-item diff --git a/vendor/github.com/uber/jaeger-client-go/RELEASE.md b/vendor/github.com/uber/jaeger-client-go/RELEASE.md new file mode 100644 index 0000000000..115e49ab8a --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/RELEASE.md @@ -0,0 +1,11 @@ +# Release Process + +1. Create a PR "Preparing for release X.Y.Z" against master branch + * Alter CHANGELOG.md from ` (unreleased)` to ` (YYYY-MM-DD)` + * Update `JaegerClientVersion` in constants.go to `Go-X.Y.Z` +2. Create a release "Release X.Y.Z" on Github + * Create Tag `vX.Y.Z` + * Copy CHANGELOG.md into the release notes +3. Create a PR "Back to development" against master branch + * Add ` (unreleased)` to CHANGELOG.md + * Update `JaegerClientVersion` in constants.go to `Go-dev` diff --git a/vendor/github.com/uber/jaeger-client-go/baggage_setter.go b/vendor/github.com/uber/jaeger-client-go/baggage_setter.go new file mode 100644 index 0000000000..1037ca0e86 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/baggage_setter.go @@ -0,0 +1,77 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 jaeger + +import ( + "github.com/opentracing/opentracing-go/log" + + "github.com/uber/jaeger-client-go/internal/baggage" +) + +// baggageSetter is an actor that can set a baggage value on a Span given certain +// restrictions (eg. maxValueLength). +type baggageSetter struct { + restrictionManager baggage.RestrictionManager + metrics *Metrics +} + +func newBaggageSetter(restrictionManager baggage.RestrictionManager, metrics *Metrics) *baggageSetter { + return &baggageSetter{ + restrictionManager: restrictionManager, + metrics: metrics, + } +} + +// (NB) span should hold the lock before making this call +func (s *baggageSetter) setBaggage(span *Span, key, value string) { + var truncated bool + var prevItem string + restriction := s.restrictionManager.GetRestriction(span.serviceName(), key) + if !restriction.KeyAllowed() { + s.logFields(span, key, value, prevItem, truncated, restriction.KeyAllowed()) + s.metrics.BaggageUpdateFailure.Inc(1) + return + } + if len(value) > restriction.MaxValueLength() { + truncated = true + value = value[:restriction.MaxValueLength()] + s.metrics.BaggageTruncate.Inc(1) + } + prevItem = span.context.baggage[key] + s.logFields(span, key, value, prevItem, truncated, restriction.KeyAllowed()) + span.context = span.context.WithBaggageItem(key, value) + s.metrics.BaggageUpdateSuccess.Inc(1) +} + +func (s *baggageSetter) logFields(span *Span, key, value, prevItem string, truncated, valid bool) { + if !span.context.IsSampled() { + return + } + fields := []log.Field{ + log.String("event", "baggage"), + log.String("key", key), + log.String("value", value), + } + if prevItem != "" { + fields = append(fields, log.String("override", "true")) + } + if truncated { + fields = append(fields, log.String("truncated", "true")) + } + if !valid { + fields = append(fields, log.String("invalid", "true")) + } + span.logFieldsNoLocking(fields...) +} diff --git a/vendor/github.com/uber/jaeger-client-go/config/config.go b/vendor/github.com/uber/jaeger-client-go/config/config.go new file mode 100644 index 0000000000..1eb2967785 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/config/config.go @@ -0,0 +1,373 @@ +// Copyright (c) 2017-2018 Uber Technologies, Inc. +// +// 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 config + +import ( + "errors" + "fmt" + "io" + "strings" + "time" + + "github.com/opentracing/opentracing-go" + + "github.com/uber/jaeger-client-go" + "github.com/uber/jaeger-client-go/internal/baggage/remote" + throttler "github.com/uber/jaeger-client-go/internal/throttler/remote" + "github.com/uber/jaeger-client-go/rpcmetrics" +) + +const defaultSamplingProbability = 0.001 + +// Configuration configures and creates Jaeger Tracer +type Configuration struct { + // ServiceName specifies the service name to use on the tracer. + // Can be provided via environment variable named JAEGER_SERVICE_NAME + ServiceName string `yaml:"serviceName"` + + // Disabled can be provided via environment variable named JAEGER_DISABLED + Disabled bool `yaml:"disabled"` + + // RPCMetrics can be provided via environment variable named JAEGER_RPC_METRICS + RPCMetrics bool `yaml:"rpc_metrics"` + + // Tags can be provided via environment variable named JAEGER_TAGS + Tags []opentracing.Tag `yaml:"tags"` + + Sampler *SamplerConfig `yaml:"sampler"` + Reporter *ReporterConfig `yaml:"reporter"` + Headers *jaeger.HeadersConfig `yaml:"headers"` + BaggageRestrictions *BaggageRestrictionsConfig `yaml:"baggage_restrictions"` + Throttler *ThrottlerConfig `yaml:"throttler"` +} + +// SamplerConfig allows initializing a non-default sampler. All fields are optional. +type SamplerConfig struct { + // Type specifies the type of the sampler: const, probabilistic, rateLimiting, or remote + // Can be set by exporting an environment variable named JAEGER_SAMPLER_TYPE + Type string `yaml:"type"` + + // Param is a value passed to the sampler. + // Valid values for Param field are: + // - for "const" sampler, 0 or 1 for always false/true respectively + // - for "probabilistic" sampler, a probability between 0 and 1 + // - for "rateLimiting" sampler, the number of spans per second + // - for "remote" sampler, param is the same as for "probabilistic" + // and indicates the initial sampling rate before the actual one + // is received from the mothership. + // Can be set by exporting an environment variable named JAEGER_SAMPLER_PARAM + Param float64 `yaml:"param"` + + // SamplingServerURL is the address of jaeger-agent's HTTP sampling server + // Can be set by exporting an environment variable named JAEGER_SAMPLER_MANAGER_HOST_PORT + SamplingServerURL string `yaml:"samplingServerURL"` + + // MaxOperations is the maximum number of operations that the sampler + // will keep track of. If an operation is not tracked, a default probabilistic + // sampler will be used rather than the per operation specific sampler. + // Can be set by exporting an environment variable named JAEGER_SAMPLER_MAX_OPERATIONS + MaxOperations int `yaml:"maxOperations"` + + // SamplingRefreshInterval controls how often the remotely controlled sampler will poll + // jaeger-agent for the appropriate sampling strategy. + // Can be set by exporting an environment variable named JAEGER_SAMPLER_REFRESH_INTERVAL + SamplingRefreshInterval time.Duration `yaml:"samplingRefreshInterval"` +} + +// ReporterConfig configures the reporter. All fields are optional. +type ReporterConfig struct { + // QueueSize controls how many spans the reporter can keep in memory before it starts dropping + // new spans. The queue is continuously drained by a background go-routine, as fast as spans + // can be sent out of process. + // Can be set by exporting an environment variable named JAEGER_REPORTER_MAX_QUEUE_SIZE + QueueSize int `yaml:"queueSize"` + + // BufferFlushInterval controls how often the buffer is force-flushed, even if it's not full. + // It is generally not useful, as it only matters for very low traffic services. + // Can be set by exporting an environment variable named JAEGER_REPORTER_FLUSH_INTERVAL + BufferFlushInterval time.Duration + + // LogSpans, when true, enables LoggingReporter that runs in parallel with the main reporter + // and logs all submitted spans. Main Configuration.Logger must be initialized in the code + // for this option to have any effect. + // Can be set by exporting an environment variable named JAEGER_REPORTER_LOG_SPANS + LogSpans bool `yaml:"logSpans"` + + // LocalAgentHostPort instructs reporter to send spans to jaeger-agent at this address + // Can be set by exporting an environment variable named JAEGER_AGENT_HOST / JAEGER_AGENT_PORT + LocalAgentHostPort string `yaml:"localAgentHostPort"` +} + +// BaggageRestrictionsConfig configures the baggage restrictions manager which can be used to whitelist +// certain baggage keys. All fields are optional. +type BaggageRestrictionsConfig struct { + // DenyBaggageOnInitializationFailure controls the startup failure mode of the baggage restriction + // manager. If true, the manager will not allow any baggage to be written until baggage restrictions have + // been retrieved from jaeger-agent. If false, the manager wil allow any baggage to be written until baggage + // restrictions have been retrieved from jaeger-agent. + DenyBaggageOnInitializationFailure bool `yaml:"denyBaggageOnInitializationFailure"` + + // HostPort is the hostPort of jaeger-agent's baggage restrictions server + HostPort string `yaml:"hostPort"` + + // RefreshInterval controls how often the baggage restriction manager will poll + // jaeger-agent for the most recent baggage restrictions. + RefreshInterval time.Duration `yaml:"refreshInterval"` +} + +// ThrottlerConfig configures the throttler which can be used to throttle the +// rate at which the client may send debug requests. +type ThrottlerConfig struct { + // HostPort of jaeger-agent's credit server. + HostPort string `yaml:"hostPort"` + + // RefreshInterval controls how often the throttler will poll jaeger-agent + // for more throttling credits. + RefreshInterval time.Duration `yaml:"refreshInterval"` + + // SynchronousInitialization determines whether or not the throttler should + // synchronously fetch credits from the agent when an operation is seen for + // the first time. This should be set to true if the client will be used by + // a short lived service that needs to ensure that credits are fetched + // upfront such that sampling or throttling occurs. + SynchronousInitialization bool `yaml:"synchronousInitialization"` +} + +type nullCloser struct{} + +func (*nullCloser) Close() error { return nil } + +// New creates a new Jaeger Tracer, and a closer func that can be used to flush buffers +// before shutdown. +// +// Deprecated: use NewTracer() function +func (c Configuration) New( + serviceName string, + options ...Option, +) (opentracing.Tracer, io.Closer, error) { + if serviceName != "" { + c.ServiceName = serviceName + } + + return c.NewTracer(options...) +} + +// NewTracer returns a new tracer based on the current configuration, using the given options, +// and a closer func that can be used to flush buffers before shutdown. +func (c Configuration) NewTracer(options ...Option) (opentracing.Tracer, io.Closer, error) { + if c.ServiceName == "" { + return nil, nil, errors.New("no service name provided") + } + + if c.Disabled { + return &opentracing.NoopTracer{}, &nullCloser{}, nil + } + opts := applyOptions(options...) + tracerMetrics := jaeger.NewMetrics(opts.metrics, nil) + if c.RPCMetrics { + Observer( + rpcmetrics.NewObserver( + opts.metrics.Namespace("jaeger-rpc", map[string]string{"component": "jaeger"}), + rpcmetrics.DefaultNameNormalizer, + ), + )(&opts) // adds to c.observers + } + if c.Sampler == nil { + c.Sampler = &SamplerConfig{ + Type: jaeger.SamplerTypeRemote, + Param: defaultSamplingProbability, + } + } + if c.Reporter == nil { + c.Reporter = &ReporterConfig{} + } + + sampler := opts.sampler + if sampler == nil { + s, err := c.Sampler.NewSampler(c.ServiceName, tracerMetrics) + if err != nil { + return nil, nil, err + } + sampler = s + } + + reporter := opts.reporter + if reporter == nil { + r, err := c.Reporter.NewReporter(c.ServiceName, tracerMetrics, opts.logger) + if err != nil { + return nil, nil, err + } + reporter = r + } + + tracerOptions := []jaeger.TracerOption{ + jaeger.TracerOptions.Metrics(tracerMetrics), + jaeger.TracerOptions.Logger(opts.logger), + jaeger.TracerOptions.CustomHeaderKeys(c.Headers), + jaeger.TracerOptions.Gen128Bit(opts.gen128Bit), + jaeger.TracerOptions.ZipkinSharedRPCSpan(opts.zipkinSharedRPCSpan), + jaeger.TracerOptions.MaxTagValueLength(opts.maxTagValueLength), + } + + for _, tag := range opts.tags { + tracerOptions = append(tracerOptions, jaeger.TracerOptions.Tag(tag.Key, tag.Value)) + } + + for _, tag := range c.Tags { + tracerOptions = append(tracerOptions, jaeger.TracerOptions.Tag(tag.Key, tag.Value)) + } + + for _, obs := range opts.observers { + tracerOptions = append(tracerOptions, jaeger.TracerOptions.Observer(obs)) + } + + for _, cobs := range opts.contribObservers { + tracerOptions = append(tracerOptions, jaeger.TracerOptions.ContribObserver(cobs)) + } + + for format, injector := range opts.injectors { + tracerOptions = append(tracerOptions, jaeger.TracerOptions.Injector(format, injector)) + } + + for format, extractor := range opts.extractors { + tracerOptions = append(tracerOptions, jaeger.TracerOptions.Extractor(format, extractor)) + } + + if c.BaggageRestrictions != nil { + mgr := remote.NewRestrictionManager( + c.ServiceName, + remote.Options.Metrics(tracerMetrics), + remote.Options.Logger(opts.logger), + remote.Options.HostPort(c.BaggageRestrictions.HostPort), + remote.Options.RefreshInterval(c.BaggageRestrictions.RefreshInterval), + remote.Options.DenyBaggageOnInitializationFailure( + c.BaggageRestrictions.DenyBaggageOnInitializationFailure, + ), + ) + tracerOptions = append(tracerOptions, jaeger.TracerOptions.BaggageRestrictionManager(mgr)) + } + + if c.Throttler != nil { + debugThrottler := throttler.NewThrottler( + c.ServiceName, + throttler.Options.Metrics(tracerMetrics), + throttler.Options.Logger(opts.logger), + throttler.Options.HostPort(c.Throttler.HostPort), + throttler.Options.RefreshInterval(c.Throttler.RefreshInterval), + throttler.Options.SynchronousInitialization( + c.Throttler.SynchronousInitialization, + ), + ) + + tracerOptions = append(tracerOptions, jaeger.TracerOptions.DebugThrottler(debugThrottler)) + } + + tracer, closer := jaeger.NewTracer( + c.ServiceName, + sampler, + reporter, + tracerOptions..., + ) + + return tracer, closer, nil +} + +// InitGlobalTracer creates a new Jaeger Tracer, and sets it as global OpenTracing Tracer. +// It returns a closer func that can be used to flush buffers before shutdown. +func (c Configuration) InitGlobalTracer( + serviceName string, + options ...Option, +) (io.Closer, error) { + if c.Disabled { + return &nullCloser{}, nil + } + tracer, closer, err := c.New(serviceName, options...) + if err != nil { + return nil, err + } + opentracing.SetGlobalTracer(tracer) + return closer, nil +} + +// NewSampler creates a new sampler based on the configuration +func (sc *SamplerConfig) NewSampler( + serviceName string, + metrics *jaeger.Metrics, +) (jaeger.Sampler, error) { + samplerType := strings.ToLower(sc.Type) + if samplerType == jaeger.SamplerTypeConst { + return jaeger.NewConstSampler(sc.Param != 0), nil + } + if samplerType == jaeger.SamplerTypeProbabilistic { + if sc.Param >= 0 && sc.Param <= 1.0 { + return jaeger.NewProbabilisticSampler(sc.Param) + } + return nil, fmt.Errorf( + "Invalid Param for probabilistic sampler: %v. Expecting value between 0 and 1", + sc.Param, + ) + } + if samplerType == jaeger.SamplerTypeRateLimiting { + return jaeger.NewRateLimitingSampler(sc.Param), nil + } + if samplerType == jaeger.SamplerTypeRemote || sc.Type == "" { + sc2 := *sc + sc2.Type = jaeger.SamplerTypeProbabilistic + initSampler, err := sc2.NewSampler(serviceName, nil) + if err != nil { + return nil, err + } + options := []jaeger.SamplerOption{ + jaeger.SamplerOptions.Metrics(metrics), + jaeger.SamplerOptions.InitialSampler(initSampler), + jaeger.SamplerOptions.SamplingServerURL(sc.SamplingServerURL), + } + if sc.MaxOperations != 0 { + options = append(options, jaeger.SamplerOptions.MaxOperations(sc.MaxOperations)) + } + if sc.SamplingRefreshInterval != 0 { + options = append(options, jaeger.SamplerOptions.SamplingRefreshInterval(sc.SamplingRefreshInterval)) + } + return jaeger.NewRemotelyControlledSampler(serviceName, options...), nil + } + return nil, fmt.Errorf("Unknown sampler type %v", sc.Type) +} + +// NewReporter instantiates a new reporter that submits spans to tcollector +func (rc *ReporterConfig) NewReporter( + serviceName string, + metrics *jaeger.Metrics, + logger jaeger.Logger, +) (jaeger.Reporter, error) { + sender, err := rc.newTransport() + if err != nil { + return nil, err + } + reporter := jaeger.NewRemoteReporter( + sender, + jaeger.ReporterOptions.QueueSize(rc.QueueSize), + jaeger.ReporterOptions.BufferFlushInterval(rc.BufferFlushInterval), + jaeger.ReporterOptions.Logger(logger), + jaeger.ReporterOptions.Metrics(metrics)) + if rc.LogSpans && logger != nil { + logger.Infof("Initializing logging reporter\n") + reporter = jaeger.NewCompositeReporter(jaeger.NewLoggingReporter(logger), reporter) + } + return reporter, err +} + +func (rc *ReporterConfig) newTransport() (jaeger.Transport, error) { + return jaeger.NewUDPTransport(rc.LocalAgentHostPort, 0) +} diff --git a/vendor/github.com/uber/jaeger-client-go/config/config_env.go b/vendor/github.com/uber/jaeger-client-go/config/config_env.go new file mode 100644 index 0000000000..96f170c539 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/config/config_env.go @@ -0,0 +1,205 @@ +// Copyright (c) 2018 The Jaeger Authors. +// +// 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 config + +import ( + "fmt" + "os" + "strconv" + "strings" + "time" + + opentracing "github.com/opentracing/opentracing-go" + "github.com/pkg/errors" + + "github.com/uber/jaeger-client-go" +) + +const ( + // environment variable names + envServiceName = "JAEGER_SERVICE_NAME" + envDisabled = "JAEGER_DISABLED" + envRPCMetrics = "JAEGER_RPC_METRICS" + envTags = "JAEGER_TAGS" + envSamplerType = "JAEGER_SAMPLER_TYPE" + envSamplerParam = "JAEGER_SAMPLER_PARAM" + envSamplerManagerHostPort = "JAEGER_SAMPLER_MANAGER_HOST_PORT" + envSamplerMaxOperations = "JAEGER_SAMPLER_MAX_OPERATIONS" + envSamplerRefreshInterval = "JAEGER_SAMPLER_REFRESH_INTERVAL" + envReporterMaxQueueSize = "JAEGER_REPORTER_MAX_QUEUE_SIZE" + envReporterFlushInterval = "JAEGER_REPORTER_FLUSH_INTERVAL" + envReporterLogSpans = "JAEGER_REPORTER_LOG_SPANS" + envAgentHost = "JAEGER_AGENT_HOST" + envAgentPort = "JAEGER_AGENT_PORT" +) + +// FromEnv uses environment variables to set the tracer's Configuration +func FromEnv() (*Configuration, error) { + c := &Configuration{} + + if e := os.Getenv(envServiceName); e != "" { + c.ServiceName = e + } + + if e := os.Getenv(envRPCMetrics); e != "" { + if value, err := strconv.ParseBool(e); err == nil { + c.RPCMetrics = value + } else { + return nil, errors.Wrapf(err, "cannot parse env var %s=%s", envRPCMetrics, e) + } + } + + if e := os.Getenv(envDisabled); e != "" { + if value, err := strconv.ParseBool(e); err == nil { + c.Disabled = value + } else { + return nil, errors.Wrapf(err, "cannot parse env var %s=%s", envDisabled, e) + } + } + + if e := os.Getenv(envTags); e != "" { + c.Tags = parseTags(e) + } + + if s, err := samplerConfigFromEnv(); err == nil { + c.Sampler = s + } else { + return nil, errors.Wrap(err, "cannot obtain sampler config from env") + } + + if r, err := reporterConfigFromEnv(); err == nil { + c.Reporter = r + } else { + return nil, errors.Wrap(err, "cannot obtain reporter config from env") + } + + return c, nil +} + +// samplerConfigFromEnv creates a new SamplerConfig based on the environment variables +func samplerConfigFromEnv() (*SamplerConfig, error) { + sc := &SamplerConfig{} + + if e := os.Getenv(envSamplerType); e != "" { + sc.Type = e + } + + if e := os.Getenv(envSamplerParam); e != "" { + if value, err := strconv.ParseFloat(e, 64); err == nil { + sc.Param = value + } else { + return nil, errors.Wrapf(err, "cannot parse env var %s=%s", envSamplerParam, e) + } + } + + if e := os.Getenv(envSamplerManagerHostPort); e != "" { + sc.SamplingServerURL = e + } + + if e := os.Getenv(envSamplerMaxOperations); e != "" { + if value, err := strconv.ParseInt(e, 10, 0); err == nil { + sc.MaxOperations = int(value) + } else { + return nil, errors.Wrapf(err, "cannot parse env var %s=%s", envSamplerMaxOperations, e) + } + } + + if e := os.Getenv(envSamplerRefreshInterval); e != "" { + if value, err := time.ParseDuration(e); err == nil { + sc.SamplingRefreshInterval = value + } else { + return nil, errors.Wrapf(err, "cannot parse env var %s=%s", envSamplerRefreshInterval, e) + } + } + + return sc, nil +} + +// reporterConfigFromEnv creates a new ReporterConfig based on the environment variables +func reporterConfigFromEnv() (*ReporterConfig, error) { + rc := &ReporterConfig{} + + if e := os.Getenv(envReporterMaxQueueSize); e != "" { + if value, err := strconv.ParseInt(e, 10, 0); err == nil { + rc.QueueSize = int(value) + } else { + return nil, errors.Wrapf(err, "cannot parse env var %s=%s", envReporterMaxQueueSize, e) + } + } + + if e := os.Getenv(envReporterFlushInterval); e != "" { + if value, err := time.ParseDuration(e); err == nil { + rc.BufferFlushInterval = value + } else { + return nil, errors.Wrapf(err, "cannot parse env var %s=%s", envReporterFlushInterval, e) + } + } + + if e := os.Getenv(envReporterLogSpans); e != "" { + if value, err := strconv.ParseBool(e); err == nil { + rc.LogSpans = value + } else { + return nil, errors.Wrapf(err, "cannot parse env var %s=%s", envReporterLogSpans, e) + } + } + + host := jaeger.DefaultUDPSpanServerHost + if e := os.Getenv(envAgentHost); e != "" { + host = e + } + + port := jaeger.DefaultUDPSpanServerPort + if e := os.Getenv(envAgentPort); e != "" { + if value, err := strconv.ParseInt(e, 10, 0); err == nil { + port = int(value) + } else { + return nil, errors.Wrapf(err, "cannot parse env var %s=%s", envAgentPort, e) + } + } + + // the side effect of this is that we are building the default value, even if none of the env vars + // were not explicitly passed + rc.LocalAgentHostPort = fmt.Sprintf("%s:%d", host, port) + + return rc, nil +} + +// parseTags parses the given string into a collection of Tags. +// Spec for this value: +// - comma separated list of key=value +// - value can be specified using the notation ${envVar:defaultValue}, where `envVar` +// is an environment variable and `defaultValue` is the value to use in case the env var is not set +func parseTags(sTags string) []opentracing.Tag { + pairs := strings.Split(sTags, ",") + tags := make([]opentracing.Tag, 0) + for _, p := range pairs { + kv := strings.SplitN(p, "=", 2) + k, v := strings.TrimSpace(kv[0]), strings.TrimSpace(kv[1]) + + if strings.HasPrefix(v, "${") && strings.HasSuffix(v, "}") { + ed := strings.SplitN(v[2:len(v)-1], ":", 2) + e, d := ed[0], ed[1] + v = os.Getenv(e) + if v == "" && d != "" { + v = d + } + } + + tag := opentracing.Tag{Key: k, Value: v} + tags = append(tags, tag) + } + + return tags +} diff --git a/vendor/github.com/uber/jaeger-client-go/config/options.go b/vendor/github.com/uber/jaeger-client-go/config/options.go new file mode 100644 index 0000000000..d14f1f8a9b --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/config/options.go @@ -0,0 +1,148 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 config + +import ( + opentracing "github.com/opentracing/opentracing-go" + "github.com/uber/jaeger-lib/metrics" + + "github.com/uber/jaeger-client-go" +) + +// Option is a function that sets some option on the client. +type Option func(c *Options) + +// Options control behavior of the client. +type Options struct { + metrics metrics.Factory + logger jaeger.Logger + reporter jaeger.Reporter + sampler jaeger.Sampler + contribObservers []jaeger.ContribObserver + observers []jaeger.Observer + gen128Bit bool + zipkinSharedRPCSpan bool + maxTagValueLength int + tags []opentracing.Tag + injectors map[interface{}]jaeger.Injector + extractors map[interface{}]jaeger.Extractor +} + +// Metrics creates an Option that initializes Metrics in the tracer, +// which is used to emit statistics about spans. +func Metrics(factory metrics.Factory) Option { + return func(c *Options) { + c.metrics = factory + } +} + +// Logger can be provided to log Reporter errors, as well as to log spans +// if Reporter.LogSpans is set to true. +func Logger(logger jaeger.Logger) Option { + return func(c *Options) { + c.logger = logger + } +} + +// Reporter can be provided explicitly to override the configuration. +// Useful for testing, e.g. by passing InMemoryReporter. +func Reporter(reporter jaeger.Reporter) Option { + return func(c *Options) { + c.reporter = reporter + } +} + +// Sampler can be provided explicitly to override the configuration. +func Sampler(sampler jaeger.Sampler) Option { + return func(c *Options) { + c.sampler = sampler + } +} + +// Observer can be registered with the Tracer to receive notifications about new Spans. +func Observer(observer jaeger.Observer) Option { + return func(c *Options) { + c.observers = append(c.observers, observer) + } +} + +// ContribObserver can be registered with the Tracer to recieve notifications +// about new spans. +func ContribObserver(observer jaeger.ContribObserver) Option { + return func(c *Options) { + c.contribObservers = append(c.contribObservers, observer) + } +} + +// Gen128Bit specifies whether to generate 128bit trace IDs. +func Gen128Bit(gen128Bit bool) Option { + return func(c *Options) { + c.gen128Bit = gen128Bit + } +} + +// ZipkinSharedRPCSpan creates an option that enables sharing span ID between client +// and server spans a la zipkin. If false, client and server spans will be assigned +// different IDs. +func ZipkinSharedRPCSpan(zipkinSharedRPCSpan bool) Option { + return func(c *Options) { + c.zipkinSharedRPCSpan = zipkinSharedRPCSpan + } +} + +// MaxTagValueLength can be provided to override the default max tag value length. +func MaxTagValueLength(maxTagValueLength int) Option { + return func(c *Options) { + c.maxTagValueLength = maxTagValueLength + } +} + +// Tag creates an option that adds a tracer-level tag. +func Tag(key string, value interface{}) Option { + return func(c *Options) { + c.tags = append(c.tags, opentracing.Tag{Key: key, Value: value}) + } +} + +// Injector registers an Injector with the given format. +func Injector(format interface{}, injector jaeger.Injector) Option { + return func(c *Options) { + c.injectors[format] = injector + } +} + +// Extractor registers an Extractor with the given format. +func Extractor(format interface{}, extractor jaeger.Extractor) Option { + return func(c *Options) { + c.extractors[format] = extractor + } +} + +func applyOptions(options ...Option) Options { + opts := Options{ + injectors: make(map[interface{}]jaeger.Injector), + extractors: make(map[interface{}]jaeger.Extractor), + } + for _, option := range options { + option(&opts) + } + if opts.metrics == nil { + opts.metrics = metrics.NullFactory + } + if opts.logger == nil { + opts.logger = jaeger.NullLogger + } + return opts +} diff --git a/vendor/github.com/uber/jaeger-client-go/constants.go b/vendor/github.com/uber/jaeger-client-go/constants.go new file mode 100644 index 0000000000..b5368ff381 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/constants.go @@ -0,0 +1,88 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 jaeger + +const ( + // JaegerClientVersion is the version of the client library reported as Span tag. + JaegerClientVersion = "Go-2.15.0-dev" + + // JaegerClientVersionTagKey is the name of the tag used to report client version. + JaegerClientVersionTagKey = "jaeger.version" + + // JaegerDebugHeader is the name of HTTP header or a TextMap carrier key which, + // if found in the carrier, forces the trace to be sampled as "debug" trace. + // The value of the header is recorded as the tag on the root span, so that the + // trace can be found in the UI using this value as a correlation ID. + JaegerDebugHeader = "jaeger-debug-id" + + // JaegerBaggageHeader is the name of the HTTP header that is used to submit baggage. + // It differs from TraceBaggageHeaderPrefix in that it can be used only in cases where + // a root span does not exist. + JaegerBaggageHeader = "jaeger-baggage" + + // TracerHostnameTagKey used to report host name of the process. + TracerHostnameTagKey = "hostname" + + // TracerIPTagKey used to report ip of the process. + TracerIPTagKey = "ip" + + // TracerUUIDTagKey used to report UUID of the client process. + TracerUUIDTagKey = "client-uuid" + + // SamplerTypeTagKey reports which sampler was used on the root span. + SamplerTypeTagKey = "sampler.type" + + // SamplerParamTagKey reports the parameter of the sampler, like sampling probability. + SamplerParamTagKey = "sampler.param" + + // TraceContextHeaderName is the http header name used to propagate tracing context. + // This must be in lower-case to avoid mismatches when decoding incoming headers. + TraceContextHeaderName = "uber-trace-id" + + // TracerStateHeaderName is deprecated. + // Deprecated: use TraceContextHeaderName + TracerStateHeaderName = TraceContextHeaderName + + // TraceBaggageHeaderPrefix is the prefix for http headers used to propagate baggage. + // This must be in lower-case to avoid mismatches when decoding incoming headers. + TraceBaggageHeaderPrefix = "uberctx-" + + // SamplerTypeConst is the type of sampler that always makes the same decision. + SamplerTypeConst = "const" + + // SamplerTypeRemote is the type of sampler that polls Jaeger agent for sampling strategy. + SamplerTypeRemote = "remote" + + // SamplerTypeProbabilistic is the type of sampler that samples traces + // with a certain fixed probability. + SamplerTypeProbabilistic = "probabilistic" + + // SamplerTypeRateLimiting is the type of sampler that samples + // only up to a fixed number of traces per second. + SamplerTypeRateLimiting = "ratelimiting" + + // SamplerTypeLowerBound is the type of sampler that samples + // at least a fixed number of traces per second. + SamplerTypeLowerBound = "lowerbound" + + // DefaultUDPSpanServerHost is the default host to send the spans to, via UDP + DefaultUDPSpanServerHost = "localhost" + + // DefaultUDPSpanServerPort is the default port to send the spans to, via UDP + DefaultUDPSpanServerPort = 6831 + + // DefaultMaxTagValueLength is the default max length of byte array or string allowed in the tag value. + DefaultMaxTagValueLength = 256 +) diff --git a/vendor/github.com/uber/jaeger-client-go/context.go b/vendor/github.com/uber/jaeger-client-go/context.go new file mode 100644 index 0000000000..8b06173d98 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/context.go @@ -0,0 +1,258 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 jaeger + +import ( + "errors" + "fmt" + "strconv" + "strings" +) + +const ( + flagSampled = byte(1) + flagDebug = byte(2) +) + +var ( + errEmptyTracerStateString = errors.New("Cannot convert empty string to tracer state") + errMalformedTracerStateString = errors.New("String does not match tracer state format") + + emptyContext = SpanContext{} +) + +// TraceID represents unique 128bit identifier of a trace +type TraceID struct { + High, Low uint64 +} + +// SpanID represents unique 64bit identifier of a span +type SpanID uint64 + +// SpanContext represents propagated span identity and state +type SpanContext struct { + // traceID represents globally unique ID of the trace. + // Usually generated as a random number. + traceID TraceID + + // spanID represents span ID that must be unique within its trace, + // but does not have to be globally unique. + spanID SpanID + + // parentID refers to the ID of the parent span. + // Should be 0 if the current span is a root span. + parentID SpanID + + // flags is a bitmap containing such bits as 'sampled' and 'debug'. + flags byte + + // Distributed Context baggage. The is a snapshot in time. + baggage map[string]string + + // debugID can be set to some correlation ID when the context is being + // extracted from a TextMap carrier. + // + // See JaegerDebugHeader in constants.go + debugID string +} + +// ForeachBaggageItem implements ForeachBaggageItem() of opentracing.SpanContext +func (c SpanContext) ForeachBaggageItem(handler func(k, v string) bool) { + for k, v := range c.baggage { + if !handler(k, v) { + break + } + } +} + +// IsSampled returns whether this trace was chosen for permanent storage +// by the sampling mechanism of the tracer. +func (c SpanContext) IsSampled() bool { + return (c.flags & flagSampled) == flagSampled +} + +// IsDebug indicates whether sampling was explicitly requested by the service. +func (c SpanContext) IsDebug() bool { + return (c.flags & flagDebug) == flagDebug +} + +// IsValid indicates whether this context actually represents a valid trace. +func (c SpanContext) IsValid() bool { + return c.traceID.IsValid() && c.spanID != 0 +} + +func (c SpanContext) String() string { + if c.traceID.High == 0 { + return fmt.Sprintf("%x:%x:%x:%x", c.traceID.Low, uint64(c.spanID), uint64(c.parentID), c.flags) + } + return fmt.Sprintf("%x%016x:%x:%x:%x", c.traceID.High, c.traceID.Low, uint64(c.spanID), uint64(c.parentID), c.flags) +} + +// ContextFromString reconstructs the Context encoded in a string +func ContextFromString(value string) (SpanContext, error) { + var context SpanContext + if value == "" { + return emptyContext, errEmptyTracerStateString + } + parts := strings.Split(value, ":") + if len(parts) != 4 { + return emptyContext, errMalformedTracerStateString + } + var err error + if context.traceID, err = TraceIDFromString(parts[0]); err != nil { + return emptyContext, err + } + if context.spanID, err = SpanIDFromString(parts[1]); err != nil { + return emptyContext, err + } + if context.parentID, err = SpanIDFromString(parts[2]); err != nil { + return emptyContext, err + } + flags, err := strconv.ParseUint(parts[3], 10, 8) + if err != nil { + return emptyContext, err + } + context.flags = byte(flags) + return context, nil +} + +// TraceID returns the trace ID of this span context +func (c SpanContext) TraceID() TraceID { + return c.traceID +} + +// SpanID returns the span ID of this span context +func (c SpanContext) SpanID() SpanID { + return c.spanID +} + +// ParentID returns the parent span ID of this span context +func (c SpanContext) ParentID() SpanID { + return c.parentID +} + +// NewSpanContext creates a new instance of SpanContext +func NewSpanContext(traceID TraceID, spanID, parentID SpanID, sampled bool, baggage map[string]string) SpanContext { + flags := byte(0) + if sampled { + flags = flagSampled + } + return SpanContext{ + traceID: traceID, + spanID: spanID, + parentID: parentID, + flags: flags, + baggage: baggage} +} + +// CopyFrom copies data from ctx into this context, including span identity and baggage. +// TODO This is only used by interop.go. Remove once TChannel Go supports OpenTracing. +func (c *SpanContext) CopyFrom(ctx *SpanContext) { + c.traceID = ctx.traceID + c.spanID = ctx.spanID + c.parentID = ctx.parentID + c.flags = ctx.flags + if l := len(ctx.baggage); l > 0 { + c.baggage = make(map[string]string, l) + for k, v := range ctx.baggage { + c.baggage[k] = v + } + } else { + c.baggage = nil + } +} + +// WithBaggageItem creates a new context with an extra baggage item. +func (c SpanContext) WithBaggageItem(key, value string) SpanContext { + var newBaggage map[string]string + if c.baggage == nil { + newBaggage = map[string]string{key: value} + } else { + newBaggage = make(map[string]string, len(c.baggage)+1) + for k, v := range c.baggage { + newBaggage[k] = v + } + newBaggage[key] = value + } + // Use positional parameters so the compiler will help catch new fields. + return SpanContext{c.traceID, c.spanID, c.parentID, c.flags, newBaggage, ""} +} + +// isDebugIDContainerOnly returns true when the instance of the context is only +// used to return the debug/correlation ID from extract() method. This happens +// in the situation when "jaeger-debug-id" header is passed in the carrier to +// the extract() method, but the request otherwise has no span context in it. +// Previously this would've returned opentracing.ErrSpanContextNotFound from the +// extract method, but now it returns a dummy context with only debugID filled in. +// +// See JaegerDebugHeader in constants.go +// See textMapPropagator#Extract +func (c *SpanContext) isDebugIDContainerOnly() bool { + return !c.traceID.IsValid() && c.debugID != "" +} + +// ------- TraceID ------- + +func (t TraceID) String() string { + if t.High == 0 { + return fmt.Sprintf("%x", t.Low) + } + return fmt.Sprintf("%x%016x", t.High, t.Low) +} + +// TraceIDFromString creates a TraceID from a hexadecimal string +func TraceIDFromString(s string) (TraceID, error) { + var hi, lo uint64 + var err error + if len(s) > 32 { + return TraceID{}, fmt.Errorf("TraceID cannot be longer than 32 hex characters: %s", s) + } else if len(s) > 16 { + hiLen := len(s) - 16 + if hi, err = strconv.ParseUint(s[0:hiLen], 16, 64); err != nil { + return TraceID{}, err + } + if lo, err = strconv.ParseUint(s[hiLen:], 16, 64); err != nil { + return TraceID{}, err + } + } else { + if lo, err = strconv.ParseUint(s, 16, 64); err != nil { + return TraceID{}, err + } + } + return TraceID{High: hi, Low: lo}, nil +} + +// IsValid checks if the trace ID is valid, i.e. not zero. +func (t TraceID) IsValid() bool { + return t.High != 0 || t.Low != 0 +} + +// ------- SpanID ------- + +func (s SpanID) String() string { + return fmt.Sprintf("%x", uint64(s)) +} + +// SpanIDFromString creates a SpanID from a hexadecimal string +func SpanIDFromString(s string) (SpanID, error) { + if len(s) > 16 { + return SpanID(0), fmt.Errorf("SpanID cannot be longer than 16 hex characters: %s", s) + } + id, err := strconv.ParseUint(s, 16, 64) + if err != nil { + return SpanID(0), err + } + return SpanID(id), nil +} diff --git a/vendor/github.com/uber/jaeger-client-go/contrib_observer.go b/vendor/github.com/uber/jaeger-client-go/contrib_observer.go new file mode 100644 index 0000000000..4ce1881f3b --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/contrib_observer.go @@ -0,0 +1,56 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 jaeger + +import ( + opentracing "github.com/opentracing/opentracing-go" +) + +// ContribObserver can be registered with the Tracer to receive notifications +// about new Spans. Modelled after github.com/opentracing-contrib/go-observer. +type ContribObserver interface { + // Create and return a span observer. Called when a span starts. + // If the Observer is not interested in the given span, it must return (nil, false). + // E.g : + // func StartSpan(opName string, opts ...opentracing.StartSpanOption) { + // var sp opentracing.Span + // sso := opentracing.StartSpanOptions{} + // if spanObserver, ok := Observer.OnStartSpan(span, opName, sso); ok { + // // we have a valid SpanObserver + // } + // ... + // } + OnStartSpan(sp opentracing.Span, operationName string, options opentracing.StartSpanOptions) (ContribSpanObserver, bool) +} + +// ContribSpanObserver is created by the Observer and receives notifications +// about other Span events. This interface is meant to match +// github.com/opentracing-contrib/go-observer, via duck typing, without +// directly importing the go-observer package. +type ContribSpanObserver interface { + OnSetOperationName(operationName string) + OnSetTag(key string, value interface{}) + OnFinish(options opentracing.FinishOptions) +} + +// wrapper observer for the old observers (see observer.go) +type oldObserver struct { + obs Observer +} + +func (o *oldObserver) OnStartSpan(sp opentracing.Span, operationName string, options opentracing.StartSpanOptions) (ContribSpanObserver, bool) { + spanObserver := o.obs.OnStartSpan(operationName, options) + return spanObserver, spanObserver != nil +} diff --git a/vendor/github.com/uber/jaeger-client-go/doc.go b/vendor/github.com/uber/jaeger-client-go/doc.go new file mode 100644 index 0000000000..4f5549033d --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/doc.go @@ -0,0 +1,24 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 jaeger implements an OpenTracing (http://opentracing.io) Tracer. +It is currently using Zipkin-compatible data model and can be directly +itegrated with Zipkin backend (http://zipkin.io). + +For integration instructions please refer to the README: + +https://github.com/uber/jaeger-client-go/blob/master/README.md +*/ +package jaeger diff --git a/vendor/github.com/uber/jaeger-client-go/glide.lock b/vendor/github.com/uber/jaeger-client-go/glide.lock new file mode 100644 index 0000000000..d76b153617 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/glide.lock @@ -0,0 +1,89 @@ +hash: 3accf84f97bff4a91162736104c0e9b9790820712bd86db6fec5e665f7196a82 +updated: 2018-04-30T11:46:43.804556-04:00 +imports: +- name: github.com/beorn7/perks + version: 3a771d992973f24aa725d07868b467d1ddfceafb + subpackages: + - quantile +- name: github.com/codahale/hdrhistogram + version: 3a0bb77429bd3a61596f5e8a3172445844342120 +- name: github.com/crossdock/crossdock-go + version: 049aabb0122b03bc9bd30cab8f3f91fb60166361 + subpackages: + - assert + - require +- name: github.com/davecgh/go-spew + version: 8991bc29aa16c548c550c7ff78260e27b9ab7c73 + subpackages: + - spew +- name: github.com/golang/protobuf + version: bbd03ef6da3a115852eaf24c8a1c46aeb39aa175 + subpackages: + - proto +- name: github.com/matttproud/golang_protobuf_extensions + version: c12348ce28de40eed0136aa2b644d0ee0650e56c + subpackages: + - pbutil +- name: github.com/opentracing/opentracing-go + version: 1949ddbfd147afd4d964a9f00b24eb291e0e7c38 + subpackages: + - ext + - log +- name: github.com/pkg/errors + version: 645ef00459ed84a119197bfb8d8205042c6df63d +- name: github.com/pmezard/go-difflib + version: 792786c7400a136282c1664665ae0a8db921c6c2 + subpackages: + - difflib +- name: github.com/prometheus/client_golang + version: c5b7fccd204277076155f10851dad72b76a49317 + subpackages: + - prometheus +- name: github.com/prometheus/client_model + version: 99fa1f4be8e564e8a6b613da7fa6f46c9edafc6c + subpackages: + - go +- name: github.com/prometheus/common + version: 38c53a9f4bfcd932d1b00bfc65e256a7fba6b37a + subpackages: + - expfmt + - internal/bitbucket.org/ww/goautoneg + - model +- name: github.com/prometheus/procfs + version: 780932d4fbbe0e69b84c34c20f5c8d0981e109ea + subpackages: + - internal/util + - nfs + - xfs +- name: github.com/stretchr/testify + version: 12b6f73e6084dad08a7c6e575284b177ecafbc71 + subpackages: + - assert + - require + - suite +- name: github.com/uber/jaeger-lib + version: 4267858c0679cd4e47cefed8d7f70fd386cfb567 + subpackages: + - metrics + - metrics/prometheus + - metrics/testutils +- name: go.uber.org/atomic + version: 8474b86a5a6f79c443ce4b2992817ff32cf208b8 +- name: go.uber.org/multierr + version: 3c4937480c32f4c13a875a1829af76c98ca3d40a +- name: go.uber.org/zap + version: eeedf312bc6c57391d84767a4cd413f02a917974 + subpackages: + - buffer + - internal/bufferpool + - internal/color + - internal/exit + - zapcore +- name: golang.org/x/net + version: 6078986fec03a1dcc236c34816c71b0e05018fda + subpackages: + - context + - context/ctxhttp +testImports: +- name: github.com/uber-go/atomic + version: 8474b86a5a6f79c443ce4b2992817ff32cf208b8 diff --git a/vendor/github.com/uber/jaeger-client-go/glide.yaml b/vendor/github.com/uber/jaeger-client-go/glide.yaml new file mode 100644 index 0000000000..6637da2152 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/glide.yaml @@ -0,0 +1,22 @@ +package: github.com/uber/jaeger-client-go +import: +- package: github.com/opentracing/opentracing-go + version: ^1 + subpackages: + - ext + - log +- package: github.com/crossdock/crossdock-go +- package: github.com/uber/jaeger-lib + version: ^1.2.1 + subpackages: + - metrics +- package: github.com/pkg/errors + version: ~0.8.0 +testImport: +- package: github.com/stretchr/testify + subpackages: + - assert + - require + - suite +- package: github.com/prometheus/client_golang + version: v0.8.0 diff --git a/vendor/github.com/uber/jaeger-client-go/header.go b/vendor/github.com/uber/jaeger-client-go/header.go new file mode 100644 index 0000000000..19c2c055b8 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/header.go @@ -0,0 +1,64 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 jaeger + +// HeadersConfig contains the values for the header keys that Jaeger will use. +// These values may be either custom or default depending on whether custom +// values were provided via a configuration. +type HeadersConfig struct { + // JaegerDebugHeader is the name of HTTP header or a TextMap carrier key which, + // if found in the carrier, forces the trace to be sampled as "debug" trace. + // The value of the header is recorded as the tag on the root span, so that the + // trace can be found in the UI using this value as a correlation ID. + JaegerDebugHeader string `yaml:"jaegerDebugHeader"` + + // JaegerBaggageHeader is the name of the HTTP header that is used to submit baggage. + // It differs from TraceBaggageHeaderPrefix in that it can be used only in cases where + // a root span does not exist. + JaegerBaggageHeader string `yaml:"jaegerBaggageHeader"` + + // TraceContextHeaderName is the http header name used to propagate tracing context. + // This must be in lower-case to avoid mismatches when decoding incoming headers. + TraceContextHeaderName string `yaml:"TraceContextHeaderName"` + + // TraceBaggageHeaderPrefix is the prefix for http headers used to propagate baggage. + // This must be in lower-case to avoid mismatches when decoding incoming headers. + TraceBaggageHeaderPrefix string `yaml:"traceBaggageHeaderPrefix"` +} + +func (c *HeadersConfig) applyDefaults() *HeadersConfig { + if c.JaegerBaggageHeader == "" { + c.JaegerBaggageHeader = JaegerBaggageHeader + } + if c.JaegerDebugHeader == "" { + c.JaegerDebugHeader = JaegerDebugHeader + } + if c.TraceBaggageHeaderPrefix == "" { + c.TraceBaggageHeaderPrefix = TraceBaggageHeaderPrefix + } + if c.TraceContextHeaderName == "" { + c.TraceContextHeaderName = TraceContextHeaderName + } + return c +} + +func getDefaultHeadersConfig() *HeadersConfig { + return &HeadersConfig{ + JaegerDebugHeader: JaegerDebugHeader, + JaegerBaggageHeader: JaegerBaggageHeader, + TraceContextHeaderName: TraceContextHeaderName, + TraceBaggageHeaderPrefix: TraceBaggageHeaderPrefix, + } +} diff --git a/vendor/github.com/uber/jaeger-client-go/internal/baggage/remote/options.go b/vendor/github.com/uber/jaeger-client-go/internal/baggage/remote/options.go new file mode 100644 index 0000000000..745729319f --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/internal/baggage/remote/options.go @@ -0,0 +1,101 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 remote + +import ( + "time" + + "github.com/uber/jaeger-client-go" +) + +const ( + defaultMaxValueLength = 2048 + defaultRefreshInterval = time.Minute + defaultHostPort = "localhost:5778" +) + +// Option is a function that sets some option on the RestrictionManager +type Option func(options *options) + +// Options is a factory for all available options +var Options options + +type options struct { + denyBaggageOnInitializationFailure bool + metrics *jaeger.Metrics + logger jaeger.Logger + hostPort string + refreshInterval time.Duration +} + +// DenyBaggageOnInitializationFailure creates an Option that determines the startup failure mode of RestrictionManager. +// If DenyBaggageOnInitializationFailure is true, RestrictionManager will not allow any baggage to be written until baggage +// restrictions have been retrieved from agent. +// If DenyBaggageOnInitializationFailure is false, RestrictionManager will allow any baggage to be written until baggage +// restrictions have been retrieved from agent. +func (options) DenyBaggageOnInitializationFailure(b bool) Option { + return func(o *options) { + o.denyBaggageOnInitializationFailure = b + } +} + +// Metrics creates an Option that initializes Metrics on the RestrictionManager, which is used to emit statistics. +func (options) Metrics(m *jaeger.Metrics) Option { + return func(o *options) { + o.metrics = m + } +} + +// Logger creates an Option that sets the logger used by the RestrictionManager. +func (options) Logger(logger jaeger.Logger) Option { + return func(o *options) { + o.logger = logger + } +} + +// HostPort creates an Option that sets the hostPort of the local agent that contains the baggage restrictions. +func (options) HostPort(hostPort string) Option { + return func(o *options) { + o.hostPort = hostPort + } +} + +// RefreshInterval creates an Option that sets how often the RestrictionManager will poll local agent for +// the baggage restrictions. +func (options) RefreshInterval(refreshInterval time.Duration) Option { + return func(o *options) { + o.refreshInterval = refreshInterval + } +} + +func applyOptions(o ...Option) options { + opts := options{} + for _, option := range o { + option(&opts) + } + if opts.metrics == nil { + opts.metrics = jaeger.NewNullMetrics() + } + if opts.logger == nil { + opts.logger = jaeger.NullLogger + } + if opts.hostPort == "" { + opts.hostPort = defaultHostPort + } + if opts.refreshInterval == 0 { + opts.refreshInterval = defaultRefreshInterval + } + return opts +} diff --git a/vendor/github.com/uber/jaeger-client-go/internal/baggage/remote/restriction_manager.go b/vendor/github.com/uber/jaeger-client-go/internal/baggage/remote/restriction_manager.go new file mode 100644 index 0000000000..a56515acab --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/internal/baggage/remote/restriction_manager.go @@ -0,0 +1,157 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 remote + +import ( + "fmt" + "net/url" + "sync" + "time" + + "github.com/uber/jaeger-client-go/internal/baggage" + thrift "github.com/uber/jaeger-client-go/thrift-gen/baggage" + "github.com/uber/jaeger-client-go/utils" +) + +type httpBaggageRestrictionManagerProxy struct { + url string +} + +func newHTTPBaggageRestrictionManagerProxy(hostPort, serviceName string) *httpBaggageRestrictionManagerProxy { + v := url.Values{} + v.Set("service", serviceName) + return &httpBaggageRestrictionManagerProxy{ + url: fmt.Sprintf("http://%s/baggageRestrictions?%s", hostPort, v.Encode()), + } +} + +func (s *httpBaggageRestrictionManagerProxy) GetBaggageRestrictions(serviceName string) ([]*thrift.BaggageRestriction, error) { + var out []*thrift.BaggageRestriction + if err := utils.GetJSON(s.url, &out); err != nil { + return nil, err + } + return out, nil +} + +// RestrictionManager manages baggage restrictions by retrieving baggage restrictions from agent +type RestrictionManager struct { + options + + mux sync.RWMutex + serviceName string + restrictions map[string]*baggage.Restriction + thriftProxy thrift.BaggageRestrictionManager + pollStopped sync.WaitGroup + stopPoll chan struct{} + invalidRestriction *baggage.Restriction + validRestriction *baggage.Restriction + + // Determines if the manager has successfully retrieved baggage restrictions from agent + initialized bool +} + +// NewRestrictionManager returns a BaggageRestrictionManager that polls the agent for the latest +// baggage restrictions. +func NewRestrictionManager(serviceName string, options ...Option) *RestrictionManager { + // TODO there is a developing use case where a single tracer can generate traces on behalf of many services. + // restrictionsMap will need to exist per service + opts := applyOptions(options...) + m := &RestrictionManager{ + serviceName: serviceName, + options: opts, + restrictions: make(map[string]*baggage.Restriction), + thriftProxy: newHTTPBaggageRestrictionManagerProxy(opts.hostPort, serviceName), + stopPoll: make(chan struct{}), + invalidRestriction: baggage.NewRestriction(false, 0), + validRestriction: baggage.NewRestriction(true, defaultMaxValueLength), + } + m.pollStopped.Add(1) + go m.pollManager() + return m +} + +// isReady returns true if the manager has retrieved baggage restrictions from the remote source. +func (m *RestrictionManager) isReady() bool { + m.mux.RLock() + defer m.mux.RUnlock() + return m.initialized +} + +// GetRestriction implements RestrictionManager#GetRestriction. +func (m *RestrictionManager) GetRestriction(service, key string) *baggage.Restriction { + m.mux.RLock() + defer m.mux.RUnlock() + if !m.initialized { + if m.denyBaggageOnInitializationFailure { + return m.invalidRestriction + } + return m.validRestriction + } + if restriction, ok := m.restrictions[key]; ok { + return restriction + } + return m.invalidRestriction +} + +// Close stops remote polling and closes the RemoteRestrictionManager. +func (m *RestrictionManager) Close() error { + close(m.stopPoll) + m.pollStopped.Wait() + return nil +} + +func (m *RestrictionManager) pollManager() { + defer m.pollStopped.Done() + // attempt to initialize baggage restrictions + if err := m.updateRestrictions(); err != nil { + m.logger.Error(fmt.Sprintf("Failed to initialize baggage restrictions: %s", err.Error())) + } + ticker := time.NewTicker(m.refreshInterval) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + if err := m.updateRestrictions(); err != nil { + m.logger.Error(fmt.Sprintf("Failed to update baggage restrictions: %s", err.Error())) + } + case <-m.stopPoll: + return + } + } +} + +func (m *RestrictionManager) updateRestrictions() error { + restrictions, err := m.thriftProxy.GetBaggageRestrictions(m.serviceName) + if err != nil { + m.metrics.BaggageRestrictionsUpdateFailure.Inc(1) + return err + } + newRestrictions := m.parseRestrictions(restrictions) + m.metrics.BaggageRestrictionsUpdateSuccess.Inc(1) + m.mux.Lock() + defer m.mux.Unlock() + m.initialized = true + m.restrictions = newRestrictions + return nil +} + +func (m *RestrictionManager) parseRestrictions(restrictions []*thrift.BaggageRestriction) map[string]*baggage.Restriction { + setters := make(map[string]*baggage.Restriction, len(restrictions)) + for _, restriction := range restrictions { + setters[restriction.BaggageKey] = baggage.NewRestriction(true, int(restriction.MaxValueLength)) + } + return setters +} diff --git a/vendor/github.com/uber/jaeger-client-go/internal/baggage/restriction_manager.go b/vendor/github.com/uber/jaeger-client-go/internal/baggage/restriction_manager.go new file mode 100644 index 0000000000..c16a5c5662 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/internal/baggage/restriction_manager.go @@ -0,0 +1,71 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 baggage + +const ( + defaultMaxValueLength = 2048 +) + +// Restriction determines whether a baggage key is allowed and contains any restrictions on the baggage value. +type Restriction struct { + keyAllowed bool + maxValueLength int +} + +// NewRestriction returns a new Restriction. +func NewRestriction(keyAllowed bool, maxValueLength int) *Restriction { + return &Restriction{ + keyAllowed: keyAllowed, + maxValueLength: maxValueLength, + } +} + +// KeyAllowed returns whether the baggage key for this restriction is allowed. +func (r *Restriction) KeyAllowed() bool { + return r.keyAllowed +} + +// MaxValueLength returns the max length for the baggage value. +func (r *Restriction) MaxValueLength() int { + return r.maxValueLength +} + +// RestrictionManager keeps track of valid baggage keys and their restrictions. The manager +// will return a Restriction for a specific baggage key which will determine whether the baggage +// key is allowed for the current service and any other applicable restrictions on the baggage +// value. +type RestrictionManager interface { + GetRestriction(service, key string) *Restriction +} + +// DefaultRestrictionManager allows any baggage key. +type DefaultRestrictionManager struct { + defaultRestriction *Restriction +} + +// NewDefaultRestrictionManager returns a DefaultRestrictionManager. +func NewDefaultRestrictionManager(maxValueLength int) *DefaultRestrictionManager { + if maxValueLength == 0 { + maxValueLength = defaultMaxValueLength + } + return &DefaultRestrictionManager{ + defaultRestriction: &Restriction{keyAllowed: true, maxValueLength: maxValueLength}, + } +} + +// GetRestriction implements RestrictionManager#GetRestriction. +func (m *DefaultRestrictionManager) GetRestriction(service, key string) *Restriction { + return m.defaultRestriction +} diff --git a/vendor/github.com/uber/jaeger-client-go/internal/spanlog/json.go b/vendor/github.com/uber/jaeger-client-go/internal/spanlog/json.go new file mode 100644 index 0000000000..0e10b8a5aa --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/internal/spanlog/json.go @@ -0,0 +1,81 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 spanlog + +import ( + "encoding/json" + "fmt" + + "github.com/opentracing/opentracing-go/log" +) + +type fieldsAsMap map[string]string + +// MaterializeWithJSON converts log Fields into JSON string +// TODO refactor into pluggable materializer +func MaterializeWithJSON(logFields []log.Field) ([]byte, error) { + fields := fieldsAsMap(make(map[string]string, len(logFields))) + for _, field := range logFields { + field.Marshal(fields) + } + if event, ok := fields["event"]; ok && len(fields) == 1 { + return []byte(event), nil + } + return json.Marshal(fields) +} + +func (ml fieldsAsMap) EmitString(key, value string) { + ml[key] = value +} + +func (ml fieldsAsMap) EmitBool(key string, value bool) { + ml[key] = fmt.Sprintf("%t", value) +} + +func (ml fieldsAsMap) EmitInt(key string, value int) { + ml[key] = fmt.Sprintf("%d", value) +} + +func (ml fieldsAsMap) EmitInt32(key string, value int32) { + ml[key] = fmt.Sprintf("%d", value) +} + +func (ml fieldsAsMap) EmitInt64(key string, value int64) { + ml[key] = fmt.Sprintf("%d", value) +} + +func (ml fieldsAsMap) EmitUint32(key string, value uint32) { + ml[key] = fmt.Sprintf("%d", value) +} + +func (ml fieldsAsMap) EmitUint64(key string, value uint64) { + ml[key] = fmt.Sprintf("%d", value) +} + +func (ml fieldsAsMap) EmitFloat32(key string, value float32) { + ml[key] = fmt.Sprintf("%f", value) +} + +func (ml fieldsAsMap) EmitFloat64(key string, value float64) { + ml[key] = fmt.Sprintf("%f", value) +} + +func (ml fieldsAsMap) EmitObject(key string, value interface{}) { + ml[key] = fmt.Sprintf("%+v", value) +} + +func (ml fieldsAsMap) EmitLazyLogger(value log.LazyLogger) { + value(ml) +} diff --git a/vendor/github.com/uber/jaeger-client-go/internal/throttler/remote/options.go b/vendor/github.com/uber/jaeger-client-go/internal/throttler/remote/options.go new file mode 100644 index 0000000000..f52c322fb6 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/internal/throttler/remote/options.go @@ -0,0 +1,99 @@ +// Copyright (c) 2018 The Jaeger Authors. +// +// 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 remote + +import ( + "time" + + "github.com/uber/jaeger-client-go" +) + +const ( + defaultHostPort = "localhost:5778" + defaultRefreshInterval = time.Second * 5 +) + +// Option is a function that sets some option on the Throttler +type Option func(options *options) + +// Options is a factory for all available options +var Options options + +type options struct { + metrics *jaeger.Metrics + logger jaeger.Logger + hostPort string + refreshInterval time.Duration + synchronousInitialization bool +} + +// Metrics creates an Option that initializes Metrics on the Throttler, which is used to emit statistics. +func (options) Metrics(m *jaeger.Metrics) Option { + return func(o *options) { + o.metrics = m + } +} + +// Logger creates an Option that sets the logger used by the Throttler. +func (options) Logger(logger jaeger.Logger) Option { + return func(o *options) { + o.logger = logger + } +} + +// HostPort creates an Option that sets the hostPort of the local agent that keeps track of credits. +func (options) HostPort(hostPort string) Option { + return func(o *options) { + o.hostPort = hostPort + } +} + +// RefreshInterval creates an Option that sets how often the Throttler will poll local agent for +// credits. +func (options) RefreshInterval(refreshInterval time.Duration) Option { + return func(o *options) { + o.refreshInterval = refreshInterval + } +} + +// SynchronousInitialization creates an Option that determines whether the throttler should synchronously +// fetch credits from the agent when an operation is seen for the first time. This should be set to true +// if the client will be used by a short lived service that needs to ensure that credits are fetched upfront +// such that sampling or throttling occurs. +func (options) SynchronousInitialization(b bool) Option { + return func(o *options) { + o.synchronousInitialization = b + } +} + +func applyOptions(o ...Option) options { + opts := options{} + for _, option := range o { + option(&opts) + } + if opts.metrics == nil { + opts.metrics = jaeger.NewNullMetrics() + } + if opts.logger == nil { + opts.logger = jaeger.NullLogger + } + if opts.hostPort == "" { + opts.hostPort = defaultHostPort + } + if opts.refreshInterval == 0 { + opts.refreshInterval = defaultRefreshInterval + } + return opts +} diff --git a/vendor/github.com/uber/jaeger-client-go/internal/throttler/remote/throttler.go b/vendor/github.com/uber/jaeger-client-go/internal/throttler/remote/throttler.go new file mode 100644 index 0000000000..20f434fe49 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/internal/throttler/remote/throttler.go @@ -0,0 +1,216 @@ +// Copyright (c) 2018 The Jaeger Authors. +// +// 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 remote + +import ( + "fmt" + "net/url" + "sync" + "sync/atomic" + "time" + + "github.com/pkg/errors" + + "github.com/uber/jaeger-client-go" + "github.com/uber/jaeger-client-go/utils" +) + +const ( + // minimumCredits is the minimum amount of credits necessary to not be throttled. + // i.e. if currentCredits > minimumCredits, then the operation will not be throttled. + minimumCredits = 1.0 +) + +var ( + errorUUIDNotSet = errors.New("Throttler UUID must be set") +) + +type operationBalance struct { + Operation string `json:"operation"` + Balance float64 `json:"balance"` +} + +type creditResponse struct { + Balances []operationBalance `json:"balances"` +} + +type httpCreditManagerProxy struct { + hostPort string +} + +func newHTTPCreditManagerProxy(hostPort string) *httpCreditManagerProxy { + return &httpCreditManagerProxy{ + hostPort: hostPort, + } +} + +// N.B. Operations list must not be empty. +func (m *httpCreditManagerProxy) FetchCredits(uuid, serviceName string, operations []string) (*creditResponse, error) { + params := url.Values{} + params.Set("service", serviceName) + params.Set("uuid", uuid) + for _, op := range operations { + params.Add("operations", op) + } + var resp creditResponse + if err := utils.GetJSON(fmt.Sprintf("http://%s/credits?%s", m.hostPort, params.Encode()), &resp); err != nil { + return nil, errors.Wrap(err, "Failed to receive credits from agent") + } + return &resp, nil +} + +// Throttler retrieves credits from agent and uses it to throttle operations. +type Throttler struct { + options + + mux sync.RWMutex + service string + uuid atomic.Value + creditManager *httpCreditManagerProxy + credits map[string]float64 // map of operation->credits + close chan struct{} + stopped sync.WaitGroup +} + +// NewThrottler returns a Throttler that polls agent for credits and uses them to throttle +// the service. +func NewThrottler(service string, options ...Option) *Throttler { + opts := applyOptions(options...) + creditManager := newHTTPCreditManagerProxy(opts.hostPort) + t := &Throttler{ + options: opts, + creditManager: creditManager, + service: service, + credits: make(map[string]float64), + close: make(chan struct{}), + } + t.stopped.Add(1) + go t.pollManager() + return t +} + +// IsAllowed implements Throttler#IsAllowed. +func (t *Throttler) IsAllowed(operation string) bool { + t.mux.Lock() + defer t.mux.Unlock() + value, ok := t.credits[operation] + if !ok || value == 0 { + if !ok { + // NOTE: This appears to be a no-op at first glance, but it stores + // the operation key in the map. Necessary for functionality of + // Throttler#operations method. + t.credits[operation] = 0 + } + if !t.synchronousInitialization { + t.metrics.ThrottledDebugSpans.Inc(1) + return false + } + // If it is the first time this operation is being checked, synchronously fetch + // the credits. + credits, err := t.fetchCredits([]string{operation}) + if err != nil { + // Failed to receive credits from agent, try again next time + t.logger.Error("Failed to fetch credits: " + err.Error()) + return false + } + if len(credits.Balances) == 0 { + // This shouldn't happen but just in case + return false + } + for _, opBalance := range credits.Balances { + t.credits[opBalance.Operation] += opBalance.Balance + } + } + return t.isAllowed(operation) +} + +// Close stops the throttler from fetching credits from remote. +func (t *Throttler) Close() error { + close(t.close) + t.stopped.Wait() + return nil +} + +// SetProcess implements ProcessSetter#SetProcess. It's imperative that the UUID is set before any remote +// requests are made. +func (t *Throttler) SetProcess(process jaeger.Process) { + if process.UUID != "" { + t.uuid.Store(process.UUID) + } +} + +// N.B. This function must be called with the Write Lock +func (t *Throttler) isAllowed(operation string) bool { + credits := t.credits[operation] + if credits < minimumCredits { + t.metrics.ThrottledDebugSpans.Inc(1) + return false + } + t.credits[operation] = credits - minimumCredits + return true +} + +func (t *Throttler) pollManager() { + defer t.stopped.Done() + ticker := time.NewTicker(t.refreshInterval) + defer ticker.Stop() + for { + select { + case <-ticker.C: + t.refreshCredits() + case <-t.close: + return + } + } +} + +func (t *Throttler) operations() []string { + t.mux.RLock() + defer t.mux.RUnlock() + operations := make([]string, 0, len(t.credits)) + for op := range t.credits { + operations = append(operations, op) + } + return operations +} + +func (t *Throttler) refreshCredits() { + operations := t.operations() + if len(operations) == 0 { + return + } + newCredits, err := t.fetchCredits(operations) + if err != nil { + t.metrics.ThrottlerUpdateFailure.Inc(1) + t.logger.Error("Failed to fetch credits: " + err.Error()) + return + } + t.metrics.ThrottlerUpdateSuccess.Inc(1) + + t.mux.Lock() + defer t.mux.Unlock() + for _, opBalance := range newCredits.Balances { + t.credits[opBalance.Operation] += opBalance.Balance + } +} + +func (t *Throttler) fetchCredits(operations []string) (*creditResponse, error) { + uuid := t.uuid.Load() + uuidStr, _ := uuid.(string) + if uuid == nil || uuidStr == "" { + return nil, errorUUIDNotSet + } + return t.creditManager.FetchCredits(uuidStr, t.service, operations) +} diff --git a/vendor/github.com/uber/jaeger-client-go/internal/throttler/throttler.go b/vendor/github.com/uber/jaeger-client-go/internal/throttler/throttler.go new file mode 100644 index 0000000000..196ed69cac --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/internal/throttler/throttler.go @@ -0,0 +1,32 @@ +// Copyright (c) 2018 The Jaeger Authors. +// +// 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 throttler + +// Throttler is used to rate limits operations. For example, given how debug spans +// are always sampled, a throttler can be enabled per client to rate limit the amount +// of debug spans a client can start. +type Throttler interface { + // IsAllowed determines whether the operation should be allowed and not be + // throttled. + IsAllowed(operation string) bool +} + +// DefaultThrottler doesn't throttle at all. +type DefaultThrottler struct{} + +// IsAllowed implements Throttler#IsAllowed. +func (t DefaultThrottler) IsAllowed(operation string) bool { + return true +} diff --git a/vendor/github.com/uber/jaeger-client-go/interop.go b/vendor/github.com/uber/jaeger-client-go/interop.go new file mode 100644 index 0000000000..8402d087c2 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/interop.go @@ -0,0 +1,55 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 jaeger + +import ( + "github.com/opentracing/opentracing-go" +) + +// TODO this file should not be needed after TChannel PR. + +type formatKey int + +// SpanContextFormat is a constant used as OpenTracing Format. +// Requires *SpanContext as carrier. +// This format is intended for interop with TChannel or other Zipkin-like tracers. +const SpanContextFormat formatKey = iota + +type jaegerTraceContextPropagator struct { + tracer *Tracer +} + +func (p *jaegerTraceContextPropagator) Inject( + ctx SpanContext, + abstractCarrier interface{}, +) error { + carrier, ok := abstractCarrier.(*SpanContext) + if !ok { + return opentracing.ErrInvalidCarrier + } + + carrier.CopyFrom(&ctx) + return nil +} + +func (p *jaegerTraceContextPropagator) Extract(abstractCarrier interface{}) (SpanContext, error) { + carrier, ok := abstractCarrier.(*SpanContext) + if !ok { + return emptyContext, opentracing.ErrInvalidCarrier + } + ctx := new(SpanContext) + ctx.CopyFrom(carrier) + return *ctx, nil +} diff --git a/vendor/github.com/uber/jaeger-client-go/jaeger_tag.go b/vendor/github.com/uber/jaeger-client-go/jaeger_tag.go new file mode 100644 index 0000000000..868b2a5b54 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/jaeger_tag.go @@ -0,0 +1,84 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 jaeger + +import ( + "fmt" + + "github.com/opentracing/opentracing-go/log" + + j "github.com/uber/jaeger-client-go/thrift-gen/jaeger" +) + +type tags []*j.Tag + +// ConvertLogsToJaegerTags converts log Fields into jaeger tags. +func ConvertLogsToJaegerTags(logFields []log.Field) []*j.Tag { + fields := tags(make([]*j.Tag, 0, len(logFields))) + for _, field := range logFields { + field.Marshal(&fields) + } + return fields +} + +func (t *tags) EmitString(key, value string) { + *t = append(*t, &j.Tag{Key: key, VType: j.TagType_STRING, VStr: &value}) +} + +func (t *tags) EmitBool(key string, value bool) { + *t = append(*t, &j.Tag{Key: key, VType: j.TagType_BOOL, VBool: &value}) +} + +func (t *tags) EmitInt(key string, value int) { + vLong := int64(value) + *t = append(*t, &j.Tag{Key: key, VType: j.TagType_LONG, VLong: &vLong}) +} + +func (t *tags) EmitInt32(key string, value int32) { + vLong := int64(value) + *t = append(*t, &j.Tag{Key: key, VType: j.TagType_LONG, VLong: &vLong}) +} + +func (t *tags) EmitInt64(key string, value int64) { + *t = append(*t, &j.Tag{Key: key, VType: j.TagType_LONG, VLong: &value}) +} + +func (t *tags) EmitUint32(key string, value uint32) { + vLong := int64(value) + *t = append(*t, &j.Tag{Key: key, VType: j.TagType_LONG, VLong: &vLong}) +} + +func (t *tags) EmitUint64(key string, value uint64) { + vLong := int64(value) + *t = append(*t, &j.Tag{Key: key, VType: j.TagType_LONG, VLong: &vLong}) +} + +func (t *tags) EmitFloat32(key string, value float32) { + vDouble := float64(value) + *t = append(*t, &j.Tag{Key: key, VType: j.TagType_DOUBLE, VDouble: &vDouble}) +} + +func (t *tags) EmitFloat64(key string, value float64) { + *t = append(*t, &j.Tag{Key: key, VType: j.TagType_DOUBLE, VDouble: &value}) +} + +func (t *tags) EmitObject(key string, value interface{}) { + vStr := fmt.Sprintf("%+v", value) + *t = append(*t, &j.Tag{Key: key, VType: j.TagType_STRING, VStr: &vStr}) +} + +func (t *tags) EmitLazyLogger(value log.LazyLogger) { + value(t) +} diff --git a/vendor/github.com/uber/jaeger-client-go/jaeger_thrift_span.go b/vendor/github.com/uber/jaeger-client-go/jaeger_thrift_span.go new file mode 100644 index 0000000000..6ce1caf873 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/jaeger_thrift_span.go @@ -0,0 +1,179 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 jaeger + +import ( + "time" + + "github.com/opentracing/opentracing-go" + + j "github.com/uber/jaeger-client-go/thrift-gen/jaeger" + "github.com/uber/jaeger-client-go/utils" +) + +// BuildJaegerThrift builds jaeger span based on internal span. +func BuildJaegerThrift(span *Span) *j.Span { + span.Lock() + defer span.Unlock() + startTime := utils.TimeToMicrosecondsSinceEpochInt64(span.startTime) + duration := span.duration.Nanoseconds() / int64(time.Microsecond) + jaegerSpan := &j.Span{ + TraceIdLow: int64(span.context.traceID.Low), + TraceIdHigh: int64(span.context.traceID.High), + SpanId: int64(span.context.spanID), + ParentSpanId: int64(span.context.parentID), + OperationName: span.operationName, + Flags: int32(span.context.flags), + StartTime: startTime, + Duration: duration, + Tags: buildTags(span.tags, span.tracer.options.maxTagValueLength), + Logs: buildLogs(span.logs), + References: buildReferences(span.references), + } + return jaegerSpan +} + +// BuildJaegerProcessThrift creates a thrift Process type. +func BuildJaegerProcessThrift(span *Span) *j.Process { + span.Lock() + defer span.Unlock() + return buildJaegerProcessThrift(span.tracer) +} + +func buildJaegerProcessThrift(tracer *Tracer) *j.Process { + process := &j.Process{ + ServiceName: tracer.serviceName, + Tags: buildTags(tracer.tags, tracer.options.maxTagValueLength), + } + if tracer.process.UUID != "" { + process.Tags = append(process.Tags, &j.Tag{Key: TracerUUIDTagKey, VStr: &tracer.process.UUID, VType: j.TagType_STRING}) + } + return process +} + +func buildTags(tags []Tag, maxTagValueLength int) []*j.Tag { + jTags := make([]*j.Tag, 0, len(tags)) + for _, tag := range tags { + jTag := buildTag(&tag, maxTagValueLength) + jTags = append(jTags, jTag) + } + return jTags +} + +func buildLogs(logs []opentracing.LogRecord) []*j.Log { + jLogs := make([]*j.Log, 0, len(logs)) + for _, log := range logs { + jLog := &j.Log{ + Timestamp: utils.TimeToMicrosecondsSinceEpochInt64(log.Timestamp), + Fields: ConvertLogsToJaegerTags(log.Fields), + } + jLogs = append(jLogs, jLog) + } + return jLogs +} + +func buildTag(tag *Tag, maxTagValueLength int) *j.Tag { + jTag := &j.Tag{Key: tag.key} + switch value := tag.value.(type) { + case string: + vStr := truncateString(value, maxTagValueLength) + jTag.VStr = &vStr + jTag.VType = j.TagType_STRING + case []byte: + if len(value) > maxTagValueLength { + value = value[:maxTagValueLength] + } + jTag.VBinary = value + jTag.VType = j.TagType_BINARY + case int: + vLong := int64(value) + jTag.VLong = &vLong + jTag.VType = j.TagType_LONG + case uint: + vLong := int64(value) + jTag.VLong = &vLong + jTag.VType = j.TagType_LONG + case int8: + vLong := int64(value) + jTag.VLong = &vLong + jTag.VType = j.TagType_LONG + case uint8: + vLong := int64(value) + jTag.VLong = &vLong + jTag.VType = j.TagType_LONG + case int16: + vLong := int64(value) + jTag.VLong = &vLong + jTag.VType = j.TagType_LONG + case uint16: + vLong := int64(value) + jTag.VLong = &vLong + jTag.VType = j.TagType_LONG + case int32: + vLong := int64(value) + jTag.VLong = &vLong + jTag.VType = j.TagType_LONG + case uint32: + vLong := int64(value) + jTag.VLong = &vLong + jTag.VType = j.TagType_LONG + case int64: + vLong := int64(value) + jTag.VLong = &vLong + jTag.VType = j.TagType_LONG + case uint64: + vLong := int64(value) + jTag.VLong = &vLong + jTag.VType = j.TagType_LONG + case float32: + vDouble := float64(value) + jTag.VDouble = &vDouble + jTag.VType = j.TagType_DOUBLE + case float64: + vDouble := float64(value) + jTag.VDouble = &vDouble + jTag.VType = j.TagType_DOUBLE + case bool: + vBool := value + jTag.VBool = &vBool + jTag.VType = j.TagType_BOOL + default: + vStr := truncateString(stringify(value), maxTagValueLength) + jTag.VStr = &vStr + jTag.VType = j.TagType_STRING + } + return jTag +} + +func buildReferences(references []Reference) []*j.SpanRef { + retMe := make([]*j.SpanRef, 0, len(references)) + for _, ref := range references { + if ref.Type == opentracing.ChildOfRef { + retMe = append(retMe, spanRef(ref.Context, j.SpanRefType_CHILD_OF)) + } else if ref.Type == opentracing.FollowsFromRef { + retMe = append(retMe, spanRef(ref.Context, j.SpanRefType_FOLLOWS_FROM)) + } + } + return retMe +} + +func spanRef(ctx SpanContext, refType j.SpanRefType) *j.SpanRef { + return &j.SpanRef{ + RefType: refType, + TraceIdLow: int64(ctx.traceID.Low), + TraceIdHigh: int64(ctx.traceID.High), + SpanId: int64(ctx.spanID), + } +} diff --git a/vendor/github.com/uber/jaeger-client-go/log/logger.go b/vendor/github.com/uber/jaeger-client-go/log/logger.go new file mode 100644 index 0000000000..894bb3dbf7 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/log/logger.go @@ -0,0 +1,90 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 log + +import ( + "bytes" + "fmt" + "log" + "sync" +) + +// Logger provides an abstract interface for logging from Reporters. +// Applications can provide their own implementation of this interface to adapt +// reporters logging to whatever logging library they prefer (stdlib log, +// logrus, go-logging, etc). +type Logger interface { + // Error logs a message at error priority + Error(msg string) + + // Infof logs a message at info priority + Infof(msg string, args ...interface{}) +} + +// StdLogger is implementation of the Logger interface that delegates to default `log` package +var StdLogger = &stdLogger{} + +type stdLogger struct{} + +func (l *stdLogger) Error(msg string) { + log.Printf("ERROR: %s", msg) +} + +// Infof logs a message at info priority +func (l *stdLogger) Infof(msg string, args ...interface{}) { + log.Printf(msg, args...) +} + +// NullLogger is implementation of the Logger interface that is no-op +var NullLogger = &nullLogger{} + +type nullLogger struct{} + +func (l *nullLogger) Error(msg string) {} +func (l *nullLogger) Infof(msg string, args ...interface{}) {} + +// BytesBufferLogger implements Logger backed by a bytes.Buffer. +type BytesBufferLogger struct { + mux sync.Mutex + buf bytes.Buffer +} + +// Error implements Logger. +func (l *BytesBufferLogger) Error(msg string) { + l.mux.Lock() + l.buf.WriteString(fmt.Sprintf("ERROR: %s\n", msg)) + l.mux.Unlock() +} + +// Infof implements Logger. +func (l *BytesBufferLogger) Infof(msg string, args ...interface{}) { + l.mux.Lock() + l.buf.WriteString("INFO: " + fmt.Sprintf(msg, args...) + "\n") + l.mux.Unlock() +} + +// String returns string representation of the underlying buffer. +func (l *BytesBufferLogger) String() string { + l.mux.Lock() + defer l.mux.Unlock() + return l.buf.String() +} + +// Flush empties the underlying buffer. +func (l *BytesBufferLogger) Flush() { + l.mux.Lock() + defer l.mux.Unlock() + l.buf.Reset() +} diff --git a/vendor/github.com/uber/jaeger-client-go/logger.go b/vendor/github.com/uber/jaeger-client-go/logger.go new file mode 100644 index 0000000000..d4f0b50192 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/logger.go @@ -0,0 +1,53 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 jaeger + +import "log" + +// NB This will be deprecated in 3.0.0, please use jaeger-client-go/log/logger instead. + +// Logger provides an abstract interface for logging from Reporters. +// Applications can provide their own implementation of this interface to adapt +// reporters logging to whatever logging library they prefer (stdlib log, +// logrus, go-logging, etc). +type Logger interface { + // Error logs a message at error priority + Error(msg string) + + // Infof logs a message at info priority + Infof(msg string, args ...interface{}) +} + +// StdLogger is implementation of the Logger interface that delegates to default `log` package +var StdLogger = &stdLogger{} + +type stdLogger struct{} + +func (l *stdLogger) Error(msg string) { + log.Printf("ERROR: %s", msg) +} + +// Infof logs a message at info priority +func (l *stdLogger) Infof(msg string, args ...interface{}) { + log.Printf(msg, args...) +} + +// NullLogger is implementation of the Logger interface that delegates to default `log` package +var NullLogger = &nullLogger{} + +type nullLogger struct{} + +func (l *nullLogger) Error(msg string) {} +func (l *nullLogger) Infof(msg string, args ...interface{}) {} diff --git a/vendor/github.com/uber/jaeger-client-go/metrics.go b/vendor/github.com/uber/jaeger-client-go/metrics.go new file mode 100644 index 0000000000..cadb2b9c0f --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/metrics.go @@ -0,0 +1,107 @@ +// Copyright (c) 2017-2018 Uber Technologies, Inc. +// +// 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 jaeger + +import ( + "github.com/uber/jaeger-lib/metrics" +) + +// Metrics is a container of all stats emitted by Jaeger tracer. +type Metrics struct { + // Number of traces started by this tracer as sampled + TracesStartedSampled metrics.Counter `metric:"traces" tags:"state=started,sampled=y"` + + // Number of traces started by this tracer as not sampled + TracesStartedNotSampled metrics.Counter `metric:"traces" tags:"state=started,sampled=n"` + + // Number of externally started sampled traces this tracer joined + TracesJoinedSampled metrics.Counter `metric:"traces" tags:"state=joined,sampled=y"` + + // Number of externally started not-sampled traces this tracer joined + TracesJoinedNotSampled metrics.Counter `metric:"traces" tags:"state=joined,sampled=n"` + + // Number of sampled spans started by this tracer + SpansStartedSampled metrics.Counter `metric:"started_spans" tags:"sampled=y"` + + // Number of unsampled spans started by this tracer + SpansStartedNotSampled metrics.Counter `metric:"started_spans" tags:"sampled=n"` + + // Number of spans finished by this tracer + SpansFinished metrics.Counter `metric:"finished_spans"` + + // Number of errors decoding tracing context + DecodingErrors metrics.Counter `metric:"span_context_decoding_errors"` + + // Number of spans successfully reported + ReporterSuccess metrics.Counter `metric:"reporter_spans" tags:"result=ok"` + + // Number of spans not reported due to a Sender failure + ReporterFailure metrics.Counter `metric:"reporter_spans" tags:"result=err"` + + // Number of spans dropped due to internal queue overflow + ReporterDropped metrics.Counter `metric:"reporter_spans" tags:"result=dropped"` + + // Current number of spans in the reporter queue + ReporterQueueLength metrics.Gauge `metric:"reporter_queue_length"` + + // Number of times the Sampler succeeded to retrieve sampling strategy + SamplerRetrieved metrics.Counter `metric:"sampler_queries" tags:"result=ok"` + + // Number of times the Sampler failed to retrieve sampling strategy + SamplerQueryFailure metrics.Counter `metric:"sampler_queries" tags:"result=err"` + + // Number of times the Sampler succeeded to retrieve and update sampling strategy + SamplerUpdated metrics.Counter `metric:"sampler_updates" tags:"result=ok"` + + // Number of times the Sampler failed to update sampling strategy + SamplerUpdateFailure metrics.Counter `metric:"sampler_updates" tags:"result=err"` + + // Number of times baggage was successfully written or updated on spans. + BaggageUpdateSuccess metrics.Counter `metric:"baggage_updates" tags:"result=ok"` + + // Number of times baggage failed to write or update on spans. + BaggageUpdateFailure metrics.Counter `metric:"baggage_updates" tags:"result=err"` + + // Number of times baggage was truncated as per baggage restrictions. + BaggageTruncate metrics.Counter `metric:"baggage_truncations"` + + // Number of times baggage restrictions were successfully updated. + BaggageRestrictionsUpdateSuccess metrics.Counter `metric:"baggage_restrictions_updates" tags:"result=ok"` + + // Number of times baggage restrictions failed to update. + BaggageRestrictionsUpdateFailure metrics.Counter `metric:"baggage_restrictions_updates" tags:"result=err"` + + // Number of times debug spans were throttled. + ThrottledDebugSpans metrics.Counter `metric:"throttled_debug_spans"` + + // Number of times throttler successfully updated. + ThrottlerUpdateSuccess metrics.Counter `metric:"throttler_updates" tags:"result=ok"` + + // Number of times throttler failed to update. + ThrottlerUpdateFailure metrics.Counter `metric:"throttler_updates" tags:"result=err"` +} + +// NewMetrics creates a new Metrics struct and initializes it. +func NewMetrics(factory metrics.Factory, globalTags map[string]string) *Metrics { + m := &Metrics{} + // TODO the namespace "jaeger" should be configurable (e.g. in all-in-one "jaeger-client" would make more sense) + metrics.Init(m, factory.Namespace("jaeger", nil), globalTags) + return m +} + +// NewNullMetrics creates a new Metrics struct that won't report any metrics. +func NewNullMetrics() *Metrics { + return NewMetrics(metrics.NullFactory, nil) +} diff --git a/vendor/github.com/uber/jaeger-client-go/observer.go b/vendor/github.com/uber/jaeger-client-go/observer.go new file mode 100644 index 0000000000..7bbd028897 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/observer.go @@ -0,0 +1,88 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 jaeger + +import opentracing "github.com/opentracing/opentracing-go" + +// Observer can be registered with the Tracer to receive notifications about +// new Spans. +// +// Deprecated: use jaeger.ContribObserver instead. +type Observer interface { + OnStartSpan(operationName string, options opentracing.StartSpanOptions) SpanObserver +} + +// SpanObserver is created by the Observer and receives notifications about +// other Span events. +// +// Deprecated: use jaeger.ContribSpanObserver instead. +type SpanObserver interface { + OnSetOperationName(operationName string) + OnSetTag(key string, value interface{}) + OnFinish(options opentracing.FinishOptions) +} + +// compositeObserver is a dispatcher to other observers +type compositeObserver struct { + observers []ContribObserver +} + +// compositeSpanObserver is a dispatcher to other span observers +type compositeSpanObserver struct { + observers []ContribSpanObserver +} + +// noopSpanObserver is used when there are no observers registered +// on the Tracer or none of them returns span observers from OnStartSpan. +var noopSpanObserver = &compositeSpanObserver{} + +func (o *compositeObserver) append(contribObserver ContribObserver) { + o.observers = append(o.observers, contribObserver) +} + +func (o *compositeObserver) OnStartSpan(sp opentracing.Span, operationName string, options opentracing.StartSpanOptions) ContribSpanObserver { + var spanObservers []ContribSpanObserver + for _, obs := range o.observers { + spanObs, ok := obs.OnStartSpan(sp, operationName, options) + if ok { + if spanObservers == nil { + spanObservers = make([]ContribSpanObserver, 0, len(o.observers)) + } + spanObservers = append(spanObservers, spanObs) + } + } + if len(spanObservers) == 0 { + return noopSpanObserver + } + return &compositeSpanObserver{observers: spanObservers} +} + +func (o *compositeSpanObserver) OnSetOperationName(operationName string) { + for _, obs := range o.observers { + obs.OnSetOperationName(operationName) + } +} + +func (o *compositeSpanObserver) OnSetTag(key string, value interface{}) { + for _, obs := range o.observers { + obs.OnSetTag(key, value) + } +} + +func (o *compositeSpanObserver) OnFinish(options opentracing.FinishOptions) { + for _, obs := range o.observers { + obs.OnFinish(options) + } +} diff --git a/vendor/github.com/uber/jaeger-client-go/process.go b/vendor/github.com/uber/jaeger-client-go/process.go new file mode 100644 index 0000000000..30cbf99624 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/process.go @@ -0,0 +1,29 @@ +// Copyright (c) 2018 The Jaeger Authors. +// +// 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 jaeger + +// Process holds process specific metadata that's relevant to this client. +type Process struct { + Service string + UUID string + Tags []Tag +} + +// ProcessSetter sets a process. This can be used by any class that requires +// the process to be set as part of initialization. +// See internal/throttler/remote/throttler.go for an example. +type ProcessSetter interface { + SetProcess(process Process) +} diff --git a/vendor/github.com/uber/jaeger-client-go/propagation.go b/vendor/github.com/uber/jaeger-client-go/propagation.go new file mode 100644 index 0000000000..abca67a3c9 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/propagation.go @@ -0,0 +1,300 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 jaeger + +import ( + "bytes" + "encoding/binary" + "fmt" + "io" + "log" + "net/url" + "strings" + "sync" + + opentracing "github.com/opentracing/opentracing-go" +) + +// Injector is responsible for injecting SpanContext instances in a manner suitable +// for propagation via a format-specific "carrier" object. Typically the +// injection will take place across an RPC boundary, but message queues and +// other IPC mechanisms are also reasonable places to use an Injector. +type Injector interface { + // Inject takes `SpanContext` and injects it into `carrier`. The actual type + // of `carrier` depends on the `format` passed to `Tracer.Inject()`. + // + // Implementations may return opentracing.ErrInvalidCarrier or any other + // implementation-specific error if injection fails. + Inject(ctx SpanContext, carrier interface{}) error +} + +// Extractor is responsible for extracting SpanContext instances from a +// format-specific "carrier" object. Typically the extraction will take place +// on the server side of an RPC boundary, but message queues and other IPC +// mechanisms are also reasonable places to use an Extractor. +type Extractor interface { + // Extract decodes a SpanContext instance from the given `carrier`, + // or (nil, opentracing.ErrSpanContextNotFound) if no context could + // be found in the `carrier`. + Extract(carrier interface{}) (SpanContext, error) +} + +type textMapPropagator struct { + headerKeys *HeadersConfig + metrics Metrics + encodeValue func(string) string + decodeValue func(string) string +} + +func newTextMapPropagator(headerKeys *HeadersConfig, metrics Metrics) *textMapPropagator { + return &textMapPropagator{ + headerKeys: headerKeys, + metrics: metrics, + encodeValue: func(val string) string { + return val + }, + decodeValue: func(val string) string { + return val + }, + } +} + +func newHTTPHeaderPropagator(headerKeys *HeadersConfig, metrics Metrics) *textMapPropagator { + return &textMapPropagator{ + headerKeys: headerKeys, + metrics: metrics, + encodeValue: func(val string) string { + return url.QueryEscape(val) + }, + decodeValue: func(val string) string { + // ignore decoding errors, cannot do anything about them + if v, err := url.QueryUnescape(val); err == nil { + return v + } + return val + }, + } +} + +type binaryPropagator struct { + tracer *Tracer + buffers sync.Pool +} + +func newBinaryPropagator(tracer *Tracer) *binaryPropagator { + return &binaryPropagator{ + tracer: tracer, + buffers: sync.Pool{New: func() interface{} { return &bytes.Buffer{} }}, + } +} + +func (p *textMapPropagator) Inject( + sc SpanContext, + abstractCarrier interface{}, +) error { + textMapWriter, ok := abstractCarrier.(opentracing.TextMapWriter) + if !ok { + return opentracing.ErrInvalidCarrier + } + + // Do not encode the string with trace context to avoid accidental double-encoding + // if people are using opentracing < 0.10.0. Our colon-separated representation + // of the trace context is already safe for HTTP headers. + textMapWriter.Set(p.headerKeys.TraceContextHeaderName, sc.String()) + for k, v := range sc.baggage { + safeKey := p.addBaggageKeyPrefix(k) + safeVal := p.encodeValue(v) + textMapWriter.Set(safeKey, safeVal) + } + return nil +} + +func (p *textMapPropagator) Extract(abstractCarrier interface{}) (SpanContext, error) { + textMapReader, ok := abstractCarrier.(opentracing.TextMapReader) + if !ok { + return emptyContext, opentracing.ErrInvalidCarrier + } + var ctx SpanContext + var baggage map[string]string + err := textMapReader.ForeachKey(func(rawKey, value string) error { + key := strings.ToLower(rawKey) // TODO not necessary for plain TextMap + if key == p.headerKeys.TraceContextHeaderName { + var err error + safeVal := p.decodeValue(value) + if ctx, err = ContextFromString(safeVal); err != nil { + return err + } + } else if key == p.headerKeys.JaegerDebugHeader { + ctx.debugID = p.decodeValue(value) + } else if key == p.headerKeys.JaegerBaggageHeader { + if baggage == nil { + baggage = make(map[string]string) + } + for k, v := range p.parseCommaSeparatedMap(value) { + baggage[k] = v + } + } else if strings.HasPrefix(key, p.headerKeys.TraceBaggageHeaderPrefix) { + if baggage == nil { + baggage = make(map[string]string) + } + safeKey := p.removeBaggageKeyPrefix(key) + safeVal := p.decodeValue(value) + baggage[safeKey] = safeVal + } + return nil + }) + if err != nil { + p.metrics.DecodingErrors.Inc(1) + return emptyContext, err + } + if !ctx.traceID.IsValid() && ctx.debugID == "" && len(baggage) == 0 { + return emptyContext, opentracing.ErrSpanContextNotFound + } + ctx.baggage = baggage + return ctx, nil +} + +func (p *binaryPropagator) Inject( + sc SpanContext, + abstractCarrier interface{}, +) error { + carrier, ok := abstractCarrier.(io.Writer) + if !ok { + return opentracing.ErrInvalidCarrier + } + + // Handle the tracer context + if err := binary.Write(carrier, binary.BigEndian, sc.traceID); err != nil { + return err + } + if err := binary.Write(carrier, binary.BigEndian, sc.spanID); err != nil { + return err + } + if err := binary.Write(carrier, binary.BigEndian, sc.parentID); err != nil { + return err + } + if err := binary.Write(carrier, binary.BigEndian, sc.flags); err != nil { + return err + } + + // Handle the baggage items + if err := binary.Write(carrier, binary.BigEndian, int32(len(sc.baggage))); err != nil { + return err + } + for k, v := range sc.baggage { + if err := binary.Write(carrier, binary.BigEndian, int32(len(k))); err != nil { + return err + } + io.WriteString(carrier, k) + if err := binary.Write(carrier, binary.BigEndian, int32(len(v))); err != nil { + return err + } + io.WriteString(carrier, v) + } + + return nil +} + +func (p *binaryPropagator) Extract(abstractCarrier interface{}) (SpanContext, error) { + carrier, ok := abstractCarrier.(io.Reader) + if !ok { + return emptyContext, opentracing.ErrInvalidCarrier + } + var ctx SpanContext + + if err := binary.Read(carrier, binary.BigEndian, &ctx.traceID); err != nil { + return emptyContext, opentracing.ErrSpanContextCorrupted + } + if err := binary.Read(carrier, binary.BigEndian, &ctx.spanID); err != nil { + return emptyContext, opentracing.ErrSpanContextCorrupted + } + if err := binary.Read(carrier, binary.BigEndian, &ctx.parentID); err != nil { + return emptyContext, opentracing.ErrSpanContextCorrupted + } + if err := binary.Read(carrier, binary.BigEndian, &ctx.flags); err != nil { + return emptyContext, opentracing.ErrSpanContextCorrupted + } + + // Handle the baggage items + var numBaggage int32 + if err := binary.Read(carrier, binary.BigEndian, &numBaggage); err != nil { + return emptyContext, opentracing.ErrSpanContextCorrupted + } + if iNumBaggage := int(numBaggage); iNumBaggage > 0 { + ctx.baggage = make(map[string]string, iNumBaggage) + buf := p.buffers.Get().(*bytes.Buffer) + defer p.buffers.Put(buf) + + var keyLen, valLen int32 + for i := 0; i < iNumBaggage; i++ { + if err := binary.Read(carrier, binary.BigEndian, &keyLen); err != nil { + return emptyContext, opentracing.ErrSpanContextCorrupted + } + buf.Reset() + buf.Grow(int(keyLen)) + if n, err := io.CopyN(buf, carrier, int64(keyLen)); err != nil || int32(n) != keyLen { + return emptyContext, opentracing.ErrSpanContextCorrupted + } + key := buf.String() + + if err := binary.Read(carrier, binary.BigEndian, &valLen); err != nil { + return emptyContext, opentracing.ErrSpanContextCorrupted + } + buf.Reset() + buf.Grow(int(valLen)) + if n, err := io.CopyN(buf, carrier, int64(valLen)); err != nil || int32(n) != valLen { + return emptyContext, opentracing.ErrSpanContextCorrupted + } + ctx.baggage[key] = buf.String() + } + } + + return ctx, nil +} + +// Converts a comma separated key value pair list into a map +// e.g. key1=value1, key2=value2, key3 = value3 +// is converted to map[string]string { "key1" : "value1", +// "key2" : "value2", +// "key3" : "value3" } +func (p *textMapPropagator) parseCommaSeparatedMap(value string) map[string]string { + baggage := make(map[string]string) + value, err := url.QueryUnescape(value) + if err != nil { + log.Printf("Unable to unescape %s, %v", value, err) + return baggage + } + for _, kvpair := range strings.Split(value, ",") { + kv := strings.Split(strings.TrimSpace(kvpair), "=") + if len(kv) == 2 { + baggage[kv[0]] = kv[1] + } else { + log.Printf("Malformed value passed in for %s", p.headerKeys.JaegerBaggageHeader) + } + } + return baggage +} + +// Converts a baggage item key into an http header format, +// by prepending TraceBaggageHeaderPrefix and encoding the key string +func (p *textMapPropagator) addBaggageKeyPrefix(key string) string { + // TODO encodeBaggageKeyAsHeader add caching and escaping + return fmt.Sprintf("%v%v", p.headerKeys.TraceBaggageHeaderPrefix, key) +} + +func (p *textMapPropagator) removeBaggageKeyPrefix(key string) string { + // TODO decodeBaggageHeaderKey add caching and escaping + return key[len(p.headerKeys.TraceBaggageHeaderPrefix):] +} diff --git a/vendor/github.com/uber/jaeger-client-go/reference.go b/vendor/github.com/uber/jaeger-client-go/reference.go new file mode 100644 index 0000000000..5646e78bb2 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/reference.go @@ -0,0 +1,23 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 jaeger + +import "github.com/opentracing/opentracing-go" + +// Reference represents a causal reference to other Spans (via their SpanContext). +type Reference struct { + Type opentracing.SpanReferenceType + Context SpanContext +} diff --git a/vendor/github.com/uber/jaeger-client-go/reporter.go b/vendor/github.com/uber/jaeger-client-go/reporter.go new file mode 100644 index 0000000000..fe6288c4b9 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/reporter.go @@ -0,0 +1,289 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 jaeger + +import ( + "fmt" + "sync" + "sync/atomic" + "time" + + "github.com/opentracing/opentracing-go" + + "github.com/uber/jaeger-client-go/log" +) + +// Reporter is called by the tracer when a span is completed to report the span to the tracing collector. +type Reporter interface { + // Report submits a new span to collectors, possibly asynchronously and/or with buffering. + Report(span *Span) + + // Close does a clean shutdown of the reporter, flushing any traces that may be buffered in memory. + Close() +} + +// ------------------------------ + +type nullReporter struct{} + +// NewNullReporter creates a no-op reporter that ignores all reported spans. +func NewNullReporter() Reporter { + return &nullReporter{} +} + +// Report implements Report() method of Reporter by doing nothing. +func (r *nullReporter) Report(span *Span) { + // no-op +} + +// Close implements Close() method of Reporter by doing nothing. +func (r *nullReporter) Close() { + // no-op +} + +// ------------------------------ + +type loggingReporter struct { + logger Logger +} + +// NewLoggingReporter creates a reporter that logs all reported spans to provided logger. +func NewLoggingReporter(logger Logger) Reporter { + return &loggingReporter{logger} +} + +// Report implements Report() method of Reporter by logging the span to the logger. +func (r *loggingReporter) Report(span *Span) { + r.logger.Infof("Reporting span %+v", span) +} + +// Close implements Close() method of Reporter by doing nothing. +func (r *loggingReporter) Close() { + // no-op +} + +// ------------------------------ + +// InMemoryReporter is used for testing, and simply collects spans in memory. +type InMemoryReporter struct { + spans []opentracing.Span + lock sync.Mutex +} + +// NewInMemoryReporter creates a reporter that stores spans in memory. +// NOTE: the Tracer should be created with options.PoolSpans = false. +func NewInMemoryReporter() *InMemoryReporter { + return &InMemoryReporter{ + spans: make([]opentracing.Span, 0, 10), + } +} + +// Report implements Report() method of Reporter by storing the span in the buffer. +func (r *InMemoryReporter) Report(span *Span) { + r.lock.Lock() + r.spans = append(r.spans, span) + r.lock.Unlock() +} + +// Close implements Close() method of Reporter by doing nothing. +func (r *InMemoryReporter) Close() { + // no-op +} + +// SpansSubmitted returns the number of spans accumulated in the buffer. +func (r *InMemoryReporter) SpansSubmitted() int { + r.lock.Lock() + defer r.lock.Unlock() + return len(r.spans) +} + +// GetSpans returns accumulated spans as a copy of the buffer. +func (r *InMemoryReporter) GetSpans() []opentracing.Span { + r.lock.Lock() + defer r.lock.Unlock() + copied := make([]opentracing.Span, len(r.spans)) + copy(copied, r.spans) + return copied +} + +// Reset clears all accumulated spans. +func (r *InMemoryReporter) Reset() { + r.lock.Lock() + defer r.lock.Unlock() + r.spans = nil +} + +// ------------------------------ + +type compositeReporter struct { + reporters []Reporter +} + +// NewCompositeReporter creates a reporter that ignores all reported spans. +func NewCompositeReporter(reporters ...Reporter) Reporter { + return &compositeReporter{reporters: reporters} +} + +// Report implements Report() method of Reporter by delegating to each underlying reporter. +func (r *compositeReporter) Report(span *Span) { + for _, reporter := range r.reporters { + reporter.Report(span) + } +} + +// Close implements Close() method of Reporter by closing each underlying reporter. +func (r *compositeReporter) Close() { + for _, reporter := range r.reporters { + reporter.Close() + } +} + +// ------------- REMOTE REPORTER ----------------- + +type reporterQueueItemType int + +const ( + defaultQueueSize = 100 + defaultBufferFlushInterval = 1 * time.Second + + reporterQueueItemSpan reporterQueueItemType = iota + reporterQueueItemClose +) + +type reporterQueueItem struct { + itemType reporterQueueItemType + span *Span + close *sync.WaitGroup +} + +type remoteReporter struct { + // These fields must be first in the struct because `sync/atomic` expects 64-bit alignment. + // Cf. https://github.com/uber/jaeger-client-go/issues/155, https://goo.gl/zW7dgq + queueLength int64 + closed int64 // 0 - not closed, 1 - closed + + reporterOptions + + sender Transport + queue chan reporterQueueItem +} + +// NewRemoteReporter creates a new reporter that sends spans out of process by means of Sender. +// Calls to Report(Span) return immediately (side effect: if internal buffer is full the span is dropped). +// Periodically the transport buffer is flushed even if it hasn't reached max packet size. +// Calls to Close() block until all spans reported prior to the call to Close are flushed. +func NewRemoteReporter(sender Transport, opts ...ReporterOption) Reporter { + options := reporterOptions{} + for _, option := range opts { + option(&options) + } + if options.bufferFlushInterval <= 0 { + options.bufferFlushInterval = defaultBufferFlushInterval + } + if options.logger == nil { + options.logger = log.NullLogger + } + if options.metrics == nil { + options.metrics = NewNullMetrics() + } + if options.queueSize <= 0 { + options.queueSize = defaultQueueSize + } + reporter := &remoteReporter{ + reporterOptions: options, + sender: sender, + queue: make(chan reporterQueueItem, options.queueSize), + } + go reporter.processQueue() + return reporter +} + +// Report implements Report() method of Reporter. +// It passes the span to a background go-routine for submission to Jaeger backend. +// If the internal queue is full, the span is dropped and metrics.ReporterDropped counter is incremented. +// If Report() is called after the reporter has been Close()-ed, the additional spans will not be +// sent to the backend, but the metrics.ReporterDropped counter may not reflect them correctly, +// because some of them may still be successfully added to the queue. +func (r *remoteReporter) Report(span *Span) { + select { + case r.queue <- reporterQueueItem{itemType: reporterQueueItemSpan, span: span}: + atomic.AddInt64(&r.queueLength, 1) + default: + r.metrics.ReporterDropped.Inc(1) + } +} + +// Close implements Close() method of Reporter by waiting for the queue to be drained. +func (r *remoteReporter) Close() { + if swapped := atomic.CompareAndSwapInt64(&r.closed, 0, 1); !swapped { + r.logger.Error("Repeated attempt to close the reporter is ignored") + return + } + r.sendCloseEvent() + r.sender.Close() +} + +func (r *remoteReporter) sendCloseEvent() { + wg := &sync.WaitGroup{} + wg.Add(1) + item := reporterQueueItem{itemType: reporterQueueItemClose, close: wg} + + r.queue <- item // if the queue is full we will block until there is space + atomic.AddInt64(&r.queueLength, 1) + wg.Wait() +} + +// processQueue reads spans from the queue, converts them to Thrift, and stores them in an internal buffer. +// When the buffer length reaches batchSize, it is flushed by submitting the accumulated spans to Jaeger. +// Buffer also gets flushed automatically every batchFlushInterval seconds, just in case the tracer stopped +// reporting new spans. +func (r *remoteReporter) processQueue() { + // flush causes the Sender to flush its accumulated spans and clear the buffer + flush := func() { + if flushed, err := r.sender.Flush(); err != nil { + r.metrics.ReporterFailure.Inc(int64(flushed)) + r.logger.Error(fmt.Sprintf("error when flushing the buffer: %s", err.Error())) + } else if flushed > 0 { + r.metrics.ReporterSuccess.Inc(int64(flushed)) + } + } + + timer := time.NewTicker(r.bufferFlushInterval) + for { + select { + case <-timer.C: + flush() + case item := <-r.queue: + atomic.AddInt64(&r.queueLength, -1) + switch item.itemType { + case reporterQueueItemSpan: + span := item.span + if flushed, err := r.sender.Append(span); err != nil { + r.metrics.ReporterFailure.Inc(int64(flushed)) + r.logger.Error(fmt.Sprintf("error reporting span %q: %s", span.OperationName(), err.Error())) + } else if flushed > 0 { + r.metrics.ReporterSuccess.Inc(int64(flushed)) + // to reduce the number of gauge stats, we only emit queue length on flush + r.metrics.ReporterQueueLength.Update(atomic.LoadInt64(&r.queueLength)) + } + case reporterQueueItemClose: + timer.Stop() + flush() + item.close.Done() + return + } + } + } +} diff --git a/vendor/github.com/uber/jaeger-client-go/reporter_options.go b/vendor/github.com/uber/jaeger-client-go/reporter_options.go new file mode 100644 index 0000000000..65012d7015 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/reporter_options.go @@ -0,0 +1,69 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 jaeger + +import ( + "time" +) + +// ReporterOption is a function that sets some option on the reporter. +type ReporterOption func(c *reporterOptions) + +// ReporterOptions is a factory for all available ReporterOption's +var ReporterOptions reporterOptions + +// reporterOptions control behavior of the reporter. +type reporterOptions struct { + // queueSize is the size of internal queue where reported spans are stored before they are processed in the background + queueSize int + // bufferFlushInterval is how often the buffer is force-flushed, even if it's not full + bufferFlushInterval time.Duration + // logger is used to log errors of span submissions + logger Logger + // metrics is used to record runtime stats + metrics *Metrics +} + +// QueueSize creates a ReporterOption that sets the size of the internal queue where +// spans are stored before they are processed. +func (reporterOptions) QueueSize(queueSize int) ReporterOption { + return func(r *reporterOptions) { + r.queueSize = queueSize + } +} + +// Metrics creates a ReporterOption that initializes Metrics in the reporter, +// which is used to record runtime statistics. +func (reporterOptions) Metrics(metrics *Metrics) ReporterOption { + return func(r *reporterOptions) { + r.metrics = metrics + } +} + +// BufferFlushInterval creates a ReporterOption that sets how often the queue +// is force-flushed. +func (reporterOptions) BufferFlushInterval(bufferFlushInterval time.Duration) ReporterOption { + return func(r *reporterOptions) { + r.bufferFlushInterval = bufferFlushInterval + } +} + +// Logger creates a ReporterOption that initializes the logger used to log +// errors of span submissions. +func (reporterOptions) Logger(logger Logger) ReporterOption { + return func(r *reporterOptions) { + r.logger = logger + } +} diff --git a/vendor/github.com/uber/jaeger-client-go/rpcmetrics/README.md b/vendor/github.com/uber/jaeger-client-go/rpcmetrics/README.md new file mode 100644 index 0000000000..879948e9c9 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/rpcmetrics/README.md @@ -0,0 +1,5 @@ +An Observer that can be used to emit RPC metrics +================================================ + +It can be attached to the tracer during tracer construction. +See `ExampleObserver` function in [observer_test.go](./observer_test.go). diff --git a/vendor/github.com/uber/jaeger-client-go/rpcmetrics/doc.go b/vendor/github.com/uber/jaeger-client-go/rpcmetrics/doc.go new file mode 100644 index 0000000000..51aa11b350 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/rpcmetrics/doc.go @@ -0,0 +1,16 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 rpcmetrics implements an Observer that can be used to emit RPC metrics. +package rpcmetrics diff --git a/vendor/github.com/uber/jaeger-client-go/rpcmetrics/endpoints.go b/vendor/github.com/uber/jaeger-client-go/rpcmetrics/endpoints.go new file mode 100644 index 0000000000..30555243d0 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/rpcmetrics/endpoints.go @@ -0,0 +1,63 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 rpcmetrics + +import "sync" + +// normalizedEndpoints is a cache for endpointName -> safeName mappings. +type normalizedEndpoints struct { + names map[string]string + maxSize int + defaultName string + normalizer NameNormalizer + mux sync.RWMutex +} + +func newNormalizedEndpoints(maxSize int, normalizer NameNormalizer) *normalizedEndpoints { + return &normalizedEndpoints{ + maxSize: maxSize, + normalizer: normalizer, + names: make(map[string]string, maxSize), + } +} + +// normalize looks up the name in the cache, if not found it uses normalizer +// to convert the name to a safe name. If called with more than maxSize unique +// names it returns "" for all other names beyond those already cached. +func (n *normalizedEndpoints) normalize(name string) string { + n.mux.RLock() + norm, ok := n.names[name] + l := len(n.names) + n.mux.RUnlock() + if ok { + return norm + } + if l >= n.maxSize { + return "" + } + return n.normalizeWithLock(name) +} + +func (n *normalizedEndpoints) normalizeWithLock(name string) string { + norm := n.normalizer.Normalize(name) + n.mux.Lock() + defer n.mux.Unlock() + // cache may have grown while we were not holding the lock + if len(n.names) >= n.maxSize { + return "" + } + n.names[name] = norm + return norm +} diff --git a/vendor/github.com/uber/jaeger-client-go/rpcmetrics/metrics.go b/vendor/github.com/uber/jaeger-client-go/rpcmetrics/metrics.go new file mode 100644 index 0000000000..ab8d74c291 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/rpcmetrics/metrics.go @@ -0,0 +1,124 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 rpcmetrics + +import ( + "sync" + + "github.com/uber/jaeger-lib/metrics" +) + +const ( + otherEndpointsPlaceholder = "other" + endpointNameMetricTag = "endpoint" +) + +// Metrics is a collection of metrics for an endpoint describing +// throughput, success, errors, and performance. +type Metrics struct { + // RequestCountSuccess is a counter of the total number of successes. + RequestCountSuccess metrics.Counter `metric:"requests" tags:"error=false"` + + // RequestCountFailures is a counter of the number of times any failure has been observed. + RequestCountFailures metrics.Counter `metric:"requests" tags:"error=true"` + + // RequestLatencySuccess is a latency histogram of succesful requests. + RequestLatencySuccess metrics.Timer `metric:"request_latency" tags:"error=false"` + + // RequestLatencyFailures is a latency histogram of failed requests. + RequestLatencyFailures metrics.Timer `metric:"request_latency" tags:"error=true"` + + // HTTPStatusCode2xx is a counter of the total number of requests with HTTP status code 200-299 + HTTPStatusCode2xx metrics.Counter `metric:"http_requests" tags:"status_code=2xx"` + + // HTTPStatusCode3xx is a counter of the total number of requests with HTTP status code 300-399 + HTTPStatusCode3xx metrics.Counter `metric:"http_requests" tags:"status_code=3xx"` + + // HTTPStatusCode4xx is a counter of the total number of requests with HTTP status code 400-499 + HTTPStatusCode4xx metrics.Counter `metric:"http_requests" tags:"status_code=4xx"` + + // HTTPStatusCode5xx is a counter of the total number of requests with HTTP status code 500-599 + HTTPStatusCode5xx metrics.Counter `metric:"http_requests" tags:"status_code=5xx"` +} + +func (m *Metrics) recordHTTPStatusCode(statusCode uint16) { + if statusCode >= 200 && statusCode < 300 { + m.HTTPStatusCode2xx.Inc(1) + } else if statusCode >= 300 && statusCode < 400 { + m.HTTPStatusCode3xx.Inc(1) + } else if statusCode >= 400 && statusCode < 500 { + m.HTTPStatusCode4xx.Inc(1) + } else if statusCode >= 500 && statusCode < 600 { + m.HTTPStatusCode5xx.Inc(1) + } +} + +// MetricsByEndpoint is a registry/cache of metrics for each unique endpoint name. +// Only maxNumberOfEndpoints Metrics are stored, all other endpoint names are mapped +// to a generic endpoint name "other". +type MetricsByEndpoint struct { + metricsFactory metrics.Factory + endpoints *normalizedEndpoints + metricsByEndpoint map[string]*Metrics + mux sync.RWMutex +} + +func newMetricsByEndpoint( + metricsFactory metrics.Factory, + normalizer NameNormalizer, + maxNumberOfEndpoints int, +) *MetricsByEndpoint { + return &MetricsByEndpoint{ + metricsFactory: metricsFactory, + endpoints: newNormalizedEndpoints(maxNumberOfEndpoints, normalizer), + metricsByEndpoint: make(map[string]*Metrics, maxNumberOfEndpoints+1), // +1 for "other" + } +} + +func (m *MetricsByEndpoint) get(endpoint string) *Metrics { + safeName := m.endpoints.normalize(endpoint) + if safeName == "" { + safeName = otherEndpointsPlaceholder + } + m.mux.RLock() + met := m.metricsByEndpoint[safeName] + m.mux.RUnlock() + if met != nil { + return met + } + + return m.getWithWriteLock(safeName) +} + +// split to make easier to test +func (m *MetricsByEndpoint) getWithWriteLock(safeName string) *Metrics { + m.mux.Lock() + defer m.mux.Unlock() + + // it is possible that the name has been already registered after we released + // the read lock and before we grabbed the write lock, so check for that. + if met, ok := m.metricsByEndpoint[safeName]; ok { + return met + } + + // it would be nice to create the struct before locking, since Init() is somewhat + // expensive, however some metrics backends (e.g. expvar) may not like duplicate metrics. + met := &Metrics{} + tags := map[string]string{endpointNameMetricTag: safeName} + metrics.Init(met, m.metricsFactory, tags) + + m.metricsByEndpoint[safeName] = met + return met +} diff --git a/vendor/github.com/uber/jaeger-client-go/rpcmetrics/normalizer.go b/vendor/github.com/uber/jaeger-client-go/rpcmetrics/normalizer.go new file mode 100644 index 0000000000..148d84b3a1 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/rpcmetrics/normalizer.go @@ -0,0 +1,101 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 rpcmetrics + +// NameNormalizer is used to convert the endpoint names to strings +// that can be safely used as tags in the metrics. +type NameNormalizer interface { + Normalize(name string) string +} + +// DefaultNameNormalizer converts endpoint names so that they contain only characters +// from the safe charset [a-zA-Z0-9-./_]. All other characters are replaced with '-'. +var DefaultNameNormalizer = &SimpleNameNormalizer{ + SafeSets: []SafeCharacterSet{ + &Range{From: 'a', To: 'z'}, + &Range{From: 'A', To: 'Z'}, + &Range{From: '0', To: '9'}, + &Char{'-'}, + &Char{'_'}, + &Char{'/'}, + &Char{'.'}, + }, + Replacement: '-', +} + +// SimpleNameNormalizer uses a set of safe character sets. +type SimpleNameNormalizer struct { + SafeSets []SafeCharacterSet + Replacement byte +} + +// SafeCharacterSet determines if the given character is "safe" +type SafeCharacterSet interface { + IsSafe(c byte) bool +} + +// Range implements SafeCharacterSet +type Range struct { + From, To byte +} + +// IsSafe implements SafeCharacterSet +func (r *Range) IsSafe(c byte) bool { + return c >= r.From && c <= r.To +} + +// Char implements SafeCharacterSet +type Char struct { + Val byte +} + +// IsSafe implements SafeCharacterSet +func (ch *Char) IsSafe(c byte) bool { + return c == ch.Val +} + +// Normalize checks each character in the string against SafeSets, +// and if it's not safe substitutes it with Replacement. +func (n *SimpleNameNormalizer) Normalize(name string) string { + var retMe []byte + nameBytes := []byte(name) + for i, b := range nameBytes { + if n.safeByte(b) { + if retMe != nil { + retMe[i] = b + } + } else { + if retMe == nil { + retMe = make([]byte, len(nameBytes)) + copy(retMe[0:i], nameBytes[0:i]) + } + retMe[i] = n.Replacement + } + } + if retMe == nil { + return name + } + return string(retMe) +} + +// safeByte checks if b against all safe charsets. +func (n *SimpleNameNormalizer) safeByte(b byte) bool { + for i := range n.SafeSets { + if n.SafeSets[i].IsSafe(b) { + return true + } + } + return false +} diff --git a/vendor/github.com/uber/jaeger-client-go/rpcmetrics/observer.go b/vendor/github.com/uber/jaeger-client-go/rpcmetrics/observer.go new file mode 100644 index 0000000000..eca5ff6f3b --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/rpcmetrics/observer.go @@ -0,0 +1,171 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 rpcmetrics + +import ( + "strconv" + "sync" + "time" + + "github.com/opentracing/opentracing-go" + "github.com/opentracing/opentracing-go/ext" + "github.com/uber/jaeger-lib/metrics" + + jaeger "github.com/uber/jaeger-client-go" +) + +const defaultMaxNumberOfEndpoints = 200 + +// Observer is an observer that can emit RPC metrics. +type Observer struct { + metricsByEndpoint *MetricsByEndpoint +} + +// NewObserver creates a new observer that can emit RPC metrics. +func NewObserver(metricsFactory metrics.Factory, normalizer NameNormalizer) *Observer { + return &Observer{ + metricsByEndpoint: newMetricsByEndpoint( + metricsFactory, + normalizer, + defaultMaxNumberOfEndpoints, + ), + } +} + +// OnStartSpan creates a new Observer for the span. +func (o *Observer) OnStartSpan( + operationName string, + options opentracing.StartSpanOptions, +) jaeger.SpanObserver { + return NewSpanObserver(o.metricsByEndpoint, operationName, options) +} + +// SpanKind identifies the span as inboud, outbound, or internal +type SpanKind int + +const ( + // Local span kind + Local SpanKind = iota + // Inbound span kind + Inbound + // Outbound span kind + Outbound +) + +// SpanObserver collects RPC metrics +type SpanObserver struct { + metricsByEndpoint *MetricsByEndpoint + operationName string + startTime time.Time + mux sync.Mutex + kind SpanKind + httpStatusCode uint16 + err bool +} + +// NewSpanObserver creates a new SpanObserver that can emit RPC metrics. +func NewSpanObserver( + metricsByEndpoint *MetricsByEndpoint, + operationName string, + options opentracing.StartSpanOptions, +) *SpanObserver { + so := &SpanObserver{ + metricsByEndpoint: metricsByEndpoint, + operationName: operationName, + startTime: options.StartTime, + } + for k, v := range options.Tags { + so.handleTagInLock(k, v) + } + return so +} + +// handleTags watches for special tags +// - SpanKind +// - HttpStatusCode +// - Error +func (so *SpanObserver) handleTagInLock(key string, value interface{}) { + if key == string(ext.SpanKind) { + if v, ok := value.(ext.SpanKindEnum); ok { + value = string(v) + } + if v, ok := value.(string); ok { + if v == string(ext.SpanKindRPCClientEnum) { + so.kind = Outbound + } else if v == string(ext.SpanKindRPCServerEnum) { + so.kind = Inbound + } + } + return + } + if key == string(ext.HTTPStatusCode) { + if v, ok := value.(uint16); ok { + so.httpStatusCode = v + } else if v, ok := value.(int); ok { + so.httpStatusCode = uint16(v) + } else if v, ok := value.(string); ok { + if vv, err := strconv.Atoi(v); err == nil { + so.httpStatusCode = uint16(vv) + } + } + return + } + if key == string(ext.Error) { + if v, ok := value.(bool); ok { + so.err = v + } else if v, ok := value.(string); ok { + if vv, err := strconv.ParseBool(v); err == nil { + so.err = vv + } + } + return + } +} + +// OnFinish emits the RPC metrics. It only has an effect when operation name +// is not blank, and the span kind is an RPC server. +func (so *SpanObserver) OnFinish(options opentracing.FinishOptions) { + so.mux.Lock() + defer so.mux.Unlock() + + if so.operationName == "" || so.kind != Inbound { + return + } + + mets := so.metricsByEndpoint.get(so.operationName) + latency := options.FinishTime.Sub(so.startTime) + if so.err { + mets.RequestCountFailures.Inc(1) + mets.RequestLatencyFailures.Record(latency) + } else { + mets.RequestCountSuccess.Inc(1) + mets.RequestLatencySuccess.Record(latency) + } + mets.recordHTTPStatusCode(so.httpStatusCode) +} + +// OnSetOperationName records new operation name. +func (so *SpanObserver) OnSetOperationName(operationName string) { + so.mux.Lock() + so.operationName = operationName + so.mux.Unlock() +} + +// OnSetTag implements SpanObserver +func (so *SpanObserver) OnSetTag(key string, value interface{}) { + so.mux.Lock() + so.handleTagInLock(key, value) + so.mux.Unlock() +} diff --git a/vendor/github.com/uber/jaeger-client-go/sampler.go b/vendor/github.com/uber/jaeger-client-go/sampler.go new file mode 100644 index 0000000000..e6a32b3837 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/sampler.go @@ -0,0 +1,556 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 jaeger + +import ( + "fmt" + "math" + "net/url" + "sync" + "sync/atomic" + "time" + + "github.com/uber/jaeger-client-go/log" + "github.com/uber/jaeger-client-go/thrift-gen/sampling" + "github.com/uber/jaeger-client-go/utils" +) + +const ( + defaultSamplingServerURL = "http://localhost:5778/sampling" + defaultSamplingRefreshInterval = time.Minute + defaultMaxOperations = 2000 +) + +// Sampler decides whether a new trace should be sampled or not. +type Sampler interface { + // IsSampled decides whether a trace with given `id` and `operation` + // should be sampled. This function will also return the tags that + // can be used to identify the type of sampling that was applied to + // the root span. Most simple samplers would return two tags, + // sampler.type and sampler.param, similar to those used in the Configuration + IsSampled(id TraceID, operation string) (sampled bool, tags []Tag) + + // Close does a clean shutdown of the sampler, stopping any background + // go-routines it may have started. + Close() + + // Equal checks if the `other` sampler is functionally equivalent + // to this sampler. + // TODO remove this function. This function is used to determine if 2 samplers are equivalent + // which does not bode well with the adaptive sampler which has to create all the composite samplers + // for the comparison to occur. This is expensive to do if only one sampler has changed. + Equal(other Sampler) bool +} + +// ----------------------- + +// ConstSampler is a sampler that always makes the same decision. +type ConstSampler struct { + Decision bool + tags []Tag +} + +// NewConstSampler creates a ConstSampler. +func NewConstSampler(sample bool) Sampler { + tags := []Tag{ + {key: SamplerTypeTagKey, value: SamplerTypeConst}, + {key: SamplerParamTagKey, value: sample}, + } + return &ConstSampler{Decision: sample, tags: tags} +} + +// IsSampled implements IsSampled() of Sampler. +func (s *ConstSampler) IsSampled(id TraceID, operation string) (bool, []Tag) { + return s.Decision, s.tags +} + +// Close implements Close() of Sampler. +func (s *ConstSampler) Close() { + // nothing to do +} + +// Equal implements Equal() of Sampler. +func (s *ConstSampler) Equal(other Sampler) bool { + if o, ok := other.(*ConstSampler); ok { + return s.Decision == o.Decision + } + return false +} + +// ----------------------- + +// ProbabilisticSampler is a sampler that randomly samples a certain percentage +// of traces. +type ProbabilisticSampler struct { + samplingRate float64 + samplingBoundary uint64 + tags []Tag +} + +const maxRandomNumber = ^(uint64(1) << 63) // i.e. 0x7fffffffffffffff + +// NewProbabilisticSampler creates a sampler that randomly samples a certain percentage of traces specified by the +// samplingRate, in the range between 0.0 and 1.0. +// +// It relies on the fact that new trace IDs are 63bit random numbers themselves, thus making the sampling decision +// without generating a new random number, but simply calculating if traceID < (samplingRate * 2^63). +// TODO remove the error from this function for next major release +func NewProbabilisticSampler(samplingRate float64) (*ProbabilisticSampler, error) { + if samplingRate < 0.0 || samplingRate > 1.0 { + return nil, fmt.Errorf("Sampling Rate must be between 0.0 and 1.0, received %f", samplingRate) + } + return newProbabilisticSampler(samplingRate), nil +} + +func newProbabilisticSampler(samplingRate float64) *ProbabilisticSampler { + samplingRate = math.Max(0.0, math.Min(samplingRate, 1.0)) + tags := []Tag{ + {key: SamplerTypeTagKey, value: SamplerTypeProbabilistic}, + {key: SamplerParamTagKey, value: samplingRate}, + } + return &ProbabilisticSampler{ + samplingRate: samplingRate, + samplingBoundary: uint64(float64(maxRandomNumber) * samplingRate), + tags: tags, + } +} + +// SamplingRate returns the sampling probability this sampled was constructed with. +func (s *ProbabilisticSampler) SamplingRate() float64 { + return s.samplingRate +} + +// IsSampled implements IsSampled() of Sampler. +func (s *ProbabilisticSampler) IsSampled(id TraceID, operation string) (bool, []Tag) { + return s.samplingBoundary >= id.Low, s.tags +} + +// Close implements Close() of Sampler. +func (s *ProbabilisticSampler) Close() { + // nothing to do +} + +// Equal implements Equal() of Sampler. +func (s *ProbabilisticSampler) Equal(other Sampler) bool { + if o, ok := other.(*ProbabilisticSampler); ok { + return s.samplingBoundary == o.samplingBoundary + } + return false +} + +// ----------------------- + +type rateLimitingSampler struct { + maxTracesPerSecond float64 + rateLimiter utils.RateLimiter + tags []Tag +} + +// NewRateLimitingSampler creates a sampler that samples at most maxTracesPerSecond. The distribution of sampled +// traces follows burstiness of the service, i.e. a service with uniformly distributed requests will have those +// requests sampled uniformly as well, but if requests are bursty, especially sub-second, then a number of +// sequential requests can be sampled each second. +func NewRateLimitingSampler(maxTracesPerSecond float64) Sampler { + tags := []Tag{ + {key: SamplerTypeTagKey, value: SamplerTypeRateLimiting}, + {key: SamplerParamTagKey, value: maxTracesPerSecond}, + } + return &rateLimitingSampler{ + maxTracesPerSecond: maxTracesPerSecond, + rateLimiter: utils.NewRateLimiter(maxTracesPerSecond, math.Max(maxTracesPerSecond, 1.0)), + tags: tags, + } +} + +// IsSampled implements IsSampled() of Sampler. +func (s *rateLimitingSampler) IsSampled(id TraceID, operation string) (bool, []Tag) { + return s.rateLimiter.CheckCredit(1.0), s.tags +} + +func (s *rateLimitingSampler) Close() { + // nothing to do +} + +func (s *rateLimitingSampler) Equal(other Sampler) bool { + if o, ok := other.(*rateLimitingSampler); ok { + return s.maxTracesPerSecond == o.maxTracesPerSecond + } + return false +} + +// ----------------------- + +// GuaranteedThroughputProbabilisticSampler is a sampler that leverages both probabilisticSampler and +// rateLimitingSampler. The rateLimitingSampler is used as a guaranteed lower bound sampler such that +// every operation is sampled at least once in a time interval defined by the lowerBound. ie a lowerBound +// of 1.0 / (60 * 10) will sample an operation at least once every 10 minutes. +// +// The probabilisticSampler is given higher priority when tags are emitted, ie. if IsSampled() for both +// samplers return true, the tags for probabilisticSampler will be used. +type GuaranteedThroughputProbabilisticSampler struct { + probabilisticSampler *ProbabilisticSampler + lowerBoundSampler Sampler + tags []Tag + samplingRate float64 + lowerBound float64 +} + +// NewGuaranteedThroughputProbabilisticSampler returns a delegating sampler that applies both +// probabilisticSampler and rateLimitingSampler. +func NewGuaranteedThroughputProbabilisticSampler( + lowerBound, samplingRate float64, +) (*GuaranteedThroughputProbabilisticSampler, error) { + return newGuaranteedThroughputProbabilisticSampler(lowerBound, samplingRate), nil +} + +func newGuaranteedThroughputProbabilisticSampler(lowerBound, samplingRate float64) *GuaranteedThroughputProbabilisticSampler { + s := &GuaranteedThroughputProbabilisticSampler{ + lowerBoundSampler: NewRateLimitingSampler(lowerBound), + lowerBound: lowerBound, + } + s.setProbabilisticSampler(samplingRate) + return s +} + +func (s *GuaranteedThroughputProbabilisticSampler) setProbabilisticSampler(samplingRate float64) { + if s.probabilisticSampler == nil || s.samplingRate != samplingRate { + s.probabilisticSampler = newProbabilisticSampler(samplingRate) + s.samplingRate = s.probabilisticSampler.SamplingRate() + s.tags = []Tag{ + {key: SamplerTypeTagKey, value: SamplerTypeLowerBound}, + {key: SamplerParamTagKey, value: s.samplingRate}, + } + } +} + +// IsSampled implements IsSampled() of Sampler. +func (s *GuaranteedThroughputProbabilisticSampler) IsSampled(id TraceID, operation string) (bool, []Tag) { + if sampled, tags := s.probabilisticSampler.IsSampled(id, operation); sampled { + s.lowerBoundSampler.IsSampled(id, operation) + return true, tags + } + sampled, _ := s.lowerBoundSampler.IsSampled(id, operation) + return sampled, s.tags +} + +// Close implements Close() of Sampler. +func (s *GuaranteedThroughputProbabilisticSampler) Close() { + s.probabilisticSampler.Close() + s.lowerBoundSampler.Close() +} + +// Equal implements Equal() of Sampler. +func (s *GuaranteedThroughputProbabilisticSampler) Equal(other Sampler) bool { + // NB The Equal() function is expensive and will be removed. See adaptiveSampler.Equal() for + // more information. + return false +} + +// this function should only be called while holding a Write lock +func (s *GuaranteedThroughputProbabilisticSampler) update(lowerBound, samplingRate float64) { + s.setProbabilisticSampler(samplingRate) + if s.lowerBound != lowerBound { + s.lowerBoundSampler = NewRateLimitingSampler(lowerBound) + s.lowerBound = lowerBound + } +} + +// ----------------------- + +type adaptiveSampler struct { + sync.RWMutex + + samplers map[string]*GuaranteedThroughputProbabilisticSampler + defaultSampler *ProbabilisticSampler + lowerBound float64 + maxOperations int +} + +// NewAdaptiveSampler returns a delegating sampler that applies both probabilisticSampler and +// rateLimitingSampler via the guaranteedThroughputProbabilisticSampler. This sampler keeps track of all +// operations and delegates calls to the respective guaranteedThroughputProbabilisticSampler. +func NewAdaptiveSampler(strategies *sampling.PerOperationSamplingStrategies, maxOperations int) (Sampler, error) { + return newAdaptiveSampler(strategies, maxOperations), nil +} + +func newAdaptiveSampler(strategies *sampling.PerOperationSamplingStrategies, maxOperations int) Sampler { + samplers := make(map[string]*GuaranteedThroughputProbabilisticSampler) + for _, strategy := range strategies.PerOperationStrategies { + sampler := newGuaranteedThroughputProbabilisticSampler( + strategies.DefaultLowerBoundTracesPerSecond, + strategy.ProbabilisticSampling.SamplingRate, + ) + samplers[strategy.Operation] = sampler + } + return &adaptiveSampler{ + samplers: samplers, + defaultSampler: newProbabilisticSampler(strategies.DefaultSamplingProbability), + lowerBound: strategies.DefaultLowerBoundTracesPerSecond, + maxOperations: maxOperations, + } +} + +func (s *adaptiveSampler) IsSampled(id TraceID, operation string) (bool, []Tag) { + s.RLock() + sampler, ok := s.samplers[operation] + if ok { + defer s.RUnlock() + return sampler.IsSampled(id, operation) + } + s.RUnlock() + s.Lock() + defer s.Unlock() + + // Check if sampler has already been created + sampler, ok = s.samplers[operation] + if ok { + return sampler.IsSampled(id, operation) + } + // Store only up to maxOperations of unique ops. + if len(s.samplers) >= s.maxOperations { + return s.defaultSampler.IsSampled(id, operation) + } + newSampler := newGuaranteedThroughputProbabilisticSampler(s.lowerBound, s.defaultSampler.SamplingRate()) + s.samplers[operation] = newSampler + return newSampler.IsSampled(id, operation) +} + +func (s *adaptiveSampler) Close() { + s.Lock() + defer s.Unlock() + for _, sampler := range s.samplers { + sampler.Close() + } + s.defaultSampler.Close() +} + +func (s *adaptiveSampler) Equal(other Sampler) bool { + // NB The Equal() function is overly expensive for adaptiveSampler since it's composed of multiple + // samplers which all need to be initialized before this function can be called for a comparison. + // Therefore, adaptiveSampler uses the update() function to only alter the samplers that need + // changing. Hence this function always returns false so that the update function can be called. + // Once the Equal() function is removed from the Sampler API, this will no longer be needed. + return false +} + +func (s *adaptiveSampler) update(strategies *sampling.PerOperationSamplingStrategies) { + s.Lock() + defer s.Unlock() + for _, strategy := range strategies.PerOperationStrategies { + operation := strategy.Operation + samplingRate := strategy.ProbabilisticSampling.SamplingRate + lowerBound := strategies.DefaultLowerBoundTracesPerSecond + if sampler, ok := s.samplers[operation]; ok { + sampler.update(lowerBound, samplingRate) + } else { + sampler := newGuaranteedThroughputProbabilisticSampler( + lowerBound, + samplingRate, + ) + s.samplers[operation] = sampler + } + } + s.lowerBound = strategies.DefaultLowerBoundTracesPerSecond + if s.defaultSampler.SamplingRate() != strategies.DefaultSamplingProbability { + s.defaultSampler = newProbabilisticSampler(strategies.DefaultSamplingProbability) + } +} + +// ----------------------- + +// RemotelyControlledSampler is a delegating sampler that polls a remote server +// for the appropriate sampling strategy, constructs a corresponding sampler and +// delegates to it for sampling decisions. +type RemotelyControlledSampler struct { + // These fields must be first in the struct because `sync/atomic` expects 64-bit alignment. + // Cf. https://github.com/uber/jaeger-client-go/issues/155, https://goo.gl/zW7dgq + closed int64 // 0 - not closed, 1 - closed + + sync.RWMutex + samplerOptions + + serviceName string + manager sampling.SamplingManager + doneChan chan *sync.WaitGroup +} + +type httpSamplingManager struct { + serverURL string +} + +func (s *httpSamplingManager) GetSamplingStrategy(serviceName string) (*sampling.SamplingStrategyResponse, error) { + var out sampling.SamplingStrategyResponse + v := url.Values{} + v.Set("service", serviceName) + if err := utils.GetJSON(s.serverURL+"?"+v.Encode(), &out); err != nil { + return nil, err + } + return &out, nil +} + +// NewRemotelyControlledSampler creates a sampler that periodically pulls +// the sampling strategy from an HTTP sampling server (e.g. jaeger-agent). +func NewRemotelyControlledSampler( + serviceName string, + opts ...SamplerOption, +) *RemotelyControlledSampler { + options := applySamplerOptions(opts...) + sampler := &RemotelyControlledSampler{ + samplerOptions: options, + serviceName: serviceName, + manager: &httpSamplingManager{serverURL: options.samplingServerURL}, + doneChan: make(chan *sync.WaitGroup), + } + go sampler.pollController() + return sampler +} + +func applySamplerOptions(opts ...SamplerOption) samplerOptions { + options := samplerOptions{} + for _, option := range opts { + option(&options) + } + if options.sampler == nil { + options.sampler = newProbabilisticSampler(0.001) + } + if options.logger == nil { + options.logger = log.NullLogger + } + if options.maxOperations <= 0 { + options.maxOperations = defaultMaxOperations + } + if options.samplingServerURL == "" { + options.samplingServerURL = defaultSamplingServerURL + } + if options.metrics == nil { + options.metrics = NewNullMetrics() + } + if options.samplingRefreshInterval <= 0 { + options.samplingRefreshInterval = defaultSamplingRefreshInterval + } + return options +} + +// IsSampled implements IsSampled() of Sampler. +func (s *RemotelyControlledSampler) IsSampled(id TraceID, operation string) (bool, []Tag) { + s.RLock() + defer s.RUnlock() + return s.sampler.IsSampled(id, operation) +} + +// Close implements Close() of Sampler. +func (s *RemotelyControlledSampler) Close() { + if swapped := atomic.CompareAndSwapInt64(&s.closed, 0, 1); !swapped { + s.logger.Error("Repeated attempt to close the sampler is ignored") + return + } + + var wg sync.WaitGroup + wg.Add(1) + s.doneChan <- &wg + wg.Wait() +} + +// Equal implements Equal() of Sampler. +func (s *RemotelyControlledSampler) Equal(other Sampler) bool { + // NB The Equal() function is expensive and will be removed. See adaptiveSampler.Equal() for + // more information. + if o, ok := other.(*RemotelyControlledSampler); ok { + s.RLock() + o.RLock() + defer s.RUnlock() + defer o.RUnlock() + return s.sampler.Equal(o.sampler) + } + return false +} + +func (s *RemotelyControlledSampler) pollController() { + ticker := time.NewTicker(s.samplingRefreshInterval) + defer ticker.Stop() + s.pollControllerWithTicker(ticker) +} + +func (s *RemotelyControlledSampler) pollControllerWithTicker(ticker *time.Ticker) { + for { + select { + case <-ticker.C: + s.updateSampler() + case wg := <-s.doneChan: + wg.Done() + return + } + } +} + +func (s *RemotelyControlledSampler) getSampler() Sampler { + s.Lock() + defer s.Unlock() + return s.sampler +} + +func (s *RemotelyControlledSampler) setSampler(sampler Sampler) { + s.Lock() + defer s.Unlock() + s.sampler = sampler +} + +func (s *RemotelyControlledSampler) updateSampler() { + res, err := s.manager.GetSamplingStrategy(s.serviceName) + if err != nil { + s.metrics.SamplerQueryFailure.Inc(1) + return + } + s.Lock() + defer s.Unlock() + + s.metrics.SamplerRetrieved.Inc(1) + if strategies := res.GetOperationSampling(); strategies != nil { + s.updateAdaptiveSampler(strategies) + } else { + err = s.updateRateLimitingOrProbabilisticSampler(res) + } + if err != nil { + s.metrics.SamplerUpdateFailure.Inc(1) + s.logger.Infof("Unable to handle sampling strategy response %+v. Got error: %v", res, err) + return + } + s.metrics.SamplerUpdated.Inc(1) +} + +// NB: this function should only be called while holding a Write lock +func (s *RemotelyControlledSampler) updateAdaptiveSampler(strategies *sampling.PerOperationSamplingStrategies) { + if adaptiveSampler, ok := s.sampler.(*adaptiveSampler); ok { + adaptiveSampler.update(strategies) + } else { + s.sampler = newAdaptiveSampler(strategies, s.maxOperations) + } +} + +// NB: this function should only be called while holding a Write lock +func (s *RemotelyControlledSampler) updateRateLimitingOrProbabilisticSampler(res *sampling.SamplingStrategyResponse) error { + var newSampler Sampler + if probabilistic := res.GetProbabilisticSampling(); probabilistic != nil { + newSampler = newProbabilisticSampler(probabilistic.SamplingRate) + } else if rateLimiting := res.GetRateLimitingSampling(); rateLimiting != nil { + newSampler = NewRateLimitingSampler(float64(rateLimiting.MaxTracesPerSecond)) + } else { + return fmt.Errorf("Unsupported sampling strategy type %v", res.GetStrategyType()) + } + if !s.sampler.Equal(newSampler) { + s.sampler = newSampler + } + return nil +} diff --git a/vendor/github.com/uber/jaeger-client-go/sampler_options.go b/vendor/github.com/uber/jaeger-client-go/sampler_options.go new file mode 100644 index 0000000000..75d28a5611 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/sampler_options.go @@ -0,0 +1,81 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 jaeger + +import ( + "time" +) + +// SamplerOption is a function that sets some option on the sampler +type SamplerOption func(options *samplerOptions) + +// SamplerOptions is a factory for all available SamplerOption's +var SamplerOptions samplerOptions + +type samplerOptions struct { + metrics *Metrics + maxOperations int + sampler Sampler + logger Logger + samplingServerURL string + samplingRefreshInterval time.Duration +} + +// Metrics creates a SamplerOption that initializes Metrics on the sampler, +// which is used to emit statistics. +func (samplerOptions) Metrics(m *Metrics) SamplerOption { + return func(o *samplerOptions) { + o.metrics = m + } +} + +// MaxOperations creates a SamplerOption that sets the maximum number of +// operations the sampler will keep track of. +func (samplerOptions) MaxOperations(maxOperations int) SamplerOption { + return func(o *samplerOptions) { + o.maxOperations = maxOperations + } +} + +// InitialSampler creates a SamplerOption that sets the initial sampler +// to use before a remote sampler is created and used. +func (samplerOptions) InitialSampler(sampler Sampler) SamplerOption { + return func(o *samplerOptions) { + o.sampler = sampler + } +} + +// Logger creates a SamplerOption that sets the logger used by the sampler. +func (samplerOptions) Logger(logger Logger) SamplerOption { + return func(o *samplerOptions) { + o.logger = logger + } +} + +// SamplingServerURL creates a SamplerOption that sets the sampling server url +// of the local agent that contains the sampling strategies. +func (samplerOptions) SamplingServerURL(samplingServerURL string) SamplerOption { + return func(o *samplerOptions) { + o.samplingServerURL = samplingServerURL + } +} + +// SamplingRefreshInterval creates a SamplerOption that sets how often the +// sampler will poll local agent for the appropriate sampling strategy. +func (samplerOptions) SamplingRefreshInterval(samplingRefreshInterval time.Duration) SamplerOption { + return func(o *samplerOptions) { + o.samplingRefreshInterval = samplingRefreshInterval + } +} diff --git a/vendor/github.com/uber/jaeger-client-go/span.go b/vendor/github.com/uber/jaeger-client-go/span.go new file mode 100644 index 0000000000..f0b497a90a --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/span.go @@ -0,0 +1,249 @@ +// Copyright (c) 2017-2018 Uber Technologies, Inc. +// +// 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 jaeger + +import ( + "sync" + "time" + + "github.com/opentracing/opentracing-go" + "github.com/opentracing/opentracing-go/ext" + "github.com/opentracing/opentracing-go/log" +) + +// Span implements opentracing.Span +type Span struct { + sync.RWMutex + + tracer *Tracer + + context SpanContext + + // The name of the "operation" this span is an instance of. + // Known as a "span name" in some implementations. + operationName string + + // firstInProcess, if true, indicates that this span is the root of the (sub)tree + // of spans in the current process. In other words it's true for the root spans, + // and the ingress spans when the process joins another trace. + firstInProcess bool + + // startTime is the timestamp indicating when the span began, with microseconds precision. + startTime time.Time + + // duration returns duration of the span with microseconds precision. + // Zero value means duration is unknown. + duration time.Duration + + // tags attached to this span + tags []Tag + + // The span's "micro-log" + logs []opentracing.LogRecord + + // references for this span + references []Reference + + observer ContribSpanObserver +} + +// Tag is a simple key value wrapper. +// TODO deprecate in the next major release, use opentracing.Tag instead. +type Tag struct { + key string + value interface{} +} + +// SetOperationName sets or changes the operation name. +func (s *Span) SetOperationName(operationName string) opentracing.Span { + s.Lock() + defer s.Unlock() + if s.context.IsSampled() { + s.operationName = operationName + } + s.observer.OnSetOperationName(operationName) + return s +} + +// SetTag implements SetTag() of opentracing.Span +func (s *Span) SetTag(key string, value interface{}) opentracing.Span { + s.observer.OnSetTag(key, value) + if key == string(ext.SamplingPriority) && !setSamplingPriority(s, value) { + return s + } + s.Lock() + defer s.Unlock() + if s.context.IsSampled() { + s.setTagNoLocking(key, value) + } + return s +} + +func (s *Span) setTagNoLocking(key string, value interface{}) { + s.tags = append(s.tags, Tag{key: key, value: value}) +} + +// LogFields implements opentracing.Span API +func (s *Span) LogFields(fields ...log.Field) { + s.Lock() + defer s.Unlock() + if !s.context.IsSampled() { + return + } + s.logFieldsNoLocking(fields...) +} + +// this function should only be called while holding a Write lock +func (s *Span) logFieldsNoLocking(fields ...log.Field) { + lr := opentracing.LogRecord{ + Fields: fields, + Timestamp: time.Now(), + } + s.appendLog(lr) +} + +// LogKV implements opentracing.Span API +func (s *Span) LogKV(alternatingKeyValues ...interface{}) { + s.RLock() + sampled := s.context.IsSampled() + s.RUnlock() + if !sampled { + return + } + fields, err := log.InterleavedKVToFields(alternatingKeyValues...) + if err != nil { + s.LogFields(log.Error(err), log.String("function", "LogKV")) + return + } + s.LogFields(fields...) +} + +// LogEvent implements opentracing.Span API +func (s *Span) LogEvent(event string) { + s.Log(opentracing.LogData{Event: event}) +} + +// LogEventWithPayload implements opentracing.Span API +func (s *Span) LogEventWithPayload(event string, payload interface{}) { + s.Log(opentracing.LogData{Event: event, Payload: payload}) +} + +// Log implements opentracing.Span API +func (s *Span) Log(ld opentracing.LogData) { + s.Lock() + defer s.Unlock() + if s.context.IsSampled() { + if ld.Timestamp.IsZero() { + ld.Timestamp = s.tracer.timeNow() + } + s.appendLog(ld.ToLogRecord()) + } +} + +// this function should only be called while holding a Write lock +func (s *Span) appendLog(lr opentracing.LogRecord) { + // TODO add logic to limit number of logs per span (issue #46) + s.logs = append(s.logs, lr) +} + +// SetBaggageItem implements SetBaggageItem() of opentracing.SpanContext +func (s *Span) SetBaggageItem(key, value string) opentracing.Span { + s.Lock() + defer s.Unlock() + s.tracer.setBaggage(s, key, value) + return s +} + +// BaggageItem implements BaggageItem() of opentracing.SpanContext +func (s *Span) BaggageItem(key string) string { + s.RLock() + defer s.RUnlock() + return s.context.baggage[key] +} + +// Finish implements opentracing.Span API +func (s *Span) Finish() { + s.FinishWithOptions(opentracing.FinishOptions{}) +} + +// FinishWithOptions implements opentracing.Span API +func (s *Span) FinishWithOptions(options opentracing.FinishOptions) { + if options.FinishTime.IsZero() { + options.FinishTime = s.tracer.timeNow() + } + s.observer.OnFinish(options) + s.Lock() + if s.context.IsSampled() { + s.duration = options.FinishTime.Sub(s.startTime) + // Note: bulk logs are not subject to maxLogsPerSpan limit + if options.LogRecords != nil { + s.logs = append(s.logs, options.LogRecords...) + } + for _, ld := range options.BulkLogData { + s.logs = append(s.logs, ld.ToLogRecord()) + } + } + s.Unlock() + // call reportSpan even for non-sampled traces, to return span to the pool + s.tracer.reportSpan(s) +} + +// Context implements opentracing.Span API +func (s *Span) Context() opentracing.SpanContext { + s.Lock() + defer s.Unlock() + return s.context +} + +// Tracer implements opentracing.Span API +func (s *Span) Tracer() opentracing.Tracer { + return s.tracer +} + +func (s *Span) String() string { + s.RLock() + defer s.RUnlock() + return s.context.String() +} + +// OperationName allows retrieving current operation name. +func (s *Span) OperationName() string { + s.RLock() + defer s.RUnlock() + return s.operationName +} + +func (s *Span) serviceName() string { + return s.tracer.serviceName +} + +// setSamplingPriority returns true if the flag was updated successfully, false otherwise. +func setSamplingPriority(s *Span, value interface{}) bool { + s.Lock() + defer s.Unlock() + val, ok := value.(uint16) + if !ok { + return false + } + if val == 0 { + s.context.flags = s.context.flags & (^flagSampled) + return true + } + if s.tracer.isDebugAllowed(s.operationName) { + s.context.flags = s.context.flags | flagDebug | flagSampled + return true + } + return false +} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift-gen/agent/agent.go b/vendor/github.com/uber/jaeger-client-go/thrift-gen/agent/agent.go new file mode 100644 index 0000000000..e48811c500 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/thrift-gen/agent/agent.go @@ -0,0 +1,411 @@ +// Autogenerated by Thrift Compiler (0.9.3) +// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + +package agent + +import ( + "bytes" + "fmt" + "github.com/uber/jaeger-client-go/thrift" + "github.com/uber/jaeger-client-go/thrift-gen/jaeger" + "github.com/uber/jaeger-client-go/thrift-gen/zipkincore" +) + +// (needed to ensure safety because of naive import list construction.) +var _ = thrift.ZERO +var _ = fmt.Printf +var _ = bytes.Equal + +var _ = jaeger.GoUnusedProtection__ +var _ = zipkincore.GoUnusedProtection__ + +type Agent interface { + // Parameters: + // - Spans + EmitZipkinBatch(spans []*zipkincore.Span) (err error) + // Parameters: + // - Batch + EmitBatch(batch *jaeger.Batch) (err error) +} + +type AgentClient struct { + Transport thrift.TTransport + ProtocolFactory thrift.TProtocolFactory + InputProtocol thrift.TProtocol + OutputProtocol thrift.TProtocol + SeqId int32 +} + +func NewAgentClientFactory(t thrift.TTransport, f thrift.TProtocolFactory) *AgentClient { + return &AgentClient{Transport: t, + ProtocolFactory: f, + InputProtocol: f.GetProtocol(t), + OutputProtocol: f.GetProtocol(t), + SeqId: 0, + } +} + +func NewAgentClientProtocol(t thrift.TTransport, iprot thrift.TProtocol, oprot thrift.TProtocol) *AgentClient { + return &AgentClient{Transport: t, + ProtocolFactory: nil, + InputProtocol: iprot, + OutputProtocol: oprot, + SeqId: 0, + } +} + +// Parameters: +// - Spans +func (p *AgentClient) EmitZipkinBatch(spans []*zipkincore.Span) (err error) { + if err = p.sendEmitZipkinBatch(spans); err != nil { + return + } + return +} + +func (p *AgentClient) sendEmitZipkinBatch(spans []*zipkincore.Span) (err error) { + oprot := p.OutputProtocol + if oprot == nil { + oprot = p.ProtocolFactory.GetProtocol(p.Transport) + p.OutputProtocol = oprot + } + p.SeqId++ + if err = oprot.WriteMessageBegin("emitZipkinBatch", thrift.ONEWAY, p.SeqId); err != nil { + return + } + args := AgentEmitZipkinBatchArgs{ + Spans: spans, + } + if err = args.Write(oprot); err != nil { + return + } + if err = oprot.WriteMessageEnd(); err != nil { + return + } + return oprot.Flush() +} + +// Parameters: +// - Batch +func (p *AgentClient) EmitBatch(batch *jaeger.Batch) (err error) { + if err = p.sendEmitBatch(batch); err != nil { + return + } + return +} + +func (p *AgentClient) sendEmitBatch(batch *jaeger.Batch) (err error) { + oprot := p.OutputProtocol + if oprot == nil { + oprot = p.ProtocolFactory.GetProtocol(p.Transport) + p.OutputProtocol = oprot + } + p.SeqId++ + if err = oprot.WriteMessageBegin("emitBatch", thrift.ONEWAY, p.SeqId); err != nil { + return + } + args := AgentEmitBatchArgs{ + Batch: batch, + } + if err = args.Write(oprot); err != nil { + return + } + if err = oprot.WriteMessageEnd(); err != nil { + return + } + return oprot.Flush() +} + +type AgentProcessor struct { + processorMap map[string]thrift.TProcessorFunction + handler Agent +} + +func (p *AgentProcessor) AddToProcessorMap(key string, processor thrift.TProcessorFunction) { + p.processorMap[key] = processor +} + +func (p *AgentProcessor) GetProcessorFunction(key string) (processor thrift.TProcessorFunction, ok bool) { + processor, ok = p.processorMap[key] + return processor, ok +} + +func (p *AgentProcessor) ProcessorMap() map[string]thrift.TProcessorFunction { + return p.processorMap +} + +func NewAgentProcessor(handler Agent) *AgentProcessor { + + self0 := &AgentProcessor{handler: handler, processorMap: make(map[string]thrift.TProcessorFunction)} + self0.processorMap["emitZipkinBatch"] = &agentProcessorEmitZipkinBatch{handler: handler} + self0.processorMap["emitBatch"] = &agentProcessorEmitBatch{handler: handler} + return self0 +} + +func (p *AgentProcessor) Process(iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { + name, _, seqId, err := iprot.ReadMessageBegin() + if err != nil { + return false, err + } + if processor, ok := p.GetProcessorFunction(name); ok { + return processor.Process(seqId, iprot, oprot) + } + iprot.Skip(thrift.STRUCT) + iprot.ReadMessageEnd() + x1 := thrift.NewTApplicationException(thrift.UNKNOWN_METHOD, "Unknown function "+name) + oprot.WriteMessageBegin(name, thrift.EXCEPTION, seqId) + x1.Write(oprot) + oprot.WriteMessageEnd() + oprot.Flush() + return false, x1 + +} + +type agentProcessorEmitZipkinBatch struct { + handler Agent +} + +func (p *agentProcessorEmitZipkinBatch) Process(seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { + args := AgentEmitZipkinBatchArgs{} + if err = args.Read(iprot); err != nil { + iprot.ReadMessageEnd() + return false, err + } + + iprot.ReadMessageEnd() + var err2 error + if err2 = p.handler.EmitZipkinBatch(args.Spans); err2 != nil { + return true, err2 + } + return true, nil +} + +type agentProcessorEmitBatch struct { + handler Agent +} + +func (p *agentProcessorEmitBatch) Process(seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { + args := AgentEmitBatchArgs{} + if err = args.Read(iprot); err != nil { + iprot.ReadMessageEnd() + return false, err + } + + iprot.ReadMessageEnd() + var err2 error + if err2 = p.handler.EmitBatch(args.Batch); err2 != nil { + return true, err2 + } + return true, nil +} + +// HELPER FUNCTIONS AND STRUCTURES + +// Attributes: +// - Spans +type AgentEmitZipkinBatchArgs struct { + Spans []*zipkincore.Span `thrift:"spans,1" json:"spans"` +} + +func NewAgentEmitZipkinBatchArgs() *AgentEmitZipkinBatchArgs { + return &AgentEmitZipkinBatchArgs{} +} + +func (p *AgentEmitZipkinBatchArgs) GetSpans() []*zipkincore.Span { + return p.Spans +} +func (p *AgentEmitZipkinBatchArgs) Read(iprot thrift.TProtocol) error { + if _, err := iprot.ReadStructBegin(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) + } + + for { + _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() + if err != nil { + return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) + } + if fieldTypeId == thrift.STOP { + break + } + switch fieldId { + case 1: + if err := p.readField1(iprot); err != nil { + return err + } + default: + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + if err := iprot.ReadFieldEnd(); err != nil { + return err + } + } + if err := iprot.ReadStructEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) + } + return nil +} + +func (p *AgentEmitZipkinBatchArgs) readField1(iprot thrift.TProtocol) error { + _, size, err := iprot.ReadListBegin() + if err != nil { + return thrift.PrependError("error reading list begin: ", err) + } + tSlice := make([]*zipkincore.Span, 0, size) + p.Spans = tSlice + for i := 0; i < size; i++ { + _elem2 := &zipkincore.Span{} + if err := _elem2.Read(iprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", _elem2), err) + } + p.Spans = append(p.Spans, _elem2) + } + if err := iprot.ReadListEnd(); err != nil { + return thrift.PrependError("error reading list end: ", err) + } + return nil +} + +func (p *AgentEmitZipkinBatchArgs) Write(oprot thrift.TProtocol) error { + if err := oprot.WriteStructBegin("emitZipkinBatch_args"); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) + } + if err := p.writeField1(oprot); err != nil { + return err + } + if err := oprot.WriteFieldStop(); err != nil { + return thrift.PrependError("write field stop error: ", err) + } + if err := oprot.WriteStructEnd(); err != nil { + return thrift.PrependError("write struct stop error: ", err) + } + return nil +} + +func (p *AgentEmitZipkinBatchArgs) writeField1(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("spans", thrift.LIST, 1); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:spans: ", p), err) + } + if err := oprot.WriteListBegin(thrift.STRUCT, len(p.Spans)); err != nil { + return thrift.PrependError("error writing list begin: ", err) + } + for _, v := range p.Spans { + if err := v.Write(oprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", v), err) + } + } + if err := oprot.WriteListEnd(); err != nil { + return thrift.PrependError("error writing list end: ", err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 1:spans: ", p), err) + } + return err +} + +func (p *AgentEmitZipkinBatchArgs) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("AgentEmitZipkinBatchArgs(%+v)", *p) +} + +// Attributes: +// - Batch +type AgentEmitBatchArgs struct { + Batch *jaeger.Batch `thrift:"batch,1" json:"batch"` +} + +func NewAgentEmitBatchArgs() *AgentEmitBatchArgs { + return &AgentEmitBatchArgs{} +} + +var AgentEmitBatchArgs_Batch_DEFAULT *jaeger.Batch + +func (p *AgentEmitBatchArgs) GetBatch() *jaeger.Batch { + if !p.IsSetBatch() { + return AgentEmitBatchArgs_Batch_DEFAULT + } + return p.Batch +} +func (p *AgentEmitBatchArgs) IsSetBatch() bool { + return p.Batch != nil +} + +func (p *AgentEmitBatchArgs) Read(iprot thrift.TProtocol) error { + if _, err := iprot.ReadStructBegin(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) + } + + for { + _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() + if err != nil { + return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) + } + if fieldTypeId == thrift.STOP { + break + } + switch fieldId { + case 1: + if err := p.readField1(iprot); err != nil { + return err + } + default: + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + if err := iprot.ReadFieldEnd(); err != nil { + return err + } + } + if err := iprot.ReadStructEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) + } + return nil +} + +func (p *AgentEmitBatchArgs) readField1(iprot thrift.TProtocol) error { + p.Batch = &jaeger.Batch{} + if err := p.Batch.Read(iprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", p.Batch), err) + } + return nil +} + +func (p *AgentEmitBatchArgs) Write(oprot thrift.TProtocol) error { + if err := oprot.WriteStructBegin("emitBatch_args"); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) + } + if err := p.writeField1(oprot); err != nil { + return err + } + if err := oprot.WriteFieldStop(); err != nil { + return thrift.PrependError("write field stop error: ", err) + } + if err := oprot.WriteStructEnd(); err != nil { + return thrift.PrependError("write struct stop error: ", err) + } + return nil +} + +func (p *AgentEmitBatchArgs) writeField1(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("batch", thrift.STRUCT, 1); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:batch: ", p), err) + } + if err := p.Batch.Write(oprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", p.Batch), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 1:batch: ", p), err) + } + return err +} + +func (p *AgentEmitBatchArgs) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("AgentEmitBatchArgs(%+v)", *p) +} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift-gen/agent/constants.go b/vendor/github.com/uber/jaeger-client-go/thrift-gen/agent/constants.go new file mode 100644 index 0000000000..aa9857bb82 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/thrift-gen/agent/constants.go @@ -0,0 +1,23 @@ +// Autogenerated by Thrift Compiler (0.9.3) +// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + +package agent + +import ( + "bytes" + "fmt" + "github.com/uber/jaeger-client-go/thrift" + "github.com/uber/jaeger-client-go/thrift-gen/jaeger" + "github.com/uber/jaeger-client-go/thrift-gen/zipkincore" +) + +// (needed to ensure safety because of naive import list construction.) +var _ = thrift.ZERO +var _ = fmt.Printf +var _ = bytes.Equal + +var _ = jaeger.GoUnusedProtection__ +var _ = zipkincore.GoUnusedProtection__ + +func init() { +} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift-gen/agent/ttypes.go b/vendor/github.com/uber/jaeger-client-go/thrift-gen/agent/ttypes.go new file mode 100644 index 0000000000..9c28f11c1a --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/thrift-gen/agent/ttypes.go @@ -0,0 +1,21 @@ +// Autogenerated by Thrift Compiler (0.9.3) +// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + +package agent + +import ( + "bytes" + "fmt" + "github.com/uber/jaeger-client-go/thrift" + "github.com/uber/jaeger-client-go/thrift-gen/jaeger" + "github.com/uber/jaeger-client-go/thrift-gen/zipkincore" +) + +// (needed to ensure safety because of naive import list construction.) +var _ = thrift.ZERO +var _ = fmt.Printf +var _ = bytes.Equal + +var _ = jaeger.GoUnusedProtection__ +var _ = zipkincore.GoUnusedProtection__ +var GoUnusedProtection__ int diff --git a/vendor/github.com/uber/jaeger-client-go/thrift-gen/baggage/baggagerestrictionmanager.go b/vendor/github.com/uber/jaeger-client-go/thrift-gen/baggage/baggagerestrictionmanager.go new file mode 100644 index 0000000000..1f79c1255c --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/thrift-gen/baggage/baggagerestrictionmanager.go @@ -0,0 +1,435 @@ +// Autogenerated by Thrift Compiler (0.9.3) +// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + +package baggage + +import ( + "bytes" + "fmt" + "github.com/uber/jaeger-client-go/thrift" +) + +// (needed to ensure safety because of naive import list construction.) +var _ = thrift.ZERO +var _ = fmt.Printf +var _ = bytes.Equal + +type BaggageRestrictionManager interface { + // getBaggageRestrictions retrieves the baggage restrictions for a specific service. + // Usually, baggageRestrictions apply to all services however there may be situations + // where a baggageKey might only be allowed to be set by a specific service. + // + // Parameters: + // - ServiceName + GetBaggageRestrictions(serviceName string) (r []*BaggageRestriction, err error) +} + +type BaggageRestrictionManagerClient struct { + Transport thrift.TTransport + ProtocolFactory thrift.TProtocolFactory + InputProtocol thrift.TProtocol + OutputProtocol thrift.TProtocol + SeqId int32 +} + +func NewBaggageRestrictionManagerClientFactory(t thrift.TTransport, f thrift.TProtocolFactory) *BaggageRestrictionManagerClient { + return &BaggageRestrictionManagerClient{Transport: t, + ProtocolFactory: f, + InputProtocol: f.GetProtocol(t), + OutputProtocol: f.GetProtocol(t), + SeqId: 0, + } +} + +func NewBaggageRestrictionManagerClientProtocol(t thrift.TTransport, iprot thrift.TProtocol, oprot thrift.TProtocol) *BaggageRestrictionManagerClient { + return &BaggageRestrictionManagerClient{Transport: t, + ProtocolFactory: nil, + InputProtocol: iprot, + OutputProtocol: oprot, + SeqId: 0, + } +} + +// getBaggageRestrictions retrieves the baggage restrictions for a specific service. +// Usually, baggageRestrictions apply to all services however there may be situations +// where a baggageKey might only be allowed to be set by a specific service. +// +// Parameters: +// - ServiceName +func (p *BaggageRestrictionManagerClient) GetBaggageRestrictions(serviceName string) (r []*BaggageRestriction, err error) { + if err = p.sendGetBaggageRestrictions(serviceName); err != nil { + return + } + return p.recvGetBaggageRestrictions() +} + +func (p *BaggageRestrictionManagerClient) sendGetBaggageRestrictions(serviceName string) (err error) { + oprot := p.OutputProtocol + if oprot == nil { + oprot = p.ProtocolFactory.GetProtocol(p.Transport) + p.OutputProtocol = oprot + } + p.SeqId++ + if err = oprot.WriteMessageBegin("getBaggageRestrictions", thrift.CALL, p.SeqId); err != nil { + return + } + args := BaggageRestrictionManagerGetBaggageRestrictionsArgs{ + ServiceName: serviceName, + } + if err = args.Write(oprot); err != nil { + return + } + if err = oprot.WriteMessageEnd(); err != nil { + return + } + return oprot.Flush() +} + +func (p *BaggageRestrictionManagerClient) recvGetBaggageRestrictions() (value []*BaggageRestriction, err error) { + iprot := p.InputProtocol + if iprot == nil { + iprot = p.ProtocolFactory.GetProtocol(p.Transport) + p.InputProtocol = iprot + } + method, mTypeId, seqId, err := iprot.ReadMessageBegin() + if err != nil { + return + } + if method != "getBaggageRestrictions" { + err = thrift.NewTApplicationException(thrift.WRONG_METHOD_NAME, "getBaggageRestrictions failed: wrong method name") + return + } + if p.SeqId != seqId { + err = thrift.NewTApplicationException(thrift.BAD_SEQUENCE_ID, "getBaggageRestrictions failed: out of sequence response") + return + } + if mTypeId == thrift.EXCEPTION { + error0 := thrift.NewTApplicationException(thrift.UNKNOWN_APPLICATION_EXCEPTION, "Unknown Exception") + var error1 error + error1, err = error0.Read(iprot) + if err != nil { + return + } + if err = iprot.ReadMessageEnd(); err != nil { + return + } + err = error1 + return + } + if mTypeId != thrift.REPLY { + err = thrift.NewTApplicationException(thrift.INVALID_MESSAGE_TYPE_EXCEPTION, "getBaggageRestrictions failed: invalid message type") + return + } + result := BaggageRestrictionManagerGetBaggageRestrictionsResult{} + if err = result.Read(iprot); err != nil { + return + } + if err = iprot.ReadMessageEnd(); err != nil { + return + } + value = result.GetSuccess() + return +} + +type BaggageRestrictionManagerProcessor struct { + processorMap map[string]thrift.TProcessorFunction + handler BaggageRestrictionManager +} + +func (p *BaggageRestrictionManagerProcessor) AddToProcessorMap(key string, processor thrift.TProcessorFunction) { + p.processorMap[key] = processor +} + +func (p *BaggageRestrictionManagerProcessor) GetProcessorFunction(key string) (processor thrift.TProcessorFunction, ok bool) { + processor, ok = p.processorMap[key] + return processor, ok +} + +func (p *BaggageRestrictionManagerProcessor) ProcessorMap() map[string]thrift.TProcessorFunction { + return p.processorMap +} + +func NewBaggageRestrictionManagerProcessor(handler BaggageRestrictionManager) *BaggageRestrictionManagerProcessor { + + self2 := &BaggageRestrictionManagerProcessor{handler: handler, processorMap: make(map[string]thrift.TProcessorFunction)} + self2.processorMap["getBaggageRestrictions"] = &baggageRestrictionManagerProcessorGetBaggageRestrictions{handler: handler} + return self2 +} + +func (p *BaggageRestrictionManagerProcessor) Process(iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { + name, _, seqId, err := iprot.ReadMessageBegin() + if err != nil { + return false, err + } + if processor, ok := p.GetProcessorFunction(name); ok { + return processor.Process(seqId, iprot, oprot) + } + iprot.Skip(thrift.STRUCT) + iprot.ReadMessageEnd() + x3 := thrift.NewTApplicationException(thrift.UNKNOWN_METHOD, "Unknown function "+name) + oprot.WriteMessageBegin(name, thrift.EXCEPTION, seqId) + x3.Write(oprot) + oprot.WriteMessageEnd() + oprot.Flush() + return false, x3 + +} + +type baggageRestrictionManagerProcessorGetBaggageRestrictions struct { + handler BaggageRestrictionManager +} + +func (p *baggageRestrictionManagerProcessorGetBaggageRestrictions) Process(seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { + args := BaggageRestrictionManagerGetBaggageRestrictionsArgs{} + if err = args.Read(iprot); err != nil { + iprot.ReadMessageEnd() + x := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err.Error()) + oprot.WriteMessageBegin("getBaggageRestrictions", thrift.EXCEPTION, seqId) + x.Write(oprot) + oprot.WriteMessageEnd() + oprot.Flush() + return false, err + } + + iprot.ReadMessageEnd() + result := BaggageRestrictionManagerGetBaggageRestrictionsResult{} + var retval []*BaggageRestriction + var err2 error + if retval, err2 = p.handler.GetBaggageRestrictions(args.ServiceName); err2 != nil { + x := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, "Internal error processing getBaggageRestrictions: "+err2.Error()) + oprot.WriteMessageBegin("getBaggageRestrictions", thrift.EXCEPTION, seqId) + x.Write(oprot) + oprot.WriteMessageEnd() + oprot.Flush() + return true, err2 + } else { + result.Success = retval + } + if err2 = oprot.WriteMessageBegin("getBaggageRestrictions", thrift.REPLY, seqId); err2 != nil { + err = err2 + } + if err2 = result.Write(oprot); err == nil && err2 != nil { + err = err2 + } + if err2 = oprot.WriteMessageEnd(); err == nil && err2 != nil { + err = err2 + } + if err2 = oprot.Flush(); err == nil && err2 != nil { + err = err2 + } + if err != nil { + return + } + return true, err +} + +// HELPER FUNCTIONS AND STRUCTURES + +// Attributes: +// - ServiceName +type BaggageRestrictionManagerGetBaggageRestrictionsArgs struct { + ServiceName string `thrift:"serviceName,1" json:"serviceName"` +} + +func NewBaggageRestrictionManagerGetBaggageRestrictionsArgs() *BaggageRestrictionManagerGetBaggageRestrictionsArgs { + return &BaggageRestrictionManagerGetBaggageRestrictionsArgs{} +} + +func (p *BaggageRestrictionManagerGetBaggageRestrictionsArgs) GetServiceName() string { + return p.ServiceName +} +func (p *BaggageRestrictionManagerGetBaggageRestrictionsArgs) Read(iprot thrift.TProtocol) error { + if _, err := iprot.ReadStructBegin(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) + } + + for { + _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() + if err != nil { + return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) + } + if fieldTypeId == thrift.STOP { + break + } + switch fieldId { + case 1: + if err := p.readField1(iprot); err != nil { + return err + } + default: + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + if err := iprot.ReadFieldEnd(); err != nil { + return err + } + } + if err := iprot.ReadStructEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) + } + return nil +} + +func (p *BaggageRestrictionManagerGetBaggageRestrictionsArgs) readField1(iprot thrift.TProtocol) error { + if v, err := iprot.ReadString(); err != nil { + return thrift.PrependError("error reading field 1: ", err) + } else { + p.ServiceName = v + } + return nil +} + +func (p *BaggageRestrictionManagerGetBaggageRestrictionsArgs) Write(oprot thrift.TProtocol) error { + if err := oprot.WriteStructBegin("getBaggageRestrictions_args"); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) + } + if err := p.writeField1(oprot); err != nil { + return err + } + if err := oprot.WriteFieldStop(); err != nil { + return thrift.PrependError("write field stop error: ", err) + } + if err := oprot.WriteStructEnd(); err != nil { + return thrift.PrependError("write struct stop error: ", err) + } + return nil +} + +func (p *BaggageRestrictionManagerGetBaggageRestrictionsArgs) writeField1(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("serviceName", thrift.STRING, 1); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:serviceName: ", p), err) + } + if err := oprot.WriteString(string(p.ServiceName)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.serviceName (1) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 1:serviceName: ", p), err) + } + return err +} + +func (p *BaggageRestrictionManagerGetBaggageRestrictionsArgs) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("BaggageRestrictionManagerGetBaggageRestrictionsArgs(%+v)", *p) +} + +// Attributes: +// - Success +type BaggageRestrictionManagerGetBaggageRestrictionsResult struct { + Success []*BaggageRestriction `thrift:"success,0" json:"success,omitempty"` +} + +func NewBaggageRestrictionManagerGetBaggageRestrictionsResult() *BaggageRestrictionManagerGetBaggageRestrictionsResult { + return &BaggageRestrictionManagerGetBaggageRestrictionsResult{} +} + +var BaggageRestrictionManagerGetBaggageRestrictionsResult_Success_DEFAULT []*BaggageRestriction + +func (p *BaggageRestrictionManagerGetBaggageRestrictionsResult) GetSuccess() []*BaggageRestriction { + return p.Success +} +func (p *BaggageRestrictionManagerGetBaggageRestrictionsResult) IsSetSuccess() bool { + return p.Success != nil +} + +func (p *BaggageRestrictionManagerGetBaggageRestrictionsResult) Read(iprot thrift.TProtocol) error { + if _, err := iprot.ReadStructBegin(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) + } + + for { + _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() + if err != nil { + return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) + } + if fieldTypeId == thrift.STOP { + break + } + switch fieldId { + case 0: + if err := p.readField0(iprot); err != nil { + return err + } + default: + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + if err := iprot.ReadFieldEnd(); err != nil { + return err + } + } + if err := iprot.ReadStructEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) + } + return nil +} + +func (p *BaggageRestrictionManagerGetBaggageRestrictionsResult) readField0(iprot thrift.TProtocol) error { + _, size, err := iprot.ReadListBegin() + if err != nil { + return thrift.PrependError("error reading list begin: ", err) + } + tSlice := make([]*BaggageRestriction, 0, size) + p.Success = tSlice + for i := 0; i < size; i++ { + _elem4 := &BaggageRestriction{} + if err := _elem4.Read(iprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", _elem4), err) + } + p.Success = append(p.Success, _elem4) + } + if err := iprot.ReadListEnd(); err != nil { + return thrift.PrependError("error reading list end: ", err) + } + return nil +} + +func (p *BaggageRestrictionManagerGetBaggageRestrictionsResult) Write(oprot thrift.TProtocol) error { + if err := oprot.WriteStructBegin("getBaggageRestrictions_result"); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) + } + if err := p.writeField0(oprot); err != nil { + return err + } + if err := oprot.WriteFieldStop(); err != nil { + return thrift.PrependError("write field stop error: ", err) + } + if err := oprot.WriteStructEnd(); err != nil { + return thrift.PrependError("write struct stop error: ", err) + } + return nil +} + +func (p *BaggageRestrictionManagerGetBaggageRestrictionsResult) writeField0(oprot thrift.TProtocol) (err error) { + if p.IsSetSuccess() { + if err := oprot.WriteFieldBegin("success", thrift.LIST, 0); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 0:success: ", p), err) + } + if err := oprot.WriteListBegin(thrift.STRUCT, len(p.Success)); err != nil { + return thrift.PrependError("error writing list begin: ", err) + } + for _, v := range p.Success { + if err := v.Write(oprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", v), err) + } + } + if err := oprot.WriteListEnd(); err != nil { + return thrift.PrependError("error writing list end: ", err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 0:success: ", p), err) + } + } + return err +} + +func (p *BaggageRestrictionManagerGetBaggageRestrictionsResult) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("BaggageRestrictionManagerGetBaggageRestrictionsResult(%+v)", *p) +} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift-gen/baggage/constants.go b/vendor/github.com/uber/jaeger-client-go/thrift-gen/baggage/constants.go new file mode 100644 index 0000000000..ed35ce9ab5 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/thrift-gen/baggage/constants.go @@ -0,0 +1,18 @@ +// Autogenerated by Thrift Compiler (0.9.3) +// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + +package baggage + +import ( + "bytes" + "fmt" + "github.com/uber/jaeger-client-go/thrift" +) + +// (needed to ensure safety because of naive import list construction.) +var _ = thrift.ZERO +var _ = fmt.Printf +var _ = bytes.Equal + +func init() { +} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift-gen/baggage/ttypes.go b/vendor/github.com/uber/jaeger-client-go/thrift-gen/baggage/ttypes.go new file mode 100644 index 0000000000..7888892f63 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/thrift-gen/baggage/ttypes.go @@ -0,0 +1,154 @@ +// Autogenerated by Thrift Compiler (0.9.3) +// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + +package baggage + +import ( + "bytes" + "fmt" + "github.com/uber/jaeger-client-go/thrift" +) + +// (needed to ensure safety because of naive import list construction.) +var _ = thrift.ZERO +var _ = fmt.Printf +var _ = bytes.Equal + +var GoUnusedProtection__ int + +// Attributes: +// - BaggageKey +// - MaxValueLength +type BaggageRestriction struct { + BaggageKey string `thrift:"baggageKey,1,required" json:"baggageKey"` + MaxValueLength int32 `thrift:"maxValueLength,2,required" json:"maxValueLength"` +} + +func NewBaggageRestriction() *BaggageRestriction { + return &BaggageRestriction{} +} + +func (p *BaggageRestriction) GetBaggageKey() string { + return p.BaggageKey +} + +func (p *BaggageRestriction) GetMaxValueLength() int32 { + return p.MaxValueLength +} +func (p *BaggageRestriction) Read(iprot thrift.TProtocol) error { + if _, err := iprot.ReadStructBegin(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) + } + + var issetBaggageKey bool = false + var issetMaxValueLength bool = false + + for { + _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() + if err != nil { + return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) + } + if fieldTypeId == thrift.STOP { + break + } + switch fieldId { + case 1: + if err := p.readField1(iprot); err != nil { + return err + } + issetBaggageKey = true + case 2: + if err := p.readField2(iprot); err != nil { + return err + } + issetMaxValueLength = true + default: + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + if err := iprot.ReadFieldEnd(); err != nil { + return err + } + } + if err := iprot.ReadStructEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) + } + if !issetBaggageKey { + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field BaggageKey is not set")) + } + if !issetMaxValueLength { + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field MaxValueLength is not set")) + } + return nil +} + +func (p *BaggageRestriction) readField1(iprot thrift.TProtocol) error { + if v, err := iprot.ReadString(); err != nil { + return thrift.PrependError("error reading field 1: ", err) + } else { + p.BaggageKey = v + } + return nil +} + +func (p *BaggageRestriction) readField2(iprot thrift.TProtocol) error { + if v, err := iprot.ReadI32(); err != nil { + return thrift.PrependError("error reading field 2: ", err) + } else { + p.MaxValueLength = v + } + return nil +} + +func (p *BaggageRestriction) Write(oprot thrift.TProtocol) error { + if err := oprot.WriteStructBegin("BaggageRestriction"); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) + } + if err := p.writeField1(oprot); err != nil { + return err + } + if err := p.writeField2(oprot); err != nil { + return err + } + if err := oprot.WriteFieldStop(); err != nil { + return thrift.PrependError("write field stop error: ", err) + } + if err := oprot.WriteStructEnd(); err != nil { + return thrift.PrependError("write struct stop error: ", err) + } + return nil +} + +func (p *BaggageRestriction) writeField1(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("baggageKey", thrift.STRING, 1); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:baggageKey: ", p), err) + } + if err := oprot.WriteString(string(p.BaggageKey)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.baggageKey (1) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 1:baggageKey: ", p), err) + } + return err +} + +func (p *BaggageRestriction) writeField2(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("maxValueLength", thrift.I32, 2); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:maxValueLength: ", p), err) + } + if err := oprot.WriteI32(int32(p.MaxValueLength)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.maxValueLength (2) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 2:maxValueLength: ", p), err) + } + return err +} + +func (p *BaggageRestriction) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("BaggageRestriction(%+v)", *p) +} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift-gen/jaeger/agent.go b/vendor/github.com/uber/jaeger-client-go/thrift-gen/jaeger/agent.go new file mode 100644 index 0000000000..b32c37dd26 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/thrift-gen/jaeger/agent.go @@ -0,0 +1,242 @@ +// Autogenerated by Thrift Compiler (0.9.3) +// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + +package jaeger + +import ( + "bytes" + "fmt" + "github.com/uber/jaeger-client-go/thrift" +) + +// (needed to ensure safety because of naive import list construction.) +var _ = thrift.ZERO +var _ = fmt.Printf +var _ = bytes.Equal + +type Agent interface { + // Parameters: + // - Batch + EmitBatch(batch *Batch) (err error) +} + +type AgentClient struct { + Transport thrift.TTransport + ProtocolFactory thrift.TProtocolFactory + InputProtocol thrift.TProtocol + OutputProtocol thrift.TProtocol + SeqId int32 +} + +func NewAgentClientFactory(t thrift.TTransport, f thrift.TProtocolFactory) *AgentClient { + return &AgentClient{Transport: t, + ProtocolFactory: f, + InputProtocol: f.GetProtocol(t), + OutputProtocol: f.GetProtocol(t), + SeqId: 0, + } +} + +func NewAgentClientProtocol(t thrift.TTransport, iprot thrift.TProtocol, oprot thrift.TProtocol) *AgentClient { + return &AgentClient{Transport: t, + ProtocolFactory: nil, + InputProtocol: iprot, + OutputProtocol: oprot, + SeqId: 0, + } +} + +// Parameters: +// - Batch +func (p *AgentClient) EmitBatch(batch *Batch) (err error) { + if err = p.sendEmitBatch(batch); err != nil { + return + } + return +} + +func (p *AgentClient) sendEmitBatch(batch *Batch) (err error) { + oprot := p.OutputProtocol + if oprot == nil { + oprot = p.ProtocolFactory.GetProtocol(p.Transport) + p.OutputProtocol = oprot + } + p.SeqId++ + if err = oprot.WriteMessageBegin("emitBatch", thrift.ONEWAY, p.SeqId); err != nil { + return + } + args := AgentEmitBatchArgs{ + Batch: batch, + } + if err = args.Write(oprot); err != nil { + return + } + if err = oprot.WriteMessageEnd(); err != nil { + return + } + return oprot.Flush() +} + +type AgentProcessor struct { + processorMap map[string]thrift.TProcessorFunction + handler Agent +} + +func (p *AgentProcessor) AddToProcessorMap(key string, processor thrift.TProcessorFunction) { + p.processorMap[key] = processor +} + +func (p *AgentProcessor) GetProcessorFunction(key string) (processor thrift.TProcessorFunction, ok bool) { + processor, ok = p.processorMap[key] + return processor, ok +} + +func (p *AgentProcessor) ProcessorMap() map[string]thrift.TProcessorFunction { + return p.processorMap +} + +func NewAgentProcessor(handler Agent) *AgentProcessor { + + self6 := &AgentProcessor{handler: handler, processorMap: make(map[string]thrift.TProcessorFunction)} + self6.processorMap["emitBatch"] = &agentProcessorEmitBatch{handler: handler} + return self6 +} + +func (p *AgentProcessor) Process(iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { + name, _, seqId, err := iprot.ReadMessageBegin() + if err != nil { + return false, err + } + if processor, ok := p.GetProcessorFunction(name); ok { + return processor.Process(seqId, iprot, oprot) + } + iprot.Skip(thrift.STRUCT) + iprot.ReadMessageEnd() + x7 := thrift.NewTApplicationException(thrift.UNKNOWN_METHOD, "Unknown function "+name) + oprot.WriteMessageBegin(name, thrift.EXCEPTION, seqId) + x7.Write(oprot) + oprot.WriteMessageEnd() + oprot.Flush() + return false, x7 + +} + +type agentProcessorEmitBatch struct { + handler Agent +} + +func (p *agentProcessorEmitBatch) Process(seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { + args := AgentEmitBatchArgs{} + if err = args.Read(iprot); err != nil { + iprot.ReadMessageEnd() + return false, err + } + + iprot.ReadMessageEnd() + var err2 error + if err2 = p.handler.EmitBatch(args.Batch); err2 != nil { + return true, err2 + } + return true, nil +} + +// HELPER FUNCTIONS AND STRUCTURES + +// Attributes: +// - Batch +type AgentEmitBatchArgs struct { + Batch *Batch `thrift:"batch,1" json:"batch"` +} + +func NewAgentEmitBatchArgs() *AgentEmitBatchArgs { + return &AgentEmitBatchArgs{} +} + +var AgentEmitBatchArgs_Batch_DEFAULT *Batch + +func (p *AgentEmitBatchArgs) GetBatch() *Batch { + if !p.IsSetBatch() { + return AgentEmitBatchArgs_Batch_DEFAULT + } + return p.Batch +} +func (p *AgentEmitBatchArgs) IsSetBatch() bool { + return p.Batch != nil +} + +func (p *AgentEmitBatchArgs) Read(iprot thrift.TProtocol) error { + if _, err := iprot.ReadStructBegin(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) + } + + for { + _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() + if err != nil { + return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) + } + if fieldTypeId == thrift.STOP { + break + } + switch fieldId { + case 1: + if err := p.readField1(iprot); err != nil { + return err + } + default: + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + if err := iprot.ReadFieldEnd(); err != nil { + return err + } + } + if err := iprot.ReadStructEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) + } + return nil +} + +func (p *AgentEmitBatchArgs) readField1(iprot thrift.TProtocol) error { + p.Batch = &Batch{} + if err := p.Batch.Read(iprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", p.Batch), err) + } + return nil +} + +func (p *AgentEmitBatchArgs) Write(oprot thrift.TProtocol) error { + if err := oprot.WriteStructBegin("emitBatch_args"); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) + } + if err := p.writeField1(oprot); err != nil { + return err + } + if err := oprot.WriteFieldStop(); err != nil { + return thrift.PrependError("write field stop error: ", err) + } + if err := oprot.WriteStructEnd(); err != nil { + return thrift.PrependError("write struct stop error: ", err) + } + return nil +} + +func (p *AgentEmitBatchArgs) writeField1(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("batch", thrift.STRUCT, 1); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:batch: ", p), err) + } + if err := p.Batch.Write(oprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", p.Batch), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 1:batch: ", p), err) + } + return err +} + +func (p *AgentEmitBatchArgs) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("AgentEmitBatchArgs(%+v)", *p) +} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift-gen/jaeger/constants.go b/vendor/github.com/uber/jaeger-client-go/thrift-gen/jaeger/constants.go new file mode 100644 index 0000000000..621b8b1c20 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/thrift-gen/jaeger/constants.go @@ -0,0 +1,18 @@ +// Autogenerated by Thrift Compiler (0.9.3) +// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + +package jaeger + +import ( + "bytes" + "fmt" + "github.com/uber/jaeger-client-go/thrift" +) + +// (needed to ensure safety because of naive import list construction.) +var _ = thrift.ZERO +var _ = fmt.Printf +var _ = bytes.Equal + +func init() { +} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift-gen/jaeger/ttypes.go b/vendor/github.com/uber/jaeger-client-go/thrift-gen/jaeger/ttypes.go new file mode 100644 index 0000000000..d23ed2fc28 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/thrift-gen/jaeger/ttypes.go @@ -0,0 +1,1838 @@ +// Autogenerated by Thrift Compiler (0.9.3) +// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + +package jaeger + +import ( + "bytes" + "fmt" + "github.com/uber/jaeger-client-go/thrift" +) + +// (needed to ensure safety because of naive import list construction.) +var _ = thrift.ZERO +var _ = fmt.Printf +var _ = bytes.Equal + +var GoUnusedProtection__ int + +type TagType int64 + +const ( + TagType_STRING TagType = 0 + TagType_DOUBLE TagType = 1 + TagType_BOOL TagType = 2 + TagType_LONG TagType = 3 + TagType_BINARY TagType = 4 +) + +func (p TagType) String() string { + switch p { + case TagType_STRING: + return "STRING" + case TagType_DOUBLE: + return "DOUBLE" + case TagType_BOOL: + return "BOOL" + case TagType_LONG: + return "LONG" + case TagType_BINARY: + return "BINARY" + } + return "" +} + +func TagTypeFromString(s string) (TagType, error) { + switch s { + case "STRING": + return TagType_STRING, nil + case "DOUBLE": + return TagType_DOUBLE, nil + case "BOOL": + return TagType_BOOL, nil + case "LONG": + return TagType_LONG, nil + case "BINARY": + return TagType_BINARY, nil + } + return TagType(0), fmt.Errorf("not a valid TagType string") +} + +func TagTypePtr(v TagType) *TagType { return &v } + +func (p TagType) MarshalText() ([]byte, error) { + return []byte(p.String()), nil +} + +func (p *TagType) UnmarshalText(text []byte) error { + q, err := TagTypeFromString(string(text)) + if err != nil { + return err + } + *p = q + return nil +} + +type SpanRefType int64 + +const ( + SpanRefType_CHILD_OF SpanRefType = 0 + SpanRefType_FOLLOWS_FROM SpanRefType = 1 +) + +func (p SpanRefType) String() string { + switch p { + case SpanRefType_CHILD_OF: + return "CHILD_OF" + case SpanRefType_FOLLOWS_FROM: + return "FOLLOWS_FROM" + } + return "" +} + +func SpanRefTypeFromString(s string) (SpanRefType, error) { + switch s { + case "CHILD_OF": + return SpanRefType_CHILD_OF, nil + case "FOLLOWS_FROM": + return SpanRefType_FOLLOWS_FROM, nil + } + return SpanRefType(0), fmt.Errorf("not a valid SpanRefType string") +} + +func SpanRefTypePtr(v SpanRefType) *SpanRefType { return &v } + +func (p SpanRefType) MarshalText() ([]byte, error) { + return []byte(p.String()), nil +} + +func (p *SpanRefType) UnmarshalText(text []byte) error { + q, err := SpanRefTypeFromString(string(text)) + if err != nil { + return err + } + *p = q + return nil +} + +// Attributes: +// - Key +// - VType +// - VStr +// - VDouble +// - VBool +// - VLong +// - VBinary +type Tag struct { + Key string `thrift:"key,1,required" json:"key"` + VType TagType `thrift:"vType,2,required" json:"vType"` + VStr *string `thrift:"vStr,3" json:"vStr,omitempty"` + VDouble *float64 `thrift:"vDouble,4" json:"vDouble,omitempty"` + VBool *bool `thrift:"vBool,5" json:"vBool,omitempty"` + VLong *int64 `thrift:"vLong,6" json:"vLong,omitempty"` + VBinary []byte `thrift:"vBinary,7" json:"vBinary,omitempty"` +} + +func NewTag() *Tag { + return &Tag{} +} + +func (p *Tag) GetKey() string { + return p.Key +} + +func (p *Tag) GetVType() TagType { + return p.VType +} + +var Tag_VStr_DEFAULT string + +func (p *Tag) GetVStr() string { + if !p.IsSetVStr() { + return Tag_VStr_DEFAULT + } + return *p.VStr +} + +var Tag_VDouble_DEFAULT float64 + +func (p *Tag) GetVDouble() float64 { + if !p.IsSetVDouble() { + return Tag_VDouble_DEFAULT + } + return *p.VDouble +} + +var Tag_VBool_DEFAULT bool + +func (p *Tag) GetVBool() bool { + if !p.IsSetVBool() { + return Tag_VBool_DEFAULT + } + return *p.VBool +} + +var Tag_VLong_DEFAULT int64 + +func (p *Tag) GetVLong() int64 { + if !p.IsSetVLong() { + return Tag_VLong_DEFAULT + } + return *p.VLong +} + +var Tag_VBinary_DEFAULT []byte + +func (p *Tag) GetVBinary() []byte { + return p.VBinary +} +func (p *Tag) IsSetVStr() bool { + return p.VStr != nil +} + +func (p *Tag) IsSetVDouble() bool { + return p.VDouble != nil +} + +func (p *Tag) IsSetVBool() bool { + return p.VBool != nil +} + +func (p *Tag) IsSetVLong() bool { + return p.VLong != nil +} + +func (p *Tag) IsSetVBinary() bool { + return p.VBinary != nil +} + +func (p *Tag) Read(iprot thrift.TProtocol) error { + if _, err := iprot.ReadStructBegin(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) + } + + var issetKey bool = false + var issetVType bool = false + + for { + _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() + if err != nil { + return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) + } + if fieldTypeId == thrift.STOP { + break + } + switch fieldId { + case 1: + if err := p.readField1(iprot); err != nil { + return err + } + issetKey = true + case 2: + if err := p.readField2(iprot); err != nil { + return err + } + issetVType = true + case 3: + if err := p.readField3(iprot); err != nil { + return err + } + case 4: + if err := p.readField4(iprot); err != nil { + return err + } + case 5: + if err := p.readField5(iprot); err != nil { + return err + } + case 6: + if err := p.readField6(iprot); err != nil { + return err + } + case 7: + if err := p.readField7(iprot); err != nil { + return err + } + default: + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + if err := iprot.ReadFieldEnd(); err != nil { + return err + } + } + if err := iprot.ReadStructEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) + } + if !issetKey { + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field Key is not set")) + } + if !issetVType { + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field VType is not set")) + } + return nil +} + +func (p *Tag) readField1(iprot thrift.TProtocol) error { + if v, err := iprot.ReadString(); err != nil { + return thrift.PrependError("error reading field 1: ", err) + } else { + p.Key = v + } + return nil +} + +func (p *Tag) readField2(iprot thrift.TProtocol) error { + if v, err := iprot.ReadI32(); err != nil { + return thrift.PrependError("error reading field 2: ", err) + } else { + temp := TagType(v) + p.VType = temp + } + return nil +} + +func (p *Tag) readField3(iprot thrift.TProtocol) error { + if v, err := iprot.ReadString(); err != nil { + return thrift.PrependError("error reading field 3: ", err) + } else { + p.VStr = &v + } + return nil +} + +func (p *Tag) readField4(iprot thrift.TProtocol) error { + if v, err := iprot.ReadDouble(); err != nil { + return thrift.PrependError("error reading field 4: ", err) + } else { + p.VDouble = &v + } + return nil +} + +func (p *Tag) readField5(iprot thrift.TProtocol) error { + if v, err := iprot.ReadBool(); err != nil { + return thrift.PrependError("error reading field 5: ", err) + } else { + p.VBool = &v + } + return nil +} + +func (p *Tag) readField6(iprot thrift.TProtocol) error { + if v, err := iprot.ReadI64(); err != nil { + return thrift.PrependError("error reading field 6: ", err) + } else { + p.VLong = &v + } + return nil +} + +func (p *Tag) readField7(iprot thrift.TProtocol) error { + if v, err := iprot.ReadBinary(); err != nil { + return thrift.PrependError("error reading field 7: ", err) + } else { + p.VBinary = v + } + return nil +} + +func (p *Tag) Write(oprot thrift.TProtocol) error { + if err := oprot.WriteStructBegin("Tag"); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) + } + if err := p.writeField1(oprot); err != nil { + return err + } + if err := p.writeField2(oprot); err != nil { + return err + } + if err := p.writeField3(oprot); err != nil { + return err + } + if err := p.writeField4(oprot); err != nil { + return err + } + if err := p.writeField5(oprot); err != nil { + return err + } + if err := p.writeField6(oprot); err != nil { + return err + } + if err := p.writeField7(oprot); err != nil { + return err + } + if err := oprot.WriteFieldStop(); err != nil { + return thrift.PrependError("write field stop error: ", err) + } + if err := oprot.WriteStructEnd(); err != nil { + return thrift.PrependError("write struct stop error: ", err) + } + return nil +} + +func (p *Tag) writeField1(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("key", thrift.STRING, 1); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:key: ", p), err) + } + if err := oprot.WriteString(string(p.Key)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.key (1) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 1:key: ", p), err) + } + return err +} + +func (p *Tag) writeField2(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("vType", thrift.I32, 2); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:vType: ", p), err) + } + if err := oprot.WriteI32(int32(p.VType)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.vType (2) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 2:vType: ", p), err) + } + return err +} + +func (p *Tag) writeField3(oprot thrift.TProtocol) (err error) { + if p.IsSetVStr() { + if err := oprot.WriteFieldBegin("vStr", thrift.STRING, 3); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 3:vStr: ", p), err) + } + if err := oprot.WriteString(string(*p.VStr)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.vStr (3) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 3:vStr: ", p), err) + } + } + return err +} + +func (p *Tag) writeField4(oprot thrift.TProtocol) (err error) { + if p.IsSetVDouble() { + if err := oprot.WriteFieldBegin("vDouble", thrift.DOUBLE, 4); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 4:vDouble: ", p), err) + } + if err := oprot.WriteDouble(float64(*p.VDouble)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.vDouble (4) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 4:vDouble: ", p), err) + } + } + return err +} + +func (p *Tag) writeField5(oprot thrift.TProtocol) (err error) { + if p.IsSetVBool() { + if err := oprot.WriteFieldBegin("vBool", thrift.BOOL, 5); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 5:vBool: ", p), err) + } + if err := oprot.WriteBool(bool(*p.VBool)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.vBool (5) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 5:vBool: ", p), err) + } + } + return err +} + +func (p *Tag) writeField6(oprot thrift.TProtocol) (err error) { + if p.IsSetVLong() { + if err := oprot.WriteFieldBegin("vLong", thrift.I64, 6); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 6:vLong: ", p), err) + } + if err := oprot.WriteI64(int64(*p.VLong)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.vLong (6) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 6:vLong: ", p), err) + } + } + return err +} + +func (p *Tag) writeField7(oprot thrift.TProtocol) (err error) { + if p.IsSetVBinary() { + if err := oprot.WriteFieldBegin("vBinary", thrift.STRING, 7); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 7:vBinary: ", p), err) + } + if err := oprot.WriteBinary(p.VBinary); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.vBinary (7) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 7:vBinary: ", p), err) + } + } + return err +} + +func (p *Tag) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("Tag(%+v)", *p) +} + +// Attributes: +// - Timestamp +// - Fields +type Log struct { + Timestamp int64 `thrift:"timestamp,1,required" json:"timestamp"` + Fields []*Tag `thrift:"fields,2,required" json:"fields"` +} + +func NewLog() *Log { + return &Log{} +} + +func (p *Log) GetTimestamp() int64 { + return p.Timestamp +} + +func (p *Log) GetFields() []*Tag { + return p.Fields +} +func (p *Log) Read(iprot thrift.TProtocol) error { + if _, err := iprot.ReadStructBegin(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) + } + + var issetTimestamp bool = false + var issetFields bool = false + + for { + _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() + if err != nil { + return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) + } + if fieldTypeId == thrift.STOP { + break + } + switch fieldId { + case 1: + if err := p.readField1(iprot); err != nil { + return err + } + issetTimestamp = true + case 2: + if err := p.readField2(iprot); err != nil { + return err + } + issetFields = true + default: + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + if err := iprot.ReadFieldEnd(); err != nil { + return err + } + } + if err := iprot.ReadStructEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) + } + if !issetTimestamp { + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field Timestamp is not set")) + } + if !issetFields { + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field Fields is not set")) + } + return nil +} + +func (p *Log) readField1(iprot thrift.TProtocol) error { + if v, err := iprot.ReadI64(); err != nil { + return thrift.PrependError("error reading field 1: ", err) + } else { + p.Timestamp = v + } + return nil +} + +func (p *Log) readField2(iprot thrift.TProtocol) error { + _, size, err := iprot.ReadListBegin() + if err != nil { + return thrift.PrependError("error reading list begin: ", err) + } + tSlice := make([]*Tag, 0, size) + p.Fields = tSlice + for i := 0; i < size; i++ { + _elem0 := &Tag{} + if err := _elem0.Read(iprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", _elem0), err) + } + p.Fields = append(p.Fields, _elem0) + } + if err := iprot.ReadListEnd(); err != nil { + return thrift.PrependError("error reading list end: ", err) + } + return nil +} + +func (p *Log) Write(oprot thrift.TProtocol) error { + if err := oprot.WriteStructBegin("Log"); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) + } + if err := p.writeField1(oprot); err != nil { + return err + } + if err := p.writeField2(oprot); err != nil { + return err + } + if err := oprot.WriteFieldStop(); err != nil { + return thrift.PrependError("write field stop error: ", err) + } + if err := oprot.WriteStructEnd(); err != nil { + return thrift.PrependError("write struct stop error: ", err) + } + return nil +} + +func (p *Log) writeField1(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("timestamp", thrift.I64, 1); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:timestamp: ", p), err) + } + if err := oprot.WriteI64(int64(p.Timestamp)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.timestamp (1) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 1:timestamp: ", p), err) + } + return err +} + +func (p *Log) writeField2(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("fields", thrift.LIST, 2); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:fields: ", p), err) + } + if err := oprot.WriteListBegin(thrift.STRUCT, len(p.Fields)); err != nil { + return thrift.PrependError("error writing list begin: ", err) + } + for _, v := range p.Fields { + if err := v.Write(oprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", v), err) + } + } + if err := oprot.WriteListEnd(); err != nil { + return thrift.PrependError("error writing list end: ", err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 2:fields: ", p), err) + } + return err +} + +func (p *Log) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("Log(%+v)", *p) +} + +// Attributes: +// - RefType +// - TraceIdLow +// - TraceIdHigh +// - SpanId +type SpanRef struct { + RefType SpanRefType `thrift:"refType,1,required" json:"refType"` + TraceIdLow int64 `thrift:"traceIdLow,2,required" json:"traceIdLow"` + TraceIdHigh int64 `thrift:"traceIdHigh,3,required" json:"traceIdHigh"` + SpanId int64 `thrift:"spanId,4,required" json:"spanId"` +} + +func NewSpanRef() *SpanRef { + return &SpanRef{} +} + +func (p *SpanRef) GetRefType() SpanRefType { + return p.RefType +} + +func (p *SpanRef) GetTraceIdLow() int64 { + return p.TraceIdLow +} + +func (p *SpanRef) GetTraceIdHigh() int64 { + return p.TraceIdHigh +} + +func (p *SpanRef) GetSpanId() int64 { + return p.SpanId +} +func (p *SpanRef) Read(iprot thrift.TProtocol) error { + if _, err := iprot.ReadStructBegin(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) + } + + var issetRefType bool = false + var issetTraceIdLow bool = false + var issetTraceIdHigh bool = false + var issetSpanId bool = false + + for { + _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() + if err != nil { + return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) + } + if fieldTypeId == thrift.STOP { + break + } + switch fieldId { + case 1: + if err := p.readField1(iprot); err != nil { + return err + } + issetRefType = true + case 2: + if err := p.readField2(iprot); err != nil { + return err + } + issetTraceIdLow = true + case 3: + if err := p.readField3(iprot); err != nil { + return err + } + issetTraceIdHigh = true + case 4: + if err := p.readField4(iprot); err != nil { + return err + } + issetSpanId = true + default: + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + if err := iprot.ReadFieldEnd(); err != nil { + return err + } + } + if err := iprot.ReadStructEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) + } + if !issetRefType { + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field RefType is not set")) + } + if !issetTraceIdLow { + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field TraceIdLow is not set")) + } + if !issetTraceIdHigh { + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field TraceIdHigh is not set")) + } + if !issetSpanId { + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field SpanId is not set")) + } + return nil +} + +func (p *SpanRef) readField1(iprot thrift.TProtocol) error { + if v, err := iprot.ReadI32(); err != nil { + return thrift.PrependError("error reading field 1: ", err) + } else { + temp := SpanRefType(v) + p.RefType = temp + } + return nil +} + +func (p *SpanRef) readField2(iprot thrift.TProtocol) error { + if v, err := iprot.ReadI64(); err != nil { + return thrift.PrependError("error reading field 2: ", err) + } else { + p.TraceIdLow = v + } + return nil +} + +func (p *SpanRef) readField3(iprot thrift.TProtocol) error { + if v, err := iprot.ReadI64(); err != nil { + return thrift.PrependError("error reading field 3: ", err) + } else { + p.TraceIdHigh = v + } + return nil +} + +func (p *SpanRef) readField4(iprot thrift.TProtocol) error { + if v, err := iprot.ReadI64(); err != nil { + return thrift.PrependError("error reading field 4: ", err) + } else { + p.SpanId = v + } + return nil +} + +func (p *SpanRef) Write(oprot thrift.TProtocol) error { + if err := oprot.WriteStructBegin("SpanRef"); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) + } + if err := p.writeField1(oprot); err != nil { + return err + } + if err := p.writeField2(oprot); err != nil { + return err + } + if err := p.writeField3(oprot); err != nil { + return err + } + if err := p.writeField4(oprot); err != nil { + return err + } + if err := oprot.WriteFieldStop(); err != nil { + return thrift.PrependError("write field stop error: ", err) + } + if err := oprot.WriteStructEnd(); err != nil { + return thrift.PrependError("write struct stop error: ", err) + } + return nil +} + +func (p *SpanRef) writeField1(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("refType", thrift.I32, 1); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:refType: ", p), err) + } + if err := oprot.WriteI32(int32(p.RefType)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.refType (1) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 1:refType: ", p), err) + } + return err +} + +func (p *SpanRef) writeField2(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("traceIdLow", thrift.I64, 2); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:traceIdLow: ", p), err) + } + if err := oprot.WriteI64(int64(p.TraceIdLow)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.traceIdLow (2) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 2:traceIdLow: ", p), err) + } + return err +} + +func (p *SpanRef) writeField3(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("traceIdHigh", thrift.I64, 3); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 3:traceIdHigh: ", p), err) + } + if err := oprot.WriteI64(int64(p.TraceIdHigh)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.traceIdHigh (3) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 3:traceIdHigh: ", p), err) + } + return err +} + +func (p *SpanRef) writeField4(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("spanId", thrift.I64, 4); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 4:spanId: ", p), err) + } + if err := oprot.WriteI64(int64(p.SpanId)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.spanId (4) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 4:spanId: ", p), err) + } + return err +} + +func (p *SpanRef) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("SpanRef(%+v)", *p) +} + +// Attributes: +// - TraceIdLow +// - TraceIdHigh +// - SpanId +// - ParentSpanId +// - OperationName +// - References +// - Flags +// - StartTime +// - Duration +// - Tags +// - Logs +type Span struct { + TraceIdLow int64 `thrift:"traceIdLow,1,required" json:"traceIdLow"` + TraceIdHigh int64 `thrift:"traceIdHigh,2,required" json:"traceIdHigh"` + SpanId int64 `thrift:"spanId,3,required" json:"spanId"` + ParentSpanId int64 `thrift:"parentSpanId,4,required" json:"parentSpanId"` + OperationName string `thrift:"operationName,5,required" json:"operationName"` + References []*SpanRef `thrift:"references,6" json:"references,omitempty"` + Flags int32 `thrift:"flags,7,required" json:"flags"` + StartTime int64 `thrift:"startTime,8,required" json:"startTime"` + Duration int64 `thrift:"duration,9,required" json:"duration"` + Tags []*Tag `thrift:"tags,10" json:"tags,omitempty"` + Logs []*Log `thrift:"logs,11" json:"logs,omitempty"` +} + +func NewSpan() *Span { + return &Span{} +} + +func (p *Span) GetTraceIdLow() int64 { + return p.TraceIdLow +} + +func (p *Span) GetTraceIdHigh() int64 { + return p.TraceIdHigh +} + +func (p *Span) GetSpanId() int64 { + return p.SpanId +} + +func (p *Span) GetParentSpanId() int64 { + return p.ParentSpanId +} + +func (p *Span) GetOperationName() string { + return p.OperationName +} + +var Span_References_DEFAULT []*SpanRef + +func (p *Span) GetReferences() []*SpanRef { + return p.References +} + +func (p *Span) GetFlags() int32 { + return p.Flags +} + +func (p *Span) GetStartTime() int64 { + return p.StartTime +} + +func (p *Span) GetDuration() int64 { + return p.Duration +} + +var Span_Tags_DEFAULT []*Tag + +func (p *Span) GetTags() []*Tag { + return p.Tags +} + +var Span_Logs_DEFAULT []*Log + +func (p *Span) GetLogs() []*Log { + return p.Logs +} +func (p *Span) IsSetReferences() bool { + return p.References != nil +} + +func (p *Span) IsSetTags() bool { + return p.Tags != nil +} + +func (p *Span) IsSetLogs() bool { + return p.Logs != nil +} + +func (p *Span) Read(iprot thrift.TProtocol) error { + if _, err := iprot.ReadStructBegin(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) + } + + var issetTraceIdLow bool = false + var issetTraceIdHigh bool = false + var issetSpanId bool = false + var issetParentSpanId bool = false + var issetOperationName bool = false + var issetFlags bool = false + var issetStartTime bool = false + var issetDuration bool = false + + for { + _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() + if err != nil { + return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) + } + if fieldTypeId == thrift.STOP { + break + } + switch fieldId { + case 1: + if err := p.readField1(iprot); err != nil { + return err + } + issetTraceIdLow = true + case 2: + if err := p.readField2(iprot); err != nil { + return err + } + issetTraceIdHigh = true + case 3: + if err := p.readField3(iprot); err != nil { + return err + } + issetSpanId = true + case 4: + if err := p.readField4(iprot); err != nil { + return err + } + issetParentSpanId = true + case 5: + if err := p.readField5(iprot); err != nil { + return err + } + issetOperationName = true + case 6: + if err := p.readField6(iprot); err != nil { + return err + } + case 7: + if err := p.readField7(iprot); err != nil { + return err + } + issetFlags = true + case 8: + if err := p.readField8(iprot); err != nil { + return err + } + issetStartTime = true + case 9: + if err := p.readField9(iprot); err != nil { + return err + } + issetDuration = true + case 10: + if err := p.readField10(iprot); err != nil { + return err + } + case 11: + if err := p.readField11(iprot); err != nil { + return err + } + default: + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + if err := iprot.ReadFieldEnd(); err != nil { + return err + } + } + if err := iprot.ReadStructEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) + } + if !issetTraceIdLow { + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field TraceIdLow is not set")) + } + if !issetTraceIdHigh { + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field TraceIdHigh is not set")) + } + if !issetSpanId { + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field SpanId is not set")) + } + if !issetParentSpanId { + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field ParentSpanId is not set")) + } + if !issetOperationName { + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field OperationName is not set")) + } + if !issetFlags { + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field Flags is not set")) + } + if !issetStartTime { + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field StartTime is not set")) + } + if !issetDuration { + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field Duration is not set")) + } + return nil +} + +func (p *Span) readField1(iprot thrift.TProtocol) error { + if v, err := iprot.ReadI64(); err != nil { + return thrift.PrependError("error reading field 1: ", err) + } else { + p.TraceIdLow = v + } + return nil +} + +func (p *Span) readField2(iprot thrift.TProtocol) error { + if v, err := iprot.ReadI64(); err != nil { + return thrift.PrependError("error reading field 2: ", err) + } else { + p.TraceIdHigh = v + } + return nil +} + +func (p *Span) readField3(iprot thrift.TProtocol) error { + if v, err := iprot.ReadI64(); err != nil { + return thrift.PrependError("error reading field 3: ", err) + } else { + p.SpanId = v + } + return nil +} + +func (p *Span) readField4(iprot thrift.TProtocol) error { + if v, err := iprot.ReadI64(); err != nil { + return thrift.PrependError("error reading field 4: ", err) + } else { + p.ParentSpanId = v + } + return nil +} + +func (p *Span) readField5(iprot thrift.TProtocol) error { + if v, err := iprot.ReadString(); err != nil { + return thrift.PrependError("error reading field 5: ", err) + } else { + p.OperationName = v + } + return nil +} + +func (p *Span) readField6(iprot thrift.TProtocol) error { + _, size, err := iprot.ReadListBegin() + if err != nil { + return thrift.PrependError("error reading list begin: ", err) + } + tSlice := make([]*SpanRef, 0, size) + p.References = tSlice + for i := 0; i < size; i++ { + _elem1 := &SpanRef{} + if err := _elem1.Read(iprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", _elem1), err) + } + p.References = append(p.References, _elem1) + } + if err := iprot.ReadListEnd(); err != nil { + return thrift.PrependError("error reading list end: ", err) + } + return nil +} + +func (p *Span) readField7(iprot thrift.TProtocol) error { + if v, err := iprot.ReadI32(); err != nil { + return thrift.PrependError("error reading field 7: ", err) + } else { + p.Flags = v + } + return nil +} + +func (p *Span) readField8(iprot thrift.TProtocol) error { + if v, err := iprot.ReadI64(); err != nil { + return thrift.PrependError("error reading field 8: ", err) + } else { + p.StartTime = v + } + return nil +} + +func (p *Span) readField9(iprot thrift.TProtocol) error { + if v, err := iprot.ReadI64(); err != nil { + return thrift.PrependError("error reading field 9: ", err) + } else { + p.Duration = v + } + return nil +} + +func (p *Span) readField10(iprot thrift.TProtocol) error { + _, size, err := iprot.ReadListBegin() + if err != nil { + return thrift.PrependError("error reading list begin: ", err) + } + tSlice := make([]*Tag, 0, size) + p.Tags = tSlice + for i := 0; i < size; i++ { + _elem2 := &Tag{} + if err := _elem2.Read(iprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", _elem2), err) + } + p.Tags = append(p.Tags, _elem2) + } + if err := iprot.ReadListEnd(); err != nil { + return thrift.PrependError("error reading list end: ", err) + } + return nil +} + +func (p *Span) readField11(iprot thrift.TProtocol) error { + _, size, err := iprot.ReadListBegin() + if err != nil { + return thrift.PrependError("error reading list begin: ", err) + } + tSlice := make([]*Log, 0, size) + p.Logs = tSlice + for i := 0; i < size; i++ { + _elem3 := &Log{} + if err := _elem3.Read(iprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", _elem3), err) + } + p.Logs = append(p.Logs, _elem3) + } + if err := iprot.ReadListEnd(); err != nil { + return thrift.PrependError("error reading list end: ", err) + } + return nil +} + +func (p *Span) Write(oprot thrift.TProtocol) error { + if err := oprot.WriteStructBegin("Span"); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) + } + if err := p.writeField1(oprot); err != nil { + return err + } + if err := p.writeField2(oprot); err != nil { + return err + } + if err := p.writeField3(oprot); err != nil { + return err + } + if err := p.writeField4(oprot); err != nil { + return err + } + if err := p.writeField5(oprot); err != nil { + return err + } + if err := p.writeField6(oprot); err != nil { + return err + } + if err := p.writeField7(oprot); err != nil { + return err + } + if err := p.writeField8(oprot); err != nil { + return err + } + if err := p.writeField9(oprot); err != nil { + return err + } + if err := p.writeField10(oprot); err != nil { + return err + } + if err := p.writeField11(oprot); err != nil { + return err + } + if err := oprot.WriteFieldStop(); err != nil { + return thrift.PrependError("write field stop error: ", err) + } + if err := oprot.WriteStructEnd(); err != nil { + return thrift.PrependError("write struct stop error: ", err) + } + return nil +} + +func (p *Span) writeField1(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("traceIdLow", thrift.I64, 1); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:traceIdLow: ", p), err) + } + if err := oprot.WriteI64(int64(p.TraceIdLow)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.traceIdLow (1) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 1:traceIdLow: ", p), err) + } + return err +} + +func (p *Span) writeField2(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("traceIdHigh", thrift.I64, 2); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:traceIdHigh: ", p), err) + } + if err := oprot.WriteI64(int64(p.TraceIdHigh)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.traceIdHigh (2) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 2:traceIdHigh: ", p), err) + } + return err +} + +func (p *Span) writeField3(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("spanId", thrift.I64, 3); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 3:spanId: ", p), err) + } + if err := oprot.WriteI64(int64(p.SpanId)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.spanId (3) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 3:spanId: ", p), err) + } + return err +} + +func (p *Span) writeField4(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("parentSpanId", thrift.I64, 4); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 4:parentSpanId: ", p), err) + } + if err := oprot.WriteI64(int64(p.ParentSpanId)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.parentSpanId (4) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 4:parentSpanId: ", p), err) + } + return err +} + +func (p *Span) writeField5(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("operationName", thrift.STRING, 5); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 5:operationName: ", p), err) + } + if err := oprot.WriteString(string(p.OperationName)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.operationName (5) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 5:operationName: ", p), err) + } + return err +} + +func (p *Span) writeField6(oprot thrift.TProtocol) (err error) { + if p.IsSetReferences() { + if err := oprot.WriteFieldBegin("references", thrift.LIST, 6); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 6:references: ", p), err) + } + if err := oprot.WriteListBegin(thrift.STRUCT, len(p.References)); err != nil { + return thrift.PrependError("error writing list begin: ", err) + } + for _, v := range p.References { + if err := v.Write(oprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", v), err) + } + } + if err := oprot.WriteListEnd(); err != nil { + return thrift.PrependError("error writing list end: ", err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 6:references: ", p), err) + } + } + return err +} + +func (p *Span) writeField7(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("flags", thrift.I32, 7); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 7:flags: ", p), err) + } + if err := oprot.WriteI32(int32(p.Flags)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.flags (7) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 7:flags: ", p), err) + } + return err +} + +func (p *Span) writeField8(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("startTime", thrift.I64, 8); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 8:startTime: ", p), err) + } + if err := oprot.WriteI64(int64(p.StartTime)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.startTime (8) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 8:startTime: ", p), err) + } + return err +} + +func (p *Span) writeField9(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("duration", thrift.I64, 9); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 9:duration: ", p), err) + } + if err := oprot.WriteI64(int64(p.Duration)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.duration (9) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 9:duration: ", p), err) + } + return err +} + +func (p *Span) writeField10(oprot thrift.TProtocol) (err error) { + if p.IsSetTags() { + if err := oprot.WriteFieldBegin("tags", thrift.LIST, 10); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 10:tags: ", p), err) + } + if err := oprot.WriteListBegin(thrift.STRUCT, len(p.Tags)); err != nil { + return thrift.PrependError("error writing list begin: ", err) + } + for _, v := range p.Tags { + if err := v.Write(oprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", v), err) + } + } + if err := oprot.WriteListEnd(); err != nil { + return thrift.PrependError("error writing list end: ", err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 10:tags: ", p), err) + } + } + return err +} + +func (p *Span) writeField11(oprot thrift.TProtocol) (err error) { + if p.IsSetLogs() { + if err := oprot.WriteFieldBegin("logs", thrift.LIST, 11); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 11:logs: ", p), err) + } + if err := oprot.WriteListBegin(thrift.STRUCT, len(p.Logs)); err != nil { + return thrift.PrependError("error writing list begin: ", err) + } + for _, v := range p.Logs { + if err := v.Write(oprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", v), err) + } + } + if err := oprot.WriteListEnd(); err != nil { + return thrift.PrependError("error writing list end: ", err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 11:logs: ", p), err) + } + } + return err +} + +func (p *Span) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("Span(%+v)", *p) +} + +// Attributes: +// - ServiceName +// - Tags +type Process struct { + ServiceName string `thrift:"serviceName,1,required" json:"serviceName"` + Tags []*Tag `thrift:"tags,2" json:"tags,omitempty"` +} + +func NewProcess() *Process { + return &Process{} +} + +func (p *Process) GetServiceName() string { + return p.ServiceName +} + +var Process_Tags_DEFAULT []*Tag + +func (p *Process) GetTags() []*Tag { + return p.Tags +} +func (p *Process) IsSetTags() bool { + return p.Tags != nil +} + +func (p *Process) Read(iprot thrift.TProtocol) error { + if _, err := iprot.ReadStructBegin(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) + } + + var issetServiceName bool = false + + for { + _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() + if err != nil { + return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) + } + if fieldTypeId == thrift.STOP { + break + } + switch fieldId { + case 1: + if err := p.readField1(iprot); err != nil { + return err + } + issetServiceName = true + case 2: + if err := p.readField2(iprot); err != nil { + return err + } + default: + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + if err := iprot.ReadFieldEnd(); err != nil { + return err + } + } + if err := iprot.ReadStructEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) + } + if !issetServiceName { + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field ServiceName is not set")) + } + return nil +} + +func (p *Process) readField1(iprot thrift.TProtocol) error { + if v, err := iprot.ReadString(); err != nil { + return thrift.PrependError("error reading field 1: ", err) + } else { + p.ServiceName = v + } + return nil +} + +func (p *Process) readField2(iprot thrift.TProtocol) error { + _, size, err := iprot.ReadListBegin() + if err != nil { + return thrift.PrependError("error reading list begin: ", err) + } + tSlice := make([]*Tag, 0, size) + p.Tags = tSlice + for i := 0; i < size; i++ { + _elem4 := &Tag{} + if err := _elem4.Read(iprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", _elem4), err) + } + p.Tags = append(p.Tags, _elem4) + } + if err := iprot.ReadListEnd(); err != nil { + return thrift.PrependError("error reading list end: ", err) + } + return nil +} + +func (p *Process) Write(oprot thrift.TProtocol) error { + if err := oprot.WriteStructBegin("Process"); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) + } + if err := p.writeField1(oprot); err != nil { + return err + } + if err := p.writeField2(oprot); err != nil { + return err + } + if err := oprot.WriteFieldStop(); err != nil { + return thrift.PrependError("write field stop error: ", err) + } + if err := oprot.WriteStructEnd(); err != nil { + return thrift.PrependError("write struct stop error: ", err) + } + return nil +} + +func (p *Process) writeField1(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("serviceName", thrift.STRING, 1); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:serviceName: ", p), err) + } + if err := oprot.WriteString(string(p.ServiceName)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.serviceName (1) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 1:serviceName: ", p), err) + } + return err +} + +func (p *Process) writeField2(oprot thrift.TProtocol) (err error) { + if p.IsSetTags() { + if err := oprot.WriteFieldBegin("tags", thrift.LIST, 2); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:tags: ", p), err) + } + if err := oprot.WriteListBegin(thrift.STRUCT, len(p.Tags)); err != nil { + return thrift.PrependError("error writing list begin: ", err) + } + for _, v := range p.Tags { + if err := v.Write(oprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", v), err) + } + } + if err := oprot.WriteListEnd(); err != nil { + return thrift.PrependError("error writing list end: ", err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 2:tags: ", p), err) + } + } + return err +} + +func (p *Process) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("Process(%+v)", *p) +} + +// Attributes: +// - Process +// - Spans +type Batch struct { + Process *Process `thrift:"process,1,required" json:"process"` + Spans []*Span `thrift:"spans,2,required" json:"spans"` +} + +func NewBatch() *Batch { + return &Batch{} +} + +var Batch_Process_DEFAULT *Process + +func (p *Batch) GetProcess() *Process { + if !p.IsSetProcess() { + return Batch_Process_DEFAULT + } + return p.Process +} + +func (p *Batch) GetSpans() []*Span { + return p.Spans +} +func (p *Batch) IsSetProcess() bool { + return p.Process != nil +} + +func (p *Batch) Read(iprot thrift.TProtocol) error { + if _, err := iprot.ReadStructBegin(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) + } + + var issetProcess bool = false + var issetSpans bool = false + + for { + _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() + if err != nil { + return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) + } + if fieldTypeId == thrift.STOP { + break + } + switch fieldId { + case 1: + if err := p.readField1(iprot); err != nil { + return err + } + issetProcess = true + case 2: + if err := p.readField2(iprot); err != nil { + return err + } + issetSpans = true + default: + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + if err := iprot.ReadFieldEnd(); err != nil { + return err + } + } + if err := iprot.ReadStructEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) + } + if !issetProcess { + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field Process is not set")) + } + if !issetSpans { + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field Spans is not set")) + } + return nil +} + +func (p *Batch) readField1(iprot thrift.TProtocol) error { + p.Process = &Process{} + if err := p.Process.Read(iprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", p.Process), err) + } + return nil +} + +func (p *Batch) readField2(iprot thrift.TProtocol) error { + _, size, err := iprot.ReadListBegin() + if err != nil { + return thrift.PrependError("error reading list begin: ", err) + } + tSlice := make([]*Span, 0, size) + p.Spans = tSlice + for i := 0; i < size; i++ { + _elem5 := &Span{} + if err := _elem5.Read(iprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", _elem5), err) + } + p.Spans = append(p.Spans, _elem5) + } + if err := iprot.ReadListEnd(); err != nil { + return thrift.PrependError("error reading list end: ", err) + } + return nil +} + +func (p *Batch) Write(oprot thrift.TProtocol) error { + if err := oprot.WriteStructBegin("Batch"); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) + } + if err := p.writeField1(oprot); err != nil { + return err + } + if err := p.writeField2(oprot); err != nil { + return err + } + if err := oprot.WriteFieldStop(); err != nil { + return thrift.PrependError("write field stop error: ", err) + } + if err := oprot.WriteStructEnd(); err != nil { + return thrift.PrependError("write struct stop error: ", err) + } + return nil +} + +func (p *Batch) writeField1(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("process", thrift.STRUCT, 1); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:process: ", p), err) + } + if err := p.Process.Write(oprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", p.Process), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 1:process: ", p), err) + } + return err +} + +func (p *Batch) writeField2(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("spans", thrift.LIST, 2); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:spans: ", p), err) + } + if err := oprot.WriteListBegin(thrift.STRUCT, len(p.Spans)); err != nil { + return thrift.PrependError("error writing list begin: ", err) + } + for _, v := range p.Spans { + if err := v.Write(oprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", v), err) + } + } + if err := oprot.WriteListEnd(); err != nil { + return thrift.PrependError("error writing list end: ", err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 2:spans: ", p), err) + } + return err +} + +func (p *Batch) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("Batch(%+v)", *p) +} + +// Attributes: +// - Ok +type BatchSubmitResponse struct { + Ok bool `thrift:"ok,1,required" json:"ok"` +} + +func NewBatchSubmitResponse() *BatchSubmitResponse { + return &BatchSubmitResponse{} +} + +func (p *BatchSubmitResponse) GetOk() bool { + return p.Ok +} +func (p *BatchSubmitResponse) Read(iprot thrift.TProtocol) error { + if _, err := iprot.ReadStructBegin(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) + } + + var issetOk bool = false + + for { + _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() + if err != nil { + return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) + } + if fieldTypeId == thrift.STOP { + break + } + switch fieldId { + case 1: + if err := p.readField1(iprot); err != nil { + return err + } + issetOk = true + default: + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + if err := iprot.ReadFieldEnd(); err != nil { + return err + } + } + if err := iprot.ReadStructEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) + } + if !issetOk { + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field Ok is not set")) + } + return nil +} + +func (p *BatchSubmitResponse) readField1(iprot thrift.TProtocol) error { + if v, err := iprot.ReadBool(); err != nil { + return thrift.PrependError("error reading field 1: ", err) + } else { + p.Ok = v + } + return nil +} + +func (p *BatchSubmitResponse) Write(oprot thrift.TProtocol) error { + if err := oprot.WriteStructBegin("BatchSubmitResponse"); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) + } + if err := p.writeField1(oprot); err != nil { + return err + } + if err := oprot.WriteFieldStop(); err != nil { + return thrift.PrependError("write field stop error: ", err) + } + if err := oprot.WriteStructEnd(); err != nil { + return thrift.PrependError("write struct stop error: ", err) + } + return nil +} + +func (p *BatchSubmitResponse) writeField1(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("ok", thrift.BOOL, 1); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:ok: ", p), err) + } + if err := oprot.WriteBool(bool(p.Ok)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.ok (1) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 1:ok: ", p), err) + } + return err +} + +func (p *BatchSubmitResponse) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("BatchSubmitResponse(%+v)", *p) +} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift-gen/sampling/constants.go b/vendor/github.com/uber/jaeger-client-go/thrift-gen/sampling/constants.go new file mode 100644 index 0000000000..0f6e3a884d --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/thrift-gen/sampling/constants.go @@ -0,0 +1,18 @@ +// Autogenerated by Thrift Compiler (0.9.3) +// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + +package sampling + +import ( + "bytes" + "fmt" + "github.com/uber/jaeger-client-go/thrift" +) + +// (needed to ensure safety because of naive import list construction.) +var _ = thrift.ZERO +var _ = fmt.Printf +var _ = bytes.Equal + +func init() { +} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift-gen/sampling/samplingmanager.go b/vendor/github.com/uber/jaeger-client-go/thrift-gen/sampling/samplingmanager.go new file mode 100644 index 0000000000..33179cfeb3 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/thrift-gen/sampling/samplingmanager.go @@ -0,0 +1,410 @@ +// Autogenerated by Thrift Compiler (0.9.3) +// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + +package sampling + +import ( + "bytes" + "fmt" + "github.com/uber/jaeger-client-go/thrift" +) + +// (needed to ensure safety because of naive import list construction.) +var _ = thrift.ZERO +var _ = fmt.Printf +var _ = bytes.Equal + +type SamplingManager interface { + // Parameters: + // - ServiceName + GetSamplingStrategy(serviceName string) (r *SamplingStrategyResponse, err error) +} + +type SamplingManagerClient struct { + Transport thrift.TTransport + ProtocolFactory thrift.TProtocolFactory + InputProtocol thrift.TProtocol + OutputProtocol thrift.TProtocol + SeqId int32 +} + +func NewSamplingManagerClientFactory(t thrift.TTransport, f thrift.TProtocolFactory) *SamplingManagerClient { + return &SamplingManagerClient{Transport: t, + ProtocolFactory: f, + InputProtocol: f.GetProtocol(t), + OutputProtocol: f.GetProtocol(t), + SeqId: 0, + } +} + +func NewSamplingManagerClientProtocol(t thrift.TTransport, iprot thrift.TProtocol, oprot thrift.TProtocol) *SamplingManagerClient { + return &SamplingManagerClient{Transport: t, + ProtocolFactory: nil, + InputProtocol: iprot, + OutputProtocol: oprot, + SeqId: 0, + } +} + +// Parameters: +// - ServiceName +func (p *SamplingManagerClient) GetSamplingStrategy(serviceName string) (r *SamplingStrategyResponse, err error) { + if err = p.sendGetSamplingStrategy(serviceName); err != nil { + return + } + return p.recvGetSamplingStrategy() +} + +func (p *SamplingManagerClient) sendGetSamplingStrategy(serviceName string) (err error) { + oprot := p.OutputProtocol + if oprot == nil { + oprot = p.ProtocolFactory.GetProtocol(p.Transport) + p.OutputProtocol = oprot + } + p.SeqId++ + if err = oprot.WriteMessageBegin("getSamplingStrategy", thrift.CALL, p.SeqId); err != nil { + return + } + args := SamplingManagerGetSamplingStrategyArgs{ + ServiceName: serviceName, + } + if err = args.Write(oprot); err != nil { + return + } + if err = oprot.WriteMessageEnd(); err != nil { + return + } + return oprot.Flush() +} + +func (p *SamplingManagerClient) recvGetSamplingStrategy() (value *SamplingStrategyResponse, err error) { + iprot := p.InputProtocol + if iprot == nil { + iprot = p.ProtocolFactory.GetProtocol(p.Transport) + p.InputProtocol = iprot + } + method, mTypeId, seqId, err := iprot.ReadMessageBegin() + if err != nil { + return + } + if method != "getSamplingStrategy" { + err = thrift.NewTApplicationException(thrift.WRONG_METHOD_NAME, "getSamplingStrategy failed: wrong method name") + return + } + if p.SeqId != seqId { + err = thrift.NewTApplicationException(thrift.BAD_SEQUENCE_ID, "getSamplingStrategy failed: out of sequence response") + return + } + if mTypeId == thrift.EXCEPTION { + error1 := thrift.NewTApplicationException(thrift.UNKNOWN_APPLICATION_EXCEPTION, "Unknown Exception") + var error2 error + error2, err = error1.Read(iprot) + if err != nil { + return + } + if err = iprot.ReadMessageEnd(); err != nil { + return + } + err = error2 + return + } + if mTypeId != thrift.REPLY { + err = thrift.NewTApplicationException(thrift.INVALID_MESSAGE_TYPE_EXCEPTION, "getSamplingStrategy failed: invalid message type") + return + } + result := SamplingManagerGetSamplingStrategyResult{} + if err = result.Read(iprot); err != nil { + return + } + if err = iprot.ReadMessageEnd(); err != nil { + return + } + value = result.GetSuccess() + return +} + +type SamplingManagerProcessor struct { + processorMap map[string]thrift.TProcessorFunction + handler SamplingManager +} + +func (p *SamplingManagerProcessor) AddToProcessorMap(key string, processor thrift.TProcessorFunction) { + p.processorMap[key] = processor +} + +func (p *SamplingManagerProcessor) GetProcessorFunction(key string) (processor thrift.TProcessorFunction, ok bool) { + processor, ok = p.processorMap[key] + return processor, ok +} + +func (p *SamplingManagerProcessor) ProcessorMap() map[string]thrift.TProcessorFunction { + return p.processorMap +} + +func NewSamplingManagerProcessor(handler SamplingManager) *SamplingManagerProcessor { + + self3 := &SamplingManagerProcessor{handler: handler, processorMap: make(map[string]thrift.TProcessorFunction)} + self3.processorMap["getSamplingStrategy"] = &samplingManagerProcessorGetSamplingStrategy{handler: handler} + return self3 +} + +func (p *SamplingManagerProcessor) Process(iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { + name, _, seqId, err := iprot.ReadMessageBegin() + if err != nil { + return false, err + } + if processor, ok := p.GetProcessorFunction(name); ok { + return processor.Process(seqId, iprot, oprot) + } + iprot.Skip(thrift.STRUCT) + iprot.ReadMessageEnd() + x4 := thrift.NewTApplicationException(thrift.UNKNOWN_METHOD, "Unknown function "+name) + oprot.WriteMessageBegin(name, thrift.EXCEPTION, seqId) + x4.Write(oprot) + oprot.WriteMessageEnd() + oprot.Flush() + return false, x4 + +} + +type samplingManagerProcessorGetSamplingStrategy struct { + handler SamplingManager +} + +func (p *samplingManagerProcessorGetSamplingStrategy) Process(seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { + args := SamplingManagerGetSamplingStrategyArgs{} + if err = args.Read(iprot); err != nil { + iprot.ReadMessageEnd() + x := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err.Error()) + oprot.WriteMessageBegin("getSamplingStrategy", thrift.EXCEPTION, seqId) + x.Write(oprot) + oprot.WriteMessageEnd() + oprot.Flush() + return false, err + } + + iprot.ReadMessageEnd() + result := SamplingManagerGetSamplingStrategyResult{} + var retval *SamplingStrategyResponse + var err2 error + if retval, err2 = p.handler.GetSamplingStrategy(args.ServiceName); err2 != nil { + x := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, "Internal error processing getSamplingStrategy: "+err2.Error()) + oprot.WriteMessageBegin("getSamplingStrategy", thrift.EXCEPTION, seqId) + x.Write(oprot) + oprot.WriteMessageEnd() + oprot.Flush() + return true, err2 + } else { + result.Success = retval + } + if err2 = oprot.WriteMessageBegin("getSamplingStrategy", thrift.REPLY, seqId); err2 != nil { + err = err2 + } + if err2 = result.Write(oprot); err == nil && err2 != nil { + err = err2 + } + if err2 = oprot.WriteMessageEnd(); err == nil && err2 != nil { + err = err2 + } + if err2 = oprot.Flush(); err == nil && err2 != nil { + err = err2 + } + if err != nil { + return + } + return true, err +} + +// HELPER FUNCTIONS AND STRUCTURES + +// Attributes: +// - ServiceName +type SamplingManagerGetSamplingStrategyArgs struct { + ServiceName string `thrift:"serviceName,1" json:"serviceName"` +} + +func NewSamplingManagerGetSamplingStrategyArgs() *SamplingManagerGetSamplingStrategyArgs { + return &SamplingManagerGetSamplingStrategyArgs{} +} + +func (p *SamplingManagerGetSamplingStrategyArgs) GetServiceName() string { + return p.ServiceName +} +func (p *SamplingManagerGetSamplingStrategyArgs) Read(iprot thrift.TProtocol) error { + if _, err := iprot.ReadStructBegin(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) + } + + for { + _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() + if err != nil { + return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) + } + if fieldTypeId == thrift.STOP { + break + } + switch fieldId { + case 1: + if err := p.readField1(iprot); err != nil { + return err + } + default: + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + if err := iprot.ReadFieldEnd(); err != nil { + return err + } + } + if err := iprot.ReadStructEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) + } + return nil +} + +func (p *SamplingManagerGetSamplingStrategyArgs) readField1(iprot thrift.TProtocol) error { + if v, err := iprot.ReadString(); err != nil { + return thrift.PrependError("error reading field 1: ", err) + } else { + p.ServiceName = v + } + return nil +} + +func (p *SamplingManagerGetSamplingStrategyArgs) Write(oprot thrift.TProtocol) error { + if err := oprot.WriteStructBegin("getSamplingStrategy_args"); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) + } + if err := p.writeField1(oprot); err != nil { + return err + } + if err := oprot.WriteFieldStop(); err != nil { + return thrift.PrependError("write field stop error: ", err) + } + if err := oprot.WriteStructEnd(); err != nil { + return thrift.PrependError("write struct stop error: ", err) + } + return nil +} + +func (p *SamplingManagerGetSamplingStrategyArgs) writeField1(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("serviceName", thrift.STRING, 1); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:serviceName: ", p), err) + } + if err := oprot.WriteString(string(p.ServiceName)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.serviceName (1) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 1:serviceName: ", p), err) + } + return err +} + +func (p *SamplingManagerGetSamplingStrategyArgs) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("SamplingManagerGetSamplingStrategyArgs(%+v)", *p) +} + +// Attributes: +// - Success +type SamplingManagerGetSamplingStrategyResult struct { + Success *SamplingStrategyResponse `thrift:"success,0" json:"success,omitempty"` +} + +func NewSamplingManagerGetSamplingStrategyResult() *SamplingManagerGetSamplingStrategyResult { + return &SamplingManagerGetSamplingStrategyResult{} +} + +var SamplingManagerGetSamplingStrategyResult_Success_DEFAULT *SamplingStrategyResponse + +func (p *SamplingManagerGetSamplingStrategyResult) GetSuccess() *SamplingStrategyResponse { + if !p.IsSetSuccess() { + return SamplingManagerGetSamplingStrategyResult_Success_DEFAULT + } + return p.Success +} +func (p *SamplingManagerGetSamplingStrategyResult) IsSetSuccess() bool { + return p.Success != nil +} + +func (p *SamplingManagerGetSamplingStrategyResult) Read(iprot thrift.TProtocol) error { + if _, err := iprot.ReadStructBegin(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) + } + + for { + _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() + if err != nil { + return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) + } + if fieldTypeId == thrift.STOP { + break + } + switch fieldId { + case 0: + if err := p.readField0(iprot); err != nil { + return err + } + default: + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + if err := iprot.ReadFieldEnd(); err != nil { + return err + } + } + if err := iprot.ReadStructEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) + } + return nil +} + +func (p *SamplingManagerGetSamplingStrategyResult) readField0(iprot thrift.TProtocol) error { + p.Success = &SamplingStrategyResponse{} + if err := p.Success.Read(iprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", p.Success), err) + } + return nil +} + +func (p *SamplingManagerGetSamplingStrategyResult) Write(oprot thrift.TProtocol) error { + if err := oprot.WriteStructBegin("getSamplingStrategy_result"); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) + } + if err := p.writeField0(oprot); err != nil { + return err + } + if err := oprot.WriteFieldStop(); err != nil { + return thrift.PrependError("write field stop error: ", err) + } + if err := oprot.WriteStructEnd(); err != nil { + return thrift.PrependError("write struct stop error: ", err) + } + return nil +} + +func (p *SamplingManagerGetSamplingStrategyResult) writeField0(oprot thrift.TProtocol) (err error) { + if p.IsSetSuccess() { + if err := oprot.WriteFieldBegin("success", thrift.STRUCT, 0); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 0:success: ", p), err) + } + if err := p.Success.Write(oprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", p.Success), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 0:success: ", p), err) + } + } + return err +} + +func (p *SamplingManagerGetSamplingStrategyResult) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("SamplingManagerGetSamplingStrategyResult(%+v)", *p) +} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift-gen/sampling/ttypes.go b/vendor/github.com/uber/jaeger-client-go/thrift-gen/sampling/ttypes.go new file mode 100644 index 0000000000..9abaf0542d --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/thrift-gen/sampling/ttypes.go @@ -0,0 +1,873 @@ +// Autogenerated by Thrift Compiler (0.9.3) +// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + +package sampling + +import ( + "bytes" + "fmt" + "github.com/uber/jaeger-client-go/thrift" +) + +// (needed to ensure safety because of naive import list construction.) +var _ = thrift.ZERO +var _ = fmt.Printf +var _ = bytes.Equal + +var GoUnusedProtection__ int + +type SamplingStrategyType int64 + +const ( + SamplingStrategyType_PROBABILISTIC SamplingStrategyType = 0 + SamplingStrategyType_RATE_LIMITING SamplingStrategyType = 1 +) + +func (p SamplingStrategyType) String() string { + switch p { + case SamplingStrategyType_PROBABILISTIC: + return "PROBABILISTIC" + case SamplingStrategyType_RATE_LIMITING: + return "RATE_LIMITING" + } + return "" +} + +func SamplingStrategyTypeFromString(s string) (SamplingStrategyType, error) { + switch s { + case "PROBABILISTIC": + return SamplingStrategyType_PROBABILISTIC, nil + case "RATE_LIMITING": + return SamplingStrategyType_RATE_LIMITING, nil + } + return SamplingStrategyType(0), fmt.Errorf("not a valid SamplingStrategyType string") +} + +func SamplingStrategyTypePtr(v SamplingStrategyType) *SamplingStrategyType { return &v } + +func (p SamplingStrategyType) MarshalText() ([]byte, error) { + return []byte(p.String()), nil +} + +func (p *SamplingStrategyType) UnmarshalText(text []byte) error { + q, err := SamplingStrategyTypeFromString(string(text)) + if err != nil { + return err + } + *p = q + return nil +} + +// Attributes: +// - SamplingRate +type ProbabilisticSamplingStrategy struct { + SamplingRate float64 `thrift:"samplingRate,1,required" json:"samplingRate"` +} + +func NewProbabilisticSamplingStrategy() *ProbabilisticSamplingStrategy { + return &ProbabilisticSamplingStrategy{} +} + +func (p *ProbabilisticSamplingStrategy) GetSamplingRate() float64 { + return p.SamplingRate +} +func (p *ProbabilisticSamplingStrategy) Read(iprot thrift.TProtocol) error { + if _, err := iprot.ReadStructBegin(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) + } + + var issetSamplingRate bool = false + + for { + _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() + if err != nil { + return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) + } + if fieldTypeId == thrift.STOP { + break + } + switch fieldId { + case 1: + if err := p.readField1(iprot); err != nil { + return err + } + issetSamplingRate = true + default: + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + if err := iprot.ReadFieldEnd(); err != nil { + return err + } + } + if err := iprot.ReadStructEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) + } + if !issetSamplingRate { + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field SamplingRate is not set")) + } + return nil +} + +func (p *ProbabilisticSamplingStrategy) readField1(iprot thrift.TProtocol) error { + if v, err := iprot.ReadDouble(); err != nil { + return thrift.PrependError("error reading field 1: ", err) + } else { + p.SamplingRate = v + } + return nil +} + +func (p *ProbabilisticSamplingStrategy) Write(oprot thrift.TProtocol) error { + if err := oprot.WriteStructBegin("ProbabilisticSamplingStrategy"); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) + } + if err := p.writeField1(oprot); err != nil { + return err + } + if err := oprot.WriteFieldStop(); err != nil { + return thrift.PrependError("write field stop error: ", err) + } + if err := oprot.WriteStructEnd(); err != nil { + return thrift.PrependError("write struct stop error: ", err) + } + return nil +} + +func (p *ProbabilisticSamplingStrategy) writeField1(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("samplingRate", thrift.DOUBLE, 1); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:samplingRate: ", p), err) + } + if err := oprot.WriteDouble(float64(p.SamplingRate)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.samplingRate (1) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 1:samplingRate: ", p), err) + } + return err +} + +func (p *ProbabilisticSamplingStrategy) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("ProbabilisticSamplingStrategy(%+v)", *p) +} + +// Attributes: +// - MaxTracesPerSecond +type RateLimitingSamplingStrategy struct { + MaxTracesPerSecond int16 `thrift:"maxTracesPerSecond,1,required" json:"maxTracesPerSecond"` +} + +func NewRateLimitingSamplingStrategy() *RateLimitingSamplingStrategy { + return &RateLimitingSamplingStrategy{} +} + +func (p *RateLimitingSamplingStrategy) GetMaxTracesPerSecond() int16 { + return p.MaxTracesPerSecond +} +func (p *RateLimitingSamplingStrategy) Read(iprot thrift.TProtocol) error { + if _, err := iprot.ReadStructBegin(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) + } + + var issetMaxTracesPerSecond bool = false + + for { + _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() + if err != nil { + return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) + } + if fieldTypeId == thrift.STOP { + break + } + switch fieldId { + case 1: + if err := p.readField1(iprot); err != nil { + return err + } + issetMaxTracesPerSecond = true + default: + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + if err := iprot.ReadFieldEnd(); err != nil { + return err + } + } + if err := iprot.ReadStructEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) + } + if !issetMaxTracesPerSecond { + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field MaxTracesPerSecond is not set")) + } + return nil +} + +func (p *RateLimitingSamplingStrategy) readField1(iprot thrift.TProtocol) error { + if v, err := iprot.ReadI16(); err != nil { + return thrift.PrependError("error reading field 1: ", err) + } else { + p.MaxTracesPerSecond = v + } + return nil +} + +func (p *RateLimitingSamplingStrategy) Write(oprot thrift.TProtocol) error { + if err := oprot.WriteStructBegin("RateLimitingSamplingStrategy"); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) + } + if err := p.writeField1(oprot); err != nil { + return err + } + if err := oprot.WriteFieldStop(); err != nil { + return thrift.PrependError("write field stop error: ", err) + } + if err := oprot.WriteStructEnd(); err != nil { + return thrift.PrependError("write struct stop error: ", err) + } + return nil +} + +func (p *RateLimitingSamplingStrategy) writeField1(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("maxTracesPerSecond", thrift.I16, 1); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:maxTracesPerSecond: ", p), err) + } + if err := oprot.WriteI16(int16(p.MaxTracesPerSecond)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.maxTracesPerSecond (1) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 1:maxTracesPerSecond: ", p), err) + } + return err +} + +func (p *RateLimitingSamplingStrategy) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("RateLimitingSamplingStrategy(%+v)", *p) +} + +// Attributes: +// - Operation +// - ProbabilisticSampling +type OperationSamplingStrategy struct { + Operation string `thrift:"operation,1,required" json:"operation"` + ProbabilisticSampling *ProbabilisticSamplingStrategy `thrift:"probabilisticSampling,2,required" json:"probabilisticSampling"` +} + +func NewOperationSamplingStrategy() *OperationSamplingStrategy { + return &OperationSamplingStrategy{} +} + +func (p *OperationSamplingStrategy) GetOperation() string { + return p.Operation +} + +var OperationSamplingStrategy_ProbabilisticSampling_DEFAULT *ProbabilisticSamplingStrategy + +func (p *OperationSamplingStrategy) GetProbabilisticSampling() *ProbabilisticSamplingStrategy { + if !p.IsSetProbabilisticSampling() { + return OperationSamplingStrategy_ProbabilisticSampling_DEFAULT + } + return p.ProbabilisticSampling +} +func (p *OperationSamplingStrategy) IsSetProbabilisticSampling() bool { + return p.ProbabilisticSampling != nil +} + +func (p *OperationSamplingStrategy) Read(iprot thrift.TProtocol) error { + if _, err := iprot.ReadStructBegin(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) + } + + var issetOperation bool = false + var issetProbabilisticSampling bool = false + + for { + _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() + if err != nil { + return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) + } + if fieldTypeId == thrift.STOP { + break + } + switch fieldId { + case 1: + if err := p.readField1(iprot); err != nil { + return err + } + issetOperation = true + case 2: + if err := p.readField2(iprot); err != nil { + return err + } + issetProbabilisticSampling = true + default: + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + if err := iprot.ReadFieldEnd(); err != nil { + return err + } + } + if err := iprot.ReadStructEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) + } + if !issetOperation { + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field Operation is not set")) + } + if !issetProbabilisticSampling { + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field ProbabilisticSampling is not set")) + } + return nil +} + +func (p *OperationSamplingStrategy) readField1(iprot thrift.TProtocol) error { + if v, err := iprot.ReadString(); err != nil { + return thrift.PrependError("error reading field 1: ", err) + } else { + p.Operation = v + } + return nil +} + +func (p *OperationSamplingStrategy) readField2(iprot thrift.TProtocol) error { + p.ProbabilisticSampling = &ProbabilisticSamplingStrategy{} + if err := p.ProbabilisticSampling.Read(iprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", p.ProbabilisticSampling), err) + } + return nil +} + +func (p *OperationSamplingStrategy) Write(oprot thrift.TProtocol) error { + if err := oprot.WriteStructBegin("OperationSamplingStrategy"); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) + } + if err := p.writeField1(oprot); err != nil { + return err + } + if err := p.writeField2(oprot); err != nil { + return err + } + if err := oprot.WriteFieldStop(); err != nil { + return thrift.PrependError("write field stop error: ", err) + } + if err := oprot.WriteStructEnd(); err != nil { + return thrift.PrependError("write struct stop error: ", err) + } + return nil +} + +func (p *OperationSamplingStrategy) writeField1(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("operation", thrift.STRING, 1); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:operation: ", p), err) + } + if err := oprot.WriteString(string(p.Operation)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.operation (1) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 1:operation: ", p), err) + } + return err +} + +func (p *OperationSamplingStrategy) writeField2(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("probabilisticSampling", thrift.STRUCT, 2); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:probabilisticSampling: ", p), err) + } + if err := p.ProbabilisticSampling.Write(oprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", p.ProbabilisticSampling), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 2:probabilisticSampling: ", p), err) + } + return err +} + +func (p *OperationSamplingStrategy) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("OperationSamplingStrategy(%+v)", *p) +} + +// Attributes: +// - DefaultSamplingProbability +// - DefaultLowerBoundTracesPerSecond +// - PerOperationStrategies +// - DefaultUpperBoundTracesPerSecond +type PerOperationSamplingStrategies struct { + DefaultSamplingProbability float64 `thrift:"defaultSamplingProbability,1,required" json:"defaultSamplingProbability"` + DefaultLowerBoundTracesPerSecond float64 `thrift:"defaultLowerBoundTracesPerSecond,2,required" json:"defaultLowerBoundTracesPerSecond"` + PerOperationStrategies []*OperationSamplingStrategy `thrift:"perOperationStrategies,3,required" json:"perOperationStrategies"` + DefaultUpperBoundTracesPerSecond *float64 `thrift:"defaultUpperBoundTracesPerSecond,4" json:"defaultUpperBoundTracesPerSecond,omitempty"` +} + +func NewPerOperationSamplingStrategies() *PerOperationSamplingStrategies { + return &PerOperationSamplingStrategies{} +} + +func (p *PerOperationSamplingStrategies) GetDefaultSamplingProbability() float64 { + return p.DefaultSamplingProbability +} + +func (p *PerOperationSamplingStrategies) GetDefaultLowerBoundTracesPerSecond() float64 { + return p.DefaultLowerBoundTracesPerSecond +} + +func (p *PerOperationSamplingStrategies) GetPerOperationStrategies() []*OperationSamplingStrategy { + return p.PerOperationStrategies +} + +var PerOperationSamplingStrategies_DefaultUpperBoundTracesPerSecond_DEFAULT float64 + +func (p *PerOperationSamplingStrategies) GetDefaultUpperBoundTracesPerSecond() float64 { + if !p.IsSetDefaultUpperBoundTracesPerSecond() { + return PerOperationSamplingStrategies_DefaultUpperBoundTracesPerSecond_DEFAULT + } + return *p.DefaultUpperBoundTracesPerSecond +} +func (p *PerOperationSamplingStrategies) IsSetDefaultUpperBoundTracesPerSecond() bool { + return p.DefaultUpperBoundTracesPerSecond != nil +} + +func (p *PerOperationSamplingStrategies) Read(iprot thrift.TProtocol) error { + if _, err := iprot.ReadStructBegin(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) + } + + var issetDefaultSamplingProbability bool = false + var issetDefaultLowerBoundTracesPerSecond bool = false + var issetPerOperationStrategies bool = false + + for { + _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() + if err != nil { + return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) + } + if fieldTypeId == thrift.STOP { + break + } + switch fieldId { + case 1: + if err := p.readField1(iprot); err != nil { + return err + } + issetDefaultSamplingProbability = true + case 2: + if err := p.readField2(iprot); err != nil { + return err + } + issetDefaultLowerBoundTracesPerSecond = true + case 3: + if err := p.readField3(iprot); err != nil { + return err + } + issetPerOperationStrategies = true + case 4: + if err := p.readField4(iprot); err != nil { + return err + } + default: + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + if err := iprot.ReadFieldEnd(); err != nil { + return err + } + } + if err := iprot.ReadStructEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) + } + if !issetDefaultSamplingProbability { + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field DefaultSamplingProbability is not set")) + } + if !issetDefaultLowerBoundTracesPerSecond { + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field DefaultLowerBoundTracesPerSecond is not set")) + } + if !issetPerOperationStrategies { + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field PerOperationStrategies is not set")) + } + return nil +} + +func (p *PerOperationSamplingStrategies) readField1(iprot thrift.TProtocol) error { + if v, err := iprot.ReadDouble(); err != nil { + return thrift.PrependError("error reading field 1: ", err) + } else { + p.DefaultSamplingProbability = v + } + return nil +} + +func (p *PerOperationSamplingStrategies) readField2(iprot thrift.TProtocol) error { + if v, err := iprot.ReadDouble(); err != nil { + return thrift.PrependError("error reading field 2: ", err) + } else { + p.DefaultLowerBoundTracesPerSecond = v + } + return nil +} + +func (p *PerOperationSamplingStrategies) readField3(iprot thrift.TProtocol) error { + _, size, err := iprot.ReadListBegin() + if err != nil { + return thrift.PrependError("error reading list begin: ", err) + } + tSlice := make([]*OperationSamplingStrategy, 0, size) + p.PerOperationStrategies = tSlice + for i := 0; i < size; i++ { + _elem0 := &OperationSamplingStrategy{} + if err := _elem0.Read(iprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", _elem0), err) + } + p.PerOperationStrategies = append(p.PerOperationStrategies, _elem0) + } + if err := iprot.ReadListEnd(); err != nil { + return thrift.PrependError("error reading list end: ", err) + } + return nil +} + +func (p *PerOperationSamplingStrategies) readField4(iprot thrift.TProtocol) error { + if v, err := iprot.ReadDouble(); err != nil { + return thrift.PrependError("error reading field 4: ", err) + } else { + p.DefaultUpperBoundTracesPerSecond = &v + } + return nil +} + +func (p *PerOperationSamplingStrategies) Write(oprot thrift.TProtocol) error { + if err := oprot.WriteStructBegin("PerOperationSamplingStrategies"); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) + } + if err := p.writeField1(oprot); err != nil { + return err + } + if err := p.writeField2(oprot); err != nil { + return err + } + if err := p.writeField3(oprot); err != nil { + return err + } + if err := p.writeField4(oprot); err != nil { + return err + } + if err := oprot.WriteFieldStop(); err != nil { + return thrift.PrependError("write field stop error: ", err) + } + if err := oprot.WriteStructEnd(); err != nil { + return thrift.PrependError("write struct stop error: ", err) + } + return nil +} + +func (p *PerOperationSamplingStrategies) writeField1(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("defaultSamplingProbability", thrift.DOUBLE, 1); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:defaultSamplingProbability: ", p), err) + } + if err := oprot.WriteDouble(float64(p.DefaultSamplingProbability)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.defaultSamplingProbability (1) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 1:defaultSamplingProbability: ", p), err) + } + return err +} + +func (p *PerOperationSamplingStrategies) writeField2(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("defaultLowerBoundTracesPerSecond", thrift.DOUBLE, 2); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:defaultLowerBoundTracesPerSecond: ", p), err) + } + if err := oprot.WriteDouble(float64(p.DefaultLowerBoundTracesPerSecond)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.defaultLowerBoundTracesPerSecond (2) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 2:defaultLowerBoundTracesPerSecond: ", p), err) + } + return err +} + +func (p *PerOperationSamplingStrategies) writeField3(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("perOperationStrategies", thrift.LIST, 3); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 3:perOperationStrategies: ", p), err) + } + if err := oprot.WriteListBegin(thrift.STRUCT, len(p.PerOperationStrategies)); err != nil { + return thrift.PrependError("error writing list begin: ", err) + } + for _, v := range p.PerOperationStrategies { + if err := v.Write(oprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", v), err) + } + } + if err := oprot.WriteListEnd(); err != nil { + return thrift.PrependError("error writing list end: ", err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 3:perOperationStrategies: ", p), err) + } + return err +} + +func (p *PerOperationSamplingStrategies) writeField4(oprot thrift.TProtocol) (err error) { + if p.IsSetDefaultUpperBoundTracesPerSecond() { + if err := oprot.WriteFieldBegin("defaultUpperBoundTracesPerSecond", thrift.DOUBLE, 4); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 4:defaultUpperBoundTracesPerSecond: ", p), err) + } + if err := oprot.WriteDouble(float64(*p.DefaultUpperBoundTracesPerSecond)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.defaultUpperBoundTracesPerSecond (4) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 4:defaultUpperBoundTracesPerSecond: ", p), err) + } + } + return err +} + +func (p *PerOperationSamplingStrategies) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("PerOperationSamplingStrategies(%+v)", *p) +} + +// Attributes: +// - StrategyType +// - ProbabilisticSampling +// - RateLimitingSampling +// - OperationSampling +type SamplingStrategyResponse struct { + StrategyType SamplingStrategyType `thrift:"strategyType,1,required" json:"strategyType"` + ProbabilisticSampling *ProbabilisticSamplingStrategy `thrift:"probabilisticSampling,2" json:"probabilisticSampling,omitempty"` + RateLimitingSampling *RateLimitingSamplingStrategy `thrift:"rateLimitingSampling,3" json:"rateLimitingSampling,omitempty"` + OperationSampling *PerOperationSamplingStrategies `thrift:"operationSampling,4" json:"operationSampling,omitempty"` +} + +func NewSamplingStrategyResponse() *SamplingStrategyResponse { + return &SamplingStrategyResponse{} +} + +func (p *SamplingStrategyResponse) GetStrategyType() SamplingStrategyType { + return p.StrategyType +} + +var SamplingStrategyResponse_ProbabilisticSampling_DEFAULT *ProbabilisticSamplingStrategy + +func (p *SamplingStrategyResponse) GetProbabilisticSampling() *ProbabilisticSamplingStrategy { + if !p.IsSetProbabilisticSampling() { + return SamplingStrategyResponse_ProbabilisticSampling_DEFAULT + } + return p.ProbabilisticSampling +} + +var SamplingStrategyResponse_RateLimitingSampling_DEFAULT *RateLimitingSamplingStrategy + +func (p *SamplingStrategyResponse) GetRateLimitingSampling() *RateLimitingSamplingStrategy { + if !p.IsSetRateLimitingSampling() { + return SamplingStrategyResponse_RateLimitingSampling_DEFAULT + } + return p.RateLimitingSampling +} + +var SamplingStrategyResponse_OperationSampling_DEFAULT *PerOperationSamplingStrategies + +func (p *SamplingStrategyResponse) GetOperationSampling() *PerOperationSamplingStrategies { + if !p.IsSetOperationSampling() { + return SamplingStrategyResponse_OperationSampling_DEFAULT + } + return p.OperationSampling +} +func (p *SamplingStrategyResponse) IsSetProbabilisticSampling() bool { + return p.ProbabilisticSampling != nil +} + +func (p *SamplingStrategyResponse) IsSetRateLimitingSampling() bool { + return p.RateLimitingSampling != nil +} + +func (p *SamplingStrategyResponse) IsSetOperationSampling() bool { + return p.OperationSampling != nil +} + +func (p *SamplingStrategyResponse) Read(iprot thrift.TProtocol) error { + if _, err := iprot.ReadStructBegin(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) + } + + var issetStrategyType bool = false + + for { + _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() + if err != nil { + return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) + } + if fieldTypeId == thrift.STOP { + break + } + switch fieldId { + case 1: + if err := p.readField1(iprot); err != nil { + return err + } + issetStrategyType = true + case 2: + if err := p.readField2(iprot); err != nil { + return err + } + case 3: + if err := p.readField3(iprot); err != nil { + return err + } + case 4: + if err := p.readField4(iprot); err != nil { + return err + } + default: + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + if err := iprot.ReadFieldEnd(); err != nil { + return err + } + } + if err := iprot.ReadStructEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) + } + if !issetStrategyType { + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field StrategyType is not set")) + } + return nil +} + +func (p *SamplingStrategyResponse) readField1(iprot thrift.TProtocol) error { + if v, err := iprot.ReadI32(); err != nil { + return thrift.PrependError("error reading field 1: ", err) + } else { + temp := SamplingStrategyType(v) + p.StrategyType = temp + } + return nil +} + +func (p *SamplingStrategyResponse) readField2(iprot thrift.TProtocol) error { + p.ProbabilisticSampling = &ProbabilisticSamplingStrategy{} + if err := p.ProbabilisticSampling.Read(iprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", p.ProbabilisticSampling), err) + } + return nil +} + +func (p *SamplingStrategyResponse) readField3(iprot thrift.TProtocol) error { + p.RateLimitingSampling = &RateLimitingSamplingStrategy{} + if err := p.RateLimitingSampling.Read(iprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", p.RateLimitingSampling), err) + } + return nil +} + +func (p *SamplingStrategyResponse) readField4(iprot thrift.TProtocol) error { + p.OperationSampling = &PerOperationSamplingStrategies{} + if err := p.OperationSampling.Read(iprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", p.OperationSampling), err) + } + return nil +} + +func (p *SamplingStrategyResponse) Write(oprot thrift.TProtocol) error { + if err := oprot.WriteStructBegin("SamplingStrategyResponse"); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) + } + if err := p.writeField1(oprot); err != nil { + return err + } + if err := p.writeField2(oprot); err != nil { + return err + } + if err := p.writeField3(oprot); err != nil { + return err + } + if err := p.writeField4(oprot); err != nil { + return err + } + if err := oprot.WriteFieldStop(); err != nil { + return thrift.PrependError("write field stop error: ", err) + } + if err := oprot.WriteStructEnd(); err != nil { + return thrift.PrependError("write struct stop error: ", err) + } + return nil +} + +func (p *SamplingStrategyResponse) writeField1(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("strategyType", thrift.I32, 1); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:strategyType: ", p), err) + } + if err := oprot.WriteI32(int32(p.StrategyType)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.strategyType (1) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 1:strategyType: ", p), err) + } + return err +} + +func (p *SamplingStrategyResponse) writeField2(oprot thrift.TProtocol) (err error) { + if p.IsSetProbabilisticSampling() { + if err := oprot.WriteFieldBegin("probabilisticSampling", thrift.STRUCT, 2); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:probabilisticSampling: ", p), err) + } + if err := p.ProbabilisticSampling.Write(oprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", p.ProbabilisticSampling), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 2:probabilisticSampling: ", p), err) + } + } + return err +} + +func (p *SamplingStrategyResponse) writeField3(oprot thrift.TProtocol) (err error) { + if p.IsSetRateLimitingSampling() { + if err := oprot.WriteFieldBegin("rateLimitingSampling", thrift.STRUCT, 3); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 3:rateLimitingSampling: ", p), err) + } + if err := p.RateLimitingSampling.Write(oprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", p.RateLimitingSampling), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 3:rateLimitingSampling: ", p), err) + } + } + return err +} + +func (p *SamplingStrategyResponse) writeField4(oprot thrift.TProtocol) (err error) { + if p.IsSetOperationSampling() { + if err := oprot.WriteFieldBegin("operationSampling", thrift.STRUCT, 4); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 4:operationSampling: ", p), err) + } + if err := p.OperationSampling.Write(oprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", p.OperationSampling), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 4:operationSampling: ", p), err) + } + } + return err +} + +func (p *SamplingStrategyResponse) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("SamplingStrategyResponse(%+v)", *p) +} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift-gen/zipkincore/constants.go b/vendor/github.com/uber/jaeger-client-go/thrift-gen/zipkincore/constants.go new file mode 100644 index 0000000000..f05144bfc6 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/thrift-gen/zipkincore/constants.go @@ -0,0 +1,32 @@ +// Autogenerated by Thrift Compiler (0.9.3) +// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + +package zipkincore + +import ( + "bytes" + "fmt" + "github.com/uber/jaeger-client-go/thrift" +) + +// (needed to ensure safety because of naive import list construction.) +var _ = thrift.ZERO +var _ = fmt.Printf +var _ = bytes.Equal + +const CLIENT_SEND = "cs" +const CLIENT_RECV = "cr" +const SERVER_SEND = "ss" +const SERVER_RECV = "sr" +const WIRE_SEND = "ws" +const WIRE_RECV = "wr" +const CLIENT_SEND_FRAGMENT = "csf" +const CLIENT_RECV_FRAGMENT = "crf" +const SERVER_SEND_FRAGMENT = "ssf" +const SERVER_RECV_FRAGMENT = "srf" +const LOCAL_COMPONENT = "lc" +const CLIENT_ADDR = "ca" +const SERVER_ADDR = "sa" + +func init() { +} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift-gen/zipkincore/ttypes.go b/vendor/github.com/uber/jaeger-client-go/thrift-gen/zipkincore/ttypes.go new file mode 100644 index 0000000000..34b2b267eb --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/thrift-gen/zipkincore/ttypes.go @@ -0,0 +1,1247 @@ +// Autogenerated by Thrift Compiler (0.9.3) +// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + +package zipkincore + +import ( + "bytes" + "fmt" + "github.com/uber/jaeger-client-go/thrift" +) + +// (needed to ensure safety because of naive import list construction.) +var _ = thrift.ZERO +var _ = fmt.Printf +var _ = bytes.Equal + +var GoUnusedProtection__ int + +type AnnotationType int64 + +const ( + AnnotationType_BOOL AnnotationType = 0 + AnnotationType_BYTES AnnotationType = 1 + AnnotationType_I16 AnnotationType = 2 + AnnotationType_I32 AnnotationType = 3 + AnnotationType_I64 AnnotationType = 4 + AnnotationType_DOUBLE AnnotationType = 5 + AnnotationType_STRING AnnotationType = 6 +) + +func (p AnnotationType) String() string { + switch p { + case AnnotationType_BOOL: + return "BOOL" + case AnnotationType_BYTES: + return "BYTES" + case AnnotationType_I16: + return "I16" + case AnnotationType_I32: + return "I32" + case AnnotationType_I64: + return "I64" + case AnnotationType_DOUBLE: + return "DOUBLE" + case AnnotationType_STRING: + return "STRING" + } + return "" +} + +func AnnotationTypeFromString(s string) (AnnotationType, error) { + switch s { + case "BOOL": + return AnnotationType_BOOL, nil + case "BYTES": + return AnnotationType_BYTES, nil + case "I16": + return AnnotationType_I16, nil + case "I32": + return AnnotationType_I32, nil + case "I64": + return AnnotationType_I64, nil + case "DOUBLE": + return AnnotationType_DOUBLE, nil + case "STRING": + return AnnotationType_STRING, nil + } + return AnnotationType(0), fmt.Errorf("not a valid AnnotationType string") +} + +func AnnotationTypePtr(v AnnotationType) *AnnotationType { return &v } + +func (p AnnotationType) MarshalText() ([]byte, error) { + return []byte(p.String()), nil +} + +func (p *AnnotationType) UnmarshalText(text []byte) error { + q, err := AnnotationTypeFromString(string(text)) + if err != nil { + return err + } + *p = q + return nil +} + +// Indicates the network context of a service recording an annotation with two +// exceptions. +// +// When a BinaryAnnotation, and key is CLIENT_ADDR or SERVER_ADDR, +// the endpoint indicates the source or destination of an RPC. This exception +// allows zipkin to display network context of uninstrumented services, or +// clients such as web browsers. +// +// Attributes: +// - Ipv4: IPv4 host address packed into 4 bytes. +// +// Ex for the ip 1.2.3.4, it would be (1 << 24) | (2 << 16) | (3 << 8) | 4 +// - Port: IPv4 port +// +// Note: this is to be treated as an unsigned integer, so watch for negatives. +// +// Conventionally, when the port isn't known, port = 0. +// - ServiceName: Service name in lowercase, such as "memcache" or "zipkin-web" +// +// Conventionally, when the service name isn't known, service_name = "unknown". +type Endpoint struct { + Ipv4 int32 `thrift:"ipv4,1" json:"ipv4"` + Port int16 `thrift:"port,2" json:"port"` + ServiceName string `thrift:"service_name,3" json:"service_name"` +} + +func NewEndpoint() *Endpoint { + return &Endpoint{} +} + +func (p *Endpoint) GetIpv4() int32 { + return p.Ipv4 +} + +func (p *Endpoint) GetPort() int16 { + return p.Port +} + +func (p *Endpoint) GetServiceName() string { + return p.ServiceName +} +func (p *Endpoint) Read(iprot thrift.TProtocol) error { + if _, err := iprot.ReadStructBegin(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) + } + + for { + _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() + if err != nil { + return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) + } + if fieldTypeId == thrift.STOP { + break + } + switch fieldId { + case 1: + if err := p.readField1(iprot); err != nil { + return err + } + case 2: + if err := p.readField2(iprot); err != nil { + return err + } + case 3: + if err := p.readField3(iprot); err != nil { + return err + } + default: + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + if err := iprot.ReadFieldEnd(); err != nil { + return err + } + } + if err := iprot.ReadStructEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) + } + return nil +} + +func (p *Endpoint) readField1(iprot thrift.TProtocol) error { + if v, err := iprot.ReadI32(); err != nil { + return thrift.PrependError("error reading field 1: ", err) + } else { + p.Ipv4 = v + } + return nil +} + +func (p *Endpoint) readField2(iprot thrift.TProtocol) error { + if v, err := iprot.ReadI16(); err != nil { + return thrift.PrependError("error reading field 2: ", err) + } else { + p.Port = v + } + return nil +} + +func (p *Endpoint) readField3(iprot thrift.TProtocol) error { + if v, err := iprot.ReadString(); err != nil { + return thrift.PrependError("error reading field 3: ", err) + } else { + p.ServiceName = v + } + return nil +} + +func (p *Endpoint) Write(oprot thrift.TProtocol) error { + if err := oprot.WriteStructBegin("Endpoint"); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) + } + if err := p.writeField1(oprot); err != nil { + return err + } + if err := p.writeField2(oprot); err != nil { + return err + } + if err := p.writeField3(oprot); err != nil { + return err + } + if err := oprot.WriteFieldStop(); err != nil { + return thrift.PrependError("write field stop error: ", err) + } + if err := oprot.WriteStructEnd(); err != nil { + return thrift.PrependError("write struct stop error: ", err) + } + return nil +} + +func (p *Endpoint) writeField1(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("ipv4", thrift.I32, 1); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:ipv4: ", p), err) + } + if err := oprot.WriteI32(int32(p.Ipv4)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.ipv4 (1) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 1:ipv4: ", p), err) + } + return err +} + +func (p *Endpoint) writeField2(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("port", thrift.I16, 2); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:port: ", p), err) + } + if err := oprot.WriteI16(int16(p.Port)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.port (2) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 2:port: ", p), err) + } + return err +} + +func (p *Endpoint) writeField3(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("service_name", thrift.STRING, 3); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 3:service_name: ", p), err) + } + if err := oprot.WriteString(string(p.ServiceName)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.service_name (3) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 3:service_name: ", p), err) + } + return err +} + +func (p *Endpoint) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("Endpoint(%+v)", *p) +} + +// An annotation is similar to a log statement. It includes a host field which +// allows these events to be attributed properly, and also aggregatable. +// +// Attributes: +// - Timestamp: Microseconds from epoch. +// +// This value should use the most precise value possible. For example, +// gettimeofday or syncing nanoTime against a tick of currentTimeMillis. +// - Value +// - Host: Always the host that recorded the event. By specifying the host you allow +// rollup of all events (such as client requests to a service) by IP address. +type Annotation struct { + Timestamp int64 `thrift:"timestamp,1" json:"timestamp"` + Value string `thrift:"value,2" json:"value"` + Host *Endpoint `thrift:"host,3" json:"host,omitempty"` +} + +func NewAnnotation() *Annotation { + return &Annotation{} +} + +func (p *Annotation) GetTimestamp() int64 { + return p.Timestamp +} + +func (p *Annotation) GetValue() string { + return p.Value +} + +var Annotation_Host_DEFAULT *Endpoint + +func (p *Annotation) GetHost() *Endpoint { + if !p.IsSetHost() { + return Annotation_Host_DEFAULT + } + return p.Host +} +func (p *Annotation) IsSetHost() bool { + return p.Host != nil +} + +func (p *Annotation) Read(iprot thrift.TProtocol) error { + if _, err := iprot.ReadStructBegin(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) + } + + for { + _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() + if err != nil { + return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) + } + if fieldTypeId == thrift.STOP { + break + } + switch fieldId { + case 1: + if err := p.readField1(iprot); err != nil { + return err + } + case 2: + if err := p.readField2(iprot); err != nil { + return err + } + case 3: + if err := p.readField3(iprot); err != nil { + return err + } + default: + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + if err := iprot.ReadFieldEnd(); err != nil { + return err + } + } + if err := iprot.ReadStructEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) + } + return nil +} + +func (p *Annotation) readField1(iprot thrift.TProtocol) error { + if v, err := iprot.ReadI64(); err != nil { + return thrift.PrependError("error reading field 1: ", err) + } else { + p.Timestamp = v + } + return nil +} + +func (p *Annotation) readField2(iprot thrift.TProtocol) error { + if v, err := iprot.ReadString(); err != nil { + return thrift.PrependError("error reading field 2: ", err) + } else { + p.Value = v + } + return nil +} + +func (p *Annotation) readField3(iprot thrift.TProtocol) error { + p.Host = &Endpoint{} + if err := p.Host.Read(iprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", p.Host), err) + } + return nil +} + +func (p *Annotation) Write(oprot thrift.TProtocol) error { + if err := oprot.WriteStructBegin("Annotation"); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) + } + if err := p.writeField1(oprot); err != nil { + return err + } + if err := p.writeField2(oprot); err != nil { + return err + } + if err := p.writeField3(oprot); err != nil { + return err + } + if err := oprot.WriteFieldStop(); err != nil { + return thrift.PrependError("write field stop error: ", err) + } + if err := oprot.WriteStructEnd(); err != nil { + return thrift.PrependError("write struct stop error: ", err) + } + return nil +} + +func (p *Annotation) writeField1(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("timestamp", thrift.I64, 1); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:timestamp: ", p), err) + } + if err := oprot.WriteI64(int64(p.Timestamp)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.timestamp (1) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 1:timestamp: ", p), err) + } + return err +} + +func (p *Annotation) writeField2(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("value", thrift.STRING, 2); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:value: ", p), err) + } + if err := oprot.WriteString(string(p.Value)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.value (2) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 2:value: ", p), err) + } + return err +} + +func (p *Annotation) writeField3(oprot thrift.TProtocol) (err error) { + if p.IsSetHost() { + if err := oprot.WriteFieldBegin("host", thrift.STRUCT, 3); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 3:host: ", p), err) + } + if err := p.Host.Write(oprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", p.Host), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 3:host: ", p), err) + } + } + return err +} + +func (p *Annotation) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("Annotation(%+v)", *p) +} + +// Binary annotations are tags applied to a Span to give it context. For +// example, a binary annotation of "http.uri" could the path to a resource in a +// RPC call. +// +// Binary annotations of type STRING are always queryable, though more a +// historical implementation detail than a structural concern. +// +// Binary annotations can repeat, and vary on the host. Similar to Annotation, +// the host indicates who logged the event. This allows you to tell the +// difference between the client and server side of the same key. For example, +// the key "http.uri" might be different on the client and server side due to +// rewriting, like "/api/v1/myresource" vs "/myresource. Via the host field, +// you can see the different points of view, which often help in debugging. +// +// Attributes: +// - Key +// - Value +// - AnnotationType +// - Host: The host that recorded tag, which allows you to differentiate between +// multiple tags with the same key. There are two exceptions to this. +// +// When the key is CLIENT_ADDR or SERVER_ADDR, host indicates the source or +// destination of an RPC. This exception allows zipkin to display network +// context of uninstrumented services, or clients such as web browsers. +type BinaryAnnotation struct { + Key string `thrift:"key,1" json:"key"` + Value []byte `thrift:"value,2" json:"value"` + AnnotationType AnnotationType `thrift:"annotation_type,3" json:"annotation_type"` + Host *Endpoint `thrift:"host,4" json:"host,omitempty"` +} + +func NewBinaryAnnotation() *BinaryAnnotation { + return &BinaryAnnotation{} +} + +func (p *BinaryAnnotation) GetKey() string { + return p.Key +} + +func (p *BinaryAnnotation) GetValue() []byte { + return p.Value +} + +func (p *BinaryAnnotation) GetAnnotationType() AnnotationType { + return p.AnnotationType +} + +var BinaryAnnotation_Host_DEFAULT *Endpoint + +func (p *BinaryAnnotation) GetHost() *Endpoint { + if !p.IsSetHost() { + return BinaryAnnotation_Host_DEFAULT + } + return p.Host +} +func (p *BinaryAnnotation) IsSetHost() bool { + return p.Host != nil +} + +func (p *BinaryAnnotation) Read(iprot thrift.TProtocol) error { + if _, err := iprot.ReadStructBegin(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) + } + + for { + _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() + if err != nil { + return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) + } + if fieldTypeId == thrift.STOP { + break + } + switch fieldId { + case 1: + if err := p.readField1(iprot); err != nil { + return err + } + case 2: + if err := p.readField2(iprot); err != nil { + return err + } + case 3: + if err := p.readField3(iprot); err != nil { + return err + } + case 4: + if err := p.readField4(iprot); err != nil { + return err + } + default: + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + if err := iprot.ReadFieldEnd(); err != nil { + return err + } + } + if err := iprot.ReadStructEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) + } + return nil +} + +func (p *BinaryAnnotation) readField1(iprot thrift.TProtocol) error { + if v, err := iprot.ReadString(); err != nil { + return thrift.PrependError("error reading field 1: ", err) + } else { + p.Key = v + } + return nil +} + +func (p *BinaryAnnotation) readField2(iprot thrift.TProtocol) error { + if v, err := iprot.ReadBinary(); err != nil { + return thrift.PrependError("error reading field 2: ", err) + } else { + p.Value = v + } + return nil +} + +func (p *BinaryAnnotation) readField3(iprot thrift.TProtocol) error { + if v, err := iprot.ReadI32(); err != nil { + return thrift.PrependError("error reading field 3: ", err) + } else { + temp := AnnotationType(v) + p.AnnotationType = temp + } + return nil +} + +func (p *BinaryAnnotation) readField4(iprot thrift.TProtocol) error { + p.Host = &Endpoint{} + if err := p.Host.Read(iprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", p.Host), err) + } + return nil +} + +func (p *BinaryAnnotation) Write(oprot thrift.TProtocol) error { + if err := oprot.WriteStructBegin("BinaryAnnotation"); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) + } + if err := p.writeField1(oprot); err != nil { + return err + } + if err := p.writeField2(oprot); err != nil { + return err + } + if err := p.writeField3(oprot); err != nil { + return err + } + if err := p.writeField4(oprot); err != nil { + return err + } + if err := oprot.WriteFieldStop(); err != nil { + return thrift.PrependError("write field stop error: ", err) + } + if err := oprot.WriteStructEnd(); err != nil { + return thrift.PrependError("write struct stop error: ", err) + } + return nil +} + +func (p *BinaryAnnotation) writeField1(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("key", thrift.STRING, 1); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:key: ", p), err) + } + if err := oprot.WriteString(string(p.Key)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.key (1) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 1:key: ", p), err) + } + return err +} + +func (p *BinaryAnnotation) writeField2(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("value", thrift.STRING, 2); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:value: ", p), err) + } + if err := oprot.WriteBinary(p.Value); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.value (2) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 2:value: ", p), err) + } + return err +} + +func (p *BinaryAnnotation) writeField3(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("annotation_type", thrift.I32, 3); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 3:annotation_type: ", p), err) + } + if err := oprot.WriteI32(int32(p.AnnotationType)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.annotation_type (3) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 3:annotation_type: ", p), err) + } + return err +} + +func (p *BinaryAnnotation) writeField4(oprot thrift.TProtocol) (err error) { + if p.IsSetHost() { + if err := oprot.WriteFieldBegin("host", thrift.STRUCT, 4); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 4:host: ", p), err) + } + if err := p.Host.Write(oprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", p.Host), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 4:host: ", p), err) + } + } + return err +} + +func (p *BinaryAnnotation) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("BinaryAnnotation(%+v)", *p) +} + +// A trace is a series of spans (often RPC calls) which form a latency tree. +// +// The root span is where trace_id = id and parent_id = Nil. The root span is +// usually the longest interval in the trace, starting with a SERVER_RECV +// annotation and ending with a SERVER_SEND. +// +// Attributes: +// - TraceID +// - Name: Span name in lowercase, rpc method for example +// +// Conventionally, when the span name isn't known, name = "unknown". +// - ID +// - ParentID +// - Annotations +// - BinaryAnnotations +// - Debug +// - Timestamp: Microseconds from epoch of the creation of this span. +// +// This value should be set directly by instrumentation, using the most +// precise value possible. For example, gettimeofday or syncing nanoTime +// against a tick of currentTimeMillis. +// +// For compatibilty with instrumentation that precede this field, collectors +// or span stores can derive this via Annotation.timestamp. +// For example, SERVER_RECV.timestamp or CLIENT_SEND.timestamp. +// +// This field is optional for compatibility with old data: first-party span +// stores are expected to support this at time of introduction. +// - Duration: Measurement of duration in microseconds, used to support queries. +// +// This value should be set directly, where possible. Doing so encourages +// precise measurement decoupled from problems of clocks, such as skew or NTP +// updates causing time to move backwards. +// +// For compatibilty with instrumentation that precede this field, collectors +// or span stores can derive this by subtracting Annotation.timestamp. +// For example, SERVER_SEND.timestamp - SERVER_RECV.timestamp. +// +// If this field is persisted as unset, zipkin will continue to work, except +// duration query support will be implementation-specific. Similarly, setting +// this field non-atomically is implementation-specific. +// +// This field is i64 vs i32 to support spans longer than 35 minutes. +type Span struct { + TraceID int64 `thrift:"trace_id,1" json:"trace_id"` + // unused field # 2 + Name string `thrift:"name,3" json:"name"` + ID int64 `thrift:"id,4" json:"id"` + ParentID *int64 `thrift:"parent_id,5" json:"parent_id,omitempty"` + Annotations []*Annotation `thrift:"annotations,6" json:"annotations"` + // unused field # 7 + BinaryAnnotations []*BinaryAnnotation `thrift:"binary_annotations,8" json:"binary_annotations"` + Debug bool `thrift:"debug,9" json:"debug,omitempty"` + Timestamp *int64 `thrift:"timestamp,10" json:"timestamp,omitempty"` + Duration *int64 `thrift:"duration,11" json:"duration,omitempty"` +} + +func NewSpan() *Span { + return &Span{} +} + +func (p *Span) GetTraceID() int64 { + return p.TraceID +} + +func (p *Span) GetName() string { + return p.Name +} + +func (p *Span) GetID() int64 { + return p.ID +} + +var Span_ParentID_DEFAULT int64 + +func (p *Span) GetParentID() int64 { + if !p.IsSetParentID() { + return Span_ParentID_DEFAULT + } + return *p.ParentID +} + +func (p *Span) GetAnnotations() []*Annotation { + return p.Annotations +} + +func (p *Span) GetBinaryAnnotations() []*BinaryAnnotation { + return p.BinaryAnnotations +} + +var Span_Debug_DEFAULT bool = false + +func (p *Span) GetDebug() bool { + return p.Debug +} + +var Span_Timestamp_DEFAULT int64 + +func (p *Span) GetTimestamp() int64 { + if !p.IsSetTimestamp() { + return Span_Timestamp_DEFAULT + } + return *p.Timestamp +} + +var Span_Duration_DEFAULT int64 + +func (p *Span) GetDuration() int64 { + if !p.IsSetDuration() { + return Span_Duration_DEFAULT + } + return *p.Duration +} +func (p *Span) IsSetParentID() bool { + return p.ParentID != nil +} + +func (p *Span) IsSetDebug() bool { + return p.Debug != Span_Debug_DEFAULT +} + +func (p *Span) IsSetTimestamp() bool { + return p.Timestamp != nil +} + +func (p *Span) IsSetDuration() bool { + return p.Duration != nil +} + +func (p *Span) Read(iprot thrift.TProtocol) error { + if _, err := iprot.ReadStructBegin(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) + } + + for { + _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() + if err != nil { + return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) + } + if fieldTypeId == thrift.STOP { + break + } + switch fieldId { + case 1: + if err := p.readField1(iprot); err != nil { + return err + } + case 3: + if err := p.readField3(iprot); err != nil { + return err + } + case 4: + if err := p.readField4(iprot); err != nil { + return err + } + case 5: + if err := p.readField5(iprot); err != nil { + return err + } + case 6: + if err := p.readField6(iprot); err != nil { + return err + } + case 8: + if err := p.readField8(iprot); err != nil { + return err + } + case 9: + if err := p.readField9(iprot); err != nil { + return err + } + case 10: + if err := p.readField10(iprot); err != nil { + return err + } + case 11: + if err := p.readField11(iprot); err != nil { + return err + } + default: + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + if err := iprot.ReadFieldEnd(); err != nil { + return err + } + } + if err := iprot.ReadStructEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) + } + return nil +} + +func (p *Span) readField1(iprot thrift.TProtocol) error { + if v, err := iprot.ReadI64(); err != nil { + return thrift.PrependError("error reading field 1: ", err) + } else { + p.TraceID = v + } + return nil +} + +func (p *Span) readField3(iprot thrift.TProtocol) error { + if v, err := iprot.ReadString(); err != nil { + return thrift.PrependError("error reading field 3: ", err) + } else { + p.Name = v + } + return nil +} + +func (p *Span) readField4(iprot thrift.TProtocol) error { + if v, err := iprot.ReadI64(); err != nil { + return thrift.PrependError("error reading field 4: ", err) + } else { + p.ID = v + } + return nil +} + +func (p *Span) readField5(iprot thrift.TProtocol) error { + if v, err := iprot.ReadI64(); err != nil { + return thrift.PrependError("error reading field 5: ", err) + } else { + p.ParentID = &v + } + return nil +} + +func (p *Span) readField6(iprot thrift.TProtocol) error { + _, size, err := iprot.ReadListBegin() + if err != nil { + return thrift.PrependError("error reading list begin: ", err) + } + tSlice := make([]*Annotation, 0, size) + p.Annotations = tSlice + for i := 0; i < size; i++ { + _elem0 := &Annotation{} + if err := _elem0.Read(iprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", _elem0), err) + } + p.Annotations = append(p.Annotations, _elem0) + } + if err := iprot.ReadListEnd(); err != nil { + return thrift.PrependError("error reading list end: ", err) + } + return nil +} + +func (p *Span) readField8(iprot thrift.TProtocol) error { + _, size, err := iprot.ReadListBegin() + if err != nil { + return thrift.PrependError("error reading list begin: ", err) + } + tSlice := make([]*BinaryAnnotation, 0, size) + p.BinaryAnnotations = tSlice + for i := 0; i < size; i++ { + _elem1 := &BinaryAnnotation{} + if err := _elem1.Read(iprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", _elem1), err) + } + p.BinaryAnnotations = append(p.BinaryAnnotations, _elem1) + } + if err := iprot.ReadListEnd(); err != nil { + return thrift.PrependError("error reading list end: ", err) + } + return nil +} + +func (p *Span) readField9(iprot thrift.TProtocol) error { + if v, err := iprot.ReadBool(); err != nil { + return thrift.PrependError("error reading field 9: ", err) + } else { + p.Debug = v + } + return nil +} + +func (p *Span) readField10(iprot thrift.TProtocol) error { + if v, err := iprot.ReadI64(); err != nil { + return thrift.PrependError("error reading field 10: ", err) + } else { + p.Timestamp = &v + } + return nil +} + +func (p *Span) readField11(iprot thrift.TProtocol) error { + if v, err := iprot.ReadI64(); err != nil { + return thrift.PrependError("error reading field 11: ", err) + } else { + p.Duration = &v + } + return nil +} + +func (p *Span) Write(oprot thrift.TProtocol) error { + if err := oprot.WriteStructBegin("Span"); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) + } + if err := p.writeField1(oprot); err != nil { + return err + } + if err := p.writeField3(oprot); err != nil { + return err + } + if err := p.writeField4(oprot); err != nil { + return err + } + if err := p.writeField5(oprot); err != nil { + return err + } + if err := p.writeField6(oprot); err != nil { + return err + } + if err := p.writeField8(oprot); err != nil { + return err + } + if err := p.writeField9(oprot); err != nil { + return err + } + if err := p.writeField10(oprot); err != nil { + return err + } + if err := p.writeField11(oprot); err != nil { + return err + } + if err := oprot.WriteFieldStop(); err != nil { + return thrift.PrependError("write field stop error: ", err) + } + if err := oprot.WriteStructEnd(); err != nil { + return thrift.PrependError("write struct stop error: ", err) + } + return nil +} + +func (p *Span) writeField1(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("trace_id", thrift.I64, 1); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:trace_id: ", p), err) + } + if err := oprot.WriteI64(int64(p.TraceID)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.trace_id (1) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 1:trace_id: ", p), err) + } + return err +} + +func (p *Span) writeField3(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("name", thrift.STRING, 3); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 3:name: ", p), err) + } + if err := oprot.WriteString(string(p.Name)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.name (3) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 3:name: ", p), err) + } + return err +} + +func (p *Span) writeField4(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("id", thrift.I64, 4); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 4:id: ", p), err) + } + if err := oprot.WriteI64(int64(p.ID)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.id (4) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 4:id: ", p), err) + } + return err +} + +func (p *Span) writeField5(oprot thrift.TProtocol) (err error) { + if p.IsSetParentID() { + if err := oprot.WriteFieldBegin("parent_id", thrift.I64, 5); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 5:parent_id: ", p), err) + } + if err := oprot.WriteI64(int64(*p.ParentID)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.parent_id (5) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 5:parent_id: ", p), err) + } + } + return err +} + +func (p *Span) writeField6(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("annotations", thrift.LIST, 6); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 6:annotations: ", p), err) + } + if err := oprot.WriteListBegin(thrift.STRUCT, len(p.Annotations)); err != nil { + return thrift.PrependError("error writing list begin: ", err) + } + for _, v := range p.Annotations { + if err := v.Write(oprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", v), err) + } + } + if err := oprot.WriteListEnd(); err != nil { + return thrift.PrependError("error writing list end: ", err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 6:annotations: ", p), err) + } + return err +} + +func (p *Span) writeField8(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("binary_annotations", thrift.LIST, 8); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 8:binary_annotations: ", p), err) + } + if err := oprot.WriteListBegin(thrift.STRUCT, len(p.BinaryAnnotations)); err != nil { + return thrift.PrependError("error writing list begin: ", err) + } + for _, v := range p.BinaryAnnotations { + if err := v.Write(oprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", v), err) + } + } + if err := oprot.WriteListEnd(); err != nil { + return thrift.PrependError("error writing list end: ", err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 8:binary_annotations: ", p), err) + } + return err +} + +func (p *Span) writeField9(oprot thrift.TProtocol) (err error) { + if p.IsSetDebug() { + if err := oprot.WriteFieldBegin("debug", thrift.BOOL, 9); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 9:debug: ", p), err) + } + if err := oprot.WriteBool(bool(p.Debug)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.debug (9) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 9:debug: ", p), err) + } + } + return err +} + +func (p *Span) writeField10(oprot thrift.TProtocol) (err error) { + if p.IsSetTimestamp() { + if err := oprot.WriteFieldBegin("timestamp", thrift.I64, 10); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 10:timestamp: ", p), err) + } + if err := oprot.WriteI64(int64(*p.Timestamp)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.timestamp (10) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 10:timestamp: ", p), err) + } + } + return err +} + +func (p *Span) writeField11(oprot thrift.TProtocol) (err error) { + if p.IsSetDuration() { + if err := oprot.WriteFieldBegin("duration", thrift.I64, 11); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 11:duration: ", p), err) + } + if err := oprot.WriteI64(int64(*p.Duration)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.duration (11) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 11:duration: ", p), err) + } + } + return err +} + +func (p *Span) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("Span(%+v)", *p) +} + +// Attributes: +// - Ok +type Response struct { + Ok bool `thrift:"ok,1,required" json:"ok"` +} + +func NewResponse() *Response { + return &Response{} +} + +func (p *Response) GetOk() bool { + return p.Ok +} +func (p *Response) Read(iprot thrift.TProtocol) error { + if _, err := iprot.ReadStructBegin(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) + } + + var issetOk bool = false + + for { + _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() + if err != nil { + return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) + } + if fieldTypeId == thrift.STOP { + break + } + switch fieldId { + case 1: + if err := p.readField1(iprot); err != nil { + return err + } + issetOk = true + default: + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + if err := iprot.ReadFieldEnd(); err != nil { + return err + } + } + if err := iprot.ReadStructEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) + } + if !issetOk { + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field Ok is not set")) + } + return nil +} + +func (p *Response) readField1(iprot thrift.TProtocol) error { + if v, err := iprot.ReadBool(); err != nil { + return thrift.PrependError("error reading field 1: ", err) + } else { + p.Ok = v + } + return nil +} + +func (p *Response) Write(oprot thrift.TProtocol) error { + if err := oprot.WriteStructBegin("Response"); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) + } + if err := p.writeField1(oprot); err != nil { + return err + } + if err := oprot.WriteFieldStop(); err != nil { + return thrift.PrependError("write field stop error: ", err) + } + if err := oprot.WriteStructEnd(); err != nil { + return thrift.PrependError("write struct stop error: ", err) + } + return nil +} + +func (p *Response) writeField1(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("ok", thrift.BOOL, 1); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:ok: ", p), err) + } + if err := oprot.WriteBool(bool(p.Ok)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.ok (1) field write error: ", p), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 1:ok: ", p), err) + } + return err +} + +func (p *Response) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("Response(%+v)", *p) +} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift-gen/zipkincore/zipkincollector.go b/vendor/github.com/uber/jaeger-client-go/thrift-gen/zipkincore/zipkincollector.go new file mode 100644 index 0000000000..417e883d0e --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/thrift-gen/zipkincore/zipkincollector.go @@ -0,0 +1,446 @@ +// Autogenerated by Thrift Compiler (0.9.3) +// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + +package zipkincore + +import ( + "bytes" + "fmt" + "github.com/uber/jaeger-client-go/thrift" +) + +// (needed to ensure safety because of naive import list construction.) +var _ = thrift.ZERO +var _ = fmt.Printf +var _ = bytes.Equal + +type ZipkinCollector interface { + // Parameters: + // - Spans + SubmitZipkinBatch(spans []*Span) (r []*Response, err error) +} + +type ZipkinCollectorClient struct { + Transport thrift.TTransport + ProtocolFactory thrift.TProtocolFactory + InputProtocol thrift.TProtocol + OutputProtocol thrift.TProtocol + SeqId int32 +} + +func NewZipkinCollectorClientFactory(t thrift.TTransport, f thrift.TProtocolFactory) *ZipkinCollectorClient { + return &ZipkinCollectorClient{Transport: t, + ProtocolFactory: f, + InputProtocol: f.GetProtocol(t), + OutputProtocol: f.GetProtocol(t), + SeqId: 0, + } +} + +func NewZipkinCollectorClientProtocol(t thrift.TTransport, iprot thrift.TProtocol, oprot thrift.TProtocol) *ZipkinCollectorClient { + return &ZipkinCollectorClient{Transport: t, + ProtocolFactory: nil, + InputProtocol: iprot, + OutputProtocol: oprot, + SeqId: 0, + } +} + +// Parameters: +// - Spans +func (p *ZipkinCollectorClient) SubmitZipkinBatch(spans []*Span) (r []*Response, err error) { + if err = p.sendSubmitZipkinBatch(spans); err != nil { + return + } + return p.recvSubmitZipkinBatch() +} + +func (p *ZipkinCollectorClient) sendSubmitZipkinBatch(spans []*Span) (err error) { + oprot := p.OutputProtocol + if oprot == nil { + oprot = p.ProtocolFactory.GetProtocol(p.Transport) + p.OutputProtocol = oprot + } + p.SeqId++ + if err = oprot.WriteMessageBegin("submitZipkinBatch", thrift.CALL, p.SeqId); err != nil { + return + } + args := ZipkinCollectorSubmitZipkinBatchArgs{ + Spans: spans, + } + if err = args.Write(oprot); err != nil { + return + } + if err = oprot.WriteMessageEnd(); err != nil { + return + } + return oprot.Flush() +} + +func (p *ZipkinCollectorClient) recvSubmitZipkinBatch() (value []*Response, err error) { + iprot := p.InputProtocol + if iprot == nil { + iprot = p.ProtocolFactory.GetProtocol(p.Transport) + p.InputProtocol = iprot + } + method, mTypeId, seqId, err := iprot.ReadMessageBegin() + if err != nil { + return + } + if method != "submitZipkinBatch" { + err = thrift.NewTApplicationException(thrift.WRONG_METHOD_NAME, "submitZipkinBatch failed: wrong method name") + return + } + if p.SeqId != seqId { + err = thrift.NewTApplicationException(thrift.BAD_SEQUENCE_ID, "submitZipkinBatch failed: out of sequence response") + return + } + if mTypeId == thrift.EXCEPTION { + error2 := thrift.NewTApplicationException(thrift.UNKNOWN_APPLICATION_EXCEPTION, "Unknown Exception") + var error3 error + error3, err = error2.Read(iprot) + if err != nil { + return + } + if err = iprot.ReadMessageEnd(); err != nil { + return + } + err = error3 + return + } + if mTypeId != thrift.REPLY { + err = thrift.NewTApplicationException(thrift.INVALID_MESSAGE_TYPE_EXCEPTION, "submitZipkinBatch failed: invalid message type") + return + } + result := ZipkinCollectorSubmitZipkinBatchResult{} + if err = result.Read(iprot); err != nil { + return + } + if err = iprot.ReadMessageEnd(); err != nil { + return + } + value = result.GetSuccess() + return +} + +type ZipkinCollectorProcessor struct { + processorMap map[string]thrift.TProcessorFunction + handler ZipkinCollector +} + +func (p *ZipkinCollectorProcessor) AddToProcessorMap(key string, processor thrift.TProcessorFunction) { + p.processorMap[key] = processor +} + +func (p *ZipkinCollectorProcessor) GetProcessorFunction(key string) (processor thrift.TProcessorFunction, ok bool) { + processor, ok = p.processorMap[key] + return processor, ok +} + +func (p *ZipkinCollectorProcessor) ProcessorMap() map[string]thrift.TProcessorFunction { + return p.processorMap +} + +func NewZipkinCollectorProcessor(handler ZipkinCollector) *ZipkinCollectorProcessor { + + self4 := &ZipkinCollectorProcessor{handler: handler, processorMap: make(map[string]thrift.TProcessorFunction)} + self4.processorMap["submitZipkinBatch"] = &zipkinCollectorProcessorSubmitZipkinBatch{handler: handler} + return self4 +} + +func (p *ZipkinCollectorProcessor) Process(iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { + name, _, seqId, err := iprot.ReadMessageBegin() + if err != nil { + return false, err + } + if processor, ok := p.GetProcessorFunction(name); ok { + return processor.Process(seqId, iprot, oprot) + } + iprot.Skip(thrift.STRUCT) + iprot.ReadMessageEnd() + x5 := thrift.NewTApplicationException(thrift.UNKNOWN_METHOD, "Unknown function "+name) + oprot.WriteMessageBegin(name, thrift.EXCEPTION, seqId) + x5.Write(oprot) + oprot.WriteMessageEnd() + oprot.Flush() + return false, x5 + +} + +type zipkinCollectorProcessorSubmitZipkinBatch struct { + handler ZipkinCollector +} + +func (p *zipkinCollectorProcessorSubmitZipkinBatch) Process(seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { + args := ZipkinCollectorSubmitZipkinBatchArgs{} + if err = args.Read(iprot); err != nil { + iprot.ReadMessageEnd() + x := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err.Error()) + oprot.WriteMessageBegin("submitZipkinBatch", thrift.EXCEPTION, seqId) + x.Write(oprot) + oprot.WriteMessageEnd() + oprot.Flush() + return false, err + } + + iprot.ReadMessageEnd() + result := ZipkinCollectorSubmitZipkinBatchResult{} + var retval []*Response + var err2 error + if retval, err2 = p.handler.SubmitZipkinBatch(args.Spans); err2 != nil { + x := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, "Internal error processing submitZipkinBatch: "+err2.Error()) + oprot.WriteMessageBegin("submitZipkinBatch", thrift.EXCEPTION, seqId) + x.Write(oprot) + oprot.WriteMessageEnd() + oprot.Flush() + return true, err2 + } else { + result.Success = retval + } + if err2 = oprot.WriteMessageBegin("submitZipkinBatch", thrift.REPLY, seqId); err2 != nil { + err = err2 + } + if err2 = result.Write(oprot); err == nil && err2 != nil { + err = err2 + } + if err2 = oprot.WriteMessageEnd(); err == nil && err2 != nil { + err = err2 + } + if err2 = oprot.Flush(); err == nil && err2 != nil { + err = err2 + } + if err != nil { + return + } + return true, err +} + +// HELPER FUNCTIONS AND STRUCTURES + +// Attributes: +// - Spans +type ZipkinCollectorSubmitZipkinBatchArgs struct { + Spans []*Span `thrift:"spans,1" json:"spans"` +} + +func NewZipkinCollectorSubmitZipkinBatchArgs() *ZipkinCollectorSubmitZipkinBatchArgs { + return &ZipkinCollectorSubmitZipkinBatchArgs{} +} + +func (p *ZipkinCollectorSubmitZipkinBatchArgs) GetSpans() []*Span { + return p.Spans +} +func (p *ZipkinCollectorSubmitZipkinBatchArgs) Read(iprot thrift.TProtocol) error { + if _, err := iprot.ReadStructBegin(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) + } + + for { + _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() + if err != nil { + return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) + } + if fieldTypeId == thrift.STOP { + break + } + switch fieldId { + case 1: + if err := p.readField1(iprot); err != nil { + return err + } + default: + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + if err := iprot.ReadFieldEnd(); err != nil { + return err + } + } + if err := iprot.ReadStructEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) + } + return nil +} + +func (p *ZipkinCollectorSubmitZipkinBatchArgs) readField1(iprot thrift.TProtocol) error { + _, size, err := iprot.ReadListBegin() + if err != nil { + return thrift.PrependError("error reading list begin: ", err) + } + tSlice := make([]*Span, 0, size) + p.Spans = tSlice + for i := 0; i < size; i++ { + _elem6 := &Span{} + if err := _elem6.Read(iprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", _elem6), err) + } + p.Spans = append(p.Spans, _elem6) + } + if err := iprot.ReadListEnd(); err != nil { + return thrift.PrependError("error reading list end: ", err) + } + return nil +} + +func (p *ZipkinCollectorSubmitZipkinBatchArgs) Write(oprot thrift.TProtocol) error { + if err := oprot.WriteStructBegin("submitZipkinBatch_args"); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) + } + if err := p.writeField1(oprot); err != nil { + return err + } + if err := oprot.WriteFieldStop(); err != nil { + return thrift.PrependError("write field stop error: ", err) + } + if err := oprot.WriteStructEnd(); err != nil { + return thrift.PrependError("write struct stop error: ", err) + } + return nil +} + +func (p *ZipkinCollectorSubmitZipkinBatchArgs) writeField1(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("spans", thrift.LIST, 1); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:spans: ", p), err) + } + if err := oprot.WriteListBegin(thrift.STRUCT, len(p.Spans)); err != nil { + return thrift.PrependError("error writing list begin: ", err) + } + for _, v := range p.Spans { + if err := v.Write(oprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", v), err) + } + } + if err := oprot.WriteListEnd(); err != nil { + return thrift.PrependError("error writing list end: ", err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 1:spans: ", p), err) + } + return err +} + +func (p *ZipkinCollectorSubmitZipkinBatchArgs) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("ZipkinCollectorSubmitZipkinBatchArgs(%+v)", *p) +} + +// Attributes: +// - Success +type ZipkinCollectorSubmitZipkinBatchResult struct { + Success []*Response `thrift:"success,0" json:"success,omitempty"` +} + +func NewZipkinCollectorSubmitZipkinBatchResult() *ZipkinCollectorSubmitZipkinBatchResult { + return &ZipkinCollectorSubmitZipkinBatchResult{} +} + +var ZipkinCollectorSubmitZipkinBatchResult_Success_DEFAULT []*Response + +func (p *ZipkinCollectorSubmitZipkinBatchResult) GetSuccess() []*Response { + return p.Success +} +func (p *ZipkinCollectorSubmitZipkinBatchResult) IsSetSuccess() bool { + return p.Success != nil +} + +func (p *ZipkinCollectorSubmitZipkinBatchResult) Read(iprot thrift.TProtocol) error { + if _, err := iprot.ReadStructBegin(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) + } + + for { + _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() + if err != nil { + return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) + } + if fieldTypeId == thrift.STOP { + break + } + switch fieldId { + case 0: + if err := p.readField0(iprot); err != nil { + return err + } + default: + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + if err := iprot.ReadFieldEnd(); err != nil { + return err + } + } + if err := iprot.ReadStructEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) + } + return nil +} + +func (p *ZipkinCollectorSubmitZipkinBatchResult) readField0(iprot thrift.TProtocol) error { + _, size, err := iprot.ReadListBegin() + if err != nil { + return thrift.PrependError("error reading list begin: ", err) + } + tSlice := make([]*Response, 0, size) + p.Success = tSlice + for i := 0; i < size; i++ { + _elem7 := &Response{} + if err := _elem7.Read(iprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", _elem7), err) + } + p.Success = append(p.Success, _elem7) + } + if err := iprot.ReadListEnd(); err != nil { + return thrift.PrependError("error reading list end: ", err) + } + return nil +} + +func (p *ZipkinCollectorSubmitZipkinBatchResult) Write(oprot thrift.TProtocol) error { + if err := oprot.WriteStructBegin("submitZipkinBatch_result"); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) + } + if err := p.writeField0(oprot); err != nil { + return err + } + if err := oprot.WriteFieldStop(); err != nil { + return thrift.PrependError("write field stop error: ", err) + } + if err := oprot.WriteStructEnd(); err != nil { + return thrift.PrependError("write struct stop error: ", err) + } + return nil +} + +func (p *ZipkinCollectorSubmitZipkinBatchResult) writeField0(oprot thrift.TProtocol) (err error) { + if p.IsSetSuccess() { + if err := oprot.WriteFieldBegin("success", thrift.LIST, 0); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 0:success: ", p), err) + } + if err := oprot.WriteListBegin(thrift.STRUCT, len(p.Success)); err != nil { + return thrift.PrependError("error writing list begin: ", err) + } + for _, v := range p.Success { + if err := v.Write(oprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", v), err) + } + } + if err := oprot.WriteListEnd(); err != nil { + return thrift.PrependError("error writing list end: ", err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 0:success: ", p), err) + } + } + return err +} + +func (p *ZipkinCollectorSubmitZipkinBatchResult) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("ZipkinCollectorSubmitZipkinBatchResult(%+v)", *p) +} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/README.md b/vendor/github.com/uber/jaeger-client-go/thrift/README.md new file mode 100644 index 0000000000..1d8e642e02 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/thrift/README.md @@ -0,0 +1,7 @@ +# Apache Thrift + +This is a partial copy of Apache Thrift v0.10 (https://github.com/apache/thrift/commit/b2a4d4ae21c789b689dd162deb819665567f481c). + +It is vendored code to avoid compatibility issues introduced in Thrift v0.11. + +See https://github.com/jaegertracing/jaeger-client-go/pull/303. diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/application_exception.go b/vendor/github.com/uber/jaeger-client-go/thrift/application_exception.go new file mode 100644 index 0000000000..6655cc5a97 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/thrift/application_exception.go @@ -0,0 +1,142 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 thrift + +const ( + UNKNOWN_APPLICATION_EXCEPTION = 0 + UNKNOWN_METHOD = 1 + INVALID_MESSAGE_TYPE_EXCEPTION = 2 + WRONG_METHOD_NAME = 3 + BAD_SEQUENCE_ID = 4 + MISSING_RESULT = 5 + INTERNAL_ERROR = 6 + PROTOCOL_ERROR = 7 +) + +// Application level Thrift exception +type TApplicationException interface { + TException + TypeId() int32 + Read(iprot TProtocol) (TApplicationException, error) + Write(oprot TProtocol) error +} + +type tApplicationException struct { + message string + type_ int32 +} + +func (e tApplicationException) Error() string { + return e.message +} + +func NewTApplicationException(type_ int32, message string) TApplicationException { + return &tApplicationException{message, type_} +} + +func (p *tApplicationException) TypeId() int32 { + return p.type_ +} + +func (p *tApplicationException) Read(iprot TProtocol) (TApplicationException, error) { + _, err := iprot.ReadStructBegin() + if err != nil { + return nil, err + } + + message := "" + type_ := int32(UNKNOWN_APPLICATION_EXCEPTION) + + for { + _, ttype, id, err := iprot.ReadFieldBegin() + if err != nil { + return nil, err + } + if ttype == STOP { + break + } + switch id { + case 1: + if ttype == STRING { + if message, err = iprot.ReadString(); err != nil { + return nil, err + } + } else { + if err = SkipDefaultDepth(iprot, ttype); err != nil { + return nil, err + } + } + case 2: + if ttype == I32 { + if type_, err = iprot.ReadI32(); err != nil { + return nil, err + } + } else { + if err = SkipDefaultDepth(iprot, ttype); err != nil { + return nil, err + } + } + default: + if err = SkipDefaultDepth(iprot, ttype); err != nil { + return nil, err + } + } + if err = iprot.ReadFieldEnd(); err != nil { + return nil, err + } + } + return NewTApplicationException(type_, message), iprot.ReadStructEnd() +} + +func (p *tApplicationException) Write(oprot TProtocol) (err error) { + err = oprot.WriteStructBegin("TApplicationException") + if len(p.Error()) > 0 { + err = oprot.WriteFieldBegin("message", STRING, 1) + if err != nil { + return + } + err = oprot.WriteString(p.Error()) + if err != nil { + return + } + err = oprot.WriteFieldEnd() + if err != nil { + return + } + } + err = oprot.WriteFieldBegin("type", I32, 2) + if err != nil { + return + } + err = oprot.WriteI32(p.type_) + if err != nil { + return + } + err = oprot.WriteFieldEnd() + if err != nil { + return + } + err = oprot.WriteFieldStop() + if err != nil { + return + } + err = oprot.WriteStructEnd() + return +} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/binary_protocol.go b/vendor/github.com/uber/jaeger-client-go/thrift/binary_protocol.go new file mode 100644 index 0000000000..690d341111 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/thrift/binary_protocol.go @@ -0,0 +1,514 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 thrift + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + "io" + "math" +) + +type TBinaryProtocol struct { + trans TRichTransport + origTransport TTransport + reader io.Reader + writer io.Writer + strictRead bool + strictWrite bool + buffer [64]byte +} + +type TBinaryProtocolFactory struct { + strictRead bool + strictWrite bool +} + +func NewTBinaryProtocolTransport(t TTransport) *TBinaryProtocol { + return NewTBinaryProtocol(t, false, true) +} + +func NewTBinaryProtocol(t TTransport, strictRead, strictWrite bool) *TBinaryProtocol { + p := &TBinaryProtocol{origTransport: t, strictRead: strictRead, strictWrite: strictWrite} + if et, ok := t.(TRichTransport); ok { + p.trans = et + } else { + p.trans = NewTRichTransport(t) + } + p.reader = p.trans + p.writer = p.trans + return p +} + +func NewTBinaryProtocolFactoryDefault() *TBinaryProtocolFactory { + return NewTBinaryProtocolFactory(false, true) +} + +func NewTBinaryProtocolFactory(strictRead, strictWrite bool) *TBinaryProtocolFactory { + return &TBinaryProtocolFactory{strictRead: strictRead, strictWrite: strictWrite} +} + +func (p *TBinaryProtocolFactory) GetProtocol(t TTransport) TProtocol { + return NewTBinaryProtocol(t, p.strictRead, p.strictWrite) +} + +/** + * Writing Methods + */ + +func (p *TBinaryProtocol) WriteMessageBegin(name string, typeId TMessageType, seqId int32) error { + if p.strictWrite { + version := uint32(VERSION_1) | uint32(typeId) + e := p.WriteI32(int32(version)) + if e != nil { + return e + } + e = p.WriteString(name) + if e != nil { + return e + } + e = p.WriteI32(seqId) + return e + } else { + e := p.WriteString(name) + if e != nil { + return e + } + e = p.WriteByte(int8(typeId)) + if e != nil { + return e + } + e = p.WriteI32(seqId) + return e + } + return nil +} + +func (p *TBinaryProtocol) WriteMessageEnd() error { + return nil +} + +func (p *TBinaryProtocol) WriteStructBegin(name string) error { + return nil +} + +func (p *TBinaryProtocol) WriteStructEnd() error { + return nil +} + +func (p *TBinaryProtocol) WriteFieldBegin(name string, typeId TType, id int16) error { + e := p.WriteByte(int8(typeId)) + if e != nil { + return e + } + e = p.WriteI16(id) + return e +} + +func (p *TBinaryProtocol) WriteFieldEnd() error { + return nil +} + +func (p *TBinaryProtocol) WriteFieldStop() error { + e := p.WriteByte(STOP) + return e +} + +func (p *TBinaryProtocol) WriteMapBegin(keyType TType, valueType TType, size int) error { + e := p.WriteByte(int8(keyType)) + if e != nil { + return e + } + e = p.WriteByte(int8(valueType)) + if e != nil { + return e + } + e = p.WriteI32(int32(size)) + return e +} + +func (p *TBinaryProtocol) WriteMapEnd() error { + return nil +} + +func (p *TBinaryProtocol) WriteListBegin(elemType TType, size int) error { + e := p.WriteByte(int8(elemType)) + if e != nil { + return e + } + e = p.WriteI32(int32(size)) + return e +} + +func (p *TBinaryProtocol) WriteListEnd() error { + return nil +} + +func (p *TBinaryProtocol) WriteSetBegin(elemType TType, size int) error { + e := p.WriteByte(int8(elemType)) + if e != nil { + return e + } + e = p.WriteI32(int32(size)) + return e +} + +func (p *TBinaryProtocol) WriteSetEnd() error { + return nil +} + +func (p *TBinaryProtocol) WriteBool(value bool) error { + if value { + return p.WriteByte(1) + } + return p.WriteByte(0) +} + +func (p *TBinaryProtocol) WriteByte(value int8) error { + e := p.trans.WriteByte(byte(value)) + return NewTProtocolException(e) +} + +func (p *TBinaryProtocol) WriteI16(value int16) error { + v := p.buffer[0:2] + binary.BigEndian.PutUint16(v, uint16(value)) + _, e := p.writer.Write(v) + return NewTProtocolException(e) +} + +func (p *TBinaryProtocol) WriteI32(value int32) error { + v := p.buffer[0:4] + binary.BigEndian.PutUint32(v, uint32(value)) + _, e := p.writer.Write(v) + return NewTProtocolException(e) +} + +func (p *TBinaryProtocol) WriteI64(value int64) error { + v := p.buffer[0:8] + binary.BigEndian.PutUint64(v, uint64(value)) + _, err := p.writer.Write(v) + return NewTProtocolException(err) +} + +func (p *TBinaryProtocol) WriteDouble(value float64) error { + return p.WriteI64(int64(math.Float64bits(value))) +} + +func (p *TBinaryProtocol) WriteString(value string) error { + e := p.WriteI32(int32(len(value))) + if e != nil { + return e + } + _, err := p.trans.WriteString(value) + return NewTProtocolException(err) +} + +func (p *TBinaryProtocol) WriteBinary(value []byte) error { + e := p.WriteI32(int32(len(value))) + if e != nil { + return e + } + _, err := p.writer.Write(value) + return NewTProtocolException(err) +} + +/** + * Reading methods + */ + +func (p *TBinaryProtocol) ReadMessageBegin() (name string, typeId TMessageType, seqId int32, err error) { + size, e := p.ReadI32() + if e != nil { + return "", typeId, 0, NewTProtocolException(e) + } + if size < 0 { + typeId = TMessageType(size & 0x0ff) + version := int64(int64(size) & VERSION_MASK) + if version != VERSION_1 { + return name, typeId, seqId, NewTProtocolExceptionWithType(BAD_VERSION, fmt.Errorf("Bad version in ReadMessageBegin")) + } + name, e = p.ReadString() + if e != nil { + return name, typeId, seqId, NewTProtocolException(e) + } + seqId, e = p.ReadI32() + if e != nil { + return name, typeId, seqId, NewTProtocolException(e) + } + return name, typeId, seqId, nil + } + if p.strictRead { + return name, typeId, seqId, NewTProtocolExceptionWithType(BAD_VERSION, fmt.Errorf("Missing version in ReadMessageBegin")) + } + name, e2 := p.readStringBody(size) + if e2 != nil { + return name, typeId, seqId, e2 + } + b, e3 := p.ReadByte() + if e3 != nil { + return name, typeId, seqId, e3 + } + typeId = TMessageType(b) + seqId, e4 := p.ReadI32() + if e4 != nil { + return name, typeId, seqId, e4 + } + return name, typeId, seqId, nil +} + +func (p *TBinaryProtocol) ReadMessageEnd() error { + return nil +} + +func (p *TBinaryProtocol) ReadStructBegin() (name string, err error) { + return +} + +func (p *TBinaryProtocol) ReadStructEnd() error { + return nil +} + +func (p *TBinaryProtocol) ReadFieldBegin() (name string, typeId TType, seqId int16, err error) { + t, err := p.ReadByte() + typeId = TType(t) + if err != nil { + return name, typeId, seqId, err + } + if t != STOP { + seqId, err = p.ReadI16() + } + return name, typeId, seqId, err +} + +func (p *TBinaryProtocol) ReadFieldEnd() error { + return nil +} + +var invalidDataLength = NewTProtocolExceptionWithType(INVALID_DATA, errors.New("Invalid data length")) + +func (p *TBinaryProtocol) ReadMapBegin() (kType, vType TType, size int, err error) { + k, e := p.ReadByte() + if e != nil { + err = NewTProtocolException(e) + return + } + kType = TType(k) + v, e := p.ReadByte() + if e != nil { + err = NewTProtocolException(e) + return + } + vType = TType(v) + size32, e := p.ReadI32() + if e != nil { + err = NewTProtocolException(e) + return + } + if size32 < 0 { + err = invalidDataLength + return + } + size = int(size32) + return kType, vType, size, nil +} + +func (p *TBinaryProtocol) ReadMapEnd() error { + return nil +} + +func (p *TBinaryProtocol) ReadListBegin() (elemType TType, size int, err error) { + b, e := p.ReadByte() + if e != nil { + err = NewTProtocolException(e) + return + } + elemType = TType(b) + size32, e := p.ReadI32() + if e != nil { + err = NewTProtocolException(e) + return + } + if size32 < 0 { + err = invalidDataLength + return + } + size = int(size32) + + return +} + +func (p *TBinaryProtocol) ReadListEnd() error { + return nil +} + +func (p *TBinaryProtocol) ReadSetBegin() (elemType TType, size int, err error) { + b, e := p.ReadByte() + if e != nil { + err = NewTProtocolException(e) + return + } + elemType = TType(b) + size32, e := p.ReadI32() + if e != nil { + err = NewTProtocolException(e) + return + } + if size32 < 0 { + err = invalidDataLength + return + } + size = int(size32) + return elemType, size, nil +} + +func (p *TBinaryProtocol) ReadSetEnd() error { + return nil +} + +func (p *TBinaryProtocol) ReadBool() (bool, error) { + b, e := p.ReadByte() + v := true + if b != 1 { + v = false + } + return v, e +} + +func (p *TBinaryProtocol) ReadByte() (int8, error) { + v, err := p.trans.ReadByte() + return int8(v), err +} + +func (p *TBinaryProtocol) ReadI16() (value int16, err error) { + buf := p.buffer[0:2] + err = p.readAll(buf) + value = int16(binary.BigEndian.Uint16(buf)) + return value, err +} + +func (p *TBinaryProtocol) ReadI32() (value int32, err error) { + buf := p.buffer[0:4] + err = p.readAll(buf) + value = int32(binary.BigEndian.Uint32(buf)) + return value, err +} + +func (p *TBinaryProtocol) ReadI64() (value int64, err error) { + buf := p.buffer[0:8] + err = p.readAll(buf) + value = int64(binary.BigEndian.Uint64(buf)) + return value, err +} + +func (p *TBinaryProtocol) ReadDouble() (value float64, err error) { + buf := p.buffer[0:8] + err = p.readAll(buf) + value = math.Float64frombits(binary.BigEndian.Uint64(buf)) + return value, err +} + +func (p *TBinaryProtocol) ReadString() (value string, err error) { + size, e := p.ReadI32() + if e != nil { + return "", e + } + if size < 0 { + err = invalidDataLength + return + } + + return p.readStringBody(size) +} + +func (p *TBinaryProtocol) ReadBinary() ([]byte, error) { + size, e := p.ReadI32() + if e != nil { + return nil, e + } + if size < 0 { + return nil, invalidDataLength + } + if uint64(size) > p.trans.RemainingBytes() { + return nil, invalidDataLength + } + + isize := int(size) + buf := make([]byte, isize) + _, err := io.ReadFull(p.trans, buf) + return buf, NewTProtocolException(err) +} + +func (p *TBinaryProtocol) Flush() (err error) { + return NewTProtocolException(p.trans.Flush()) +} + +func (p *TBinaryProtocol) Skip(fieldType TType) (err error) { + return SkipDefaultDepth(p, fieldType) +} + +func (p *TBinaryProtocol) Transport() TTransport { + return p.origTransport +} + +func (p *TBinaryProtocol) readAll(buf []byte) error { + _, err := io.ReadFull(p.reader, buf) + return NewTProtocolException(err) +} + +const readLimit = 32768 + +func (p *TBinaryProtocol) readStringBody(size int32) (value string, err error) { + if size < 0 { + return "", nil + } + if uint64(size) > p.trans.RemainingBytes() { + return "", invalidDataLength + } + + var ( + buf bytes.Buffer + e error + b []byte + ) + + switch { + case int(size) <= len(p.buffer): + b = p.buffer[:size] // avoids allocation for small reads + case int(size) < readLimit: + b = make([]byte, size) + default: + b = make([]byte, readLimit) + } + + for size > 0 { + _, e = io.ReadFull(p.trans, b) + buf.Write(b) + if e != nil { + break + } + size -= readLimit + if size < readLimit && size > 0 { + b = b[:size] + } + } + return buf.String(), NewTProtocolException(e) +} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/compact_protocol.go b/vendor/github.com/uber/jaeger-client-go/thrift/compact_protocol.go new file mode 100644 index 0000000000..b9299f2fa1 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/thrift/compact_protocol.go @@ -0,0 +1,815 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 thrift + +import ( + "encoding/binary" + "fmt" + "io" + "math" +) + +const ( + COMPACT_PROTOCOL_ID = 0x082 + COMPACT_VERSION = 1 + COMPACT_VERSION_MASK = 0x1f + COMPACT_TYPE_MASK = 0x0E0 + COMPACT_TYPE_BITS = 0x07 + COMPACT_TYPE_SHIFT_AMOUNT = 5 +) + +type tCompactType byte + +const ( + COMPACT_BOOLEAN_TRUE = 0x01 + COMPACT_BOOLEAN_FALSE = 0x02 + COMPACT_BYTE = 0x03 + COMPACT_I16 = 0x04 + COMPACT_I32 = 0x05 + COMPACT_I64 = 0x06 + COMPACT_DOUBLE = 0x07 + COMPACT_BINARY = 0x08 + COMPACT_LIST = 0x09 + COMPACT_SET = 0x0A + COMPACT_MAP = 0x0B + COMPACT_STRUCT = 0x0C +) + +var ( + ttypeToCompactType map[TType]tCompactType +) + +func init() { + ttypeToCompactType = map[TType]tCompactType{ + STOP: STOP, + BOOL: COMPACT_BOOLEAN_TRUE, + BYTE: COMPACT_BYTE, + I16: COMPACT_I16, + I32: COMPACT_I32, + I64: COMPACT_I64, + DOUBLE: COMPACT_DOUBLE, + STRING: COMPACT_BINARY, + LIST: COMPACT_LIST, + SET: COMPACT_SET, + MAP: COMPACT_MAP, + STRUCT: COMPACT_STRUCT, + } +} + +type TCompactProtocolFactory struct{} + +func NewTCompactProtocolFactory() *TCompactProtocolFactory { + return &TCompactProtocolFactory{} +} + +func (p *TCompactProtocolFactory) GetProtocol(trans TTransport) TProtocol { + return NewTCompactProtocol(trans) +} + +type TCompactProtocol struct { + trans TRichTransport + origTransport TTransport + + // Used to keep track of the last field for the current and previous structs, + // so we can do the delta stuff. + lastField []int + lastFieldId int + + // If we encounter a boolean field begin, save the TField here so it can + // have the value incorporated. + booleanFieldName string + booleanFieldId int16 + booleanFieldPending bool + + // If we read a field header, and it's a boolean field, save the boolean + // value here so that readBool can use it. + boolValue bool + boolValueIsNotNull bool + buffer [64]byte +} + +// Create a TCompactProtocol given a TTransport +func NewTCompactProtocol(trans TTransport) *TCompactProtocol { + p := &TCompactProtocol{origTransport: trans, lastField: []int{}} + if et, ok := trans.(TRichTransport); ok { + p.trans = et + } else { + p.trans = NewTRichTransport(trans) + } + + return p + +} + +// +// Public Writing methods. +// + +// Write a message header to the wire. Compact Protocol messages contain the +// protocol version so we can migrate forwards in the future if need be. +func (p *TCompactProtocol) WriteMessageBegin(name string, typeId TMessageType, seqid int32) error { + err := p.writeByteDirect(COMPACT_PROTOCOL_ID) + if err != nil { + return NewTProtocolException(err) + } + err = p.writeByteDirect((COMPACT_VERSION & COMPACT_VERSION_MASK) | ((byte(typeId) << COMPACT_TYPE_SHIFT_AMOUNT) & COMPACT_TYPE_MASK)) + if err != nil { + return NewTProtocolException(err) + } + _, err = p.writeVarint32(seqid) + if err != nil { + return NewTProtocolException(err) + } + e := p.WriteString(name) + return e + +} + +func (p *TCompactProtocol) WriteMessageEnd() error { return nil } + +// Write a struct begin. This doesn't actually put anything on the wire. We +// use it as an opportunity to put special placeholder markers on the field +// stack so we can get the field id deltas correct. +func (p *TCompactProtocol) WriteStructBegin(name string) error { + p.lastField = append(p.lastField, p.lastFieldId) + p.lastFieldId = 0 + return nil +} + +// Write a struct end. This doesn't actually put anything on the wire. We use +// this as an opportunity to pop the last field from the current struct off +// of the field stack. +func (p *TCompactProtocol) WriteStructEnd() error { + p.lastFieldId = p.lastField[len(p.lastField)-1] + p.lastField = p.lastField[:len(p.lastField)-1] + return nil +} + +func (p *TCompactProtocol) WriteFieldBegin(name string, typeId TType, id int16) error { + if typeId == BOOL { + // we want to possibly include the value, so we'll wait. + p.booleanFieldName, p.booleanFieldId, p.booleanFieldPending = name, id, true + return nil + } + _, err := p.writeFieldBeginInternal(name, typeId, id, 0xFF) + return NewTProtocolException(err) +} + +// The workhorse of writeFieldBegin. It has the option of doing a +// 'type override' of the type header. This is used specifically in the +// boolean field case. +func (p *TCompactProtocol) writeFieldBeginInternal(name string, typeId TType, id int16, typeOverride byte) (int, error) { + // short lastField = lastField_.pop(); + + // if there's a type override, use that. + var typeToWrite byte + if typeOverride == 0xFF { + typeToWrite = byte(p.getCompactType(typeId)) + } else { + typeToWrite = typeOverride + } + // check if we can use delta encoding for the field id + fieldId := int(id) + written := 0 + if fieldId > p.lastFieldId && fieldId-p.lastFieldId <= 15 { + // write them together + err := p.writeByteDirect(byte((fieldId-p.lastFieldId)<<4) | typeToWrite) + if err != nil { + return 0, err + } + } else { + // write them separate + err := p.writeByteDirect(typeToWrite) + if err != nil { + return 0, err + } + err = p.WriteI16(id) + written = 1 + 2 + if err != nil { + return 0, err + } + } + + p.lastFieldId = fieldId + // p.lastField.Push(field.id); + return written, nil +} + +func (p *TCompactProtocol) WriteFieldEnd() error { return nil } + +func (p *TCompactProtocol) WriteFieldStop() error { + err := p.writeByteDirect(STOP) + return NewTProtocolException(err) +} + +func (p *TCompactProtocol) WriteMapBegin(keyType TType, valueType TType, size int) error { + if size == 0 { + err := p.writeByteDirect(0) + return NewTProtocolException(err) + } + _, err := p.writeVarint32(int32(size)) + if err != nil { + return NewTProtocolException(err) + } + err = p.writeByteDirect(byte(p.getCompactType(keyType))<<4 | byte(p.getCompactType(valueType))) + return NewTProtocolException(err) +} + +func (p *TCompactProtocol) WriteMapEnd() error { return nil } + +// Write a list header. +func (p *TCompactProtocol) WriteListBegin(elemType TType, size int) error { + _, err := p.writeCollectionBegin(elemType, size) + return NewTProtocolException(err) +} + +func (p *TCompactProtocol) WriteListEnd() error { return nil } + +// Write a set header. +func (p *TCompactProtocol) WriteSetBegin(elemType TType, size int) error { + _, err := p.writeCollectionBegin(elemType, size) + return NewTProtocolException(err) +} + +func (p *TCompactProtocol) WriteSetEnd() error { return nil } + +func (p *TCompactProtocol) WriteBool(value bool) error { + v := byte(COMPACT_BOOLEAN_FALSE) + if value { + v = byte(COMPACT_BOOLEAN_TRUE) + } + if p.booleanFieldPending { + // we haven't written the field header yet + _, err := p.writeFieldBeginInternal(p.booleanFieldName, BOOL, p.booleanFieldId, v) + p.booleanFieldPending = false + return NewTProtocolException(err) + } + // we're not part of a field, so just write the value. + err := p.writeByteDirect(v) + return NewTProtocolException(err) +} + +// Write a byte. Nothing to see here! +func (p *TCompactProtocol) WriteByte(value int8) error { + err := p.writeByteDirect(byte(value)) + return NewTProtocolException(err) +} + +// Write an I16 as a zigzag varint. +func (p *TCompactProtocol) WriteI16(value int16) error { + _, err := p.writeVarint32(p.int32ToZigzag(int32(value))) + return NewTProtocolException(err) +} + +// Write an i32 as a zigzag varint. +func (p *TCompactProtocol) WriteI32(value int32) error { + _, err := p.writeVarint32(p.int32ToZigzag(value)) + return NewTProtocolException(err) +} + +// Write an i64 as a zigzag varint. +func (p *TCompactProtocol) WriteI64(value int64) error { + _, err := p.writeVarint64(p.int64ToZigzag(value)) + return NewTProtocolException(err) +} + +// Write a double to the wire as 8 bytes. +func (p *TCompactProtocol) WriteDouble(value float64) error { + buf := p.buffer[0:8] + binary.LittleEndian.PutUint64(buf, math.Float64bits(value)) + _, err := p.trans.Write(buf) + return NewTProtocolException(err) +} + +// Write a string to the wire with a varint size preceding. +func (p *TCompactProtocol) WriteString(value string) error { + _, e := p.writeVarint32(int32(len(value))) + if e != nil { + return NewTProtocolException(e) + } + if len(value) > 0 { + } + _, e = p.trans.WriteString(value) + return e +} + +// Write a byte array, using a varint for the size. +func (p *TCompactProtocol) WriteBinary(bin []byte) error { + _, e := p.writeVarint32(int32(len(bin))) + if e != nil { + return NewTProtocolException(e) + } + if len(bin) > 0 { + _, e = p.trans.Write(bin) + return NewTProtocolException(e) + } + return nil +} + +// +// Reading methods. +// + +// Read a message header. +func (p *TCompactProtocol) ReadMessageBegin() (name string, typeId TMessageType, seqId int32, err error) { + + protocolId, err := p.readByteDirect() + if err != nil { + return + } + + if protocolId != COMPACT_PROTOCOL_ID { + e := fmt.Errorf("Expected protocol id %02x but got %02x", COMPACT_PROTOCOL_ID, protocolId) + return "", typeId, seqId, NewTProtocolExceptionWithType(BAD_VERSION, e) + } + + versionAndType, err := p.readByteDirect() + if err != nil { + return + } + + version := versionAndType & COMPACT_VERSION_MASK + typeId = TMessageType((versionAndType >> COMPACT_TYPE_SHIFT_AMOUNT) & COMPACT_TYPE_BITS) + if version != COMPACT_VERSION { + e := fmt.Errorf("Expected version %02x but got %02x", COMPACT_VERSION, version) + err = NewTProtocolExceptionWithType(BAD_VERSION, e) + return + } + seqId, e := p.readVarint32() + if e != nil { + err = NewTProtocolException(e) + return + } + name, err = p.ReadString() + return +} + +func (p *TCompactProtocol) ReadMessageEnd() error { return nil } + +// Read a struct begin. There's nothing on the wire for this, but it is our +// opportunity to push a new struct begin marker onto the field stack. +func (p *TCompactProtocol) ReadStructBegin() (name string, err error) { + p.lastField = append(p.lastField, p.lastFieldId) + p.lastFieldId = 0 + return +} + +// Doesn't actually consume any wire data, just removes the last field for +// this struct from the field stack. +func (p *TCompactProtocol) ReadStructEnd() error { + // consume the last field we read off the wire. + p.lastFieldId = p.lastField[len(p.lastField)-1] + p.lastField = p.lastField[:len(p.lastField)-1] + return nil +} + +// Read a field header off the wire. +func (p *TCompactProtocol) ReadFieldBegin() (name string, typeId TType, id int16, err error) { + t, err := p.readByteDirect() + if err != nil { + return + } + + // if it's a stop, then we can return immediately, as the struct is over. + if (t & 0x0f) == STOP { + return "", STOP, 0, nil + } + + // mask off the 4 MSB of the type header. it could contain a field id delta. + modifier := int16((t & 0xf0) >> 4) + if modifier == 0 { + // not a delta. look ahead for the zigzag varint field id. + id, err = p.ReadI16() + if err != nil { + return + } + } else { + // has a delta. add the delta to the last read field id. + id = int16(p.lastFieldId) + modifier + } + typeId, e := p.getTType(tCompactType(t & 0x0f)) + if e != nil { + err = NewTProtocolException(e) + return + } + + // if this happens to be a boolean field, the value is encoded in the type + if p.isBoolType(t) { + // save the boolean value in a special instance variable. + p.boolValue = (byte(t)&0x0f == COMPACT_BOOLEAN_TRUE) + p.boolValueIsNotNull = true + } + + // push the new field onto the field stack so we can keep the deltas going. + p.lastFieldId = int(id) + return +} + +func (p *TCompactProtocol) ReadFieldEnd() error { return nil } + +// Read a map header off the wire. If the size is zero, skip reading the key +// and value type. This means that 0-length maps will yield TMaps without the +// "correct" types. +func (p *TCompactProtocol) ReadMapBegin() (keyType TType, valueType TType, size int, err error) { + size32, e := p.readVarint32() + if e != nil { + err = NewTProtocolException(e) + return + } + if size32 < 0 { + err = invalidDataLength + return + } + size = int(size32) + + keyAndValueType := byte(STOP) + if size != 0 { + keyAndValueType, err = p.readByteDirect() + if err != nil { + return + } + } + keyType, _ = p.getTType(tCompactType(keyAndValueType >> 4)) + valueType, _ = p.getTType(tCompactType(keyAndValueType & 0xf)) + return +} + +func (p *TCompactProtocol) ReadMapEnd() error { return nil } + +// Read a list header off the wire. If the list size is 0-14, the size will +// be packed into the element type header. If it's a longer list, the 4 MSB +// of the element type header will be 0xF, and a varint will follow with the +// true size. +func (p *TCompactProtocol) ReadListBegin() (elemType TType, size int, err error) { + size_and_type, err := p.readByteDirect() + if err != nil { + return + } + size = int((size_and_type >> 4) & 0x0f) + if size == 15 { + size2, e := p.readVarint32() + if e != nil { + err = NewTProtocolException(e) + return + } + if size2 < 0 { + err = invalidDataLength + return + } + size = int(size2) + } + elemType, e := p.getTType(tCompactType(size_and_type)) + if e != nil { + err = NewTProtocolException(e) + return + } + return +} + +func (p *TCompactProtocol) ReadListEnd() error { return nil } + +// Read a set header off the wire. If the set size is 0-14, the size will +// be packed into the element type header. If it's a longer set, the 4 MSB +// of the element type header will be 0xF, and a varint will follow with the +// true size. +func (p *TCompactProtocol) ReadSetBegin() (elemType TType, size int, err error) { + return p.ReadListBegin() +} + +func (p *TCompactProtocol) ReadSetEnd() error { return nil } + +// Read a boolean off the wire. If this is a boolean field, the value should +// already have been read during readFieldBegin, so we'll just consume the +// pre-stored value. Otherwise, read a byte. +func (p *TCompactProtocol) ReadBool() (value bool, err error) { + if p.boolValueIsNotNull { + p.boolValueIsNotNull = false + return p.boolValue, nil + } + v, err := p.readByteDirect() + return v == COMPACT_BOOLEAN_TRUE, err +} + +// Read a single byte off the wire. Nothing interesting here. +func (p *TCompactProtocol) ReadByte() (int8, error) { + v, err := p.readByteDirect() + if err != nil { + return 0, NewTProtocolException(err) + } + return int8(v), err +} + +// Read an i16 from the wire as a zigzag varint. +func (p *TCompactProtocol) ReadI16() (value int16, err error) { + v, err := p.ReadI32() + return int16(v), err +} + +// Read an i32 from the wire as a zigzag varint. +func (p *TCompactProtocol) ReadI32() (value int32, err error) { + v, e := p.readVarint32() + if e != nil { + return 0, NewTProtocolException(e) + } + value = p.zigzagToInt32(v) + return value, nil +} + +// Read an i64 from the wire as a zigzag varint. +func (p *TCompactProtocol) ReadI64() (value int64, err error) { + v, e := p.readVarint64() + if e != nil { + return 0, NewTProtocolException(e) + } + value = p.zigzagToInt64(v) + return value, nil +} + +// No magic here - just read a double off the wire. +func (p *TCompactProtocol) ReadDouble() (value float64, err error) { + longBits := p.buffer[0:8] + _, e := io.ReadFull(p.trans, longBits) + if e != nil { + return 0.0, NewTProtocolException(e) + } + return math.Float64frombits(p.bytesToUint64(longBits)), nil +} + +// Reads a []byte (via readBinary), and then UTF-8 decodes it. +func (p *TCompactProtocol) ReadString() (value string, err error) { + length, e := p.readVarint32() + if e != nil { + return "", NewTProtocolException(e) + } + if length < 0 { + return "", invalidDataLength + } + if uint64(length) > p.trans.RemainingBytes() { + return "", invalidDataLength + } + + if length == 0 { + return "", nil + } + var buf []byte + if length <= int32(len(p.buffer)) { + buf = p.buffer[0:length] + } else { + buf = make([]byte, length) + } + _, e = io.ReadFull(p.trans, buf) + return string(buf), NewTProtocolException(e) +} + +// Read a []byte from the wire. +func (p *TCompactProtocol) ReadBinary() (value []byte, err error) { + length, e := p.readVarint32() + if e != nil { + return nil, NewTProtocolException(e) + } + if length == 0 { + return []byte{}, nil + } + if length < 0 { + return nil, invalidDataLength + } + if uint64(length) > p.trans.RemainingBytes() { + return nil, invalidDataLength + } + + buf := make([]byte, length) + _, e = io.ReadFull(p.trans, buf) + return buf, NewTProtocolException(e) +} + +func (p *TCompactProtocol) Flush() (err error) { + return NewTProtocolException(p.trans.Flush()) +} + +func (p *TCompactProtocol) Skip(fieldType TType) (err error) { + return SkipDefaultDepth(p, fieldType) +} + +func (p *TCompactProtocol) Transport() TTransport { + return p.origTransport +} + +// +// Internal writing methods +// + +// Abstract method for writing the start of lists and sets. List and sets on +// the wire differ only by the type indicator. +func (p *TCompactProtocol) writeCollectionBegin(elemType TType, size int) (int, error) { + if size <= 14 { + return 1, p.writeByteDirect(byte(int32(size<<4) | int32(p.getCompactType(elemType)))) + } + err := p.writeByteDirect(0xf0 | byte(p.getCompactType(elemType))) + if err != nil { + return 0, err + } + m, err := p.writeVarint32(int32(size)) + return 1 + m, err +} + +// Write an i32 as a varint. Results in 1-5 bytes on the wire. +// TODO(pomack): make a permanent buffer like writeVarint64? +func (p *TCompactProtocol) writeVarint32(n int32) (int, error) { + i32buf := p.buffer[0:5] + idx := 0 + for { + if (n & ^0x7F) == 0 { + i32buf[idx] = byte(n) + idx++ + // p.writeByteDirect(byte(n)); + break + // return; + } else { + i32buf[idx] = byte((n & 0x7F) | 0x80) + idx++ + // p.writeByteDirect(byte(((n & 0x7F) | 0x80))); + u := uint32(n) + n = int32(u >> 7) + } + } + return p.trans.Write(i32buf[0:idx]) +} + +// Write an i64 as a varint. Results in 1-10 bytes on the wire. +func (p *TCompactProtocol) writeVarint64(n int64) (int, error) { + varint64out := p.buffer[0:10] + idx := 0 + for { + if (n & ^0x7F) == 0 { + varint64out[idx] = byte(n) + idx++ + break + } else { + varint64out[idx] = byte((n & 0x7F) | 0x80) + idx++ + u := uint64(n) + n = int64(u >> 7) + } + } + return p.trans.Write(varint64out[0:idx]) +} + +// Convert l into a zigzag long. This allows negative numbers to be +// represented compactly as a varint. +func (p *TCompactProtocol) int64ToZigzag(l int64) int64 { + return (l << 1) ^ (l >> 63) +} + +// Convert l into a zigzag long. This allows negative numbers to be +// represented compactly as a varint. +func (p *TCompactProtocol) int32ToZigzag(n int32) int32 { + return (n << 1) ^ (n >> 31) +} + +func (p *TCompactProtocol) fixedUint64ToBytes(n uint64, buf []byte) { + binary.LittleEndian.PutUint64(buf, n) +} + +func (p *TCompactProtocol) fixedInt64ToBytes(n int64, buf []byte) { + binary.LittleEndian.PutUint64(buf, uint64(n)) +} + +// Writes a byte without any possibility of all that field header nonsense. +// Used internally by other writing methods that know they need to write a byte. +func (p *TCompactProtocol) writeByteDirect(b byte) error { + return p.trans.WriteByte(b) +} + +// Writes a byte without any possibility of all that field header nonsense. +func (p *TCompactProtocol) writeIntAsByteDirect(n int) (int, error) { + return 1, p.writeByteDirect(byte(n)) +} + +// +// Internal reading methods +// + +// Read an i32 from the wire as a varint. The MSB of each byte is set +// if there is another byte to follow. This can read up to 5 bytes. +func (p *TCompactProtocol) readVarint32() (int32, error) { + // if the wire contains the right stuff, this will just truncate the i64 we + // read and get us the right sign. + v, err := p.readVarint64() + return int32(v), err +} + +// Read an i64 from the wire as a proper varint. The MSB of each byte is set +// if there is another byte to follow. This can read up to 10 bytes. +func (p *TCompactProtocol) readVarint64() (int64, error) { + shift := uint(0) + result := int64(0) + for { + b, err := p.readByteDirect() + if err != nil { + return 0, err + } + result |= int64(b&0x7f) << shift + if (b & 0x80) != 0x80 { + break + } + shift += 7 + } + return result, nil +} + +// Read a byte, unlike ReadByte that reads Thrift-byte that is i8. +func (p *TCompactProtocol) readByteDirect() (byte, error) { + return p.trans.ReadByte() +} + +// +// encoding helpers +// + +// Convert from zigzag int to int. +func (p *TCompactProtocol) zigzagToInt32(n int32) int32 { + u := uint32(n) + return int32(u>>1) ^ -(n & 1) +} + +// Convert from zigzag long to long. +func (p *TCompactProtocol) zigzagToInt64(n int64) int64 { + u := uint64(n) + return int64(u>>1) ^ -(n & 1) +} + +// Note that it's important that the mask bytes are long literals, +// otherwise they'll default to ints, and when you shift an int left 56 bits, +// you just get a messed up int. +func (p *TCompactProtocol) bytesToInt64(b []byte) int64 { + return int64(binary.LittleEndian.Uint64(b)) +} + +// Note that it's important that the mask bytes are long literals, +// otherwise they'll default to ints, and when you shift an int left 56 bits, +// you just get a messed up int. +func (p *TCompactProtocol) bytesToUint64(b []byte) uint64 { + return binary.LittleEndian.Uint64(b) +} + +// +// type testing and converting +// + +func (p *TCompactProtocol) isBoolType(b byte) bool { + return (b&0x0f) == COMPACT_BOOLEAN_TRUE || (b&0x0f) == COMPACT_BOOLEAN_FALSE +} + +// Given a tCompactType constant, convert it to its corresponding +// TType value. +func (p *TCompactProtocol) getTType(t tCompactType) (TType, error) { + switch byte(t) & 0x0f { + case STOP: + return STOP, nil + case COMPACT_BOOLEAN_FALSE, COMPACT_BOOLEAN_TRUE: + return BOOL, nil + case COMPACT_BYTE: + return BYTE, nil + case COMPACT_I16: + return I16, nil + case COMPACT_I32: + return I32, nil + case COMPACT_I64: + return I64, nil + case COMPACT_DOUBLE: + return DOUBLE, nil + case COMPACT_BINARY: + return STRING, nil + case COMPACT_LIST: + return LIST, nil + case COMPACT_SET: + return SET, nil + case COMPACT_MAP: + return MAP, nil + case COMPACT_STRUCT: + return STRUCT, nil + } + return STOP, TException(fmt.Errorf("don't know what type: %d", t&0x0f)) +} + +// Given a TType value, find the appropriate TCompactProtocol.Types constant. +func (p *TCompactProtocol) getCompactType(t TType) tCompactType { + return ttypeToCompactType[t] +} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/exception.go b/vendor/github.com/uber/jaeger-client-go/thrift/exception.go new file mode 100644 index 0000000000..ea8d6f6611 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/thrift/exception.go @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 thrift + +import ( + "errors" +) + +// Generic Thrift exception +type TException interface { + error +} + +// Prepends additional information to an error without losing the Thrift exception interface +func PrependError(prepend string, err error) error { + if t, ok := err.(TTransportException); ok { + return NewTTransportException(t.TypeId(), prepend+t.Error()) + } + if t, ok := err.(TProtocolException); ok { + return NewTProtocolExceptionWithType(t.TypeId(), errors.New(prepend+err.Error())) + } + if t, ok := err.(TApplicationException); ok { + return NewTApplicationException(t.TypeId(), prepend+t.Error()) + } + + return errors.New(prepend + err.Error()) +} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/memory_buffer.go b/vendor/github.com/uber/jaeger-client-go/thrift/memory_buffer.go new file mode 100644 index 0000000000..b62fd56f06 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/thrift/memory_buffer.go @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 thrift + +import ( + "bytes" +) + +// Memory buffer-based implementation of the TTransport interface. +type TMemoryBuffer struct { + *bytes.Buffer + size int +} + +type TMemoryBufferTransportFactory struct { + size int +} + +func (p *TMemoryBufferTransportFactory) GetTransport(trans TTransport) TTransport { + if trans != nil { + t, ok := trans.(*TMemoryBuffer) + if ok && t.size > 0 { + return NewTMemoryBufferLen(t.size) + } + } + return NewTMemoryBufferLen(p.size) +} + +func NewTMemoryBufferTransportFactory(size int) *TMemoryBufferTransportFactory { + return &TMemoryBufferTransportFactory{size: size} +} + +func NewTMemoryBuffer() *TMemoryBuffer { + return &TMemoryBuffer{Buffer: &bytes.Buffer{}, size: 0} +} + +func NewTMemoryBufferLen(size int) *TMemoryBuffer { + buf := make([]byte, 0, size) + return &TMemoryBuffer{Buffer: bytes.NewBuffer(buf), size: size} +} + +func (p *TMemoryBuffer) IsOpen() bool { + return true +} + +func (p *TMemoryBuffer) Open() error { + return nil +} + +func (p *TMemoryBuffer) Close() error { + p.Buffer.Reset() + return nil +} + +// Flushing a memory buffer is a no-op +func (p *TMemoryBuffer) Flush() error { + return nil +} + +func (p *TMemoryBuffer) RemainingBytes() (num_bytes uint64) { + return uint64(p.Buffer.Len()) +} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/messagetype.go b/vendor/github.com/uber/jaeger-client-go/thrift/messagetype.go new file mode 100644 index 0000000000..25ab2e98a2 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/thrift/messagetype.go @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 thrift + +// Message type constants in the Thrift protocol. +type TMessageType int32 + +const ( + INVALID_TMESSAGE_TYPE TMessageType = 0 + CALL TMessageType = 1 + REPLY TMessageType = 2 + EXCEPTION TMessageType = 3 + ONEWAY TMessageType = 4 +) diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/numeric.go b/vendor/github.com/uber/jaeger-client-go/thrift/numeric.go new file mode 100644 index 0000000000..aa8daa9b54 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/thrift/numeric.go @@ -0,0 +1,164 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 thrift + +import ( + "math" + "strconv" +) + +type Numeric interface { + Int64() int64 + Int32() int32 + Int16() int16 + Byte() byte + Int() int + Float64() float64 + Float32() float32 + String() string + isNull() bool +} + +type numeric struct { + iValue int64 + dValue float64 + sValue string + isNil bool +} + +var ( + INFINITY Numeric + NEGATIVE_INFINITY Numeric + NAN Numeric + ZERO Numeric + NUMERIC_NULL Numeric +) + +func NewNumericFromDouble(dValue float64) Numeric { + if math.IsInf(dValue, 1) { + return INFINITY + } + if math.IsInf(dValue, -1) { + return NEGATIVE_INFINITY + } + if math.IsNaN(dValue) { + return NAN + } + iValue := int64(dValue) + sValue := strconv.FormatFloat(dValue, 'g', 10, 64) + isNil := false + return &numeric{iValue: iValue, dValue: dValue, sValue: sValue, isNil: isNil} +} + +func NewNumericFromI64(iValue int64) Numeric { + dValue := float64(iValue) + sValue := string(iValue) + isNil := false + return &numeric{iValue: iValue, dValue: dValue, sValue: sValue, isNil: isNil} +} + +func NewNumericFromI32(iValue int32) Numeric { + dValue := float64(iValue) + sValue := string(iValue) + isNil := false + return &numeric{iValue: int64(iValue), dValue: dValue, sValue: sValue, isNil: isNil} +} + +func NewNumericFromString(sValue string) Numeric { + if sValue == INFINITY.String() { + return INFINITY + } + if sValue == NEGATIVE_INFINITY.String() { + return NEGATIVE_INFINITY + } + if sValue == NAN.String() { + return NAN + } + iValue, _ := strconv.ParseInt(sValue, 10, 64) + dValue, _ := strconv.ParseFloat(sValue, 64) + isNil := len(sValue) == 0 + return &numeric{iValue: iValue, dValue: dValue, sValue: sValue, isNil: isNil} +} + +func NewNumericFromJSONString(sValue string, isNull bool) Numeric { + if isNull { + return NewNullNumeric() + } + if sValue == JSON_INFINITY { + return INFINITY + } + if sValue == JSON_NEGATIVE_INFINITY { + return NEGATIVE_INFINITY + } + if sValue == JSON_NAN { + return NAN + } + iValue, _ := strconv.ParseInt(sValue, 10, 64) + dValue, _ := strconv.ParseFloat(sValue, 64) + return &numeric{iValue: iValue, dValue: dValue, sValue: sValue, isNil: isNull} +} + +func NewNullNumeric() Numeric { + return &numeric{iValue: 0, dValue: 0.0, sValue: "", isNil: true} +} + +func (p *numeric) Int64() int64 { + return p.iValue +} + +func (p *numeric) Int32() int32 { + return int32(p.iValue) +} + +func (p *numeric) Int16() int16 { + return int16(p.iValue) +} + +func (p *numeric) Byte() byte { + return byte(p.iValue) +} + +func (p *numeric) Int() int { + return int(p.iValue) +} + +func (p *numeric) Float64() float64 { + return p.dValue +} + +func (p *numeric) Float32() float32 { + return float32(p.dValue) +} + +func (p *numeric) String() string { + return p.sValue +} + +func (p *numeric) isNull() bool { + return p.isNil +} + +func init() { + INFINITY = &numeric{iValue: 0, dValue: math.Inf(1), sValue: "Infinity", isNil: false} + NEGATIVE_INFINITY = &numeric{iValue: 0, dValue: math.Inf(-1), sValue: "-Infinity", isNil: false} + NAN = &numeric{iValue: 0, dValue: math.NaN(), sValue: "NaN", isNil: false} + ZERO = &numeric{iValue: 0, dValue: 0, sValue: "0", isNil: false} + NUMERIC_NULL = &numeric{iValue: 0, dValue: 0, sValue: "0", isNil: true} +} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/processor.go b/vendor/github.com/uber/jaeger-client-go/thrift/processor.go new file mode 100644 index 0000000000..ca0d3faf20 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/thrift/processor.go @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 thrift + +// A processor is a generic object which operates upon an input stream and +// writes to some output stream. +type TProcessor interface { + Process(in, out TProtocol) (bool, TException) +} + +type TProcessorFunction interface { + Process(seqId int32, in, out TProtocol) (bool, TException) +} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/protocol.go b/vendor/github.com/uber/jaeger-client-go/thrift/protocol.go new file mode 100644 index 0000000000..45fa202e74 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/thrift/protocol.go @@ -0,0 +1,175 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 thrift + +import ( + "errors" +) + +const ( + VERSION_MASK = 0xffff0000 + VERSION_1 = 0x80010000 +) + +type TProtocol interface { + WriteMessageBegin(name string, typeId TMessageType, seqid int32) error + WriteMessageEnd() error + WriteStructBegin(name string) error + WriteStructEnd() error + WriteFieldBegin(name string, typeId TType, id int16) error + WriteFieldEnd() error + WriteFieldStop() error + WriteMapBegin(keyType TType, valueType TType, size int) error + WriteMapEnd() error + WriteListBegin(elemType TType, size int) error + WriteListEnd() error + WriteSetBegin(elemType TType, size int) error + WriteSetEnd() error + WriteBool(value bool) error + WriteByte(value int8) error + WriteI16(value int16) error + WriteI32(value int32) error + WriteI64(value int64) error + WriteDouble(value float64) error + WriteString(value string) error + WriteBinary(value []byte) error + + ReadMessageBegin() (name string, typeId TMessageType, seqid int32, err error) + ReadMessageEnd() error + ReadStructBegin() (name string, err error) + ReadStructEnd() error + ReadFieldBegin() (name string, typeId TType, id int16, err error) + ReadFieldEnd() error + ReadMapBegin() (keyType TType, valueType TType, size int, err error) + ReadMapEnd() error + ReadListBegin() (elemType TType, size int, err error) + ReadListEnd() error + ReadSetBegin() (elemType TType, size int, err error) + ReadSetEnd() error + ReadBool() (value bool, err error) + ReadByte() (value int8, err error) + ReadI16() (value int16, err error) + ReadI32() (value int32, err error) + ReadI64() (value int64, err error) + ReadDouble() (value float64, err error) + ReadString() (value string, err error) + ReadBinary() (value []byte, err error) + + Skip(fieldType TType) (err error) + Flush() (err error) + + Transport() TTransport +} + +// The maximum recursive depth the skip() function will traverse +const DEFAULT_RECURSION_DEPTH = 64 + +// Skips over the next data element from the provided input TProtocol object. +func SkipDefaultDepth(prot TProtocol, typeId TType) (err error) { + return Skip(prot, typeId, DEFAULT_RECURSION_DEPTH) +} + +// Skips over the next data element from the provided input TProtocol object. +func Skip(self TProtocol, fieldType TType, maxDepth int) (err error) { + + if maxDepth <= 0 { + return NewTProtocolExceptionWithType( DEPTH_LIMIT, errors.New("Depth limit exceeded")) + } + + switch fieldType { + case STOP: + return + case BOOL: + _, err = self.ReadBool() + return + case BYTE: + _, err = self.ReadByte() + return + case I16: + _, err = self.ReadI16() + return + case I32: + _, err = self.ReadI32() + return + case I64: + _, err = self.ReadI64() + return + case DOUBLE: + _, err = self.ReadDouble() + return + case STRING: + _, err = self.ReadString() + return + case STRUCT: + if _, err = self.ReadStructBegin(); err != nil { + return err + } + for { + _, typeId, _, _ := self.ReadFieldBegin() + if typeId == STOP { + break + } + err := Skip(self, typeId, maxDepth-1) + if err != nil { + return err + } + self.ReadFieldEnd() + } + return self.ReadStructEnd() + case MAP: + keyType, valueType, size, err := self.ReadMapBegin() + if err != nil { + return err + } + for i := 0; i < size; i++ { + err := Skip(self, keyType, maxDepth-1) + if err != nil { + return err + } + self.Skip(valueType) + } + return self.ReadMapEnd() + case SET: + elemType, size, err := self.ReadSetBegin() + if err != nil { + return err + } + for i := 0; i < size; i++ { + err := Skip(self, elemType, maxDepth-1) + if err != nil { + return err + } + } + return self.ReadSetEnd() + case LIST: + elemType, size, err := self.ReadListBegin() + if err != nil { + return err + } + for i := 0; i < size; i++ { + err := Skip(self, elemType, maxDepth-1) + if err != nil { + return err + } + } + return self.ReadListEnd() + } + return nil +} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/protocol_exception.go b/vendor/github.com/uber/jaeger-client-go/thrift/protocol_exception.go new file mode 100644 index 0000000000..6e357ee890 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/thrift/protocol_exception.go @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 thrift + +import ( + "encoding/base64" +) + +// Thrift Protocol exception +type TProtocolException interface { + TException + TypeId() int +} + +const ( + UNKNOWN_PROTOCOL_EXCEPTION = 0 + INVALID_DATA = 1 + NEGATIVE_SIZE = 2 + SIZE_LIMIT = 3 + BAD_VERSION = 4 + NOT_IMPLEMENTED = 5 + DEPTH_LIMIT = 6 +) + +type tProtocolException struct { + typeId int + message string +} + +func (p *tProtocolException) TypeId() int { + return p.typeId +} + +func (p *tProtocolException) String() string { + return p.message +} + +func (p *tProtocolException) Error() string { + return p.message +} + +func NewTProtocolException(err error) TProtocolException { + if err == nil { + return nil + } + if e,ok := err.(TProtocolException); ok { + return e + } + if _, ok := err.(base64.CorruptInputError); ok { + return &tProtocolException{INVALID_DATA, err.Error()} + } + return &tProtocolException{UNKNOWN_PROTOCOL_EXCEPTION, err.Error()} +} + +func NewTProtocolExceptionWithType(errType int, err error) TProtocolException { + if err == nil { + return nil + } + return &tProtocolException{errType, err.Error()} +} + diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/protocol_factory.go b/vendor/github.com/uber/jaeger-client-go/thrift/protocol_factory.go new file mode 100644 index 0000000000..c40f796d88 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/thrift/protocol_factory.go @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 thrift + +// Factory interface for constructing protocol instances. +type TProtocolFactory interface { + GetProtocol(trans TTransport) TProtocol +} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/rich_transport.go b/vendor/github.com/uber/jaeger-client-go/thrift/rich_transport.go new file mode 100644 index 0000000000..8e296a99b5 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/thrift/rich_transport.go @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 thrift + +import "io" + +type RichTransport struct { + TTransport +} + +// Wraps Transport to provide TRichTransport interface +func NewTRichTransport(trans TTransport) *RichTransport { + return &RichTransport{trans} +} + +func (r *RichTransport) ReadByte() (c byte, err error) { + return readByte(r.TTransport) +} + +func (r *RichTransport) WriteByte(c byte) error { + return writeByte(r.TTransport, c) +} + +func (r *RichTransport) WriteString(s string) (n int, err error) { + return r.Write([]byte(s)) +} + +func (r *RichTransport) RemainingBytes() (num_bytes uint64) { + return r.TTransport.RemainingBytes() +} + +func readByte(r io.Reader) (c byte, err error) { + v := [1]byte{0} + n, err := r.Read(v[0:1]) + if n > 0 && (err == nil || err == io.EOF) { + return v[0], nil + } + if n > 0 && err != nil { + return v[0], err + } + if err != nil { + return 0, err + } + return v[0], nil +} + +func writeByte(w io.Writer, c byte) error { + v := [1]byte{c} + _, err := w.Write(v[0:1]) + return err +} + diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/serializer.go b/vendor/github.com/uber/jaeger-client-go/thrift/serializer.go new file mode 100644 index 0000000000..7712229990 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/thrift/serializer.go @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 thrift + +type TSerializer struct { + Transport *TMemoryBuffer + Protocol TProtocol +} + +type TStruct interface { + Write(p TProtocol) error + Read(p TProtocol) error +} + +func NewTSerializer() *TSerializer { + transport := NewTMemoryBufferLen(1024) + protocol := NewTBinaryProtocolFactoryDefault().GetProtocol(transport) + + return &TSerializer{ + transport, + protocol} +} + +func (t *TSerializer) WriteString(msg TStruct) (s string, err error) { + t.Transport.Reset() + + if err = msg.Write(t.Protocol); err != nil { + return + } + + if err = t.Protocol.Flush(); err != nil { + return + } + if err = t.Transport.Flush(); err != nil { + return + } + + return t.Transport.String(), nil +} + +func (t *TSerializer) Write(msg TStruct) (b []byte, err error) { + t.Transport.Reset() + + if err = msg.Write(t.Protocol); err != nil { + return + } + + if err = t.Protocol.Flush(); err != nil { + return + } + + if err = t.Transport.Flush(); err != nil { + return + } + + b = append(b, t.Transport.Bytes()...) + return +} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/simple_json_protocol.go b/vendor/github.com/uber/jaeger-client-go/thrift/simple_json_protocol.go new file mode 100644 index 0000000000..412a482d05 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/thrift/simple_json_protocol.go @@ -0,0 +1,1337 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 thrift + +import ( + "bufio" + "bytes" + "encoding/base64" + "encoding/json" + "fmt" + "io" + "math" + "strconv" +) + +type _ParseContext int + +const ( + _CONTEXT_IN_TOPLEVEL _ParseContext = 1 + _CONTEXT_IN_LIST_FIRST _ParseContext = 2 + _CONTEXT_IN_LIST _ParseContext = 3 + _CONTEXT_IN_OBJECT_FIRST _ParseContext = 4 + _CONTEXT_IN_OBJECT_NEXT_KEY _ParseContext = 5 + _CONTEXT_IN_OBJECT_NEXT_VALUE _ParseContext = 6 +) + +func (p _ParseContext) String() string { + switch p { + case _CONTEXT_IN_TOPLEVEL: + return "TOPLEVEL" + case _CONTEXT_IN_LIST_FIRST: + return "LIST-FIRST" + case _CONTEXT_IN_LIST: + return "LIST" + case _CONTEXT_IN_OBJECT_FIRST: + return "OBJECT-FIRST" + case _CONTEXT_IN_OBJECT_NEXT_KEY: + return "OBJECT-NEXT-KEY" + case _CONTEXT_IN_OBJECT_NEXT_VALUE: + return "OBJECT-NEXT-VALUE" + } + return "UNKNOWN-PARSE-CONTEXT" +} + +// JSON protocol implementation for thrift. +// +// This protocol produces/consumes a simple output format +// suitable for parsing by scripting languages. It should not be +// confused with the full-featured TJSONProtocol. +// +type TSimpleJSONProtocol struct { + trans TTransport + + parseContextStack []int + dumpContext []int + + writer *bufio.Writer + reader *bufio.Reader +} + +// Constructor +func NewTSimpleJSONProtocol(t TTransport) *TSimpleJSONProtocol { + v := &TSimpleJSONProtocol{trans: t, + writer: bufio.NewWriter(t), + reader: bufio.NewReader(t), + } + v.parseContextStack = append(v.parseContextStack, int(_CONTEXT_IN_TOPLEVEL)) + v.dumpContext = append(v.dumpContext, int(_CONTEXT_IN_TOPLEVEL)) + return v +} + +// Factory +type TSimpleJSONProtocolFactory struct{} + +func (p *TSimpleJSONProtocolFactory) GetProtocol(trans TTransport) TProtocol { + return NewTSimpleJSONProtocol(trans) +} + +func NewTSimpleJSONProtocolFactory() *TSimpleJSONProtocolFactory { + return &TSimpleJSONProtocolFactory{} +} + +var ( + JSON_COMMA []byte + JSON_COLON []byte + JSON_LBRACE []byte + JSON_RBRACE []byte + JSON_LBRACKET []byte + JSON_RBRACKET []byte + JSON_QUOTE byte + JSON_QUOTE_BYTES []byte + JSON_NULL []byte + JSON_TRUE []byte + JSON_FALSE []byte + JSON_INFINITY string + JSON_NEGATIVE_INFINITY string + JSON_NAN string + JSON_INFINITY_BYTES []byte + JSON_NEGATIVE_INFINITY_BYTES []byte + JSON_NAN_BYTES []byte + json_nonbase_map_elem_bytes []byte +) + +func init() { + JSON_COMMA = []byte{','} + JSON_COLON = []byte{':'} + JSON_LBRACE = []byte{'{'} + JSON_RBRACE = []byte{'}'} + JSON_LBRACKET = []byte{'['} + JSON_RBRACKET = []byte{']'} + JSON_QUOTE = '"' + JSON_QUOTE_BYTES = []byte{'"'} + JSON_NULL = []byte{'n', 'u', 'l', 'l'} + JSON_TRUE = []byte{'t', 'r', 'u', 'e'} + JSON_FALSE = []byte{'f', 'a', 'l', 's', 'e'} + JSON_INFINITY = "Infinity" + JSON_NEGATIVE_INFINITY = "-Infinity" + JSON_NAN = "NaN" + JSON_INFINITY_BYTES = []byte{'I', 'n', 'f', 'i', 'n', 'i', 't', 'y'} + JSON_NEGATIVE_INFINITY_BYTES = []byte{'-', 'I', 'n', 'f', 'i', 'n', 'i', 't', 'y'} + JSON_NAN_BYTES = []byte{'N', 'a', 'N'} + json_nonbase_map_elem_bytes = []byte{']', ',', '['} +} + +func jsonQuote(s string) string { + b, _ := json.Marshal(s) + s1 := string(b) + return s1 +} + +func jsonUnquote(s string) (string, bool) { + s1 := new(string) + err := json.Unmarshal([]byte(s), s1) + return *s1, err == nil +} + +func mismatch(expected, actual string) error { + return fmt.Errorf("Expected '%s' but found '%s' while parsing JSON.", expected, actual) +} + +func (p *TSimpleJSONProtocol) WriteMessageBegin(name string, typeId TMessageType, seqId int32) error { + p.resetContextStack() // THRIFT-3735 + if e := p.OutputListBegin(); e != nil { + return e + } + if e := p.WriteString(name); e != nil { + return e + } + if e := p.WriteByte(int8(typeId)); e != nil { + return e + } + if e := p.WriteI32(seqId); e != nil { + return e + } + return nil +} + +func (p *TSimpleJSONProtocol) WriteMessageEnd() error { + return p.OutputListEnd() +} + +func (p *TSimpleJSONProtocol) WriteStructBegin(name string) error { + if e := p.OutputObjectBegin(); e != nil { + return e + } + return nil +} + +func (p *TSimpleJSONProtocol) WriteStructEnd() error { + return p.OutputObjectEnd() +} + +func (p *TSimpleJSONProtocol) WriteFieldBegin(name string, typeId TType, id int16) error { + if e := p.WriteString(name); e != nil { + return e + } + return nil +} + +func (p *TSimpleJSONProtocol) WriteFieldEnd() error { + //return p.OutputListEnd() + return nil +} + +func (p *TSimpleJSONProtocol) WriteFieldStop() error { return nil } + +func (p *TSimpleJSONProtocol) WriteMapBegin(keyType TType, valueType TType, size int) error { + if e := p.OutputListBegin(); e != nil { + return e + } + if e := p.WriteByte(int8(keyType)); e != nil { + return e + } + if e := p.WriteByte(int8(valueType)); e != nil { + return e + } + return p.WriteI32(int32(size)) +} + +func (p *TSimpleJSONProtocol) WriteMapEnd() error { + return p.OutputListEnd() +} + +func (p *TSimpleJSONProtocol) WriteListBegin(elemType TType, size int) error { + return p.OutputElemListBegin(elemType, size) +} + +func (p *TSimpleJSONProtocol) WriteListEnd() error { + return p.OutputListEnd() +} + +func (p *TSimpleJSONProtocol) WriteSetBegin(elemType TType, size int) error { + return p.OutputElemListBegin(elemType, size) +} + +func (p *TSimpleJSONProtocol) WriteSetEnd() error { + return p.OutputListEnd() +} + +func (p *TSimpleJSONProtocol) WriteBool(b bool) error { + return p.OutputBool(b) +} + +func (p *TSimpleJSONProtocol) WriteByte(b int8) error { + return p.WriteI32(int32(b)) +} + +func (p *TSimpleJSONProtocol) WriteI16(v int16) error { + return p.WriteI32(int32(v)) +} + +func (p *TSimpleJSONProtocol) WriteI32(v int32) error { + return p.OutputI64(int64(v)) +} + +func (p *TSimpleJSONProtocol) WriteI64(v int64) error { + return p.OutputI64(int64(v)) +} + +func (p *TSimpleJSONProtocol) WriteDouble(v float64) error { + return p.OutputF64(v) +} + +func (p *TSimpleJSONProtocol) WriteString(v string) error { + return p.OutputString(v) +} + +func (p *TSimpleJSONProtocol) WriteBinary(v []byte) error { + // JSON library only takes in a string, + // not an arbitrary byte array, to ensure bytes are transmitted + // efficiently we must convert this into a valid JSON string + // therefore we use base64 encoding to avoid excessive escaping/quoting + if e := p.OutputPreValue(); e != nil { + return e + } + if _, e := p.write(JSON_QUOTE_BYTES); e != nil { + return NewTProtocolException(e) + } + writer := base64.NewEncoder(base64.StdEncoding, p.writer) + if _, e := writer.Write(v); e != nil { + p.writer.Reset(p.trans) // THRIFT-3735 + return NewTProtocolException(e) + } + if e := writer.Close(); e != nil { + return NewTProtocolException(e) + } + if _, e := p.write(JSON_QUOTE_BYTES); e != nil { + return NewTProtocolException(e) + } + return p.OutputPostValue() +} + +// Reading methods. +func (p *TSimpleJSONProtocol) ReadMessageBegin() (name string, typeId TMessageType, seqId int32, err error) { + p.resetContextStack() // THRIFT-3735 + if isNull, err := p.ParseListBegin(); isNull || err != nil { + return name, typeId, seqId, err + } + if name, err = p.ReadString(); err != nil { + return name, typeId, seqId, err + } + bTypeId, err := p.ReadByte() + typeId = TMessageType(bTypeId) + if err != nil { + return name, typeId, seqId, err + } + if seqId, err = p.ReadI32(); err != nil { + return name, typeId, seqId, err + } + return name, typeId, seqId, nil +} + +func (p *TSimpleJSONProtocol) ReadMessageEnd() error { + return p.ParseListEnd() +} + +func (p *TSimpleJSONProtocol) ReadStructBegin() (name string, err error) { + _, err = p.ParseObjectStart() + return "", err +} + +func (p *TSimpleJSONProtocol) ReadStructEnd() error { + return p.ParseObjectEnd() +} + +func (p *TSimpleJSONProtocol) ReadFieldBegin() (string, TType, int16, error) { + if err := p.ParsePreValue(); err != nil { + return "", STOP, 0, err + } + b, _ := p.reader.Peek(1) + if len(b) > 0 { + switch b[0] { + case JSON_RBRACE[0]: + return "", STOP, 0, nil + case JSON_QUOTE: + p.reader.ReadByte() + name, err := p.ParseStringBody() + // simplejson is not meant to be read back into thrift + // - see http://wiki.apache.org/thrift/ThriftUsageJava + // - use JSON instead + if err != nil { + return name, STOP, 0, err + } + return name, STOP, -1, p.ParsePostValue() + /* + if err = p.ParsePostValue(); err != nil { + return name, STOP, 0, err + } + if isNull, err := p.ParseListBegin(); isNull || err != nil { + return name, STOP, 0, err + } + bType, err := p.ReadByte() + thetype := TType(bType) + if err != nil { + return name, thetype, 0, err + } + id, err := p.ReadI16() + return name, thetype, id, err + */ + } + e := fmt.Errorf("Expected \"}\" or '\"', but found: '%s'", string(b)) + return "", STOP, 0, NewTProtocolExceptionWithType(INVALID_DATA, e) + } + return "", STOP, 0, NewTProtocolException(io.EOF) +} + +func (p *TSimpleJSONProtocol) ReadFieldEnd() error { + return nil + //return p.ParseListEnd() +} + +func (p *TSimpleJSONProtocol) ReadMapBegin() (keyType TType, valueType TType, size int, e error) { + if isNull, e := p.ParseListBegin(); isNull || e != nil { + return VOID, VOID, 0, e + } + + // read keyType + bKeyType, e := p.ReadByte() + keyType = TType(bKeyType) + if e != nil { + return keyType, valueType, size, e + } + + // read valueType + bValueType, e := p.ReadByte() + valueType = TType(bValueType) + if e != nil { + return keyType, valueType, size, e + } + + // read size + iSize, err := p.ReadI64() + size = int(iSize) + return keyType, valueType, size, err +} + +func (p *TSimpleJSONProtocol) ReadMapEnd() error { + return p.ParseListEnd() +} + +func (p *TSimpleJSONProtocol) ReadListBegin() (elemType TType, size int, e error) { + return p.ParseElemListBegin() +} + +func (p *TSimpleJSONProtocol) ReadListEnd() error { + return p.ParseListEnd() +} + +func (p *TSimpleJSONProtocol) ReadSetBegin() (elemType TType, size int, e error) { + return p.ParseElemListBegin() +} + +func (p *TSimpleJSONProtocol) ReadSetEnd() error { + return p.ParseListEnd() +} + +func (p *TSimpleJSONProtocol) ReadBool() (bool, error) { + var value bool + + if err := p.ParsePreValue(); err != nil { + return value, err + } + f, _ := p.reader.Peek(1) + if len(f) > 0 { + switch f[0] { + case JSON_TRUE[0]: + b := make([]byte, len(JSON_TRUE)) + _, err := p.reader.Read(b) + if err != nil { + return false, NewTProtocolException(err) + } + if string(b) == string(JSON_TRUE) { + value = true + } else { + e := fmt.Errorf("Expected \"true\" but found: %s", string(b)) + return value, NewTProtocolExceptionWithType(INVALID_DATA, e) + } + break + case JSON_FALSE[0]: + b := make([]byte, len(JSON_FALSE)) + _, err := p.reader.Read(b) + if err != nil { + return false, NewTProtocolException(err) + } + if string(b) == string(JSON_FALSE) { + value = false + } else { + e := fmt.Errorf("Expected \"false\" but found: %s", string(b)) + return value, NewTProtocolExceptionWithType(INVALID_DATA, e) + } + break + case JSON_NULL[0]: + b := make([]byte, len(JSON_NULL)) + _, err := p.reader.Read(b) + if err != nil { + return false, NewTProtocolException(err) + } + if string(b) == string(JSON_NULL) { + value = false + } else { + e := fmt.Errorf("Expected \"null\" but found: %s", string(b)) + return value, NewTProtocolExceptionWithType(INVALID_DATA, e) + } + default: + e := fmt.Errorf("Expected \"true\", \"false\", or \"null\" but found: %s", string(f)) + return value, NewTProtocolExceptionWithType(INVALID_DATA, e) + } + } + return value, p.ParsePostValue() +} + +func (p *TSimpleJSONProtocol) ReadByte() (int8, error) { + v, err := p.ReadI64() + return int8(v), err +} + +func (p *TSimpleJSONProtocol) ReadI16() (int16, error) { + v, err := p.ReadI64() + return int16(v), err +} + +func (p *TSimpleJSONProtocol) ReadI32() (int32, error) { + v, err := p.ReadI64() + return int32(v), err +} + +func (p *TSimpleJSONProtocol) ReadI64() (int64, error) { + v, _, err := p.ParseI64() + return v, err +} + +func (p *TSimpleJSONProtocol) ReadDouble() (float64, error) { + v, _, err := p.ParseF64() + return v, err +} + +func (p *TSimpleJSONProtocol) ReadString() (string, error) { + var v string + if err := p.ParsePreValue(); err != nil { + return v, err + } + f, _ := p.reader.Peek(1) + if len(f) > 0 && f[0] == JSON_QUOTE { + p.reader.ReadByte() + value, err := p.ParseStringBody() + v = value + if err != nil { + return v, err + } + } else if len(f) > 0 && f[0] == JSON_NULL[0] { + b := make([]byte, len(JSON_NULL)) + _, err := p.reader.Read(b) + if err != nil { + return v, NewTProtocolException(err) + } + if string(b) != string(JSON_NULL) { + e := fmt.Errorf("Expected a JSON string, found unquoted data started with %s", string(b)) + return v, NewTProtocolExceptionWithType(INVALID_DATA, e) + } + } else { + e := fmt.Errorf("Expected a JSON string, found unquoted data started with %s", string(f)) + return v, NewTProtocolExceptionWithType(INVALID_DATA, e) + } + return v, p.ParsePostValue() +} + +func (p *TSimpleJSONProtocol) ReadBinary() ([]byte, error) { + var v []byte + if err := p.ParsePreValue(); err != nil { + return nil, err + } + f, _ := p.reader.Peek(1) + if len(f) > 0 && f[0] == JSON_QUOTE { + p.reader.ReadByte() + value, err := p.ParseBase64EncodedBody() + v = value + if err != nil { + return v, err + } + } else if len(f) > 0 && f[0] == JSON_NULL[0] { + b := make([]byte, len(JSON_NULL)) + _, err := p.reader.Read(b) + if err != nil { + return v, NewTProtocolException(err) + } + if string(b) != string(JSON_NULL) { + e := fmt.Errorf("Expected a JSON string, found unquoted data started with %s", string(b)) + return v, NewTProtocolExceptionWithType(INVALID_DATA, e) + } + } else { + e := fmt.Errorf("Expected a JSON string, found unquoted data started with %s", string(f)) + return v, NewTProtocolExceptionWithType(INVALID_DATA, e) + } + + return v, p.ParsePostValue() +} + +func (p *TSimpleJSONProtocol) Flush() (err error) { + return NewTProtocolException(p.writer.Flush()) +} + +func (p *TSimpleJSONProtocol) Skip(fieldType TType) (err error) { + return SkipDefaultDepth(p, fieldType) +} + +func (p *TSimpleJSONProtocol) Transport() TTransport { + return p.trans +} + +func (p *TSimpleJSONProtocol) OutputPreValue() error { + cxt := _ParseContext(p.dumpContext[len(p.dumpContext)-1]) + switch cxt { + case _CONTEXT_IN_LIST, _CONTEXT_IN_OBJECT_NEXT_KEY: + if _, e := p.write(JSON_COMMA); e != nil { + return NewTProtocolException(e) + } + break + case _CONTEXT_IN_OBJECT_NEXT_VALUE: + if _, e := p.write(JSON_COLON); e != nil { + return NewTProtocolException(e) + } + break + } + return nil +} + +func (p *TSimpleJSONProtocol) OutputPostValue() error { + cxt := _ParseContext(p.dumpContext[len(p.dumpContext)-1]) + switch cxt { + case _CONTEXT_IN_LIST_FIRST: + p.dumpContext = p.dumpContext[:len(p.dumpContext)-1] + p.dumpContext = append(p.dumpContext, int(_CONTEXT_IN_LIST)) + break + case _CONTEXT_IN_OBJECT_FIRST: + p.dumpContext = p.dumpContext[:len(p.dumpContext)-1] + p.dumpContext = append(p.dumpContext, int(_CONTEXT_IN_OBJECT_NEXT_VALUE)) + break + case _CONTEXT_IN_OBJECT_NEXT_KEY: + p.dumpContext = p.dumpContext[:len(p.dumpContext)-1] + p.dumpContext = append(p.dumpContext, int(_CONTEXT_IN_OBJECT_NEXT_VALUE)) + break + case _CONTEXT_IN_OBJECT_NEXT_VALUE: + p.dumpContext = p.dumpContext[:len(p.dumpContext)-1] + p.dumpContext = append(p.dumpContext, int(_CONTEXT_IN_OBJECT_NEXT_KEY)) + break + } + return nil +} + +func (p *TSimpleJSONProtocol) OutputBool(value bool) error { + if e := p.OutputPreValue(); e != nil { + return e + } + var v string + if value { + v = string(JSON_TRUE) + } else { + v = string(JSON_FALSE) + } + switch _ParseContext(p.dumpContext[len(p.dumpContext)-1]) { + case _CONTEXT_IN_OBJECT_FIRST, _CONTEXT_IN_OBJECT_NEXT_KEY: + v = jsonQuote(v) + default: + } + if e := p.OutputStringData(v); e != nil { + return e + } + return p.OutputPostValue() +} + +func (p *TSimpleJSONProtocol) OutputNull() error { + if e := p.OutputPreValue(); e != nil { + return e + } + if _, e := p.write(JSON_NULL); e != nil { + return NewTProtocolException(e) + } + return p.OutputPostValue() +} + +func (p *TSimpleJSONProtocol) OutputF64(value float64) error { + if e := p.OutputPreValue(); e != nil { + return e + } + var v string + if math.IsNaN(value) { + v = string(JSON_QUOTE) + JSON_NAN + string(JSON_QUOTE) + } else if math.IsInf(value, 1) { + v = string(JSON_QUOTE) + JSON_INFINITY + string(JSON_QUOTE) + } else if math.IsInf(value, -1) { + v = string(JSON_QUOTE) + JSON_NEGATIVE_INFINITY + string(JSON_QUOTE) + } else { + v = strconv.FormatFloat(value, 'g', -1, 64) + switch _ParseContext(p.dumpContext[len(p.dumpContext)-1]) { + case _CONTEXT_IN_OBJECT_FIRST, _CONTEXT_IN_OBJECT_NEXT_KEY: + v = string(JSON_QUOTE) + v + string(JSON_QUOTE) + default: + } + } + if e := p.OutputStringData(v); e != nil { + return e + } + return p.OutputPostValue() +} + +func (p *TSimpleJSONProtocol) OutputI64(value int64) error { + if e := p.OutputPreValue(); e != nil { + return e + } + v := strconv.FormatInt(value, 10) + switch _ParseContext(p.dumpContext[len(p.dumpContext)-1]) { + case _CONTEXT_IN_OBJECT_FIRST, _CONTEXT_IN_OBJECT_NEXT_KEY: + v = jsonQuote(v) + default: + } + if e := p.OutputStringData(v); e != nil { + return e + } + return p.OutputPostValue() +} + +func (p *TSimpleJSONProtocol) OutputString(s string) error { + if e := p.OutputPreValue(); e != nil { + return e + } + if e := p.OutputStringData(jsonQuote(s)); e != nil { + return e + } + return p.OutputPostValue() +} + +func (p *TSimpleJSONProtocol) OutputStringData(s string) error { + _, e := p.write([]byte(s)) + return NewTProtocolException(e) +} + +func (p *TSimpleJSONProtocol) OutputObjectBegin() error { + if e := p.OutputPreValue(); e != nil { + return e + } + if _, e := p.write(JSON_LBRACE); e != nil { + return NewTProtocolException(e) + } + p.dumpContext = append(p.dumpContext, int(_CONTEXT_IN_OBJECT_FIRST)) + return nil +} + +func (p *TSimpleJSONProtocol) OutputObjectEnd() error { + if _, e := p.write(JSON_RBRACE); e != nil { + return NewTProtocolException(e) + } + p.dumpContext = p.dumpContext[:len(p.dumpContext)-1] + if e := p.OutputPostValue(); e != nil { + return e + } + return nil +} + +func (p *TSimpleJSONProtocol) OutputListBegin() error { + if e := p.OutputPreValue(); e != nil { + return e + } + if _, e := p.write(JSON_LBRACKET); e != nil { + return NewTProtocolException(e) + } + p.dumpContext = append(p.dumpContext, int(_CONTEXT_IN_LIST_FIRST)) + return nil +} + +func (p *TSimpleJSONProtocol) OutputListEnd() error { + if _, e := p.write(JSON_RBRACKET); e != nil { + return NewTProtocolException(e) + } + p.dumpContext = p.dumpContext[:len(p.dumpContext)-1] + if e := p.OutputPostValue(); e != nil { + return e + } + return nil +} + +func (p *TSimpleJSONProtocol) OutputElemListBegin(elemType TType, size int) error { + if e := p.OutputListBegin(); e != nil { + return e + } + if e := p.WriteByte(int8(elemType)); e != nil { + return e + } + if e := p.WriteI64(int64(size)); e != nil { + return e + } + return nil +} + +func (p *TSimpleJSONProtocol) ParsePreValue() error { + if e := p.readNonSignificantWhitespace(); e != nil { + return NewTProtocolException(e) + } + cxt := _ParseContext(p.parseContextStack[len(p.parseContextStack)-1]) + b, _ := p.reader.Peek(1) + switch cxt { + case _CONTEXT_IN_LIST: + if len(b) > 0 { + switch b[0] { + case JSON_RBRACKET[0]: + return nil + case JSON_COMMA[0]: + p.reader.ReadByte() + if e := p.readNonSignificantWhitespace(); e != nil { + return NewTProtocolException(e) + } + return nil + default: + e := fmt.Errorf("Expected \"]\" or \",\" in list context, but found \"%s\"", string(b)) + return NewTProtocolExceptionWithType(INVALID_DATA, e) + } + } + break + case _CONTEXT_IN_OBJECT_NEXT_KEY: + if len(b) > 0 { + switch b[0] { + case JSON_RBRACE[0]: + return nil + case JSON_COMMA[0]: + p.reader.ReadByte() + if e := p.readNonSignificantWhitespace(); e != nil { + return NewTProtocolException(e) + } + return nil + default: + e := fmt.Errorf("Expected \"}\" or \",\" in object context, but found \"%s\"", string(b)) + return NewTProtocolExceptionWithType(INVALID_DATA, e) + } + } + break + case _CONTEXT_IN_OBJECT_NEXT_VALUE: + if len(b) > 0 { + switch b[0] { + case JSON_COLON[0]: + p.reader.ReadByte() + if e := p.readNonSignificantWhitespace(); e != nil { + return NewTProtocolException(e) + } + return nil + default: + e := fmt.Errorf("Expected \":\" in object context, but found \"%s\"", string(b)) + return NewTProtocolExceptionWithType(INVALID_DATA, e) + } + } + break + } + return nil +} + +func (p *TSimpleJSONProtocol) ParsePostValue() error { + if e := p.readNonSignificantWhitespace(); e != nil { + return NewTProtocolException(e) + } + cxt := _ParseContext(p.parseContextStack[len(p.parseContextStack)-1]) + switch cxt { + case _CONTEXT_IN_LIST_FIRST: + p.parseContextStack = p.parseContextStack[:len(p.parseContextStack)-1] + p.parseContextStack = append(p.parseContextStack, int(_CONTEXT_IN_LIST)) + break + case _CONTEXT_IN_OBJECT_FIRST, _CONTEXT_IN_OBJECT_NEXT_KEY: + p.parseContextStack = p.parseContextStack[:len(p.parseContextStack)-1] + p.parseContextStack = append(p.parseContextStack, int(_CONTEXT_IN_OBJECT_NEXT_VALUE)) + break + case _CONTEXT_IN_OBJECT_NEXT_VALUE: + p.parseContextStack = p.parseContextStack[:len(p.parseContextStack)-1] + p.parseContextStack = append(p.parseContextStack, int(_CONTEXT_IN_OBJECT_NEXT_KEY)) + break + } + return nil +} + +func (p *TSimpleJSONProtocol) readNonSignificantWhitespace() error { + for { + b, _ := p.reader.Peek(1) + if len(b) < 1 { + return nil + } + switch b[0] { + case ' ', '\r', '\n', '\t': + p.reader.ReadByte() + continue + default: + break + } + break + } + return nil +} + +func (p *TSimpleJSONProtocol) ParseStringBody() (string, error) { + line, err := p.reader.ReadString(JSON_QUOTE) + if err != nil { + return "", NewTProtocolException(err) + } + l := len(line) + // count number of escapes to see if we need to keep going + i := 1 + for ; i < l; i++ { + if line[l-i-1] != '\\' { + break + } + } + if i&0x01 == 1 { + v, ok := jsonUnquote(string(JSON_QUOTE) + line) + if !ok { + return "", NewTProtocolException(err) + } + return v, nil + } + s, err := p.ParseQuotedStringBody() + if err != nil { + return "", NewTProtocolException(err) + } + str := string(JSON_QUOTE) + line + s + v, ok := jsonUnquote(str) + if !ok { + e := fmt.Errorf("Unable to parse as JSON string %s", str) + return "", NewTProtocolExceptionWithType(INVALID_DATA, e) + } + return v, nil +} + +func (p *TSimpleJSONProtocol) ParseQuotedStringBody() (string, error) { + line, err := p.reader.ReadString(JSON_QUOTE) + if err != nil { + return "", NewTProtocolException(err) + } + l := len(line) + // count number of escapes to see if we need to keep going + i := 1 + for ; i < l; i++ { + if line[l-i-1] != '\\' { + break + } + } + if i&0x01 == 1 { + return line, nil + } + s, err := p.ParseQuotedStringBody() + if err != nil { + return "", NewTProtocolException(err) + } + v := line + s + return v, nil +} + +func (p *TSimpleJSONProtocol) ParseBase64EncodedBody() ([]byte, error) { + line, err := p.reader.ReadBytes(JSON_QUOTE) + if err != nil { + return line, NewTProtocolException(err) + } + line2 := line[0 : len(line)-1] + l := len(line2) + if (l % 4) != 0 { + pad := 4 - (l % 4) + fill := [...]byte{'=', '=', '='} + line2 = append(line2, fill[:pad]...) + l = len(line2) + } + output := make([]byte, base64.StdEncoding.DecodedLen(l)) + n, err := base64.StdEncoding.Decode(output, line2) + return output[0:n], NewTProtocolException(err) +} + +func (p *TSimpleJSONProtocol) ParseI64() (int64, bool, error) { + if err := p.ParsePreValue(); err != nil { + return 0, false, err + } + var value int64 + var isnull bool + if p.safePeekContains(JSON_NULL) { + p.reader.Read(make([]byte, len(JSON_NULL))) + isnull = true + } else { + num, err := p.readNumeric() + isnull = (num == nil) + if !isnull { + value = num.Int64() + } + if err != nil { + return value, isnull, err + } + } + return value, isnull, p.ParsePostValue() +} + +func (p *TSimpleJSONProtocol) ParseF64() (float64, bool, error) { + if err := p.ParsePreValue(); err != nil { + return 0, false, err + } + var value float64 + var isnull bool + if p.safePeekContains(JSON_NULL) { + p.reader.Read(make([]byte, len(JSON_NULL))) + isnull = true + } else { + num, err := p.readNumeric() + isnull = (num == nil) + if !isnull { + value = num.Float64() + } + if err != nil { + return value, isnull, err + } + } + return value, isnull, p.ParsePostValue() +} + +func (p *TSimpleJSONProtocol) ParseObjectStart() (bool, error) { + if err := p.ParsePreValue(); err != nil { + return false, err + } + var b []byte + b, err := p.reader.Peek(1) + if err != nil { + return false, err + } + if len(b) > 0 && b[0] == JSON_LBRACE[0] { + p.reader.ReadByte() + p.parseContextStack = append(p.parseContextStack, int(_CONTEXT_IN_OBJECT_FIRST)) + return false, nil + } else if p.safePeekContains(JSON_NULL) { + return true, nil + } + e := fmt.Errorf("Expected '{' or null, but found '%s'", string(b)) + return false, NewTProtocolExceptionWithType(INVALID_DATA, e) +} + +func (p *TSimpleJSONProtocol) ParseObjectEnd() error { + if isNull, err := p.readIfNull(); isNull || err != nil { + return err + } + cxt := _ParseContext(p.parseContextStack[len(p.parseContextStack)-1]) + if (cxt != _CONTEXT_IN_OBJECT_FIRST) && (cxt != _CONTEXT_IN_OBJECT_NEXT_KEY) { + e := fmt.Errorf("Expected to be in the Object Context, but not in Object Context (%d)", cxt) + return NewTProtocolExceptionWithType(INVALID_DATA, e) + } + line, err := p.reader.ReadString(JSON_RBRACE[0]) + if err != nil { + return NewTProtocolException(err) + } + for _, char := range line { + switch char { + default: + e := fmt.Errorf("Expecting end of object \"}\", but found: \"%s\"", line) + return NewTProtocolExceptionWithType(INVALID_DATA, e) + case ' ', '\n', '\r', '\t', '}': + break + } + } + p.parseContextStack = p.parseContextStack[:len(p.parseContextStack)-1] + return p.ParsePostValue() +} + +func (p *TSimpleJSONProtocol) ParseListBegin() (isNull bool, err error) { + if e := p.ParsePreValue(); e != nil { + return false, e + } + var b []byte + b, err = p.reader.Peek(1) + if err != nil { + return false, err + } + if len(b) >= 1 && b[0] == JSON_LBRACKET[0] { + p.parseContextStack = append(p.parseContextStack, int(_CONTEXT_IN_LIST_FIRST)) + p.reader.ReadByte() + isNull = false + } else if p.safePeekContains(JSON_NULL) { + isNull = true + } else { + err = fmt.Errorf("Expected \"null\" or \"[\", received %q", b) + } + return isNull, NewTProtocolExceptionWithType(INVALID_DATA, err) +} + +func (p *TSimpleJSONProtocol) ParseElemListBegin() (elemType TType, size int, e error) { + if isNull, e := p.ParseListBegin(); isNull || e != nil { + return VOID, 0, e + } + bElemType, err := p.ReadByte() + elemType = TType(bElemType) + if err != nil { + return elemType, size, err + } + nSize, err2 := p.ReadI64() + size = int(nSize) + return elemType, size, err2 +} + +func (p *TSimpleJSONProtocol) ParseListEnd() error { + if isNull, err := p.readIfNull(); isNull || err != nil { + return err + } + cxt := _ParseContext(p.parseContextStack[len(p.parseContextStack)-1]) + if cxt != _CONTEXT_IN_LIST { + e := fmt.Errorf("Expected to be in the List Context, but not in List Context (%d)", cxt) + return NewTProtocolExceptionWithType(INVALID_DATA, e) + } + line, err := p.reader.ReadString(JSON_RBRACKET[0]) + if err != nil { + return NewTProtocolException(err) + } + for _, char := range line { + switch char { + default: + e := fmt.Errorf("Expecting end of list \"]\", but found: \"%s\"", line) + return NewTProtocolExceptionWithType(INVALID_DATA, e) + case ' ', '\n', '\r', '\t', rune(JSON_RBRACKET[0]): + break + } + } + p.parseContextStack = p.parseContextStack[:len(p.parseContextStack)-1] + if _ParseContext(p.parseContextStack[len(p.parseContextStack)-1]) == _CONTEXT_IN_TOPLEVEL { + return nil + } + return p.ParsePostValue() +} + +func (p *TSimpleJSONProtocol) readSingleValue() (interface{}, TType, error) { + e := p.readNonSignificantWhitespace() + if e != nil { + return nil, VOID, NewTProtocolException(e) + } + b, e := p.reader.Peek(1) + if len(b) > 0 { + c := b[0] + switch c { + case JSON_NULL[0]: + buf := make([]byte, len(JSON_NULL)) + _, e := p.reader.Read(buf) + if e != nil { + return nil, VOID, NewTProtocolException(e) + } + if string(JSON_NULL) != string(buf) { + e = mismatch(string(JSON_NULL), string(buf)) + return nil, VOID, NewTProtocolExceptionWithType(INVALID_DATA, e) + } + return nil, VOID, nil + case JSON_QUOTE: + p.reader.ReadByte() + v, e := p.ParseStringBody() + if e != nil { + return v, UTF8, NewTProtocolException(e) + } + if v == JSON_INFINITY { + return INFINITY, DOUBLE, nil + } else if v == JSON_NEGATIVE_INFINITY { + return NEGATIVE_INFINITY, DOUBLE, nil + } else if v == JSON_NAN { + return NAN, DOUBLE, nil + } + return v, UTF8, nil + case JSON_TRUE[0]: + buf := make([]byte, len(JSON_TRUE)) + _, e := p.reader.Read(buf) + if e != nil { + return true, BOOL, NewTProtocolException(e) + } + if string(JSON_TRUE) != string(buf) { + e := mismatch(string(JSON_TRUE), string(buf)) + return true, BOOL, NewTProtocolExceptionWithType(INVALID_DATA, e) + } + return true, BOOL, nil + case JSON_FALSE[0]: + buf := make([]byte, len(JSON_FALSE)) + _, e := p.reader.Read(buf) + if e != nil { + return false, BOOL, NewTProtocolException(e) + } + if string(JSON_FALSE) != string(buf) { + e := mismatch(string(JSON_FALSE), string(buf)) + return false, BOOL, NewTProtocolExceptionWithType(INVALID_DATA, e) + } + return false, BOOL, nil + case JSON_LBRACKET[0]: + _, e := p.reader.ReadByte() + return make([]interface{}, 0), LIST, NewTProtocolException(e) + case JSON_LBRACE[0]: + _, e := p.reader.ReadByte() + return make(map[string]interface{}), STRUCT, NewTProtocolException(e) + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'e', 'E', '.', '+', '-', JSON_INFINITY[0], JSON_NAN[0]: + // assume numeric + v, e := p.readNumeric() + return v, DOUBLE, e + default: + e := fmt.Errorf("Expected element in list but found '%s' while parsing JSON.", string(c)) + return nil, VOID, NewTProtocolExceptionWithType(INVALID_DATA, e) + } + } + e = fmt.Errorf("Cannot read a single element while parsing JSON.") + return nil, VOID, NewTProtocolExceptionWithType(INVALID_DATA, e) + +} + +func (p *TSimpleJSONProtocol) readIfNull() (bool, error) { + cont := true + for cont { + b, _ := p.reader.Peek(1) + if len(b) < 1 { + return false, nil + } + switch b[0] { + default: + return false, nil + case JSON_NULL[0]: + cont = false + break + case ' ', '\n', '\r', '\t': + p.reader.ReadByte() + break + } + } + if p.safePeekContains(JSON_NULL) { + p.reader.Read(make([]byte, len(JSON_NULL))) + return true, nil + } + return false, nil +} + +func (p *TSimpleJSONProtocol) readQuoteIfNext() { + b, _ := p.reader.Peek(1) + if len(b) > 0 && b[0] == JSON_QUOTE { + p.reader.ReadByte() + } +} + +func (p *TSimpleJSONProtocol) readNumeric() (Numeric, error) { + isNull, err := p.readIfNull() + if isNull || err != nil { + return NUMERIC_NULL, err + } + hasDecimalPoint := false + nextCanBeSign := true + hasE := false + MAX_LEN := 40 + buf := bytes.NewBuffer(make([]byte, 0, MAX_LEN)) + continueFor := true + inQuotes := false + for continueFor { + c, err := p.reader.ReadByte() + if err != nil { + if err == io.EOF { + break + } + return NUMERIC_NULL, NewTProtocolException(err) + } + switch c { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + buf.WriteByte(c) + nextCanBeSign = false + case '.': + if hasDecimalPoint { + e := fmt.Errorf("Unable to parse number with multiple decimal points '%s.'", buf.String()) + return NUMERIC_NULL, NewTProtocolExceptionWithType(INVALID_DATA, e) + } + if hasE { + e := fmt.Errorf("Unable to parse number with decimal points in the exponent '%s.'", buf.String()) + return NUMERIC_NULL, NewTProtocolExceptionWithType(INVALID_DATA, e) + } + buf.WriteByte(c) + hasDecimalPoint, nextCanBeSign = true, false + case 'e', 'E': + if hasE { + e := fmt.Errorf("Unable to parse number with multiple exponents '%s%c'", buf.String(), c) + return NUMERIC_NULL, NewTProtocolExceptionWithType(INVALID_DATA, e) + } + buf.WriteByte(c) + hasE, nextCanBeSign = true, true + case '-', '+': + if !nextCanBeSign { + e := fmt.Errorf("Negative sign within number") + return NUMERIC_NULL, NewTProtocolExceptionWithType(INVALID_DATA, e) + } + buf.WriteByte(c) + nextCanBeSign = false + case ' ', 0, '\t', '\n', '\r', JSON_RBRACE[0], JSON_RBRACKET[0], JSON_COMMA[0], JSON_COLON[0]: + p.reader.UnreadByte() + continueFor = false + case JSON_NAN[0]: + if buf.Len() == 0 { + buffer := make([]byte, len(JSON_NAN)) + buffer[0] = c + _, e := p.reader.Read(buffer[1:]) + if e != nil { + return NUMERIC_NULL, NewTProtocolException(e) + } + if JSON_NAN != string(buffer) { + e := mismatch(JSON_NAN, string(buffer)) + return NUMERIC_NULL, NewTProtocolExceptionWithType(INVALID_DATA, e) + } + if inQuotes { + p.readQuoteIfNext() + } + return NAN, nil + } else { + e := fmt.Errorf("Unable to parse number starting with character '%c'", c) + return NUMERIC_NULL, NewTProtocolExceptionWithType(INVALID_DATA, e) + } + case JSON_INFINITY[0]: + if buf.Len() == 0 || (buf.Len() == 1 && buf.Bytes()[0] == '+') { + buffer := make([]byte, len(JSON_INFINITY)) + buffer[0] = c + _, e := p.reader.Read(buffer[1:]) + if e != nil { + return NUMERIC_NULL, NewTProtocolException(e) + } + if JSON_INFINITY != string(buffer) { + e := mismatch(JSON_INFINITY, string(buffer)) + return NUMERIC_NULL, NewTProtocolExceptionWithType(INVALID_DATA, e) + } + if inQuotes { + p.readQuoteIfNext() + } + return INFINITY, nil + } else if buf.Len() == 1 && buf.Bytes()[0] == JSON_NEGATIVE_INFINITY[0] { + buffer := make([]byte, len(JSON_NEGATIVE_INFINITY)) + buffer[0] = JSON_NEGATIVE_INFINITY[0] + buffer[1] = c + _, e := p.reader.Read(buffer[2:]) + if e != nil { + return NUMERIC_NULL, NewTProtocolException(e) + } + if JSON_NEGATIVE_INFINITY != string(buffer) { + e := mismatch(JSON_NEGATIVE_INFINITY, string(buffer)) + return NUMERIC_NULL, NewTProtocolExceptionWithType(INVALID_DATA, e) + } + if inQuotes { + p.readQuoteIfNext() + } + return NEGATIVE_INFINITY, nil + } else { + e := fmt.Errorf("Unable to parse number starting with character '%c' due to existing buffer %s", c, buf.String()) + return NUMERIC_NULL, NewTProtocolExceptionWithType(INVALID_DATA, e) + } + case JSON_QUOTE: + if !inQuotes { + inQuotes = true + } else { + break + } + default: + e := fmt.Errorf("Unable to parse number starting with character '%c'", c) + return NUMERIC_NULL, NewTProtocolExceptionWithType(INVALID_DATA, e) + } + } + if buf.Len() == 0 { + e := fmt.Errorf("Unable to parse number from empty string ''") + return NUMERIC_NULL, NewTProtocolExceptionWithType(INVALID_DATA, e) + } + return NewNumericFromJSONString(buf.String(), false), nil +} + +// Safely peeks into the buffer, reading only what is necessary +func (p *TSimpleJSONProtocol) safePeekContains(b []byte) bool { + for i := 0; i < len(b); i++ { + a, _ := p.reader.Peek(i + 1) + if len(a) == 0 || a[i] != b[i] { + return false + } + } + return true +} + +// Reset the context stack to its initial state. +func (p *TSimpleJSONProtocol) resetContextStack() { + p.parseContextStack = []int{int(_CONTEXT_IN_TOPLEVEL)} + p.dumpContext = []int{int(_CONTEXT_IN_TOPLEVEL)} +} + +func (p *TSimpleJSONProtocol) write(b []byte) (int, error) { + n, err := p.writer.Write(b) + if err != nil { + p.writer.Reset(p.trans) // THRIFT-3735 + } + return n, err +} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/transport.go b/vendor/github.com/uber/jaeger-client-go/thrift/transport.go new file mode 100644 index 0000000000..453899651f --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/thrift/transport.go @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 thrift + +import ( + "errors" + "io" +) + +var errTransportInterrupted = errors.New("Transport Interrupted") + +type Flusher interface { + Flush() (err error) +} + +type ReadSizeProvider interface { + RemainingBytes() (num_bytes uint64) +} + + +// Encapsulates the I/O layer +type TTransport interface { + io.ReadWriteCloser + Flusher + ReadSizeProvider + + // Opens the transport for communication + Open() error + + // Returns true if the transport is open + IsOpen() bool +} + +type stringWriter interface { + WriteString(s string) (n int, err error) +} + + +// This is "enchanced" transport with extra capabilities. You need to use one of these +// to construct protocol. +// Notably, TSocket does not implement this interface, and it is always a mistake to use +// TSocket directly in protocol. +type TRichTransport interface { + io.ReadWriter + io.ByteReader + io.ByteWriter + stringWriter + Flusher + ReadSizeProvider +} + diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/transport_exception.go b/vendor/github.com/uber/jaeger-client-go/thrift/transport_exception.go new file mode 100644 index 0000000000..9505b44612 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/thrift/transport_exception.go @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 thrift + +import ( + "errors" + "io" +) + +type timeoutable interface { + Timeout() bool +} + +// Thrift Transport exception +type TTransportException interface { + TException + TypeId() int + Err() error +} + +const ( + UNKNOWN_TRANSPORT_EXCEPTION = 0 + NOT_OPEN = 1 + ALREADY_OPEN = 2 + TIMED_OUT = 3 + END_OF_FILE = 4 +) + +type tTransportException struct { + typeId int + err error +} + +func (p *tTransportException) TypeId() int { + return p.typeId +} + +func (p *tTransportException) Error() string { + return p.err.Error() +} + +func (p *tTransportException) Err() error { + return p.err +} + +func NewTTransportException(t int, e string) TTransportException { + return &tTransportException{typeId: t, err: errors.New(e)} +} + +func NewTTransportExceptionFromError(e error) TTransportException { + if e == nil { + return nil + } + + if t, ok := e.(TTransportException); ok { + return t + } + + switch v := e.(type) { + case TTransportException: + return v + case timeoutable: + if v.Timeout() { + return &tTransportException{typeId: TIMED_OUT, err: e} + } + } + + if e == io.EOF { + return &tTransportException{typeId: END_OF_FILE, err: e} + } + + return &tTransportException{typeId: UNKNOWN_TRANSPORT_EXCEPTION, err: e} +} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/transport_factory.go b/vendor/github.com/uber/jaeger-client-go/thrift/transport_factory.go new file mode 100644 index 0000000000..533d1b4375 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/thrift/transport_factory.go @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 thrift + +// Factory class used to create wrapped instance of Transports. +// This is used primarily in servers, which get Transports from +// a ServerTransport and then may want to mutate them (i.e. create +// a BufferedTransport from the underlying base transport) +type TTransportFactory interface { + GetTransport(trans TTransport) TTransport +} + +type tTransportFactory struct{} + +// Return a wrapped instance of the base Transport. +func (p *tTransportFactory) GetTransport(trans TTransport) TTransport { + return trans +} + +func NewTTransportFactory() TTransportFactory { + return &tTransportFactory{} +} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/type.go b/vendor/github.com/uber/jaeger-client-go/thrift/type.go new file mode 100644 index 0000000000..4292ffcadb --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/thrift/type.go @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 thrift + +// Type constants in the Thrift protocol +type TType byte + +const ( + STOP = 0 + VOID = 1 + BOOL = 2 + BYTE = 3 + I08 = 3 + DOUBLE = 4 + I16 = 6 + I32 = 8 + I64 = 10 + STRING = 11 + UTF7 = 11 + STRUCT = 12 + MAP = 13 + SET = 14 + LIST = 15 + UTF8 = 16 + UTF16 = 17 + //BINARY = 18 wrong and unusued +) + +var typeNames = map[int]string{ + STOP: "STOP", + VOID: "VOID", + BOOL: "BOOL", + BYTE: "BYTE", + DOUBLE: "DOUBLE", + I16: "I16", + I32: "I32", + I64: "I64", + STRING: "STRING", + STRUCT: "STRUCT", + MAP: "MAP", + SET: "SET", + LIST: "LIST", + UTF8: "UTF8", + UTF16: "UTF16", +} + +func (p TType) String() string { + if s, ok := typeNames[int(p)]; ok { + return s + } + return "Unknown" +} diff --git a/vendor/github.com/uber/jaeger-client-go/tracer.go b/vendor/github.com/uber/jaeger-client-go/tracer.go new file mode 100644 index 0000000000..198c32eb4f --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/tracer.go @@ -0,0 +1,431 @@ +// Copyright (c) 2017-2018 Uber Technologies, Inc. +// +// 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 jaeger + +import ( + "fmt" + "io" + "os" + "reflect" + "strconv" + "sync" + "time" + + "github.com/opentracing/opentracing-go" + "github.com/opentracing/opentracing-go/ext" + + "github.com/uber/jaeger-client-go/internal/baggage" + "github.com/uber/jaeger-client-go/internal/throttler" + "github.com/uber/jaeger-client-go/log" + "github.com/uber/jaeger-client-go/utils" +) + +// Tracer implements opentracing.Tracer. +type Tracer struct { + serviceName string + hostIPv4 uint32 // this is for zipkin endpoint conversion + + sampler Sampler + reporter Reporter + metrics Metrics + logger log.Logger + + timeNow func() time.Time + randomNumber func() uint64 + + options struct { + poolSpans bool + gen128Bit bool // whether to generate 128bit trace IDs + zipkinSharedRPCSpan bool + highTraceIDGenerator func() uint64 // custom high trace ID generator + maxTagValueLength int + // more options to come + } + // pool for Span objects + spanPool sync.Pool + + injectors map[interface{}]Injector + extractors map[interface{}]Extractor + + observer compositeObserver + + tags []Tag + process Process + + baggageRestrictionManager baggage.RestrictionManager + baggageSetter *baggageSetter + + debugThrottler throttler.Throttler +} + +// NewTracer creates Tracer implementation that reports tracing to Jaeger. +// The returned io.Closer can be used in shutdown hooks to ensure that the internal +// queue of the Reporter is drained and all buffered spans are submitted to collectors. +func NewTracer( + serviceName string, + sampler Sampler, + reporter Reporter, + options ...TracerOption, +) (opentracing.Tracer, io.Closer) { + t := &Tracer{ + serviceName: serviceName, + sampler: sampler, + reporter: reporter, + injectors: make(map[interface{}]Injector), + extractors: make(map[interface{}]Extractor), + metrics: *NewNullMetrics(), + spanPool: sync.Pool{New: func() interface{} { + return &Span{} + }}, + } + + for _, option := range options { + option(t) + } + + // register default injectors/extractors unless they are already provided via options + textPropagator := newTextMapPropagator(getDefaultHeadersConfig(), t.metrics) + t.addCodec(opentracing.TextMap, textPropagator, textPropagator) + + httpHeaderPropagator := newHTTPHeaderPropagator(getDefaultHeadersConfig(), t.metrics) + t.addCodec(opentracing.HTTPHeaders, httpHeaderPropagator, httpHeaderPropagator) + + binaryPropagator := newBinaryPropagator(t) + t.addCodec(opentracing.Binary, binaryPropagator, binaryPropagator) + + // TODO remove after TChannel supports OpenTracing + interopPropagator := &jaegerTraceContextPropagator{tracer: t} + t.addCodec(SpanContextFormat, interopPropagator, interopPropagator) + + zipkinPropagator := &zipkinPropagator{tracer: t} + t.addCodec(ZipkinSpanFormat, zipkinPropagator, zipkinPropagator) + + if t.baggageRestrictionManager != nil { + t.baggageSetter = newBaggageSetter(t.baggageRestrictionManager, &t.metrics) + } else { + t.baggageSetter = newBaggageSetter(baggage.NewDefaultRestrictionManager(0), &t.metrics) + } + if t.debugThrottler == nil { + t.debugThrottler = throttler.DefaultThrottler{} + } + + if t.randomNumber == nil { + rng := utils.NewRand(time.Now().UnixNano()) + t.randomNumber = func() uint64 { + return uint64(rng.Int63()) + } + } + if t.timeNow == nil { + t.timeNow = time.Now + } + if t.logger == nil { + t.logger = log.NullLogger + } + // Set tracer-level tags + t.tags = append(t.tags, Tag{key: JaegerClientVersionTagKey, value: JaegerClientVersion}) + if hostname, err := os.Hostname(); err == nil { + t.tags = append(t.tags, Tag{key: TracerHostnameTagKey, value: hostname}) + } + if ip, err := utils.HostIP(); err == nil { + t.tags = append(t.tags, Tag{key: TracerIPTagKey, value: ip.String()}) + t.hostIPv4 = utils.PackIPAsUint32(ip) + } else { + t.logger.Error("Unable to determine this host's IP address: " + err.Error()) + } + + if t.options.gen128Bit { + if t.options.highTraceIDGenerator == nil { + t.options.highTraceIDGenerator = t.randomNumber + } + } else if t.options.highTraceIDGenerator != nil { + t.logger.Error("Overriding high trace ID generator but not generating " + + "128 bit trace IDs, consider enabling the \"Gen128Bit\" option") + } + if t.options.maxTagValueLength == 0 { + t.options.maxTagValueLength = DefaultMaxTagValueLength + } + t.process = Process{ + Service: serviceName, + UUID: strconv.FormatUint(t.randomNumber(), 16), + Tags: t.tags, + } + if throttler, ok := t.debugThrottler.(ProcessSetter); ok { + throttler.SetProcess(t.process) + } + + return t, t +} + +// addCodec adds registers injector and extractor for given propagation format if not already defined. +func (t *Tracer) addCodec(format interface{}, injector Injector, extractor Extractor) { + if _, ok := t.injectors[format]; !ok { + t.injectors[format] = injector + } + if _, ok := t.extractors[format]; !ok { + t.extractors[format] = extractor + } +} + +// StartSpan implements StartSpan() method of opentracing.Tracer. +func (t *Tracer) StartSpan( + operationName string, + options ...opentracing.StartSpanOption, +) opentracing.Span { + sso := opentracing.StartSpanOptions{} + for _, o := range options { + o.Apply(&sso) + } + return t.startSpanWithOptions(operationName, sso) +} + +func (t *Tracer) startSpanWithOptions( + operationName string, + options opentracing.StartSpanOptions, +) opentracing.Span { + if options.StartTime.IsZero() { + options.StartTime = t.timeNow() + } + + // Predicate whether the given span context is a valid reference + // which may be used as parent / debug ID / baggage items source + isValidReference := func(ctx SpanContext) bool { + return ctx.IsValid() || ctx.isDebugIDContainerOnly() || len(ctx.baggage) != 0 + } + + var references []Reference + var parent SpanContext + var hasParent bool // need this because `parent` is a value, not reference + for _, ref := range options.References { + ctx, ok := ref.ReferencedContext.(SpanContext) + if !ok { + t.logger.Error(fmt.Sprintf( + "Reference contains invalid type of SpanReference: %s", + reflect.ValueOf(ref.ReferencedContext))) + continue + } + if !isValidReference(ctx) { + continue + } + references = append(references, Reference{Type: ref.Type, Context: ctx}) + if !hasParent { + parent = ctx + hasParent = ref.Type == opentracing.ChildOfRef + } + } + if !hasParent && isValidReference(parent) { + // If ChildOfRef wasn't found but a FollowFromRef exists, use the context from + // the FollowFromRef as the parent + hasParent = true + } + + rpcServer := false + if v, ok := options.Tags[ext.SpanKindRPCServer.Key]; ok { + rpcServer = (v == ext.SpanKindRPCServerEnum || v == string(ext.SpanKindRPCServerEnum)) + } + + var samplerTags []Tag + var ctx SpanContext + newTrace := false + if !hasParent || !parent.IsValid() { + newTrace = true + ctx.traceID.Low = t.randomID() + if t.options.gen128Bit { + ctx.traceID.High = t.options.highTraceIDGenerator() + } + ctx.spanID = SpanID(ctx.traceID.Low) + ctx.parentID = 0 + ctx.flags = byte(0) + if hasParent && parent.isDebugIDContainerOnly() && t.isDebugAllowed(operationName) { + ctx.flags |= (flagSampled | flagDebug) + samplerTags = []Tag{{key: JaegerDebugHeader, value: parent.debugID}} + } else if sampled, tags := t.sampler.IsSampled(ctx.traceID, operationName); sampled { + ctx.flags |= flagSampled + samplerTags = tags + } + } else { + ctx.traceID = parent.traceID + if rpcServer && t.options.zipkinSharedRPCSpan { + // Support Zipkin's one-span-per-RPC model + ctx.spanID = parent.spanID + ctx.parentID = parent.parentID + } else { + ctx.spanID = SpanID(t.randomID()) + ctx.parentID = parent.spanID + } + ctx.flags = parent.flags + } + if hasParent { + // copy baggage items + if l := len(parent.baggage); l > 0 { + ctx.baggage = make(map[string]string, len(parent.baggage)) + for k, v := range parent.baggage { + ctx.baggage[k] = v + } + } + } + + sp := t.newSpan() + sp.context = ctx + sp.observer = t.observer.OnStartSpan(sp, operationName, options) + return t.startSpanInternal( + sp, + operationName, + options.StartTime, + samplerTags, + options.Tags, + newTrace, + rpcServer, + references, + ) +} + +// Inject implements Inject() method of opentracing.Tracer +func (t *Tracer) Inject(ctx opentracing.SpanContext, format interface{}, carrier interface{}) error { + c, ok := ctx.(SpanContext) + if !ok { + return opentracing.ErrInvalidSpanContext + } + if injector, ok := t.injectors[format]; ok { + return injector.Inject(c, carrier) + } + return opentracing.ErrUnsupportedFormat +} + +// Extract implements Extract() method of opentracing.Tracer +func (t *Tracer) Extract( + format interface{}, + carrier interface{}, +) (opentracing.SpanContext, error) { + if extractor, ok := t.extractors[format]; ok { + return extractor.Extract(carrier) + } + return nil, opentracing.ErrUnsupportedFormat +} + +// Close releases all resources used by the Tracer and flushes any remaining buffered spans. +func (t *Tracer) Close() error { + t.reporter.Close() + t.sampler.Close() + if mgr, ok := t.baggageRestrictionManager.(io.Closer); ok { + mgr.Close() + } + if throttler, ok := t.debugThrottler.(io.Closer); ok { + throttler.Close() + } + return nil +} + +// Tags returns a slice of tracer-level tags. +func (t *Tracer) Tags() []opentracing.Tag { + tags := make([]opentracing.Tag, len(t.tags)) + for i, tag := range t.tags { + tags[i] = opentracing.Tag{Key: tag.key, Value: tag.value} + } + return tags +} + +// newSpan returns an instance of a clean Span object. +// If options.PoolSpans is true, the spans are retrieved from an object pool. +func (t *Tracer) newSpan() *Span { + if !t.options.poolSpans { + return &Span{} + } + sp := t.spanPool.Get().(*Span) + sp.context = emptyContext + sp.tracer = nil + sp.tags = nil + sp.logs = nil + return sp +} + +func (t *Tracer) startSpanInternal( + sp *Span, + operationName string, + startTime time.Time, + internalTags []Tag, + tags opentracing.Tags, + newTrace bool, + rpcServer bool, + references []Reference, +) *Span { + sp.tracer = t + sp.operationName = operationName + sp.startTime = startTime + sp.duration = 0 + sp.references = references + sp.firstInProcess = rpcServer || sp.context.parentID == 0 + if len(tags) > 0 || len(internalTags) > 0 { + sp.tags = make([]Tag, len(internalTags), len(tags)+len(internalTags)) + copy(sp.tags, internalTags) + for k, v := range tags { + sp.observer.OnSetTag(k, v) + if k == string(ext.SamplingPriority) && !setSamplingPriority(sp, v) { + continue + } + sp.setTagNoLocking(k, v) + } + } + // emit metrics + if sp.context.IsSampled() { + t.metrics.SpansStartedSampled.Inc(1) + if newTrace { + // We cannot simply check for parentID==0 because in Zipkin model the + // server-side RPC span has the exact same trace/span/parent IDs as the + // calling client-side span, but obviously the server side span is + // no longer a root span of the trace. + t.metrics.TracesStartedSampled.Inc(1) + } else if sp.firstInProcess { + t.metrics.TracesJoinedSampled.Inc(1) + } + } else { + t.metrics.SpansStartedNotSampled.Inc(1) + if newTrace { + t.metrics.TracesStartedNotSampled.Inc(1) + } else if sp.firstInProcess { + t.metrics.TracesJoinedNotSampled.Inc(1) + } + } + return sp +} + +func (t *Tracer) reportSpan(sp *Span) { + t.metrics.SpansFinished.Inc(1) + if sp.context.IsSampled() { + t.reporter.Report(sp) + } + if t.options.poolSpans { + t.spanPool.Put(sp) + } +} + +// randomID generates a random trace/span ID, using tracer.random() generator. +// It never returns 0. +func (t *Tracer) randomID() uint64 { + val := t.randomNumber() + for val == 0 { + val = t.randomNumber() + } + return val +} + +// (NB) span must hold the lock before making this call +func (t *Tracer) setBaggage(sp *Span, key, value string) { + t.baggageSetter.setBaggage(sp, key, value) +} + +// (NB) span must hold the lock before making this call +func (t *Tracer) isDebugAllowed(operation string) bool { + return t.debugThrottler.IsAllowed(operation) +} diff --git a/vendor/github.com/uber/jaeger-client-go/tracer_options.go b/vendor/github.com/uber/jaeger-client-go/tracer_options.go new file mode 100644 index 0000000000..a90265f031 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/tracer_options.go @@ -0,0 +1,159 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 jaeger + +import ( + "time" + + "github.com/opentracing/opentracing-go" + + "github.com/uber/jaeger-client-go/internal/baggage" + "github.com/uber/jaeger-client-go/internal/throttler" +) + +// TracerOption is a function that sets some option on the tracer +type TracerOption func(tracer *Tracer) + +// TracerOptions is a factory for all available TracerOption's +var TracerOptions tracerOptions + +type tracerOptions struct{} + +// Metrics creates a TracerOption that initializes Metrics on the tracer, +// which is used to emit statistics. +func (tracerOptions) Metrics(m *Metrics) TracerOption { + return func(tracer *Tracer) { + tracer.metrics = *m + } +} + +// Logger creates a TracerOption that gives the tracer a Logger. +func (tracerOptions) Logger(logger Logger) TracerOption { + return func(tracer *Tracer) { + tracer.logger = logger + } +} + +func (tracerOptions) CustomHeaderKeys(headerKeys *HeadersConfig) TracerOption { + return func(tracer *Tracer) { + if headerKeys == nil { + return + } + textPropagator := newTextMapPropagator(headerKeys.applyDefaults(), tracer.metrics) + tracer.addCodec(opentracing.TextMap, textPropagator, textPropagator) + + httpHeaderPropagator := newHTTPHeaderPropagator(headerKeys.applyDefaults(), tracer.metrics) + tracer.addCodec(opentracing.HTTPHeaders, httpHeaderPropagator, httpHeaderPropagator) + } +} + +// TimeNow creates a TracerOption that gives the tracer a function +// used to generate timestamps for spans. +func (tracerOptions) TimeNow(timeNow func() time.Time) TracerOption { + return func(tracer *Tracer) { + tracer.timeNow = timeNow + } +} + +// RandomNumber creates a TracerOption that gives the tracer +// a thread-safe random number generator function for generating trace IDs. +func (tracerOptions) RandomNumber(randomNumber func() uint64) TracerOption { + return func(tracer *Tracer) { + tracer.randomNumber = randomNumber + } +} + +// PoolSpans creates a TracerOption that tells the tracer whether it should use +// an object pool to minimize span allocations. +// This should be used with care, only if the service is not running any async tasks +// that can access parent spans after those spans have been finished. +func (tracerOptions) PoolSpans(poolSpans bool) TracerOption { + return func(tracer *Tracer) { + tracer.options.poolSpans = poolSpans + } +} + +// Deprecated: HostIPv4 creates a TracerOption that identifies the current service/process. +// If not set, the factory method will obtain the current IP address. +// The TracerOption is deprecated; the tracer will attempt to automatically detect the IP. +func (tracerOptions) HostIPv4(hostIPv4 uint32) TracerOption { + return func(tracer *Tracer) { + tracer.hostIPv4 = hostIPv4 + } +} + +func (tracerOptions) Injector(format interface{}, injector Injector) TracerOption { + return func(tracer *Tracer) { + tracer.injectors[format] = injector + } +} + +func (tracerOptions) Extractor(format interface{}, extractor Extractor) TracerOption { + return func(tracer *Tracer) { + tracer.extractors[format] = extractor + } +} + +func (t tracerOptions) Observer(observer Observer) TracerOption { + return t.ContribObserver(&oldObserver{obs: observer}) +} + +func (tracerOptions) ContribObserver(observer ContribObserver) TracerOption { + return func(tracer *Tracer) { + tracer.observer.append(observer) + } +} + +func (tracerOptions) Gen128Bit(gen128Bit bool) TracerOption { + return func(tracer *Tracer) { + tracer.options.gen128Bit = gen128Bit + } +} + +func (tracerOptions) HighTraceIDGenerator(highTraceIDGenerator func() uint64) TracerOption { + return func(tracer *Tracer) { + tracer.options.highTraceIDGenerator = highTraceIDGenerator + } +} + +func (tracerOptions) MaxTagValueLength(maxTagValueLength int) TracerOption { + return func(tracer *Tracer) { + tracer.options.maxTagValueLength = maxTagValueLength + } +} + +func (tracerOptions) ZipkinSharedRPCSpan(zipkinSharedRPCSpan bool) TracerOption { + return func(tracer *Tracer) { + tracer.options.zipkinSharedRPCSpan = zipkinSharedRPCSpan + } +} + +func (tracerOptions) Tag(key string, value interface{}) TracerOption { + return func(tracer *Tracer) { + tracer.tags = append(tracer.tags, Tag{key: key, value: value}) + } +} + +func (tracerOptions) BaggageRestrictionManager(mgr baggage.RestrictionManager) TracerOption { + return func(tracer *Tracer) { + tracer.baggageRestrictionManager = mgr + } +} + +func (tracerOptions) DebugThrottler(throttler throttler.Throttler) TracerOption { + return func(tracer *Tracer) { + tracer.debugThrottler = throttler + } +} diff --git a/vendor/github.com/uber/jaeger-client-go/transport.go b/vendor/github.com/uber/jaeger-client-go/transport.go new file mode 100644 index 0000000000..c5f5b19551 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/transport.go @@ -0,0 +1,38 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 jaeger + +import ( + "io" +) + +// Transport abstracts the method of sending spans out of process. +// Implementations are NOT required to be thread-safe; the RemoteReporter +// is expected to only call methods on the Transport from the same go-routine. +type Transport interface { + // Append converts the span to the wire representation and adds it + // to sender's internal buffer. If the buffer exceeds its designated + // size, the transport should call Flush() and return the number of spans + // flushed, otherwise return 0. If error is returned, the returned number + // of spans is treated as failed span, and reported to metrics accordingly. + Append(span *Span) (int, error) + + // Flush submits the internal buffer to the remote server. It returns the + // number of spans flushed. If error is returned, the returned number of + // spans is treated as failed span, and reported to metrics accordingly. + Flush() (int, error) + + io.Closer +} diff --git a/vendor/github.com/uber/jaeger-client-go/transport_udp.go b/vendor/github.com/uber/jaeger-client-go/transport_udp.go new file mode 100644 index 0000000000..7b9ccf9374 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/transport_udp.go @@ -0,0 +1,131 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 jaeger + +import ( + "errors" + "fmt" + + "github.com/uber/jaeger-client-go/thrift" + + j "github.com/uber/jaeger-client-go/thrift-gen/jaeger" + "github.com/uber/jaeger-client-go/utils" +) + +// Empirically obtained constant for how many bytes in the message are used for envelope. +// The total datagram size is: +// sizeof(Span) * numSpans + processByteSize + emitBatchOverhead <= maxPacketSize +// There is a unit test `TestEmitBatchOverhead` that validates this number. +// Note that due to the use of Compact Thrift protocol, overhead grows with the number of spans +// in the batch, because the length of the list is encoded as varint32, as well as SeqId. +const emitBatchOverhead = 30 + +var errSpanTooLarge = errors.New("Span is too large") + +type udpSender struct { + client *utils.AgentClientUDP + maxPacketSize int // max size of datagram in bytes + maxSpanBytes int // max number of bytes to record spans (excluding envelope) in the datagram + byteBufferSize int // current number of span bytes accumulated in the buffer + spanBuffer []*j.Span // spans buffered before a flush + thriftBuffer *thrift.TMemoryBuffer // buffer used to calculate byte size of a span + thriftProtocol thrift.TProtocol + process *j.Process + processByteSize int +} + +// NewUDPTransport creates a reporter that submits spans to jaeger-agent +func NewUDPTransport(hostPort string, maxPacketSize int) (Transport, error) { + if len(hostPort) == 0 { + hostPort = fmt.Sprintf("%s:%d", DefaultUDPSpanServerHost, DefaultUDPSpanServerPort) + } + if maxPacketSize == 0 { + maxPacketSize = utils.UDPPacketMaxLength + } + + protocolFactory := thrift.NewTCompactProtocolFactory() + + // Each span is first written to thriftBuffer to determine its size in bytes. + thriftBuffer := thrift.NewTMemoryBufferLen(maxPacketSize) + thriftProtocol := protocolFactory.GetProtocol(thriftBuffer) + + client, err := utils.NewAgentClientUDP(hostPort, maxPacketSize) + if err != nil { + return nil, err + } + + sender := &udpSender{ + client: client, + maxSpanBytes: maxPacketSize - emitBatchOverhead, + thriftBuffer: thriftBuffer, + thriftProtocol: thriftProtocol} + return sender, nil +} + +func (s *udpSender) calcSizeOfSerializedThrift(thriftStruct thrift.TStruct) int { + s.thriftBuffer.Reset() + thriftStruct.Write(s.thriftProtocol) + return s.thriftBuffer.Len() +} + +func (s *udpSender) Append(span *Span) (int, error) { + if s.process == nil { + s.process = BuildJaegerProcessThrift(span) + s.processByteSize = s.calcSizeOfSerializedThrift(s.process) + s.byteBufferSize += s.processByteSize + } + jSpan := BuildJaegerThrift(span) + spanSize := s.calcSizeOfSerializedThrift(jSpan) + if spanSize > s.maxSpanBytes { + return 1, errSpanTooLarge + } + + s.byteBufferSize += spanSize + if s.byteBufferSize <= s.maxSpanBytes { + s.spanBuffer = append(s.spanBuffer, jSpan) + if s.byteBufferSize < s.maxSpanBytes { + return 0, nil + } + return s.Flush() + } + // the latest span did not fit in the buffer + n, err := s.Flush() + s.spanBuffer = append(s.spanBuffer, jSpan) + s.byteBufferSize = spanSize + s.processByteSize + return n, err +} + +func (s *udpSender) Flush() (int, error) { + n := len(s.spanBuffer) + if n == 0 { + return 0, nil + } + err := s.client.EmitBatch(&j.Batch{Process: s.process, Spans: s.spanBuffer}) + s.resetBuffers() + + return n, err +} + +func (s *udpSender) Close() error { + return s.client.Close() +} + +func (s *udpSender) resetBuffers() { + for i := range s.spanBuffer { + s.spanBuffer[i] = nil + } + s.spanBuffer = s.spanBuffer[:0] + s.byteBufferSize = s.processByteSize +} diff --git a/vendor/github.com/uber/jaeger-client-go/utils/http_json.go b/vendor/github.com/uber/jaeger-client-go/utils/http_json.go new file mode 100644 index 0000000000..237211f822 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/utils/http_json.go @@ -0,0 +1,54 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 utils + +import ( + "encoding/json" + "fmt" + "io" + "io/ioutil" + "net/http" +) + +// GetJSON makes an HTTP call to the specified URL and parses the returned JSON into `out`. +func GetJSON(url string, out interface{}) error { + resp, err := http.Get(url) + if err != nil { + return err + } + return ReadJSON(resp, out) +} + +// ReadJSON reads JSON from http.Response and parses it into `out` +func ReadJSON(resp *http.Response, out interface{}) error { + defer resp.Body.Close() + + if resp.StatusCode >= 400 { + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + + return fmt.Errorf("StatusCode: %d, Body: %s", resp.StatusCode, body) + } + + if out == nil { + io.Copy(ioutil.Discard, resp.Body) + return nil + } + + decoder := json.NewDecoder(resp.Body) + return decoder.Decode(out) +} diff --git a/vendor/github.com/uber/jaeger-client-go/utils/localip.go b/vendor/github.com/uber/jaeger-client-go/utils/localip.go new file mode 100644 index 0000000000..b51af7713f --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/utils/localip.go @@ -0,0 +1,84 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 utils + +import ( + "errors" + "net" +) + +// This code is borrowed from https://github.com/uber/tchannel-go/blob/dev/localip.go + +// scoreAddr scores how likely the given addr is to be a remote address and returns the +// IP to use when listening. Any address which receives a negative score should not be used. +// Scores are calculated as: +// -1 for any unknown IP addresses. +// +300 for IPv4 addresses +// +100 for non-local addresses, extra +100 for "up" interaces. +func scoreAddr(iface net.Interface, addr net.Addr) (int, net.IP) { + var ip net.IP + if netAddr, ok := addr.(*net.IPNet); ok { + ip = netAddr.IP + } else if netIP, ok := addr.(*net.IPAddr); ok { + ip = netIP.IP + } else { + return -1, nil + } + + var score int + if ip.To4() != nil { + score += 300 + } + if iface.Flags&net.FlagLoopback == 0 && !ip.IsLoopback() { + score += 100 + if iface.Flags&net.FlagUp != 0 { + score += 100 + } + } + return score, ip +} + +// HostIP tries to find an IP that can be used by other machines to reach this machine. +func HostIP() (net.IP, error) { + interfaces, err := net.Interfaces() + if err != nil { + return nil, err + } + + bestScore := -1 + var bestIP net.IP + // Select the highest scoring IP as the best IP. + for _, iface := range interfaces { + addrs, err := iface.Addrs() + if err != nil { + // Skip this interface if there is an error. + continue + } + + for _, addr := range addrs { + score, ip := scoreAddr(iface, addr) + if score > bestScore { + bestScore = score + bestIP = ip + } + } + } + + if bestScore == -1 { + return nil, errors.New("no addresses to listen on") + } + + return bestIP, nil +} diff --git a/vendor/github.com/uber/jaeger-client-go/utils/rand.go b/vendor/github.com/uber/jaeger-client-go/utils/rand.go new file mode 100644 index 0000000000..9875f7f55c --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/utils/rand.go @@ -0,0 +1,46 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 utils + +import ( + "math/rand" + "sync" +) + +// lockedSource allows a random number generator to be used by multiple goroutines concurrently. +// The code is very similar to math/rand.lockedSource, which is unfortunately not exposed. +type lockedSource struct { + mut sync.Mutex + src rand.Source +} + +// NewRand returns a rand.Rand that is threadsafe. +func NewRand(seed int64) *rand.Rand { + return rand.New(&lockedSource{src: rand.NewSource(seed)}) +} + +func (r *lockedSource) Int63() (n int64) { + r.mut.Lock() + n = r.src.Int63() + r.mut.Unlock() + return +} + +// Seed implements Seed() of Source +func (r *lockedSource) Seed(seed int64) { + r.mut.Lock() + r.src.Seed(seed) + r.mut.Unlock() +} diff --git a/vendor/github.com/uber/jaeger-client-go/utils/rate_limiter.go b/vendor/github.com/uber/jaeger-client-go/utils/rate_limiter.go new file mode 100644 index 0000000000..1b8db97584 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/utils/rate_limiter.go @@ -0,0 +1,77 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 utils + +import ( + "sync" + "time" +) + +// RateLimiter is a filter used to check if a message that is worth itemCost units is within the rate limits. +type RateLimiter interface { + CheckCredit(itemCost float64) bool +} + +type rateLimiter struct { + sync.Mutex + + creditsPerSecond float64 + balance float64 + maxBalance float64 + lastTick time.Time + + timeNow func() time.Time +} + +// NewRateLimiter creates a new rate limiter based on leaky bucket algorithm, formulated in terms of a +// credits balance that is replenished every time CheckCredit() method is called (tick) by the amount proportional +// to the time elapsed since the last tick, up to max of creditsPerSecond. A call to CheckCredit() takes a cost +// of an item we want to pay with the balance. If the balance exceeds the cost of the item, the item is "purchased" +// and the balance reduced, indicated by returned value of true. Otherwise the balance is unchanged and return false. +// +// This can be used to limit a rate of messages emitted by a service by instantiating the Rate Limiter with the +// max number of messages a service is allowed to emit per second, and calling CheckCredit(1.0) for each message +// to determine if the message is within the rate limit. +// +// It can also be used to limit the rate of traffic in bytes, by setting creditsPerSecond to desired throughput +// as bytes/second, and calling CheckCredit() with the actual message size. +func NewRateLimiter(creditsPerSecond, maxBalance float64) RateLimiter { + return &rateLimiter{ + creditsPerSecond: creditsPerSecond, + balance: maxBalance, + maxBalance: maxBalance, + lastTick: time.Now(), + timeNow: time.Now} +} + +func (b *rateLimiter) CheckCredit(itemCost float64) bool { + b.Lock() + defer b.Unlock() + // calculate how much time passed since the last tick, and update current tick + currentTime := b.timeNow() + elapsedTime := currentTime.Sub(b.lastTick) + b.lastTick = currentTime + // calculate how much credit have we accumulated since the last tick + b.balance += elapsedTime.Seconds() * b.creditsPerSecond + if b.balance > b.maxBalance { + b.balance = b.maxBalance + } + // if we have enough credits to pay for current item, then reduce balance and allow + if b.balance >= itemCost { + b.balance -= itemCost + return true + } + return false +} diff --git a/vendor/github.com/uber/jaeger-client-go/utils/udp_client.go b/vendor/github.com/uber/jaeger-client-go/utils/udp_client.go new file mode 100644 index 0000000000..6f042073d6 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/utils/udp_client.go @@ -0,0 +1,98 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 utils + +import ( + "errors" + "fmt" + "io" + "net" + + "github.com/uber/jaeger-client-go/thrift" + + "github.com/uber/jaeger-client-go/thrift-gen/agent" + "github.com/uber/jaeger-client-go/thrift-gen/jaeger" + "github.com/uber/jaeger-client-go/thrift-gen/zipkincore" +) + +// UDPPacketMaxLength is the max size of UDP packet we want to send, synced with jaeger-agent +const UDPPacketMaxLength = 65000 + +// AgentClientUDP is a UDP client to Jaeger agent that implements agent.Agent interface. +type AgentClientUDP struct { + agent.Agent + io.Closer + + connUDP *net.UDPConn + client *agent.AgentClient + maxPacketSize int // max size of datagram in bytes + thriftBuffer *thrift.TMemoryBuffer // buffer used to calculate byte size of a span +} + +// NewAgentClientUDP creates a client that sends spans to Jaeger Agent over UDP. +func NewAgentClientUDP(hostPort string, maxPacketSize int) (*AgentClientUDP, error) { + if maxPacketSize == 0 { + maxPacketSize = UDPPacketMaxLength + } + + thriftBuffer := thrift.NewTMemoryBufferLen(maxPacketSize) + protocolFactory := thrift.NewTCompactProtocolFactory() + client := agent.NewAgentClientFactory(thriftBuffer, protocolFactory) + + destAddr, err := net.ResolveUDPAddr("udp", hostPort) + if err != nil { + return nil, err + } + + connUDP, err := net.DialUDP(destAddr.Network(), nil, destAddr) + if err != nil { + return nil, err + } + if err := connUDP.SetWriteBuffer(maxPacketSize); err != nil { + return nil, err + } + + clientUDP := &AgentClientUDP{ + connUDP: connUDP, + client: client, + maxPacketSize: maxPacketSize, + thriftBuffer: thriftBuffer} + return clientUDP, nil +} + +// EmitZipkinBatch implements EmitZipkinBatch() of Agent interface +func (a *AgentClientUDP) EmitZipkinBatch(spans []*zipkincore.Span) error { + return errors.New("Not implemented") +} + +// EmitBatch implements EmitBatch() of Agent interface +func (a *AgentClientUDP) EmitBatch(batch *jaeger.Batch) error { + a.thriftBuffer.Reset() + a.client.SeqId = 0 // we have no need for distinct SeqIds for our one-way UDP messages + if err := a.client.EmitBatch(batch); err != nil { + return err + } + if a.thriftBuffer.Len() > a.maxPacketSize { + return fmt.Errorf("Data does not fit within one UDP packet; size %d, max %d, spans %d", + a.thriftBuffer.Len(), a.maxPacketSize, len(batch.Spans)) + } + _, err := a.connUDP.Write(a.thriftBuffer.Bytes()) + return err +} + +// Close implements Close() of io.Closer and closes the underlying UDP connection. +func (a *AgentClientUDP) Close() error { + return a.connUDP.Close() +} diff --git a/vendor/github.com/uber/jaeger-client-go/utils/utils.go b/vendor/github.com/uber/jaeger-client-go/utils/utils.go new file mode 100644 index 0000000000..ac3c325d1e --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/utils/utils.go @@ -0,0 +1,87 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 utils + +import ( + "encoding/binary" + "errors" + "net" + "strconv" + "strings" + "time" +) + +var ( + // ErrEmptyIP an error for empty ip strings + ErrEmptyIP = errors.New("empty string given for ip") + + // ErrNotHostColonPort an error for invalid host port string + ErrNotHostColonPort = errors.New("expecting host:port") + + // ErrNotFourOctets an error for the wrong number of octets after splitting a string + ErrNotFourOctets = errors.New("Wrong number of octets") +) + +// ParseIPToUint32 converts a string ip (e.g. "x.y.z.w") to an uint32 +func ParseIPToUint32(ip string) (uint32, error) { + if ip == "" { + return 0, ErrEmptyIP + } + + if ip == "localhost" { + return 127<<24 | 1, nil + } + + octets := strings.Split(ip, ".") + if len(octets) != 4 { + return 0, ErrNotFourOctets + } + + var intIP uint32 + for i := 0; i < 4; i++ { + octet, err := strconv.Atoi(octets[i]) + if err != nil { + return 0, err + } + intIP = (intIP << 8) | uint32(octet) + } + + return intIP, nil +} + +// ParsePort converts port number from string to uin16 +func ParsePort(portString string) (uint16, error) { + port, err := strconv.ParseUint(portString, 10, 16) + return uint16(port), err +} + +// PackIPAsUint32 packs an IPv4 as uint32 +func PackIPAsUint32(ip net.IP) uint32 { + if ipv4 := ip.To4(); ipv4 != nil { + return binary.BigEndian.Uint32(ipv4) + } + return 0 +} + +// TimeToMicrosecondsSinceEpochInt64 converts Go time.Time to a long +// representing time since epoch in microseconds, which is used expected +// in the Jaeger spans encoded as Thrift. +func TimeToMicrosecondsSinceEpochInt64(t time.Time) int64 { + // ^^^ Passing time.Time by value is faster than passing a pointer! + // BenchmarkTimeByValue-8 2000000000 1.37 ns/op + // BenchmarkTimeByPtr-8 2000000000 1.98 ns/op + + return t.UnixNano() / 1000 +} diff --git a/vendor/github.com/uber/jaeger-client-go/zipkin.go b/vendor/github.com/uber/jaeger-client-go/zipkin.go new file mode 100644 index 0000000000..636952b7f1 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/zipkin.go @@ -0,0 +1,76 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 jaeger + +import ( + "github.com/opentracing/opentracing-go" +) + +// ZipkinSpanFormat is an OpenTracing carrier format constant +const ZipkinSpanFormat = "zipkin-span-format" + +// ExtractableZipkinSpan is a type of Carrier used for integration with Zipkin-aware +// RPC frameworks (like TChannel). It does not support baggage, only trace IDs. +type ExtractableZipkinSpan interface { + TraceID() uint64 + SpanID() uint64 + ParentID() uint64 + Flags() byte +} + +// InjectableZipkinSpan is a type of Carrier used for integration with Zipkin-aware +// RPC frameworks (like TChannel). It does not support baggage, only trace IDs. +type InjectableZipkinSpan interface { + SetTraceID(traceID uint64) + SetSpanID(spanID uint64) + SetParentID(parentID uint64) + SetFlags(flags byte) +} + +type zipkinPropagator struct { + tracer *Tracer +} + +func (p *zipkinPropagator) Inject( + ctx SpanContext, + abstractCarrier interface{}, +) error { + carrier, ok := abstractCarrier.(InjectableZipkinSpan) + if !ok { + return opentracing.ErrInvalidCarrier + } + + carrier.SetTraceID(ctx.TraceID().Low) // TODO this cannot work with 128bit IDs + carrier.SetSpanID(uint64(ctx.SpanID())) + carrier.SetParentID(uint64(ctx.ParentID())) + carrier.SetFlags(ctx.flags) + return nil +} + +func (p *zipkinPropagator) Extract(abstractCarrier interface{}) (SpanContext, error) { + carrier, ok := abstractCarrier.(ExtractableZipkinSpan) + if !ok { + return emptyContext, opentracing.ErrInvalidCarrier + } + if carrier.TraceID() == 0 { + return emptyContext, opentracing.ErrSpanContextNotFound + } + var ctx SpanContext + ctx.traceID.Low = carrier.TraceID() + ctx.spanID = SpanID(carrier.SpanID()) + ctx.parentID = SpanID(carrier.ParentID()) + ctx.flags = carrier.Flags() + return ctx, nil +} diff --git a/vendor/github.com/uber/jaeger-client-go/zipkin_thrift_span.go b/vendor/github.com/uber/jaeger-client-go/zipkin_thrift_span.go new file mode 100644 index 0000000000..dce58b4331 --- /dev/null +++ b/vendor/github.com/uber/jaeger-client-go/zipkin_thrift_span.go @@ -0,0 +1,322 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 jaeger + +import ( + "encoding/binary" + "fmt" + "time" + + "github.com/opentracing/opentracing-go/ext" + + "github.com/uber/jaeger-client-go/internal/spanlog" + z "github.com/uber/jaeger-client-go/thrift-gen/zipkincore" + "github.com/uber/jaeger-client-go/utils" +) + +const ( + // Zipkin UI does not work well with non-string tag values + allowPackedNumbers = false +) + +var specialTagHandlers = map[string]func(*zipkinSpan, interface{}){ + string(ext.SpanKind): setSpanKind, + string(ext.PeerHostIPv4): setPeerIPv4, + string(ext.PeerPort): setPeerPort, + string(ext.PeerService): setPeerService, + TracerIPTagKey: removeTag, +} + +// BuildZipkinThrift builds thrift span based on internal span. +func BuildZipkinThrift(s *Span) *z.Span { + span := &zipkinSpan{Span: s} + span.handleSpecialTags() + parentID := int64(span.context.parentID) + var ptrParentID *int64 + if parentID != 0 { + ptrParentID = &parentID + } + timestamp := utils.TimeToMicrosecondsSinceEpochInt64(span.startTime) + duration := span.duration.Nanoseconds() / int64(time.Microsecond) + endpoint := &z.Endpoint{ + ServiceName: span.tracer.serviceName, + Ipv4: int32(span.tracer.hostIPv4)} + thriftSpan := &z.Span{ + TraceID: int64(span.context.traceID.Low), // TODO upgrade zipkin thrift and use TraceIdHigh + ID: int64(span.context.spanID), + ParentID: ptrParentID, + Name: span.operationName, + Timestamp: ×tamp, + Duration: &duration, + Debug: span.context.IsDebug(), + Annotations: buildAnnotations(span, endpoint), + BinaryAnnotations: buildBinaryAnnotations(span, endpoint)} + return thriftSpan +} + +func buildAnnotations(span *zipkinSpan, endpoint *z.Endpoint) []*z.Annotation { + // automatically adding 2 Zipkin CoreAnnotations + annotations := make([]*z.Annotation, 0, 2+len(span.logs)) + var startLabel, endLabel string + if span.spanKind == string(ext.SpanKindRPCClientEnum) { + startLabel, endLabel = z.CLIENT_SEND, z.CLIENT_RECV + } else if span.spanKind == string(ext.SpanKindRPCServerEnum) { + startLabel, endLabel = z.SERVER_RECV, z.SERVER_SEND + } + if !span.startTime.IsZero() && startLabel != "" { + start := &z.Annotation{ + Timestamp: utils.TimeToMicrosecondsSinceEpochInt64(span.startTime), + Value: startLabel, + Host: endpoint} + annotations = append(annotations, start) + if span.duration != 0 { + endTs := span.startTime.Add(span.duration) + end := &z.Annotation{ + Timestamp: utils.TimeToMicrosecondsSinceEpochInt64(endTs), + Value: endLabel, + Host: endpoint} + annotations = append(annotations, end) + } + } + for _, log := range span.logs { + anno := &z.Annotation{ + Timestamp: utils.TimeToMicrosecondsSinceEpochInt64(log.Timestamp), + Host: endpoint} + if content, err := spanlog.MaterializeWithJSON(log.Fields); err == nil { + anno.Value = truncateString(string(content), span.tracer.options.maxTagValueLength) + } else { + anno.Value = err.Error() + } + annotations = append(annotations, anno) + } + return annotations +} + +func buildBinaryAnnotations(span *zipkinSpan, endpoint *z.Endpoint) []*z.BinaryAnnotation { + // automatically adding local component or server/client address tag, and client version + annotations := make([]*z.BinaryAnnotation, 0, 2+len(span.tags)) + + if span.peerDefined() && span.isRPC() { + peer := z.Endpoint{ + Ipv4: span.peer.Ipv4, + Port: span.peer.Port, + ServiceName: span.peer.ServiceName} + label := z.CLIENT_ADDR + if span.isRPCClient() { + label = z.SERVER_ADDR + } + anno := &z.BinaryAnnotation{ + Key: label, + Value: []byte{1}, + AnnotationType: z.AnnotationType_BOOL, + Host: &peer} + annotations = append(annotations, anno) + } + if !span.isRPC() { + componentName := endpoint.ServiceName + for _, tag := range span.tags { + if tag.key == string(ext.Component) { + componentName = stringify(tag.value) + break + } + } + local := &z.BinaryAnnotation{ + Key: z.LOCAL_COMPONENT, + Value: []byte(componentName), + AnnotationType: z.AnnotationType_STRING, + Host: endpoint} + annotations = append(annotations, local) + } + for _, tag := range span.tags { + // "Special tags" are already handled by this point, we'd be double reporting the + // tags if we don't skip here + if _, ok := specialTagHandlers[tag.key]; ok { + continue + } + if anno := buildBinaryAnnotation(tag.key, tag.value, span.tracer.options.maxTagValueLength, nil); anno != nil { + annotations = append(annotations, anno) + } + } + return annotations +} + +func buildBinaryAnnotation(key string, val interface{}, maxTagValueLength int, endpoint *z.Endpoint) *z.BinaryAnnotation { + bann := &z.BinaryAnnotation{Key: key, Host: endpoint} + if value, ok := val.(string); ok { + bann.Value = []byte(truncateString(value, maxTagValueLength)) + bann.AnnotationType = z.AnnotationType_STRING + } else if value, ok := val.([]byte); ok { + if len(value) > maxTagValueLength { + value = value[:maxTagValueLength] + } + bann.Value = value + bann.AnnotationType = z.AnnotationType_BYTES + } else if value, ok := val.(int32); ok && allowPackedNumbers { + bann.Value = int32ToBytes(value) + bann.AnnotationType = z.AnnotationType_I32 + } else if value, ok := val.(int64); ok && allowPackedNumbers { + bann.Value = int64ToBytes(value) + bann.AnnotationType = z.AnnotationType_I64 + } else if value, ok := val.(int); ok && allowPackedNumbers { + bann.Value = int64ToBytes(int64(value)) + bann.AnnotationType = z.AnnotationType_I64 + } else if value, ok := val.(bool); ok { + bann.Value = []byte{boolToByte(value)} + bann.AnnotationType = z.AnnotationType_BOOL + } else { + value := stringify(val) + bann.Value = []byte(truncateString(value, maxTagValueLength)) + bann.AnnotationType = z.AnnotationType_STRING + } + return bann +} + +func stringify(value interface{}) string { + if s, ok := value.(string); ok { + return s + } + return fmt.Sprintf("%+v", value) +} + +func truncateString(value string, maxLength int) string { + // we ignore the problem of utf8 runes possibly being sliced in the middle, + // as it is rather expensive to iterate through each tag just to find rune + // boundaries. + if len(value) > maxLength { + return value[:maxLength] + } + return value +} + +func boolToByte(b bool) byte { + if b { + return 1 + } + return 0 +} + +// int32ToBytes converts int32 to bytes. +func int32ToBytes(i int32) []byte { + buf := make([]byte, 4) + binary.BigEndian.PutUint32(buf, uint32(i)) + return buf +} + +// int64ToBytes converts int64 to bytes. +func int64ToBytes(i int64) []byte { + buf := make([]byte, 8) + binary.BigEndian.PutUint64(buf, uint64(i)) + return buf +} + +type zipkinSpan struct { + *Span + + // peer points to the peer service participating in this span, + // e.g. the Client if this span is a server span, + // or Server if this span is a client span + peer struct { + Ipv4 int32 + Port int16 + ServiceName string + } + + // used to distinguish local vs. RPC Server vs. RPC Client spans + spanKind string +} + +func (s *zipkinSpan) handleSpecialTags() { + s.Lock() + defer s.Unlock() + if s.firstInProcess { + // append the process tags + s.tags = append(s.tags, s.tracer.tags...) + } + filteredTags := make([]Tag, 0, len(s.tags)) + for _, tag := range s.tags { + if handler, ok := specialTagHandlers[tag.key]; ok { + handler(s, tag.value) + } else { + filteredTags = append(filteredTags, tag) + } + } + s.tags = filteredTags +} + +func setSpanKind(s *zipkinSpan, value interface{}) { + if val, ok := value.(string); ok { + s.spanKind = val + return + } + if val, ok := value.(ext.SpanKindEnum); ok { + s.spanKind = string(val) + } +} + +func setPeerIPv4(s *zipkinSpan, value interface{}) { + if val, ok := value.(string); ok { + if ip, err := utils.ParseIPToUint32(val); err == nil { + s.peer.Ipv4 = int32(ip) + return + } + } + if val, ok := value.(uint32); ok { + s.peer.Ipv4 = int32(val) + return + } + if val, ok := value.(int32); ok { + s.peer.Ipv4 = val + } +} + +func setPeerPort(s *zipkinSpan, value interface{}) { + if val, ok := value.(string); ok { + if port, err := utils.ParsePort(val); err == nil { + s.peer.Port = int16(port) + return + } + } + if val, ok := value.(uint16); ok { + s.peer.Port = int16(val) + return + } + if val, ok := value.(int); ok { + s.peer.Port = int16(val) + } +} + +func setPeerService(s *zipkinSpan, value interface{}) { + if val, ok := value.(string); ok { + s.peer.ServiceName = val + } +} + +func removeTag(s *zipkinSpan, value interface{}) {} + +func (s *zipkinSpan) peerDefined() bool { + return s.peer.ServiceName != "" || s.peer.Ipv4 != 0 || s.peer.Port != 0 +} + +func (s *zipkinSpan) isRPC() bool { + s.RLock() + defer s.RUnlock() + return s.spanKind == string(ext.SpanKindRPCClientEnum) || s.spanKind == string(ext.SpanKindRPCServerEnum) +} + +func (s *zipkinSpan) isRPCClient() bool { + s.RLock() + defer s.RUnlock() + return s.spanKind == string(ext.SpanKindRPCClientEnum) +} diff --git a/vendor/github.com/uber/jaeger-lib/LICENSE b/vendor/github.com/uber/jaeger-lib/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/vendor/github.com/uber/jaeger-lib/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/uber/jaeger-lib/metrics/counter.go b/vendor/github.com/uber/jaeger-lib/metrics/counter.go new file mode 100644 index 0000000000..2a6a43efdb --- /dev/null +++ b/vendor/github.com/uber/jaeger-lib/metrics/counter.go @@ -0,0 +1,28 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 metrics + +// Counter tracks the number of times an event has occurred +type Counter interface { + // Inc adds the given value to the counter. + Inc(int64) +} + +// NullCounter counter that does nothing +var NullCounter Counter = nullCounter{} + +type nullCounter struct{} + +func (nullCounter) Inc(int64) {} diff --git a/vendor/github.com/uber/jaeger-lib/metrics/factory.go b/vendor/github.com/uber/jaeger-lib/metrics/factory.go new file mode 100644 index 0000000000..a744a890df --- /dev/null +++ b/vendor/github.com/uber/jaeger-lib/metrics/factory.go @@ -0,0 +1,35 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 metrics + +// Factory creates new metrics +type Factory interface { + Counter(name string, tags map[string]string) Counter + Timer(name string, tags map[string]string) Timer + Gauge(name string, tags map[string]string) Gauge + + // Namespace returns a nested metrics factory. + Namespace(name string, tags map[string]string) Factory +} + +// NullFactory is a metrics factory that returns NullCounter, NullTimer, and NullGauge. +var NullFactory Factory = nullFactory{} + +type nullFactory struct{} + +func (nullFactory) Counter(name string, tags map[string]string) Counter { return NullCounter } +func (nullFactory) Timer(name string, tags map[string]string) Timer { return NullTimer } +func (nullFactory) Gauge(name string, tags map[string]string) Gauge { return NullGauge } +func (nullFactory) Namespace(name string, tags map[string]string) Factory { return NullFactory } diff --git a/vendor/github.com/uber/jaeger-lib/metrics/gauge.go b/vendor/github.com/uber/jaeger-lib/metrics/gauge.go new file mode 100644 index 0000000000..3c606391a0 --- /dev/null +++ b/vendor/github.com/uber/jaeger-lib/metrics/gauge.go @@ -0,0 +1,28 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 metrics + +// Gauge returns instantaneous measurements of something as an int64 value +type Gauge interface { + // Update the gauge to the value passed in. + Update(int64) +} + +// NullGauge gauge that does nothing +var NullGauge Gauge = nullGauge{} + +type nullGauge struct{} + +func (nullGauge) Update(int64) {} diff --git a/vendor/github.com/uber/jaeger-lib/metrics/local.go b/vendor/github.com/uber/jaeger-lib/metrics/local.go new file mode 100644 index 0000000000..217d30600a --- /dev/null +++ b/vendor/github.com/uber/jaeger-lib/metrics/local.go @@ -0,0 +1,337 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 metrics + +import ( + "sort" + "sync" + "sync/atomic" + "time" + + "github.com/codahale/hdrhistogram" +) + +// This is intentionally very similar to github.com/codahale/metrics, the +// main difference being that counters/gauges are scoped to the provider +// rather than being global (to facilitate testing). + +// A LocalBackend is a metrics provider which aggregates data in-vm, and +// allows exporting snapshots to shove the data into a remote collector +type LocalBackend struct { + cm sync.Mutex + gm sync.Mutex + tm sync.Mutex + counters map[string]*int64 + gauges map[string]*int64 + timers map[string]*localBackendTimer + stop chan struct{} + wg sync.WaitGroup + TagsSep string + TagKVSep string +} + +// NewLocalBackend returns a new LocalBackend. The collectionInterval is the histogram +// time window for each timer. +func NewLocalBackend(collectionInterval time.Duration) *LocalBackend { + b := &LocalBackend{ + counters: make(map[string]*int64), + gauges: make(map[string]*int64), + timers: make(map[string]*localBackendTimer), + stop: make(chan struct{}), + TagsSep: "|", + TagKVSep: "=", + } + if collectionInterval == 0 { + // Use one histogram time window for all timers + return b + } + b.wg.Add(1) + go b.runLoop(collectionInterval) + return b +} + +// Clear discards accumulated stats +func (b *LocalBackend) Clear() { + b.cm.Lock() + defer b.cm.Unlock() + b.gm.Lock() + defer b.gm.Unlock() + b.tm.Lock() + defer b.tm.Unlock() + b.counters = make(map[string]*int64) + b.gauges = make(map[string]*int64) + b.timers = make(map[string]*localBackendTimer) +} + +func (b *LocalBackend) runLoop(collectionInterval time.Duration) { + defer b.wg.Done() + ticker := time.NewTicker(collectionInterval) + for { + select { + case <-ticker.C: + b.tm.Lock() + timers := make(map[string]*localBackendTimer, len(b.timers)) + for timerName, timer := range b.timers { + timers[timerName] = timer + } + b.tm.Unlock() + + for _, t := range timers { + t.Lock() + t.hist.Rotate() + t.Unlock() + } + case <-b.stop: + ticker.Stop() + return + } + } +} + +// IncCounter increments a counter value +func (b *LocalBackend) IncCounter(name string, tags map[string]string, delta int64) { + name = GetKey(name, tags, b.TagsSep, b.TagKVSep) + b.cm.Lock() + defer b.cm.Unlock() + counter := b.counters[name] + if counter == nil { + b.counters[name] = new(int64) + *b.counters[name] = delta + return + } + atomic.AddInt64(counter, delta) +} + +// UpdateGauge updates the value of a gauge +func (b *LocalBackend) UpdateGauge(name string, tags map[string]string, value int64) { + name = GetKey(name, tags, b.TagsSep, b.TagKVSep) + b.gm.Lock() + defer b.gm.Unlock() + gauge := b.gauges[name] + if gauge == nil { + b.gauges[name] = new(int64) + *b.gauges[name] = value + return + } + atomic.StoreInt64(gauge, value) +} + +// RecordTimer records a timing duration +func (b *LocalBackend) RecordTimer(name string, tags map[string]string, d time.Duration) { + name = GetKey(name, tags, b.TagsSep, b.TagKVSep) + timer := b.findOrCreateTimer(name) + timer.Lock() + timer.hist.Current.RecordValue(int64(d / time.Millisecond)) + timer.Unlock() +} + +func (b *LocalBackend) findOrCreateTimer(name string) *localBackendTimer { + b.tm.Lock() + defer b.tm.Unlock() + if t, ok := b.timers[name]; ok { + return t + } + + t := &localBackendTimer{ + hist: hdrhistogram.NewWindowed(5, 0, int64((5*time.Minute)/time.Millisecond), 1), + } + b.timers[name] = t + return t +} + +type localBackendTimer struct { + sync.Mutex + hist *hdrhistogram.WindowedHistogram +} + +var ( + percentiles = map[string]float64{ + "P50": 50, + "P75": 75, + "P90": 90, + "P95": 95, + "P99": 99, + "P999": 99.9, + } +) + +// Snapshot captures a snapshot of the current counter and gauge values +func (b *LocalBackend) Snapshot() (counters, gauges map[string]int64) { + b.cm.Lock() + defer b.cm.Unlock() + + counters = make(map[string]int64, len(b.counters)) + for name, value := range b.counters { + counters[name] = atomic.LoadInt64(value) + } + + b.gm.Lock() + defer b.gm.Unlock() + + gauges = make(map[string]int64, len(b.gauges)) + for name, value := range b.gauges { + gauges[name] = atomic.LoadInt64(value) + } + + b.tm.Lock() + timers := make(map[string]*localBackendTimer) + for timerName, timer := range b.timers { + timers[timerName] = timer + } + b.tm.Unlock() + + for timerName, timer := range timers { + timer.Lock() + hist := timer.hist.Merge() + timer.Unlock() + for name, q := range percentiles { + gauges[timerName+"."+name] = hist.ValueAtQuantile(q) + } + } + + return +} + +// Stop cleanly closes the background goroutine spawned by NewLocalBackend. +func (b *LocalBackend) Stop() { + close(b.stop) + b.wg.Wait() +} + +// GetKey converts name+tags into a single string of the form +// "name|tag1=value1|...|tagN=valueN", where tag names are +// sorted alphabetically. +func GetKey(name string, tags map[string]string, tagsSep string, tagKVSep string) string { + keys := make([]string, 0, len(tags)) + for k := range tags { + keys = append(keys, k) + } + sort.Strings(keys) + key := name + for _, k := range keys { + key = key + tagsSep + k + tagKVSep + tags[k] + } + return key +} + +type stats struct { + name string + tags map[string]string + localBackend *LocalBackend +} + +type localTimer struct { + stats +} + +func (l *localTimer) Record(d time.Duration) { + l.localBackend.RecordTimer(l.name, l.tags, d) +} + +type localCounter struct { + stats +} + +func (l *localCounter) Inc(delta int64) { + l.localBackend.IncCounter(l.name, l.tags, delta) +} + +type localGauge struct { + stats +} + +func (l *localGauge) Update(value int64) { + l.localBackend.UpdateGauge(l.name, l.tags, value) +} + +// LocalFactory stats factory that creates metrics that are stored locally +type LocalFactory struct { + *LocalBackend + namespace string + tags map[string]string +} + +// NewLocalFactory returns a new LocalMetricsFactory +func NewLocalFactory(collectionInterval time.Duration) *LocalFactory { + return &LocalFactory{ + LocalBackend: NewLocalBackend(collectionInterval), + } +} + +// appendTags adds the tags to the namespace tags and returns a combined map. +func (l *LocalFactory) appendTags(tags map[string]string) map[string]string { + newTags := make(map[string]string) + for k, v := range l.tags { + newTags[k] = v + } + for k, v := range tags { + newTags[k] = v + } + return newTags +} + +func (l *LocalFactory) newNamespace(name string) string { + if l.namespace == "" { + return name + } + + if name == "" { + return l.namespace + } + + return l.namespace + "." + name +} + +// Counter returns a local stats counter +func (l *LocalFactory) Counter(name string, tags map[string]string) Counter { + return &localCounter{ + stats{ + name: l.newNamespace(name), + tags: l.appendTags(tags), + localBackend: l.LocalBackend, + }, + } +} + +// Timer returns a local stats timer. +func (l *LocalFactory) Timer(name string, tags map[string]string) Timer { + return &localTimer{ + stats{ + name: l.newNamespace(name), + tags: l.appendTags(tags), + localBackend: l.LocalBackend, + }, + } +} + +// Gauge returns a local stats gauge. +func (l *LocalFactory) Gauge(name string, tags map[string]string) Gauge { + return &localGauge{ + stats{ + name: l.newNamespace(name), + tags: l.appendTags(tags), + localBackend: l.LocalBackend, + }, + } +} + +// Namespace returns a new namespace. +func (l *LocalFactory) Namespace(name string, tags map[string]string) Factory { + return &LocalFactory{ + namespace: l.newNamespace(name), + tags: l.appendTags(tags), + LocalBackend: l.LocalBackend, + } +} diff --git a/vendor/github.com/uber/jaeger-lib/metrics/metrics.go b/vendor/github.com/uber/jaeger-lib/metrics/metrics.go new file mode 100644 index 0000000000..0b97707b07 --- /dev/null +++ b/vendor/github.com/uber/jaeger-lib/metrics/metrics.go @@ -0,0 +1,85 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 metrics + +import ( + "fmt" + "reflect" + "strings" +) + +// Init initializes the passed in metrics and initializes its fields using the passed in factory. +func Init(metrics interface{}, factory Factory, globalTags map[string]string) { + if err := initMetrics(metrics, factory, globalTags); err != nil { + panic(err.Error()) + } +} + +// initMetrics uses reflection to initialize a struct containing metrics fields +// by assigning new Counter/Gauge/Timer values with the metric name retrieved +// from the `metric` tag and stats tags retrieved from the `tags` tag. +// +// Note: all fields of the struct must be exported, have a `metric` tag, and be +// of type Counter or Gauge or Timer. +func initMetrics(m interface{}, factory Factory, globalTags map[string]string) error { + // Allow user to opt out of reporting metrics by passing in nil. + if factory == nil { + factory = NullFactory + } + + counterPtrType := reflect.TypeOf((*Counter)(nil)).Elem() + gaugePtrType := reflect.TypeOf((*Gauge)(nil)).Elem() + timerPtrType := reflect.TypeOf((*Timer)(nil)).Elem() + + v := reflect.ValueOf(m).Elem() + t := v.Type() + for i := 0; i < t.NumField(); i++ { + tags := make(map[string]string) + for k, v := range globalTags { + tags[k] = v + } + field := t.Field(i) + metric := field.Tag.Get("metric") + if metric == "" { + return fmt.Errorf("Field %s is missing a tag 'metric'", field.Name) + } + if tagString := field.Tag.Get("tags"); tagString != "" { + tagPairs := strings.Split(tagString, ",") + for _, tagPair := range tagPairs { + tag := strings.Split(tagPair, "=") + if len(tag) != 2 { + return fmt.Errorf( + "Field [%s]: Tag [%s] is not of the form key=value in 'tags' string [%s]", + field.Name, tagPair, tagString) + } + tags[tag[0]] = tag[1] + } + } + var obj interface{} + if field.Type.AssignableTo(counterPtrType) { + obj = factory.Counter(metric, tags) + } else if field.Type.AssignableTo(gaugePtrType) { + obj = factory.Gauge(metric, tags) + } else if field.Type.AssignableTo(timerPtrType) { + obj = factory.Timer(metric, tags) + } else { + return fmt.Errorf( + "Field %s is not a pointer to timer, gauge, or counter", + field.Name) + } + v.Field(i).Set(reflect.ValueOf(obj)) + } + return nil +} diff --git a/vendor/github.com/uber/jaeger-lib/metrics/stopwatch.go b/vendor/github.com/uber/jaeger-lib/metrics/stopwatch.go new file mode 100644 index 0000000000..4a8abdb539 --- /dev/null +++ b/vendor/github.com/uber/jaeger-lib/metrics/stopwatch.go @@ -0,0 +1,43 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 metrics + +import ( + "time" +) + +// StartStopwatch begins recording the executing time of an event, returning +// a Stopwatch that should be used to stop the recording the time for +// that event. Multiple events can be occurring simultaneously each +// represented by different active Stopwatches +func StartStopwatch(timer Timer) Stopwatch { + return Stopwatch{t: timer, start: time.Now()} +} + +// A Stopwatch tracks the execution time of a specific event +type Stopwatch struct { + t Timer + start time.Time +} + +// Stop stops executing of the stopwatch and records the amount of elapsed time +func (s Stopwatch) Stop() { + s.t.Record(s.ElapsedTime()) +} + +// ElapsedTime returns the amount of elapsed time (in time.Duration) +func (s Stopwatch) ElapsedTime() time.Duration { + return time.Since(s.start) +} diff --git a/vendor/github.com/uber/jaeger-lib/metrics/timer.go b/vendor/github.com/uber/jaeger-lib/metrics/timer.go new file mode 100644 index 0000000000..e18d222abb --- /dev/null +++ b/vendor/github.com/uber/jaeger-lib/metrics/timer.go @@ -0,0 +1,33 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 metrics + +import ( + "time" +) + +// Timer accumulates observations about how long some operation took, +// and also maintains a historgam of percentiles. +type Timer interface { + // Records the time passed in. + Record(time.Duration) +} + +// NullTimer timer that does nothing +var NullTimer Timer = nullTimer{} + +type nullTimer struct{} + +func (nullTimer) Record(time.Duration) {} diff --git a/vendor/golang.org/x/crypto/ed25519/ed25519.go b/vendor/golang.org/x/crypto/ed25519/ed25519.go index 4f26b49b6a..d6f683ba3f 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 @@ -171,9 +200,16 @@ func Verify(publicKey PublicKey, message, sig []byte) bool { edwards25519.ScReduce(&hReduced, &digest) var R edwards25519.ProjectiveGroupElement - var b [32]byte - copy(b[:], sig[32:]) - edwards25519.GeDoubleScalarMultVartime(&R, &hReduced, &A, &b) + var s [32]byte + copy(s[:], sig[32:]) + + // https://tools.ietf.org/html/rfc8032#section-5.1.7 requires that s be in + // the range [0, order) in order to prevent signature malleability. + if !edwards25519.ScMinimal(&s) { + return false + } + + edwards25519.GeDoubleScalarMultVartime(&R, &hReduced, &A, &s) var checkR [32]byte R.ToBytes(&checkR) diff --git a/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go b/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go index 5f8b994787..fd03c252af 100644 --- a/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go +++ b/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go @@ -4,6 +4,8 @@ package edwards25519 +import "encoding/binary" + // This code is a port of the public domain, “ref10” implementation of ed25519 // from SUPERCOP. @@ -1769,3 +1771,23 @@ func ScReduce(out *[32]byte, s *[64]byte) { out[30] = byte(s11 >> 9) out[31] = byte(s11 >> 17) } + +// order is the order of Curve25519 in little-endian form. +var order = [4]uint64{0x5812631a5cf5d3ed, 0x14def9dea2f79cd6, 0, 0x1000000000000000} + +// ScMinimal returns true if the given scalar is less than the order of the +// curve. +func ScMinimal(scalar *[32]byte) bool { + for i := 3; ; i-- { + v := binary.LittleEndian.Uint64(scalar[i*8:]) + if v > order[i] { + return false + } else if v < order[i] { + break + } else if i == 0 { + return false + } + } + + return true +} diff --git a/vendor/golang.org/x/crypto/internal/chacha20/chacha_generic.go b/vendor/golang.org/x/crypto/internal/chacha20/chacha_generic.go new file mode 100644 index 0000000000..6570847f5e --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/chacha20/chacha_generic.go @@ -0,0 +1,264 @@ +// Copyright 2016 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 ChaCha20 implements the core ChaCha20 function as specified +// in https://tools.ietf.org/html/rfc7539#section-2.3. +package chacha20 + +import ( + "crypto/cipher" + "encoding/binary" + + "golang.org/x/crypto/internal/subtle" +) + +// assert that *Cipher implements cipher.Stream +var _ cipher.Stream = (*Cipher)(nil) + +// Cipher is a stateful instance of ChaCha20 using a particular key +// and nonce. A *Cipher implements the cipher.Stream interface. +type Cipher struct { + key [8]uint32 + counter uint32 // incremented after each block + nonce [3]uint32 + buf [bufSize]byte // buffer for unused keystream bytes + len int // number of unused keystream bytes at end of buf +} + +// New creates a new ChaCha20 stream cipher with the given key and nonce. +// The initial counter value is set to 0. +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. +// +// If len(dst) < len(src), XORKeyStream will panic. It is acceptable +// to pass a dst bigger than src, and in that case, XORKeyStream will +// only update dst[:len(src)] and will not touch the rest of dst. +// +// Multiple calls to XORKeyStream behave as if the concatenation of +// 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:] + if len(src) < len(buf) { + buf = buf[:len(src)] + } + td, ts := dst[:len(buf)], src[:len(buf)] // BCE hint + for i, b := range buf { + td[i] = ts[i] ^ b + } + s.len -= len(buf) + if s.len != 0 { + return + } + s.buf = [len(s.buf)]byte{} // zero the empty buffer + src = src[len(buf):] + dst = dst[len(buf):] + } + + if len(src) == 0 { + return + } + if haveAsm { + if uint64(len(src))+uint64(s.counter)*64 > (1<<38)-64 { + panic("chacha20: counter overflow") + } + s.xorKeyStreamAsm(dst, src) + return + } + + // set up a 64-byte buffer to pad out the final block if needed + // (hoisted out of the main loop to avoid spills) + rem := len(src) % 64 // length of final block + fin := len(src) - rem // index of final block + if rem > 0 { + copy(s.buf[len(s.buf)-64:], src[fin:]) + } + + // pre-calculate most of the first round + 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 := quarterRound(j0, s.key[0], s.key[4], s.counter) + + // execute the second round + 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 = 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) + } + + x0 += j0 + x1 += j1 + x2 += j2 + x3 += j3 + + x4 += s.key[0] + x5 += s.key[1] + x6 += s.key[2] + x7 += s.key[3] + x8 += s.key[4] + x9 += s.key[5] + x10 += s.key[6] + x11 += s.key[7] + + x12 += s.counter + x13 += s.nonce[0] + x14 += s.nonce[1] + x15 += s.nonce[2] + + // increment the counter + s.counter += 1 + if s.counter == 0 { + panic("chacha20: counter overflow") + } + + // pad to 64 bytes if needed + in, out := src[i:], dst[i:] + if i == fin { + // src[fin:] has already been copied into s.buf before + // the main loop + in, out = s.buf[len(s.buf)-64:], s.buf[len(s.buf)-64:] + } + in, out = in[:64], out[:64] // BCE hint + + // XOR the key stream with the source and write out the result + xor(out[0:], in[0:], x0) + xor(out[4:], in[4:], x1) + xor(out[8:], in[8:], x2) + xor(out[12:], in[12:], x3) + xor(out[16:], in[16:], x4) + xor(out[20:], in[20:], x5) + xor(out[24:], in[24:], x6) + xor(out[28:], in[28:], x7) + xor(out[32:], in[32:], x8) + xor(out[36:], in[36:], x9) + xor(out[40:], in[40:], x10) + xor(out[44:], in[44:], x11) + xor(out[48:], in[48:], x12) + xor(out[52:], in[52:], x13) + xor(out[56:], in[56:], x14) + xor(out[60:], in[60:], x15) + } + // copy any trailing bytes out of the buffer and into dst + if rem != 0 { + s.len = 64 - rem + copy(dst[fin:], s.buf[len(s.buf)-64:]) + } +} + +// Advance discards bytes in the key stream until the next 64 byte block +// boundary is reached and updates the counter accordingly. If the key +// stream is already at a block boundary no bytes will be discarded and +// the counter will be unchanged. +func (s *Cipher) Advance() { + s.len -= s.len % 64 + if s.len == 0 { + s.buf = [len(s.buf)]byte{} + } +} + +// XORKeyStream crypts bytes from in to out using the given key and counters. +// In and out must overlap entirely or not at all. Counter contains the raw +// ChaCha20 counter bytes (i.e. block counter followed by nonce). +func XORKeyStream(out, in []byte, counter *[16]byte, key *[32]byte) { + s := Cipher{ + key: [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]), + }, + nonce: [3]uint32{ + binary.LittleEndian.Uint32(counter[4:8]), + binary.LittleEndian.Uint32(counter[8:12]), + binary.LittleEndian.Uint32(counter[12:16]), + }, + counter: binary.LittleEndian.Uint32(counter[0:4]), + } + 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/chacha_noasm.go b/vendor/golang.org/x/crypto/internal/chacha20/chacha_noasm.go new file mode 100644 index 0000000000..91520d1de0 --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/chacha20/chacha_noasm.go @@ -0,0 +1,16 @@ +// 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 gccgo appengine + +package chacha20 + +const ( + bufSize = 64 + haveAsm = false +) + +func (*Cipher) xorKeyStreamAsm(dst, src []byte) { + panic("not implemented") +} diff --git a/vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.go b/vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.go new file mode 100644 index 0000000000..0c1c671c40 --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.go @@ -0,0 +1,30 @@ +// 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,!gccgo,!appengine + +package chacha20 + +var haveAsm = hasVectorFacility() + +const bufSize = 256 + +// hasVectorFacility reports whether the machine supports the vector +// facility (vx). +// Implementation in asm_s390x.s. +func hasVectorFacility() bool + +// xorKeyStreamVX is an assembly implementation of XORKeyStream. It must only +// be called when the vector facility is available. +// Implementation in asm_s390x.s. +//go:noescape +func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32, buf *[256]byte, len *int) + +func (c *Cipher) xorKeyStreamAsm(dst, src []byte) { + xorKeyStreamVX(dst, src, &c.key, &c.nonce, &c.counter, &c.buf, &c.len) +} + +// EXRL targets, DO NOT CALL! +func mvcSrcToBuf() +func mvcBufToDst() diff --git a/vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.s b/vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.s new file mode 100644 index 0000000000..98427c5e22 --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.s @@ -0,0 +1,283 @@ +// 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,!gccgo,!appengine + +#include "go_asm.h" +#include "textflag.h" + +// This is an implementation of the ChaCha20 encryption algorithm as +// specified in RFC 7539. It uses vector instructions to compute +// 4 keystream blocks in parallel (256 bytes) which are then XORed +// with the bytes in the input slice. + +GLOBL ·constants<>(SB), RODATA|NOPTR, $32 +// BSWAP: swap bytes in each 4-byte element +DATA ·constants<>+0x00(SB)/4, $0x03020100 +DATA ·constants<>+0x04(SB)/4, $0x07060504 +DATA ·constants<>+0x08(SB)/4, $0x0b0a0908 +DATA ·constants<>+0x0c(SB)/4, $0x0f0e0d0c +// J0: [j0, j1, j2, j3] +DATA ·constants<>+0x10(SB)/4, $0x61707865 +DATA ·constants<>+0x14(SB)/4, $0x3320646e +DATA ·constants<>+0x18(SB)/4, $0x79622d32 +DATA ·constants<>+0x1c(SB)/4, $0x6b206574 + +// EXRL targets: +TEXT ·mvcSrcToBuf(SB), NOFRAME|NOSPLIT, $0 + MVC $1, (R1), (R8) + RET + +TEXT ·mvcBufToDst(SB), NOFRAME|NOSPLIT, $0 + MVC $1, (R8), (R9) + RET + +#define BSWAP V5 +#define J0 V6 +#define KEY0 V7 +#define KEY1 V8 +#define NONCE V9 +#define CTR V10 +#define M0 V11 +#define M1 V12 +#define M2 V13 +#define M3 V14 +#define INC V15 +#define X0 V16 +#define X1 V17 +#define X2 V18 +#define X3 V19 +#define X4 V20 +#define X5 V21 +#define X6 V22 +#define X7 V23 +#define X8 V24 +#define X9 V25 +#define X10 V26 +#define X11 V27 +#define X12 V28 +#define X13 V29 +#define X14 V30 +#define X15 V31 + +#define NUM_ROUNDS 20 + +#define ROUND4(a0, a1, a2, a3, b0, b1, b2, b3, c0, c1, c2, c3, d0, d1, d2, d3) \ + VAF a1, a0, a0 \ + VAF b1, b0, b0 \ + VAF c1, c0, c0 \ + VAF d1, d0, d0 \ + VX a0, a2, a2 \ + VX b0, b2, b2 \ + VX c0, c2, c2 \ + VX d0, d2, d2 \ + VERLLF $16, a2, a2 \ + VERLLF $16, b2, b2 \ + VERLLF $16, c2, c2 \ + VERLLF $16, d2, d2 \ + VAF a2, a3, a3 \ + VAF b2, b3, b3 \ + VAF c2, c3, c3 \ + VAF d2, d3, d3 \ + VX a3, a1, a1 \ + VX b3, b1, b1 \ + VX c3, c1, c1 \ + VX d3, d1, d1 \ + VERLLF $12, a1, a1 \ + VERLLF $12, b1, b1 \ + VERLLF $12, c1, c1 \ + VERLLF $12, d1, d1 \ + VAF a1, a0, a0 \ + VAF b1, b0, b0 \ + VAF c1, c0, c0 \ + VAF d1, d0, d0 \ + VX a0, a2, a2 \ + VX b0, b2, b2 \ + VX c0, c2, c2 \ + VX d0, d2, d2 \ + VERLLF $8, a2, a2 \ + VERLLF $8, b2, b2 \ + VERLLF $8, c2, c2 \ + VERLLF $8, d2, d2 \ + VAF a2, a3, a3 \ + VAF b2, b3, b3 \ + VAF c2, c3, c3 \ + VAF d2, d3, d3 \ + VX a3, a1, a1 \ + VX b3, b1, b1 \ + VX c3, c1, c1 \ + VX d3, d1, d1 \ + VERLLF $7, a1, a1 \ + VERLLF $7, b1, b1 \ + VERLLF $7, c1, c1 \ + VERLLF $7, d1, d1 + +#define PERMUTE(mask, v0, v1, v2, v3) \ + VPERM v0, v0, mask, v0 \ + VPERM v1, v1, mask, v1 \ + VPERM v2, v2, mask, v2 \ + VPERM v3, v3, mask, v3 + +#define ADDV(x, v0, v1, v2, v3) \ + VAF x, v0, v0 \ + VAF x, v1, v1 \ + VAF x, v2, v2 \ + VAF x, v3, v3 + +#define XORV(off, dst, src, v0, v1, v2, v3) \ + VLM off(src), M0, M3 \ + PERMUTE(BSWAP, v0, v1, v2, v3) \ + VX v0, M0, M0 \ + VX v1, M1, M1 \ + VX v2, M2, M2 \ + VX v3, M3, M3 \ + VSTM M0, M3, off(dst) + +#define SHUFFLE(a, b, c, d, t, u, v, w) \ + VMRHF a, c, t \ // t = {a[0], c[0], a[1], c[1]} + VMRHF b, d, u \ // u = {b[0], d[0], b[1], d[1]} + VMRLF a, c, v \ // v = {a[2], c[2], a[3], c[3]} + VMRLF b, d, w \ // w = {b[2], d[2], b[3], d[3]} + VMRHF t, u, a \ // a = {a[0], b[0], c[0], d[0]} + VMRLF t, u, b \ // b = {a[1], b[1], c[1], d[1]} + VMRHF v, w, c \ // c = {a[2], b[2], c[2], d[2]} + VMRLF v, w, d // d = {a[3], b[3], c[3], d[3]} + +// func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32, buf *[256]byte, len *int) +TEXT ·xorKeyStreamVX(SB), NOSPLIT, $0 + MOVD $·constants<>(SB), R1 + MOVD dst+0(FP), R2 // R2=&dst[0] + LMG src+24(FP), R3, R4 // R3=&src[0] R4=len(src) + MOVD key+48(FP), R5 // R5=key + MOVD nonce+56(FP), R6 // R6=nonce + MOVD counter+64(FP), R7 // R7=counter + MOVD buf+72(FP), R8 // R8=buf + MOVD len+80(FP), R9 // R9=len + + // load BSWAP and J0 + VLM (R1), BSWAP, J0 + + // set up tail buffer + ADD $-1, R4, R12 + MOVBZ R12, R12 + CMPUBEQ R12, $255, aligned + MOVD R4, R1 + AND $~255, R1 + MOVD $(R3)(R1*1), R1 + EXRL $·mvcSrcToBuf(SB), R12 + MOVD $255, R0 + SUB R12, R0 + MOVD R0, (R9) // update len + +aligned: + // setup + MOVD $95, R0 + VLM (R5), KEY0, KEY1 + VLL R0, (R6), NONCE + VZERO M0 + VLEIB $7, $32, M0 + VSRLB M0, NONCE, NONCE + + // initialize counter values + VLREPF (R7), CTR + VZERO INC + VLEIF $1, $1, INC + VLEIF $2, $2, INC + VLEIF $3, $3, INC + VAF INC, CTR, CTR + VREPIF $4, INC + +chacha: + VREPF $0, J0, X0 + VREPF $1, J0, X1 + VREPF $2, J0, X2 + VREPF $3, J0, X3 + VREPF $0, KEY0, X4 + VREPF $1, KEY0, X5 + VREPF $2, KEY0, X6 + VREPF $3, KEY0, X7 + VREPF $0, KEY1, X8 + VREPF $1, KEY1, X9 + VREPF $2, KEY1, X10 + VREPF $3, KEY1, X11 + VLR CTR, X12 + VREPF $1, NONCE, X13 + VREPF $2, NONCE, X14 + VREPF $3, NONCE, X15 + + MOVD $(NUM_ROUNDS/2), R1 + +loop: + ROUND4(X0, X4, X12, X8, X1, X5, X13, X9, X2, X6, X14, X10, X3, X7, X15, X11) + ROUND4(X0, X5, X15, X10, X1, X6, X12, X11, X2, X7, X13, X8, X3, X4, X14, X9) + + ADD $-1, R1 + BNE loop + + // decrement length + ADD $-256, R4 + BLT tail + +continue: + // rearrange vectors + SHUFFLE(X0, X1, X2, X3, M0, M1, M2, M3) + ADDV(J0, X0, X1, X2, X3) + SHUFFLE(X4, X5, X6, X7, M0, M1, M2, M3) + ADDV(KEY0, X4, X5, X6, X7) + SHUFFLE(X8, X9, X10, X11, M0, M1, M2, M3) + ADDV(KEY1, X8, X9, X10, X11) + VAF CTR, X12, X12 + SHUFFLE(X12, X13, X14, X15, M0, M1, M2, M3) + ADDV(NONCE, X12, X13, X14, X15) + + // increment counters + VAF INC, CTR, CTR + + // xor keystream with plaintext + XORV(0*64, R2, R3, X0, X4, X8, X12) + XORV(1*64, R2, R3, X1, X5, X9, X13) + XORV(2*64, R2, R3, X2, X6, X10, X14) + XORV(3*64, R2, R3, X3, X7, X11, X15) + + // increment pointers + MOVD $256(R2), R2 + MOVD $256(R3), R3 + + CMPBNE R4, $0, chacha + CMPUBEQ R12, $255, return + EXRL $·mvcBufToDst(SB), R12 // len was updated during setup + +return: + VSTEF $0, CTR, (R7) + RET + +tail: + MOVD R2, R9 + MOVD R8, R2 + MOVD R8, R3 + MOVD $0, R4 + JMP continue + +// func hasVectorFacility() bool +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/internal/chacha20/xor.go b/vendor/golang.org/x/crypto/internal/chacha20/xor.go new file mode 100644 index 0000000000..9c5ba0b33a --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/chacha20/xor.go @@ -0,0 +1,43 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found src the LICENSE file. + +package chacha20 + +import ( + "runtime" +) + +// Platforms that have fast unaligned 32-bit little endian accesses. +const unaligned = runtime.GOARCH == "386" || + runtime.GOARCH == "amd64" || + runtime.GOARCH == "arm64" || + runtime.GOARCH == "ppc64le" || + runtime.GOARCH == "s390x" + +// xor reads a little endian uint32 from src, XORs it with u and +// places the result in little endian byte order in dst. +func xor(dst, src []byte, u uint32) { + _, _ = src[3], dst[3] // eliminate bounds checks + if unaligned { + // The compiler should optimize this code into + // 32-bit unaligned little endian loads and stores. + // TODO: delete once the compiler does a reliably + // good job with the generic code below. + // See issue #25111 for more details. + v := uint32(src[0]) + v |= uint32(src[1]) << 8 + v |= uint32(src[2]) << 16 + v |= uint32(src[3]) << 24 + v ^= u + dst[0] = byte(v) + dst[1] = byte(v >> 8) + dst[2] = byte(v >> 16) + dst[3] = byte(v >> 24) + } else { + dst[0] = src[0] ^ byte(u) + dst[1] = src[1] ^ byte(u>>8) + dst[2] = src[2] ^ byte(u>>16) + dst[3] = src[3] ^ byte(u>>24) + } +} 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 0000000000..f38797bfa1 --- /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 0000000000..0cc4a8a642 --- /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/openpgp/keys.go b/vendor/golang.org/x/crypto/openpgp/keys.go index 68b14c6ae6..3e2518600e 100644 --- a/vendor/golang.org/x/crypto/openpgp/keys.go +++ b/vendor/golang.org/x/crypto/openpgp/keys.go @@ -325,16 +325,14 @@ func ReadEntity(packets *packet.Reader) (*Entity, error) { if e.PrivateKey, ok = p.(*packet.PrivateKey); !ok { packets.Unread(p) return nil, errors.StructuralError("first packet was not a public/private key") - } else { - e.PrimaryKey = &e.PrivateKey.PublicKey } + e.PrimaryKey = &e.PrivateKey.PublicKey } if !e.PrimaryKey.PubKeyAlgo.CanSign() { return nil, errors.StructuralError("primary key cannot be used for signatures") } - var current *Identity var revocations []*packet.Signature EachPacket: for { @@ -347,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 { @@ -381,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) @@ -426,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 @@ -487,7 +531,7 @@ func NewEntity(name, comment, email string, config *packet.Config) (*Entity, err } isPrimaryId := true e.Identities[uid.Id] = &Identity{ - Name: uid.Name, + Name: uid.Id, UserId: uid, SelfSignature: &packet.Signature{ CreationTime: currentTime, @@ -501,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. @@ -508,6 +556,11 @@ func NewEntity(name, comment, email string, config *packet.Config) (*Entity, err e.Identities[uid.Id].SelfSignature.PreferredHash = []uint8{hashToHashId(config.DefaultHash)} } + // Likewise for DefaultCipher. + if config != nil && config.DefaultCipher != 0 { + e.Identities[uid.Id].SelfSignature.PreferredSymmetric = []uint8{uint8(config.DefaultCipher)} + } + e.Subkeys = make([]Subkey, 1) e.Subkeys[0] = Subkey{ PublicKey: packet.NewRSAPublicKey(currentTime, &encryptingPriv.PublicKey), @@ -525,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) @@ -569,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/packet/encrypted_key.go b/vendor/golang.org/x/crypto/openpgp/packet/encrypted_key.go index 266840d05a..02b372cf37 100644 --- a/vendor/golang.org/x/crypto/openpgp/packet/encrypted_key.go +++ b/vendor/golang.org/x/crypto/openpgp/packet/encrypted_key.go @@ -42,12 +42,18 @@ func (e *EncryptedKey) parse(r io.Reader) (err error) { switch e.Algo { case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: e.encryptedMPI1.bytes, e.encryptedMPI1.bitLength, err = readMPI(r) + if err != nil { + return + } case PubKeyAlgoElGamal: e.encryptedMPI1.bytes, e.encryptedMPI1.bitLength, err = readMPI(r) if err != nil { return } e.encryptedMPI2.bytes, e.encryptedMPI2.bitLength, err = readMPI(r) + if err != nil { + return + } } _, err = consumeAll(r) return @@ -72,7 +78,8 @@ func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error { // padding oracle attacks. switch priv.PubKeyAlgo { case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: - b, err = rsa.DecryptPKCS1v15(config.Random(), priv.PrivateKey.(*rsa.PrivateKey), e.encryptedMPI1.bytes) + k := priv.PrivateKey.(*rsa.PrivateKey) + b, err = rsa.DecryptPKCS1v15(config.Random(), k, padToKeySize(&k.PublicKey, e.encryptedMPI1.bytes)) case PubKeyAlgoElGamal: c1 := new(big.Int).SetBytes(e.encryptedMPI1.bytes) c2 := new(big.Int).SetBytes(e.encryptedMPI2.bytes) diff --git a/vendor/golang.org/x/crypto/openpgp/packet/packet.go b/vendor/golang.org/x/crypto/openpgp/packet/packet.go index 3eded93f04..5af64c5421 100644 --- a/vendor/golang.org/x/crypto/openpgp/packet/packet.go +++ b/vendor/golang.org/x/crypto/openpgp/packet/packet.go @@ -11,10 +11,12 @@ import ( "crypto/aes" "crypto/cipher" "crypto/des" - "golang.org/x/crypto/cast5" - "golang.org/x/crypto/openpgp/errors" + "crypto/rsa" "io" "math/big" + + "golang.org/x/crypto/cast5" + "golang.org/x/crypto/openpgp/errors" ) // readFull is the same as io.ReadFull except that reading zero bytes returns @@ -402,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 @@ -500,19 +504,17 @@ func readMPI(r io.Reader) (mpi []byte, bitLength uint16, err error) { numBytes := (int(bitLength) + 7) / 8 mpi = make([]byte, numBytes) _, err = readFull(r, mpi) - return -} - -// mpiLength returns the length of the given *big.Int when serialized as an -// MPI. -func mpiLength(n *big.Int) (mpiLengthInBytes int) { - mpiLengthInBytes = 2 /* MPI length */ - mpiLengthInBytes += (n.BitLen() + 7) / 8 + // According to RFC 4880 3.2. we should check that the MPI has no leading + // zeroes (at least when not an encrypted MPI?), but this implementation + // does generate leading zeroes, so we keep accepting them. return } // writeMPI serializes a big integer to w. func writeMPI(w io.Writer, bitLength uint16, mpiBytes []byte) (err error) { + // Note that we can produce leading zeroes, in violation of RFC 4880 3.2. + // Implementations seem to be tolerant of them, and stripping them would + // make it complex to guarantee matching re-serialization. _, err = w.Write([]byte{byte(bitLength >> 8), byte(bitLength)}) if err == nil { _, err = w.Write(mpiBytes) @@ -525,6 +527,18 @@ func writeBig(w io.Writer, i *big.Int) error { return writeMPI(w, uint16(i.BitLen()), i.Bytes()) } +// padToKeySize left-pads a MPI with zeroes to match the length of the +// specified RSA public. +func padToKeySize(pub *rsa.PublicKey, b []byte) []byte { + k := (pub.N.BitLen() + 7) / 8 + if len(b) >= k { + return b + } + bb := make([]byte, k) + copy(bb[len(bb)-len(b):], b) + return bb +} + // CompressionAlgo Represents the different compression algorithms // supported by OpenPGP (except for BZIP2, which is not currently // supported). See Section 9.3 of RFC 4880. 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 34734cc63d..bd31cceac6 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/public_key.go b/vendor/golang.org/x/crypto/openpgp/packet/public_key.go index ead26233dd..fcd5f52519 100644 --- a/vendor/golang.org/x/crypto/openpgp/packet/public_key.go +++ b/vendor/golang.org/x/crypto/openpgp/packet/public_key.go @@ -244,7 +244,12 @@ func NewECDSAPublicKey(creationTime time.Time, pub *ecdsa.PublicKey) *PublicKey } pk.ec.p.bytes = elliptic.Marshal(pub.Curve, pub.X, pub.Y) - pk.ec.p.bitLength = uint16(8 * len(pk.ec.p.bytes)) + + // The bit length is 3 (for the 0x04 specifying an uncompressed key) + // plus two field elements (for x and y), which are rounded up to the + // nearest byte. See https://tools.ietf.org/html/rfc6637#section-6 + fieldBytes := (pub.Curve.Params().BitSize + 7) & ^7 + pk.ec.p.bitLength = uint16(3 + fieldBytes + fieldBytes) pk.setFingerPrintAndKeyId() return pk @@ -515,7 +520,7 @@ func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err erro switch pk.PubKeyAlgo { case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: rsaPublicKey, _ := pk.PublicKey.(*rsa.PublicKey) - err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, sig.RSASignature.bytes) + err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, padToKeySize(rsaPublicKey, sig.RSASignature.bytes)) if err != nil { return errors.SignatureError("RSA verification failure") } @@ -566,7 +571,7 @@ func (pk *PublicKey) VerifySignatureV3(signed hash.Hash, sig *SignatureV3) (err switch pk.PubKeyAlgo { case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: rsaPublicKey := pk.PublicKey.(*rsa.PublicKey) - if err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, sig.RSASignature.bytes); err != nil { + if err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, padToKeySize(rsaPublicKey, sig.RSASignature.bytes)); err != nil { return errors.SignatureError("RSA verification failure") } return diff --git a/vendor/golang.org/x/crypto/openpgp/packet/signature.go b/vendor/golang.org/x/crypto/openpgp/packet/signature.go index 6ce0cbedbe..b2a24a5323 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 96a2b382a1..d19ffbc786 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/write.go b/vendor/golang.org/x/crypto/openpgp/write.go index 65a304cc86..4ee71784eb 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/poly1305/poly1305.go b/vendor/golang.org/x/crypto/poly1305/poly1305.go new file mode 100644 index 0000000000..f562fa5712 --- /dev/null +++ b/vendor/golang.org/x/crypto/poly1305/poly1305.go @@ -0,0 +1,33 @@ +// Copyright 2012 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 implements Poly1305 one-time message authentication code as +specified in https://cr.yp.to/mac/poly1305-20050329.pdf. + +Poly1305 is a fast, one-time authentication function. It is infeasible for an +attacker to generate an authenticator for a message without the key. However, a +key must only be used for a single message. Authenticating two different +messages with the same key allows an attacker to forge authenticators for other +messages with the same key. + +Poly1305 was originally coupled with AES in order to make Poly1305-AES. AES was +used with a fixed key in order to generate one-time keys from an nonce. +However, in this package AES isn't used and the one-time key is specified +directly. +*/ +package poly1305 // import "golang.org/x/crypto/poly1305" + +import "crypto/subtle" + +// TagSize is the size, in bytes, of a poly1305 authenticator. +const TagSize = 16 + +// Verify returns true if mac is a valid authenticator for m with the given +// key. +func Verify(mac *[16]byte, m []byte, key *[32]byte) bool { + var tmp [16]byte + Sum(&tmp, m, key) + return subtle.ConstantTimeCompare(tmp[:], mac[:]) == 1 +} diff --git a/vendor/golang.org/x/crypto/poly1305/sum_amd64.go b/vendor/golang.org/x/crypto/poly1305/sum_amd64.go new file mode 100644 index 0000000000..4dd72fe799 --- /dev/null +++ b/vendor/golang.org/x/crypto/poly1305/sum_amd64.go @@ -0,0 +1,22 @@ +// Copyright 2012 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,!gccgo,!appengine + +package poly1305 + +// This function is implemented in sum_amd64.s +//go:noescape +func poly1305(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) { + var mPtr *byte + if len(m) > 0 { + mPtr = &m[0] + } + poly1305(out, mPtr, uint64(len(m)), key) +} diff --git a/vendor/golang.org/x/crypto/poly1305/sum_amd64.s b/vendor/golang.org/x/crypto/poly1305/sum_amd64.s new file mode 100644 index 0000000000..2edae63828 --- /dev/null +++ b/vendor/golang.org/x/crypto/poly1305/sum_amd64.s @@ -0,0 +1,125 @@ +// Copyright 2012 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,!gccgo,!appengine + +#include "textflag.h" + +#define POLY1305_ADD(msg, h0, h1, h2) \ + ADDQ 0(msg), h0; \ + ADCQ 8(msg), h1; \ + ADCQ $1, h2; \ + LEAQ 16(msg), msg + +#define POLY1305_MUL(h0, h1, h2, r0, r1, t0, t1, t2, t3) \ + MOVQ r0, AX; \ + MULQ h0; \ + MOVQ AX, t0; \ + MOVQ DX, t1; \ + MOVQ r0, AX; \ + MULQ h1; \ + ADDQ AX, t1; \ + ADCQ $0, DX; \ + MOVQ r0, t2; \ + IMULQ h2, t2; \ + ADDQ DX, t2; \ + \ + MOVQ r1, AX; \ + MULQ h0; \ + ADDQ AX, t1; \ + ADCQ $0, DX; \ + MOVQ DX, h0; \ + MOVQ r1, t3; \ + IMULQ h2, t3; \ + MOVQ r1, AX; \ + MULQ h1; \ + ADDQ AX, t2; \ + ADCQ DX, t3; \ + ADDQ h0, t2; \ + ADCQ $0, t3; \ + \ + MOVQ t0, h0; \ + MOVQ t1, h1; \ + MOVQ t2, h2; \ + ANDQ $3, h2; \ + MOVQ t2, t0; \ + ANDQ $0xFFFFFFFFFFFFFFFC, t0; \ + ADDQ t0, h0; \ + ADCQ t3, h1; \ + ADCQ $0, h2; \ + SHRQ $2, t3, t2; \ + SHRQ $2, t3; \ + ADDQ t2, h0; \ + ADCQ t3, h1; \ + ADCQ $0, h2 + +DATA ·poly1305Mask<>+0x00(SB)/8, $0x0FFFFFFC0FFFFFFF +DATA ·poly1305Mask<>+0x08(SB)/8, $0x0FFFFFFC0FFFFFFC +GLOBL ·poly1305Mask<>(SB), RODATA, $16 + +// func poly1305(out *[16]byte, m *byte, mlen uint64, key *[32]key) +TEXT ·poly1305(SB), $0-32 + MOVQ out+0(FP), DI + MOVQ m+8(FP), SI + MOVQ mlen+16(FP), R15 + MOVQ key+24(FP), AX + + MOVQ 0(AX), R11 + MOVQ 8(AX), R12 + ANDQ ·poly1305Mask<>(SB), R11 // r0 + ANDQ ·poly1305Mask<>+8(SB), R12 // r1 + XORQ R8, R8 // h0 + XORQ R9, R9 // h1 + XORQ R10, R10 // h2 + + CMPQ R15, $16 + JB bytes_between_0_and_15 + +loop: + POLY1305_ADD(SI, R8, R9, R10) + +multiply: + POLY1305_MUL(R8, R9, R10, R11, R12, BX, CX, R13, R14) + SUBQ $16, R15 + CMPQ R15, $16 + JAE loop + +bytes_between_0_and_15: + TESTQ R15, R15 + JZ done + MOVQ $1, BX + XORQ CX, CX + XORQ R13, R13 + ADDQ R15, SI + +flush_buffer: + SHLQ $8, BX, CX + SHLQ $8, BX + MOVB -1(SI), R13 + XORQ R13, BX + DECQ SI + DECQ R15 + JNZ flush_buffer + + ADDQ BX, R8 + ADCQ CX, R9 + ADCQ $0, R10 + MOVQ $16, R15 + JMP multiply + +done: + MOVQ R8, AX + MOVQ R9, BX + SUBQ $0xFFFFFFFFFFFFFFFB, AX + SBBQ $0xFFFFFFFFFFFFFFFF, BX + SBBQ $3, R10 + CMOVQCS R8, AX + CMOVQCS R9, BX + MOVQ key+24(FP), R8 + ADDQ 16(R8), AX + ADCQ 24(R8), BX + + MOVQ AX, 0(DI) + MOVQ BX, 8(DI) + RET diff --git a/vendor/golang.org/x/crypto/poly1305/sum_arm.go b/vendor/golang.org/x/crypto/poly1305/sum_arm.go new file mode 100644 index 0000000000..5dc321c2f3 --- /dev/null +++ b/vendor/golang.org/x/crypto/poly1305/sum_arm.go @@ -0,0 +1,22 @@ +// 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 arm,!gccgo,!appengine,!nacl + +package poly1305 + +// This function is implemented in sum_arm.s +//go:noescape +func poly1305_auth_armv6(out *[16]byte, m *byte, mlen uint32, 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) { + var mPtr *byte + if len(m) > 0 { + mPtr = &m[0] + } + poly1305_auth_armv6(out, mPtr, uint32(len(m)), key) +} diff --git a/vendor/golang.org/x/crypto/poly1305/sum_arm.s b/vendor/golang.org/x/crypto/poly1305/sum_arm.s new file mode 100644 index 0000000000..f70b4ac484 --- /dev/null +++ b/vendor/golang.org/x/crypto/poly1305/sum_arm.s @@ -0,0 +1,427 @@ +// 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 arm,!gccgo,!appengine,!nacl + +#include "textflag.h" + +// This code was translated into a form compatible with 5a from the public +// domain source by Andrew Moon: github.com/floodyberry/poly1305-opt/blob/master/app/extensions/poly1305. + +DATA ·poly1305_init_constants_armv6<>+0x00(SB)/4, $0x3ffffff +DATA ·poly1305_init_constants_armv6<>+0x04(SB)/4, $0x3ffff03 +DATA ·poly1305_init_constants_armv6<>+0x08(SB)/4, $0x3ffc0ff +DATA ·poly1305_init_constants_armv6<>+0x0c(SB)/4, $0x3f03fff +DATA ·poly1305_init_constants_armv6<>+0x10(SB)/4, $0x00fffff +GLOBL ·poly1305_init_constants_armv6<>(SB), 8, $20 + +// Warning: the linker may use R11 to synthesize certain instructions. Please +// take care and verify that no synthetic instructions use it. + +TEXT poly1305_init_ext_armv6<>(SB), NOSPLIT, $0 + // Needs 16 bytes of stack and 64 bytes of space pointed to by R0. (It + // might look like it's only 60 bytes of space but the final four bytes + // will be written by another function.) We need to skip over four + // bytes of stack because that's saving the value of 'g'. + ADD $4, R13, R8 + MOVM.IB [R4-R7], (R8) + MOVM.IA.W (R1), [R2-R5] + MOVW $·poly1305_init_constants_armv6<>(SB), R7 + MOVW R2, R8 + MOVW R2>>26, R9 + MOVW R3>>20, g + MOVW R4>>14, R11 + MOVW R5>>8, R12 + ORR R3<<6, R9, R9 + ORR R4<<12, g, g + ORR R5<<18, R11, R11 + MOVM.IA (R7), [R2-R6] + AND R8, R2, R2 + AND R9, R3, R3 + AND g, R4, R4 + AND R11, R5, R5 + AND R12, R6, R6 + MOVM.IA.W [R2-R6], (R0) + EOR R2, R2, R2 + EOR R3, R3, R3 + EOR R4, R4, R4 + EOR R5, R5, R5 + EOR R6, R6, R6 + MOVM.IA.W [R2-R6], (R0) + MOVM.IA.W (R1), [R2-R5] + MOVM.IA [R2-R6], (R0) + ADD $20, R13, R0 + MOVM.DA (R0), [R4-R7] + RET + +#define MOVW_UNALIGNED(Rsrc, Rdst, Rtmp, offset) \ + MOVBU (offset+0)(Rsrc), Rtmp; \ + MOVBU Rtmp, (offset+0)(Rdst); \ + MOVBU (offset+1)(Rsrc), Rtmp; \ + MOVBU Rtmp, (offset+1)(Rdst); \ + MOVBU (offset+2)(Rsrc), Rtmp; \ + MOVBU Rtmp, (offset+2)(Rdst); \ + MOVBU (offset+3)(Rsrc), Rtmp; \ + MOVBU Rtmp, (offset+3)(Rdst) + +TEXT poly1305_blocks_armv6<>(SB), NOSPLIT, $0 + // Needs 24 bytes of stack for saved registers and then 88 bytes of + // scratch space after that. We assume that 24 bytes at (R13) have + // already been used: four bytes for the link register saved in the + // prelude of poly1305_auth_armv6, four bytes for saving the value of g + // in that function and 16 bytes of scratch space used around + // poly1305_finish_ext_armv6_skip1. + ADD $24, R13, R12 + MOVM.IB [R4-R8, R14], (R12) + MOVW R0, 88(R13) + MOVW R1, 92(R13) + MOVW R2, 96(R13) + MOVW R1, R14 + MOVW R2, R12 + MOVW 56(R0), R8 + WORD $0xe1180008 // TST R8, R8 not working see issue 5921 + EOR R6, R6, R6 + MOVW.EQ $(1<<24), R6 + MOVW R6, 84(R13) + ADD $116, R13, g + MOVM.IA (R0), [R0-R9] + MOVM.IA [R0-R4], (g) + CMP $16, R12 + BLO poly1305_blocks_armv6_done + +poly1305_blocks_armv6_mainloop: + WORD $0xe31e0003 // TST R14, #3 not working see issue 5921 + BEQ poly1305_blocks_armv6_mainloop_aligned + ADD $100, R13, g + MOVW_UNALIGNED(R14, g, R0, 0) + MOVW_UNALIGNED(R14, g, R0, 4) + MOVW_UNALIGNED(R14, g, R0, 8) + MOVW_UNALIGNED(R14, g, R0, 12) + MOVM.IA (g), [R0-R3] + ADD $16, R14 + B poly1305_blocks_armv6_mainloop_loaded + +poly1305_blocks_armv6_mainloop_aligned: + MOVM.IA.W (R14), [R0-R3] + +poly1305_blocks_armv6_mainloop_loaded: + MOVW R0>>26, g + MOVW R1>>20, R11 + MOVW R2>>14, R12 + MOVW R14, 92(R13) + MOVW R3>>8, R4 + ORR R1<<6, g, g + ORR R2<<12, R11, R11 + ORR R3<<18, R12, R12 + BIC $0xfc000000, R0, R0 + BIC $0xfc000000, g, g + MOVW 84(R13), R3 + BIC $0xfc000000, R11, R11 + BIC $0xfc000000, R12, R12 + ADD R0, R5, R5 + ADD g, R6, R6 + ORR R3, R4, R4 + ADD R11, R7, R7 + ADD $116, R13, R14 + ADD R12, R8, R8 + ADD R4, R9, R9 + MOVM.IA (R14), [R0-R4] + MULLU R4, R5, (R11, g) + MULLU R3, R5, (R14, R12) + MULALU R3, R6, (R11, g) + MULALU R2, R6, (R14, R12) + MULALU R2, R7, (R11, g) + MULALU R1, R7, (R14, R12) + ADD R4<<2, R4, R4 + ADD R3<<2, R3, R3 + MULALU R1, R8, (R11, g) + MULALU R0, R8, (R14, R12) + MULALU R0, R9, (R11, g) + MULALU R4, R9, (R14, R12) + MOVW g, 76(R13) + MOVW R11, 80(R13) + MOVW R12, 68(R13) + MOVW R14, 72(R13) + MULLU R2, R5, (R11, g) + MULLU R1, R5, (R14, R12) + MULALU R1, R6, (R11, g) + MULALU R0, R6, (R14, R12) + MULALU R0, R7, (R11, g) + MULALU R4, R7, (R14, R12) + ADD R2<<2, R2, R2 + ADD R1<<2, R1, R1 + MULALU R4, R8, (R11, g) + MULALU R3, R8, (R14, R12) + MULALU R3, R9, (R11, g) + MULALU R2, R9, (R14, R12) + MOVW g, 60(R13) + MOVW R11, 64(R13) + MOVW R12, 52(R13) + MOVW R14, 56(R13) + MULLU R0, R5, (R11, g) + MULALU R4, R6, (R11, g) + MULALU R3, R7, (R11, g) + MULALU R2, R8, (R11, g) + MULALU R1, R9, (R11, g) + ADD $52, R13, R0 + MOVM.IA (R0), [R0-R7] + MOVW g>>26, R12 + MOVW R4>>26, R14 + ORR R11<<6, R12, R12 + ORR R5<<6, R14, R14 + BIC $0xfc000000, g, g + BIC $0xfc000000, R4, R4 + ADD.S R12, R0, R0 + ADC $0, R1, R1 + ADD.S R14, R6, R6 + ADC $0, R7, R7 + MOVW R0>>26, R12 + MOVW R6>>26, R14 + ORR R1<<6, R12, R12 + ORR R7<<6, R14, R14 + BIC $0xfc000000, R0, R0 + BIC $0xfc000000, R6, R6 + ADD R14<<2, R14, R14 + ADD.S R12, R2, R2 + ADC $0, R3, R3 + ADD R14, g, g + MOVW R2>>26, R12 + MOVW g>>26, R14 + ORR R3<<6, R12, R12 + BIC $0xfc000000, g, R5 + BIC $0xfc000000, R2, R7 + ADD R12, R4, R4 + ADD R14, R0, R0 + MOVW R4>>26, R12 + BIC $0xfc000000, R4, R8 + ADD R12, R6, R9 + MOVW 96(R13), R12 + MOVW 92(R13), R14 + MOVW R0, R6 + CMP $32, R12 + SUB $16, R12, R12 + MOVW R12, 96(R13) + BHS poly1305_blocks_armv6_mainloop + +poly1305_blocks_armv6_done: + MOVW 88(R13), R12 + MOVW R5, 20(R12) + MOVW R6, 24(R12) + MOVW R7, 28(R12) + MOVW R8, 32(R12) + MOVW R9, 36(R12) + ADD $48, R13, R0 + MOVM.DA (R0), [R4-R8, R14] + RET + +#define MOVHUP_UNALIGNED(Rsrc, Rdst, Rtmp) \ + MOVBU.P 1(Rsrc), Rtmp; \ + MOVBU.P Rtmp, 1(Rdst); \ + MOVBU.P 1(Rsrc), Rtmp; \ + MOVBU.P Rtmp, 1(Rdst) + +#define MOVWP_UNALIGNED(Rsrc, Rdst, Rtmp) \ + MOVHUP_UNALIGNED(Rsrc, Rdst, Rtmp); \ + MOVHUP_UNALIGNED(Rsrc, Rdst, Rtmp) + +// func poly1305_auth_armv6(out *[16]byte, m *byte, mlen uint32, key *[32]key) +TEXT ·poly1305_auth_armv6(SB), $196-16 + // The value 196, just above, is the sum of 64 (the size of the context + // structure) and 132 (the amount of stack needed). + // + // At this point, the stack pointer (R13) has been moved down. It + // points to the saved link register and there's 196 bytes of free + // space above it. + // + // The stack for this function looks like: + // + // +--------------------- + // | + // | 64 bytes of context structure + // | + // +--------------------- + // | + // | 112 bytes for poly1305_blocks_armv6 + // | + // +--------------------- + // | 16 bytes of final block, constructed at + // | poly1305_finish_ext_armv6_skip8 + // +--------------------- + // | four bytes of saved 'g' + // +--------------------- + // | lr, saved by prelude <- R13 points here + // +--------------------- + MOVW g, 4(R13) + + MOVW out+0(FP), R4 + MOVW m+4(FP), R5 + MOVW mlen+8(FP), R6 + MOVW key+12(FP), R7 + + ADD $136, R13, R0 // 136 = 4 + 4 + 16 + 112 + MOVW R7, R1 + + // poly1305_init_ext_armv6 will write to the stack from R13+4, but + // that's ok because none of the other values have been written yet. + BL poly1305_init_ext_armv6<>(SB) + BIC.S $15, R6, R2 + BEQ poly1305_auth_armv6_noblocks + ADD $136, R13, R0 + MOVW R5, R1 + ADD R2, R5, R5 + SUB R2, R6, R6 + BL poly1305_blocks_armv6<>(SB) + +poly1305_auth_armv6_noblocks: + ADD $136, R13, R0 + MOVW R5, R1 + MOVW R6, R2 + MOVW R4, R3 + + MOVW R0, R5 + MOVW R1, R6 + MOVW R2, R7 + MOVW R3, R8 + AND.S R2, R2, R2 + BEQ poly1305_finish_ext_armv6_noremaining + EOR R0, R0 + ADD $8, R13, R9 // 8 = offset to 16 byte scratch space + MOVW R0, (R9) + MOVW R0, 4(R9) + MOVW R0, 8(R9) + MOVW R0, 12(R9) + WORD $0xe3110003 // TST R1, #3 not working see issue 5921 + BEQ poly1305_finish_ext_armv6_aligned + WORD $0xe3120008 // TST R2, #8 not working see issue 5921 + BEQ poly1305_finish_ext_armv6_skip8 + MOVWP_UNALIGNED(R1, R9, g) + MOVWP_UNALIGNED(R1, R9, g) + +poly1305_finish_ext_armv6_skip8: + WORD $0xe3120004 // TST $4, R2 not working see issue 5921 + BEQ poly1305_finish_ext_armv6_skip4 + MOVWP_UNALIGNED(R1, R9, g) + +poly1305_finish_ext_armv6_skip4: + WORD $0xe3120002 // TST $2, R2 not working see issue 5921 + BEQ poly1305_finish_ext_armv6_skip2 + MOVHUP_UNALIGNED(R1, R9, g) + B poly1305_finish_ext_armv6_skip2 + +poly1305_finish_ext_armv6_aligned: + WORD $0xe3120008 // TST R2, #8 not working see issue 5921 + BEQ poly1305_finish_ext_armv6_skip8_aligned + MOVM.IA.W (R1), [g-R11] + MOVM.IA.W [g-R11], (R9) + +poly1305_finish_ext_armv6_skip8_aligned: + WORD $0xe3120004 // TST $4, R2 not working see issue 5921 + BEQ poly1305_finish_ext_armv6_skip4_aligned + MOVW.P 4(R1), g + MOVW.P g, 4(R9) + +poly1305_finish_ext_armv6_skip4_aligned: + WORD $0xe3120002 // TST $2, R2 not working see issue 5921 + BEQ poly1305_finish_ext_armv6_skip2 + MOVHU.P 2(R1), g + MOVH.P g, 2(R9) + +poly1305_finish_ext_armv6_skip2: + WORD $0xe3120001 // TST $1, R2 not working see issue 5921 + BEQ poly1305_finish_ext_armv6_skip1 + MOVBU.P 1(R1), g + MOVBU.P g, 1(R9) + +poly1305_finish_ext_armv6_skip1: + MOVW $1, R11 + MOVBU R11, 0(R9) + MOVW R11, 56(R5) + MOVW R5, R0 + ADD $8, R13, R1 + MOVW $16, R2 + BL poly1305_blocks_armv6<>(SB) + +poly1305_finish_ext_armv6_noremaining: + MOVW 20(R5), R0 + MOVW 24(R5), R1 + MOVW 28(R5), R2 + MOVW 32(R5), R3 + MOVW 36(R5), R4 + MOVW R4>>26, R12 + BIC $0xfc000000, R4, R4 + ADD R12<<2, R12, R12 + ADD R12, R0, R0 + MOVW R0>>26, R12 + BIC $0xfc000000, R0, R0 + ADD R12, R1, R1 + MOVW R1>>26, R12 + BIC $0xfc000000, R1, R1 + ADD R12, R2, R2 + MOVW R2>>26, R12 + BIC $0xfc000000, R2, R2 + ADD R12, R3, R3 + MOVW R3>>26, R12 + BIC $0xfc000000, R3, R3 + ADD R12, R4, R4 + ADD $5, R0, R6 + MOVW R6>>26, R12 + BIC $0xfc000000, R6, R6 + ADD R12, R1, R7 + MOVW R7>>26, R12 + BIC $0xfc000000, R7, R7 + ADD R12, R2, g + MOVW g>>26, R12 + BIC $0xfc000000, g, g + ADD R12, R3, R11 + MOVW $-(1<<26), R12 + ADD R11>>26, R12, R12 + BIC $0xfc000000, R11, R11 + ADD R12, R4, R9 + MOVW R9>>31, R12 + SUB $1, R12 + AND R12, R6, R6 + AND R12, R7, R7 + AND R12, g, g + AND R12, R11, R11 + AND R12, R9, R9 + MVN R12, R12 + AND R12, R0, R0 + AND R12, R1, R1 + AND R12, R2, R2 + AND R12, R3, R3 + AND R12, R4, R4 + ORR R6, R0, R0 + ORR R7, R1, R1 + ORR g, R2, R2 + ORR R11, R3, R3 + ORR R9, R4, R4 + ORR R1<<26, R0, R0 + MOVW R1>>6, R1 + ORR R2<<20, R1, R1 + MOVW R2>>12, R2 + ORR R3<<14, R2, R2 + MOVW R3>>18, R3 + ORR R4<<8, R3, R3 + MOVW 40(R5), R6 + MOVW 44(R5), R7 + MOVW 48(R5), g + MOVW 52(R5), R11 + ADD.S R6, R0, R0 + ADC.S R7, R1, R1 + ADC.S g, R2, R2 + ADC.S R11, R3, R3 + MOVM.IA [R0-R3], (R8) + MOVW R5, R12 + EOR R0, R0, R0 + EOR R1, R1, R1 + EOR R2, R2, R2 + EOR R3, R3, R3 + EOR R4, R4, R4 + EOR R5, R5, R5 + EOR R6, R6, R6 + EOR R7, R7, R7 + MOVM.IA.W [R0-R7], (R12) + MOVM.IA [R0-R7], (R12) + MOVW 4(R13), g + RET 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 0000000000..751eec5274 --- /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 new file mode 100644 index 0000000000..c4d59bd098 --- /dev/null +++ b/vendor/golang.org/x/crypto/poly1305/sum_ref.go @@ -0,0 +1,139 @@ +// Copyright 2012 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 + +import "encoding/binary" + +// 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 + ) + + r0 = uint64(binary.LittleEndian.Uint32(key[0:]) & 0x3ffffff) + r1 = uint64((binary.LittleEndian.Uint32(key[3:]) >> 2) & 0x3ffff03) + r2 = uint64((binary.LittleEndian.Uint32(key[6:]) >> 4) & 0x3ffc0ff) + r3 = uint64((binary.LittleEndian.Uint32(key[9:]) >> 6) & 0x3f03fff) + r4 = uint64((binary.LittleEndian.Uint32(key[12:]) >> 8) & 0x00fffff) + + R1, R2, R3, R4 := r1*5, r2*5, r3*5, r4*5 + + for len(msg) >= TagSize { + // h += msg + h0 += binary.LittleEndian.Uint32(msg[0:]) & 0x3ffffff + h1 += (binary.LittleEndian.Uint32(msg[3:]) >> 2) & 0x3ffffff + h2 += (binary.LittleEndian.Uint32(msg[6:]) >> 4) & 0x3ffffff + h3 += (binary.LittleEndian.Uint32(msg[9:]) >> 6) & 0x3ffffff + h4 += (binary.LittleEndian.Uint32(msg[12:]) >> 8) | (1 << 24) + + // h *= r + d0 := (uint64(h0) * r0) + (uint64(h1) * R4) + (uint64(h2) * R3) + (uint64(h3) * R2) + (uint64(h4) * R1) + d1 := (d0 >> 26) + (uint64(h0) * r1) + (uint64(h1) * r0) + (uint64(h2) * R4) + (uint64(h3) * R3) + (uint64(h4) * R2) + d2 := (d1 >> 26) + (uint64(h0) * r2) + (uint64(h1) * r1) + (uint64(h2) * r0) + (uint64(h3) * R4) + (uint64(h4) * R3) + d3 := (d2 >> 26) + (uint64(h0) * r3) + (uint64(h1) * r2) + (uint64(h2) * r1) + (uint64(h3) * r0) + (uint64(h4) * R4) + d4 := (d3 >> 26) + (uint64(h0) * r4) + (uint64(h1) * r3) + (uint64(h2) * r2) + (uint64(h3) * r1) + (uint64(h4) * r0) + + // h %= p + h0 = uint32(d0) & 0x3ffffff + h1 = uint32(d1) & 0x3ffffff + h2 = uint32(d2) & 0x3ffffff + h3 = uint32(d3) & 0x3ffffff + h4 = uint32(d4) & 0x3ffffff + + h0 += uint32(d4>>26) * 5 + h1 += h0 >> 26 + h0 = h0 & 0x3ffffff + + msg = msg[TagSize:] + } + + if len(msg) > 0 { + var block [TagSize]byte + off := copy(block[:], msg) + block[off] = 0x01 + + // h += msg + h0 += binary.LittleEndian.Uint32(block[0:]) & 0x3ffffff + h1 += (binary.LittleEndian.Uint32(block[3:]) >> 2) & 0x3ffffff + h2 += (binary.LittleEndian.Uint32(block[6:]) >> 4) & 0x3ffffff + h3 += (binary.LittleEndian.Uint32(block[9:]) >> 6) & 0x3ffffff + h4 += (binary.LittleEndian.Uint32(block[12:]) >> 8) + + // h *= r + d0 := (uint64(h0) * r0) + (uint64(h1) * R4) + (uint64(h2) * R3) + (uint64(h3) * R2) + (uint64(h4) * R1) + d1 := (d0 >> 26) + (uint64(h0) * r1) + (uint64(h1) * r0) + (uint64(h2) * R4) + (uint64(h3) * R3) + (uint64(h4) * R2) + d2 := (d1 >> 26) + (uint64(h0) * r2) + (uint64(h1) * r1) + (uint64(h2) * r0) + (uint64(h3) * R4) + (uint64(h4) * R3) + d3 := (d2 >> 26) + (uint64(h0) * r3) + (uint64(h1) * r2) + (uint64(h2) * r1) + (uint64(h3) * r0) + (uint64(h4) * R4) + d4 := (d3 >> 26) + (uint64(h0) * r4) + (uint64(h1) * r3) + (uint64(h2) * r2) + (uint64(h3) * r1) + (uint64(h4) * r0) + + // h %= p + h0 = uint32(d0) & 0x3ffffff + h1 = uint32(d1) & 0x3ffffff + h2 = uint32(d2) & 0x3ffffff + h3 = uint32(d3) & 0x3ffffff + h4 = uint32(d4) & 0x3ffffff + + h0 += uint32(d4>>26) * 5 + h1 += h0 >> 26 + h0 = h0 & 0x3ffffff + } + + // h %= p reduction + h2 += h1 >> 26 + h1 &= 0x3ffffff + h3 += h2 >> 26 + h2 &= 0x3ffffff + h4 += h3 >> 26 + h3 &= 0x3ffffff + h0 += 5 * (h4 >> 26) + h4 &= 0x3ffffff + h1 += h0 >> 26 + h0 &= 0x3ffffff + + // h - p + t0 := h0 + 5 + t1 := h1 + (t0 >> 26) + t2 := h2 + (t1 >> 26) + t3 := h3 + (t2 >> 26) + t4 := h4 + (t3 >> 26) - (1 << 26) + t0 &= 0x3ffffff + t1 &= 0x3ffffff + t2 &= 0x3ffffff + t3 &= 0x3ffffff + + // select h if h < p else h - p + t_mask := (t4 >> 31) - 1 + h_mask := ^t_mask + h0 = (h0 & h_mask) | (t0 & t_mask) + h1 = (h1 & h_mask) | (t1 & t_mask) + h2 = (h2 & h_mask) | (t2 & t_mask) + h3 = (h3 & h_mask) | (t3 & t_mask) + h4 = (h4 & h_mask) | (t4 & t_mask) + + // h %= 2^128 + h0 |= h1 << 26 + h1 = ((h1 >> 6) | (h2 << 20)) + h2 = ((h2 >> 12) | (h3 << 14)) + h3 = ((h3 >> 18) | (h4 << 8)) + + // s: the s part of the key + // tag = (h + s) % (2^128) + t := uint64(h0) + uint64(binary.LittleEndian.Uint32(key[16:])) + h0 = uint32(t) + t = uint64(h1) + uint64(binary.LittleEndian.Uint32(key[20:])) + (t >> 32) + h1 = uint32(t) + t = uint64(h2) + uint64(binary.LittleEndian.Uint32(key[24:])) + (t >> 32) + h2 = uint32(t) + t = uint64(h3) + uint64(binary.LittleEndian.Uint32(key[28:])) + (t >> 32) + h3 = uint32(t) + + binary.LittleEndian.PutUint32(out[0:], h0) + binary.LittleEndian.PutUint32(out[4:], h1) + binary.LittleEndian.PutUint32(out[8:], h2) + binary.LittleEndian.PutUint32(out[12:], h3) +} 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 0000000000..7a266cece4 --- /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 0000000000..356c07a6c2 --- /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 0000000000..e548020b14 --- /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/ripemd160/ripemd160.go b/vendor/golang.org/x/crypto/ripemd160/ripemd160.go index 6c6e84236a..fd97ba1b06 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/ripemd160/ripemd160block.go b/vendor/golang.org/x/crypto/ripemd160/ripemd160block.go index 7bc8e6c485..e0edc02f0f 100644 --- a/vendor/golang.org/x/crypto/ripemd160/ripemd160block.go +++ b/vendor/golang.org/x/crypto/ripemd160/ripemd160block.go @@ -8,6 +8,10 @@ package ripemd160 +import ( + "math/bits" +) + // work buffer indices and roll amounts for one line var _n = [80]uint{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, @@ -59,16 +63,16 @@ func _Block(md *digest, p []byte) int { i := 0 for i < 16 { alpha = a + (b ^ c ^ d) + x[_n[i]] - s := _r[i] - alpha = (alpha<>(32-s)) + e - beta = c<<10 | c>>22 + s := int(_r[i]) + alpha = bits.RotateLeft32(alpha, s) + e + beta = bits.RotateLeft32(c, 10) a, b, c, d, e = e, alpha, b, beta, d // parallel line alpha = aa + (bb ^ (cc | ^dd)) + x[n_[i]] + 0x50a28be6 - s = r_[i] - alpha = (alpha<>(32-s)) + ee - beta = cc<<10 | cc>>22 + s = int(r_[i]) + alpha = bits.RotateLeft32(alpha, s) + ee + beta = bits.RotateLeft32(cc, 10) aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd i++ @@ -77,16 +81,16 @@ func _Block(md *digest, p []byte) int { // round 2 for i < 32 { alpha = a + (b&c | ^b&d) + x[_n[i]] + 0x5a827999 - s := _r[i] - alpha = (alpha<>(32-s)) + e - beta = c<<10 | c>>22 + s := int(_r[i]) + alpha = bits.RotateLeft32(alpha, s) + e + beta = bits.RotateLeft32(c, 10) a, b, c, d, e = e, alpha, b, beta, d // parallel line alpha = aa + (bb&dd | cc&^dd) + x[n_[i]] + 0x5c4dd124 - s = r_[i] - alpha = (alpha<>(32-s)) + ee - beta = cc<<10 | cc>>22 + s = int(r_[i]) + alpha = bits.RotateLeft32(alpha, s) + ee + beta = bits.RotateLeft32(cc, 10) aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd i++ @@ -95,16 +99,16 @@ func _Block(md *digest, p []byte) int { // round 3 for i < 48 { alpha = a + (b | ^c ^ d) + x[_n[i]] + 0x6ed9eba1 - s := _r[i] - alpha = (alpha<>(32-s)) + e - beta = c<<10 | c>>22 + s := int(_r[i]) + alpha = bits.RotateLeft32(alpha, s) + e + beta = bits.RotateLeft32(c, 10) a, b, c, d, e = e, alpha, b, beta, d // parallel line alpha = aa + (bb | ^cc ^ dd) + x[n_[i]] + 0x6d703ef3 - s = r_[i] - alpha = (alpha<>(32-s)) + ee - beta = cc<<10 | cc>>22 + s = int(r_[i]) + alpha = bits.RotateLeft32(alpha, s) + ee + beta = bits.RotateLeft32(cc, 10) aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd i++ @@ -113,16 +117,16 @@ func _Block(md *digest, p []byte) int { // round 4 for i < 64 { alpha = a + (b&d | c&^d) + x[_n[i]] + 0x8f1bbcdc - s := _r[i] - alpha = (alpha<>(32-s)) + e - beta = c<<10 | c>>22 + s := int(_r[i]) + alpha = bits.RotateLeft32(alpha, s) + e + beta = bits.RotateLeft32(c, 10) a, b, c, d, e = e, alpha, b, beta, d // parallel line alpha = aa + (bb&cc | ^bb&dd) + x[n_[i]] + 0x7a6d76e9 - s = r_[i] - alpha = (alpha<>(32-s)) + ee - beta = cc<<10 | cc>>22 + s = int(r_[i]) + alpha = bits.RotateLeft32(alpha, s) + ee + beta = bits.RotateLeft32(cc, 10) aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd i++ @@ -131,16 +135,16 @@ func _Block(md *digest, p []byte) int { // round 5 for i < 80 { alpha = a + (b ^ (c | ^d)) + x[_n[i]] + 0xa953fd4e - s := _r[i] - alpha = (alpha<>(32-s)) + e - beta = c<<10 | c>>22 + s := int(_r[i]) + alpha = bits.RotateLeft32(alpha, s) + e + beta = bits.RotateLeft32(c, 10) a, b, c, d, e = e, alpha, b, beta, d // parallel line alpha = aa + (bb ^ cc ^ dd) + x[n_[i]] - s = r_[i] - alpha = (alpha<>(32-s)) + ee - beta = cc<<10 | cc>>22 + s = int(r_[i]) + alpha = bits.RotateLeft32(alpha, s) + ee + beta = bits.RotateLeft32(cc, 10) aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd i++ diff --git a/vendor/golang.org/x/crypto/scrypt/scrypt.go b/vendor/golang.org/x/crypto/scrypt/scrypt.go index ff28aaef6f..3362afd118 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/crypto/sha3/doc.go b/vendor/golang.org/x/crypto/sha3/doc.go similarity index 96% rename from crypto/sha3/doc.go rename to vendor/golang.org/x/crypto/sha3/doc.go index 3dab530f86..c2fef30aff 100644 --- a/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. @@ -63,4 +63,4 @@ // 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 +package sha3 // import "golang.org/x/crypto/sha3" diff --git a/crypto/sha3/hashes.go b/vendor/golang.org/x/crypto/sha3/hashes.go similarity index 58% rename from crypto/sha3/hashes.go rename to vendor/golang.org/x/crypto/sha3/hashes.go index fa0d7b4362..0d8043fd2a 100644 --- a/crypto/sha3/hashes.go +++ b/vendor/golang.org/x/crypto/sha3/hashes.go @@ -12,31 +12,57 @@ 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} } +func New224() hash.Hash { + if h := new224Asm(); h != nil { + return h + } + 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} } +func New256() hash.Hash { + if h := new256Asm(); h != nil { + return h + } + 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} } +func New384() hash.Hash { + if h := new384Asm(); h != nil { + return h + } + 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} } +func New512() hash.Hash { + if h := new512Asm(); h != nil { + return h + } + 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) { diff --git a/vendor/golang.org/x/crypto/sha3/hashes_generic.go b/vendor/golang.org/x/crypto/sha3/hashes_generic.go new file mode 100644 index 0000000000..c4ff3f6e66 --- /dev/null +++ b/vendor/golang.org/x/crypto/sha3/hashes_generic.go @@ -0,0 +1,27 @@ +// Copyright 2017 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 gccgo appengine !s390x + +package sha3 + +import ( + "hash" +) + +// new224Asm returns an assembly implementation of SHA3-224 if available, +// otherwise it returns nil. +func new224Asm() hash.Hash { return nil } + +// new256Asm returns an assembly implementation of SHA3-256 if available, +// otherwise it returns nil. +func new256Asm() hash.Hash { return nil } + +// new384Asm returns an assembly implementation of SHA3-384 if available, +// otherwise it returns nil. +func new384Asm() hash.Hash { return nil } + +// new512Asm returns an assembly implementation of SHA3-512 if available, +// otherwise it returns nil. +func new512Asm() hash.Hash { return nil } diff --git a/crypto/sha3/keccakf.go b/vendor/golang.org/x/crypto/sha3/keccakf.go similarity index 100% rename from crypto/sha3/keccakf.go rename to vendor/golang.org/x/crypto/sha3/keccakf.go diff --git a/crypto/sha3/keccakf_amd64.go b/vendor/golang.org/x/crypto/sha3/keccakf_amd64.go similarity index 88% rename from crypto/sha3/keccakf_amd64.go rename to vendor/golang.org/x/crypto/sha3/keccakf_amd64.go index de035c550f..7886795850 100644 --- a/crypto/sha3/keccakf_amd64.go +++ b/vendor/golang.org/x/crypto/sha3/keccakf_amd64.go @@ -10,4 +10,4 @@ package sha3 //go:noescape -func keccakF1600(state *[25]uint64) +func keccakF1600(a *[25]uint64) diff --git a/crypto/sha3/keccakf_amd64.s b/vendor/golang.org/x/crypto/sha3/keccakf_amd64.s similarity index 100% rename from crypto/sha3/keccakf_amd64.s rename to vendor/golang.org/x/crypto/sha3/keccakf_amd64.s diff --git a/crypto/sha3/register.go b/vendor/golang.org/x/crypto/sha3/register.go similarity index 100% rename from crypto/sha3/register.go rename to vendor/golang.org/x/crypto/sha3/register.go diff --git a/crypto/sha3/sha3.go b/vendor/golang.org/x/crypto/sha3/sha3.go similarity index 100% rename from crypto/sha3/sha3.go rename to vendor/golang.org/x/crypto/sha3/sha3.go diff --git a/vendor/golang.org/x/crypto/sha3/sha3_s390x.go b/vendor/golang.org/x/crypto/sha3/sha3_s390x.go new file mode 100644 index 0000000000..f1fb79cc39 --- /dev/null +++ b/vendor/golang.org/x/crypto/sha3/sha3_s390x.go @@ -0,0 +1,289 @@ +// Copyright 2017 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 !gccgo,!appengine + +package sha3 + +// This file contains code for using the 'compute intermediate +// message digest' (KIMD) and 'compute last message digest' (KLMD) +// instructions to compute SHA-3 and SHAKE hashes on IBM Z. + +import ( + "hash" +) + +// codes represent 7-bit KIMD/KLMD function codes as defined in +// the Principles of Operation. +type code uint64 + +const ( + // function codes for KIMD/KLMD + sha3_224 code = 32 + sha3_256 = 33 + sha3_384 = 34 + sha3_512 = 35 + shake_128 = 36 + shake_256 = 37 + nopad = 0x100 +) + +// hasMSA6 reports whether the machine supports the SHA-3 and SHAKE function +// codes, as defined in message-security-assist extension 6. +func hasMSA6() bool + +// hasAsm caches the result of hasMSA6 (which might be expensive to call). +var hasAsm = hasMSA6() + +// kimd is a wrapper for the 'compute intermediate message digest' instruction. +// src must be a multiple of the rate for the given function code. +//go:noescape +func kimd(function code, chain *[200]byte, src []byte) + +// klmd is a wrapper for the 'compute last message digest' instruction. +// src padding is handled by the instruction. +//go:noescape +func klmd(function code, chain *[200]byte, dst, src []byte) + +type asmState struct { + a [200]byte // 1600 bit state + buf []byte // care must be taken to ensure cap(buf) is a multiple of rate + rate int // equivalent to block size + storage [3072]byte // underlying storage for buf + outputLen int // output length if fixed, 0 if not + function code // KIMD/KLMD function code + state spongeDirection // whether the sponge is absorbing or squeezing +} + +func newAsmState(function code) *asmState { + var s asmState + s.function = function + switch function { + case sha3_224: + s.rate = 144 + s.outputLen = 28 + case sha3_256: + s.rate = 136 + s.outputLen = 32 + case sha3_384: + s.rate = 104 + s.outputLen = 48 + case sha3_512: + s.rate = 72 + s.outputLen = 64 + case shake_128: + s.rate = 168 + case shake_256: + s.rate = 136 + default: + panic("sha3: unrecognized function code") + } + + // limit s.buf size to a multiple of s.rate + s.resetBuf() + return &s +} + +func (s *asmState) clone() *asmState { + c := *s + c.buf = c.storage[:len(s.buf):cap(s.buf)] + return &c +} + +// copyIntoBuf copies b into buf. It will panic if there is not enough space to +// store all of b. +func (s *asmState) copyIntoBuf(b []byte) { + bufLen := len(s.buf) + s.buf = s.buf[:len(s.buf)+len(b)] + copy(s.buf[bufLen:], b) +} + +// resetBuf points buf at storage, sets the length to 0 and sets cap to be a +// multiple of the rate. +func (s *asmState) resetBuf() { + max := (cap(s.storage) / s.rate) * s.rate + s.buf = s.storage[:0:max] +} + +// Write (via the embedded io.Writer interface) adds more data to the running hash. +// It never returns an error. +func (s *asmState) Write(b []byte) (int, error) { + if s.state != spongeAbsorbing { + panic("sha3: write to sponge after read") + } + length := len(b) + for len(b) > 0 { + if len(s.buf) == 0 && len(b) >= cap(s.buf) { + // Hash the data directly and push any remaining bytes + // into the buffer. + remainder := len(s.buf) % s.rate + kimd(s.function, &s.a, b[:len(b)-remainder]) + if remainder != 0 { + s.copyIntoBuf(b[len(b)-remainder:]) + } + return length, nil + } + + if len(s.buf) == cap(s.buf) { + // flush the buffer + kimd(s.function, &s.a, s.buf) + s.buf = s.buf[:0] + } + + // copy as much as we can into the buffer + n := len(b) + if len(b) > cap(s.buf)-len(s.buf) { + n = cap(s.buf) - len(s.buf) + } + s.copyIntoBuf(b[:n]) + b = b[n:] + } + return length, nil +} + +// Read squeezes an arbitrary number of bytes from the sponge. +func (s *asmState) Read(out []byte) (n int, err error) { + n = len(out) + + // need to pad if we were absorbing + if s.state == spongeAbsorbing { + s.state = spongeSqueezing + + // write hash directly into out if possible + if len(out)%s.rate == 0 { + klmd(s.function, &s.a, out, s.buf) // len(out) may be 0 + s.buf = s.buf[:0] + return + } + + // write hash into buffer + max := cap(s.buf) + if max > len(out) { + max = (len(out)/s.rate)*s.rate + s.rate + } + klmd(s.function, &s.a, s.buf[:max], s.buf) + s.buf = s.buf[:max] + } + + for len(out) > 0 { + // flush the buffer + if len(s.buf) != 0 { + c := copy(out, s.buf) + out = out[c:] + s.buf = s.buf[c:] + continue + } + + // write hash directly into out if possible + if len(out)%s.rate == 0 { + klmd(s.function|nopad, &s.a, out, nil) + return + } + + // write hash into buffer + s.resetBuf() + if cap(s.buf) > len(out) { + s.buf = s.buf[:(len(out)/s.rate)*s.rate+s.rate] + } + klmd(s.function|nopad, &s.a, s.buf, nil) + } + return +} + +// Sum appends the current hash to b and returns the resulting slice. +// It does not change the underlying hash state. +func (s *asmState) Sum(b []byte) []byte { + if s.outputLen == 0 { + panic("sha3: cannot call Sum on SHAKE functions") + } + + // Copy the state to preserve the original. + a := s.a + + // Hash the buffer. Note that we don't clear it because we + // aren't updating the state. + klmd(s.function, &a, nil, s.buf) + return append(b, a[:s.outputLen]...) +} + +// Reset resets the Hash to its initial state. +func (s *asmState) Reset() { + for i := range s.a { + s.a[i] = 0 + } + s.resetBuf() + s.state = spongeAbsorbing +} + +// Size returns the number of bytes Sum will return. +func (s *asmState) Size() int { + return s.outputLen +} + +// BlockSize returns the hash's underlying block size. +// The Write method must be able to accept any amount +// of data, but it may operate more efficiently if all writes +// are a multiple of the block size. +func (s *asmState) BlockSize() int { + return s.rate +} + +// Clone returns a copy of the ShakeHash in its current state. +func (s *asmState) Clone() ShakeHash { + return s.clone() +} + +// new224Asm returns an assembly implementation of SHA3-224 if available, +// otherwise it returns nil. +func new224Asm() hash.Hash { + if hasAsm { + return newAsmState(sha3_224) + } + return nil +} + +// new256Asm returns an assembly implementation of SHA3-256 if available, +// otherwise it returns nil. +func new256Asm() hash.Hash { + if hasAsm { + return newAsmState(sha3_256) + } + return nil +} + +// new384Asm returns an assembly implementation of SHA3-384 if available, +// otherwise it returns nil. +func new384Asm() hash.Hash { + if hasAsm { + return newAsmState(sha3_384) + } + return nil +} + +// new512Asm returns an assembly implementation of SHA3-512 if available, +// otherwise it returns nil. +func new512Asm() hash.Hash { + if hasAsm { + return newAsmState(sha3_512) + } + return nil +} + +// newShake128Asm returns an assembly implementation of SHAKE-128 if available, +// otherwise it returns nil. +func newShake128Asm() ShakeHash { + if hasAsm { + return newAsmState(shake_128) + } + return nil +} + +// newShake256Asm returns an assembly implementation of SHAKE-256 if available, +// otherwise it returns nil. +func newShake256Asm() ShakeHash { + if hasAsm { + return newAsmState(shake_256) + } + return nil +} diff --git a/vendor/golang.org/x/crypto/sha3/sha3_s390x.s b/vendor/golang.org/x/crypto/sha3/sha3_s390x.s new file mode 100644 index 0000000000..20978fc713 --- /dev/null +++ b/vendor/golang.org/x/crypto/sha3/sha3_s390x.s @@ -0,0 +1,49 @@ +// Copyright 2017 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 !gccgo,!appengine + +#include "textflag.h" + +TEXT ·hasMSA6(SB), NOSPLIT, $16-1 + MOVD $0, R0 // KIMD-Query function code + MOVD $tmp-16(SP), R1 // parameter block + XC $16, (R1), (R1) // clear the parameter block + WORD $0xB93E0002 // KIMD --, -- + WORD $0x91FC1004 // TM 4(R1), 0xFC (test bits [32-37]) + BVS yes + +no: + MOVB $0, ret+0(FP) + RET + +yes: + MOVB $1, ret+0(FP) + RET + +// func kimd(function code, params *[200]byte, src []byte) +TEXT ·kimd(SB), NOFRAME|NOSPLIT, $0-40 + MOVD function+0(FP), R0 + MOVD params+8(FP), R1 + LMG src+16(FP), R2, R3 // R2=base, R3=len + +continue: + WORD $0xB93E0002 // KIMD --, R2 + BVS continue // continue if interrupted + MOVD $0, R0 // reset R0 for pre-go1.8 compilers + RET + +// func klmd(function code, params *[200]byte, dst, src []byte) +TEXT ·klmd(SB), NOFRAME|NOSPLIT, $0-64 + // TODO: SHAKE support + MOVD function+0(FP), R0 + MOVD params+8(FP), R1 + LMG dst+16(FP), R2, R3 // R2=base, R3=len + LMG src+40(FP), R4, R5 // R4=base, R5=len + +continue: + WORD $0xB93F0024 // KLMD R2, R4 + BVS continue // continue if interrupted + MOVD $0, R0 // reset R0 for pre-go1.8 compilers + RET diff --git a/crypto/sha3/shake.go b/vendor/golang.org/x/crypto/sha3/shake.go similarity index 83% rename from crypto/sha3/shake.go rename to vendor/golang.org/x/crypto/sha3/shake.go index 841f9860f0..97c9b0624a 100644 --- a/crypto/sha3/shake.go +++ b/vendor/golang.org/x/crypto/sha3/shake.go @@ -38,12 +38,22 @@ func (d *state) Clone() ShakeHash { // 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} } +func NewShake128() ShakeHash { + if h := newShake128Asm(); h != nil { + return h + } + return &state{rate: 168, dsbyte: 0x1f} +} -// NewShake256 creates a new SHAKE128 variable-output-length ShakeHash. +// NewShake256 creates a new SHAKE256 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} } +func NewShake256() ShakeHash { + if h := newShake256Asm(); h != nil { + return h + } + return &state{rate: 136, dsbyte: 0x1f} +} // ShakeSum128 writes an arbitrary-length digest of data into hash. func ShakeSum128(hash, data []byte) { diff --git a/vendor/golang.org/x/crypto/sha3/shake_generic.go b/vendor/golang.org/x/crypto/sha3/shake_generic.go new file mode 100644 index 0000000000..73d0c90bf5 --- /dev/null +++ b/vendor/golang.org/x/crypto/sha3/shake_generic.go @@ -0,0 +1,19 @@ +// Copyright 2017 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 gccgo appengine !s390x + +package sha3 + +// newShake128Asm returns an assembly implementation of SHAKE-128 if available, +// otherwise it returns nil. +func newShake128Asm() ShakeHash { + return nil +} + +// newShake256Asm returns an assembly implementation of SHAKE-256 if available, +// otherwise it returns nil. +func newShake256Asm() ShakeHash { + return nil +} diff --git a/crypto/sha3/xor.go b/vendor/golang.org/x/crypto/sha3/xor.go similarity index 100% rename from crypto/sha3/xor.go rename to vendor/golang.org/x/crypto/sha3/xor.go diff --git a/crypto/sha3/xor_generic.go b/vendor/golang.org/x/crypto/sha3/xor_generic.go similarity index 100% rename from crypto/sha3/xor_generic.go rename to vendor/golang.org/x/crypto/sha3/xor_generic.go diff --git a/crypto/sha3/xor_unaligned.go b/vendor/golang.org/x/crypto/sha3/xor_unaligned.go similarity index 100% rename from crypto/sha3/xor_unaligned.go rename to vendor/golang.org/x/crypto/sha3/xor_unaligned.go diff --git a/vendor/golang.org/x/crypto/ssh/certs.go b/vendor/golang.org/x/crypto/ssh/certs.go index b1f0220781..00ed9923e7 100644 --- a/vendor/golang.org/x/crypto/ssh/certs.go +++ b/vendor/golang.org/x/crypto/ssh/certs.go @@ -44,7 +44,9 @@ type Signature struct { const CertTimeInfinity = 1<<64 - 1 // An Certificate represents an OpenSSH certificate as defined in -// [PROTOCOL.certkeys]?rev=1.8. +// [PROTOCOL.certkeys]?rev=1.8. The Certificate type implements the +// PublicKey interface, so it can be unmarshaled using +// ParsePublicKey. type Certificate struct { Nonce []byte Key PublicKey @@ -220,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. @@ -228,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) { @@ -239,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 @@ -340,10 +356,10 @@ func (c *CertChecker) Authenticate(conn ConnMetadata, pubKey PublicKey) (*Permis // the signature of the certificate. func (c *CertChecker) CheckCert(principal string, cert *Certificate) error { if c.IsRevoked != nil && c.IsRevoked(cert) { - return fmt.Errorf("ssh: certicate serial %d revoked", cert.Serial) + return fmt.Errorf("ssh: certificate serial %d revoked", cert.Serial) } - for opt, _ := range cert.CriticalOptions { + for opt := range cert.CriticalOptions { // sourceAddressCriticalOption will be enforced by // serverAuthenticate if opt == sourceAddressCriticalOption { diff --git a/vendor/golang.org/x/crypto/ssh/channel.go b/vendor/golang.org/x/crypto/ssh/channel.go index 195530ea0d..c0834c00df 100644 --- a/vendor/golang.org/x/crypto/ssh/channel.go +++ b/vendor/golang.org/x/crypto/ssh/channel.go @@ -205,32 +205,32 @@ type channel struct { // writePacket sends a packet. If the packet is a channel close, it updates // sentClose. This method takes the lock c.writeMu. -func (c *channel) writePacket(packet []byte) error { - c.writeMu.Lock() - if c.sentClose { - c.writeMu.Unlock() +func (ch *channel) writePacket(packet []byte) error { + ch.writeMu.Lock() + if ch.sentClose { + ch.writeMu.Unlock() return io.EOF } - c.sentClose = (packet[0] == msgChannelClose) - err := c.mux.conn.writePacket(packet) - c.writeMu.Unlock() + ch.sentClose = (packet[0] == msgChannelClose) + err := ch.mux.conn.writePacket(packet) + ch.writeMu.Unlock() return err } -func (c *channel) sendMessage(msg interface{}) error { +func (ch *channel) sendMessage(msg interface{}) error { if debugMux { - log.Printf("send(%d): %#v", c.mux.chanList.offset, msg) + log.Printf("send(%d): %#v", ch.mux.chanList.offset, msg) } p := Marshal(msg) - binary.BigEndian.PutUint32(p[1:], c.remoteId) - return c.writePacket(p) + binary.BigEndian.PutUint32(p[1:], ch.remoteId) + return ch.writePacket(p) } // WriteExtended writes data to a specific extended stream. These streams are // used, for example, for stderr. -func (c *channel) WriteExtended(data []byte, extendedCode uint32) (n int, err error) { - if c.sentEOF { +func (ch *channel) WriteExtended(data []byte, extendedCode uint32) (n int, err error) { + if ch.sentEOF { return 0, io.EOF } // 1 byte message type, 4 bytes remoteId, 4 bytes data length @@ -241,16 +241,16 @@ func (c *channel) WriteExtended(data []byte, extendedCode uint32) (n int, err er opCode = msgChannelExtendedData } - c.writeMu.Lock() - packet := c.packetPool[extendedCode] + ch.writeMu.Lock() + packet := ch.packetPool[extendedCode] // We don't remove the buffer from packetPool, so // WriteExtended calls from different goroutines will be // flagged as errors by the race detector. - c.writeMu.Unlock() + ch.writeMu.Unlock() for len(data) > 0 { - space := min(c.maxRemotePayload, len(data)) - if space, err = c.remoteWin.reserve(space); err != nil { + space := min(ch.maxRemotePayload, len(data)) + if space, err = ch.remoteWin.reserve(space); err != nil { return n, err } if want := headerLength + space; uint32(cap(packet)) < want { @@ -262,13 +262,13 @@ func (c *channel) WriteExtended(data []byte, extendedCode uint32) (n int, err er todo := data[:space] packet[0] = opCode - binary.BigEndian.PutUint32(packet[1:], c.remoteId) + binary.BigEndian.PutUint32(packet[1:], ch.remoteId) if extendedCode > 0 { binary.BigEndian.PutUint32(packet[5:], uint32(extendedCode)) } binary.BigEndian.PutUint32(packet[headerLength-4:], uint32(len(todo))) copy(packet[headerLength:], todo) - if err = c.writePacket(packet); err != nil { + if err = ch.writePacket(packet); err != nil { return n, err } @@ -276,14 +276,14 @@ func (c *channel) WriteExtended(data []byte, extendedCode uint32) (n int, err er data = data[len(todo):] } - c.writeMu.Lock() - c.packetPool[extendedCode] = packet - c.writeMu.Unlock() + ch.writeMu.Lock() + ch.packetPool[extendedCode] = packet + ch.writeMu.Unlock() return n, err } -func (c *channel) handleData(packet []byte) error { +func (ch *channel) handleData(packet []byte) error { headerLen := 9 isExtendedData := packet[0] == msgChannelExtendedData if isExtendedData { @@ -303,7 +303,7 @@ func (c *channel) handleData(packet []byte) error { if length == 0 { return nil } - if length > c.maxIncomingPayload { + if length > ch.maxIncomingPayload { // TODO(hanwen): should send Disconnect? return errors.New("ssh: incoming packet exceeds maximum payload size") } @@ -313,21 +313,21 @@ func (c *channel) handleData(packet []byte) error { return errors.New("ssh: wrong packet length") } - c.windowMu.Lock() - if c.myWindow < length { - c.windowMu.Unlock() + ch.windowMu.Lock() + if ch.myWindow < length { + ch.windowMu.Unlock() // TODO(hanwen): should send Disconnect with reason? return errors.New("ssh: remote side wrote too much") } - c.myWindow -= length - c.windowMu.Unlock() + ch.myWindow -= length + ch.windowMu.Unlock() if extended == 1 { - c.extPending.write(data) + ch.extPending.write(data) } else if extended > 0 { // discard other extended data. } else { - c.pending.write(data) + ch.pending.write(data) } return nil } @@ -384,31 +384,31 @@ func (c *channel) close() { // responseMessageReceived is called when a success or failure message is // received on a channel to check that such a message is reasonable for the // given channel. -func (c *channel) responseMessageReceived() error { - if c.direction == channelInbound { +func (ch *channel) responseMessageReceived() error { + if ch.direction == channelInbound { return errors.New("ssh: channel response message received on inbound channel") } - if c.decided { + if ch.decided { return errors.New("ssh: duplicate response received for channel") } - c.decided = true + ch.decided = true return nil } -func (c *channel) handlePacket(packet []byte) error { +func (ch *channel) handlePacket(packet []byte) error { switch packet[0] { case msgChannelData, msgChannelExtendedData: - return c.handleData(packet) + return ch.handleData(packet) case msgChannelClose: - c.sendMessage(channelCloseMsg{PeersId: c.remoteId}) - c.mux.chanList.remove(c.localId) - c.close() + ch.sendMessage(channelCloseMsg{PeersID: ch.remoteId}) + ch.mux.chanList.remove(ch.localId) + ch.close() return nil case msgChannelEOF: // RFC 4254 is mute on how EOF affects dataExt messages but // it is logical to signal EOF at the same time. - c.extPending.eof() - c.pending.eof() + ch.extPending.eof() + ch.pending.eof() return nil } @@ -419,24 +419,24 @@ func (c *channel) handlePacket(packet []byte) error { switch msg := decoded.(type) { case *channelOpenFailureMsg: - if err := c.responseMessageReceived(); err != nil { + if err := ch.responseMessageReceived(); err != nil { return err } - c.mux.chanList.remove(msg.PeersId) - c.msg <- msg + ch.mux.chanList.remove(msg.PeersID) + ch.msg <- msg case *channelOpenConfirmMsg: - if err := c.responseMessageReceived(); err != nil { + if err := ch.responseMessageReceived(); err != nil { return err } if msg.MaxPacketSize < minPacketLength || msg.MaxPacketSize > 1<<31 { return fmt.Errorf("ssh: invalid MaxPacketSize %d from peer", msg.MaxPacketSize) } - c.remoteId = msg.MyId - c.maxRemotePayload = msg.MaxPacketSize - c.remoteWin.add(msg.MyWindow) - c.msg <- msg + ch.remoteId = msg.MyID + ch.maxRemotePayload = msg.MaxPacketSize + ch.remoteWin.add(msg.MyWindow) + ch.msg <- msg case *windowAdjustMsg: - if !c.remoteWin.add(msg.AdditionalBytes) { + if !ch.remoteWin.add(msg.AdditionalBytes) { return fmt.Errorf("ssh: invalid window update for %d bytes", msg.AdditionalBytes) } case *channelRequestMsg: @@ -444,12 +444,12 @@ func (c *channel) handlePacket(packet []byte) error { Type: msg.Request, WantReply: msg.WantReply, Payload: msg.RequestSpecificData, - ch: c, + ch: ch, } - c.incomingRequests <- &req + ch.incomingRequests <- &req default: - c.msg <- msg + ch.msg <- msg } return nil } @@ -488,23 +488,23 @@ func (e *extChannel) Read(data []byte) (n int, err error) { return e.ch.ReadExtended(data, e.code) } -func (c *channel) Accept() (Channel, <-chan *Request, error) { - if c.decided { +func (ch *channel) Accept() (Channel, <-chan *Request, error) { + if ch.decided { return nil, nil, errDecidedAlready } - c.maxIncomingPayload = channelMaxPacket + ch.maxIncomingPayload = channelMaxPacket confirm := channelOpenConfirmMsg{ - PeersId: c.remoteId, - MyId: c.localId, - MyWindow: c.myWindow, - MaxPacketSize: c.maxIncomingPayload, + PeersID: ch.remoteId, + MyID: ch.localId, + MyWindow: ch.myWindow, + MaxPacketSize: ch.maxIncomingPayload, } - c.decided = true - if err := c.sendMessage(confirm); err != nil { + ch.decided = true + if err := ch.sendMessage(confirm); err != nil { return nil, nil, err } - return c, c.incomingRequests, nil + return ch, ch.incomingRequests, nil } func (ch *channel) Reject(reason RejectionReason, message string) error { @@ -512,7 +512,7 @@ func (ch *channel) Reject(reason RejectionReason, message string) error { return errDecidedAlready } reject := channelOpenFailureMsg{ - PeersId: ch.remoteId, + PeersID: ch.remoteId, Reason: reason, Message: message, Language: "en", @@ -541,7 +541,7 @@ func (ch *channel) CloseWrite() error { } ch.sentEOF = true return ch.sendMessage(channelEOFMsg{ - PeersId: ch.remoteId}) + PeersID: ch.remoteId}) } func (ch *channel) Close() error { @@ -550,7 +550,7 @@ func (ch *channel) Close() error { } return ch.sendMessage(channelCloseMsg{ - PeersId: ch.remoteId}) + PeersID: ch.remoteId}) } // Extended returns an io.ReadWriter that sends and receives data on the given, @@ -577,7 +577,7 @@ func (ch *channel) SendRequest(name string, wantReply bool, payload []byte) (boo } msg := channelRequestMsg{ - PeersId: ch.remoteId, + PeersID: ch.remoteId, Request: name, WantReply: wantReply, RequestSpecificData: payload, @@ -614,11 +614,11 @@ func (ch *channel) ackRequest(ok bool) error { var msg interface{} if !ok { msg = channelRequestFailureMsg{ - PeersId: ch.remoteId, + PeersID: ch.remoteId, } } else { msg = channelRequestSuccessMsg{ - PeersId: ch.remoteId, + PeersID: ch.remoteId, } } return ch.sendMessage(msg) diff --git a/vendor/golang.org/x/crypto/ssh/cipher.go b/vendor/golang.org/x/crypto/ssh/cipher.go index aed2b1f017..67b0126105 100644 --- a/vendor/golang.org/x/crypto/ssh/cipher.go +++ b/vendor/golang.org/x/crypto/ssh/cipher.go @@ -16,6 +16,10 @@ import ( "hash" "io" "io/ioutil" + "math/bits" + + "golang.org/x/crypto/internal/chacha20" + "golang.org/x/crypto/poly1305" ) const ( @@ -53,78 +57,78 @@ func newRC4(key, iv []byte) (cipher.Stream, error) { return rc4.NewCipher(key) } -type streamCipherMode struct { - keySize int - ivSize int - skip int - createFunc func(key, iv []byte) (cipher.Stream, error) +type cipherMode struct { + keySize int + ivSize int + create func(key, iv []byte, macKey []byte, algs directionAlgorithms) (packetCipher, error) } -func (c *streamCipherMode) createStream(key, iv []byte) (cipher.Stream, error) { - if len(key) < c.keySize { - panic("ssh: key length too small for cipher") - } - if len(iv) < c.ivSize { - panic("ssh: iv too small for cipher") - } - - stream, err := c.createFunc(key[:c.keySize], iv[:c.ivSize]) - if err != nil { - return nil, err - } - - var streamDump []byte - if c.skip > 0 { - streamDump = make([]byte, 512) - } - - for remainingToDump := c.skip; remainingToDump > 0; { - dumpThisTime := remainingToDump - if dumpThisTime > len(streamDump) { - dumpThisTime = len(streamDump) +func streamCipherMode(skip int, createFunc func(key, iv []byte) (cipher.Stream, error)) func(key, iv []byte, macKey []byte, algs directionAlgorithms) (packetCipher, error) { + return func(key, iv, macKey []byte, algs directionAlgorithms) (packetCipher, error) { + stream, err := createFunc(key, iv) + if err != nil { + return nil, err } - stream.XORKeyStream(streamDump[:dumpThisTime], streamDump[:dumpThisTime]) - remainingToDump -= dumpThisTime - } - return stream, nil + var streamDump []byte + if skip > 0 { + streamDump = make([]byte, 512) + } + + for remainingToDump := skip; remainingToDump > 0; { + dumpThisTime := remainingToDump + if dumpThisTime > len(streamDump) { + dumpThisTime = len(streamDump) + } + stream.XORKeyStream(streamDump[:dumpThisTime], streamDump[:dumpThisTime]) + remainingToDump -= dumpThisTime + } + + mac := macModes[algs.MAC].new(macKey) + return &streamPacketCipher{ + mac: mac, + etm: macModes[algs.MAC].etm, + macResult: make([]byte, mac.Size()), + cipher: stream, + }, nil + } } // cipherModes documents properties of supported ciphers. Ciphers not included // are not supported and will not be negotiated, even if explicitly requested in // ClientConfig.Crypto.Ciphers. -var cipherModes = map[string]*streamCipherMode{ +var cipherModes = map[string]*cipherMode{ // Ciphers from RFC4344, which introduced many CTR-based ciphers. Algorithms // are defined in the order specified in the RFC. - "aes128-ctr": {16, aes.BlockSize, 0, newAESCTR}, - "aes192-ctr": {24, aes.BlockSize, 0, newAESCTR}, - "aes256-ctr": {32, aes.BlockSize, 0, newAESCTR}, + "aes128-ctr": {16, aes.BlockSize, streamCipherMode(0, newAESCTR)}, + "aes192-ctr": {24, aes.BlockSize, streamCipherMode(0, newAESCTR)}, + "aes256-ctr": {32, aes.BlockSize, streamCipherMode(0, newAESCTR)}, // Ciphers from RFC4345, which introduces security-improved arcfour ciphers. // They are defined in the order specified in the RFC. - "arcfour128": {16, 0, 1536, newRC4}, - "arcfour256": {32, 0, 1536, newRC4}, + "arcfour128": {16, 0, streamCipherMode(1536, newRC4)}, + "arcfour256": {32, 0, streamCipherMode(1536, newRC4)}, // Cipher defined in RFC 4253, which describes SSH Transport Layer Protocol. // Note that this cipher is not safe, as stated in RFC 4253: "Arcfour (and // RC4) has problems with weak keys, and should be used with caution." // RFC4345 introduces improved versions of Arcfour. - "arcfour": {16, 0, 0, newRC4}, + "arcfour": {16, 0, streamCipherMode(0, newRC4)}, - // AES-GCM is not a stream cipher, so it is constructed with a - // special case. If we add any more non-stream ciphers, we - // should invest a cleaner way to do this. - gcmCipherID: {16, 12, 0, nil}, + // AEAD ciphers + gcmCipherID: {16, 12, newGCMCipher}, + chacha20Poly1305ID: {64, 0, newChaCha20Cipher}, // CBC mode is insecure and so is not included in the default config. // (See http://www.isg.rhul.ac.uk/~kp/SandPfinal.pdf). If absolutely // needed, it's possible to specify a custom Config to enable it. // You should expect that an active attacker can recover plaintext if // you do. - aes128cbcID: {16, aes.BlockSize, 0, nil}, + aes128cbcID: {16, aes.BlockSize, newAESCBCCipher}, - // 3des-cbc is insecure and is disabled by default. - tripledescbcID: {24, des.BlockSize, 0, nil}, + // 3des-cbc is insecure and is not included in the default + // config. + tripledescbcID: {24, des.BlockSize, newTripleDESCBCCipher}, } // prefixLen is the length of the packet prefix that contains the packet length @@ -304,7 +308,7 @@ type gcmCipher struct { buf []byte } -func newGCMCipher(iv, key []byte) (packetCipher, error) { +func newGCMCipher(key, iv, unusedMacKey []byte, unusedAlgs directionAlgorithms) (packetCipher, error) { c, err := aes.NewCipher(key) if err != nil { return nil, err @@ -372,7 +376,7 @@ func (c *gcmCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { } length := binary.BigEndian.Uint32(c.prefix[:]) if length > maxPacket { - return nil, errors.New("ssh: max packet length exceeded.") + return nil, errors.New("ssh: max packet length exceeded") } if cap(c.buf) < int(length+gcmTagSize) { @@ -422,7 +426,7 @@ type cbcCipher struct { oracleCamouflage uint32 } -func newCBCCipher(c cipher.Block, iv, key, macKey []byte, algs directionAlgorithms) (packetCipher, error) { +func newCBCCipher(c cipher.Block, key, iv, macKey []byte, algs directionAlgorithms) (packetCipher, error) { cbc := &cbcCipher{ mac: macModes[algs.MAC].new(macKey), decrypter: cipher.NewCBCDecrypter(c, iv), @@ -436,13 +440,13 @@ func newCBCCipher(c cipher.Block, iv, key, macKey []byte, algs directionAlgorith return cbc, nil } -func newAESCBCCipher(iv, key, macKey []byte, algs directionAlgorithms) (packetCipher, error) { +func newAESCBCCipher(key, iv, macKey []byte, algs directionAlgorithms) (packetCipher, error) { c, err := aes.NewCipher(key) if err != nil { return nil, err } - cbc, err := newCBCCipher(c, iv, key, macKey, algs) + cbc, err := newCBCCipher(c, key, iv, macKey, algs) if err != nil { return nil, err } @@ -450,13 +454,13 @@ func newAESCBCCipher(iv, key, macKey []byte, algs directionAlgorithms) (packetCi return cbc, nil } -func newTripleDESCBCCipher(iv, key, macKey []byte, algs directionAlgorithms) (packetCipher, error) { +func newTripleDESCBCCipher(key, iv, macKey []byte, algs directionAlgorithms) (packetCipher, error) { c, err := des.NewTripleDESCipher(key) if err != nil { return nil, err } - cbc, err := newCBCCipher(c, iv, key, macKey, algs) + cbc, err := newCBCCipher(c, key, iv, macKey, algs) if err != nil { return nil, err } @@ -548,11 +552,11 @@ func (c *cbcCipher) readPacketLeaky(seqNum uint32, r io.Reader) ([]byte, error) c.packetData = c.packetData[:entirePacketSize] } - if n, err := io.ReadFull(r, c.packetData[firstBlockLength:]); err != nil { + n, err := io.ReadFull(r, c.packetData[firstBlockLength:]) + if err != nil { return nil, err - } else { - c.oracleCamouflage -= uint32(n) } + c.oracleCamouflage -= uint32(n) remainingCrypted := c.packetData[firstBlockLength:macStart] c.decrypter.CryptBlocks(remainingCrypted, remainingCrypted) @@ -627,3 +631,140 @@ func (c *cbcCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, pack return nil } + +const chacha20Poly1305ID = "chacha20-poly1305@openssh.com" + +// chacha20Poly1305Cipher implements the chacha20-poly1305@openssh.com +// AEAD, which is described here: +// +// https://tools.ietf.org/html/draft-josefsson-ssh-chacha20-poly1305-openssh-00 +// +// the methods here also implement padding, which RFC4253 Section 6 +// also requires of stream ciphers. +type chacha20Poly1305Cipher struct { + lengthKey [8]uint32 + contentKey [8]uint32 + buf []byte +} + +func newChaCha20Cipher(key, unusedIV, unusedMACKey []byte, unusedAlgs directionAlgorithms) (packetCipher, error) { + if len(key) != 64 { + panic(len(key)) + } + + c := &chacha20Poly1305Cipher{ + buf: make([]byte, 256), + } + + for i := range c.contentKey { + c.contentKey[i] = binary.LittleEndian.Uint32(key[i*4 : (i+1)*4]) + } + for i := range c.lengthKey { + c.lengthKey[i] = binary.LittleEndian.Uint32(key[(i+8)*4 : (i+9)*4]) + } + return c, nil +} + +func (c *chacha20Poly1305Cipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { + nonce := [3]uint32{0, 0, bits.ReverseBytes32(seqNum)} + s := chacha20.New(c.contentKey, nonce) + var polyKey [32]byte + s.XORKeyStream(polyKey[:], polyKey[:]) + s.Advance() // skip next 32 bytes + + encryptedLength := c.buf[:4] + if _, err := io.ReadFull(r, encryptedLength); err != nil { + return nil, err + } + + var lenBytes [4]byte + chacha20.New(c.lengthKey, nonce).XORKeyStream(lenBytes[:], encryptedLength) + + length := binary.BigEndian.Uint32(lenBytes[:]) + if length > maxPacket { + return nil, errors.New("ssh: invalid packet length, packet too large") + } + + contentEnd := 4 + length + packetEnd := contentEnd + poly1305.TagSize + if uint32(cap(c.buf)) < packetEnd { + c.buf = make([]byte, packetEnd) + copy(c.buf[:], encryptedLength) + } else { + c.buf = c.buf[:packetEnd] + } + + if _, err := io.ReadFull(r, c.buf[4:packetEnd]); err != nil { + return nil, err + } + + var mac [poly1305.TagSize]byte + copy(mac[:], c.buf[contentEnd:packetEnd]) + if !poly1305.Verify(&mac, c.buf[:contentEnd], &polyKey) { + return nil, errors.New("ssh: MAC failure") + } + + plain := c.buf[4:contentEnd] + s.XORKeyStream(plain, plain) + + padding := plain[0] + if padding < 4 { + // padding is a byte, so it automatically satisfies + // the maximum size, which is 255. + return nil, fmt.Errorf("ssh: illegal padding %d", padding) + } + + if int(padding)+1 >= len(plain) { + return nil, fmt.Errorf("ssh: padding %d too large", padding) + } + + plain = plain[1 : len(plain)-int(padding)] + + return plain, nil +} + +func (c *chacha20Poly1305Cipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, payload []byte) error { + nonce := [3]uint32{0, 0, bits.ReverseBytes32(seqNum)} + s := chacha20.New(c.contentKey, nonce) + var polyKey [32]byte + s.XORKeyStream(polyKey[:], polyKey[:]) + s.Advance() // skip next 32 bytes + + // There is no blocksize, so fall back to multiple of 8 byte + // padding, as described in RFC 4253, Sec 6. + const packetSizeMultiple = 8 + + padding := packetSizeMultiple - (1+len(payload))%packetSizeMultiple + if padding < 4 { + padding += packetSizeMultiple + } + + // size (4 bytes), padding (1), payload, padding, tag. + totalLength := 4 + 1 + len(payload) + padding + poly1305.TagSize + if cap(c.buf) < totalLength { + c.buf = make([]byte, totalLength) + } else { + c.buf = c.buf[:totalLength] + } + + binary.BigEndian.PutUint32(c.buf, uint32(1+len(payload)+padding)) + chacha20.New(c.lengthKey, nonce).XORKeyStream(c.buf, c.buf[:4]) + c.buf[4] = byte(padding) + copy(c.buf[5:], payload) + packetEnd := 5 + len(payload) + padding + if _, err := io.ReadFull(rand, c.buf[5+len(payload):packetEnd]); err != nil { + return err + } + + s.XORKeyStream(c.buf[4:], c.buf[4:packetEnd]) + + var mac [poly1305.TagSize]byte + poly1305.Sum(&mac, c.buf[:packetEnd], &polyKey) + + copy(c.buf[packetEnd:], mac[:]) + + if _, err := w.Write(c.buf); err != nil { + return err + } + return nil +} diff --git a/vendor/golang.org/x/crypto/ssh/client.go b/vendor/golang.org/x/crypto/ssh/client.go index a7e3263bca..7b00bff1ca 100644 --- a/vendor/golang.org/x/crypto/ssh/client.go +++ b/vendor/golang.org/x/crypto/ssh/client.go @@ -9,6 +9,7 @@ import ( "errors" "fmt" "net" + "os" "sync" "time" ) @@ -18,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 @@ -59,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 } @@ -184,9 +185,13 @@ 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 +// the server. A BannerCallback receives the message sent by the remote server. +type BannerCallback func(message string) error + // A ClientConfig structure is used to configure a Client. It must not be // modified after having been passed to an SSH function. type ClientConfig struct { @@ -209,6 +214,12 @@ type ClientConfig struct { // FixedHostKey can be used for simplistic host key checks. HostKeyCallback HostKeyCallback + // BannerCallback is called during the SSH dance to display a custom + // server's message. The client configuration can supply this callback to + // handle it as wished. The function BannerDisplayStderr can be used for + // simplistic display on Stderr. + BannerCallback BannerCallback + // ClientVersion contains the version identification string that will // be used for the connection. If empty, a reasonable default is used. ClientVersion string @@ -255,3 +266,13 @@ func FixedHostKey(key PublicKey) HostKeyCallback { hk := &fixedHostKey{key} return hk.check } + +// BannerDisplayStderr returns a function that can be used for +// ClientConfig.BannerCallback to display banners on os.Stderr. +func BannerDisplayStderr() BannerCallback { + return func(banner string) error { + _, err := os.Stderr.WriteString(banner) + + return err + } +} diff --git a/vendor/golang.org/x/crypto/ssh/client_auth.go b/vendor/golang.org/x/crypto/ssh/client_auth.go index 3acd8d4988..5f44b77403 100644 --- a/vendor/golang.org/x/crypto/ssh/client_auth.go +++ b/vendor/golang.org/x/crypto/ssh/client_auth.go @@ -11,6 +11,14 @@ import ( "io" ) +type authResult int + +const ( + authFailure authResult = iota + authPartialSuccess + authSuccess +) + // clientAuthenticate authenticates with the remote server. See RFC 4252. func (c *connection) clientAuthenticate(config *ClientConfig) error { // initiate user auth session @@ -37,11 +45,12 @@ func (c *connection) clientAuthenticate(config *ClientConfig) error { if err != nil { return err } - if ok { + if ok == authSuccess { // success return nil + } else if ok == authFailure { + tried[auth.method()] = true } - tried[auth.method()] = true if methods == nil { methods = lastMethods } @@ -82,7 +91,7 @@ type AuthMethod interface { // If authentication is not successful, a []string of alternative // method names is returned. If the slice is nil, it will be ignored // and the previous set of possible methods will be reused. - auth(session []byte, user string, p packetConn, rand io.Reader) (bool, []string, error) + auth(session []byte, user string, p packetConn, rand io.Reader) (authResult, []string, error) // method returns the RFC 4252 method name. method() string @@ -91,13 +100,13 @@ type AuthMethod interface { // "none" authentication, RFC 4252 section 5.2. type noneAuth int -func (n *noneAuth) auth(session []byte, user string, c packetConn, rand io.Reader) (bool, []string, error) { +func (n *noneAuth) auth(session []byte, user string, c packetConn, rand io.Reader) (authResult, []string, error) { if err := c.writePacket(Marshal(&userAuthRequestMsg{ User: user, Service: serviceSSH, Method: "none", })); err != nil { - return false, nil, err + return authFailure, nil, err } return handleAuthResponse(c) @@ -111,7 +120,7 @@ func (n *noneAuth) method() string { // a function call, e.g. by prompting the user. type passwordCallback func() (password string, err error) -func (cb passwordCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (bool, []string, error) { +func (cb passwordCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (authResult, []string, error) { type passwordAuthMsg struct { User string `sshtype:"50"` Service string @@ -125,7 +134,7 @@ func (cb passwordCallback) auth(session []byte, user string, c packetConn, rand // The program may only find out that the user doesn't have a password // when prompting. if err != nil { - return false, nil, err + return authFailure, nil, err } if err := c.writePacket(Marshal(&passwordAuthMsg{ @@ -135,7 +144,7 @@ func (cb passwordCallback) auth(session []byte, user string, c packetConn, rand Reply: false, Password: pw, })); err != nil { - return false, nil, err + return authFailure, nil, err } return handleAuthResponse(c) @@ -178,7 +187,7 @@ func (cb publicKeyCallback) method() string { return "publickey" } -func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (bool, []string, error) { +func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (authResult, []string, error) { // Authentication is performed by sending an enquiry to test if a key is // acceptable to the remote. If the key is acceptable, the client will // attempt to authenticate with the valid key. If not the client will repeat @@ -186,13 +195,13 @@ func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand signers, err := cb() if err != nil { - return false, nil, err + return authFailure, nil, err } var methods []string for _, signer := range signers { ok, err := validateKey(signer.PublicKey(), user, c) if err != nil { - return false, nil, err + return authFailure, nil, err } if !ok { continue @@ -206,7 +215,7 @@ func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand Method: cb.method(), }, []byte(pub.Type()), pubKey)) if err != nil { - return false, nil, err + return authFailure, nil, err } // manually wrap the serialized signature in a string @@ -224,24 +233,24 @@ func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand } p := Marshal(&msg) if err := c.writePacket(p); err != nil { - return false, nil, err + return authFailure, nil, err } - var success bool + var success authResult success, methods, err = handleAuthResponse(c) if err != nil { - return false, nil, err + return authFailure, nil, err } // If authentication succeeds or the list of available methods does not // contain the "publickey" method, do not attempt to authenticate with any // other keys. According to RFC 4252 Section 7, the latter can occur when // additional authentication methods are required. - if success || !containsMethod(methods, cb.method()) { + if success == authSuccess || !containsMethod(methods, cb.method()) { return success, methods, err } } - return false, methods, nil + return authFailure, methods, nil } func containsMethod(methods []string, method string) bool { @@ -283,7 +292,9 @@ func confirmKeyAck(key PublicKey, c packetConn) (bool, error) { } switch packet[0] { case msgUserAuthBanner: - // TODO(gpaul): add callback to present the banner to the user + if err := handleBannerResponse(c, packet); err != nil { + return false, err + } case msgUserAuthPubKeyOk: var msg userAuthPubKeyOkMsg if err := Unmarshal(packet, &msg); err != nil { @@ -316,30 +327,53 @@ func PublicKeysCallback(getSigners func() (signers []Signer, err error)) AuthMet // handleAuthResponse returns whether the preceding authentication request succeeded // along with a list of remaining authentication methods to try next and // an error if an unexpected response was received. -func handleAuthResponse(c packetConn) (bool, []string, error) { +func handleAuthResponse(c packetConn) (authResult, []string, error) { for { packet, err := c.readPacket() if err != nil { - return false, nil, err + return authFailure, nil, err } switch packet[0] { case msgUserAuthBanner: - // TODO: add callback to present the banner to the user + if err := handleBannerResponse(c, packet); err != nil { + return authFailure, nil, err + } case msgUserAuthFailure: var msg userAuthFailureMsg if err := Unmarshal(packet, &msg); err != nil { - return false, nil, err + return authFailure, nil, err } - return false, msg.Methods, nil + if msg.PartialSuccess { + return authPartialSuccess, msg.Methods, nil + } + return authFailure, msg.Methods, nil case msgUserAuthSuccess: - return true, nil, nil + return authSuccess, nil, nil default: - return false, nil, unexpectedMessageError(msgUserAuthSuccess, packet[0]) + return authFailure, nil, unexpectedMessageError(msgUserAuthSuccess, packet[0]) } } } +func handleBannerResponse(c packetConn, packet []byte) error { + var msg userAuthBannerMsg + if err := Unmarshal(packet, &msg); err != nil { + return err + } + + transport, ok := c.(*handshakeTransport) + if !ok { + return nil + } + + if transport.bannerCallback != nil { + return transport.bannerCallback(msg.Message) + } + + return nil +} + // KeyboardInteractiveChallenge should print questions, optionally // disabling echoing (e.g. for passwords), and return all the answers. // Challenge may be called multiple times in a single session. After @@ -359,7 +393,7 @@ func (cb KeyboardInteractiveChallenge) method() string { return "keyboard-interactive" } -func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packetConn, rand io.Reader) (bool, []string, error) { +func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packetConn, rand io.Reader) (authResult, []string, error) { type initiateMsg struct { User string `sshtype:"50"` Service string @@ -373,37 +407,42 @@ func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packe Service: serviceSSH, Method: "keyboard-interactive", })); err != nil { - return false, nil, err + return authFailure, nil, err } for { packet, err := c.readPacket() if err != nil { - return false, nil, err + return authFailure, nil, err } // like handleAuthResponse, but with less options. switch packet[0] { case msgUserAuthBanner: - // TODO: Print banners during userauth. + if err := handleBannerResponse(c, packet); err != nil { + return authFailure, nil, err + } continue case msgUserAuthInfoRequest: // OK case msgUserAuthFailure: var msg userAuthFailureMsg if err := Unmarshal(packet, &msg); err != nil { - return false, nil, err + return authFailure, nil, err } - return false, msg.Methods, nil + if msg.PartialSuccess { + return authPartialSuccess, msg.Methods, nil + } + return authFailure, msg.Methods, nil case msgUserAuthSuccess: - return true, nil, nil + return authSuccess, nil, nil default: - return false, nil, unexpectedMessageError(msgUserAuthInfoRequest, packet[0]) + return authFailure, nil, unexpectedMessageError(msgUserAuthInfoRequest, packet[0]) } var msg userAuthInfoRequestMsg if err := Unmarshal(packet, &msg); err != nil { - return false, nil, err + return authFailure, nil, err } // Manually unpack the prompt/echo pairs. @@ -413,7 +452,7 @@ func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packe for i := 0; i < int(msg.NumPrompts); i++ { prompt, r, ok := parseString(rest) if !ok || len(r) == 0 { - return false, nil, errors.New("ssh: prompt format error") + return authFailure, nil, errors.New("ssh: prompt format error") } prompts = append(prompts, string(prompt)) echos = append(echos, r[0] != 0) @@ -421,16 +460,16 @@ func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packe } if len(rest) != 0 { - return false, nil, errors.New("ssh: extra data following keyboard-interactive pairs") + return authFailure, nil, errors.New("ssh: extra data following keyboard-interactive pairs") } answers, err := cb(msg.User, msg.Instruction, prompts, echos) if err != nil { - return false, nil, err + return authFailure, nil, err } if len(answers) != len(prompts) { - return false, nil, errors.New("ssh: not enough answers from keyboard-interactive callback") + return authFailure, nil, errors.New("ssh: not enough answers from keyboard-interactive callback") } responseLength := 1 + 4 for _, a := range answers { @@ -446,7 +485,7 @@ func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packe } if err := c.writePacket(serialized); err != nil { - return false, nil, err + return authFailure, nil, err } } } @@ -456,10 +495,10 @@ type retryableAuthMethod struct { maxTries int } -func (r *retryableAuthMethod) auth(session []byte, user string, c packetConn, rand io.Reader) (ok bool, methods []string, err error) { +func (r *retryableAuthMethod) auth(session []byte, user string, c packetConn, rand io.Reader) (ok authResult, methods []string, err error) { for i := 0; r.maxTries <= 0 || i < r.maxTries; i++ { ok, methods, err = r.authMethod.auth(session, user, c, rand) - if ok || err != nil { // either success or error terminate + if ok != authFailure || err != nil { // either success, partial success or error terminate return ok, methods, err } } diff --git a/vendor/golang.org/x/crypto/ssh/common.go b/vendor/golang.org/x/crypto/ssh/common.go index dc39e4d231..04f3620b3d 100644 --- a/vendor/golang.org/x/crypto/ssh/common.go +++ b/vendor/golang.org/x/crypto/ssh/common.go @@ -24,11 +24,21 @@ const ( serviceSSH = "ssh-connection" ) -// supportedCiphers specifies the supported ciphers in preference order. +// supportedCiphers lists ciphers we support but might not recommend. var supportedCiphers = []string{ "aes128-ctr", "aes192-ctr", "aes256-ctr", "aes128-gcm@openssh.com", - "arcfour256", "arcfour128", + chacha20Poly1305ID, + "arcfour256", "arcfour128", "arcfour", + aes128cbcID, + tripledescbcID, +} + +// preferredCiphers specifies the default preference for ciphers. +var preferredCiphers = []string{ + "aes128-gcm@openssh.com", + chacha20Poly1305ID, + "aes128-ctr", "aes192-ctr", "aes256-ctr", } // supportedKexAlgos specifies the supported key-exchange algorithms in @@ -211,7 +221,7 @@ func (c *Config) SetDefaults() { c.Rand = rand.Reader } if c.Ciphers == nil { - c.Ciphers = supportedCiphers + c.Ciphers = preferredCiphers } var ciphers []string for _, c := range c.Ciphers { @@ -242,7 +252,7 @@ func (c *Config) SetDefaults() { // buildDataSignedForAuth returns the data that is signed in order to prove // possession of a private key. See RFC 4252, section 7. -func buildDataSignedForAuth(sessionId []byte, req userAuthRequestMsg, algo, pubKey []byte) []byte { +func buildDataSignedForAuth(sessionID []byte, req userAuthRequestMsg, algo, pubKey []byte) []byte { data := struct { Session []byte Type byte @@ -253,7 +263,7 @@ func buildDataSignedForAuth(sessionId []byte, req userAuthRequestMsg, algo, pubK Algo []byte PubKey []byte }{ - sessionId, + sessionID, msgUserAuthRequest, req.User, req.Service, diff --git a/vendor/golang.org/x/crypto/ssh/handshake.go b/vendor/golang.org/x/crypto/ssh/handshake.go index 932ce8393e..4f7912ecd6 100644 --- a/vendor/golang.org/x/crypto/ssh/handshake.go +++ b/vendor/golang.org/x/crypto/ssh/handshake.go @@ -78,6 +78,11 @@ type handshakeTransport struct { dialAddress string remoteAddr net.Addr + // bannerCallback is non-empty if we are the client and it has been set in + // ClientConfig. In that case it is called during the user authentication + // dance to handle a custom server's message. + bannerCallback BannerCallback + // Algorithms agreed in the last key exchange. algorithms *algorithms @@ -120,6 +125,7 @@ func newClientTransport(conn keyingTransport, clientVersion, serverVersion []byt t.dialAddress = dialAddr t.remoteAddr = addr t.hostKeyCallback = config.HostKeyCallback + t.bannerCallback = config.BannerCallback if config.HostKeyAlgorithms != nil { t.hostKeyAlgorithms = config.HostKeyAlgorithms } else { diff --git a/vendor/golang.org/x/crypto/ssh/kex.go b/vendor/golang.org/x/crypto/ssh/kex.go index f91c2770ed..f34bcc0133 100644 --- a/vendor/golang.org/x/crypto/ssh/kex.go +++ b/vendor/golang.org/x/crypto/ssh/kex.go @@ -119,7 +119,7 @@ func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handsha return nil, err } - kInt, err := group.diffieHellman(kexDHReply.Y, x) + ki, err := group.diffieHellman(kexDHReply.Y, x) if err != nil { return nil, err } @@ -129,8 +129,8 @@ func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handsha writeString(h, kexDHReply.HostKey) writeInt(h, X) writeInt(h, kexDHReply.Y) - K := make([]byte, intLength(kInt)) - marshalInt(K, kInt) + K := make([]byte, intLength(ki)) + marshalInt(K, ki) h.Write(K) return &kexResult{ @@ -164,7 +164,7 @@ func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handsha } Y := new(big.Int).Exp(group.g, y, group.p) - kInt, err := group.diffieHellman(kexDHInit.X, y) + ki, err := group.diffieHellman(kexDHInit.X, y) if err != nil { return nil, err } @@ -177,8 +177,8 @@ func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handsha writeInt(h, kexDHInit.X) writeInt(h, Y) - K := make([]byte, intLength(kInt)) - marshalInt(K, kInt) + K := make([]byte, intLength(ki)) + marshalInt(K, ki) h.Write(K) H := h.Sum(nil) @@ -462,9 +462,9 @@ func (kex *curve25519sha256) Client(c packetConn, rand io.Reader, magics *handsh writeString(h, kp.pub[:]) writeString(h, reply.EphemeralPubKey) - kInt := new(big.Int).SetBytes(secret[:]) - K := make([]byte, intLength(kInt)) - marshalInt(K, kInt) + ki := new(big.Int).SetBytes(secret[:]) + K := make([]byte, intLength(ki)) + marshalInt(K, ki) h.Write(K) return &kexResult{ @@ -510,9 +510,9 @@ func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics *handsh writeString(h, kexInit.ClientPubKey) writeString(h, kp.pub[:]) - kInt := new(big.Int).SetBytes(secret[:]) - K := make([]byte, intLength(kInt)) - marshalInt(K, kInt) + ki := new(big.Int).SetBytes(secret[:]) + K := make([]byte, intLength(ki)) + marshalInt(K, ki) h.Write(K) H := h.Sum(nil) diff --git a/vendor/golang.org/x/crypto/ssh/keys.go b/vendor/golang.org/x/crypto/ssh/keys.go index b682c1741b..969804794f 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) { @@ -276,7 +286,8 @@ type PublicKey interface { Type() string // Marshal returns the serialized key data in SSH wire format, - // with the name prefix. + // with the name prefix. To unmarshal the returned data, use + // the ParsePublicKey function. Marshal() []byte // Verify that sig is a signature on the given data using this @@ -300,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 { @@ -348,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 { @@ -363,7 +395,7 @@ func (r *rsaPublicKey) CryptoPublicKey() crypto.PublicKey { type dsaPublicKey dsa.PublicKey -func (r *dsaPublicKey) Type() string { +func (k *dsaPublicKey) Type() string { return "ssh-dss" } @@ -458,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) @@ -481,12 +521,12 @@ func (k *dsaPrivateKey) Sign(rand io.Reader, data []byte) (*Signature, error) { type ecdsaPublicKey ecdsa.PublicKey -func (key *ecdsaPublicKey) Type() string { - return "ecdsa-sha2-" + key.nistID() +func (k *ecdsaPublicKey) Type() string { + return "ecdsa-sha2-" + k.nistID() } -func (key *ecdsaPublicKey) nistID() string { - switch key.Params().BitSize { +func (k *ecdsaPublicKey) nistID() string { + switch k.Params().BitSize { case 256: return "nistp256" case 384: @@ -499,7 +539,7 @@ func (key *ecdsaPublicKey) nistID() string { type ed25519PublicKey ed25519.PublicKey -func (key ed25519PublicKey) Type() string { +func (k ed25519PublicKey) Type() string { return KeyAlgoED25519 } @@ -518,23 +558,23 @@ func parseED25519(in []byte) (out PublicKey, rest []byte, err error) { return (ed25519PublicKey)(key), w.Rest, nil } -func (key ed25519PublicKey) Marshal() []byte { +func (k ed25519PublicKey) Marshal() []byte { w := struct { Name string KeyBytes []byte }{ KeyAlgoED25519, - []byte(key), + []byte(k), } return Marshal(&w) } -func (key ed25519PublicKey) Verify(b []byte, sig *Signature) error { - if sig.Format != key.Type() { - return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, key.Type()) +func (k ed25519PublicKey) Verify(b []byte, sig *Signature) error { + if sig.Format != k.Type() { + return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type()) } - edKey := (ed25519.PublicKey)(key) + edKey := (ed25519.PublicKey)(k) if ok := ed25519.Verify(edKey, b, sig.Blob); !ok { return errors.New("ssh: signature did not verify") } @@ -595,9 +635,9 @@ func parseECDSA(in []byte) (out PublicKey, rest []byte, err error) { return (*ecdsaPublicKey)(key), w.Rest, nil } -func (key *ecdsaPublicKey) Marshal() []byte { +func (k *ecdsaPublicKey) Marshal() []byte { // See RFC 5656, section 3.1. - keyBytes := elliptic.Marshal(key.Curve, key.X, key.Y) + keyBytes := elliptic.Marshal(k.Curve, k.X, k.Y) // ECDSA publickey struct layout should match the struct used by // parseECDSACert in the x/crypto/ssh/agent package. w := struct { @@ -605,20 +645,20 @@ func (key *ecdsaPublicKey) Marshal() []byte { ID string Key []byte }{ - key.Type(), - key.nistID(), + k.Type(), + k.nistID(), keyBytes, } return Marshal(&w) } -func (key *ecdsaPublicKey) Verify(data []byte, sig *Signature) error { - if sig.Format != key.Type() { - return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, key.Type()) +func (k *ecdsaPublicKey) Verify(data []byte, sig *Signature) error { + if sig.Format != k.Type() { + return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type()) } - h := ecHash(key.Curve).New() + h := ecHash(k.Curve).New() h.Write(data) digest := h.Sum(nil) @@ -635,7 +675,7 @@ func (key *ecdsaPublicKey) Verify(data []byte, sig *Signature) error { return err } - if ecdsa.Verify((*ecdsa.PublicKey)(key), digest, ecSig.R, ecSig.S) { + if ecdsa.Verify((*ecdsa.PublicKey)(k), digest, ecSig.R, ecSig.S) { return nil } return errors.New("ssh: signature did not verify") @@ -690,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 @@ -744,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 } @@ -758,7 +824,7 @@ func NewPublicKey(key interface{}) (PublicKey, error) { return (*rsaPublicKey)(key), nil case *ecdsa.PublicKey: if !supportedEllipticCurve(key.Curve) { - return nil, errors.New("ssh: only P-256, P-384 and P-521 EC keys are supported.") + return nil, errors.New("ssh: only P-256, P-384 and P-521 EC keys are supported") } return (*ecdsaPublicKey)(key), nil case *dsa.PublicKey: @@ -802,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 { @@ -816,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": @@ -899,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/messages.go b/vendor/golang.org/x/crypto/ssh/messages.go index e6ecd3afa5..08d2811730 100644 --- a/vendor/golang.org/x/crypto/ssh/messages.go +++ b/vendor/golang.org/x/crypto/ssh/messages.go @@ -23,10 +23,6 @@ const ( msgUnimplemented = 3 msgDebug = 4 msgNewKeys = 21 - - // Standard authentication messages - msgUserAuthSuccess = 52 - msgUserAuthBanner = 53 ) // SSH messages: @@ -137,6 +133,18 @@ type userAuthFailureMsg struct { PartialSuccess bool } +// See RFC 4252, section 5.1 +const msgUserAuthSuccess = 52 + +// See RFC 4252, section 5.4 +const msgUserAuthBanner = 53 + +type userAuthBannerMsg struct { + Message string `sshtype:"53"` + // unused, but required to allow message parsing + Language string +} + // See RFC 4256, section 3.2 const msgUserAuthInfoRequest = 60 const msgUserAuthInfoResponse = 61 @@ -154,7 +162,7 @@ const msgChannelOpen = 90 type channelOpenMsg struct { ChanType string `sshtype:"90"` - PeersId uint32 + PeersID uint32 PeersWindow uint32 MaxPacketSize uint32 TypeSpecificData []byte `ssh:"rest"` @@ -165,7 +173,7 @@ const msgChannelData = 94 // Used for debug print outs of packets. type channelDataMsg struct { - PeersId uint32 `sshtype:"94"` + PeersID uint32 `sshtype:"94"` Length uint32 Rest []byte `ssh:"rest"` } @@ -174,8 +182,8 @@ type channelDataMsg struct { const msgChannelOpenConfirm = 91 type channelOpenConfirmMsg struct { - PeersId uint32 `sshtype:"91"` - MyId uint32 + PeersID uint32 `sshtype:"91"` + MyID uint32 MyWindow uint32 MaxPacketSize uint32 TypeSpecificData []byte `ssh:"rest"` @@ -185,7 +193,7 @@ type channelOpenConfirmMsg struct { const msgChannelOpenFailure = 92 type channelOpenFailureMsg struct { - PeersId uint32 `sshtype:"92"` + PeersID uint32 `sshtype:"92"` Reason RejectionReason Message string Language string @@ -194,7 +202,7 @@ type channelOpenFailureMsg struct { const msgChannelRequest = 98 type channelRequestMsg struct { - PeersId uint32 `sshtype:"98"` + PeersID uint32 `sshtype:"98"` Request string WantReply bool RequestSpecificData []byte `ssh:"rest"` @@ -204,28 +212,28 @@ type channelRequestMsg struct { const msgChannelSuccess = 99 type channelRequestSuccessMsg struct { - PeersId uint32 `sshtype:"99"` + PeersID uint32 `sshtype:"99"` } // See RFC 4254, section 5.4. const msgChannelFailure = 100 type channelRequestFailureMsg struct { - PeersId uint32 `sshtype:"100"` + PeersID uint32 `sshtype:"100"` } // See RFC 4254, section 5.3 const msgChannelClose = 97 type channelCloseMsg struct { - PeersId uint32 `sshtype:"97"` + PeersID uint32 `sshtype:"97"` } // See RFC 4254, section 5.3 const msgChannelEOF = 96 type channelEOFMsg struct { - PeersId uint32 `sshtype:"96"` + PeersID uint32 `sshtype:"96"` } // See RFC 4254, section 4 @@ -255,7 +263,7 @@ type globalRequestFailureMsg struct { const msgChannelWindowAdjust = 93 type windowAdjustMsg struct { - PeersId uint32 `sshtype:"93"` + PeersID uint32 `sshtype:"93"` AdditionalBytes uint32 } diff --git a/vendor/golang.org/x/crypto/ssh/mux.go b/vendor/golang.org/x/crypto/ssh/mux.go index 27a527c106..f19016270e 100644 --- a/vendor/golang.org/x/crypto/ssh/mux.go +++ b/vendor/golang.org/x/crypto/ssh/mux.go @@ -278,7 +278,7 @@ func (m *mux) handleChannelOpen(packet []byte) error { if msg.MaxPacketSize < minPacketLength || msg.MaxPacketSize > 1<<31 { failMsg := channelOpenFailureMsg{ - PeersId: msg.PeersId, + PeersID: msg.PeersID, Reason: ConnectionFailed, Message: "invalid request", Language: "en_US.UTF-8", @@ -287,7 +287,7 @@ func (m *mux) handleChannelOpen(packet []byte) error { } c := m.newChannel(msg.ChanType, channelInbound, msg.TypeSpecificData) - c.remoteId = msg.PeersId + c.remoteId = msg.PeersID c.maxRemotePayload = msg.MaxPacketSize c.remoteWin.add(msg.PeersWindow) m.incomingChannels <- c @@ -313,7 +313,7 @@ func (m *mux) openChannel(chanType string, extra []byte) (*channel, error) { PeersWindow: ch.myWindow, MaxPacketSize: ch.maxIncomingPayload, TypeSpecificData: extra, - PeersId: ch.localId, + PeersID: ch.localId, } if err := m.sendMessage(open); err != nil { return nil, err diff --git a/vendor/golang.org/x/crypto/ssh/server.go b/vendor/golang.org/x/crypto/ssh/server.go index 8a78b7ca0f..e86e89661a 100644 --- a/vendor/golang.org/x/crypto/ssh/server.go +++ b/vendor/golang.org/x/crypto/ssh/server.go @@ -95,6 +95,10 @@ type ServerConfig struct { // Note that RFC 4253 section 4.2 requires that this string start with // "SSH-2.0-". ServerVersion string + + // BannerCallback, if present, is called and the return string is sent to + // the client after key exchange completed but before authentication. + BannerCallback func(conn ConnMetadata) string } // AddHostKey adds a private key as a host key. If an existing host @@ -162,6 +166,9 @@ type ServerConn struct { // unsuccessful, it closes the connection and returns an error. The // Request and NewChannel channels must be serviced, or the connection // will hang. +// +// The returned error may be of type *ServerAuthError for +// authentication errors. func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewChannel, <-chan *Request, error) { fullConf := *config fullConf.SetDefaults() @@ -252,7 +259,7 @@ func (s *connection) serverHandshake(config *ServerConfig) (*Permissions, error) func isAcceptableAlgo(algo string) bool { switch algo { case KeyAlgoRSA, KeyAlgoDSA, KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, KeyAlgoED25519, - CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01: + CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoED25519v01: return true } return false @@ -288,12 +295,13 @@ func checkSourceAddress(addr net.Addr, sourceAddrs string) error { return fmt.Errorf("ssh: remote address %v is not allowed because of source-address restriction", addr) } -// ServerAuthError implements the error interface. It appends any authentication -// errors that may occur, and is returned if all of the authentication methods -// provided by the user failed to authenticate. +// ServerAuthError represents server authentication errors and is +// sometimes returned by NewServerConn. It appends any authentication +// errors that may occur, and is returned if all of the authentication +// methods provided by the user failed to authenticate. type ServerAuthError struct { // Errors contains authentication errors returned by the authentication - // callback methods. + // callback methods. The first entry is typically ErrNoAuth. Errors []error } @@ -305,6 +313,13 @@ func (l ServerAuthError) Error() string { return "[" + strings.Join(errs, ", ") + "]" } +// ErrNoAuth is the error value returned if no +// authentication method has been passed yet. This happens as a normal +// part of the authentication loop, since the client first tries +// 'none' authentication to discover available methods. +// It is returned in ServerAuthError.Errors from NewServerConn. +var ErrNoAuth = errors.New("ssh: no auth passed yet") + func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, error) { sessionID := s.transport.getSessionID() var cache pubKeyCache @@ -312,6 +327,7 @@ func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, err authFailures := 0 var authErrs []error + var displayedBanner bool userAuthLoop: for { @@ -343,8 +359,22 @@ userAuthLoop: } s.user = userAuthReq.User + + if !displayedBanner && config.BannerCallback != nil { + displayedBanner = true + msg := config.BannerCallback(s) + if msg != "" { + bannerMsg := &userAuthBannerMsg{ + Message: msg, + } + if err := s.transport.writePacket(Marshal(bannerMsg)); err != nil { + return nil, err + } + } + } + perms = nil - authErr := errors.New("no auth passed yet") + authErr := ErrNoAuth switch userAuthReq.Method { case "none": @@ -374,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 } @@ -454,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/session.go b/vendor/golang.org/x/crypto/ssh/session.go index cc06e03f5c..d3321f6b78 100644 --- a/vendor/golang.org/x/crypto/ssh/session.go +++ b/vendor/golang.org/x/crypto/ssh/session.go @@ -406,7 +406,7 @@ func (s *Session) Wait() error { s.stdinPipeWriter.Close() } var copyError error - for _ = range s.copyFuncs { + for range s.copyFuncs { if err := <-s.errors; err != nil && copyError == nil { copyError = err } diff --git a/vendor/golang.org/x/crypto/ssh/streamlocal.go b/vendor/golang.org/x/crypto/ssh/streamlocal.go index a2dccc64c7..b171b330bc 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 acf17175df..80d35f5ec1 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.go b/vendor/golang.org/x/crypto/ssh/terminal/terminal.go index 18379a935b..9a887598ff 100644 --- a/vendor/golang.org/x/crypto/ssh/terminal/terminal.go +++ b/vendor/golang.org/x/crypto/ssh/terminal/terminal.go @@ -617,7 +617,7 @@ func writeWithCRLF(w io.Writer, buf []byte) (n int, err error) { if _, err = w.Write(crlf); err != nil { return n, err } - n += 1 + n++ buf = buf[1:] } } diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util.go b/vendor/golang.org/x/crypto/ssh/terminal/util.go index 02dad484e5..3911040840 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 @@ -108,9 +108,7 @@ func ReadPassword(fd int) ([]byte, error) { return nil, err } - defer func() { - unix.IoctlSetTermios(fd, ioctlWriteTermios, termios) - }() + defer unix.IoctlSetTermios(fd, ioctlWriteTermios, termios) return readPasswordLine(passwordReader(fd)) } diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_aix.go b/vendor/golang.org/x/crypto/ssh/terminal/util_aix.go new file mode 100644 index 0000000000..dfcd627859 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/terminal/util_aix.go @@ -0,0 +1,12 @@ +// 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 aix + +package terminal + +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 799f049f04..9317ac7ede 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 a2e1b57dc1..3d5f06a9f0 100644 --- a/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go +++ b/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go @@ -14,10 +14,10 @@ import ( // State contains the state of a terminal. type State struct { - state *unix.Termios + 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 @@ -75,47 +75,43 @@ func ReadPassword(fd int) ([]byte, error) { // restored. // see http://cr.illumos.org/~webrev/andy_js/1060/ func MakeRaw(fd int) (*State, error) { - oldTermiosPtr, err := unix.IoctlGetTermios(fd, unix.TCGETS) + termios, err := unix.IoctlGetTermios(fd, unix.TCGETS) if err != nil { return nil, err } - oldTermios := *oldTermiosPtr - newTermios := oldTermios - newTermios.Iflag &^= syscall.IGNBRK | syscall.BRKINT | syscall.PARMRK | syscall.ISTRIP | syscall.INLCR | syscall.IGNCR | syscall.ICRNL | syscall.IXON - newTermios.Oflag &^= syscall.OPOST - newTermios.Lflag &^= syscall.ECHO | syscall.ECHONL | syscall.ICANON | syscall.ISIG | syscall.IEXTEN - newTermios.Cflag &^= syscall.CSIZE | syscall.PARENB - newTermios.Cflag |= syscall.CS8 - newTermios.Cc[unix.VMIN] = 1 - newTermios.Cc[unix.VTIME] = 0 + oldState := State{termios: *termios} - if err := unix.IoctlSetTermios(fd, unix.TCSETS, &newTermios); err != nil { + termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON + termios.Oflag &^= unix.OPOST + termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN + termios.Cflag &^= unix.CSIZE | unix.PARENB + termios.Cflag |= unix.CS8 + termios.Cc[unix.VMIN] = 1 + termios.Cc[unix.VTIME] = 0 + + if err := unix.IoctlSetTermios(fd, unix.TCSETS, termios); err != nil { return nil, err } - return &State{ - state: oldTermiosPtr, - }, nil + return &oldState, nil } // Restore restores the terminal connected to the given file descriptor to a // previous state. func Restore(fd int, oldState *State) error { - return unix.IoctlSetTermios(fd, unix.TCSETS, oldState.state) + return unix.IoctlSetTermios(fd, unix.TCSETS, &oldState.termios) } // GetState returns the current state of a terminal which may be useful to // restore the terminal after a signal. func GetState(fd int) (*State, error) { - oldTermiosPtr, err := unix.IoctlGetTermios(fd, unix.TCGETS) + termios, err := unix.IoctlGetTermios(fd, unix.TCGETS) if err != nil { return nil, err } - return &State{ - state: oldTermiosPtr, - }, nil + return &State{termios: *termios}, nil } // GetSize returns the dimensions of the given terminal. 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 60979ccd00..6cb8a95038 100644 --- a/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go +++ b/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go @@ -17,6 +17,8 @@ package terminal import ( + "os" + "golang.org/x/sys/windows" ) @@ -24,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) @@ -71,13 +73,6 @@ func GetSize(fd int) (width, height int, err error) { return int(info.Size.X), int(info.Size.Y), nil } -// passwordReader is an io.Reader that reads from a specific Windows HANDLE. -type passwordReader int - -func (r passwordReader) Read(buf []byte) (int, error) { - return windows.Read(windows.Handle(r), buf) -} - // ReadPassword reads a line of input from a terminal without local echo. This // is commonly used for inputting passwords and other sensitive data. The slice // returned does not include the \n. @@ -94,9 +89,15 @@ func ReadPassword(fd int) ([]byte, error) { return nil, err } - defer func() { - windows.SetConsoleMode(windows.Handle(fd), old) - }() + defer windows.SetConsoleMode(windows.Handle(fd), old) - return readPasswordLine(passwordReader(fd)) + var h windows.Handle + p, _ := windows.GetCurrentProcess() + if err := windows.DuplicateHandle(p, windows.Handle(fd), p, &h, 0, false, windows.DUPLICATE_SAME_ACCESS); err != nil { + return nil, err + } + + f := os.NewFile(uintptr(h), "stdin") + defer f.Close() + return readPasswordLine(f) } diff --git a/vendor/golang.org/x/crypto/ssh/transport.go b/vendor/golang.org/x/crypto/ssh/transport.go index ab2b88765a..f6fae1db46 100644 --- a/vendor/golang.org/x/crypto/ssh/transport.go +++ b/vendor/golang.org/x/crypto/ssh/transport.go @@ -6,6 +6,7 @@ package ssh import ( "bufio" + "bytes" "errors" "io" "log" @@ -76,17 +77,17 @@ type connectionState struct { // both directions are triggered by reading and writing a msgNewKey packet // respectively. func (t *transport) prepareKeyChange(algs *algorithms, kexResult *kexResult) error { - if ciph, err := newPacketCipher(t.reader.dir, algs.r, kexResult); err != nil { + ciph, err := newPacketCipher(t.reader.dir, algs.r, kexResult) + if err != nil { return err - } else { - t.reader.pendingKeyChange <- ciph } + t.reader.pendingKeyChange <- ciph - if ciph, err := newPacketCipher(t.writer.dir, algs.w, kexResult); err != nil { + ciph, err = newPacketCipher(t.writer.dir, algs.w, kexResult) + if err != nil { return err - } else { - t.writer.pendingKeyChange <- ciph } + t.writer.pendingKeyChange <- ciph return nil } @@ -139,7 +140,7 @@ func (s *connectionState) readPacket(r *bufio.Reader) ([]byte, error) { case cipher := <-s.pendingKeyChange: s.packetCipher = cipher default: - return nil, errors.New("ssh: got bogus newkeys message.") + return nil, errors.New("ssh: got bogus newkeys message") } case msgDisconnect: @@ -232,52 +233,22 @@ var ( clientKeys = direction{[]byte{'A'}, []byte{'C'}, []byte{'E'}} ) -// generateKeys generates key material for IV, MAC and encryption. -func generateKeys(d direction, algs directionAlgorithms, kex *kexResult) (iv, key, macKey []byte) { - cipherMode := cipherModes[algs.Cipher] - macMode := macModes[algs.MAC] - - iv = make([]byte, cipherMode.ivSize) - key = make([]byte, cipherMode.keySize) - macKey = make([]byte, macMode.keySize) - - generateKeyMaterial(iv, d.ivTag, kex) - generateKeyMaterial(key, d.keyTag, kex) - generateKeyMaterial(macKey, d.macKeyTag, kex) - return -} - // setupKeys sets the cipher and MAC keys from kex.K, kex.H and sessionId, as // described in RFC 4253, section 6.4. direction should either be serverKeys // (to setup server->client keys) or clientKeys (for client->server keys). func newPacketCipher(d direction, algs directionAlgorithms, kex *kexResult) (packetCipher, error) { - iv, key, macKey := generateKeys(d, algs, kex) + cipherMode := cipherModes[algs.Cipher] + macMode := macModes[algs.MAC] - if algs.Cipher == gcmCipherID { - return newGCMCipher(iv, key) - } + iv := make([]byte, cipherMode.ivSize) + key := make([]byte, cipherMode.keySize) + macKey := make([]byte, macMode.keySize) - if algs.Cipher == aes128cbcID { - return newAESCBCCipher(iv, key, macKey, algs) - } + generateKeyMaterial(iv, d.ivTag, kex) + generateKeyMaterial(key, d.keyTag, kex) + generateKeyMaterial(macKey, d.macKeyTag, kex) - if algs.Cipher == tripledescbcID { - return newTripleDESCBCCipher(iv, key, macKey, algs) - } - - c := &streamPacketCipher{ - mac: macModes[algs.MAC].new(macKey), - etm: macModes[algs.MAC].etm, - } - c.macResult = make([]byte, c.mac.Size()) - - var err error - c.cipher, err = cipherModes[algs.Cipher].createStream(key, iv) - if err != nil { - return nil, err - } - - return c, nil + return cipherModes[algs.Cipher].create(key, iv, macKey, algs) } // generateKeyMaterial fills out with key material generated from tag, K, H @@ -342,7 +313,7 @@ func readVersion(r io.Reader) ([]byte, error) { var ok bool var buf [1]byte - for len(versionString) < maxVersionStringBytes { + for length := 0; length < maxVersionStringBytes; length++ { _, err := io.ReadFull(r, buf[:]) if err != nil { return nil, err @@ -350,6 +321,13 @@ func readVersion(r io.Reader) ([]byte, error) { // The RFC says that the version should be terminated with \r\n // but several SSH servers actually only send a \n. if buf[0] == '\n' { + if !bytes.HasPrefix(versionString, []byte("SSH-")) { + // RFC 4253 says we need to ignore all version string lines + // except the one containing the SSH version (provided that + // all the lines do not exceed 255 bytes in total). + versionString = versionString[:0] + continue + } ok = true break } diff --git a/vendor/golang.org/x/net/idna/idna.go b/vendor/golang.org/x/net/idna/idna.go new file mode 100644 index 0000000000..346fe4423e --- /dev/null +++ b/vendor/golang.org/x/net/idna/idna.go @@ -0,0 +1,732 @@ +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. + +// Copyright 2016 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 idna implements IDNA2008 using the compatibility processing +// defined by UTS (Unicode Technical Standard) #46, which defines a standard to +// deal with the transition from IDNA2003. +// +// IDNA2008 (Internationalized Domain Names for Applications), is defined in RFC +// 5890, RFC 5891, RFC 5892, RFC 5893 and RFC 5894. +// UTS #46 is defined in http://www.unicode.org/reports/tr46. +// See http://unicode.org/cldr/utility/idna.jsp for a visualization of the +// differences between these two standards. +package idna // import "golang.org/x/net/idna" + +import ( + "fmt" + "strings" + "unicode/utf8" + + "golang.org/x/text/secure/bidirule" + "golang.org/x/text/unicode/bidi" + "golang.org/x/text/unicode/norm" +) + +// NOTE: Unlike common practice in Go APIs, the functions will return a +// sanitized domain name in case of errors. Browsers sometimes use a partially +// evaluated string as lookup. +// TODO: the current error handling is, in my opinion, the least opinionated. +// Other strategies are also viable, though: +// Option 1) Return an empty string in case of error, but allow the user to +// specify explicitly which errors to ignore. +// Option 2) Return the partially evaluated string if it is itself a valid +// string, otherwise return the empty string in case of error. +// Option 3) Option 1 and 2. +// Option 4) Always return an empty string for now and implement Option 1 as +// needed, and document that the return string may not be empty in case of +// error in the future. +// I think Option 1 is best, but it is quite opinionated. + +// ToASCII is a wrapper for Punycode.ToASCII. +func ToASCII(s string) (string, error) { + return Punycode.process(s, true) +} + +// ToUnicode is a wrapper for Punycode.ToUnicode. +func ToUnicode(s string) (string, error) { + return Punycode.process(s, false) +} + +// An Option configures a Profile at creation time. +type Option func(*options) + +// Transitional sets a Profile to use the Transitional mapping as defined in UTS +// #46. This will cause, for example, "ß" to be mapped to "ss". Using the +// transitional mapping provides a compromise between IDNA2003 and IDNA2008 +// compatibility. It is used by most browsers when resolving domain names. This +// option is only meaningful if combined with MapForLookup. +func Transitional(transitional bool) Option { + return func(o *options) { o.transitional = true } +} + +// VerifyDNSLength sets whether a Profile should fail if any of the IDN parts +// are longer than allowed by the RFC. +func VerifyDNSLength(verify bool) Option { + return func(o *options) { o.verifyDNSLength = verify } +} + +// RemoveLeadingDots removes leading label separators. Leading runes that map to +// dots, such as U+3002 IDEOGRAPHIC FULL STOP, are removed as well. +// +// This is the behavior suggested by the UTS #46 and is adopted by some +// browsers. +func RemoveLeadingDots(remove bool) Option { + return func(o *options) { o.removeLeadingDots = remove } +} + +// ValidateLabels sets whether to check the mandatory label validation criteria +// as defined in Section 5.4 of RFC 5891. This includes testing for correct use +// of hyphens ('-'), normalization, validity of runes, and the context rules. +func ValidateLabels(enable bool) Option { + return func(o *options) { + // Don't override existing mappings, but set one that at least checks + // normalization if it is not set. + if o.mapping == nil && enable { + o.mapping = normalize + } + o.trie = trie + o.validateLabels = enable + o.fromPuny = validateFromPunycode + } +} + +// StrictDomainName limits the set of permissible ASCII characters to those +// allowed in domain names as defined in RFC 1034 (A-Z, a-z, 0-9 and the +// hyphen). This is set by default for MapForLookup and ValidateForRegistration. +// +// This option is useful, for instance, for browsers that allow characters +// outside this range, for example a '_' (U+005F LOW LINE). See +// http://www.rfc-editor.org/std/std3.txt for more details This option +// corresponds to the UseSTD3ASCIIRules option in UTS #46. +func StrictDomainName(use bool) Option { + return func(o *options) { + o.trie = trie + o.useSTD3Rules = use + o.fromPuny = validateFromPunycode + } +} + +// NOTE: the following options pull in tables. The tables should not be linked +// in as long as the options are not used. + +// BidiRule enables the Bidi rule as defined in RFC 5893. Any application +// that relies on proper validation of labels should include this rule. +func BidiRule() Option { + return func(o *options) { o.bidirule = bidirule.ValidString } +} + +// ValidateForRegistration sets validation options to verify that a given IDN is +// properly formatted for registration as defined by Section 4 of RFC 5891. +func ValidateForRegistration() Option { + return func(o *options) { + o.mapping = validateRegistration + StrictDomainName(true)(o) + ValidateLabels(true)(o) + VerifyDNSLength(true)(o) + BidiRule()(o) + } +} + +// MapForLookup sets validation and mapping options such that a given IDN is +// transformed for domain name lookup according to the requirements set out in +// Section 5 of RFC 5891. The mappings follow the recommendations of RFC 5894, +// RFC 5895 and UTS 46. It does not add the Bidi Rule. Use the BidiRule option +// to add this check. +// +// The mappings include normalization and mapping case, width and other +// compatibility mappings. +func MapForLookup() Option { + return func(o *options) { + o.mapping = validateAndMap + StrictDomainName(true)(o) + ValidateLabels(true)(o) + } +} + +type options struct { + transitional bool + useSTD3Rules bool + validateLabels bool + verifyDNSLength bool + removeLeadingDots bool + + trie *idnaTrie + + // fromPuny calls validation rules when converting A-labels to U-labels. + fromPuny func(p *Profile, s string) error + + // mapping implements a validation and mapping step as defined in RFC 5895 + // or UTS 46, tailored to, for example, domain registration or lookup. + mapping func(p *Profile, s string) (mapped string, isBidi bool, err error) + + // bidirule, if specified, checks whether s conforms to the Bidi Rule + // defined in RFC 5893. + bidirule func(s string) bool +} + +// A Profile defines the configuration of an IDNA mapper. +type Profile struct { + options +} + +func apply(o *options, opts []Option) { + for _, f := range opts { + f(o) + } +} + +// New creates a new Profile. +// +// With no options, the returned Profile is the most permissive and equals the +// Punycode Profile. Options can be passed to further restrict the Profile. The +// MapForLookup and ValidateForRegistration options set a collection of options, +// for lookup and registration purposes respectively, which can be tailored by +// adding more fine-grained options, where later options override earlier +// options. +func New(o ...Option) *Profile { + p := &Profile{} + apply(&p.options, o) + return p +} + +// ToASCII converts a domain or domain label to its ASCII form. For example, +// ToASCII("bücher.example.com") is "xn--bcher-kva.example.com", and +// ToASCII("golang") is "golang". If an error is encountered it will return +// an error and a (partially) processed result. +func (p *Profile) ToASCII(s string) (string, error) { + return p.process(s, true) +} + +// ToUnicode converts a domain or domain label to its Unicode form. For example, +// ToUnicode("xn--bcher-kva.example.com") is "bücher.example.com", and +// ToUnicode("golang") is "golang". If an error is encountered it will return +// an error and a (partially) processed result. +func (p *Profile) ToUnicode(s string) (string, error) { + pp := *p + pp.transitional = false + return pp.process(s, false) +} + +// String reports a string with a description of the profile for debugging +// purposes. The string format may change with different versions. +func (p *Profile) String() string { + s := "" + if p.transitional { + s = "Transitional" + } else { + s = "NonTransitional" + } + if p.useSTD3Rules { + s += ":UseSTD3Rules" + } + if p.validateLabels { + s += ":ValidateLabels" + } + if p.verifyDNSLength { + s += ":VerifyDNSLength" + } + return s +} + +var ( + // Punycode is a Profile that does raw punycode processing with a minimum + // of validation. + Punycode *Profile = punycode + + // Lookup is the recommended profile for looking up domain names, according + // to Section 5 of RFC 5891. The exact configuration of this profile may + // change over time. + Lookup *Profile = lookup + + // Display is the recommended profile for displaying domain names. + // The configuration of this profile may change over time. + Display *Profile = display + + // Registration is the recommended profile for checking whether a given + // IDN is valid for registration, according to Section 4 of RFC 5891. + Registration *Profile = registration + + punycode = &Profile{} + lookup = &Profile{options{ + transitional: true, + useSTD3Rules: true, + validateLabels: true, + trie: trie, + fromPuny: validateFromPunycode, + mapping: validateAndMap, + bidirule: bidirule.ValidString, + }} + display = &Profile{options{ + useSTD3Rules: true, + validateLabels: true, + trie: trie, + fromPuny: validateFromPunycode, + mapping: validateAndMap, + bidirule: bidirule.ValidString, + }} + registration = &Profile{options{ + useSTD3Rules: true, + validateLabels: true, + verifyDNSLength: true, + trie: trie, + fromPuny: validateFromPunycode, + mapping: validateRegistration, + bidirule: bidirule.ValidString, + }} + + // TODO: profiles + // Register: recommended for approving domain names: don't do any mappings + // but rather reject on invalid input. Bundle or block deviation characters. +) + +type labelError struct{ label, code_ string } + +func (e labelError) code() string { return e.code_ } +func (e labelError) Error() string { + return fmt.Sprintf("idna: invalid label %q", e.label) +} + +type runeError rune + +func (e runeError) code() string { return "P1" } +func (e runeError) Error() string { + return fmt.Sprintf("idna: disallowed rune %U", e) +} + +// process implements the algorithm described in section 4 of UTS #46, +// see http://www.unicode.org/reports/tr46. +func (p *Profile) process(s string, toASCII bool) (string, error) { + var err error + var isBidi bool + if p.mapping != nil { + s, isBidi, err = p.mapping(p, s) + } + // Remove leading empty labels. + if p.removeLeadingDots { + for ; len(s) > 0 && s[0] == '.'; s = s[1:] { + } + } + // TODO: allow for a quick check of the tables data. + // It seems like we should only create this error on ToASCII, but the + // UTS 46 conformance tests suggests we should always check this. + if err == nil && p.verifyDNSLength && s == "" { + err = &labelError{s, "A4"} + } + labels := labelIter{orig: s} + for ; !labels.done(); labels.next() { + label := labels.label() + if label == "" { + // Empty labels are not okay. The label iterator skips the last + // label if it is empty. + if err == nil && p.verifyDNSLength { + err = &labelError{s, "A4"} + } + continue + } + if strings.HasPrefix(label, acePrefix) { + u, err2 := decode(label[len(acePrefix):]) + if err2 != nil { + if err == nil { + err = err2 + } + // Spec says keep the old label. + continue + } + isBidi = isBidi || bidirule.DirectionString(u) != bidi.LeftToRight + labels.set(u) + if err == nil && p.validateLabels { + err = p.fromPuny(p, u) + } + if err == nil { + // This should be called on NonTransitional, according to the + // spec, but that currently does not have any effect. Use the + // original profile to preserve options. + err = p.validateLabel(u) + } + } else if err == nil { + err = p.validateLabel(label) + } + } + if isBidi && p.bidirule != nil && err == nil { + for labels.reset(); !labels.done(); labels.next() { + if !p.bidirule(labels.label()) { + err = &labelError{s, "B"} + break + } + } + } + if toASCII { + for labels.reset(); !labels.done(); labels.next() { + label := labels.label() + if !ascii(label) { + a, err2 := encode(acePrefix, label) + if err == nil { + err = err2 + } + label = a + labels.set(a) + } + n := len(label) + if p.verifyDNSLength && err == nil && (n == 0 || n > 63) { + err = &labelError{label, "A4"} + } + } + } + s = labels.result() + if toASCII && p.verifyDNSLength && err == nil { + // Compute the length of the domain name minus the root label and its dot. + n := len(s) + if n > 0 && s[n-1] == '.' { + n-- + } + if len(s) < 1 || n > 253 { + err = &labelError{s, "A4"} + } + } + return s, err +} + +func normalize(p *Profile, s string) (mapped string, isBidi bool, err error) { + // TODO: consider first doing a quick check to see if any of these checks + // need to be done. This will make it slower in the general case, but + // faster in the common case. + mapped = norm.NFC.String(s) + isBidi = bidirule.DirectionString(mapped) == bidi.RightToLeft + return mapped, isBidi, nil +} + +func validateRegistration(p *Profile, s string) (idem string, bidi bool, err error) { + // TODO: filter need for normalization in loop below. + if !norm.NFC.IsNormalString(s) { + return s, false, &labelError{s, "V1"} + } + for i := 0; i < len(s); { + v, sz := trie.lookupString(s[i:]) + if sz == 0 { + return s, bidi, runeError(utf8.RuneError) + } + bidi = bidi || info(v).isBidi(s[i:]) + // Copy bytes not copied so far. + switch p.simplify(info(v).category()) { + // TODO: handle the NV8 defined in the Unicode idna data set to allow + // for strict conformance to IDNA2008. + case valid, deviation: + case disallowed, mapped, unknown, ignored: + r, _ := utf8.DecodeRuneInString(s[i:]) + return s, bidi, runeError(r) + } + i += sz + } + return s, bidi, nil +} + +func (c info) isBidi(s string) bool { + if !c.isMapped() { + return c&attributesMask == rtl + } + // TODO: also store bidi info for mapped data. This is possible, but a bit + // cumbersome and not for the common case. + p, _ := bidi.LookupString(s) + switch p.Class() { + case bidi.R, bidi.AL, bidi.AN: + return true + } + return false +} + +func validateAndMap(p *Profile, s string) (vm string, bidi bool, err error) { + var ( + b []byte + k int + ) + // combinedInfoBits contains the or-ed bits of all runes. We use this + // to derive the mayNeedNorm bit later. This may trigger normalization + // overeagerly, but it will not do so in the common case. The end result + // is another 10% saving on BenchmarkProfile for the common case. + var combinedInfoBits info + for i := 0; i < len(s); { + v, sz := trie.lookupString(s[i:]) + if sz == 0 { + b = append(b, s[k:i]...) + b = append(b, "\ufffd"...) + k = len(s) + if err == nil { + err = runeError(utf8.RuneError) + } + break + } + combinedInfoBits |= info(v) + bidi = bidi || info(v).isBidi(s[i:]) + start := i + i += sz + // Copy bytes not copied so far. + switch p.simplify(info(v).category()) { + case valid: + continue + case disallowed: + if err == nil { + r, _ := utf8.DecodeRuneInString(s[start:]) + err = runeError(r) + } + continue + case mapped, deviation: + b = append(b, s[k:start]...) + b = info(v).appendMapping(b, s[start:i]) + case ignored: + b = append(b, s[k:start]...) + // drop the rune + case unknown: + b = append(b, s[k:start]...) + b = append(b, "\ufffd"...) + } + k = i + } + if k == 0 { + // No changes so far. + if combinedInfoBits&mayNeedNorm != 0 { + s = norm.NFC.String(s) + } + } else { + b = append(b, s[k:]...) + if norm.NFC.QuickSpan(b) != len(b) { + b = norm.NFC.Bytes(b) + } + // TODO: the punycode converters require strings as input. + s = string(b) + } + return s, bidi, err +} + +// A labelIter allows iterating over domain name labels. +type labelIter struct { + orig string + slice []string + curStart int + curEnd int + i int +} + +func (l *labelIter) reset() { + l.curStart = 0 + l.curEnd = 0 + l.i = 0 +} + +func (l *labelIter) done() bool { + return l.curStart >= len(l.orig) +} + +func (l *labelIter) result() string { + if l.slice != nil { + return strings.Join(l.slice, ".") + } + return l.orig +} + +func (l *labelIter) label() string { + if l.slice != nil { + return l.slice[l.i] + } + p := strings.IndexByte(l.orig[l.curStart:], '.') + l.curEnd = l.curStart + p + if p == -1 { + l.curEnd = len(l.orig) + } + return l.orig[l.curStart:l.curEnd] +} + +// next sets the value to the next label. It skips the last label if it is empty. +func (l *labelIter) next() { + l.i++ + if l.slice != nil { + if l.i >= len(l.slice) || l.i == len(l.slice)-1 && l.slice[l.i] == "" { + l.curStart = len(l.orig) + } + } else { + l.curStart = l.curEnd + 1 + if l.curStart == len(l.orig)-1 && l.orig[l.curStart] == '.' { + l.curStart = len(l.orig) + } + } +} + +func (l *labelIter) set(s string) { + if l.slice == nil { + l.slice = strings.Split(l.orig, ".") + } + l.slice[l.i] = s +} + +// acePrefix is the ASCII Compatible Encoding prefix. +const acePrefix = "xn--" + +func (p *Profile) simplify(cat category) category { + switch cat { + case disallowedSTD3Mapped: + if p.useSTD3Rules { + cat = disallowed + } else { + cat = mapped + } + case disallowedSTD3Valid: + if p.useSTD3Rules { + cat = disallowed + } else { + cat = valid + } + case deviation: + if !p.transitional { + cat = valid + } + case validNV8, validXV8: + // TODO: handle V2008 + cat = valid + } + return cat +} + +func validateFromPunycode(p *Profile, s string) error { + if !norm.NFC.IsNormalString(s) { + return &labelError{s, "V1"} + } + // TODO: detect whether string may have to be normalized in the following + // loop. + for i := 0; i < len(s); { + v, sz := trie.lookupString(s[i:]) + if sz == 0 { + return runeError(utf8.RuneError) + } + if c := p.simplify(info(v).category()); c != valid && c != deviation { + return &labelError{s, "V6"} + } + i += sz + } + return nil +} + +const ( + zwnj = "\u200c" + zwj = "\u200d" +) + +type joinState int8 + +const ( + stateStart joinState = iota + stateVirama + stateBefore + stateBeforeVirama + stateAfter + stateFAIL +) + +var joinStates = [][numJoinTypes]joinState{ + stateStart: { + joiningL: stateBefore, + joiningD: stateBefore, + joinZWNJ: stateFAIL, + joinZWJ: stateFAIL, + joinVirama: stateVirama, + }, + stateVirama: { + joiningL: stateBefore, + joiningD: stateBefore, + }, + stateBefore: { + joiningL: stateBefore, + joiningD: stateBefore, + joiningT: stateBefore, + joinZWNJ: stateAfter, + joinZWJ: stateFAIL, + joinVirama: stateBeforeVirama, + }, + stateBeforeVirama: { + joiningL: stateBefore, + joiningD: stateBefore, + joiningT: stateBefore, + }, + stateAfter: { + joiningL: stateFAIL, + joiningD: stateBefore, + joiningT: stateAfter, + joiningR: stateStart, + joinZWNJ: stateFAIL, + joinZWJ: stateFAIL, + joinVirama: stateAfter, // no-op as we can't accept joiners here + }, + stateFAIL: { + 0: stateFAIL, + joiningL: stateFAIL, + joiningD: stateFAIL, + joiningT: stateFAIL, + joiningR: stateFAIL, + joinZWNJ: stateFAIL, + joinZWJ: stateFAIL, + joinVirama: stateFAIL, + }, +} + +// validateLabel validates the criteria from Section 4.1. Item 1, 4, and 6 are +// already implicitly satisfied by the overall implementation. +func (p *Profile) validateLabel(s string) (err error) { + if s == "" { + if p.verifyDNSLength { + return &labelError{s, "A4"} + } + return nil + } + if !p.validateLabels { + return nil + } + trie := p.trie // p.validateLabels is only set if trie is set. + if len(s) > 4 && s[2] == '-' && s[3] == '-' { + return &labelError{s, "V2"} + } + if s[0] == '-' || s[len(s)-1] == '-' { + return &labelError{s, "V3"} + } + // TODO: merge the use of this in the trie. + v, sz := trie.lookupString(s) + x := info(v) + if x.isModifier() { + return &labelError{s, "V5"} + } + // Quickly return in the absence of zero-width (non) joiners. + if strings.Index(s, zwj) == -1 && strings.Index(s, zwnj) == -1 { + return nil + } + st := stateStart + for i := 0; ; { + jt := x.joinType() + if s[i:i+sz] == zwj { + jt = joinZWJ + } else if s[i:i+sz] == zwnj { + jt = joinZWNJ + } + st = joinStates[st][jt] + if x.isViramaModifier() { + st = joinStates[st][joinVirama] + } + if i += sz; i == len(s) { + break + } + v, sz = trie.lookupString(s[i:]) + x = info(v) + } + if st == stateFAIL || st == stateAfter { + return &labelError{s, "C"} + } + return nil +} + +func ascii(s string) bool { + for i := 0; i < len(s); i++ { + if s[i] >= utf8.RuneSelf { + return false + } + } + return true +} diff --git a/vendor/golang.org/x/net/idna/punycode.go b/vendor/golang.org/x/net/idna/punycode.go new file mode 100644 index 0000000000..02c7d59af3 --- /dev/null +++ b/vendor/golang.org/x/net/idna/punycode.go @@ -0,0 +1,203 @@ +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. + +// Copyright 2016 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 idna + +// This file implements the Punycode algorithm from RFC 3492. + +import ( + "math" + "strings" + "unicode/utf8" +) + +// These parameter values are specified in section 5. +// +// All computation is done with int32s, so that overflow behavior is identical +// regardless of whether int is 32-bit or 64-bit. +const ( + base int32 = 36 + damp int32 = 700 + initialBias int32 = 72 + initialN int32 = 128 + skew int32 = 38 + tmax int32 = 26 + tmin int32 = 1 +) + +func punyError(s string) error { return &labelError{s, "A3"} } + +// decode decodes a string as specified in section 6.2. +func decode(encoded string) (string, error) { + if encoded == "" { + return "", nil + } + pos := 1 + strings.LastIndex(encoded, "-") + if pos == 1 { + return "", punyError(encoded) + } + if pos == len(encoded) { + return encoded[:len(encoded)-1], nil + } + output := make([]rune, 0, len(encoded)) + if pos != 0 { + for _, r := range encoded[:pos-1] { + output = append(output, r) + } + } + i, n, bias := int32(0), initialN, initialBias + for pos < len(encoded) { + oldI, w := i, int32(1) + for k := base; ; k += base { + if pos == len(encoded) { + return "", punyError(encoded) + } + digit, ok := decodeDigit(encoded[pos]) + if !ok { + return "", punyError(encoded) + } + pos++ + i += digit * w + if i < 0 { + return "", punyError(encoded) + } + t := k - bias + if t < tmin { + t = tmin + } else if t > tmax { + t = tmax + } + if digit < t { + break + } + w *= base - t + if w >= math.MaxInt32/base { + return "", punyError(encoded) + } + } + x := int32(len(output) + 1) + bias = adapt(i-oldI, x, oldI == 0) + n += i / x + i %= x + if n > utf8.MaxRune || len(output) >= 1024 { + return "", punyError(encoded) + } + output = append(output, 0) + copy(output[i+1:], output[i:]) + output[i] = n + i++ + } + return string(output), nil +} + +// encode encodes a string as specified in section 6.3 and prepends prefix to +// the result. +// +// The "while h < length(input)" line in the specification becomes "for +// remaining != 0" in the Go code, because len(s) in Go is in bytes, not runes. +func encode(prefix, s string) (string, error) { + output := make([]byte, len(prefix), len(prefix)+1+2*len(s)) + copy(output, prefix) + delta, n, bias := int32(0), initialN, initialBias + b, remaining := int32(0), int32(0) + for _, r := range s { + if r < 0x80 { + b++ + output = append(output, byte(r)) + } else { + remaining++ + } + } + h := b + if b > 0 { + output = append(output, '-') + } + for remaining != 0 { + m := int32(0x7fffffff) + for _, r := range s { + if m > r && r >= n { + m = r + } + } + delta += (m - n) * (h + 1) + if delta < 0 { + return "", punyError(s) + } + n = m + for _, r := range s { + if r < n { + delta++ + if delta < 0 { + return "", punyError(s) + } + continue + } + if r > n { + continue + } + q := delta + for k := base; ; k += base { + t := k - bias + if t < tmin { + t = tmin + } else if t > tmax { + t = tmax + } + if q < t { + break + } + output = append(output, encodeDigit(t+(q-t)%(base-t))) + q = (q - t) / (base - t) + } + output = append(output, encodeDigit(q)) + bias = adapt(delta, h+1, h == b) + delta = 0 + h++ + remaining-- + } + delta++ + n++ + } + return string(output), nil +} + +func decodeDigit(x byte) (digit int32, ok bool) { + switch { + case '0' <= x && x <= '9': + return int32(x - ('0' - 26)), true + case 'A' <= x && x <= 'Z': + return int32(x - 'A'), true + case 'a' <= x && x <= 'z': + return int32(x - 'a'), true + } + return 0, false +} + +func encodeDigit(digit int32) byte { + switch { + case 0 <= digit && digit < 26: + return byte(digit + 'a') + case 26 <= digit && digit < 36: + return byte(digit + ('0' - 26)) + } + panic("idna: internal error in punycode encoding") +} + +// adapt is the bias adaptation function specified in section 6.1. +func adapt(delta, numPoints int32, firstTime bool) int32 { + if firstTime { + delta /= damp + } else { + delta /= 2 + } + delta += delta / numPoints + k := int32(0) + for delta > ((base-tmin)*tmax)/2 { + delta /= base - tmin + k += base + } + return k + (base-tmin+1)*delta/(delta+skew) +} diff --git a/vendor/golang.org/x/net/idna/tables.go b/vendor/golang.org/x/net/idna/tables.go new file mode 100644 index 0000000000..f910b26914 --- /dev/null +++ b/vendor/golang.org/x/net/idna/tables.go @@ -0,0 +1,4557 @@ +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. + +package idna + +// UnicodeVersion is the Unicode version from which the tables in this package are derived. +const UnicodeVersion = "10.0.0" + +var mappings string = "" + // Size: 8176 bytes + "\x00\x01 \x03 ̈\x01a\x03 ̄\x012\x013\x03 ́\x03 ̧\x011\x01o\x051⁄4\x051⁄2" + + "\x053⁄4\x03i̇\x03l·\x03ʼn\x01s\x03dž\x03ⱥ\x03ⱦ\x01h\x01j\x01r\x01w\x01y" + + "\x03 ̆\x03 ̇\x03 ̊\x03 ̨\x03 ̃\x03 ̋\x01l\x01x\x04̈́\x03 ι\x01;\x05 ̈́" + + "\x04եւ\x04اٴ\x04وٴ\x04ۇٴ\x04يٴ\x06क़\x06ख़\x06ग़\x06ज़\x06ड़\x06ढ़\x06फ़" + + "\x06य़\x06ড়\x06ঢ়\x06য়\x06ਲ਼\x06ਸ਼\x06ਖ਼\x06ਗ਼\x06ਜ਼\x06ਫ਼\x06ଡ଼\x06ଢ଼" + + "\x06ํา\x06ໍາ\x06ຫນ\x06ຫມ\x06གྷ\x06ཌྷ\x06དྷ\x06བྷ\x06ཛྷ\x06ཀྵ\x06ཱི\x06ཱུ" + + "\x06ྲྀ\x09ྲཱྀ\x06ླྀ\x09ླཱྀ\x06ཱྀ\x06ྒྷ\x06ྜྷ\x06ྡྷ\x06ྦྷ\x06ྫྷ\x06ྐྵ\x02" + + "в\x02д\x02о\x02с\x02т\x02ъ\x02ѣ\x02æ\x01b\x01d\x01e\x02ǝ\x01g\x01i\x01k" + + "\x01m\x01n\x02ȣ\x01p\x01t\x01u\x02ɐ\x02ɑ\x02ə\x02ɛ\x02ɜ\x02ŋ\x02ɔ\x02ɯ" + + "\x01v\x02β\x02γ\x02δ\x02φ\x02χ\x02ρ\x02н\x02ɒ\x01c\x02ɕ\x02ð\x01f\x02ɟ" + + "\x02ɡ\x02ɥ\x02ɨ\x02ɩ\x02ɪ\x02ʝ\x02ɭ\x02ʟ\x02ɱ\x02ɰ\x02ɲ\x02ɳ\x02ɴ\x02ɵ" + + "\x02ɸ\x02ʂ\x02ʃ\x02ƫ\x02ʉ\x02ʊ\x02ʋ\x02ʌ\x01z\x02ʐ\x02ʑ\x02ʒ\x02θ\x02ss" + + "\x02ά\x02έ\x02ή\x02ί\x02ό\x02ύ\x02ώ\x05ἀι\x05ἁι\x05ἂι\x05ἃι\x05ἄι\x05ἅι" + + "\x05ἆι\x05ἇι\x05ἠι\x05ἡι\x05ἢι\x05ἣι\x05ἤι\x05ἥι\x05ἦι\x05ἧι\x05ὠι\x05ὡι" + + "\x05ὢι\x05ὣι\x05ὤι\x05ὥι\x05ὦι\x05ὧι\x05ὰι\x04αι\x04άι\x05ᾶι\x02ι\x05 ̈͂" + + "\x05ὴι\x04ηι\x04ήι\x05ῆι\x05 ̓̀\x05 ̓́\x05 ̓͂\x02ΐ\x05 ̔̀\x05 ̔́\x05 ̔͂" + + "\x02ΰ\x05 ̈̀\x01`\x05ὼι\x04ωι\x04ώι\x05ῶι\x06′′\x09′′′\x06‵‵\x09‵‵‵\x02!" + + "!\x02??\x02?!\x02!?\x0c′′′′\x010\x014\x015\x016\x017\x018\x019\x01+\x01=" + + "\x01(\x01)\x02rs\x02ħ\x02no\x01q\x02sm\x02tm\x02ω\x02å\x02א\x02ב\x02ג" + + "\x02ד\x02π\x051⁄7\x051⁄9\x061⁄10\x051⁄3\x052⁄3\x051⁄5\x052⁄5\x053⁄5\x054" + + "⁄5\x051⁄6\x055⁄6\x051⁄8\x053⁄8\x055⁄8\x057⁄8\x041⁄\x02ii\x02iv\x02vi" + + "\x04viii\x02ix\x02xi\x050⁄3\x06∫∫\x09∫∫∫\x06∮∮\x09∮∮∮\x0210\x0211\x0212" + + "\x0213\x0214\x0215\x0216\x0217\x0218\x0219\x0220\x04(10)\x04(11)\x04(12)" + + "\x04(13)\x04(14)\x04(15)\x04(16)\x04(17)\x04(18)\x04(19)\x04(20)\x0c∫∫∫∫" + + "\x02==\x05⫝̸\x02ɫ\x02ɽ\x02ȿ\x02ɀ\x01.\x04 ゙\x04 ゚\x06より\x06コト\x05(ᄀ)\x05" + + "(ᄂ)\x05(ᄃ)\x05(ᄅ)\x05(ᄆ)\x05(ᄇ)\x05(ᄉ)\x05(ᄋ)\x05(ᄌ)\x05(ᄎ)\x05(ᄏ)\x05(ᄐ" + + ")\x05(ᄑ)\x05(ᄒ)\x05(가)\x05(나)\x05(다)\x05(라)\x05(마)\x05(바)\x05(사)\x05(아)" + + "\x05(자)\x05(차)\x05(카)\x05(타)\x05(파)\x05(하)\x05(주)\x08(오전)\x08(오후)\x05(一)" + + "\x05(二)\x05(三)\x05(四)\x05(五)\x05(六)\x05(七)\x05(八)\x05(九)\x05(十)\x05(月)" + + "\x05(火)\x05(水)\x05(木)\x05(金)\x05(土)\x05(日)\x05(株)\x05(有)\x05(社)\x05(名)" + + "\x05(特)\x05(財)\x05(祝)\x05(労)\x05(代)\x05(呼)\x05(学)\x05(監)\x05(企)\x05(資)" + + "\x05(協)\x05(祭)\x05(休)\x05(自)\x05(至)\x0221\x0222\x0223\x0224\x0225\x0226" + + "\x0227\x0228\x0229\x0230\x0231\x0232\x0233\x0234\x0235\x06참고\x06주의\x0236" + + "\x0237\x0238\x0239\x0240\x0241\x0242\x0243\x0244\x0245\x0246\x0247\x0248" + + "\x0249\x0250\x041月\x042月\x043月\x044月\x045月\x046月\x047月\x048月\x049月\x0510" + + "月\x0511月\x0512月\x02hg\x02ev\x0cアパート\x0cアルファ\x0cアンペア\x09アール\x0cイニング\x09" + + "インチ\x09ウォン\x0fエスクード\x0cエーカー\x09オンス\x09オーム\x09カイリ\x0cカラット\x0cカロリー\x09ガロ" + + "ン\x09ガンマ\x06ギガ\x09ギニー\x0cキュリー\x0cギルダー\x06キロ\x0fキログラム\x12キロメートル\x0fキロワッ" + + "ト\x09グラム\x0fグラムトン\x0fクルゼイロ\x0cクローネ\x09ケース\x09コルナ\x09コーポ\x0cサイクル\x0fサンチ" + + "ーム\x0cシリング\x09センチ\x09セント\x09ダース\x06デシ\x06ドル\x06トン\x06ナノ\x09ノット\x09ハイツ" + + "\x0fパーセント\x09パーツ\x0cバーレル\x0fピアストル\x09ピクル\x06ピコ\x06ビル\x0fファラッド\x0cフィート" + + "\x0fブッシェル\x09フラン\x0fヘクタール\x06ペソ\x09ペニヒ\x09ヘルツ\x09ペンス\x09ページ\x09ベータ\x0cポイ" + + "ント\x09ボルト\x06ホン\x09ポンド\x09ホール\x09ホーン\x0cマイクロ\x09マイル\x09マッハ\x09マルク\x0fマ" + + "ンション\x0cミクロン\x06ミリ\x0fミリバール\x06メガ\x0cメガトン\x0cメートル\x09ヤード\x09ヤール\x09ユアン" + + "\x0cリットル\x06リラ\x09ルピー\x0cルーブル\x06レム\x0fレントゲン\x09ワット\x040点\x041点\x042点" + + "\x043点\x044点\x045点\x046点\x047点\x048点\x049点\x0510点\x0511点\x0512点\x0513点" + + "\x0514点\x0515点\x0516点\x0517点\x0518点\x0519点\x0520点\x0521点\x0522点\x0523点" + + "\x0524点\x02da\x02au\x02ov\x02pc\x02dm\x02iu\x06平成\x06昭和\x06大正\x06明治\x0c株" + + "式会社\x02pa\x02na\x02ma\x02ka\x02kb\x02mb\x02gb\x04kcal\x02pf\x02nf\x02m" + + "g\x02kg\x02hz\x02ml\x02dl\x02kl\x02fm\x02nm\x02mm\x02cm\x02km\x02m2\x02m" + + "3\x05m∕s\x06m∕s2\x07rad∕s\x08rad∕s2\x02ps\x02ns\x02ms\x02pv\x02nv\x02mv" + + "\x02kv\x02pw\x02nw\x02mw\x02kw\x02bq\x02cc\x02cd\x06c∕kg\x02db\x02gy\x02" + + "ha\x02hp\x02in\x02kk\x02kt\x02lm\x02ln\x02lx\x02ph\x02pr\x02sr\x02sv\x02" + + "wb\x05v∕m\x05a∕m\x041日\x042日\x043日\x044日\x045日\x046日\x047日\x048日\x049日" + + "\x0510日\x0511日\x0512日\x0513日\x0514日\x0515日\x0516日\x0517日\x0518日\x0519日" + + "\x0520日\x0521日\x0522日\x0523日\x0524日\x0525日\x0526日\x0527日\x0528日\x0529日" + + "\x0530日\x0531日\x02ь\x02ɦ\x02ɬ\x02ʞ\x02ʇ\x02œ\x04𤋮\x04𢡊\x04𢡄\x04𣏕\x04𥉉" + + "\x04𥳐\x04𧻓\x02ff\x02fi\x02fl\x02st\x04մն\x04մե\x04մի\x04վն\x04մխ\x04יִ" + + "\x04ײַ\x02ע\x02ה\x02כ\x02ל\x02ם\x02ר\x02ת\x04שׁ\x04שׂ\x06שּׁ\x06שּׂ\x04א" + + "ַ\x04אָ\x04אּ\x04בּ\x04גּ\x04דּ\x04הּ\x04וּ\x04זּ\x04טּ\x04יּ\x04ךּ\x04" + + "כּ\x04לּ\x04מּ\x04נּ\x04סּ\x04ףּ\x04פּ\x04צּ\x04קּ\x04רּ\x04שּ\x04תּ" + + "\x04וֹ\x04בֿ\x04כֿ\x04פֿ\x04אל\x02ٱ\x02ٻ\x02پ\x02ڀ\x02ٺ\x02ٿ\x02ٹ\x02ڤ" + + "\x02ڦ\x02ڄ\x02ڃ\x02چ\x02ڇ\x02ڍ\x02ڌ\x02ڎ\x02ڈ\x02ژ\x02ڑ\x02ک\x02گ\x02ڳ" + + "\x02ڱ\x02ں\x02ڻ\x02ۀ\x02ہ\x02ھ\x02ے\x02ۓ\x02ڭ\x02ۇ\x02ۆ\x02ۈ\x02ۋ\x02ۅ" + + "\x02ۉ\x02ې\x02ى\x04ئا\x04ئە\x04ئو\x04ئۇ\x04ئۆ\x04ئۈ\x04ئې\x04ئى\x02ی\x04" + + "ئج\x04ئح\x04ئم\x04ئي\x04بج\x04بح\x04بخ\x04بم\x04بى\x04بي\x04تج\x04تح" + + "\x04تخ\x04تم\x04تى\x04تي\x04ثج\x04ثم\x04ثى\x04ثي\x04جح\x04جم\x04حج\x04حم" + + "\x04خج\x04خح\x04خم\x04سج\x04سح\x04سخ\x04سم\x04صح\x04صم\x04ضج\x04ضح\x04ضخ" + + "\x04ضم\x04طح\x04طم\x04ظم\x04عج\x04عم\x04غج\x04غم\x04فج\x04فح\x04فخ\x04فم" + + "\x04فى\x04في\x04قح\x04قم\x04قى\x04قي\x04كا\x04كج\x04كح\x04كخ\x04كل\x04كم" + + "\x04كى\x04كي\x04لج\x04لح\x04لخ\x04لم\x04لى\x04لي\x04مج\x04مح\x04مخ\x04مم" + + "\x04مى\x04مي\x04نج\x04نح\x04نخ\x04نم\x04نى\x04ني\x04هج\x04هم\x04هى\x04هي" + + "\x04يج\x04يح\x04يخ\x04يم\x04يى\x04يي\x04ذٰ\x04رٰ\x04ىٰ\x05 ٌّ\x05 ٍّ\x05" + + " َّ\x05 ُّ\x05 ِّ\x05 ّٰ\x04ئر\x04ئز\x04ئن\x04بر\x04بز\x04بن\x04تر\x04تز" + + "\x04تن\x04ثر\x04ثز\x04ثن\x04ما\x04نر\x04نز\x04نن\x04ير\x04يز\x04ين\x04ئخ" + + "\x04ئه\x04به\x04ته\x04صخ\x04له\x04نه\x04هٰ\x04يه\x04ثه\x04سه\x04شم\x04شه" + + "\x06ـَّ\x06ـُّ\x06ـِّ\x04طى\x04طي\x04عى\x04عي\x04غى\x04غي\x04سى\x04سي" + + "\x04شى\x04شي\x04حى\x04حي\x04جى\x04جي\x04خى\x04خي\x04صى\x04صي\x04ضى\x04ضي" + + "\x04شج\x04شح\x04شخ\x04شر\x04سر\x04صر\x04ضر\x04اً\x06تجم\x06تحج\x06تحم" + + "\x06تخم\x06تمج\x06تمح\x06تمخ\x06جمح\x06حمي\x06حمى\x06سحج\x06سجح\x06سجى" + + "\x06سمح\x06سمج\x06سمم\x06صحح\x06صمم\x06شحم\x06شجي\x06شمخ\x06شمم\x06ضحى" + + "\x06ضخم\x06طمح\x06طمم\x06طمي\x06عجم\x06عمم\x06عمى\x06غمم\x06غمي\x06غمى" + + "\x06فخم\x06قمح\x06قمم\x06لحم\x06لحي\x06لحى\x06لجج\x06لخم\x06لمح\x06محج" + + "\x06محم\x06محي\x06مجح\x06مجم\x06مخج\x06مخم\x06مجخ\x06همج\x06همم\x06نحم" + + "\x06نحى\x06نجم\x06نجى\x06نمي\x06نمى\x06يمم\x06بخي\x06تجي\x06تجى\x06تخي" + + "\x06تخى\x06تمي\x06تمى\x06جمي\x06جحى\x06جمى\x06سخى\x06صحي\x06شحي\x06ضحي" + + "\x06لجي\x06لمي\x06يحي\x06يجي\x06يمي\x06ممي\x06قمي\x06نحي\x06عمي\x06كمي" + + "\x06نجح\x06مخي\x06لجم\x06كمم\x06جحي\x06حجي\x06مجي\x06فمي\x06بحي\x06سخي" + + "\x06نجي\x06صلے\x06قلے\x08الله\x08اكبر\x08محمد\x08صلعم\x08رسول\x08عليه" + + "\x08وسلم\x06صلى!صلى الله عليه وسلم\x0fجل جلاله\x08ریال\x01,\x01:\x01!" + + "\x01?\x01_\x01{\x01}\x01[\x01]\x01#\x01&\x01*\x01-\x01<\x01>\x01\\\x01$" + + "\x01%\x01@\x04ـً\x04ـَ\x04ـُ\x04ـِ\x04ـّ\x04ـْ\x02ء\x02آ\x02أ\x02ؤ\x02إ" + + "\x02ئ\x02ا\x02ب\x02ة\x02ت\x02ث\x02ج\x02ح\x02خ\x02د\x02ذ\x02ر\x02ز\x02س" + + "\x02ش\x02ص\x02ض\x02ط\x02ظ\x02ع\x02غ\x02ف\x02ق\x02ك\x02ل\x02م\x02ن\x02ه" + + "\x02و\x02ي\x04لآ\x04لأ\x04لإ\x04لا\x01\x22\x01'\x01/\x01^\x01|\x01~\x02¢" + + "\x02£\x02¬\x02¦\x02¥\x08𝅗𝅥\x08𝅘𝅥\x0c𝅘𝅥𝅮\x0c𝅘𝅥𝅯\x0c𝅘𝅥𝅰\x0c𝅘𝅥𝅱\x0c𝅘𝅥𝅲\x08𝆹" + + "𝅥\x08𝆺𝅥\x0c𝆹𝅥𝅮\x0c𝆺𝅥𝅮\x0c𝆹𝅥𝅯\x0c𝆺𝅥𝅯\x02ı\x02ȷ\x02α\x02ε\x02ζ\x02η\x02" + + "κ\x02λ\x02μ\x02ν\x02ξ\x02ο\x02σ\x02τ\x02υ\x02ψ\x03∇\x03∂\x02ϝ\x02ٮ\x02ڡ" + + "\x02ٯ\x020,\x021,\x022,\x023,\x024,\x025,\x026,\x027,\x028,\x029,\x03(a)" + + "\x03(b)\x03(c)\x03(d)\x03(e)\x03(f)\x03(g)\x03(h)\x03(i)\x03(j)\x03(k)" + + "\x03(l)\x03(m)\x03(n)\x03(o)\x03(p)\x03(q)\x03(r)\x03(s)\x03(t)\x03(u)" + + "\x03(v)\x03(w)\x03(x)\x03(y)\x03(z)\x07〔s〕\x02wz\x02hv\x02sd\x03ppv\x02w" + + "c\x02mc\x02md\x02dj\x06ほか\x06ココ\x03サ\x03手\x03字\x03双\x03デ\x03二\x03多\x03解" + + "\x03天\x03交\x03映\x03無\x03料\x03前\x03後\x03再\x03新\x03初\x03終\x03生\x03販\x03声" + + "\x03吹\x03演\x03投\x03捕\x03一\x03三\x03遊\x03左\x03中\x03右\x03指\x03走\x03打\x03禁" + + "\x03空\x03合\x03満\x03有\x03月\x03申\x03割\x03営\x03配\x09〔本〕\x09〔三〕\x09〔二〕\x09〔安" + + "〕\x09〔点〕\x09〔打〕\x09〔盗〕\x09〔勝〕\x09〔敗〕\x03得\x03可\x03丽\x03丸\x03乁\x03你\x03" + + "侮\x03侻\x03倂\x03偺\x03備\x03僧\x03像\x03㒞\x03免\x03兔\x03兤\x03具\x03㒹\x03內\x03" + + "冗\x03冤\x03仌\x03冬\x03况\x03凵\x03刃\x03㓟\x03刻\x03剆\x03剷\x03㔕\x03勇\x03勉\x03" + + "勤\x03勺\x03包\x03匆\x03北\x03卉\x03卑\x03博\x03即\x03卽\x03卿\x03灰\x03及\x03叟\x03" + + "叫\x03叱\x03吆\x03咞\x03吸\x03呈\x03周\x03咢\x03哶\x03唐\x03啓\x03啣\x03善\x03喙\x03" + + "喫\x03喳\x03嗂\x03圖\x03嘆\x03圗\x03噑\x03噴\x03切\x03壮\x03城\x03埴\x03堍\x03型\x03" + + "堲\x03報\x03墬\x03売\x03壷\x03夆\x03夢\x03奢\x03姬\x03娛\x03娧\x03姘\x03婦\x03㛮\x03" + + "嬈\x03嬾\x03寃\x03寘\x03寧\x03寳\x03寿\x03将\x03尢\x03㞁\x03屠\x03屮\x03峀\x03岍\x03" + + "嵃\x03嵮\x03嵫\x03嵼\x03巡\x03巢\x03㠯\x03巽\x03帨\x03帽\x03幩\x03㡢\x03㡼\x03庰\x03" + + "庳\x03庶\x03廊\x03廾\x03舁\x03弢\x03㣇\x03形\x03彫\x03㣣\x03徚\x03忍\x03志\x03忹\x03" + + "悁\x03㤺\x03㤜\x03悔\x03惇\x03慈\x03慌\x03慎\x03慺\x03憎\x03憲\x03憤\x03憯\x03懞\x03" + + "懲\x03懶\x03成\x03戛\x03扝\x03抱\x03拔\x03捐\x03挽\x03拼\x03捨\x03掃\x03揤\x03搢\x03" + + "揅\x03掩\x03㨮\x03摩\x03摾\x03撝\x03摷\x03㩬\x03敏\x03敬\x03旣\x03書\x03晉\x03㬙\x03" + + "暑\x03㬈\x03㫤\x03冒\x03冕\x03最\x03暜\x03肭\x03䏙\x03朗\x03望\x03朡\x03杞\x03杓\x03" + + "㭉\x03柺\x03枅\x03桒\x03梅\x03梎\x03栟\x03椔\x03㮝\x03楂\x03榣\x03槪\x03檨\x03櫛\x03" + + "㰘\x03次\x03歔\x03㱎\x03歲\x03殟\x03殺\x03殻\x03汎\x03沿\x03泍\x03汧\x03洖\x03派\x03" + + "海\x03流\x03浩\x03浸\x03涅\x03洴\x03港\x03湮\x03㴳\x03滋\x03滇\x03淹\x03潮\x03濆\x03" + + "瀹\x03瀞\x03瀛\x03㶖\x03灊\x03災\x03灷\x03炭\x03煅\x03熜\x03爨\x03爵\x03牐\x03犀\x03" + + "犕\x03獺\x03王\x03㺬\x03玥\x03㺸\x03瑇\x03瑜\x03瑱\x03璅\x03瓊\x03㼛\x03甤\x03甾\x03" + + "異\x03瘐\x03㿼\x03䀈\x03直\x03眞\x03真\x03睊\x03䀹\x03瞋\x03䁆\x03䂖\x03硎\x03碌\x03" + + "磌\x03䃣\x03祖\x03福\x03秫\x03䄯\x03穀\x03穊\x03穏\x03䈂\x03篆\x03築\x03䈧\x03糒\x03" + + "䊠\x03糨\x03糣\x03紀\x03絣\x03䌁\x03緇\x03縂\x03繅\x03䌴\x03䍙\x03罺\x03羕\x03翺\x03" + + "者\x03聠\x03聰\x03䏕\x03育\x03脃\x03䐋\x03脾\x03媵\x03舄\x03辞\x03䑫\x03芑\x03芋\x03" + + "芝\x03劳\x03花\x03芳\x03芽\x03苦\x03若\x03茝\x03荣\x03莭\x03茣\x03莽\x03菧\x03著\x03" + + "荓\x03菊\x03菌\x03菜\x03䔫\x03蓱\x03蓳\x03蔖\x03蕤\x03䕝\x03䕡\x03䕫\x03虐\x03虜\x03" + + "虧\x03虩\x03蚩\x03蚈\x03蜎\x03蛢\x03蝹\x03蜨\x03蝫\x03螆\x03蟡\x03蠁\x03䗹\x03衠\x03" + + "衣\x03裗\x03裞\x03䘵\x03裺\x03㒻\x03䚾\x03䛇\x03誠\x03諭\x03變\x03豕\x03貫\x03賁\x03" + + "贛\x03起\x03跋\x03趼\x03跰\x03軔\x03輸\x03邔\x03郱\x03鄑\x03鄛\x03鈸\x03鋗\x03鋘\x03" + + "鉼\x03鏹\x03鐕\x03開\x03䦕\x03閷\x03䧦\x03雃\x03嶲\x03霣\x03䩮\x03䩶\x03韠\x03䪲\x03" + + "頋\x03頩\x03飢\x03䬳\x03餩\x03馧\x03駂\x03駾\x03䯎\x03鬒\x03鱀\x03鳽\x03䳎\x03䳭\x03" + + "鵧\x03䳸\x03麻\x03䵖\x03黹\x03黾\x03鼅\x03鼏\x03鼖\x03鼻" + +var xorData string = "" + // Size: 4855 bytes + "\x02\x0c\x09\x02\xb0\xec\x02\xad\xd8\x02\xad\xd9\x02\x06\x07\x02\x0f\x12" + + "\x02\x0f\x1f\x02\x0f\x1d\x02\x01\x13\x02\x0f\x16\x02\x0f\x0b\x02\x0f3" + + "\x02\x0f7\x02\x0f?\x02\x0f/\x02\x0f*\x02\x0c&\x02\x0c*\x02\x0c;\x02\x0c9" + + "\x02\x0c%\x02\xab\xed\x02\xab\xe2\x02\xab\xe3\x02\xa9\xe0\x02\xa9\xe1" + + "\x02\xa9\xe6\x02\xa3\xcb\x02\xa3\xc8\x02\xa3\xc9\x02\x01#\x02\x01\x08" + + "\x02\x0e>\x02\x0e'\x02\x0f\x03\x02\x03\x0d\x02\x03\x09\x02\x03\x17\x02" + + "\x03\x0e\x02\x02\x03\x02\x011\x02\x01\x00\x02\x01\x10\x02\x03<\x02\x07" + + "\x0d\x02\x02\x0c\x02\x0c0\x02\x01\x03\x02\x01\x01\x02\x01 \x02\x01\x22" + + "\x02\x01)\x02\x01\x0a\x02\x01\x0c\x02\x02\x06\x02\x02\x02\x02\x03\x10" + + "\x03\x037 \x03\x0b+\x03\x02\x01\x04\x02\x01\x02\x02\x019\x02\x03\x1c\x02" + + "\x02$\x03\x80p$\x02\x03:\x02\x03\x0a\x03\xc1r.\x03\xc1r,\x03\xc1r\x02" + + "\x02\x02:\x02\x02>\x02\x02,\x02\x02\x10\x02\x02\x00\x03\xc1s<\x03\xc1s*" + + "\x03\xc2L$\x03\xc2L;\x02\x09)\x02\x0a\x19\x03\x83\xab\xe3\x03\x83\xab" + + "\xf2\x03 4\xe0\x03\x81\xab\xea\x03\x81\xab\xf3\x03 4\xef\x03\x96\xe1\xcd" + + "\x03\x84\xe5\xc3\x02\x0d\x11\x03\x8b\xec\xcb\x03\x94\xec\xcf\x03\x9a\xec" + + "\xc2\x03\x8b\xec\xdb\x03\x94\xec\xdf\x03\x9a\xec\xd2\x03\x01\x0c!\x03" + + "\x01\x0c#\x03ʠ\x9d\x03ʣ\x9c\x03ʢ\x9f\x03ʥ\x9e\x03ʤ\x91\x03ʧ\x90\x03ʦ\x93" + + "\x03ʩ\x92\x03ʨ\x95\x03\xca\xf3\xb5\x03\xca\xf0\xb4\x03\xca\xf1\xb7\x03" + + "\xca\xf6\xb6\x03\xca\xf7\x89\x03\xca\xf4\x88\x03\xca\xf5\x8b\x03\xca\xfa" + + "\x8a\x03\xca\xfb\x8d\x03\xca\xf8\x8c\x03\xca\xf9\x8f\x03\xca\xfe\x8e\x03" + + "\xca\xff\x81\x03\xca\xfc\x80\x03\xca\xfd\x83\x03\xca\xe2\x82\x03\xca\xe3" + + "\x85\x03\xca\xe0\x84\x03\xca\xe1\x87\x03\xca\xe6\x86\x03\xca\xe7\x99\x03" + + "\xca\xe4\x98\x03\xca\xe5\x9b\x03\xca\xea\x9a\x03\xca\xeb\x9d\x03\xca\xe8" + + "\x9c\x03ؓ\x89\x03ߔ\x8b\x02\x010\x03\x03\x04\x1e\x03\x04\x15\x12\x03\x0b" + + "\x05,\x03\x06\x04\x00\x03\x06\x04)\x03\x06\x044\x03\x06\x04<\x03\x06\x05" + + "\x1d\x03\x06\x06\x00\x03\x06\x06\x0a\x03\x06\x06'\x03\x06\x062\x03\x0786" + + "\x03\x079/\x03\x079 \x03\x07:\x0e\x03\x07:\x1b\x03\x07:%\x03\x07;/\x03" + + "\x07;%\x03\x074\x11\x03\x076\x09\x03\x077*\x03\x070\x01\x03\x070\x0f\x03" + + "\x070.\x03\x071\x16\x03\x071\x04\x03\x0710\x03\x072\x18\x03\x072-\x03" + + "\x073\x14\x03\x073>\x03\x07'\x09\x03\x07 \x00\x03\x07\x1f\x0b\x03\x07" + + "\x18#\x03\x07\x18(\x03\x07\x186\x03\x07\x18\x03\x03\x07\x19\x16\x03\x07" + + "\x116\x03\x07\x12'\x03\x07\x13\x10\x03\x07\x0c&\x03\x07\x0c\x08\x03\x07" + + "\x0c\x13\x03\x07\x0d\x02\x03\x07\x0d\x1c\x03\x07\x0b5\x03\x07\x0b\x0a" + + "\x03\x07\x0b\x01\x03\x07\x0b\x0f\x03\x07\x05\x00\x03\x07\x05\x09\x03\x07" + + "\x05\x0b\x03\x07\x07\x01\x03\x07\x07\x08\x03\x07\x00<\x03\x07\x00+\x03" + + "\x07\x01)\x03\x07\x01\x1b\x03\x07\x01\x08\x03\x07\x03?\x03\x0445\x03\x04" + + "4\x08\x03\x0454\x03\x04)/\x03\x04)5\x03\x04+\x05\x03\x04+\x14\x03\x04+ " + + "\x03\x04+<\x03\x04*&\x03\x04*\x22\x03\x04&8\x03\x04!\x01\x03\x04!\x22" + + "\x03\x04\x11+\x03\x04\x10.\x03\x04\x104\x03\x04\x13=\x03\x04\x12\x04\x03" + + "\x04\x12\x0a\x03\x04\x0d\x1d\x03\x04\x0d\x07\x03\x04\x0d \x03\x05<>\x03" + + "\x055<\x03\x055!\x03\x055#\x03\x055&\x03\x054\x1d\x03\x054\x02\x03\x054" + + "\x07\x03\x0571\x03\x053\x1a\x03\x053\x16\x03\x05.<\x03\x05.\x07\x03\x05)" + + ":\x03\x05)<\x03\x05)\x0c\x03\x05)\x15\x03\x05+-\x03\x05+5\x03\x05$\x1e" + + "\x03\x05$\x14\x03\x05'\x04\x03\x05'\x14\x03\x05&\x02\x03\x05\x226\x03" + + "\x05\x22\x0c\x03\x05\x22\x1c\x03\x05\x19\x0a\x03\x05\x1b\x09\x03\x05\x1b" + + "\x0c\x03\x05\x14\x07\x03\x05\x16?\x03\x05\x16\x0c\x03\x05\x0c\x05\x03" + + "\x05\x0e\x0f\x03\x05\x01\x0e\x03\x05\x00(\x03\x05\x030\x03\x05\x03\x06" + + "\x03\x0a==\x03\x0a=1\x03\x0a=,\x03\x0a=\x0c\x03\x0a??\x03\x0a<\x08\x03" + + "\x0a9!\x03\x0a9)\x03\x0a97\x03\x0a99\x03\x0a6\x0a\x03\x0a6\x1c\x03\x0a6" + + "\x17\x03\x0a7'\x03\x0a78\x03\x0a73\x03\x0a'\x01\x03\x0a'&\x03\x0a\x1f" + + "\x0e\x03\x0a\x1f\x03\x03\x0a\x1f3\x03\x0a\x1b/\x03\x0a\x18\x19\x03\x0a" + + "\x19\x01\x03\x0a\x16\x14\x03\x0a\x0e\x22\x03\x0a\x0f\x10\x03\x0a\x0f\x02" + + "\x03\x0a\x0f \x03\x0a\x0c\x04\x03\x0a\x0b>\x03\x0a\x0b+\x03\x0a\x08/\x03" + + "\x0a\x046\x03\x0a\x05\x14\x03\x0a\x00\x04\x03\x0a\x00\x10\x03\x0a\x00" + + "\x14\x03\x0b<3\x03\x0b;*\x03\x0b9\x22\x03\x0b9)\x03\x0b97\x03\x0b+\x10" + + "\x03\x0b((\x03\x0b&5\x03\x0b$\x1c\x03\x0b$\x12\x03\x0b%\x04\x03\x0b#<" + + "\x03\x0b#0\x03\x0b#\x0d\x03\x0b#\x19\x03\x0b!:\x03\x0b!\x1f\x03\x0b!\x00" + + "\x03\x0b\x1e5\x03\x0b\x1c\x1d\x03\x0b\x1d-\x03\x0b\x1d(\x03\x0b\x18.\x03" + + "\x0b\x18 \x03\x0b\x18\x16\x03\x0b\x14\x13\x03\x0b\x15$\x03\x0b\x15\x22" + + "\x03\x0b\x12\x1b\x03\x0b\x12\x10\x03\x0b\x132\x03\x0b\x13=\x03\x0b\x12" + + "\x18\x03\x0b\x0c&\x03\x0b\x061\x03\x0b\x06:\x03\x0b\x05#\x03\x0b\x05<" + + "\x03\x0b\x04\x0b\x03\x0b\x04\x04\x03\x0b\x04\x1b\x03\x0b\x042\x03\x0b" + + "\x041\x03\x0b\x03\x03\x03\x0b\x03\x1d\x03\x0b\x03/\x03\x0b\x03+\x03\x0b" + + "\x02\x1b\x03\x0b\x02\x00\x03\x0b\x01\x1e\x03\x0b\x01\x08\x03\x0b\x015" + + "\x03\x06\x0d9\x03\x06\x0d=\x03\x06\x0d?\x03\x02\x001\x03\x02\x003\x03" + + "\x02\x02\x19\x03\x02\x006\x03\x02\x02\x1b\x03\x02\x004\x03\x02\x00<\x03" + + "\x02\x02\x0a\x03\x02\x02\x0e\x03\x02\x01\x1a\x03\x02\x01\x07\x03\x02\x01" + + "\x05\x03\x02\x01\x0b\x03\x02\x01%\x03\x02\x01\x0c\x03\x02\x01\x04\x03" + + "\x02\x01\x1c\x03\x02\x00.\x03\x02\x002\x03\x02\x00>\x03\x02\x00\x12\x03" + + "\x02\x00\x16\x03\x02\x011\x03\x02\x013\x03\x02\x02 \x03\x02\x02%\x03\x02" + + "\x02$\x03\x02\x028\x03\x02\x02;\x03\x02\x024\x03\x02\x012\x03\x02\x022" + + "\x03\x02\x02/\x03\x02\x01,\x03\x02\x01\x13\x03\x02\x01\x16\x03\x02\x01" + + "\x11\x03\x02\x01\x1e\x03\x02\x01\x15\x03\x02\x01\x17\x03\x02\x01\x0f\x03" + + "\x02\x01\x08\x03\x02\x00?\x03\x02\x03\x07\x03\x02\x03\x0d\x03\x02\x03" + + "\x13\x03\x02\x03\x1d\x03\x02\x03\x1f\x03\x02\x00\x03\x03\x02\x00\x0d\x03" + + "\x02\x00\x01\x03\x02\x00\x1b\x03\x02\x00\x19\x03\x02\x00\x18\x03\x02\x00" + + "\x13\x03\x02\x00/\x03\x07>\x12\x03\x07<\x1f\x03\x07>\x1d\x03\x06\x1d\x0e" + + "\x03\x07>\x1c\x03\x07>:\x03\x07>\x13\x03\x04\x12+\x03\x07?\x03\x03\x07>" + + "\x02\x03\x06\x224\x03\x06\x1a.\x03\x07<%\x03\x06\x1c\x0b\x03\x0609\x03" + + "\x05\x1f\x01\x03\x04'\x08\x03\x93\xfd\xf5\x03\x02\x0d \x03\x02\x0d#\x03" + + "\x02\x0d!\x03\x02\x0d&\x03\x02\x0d\x22\x03\x02\x0d/\x03\x02\x0d,\x03\x02" + + "\x0d$\x03\x02\x0d'\x03\x02\x0d%\x03\x02\x0d;\x03\x02\x0d=\x03\x02\x0d?" + + "\x03\x099.\x03\x08\x0b7\x03\x08\x02\x14\x03\x08\x14\x0d\x03\x08.:\x03" + + "\x089'\x03\x0f\x0b\x18\x03\x0f\x1c1\x03\x0f\x17&\x03\x0f9\x1f\x03\x0f0" + + "\x0c\x03\x0e\x0a9\x03\x0e\x056\x03\x0e\x1c#\x03\x0f\x13\x0e\x03\x072\x00" + + "\x03\x070\x0d\x03\x072\x0b\x03\x06\x11\x18\x03\x070\x10\x03\x06\x0f(\x03" + + "\x072\x05\x03\x06\x0f,\x03\x073\x15\x03\x06\x07\x08\x03\x05\x16\x02\x03" + + "\x04\x0b \x03\x05:8\x03\x05\x16%\x03\x0a\x0d\x1f\x03\x06\x16\x10\x03\x05" + + "\x1d5\x03\x05*;\x03\x05\x16\x1b\x03\x04.-\x03\x06\x1a\x19\x03\x04\x03," + + "\x03\x0b87\x03\x04/\x0a\x03\x06\x00,\x03\x04-\x01\x03\x04\x1e-\x03\x06/(" + + "\x03\x0a\x0b5\x03\x06\x0e7\x03\x06\x07.\x03\x0597\x03\x0a*%\x03\x0760" + + "\x03\x06\x0c;\x03\x05'\x00\x03\x072.\x03\x072\x08\x03\x06=\x01\x03\x06" + + "\x05\x1b\x03\x06\x06\x12\x03\x06$=\x03\x06'\x0d\x03\x04\x11\x0f\x03\x076" + + ",\x03\x06\x07;\x03\x06.,\x03\x86\xf9\xea\x03\x8f\xff\xeb\x02\x092\x02" + + "\x095\x02\x094\x02\x09;\x02\x09>\x02\x098\x02\x09*\x02\x09/\x02\x09,\x02" + + "\x09%\x02\x09&\x02\x09#\x02\x09 \x02\x08!\x02\x08%\x02\x08$\x02\x08+\x02" + + "\x08.\x02\x08*\x02\x08&\x02\x088\x02\x08>\x02\x084\x02\x086\x02\x080\x02" + + "\x08\x10\x02\x08\x17\x02\x08\x12\x02\x08\x1d\x02\x08\x1f\x02\x08\x13\x02" + + "\x08\x15\x02\x08\x14\x02\x08\x0c\x03\x8b\xfd\xd0\x03\x81\xec\xc6\x03\x87" + + "\xe0\x8a\x03-2\xe3\x03\x80\xef\xe4\x03-2\xea\x03\x88\xe6\xeb\x03\x8e\xe6" + + "\xe8\x03\x84\xe6\xe9\x03\x97\xe6\xee\x03-2\xf9\x03-2\xf6\x03\x8e\xe3\xad" + + "\x03\x80\xe3\x92\x03\x88\xe3\x90\x03\x8e\xe3\x90\x03\x80\xe3\x97\x03\x88" + + "\xe3\x95\x03\x88\xfe\xcb\x03\x8e\xfe\xca\x03\x84\xfe\xcd\x03\x91\xef\xc9" + + "\x03-2\xc1\x03-2\xc0\x03-2\xcb\x03\x88@\x09\x03\x8e@\x08\x03\x8f\xe0\xf5" + + "\x03\x8e\xe6\xf9\x03\x8e\xe0\xfa\x03\x93\xff\xf4\x03\x84\xee\xd3\x03\x0b" + + "(\x04\x023 \x021;\x02\x01*\x03\x0b#\x10\x03\x0b 0\x03\x0b!\x10\x03\x0b!0" + + "\x03\x07\x15\x08\x03\x09?5\x03\x07\x1f\x08\x03\x07\x17\x0b\x03\x09\x1f" + + "\x15\x03\x0b\x1c7\x03\x0a+#\x03\x06\x1a\x1b\x03\x06\x1a\x14\x03\x0a\x01" + + "\x18\x03\x06#\x1b\x03\x0a2\x0c\x03\x0a\x01\x04\x03\x09#;\x03\x08='\x03" + + "\x08\x1a\x0a\x03\x07\x03\x0a\x111\x03\x09\x1b\x09\x03\x073.\x03\x07\x01\x00" + + "\x03\x09/,\x03\x07#>\x03\x07\x048\x03\x0a\x1f\x22\x03\x098>\x03\x09\x11" + + "\x00\x03\x08/\x17\x03\x06'\x22\x03\x0b\x1a+\x03\x0a\x22\x19\x03\x0a/1" + + "\x03\x0974\x03\x09\x0f\x22\x03\x08,\x22\x03\x08?\x14\x03\x07$5\x03\x07<3" + + "\x03\x07=*\x03\x07\x13\x18\x03\x068\x0a\x03\x06\x09\x16\x03\x06\x13\x00" + + "\x03\x08\x067\x03\x08\x01\x03\x03\x08\x12\x1d\x03\x07+7\x03\x06(;\x03" + + "\x06\x1c?\x03\x07\x0e\x17\x03\x0a\x06\x1d\x03\x0a\x19\x07\x03\x08\x14$" + + "\x03\x07$;\x03\x08,$\x03\x08\x06\x0d\x03\x07\x16\x0a\x03\x06>>\x03\x0a" + + "\x06\x12\x03\x0a\x14)\x03\x09\x0d\x1f\x03\x09\x12\x17\x03\x09\x19\x01" + + "\x03\x08\x11 \x03\x08\x1d'\x03\x06<\x1a\x03\x0a.\x00\x03\x07'\x18\x03" + + "\x0a\x22\x08\x03\x08\x0d\x0a\x03\x08\x13)\x03\x07*)\x03\x06<,\x03\x07" + + "\x0b\x1a\x03\x09.\x14\x03\x09\x0d\x1e\x03\x07\x0e#\x03\x0b\x1d'\x03\x0a" + + "\x0a8\x03\x09%2\x03\x08+&\x03\x080\x12\x03\x0a)4\x03\x08\x06\x1f\x03\x0b" + + "\x1b\x1a\x03\x0a\x1b\x0f\x03\x0b\x1d*\x03\x09\x16$\x03\x090\x11\x03\x08" + + "\x11\x08\x03\x0a*(\x03\x0a\x042\x03\x089,\x03\x074'\x03\x07\x0f\x05\x03" + + "\x09\x0b\x0a\x03\x07\x1b\x01\x03\x09\x17:\x03\x09.\x0d\x03\x07.\x11\x03" + + "\x09+\x15\x03\x080\x13\x03\x0b\x1f\x19\x03\x0a \x11\x03\x0a\x220\x03\x09" + + "\x07;\x03\x08\x16\x1c\x03\x07,\x13\x03\x07\x0e/\x03\x06\x221\x03\x0a." + + "\x0a\x03\x0a7\x02\x03\x0a\x032\x03\x0a\x1d.\x03\x091\x06\x03\x09\x19:" + + "\x03\x08\x02/\x03\x060+\x03\x06\x0f-\x03\x06\x1c\x1f\x03\x06\x1d\x07\x03" + + "\x0a,\x11\x03\x09=\x0d\x03\x09\x0b;\x03\x07\x1b/\x03\x0a\x1f:\x03\x09 " + + "\x1f\x03\x09.\x10\x03\x094\x0b\x03\x09\x1a1\x03\x08#\x1a\x03\x084\x1d" + + "\x03\x08\x01\x1f\x03\x08\x11\x22\x03\x07'8\x03\x07\x1a>\x03\x0757\x03" + + "\x06&9\x03\x06+\x11\x03\x0a.\x0b\x03\x0a,>\x03\x0a4#\x03\x08%\x17\x03" + + "\x07\x05\x22\x03\x07\x0c\x0b\x03\x0a\x1d+\x03\x0a\x19\x16\x03\x09+\x1f" + + "\x03\x09\x08\x0b\x03\x08\x16\x18\x03\x08+\x12\x03\x0b\x1d\x0c\x03\x0a=" + + "\x10\x03\x0a\x09\x0d\x03\x0a\x10\x11\x03\x09&0\x03\x08(\x1f\x03\x087\x07" + + "\x03\x08\x185\x03\x07'6\x03\x06.\x05\x03\x06=\x04\x03\x06;;\x03\x06\x06," + + "\x03\x0b\x18>\x03\x08\x00\x18\x03\x06 \x03\x03\x06<\x00\x03\x09%\x18\x03" + + "\x0b\x1c<\x03\x0a%!\x03\x0a\x09\x12\x03\x0a\x16\x02\x03\x090'\x03\x09" + + "\x0e=\x03\x08 \x0e\x03\x08>\x03\x03\x074>\x03\x06&?\x03\x06\x19\x09\x03" + + "\x06?(\x03\x0a-\x0e\x03\x09:3\x03\x098:\x03\x09\x12\x0b\x03\x09\x1d\x17" + + "\x03\x087\x05\x03\x082\x14\x03\x08\x06%\x03\x08\x13\x1f\x03\x06\x06\x0e" + + "\x03\x0a\x22<\x03\x09/<\x03\x06>+\x03\x0a'?\x03\x0a\x13\x0c\x03\x09\x10<" + + "\x03\x07\x1b=\x03\x0a\x19\x13\x03\x09\x22\x1d\x03\x09\x07\x0d\x03\x08)" + + "\x1c\x03\x06=\x1a\x03\x0a/4\x03\x0a7\x11\x03\x0a\x16:\x03\x09?3\x03\x09:" + + "/\x03\x09\x05\x0a\x03\x09\x14\x06\x03\x087\x22\x03\x080\x07\x03\x08\x1a" + + "\x1f\x03\x07\x04(\x03\x07\x04\x09\x03\x06 %\x03\x06<\x08\x03\x0a+\x14" + + "\x03\x09\x1d\x16\x03\x0a70\x03\x08 >\x03\x0857\x03\x070\x0a\x03\x06=\x12" + + "\x03\x06\x16%\x03\x06\x1d,\x03\x099#\x03\x09\x10>\x03\x07 \x1e\x03\x08" + + "\x0c<\x03\x08\x0b\x18\x03\x08\x15+\x03\x08,:\x03\x08%\x22\x03\x07\x0a$" + + "\x03\x0b\x1c=\x03\x07+\x08\x03\x0a/\x05\x03\x0a \x07\x03\x0a\x12'\x03" + + "\x09#\x11\x03\x08\x1b\x15\x03\x0a\x06\x01\x03\x09\x1c\x1b\x03\x0922\x03" + + "\x07\x14<\x03\x07\x09\x04\x03\x061\x04\x03\x07\x0e\x01\x03\x0a\x13\x18" + + "\x03\x0a-\x0c\x03\x0a?\x0d\x03\x0a\x09\x0a\x03\x091&\x03\x0a/\x0b\x03" + + "\x08$<\x03\x083\x1d\x03\x08\x0c$\x03\x08\x0d\x07\x03\x08\x0d?\x03\x08" + + "\x0e\x14\x03\x065\x0a\x03\x08\x1a#\x03\x08\x16#\x03\x0702\x03\x07\x03" + + "\x1a\x03\x06(\x1d\x03\x06+\x1b\x03\x06\x0b\x05\x03\x06\x0b\x17\x03\x06" + + "\x0c\x04\x03\x06\x1e\x19\x03\x06+0\x03\x062\x18\x03\x0b\x16\x1e\x03\x0a+" + + "\x16\x03\x0a-?\x03\x0a#:\x03\x0a#\x10\x03\x0a%$\x03\x0a>+\x03\x0a01\x03" + + "\x0a1\x10\x03\x0a\x099\x03\x0a\x0a\x12\x03\x0a\x19\x1f\x03\x0a\x19\x12" + + "\x03\x09*)\x03\x09-\x16\x03\x09.1\x03\x09.2\x03\x09<\x0e\x03\x09> \x03" + + "\x093\x12\x03\x09\x0b\x01\x03\x09\x1c2\x03\x09\x11\x1c\x03\x09\x15%\x03" + + "\x08,&\x03\x08!\x22\x03\x089(\x03\x08\x0b\x1a\x03\x08\x0d2\x03\x08\x0c" + + "\x04\x03\x08\x0c\x06\x03\x08\x0c\x1f\x03\x08\x0c\x0c\x03\x08\x0f\x1f\x03" + + "\x08\x0f\x1d\x03\x08\x00\x14\x03\x08\x03\x14\x03\x08\x06\x16\x03\x08\x1e" + + "#\x03\x08\x11\x11\x03\x08\x10\x18\x03\x08\x14(\x03\x07)\x1e\x03\x07.1" + + "\x03\x07 $\x03\x07 '\x03\x078\x08\x03\x07\x0d0\x03\x07\x0f7\x03\x07\x05#" + + "\x03\x07\x05\x1a\x03\x07\x1a7\x03\x07\x1d-\x03\x07\x17\x10\x03\x06)\x1f" + + "\x03\x062\x0b\x03\x066\x16\x03\x06\x09\x11\x03\x09(\x1e\x03\x07!5\x03" + + "\x0b\x11\x16\x03\x0a/\x04\x03\x0a,\x1a\x03\x0b\x173\x03\x0a,1\x03\x0a/5" + + "\x03\x0a\x221\x03\x0a\x22\x0d\x03\x0a?%\x03\x0a<,\x03\x0a?#\x03\x0a>\x19" + + "\x03\x0a\x08&\x03\x0a\x0b\x0e\x03\x0a\x0c:\x03\x0a\x0c+\x03\x0a\x03\x22" + + "\x03\x0a\x06)\x03\x0a\x11\x10\x03\x0a\x11\x1a\x03\x0a\x17-\x03\x0a\x14(" + + "\x03\x09)\x1e\x03\x09/\x09\x03\x09.\x00\x03\x09,\x07\x03\x09/*\x03\x09-9" + + "\x03\x09\x228\x03\x09%\x09\x03\x09:\x12\x03\x09;\x1d\x03\x09?\x06\x03" + + "\x093%\x03\x096\x05\x03\x096\x08\x03\x097\x02\x03\x09\x07,\x03\x09\x04," + + "\x03\x09\x1f\x16\x03\x09\x11\x03\x03\x09\x11\x12\x03\x09\x168\x03\x08*" + + "\x05\x03\x08/2\x03\x084:\x03\x08\x22+\x03\x08 0\x03\x08&\x0a\x03\x08;" + + "\x10\x03\x08>$\x03\x08>\x18\x03\x0829\x03\x082:\x03\x081,\x03\x081<\x03" + + "\x081\x1c\x03\x087#\x03\x087*\x03\x08\x09'\x03\x08\x00\x1d\x03\x08\x05-" + + "\x03\x08\x1f4\x03\x08\x1d\x04\x03\x08\x16\x0f\x03\x07*7\x03\x07'!\x03" + + "\x07%\x1b\x03\x077\x0c\x03\x07\x0c1\x03\x07\x0c.\x03\x07\x00\x06\x03\x07" + + "\x01\x02\x03\x07\x010\x03\x07\x06=\x03\x07\x01\x03\x03\x07\x01\x13\x03" + + "\x07\x06\x06\x03\x07\x05\x0a\x03\x07\x1f\x09\x03\x07\x17:\x03\x06*1\x03" + + "\x06-\x1d\x03\x06\x223\x03\x062:\x03\x060$\x03\x066\x1e\x03\x064\x12\x03" + + "\x0645\x03\x06\x0b\x00\x03\x06\x0b7\x03\x06\x07\x1f\x03\x06\x15\x12\x03" + + "\x0c\x05\x0f\x03\x0b+\x0b\x03\x0b+-\x03\x06\x16\x1b\x03\x06\x15\x17\x03" + + "\x89\xca\xea\x03\x89\xca\xe8\x03\x0c8\x10\x03\x0c8\x01\x03\x0c8\x0f\x03" + + "\x0d8%\x03\x0d8!\x03\x0c8-\x03\x0c8/\x03\x0c8+\x03\x0c87\x03\x0c85\x03" + + "\x0c9\x09\x03\x0c9\x0d\x03\x0c9\x0f\x03\x0c9\x0b\x03\xcfu\x0c\x03\xcfu" + + "\x0f\x03\xcfu\x0e\x03\xcfu\x09\x03\x0c9\x10\x03\x0d9\x0c\x03\xcf`;\x03" + + "\xcf`>\x03\xcf`9\x03\xcf`8\x03\xcf`7\x03\xcf`*\x03\xcf`-\x03\xcf`,\x03" + + "\x0d\x1b\x1a\x03\x0d\x1b&\x03\x0c=.\x03\x0c=%\x03\x0c>\x1e\x03\x0c>\x14" + + "\x03\x0c?\x06\x03\x0c?\x0b\x03\x0c?\x0c\x03\x0c?\x0d\x03\x0c?\x02\x03" + + "\x0c>\x0f\x03\x0c>\x08\x03\x0c>\x09\x03\x0c>,\x03\x0c>\x0c\x03\x0c?\x13" + + "\x03\x0c?\x16\x03\x0c?\x15\x03\x0c?\x1c\x03\x0c?\x1f\x03\x0c?\x1d\x03" + + "\x0c?\x1a\x03\x0c?\x17\x03\x0c?\x08\x03\x0c?\x09\x03\x0c?\x0e\x03\x0c?" + + "\x04\x03\x0c?\x05\x03\x0c" + + "\x03\x0c=2\x03\x0c=6\x03\x0c<\x07\x03\x0c<\x05\x03\x0e:!\x03\x0e:#\x03" + + "\x0e8\x09\x03\x0e:&\x03\x0e8\x0b\x03\x0e:$\x03\x0e:,\x03\x0e8\x1a\x03" + + "\x0e8\x1e\x03\x0e:*\x03\x0e:7\x03\x0e:5\x03\x0e:;\x03\x0e:\x15\x03\x0e:<" + + "\x03\x0e:4\x03\x0e:'\x03\x0e:-\x03\x0e:%\x03\x0e:?\x03\x0e:=\x03\x0e:)" + + "\x03\x0e:/\x03\xcfs'\x03\x0d=\x0f\x03\x0d+*\x03\x0d99\x03\x0d9;\x03\x0d9" + + "?\x03\x0d)\x0d\x03\x0d(%\x02\x01\x18\x02\x01(\x02\x01\x1e\x03\x0f$!\x03" + + "\x0f87\x03\x0f4\x0e\x03\x0f5\x1d\x03\x06'\x03\x03\x0f\x08\x18\x03\x0f" + + "\x0d\x1b\x03\x0e2=\x03\x0e;\x08\x03\x0e:\x0b\x03\x0e\x06$\x03\x0e\x0d)" + + "\x03\x0e\x16\x1f\x03\x0e\x16\x1b\x03\x0d$\x0a\x03\x05,\x1d\x03\x0d. \x03" + + "\x0d.#\x03\x0c(/\x03\x09%\x02\x03\x0d90\x03\x0d\x0e4\x03\x0d\x0d\x0f\x03" + + "\x0c#\x00\x03\x0c,\x1e\x03\x0c2\x0e\x03\x0c\x01\x17\x03\x0c\x09:\x03\x0e" + + "\x173\x03\x0c\x08\x03\x03\x0c\x11\x07\x03\x0c\x10\x18\x03\x0c\x1f\x1c" + + "\x03\x0c\x19\x0e\x03\x0c\x1a\x1f\x03\x0f0>\x03\x0b->\x03\x0b<+\x03\x0b8" + + "\x13\x03\x0b\x043\x03\x0b\x14\x03\x03\x0b\x16%\x03\x0d\x22&\x03\x0b\x1a" + + "\x1a\x03\x0b\x1a\x04\x03\x0a%9\x03\x0a&2\x03\x0a&0\x03\x0a!\x1a\x03\x0a!" + + "7\x03\x0a5\x10\x03\x0a=4\x03\x0a?\x0e\x03\x0a>\x10\x03\x0a\x00 \x03\x0a" + + "\x0f:\x03\x0a\x0f9\x03\x0a\x0b\x0a\x03\x0a\x17%\x03\x0a\x1b-\x03\x09-" + + "\x1a\x03\x09,4\x03\x09.,\x03\x09)\x09\x03\x096!\x03\x091\x1f\x03\x093" + + "\x16\x03\x0c+\x1f\x03\x098 \x03\x098=\x03\x0c(\x1a\x03\x0c(\x16\x03\x09" + + "\x0a+\x03\x09\x16\x12\x03\x09\x13\x0e\x03\x09\x153\x03\x08)!\x03\x09\x1a" + + "\x01\x03\x09\x18\x01\x03\x08%#\x03\x08>\x22\x03\x08\x05%\x03\x08\x02*" + + "\x03\x08\x15;\x03\x08\x1b7\x03\x0f\x07\x1d\x03\x0f\x04\x03\x03\x070\x0c" + + "\x03\x07;\x0b\x03\x07\x08\x17\x03\x07\x12\x06\x03\x06/-\x03\x0671\x03" + + "\x065+\x03\x06>7\x03\x06\x049\x03\x05+\x1e\x03\x05,\x17\x03\x05 \x1d\x03" + + "\x05\x22\x05\x03\x050\x1d" + +// lookup returns the trie value for the first UTF-8 encoding in s and +// the width in bytes of this encoding. The size will be 0 if s does not +// hold enough bytes to complete the encoding. len(s) must be greater than 0. +func (t *idnaTrie) lookup(s []byte) (v uint16, sz int) { + c0 := s[0] + switch { + case c0 < 0x80: // is ASCII + return idnaValues[c0], 1 + case c0 < 0xC2: + return 0, 1 // Illegal UTF-8: not a starter, not ASCII. + case c0 < 0xE0: // 2-byte UTF-8 + if len(s) < 2 { + return 0, 0 + } + i := idnaIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c1), 2 + case c0 < 0xF0: // 3-byte UTF-8 + if len(s) < 3 { + return 0, 0 + } + i := idnaIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = idnaIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c2), 3 + case c0 < 0xF8: // 4-byte UTF-8 + if len(s) < 4 { + return 0, 0 + } + i := idnaIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = idnaIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + o = uint32(i)<<6 + uint32(c2) + i = idnaIndex[o] + c3 := s[3] + if c3 < 0x80 || 0xC0 <= c3 { + return 0, 3 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c3), 4 + } + // Illegal rune + return 0, 1 +} + +// lookupUnsafe returns the trie value for the first UTF-8 encoding in s. +// s must start with a full and valid UTF-8 encoded rune. +func (t *idnaTrie) lookupUnsafe(s []byte) uint16 { + c0 := s[0] + if c0 < 0x80 { // is ASCII + return idnaValues[c0] + } + i := idnaIndex[c0] + if c0 < 0xE0 { // 2-byte UTF-8 + return t.lookupValue(uint32(i), s[1]) + } + i = idnaIndex[uint32(i)<<6+uint32(s[1])] + if c0 < 0xF0 { // 3-byte UTF-8 + return t.lookupValue(uint32(i), s[2]) + } + i = idnaIndex[uint32(i)<<6+uint32(s[2])] + if c0 < 0xF8 { // 4-byte UTF-8 + return t.lookupValue(uint32(i), s[3]) + } + return 0 +} + +// lookupString returns the trie value for the first UTF-8 encoding in s and +// the width in bytes of this encoding. The size will be 0 if s does not +// hold enough bytes to complete the encoding. len(s) must be greater than 0. +func (t *idnaTrie) lookupString(s string) (v uint16, sz int) { + c0 := s[0] + switch { + case c0 < 0x80: // is ASCII + return idnaValues[c0], 1 + case c0 < 0xC2: + return 0, 1 // Illegal UTF-8: not a starter, not ASCII. + case c0 < 0xE0: // 2-byte UTF-8 + if len(s) < 2 { + return 0, 0 + } + i := idnaIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c1), 2 + case c0 < 0xF0: // 3-byte UTF-8 + if len(s) < 3 { + return 0, 0 + } + i := idnaIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = idnaIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c2), 3 + case c0 < 0xF8: // 4-byte UTF-8 + if len(s) < 4 { + return 0, 0 + } + i := idnaIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = idnaIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + o = uint32(i)<<6 + uint32(c2) + i = idnaIndex[o] + c3 := s[3] + if c3 < 0x80 || 0xC0 <= c3 { + return 0, 3 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c3), 4 + } + // Illegal rune + return 0, 1 +} + +// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s. +// s must start with a full and valid UTF-8 encoded rune. +func (t *idnaTrie) lookupStringUnsafe(s string) uint16 { + c0 := s[0] + if c0 < 0x80 { // is ASCII + return idnaValues[c0] + } + i := idnaIndex[c0] + if c0 < 0xE0 { // 2-byte UTF-8 + return t.lookupValue(uint32(i), s[1]) + } + i = idnaIndex[uint32(i)<<6+uint32(s[1])] + if c0 < 0xF0 { // 3-byte UTF-8 + return t.lookupValue(uint32(i), s[2]) + } + i = idnaIndex[uint32(i)<<6+uint32(s[2])] + if c0 < 0xF8 { // 4-byte UTF-8 + return t.lookupValue(uint32(i), s[3]) + } + return 0 +} + +// idnaTrie. Total size: 29052 bytes (28.37 KiB). Checksum: ef06e7ecc26f36dd. +type idnaTrie struct{} + +func newIdnaTrie(i int) *idnaTrie { + return &idnaTrie{} +} + +// lookupValue determines the type of block n and looks up the value for b. +func (t *idnaTrie) lookupValue(n uint32, b byte) uint16 { + switch { + case n < 125: + return uint16(idnaValues[n<<6+uint32(b)]) + default: + n -= 125 + return uint16(idnaSparse.lookup(n, b)) + } +} + +// idnaValues: 127 blocks, 8128 entries, 16256 bytes +// The third block is the zero block. +var idnaValues = [8128]uint16{ + // Block 0x0, offset 0x0 + 0x00: 0x0080, 0x01: 0x0080, 0x02: 0x0080, 0x03: 0x0080, 0x04: 0x0080, 0x05: 0x0080, + 0x06: 0x0080, 0x07: 0x0080, 0x08: 0x0080, 0x09: 0x0080, 0x0a: 0x0080, 0x0b: 0x0080, + 0x0c: 0x0080, 0x0d: 0x0080, 0x0e: 0x0080, 0x0f: 0x0080, 0x10: 0x0080, 0x11: 0x0080, + 0x12: 0x0080, 0x13: 0x0080, 0x14: 0x0080, 0x15: 0x0080, 0x16: 0x0080, 0x17: 0x0080, + 0x18: 0x0080, 0x19: 0x0080, 0x1a: 0x0080, 0x1b: 0x0080, 0x1c: 0x0080, 0x1d: 0x0080, + 0x1e: 0x0080, 0x1f: 0x0080, 0x20: 0x0080, 0x21: 0x0080, 0x22: 0x0080, 0x23: 0x0080, + 0x24: 0x0080, 0x25: 0x0080, 0x26: 0x0080, 0x27: 0x0080, 0x28: 0x0080, 0x29: 0x0080, + 0x2a: 0x0080, 0x2b: 0x0080, 0x2c: 0x0080, 0x2d: 0x0008, 0x2e: 0x0008, 0x2f: 0x0080, + 0x30: 0x0008, 0x31: 0x0008, 0x32: 0x0008, 0x33: 0x0008, 0x34: 0x0008, 0x35: 0x0008, + 0x36: 0x0008, 0x37: 0x0008, 0x38: 0x0008, 0x39: 0x0008, 0x3a: 0x0080, 0x3b: 0x0080, + 0x3c: 0x0080, 0x3d: 0x0080, 0x3e: 0x0080, 0x3f: 0x0080, + // Block 0x1, offset 0x40 + 0x40: 0x0080, 0x41: 0xe105, 0x42: 0xe105, 0x43: 0xe105, 0x44: 0xe105, 0x45: 0xe105, + 0x46: 0xe105, 0x47: 0xe105, 0x48: 0xe105, 0x49: 0xe105, 0x4a: 0xe105, 0x4b: 0xe105, + 0x4c: 0xe105, 0x4d: 0xe105, 0x4e: 0xe105, 0x4f: 0xe105, 0x50: 0xe105, 0x51: 0xe105, + 0x52: 0xe105, 0x53: 0xe105, 0x54: 0xe105, 0x55: 0xe105, 0x56: 0xe105, 0x57: 0xe105, + 0x58: 0xe105, 0x59: 0xe105, 0x5a: 0xe105, 0x5b: 0x0080, 0x5c: 0x0080, 0x5d: 0x0080, + 0x5e: 0x0080, 0x5f: 0x0080, 0x60: 0x0080, 0x61: 0x0008, 0x62: 0x0008, 0x63: 0x0008, + 0x64: 0x0008, 0x65: 0x0008, 0x66: 0x0008, 0x67: 0x0008, 0x68: 0x0008, 0x69: 0x0008, + 0x6a: 0x0008, 0x6b: 0x0008, 0x6c: 0x0008, 0x6d: 0x0008, 0x6e: 0x0008, 0x6f: 0x0008, + 0x70: 0x0008, 0x71: 0x0008, 0x72: 0x0008, 0x73: 0x0008, 0x74: 0x0008, 0x75: 0x0008, + 0x76: 0x0008, 0x77: 0x0008, 0x78: 0x0008, 0x79: 0x0008, 0x7a: 0x0008, 0x7b: 0x0080, + 0x7c: 0x0080, 0x7d: 0x0080, 0x7e: 0x0080, 0x7f: 0x0080, + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0xc0: 0x0040, 0xc1: 0x0040, 0xc2: 0x0040, 0xc3: 0x0040, 0xc4: 0x0040, 0xc5: 0x0040, + 0xc6: 0x0040, 0xc7: 0x0040, 0xc8: 0x0040, 0xc9: 0x0040, 0xca: 0x0040, 0xcb: 0x0040, + 0xcc: 0x0040, 0xcd: 0x0040, 0xce: 0x0040, 0xcf: 0x0040, 0xd0: 0x0040, 0xd1: 0x0040, + 0xd2: 0x0040, 0xd3: 0x0040, 0xd4: 0x0040, 0xd5: 0x0040, 0xd6: 0x0040, 0xd7: 0x0040, + 0xd8: 0x0040, 0xd9: 0x0040, 0xda: 0x0040, 0xdb: 0x0040, 0xdc: 0x0040, 0xdd: 0x0040, + 0xde: 0x0040, 0xdf: 0x0040, 0xe0: 0x000a, 0xe1: 0x0018, 0xe2: 0x0018, 0xe3: 0x0018, + 0xe4: 0x0018, 0xe5: 0x0018, 0xe6: 0x0018, 0xe7: 0x0018, 0xe8: 0x001a, 0xe9: 0x0018, + 0xea: 0x0039, 0xeb: 0x0018, 0xec: 0x0018, 0xed: 0x03c0, 0xee: 0x0018, 0xef: 0x004a, + 0xf0: 0x0018, 0xf1: 0x0018, 0xf2: 0x0069, 0xf3: 0x0079, 0xf4: 0x008a, 0xf5: 0x0005, + 0xf6: 0x0018, 0xf7: 0x0008, 0xf8: 0x00aa, 0xf9: 0x00c9, 0xfa: 0x00d9, 0xfb: 0x0018, + 0xfc: 0x00e9, 0xfd: 0x0119, 0xfe: 0x0149, 0xff: 0x0018, + // Block 0x4, offset 0x100 + 0x100: 0xe00d, 0x101: 0x0008, 0x102: 0xe00d, 0x103: 0x0008, 0x104: 0xe00d, 0x105: 0x0008, + 0x106: 0xe00d, 0x107: 0x0008, 0x108: 0xe00d, 0x109: 0x0008, 0x10a: 0xe00d, 0x10b: 0x0008, + 0x10c: 0xe00d, 0x10d: 0x0008, 0x10e: 0xe00d, 0x10f: 0x0008, 0x110: 0xe00d, 0x111: 0x0008, + 0x112: 0xe00d, 0x113: 0x0008, 0x114: 0xe00d, 0x115: 0x0008, 0x116: 0xe00d, 0x117: 0x0008, + 0x118: 0xe00d, 0x119: 0x0008, 0x11a: 0xe00d, 0x11b: 0x0008, 0x11c: 0xe00d, 0x11d: 0x0008, + 0x11e: 0xe00d, 0x11f: 0x0008, 0x120: 0xe00d, 0x121: 0x0008, 0x122: 0xe00d, 0x123: 0x0008, + 0x124: 0xe00d, 0x125: 0x0008, 0x126: 0xe00d, 0x127: 0x0008, 0x128: 0xe00d, 0x129: 0x0008, + 0x12a: 0xe00d, 0x12b: 0x0008, 0x12c: 0xe00d, 0x12d: 0x0008, 0x12e: 0xe00d, 0x12f: 0x0008, + 0x130: 0x0179, 0x131: 0x0008, 0x132: 0x0035, 0x133: 0x004d, 0x134: 0xe00d, 0x135: 0x0008, + 0x136: 0xe00d, 0x137: 0x0008, 0x138: 0x0008, 0x139: 0xe01d, 0x13a: 0x0008, 0x13b: 0xe03d, + 0x13c: 0x0008, 0x13d: 0xe01d, 0x13e: 0x0008, 0x13f: 0x0199, + // Block 0x5, offset 0x140 + 0x140: 0x0199, 0x141: 0xe01d, 0x142: 0x0008, 0x143: 0xe03d, 0x144: 0x0008, 0x145: 0xe01d, + 0x146: 0x0008, 0x147: 0xe07d, 0x148: 0x0008, 0x149: 0x01b9, 0x14a: 0xe00d, 0x14b: 0x0008, + 0x14c: 0xe00d, 0x14d: 0x0008, 0x14e: 0xe00d, 0x14f: 0x0008, 0x150: 0xe00d, 0x151: 0x0008, + 0x152: 0xe00d, 0x153: 0x0008, 0x154: 0xe00d, 0x155: 0x0008, 0x156: 0xe00d, 0x157: 0x0008, + 0x158: 0xe00d, 0x159: 0x0008, 0x15a: 0xe00d, 0x15b: 0x0008, 0x15c: 0xe00d, 0x15d: 0x0008, + 0x15e: 0xe00d, 0x15f: 0x0008, 0x160: 0xe00d, 0x161: 0x0008, 0x162: 0xe00d, 0x163: 0x0008, + 0x164: 0xe00d, 0x165: 0x0008, 0x166: 0xe00d, 0x167: 0x0008, 0x168: 0xe00d, 0x169: 0x0008, + 0x16a: 0xe00d, 0x16b: 0x0008, 0x16c: 0xe00d, 0x16d: 0x0008, 0x16e: 0xe00d, 0x16f: 0x0008, + 0x170: 0xe00d, 0x171: 0x0008, 0x172: 0xe00d, 0x173: 0x0008, 0x174: 0xe00d, 0x175: 0x0008, + 0x176: 0xe00d, 0x177: 0x0008, 0x178: 0x0065, 0x179: 0xe01d, 0x17a: 0x0008, 0x17b: 0xe03d, + 0x17c: 0x0008, 0x17d: 0xe01d, 0x17e: 0x0008, 0x17f: 0x01d9, + // Block 0x6, offset 0x180 + 0x180: 0x0008, 0x181: 0x007d, 0x182: 0xe00d, 0x183: 0x0008, 0x184: 0xe00d, 0x185: 0x0008, + 0x186: 0x007d, 0x187: 0xe07d, 0x188: 0x0008, 0x189: 0x0095, 0x18a: 0x00ad, 0x18b: 0xe03d, + 0x18c: 0x0008, 0x18d: 0x0008, 0x18e: 0x00c5, 0x18f: 0x00dd, 0x190: 0x00f5, 0x191: 0xe01d, + 0x192: 0x0008, 0x193: 0x010d, 0x194: 0x0125, 0x195: 0x0008, 0x196: 0x013d, 0x197: 0x013d, + 0x198: 0xe00d, 0x199: 0x0008, 0x19a: 0x0008, 0x19b: 0x0008, 0x19c: 0x010d, 0x19d: 0x0155, + 0x19e: 0x0008, 0x19f: 0x016d, 0x1a0: 0xe00d, 0x1a1: 0x0008, 0x1a2: 0xe00d, 0x1a3: 0x0008, + 0x1a4: 0xe00d, 0x1a5: 0x0008, 0x1a6: 0x0185, 0x1a7: 0xe07d, 0x1a8: 0x0008, 0x1a9: 0x019d, + 0x1aa: 0x0008, 0x1ab: 0x0008, 0x1ac: 0xe00d, 0x1ad: 0x0008, 0x1ae: 0x0185, 0x1af: 0xe0fd, + 0x1b0: 0x0008, 0x1b1: 0x01b5, 0x1b2: 0x01cd, 0x1b3: 0xe03d, 0x1b4: 0x0008, 0x1b5: 0xe01d, + 0x1b6: 0x0008, 0x1b7: 0x01e5, 0x1b8: 0xe00d, 0x1b9: 0x0008, 0x1ba: 0x0008, 0x1bb: 0x0008, + 0x1bc: 0xe00d, 0x1bd: 0x0008, 0x1be: 0x0008, 0x1bf: 0x0008, + // Block 0x7, offset 0x1c0 + 0x1c0: 0x0008, 0x1c1: 0x0008, 0x1c2: 0x0008, 0x1c3: 0x0008, 0x1c4: 0x01e9, 0x1c5: 0x01e9, + 0x1c6: 0x01e9, 0x1c7: 0x01fd, 0x1c8: 0x0215, 0x1c9: 0x022d, 0x1ca: 0x0245, 0x1cb: 0x025d, + 0x1cc: 0x0275, 0x1cd: 0xe01d, 0x1ce: 0x0008, 0x1cf: 0xe0fd, 0x1d0: 0x0008, 0x1d1: 0xe01d, + 0x1d2: 0x0008, 0x1d3: 0xe03d, 0x1d4: 0x0008, 0x1d5: 0xe01d, 0x1d6: 0x0008, 0x1d7: 0xe07d, + 0x1d8: 0x0008, 0x1d9: 0xe01d, 0x1da: 0x0008, 0x1db: 0xe03d, 0x1dc: 0x0008, 0x1dd: 0x0008, + 0x1de: 0xe00d, 0x1df: 0x0008, 0x1e0: 0xe00d, 0x1e1: 0x0008, 0x1e2: 0xe00d, 0x1e3: 0x0008, + 0x1e4: 0xe00d, 0x1e5: 0x0008, 0x1e6: 0xe00d, 0x1e7: 0x0008, 0x1e8: 0xe00d, 0x1e9: 0x0008, + 0x1ea: 0xe00d, 0x1eb: 0x0008, 0x1ec: 0xe00d, 0x1ed: 0x0008, 0x1ee: 0xe00d, 0x1ef: 0x0008, + 0x1f0: 0x0008, 0x1f1: 0x028d, 0x1f2: 0x02a5, 0x1f3: 0x02bd, 0x1f4: 0xe00d, 0x1f5: 0x0008, + 0x1f6: 0x02d5, 0x1f7: 0x02ed, 0x1f8: 0xe00d, 0x1f9: 0x0008, 0x1fa: 0xe00d, 0x1fb: 0x0008, + 0x1fc: 0xe00d, 0x1fd: 0x0008, 0x1fe: 0xe00d, 0x1ff: 0x0008, + // Block 0x8, offset 0x200 + 0x200: 0xe00d, 0x201: 0x0008, 0x202: 0xe00d, 0x203: 0x0008, 0x204: 0xe00d, 0x205: 0x0008, + 0x206: 0xe00d, 0x207: 0x0008, 0x208: 0xe00d, 0x209: 0x0008, 0x20a: 0xe00d, 0x20b: 0x0008, + 0x20c: 0xe00d, 0x20d: 0x0008, 0x20e: 0xe00d, 0x20f: 0x0008, 0x210: 0xe00d, 0x211: 0x0008, + 0x212: 0xe00d, 0x213: 0x0008, 0x214: 0xe00d, 0x215: 0x0008, 0x216: 0xe00d, 0x217: 0x0008, + 0x218: 0xe00d, 0x219: 0x0008, 0x21a: 0xe00d, 0x21b: 0x0008, 0x21c: 0xe00d, 0x21d: 0x0008, + 0x21e: 0xe00d, 0x21f: 0x0008, 0x220: 0x0305, 0x221: 0x0008, 0x222: 0xe00d, 0x223: 0x0008, + 0x224: 0xe00d, 0x225: 0x0008, 0x226: 0xe00d, 0x227: 0x0008, 0x228: 0xe00d, 0x229: 0x0008, + 0x22a: 0xe00d, 0x22b: 0x0008, 0x22c: 0xe00d, 0x22d: 0x0008, 0x22e: 0xe00d, 0x22f: 0x0008, + 0x230: 0xe00d, 0x231: 0x0008, 0x232: 0xe00d, 0x233: 0x0008, 0x234: 0x0008, 0x235: 0x0008, + 0x236: 0x0008, 0x237: 0x0008, 0x238: 0x0008, 0x239: 0x0008, 0x23a: 0x0209, 0x23b: 0xe03d, + 0x23c: 0x0008, 0x23d: 0x031d, 0x23e: 0x0229, 0x23f: 0x0008, + // Block 0x9, offset 0x240 + 0x240: 0x0008, 0x241: 0x0008, 0x242: 0x0018, 0x243: 0x0018, 0x244: 0x0018, 0x245: 0x0018, + 0x246: 0x0008, 0x247: 0x0008, 0x248: 0x0008, 0x249: 0x0008, 0x24a: 0x0008, 0x24b: 0x0008, + 0x24c: 0x0008, 0x24d: 0x0008, 0x24e: 0x0008, 0x24f: 0x0008, 0x250: 0x0008, 0x251: 0x0008, + 0x252: 0x0018, 0x253: 0x0018, 0x254: 0x0018, 0x255: 0x0018, 0x256: 0x0018, 0x257: 0x0018, + 0x258: 0x029a, 0x259: 0x02ba, 0x25a: 0x02da, 0x25b: 0x02fa, 0x25c: 0x031a, 0x25d: 0x033a, + 0x25e: 0x0018, 0x25f: 0x0018, 0x260: 0x03ad, 0x261: 0x0359, 0x262: 0x01d9, 0x263: 0x0369, + 0x264: 0x03c5, 0x265: 0x0018, 0x266: 0x0018, 0x267: 0x0018, 0x268: 0x0018, 0x269: 0x0018, + 0x26a: 0x0018, 0x26b: 0x0018, 0x26c: 0x0008, 0x26d: 0x0018, 0x26e: 0x0008, 0x26f: 0x0018, + 0x270: 0x0018, 0x271: 0x0018, 0x272: 0x0018, 0x273: 0x0018, 0x274: 0x0018, 0x275: 0x0018, + 0x276: 0x0018, 0x277: 0x0018, 0x278: 0x0018, 0x279: 0x0018, 0x27a: 0x0018, 0x27b: 0x0018, + 0x27c: 0x0018, 0x27d: 0x0018, 0x27e: 0x0018, 0x27f: 0x0018, + // Block 0xa, offset 0x280 + 0x280: 0x03dd, 0x281: 0x03dd, 0x282: 0x3308, 0x283: 0x03f5, 0x284: 0x0379, 0x285: 0x040d, + 0x286: 0x3308, 0x287: 0x3308, 0x288: 0x3308, 0x289: 0x3308, 0x28a: 0x3308, 0x28b: 0x3308, + 0x28c: 0x3308, 0x28d: 0x3308, 0x28e: 0x3308, 0x28f: 0x33c0, 0x290: 0x3308, 0x291: 0x3308, + 0x292: 0x3308, 0x293: 0x3308, 0x294: 0x3308, 0x295: 0x3308, 0x296: 0x3308, 0x297: 0x3308, + 0x298: 0x3308, 0x299: 0x3308, 0x29a: 0x3308, 0x29b: 0x3308, 0x29c: 0x3308, 0x29d: 0x3308, + 0x29e: 0x3308, 0x29f: 0x3308, 0x2a0: 0x3308, 0x2a1: 0x3308, 0x2a2: 0x3308, 0x2a3: 0x3308, + 0x2a4: 0x3308, 0x2a5: 0x3308, 0x2a6: 0x3308, 0x2a7: 0x3308, 0x2a8: 0x3308, 0x2a9: 0x3308, + 0x2aa: 0x3308, 0x2ab: 0x3308, 0x2ac: 0x3308, 0x2ad: 0x3308, 0x2ae: 0x3308, 0x2af: 0x3308, + 0x2b0: 0xe00d, 0x2b1: 0x0008, 0x2b2: 0xe00d, 0x2b3: 0x0008, 0x2b4: 0x0425, 0x2b5: 0x0008, + 0x2b6: 0xe00d, 0x2b7: 0x0008, 0x2b8: 0x0040, 0x2b9: 0x0040, 0x2ba: 0x03a2, 0x2bb: 0x0008, + 0x2bc: 0x0008, 0x2bd: 0x0008, 0x2be: 0x03c2, 0x2bf: 0x043d, + // Block 0xb, offset 0x2c0 + 0x2c0: 0x0040, 0x2c1: 0x0040, 0x2c2: 0x0040, 0x2c3: 0x0040, 0x2c4: 0x008a, 0x2c5: 0x03d2, + 0x2c6: 0xe155, 0x2c7: 0x0455, 0x2c8: 0xe12d, 0x2c9: 0xe13d, 0x2ca: 0xe12d, 0x2cb: 0x0040, + 0x2cc: 0x03dd, 0x2cd: 0x0040, 0x2ce: 0x046d, 0x2cf: 0x0485, 0x2d0: 0x0008, 0x2d1: 0xe105, + 0x2d2: 0xe105, 0x2d3: 0xe105, 0x2d4: 0xe105, 0x2d5: 0xe105, 0x2d6: 0xe105, 0x2d7: 0xe105, + 0x2d8: 0xe105, 0x2d9: 0xe105, 0x2da: 0xe105, 0x2db: 0xe105, 0x2dc: 0xe105, 0x2dd: 0xe105, + 0x2de: 0xe105, 0x2df: 0xe105, 0x2e0: 0x049d, 0x2e1: 0x049d, 0x2e2: 0x0040, 0x2e3: 0x049d, + 0x2e4: 0x049d, 0x2e5: 0x049d, 0x2e6: 0x049d, 0x2e7: 0x049d, 0x2e8: 0x049d, 0x2e9: 0x049d, + 0x2ea: 0x049d, 0x2eb: 0x049d, 0x2ec: 0x0008, 0x2ed: 0x0008, 0x2ee: 0x0008, 0x2ef: 0x0008, + 0x2f0: 0x0008, 0x2f1: 0x0008, 0x2f2: 0x0008, 0x2f3: 0x0008, 0x2f4: 0x0008, 0x2f5: 0x0008, + 0x2f6: 0x0008, 0x2f7: 0x0008, 0x2f8: 0x0008, 0x2f9: 0x0008, 0x2fa: 0x0008, 0x2fb: 0x0008, + 0x2fc: 0x0008, 0x2fd: 0x0008, 0x2fe: 0x0008, 0x2ff: 0x0008, + // Block 0xc, offset 0x300 + 0x300: 0x0008, 0x301: 0x0008, 0x302: 0xe00f, 0x303: 0x0008, 0x304: 0x0008, 0x305: 0x0008, + 0x306: 0x0008, 0x307: 0x0008, 0x308: 0x0008, 0x309: 0x0008, 0x30a: 0x0008, 0x30b: 0x0008, + 0x30c: 0x0008, 0x30d: 0x0008, 0x30e: 0x0008, 0x30f: 0xe0c5, 0x310: 0x04b5, 0x311: 0x04cd, + 0x312: 0xe0bd, 0x313: 0xe0f5, 0x314: 0xe0fd, 0x315: 0xe09d, 0x316: 0xe0b5, 0x317: 0x0008, + 0x318: 0xe00d, 0x319: 0x0008, 0x31a: 0xe00d, 0x31b: 0x0008, 0x31c: 0xe00d, 0x31d: 0x0008, + 0x31e: 0xe00d, 0x31f: 0x0008, 0x320: 0xe00d, 0x321: 0x0008, 0x322: 0xe00d, 0x323: 0x0008, + 0x324: 0xe00d, 0x325: 0x0008, 0x326: 0xe00d, 0x327: 0x0008, 0x328: 0xe00d, 0x329: 0x0008, + 0x32a: 0xe00d, 0x32b: 0x0008, 0x32c: 0xe00d, 0x32d: 0x0008, 0x32e: 0xe00d, 0x32f: 0x0008, + 0x330: 0x04e5, 0x331: 0xe185, 0x332: 0xe18d, 0x333: 0x0008, 0x334: 0x04fd, 0x335: 0x03dd, + 0x336: 0x0018, 0x337: 0xe07d, 0x338: 0x0008, 0x339: 0xe1d5, 0x33a: 0xe00d, 0x33b: 0x0008, + 0x33c: 0x0008, 0x33d: 0x0515, 0x33e: 0x052d, 0x33f: 0x052d, + // Block 0xd, offset 0x340 + 0x340: 0x0008, 0x341: 0x0008, 0x342: 0x0008, 0x343: 0x0008, 0x344: 0x0008, 0x345: 0x0008, + 0x346: 0x0008, 0x347: 0x0008, 0x348: 0x0008, 0x349: 0x0008, 0x34a: 0x0008, 0x34b: 0x0008, + 0x34c: 0x0008, 0x34d: 0x0008, 0x34e: 0x0008, 0x34f: 0x0008, 0x350: 0x0008, 0x351: 0x0008, + 0x352: 0x0008, 0x353: 0x0008, 0x354: 0x0008, 0x355: 0x0008, 0x356: 0x0008, 0x357: 0x0008, + 0x358: 0x0008, 0x359: 0x0008, 0x35a: 0x0008, 0x35b: 0x0008, 0x35c: 0x0008, 0x35d: 0x0008, + 0x35e: 0x0008, 0x35f: 0x0008, 0x360: 0xe00d, 0x361: 0x0008, 0x362: 0xe00d, 0x363: 0x0008, + 0x364: 0xe00d, 0x365: 0x0008, 0x366: 0xe00d, 0x367: 0x0008, 0x368: 0xe00d, 0x369: 0x0008, + 0x36a: 0xe00d, 0x36b: 0x0008, 0x36c: 0xe00d, 0x36d: 0x0008, 0x36e: 0xe00d, 0x36f: 0x0008, + 0x370: 0xe00d, 0x371: 0x0008, 0x372: 0xe00d, 0x373: 0x0008, 0x374: 0xe00d, 0x375: 0x0008, + 0x376: 0xe00d, 0x377: 0x0008, 0x378: 0xe00d, 0x379: 0x0008, 0x37a: 0xe00d, 0x37b: 0x0008, + 0x37c: 0xe00d, 0x37d: 0x0008, 0x37e: 0xe00d, 0x37f: 0x0008, + // Block 0xe, offset 0x380 + 0x380: 0xe00d, 0x381: 0x0008, 0x382: 0x0018, 0x383: 0x3308, 0x384: 0x3308, 0x385: 0x3308, + 0x386: 0x3308, 0x387: 0x3308, 0x388: 0x3318, 0x389: 0x3318, 0x38a: 0xe00d, 0x38b: 0x0008, + 0x38c: 0xe00d, 0x38d: 0x0008, 0x38e: 0xe00d, 0x38f: 0x0008, 0x390: 0xe00d, 0x391: 0x0008, + 0x392: 0xe00d, 0x393: 0x0008, 0x394: 0xe00d, 0x395: 0x0008, 0x396: 0xe00d, 0x397: 0x0008, + 0x398: 0xe00d, 0x399: 0x0008, 0x39a: 0xe00d, 0x39b: 0x0008, 0x39c: 0xe00d, 0x39d: 0x0008, + 0x39e: 0xe00d, 0x39f: 0x0008, 0x3a0: 0xe00d, 0x3a1: 0x0008, 0x3a2: 0xe00d, 0x3a3: 0x0008, + 0x3a4: 0xe00d, 0x3a5: 0x0008, 0x3a6: 0xe00d, 0x3a7: 0x0008, 0x3a8: 0xe00d, 0x3a9: 0x0008, + 0x3aa: 0xe00d, 0x3ab: 0x0008, 0x3ac: 0xe00d, 0x3ad: 0x0008, 0x3ae: 0xe00d, 0x3af: 0x0008, + 0x3b0: 0xe00d, 0x3b1: 0x0008, 0x3b2: 0xe00d, 0x3b3: 0x0008, 0x3b4: 0xe00d, 0x3b5: 0x0008, + 0x3b6: 0xe00d, 0x3b7: 0x0008, 0x3b8: 0xe00d, 0x3b9: 0x0008, 0x3ba: 0xe00d, 0x3bb: 0x0008, + 0x3bc: 0xe00d, 0x3bd: 0x0008, 0x3be: 0xe00d, 0x3bf: 0x0008, + // Block 0xf, offset 0x3c0 + 0x3c0: 0x0040, 0x3c1: 0xe01d, 0x3c2: 0x0008, 0x3c3: 0xe03d, 0x3c4: 0x0008, 0x3c5: 0xe01d, + 0x3c6: 0x0008, 0x3c7: 0xe07d, 0x3c8: 0x0008, 0x3c9: 0xe01d, 0x3ca: 0x0008, 0x3cb: 0xe03d, + 0x3cc: 0x0008, 0x3cd: 0xe01d, 0x3ce: 0x0008, 0x3cf: 0x0008, 0x3d0: 0xe00d, 0x3d1: 0x0008, + 0x3d2: 0xe00d, 0x3d3: 0x0008, 0x3d4: 0xe00d, 0x3d5: 0x0008, 0x3d6: 0xe00d, 0x3d7: 0x0008, + 0x3d8: 0xe00d, 0x3d9: 0x0008, 0x3da: 0xe00d, 0x3db: 0x0008, 0x3dc: 0xe00d, 0x3dd: 0x0008, + 0x3de: 0xe00d, 0x3df: 0x0008, 0x3e0: 0xe00d, 0x3e1: 0x0008, 0x3e2: 0xe00d, 0x3e3: 0x0008, + 0x3e4: 0xe00d, 0x3e5: 0x0008, 0x3e6: 0xe00d, 0x3e7: 0x0008, 0x3e8: 0xe00d, 0x3e9: 0x0008, + 0x3ea: 0xe00d, 0x3eb: 0x0008, 0x3ec: 0xe00d, 0x3ed: 0x0008, 0x3ee: 0xe00d, 0x3ef: 0x0008, + 0x3f0: 0xe00d, 0x3f1: 0x0008, 0x3f2: 0xe00d, 0x3f3: 0x0008, 0x3f4: 0xe00d, 0x3f5: 0x0008, + 0x3f6: 0xe00d, 0x3f7: 0x0008, 0x3f8: 0xe00d, 0x3f9: 0x0008, 0x3fa: 0xe00d, 0x3fb: 0x0008, + 0x3fc: 0xe00d, 0x3fd: 0x0008, 0x3fe: 0xe00d, 0x3ff: 0x0008, + // Block 0x10, offset 0x400 + 0x400: 0xe00d, 0x401: 0x0008, 0x402: 0xe00d, 0x403: 0x0008, 0x404: 0xe00d, 0x405: 0x0008, + 0x406: 0xe00d, 0x407: 0x0008, 0x408: 0xe00d, 0x409: 0x0008, 0x40a: 0xe00d, 0x40b: 0x0008, + 0x40c: 0xe00d, 0x40d: 0x0008, 0x40e: 0xe00d, 0x40f: 0x0008, 0x410: 0xe00d, 0x411: 0x0008, + 0x412: 0xe00d, 0x413: 0x0008, 0x414: 0xe00d, 0x415: 0x0008, 0x416: 0xe00d, 0x417: 0x0008, + 0x418: 0xe00d, 0x419: 0x0008, 0x41a: 0xe00d, 0x41b: 0x0008, 0x41c: 0xe00d, 0x41d: 0x0008, + 0x41e: 0xe00d, 0x41f: 0x0008, 0x420: 0xe00d, 0x421: 0x0008, 0x422: 0xe00d, 0x423: 0x0008, + 0x424: 0xe00d, 0x425: 0x0008, 0x426: 0xe00d, 0x427: 0x0008, 0x428: 0xe00d, 0x429: 0x0008, + 0x42a: 0xe00d, 0x42b: 0x0008, 0x42c: 0xe00d, 0x42d: 0x0008, 0x42e: 0xe00d, 0x42f: 0x0008, + 0x430: 0x0040, 0x431: 0x03f5, 0x432: 0x03f5, 0x433: 0x03f5, 0x434: 0x03f5, 0x435: 0x03f5, + 0x436: 0x03f5, 0x437: 0x03f5, 0x438: 0x03f5, 0x439: 0x03f5, 0x43a: 0x03f5, 0x43b: 0x03f5, + 0x43c: 0x03f5, 0x43d: 0x03f5, 0x43e: 0x03f5, 0x43f: 0x03f5, + // Block 0x11, offset 0x440 + 0x440: 0x0840, 0x441: 0x0840, 0x442: 0x0840, 0x443: 0x0840, 0x444: 0x0840, 0x445: 0x0840, + 0x446: 0x0018, 0x447: 0x0018, 0x448: 0x0818, 0x449: 0x0018, 0x44a: 0x0018, 0x44b: 0x0818, + 0x44c: 0x0018, 0x44d: 0x0818, 0x44e: 0x0018, 0x44f: 0x0018, 0x450: 0x3308, 0x451: 0x3308, + 0x452: 0x3308, 0x453: 0x3308, 0x454: 0x3308, 0x455: 0x3308, 0x456: 0x3308, 0x457: 0x3308, + 0x458: 0x3308, 0x459: 0x3308, 0x45a: 0x3308, 0x45b: 0x0818, 0x45c: 0x0b40, 0x45d: 0x0040, + 0x45e: 0x0818, 0x45f: 0x0818, 0x460: 0x0a08, 0x461: 0x0808, 0x462: 0x0c08, 0x463: 0x0c08, + 0x464: 0x0c08, 0x465: 0x0c08, 0x466: 0x0a08, 0x467: 0x0c08, 0x468: 0x0a08, 0x469: 0x0c08, + 0x46a: 0x0a08, 0x46b: 0x0a08, 0x46c: 0x0a08, 0x46d: 0x0a08, 0x46e: 0x0a08, 0x46f: 0x0c08, + 0x470: 0x0c08, 0x471: 0x0c08, 0x472: 0x0c08, 0x473: 0x0a08, 0x474: 0x0a08, 0x475: 0x0a08, + 0x476: 0x0a08, 0x477: 0x0a08, 0x478: 0x0a08, 0x479: 0x0a08, 0x47a: 0x0a08, 0x47b: 0x0a08, + 0x47c: 0x0a08, 0x47d: 0x0a08, 0x47e: 0x0a08, 0x47f: 0x0a08, + // Block 0x12, offset 0x480 + 0x480: 0x0818, 0x481: 0x0a08, 0x482: 0x0a08, 0x483: 0x0a08, 0x484: 0x0a08, 0x485: 0x0a08, + 0x486: 0x0a08, 0x487: 0x0a08, 0x488: 0x0c08, 0x489: 0x0a08, 0x48a: 0x0a08, 0x48b: 0x3308, + 0x48c: 0x3308, 0x48d: 0x3308, 0x48e: 0x3308, 0x48f: 0x3308, 0x490: 0x3308, 0x491: 0x3308, + 0x492: 0x3308, 0x493: 0x3308, 0x494: 0x3308, 0x495: 0x3308, 0x496: 0x3308, 0x497: 0x3308, + 0x498: 0x3308, 0x499: 0x3308, 0x49a: 0x3308, 0x49b: 0x3308, 0x49c: 0x3308, 0x49d: 0x3308, + 0x49e: 0x3308, 0x49f: 0x3308, 0x4a0: 0x0808, 0x4a1: 0x0808, 0x4a2: 0x0808, 0x4a3: 0x0808, + 0x4a4: 0x0808, 0x4a5: 0x0808, 0x4a6: 0x0808, 0x4a7: 0x0808, 0x4a8: 0x0808, 0x4a9: 0x0808, + 0x4aa: 0x0018, 0x4ab: 0x0818, 0x4ac: 0x0818, 0x4ad: 0x0818, 0x4ae: 0x0a08, 0x4af: 0x0a08, + 0x4b0: 0x3308, 0x4b1: 0x0c08, 0x4b2: 0x0c08, 0x4b3: 0x0c08, 0x4b4: 0x0808, 0x4b5: 0x0429, + 0x4b6: 0x0451, 0x4b7: 0x0479, 0x4b8: 0x04a1, 0x4b9: 0x0a08, 0x4ba: 0x0a08, 0x4bb: 0x0a08, + 0x4bc: 0x0a08, 0x4bd: 0x0a08, 0x4be: 0x0a08, 0x4bf: 0x0a08, + // Block 0x13, offset 0x4c0 + 0x4c0: 0x0c08, 0x4c1: 0x0a08, 0x4c2: 0x0a08, 0x4c3: 0x0c08, 0x4c4: 0x0c08, 0x4c5: 0x0c08, + 0x4c6: 0x0c08, 0x4c7: 0x0c08, 0x4c8: 0x0c08, 0x4c9: 0x0c08, 0x4ca: 0x0c08, 0x4cb: 0x0c08, + 0x4cc: 0x0a08, 0x4cd: 0x0c08, 0x4ce: 0x0a08, 0x4cf: 0x0c08, 0x4d0: 0x0a08, 0x4d1: 0x0a08, + 0x4d2: 0x0c08, 0x4d3: 0x0c08, 0x4d4: 0x0818, 0x4d5: 0x0c08, 0x4d6: 0x3308, 0x4d7: 0x3308, + 0x4d8: 0x3308, 0x4d9: 0x3308, 0x4da: 0x3308, 0x4db: 0x3308, 0x4dc: 0x3308, 0x4dd: 0x0840, + 0x4de: 0x0018, 0x4df: 0x3308, 0x4e0: 0x3308, 0x4e1: 0x3308, 0x4e2: 0x3308, 0x4e3: 0x3308, + 0x4e4: 0x3308, 0x4e5: 0x0808, 0x4e6: 0x0808, 0x4e7: 0x3308, 0x4e8: 0x3308, 0x4e9: 0x0018, + 0x4ea: 0x3308, 0x4eb: 0x3308, 0x4ec: 0x3308, 0x4ed: 0x3308, 0x4ee: 0x0c08, 0x4ef: 0x0c08, + 0x4f0: 0x0008, 0x4f1: 0x0008, 0x4f2: 0x0008, 0x4f3: 0x0008, 0x4f4: 0x0008, 0x4f5: 0x0008, + 0x4f6: 0x0008, 0x4f7: 0x0008, 0x4f8: 0x0008, 0x4f9: 0x0008, 0x4fa: 0x0a08, 0x4fb: 0x0a08, + 0x4fc: 0x0a08, 0x4fd: 0x0808, 0x4fe: 0x0808, 0x4ff: 0x0a08, + // Block 0x14, offset 0x500 + 0x500: 0x0818, 0x501: 0x0818, 0x502: 0x0818, 0x503: 0x0818, 0x504: 0x0818, 0x505: 0x0818, + 0x506: 0x0818, 0x507: 0x0818, 0x508: 0x0818, 0x509: 0x0818, 0x50a: 0x0818, 0x50b: 0x0818, + 0x50c: 0x0818, 0x50d: 0x0818, 0x50e: 0x0040, 0x50f: 0x0b40, 0x510: 0x0c08, 0x511: 0x3308, + 0x512: 0x0a08, 0x513: 0x0a08, 0x514: 0x0a08, 0x515: 0x0c08, 0x516: 0x0c08, 0x517: 0x0c08, + 0x518: 0x0c08, 0x519: 0x0c08, 0x51a: 0x0a08, 0x51b: 0x0a08, 0x51c: 0x0a08, 0x51d: 0x0a08, + 0x51e: 0x0c08, 0x51f: 0x0a08, 0x520: 0x0a08, 0x521: 0x0a08, 0x522: 0x0a08, 0x523: 0x0a08, + 0x524: 0x0a08, 0x525: 0x0a08, 0x526: 0x0a08, 0x527: 0x0a08, 0x528: 0x0c08, 0x529: 0x0a08, + 0x52a: 0x0c08, 0x52b: 0x0a08, 0x52c: 0x0c08, 0x52d: 0x0a08, 0x52e: 0x0a08, 0x52f: 0x0c08, + 0x530: 0x3308, 0x531: 0x3308, 0x532: 0x3308, 0x533: 0x3308, 0x534: 0x3308, 0x535: 0x3308, + 0x536: 0x3308, 0x537: 0x3308, 0x538: 0x3308, 0x539: 0x3308, 0x53a: 0x3308, 0x53b: 0x3308, + 0x53c: 0x3308, 0x53d: 0x3308, 0x53e: 0x3308, 0x53f: 0x3308, + // Block 0x15, offset 0x540 + 0x540: 0x0c08, 0x541: 0x0a08, 0x542: 0x0a08, 0x543: 0x0a08, 0x544: 0x0a08, 0x545: 0x0a08, + 0x546: 0x0c08, 0x547: 0x0c08, 0x548: 0x0a08, 0x549: 0x0c08, 0x54a: 0x0a08, 0x54b: 0x0a08, + 0x54c: 0x0a08, 0x54d: 0x0a08, 0x54e: 0x0a08, 0x54f: 0x0a08, 0x550: 0x0a08, 0x551: 0x0a08, + 0x552: 0x0a08, 0x553: 0x0a08, 0x554: 0x0c08, 0x555: 0x0a08, 0x556: 0x0808, 0x557: 0x0808, + 0x558: 0x0808, 0x559: 0x3308, 0x55a: 0x3308, 0x55b: 0x3308, 0x55c: 0x0040, 0x55d: 0x0040, + 0x55e: 0x0818, 0x55f: 0x0040, 0x560: 0x0a08, 0x561: 0x0808, 0x562: 0x0a08, 0x563: 0x0a08, + 0x564: 0x0a08, 0x565: 0x0a08, 0x566: 0x0808, 0x567: 0x0c08, 0x568: 0x0a08, 0x569: 0x0c08, + 0x56a: 0x0c08, 0x56b: 0x0040, 0x56c: 0x0040, 0x56d: 0x0040, 0x56e: 0x0040, 0x56f: 0x0040, + 0x570: 0x0040, 0x571: 0x0040, 0x572: 0x0040, 0x573: 0x0040, 0x574: 0x0040, 0x575: 0x0040, + 0x576: 0x0040, 0x577: 0x0040, 0x578: 0x0040, 0x579: 0x0040, 0x57a: 0x0040, 0x57b: 0x0040, + 0x57c: 0x0040, 0x57d: 0x0040, 0x57e: 0x0040, 0x57f: 0x0040, + // Block 0x16, offset 0x580 + 0x580: 0x3008, 0x581: 0x3308, 0x582: 0x3308, 0x583: 0x3308, 0x584: 0x3308, 0x585: 0x3308, + 0x586: 0x3308, 0x587: 0x3308, 0x588: 0x3308, 0x589: 0x3008, 0x58a: 0x3008, 0x58b: 0x3008, + 0x58c: 0x3008, 0x58d: 0x3b08, 0x58e: 0x3008, 0x58f: 0x3008, 0x590: 0x0008, 0x591: 0x3308, + 0x592: 0x3308, 0x593: 0x3308, 0x594: 0x3308, 0x595: 0x3308, 0x596: 0x3308, 0x597: 0x3308, + 0x598: 0x04c9, 0x599: 0x0501, 0x59a: 0x0539, 0x59b: 0x0571, 0x59c: 0x05a9, 0x59d: 0x05e1, + 0x59e: 0x0619, 0x59f: 0x0651, 0x5a0: 0x0008, 0x5a1: 0x0008, 0x5a2: 0x3308, 0x5a3: 0x3308, + 0x5a4: 0x0018, 0x5a5: 0x0018, 0x5a6: 0x0008, 0x5a7: 0x0008, 0x5a8: 0x0008, 0x5a9: 0x0008, + 0x5aa: 0x0008, 0x5ab: 0x0008, 0x5ac: 0x0008, 0x5ad: 0x0008, 0x5ae: 0x0008, 0x5af: 0x0008, + 0x5b0: 0x0018, 0x5b1: 0x0008, 0x5b2: 0x0008, 0x5b3: 0x0008, 0x5b4: 0x0008, 0x5b5: 0x0008, + 0x5b6: 0x0008, 0x5b7: 0x0008, 0x5b8: 0x0008, 0x5b9: 0x0008, 0x5ba: 0x0008, 0x5bb: 0x0008, + 0x5bc: 0x0008, 0x5bd: 0x0008, 0x5be: 0x0008, 0x5bf: 0x0008, + // Block 0x17, offset 0x5c0 + 0x5c0: 0x0008, 0x5c1: 0x3308, 0x5c2: 0x3008, 0x5c3: 0x3008, 0x5c4: 0x0040, 0x5c5: 0x0008, + 0x5c6: 0x0008, 0x5c7: 0x0008, 0x5c8: 0x0008, 0x5c9: 0x0008, 0x5ca: 0x0008, 0x5cb: 0x0008, + 0x5cc: 0x0008, 0x5cd: 0x0040, 0x5ce: 0x0040, 0x5cf: 0x0008, 0x5d0: 0x0008, 0x5d1: 0x0040, + 0x5d2: 0x0040, 0x5d3: 0x0008, 0x5d4: 0x0008, 0x5d5: 0x0008, 0x5d6: 0x0008, 0x5d7: 0x0008, + 0x5d8: 0x0008, 0x5d9: 0x0008, 0x5da: 0x0008, 0x5db: 0x0008, 0x5dc: 0x0008, 0x5dd: 0x0008, + 0x5de: 0x0008, 0x5df: 0x0008, 0x5e0: 0x0008, 0x5e1: 0x0008, 0x5e2: 0x0008, 0x5e3: 0x0008, + 0x5e4: 0x0008, 0x5e5: 0x0008, 0x5e6: 0x0008, 0x5e7: 0x0008, 0x5e8: 0x0008, 0x5e9: 0x0040, + 0x5ea: 0x0008, 0x5eb: 0x0008, 0x5ec: 0x0008, 0x5ed: 0x0008, 0x5ee: 0x0008, 0x5ef: 0x0008, + 0x5f0: 0x0008, 0x5f1: 0x0040, 0x5f2: 0x0008, 0x5f3: 0x0040, 0x5f4: 0x0040, 0x5f5: 0x0040, + 0x5f6: 0x0008, 0x5f7: 0x0008, 0x5f8: 0x0008, 0x5f9: 0x0008, 0x5fa: 0x0040, 0x5fb: 0x0040, + 0x5fc: 0x3308, 0x5fd: 0x0008, 0x5fe: 0x3008, 0x5ff: 0x3008, + // Block 0x18, offset 0x600 + 0x600: 0x3008, 0x601: 0x3308, 0x602: 0x3308, 0x603: 0x3308, 0x604: 0x3308, 0x605: 0x0040, + 0x606: 0x0040, 0x607: 0x3008, 0x608: 0x3008, 0x609: 0x0040, 0x60a: 0x0040, 0x60b: 0x3008, + 0x60c: 0x3008, 0x60d: 0x3b08, 0x60e: 0x0008, 0x60f: 0x0040, 0x610: 0x0040, 0x611: 0x0040, + 0x612: 0x0040, 0x613: 0x0040, 0x614: 0x0040, 0x615: 0x0040, 0x616: 0x0040, 0x617: 0x3008, + 0x618: 0x0040, 0x619: 0x0040, 0x61a: 0x0040, 0x61b: 0x0040, 0x61c: 0x0689, 0x61d: 0x06c1, + 0x61e: 0x0040, 0x61f: 0x06f9, 0x620: 0x0008, 0x621: 0x0008, 0x622: 0x3308, 0x623: 0x3308, + 0x624: 0x0040, 0x625: 0x0040, 0x626: 0x0008, 0x627: 0x0008, 0x628: 0x0008, 0x629: 0x0008, + 0x62a: 0x0008, 0x62b: 0x0008, 0x62c: 0x0008, 0x62d: 0x0008, 0x62e: 0x0008, 0x62f: 0x0008, + 0x630: 0x0008, 0x631: 0x0008, 0x632: 0x0018, 0x633: 0x0018, 0x634: 0x0018, 0x635: 0x0018, + 0x636: 0x0018, 0x637: 0x0018, 0x638: 0x0018, 0x639: 0x0018, 0x63a: 0x0018, 0x63b: 0x0018, + 0x63c: 0x0008, 0x63d: 0x0018, 0x63e: 0x0040, 0x63f: 0x0040, + // Block 0x19, offset 0x640 + 0x640: 0x0040, 0x641: 0x3308, 0x642: 0x3308, 0x643: 0x3008, 0x644: 0x0040, 0x645: 0x0008, + 0x646: 0x0008, 0x647: 0x0008, 0x648: 0x0008, 0x649: 0x0008, 0x64a: 0x0008, 0x64b: 0x0040, + 0x64c: 0x0040, 0x64d: 0x0040, 0x64e: 0x0040, 0x64f: 0x0008, 0x650: 0x0008, 0x651: 0x0040, + 0x652: 0x0040, 0x653: 0x0008, 0x654: 0x0008, 0x655: 0x0008, 0x656: 0x0008, 0x657: 0x0008, + 0x658: 0x0008, 0x659: 0x0008, 0x65a: 0x0008, 0x65b: 0x0008, 0x65c: 0x0008, 0x65d: 0x0008, + 0x65e: 0x0008, 0x65f: 0x0008, 0x660: 0x0008, 0x661: 0x0008, 0x662: 0x0008, 0x663: 0x0008, + 0x664: 0x0008, 0x665: 0x0008, 0x666: 0x0008, 0x667: 0x0008, 0x668: 0x0008, 0x669: 0x0040, + 0x66a: 0x0008, 0x66b: 0x0008, 0x66c: 0x0008, 0x66d: 0x0008, 0x66e: 0x0008, 0x66f: 0x0008, + 0x670: 0x0008, 0x671: 0x0040, 0x672: 0x0008, 0x673: 0x0731, 0x674: 0x0040, 0x675: 0x0008, + 0x676: 0x0769, 0x677: 0x0040, 0x678: 0x0008, 0x679: 0x0008, 0x67a: 0x0040, 0x67b: 0x0040, + 0x67c: 0x3308, 0x67d: 0x0040, 0x67e: 0x3008, 0x67f: 0x3008, + // Block 0x1a, offset 0x680 + 0x680: 0x3008, 0x681: 0x3308, 0x682: 0x3308, 0x683: 0x0040, 0x684: 0x0040, 0x685: 0x0040, + 0x686: 0x0040, 0x687: 0x3308, 0x688: 0x3308, 0x689: 0x0040, 0x68a: 0x0040, 0x68b: 0x3308, + 0x68c: 0x3308, 0x68d: 0x3b08, 0x68e: 0x0040, 0x68f: 0x0040, 0x690: 0x0040, 0x691: 0x3308, + 0x692: 0x0040, 0x693: 0x0040, 0x694: 0x0040, 0x695: 0x0040, 0x696: 0x0040, 0x697: 0x0040, + 0x698: 0x0040, 0x699: 0x07a1, 0x69a: 0x07d9, 0x69b: 0x0811, 0x69c: 0x0008, 0x69d: 0x0040, + 0x69e: 0x0849, 0x69f: 0x0040, 0x6a0: 0x0040, 0x6a1: 0x0040, 0x6a2: 0x0040, 0x6a3: 0x0040, + 0x6a4: 0x0040, 0x6a5: 0x0040, 0x6a6: 0x0008, 0x6a7: 0x0008, 0x6a8: 0x0008, 0x6a9: 0x0008, + 0x6aa: 0x0008, 0x6ab: 0x0008, 0x6ac: 0x0008, 0x6ad: 0x0008, 0x6ae: 0x0008, 0x6af: 0x0008, + 0x6b0: 0x3308, 0x6b1: 0x3308, 0x6b2: 0x0008, 0x6b3: 0x0008, 0x6b4: 0x0008, 0x6b5: 0x3308, + 0x6b6: 0x0040, 0x6b7: 0x0040, 0x6b8: 0x0040, 0x6b9: 0x0040, 0x6ba: 0x0040, 0x6bb: 0x0040, + 0x6bc: 0x0040, 0x6bd: 0x0040, 0x6be: 0x0040, 0x6bf: 0x0040, + // Block 0x1b, offset 0x6c0 + 0x6c0: 0x0040, 0x6c1: 0x3308, 0x6c2: 0x3308, 0x6c3: 0x3008, 0x6c4: 0x0040, 0x6c5: 0x0008, + 0x6c6: 0x0008, 0x6c7: 0x0008, 0x6c8: 0x0008, 0x6c9: 0x0008, 0x6ca: 0x0008, 0x6cb: 0x0008, + 0x6cc: 0x0008, 0x6cd: 0x0008, 0x6ce: 0x0040, 0x6cf: 0x0008, 0x6d0: 0x0008, 0x6d1: 0x0008, + 0x6d2: 0x0040, 0x6d3: 0x0008, 0x6d4: 0x0008, 0x6d5: 0x0008, 0x6d6: 0x0008, 0x6d7: 0x0008, + 0x6d8: 0x0008, 0x6d9: 0x0008, 0x6da: 0x0008, 0x6db: 0x0008, 0x6dc: 0x0008, 0x6dd: 0x0008, + 0x6de: 0x0008, 0x6df: 0x0008, 0x6e0: 0x0008, 0x6e1: 0x0008, 0x6e2: 0x0008, 0x6e3: 0x0008, + 0x6e4: 0x0008, 0x6e5: 0x0008, 0x6e6: 0x0008, 0x6e7: 0x0008, 0x6e8: 0x0008, 0x6e9: 0x0040, + 0x6ea: 0x0008, 0x6eb: 0x0008, 0x6ec: 0x0008, 0x6ed: 0x0008, 0x6ee: 0x0008, 0x6ef: 0x0008, + 0x6f0: 0x0008, 0x6f1: 0x0040, 0x6f2: 0x0008, 0x6f3: 0x0008, 0x6f4: 0x0040, 0x6f5: 0x0008, + 0x6f6: 0x0008, 0x6f7: 0x0008, 0x6f8: 0x0008, 0x6f9: 0x0008, 0x6fa: 0x0040, 0x6fb: 0x0040, + 0x6fc: 0x3308, 0x6fd: 0x0008, 0x6fe: 0x3008, 0x6ff: 0x3008, + // Block 0x1c, offset 0x700 + 0x700: 0x3008, 0x701: 0x3308, 0x702: 0x3308, 0x703: 0x3308, 0x704: 0x3308, 0x705: 0x3308, + 0x706: 0x0040, 0x707: 0x3308, 0x708: 0x3308, 0x709: 0x3008, 0x70a: 0x0040, 0x70b: 0x3008, + 0x70c: 0x3008, 0x70d: 0x3b08, 0x70e: 0x0040, 0x70f: 0x0040, 0x710: 0x0008, 0x711: 0x0040, + 0x712: 0x0040, 0x713: 0x0040, 0x714: 0x0040, 0x715: 0x0040, 0x716: 0x0040, 0x717: 0x0040, + 0x718: 0x0040, 0x719: 0x0040, 0x71a: 0x0040, 0x71b: 0x0040, 0x71c: 0x0040, 0x71d: 0x0040, + 0x71e: 0x0040, 0x71f: 0x0040, 0x720: 0x0008, 0x721: 0x0008, 0x722: 0x3308, 0x723: 0x3308, + 0x724: 0x0040, 0x725: 0x0040, 0x726: 0x0008, 0x727: 0x0008, 0x728: 0x0008, 0x729: 0x0008, + 0x72a: 0x0008, 0x72b: 0x0008, 0x72c: 0x0008, 0x72d: 0x0008, 0x72e: 0x0008, 0x72f: 0x0008, + 0x730: 0x0018, 0x731: 0x0018, 0x732: 0x0040, 0x733: 0x0040, 0x734: 0x0040, 0x735: 0x0040, + 0x736: 0x0040, 0x737: 0x0040, 0x738: 0x0040, 0x739: 0x0008, 0x73a: 0x3308, 0x73b: 0x3308, + 0x73c: 0x3308, 0x73d: 0x3308, 0x73e: 0x3308, 0x73f: 0x3308, + // Block 0x1d, offset 0x740 + 0x740: 0x0040, 0x741: 0x3308, 0x742: 0x3008, 0x743: 0x3008, 0x744: 0x0040, 0x745: 0x0008, + 0x746: 0x0008, 0x747: 0x0008, 0x748: 0x0008, 0x749: 0x0008, 0x74a: 0x0008, 0x74b: 0x0008, + 0x74c: 0x0008, 0x74d: 0x0040, 0x74e: 0x0040, 0x74f: 0x0008, 0x750: 0x0008, 0x751: 0x0040, + 0x752: 0x0040, 0x753: 0x0008, 0x754: 0x0008, 0x755: 0x0008, 0x756: 0x0008, 0x757: 0x0008, + 0x758: 0x0008, 0x759: 0x0008, 0x75a: 0x0008, 0x75b: 0x0008, 0x75c: 0x0008, 0x75d: 0x0008, + 0x75e: 0x0008, 0x75f: 0x0008, 0x760: 0x0008, 0x761: 0x0008, 0x762: 0x0008, 0x763: 0x0008, + 0x764: 0x0008, 0x765: 0x0008, 0x766: 0x0008, 0x767: 0x0008, 0x768: 0x0008, 0x769: 0x0040, + 0x76a: 0x0008, 0x76b: 0x0008, 0x76c: 0x0008, 0x76d: 0x0008, 0x76e: 0x0008, 0x76f: 0x0008, + 0x770: 0x0008, 0x771: 0x0040, 0x772: 0x0008, 0x773: 0x0008, 0x774: 0x0040, 0x775: 0x0008, + 0x776: 0x0008, 0x777: 0x0008, 0x778: 0x0008, 0x779: 0x0008, 0x77a: 0x0040, 0x77b: 0x0040, + 0x77c: 0x3308, 0x77d: 0x0008, 0x77e: 0x3008, 0x77f: 0x3308, + // Block 0x1e, offset 0x780 + 0x780: 0x3008, 0x781: 0x3308, 0x782: 0x3308, 0x783: 0x3308, 0x784: 0x3308, 0x785: 0x0040, + 0x786: 0x0040, 0x787: 0x3008, 0x788: 0x3008, 0x789: 0x0040, 0x78a: 0x0040, 0x78b: 0x3008, + 0x78c: 0x3008, 0x78d: 0x3b08, 0x78e: 0x0040, 0x78f: 0x0040, 0x790: 0x0040, 0x791: 0x0040, + 0x792: 0x0040, 0x793: 0x0040, 0x794: 0x0040, 0x795: 0x0040, 0x796: 0x3308, 0x797: 0x3008, + 0x798: 0x0040, 0x799: 0x0040, 0x79a: 0x0040, 0x79b: 0x0040, 0x79c: 0x0881, 0x79d: 0x08b9, + 0x79e: 0x0040, 0x79f: 0x0008, 0x7a0: 0x0008, 0x7a1: 0x0008, 0x7a2: 0x3308, 0x7a3: 0x3308, + 0x7a4: 0x0040, 0x7a5: 0x0040, 0x7a6: 0x0008, 0x7a7: 0x0008, 0x7a8: 0x0008, 0x7a9: 0x0008, + 0x7aa: 0x0008, 0x7ab: 0x0008, 0x7ac: 0x0008, 0x7ad: 0x0008, 0x7ae: 0x0008, 0x7af: 0x0008, + 0x7b0: 0x0018, 0x7b1: 0x0008, 0x7b2: 0x0018, 0x7b3: 0x0018, 0x7b4: 0x0018, 0x7b5: 0x0018, + 0x7b6: 0x0018, 0x7b7: 0x0018, 0x7b8: 0x0040, 0x7b9: 0x0040, 0x7ba: 0x0040, 0x7bb: 0x0040, + 0x7bc: 0x0040, 0x7bd: 0x0040, 0x7be: 0x0040, 0x7bf: 0x0040, + // Block 0x1f, offset 0x7c0 + 0x7c0: 0x0040, 0x7c1: 0x0040, 0x7c2: 0x3308, 0x7c3: 0x0008, 0x7c4: 0x0040, 0x7c5: 0x0008, + 0x7c6: 0x0008, 0x7c7: 0x0008, 0x7c8: 0x0008, 0x7c9: 0x0008, 0x7ca: 0x0008, 0x7cb: 0x0040, + 0x7cc: 0x0040, 0x7cd: 0x0040, 0x7ce: 0x0008, 0x7cf: 0x0008, 0x7d0: 0x0008, 0x7d1: 0x0040, + 0x7d2: 0x0008, 0x7d3: 0x0008, 0x7d4: 0x0008, 0x7d5: 0x0008, 0x7d6: 0x0040, 0x7d7: 0x0040, + 0x7d8: 0x0040, 0x7d9: 0x0008, 0x7da: 0x0008, 0x7db: 0x0040, 0x7dc: 0x0008, 0x7dd: 0x0040, + 0x7de: 0x0008, 0x7df: 0x0008, 0x7e0: 0x0040, 0x7e1: 0x0040, 0x7e2: 0x0040, 0x7e3: 0x0008, + 0x7e4: 0x0008, 0x7e5: 0x0040, 0x7e6: 0x0040, 0x7e7: 0x0040, 0x7e8: 0x0008, 0x7e9: 0x0008, + 0x7ea: 0x0008, 0x7eb: 0x0040, 0x7ec: 0x0040, 0x7ed: 0x0040, 0x7ee: 0x0008, 0x7ef: 0x0008, + 0x7f0: 0x0008, 0x7f1: 0x0008, 0x7f2: 0x0008, 0x7f3: 0x0008, 0x7f4: 0x0008, 0x7f5: 0x0008, + 0x7f6: 0x0008, 0x7f7: 0x0008, 0x7f8: 0x0008, 0x7f9: 0x0008, 0x7fa: 0x0040, 0x7fb: 0x0040, + 0x7fc: 0x0040, 0x7fd: 0x0040, 0x7fe: 0x3008, 0x7ff: 0x3008, + // Block 0x20, offset 0x800 + 0x800: 0x3308, 0x801: 0x3008, 0x802: 0x3008, 0x803: 0x3008, 0x804: 0x3008, 0x805: 0x0040, + 0x806: 0x3308, 0x807: 0x3308, 0x808: 0x3308, 0x809: 0x0040, 0x80a: 0x3308, 0x80b: 0x3308, + 0x80c: 0x3308, 0x80d: 0x3b08, 0x80e: 0x0040, 0x80f: 0x0040, 0x810: 0x0040, 0x811: 0x0040, + 0x812: 0x0040, 0x813: 0x0040, 0x814: 0x0040, 0x815: 0x3308, 0x816: 0x3308, 0x817: 0x0040, + 0x818: 0x0008, 0x819: 0x0008, 0x81a: 0x0008, 0x81b: 0x0040, 0x81c: 0x0040, 0x81d: 0x0040, + 0x81e: 0x0040, 0x81f: 0x0040, 0x820: 0x0008, 0x821: 0x0008, 0x822: 0x3308, 0x823: 0x3308, + 0x824: 0x0040, 0x825: 0x0040, 0x826: 0x0008, 0x827: 0x0008, 0x828: 0x0008, 0x829: 0x0008, + 0x82a: 0x0008, 0x82b: 0x0008, 0x82c: 0x0008, 0x82d: 0x0008, 0x82e: 0x0008, 0x82f: 0x0008, + 0x830: 0x0040, 0x831: 0x0040, 0x832: 0x0040, 0x833: 0x0040, 0x834: 0x0040, 0x835: 0x0040, + 0x836: 0x0040, 0x837: 0x0040, 0x838: 0x0018, 0x839: 0x0018, 0x83a: 0x0018, 0x83b: 0x0018, + 0x83c: 0x0018, 0x83d: 0x0018, 0x83e: 0x0018, 0x83f: 0x0018, + // Block 0x21, offset 0x840 + 0x840: 0x0008, 0x841: 0x3308, 0x842: 0x3008, 0x843: 0x3008, 0x844: 0x0040, 0x845: 0x0008, + 0x846: 0x0008, 0x847: 0x0008, 0x848: 0x0008, 0x849: 0x0008, 0x84a: 0x0008, 0x84b: 0x0008, + 0x84c: 0x0008, 0x84d: 0x0040, 0x84e: 0x0008, 0x84f: 0x0008, 0x850: 0x0008, 0x851: 0x0040, + 0x852: 0x0008, 0x853: 0x0008, 0x854: 0x0008, 0x855: 0x0008, 0x856: 0x0008, 0x857: 0x0008, + 0x858: 0x0008, 0x859: 0x0008, 0x85a: 0x0008, 0x85b: 0x0008, 0x85c: 0x0008, 0x85d: 0x0008, + 0x85e: 0x0008, 0x85f: 0x0008, 0x860: 0x0008, 0x861: 0x0008, 0x862: 0x0008, 0x863: 0x0008, + 0x864: 0x0008, 0x865: 0x0008, 0x866: 0x0008, 0x867: 0x0008, 0x868: 0x0008, 0x869: 0x0040, + 0x86a: 0x0008, 0x86b: 0x0008, 0x86c: 0x0008, 0x86d: 0x0008, 0x86e: 0x0008, 0x86f: 0x0008, + 0x870: 0x0008, 0x871: 0x0008, 0x872: 0x0008, 0x873: 0x0008, 0x874: 0x0040, 0x875: 0x0008, + 0x876: 0x0008, 0x877: 0x0008, 0x878: 0x0008, 0x879: 0x0008, 0x87a: 0x0040, 0x87b: 0x0040, + 0x87c: 0x3308, 0x87d: 0x0008, 0x87e: 0x3008, 0x87f: 0x3308, + // Block 0x22, offset 0x880 + 0x880: 0x3008, 0x881: 0x3008, 0x882: 0x3008, 0x883: 0x3008, 0x884: 0x3008, 0x885: 0x0040, + 0x886: 0x3308, 0x887: 0x3008, 0x888: 0x3008, 0x889: 0x0040, 0x88a: 0x3008, 0x88b: 0x3008, + 0x88c: 0x3308, 0x88d: 0x3b08, 0x88e: 0x0040, 0x88f: 0x0040, 0x890: 0x0040, 0x891: 0x0040, + 0x892: 0x0040, 0x893: 0x0040, 0x894: 0x0040, 0x895: 0x3008, 0x896: 0x3008, 0x897: 0x0040, + 0x898: 0x0040, 0x899: 0x0040, 0x89a: 0x0040, 0x89b: 0x0040, 0x89c: 0x0040, 0x89d: 0x0040, + 0x89e: 0x0008, 0x89f: 0x0040, 0x8a0: 0x0008, 0x8a1: 0x0008, 0x8a2: 0x3308, 0x8a3: 0x3308, + 0x8a4: 0x0040, 0x8a5: 0x0040, 0x8a6: 0x0008, 0x8a7: 0x0008, 0x8a8: 0x0008, 0x8a9: 0x0008, + 0x8aa: 0x0008, 0x8ab: 0x0008, 0x8ac: 0x0008, 0x8ad: 0x0008, 0x8ae: 0x0008, 0x8af: 0x0008, + 0x8b0: 0x0040, 0x8b1: 0x0008, 0x8b2: 0x0008, 0x8b3: 0x0040, 0x8b4: 0x0040, 0x8b5: 0x0040, + 0x8b6: 0x0040, 0x8b7: 0x0040, 0x8b8: 0x0040, 0x8b9: 0x0040, 0x8ba: 0x0040, 0x8bb: 0x0040, + 0x8bc: 0x0040, 0x8bd: 0x0040, 0x8be: 0x0040, 0x8bf: 0x0040, + // Block 0x23, offset 0x8c0 + 0x8c0: 0x3008, 0x8c1: 0x3308, 0x8c2: 0x3308, 0x8c3: 0x3308, 0x8c4: 0x3308, 0x8c5: 0x0040, + 0x8c6: 0x3008, 0x8c7: 0x3008, 0x8c8: 0x3008, 0x8c9: 0x0040, 0x8ca: 0x3008, 0x8cb: 0x3008, + 0x8cc: 0x3008, 0x8cd: 0x3b08, 0x8ce: 0x0008, 0x8cf: 0x0018, 0x8d0: 0x0040, 0x8d1: 0x0040, + 0x8d2: 0x0040, 0x8d3: 0x0040, 0x8d4: 0x0008, 0x8d5: 0x0008, 0x8d6: 0x0008, 0x8d7: 0x3008, + 0x8d8: 0x0018, 0x8d9: 0x0018, 0x8da: 0x0018, 0x8db: 0x0018, 0x8dc: 0x0018, 0x8dd: 0x0018, + 0x8de: 0x0018, 0x8df: 0x0008, 0x8e0: 0x0008, 0x8e1: 0x0008, 0x8e2: 0x3308, 0x8e3: 0x3308, + 0x8e4: 0x0040, 0x8e5: 0x0040, 0x8e6: 0x0008, 0x8e7: 0x0008, 0x8e8: 0x0008, 0x8e9: 0x0008, + 0x8ea: 0x0008, 0x8eb: 0x0008, 0x8ec: 0x0008, 0x8ed: 0x0008, 0x8ee: 0x0008, 0x8ef: 0x0008, + 0x8f0: 0x0018, 0x8f1: 0x0018, 0x8f2: 0x0018, 0x8f3: 0x0018, 0x8f4: 0x0018, 0x8f5: 0x0018, + 0x8f6: 0x0018, 0x8f7: 0x0018, 0x8f8: 0x0018, 0x8f9: 0x0018, 0x8fa: 0x0008, 0x8fb: 0x0008, + 0x8fc: 0x0008, 0x8fd: 0x0008, 0x8fe: 0x0008, 0x8ff: 0x0008, + // Block 0x24, offset 0x900 + 0x900: 0x0040, 0x901: 0x0008, 0x902: 0x0008, 0x903: 0x0040, 0x904: 0x0008, 0x905: 0x0040, + 0x906: 0x0040, 0x907: 0x0008, 0x908: 0x0008, 0x909: 0x0040, 0x90a: 0x0008, 0x90b: 0x0040, + 0x90c: 0x0040, 0x90d: 0x0008, 0x90e: 0x0040, 0x90f: 0x0040, 0x910: 0x0040, 0x911: 0x0040, + 0x912: 0x0040, 0x913: 0x0040, 0x914: 0x0008, 0x915: 0x0008, 0x916: 0x0008, 0x917: 0x0008, + 0x918: 0x0040, 0x919: 0x0008, 0x91a: 0x0008, 0x91b: 0x0008, 0x91c: 0x0008, 0x91d: 0x0008, + 0x91e: 0x0008, 0x91f: 0x0008, 0x920: 0x0040, 0x921: 0x0008, 0x922: 0x0008, 0x923: 0x0008, + 0x924: 0x0040, 0x925: 0x0008, 0x926: 0x0040, 0x927: 0x0008, 0x928: 0x0040, 0x929: 0x0040, + 0x92a: 0x0008, 0x92b: 0x0008, 0x92c: 0x0040, 0x92d: 0x0008, 0x92e: 0x0008, 0x92f: 0x0008, + 0x930: 0x0008, 0x931: 0x3308, 0x932: 0x0008, 0x933: 0x0929, 0x934: 0x3308, 0x935: 0x3308, + 0x936: 0x3308, 0x937: 0x3308, 0x938: 0x3308, 0x939: 0x3308, 0x93a: 0x0040, 0x93b: 0x3308, + 0x93c: 0x3308, 0x93d: 0x0008, 0x93e: 0x0040, 0x93f: 0x0040, + // Block 0x25, offset 0x940 + 0x940: 0x0008, 0x941: 0x0008, 0x942: 0x0008, 0x943: 0x09d1, 0x944: 0x0008, 0x945: 0x0008, + 0x946: 0x0008, 0x947: 0x0008, 0x948: 0x0040, 0x949: 0x0008, 0x94a: 0x0008, 0x94b: 0x0008, + 0x94c: 0x0008, 0x94d: 0x0a09, 0x94e: 0x0008, 0x94f: 0x0008, 0x950: 0x0008, 0x951: 0x0008, + 0x952: 0x0a41, 0x953: 0x0008, 0x954: 0x0008, 0x955: 0x0008, 0x956: 0x0008, 0x957: 0x0a79, + 0x958: 0x0008, 0x959: 0x0008, 0x95a: 0x0008, 0x95b: 0x0008, 0x95c: 0x0ab1, 0x95d: 0x0008, + 0x95e: 0x0008, 0x95f: 0x0008, 0x960: 0x0008, 0x961: 0x0008, 0x962: 0x0008, 0x963: 0x0008, + 0x964: 0x0008, 0x965: 0x0008, 0x966: 0x0008, 0x967: 0x0008, 0x968: 0x0008, 0x969: 0x0ae9, + 0x96a: 0x0008, 0x96b: 0x0008, 0x96c: 0x0008, 0x96d: 0x0040, 0x96e: 0x0040, 0x96f: 0x0040, + 0x970: 0x0040, 0x971: 0x3308, 0x972: 0x3308, 0x973: 0x0b21, 0x974: 0x3308, 0x975: 0x0b59, + 0x976: 0x0b91, 0x977: 0x0bc9, 0x978: 0x0c19, 0x979: 0x0c51, 0x97a: 0x3308, 0x97b: 0x3308, + 0x97c: 0x3308, 0x97d: 0x3308, 0x97e: 0x3308, 0x97f: 0x3008, + // Block 0x26, offset 0x980 + 0x980: 0x3308, 0x981: 0x0ca1, 0x982: 0x3308, 0x983: 0x3308, 0x984: 0x3b08, 0x985: 0x0018, + 0x986: 0x3308, 0x987: 0x3308, 0x988: 0x0008, 0x989: 0x0008, 0x98a: 0x0008, 0x98b: 0x0008, + 0x98c: 0x0008, 0x98d: 0x3308, 0x98e: 0x3308, 0x98f: 0x3308, 0x990: 0x3308, 0x991: 0x3308, + 0x992: 0x3308, 0x993: 0x0cd9, 0x994: 0x3308, 0x995: 0x3308, 0x996: 0x3308, 0x997: 0x3308, + 0x998: 0x0040, 0x999: 0x3308, 0x99a: 0x3308, 0x99b: 0x3308, 0x99c: 0x3308, 0x99d: 0x0d11, + 0x99e: 0x3308, 0x99f: 0x3308, 0x9a0: 0x3308, 0x9a1: 0x3308, 0x9a2: 0x0d49, 0x9a3: 0x3308, + 0x9a4: 0x3308, 0x9a5: 0x3308, 0x9a6: 0x3308, 0x9a7: 0x0d81, 0x9a8: 0x3308, 0x9a9: 0x3308, + 0x9aa: 0x3308, 0x9ab: 0x3308, 0x9ac: 0x0db9, 0x9ad: 0x3308, 0x9ae: 0x3308, 0x9af: 0x3308, + 0x9b0: 0x3308, 0x9b1: 0x3308, 0x9b2: 0x3308, 0x9b3: 0x3308, 0x9b4: 0x3308, 0x9b5: 0x3308, + 0x9b6: 0x3308, 0x9b7: 0x3308, 0x9b8: 0x3308, 0x9b9: 0x0df1, 0x9ba: 0x3308, 0x9bb: 0x3308, + 0x9bc: 0x3308, 0x9bd: 0x0040, 0x9be: 0x0018, 0x9bf: 0x0018, + // Block 0x27, offset 0x9c0 + 0x9c0: 0x0008, 0x9c1: 0x0008, 0x9c2: 0x0008, 0x9c3: 0x0008, 0x9c4: 0x0008, 0x9c5: 0x0008, + 0x9c6: 0x0008, 0x9c7: 0x0008, 0x9c8: 0x0008, 0x9c9: 0x0008, 0x9ca: 0x0008, 0x9cb: 0x0008, + 0x9cc: 0x0008, 0x9cd: 0x0008, 0x9ce: 0x0008, 0x9cf: 0x0008, 0x9d0: 0x0008, 0x9d1: 0x0008, + 0x9d2: 0x0008, 0x9d3: 0x0008, 0x9d4: 0x0008, 0x9d5: 0x0008, 0x9d6: 0x0008, 0x9d7: 0x0008, + 0x9d8: 0x0008, 0x9d9: 0x0008, 0x9da: 0x0008, 0x9db: 0x0008, 0x9dc: 0x0008, 0x9dd: 0x0008, + 0x9de: 0x0008, 0x9df: 0x0008, 0x9e0: 0x0008, 0x9e1: 0x0008, 0x9e2: 0x0008, 0x9e3: 0x0008, + 0x9e4: 0x0008, 0x9e5: 0x0008, 0x9e6: 0x0008, 0x9e7: 0x0008, 0x9e8: 0x0008, 0x9e9: 0x0008, + 0x9ea: 0x0008, 0x9eb: 0x0008, 0x9ec: 0x0039, 0x9ed: 0x0ed1, 0x9ee: 0x0ee9, 0x9ef: 0x0008, + 0x9f0: 0x0ef9, 0x9f1: 0x0f09, 0x9f2: 0x0f19, 0x9f3: 0x0f31, 0x9f4: 0x0249, 0x9f5: 0x0f41, + 0x9f6: 0x0259, 0x9f7: 0x0f51, 0x9f8: 0x0359, 0x9f9: 0x0f61, 0x9fa: 0x0f71, 0x9fb: 0x0008, + 0x9fc: 0x00d9, 0x9fd: 0x0f81, 0x9fe: 0x0f99, 0x9ff: 0x0269, + // Block 0x28, offset 0xa00 + 0xa00: 0x0fa9, 0xa01: 0x0fb9, 0xa02: 0x0279, 0xa03: 0x0039, 0xa04: 0x0fc9, 0xa05: 0x0fe1, + 0xa06: 0x059d, 0xa07: 0x0ee9, 0xa08: 0x0ef9, 0xa09: 0x0f09, 0xa0a: 0x0ff9, 0xa0b: 0x1011, + 0xa0c: 0x1029, 0xa0d: 0x0f31, 0xa0e: 0x0008, 0xa0f: 0x0f51, 0xa10: 0x0f61, 0xa11: 0x1041, + 0xa12: 0x00d9, 0xa13: 0x1059, 0xa14: 0x05b5, 0xa15: 0x05b5, 0xa16: 0x0f99, 0xa17: 0x0fa9, + 0xa18: 0x0fb9, 0xa19: 0x059d, 0xa1a: 0x1071, 0xa1b: 0x1089, 0xa1c: 0x05cd, 0xa1d: 0x1099, + 0xa1e: 0x10b1, 0xa1f: 0x10c9, 0xa20: 0x10e1, 0xa21: 0x10f9, 0xa22: 0x0f41, 0xa23: 0x0269, + 0xa24: 0x0fb9, 0xa25: 0x1089, 0xa26: 0x1099, 0xa27: 0x10b1, 0xa28: 0x1111, 0xa29: 0x10e1, + 0xa2a: 0x10f9, 0xa2b: 0x0008, 0xa2c: 0x0008, 0xa2d: 0x0008, 0xa2e: 0x0008, 0xa2f: 0x0008, + 0xa30: 0x0008, 0xa31: 0x0008, 0xa32: 0x0008, 0xa33: 0x0008, 0xa34: 0x0008, 0xa35: 0x0008, + 0xa36: 0x0008, 0xa37: 0x0008, 0xa38: 0x1129, 0xa39: 0x0008, 0xa3a: 0x0008, 0xa3b: 0x0008, + 0xa3c: 0x0008, 0xa3d: 0x0008, 0xa3e: 0x0008, 0xa3f: 0x0008, + // Block 0x29, offset 0xa40 + 0xa40: 0x0008, 0xa41: 0x0008, 0xa42: 0x0008, 0xa43: 0x0008, 0xa44: 0x0008, 0xa45: 0x0008, + 0xa46: 0x0008, 0xa47: 0x0008, 0xa48: 0x0008, 0xa49: 0x0008, 0xa4a: 0x0008, 0xa4b: 0x0008, + 0xa4c: 0x0008, 0xa4d: 0x0008, 0xa4e: 0x0008, 0xa4f: 0x0008, 0xa50: 0x0008, 0xa51: 0x0008, + 0xa52: 0x0008, 0xa53: 0x0008, 0xa54: 0x0008, 0xa55: 0x0008, 0xa56: 0x0008, 0xa57: 0x0008, + 0xa58: 0x0008, 0xa59: 0x0008, 0xa5a: 0x0008, 0xa5b: 0x1141, 0xa5c: 0x1159, 0xa5d: 0x1169, + 0xa5e: 0x1181, 0xa5f: 0x1029, 0xa60: 0x1199, 0xa61: 0x11a9, 0xa62: 0x11c1, 0xa63: 0x11d9, + 0xa64: 0x11f1, 0xa65: 0x1209, 0xa66: 0x1221, 0xa67: 0x05e5, 0xa68: 0x1239, 0xa69: 0x1251, + 0xa6a: 0xe17d, 0xa6b: 0x1269, 0xa6c: 0x1281, 0xa6d: 0x1299, 0xa6e: 0x12b1, 0xa6f: 0x12c9, + 0xa70: 0x12e1, 0xa71: 0x12f9, 0xa72: 0x1311, 0xa73: 0x1329, 0xa74: 0x1341, 0xa75: 0x1359, + 0xa76: 0x1371, 0xa77: 0x1389, 0xa78: 0x05fd, 0xa79: 0x13a1, 0xa7a: 0x13b9, 0xa7b: 0x13d1, + 0xa7c: 0x13e1, 0xa7d: 0x13f9, 0xa7e: 0x1411, 0xa7f: 0x1429, + // Block 0x2a, offset 0xa80 + 0xa80: 0xe00d, 0xa81: 0x0008, 0xa82: 0xe00d, 0xa83: 0x0008, 0xa84: 0xe00d, 0xa85: 0x0008, + 0xa86: 0xe00d, 0xa87: 0x0008, 0xa88: 0xe00d, 0xa89: 0x0008, 0xa8a: 0xe00d, 0xa8b: 0x0008, + 0xa8c: 0xe00d, 0xa8d: 0x0008, 0xa8e: 0xe00d, 0xa8f: 0x0008, 0xa90: 0xe00d, 0xa91: 0x0008, + 0xa92: 0xe00d, 0xa93: 0x0008, 0xa94: 0xe00d, 0xa95: 0x0008, 0xa96: 0xe00d, 0xa97: 0x0008, + 0xa98: 0xe00d, 0xa99: 0x0008, 0xa9a: 0xe00d, 0xa9b: 0x0008, 0xa9c: 0xe00d, 0xa9d: 0x0008, + 0xa9e: 0xe00d, 0xa9f: 0x0008, 0xaa0: 0xe00d, 0xaa1: 0x0008, 0xaa2: 0xe00d, 0xaa3: 0x0008, + 0xaa4: 0xe00d, 0xaa5: 0x0008, 0xaa6: 0xe00d, 0xaa7: 0x0008, 0xaa8: 0xe00d, 0xaa9: 0x0008, + 0xaaa: 0xe00d, 0xaab: 0x0008, 0xaac: 0xe00d, 0xaad: 0x0008, 0xaae: 0xe00d, 0xaaf: 0x0008, + 0xab0: 0xe00d, 0xab1: 0x0008, 0xab2: 0xe00d, 0xab3: 0x0008, 0xab4: 0xe00d, 0xab5: 0x0008, + 0xab6: 0xe00d, 0xab7: 0x0008, 0xab8: 0xe00d, 0xab9: 0x0008, 0xaba: 0xe00d, 0xabb: 0x0008, + 0xabc: 0xe00d, 0xabd: 0x0008, 0xabe: 0xe00d, 0xabf: 0x0008, + // Block 0x2b, offset 0xac0 + 0xac0: 0xe00d, 0xac1: 0x0008, 0xac2: 0xe00d, 0xac3: 0x0008, 0xac4: 0xe00d, 0xac5: 0x0008, + 0xac6: 0xe00d, 0xac7: 0x0008, 0xac8: 0xe00d, 0xac9: 0x0008, 0xaca: 0xe00d, 0xacb: 0x0008, + 0xacc: 0xe00d, 0xacd: 0x0008, 0xace: 0xe00d, 0xacf: 0x0008, 0xad0: 0xe00d, 0xad1: 0x0008, + 0xad2: 0xe00d, 0xad3: 0x0008, 0xad4: 0xe00d, 0xad5: 0x0008, 0xad6: 0x0008, 0xad7: 0x0008, + 0xad8: 0x0008, 0xad9: 0x0008, 0xada: 0x0615, 0xadb: 0x0635, 0xadc: 0x0008, 0xadd: 0x0008, + 0xade: 0x1441, 0xadf: 0x0008, 0xae0: 0xe00d, 0xae1: 0x0008, 0xae2: 0xe00d, 0xae3: 0x0008, + 0xae4: 0xe00d, 0xae5: 0x0008, 0xae6: 0xe00d, 0xae7: 0x0008, 0xae8: 0xe00d, 0xae9: 0x0008, + 0xaea: 0xe00d, 0xaeb: 0x0008, 0xaec: 0xe00d, 0xaed: 0x0008, 0xaee: 0xe00d, 0xaef: 0x0008, + 0xaf0: 0xe00d, 0xaf1: 0x0008, 0xaf2: 0xe00d, 0xaf3: 0x0008, 0xaf4: 0xe00d, 0xaf5: 0x0008, + 0xaf6: 0xe00d, 0xaf7: 0x0008, 0xaf8: 0xe00d, 0xaf9: 0x0008, 0xafa: 0xe00d, 0xafb: 0x0008, + 0xafc: 0xe00d, 0xafd: 0x0008, 0xafe: 0xe00d, 0xaff: 0x0008, + // Block 0x2c, offset 0xb00 + 0xb00: 0x0008, 0xb01: 0x0008, 0xb02: 0x0008, 0xb03: 0x0008, 0xb04: 0x0008, 0xb05: 0x0008, + 0xb06: 0x0040, 0xb07: 0x0040, 0xb08: 0xe045, 0xb09: 0xe045, 0xb0a: 0xe045, 0xb0b: 0xe045, + 0xb0c: 0xe045, 0xb0d: 0xe045, 0xb0e: 0x0040, 0xb0f: 0x0040, 0xb10: 0x0008, 0xb11: 0x0008, + 0xb12: 0x0008, 0xb13: 0x0008, 0xb14: 0x0008, 0xb15: 0x0008, 0xb16: 0x0008, 0xb17: 0x0008, + 0xb18: 0x0040, 0xb19: 0xe045, 0xb1a: 0x0040, 0xb1b: 0xe045, 0xb1c: 0x0040, 0xb1d: 0xe045, + 0xb1e: 0x0040, 0xb1f: 0xe045, 0xb20: 0x0008, 0xb21: 0x0008, 0xb22: 0x0008, 0xb23: 0x0008, + 0xb24: 0x0008, 0xb25: 0x0008, 0xb26: 0x0008, 0xb27: 0x0008, 0xb28: 0xe045, 0xb29: 0xe045, + 0xb2a: 0xe045, 0xb2b: 0xe045, 0xb2c: 0xe045, 0xb2d: 0xe045, 0xb2e: 0xe045, 0xb2f: 0xe045, + 0xb30: 0x0008, 0xb31: 0x1459, 0xb32: 0x0008, 0xb33: 0x1471, 0xb34: 0x0008, 0xb35: 0x1489, + 0xb36: 0x0008, 0xb37: 0x14a1, 0xb38: 0x0008, 0xb39: 0x14b9, 0xb3a: 0x0008, 0xb3b: 0x14d1, + 0xb3c: 0x0008, 0xb3d: 0x14e9, 0xb3e: 0x0040, 0xb3f: 0x0040, + // Block 0x2d, offset 0xb40 + 0xb40: 0x1501, 0xb41: 0x1531, 0xb42: 0x1561, 0xb43: 0x1591, 0xb44: 0x15c1, 0xb45: 0x15f1, + 0xb46: 0x1621, 0xb47: 0x1651, 0xb48: 0x1501, 0xb49: 0x1531, 0xb4a: 0x1561, 0xb4b: 0x1591, + 0xb4c: 0x15c1, 0xb4d: 0x15f1, 0xb4e: 0x1621, 0xb4f: 0x1651, 0xb50: 0x1681, 0xb51: 0x16b1, + 0xb52: 0x16e1, 0xb53: 0x1711, 0xb54: 0x1741, 0xb55: 0x1771, 0xb56: 0x17a1, 0xb57: 0x17d1, + 0xb58: 0x1681, 0xb59: 0x16b1, 0xb5a: 0x16e1, 0xb5b: 0x1711, 0xb5c: 0x1741, 0xb5d: 0x1771, + 0xb5e: 0x17a1, 0xb5f: 0x17d1, 0xb60: 0x1801, 0xb61: 0x1831, 0xb62: 0x1861, 0xb63: 0x1891, + 0xb64: 0x18c1, 0xb65: 0x18f1, 0xb66: 0x1921, 0xb67: 0x1951, 0xb68: 0x1801, 0xb69: 0x1831, + 0xb6a: 0x1861, 0xb6b: 0x1891, 0xb6c: 0x18c1, 0xb6d: 0x18f1, 0xb6e: 0x1921, 0xb6f: 0x1951, + 0xb70: 0x0008, 0xb71: 0x0008, 0xb72: 0x1981, 0xb73: 0x19b1, 0xb74: 0x19d9, 0xb75: 0x0040, + 0xb76: 0x0008, 0xb77: 0x1a01, 0xb78: 0xe045, 0xb79: 0xe045, 0xb7a: 0x064d, 0xb7b: 0x1459, + 0xb7c: 0x19b1, 0xb7d: 0x0666, 0xb7e: 0x1a31, 0xb7f: 0x0686, + // Block 0x2e, offset 0xb80 + 0xb80: 0x06a6, 0xb81: 0x1a4a, 0xb82: 0x1a79, 0xb83: 0x1aa9, 0xb84: 0x1ad1, 0xb85: 0x0040, + 0xb86: 0x0008, 0xb87: 0x1af9, 0xb88: 0x06c5, 0xb89: 0x1471, 0xb8a: 0x06dd, 0xb8b: 0x1489, + 0xb8c: 0x1aa9, 0xb8d: 0x1b2a, 0xb8e: 0x1b5a, 0xb8f: 0x1b8a, 0xb90: 0x0008, 0xb91: 0x0008, + 0xb92: 0x0008, 0xb93: 0x1bb9, 0xb94: 0x0040, 0xb95: 0x0040, 0xb96: 0x0008, 0xb97: 0x0008, + 0xb98: 0xe045, 0xb99: 0xe045, 0xb9a: 0x06f5, 0xb9b: 0x14a1, 0xb9c: 0x0040, 0xb9d: 0x1bd2, + 0xb9e: 0x1c02, 0xb9f: 0x1c32, 0xba0: 0x0008, 0xba1: 0x0008, 0xba2: 0x0008, 0xba3: 0x1c61, + 0xba4: 0x0008, 0xba5: 0x0008, 0xba6: 0x0008, 0xba7: 0x0008, 0xba8: 0xe045, 0xba9: 0xe045, + 0xbaa: 0x070d, 0xbab: 0x14d1, 0xbac: 0xe04d, 0xbad: 0x1c7a, 0xbae: 0x03d2, 0xbaf: 0x1caa, + 0xbb0: 0x0040, 0xbb1: 0x0040, 0xbb2: 0x1cb9, 0xbb3: 0x1ce9, 0xbb4: 0x1d11, 0xbb5: 0x0040, + 0xbb6: 0x0008, 0xbb7: 0x1d39, 0xbb8: 0x0725, 0xbb9: 0x14b9, 0xbba: 0x0515, 0xbbb: 0x14e9, + 0xbbc: 0x1ce9, 0xbbd: 0x073e, 0xbbe: 0x075e, 0xbbf: 0x0040, + // Block 0x2f, offset 0xbc0 + 0xbc0: 0x000a, 0xbc1: 0x000a, 0xbc2: 0x000a, 0xbc3: 0x000a, 0xbc4: 0x000a, 0xbc5: 0x000a, + 0xbc6: 0x000a, 0xbc7: 0x000a, 0xbc8: 0x000a, 0xbc9: 0x000a, 0xbca: 0x000a, 0xbcb: 0x03c0, + 0xbcc: 0x0003, 0xbcd: 0x0003, 0xbce: 0x0340, 0xbcf: 0x0b40, 0xbd0: 0x0018, 0xbd1: 0xe00d, + 0xbd2: 0x0018, 0xbd3: 0x0018, 0xbd4: 0x0018, 0xbd5: 0x0018, 0xbd6: 0x0018, 0xbd7: 0x077e, + 0xbd8: 0x0018, 0xbd9: 0x0018, 0xbda: 0x0018, 0xbdb: 0x0018, 0xbdc: 0x0018, 0xbdd: 0x0018, + 0xbde: 0x0018, 0xbdf: 0x0018, 0xbe0: 0x0018, 0xbe1: 0x0018, 0xbe2: 0x0018, 0xbe3: 0x0018, + 0xbe4: 0x0040, 0xbe5: 0x0040, 0xbe6: 0x0040, 0xbe7: 0x0018, 0xbe8: 0x0040, 0xbe9: 0x0040, + 0xbea: 0x0340, 0xbeb: 0x0340, 0xbec: 0x0340, 0xbed: 0x0340, 0xbee: 0x0340, 0xbef: 0x000a, + 0xbf0: 0x0018, 0xbf1: 0x0018, 0xbf2: 0x0018, 0xbf3: 0x1d69, 0xbf4: 0x1da1, 0xbf5: 0x0018, + 0xbf6: 0x1df1, 0xbf7: 0x1e29, 0xbf8: 0x0018, 0xbf9: 0x0018, 0xbfa: 0x0018, 0xbfb: 0x0018, + 0xbfc: 0x1e7a, 0xbfd: 0x0018, 0xbfe: 0x079e, 0xbff: 0x0018, + // Block 0x30, offset 0xc00 + 0xc00: 0x0018, 0xc01: 0x0018, 0xc02: 0x0018, 0xc03: 0x0018, 0xc04: 0x0018, 0xc05: 0x0018, + 0xc06: 0x0018, 0xc07: 0x1e92, 0xc08: 0x1eaa, 0xc09: 0x1ec2, 0xc0a: 0x0018, 0xc0b: 0x0018, + 0xc0c: 0x0018, 0xc0d: 0x0018, 0xc0e: 0x0018, 0xc0f: 0x0018, 0xc10: 0x0018, 0xc11: 0x0018, + 0xc12: 0x0018, 0xc13: 0x0018, 0xc14: 0x0018, 0xc15: 0x0018, 0xc16: 0x0018, 0xc17: 0x1ed9, + 0xc18: 0x0018, 0xc19: 0x0018, 0xc1a: 0x0018, 0xc1b: 0x0018, 0xc1c: 0x0018, 0xc1d: 0x0018, + 0xc1e: 0x0018, 0xc1f: 0x000a, 0xc20: 0x03c0, 0xc21: 0x0340, 0xc22: 0x0340, 0xc23: 0x0340, + 0xc24: 0x03c0, 0xc25: 0x0040, 0xc26: 0x0040, 0xc27: 0x0040, 0xc28: 0x0040, 0xc29: 0x0040, + 0xc2a: 0x0340, 0xc2b: 0x0340, 0xc2c: 0x0340, 0xc2d: 0x0340, 0xc2e: 0x0340, 0xc2f: 0x0340, + 0xc30: 0x1f41, 0xc31: 0x0f41, 0xc32: 0x0040, 0xc33: 0x0040, 0xc34: 0x1f51, 0xc35: 0x1f61, + 0xc36: 0x1f71, 0xc37: 0x1f81, 0xc38: 0x1f91, 0xc39: 0x1fa1, 0xc3a: 0x1fb2, 0xc3b: 0x07bd, + 0xc3c: 0x1fc2, 0xc3d: 0x1fd2, 0xc3e: 0x1fe2, 0xc3f: 0x0f71, + // Block 0x31, offset 0xc40 + 0xc40: 0x1f41, 0xc41: 0x00c9, 0xc42: 0x0069, 0xc43: 0x0079, 0xc44: 0x1f51, 0xc45: 0x1f61, + 0xc46: 0x1f71, 0xc47: 0x1f81, 0xc48: 0x1f91, 0xc49: 0x1fa1, 0xc4a: 0x1fb2, 0xc4b: 0x07d5, + 0xc4c: 0x1fc2, 0xc4d: 0x1fd2, 0xc4e: 0x1fe2, 0xc4f: 0x0040, 0xc50: 0x0039, 0xc51: 0x0f09, + 0xc52: 0x00d9, 0xc53: 0x0369, 0xc54: 0x0ff9, 0xc55: 0x0249, 0xc56: 0x0f51, 0xc57: 0x0359, + 0xc58: 0x0f61, 0xc59: 0x0f71, 0xc5a: 0x0f99, 0xc5b: 0x01d9, 0xc5c: 0x0fa9, 0xc5d: 0x0040, + 0xc5e: 0x0040, 0xc5f: 0x0040, 0xc60: 0x0018, 0xc61: 0x0018, 0xc62: 0x0018, 0xc63: 0x0018, + 0xc64: 0x0018, 0xc65: 0x0018, 0xc66: 0x0018, 0xc67: 0x0018, 0xc68: 0x1ff1, 0xc69: 0x0018, + 0xc6a: 0x0018, 0xc6b: 0x0018, 0xc6c: 0x0018, 0xc6d: 0x0018, 0xc6e: 0x0018, 0xc6f: 0x0018, + 0xc70: 0x0018, 0xc71: 0x0018, 0xc72: 0x0018, 0xc73: 0x0018, 0xc74: 0x0018, 0xc75: 0x0018, + 0xc76: 0x0018, 0xc77: 0x0018, 0xc78: 0x0018, 0xc79: 0x0018, 0xc7a: 0x0018, 0xc7b: 0x0018, + 0xc7c: 0x0018, 0xc7d: 0x0018, 0xc7e: 0x0018, 0xc7f: 0x0018, + // Block 0x32, offset 0xc80 + 0xc80: 0x07ee, 0xc81: 0x080e, 0xc82: 0x1159, 0xc83: 0x082d, 0xc84: 0x0018, 0xc85: 0x084e, + 0xc86: 0x086e, 0xc87: 0x1011, 0xc88: 0x0018, 0xc89: 0x088d, 0xc8a: 0x0f31, 0xc8b: 0x0249, + 0xc8c: 0x0249, 0xc8d: 0x0249, 0xc8e: 0x0249, 0xc8f: 0x2009, 0xc90: 0x0f41, 0xc91: 0x0f41, + 0xc92: 0x0359, 0xc93: 0x0359, 0xc94: 0x0018, 0xc95: 0x0f71, 0xc96: 0x2021, 0xc97: 0x0018, + 0xc98: 0x0018, 0xc99: 0x0f99, 0xc9a: 0x2039, 0xc9b: 0x0269, 0xc9c: 0x0269, 0xc9d: 0x0269, + 0xc9e: 0x0018, 0xc9f: 0x0018, 0xca0: 0x2049, 0xca1: 0x08ad, 0xca2: 0x2061, 0xca3: 0x0018, + 0xca4: 0x13d1, 0xca5: 0x0018, 0xca6: 0x2079, 0xca7: 0x0018, 0xca8: 0x13d1, 0xca9: 0x0018, + 0xcaa: 0x0f51, 0xcab: 0x2091, 0xcac: 0x0ee9, 0xcad: 0x1159, 0xcae: 0x0018, 0xcaf: 0x0f09, + 0xcb0: 0x0f09, 0xcb1: 0x1199, 0xcb2: 0x0040, 0xcb3: 0x0f61, 0xcb4: 0x00d9, 0xcb5: 0x20a9, + 0xcb6: 0x20c1, 0xcb7: 0x20d9, 0xcb8: 0x20f1, 0xcb9: 0x0f41, 0xcba: 0x0018, 0xcbb: 0x08cd, + 0xcbc: 0x2109, 0xcbd: 0x10b1, 0xcbe: 0x10b1, 0xcbf: 0x2109, + // Block 0x33, offset 0xcc0 + 0xcc0: 0x08ed, 0xcc1: 0x0018, 0xcc2: 0x0018, 0xcc3: 0x0018, 0xcc4: 0x0018, 0xcc5: 0x0ef9, + 0xcc6: 0x0ef9, 0xcc7: 0x0f09, 0xcc8: 0x0f41, 0xcc9: 0x0259, 0xcca: 0x0018, 0xccb: 0x0018, + 0xccc: 0x0018, 0xccd: 0x0018, 0xcce: 0x0008, 0xccf: 0x0018, 0xcd0: 0x2121, 0xcd1: 0x2151, + 0xcd2: 0x2181, 0xcd3: 0x21b9, 0xcd4: 0x21e9, 0xcd5: 0x2219, 0xcd6: 0x2249, 0xcd7: 0x2279, + 0xcd8: 0x22a9, 0xcd9: 0x22d9, 0xcda: 0x2309, 0xcdb: 0x2339, 0xcdc: 0x2369, 0xcdd: 0x2399, + 0xcde: 0x23c9, 0xcdf: 0x23f9, 0xce0: 0x0f41, 0xce1: 0x2421, 0xce2: 0x0905, 0xce3: 0x2439, + 0xce4: 0x1089, 0xce5: 0x2451, 0xce6: 0x0925, 0xce7: 0x2469, 0xce8: 0x2491, 0xce9: 0x0369, + 0xcea: 0x24a9, 0xceb: 0x0945, 0xcec: 0x0359, 0xced: 0x1159, 0xcee: 0x0ef9, 0xcef: 0x0f61, + 0xcf0: 0x0f41, 0xcf1: 0x2421, 0xcf2: 0x0965, 0xcf3: 0x2439, 0xcf4: 0x1089, 0xcf5: 0x2451, + 0xcf6: 0x0985, 0xcf7: 0x2469, 0xcf8: 0x2491, 0xcf9: 0x0369, 0xcfa: 0x24a9, 0xcfb: 0x09a5, + 0xcfc: 0x0359, 0xcfd: 0x1159, 0xcfe: 0x0ef9, 0xcff: 0x0f61, + // Block 0x34, offset 0xd00 + 0xd00: 0x0018, 0xd01: 0x0018, 0xd02: 0x0018, 0xd03: 0x0018, 0xd04: 0x0018, 0xd05: 0x0018, + 0xd06: 0x0018, 0xd07: 0x0018, 0xd08: 0x0018, 0xd09: 0x0018, 0xd0a: 0x0018, 0xd0b: 0x0040, + 0xd0c: 0x0040, 0xd0d: 0x0040, 0xd0e: 0x0040, 0xd0f: 0x0040, 0xd10: 0x0040, 0xd11: 0x0040, + 0xd12: 0x0040, 0xd13: 0x0040, 0xd14: 0x0040, 0xd15: 0x0040, 0xd16: 0x0040, 0xd17: 0x0040, + 0xd18: 0x0040, 0xd19: 0x0040, 0xd1a: 0x0040, 0xd1b: 0x0040, 0xd1c: 0x0040, 0xd1d: 0x0040, + 0xd1e: 0x0040, 0xd1f: 0x0040, 0xd20: 0x00c9, 0xd21: 0x0069, 0xd22: 0x0079, 0xd23: 0x1f51, + 0xd24: 0x1f61, 0xd25: 0x1f71, 0xd26: 0x1f81, 0xd27: 0x1f91, 0xd28: 0x1fa1, 0xd29: 0x2601, + 0xd2a: 0x2619, 0xd2b: 0x2631, 0xd2c: 0x2649, 0xd2d: 0x2661, 0xd2e: 0x2679, 0xd2f: 0x2691, + 0xd30: 0x26a9, 0xd31: 0x26c1, 0xd32: 0x26d9, 0xd33: 0x26f1, 0xd34: 0x0a06, 0xd35: 0x0a26, + 0xd36: 0x0a46, 0xd37: 0x0a66, 0xd38: 0x0a86, 0xd39: 0x0aa6, 0xd3a: 0x0ac6, 0xd3b: 0x0ae6, + 0xd3c: 0x0b06, 0xd3d: 0x270a, 0xd3e: 0x2732, 0xd3f: 0x275a, + // Block 0x35, offset 0xd40 + 0xd40: 0x2782, 0xd41: 0x27aa, 0xd42: 0x27d2, 0xd43: 0x27fa, 0xd44: 0x2822, 0xd45: 0x284a, + 0xd46: 0x2872, 0xd47: 0x289a, 0xd48: 0x0040, 0xd49: 0x0040, 0xd4a: 0x0040, 0xd4b: 0x0040, + 0xd4c: 0x0040, 0xd4d: 0x0040, 0xd4e: 0x0040, 0xd4f: 0x0040, 0xd50: 0x0040, 0xd51: 0x0040, + 0xd52: 0x0040, 0xd53: 0x0040, 0xd54: 0x0040, 0xd55: 0x0040, 0xd56: 0x0040, 0xd57: 0x0040, + 0xd58: 0x0040, 0xd59: 0x0040, 0xd5a: 0x0040, 0xd5b: 0x0040, 0xd5c: 0x0b26, 0xd5d: 0x0b46, + 0xd5e: 0x0b66, 0xd5f: 0x0b86, 0xd60: 0x0ba6, 0xd61: 0x0bc6, 0xd62: 0x0be6, 0xd63: 0x0c06, + 0xd64: 0x0c26, 0xd65: 0x0c46, 0xd66: 0x0c66, 0xd67: 0x0c86, 0xd68: 0x0ca6, 0xd69: 0x0cc6, + 0xd6a: 0x0ce6, 0xd6b: 0x0d06, 0xd6c: 0x0d26, 0xd6d: 0x0d46, 0xd6e: 0x0d66, 0xd6f: 0x0d86, + 0xd70: 0x0da6, 0xd71: 0x0dc6, 0xd72: 0x0de6, 0xd73: 0x0e06, 0xd74: 0x0e26, 0xd75: 0x0e46, + 0xd76: 0x0039, 0xd77: 0x0ee9, 0xd78: 0x1159, 0xd79: 0x0ef9, 0xd7a: 0x0f09, 0xd7b: 0x1199, + 0xd7c: 0x0f31, 0xd7d: 0x0249, 0xd7e: 0x0f41, 0xd7f: 0x0259, + // Block 0x36, offset 0xd80 + 0xd80: 0x0f51, 0xd81: 0x0359, 0xd82: 0x0f61, 0xd83: 0x0f71, 0xd84: 0x00d9, 0xd85: 0x0f99, + 0xd86: 0x2039, 0xd87: 0x0269, 0xd88: 0x01d9, 0xd89: 0x0fa9, 0xd8a: 0x0fb9, 0xd8b: 0x1089, + 0xd8c: 0x0279, 0xd8d: 0x0369, 0xd8e: 0x0289, 0xd8f: 0x13d1, 0xd90: 0x0039, 0xd91: 0x0ee9, + 0xd92: 0x1159, 0xd93: 0x0ef9, 0xd94: 0x0f09, 0xd95: 0x1199, 0xd96: 0x0f31, 0xd97: 0x0249, + 0xd98: 0x0f41, 0xd99: 0x0259, 0xd9a: 0x0f51, 0xd9b: 0x0359, 0xd9c: 0x0f61, 0xd9d: 0x0f71, + 0xd9e: 0x00d9, 0xd9f: 0x0f99, 0xda0: 0x2039, 0xda1: 0x0269, 0xda2: 0x01d9, 0xda3: 0x0fa9, + 0xda4: 0x0fb9, 0xda5: 0x1089, 0xda6: 0x0279, 0xda7: 0x0369, 0xda8: 0x0289, 0xda9: 0x13d1, + 0xdaa: 0x1f41, 0xdab: 0x0018, 0xdac: 0x0018, 0xdad: 0x0018, 0xdae: 0x0018, 0xdaf: 0x0018, + 0xdb0: 0x0018, 0xdb1: 0x0018, 0xdb2: 0x0018, 0xdb3: 0x0018, 0xdb4: 0x0018, 0xdb5: 0x0018, + 0xdb6: 0x0018, 0xdb7: 0x0018, 0xdb8: 0x0018, 0xdb9: 0x0018, 0xdba: 0x0018, 0xdbb: 0x0018, + 0xdbc: 0x0018, 0xdbd: 0x0018, 0xdbe: 0x0018, 0xdbf: 0x0018, + // Block 0x37, offset 0xdc0 + 0xdc0: 0x0008, 0xdc1: 0x0008, 0xdc2: 0x0008, 0xdc3: 0x0008, 0xdc4: 0x0008, 0xdc5: 0x0008, + 0xdc6: 0x0008, 0xdc7: 0x0008, 0xdc8: 0x0008, 0xdc9: 0x0008, 0xdca: 0x0008, 0xdcb: 0x0008, + 0xdcc: 0x0008, 0xdcd: 0x0008, 0xdce: 0x0008, 0xdcf: 0x0008, 0xdd0: 0x0008, 0xdd1: 0x0008, + 0xdd2: 0x0008, 0xdd3: 0x0008, 0xdd4: 0x0008, 0xdd5: 0x0008, 0xdd6: 0x0008, 0xdd7: 0x0008, + 0xdd8: 0x0008, 0xdd9: 0x0008, 0xdda: 0x0008, 0xddb: 0x0008, 0xddc: 0x0008, 0xddd: 0x0008, + 0xdde: 0x0008, 0xddf: 0x0040, 0xde0: 0xe00d, 0xde1: 0x0008, 0xde2: 0x2971, 0xde3: 0x0ebd, + 0xde4: 0x2989, 0xde5: 0x0008, 0xde6: 0x0008, 0xde7: 0xe07d, 0xde8: 0x0008, 0xde9: 0xe01d, + 0xdea: 0x0008, 0xdeb: 0xe03d, 0xdec: 0x0008, 0xded: 0x0fe1, 0xdee: 0x1281, 0xdef: 0x0fc9, + 0xdf0: 0x1141, 0xdf1: 0x0008, 0xdf2: 0xe00d, 0xdf3: 0x0008, 0xdf4: 0x0008, 0xdf5: 0xe01d, + 0xdf6: 0x0008, 0xdf7: 0x0008, 0xdf8: 0x0008, 0xdf9: 0x0008, 0xdfa: 0x0008, 0xdfb: 0x0008, + 0xdfc: 0x0259, 0xdfd: 0x1089, 0xdfe: 0x29a1, 0xdff: 0x29b9, + // Block 0x38, offset 0xe00 + 0xe00: 0xe00d, 0xe01: 0x0008, 0xe02: 0xe00d, 0xe03: 0x0008, 0xe04: 0xe00d, 0xe05: 0x0008, + 0xe06: 0xe00d, 0xe07: 0x0008, 0xe08: 0xe00d, 0xe09: 0x0008, 0xe0a: 0xe00d, 0xe0b: 0x0008, + 0xe0c: 0xe00d, 0xe0d: 0x0008, 0xe0e: 0xe00d, 0xe0f: 0x0008, 0xe10: 0xe00d, 0xe11: 0x0008, + 0xe12: 0xe00d, 0xe13: 0x0008, 0xe14: 0xe00d, 0xe15: 0x0008, 0xe16: 0xe00d, 0xe17: 0x0008, + 0xe18: 0xe00d, 0xe19: 0x0008, 0xe1a: 0xe00d, 0xe1b: 0x0008, 0xe1c: 0xe00d, 0xe1d: 0x0008, + 0xe1e: 0xe00d, 0xe1f: 0x0008, 0xe20: 0xe00d, 0xe21: 0x0008, 0xe22: 0xe00d, 0xe23: 0x0008, + 0xe24: 0x0008, 0xe25: 0x0018, 0xe26: 0x0018, 0xe27: 0x0018, 0xe28: 0x0018, 0xe29: 0x0018, + 0xe2a: 0x0018, 0xe2b: 0xe03d, 0xe2c: 0x0008, 0xe2d: 0xe01d, 0xe2e: 0x0008, 0xe2f: 0x3308, + 0xe30: 0x3308, 0xe31: 0x3308, 0xe32: 0xe00d, 0xe33: 0x0008, 0xe34: 0x0040, 0xe35: 0x0040, + 0xe36: 0x0040, 0xe37: 0x0040, 0xe38: 0x0040, 0xe39: 0x0018, 0xe3a: 0x0018, 0xe3b: 0x0018, + 0xe3c: 0x0018, 0xe3d: 0x0018, 0xe3e: 0x0018, 0xe3f: 0x0018, + // Block 0x39, offset 0xe40 + 0xe40: 0x26fd, 0xe41: 0x271d, 0xe42: 0x273d, 0xe43: 0x275d, 0xe44: 0x277d, 0xe45: 0x279d, + 0xe46: 0x27bd, 0xe47: 0x27dd, 0xe48: 0x27fd, 0xe49: 0x281d, 0xe4a: 0x283d, 0xe4b: 0x285d, + 0xe4c: 0x287d, 0xe4d: 0x289d, 0xe4e: 0x28bd, 0xe4f: 0x28dd, 0xe50: 0x28fd, 0xe51: 0x291d, + 0xe52: 0x293d, 0xe53: 0x295d, 0xe54: 0x297d, 0xe55: 0x299d, 0xe56: 0x0040, 0xe57: 0x0040, + 0xe58: 0x0040, 0xe59: 0x0040, 0xe5a: 0x0040, 0xe5b: 0x0040, 0xe5c: 0x0040, 0xe5d: 0x0040, + 0xe5e: 0x0040, 0xe5f: 0x0040, 0xe60: 0x0040, 0xe61: 0x0040, 0xe62: 0x0040, 0xe63: 0x0040, + 0xe64: 0x0040, 0xe65: 0x0040, 0xe66: 0x0040, 0xe67: 0x0040, 0xe68: 0x0040, 0xe69: 0x0040, + 0xe6a: 0x0040, 0xe6b: 0x0040, 0xe6c: 0x0040, 0xe6d: 0x0040, 0xe6e: 0x0040, 0xe6f: 0x0040, + 0xe70: 0x0040, 0xe71: 0x0040, 0xe72: 0x0040, 0xe73: 0x0040, 0xe74: 0x0040, 0xe75: 0x0040, + 0xe76: 0x0040, 0xe77: 0x0040, 0xe78: 0x0040, 0xe79: 0x0040, 0xe7a: 0x0040, 0xe7b: 0x0040, + 0xe7c: 0x0040, 0xe7d: 0x0040, 0xe7e: 0x0040, 0xe7f: 0x0040, + // Block 0x3a, offset 0xe80 + 0xe80: 0x000a, 0xe81: 0x0018, 0xe82: 0x29d1, 0xe83: 0x0018, 0xe84: 0x0018, 0xe85: 0x0008, + 0xe86: 0x0008, 0xe87: 0x0008, 0xe88: 0x0018, 0xe89: 0x0018, 0xe8a: 0x0018, 0xe8b: 0x0018, + 0xe8c: 0x0018, 0xe8d: 0x0018, 0xe8e: 0x0018, 0xe8f: 0x0018, 0xe90: 0x0018, 0xe91: 0x0018, + 0xe92: 0x0018, 0xe93: 0x0018, 0xe94: 0x0018, 0xe95: 0x0018, 0xe96: 0x0018, 0xe97: 0x0018, + 0xe98: 0x0018, 0xe99: 0x0018, 0xe9a: 0x0018, 0xe9b: 0x0018, 0xe9c: 0x0018, 0xe9d: 0x0018, + 0xe9e: 0x0018, 0xe9f: 0x0018, 0xea0: 0x0018, 0xea1: 0x0018, 0xea2: 0x0018, 0xea3: 0x0018, + 0xea4: 0x0018, 0xea5: 0x0018, 0xea6: 0x0018, 0xea7: 0x0018, 0xea8: 0x0018, 0xea9: 0x0018, + 0xeaa: 0x3308, 0xeab: 0x3308, 0xeac: 0x3308, 0xead: 0x3308, 0xeae: 0x3018, 0xeaf: 0x3018, + 0xeb0: 0x0018, 0xeb1: 0x0018, 0xeb2: 0x0018, 0xeb3: 0x0018, 0xeb4: 0x0018, 0xeb5: 0x0018, + 0xeb6: 0xe125, 0xeb7: 0x0018, 0xeb8: 0x29bd, 0xeb9: 0x29dd, 0xeba: 0x29fd, 0xebb: 0x0018, + 0xebc: 0x0008, 0xebd: 0x0018, 0xebe: 0x0018, 0xebf: 0x0018, + // Block 0x3b, offset 0xec0 + 0xec0: 0x2b3d, 0xec1: 0x2b5d, 0xec2: 0x2b7d, 0xec3: 0x2b9d, 0xec4: 0x2bbd, 0xec5: 0x2bdd, + 0xec6: 0x2bdd, 0xec7: 0x2bdd, 0xec8: 0x2bfd, 0xec9: 0x2bfd, 0xeca: 0x2bfd, 0xecb: 0x2bfd, + 0xecc: 0x2c1d, 0xecd: 0x2c1d, 0xece: 0x2c1d, 0xecf: 0x2c3d, 0xed0: 0x2c5d, 0xed1: 0x2c5d, + 0xed2: 0x2a7d, 0xed3: 0x2a7d, 0xed4: 0x2c5d, 0xed5: 0x2c5d, 0xed6: 0x2c7d, 0xed7: 0x2c7d, + 0xed8: 0x2c5d, 0xed9: 0x2c5d, 0xeda: 0x2a7d, 0xedb: 0x2a7d, 0xedc: 0x2c5d, 0xedd: 0x2c5d, + 0xede: 0x2c3d, 0xedf: 0x2c3d, 0xee0: 0x2c9d, 0xee1: 0x2c9d, 0xee2: 0x2cbd, 0xee3: 0x2cbd, + 0xee4: 0x0040, 0xee5: 0x2cdd, 0xee6: 0x2cfd, 0xee7: 0x2d1d, 0xee8: 0x2d1d, 0xee9: 0x2d3d, + 0xeea: 0x2d5d, 0xeeb: 0x2d7d, 0xeec: 0x2d9d, 0xeed: 0x2dbd, 0xeee: 0x2ddd, 0xeef: 0x2dfd, + 0xef0: 0x2e1d, 0xef1: 0x2e3d, 0xef2: 0x2e3d, 0xef3: 0x2e5d, 0xef4: 0x2e7d, 0xef5: 0x2e7d, + 0xef6: 0x2e9d, 0xef7: 0x2ebd, 0xef8: 0x2e5d, 0xef9: 0x2edd, 0xefa: 0x2efd, 0xefb: 0x2edd, + 0xefc: 0x2e5d, 0xefd: 0x2f1d, 0xefe: 0x2f3d, 0xeff: 0x2f5d, + // Block 0x3c, offset 0xf00 + 0xf00: 0x2f7d, 0xf01: 0x2f9d, 0xf02: 0x2cfd, 0xf03: 0x2cdd, 0xf04: 0x2fbd, 0xf05: 0x2fdd, + 0xf06: 0x2ffd, 0xf07: 0x301d, 0xf08: 0x303d, 0xf09: 0x305d, 0xf0a: 0x307d, 0xf0b: 0x309d, + 0xf0c: 0x30bd, 0xf0d: 0x30dd, 0xf0e: 0x30fd, 0xf0f: 0x0040, 0xf10: 0x0018, 0xf11: 0x0018, + 0xf12: 0x311d, 0xf13: 0x313d, 0xf14: 0x315d, 0xf15: 0x317d, 0xf16: 0x319d, 0xf17: 0x31bd, + 0xf18: 0x31dd, 0xf19: 0x31fd, 0xf1a: 0x321d, 0xf1b: 0x323d, 0xf1c: 0x315d, 0xf1d: 0x325d, + 0xf1e: 0x327d, 0xf1f: 0x329d, 0xf20: 0x0008, 0xf21: 0x0008, 0xf22: 0x0008, 0xf23: 0x0008, + 0xf24: 0x0008, 0xf25: 0x0008, 0xf26: 0x0008, 0xf27: 0x0008, 0xf28: 0x0008, 0xf29: 0x0008, + 0xf2a: 0x0008, 0xf2b: 0x0008, 0xf2c: 0x0008, 0xf2d: 0x0008, 0xf2e: 0x0008, 0xf2f: 0x0008, + 0xf30: 0x0008, 0xf31: 0x0008, 0xf32: 0x0008, 0xf33: 0x0008, 0xf34: 0x0008, 0xf35: 0x0008, + 0xf36: 0x0008, 0xf37: 0x0008, 0xf38: 0x0008, 0xf39: 0x0008, 0xf3a: 0x0008, 0xf3b: 0x0040, + 0xf3c: 0x0040, 0xf3d: 0x0040, 0xf3e: 0x0040, 0xf3f: 0x0040, + // Block 0x3d, offset 0xf40 + 0xf40: 0x36a2, 0xf41: 0x36d2, 0xf42: 0x3702, 0xf43: 0x3732, 0xf44: 0x32bd, 0xf45: 0x32dd, + 0xf46: 0x32fd, 0xf47: 0x331d, 0xf48: 0x0018, 0xf49: 0x0018, 0xf4a: 0x0018, 0xf4b: 0x0018, + 0xf4c: 0x0018, 0xf4d: 0x0018, 0xf4e: 0x0018, 0xf4f: 0x0018, 0xf50: 0x333d, 0xf51: 0x3761, + 0xf52: 0x3779, 0xf53: 0x3791, 0xf54: 0x37a9, 0xf55: 0x37c1, 0xf56: 0x37d9, 0xf57: 0x37f1, + 0xf58: 0x3809, 0xf59: 0x3821, 0xf5a: 0x3839, 0xf5b: 0x3851, 0xf5c: 0x3869, 0xf5d: 0x3881, + 0xf5e: 0x3899, 0xf5f: 0x38b1, 0xf60: 0x335d, 0xf61: 0x337d, 0xf62: 0x339d, 0xf63: 0x33bd, + 0xf64: 0x33dd, 0xf65: 0x33dd, 0xf66: 0x33fd, 0xf67: 0x341d, 0xf68: 0x343d, 0xf69: 0x345d, + 0xf6a: 0x347d, 0xf6b: 0x349d, 0xf6c: 0x34bd, 0xf6d: 0x34dd, 0xf6e: 0x34fd, 0xf6f: 0x351d, + 0xf70: 0x353d, 0xf71: 0x355d, 0xf72: 0x357d, 0xf73: 0x359d, 0xf74: 0x35bd, 0xf75: 0x35dd, + 0xf76: 0x35fd, 0xf77: 0x361d, 0xf78: 0x363d, 0xf79: 0x365d, 0xf7a: 0x367d, 0xf7b: 0x369d, + 0xf7c: 0x38c9, 0xf7d: 0x3901, 0xf7e: 0x36bd, 0xf7f: 0x0018, + // Block 0x3e, offset 0xf80 + 0xf80: 0x36dd, 0xf81: 0x36fd, 0xf82: 0x371d, 0xf83: 0x373d, 0xf84: 0x375d, 0xf85: 0x377d, + 0xf86: 0x379d, 0xf87: 0x37bd, 0xf88: 0x37dd, 0xf89: 0x37fd, 0xf8a: 0x381d, 0xf8b: 0x383d, + 0xf8c: 0x385d, 0xf8d: 0x387d, 0xf8e: 0x389d, 0xf8f: 0x38bd, 0xf90: 0x38dd, 0xf91: 0x38fd, + 0xf92: 0x391d, 0xf93: 0x393d, 0xf94: 0x395d, 0xf95: 0x397d, 0xf96: 0x399d, 0xf97: 0x39bd, + 0xf98: 0x39dd, 0xf99: 0x39fd, 0xf9a: 0x3a1d, 0xf9b: 0x3a3d, 0xf9c: 0x3a5d, 0xf9d: 0x3a7d, + 0xf9e: 0x3a9d, 0xf9f: 0x3abd, 0xfa0: 0x3add, 0xfa1: 0x3afd, 0xfa2: 0x3b1d, 0xfa3: 0x3b3d, + 0xfa4: 0x3b5d, 0xfa5: 0x3b7d, 0xfa6: 0x127d, 0xfa7: 0x3b9d, 0xfa8: 0x3bbd, 0xfa9: 0x3bdd, + 0xfaa: 0x3bfd, 0xfab: 0x3c1d, 0xfac: 0x3c3d, 0xfad: 0x3c5d, 0xfae: 0x239d, 0xfaf: 0x3c7d, + 0xfb0: 0x3c9d, 0xfb1: 0x3939, 0xfb2: 0x3951, 0xfb3: 0x3969, 0xfb4: 0x3981, 0xfb5: 0x3999, + 0xfb6: 0x39b1, 0xfb7: 0x39c9, 0xfb8: 0x39e1, 0xfb9: 0x39f9, 0xfba: 0x3a11, 0xfbb: 0x3a29, + 0xfbc: 0x3a41, 0xfbd: 0x3a59, 0xfbe: 0x3a71, 0xfbf: 0x3a89, + // Block 0x3f, offset 0xfc0 + 0xfc0: 0x3aa1, 0xfc1: 0x3ac9, 0xfc2: 0x3af1, 0xfc3: 0x3b19, 0xfc4: 0x3b41, 0xfc5: 0x3b69, + 0xfc6: 0x3b91, 0xfc7: 0x3bb9, 0xfc8: 0x3be1, 0xfc9: 0x3c09, 0xfca: 0x3c39, 0xfcb: 0x3c69, + 0xfcc: 0x3c99, 0xfcd: 0x3cbd, 0xfce: 0x3cb1, 0xfcf: 0x3cdd, 0xfd0: 0x3cfd, 0xfd1: 0x3d15, + 0xfd2: 0x3d2d, 0xfd3: 0x3d45, 0xfd4: 0x3d5d, 0xfd5: 0x3d5d, 0xfd6: 0x3d45, 0xfd7: 0x3d75, + 0xfd8: 0x07bd, 0xfd9: 0x3d8d, 0xfda: 0x3da5, 0xfdb: 0x3dbd, 0xfdc: 0x3dd5, 0xfdd: 0x3ded, + 0xfde: 0x3e05, 0xfdf: 0x3e1d, 0xfe0: 0x3e35, 0xfe1: 0x3e4d, 0xfe2: 0x3e65, 0xfe3: 0x3e7d, + 0xfe4: 0x3e95, 0xfe5: 0x3e95, 0xfe6: 0x3ead, 0xfe7: 0x3ead, 0xfe8: 0x3ec5, 0xfe9: 0x3ec5, + 0xfea: 0x3edd, 0xfeb: 0x3ef5, 0xfec: 0x3f0d, 0xfed: 0x3f25, 0xfee: 0x3f3d, 0xfef: 0x3f3d, + 0xff0: 0x3f55, 0xff1: 0x3f55, 0xff2: 0x3f55, 0xff3: 0x3f6d, 0xff4: 0x3f85, 0xff5: 0x3f9d, + 0xff6: 0x3fb5, 0xff7: 0x3f9d, 0xff8: 0x3fcd, 0xff9: 0x3fe5, 0xffa: 0x3f6d, 0xffb: 0x3ffd, + 0xffc: 0x4015, 0xffd: 0x4015, 0xffe: 0x4015, 0xfff: 0x0040, + // Block 0x40, offset 0x1000 + 0x1000: 0x3cc9, 0x1001: 0x3d31, 0x1002: 0x3d99, 0x1003: 0x3e01, 0x1004: 0x3e51, 0x1005: 0x3eb9, + 0x1006: 0x3f09, 0x1007: 0x3f59, 0x1008: 0x3fd9, 0x1009: 0x4041, 0x100a: 0x4091, 0x100b: 0x40e1, + 0x100c: 0x4131, 0x100d: 0x4199, 0x100e: 0x4201, 0x100f: 0x4251, 0x1010: 0x42a1, 0x1011: 0x42d9, + 0x1012: 0x4329, 0x1013: 0x4391, 0x1014: 0x43f9, 0x1015: 0x4431, 0x1016: 0x44b1, 0x1017: 0x4549, + 0x1018: 0x45c9, 0x1019: 0x4619, 0x101a: 0x4699, 0x101b: 0x4719, 0x101c: 0x4781, 0x101d: 0x47d1, + 0x101e: 0x4821, 0x101f: 0x4871, 0x1020: 0x48d9, 0x1021: 0x4959, 0x1022: 0x49c1, 0x1023: 0x4a11, + 0x1024: 0x4a61, 0x1025: 0x4ab1, 0x1026: 0x4ae9, 0x1027: 0x4b21, 0x1028: 0x4b59, 0x1029: 0x4b91, + 0x102a: 0x4be1, 0x102b: 0x4c31, 0x102c: 0x4cb1, 0x102d: 0x4d01, 0x102e: 0x4d69, 0x102f: 0x4de9, + 0x1030: 0x4e39, 0x1031: 0x4e71, 0x1032: 0x4ea9, 0x1033: 0x4f29, 0x1034: 0x4f91, 0x1035: 0x5011, + 0x1036: 0x5061, 0x1037: 0x50e1, 0x1038: 0x5119, 0x1039: 0x5169, 0x103a: 0x51b9, 0x103b: 0x5209, + 0x103c: 0x5259, 0x103d: 0x52a9, 0x103e: 0x5311, 0x103f: 0x5361, + // Block 0x41, offset 0x1040 + 0x1040: 0x5399, 0x1041: 0x53e9, 0x1042: 0x5439, 0x1043: 0x5489, 0x1044: 0x54f1, 0x1045: 0x5541, + 0x1046: 0x5591, 0x1047: 0x55e1, 0x1048: 0x5661, 0x1049: 0x56c9, 0x104a: 0x5701, 0x104b: 0x5781, + 0x104c: 0x57b9, 0x104d: 0x5821, 0x104e: 0x5889, 0x104f: 0x58d9, 0x1050: 0x5929, 0x1051: 0x5979, + 0x1052: 0x59e1, 0x1053: 0x5a19, 0x1054: 0x5a69, 0x1055: 0x5ad1, 0x1056: 0x5b09, 0x1057: 0x5b89, + 0x1058: 0x5bd9, 0x1059: 0x5c01, 0x105a: 0x5c29, 0x105b: 0x5c51, 0x105c: 0x5c79, 0x105d: 0x5ca1, + 0x105e: 0x5cc9, 0x105f: 0x5cf1, 0x1060: 0x5d19, 0x1061: 0x5d41, 0x1062: 0x5d69, 0x1063: 0x5d99, + 0x1064: 0x5dc9, 0x1065: 0x5df9, 0x1066: 0x5e29, 0x1067: 0x5e59, 0x1068: 0x5e89, 0x1069: 0x5eb9, + 0x106a: 0x5ee9, 0x106b: 0x5f19, 0x106c: 0x5f49, 0x106d: 0x5f79, 0x106e: 0x5fa9, 0x106f: 0x5fd9, + 0x1070: 0x6009, 0x1071: 0x402d, 0x1072: 0x6039, 0x1073: 0x6051, 0x1074: 0x404d, 0x1075: 0x6069, + 0x1076: 0x6081, 0x1077: 0x6099, 0x1078: 0x406d, 0x1079: 0x406d, 0x107a: 0x60b1, 0x107b: 0x60c9, + 0x107c: 0x6101, 0x107d: 0x6139, 0x107e: 0x6171, 0x107f: 0x61a9, + // Block 0x42, offset 0x1080 + 0x1080: 0x6211, 0x1081: 0x6229, 0x1082: 0x408d, 0x1083: 0x6241, 0x1084: 0x6259, 0x1085: 0x6271, + 0x1086: 0x6289, 0x1087: 0x62a1, 0x1088: 0x40ad, 0x1089: 0x62b9, 0x108a: 0x62e1, 0x108b: 0x62f9, + 0x108c: 0x40cd, 0x108d: 0x40cd, 0x108e: 0x6311, 0x108f: 0x6329, 0x1090: 0x6341, 0x1091: 0x40ed, + 0x1092: 0x410d, 0x1093: 0x412d, 0x1094: 0x414d, 0x1095: 0x416d, 0x1096: 0x6359, 0x1097: 0x6371, + 0x1098: 0x6389, 0x1099: 0x63a1, 0x109a: 0x63b9, 0x109b: 0x418d, 0x109c: 0x63d1, 0x109d: 0x63e9, + 0x109e: 0x6401, 0x109f: 0x41ad, 0x10a0: 0x41cd, 0x10a1: 0x6419, 0x10a2: 0x41ed, 0x10a3: 0x420d, + 0x10a4: 0x422d, 0x10a5: 0x6431, 0x10a6: 0x424d, 0x10a7: 0x6449, 0x10a8: 0x6479, 0x10a9: 0x6211, + 0x10aa: 0x426d, 0x10ab: 0x428d, 0x10ac: 0x42ad, 0x10ad: 0x42cd, 0x10ae: 0x64b1, 0x10af: 0x64f1, + 0x10b0: 0x6539, 0x10b1: 0x6551, 0x10b2: 0x42ed, 0x10b3: 0x6569, 0x10b4: 0x6581, 0x10b5: 0x6599, + 0x10b6: 0x430d, 0x10b7: 0x65b1, 0x10b8: 0x65c9, 0x10b9: 0x65b1, 0x10ba: 0x65e1, 0x10bb: 0x65f9, + 0x10bc: 0x432d, 0x10bd: 0x6611, 0x10be: 0x6629, 0x10bf: 0x6611, + // Block 0x43, offset 0x10c0 + 0x10c0: 0x434d, 0x10c1: 0x436d, 0x10c2: 0x0040, 0x10c3: 0x6641, 0x10c4: 0x6659, 0x10c5: 0x6671, + 0x10c6: 0x6689, 0x10c7: 0x0040, 0x10c8: 0x66c1, 0x10c9: 0x66d9, 0x10ca: 0x66f1, 0x10cb: 0x6709, + 0x10cc: 0x6721, 0x10cd: 0x6739, 0x10ce: 0x6401, 0x10cf: 0x6751, 0x10d0: 0x6769, 0x10d1: 0x6781, + 0x10d2: 0x438d, 0x10d3: 0x6799, 0x10d4: 0x6289, 0x10d5: 0x43ad, 0x10d6: 0x43cd, 0x10d7: 0x67b1, + 0x10d8: 0x0040, 0x10d9: 0x43ed, 0x10da: 0x67c9, 0x10db: 0x67e1, 0x10dc: 0x67f9, 0x10dd: 0x6811, + 0x10de: 0x6829, 0x10df: 0x6859, 0x10e0: 0x6889, 0x10e1: 0x68b1, 0x10e2: 0x68d9, 0x10e3: 0x6901, + 0x10e4: 0x6929, 0x10e5: 0x6951, 0x10e6: 0x6979, 0x10e7: 0x69a1, 0x10e8: 0x69c9, 0x10e9: 0x69f1, + 0x10ea: 0x6a21, 0x10eb: 0x6a51, 0x10ec: 0x6a81, 0x10ed: 0x6ab1, 0x10ee: 0x6ae1, 0x10ef: 0x6b11, + 0x10f0: 0x6b41, 0x10f1: 0x6b71, 0x10f2: 0x6ba1, 0x10f3: 0x6bd1, 0x10f4: 0x6c01, 0x10f5: 0x6c31, + 0x10f6: 0x6c61, 0x10f7: 0x6c91, 0x10f8: 0x6cc1, 0x10f9: 0x6cf1, 0x10fa: 0x6d21, 0x10fb: 0x6d51, + 0x10fc: 0x6d81, 0x10fd: 0x6db1, 0x10fe: 0x6de1, 0x10ff: 0x440d, + // Block 0x44, offset 0x1100 + 0x1100: 0xe00d, 0x1101: 0x0008, 0x1102: 0xe00d, 0x1103: 0x0008, 0x1104: 0xe00d, 0x1105: 0x0008, + 0x1106: 0xe00d, 0x1107: 0x0008, 0x1108: 0xe00d, 0x1109: 0x0008, 0x110a: 0xe00d, 0x110b: 0x0008, + 0x110c: 0xe00d, 0x110d: 0x0008, 0x110e: 0xe00d, 0x110f: 0x0008, 0x1110: 0xe00d, 0x1111: 0x0008, + 0x1112: 0xe00d, 0x1113: 0x0008, 0x1114: 0xe00d, 0x1115: 0x0008, 0x1116: 0xe00d, 0x1117: 0x0008, + 0x1118: 0xe00d, 0x1119: 0x0008, 0x111a: 0xe00d, 0x111b: 0x0008, 0x111c: 0xe00d, 0x111d: 0x0008, + 0x111e: 0xe00d, 0x111f: 0x0008, 0x1120: 0xe00d, 0x1121: 0x0008, 0x1122: 0xe00d, 0x1123: 0x0008, + 0x1124: 0xe00d, 0x1125: 0x0008, 0x1126: 0xe00d, 0x1127: 0x0008, 0x1128: 0xe00d, 0x1129: 0x0008, + 0x112a: 0xe00d, 0x112b: 0x0008, 0x112c: 0xe00d, 0x112d: 0x0008, 0x112e: 0x0008, 0x112f: 0x3308, + 0x1130: 0x3318, 0x1131: 0x3318, 0x1132: 0x3318, 0x1133: 0x0018, 0x1134: 0x3308, 0x1135: 0x3308, + 0x1136: 0x3308, 0x1137: 0x3308, 0x1138: 0x3308, 0x1139: 0x3308, 0x113a: 0x3308, 0x113b: 0x3308, + 0x113c: 0x3308, 0x113d: 0x3308, 0x113e: 0x0018, 0x113f: 0x0008, + // Block 0x45, offset 0x1140 + 0x1140: 0xe00d, 0x1141: 0x0008, 0x1142: 0xe00d, 0x1143: 0x0008, 0x1144: 0xe00d, 0x1145: 0x0008, + 0x1146: 0xe00d, 0x1147: 0x0008, 0x1148: 0xe00d, 0x1149: 0x0008, 0x114a: 0xe00d, 0x114b: 0x0008, + 0x114c: 0xe00d, 0x114d: 0x0008, 0x114e: 0xe00d, 0x114f: 0x0008, 0x1150: 0xe00d, 0x1151: 0x0008, + 0x1152: 0xe00d, 0x1153: 0x0008, 0x1154: 0xe00d, 0x1155: 0x0008, 0x1156: 0xe00d, 0x1157: 0x0008, + 0x1158: 0xe00d, 0x1159: 0x0008, 0x115a: 0xe00d, 0x115b: 0x0008, 0x115c: 0x0ea1, 0x115d: 0x6e11, + 0x115e: 0x3308, 0x115f: 0x3308, 0x1160: 0x0008, 0x1161: 0x0008, 0x1162: 0x0008, 0x1163: 0x0008, + 0x1164: 0x0008, 0x1165: 0x0008, 0x1166: 0x0008, 0x1167: 0x0008, 0x1168: 0x0008, 0x1169: 0x0008, + 0x116a: 0x0008, 0x116b: 0x0008, 0x116c: 0x0008, 0x116d: 0x0008, 0x116e: 0x0008, 0x116f: 0x0008, + 0x1170: 0x0008, 0x1171: 0x0008, 0x1172: 0x0008, 0x1173: 0x0008, 0x1174: 0x0008, 0x1175: 0x0008, + 0x1176: 0x0008, 0x1177: 0x0008, 0x1178: 0x0008, 0x1179: 0x0008, 0x117a: 0x0008, 0x117b: 0x0008, + 0x117c: 0x0008, 0x117d: 0x0008, 0x117e: 0x0008, 0x117f: 0x0008, + // Block 0x46, offset 0x1180 + 0x1180: 0x0018, 0x1181: 0x0018, 0x1182: 0x0018, 0x1183: 0x0018, 0x1184: 0x0018, 0x1185: 0x0018, + 0x1186: 0x0018, 0x1187: 0x0018, 0x1188: 0x0018, 0x1189: 0x0018, 0x118a: 0x0018, 0x118b: 0x0018, + 0x118c: 0x0018, 0x118d: 0x0018, 0x118e: 0x0018, 0x118f: 0x0018, 0x1190: 0x0018, 0x1191: 0x0018, + 0x1192: 0x0018, 0x1193: 0x0018, 0x1194: 0x0018, 0x1195: 0x0018, 0x1196: 0x0018, 0x1197: 0x0008, + 0x1198: 0x0008, 0x1199: 0x0008, 0x119a: 0x0008, 0x119b: 0x0008, 0x119c: 0x0008, 0x119d: 0x0008, + 0x119e: 0x0008, 0x119f: 0x0008, 0x11a0: 0x0018, 0x11a1: 0x0018, 0x11a2: 0xe00d, 0x11a3: 0x0008, + 0x11a4: 0xe00d, 0x11a5: 0x0008, 0x11a6: 0xe00d, 0x11a7: 0x0008, 0x11a8: 0xe00d, 0x11a9: 0x0008, + 0x11aa: 0xe00d, 0x11ab: 0x0008, 0x11ac: 0xe00d, 0x11ad: 0x0008, 0x11ae: 0xe00d, 0x11af: 0x0008, + 0x11b0: 0x0008, 0x11b1: 0x0008, 0x11b2: 0xe00d, 0x11b3: 0x0008, 0x11b4: 0xe00d, 0x11b5: 0x0008, + 0x11b6: 0xe00d, 0x11b7: 0x0008, 0x11b8: 0xe00d, 0x11b9: 0x0008, 0x11ba: 0xe00d, 0x11bb: 0x0008, + 0x11bc: 0xe00d, 0x11bd: 0x0008, 0x11be: 0xe00d, 0x11bf: 0x0008, + // Block 0x47, offset 0x11c0 + 0x11c0: 0xe00d, 0x11c1: 0x0008, 0x11c2: 0xe00d, 0x11c3: 0x0008, 0x11c4: 0xe00d, 0x11c5: 0x0008, + 0x11c6: 0xe00d, 0x11c7: 0x0008, 0x11c8: 0xe00d, 0x11c9: 0x0008, 0x11ca: 0xe00d, 0x11cb: 0x0008, + 0x11cc: 0xe00d, 0x11cd: 0x0008, 0x11ce: 0xe00d, 0x11cf: 0x0008, 0x11d0: 0xe00d, 0x11d1: 0x0008, + 0x11d2: 0xe00d, 0x11d3: 0x0008, 0x11d4: 0xe00d, 0x11d5: 0x0008, 0x11d6: 0xe00d, 0x11d7: 0x0008, + 0x11d8: 0xe00d, 0x11d9: 0x0008, 0x11da: 0xe00d, 0x11db: 0x0008, 0x11dc: 0xe00d, 0x11dd: 0x0008, + 0x11de: 0xe00d, 0x11df: 0x0008, 0x11e0: 0xe00d, 0x11e1: 0x0008, 0x11e2: 0xe00d, 0x11e3: 0x0008, + 0x11e4: 0xe00d, 0x11e5: 0x0008, 0x11e6: 0xe00d, 0x11e7: 0x0008, 0x11e8: 0xe00d, 0x11e9: 0x0008, + 0x11ea: 0xe00d, 0x11eb: 0x0008, 0x11ec: 0xe00d, 0x11ed: 0x0008, 0x11ee: 0xe00d, 0x11ef: 0x0008, + 0x11f0: 0xe0fd, 0x11f1: 0x0008, 0x11f2: 0x0008, 0x11f3: 0x0008, 0x11f4: 0x0008, 0x11f5: 0x0008, + 0x11f6: 0x0008, 0x11f7: 0x0008, 0x11f8: 0x0008, 0x11f9: 0xe01d, 0x11fa: 0x0008, 0x11fb: 0xe03d, + 0x11fc: 0x0008, 0x11fd: 0x442d, 0x11fe: 0xe00d, 0x11ff: 0x0008, + // Block 0x48, offset 0x1200 + 0x1200: 0xe00d, 0x1201: 0x0008, 0x1202: 0xe00d, 0x1203: 0x0008, 0x1204: 0xe00d, 0x1205: 0x0008, + 0x1206: 0xe00d, 0x1207: 0x0008, 0x1208: 0x0008, 0x1209: 0x0018, 0x120a: 0x0018, 0x120b: 0xe03d, + 0x120c: 0x0008, 0x120d: 0x11d9, 0x120e: 0x0008, 0x120f: 0x0008, 0x1210: 0xe00d, 0x1211: 0x0008, + 0x1212: 0xe00d, 0x1213: 0x0008, 0x1214: 0x0008, 0x1215: 0x0008, 0x1216: 0xe00d, 0x1217: 0x0008, + 0x1218: 0xe00d, 0x1219: 0x0008, 0x121a: 0xe00d, 0x121b: 0x0008, 0x121c: 0xe00d, 0x121d: 0x0008, + 0x121e: 0xe00d, 0x121f: 0x0008, 0x1220: 0xe00d, 0x1221: 0x0008, 0x1222: 0xe00d, 0x1223: 0x0008, + 0x1224: 0xe00d, 0x1225: 0x0008, 0x1226: 0xe00d, 0x1227: 0x0008, 0x1228: 0xe00d, 0x1229: 0x0008, + 0x122a: 0x6e29, 0x122b: 0x1029, 0x122c: 0x11c1, 0x122d: 0x6e41, 0x122e: 0x1221, 0x122f: 0x0040, + 0x1230: 0x6e59, 0x1231: 0x6e71, 0x1232: 0x1239, 0x1233: 0x444d, 0x1234: 0xe00d, 0x1235: 0x0008, + 0x1236: 0xe00d, 0x1237: 0x0008, 0x1238: 0x0040, 0x1239: 0x0040, 0x123a: 0x0040, 0x123b: 0x0040, + 0x123c: 0x0040, 0x123d: 0x0040, 0x123e: 0x0040, 0x123f: 0x0040, + // Block 0x49, offset 0x1240 + 0x1240: 0x64d5, 0x1241: 0x64f5, 0x1242: 0x6515, 0x1243: 0x6535, 0x1244: 0x6555, 0x1245: 0x6575, + 0x1246: 0x6595, 0x1247: 0x65b5, 0x1248: 0x65d5, 0x1249: 0x65f5, 0x124a: 0x6615, 0x124b: 0x6635, + 0x124c: 0x6655, 0x124d: 0x6675, 0x124e: 0x0008, 0x124f: 0x0008, 0x1250: 0x6695, 0x1251: 0x0008, + 0x1252: 0x66b5, 0x1253: 0x0008, 0x1254: 0x0008, 0x1255: 0x66d5, 0x1256: 0x66f5, 0x1257: 0x6715, + 0x1258: 0x6735, 0x1259: 0x6755, 0x125a: 0x6775, 0x125b: 0x6795, 0x125c: 0x67b5, 0x125d: 0x67d5, + 0x125e: 0x67f5, 0x125f: 0x0008, 0x1260: 0x6815, 0x1261: 0x0008, 0x1262: 0x6835, 0x1263: 0x0008, + 0x1264: 0x0008, 0x1265: 0x6855, 0x1266: 0x6875, 0x1267: 0x0008, 0x1268: 0x0008, 0x1269: 0x0008, + 0x126a: 0x6895, 0x126b: 0x68b5, 0x126c: 0x68d5, 0x126d: 0x68f5, 0x126e: 0x6915, 0x126f: 0x6935, + 0x1270: 0x6955, 0x1271: 0x6975, 0x1272: 0x6995, 0x1273: 0x69b5, 0x1274: 0x69d5, 0x1275: 0x69f5, + 0x1276: 0x6a15, 0x1277: 0x6a35, 0x1278: 0x6a55, 0x1279: 0x6a75, 0x127a: 0x6a95, 0x127b: 0x6ab5, + 0x127c: 0x6ad5, 0x127d: 0x6af5, 0x127e: 0x6b15, 0x127f: 0x6b35, + // Block 0x4a, offset 0x1280 + 0x1280: 0x7a95, 0x1281: 0x7ab5, 0x1282: 0x7ad5, 0x1283: 0x7af5, 0x1284: 0x7b15, 0x1285: 0x7b35, + 0x1286: 0x7b55, 0x1287: 0x7b75, 0x1288: 0x7b95, 0x1289: 0x7bb5, 0x128a: 0x7bd5, 0x128b: 0x7bf5, + 0x128c: 0x7c15, 0x128d: 0x7c35, 0x128e: 0x7c55, 0x128f: 0x6ec9, 0x1290: 0x6ef1, 0x1291: 0x6f19, + 0x1292: 0x7c75, 0x1293: 0x7c95, 0x1294: 0x7cb5, 0x1295: 0x6f41, 0x1296: 0x6f69, 0x1297: 0x6f91, + 0x1298: 0x7cd5, 0x1299: 0x7cf5, 0x129a: 0x0040, 0x129b: 0x0040, 0x129c: 0x0040, 0x129d: 0x0040, + 0x129e: 0x0040, 0x129f: 0x0040, 0x12a0: 0x0040, 0x12a1: 0x0040, 0x12a2: 0x0040, 0x12a3: 0x0040, + 0x12a4: 0x0040, 0x12a5: 0x0040, 0x12a6: 0x0040, 0x12a7: 0x0040, 0x12a8: 0x0040, 0x12a9: 0x0040, + 0x12aa: 0x0040, 0x12ab: 0x0040, 0x12ac: 0x0040, 0x12ad: 0x0040, 0x12ae: 0x0040, 0x12af: 0x0040, + 0x12b0: 0x0040, 0x12b1: 0x0040, 0x12b2: 0x0040, 0x12b3: 0x0040, 0x12b4: 0x0040, 0x12b5: 0x0040, + 0x12b6: 0x0040, 0x12b7: 0x0040, 0x12b8: 0x0040, 0x12b9: 0x0040, 0x12ba: 0x0040, 0x12bb: 0x0040, + 0x12bc: 0x0040, 0x12bd: 0x0040, 0x12be: 0x0040, 0x12bf: 0x0040, + // Block 0x4b, offset 0x12c0 + 0x12c0: 0x6fb9, 0x12c1: 0x6fd1, 0x12c2: 0x6fe9, 0x12c3: 0x7d15, 0x12c4: 0x7d35, 0x12c5: 0x7001, + 0x12c6: 0x7001, 0x12c7: 0x0040, 0x12c8: 0x0040, 0x12c9: 0x0040, 0x12ca: 0x0040, 0x12cb: 0x0040, + 0x12cc: 0x0040, 0x12cd: 0x0040, 0x12ce: 0x0040, 0x12cf: 0x0040, 0x12d0: 0x0040, 0x12d1: 0x0040, + 0x12d2: 0x0040, 0x12d3: 0x7019, 0x12d4: 0x7041, 0x12d5: 0x7069, 0x12d6: 0x7091, 0x12d7: 0x70b9, + 0x12d8: 0x0040, 0x12d9: 0x0040, 0x12da: 0x0040, 0x12db: 0x0040, 0x12dc: 0x0040, 0x12dd: 0x70e1, + 0x12de: 0x3308, 0x12df: 0x7109, 0x12e0: 0x7131, 0x12e1: 0x20a9, 0x12e2: 0x20f1, 0x12e3: 0x7149, + 0x12e4: 0x7161, 0x12e5: 0x7179, 0x12e6: 0x7191, 0x12e7: 0x71a9, 0x12e8: 0x71c1, 0x12e9: 0x1fb2, + 0x12ea: 0x71d9, 0x12eb: 0x7201, 0x12ec: 0x7229, 0x12ed: 0x7261, 0x12ee: 0x7299, 0x12ef: 0x72c1, + 0x12f0: 0x72e9, 0x12f1: 0x7311, 0x12f2: 0x7339, 0x12f3: 0x7361, 0x12f4: 0x7389, 0x12f5: 0x73b1, + 0x12f6: 0x73d9, 0x12f7: 0x0040, 0x12f8: 0x7401, 0x12f9: 0x7429, 0x12fa: 0x7451, 0x12fb: 0x7479, + 0x12fc: 0x74a1, 0x12fd: 0x0040, 0x12fe: 0x74c9, 0x12ff: 0x0040, + // Block 0x4c, offset 0x1300 + 0x1300: 0x74f1, 0x1301: 0x7519, 0x1302: 0x0040, 0x1303: 0x7541, 0x1304: 0x7569, 0x1305: 0x0040, + 0x1306: 0x7591, 0x1307: 0x75b9, 0x1308: 0x75e1, 0x1309: 0x7609, 0x130a: 0x7631, 0x130b: 0x7659, + 0x130c: 0x7681, 0x130d: 0x76a9, 0x130e: 0x76d1, 0x130f: 0x76f9, 0x1310: 0x7721, 0x1311: 0x7721, + 0x1312: 0x7739, 0x1313: 0x7739, 0x1314: 0x7739, 0x1315: 0x7739, 0x1316: 0x7751, 0x1317: 0x7751, + 0x1318: 0x7751, 0x1319: 0x7751, 0x131a: 0x7769, 0x131b: 0x7769, 0x131c: 0x7769, 0x131d: 0x7769, + 0x131e: 0x7781, 0x131f: 0x7781, 0x1320: 0x7781, 0x1321: 0x7781, 0x1322: 0x7799, 0x1323: 0x7799, + 0x1324: 0x7799, 0x1325: 0x7799, 0x1326: 0x77b1, 0x1327: 0x77b1, 0x1328: 0x77b1, 0x1329: 0x77b1, + 0x132a: 0x77c9, 0x132b: 0x77c9, 0x132c: 0x77c9, 0x132d: 0x77c9, 0x132e: 0x77e1, 0x132f: 0x77e1, + 0x1330: 0x77e1, 0x1331: 0x77e1, 0x1332: 0x77f9, 0x1333: 0x77f9, 0x1334: 0x77f9, 0x1335: 0x77f9, + 0x1336: 0x7811, 0x1337: 0x7811, 0x1338: 0x7811, 0x1339: 0x7811, 0x133a: 0x7829, 0x133b: 0x7829, + 0x133c: 0x7829, 0x133d: 0x7829, 0x133e: 0x7841, 0x133f: 0x7841, + // Block 0x4d, offset 0x1340 + 0x1340: 0x7841, 0x1341: 0x7841, 0x1342: 0x7859, 0x1343: 0x7859, 0x1344: 0x7871, 0x1345: 0x7871, + 0x1346: 0x7889, 0x1347: 0x7889, 0x1348: 0x78a1, 0x1349: 0x78a1, 0x134a: 0x78b9, 0x134b: 0x78b9, + 0x134c: 0x78d1, 0x134d: 0x78d1, 0x134e: 0x78e9, 0x134f: 0x78e9, 0x1350: 0x78e9, 0x1351: 0x78e9, + 0x1352: 0x7901, 0x1353: 0x7901, 0x1354: 0x7901, 0x1355: 0x7901, 0x1356: 0x7919, 0x1357: 0x7919, + 0x1358: 0x7919, 0x1359: 0x7919, 0x135a: 0x7931, 0x135b: 0x7931, 0x135c: 0x7931, 0x135d: 0x7931, + 0x135e: 0x7949, 0x135f: 0x7949, 0x1360: 0x7961, 0x1361: 0x7961, 0x1362: 0x7961, 0x1363: 0x7961, + 0x1364: 0x7979, 0x1365: 0x7979, 0x1366: 0x7991, 0x1367: 0x7991, 0x1368: 0x7991, 0x1369: 0x7991, + 0x136a: 0x79a9, 0x136b: 0x79a9, 0x136c: 0x79a9, 0x136d: 0x79a9, 0x136e: 0x79c1, 0x136f: 0x79c1, + 0x1370: 0x79d9, 0x1371: 0x79d9, 0x1372: 0x0818, 0x1373: 0x0818, 0x1374: 0x0818, 0x1375: 0x0818, + 0x1376: 0x0818, 0x1377: 0x0818, 0x1378: 0x0818, 0x1379: 0x0818, 0x137a: 0x0818, 0x137b: 0x0818, + 0x137c: 0x0818, 0x137d: 0x0818, 0x137e: 0x0818, 0x137f: 0x0818, + // Block 0x4e, offset 0x1380 + 0x1380: 0x0818, 0x1381: 0x0818, 0x1382: 0x0040, 0x1383: 0x0040, 0x1384: 0x0040, 0x1385: 0x0040, + 0x1386: 0x0040, 0x1387: 0x0040, 0x1388: 0x0040, 0x1389: 0x0040, 0x138a: 0x0040, 0x138b: 0x0040, + 0x138c: 0x0040, 0x138d: 0x0040, 0x138e: 0x0040, 0x138f: 0x0040, 0x1390: 0x0040, 0x1391: 0x0040, + 0x1392: 0x0040, 0x1393: 0x79f1, 0x1394: 0x79f1, 0x1395: 0x79f1, 0x1396: 0x79f1, 0x1397: 0x7a09, + 0x1398: 0x7a09, 0x1399: 0x7a21, 0x139a: 0x7a21, 0x139b: 0x7a39, 0x139c: 0x7a39, 0x139d: 0x0479, + 0x139e: 0x7a51, 0x139f: 0x7a51, 0x13a0: 0x7a69, 0x13a1: 0x7a69, 0x13a2: 0x7a81, 0x13a3: 0x7a81, + 0x13a4: 0x7a99, 0x13a5: 0x7a99, 0x13a6: 0x7a99, 0x13a7: 0x7a99, 0x13a8: 0x7ab1, 0x13a9: 0x7ab1, + 0x13aa: 0x7ac9, 0x13ab: 0x7ac9, 0x13ac: 0x7af1, 0x13ad: 0x7af1, 0x13ae: 0x7b19, 0x13af: 0x7b19, + 0x13b0: 0x7b41, 0x13b1: 0x7b41, 0x13b2: 0x7b69, 0x13b3: 0x7b69, 0x13b4: 0x7b91, 0x13b5: 0x7b91, + 0x13b6: 0x7bb9, 0x13b7: 0x7bb9, 0x13b8: 0x7bb9, 0x13b9: 0x7be1, 0x13ba: 0x7be1, 0x13bb: 0x7be1, + 0x13bc: 0x7c09, 0x13bd: 0x7c09, 0x13be: 0x7c09, 0x13bf: 0x7c09, + // Block 0x4f, offset 0x13c0 + 0x13c0: 0x85f9, 0x13c1: 0x8621, 0x13c2: 0x8649, 0x13c3: 0x8671, 0x13c4: 0x8699, 0x13c5: 0x86c1, + 0x13c6: 0x86e9, 0x13c7: 0x8711, 0x13c8: 0x8739, 0x13c9: 0x8761, 0x13ca: 0x8789, 0x13cb: 0x87b1, + 0x13cc: 0x87d9, 0x13cd: 0x8801, 0x13ce: 0x8829, 0x13cf: 0x8851, 0x13d0: 0x8879, 0x13d1: 0x88a1, + 0x13d2: 0x88c9, 0x13d3: 0x88f1, 0x13d4: 0x8919, 0x13d5: 0x8941, 0x13d6: 0x8969, 0x13d7: 0x8991, + 0x13d8: 0x89b9, 0x13d9: 0x89e1, 0x13da: 0x8a09, 0x13db: 0x8a31, 0x13dc: 0x8a59, 0x13dd: 0x8a81, + 0x13de: 0x8aaa, 0x13df: 0x8ada, 0x13e0: 0x8b0a, 0x13e1: 0x8b3a, 0x13e2: 0x8b6a, 0x13e3: 0x8b9a, + 0x13e4: 0x8bc9, 0x13e5: 0x8bf1, 0x13e6: 0x7c71, 0x13e7: 0x8c19, 0x13e8: 0x7be1, 0x13e9: 0x7c99, + 0x13ea: 0x8c41, 0x13eb: 0x8c69, 0x13ec: 0x7d39, 0x13ed: 0x8c91, 0x13ee: 0x7d61, 0x13ef: 0x7d89, + 0x13f0: 0x8cb9, 0x13f1: 0x8ce1, 0x13f2: 0x7e29, 0x13f3: 0x8d09, 0x13f4: 0x7e51, 0x13f5: 0x7e79, + 0x13f6: 0x8d31, 0x13f7: 0x8d59, 0x13f8: 0x7ec9, 0x13f9: 0x8d81, 0x13fa: 0x7ef1, 0x13fb: 0x7f19, + 0x13fc: 0x83a1, 0x13fd: 0x83c9, 0x13fe: 0x8441, 0x13ff: 0x8469, + // Block 0x50, offset 0x1400 + 0x1400: 0x8491, 0x1401: 0x8531, 0x1402: 0x8559, 0x1403: 0x8581, 0x1404: 0x85a9, 0x1405: 0x8649, + 0x1406: 0x8671, 0x1407: 0x8699, 0x1408: 0x8da9, 0x1409: 0x8739, 0x140a: 0x8dd1, 0x140b: 0x8df9, + 0x140c: 0x8829, 0x140d: 0x8e21, 0x140e: 0x8851, 0x140f: 0x8879, 0x1410: 0x8a81, 0x1411: 0x8e49, + 0x1412: 0x8e71, 0x1413: 0x89b9, 0x1414: 0x8e99, 0x1415: 0x89e1, 0x1416: 0x8a09, 0x1417: 0x7c21, + 0x1418: 0x7c49, 0x1419: 0x8ec1, 0x141a: 0x7c71, 0x141b: 0x8ee9, 0x141c: 0x7cc1, 0x141d: 0x7ce9, + 0x141e: 0x7d11, 0x141f: 0x7d39, 0x1420: 0x8f11, 0x1421: 0x7db1, 0x1422: 0x7dd9, 0x1423: 0x7e01, + 0x1424: 0x7e29, 0x1425: 0x8f39, 0x1426: 0x7ec9, 0x1427: 0x7f41, 0x1428: 0x7f69, 0x1429: 0x7f91, + 0x142a: 0x7fb9, 0x142b: 0x7fe1, 0x142c: 0x8031, 0x142d: 0x8059, 0x142e: 0x8081, 0x142f: 0x80a9, + 0x1430: 0x80d1, 0x1431: 0x80f9, 0x1432: 0x8f61, 0x1433: 0x8121, 0x1434: 0x8149, 0x1435: 0x8171, + 0x1436: 0x8199, 0x1437: 0x81c1, 0x1438: 0x81e9, 0x1439: 0x8239, 0x143a: 0x8261, 0x143b: 0x8289, + 0x143c: 0x82b1, 0x143d: 0x82d9, 0x143e: 0x8301, 0x143f: 0x8329, + // Block 0x51, offset 0x1440 + 0x1440: 0x8351, 0x1441: 0x8379, 0x1442: 0x83f1, 0x1443: 0x8419, 0x1444: 0x84b9, 0x1445: 0x84e1, + 0x1446: 0x8509, 0x1447: 0x8531, 0x1448: 0x8559, 0x1449: 0x85d1, 0x144a: 0x85f9, 0x144b: 0x8621, + 0x144c: 0x8649, 0x144d: 0x8f89, 0x144e: 0x86c1, 0x144f: 0x86e9, 0x1450: 0x8711, 0x1451: 0x8739, + 0x1452: 0x87b1, 0x1453: 0x87d9, 0x1454: 0x8801, 0x1455: 0x8829, 0x1456: 0x8fb1, 0x1457: 0x88a1, + 0x1458: 0x88c9, 0x1459: 0x8fd9, 0x145a: 0x8941, 0x145b: 0x8969, 0x145c: 0x8991, 0x145d: 0x89b9, + 0x145e: 0x9001, 0x145f: 0x7c71, 0x1460: 0x8ee9, 0x1461: 0x7d39, 0x1462: 0x8f11, 0x1463: 0x7e29, + 0x1464: 0x8f39, 0x1465: 0x7ec9, 0x1466: 0x9029, 0x1467: 0x80d1, 0x1468: 0x9051, 0x1469: 0x9079, + 0x146a: 0x90a1, 0x146b: 0x8531, 0x146c: 0x8559, 0x146d: 0x8649, 0x146e: 0x8829, 0x146f: 0x8fb1, + 0x1470: 0x89b9, 0x1471: 0x9001, 0x1472: 0x90c9, 0x1473: 0x9101, 0x1474: 0x9139, 0x1475: 0x9171, + 0x1476: 0x9199, 0x1477: 0x91c1, 0x1478: 0x91e9, 0x1479: 0x9211, 0x147a: 0x9239, 0x147b: 0x9261, + 0x147c: 0x9289, 0x147d: 0x92b1, 0x147e: 0x92d9, 0x147f: 0x9301, + // Block 0x52, offset 0x1480 + 0x1480: 0x9329, 0x1481: 0x9351, 0x1482: 0x9379, 0x1483: 0x93a1, 0x1484: 0x93c9, 0x1485: 0x93f1, + 0x1486: 0x9419, 0x1487: 0x9441, 0x1488: 0x9469, 0x1489: 0x9491, 0x148a: 0x94b9, 0x148b: 0x94e1, + 0x148c: 0x9079, 0x148d: 0x9509, 0x148e: 0x9531, 0x148f: 0x9559, 0x1490: 0x9581, 0x1491: 0x9171, + 0x1492: 0x9199, 0x1493: 0x91c1, 0x1494: 0x91e9, 0x1495: 0x9211, 0x1496: 0x9239, 0x1497: 0x9261, + 0x1498: 0x9289, 0x1499: 0x92b1, 0x149a: 0x92d9, 0x149b: 0x9301, 0x149c: 0x9329, 0x149d: 0x9351, + 0x149e: 0x9379, 0x149f: 0x93a1, 0x14a0: 0x93c9, 0x14a1: 0x93f1, 0x14a2: 0x9419, 0x14a3: 0x9441, + 0x14a4: 0x9469, 0x14a5: 0x9491, 0x14a6: 0x94b9, 0x14a7: 0x94e1, 0x14a8: 0x9079, 0x14a9: 0x9509, + 0x14aa: 0x9531, 0x14ab: 0x9559, 0x14ac: 0x9581, 0x14ad: 0x9491, 0x14ae: 0x94b9, 0x14af: 0x94e1, + 0x14b0: 0x9079, 0x14b1: 0x9051, 0x14b2: 0x90a1, 0x14b3: 0x8211, 0x14b4: 0x8059, 0x14b5: 0x8081, + 0x14b6: 0x80a9, 0x14b7: 0x9491, 0x14b8: 0x94b9, 0x14b9: 0x94e1, 0x14ba: 0x8211, 0x14bb: 0x8239, + 0x14bc: 0x95a9, 0x14bd: 0x95a9, 0x14be: 0x0018, 0x14bf: 0x0018, + // Block 0x53, offset 0x14c0 + 0x14c0: 0x0040, 0x14c1: 0x0040, 0x14c2: 0x0040, 0x14c3: 0x0040, 0x14c4: 0x0040, 0x14c5: 0x0040, + 0x14c6: 0x0040, 0x14c7: 0x0040, 0x14c8: 0x0040, 0x14c9: 0x0040, 0x14ca: 0x0040, 0x14cb: 0x0040, + 0x14cc: 0x0040, 0x14cd: 0x0040, 0x14ce: 0x0040, 0x14cf: 0x0040, 0x14d0: 0x95d1, 0x14d1: 0x9609, + 0x14d2: 0x9609, 0x14d3: 0x9641, 0x14d4: 0x9679, 0x14d5: 0x96b1, 0x14d6: 0x96e9, 0x14d7: 0x9721, + 0x14d8: 0x9759, 0x14d9: 0x9759, 0x14da: 0x9791, 0x14db: 0x97c9, 0x14dc: 0x9801, 0x14dd: 0x9839, + 0x14de: 0x9871, 0x14df: 0x98a9, 0x14e0: 0x98a9, 0x14e1: 0x98e1, 0x14e2: 0x9919, 0x14e3: 0x9919, + 0x14e4: 0x9951, 0x14e5: 0x9951, 0x14e6: 0x9989, 0x14e7: 0x99c1, 0x14e8: 0x99c1, 0x14e9: 0x99f9, + 0x14ea: 0x9a31, 0x14eb: 0x9a31, 0x14ec: 0x9a69, 0x14ed: 0x9a69, 0x14ee: 0x9aa1, 0x14ef: 0x9ad9, + 0x14f0: 0x9ad9, 0x14f1: 0x9b11, 0x14f2: 0x9b11, 0x14f3: 0x9b49, 0x14f4: 0x9b81, 0x14f5: 0x9bb9, + 0x14f6: 0x9bf1, 0x14f7: 0x9bf1, 0x14f8: 0x9c29, 0x14f9: 0x9c61, 0x14fa: 0x9c99, 0x14fb: 0x9cd1, + 0x14fc: 0x9d09, 0x14fd: 0x9d09, 0x14fe: 0x9d41, 0x14ff: 0x9d79, + // Block 0x54, offset 0x1500 + 0x1500: 0xa949, 0x1501: 0xa981, 0x1502: 0xa9b9, 0x1503: 0xa8a1, 0x1504: 0x9bb9, 0x1505: 0x9989, + 0x1506: 0xa9f1, 0x1507: 0xaa29, 0x1508: 0x0040, 0x1509: 0x0040, 0x150a: 0x0040, 0x150b: 0x0040, + 0x150c: 0x0040, 0x150d: 0x0040, 0x150e: 0x0040, 0x150f: 0x0040, 0x1510: 0x0040, 0x1511: 0x0040, + 0x1512: 0x0040, 0x1513: 0x0040, 0x1514: 0x0040, 0x1515: 0x0040, 0x1516: 0x0040, 0x1517: 0x0040, + 0x1518: 0x0040, 0x1519: 0x0040, 0x151a: 0x0040, 0x151b: 0x0040, 0x151c: 0x0040, 0x151d: 0x0040, + 0x151e: 0x0040, 0x151f: 0x0040, 0x1520: 0x0040, 0x1521: 0x0040, 0x1522: 0x0040, 0x1523: 0x0040, + 0x1524: 0x0040, 0x1525: 0x0040, 0x1526: 0x0040, 0x1527: 0x0040, 0x1528: 0x0040, 0x1529: 0x0040, + 0x152a: 0x0040, 0x152b: 0x0040, 0x152c: 0x0040, 0x152d: 0x0040, 0x152e: 0x0040, 0x152f: 0x0040, + 0x1530: 0xaa61, 0x1531: 0xaa99, 0x1532: 0xaad1, 0x1533: 0xab19, 0x1534: 0xab61, 0x1535: 0xaba9, + 0x1536: 0xabf1, 0x1537: 0xac39, 0x1538: 0xac81, 0x1539: 0xacc9, 0x153a: 0xad02, 0x153b: 0xae12, + 0x153c: 0xae91, 0x153d: 0x0018, 0x153e: 0x0040, 0x153f: 0x0040, + // Block 0x55, offset 0x1540 + 0x1540: 0x33c0, 0x1541: 0x33c0, 0x1542: 0x33c0, 0x1543: 0x33c0, 0x1544: 0x33c0, 0x1545: 0x33c0, + 0x1546: 0x33c0, 0x1547: 0x33c0, 0x1548: 0x33c0, 0x1549: 0x33c0, 0x154a: 0x33c0, 0x154b: 0x33c0, + 0x154c: 0x33c0, 0x154d: 0x33c0, 0x154e: 0x33c0, 0x154f: 0x33c0, 0x1550: 0xaeda, 0x1551: 0x7d55, + 0x1552: 0x0040, 0x1553: 0xaeea, 0x1554: 0x03c2, 0x1555: 0xaefa, 0x1556: 0xaf0a, 0x1557: 0x7d75, + 0x1558: 0x7d95, 0x1559: 0x0040, 0x155a: 0x0040, 0x155b: 0x0040, 0x155c: 0x0040, 0x155d: 0x0040, + 0x155e: 0x0040, 0x155f: 0x0040, 0x1560: 0x3308, 0x1561: 0x3308, 0x1562: 0x3308, 0x1563: 0x3308, + 0x1564: 0x3308, 0x1565: 0x3308, 0x1566: 0x3308, 0x1567: 0x3308, 0x1568: 0x3308, 0x1569: 0x3308, + 0x156a: 0x3308, 0x156b: 0x3308, 0x156c: 0x3308, 0x156d: 0x3308, 0x156e: 0x3308, 0x156f: 0x3308, + 0x1570: 0x0040, 0x1571: 0x7db5, 0x1572: 0x7dd5, 0x1573: 0xaf1a, 0x1574: 0xaf1a, 0x1575: 0x1fd2, + 0x1576: 0x1fe2, 0x1577: 0xaf2a, 0x1578: 0xaf3a, 0x1579: 0x7df5, 0x157a: 0x7e15, 0x157b: 0x7e35, + 0x157c: 0x7df5, 0x157d: 0x7e55, 0x157e: 0x7e75, 0x157f: 0x7e55, + // Block 0x56, offset 0x1580 + 0x1580: 0x7e95, 0x1581: 0x7eb5, 0x1582: 0x7ed5, 0x1583: 0x7eb5, 0x1584: 0x7ef5, 0x1585: 0x0018, + 0x1586: 0x0018, 0x1587: 0xaf4a, 0x1588: 0xaf5a, 0x1589: 0x7f16, 0x158a: 0x7f36, 0x158b: 0x7f56, + 0x158c: 0x7f76, 0x158d: 0xaf1a, 0x158e: 0xaf1a, 0x158f: 0xaf1a, 0x1590: 0xaeda, 0x1591: 0x7f95, + 0x1592: 0x0040, 0x1593: 0x0040, 0x1594: 0x03c2, 0x1595: 0xaeea, 0x1596: 0xaf0a, 0x1597: 0xaefa, + 0x1598: 0x7fb5, 0x1599: 0x1fd2, 0x159a: 0x1fe2, 0x159b: 0xaf2a, 0x159c: 0xaf3a, 0x159d: 0x7e95, + 0x159e: 0x7ef5, 0x159f: 0xaf6a, 0x15a0: 0xaf7a, 0x15a1: 0xaf8a, 0x15a2: 0x1fb2, 0x15a3: 0xaf99, + 0x15a4: 0xafaa, 0x15a5: 0xafba, 0x15a6: 0x1fc2, 0x15a7: 0x0040, 0x15a8: 0xafca, 0x15a9: 0xafda, + 0x15aa: 0xafea, 0x15ab: 0xaffa, 0x15ac: 0x0040, 0x15ad: 0x0040, 0x15ae: 0x0040, 0x15af: 0x0040, + 0x15b0: 0x7fd6, 0x15b1: 0xb009, 0x15b2: 0x7ff6, 0x15b3: 0x0808, 0x15b4: 0x8016, 0x15b5: 0x0040, + 0x15b6: 0x8036, 0x15b7: 0xb031, 0x15b8: 0x8056, 0x15b9: 0xb059, 0x15ba: 0x8076, 0x15bb: 0xb081, + 0x15bc: 0x8096, 0x15bd: 0xb0a9, 0x15be: 0x80b6, 0x15bf: 0xb0d1, + // Block 0x57, offset 0x15c0 + 0x15c0: 0xb0f9, 0x15c1: 0xb111, 0x15c2: 0xb111, 0x15c3: 0xb129, 0x15c4: 0xb129, 0x15c5: 0xb141, + 0x15c6: 0xb141, 0x15c7: 0xb159, 0x15c8: 0xb159, 0x15c9: 0xb171, 0x15ca: 0xb171, 0x15cb: 0xb171, + 0x15cc: 0xb171, 0x15cd: 0xb189, 0x15ce: 0xb189, 0x15cf: 0xb1a1, 0x15d0: 0xb1a1, 0x15d1: 0xb1a1, + 0x15d2: 0xb1a1, 0x15d3: 0xb1b9, 0x15d4: 0xb1b9, 0x15d5: 0xb1d1, 0x15d6: 0xb1d1, 0x15d7: 0xb1d1, + 0x15d8: 0xb1d1, 0x15d9: 0xb1e9, 0x15da: 0xb1e9, 0x15db: 0xb1e9, 0x15dc: 0xb1e9, 0x15dd: 0xb201, + 0x15de: 0xb201, 0x15df: 0xb201, 0x15e0: 0xb201, 0x15e1: 0xb219, 0x15e2: 0xb219, 0x15e3: 0xb219, + 0x15e4: 0xb219, 0x15e5: 0xb231, 0x15e6: 0xb231, 0x15e7: 0xb231, 0x15e8: 0xb231, 0x15e9: 0xb249, + 0x15ea: 0xb249, 0x15eb: 0xb261, 0x15ec: 0xb261, 0x15ed: 0xb279, 0x15ee: 0xb279, 0x15ef: 0xb291, + 0x15f0: 0xb291, 0x15f1: 0xb2a9, 0x15f2: 0xb2a9, 0x15f3: 0xb2a9, 0x15f4: 0xb2a9, 0x15f5: 0xb2c1, + 0x15f6: 0xb2c1, 0x15f7: 0xb2c1, 0x15f8: 0xb2c1, 0x15f9: 0xb2d9, 0x15fa: 0xb2d9, 0x15fb: 0xb2d9, + 0x15fc: 0xb2d9, 0x15fd: 0xb2f1, 0x15fe: 0xb2f1, 0x15ff: 0xb2f1, + // Block 0x58, offset 0x1600 + 0x1600: 0xb2f1, 0x1601: 0xb309, 0x1602: 0xb309, 0x1603: 0xb309, 0x1604: 0xb309, 0x1605: 0xb321, + 0x1606: 0xb321, 0x1607: 0xb321, 0x1608: 0xb321, 0x1609: 0xb339, 0x160a: 0xb339, 0x160b: 0xb339, + 0x160c: 0xb339, 0x160d: 0xb351, 0x160e: 0xb351, 0x160f: 0xb351, 0x1610: 0xb351, 0x1611: 0xb369, + 0x1612: 0xb369, 0x1613: 0xb369, 0x1614: 0xb369, 0x1615: 0xb381, 0x1616: 0xb381, 0x1617: 0xb381, + 0x1618: 0xb381, 0x1619: 0xb399, 0x161a: 0xb399, 0x161b: 0xb399, 0x161c: 0xb399, 0x161d: 0xb3b1, + 0x161e: 0xb3b1, 0x161f: 0xb3b1, 0x1620: 0xb3b1, 0x1621: 0xb3c9, 0x1622: 0xb3c9, 0x1623: 0xb3c9, + 0x1624: 0xb3c9, 0x1625: 0xb3e1, 0x1626: 0xb3e1, 0x1627: 0xb3e1, 0x1628: 0xb3e1, 0x1629: 0xb3f9, + 0x162a: 0xb3f9, 0x162b: 0xb3f9, 0x162c: 0xb3f9, 0x162d: 0xb411, 0x162e: 0xb411, 0x162f: 0x7ab1, + 0x1630: 0x7ab1, 0x1631: 0xb429, 0x1632: 0xb429, 0x1633: 0xb429, 0x1634: 0xb429, 0x1635: 0xb441, + 0x1636: 0xb441, 0x1637: 0xb469, 0x1638: 0xb469, 0x1639: 0xb491, 0x163a: 0xb491, 0x163b: 0xb4b9, + 0x163c: 0xb4b9, 0x163d: 0x0040, 0x163e: 0x0040, 0x163f: 0x03c0, + // Block 0x59, offset 0x1640 + 0x1640: 0x0040, 0x1641: 0xaefa, 0x1642: 0xb4e2, 0x1643: 0xaf6a, 0x1644: 0xafda, 0x1645: 0xafea, + 0x1646: 0xaf7a, 0x1647: 0xb4f2, 0x1648: 0x1fd2, 0x1649: 0x1fe2, 0x164a: 0xaf8a, 0x164b: 0x1fb2, + 0x164c: 0xaeda, 0x164d: 0xaf99, 0x164e: 0x29d1, 0x164f: 0xb502, 0x1650: 0x1f41, 0x1651: 0x00c9, + 0x1652: 0x0069, 0x1653: 0x0079, 0x1654: 0x1f51, 0x1655: 0x1f61, 0x1656: 0x1f71, 0x1657: 0x1f81, + 0x1658: 0x1f91, 0x1659: 0x1fa1, 0x165a: 0xaeea, 0x165b: 0x03c2, 0x165c: 0xafaa, 0x165d: 0x1fc2, + 0x165e: 0xafba, 0x165f: 0xaf0a, 0x1660: 0xaffa, 0x1661: 0x0039, 0x1662: 0x0ee9, 0x1663: 0x1159, + 0x1664: 0x0ef9, 0x1665: 0x0f09, 0x1666: 0x1199, 0x1667: 0x0f31, 0x1668: 0x0249, 0x1669: 0x0f41, + 0x166a: 0x0259, 0x166b: 0x0f51, 0x166c: 0x0359, 0x166d: 0x0f61, 0x166e: 0x0f71, 0x166f: 0x00d9, + 0x1670: 0x0f99, 0x1671: 0x2039, 0x1672: 0x0269, 0x1673: 0x01d9, 0x1674: 0x0fa9, 0x1675: 0x0fb9, + 0x1676: 0x1089, 0x1677: 0x0279, 0x1678: 0x0369, 0x1679: 0x0289, 0x167a: 0x13d1, 0x167b: 0xaf4a, + 0x167c: 0xafca, 0x167d: 0xaf5a, 0x167e: 0xb512, 0x167f: 0xaf1a, + // Block 0x5a, offset 0x1680 + 0x1680: 0x1caa, 0x1681: 0x0039, 0x1682: 0x0ee9, 0x1683: 0x1159, 0x1684: 0x0ef9, 0x1685: 0x0f09, + 0x1686: 0x1199, 0x1687: 0x0f31, 0x1688: 0x0249, 0x1689: 0x0f41, 0x168a: 0x0259, 0x168b: 0x0f51, + 0x168c: 0x0359, 0x168d: 0x0f61, 0x168e: 0x0f71, 0x168f: 0x00d9, 0x1690: 0x0f99, 0x1691: 0x2039, + 0x1692: 0x0269, 0x1693: 0x01d9, 0x1694: 0x0fa9, 0x1695: 0x0fb9, 0x1696: 0x1089, 0x1697: 0x0279, + 0x1698: 0x0369, 0x1699: 0x0289, 0x169a: 0x13d1, 0x169b: 0xaf2a, 0x169c: 0xb522, 0x169d: 0xaf3a, + 0x169e: 0xb532, 0x169f: 0x80d5, 0x16a0: 0x80f5, 0x16a1: 0x29d1, 0x16a2: 0x8115, 0x16a3: 0x8115, + 0x16a4: 0x8135, 0x16a5: 0x8155, 0x16a6: 0x8175, 0x16a7: 0x8195, 0x16a8: 0x81b5, 0x16a9: 0x81d5, + 0x16aa: 0x81f5, 0x16ab: 0x8215, 0x16ac: 0x8235, 0x16ad: 0x8255, 0x16ae: 0x8275, 0x16af: 0x8295, + 0x16b0: 0x82b5, 0x16b1: 0x82d5, 0x16b2: 0x82f5, 0x16b3: 0x8315, 0x16b4: 0x8335, 0x16b5: 0x8355, + 0x16b6: 0x8375, 0x16b7: 0x8395, 0x16b8: 0x83b5, 0x16b9: 0x83d5, 0x16ba: 0x83f5, 0x16bb: 0x8415, + 0x16bc: 0x81b5, 0x16bd: 0x8435, 0x16be: 0x8455, 0x16bf: 0x8215, + // Block 0x5b, offset 0x16c0 + 0x16c0: 0x8475, 0x16c1: 0x8495, 0x16c2: 0x84b5, 0x16c3: 0x84d5, 0x16c4: 0x84f5, 0x16c5: 0x8515, + 0x16c6: 0x8535, 0x16c7: 0x8555, 0x16c8: 0x84d5, 0x16c9: 0x8575, 0x16ca: 0x84d5, 0x16cb: 0x8595, + 0x16cc: 0x8595, 0x16cd: 0x85b5, 0x16ce: 0x85b5, 0x16cf: 0x85d5, 0x16d0: 0x8515, 0x16d1: 0x85f5, + 0x16d2: 0x8615, 0x16d3: 0x85f5, 0x16d4: 0x8635, 0x16d5: 0x8615, 0x16d6: 0x8655, 0x16d7: 0x8655, + 0x16d8: 0x8675, 0x16d9: 0x8675, 0x16da: 0x8695, 0x16db: 0x8695, 0x16dc: 0x8615, 0x16dd: 0x8115, + 0x16de: 0x86b5, 0x16df: 0x86d5, 0x16e0: 0x0040, 0x16e1: 0x86f5, 0x16e2: 0x8715, 0x16e3: 0x8735, + 0x16e4: 0x8755, 0x16e5: 0x8735, 0x16e6: 0x8775, 0x16e7: 0x8795, 0x16e8: 0x87b5, 0x16e9: 0x87b5, + 0x16ea: 0x87d5, 0x16eb: 0x87d5, 0x16ec: 0x87f5, 0x16ed: 0x87f5, 0x16ee: 0x87d5, 0x16ef: 0x87d5, + 0x16f0: 0x8815, 0x16f1: 0x8835, 0x16f2: 0x8855, 0x16f3: 0x8875, 0x16f4: 0x8895, 0x16f5: 0x88b5, + 0x16f6: 0x88b5, 0x16f7: 0x88b5, 0x16f8: 0x88d5, 0x16f9: 0x88d5, 0x16fa: 0x88d5, 0x16fb: 0x88d5, + 0x16fc: 0x87b5, 0x16fd: 0x87b5, 0x16fe: 0x87b5, 0x16ff: 0x0040, + // Block 0x5c, offset 0x1700 + 0x1700: 0x0040, 0x1701: 0x0040, 0x1702: 0x8715, 0x1703: 0x86f5, 0x1704: 0x88f5, 0x1705: 0x86f5, + 0x1706: 0x8715, 0x1707: 0x86f5, 0x1708: 0x0040, 0x1709: 0x0040, 0x170a: 0x8915, 0x170b: 0x8715, + 0x170c: 0x8935, 0x170d: 0x88f5, 0x170e: 0x8935, 0x170f: 0x8715, 0x1710: 0x0040, 0x1711: 0x0040, + 0x1712: 0x8955, 0x1713: 0x8975, 0x1714: 0x8875, 0x1715: 0x8935, 0x1716: 0x88f5, 0x1717: 0x8935, + 0x1718: 0x0040, 0x1719: 0x0040, 0x171a: 0x8995, 0x171b: 0x89b5, 0x171c: 0x8995, 0x171d: 0x0040, + 0x171e: 0x0040, 0x171f: 0x0040, 0x1720: 0xb541, 0x1721: 0xb559, 0x1722: 0xb571, 0x1723: 0x89d6, + 0x1724: 0xb589, 0x1725: 0xb5a1, 0x1726: 0x89f5, 0x1727: 0x0040, 0x1728: 0x8a15, 0x1729: 0x8a35, + 0x172a: 0x8a55, 0x172b: 0x8a35, 0x172c: 0x8a75, 0x172d: 0x8a95, 0x172e: 0x8ab5, 0x172f: 0x0040, + 0x1730: 0x0040, 0x1731: 0x0040, 0x1732: 0x0040, 0x1733: 0x0040, 0x1734: 0x0040, 0x1735: 0x0040, + 0x1736: 0x0040, 0x1737: 0x0040, 0x1738: 0x0040, 0x1739: 0x0340, 0x173a: 0x0340, 0x173b: 0x0340, + 0x173c: 0x0040, 0x173d: 0x0040, 0x173e: 0x0040, 0x173f: 0x0040, + // Block 0x5d, offset 0x1740 + 0x1740: 0x0a08, 0x1741: 0x0a08, 0x1742: 0x0a08, 0x1743: 0x0a08, 0x1744: 0x0a08, 0x1745: 0x0c08, + 0x1746: 0x0808, 0x1747: 0x0c08, 0x1748: 0x0818, 0x1749: 0x0c08, 0x174a: 0x0c08, 0x174b: 0x0808, + 0x174c: 0x0808, 0x174d: 0x0908, 0x174e: 0x0c08, 0x174f: 0x0c08, 0x1750: 0x0c08, 0x1751: 0x0c08, + 0x1752: 0x0c08, 0x1753: 0x0a08, 0x1754: 0x0a08, 0x1755: 0x0a08, 0x1756: 0x0a08, 0x1757: 0x0908, + 0x1758: 0x0a08, 0x1759: 0x0a08, 0x175a: 0x0a08, 0x175b: 0x0a08, 0x175c: 0x0a08, 0x175d: 0x0c08, + 0x175e: 0x0a08, 0x175f: 0x0a08, 0x1760: 0x0a08, 0x1761: 0x0c08, 0x1762: 0x0808, 0x1763: 0x0808, + 0x1764: 0x0c08, 0x1765: 0x3308, 0x1766: 0x3308, 0x1767: 0x0040, 0x1768: 0x0040, 0x1769: 0x0040, + 0x176a: 0x0040, 0x176b: 0x0a18, 0x176c: 0x0a18, 0x176d: 0x0a18, 0x176e: 0x0a18, 0x176f: 0x0c18, + 0x1770: 0x0818, 0x1771: 0x0818, 0x1772: 0x0818, 0x1773: 0x0818, 0x1774: 0x0818, 0x1775: 0x0818, + 0x1776: 0x0818, 0x1777: 0x0040, 0x1778: 0x0040, 0x1779: 0x0040, 0x177a: 0x0040, 0x177b: 0x0040, + 0x177c: 0x0040, 0x177d: 0x0040, 0x177e: 0x0040, 0x177f: 0x0040, + // Block 0x5e, offset 0x1780 + 0x1780: 0x0a08, 0x1781: 0x0c08, 0x1782: 0x0a08, 0x1783: 0x0c08, 0x1784: 0x0c08, 0x1785: 0x0c08, + 0x1786: 0x0a08, 0x1787: 0x0a08, 0x1788: 0x0a08, 0x1789: 0x0c08, 0x178a: 0x0a08, 0x178b: 0x0a08, + 0x178c: 0x0c08, 0x178d: 0x0a08, 0x178e: 0x0c08, 0x178f: 0x0c08, 0x1790: 0x0a08, 0x1791: 0x0c08, + 0x1792: 0x0040, 0x1793: 0x0040, 0x1794: 0x0040, 0x1795: 0x0040, 0x1796: 0x0040, 0x1797: 0x0040, + 0x1798: 0x0040, 0x1799: 0x0818, 0x179a: 0x0818, 0x179b: 0x0818, 0x179c: 0x0818, 0x179d: 0x0040, + 0x179e: 0x0040, 0x179f: 0x0040, 0x17a0: 0x0040, 0x17a1: 0x0040, 0x17a2: 0x0040, 0x17a3: 0x0040, + 0x17a4: 0x0040, 0x17a5: 0x0040, 0x17a6: 0x0040, 0x17a7: 0x0040, 0x17a8: 0x0040, 0x17a9: 0x0c18, + 0x17aa: 0x0c18, 0x17ab: 0x0c18, 0x17ac: 0x0c18, 0x17ad: 0x0a18, 0x17ae: 0x0a18, 0x17af: 0x0818, + 0x17b0: 0x0040, 0x17b1: 0x0040, 0x17b2: 0x0040, 0x17b3: 0x0040, 0x17b4: 0x0040, 0x17b5: 0x0040, + 0x17b6: 0x0040, 0x17b7: 0x0040, 0x17b8: 0x0040, 0x17b9: 0x0040, 0x17ba: 0x0040, 0x17bb: 0x0040, + 0x17bc: 0x0040, 0x17bd: 0x0040, 0x17be: 0x0040, 0x17bf: 0x0040, + // Block 0x5f, offset 0x17c0 + 0x17c0: 0x3308, 0x17c1: 0x3308, 0x17c2: 0x3008, 0x17c3: 0x3008, 0x17c4: 0x0040, 0x17c5: 0x0008, + 0x17c6: 0x0008, 0x17c7: 0x0008, 0x17c8: 0x0008, 0x17c9: 0x0008, 0x17ca: 0x0008, 0x17cb: 0x0008, + 0x17cc: 0x0008, 0x17cd: 0x0040, 0x17ce: 0x0040, 0x17cf: 0x0008, 0x17d0: 0x0008, 0x17d1: 0x0040, + 0x17d2: 0x0040, 0x17d3: 0x0008, 0x17d4: 0x0008, 0x17d5: 0x0008, 0x17d6: 0x0008, 0x17d7: 0x0008, + 0x17d8: 0x0008, 0x17d9: 0x0008, 0x17da: 0x0008, 0x17db: 0x0008, 0x17dc: 0x0008, 0x17dd: 0x0008, + 0x17de: 0x0008, 0x17df: 0x0008, 0x17e0: 0x0008, 0x17e1: 0x0008, 0x17e2: 0x0008, 0x17e3: 0x0008, + 0x17e4: 0x0008, 0x17e5: 0x0008, 0x17e6: 0x0008, 0x17e7: 0x0008, 0x17e8: 0x0008, 0x17e9: 0x0040, + 0x17ea: 0x0008, 0x17eb: 0x0008, 0x17ec: 0x0008, 0x17ed: 0x0008, 0x17ee: 0x0008, 0x17ef: 0x0008, + 0x17f0: 0x0008, 0x17f1: 0x0040, 0x17f2: 0x0008, 0x17f3: 0x0008, 0x17f4: 0x0040, 0x17f5: 0x0008, + 0x17f6: 0x0008, 0x17f7: 0x0008, 0x17f8: 0x0008, 0x17f9: 0x0008, 0x17fa: 0x0040, 0x17fb: 0x0040, + 0x17fc: 0x3308, 0x17fd: 0x0008, 0x17fe: 0x3008, 0x17ff: 0x3008, + // Block 0x60, offset 0x1800 + 0x1800: 0x3308, 0x1801: 0x3008, 0x1802: 0x3008, 0x1803: 0x3008, 0x1804: 0x3008, 0x1805: 0x0040, + 0x1806: 0x0040, 0x1807: 0x3008, 0x1808: 0x3008, 0x1809: 0x0040, 0x180a: 0x0040, 0x180b: 0x3008, + 0x180c: 0x3008, 0x180d: 0x3808, 0x180e: 0x0040, 0x180f: 0x0040, 0x1810: 0x0008, 0x1811: 0x0040, + 0x1812: 0x0040, 0x1813: 0x0040, 0x1814: 0x0040, 0x1815: 0x0040, 0x1816: 0x0040, 0x1817: 0x3008, + 0x1818: 0x0040, 0x1819: 0x0040, 0x181a: 0x0040, 0x181b: 0x0040, 0x181c: 0x0040, 0x181d: 0x0008, + 0x181e: 0x0008, 0x181f: 0x0008, 0x1820: 0x0008, 0x1821: 0x0008, 0x1822: 0x3008, 0x1823: 0x3008, + 0x1824: 0x0040, 0x1825: 0x0040, 0x1826: 0x3308, 0x1827: 0x3308, 0x1828: 0x3308, 0x1829: 0x3308, + 0x182a: 0x3308, 0x182b: 0x3308, 0x182c: 0x3308, 0x182d: 0x0040, 0x182e: 0x0040, 0x182f: 0x0040, + 0x1830: 0x3308, 0x1831: 0x3308, 0x1832: 0x3308, 0x1833: 0x3308, 0x1834: 0x3308, 0x1835: 0x0040, + 0x1836: 0x0040, 0x1837: 0x0040, 0x1838: 0x0040, 0x1839: 0x0040, 0x183a: 0x0040, 0x183b: 0x0040, + 0x183c: 0x0040, 0x183d: 0x0040, 0x183e: 0x0040, 0x183f: 0x0040, + // Block 0x61, offset 0x1840 + 0x1840: 0x0039, 0x1841: 0x0ee9, 0x1842: 0x1159, 0x1843: 0x0ef9, 0x1844: 0x0f09, 0x1845: 0x1199, + 0x1846: 0x0f31, 0x1847: 0x0249, 0x1848: 0x0f41, 0x1849: 0x0259, 0x184a: 0x0f51, 0x184b: 0x0359, + 0x184c: 0x0f61, 0x184d: 0x0f71, 0x184e: 0x00d9, 0x184f: 0x0f99, 0x1850: 0x2039, 0x1851: 0x0269, + 0x1852: 0x01d9, 0x1853: 0x0fa9, 0x1854: 0x0fb9, 0x1855: 0x1089, 0x1856: 0x0279, 0x1857: 0x0369, + 0x1858: 0x0289, 0x1859: 0x13d1, 0x185a: 0x0039, 0x185b: 0x0ee9, 0x185c: 0x1159, 0x185d: 0x0ef9, + 0x185e: 0x0f09, 0x185f: 0x1199, 0x1860: 0x0f31, 0x1861: 0x0249, 0x1862: 0x0f41, 0x1863: 0x0259, + 0x1864: 0x0f51, 0x1865: 0x0359, 0x1866: 0x0f61, 0x1867: 0x0f71, 0x1868: 0x00d9, 0x1869: 0x0f99, + 0x186a: 0x2039, 0x186b: 0x0269, 0x186c: 0x01d9, 0x186d: 0x0fa9, 0x186e: 0x0fb9, 0x186f: 0x1089, + 0x1870: 0x0279, 0x1871: 0x0369, 0x1872: 0x0289, 0x1873: 0x13d1, 0x1874: 0x0039, 0x1875: 0x0ee9, + 0x1876: 0x1159, 0x1877: 0x0ef9, 0x1878: 0x0f09, 0x1879: 0x1199, 0x187a: 0x0f31, 0x187b: 0x0249, + 0x187c: 0x0f41, 0x187d: 0x0259, 0x187e: 0x0f51, 0x187f: 0x0359, + // Block 0x62, offset 0x1880 + 0x1880: 0x0f61, 0x1881: 0x0f71, 0x1882: 0x00d9, 0x1883: 0x0f99, 0x1884: 0x2039, 0x1885: 0x0269, + 0x1886: 0x01d9, 0x1887: 0x0fa9, 0x1888: 0x0fb9, 0x1889: 0x1089, 0x188a: 0x0279, 0x188b: 0x0369, + 0x188c: 0x0289, 0x188d: 0x13d1, 0x188e: 0x0039, 0x188f: 0x0ee9, 0x1890: 0x1159, 0x1891: 0x0ef9, + 0x1892: 0x0f09, 0x1893: 0x1199, 0x1894: 0x0f31, 0x1895: 0x0040, 0x1896: 0x0f41, 0x1897: 0x0259, + 0x1898: 0x0f51, 0x1899: 0x0359, 0x189a: 0x0f61, 0x189b: 0x0f71, 0x189c: 0x00d9, 0x189d: 0x0f99, + 0x189e: 0x2039, 0x189f: 0x0269, 0x18a0: 0x01d9, 0x18a1: 0x0fa9, 0x18a2: 0x0fb9, 0x18a3: 0x1089, + 0x18a4: 0x0279, 0x18a5: 0x0369, 0x18a6: 0x0289, 0x18a7: 0x13d1, 0x18a8: 0x0039, 0x18a9: 0x0ee9, + 0x18aa: 0x1159, 0x18ab: 0x0ef9, 0x18ac: 0x0f09, 0x18ad: 0x1199, 0x18ae: 0x0f31, 0x18af: 0x0249, + 0x18b0: 0x0f41, 0x18b1: 0x0259, 0x18b2: 0x0f51, 0x18b3: 0x0359, 0x18b4: 0x0f61, 0x18b5: 0x0f71, + 0x18b6: 0x00d9, 0x18b7: 0x0f99, 0x18b8: 0x2039, 0x18b9: 0x0269, 0x18ba: 0x01d9, 0x18bb: 0x0fa9, + 0x18bc: 0x0fb9, 0x18bd: 0x1089, 0x18be: 0x0279, 0x18bf: 0x0369, + // Block 0x63, offset 0x18c0 + 0x18c0: 0x0289, 0x18c1: 0x13d1, 0x18c2: 0x0039, 0x18c3: 0x0ee9, 0x18c4: 0x1159, 0x18c5: 0x0ef9, + 0x18c6: 0x0f09, 0x18c7: 0x1199, 0x18c8: 0x0f31, 0x18c9: 0x0249, 0x18ca: 0x0f41, 0x18cb: 0x0259, + 0x18cc: 0x0f51, 0x18cd: 0x0359, 0x18ce: 0x0f61, 0x18cf: 0x0f71, 0x18d0: 0x00d9, 0x18d1: 0x0f99, + 0x18d2: 0x2039, 0x18d3: 0x0269, 0x18d4: 0x01d9, 0x18d5: 0x0fa9, 0x18d6: 0x0fb9, 0x18d7: 0x1089, + 0x18d8: 0x0279, 0x18d9: 0x0369, 0x18da: 0x0289, 0x18db: 0x13d1, 0x18dc: 0x0039, 0x18dd: 0x0040, + 0x18de: 0x1159, 0x18df: 0x0ef9, 0x18e0: 0x0040, 0x18e1: 0x0040, 0x18e2: 0x0f31, 0x18e3: 0x0040, + 0x18e4: 0x0040, 0x18e5: 0x0259, 0x18e6: 0x0f51, 0x18e7: 0x0040, 0x18e8: 0x0040, 0x18e9: 0x0f71, + 0x18ea: 0x00d9, 0x18eb: 0x0f99, 0x18ec: 0x2039, 0x18ed: 0x0040, 0x18ee: 0x01d9, 0x18ef: 0x0fa9, + 0x18f0: 0x0fb9, 0x18f1: 0x1089, 0x18f2: 0x0279, 0x18f3: 0x0369, 0x18f4: 0x0289, 0x18f5: 0x13d1, + 0x18f6: 0x0039, 0x18f7: 0x0ee9, 0x18f8: 0x1159, 0x18f9: 0x0ef9, 0x18fa: 0x0040, 0x18fb: 0x1199, + 0x18fc: 0x0040, 0x18fd: 0x0249, 0x18fe: 0x0f41, 0x18ff: 0x0259, + // Block 0x64, offset 0x1900 + 0x1900: 0x0f51, 0x1901: 0x0359, 0x1902: 0x0f61, 0x1903: 0x0f71, 0x1904: 0x0040, 0x1905: 0x0f99, + 0x1906: 0x2039, 0x1907: 0x0269, 0x1908: 0x01d9, 0x1909: 0x0fa9, 0x190a: 0x0fb9, 0x190b: 0x1089, + 0x190c: 0x0279, 0x190d: 0x0369, 0x190e: 0x0289, 0x190f: 0x13d1, 0x1910: 0x0039, 0x1911: 0x0ee9, + 0x1912: 0x1159, 0x1913: 0x0ef9, 0x1914: 0x0f09, 0x1915: 0x1199, 0x1916: 0x0f31, 0x1917: 0x0249, + 0x1918: 0x0f41, 0x1919: 0x0259, 0x191a: 0x0f51, 0x191b: 0x0359, 0x191c: 0x0f61, 0x191d: 0x0f71, + 0x191e: 0x00d9, 0x191f: 0x0f99, 0x1920: 0x2039, 0x1921: 0x0269, 0x1922: 0x01d9, 0x1923: 0x0fa9, + 0x1924: 0x0fb9, 0x1925: 0x1089, 0x1926: 0x0279, 0x1927: 0x0369, 0x1928: 0x0289, 0x1929: 0x13d1, + 0x192a: 0x0039, 0x192b: 0x0ee9, 0x192c: 0x1159, 0x192d: 0x0ef9, 0x192e: 0x0f09, 0x192f: 0x1199, + 0x1930: 0x0f31, 0x1931: 0x0249, 0x1932: 0x0f41, 0x1933: 0x0259, 0x1934: 0x0f51, 0x1935: 0x0359, + 0x1936: 0x0f61, 0x1937: 0x0f71, 0x1938: 0x00d9, 0x1939: 0x0f99, 0x193a: 0x2039, 0x193b: 0x0269, + 0x193c: 0x01d9, 0x193d: 0x0fa9, 0x193e: 0x0fb9, 0x193f: 0x1089, + // Block 0x65, offset 0x1940 + 0x1940: 0x0279, 0x1941: 0x0369, 0x1942: 0x0289, 0x1943: 0x13d1, 0x1944: 0x0039, 0x1945: 0x0ee9, + 0x1946: 0x0040, 0x1947: 0x0ef9, 0x1948: 0x0f09, 0x1949: 0x1199, 0x194a: 0x0f31, 0x194b: 0x0040, + 0x194c: 0x0040, 0x194d: 0x0259, 0x194e: 0x0f51, 0x194f: 0x0359, 0x1950: 0x0f61, 0x1951: 0x0f71, + 0x1952: 0x00d9, 0x1953: 0x0f99, 0x1954: 0x2039, 0x1955: 0x0040, 0x1956: 0x01d9, 0x1957: 0x0fa9, + 0x1958: 0x0fb9, 0x1959: 0x1089, 0x195a: 0x0279, 0x195b: 0x0369, 0x195c: 0x0289, 0x195d: 0x0040, + 0x195e: 0x0039, 0x195f: 0x0ee9, 0x1960: 0x1159, 0x1961: 0x0ef9, 0x1962: 0x0f09, 0x1963: 0x1199, + 0x1964: 0x0f31, 0x1965: 0x0249, 0x1966: 0x0f41, 0x1967: 0x0259, 0x1968: 0x0f51, 0x1969: 0x0359, + 0x196a: 0x0f61, 0x196b: 0x0f71, 0x196c: 0x00d9, 0x196d: 0x0f99, 0x196e: 0x2039, 0x196f: 0x0269, + 0x1970: 0x01d9, 0x1971: 0x0fa9, 0x1972: 0x0fb9, 0x1973: 0x1089, 0x1974: 0x0279, 0x1975: 0x0369, + 0x1976: 0x0289, 0x1977: 0x13d1, 0x1978: 0x0039, 0x1979: 0x0ee9, 0x197a: 0x0040, 0x197b: 0x0ef9, + 0x197c: 0x0f09, 0x197d: 0x1199, 0x197e: 0x0f31, 0x197f: 0x0040, + // Block 0x66, offset 0x1980 + 0x1980: 0x0f41, 0x1981: 0x0259, 0x1982: 0x0f51, 0x1983: 0x0359, 0x1984: 0x0f61, 0x1985: 0x0040, + 0x1986: 0x00d9, 0x1987: 0x0040, 0x1988: 0x0040, 0x1989: 0x0040, 0x198a: 0x01d9, 0x198b: 0x0fa9, + 0x198c: 0x0fb9, 0x198d: 0x1089, 0x198e: 0x0279, 0x198f: 0x0369, 0x1990: 0x0289, 0x1991: 0x0040, + 0x1992: 0x0039, 0x1993: 0x0ee9, 0x1994: 0x1159, 0x1995: 0x0ef9, 0x1996: 0x0f09, 0x1997: 0x1199, + 0x1998: 0x0f31, 0x1999: 0x0249, 0x199a: 0x0f41, 0x199b: 0x0259, 0x199c: 0x0f51, 0x199d: 0x0359, + 0x199e: 0x0f61, 0x199f: 0x0f71, 0x19a0: 0x00d9, 0x19a1: 0x0f99, 0x19a2: 0x2039, 0x19a3: 0x0269, + 0x19a4: 0x01d9, 0x19a5: 0x0fa9, 0x19a6: 0x0fb9, 0x19a7: 0x1089, 0x19a8: 0x0279, 0x19a9: 0x0369, + 0x19aa: 0x0289, 0x19ab: 0x13d1, 0x19ac: 0x0039, 0x19ad: 0x0ee9, 0x19ae: 0x1159, 0x19af: 0x0ef9, + 0x19b0: 0x0f09, 0x19b1: 0x1199, 0x19b2: 0x0f31, 0x19b3: 0x0249, 0x19b4: 0x0f41, 0x19b5: 0x0259, + 0x19b6: 0x0f51, 0x19b7: 0x0359, 0x19b8: 0x0f61, 0x19b9: 0x0f71, 0x19ba: 0x00d9, 0x19bb: 0x0f99, + 0x19bc: 0x2039, 0x19bd: 0x0269, 0x19be: 0x01d9, 0x19bf: 0x0fa9, + // Block 0x67, offset 0x19c0 + 0x19c0: 0x0fb9, 0x19c1: 0x1089, 0x19c2: 0x0279, 0x19c3: 0x0369, 0x19c4: 0x0289, 0x19c5: 0x13d1, + 0x19c6: 0x0039, 0x19c7: 0x0ee9, 0x19c8: 0x1159, 0x19c9: 0x0ef9, 0x19ca: 0x0f09, 0x19cb: 0x1199, + 0x19cc: 0x0f31, 0x19cd: 0x0249, 0x19ce: 0x0f41, 0x19cf: 0x0259, 0x19d0: 0x0f51, 0x19d1: 0x0359, + 0x19d2: 0x0f61, 0x19d3: 0x0f71, 0x19d4: 0x00d9, 0x19d5: 0x0f99, 0x19d6: 0x2039, 0x19d7: 0x0269, + 0x19d8: 0x01d9, 0x19d9: 0x0fa9, 0x19da: 0x0fb9, 0x19db: 0x1089, 0x19dc: 0x0279, 0x19dd: 0x0369, + 0x19de: 0x0289, 0x19df: 0x13d1, 0x19e0: 0x0039, 0x19e1: 0x0ee9, 0x19e2: 0x1159, 0x19e3: 0x0ef9, + 0x19e4: 0x0f09, 0x19e5: 0x1199, 0x19e6: 0x0f31, 0x19e7: 0x0249, 0x19e8: 0x0f41, 0x19e9: 0x0259, + 0x19ea: 0x0f51, 0x19eb: 0x0359, 0x19ec: 0x0f61, 0x19ed: 0x0f71, 0x19ee: 0x00d9, 0x19ef: 0x0f99, + 0x19f0: 0x2039, 0x19f1: 0x0269, 0x19f2: 0x01d9, 0x19f3: 0x0fa9, 0x19f4: 0x0fb9, 0x19f5: 0x1089, + 0x19f6: 0x0279, 0x19f7: 0x0369, 0x19f8: 0x0289, 0x19f9: 0x13d1, 0x19fa: 0x0039, 0x19fb: 0x0ee9, + 0x19fc: 0x1159, 0x19fd: 0x0ef9, 0x19fe: 0x0f09, 0x19ff: 0x1199, + // Block 0x68, offset 0x1a00 + 0x1a00: 0x0f31, 0x1a01: 0x0249, 0x1a02: 0x0f41, 0x1a03: 0x0259, 0x1a04: 0x0f51, 0x1a05: 0x0359, + 0x1a06: 0x0f61, 0x1a07: 0x0f71, 0x1a08: 0x00d9, 0x1a09: 0x0f99, 0x1a0a: 0x2039, 0x1a0b: 0x0269, + 0x1a0c: 0x01d9, 0x1a0d: 0x0fa9, 0x1a0e: 0x0fb9, 0x1a0f: 0x1089, 0x1a10: 0x0279, 0x1a11: 0x0369, + 0x1a12: 0x0289, 0x1a13: 0x13d1, 0x1a14: 0x0039, 0x1a15: 0x0ee9, 0x1a16: 0x1159, 0x1a17: 0x0ef9, + 0x1a18: 0x0f09, 0x1a19: 0x1199, 0x1a1a: 0x0f31, 0x1a1b: 0x0249, 0x1a1c: 0x0f41, 0x1a1d: 0x0259, + 0x1a1e: 0x0f51, 0x1a1f: 0x0359, 0x1a20: 0x0f61, 0x1a21: 0x0f71, 0x1a22: 0x00d9, 0x1a23: 0x0f99, + 0x1a24: 0x2039, 0x1a25: 0x0269, 0x1a26: 0x01d9, 0x1a27: 0x0fa9, 0x1a28: 0x0fb9, 0x1a29: 0x1089, + 0x1a2a: 0x0279, 0x1a2b: 0x0369, 0x1a2c: 0x0289, 0x1a2d: 0x13d1, 0x1a2e: 0x0039, 0x1a2f: 0x0ee9, + 0x1a30: 0x1159, 0x1a31: 0x0ef9, 0x1a32: 0x0f09, 0x1a33: 0x1199, 0x1a34: 0x0f31, 0x1a35: 0x0249, + 0x1a36: 0x0f41, 0x1a37: 0x0259, 0x1a38: 0x0f51, 0x1a39: 0x0359, 0x1a3a: 0x0f61, 0x1a3b: 0x0f71, + 0x1a3c: 0x00d9, 0x1a3d: 0x0f99, 0x1a3e: 0x2039, 0x1a3f: 0x0269, + // Block 0x69, offset 0x1a40 + 0x1a40: 0x01d9, 0x1a41: 0x0fa9, 0x1a42: 0x0fb9, 0x1a43: 0x1089, 0x1a44: 0x0279, 0x1a45: 0x0369, + 0x1a46: 0x0289, 0x1a47: 0x13d1, 0x1a48: 0x0039, 0x1a49: 0x0ee9, 0x1a4a: 0x1159, 0x1a4b: 0x0ef9, + 0x1a4c: 0x0f09, 0x1a4d: 0x1199, 0x1a4e: 0x0f31, 0x1a4f: 0x0249, 0x1a50: 0x0f41, 0x1a51: 0x0259, + 0x1a52: 0x0f51, 0x1a53: 0x0359, 0x1a54: 0x0f61, 0x1a55: 0x0f71, 0x1a56: 0x00d9, 0x1a57: 0x0f99, + 0x1a58: 0x2039, 0x1a59: 0x0269, 0x1a5a: 0x01d9, 0x1a5b: 0x0fa9, 0x1a5c: 0x0fb9, 0x1a5d: 0x1089, + 0x1a5e: 0x0279, 0x1a5f: 0x0369, 0x1a60: 0x0289, 0x1a61: 0x13d1, 0x1a62: 0x0039, 0x1a63: 0x0ee9, + 0x1a64: 0x1159, 0x1a65: 0x0ef9, 0x1a66: 0x0f09, 0x1a67: 0x1199, 0x1a68: 0x0f31, 0x1a69: 0x0249, + 0x1a6a: 0x0f41, 0x1a6b: 0x0259, 0x1a6c: 0x0f51, 0x1a6d: 0x0359, 0x1a6e: 0x0f61, 0x1a6f: 0x0f71, + 0x1a70: 0x00d9, 0x1a71: 0x0f99, 0x1a72: 0x2039, 0x1a73: 0x0269, 0x1a74: 0x01d9, 0x1a75: 0x0fa9, + 0x1a76: 0x0fb9, 0x1a77: 0x1089, 0x1a78: 0x0279, 0x1a79: 0x0369, 0x1a7a: 0x0289, 0x1a7b: 0x13d1, + 0x1a7c: 0x0039, 0x1a7d: 0x0ee9, 0x1a7e: 0x1159, 0x1a7f: 0x0ef9, + // Block 0x6a, offset 0x1a80 + 0x1a80: 0x0f09, 0x1a81: 0x1199, 0x1a82: 0x0f31, 0x1a83: 0x0249, 0x1a84: 0x0f41, 0x1a85: 0x0259, + 0x1a86: 0x0f51, 0x1a87: 0x0359, 0x1a88: 0x0f61, 0x1a89: 0x0f71, 0x1a8a: 0x00d9, 0x1a8b: 0x0f99, + 0x1a8c: 0x2039, 0x1a8d: 0x0269, 0x1a8e: 0x01d9, 0x1a8f: 0x0fa9, 0x1a90: 0x0fb9, 0x1a91: 0x1089, + 0x1a92: 0x0279, 0x1a93: 0x0369, 0x1a94: 0x0289, 0x1a95: 0x13d1, 0x1a96: 0x0039, 0x1a97: 0x0ee9, + 0x1a98: 0x1159, 0x1a99: 0x0ef9, 0x1a9a: 0x0f09, 0x1a9b: 0x1199, 0x1a9c: 0x0f31, 0x1a9d: 0x0249, + 0x1a9e: 0x0f41, 0x1a9f: 0x0259, 0x1aa0: 0x0f51, 0x1aa1: 0x0359, 0x1aa2: 0x0f61, 0x1aa3: 0x0f71, + 0x1aa4: 0x00d9, 0x1aa5: 0x0f99, 0x1aa6: 0x2039, 0x1aa7: 0x0269, 0x1aa8: 0x01d9, 0x1aa9: 0x0fa9, + 0x1aaa: 0x0fb9, 0x1aab: 0x1089, 0x1aac: 0x0279, 0x1aad: 0x0369, 0x1aae: 0x0289, 0x1aaf: 0x13d1, + 0x1ab0: 0x0039, 0x1ab1: 0x0ee9, 0x1ab2: 0x1159, 0x1ab3: 0x0ef9, 0x1ab4: 0x0f09, 0x1ab5: 0x1199, + 0x1ab6: 0x0f31, 0x1ab7: 0x0249, 0x1ab8: 0x0f41, 0x1ab9: 0x0259, 0x1aba: 0x0f51, 0x1abb: 0x0359, + 0x1abc: 0x0f61, 0x1abd: 0x0f71, 0x1abe: 0x00d9, 0x1abf: 0x0f99, + // Block 0x6b, offset 0x1ac0 + 0x1ac0: 0x2039, 0x1ac1: 0x0269, 0x1ac2: 0x01d9, 0x1ac3: 0x0fa9, 0x1ac4: 0x0fb9, 0x1ac5: 0x1089, + 0x1ac6: 0x0279, 0x1ac7: 0x0369, 0x1ac8: 0x0289, 0x1ac9: 0x13d1, 0x1aca: 0x0039, 0x1acb: 0x0ee9, + 0x1acc: 0x1159, 0x1acd: 0x0ef9, 0x1ace: 0x0f09, 0x1acf: 0x1199, 0x1ad0: 0x0f31, 0x1ad1: 0x0249, + 0x1ad2: 0x0f41, 0x1ad3: 0x0259, 0x1ad4: 0x0f51, 0x1ad5: 0x0359, 0x1ad6: 0x0f61, 0x1ad7: 0x0f71, + 0x1ad8: 0x00d9, 0x1ad9: 0x0f99, 0x1ada: 0x2039, 0x1adb: 0x0269, 0x1adc: 0x01d9, 0x1add: 0x0fa9, + 0x1ade: 0x0fb9, 0x1adf: 0x1089, 0x1ae0: 0x0279, 0x1ae1: 0x0369, 0x1ae2: 0x0289, 0x1ae3: 0x13d1, + 0x1ae4: 0xba81, 0x1ae5: 0xba99, 0x1ae6: 0x0040, 0x1ae7: 0x0040, 0x1ae8: 0xbab1, 0x1ae9: 0x1099, + 0x1aea: 0x10b1, 0x1aeb: 0x10c9, 0x1aec: 0xbac9, 0x1aed: 0xbae1, 0x1aee: 0xbaf9, 0x1aef: 0x1429, + 0x1af0: 0x1a31, 0x1af1: 0xbb11, 0x1af2: 0xbb29, 0x1af3: 0xbb41, 0x1af4: 0xbb59, 0x1af5: 0xbb71, + 0x1af6: 0xbb89, 0x1af7: 0x2109, 0x1af8: 0x1111, 0x1af9: 0x1429, 0x1afa: 0xbba1, 0x1afb: 0xbbb9, + 0x1afc: 0xbbd1, 0x1afd: 0x10e1, 0x1afe: 0x10f9, 0x1aff: 0xbbe9, + // Block 0x6c, offset 0x1b00 + 0x1b00: 0x2079, 0x1b01: 0xbc01, 0x1b02: 0xbab1, 0x1b03: 0x1099, 0x1b04: 0x10b1, 0x1b05: 0x10c9, + 0x1b06: 0xbac9, 0x1b07: 0xbae1, 0x1b08: 0xbaf9, 0x1b09: 0x1429, 0x1b0a: 0x1a31, 0x1b0b: 0xbb11, + 0x1b0c: 0xbb29, 0x1b0d: 0xbb41, 0x1b0e: 0xbb59, 0x1b0f: 0xbb71, 0x1b10: 0xbb89, 0x1b11: 0x2109, + 0x1b12: 0x1111, 0x1b13: 0xbba1, 0x1b14: 0xbba1, 0x1b15: 0xbbb9, 0x1b16: 0xbbd1, 0x1b17: 0x10e1, + 0x1b18: 0x10f9, 0x1b19: 0xbbe9, 0x1b1a: 0x2079, 0x1b1b: 0xbc21, 0x1b1c: 0xbac9, 0x1b1d: 0x1429, + 0x1b1e: 0xbb11, 0x1b1f: 0x10e1, 0x1b20: 0x1111, 0x1b21: 0x2109, 0x1b22: 0xbab1, 0x1b23: 0x1099, + 0x1b24: 0x10b1, 0x1b25: 0x10c9, 0x1b26: 0xbac9, 0x1b27: 0xbae1, 0x1b28: 0xbaf9, 0x1b29: 0x1429, + 0x1b2a: 0x1a31, 0x1b2b: 0xbb11, 0x1b2c: 0xbb29, 0x1b2d: 0xbb41, 0x1b2e: 0xbb59, 0x1b2f: 0xbb71, + 0x1b30: 0xbb89, 0x1b31: 0x2109, 0x1b32: 0x1111, 0x1b33: 0x1429, 0x1b34: 0xbba1, 0x1b35: 0xbbb9, + 0x1b36: 0xbbd1, 0x1b37: 0x10e1, 0x1b38: 0x10f9, 0x1b39: 0xbbe9, 0x1b3a: 0x2079, 0x1b3b: 0xbc01, + 0x1b3c: 0xbab1, 0x1b3d: 0x1099, 0x1b3e: 0x10b1, 0x1b3f: 0x10c9, + // Block 0x6d, offset 0x1b40 + 0x1b40: 0xbac9, 0x1b41: 0xbae1, 0x1b42: 0xbaf9, 0x1b43: 0x1429, 0x1b44: 0x1a31, 0x1b45: 0xbb11, + 0x1b46: 0xbb29, 0x1b47: 0xbb41, 0x1b48: 0xbb59, 0x1b49: 0xbb71, 0x1b4a: 0xbb89, 0x1b4b: 0x2109, + 0x1b4c: 0x1111, 0x1b4d: 0xbba1, 0x1b4e: 0xbba1, 0x1b4f: 0xbbb9, 0x1b50: 0xbbd1, 0x1b51: 0x10e1, + 0x1b52: 0x10f9, 0x1b53: 0xbbe9, 0x1b54: 0x2079, 0x1b55: 0xbc21, 0x1b56: 0xbac9, 0x1b57: 0x1429, + 0x1b58: 0xbb11, 0x1b59: 0x10e1, 0x1b5a: 0x1111, 0x1b5b: 0x2109, 0x1b5c: 0xbab1, 0x1b5d: 0x1099, + 0x1b5e: 0x10b1, 0x1b5f: 0x10c9, 0x1b60: 0xbac9, 0x1b61: 0xbae1, 0x1b62: 0xbaf9, 0x1b63: 0x1429, + 0x1b64: 0x1a31, 0x1b65: 0xbb11, 0x1b66: 0xbb29, 0x1b67: 0xbb41, 0x1b68: 0xbb59, 0x1b69: 0xbb71, + 0x1b6a: 0xbb89, 0x1b6b: 0x2109, 0x1b6c: 0x1111, 0x1b6d: 0x1429, 0x1b6e: 0xbba1, 0x1b6f: 0xbbb9, + 0x1b70: 0xbbd1, 0x1b71: 0x10e1, 0x1b72: 0x10f9, 0x1b73: 0xbbe9, 0x1b74: 0x2079, 0x1b75: 0xbc01, + 0x1b76: 0xbab1, 0x1b77: 0x1099, 0x1b78: 0x10b1, 0x1b79: 0x10c9, 0x1b7a: 0xbac9, 0x1b7b: 0xbae1, + 0x1b7c: 0xbaf9, 0x1b7d: 0x1429, 0x1b7e: 0x1a31, 0x1b7f: 0xbb11, + // Block 0x6e, offset 0x1b80 + 0x1b80: 0xbb29, 0x1b81: 0xbb41, 0x1b82: 0xbb59, 0x1b83: 0xbb71, 0x1b84: 0xbb89, 0x1b85: 0x2109, + 0x1b86: 0x1111, 0x1b87: 0xbba1, 0x1b88: 0xbba1, 0x1b89: 0xbbb9, 0x1b8a: 0xbbd1, 0x1b8b: 0x10e1, + 0x1b8c: 0x10f9, 0x1b8d: 0xbbe9, 0x1b8e: 0x2079, 0x1b8f: 0xbc21, 0x1b90: 0xbac9, 0x1b91: 0x1429, + 0x1b92: 0xbb11, 0x1b93: 0x10e1, 0x1b94: 0x1111, 0x1b95: 0x2109, 0x1b96: 0xbab1, 0x1b97: 0x1099, + 0x1b98: 0x10b1, 0x1b99: 0x10c9, 0x1b9a: 0xbac9, 0x1b9b: 0xbae1, 0x1b9c: 0xbaf9, 0x1b9d: 0x1429, + 0x1b9e: 0x1a31, 0x1b9f: 0xbb11, 0x1ba0: 0xbb29, 0x1ba1: 0xbb41, 0x1ba2: 0xbb59, 0x1ba3: 0xbb71, + 0x1ba4: 0xbb89, 0x1ba5: 0x2109, 0x1ba6: 0x1111, 0x1ba7: 0x1429, 0x1ba8: 0xbba1, 0x1ba9: 0xbbb9, + 0x1baa: 0xbbd1, 0x1bab: 0x10e1, 0x1bac: 0x10f9, 0x1bad: 0xbbe9, 0x1bae: 0x2079, 0x1baf: 0xbc01, + 0x1bb0: 0xbab1, 0x1bb1: 0x1099, 0x1bb2: 0x10b1, 0x1bb3: 0x10c9, 0x1bb4: 0xbac9, 0x1bb5: 0xbae1, + 0x1bb6: 0xbaf9, 0x1bb7: 0x1429, 0x1bb8: 0x1a31, 0x1bb9: 0xbb11, 0x1bba: 0xbb29, 0x1bbb: 0xbb41, + 0x1bbc: 0xbb59, 0x1bbd: 0xbb71, 0x1bbe: 0xbb89, 0x1bbf: 0x2109, + // Block 0x6f, offset 0x1bc0 + 0x1bc0: 0x1111, 0x1bc1: 0xbba1, 0x1bc2: 0xbba1, 0x1bc3: 0xbbb9, 0x1bc4: 0xbbd1, 0x1bc5: 0x10e1, + 0x1bc6: 0x10f9, 0x1bc7: 0xbbe9, 0x1bc8: 0x2079, 0x1bc9: 0xbc21, 0x1bca: 0xbac9, 0x1bcb: 0x1429, + 0x1bcc: 0xbb11, 0x1bcd: 0x10e1, 0x1bce: 0x1111, 0x1bcf: 0x2109, 0x1bd0: 0xbab1, 0x1bd1: 0x1099, + 0x1bd2: 0x10b1, 0x1bd3: 0x10c9, 0x1bd4: 0xbac9, 0x1bd5: 0xbae1, 0x1bd6: 0xbaf9, 0x1bd7: 0x1429, + 0x1bd8: 0x1a31, 0x1bd9: 0xbb11, 0x1bda: 0xbb29, 0x1bdb: 0xbb41, 0x1bdc: 0xbb59, 0x1bdd: 0xbb71, + 0x1bde: 0xbb89, 0x1bdf: 0x2109, 0x1be0: 0x1111, 0x1be1: 0x1429, 0x1be2: 0xbba1, 0x1be3: 0xbbb9, + 0x1be4: 0xbbd1, 0x1be5: 0x10e1, 0x1be6: 0x10f9, 0x1be7: 0xbbe9, 0x1be8: 0x2079, 0x1be9: 0xbc01, + 0x1bea: 0xbab1, 0x1beb: 0x1099, 0x1bec: 0x10b1, 0x1bed: 0x10c9, 0x1bee: 0xbac9, 0x1bef: 0xbae1, + 0x1bf0: 0xbaf9, 0x1bf1: 0x1429, 0x1bf2: 0x1a31, 0x1bf3: 0xbb11, 0x1bf4: 0xbb29, 0x1bf5: 0xbb41, + 0x1bf6: 0xbb59, 0x1bf7: 0xbb71, 0x1bf8: 0xbb89, 0x1bf9: 0x2109, 0x1bfa: 0x1111, 0x1bfb: 0xbba1, + 0x1bfc: 0xbba1, 0x1bfd: 0xbbb9, 0x1bfe: 0xbbd1, 0x1bff: 0x10e1, + // Block 0x70, offset 0x1c00 + 0x1c00: 0x10f9, 0x1c01: 0xbbe9, 0x1c02: 0x2079, 0x1c03: 0xbc21, 0x1c04: 0xbac9, 0x1c05: 0x1429, + 0x1c06: 0xbb11, 0x1c07: 0x10e1, 0x1c08: 0x1111, 0x1c09: 0x2109, 0x1c0a: 0xbc41, 0x1c0b: 0xbc41, + 0x1c0c: 0x0040, 0x1c0d: 0x0040, 0x1c0e: 0x1f41, 0x1c0f: 0x00c9, 0x1c10: 0x0069, 0x1c11: 0x0079, + 0x1c12: 0x1f51, 0x1c13: 0x1f61, 0x1c14: 0x1f71, 0x1c15: 0x1f81, 0x1c16: 0x1f91, 0x1c17: 0x1fa1, + 0x1c18: 0x1f41, 0x1c19: 0x00c9, 0x1c1a: 0x0069, 0x1c1b: 0x0079, 0x1c1c: 0x1f51, 0x1c1d: 0x1f61, + 0x1c1e: 0x1f71, 0x1c1f: 0x1f81, 0x1c20: 0x1f91, 0x1c21: 0x1fa1, 0x1c22: 0x1f41, 0x1c23: 0x00c9, + 0x1c24: 0x0069, 0x1c25: 0x0079, 0x1c26: 0x1f51, 0x1c27: 0x1f61, 0x1c28: 0x1f71, 0x1c29: 0x1f81, + 0x1c2a: 0x1f91, 0x1c2b: 0x1fa1, 0x1c2c: 0x1f41, 0x1c2d: 0x00c9, 0x1c2e: 0x0069, 0x1c2f: 0x0079, + 0x1c30: 0x1f51, 0x1c31: 0x1f61, 0x1c32: 0x1f71, 0x1c33: 0x1f81, 0x1c34: 0x1f91, 0x1c35: 0x1fa1, + 0x1c36: 0x1f41, 0x1c37: 0x00c9, 0x1c38: 0x0069, 0x1c39: 0x0079, 0x1c3a: 0x1f51, 0x1c3b: 0x1f61, + 0x1c3c: 0x1f71, 0x1c3d: 0x1f81, 0x1c3e: 0x1f91, 0x1c3f: 0x1fa1, + // Block 0x71, offset 0x1c40 + 0x1c40: 0xe115, 0x1c41: 0xe115, 0x1c42: 0xe135, 0x1c43: 0xe135, 0x1c44: 0xe115, 0x1c45: 0xe115, + 0x1c46: 0xe175, 0x1c47: 0xe175, 0x1c48: 0xe115, 0x1c49: 0xe115, 0x1c4a: 0xe135, 0x1c4b: 0xe135, + 0x1c4c: 0xe115, 0x1c4d: 0xe115, 0x1c4e: 0xe1f5, 0x1c4f: 0xe1f5, 0x1c50: 0xe115, 0x1c51: 0xe115, + 0x1c52: 0xe135, 0x1c53: 0xe135, 0x1c54: 0xe115, 0x1c55: 0xe115, 0x1c56: 0xe175, 0x1c57: 0xe175, + 0x1c58: 0xe115, 0x1c59: 0xe115, 0x1c5a: 0xe135, 0x1c5b: 0xe135, 0x1c5c: 0xe115, 0x1c5d: 0xe115, + 0x1c5e: 0x8b05, 0x1c5f: 0x8b05, 0x1c60: 0x04b5, 0x1c61: 0x04b5, 0x1c62: 0x0a08, 0x1c63: 0x0a08, + 0x1c64: 0x0a08, 0x1c65: 0x0a08, 0x1c66: 0x0a08, 0x1c67: 0x0a08, 0x1c68: 0x0a08, 0x1c69: 0x0a08, + 0x1c6a: 0x0a08, 0x1c6b: 0x0a08, 0x1c6c: 0x0a08, 0x1c6d: 0x0a08, 0x1c6e: 0x0a08, 0x1c6f: 0x0a08, + 0x1c70: 0x0a08, 0x1c71: 0x0a08, 0x1c72: 0x0a08, 0x1c73: 0x0a08, 0x1c74: 0x0a08, 0x1c75: 0x0a08, + 0x1c76: 0x0a08, 0x1c77: 0x0a08, 0x1c78: 0x0a08, 0x1c79: 0x0a08, 0x1c7a: 0x0a08, 0x1c7b: 0x0a08, + 0x1c7c: 0x0a08, 0x1c7d: 0x0a08, 0x1c7e: 0x0a08, 0x1c7f: 0x0a08, + // Block 0x72, offset 0x1c80 + 0x1c80: 0xb189, 0x1c81: 0xb1a1, 0x1c82: 0xb201, 0x1c83: 0xb249, 0x1c84: 0x0040, 0x1c85: 0xb411, + 0x1c86: 0xb291, 0x1c87: 0xb219, 0x1c88: 0xb309, 0x1c89: 0xb429, 0x1c8a: 0xb399, 0x1c8b: 0xb3b1, + 0x1c8c: 0xb3c9, 0x1c8d: 0xb3e1, 0x1c8e: 0xb2a9, 0x1c8f: 0xb339, 0x1c90: 0xb369, 0x1c91: 0xb2d9, + 0x1c92: 0xb381, 0x1c93: 0xb279, 0x1c94: 0xb2c1, 0x1c95: 0xb1d1, 0x1c96: 0xb1e9, 0x1c97: 0xb231, + 0x1c98: 0xb261, 0x1c99: 0xb2f1, 0x1c9a: 0xb321, 0x1c9b: 0xb351, 0x1c9c: 0xbc59, 0x1c9d: 0x7949, + 0x1c9e: 0xbc71, 0x1c9f: 0xbc89, 0x1ca0: 0x0040, 0x1ca1: 0xb1a1, 0x1ca2: 0xb201, 0x1ca3: 0x0040, + 0x1ca4: 0xb3f9, 0x1ca5: 0x0040, 0x1ca6: 0x0040, 0x1ca7: 0xb219, 0x1ca8: 0x0040, 0x1ca9: 0xb429, + 0x1caa: 0xb399, 0x1cab: 0xb3b1, 0x1cac: 0xb3c9, 0x1cad: 0xb3e1, 0x1cae: 0xb2a9, 0x1caf: 0xb339, + 0x1cb0: 0xb369, 0x1cb1: 0xb2d9, 0x1cb2: 0xb381, 0x1cb3: 0x0040, 0x1cb4: 0xb2c1, 0x1cb5: 0xb1d1, + 0x1cb6: 0xb1e9, 0x1cb7: 0xb231, 0x1cb8: 0x0040, 0x1cb9: 0xb2f1, 0x1cba: 0x0040, 0x1cbb: 0xb351, + 0x1cbc: 0x0040, 0x1cbd: 0x0040, 0x1cbe: 0x0040, 0x1cbf: 0x0040, + // Block 0x73, offset 0x1cc0 + 0x1cc0: 0x0040, 0x1cc1: 0x0040, 0x1cc2: 0xb201, 0x1cc3: 0x0040, 0x1cc4: 0x0040, 0x1cc5: 0x0040, + 0x1cc6: 0x0040, 0x1cc7: 0xb219, 0x1cc8: 0x0040, 0x1cc9: 0xb429, 0x1cca: 0x0040, 0x1ccb: 0xb3b1, + 0x1ccc: 0x0040, 0x1ccd: 0xb3e1, 0x1cce: 0xb2a9, 0x1ccf: 0xb339, 0x1cd0: 0x0040, 0x1cd1: 0xb2d9, + 0x1cd2: 0xb381, 0x1cd3: 0x0040, 0x1cd4: 0xb2c1, 0x1cd5: 0x0040, 0x1cd6: 0x0040, 0x1cd7: 0xb231, + 0x1cd8: 0x0040, 0x1cd9: 0xb2f1, 0x1cda: 0x0040, 0x1cdb: 0xb351, 0x1cdc: 0x0040, 0x1cdd: 0x7949, + 0x1cde: 0x0040, 0x1cdf: 0xbc89, 0x1ce0: 0x0040, 0x1ce1: 0xb1a1, 0x1ce2: 0xb201, 0x1ce3: 0x0040, + 0x1ce4: 0xb3f9, 0x1ce5: 0x0040, 0x1ce6: 0x0040, 0x1ce7: 0xb219, 0x1ce8: 0xb309, 0x1ce9: 0xb429, + 0x1cea: 0xb399, 0x1ceb: 0x0040, 0x1cec: 0xb3c9, 0x1ced: 0xb3e1, 0x1cee: 0xb2a9, 0x1cef: 0xb339, + 0x1cf0: 0xb369, 0x1cf1: 0xb2d9, 0x1cf2: 0xb381, 0x1cf3: 0x0040, 0x1cf4: 0xb2c1, 0x1cf5: 0xb1d1, + 0x1cf6: 0xb1e9, 0x1cf7: 0xb231, 0x1cf8: 0x0040, 0x1cf9: 0xb2f1, 0x1cfa: 0xb321, 0x1cfb: 0xb351, + 0x1cfc: 0xbc59, 0x1cfd: 0x0040, 0x1cfe: 0xbc71, 0x1cff: 0x0040, + // Block 0x74, offset 0x1d00 + 0x1d00: 0xb189, 0x1d01: 0xb1a1, 0x1d02: 0xb201, 0x1d03: 0xb249, 0x1d04: 0xb3f9, 0x1d05: 0xb411, + 0x1d06: 0xb291, 0x1d07: 0xb219, 0x1d08: 0xb309, 0x1d09: 0xb429, 0x1d0a: 0x0040, 0x1d0b: 0xb3b1, + 0x1d0c: 0xb3c9, 0x1d0d: 0xb3e1, 0x1d0e: 0xb2a9, 0x1d0f: 0xb339, 0x1d10: 0xb369, 0x1d11: 0xb2d9, + 0x1d12: 0xb381, 0x1d13: 0xb279, 0x1d14: 0xb2c1, 0x1d15: 0xb1d1, 0x1d16: 0xb1e9, 0x1d17: 0xb231, + 0x1d18: 0xb261, 0x1d19: 0xb2f1, 0x1d1a: 0xb321, 0x1d1b: 0xb351, 0x1d1c: 0x0040, 0x1d1d: 0x0040, + 0x1d1e: 0x0040, 0x1d1f: 0x0040, 0x1d20: 0x0040, 0x1d21: 0xb1a1, 0x1d22: 0xb201, 0x1d23: 0xb249, + 0x1d24: 0x0040, 0x1d25: 0xb411, 0x1d26: 0xb291, 0x1d27: 0xb219, 0x1d28: 0xb309, 0x1d29: 0xb429, + 0x1d2a: 0x0040, 0x1d2b: 0xb3b1, 0x1d2c: 0xb3c9, 0x1d2d: 0xb3e1, 0x1d2e: 0xb2a9, 0x1d2f: 0xb339, + 0x1d30: 0xb369, 0x1d31: 0xb2d9, 0x1d32: 0xb381, 0x1d33: 0xb279, 0x1d34: 0xb2c1, 0x1d35: 0xb1d1, + 0x1d36: 0xb1e9, 0x1d37: 0xb231, 0x1d38: 0xb261, 0x1d39: 0xb2f1, 0x1d3a: 0xb321, 0x1d3b: 0xb351, + 0x1d3c: 0x0040, 0x1d3d: 0x0040, 0x1d3e: 0x0040, 0x1d3f: 0x0040, + // Block 0x75, offset 0x1d40 + 0x1d40: 0x0040, 0x1d41: 0xbca2, 0x1d42: 0xbcba, 0x1d43: 0xbcd2, 0x1d44: 0xbcea, 0x1d45: 0xbd02, + 0x1d46: 0xbd1a, 0x1d47: 0xbd32, 0x1d48: 0xbd4a, 0x1d49: 0xbd62, 0x1d4a: 0xbd7a, 0x1d4b: 0x0018, + 0x1d4c: 0x0018, 0x1d4d: 0x0040, 0x1d4e: 0x0040, 0x1d4f: 0x0040, 0x1d50: 0xbd92, 0x1d51: 0xbdb2, + 0x1d52: 0xbdd2, 0x1d53: 0xbdf2, 0x1d54: 0xbe12, 0x1d55: 0xbe32, 0x1d56: 0xbe52, 0x1d57: 0xbe72, + 0x1d58: 0xbe92, 0x1d59: 0xbeb2, 0x1d5a: 0xbed2, 0x1d5b: 0xbef2, 0x1d5c: 0xbf12, 0x1d5d: 0xbf32, + 0x1d5e: 0xbf52, 0x1d5f: 0xbf72, 0x1d60: 0xbf92, 0x1d61: 0xbfb2, 0x1d62: 0xbfd2, 0x1d63: 0xbff2, + 0x1d64: 0xc012, 0x1d65: 0xc032, 0x1d66: 0xc052, 0x1d67: 0xc072, 0x1d68: 0xc092, 0x1d69: 0xc0b2, + 0x1d6a: 0xc0d1, 0x1d6b: 0x1159, 0x1d6c: 0x0269, 0x1d6d: 0x6671, 0x1d6e: 0xc111, 0x1d6f: 0x0040, + 0x1d70: 0x0039, 0x1d71: 0x0ee9, 0x1d72: 0x1159, 0x1d73: 0x0ef9, 0x1d74: 0x0f09, 0x1d75: 0x1199, + 0x1d76: 0x0f31, 0x1d77: 0x0249, 0x1d78: 0x0f41, 0x1d79: 0x0259, 0x1d7a: 0x0f51, 0x1d7b: 0x0359, + 0x1d7c: 0x0f61, 0x1d7d: 0x0f71, 0x1d7e: 0x00d9, 0x1d7f: 0x0f99, + // Block 0x76, offset 0x1d80 + 0x1d80: 0x2039, 0x1d81: 0x0269, 0x1d82: 0x01d9, 0x1d83: 0x0fa9, 0x1d84: 0x0fb9, 0x1d85: 0x1089, + 0x1d86: 0x0279, 0x1d87: 0x0369, 0x1d88: 0x0289, 0x1d89: 0x13d1, 0x1d8a: 0xc129, 0x1d8b: 0x65b1, + 0x1d8c: 0xc141, 0x1d8d: 0x1441, 0x1d8e: 0xc159, 0x1d8f: 0xc179, 0x1d90: 0x0018, 0x1d91: 0x0018, + 0x1d92: 0x0018, 0x1d93: 0x0018, 0x1d94: 0x0018, 0x1d95: 0x0018, 0x1d96: 0x0018, 0x1d97: 0x0018, + 0x1d98: 0x0018, 0x1d99: 0x0018, 0x1d9a: 0x0018, 0x1d9b: 0x0018, 0x1d9c: 0x0018, 0x1d9d: 0x0018, + 0x1d9e: 0x0018, 0x1d9f: 0x0018, 0x1da0: 0x0018, 0x1da1: 0x0018, 0x1da2: 0x0018, 0x1da3: 0x0018, + 0x1da4: 0x0018, 0x1da5: 0x0018, 0x1da6: 0x0018, 0x1da7: 0x0018, 0x1da8: 0x0018, 0x1da9: 0x0018, + 0x1daa: 0xc191, 0x1dab: 0xc1a9, 0x1dac: 0x0040, 0x1dad: 0x0040, 0x1dae: 0x0040, 0x1daf: 0x0040, + 0x1db0: 0x0018, 0x1db1: 0x0018, 0x1db2: 0x0018, 0x1db3: 0x0018, 0x1db4: 0x0018, 0x1db5: 0x0018, + 0x1db6: 0x0018, 0x1db7: 0x0018, 0x1db8: 0x0018, 0x1db9: 0x0018, 0x1dba: 0x0018, 0x1dbb: 0x0018, + 0x1dbc: 0x0018, 0x1dbd: 0x0018, 0x1dbe: 0x0018, 0x1dbf: 0x0018, + // Block 0x77, offset 0x1dc0 + 0x1dc0: 0xc1d9, 0x1dc1: 0xc211, 0x1dc2: 0xc249, 0x1dc3: 0x0040, 0x1dc4: 0x0040, 0x1dc5: 0x0040, + 0x1dc6: 0x0040, 0x1dc7: 0x0040, 0x1dc8: 0x0040, 0x1dc9: 0x0040, 0x1dca: 0x0040, 0x1dcb: 0x0040, + 0x1dcc: 0x0040, 0x1dcd: 0x0040, 0x1dce: 0x0040, 0x1dcf: 0x0040, 0x1dd0: 0xc269, 0x1dd1: 0xc289, + 0x1dd2: 0xc2a9, 0x1dd3: 0xc2c9, 0x1dd4: 0xc2e9, 0x1dd5: 0xc309, 0x1dd6: 0xc329, 0x1dd7: 0xc349, + 0x1dd8: 0xc369, 0x1dd9: 0xc389, 0x1dda: 0xc3a9, 0x1ddb: 0xc3c9, 0x1ddc: 0xc3e9, 0x1ddd: 0xc409, + 0x1dde: 0xc429, 0x1ddf: 0xc449, 0x1de0: 0xc469, 0x1de1: 0xc489, 0x1de2: 0xc4a9, 0x1de3: 0xc4c9, + 0x1de4: 0xc4e9, 0x1de5: 0xc509, 0x1de6: 0xc529, 0x1de7: 0xc549, 0x1de8: 0xc569, 0x1de9: 0xc589, + 0x1dea: 0xc5a9, 0x1deb: 0xc5c9, 0x1dec: 0xc5e9, 0x1ded: 0xc609, 0x1dee: 0xc629, 0x1def: 0xc649, + 0x1df0: 0xc669, 0x1df1: 0xc689, 0x1df2: 0xc6a9, 0x1df3: 0xc6c9, 0x1df4: 0xc6e9, 0x1df5: 0xc709, + 0x1df6: 0xc729, 0x1df7: 0xc749, 0x1df8: 0xc769, 0x1df9: 0xc789, 0x1dfa: 0xc7a9, 0x1dfb: 0xc7c9, + 0x1dfc: 0x0040, 0x1dfd: 0x0040, 0x1dfe: 0x0040, 0x1dff: 0x0040, + // Block 0x78, offset 0x1e00 + 0x1e00: 0xcaf9, 0x1e01: 0xcb19, 0x1e02: 0xcb39, 0x1e03: 0x8b1d, 0x1e04: 0xcb59, 0x1e05: 0xcb79, + 0x1e06: 0xcb99, 0x1e07: 0xcbb9, 0x1e08: 0xcbd9, 0x1e09: 0xcbf9, 0x1e0a: 0xcc19, 0x1e0b: 0xcc39, + 0x1e0c: 0xcc59, 0x1e0d: 0x8b3d, 0x1e0e: 0xcc79, 0x1e0f: 0xcc99, 0x1e10: 0xccb9, 0x1e11: 0xccd9, + 0x1e12: 0x8b5d, 0x1e13: 0xccf9, 0x1e14: 0xcd19, 0x1e15: 0xc429, 0x1e16: 0x8b7d, 0x1e17: 0xcd39, + 0x1e18: 0xcd59, 0x1e19: 0xcd79, 0x1e1a: 0xcd99, 0x1e1b: 0xcdb9, 0x1e1c: 0x8b9d, 0x1e1d: 0xcdd9, + 0x1e1e: 0xcdf9, 0x1e1f: 0xce19, 0x1e20: 0xce39, 0x1e21: 0xce59, 0x1e22: 0xc789, 0x1e23: 0xce79, + 0x1e24: 0xce99, 0x1e25: 0xceb9, 0x1e26: 0xced9, 0x1e27: 0xcef9, 0x1e28: 0xcf19, 0x1e29: 0xcf39, + 0x1e2a: 0xcf59, 0x1e2b: 0xcf79, 0x1e2c: 0xcf99, 0x1e2d: 0xcfb9, 0x1e2e: 0xcfd9, 0x1e2f: 0xcff9, + 0x1e30: 0xd019, 0x1e31: 0xd039, 0x1e32: 0xd039, 0x1e33: 0xd039, 0x1e34: 0x8bbd, 0x1e35: 0xd059, + 0x1e36: 0xd079, 0x1e37: 0xd099, 0x1e38: 0x8bdd, 0x1e39: 0xd0b9, 0x1e3a: 0xd0d9, 0x1e3b: 0xd0f9, + 0x1e3c: 0xd119, 0x1e3d: 0xd139, 0x1e3e: 0xd159, 0x1e3f: 0xd179, + // Block 0x79, offset 0x1e40 + 0x1e40: 0xd199, 0x1e41: 0xd1b9, 0x1e42: 0xd1d9, 0x1e43: 0xd1f9, 0x1e44: 0xd219, 0x1e45: 0xd239, + 0x1e46: 0xd239, 0x1e47: 0xd259, 0x1e48: 0xd279, 0x1e49: 0xd299, 0x1e4a: 0xd2b9, 0x1e4b: 0xd2d9, + 0x1e4c: 0xd2f9, 0x1e4d: 0xd319, 0x1e4e: 0xd339, 0x1e4f: 0xd359, 0x1e50: 0xd379, 0x1e51: 0xd399, + 0x1e52: 0xd3b9, 0x1e53: 0xd3d9, 0x1e54: 0xd3f9, 0x1e55: 0xd419, 0x1e56: 0xd439, 0x1e57: 0xd459, + 0x1e58: 0xd479, 0x1e59: 0x8bfd, 0x1e5a: 0xd499, 0x1e5b: 0xd4b9, 0x1e5c: 0xd4d9, 0x1e5d: 0xc309, + 0x1e5e: 0xd4f9, 0x1e5f: 0xd519, 0x1e60: 0x8c1d, 0x1e61: 0x8c3d, 0x1e62: 0xd539, 0x1e63: 0xd559, + 0x1e64: 0xd579, 0x1e65: 0xd599, 0x1e66: 0xd5b9, 0x1e67: 0xd5d9, 0x1e68: 0x2040, 0x1e69: 0xd5f9, + 0x1e6a: 0xd619, 0x1e6b: 0xd619, 0x1e6c: 0x8c5d, 0x1e6d: 0xd639, 0x1e6e: 0xd659, 0x1e6f: 0xd679, + 0x1e70: 0xd699, 0x1e71: 0x8c7d, 0x1e72: 0xd6b9, 0x1e73: 0xd6d9, 0x1e74: 0x2040, 0x1e75: 0xd6f9, + 0x1e76: 0xd719, 0x1e77: 0xd739, 0x1e78: 0xd759, 0x1e79: 0xd779, 0x1e7a: 0xd799, 0x1e7b: 0x8c9d, + 0x1e7c: 0xd7b9, 0x1e7d: 0x8cbd, 0x1e7e: 0xd7d9, 0x1e7f: 0xd7f9, + // Block 0x7a, offset 0x1e80 + 0x1e80: 0xd819, 0x1e81: 0xd839, 0x1e82: 0xd859, 0x1e83: 0xd879, 0x1e84: 0xd899, 0x1e85: 0xd8b9, + 0x1e86: 0xd8d9, 0x1e87: 0xd8f9, 0x1e88: 0xd919, 0x1e89: 0x8cdd, 0x1e8a: 0xd939, 0x1e8b: 0xd959, + 0x1e8c: 0xd979, 0x1e8d: 0xd999, 0x1e8e: 0xd9b9, 0x1e8f: 0x8cfd, 0x1e90: 0xd9d9, 0x1e91: 0x8d1d, + 0x1e92: 0x8d3d, 0x1e93: 0xd9f9, 0x1e94: 0xda19, 0x1e95: 0xda19, 0x1e96: 0xda39, 0x1e97: 0x8d5d, + 0x1e98: 0x8d7d, 0x1e99: 0xda59, 0x1e9a: 0xda79, 0x1e9b: 0xda99, 0x1e9c: 0xdab9, 0x1e9d: 0xdad9, + 0x1e9e: 0xdaf9, 0x1e9f: 0xdb19, 0x1ea0: 0xdb39, 0x1ea1: 0xdb59, 0x1ea2: 0xdb79, 0x1ea3: 0xdb99, + 0x1ea4: 0x8d9d, 0x1ea5: 0xdbb9, 0x1ea6: 0xdbd9, 0x1ea7: 0xdbf9, 0x1ea8: 0xdc19, 0x1ea9: 0xdbf9, + 0x1eaa: 0xdc39, 0x1eab: 0xdc59, 0x1eac: 0xdc79, 0x1ead: 0xdc99, 0x1eae: 0xdcb9, 0x1eaf: 0xdcd9, + 0x1eb0: 0xdcf9, 0x1eb1: 0xdd19, 0x1eb2: 0xdd39, 0x1eb3: 0xdd59, 0x1eb4: 0xdd79, 0x1eb5: 0xdd99, + 0x1eb6: 0xddb9, 0x1eb7: 0xddd9, 0x1eb8: 0x8dbd, 0x1eb9: 0xddf9, 0x1eba: 0xde19, 0x1ebb: 0xde39, + 0x1ebc: 0xde59, 0x1ebd: 0xde79, 0x1ebe: 0x8ddd, 0x1ebf: 0xde99, + // Block 0x7b, offset 0x1ec0 + 0x1ec0: 0xe599, 0x1ec1: 0xe5b9, 0x1ec2: 0xe5d9, 0x1ec3: 0xe5f9, 0x1ec4: 0xe619, 0x1ec5: 0xe639, + 0x1ec6: 0x8efd, 0x1ec7: 0xe659, 0x1ec8: 0xe679, 0x1ec9: 0xe699, 0x1eca: 0xe6b9, 0x1ecb: 0xe6d9, + 0x1ecc: 0xe6f9, 0x1ecd: 0x8f1d, 0x1ece: 0xe719, 0x1ecf: 0xe739, 0x1ed0: 0x8f3d, 0x1ed1: 0x8f5d, + 0x1ed2: 0xe759, 0x1ed3: 0xe779, 0x1ed4: 0xe799, 0x1ed5: 0xe7b9, 0x1ed6: 0xe7d9, 0x1ed7: 0xe7f9, + 0x1ed8: 0xe819, 0x1ed9: 0xe839, 0x1eda: 0xe859, 0x1edb: 0x8f7d, 0x1edc: 0xe879, 0x1edd: 0x8f9d, + 0x1ede: 0xe899, 0x1edf: 0x2040, 0x1ee0: 0xe8b9, 0x1ee1: 0xe8d9, 0x1ee2: 0xe8f9, 0x1ee3: 0x8fbd, + 0x1ee4: 0xe919, 0x1ee5: 0xe939, 0x1ee6: 0x8fdd, 0x1ee7: 0x8ffd, 0x1ee8: 0xe959, 0x1ee9: 0xe979, + 0x1eea: 0xe999, 0x1eeb: 0xe9b9, 0x1eec: 0xe9d9, 0x1eed: 0xe9d9, 0x1eee: 0xe9f9, 0x1eef: 0xea19, + 0x1ef0: 0xea39, 0x1ef1: 0xea59, 0x1ef2: 0xea79, 0x1ef3: 0xea99, 0x1ef4: 0xeab9, 0x1ef5: 0x901d, + 0x1ef6: 0xead9, 0x1ef7: 0x903d, 0x1ef8: 0xeaf9, 0x1ef9: 0x905d, 0x1efa: 0xeb19, 0x1efb: 0x907d, + 0x1efc: 0x909d, 0x1efd: 0x90bd, 0x1efe: 0xeb39, 0x1eff: 0xeb59, + // Block 0x7c, offset 0x1f00 + 0x1f00: 0xeb79, 0x1f01: 0x90dd, 0x1f02: 0x90fd, 0x1f03: 0x911d, 0x1f04: 0x913d, 0x1f05: 0xeb99, + 0x1f06: 0xebb9, 0x1f07: 0xebb9, 0x1f08: 0xebd9, 0x1f09: 0xebf9, 0x1f0a: 0xec19, 0x1f0b: 0xec39, + 0x1f0c: 0xec59, 0x1f0d: 0x915d, 0x1f0e: 0xec79, 0x1f0f: 0xec99, 0x1f10: 0xecb9, 0x1f11: 0xecd9, + 0x1f12: 0x917d, 0x1f13: 0xecf9, 0x1f14: 0x919d, 0x1f15: 0x91bd, 0x1f16: 0xed19, 0x1f17: 0xed39, + 0x1f18: 0xed59, 0x1f19: 0xed79, 0x1f1a: 0xed99, 0x1f1b: 0xedb9, 0x1f1c: 0x91dd, 0x1f1d: 0x91fd, + 0x1f1e: 0x921d, 0x1f1f: 0x2040, 0x1f20: 0xedd9, 0x1f21: 0x923d, 0x1f22: 0xedf9, 0x1f23: 0xee19, + 0x1f24: 0xee39, 0x1f25: 0x925d, 0x1f26: 0xee59, 0x1f27: 0xee79, 0x1f28: 0xee99, 0x1f29: 0xeeb9, + 0x1f2a: 0xeed9, 0x1f2b: 0x927d, 0x1f2c: 0xeef9, 0x1f2d: 0xef19, 0x1f2e: 0xef39, 0x1f2f: 0xef59, + 0x1f30: 0xef79, 0x1f31: 0xef99, 0x1f32: 0x929d, 0x1f33: 0x92bd, 0x1f34: 0xefb9, 0x1f35: 0x92dd, + 0x1f36: 0xefd9, 0x1f37: 0x92fd, 0x1f38: 0xeff9, 0x1f39: 0xf019, 0x1f3a: 0xf039, 0x1f3b: 0x931d, + 0x1f3c: 0x933d, 0x1f3d: 0xf059, 0x1f3e: 0x935d, 0x1f3f: 0xf079, + // Block 0x7d, offset 0x1f40 + 0x1f40: 0xf6b9, 0x1f41: 0xf6d9, 0x1f42: 0xf6f9, 0x1f43: 0xf719, 0x1f44: 0xf739, 0x1f45: 0x951d, + 0x1f46: 0xf759, 0x1f47: 0xf779, 0x1f48: 0xf799, 0x1f49: 0xf7b9, 0x1f4a: 0xf7d9, 0x1f4b: 0x953d, + 0x1f4c: 0x955d, 0x1f4d: 0xf7f9, 0x1f4e: 0xf819, 0x1f4f: 0xf839, 0x1f50: 0xf859, 0x1f51: 0xf879, + 0x1f52: 0xf899, 0x1f53: 0x957d, 0x1f54: 0xf8b9, 0x1f55: 0xf8d9, 0x1f56: 0xf8f9, 0x1f57: 0xf919, + 0x1f58: 0x959d, 0x1f59: 0x95bd, 0x1f5a: 0xf939, 0x1f5b: 0xf959, 0x1f5c: 0xf979, 0x1f5d: 0x95dd, + 0x1f5e: 0xf999, 0x1f5f: 0xf9b9, 0x1f60: 0x6815, 0x1f61: 0x95fd, 0x1f62: 0xf9d9, 0x1f63: 0xf9f9, + 0x1f64: 0xfa19, 0x1f65: 0x961d, 0x1f66: 0xfa39, 0x1f67: 0xfa59, 0x1f68: 0xfa79, 0x1f69: 0xfa99, + 0x1f6a: 0xfab9, 0x1f6b: 0xfad9, 0x1f6c: 0xfaf9, 0x1f6d: 0x963d, 0x1f6e: 0xfb19, 0x1f6f: 0xfb39, + 0x1f70: 0xfb59, 0x1f71: 0x965d, 0x1f72: 0xfb79, 0x1f73: 0xfb99, 0x1f74: 0xfbb9, 0x1f75: 0xfbd9, + 0x1f76: 0x7b35, 0x1f77: 0x967d, 0x1f78: 0xfbf9, 0x1f79: 0xfc19, 0x1f7a: 0xfc39, 0x1f7b: 0x969d, + 0x1f7c: 0xfc59, 0x1f7d: 0x96bd, 0x1f7e: 0xfc79, 0x1f7f: 0xfc79, + // Block 0x7e, offset 0x1f80 + 0x1f80: 0xfc99, 0x1f81: 0x96dd, 0x1f82: 0xfcb9, 0x1f83: 0xfcd9, 0x1f84: 0xfcf9, 0x1f85: 0xfd19, + 0x1f86: 0xfd39, 0x1f87: 0xfd59, 0x1f88: 0xfd79, 0x1f89: 0x96fd, 0x1f8a: 0xfd99, 0x1f8b: 0xfdb9, + 0x1f8c: 0xfdd9, 0x1f8d: 0xfdf9, 0x1f8e: 0xfe19, 0x1f8f: 0xfe39, 0x1f90: 0x971d, 0x1f91: 0xfe59, + 0x1f92: 0x973d, 0x1f93: 0x975d, 0x1f94: 0x977d, 0x1f95: 0xfe79, 0x1f96: 0xfe99, 0x1f97: 0xfeb9, + 0x1f98: 0xfed9, 0x1f99: 0xfef9, 0x1f9a: 0xff19, 0x1f9b: 0xff39, 0x1f9c: 0xff59, 0x1f9d: 0x979d, + 0x1f9e: 0x0040, 0x1f9f: 0x0040, 0x1fa0: 0x0040, 0x1fa1: 0x0040, 0x1fa2: 0x0040, 0x1fa3: 0x0040, + 0x1fa4: 0x0040, 0x1fa5: 0x0040, 0x1fa6: 0x0040, 0x1fa7: 0x0040, 0x1fa8: 0x0040, 0x1fa9: 0x0040, + 0x1faa: 0x0040, 0x1fab: 0x0040, 0x1fac: 0x0040, 0x1fad: 0x0040, 0x1fae: 0x0040, 0x1faf: 0x0040, + 0x1fb0: 0x0040, 0x1fb1: 0x0040, 0x1fb2: 0x0040, 0x1fb3: 0x0040, 0x1fb4: 0x0040, 0x1fb5: 0x0040, + 0x1fb6: 0x0040, 0x1fb7: 0x0040, 0x1fb8: 0x0040, 0x1fb9: 0x0040, 0x1fba: 0x0040, 0x1fbb: 0x0040, + 0x1fbc: 0x0040, 0x1fbd: 0x0040, 0x1fbe: 0x0040, 0x1fbf: 0x0040, +} + +// idnaIndex: 36 blocks, 2304 entries, 4608 bytes +// Block 0 is the zero block. +var idnaIndex = [2304]uint16{ + // Block 0x0, offset 0x0 + // Block 0x1, offset 0x40 + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0xc2: 0x01, 0xc3: 0x7d, 0xc4: 0x02, 0xc5: 0x03, 0xc6: 0x04, 0xc7: 0x05, + 0xc8: 0x06, 0xc9: 0x7e, 0xca: 0x7f, 0xcb: 0x07, 0xcc: 0x80, 0xcd: 0x08, 0xce: 0x09, 0xcf: 0x0a, + 0xd0: 0x81, 0xd1: 0x0b, 0xd2: 0x0c, 0xd3: 0x0d, 0xd4: 0x0e, 0xd5: 0x82, 0xd6: 0x83, 0xd7: 0x84, + 0xd8: 0x0f, 0xd9: 0x10, 0xda: 0x85, 0xdb: 0x11, 0xdc: 0x12, 0xdd: 0x86, 0xde: 0x87, 0xdf: 0x88, + 0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05, 0xe4: 0x06, 0xe5: 0x07, 0xe6: 0x07, 0xe7: 0x07, + 0xe8: 0x07, 0xe9: 0x08, 0xea: 0x09, 0xeb: 0x07, 0xec: 0x07, 0xed: 0x0a, 0xee: 0x0b, 0xef: 0x0c, + 0xf0: 0x1d, 0xf1: 0x1e, 0xf2: 0x1e, 0xf3: 0x20, 0xf4: 0x21, + // Block 0x4, offset 0x100 + 0x120: 0x89, 0x121: 0x13, 0x122: 0x8a, 0x123: 0x8b, 0x124: 0x8c, 0x125: 0x14, 0x126: 0x15, 0x127: 0x16, + 0x128: 0x17, 0x129: 0x18, 0x12a: 0x19, 0x12b: 0x1a, 0x12c: 0x1b, 0x12d: 0x1c, 0x12e: 0x1d, 0x12f: 0x8d, + 0x130: 0x8e, 0x131: 0x1e, 0x132: 0x1f, 0x133: 0x20, 0x134: 0x8f, 0x135: 0x21, 0x136: 0x90, 0x137: 0x91, + 0x138: 0x92, 0x139: 0x93, 0x13a: 0x22, 0x13b: 0x94, 0x13c: 0x95, 0x13d: 0x23, 0x13e: 0x24, 0x13f: 0x96, + // Block 0x5, offset 0x140 + 0x140: 0x97, 0x141: 0x98, 0x142: 0x99, 0x143: 0x9a, 0x144: 0x9b, 0x145: 0x9c, 0x146: 0x9d, 0x147: 0x9e, + 0x148: 0x9f, 0x149: 0xa0, 0x14a: 0xa1, 0x14b: 0xa2, 0x14c: 0xa3, 0x14d: 0xa4, 0x14e: 0xa5, 0x14f: 0xa6, + 0x150: 0xa7, 0x151: 0x9f, 0x152: 0x9f, 0x153: 0x9f, 0x154: 0x9f, 0x155: 0x9f, 0x156: 0x9f, 0x157: 0x9f, + 0x158: 0x9f, 0x159: 0xa8, 0x15a: 0xa9, 0x15b: 0xaa, 0x15c: 0xab, 0x15d: 0xac, 0x15e: 0xad, 0x15f: 0xae, + 0x160: 0xaf, 0x161: 0xb0, 0x162: 0xb1, 0x163: 0xb2, 0x164: 0xb3, 0x165: 0xb4, 0x166: 0xb5, 0x167: 0xb6, + 0x168: 0xb7, 0x169: 0xb8, 0x16a: 0xb9, 0x16b: 0xba, 0x16c: 0xbb, 0x16d: 0xbc, 0x16e: 0xbd, 0x16f: 0xbe, + 0x170: 0xbf, 0x171: 0xc0, 0x172: 0xc1, 0x173: 0xc2, 0x174: 0x25, 0x175: 0x26, 0x176: 0x27, 0x177: 0xc3, + 0x178: 0x28, 0x179: 0x28, 0x17a: 0x29, 0x17b: 0x28, 0x17c: 0xc4, 0x17d: 0x2a, 0x17e: 0x2b, 0x17f: 0x2c, + // Block 0x6, offset 0x180 + 0x180: 0x2d, 0x181: 0x2e, 0x182: 0x2f, 0x183: 0xc5, 0x184: 0x30, 0x185: 0x31, 0x186: 0xc6, 0x187: 0x9b, + 0x188: 0xc7, 0x189: 0xc8, 0x18a: 0x9b, 0x18b: 0x9b, 0x18c: 0xc9, 0x18d: 0x9b, 0x18e: 0x9b, 0x18f: 0x9b, + 0x190: 0xca, 0x191: 0x32, 0x192: 0x33, 0x193: 0x34, 0x194: 0x9b, 0x195: 0x9b, 0x196: 0x9b, 0x197: 0x9b, + 0x198: 0x9b, 0x199: 0x9b, 0x19a: 0x9b, 0x19b: 0x9b, 0x19c: 0x9b, 0x19d: 0x9b, 0x19e: 0x9b, 0x19f: 0x9b, + 0x1a0: 0x9b, 0x1a1: 0x9b, 0x1a2: 0x9b, 0x1a3: 0x9b, 0x1a4: 0x9b, 0x1a5: 0x9b, 0x1a6: 0x9b, 0x1a7: 0x9b, + 0x1a8: 0xcb, 0x1a9: 0xcc, 0x1aa: 0x9b, 0x1ab: 0xcd, 0x1ac: 0x9b, 0x1ad: 0xce, 0x1ae: 0xcf, 0x1af: 0xd0, + 0x1b0: 0xd1, 0x1b1: 0x35, 0x1b2: 0x28, 0x1b3: 0x36, 0x1b4: 0xd2, 0x1b5: 0xd3, 0x1b6: 0xd4, 0x1b7: 0xd5, + 0x1b8: 0xd6, 0x1b9: 0xd7, 0x1ba: 0xd8, 0x1bb: 0xd9, 0x1bc: 0xda, 0x1bd: 0xdb, 0x1be: 0xdc, 0x1bf: 0x37, + // Block 0x7, offset 0x1c0 + 0x1c0: 0x38, 0x1c1: 0xdd, 0x1c2: 0xde, 0x1c3: 0xdf, 0x1c4: 0xe0, 0x1c5: 0x39, 0x1c6: 0x3a, 0x1c7: 0xe1, + 0x1c8: 0xe2, 0x1c9: 0x3b, 0x1ca: 0x3c, 0x1cb: 0x3d, 0x1cc: 0x3e, 0x1cd: 0x3f, 0x1ce: 0x40, 0x1cf: 0x41, + 0x1d0: 0x9f, 0x1d1: 0x9f, 0x1d2: 0x9f, 0x1d3: 0x9f, 0x1d4: 0x9f, 0x1d5: 0x9f, 0x1d6: 0x9f, 0x1d7: 0x9f, + 0x1d8: 0x9f, 0x1d9: 0x9f, 0x1da: 0x9f, 0x1db: 0x9f, 0x1dc: 0x9f, 0x1dd: 0x9f, 0x1de: 0x9f, 0x1df: 0x9f, + 0x1e0: 0x9f, 0x1e1: 0x9f, 0x1e2: 0x9f, 0x1e3: 0x9f, 0x1e4: 0x9f, 0x1e5: 0x9f, 0x1e6: 0x9f, 0x1e7: 0x9f, + 0x1e8: 0x9f, 0x1e9: 0x9f, 0x1ea: 0x9f, 0x1eb: 0x9f, 0x1ec: 0x9f, 0x1ed: 0x9f, 0x1ee: 0x9f, 0x1ef: 0x9f, + 0x1f0: 0x9f, 0x1f1: 0x9f, 0x1f2: 0x9f, 0x1f3: 0x9f, 0x1f4: 0x9f, 0x1f5: 0x9f, 0x1f6: 0x9f, 0x1f7: 0x9f, + 0x1f8: 0x9f, 0x1f9: 0x9f, 0x1fa: 0x9f, 0x1fb: 0x9f, 0x1fc: 0x9f, 0x1fd: 0x9f, 0x1fe: 0x9f, 0x1ff: 0x9f, + // Block 0x8, offset 0x200 + 0x200: 0x9f, 0x201: 0x9f, 0x202: 0x9f, 0x203: 0x9f, 0x204: 0x9f, 0x205: 0x9f, 0x206: 0x9f, 0x207: 0x9f, + 0x208: 0x9f, 0x209: 0x9f, 0x20a: 0x9f, 0x20b: 0x9f, 0x20c: 0x9f, 0x20d: 0x9f, 0x20e: 0x9f, 0x20f: 0x9f, + 0x210: 0x9f, 0x211: 0x9f, 0x212: 0x9f, 0x213: 0x9f, 0x214: 0x9f, 0x215: 0x9f, 0x216: 0x9f, 0x217: 0x9f, + 0x218: 0x9f, 0x219: 0x9f, 0x21a: 0x9f, 0x21b: 0x9f, 0x21c: 0x9f, 0x21d: 0x9f, 0x21e: 0x9f, 0x21f: 0x9f, + 0x220: 0x9f, 0x221: 0x9f, 0x222: 0x9f, 0x223: 0x9f, 0x224: 0x9f, 0x225: 0x9f, 0x226: 0x9f, 0x227: 0x9f, + 0x228: 0x9f, 0x229: 0x9f, 0x22a: 0x9f, 0x22b: 0x9f, 0x22c: 0x9f, 0x22d: 0x9f, 0x22e: 0x9f, 0x22f: 0x9f, + 0x230: 0x9f, 0x231: 0x9f, 0x232: 0x9f, 0x233: 0x9f, 0x234: 0x9f, 0x235: 0x9f, 0x236: 0xb2, 0x237: 0x9b, + 0x238: 0x9f, 0x239: 0x9f, 0x23a: 0x9f, 0x23b: 0x9f, 0x23c: 0x9f, 0x23d: 0x9f, 0x23e: 0x9f, 0x23f: 0x9f, + // Block 0x9, offset 0x240 + 0x240: 0x9f, 0x241: 0x9f, 0x242: 0x9f, 0x243: 0x9f, 0x244: 0x9f, 0x245: 0x9f, 0x246: 0x9f, 0x247: 0x9f, + 0x248: 0x9f, 0x249: 0x9f, 0x24a: 0x9f, 0x24b: 0x9f, 0x24c: 0x9f, 0x24d: 0x9f, 0x24e: 0x9f, 0x24f: 0x9f, + 0x250: 0x9f, 0x251: 0x9f, 0x252: 0x9f, 0x253: 0x9f, 0x254: 0x9f, 0x255: 0x9f, 0x256: 0x9f, 0x257: 0x9f, + 0x258: 0x9f, 0x259: 0x9f, 0x25a: 0x9f, 0x25b: 0x9f, 0x25c: 0x9f, 0x25d: 0x9f, 0x25e: 0x9f, 0x25f: 0x9f, + 0x260: 0x9f, 0x261: 0x9f, 0x262: 0x9f, 0x263: 0x9f, 0x264: 0x9f, 0x265: 0x9f, 0x266: 0x9f, 0x267: 0x9f, + 0x268: 0x9f, 0x269: 0x9f, 0x26a: 0x9f, 0x26b: 0x9f, 0x26c: 0x9f, 0x26d: 0x9f, 0x26e: 0x9f, 0x26f: 0x9f, + 0x270: 0x9f, 0x271: 0x9f, 0x272: 0x9f, 0x273: 0x9f, 0x274: 0x9f, 0x275: 0x9f, 0x276: 0x9f, 0x277: 0x9f, + 0x278: 0x9f, 0x279: 0x9f, 0x27a: 0x9f, 0x27b: 0x9f, 0x27c: 0x9f, 0x27d: 0x9f, 0x27e: 0x9f, 0x27f: 0x9f, + // Block 0xa, offset 0x280 + 0x280: 0x9f, 0x281: 0x9f, 0x282: 0x9f, 0x283: 0x9f, 0x284: 0x9f, 0x285: 0x9f, 0x286: 0x9f, 0x287: 0x9f, + 0x288: 0x9f, 0x289: 0x9f, 0x28a: 0x9f, 0x28b: 0x9f, 0x28c: 0x9f, 0x28d: 0x9f, 0x28e: 0x9f, 0x28f: 0x9f, + 0x290: 0x9f, 0x291: 0x9f, 0x292: 0x9f, 0x293: 0x9f, 0x294: 0x9f, 0x295: 0x9f, 0x296: 0x9f, 0x297: 0x9f, + 0x298: 0x9f, 0x299: 0x9f, 0x29a: 0x9f, 0x29b: 0x9f, 0x29c: 0x9f, 0x29d: 0x9f, 0x29e: 0x9f, 0x29f: 0x9f, + 0x2a0: 0x9f, 0x2a1: 0x9f, 0x2a2: 0x9f, 0x2a3: 0x9f, 0x2a4: 0x9f, 0x2a5: 0x9f, 0x2a6: 0x9f, 0x2a7: 0x9f, + 0x2a8: 0x9f, 0x2a9: 0x9f, 0x2aa: 0x9f, 0x2ab: 0x9f, 0x2ac: 0x9f, 0x2ad: 0x9f, 0x2ae: 0x9f, 0x2af: 0x9f, + 0x2b0: 0x9f, 0x2b1: 0x9f, 0x2b2: 0x9f, 0x2b3: 0x9f, 0x2b4: 0x9f, 0x2b5: 0x9f, 0x2b6: 0x9f, 0x2b7: 0x9f, + 0x2b8: 0x9f, 0x2b9: 0x9f, 0x2ba: 0x9f, 0x2bb: 0x9f, 0x2bc: 0x9f, 0x2bd: 0x9f, 0x2be: 0x9f, 0x2bf: 0xe3, + // Block 0xb, offset 0x2c0 + 0x2c0: 0x9f, 0x2c1: 0x9f, 0x2c2: 0x9f, 0x2c3: 0x9f, 0x2c4: 0x9f, 0x2c5: 0x9f, 0x2c6: 0x9f, 0x2c7: 0x9f, + 0x2c8: 0x9f, 0x2c9: 0x9f, 0x2ca: 0x9f, 0x2cb: 0x9f, 0x2cc: 0x9f, 0x2cd: 0x9f, 0x2ce: 0x9f, 0x2cf: 0x9f, + 0x2d0: 0x9f, 0x2d1: 0x9f, 0x2d2: 0xe4, 0x2d3: 0xe5, 0x2d4: 0x9f, 0x2d5: 0x9f, 0x2d6: 0x9f, 0x2d7: 0x9f, + 0x2d8: 0xe6, 0x2d9: 0x42, 0x2da: 0x43, 0x2db: 0xe7, 0x2dc: 0x44, 0x2dd: 0x45, 0x2de: 0x46, 0x2df: 0xe8, + 0x2e0: 0xe9, 0x2e1: 0xea, 0x2e2: 0xeb, 0x2e3: 0xec, 0x2e4: 0xed, 0x2e5: 0xee, 0x2e6: 0xef, 0x2e7: 0xf0, + 0x2e8: 0xf1, 0x2e9: 0xf2, 0x2ea: 0xf3, 0x2eb: 0xf4, 0x2ec: 0xf5, 0x2ed: 0xf6, 0x2ee: 0xf7, 0x2ef: 0xf8, + 0x2f0: 0x9f, 0x2f1: 0x9f, 0x2f2: 0x9f, 0x2f3: 0x9f, 0x2f4: 0x9f, 0x2f5: 0x9f, 0x2f6: 0x9f, 0x2f7: 0x9f, + 0x2f8: 0x9f, 0x2f9: 0x9f, 0x2fa: 0x9f, 0x2fb: 0x9f, 0x2fc: 0x9f, 0x2fd: 0x9f, 0x2fe: 0x9f, 0x2ff: 0x9f, + // Block 0xc, offset 0x300 + 0x300: 0x9f, 0x301: 0x9f, 0x302: 0x9f, 0x303: 0x9f, 0x304: 0x9f, 0x305: 0x9f, 0x306: 0x9f, 0x307: 0x9f, + 0x308: 0x9f, 0x309: 0x9f, 0x30a: 0x9f, 0x30b: 0x9f, 0x30c: 0x9f, 0x30d: 0x9f, 0x30e: 0x9f, 0x30f: 0x9f, + 0x310: 0x9f, 0x311: 0x9f, 0x312: 0x9f, 0x313: 0x9f, 0x314: 0x9f, 0x315: 0x9f, 0x316: 0x9f, 0x317: 0x9f, + 0x318: 0x9f, 0x319: 0x9f, 0x31a: 0x9f, 0x31b: 0x9f, 0x31c: 0x9f, 0x31d: 0x9f, 0x31e: 0xf9, 0x31f: 0xfa, + // Block 0xd, offset 0x340 + 0x340: 0xba, 0x341: 0xba, 0x342: 0xba, 0x343: 0xba, 0x344: 0xba, 0x345: 0xba, 0x346: 0xba, 0x347: 0xba, + 0x348: 0xba, 0x349: 0xba, 0x34a: 0xba, 0x34b: 0xba, 0x34c: 0xba, 0x34d: 0xba, 0x34e: 0xba, 0x34f: 0xba, + 0x350: 0xba, 0x351: 0xba, 0x352: 0xba, 0x353: 0xba, 0x354: 0xba, 0x355: 0xba, 0x356: 0xba, 0x357: 0xba, + 0x358: 0xba, 0x359: 0xba, 0x35a: 0xba, 0x35b: 0xba, 0x35c: 0xba, 0x35d: 0xba, 0x35e: 0xba, 0x35f: 0xba, + 0x360: 0xba, 0x361: 0xba, 0x362: 0xba, 0x363: 0xba, 0x364: 0xba, 0x365: 0xba, 0x366: 0xba, 0x367: 0xba, + 0x368: 0xba, 0x369: 0xba, 0x36a: 0xba, 0x36b: 0xba, 0x36c: 0xba, 0x36d: 0xba, 0x36e: 0xba, 0x36f: 0xba, + 0x370: 0xba, 0x371: 0xba, 0x372: 0xba, 0x373: 0xba, 0x374: 0xba, 0x375: 0xba, 0x376: 0xba, 0x377: 0xba, + 0x378: 0xba, 0x379: 0xba, 0x37a: 0xba, 0x37b: 0xba, 0x37c: 0xba, 0x37d: 0xba, 0x37e: 0xba, 0x37f: 0xba, + // Block 0xe, offset 0x380 + 0x380: 0xba, 0x381: 0xba, 0x382: 0xba, 0x383: 0xba, 0x384: 0xba, 0x385: 0xba, 0x386: 0xba, 0x387: 0xba, + 0x388: 0xba, 0x389: 0xba, 0x38a: 0xba, 0x38b: 0xba, 0x38c: 0xba, 0x38d: 0xba, 0x38e: 0xba, 0x38f: 0xba, + 0x390: 0xba, 0x391: 0xba, 0x392: 0xba, 0x393: 0xba, 0x394: 0xba, 0x395: 0xba, 0x396: 0xba, 0x397: 0xba, + 0x398: 0xba, 0x399: 0xba, 0x39a: 0xba, 0x39b: 0xba, 0x39c: 0xba, 0x39d: 0xba, 0x39e: 0xba, 0x39f: 0xba, + 0x3a0: 0xba, 0x3a1: 0xba, 0x3a2: 0xba, 0x3a3: 0xba, 0x3a4: 0xfb, 0x3a5: 0xfc, 0x3a6: 0xfd, 0x3a7: 0xfe, + 0x3a8: 0x47, 0x3a9: 0xff, 0x3aa: 0x100, 0x3ab: 0x48, 0x3ac: 0x49, 0x3ad: 0x4a, 0x3ae: 0x4b, 0x3af: 0x4c, + 0x3b0: 0x101, 0x3b1: 0x4d, 0x3b2: 0x4e, 0x3b3: 0x4f, 0x3b4: 0x50, 0x3b5: 0x51, 0x3b6: 0x102, 0x3b7: 0x52, + 0x3b8: 0x53, 0x3b9: 0x54, 0x3ba: 0x55, 0x3bb: 0x56, 0x3bc: 0x57, 0x3bd: 0x58, 0x3be: 0x59, 0x3bf: 0x5a, + // Block 0xf, offset 0x3c0 + 0x3c0: 0x103, 0x3c1: 0x104, 0x3c2: 0x9f, 0x3c3: 0x105, 0x3c4: 0x106, 0x3c5: 0x9b, 0x3c6: 0x107, 0x3c7: 0x108, + 0x3c8: 0xba, 0x3c9: 0xba, 0x3ca: 0x109, 0x3cb: 0x10a, 0x3cc: 0x10b, 0x3cd: 0x10c, 0x3ce: 0x10d, 0x3cf: 0x10e, + 0x3d0: 0x10f, 0x3d1: 0x9f, 0x3d2: 0x110, 0x3d3: 0x111, 0x3d4: 0x112, 0x3d5: 0x113, 0x3d6: 0xba, 0x3d7: 0xba, + 0x3d8: 0x9f, 0x3d9: 0x9f, 0x3da: 0x9f, 0x3db: 0x9f, 0x3dc: 0x114, 0x3dd: 0x115, 0x3de: 0xba, 0x3df: 0xba, + 0x3e0: 0x116, 0x3e1: 0x117, 0x3e2: 0x118, 0x3e3: 0x119, 0x3e4: 0x11a, 0x3e5: 0xba, 0x3e6: 0x11b, 0x3e7: 0x11c, + 0x3e8: 0x11d, 0x3e9: 0x11e, 0x3ea: 0x11f, 0x3eb: 0x5b, 0x3ec: 0x120, 0x3ed: 0x121, 0x3ee: 0x5c, 0x3ef: 0xba, + 0x3f0: 0x122, 0x3f1: 0x123, 0x3f2: 0x124, 0x3f3: 0x125, 0x3f4: 0xba, 0x3f5: 0xba, 0x3f6: 0xba, 0x3f7: 0xba, + 0x3f8: 0xba, 0x3f9: 0x126, 0x3fa: 0xba, 0x3fb: 0xba, 0x3fc: 0xba, 0x3fd: 0xba, 0x3fe: 0xba, 0x3ff: 0xba, + // Block 0x10, offset 0x400 + 0x400: 0x127, 0x401: 0x128, 0x402: 0x129, 0x403: 0x12a, 0x404: 0x12b, 0x405: 0x12c, 0x406: 0x12d, 0x407: 0x12e, + 0x408: 0x12f, 0x409: 0xba, 0x40a: 0x130, 0x40b: 0x131, 0x40c: 0x5d, 0x40d: 0x5e, 0x40e: 0xba, 0x40f: 0xba, + 0x410: 0x132, 0x411: 0x133, 0x412: 0x134, 0x413: 0x135, 0x414: 0xba, 0x415: 0xba, 0x416: 0x136, 0x417: 0x137, + 0x418: 0x138, 0x419: 0x139, 0x41a: 0x13a, 0x41b: 0x13b, 0x41c: 0x13c, 0x41d: 0xba, 0x41e: 0xba, 0x41f: 0xba, + 0x420: 0xba, 0x421: 0xba, 0x422: 0x13d, 0x423: 0x13e, 0x424: 0xba, 0x425: 0xba, 0x426: 0xba, 0x427: 0xba, + 0x428: 0x13f, 0x429: 0x140, 0x42a: 0x141, 0x42b: 0x142, 0x42c: 0xba, 0x42d: 0xba, 0x42e: 0xba, 0x42f: 0xba, + 0x430: 0x143, 0x431: 0x144, 0x432: 0x145, 0x433: 0xba, 0x434: 0x146, 0x435: 0x147, 0x436: 0xba, 0x437: 0xba, + 0x438: 0xba, 0x439: 0xba, 0x43a: 0xba, 0x43b: 0xba, 0x43c: 0xba, 0x43d: 0xba, 0x43e: 0xba, 0x43f: 0xba, + // Block 0x11, offset 0x440 + 0x440: 0x9f, 0x441: 0x9f, 0x442: 0x9f, 0x443: 0x9f, 0x444: 0x9f, 0x445: 0x9f, 0x446: 0x9f, 0x447: 0x9f, + 0x448: 0x9f, 0x449: 0x9f, 0x44a: 0x9f, 0x44b: 0x9f, 0x44c: 0x9f, 0x44d: 0x9f, 0x44e: 0x148, 0x44f: 0xba, + 0x450: 0x9b, 0x451: 0x149, 0x452: 0x9f, 0x453: 0x9f, 0x454: 0x9f, 0x455: 0x14a, 0x456: 0xba, 0x457: 0xba, + 0x458: 0xba, 0x459: 0xba, 0x45a: 0xba, 0x45b: 0xba, 0x45c: 0xba, 0x45d: 0xba, 0x45e: 0xba, 0x45f: 0xba, + 0x460: 0xba, 0x461: 0xba, 0x462: 0xba, 0x463: 0xba, 0x464: 0xba, 0x465: 0xba, 0x466: 0xba, 0x467: 0xba, + 0x468: 0xba, 0x469: 0xba, 0x46a: 0xba, 0x46b: 0xba, 0x46c: 0xba, 0x46d: 0xba, 0x46e: 0xba, 0x46f: 0xba, + 0x470: 0xba, 0x471: 0xba, 0x472: 0xba, 0x473: 0xba, 0x474: 0xba, 0x475: 0xba, 0x476: 0xba, 0x477: 0xba, + 0x478: 0xba, 0x479: 0xba, 0x47a: 0xba, 0x47b: 0xba, 0x47c: 0xba, 0x47d: 0xba, 0x47e: 0xba, 0x47f: 0xba, + // Block 0x12, offset 0x480 + 0x480: 0x9f, 0x481: 0x9f, 0x482: 0x9f, 0x483: 0x9f, 0x484: 0x9f, 0x485: 0x9f, 0x486: 0x9f, 0x487: 0x9f, + 0x488: 0x9f, 0x489: 0x9f, 0x48a: 0x9f, 0x48b: 0x9f, 0x48c: 0x9f, 0x48d: 0x9f, 0x48e: 0x9f, 0x48f: 0x9f, + 0x490: 0x14b, 0x491: 0xba, 0x492: 0xba, 0x493: 0xba, 0x494: 0xba, 0x495: 0xba, 0x496: 0xba, 0x497: 0xba, + 0x498: 0xba, 0x499: 0xba, 0x49a: 0xba, 0x49b: 0xba, 0x49c: 0xba, 0x49d: 0xba, 0x49e: 0xba, 0x49f: 0xba, + 0x4a0: 0xba, 0x4a1: 0xba, 0x4a2: 0xba, 0x4a3: 0xba, 0x4a4: 0xba, 0x4a5: 0xba, 0x4a6: 0xba, 0x4a7: 0xba, + 0x4a8: 0xba, 0x4a9: 0xba, 0x4aa: 0xba, 0x4ab: 0xba, 0x4ac: 0xba, 0x4ad: 0xba, 0x4ae: 0xba, 0x4af: 0xba, + 0x4b0: 0xba, 0x4b1: 0xba, 0x4b2: 0xba, 0x4b3: 0xba, 0x4b4: 0xba, 0x4b5: 0xba, 0x4b6: 0xba, 0x4b7: 0xba, + 0x4b8: 0xba, 0x4b9: 0xba, 0x4ba: 0xba, 0x4bb: 0xba, 0x4bc: 0xba, 0x4bd: 0xba, 0x4be: 0xba, 0x4bf: 0xba, + // Block 0x13, offset 0x4c0 + 0x4c0: 0xba, 0x4c1: 0xba, 0x4c2: 0xba, 0x4c3: 0xba, 0x4c4: 0xba, 0x4c5: 0xba, 0x4c6: 0xba, 0x4c7: 0xba, + 0x4c8: 0xba, 0x4c9: 0xba, 0x4ca: 0xba, 0x4cb: 0xba, 0x4cc: 0xba, 0x4cd: 0xba, 0x4ce: 0xba, 0x4cf: 0xba, + 0x4d0: 0x9f, 0x4d1: 0x9f, 0x4d2: 0x9f, 0x4d3: 0x9f, 0x4d4: 0x9f, 0x4d5: 0x9f, 0x4d6: 0x9f, 0x4d7: 0x9f, + 0x4d8: 0x9f, 0x4d9: 0x14c, 0x4da: 0xba, 0x4db: 0xba, 0x4dc: 0xba, 0x4dd: 0xba, 0x4de: 0xba, 0x4df: 0xba, + 0x4e0: 0xba, 0x4e1: 0xba, 0x4e2: 0xba, 0x4e3: 0xba, 0x4e4: 0xba, 0x4e5: 0xba, 0x4e6: 0xba, 0x4e7: 0xba, + 0x4e8: 0xba, 0x4e9: 0xba, 0x4ea: 0xba, 0x4eb: 0xba, 0x4ec: 0xba, 0x4ed: 0xba, 0x4ee: 0xba, 0x4ef: 0xba, + 0x4f0: 0xba, 0x4f1: 0xba, 0x4f2: 0xba, 0x4f3: 0xba, 0x4f4: 0xba, 0x4f5: 0xba, 0x4f6: 0xba, 0x4f7: 0xba, + 0x4f8: 0xba, 0x4f9: 0xba, 0x4fa: 0xba, 0x4fb: 0xba, 0x4fc: 0xba, 0x4fd: 0xba, 0x4fe: 0xba, 0x4ff: 0xba, + // Block 0x14, offset 0x500 + 0x500: 0xba, 0x501: 0xba, 0x502: 0xba, 0x503: 0xba, 0x504: 0xba, 0x505: 0xba, 0x506: 0xba, 0x507: 0xba, + 0x508: 0xba, 0x509: 0xba, 0x50a: 0xba, 0x50b: 0xba, 0x50c: 0xba, 0x50d: 0xba, 0x50e: 0xba, 0x50f: 0xba, + 0x510: 0xba, 0x511: 0xba, 0x512: 0xba, 0x513: 0xba, 0x514: 0xba, 0x515: 0xba, 0x516: 0xba, 0x517: 0xba, + 0x518: 0xba, 0x519: 0xba, 0x51a: 0xba, 0x51b: 0xba, 0x51c: 0xba, 0x51d: 0xba, 0x51e: 0xba, 0x51f: 0xba, + 0x520: 0x9f, 0x521: 0x9f, 0x522: 0x9f, 0x523: 0x9f, 0x524: 0x9f, 0x525: 0x9f, 0x526: 0x9f, 0x527: 0x9f, + 0x528: 0x142, 0x529: 0x14d, 0x52a: 0xba, 0x52b: 0x14e, 0x52c: 0x14f, 0x52d: 0x150, 0x52e: 0x151, 0x52f: 0xba, + 0x530: 0xba, 0x531: 0xba, 0x532: 0xba, 0x533: 0xba, 0x534: 0xba, 0x535: 0xba, 0x536: 0xba, 0x537: 0xba, + 0x538: 0xba, 0x539: 0xba, 0x53a: 0xba, 0x53b: 0xba, 0x53c: 0x9f, 0x53d: 0x152, 0x53e: 0x153, 0x53f: 0x154, + // Block 0x15, offset 0x540 + 0x540: 0x9f, 0x541: 0x9f, 0x542: 0x9f, 0x543: 0x9f, 0x544: 0x9f, 0x545: 0x9f, 0x546: 0x9f, 0x547: 0x9f, + 0x548: 0x9f, 0x549: 0x9f, 0x54a: 0x9f, 0x54b: 0x9f, 0x54c: 0x9f, 0x54d: 0x9f, 0x54e: 0x9f, 0x54f: 0x9f, + 0x550: 0x9f, 0x551: 0x9f, 0x552: 0x9f, 0x553: 0x9f, 0x554: 0x9f, 0x555: 0x9f, 0x556: 0x9f, 0x557: 0x9f, + 0x558: 0x9f, 0x559: 0x9f, 0x55a: 0x9f, 0x55b: 0x9f, 0x55c: 0x9f, 0x55d: 0x9f, 0x55e: 0x9f, 0x55f: 0x155, + 0x560: 0x9f, 0x561: 0x9f, 0x562: 0x9f, 0x563: 0x9f, 0x564: 0x9f, 0x565: 0x9f, 0x566: 0x9f, 0x567: 0x9f, + 0x568: 0x9f, 0x569: 0x9f, 0x56a: 0x9f, 0x56b: 0x156, 0x56c: 0xba, 0x56d: 0xba, 0x56e: 0xba, 0x56f: 0xba, + 0x570: 0xba, 0x571: 0xba, 0x572: 0xba, 0x573: 0xba, 0x574: 0xba, 0x575: 0xba, 0x576: 0xba, 0x577: 0xba, + 0x578: 0xba, 0x579: 0xba, 0x57a: 0xba, 0x57b: 0xba, 0x57c: 0xba, 0x57d: 0xba, 0x57e: 0xba, 0x57f: 0xba, + // Block 0x16, offset 0x580 + 0x580: 0x9f, 0x581: 0x9f, 0x582: 0x9f, 0x583: 0x9f, 0x584: 0x157, 0x585: 0x158, 0x586: 0x9f, 0x587: 0x9f, + 0x588: 0x9f, 0x589: 0x9f, 0x58a: 0x9f, 0x58b: 0x159, 0x58c: 0xba, 0x58d: 0xba, 0x58e: 0xba, 0x58f: 0xba, + 0x590: 0xba, 0x591: 0xba, 0x592: 0xba, 0x593: 0xba, 0x594: 0xba, 0x595: 0xba, 0x596: 0xba, 0x597: 0xba, + 0x598: 0xba, 0x599: 0xba, 0x59a: 0xba, 0x59b: 0xba, 0x59c: 0xba, 0x59d: 0xba, 0x59e: 0xba, 0x59f: 0xba, + 0x5a0: 0xba, 0x5a1: 0xba, 0x5a2: 0xba, 0x5a3: 0xba, 0x5a4: 0xba, 0x5a5: 0xba, 0x5a6: 0xba, 0x5a7: 0xba, + 0x5a8: 0xba, 0x5a9: 0xba, 0x5aa: 0xba, 0x5ab: 0xba, 0x5ac: 0xba, 0x5ad: 0xba, 0x5ae: 0xba, 0x5af: 0xba, + 0x5b0: 0x9f, 0x5b1: 0x15a, 0x5b2: 0x15b, 0x5b3: 0xba, 0x5b4: 0xba, 0x5b5: 0xba, 0x5b6: 0xba, 0x5b7: 0xba, + 0x5b8: 0xba, 0x5b9: 0xba, 0x5ba: 0xba, 0x5bb: 0xba, 0x5bc: 0xba, 0x5bd: 0xba, 0x5be: 0xba, 0x5bf: 0xba, + // Block 0x17, offset 0x5c0 + 0x5c0: 0x9b, 0x5c1: 0x9b, 0x5c2: 0x9b, 0x5c3: 0x15c, 0x5c4: 0x15d, 0x5c5: 0x15e, 0x5c6: 0x15f, 0x5c7: 0x160, + 0x5c8: 0x9b, 0x5c9: 0x161, 0x5ca: 0xba, 0x5cb: 0xba, 0x5cc: 0x9b, 0x5cd: 0x162, 0x5ce: 0xba, 0x5cf: 0xba, + 0x5d0: 0x5f, 0x5d1: 0x60, 0x5d2: 0x61, 0x5d3: 0x62, 0x5d4: 0x63, 0x5d5: 0x64, 0x5d6: 0x65, 0x5d7: 0x66, + 0x5d8: 0x67, 0x5d9: 0x68, 0x5da: 0x69, 0x5db: 0x6a, 0x5dc: 0x6b, 0x5dd: 0x6c, 0x5de: 0x6d, 0x5df: 0x6e, + 0x5e0: 0x9b, 0x5e1: 0x9b, 0x5e2: 0x9b, 0x5e3: 0x9b, 0x5e4: 0x9b, 0x5e5: 0x9b, 0x5e6: 0x9b, 0x5e7: 0x9b, + 0x5e8: 0x163, 0x5e9: 0x164, 0x5ea: 0x165, 0x5eb: 0xba, 0x5ec: 0xba, 0x5ed: 0xba, 0x5ee: 0xba, 0x5ef: 0xba, + 0x5f0: 0xba, 0x5f1: 0xba, 0x5f2: 0xba, 0x5f3: 0xba, 0x5f4: 0xba, 0x5f5: 0xba, 0x5f6: 0xba, 0x5f7: 0xba, + 0x5f8: 0xba, 0x5f9: 0xba, 0x5fa: 0xba, 0x5fb: 0xba, 0x5fc: 0xba, 0x5fd: 0xba, 0x5fe: 0xba, 0x5ff: 0xba, + // Block 0x18, offset 0x600 + 0x600: 0x166, 0x601: 0xba, 0x602: 0xba, 0x603: 0xba, 0x604: 0xba, 0x605: 0xba, 0x606: 0xba, 0x607: 0xba, + 0x608: 0xba, 0x609: 0xba, 0x60a: 0xba, 0x60b: 0xba, 0x60c: 0xba, 0x60d: 0xba, 0x60e: 0xba, 0x60f: 0xba, + 0x610: 0xba, 0x611: 0xba, 0x612: 0xba, 0x613: 0xba, 0x614: 0xba, 0x615: 0xba, 0x616: 0xba, 0x617: 0xba, + 0x618: 0xba, 0x619: 0xba, 0x61a: 0xba, 0x61b: 0xba, 0x61c: 0xba, 0x61d: 0xba, 0x61e: 0xba, 0x61f: 0xba, + 0x620: 0x122, 0x621: 0x122, 0x622: 0x122, 0x623: 0x167, 0x624: 0x6f, 0x625: 0x168, 0x626: 0xba, 0x627: 0xba, + 0x628: 0xba, 0x629: 0xba, 0x62a: 0xba, 0x62b: 0xba, 0x62c: 0xba, 0x62d: 0xba, 0x62e: 0xba, 0x62f: 0xba, + 0x630: 0xba, 0x631: 0xba, 0x632: 0xba, 0x633: 0xba, 0x634: 0xba, 0x635: 0xba, 0x636: 0xba, 0x637: 0xba, + 0x638: 0x70, 0x639: 0x71, 0x63a: 0x72, 0x63b: 0x169, 0x63c: 0xba, 0x63d: 0xba, 0x63e: 0xba, 0x63f: 0xba, + // Block 0x19, offset 0x640 + 0x640: 0x16a, 0x641: 0x9b, 0x642: 0x16b, 0x643: 0x16c, 0x644: 0x73, 0x645: 0x74, 0x646: 0x16d, 0x647: 0x16e, + 0x648: 0x75, 0x649: 0x16f, 0x64a: 0xba, 0x64b: 0xba, 0x64c: 0x9b, 0x64d: 0x9b, 0x64e: 0x9b, 0x64f: 0x9b, + 0x650: 0x9b, 0x651: 0x9b, 0x652: 0x9b, 0x653: 0x9b, 0x654: 0x9b, 0x655: 0x9b, 0x656: 0x9b, 0x657: 0x9b, + 0x658: 0x9b, 0x659: 0x9b, 0x65a: 0x9b, 0x65b: 0x170, 0x65c: 0x9b, 0x65d: 0x171, 0x65e: 0x9b, 0x65f: 0x172, + 0x660: 0x173, 0x661: 0x174, 0x662: 0x175, 0x663: 0xba, 0x664: 0x176, 0x665: 0x177, 0x666: 0x178, 0x667: 0x179, + 0x668: 0xba, 0x669: 0xba, 0x66a: 0xba, 0x66b: 0xba, 0x66c: 0xba, 0x66d: 0xba, 0x66e: 0xba, 0x66f: 0xba, + 0x670: 0xba, 0x671: 0xba, 0x672: 0xba, 0x673: 0xba, 0x674: 0xba, 0x675: 0xba, 0x676: 0xba, 0x677: 0xba, + 0x678: 0xba, 0x679: 0xba, 0x67a: 0xba, 0x67b: 0xba, 0x67c: 0xba, 0x67d: 0xba, 0x67e: 0xba, 0x67f: 0xba, + // Block 0x1a, offset 0x680 + 0x680: 0x9f, 0x681: 0x9f, 0x682: 0x9f, 0x683: 0x9f, 0x684: 0x9f, 0x685: 0x9f, 0x686: 0x9f, 0x687: 0x9f, + 0x688: 0x9f, 0x689: 0x9f, 0x68a: 0x9f, 0x68b: 0x9f, 0x68c: 0x9f, 0x68d: 0x9f, 0x68e: 0x9f, 0x68f: 0x9f, + 0x690: 0x9f, 0x691: 0x9f, 0x692: 0x9f, 0x693: 0x9f, 0x694: 0x9f, 0x695: 0x9f, 0x696: 0x9f, 0x697: 0x9f, + 0x698: 0x9f, 0x699: 0x9f, 0x69a: 0x9f, 0x69b: 0x17a, 0x69c: 0x9f, 0x69d: 0x9f, 0x69e: 0x9f, 0x69f: 0x9f, + 0x6a0: 0x9f, 0x6a1: 0x9f, 0x6a2: 0x9f, 0x6a3: 0x9f, 0x6a4: 0x9f, 0x6a5: 0x9f, 0x6a6: 0x9f, 0x6a7: 0x9f, + 0x6a8: 0x9f, 0x6a9: 0x9f, 0x6aa: 0x9f, 0x6ab: 0x9f, 0x6ac: 0x9f, 0x6ad: 0x9f, 0x6ae: 0x9f, 0x6af: 0x9f, + 0x6b0: 0x9f, 0x6b1: 0x9f, 0x6b2: 0x9f, 0x6b3: 0x9f, 0x6b4: 0x9f, 0x6b5: 0x9f, 0x6b6: 0x9f, 0x6b7: 0x9f, + 0x6b8: 0x9f, 0x6b9: 0x9f, 0x6ba: 0x9f, 0x6bb: 0x9f, 0x6bc: 0x9f, 0x6bd: 0x9f, 0x6be: 0x9f, 0x6bf: 0x9f, + // Block 0x1b, offset 0x6c0 + 0x6c0: 0x9f, 0x6c1: 0x9f, 0x6c2: 0x9f, 0x6c3: 0x9f, 0x6c4: 0x9f, 0x6c5: 0x9f, 0x6c6: 0x9f, 0x6c7: 0x9f, + 0x6c8: 0x9f, 0x6c9: 0x9f, 0x6ca: 0x9f, 0x6cb: 0x9f, 0x6cc: 0x9f, 0x6cd: 0x9f, 0x6ce: 0x9f, 0x6cf: 0x9f, + 0x6d0: 0x9f, 0x6d1: 0x9f, 0x6d2: 0x9f, 0x6d3: 0x9f, 0x6d4: 0x9f, 0x6d5: 0x9f, 0x6d6: 0x9f, 0x6d7: 0x9f, + 0x6d8: 0x9f, 0x6d9: 0x9f, 0x6da: 0x9f, 0x6db: 0x9f, 0x6dc: 0x17b, 0x6dd: 0x9f, 0x6de: 0x9f, 0x6df: 0x9f, + 0x6e0: 0x17c, 0x6e1: 0x9f, 0x6e2: 0x9f, 0x6e3: 0x9f, 0x6e4: 0x9f, 0x6e5: 0x9f, 0x6e6: 0x9f, 0x6e7: 0x9f, + 0x6e8: 0x9f, 0x6e9: 0x9f, 0x6ea: 0x9f, 0x6eb: 0x9f, 0x6ec: 0x9f, 0x6ed: 0x9f, 0x6ee: 0x9f, 0x6ef: 0x9f, + 0x6f0: 0x9f, 0x6f1: 0x9f, 0x6f2: 0x9f, 0x6f3: 0x9f, 0x6f4: 0x9f, 0x6f5: 0x9f, 0x6f6: 0x9f, 0x6f7: 0x9f, + 0x6f8: 0x9f, 0x6f9: 0x9f, 0x6fa: 0x9f, 0x6fb: 0x9f, 0x6fc: 0x9f, 0x6fd: 0x9f, 0x6fe: 0x9f, 0x6ff: 0x9f, + // Block 0x1c, offset 0x700 + 0x700: 0x9f, 0x701: 0x9f, 0x702: 0x9f, 0x703: 0x9f, 0x704: 0x9f, 0x705: 0x9f, 0x706: 0x9f, 0x707: 0x9f, + 0x708: 0x9f, 0x709: 0x9f, 0x70a: 0x9f, 0x70b: 0x9f, 0x70c: 0x9f, 0x70d: 0x9f, 0x70e: 0x9f, 0x70f: 0x9f, + 0x710: 0x9f, 0x711: 0x9f, 0x712: 0x9f, 0x713: 0x9f, 0x714: 0x9f, 0x715: 0x9f, 0x716: 0x9f, 0x717: 0x9f, + 0x718: 0x9f, 0x719: 0x9f, 0x71a: 0x9f, 0x71b: 0x9f, 0x71c: 0x9f, 0x71d: 0x9f, 0x71e: 0x9f, 0x71f: 0x9f, + 0x720: 0x9f, 0x721: 0x9f, 0x722: 0x9f, 0x723: 0x9f, 0x724: 0x9f, 0x725: 0x9f, 0x726: 0x9f, 0x727: 0x9f, + 0x728: 0x9f, 0x729: 0x9f, 0x72a: 0x9f, 0x72b: 0x9f, 0x72c: 0x9f, 0x72d: 0x9f, 0x72e: 0x9f, 0x72f: 0x9f, + 0x730: 0x9f, 0x731: 0x9f, 0x732: 0x9f, 0x733: 0x9f, 0x734: 0x9f, 0x735: 0x9f, 0x736: 0x9f, 0x737: 0x9f, + 0x738: 0x9f, 0x739: 0x9f, 0x73a: 0x17d, 0x73b: 0x9f, 0x73c: 0x9f, 0x73d: 0x9f, 0x73e: 0x9f, 0x73f: 0x9f, + // Block 0x1d, offset 0x740 + 0x740: 0x9f, 0x741: 0x9f, 0x742: 0x9f, 0x743: 0x9f, 0x744: 0x9f, 0x745: 0x9f, 0x746: 0x9f, 0x747: 0x9f, + 0x748: 0x9f, 0x749: 0x9f, 0x74a: 0x9f, 0x74b: 0x9f, 0x74c: 0x9f, 0x74d: 0x9f, 0x74e: 0x9f, 0x74f: 0x9f, + 0x750: 0x9f, 0x751: 0x9f, 0x752: 0x9f, 0x753: 0x9f, 0x754: 0x9f, 0x755: 0x9f, 0x756: 0x9f, 0x757: 0x9f, + 0x758: 0x9f, 0x759: 0x9f, 0x75a: 0x9f, 0x75b: 0x9f, 0x75c: 0x9f, 0x75d: 0x9f, 0x75e: 0x9f, 0x75f: 0x9f, + 0x760: 0x9f, 0x761: 0x9f, 0x762: 0x9f, 0x763: 0x9f, 0x764: 0x9f, 0x765: 0x9f, 0x766: 0x9f, 0x767: 0x9f, + 0x768: 0x9f, 0x769: 0x9f, 0x76a: 0x9f, 0x76b: 0x9f, 0x76c: 0x9f, 0x76d: 0x9f, 0x76e: 0x9f, 0x76f: 0x17e, + 0x770: 0xba, 0x771: 0xba, 0x772: 0xba, 0x773: 0xba, 0x774: 0xba, 0x775: 0xba, 0x776: 0xba, 0x777: 0xba, + 0x778: 0xba, 0x779: 0xba, 0x77a: 0xba, 0x77b: 0xba, 0x77c: 0xba, 0x77d: 0xba, 0x77e: 0xba, 0x77f: 0xba, + // Block 0x1e, offset 0x780 + 0x780: 0xba, 0x781: 0xba, 0x782: 0xba, 0x783: 0xba, 0x784: 0xba, 0x785: 0xba, 0x786: 0xba, 0x787: 0xba, + 0x788: 0xba, 0x789: 0xba, 0x78a: 0xba, 0x78b: 0xba, 0x78c: 0xba, 0x78d: 0xba, 0x78e: 0xba, 0x78f: 0xba, + 0x790: 0xba, 0x791: 0xba, 0x792: 0xba, 0x793: 0xba, 0x794: 0xba, 0x795: 0xba, 0x796: 0xba, 0x797: 0xba, + 0x798: 0xba, 0x799: 0xba, 0x79a: 0xba, 0x79b: 0xba, 0x79c: 0xba, 0x79d: 0xba, 0x79e: 0xba, 0x79f: 0xba, + 0x7a0: 0x76, 0x7a1: 0x77, 0x7a2: 0x78, 0x7a3: 0x17f, 0x7a4: 0x79, 0x7a5: 0x7a, 0x7a6: 0x180, 0x7a7: 0x7b, + 0x7a8: 0x7c, 0x7a9: 0xba, 0x7aa: 0xba, 0x7ab: 0xba, 0x7ac: 0xba, 0x7ad: 0xba, 0x7ae: 0xba, 0x7af: 0xba, + 0x7b0: 0xba, 0x7b1: 0xba, 0x7b2: 0xba, 0x7b3: 0xba, 0x7b4: 0xba, 0x7b5: 0xba, 0x7b6: 0xba, 0x7b7: 0xba, + 0x7b8: 0xba, 0x7b9: 0xba, 0x7ba: 0xba, 0x7bb: 0xba, 0x7bc: 0xba, 0x7bd: 0xba, 0x7be: 0xba, 0x7bf: 0xba, + // Block 0x1f, offset 0x7c0 + 0x7d0: 0x0d, 0x7d1: 0x0e, 0x7d2: 0x0f, 0x7d3: 0x10, 0x7d4: 0x11, 0x7d5: 0x0b, 0x7d6: 0x12, 0x7d7: 0x07, + 0x7d8: 0x13, 0x7d9: 0x0b, 0x7da: 0x0b, 0x7db: 0x14, 0x7dc: 0x0b, 0x7dd: 0x15, 0x7de: 0x16, 0x7df: 0x17, + 0x7e0: 0x07, 0x7e1: 0x07, 0x7e2: 0x07, 0x7e3: 0x07, 0x7e4: 0x07, 0x7e5: 0x07, 0x7e6: 0x07, 0x7e7: 0x07, + 0x7e8: 0x07, 0x7e9: 0x07, 0x7ea: 0x18, 0x7eb: 0x19, 0x7ec: 0x1a, 0x7ed: 0x07, 0x7ee: 0x1b, 0x7ef: 0x1c, + 0x7f0: 0x0b, 0x7f1: 0x0b, 0x7f2: 0x0b, 0x7f3: 0x0b, 0x7f4: 0x0b, 0x7f5: 0x0b, 0x7f6: 0x0b, 0x7f7: 0x0b, + 0x7f8: 0x0b, 0x7f9: 0x0b, 0x7fa: 0x0b, 0x7fb: 0x0b, 0x7fc: 0x0b, 0x7fd: 0x0b, 0x7fe: 0x0b, 0x7ff: 0x0b, + // Block 0x20, offset 0x800 + 0x800: 0x0b, 0x801: 0x0b, 0x802: 0x0b, 0x803: 0x0b, 0x804: 0x0b, 0x805: 0x0b, 0x806: 0x0b, 0x807: 0x0b, + 0x808: 0x0b, 0x809: 0x0b, 0x80a: 0x0b, 0x80b: 0x0b, 0x80c: 0x0b, 0x80d: 0x0b, 0x80e: 0x0b, 0x80f: 0x0b, + 0x810: 0x0b, 0x811: 0x0b, 0x812: 0x0b, 0x813: 0x0b, 0x814: 0x0b, 0x815: 0x0b, 0x816: 0x0b, 0x817: 0x0b, + 0x818: 0x0b, 0x819: 0x0b, 0x81a: 0x0b, 0x81b: 0x0b, 0x81c: 0x0b, 0x81d: 0x0b, 0x81e: 0x0b, 0x81f: 0x0b, + 0x820: 0x0b, 0x821: 0x0b, 0x822: 0x0b, 0x823: 0x0b, 0x824: 0x0b, 0x825: 0x0b, 0x826: 0x0b, 0x827: 0x0b, + 0x828: 0x0b, 0x829: 0x0b, 0x82a: 0x0b, 0x82b: 0x0b, 0x82c: 0x0b, 0x82d: 0x0b, 0x82e: 0x0b, 0x82f: 0x0b, + 0x830: 0x0b, 0x831: 0x0b, 0x832: 0x0b, 0x833: 0x0b, 0x834: 0x0b, 0x835: 0x0b, 0x836: 0x0b, 0x837: 0x0b, + 0x838: 0x0b, 0x839: 0x0b, 0x83a: 0x0b, 0x83b: 0x0b, 0x83c: 0x0b, 0x83d: 0x0b, 0x83e: 0x0b, 0x83f: 0x0b, + // Block 0x21, offset 0x840 + 0x840: 0x181, 0x841: 0x182, 0x842: 0xba, 0x843: 0xba, 0x844: 0x183, 0x845: 0x183, 0x846: 0x183, 0x847: 0x184, + 0x848: 0xba, 0x849: 0xba, 0x84a: 0xba, 0x84b: 0xba, 0x84c: 0xba, 0x84d: 0xba, 0x84e: 0xba, 0x84f: 0xba, + 0x850: 0xba, 0x851: 0xba, 0x852: 0xba, 0x853: 0xba, 0x854: 0xba, 0x855: 0xba, 0x856: 0xba, 0x857: 0xba, + 0x858: 0xba, 0x859: 0xba, 0x85a: 0xba, 0x85b: 0xba, 0x85c: 0xba, 0x85d: 0xba, 0x85e: 0xba, 0x85f: 0xba, + 0x860: 0xba, 0x861: 0xba, 0x862: 0xba, 0x863: 0xba, 0x864: 0xba, 0x865: 0xba, 0x866: 0xba, 0x867: 0xba, + 0x868: 0xba, 0x869: 0xba, 0x86a: 0xba, 0x86b: 0xba, 0x86c: 0xba, 0x86d: 0xba, 0x86e: 0xba, 0x86f: 0xba, + 0x870: 0xba, 0x871: 0xba, 0x872: 0xba, 0x873: 0xba, 0x874: 0xba, 0x875: 0xba, 0x876: 0xba, 0x877: 0xba, + 0x878: 0xba, 0x879: 0xba, 0x87a: 0xba, 0x87b: 0xba, 0x87c: 0xba, 0x87d: 0xba, 0x87e: 0xba, 0x87f: 0xba, + // Block 0x22, offset 0x880 + 0x880: 0x0b, 0x881: 0x0b, 0x882: 0x0b, 0x883: 0x0b, 0x884: 0x0b, 0x885: 0x0b, 0x886: 0x0b, 0x887: 0x0b, + 0x888: 0x0b, 0x889: 0x0b, 0x88a: 0x0b, 0x88b: 0x0b, 0x88c: 0x0b, 0x88d: 0x0b, 0x88e: 0x0b, 0x88f: 0x0b, + 0x890: 0x0b, 0x891: 0x0b, 0x892: 0x0b, 0x893: 0x0b, 0x894: 0x0b, 0x895: 0x0b, 0x896: 0x0b, 0x897: 0x0b, + 0x898: 0x0b, 0x899: 0x0b, 0x89a: 0x0b, 0x89b: 0x0b, 0x89c: 0x0b, 0x89d: 0x0b, 0x89e: 0x0b, 0x89f: 0x0b, + 0x8a0: 0x1f, 0x8a1: 0x0b, 0x8a2: 0x0b, 0x8a3: 0x0b, 0x8a4: 0x0b, 0x8a5: 0x0b, 0x8a6: 0x0b, 0x8a7: 0x0b, + 0x8a8: 0x0b, 0x8a9: 0x0b, 0x8aa: 0x0b, 0x8ab: 0x0b, 0x8ac: 0x0b, 0x8ad: 0x0b, 0x8ae: 0x0b, 0x8af: 0x0b, + 0x8b0: 0x0b, 0x8b1: 0x0b, 0x8b2: 0x0b, 0x8b3: 0x0b, 0x8b4: 0x0b, 0x8b5: 0x0b, 0x8b6: 0x0b, 0x8b7: 0x0b, + 0x8b8: 0x0b, 0x8b9: 0x0b, 0x8ba: 0x0b, 0x8bb: 0x0b, 0x8bc: 0x0b, 0x8bd: 0x0b, 0x8be: 0x0b, 0x8bf: 0x0b, + // Block 0x23, offset 0x8c0 + 0x8c0: 0x0b, 0x8c1: 0x0b, 0x8c2: 0x0b, 0x8c3: 0x0b, 0x8c4: 0x0b, 0x8c5: 0x0b, 0x8c6: 0x0b, 0x8c7: 0x0b, + 0x8c8: 0x0b, 0x8c9: 0x0b, 0x8ca: 0x0b, 0x8cb: 0x0b, 0x8cc: 0x0b, 0x8cd: 0x0b, 0x8ce: 0x0b, 0x8cf: 0x0b, +} + +// idnaSparseOffset: 264 entries, 528 bytes +var idnaSparseOffset = []uint16{0x0, 0x8, 0x19, 0x25, 0x27, 0x2c, 0x34, 0x3f, 0x4b, 0x4f, 0x5e, 0x63, 0x6b, 0x77, 0x85, 0x8a, 0x93, 0xa3, 0xb1, 0xbd, 0xc9, 0xda, 0xe4, 0xeb, 0xf8, 0x109, 0x110, 0x11b, 0x12a, 0x138, 0x142, 0x144, 0x149, 0x14c, 0x14f, 0x151, 0x15d, 0x168, 0x170, 0x176, 0x17c, 0x181, 0x186, 0x189, 0x18d, 0x193, 0x198, 0x1a4, 0x1ae, 0x1b4, 0x1c5, 0x1cf, 0x1d2, 0x1da, 0x1dd, 0x1ea, 0x1f2, 0x1f6, 0x1fd, 0x205, 0x215, 0x221, 0x223, 0x22d, 0x239, 0x245, 0x251, 0x259, 0x25e, 0x268, 0x279, 0x27d, 0x288, 0x28c, 0x295, 0x29d, 0x2a3, 0x2a8, 0x2ab, 0x2af, 0x2b5, 0x2b9, 0x2bd, 0x2c3, 0x2ca, 0x2d0, 0x2d8, 0x2df, 0x2ea, 0x2f4, 0x2f8, 0x2fb, 0x301, 0x305, 0x307, 0x30a, 0x30c, 0x30f, 0x319, 0x31c, 0x32b, 0x32f, 0x334, 0x337, 0x33b, 0x340, 0x345, 0x34b, 0x351, 0x360, 0x366, 0x36a, 0x379, 0x37e, 0x386, 0x390, 0x39b, 0x3a3, 0x3b4, 0x3bd, 0x3cd, 0x3da, 0x3e4, 0x3e9, 0x3f6, 0x3fa, 0x3ff, 0x401, 0x405, 0x407, 0x40b, 0x414, 0x41a, 0x41e, 0x42e, 0x438, 0x43d, 0x440, 0x446, 0x44d, 0x452, 0x456, 0x45c, 0x461, 0x46a, 0x46f, 0x475, 0x47c, 0x483, 0x48a, 0x48e, 0x493, 0x496, 0x49b, 0x4a7, 0x4ad, 0x4b2, 0x4b9, 0x4c1, 0x4c6, 0x4ca, 0x4da, 0x4e1, 0x4e5, 0x4e9, 0x4f0, 0x4f2, 0x4f5, 0x4f8, 0x4fc, 0x500, 0x506, 0x50f, 0x51b, 0x522, 0x52b, 0x533, 0x53a, 0x548, 0x555, 0x562, 0x56b, 0x56f, 0x57d, 0x585, 0x590, 0x599, 0x59f, 0x5a7, 0x5b0, 0x5ba, 0x5bd, 0x5c9, 0x5cc, 0x5d1, 0x5de, 0x5e7, 0x5f3, 0x5f6, 0x600, 0x609, 0x615, 0x622, 0x62a, 0x62d, 0x632, 0x635, 0x638, 0x63b, 0x642, 0x649, 0x64d, 0x658, 0x65b, 0x661, 0x666, 0x66a, 0x66d, 0x670, 0x673, 0x676, 0x679, 0x67e, 0x688, 0x68b, 0x68f, 0x69e, 0x6aa, 0x6ae, 0x6b3, 0x6b8, 0x6bc, 0x6c1, 0x6ca, 0x6d5, 0x6db, 0x6e3, 0x6e7, 0x6eb, 0x6f1, 0x6f7, 0x6fc, 0x6ff, 0x70f, 0x716, 0x719, 0x71c, 0x720, 0x726, 0x72b, 0x730, 0x735, 0x738, 0x73d, 0x740, 0x743, 0x747, 0x74b, 0x74e, 0x75e, 0x76f, 0x774, 0x776, 0x778} + +// idnaSparseValues: 1915 entries, 7660 bytes +var idnaSparseValues = [1915]valueRange{ + // Block 0x0, offset 0x0 + {value: 0x0000, lo: 0x07}, + {value: 0xe105, lo: 0x80, hi: 0x96}, + {value: 0x0018, lo: 0x97, hi: 0x97}, + {value: 0xe105, lo: 0x98, hi: 0x9e}, + {value: 0x001f, lo: 0x9f, hi: 0x9f}, + {value: 0x0008, lo: 0xa0, hi: 0xb6}, + {value: 0x0018, lo: 0xb7, hi: 0xb7}, + {value: 0x0008, lo: 0xb8, hi: 0xbf}, + // Block 0x1, offset 0x8 + {value: 0x0000, lo: 0x10}, + {value: 0x0008, lo: 0x80, hi: 0x80}, + {value: 0xe01d, lo: 0x81, hi: 0x81}, + {value: 0x0008, lo: 0x82, hi: 0x82}, + {value: 0x0335, lo: 0x83, hi: 0x83}, + {value: 0x034d, lo: 0x84, hi: 0x84}, + {value: 0x0365, lo: 0x85, hi: 0x85}, + {value: 0xe00d, lo: 0x86, hi: 0x86}, + {value: 0x0008, lo: 0x87, hi: 0x87}, + {value: 0xe00d, lo: 0x88, hi: 0x88}, + {value: 0x0008, lo: 0x89, hi: 0x89}, + {value: 0xe00d, lo: 0x8a, hi: 0x8a}, + {value: 0x0008, lo: 0x8b, hi: 0x8b}, + {value: 0xe00d, lo: 0x8c, hi: 0x8c}, + {value: 0x0008, lo: 0x8d, hi: 0x8d}, + {value: 0xe00d, lo: 0x8e, hi: 0x8e}, + {value: 0x0008, lo: 0x8f, hi: 0xbf}, + // Block 0x2, offset 0x19 + {value: 0x0000, lo: 0x0b}, + {value: 0x0008, lo: 0x80, hi: 0xaf}, + {value: 0x0249, lo: 0xb0, hi: 0xb0}, + {value: 0x037d, lo: 0xb1, hi: 0xb1}, + {value: 0x0259, lo: 0xb2, hi: 0xb2}, + {value: 0x0269, lo: 0xb3, hi: 0xb3}, + {value: 0x034d, lo: 0xb4, hi: 0xb4}, + {value: 0x0395, lo: 0xb5, hi: 0xb5}, + {value: 0xe1bd, lo: 0xb6, hi: 0xb6}, + {value: 0x0279, lo: 0xb7, hi: 0xb7}, + {value: 0x0289, lo: 0xb8, hi: 0xb8}, + {value: 0x0008, lo: 0xb9, hi: 0xbf}, + // Block 0x3, offset 0x25 + {value: 0x0000, lo: 0x01}, + {value: 0x3308, lo: 0x80, hi: 0xbf}, + // Block 0x4, offset 0x27 + {value: 0x0000, lo: 0x04}, + {value: 0x03f5, lo: 0x80, hi: 0x8f}, + {value: 0xe105, lo: 0x90, hi: 0x9f}, + {value: 0x049d, lo: 0xa0, hi: 0xaf}, + {value: 0x0008, lo: 0xb0, hi: 0xbf}, + // Block 0x5, offset 0x2c + {value: 0x0000, lo: 0x07}, + {value: 0xe185, lo: 0x80, hi: 0x8f}, + {value: 0x0545, lo: 0x90, hi: 0x96}, + {value: 0x0040, lo: 0x97, hi: 0x98}, + {value: 0x0008, lo: 0x99, hi: 0x99}, + {value: 0x0018, lo: 0x9a, hi: 0x9f}, + {value: 0x0040, lo: 0xa0, hi: 0xa0}, + {value: 0x0008, lo: 0xa1, hi: 0xbf}, + // Block 0x6, offset 0x34 + {value: 0x0000, lo: 0x0a}, + {value: 0x0008, lo: 0x80, hi: 0x86}, + {value: 0x0401, lo: 0x87, hi: 0x87}, + {value: 0x0040, lo: 0x88, hi: 0x88}, + {value: 0x0018, lo: 0x89, hi: 0x8a}, + {value: 0x0040, lo: 0x8b, hi: 0x8c}, + {value: 0x0018, lo: 0x8d, hi: 0x8f}, + {value: 0x0040, lo: 0x90, hi: 0x90}, + {value: 0x3308, lo: 0x91, hi: 0xbd}, + {value: 0x0818, lo: 0xbe, hi: 0xbe}, + {value: 0x3308, lo: 0xbf, hi: 0xbf}, + // Block 0x7, offset 0x3f + {value: 0x0000, lo: 0x0b}, + {value: 0x0818, lo: 0x80, hi: 0x80}, + {value: 0x3308, lo: 0x81, hi: 0x82}, + {value: 0x0818, lo: 0x83, hi: 0x83}, + {value: 0x3308, lo: 0x84, hi: 0x85}, + {value: 0x0818, lo: 0x86, hi: 0x86}, + {value: 0x3308, lo: 0x87, hi: 0x87}, + {value: 0x0040, lo: 0x88, hi: 0x8f}, + {value: 0x0808, lo: 0x90, hi: 0xaa}, + {value: 0x0040, lo: 0xab, hi: 0xaf}, + {value: 0x0808, lo: 0xb0, hi: 0xb4}, + {value: 0x0040, lo: 0xb5, hi: 0xbf}, + // Block 0x8, offset 0x4b + {value: 0x0000, lo: 0x03}, + {value: 0x0a08, lo: 0x80, hi: 0x87}, + {value: 0x0c08, lo: 0x88, hi: 0x99}, + {value: 0x0a08, lo: 0x9a, hi: 0xbf}, + // Block 0x9, offset 0x4f + {value: 0x0000, lo: 0x0e}, + {value: 0x3308, lo: 0x80, hi: 0x8a}, + {value: 0x0040, lo: 0x8b, hi: 0x8c}, + {value: 0x0c08, lo: 0x8d, hi: 0x8d}, + {value: 0x0a08, lo: 0x8e, hi: 0x98}, + {value: 0x0c08, lo: 0x99, hi: 0x9b}, + {value: 0x0a08, lo: 0x9c, hi: 0xaa}, + {value: 0x0c08, lo: 0xab, hi: 0xac}, + {value: 0x0a08, lo: 0xad, hi: 0xb0}, + {value: 0x0c08, lo: 0xb1, hi: 0xb1}, + {value: 0x0a08, lo: 0xb2, hi: 0xb2}, + {value: 0x0c08, lo: 0xb3, hi: 0xb4}, + {value: 0x0a08, lo: 0xb5, hi: 0xb7}, + {value: 0x0c08, lo: 0xb8, hi: 0xb9}, + {value: 0x0a08, lo: 0xba, hi: 0xbf}, + // Block 0xa, offset 0x5e + {value: 0x0000, lo: 0x04}, + {value: 0x0808, lo: 0x80, hi: 0xa5}, + {value: 0x3308, lo: 0xa6, hi: 0xb0}, + {value: 0x0808, lo: 0xb1, hi: 0xb1}, + {value: 0x0040, lo: 0xb2, hi: 0xbf}, + // Block 0xb, offset 0x63 + {value: 0x0000, lo: 0x07}, + {value: 0x0808, lo: 0x80, hi: 0x89}, + {value: 0x0a08, lo: 0x8a, hi: 0xaa}, + {value: 0x3308, lo: 0xab, hi: 0xb3}, + {value: 0x0808, lo: 0xb4, hi: 0xb5}, + {value: 0x0018, lo: 0xb6, hi: 0xb9}, + {value: 0x0818, lo: 0xba, hi: 0xba}, + {value: 0x0040, lo: 0xbb, hi: 0xbf}, + // Block 0xc, offset 0x6b + {value: 0x0000, lo: 0x0b}, + {value: 0x0808, lo: 0x80, hi: 0x95}, + {value: 0x3308, lo: 0x96, hi: 0x99}, + {value: 0x0808, lo: 0x9a, hi: 0x9a}, + {value: 0x3308, lo: 0x9b, hi: 0xa3}, + {value: 0x0808, lo: 0xa4, hi: 0xa4}, + {value: 0x3308, lo: 0xa5, hi: 0xa7}, + {value: 0x0808, lo: 0xa8, hi: 0xa8}, + {value: 0x3308, lo: 0xa9, hi: 0xad}, + {value: 0x0040, lo: 0xae, hi: 0xaf}, + {value: 0x0818, lo: 0xb0, hi: 0xbe}, + {value: 0x0040, lo: 0xbf, hi: 0xbf}, + // Block 0xd, offset 0x77 + {value: 0x0000, lo: 0x0d}, + {value: 0x0040, lo: 0x80, hi: 0x9f}, + {value: 0x0a08, lo: 0xa0, hi: 0xa9}, + {value: 0x0c08, lo: 0xaa, hi: 0xac}, + {value: 0x0808, lo: 0xad, hi: 0xad}, + {value: 0x0c08, lo: 0xae, hi: 0xae}, + {value: 0x0a08, lo: 0xaf, hi: 0xb0}, + {value: 0x0c08, lo: 0xb1, hi: 0xb2}, + {value: 0x0a08, lo: 0xb3, hi: 0xb4}, + {value: 0x0040, lo: 0xb5, hi: 0xb5}, + {value: 0x0a08, lo: 0xb6, hi: 0xb8}, + {value: 0x0c08, lo: 0xb9, hi: 0xb9}, + {value: 0x0a08, lo: 0xba, hi: 0xbd}, + {value: 0x0040, lo: 0xbe, hi: 0xbf}, + // Block 0xe, offset 0x85 + {value: 0x0000, lo: 0x04}, + {value: 0x0040, lo: 0x80, hi: 0x93}, + {value: 0x3308, lo: 0x94, hi: 0xa1}, + {value: 0x0840, lo: 0xa2, hi: 0xa2}, + {value: 0x3308, lo: 0xa3, hi: 0xbf}, + // Block 0xf, offset 0x8a + {value: 0x0000, lo: 0x08}, + {value: 0x3308, lo: 0x80, hi: 0x82}, + {value: 0x3008, lo: 0x83, hi: 0x83}, + {value: 0x0008, lo: 0x84, hi: 0xb9}, + {value: 0x3308, lo: 0xba, hi: 0xba}, + {value: 0x3008, lo: 0xbb, hi: 0xbb}, + {value: 0x3308, lo: 0xbc, hi: 0xbc}, + {value: 0x0008, lo: 0xbd, hi: 0xbd}, + {value: 0x3008, lo: 0xbe, hi: 0xbf}, + // Block 0x10, offset 0x93 + {value: 0x0000, lo: 0x0f}, + {value: 0x3308, lo: 0x80, hi: 0x80}, + {value: 0x3008, lo: 0x81, hi: 0x82}, + {value: 0x0040, lo: 0x83, hi: 0x85}, + {value: 0x3008, lo: 0x86, hi: 0x88}, + {value: 0x0040, lo: 0x89, hi: 0x89}, + {value: 0x3008, lo: 0x8a, hi: 0x8c}, + {value: 0x3b08, lo: 0x8d, hi: 0x8d}, + {value: 0x0040, lo: 0x8e, hi: 0x8f}, + {value: 0x0008, lo: 0x90, hi: 0x90}, + {value: 0x0040, lo: 0x91, hi: 0x96}, + {value: 0x3008, lo: 0x97, hi: 0x97}, + {value: 0x0040, lo: 0x98, hi: 0xa5}, + {value: 0x0008, lo: 0xa6, hi: 0xaf}, + {value: 0x0018, lo: 0xb0, hi: 0xba}, + {value: 0x0040, lo: 0xbb, hi: 0xbf}, + // Block 0x11, offset 0xa3 + {value: 0x0000, lo: 0x0d}, + {value: 0x3308, lo: 0x80, hi: 0x80}, + {value: 0x3008, lo: 0x81, hi: 0x83}, + {value: 0x0040, lo: 0x84, hi: 0x84}, + {value: 0x0008, lo: 0x85, hi: 0x8c}, + {value: 0x0040, lo: 0x8d, hi: 0x8d}, + {value: 0x0008, lo: 0x8e, hi: 0x90}, + {value: 0x0040, lo: 0x91, hi: 0x91}, + {value: 0x0008, lo: 0x92, hi: 0xa8}, + {value: 0x0040, lo: 0xa9, hi: 0xa9}, + {value: 0x0008, lo: 0xaa, hi: 0xb9}, + {value: 0x0040, lo: 0xba, hi: 0xbc}, + {value: 0x0008, lo: 0xbd, hi: 0xbd}, + {value: 0x3308, lo: 0xbe, hi: 0xbf}, + // Block 0x12, offset 0xb1 + {value: 0x0000, lo: 0x0b}, + {value: 0x3308, lo: 0x80, hi: 0x81}, + {value: 0x3008, lo: 0x82, hi: 0x83}, + {value: 0x0040, lo: 0x84, hi: 0x84}, + {value: 0x0008, lo: 0x85, hi: 0x8c}, + {value: 0x0040, lo: 0x8d, hi: 0x8d}, + {value: 0x0008, lo: 0x8e, hi: 0x90}, + {value: 0x0040, lo: 0x91, hi: 0x91}, + {value: 0x0008, lo: 0x92, hi: 0xba}, + {value: 0x3b08, lo: 0xbb, hi: 0xbc}, + {value: 0x0008, lo: 0xbd, hi: 0xbd}, + {value: 0x3008, lo: 0xbe, hi: 0xbf}, + // Block 0x13, offset 0xbd + {value: 0x0000, lo: 0x0b}, + {value: 0x0040, lo: 0x80, hi: 0x81}, + {value: 0x3008, lo: 0x82, hi: 0x83}, + {value: 0x0040, lo: 0x84, hi: 0x84}, + {value: 0x0008, lo: 0x85, hi: 0x96}, + {value: 0x0040, lo: 0x97, hi: 0x99}, + {value: 0x0008, lo: 0x9a, hi: 0xb1}, + {value: 0x0040, lo: 0xb2, hi: 0xb2}, + {value: 0x0008, lo: 0xb3, hi: 0xbb}, + {value: 0x0040, lo: 0xbc, hi: 0xbc}, + {value: 0x0008, lo: 0xbd, hi: 0xbd}, + {value: 0x0040, lo: 0xbe, hi: 0xbf}, + // Block 0x14, offset 0xc9 + {value: 0x0000, lo: 0x10}, + {value: 0x0008, lo: 0x80, hi: 0x86}, + {value: 0x0040, lo: 0x87, hi: 0x89}, + {value: 0x3b08, lo: 0x8a, hi: 0x8a}, + {value: 0x0040, lo: 0x8b, hi: 0x8e}, + {value: 0x3008, lo: 0x8f, hi: 0x91}, + {value: 0x3308, lo: 0x92, hi: 0x94}, + {value: 0x0040, lo: 0x95, hi: 0x95}, + {value: 0x3308, lo: 0x96, hi: 0x96}, + {value: 0x0040, lo: 0x97, hi: 0x97}, + {value: 0x3008, lo: 0x98, hi: 0x9f}, + {value: 0x0040, lo: 0xa0, hi: 0xa5}, + {value: 0x0008, lo: 0xa6, hi: 0xaf}, + {value: 0x0040, lo: 0xb0, hi: 0xb1}, + {value: 0x3008, lo: 0xb2, hi: 0xb3}, + {value: 0x0018, lo: 0xb4, hi: 0xb4}, + {value: 0x0040, lo: 0xb5, hi: 0xbf}, + // Block 0x15, offset 0xda + {value: 0x0000, lo: 0x09}, + {value: 0x0040, lo: 0x80, hi: 0x80}, + {value: 0x0008, lo: 0x81, hi: 0xb0}, + {value: 0x3308, lo: 0xb1, hi: 0xb1}, + {value: 0x0008, lo: 0xb2, hi: 0xb2}, + {value: 0x08f1, lo: 0xb3, hi: 0xb3}, + {value: 0x3308, lo: 0xb4, hi: 0xb9}, + {value: 0x3b08, lo: 0xba, hi: 0xba}, + {value: 0x0040, lo: 0xbb, hi: 0xbe}, + {value: 0x0018, lo: 0xbf, hi: 0xbf}, + // Block 0x16, offset 0xe4 + {value: 0x0000, lo: 0x06}, + {value: 0x0008, lo: 0x80, hi: 0x86}, + {value: 0x3308, lo: 0x87, hi: 0x8e}, + {value: 0x0018, lo: 0x8f, hi: 0x8f}, + {value: 0x0008, lo: 0x90, hi: 0x99}, + {value: 0x0018, lo: 0x9a, hi: 0x9b}, + {value: 0x0040, lo: 0x9c, hi: 0xbf}, + // Block 0x17, offset 0xeb + {value: 0x0000, lo: 0x0c}, + {value: 0x0008, lo: 0x80, hi: 0x84}, + {value: 0x0040, lo: 0x85, hi: 0x85}, + {value: 0x0008, lo: 0x86, hi: 0x86}, + {value: 0x0040, lo: 0x87, hi: 0x87}, + {value: 0x3308, lo: 0x88, hi: 0x8d}, + {value: 0x0040, lo: 0x8e, hi: 0x8f}, + {value: 0x0008, lo: 0x90, hi: 0x99}, + {value: 0x0040, lo: 0x9a, hi: 0x9b}, + {value: 0x0961, lo: 0x9c, hi: 0x9c}, + {value: 0x0999, lo: 0x9d, hi: 0x9d}, + {value: 0x0008, lo: 0x9e, hi: 0x9f}, + {value: 0x0040, lo: 0xa0, hi: 0xbf}, + // Block 0x18, offset 0xf8 + {value: 0x0000, lo: 0x10}, + {value: 0x0008, lo: 0x80, hi: 0x80}, + {value: 0x0018, lo: 0x81, hi: 0x8a}, + {value: 0x0008, lo: 0x8b, hi: 0x8b}, + {value: 0xe03d, lo: 0x8c, hi: 0x8c}, + {value: 0x0018, lo: 0x8d, hi: 0x97}, + {value: 0x3308, lo: 0x98, hi: 0x99}, + {value: 0x0018, lo: 0x9a, hi: 0x9f}, + {value: 0x0008, lo: 0xa0, hi: 0xa9}, + {value: 0x0018, lo: 0xaa, hi: 0xb4}, + {value: 0x3308, lo: 0xb5, hi: 0xb5}, + {value: 0x0018, lo: 0xb6, hi: 0xb6}, + {value: 0x3308, lo: 0xb7, hi: 0xb7}, + {value: 0x0018, lo: 0xb8, hi: 0xb8}, + {value: 0x3308, lo: 0xb9, hi: 0xb9}, + {value: 0x0018, lo: 0xba, hi: 0xbd}, + {value: 0x3008, lo: 0xbe, hi: 0xbf}, + // Block 0x19, offset 0x109 + {value: 0x0000, lo: 0x06}, + {value: 0x0018, lo: 0x80, hi: 0x85}, + {value: 0x3308, lo: 0x86, hi: 0x86}, + {value: 0x0018, lo: 0x87, hi: 0x8c}, + {value: 0x0040, lo: 0x8d, hi: 0x8d}, + {value: 0x0018, lo: 0x8e, hi: 0x9a}, + {value: 0x0040, lo: 0x9b, hi: 0xbf}, + // Block 0x1a, offset 0x110 + {value: 0x0000, lo: 0x0a}, + {value: 0x0008, lo: 0x80, hi: 0xaa}, + {value: 0x3008, lo: 0xab, hi: 0xac}, + {value: 0x3308, lo: 0xad, hi: 0xb0}, + {value: 0x3008, lo: 0xb1, hi: 0xb1}, + {value: 0x3308, lo: 0xb2, hi: 0xb7}, + {value: 0x3008, lo: 0xb8, hi: 0xb8}, + {value: 0x3b08, lo: 0xb9, hi: 0xba}, + {value: 0x3008, lo: 0xbb, hi: 0xbc}, + {value: 0x3308, lo: 0xbd, hi: 0xbe}, + {value: 0x0008, lo: 0xbf, hi: 0xbf}, + // Block 0x1b, offset 0x11b + {value: 0x0000, lo: 0x0e}, + {value: 0x0008, lo: 0x80, hi: 0x89}, + {value: 0x0018, lo: 0x8a, hi: 0x8f}, + {value: 0x0008, lo: 0x90, hi: 0x95}, + {value: 0x3008, lo: 0x96, hi: 0x97}, + {value: 0x3308, lo: 0x98, hi: 0x99}, + {value: 0x0008, lo: 0x9a, hi: 0x9d}, + {value: 0x3308, lo: 0x9e, hi: 0xa0}, + {value: 0x0008, lo: 0xa1, hi: 0xa1}, + {value: 0x3008, lo: 0xa2, hi: 0xa4}, + {value: 0x0008, lo: 0xa5, hi: 0xa6}, + {value: 0x3008, lo: 0xa7, hi: 0xad}, + {value: 0x0008, lo: 0xae, hi: 0xb0}, + {value: 0x3308, lo: 0xb1, hi: 0xb4}, + {value: 0x0008, lo: 0xb5, hi: 0xbf}, + // Block 0x1c, offset 0x12a + {value: 0x0000, lo: 0x0d}, + {value: 0x0008, lo: 0x80, hi: 0x81}, + {value: 0x3308, lo: 0x82, hi: 0x82}, + {value: 0x3008, lo: 0x83, hi: 0x84}, + {value: 0x3308, lo: 0x85, hi: 0x86}, + {value: 0x3008, lo: 0x87, hi: 0x8c}, + {value: 0x3308, lo: 0x8d, hi: 0x8d}, + {value: 0x0008, lo: 0x8e, hi: 0x8e}, + {value: 0x3008, lo: 0x8f, hi: 0x8f}, + {value: 0x0008, lo: 0x90, hi: 0x99}, + {value: 0x3008, lo: 0x9a, hi: 0x9c}, + {value: 0x3308, lo: 0x9d, hi: 0x9d}, + {value: 0x0018, lo: 0x9e, hi: 0x9f}, + {value: 0x0040, lo: 0xa0, hi: 0xbf}, + // Block 0x1d, offset 0x138 + {value: 0x0000, lo: 0x09}, + {value: 0x0040, lo: 0x80, hi: 0x86}, + {value: 0x055d, lo: 0x87, hi: 0x87}, + {value: 0x0040, lo: 0x88, hi: 0x8c}, + {value: 0x055d, lo: 0x8d, hi: 0x8d}, + {value: 0x0040, lo: 0x8e, hi: 0x8f}, + {value: 0x0008, lo: 0x90, hi: 0xba}, + {value: 0x0018, lo: 0xbb, hi: 0xbb}, + {value: 0xe105, lo: 0xbc, hi: 0xbc}, + {value: 0x0008, lo: 0xbd, hi: 0xbf}, + // Block 0x1e, offset 0x142 + {value: 0x0000, lo: 0x01}, + {value: 0x0018, lo: 0x80, hi: 0xbf}, + // Block 0x1f, offset 0x144 + {value: 0x0000, lo: 0x04}, + {value: 0x0018, lo: 0x80, hi: 0x9e}, + {value: 0x0040, lo: 0x9f, hi: 0xa0}, + {value: 0x2018, lo: 0xa1, hi: 0xb5}, + {value: 0x0018, lo: 0xb6, hi: 0xbf}, + // Block 0x20, offset 0x149 + {value: 0x0000, lo: 0x02}, + {value: 0x0018, lo: 0x80, hi: 0xa7}, + {value: 0x2018, lo: 0xa8, hi: 0xbf}, + // Block 0x21, offset 0x14c + {value: 0x0000, lo: 0x02}, + {value: 0x2018, lo: 0x80, hi: 0x82}, + {value: 0x0018, lo: 0x83, hi: 0xbf}, + // Block 0x22, offset 0x14f + {value: 0x0000, lo: 0x01}, + {value: 0x0008, lo: 0x80, hi: 0xbf}, + // Block 0x23, offset 0x151 + {value: 0x0000, lo: 0x0b}, + {value: 0x0008, lo: 0x80, hi: 0x88}, + {value: 0x0040, lo: 0x89, hi: 0x89}, + {value: 0x0008, lo: 0x8a, hi: 0x8d}, + {value: 0x0040, lo: 0x8e, hi: 0x8f}, + {value: 0x0008, lo: 0x90, hi: 0x96}, + {value: 0x0040, lo: 0x97, hi: 0x97}, + {value: 0x0008, lo: 0x98, hi: 0x98}, + {value: 0x0040, lo: 0x99, hi: 0x99}, + {value: 0x0008, lo: 0x9a, hi: 0x9d}, + {value: 0x0040, lo: 0x9e, hi: 0x9f}, + {value: 0x0008, lo: 0xa0, hi: 0xbf}, + // Block 0x24, offset 0x15d + {value: 0x0000, lo: 0x0a}, + {value: 0x0008, lo: 0x80, hi: 0x88}, + {value: 0x0040, lo: 0x89, hi: 0x89}, + {value: 0x0008, lo: 0x8a, hi: 0x8d}, + {value: 0x0040, lo: 0x8e, hi: 0x8f}, + {value: 0x0008, lo: 0x90, hi: 0xb0}, + {value: 0x0040, lo: 0xb1, hi: 0xb1}, + {value: 0x0008, lo: 0xb2, hi: 0xb5}, + {value: 0x0040, lo: 0xb6, hi: 0xb7}, + {value: 0x0008, lo: 0xb8, hi: 0xbe}, + {value: 0x0040, lo: 0xbf, hi: 0xbf}, + // Block 0x25, offset 0x168 + {value: 0x0000, lo: 0x07}, + {value: 0x0008, lo: 0x80, hi: 0x80}, + {value: 0x0040, lo: 0x81, hi: 0x81}, + {value: 0x0008, lo: 0x82, hi: 0x85}, + {value: 0x0040, lo: 0x86, hi: 0x87}, + {value: 0x0008, lo: 0x88, hi: 0x96}, + {value: 0x0040, lo: 0x97, hi: 0x97}, + {value: 0x0008, lo: 0x98, hi: 0xbf}, + // Block 0x26, offset 0x170 + {value: 0x0000, lo: 0x05}, + {value: 0x0008, lo: 0x80, hi: 0x90}, + {value: 0x0040, lo: 0x91, hi: 0x91}, + {value: 0x0008, lo: 0x92, hi: 0x95}, + {value: 0x0040, lo: 0x96, hi: 0x97}, + {value: 0x0008, lo: 0x98, hi: 0xbf}, + // Block 0x27, offset 0x176 + {value: 0x0000, lo: 0x05}, + {value: 0x0008, lo: 0x80, hi: 0x9a}, + {value: 0x0040, lo: 0x9b, hi: 0x9c}, + {value: 0x3308, lo: 0x9d, hi: 0x9f}, + {value: 0x0018, lo: 0xa0, hi: 0xbc}, + {value: 0x0040, lo: 0xbd, hi: 0xbf}, + // Block 0x28, offset 0x17c + {value: 0x0000, lo: 0x04}, + {value: 0x0008, lo: 0x80, hi: 0x8f}, + {value: 0x0018, lo: 0x90, hi: 0x99}, + {value: 0x0040, lo: 0x9a, hi: 0x9f}, + {value: 0x0008, lo: 0xa0, hi: 0xbf}, + // Block 0x29, offset 0x181 + {value: 0x0000, lo: 0x04}, + {value: 0x0008, lo: 0x80, hi: 0xb5}, + {value: 0x0040, lo: 0xb6, hi: 0xb7}, + {value: 0xe045, lo: 0xb8, hi: 0xbd}, + {value: 0x0040, lo: 0xbe, hi: 0xbf}, + // Block 0x2a, offset 0x186 + {value: 0x0000, lo: 0x02}, + {value: 0x0018, lo: 0x80, hi: 0x80}, + {value: 0x0008, lo: 0x81, hi: 0xbf}, + // Block 0x2b, offset 0x189 + {value: 0x0000, lo: 0x03}, + {value: 0x0008, lo: 0x80, hi: 0xac}, + {value: 0x0018, lo: 0xad, hi: 0xae}, + {value: 0x0008, lo: 0xaf, hi: 0xbf}, + // Block 0x2c, offset 0x18d + {value: 0x0000, lo: 0x05}, + {value: 0x0040, lo: 0x80, hi: 0x80}, + {value: 0x0008, lo: 0x81, hi: 0x9a}, + {value: 0x0018, lo: 0x9b, hi: 0x9c}, + {value: 0x0040, lo: 0x9d, hi: 0x9f}, + {value: 0x0008, lo: 0xa0, hi: 0xbf}, + // Block 0x2d, offset 0x193 + {value: 0x0000, lo: 0x04}, + {value: 0x0008, lo: 0x80, hi: 0xaa}, + {value: 0x0018, lo: 0xab, hi: 0xb0}, + {value: 0x0008, lo: 0xb1, hi: 0xb8}, + {value: 0x0040, lo: 0xb9, hi: 0xbf}, + // Block 0x2e, offset 0x198 + {value: 0x0000, lo: 0x0b}, + {value: 0x0008, lo: 0x80, hi: 0x8c}, + {value: 0x0040, lo: 0x8d, hi: 0x8d}, + {value: 0x0008, lo: 0x8e, hi: 0x91}, + {value: 0x3308, lo: 0x92, hi: 0x93}, + {value: 0x3b08, lo: 0x94, hi: 0x94}, + {value: 0x0040, lo: 0x95, hi: 0x9f}, + {value: 0x0008, lo: 0xa0, hi: 0xb1}, + {value: 0x3308, lo: 0xb2, hi: 0xb3}, + {value: 0x3b08, lo: 0xb4, hi: 0xb4}, + {value: 0x0018, lo: 0xb5, hi: 0xb6}, + {value: 0x0040, lo: 0xb7, hi: 0xbf}, + // Block 0x2f, offset 0x1a4 + {value: 0x0000, lo: 0x09}, + {value: 0x0008, lo: 0x80, hi: 0x91}, + {value: 0x3308, lo: 0x92, hi: 0x93}, + {value: 0x0040, lo: 0x94, hi: 0x9f}, + {value: 0x0008, lo: 0xa0, hi: 0xac}, + {value: 0x0040, lo: 0xad, hi: 0xad}, + {value: 0x0008, lo: 0xae, hi: 0xb0}, + {value: 0x0040, lo: 0xb1, hi: 0xb1}, + {value: 0x3308, lo: 0xb2, hi: 0xb3}, + {value: 0x0040, lo: 0xb4, hi: 0xbf}, + // Block 0x30, offset 0x1ae + {value: 0x0000, lo: 0x05}, + {value: 0x0008, lo: 0x80, hi: 0xb3}, + {value: 0x3340, lo: 0xb4, hi: 0xb5}, + {value: 0x3008, lo: 0xb6, hi: 0xb6}, + {value: 0x3308, lo: 0xb7, hi: 0xbd}, + {value: 0x3008, lo: 0xbe, hi: 0xbf}, + // Block 0x31, offset 0x1b4 + {value: 0x0000, lo: 0x10}, + {value: 0x3008, lo: 0x80, hi: 0x85}, + {value: 0x3308, lo: 0x86, hi: 0x86}, + {value: 0x3008, lo: 0x87, hi: 0x88}, + {value: 0x3308, lo: 0x89, hi: 0x91}, + {value: 0x3b08, lo: 0x92, hi: 0x92}, + {value: 0x3308, lo: 0x93, hi: 0x93}, + {value: 0x0018, lo: 0x94, hi: 0x96}, + {value: 0x0008, lo: 0x97, hi: 0x97}, + {value: 0x0018, lo: 0x98, hi: 0x9b}, + {value: 0x0008, lo: 0x9c, hi: 0x9c}, + {value: 0x3308, lo: 0x9d, hi: 0x9d}, + {value: 0x0040, lo: 0x9e, hi: 0x9f}, + {value: 0x0008, lo: 0xa0, hi: 0xa9}, + {value: 0x0040, lo: 0xaa, hi: 0xaf}, + {value: 0x0018, lo: 0xb0, hi: 0xb9}, + {value: 0x0040, lo: 0xba, hi: 0xbf}, + // Block 0x32, offset 0x1c5 + {value: 0x0000, lo: 0x09}, + {value: 0x0018, lo: 0x80, hi: 0x85}, + {value: 0x0040, lo: 0x86, hi: 0x86}, + {value: 0x0218, lo: 0x87, hi: 0x87}, + {value: 0x0018, lo: 0x88, hi: 0x8a}, + {value: 0x33c0, lo: 0x8b, hi: 0x8d}, + {value: 0x0040, lo: 0x8e, hi: 0x8f}, + {value: 0x0008, lo: 0x90, hi: 0x99}, + {value: 0x0040, lo: 0x9a, hi: 0x9f}, + {value: 0x0208, lo: 0xa0, hi: 0xbf}, + // Block 0x33, offset 0x1cf + {value: 0x0000, lo: 0x02}, + {value: 0x0208, lo: 0x80, hi: 0xb7}, + {value: 0x0040, lo: 0xb8, hi: 0xbf}, + // Block 0x34, offset 0x1d2 + {value: 0x0000, lo: 0x07}, + {value: 0x0008, lo: 0x80, hi: 0x84}, + {value: 0x3308, lo: 0x85, hi: 0x86}, + {value: 0x0208, lo: 0x87, hi: 0xa8}, + {value: 0x3308, lo: 0xa9, hi: 0xa9}, + {value: 0x0208, lo: 0xaa, hi: 0xaa}, + {value: 0x0040, lo: 0xab, hi: 0xaf}, + {value: 0x0008, lo: 0xb0, hi: 0xbf}, + // Block 0x35, offset 0x1da + {value: 0x0000, lo: 0x02}, + {value: 0x0008, lo: 0x80, hi: 0xb5}, + {value: 0x0040, lo: 0xb6, hi: 0xbf}, + // Block 0x36, offset 0x1dd + {value: 0x0000, lo: 0x0c}, + {value: 0x0008, lo: 0x80, hi: 0x9e}, + {value: 0x0040, lo: 0x9f, hi: 0x9f}, + {value: 0x3308, lo: 0xa0, hi: 0xa2}, + {value: 0x3008, lo: 0xa3, hi: 0xa6}, + {value: 0x3308, lo: 0xa7, hi: 0xa8}, + {value: 0x3008, lo: 0xa9, hi: 0xab}, + {value: 0x0040, lo: 0xac, hi: 0xaf}, + {value: 0x3008, lo: 0xb0, hi: 0xb1}, + {value: 0x3308, lo: 0xb2, hi: 0xb2}, + {value: 0x3008, lo: 0xb3, hi: 0xb8}, + {value: 0x3308, lo: 0xb9, hi: 0xbb}, + {value: 0x0040, lo: 0xbc, hi: 0xbf}, + // Block 0x37, offset 0x1ea + {value: 0x0000, lo: 0x07}, + {value: 0x0018, lo: 0x80, hi: 0x80}, + {value: 0x0040, lo: 0x81, hi: 0x83}, + {value: 0x0018, lo: 0x84, hi: 0x85}, + {value: 0x0008, lo: 0x86, hi: 0xad}, + {value: 0x0040, lo: 0xae, hi: 0xaf}, + {value: 0x0008, lo: 0xb0, hi: 0xb4}, + {value: 0x0040, lo: 0xb5, hi: 0xbf}, + // Block 0x38, offset 0x1f2 + {value: 0x0000, lo: 0x03}, + {value: 0x0008, lo: 0x80, hi: 0xab}, + {value: 0x0040, lo: 0xac, hi: 0xaf}, + {value: 0x0008, lo: 0xb0, hi: 0xbf}, + // Block 0x39, offset 0x1f6 + {value: 0x0000, lo: 0x06}, + {value: 0x0008, lo: 0x80, hi: 0x89}, + {value: 0x0040, lo: 0x8a, hi: 0x8f}, + {value: 0x0008, lo: 0x90, hi: 0x99}, + {value: 0x0028, lo: 0x9a, hi: 0x9a}, + {value: 0x0040, lo: 0x9b, hi: 0x9d}, + {value: 0x0018, lo: 0x9e, hi: 0xbf}, + // Block 0x3a, offset 0x1fd + {value: 0x0000, lo: 0x07}, + {value: 0x0008, lo: 0x80, hi: 0x96}, + {value: 0x3308, lo: 0x97, hi: 0x98}, + {value: 0x3008, lo: 0x99, hi: 0x9a}, + {value: 0x3308, lo: 0x9b, hi: 0x9b}, + {value: 0x0040, lo: 0x9c, hi: 0x9d}, + {value: 0x0018, lo: 0x9e, hi: 0x9f}, + {value: 0x0008, lo: 0xa0, hi: 0xbf}, + // Block 0x3b, offset 0x205 + {value: 0x0000, lo: 0x0f}, + {value: 0x0008, lo: 0x80, hi: 0x94}, + {value: 0x3008, lo: 0x95, hi: 0x95}, + {value: 0x3308, lo: 0x96, hi: 0x96}, + {value: 0x3008, lo: 0x97, hi: 0x97}, + {value: 0x3308, lo: 0x98, hi: 0x9e}, + {value: 0x0040, lo: 0x9f, hi: 0x9f}, + {value: 0x3b08, lo: 0xa0, hi: 0xa0}, + {value: 0x3008, lo: 0xa1, hi: 0xa1}, + {value: 0x3308, lo: 0xa2, hi: 0xa2}, + {value: 0x3008, lo: 0xa3, hi: 0xa4}, + {value: 0x3308, lo: 0xa5, hi: 0xac}, + {value: 0x3008, lo: 0xad, hi: 0xb2}, + {value: 0x3308, lo: 0xb3, hi: 0xbc}, + {value: 0x0040, lo: 0xbd, hi: 0xbe}, + {value: 0x3308, lo: 0xbf, hi: 0xbf}, + // Block 0x3c, offset 0x215 + {value: 0x0000, lo: 0x0b}, + {value: 0x0008, lo: 0x80, hi: 0x89}, + {value: 0x0040, lo: 0x8a, hi: 0x8f}, + {value: 0x0008, lo: 0x90, hi: 0x99}, + {value: 0x0040, lo: 0x9a, hi: 0x9f}, + {value: 0x0018, lo: 0xa0, hi: 0xa6}, + {value: 0x0008, lo: 0xa7, hi: 0xa7}, + {value: 0x0018, lo: 0xa8, hi: 0xad}, + {value: 0x0040, lo: 0xae, hi: 0xaf}, + {value: 0x3308, lo: 0xb0, hi: 0xbd}, + {value: 0x3318, lo: 0xbe, hi: 0xbe}, + {value: 0x0040, lo: 0xbf, hi: 0xbf}, + // Block 0x3d, offset 0x221 + {value: 0x0000, lo: 0x01}, + {value: 0x0040, lo: 0x80, hi: 0xbf}, + // Block 0x3e, offset 0x223 + {value: 0x0000, lo: 0x09}, + {value: 0x3308, lo: 0x80, hi: 0x83}, + {value: 0x3008, lo: 0x84, hi: 0x84}, + {value: 0x0008, lo: 0x85, hi: 0xb3}, + {value: 0x3308, lo: 0xb4, hi: 0xb4}, + {value: 0x3008, lo: 0xb5, hi: 0xb5}, + {value: 0x3308, lo: 0xb6, hi: 0xba}, + {value: 0x3008, lo: 0xbb, hi: 0xbb}, + {value: 0x3308, lo: 0xbc, hi: 0xbc}, + {value: 0x3008, lo: 0xbd, hi: 0xbf}, + // Block 0x3f, offset 0x22d + {value: 0x0000, lo: 0x0b}, + {value: 0x3008, lo: 0x80, hi: 0x81}, + {value: 0x3308, lo: 0x82, hi: 0x82}, + {value: 0x3008, lo: 0x83, hi: 0x83}, + {value: 0x3808, lo: 0x84, hi: 0x84}, + {value: 0x0008, lo: 0x85, hi: 0x8b}, + {value: 0x0040, lo: 0x8c, hi: 0x8f}, + {value: 0x0008, lo: 0x90, hi: 0x99}, + {value: 0x0018, lo: 0x9a, hi: 0xaa}, + {value: 0x3308, lo: 0xab, hi: 0xb3}, + {value: 0x0018, lo: 0xb4, hi: 0xbc}, + {value: 0x0040, lo: 0xbd, hi: 0xbf}, + // Block 0x40, offset 0x239 + {value: 0x0000, lo: 0x0b}, + {value: 0x3308, lo: 0x80, hi: 0x81}, + {value: 0x3008, lo: 0x82, hi: 0x82}, + {value: 0x0008, lo: 0x83, hi: 0xa0}, + {value: 0x3008, lo: 0xa1, hi: 0xa1}, + {value: 0x3308, lo: 0xa2, hi: 0xa5}, + {value: 0x3008, lo: 0xa6, hi: 0xa7}, + {value: 0x3308, lo: 0xa8, hi: 0xa9}, + {value: 0x3808, lo: 0xaa, hi: 0xaa}, + {value: 0x3b08, lo: 0xab, hi: 0xab}, + {value: 0x3308, lo: 0xac, hi: 0xad}, + {value: 0x0008, lo: 0xae, hi: 0xbf}, + // Block 0x41, offset 0x245 + {value: 0x0000, lo: 0x0b}, + {value: 0x0008, lo: 0x80, hi: 0xa5}, + {value: 0x3308, lo: 0xa6, hi: 0xa6}, + {value: 0x3008, lo: 0xa7, hi: 0xa7}, + {value: 0x3308, lo: 0xa8, hi: 0xa9}, + {value: 0x3008, lo: 0xaa, hi: 0xac}, + {value: 0x3308, lo: 0xad, hi: 0xad}, + {value: 0x3008, lo: 0xae, hi: 0xae}, + {value: 0x3308, lo: 0xaf, hi: 0xb1}, + {value: 0x3808, lo: 0xb2, hi: 0xb3}, + {value: 0x0040, lo: 0xb4, hi: 0xbb}, + {value: 0x0018, lo: 0xbc, hi: 0xbf}, + // Block 0x42, offset 0x251 + {value: 0x0000, lo: 0x07}, + {value: 0x0008, lo: 0x80, hi: 0xa3}, + {value: 0x3008, lo: 0xa4, hi: 0xab}, + {value: 0x3308, lo: 0xac, hi: 0xb3}, + {value: 0x3008, lo: 0xb4, hi: 0xb5}, + {value: 0x3308, lo: 0xb6, hi: 0xb7}, + {value: 0x0040, lo: 0xb8, hi: 0xba}, + {value: 0x0018, lo: 0xbb, hi: 0xbf}, + // Block 0x43, offset 0x259 + {value: 0x0000, lo: 0x04}, + {value: 0x0008, lo: 0x80, hi: 0x89}, + {value: 0x0040, lo: 0x8a, hi: 0x8c}, + {value: 0x0008, lo: 0x8d, hi: 0xbd}, + {value: 0x0018, lo: 0xbe, hi: 0xbf}, + // Block 0x44, offset 0x25e + {value: 0x0000, lo: 0x09}, + {value: 0x0e29, lo: 0x80, hi: 0x80}, + {value: 0x0e41, lo: 0x81, hi: 0x81}, + {value: 0x0e59, lo: 0x82, hi: 0x82}, + {value: 0x0e71, lo: 0x83, hi: 0x83}, + {value: 0x0e89, lo: 0x84, hi: 0x85}, + {value: 0x0ea1, lo: 0x86, hi: 0x86}, + {value: 0x0eb9, lo: 0x87, hi: 0x87}, + {value: 0x057d, lo: 0x88, hi: 0x88}, + {value: 0x0040, lo: 0x89, hi: 0xbf}, + // Block 0x45, offset 0x268 + {value: 0x0000, lo: 0x10}, + {value: 0x0018, lo: 0x80, hi: 0x87}, + {value: 0x0040, lo: 0x88, hi: 0x8f}, + {value: 0x3308, lo: 0x90, hi: 0x92}, + {value: 0x0018, lo: 0x93, hi: 0x93}, + {value: 0x3308, lo: 0x94, hi: 0xa0}, + {value: 0x3008, lo: 0xa1, hi: 0xa1}, + {value: 0x3308, lo: 0xa2, hi: 0xa8}, + {value: 0x0008, lo: 0xa9, hi: 0xac}, + {value: 0x3308, lo: 0xad, hi: 0xad}, + {value: 0x0008, lo: 0xae, hi: 0xb1}, + {value: 0x3008, lo: 0xb2, hi: 0xb3}, + {value: 0x3308, lo: 0xb4, hi: 0xb4}, + {value: 0x0008, lo: 0xb5, hi: 0xb6}, + {value: 0x3008, lo: 0xb7, hi: 0xb7}, + {value: 0x3308, lo: 0xb8, hi: 0xb9}, + {value: 0x0040, lo: 0xba, hi: 0xbf}, + // Block 0x46, offset 0x279 + {value: 0x0000, lo: 0x03}, + {value: 0x3308, lo: 0x80, hi: 0xb9}, + {value: 0x0040, lo: 0xba, hi: 0xba}, + {value: 0x3308, lo: 0xbb, hi: 0xbf}, + // Block 0x47, offset 0x27d + {value: 0x0000, lo: 0x0a}, + {value: 0x0008, lo: 0x80, hi: 0x87}, + {value: 0xe045, lo: 0x88, hi: 0x8f}, + {value: 0x0008, lo: 0x90, hi: 0x95}, + {value: 0x0040, lo: 0x96, hi: 0x97}, + {value: 0xe045, lo: 0x98, hi: 0x9d}, + {value: 0x0040, lo: 0x9e, hi: 0x9f}, + {value: 0x0008, lo: 0xa0, hi: 0xa7}, + {value: 0xe045, lo: 0xa8, hi: 0xaf}, + {value: 0x0008, lo: 0xb0, hi: 0xb7}, + {value: 0xe045, lo: 0xb8, hi: 0xbf}, + // Block 0x48, offset 0x288 + {value: 0x0000, lo: 0x03}, + {value: 0x0040, lo: 0x80, hi: 0x8f}, + {value: 0x3318, lo: 0x90, hi: 0xb0}, + {value: 0x0040, lo: 0xb1, hi: 0xbf}, + // Block 0x49, offset 0x28c + {value: 0x0000, lo: 0x08}, + {value: 0x0018, lo: 0x80, hi: 0x82}, + {value: 0x0040, lo: 0x83, hi: 0x83}, + {value: 0x0008, lo: 0x84, hi: 0x84}, + {value: 0x0018, lo: 0x85, hi: 0x88}, + {value: 0x24c1, lo: 0x89, hi: 0x89}, + {value: 0x0018, lo: 0x8a, hi: 0x8b}, + {value: 0x0040, lo: 0x8c, hi: 0x8f}, + {value: 0x0018, lo: 0x90, hi: 0xbf}, + // Block 0x4a, offset 0x295 + {value: 0x0000, lo: 0x07}, + {value: 0x0018, lo: 0x80, hi: 0xab}, + {value: 0x24f1, lo: 0xac, hi: 0xac}, + {value: 0x2529, lo: 0xad, hi: 0xad}, + {value: 0x0018, lo: 0xae, hi: 0xae}, + {value: 0x2579, lo: 0xaf, hi: 0xaf}, + {value: 0x25b1, lo: 0xb0, hi: 0xb0}, + {value: 0x0018, lo: 0xb1, hi: 0xbf}, + // Block 0x4b, offset 0x29d + {value: 0x0000, lo: 0x05}, + {value: 0x0018, lo: 0x80, hi: 0x9f}, + {value: 0x0080, lo: 0xa0, hi: 0xa0}, + {value: 0x0018, lo: 0xa1, hi: 0xad}, + {value: 0x0080, lo: 0xae, hi: 0xaf}, + {value: 0x0018, lo: 0xb0, hi: 0xbf}, + // Block 0x4c, offset 0x2a3 + {value: 0x0000, lo: 0x04}, + {value: 0x0018, lo: 0x80, hi: 0xa8}, + {value: 0x09c5, lo: 0xa9, hi: 0xa9}, + {value: 0x09e5, lo: 0xaa, hi: 0xaa}, + {value: 0x0018, lo: 0xab, hi: 0xbf}, + // Block 0x4d, offset 0x2a8 + {value: 0x0000, lo: 0x02}, + {value: 0x0018, lo: 0x80, hi: 0xa6}, + {value: 0x0040, lo: 0xa7, hi: 0xbf}, + // Block 0x4e, offset 0x2ab + {value: 0x0000, lo: 0x03}, + {value: 0x0018, lo: 0x80, hi: 0x8b}, + {value: 0x28c1, lo: 0x8c, hi: 0x8c}, + {value: 0x0018, lo: 0x8d, hi: 0xbf}, + // Block 0x4f, offset 0x2af + {value: 0x0000, lo: 0x05}, + {value: 0x0018, lo: 0x80, hi: 0xb3}, + {value: 0x0e66, lo: 0xb4, hi: 0xb4}, + {value: 0x292a, lo: 0xb5, hi: 0xb5}, + {value: 0x0e86, lo: 0xb6, hi: 0xb6}, + {value: 0x0018, lo: 0xb7, hi: 0xbf}, + // Block 0x50, offset 0x2b5 + {value: 0x0000, lo: 0x03}, + {value: 0x0018, lo: 0x80, hi: 0x9b}, + {value: 0x2941, lo: 0x9c, hi: 0x9c}, + {value: 0x0018, lo: 0x9d, hi: 0xbf}, + // Block 0x51, offset 0x2b9 + {value: 0x0000, lo: 0x03}, + {value: 0x0018, lo: 0x80, hi: 0xb3}, + {value: 0x0040, lo: 0xb4, hi: 0xb5}, + {value: 0x0018, lo: 0xb6, hi: 0xbf}, + // Block 0x52, offset 0x2bd + {value: 0x0000, lo: 0x05}, + {value: 0x0018, lo: 0x80, hi: 0x95}, + {value: 0x0040, lo: 0x96, hi: 0x97}, + {value: 0x0018, lo: 0x98, hi: 0xb9}, + {value: 0x0040, lo: 0xba, hi: 0xbc}, + {value: 0x0018, lo: 0xbd, hi: 0xbf}, + // Block 0x53, offset 0x2c3 + {value: 0x0000, lo: 0x06}, + {value: 0x0018, lo: 0x80, hi: 0x88}, + {value: 0x0040, lo: 0x89, hi: 0x89}, + {value: 0x0018, lo: 0x8a, hi: 0x92}, + {value: 0x0040, lo: 0x93, hi: 0xab}, + {value: 0x0018, lo: 0xac, hi: 0xaf}, + {value: 0x0040, lo: 0xb0, hi: 0xbf}, + // Block 0x54, offset 0x2ca + {value: 0x0000, lo: 0x05}, + {value: 0xe185, lo: 0x80, hi: 0x8f}, + {value: 0x03f5, lo: 0x90, hi: 0x9f}, + {value: 0x0ea5, lo: 0xa0, hi: 0xae}, + {value: 0x0040, lo: 0xaf, hi: 0xaf}, + {value: 0x0008, lo: 0xb0, hi: 0xbf}, + // Block 0x55, offset 0x2d0 + {value: 0x0000, lo: 0x07}, + {value: 0x0008, lo: 0x80, hi: 0xa5}, + {value: 0x0040, lo: 0xa6, hi: 0xa6}, + {value: 0x0008, lo: 0xa7, hi: 0xa7}, + {value: 0x0040, lo: 0xa8, hi: 0xac}, + {value: 0x0008, lo: 0xad, hi: 0xad}, + {value: 0x0040, lo: 0xae, hi: 0xaf}, + {value: 0x0008, lo: 0xb0, hi: 0xbf}, + // Block 0x56, offset 0x2d8 + {value: 0x0000, lo: 0x06}, + {value: 0x0008, lo: 0x80, hi: 0xa7}, + {value: 0x0040, lo: 0xa8, hi: 0xae}, + {value: 0xe075, lo: 0xaf, hi: 0xaf}, + {value: 0x0018, lo: 0xb0, hi: 0xb0}, + {value: 0x0040, lo: 0xb1, hi: 0xbe}, + {value: 0x3b08, lo: 0xbf, hi: 0xbf}, + // Block 0x57, offset 0x2df + {value: 0x0000, lo: 0x0a}, + {value: 0x0008, lo: 0x80, hi: 0x96}, + {value: 0x0040, lo: 0x97, hi: 0x9f}, + {value: 0x0008, lo: 0xa0, hi: 0xa6}, + {value: 0x0040, lo: 0xa7, hi: 0xa7}, + {value: 0x0008, lo: 0xa8, hi: 0xae}, + {value: 0x0040, lo: 0xaf, hi: 0xaf}, + {value: 0x0008, lo: 0xb0, hi: 0xb6}, + {value: 0x0040, lo: 0xb7, hi: 0xb7}, + {value: 0x0008, lo: 0xb8, hi: 0xbe}, + {value: 0x0040, lo: 0xbf, hi: 0xbf}, + // Block 0x58, offset 0x2ea + {value: 0x0000, lo: 0x09}, + {value: 0x0008, lo: 0x80, hi: 0x86}, + {value: 0x0040, lo: 0x87, hi: 0x87}, + {value: 0x0008, lo: 0x88, hi: 0x8e}, + {value: 0x0040, lo: 0x8f, hi: 0x8f}, + {value: 0x0008, lo: 0x90, hi: 0x96}, + {value: 0x0040, lo: 0x97, hi: 0x97}, + {value: 0x0008, lo: 0x98, hi: 0x9e}, + {value: 0x0040, lo: 0x9f, hi: 0x9f}, + {value: 0x3308, lo: 0xa0, hi: 0xbf}, + // Block 0x59, offset 0x2f4 + {value: 0x0000, lo: 0x03}, + {value: 0x0018, lo: 0x80, hi: 0xae}, + {value: 0x0008, lo: 0xaf, hi: 0xaf}, + {value: 0x0018, lo: 0xb0, hi: 0xbf}, + // Block 0x5a, offset 0x2f8 + {value: 0x0000, lo: 0x02}, + {value: 0x0018, lo: 0x80, hi: 0x89}, + {value: 0x0040, lo: 0x8a, hi: 0xbf}, + // Block 0x5b, offset 0x2fb + {value: 0x0000, lo: 0x05}, + {value: 0x0018, lo: 0x80, hi: 0x99}, + {value: 0x0040, lo: 0x9a, hi: 0x9a}, + {value: 0x0018, lo: 0x9b, hi: 0x9e}, + {value: 0x0edd, lo: 0x9f, hi: 0x9f}, + {value: 0x0018, lo: 0xa0, hi: 0xbf}, + // Block 0x5c, offset 0x301 + {value: 0x0000, lo: 0x03}, + {value: 0x0018, lo: 0x80, hi: 0xb2}, + {value: 0x0efd, lo: 0xb3, hi: 0xb3}, + {value: 0x0040, lo: 0xb4, hi: 0xbf}, + // Block 0x5d, offset 0x305 + {value: 0x0020, lo: 0x01}, + {value: 0x0f1d, lo: 0x80, hi: 0xbf}, + // Block 0x5e, offset 0x307 + {value: 0x0020, lo: 0x02}, + {value: 0x171d, lo: 0x80, hi: 0x8f}, + {value: 0x18fd, lo: 0x90, hi: 0xbf}, + // Block 0x5f, offset 0x30a + {value: 0x0020, lo: 0x01}, + {value: 0x1efd, lo: 0x80, hi: 0xbf}, + // Block 0x60, offset 0x30c + {value: 0x0000, lo: 0x02}, + {value: 0x0040, lo: 0x80, hi: 0x80}, + {value: 0x0008, lo: 0x81, hi: 0xbf}, + // Block 0x61, offset 0x30f + {value: 0x0000, lo: 0x09}, + {value: 0x0008, lo: 0x80, hi: 0x96}, + {value: 0x0040, lo: 0x97, hi: 0x98}, + {value: 0x3308, lo: 0x99, hi: 0x9a}, + {value: 0x29e2, lo: 0x9b, hi: 0x9b}, + {value: 0x2a0a, lo: 0x9c, hi: 0x9c}, + {value: 0x0008, lo: 0x9d, hi: 0x9e}, + {value: 0x2a31, lo: 0x9f, hi: 0x9f}, + {value: 0x0018, lo: 0xa0, hi: 0xa0}, + {value: 0x0008, lo: 0xa1, hi: 0xbf}, + // Block 0x62, offset 0x319 + {value: 0x0000, lo: 0x02}, + {value: 0x0008, lo: 0x80, hi: 0xbe}, + {value: 0x2a69, lo: 0xbf, hi: 0xbf}, + // Block 0x63, offset 0x31c + {value: 0x0000, lo: 0x0e}, + {value: 0x0040, lo: 0x80, hi: 0x84}, + {value: 0x0008, lo: 0x85, hi: 0xae}, + {value: 0x0040, lo: 0xaf, hi: 0xb0}, + {value: 0x2a1d, lo: 0xb1, hi: 0xb1}, + {value: 0x2a3d, lo: 0xb2, hi: 0xb2}, + {value: 0x2a5d, lo: 0xb3, hi: 0xb3}, + {value: 0x2a7d, lo: 0xb4, hi: 0xb4}, + {value: 0x2a5d, lo: 0xb5, hi: 0xb5}, + {value: 0x2a9d, lo: 0xb6, hi: 0xb6}, + {value: 0x2abd, lo: 0xb7, hi: 0xb7}, + {value: 0x2add, lo: 0xb8, hi: 0xb9}, + {value: 0x2afd, lo: 0xba, hi: 0xbb}, + {value: 0x2b1d, lo: 0xbc, hi: 0xbd}, + {value: 0x2afd, lo: 0xbe, hi: 0xbf}, + // Block 0x64, offset 0x32b + {value: 0x0000, lo: 0x03}, + {value: 0x0018, lo: 0x80, hi: 0xa3}, + {value: 0x0040, lo: 0xa4, hi: 0xaf}, + {value: 0x0008, lo: 0xb0, hi: 0xbf}, + // Block 0x65, offset 0x32f + {value: 0x0030, lo: 0x04}, + {value: 0x2aa2, lo: 0x80, hi: 0x9d}, + {value: 0x305a, lo: 0x9e, hi: 0x9e}, + {value: 0x0040, lo: 0x9f, hi: 0x9f}, + {value: 0x30a2, lo: 0xa0, hi: 0xbf}, + // Block 0x66, offset 0x334 + {value: 0x0000, lo: 0x02}, + {value: 0x0008, lo: 0x80, hi: 0xaa}, + {value: 0x0040, lo: 0xab, hi: 0xbf}, + // Block 0x67, offset 0x337 + {value: 0x0000, lo: 0x03}, + {value: 0x0008, lo: 0x80, hi: 0x8c}, + {value: 0x0040, lo: 0x8d, hi: 0x8f}, + {value: 0x0018, lo: 0x90, hi: 0xbf}, + // Block 0x68, offset 0x33b + {value: 0x0000, lo: 0x04}, + {value: 0x0018, lo: 0x80, hi: 0x86}, + {value: 0x0040, lo: 0x87, hi: 0x8f}, + {value: 0x0008, lo: 0x90, hi: 0xbd}, + {value: 0x0018, lo: 0xbe, hi: 0xbf}, + // Block 0x69, offset 0x340 + {value: 0x0000, lo: 0x04}, + {value: 0x0008, lo: 0x80, hi: 0x8c}, + {value: 0x0018, lo: 0x8d, hi: 0x8f}, + {value: 0x0008, lo: 0x90, hi: 0xab}, + {value: 0x0040, lo: 0xac, hi: 0xbf}, + // Block 0x6a, offset 0x345 + {value: 0x0000, lo: 0x05}, + {value: 0x0008, lo: 0x80, hi: 0xa5}, + {value: 0x0018, lo: 0xa6, hi: 0xaf}, + {value: 0x3308, lo: 0xb0, hi: 0xb1}, + {value: 0x0018, lo: 0xb2, hi: 0xb7}, + {value: 0x0040, lo: 0xb8, hi: 0xbf}, + // Block 0x6b, offset 0x34b + {value: 0x0000, lo: 0x05}, + {value: 0x0040, lo: 0x80, hi: 0xb6}, + {value: 0x0008, lo: 0xb7, hi: 0xb7}, + {value: 0x2009, lo: 0xb8, hi: 0xb8}, + {value: 0x6e89, lo: 0xb9, hi: 0xb9}, + {value: 0x0008, lo: 0xba, hi: 0xbf}, + // Block 0x6c, offset 0x351 + {value: 0x0000, lo: 0x0e}, + {value: 0x0008, lo: 0x80, hi: 0x81}, + {value: 0x3308, lo: 0x82, hi: 0x82}, + {value: 0x0008, lo: 0x83, hi: 0x85}, + {value: 0x3b08, lo: 0x86, hi: 0x86}, + {value: 0x0008, lo: 0x87, hi: 0x8a}, + {value: 0x3308, lo: 0x8b, hi: 0x8b}, + {value: 0x0008, lo: 0x8c, hi: 0xa2}, + {value: 0x3008, lo: 0xa3, hi: 0xa4}, + {value: 0x3308, lo: 0xa5, hi: 0xa6}, + {value: 0x3008, lo: 0xa7, hi: 0xa7}, + {value: 0x0018, lo: 0xa8, hi: 0xab}, + {value: 0x0040, lo: 0xac, hi: 0xaf}, + {value: 0x0018, lo: 0xb0, hi: 0xb9}, + {value: 0x0040, lo: 0xba, hi: 0xbf}, + // Block 0x6d, offset 0x360 + {value: 0x0000, lo: 0x05}, + {value: 0x0208, lo: 0x80, hi: 0xb1}, + {value: 0x0108, lo: 0xb2, hi: 0xb2}, + {value: 0x0008, lo: 0xb3, hi: 0xb3}, + {value: 0x0018, lo: 0xb4, hi: 0xb7}, + {value: 0x0040, lo: 0xb8, hi: 0xbf}, + // Block 0x6e, offset 0x366 + {value: 0x0000, lo: 0x03}, + {value: 0x3008, lo: 0x80, hi: 0x81}, + {value: 0x0008, lo: 0x82, hi: 0xb3}, + {value: 0x3008, lo: 0xb4, hi: 0xbf}, + // Block 0x6f, offset 0x36a + {value: 0x0000, lo: 0x0e}, + {value: 0x3008, lo: 0x80, hi: 0x83}, + {value: 0x3b08, lo: 0x84, hi: 0x84}, + {value: 0x3308, lo: 0x85, hi: 0x85}, + {value: 0x0040, lo: 0x86, hi: 0x8d}, + {value: 0x0018, lo: 0x8e, hi: 0x8f}, + {value: 0x0008, lo: 0x90, hi: 0x99}, + {value: 0x0040, lo: 0x9a, hi: 0x9f}, + {value: 0x3308, lo: 0xa0, hi: 0xb1}, + {value: 0x0008, lo: 0xb2, hi: 0xb7}, + {value: 0x0018, lo: 0xb8, hi: 0xba}, + {value: 0x0008, lo: 0xbb, hi: 0xbb}, + {value: 0x0018, lo: 0xbc, hi: 0xbc}, + {value: 0x0008, lo: 0xbd, hi: 0xbd}, + {value: 0x0040, lo: 0xbe, hi: 0xbf}, + // Block 0x70, offset 0x379 + {value: 0x0000, lo: 0x04}, + {value: 0x0008, lo: 0x80, hi: 0xa5}, + {value: 0x3308, lo: 0xa6, hi: 0xad}, + {value: 0x0018, lo: 0xae, hi: 0xaf}, + {value: 0x0008, lo: 0xb0, hi: 0xbf}, + // Block 0x71, offset 0x37e + {value: 0x0000, lo: 0x07}, + {value: 0x0008, lo: 0x80, hi: 0x86}, + {value: 0x3308, lo: 0x87, hi: 0x91}, + {value: 0x3008, lo: 0x92, hi: 0x92}, + {value: 0x3808, lo: 0x93, hi: 0x93}, + {value: 0x0040, lo: 0x94, hi: 0x9e}, + {value: 0x0018, lo: 0x9f, hi: 0xbc}, + {value: 0x0040, lo: 0xbd, hi: 0xbf}, + // Block 0x72, offset 0x386 + {value: 0x0000, lo: 0x09}, + {value: 0x3308, lo: 0x80, hi: 0x82}, + {value: 0x3008, lo: 0x83, hi: 0x83}, + {value: 0x0008, lo: 0x84, hi: 0xb2}, + {value: 0x3308, lo: 0xb3, hi: 0xb3}, + {value: 0x3008, lo: 0xb4, hi: 0xb5}, + {value: 0x3308, lo: 0xb6, hi: 0xb9}, + {value: 0x3008, lo: 0xba, hi: 0xbb}, + {value: 0x3308, lo: 0xbc, hi: 0xbc}, + {value: 0x3008, lo: 0xbd, hi: 0xbf}, + // Block 0x73, offset 0x390 + {value: 0x0000, lo: 0x0a}, + {value: 0x3808, lo: 0x80, hi: 0x80}, + {value: 0x0018, lo: 0x81, hi: 0x8d}, + {value: 0x0040, lo: 0x8e, hi: 0x8e}, + {value: 0x0008, lo: 0x8f, hi: 0x99}, + {value: 0x0040, lo: 0x9a, hi: 0x9d}, + {value: 0x0018, lo: 0x9e, hi: 0x9f}, + {value: 0x0008, lo: 0xa0, hi: 0xa4}, + {value: 0x3308, lo: 0xa5, hi: 0xa5}, + {value: 0x0008, lo: 0xa6, hi: 0xbe}, + {value: 0x0040, lo: 0xbf, hi: 0xbf}, + // Block 0x74, offset 0x39b + {value: 0x0000, lo: 0x07}, + {value: 0x0008, lo: 0x80, hi: 0xa8}, + {value: 0x3308, lo: 0xa9, hi: 0xae}, + {value: 0x3008, lo: 0xaf, hi: 0xb0}, + {value: 0x3308, lo: 0xb1, hi: 0xb2}, + {value: 0x3008, lo: 0xb3, hi: 0xb4}, + {value: 0x3308, lo: 0xb5, hi: 0xb6}, + {value: 0x0040, lo: 0xb7, hi: 0xbf}, + // Block 0x75, offset 0x3a3 + {value: 0x0000, lo: 0x10}, + {value: 0x0008, lo: 0x80, hi: 0x82}, + {value: 0x3308, lo: 0x83, hi: 0x83}, + {value: 0x0008, lo: 0x84, hi: 0x8b}, + {value: 0x3308, lo: 0x8c, hi: 0x8c}, + {value: 0x3008, lo: 0x8d, hi: 0x8d}, + {value: 0x0040, lo: 0x8e, hi: 0x8f}, + {value: 0x0008, lo: 0x90, hi: 0x99}, + {value: 0x0040, lo: 0x9a, hi: 0x9b}, + {value: 0x0018, lo: 0x9c, hi: 0x9f}, + {value: 0x0008, lo: 0xa0, hi: 0xb6}, + {value: 0x0018, lo: 0xb7, hi: 0xb9}, + {value: 0x0008, lo: 0xba, hi: 0xba}, + {value: 0x3008, lo: 0xbb, hi: 0xbb}, + {value: 0x3308, lo: 0xbc, hi: 0xbc}, + {value: 0x3008, lo: 0xbd, hi: 0xbd}, + {value: 0x0008, lo: 0xbe, hi: 0xbf}, + // Block 0x76, offset 0x3b4 + {value: 0x0000, lo: 0x08}, + {value: 0x0008, lo: 0x80, hi: 0xaf}, + {value: 0x3308, lo: 0xb0, hi: 0xb0}, + {value: 0x0008, lo: 0xb1, hi: 0xb1}, + {value: 0x3308, lo: 0xb2, hi: 0xb4}, + {value: 0x0008, lo: 0xb5, hi: 0xb6}, + {value: 0x3308, lo: 0xb7, hi: 0xb8}, + {value: 0x0008, lo: 0xb9, hi: 0xbd}, + {value: 0x3308, lo: 0xbe, hi: 0xbf}, + // Block 0x77, offset 0x3bd + {value: 0x0000, lo: 0x0f}, + {value: 0x0008, lo: 0x80, hi: 0x80}, + {value: 0x3308, lo: 0x81, hi: 0x81}, + {value: 0x0008, lo: 0x82, hi: 0x82}, + {value: 0x0040, lo: 0x83, hi: 0x9a}, + {value: 0x0008, lo: 0x9b, hi: 0x9d}, + {value: 0x0018, lo: 0x9e, hi: 0x9f}, + {value: 0x0008, lo: 0xa0, hi: 0xaa}, + {value: 0x3008, lo: 0xab, hi: 0xab}, + {value: 0x3308, lo: 0xac, hi: 0xad}, + {value: 0x3008, lo: 0xae, hi: 0xaf}, + {value: 0x0018, lo: 0xb0, hi: 0xb1}, + {value: 0x0008, lo: 0xb2, hi: 0xb4}, + {value: 0x3008, lo: 0xb5, hi: 0xb5}, + {value: 0x3b08, lo: 0xb6, hi: 0xb6}, + {value: 0x0040, lo: 0xb7, hi: 0xbf}, + // Block 0x78, offset 0x3cd + {value: 0x0000, lo: 0x0c}, + {value: 0x0040, lo: 0x80, hi: 0x80}, + {value: 0x0008, lo: 0x81, hi: 0x86}, + {value: 0x0040, lo: 0x87, hi: 0x88}, + {value: 0x0008, lo: 0x89, hi: 0x8e}, + {value: 0x0040, lo: 0x8f, hi: 0x90}, + {value: 0x0008, lo: 0x91, hi: 0x96}, + {value: 0x0040, lo: 0x97, hi: 0x9f}, + {value: 0x0008, lo: 0xa0, hi: 0xa6}, + {value: 0x0040, lo: 0xa7, hi: 0xa7}, + {value: 0x0008, lo: 0xa8, hi: 0xae}, + {value: 0x0040, lo: 0xaf, hi: 0xaf}, + {value: 0x0008, lo: 0xb0, hi: 0xbf}, + // Block 0x79, offset 0x3da + {value: 0x0000, lo: 0x09}, + {value: 0x0008, lo: 0x80, hi: 0x9a}, + {value: 0x0018, lo: 0x9b, hi: 0x9b}, + {value: 0x4465, lo: 0x9c, hi: 0x9c}, + {value: 0x447d, lo: 0x9d, hi: 0x9d}, + {value: 0x2971, lo: 0x9e, hi: 0x9e}, + {value: 0xe06d, lo: 0x9f, hi: 0x9f}, + {value: 0x0008, lo: 0xa0, hi: 0xa5}, + {value: 0x0040, lo: 0xa6, hi: 0xaf}, + {value: 0x4495, lo: 0xb0, hi: 0xbf}, + // Block 0x7a, offset 0x3e4 + {value: 0x0000, lo: 0x04}, + {value: 0x44b5, lo: 0x80, hi: 0x8f}, + {value: 0x44d5, lo: 0x90, hi: 0x9f}, + {value: 0x44f5, lo: 0xa0, hi: 0xaf}, + {value: 0x44d5, lo: 0xb0, hi: 0xbf}, + // Block 0x7b, offset 0x3e9 + {value: 0x0000, lo: 0x0c}, + {value: 0x0008, lo: 0x80, hi: 0xa2}, + {value: 0x3008, lo: 0xa3, hi: 0xa4}, + {value: 0x3308, lo: 0xa5, hi: 0xa5}, + {value: 0x3008, lo: 0xa6, hi: 0xa7}, + {value: 0x3308, lo: 0xa8, hi: 0xa8}, + {value: 0x3008, lo: 0xa9, hi: 0xaa}, + {value: 0x0018, lo: 0xab, hi: 0xab}, + {value: 0x3008, lo: 0xac, hi: 0xac}, + {value: 0x3b08, lo: 0xad, hi: 0xad}, + {value: 0x0040, lo: 0xae, hi: 0xaf}, + {value: 0x0008, lo: 0xb0, hi: 0xb9}, + {value: 0x0040, lo: 0xba, hi: 0xbf}, + // Block 0x7c, offset 0x3f6 + {value: 0x0000, lo: 0x03}, + {value: 0x0008, lo: 0x80, hi: 0xa3}, + {value: 0x0040, lo: 0xa4, hi: 0xaf}, + {value: 0x0018, lo: 0xb0, hi: 0xbf}, + // Block 0x7d, offset 0x3fa + {value: 0x0000, lo: 0x04}, + {value: 0x0018, lo: 0x80, hi: 0x86}, + {value: 0x0040, lo: 0x87, hi: 0x8a}, + {value: 0x0018, lo: 0x8b, hi: 0xbb}, + {value: 0x0040, lo: 0xbc, hi: 0xbf}, + // Block 0x7e, offset 0x3ff + {value: 0x0020, lo: 0x01}, + {value: 0x4515, lo: 0x80, hi: 0xbf}, + // Block 0x7f, offset 0x401 + {value: 0x0020, lo: 0x03}, + {value: 0x4d15, lo: 0x80, hi: 0x94}, + {value: 0x4ad5, lo: 0x95, hi: 0x95}, + {value: 0x4fb5, lo: 0x96, hi: 0xbf}, + // Block 0x80, offset 0x405 + {value: 0x0020, lo: 0x01}, + {value: 0x54f5, lo: 0x80, hi: 0xbf}, + // Block 0x81, offset 0x407 + {value: 0x0020, lo: 0x03}, + {value: 0x5cf5, lo: 0x80, hi: 0x84}, + {value: 0x5655, lo: 0x85, hi: 0x85}, + {value: 0x5d95, lo: 0x86, hi: 0xbf}, + // Block 0x82, offset 0x40b + {value: 0x0020, lo: 0x08}, + {value: 0x6b55, lo: 0x80, hi: 0x8f}, + {value: 0x6d15, lo: 0x90, hi: 0x90}, + {value: 0x6d55, lo: 0x91, hi: 0xab}, + {value: 0x6ea1, lo: 0xac, hi: 0xac}, + {value: 0x70b5, lo: 0xad, hi: 0xad}, + {value: 0x0040, lo: 0xae, hi: 0xae}, + {value: 0x0040, lo: 0xaf, hi: 0xaf}, + {value: 0x70d5, lo: 0xb0, hi: 0xbf}, + // Block 0x83, offset 0x414 + {value: 0x0020, lo: 0x05}, + {value: 0x72d5, lo: 0x80, hi: 0xad}, + {value: 0x6535, lo: 0xae, hi: 0xae}, + {value: 0x7895, lo: 0xaf, hi: 0xb5}, + {value: 0x6f55, lo: 0xb6, hi: 0xb6}, + {value: 0x7975, lo: 0xb7, hi: 0xbf}, + // Block 0x84, offset 0x41a + {value: 0x0028, lo: 0x03}, + {value: 0x7c21, lo: 0x80, hi: 0x82}, + {value: 0x7be1, lo: 0x83, hi: 0x83}, + {value: 0x7c99, lo: 0x84, hi: 0xbf}, + // Block 0x85, offset 0x41e + {value: 0x0038, lo: 0x0f}, + {value: 0x9db1, lo: 0x80, hi: 0x83}, + {value: 0x9e59, lo: 0x84, hi: 0x85}, + {value: 0x9e91, lo: 0x86, hi: 0x87}, + {value: 0x9ec9, lo: 0x88, hi: 0x8f}, + {value: 0x0040, lo: 0x90, hi: 0x90}, + {value: 0x0040, lo: 0x91, hi: 0x91}, + {value: 0xa089, lo: 0x92, hi: 0x97}, + {value: 0xa1a1, lo: 0x98, hi: 0x9c}, + {value: 0xa281, lo: 0x9d, hi: 0xb3}, + {value: 0x9d41, lo: 0xb4, hi: 0xb4}, + {value: 0x9db1, lo: 0xb5, hi: 0xb5}, + {value: 0xa789, lo: 0xb6, hi: 0xbb}, + {value: 0xa869, lo: 0xbc, hi: 0xbc}, + {value: 0xa7f9, lo: 0xbd, hi: 0xbd}, + {value: 0xa8d9, lo: 0xbe, hi: 0xbf}, + // Block 0x86, offset 0x42e + {value: 0x0000, lo: 0x09}, + {value: 0x0008, lo: 0x80, hi: 0x8b}, + {value: 0x0040, lo: 0x8c, hi: 0x8c}, + {value: 0x0008, lo: 0x8d, hi: 0xa6}, + {value: 0x0040, lo: 0xa7, hi: 0xa7}, + {value: 0x0008, lo: 0xa8, hi: 0xba}, + {value: 0x0040, lo: 0xbb, hi: 0xbb}, + {value: 0x0008, lo: 0xbc, hi: 0xbd}, + {value: 0x0040, lo: 0xbe, hi: 0xbe}, + {value: 0x0008, lo: 0xbf, hi: 0xbf}, + // Block 0x87, offset 0x438 + {value: 0x0000, lo: 0x04}, + {value: 0x0008, lo: 0x80, hi: 0x8d}, + {value: 0x0040, lo: 0x8e, hi: 0x8f}, + {value: 0x0008, lo: 0x90, hi: 0x9d}, + {value: 0x0040, lo: 0x9e, hi: 0xbf}, + // Block 0x88, offset 0x43d + {value: 0x0000, lo: 0x02}, + {value: 0x0008, lo: 0x80, hi: 0xba}, + {value: 0x0040, lo: 0xbb, hi: 0xbf}, + // Block 0x89, offset 0x440 + {value: 0x0000, lo: 0x05}, + {value: 0x0018, lo: 0x80, hi: 0x82}, + {value: 0x0040, lo: 0x83, hi: 0x86}, + {value: 0x0018, lo: 0x87, hi: 0xb3}, + {value: 0x0040, lo: 0xb4, hi: 0xb6}, + {value: 0x0018, lo: 0xb7, hi: 0xbf}, + // Block 0x8a, offset 0x446 + {value: 0x0000, lo: 0x06}, + {value: 0x0018, lo: 0x80, hi: 0x8e}, + {value: 0x0040, lo: 0x8f, hi: 0x8f}, + {value: 0x0018, lo: 0x90, hi: 0x9b}, + {value: 0x0040, lo: 0x9c, hi: 0x9f}, + {value: 0x0018, lo: 0xa0, hi: 0xa0}, + {value: 0x0040, lo: 0xa1, hi: 0xbf}, + // Block 0x8b, offset 0x44d + {value: 0x0000, lo: 0x04}, + {value: 0x0040, lo: 0x80, hi: 0x8f}, + {value: 0x0018, lo: 0x90, hi: 0xbc}, + {value: 0x3308, lo: 0xbd, hi: 0xbd}, + {value: 0x0040, lo: 0xbe, hi: 0xbf}, + // Block 0x8c, offset 0x452 + {value: 0x0000, lo: 0x03}, + {value: 0x0008, lo: 0x80, hi: 0x9c}, + {value: 0x0040, lo: 0x9d, hi: 0x9f}, + {value: 0x0008, lo: 0xa0, hi: 0xbf}, + // Block 0x8d, offset 0x456 + {value: 0x0000, lo: 0x05}, + {value: 0x0008, lo: 0x80, hi: 0x90}, + {value: 0x0040, lo: 0x91, hi: 0x9f}, + {value: 0x3308, lo: 0xa0, hi: 0xa0}, + {value: 0x0018, lo: 0xa1, hi: 0xbb}, + {value: 0x0040, lo: 0xbc, hi: 0xbf}, + // Block 0x8e, offset 0x45c + {value: 0x0000, lo: 0x04}, + {value: 0x0008, lo: 0x80, hi: 0x9f}, + {value: 0x0018, lo: 0xa0, hi: 0xa3}, + {value: 0x0040, lo: 0xa4, hi: 0xac}, + {value: 0x0008, lo: 0xad, hi: 0xbf}, + // Block 0x8f, offset 0x461 + {value: 0x0000, lo: 0x08}, + {value: 0x0008, lo: 0x80, hi: 0x80}, + {value: 0x0018, lo: 0x81, hi: 0x81}, + {value: 0x0008, lo: 0x82, hi: 0x89}, + {value: 0x0018, lo: 0x8a, hi: 0x8a}, + {value: 0x0040, lo: 0x8b, hi: 0x8f}, + {value: 0x0008, lo: 0x90, hi: 0xb5}, + {value: 0x3308, lo: 0xb6, hi: 0xba}, + {value: 0x0040, lo: 0xbb, hi: 0xbf}, + // Block 0x90, offset 0x46a + {value: 0x0000, lo: 0x04}, + {value: 0x0008, lo: 0x80, hi: 0x9d}, + {value: 0x0040, lo: 0x9e, hi: 0x9e}, + {value: 0x0018, lo: 0x9f, hi: 0x9f}, + {value: 0x0008, lo: 0xa0, hi: 0xbf}, + // Block 0x91, offset 0x46f + {value: 0x0000, lo: 0x05}, + {value: 0x0008, lo: 0x80, hi: 0x83}, + {value: 0x0040, lo: 0x84, hi: 0x87}, + {value: 0x0008, lo: 0x88, hi: 0x8f}, + {value: 0x0018, lo: 0x90, hi: 0x95}, + {value: 0x0040, lo: 0x96, hi: 0xbf}, + // Block 0x92, offset 0x475 + {value: 0x0000, lo: 0x06}, + {value: 0xe145, lo: 0x80, hi: 0x87}, + {value: 0xe1c5, lo: 0x88, hi: 0x8f}, + {value: 0xe145, lo: 0x90, hi: 0x97}, + {value: 0x8ad5, lo: 0x98, hi: 0x9f}, + {value: 0x8aed, lo: 0xa0, hi: 0xa7}, + {value: 0x0008, lo: 0xa8, hi: 0xbf}, + // Block 0x93, offset 0x47c + {value: 0x0000, lo: 0x06}, + {value: 0x0008, lo: 0x80, hi: 0x9d}, + {value: 0x0040, lo: 0x9e, hi: 0x9f}, + {value: 0x0008, lo: 0xa0, hi: 0xa9}, + {value: 0x0040, lo: 0xaa, hi: 0xaf}, + {value: 0x8aed, lo: 0xb0, hi: 0xb7}, + {value: 0x8ad5, lo: 0xb8, hi: 0xbf}, + // Block 0x94, offset 0x483 + {value: 0x0000, lo: 0x06}, + {value: 0xe145, lo: 0x80, hi: 0x87}, + {value: 0xe1c5, lo: 0x88, hi: 0x8f}, + {value: 0xe145, lo: 0x90, hi: 0x93}, + {value: 0x0040, lo: 0x94, hi: 0x97}, + {value: 0x0008, lo: 0x98, hi: 0xbb}, + {value: 0x0040, lo: 0xbc, hi: 0xbf}, + // Block 0x95, offset 0x48a + {value: 0x0000, lo: 0x03}, + {value: 0x0008, lo: 0x80, hi: 0xa7}, + {value: 0x0040, lo: 0xa8, hi: 0xaf}, + {value: 0x0008, lo: 0xb0, hi: 0xbf}, + // Block 0x96, offset 0x48e + {value: 0x0000, lo: 0x04}, + {value: 0x0008, lo: 0x80, hi: 0xa3}, + {value: 0x0040, lo: 0xa4, hi: 0xae}, + {value: 0x0018, lo: 0xaf, hi: 0xaf}, + {value: 0x0040, lo: 0xb0, hi: 0xbf}, + // Block 0x97, offset 0x493 + {value: 0x0000, lo: 0x02}, + {value: 0x0008, lo: 0x80, hi: 0xb6}, + {value: 0x0040, lo: 0xb7, hi: 0xbf}, + // Block 0x98, offset 0x496 + {value: 0x0000, lo: 0x04}, + {value: 0x0008, lo: 0x80, hi: 0x95}, + {value: 0x0040, lo: 0x96, hi: 0x9f}, + {value: 0x0008, lo: 0xa0, hi: 0xa7}, + {value: 0x0040, lo: 0xa8, hi: 0xbf}, + // Block 0x99, offset 0x49b + {value: 0x0000, lo: 0x0b}, + {value: 0x0808, lo: 0x80, hi: 0x85}, + {value: 0x0040, lo: 0x86, hi: 0x87}, + {value: 0x0808, lo: 0x88, hi: 0x88}, + {value: 0x0040, lo: 0x89, hi: 0x89}, + {value: 0x0808, lo: 0x8a, hi: 0xb5}, + {value: 0x0040, lo: 0xb6, hi: 0xb6}, + {value: 0x0808, lo: 0xb7, hi: 0xb8}, + {value: 0x0040, lo: 0xb9, hi: 0xbb}, + {value: 0x0808, lo: 0xbc, hi: 0xbc}, + {value: 0x0040, lo: 0xbd, hi: 0xbe}, + {value: 0x0808, lo: 0xbf, hi: 0xbf}, + // Block 0x9a, offset 0x4a7 + {value: 0x0000, lo: 0x05}, + {value: 0x0808, lo: 0x80, hi: 0x95}, + {value: 0x0040, lo: 0x96, hi: 0x96}, + {value: 0x0818, lo: 0x97, hi: 0x9f}, + {value: 0x0808, lo: 0xa0, hi: 0xb6}, + {value: 0x0818, lo: 0xb7, hi: 0xbf}, + // Block 0x9b, offset 0x4ad + {value: 0x0000, lo: 0x04}, + {value: 0x0808, lo: 0x80, hi: 0x9e}, + {value: 0x0040, lo: 0x9f, hi: 0xa6}, + {value: 0x0818, lo: 0xa7, hi: 0xaf}, + {value: 0x0040, lo: 0xb0, hi: 0xbf}, + // Block 0x9c, offset 0x4b2 + {value: 0x0000, lo: 0x06}, + {value: 0x0040, lo: 0x80, hi: 0x9f}, + {value: 0x0808, lo: 0xa0, hi: 0xb2}, + {value: 0x0040, lo: 0xb3, hi: 0xb3}, + {value: 0x0808, lo: 0xb4, hi: 0xb5}, + {value: 0x0040, lo: 0xb6, hi: 0xba}, + {value: 0x0818, lo: 0xbb, hi: 0xbf}, + // Block 0x9d, offset 0x4b9 + {value: 0x0000, lo: 0x07}, + {value: 0x0808, lo: 0x80, hi: 0x95}, + {value: 0x0818, lo: 0x96, hi: 0x9b}, + {value: 0x0040, lo: 0x9c, hi: 0x9e}, + {value: 0x0018, lo: 0x9f, hi: 0x9f}, + {value: 0x0808, lo: 0xa0, hi: 0xb9}, + {value: 0x0040, lo: 0xba, hi: 0xbe}, + {value: 0x0818, lo: 0xbf, hi: 0xbf}, + // Block 0x9e, offset 0x4c1 + {value: 0x0000, lo: 0x04}, + {value: 0x0808, lo: 0x80, hi: 0xb7}, + {value: 0x0040, lo: 0xb8, hi: 0xbb}, + {value: 0x0818, lo: 0xbc, hi: 0xbd}, + {value: 0x0808, lo: 0xbe, hi: 0xbf}, + // Block 0x9f, offset 0x4c6 + {value: 0x0000, lo: 0x03}, + {value: 0x0818, lo: 0x80, hi: 0x8f}, + {value: 0x0040, lo: 0x90, hi: 0x91}, + {value: 0x0818, lo: 0x92, hi: 0xbf}, + // Block 0xa0, offset 0x4ca + {value: 0x0000, lo: 0x0f}, + {value: 0x0808, lo: 0x80, hi: 0x80}, + {value: 0x3308, lo: 0x81, hi: 0x83}, + {value: 0x0040, lo: 0x84, hi: 0x84}, + {value: 0x3308, lo: 0x85, hi: 0x86}, + {value: 0x0040, lo: 0x87, hi: 0x8b}, + {value: 0x3308, lo: 0x8c, hi: 0x8f}, + {value: 0x0808, lo: 0x90, hi: 0x93}, + {value: 0x0040, lo: 0x94, hi: 0x94}, + {value: 0x0808, lo: 0x95, hi: 0x97}, + {value: 0x0040, lo: 0x98, hi: 0x98}, + {value: 0x0808, lo: 0x99, hi: 0xb3}, + {value: 0x0040, lo: 0xb4, hi: 0xb7}, + {value: 0x3308, lo: 0xb8, hi: 0xba}, + {value: 0x0040, lo: 0xbb, hi: 0xbe}, + {value: 0x3b08, lo: 0xbf, hi: 0xbf}, + // Block 0xa1, offset 0x4da + {value: 0x0000, lo: 0x06}, + {value: 0x0818, lo: 0x80, hi: 0x87}, + {value: 0x0040, lo: 0x88, hi: 0x8f}, + {value: 0x0818, lo: 0x90, hi: 0x98}, + {value: 0x0040, lo: 0x99, hi: 0x9f}, + {value: 0x0808, lo: 0xa0, hi: 0xbc}, + {value: 0x0818, lo: 0xbd, hi: 0xbf}, + // Block 0xa2, offset 0x4e1 + {value: 0x0000, lo: 0x03}, + {value: 0x0808, lo: 0x80, hi: 0x9c}, + {value: 0x0818, lo: 0x9d, hi: 0x9f}, + {value: 0x0040, lo: 0xa0, hi: 0xbf}, + // Block 0xa3, offset 0x4e5 + {value: 0x0000, lo: 0x03}, + {value: 0x0808, lo: 0x80, hi: 0xb5}, + {value: 0x0040, lo: 0xb6, hi: 0xb8}, + {value: 0x0018, lo: 0xb9, hi: 0xbf}, + // Block 0xa4, offset 0x4e9 + {value: 0x0000, lo: 0x06}, + {value: 0x0808, lo: 0x80, hi: 0x95}, + {value: 0x0040, lo: 0x96, hi: 0x97}, + {value: 0x0818, lo: 0x98, hi: 0x9f}, + {value: 0x0808, lo: 0xa0, hi: 0xb2}, + {value: 0x0040, lo: 0xb3, hi: 0xb7}, + {value: 0x0818, lo: 0xb8, hi: 0xbf}, + // Block 0xa5, offset 0x4f0 + {value: 0x0000, lo: 0x01}, + {value: 0x0808, lo: 0x80, hi: 0xbf}, + // Block 0xa6, offset 0x4f2 + {value: 0x0000, lo: 0x02}, + {value: 0x0808, lo: 0x80, hi: 0x88}, + {value: 0x0040, lo: 0x89, hi: 0xbf}, + // Block 0xa7, offset 0x4f5 + {value: 0x0000, lo: 0x02}, + {value: 0x03dd, lo: 0x80, hi: 0xb2}, + {value: 0x0040, lo: 0xb3, hi: 0xbf}, + // Block 0xa8, offset 0x4f8 + {value: 0x0000, lo: 0x03}, + {value: 0x0808, lo: 0x80, hi: 0xb2}, + {value: 0x0040, lo: 0xb3, hi: 0xb9}, + {value: 0x0818, lo: 0xba, hi: 0xbf}, + // Block 0xa9, offset 0x4fc + {value: 0x0000, lo: 0x03}, + {value: 0x0040, lo: 0x80, hi: 0x9f}, + {value: 0x0818, lo: 0xa0, hi: 0xbe}, + {value: 0x0040, lo: 0xbf, hi: 0xbf}, + // Block 0xaa, offset 0x500 + {value: 0x0000, lo: 0x05}, + {value: 0x3008, lo: 0x80, hi: 0x80}, + {value: 0x3308, lo: 0x81, hi: 0x81}, + {value: 0x3008, lo: 0x82, hi: 0x82}, + {value: 0x0008, lo: 0x83, hi: 0xb7}, + {value: 0x3308, lo: 0xb8, hi: 0xbf}, + // Block 0xab, offset 0x506 + {value: 0x0000, lo: 0x08}, + {value: 0x3308, lo: 0x80, hi: 0x85}, + {value: 0x3b08, lo: 0x86, hi: 0x86}, + {value: 0x0018, lo: 0x87, hi: 0x8d}, + {value: 0x0040, lo: 0x8e, hi: 0x91}, + {value: 0x0018, lo: 0x92, hi: 0xa5}, + {value: 0x0008, lo: 0xa6, hi: 0xaf}, + {value: 0x0040, lo: 0xb0, hi: 0xbe}, + {value: 0x3b08, lo: 0xbf, hi: 0xbf}, + // Block 0xac, offset 0x50f + {value: 0x0000, lo: 0x0b}, + {value: 0x3308, lo: 0x80, hi: 0x81}, + {value: 0x3008, lo: 0x82, hi: 0x82}, + {value: 0x0008, lo: 0x83, hi: 0xaf}, + {value: 0x3008, lo: 0xb0, hi: 0xb2}, + {value: 0x3308, lo: 0xb3, hi: 0xb6}, + {value: 0x3008, lo: 0xb7, hi: 0xb8}, + {value: 0x3b08, lo: 0xb9, hi: 0xb9}, + {value: 0x3308, lo: 0xba, hi: 0xba}, + {value: 0x0018, lo: 0xbb, hi: 0xbc}, + {value: 0x0340, lo: 0xbd, hi: 0xbd}, + {value: 0x0018, lo: 0xbe, hi: 0xbf}, + // Block 0xad, offset 0x51b + {value: 0x0000, lo: 0x06}, + {value: 0x0018, lo: 0x80, hi: 0x81}, + {value: 0x0040, lo: 0x82, hi: 0x8f}, + {value: 0x0008, lo: 0x90, hi: 0xa8}, + {value: 0x0040, lo: 0xa9, hi: 0xaf}, + {value: 0x0008, lo: 0xb0, hi: 0xb9}, + {value: 0x0040, lo: 0xba, hi: 0xbf}, + // Block 0xae, offset 0x522 + {value: 0x0000, lo: 0x08}, + {value: 0x3308, lo: 0x80, hi: 0x82}, + {value: 0x0008, lo: 0x83, hi: 0xa6}, + {value: 0x3308, lo: 0xa7, hi: 0xab}, + {value: 0x3008, lo: 0xac, hi: 0xac}, + {value: 0x3308, lo: 0xad, hi: 0xb2}, + {value: 0x3b08, lo: 0xb3, hi: 0xb4}, + {value: 0x0040, lo: 0xb5, hi: 0xb5}, + {value: 0x0008, lo: 0xb6, hi: 0xbf}, + // Block 0xaf, offset 0x52b + {value: 0x0000, lo: 0x07}, + {value: 0x0018, lo: 0x80, hi: 0x83}, + {value: 0x0040, lo: 0x84, hi: 0x8f}, + {value: 0x0008, lo: 0x90, hi: 0xb2}, + {value: 0x3308, lo: 0xb3, hi: 0xb3}, + {value: 0x0018, lo: 0xb4, hi: 0xb5}, + {value: 0x0008, lo: 0xb6, hi: 0xb6}, + {value: 0x0040, lo: 0xb7, hi: 0xbf}, + // Block 0xb0, offset 0x533 + {value: 0x0000, lo: 0x06}, + {value: 0x3308, lo: 0x80, hi: 0x81}, + {value: 0x3008, lo: 0x82, hi: 0x82}, + {value: 0x0008, lo: 0x83, hi: 0xb2}, + {value: 0x3008, lo: 0xb3, hi: 0xb5}, + {value: 0x3308, lo: 0xb6, hi: 0xbe}, + {value: 0x3008, lo: 0xbf, hi: 0xbf}, + // Block 0xb1, offset 0x53a + {value: 0x0000, lo: 0x0d}, + {value: 0x3808, lo: 0x80, hi: 0x80}, + {value: 0x0008, lo: 0x81, hi: 0x84}, + {value: 0x0018, lo: 0x85, hi: 0x89}, + {value: 0x3308, lo: 0x8a, hi: 0x8c}, + {value: 0x0018, lo: 0x8d, hi: 0x8d}, + {value: 0x0040, lo: 0x8e, hi: 0x8f}, + {value: 0x0008, lo: 0x90, hi: 0x9a}, + {value: 0x0018, lo: 0x9b, hi: 0x9b}, + {value: 0x0008, lo: 0x9c, hi: 0x9c}, + {value: 0x0018, lo: 0x9d, hi: 0x9f}, + {value: 0x0040, lo: 0xa0, hi: 0xa0}, + {value: 0x0018, lo: 0xa1, hi: 0xb4}, + {value: 0x0040, lo: 0xb5, hi: 0xbf}, + // Block 0xb2, offset 0x548 + {value: 0x0000, lo: 0x0c}, + {value: 0x0008, lo: 0x80, hi: 0x91}, + {value: 0x0040, lo: 0x92, hi: 0x92}, + {value: 0x0008, lo: 0x93, hi: 0xab}, + {value: 0x3008, lo: 0xac, hi: 0xae}, + {value: 0x3308, lo: 0xaf, hi: 0xb1}, + {value: 0x3008, lo: 0xb2, hi: 0xb3}, + {value: 0x3308, lo: 0xb4, hi: 0xb4}, + {value: 0x3808, lo: 0xb5, hi: 0xb5}, + {value: 0x3308, lo: 0xb6, hi: 0xb7}, + {value: 0x0018, lo: 0xb8, hi: 0xbd}, + {value: 0x3308, lo: 0xbe, hi: 0xbe}, + {value: 0x0040, lo: 0xbf, hi: 0xbf}, + // Block 0xb3, offset 0x555 + {value: 0x0000, lo: 0x0c}, + {value: 0x0008, lo: 0x80, hi: 0x86}, + {value: 0x0040, lo: 0x87, hi: 0x87}, + {value: 0x0008, lo: 0x88, hi: 0x88}, + {value: 0x0040, lo: 0x89, hi: 0x89}, + {value: 0x0008, lo: 0x8a, hi: 0x8d}, + {value: 0x0040, lo: 0x8e, hi: 0x8e}, + {value: 0x0008, lo: 0x8f, hi: 0x9d}, + {value: 0x0040, lo: 0x9e, hi: 0x9e}, + {value: 0x0008, lo: 0x9f, hi: 0xa8}, + {value: 0x0018, lo: 0xa9, hi: 0xa9}, + {value: 0x0040, lo: 0xaa, hi: 0xaf}, + {value: 0x0008, lo: 0xb0, hi: 0xbf}, + // Block 0xb4, offset 0x562 + {value: 0x0000, lo: 0x08}, + {value: 0x0008, lo: 0x80, hi: 0x9e}, + {value: 0x3308, lo: 0x9f, hi: 0x9f}, + {value: 0x3008, lo: 0xa0, hi: 0xa2}, + {value: 0x3308, lo: 0xa3, hi: 0xa9}, + {value: 0x3b08, lo: 0xaa, hi: 0xaa}, + {value: 0x0040, lo: 0xab, hi: 0xaf}, + {value: 0x0008, lo: 0xb0, hi: 0xb9}, + {value: 0x0040, lo: 0xba, hi: 0xbf}, + // Block 0xb5, offset 0x56b + {value: 0x0000, lo: 0x03}, + {value: 0x0008, lo: 0x80, hi: 0xb4}, + {value: 0x3008, lo: 0xb5, hi: 0xb7}, + {value: 0x3308, lo: 0xb8, hi: 0xbf}, + // Block 0xb6, offset 0x56f + {value: 0x0000, lo: 0x0d}, + {value: 0x3008, lo: 0x80, hi: 0x81}, + {value: 0x3b08, lo: 0x82, hi: 0x82}, + {value: 0x3308, lo: 0x83, hi: 0x84}, + {value: 0x3008, lo: 0x85, hi: 0x85}, + {value: 0x3308, lo: 0x86, hi: 0x86}, + {value: 0x0008, lo: 0x87, hi: 0x8a}, + {value: 0x0018, lo: 0x8b, hi: 0x8f}, + {value: 0x0008, lo: 0x90, hi: 0x99}, + {value: 0x0040, lo: 0x9a, hi: 0x9a}, + {value: 0x0018, lo: 0x9b, hi: 0x9b}, + {value: 0x0040, lo: 0x9c, hi: 0x9c}, + {value: 0x0018, lo: 0x9d, hi: 0x9d}, + {value: 0x0040, lo: 0x9e, hi: 0xbf}, + // Block 0xb7, offset 0x57d + {value: 0x0000, lo: 0x07}, + {value: 0x0008, lo: 0x80, hi: 0xaf}, + {value: 0x3008, lo: 0xb0, hi: 0xb2}, + {value: 0x3308, lo: 0xb3, hi: 0xb8}, + {value: 0x3008, lo: 0xb9, hi: 0xb9}, + {value: 0x3308, lo: 0xba, hi: 0xba}, + {value: 0x3008, lo: 0xbb, hi: 0xbe}, + {value: 0x3308, lo: 0xbf, hi: 0xbf}, + // Block 0xb8, offset 0x585 + {value: 0x0000, lo: 0x0a}, + {value: 0x3308, lo: 0x80, hi: 0x80}, + {value: 0x3008, lo: 0x81, hi: 0x81}, + {value: 0x3b08, lo: 0x82, hi: 0x82}, + {value: 0x3308, lo: 0x83, hi: 0x83}, + {value: 0x0008, lo: 0x84, hi: 0x85}, + {value: 0x0018, lo: 0x86, hi: 0x86}, + {value: 0x0008, lo: 0x87, hi: 0x87}, + {value: 0x0040, lo: 0x88, hi: 0x8f}, + {value: 0x0008, lo: 0x90, hi: 0x99}, + {value: 0x0040, lo: 0x9a, hi: 0xbf}, + // Block 0xb9, offset 0x590 + {value: 0x0000, lo: 0x08}, + {value: 0x0008, lo: 0x80, hi: 0xae}, + {value: 0x3008, lo: 0xaf, hi: 0xb1}, + {value: 0x3308, lo: 0xb2, hi: 0xb5}, + {value: 0x0040, lo: 0xb6, hi: 0xb7}, + {value: 0x3008, lo: 0xb8, hi: 0xbb}, + {value: 0x3308, lo: 0xbc, hi: 0xbd}, + {value: 0x3008, lo: 0xbe, hi: 0xbe}, + {value: 0x3b08, lo: 0xbf, hi: 0xbf}, + // Block 0xba, offset 0x599 + {value: 0x0000, lo: 0x05}, + {value: 0x3308, lo: 0x80, hi: 0x80}, + {value: 0x0018, lo: 0x81, hi: 0x97}, + {value: 0x0008, lo: 0x98, hi: 0x9b}, + {value: 0x3308, lo: 0x9c, hi: 0x9d}, + {value: 0x0040, lo: 0x9e, hi: 0xbf}, + // Block 0xbb, offset 0x59f + {value: 0x0000, lo: 0x07}, + {value: 0x0008, lo: 0x80, hi: 0xaf}, + {value: 0x3008, lo: 0xb0, hi: 0xb2}, + {value: 0x3308, lo: 0xb3, hi: 0xba}, + {value: 0x3008, lo: 0xbb, hi: 0xbc}, + {value: 0x3308, lo: 0xbd, hi: 0xbd}, + {value: 0x3008, lo: 0xbe, hi: 0xbe}, + {value: 0x3b08, lo: 0xbf, hi: 0xbf}, + // Block 0xbc, offset 0x5a7 + {value: 0x0000, lo: 0x08}, + {value: 0x3308, lo: 0x80, hi: 0x80}, + {value: 0x0018, lo: 0x81, hi: 0x83}, + {value: 0x0008, lo: 0x84, hi: 0x84}, + {value: 0x0040, lo: 0x85, hi: 0x8f}, + {value: 0x0008, lo: 0x90, hi: 0x99}, + {value: 0x0040, lo: 0x9a, hi: 0x9f}, + {value: 0x0018, lo: 0xa0, hi: 0xac}, + {value: 0x0040, lo: 0xad, hi: 0xbf}, + // Block 0xbd, offset 0x5b0 + {value: 0x0000, lo: 0x09}, + {value: 0x0008, lo: 0x80, hi: 0xaa}, + {value: 0x3308, lo: 0xab, hi: 0xab}, + {value: 0x3008, lo: 0xac, hi: 0xac}, + {value: 0x3308, lo: 0xad, hi: 0xad}, + {value: 0x3008, lo: 0xae, hi: 0xaf}, + {value: 0x3308, lo: 0xb0, hi: 0xb5}, + {value: 0x3808, lo: 0xb6, hi: 0xb6}, + {value: 0x3308, lo: 0xb7, hi: 0xb7}, + {value: 0x0040, lo: 0xb8, hi: 0xbf}, + // Block 0xbe, offset 0x5ba + {value: 0x0000, lo: 0x02}, + {value: 0x0008, lo: 0x80, hi: 0x89}, + {value: 0x0040, lo: 0x8a, hi: 0xbf}, + // Block 0xbf, offset 0x5bd + {value: 0x0000, lo: 0x0b}, + {value: 0x0008, lo: 0x80, hi: 0x99}, + {value: 0x0040, lo: 0x9a, hi: 0x9c}, + {value: 0x3308, lo: 0x9d, hi: 0x9f}, + {value: 0x3008, lo: 0xa0, hi: 0xa1}, + {value: 0x3308, lo: 0xa2, hi: 0xa5}, + {value: 0x3008, lo: 0xa6, hi: 0xa6}, + {value: 0x3308, lo: 0xa7, hi: 0xaa}, + {value: 0x3b08, lo: 0xab, hi: 0xab}, + {value: 0x0040, lo: 0xac, hi: 0xaf}, + {value: 0x0008, lo: 0xb0, hi: 0xb9}, + {value: 0x0018, lo: 0xba, hi: 0xbf}, + // Block 0xc0, offset 0x5c9 + {value: 0x0000, lo: 0x02}, + {value: 0x0040, lo: 0x80, hi: 0x9f}, + {value: 0x049d, lo: 0xa0, hi: 0xbf}, + // Block 0xc1, offset 0x5cc + {value: 0x0000, lo: 0x04}, + {value: 0x0008, lo: 0x80, hi: 0xa9}, + {value: 0x0018, lo: 0xaa, hi: 0xb2}, + {value: 0x0040, lo: 0xb3, hi: 0xbe}, + {value: 0x0008, lo: 0xbf, hi: 0xbf}, + // Block 0xc2, offset 0x5d1 + {value: 0x0000, lo: 0x0c}, + {value: 0x0008, lo: 0x80, hi: 0x80}, + {value: 0x3308, lo: 0x81, hi: 0x86}, + {value: 0x3008, lo: 0x87, hi: 0x88}, + {value: 0x3308, lo: 0x89, hi: 0x8a}, + {value: 0x0008, lo: 0x8b, hi: 0xb2}, + {value: 0x3308, lo: 0xb3, hi: 0xb3}, + {value: 0x3b08, lo: 0xb4, hi: 0xb4}, + {value: 0x3308, lo: 0xb5, hi: 0xb8}, + {value: 0x3008, lo: 0xb9, hi: 0xb9}, + {value: 0x0008, lo: 0xba, hi: 0xba}, + {value: 0x3308, lo: 0xbb, hi: 0xbe}, + {value: 0x0018, lo: 0xbf, hi: 0xbf}, + // Block 0xc3, offset 0x5de + {value: 0x0000, lo: 0x08}, + {value: 0x0018, lo: 0x80, hi: 0x86}, + {value: 0x3b08, lo: 0x87, hi: 0x87}, + {value: 0x0040, lo: 0x88, hi: 0x8f}, + {value: 0x0008, lo: 0x90, hi: 0x90}, + {value: 0x3308, lo: 0x91, hi: 0x96}, + {value: 0x3008, lo: 0x97, hi: 0x98}, + {value: 0x3308, lo: 0x99, hi: 0x9b}, + {value: 0x0008, lo: 0x9c, hi: 0xbf}, + // Block 0xc4, offset 0x5e7 + {value: 0x0000, lo: 0x0b}, + {value: 0x0008, lo: 0x80, hi: 0x83}, + {value: 0x0040, lo: 0x84, hi: 0x85}, + {value: 0x0008, lo: 0x86, hi: 0x89}, + {value: 0x3308, lo: 0x8a, hi: 0x96}, + {value: 0x3008, lo: 0x97, hi: 0x97}, + {value: 0x3308, lo: 0x98, hi: 0x98}, + {value: 0x3b08, lo: 0x99, hi: 0x99}, + {value: 0x0018, lo: 0x9a, hi: 0x9c}, + {value: 0x0040, lo: 0x9d, hi: 0x9d}, + {value: 0x0018, lo: 0x9e, hi: 0xa2}, + {value: 0x0040, lo: 0xa3, hi: 0xbf}, + // Block 0xc5, offset 0x5f3 + {value: 0x0000, lo: 0x02}, + {value: 0x0008, lo: 0x80, hi: 0xb8}, + {value: 0x0040, lo: 0xb9, hi: 0xbf}, + // Block 0xc6, offset 0x5f6 + {value: 0x0000, lo: 0x09}, + {value: 0x0008, lo: 0x80, hi: 0x88}, + {value: 0x0040, lo: 0x89, hi: 0x89}, + {value: 0x0008, lo: 0x8a, hi: 0xae}, + {value: 0x3008, lo: 0xaf, hi: 0xaf}, + {value: 0x3308, lo: 0xb0, hi: 0xb6}, + {value: 0x0040, lo: 0xb7, hi: 0xb7}, + {value: 0x3308, lo: 0xb8, hi: 0xbd}, + {value: 0x3008, lo: 0xbe, hi: 0xbe}, + {value: 0x3b08, lo: 0xbf, hi: 0xbf}, + // Block 0xc7, offset 0x600 + {value: 0x0000, lo: 0x08}, + {value: 0x0008, lo: 0x80, hi: 0x80}, + {value: 0x0018, lo: 0x81, hi: 0x85}, + {value: 0x0040, lo: 0x86, hi: 0x8f}, + {value: 0x0008, lo: 0x90, hi: 0x99}, + {value: 0x0018, lo: 0x9a, hi: 0xac}, + {value: 0x0040, lo: 0xad, hi: 0xaf}, + {value: 0x0018, lo: 0xb0, hi: 0xb1}, + {value: 0x0008, lo: 0xb2, hi: 0xbf}, + // Block 0xc8, offset 0x609 + {value: 0x0000, lo: 0x0b}, + {value: 0x0008, lo: 0x80, hi: 0x8f}, + {value: 0x0040, lo: 0x90, hi: 0x91}, + {value: 0x3308, lo: 0x92, hi: 0xa7}, + {value: 0x0040, lo: 0xa8, hi: 0xa8}, + {value: 0x3008, lo: 0xa9, hi: 0xa9}, + {value: 0x3308, lo: 0xaa, hi: 0xb0}, + {value: 0x3008, lo: 0xb1, hi: 0xb1}, + {value: 0x3308, lo: 0xb2, hi: 0xb3}, + {value: 0x3008, lo: 0xb4, hi: 0xb4}, + {value: 0x3308, lo: 0xb5, hi: 0xb6}, + {value: 0x0040, lo: 0xb7, hi: 0xbf}, + // Block 0xc9, offset 0x615 + {value: 0x0000, lo: 0x0c}, + {value: 0x0008, lo: 0x80, hi: 0x86}, + {value: 0x0040, lo: 0x87, hi: 0x87}, + {value: 0x0008, lo: 0x88, hi: 0x89}, + {value: 0x0040, lo: 0x8a, hi: 0x8a}, + {value: 0x0008, lo: 0x8b, hi: 0xb0}, + {value: 0x3308, lo: 0xb1, hi: 0xb6}, + {value: 0x0040, lo: 0xb7, hi: 0xb9}, + {value: 0x3308, lo: 0xba, hi: 0xba}, + {value: 0x0040, lo: 0xbb, hi: 0xbb}, + {value: 0x3308, lo: 0xbc, hi: 0xbd}, + {value: 0x0040, lo: 0xbe, hi: 0xbe}, + {value: 0x3308, lo: 0xbf, hi: 0xbf}, + // Block 0xca, offset 0x622 + {value: 0x0000, lo: 0x07}, + {value: 0x3308, lo: 0x80, hi: 0x83}, + {value: 0x3b08, lo: 0x84, hi: 0x85}, + {value: 0x0008, lo: 0x86, hi: 0x86}, + {value: 0x3308, lo: 0x87, hi: 0x87}, + {value: 0x0040, lo: 0x88, hi: 0x8f}, + {value: 0x0008, lo: 0x90, hi: 0x99}, + {value: 0x0040, lo: 0x9a, hi: 0xbf}, + // Block 0xcb, offset 0x62a + {value: 0x0000, lo: 0x02}, + {value: 0x0008, lo: 0x80, hi: 0x99}, + {value: 0x0040, lo: 0x9a, hi: 0xbf}, + // Block 0xcc, offset 0x62d + {value: 0x0000, lo: 0x04}, + {value: 0x0018, lo: 0x80, hi: 0xae}, + {value: 0x0040, lo: 0xaf, hi: 0xaf}, + {value: 0x0018, lo: 0xb0, hi: 0xb4}, + {value: 0x0040, lo: 0xb5, hi: 0xbf}, + // Block 0xcd, offset 0x632 + {value: 0x0000, lo: 0x02}, + {value: 0x0008, lo: 0x80, hi: 0x83}, + {value: 0x0040, lo: 0x84, hi: 0xbf}, + // Block 0xce, offset 0x635 + {value: 0x0000, lo: 0x02}, + {value: 0x0008, lo: 0x80, hi: 0xae}, + {value: 0x0040, lo: 0xaf, hi: 0xbf}, + // Block 0xcf, offset 0x638 + {value: 0x0000, lo: 0x02}, + {value: 0x0008, lo: 0x80, hi: 0x86}, + {value: 0x0040, lo: 0x87, hi: 0xbf}, + // Block 0xd0, offset 0x63b + {value: 0x0000, lo: 0x06}, + {value: 0x0008, lo: 0x80, hi: 0x9e}, + {value: 0x0040, lo: 0x9f, hi: 0x9f}, + {value: 0x0008, lo: 0xa0, hi: 0xa9}, + {value: 0x0040, lo: 0xaa, hi: 0xad}, + {value: 0x0018, lo: 0xae, hi: 0xaf}, + {value: 0x0040, lo: 0xb0, hi: 0xbf}, + // Block 0xd1, offset 0x642 + {value: 0x0000, lo: 0x06}, + {value: 0x0040, lo: 0x80, hi: 0x8f}, + {value: 0x0008, lo: 0x90, hi: 0xad}, + {value: 0x0040, lo: 0xae, hi: 0xaf}, + {value: 0x3308, lo: 0xb0, hi: 0xb4}, + {value: 0x0018, lo: 0xb5, hi: 0xb5}, + {value: 0x0040, lo: 0xb6, hi: 0xbf}, + // Block 0xd2, offset 0x649 + {value: 0x0000, lo: 0x03}, + {value: 0x0008, lo: 0x80, hi: 0xaf}, + {value: 0x3308, lo: 0xb0, hi: 0xb6}, + {value: 0x0018, lo: 0xb7, hi: 0xbf}, + // Block 0xd3, offset 0x64d + {value: 0x0000, lo: 0x0a}, + {value: 0x0008, lo: 0x80, hi: 0x83}, + {value: 0x0018, lo: 0x84, hi: 0x85}, + {value: 0x0040, lo: 0x86, hi: 0x8f}, + {value: 0x0008, lo: 0x90, hi: 0x99}, + {value: 0x0040, lo: 0x9a, hi: 0x9a}, + {value: 0x0018, lo: 0x9b, hi: 0xa1}, + {value: 0x0040, lo: 0xa2, hi: 0xa2}, + {value: 0x0008, lo: 0xa3, hi: 0xb7}, + {value: 0x0040, lo: 0xb8, hi: 0xbc}, + {value: 0x0008, lo: 0xbd, hi: 0xbf}, + // Block 0xd4, offset 0x658 + {value: 0x0000, lo: 0x02}, + {value: 0x0008, lo: 0x80, hi: 0x8f}, + {value: 0x0040, lo: 0x90, hi: 0xbf}, + // Block 0xd5, offset 0x65b + {value: 0x0000, lo: 0x05}, + {value: 0x0008, lo: 0x80, hi: 0x84}, + {value: 0x0040, lo: 0x85, hi: 0x8f}, + {value: 0x0008, lo: 0x90, hi: 0x90}, + {value: 0x3008, lo: 0x91, hi: 0xbe}, + {value: 0x0040, lo: 0xbf, hi: 0xbf}, + // Block 0xd6, offset 0x661 + {value: 0x0000, lo: 0x04}, + {value: 0x0040, lo: 0x80, hi: 0x8e}, + {value: 0x3308, lo: 0x8f, hi: 0x92}, + {value: 0x0008, lo: 0x93, hi: 0x9f}, + {value: 0x0040, lo: 0xa0, hi: 0xbf}, + // Block 0xd7, offset 0x666 + {value: 0x0000, lo: 0x03}, + {value: 0x0040, lo: 0x80, hi: 0x9f}, + {value: 0x0008, lo: 0xa0, hi: 0xa1}, + {value: 0x0040, lo: 0xa2, hi: 0xbf}, + // Block 0xd8, offset 0x66a + {value: 0x0000, lo: 0x02}, + {value: 0x0008, lo: 0x80, hi: 0xac}, + {value: 0x0040, lo: 0xad, hi: 0xbf}, + // Block 0xd9, offset 0x66d + {value: 0x0000, lo: 0x02}, + {value: 0x0008, lo: 0x80, hi: 0xb2}, + {value: 0x0040, lo: 0xb3, hi: 0xbf}, + // Block 0xda, offset 0x670 + {value: 0x0000, lo: 0x02}, + {value: 0x0008, lo: 0x80, hi: 0x9e}, + {value: 0x0040, lo: 0x9f, hi: 0xbf}, + // Block 0xdb, offset 0x673 + {value: 0x0000, lo: 0x02}, + {value: 0x0040, lo: 0x80, hi: 0xaf}, + {value: 0x0008, lo: 0xb0, hi: 0xbf}, + // Block 0xdc, offset 0x676 + {value: 0x0000, lo: 0x02}, + {value: 0x0008, lo: 0x80, hi: 0xbb}, + {value: 0x0040, lo: 0xbc, hi: 0xbf}, + // Block 0xdd, offset 0x679 + {value: 0x0000, lo: 0x04}, + {value: 0x0008, lo: 0x80, hi: 0xaa}, + {value: 0x0040, lo: 0xab, hi: 0xaf}, + {value: 0x0008, lo: 0xb0, hi: 0xbc}, + {value: 0x0040, lo: 0xbd, hi: 0xbf}, + // Block 0xde, offset 0x67e + {value: 0x0000, lo: 0x09}, + {value: 0x0008, lo: 0x80, hi: 0x88}, + {value: 0x0040, lo: 0x89, hi: 0x8f}, + {value: 0x0008, lo: 0x90, hi: 0x99}, + {value: 0x0040, lo: 0x9a, hi: 0x9b}, + {value: 0x0018, lo: 0x9c, hi: 0x9c}, + {value: 0x3308, lo: 0x9d, hi: 0x9e}, + {value: 0x0018, lo: 0x9f, hi: 0x9f}, + {value: 0x03c0, lo: 0xa0, hi: 0xa3}, + {value: 0x0040, lo: 0xa4, hi: 0xbf}, + // Block 0xdf, offset 0x688 + {value: 0x0000, lo: 0x02}, + {value: 0x0018, lo: 0x80, hi: 0xb5}, + {value: 0x0040, lo: 0xb6, hi: 0xbf}, + // Block 0xe0, offset 0x68b + {value: 0x0000, lo: 0x03}, + {value: 0x0018, lo: 0x80, hi: 0xa6}, + {value: 0x0040, lo: 0xa7, hi: 0xa8}, + {value: 0x0018, lo: 0xa9, hi: 0xbf}, + // Block 0xe1, offset 0x68f + {value: 0x0000, lo: 0x0e}, + {value: 0x0018, lo: 0x80, hi: 0x9d}, + {value: 0xb5b9, lo: 0x9e, hi: 0x9e}, + {value: 0xb601, lo: 0x9f, hi: 0x9f}, + {value: 0xb649, lo: 0xa0, hi: 0xa0}, + {value: 0xb6b1, lo: 0xa1, hi: 0xa1}, + {value: 0xb719, lo: 0xa2, hi: 0xa2}, + {value: 0xb781, lo: 0xa3, hi: 0xa3}, + {value: 0xb7e9, lo: 0xa4, hi: 0xa4}, + {value: 0x3018, lo: 0xa5, hi: 0xa6}, + {value: 0x3318, lo: 0xa7, hi: 0xa9}, + {value: 0x0018, lo: 0xaa, hi: 0xac}, + {value: 0x3018, lo: 0xad, hi: 0xb2}, + {value: 0x0340, lo: 0xb3, hi: 0xba}, + {value: 0x3318, lo: 0xbb, hi: 0xbf}, + // Block 0xe2, offset 0x69e + {value: 0x0000, lo: 0x0b}, + {value: 0x3318, lo: 0x80, hi: 0x82}, + {value: 0x0018, lo: 0x83, hi: 0x84}, + {value: 0x3318, lo: 0x85, hi: 0x8b}, + {value: 0x0018, lo: 0x8c, hi: 0xa9}, + {value: 0x3318, lo: 0xaa, hi: 0xad}, + {value: 0x0018, lo: 0xae, hi: 0xba}, + {value: 0xb851, lo: 0xbb, hi: 0xbb}, + {value: 0xb899, lo: 0xbc, hi: 0xbc}, + {value: 0xb8e1, lo: 0xbd, hi: 0xbd}, + {value: 0xb949, lo: 0xbe, hi: 0xbe}, + {value: 0xb9b1, lo: 0xbf, hi: 0xbf}, + // Block 0xe3, offset 0x6aa + {value: 0x0000, lo: 0x03}, + {value: 0xba19, lo: 0x80, hi: 0x80}, + {value: 0x0018, lo: 0x81, hi: 0xa8}, + {value: 0x0040, lo: 0xa9, hi: 0xbf}, + // Block 0xe4, offset 0x6ae + {value: 0x0000, lo: 0x04}, + {value: 0x0018, lo: 0x80, hi: 0x81}, + {value: 0x3318, lo: 0x82, hi: 0x84}, + {value: 0x0018, lo: 0x85, hi: 0x85}, + {value: 0x0040, lo: 0x86, hi: 0xbf}, + // Block 0xe5, offset 0x6b3 + {value: 0x0000, lo: 0x04}, + {value: 0x0018, lo: 0x80, hi: 0x96}, + {value: 0x0040, lo: 0x97, hi: 0x9f}, + {value: 0x0018, lo: 0xa0, hi: 0xb1}, + {value: 0x0040, lo: 0xb2, hi: 0xbf}, + // Block 0xe6, offset 0x6b8 + {value: 0x0000, lo: 0x03}, + {value: 0x3308, lo: 0x80, hi: 0xb6}, + {value: 0x0018, lo: 0xb7, hi: 0xba}, + {value: 0x3308, lo: 0xbb, hi: 0xbf}, + // Block 0xe7, offset 0x6bc + {value: 0x0000, lo: 0x04}, + {value: 0x3308, lo: 0x80, hi: 0xac}, + {value: 0x0018, lo: 0xad, hi: 0xb4}, + {value: 0x3308, lo: 0xb5, hi: 0xb5}, + {value: 0x0018, lo: 0xb6, hi: 0xbf}, + // Block 0xe8, offset 0x6c1 + {value: 0x0000, lo: 0x08}, + {value: 0x0018, lo: 0x80, hi: 0x83}, + {value: 0x3308, lo: 0x84, hi: 0x84}, + {value: 0x0018, lo: 0x85, hi: 0x8b}, + {value: 0x0040, lo: 0x8c, hi: 0x9a}, + {value: 0x3308, lo: 0x9b, hi: 0x9f}, + {value: 0x0040, lo: 0xa0, hi: 0xa0}, + {value: 0x3308, lo: 0xa1, hi: 0xaf}, + {value: 0x0040, lo: 0xb0, hi: 0xbf}, + // Block 0xe9, offset 0x6ca + {value: 0x0000, lo: 0x0a}, + {value: 0x3308, lo: 0x80, hi: 0x86}, + {value: 0x0040, lo: 0x87, hi: 0x87}, + {value: 0x3308, lo: 0x88, hi: 0x98}, + {value: 0x0040, lo: 0x99, hi: 0x9a}, + {value: 0x3308, lo: 0x9b, hi: 0xa1}, + {value: 0x0040, lo: 0xa2, hi: 0xa2}, + {value: 0x3308, lo: 0xa3, hi: 0xa4}, + {value: 0x0040, lo: 0xa5, hi: 0xa5}, + {value: 0x3308, lo: 0xa6, hi: 0xaa}, + {value: 0x0040, lo: 0xab, hi: 0xbf}, + // Block 0xea, offset 0x6d5 + {value: 0x0000, lo: 0x05}, + {value: 0x0808, lo: 0x80, hi: 0x84}, + {value: 0x0040, lo: 0x85, hi: 0x86}, + {value: 0x0818, lo: 0x87, hi: 0x8f}, + {value: 0x3308, lo: 0x90, hi: 0x96}, + {value: 0x0040, lo: 0x97, hi: 0xbf}, + // Block 0xeb, offset 0x6db + {value: 0x0000, lo: 0x07}, + {value: 0x0a08, lo: 0x80, hi: 0x83}, + {value: 0x3308, lo: 0x84, hi: 0x8a}, + {value: 0x0040, lo: 0x8b, hi: 0x8f}, + {value: 0x0808, lo: 0x90, hi: 0x99}, + {value: 0x0040, lo: 0x9a, hi: 0x9d}, + {value: 0x0818, lo: 0x9e, hi: 0x9f}, + {value: 0x0040, lo: 0xa0, hi: 0xbf}, + // Block 0xec, offset 0x6e3 + {value: 0x0000, lo: 0x03}, + {value: 0x0040, lo: 0x80, hi: 0xaf}, + {value: 0x0018, lo: 0xb0, hi: 0xb1}, + {value: 0x0040, lo: 0xb2, hi: 0xbf}, + // Block 0xed, offset 0x6e7 + {value: 0x0000, lo: 0x03}, + {value: 0x0018, lo: 0x80, hi: 0xab}, + {value: 0x0040, lo: 0xac, hi: 0xaf}, + {value: 0x0018, lo: 0xb0, hi: 0xbf}, + // Block 0xee, offset 0x6eb + {value: 0x0000, lo: 0x05}, + {value: 0x0018, lo: 0x80, hi: 0x93}, + {value: 0x0040, lo: 0x94, hi: 0x9f}, + {value: 0x0018, lo: 0xa0, hi: 0xae}, + {value: 0x0040, lo: 0xaf, hi: 0xb0}, + {value: 0x0018, lo: 0xb1, hi: 0xbf}, + // Block 0xef, offset 0x6f1 + {value: 0x0000, lo: 0x05}, + {value: 0x0040, lo: 0x80, hi: 0x80}, + {value: 0x0018, lo: 0x81, hi: 0x8f}, + {value: 0x0040, lo: 0x90, hi: 0x90}, + {value: 0x0018, lo: 0x91, hi: 0xb5}, + {value: 0x0040, lo: 0xb6, hi: 0xbf}, + // Block 0xf0, offset 0x6f7 + {value: 0x0000, lo: 0x04}, + {value: 0x0018, lo: 0x80, hi: 0x8f}, + {value: 0xc1c1, lo: 0x90, hi: 0x90}, + {value: 0x0018, lo: 0x91, hi: 0xac}, + {value: 0x0040, lo: 0xad, hi: 0xbf}, + // Block 0xf1, offset 0x6fc + {value: 0x0000, lo: 0x02}, + {value: 0x0040, lo: 0x80, hi: 0xa5}, + {value: 0x0018, lo: 0xa6, hi: 0xbf}, + // Block 0xf2, offset 0x6ff + {value: 0x0000, lo: 0x0f}, + {value: 0xc7e9, lo: 0x80, hi: 0x80}, + {value: 0xc839, lo: 0x81, hi: 0x81}, + {value: 0xc889, lo: 0x82, hi: 0x82}, + {value: 0xc8d9, lo: 0x83, hi: 0x83}, + {value: 0xc929, lo: 0x84, hi: 0x84}, + {value: 0xc979, lo: 0x85, hi: 0x85}, + {value: 0xc9c9, lo: 0x86, hi: 0x86}, + {value: 0xca19, lo: 0x87, hi: 0x87}, + {value: 0xca69, lo: 0x88, hi: 0x88}, + {value: 0x0040, lo: 0x89, hi: 0x8f}, + {value: 0xcab9, lo: 0x90, hi: 0x90}, + {value: 0xcad9, lo: 0x91, hi: 0x91}, + {value: 0x0040, lo: 0x92, hi: 0x9f}, + {value: 0x0018, lo: 0xa0, hi: 0xa5}, + {value: 0x0040, lo: 0xa6, hi: 0xbf}, + // Block 0xf3, offset 0x70f + {value: 0x0000, lo: 0x06}, + {value: 0x0018, lo: 0x80, hi: 0x94}, + {value: 0x0040, lo: 0x95, hi: 0x9f}, + {value: 0x0018, lo: 0xa0, hi: 0xac}, + {value: 0x0040, lo: 0xad, hi: 0xaf}, + {value: 0x0018, lo: 0xb0, hi: 0xb8}, + {value: 0x0040, lo: 0xb9, hi: 0xbf}, + // Block 0xf4, offset 0x716 + {value: 0x0000, lo: 0x02}, + {value: 0x0018, lo: 0x80, hi: 0xb3}, + {value: 0x0040, lo: 0xb4, hi: 0xbf}, + // Block 0xf5, offset 0x719 + {value: 0x0000, lo: 0x02}, + {value: 0x0018, lo: 0x80, hi: 0x94}, + {value: 0x0040, lo: 0x95, hi: 0xbf}, + // Block 0xf6, offset 0x71c + {value: 0x0000, lo: 0x03}, + {value: 0x0018, lo: 0x80, hi: 0x8b}, + {value: 0x0040, lo: 0x8c, hi: 0x8f}, + {value: 0x0018, lo: 0x90, hi: 0xbf}, + // Block 0xf7, offset 0x720 + {value: 0x0000, lo: 0x05}, + {value: 0x0018, lo: 0x80, hi: 0x87}, + {value: 0x0040, lo: 0x88, hi: 0x8f}, + {value: 0x0018, lo: 0x90, hi: 0x99}, + {value: 0x0040, lo: 0x9a, hi: 0x9f}, + {value: 0x0018, lo: 0xa0, hi: 0xbf}, + // Block 0xf8, offset 0x726 + {value: 0x0000, lo: 0x04}, + {value: 0x0018, lo: 0x80, hi: 0x87}, + {value: 0x0040, lo: 0x88, hi: 0x8f}, + {value: 0x0018, lo: 0x90, hi: 0xad}, + {value: 0x0040, lo: 0xae, hi: 0xbf}, + // Block 0xf9, offset 0x72b + {value: 0x0000, lo: 0x04}, + {value: 0x0018, lo: 0x80, hi: 0x8b}, + {value: 0x0040, lo: 0x8c, hi: 0x8f}, + {value: 0x0018, lo: 0x90, hi: 0xbe}, + {value: 0x0040, lo: 0xbf, hi: 0xbf}, + // Block 0xfa, offset 0x730 + {value: 0x0000, lo: 0x04}, + {value: 0x0018, lo: 0x80, hi: 0x8c}, + {value: 0x0040, lo: 0x8d, hi: 0x8f}, + {value: 0x0018, lo: 0x90, hi: 0xab}, + {value: 0x0040, lo: 0xac, hi: 0xbf}, + // Block 0xfb, offset 0x735 + {value: 0x0000, lo: 0x02}, + {value: 0x0018, lo: 0x80, hi: 0x97}, + {value: 0x0040, lo: 0x98, hi: 0xbf}, + // Block 0xfc, offset 0x738 + {value: 0x0000, lo: 0x04}, + {value: 0x0018, lo: 0x80, hi: 0x80}, + {value: 0x0040, lo: 0x81, hi: 0x8f}, + {value: 0x0018, lo: 0x90, hi: 0xa6}, + {value: 0x0040, lo: 0xa7, hi: 0xbf}, + // Block 0xfd, offset 0x73d + {value: 0x0000, lo: 0x02}, + {value: 0x0008, lo: 0x80, hi: 0x96}, + {value: 0x0040, lo: 0x97, hi: 0xbf}, + // Block 0xfe, offset 0x740 + {value: 0x0000, lo: 0x02}, + {value: 0x0008, lo: 0x80, hi: 0xb4}, + {value: 0x0040, lo: 0xb5, hi: 0xbf}, + // Block 0xff, offset 0x743 + {value: 0x0000, lo: 0x03}, + {value: 0x0008, lo: 0x80, hi: 0x9d}, + {value: 0x0040, lo: 0x9e, hi: 0x9f}, + {value: 0x0008, lo: 0xa0, hi: 0xbf}, + // Block 0x100, offset 0x747 + {value: 0x0000, lo: 0x03}, + {value: 0x0008, lo: 0x80, hi: 0xa1}, + {value: 0x0040, lo: 0xa2, hi: 0xaf}, + {value: 0x0008, lo: 0xb0, hi: 0xbf}, + // Block 0x101, offset 0x74b + {value: 0x0000, lo: 0x02}, + {value: 0x0008, lo: 0x80, hi: 0xa0}, + {value: 0x0040, lo: 0xa1, hi: 0xbf}, + // Block 0x102, offset 0x74e + {value: 0x0020, lo: 0x0f}, + {value: 0xdeb9, lo: 0x80, hi: 0x89}, + {value: 0x8dfd, lo: 0x8a, hi: 0x8a}, + {value: 0xdff9, lo: 0x8b, hi: 0x9c}, + {value: 0x8e1d, lo: 0x9d, hi: 0x9d}, + {value: 0xe239, lo: 0x9e, hi: 0xa2}, + {value: 0x8e3d, lo: 0xa3, hi: 0xa3}, + {value: 0xe2d9, lo: 0xa4, hi: 0xab}, + {value: 0x7ed5, lo: 0xac, hi: 0xac}, + {value: 0xe3d9, lo: 0xad, hi: 0xaf}, + {value: 0x8e5d, lo: 0xb0, hi: 0xb0}, + {value: 0xe439, lo: 0xb1, hi: 0xb6}, + {value: 0x8e7d, lo: 0xb7, hi: 0xb9}, + {value: 0xe4f9, lo: 0xba, hi: 0xba}, + {value: 0x8edd, lo: 0xbb, hi: 0xbb}, + {value: 0xe519, lo: 0xbc, hi: 0xbf}, + // Block 0x103, offset 0x75e + {value: 0x0020, lo: 0x10}, + {value: 0x937d, lo: 0x80, hi: 0x80}, + {value: 0xf099, lo: 0x81, hi: 0x86}, + {value: 0x939d, lo: 0x87, hi: 0x8a}, + {value: 0xd9f9, lo: 0x8b, hi: 0x8b}, + {value: 0xf159, lo: 0x8c, hi: 0x96}, + {value: 0x941d, lo: 0x97, hi: 0x97}, + {value: 0xf2b9, lo: 0x98, hi: 0xa3}, + {value: 0x943d, lo: 0xa4, hi: 0xa6}, + {value: 0xf439, lo: 0xa7, hi: 0xaa}, + {value: 0x949d, lo: 0xab, hi: 0xab}, + {value: 0xf4b9, lo: 0xac, hi: 0xac}, + {value: 0x94bd, lo: 0xad, hi: 0xad}, + {value: 0xf4d9, lo: 0xae, hi: 0xaf}, + {value: 0x94dd, lo: 0xb0, hi: 0xb1}, + {value: 0xf519, lo: 0xb2, hi: 0xbe}, + {value: 0x2040, lo: 0xbf, hi: 0xbf}, + // Block 0x104, offset 0x76f + {value: 0x0000, lo: 0x04}, + {value: 0x0040, lo: 0x80, hi: 0x80}, + {value: 0x0340, lo: 0x81, hi: 0x81}, + {value: 0x0040, lo: 0x82, hi: 0x9f}, + {value: 0x0340, lo: 0xa0, hi: 0xbf}, + // Block 0x105, offset 0x774 + {value: 0x0000, lo: 0x01}, + {value: 0x0340, lo: 0x80, hi: 0xbf}, + // Block 0x106, offset 0x776 + {value: 0x0000, lo: 0x01}, + {value: 0x33c0, lo: 0x80, hi: 0xbf}, + // Block 0x107, offset 0x778 + {value: 0x0000, lo: 0x02}, + {value: 0x33c0, lo: 0x80, hi: 0xaf}, + {value: 0x0040, lo: 0xb0, hi: 0xbf}, +} + +// Total table size 42115 bytes (41KiB); checksum: F4A1FA4E diff --git a/vendor/golang.org/x/net/idna/trie.go b/vendor/golang.org/x/net/idna/trie.go new file mode 100644 index 0000000000..c4ef847e7a --- /dev/null +++ b/vendor/golang.org/x/net/idna/trie.go @@ -0,0 +1,72 @@ +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. + +// Copyright 2016 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 idna + +// appendMapping appends the mapping for the respective rune. isMapped must be +// true. A mapping is a categorization of a rune as defined in UTS #46. +func (c info) appendMapping(b []byte, s string) []byte { + index := int(c >> indexShift) + if c&xorBit == 0 { + s := mappings[index:] + return append(b, s[1:s[0]+1]...) + } + b = append(b, s...) + if c&inlineXOR == inlineXOR { + // TODO: support and handle two-byte inline masks + b[len(b)-1] ^= byte(index) + } else { + for p := len(b) - int(xorData[index]); p < len(b); p++ { + index++ + b[p] ^= xorData[index] + } + } + return b +} + +// Sparse block handling code. + +type valueRange struct { + value uint16 // header: value:stride + lo, hi byte // header: lo:n +} + +type sparseBlocks struct { + values []valueRange + offset []uint16 +} + +var idnaSparse = sparseBlocks{ + values: idnaSparseValues[:], + offset: idnaSparseOffset[:], +} + +// Don't use newIdnaTrie to avoid unconditional linking in of the table. +var trie = &idnaTrie{} + +// lookup determines the type of block n and looks up the value for b. +// For n < t.cutoff, the block is a simple lookup table. Otherwise, the block +// is a list of ranges with an accompanying value. Given a matching range r, +// the value for b is by r.value + (b - r.lo) * stride. +func (t *sparseBlocks) lookup(n uint32, b byte) uint16 { + offset := t.offset[n] + header := t.values[offset] + lo := offset + 1 + hi := lo + uint16(header.lo) + for lo < hi { + m := lo + (hi-lo)/2 + r := t.values[m] + if r.lo <= b && b <= r.hi { + return r.value + uint16(b-r.lo)*header.value + } + if b < r.lo { + hi = m + } else { + lo = m + 1 + } + } + return 0 +} diff --git a/vendor/golang.org/x/net/idna/trieval.go b/vendor/golang.org/x/net/idna/trieval.go new file mode 100644 index 0000000000..7a8cf889b5 --- /dev/null +++ b/vendor/golang.org/x/net/idna/trieval.go @@ -0,0 +1,119 @@ +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. + +package idna + +// This file contains definitions for interpreting the trie value of the idna +// trie generated by "go run gen*.go". It is shared by both the generator +// program and the resultant package. Sharing is achieved by the generator +// copying gen_trieval.go to trieval.go and changing what's above this comment. + +// info holds information from the IDNA mapping table for a single rune. It is +// the value returned by a trie lookup. In most cases, all information fits in +// a 16-bit value. For mappings, this value may contain an index into a slice +// with the mapped string. Such mappings can consist of the actual mapped value +// or an XOR pattern to be applied to the bytes of the UTF8 encoding of the +// input rune. This technique is used by the cases packages and reduces the +// table size significantly. +// +// The per-rune values have the following format: +// +// if mapped { +// if inlinedXOR { +// 15..13 inline XOR marker +// 12..11 unused +// 10..3 inline XOR mask +// } else { +// 15..3 index into xor or mapping table +// } +// } else { +// 15..14 unused +// 13 mayNeedNorm +// 12..11 attributes +// 10..8 joining type +// 7..3 category type +// } +// 2 use xor pattern +// 1..0 mapped category +// +// See the definitions below for a more detailed description of the various +// bits. +type info uint16 + +const ( + catSmallMask = 0x3 + catBigMask = 0xF8 + indexShift = 3 + xorBit = 0x4 // interpret the index as an xor pattern + inlineXOR = 0xE000 // These bits are set if the XOR pattern is inlined. + + joinShift = 8 + joinMask = 0x07 + + // Attributes + attributesMask = 0x1800 + viramaModifier = 0x1800 + modifier = 0x1000 + rtl = 0x0800 + + mayNeedNorm = 0x2000 +) + +// A category corresponds to a category defined in the IDNA mapping table. +type category uint16 + +const ( + unknown category = 0 // not currently defined in unicode. + mapped category = 1 + disallowedSTD3Mapped category = 2 + deviation category = 3 +) + +const ( + valid category = 0x08 + validNV8 category = 0x18 + validXV8 category = 0x28 + disallowed category = 0x40 + disallowedSTD3Valid category = 0x80 + ignored category = 0xC0 +) + +// join types and additional rune information +const ( + joiningL = (iota + 1) + joiningD + joiningT + joiningR + + //the following types are derived during processing + joinZWJ + joinZWNJ + joinVirama + numJoinTypes +) + +func (c info) isMapped() bool { + return c&0x3 != 0 +} + +func (c info) category() category { + small := c & catSmallMask + if small != 0 { + return category(small) + } + return category(c & catBigMask) +} + +func (c info) joinType() info { + if c.isMapped() { + return 0 + } + return (c >> joinShift) & joinMask +} + +func (c info) isModifier() bool { + return c&(modifier|catSmallMask) == modifier +} + +func (c info) isViramaModifier() bool { + return c&(attributesMask|catSmallMask) == viramaModifier +} diff --git a/vendor/golang.org/x/sys/cpu/cpu.go b/vendor/golang.org/x/sys/cpu/cpu.go new file mode 100644 index 0000000000..6b0034ecd7 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu.go @@ -0,0 +1,89 @@ +// 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 cpu implements processor feature detection for +// various CPU architectures. +package cpu + +// CacheLinePad is used to pad structs to avoid false sharing. +type CacheLinePad struct{ _ [cacheLineSize]byte } + +// X86 contains the supported CPU features of the +// current X86/AMD64 platform. If the current platform +// is not X86/AMD64 then all feature flags are false. +// +// X86 is padded to avoid false sharing. Further the HasAVX +// and HasAVX2 are only set if the OS supports XMM and YMM +// registers in addition to the CPUID feature bit being set. +var X86 struct { + _ CacheLinePad + HasAES bool // AES hardware implementation (AES NI) + HasADX bool // Multi-precision add-carry instruction extensions + HasAVX bool // Advanced vector extension + HasAVX2 bool // Advanced vector extension 2 + HasBMI1 bool // Bit manipulation instruction set 1 + HasBMI2 bool // Bit manipulation instruction set 2 + HasERMS bool // Enhanced REP for MOVSB and STOSB + HasFMA bool // Fused-multiply-add instructions + HasOSXSAVE bool // OS supports XSAVE/XRESTOR for saving/restoring XMM registers. + HasPCLMULQDQ bool // PCLMULQDQ instruction - most often used for AES-GCM + HasPOPCNT bool // Hamming weight instruction POPCNT. + HasRDRAND bool // RDRAND instruction (on-chip random number generator) + HasRDSEED bool // RDSEED instruction (on-chip random number generator) + HasSSE2 bool // Streaming SIMD extension 2 (always available on amd64) + HasSSE3 bool // Streaming SIMD extension 3 + HasSSSE3 bool // Supplemental streaming SIMD extension 3 + HasSSE41 bool // Streaming SIMD extension 4 and 4.1 + HasSSE42 bool // Streaming SIMD extension 4 and 4.2 + _ CacheLinePad +} + +// ARM64 contains the supported CPU features of the +// current ARMv8(aarch64) platform. If the current platform +// is not arm64 then all feature flags are false. +var ARM64 struct { + _ CacheLinePad + HasFP bool // Floating-point instruction set (always available) + HasASIMD bool // Advanced SIMD (always available) + HasEVTSTRM bool // Event stream support + HasAES bool // AES hardware implementation + HasPMULL bool // Polynomial multiplication instruction set + HasSHA1 bool // SHA1 hardware implementation + HasSHA2 bool // SHA2 hardware implementation + HasCRC32 bool // CRC32 hardware implementation + HasATOMICS bool // Atomic memory operation instruction set + HasFPHP bool // Half precision floating-point instruction set + HasASIMDHP bool // Advanced SIMD half precision instruction set + HasCPUID bool // CPUID identification scheme registers + HasASIMDRDM bool // Rounding double multiply add/subtract instruction set + HasJSCVT bool // Javascript conversion from floating-point to integer + HasFCMA bool // Floating-point multiplication and addition of complex numbers + HasLRCPC bool // Release Consistent processor consistent support + HasDCPOP bool // Persistent memory support + HasSHA3 bool // SHA3 hardware implementation + HasSM3 bool // SM3 hardware implementation + HasSM4 bool // SM4 hardware implementation + HasASIMDDP bool // Advanced SIMD double precision instruction set + HasSHA512 bool // SHA512 hardware implementation + HasSVE bool // Scalable Vector Extensions + HasASIMDFHM bool // Advanced SIMD multiplication FP16 to FP32 + _ CacheLinePad +} + +// PPC64 contains the supported CPU features of the current ppc64/ppc64le platforms. +// If the current platform is not ppc64/ppc64le then all feature flags are false. +// +// For ppc64/ppc64le, it is safe to check only for ISA level starting on ISA v3.00, +// since there are no optional categories. There are some exceptions that also +// require kernel support to work (DARN, SCV), so there are feature bits for +// those as well. The minimum processor requirement is POWER8 (ISA 2.07). +// The struct is padded to avoid false sharing. +var PPC64 struct { + _ CacheLinePad + HasDARN bool // Hardware random number generator (requires kernel enablement) + HasSCV bool // Syscall vectored (requires kernel enablement) + IsPOWER8 bool // ISA v2.07 (POWER8) + IsPOWER9 bool // ISA v3.00 (POWER9) + _ CacheLinePad +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_arm.go b/vendor/golang.org/x/sys/cpu/cpu_arm.go new file mode 100644 index 0000000000..7f2348b7d4 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_arm.go @@ -0,0 +1,9 @@ +// 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 cpu + +const cacheLineSize = 32 + +func doinit() {} diff --git a/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go b/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go new file mode 100644 index 0000000000..f7cb46971c --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go @@ -0,0 +1,16 @@ +// 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 386 amd64 amd64p32 +// +build !gccgo + +package cpu + +// cpuid is implemented in cpu_x86.s for gc compiler +// and in cpu_gccgo.c for gccgo. +func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) + +// xgetbv with ecx = 0 is implemented in cpu_x86.s for gc compiler +// and in cpu_gccgo.c for gccgo. +func xgetbv() (eax, edx uint32) diff --git a/vendor/golang.org/x/sys/cpu/cpu_gccgo.c b/vendor/golang.org/x/sys/cpu/cpu_gccgo.c new file mode 100644 index 0000000000..e363c7d131 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_gccgo.c @@ -0,0 +1,43 @@ +// 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 386 amd64 amd64p32 +// +build gccgo + +#include +#include + +// Need to wrap __get_cpuid_count because it's declared as static. +int +gccgoGetCpuidCount(uint32_t leaf, uint32_t subleaf, + uint32_t *eax, uint32_t *ebx, + uint32_t *ecx, uint32_t *edx) +{ + return __get_cpuid_count(leaf, subleaf, eax, ebx, ecx, edx); +} + +// xgetbv reads the contents of an XCR (Extended Control Register) +// specified in the ECX register into registers EDX:EAX. +// Currently, the only supported value for XCR is 0. +// +// TODO: Replace with a better alternative: +// +// #include +// +// #pragma GCC target("xsave") +// +// void gccgoXgetbv(uint32_t *eax, uint32_t *edx) { +// unsigned long long x = _xgetbv(0); +// *eax = x & 0xffffffff; +// *edx = (x >> 32) & 0xffffffff; +// } +// +// Note that _xgetbv is defined starting with GCC 8. +void +gccgoXgetbv(uint32_t *eax, uint32_t *edx) +{ + __asm(" xorl %%ecx, %%ecx\n" + " xgetbv" + : "=a"(*eax), "=d"(*edx)); +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_gccgo.go b/vendor/golang.org/x/sys/cpu/cpu_gccgo.go new file mode 100644 index 0000000000..ba49b91bd3 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_gccgo.go @@ -0,0 +1,26 @@ +// 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 386 amd64 amd64p32 +// +build gccgo + +package cpu + +//extern gccgoGetCpuidCount +func gccgoGetCpuidCount(eaxArg, ecxArg uint32, eax, ebx, ecx, edx *uint32) + +func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) { + var a, b, c, d uint32 + gccgoGetCpuidCount(eaxArg, ecxArg, &a, &b, &c, &d) + return a, b, c, d +} + +//extern gccgoXgetbv +func gccgoXgetbv(eax, edx *uint32) + +func xgetbv() (eax, edx uint32) { + var a, d uint32 + gccgoXgetbv(&a, &d) + return a, d +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux.go b/vendor/golang.org/x/sys/cpu/cpu_linux.go new file mode 100644 index 0000000000..a8452e094b --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_linux.go @@ -0,0 +1,61 @@ +// 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 !amd64,!amd64p32,!386 + +package cpu + +import ( + "encoding/binary" + "io/ioutil" + "runtime" +) + +const ( + _AT_HWCAP = 16 + _AT_HWCAP2 = 26 + + procAuxv = "/proc/self/auxv" + + uintSize uint = 32 << (^uint(0) >> 63) +) + +// For those platforms don't have a 'cpuid' equivalent we use HWCAP/HWCAP2 +// These are initialized in cpu_$GOARCH.go +// and should not be changed after they are initialized. +var HWCap uint +var HWCap2 uint + +func init() { + buf, err := ioutil.ReadFile(procAuxv) + if err != nil { + panic("read proc auxv failed: " + err.Error()) + } + + pb := int(uintSize / 8) + + for i := 0; i < len(buf)-pb*2; i += pb * 2 { + var tag, val uint + switch uintSize { + case 32: + tag = uint(binary.LittleEndian.Uint32(buf[i:])) + val = uint(binary.LittleEndian.Uint32(buf[i+pb:])) + case 64: + if runtime.GOARCH == "ppc64" { + tag = uint(binary.BigEndian.Uint64(buf[i:])) + val = uint(binary.BigEndian.Uint64(buf[i+pb:])) + } else { + tag = uint(binary.LittleEndian.Uint64(buf[i:])) + val = uint(binary.LittleEndian.Uint64(buf[i+pb:])) + } + } + switch tag { + case _AT_HWCAP: + HWCap = val + case _AT_HWCAP2: + HWCap2 = val + } + } + doinit() +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go b/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go new file mode 100644 index 0000000000..02ed58b30d --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go @@ -0,0 +1,67 @@ +// 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 cpu + +const cacheLineSize = 64 + +// HWCAP/HWCAP2 bits. These are exposed by Linux. +const ( + hwcap_FP = 1 << 0 + hwcap_ASIMD = 1 << 1 + hwcap_EVTSTRM = 1 << 2 + hwcap_AES = 1 << 3 + hwcap_PMULL = 1 << 4 + hwcap_SHA1 = 1 << 5 + hwcap_SHA2 = 1 << 6 + hwcap_CRC32 = 1 << 7 + hwcap_ATOMICS = 1 << 8 + hwcap_FPHP = 1 << 9 + hwcap_ASIMDHP = 1 << 10 + hwcap_CPUID = 1 << 11 + hwcap_ASIMDRDM = 1 << 12 + hwcap_JSCVT = 1 << 13 + hwcap_FCMA = 1 << 14 + hwcap_LRCPC = 1 << 15 + hwcap_DCPOP = 1 << 16 + hwcap_SHA3 = 1 << 17 + hwcap_SM3 = 1 << 18 + hwcap_SM4 = 1 << 19 + hwcap_ASIMDDP = 1 << 20 + hwcap_SHA512 = 1 << 21 + hwcap_SVE = 1 << 22 + hwcap_ASIMDFHM = 1 << 23 +) + +func doinit() { + // HWCAP feature bits + ARM64.HasFP = isSet(HWCap, hwcap_FP) + ARM64.HasASIMD = isSet(HWCap, hwcap_ASIMD) + ARM64.HasEVTSTRM = isSet(HWCap, hwcap_EVTSTRM) + ARM64.HasAES = isSet(HWCap, hwcap_AES) + ARM64.HasPMULL = isSet(HWCap, hwcap_PMULL) + ARM64.HasSHA1 = isSet(HWCap, hwcap_SHA1) + ARM64.HasSHA2 = isSet(HWCap, hwcap_SHA2) + ARM64.HasCRC32 = isSet(HWCap, hwcap_CRC32) + ARM64.HasATOMICS = isSet(HWCap, hwcap_ATOMICS) + ARM64.HasFPHP = isSet(HWCap, hwcap_FPHP) + ARM64.HasASIMDHP = isSet(HWCap, hwcap_ASIMDHP) + ARM64.HasCPUID = isSet(HWCap, hwcap_CPUID) + ARM64.HasASIMDRDM = isSet(HWCap, hwcap_ASIMDRDM) + ARM64.HasJSCVT = isSet(HWCap, hwcap_JSCVT) + ARM64.HasFCMA = isSet(HWCap, hwcap_FCMA) + ARM64.HasLRCPC = isSet(HWCap, hwcap_LRCPC) + ARM64.HasDCPOP = isSet(HWCap, hwcap_DCPOP) + ARM64.HasSHA3 = isSet(HWCap, hwcap_SHA3) + ARM64.HasSM3 = isSet(HWCap, hwcap_SM3) + ARM64.HasSM4 = isSet(HWCap, hwcap_SM4) + ARM64.HasASIMDDP = isSet(HWCap, hwcap_ASIMDDP) + ARM64.HasSHA512 = isSet(HWCap, hwcap_SHA512) + ARM64.HasSVE = isSet(HWCap, hwcap_SVE) + ARM64.HasASIMDFHM = isSet(HWCap, hwcap_ASIMDFHM) +} + +func isSet(hwc uint, value uint) bool { + return hwc&value != 0 +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_mips64x.go b/vendor/golang.org/x/sys/cpu/cpu_mips64x.go new file mode 100644 index 0000000000..f55e0c82c7 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_mips64x.go @@ -0,0 +1,11 @@ +// 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 mips64 mips64le + +package cpu + +const cacheLineSize = 32 + +func doinit() {} diff --git a/vendor/golang.org/x/sys/cpu/cpu_mipsx.go b/vendor/golang.org/x/sys/cpu/cpu_mipsx.go new file mode 100644 index 0000000000..cda87b1a1b --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_mipsx.go @@ -0,0 +1,11 @@ +// 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 mips mipsle + +package cpu + +const cacheLineSize = 32 + +func doinit() {} diff --git a/vendor/golang.org/x/sys/cpu/cpu_other_arm64.go b/vendor/golang.org/x/sys/cpu/cpu_other_arm64.go new file mode 100644 index 0000000000..dd1e76dc92 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_other_arm64.go @@ -0,0 +1,11 @@ +// Copyright 2019 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 !linux,arm64 + +package cpu + +const cacheLineSize = 64 + +func doinit() {} diff --git a/vendor/golang.org/x/sys/cpu/cpu_ppc64x.go b/vendor/golang.org/x/sys/cpu/cpu_ppc64x.go new file mode 100644 index 0000000000..ed975de621 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_ppc64x.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 ppc64 ppc64le + +package cpu + +const cacheLineSize = 128 + +// HWCAP/HWCAP2 bits. These are exposed by the kernel. +const ( + // ISA Level + _PPC_FEATURE2_ARCH_2_07 = 0x80000000 + _PPC_FEATURE2_ARCH_3_00 = 0x00800000 + + // CPU features + _PPC_FEATURE2_DARN = 0x00200000 + _PPC_FEATURE2_SCV = 0x00100000 +) + +func doinit() { + // HWCAP2 feature bits + PPC64.IsPOWER8 = isSet(HWCap2, _PPC_FEATURE2_ARCH_2_07) + PPC64.IsPOWER9 = isSet(HWCap2, _PPC_FEATURE2_ARCH_3_00) + PPC64.HasDARN = isSet(HWCap2, _PPC_FEATURE2_DARN) + PPC64.HasSCV = isSet(HWCap2, _PPC_FEATURE2_SCV) +} + +func isSet(hwc uint, value uint) bool { + return hwc&value != 0 +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_s390x.go b/vendor/golang.org/x/sys/cpu/cpu_s390x.go new file mode 100644 index 0000000000..ce8a2289e0 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_s390x.go @@ -0,0 +1,9 @@ +// 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 cpu + +const cacheLineSize = 256 + +func doinit() {} diff --git a/vendor/golang.org/x/sys/cpu/cpu_x86.go b/vendor/golang.org/x/sys/cpu/cpu_x86.go new file mode 100644 index 0000000000..2b3ca2e115 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_x86.go @@ -0,0 +1,57 @@ +// 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 386 amd64 amd64p32 + +package cpu + +const cacheLineSize = 64 + +func init() { + maxID, _, _, _ := cpuid(0, 0) + + if maxID < 1 { + return + } + + _, _, ecx1, edx1 := cpuid(1, 0) + X86.HasSSE2 = isSet(26, edx1) + + X86.HasSSE3 = isSet(0, ecx1) + X86.HasPCLMULQDQ = isSet(1, ecx1) + X86.HasSSSE3 = isSet(9, ecx1) + X86.HasFMA = isSet(12, ecx1) + X86.HasSSE41 = isSet(19, ecx1) + X86.HasSSE42 = isSet(20, ecx1) + X86.HasPOPCNT = isSet(23, ecx1) + X86.HasAES = isSet(25, ecx1) + X86.HasOSXSAVE = isSet(27, ecx1) + X86.HasRDRAND = isSet(30, ecx1) + + osSupportsAVX := false + // For XGETBV, OSXSAVE bit is required and sufficient. + if X86.HasOSXSAVE { + eax, _ := xgetbv() + // Check if XMM and YMM registers have OS support. + osSupportsAVX = isSet(1, eax) && isSet(2, eax) + } + + X86.HasAVX = isSet(28, ecx1) && osSupportsAVX + + if maxID < 7 { + return + } + + _, ebx7, _, _ := cpuid(7, 0) + X86.HasBMI1 = isSet(3, ebx7) + X86.HasAVX2 = isSet(5, ebx7) && osSupportsAVX + X86.HasBMI2 = isSet(8, ebx7) + X86.HasERMS = isSet(9, ebx7) + X86.HasRDSEED = isSet(18, ebx7) + X86.HasADX = isSet(19, ebx7) +} + +func isSet(bitpos uint, value uint32) bool { + return value&(1<>1&(m0&m) + x&(m0&m) + // x = x>>2&(m1&m) + x&(m1&m) + // x = x>>4&(m2&m) + x&(m2&m) + // x = x>>8&(m3&m) + x&(m3&m) + // x = x>>16&(m4&m) + x&(m4&m) + // x = x>>32&(m5&m) + x&(m5&m) + // return int(x) + // + // Masking (& operations) can be left away when there's no + // danger that a field's sum will carry over into the next + // field: Since the result cannot be > 64, 8 bits is enough + // and we can ignore the masks for the shifts by 8 and up. + // Per "Hacker's Delight", the first line can be simplified + // more, but it saves at best one instruction, so we leave + // it alone for clarity. + const m = 1<<64 - 1 + x = x>>1&(m0&m) + x&(m0&m) + x = x>>2&(m1&m) + x&(m1&m) + x = (x>>4 + x) & (m2 & m) + x += x >> 8 + x += x >> 16 + x += x >> 32 + return int(x) & (1<<7 - 1) +} diff --git a/vendor/golang.org/x/sys/unix/aliases.go b/vendor/golang.org/x/sys/unix/aliases.go new file mode 100644 index 0000000000..951fce4d0d --- /dev/null +++ b/vendor/golang.org/x/sys/unix/aliases.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 aix darwin dragonfly freebsd linux netbsd openbsd solaris +// +build go1.9 + +package unix + +import "syscall" + +type Signal = syscall.Signal +type Errno = syscall.Errno +type SysProcAttr = syscall.SysProcAttr diff --git a/vendor/golang.org/x/sys/unix/asm_aix_ppc64.s b/vendor/golang.org/x/sys/unix/asm_aix_ppc64.s new file mode 100644 index 0000000000..06f84b8555 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/asm_aix_ppc64.s @@ -0,0 +1,17 @@ +// 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 !gccgo + +#include "textflag.h" + +// +// System calls for ppc64, AIX are implemented in runtime/syscall_aix.go +// + +TEXT ·syscall6(SB),NOSPLIT,$0-88 + JMP syscall·syscall6(SB) + +TEXT ·rawSyscall6(SB),NOSPLIT,$0-88 + JMP syscall·rawSyscall6(SB) diff --git a/vendor/golang.org/x/sys/unix/asm_dragonfly_amd64.s b/vendor/golang.org/x/sys/unix/asm_dragonfly_amd64.s index d5ed6726cc..603dd5728c 100644 --- a/vendor/golang.org/x/sys/unix/asm_dragonfly_amd64.s +++ b/vendor/golang.org/x/sys/unix/asm_dragonfly_amd64.s @@ -13,17 +13,17 @@ // Just jump to package syscall's implementation for all these functions. // The runtime may know about them. -TEXT ·Syscall(SB),NOSPLIT,$0-64 +TEXT ·Syscall(SB),NOSPLIT,$0-56 JMP syscall·Syscall(SB) -TEXT ·Syscall6(SB),NOSPLIT,$0-88 +TEXT ·Syscall6(SB),NOSPLIT,$0-80 JMP syscall·Syscall6(SB) -TEXT ·Syscall9(SB),NOSPLIT,$0-112 +TEXT ·Syscall9(SB),NOSPLIT,$0-104 JMP syscall·Syscall9(SB) -TEXT ·RawSyscall(SB),NOSPLIT,$0-64 +TEXT ·RawSyscall(SB),NOSPLIT,$0-56 JMP syscall·RawSyscall(SB) -TEXT ·RawSyscall6(SB),NOSPLIT,$0-88 +TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 JMP syscall·RawSyscall6(SB) diff --git a/vendor/golang.org/x/sys/unix/asm_freebsd_arm64.s b/vendor/golang.org/x/sys/unix/asm_freebsd_arm64.s new file mode 100644 index 0000000000..d9318cbf03 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/asm_freebsd_arm64.s @@ -0,0 +1,29 @@ +// 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 !gccgo + +#include "textflag.h" + +// +// System call support for ARM64, FreeBSD +// + +// Just jump to package syscall's implementation for all these functions. +// The runtime may know about them. + +TEXT ·Syscall(SB),NOSPLIT,$0-56 + JMP syscall·Syscall(SB) + +TEXT ·Syscall6(SB),NOSPLIT,$0-80 + JMP syscall·Syscall6(SB) + +TEXT ·Syscall9(SB),NOSPLIT,$0-104 + JMP syscall·Syscall9(SB) + +TEXT ·RawSyscall(SB),NOSPLIT,$0-56 + JMP syscall·RawSyscall(SB) + +TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 + JMP syscall·RawSyscall6(SB) diff --git a/vendor/golang.org/x/sys/unix/asm_linux_386.s b/vendor/golang.org/x/sys/unix/asm_linux_386.s index 4db2909323..448bebbb59 100644 --- a/vendor/golang.org/x/sys/unix/asm_linux_386.s +++ b/vendor/golang.org/x/sys/unix/asm_linux_386.s @@ -10,21 +10,51 @@ // System calls for 386, Linux // +// See ../runtime/sys_linux_386.s for the reason why we always use int 0x80 +// instead of the glibc-specific "CALL 0x10(GS)". +#define INVOKE_SYSCALL INT $0x80 + // Just jump to package syscall's implementation for all these functions. // The runtime may know about them. -TEXT ·Syscall(SB),NOSPLIT,$0-28 +TEXT ·Syscall(SB),NOSPLIT,$0-28 JMP syscall·Syscall(SB) -TEXT ·Syscall6(SB),NOSPLIT,$0-40 +TEXT ·Syscall6(SB),NOSPLIT,$0-40 JMP syscall·Syscall6(SB) +TEXT ·SyscallNoError(SB),NOSPLIT,$0-24 + CALL runtime·entersyscall(SB) + MOVL trap+0(FP), AX // syscall entry + MOVL a1+4(FP), BX + MOVL a2+8(FP), CX + MOVL a3+12(FP), DX + MOVL $0, SI + MOVL $0, DI + INVOKE_SYSCALL + MOVL AX, r1+16(FP) + MOVL DX, r2+20(FP) + CALL runtime·exitsyscall(SB) + RET + TEXT ·RawSyscall(SB),NOSPLIT,$0-28 JMP syscall·RawSyscall(SB) -TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 +TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 JMP syscall·RawSyscall6(SB) +TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24 + MOVL trap+0(FP), AX // syscall entry + MOVL a1+4(FP), BX + MOVL a2+8(FP), CX + MOVL a3+12(FP), DX + MOVL $0, SI + MOVL $0, DI + INVOKE_SYSCALL + MOVL AX, r1+16(FP) + MOVL DX, r2+20(FP) + RET + TEXT ·socketcall(SB),NOSPLIT,$0-36 JMP syscall·socketcall(SB) diff --git a/vendor/golang.org/x/sys/unix/asm_linux_amd64.s b/vendor/golang.org/x/sys/unix/asm_linux_amd64.s index 44e25c62f9..c6468a9588 100644 --- a/vendor/golang.org/x/sys/unix/asm_linux_amd64.s +++ b/vendor/golang.org/x/sys/unix/asm_linux_amd64.s @@ -13,17 +13,45 @@ // Just jump to package syscall's implementation for all these functions. // The runtime may know about them. -TEXT ·Syscall(SB),NOSPLIT,$0-56 +TEXT ·Syscall(SB),NOSPLIT,$0-56 JMP syscall·Syscall(SB) TEXT ·Syscall6(SB),NOSPLIT,$0-80 JMP syscall·Syscall6(SB) +TEXT ·SyscallNoError(SB),NOSPLIT,$0-48 + CALL runtime·entersyscall(SB) + MOVQ a1+8(FP), DI + MOVQ a2+16(FP), SI + MOVQ a3+24(FP), DX + MOVQ $0, R10 + MOVQ $0, R8 + MOVQ $0, R9 + MOVQ trap+0(FP), AX // syscall entry + SYSCALL + MOVQ AX, r1+32(FP) + MOVQ DX, r2+40(FP) + CALL runtime·exitsyscall(SB) + RET + TEXT ·RawSyscall(SB),NOSPLIT,$0-56 JMP syscall·RawSyscall(SB) TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 JMP syscall·RawSyscall6(SB) +TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48 + MOVQ a1+8(FP), DI + MOVQ a2+16(FP), SI + MOVQ a3+24(FP), DX + MOVQ $0, R10 + MOVQ $0, R8 + MOVQ $0, R9 + MOVQ trap+0(FP), AX // syscall entry + SYSCALL + MOVQ AX, r1+32(FP) + MOVQ DX, r2+40(FP) + RET + TEXT ·gettimeofday(SB),NOSPLIT,$0-16 JMP syscall·gettimeofday(SB) diff --git a/vendor/golang.org/x/sys/unix/asm_linux_arm.s b/vendor/golang.org/x/sys/unix/asm_linux_arm.s index cf0b574658..cf0f3575c1 100644 --- a/vendor/golang.org/x/sys/unix/asm_linux_arm.s +++ b/vendor/golang.org/x/sys/unix/asm_linux_arm.s @@ -13,17 +13,44 @@ // Just jump to package syscall's implementation for all these functions. // The runtime may know about them. -TEXT ·Syscall(SB),NOSPLIT,$0-28 +TEXT ·Syscall(SB),NOSPLIT,$0-28 B syscall·Syscall(SB) -TEXT ·Syscall6(SB),NOSPLIT,$0-40 +TEXT ·Syscall6(SB),NOSPLIT,$0-40 B syscall·Syscall6(SB) +TEXT ·SyscallNoError(SB),NOSPLIT,$0-24 + BL runtime·entersyscall(SB) + MOVW trap+0(FP), R7 + MOVW a1+4(FP), R0 + MOVW a2+8(FP), R1 + MOVW a3+12(FP), R2 + MOVW $0, R3 + MOVW $0, R4 + MOVW $0, R5 + SWI $0 + MOVW R0, r1+16(FP) + MOVW $0, R0 + MOVW R0, r2+20(FP) + BL runtime·exitsyscall(SB) + RET + TEXT ·RawSyscall(SB),NOSPLIT,$0-28 B syscall·RawSyscall(SB) -TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 +TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 B syscall·RawSyscall6(SB) -TEXT ·seek(SB),NOSPLIT,$0-32 +TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24 + MOVW trap+0(FP), R7 // syscall entry + MOVW a1+4(FP), R0 + MOVW a2+8(FP), R1 + MOVW a3+12(FP), R2 + SWI $0 + MOVW R0, r1+16(FP) + MOVW $0, R0 + MOVW R0, r2+20(FP) + RET + +TEXT ·seek(SB),NOSPLIT,$0-28 B syscall·seek(SB) diff --git a/vendor/golang.org/x/sys/unix/asm_linux_arm64.s b/vendor/golang.org/x/sys/unix/asm_linux_arm64.s index 4be9bfedea..afe6fdf6b1 100644 --- a/vendor/golang.org/x/sys/unix/asm_linux_arm64.s +++ b/vendor/golang.org/x/sys/unix/asm_linux_arm64.s @@ -11,14 +11,42 @@ // Just jump to package syscall's implementation for all these functions. // The runtime may know about them. -TEXT ·Syscall(SB),NOSPLIT,$0-56 +TEXT ·Syscall(SB),NOSPLIT,$0-56 B syscall·Syscall(SB) TEXT ·Syscall6(SB),NOSPLIT,$0-80 B syscall·Syscall6(SB) +TEXT ·SyscallNoError(SB),NOSPLIT,$0-48 + BL runtime·entersyscall(SB) + MOVD a1+8(FP), R0 + MOVD a2+16(FP), R1 + MOVD a3+24(FP), R2 + MOVD $0, R3 + MOVD $0, R4 + MOVD $0, R5 + MOVD trap+0(FP), R8 // syscall entry + SVC + MOVD R0, r1+32(FP) // r1 + MOVD R1, r2+40(FP) // r2 + BL runtime·exitsyscall(SB) + RET + TEXT ·RawSyscall(SB),NOSPLIT,$0-56 B syscall·RawSyscall(SB) TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 B syscall·RawSyscall6(SB) + +TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48 + MOVD a1+8(FP), R0 + MOVD a2+16(FP), R1 + MOVD a3+24(FP), R2 + MOVD $0, R3 + MOVD $0, R4 + MOVD $0, R5 + MOVD trap+0(FP), R8 // syscall entry + SVC + MOVD R0, r1+32(FP) + MOVD R1, r2+40(FP) + RET diff --git a/vendor/golang.org/x/sys/unix/asm_linux_mips64x.s b/vendor/golang.org/x/sys/unix/asm_linux_mips64x.s index 724e580c4e..ab9d63831a 100644 --- a/vendor/golang.org/x/sys/unix/asm_linux_mips64x.s +++ b/vendor/golang.org/x/sys/unix/asm_linux_mips64x.s @@ -15,14 +15,42 @@ // Just jump to package syscall's implementation for all these functions. // The runtime may know about them. -TEXT ·Syscall(SB),NOSPLIT,$0-56 +TEXT ·Syscall(SB),NOSPLIT,$0-56 JMP syscall·Syscall(SB) -TEXT ·Syscall6(SB),NOSPLIT,$0-80 +TEXT ·Syscall6(SB),NOSPLIT,$0-80 JMP syscall·Syscall6(SB) -TEXT ·RawSyscall(SB),NOSPLIT,$0-56 +TEXT ·SyscallNoError(SB),NOSPLIT,$0-48 + JAL runtime·entersyscall(SB) + MOVV a1+8(FP), R4 + MOVV a2+16(FP), R5 + MOVV a3+24(FP), R6 + MOVV R0, R7 + MOVV R0, R8 + MOVV R0, R9 + MOVV trap+0(FP), R2 // syscall entry + SYSCALL + MOVV R2, r1+32(FP) + MOVV R3, r2+40(FP) + JAL runtime·exitsyscall(SB) + RET + +TEXT ·RawSyscall(SB),NOSPLIT,$0-56 JMP syscall·RawSyscall(SB) -TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 +TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 JMP syscall·RawSyscall6(SB) + +TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48 + MOVV a1+8(FP), R4 + MOVV a2+16(FP), R5 + MOVV a3+24(FP), R6 + MOVV R0, R7 + MOVV R0, R8 + MOVV R0, R9 + MOVV trap+0(FP), R2 // syscall entry + SYSCALL + MOVV R2, r1+32(FP) + MOVV R3, r2+40(FP) + RET diff --git a/vendor/golang.org/x/sys/unix/asm_linux_mipsx.s b/vendor/golang.org/x/sys/unix/asm_linux_mipsx.s index 2ea425755e..99e5399045 100644 --- a/vendor/golang.org/x/sys/unix/asm_linux_mipsx.s +++ b/vendor/golang.org/x/sys/unix/asm_linux_mipsx.s @@ -15,17 +15,40 @@ // Just jump to package syscall's implementation for all these functions. // The runtime may know about them. -TEXT ·Syscall(SB),NOSPLIT,$0-28 +TEXT ·Syscall(SB),NOSPLIT,$0-28 JMP syscall·Syscall(SB) -TEXT ·Syscall6(SB),NOSPLIT,$0-40 +TEXT ·Syscall6(SB),NOSPLIT,$0-40 JMP syscall·Syscall6(SB) -TEXT ·Syscall9(SB),NOSPLIT,$0-52 +TEXT ·Syscall9(SB),NOSPLIT,$0-52 JMP syscall·Syscall9(SB) -TEXT ·RawSyscall(SB),NOSPLIT,$0-28 +TEXT ·SyscallNoError(SB),NOSPLIT,$0-24 + JAL runtime·entersyscall(SB) + MOVW a1+4(FP), R4 + MOVW a2+8(FP), R5 + MOVW a3+12(FP), R6 + MOVW R0, R7 + MOVW trap+0(FP), R2 // syscall entry + SYSCALL + MOVW R2, r1+16(FP) // r1 + MOVW R3, r2+20(FP) // r2 + JAL runtime·exitsyscall(SB) + RET + +TEXT ·RawSyscall(SB),NOSPLIT,$0-28 JMP syscall·RawSyscall(SB) -TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 +TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 JMP syscall·RawSyscall6(SB) + +TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24 + MOVW a1+4(FP), R4 + MOVW a2+8(FP), R5 + MOVW a3+12(FP), R6 + MOVW trap+0(FP), R2 // syscall entry + SYSCALL + MOVW R2, r1+16(FP) + MOVW R3, r2+20(FP) + RET diff --git a/vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s b/vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s index 8d231feb4b..88f7125578 100644 --- a/vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s +++ b/vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s @@ -15,14 +15,30 @@ // Just jump to package syscall's implementation for all these functions. // The runtime may know about them. -TEXT ·Syscall(SB),NOSPLIT,$0-56 - BR syscall·Syscall(SB) +TEXT ·SyscallNoError(SB),NOSPLIT,$0-48 + BL runtime·entersyscall(SB) + MOVD a1+8(FP), R3 + MOVD a2+16(FP), R4 + MOVD a3+24(FP), R5 + MOVD R0, R6 + MOVD R0, R7 + MOVD R0, R8 + MOVD trap+0(FP), R9 // syscall entry + SYSCALL R9 + MOVD R3, r1+32(FP) + MOVD R4, r2+40(FP) + BL runtime·exitsyscall(SB) + RET -TEXT ·Syscall6(SB),NOSPLIT,$0-80 - BR syscall·Syscall6(SB) - -TEXT ·RawSyscall(SB),NOSPLIT,$0-56 - BR syscall·RawSyscall(SB) - -TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 - BR syscall·RawSyscall6(SB) +TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48 + MOVD a1+8(FP), R3 + MOVD a2+16(FP), R4 + MOVD a3+24(FP), R5 + MOVD R0, R6 + MOVD R0, R7 + MOVD R0, R8 + MOVD trap+0(FP), R9 // syscall entry + SYSCALL R9 + MOVD R3, r1+32(FP) + MOVD R4, r2+40(FP) + RET diff --git a/vendor/golang.org/x/sys/unix/asm_linux_s390x.s b/vendor/golang.org/x/sys/unix/asm_linux_s390x.s index 11889859fb..a5a863c6bd 100644 --- a/vendor/golang.org/x/sys/unix/asm_linux_s390x.s +++ b/vendor/golang.org/x/sys/unix/asm_linux_s390x.s @@ -21,8 +21,36 @@ TEXT ·Syscall(SB),NOSPLIT,$0-56 TEXT ·Syscall6(SB),NOSPLIT,$0-80 BR syscall·Syscall6(SB) +TEXT ·SyscallNoError(SB),NOSPLIT,$0-48 + BL runtime·entersyscall(SB) + MOVD a1+8(FP), R2 + MOVD a2+16(FP), R3 + MOVD a3+24(FP), R4 + MOVD $0, R5 + MOVD $0, R6 + MOVD $0, R7 + MOVD trap+0(FP), R1 // syscall entry + SYSCALL + MOVD R2, r1+32(FP) + MOVD R3, r2+40(FP) + BL runtime·exitsyscall(SB) + RET + TEXT ·RawSyscall(SB),NOSPLIT,$0-56 BR syscall·RawSyscall(SB) TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 BR syscall·RawSyscall6(SB) + +TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48 + MOVD a1+8(FP), R2 + MOVD a2+16(FP), R3 + MOVD a3+24(FP), R4 + MOVD $0, R5 + MOVD $0, R6 + MOVD $0, R7 + MOVD trap+0(FP), R1 // syscall entry + SYSCALL + MOVD R2, r1+32(FP) + MOVD R3, r2+40(FP) + RET diff --git a/vendor/golang.org/x/sys/unix/asm_netbsd_arm64.s b/vendor/golang.org/x/sys/unix/asm_netbsd_arm64.s new file mode 100644 index 0000000000..6f98ba5a37 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/asm_netbsd_arm64.s @@ -0,0 +1,29 @@ +// Copyright 2019 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 !gccgo + +#include "textflag.h" + +// +// System call support for ARM64, NetBSD +// + +// Just jump to package syscall's implementation for all these functions. +// The runtime may know about them. + +TEXT ·Syscall(SB),NOSPLIT,$0-56 + B syscall·Syscall(SB) + +TEXT ·Syscall6(SB),NOSPLIT,$0-80 + B syscall·Syscall6(SB) + +TEXT ·Syscall9(SB),NOSPLIT,$0-104 + B syscall·Syscall9(SB) + +TEXT ·RawSyscall(SB),NOSPLIT,$0-56 + B syscall·RawSyscall(SB) + +TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 + B syscall·RawSyscall6(SB) diff --git a/vendor/golang.org/x/sys/unix/cap_freebsd.go b/vendor/golang.org/x/sys/unix/cap_freebsd.go index 83b6bceab4..df52048773 100644 --- a/vendor/golang.org/x/sys/unix/cap_freebsd.go +++ b/vendor/golang.org/x/sys/unix/cap_freebsd.go @@ -7,7 +7,7 @@ package unix import ( - errorspkg "errors" + "errors" "fmt" ) @@ -60,26 +60,26 @@ func CapRightsSet(rights *CapRights, setrights []uint64) error { n := caparsize(rights) if n < capArSizeMin || n > capArSizeMax { - return errorspkg.New("bad rights size") + return errors.New("bad rights size") } for _, right := range setrights { if caprver(right) != CAP_RIGHTS_VERSION_00 { - return errorspkg.New("bad right version") + return errors.New("bad right version") } i, err := rightToIndex(right) if err != nil { return err } if i >= n { - return errorspkg.New("index overflow") + return errors.New("index overflow") } if capidxbit(rights.Rights[i]) != capidxbit(right) { - return errorspkg.New("index mismatch") + return errors.New("index mismatch") } rights.Rights[i] |= right if capidxbit(rights.Rights[i]) != capidxbit(right) { - return errorspkg.New("index mismatch (after assign)") + return errors.New("index mismatch (after assign)") } } @@ -95,26 +95,26 @@ func CapRightsClear(rights *CapRights, clearrights []uint64) error { n := caparsize(rights) if n < capArSizeMin || n > capArSizeMax { - return errorspkg.New("bad rights size") + return errors.New("bad rights size") } for _, right := range clearrights { if caprver(right) != CAP_RIGHTS_VERSION_00 { - return errorspkg.New("bad right version") + return errors.New("bad right version") } i, err := rightToIndex(right) if err != nil { return err } if i >= n { - return errorspkg.New("index overflow") + return errors.New("index overflow") } if capidxbit(rights.Rights[i]) != capidxbit(right) { - return errorspkg.New("index mismatch") + return errors.New("index mismatch") } rights.Rights[i] &= ^(right & 0x01FFFFFFFFFFFFFF) if capidxbit(rights.Rights[i]) != capidxbit(right) { - return errorspkg.New("index mismatch (after assign)") + return errors.New("index mismatch (after assign)") } } @@ -130,22 +130,22 @@ func CapRightsIsSet(rights *CapRights, setrights []uint64) (bool, error) { n := caparsize(rights) if n < capArSizeMin || n > capArSizeMax { - return false, errorspkg.New("bad rights size") + return false, errors.New("bad rights size") } for _, right := range setrights { if caprver(right) != CAP_RIGHTS_VERSION_00 { - return false, errorspkg.New("bad right version") + return false, errors.New("bad right version") } i, err := rightToIndex(right) if err != nil { return false, err } if i >= n { - return false, errorspkg.New("index overflow") + return false, errors.New("index overflow") } if capidxbit(rights.Rights[i]) != capidxbit(right) { - return false, errorspkg.New("index mismatch") + return false, errors.New("index mismatch") } if (rights.Rights[i] & right) != right { return false, nil diff --git a/vendor/golang.org/x/sys/unix/constants.go b/vendor/golang.org/x/sys/unix/constants.go index a96f0ebc26..3a6ac648dd 100644 --- a/vendor/golang.org/x/sys/unix/constants.go +++ b/vendor/golang.org/x/sys/unix/constants.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 netbsd openbsd solaris +// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package unix diff --git a/vendor/golang.org/x/sys/unix/dev_aix_ppc.go b/vendor/golang.org/x/sys/unix/dev_aix_ppc.go new file mode 100644 index 0000000000..5e5fb45104 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/dev_aix_ppc.go @@ -0,0 +1,27 @@ +// 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 aix +// +build ppc + +// Functions to access/create device major and minor numbers matching the +// encoding used by AIX. + +package unix + +// Major returns the major component of a Linux device number. +func Major(dev uint64) uint32 { + return uint32((dev >> 16) & 0xffff) +} + +// Minor returns the minor component of a Linux device number. +func Minor(dev uint64) uint32 { + return uint32(dev & 0xffff) +} + +// Mkdev returns a Linux device number generated from the given major and minor +// components. +func Mkdev(major, minor uint32) uint64 { + return uint64(((major) << 16) | (minor)) +} diff --git a/vendor/golang.org/x/sys/unix/dev_aix_ppc64.go b/vendor/golang.org/x/sys/unix/dev_aix_ppc64.go new file mode 100644 index 0000000000..8b401244c4 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/dev_aix_ppc64.go @@ -0,0 +1,29 @@ +// 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 aix +// +build ppc64 + +// Functions to access/create device major and minor numbers matching the +// encoding used AIX. + +package unix + +// Major returns the major component of a Linux device number. +func Major(dev uint64) uint32 { + return uint32((dev & 0x3fffffff00000000) >> 32) +} + +// Minor returns the minor component of a Linux device number. +func Minor(dev uint64) uint32 { + return uint32((dev & 0x00000000ffffffff) >> 0) +} + +// Mkdev returns a Linux device number generated from the given major and minor +// components. +func Mkdev(major, minor uint32) uint64 { + var DEVNO64 uint64 + DEVNO64 = 0x8000000000000000 + return ((uint64(major) << 32) | (uint64(minor) & 0x00000000FFFFFFFF) | DEVNO64) +} diff --git a/vendor/golang.org/x/sys/unix/dirent.go b/vendor/golang.org/x/sys/unix/dirent.go index bd475812b7..4407c505a3 100644 --- a/vendor/golang.org/x/sys/unix/dirent.go +++ b/vendor/golang.org/x/sys/unix/dirent.go @@ -2,101 +2,16 @@ // 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 nacl netbsd openbsd solaris +// +build aix darwin dragonfly freebsd linux nacl netbsd openbsd solaris package unix -import "unsafe" - -// readInt returns the size-bytes unsigned integer in native byte order at offset off. -func readInt(b []byte, off, size uintptr) (u uint64, ok bool) { - if len(b) < int(off+size) { - return 0, false - } - if isBigEndian { - return readIntBE(b[off:], size), true - } - return readIntLE(b[off:], size), true -} - -func readIntBE(b []byte, size uintptr) uint64 { - switch size { - case 1: - return uint64(b[0]) - case 2: - _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[1]) | uint64(b[0])<<8 - case 4: - _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[3]) | uint64(b[2])<<8 | uint64(b[1])<<16 | uint64(b[0])<<24 - case 8: - _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | - uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 - default: - panic("syscall: readInt with unsupported size") - } -} - -func readIntLE(b []byte, size uintptr) uint64 { - switch size { - case 1: - return uint64(b[0]) - case 2: - _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[0]) | uint64(b[1])<<8 - case 4: - _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 - case 8: - _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 - return 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 - default: - panic("syscall: readInt with unsupported size") - } -} +import "syscall" // ParseDirent parses up to max directory entries in buf, // appending the names to names. It returns the number of // bytes consumed from buf, the number of entries added // to names, and the new names slice. func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) { - origlen := len(buf) - count = 0 - for max != 0 && len(buf) > 0 { - reclen, ok := direntReclen(buf) - if !ok || reclen > uint64(len(buf)) { - return origlen, count, names - } - rec := buf[:reclen] - buf = buf[reclen:] - ino, ok := direntIno(rec) - if !ok { - break - } - if ino == 0 { // File absent in directory. - continue - } - const namoff = uint64(unsafe.Offsetof(Dirent{}.Name)) - namlen, ok := direntNamlen(rec) - if !ok || namoff+namlen > uint64(len(rec)) { - break - } - name := rec[namoff : namoff+namlen] - for i, c := range name { - if c == 0 { - name = name[:i] - break - } - } - // Check for useless names before allocating a string. - if string(name) == "." || string(name) == ".." { - continue - } - max-- - count++ - names = append(names, string(name)) - } - return origlen - len(buf), count, names + return syscall.ParseDirent(buf, max, names) } diff --git a/vendor/golang.org/x/sys/unix/env_unix.go b/vendor/golang.org/x/sys/unix/env_unix.go index 2e06b33f2e..84178b0a13 100644 --- a/vendor/golang.org/x/sys/unix/env_unix.go +++ b/vendor/golang.org/x/sys/unix/env_unix.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 netbsd openbsd solaris +// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris // Unix environment variables. @@ -25,3 +25,7 @@ func Clearenv() { func Environ() []string { return syscall.Environ() } + +func Unsetenv(key string) error { + return syscall.Unsetenv(key) +} diff --git a/vendor/golang.org/x/sys/unix/env_unset.go b/vendor/golang.org/x/sys/unix/env_unset.go deleted file mode 100644 index c44fdc4afa..0000000000 --- a/vendor/golang.org/x/sys/unix/env_unset.go +++ /dev/null @@ -1,14 +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 unix - -import "syscall" - -func Unsetenv(key string) error { - // This was added in Go 1.4. - return syscall.Unsetenv(key) -} diff --git a/vendor/golang.org/x/sys/unix/flock.go b/vendor/golang.org/x/sys/unix/fcntl.go similarity index 65% rename from vendor/golang.org/x/sys/unix/flock.go rename to vendor/golang.org/x/sys/unix/fcntl.go index 2994ce75f2..39c03f1ef1 100644 --- a/vendor/golang.org/x/sys/unix/flock.go +++ b/vendor/golang.org/x/sys/unix/fcntl.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 netbsd openbsd +// +build dragonfly freebsd linux netbsd openbsd package unix @@ -12,6 +12,16 @@ import "unsafe" // systems by flock_linux_32bit.go to be SYS_FCNTL64. var fcntl64Syscall uintptr = SYS_FCNTL +// FcntlInt performs a fcntl syscall on fd with the provided command and argument. +func FcntlInt(fd uintptr, cmd, arg int) (int, error) { + valptr, _, errno := Syscall(fcntl64Syscall, fd, uintptr(cmd), uintptr(arg)) + var err error + if errno != 0 { + err = errno + } + return int(valptr), err +} + // FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command. func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error { _, _, errno := Syscall(fcntl64Syscall, fd, uintptr(cmd), uintptr(unsafe.Pointer(lk))) diff --git a/vendor/golang.org/x/sys/unix/fcntl_darwin.go b/vendor/golang.org/x/sys/unix/fcntl_darwin.go new file mode 100644 index 0000000000..5868a4a47b --- /dev/null +++ b/vendor/golang.org/x/sys/unix/fcntl_darwin.go @@ -0,0 +1,18 @@ +// Copyright 2019 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 unix + +import "unsafe" + +// FcntlInt performs a fcntl syscall on fd with the provided command and argument. +func FcntlInt(fd uintptr, cmd, arg int) (int, error) { + return fcntl(int(fd), cmd, arg) +} + +// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command. +func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error { + _, err := fcntl(int(fd), cmd, int(uintptr(unsafe.Pointer(lk)))) + return err +} diff --git a/vendor/golang.org/x/sys/unix/flock_linux_32bit.go b/vendor/golang.org/x/sys/unix/fcntl_linux_32bit.go similarity index 100% rename from vendor/golang.org/x/sys/unix/flock_linux_32bit.go rename to vendor/golang.org/x/sys/unix/fcntl_linux_32bit.go diff --git a/vendor/golang.org/x/sys/unix/gccgo.go b/vendor/golang.org/x/sys/unix/gccgo.go index 40bed3fa80..cd6f5a6133 100644 --- a/vendor/golang.org/x/sys/unix/gccgo.go +++ b/vendor/golang.org/x/sys/unix/gccgo.go @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. // +build gccgo +// +build !aix package unix @@ -11,9 +12,19 @@ import "syscall" // We can't use the gc-syntax .s files for gccgo. On the plus side // much of the functionality can be written directly in Go. +//extern gccgoRealSyscallNoError +func realSyscallNoError(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r uintptr) + //extern gccgoRealSyscall func realSyscall(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r, errno uintptr) +func SyscallNoError(trap, a1, a2, a3 uintptr) (r1, r2 uintptr) { + syscall.Entersyscall() + r := realSyscallNoError(trap, a1, a2, a3, 0, 0, 0, 0, 0, 0) + syscall.Exitsyscall() + return r, 0 +} + func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) { syscall.Entersyscall() r, errno := realSyscall(trap, a1, a2, a3, 0, 0, 0, 0, 0, 0) @@ -35,6 +46,11 @@ func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, return r, 0, syscall.Errno(errno) } +func RawSyscallNoError(trap, a1, a2, a3 uintptr) (r1, r2 uintptr) { + r := realSyscallNoError(trap, a1, a2, a3, 0, 0, 0, 0, 0, 0) + return r, 0 +} + func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) { r, errno := realSyscall(trap, a1, a2, a3, 0, 0, 0, 0, 0, 0) return r, 0, syscall.Errno(errno) diff --git a/vendor/golang.org/x/sys/unix/gccgo_c.c b/vendor/golang.org/x/sys/unix/gccgo_c.c index 99a774f2be..c44730c5e9 100644 --- a/vendor/golang.org/x/sys/unix/gccgo_c.c +++ b/vendor/golang.org/x/sys/unix/gccgo_c.c @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. // +build gccgo +// +build !aix #include #include @@ -31,11 +32,8 @@ gccgoRealSyscall(uintptr_t trap, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintp return r; } -// Define the use function in C so that it is not inlined. - -extern void use(void *) __asm__ (GOSYM_PREFIX GOPKGPATH ".use") __attribute__((noinline)); - -void -use(void *p __attribute__ ((unused))) +uintptr_t +gccgoRealSyscallNoError(uintptr_t trap, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6, uintptr_t a7, uintptr_t a8, uintptr_t a9) { + return syscall(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9); } diff --git a/vendor/golang.org/x/sys/unix/ioctl.go b/vendor/golang.org/x/sys/unix/ioctl.go new file mode 100644 index 0000000000..f121a8d64b --- /dev/null +++ b/vendor/golang.org/x/sys/unix/ioctl.go @@ -0,0 +1,30 @@ +// 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 aix darwin dragonfly freebsd linux netbsd openbsd solaris + +package unix + +import "runtime" + +// IoctlSetWinsize performs an ioctl on fd with a *Winsize argument. +// +// To change fd's window size, the req argument should be TIOCSWINSZ. +func IoctlSetWinsize(fd int, req uint, value *Winsize) error { + // TODO: if we get the chance, remove the req parameter and + // hardcode TIOCSWINSZ. + err := ioctlSetWinsize(fd, req, value) + runtime.KeepAlive(value) + return err +} + +// IoctlSetTermios performs an ioctl on fd with a *Termios. +// +// The req value will usually be TCSETA or TIOCSETA. +func IoctlSetTermios(fd int, req uint, value *Termios) error { + // TODO: if we get the chance, remove the req parameter. + err := ioctlSetTermios(fd, req, value) + runtime.KeepAlive(value) + return err +} diff --git a/vendor/golang.org/x/sys/unix/mkall.sh b/vendor/golang.org/x/sys/unix/mkall.sh index 00b7ce7ac1..75152f99b2 100755 --- a/vendor/golang.org/x/sys/unix/mkall.sh +++ b/vendor/golang.org/x/sys/unix/mkall.sh @@ -10,13 +10,14 @@ GOOSARCH="${GOOS}_${GOARCH}" # defaults -mksyscall="./mksyscall.pl" +mksyscall="go run mksyscall.go" mkerrors="./mkerrors.sh" zerrors="zerrors_$GOOSARCH.go" mksysctl="" zsysctl="zsysctl_$GOOSARCH.go" mksysnum= mktypes= +mkasm= run="sh" cmd="" @@ -45,8 +46,8 @@ case "$#" in exit 2 esac -if [[ "$GOOS" = "linux" ]] && [[ "$GOARCH" != "sparc64" ]]; then - # Use then new build system +if [[ "$GOOS" = "linux" ]]; then + # Use the Docker-based build system # Files generated through docker (use $cmd so you can Ctl-C the build or run) $cmd docker build --tag generate:$GOOS $GOOS $cmd docker run --interactive --tty --volume $(dirname "$(readlink -f "$0")"):/build generate:$GOOS @@ -59,110 +60,117 @@ _* | *_ | _) echo 'undefined $GOOS_$GOARCH:' "$GOOSARCH" 1>&2 exit 1 ;; +aix_ppc) + mkerrors="$mkerrors -maix32" + mksyscall="go run mksyscall_aix_ppc.go -aix" + mktypes="GOARCH=$GOARCH go tool cgo -godefs" + ;; +aix_ppc64) + mkerrors="$mkerrors -maix64" + mksyscall="go run mksyscall_aix_ppc64.go -aix" + mktypes="GOARCH=$GOARCH go tool cgo -godefs" + ;; darwin_386) mkerrors="$mkerrors -m32" - mksyscall="./mksyscall.pl -l32" - mksysnum="./mksysnum_darwin.pl $(xcrun --show-sdk-path --sdk macosx)/usr/include/sys/syscall.h" + mksyscall="go run mksyscall.go -l32" + mksysnum="go run mksysnum.go $(xcrun --show-sdk-path --sdk macosx)/usr/include/sys/syscall.h" mktypes="GOARCH=$GOARCH go tool cgo -godefs" + mkasm="go run mkasm_darwin.go" ;; darwin_amd64) mkerrors="$mkerrors -m64" - mksysnum="./mksysnum_darwin.pl $(xcrun --show-sdk-path --sdk macosx)/usr/include/sys/syscall.h" + mksysnum="go run mksysnum.go $(xcrun --show-sdk-path --sdk macosx)/usr/include/sys/syscall.h" mktypes="GOARCH=$GOARCH go tool cgo -godefs" + mkasm="go run mkasm_darwin.go" ;; darwin_arm) mkerrors="$mkerrors" - mksysnum="./mksysnum_darwin.pl $(xcrun --show-sdk-path --sdk iphoneos)/usr/include/sys/syscall.h" + mksyscall="go run mksyscall.go -l32" + mksysnum="go run mksysnum.go $(xcrun --show-sdk-path --sdk iphoneos)/usr/include/sys/syscall.h" mktypes="GOARCH=$GOARCH go tool cgo -godefs" + mkasm="go run mkasm_darwin.go" ;; darwin_arm64) mkerrors="$mkerrors -m64" - mksysnum="./mksysnum_darwin.pl $(xcrun --show-sdk-path --sdk iphoneos)/usr/include/sys/syscall.h" - mktypes="GOARCH=$GOARCH go tool cgo -godefs" - ;; -dragonfly_386) - mkerrors="$mkerrors -m32" - mksyscall="./mksyscall.pl -l32 -dragonfly" - mksysnum="curl -s 'http://gitweb.dragonflybsd.org/dragonfly.git/blob_plain/HEAD:/sys/kern/syscalls.master' | ./mksysnum_dragonfly.pl" + mksysnum="go run mksysnum.go $(xcrun --show-sdk-path --sdk iphoneos)/usr/include/sys/syscall.h" mktypes="GOARCH=$GOARCH go tool cgo -godefs" + mkasm="go run mkasm_darwin.go" ;; dragonfly_amd64) mkerrors="$mkerrors -m64" - mksyscall="./mksyscall.pl -dragonfly" - mksysnum="curl -s 'http://gitweb.dragonflybsd.org/dragonfly.git/blob_plain/HEAD:/sys/kern/syscalls.master' | ./mksysnum_dragonfly.pl" + mksyscall="go run mksyscall.go -dragonfly" + mksysnum="go run mksysnum.go 'https://gitweb.dragonflybsd.org/dragonfly.git/blob_plain/HEAD:/sys/kern/syscalls.master'" mktypes="GOARCH=$GOARCH go tool cgo -godefs" ;; freebsd_386) mkerrors="$mkerrors -m32" - mksyscall="./mksyscall.pl -l32" - mksysnum="curl -s 'http://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl" + mksyscall="go run mksyscall.go -l32" + mksysnum="go run mksysnum.go 'https://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master'" mktypes="GOARCH=$GOARCH go tool cgo -godefs" ;; freebsd_amd64) mkerrors="$mkerrors -m64" - mksysnum="curl -s 'http://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl" + mksysnum="go run mksysnum.go 'https://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master'" mktypes="GOARCH=$GOARCH go tool cgo -godefs" ;; freebsd_arm) mkerrors="$mkerrors" - mksyscall="./mksyscall.pl -l32 -arm" - mksysnum="curl -s 'http://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl" + mksyscall="go run mksyscall.go -l32 -arm" + mksysnum="go run mksysnum.go 'https://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master'" # Let the type of C char be signed for making the bare syscall # API consistent across platforms. mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char" ;; -linux_sparc64) - GOOSARCH_in=syscall_linux_sparc64.go - unistd_h=/usr/include/sparc64-linux-gnu/asm/unistd.h +freebsd_arm64) mkerrors="$mkerrors -m64" - mksysnum="./mksysnum_linux.pl $unistd_h" + mksysnum="go run mksysnum.go 'https://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master'" mktypes="GOARCH=$GOARCH go tool cgo -godefs" ;; netbsd_386) mkerrors="$mkerrors -m32" - mksyscall="./mksyscall.pl -l32 -netbsd" - mksysnum="curl -s 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_netbsd.pl" + mksyscall="go run mksyscall.go -l32 -netbsd" + mksysnum="go run mksysnum.go 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master'" mktypes="GOARCH=$GOARCH go tool cgo -godefs" ;; netbsd_amd64) mkerrors="$mkerrors -m64" - mksyscall="./mksyscall.pl -netbsd" - mksysnum="curl -s 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_netbsd.pl" + mksyscall="go run mksyscall.go -netbsd" + mksysnum="go run mksysnum.go 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master'" mktypes="GOARCH=$GOARCH go tool cgo -godefs" ;; netbsd_arm) mkerrors="$mkerrors" - mksyscall="./mksyscall.pl -l32 -netbsd -arm" - mksysnum="curl -s 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_netbsd.pl" + mksyscall="go run mksyscall.go -l32 -netbsd -arm" + mksysnum="go run mksysnum.go 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master'" # Let the type of C char be signed for making the bare syscall # API consistent across platforms. mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char" ;; openbsd_386) mkerrors="$mkerrors -m32" - mksyscall="./mksyscall.pl -l32 -openbsd" + mksyscall="go run mksyscall.go -l32 -openbsd" mksysctl="./mksysctl_openbsd.pl" - mksysnum="curl -s 'http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_openbsd.pl" + mksysnum="go run mksysnum.go 'https://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master'" mktypes="GOARCH=$GOARCH go tool cgo -godefs" ;; openbsd_amd64) mkerrors="$mkerrors -m64" - mksyscall="./mksyscall.pl -openbsd" + mksyscall="go run mksyscall.go -openbsd" mksysctl="./mksysctl_openbsd.pl" - mksysnum="curl -s 'http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_openbsd.pl" + mksysnum="go run mksysnum.go 'https://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master'" mktypes="GOARCH=$GOARCH go tool cgo -godefs" ;; openbsd_arm) mkerrors="$mkerrors" - mksyscall="./mksyscall.pl -l32 -openbsd -arm" + mksyscall="go run mksyscall.go -l32 -openbsd -arm" mksysctl="./mksysctl_openbsd.pl" - mksysnum="curl -s 'http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_openbsd.pl" + mksysnum="go run mksysnum.go 'https://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master'" # Let the type of C char be signed for making the bare syscall # API consistent across platforms. mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char" ;; solaris_amd64) - mksyscall="./mksyscall_solaris.pl" + mksyscall="go run mksyscall_solaris.go" mkerrors="$mkerrors -m64" mksysnum= mktypes="GOARCH=$GOARCH go tool cgo -godefs" @@ -183,12 +191,24 @@ esac syscall_goos="syscall_bsd.go $syscall_goos" ;; esac - if [ -n "$mksyscall" ]; then echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go"; fi - ;; + if [ -n "$mksyscall" ]; then + if [ "$GOOSARCH" == "aix_ppc64" ]; then + # aix/ppc64 script generates files instead of writing to stdin. + echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in && gofmt -w zsyscall_$GOOSARCH.go && gofmt -w zsyscall_"$GOOSARCH"_gccgo.go && gofmt -w zsyscall_"$GOOSARCH"_gc.go " ; + elif [ "$GOOS" == "darwin" ]; then + # pre-1.12, direct syscalls + echo "$mksyscall -tags $GOOS,$GOARCH,!go1.12 $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.1_11.go"; + # 1.12 and later, syscalls via libSystem + echo "$mksyscall -tags $GOOS,$GOARCH,go1.12 $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go"; + else + echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go"; + fi + fi esac if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.go | go run mkpost.go > ztypes_$GOOSARCH.go"; + if [ -n "$mkasm" ]; then echo "$mkasm $GOARCH"; fi fi ) | $run diff --git a/vendor/golang.org/x/sys/unix/mkerrors.sh b/vendor/golang.org/x/sys/unix/mkerrors.sh index 2db9e0adce..6a23484e5b 100755 --- a/vendor/golang.org/x/sys/unix/mkerrors.sh +++ b/vendor/golang.org/x/sys/unix/mkerrors.sh @@ -17,15 +17,17 @@ if test -z "$GOARCH" -o -z "$GOOS"; then fi # Check that we are using the new build system if we should -if [[ "$GOOS" = "linux" ]] && [[ "$GOARCH" != "sparc64" ]]; then - if [[ "$GOLANG_SYS_BUILD" != "docker" ]]; then - echo 1>&2 "In the new build system, mkerrors should not be called directly." - echo 1>&2 "See README.md" - exit 1 - fi +if [[ "$GOOS" = "linux" ]] && [[ "$GOLANG_SYS_BUILD" != "docker" ]]; then + echo 1>&2 "In the Docker based build system, mkerrors should not be called directly." + echo 1>&2 "See README.md" + exit 1 fi -CC=${CC:-cc} +if [[ "$GOOS" = "aix" ]]; then + CC=${CC:-gcc} +else + CC=${CC:-cc} +fi if [[ "$GOOS" = "solaris" ]]; then # Assumes GNU versions of utilities in PATH. @@ -34,6 +36,21 @@ fi uname=$(uname) +includes_AIX=' +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define AF_LOCAL AF_UNIX +' + includes_Darwin=' #define _DARWIN_C_SOURCE #define KERNEL @@ -48,7 +65,9 @@ includes_Darwin=' #include #include #include +#include #include +#include #include #include #include @@ -63,8 +82,10 @@ includes_DragonFly=' #include #include #include +#include #include #include +#include #include #include #include @@ -78,12 +99,13 @@ includes_DragonFly=' ' includes_FreeBSD=' -#include +#include #include #include #include #include #include +#include #include #include #include @@ -157,20 +179,29 @@ struct ltchars { #include #include #include +#include #include #include +#include #include #include #include #include +#include #include #include #include #include #include #include +#include #include +#include +#include +#include +#include #include +#include #include #include #include @@ -187,8 +218,20 @@ struct ltchars { #include #include #include +#include +#include +#include +#include #include + +#if defined(__sparc__) +// On sparc{,64}, the kernel defines struct termios2 itself which clashes with the +// definition in glibc. As only the error constants are needed here, include the +// generic termibits.h (which is included by termbits.h on sparc). +#include +#else #include +#endif #ifndef MSG_FASTOPEN #define MSG_FASTOPEN 0x20000000 @@ -222,7 +265,9 @@ includes_NetBSD=' #include #include #include +#include #include +#include #include #include #include @@ -248,11 +293,14 @@ includes_OpenBSD=' #include #include #include +#include #include #include +#include #include #include #include +#include #include #include #include @@ -284,6 +332,7 @@ includes_SunOS=' #include #include #include +#include #include #include #include @@ -346,6 +395,7 @@ ccflags="$@" $2 ~ /^EXTATTR_NAMESPACE_NAMES/ || $2 ~ /^EXTATTR_NAMESPACE_[A-Z]+_STRING/ {next} + $2 !~ /^ECCAPBITS/ && $2 !~ /^ETH_/ && $2 !~ /^EPROC_/ && $2 !~ /^EQUIV_/ && @@ -362,6 +412,7 @@ ccflags="$@" $2 ~ /^IGN/ || $2 ~ /^IX(ON|ANY|OFF)$/ || $2 ~ /^IN(LCR|PCK)$/ || + $2 !~ "X86_CR3_PCID_NOFLUSH" && $2 ~ /(^FLU?SH)|(FLU?SH$)/ || $2 ~ /^C(LOCAL|READ|MSPAR|RTSCTS)$/ || $2 == "BRKINT" || @@ -380,21 +431,27 @@ ccflags="$@" $2 ~ /^TC[IO](ON|OFF)$/ || $2 ~ /^IN_/ || $2 ~ /^LOCK_(SH|EX|NB|UN)$/ || - $2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|ICMP6|TCP|EVFILT|NOTE|EV|SHUT|PROT|MAP|PACKET|MSG|SCM|MCL|DT|MADV|PR)_/ || + $2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|ICMP6|TCP|EVFILT|NOTE|EV|SHUT|PROT|MAP|MFD|T?PACKET|MSG|SCM|MCL|DT|MADV|PR)_/ || + $2 ~ /^TP_STATUS_/ || $2 ~ /^FALLOC_/ || $2 == "ICMPV6_FILTER" || $2 == "SOMAXCONN" || $2 == "NAME_MAX" || $2 == "IFNAMSIZ" || - $2 ~ /^CTL_(MAXNAME|NET|QUERY)$/ || + $2 ~ /^CTL_(HW|KERN|MAXNAME|NET|QUERY)$/ || + $2 ~ /^KERN_(HOSTNAME|OS(RELEASE|TYPE)|VERSION)$/ || + $2 ~ /^HW_MACHINE$/ || $2 ~ /^SYSCTL_VERS/ || + $2 !~ "MNT_BITS" && $2 ~ /^(MS|MNT|UMOUNT)_/ || $2 ~ /^TUN(SET|GET|ATTACH|DETACH)/ || - $2 ~ /^(O|F|E?FD|NAME|S|PTRACE|PT)_/ || + $2 ~ /^(O|F|[ES]?FD|NAME|S|PTRACE|PT)_/ || + $2 ~ /^KEXEC_/ || $2 ~ /^LINUX_REBOOT_CMD_/ || $2 ~ /^LINUX_REBOOT_MAGIC[12]$/ || + $2 ~ /^MODULE_INIT_/ || $2 !~ "NLA_TYPE_MASK" && - $2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|IFAN|RT|RTCF|RTN|RTPROT|RTNH|ARPHRD|ETH_P)_/ || + $2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|IFAN|RT|RTC|RTCF|RTN|RTPROT|RTNH|ARPHRD|ETH_P|NETNSA)_/ || $2 ~ /^SIOC/ || $2 ~ /^TIOC/ || $2 ~ /^TCGET/ || @@ -409,28 +466,41 @@ ccflags="$@" $2 ~ /^CLONE_[A-Z_]+/ || $2 !~ /^(BPF_TIMEVAL)$/ && $2 ~ /^(BPF|DLT)_/ || - $2 ~ /^CLOCK_/ || + $2 ~ /^(CLOCK|TIMER)_/ || $2 ~ /^CAN_/ || $2 ~ /^CAP_/ || $2 ~ /^ALG_/ || $2 ~ /^FS_(POLICY_FLAGS|KEY_DESC|ENCRYPTION_MODE|[A-Z0-9_]+_KEY_SIZE|IOC_(GET|SET)_ENCRYPTION)/ || $2 ~ /^GRND_/ || + $2 ~ /^RND/ || $2 ~ /^KEY_(SPEC|REQKEY_DEFL)_/ || $2 ~ /^KEYCTL_/ || $2 ~ /^PERF_EVENT_IOC_/ || $2 ~ /^SECCOMP_MODE_/ || $2 ~ /^SPLICE_/ || + $2 ~ /^SYNC_FILE_RANGE_/ || + $2 !~ /^AUDIT_RECORD_MAGIC/ && + $2 !~ /IOC_MAGIC/ && + $2 ~ /^[A-Z][A-Z0-9_]+_MAGIC2?$/ || $2 ~ /^(VM|VMADDR)_/ || $2 ~ /^IOCTL_VM_SOCKETS_/ || $2 ~ /^(TASKSTATS|TS)_/ || + $2 ~ /^CGROUPSTATS_/ || $2 ~ /^GENL_/ || + $2 ~ /^STATX_/ || + $2 ~ /^RENAME/ || + $2 ~ /^UBI_IOC[A-Z]/ || $2 ~ /^UTIME_/ || - $2 ~ /^XATTR_(CREATE|REPLACE)/ || + $2 ~ /^XATTR_(CREATE|REPLACE|NO(DEFAULT|FOLLOW|SECURITY)|SHOWCOMPRESSION)/ || $2 ~ /^ATTR_(BIT_MAP_COUNT|(CMN|VOL|FILE)_)/ || $2 ~ /^FSOPT_/ || $2 ~ /^WDIOC_/ || + $2 ~ /^NFN/ || + $2 ~ /^XDP_/ || + $2 ~ /^(HDIO|WIN|SMART)_/ || $2 !~ "WMESGLEN" && $2 ~ /^W[A-Z0-9]+$/ || + $2 ~/^PPPIOC/ || $2 ~ /^BLK[A-Z]*(GET$|SET$|BUF$|PART$|SIZE)/ {printf("\t%s = C.%s\n", $2, $2)} $2 ~ /^__WCOREFLAG$/ {next} $2 ~ /^__W[A-Z0-9]+$/ {printf("\t%s = C.%s\n", substr($2,3), $2)} @@ -452,7 +522,7 @@ errors=$( signals=$( echo '#include ' | $CC -x c - -E -dM $ccflags | awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print $2 }' | - egrep -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT)' | + egrep -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT|SIGMAX64)' | sort ) @@ -462,7 +532,7 @@ echo '#include ' | $CC -x c - -E -dM $ccflags | sort >_error.grep echo '#include ' | $CC -x c - -E -dM $ccflags | awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print "^\t" $2 "[ \t]*=" }' | - egrep -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT)' | + egrep -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT|SIGMAX64)' | sort >_signal.grep echo '// mkerrors.sh' "$@" @@ -498,21 +568,26 @@ echo ')' enum { A = 'A', Z = 'Z', a = 'a', z = 'z' }; // avoid need for single quotes below -int errors[] = { +struct tuple { + int num; + const char *name; +}; + +struct tuple errors[] = { " for i in $errors do - echo -E ' '$i, + echo -E ' {'$i', "'$i'" },' done echo -E " }; -int signals[] = { +struct tuple signals[] = { " for i in $signals do - echo -E ' '$i, + echo -E ' {'$i', "'$i'" },' done # Use -E because on some systems bash builtin interprets \n itself. @@ -520,9 +595,9 @@ int signals[] = { }; static int -intcmp(const void *a, const void *b) +tuplecmp(const void *a, const void *b) { - return *(int*)a - *(int*)b; + return ((struct tuple *)a)->num - ((struct tuple *)b)->num; } int @@ -532,26 +607,34 @@ main(void) char buf[1024], *p; printf("\n\n// Error table\n"); - printf("var errors = [...]string {\n"); - qsort(errors, nelem(errors), sizeof errors[0], intcmp); + printf("var errorList = [...]struct {\n"); + printf("\tnum syscall.Errno\n"); + printf("\tname string\n"); + printf("\tdesc string\n"); + printf("} {\n"); + qsort(errors, nelem(errors), sizeof errors[0], tuplecmp); for(i=0; i 0 && errors[i-1] == e) + e = errors[i].num; + if(i > 0 && errors[i-1].num == e) continue; strcpy(buf, strerror(e)); // lowercase first letter: Bad -> bad, but STREAM -> STREAM. if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z) buf[0] += a - A; - printf("\t%d: \"%s\",\n", e, buf); + printf("\t{ %d, \"%s\", \"%s\" },\n", e, errors[i].name, buf); } printf("}\n\n"); printf("\n\n// Signal table\n"); - printf("var signals = [...]string {\n"); - qsort(signals, nelem(signals), sizeof signals[0], intcmp); + printf("var signalList = [...]struct {\n"); + printf("\tnum syscall.Signal\n"); + printf("\tname string\n"); + printf("\tdesc string\n"); + printf("} {\n"); + qsort(signals, nelem(signals), sizeof signals[0], tuplecmp); for(i=0; i 0 && signals[i-1] == e) + e = signals[i].num; + if(i > 0 && signals[i-1].num == e) continue; strcpy(buf, strsignal(e)); // lowercase first letter: Bad -> bad, but STREAM -> STREAM. @@ -561,7 +644,7 @@ main(void) p = strrchr(buf, ":"[0]); if(p) *p = '\0'; - printf("\t%d: \"%s\",\n", e, buf); + printf("\t{ %d, \"%s\", \"%s\" },\n", e, signals[i].name, buf); } printf("}\n\n"); diff --git a/vendor/golang.org/x/sys/unix/mksyscall.pl b/vendor/golang.org/x/sys/unix/mksyscall.pl deleted file mode 100755 index fb929b4ce1..0000000000 --- a/vendor/golang.org/x/sys/unix/mksyscall.pl +++ /dev/null @@ -1,328 +0,0 @@ -#!/usr/bin/env perl -# Copyright 2009 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. - -# This program reads a file containing function prototypes -# (like syscall_darwin.go) and generates system call bodies. -# The prototypes are marked by lines beginning with "//sys" -# and read like func declarations if //sys is replaced by func, but: -# * The parameter lists must give a name for each argument. -# This includes return parameters. -# * The parameter lists must give a type for each argument: -# the (x, y, z int) shorthand is not allowed. -# * If the return parameter is an error number, it must be named errno. - -# A line beginning with //sysnb is like //sys, except that the -# goroutine will not be suspended during the execution of the system -# call. This must only be used for system calls which can never -# block, as otherwise the system call could cause all goroutines to -# hang. - -use strict; - -my $cmdline = "mksyscall.pl " . join(' ', @ARGV); -my $errors = 0; -my $_32bit = ""; -my $plan9 = 0; -my $openbsd = 0; -my $netbsd = 0; -my $dragonfly = 0; -my $arm = 0; # 64-bit value should use (even, odd)-pair -my $tags = ""; # build tags - -if($ARGV[0] eq "-b32") { - $_32bit = "big-endian"; - shift; -} elsif($ARGV[0] eq "-l32") { - $_32bit = "little-endian"; - shift; -} -if($ARGV[0] eq "-plan9") { - $plan9 = 1; - shift; -} -if($ARGV[0] eq "-openbsd") { - $openbsd = 1; - shift; -} -if($ARGV[0] eq "-netbsd") { - $netbsd = 1; - shift; -} -if($ARGV[0] eq "-dragonfly") { - $dragonfly = 1; - shift; -} -if($ARGV[0] eq "-arm") { - $arm = 1; - shift; -} -if($ARGV[0] eq "-tags") { - shift; - $tags = $ARGV[0]; - shift; -} - -if($ARGV[0] =~ /^-/) { - print STDERR "usage: mksyscall.pl [-b32 | -l32] [-tags x,y] [file ...]\n"; - exit 1; -} - -# Check that we are using the new build system if we should -if($ENV{'GOOS'} eq "linux" && $ENV{'GOARCH'} ne "sparc64") { - if($ENV{'GOLANG_SYS_BUILD'} ne "docker") { - print STDERR "In the new build system, mksyscall should not be called directly.\n"; - print STDERR "See README.md\n"; - exit 1; - } -} - - -sub parseparamlist($) { - my ($list) = @_; - $list =~ s/^\s*//; - $list =~ s/\s*$//; - if($list eq "") { - return (); - } - return split(/\s*,\s*/, $list); -} - -sub parseparam($) { - my ($p) = @_; - if($p !~ /^(\S*) (\S*)$/) { - print STDERR "$ARGV:$.: malformed parameter: $p\n"; - $errors = 1; - return ("xx", "int"); - } - return ($1, $2); -} - -my $text = ""; -while(<>) { - chomp; - s/\s+/ /g; - s/^\s+//; - s/\s+$//; - my $nonblock = /^\/\/sysnb /; - next if !/^\/\/sys / && !$nonblock; - - # Line must be of the form - # func Open(path string, mode int, perm int) (fd int, errno error) - # Split into name, in params, out params. - if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*((?i)SYS_[A-Z0-9_]+))?$/) { - print STDERR "$ARGV:$.: malformed //sys declaration\n"; - $errors = 1; - next; - } - my ($func, $in, $out, $sysname) = ($2, $3, $4, $5); - - # Split argument lists on comma. - my @in = parseparamlist($in); - my @out = parseparamlist($out); - - # Try in vain to keep people from editing this file. - # The theory is that they jump into the middle of the file - # without reading the header. - $text .= "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n"; - - # Go function header. - my $out_decl = @out ? sprintf(" (%s)", join(', ', @out)) : ""; - $text .= sprintf "func %s(%s)%s {\n", $func, join(', ', @in), $out_decl; - - # Check if err return available - my $errvar = ""; - foreach my $p (@out) { - my ($name, $type) = parseparam($p); - if($type eq "error") { - $errvar = $name; - last; - } - } - - # Prepare arguments to Syscall. - my @args = (); - my $n = 0; - foreach my $p (@in) { - my ($name, $type) = parseparam($p); - if($type =~ /^\*/) { - push @args, "uintptr(unsafe.Pointer($name))"; - } elsif($type eq "string" && $errvar ne "") { - $text .= "\tvar _p$n *byte\n"; - $text .= "\t_p$n, $errvar = BytePtrFromString($name)\n"; - $text .= "\tif $errvar != nil {\n\t\treturn\n\t}\n"; - push @args, "uintptr(unsafe.Pointer(_p$n))"; - $n++; - } elsif($type eq "string") { - print STDERR "$ARGV:$.: $func uses string arguments, but has no error return\n"; - $text .= "\tvar _p$n *byte\n"; - $text .= "\t_p$n, _ = BytePtrFromString($name)\n"; - push @args, "uintptr(unsafe.Pointer(_p$n))"; - $n++; - } elsif($type =~ /^\[\](.*)/) { - # Convert slice into pointer, length. - # Have to be careful not to take address of &a[0] if len == 0: - # pass dummy pointer in that case. - # Used to pass nil, but some OSes or simulators reject write(fd, nil, 0). - $text .= "\tvar _p$n unsafe.Pointer\n"; - $text .= "\tif len($name) > 0 {\n\t\t_p$n = unsafe.Pointer(\&${name}[0])\n\t}"; - $text .= " else {\n\t\t_p$n = unsafe.Pointer(&_zero)\n\t}"; - $text .= "\n"; - push @args, "uintptr(_p$n)", "uintptr(len($name))"; - $n++; - } elsif($type eq "int64" && ($openbsd || $netbsd)) { - push @args, "0"; - if($_32bit eq "big-endian") { - push @args, "uintptr($name>>32)", "uintptr($name)"; - } elsif($_32bit eq "little-endian") { - push @args, "uintptr($name)", "uintptr($name>>32)"; - } else { - push @args, "uintptr($name)"; - } - } elsif($type eq "int64" && $dragonfly) { - if ($func !~ /^extp(read|write)/i) { - push @args, "0"; - } - if($_32bit eq "big-endian") { - push @args, "uintptr($name>>32)", "uintptr($name)"; - } elsif($_32bit eq "little-endian") { - push @args, "uintptr($name)", "uintptr($name>>32)"; - } else { - push @args, "uintptr($name)"; - } - } elsif($type eq "int64" && $_32bit ne "") { - if(@args % 2 && $arm) { - # arm abi specifies 64-bit argument uses - # (even, odd) pair - push @args, "0" - } - if($_32bit eq "big-endian") { - push @args, "uintptr($name>>32)", "uintptr($name)"; - } else { - push @args, "uintptr($name)", "uintptr($name>>32)"; - } - } else { - push @args, "uintptr($name)"; - } - } - - # Determine which form to use; pad args with zeros. - my $asm = "Syscall"; - if ($nonblock) { - $asm = "RawSyscall"; - } - if(@args <= 3) { - while(@args < 3) { - push @args, "0"; - } - } elsif(@args <= 6) { - $asm .= "6"; - while(@args < 6) { - push @args, "0"; - } - } elsif(@args <= 9) { - $asm .= "9"; - while(@args < 9) { - push @args, "0"; - } - } else { - print STDERR "$ARGV:$.: too many arguments to system call\n"; - } - - # System call number. - if($sysname eq "") { - $sysname = "SYS_$func"; - $sysname =~ s/([a-z])([A-Z])/${1}_$2/g; # turn FooBar into Foo_Bar - $sysname =~ y/a-z/A-Z/; - } - - # Actual call. - my $args = join(', ', @args); - my $call = "$asm($sysname, $args)"; - - # Assign return values. - my $body = ""; - my @ret = ("_", "_", "_"); - my $do_errno = 0; - for(my $i=0; $i<@out; $i++) { - my $p = $out[$i]; - my ($name, $type) = parseparam($p); - my $reg = ""; - if($name eq "err" && !$plan9) { - $reg = "e1"; - $ret[2] = $reg; - $do_errno = 1; - } elsif($name eq "err" && $plan9) { - $ret[0] = "r0"; - $ret[2] = "e1"; - next; - } else { - $reg = sprintf("r%d", $i); - $ret[$i] = $reg; - } - if($type eq "bool") { - $reg = "$reg != 0"; - } - if($type eq "int64" && $_32bit ne "") { - # 64-bit number in r1:r0 or r0:r1. - if($i+2 > @out) { - print STDERR "$ARGV:$.: not enough registers for int64 return\n"; - } - if($_32bit eq "big-endian") { - $reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i, $i+1); - } else { - $reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i+1, $i); - } - $ret[$i] = sprintf("r%d", $i); - $ret[$i+1] = sprintf("r%d", $i+1); - } - if($reg ne "e1" || $plan9) { - $body .= "\t$name = $type($reg)\n"; - } - } - if ($ret[0] eq "_" && $ret[1] eq "_" && $ret[2] eq "_") { - $text .= "\t$call\n"; - } else { - $text .= "\t$ret[0], $ret[1], $ret[2] := $call\n"; - } - $text .= $body; - - if ($plan9 && $ret[2] eq "e1") { - $text .= "\tif int32(r0) == -1 {\n"; - $text .= "\t\terr = e1\n"; - $text .= "\t}\n"; - } elsif ($do_errno) { - $text .= "\tif e1 != 0 {\n"; - $text .= "\t\terr = errnoErr(e1)\n"; - $text .= "\t}\n"; - } - $text .= "\treturn\n"; - $text .= "}\n\n"; -} - -chomp $text; -chomp $text; - -if($errors) { - exit 1; -} - -print <) { - chomp; - s/\s+/ /g; - s/^\s+//; - s/\s+$//; - $package = $1 if !$package && /^package (\S+)$/; - my $nonblock = /^\/\/sysnb /; - next if !/^\/\/sys / && !$nonblock; - - # Line must be of the form - # func Open(path string, mode int, perm int) (fd int, err error) - # Split into name, in params, out params. - if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*(?:(\w*)\.)?(\w*))?$/) { - print STDERR "$ARGV:$.: malformed //sys declaration\n"; - $errors = 1; - next; - } - my ($nb, $func, $in, $out, $modname, $sysname) = ($1, $2, $3, $4, $5, $6); - - # Split argument lists on comma. - my @in = parseparamlist($in); - my @out = parseparamlist($out); - - # So file name. - if($modname eq "") { - $modname = "libc"; - } - - # System call name. - if($sysname eq "") { - $sysname = "$func"; - } - - # System call pointer variable name. - my $sysvarname = "proc$sysname"; - - my $strconvfunc = "BytePtrFromString"; - my $strconvtype = "*byte"; - - $sysname =~ y/A-Z/a-z/; # All libc functions are lowercase. - - # Runtime import of function to allow cross-platform builds. - $dynimports .= "//go:cgo_import_dynamic libc_${sysname} ${sysname} \"$modname.so\"\n"; - # Link symbol to proc address variable. - $linknames .= "//go:linkname ${sysvarname} libc_${sysname}\n"; - # Library proc address variable. - push @vars, $sysvarname; - - # Go function header. - $out = join(', ', @out); - if($out ne "") { - $out = " ($out)"; - } - if($text ne "") { - $text .= "\n" - } - $text .= sprintf "func %s(%s)%s {\n", $func, join(', ', @in), $out; - - # Check if err return available - my $errvar = ""; - foreach my $p (@out) { - my ($name, $type) = parseparam($p); - if($type eq "error") { - $errvar = $name; - last; - } - } - - # Prepare arguments to Syscall. - my @args = (); - my $n = 0; - foreach my $p (@in) { - my ($name, $type) = parseparam($p); - if($type =~ /^\*/) { - push @args, "uintptr(unsafe.Pointer($name))"; - } elsif($type eq "string" && $errvar ne "") { - $text .= "\tvar _p$n $strconvtype\n"; - $text .= "\t_p$n, $errvar = $strconvfunc($name)\n"; - $text .= "\tif $errvar != nil {\n\t\treturn\n\t}\n"; - push @args, "uintptr(unsafe.Pointer(_p$n))"; - $n++; - } elsif($type eq "string") { - print STDERR "$ARGV:$.: $func uses string arguments, but has no error return\n"; - $text .= "\tvar _p$n $strconvtype\n"; - $text .= "\t_p$n, _ = $strconvfunc($name)\n"; - push @args, "uintptr(unsafe.Pointer(_p$n))"; - $n++; - } elsif($type =~ /^\[\](.*)/) { - # Convert slice into pointer, length. - # Have to be careful not to take address of &a[0] if len == 0: - # pass nil in that case. - $text .= "\tvar _p$n *$1\n"; - $text .= "\tif len($name) > 0 {\n\t\t_p$n = \&$name\[0]\n\t}\n"; - push @args, "uintptr(unsafe.Pointer(_p$n))", "uintptr(len($name))"; - $n++; - } elsif($type eq "int64" && $_32bit ne "") { - if($_32bit eq "big-endian") { - push @args, "uintptr($name >> 32)", "uintptr($name)"; - } else { - push @args, "uintptr($name)", "uintptr($name >> 32)"; - } - } elsif($type eq "bool") { - $text .= "\tvar _p$n uint32\n"; - $text .= "\tif $name {\n\t\t_p$n = 1\n\t} else {\n\t\t_p$n = 0\n\t}\n"; - push @args, "uintptr(_p$n)"; - $n++; - } else { - push @args, "uintptr($name)"; - } - } - my $nargs = @args; - - # Determine which form to use; pad args with zeros. - my $asm = "sysvicall6"; - if ($nonblock) { - $asm = "rawSysvicall6"; - } - if(@args <= 6) { - while(@args < 6) { - push @args, "0"; - } - } else { - print STDERR "$ARGV:$.: too many arguments to system call\n"; - } - - # Actual call. - my $args = join(', ', @args); - my $call = "$asm(uintptr(unsafe.Pointer(&$sysvarname)), $nargs, $args)"; - - # Assign return values. - my $body = ""; - my $failexpr = ""; - my @ret = ("_", "_", "_"); - my @pout= (); - my $do_errno = 0; - for(my $i=0; $i<@out; $i++) { - my $p = $out[$i]; - my ($name, $type) = parseparam($p); - my $reg = ""; - if($name eq "err") { - $reg = "e1"; - $ret[2] = $reg; - $do_errno = 1; - } else { - $reg = sprintf("r%d", $i); - $ret[$i] = $reg; - } - if($type eq "bool") { - $reg = "$reg != 0"; - } - if($type eq "int64" && $_32bit ne "") { - # 64-bit number in r1:r0 or r0:r1. - if($i+2 > @out) { - print STDERR "$ARGV:$.: not enough registers for int64 return\n"; - } - if($_32bit eq "big-endian") { - $reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i, $i+1); - } else { - $reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i+1, $i); - } - $ret[$i] = sprintf("r%d", $i); - $ret[$i+1] = sprintf("r%d", $i+1); - } - if($reg ne "e1") { - $body .= "\t$name = $type($reg)\n"; - } - } - if ($ret[0] eq "_" && $ret[1] eq "_" && $ret[2] eq "_") { - $text .= "\t$call\n"; - } else { - $text .= "\t$ret[0], $ret[1], $ret[2] := $call\n"; - } - $text .= $body; - - if ($do_errno) { - $text .= "\tif e1 != 0 {\n"; - $text .= "\t\terr = e1\n"; - $text .= "\t}\n"; - } - $text .= "\treturn\n"; - $text .= "}\n"; -} - -if($errors) { - exit 1; -} - -print <){ - if(/^#define\s+SYS_(\w+)\s+([0-9]+)/){ - my $name = $1; - my $num = $2; - $name =~ y/a-z/A-Z/; - print " SYS_$name = $num;" - } -} - -print <){ - if(/^([0-9]+)\s+STD\s+({ \S+\s+(\w+).*)$/){ - my $num = $1; - my $proto = $2; - my $name = "SYS_$3"; - $name =~ y/a-z/A-Z/; - - # There are multiple entries for enosys and nosys, so comment them out. - if($name =~ /^SYS_E?NOSYS$/){ - $name = "// $name"; - } - if($name eq 'SYS_SYS_EXIT'){ - $name = 'SYS_EXIT'; - } - - print " $name = $num; // $proto\n"; - } -} - -print <){ - if(/^([0-9]+)\s+\S+\s+STD\s+({ \S+\s+(\w+).*)$/){ - my $num = $1; - my $proto = $2; - my $name = "SYS_$3"; - $name =~ y/a-z/A-Z/; - - # There are multiple entries for enosys and nosys, so comment them out. - if($name =~ /^SYS_E?NOSYS$/){ - $name = "// $name"; - } - if($name eq 'SYS_SYS_EXIT'){ - $name = 'SYS_EXIT'; - } - - print " $name = $num; // $proto\n"; - } -} - -print <){ - if($line =~ /^(.*)\\$/) { - # Handle continuation - $line = $1; - $_ =~ s/^\s+//; - $line .= $_; - } else { - # New line - $line = $_; - } - next if $line =~ /\\$/; - if($line =~ /^([0-9]+)\s+((STD)|(NOERR))\s+(RUMP\s+)?({\s+\S+\s*\*?\s*\|(\S+)\|(\S*)\|(\w+).*\s+})(\s+(\S+))?$/) { - my $num = $1; - my $proto = $6; - my $compat = $8; - my $name = "$7_$9"; - - $name = "$7_$11" if $11 ne ''; - $name =~ y/a-z/A-Z/; - - if($compat eq '' || $compat eq '13' || $compat eq '30' || $compat eq '50') { - print " $name = $num; // $proto\n"; - } - } -} - -print <){ - if(/^([0-9]+)\s+STD\s+(NOLOCK\s+)?({ \S+\s+\*?(\w+).*)$/){ - my $num = $1; - my $proto = $3; - my $name = $4; - $name =~ y/a-z/A-Z/; - - # There are multiple entries for enosys and nosys, so comment them out. - if($name =~ /^SYS_E?NOSYS$/){ - $name = "// $name"; - } - if($name eq 'SYS_SYS_EXIT'){ - $name = 'SYS_EXIT'; - } - - print " $name = $num; // $proto\n"; - } -} - -print < 6.2, pass execpromises to the syscall. + if maj > 6 || (maj == 6 && min > 2) { + exptr, err := syscall.BytePtrFromString(execpromises) + if err != nil { return err } - pathsUnsafe = unsafe.Pointer(&pathsPtr[0]) + expr = unsafe.Pointer(exptr) } - _, _, e := syscall.Syscall(SYS_PLEDGE, uintptr(promisesUnsafe), uintptr(pathsUnsafe), 0) + + _, _, e := syscall.Syscall(SYS_PLEDGE, uintptr(unsafe.Pointer(pptr)), uintptr(expr), 0) if e != 0 { return e } + + return nil +} + +// PledgePromises implements the pledge syscall. +// +// This changes the promises and leaves the execpromises untouched. +// +// For more information see pledge(2). +func PledgePromises(promises string) error { + maj, min, err := majmin() + if err != nil { + return err + } + + err = pledgeAvailable(maj, min, "") + if err != nil { + return err + } + + // This variable holds the execpromises and is always nil. + var expr unsafe.Pointer + + pptr, err := syscall.BytePtrFromString(promises) + if err != nil { + return err + } + + _, _, e := syscall.Syscall(SYS_PLEDGE, uintptr(unsafe.Pointer(pptr)), uintptr(expr), 0) + if e != 0 { + return e + } + + return nil +} + +// PledgeExecpromises implements the pledge syscall. +// +// This changes the execpromises and leaves the promises untouched. +// +// For more information see pledge(2). +func PledgeExecpromises(execpromises string) error { + maj, min, err := majmin() + if err != nil { + return err + } + + err = pledgeAvailable(maj, min, execpromises) + if err != nil { + return err + } + + // This variable holds the promises and is always nil. + var pptr unsafe.Pointer + + exptr, err := syscall.BytePtrFromString(execpromises) + if err != nil { + return err + } + + _, _, e := syscall.Syscall(SYS_PLEDGE, uintptr(pptr), uintptr(unsafe.Pointer(exptr)), 0) + if e != 0 { + return e + } + + return nil +} + +// majmin returns major and minor version number for an OpenBSD system. +func majmin() (major int, minor int, err error) { + var v Utsname + err = Uname(&v) + if err != nil { + return + } + + major, err = strconv.Atoi(string(v.Release[0])) + if err != nil { + err = errors.New("cannot parse major version number returned by uname") + return + } + + minor, err = strconv.Atoi(string(v.Release[2])) + if err != nil { + err = errors.New("cannot parse minor version number returned by uname") + return + } + + return +} + +// pledgeAvailable checks for availability of the pledge(2) syscall +// based on the running OpenBSD version. +func pledgeAvailable(maj, min int, execpromises string) error { + // If OpenBSD <= 5.9, pledge is not available. + if (maj == 5 && min != 9) || maj < 5 { + return fmt.Errorf("pledge syscall is not available on OpenBSD %d.%d", maj, min) + } + + // If OpenBSD <= 6.2 and execpromises is not empty, + // return an error - execpromises is not available before 6.3 + if (maj < 6 || (maj == 6 && min <= 2)) && execpromises != "" { + return fmt.Errorf("cannot use execpromises on OpenBSD %d.%d", maj, min) + } + return nil } diff --git a/vendor/golang.org/x/sys/unix/openbsd_unveil.go b/vendor/golang.org/x/sys/unix/openbsd_unveil.go new file mode 100644 index 0000000000..aebc2dc576 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/openbsd_unveil.go @@ -0,0 +1,44 @@ +// 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 openbsd + +package unix + +import ( + "syscall" + "unsafe" +) + +// Unveil implements the unveil syscall. +// For more information see unveil(2). +// Note that the special case of blocking further +// unveil calls is handled by UnveilBlock. +func Unveil(path string, flags string) error { + pathPtr, err := syscall.BytePtrFromString(path) + if err != nil { + return err + } + flagsPtr, err := syscall.BytePtrFromString(flags) + if err != nil { + return err + } + _, _, e := syscall.Syscall(SYS_UNVEIL, uintptr(unsafe.Pointer(pathPtr)), uintptr(unsafe.Pointer(flagsPtr)), 0) + if e != 0 { + return e + } + return nil +} + +// UnveilBlock blocks future unveil calls. +// For more information see unveil(2). +func UnveilBlock() error { + // Both pointers must be nil. + var pathUnsafe, flagsUnsafe unsafe.Pointer + _, _, e := syscall.Syscall(SYS_UNVEIL, uintptr(pathUnsafe), uintptr(flagsUnsafe), 0) + if e != 0 { + return e + } + return nil +} diff --git a/vendor/golang.org/x/sys/unix/pagesize_unix.go b/vendor/golang.org/x/sys/unix/pagesize_unix.go index 83c85e0196..bc2f3629a7 100644 --- a/vendor/golang.org/x/sys/unix/pagesize_unix.go +++ b/vendor/golang.org/x/sys/unix/pagesize_unix.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 netbsd openbsd solaris +// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris // For Unix, get the pagesize from the runtime. diff --git a/vendor/golang.org/x/sys/unix/race0.go b/vendor/golang.org/x/sys/unix/race0.go index dd0820431e..ad026678c7 100644 --- a/vendor/golang.org/x/sys/unix/race0.go +++ b/vendor/golang.org/x/sys/unix/race0.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,!race linux,!race freebsd,!race netbsd openbsd solaris dragonfly +// +build aix darwin,!race linux,!race freebsd,!race netbsd openbsd solaris dragonfly package unix diff --git a/vendor/golang.org/x/sys/unix/sockcmsg_unix.go b/vendor/golang.org/x/sys/unix/sockcmsg_unix.go index bb756ece15..5f9ae233a7 100644 --- a/vendor/golang.org/x/sys/unix/sockcmsg_unix.go +++ b/vendor/golang.org/x/sys/unix/sockcmsg_unix.go @@ -2,23 +2,36 @@ // 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 netbsd openbsd solaris +// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris // Socket control messages package unix -import "unsafe" +import ( + "runtime" + "unsafe" +) // Round the length of a raw sockaddr up to align it properly. func cmsgAlignOf(salen int) int { - salign := sizeofPtr - // NOTE: It seems like 64-bit Darwin, DragonFly BSD and - // Solaris kernels still require 32-bit aligned access to - // network subsystem. - if darwin64Bit || dragonfly64Bit || solaris64Bit { - salign = 4 + salign := SizeofPtr + + switch runtime.GOOS { + case "darwin", "dragonfly", "solaris": + // NOTE: It seems like 64-bit Darwin, DragonFly BSD and + // Solaris kernels still require 32-bit aligned access to + // network subsystem. + if SizeofPtr == 8 { + salign = 4 + } + case "openbsd": + // OpenBSD armv7 requires 64-bit alignment. + if runtime.GOARCH == "arm" { + salign = 8 + } } + return (salen + salign - 1) & ^(salign - 1) } diff --git a/vendor/golang.org/x/sys/unix/str.go b/vendor/golang.org/x/sys/unix/str.go index 35ed664353..17fb698683 100644 --- a/vendor/golang.org/x/sys/unix/str.go +++ b/vendor/golang.org/x/sys/unix/str.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 netbsd openbsd solaris +// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package unix diff --git a/vendor/golang.org/x/sys/unix/syscall.go b/vendor/golang.org/x/sys/unix/syscall.go index 857d2a42d4..0d4b1d7a20 100644 --- a/vendor/golang.org/x/sys/unix/syscall.go +++ b/vendor/golang.org/x/sys/unix/syscall.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 netbsd openbsd solaris +// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris // Package unix contains an interface to the low-level operating system // primitives. OS details vary depending on the underlying system, and @@ -11,24 +11,27 @@ // system, set $GOOS and $GOARCH to the desired system. For example, if // you want to view documentation for freebsd/arm on linux/amd64, set $GOOS // to freebsd and $GOARCH to arm. +// // The primary use of this package is inside other packages that provide a more // portable interface to the system, such as "os", "time" and "net". Use // those packages rather than this one if you can. +// // For details of the functions and data types in this package consult // the manuals for the appropriate operating system. +// // These calls return err == nil to indicate success; otherwise // err represents an operating system error describing the failure and // holds a value of type syscall.Errno. package unix // import "golang.org/x/sys/unix" +import "strings" + // ByteSliceFromString returns a NUL-terminated slice of bytes // containing the text of s. If s contains a NUL byte at any // location, it returns (nil, EINVAL). func ByteSliceFromString(s string) ([]byte, error) { - for i := 0; i < len(s); i++ { - if s[i] == 0 { - return nil, EINVAL - } + if strings.IndexByte(s, 0) != -1 { + return nil, EINVAL } a := make([]byte, len(s)+1) copy(a, s) diff --git a/vendor/golang.org/x/sys/unix/syscall_aix.go b/vendor/golang.org/x/sys/unix/syscall_aix.go new file mode 100644 index 0000000000..a76826f443 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/syscall_aix.go @@ -0,0 +1,547 @@ +// 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 aix + +// Aix system calls. +// This file is compiled as ordinary Go code, +// but it is also input to mksyscall, +// which parses the //sys lines and generates system call stubs. +// Note that sometimes we use a lowercase //sys name and +// wrap it in our own nicer implementation. + +package unix + +import "unsafe" + +/* + * Wrapped + */ + +//sys utimes(path string, times *[2]Timeval) (err error) +func Utimes(path string, tv []Timeval) error { + if len(tv) != 2 { + return EINVAL + } + return utimes(path, (*[2]Timeval)(unsafe.Pointer(&tv[0]))) +} + +//sys utimensat(dirfd int, path string, times *[2]Timespec, flag int) (err error) +func UtimesNano(path string, ts []Timespec) error { + if len(ts) != 2 { + return EINVAL + } + return utimensat(AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0) +} + +func UtimesNanoAt(dirfd int, path string, ts []Timespec, flags int) error { + if ts == nil { + return utimensat(dirfd, path, nil, flags) + } + if len(ts) != 2 { + return EINVAL + } + return utimensat(dirfd, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), flags) +} + +func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) { + if sa.Port < 0 || sa.Port > 0xFFFF { + return nil, 0, EINVAL + } + sa.raw.Family = AF_INET + p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port)) + p[0] = byte(sa.Port >> 8) + p[1] = byte(sa.Port) + for i := 0; i < len(sa.Addr); i++ { + sa.raw.Addr[i] = sa.Addr[i] + } + return unsafe.Pointer(&sa.raw), SizeofSockaddrInet4, nil +} + +func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, _Socklen, error) { + if sa.Port < 0 || sa.Port > 0xFFFF { + return nil, 0, EINVAL + } + sa.raw.Family = AF_INET6 + p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port)) + p[0] = byte(sa.Port >> 8) + p[1] = byte(sa.Port) + sa.raw.Scope_id = sa.ZoneId + for i := 0; i < len(sa.Addr); i++ { + sa.raw.Addr[i] = sa.Addr[i] + } + return unsafe.Pointer(&sa.raw), SizeofSockaddrInet6, nil +} + +func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, _Socklen, error) { + name := sa.Name + n := len(name) + if n > len(sa.raw.Path) { + return nil, 0, EINVAL + } + if n == len(sa.raw.Path) && name[0] != '@' { + return nil, 0, EINVAL + } + sa.raw.Family = AF_UNIX + for i := 0; i < n; i++ { + sa.raw.Path[i] = uint8(name[i]) + } + // length is family (uint16), name, NUL. + sl := _Socklen(2) + if n > 0 { + sl += _Socklen(n) + 1 + } + if sa.raw.Path[0] == '@' { + sa.raw.Path[0] = 0 + // Don't count trailing NUL for abstract address. + sl-- + } + + return unsafe.Pointer(&sa.raw), sl, nil +} + +func Getsockname(fd int) (sa Sockaddr, err error) { + var rsa RawSockaddrAny + var len _Socklen = SizeofSockaddrAny + if err = getsockname(fd, &rsa, &len); err != nil { + return + } + return anyToSockaddr(fd, &rsa) +} + +//sys getcwd(buf []byte) (err error) + +const ImplementsGetwd = true + +func Getwd() (ret string, err error) { + for len := uint64(4096); ; len *= 2 { + b := make([]byte, len) + err := getcwd(b) + if err == nil { + i := 0 + for b[i] != 0 { + i++ + } + return string(b[0:i]), nil + } + if err != ERANGE { + return "", err + } + } +} + +func Getcwd(buf []byte) (n int, err error) { + err = getcwd(buf) + if err == nil { + i := 0 + for buf[i] != 0 { + i++ + } + n = i + 1 + } + return +} + +func Getgroups() (gids []int, err error) { + n, err := getgroups(0, nil) + if err != nil { + return nil, err + } + if n == 0 { + return nil, nil + } + + // Sanity check group count. Max is 16 on BSD. + if n < 0 || n > 1000 { + return nil, EINVAL + } + + a := make([]_Gid_t, n) + n, err = getgroups(n, &a[0]) + if err != nil { + return nil, err + } + gids = make([]int, n) + for i, v := range a[0:n] { + gids[i] = int(v) + } + return +} + +func Setgroups(gids []int) (err error) { + if len(gids) == 0 { + return setgroups(0, nil) + } + + a := make([]_Gid_t, len(gids)) + for i, v := range gids { + a[i] = _Gid_t(v) + } + return setgroups(len(a), &a[0]) +} + +/* + * Socket + */ + +//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) + +func Accept(fd int) (nfd int, sa Sockaddr, err error) { + var rsa RawSockaddrAny + var len _Socklen = SizeofSockaddrAny + nfd, err = accept(fd, &rsa, &len) + if nfd == -1 { + return + } + sa, err = anyToSockaddr(fd, &rsa) + if err != nil { + Close(nfd) + nfd = 0 + } + return +} + +func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) { + // Recvmsg not implemented on AIX + sa := new(SockaddrUnix) + return -1, -1, -1, sa, ENOSYS +} + +func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) { + _, err = SendmsgN(fd, p, oob, to, flags) + return +} + +func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) { + // SendmsgN not implemented on AIX + return -1, ENOSYS +} + +func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { + switch rsa.Addr.Family { + + case AF_UNIX: + pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa)) + sa := new(SockaddrUnix) + + // Some versions of AIX have a bug in getsockname (see IV78655). + // We can't rely on sa.Len being set correctly. + n := SizeofSockaddrUnix - 3 // subtract leading Family, Len, terminating NUL. + for i := 0; i < n; i++ { + if pp.Path[i] == 0 { + n = i + break + } + } + + bytes := (*[10000]byte)(unsafe.Pointer(&pp.Path[0]))[0:n] + sa.Name = string(bytes) + return sa, nil + + case AF_INET: + pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa)) + sa := new(SockaddrInet4) + p := (*[2]byte)(unsafe.Pointer(&pp.Port)) + sa.Port = int(p[0])<<8 + int(p[1]) + for i := 0; i < len(sa.Addr); i++ { + sa.Addr[i] = pp.Addr[i] + } + return sa, nil + + case AF_INET6: + pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa)) + sa := new(SockaddrInet6) + p := (*[2]byte)(unsafe.Pointer(&pp.Port)) + sa.Port = int(p[0])<<8 + int(p[1]) + sa.ZoneId = pp.Scope_id + for i := 0; i < len(sa.Addr); i++ { + sa.Addr[i] = pp.Addr[i] + } + return sa, nil + } + return nil, EAFNOSUPPORT +} + +func Gettimeofday(tv *Timeval) (err error) { + err = gettimeofday(tv, nil) + return +} + +func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { + if raceenabled { + raceReleaseMerge(unsafe.Pointer(&ioSync)) + } + return sendfile(outfd, infd, offset, count) +} + +// TODO +func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { + return -1, ENOSYS +} + +//sys getdirent(fd int, buf []byte) (n int, err error) +func ReadDirent(fd int, buf []byte) (n int, err error) { + return getdirent(fd, buf) +} + +//sys wait4(pid Pid_t, status *_C_int, options int, rusage *Rusage) (wpid Pid_t, err error) +func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, err error) { + var status _C_int + var r Pid_t + err = ERESTART + // AIX wait4 may return with ERESTART errno, while the processus is still + // active. + for err == ERESTART { + r, err = wait4(Pid_t(pid), &status, options, rusage) + } + wpid = int(r) + if wstatus != nil { + *wstatus = WaitStatus(status) + } + return +} + +/* + * Wait + */ + +type WaitStatus uint32 + +func (w WaitStatus) Stopped() bool { return w&0x40 != 0 } +func (w WaitStatus) StopSignal() Signal { + if !w.Stopped() { + return -1 + } + return Signal(w>>8) & 0xFF +} + +func (w WaitStatus) Exited() bool { return w&0xFF == 0 } +func (w WaitStatus) ExitStatus() int { + if !w.Exited() { + return -1 + } + return int((w >> 8) & 0xFF) +} + +func (w WaitStatus) Signaled() bool { return w&0x40 == 0 && w&0xFF != 0 } +func (w WaitStatus) Signal() Signal { + if !w.Signaled() { + return -1 + } + return Signal(w>>16) & 0xFF +} + +func (w WaitStatus) Continued() bool { return w&0x01000000 != 0 } + +func (w WaitStatus) CoreDump() bool { return w&0x200 != 0 } + +func (w WaitStatus) TrapCause() int { return -1 } + +//sys ioctl(fd int, req uint, arg uintptr) (err error) + +// ioctl itself should not be exposed directly, but additional get/set +// functions for specific types are permissible. + +// IoctlSetInt performs an ioctl operation which sets an integer value +// on fd, using the specified request number. +func IoctlSetInt(fd int, req uint, value int) error { + return ioctl(fd, req, uintptr(value)) +} + +func ioctlSetWinsize(fd int, req uint, value *Winsize) error { + return ioctl(fd, req, uintptr(unsafe.Pointer(value))) +} + +func ioctlSetTermios(fd int, req uint, value *Termios) error { + return ioctl(fd, req, uintptr(unsafe.Pointer(value))) +} + +// IoctlGetInt performs an ioctl operation which gets an integer value +// from fd, using the specified request number. +func IoctlGetInt(fd int, req uint) (int, error) { + var value int + err := ioctl(fd, req, uintptr(unsafe.Pointer(&value))) + return value, err +} + +func IoctlGetWinsize(fd int, req uint) (*Winsize, error) { + var value Winsize + err := ioctl(fd, req, uintptr(unsafe.Pointer(&value))) + return &value, err +} + +func IoctlGetTermios(fd int, req uint) (*Termios, error) { + var value Termios + err := ioctl(fd, req, uintptr(unsafe.Pointer(&value))) + return &value, err +} + +// fcntl must never be called with cmd=F_DUP2FD because it doesn't work on AIX +// There is no way to create a custom fcntl and to keep //sys fcntl easily, +// Therefore, the programmer must call dup2 instead of fcntl in this case. + +// FcntlInt performs a fcntl syscall on fd with the provided command and argument. +//sys FcntlInt(fd uintptr, cmd int, arg int) (r int,err error) = fcntl + +// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command. +//sys FcntlFlock(fd uintptr, cmd int, lk *Flock_t) (err error) = fcntl + +//sys fcntl(fd int, cmd int, arg int) (val int, err error) + +/* + * Direct access + */ + +//sys Acct(path string) (err error) +//sys Chdir(path string) (err error) +//sys Chroot(path string) (err error) +//sys Close(fd int) (err error) +//sys Dup(oldfd int) (fd int, err error) +//sys Exit(code int) +//sys Faccessat(dirfd int, path string, mode uint32, flags int) (err error) +//sys Fchdir(fd int) (err error) +//sys Fchmod(fd int, mode uint32) (err error) +//sys Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) +//sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) +//sys Fdatasync(fd int) (err error) +//sys Fsync(fd int) (err error) +// readdir_r +//sysnb Getpgid(pid int) (pgid int, err error) + +//sys Getpgrp() (pid int) + +//sysnb Getpid() (pid int) +//sysnb Getppid() (ppid int) +//sys Getpriority(which int, who int) (prio int, err error) +//sysnb Getrusage(who int, rusage *Rusage) (err error) +//sysnb Getsid(pid int) (sid int, err error) +//sysnb Kill(pid int, sig Signal) (err error) +//sys Klogctl(typ int, buf []byte) (n int, err error) = syslog +//sys Mkdir(dirfd int, path string, mode uint32) (err error) +//sys Mkdirat(dirfd int, path string, mode uint32) (err error) +//sys Mkfifo(path string, mode uint32) (err error) +//sys Mknod(path string, mode uint32, dev int) (err error) +//sys Mknodat(dirfd int, path string, mode uint32, dev int) (err error) +//sys Nanosleep(time *Timespec, leftover *Timespec) (err error) +//sys Open(path string, mode int, perm uint32) (fd int, err error) = open64 +//sys Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) +//sys read(fd int, p []byte) (n int, err error) +//sys Readlink(path string, buf []byte) (n int, err error) +//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) +//sys Setdomainname(p []byte) (err error) +//sys Sethostname(p []byte) (err error) +//sysnb Setpgid(pid int, pgid int) (err error) +//sysnb Setsid() (pid int, err error) +//sysnb Settimeofday(tv *Timeval) (err error) + +//sys Setuid(uid int) (err error) +//sys Setgid(uid int) (err error) + +//sys Setpriority(which int, who int, prio int) (err error) +//sys Statx(dirfd int, path string, flags int, mask int, stat *Statx_t) (err error) +//sys Sync() +//sysnb Times(tms *Tms) (ticks uintptr, err error) +//sysnb Umask(mask int) (oldmask int) +//sysnb Uname(buf *Utsname) (err error) +//TODO umount +// //sys Unmount(target string, flags int) (err error) = umount +//sys Unlink(path string) (err error) +//sys Unlinkat(dirfd int, path string, flags int) (err error) +//sys Ustat(dev int, ubuf *Ustat_t) (err error) +//sys write(fd int, p []byte) (n int, err error) +//sys readlen(fd int, p *byte, np int) (n int, err error) = read +//sys writelen(fd int, p *byte, np int) (n int, err error) = write + +//sys Dup2(oldfd int, newfd int) (err error) +//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = posix_fadvise64 +//sys Fchown(fd int, uid int, gid int) (err error) +//sys Fstat(fd int, stat *Stat_t) (err error) +//sys Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) = fstatat +//sys Fstatfs(fd int, buf *Statfs_t) (err error) +//sys Ftruncate(fd int, length int64) (err error) +//sysnb Getegid() (egid int) +//sysnb Geteuid() (euid int) +//sysnb Getgid() (gid int) +//sysnb Getuid() (uid int) +//sys Lchown(path string, uid int, gid int) (err error) +//sys Listen(s int, n int) (err error) +//sys Lstat(path string, stat *Stat_t) (err error) +//sys Pause() (err error) +//sys Pread(fd int, p []byte, offset int64) (n int, err error) = pread64 +//sys Pwrite(fd int, p []byte, offset int64) (n int, err error) = pwrite64 +//TODO Select +// //sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) +//sys Pselect(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *Sigset_t) (n int, err error) +//sysnb Setregid(rgid int, egid int) (err error) +//sysnb Setreuid(ruid int, euid int) (err error) +//sys Shutdown(fd int, how int) (err error) +//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error) +//sys Stat(path string, stat *Stat_t) (err error) +//sys Statfs(path string, buf *Statfs_t) (err error) +//sys Truncate(path string, length int64) (err error) + +//sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) +//sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) +//sysnb getgroups(n int, list *_Gid_t) (nn int, err error) +//sysnb setgroups(n int, list *_Gid_t) (err error) +//sys getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) +//sys setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) +//sysnb socket(domain int, typ int, proto int) (fd int, err error) +//sysnb socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) +//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) +//sysnb getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) +//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) +//sys sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) +//sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error) +//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error) + +//sys munmap(addr uintptr, length uintptr) (err error) + +var mapper = &mmapper{ + active: make(map[*byte][]byte), + mmap: mmap, + munmap: munmap, +} + +func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) { + return mapper.Mmap(fd, offset, length, prot, flags) +} + +func Munmap(b []byte) (err error) { + return mapper.Munmap(b) +} + +//sys Madvise(b []byte, advice int) (err error) +//sys Mprotect(b []byte, prot int) (err error) +//sys Mlock(b []byte) (err error) +//sys Mlockall(flags int) (err error) +//sys Msync(b []byte, flags int) (err error) +//sys Munlock(b []byte) (err error) +//sys Munlockall() (err error) + +//sysnb pipe(p *[2]_C_int) (err error) + +func Pipe(p []int) (err error) { + if len(p) != 2 { + return EINVAL + } + var pp [2]_C_int + err = pipe(&pp) + p[0] = int(pp[0]) + p[1] = int(pp[1]) + return +} + +//sys poll(fds *PollFd, nfds int, timeout int) (n int, err error) + +func Poll(fds []PollFd, timeout int) (n int, err error) { + if len(fds) == 0 { + return poll(nil, 0, timeout) + } + return poll(&fds[0], len(fds), timeout) +} + +//sys gettimeofday(tv *Timeval, tzp *Timezone) (err error) +//sysnb Time(t *Time_t) (tt Time_t, err error) +//sys Utime(path string, buf *Utimbuf) (err error) diff --git a/vendor/golang.org/x/sys/unix/syscall_aix_ppc.go b/vendor/golang.org/x/sys/unix/syscall_aix_ppc.go new file mode 100644 index 0000000000..c28af1f86e --- /dev/null +++ b/vendor/golang.org/x/sys/unix/syscall_aix_ppc.go @@ -0,0 +1,34 @@ +// 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 aix +// +build ppc + +package unix + +//sysnb Getrlimit(resource int, rlim *Rlimit) (err error) = getrlimit64 +//sysnb Setrlimit(resource int, rlim *Rlimit) (err error) = setrlimit64 +//sys Seek(fd int, offset int64, whence int) (off int64, err error) = lseek64 + +//sys mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) + +func setTimespec(sec, nsec int64) Timespec { + return Timespec{Sec: int32(sec), Nsec: int32(nsec)} +} + +func setTimeval(sec, usec int64) Timeval { + return Timeval{Sec: int32(sec), Usec: int32(usec)} +} + +func (iov *Iovec) SetLen(length int) { + iov.Len = uint32(length) +} + +func (msghdr *Msghdr) SetControllen(length int) { + msghdr.Controllen = uint32(length) +} + +func (cmsg *Cmsghdr) SetLen(length int) { + cmsg.Len = uint32(length) +} diff --git a/vendor/golang.org/x/sys/unix/syscall_aix_ppc64.go b/vendor/golang.org/x/sys/unix/syscall_aix_ppc64.go new file mode 100644 index 0000000000..881cacc6cc --- /dev/null +++ b/vendor/golang.org/x/sys/unix/syscall_aix_ppc64.go @@ -0,0 +1,34 @@ +// 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 aix +// +build ppc64 + +package unix + +//sysnb Getrlimit(resource int, rlim *Rlimit) (err error) +//sysnb Setrlimit(resource int, rlim *Rlimit) (err error) +//sys Seek(fd int, offset int64, whence int) (off int64, err error) = lseek + +//sys mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) = mmap64 + +func setTimespec(sec, nsec int64) Timespec { + return Timespec{Sec: sec, Nsec: nsec} +} + +func setTimeval(sec, usec int64) Timeval { + return Timeval{Sec: int64(sec), Usec: int32(usec)} +} + +func (iov *Iovec) SetLen(length int) { + iov.Len = uint64(length) +} + +func (msghdr *Msghdr) SetControllen(length int) { + msghdr.Controllen = uint32(length) +} + +func (cmsg *Cmsghdr) SetLen(length int) { + cmsg.Len = uint32(length) +} diff --git a/vendor/golang.org/x/sys/unix/syscall_bsd.go b/vendor/golang.org/x/sys/unix/syscall_bsd.go index 47b0598401..33c8b5f0db 100644 --- a/vendor/golang.org/x/sys/unix/syscall_bsd.go +++ b/vendor/golang.org/x/sys/unix/syscall_bsd.go @@ -206,7 +206,7 @@ func (sa *SockaddrDatalink) sockaddr() (unsafe.Pointer, _Socklen, error) { return unsafe.Pointer(&sa.raw), SizeofSockaddrDatalink, nil } -func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) { +func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { switch rsa.Addr.Family { case AF_LINK: pp := (*RawSockaddrDatalink)(unsafe.Pointer(rsa)) @@ -286,7 +286,7 @@ func Accept(fd int) (nfd int, sa Sockaddr, err error) { Close(nfd) return 0, nil, ECONNABORTED } - sa, err = anyToSockaddr(&rsa) + sa, err = anyToSockaddr(fd, &rsa) if err != nil { Close(nfd) nfd = 0 @@ -306,50 +306,21 @@ func Getsockname(fd int) (sa Sockaddr, err error) { rsa.Addr.Family = AF_UNIX rsa.Addr.Len = SizeofSockaddrUnix } - return anyToSockaddr(&rsa) + return anyToSockaddr(fd, &rsa) } //sysnb socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) -func GetsockoptByte(fd, level, opt int) (value byte, err error) { - var n byte - vallen := _Socklen(1) - err = getsockopt(fd, level, opt, unsafe.Pointer(&n), &vallen) - return n, err -} - -func GetsockoptInet4Addr(fd, level, opt int) (value [4]byte, err error) { - vallen := _Socklen(4) - err = getsockopt(fd, level, opt, unsafe.Pointer(&value[0]), &vallen) - return value, err -} - -func GetsockoptIPMreq(fd, level, opt int) (*IPMreq, error) { - var value IPMreq - vallen := _Socklen(SizeofIPMreq) - err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen) - return &value, err -} - -func GetsockoptIPv6Mreq(fd, level, opt int) (*IPv6Mreq, error) { - var value IPv6Mreq - vallen := _Socklen(SizeofIPv6Mreq) - err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen) - return &value, err -} - -func GetsockoptIPv6MTUInfo(fd, level, opt int) (*IPv6MTUInfo, error) { - var value IPv6MTUInfo - vallen := _Socklen(SizeofIPv6MTUInfo) - err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen) - return &value, err -} - -func GetsockoptICMPv6Filter(fd, level, opt int) (*ICMPv6Filter, error) { - var value ICMPv6Filter - vallen := _Socklen(SizeofICMPv6Filter) - err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen) - return &value, err +// GetsockoptString returns the string value of the socket option opt for the +// socket associated with fd at the given socket level. +func GetsockoptString(fd, level, opt int) (string, error) { + buf := make([]byte, 256) + vallen := _Socklen(len(buf)) + err := getsockopt(fd, level, opt, unsafe.Pointer(&buf[0]), &vallen) + if err != nil { + return "", err + } + return string(buf[:vallen-1]), nil } //sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) @@ -385,7 +356,7 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from recvflags = int(msg.Flags) // source address is only specified if the socket is unconnected if rsa.Addr.Family != AF_UNSPEC { - from, err = anyToSockaddr(&rsa) + from, err = anyToSockaddr(fd, &rsa) } return } diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin.go b/vendor/golang.org/x/sys/unix/syscall_darwin.go index 9a6783e9b9..a2e3688822 100644 --- a/vendor/golang.org/x/sys/unix/syscall_darwin.go +++ b/vendor/golang.org/x/sys/unix/syscall_darwin.go @@ -13,7 +13,7 @@ package unix import ( - errorspkg "errors" + "errors" "syscall" "unsafe" ) @@ -36,6 +36,7 @@ func Getwd() (string, error) { return "", ENOTSUP } +// SockaddrDatalink implements the Sockaddr interface for AF_LINK type sockets. type SockaddrDatalink struct { Len uint8 Family uint8 @@ -76,18 +77,6 @@ func nametomib(name string) (mib []_C_int, err error) { return buf[0 : n/siz], nil } -func direntIno(buf []byte) (uint64, bool) { - return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino)) -} - -func direntReclen(buf []byte) (uint64, bool) { - return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen)) -} - -func direntNamlen(buf []byte) (uint64, bool) { - return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen)) -} - //sys ptrace(request int, pid int, addr uintptr, data uintptr) (err error) func PtraceAttach(pid int) (err error) { return ptrace(PT_ATTACH, pid, 0, 0) } func PtraceDetach(pid int) (err error) { return ptrace(PT_DETACH, pid, 0, 0) } @@ -109,7 +98,7 @@ type attrList struct { func getAttrList(path string, attrList attrList, attrBuf []byte, options uint) (attrs [][]byte, err error) { if len(attrBuf) < 4 { - return nil, errorspkg.New("attrBuf too small") + return nil, errors.New("attrBuf too small") } attrList.bitmapCount = attrBitMapCount @@ -119,17 +108,8 @@ func getAttrList(path string, attrList attrList, attrBuf []byte, options uint) ( return nil, err } - _, _, e1 := Syscall6( - SYS_GETATTRLIST, - uintptr(unsafe.Pointer(_p0)), - uintptr(unsafe.Pointer(&attrList)), - uintptr(unsafe.Pointer(&attrBuf[0])), - uintptr(len(attrBuf)), - uintptr(options), - 0, - ) - if e1 != 0 { - return nil, e1 + if err := getattrlist(_p0, unsafe.Pointer(&attrList), unsafe.Pointer(&attrBuf[0]), uintptr(len(attrBuf)), int(options)); err != nil { + return nil, err } size := *(*uint32)(unsafe.Pointer(&attrBuf[0])) @@ -145,12 +125,12 @@ func getAttrList(path string, attrList attrList, attrBuf []byte, options uint) ( for i := uint32(0); int(i) < len(dat); { header := dat[i:] if len(header) < 8 { - return attrs, errorspkg.New("truncated attribute header") + return attrs, errors.New("truncated attribute header") } datOff := *(*int32)(unsafe.Pointer(&header[0])) attrLen := *(*uint32)(unsafe.Pointer(&header[4])) if datOff < 0 || uint32(datOff)+attrLen > uint32(len(dat)) { - return attrs, errorspkg.New("truncated results; attrBuf too small") + return attrs, errors.New("truncated results; attrBuf too small") } end := uint32(datOff) + attrLen attrs = append(attrs, dat[datOff:end]) @@ -162,6 +142,8 @@ func getAttrList(path string, attrList attrList, attrBuf []byte, options uint) ( return } +//sys getattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error) + //sysnb pipe() (r int, w int, err error) func Pipe(p []int) (err error) { @@ -179,12 +161,113 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) { _p0 = unsafe.Pointer(&buf[0]) bufsize = unsafe.Sizeof(Statfs_t{}) * uintptr(len(buf)) } - r0, _, e1 := Syscall(SYS_GETFSSTAT64, uintptr(_p0), bufsize, uintptr(flags)) - n = int(r0) - if e1 != 0 { - err = e1 + return getfsstat(_p0, bufsize, flags) +} + +func xattrPointer(dest []byte) *byte { + // It's only when dest is set to NULL that the OS X implementations of + // getxattr() and listxattr() return the current sizes of the named attributes. + // An empty byte array is not sufficient. To maintain the same behaviour as the + // linux implementation, we wrap around the system calls and pass in NULL when + // dest is empty. + var destp *byte + if len(dest) > 0 { + destp = &dest[0] } - return + return destp +} + +//sys getxattr(path string, attr string, dest *byte, size int, position uint32, options int) (sz int, err error) + +func Getxattr(path string, attr string, dest []byte) (sz int, err error) { + return getxattr(path, attr, xattrPointer(dest), len(dest), 0, 0) +} + +func Lgetxattr(link string, attr string, dest []byte) (sz int, err error) { + return getxattr(link, attr, xattrPointer(dest), len(dest), 0, XATTR_NOFOLLOW) +} + +//sys fgetxattr(fd int, attr string, dest *byte, size int, position uint32, options int) (sz int, err error) + +func Fgetxattr(fd int, attr string, dest []byte) (sz int, err error) { + return fgetxattr(fd, attr, xattrPointer(dest), len(dest), 0, 0) +} + +//sys setxattr(path string, attr string, data *byte, size int, position uint32, options int) (err error) + +func Setxattr(path string, attr string, data []byte, flags int) (err error) { + // The parameters for the OS X implementation vary slightly compared to the + // linux system call, specifically the position parameter: + // + // linux: + // int setxattr( + // const char *path, + // const char *name, + // const void *value, + // size_t size, + // int flags + // ); + // + // darwin: + // int setxattr( + // const char *path, + // const char *name, + // void *value, + // size_t size, + // u_int32_t position, + // int options + // ); + // + // position specifies the offset within the extended attribute. In the + // current implementation, only the resource fork extended attribute makes + // use of this argument. For all others, position is reserved. We simply + // default to setting it to zero. + return setxattr(path, attr, xattrPointer(data), len(data), 0, flags) +} + +func Lsetxattr(link string, attr string, data []byte, flags int) (err error) { + return setxattr(link, attr, xattrPointer(data), len(data), 0, flags|XATTR_NOFOLLOW) +} + +//sys fsetxattr(fd int, attr string, data *byte, size int, position uint32, options int) (err error) + +func Fsetxattr(fd int, attr string, data []byte, flags int) (err error) { + return fsetxattr(fd, attr, xattrPointer(data), len(data), 0, 0) +} + +//sys removexattr(path string, attr string, options int) (err error) + +func Removexattr(path string, attr string) (err error) { + // We wrap around and explicitly zero out the options provided to the OS X + // implementation of removexattr, we do so for interoperability with the + // linux variant. + return removexattr(path, attr, 0) +} + +func Lremovexattr(link string, attr string) (err error) { + return removexattr(link, attr, XATTR_NOFOLLOW) +} + +//sys fremovexattr(fd int, attr string, options int) (err error) + +func Fremovexattr(fd int, attr string) (err error) { + return fremovexattr(fd, attr, 0) +} + +//sys listxattr(path string, dest *byte, size int, options int) (sz int, err error) + +func Listxattr(path string, dest []byte) (sz int, err error) { + return listxattr(path, xattrPointer(dest), len(dest), 0) +} + +func Llistxattr(link string, dest []byte) (sz int, err error) { + return listxattr(link, xattrPointer(dest), len(dest), XATTR_NOFOLLOW) +} + +//sys flistxattr(fd int, dest *byte, size int, options int) (sz int, err error) + +func Flistxattr(fd int, dest []byte) (sz int, err error) { + return flistxattr(fd, xattrPointer(dest), len(dest), 0) } func setattrlistTimes(path string, times []Timespec, flags int) error { @@ -203,21 +286,16 @@ func setattrlistTimes(path string, times []Timespec, flags int) error { if flags&AT_SYMLINK_NOFOLLOW != 0 { options |= FSOPT_NOFOLLOW } - _, _, e1 := Syscall6( - SYS_SETATTRLIST, - uintptr(unsafe.Pointer(_p0)), - uintptr(unsafe.Pointer(&attrList)), - uintptr(unsafe.Pointer(&attributes)), - uintptr(unsafe.Sizeof(attributes)), - uintptr(options), - 0, - ) - if e1 != 0 { - return e1 - } - return nil + return setattrlist( + _p0, + unsafe.Pointer(&attrList), + unsafe.Pointer(&attributes), + unsafe.Sizeof(attributes), + options) } +//sys setattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error) + func utimensat(dirfd int, path string, times *[2]Timespec, flags int) error { // Darwin doesn't support SYS_UTIMENSAT return ENOSYS @@ -242,11 +320,11 @@ func IoctlSetInt(fd int, req uint, value int) error { return ioctl(fd, req, uintptr(value)) } -func IoctlSetWinsize(fd int, req uint, value *Winsize) error { +func ioctlSetWinsize(fd int, req uint, value *Winsize) error { return ioctl(fd, req, uintptr(unsafe.Pointer(value))) } -func IoctlSetTermios(fd int, req uint, value *Termios) error { +func ioctlSetTermios(fd int, req uint, value *Termios) error { return ioctl(fd, req, uintptr(unsafe.Pointer(value))) } @@ -270,6 +348,64 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) { return &value, err } +func Uname(uname *Utsname) error { + mib := []_C_int{CTL_KERN, KERN_OSTYPE} + n := unsafe.Sizeof(uname.Sysname) + if err := sysctl(mib, &uname.Sysname[0], &n, nil, 0); err != nil { + return err + } + + mib = []_C_int{CTL_KERN, KERN_HOSTNAME} + n = unsafe.Sizeof(uname.Nodename) + if err := sysctl(mib, &uname.Nodename[0], &n, nil, 0); err != nil { + return err + } + + mib = []_C_int{CTL_KERN, KERN_OSRELEASE} + n = unsafe.Sizeof(uname.Release) + if err := sysctl(mib, &uname.Release[0], &n, nil, 0); err != nil { + return err + } + + mib = []_C_int{CTL_KERN, KERN_VERSION} + n = unsafe.Sizeof(uname.Version) + if err := sysctl(mib, &uname.Version[0], &n, nil, 0); err != nil { + return err + } + + // The version might have newlines or tabs in it, convert them to + // spaces. + for i, b := range uname.Version { + if b == '\n' || b == '\t' { + if i == len(uname.Version)-1 { + uname.Version[i] = 0 + } else { + uname.Version[i] = ' ' + } + } + } + + mib = []_C_int{CTL_HW, HW_MACHINE} + n = unsafe.Sizeof(uname.Machine) + if err := sysctl(mib, &uname.Machine[0], &n, nil, 0); err != nil { + return err + } + + return nil +} + +func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { + if raceenabled { + raceReleaseMerge(unsafe.Pointer(&ioSync)) + } + var length = int64(count) + err = sendfile(infd, outfd, *offset, &length, nil, 0) + written = int(length) + return +} + +//sys sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) + /* * Exposed directly */ @@ -280,6 +416,7 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) { //sys Chmod(path string, mode uint32) (err error) //sys Chown(path string, uid int, gid int) (err error) //sys Chroot(path string) (err error) +//sys ClockGettime(clockid int32, time *Timespec) (err error) //sys Close(fd int) (err error) //sys Dup(fd int) (nfd int, err error) //sys Dup2(from int, to int) (err error) @@ -294,11 +431,8 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) { //sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) //sys Flock(fd int, how int) (err error) //sys Fpathconf(fd int, name int) (val int, err error) -//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64 -//sys Fstatfs(fd int, stat *Statfs_t) (err error) = SYS_FSTATFS64 //sys Fsync(fd int) (err error) //sys Ftruncate(fd int, length int64) (err error) -//sys Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) = SYS_GETDIRENTRIES64 //sys Getdtablesize() (size int) //sysnb Getegid() (egid int) //sysnb Geteuid() (uid int) @@ -318,7 +452,6 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) { //sys Link(path string, link string) (err error) //sys Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error) //sys Listen(s int, backlog int) (err error) -//sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64 //sys Mkdir(path string, mode uint32) (err error) //sys Mkdirat(dirfd int, path string, mode uint32) (err error) //sys Mkfifo(path string, mode uint32) (err error) @@ -350,8 +483,6 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) { //sysnb Setsid() (pid int, err error) //sysnb Settimeofday(tp *Timeval) (err error) //sysnb Setuid(uid int) (err error) -//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64 -//sys Statfs(path string, stat *Statfs_t) (err error) = SYS_STATFS64 //sys Symlink(path string, link string) (err error) //sys Symlinkat(oldpath string, newdirfd int, newpath string) (err error) //sys Sync() (err error) @@ -411,14 +542,6 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) { // Watchevent // Waitevent // Modwatch -// Getxattr -// Fgetxattr -// Setxattr -// Fsetxattr -// Removexattr -// Fremovexattr -// Listxattr -// Flistxattr // Fsctl // Initgroups // Posix_spawn diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin_386.go b/vendor/golang.org/x/sys/unix/syscall_darwin_386.go index b3ac109a2f..489726fa9b 100644 --- a/vendor/golang.org/x/sys/unix/syscall_darwin_386.go +++ b/vendor/golang.org/x/sys/unix/syscall_darwin_386.go @@ -8,7 +8,6 @@ package unix import ( "syscall" - "unsafe" ) func setTimespec(sec, nsec int64) Timespec { @@ -48,21 +47,17 @@ func (cmsg *Cmsghdr) SetLen(length int) { cmsg.Len = uint32(length) } -func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { - var length = uint64(count) - - _, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(*offset>>32), uintptr(unsafe.Pointer(&length)), 0, 0, 0, 0) - - written = int(length) - - if e1 != 0 { - err = e1 - } - return -} - func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) // SYS___SYSCTL is used by syscall_bsd.go for all BSDs, but in modern versions // of darwin/386 the syscall is called sysctl instead of __sysctl. const SYS___SYSCTL = SYS_SYSCTL + +//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64 +//sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64 +//sys Fstatfs(fd int, stat *Statfs_t) (err error) = SYS_FSTATFS64 +//sys Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) = SYS_GETDIRENTRIES64 +//sys getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) = SYS_GETFSSTAT64 +//sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64 +//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64 +//sys Statfs(path string, stat *Statfs_t) (err error) = SYS_STATFS64 diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin_amd64.go b/vendor/golang.org/x/sys/unix/syscall_darwin_amd64.go index 75219444a8..914b89bde5 100644 --- a/vendor/golang.org/x/sys/unix/syscall_darwin_amd64.go +++ b/vendor/golang.org/x/sys/unix/syscall_darwin_amd64.go @@ -8,7 +8,6 @@ package unix import ( "syscall" - "unsafe" ) func setTimespec(sec, nsec int64) Timespec { @@ -48,21 +47,17 @@ func (cmsg *Cmsghdr) SetLen(length int) { cmsg.Len = uint32(length) } -func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { - var length = uint64(count) - - _, _, e1 := Syscall6(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(unsafe.Pointer(&length)), 0, 0) - - written = int(length) - - if e1 != 0 { - err = e1 - } - return -} - func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) // SYS___SYSCTL is used by syscall_bsd.go for all BSDs, but in modern versions // of darwin/amd64 the syscall is called sysctl instead of __sysctl. const SYS___SYSCTL = SYS_SYSCTL + +//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64 +//sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64 +//sys Fstatfs(fd int, stat *Statfs_t) (err error) = SYS_FSTATFS64 +//sys Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) = SYS_GETDIRENTRIES64 +//sys getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) = SYS_GETFSSTAT64 +//sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64 +//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64 +//sys Statfs(path string, stat *Statfs_t) (err error) = SYS_STATFS64 diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin_arm.go b/vendor/golang.org/x/sys/unix/syscall_darwin_arm.go index 47ab664859..4a284cf502 100644 --- a/vendor/golang.org/x/sys/unix/syscall_darwin_arm.go +++ b/vendor/golang.org/x/sys/unix/syscall_darwin_arm.go @@ -6,7 +6,6 @@ package unix import ( "syscall" - "unsafe" ) func setTimespec(sec, nsec int64) Timespec { @@ -46,17 +45,20 @@ func (cmsg *Cmsghdr) SetLen(length int) { cmsg.Len = uint32(length) } -func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { - var length = uint64(count) - - _, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(*offset>>32), uintptr(unsafe.Pointer(&length)), 0, 0, 0, 0) - - written = int(length) - - if e1 != 0 { - err = e1 - } - return -} - func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) // sic + +// SYS___SYSCTL is used by syscall_bsd.go for all BSDs, but in modern versions +// of darwin/arm the syscall is called sysctl instead of __sysctl. +const SYS___SYSCTL = SYS_SYSCTL + +//sys Fstat(fd int, stat *Stat_t) (err error) +//sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) +//sys Fstatfs(fd int, stat *Statfs_t) (err error) +//sys getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) = SYS_GETFSSTAT +//sys Lstat(path string, stat *Stat_t) (err error) +//sys Stat(path string, stat *Stat_t) (err error) +//sys Statfs(path string, stat *Statfs_t) (err error) + +func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { + return 0, ENOSYS +} diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin_arm64.go b/vendor/golang.org/x/sys/unix/syscall_darwin_arm64.go index d6d9628014..52dcd88f6b 100644 --- a/vendor/golang.org/x/sys/unix/syscall_darwin_arm64.go +++ b/vendor/golang.org/x/sys/unix/syscall_darwin_arm64.go @@ -8,7 +8,6 @@ package unix import ( "syscall" - "unsafe" ) func setTimespec(sec, nsec int64) Timespec { @@ -48,21 +47,20 @@ func (cmsg *Cmsghdr) SetLen(length int) { cmsg.Len = uint32(length) } -func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { - var length = uint64(count) - - _, _, e1 := Syscall6(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(unsafe.Pointer(&length)), 0, 0) - - written = int(length) - - if e1 != 0 { - err = e1 - } - return -} - func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) // sic // SYS___SYSCTL is used by syscall_bsd.go for all BSDs, but in modern versions // of darwin/arm64 the syscall is called sysctl instead of __sysctl. const SYS___SYSCTL = SYS_SYSCTL + +//sys Fstat(fd int, stat *Stat_t) (err error) +//sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) +//sys Fstatfs(fd int, stat *Statfs_t) (err error) +//sys getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) = SYS_GETFSSTAT +//sys Lstat(path string, stat *Stat_t) (err error) +//sys Stat(path string, stat *Stat_t) (err error) +//sys Statfs(path string, stat *Statfs_t) (err error) + +func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { + return 0, ENOSYS +} diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin_libSystem.go b/vendor/golang.org/x/sys/unix/syscall_darwin_libSystem.go new file mode 100644 index 0000000000..4b4ae460f2 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/syscall_darwin_libSystem.go @@ -0,0 +1,31 @@ +// 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 darwin,go1.12 + +package unix + +import "unsafe" + +// Implemented in the runtime package (runtime/sys_darwin.go) +func syscall_syscall(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) +func syscall_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) +func syscall_syscall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) +func syscall_syscall9(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) // 32-bit only +func syscall_rawSyscall(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) +func syscall_rawSyscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) + +//go:linkname syscall_syscall syscall.syscall +//go:linkname syscall_syscall6 syscall.syscall6 +//go:linkname syscall_syscall6X syscall.syscall6X +//go:linkname syscall_syscall9 syscall.syscall9 +//go:linkname syscall_rawSyscall syscall.rawSyscall +//go:linkname syscall_rawSyscall6 syscall.rawSyscall6 + +// Find the entry point for f. See comments in runtime/proc.go for the +// function of the same name. +//go:nosplit +func funcPC(f func()) uintptr { + return **(**uintptr)(unsafe.Pointer(&f)) +} diff --git a/vendor/golang.org/x/sys/unix/syscall_dragonfly.go b/vendor/golang.org/x/sys/unix/syscall_dragonfly.go index 49c65ea61b..962eee3046 100644 --- a/vendor/golang.org/x/sys/unix/syscall_dragonfly.go +++ b/vendor/golang.org/x/sys/unix/syscall_dragonfly.go @@ -14,6 +14,7 @@ package unix import "unsafe" +// SockaddrDatalink implements the Sockaddr interface for AF_LINK type sockets. type SockaddrDatalink struct { Len uint8 Family uint8 @@ -56,22 +57,6 @@ func nametomib(name string) (mib []_C_int, err error) { return buf[0 : n/siz], nil } -func direntIno(buf []byte) (uint64, bool) { - return readInt(buf, unsafe.Offsetof(Dirent{}.Fileno), unsafe.Sizeof(Dirent{}.Fileno)) -} - -func direntReclen(buf []byte) (uint64, bool) { - namlen, ok := direntNamlen(buf) - if !ok { - return 0, false - } - return (16 + namlen + 1 + 7) &^ 7, true -} - -func direntNamlen(buf []byte) (uint64, bool) { - return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen)) -} - //sysnb pipe() (r int, w int, err error) func Pipe(p []int) (err error) { @@ -102,7 +87,7 @@ func Accept4(fd, flags int) (nfd int, sa Sockaddr, err error) { if len > SizeofSockaddrAny { panic("RawSockaddrAny too small") } - sa, err = anyToSockaddr(&rsa) + sa, err = anyToSockaddr(fd, &rsa) if err != nil { Close(nfd) nfd = 0 @@ -110,6 +95,23 @@ func Accept4(fd, flags int) (nfd int, sa Sockaddr, err error) { return } +const ImplementsGetwd = true + +//sys Getcwd(buf []byte) (n int, err error) = SYS___GETCWD + +func Getwd() (string, error) { + var buf [PathMax]byte + _, err := Getcwd(buf[0:]) + if err != nil { + return "", err + } + n := clen(buf[:]) + if n < 1 { + return "", EINVAL + } + return string(buf[:n]), nil +} + func Getfsstat(buf []Statfs_t, flags int) (n int, err error) { var _p0 unsafe.Pointer var bufsize uintptr @@ -141,11 +143,11 @@ func IoctlSetInt(fd int, req uint, value int) error { return ioctl(fd, req, uintptr(value)) } -func IoctlSetWinsize(fd int, req uint, value *Winsize) error { +func ioctlSetWinsize(fd int, req uint, value *Winsize) error { return ioctl(fd, req, uintptr(unsafe.Pointer(value))) } -func IoctlSetTermios(fd int, req uint, value *Termios) error { +func ioctlSetTermios(fd int, req uint, value *Termios) error { return ioctl(fd, req, uintptr(unsafe.Pointer(value))) } @@ -169,6 +171,76 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) { return &value, err } +func sysctlUname(mib []_C_int, old *byte, oldlen *uintptr) error { + err := sysctl(mib, old, oldlen, nil, 0) + if err != nil { + // Utsname members on Dragonfly are only 32 bytes and + // the syscall returns ENOMEM in case the actual value + // is longer. + if err == ENOMEM { + err = nil + } + } + return err +} + +func Uname(uname *Utsname) error { + mib := []_C_int{CTL_KERN, KERN_OSTYPE} + n := unsafe.Sizeof(uname.Sysname) + if err := sysctlUname(mib, &uname.Sysname[0], &n); err != nil { + return err + } + uname.Sysname[unsafe.Sizeof(uname.Sysname)-1] = 0 + + mib = []_C_int{CTL_KERN, KERN_HOSTNAME} + n = unsafe.Sizeof(uname.Nodename) + if err := sysctlUname(mib, &uname.Nodename[0], &n); err != nil { + return err + } + uname.Nodename[unsafe.Sizeof(uname.Nodename)-1] = 0 + + mib = []_C_int{CTL_KERN, KERN_OSRELEASE} + n = unsafe.Sizeof(uname.Release) + if err := sysctlUname(mib, &uname.Release[0], &n); err != nil { + return err + } + uname.Release[unsafe.Sizeof(uname.Release)-1] = 0 + + mib = []_C_int{CTL_KERN, KERN_VERSION} + n = unsafe.Sizeof(uname.Version) + if err := sysctlUname(mib, &uname.Version[0], &n); err != nil { + return err + } + + // The version might have newlines or tabs in it, convert them to + // spaces. + for i, b := range uname.Version { + if b == '\n' || b == '\t' { + if i == len(uname.Version)-1 { + uname.Version[i] = 0 + } else { + uname.Version[i] = ' ' + } + } + } + + mib = []_C_int{CTL_HW, HW_MACHINE} + n = unsafe.Sizeof(uname.Machine) + if err := sysctlUname(mib, &uname.Machine[0], &n); err != nil { + return err + } + uname.Machine[unsafe.Sizeof(uname.Machine)-1] = 0 + + return nil +} + +func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { + if raceenabled { + raceReleaseMerge(unsafe.Pointer(&ioSync)) + } + return sendfile(outfd, infd, offset, count) +} + /* * Exposed directly */ @@ -183,13 +255,17 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) { //sys Dup(fd int) (nfd int, err error) //sys Dup2(from int, to int) (err error) //sys Exit(code int) +//sys Faccessat(dirfd int, path string, mode uint32, flags int) (err error) //sys Fchdir(fd int) (err error) //sys Fchflags(fd int, flags int) (err error) //sys Fchmod(fd int, mode uint32) (err error) +//sys Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) //sys Fchown(fd int, uid int, gid int) (err error) +//sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) //sys Flock(fd int, how int) (err error) //sys Fpathconf(fd int, name int) (val int, err error) //sys Fstat(fd int, stat *Stat_t) (err error) +//sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) //sys Fstatfs(fd int, stat *Statfs_t) (err error) //sys Fsync(fd int) (err error) //sys Ftruncate(fd int, length int64) (err error) @@ -213,17 +289,22 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) { //sys Kqueue() (fd int, err error) //sys Lchown(path string, uid int, gid int) (err error) //sys Link(path string, link string) (err error) +//sys Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error) //sys Listen(s int, backlog int) (err error) //sys Lstat(path string, stat *Stat_t) (err error) //sys Mkdir(path string, mode uint32) (err error) +//sys Mkdirat(dirfd int, path string, mode uint32) (err error) //sys Mkfifo(path string, mode uint32) (err error) //sys Mknod(path string, mode uint32, dev int) (err error) +//sys Mknodat(fd int, path string, mode uint32, dev int) (err error) //sys Nanosleep(time *Timespec, leftover *Timespec) (err error) //sys Open(path string, mode int, perm uint32) (fd int, err error) +//sys Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) //sys Pathconf(path string, name int) (val int, err error) //sys read(fd int, p []byte) (n int, err error) //sys Readlink(path string, buf []byte) (n int, err error) //sys Rename(from string, to string) (err error) +//sys Renameat(fromfd int, from string, tofd int, to string) (err error) //sys Revoke(path string) (err error) //sys Rmdir(path string) (err error) //sys Seek(fd int, offset int64, whence int) (newoffset int64, err error) = SYS_LSEEK @@ -245,11 +326,13 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) { //sys Stat(path string, stat *Stat_t) (err error) //sys Statfs(path string, stat *Statfs_t) (err error) //sys Symlink(path string, link string) (err error) +//sys Symlinkat(oldpath string, newdirfd int, newpath string) (err error) //sys Sync() (err error) //sys Truncate(path string, length int64) (err error) //sys Umask(newmask int) (oldmask int) //sys Undelete(path string) (err error) //sys Unlink(path string) (err error) +//sys Unlinkat(dirfd int, path string, flags int) (err error) //sys Unmount(path string, flags int) (err error) //sys write(fd int, p []byte) (n int, err error) //sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) diff --git a/vendor/golang.org/x/sys/unix/syscall_freebsd.go b/vendor/golang.org/x/sys/unix/syscall_freebsd.go index a82ce127e6..a7ca1ebea3 100644 --- a/vendor/golang.org/x/sys/unix/syscall_freebsd.go +++ b/vendor/golang.org/x/sys/unix/syscall_freebsd.go @@ -12,8 +12,36 @@ package unix -import "unsafe" +import ( + "sync" + "unsafe" +) +const ( + SYS_FSTAT_FREEBSD12 = 551 // { int fstat(int fd, _Out_ struct stat *sb); } + SYS_FSTATAT_FREEBSD12 = 552 // { int fstatat(int fd, _In_z_ char *path, \ + SYS_GETDIRENTRIES_FREEBSD12 = 554 // { ssize_t getdirentries(int fd, \ + SYS_STATFS_FREEBSD12 = 555 // { int statfs(_In_z_ char *path, \ + SYS_FSTATFS_FREEBSD12 = 556 // { int fstatfs(int fd, \ + SYS_GETFSSTAT_FREEBSD12 = 557 // { int getfsstat( \ + SYS_MKNODAT_FREEBSD12 = 559 // { int mknodat(int fd, _In_z_ char *path, \ +) + +// See https://www.freebsd.org/doc/en_US.ISO8859-1/books/porters-handbook/versions.html. +var ( + osreldateOnce sync.Once + osreldate uint32 +) + +// INO64_FIRST from /usr/src/lib/libc/sys/compat-ino64.h +const _ino64First = 1200031 + +func supportsABI(ver uint32) bool { + osreldateOnce.Do(func() { osreldate, _ = SysctlUint32("kern.osreldate") }) + return osreldate >= ver +} + +// SockaddrDatalink implements the Sockaddr interface for AF_LINK type sockets. type SockaddrDatalink struct { Len uint8 Family uint8 @@ -54,26 +82,21 @@ func nametomib(name string) (mib []_C_int, err error) { return buf[0 : n/siz], nil } -func direntIno(buf []byte) (uint64, bool) { - return readInt(buf, unsafe.Offsetof(Dirent{}.Fileno), unsafe.Sizeof(Dirent{}.Fileno)) -} - -func direntReclen(buf []byte) (uint64, bool) { - return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen)) -} - -func direntNamlen(buf []byte) (uint64, bool) { - return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen)) -} - -//sysnb pipe() (r int, w int, err error) - func Pipe(p []int) (err error) { + return Pipe2(p, 0) +} + +//sysnb pipe2(p *[2]_C_int, flags int) (err error) + +func Pipe2(p []int, flags int) error { if len(p) != 2 { return EINVAL } - p[0], p[1], err = pipe() - return + var pp [2]_C_int + err := pipe2(&pp, flags) + p[0] = int(pp[0]) + p[1] = int(pp[1]) + return err } func GetsockoptIPMreqn(fd, level, opt int) (*IPMreqn, error) { @@ -97,7 +120,7 @@ func Accept4(fd, flags int) (nfd int, sa Sockaddr, err error) { if len > SizeofSockaddrAny { panic("RawSockaddrAny too small") } - sa, err = anyToSockaddr(&rsa) + sa, err = anyToSockaddr(fd, &rsa) if err != nil { Close(nfd) nfd = 0 @@ -105,18 +128,57 @@ func Accept4(fd, flags int) (nfd int, sa Sockaddr, err error) { return } -func Getfsstat(buf []Statfs_t, flags int) (n int, err error) { - var _p0 unsafe.Pointer - var bufsize uintptr - if len(buf) > 0 { - _p0 = unsafe.Pointer(&buf[0]) - bufsize = unsafe.Sizeof(Statfs_t{}) * uintptr(len(buf)) +const ImplementsGetwd = true + +//sys Getcwd(buf []byte) (n int, err error) = SYS___GETCWD + +func Getwd() (string, error) { + var buf [PathMax]byte + _, err := Getcwd(buf[0:]) + if err != nil { + return "", err } - r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), bufsize, uintptr(flags)) + n := clen(buf[:]) + if n < 1 { + return "", EINVAL + } + return string(buf[:n]), nil +} + +func Getfsstat(buf []Statfs_t, flags int) (n int, err error) { + var ( + _p0 unsafe.Pointer + bufsize uintptr + oldBuf []statfs_freebsd11_t + needsConvert bool + ) + + if len(buf) > 0 { + if supportsABI(_ino64First) { + _p0 = unsafe.Pointer(&buf[0]) + bufsize = unsafe.Sizeof(Statfs_t{}) * uintptr(len(buf)) + } else { + n := len(buf) + oldBuf = make([]statfs_freebsd11_t, n) + _p0 = unsafe.Pointer(&oldBuf[0]) + bufsize = unsafe.Sizeof(statfs_freebsd11_t{}) * uintptr(n) + needsConvert = true + } + } + var sysno uintptr = SYS_GETFSSTAT + if supportsABI(_ino64First) { + sysno = SYS_GETFSSTAT_FREEBSD12 + } + r0, _, e1 := Syscall(sysno, uintptr(_p0), bufsize, uintptr(flags)) n = int(r0) if e1 != 0 { err = e1 } + if e1 == 0 && needsConvert { + for i := range oldBuf { + buf[i].convertFrom(&oldBuf[i]) + } + } return } @@ -125,238 +187,6 @@ func setattrlistTimes(path string, times []Timespec, flags int) error { return ENOSYS } -// Derive extattr namespace and attribute name - -func xattrnamespace(fullattr string) (ns int, attr string, err error) { - s := -1 - for idx, val := range fullattr { - if val == '.' { - s = idx - break - } - } - - if s == -1 { - return -1, "", ENOATTR - } - - namespace := fullattr[0:s] - attr = fullattr[s+1:] - - switch namespace { - case "user": - return EXTATTR_NAMESPACE_USER, attr, nil - case "system": - return EXTATTR_NAMESPACE_SYSTEM, attr, nil - default: - return -1, "", ENOATTR - } -} - -func initxattrdest(dest []byte, idx int) (d unsafe.Pointer) { - if len(dest) > idx { - return unsafe.Pointer(&dest[idx]) - } else { - return unsafe.Pointer(_zero) - } -} - -// FreeBSD implements its own syscalls to handle extended attributes - -func Getxattr(file string, attr string, dest []byte) (sz int, err error) { - d := initxattrdest(dest, 0) - destsize := len(dest) - - nsid, a, err := xattrnamespace(attr) - if err != nil { - return -1, err - } - - return ExtattrGetFile(file, nsid, a, uintptr(d), destsize) -} - -func Fgetxattr(fd int, attr string, dest []byte) (sz int, err error) { - d := initxattrdest(dest, 0) - destsize := len(dest) - - nsid, a, err := xattrnamespace(attr) - if err != nil { - return -1, err - } - - return ExtattrGetFd(fd, nsid, a, uintptr(d), destsize) -} - -func Lgetxattr(link string, attr string, dest []byte) (sz int, err error) { - d := initxattrdest(dest, 0) - destsize := len(dest) - - nsid, a, err := xattrnamespace(attr) - if err != nil { - return -1, err - } - - return ExtattrGetLink(link, nsid, a, uintptr(d), destsize) -} - -// flags are unused on FreeBSD - -func Fsetxattr(fd int, attr string, data []byte, flags int) (err error) { - d := unsafe.Pointer(&data[0]) - datasiz := len(data) - - nsid, a, err := xattrnamespace(attr) - if err != nil { - return - } - - _, err = ExtattrSetFd(fd, nsid, a, uintptr(d), datasiz) - return -} - -func Setxattr(file string, attr string, data []byte, flags int) (err error) { - d := unsafe.Pointer(&data[0]) - datasiz := len(data) - - nsid, a, err := xattrnamespace(attr) - if err != nil { - return - } - - _, err = ExtattrSetFile(file, nsid, a, uintptr(d), datasiz) - return -} - -func Lsetxattr(link string, attr string, data []byte, flags int) (err error) { - d := unsafe.Pointer(&data[0]) - datasiz := len(data) - - nsid, a, err := xattrnamespace(attr) - if err != nil { - return - } - - _, err = ExtattrSetLink(link, nsid, a, uintptr(d), datasiz) - return -} - -func Removexattr(file string, attr string) (err error) { - nsid, a, err := xattrnamespace(attr) - if err != nil { - return - } - - err = ExtattrDeleteFile(file, nsid, a) - return -} - -func Fremovexattr(fd int, attr string) (err error) { - nsid, a, err := xattrnamespace(attr) - if err != nil { - return - } - - err = ExtattrDeleteFd(fd, nsid, a) - return -} - -func Lremovexattr(link string, attr string) (err error) { - nsid, a, err := xattrnamespace(attr) - if err != nil { - return - } - - err = ExtattrDeleteLink(link, nsid, a) - return -} - -func Listxattr(file string, dest []byte) (sz int, err error) { - d := initxattrdest(dest, 0) - destsiz := len(dest) - - // FreeBSD won't allow you to list xattrs from multiple namespaces - s := 0 - var e error - for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} { - stmp, e := ExtattrListFile(file, nsid, uintptr(d), destsiz) - - /* Errors accessing system attrs are ignored so that - * we can implement the Linux-like behavior of omitting errors that - * we don't have read permissions on - * - * Linux will still error if we ask for user attributes on a file that - * we don't have read permissions on, so don't ignore those errors - */ - if e != nil && e == EPERM && nsid != EXTATTR_NAMESPACE_USER { - e = nil - continue - } else if e != nil { - return s, e - } - - s += stmp - destsiz -= s - if destsiz < 0 { - destsiz = 0 - } - d = initxattrdest(dest, s) - } - - return s, e -} - -func Flistxattr(fd int, dest []byte) (sz int, err error) { - d := initxattrdest(dest, 0) - destsiz := len(dest) - - s := 0 - var e error - for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} { - stmp, e := ExtattrListFd(fd, nsid, uintptr(d), destsiz) - if e != nil && e == EPERM && nsid != EXTATTR_NAMESPACE_USER { - e = nil - continue - } else if e != nil { - return s, e - } - - s += stmp - destsiz -= s - if destsiz < 0 { - destsiz = 0 - } - d = initxattrdest(dest, s) - } - - return s, e -} - -func Llistxattr(link string, dest []byte) (sz int, err error) { - d := initxattrdest(dest, 0) - destsiz := len(dest) - - s := 0 - var e error - for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} { - stmp, e := ExtattrListLink(link, nsid, uintptr(d), destsiz) - if e != nil && e == EPERM && nsid != EXTATTR_NAMESPACE_USER { - e = nil - continue - } else if e != nil { - return s, e - } - - s += stmp - destsiz -= s - if destsiz < 0 { - destsiz = 0 - } - d = initxattrdest(dest, s) - } - - return s, e -} - //sys ioctl(fd int, req uint, arg uintptr) (err error) // ioctl itself should not be exposed directly, but additional get/set @@ -368,11 +198,11 @@ func IoctlSetInt(fd int, req uint, value int) error { return ioctl(fd, req, uintptr(value)) } -func IoctlSetWinsize(fd int, req uint, value *Winsize) error { +func ioctlSetWinsize(fd int, req uint, value *Winsize) error { return ioctl(fd, req, uintptr(unsafe.Pointer(value))) } -func IoctlSetTermios(fd int, req uint, value *Termios) error { +func ioctlSetTermios(fd int, req uint, value *Termios) error { return ioctl(fd, req, uintptr(unsafe.Pointer(value))) } @@ -396,6 +226,287 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) { return &value, err } +func Uname(uname *Utsname) error { + mib := []_C_int{CTL_KERN, KERN_OSTYPE} + n := unsafe.Sizeof(uname.Sysname) + if err := sysctl(mib, &uname.Sysname[0], &n, nil, 0); err != nil { + return err + } + + mib = []_C_int{CTL_KERN, KERN_HOSTNAME} + n = unsafe.Sizeof(uname.Nodename) + if err := sysctl(mib, &uname.Nodename[0], &n, nil, 0); err != nil { + return err + } + + mib = []_C_int{CTL_KERN, KERN_OSRELEASE} + n = unsafe.Sizeof(uname.Release) + if err := sysctl(mib, &uname.Release[0], &n, nil, 0); err != nil { + return err + } + + mib = []_C_int{CTL_KERN, KERN_VERSION} + n = unsafe.Sizeof(uname.Version) + if err := sysctl(mib, &uname.Version[0], &n, nil, 0); err != nil { + return err + } + + // The version might have newlines or tabs in it, convert them to + // spaces. + for i, b := range uname.Version { + if b == '\n' || b == '\t' { + if i == len(uname.Version)-1 { + uname.Version[i] = 0 + } else { + uname.Version[i] = ' ' + } + } + } + + mib = []_C_int{CTL_HW, HW_MACHINE} + n = unsafe.Sizeof(uname.Machine) + if err := sysctl(mib, &uname.Machine[0], &n, nil, 0); err != nil { + return err + } + + return nil +} + +func Stat(path string, st *Stat_t) (err error) { + var oldStat stat_freebsd11_t + if supportsABI(_ino64First) { + return fstatat_freebsd12(AT_FDCWD, path, st, 0) + } + err = stat(path, &oldStat) + if err != nil { + return err + } + + st.convertFrom(&oldStat) + return nil +} + +func Lstat(path string, st *Stat_t) (err error) { + var oldStat stat_freebsd11_t + if supportsABI(_ino64First) { + return fstatat_freebsd12(AT_FDCWD, path, st, AT_SYMLINK_NOFOLLOW) + } + err = lstat(path, &oldStat) + if err != nil { + return err + } + + st.convertFrom(&oldStat) + return nil +} + +func Fstat(fd int, st *Stat_t) (err error) { + var oldStat stat_freebsd11_t + if supportsABI(_ino64First) { + return fstat_freebsd12(fd, st) + } + err = fstat(fd, &oldStat) + if err != nil { + return err + } + + st.convertFrom(&oldStat) + return nil +} + +func Fstatat(fd int, path string, st *Stat_t, flags int) (err error) { + var oldStat stat_freebsd11_t + if supportsABI(_ino64First) { + return fstatat_freebsd12(fd, path, st, flags) + } + err = fstatat(fd, path, &oldStat, flags) + if err != nil { + return err + } + + st.convertFrom(&oldStat) + return nil +} + +func Statfs(path string, st *Statfs_t) (err error) { + var oldStatfs statfs_freebsd11_t + if supportsABI(_ino64First) { + return statfs_freebsd12(path, st) + } + err = statfs(path, &oldStatfs) + if err != nil { + return err + } + + st.convertFrom(&oldStatfs) + return nil +} + +func Fstatfs(fd int, st *Statfs_t) (err error) { + var oldStatfs statfs_freebsd11_t + if supportsABI(_ino64First) { + return fstatfs_freebsd12(fd, st) + } + err = fstatfs(fd, &oldStatfs) + if err != nil { + return err + } + + st.convertFrom(&oldStatfs) + return nil +} + +func Getdents(fd int, buf []byte) (n int, err error) { + return Getdirentries(fd, buf, nil) +} + +func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { + if supportsABI(_ino64First) { + return getdirentries_freebsd12(fd, buf, basep) + } + + // The old syscall entries are smaller than the new. Use 1/4 of the original + // buffer size rounded up to DIRBLKSIZ (see /usr/src/lib/libc/sys/getdirentries.c). + oldBufLen := roundup(len(buf)/4, _dirblksiz) + oldBuf := make([]byte, oldBufLen) + n, err = getdirentries(fd, oldBuf, basep) + if err == nil && n > 0 { + n = convertFromDirents11(buf, oldBuf[:n]) + } + return +} + +func Mknod(path string, mode uint32, dev uint64) (err error) { + var oldDev int + if supportsABI(_ino64First) { + return mknodat_freebsd12(AT_FDCWD, path, mode, dev) + } + oldDev = int(dev) + return mknod(path, mode, oldDev) +} + +func Mknodat(fd int, path string, mode uint32, dev uint64) (err error) { + var oldDev int + if supportsABI(_ino64First) { + return mknodat_freebsd12(fd, path, mode, dev) + } + oldDev = int(dev) + return mknodat(fd, path, mode, oldDev) +} + +// round x to the nearest multiple of y, larger or equal to x. +// +// from /usr/include/sys/param.h Macros for counting and rounding. +// #define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) +func roundup(x, y int) int { + return ((x + y - 1) / y) * y +} + +func (s *Stat_t) convertFrom(old *stat_freebsd11_t) { + *s = Stat_t{ + Dev: uint64(old.Dev), + Ino: uint64(old.Ino), + Nlink: uint64(old.Nlink), + Mode: old.Mode, + Uid: old.Uid, + Gid: old.Gid, + Rdev: uint64(old.Rdev), + Atim: old.Atim, + Mtim: old.Mtim, + Ctim: old.Ctim, + Birthtim: old.Birthtim, + Size: old.Size, + Blocks: old.Blocks, + Blksize: old.Blksize, + Flags: old.Flags, + Gen: uint64(old.Gen), + } +} + +func (s *Statfs_t) convertFrom(old *statfs_freebsd11_t) { + *s = Statfs_t{ + Version: _statfsVersion, + Type: old.Type, + Flags: old.Flags, + Bsize: old.Bsize, + Iosize: old.Iosize, + Blocks: old.Blocks, + Bfree: old.Bfree, + Bavail: old.Bavail, + Files: old.Files, + Ffree: old.Ffree, + Syncwrites: old.Syncwrites, + Asyncwrites: old.Asyncwrites, + Syncreads: old.Syncreads, + Asyncreads: old.Asyncreads, + // Spare + Namemax: old.Namemax, + Owner: old.Owner, + Fsid: old.Fsid, + // Charspare + // Fstypename + // Mntfromname + // Mntonname + } + + sl := old.Fstypename[:] + n := clen(*(*[]byte)(unsafe.Pointer(&sl))) + copy(s.Fstypename[:], old.Fstypename[:n]) + + sl = old.Mntfromname[:] + n = clen(*(*[]byte)(unsafe.Pointer(&sl))) + copy(s.Mntfromname[:], old.Mntfromname[:n]) + + sl = old.Mntonname[:] + n = clen(*(*[]byte)(unsafe.Pointer(&sl))) + copy(s.Mntonname[:], old.Mntonname[:n]) +} + +func convertFromDirents11(buf []byte, old []byte) int { + const ( + fixedSize = int(unsafe.Offsetof(Dirent{}.Name)) + oldFixedSize = int(unsafe.Offsetof(dirent_freebsd11{}.Name)) + ) + + dstPos := 0 + srcPos := 0 + for dstPos+fixedSize < len(buf) && srcPos+oldFixedSize < len(old) { + dstDirent := (*Dirent)(unsafe.Pointer(&buf[dstPos])) + srcDirent := (*dirent_freebsd11)(unsafe.Pointer(&old[srcPos])) + + reclen := roundup(fixedSize+int(srcDirent.Namlen)+1, 8) + if dstPos+reclen > len(buf) { + break + } + + dstDirent.Fileno = uint64(srcDirent.Fileno) + dstDirent.Off = 0 + dstDirent.Reclen = uint16(reclen) + dstDirent.Type = srcDirent.Type + dstDirent.Pad0 = 0 + dstDirent.Namlen = uint16(srcDirent.Namlen) + dstDirent.Pad1 = 0 + + copy(dstDirent.Name[:], srcDirent.Name[:srcDirent.Namlen]) + padding := buf[dstPos+fixedSize+int(dstDirent.Namlen) : dstPos+reclen] + for i := range padding { + padding[i] = 0 + } + + dstPos += int(dstDirent.Reclen) + srcPos += int(srcDirent.Reclen) + } + + return dstPos +} + +func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { + if raceenabled { + raceReleaseMerge(unsafe.Pointer(&ioSync)) + } + return sendfile(outfd, infd, offset, count) +} + /* * Exposed directly */ @@ -435,11 +546,16 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) { //sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) //sys Flock(fd int, how int) (err error) //sys Fpathconf(fd int, name int) (val int, err error) -//sys Fstat(fd int, stat *Stat_t) (err error) -//sys Fstatfs(fd int, stat *Statfs_t) (err error) +//sys fstat(fd int, stat *stat_freebsd11_t) (err error) +//sys fstat_freebsd12(fd int, stat *Stat_t) (err error) +//sys fstatat(fd int, path string, stat *stat_freebsd11_t, flags int) (err error) +//sys fstatat_freebsd12(fd int, path string, stat *Stat_t, flags int) (err error) +//sys fstatfs(fd int, stat *statfs_freebsd11_t) (err error) +//sys fstatfs_freebsd12(fd int, stat *Statfs_t) (err error) //sys Fsync(fd int) (err error) //sys Ftruncate(fd int, length int64) (err error) -//sys Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) +//sys getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) +//sys getdirentries_freebsd12(fd int, buf []byte, basep *uintptr) (n int, err error) //sys Getdtablesize() (size int) //sysnb Getegid() (egid int) //sysnb Geteuid() (uid int) @@ -461,11 +577,13 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) { //sys Link(path string, link string) (err error) //sys Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error) //sys Listen(s int, backlog int) (err error) -//sys Lstat(path string, stat *Stat_t) (err error) +//sys lstat(path string, stat *stat_freebsd11_t) (err error) //sys Mkdir(path string, mode uint32) (err error) //sys Mkdirat(dirfd int, path string, mode uint32) (err error) //sys Mkfifo(path string, mode uint32) (err error) -//sys Mknod(path string, mode uint32, dev int) (err error) +//sys mknod(path string, mode uint32, dev int) (err error) +//sys mknodat(fd int, path string, mode uint32, dev int) (err error) +//sys mknodat_freebsd12(fd int, path string, mode uint32, dev uint64) (err error) //sys Nanosleep(time *Timespec, leftover *Timespec) (err error) //sys Open(path string, mode int, perm uint32) (fd int, err error) //sys Openat(fdat int, path string, mode int, perm uint32) (fd int, err error) @@ -495,8 +613,9 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) { //sysnb Setsid() (pid int, err error) //sysnb Settimeofday(tp *Timeval) (err error) //sysnb Setuid(uid int) (err error) -//sys Stat(path string, stat *Stat_t) (err error) -//sys Statfs(path string, stat *Statfs_t) (err error) +//sys stat(path string, stat *stat_freebsd11_t) (err error) +//sys statfs(path string, stat *statfs_freebsd11_t) (err error) +//sys statfs_freebsd12(path string, stat *Statfs_t) (err error) //sys Symlink(path string, link string) (err error) //sys Symlinkat(oldpath string, newdirfd int, newpath string) (err error) //sys Sync() (err error) @@ -551,6 +670,7 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) { // Kqueue_portset // Getattrlist // Setattrlist +// Getdents // Getdirentriesattr // Searchfs // Delete @@ -558,14 +678,6 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) { // Watchevent // Waitevent // Modwatch -// Getxattr -// Fgetxattr -// Setxattr -// Fsetxattr -// Removexattr -// Fremovexattr -// Listxattr -// Flistxattr // Fsctl // Initgroups // Posix_spawn diff --git a/vendor/golang.org/x/sys/unix/syscall_freebsd_arm64.go b/vendor/golang.org/x/sys/unix/syscall_freebsd_arm64.go new file mode 100644 index 0000000000..a318054878 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/syscall_freebsd_arm64.go @@ -0,0 +1,52 @@ +// 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 arm64,freebsd + +package unix + +import ( + "syscall" + "unsafe" +) + +func setTimespec(sec, nsec int64) Timespec { + return Timespec{Sec: sec, Nsec: nsec} +} + +func setTimeval(sec, usec int64) Timeval { + return Timeval{Sec: sec, Usec: usec} +} + +func SetKevent(k *Kevent_t, fd, mode, flags int) { + k.Ident = uint64(fd) + k.Filter = int16(mode) + k.Flags = uint16(flags) +} + +func (iov *Iovec) SetLen(length int) { + iov.Len = uint64(length) +} + +func (msghdr *Msghdr) SetControllen(length int) { + msghdr.Controllen = uint32(length) +} + +func (cmsg *Cmsghdr) SetLen(length int) { + cmsg.Len = uint32(length) +} + +func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { + var writtenOut uint64 = 0 + _, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(count), 0, uintptr(unsafe.Pointer(&writtenOut)), 0, 0, 0) + + written = int(writtenOut) + + if e1 != 0 { + err = e1 + } + return +} + +func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) diff --git a/vendor/golang.org/x/sys/unix/syscall_linux.go b/vendor/golang.org/x/sys/unix/syscall_linux.go index 9098661a3c..a07ee49ea3 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux.go @@ -12,6 +12,9 @@ package unix import ( + "encoding/binary" + "net" + "runtime" "syscall" "unsafe" ) @@ -55,20 +58,35 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { // ioctl itself should not be exposed directly, but additional get/set // functions for specific types are permissible. +// IoctlSetPointerInt performs an ioctl operation which sets an +// integer value on fd, using the specified request number. The ioctl +// argument is called with a pointer to the integer value, rather than +// passing the integer value directly. +func IoctlSetPointerInt(fd int, req uint, value int) error { + v := int32(value) + return ioctl(fd, req, uintptr(unsafe.Pointer(&v))) +} + // IoctlSetInt performs an ioctl operation which sets an integer value // on fd, using the specified request number. func IoctlSetInt(fd int, req uint, value int) error { return ioctl(fd, req, uintptr(value)) } -func IoctlSetWinsize(fd int, req uint, value *Winsize) error { +func ioctlSetWinsize(fd int, req uint, value *Winsize) error { return ioctl(fd, req, uintptr(unsafe.Pointer(value))) } -func IoctlSetTermios(fd int, req uint, value *Termios) error { +func ioctlSetTermios(fd int, req uint, value *Termios) error { return ioctl(fd, req, uintptr(unsafe.Pointer(value))) } +func IoctlSetRTCTime(fd int, value *RTCTime) error { + err := ioctl(fd, RTC_SET_TIME, uintptr(unsafe.Pointer(value))) + runtime.KeepAlive(value) + return err +} + // IoctlGetInt performs an ioctl operation which gets an integer value // from fd, using the specified request number. func IoctlGetInt(fd int, req uint) (int, error) { @@ -89,6 +107,12 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) { return &value, err } +func IoctlGetRTCTime(fd int) (*RTCTime, error) { + var value RTCTime + err := ioctl(fd, RTC_RD_TIME, uintptr(unsafe.Pointer(&value))) + return &value, err +} + //sys Linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) func Link(oldpath string, newpath string) (err error) { @@ -148,8 +172,6 @@ func Unlink(path string) error { //sys Unlinkat(dirfd int, path string, flags int) (err error) -//sys utimes(path string, times *[2]Timeval) (err error) - func Utimes(path string, tv []Timeval) error { if tv == nil { err := utimensat(AT_FDCWD, path, nil, 0) @@ -207,20 +229,14 @@ func UtimesNanoAt(dirfd int, path string, ts []Timespec, flags int) error { return utimensat(dirfd, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), flags) } -//sys futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) - func Futimesat(dirfd int, path string, tv []Timeval) error { - pathp, err := BytePtrFromString(path) - if err != nil { - return err - } if tv == nil { - return futimesat(dirfd, pathp, nil) + return futimesat(dirfd, path, nil) } if len(tv) != 2 { return EINVAL } - return futimesat(dirfd, pathp, (*[2]Timeval)(unsafe.Pointer(&tv[0]))) + return futimesat(dirfd, path, (*[2]Timeval)(unsafe.Pointer(&tv[0]))) } func Futimes(fd int, tv []Timeval) (err error) { @@ -413,6 +429,7 @@ func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, _Socklen, error) { return unsafe.Pointer(&sa.raw), sl, nil } +// SockaddrLinklayer implements the Sockaddr interface for AF_PACKET type sockets. type SockaddrLinklayer struct { Protocol uint16 Ifindex int @@ -439,6 +456,7 @@ func (sa *SockaddrLinklayer) sockaddr() (unsafe.Pointer, _Socklen, error) { return unsafe.Pointer(&sa.raw), SizeofSockaddrLinklayer, nil } +// SockaddrNetlink implements the Sockaddr interface for AF_NETLINK type sockets. type SockaddrNetlink struct { Family uint16 Pad uint16 @@ -455,6 +473,8 @@ func (sa *SockaddrNetlink) sockaddr() (unsafe.Pointer, _Socklen, error) { return unsafe.Pointer(&sa.raw), SizeofSockaddrNetlink, nil } +// SockaddrHCI implements the Sockaddr interface for AF_BLUETOOTH type sockets +// using the HCI protocol. type SockaddrHCI struct { Dev uint16 Channel uint16 @@ -468,6 +488,72 @@ func (sa *SockaddrHCI) sockaddr() (unsafe.Pointer, _Socklen, error) { return unsafe.Pointer(&sa.raw), SizeofSockaddrHCI, nil } +// SockaddrL2 implements the Sockaddr interface for AF_BLUETOOTH type sockets +// using the L2CAP protocol. +type SockaddrL2 struct { + PSM uint16 + CID uint16 + Addr [6]uint8 + AddrType uint8 + raw RawSockaddrL2 +} + +func (sa *SockaddrL2) sockaddr() (unsafe.Pointer, _Socklen, error) { + sa.raw.Family = AF_BLUETOOTH + psm := (*[2]byte)(unsafe.Pointer(&sa.raw.Psm)) + psm[0] = byte(sa.PSM) + psm[1] = byte(sa.PSM >> 8) + for i := 0; i < len(sa.Addr); i++ { + sa.raw.Bdaddr[i] = sa.Addr[len(sa.Addr)-1-i] + } + cid := (*[2]byte)(unsafe.Pointer(&sa.raw.Cid)) + cid[0] = byte(sa.CID) + cid[1] = byte(sa.CID >> 8) + sa.raw.Bdaddr_type = sa.AddrType + return unsafe.Pointer(&sa.raw), SizeofSockaddrL2, nil +} + +// SockaddrRFCOMM implements the Sockaddr interface for AF_BLUETOOTH type sockets +// using the RFCOMM protocol. +// +// Server example: +// +// fd, _ := Socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM) +// _ = unix.Bind(fd, &unix.SockaddrRFCOMM{ +// Channel: 1, +// Addr: [6]uint8{0, 0, 0, 0, 0, 0}, // BDADDR_ANY or 00:00:00:00:00:00 +// }) +// _ = Listen(fd, 1) +// nfd, sa, _ := Accept(fd) +// fmt.Printf("conn addr=%v fd=%d", sa.(*unix.SockaddrRFCOMM).Addr, nfd) +// Read(nfd, buf) +// +// Client example: +// +// fd, _ := Socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM) +// _ = Connect(fd, &SockaddrRFCOMM{ +// Channel: 1, +// Addr: [6]byte{0x11, 0x22, 0x33, 0xaa, 0xbb, 0xcc}, // CC:BB:AA:33:22:11 +// }) +// Write(fd, []byte(`hello`)) +type SockaddrRFCOMM struct { + // Addr represents a bluetooth address, byte ordering is little-endian. + Addr [6]uint8 + + // Channel is a designated bluetooth channel, only 1-30 are available for use. + // Since Linux 2.6.7 and further zero value is the first available channel. + Channel uint8 + + raw RawSockaddrRFCOMM +} + +func (sa *SockaddrRFCOMM) sockaddr() (unsafe.Pointer, _Socklen, error) { + sa.raw.Family = AF_BLUETOOTH + sa.raw.Channel = sa.Channel + sa.raw.Bdaddr = sa.Addr + return unsafe.Pointer(&sa.raw), SizeofSockaddrRFCOMM, nil +} + // SockaddrCAN implements the Sockaddr interface for AF_CAN type sockets. // The RxID and TxID fields are used for transport protocol addressing in // (CAN_TP16, CAN_TP20, CAN_MCNET, and CAN_ISOTP), they can be left with @@ -630,7 +716,70 @@ func (sa *SockaddrVM) sockaddr() (unsafe.Pointer, _Socklen, error) { return unsafe.Pointer(&sa.raw), SizeofSockaddrVM, nil } -func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) { +type SockaddrXDP struct { + Flags uint16 + Ifindex uint32 + QueueID uint32 + SharedUmemFD uint32 + raw RawSockaddrXDP +} + +func (sa *SockaddrXDP) sockaddr() (unsafe.Pointer, _Socklen, error) { + sa.raw.Family = AF_XDP + sa.raw.Flags = sa.Flags + sa.raw.Ifindex = sa.Ifindex + sa.raw.Queue_id = sa.QueueID + sa.raw.Shared_umem_fd = sa.SharedUmemFD + + return unsafe.Pointer(&sa.raw), SizeofSockaddrXDP, nil +} + +// This constant mirrors the #define of PX_PROTO_OE in +// linux/if_pppox.h. We're defining this by hand here instead of +// autogenerating through mkerrors.sh because including +// linux/if_pppox.h causes some declaration conflicts with other +// includes (linux/if_pppox.h includes linux/in.h, which conflicts +// with netinet/in.h). Given that we only need a single zero constant +// out of that file, it's cleaner to just define it by hand here. +const px_proto_oe = 0 + +type SockaddrPPPoE struct { + SID uint16 + Remote net.HardwareAddr + Dev string + raw RawSockaddrPPPoX +} + +func (sa *SockaddrPPPoE) sockaddr() (unsafe.Pointer, _Socklen, error) { + if len(sa.Remote) != 6 { + return nil, 0, EINVAL + } + if len(sa.Dev) > IFNAMSIZ-1 { + return nil, 0, EINVAL + } + + *(*uint16)(unsafe.Pointer(&sa.raw[0])) = AF_PPPOX + // This next field is in host-endian byte order. We can't use the + // same unsafe pointer cast as above, because this value is not + // 32-bit aligned and some architectures don't allow unaligned + // access. + // + // However, the value of px_proto_oe is 0, so we can use + // encoding/binary helpers to write the bytes without worrying + // about the ordering. + binary.BigEndian.PutUint32(sa.raw[2:6], px_proto_oe) + // This field is deliberately big-endian, unlike the previous + // one. The kernel expects SID to be in network byte order. + binary.BigEndian.PutUint16(sa.raw[6:8], sa.SID) + copy(sa.raw[8:14], sa.Remote) + for i := 14; i < 14+IFNAMSIZ; i++ { + sa.raw[i] = 0 + } + copy(sa.raw[14:], sa.Dev) + return unsafe.Pointer(&sa.raw), SizeofSockaddrPPPoX, nil +} + +func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { switch rsa.Addr.Family { case AF_NETLINK: pp := (*RawSockaddrNetlink)(unsafe.Pointer(rsa)) @@ -707,6 +856,55 @@ func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) { Port: pp.Port, } return sa, nil + case AF_BLUETOOTH: + proto, err := GetsockoptInt(fd, SOL_SOCKET, SO_PROTOCOL) + if err != nil { + return nil, err + } + // only BTPROTO_L2CAP and BTPROTO_RFCOMM can accept connections + switch proto { + case BTPROTO_L2CAP: + pp := (*RawSockaddrL2)(unsafe.Pointer(rsa)) + sa := &SockaddrL2{ + PSM: pp.Psm, + CID: pp.Cid, + Addr: pp.Bdaddr, + AddrType: pp.Bdaddr_type, + } + return sa, nil + case BTPROTO_RFCOMM: + pp := (*RawSockaddrRFCOMM)(unsafe.Pointer(rsa)) + sa := &SockaddrRFCOMM{ + Channel: pp.Channel, + Addr: pp.Bdaddr, + } + return sa, nil + } + case AF_XDP: + pp := (*RawSockaddrXDP)(unsafe.Pointer(rsa)) + sa := &SockaddrXDP{ + Flags: pp.Flags, + Ifindex: pp.Ifindex, + QueueID: pp.Queue_id, + SharedUmemFD: pp.Shared_umem_fd, + } + return sa, nil + case AF_PPPOX: + pp := (*RawSockaddrPPPoX)(unsafe.Pointer(rsa)) + if binary.BigEndian.Uint32(pp[2:6]) != px_proto_oe { + return nil, EINVAL + } + sa := &SockaddrPPPoE{ + SID: binary.BigEndian.Uint16(pp[6:8]), + Remote: net.HardwareAddr(pp[8:14]), + } + for i := 14; i < 14+IFNAMSIZ; i++ { + if pp[i] == 0 { + sa.Dev = string(pp[14:i]) + break + } + } + return sa, nil } return nil, EAFNOSUPPORT } @@ -718,7 +916,7 @@ func Accept(fd int) (nfd int, sa Sockaddr, err error) { if err != nil { return } - sa, err = anyToSockaddr(&rsa) + sa, err = anyToSockaddr(fd, &rsa) if err != nil { Close(nfd) nfd = 0 @@ -736,7 +934,7 @@ func Accept4(fd int, flags int) (nfd int, sa Sockaddr, err error) { if len > SizeofSockaddrAny { panic("RawSockaddrAny too small") } - sa, err = anyToSockaddr(&rsa) + sa, err = anyToSockaddr(fd, &rsa) if err != nil { Close(nfd) nfd = 0 @@ -750,20 +948,7 @@ func Getsockname(fd int) (sa Sockaddr, err error) { if err = getsockname(fd, &rsa, &len); err != nil { return } - return anyToSockaddr(&rsa) -} - -func GetsockoptInet4Addr(fd, level, opt int) (value [4]byte, err error) { - vallen := _Socklen(4) - err = getsockopt(fd, level, opt, unsafe.Pointer(&value[0]), &vallen) - return value, err -} - -func GetsockoptIPMreq(fd, level, opt int) (*IPMreq, error) { - var value IPMreq - vallen := _Socklen(SizeofIPMreq) - err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen) - return &value, err + return anyToSockaddr(fd, &rsa) } func GetsockoptIPMreqn(fd, level, opt int) (*IPMreqn, error) { @@ -773,27 +958,6 @@ func GetsockoptIPMreqn(fd, level, opt int) (*IPMreqn, error) { return &value, err } -func GetsockoptIPv6Mreq(fd, level, opt int) (*IPv6Mreq, error) { - var value IPv6Mreq - vallen := _Socklen(SizeofIPv6Mreq) - err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen) - return &value, err -} - -func GetsockoptIPv6MTUInfo(fd, level, opt int) (*IPv6MTUInfo, error) { - var value IPv6MTUInfo - vallen := _Socklen(SizeofIPv6MTUInfo) - err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen) - return &value, err -} - -func GetsockoptICMPv6Filter(fd, level, opt int) (*ICMPv6Filter, error) { - var value ICMPv6Filter - vallen := _Socklen(SizeofICMPv6Filter) - err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen) - return &value, err -} - func GetsockoptUcred(fd, level, opt int) (*Ucred, error) { var value Ucred vallen := _Socklen(SizeofUcred) @@ -808,6 +972,24 @@ func GetsockoptTCPInfo(fd, level, opt int) (*TCPInfo, error) { return &value, err } +// GetsockoptString returns the string value of the socket option opt for the +// socket associated with fd at the given socket level. +func GetsockoptString(fd, level, opt int) (string, error) { + buf := make([]byte, 256) + vallen := _Socklen(len(buf)) + err := getsockopt(fd, level, opt, unsafe.Pointer(&buf[0]), &vallen) + if err != nil { + if err == ERANGE { + buf = make([]byte, vallen) + err = getsockopt(fd, level, opt, unsafe.Pointer(&buf[0]), &vallen) + } + if err != nil { + return "", err + } + } + return string(buf[:vallen-1]), nil +} + func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) (err error) { return setsockopt(fd, level, opt, unsafe.Pointer(mreq), unsafe.Sizeof(*mreq)) } @@ -931,15 +1113,17 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from } var dummy byte if len(oob) > 0 { - var sockType int - sockType, err = GetsockoptInt(fd, SOL_SOCKET, SO_TYPE) - if err != nil { - return - } - // receive at least one normal byte - if sockType != SOCK_DGRAM && len(p) == 0 { - iov.Base = &dummy - iov.SetLen(1) + if len(p) == 0 { + var sockType int + sockType, err = GetsockoptInt(fd, SOL_SOCKET, SO_TYPE) + if err != nil { + return + } + // receive at least one normal byte + if sockType != SOCK_DGRAM { + iov.Base = &dummy + iov.SetLen(1) + } } msg.Control = &oob[0] msg.SetControllen(len(oob)) @@ -953,7 +1137,7 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from recvflags = int(msg.Flags) // source address is only specified if the socket is unconnected if rsa.Addr.Family != AF_UNSPEC { - from, err = anyToSockaddr(&rsa) + from, err = anyToSockaddr(fd, &rsa) } return } @@ -983,15 +1167,17 @@ func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) } var dummy byte if len(oob) > 0 { - var sockType int - sockType, err = GetsockoptInt(fd, SOL_SOCKET, SO_TYPE) - if err != nil { - return 0, err - } - // send at least one normal byte - if sockType != SOCK_DGRAM && len(p) == 0 { - iov.Base = &dummy - iov.SetLen(1) + if len(p) == 0 { + var sockType int + sockType, err = GetsockoptInt(fd, SOL_SOCKET, SO_TYPE) + if err != nil { + return 0, err + } + // send at least one normal byte + if sockType != SOCK_DGRAM { + iov.Base = &dummy + iov.SetLen(1) + } } msg.Control = &oob[0] msg.SetControllen(len(oob)) @@ -1021,7 +1207,7 @@ func ptracePeek(req int, pid int, addr uintptr, out []byte) (count int, err erro // The ptrace syscall differs from glibc's ptrace. // Peeks returns the word in *data, not as the return value. - var buf [sizeofPtr]byte + var buf [SizeofPtr]byte // Leading edge. PEEKTEXT/PEEKDATA don't require aligned // access (PEEKUSER warns that it might), but if we don't @@ -1029,12 +1215,12 @@ func ptracePeek(req int, pid int, addr uintptr, out []byte) (count int, err erro // boundary and not get the bytes leading up to the page // boundary. n := 0 - if addr%sizeofPtr != 0 { - err = ptrace(req, pid, addr-addr%sizeofPtr, uintptr(unsafe.Pointer(&buf[0]))) + if addr%SizeofPtr != 0 { + err = ptrace(req, pid, addr-addr%SizeofPtr, uintptr(unsafe.Pointer(&buf[0]))) if err != nil { return 0, err } - n += copy(out, buf[addr%sizeofPtr:]) + n += copy(out, buf[addr%SizeofPtr:]) out = out[n:] } @@ -1072,15 +1258,15 @@ func ptracePoke(pokeReq int, peekReq int, pid int, addr uintptr, data []byte) (c // Leading edge. n := 0 - if addr%sizeofPtr != 0 { - var buf [sizeofPtr]byte - err = ptrace(peekReq, pid, addr-addr%sizeofPtr, uintptr(unsafe.Pointer(&buf[0]))) + if addr%SizeofPtr != 0 { + var buf [SizeofPtr]byte + err = ptrace(peekReq, pid, addr-addr%SizeofPtr, uintptr(unsafe.Pointer(&buf[0]))) if err != nil { return 0, err } - n += copy(buf[addr%sizeofPtr:], data) + n += copy(buf[addr%SizeofPtr:], data) word := *((*uintptr)(unsafe.Pointer(&buf[0]))) - err = ptrace(pokeReq, pid, addr-addr%sizeofPtr, word) + err = ptrace(pokeReq, pid, addr-addr%SizeofPtr, word) if err != nil { return 0, err } @@ -1088,19 +1274,19 @@ func ptracePoke(pokeReq int, peekReq int, pid int, addr uintptr, data []byte) (c } // Interior. - for len(data) > sizeofPtr { + for len(data) > SizeofPtr { word := *((*uintptr)(unsafe.Pointer(&data[0]))) err = ptrace(pokeReq, pid, addr+uintptr(n), word) if err != nil { return n, err } - n += sizeofPtr - data = data[sizeofPtr:] + n += SizeofPtr + data = data[SizeofPtr:] } // Trailing edge. if len(data) > 0 { - var buf [sizeofPtr]byte + var buf [SizeofPtr]byte err = ptrace(peekReq, pid, addr+uintptr(n), uintptr(unsafe.Pointer(&buf[0]))) if err != nil { return n, err @@ -1172,22 +1358,6 @@ func ReadDirent(fd int, buf []byte) (n int, err error) { return Getdents(fd, buf) } -func direntIno(buf []byte) (uint64, bool) { - return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino)) -} - -func direntReclen(buf []byte) (uint64, bool) { - return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen)) -} - -func direntNamlen(buf []byte) (uint64, bool) { - reclen, ok := direntReclen(buf) - if !ok { - return 0, false - } - return reclen - uint64(unsafe.Offsetof(Dirent{}.Name)), true -} - //sys mount(source string, target string, fstype string, flags uintptr, data *byte) (err error) func Mount(source string, target string, fstype string, flags uintptr, data string) (err error) { @@ -1203,6 +1373,13 @@ func Mount(source string, target string, fstype string, flags uintptr, data stri return mount(source, target, fstype, flags, datap) } +func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { + if raceenabled { + raceReleaseMerge(unsafe.Pointer(&ioSync)) + } + return sendfile(outfd, infd, offset, count) +} + // Sendto // Recvfrom // Socketpair @@ -1215,24 +1392,30 @@ func Mount(source string, target string, fstype string, flags uintptr, data stri //sys Adjtimex(buf *Timex) (state int, err error) //sys Chdir(path string) (err error) //sys Chroot(path string) (err error) +//sys ClockGetres(clockid int32, res *Timespec) (err error) //sys ClockGettime(clockid int32, time *Timespec) (err error) +//sys ClockNanosleep(clockid int32, flags int, request *Timespec, remain *Timespec) (err error) //sys Close(fd int) (err error) //sys CopyFileRange(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, err error) +//sys DeleteModule(name string, flags int) (err error) //sys Dup(oldfd int) (fd int, err error) //sys Dup3(oldfd int, newfd int, flags int) (err error) -//sysnb EpollCreate(size int) (fd int, err error) //sysnb EpollCreate1(flag int) (fd int, err error) //sysnb EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) //sys Eventfd(initval uint, flags int) (fd int, err error) = SYS_EVENTFD2 //sys Exit(code int) = SYS_EXIT_GROUP -//sys Faccessat(dirfd int, path string, mode uint32, flags int) (err error) //sys Fallocate(fd int, mode uint32, off int64, len int64) (err error) //sys Fchdir(fd int) (err error) //sys Fchmod(fd int, mode uint32) (err error) //sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) //sys fcntl(fd int, cmd int, arg int) (val int, err error) //sys Fdatasync(fd int) (err error) +//sys Fgetxattr(fd int, attr string, dest []byte) (sz int, err error) +//sys FinitModule(fd int, params string, flags int) (err error) +//sys Flistxattr(fd int, dest []byte) (sz int, err error) //sys Flock(fd int, how int) (err error) +//sys Fremovexattr(fd int, attr string) (err error) +//sys Fsetxattr(fd int, attr string, dest []byte, flags int) (err error) //sys Fsync(fd int) (err error) //sys Getdents(fd int, buf []byte) (n int, err error) = SYS_GETDENTS64 //sysnb Getpgid(pid int) (pgid int, err error) @@ -1250,6 +1433,7 @@ func Getpgrp() (pid int) { //sysnb Getsid(pid int) (sid int, err error) //sysnb Gettid() (tid int) //sys Getxattr(path string, attr string, dest []byte) (sz int, err error) +//sys InitModule(moduleImage []byte, params string) (err error) //sys InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err error) //sysnb InotifyInit1(flags int) (fd int, err error) //sysnb InotifyRmWatch(fd int, watchdesc uint32) (success int, err error) @@ -1260,16 +1444,18 @@ func Getpgrp() (pid int) { //sys Llistxattr(path string, dest []byte) (sz int, err error) //sys Lremovexattr(path string, attr string) (err error) //sys Lsetxattr(path string, attr string, data []byte, flags int) (err error) +//sys MemfdCreate(name string, flags int) (fd int, err error) //sys Mkdirat(dirfd int, path string, mode uint32) (err error) //sys Mknodat(dirfd int, path string, mode uint32, dev int) (err error) //sys Nanosleep(time *Timespec, leftover *Timespec) (err error) +//sys PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error) //sys PivotRoot(newroot string, putold string) (err error) = SYS_PIVOT_ROOT //sysnb prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) = SYS_PRLIMIT64 //sys Prctl(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uintptr) (err error) //sys Pselect(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *Sigset_t) (n int, err error) = SYS_PSELECT6 //sys read(fd int, p []byte) (n int, err error) //sys Removexattr(path string, attr string) (err error) -//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) +//sys Renameat2(olddirfd int, oldpath string, newdirfd int, newpath string, flags uint) (err error) //sys RequestKey(keyType string, description string, callback string, destRingid int) (id int, err error) //sys Setdomainname(p []byte) (err error) //sys Sethostname(p []byte) (err error) @@ -1293,6 +1479,8 @@ func Setgid(uid int) (err error) { //sys Setpriority(which int, who int, prio int) (err error) //sys Setxattr(path string, attr string, data []byte, flags int) (err error) +//sys Signalfd(fd int, mask *Sigset_t, flags int) = SYS_SIGNALFD4 +//sys Statx(dirfd int, path string, flags int, mask int, stat *Statx_t) (err error) //sys Sync() //sys Syncfs(fd int) (err error) //sysnb Sysinfo(info *Sysinfo_t) (err error) @@ -1303,7 +1491,6 @@ func Setgid(uid int) (err error) { //sysnb Uname(buf *Utsname) (err error) //sys Unmount(target string, flags int) (err error) = SYS_UMOUNT2 //sys Unshare(flags int) (err error) -//sys Ustat(dev int, ubuf *Ustat_t) (err error) //sys write(fd int, p []byte) (n int, err error) //sys exitThread(code int) (err error) = SYS_EXIT //sys readlen(fd int, p *byte, np int) (n int, err error) = SYS_READ @@ -1337,15 +1524,12 @@ func Munmap(b []byte) (err error) { // Vmsplice splices user pages from a slice of Iovecs into a pipe specified by fd, // using the specified flags. func Vmsplice(fd int, iovs []Iovec, flags int) (int, error) { - n, _, errno := Syscall6( - SYS_VMSPLICE, - uintptr(fd), - uintptr(unsafe.Pointer(&iovs[0])), - uintptr(len(iovs)), - uintptr(flags), - 0, - 0, - ) + var p unsafe.Pointer + if len(iovs) > 0 { + p = unsafe.Pointer(&iovs[0]) + } + + n, _, errno := Syscall6(SYS_VMSPLICE, uintptr(fd), uintptr(p), uintptr(len(iovs)), uintptr(flags), 0, 0) if errno != 0 { return 0, syscall.Errno(errno) } @@ -1353,6 +1537,77 @@ func Vmsplice(fd int, iovs []Iovec, flags int) (int, error) { return int(n), nil } +//sys faccessat(dirfd int, path string, mode uint32) (err error) + +func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { + if flags & ^(AT_SYMLINK_NOFOLLOW|AT_EACCESS) != 0 { + return EINVAL + } + + // The Linux kernel faccessat system call does not take any flags. + // The glibc faccessat implements the flags itself; see + // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/faccessat.c;hb=HEAD + // Because people naturally expect syscall.Faccessat to act + // like C faccessat, we do the same. + + if flags == 0 { + return faccessat(dirfd, path, mode) + } + + var st Stat_t + if err := Fstatat(dirfd, path, &st, flags&AT_SYMLINK_NOFOLLOW); err != nil { + return err + } + + mode &= 7 + if mode == 0 { + return nil + } + + var uid int + if flags&AT_EACCESS != 0 { + uid = Geteuid() + } else { + uid = Getuid() + } + + if uid == 0 { + if mode&1 == 0 { + // Root can read and write any file. + return nil + } + if st.Mode&0111 != 0 { + // Root can execute any file that anybody can execute. + return nil + } + return EACCES + } + + var fmode uint32 + if uint32(uid) == st.Uid { + fmode = (st.Mode >> 6) & 7 + } else { + var gid int + if flags&AT_EACCESS != 0 { + gid = Getegid() + } else { + gid = Getgid() + } + + if uint32(gid) == st.Gid { + fmode = (st.Mode >> 3) & 7 + } else { + fmode = st.Mode & 7 + } + } + + if fmode&mode == mode { + return nil + } + + return EACCES +} + /* * Unimplemented */ @@ -1362,21 +1617,14 @@ func Vmsplice(fd int, iovs []Iovec, flags int) (int, error) { // Brk // Capget // Capset -// ClockGetres // ClockNanosleep // ClockSettime // Clone -// CreateModule -// DeleteModule // EpollCtlOld // EpollPwait // EpollWaitOld // Execve -// Fgetxattr -// Flistxattr // Fork -// Fremovexattr -// Fsetxattr // Futex // GetKernelSyms // GetMempolicy @@ -1410,13 +1658,11 @@ func Vmsplice(fd int, iovs []Iovec, flags int) (int, error) { // Msgget // Msgrcv // Msgsnd -// Newfstatat // Nfsservctl // Personality // Pselect6 // Ptrace // Putpmsg -// QueryModule // Quotactl // Readahead // Readv @@ -1431,11 +1677,9 @@ func Vmsplice(fd int, iovs []Iovec, flags int) (int, error) { // RtSigtimedwait // SchedGetPriorityMax // SchedGetPriorityMin -// SchedGetaffinity // SchedGetparam // SchedGetscheduler // SchedRrGetInterval -// SchedSetaffinity // SchedSetparam // SchedYield // Security @@ -1452,7 +1696,6 @@ func Vmsplice(fd int, iovs []Iovec, flags int) (int, error) { // Shmdt // Shmget // Sigaltstack -// Signalfd // Swapoff // Swapon // Sysfs diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_386.go b/vendor/golang.org/x/sys/unix/syscall_linux_386.go index 4774fa363e..e2f8cf6e5a 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_386.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_386.go @@ -10,7 +10,6 @@ package unix import ( - "syscall" "unsafe" ) @@ -51,9 +50,12 @@ func Pipe2(p []int, flags int) (err error) { // 64-bit file system and 32-bit uid calls // (386 default is 32-bit file system and 16-bit uid). //sys Dup2(oldfd int, newfd int) (err error) +//sysnb EpollCreate(size int) (fd int, err error) +//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) //sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64_64 //sys Fchown(fd int, uid int, gid int) (err error) = SYS_FCHOWN32 //sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64 +//sys Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64 //sys Ftruncate(fd int, length int64) (err error) = SYS_FTRUNCATE64 //sysnb Getegid() (egid int) = SYS_GETEGID32 //sysnb Geteuid() (euid int) = SYS_GETEUID32 @@ -66,6 +68,7 @@ func Pipe2(p []int, flags int) (err error) { //sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64 //sys Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64 //sys Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64 +//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) //sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) = SYS_SENDFILE64 //sys Setfsgid(gid int) (err error) = SYS_SETFSGID32 //sys Setfsuid(uid int) (err error) = SYS_SETFSUID32 @@ -77,12 +80,12 @@ func Pipe2(p []int, flags int) (err error) { //sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64 //sys SyncFileRange(fd int, off int64, n int64, flags int) (err error) //sys Truncate(path string, length int64) (err error) = SYS_TRUNCATE64 +//sys Ustat(dev int, ubuf *Ustat_t) (err error) //sysnb getgroups(n int, list *_Gid_t) (nn int, err error) = SYS_GETGROUPS32 //sysnb setgroups(n int, list *_Gid_t) (err error) = SYS_SETGROUPS32 //sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) = SYS__NEWSELECT //sys mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, err error) -//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) //sys Pause() (err error) func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) { @@ -156,10 +159,6 @@ func Setrlimit(resource int, rlim *Rlimit) (err error) { return setrlimit(resource, &rl) } -// Underlying system call writes to newoffset via pointer. -// Implemented in assembly to avoid allocation. -func seek(fd int, offset int64, whence int) (newoffset int64, err syscall.Errno) - func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { newoffset, errno := seek(fd, offset, whence) if errno != 0 { @@ -168,11 +167,11 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { return newoffset, nil } -// Vsyscalls on amd64. +//sys futimesat(dirfd int, path string, times *[2]Timeval) (err error) //sysnb Gettimeofday(tv *Timeval) (err error) //sysnb Time(t *Time_t) (tt Time_t, err error) - //sys Utime(path string, buf *Utimbuf) (err error) +//sys utimes(path string, times *[2]Timeval) (err error) // On x86 Linux, all the socket calls go through an extra indirection, // I think because the 5-register system call interface can't handle @@ -205,9 +204,6 @@ const ( _SENDMMSG = 20 ) -func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, err syscall.Errno) -func rawsocketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, err syscall.Errno) - func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { fd, e := socketcall(_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0) if e != 0 { diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go b/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go index 3707f6b7c9..87a30744d6 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go @@ -7,10 +7,12 @@ package unix //sys Dup2(oldfd int, newfd int) (err error) +//sysnb EpollCreate(size int) (fd int, err error) //sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) //sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64 //sys Fchown(fd int, uid int, gid int) (err error) //sys Fstat(fd int, stat *Stat_t) (err error) +//sys Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) = SYS_NEWFSTATAT //sys Fstatfs(fd int, buf *Statfs_t) (err error) //sys Ftruncate(fd int, length int64) (err error) //sysnb Getegid() (egid int) @@ -18,17 +20,40 @@ package unix //sysnb Getgid() (gid int) //sysnb Getrlimit(resource int, rlim *Rlimit) (err error) //sysnb Getuid() (uid int) -//sysnb InotifyInit() (fd int, err error) +//sysnb inotifyInit() (fd int, err error) + +func InotifyInit() (fd int, err error) { + // First try inotify_init1, because Android's seccomp policy blocks the latter. + fd, err = InotifyInit1(0) + if err == ENOSYS { + fd, err = inotifyInit() + } + return +} + //sys Ioperm(from int, num int, on int) (err error) //sys Iopl(level int) (err error) //sys Lchown(path string, uid int, gid int) (err error) //sys Listen(s int, n int) (err error) -//sys Lstat(path string, stat *Stat_t) (err error) + +func Lstat(path string, stat *Stat_t) (err error) { + return Fstatat(AT_FDCWD, path, stat, AT_SYMLINK_NOFOLLOW) +} + //sys Pause() (err error) //sys Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64 //sys Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64 +//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) //sys Seek(fd int, offset int64, whence int) (off int64, err error) = SYS_LSEEK -//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) + +func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) { + var ts *Timespec + if timeout != nil { + ts = &Timespec{Sec: timeout.Sec, Nsec: timeout.Usec * 1000} + } + return Pselect(nfd, r, w, e, ts, nil) +} + //sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) //sys Setfsgid(gid int) (err error) //sys Setfsuid(uid int) (err error) @@ -39,10 +64,16 @@ package unix //sysnb Setreuid(ruid int, euid int) (err error) //sys Shutdown(fd int, how int) (err error) //sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error) -//sys Stat(path string, stat *Stat_t) (err error) + +func Stat(path string, stat *Stat_t) (err error) { + // Use fstatat, because Android's seccomp policy blocks stat. + return Fstatat(AT_FDCWD, path, stat, 0) +} + //sys Statfs(path string, buf *Statfs_t) (err error) //sys SyncFileRange(fd int, off int64, n int64, flags int) (err error) //sys Truncate(path string, length int64) (err error) +//sys Ustat(dev int, ubuf *Ustat_t) (err error) //sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) //sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) //sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) @@ -61,6 +92,8 @@ package unix //sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error) //sys mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) +//sys futimesat(dirfd int, path string, times *[2]Timeval) (err error) + func Gettimeofday(tv *Timeval) (err error) { errno := gettimeofday(tv) if errno != 0 { @@ -82,6 +115,7 @@ func Time(t *Time_t) (tt Time_t, err error) { } //sys Utime(path string, buf *Utimbuf) (err error) +//sys utimes(path string, times *[2]Timeval) (err error) func setTimespec(sec, nsec int64) Timespec { return Timespec{Sec: sec, Nsec: nsec} @@ -141,3 +175,16 @@ func Poll(fds []PollFd, timeout int) (n int, err error) { } return poll(&fds[0], len(fds), timeout) } + +//sys kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, flags int) (err error) + +func KexecFileLoad(kernelFd int, initrdFd int, cmdline string, flags int) error { + cmdlineLen := len(cmdline) + if cmdlineLen > 0 { + // Account for the additional NULL byte added by + // BytePtrFromString in kexecFileLoad. The kexec_file_load + // syscall expects a NULL-terminated string. + cmdlineLen++ + } + return kexecFileLoad(kernelFd, initrdFd, cmdlineLen, cmdline, flags) +} diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_arm.go b/vendor/golang.org/x/sys/unix/syscall_linux_arm.go index 226be100f5..cda3559419 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_arm.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_arm.go @@ -75,8 +75,11 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { // 64-bit file system and 32-bit uid calls // (16-bit uid calls are not always supported in newer kernels) //sys Dup2(oldfd int, newfd int) (err error) +//sysnb EpollCreate(size int) (fd int, err error) +//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) //sys Fchown(fd int, uid int, gid int) (err error) = SYS_FCHOWN32 //sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64 +//sys Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64 //sysnb Getegid() (egid int) = SYS_GETEGID32 //sysnb Geteuid() (euid int) = SYS_GETEUID32 //sysnb Getgid() (gid int) = SYS_GETGID32 @@ -85,6 +88,8 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { //sys Lchown(path string, uid int, gid int) (err error) = SYS_LCHOWN32 //sys Listen(s int, n int) (err error) //sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64 +//sys Pause() (err error) +//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) //sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) = SYS_SENDFILE64 //sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) = SYS__NEWSELECT //sys Setfsgid(gid int) (err error) = SYS_SETFSGID32 @@ -96,11 +101,10 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { //sys Shutdown(fd int, how int) (err error) //sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, err error) //sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64 +//sys Ustat(dev int, ubuf *Ustat_t) (err error) -// Vsyscalls on amd64. +//sys futimesat(dirfd int, path string, times *[2]Timeval) (err error) //sysnb Gettimeofday(tv *Timeval) (err error) -//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) -//sys Pause() (err error) func Time(t *Time_t) (Time_t, error) { var tv Timeval @@ -122,6 +126,8 @@ func Utime(path string, buf *Utimbuf) error { return Utimes(path, tv) } +//sys utimes(path string, times *[2]Timeval) (err error) + //sys Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64 //sys Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64 //sys Truncate(path string, length int64) (err error) = SYS_TRUNCATE64 @@ -252,3 +258,11 @@ func Poll(fds []PollFd, timeout int) (n int, err error) { } return poll(&fds[0], len(fds), timeout) } + +//sys armSyncFileRange(fd int, flags int, off int64, n int64) (err error) = SYS_ARM_SYNC_FILE_RANGE + +func SyncFileRange(fd int, off int64, n int64, flags int) error { + // The sync_file_range and arm_sync_file_range syscalls differ only in the + // order of their arguments. + return armSyncFileRange(fd, flags, off, n) +} diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go b/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go index 9a8e6e4117..6d56722401 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go @@ -6,7 +6,17 @@ package unix +import "unsafe" + +func EpollCreate(size int) (fd int, err error) { + if size <= 0 { + return -1, EINVAL + } + return EpollCreate1(0) +} + //sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) = SYS_EPOLL_PWAIT +//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64 //sys Fchown(fd int, uid int, gid int) (err error) //sys Fstat(fd int, stat *Stat_t) (err error) //sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) @@ -20,11 +30,15 @@ package unix //sys Listen(s int, n int) (err error) //sys Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64 //sys Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64 +//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) //sys Seek(fd int, offset int64, whence int) (off int64, err error) = SYS_LSEEK func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) { - ts := Timespec{Sec: timeout.Sec, Nsec: timeout.Usec * 1000} - return Pselect(nfd, r, w, e, &ts, nil) + var ts *Timespec + if timeout != nil { + ts = &Timespec{Sec: timeout.Sec, Nsec: timeout.Usec * 1000} + } + return Pselect(nfd, r, w, e, ts, nil) } //sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) @@ -53,6 +67,11 @@ func Lstat(path string, stat *Stat_t) (err error) { //sys Statfs(path string, buf *Statfs_t) (err error) //sys SyncFileRange(fd int, off int64, n int64, flags int) (err error) //sys Truncate(path string, length int64) (err error) + +func Ustat(dev int, ubuf *Ustat_t) (err error) { + return ENOSYS +} + //sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) //sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) //sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) @@ -81,6 +100,18 @@ func setTimeval(sec, usec int64) Timeval { return Timeval{Sec: sec, Usec: usec} } +func futimesat(dirfd int, path string, tv *[2]Timeval) (err error) { + if tv == nil { + return utimensat(dirfd, path, nil, 0) + } + + ts := []Timespec{ + NsecToTimespec(TimevalToNsec(tv[0])), + NsecToTimespec(TimevalToNsec(tv[1])), + } + return utimensat(dirfd, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0) +} + func Time(t *Time_t) (Time_t, error) { var tv Timeval err := Gettimeofday(&tv) @@ -101,6 +132,18 @@ func Utime(path string, buf *Utimbuf) error { return Utimes(path, tv) } +func utimes(path string, tv *[2]Timeval) (err error) { + if tv == nil { + return utimensat(AT_FDCWD, path, nil, 0) + } + + ts := []Timespec{ + NsecToTimespec(TimevalToNsec(tv[0])), + NsecToTimespec(TimevalToNsec(tv[1])), + } + return utimensat(AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0) +} + func Pipe(p []int) (err error) { if len(p) != 2 { return EINVAL @@ -149,30 +192,11 @@ func Dup2(oldfd int, newfd int) (err error) { return Dup3(oldfd, newfd, 0) } -func Pause() (err error) { - _, _, e1 := Syscall6(SYS_PPOLL, 0, 0, 0, 0, 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return +func Pause() error { + _, err := ppoll(nil, 0, nil, nil) + return err } -// TODO(dfc): constants that should be in zsysnum_linux_arm64.go, remove -// these when the deprecated syscalls that the syscall package relies on -// are removed. -const ( - SYS_GETPGRP = 1060 - SYS_UTIMES = 1037 - SYS_FUTIMESAT = 1066 - SYS_PAUSE = 1061 - SYS_USTAT = 1070 - SYS_UTIME = 1063 - SYS_LCHOWN = 1032 - SYS_TIME = 1062 - SYS_EPOLL_CREATE = 1042 - SYS_EPOLL_WAIT = 1069 -) - func Poll(fds []PollFd, timeout int) (n int, err error) { var ts *Timespec if timeout >= 0 { diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_gc.go b/vendor/golang.org/x/sys/unix/syscall_linux_gc.go new file mode 100644 index 0000000000..c26e6ec231 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/syscall_linux_gc.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 linux,!gccgo + +package unix + +// SyscallNoError may be used instead of Syscall for syscalls that don't fail. +func SyscallNoError(trap, a1, a2, a3 uintptr) (r1, r2 uintptr) + +// RawSyscallNoError may be used instead of RawSyscall for syscalls that don't +// fail. +func RawSyscallNoError(trap, a1, a2, a3 uintptr) (r1, r2 uintptr) diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_gc_386.go b/vendor/golang.org/x/sys/unix/syscall_linux_gc_386.go new file mode 100644 index 0000000000..070bd38994 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/syscall_linux_gc_386.go @@ -0,0 +1,16 @@ +// 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 linux,!gccgo,386 + +package unix + +import "syscall" + +// Underlying system call writes to newoffset via pointer. +// Implemented in assembly to avoid allocation. +func seek(fd int, offset int64, whence int) (newoffset int64, err syscall.Errno) + +func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, err syscall.Errno) +func rawsocketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, err syscall.Errno) diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_gccgo_386.go b/vendor/golang.org/x/sys/unix/syscall_linux_gccgo_386.go new file mode 100644 index 0000000000..308eb7aecf --- /dev/null +++ b/vendor/golang.org/x/sys/unix/syscall_linux_gccgo_386.go @@ -0,0 +1,30 @@ +// 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 linux,gccgo,386 + +package unix + +import ( + "syscall" + "unsafe" +) + +func seek(fd int, offset int64, whence int) (int64, syscall.Errno) { + var newoffset int64 + offsetLow := uint32(offset & 0xffffffff) + offsetHigh := uint32((offset >> 32) & 0xffffffff) + _, _, err := Syscall6(SYS__LLSEEK, uintptr(fd), uintptr(offsetHigh), uintptr(offsetLow), uintptr(unsafe.Pointer(&newoffset)), uintptr(whence), 0) + return newoffset, err +} + +func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (int, syscall.Errno) { + fd, _, err := Syscall(SYS_SOCKETCALL, uintptr(call), uintptr(unsafe.Pointer(&a0)), 0) + return int(fd), err +} + +func rawsocketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (int, syscall.Errno) { + fd, _, err := RawSyscall(SYS_SOCKETCALL, uintptr(call), uintptr(unsafe.Pointer(&a0)), 0) + return int(fd), err +} diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_gccgo_arm.go b/vendor/golang.org/x/sys/unix/syscall_linux_gccgo_arm.go new file mode 100644 index 0000000000..aa7fc9e199 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/syscall_linux_gccgo_arm.go @@ -0,0 +1,20 @@ +// 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 linux,gccgo,arm + +package unix + +import ( + "syscall" + "unsafe" +) + +func seek(fd int, offset int64, whence int) (int64, syscall.Errno) { + var newoffset int64 + offsetLow := uint32(offset & 0xffffffff) + offsetHigh := uint32((offset >> 32) & 0xffffffff) + _, _, err := Syscall6(SYS__LLSEEK, uintptr(fd), uintptr(offsetHigh), uintptr(offsetLow), uintptr(unsafe.Pointer(&newoffset)), uintptr(whence), 0) + return newoffset, err +} diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go b/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go index cdda11a9fa..b3b21ec1e2 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go @@ -8,7 +8,9 @@ package unix //sys Dup2(oldfd int, newfd int) (err error) +//sysnb EpollCreate(size int) (fd int, err error) //sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) +//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64 //sys Fchown(fd int, uid int, gid int) (err error) //sys Fstatfs(fd int, buf *Statfs_t) (err error) //sys Ftruncate(fd int, length int64) (err error) @@ -22,11 +24,15 @@ package unix //sys Pause() (err error) //sys Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64 //sys Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64 +//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) //sys Seek(fd int, offset int64, whence int) (off int64, err error) = SYS_LSEEK func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) { - ts := Timespec{Sec: timeout.Sec, Nsec: timeout.Usec * 1000} - return Pselect(nfd, r, w, e, &ts, nil) + var ts *Timespec + if timeout != nil { + ts = &Timespec{Sec: timeout.Sec, Nsec: timeout.Usec * 1000} + } + return Pselect(nfd, r, w, e, ts, nil) } //sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) @@ -42,6 +48,7 @@ func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err //sys Statfs(path string, buf *Statfs_t) (err error) //sys SyncFileRange(fd int, off int64, n int64, flags int) (err error) //sys Truncate(path string, length int64) (err error) +//sys Ustat(dev int, ubuf *Ustat_t) (err error) //sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) //sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) //sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) @@ -60,6 +67,7 @@ func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err //sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error) //sys mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) +//sys futimesat(dirfd int, path string, times *[2]Timeval) (err error) //sysnb Gettimeofday(tv *Timeval) (err error) func Time(t *Time_t) (tt Time_t, err error) { @@ -75,6 +83,7 @@ func Time(t *Time_t) (tt Time_t, err error) { } //sys Utime(path string, buf *Utimbuf) (err error) +//sys utimes(path string, times *[2]Timeval) (err error) func setTimespec(sec, nsec int64) Timespec { return Timespec{Sec: sec, Nsec: nsec} @@ -139,6 +148,7 @@ type stat_t struct { } //sys fstat(fd int, st *stat_t) (err error) +//sys fstatat(dirfd int, path string, st *stat_t, flags int) (err error) = SYS_NEWFSTATAT //sys lstat(path string, st *stat_t) (err error) //sys stat(path string, st *stat_t) (err error) @@ -149,6 +159,13 @@ func Fstat(fd int, s *Stat_t) (err error) { return } +func Fstatat(dirfd int, path string, s *Stat_t, flags int) (err error) { + st := &stat_t{} + err = fstatat(dirfd, path, st, flags) + fillStat_t(s, st) + return +} + func Lstat(path string, s *Stat_t) (err error) { st := &stat_t{} err = lstat(path, st) diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go b/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go index a114ba8cb3..5144d4e133 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go @@ -15,6 +15,9 @@ import ( func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) //sys Dup2(oldfd int, newfd int) (err error) +//sysnb EpollCreate(size int) (fd int, err error) +//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) +//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64 //sys Fchown(fd int, uid int, gid int) (err error) //sys Ftruncate(fd int, length int64) (err error) = SYS_FTRUNCATE64 //sysnb Getegid() (egid int) @@ -25,6 +28,7 @@ func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, //sys Listen(s int, n int) (err error) //sys Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64 //sys Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64 +//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) //sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) = SYS__NEWSELECT //sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) = SYS_SENDFILE64 //sys Setfsgid(gid int) (err error) @@ -32,13 +36,12 @@ func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, //sysnb Setregid(rgid int, egid int) (err error) //sysnb Setresgid(rgid int, egid int, sgid int) (err error) //sysnb Setresuid(ruid int, euid int, suid int) (err error) - //sysnb Setreuid(ruid int, euid int) (err error) //sys Shutdown(fd int, how int) (err error) -//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error) - +//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, err error) //sys SyncFileRange(fd int, off int64, n int64, flags int) (err error) //sys Truncate(path string, length int64) (err error) = SYS_TRUNCATE64 +//sys Ustat(dev int, ubuf *Ustat_t) (err error) //sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) //sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) //sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) @@ -60,15 +63,17 @@ func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, //sys Ioperm(from int, num int, on int) (err error) //sys Iopl(level int) (err error) +//sys futimesat(dirfd int, path string, times *[2]Timeval) (err error) //sysnb Gettimeofday(tv *Timeval) (err error) //sysnb Time(t *Time_t) (tt Time_t, err error) +//sys Utime(path string, buf *Utimbuf) (err error) +//sys utimes(path string, times *[2]Timeval) (err error) //sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64 //sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64 +//sys Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64 //sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64 -//sys Utime(path string, buf *Utimbuf) (err error) -//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) //sys Pause() (err error) func Fstatfs(fd int, buf *Statfs_t) (err error) { @@ -120,14 +125,13 @@ func Pipe2(p []int, flags int) (err error) { return } +//sysnb pipe() (p1 int, p2 int, err error) + func Pipe(p []int) (err error) { if len(p) != 2 { return EINVAL } - var pp [2]_C_int - err = pipe2(&pp, 0) - p[0] = int(pp[0]) - p[1] = int(pp[1]) + p[0], p[1], err = pipe() return } diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go b/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go index 7cae936c45..0a100b66a3 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go @@ -7,10 +7,13 @@ package unix -//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) //sys Dup2(oldfd int, newfd int) (err error) +//sysnb EpollCreate(size int) (fd int, err error) +//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) +//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64 //sys Fchown(fd int, uid int, gid int) (err error) //sys Fstat(fd int, stat *Stat_t) (err error) +//sys Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) = SYS_NEWFSTATAT //sys Fstatfs(fd int, buf *Statfs_t) (err error) //sys Ftruncate(fd int, length int64) (err error) //sysnb Getegid() (egid int) @@ -27,6 +30,7 @@ package unix //sys Pause() (err error) //sys Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64 //sys Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64 +//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) //sys Seek(fd int, offset int64, whence int) (off int64, err error) = SYS_LSEEK //sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) = SYS__NEWSELECT //sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) @@ -41,8 +45,8 @@ package unix //sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error) //sys Stat(path string, stat *Stat_t) (err error) //sys Statfs(path string, buf *Statfs_t) (err error) -//sys SyncFileRange(fd int, off int64, n int64, flags int) (err error) = SYS_SYNC_FILE_RANGE2 //sys Truncate(path string, length int64) (err error) +//sys Ustat(dev int, ubuf *Ustat_t) (err error) //sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) //sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) //sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) @@ -61,10 +65,11 @@ package unix //sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error) //sys mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) +//sys futimesat(dirfd int, path string, times *[2]Timeval) (err error) //sysnb Gettimeofday(tv *Timeval) (err error) //sysnb Time(t *Time_t) (tt Time_t, err error) - //sys Utime(path string, buf *Utimbuf) (err error) +//sys utimes(path string, times *[2]Timeval) (err error) func setTimespec(sec, nsec int64) Timespec { return Timespec{Sec: sec, Nsec: nsec} @@ -124,3 +129,24 @@ func Poll(fds []PollFd, timeout int) (n int, err error) { } return poll(&fds[0], len(fds), timeout) } + +//sys syncFileRange2(fd int, flags int, off int64, n int64) (err error) = SYS_SYNC_FILE_RANGE2 + +func SyncFileRange(fd int, off int64, n int64, flags int) error { + // The sync_file_range and sync_file_range2 syscalls differ only in the + // order of their arguments. + return syncFileRange2(fd, flags, off, n) +} + +//sys kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, flags int) (err error) + +func KexecFileLoad(kernelFd int, initrdFd int, cmdline string, flags int) error { + cmdlineLen := len(cmdline) + if cmdlineLen > 0 { + // Account for the additional NULL byte added by + // BytePtrFromString in kexecFileLoad. The kexec_file_load + // syscall expects a NULL-terminated string. + cmdlineLen++ + } + return kexecFileLoad(kernelFd, initrdFd, cmdlineLen, cmdline, flags) +} diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go b/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go new file mode 100644 index 0000000000..f23ca451c7 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go @@ -0,0 +1,213 @@ +// 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 riscv64,linux + +package unix + +import "unsafe" + +func EpollCreate(size int) (fd int, err error) { + if size <= 0 { + return -1, EINVAL + } + return EpollCreate1(0) +} + +//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) = SYS_EPOLL_PWAIT +//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64 +//sys Fchown(fd int, uid int, gid int) (err error) +//sys Fstat(fd int, stat *Stat_t) (err error) +//sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) +//sys Fstatfs(fd int, buf *Statfs_t) (err error) +//sys Ftruncate(fd int, length int64) (err error) +//sysnb Getegid() (egid int) +//sysnb Geteuid() (euid int) +//sysnb Getgid() (gid int) +//sysnb Getrlimit(resource int, rlim *Rlimit) (err error) +//sysnb Getuid() (uid int) +//sys Listen(s int, n int) (err error) +//sys Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64 +//sys Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64 +//sys Seek(fd int, offset int64, whence int) (off int64, err error) = SYS_LSEEK + +func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) { + var ts *Timespec + if timeout != nil { + ts = &Timespec{Sec: timeout.Sec, Nsec: timeout.Usec * 1000} + } + return Pselect(nfd, r, w, e, ts, nil) +} + +//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) +//sys Setfsgid(gid int) (err error) +//sys Setfsuid(uid int) (err error) +//sysnb Setregid(rgid int, egid int) (err error) +//sysnb Setresgid(rgid int, egid int, sgid int) (err error) +//sysnb Setresuid(ruid int, euid int, suid int) (err error) +//sysnb Setrlimit(resource int, rlim *Rlimit) (err error) +//sysnb Setreuid(ruid int, euid int) (err error) +//sys Shutdown(fd int, how int) (err error) +//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error) + +func Stat(path string, stat *Stat_t) (err error) { + return Fstatat(AT_FDCWD, path, stat, 0) +} + +func Lchown(path string, uid int, gid int) (err error) { + return Fchownat(AT_FDCWD, path, uid, gid, AT_SYMLINK_NOFOLLOW) +} + +func Lstat(path string, stat *Stat_t) (err error) { + return Fstatat(AT_FDCWD, path, stat, AT_SYMLINK_NOFOLLOW) +} + +//sys Statfs(path string, buf *Statfs_t) (err error) +//sys SyncFileRange(fd int, off int64, n int64, flags int) (err error) +//sys Truncate(path string, length int64) (err error) + +func Ustat(dev int, ubuf *Ustat_t) (err error) { + return ENOSYS +} + +//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) +//sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) +//sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) +//sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) +//sysnb getgroups(n int, list *_Gid_t) (nn int, err error) +//sysnb setgroups(n int, list *_Gid_t) (err error) +//sys getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) +//sys setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) +//sysnb socket(domain int, typ int, proto int) (fd int, err error) +//sysnb socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) +//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) +//sysnb getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) +//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) +//sys sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) +//sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error) +//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error) +//sys mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) + +//sysnb Gettimeofday(tv *Timeval) (err error) + +func setTimespec(sec, nsec int64) Timespec { + return Timespec{Sec: sec, Nsec: nsec} +} + +func setTimeval(sec, usec int64) Timeval { + return Timeval{Sec: sec, Usec: usec} +} + +func futimesat(dirfd int, path string, tv *[2]Timeval) (err error) { + if tv == nil { + return utimensat(dirfd, path, nil, 0) + } + + ts := []Timespec{ + NsecToTimespec(TimevalToNsec(tv[0])), + NsecToTimespec(TimevalToNsec(tv[1])), + } + return utimensat(dirfd, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0) +} + +func Time(t *Time_t) (Time_t, error) { + var tv Timeval + err := Gettimeofday(&tv) + if err != nil { + return 0, err + } + if t != nil { + *t = Time_t(tv.Sec) + } + return Time_t(tv.Sec), nil +} + +func Utime(path string, buf *Utimbuf) error { + tv := []Timeval{ + {Sec: buf.Actime}, + {Sec: buf.Modtime}, + } + return Utimes(path, tv) +} + +func utimes(path string, tv *[2]Timeval) (err error) { + if tv == nil { + return utimensat(AT_FDCWD, path, nil, 0) + } + + ts := []Timespec{ + NsecToTimespec(TimevalToNsec(tv[0])), + NsecToTimespec(TimevalToNsec(tv[1])), + } + return utimensat(AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0) +} + +func Pipe(p []int) (err error) { + if len(p) != 2 { + return EINVAL + } + var pp [2]_C_int + err = pipe2(&pp, 0) + p[0] = int(pp[0]) + p[1] = int(pp[1]) + return +} + +//sysnb pipe2(p *[2]_C_int, flags int) (err error) + +func Pipe2(p []int, flags int) (err error) { + if len(p) != 2 { + return EINVAL + } + var pp [2]_C_int + err = pipe2(&pp, flags) + p[0] = int(pp[0]) + p[1] = int(pp[1]) + return +} + +func (r *PtraceRegs) PC() uint64 { return r.Pc } + +func (r *PtraceRegs) SetPC(pc uint64) { r.Pc = pc } + +func (iov *Iovec) SetLen(length int) { + iov.Len = uint64(length) +} + +func (msghdr *Msghdr) SetControllen(length int) { + msghdr.Controllen = uint64(length) +} + +func (cmsg *Cmsghdr) SetLen(length int) { + cmsg.Len = uint64(length) +} + +func InotifyInit() (fd int, err error) { + return InotifyInit1(0) +} + +func Dup2(oldfd int, newfd int) (err error) { + return Dup3(oldfd, newfd, 0) +} + +func Pause() error { + _, err := ppoll(nil, 0, nil, nil) + return err +} + +func Poll(fds []PollFd, timeout int) (n int, err error) { + var ts *Timespec + if timeout >= 0 { + ts = new(Timespec) + *ts = NsecToTimespec(int64(timeout) * 1e6) + } + if len(fds) == 0 { + return ppoll(nil, 0, ts, nil) + } + return ppoll(&fds[0], len(fds), ts, nil) +} + +func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { + return Renameat2(olddirfd, oldpath, newdirfd, newpath, 0) +} diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go b/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go index e96a40cb21..f81dbdc9c8 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go @@ -11,10 +11,12 @@ import ( ) //sys Dup2(oldfd int, newfd int) (err error) +//sysnb EpollCreate(size int) (fd int, err error) //sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) //sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64 //sys Fchown(fd int, uid int, gid int) (err error) //sys Fstat(fd int, stat *Stat_t) (err error) +//sys Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) = SYS_NEWFSTATAT //sys Fstatfs(fd int, buf *Statfs_t) (err error) //sys Ftruncate(fd int, length int64) (err error) //sysnb Getegid() (egid int) @@ -28,6 +30,7 @@ import ( //sys Pause() (err error) //sys Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64 //sys Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64 +//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) //sys Seek(fd int, offset int64, whence int) (off int64, err error) = SYS_LSEEK //sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) //sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) @@ -43,9 +46,11 @@ import ( //sys Statfs(path string, buf *Statfs_t) (err error) //sys SyncFileRange(fd int, off int64, n int64, flags int) (err error) //sys Truncate(path string, length int64) (err error) +//sys Ustat(dev int, ubuf *Ustat_t) (err error) //sysnb getgroups(n int, list *_Gid_t) (nn int, err error) //sysnb setgroups(n int, list *_Gid_t) (err error) +//sys futimesat(dirfd int, path string, times *[2]Timeval) (err error) //sysnb Gettimeofday(tv *Timeval) (err error) func Time(t *Time_t) (tt Time_t, err error) { @@ -61,6 +66,7 @@ func Time(t *Time_t) (tt Time_t, err error) { } //sys Utime(path string, buf *Utimbuf) (err error) +//sys utimes(path string, times *[2]Timeval) (err error) func setTimespec(sec, nsec int64) Timespec { return Timespec{Sec: sec, Nsec: nsec} @@ -317,3 +323,16 @@ func Poll(fds []PollFd, timeout int) (n int, err error) { } return poll(&fds[0], len(fds), timeout) } + +//sys kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, flags int) (err error) + +func KexecFileLoad(kernelFd int, initrdFd int, cmdline string, flags int) error { + cmdlineLen := len(cmdline) + if cmdlineLen > 0 { + // Account for the additional NULL byte added by + // BytePtrFromString in kexecFileLoad. The kexec_file_load + // syscall expects a NULL-terminated string. + cmdlineLen++ + } + return kexecFileLoad(kernelFd, initrdFd, cmdlineLen, cmdline, flags) +} diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go b/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go index 012a3285ef..b69565616f 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go @@ -7,9 +7,11 @@ package unix //sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) +//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64 //sys Dup2(oldfd int, newfd int) (err error) //sys Fchown(fd int, uid int, gid int) (err error) //sys Fstat(fd int, stat *Stat_t) (err error) +//sys Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64 //sys Fstatfs(fd int, buf *Statfs_t) (err error) //sys Ftruncate(fd int, length int64) (err error) //sysnb Getegid() (egid int) @@ -24,6 +26,7 @@ package unix //sys Pause() (err error) //sys Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64 //sys Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64 +//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) //sys Seek(fd int, offset int64, whence int) (off int64, err error) = SYS_LSEEK //sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) //sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) @@ -66,6 +69,7 @@ func Iopl(level int) (err error) { return ENOSYS } +//sys futimesat(dirfd int, path string, times *[2]Timeval) (err error) //sysnb Gettimeofday(tv *Timeval) (err error) func Time(t *Time_t) (tt Time_t, err error) { @@ -81,6 +85,7 @@ func Time(t *Time_t) (tt Time_t, err error) { } //sys Utime(path string, buf *Utimbuf) (err error) +//sys utimes(path string, times *[2]Timeval) (err error) func setTimespec(sec, nsec int64) Timespec { return Timespec{Sec: sec, Nsec: nsec} diff --git a/vendor/golang.org/x/sys/unix/syscall_netbsd.go b/vendor/golang.org/x/sys/unix/syscall_netbsd.go index 9146809527..5240e16e4b 100644 --- a/vendor/golang.org/x/sys/unix/syscall_netbsd.go +++ b/vendor/golang.org/x/sys/unix/syscall_netbsd.go @@ -13,10 +13,12 @@ package unix import ( + "runtime" "syscall" "unsafe" ) +// SockaddrDatalink implements the Sockaddr interface for AF_LINK type sockets. type SockaddrDatalink struct { Len uint8 Family uint8 @@ -92,16 +94,21 @@ func nametomib(name string) (mib []_C_int, err error) { return mib, nil } -func direntIno(buf []byte) (uint64, bool) { - return readInt(buf, unsafe.Offsetof(Dirent{}.Fileno), unsafe.Sizeof(Dirent{}.Fileno)) -} +func SysctlClockinfo(name string) (*Clockinfo, error) { + mib, err := sysctlmib(name) + if err != nil { + return nil, err + } -func direntReclen(buf []byte) (uint64, bool) { - return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen)) -} - -func direntNamlen(buf []byte) (uint64, bool) { - return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen)) + n := uintptr(SizeofClockinfo) + var ci Clockinfo + if err := sysctl(mib, (*byte)(unsafe.Pointer(&ci)), &n, nil, 0); err != nil { + return nil, err + } + if n != SizeofClockinfo { + return nil, EIO + } + return &ci, nil } //sysnb pipe() (fd1 int, fd2 int, err error) @@ -118,6 +125,23 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { return getdents(fd, buf) } +const ImplementsGetwd = true + +//sys Getcwd(buf []byte) (n int, err error) = SYS___GETCWD + +func Getwd() (string, error) { + var buf [PathMax]byte + _, err := Getcwd(buf[0:]) + if err != nil { + return "", err + } + n := clen(buf[:]) + if n < 1 { + return "", EINVAL + } + return string(buf[:n]), nil +} + // TODO func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { return -1, ENOSYS @@ -139,11 +163,11 @@ func IoctlSetInt(fd int, req uint, value int) error { return ioctl(fd, req, uintptr(value)) } -func IoctlSetWinsize(fd int, req uint, value *Winsize) error { +func ioctlSetWinsize(fd int, req uint, value *Winsize) error { return ioctl(fd, req, uintptr(unsafe.Pointer(value))) } -func IoctlSetTermios(fd int, req uint, value *Termios) error { +func ioctlSetTermios(fd int, req uint, value *Termios) error { return ioctl(fd, req, uintptr(unsafe.Pointer(value))) } @@ -167,6 +191,66 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) { return &value, err } +func IoctlGetPtmget(fd int, req uint) (*Ptmget, error) { + var value Ptmget + err := ioctl(fd, req, uintptr(unsafe.Pointer(&value))) + runtime.KeepAlive(value) + return &value, err +} + +func Uname(uname *Utsname) error { + mib := []_C_int{CTL_KERN, KERN_OSTYPE} + n := unsafe.Sizeof(uname.Sysname) + if err := sysctl(mib, &uname.Sysname[0], &n, nil, 0); err != nil { + return err + } + + mib = []_C_int{CTL_KERN, KERN_HOSTNAME} + n = unsafe.Sizeof(uname.Nodename) + if err := sysctl(mib, &uname.Nodename[0], &n, nil, 0); err != nil { + return err + } + + mib = []_C_int{CTL_KERN, KERN_OSRELEASE} + n = unsafe.Sizeof(uname.Release) + if err := sysctl(mib, &uname.Release[0], &n, nil, 0); err != nil { + return err + } + + mib = []_C_int{CTL_KERN, KERN_VERSION} + n = unsafe.Sizeof(uname.Version) + if err := sysctl(mib, &uname.Version[0], &n, nil, 0); err != nil { + return err + } + + // The version might have newlines or tabs in it, convert them to + // spaces. + for i, b := range uname.Version { + if b == '\n' || b == '\t' { + if i == len(uname.Version)-1 { + uname.Version[i] = 0 + } else { + uname.Version[i] = ' ' + } + } + } + + mib = []_C_int{CTL_HW, HW_MACHINE} + n = unsafe.Sizeof(uname.Machine) + if err := sysctl(mib, &uname.Machine[0], &n, nil, 0); err != nil { + return err + } + + return nil +} + +func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { + if raceenabled { + raceReleaseMerge(unsafe.Pointer(&ioSync)) + } + return sendfile(outfd, infd, offset, count) +} + /* * Exposed directly */ @@ -181,13 +265,30 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) { //sys Dup(fd int) (nfd int, err error) //sys Dup2(from int, to int) (err error) //sys Exit(code int) +//sys ExtattrGetFd(fd int, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) +//sys ExtattrSetFd(fd int, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) +//sys ExtattrDeleteFd(fd int, attrnamespace int, attrname string) (err error) +//sys ExtattrListFd(fd int, attrnamespace int, data uintptr, nbytes int) (ret int, err error) +//sys ExtattrGetFile(file string, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) +//sys ExtattrSetFile(file string, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) +//sys ExtattrDeleteFile(file string, attrnamespace int, attrname string) (err error) +//sys ExtattrListFile(file string, attrnamespace int, data uintptr, nbytes int) (ret int, err error) +//sys ExtattrGetLink(link string, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) +//sys ExtattrSetLink(link string, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) +//sys ExtattrDeleteLink(link string, attrnamespace int, attrname string) (err error) +//sys ExtattrListLink(link string, attrnamespace int, data uintptr, nbytes int) (ret int, err error) +//sys Faccessat(dirfd int, path string, mode uint32, flags int) (err error) +//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_POSIX_FADVISE //sys Fchdir(fd int) (err error) //sys Fchflags(fd int, flags int) (err error) //sys Fchmod(fd int, mode uint32) (err error) +//sys Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) //sys Fchown(fd int, uid int, gid int) (err error) +//sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) //sys Flock(fd int, how int) (err error) //sys Fpathconf(fd int, name int) (val int, err error) //sys Fstat(fd int, stat *Stat_t) (err error) +//sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) //sys Fsync(fd int) (err error) //sys Ftruncate(fd int, length int64) (err error) //sysnb Getegid() (egid int) @@ -208,19 +309,26 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) { //sys Kqueue() (fd int, err error) //sys Lchown(path string, uid int, gid int) (err error) //sys Link(path string, link string) (err error) +//sys Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error) //sys Listen(s int, backlog int) (err error) //sys Lstat(path string, stat *Stat_t) (err error) //sys Mkdir(path string, mode uint32) (err error) +//sys Mkdirat(dirfd int, path string, mode uint32) (err error) //sys Mkfifo(path string, mode uint32) (err error) +//sys Mkfifoat(dirfd int, path string, mode uint32) (err error) //sys Mknod(path string, mode uint32, dev int) (err error) +//sys Mknodat(dirfd int, path string, mode uint32, dev int) (err error) //sys Nanosleep(time *Timespec, leftover *Timespec) (err error) //sys Open(path string, mode int, perm uint32) (fd int, err error) +//sys Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) //sys Pathconf(path string, name int) (val int, err error) //sys Pread(fd int, p []byte, offset int64) (n int, err error) //sys Pwrite(fd int, p []byte, offset int64) (n int, err error) //sys read(fd int, p []byte) (n int, err error) //sys Readlink(path string, buf []byte) (n int, err error) +//sys Readlinkat(dirfd int, path string, buf []byte) (n int, err error) //sys Rename(from string, to string) (err error) +//sys Renameat(fromfd int, from string, tofd int, to string) (err error) //sys Revoke(path string) (err error) //sys Rmdir(path string) (err error) //sys Seek(fd int, offset int64, whence int) (newoffset int64, err error) = SYS_LSEEK @@ -238,10 +346,12 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) { //sysnb Setuid(uid int) (err error) //sys Stat(path string, stat *Stat_t) (err error) //sys Symlink(path string, link string) (err error) +//sys Symlinkat(oldpath string, newdirfd int, newpath string) (err error) //sys Sync() (err error) //sys Truncate(path string, length int64) (err error) //sys Umask(newmask int) (oldmask int) //sys Unlink(path string) (err error) +//sys Unlinkat(dirfd int, path string, flags int) (err error) //sys Unmount(path string, flags int) (err error) //sys write(fd int, p []byte) (n int, err error) //sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) @@ -268,7 +378,6 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) { // __msync13 // __ntp_gettime30 // __posix_chown -// __posix_fadvise50 // __posix_fchown // __posix_lchown // __posix_rename diff --git a/vendor/golang.org/x/sys/unix/syscall_netbsd_arm64.go b/vendor/golang.org/x/sys/unix/syscall_netbsd_arm64.go new file mode 100644 index 0000000000..f3434465a1 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/syscall_netbsd_arm64.go @@ -0,0 +1,33 @@ +// Copyright 2019 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 arm64,netbsd + +package unix + +func setTimespec(sec, nsec int64) Timespec { + return Timespec{Sec: sec, Nsec: nsec} +} + +func setTimeval(sec, usec int64) Timeval { + return Timeval{Sec: sec, Usec: int32(usec)} +} + +func SetKevent(k *Kevent_t, fd, mode, flags int) { + k.Ident = uint64(fd) + k.Filter = uint32(mode) + k.Flags = uint32(flags) +} + +func (iov *Iovec) SetLen(length int) { + iov.Len = uint64(length) +} + +func (msghdr *Msghdr) SetControllen(length int) { + msghdr.Controllen = uint32(length) +} + +func (cmsg *Cmsghdr) SetLen(length int) { + cmsg.Len = uint32(length) +} diff --git a/vendor/golang.org/x/sys/unix/syscall_no_getwd.go b/vendor/golang.org/x/sys/unix/syscall_no_getwd.go deleted file mode 100644 index 530792ea93..0000000000 --- a/vendor/golang.org/x/sys/unix/syscall_no_getwd.go +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2013 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 dragonfly freebsd netbsd openbsd - -package unix - -const ImplementsGetwd = false - -func Getwd() (string, error) { return "", ENOTSUP } diff --git a/vendor/golang.org/x/sys/unix/syscall_openbsd.go b/vendor/golang.org/x/sys/unix/syscall_openbsd.go index 0bda73c384..687999549c 100644 --- a/vendor/golang.org/x/sys/unix/syscall_openbsd.go +++ b/vendor/golang.org/x/sys/unix/syscall_openbsd.go @@ -13,10 +13,12 @@ package unix import ( + "sort" "syscall" "unsafe" ) +// SockaddrDatalink implements the Sockaddr interface for AF_LINK type sockets. type SockaddrDatalink struct { Len uint8 Family uint8 @@ -32,36 +34,30 @@ type SockaddrDatalink struct { func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) func nametomib(name string) (mib []_C_int, err error) { - // Perform lookup via a binary search - left := 0 - right := len(sysctlMib) - 1 - for { - idx := left + (right-left)/2 - switch { - case name == sysctlMib[idx].ctlname: - return sysctlMib[idx].ctloid, nil - case name > sysctlMib[idx].ctlname: - left = idx + 1 - default: - right = idx - 1 - } - if left > right { - break - } + i := sort.Search(len(sysctlMib), func(i int) bool { + return sysctlMib[i].ctlname >= name + }) + if i < len(sysctlMib) && sysctlMib[i].ctlname == name { + return sysctlMib[i].ctloid, nil } return nil, EINVAL } -func direntIno(buf []byte) (uint64, bool) { - return readInt(buf, unsafe.Offsetof(Dirent{}.Fileno), unsafe.Sizeof(Dirent{}.Fileno)) -} +func SysctlUvmexp(name string) (*Uvmexp, error) { + mib, err := sysctlmib(name) + if err != nil { + return nil, err + } -func direntReclen(buf []byte) (uint64, bool) { - return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen)) -} - -func direntNamlen(buf []byte) (uint64, bool) { - return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen)) + n := uintptr(SizeofUvmexp) + var u Uvmexp + if err := sysctl(mib, (*byte)(unsafe.Pointer(&u)), &n, nil, 0); err != nil { + return nil, err + } + if n != SizeofUvmexp { + return nil, EIO + } + return &u, nil } //sysnb pipe(p *[2]_C_int) (err error) @@ -81,6 +77,30 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { return getdents(fd, buf) } +const ImplementsGetwd = true + +//sys Getcwd(buf []byte) (n int, err error) = SYS___GETCWD + +func Getwd() (string, error) { + var buf [PathMax]byte + _, err := Getcwd(buf[0:]) + if err != nil { + return "", err + } + n := clen(buf[:]) + if n < 1 { + return "", EINVAL + } + return string(buf[:n]), nil +} + +func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { + if raceenabled { + raceReleaseMerge(unsafe.Pointer(&ioSync)) + } + return sendfile(outfd, infd, offset, count) +} + // TODO func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { return -1, ENOSYS @@ -117,11 +137,11 @@ func IoctlSetInt(fd int, req uint, value int) error { return ioctl(fd, req, uintptr(value)) } -func IoctlSetWinsize(fd int, req uint, value *Winsize) error { +func ioctlSetWinsize(fd int, req uint, value *Winsize) error { return ioctl(fd, req, uintptr(unsafe.Pointer(value))) } -func IoctlSetTermios(fd int, req uint, value *Termios) error { +func ioctlSetTermios(fd int, req uint, value *Termios) error { return ioctl(fd, req, uintptr(unsafe.Pointer(value))) } @@ -145,6 +165,61 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) { return &value, err } +//sys ppoll(fds *PollFd, nfds int, timeout *Timespec, sigmask *Sigset_t) (n int, err error) + +func Ppoll(fds []PollFd, timeout *Timespec, sigmask *Sigset_t) (n int, err error) { + if len(fds) == 0 { + return ppoll(nil, 0, timeout, sigmask) + } + return ppoll(&fds[0], len(fds), timeout, sigmask) +} + +func Uname(uname *Utsname) error { + mib := []_C_int{CTL_KERN, KERN_OSTYPE} + n := unsafe.Sizeof(uname.Sysname) + if err := sysctl(mib, &uname.Sysname[0], &n, nil, 0); err != nil { + return err + } + + mib = []_C_int{CTL_KERN, KERN_HOSTNAME} + n = unsafe.Sizeof(uname.Nodename) + if err := sysctl(mib, &uname.Nodename[0], &n, nil, 0); err != nil { + return err + } + + mib = []_C_int{CTL_KERN, KERN_OSRELEASE} + n = unsafe.Sizeof(uname.Release) + if err := sysctl(mib, &uname.Release[0], &n, nil, 0); err != nil { + return err + } + + mib = []_C_int{CTL_KERN, KERN_VERSION} + n = unsafe.Sizeof(uname.Version) + if err := sysctl(mib, &uname.Version[0], &n, nil, 0); err != nil { + return err + } + + // The version might have newlines or tabs in it, convert them to + // spaces. + for i, b := range uname.Version { + if b == '\n' || b == '\t' { + if i == len(uname.Version)-1 { + uname.Version[i] = 0 + } else { + uname.Version[i] = ' ' + } + } + } + + mib = []_C_int{CTL_HW, HW_MACHINE} + n = unsafe.Sizeof(uname.Machine) + if err := sysctl(mib, &uname.Machine[0], &n, nil, 0); err != nil { + return err + } + + return nil +} + /* * Exposed directly */ @@ -159,13 +234,17 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) { //sys Dup(fd int) (nfd int, err error) //sys Dup2(from int, to int) (err error) //sys Exit(code int) +//sys Faccessat(dirfd int, path string, mode uint32, flags int) (err error) //sys Fchdir(fd int) (err error) //sys Fchflags(fd int, flags int) (err error) //sys Fchmod(fd int, mode uint32) (err error) +//sys Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) //sys Fchown(fd int, uid int, gid int) (err error) +//sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) //sys Flock(fd int, how int) (err error) //sys Fpathconf(fd int, name int) (val int, err error) //sys Fstat(fd int, stat *Stat_t) (err error) +//sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) //sys Fstatfs(fd int, stat *Statfs_t) (err error) //sys Fsync(fd int) (err error) //sys Ftruncate(fd int, length int64) (err error) @@ -178,6 +257,7 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) { //sysnb Getppid() (ppid int) //sys Getpriority(which int, who int) (prio int, err error) //sysnb Getrlimit(which int, lim *Rlimit) (err error) +//sysnb Getrtable() (rtable int, err error) //sysnb Getrusage(who int, rusage *Rusage) (err error) //sysnb Getsid(pid int) (sid int, err error) //sysnb Gettimeofday(tv *Timeval) (err error) @@ -187,19 +267,26 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) { //sys Kqueue() (fd int, err error) //sys Lchown(path string, uid int, gid int) (err error) //sys Link(path string, link string) (err error) +//sys Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error) //sys Listen(s int, backlog int) (err error) //sys Lstat(path string, stat *Stat_t) (err error) //sys Mkdir(path string, mode uint32) (err error) +//sys Mkdirat(dirfd int, path string, mode uint32) (err error) //sys Mkfifo(path string, mode uint32) (err error) +//sys Mkfifoat(dirfd int, path string, mode uint32) (err error) //sys Mknod(path string, mode uint32, dev int) (err error) +//sys Mknodat(dirfd int, path string, mode uint32, dev int) (err error) //sys Nanosleep(time *Timespec, leftover *Timespec) (err error) //sys Open(path string, mode int, perm uint32) (fd int, err error) +//sys Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) //sys Pathconf(path string, name int) (val int, err error) //sys Pread(fd int, p []byte, offset int64) (n int, err error) //sys Pwrite(fd int, p []byte, offset int64) (n int, err error) //sys read(fd int, p []byte) (n int, err error) //sys Readlink(path string, buf []byte) (n int, err error) +//sys Readlinkat(dirfd int, path string, buf []byte) (n int, err error) //sys Rename(from string, to string) (err error) +//sys Renameat(fromfd int, from string, tofd int, to string) (err error) //sys Revoke(path string) (err error) //sys Rmdir(path string) (err error) //sys Seek(fd int, offset int64, whence int) (newoffset int64, err error) = SYS_LSEEK @@ -215,16 +302,19 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) { //sysnb Setresgid(rgid int, egid int, sgid int) (err error) //sysnb Setresuid(ruid int, euid int, suid int) (err error) //sysnb Setrlimit(which int, lim *Rlimit) (err error) +//sysnb Setrtable(rtable int) (err error) //sysnb Setsid() (pid int, err error) //sysnb Settimeofday(tp *Timeval) (err error) //sysnb Setuid(uid int) (err error) //sys Stat(path string, stat *Stat_t) (err error) //sys Statfs(path string, stat *Statfs_t) (err error) //sys Symlink(path string, link string) (err error) +//sys Symlinkat(oldpath string, newdirfd int, newpath string) (err error) //sys Sync() (err error) //sys Truncate(path string, length int64) (err error) //sys Umask(newmask int) (oldmask int) //sys Unlink(path string) (err error) +//sys Unlinkat(dirfd int, path string, flags int) (err error) //sys Unmount(path string, flags int) (err error) //sys write(fd int, p []byte) (n int, err error) //sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) @@ -247,15 +337,11 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) { // clock_settime // closefrom // execve -// faccessat -// fchmodat -// fchownat // fcntl // fhopen // fhstat // fhstatfs // fork -// fstatat // futimens // getfh // getgid @@ -263,19 +349,14 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) { // getlogin // getresgid // getresuid -// getrtable // getthrid // ktrace // lfs_bmapv // lfs_markv // lfs_segclean // lfs_segwait -// linkat // mincore // minherit -// mkdirat -// mkfifoat -// mknodat // mount // mquery // msgctl @@ -284,12 +365,10 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) { // msgsnd // nfssvc // nnpfspioctl -// openat // preadv // profil // pwritev // quotactl -// readlinkat // readv // reboot // renameat @@ -299,7 +378,6 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) { // semop // setgroups // setitimer -// setrtable // setsockopt // shmat // shmctl @@ -311,13 +389,11 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) { // sigprocmask // sigreturn // sigsuspend -// symlinkat // sysarch // syscall // threxit // thrsigdivert // thrsleep // thrwakeup -// unlinkat // vfork // writev diff --git a/vendor/golang.org/x/sys/unix/syscall_openbsd_386.go b/vendor/golang.org/x/sys/unix/syscall_openbsd_386.go index 994964a916..d62da60d1f 100644 --- a/vendor/golang.org/x/sys/unix/syscall_openbsd_386.go +++ b/vendor/golang.org/x/sys/unix/syscall_openbsd_386.go @@ -31,3 +31,7 @@ func (msghdr *Msghdr) SetControllen(length int) { func (cmsg *Cmsghdr) SetLen(length int) { cmsg.Len = uint32(length) } + +// SYS___SYSCTL is used by syscall_bsd.go for all BSDs, but in modern versions +// of openbsd/386 the syscall is called sysctl instead of __sysctl. +const SYS___SYSCTL = SYS_SYSCTL diff --git a/vendor/golang.org/x/sys/unix/syscall_openbsd_amd64.go b/vendor/golang.org/x/sys/unix/syscall_openbsd_amd64.go index 649e67fccc..9a35334cba 100644 --- a/vendor/golang.org/x/sys/unix/syscall_openbsd_amd64.go +++ b/vendor/golang.org/x/sys/unix/syscall_openbsd_amd64.go @@ -31,3 +31,7 @@ func (msghdr *Msghdr) SetControllen(length int) { func (cmsg *Cmsghdr) SetLen(length int) { cmsg.Len = uint32(length) } + +// SYS___SYSCTL is used by syscall_bsd.go for all BSDs, but in modern versions +// of openbsd/amd64 the syscall is called sysctl instead of __sysctl. +const SYS___SYSCTL = SYS_SYSCTL diff --git a/vendor/golang.org/x/sys/unix/syscall_openbsd_arm.go b/vendor/golang.org/x/sys/unix/syscall_openbsd_arm.go index 59844f5041..5d812aaea5 100644 --- a/vendor/golang.org/x/sys/unix/syscall_openbsd_arm.go +++ b/vendor/golang.org/x/sys/unix/syscall_openbsd_arm.go @@ -31,3 +31,7 @@ func (msghdr *Msghdr) SetControllen(length int) { func (cmsg *Cmsghdr) SetLen(length int) { cmsg.Len = uint32(length) } + +// SYS___SYSCTL is used by syscall_bsd.go for all BSDs, but in modern versions +// of openbsd/arm the syscall is called sysctl instead of __sysctl. +const SYS___SYSCTL = SYS_SYSCTL diff --git a/vendor/golang.org/x/sys/unix/syscall_solaris.go b/vendor/golang.org/x/sys/unix/syscall_solaris.go index 3ab9e07c8c..e478012753 100644 --- a/vendor/golang.org/x/sys/unix/syscall_solaris.go +++ b/vendor/golang.org/x/sys/unix/syscall_solaris.go @@ -23,6 +23,7 @@ type syscallFunc uintptr func rawSysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) func sysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) +// SockaddrDatalink implements the Sockaddr interface for AF_LINK type sockets. type SockaddrDatalink struct { Family uint16 Index uint16 @@ -34,31 +35,6 @@ type SockaddrDatalink struct { raw RawSockaddrDatalink } -func clen(n []byte) int { - for i := 0; i < len(n); i++ { - if n[i] == 0 { - return i - } - } - return len(n) -} - -func direntIno(buf []byte) (uint64, bool) { - return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino)) -} - -func direntReclen(buf []byte) (uint64, bool) { - return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen)) -} - -func direntNamlen(buf []byte) (uint64, bool) { - reclen, ok := direntReclen(buf) - if !ok { - return 0, false - } - return reclen - uint64(unsafe.Offsetof(Dirent{}.Name)), true -} - //sysnb pipe(p *[2]_C_int) (n int, err error) func Pipe(p []int) (err error) { @@ -136,7 +112,19 @@ func Getsockname(fd int) (sa Sockaddr, err error) { if err = getsockname(fd, &rsa, &len); err != nil { return } - return anyToSockaddr(&rsa) + return anyToSockaddr(fd, &rsa) +} + +// GetsockoptString returns the string value of the socket option opt for the +// socket associated with fd at the given socket level. +func GetsockoptString(fd, level, opt int) (string, error) { + buf := make([]byte, 256) + vallen := _Socklen(len(buf)) + err := getsockopt(fd, level, opt, unsafe.Pointer(&buf[0]), &vallen) + if err != nil { + return "", err + } + return string(buf[:vallen-1]), nil } const ImplementsGetwd = true @@ -324,6 +312,16 @@ func UtimesNanoAt(dirfd int, path string, ts []Timespec, flags int) error { //sys fcntl(fd int, cmd int, arg int) (val int, err error) +// FcntlInt performs a fcntl syscall on fd with the provided command and argument. +func FcntlInt(fd uintptr, cmd, arg int) (int, error) { + valptr, _, errno := sysvicall6(uintptr(unsafe.Pointer(&procfcntl)), 3, uintptr(fd), uintptr(cmd), uintptr(arg), 0, 0, 0) + var err error + if errno != 0 { + err = errno + } + return int(valptr), err +} + // FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command. func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error { _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procfcntl)), 3, uintptr(fd), uintptr(cmd), uintptr(unsafe.Pointer(lk)), 0, 0, 0) @@ -362,7 +360,7 @@ func Futimes(fd int, tv []Timeval) error { return futimesat(fd, nil, (*[2]Timeval)(unsafe.Pointer(&tv[0]))) } -func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) { +func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { switch rsa.Addr.Family { case AF_UNIX: pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa)) @@ -413,7 +411,7 @@ func Accept(fd int) (nfd int, sa Sockaddr, err error) { if nfd == -1 { return } - sa, err = anyToSockaddr(&rsa) + sa, err = anyToSockaddr(fd, &rsa) if err != nil { Close(nfd) nfd = 0 @@ -450,7 +448,7 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from oobn = int(msg.Accrightslen) // source address is only specified if the socket is unconnected if rsa.Addr.Family != AF_UNSPEC { - from, err = anyToSockaddr(&rsa) + from, err = anyToSockaddr(fd, &rsa) } return } @@ -542,11 +540,11 @@ func IoctlSetInt(fd int, req uint, value int) (err error) { return ioctl(fd, req, uintptr(value)) } -func IoctlSetWinsize(fd int, req uint, value *Winsize) (err error) { +func ioctlSetWinsize(fd int, req uint, value *Winsize) (err error) { return ioctl(fd, req, uintptr(unsafe.Pointer(value))) } -func IoctlSetTermios(fd int, req uint, value *Termios) (err error) { +func ioctlSetTermios(fd int, req uint, value *Termios) (err error) { return ioctl(fd, req, uintptr(unsafe.Pointer(value))) } @@ -587,6 +585,13 @@ func Poll(fds []PollFd, timeout int) (n int, err error) { return poll(&fds[0], len(fds), timeout) } +func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { + if raceenabled { + raceReleaseMerge(unsafe.Pointer(&ioSync)) + } + return sendfile(outfd, infd, offset, count) +} + /* * Exposed directly */ @@ -601,15 +606,17 @@ func Poll(fds []PollFd, timeout int) (n int, err error) { //sys Dup(fd int) (nfd int, err error) //sys Dup2(oldfd int, newfd int) (err error) //sys Exit(code int) +//sys Faccessat(dirfd int, path string, mode uint32, flags int) (err error) //sys Fchdir(fd int) (err error) //sys Fchmod(fd int, mode uint32) (err error) //sys Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) //sys Fchown(fd int, uid int, gid int) (err error) //sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) //sys Fdatasync(fd int) (err error) -//sys Flock(fd int, how int) (err error) +//sys Flock(fd int, how int) (err error) //sys Fpathconf(fd int, name int) (val int, err error) //sys Fstat(fd int, stat *Stat_t) (err error) +//sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) //sys Fstatvfs(fd int, vfsstat *Statvfs_t) (err error) //sys Getdents(fd int, buf []byte, basep *uintptr) (n int, err error) //sysnb Getgid() (gid int) @@ -655,6 +662,7 @@ func Poll(fds []PollFd, timeout int) (n int, err error) { //sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) //sys Rmdir(path string) (err error) //sys Seek(fd int, offset int64, whence int) (newoffset int64, err error) = lseek +//sys Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) //sysnb Setegid(egid int) (err error) //sysnb Seteuid(euid int) (err error) //sysnb Setgid(gid int) (err error) @@ -686,6 +694,7 @@ func Poll(fds []PollFd, timeout int) (n int, err error) { //sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) = libsocket.__xnet_connect //sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) //sys munmap(addr uintptr, length uintptr) (err error) +//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) = libsendfile.sendfile //sys sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) = libsocket.__xnet_sendto //sys socket(domain int, typ int, proto int) (fd int, err error) = libsocket.__xnet_socket //sysnb socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) = libsocket.__xnet_socketpair diff --git a/vendor/golang.org/x/sys/unix/syscall_solaris_amd64.go b/vendor/golang.org/x/sys/unix/syscall_solaris_amd64.go index 9d4e7a678f..91c32ddf02 100644 --- a/vendor/golang.org/x/sys/unix/syscall_solaris_amd64.go +++ b/vendor/golang.org/x/sys/unix/syscall_solaris_amd64.go @@ -21,8 +21,3 @@ func (iov *Iovec) SetLen(length int) { func (cmsg *Cmsghdr) SetLen(length int) { cmsg.Len = uint32(length) } - -func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { - // TODO(aram): implement this, see issue 5847. - panic("unimplemented") -} diff --git a/vendor/golang.org/x/sys/unix/syscall_unix.go b/vendor/golang.org/x/sys/unix/syscall_unix.go index 3ed8a91f5c..33583a22b6 100644 --- a/vendor/golang.org/x/sys/unix/syscall_unix.go +++ b/vendor/golang.org/x/sys/unix/syscall_unix.go @@ -2,12 +2,13 @@ // 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 netbsd openbsd solaris +// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package unix import ( - "runtime" + "bytes" + "sort" "sync" "syscall" "unsafe" @@ -19,13 +20,6 @@ var ( Stderr = 2 ) -const ( - darwin64Bit = runtime.GOOS == "darwin" && sizeofPtr == 8 - dragonfly64Bit = runtime.GOOS == "dragonfly" && sizeofPtr == 8 - netbsd32Bit = runtime.GOOS == "netbsd" && sizeofPtr == 4 - solaris64Bit = runtime.GOOS == "solaris" && sizeofPtr == 8 -) - // Do the interface allocations only once for common // Errno values. var ( @@ -50,6 +44,37 @@ func errnoErr(e syscall.Errno) error { return e } +// ErrnoName returns the error name for error number e. +func ErrnoName(e syscall.Errno) string { + i := sort.Search(len(errorList), func(i int) bool { + return errorList[i].num >= e + }) + if i < len(errorList) && errorList[i].num == e { + return errorList[i].name + } + return "" +} + +// SignalName returns the signal name for signal number s. +func SignalName(s syscall.Signal) string { + i := sort.Search(len(signalList), func(i int) bool { + return signalList[i].num >= s + }) + if i < len(signalList) && signalList[i].num == s { + return signalList[i].name + } + return "" +} + +// clen returns the index of the first NULL byte in n or len(n) if n contains no NULL byte. +func clen(n []byte) int { + i := bytes.IndexByte(n, 0) + if i == -1 { + i = len(n) + } + return i +} + // Mmap manager, for use by operating system-specific implementations. type mmapper struct { @@ -138,16 +163,19 @@ func Write(fd int, p []byte) (n int, err error) { // creation of IPv6 sockets to return EAFNOSUPPORT. var SocketDisableIPv6 bool +// Sockaddr represents a socket address. type Sockaddr interface { sockaddr() (ptr unsafe.Pointer, len _Socklen, err error) // lowercase; only we can define Sockaddrs } +// SockaddrInet4 implements the Sockaddr interface for AF_INET type sockets. type SockaddrInet4 struct { Port int Addr [4]byte raw RawSockaddrInet4 } +// SockaddrInet6 implements the Sockaddr interface for AF_INET6 type sockets. type SockaddrInet6 struct { Port int ZoneId uint32 @@ -155,6 +183,7 @@ type SockaddrInet6 struct { raw RawSockaddrInet6 } +// SockaddrUnix implements the Sockaddr interface for AF_UNIX type sockets. type SockaddrUnix struct { Name string raw RawSockaddrUnix @@ -182,7 +211,14 @@ func Getpeername(fd int) (sa Sockaddr, err error) { if err = getpeername(fd, &rsa, &len); err != nil { return } - return anyToSockaddr(&rsa) + return anyToSockaddr(fd, &rsa) +} + +func GetsockoptByte(fd, level, opt int) (value byte, err error) { + var n byte + vallen := _Socklen(1) + err = getsockopt(fd, level, opt, unsafe.Pointer(&n), &vallen) + return n, err } func GetsockoptInt(fd, level, opt int) (value int, err error) { @@ -192,6 +228,54 @@ func GetsockoptInt(fd, level, opt int) (value int, err error) { return int(n), err } +func GetsockoptInet4Addr(fd, level, opt int) (value [4]byte, err error) { + vallen := _Socklen(4) + err = getsockopt(fd, level, opt, unsafe.Pointer(&value[0]), &vallen) + return value, err +} + +func GetsockoptIPMreq(fd, level, opt int) (*IPMreq, error) { + var value IPMreq + vallen := _Socklen(SizeofIPMreq) + err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen) + return &value, err +} + +func GetsockoptIPv6Mreq(fd, level, opt int) (*IPv6Mreq, error) { + var value IPv6Mreq + vallen := _Socklen(SizeofIPv6Mreq) + err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen) + return &value, err +} + +func GetsockoptIPv6MTUInfo(fd, level, opt int) (*IPv6MTUInfo, error) { + var value IPv6MTUInfo + vallen := _Socklen(SizeofIPv6MTUInfo) + err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen) + return &value, err +} + +func GetsockoptICMPv6Filter(fd, level, opt int) (*ICMPv6Filter, error) { + var value ICMPv6Filter + vallen := _Socklen(SizeofICMPv6Filter) + err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen) + return &value, err +} + +func GetsockoptLinger(fd, level, opt int) (*Linger, error) { + var linger Linger + vallen := _Socklen(SizeofLinger) + err := getsockopt(fd, level, opt, unsafe.Pointer(&linger), &vallen) + return &linger, err +} + +func GetsockoptTimeval(fd, level, opt int) (*Timeval, error) { + var tv Timeval + vallen := _Socklen(unsafe.Sizeof(tv)) + err := getsockopt(fd, level, opt, unsafe.Pointer(&tv), &vallen) + return &tv, err +} + func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error) { var rsa RawSockaddrAny var len _Socklen = SizeofSockaddrAny @@ -199,7 +283,7 @@ func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error) { return } if rsa.Addr.Family != AF_UNSPEC { - from, err = anyToSockaddr(&rsa) + from, err = anyToSockaddr(fd, &rsa) } return } @@ -267,13 +351,6 @@ func Socketpair(domain, typ, proto int) (fd [2]int, err error) { return } -func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { - if raceenabled { - raceReleaseMerge(unsafe.Pointer(&ioSync)) - } - return sendfile(outfd, infd, offset, count) -} - var ioSync int64 func CloseOnExec(fd int) { fcntl(fd, F_SETFD, FD_CLOEXEC) } @@ -291,3 +368,12 @@ func SetNonblock(fd int, nonblocking bool) (err error) { _, err = fcntl(fd, F_SETFL, flag) return err } + +// Exec calls execve(2), which replaces the calling executable in the process +// tree. argv0 should be the full path to an executable ("/bin/ls") and the +// executable name should also be the first argument in argv (["ls", "-l"]). +// envv are the environment variables that should be passed to the new +// process (["USER=go", "PWD=/tmp"]). +func Exec(argv0 string, argv []string, envv []string) error { + return syscall.Exec(argv0, argv, envv) +} diff --git a/vendor/golang.org/x/sys/unix/syscall_unix_gc.go b/vendor/golang.org/x/sys/unix/syscall_unix_gc.go index 4cb8e8edf1..1c70d1b690 100644 --- a/vendor/golang.org/x/sys/unix/syscall_unix_gc.go +++ b/vendor/golang.org/x/sys/unix/syscall_unix_gc.go @@ -3,7 +3,7 @@ // license that can be found in the LICENSE file. // +build darwin dragonfly freebsd linux netbsd openbsd solaris -// +build !gccgo +// +build !gccgo,!ppc64le,!ppc64 package unix diff --git a/vendor/golang.org/x/sys/unix/syscall_unix_gc_ppc64x.go b/vendor/golang.org/x/sys/unix/syscall_unix_gc_ppc64x.go new file mode 100644 index 0000000000..86dc765aba --- /dev/null +++ b/vendor/golang.org/x/sys/unix/syscall_unix_gc_ppc64x.go @@ -0,0 +1,24 @@ +// 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 linux +// +build ppc64le ppc64 +// +build !gccgo + +package unix + +import "syscall" + +func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) { + return syscall.Syscall(trap, a1, a2, a3) +} +func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) { + return syscall.Syscall6(trap, a1, a2, a3, a4, a5, a6) +} +func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) { + return syscall.RawSyscall(trap, a1, a2, a3) +} +func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) { + return syscall.RawSyscall6(trap, a1, a2, a3, a4, a5, a6) +} diff --git a/vendor/golang.org/x/sys/unix/timestruct.go b/vendor/golang.org/x/sys/unix/timestruct.go index 139fbbebbb..4a672f5694 100644 --- a/vendor/golang.org/x/sys/unix/timestruct.go +++ b/vendor/golang.org/x/sys/unix/timestruct.go @@ -2,10 +2,12 @@ // 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 netbsd openbsd solaris +// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package unix +import "time" + // TimespecToNsec converts a Timespec value into a number of // nanoseconds since the Unix epoch. func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) } @@ -22,6 +24,24 @@ func NsecToTimespec(nsec int64) Timespec { return setTimespec(sec, nsec) } +// TimeToTimespec converts t into a Timespec. +// On some 32-bit systems the range of valid Timespec values are smaller +// than that of time.Time values. So if t is out of the valid range of +// Timespec, it returns a zero Timespec and ERANGE. +func TimeToTimespec(t time.Time) (Timespec, error) { + sec := t.Unix() + nsec := int64(t.Nanosecond()) + ts := setTimespec(sec, nsec) + + // Currently all targets have either int32 or int64 for Timespec.Sec. + // If there were a new target with floating point type for it, we have + // to consider the rounding error. + if int64(ts.Sec) != sec { + return Timespec{}, ERANGE + } + return ts, nil +} + // TimevalToNsec converts a Timeval value into a number of nanoseconds // since the Unix epoch. func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 } diff --git a/vendor/golang.org/x/sys/unix/xattr_bsd.go b/vendor/golang.org/x/sys/unix/xattr_bsd.go new file mode 100644 index 0000000000..30c1d71f4e --- /dev/null +++ b/vendor/golang.org/x/sys/unix/xattr_bsd.go @@ -0,0 +1,240 @@ +// 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 freebsd netbsd + +package unix + +import ( + "strings" + "unsafe" +) + +// Derive extattr namespace and attribute name + +func xattrnamespace(fullattr string) (ns int, attr string, err error) { + s := strings.IndexByte(fullattr, '.') + if s == -1 { + return -1, "", ENOATTR + } + + namespace := fullattr[0:s] + attr = fullattr[s+1:] + + switch namespace { + case "user": + return EXTATTR_NAMESPACE_USER, attr, nil + case "system": + return EXTATTR_NAMESPACE_SYSTEM, attr, nil + default: + return -1, "", ENOATTR + } +} + +func initxattrdest(dest []byte, idx int) (d unsafe.Pointer) { + if len(dest) > idx { + return unsafe.Pointer(&dest[idx]) + } else { + return unsafe.Pointer(_zero) + } +} + +// FreeBSD and NetBSD implement their own syscalls to handle extended attributes + +func Getxattr(file string, attr string, dest []byte) (sz int, err error) { + d := initxattrdest(dest, 0) + destsize := len(dest) + + nsid, a, err := xattrnamespace(attr) + if err != nil { + return -1, err + } + + return ExtattrGetFile(file, nsid, a, uintptr(d), destsize) +} + +func Fgetxattr(fd int, attr string, dest []byte) (sz int, err error) { + d := initxattrdest(dest, 0) + destsize := len(dest) + + nsid, a, err := xattrnamespace(attr) + if err != nil { + return -1, err + } + + return ExtattrGetFd(fd, nsid, a, uintptr(d), destsize) +} + +func Lgetxattr(link string, attr string, dest []byte) (sz int, err error) { + d := initxattrdest(dest, 0) + destsize := len(dest) + + nsid, a, err := xattrnamespace(attr) + if err != nil { + return -1, err + } + + return ExtattrGetLink(link, nsid, a, uintptr(d), destsize) +} + +// flags are unused on FreeBSD + +func Fsetxattr(fd int, attr string, data []byte, flags int) (err error) { + var d unsafe.Pointer + if len(data) > 0 { + d = unsafe.Pointer(&data[0]) + } + datasiz := len(data) + + nsid, a, err := xattrnamespace(attr) + if err != nil { + return + } + + _, err = ExtattrSetFd(fd, nsid, a, uintptr(d), datasiz) + return +} + +func Setxattr(file string, attr string, data []byte, flags int) (err error) { + var d unsafe.Pointer + if len(data) > 0 { + d = unsafe.Pointer(&data[0]) + } + datasiz := len(data) + + nsid, a, err := xattrnamespace(attr) + if err != nil { + return + } + + _, err = ExtattrSetFile(file, nsid, a, uintptr(d), datasiz) + return +} + +func Lsetxattr(link string, attr string, data []byte, flags int) (err error) { + var d unsafe.Pointer + if len(data) > 0 { + d = unsafe.Pointer(&data[0]) + } + datasiz := len(data) + + nsid, a, err := xattrnamespace(attr) + if err != nil { + return + } + + _, err = ExtattrSetLink(link, nsid, a, uintptr(d), datasiz) + return +} + +func Removexattr(file string, attr string) (err error) { + nsid, a, err := xattrnamespace(attr) + if err != nil { + return + } + + err = ExtattrDeleteFile(file, nsid, a) + return +} + +func Fremovexattr(fd int, attr string) (err error) { + nsid, a, err := xattrnamespace(attr) + if err != nil { + return + } + + err = ExtattrDeleteFd(fd, nsid, a) + return +} + +func Lremovexattr(link string, attr string) (err error) { + nsid, a, err := xattrnamespace(attr) + if err != nil { + return + } + + err = ExtattrDeleteLink(link, nsid, a) + return +} + +func Listxattr(file string, dest []byte) (sz int, err error) { + d := initxattrdest(dest, 0) + destsiz := len(dest) + + // FreeBSD won't allow you to list xattrs from multiple namespaces + s := 0 + for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} { + stmp, e := ExtattrListFile(file, nsid, uintptr(d), destsiz) + + /* Errors accessing system attrs are ignored so that + * we can implement the Linux-like behavior of omitting errors that + * we don't have read permissions on + * + * Linux will still error if we ask for user attributes on a file that + * we don't have read permissions on, so don't ignore those errors + */ + if e != nil && e == EPERM && nsid != EXTATTR_NAMESPACE_USER { + continue + } else if e != nil { + return s, e + } + + s += stmp + destsiz -= s + if destsiz < 0 { + destsiz = 0 + } + d = initxattrdest(dest, s) + } + + return s, nil +} + +func Flistxattr(fd int, dest []byte) (sz int, err error) { + d := initxattrdest(dest, 0) + destsiz := len(dest) + + s := 0 + for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} { + stmp, e := ExtattrListFd(fd, nsid, uintptr(d), destsiz) + if e != nil && e == EPERM && nsid != EXTATTR_NAMESPACE_USER { + continue + } else if e != nil { + return s, e + } + + s += stmp + destsiz -= s + if destsiz < 0 { + destsiz = 0 + } + d = initxattrdest(dest, s) + } + + return s, nil +} + +func Llistxattr(link string, dest []byte) (sz int, err error) { + d := initxattrdest(dest, 0) + destsiz := len(dest) + + s := 0 + for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} { + stmp, e := ExtattrListLink(link, nsid, uintptr(d), destsiz) + if e != nil && e == EPERM && nsid != EXTATTR_NAMESPACE_USER { + continue + } else if e != nil { + return s, e + } + + s += stmp + destsiz -= s + if destsiz < 0 { + destsiz = 0 + } + d = initxattrdest(dest, s) + } + + return s, nil +} diff --git a/vendor/golang.org/x/sys/unix/zerrors_aix_ppc.go b/vendor/golang.org/x/sys/unix/zerrors_aix_ppc.go new file mode 100644 index 0000000000..4b7b965027 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/zerrors_aix_ppc.go @@ -0,0 +1,1372 @@ +// mkerrors.sh -maix32 +// Code generated by the command above; see README.md. DO NOT EDIT. + +// +build ppc,aix + +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs -- -maix32 _const.go + +package unix + +import "syscall" + +const ( + AF_APPLETALK = 0x10 + AF_BYPASS = 0x19 + AF_CCITT = 0xa + AF_CHAOS = 0x5 + AF_DATAKIT = 0x9 + AF_DECnet = 0xc + AF_DLI = 0xd + AF_ECMA = 0x8 + AF_HYLINK = 0xf + AF_IMPLINK = 0x3 + AF_INET = 0x2 + AF_INET6 = 0x18 + AF_INTF = 0x14 + AF_ISO = 0x7 + AF_LAT = 0xe + AF_LINK = 0x12 + AF_LOCAL = 0x1 + AF_MAX = 0x1e + AF_NDD = 0x17 + AF_NETWARE = 0x16 + AF_NS = 0x6 + AF_OSI = 0x7 + AF_PUP = 0x4 + AF_RIF = 0x15 + AF_ROUTE = 0x11 + AF_SNA = 0xb + AF_UNIX = 0x1 + AF_UNSPEC = 0x0 + ALTWERASE = 0x400000 + ARPHRD_802_3 = 0x6 + ARPHRD_802_5 = 0x6 + ARPHRD_ETHER = 0x1 + ARPHRD_FDDI = 0x1 + B0 = 0x0 + B110 = 0x3 + B1200 = 0x9 + B134 = 0x4 + B150 = 0x5 + B1800 = 0xa + B19200 = 0xe + B200 = 0x6 + B2400 = 0xb + B300 = 0x7 + B38400 = 0xf + B4800 = 0xc + B50 = 0x1 + B600 = 0x8 + B75 = 0x2 + B9600 = 0xd + BRKINT = 0x2 + BS0 = 0x0 + BS1 = 0x1000 + BSDLY = 0x1000 + CAP_AACCT = 0x6 + CAP_ARM_APPLICATION = 0x5 + CAP_BYPASS_RAC_VMM = 0x3 + CAP_CLEAR = 0x0 + CAP_CREDENTIALS = 0x7 + CAP_EFFECTIVE = 0x1 + CAP_EWLM_AGENT = 0x4 + CAP_INHERITABLE = 0x2 + CAP_MAXIMUM = 0x7 + CAP_NUMA_ATTACH = 0x2 + CAP_PERMITTED = 0x3 + CAP_PROPAGATE = 0x1 + CAP_PROPOGATE = 0x1 + CAP_SET = 0x1 + CBAUD = 0xf + CFLUSH = 0xf + CIBAUD = 0xf0000 + CLOCAL = 0x800 + CLOCK_MONOTONIC = 0xa + CLOCK_PROCESS_CPUTIME_ID = 0xb + CLOCK_REALTIME = 0x9 + CLOCK_THREAD_CPUTIME_ID = 0xc + CR0 = 0x0 + CR1 = 0x100 + CR2 = 0x200 + CR3 = 0x300 + CRDLY = 0x300 + CREAD = 0x80 + CS5 = 0x0 + CS6 = 0x10 + CS7 = 0x20 + CS8 = 0x30 + CSIOCGIFCONF = -0x3ff796dc + CSIZE = 0x30 + CSMAP_DIR = "/usr/lib/nls/csmap/" + CSTART = '\021' + CSTOP = '\023' + CSTOPB = 0x40 + CSUSP = 0x1a + ECHO = 0x8 + ECHOCTL = 0x20000 + ECHOE = 0x10 + ECHOK = 0x20 + ECHOKE = 0x80000 + ECHONL = 0x40 + ECHOPRT = 0x40000 + ECH_ICMPID = 0x2 + ETHERNET_CSMACD = 0x6 + EVENP = 0x80 + EXCONTINUE = 0x0 + EXDLOK = 0x3 + EXIO = 0x2 + EXPGIO = 0x0 + EXRESUME = 0x2 + EXRETURN = 0x1 + EXSIG = 0x4 + EXTA = 0xe + EXTB = 0xf + EXTRAP = 0x1 + EYEC_RTENTRYA = 0x257274656e747241 + EYEC_RTENTRYF = 0x257274656e747246 + E_ACC = 0x0 + FD_CLOEXEC = 0x1 + FD_SETSIZE = 0xfffe + FF0 = 0x0 + FF1 = 0x2000 + FFDLY = 0x2000 + FLUSHBAND = 0x40 + FLUSHLOW = 0x8 + FLUSHO = 0x100000 + FLUSHR = 0x1 + FLUSHRW = 0x3 + FLUSHW = 0x2 + F_CLOSEM = 0xa + F_DUP2FD = 0xe + F_DUPFD = 0x0 + F_GETFD = 0x1 + F_GETFL = 0x3 + F_GETLK = 0x5 + F_GETLK64 = 0xb + F_GETOWN = 0x8 + F_LOCK = 0x1 + F_OK = 0x0 + F_RDLCK = 0x1 + F_SETFD = 0x2 + F_SETFL = 0x4 + F_SETLK = 0x6 + F_SETLK64 = 0xc + F_SETLKW = 0x7 + F_SETLKW64 = 0xd + F_SETOWN = 0x9 + F_TEST = 0x3 + F_TLOCK = 0x2 + F_TSTLK = 0xf + F_ULOCK = 0x0 + F_UNLCK = 0x3 + F_WRLCK = 0x2 + HUPCL = 0x400 + IBSHIFT = 0x10 + ICANON = 0x2 + ICMP6_FILTER = 0x26 + ICMP6_SEC_SEND_DEL = 0x46 + ICMP6_SEC_SEND_GET = 0x47 + ICMP6_SEC_SEND_SET = 0x44 + ICMP6_SEC_SEND_SET_CGA_ADDR = 0x45 + ICRNL = 0x100 + IEXTEN = 0x200000 + IFA_FIRSTALIAS = 0x2000 + IFA_ROUTE = 0x1 + IFF_64BIT = 0x4000000 + IFF_ALLCAST = 0x20000 + IFF_ALLMULTI = 0x200 + IFF_BPF = 0x8000000 + IFF_BRIDGE = 0x40000 + IFF_BROADCAST = 0x2 + IFF_CANTCHANGE = 0x80c52 + IFF_CHECKSUM_OFFLOAD = 0x10000000 + IFF_D1 = 0x8000 + IFF_D2 = 0x4000 + IFF_D3 = 0x2000 + IFF_D4 = 0x1000 + IFF_DEBUG = 0x4 + IFF_DEVHEALTH = 0x4000 + IFF_DO_HW_LOOPBACK = 0x10000 + IFF_GROUP_ROUTING = 0x2000000 + IFF_IFBUFMGT = 0x800000 + IFF_LINK0 = 0x100000 + IFF_LINK1 = 0x200000 + IFF_LINK2 = 0x400000 + IFF_LOOPBACK = 0x8 + IFF_MULTICAST = 0x80000 + IFF_NOARP = 0x80 + IFF_NOECHO = 0x800 + IFF_NOTRAILERS = 0x20 + IFF_OACTIVE = 0x400 + IFF_POINTOPOINT = 0x10 + IFF_PROMISC = 0x100 + IFF_PSEG = 0x40000000 + IFF_RUNNING = 0x40 + IFF_SIMPLEX = 0x800 + IFF_SNAP = 0x8000 + IFF_TCP_DISABLE_CKSUM = 0x20000000 + IFF_TCP_NOCKSUM = 0x1000000 + IFF_UP = 0x1 + IFF_VIPA = 0x80000000 + IFNAMSIZ = 0x10 + IFO_FLUSH = 0x1 + IFT_1822 = 0x2 + IFT_AAL5 = 0x31 + IFT_ARCNET = 0x23 + IFT_ARCNETPLUS = 0x24 + IFT_ATM = 0x25 + IFT_CEPT = 0x13 + IFT_CLUSTER = 0x3e + IFT_DS3 = 0x1e + IFT_EON = 0x19 + IFT_ETHER = 0x6 + IFT_FCS = 0x3a + IFT_FDDI = 0xf + IFT_FRELAY = 0x20 + IFT_FRELAYDCE = 0x2c + IFT_GIFTUNNEL = 0x3c + IFT_HDH1822 = 0x3 + IFT_HF = 0x3d + IFT_HIPPI = 0x2f + IFT_HSSI = 0x2e + IFT_HY = 0xe + IFT_IB = 0xc7 + IFT_ISDNBASIC = 0x14 + IFT_ISDNPRIMARY = 0x15 + IFT_ISO88022LLC = 0x29 + IFT_ISO88023 = 0x7 + IFT_ISO88024 = 0x8 + IFT_ISO88025 = 0x9 + IFT_ISO88026 = 0xa + IFT_LAPB = 0x10 + IFT_LOCALTALK = 0x2a + IFT_LOOP = 0x18 + IFT_MIOX25 = 0x26 + IFT_MODEM = 0x30 + IFT_NSIP = 0x1b + IFT_OTHER = 0x1 + IFT_P10 = 0xc + IFT_P80 = 0xd + IFT_PARA = 0x22 + IFT_PPP = 0x17 + IFT_PROPMUX = 0x36 + IFT_PROPVIRTUAL = 0x35 + IFT_PTPSERIAL = 0x16 + IFT_RS232 = 0x21 + IFT_SDLC = 0x11 + IFT_SIP = 0x1f + IFT_SLIP = 0x1c + IFT_SMDSDXI = 0x2b + IFT_SMDSICIP = 0x34 + IFT_SN = 0x38 + IFT_SONET = 0x27 + IFT_SONETPATH = 0x32 + IFT_SONETVT = 0x33 + IFT_SP = 0x39 + IFT_STARLAN = 0xb + IFT_T1 = 0x12 + IFT_TUNNEL = 0x3b + IFT_ULTRA = 0x1d + IFT_V35 = 0x2d + IFT_VIPA = 0x37 + IFT_X25 = 0x5 + IFT_X25DDN = 0x4 + IFT_X25PLE = 0x28 + IFT_XETHER = 0x1a + IGNBRK = 0x1 + IGNCR = 0x80 + IGNPAR = 0x4 + IMAXBEL = 0x10000 + INLCR = 0x40 + INPCK = 0x10 + IN_CLASSA_HOST = 0xffffff + IN_CLASSA_MAX = 0x80 + IN_CLASSA_NET = 0xff000000 + IN_CLASSA_NSHIFT = 0x18 + IN_CLASSB_HOST = 0xffff + IN_CLASSB_MAX = 0x10000 + IN_CLASSB_NET = 0xffff0000 + IN_CLASSB_NSHIFT = 0x10 + IN_CLASSC_HOST = 0xff + IN_CLASSC_NET = 0xffffff00 + IN_CLASSC_NSHIFT = 0x8 + IN_CLASSD_HOST = 0xfffffff + IN_CLASSD_NET = 0xf0000000 + IN_CLASSD_NSHIFT = 0x1c + IN_LOOPBACKNET = 0x7f + IN_USE = 0x1 + IPPROTO_AH = 0x33 + IPPROTO_BIP = 0x53 + IPPROTO_DSTOPTS = 0x3c + IPPROTO_EGP = 0x8 + IPPROTO_EON = 0x50 + IPPROTO_ESP = 0x32 + IPPROTO_FRAGMENT = 0x2c + IPPROTO_GGP = 0x3 + IPPROTO_GIF = 0x8c + IPPROTO_GRE = 0x2f + IPPROTO_HOPOPTS = 0x0 + IPPROTO_ICMP = 0x1 + IPPROTO_ICMPV6 = 0x3a + IPPROTO_IDP = 0x16 + IPPROTO_IGMP = 0x2 + IPPROTO_IP = 0x0 + IPPROTO_IPIP = 0x4 + IPPROTO_IPV6 = 0x29 + IPPROTO_LOCAL = 0x3f + IPPROTO_MAX = 0x100 + IPPROTO_MH = 0x87 + IPPROTO_NONE = 0x3b + IPPROTO_PUP = 0xc + IPPROTO_QOS = 0x2d + IPPROTO_RAW = 0xff + IPPROTO_ROUTING = 0x2b + IPPROTO_RSVP = 0x2e + IPPROTO_SCTP = 0x84 + IPPROTO_TCP = 0x6 + IPPROTO_TP = 0x1d + IPPROTO_UDP = 0x11 + IPV6_ADDRFORM = 0x16 + IPV6_ADDR_PREFERENCES = 0x4a + IPV6_ADD_MEMBERSHIP = 0xc + IPV6_AIXRAWSOCKET = 0x39 + IPV6_CHECKSUM = 0x27 + IPV6_DONTFRAG = 0x2d + IPV6_DROP_MEMBERSHIP = 0xd + IPV6_DSTOPTS = 0x36 + IPV6_FLOWINFO_FLOWLABEL = 0xffffff + IPV6_FLOWINFO_PRIFLOW = 0xfffffff + IPV6_FLOWINFO_PRIORITY = 0xf000000 + IPV6_FLOWINFO_SRFLAG = 0x10000000 + IPV6_FLOWINFO_VERSION = 0xf0000000 + IPV6_HOPLIMIT = 0x28 + IPV6_HOPOPTS = 0x34 + IPV6_JOIN_GROUP = 0xc + IPV6_LEAVE_GROUP = 0xd + IPV6_MIPDSTOPTS = 0x36 + IPV6_MULTICAST_HOPS = 0xa + IPV6_MULTICAST_IF = 0x9 + IPV6_MULTICAST_LOOP = 0xb + IPV6_NEXTHOP = 0x30 + IPV6_NOPROBE = 0x1c + IPV6_PATHMTU = 0x2e + IPV6_PKTINFO = 0x21 + IPV6_PKTOPTIONS = 0x24 + IPV6_PRIORITY_10 = 0xa000000 + IPV6_PRIORITY_11 = 0xb000000 + IPV6_PRIORITY_12 = 0xc000000 + IPV6_PRIORITY_13 = 0xd000000 + IPV6_PRIORITY_14 = 0xe000000 + IPV6_PRIORITY_15 = 0xf000000 + IPV6_PRIORITY_8 = 0x8000000 + IPV6_PRIORITY_9 = 0x9000000 + IPV6_PRIORITY_BULK = 0x4000000 + IPV6_PRIORITY_CONTROL = 0x7000000 + IPV6_PRIORITY_FILLER = 0x1000000 + IPV6_PRIORITY_INTERACTIVE = 0x6000000 + IPV6_PRIORITY_RESERVED1 = 0x3000000 + IPV6_PRIORITY_RESERVED2 = 0x5000000 + IPV6_PRIORITY_UNATTENDED = 0x2000000 + IPV6_PRIORITY_UNCHARACTERIZED = 0x0 + IPV6_RECVDSTOPTS = 0x38 + IPV6_RECVHOPLIMIT = 0x29 + IPV6_RECVHOPOPTS = 0x35 + IPV6_RECVHOPS = 0x22 + IPV6_RECVIF = 0x1e + IPV6_RECVPATHMTU = 0x2f + IPV6_RECVPKTINFO = 0x23 + IPV6_RECVRTHDR = 0x33 + IPV6_RECVSRCRT = 0x1d + IPV6_RECVTCLASS = 0x2a + IPV6_RTHDR = 0x32 + IPV6_RTHDRDSTOPTS = 0x37 + IPV6_RTHDR_TYPE_0 = 0x0 + IPV6_RTHDR_TYPE_2 = 0x2 + IPV6_SENDIF = 0x1f + IPV6_SRFLAG_LOOSE = 0x0 + IPV6_SRFLAG_STRICT = 0x10000000 + IPV6_TCLASS = 0x2b + IPV6_TOKEN_LENGTH = 0x40 + IPV6_UNICAST_HOPS = 0x4 + IPV6_USE_MIN_MTU = 0x2c + IPV6_V6ONLY = 0x25 + IPV6_VERSION = 0x60000000 + IP_ADDRFORM = 0x16 + IP_ADD_MEMBERSHIP = 0xc + IP_ADD_SOURCE_MEMBERSHIP = 0x3c + IP_BLOCK_SOURCE = 0x3a + IP_BROADCAST_IF = 0x10 + IP_CACHE_LINE_SIZE = 0x80 + IP_DEFAULT_MULTICAST_LOOP = 0x1 + IP_DEFAULT_MULTICAST_TTL = 0x1 + IP_DF = 0x4000 + IP_DHCPMODE = 0x11 + IP_DONTFRAG = 0x19 + IP_DROP_MEMBERSHIP = 0xd + IP_DROP_SOURCE_MEMBERSHIP = 0x3d + IP_FINDPMTU = 0x1a + IP_HDRINCL = 0x2 + IP_INC_MEMBERSHIPS = 0x14 + IP_INIT_MEMBERSHIP = 0x14 + IP_MAXPACKET = 0xffff + IP_MF = 0x2000 + IP_MSS = 0x240 + IP_MULTICAST_HOPS = 0xa + IP_MULTICAST_IF = 0x9 + IP_MULTICAST_LOOP = 0xb + IP_MULTICAST_TTL = 0xa + IP_OPT = 0x1b + IP_OPTIONS = 0x1 + IP_PMTUAGE = 0x1b + IP_RECVDSTADDR = 0x7 + IP_RECVIF = 0x14 + IP_RECVIFINFO = 0xf + IP_RECVINTERFACE = 0x20 + IP_RECVMACHDR = 0xe + IP_RECVOPTS = 0x5 + IP_RECVRETOPTS = 0x6 + IP_RECVTTL = 0x22 + IP_RETOPTS = 0x8 + IP_SOURCE_FILTER = 0x48 + IP_TOS = 0x3 + IP_TTL = 0x4 + IP_UNBLOCK_SOURCE = 0x3b + IP_UNICAST_HOPS = 0x4 + ISIG = 0x1 + ISTRIP = 0x20 + IUCLC = 0x800 + IXANY = 0x1000 + IXOFF = 0x400 + IXON = 0x200 + I_FLUSH = 0x20005305 + LNOFLSH = 0x8000 + LOCK_EX = 0x2 + LOCK_NB = 0x4 + LOCK_SH = 0x1 + LOCK_UN = 0x8 + MADV_DONTNEED = 0x4 + MADV_NORMAL = 0x0 + MADV_RANDOM = 0x1 + MADV_SEQUENTIAL = 0x2 + MADV_SPACEAVAIL = 0x5 + MADV_WILLNEED = 0x3 + MAP_ANON = 0x10 + MAP_ANONYMOUS = 0x10 + MAP_FILE = 0x0 + MAP_FIXED = 0x100 + MAP_PRIVATE = 0x2 + MAP_SHARED = 0x1 + MAP_TYPE = 0xf0 + MAP_VARIABLE = 0x0 + MCL_CURRENT = 0x100 + MCL_FUTURE = 0x200 + MSG_ANY = 0x4 + MSG_ARGEXT = 0x400 + MSG_BAND = 0x2 + MSG_COMPAT = 0x8000 + MSG_CTRUNC = 0x20 + MSG_DONTROUTE = 0x4 + MSG_EOR = 0x8 + MSG_HIPRI = 0x1 + MSG_MAXIOVLEN = 0x10 + MSG_MPEG2 = 0x80 + MSG_NONBLOCK = 0x4000 + MSG_NOSIGNAL = 0x100 + MSG_OOB = 0x1 + MSG_PEEK = 0x2 + MSG_TRUNC = 0x10 + MSG_WAITALL = 0x40 + MSG_WAITFORONE = 0x200 + MS_ASYNC = 0x10 + MS_EINTR = 0x80 + MS_INVALIDATE = 0x40 + MS_PER_SEC = 0x3e8 + MS_SYNC = 0x20 + NL0 = 0x0 + NL1 = 0x4000 + NL2 = 0x8000 + NL3 = 0xc000 + NLDLY = 0x4000 + NOFLSH = 0x80 + NOFLUSH = 0x80000000 + OCRNL = 0x8 + OFDEL = 0x80 + OFILL = 0x40 + OLCUC = 0x2 + ONLCR = 0x4 + ONLRET = 0x20 + ONOCR = 0x10 + ONOEOT = 0x80000 + OPOST = 0x1 + OXTABS = 0x40000 + O_ACCMODE = 0x23 + O_APPEND = 0x8 + O_CIO = 0x80 + O_CIOR = 0x800000000 + O_CLOEXEC = 0x800000 + O_CREAT = 0x100 + O_DEFER = 0x2000 + O_DELAY = 0x4000 + O_DIRECT = 0x8000000 + O_DIRECTORY = 0x80000 + O_DSYNC = 0x400000 + O_EFSOFF = 0x400000000 + O_EFSON = 0x200000000 + O_EXCL = 0x400 + O_EXEC = 0x20 + O_LARGEFILE = 0x4000000 + O_NDELAY = 0x8000 + O_NOCACHE = 0x100000 + O_NOCTTY = 0x800 + O_NOFOLLOW = 0x1000000 + O_NONBLOCK = 0x4 + O_NONE = 0x3 + O_NSHARE = 0x10000 + O_RAW = 0x100000000 + O_RDONLY = 0x0 + O_RDWR = 0x2 + O_RSHARE = 0x1000 + O_RSYNC = 0x200000 + O_SEARCH = 0x20 + O_SNAPSHOT = 0x40 + O_SYNC = 0x10 + O_TRUNC = 0x200 + O_TTY_INIT = 0x0 + O_WRONLY = 0x1 + PARENB = 0x100 + PAREXT = 0x100000 + PARMRK = 0x8 + PARODD = 0x200 + PENDIN = 0x20000000 + PRIO_PGRP = 0x1 + PRIO_PROCESS = 0x0 + PRIO_USER = 0x2 + PROT_EXEC = 0x4 + PROT_NONE = 0x0 + PROT_READ = 0x1 + PROT_WRITE = 0x2 + PR_64BIT = 0x20 + PR_ADDR = 0x2 + PR_ARGEXT = 0x400 + PR_ATOMIC = 0x1 + PR_CONNREQUIRED = 0x4 + PR_FASTHZ = 0x5 + PR_INP = 0x40 + PR_INTRLEVEL = 0x8000 + PR_MLS = 0x100 + PR_MLS_1_LABEL = 0x200 + PR_NOEOR = 0x4000 + PR_RIGHTS = 0x10 + PR_SLOWHZ = 0x2 + PR_WANTRCVD = 0x8 + RLIMIT_AS = 0x6 + RLIMIT_CORE = 0x4 + RLIMIT_CPU = 0x0 + RLIMIT_DATA = 0x2 + RLIMIT_FSIZE = 0x1 + RLIMIT_NOFILE = 0x7 + RLIMIT_NPROC = 0x9 + RLIMIT_RSS = 0x5 + RLIMIT_STACK = 0x3 + RLIM_INFINITY = 0x7fffffff + RTAX_AUTHOR = 0x6 + RTAX_BRD = 0x7 + RTAX_DST = 0x0 + RTAX_GATEWAY = 0x1 + RTAX_GENMASK = 0x3 + RTAX_IFA = 0x5 + RTAX_IFP = 0x4 + RTAX_MAX = 0x8 + RTAX_NETMASK = 0x2 + RTA_AUTHOR = 0x40 + RTA_BRD = 0x80 + RTA_DOWNSTREAM = 0x100 + RTA_DST = 0x1 + RTA_GATEWAY = 0x2 + RTA_GENMASK = 0x8 + RTA_IFA = 0x20 + RTA_IFP = 0x10 + RTA_NETMASK = 0x4 + RTC_IA64 = 0x3 + RTC_POWER = 0x1 + RTC_POWER_PC = 0x2 + RTF_ACTIVE_DGD = 0x1000000 + RTF_BCE = 0x80000 + RTF_BLACKHOLE = 0x1000 + RTF_BROADCAST = 0x400000 + RTF_BUL = 0x2000 + RTF_CLONE = 0x10000 + RTF_CLONED = 0x20000 + RTF_CLONING = 0x100 + RTF_DONE = 0x40 + RTF_DYNAMIC = 0x10 + RTF_FREE_IN_PROG = 0x4000000 + RTF_GATEWAY = 0x2 + RTF_HOST = 0x4 + RTF_LLINFO = 0x400 + RTF_LOCAL = 0x200000 + RTF_MASK = 0x80 + RTF_MODIFIED = 0x20 + RTF_MULTICAST = 0x800000 + RTF_PERMANENT6 = 0x8000000 + RTF_PINNED = 0x100000 + RTF_PROTO1 = 0x8000 + RTF_PROTO2 = 0x4000 + RTF_PROTO3 = 0x40000 + RTF_REJECT = 0x8 + RTF_SMALLMTU = 0x40000 + RTF_STATIC = 0x800 + RTF_STOPSRCH = 0x2000000 + RTF_UNREACHABLE = 0x10000000 + RTF_UP = 0x1 + RTF_XRESOLVE = 0x200 + RTM_ADD = 0x1 + RTM_CHANGE = 0x3 + RTM_DELADDR = 0xd + RTM_DELETE = 0x2 + RTM_EXPIRE = 0xf + RTM_GET = 0x4 + RTM_GETNEXT = 0x11 + RTM_IFINFO = 0xe + RTM_LOCK = 0x8 + RTM_LOSING = 0x5 + RTM_MISS = 0x7 + RTM_NEWADDR = 0xc + RTM_OLDADD = 0x9 + RTM_OLDDEL = 0xa + RTM_REDIRECT = 0x6 + RTM_RESOLVE = 0xb + RTM_RTLOST = 0x10 + RTM_RTTUNIT = 0xf4240 + RTM_SAMEADDR = 0x12 + RTM_SET = 0x13 + RTM_VERSION = 0x2 + RTM_VERSION_GR = 0x4 + RTM_VERSION_GR_COMPAT = 0x3 + RTM_VERSION_POLICY = 0x5 + RTM_VERSION_POLICY_EXT = 0x6 + RTM_VERSION_POLICY_PRFN = 0x7 + RTV_EXPIRE = 0x4 + RTV_HOPCOUNT = 0x2 + RTV_MTU = 0x1 + RTV_RPIPE = 0x8 + RTV_RTT = 0x40 + RTV_RTTVAR = 0x80 + RTV_SPIPE = 0x10 + RTV_SSTHRESH = 0x20 + RUSAGE_CHILDREN = -0x1 + RUSAGE_SELF = 0x0 + RUSAGE_THREAD = 0x1 + SCM_RIGHTS = 0x1 + SHUT_RD = 0x0 + SHUT_RDWR = 0x2 + SHUT_WR = 0x1 + SIGMAX64 = 0xff + SIGQUEUE_MAX = 0x20 + SIOCADDIFVIPA = 0x20006942 + SIOCADDMTU = -0x7ffb9690 + SIOCADDMULTI = -0x7fdf96cf + SIOCADDNETID = -0x7fd796a9 + SIOCADDRT = -0x7fcf8df6 + SIOCAIFADDR = -0x7fbf96e6 + SIOCATMARK = 0x40047307 + SIOCDARP = -0x7fb396e0 + SIOCDELIFVIPA = 0x20006943 + SIOCDELMTU = -0x7ffb968f + SIOCDELMULTI = -0x7fdf96ce + SIOCDELPMTU = -0x7fd78ff6 + SIOCDELRT = -0x7fcf8df5 + SIOCDIFADDR = -0x7fd796e7 + SIOCDNETOPT = -0x3ffe9680 + SIOCDX25XLATE = -0x7fd7969b + SIOCFIFADDR = -0x7fdf966d + SIOCGARP = -0x3fb396da + SIOCGETMTUS = 0x2000696f + SIOCGETSGCNT = -0x3feb8acc + SIOCGETVIFCNT = -0x3feb8acd + SIOCGHIWAT = 0x40047301 + SIOCGIFADDR = -0x3fd796df + SIOCGIFADDRS = 0x2000698c + SIOCGIFBAUDRATE = -0x3fd79693 + SIOCGIFBRDADDR = -0x3fd796dd + SIOCGIFCONF = -0x3ff796bb + SIOCGIFCONFGLOB = -0x3ff79670 + SIOCGIFDSTADDR = -0x3fd796de + SIOCGIFFLAGS = -0x3fd796ef + SIOCGIFGIDLIST = 0x20006968 + SIOCGIFHWADDR = -0x3fab966b + SIOCGIFMETRIC = -0x3fd796e9 + SIOCGIFMTU = -0x3fd796aa + SIOCGIFNETMASK = -0x3fd796db + SIOCGIFOPTIONS = -0x3fd796d6 + SIOCGISNO = -0x3fd79695 + SIOCGLOADF = -0x3ffb967e + SIOCGLOWAT = 0x40047303 + SIOCGNETOPT = -0x3ffe96a5 + SIOCGNETOPT1 = -0x3fdf967f + SIOCGNMTUS = 0x2000696e + SIOCGPGRP = 0x40047309 + SIOCGSIZIFCONF = 0x4004696a + SIOCGSRCFILTER = -0x3fe796cb + SIOCGTUNEPHASE = -0x3ffb9676 + SIOCGX25XLATE = -0x3fd7969c + SIOCIFATTACH = -0x7fdf9699 + SIOCIFDETACH = -0x7fdf969a + SIOCIFGETPKEY = -0x7fdf969b + SIOCIF_ATM_DARP = -0x7fdf9683 + SIOCIF_ATM_DUMPARP = -0x7fdf9685 + SIOCIF_ATM_GARP = -0x7fdf9682 + SIOCIF_ATM_IDLE = -0x7fdf9686 + SIOCIF_ATM_SARP = -0x7fdf9681 + SIOCIF_ATM_SNMPARP = -0x7fdf9687 + SIOCIF_ATM_SVC = -0x7fdf9684 + SIOCIF_ATM_UBR = -0x7fdf9688 + SIOCIF_DEVHEALTH = -0x7ffb966c + SIOCIF_IB_ARP_INCOMP = -0x7fdf9677 + SIOCIF_IB_ARP_TIMER = -0x7fdf9678 + SIOCIF_IB_CLEAR_PINFO = -0x3fdf966f + SIOCIF_IB_DEL_ARP = -0x7fdf967f + SIOCIF_IB_DEL_PINFO = -0x3fdf9670 + SIOCIF_IB_DUMP_ARP = -0x7fdf9680 + SIOCIF_IB_GET_ARP = -0x7fdf967e + SIOCIF_IB_GET_INFO = -0x3f879675 + SIOCIF_IB_GET_STATS = -0x3f879672 + SIOCIF_IB_NOTIFY_ADDR_REM = -0x3f87966a + SIOCIF_IB_RESET_STATS = -0x3f879671 + SIOCIF_IB_RESIZE_CQ = -0x7fdf9679 + SIOCIF_IB_SET_ARP = -0x7fdf967d + SIOCIF_IB_SET_PKEY = -0x7fdf967c + SIOCIF_IB_SET_PORT = -0x7fdf967b + SIOCIF_IB_SET_QKEY = -0x7fdf9676 + SIOCIF_IB_SET_QSIZE = -0x7fdf967a + SIOCLISTIFVIPA = 0x20006944 + SIOCSARP = -0x7fb396e2 + SIOCSHIWAT = 0x80047300 + SIOCSIFADDR = -0x7fd796f4 + SIOCSIFADDRORI = -0x7fdb9673 + SIOCSIFBRDADDR = -0x7fd796ed + SIOCSIFDSTADDR = -0x7fd796f2 + SIOCSIFFLAGS = -0x7fd796f0 + SIOCSIFGIDLIST = 0x20006969 + SIOCSIFMETRIC = -0x7fd796e8 + SIOCSIFMTU = -0x7fd796a8 + SIOCSIFNETDUMP = -0x7fd796e4 + SIOCSIFNETMASK = -0x7fd796ea + SIOCSIFOPTIONS = -0x7fd796d7 + SIOCSIFSUBCHAN = -0x7fd796e5 + SIOCSISNO = -0x7fd79694 + SIOCSLOADF = -0x3ffb967d + SIOCSLOWAT = 0x80047302 + SIOCSNETOPT = -0x7ffe96a6 + SIOCSPGRP = 0x80047308 + SIOCSX25XLATE = -0x7fd7969d + SOCK_CONN_DGRAM = 0x6 + SOCK_DGRAM = 0x2 + SOCK_RAW = 0x3 + SOCK_RDM = 0x4 + SOCK_SEQPACKET = 0x5 + SOCK_STREAM = 0x1 + SOL_SOCKET = 0xffff + SOMAXCONN = 0x400 + SO_ACCEPTCONN = 0x2 + SO_AUDIT = 0x8000 + SO_BROADCAST = 0x20 + SO_CKSUMRECV = 0x800 + SO_DEBUG = 0x1 + SO_DONTROUTE = 0x10 + SO_ERROR = 0x1007 + SO_KEEPALIVE = 0x8 + SO_KERNACCEPT = 0x2000 + SO_LINGER = 0x80 + SO_NOMULTIPATH = 0x4000 + SO_NOREUSEADDR = 0x1000 + SO_OOBINLINE = 0x100 + SO_PEERID = 0x1009 + SO_RCVBUF = 0x1002 + SO_RCVLOWAT = 0x1004 + SO_RCVTIMEO = 0x1006 + SO_REUSEADDR = 0x4 + SO_REUSEPORT = 0x200 + SO_SNDBUF = 0x1001 + SO_SNDLOWAT = 0x1003 + SO_SNDTIMEO = 0x1005 + SO_TIMESTAMPNS = 0x100a + SO_TYPE = 0x1008 + SO_USELOOPBACK = 0x40 + SO_USE_IFBUFS = 0x400 + S_BANDURG = 0x400 + S_EMODFMT = 0x3c000000 + S_ENFMT = 0x400 + S_ERROR = 0x100 + S_HANGUP = 0x200 + S_HIPRI = 0x2 + S_ICRYPTO = 0x80000 + S_IEXEC = 0x40 + S_IFBLK = 0x6000 + S_IFCHR = 0x2000 + S_IFDIR = 0x4000 + S_IFIFO = 0x1000 + S_IFJOURNAL = 0x10000 + S_IFLNK = 0xa000 + S_IFMPX = 0x2200 + S_IFMT = 0xf000 + S_IFPDIR = 0x4000000 + S_IFPSDIR = 0x8000000 + S_IFPSSDIR = 0xc000000 + S_IFREG = 0x8000 + S_IFSOCK = 0xc000 + S_IFSYSEA = 0x30000000 + S_INPUT = 0x1 + S_IREAD = 0x100 + S_IRGRP = 0x20 + S_IROTH = 0x4 + S_IRUSR = 0x100 + S_IRWXG = 0x38 + S_IRWXO = 0x7 + S_IRWXU = 0x1c0 + S_ISGID = 0x400 + S_ISUID = 0x800 + S_ISVTX = 0x200 + S_ITCB = 0x1000000 + S_ITP = 0x800000 + S_IWGRP = 0x10 + S_IWOTH = 0x2 + S_IWRITE = 0x80 + S_IWUSR = 0x80 + S_IXACL = 0x2000000 + S_IXATTR = 0x40000 + S_IXGRP = 0x8 + S_IXINTERFACE = 0x100000 + S_IXMOD = 0x40000000 + S_IXOTH = 0x1 + S_IXUSR = 0x40 + S_MSG = 0x8 + S_OUTPUT = 0x4 + S_RDBAND = 0x20 + S_RDNORM = 0x10 + S_RESERVED1 = 0x20000 + S_RESERVED2 = 0x200000 + S_RESERVED3 = 0x400000 + S_RESERVED4 = 0x80000000 + S_RESFMT1 = 0x10000000 + S_RESFMT10 = 0x34000000 + S_RESFMT11 = 0x38000000 + S_RESFMT12 = 0x3c000000 + S_RESFMT2 = 0x14000000 + S_RESFMT3 = 0x18000000 + S_RESFMT4 = 0x1c000000 + S_RESFMT5 = 0x20000000 + S_RESFMT6 = 0x24000000 + S_RESFMT7 = 0x28000000 + S_RESFMT8 = 0x2c000000 + S_WRBAND = 0x80 + S_WRNORM = 0x40 + TAB0 = 0x0 + TAB1 = 0x400 + TAB2 = 0x800 + TAB3 = 0xc00 + TABDLY = 0xc00 + TCFLSH = 0x540c + TCGETA = 0x5405 + TCGETS = 0x5401 + TCIFLUSH = 0x0 + TCIOFF = 0x2 + TCIOFLUSH = 0x2 + TCION = 0x3 + TCOFLUSH = 0x1 + TCOOFF = 0x0 + TCOON = 0x1 + TCP_24DAYS_WORTH_OF_SLOWTICKS = 0x3f4800 + TCP_ACLADD = 0x23 + TCP_ACLBIND = 0x26 + TCP_ACLCLEAR = 0x22 + TCP_ACLDEL = 0x24 + TCP_ACLDENY = 0x8 + TCP_ACLFLUSH = 0x21 + TCP_ACLGID = 0x1 + TCP_ACLLS = 0x25 + TCP_ACLSUBNET = 0x4 + TCP_ACLUID = 0x2 + TCP_CWND_DF = 0x16 + TCP_CWND_IF = 0x15 + TCP_DELAY_ACK_FIN = 0x2 + TCP_DELAY_ACK_SYN = 0x1 + TCP_FASTNAME = 0x101080a + TCP_KEEPCNT = 0x13 + TCP_KEEPIDLE = 0x11 + TCP_KEEPINTVL = 0x12 + TCP_LSPRIV = 0x29 + TCP_LUID = 0x20 + TCP_MAXBURST = 0x8 + TCP_MAXDF = 0x64 + TCP_MAXIF = 0x64 + TCP_MAXSEG = 0x2 + TCP_MAXWIN = 0xffff + TCP_MAXWINDOWSCALE = 0xe + TCP_MAX_SACK = 0x4 + TCP_MSS = 0x5b4 + TCP_NODELAY = 0x1 + TCP_NODELAYACK = 0x14 + TCP_NOREDUCE_CWND_EXIT_FRXMT = 0x19 + TCP_NOREDUCE_CWND_IN_FRXMT = 0x18 + TCP_NOTENTER_SSTART = 0x17 + TCP_OPT = 0x19 + TCP_RFC1323 = 0x4 + TCP_SETPRIV = 0x27 + TCP_STDURG = 0x10 + TCP_TIMESTAMP_OPTLEN = 0xc + TCP_UNSETPRIV = 0x28 + TCSAFLUSH = 0x2 + TCSBRK = 0x5409 + TCSETA = 0x5406 + TCSETAF = 0x5408 + TCSETAW = 0x5407 + TCSETS = 0x5402 + TCSETSF = 0x5404 + TCSETSW = 0x5403 + TCXONC = 0x540b + TIOC = 0x5400 + TIOCCBRK = 0x2000747a + TIOCCDTR = 0x20007478 + TIOCCONS = 0x80047462 + TIOCEXCL = 0x2000740d + TIOCFLUSH = 0x80047410 + TIOCGETC = 0x40067412 + TIOCGETD = 0x40047400 + TIOCGETP = 0x40067408 + TIOCGLTC = 0x40067474 + TIOCGPGRP = 0x40047477 + TIOCGSID = 0x40047448 + TIOCGSIZE = 0x40087468 + TIOCGWINSZ = 0x40087468 + TIOCHPCL = 0x20007402 + TIOCLBIC = 0x8004747e + TIOCLBIS = 0x8004747f + TIOCLGET = 0x4004747c + TIOCLSET = 0x8004747d + TIOCMBIC = 0x8004746b + TIOCMBIS = 0x8004746c + TIOCMGET = 0x4004746a + TIOCMIWAIT = 0x80047464 + TIOCMODG = 0x40047403 + TIOCMODS = 0x80047404 + TIOCMSET = 0x8004746d + TIOCM_CAR = 0x40 + TIOCM_CD = 0x40 + TIOCM_CTS = 0x20 + TIOCM_DSR = 0x100 + TIOCM_DTR = 0x2 + TIOCM_LE = 0x1 + TIOCM_RI = 0x80 + TIOCM_RNG = 0x80 + TIOCM_RTS = 0x4 + TIOCM_SR = 0x10 + TIOCM_ST = 0x8 + TIOCNOTTY = 0x20007471 + TIOCNXCL = 0x2000740e + TIOCOUTQ = 0x40047473 + TIOCPKT = 0x80047470 + TIOCPKT_DATA = 0x0 + TIOCPKT_DOSTOP = 0x20 + TIOCPKT_FLUSHREAD = 0x1 + TIOCPKT_FLUSHWRITE = 0x2 + TIOCPKT_NOSTOP = 0x10 + TIOCPKT_START = 0x8 + TIOCPKT_STOP = 0x4 + TIOCREMOTE = 0x80047469 + TIOCSBRK = 0x2000747b + TIOCSDTR = 0x20007479 + TIOCSETC = 0x80067411 + TIOCSETD = 0x80047401 + TIOCSETN = 0x8006740a + TIOCSETP = 0x80067409 + TIOCSLTC = 0x80067475 + TIOCSPGRP = 0x80047476 + TIOCSSIZE = 0x80087467 + TIOCSTART = 0x2000746e + TIOCSTI = 0x80017472 + TIOCSTOP = 0x2000746f + TIOCSWINSZ = 0x80087467 + TIOCUCNTL = 0x80047466 + TOSTOP = 0x10000 + UTIME_NOW = -0x2 + UTIME_OMIT = -0x3 + VDISCRD = 0xc + VDSUSP = 0xa + VEOF = 0x4 + VEOL = 0x5 + VEOL2 = 0x6 + VERASE = 0x2 + VINTR = 0x0 + VKILL = 0x3 + VLNEXT = 0xe + VMIN = 0x4 + VQUIT = 0x1 + VREPRINT = 0xb + VSTART = 0x7 + VSTOP = 0x8 + VSTRT = 0x7 + VSUSP = 0x9 + VT0 = 0x0 + VT1 = 0x8000 + VTDELAY = 0x2000 + VTDLY = 0x8000 + VTIME = 0x5 + VWERSE = 0xd + WPARSTART = 0x1 + WPARSTOP = 0x2 + WPARTTYNAME = "Global" + XCASE = 0x4 + XTABS = 0xc00 + _FDATAFLUSH = 0x2000000000 +) + +// Errors +const ( + E2BIG = syscall.Errno(0x7) + EACCES = syscall.Errno(0xd) + EADDRINUSE = syscall.Errno(0x43) + EADDRNOTAVAIL = syscall.Errno(0x44) + EAFNOSUPPORT = syscall.Errno(0x42) + EAGAIN = syscall.Errno(0xb) + EALREADY = syscall.Errno(0x38) + EBADF = syscall.Errno(0x9) + EBADMSG = syscall.Errno(0x78) + EBUSY = syscall.Errno(0x10) + ECANCELED = syscall.Errno(0x75) + ECHILD = syscall.Errno(0xa) + ECHRNG = syscall.Errno(0x25) + ECLONEME = syscall.Errno(0x52) + ECONNABORTED = syscall.Errno(0x48) + ECONNREFUSED = syscall.Errno(0x4f) + ECONNRESET = syscall.Errno(0x49) + ECORRUPT = syscall.Errno(0x59) + EDEADLK = syscall.Errno(0x2d) + EDESTADDREQ = syscall.Errno(0x3a) + EDESTADDRREQ = syscall.Errno(0x3a) + EDIST = syscall.Errno(0x35) + EDOM = syscall.Errno(0x21) + EDQUOT = syscall.Errno(0x58) + EEXIST = syscall.Errno(0x11) + EFAULT = syscall.Errno(0xe) + EFBIG = syscall.Errno(0x1b) + EFORMAT = syscall.Errno(0x30) + EHOSTDOWN = syscall.Errno(0x50) + EHOSTUNREACH = syscall.Errno(0x51) + EIDRM = syscall.Errno(0x24) + EILSEQ = syscall.Errno(0x74) + EINPROGRESS = syscall.Errno(0x37) + EINTR = syscall.Errno(0x4) + EINVAL = syscall.Errno(0x16) + EIO = syscall.Errno(0x5) + EISCONN = syscall.Errno(0x4b) + EISDIR = syscall.Errno(0x15) + EL2HLT = syscall.Errno(0x2c) + EL2NSYNC = syscall.Errno(0x26) + EL3HLT = syscall.Errno(0x27) + EL3RST = syscall.Errno(0x28) + ELNRNG = syscall.Errno(0x29) + ELOOP = syscall.Errno(0x55) + EMEDIA = syscall.Errno(0x6e) + EMFILE = syscall.Errno(0x18) + EMLINK = syscall.Errno(0x1f) + EMSGSIZE = syscall.Errno(0x3b) + EMULTIHOP = syscall.Errno(0x7d) + ENAMETOOLONG = syscall.Errno(0x56) + ENETDOWN = syscall.Errno(0x45) + ENETRESET = syscall.Errno(0x47) + ENETUNREACH = syscall.Errno(0x46) + ENFILE = syscall.Errno(0x17) + ENOATTR = syscall.Errno(0x70) + ENOBUFS = syscall.Errno(0x4a) + ENOCONNECT = syscall.Errno(0x32) + ENOCSI = syscall.Errno(0x2b) + ENODATA = syscall.Errno(0x7a) + ENODEV = syscall.Errno(0x13) + ENOENT = syscall.Errno(0x2) + ENOEXEC = syscall.Errno(0x8) + ENOLCK = syscall.Errno(0x31) + ENOLINK = syscall.Errno(0x7e) + ENOMEM = syscall.Errno(0xc) + ENOMSG = syscall.Errno(0x23) + ENOPROTOOPT = syscall.Errno(0x3d) + ENOSPC = syscall.Errno(0x1c) + ENOSR = syscall.Errno(0x76) + ENOSTR = syscall.Errno(0x7b) + ENOSYS = syscall.Errno(0x6d) + ENOTBLK = syscall.Errno(0xf) + ENOTCONN = syscall.Errno(0x4c) + ENOTDIR = syscall.Errno(0x14) + ENOTEMPTY = syscall.Errno(0x11) + ENOTREADY = syscall.Errno(0x2e) + ENOTRECOVERABLE = syscall.Errno(0x5e) + ENOTRUST = syscall.Errno(0x72) + ENOTSOCK = syscall.Errno(0x39) + ENOTSUP = syscall.Errno(0x7c) + ENOTTY = syscall.Errno(0x19) + ENXIO = syscall.Errno(0x6) + EOPNOTSUPP = syscall.Errno(0x40) + EOVERFLOW = syscall.Errno(0x7f) + EOWNERDEAD = syscall.Errno(0x5f) + EPERM = syscall.Errno(0x1) + EPFNOSUPPORT = syscall.Errno(0x41) + EPIPE = syscall.Errno(0x20) + EPROCLIM = syscall.Errno(0x53) + EPROTO = syscall.Errno(0x79) + EPROTONOSUPPORT = syscall.Errno(0x3e) + EPROTOTYPE = syscall.Errno(0x3c) + ERANGE = syscall.Errno(0x22) + EREMOTE = syscall.Errno(0x5d) + ERESTART = syscall.Errno(0x52) + EROFS = syscall.Errno(0x1e) + ESAD = syscall.Errno(0x71) + ESHUTDOWN = syscall.Errno(0x4d) + ESOCKTNOSUPPORT = syscall.Errno(0x3f) + ESOFT = syscall.Errno(0x6f) + ESPIPE = syscall.Errno(0x1d) + ESRCH = syscall.Errno(0x3) + ESTALE = syscall.Errno(0x34) + ESYSERROR = syscall.Errno(0x5a) + ETIME = syscall.Errno(0x77) + ETIMEDOUT = syscall.Errno(0x4e) + ETOOMANYREFS = syscall.Errno(0x73) + ETXTBSY = syscall.Errno(0x1a) + EUNATCH = syscall.Errno(0x2a) + EUSERS = syscall.Errno(0x54) + EWOULDBLOCK = syscall.Errno(0xb) + EWRPROTECT = syscall.Errno(0x2f) + EXDEV = syscall.Errno(0x12) +) + +// Signals +const ( + SIGABRT = syscall.Signal(0x6) + SIGAIO = syscall.Signal(0x17) + SIGALRM = syscall.Signal(0xe) + SIGALRM1 = syscall.Signal(0x26) + SIGBUS = syscall.Signal(0xa) + SIGCAPI = syscall.Signal(0x31) + SIGCHLD = syscall.Signal(0x14) + SIGCLD = syscall.Signal(0x14) + SIGCONT = syscall.Signal(0x13) + SIGCPUFAIL = syscall.Signal(0x3b) + SIGDANGER = syscall.Signal(0x21) + SIGEMT = syscall.Signal(0x7) + SIGFPE = syscall.Signal(0x8) + SIGGRANT = syscall.Signal(0x3c) + SIGHUP = syscall.Signal(0x1) + SIGILL = syscall.Signal(0x4) + SIGINT = syscall.Signal(0x2) + SIGIO = syscall.Signal(0x17) + SIGIOINT = syscall.Signal(0x10) + SIGIOT = syscall.Signal(0x6) + SIGKAP = syscall.Signal(0x3c) + SIGKILL = syscall.Signal(0x9) + SIGLOST = syscall.Signal(0x6) + SIGMAX = syscall.Signal(0x3f) + SIGMAX32 = syscall.Signal(0x3f) + SIGMIGRATE = syscall.Signal(0x23) + SIGMSG = syscall.Signal(0x1b) + SIGPIPE = syscall.Signal(0xd) + SIGPOLL = syscall.Signal(0x17) + SIGPRE = syscall.Signal(0x24) + SIGPROF = syscall.Signal(0x20) + SIGPTY = syscall.Signal(0x17) + SIGPWR = syscall.Signal(0x1d) + SIGQUIT = syscall.Signal(0x3) + SIGRECONFIG = syscall.Signal(0x3a) + SIGRETRACT = syscall.Signal(0x3d) + SIGSAK = syscall.Signal(0x3f) + SIGSEGV = syscall.Signal(0xb) + SIGSOUND = syscall.Signal(0x3e) + SIGSTOP = syscall.Signal(0x11) + SIGSYS = syscall.Signal(0xc) + SIGSYSERROR = syscall.Signal(0x30) + SIGTALRM = syscall.Signal(0x26) + SIGTERM = syscall.Signal(0xf) + SIGTRAP = syscall.Signal(0x5) + SIGTSTP = syscall.Signal(0x12) + SIGTTIN = syscall.Signal(0x15) + SIGTTOU = syscall.Signal(0x16) + SIGURG = syscall.Signal(0x10) + SIGUSR1 = syscall.Signal(0x1e) + SIGUSR2 = syscall.Signal(0x1f) + SIGVIRT = syscall.Signal(0x25) + SIGVTALRM = syscall.Signal(0x22) + SIGWAITING = syscall.Signal(0x27) + SIGWINCH = syscall.Signal(0x1c) + SIGXCPU = syscall.Signal(0x18) + SIGXFSZ = syscall.Signal(0x19) +) + +// Error table +var errorList = [...]struct { + num syscall.Errno + name string + desc string +}{ + {1, "EPERM", "not owner"}, + {2, "ENOENT", "no such file or directory"}, + {3, "ESRCH", "no such process"}, + {4, "EINTR", "interrupted system call"}, + {5, "EIO", "I/O error"}, + {6, "ENXIO", "no such device or address"}, + {7, "E2BIG", "arg list too long"}, + {8, "ENOEXEC", "exec format error"}, + {9, "EBADF", "bad file number"}, + {10, "ECHILD", "no child processes"}, + {11, "EWOULDBLOCK", "resource temporarily unavailable"}, + {12, "ENOMEM", "not enough space"}, + {13, "EACCES", "permission denied"}, + {14, "EFAULT", "bad address"}, + {15, "ENOTBLK", "block device required"}, + {16, "EBUSY", "device busy"}, + {17, "ENOTEMPTY", "file exists"}, + {18, "EXDEV", "cross-device link"}, + {19, "ENODEV", "no such device"}, + {20, "ENOTDIR", "not a directory"}, + {21, "EISDIR", "is a directory"}, + {22, "EINVAL", "invalid argument"}, + {23, "ENFILE", "file table overflow"}, + {24, "EMFILE", "too many open files"}, + {25, "ENOTTY", "not a typewriter"}, + {26, "ETXTBSY", "text file busy"}, + {27, "EFBIG", "file too large"}, + {28, "ENOSPC", "no space left on device"}, + {29, "ESPIPE", "illegal seek"}, + {30, "EROFS", "read-only file system"}, + {31, "EMLINK", "too many links"}, + {32, "EPIPE", "broken pipe"}, + {33, "EDOM", "argument out of domain"}, + {34, "ERANGE", "result too large"}, + {35, "ENOMSG", "no message of desired type"}, + {36, "EIDRM", "identifier removed"}, + {37, "ECHRNG", "channel number out of range"}, + {38, "EL2NSYNC", "level 2 not synchronized"}, + {39, "EL3HLT", "level 3 halted"}, + {40, "EL3RST", "level 3 reset"}, + {41, "ELNRNG", "link number out of range"}, + {42, "EUNATCH", "protocol driver not attached"}, + {43, "ENOCSI", "no CSI structure available"}, + {44, "EL2HLT", "level 2 halted"}, + {45, "EDEADLK", "deadlock condition if locked"}, + {46, "ENOTREADY", "device not ready"}, + {47, "EWRPROTECT", "write-protected media"}, + {48, "EFORMAT", "unformatted or incompatible media"}, + {49, "ENOLCK", "no locks available"}, + {50, "ENOCONNECT", "cannot Establish Connection"}, + {52, "ESTALE", "missing file or filesystem"}, + {53, "EDIST", "requests blocked by Administrator"}, + {55, "EINPROGRESS", "operation now in progress"}, + {56, "EALREADY", "operation already in progress"}, + {57, "ENOTSOCK", "socket operation on non-socket"}, + {58, "EDESTADDREQ", "destination address required"}, + {59, "EMSGSIZE", "message too long"}, + {60, "EPROTOTYPE", "protocol wrong type for socket"}, + {61, "ENOPROTOOPT", "protocol not available"}, + {62, "EPROTONOSUPPORT", "protocol not supported"}, + {63, "ESOCKTNOSUPPORT", "socket type not supported"}, + {64, "EOPNOTSUPP", "operation not supported on socket"}, + {65, "EPFNOSUPPORT", "protocol family not supported"}, + {66, "EAFNOSUPPORT", "addr family not supported by protocol"}, + {67, "EADDRINUSE", "address already in use"}, + {68, "EADDRNOTAVAIL", "can't assign requested address"}, + {69, "ENETDOWN", "network is down"}, + {70, "ENETUNREACH", "network is unreachable"}, + {71, "ENETRESET", "network dropped connection on reset"}, + {72, "ECONNABORTED", "software caused connection abort"}, + {73, "ECONNRESET", "connection reset by peer"}, + {74, "ENOBUFS", "no buffer space available"}, + {75, "EISCONN", "socket is already connected"}, + {76, "ENOTCONN", "socket is not connected"}, + {77, "ESHUTDOWN", "can't send after socket shutdown"}, + {78, "ETIMEDOUT", "connection timed out"}, + {79, "ECONNREFUSED", "connection refused"}, + {80, "EHOSTDOWN", "host is down"}, + {81, "EHOSTUNREACH", "no route to host"}, + {82, "ERESTART", "restart the system call"}, + {83, "EPROCLIM", "too many processes"}, + {84, "EUSERS", "too many users"}, + {85, "ELOOP", "too many levels of symbolic links"}, + {86, "ENAMETOOLONG", "file name too long"}, + {88, "EDQUOT", "disk quota exceeded"}, + {89, "ECORRUPT", "invalid file system control data detected"}, + {90, "ESYSERROR", "for future use "}, + {93, "EREMOTE", "item is not local to host"}, + {94, "ENOTRECOVERABLE", "state not recoverable "}, + {95, "EOWNERDEAD", "previous owner died "}, + {109, "ENOSYS", "function not implemented"}, + {110, "EMEDIA", "media surface error"}, + {111, "ESOFT", "I/O completed, but needs relocation"}, + {112, "ENOATTR", "no attribute found"}, + {113, "ESAD", "security Authentication Denied"}, + {114, "ENOTRUST", "not a Trusted Program"}, + {115, "ETOOMANYREFS", "too many references: can't splice"}, + {116, "EILSEQ", "invalid wide character"}, + {117, "ECANCELED", "asynchronous I/O cancelled"}, + {118, "ENOSR", "out of STREAMS resources"}, + {119, "ETIME", "system call timed out"}, + {120, "EBADMSG", "next message has wrong type"}, + {121, "EPROTO", "error in protocol"}, + {122, "ENODATA", "no message on stream head read q"}, + {123, "ENOSTR", "fd not associated with a stream"}, + {124, "ENOTSUP", "unsupported attribute value"}, + {125, "EMULTIHOP", "multihop is not allowed"}, + {126, "ENOLINK", "the server link has been severed"}, + {127, "EOVERFLOW", "value too large to be stored in data type"}, +} + +// Signal table +var signalList = [...]struct { + num syscall.Signal + name string + desc string +}{ + {1, "SIGHUP", "hangup"}, + {2, "SIGINT", "interrupt"}, + {3, "SIGQUIT", "quit"}, + {4, "SIGILL", "illegal instruction"}, + {5, "SIGTRAP", "trace/BPT trap"}, + {6, "SIGIOT", "IOT/Abort trap"}, + {7, "SIGEMT", "EMT trap"}, + {8, "SIGFPE", "floating point exception"}, + {9, "SIGKILL", "killed"}, + {10, "SIGBUS", "bus error"}, + {11, "SIGSEGV", "segmentation fault"}, + {12, "SIGSYS", "bad system call"}, + {13, "SIGPIPE", "broken pipe"}, + {14, "SIGALRM", "alarm clock"}, + {15, "SIGTERM", "terminated"}, + {16, "SIGURG", "urgent I/O condition"}, + {17, "SIGSTOP", "stopped (signal)"}, + {18, "SIGTSTP", "stopped"}, + {19, "SIGCONT", "continued"}, + {20, "SIGCHLD", "child exited"}, + {21, "SIGTTIN", "stopped (tty input)"}, + {22, "SIGTTOU", "stopped (tty output)"}, + {23, "SIGIO", "I/O possible/complete"}, + {24, "SIGXCPU", "cputime limit exceeded"}, + {25, "SIGXFSZ", "filesize limit exceeded"}, + {27, "SIGMSG", "input device data"}, + {28, "SIGWINCH", "window size changes"}, + {29, "SIGPWR", "power-failure"}, + {30, "SIGUSR1", "user defined signal 1"}, + {31, "SIGUSR2", "user defined signal 2"}, + {32, "SIGPROF", "profiling timer expired"}, + {33, "SIGDANGER", "paging space low"}, + {34, "SIGVTALRM", "virtual timer expired"}, + {35, "SIGMIGRATE", "signal 35"}, + {36, "SIGPRE", "signal 36"}, + {37, "SIGVIRT", "signal 37"}, + {38, "SIGTALRM", "signal 38"}, + {39, "SIGWAITING", "signal 39"}, + {48, "SIGSYSERROR", "signal 48"}, + {49, "SIGCAPI", "signal 49"}, + {58, "SIGRECONFIG", "signal 58"}, + {59, "SIGCPUFAIL", "CPU Failure Predicted"}, + {60, "SIGKAP", "monitor mode granted"}, + {61, "SIGRETRACT", "monitor mode retracted"}, + {62, "SIGSOUND", "sound completed"}, + {63, "SIGSAK", "secure attention"}, +} diff --git a/vendor/golang.org/x/sys/unix/zerrors_aix_ppc64.go b/vendor/golang.org/x/sys/unix/zerrors_aix_ppc64.go new file mode 100644 index 0000000000..ed04fd1b77 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/zerrors_aix_ppc64.go @@ -0,0 +1,1373 @@ +// mkerrors.sh -maix64 +// Code generated by the command above; see README.md. DO NOT EDIT. + +// +build ppc64,aix + +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs -- -maix64 _const.go + +package unix + +import "syscall" + +const ( + AF_APPLETALK = 0x10 + AF_BYPASS = 0x19 + AF_CCITT = 0xa + AF_CHAOS = 0x5 + AF_DATAKIT = 0x9 + AF_DECnet = 0xc + AF_DLI = 0xd + AF_ECMA = 0x8 + AF_HYLINK = 0xf + AF_IMPLINK = 0x3 + AF_INET = 0x2 + AF_INET6 = 0x18 + AF_INTF = 0x14 + AF_ISO = 0x7 + AF_LAT = 0xe + AF_LINK = 0x12 + AF_LOCAL = 0x1 + AF_MAX = 0x1e + AF_NDD = 0x17 + AF_NETWARE = 0x16 + AF_NS = 0x6 + AF_OSI = 0x7 + AF_PUP = 0x4 + AF_RIF = 0x15 + AF_ROUTE = 0x11 + AF_SNA = 0xb + AF_UNIX = 0x1 + AF_UNSPEC = 0x0 + ALTWERASE = 0x400000 + ARPHRD_802_3 = 0x6 + ARPHRD_802_5 = 0x6 + ARPHRD_ETHER = 0x1 + ARPHRD_FDDI = 0x1 + B0 = 0x0 + B110 = 0x3 + B1200 = 0x9 + B134 = 0x4 + B150 = 0x5 + B1800 = 0xa + B19200 = 0xe + B200 = 0x6 + B2400 = 0xb + B300 = 0x7 + B38400 = 0xf + B4800 = 0xc + B50 = 0x1 + B600 = 0x8 + B75 = 0x2 + B9600 = 0xd + BRKINT = 0x2 + BS0 = 0x0 + BS1 = 0x1000 + BSDLY = 0x1000 + CAP_AACCT = 0x6 + CAP_ARM_APPLICATION = 0x5 + CAP_BYPASS_RAC_VMM = 0x3 + CAP_CLEAR = 0x0 + CAP_CREDENTIALS = 0x7 + CAP_EFFECTIVE = 0x1 + CAP_EWLM_AGENT = 0x4 + CAP_INHERITABLE = 0x2 + CAP_MAXIMUM = 0x7 + CAP_NUMA_ATTACH = 0x2 + CAP_PERMITTED = 0x3 + CAP_PROPAGATE = 0x1 + CAP_PROPOGATE = 0x1 + CAP_SET = 0x1 + CBAUD = 0xf + CFLUSH = 0xf + CIBAUD = 0xf0000 + CLOCAL = 0x800 + CLOCK_MONOTONIC = 0xa + CLOCK_PROCESS_CPUTIME_ID = 0xb + CLOCK_REALTIME = 0x9 + CLOCK_THREAD_CPUTIME_ID = 0xc + CR0 = 0x0 + CR1 = 0x100 + CR2 = 0x200 + CR3 = 0x300 + CRDLY = 0x300 + CREAD = 0x80 + CS5 = 0x0 + CS6 = 0x10 + CS7 = 0x20 + CS8 = 0x30 + CSIOCGIFCONF = -0x3fef96dc + CSIZE = 0x30 + CSMAP_DIR = "/usr/lib/nls/csmap/" + CSTART = '\021' + CSTOP = '\023' + CSTOPB = 0x40 + CSUSP = 0x1a + ECHO = 0x8 + ECHOCTL = 0x20000 + ECHOE = 0x10 + ECHOK = 0x20 + ECHOKE = 0x80000 + ECHONL = 0x40 + ECHOPRT = 0x40000 + ECH_ICMPID = 0x2 + ETHERNET_CSMACD = 0x6 + EVENP = 0x80 + EXCONTINUE = 0x0 + EXDLOK = 0x3 + EXIO = 0x2 + EXPGIO = 0x0 + EXRESUME = 0x2 + EXRETURN = 0x1 + EXSIG = 0x4 + EXTA = 0xe + EXTB = 0xf + EXTRAP = 0x1 + EYEC_RTENTRYA = 0x257274656e747241 + EYEC_RTENTRYF = 0x257274656e747246 + E_ACC = 0x0 + FD_CLOEXEC = 0x1 + FD_SETSIZE = 0xfffe + FF0 = 0x0 + FF1 = 0x2000 + FFDLY = 0x2000 + FLUSHBAND = 0x40 + FLUSHLOW = 0x8 + FLUSHO = 0x100000 + FLUSHR = 0x1 + FLUSHRW = 0x3 + FLUSHW = 0x2 + F_CLOSEM = 0xa + F_DUP2FD = 0xe + F_DUPFD = 0x0 + F_GETFD = 0x1 + F_GETFL = 0x3 + F_GETLK = 0xb + F_GETLK64 = 0xb + F_GETOWN = 0x8 + F_LOCK = 0x1 + F_OK = 0x0 + F_RDLCK = 0x1 + F_SETFD = 0x2 + F_SETFL = 0x4 + F_SETLK = 0xc + F_SETLK64 = 0xc + F_SETLKW = 0xd + F_SETLKW64 = 0xd + F_SETOWN = 0x9 + F_TEST = 0x3 + F_TLOCK = 0x2 + F_TSTLK = 0xf + F_ULOCK = 0x0 + F_UNLCK = 0x3 + F_WRLCK = 0x2 + HUPCL = 0x400 + IBSHIFT = 0x10 + ICANON = 0x2 + ICMP6_FILTER = 0x26 + ICMP6_SEC_SEND_DEL = 0x46 + ICMP6_SEC_SEND_GET = 0x47 + ICMP6_SEC_SEND_SET = 0x44 + ICMP6_SEC_SEND_SET_CGA_ADDR = 0x45 + ICRNL = 0x100 + IEXTEN = 0x200000 + IFA_FIRSTALIAS = 0x2000 + IFA_ROUTE = 0x1 + IFF_64BIT = 0x4000000 + IFF_ALLCAST = 0x20000 + IFF_ALLMULTI = 0x200 + IFF_BPF = 0x8000000 + IFF_BRIDGE = 0x40000 + IFF_BROADCAST = 0x2 + IFF_CANTCHANGE = 0x80c52 + IFF_CHECKSUM_OFFLOAD = 0x10000000 + IFF_D1 = 0x8000 + IFF_D2 = 0x4000 + IFF_D3 = 0x2000 + IFF_D4 = 0x1000 + IFF_DEBUG = 0x4 + IFF_DEVHEALTH = 0x4000 + IFF_DO_HW_LOOPBACK = 0x10000 + IFF_GROUP_ROUTING = 0x2000000 + IFF_IFBUFMGT = 0x800000 + IFF_LINK0 = 0x100000 + IFF_LINK1 = 0x200000 + IFF_LINK2 = 0x400000 + IFF_LOOPBACK = 0x8 + IFF_MULTICAST = 0x80000 + IFF_NOARP = 0x80 + IFF_NOECHO = 0x800 + IFF_NOTRAILERS = 0x20 + IFF_OACTIVE = 0x400 + IFF_POINTOPOINT = 0x10 + IFF_PROMISC = 0x100 + IFF_PSEG = 0x40000000 + IFF_RUNNING = 0x40 + IFF_SIMPLEX = 0x800 + IFF_SNAP = 0x8000 + IFF_TCP_DISABLE_CKSUM = 0x20000000 + IFF_TCP_NOCKSUM = 0x1000000 + IFF_UP = 0x1 + IFF_VIPA = 0x80000000 + IFNAMSIZ = 0x10 + IFO_FLUSH = 0x1 + IFT_1822 = 0x2 + IFT_AAL5 = 0x31 + IFT_ARCNET = 0x23 + IFT_ARCNETPLUS = 0x24 + IFT_ATM = 0x25 + IFT_CEPT = 0x13 + IFT_CLUSTER = 0x3e + IFT_DS3 = 0x1e + IFT_EON = 0x19 + IFT_ETHER = 0x6 + IFT_FCS = 0x3a + IFT_FDDI = 0xf + IFT_FRELAY = 0x20 + IFT_FRELAYDCE = 0x2c + IFT_GIFTUNNEL = 0x3c + IFT_HDH1822 = 0x3 + IFT_HF = 0x3d + IFT_HIPPI = 0x2f + IFT_HSSI = 0x2e + IFT_HY = 0xe + IFT_IB = 0xc7 + IFT_ISDNBASIC = 0x14 + IFT_ISDNPRIMARY = 0x15 + IFT_ISO88022LLC = 0x29 + IFT_ISO88023 = 0x7 + IFT_ISO88024 = 0x8 + IFT_ISO88025 = 0x9 + IFT_ISO88026 = 0xa + IFT_LAPB = 0x10 + IFT_LOCALTALK = 0x2a + IFT_LOOP = 0x18 + IFT_MIOX25 = 0x26 + IFT_MODEM = 0x30 + IFT_NSIP = 0x1b + IFT_OTHER = 0x1 + IFT_P10 = 0xc + IFT_P80 = 0xd + IFT_PARA = 0x22 + IFT_PPP = 0x17 + IFT_PROPMUX = 0x36 + IFT_PROPVIRTUAL = 0x35 + IFT_PTPSERIAL = 0x16 + IFT_RS232 = 0x21 + IFT_SDLC = 0x11 + IFT_SIP = 0x1f + IFT_SLIP = 0x1c + IFT_SMDSDXI = 0x2b + IFT_SMDSICIP = 0x34 + IFT_SN = 0x38 + IFT_SONET = 0x27 + IFT_SONETPATH = 0x32 + IFT_SONETVT = 0x33 + IFT_SP = 0x39 + IFT_STARLAN = 0xb + IFT_T1 = 0x12 + IFT_TUNNEL = 0x3b + IFT_ULTRA = 0x1d + IFT_V35 = 0x2d + IFT_VIPA = 0x37 + IFT_X25 = 0x5 + IFT_X25DDN = 0x4 + IFT_X25PLE = 0x28 + IFT_XETHER = 0x1a + IGNBRK = 0x1 + IGNCR = 0x80 + IGNPAR = 0x4 + IMAXBEL = 0x10000 + INLCR = 0x40 + INPCK = 0x10 + IN_CLASSA_HOST = 0xffffff + IN_CLASSA_MAX = 0x80 + IN_CLASSA_NET = 0xff000000 + IN_CLASSA_NSHIFT = 0x18 + IN_CLASSB_HOST = 0xffff + IN_CLASSB_MAX = 0x10000 + IN_CLASSB_NET = 0xffff0000 + IN_CLASSB_NSHIFT = 0x10 + IN_CLASSC_HOST = 0xff + IN_CLASSC_NET = 0xffffff00 + IN_CLASSC_NSHIFT = 0x8 + IN_CLASSD_HOST = 0xfffffff + IN_CLASSD_NET = 0xf0000000 + IN_CLASSD_NSHIFT = 0x1c + IN_LOOPBACKNET = 0x7f + IN_USE = 0x1 + IPPROTO_AH = 0x33 + IPPROTO_BIP = 0x53 + IPPROTO_DSTOPTS = 0x3c + IPPROTO_EGP = 0x8 + IPPROTO_EON = 0x50 + IPPROTO_ESP = 0x32 + IPPROTO_FRAGMENT = 0x2c + IPPROTO_GGP = 0x3 + IPPROTO_GIF = 0x8c + IPPROTO_GRE = 0x2f + IPPROTO_HOPOPTS = 0x0 + IPPROTO_ICMP = 0x1 + IPPROTO_ICMPV6 = 0x3a + IPPROTO_IDP = 0x16 + IPPROTO_IGMP = 0x2 + IPPROTO_IP = 0x0 + IPPROTO_IPIP = 0x4 + IPPROTO_IPV6 = 0x29 + IPPROTO_LOCAL = 0x3f + IPPROTO_MAX = 0x100 + IPPROTO_MH = 0x87 + IPPROTO_NONE = 0x3b + IPPROTO_PUP = 0xc + IPPROTO_QOS = 0x2d + IPPROTO_RAW = 0xff + IPPROTO_ROUTING = 0x2b + IPPROTO_RSVP = 0x2e + IPPROTO_SCTP = 0x84 + IPPROTO_TCP = 0x6 + IPPROTO_TP = 0x1d + IPPROTO_UDP = 0x11 + IPV6_ADDRFORM = 0x16 + IPV6_ADDR_PREFERENCES = 0x4a + IPV6_ADD_MEMBERSHIP = 0xc + IPV6_AIXRAWSOCKET = 0x39 + IPV6_CHECKSUM = 0x27 + IPV6_DONTFRAG = 0x2d + IPV6_DROP_MEMBERSHIP = 0xd + IPV6_DSTOPTS = 0x36 + IPV6_FLOWINFO_FLOWLABEL = 0xffffff + IPV6_FLOWINFO_PRIFLOW = 0xfffffff + IPV6_FLOWINFO_PRIORITY = 0xf000000 + IPV6_FLOWINFO_SRFLAG = 0x10000000 + IPV6_FLOWINFO_VERSION = 0xf0000000 + IPV6_HOPLIMIT = 0x28 + IPV6_HOPOPTS = 0x34 + IPV6_JOIN_GROUP = 0xc + IPV6_LEAVE_GROUP = 0xd + IPV6_MIPDSTOPTS = 0x36 + IPV6_MULTICAST_HOPS = 0xa + IPV6_MULTICAST_IF = 0x9 + IPV6_MULTICAST_LOOP = 0xb + IPV6_NEXTHOP = 0x30 + IPV6_NOPROBE = 0x1c + IPV6_PATHMTU = 0x2e + IPV6_PKTINFO = 0x21 + IPV6_PKTOPTIONS = 0x24 + IPV6_PRIORITY_10 = 0xa000000 + IPV6_PRIORITY_11 = 0xb000000 + IPV6_PRIORITY_12 = 0xc000000 + IPV6_PRIORITY_13 = 0xd000000 + IPV6_PRIORITY_14 = 0xe000000 + IPV6_PRIORITY_15 = 0xf000000 + IPV6_PRIORITY_8 = 0x8000000 + IPV6_PRIORITY_9 = 0x9000000 + IPV6_PRIORITY_BULK = 0x4000000 + IPV6_PRIORITY_CONTROL = 0x7000000 + IPV6_PRIORITY_FILLER = 0x1000000 + IPV6_PRIORITY_INTERACTIVE = 0x6000000 + IPV6_PRIORITY_RESERVED1 = 0x3000000 + IPV6_PRIORITY_RESERVED2 = 0x5000000 + IPV6_PRIORITY_UNATTENDED = 0x2000000 + IPV6_PRIORITY_UNCHARACTERIZED = 0x0 + IPV6_RECVDSTOPTS = 0x38 + IPV6_RECVHOPLIMIT = 0x29 + IPV6_RECVHOPOPTS = 0x35 + IPV6_RECVHOPS = 0x22 + IPV6_RECVIF = 0x1e + IPV6_RECVPATHMTU = 0x2f + IPV6_RECVPKTINFO = 0x23 + IPV6_RECVRTHDR = 0x33 + IPV6_RECVSRCRT = 0x1d + IPV6_RECVTCLASS = 0x2a + IPV6_RTHDR = 0x32 + IPV6_RTHDRDSTOPTS = 0x37 + IPV6_RTHDR_TYPE_0 = 0x0 + IPV6_RTHDR_TYPE_2 = 0x2 + IPV6_SENDIF = 0x1f + IPV6_SRFLAG_LOOSE = 0x0 + IPV6_SRFLAG_STRICT = 0x10000000 + IPV6_TCLASS = 0x2b + IPV6_TOKEN_LENGTH = 0x40 + IPV6_UNICAST_HOPS = 0x4 + IPV6_USE_MIN_MTU = 0x2c + IPV6_V6ONLY = 0x25 + IPV6_VERSION = 0x60000000 + IP_ADDRFORM = 0x16 + IP_ADD_MEMBERSHIP = 0xc + IP_ADD_SOURCE_MEMBERSHIP = 0x3c + IP_BLOCK_SOURCE = 0x3a + IP_BROADCAST_IF = 0x10 + IP_CACHE_LINE_SIZE = 0x80 + IP_DEFAULT_MULTICAST_LOOP = 0x1 + IP_DEFAULT_MULTICAST_TTL = 0x1 + IP_DF = 0x4000 + IP_DHCPMODE = 0x11 + IP_DONTFRAG = 0x19 + IP_DROP_MEMBERSHIP = 0xd + IP_DROP_SOURCE_MEMBERSHIP = 0x3d + IP_FINDPMTU = 0x1a + IP_HDRINCL = 0x2 + IP_INC_MEMBERSHIPS = 0x14 + IP_INIT_MEMBERSHIP = 0x14 + IP_MAXPACKET = 0xffff + IP_MF = 0x2000 + IP_MSS = 0x240 + IP_MULTICAST_HOPS = 0xa + IP_MULTICAST_IF = 0x9 + IP_MULTICAST_LOOP = 0xb + IP_MULTICAST_TTL = 0xa + IP_OPT = 0x1b + IP_OPTIONS = 0x1 + IP_PMTUAGE = 0x1b + IP_RECVDSTADDR = 0x7 + IP_RECVIF = 0x14 + IP_RECVIFINFO = 0xf + IP_RECVINTERFACE = 0x20 + IP_RECVMACHDR = 0xe + IP_RECVOPTS = 0x5 + IP_RECVRETOPTS = 0x6 + IP_RECVTTL = 0x22 + IP_RETOPTS = 0x8 + IP_SOURCE_FILTER = 0x48 + IP_TOS = 0x3 + IP_TTL = 0x4 + IP_UNBLOCK_SOURCE = 0x3b + IP_UNICAST_HOPS = 0x4 + ISIG = 0x1 + ISTRIP = 0x20 + IUCLC = 0x800 + IXANY = 0x1000 + IXOFF = 0x400 + IXON = 0x200 + I_FLUSH = 0x20005305 + LNOFLSH = 0x8000 + LOCK_EX = 0x2 + LOCK_NB = 0x4 + LOCK_SH = 0x1 + LOCK_UN = 0x8 + MADV_DONTNEED = 0x4 + MADV_NORMAL = 0x0 + MADV_RANDOM = 0x1 + MADV_SEQUENTIAL = 0x2 + MADV_SPACEAVAIL = 0x5 + MADV_WILLNEED = 0x3 + MAP_ANON = 0x10 + MAP_ANONYMOUS = 0x10 + MAP_FILE = 0x0 + MAP_FIXED = 0x100 + MAP_PRIVATE = 0x2 + MAP_SHARED = 0x1 + MAP_TYPE = 0xf0 + MAP_VARIABLE = 0x0 + MCL_CURRENT = 0x100 + MCL_FUTURE = 0x200 + MSG_ANY = 0x4 + MSG_ARGEXT = 0x400 + MSG_BAND = 0x2 + MSG_COMPAT = 0x8000 + MSG_CTRUNC = 0x20 + MSG_DONTROUTE = 0x4 + MSG_EOR = 0x8 + MSG_HIPRI = 0x1 + MSG_MAXIOVLEN = 0x10 + MSG_MPEG2 = 0x80 + MSG_NONBLOCK = 0x4000 + MSG_NOSIGNAL = 0x100 + MSG_OOB = 0x1 + MSG_PEEK = 0x2 + MSG_TRUNC = 0x10 + MSG_WAITALL = 0x40 + MSG_WAITFORONE = 0x200 + MS_ASYNC = 0x10 + MS_EINTR = 0x80 + MS_INVALIDATE = 0x40 + MS_PER_SEC = 0x3e8 + MS_SYNC = 0x20 + NL0 = 0x0 + NL1 = 0x4000 + NL2 = 0x8000 + NL3 = 0xc000 + NLDLY = 0x4000 + NOFLSH = 0x80 + NOFLUSH = 0x80000000 + OCRNL = 0x8 + OFDEL = 0x80 + OFILL = 0x40 + OLCUC = 0x2 + ONLCR = 0x4 + ONLRET = 0x20 + ONOCR = 0x10 + ONOEOT = 0x80000 + OPOST = 0x1 + OXTABS = 0x40000 + O_ACCMODE = 0x23 + O_APPEND = 0x8 + O_CIO = 0x80 + O_CIOR = 0x800000000 + O_CLOEXEC = 0x800000 + O_CREAT = 0x100 + O_DEFER = 0x2000 + O_DELAY = 0x4000 + O_DIRECT = 0x8000000 + O_DIRECTORY = 0x80000 + O_DSYNC = 0x400000 + O_EFSOFF = 0x400000000 + O_EFSON = 0x200000000 + O_EXCL = 0x400 + O_EXEC = 0x20 + O_LARGEFILE = 0x4000000 + O_NDELAY = 0x8000 + O_NOCACHE = 0x100000 + O_NOCTTY = 0x800 + O_NOFOLLOW = 0x1000000 + O_NONBLOCK = 0x4 + O_NONE = 0x3 + O_NSHARE = 0x10000 + O_RAW = 0x100000000 + O_RDONLY = 0x0 + O_RDWR = 0x2 + O_RSHARE = 0x1000 + O_RSYNC = 0x200000 + O_SEARCH = 0x20 + O_SNAPSHOT = 0x40 + O_SYNC = 0x10 + O_TRUNC = 0x200 + O_TTY_INIT = 0x0 + O_WRONLY = 0x1 + PARENB = 0x100 + PAREXT = 0x100000 + PARMRK = 0x8 + PARODD = 0x200 + PENDIN = 0x20000000 + PRIO_PGRP = 0x1 + PRIO_PROCESS = 0x0 + PRIO_USER = 0x2 + PROT_EXEC = 0x4 + PROT_NONE = 0x0 + PROT_READ = 0x1 + PROT_WRITE = 0x2 + PR_64BIT = 0x20 + PR_ADDR = 0x2 + PR_ARGEXT = 0x400 + PR_ATOMIC = 0x1 + PR_CONNREQUIRED = 0x4 + PR_FASTHZ = 0x5 + PR_INP = 0x40 + PR_INTRLEVEL = 0x8000 + PR_MLS = 0x100 + PR_MLS_1_LABEL = 0x200 + PR_NOEOR = 0x4000 + PR_RIGHTS = 0x10 + PR_SLOWHZ = 0x2 + PR_WANTRCVD = 0x8 + RLIMIT_AS = 0x6 + RLIMIT_CORE = 0x4 + RLIMIT_CPU = 0x0 + RLIMIT_DATA = 0x2 + RLIMIT_FSIZE = 0x1 + RLIMIT_NOFILE = 0x7 + RLIMIT_NPROC = 0x9 + RLIMIT_RSS = 0x5 + RLIMIT_STACK = 0x3 + RLIM_INFINITY = 0x7fffffffffffffff + RTAX_AUTHOR = 0x6 + RTAX_BRD = 0x7 + RTAX_DST = 0x0 + RTAX_GATEWAY = 0x1 + RTAX_GENMASK = 0x3 + RTAX_IFA = 0x5 + RTAX_IFP = 0x4 + RTAX_MAX = 0x8 + RTAX_NETMASK = 0x2 + RTA_AUTHOR = 0x40 + RTA_BRD = 0x80 + RTA_DOWNSTREAM = 0x100 + RTA_DST = 0x1 + RTA_GATEWAY = 0x2 + RTA_GENMASK = 0x8 + RTA_IFA = 0x20 + RTA_IFP = 0x10 + RTA_NETMASK = 0x4 + RTC_IA64 = 0x3 + RTC_POWER = 0x1 + RTC_POWER_PC = 0x2 + RTF_ACTIVE_DGD = 0x1000000 + RTF_BCE = 0x80000 + RTF_BLACKHOLE = 0x1000 + RTF_BROADCAST = 0x400000 + RTF_BUL = 0x2000 + RTF_CLONE = 0x10000 + RTF_CLONED = 0x20000 + RTF_CLONING = 0x100 + RTF_DONE = 0x40 + RTF_DYNAMIC = 0x10 + RTF_FREE_IN_PROG = 0x4000000 + RTF_GATEWAY = 0x2 + RTF_HOST = 0x4 + RTF_LLINFO = 0x400 + RTF_LOCAL = 0x200000 + RTF_MASK = 0x80 + RTF_MODIFIED = 0x20 + RTF_MULTICAST = 0x800000 + RTF_PERMANENT6 = 0x8000000 + RTF_PINNED = 0x100000 + RTF_PROTO1 = 0x8000 + RTF_PROTO2 = 0x4000 + RTF_PROTO3 = 0x40000 + RTF_REJECT = 0x8 + RTF_SMALLMTU = 0x40000 + RTF_STATIC = 0x800 + RTF_STOPSRCH = 0x2000000 + RTF_UNREACHABLE = 0x10000000 + RTF_UP = 0x1 + RTF_XRESOLVE = 0x200 + RTM_ADD = 0x1 + RTM_CHANGE = 0x3 + RTM_DELADDR = 0xd + RTM_DELETE = 0x2 + RTM_EXPIRE = 0xf + RTM_GET = 0x4 + RTM_GETNEXT = 0x11 + RTM_IFINFO = 0xe + RTM_LOCK = 0x8 + RTM_LOSING = 0x5 + RTM_MISS = 0x7 + RTM_NEWADDR = 0xc + RTM_OLDADD = 0x9 + RTM_OLDDEL = 0xa + RTM_REDIRECT = 0x6 + RTM_RESOLVE = 0xb + RTM_RTLOST = 0x10 + RTM_RTTUNIT = 0xf4240 + RTM_SAMEADDR = 0x12 + RTM_SET = 0x13 + RTM_VERSION = 0x2 + RTM_VERSION_GR = 0x4 + RTM_VERSION_GR_COMPAT = 0x3 + RTM_VERSION_POLICY = 0x5 + RTM_VERSION_POLICY_EXT = 0x6 + RTM_VERSION_POLICY_PRFN = 0x7 + RTV_EXPIRE = 0x4 + RTV_HOPCOUNT = 0x2 + RTV_MTU = 0x1 + RTV_RPIPE = 0x8 + RTV_RTT = 0x40 + RTV_RTTVAR = 0x80 + RTV_SPIPE = 0x10 + RTV_SSTHRESH = 0x20 + RUSAGE_CHILDREN = -0x1 + RUSAGE_SELF = 0x0 + RUSAGE_THREAD = 0x1 + SCM_RIGHTS = 0x1 + SHUT_RD = 0x0 + SHUT_RDWR = 0x2 + SHUT_WR = 0x1 + SIGMAX64 = 0xff + SIGQUEUE_MAX = 0x20 + SIOCADDIFVIPA = 0x20006942 + SIOCADDMTU = -0x7ffb9690 + SIOCADDMULTI = -0x7fdf96cf + SIOCADDNETID = -0x7fd796a9 + SIOCADDRT = -0x7fc78df6 + SIOCAIFADDR = -0x7fbf96e6 + SIOCATMARK = 0x40047307 + SIOCDARP = -0x7fb396e0 + SIOCDELIFVIPA = 0x20006943 + SIOCDELMTU = -0x7ffb968f + SIOCDELMULTI = -0x7fdf96ce + SIOCDELPMTU = -0x7fd78ff6 + SIOCDELRT = -0x7fc78df5 + SIOCDIFADDR = -0x7fd796e7 + SIOCDNETOPT = -0x3ffe9680 + SIOCDX25XLATE = -0x7fd7969b + SIOCFIFADDR = -0x7fdf966d + SIOCGARP = -0x3fb396da + SIOCGETMTUS = 0x2000696f + SIOCGETSGCNT = -0x3feb8acc + SIOCGETVIFCNT = -0x3feb8acd + SIOCGHIWAT = 0x40047301 + SIOCGIFADDR = -0x3fd796df + SIOCGIFADDRS = 0x2000698c + SIOCGIFBAUDRATE = -0x3fd79693 + SIOCGIFBRDADDR = -0x3fd796dd + SIOCGIFCONF = -0x3fef96bb + SIOCGIFCONFGLOB = -0x3fef9670 + SIOCGIFDSTADDR = -0x3fd796de + SIOCGIFFLAGS = -0x3fd796ef + SIOCGIFGIDLIST = 0x20006968 + SIOCGIFHWADDR = -0x3fab966b + SIOCGIFMETRIC = -0x3fd796e9 + SIOCGIFMTU = -0x3fd796aa + SIOCGIFNETMASK = -0x3fd796db + SIOCGIFOPTIONS = -0x3fd796d6 + SIOCGISNO = -0x3fd79695 + SIOCGLOADF = -0x3ffb967e + SIOCGLOWAT = 0x40047303 + SIOCGNETOPT = -0x3ffe96a5 + SIOCGNETOPT1 = -0x3fdf967f + SIOCGNMTUS = 0x2000696e + SIOCGPGRP = 0x40047309 + SIOCGSIZIFCONF = 0x4004696a + SIOCGSRCFILTER = -0x3fe796cb + SIOCGTUNEPHASE = -0x3ffb9676 + SIOCGX25XLATE = -0x3fd7969c + SIOCIFATTACH = -0x7fdf9699 + SIOCIFDETACH = -0x7fdf969a + SIOCIFGETPKEY = -0x7fdf969b + SIOCIF_ATM_DARP = -0x7fdf9683 + SIOCIF_ATM_DUMPARP = -0x7fdf9685 + SIOCIF_ATM_GARP = -0x7fdf9682 + SIOCIF_ATM_IDLE = -0x7fdf9686 + SIOCIF_ATM_SARP = -0x7fdf9681 + SIOCIF_ATM_SNMPARP = -0x7fdf9687 + SIOCIF_ATM_SVC = -0x7fdf9684 + SIOCIF_ATM_UBR = -0x7fdf9688 + SIOCIF_DEVHEALTH = -0x7ffb966c + SIOCIF_IB_ARP_INCOMP = -0x7fdf9677 + SIOCIF_IB_ARP_TIMER = -0x7fdf9678 + SIOCIF_IB_CLEAR_PINFO = -0x3fdf966f + SIOCIF_IB_DEL_ARP = -0x7fdf967f + SIOCIF_IB_DEL_PINFO = -0x3fdf9670 + SIOCIF_IB_DUMP_ARP = -0x7fdf9680 + SIOCIF_IB_GET_ARP = -0x7fdf967e + SIOCIF_IB_GET_INFO = -0x3f879675 + SIOCIF_IB_GET_STATS = -0x3f879672 + SIOCIF_IB_NOTIFY_ADDR_REM = -0x3f87966a + SIOCIF_IB_RESET_STATS = -0x3f879671 + SIOCIF_IB_RESIZE_CQ = -0x7fdf9679 + SIOCIF_IB_SET_ARP = -0x7fdf967d + SIOCIF_IB_SET_PKEY = -0x7fdf967c + SIOCIF_IB_SET_PORT = -0x7fdf967b + SIOCIF_IB_SET_QKEY = -0x7fdf9676 + SIOCIF_IB_SET_QSIZE = -0x7fdf967a + SIOCLISTIFVIPA = 0x20006944 + SIOCSARP = -0x7fb396e2 + SIOCSHIWAT = 0xffffffff80047300 + SIOCSIFADDR = -0x7fd796f4 + SIOCSIFADDRORI = -0x7fdb9673 + SIOCSIFBRDADDR = -0x7fd796ed + SIOCSIFDSTADDR = -0x7fd796f2 + SIOCSIFFLAGS = -0x7fd796f0 + SIOCSIFGIDLIST = 0x20006969 + SIOCSIFMETRIC = -0x7fd796e8 + SIOCSIFMTU = -0x7fd796a8 + SIOCSIFNETDUMP = -0x7fd796e4 + SIOCSIFNETMASK = -0x7fd796ea + SIOCSIFOPTIONS = -0x7fd796d7 + SIOCSIFSUBCHAN = -0x7fd796e5 + SIOCSISNO = -0x7fd79694 + SIOCSLOADF = -0x3ffb967d + SIOCSLOWAT = 0xffffffff80047302 + SIOCSNETOPT = -0x7ffe96a6 + SIOCSPGRP = 0xffffffff80047308 + SIOCSX25XLATE = -0x7fd7969d + SOCK_CONN_DGRAM = 0x6 + SOCK_DGRAM = 0x2 + SOCK_RAW = 0x3 + SOCK_RDM = 0x4 + SOCK_SEQPACKET = 0x5 + SOCK_STREAM = 0x1 + SOL_SOCKET = 0xffff + SOMAXCONN = 0x400 + SO_ACCEPTCONN = 0x2 + SO_AUDIT = 0x8000 + SO_BROADCAST = 0x20 + SO_CKSUMRECV = 0x800 + SO_DEBUG = 0x1 + SO_DONTROUTE = 0x10 + SO_ERROR = 0x1007 + SO_KEEPALIVE = 0x8 + SO_KERNACCEPT = 0x2000 + SO_LINGER = 0x80 + SO_NOMULTIPATH = 0x4000 + SO_NOREUSEADDR = 0x1000 + SO_OOBINLINE = 0x100 + SO_PEERID = 0x1009 + SO_RCVBUF = 0x1002 + SO_RCVLOWAT = 0x1004 + SO_RCVTIMEO = 0x1006 + SO_REUSEADDR = 0x4 + SO_REUSEPORT = 0x200 + SO_SNDBUF = 0x1001 + SO_SNDLOWAT = 0x1003 + SO_SNDTIMEO = 0x1005 + SO_TIMESTAMPNS = 0x100a + SO_TYPE = 0x1008 + SO_USELOOPBACK = 0x40 + SO_USE_IFBUFS = 0x400 + S_BANDURG = 0x400 + S_EMODFMT = 0x3c000000 + S_ENFMT = 0x400 + S_ERROR = 0x100 + S_HANGUP = 0x200 + S_HIPRI = 0x2 + S_ICRYPTO = 0x80000 + S_IEXEC = 0x40 + S_IFBLK = 0x6000 + S_IFCHR = 0x2000 + S_IFDIR = 0x4000 + S_IFIFO = 0x1000 + S_IFJOURNAL = 0x10000 + S_IFLNK = 0xa000 + S_IFMPX = 0x2200 + S_IFMT = 0xf000 + S_IFPDIR = 0x4000000 + S_IFPSDIR = 0x8000000 + S_IFPSSDIR = 0xc000000 + S_IFREG = 0x8000 + S_IFSOCK = 0xc000 + S_IFSYSEA = 0x30000000 + S_INPUT = 0x1 + S_IREAD = 0x100 + S_IRGRP = 0x20 + S_IROTH = 0x4 + S_IRUSR = 0x100 + S_IRWXG = 0x38 + S_IRWXO = 0x7 + S_IRWXU = 0x1c0 + S_ISGID = 0x400 + S_ISUID = 0x800 + S_ISVTX = 0x200 + S_ITCB = 0x1000000 + S_ITP = 0x800000 + S_IWGRP = 0x10 + S_IWOTH = 0x2 + S_IWRITE = 0x80 + S_IWUSR = 0x80 + S_IXACL = 0x2000000 + S_IXATTR = 0x40000 + S_IXGRP = 0x8 + S_IXINTERFACE = 0x100000 + S_IXMOD = 0x40000000 + S_IXOTH = 0x1 + S_IXUSR = 0x40 + S_MSG = 0x8 + S_OUTPUT = 0x4 + S_RDBAND = 0x20 + S_RDNORM = 0x10 + S_RESERVED1 = 0x20000 + S_RESERVED2 = 0x200000 + S_RESERVED3 = 0x400000 + S_RESERVED4 = 0x80000000 + S_RESFMT1 = 0x10000000 + S_RESFMT10 = 0x34000000 + S_RESFMT11 = 0x38000000 + S_RESFMT12 = 0x3c000000 + S_RESFMT2 = 0x14000000 + S_RESFMT3 = 0x18000000 + S_RESFMT4 = 0x1c000000 + S_RESFMT5 = 0x20000000 + S_RESFMT6 = 0x24000000 + S_RESFMT7 = 0x28000000 + S_RESFMT8 = 0x2c000000 + S_WRBAND = 0x80 + S_WRNORM = 0x40 + TAB0 = 0x0 + TAB1 = 0x400 + TAB2 = 0x800 + TAB3 = 0xc00 + TABDLY = 0xc00 + TCFLSH = 0x540c + TCGETA = 0x5405 + TCGETS = 0x5401 + TCIFLUSH = 0x0 + TCIOFF = 0x2 + TCIOFLUSH = 0x2 + TCION = 0x3 + TCOFLUSH = 0x1 + TCOOFF = 0x0 + TCOON = 0x1 + TCP_24DAYS_WORTH_OF_SLOWTICKS = 0x3f4800 + TCP_ACLADD = 0x23 + TCP_ACLBIND = 0x26 + TCP_ACLCLEAR = 0x22 + TCP_ACLDEL = 0x24 + TCP_ACLDENY = 0x8 + TCP_ACLFLUSH = 0x21 + TCP_ACLGID = 0x1 + TCP_ACLLS = 0x25 + TCP_ACLSUBNET = 0x4 + TCP_ACLUID = 0x2 + TCP_CWND_DF = 0x16 + TCP_CWND_IF = 0x15 + TCP_DELAY_ACK_FIN = 0x2 + TCP_DELAY_ACK_SYN = 0x1 + TCP_FASTNAME = 0x101080a + TCP_KEEPCNT = 0x13 + TCP_KEEPIDLE = 0x11 + TCP_KEEPINTVL = 0x12 + TCP_LSPRIV = 0x29 + TCP_LUID = 0x20 + TCP_MAXBURST = 0x8 + TCP_MAXDF = 0x64 + TCP_MAXIF = 0x64 + TCP_MAXSEG = 0x2 + TCP_MAXWIN = 0xffff + TCP_MAXWINDOWSCALE = 0xe + TCP_MAX_SACK = 0x4 + TCP_MSS = 0x5b4 + TCP_NODELAY = 0x1 + TCP_NODELAYACK = 0x14 + TCP_NOREDUCE_CWND_EXIT_FRXMT = 0x19 + TCP_NOREDUCE_CWND_IN_FRXMT = 0x18 + TCP_NOTENTER_SSTART = 0x17 + TCP_OPT = 0x19 + TCP_RFC1323 = 0x4 + TCP_SETPRIV = 0x27 + TCP_STDURG = 0x10 + TCP_TIMESTAMP_OPTLEN = 0xc + TCP_UNSETPRIV = 0x28 + TCSAFLUSH = 0x2 + TCSBRK = 0x5409 + TCSETA = 0x5406 + TCSETAF = 0x5408 + TCSETAW = 0x5407 + TCSETS = 0x5402 + TCSETSF = 0x5404 + TCSETSW = 0x5403 + TCXONC = 0x540b + TIOC = 0x5400 + TIOCCBRK = 0x2000747a + TIOCCDTR = 0x20007478 + TIOCCONS = 0xffffffff80047462 + TIOCEXCL = 0x2000740d + TIOCFLUSH = 0xffffffff80047410 + TIOCGETC = 0x40067412 + TIOCGETD = 0x40047400 + TIOCGETP = 0x40067408 + TIOCGLTC = 0x40067474 + TIOCGPGRP = 0x40047477 + TIOCGSID = 0x40047448 + TIOCGSIZE = 0x40087468 + TIOCGWINSZ = 0x40087468 + TIOCHPCL = 0x20007402 + TIOCLBIC = 0xffffffff8004747e + TIOCLBIS = 0xffffffff8004747f + TIOCLGET = 0x4004747c + TIOCLSET = 0xffffffff8004747d + TIOCMBIC = 0xffffffff8004746b + TIOCMBIS = 0xffffffff8004746c + TIOCMGET = 0x4004746a + TIOCMIWAIT = 0xffffffff80047464 + TIOCMODG = 0x40047403 + TIOCMODS = 0xffffffff80047404 + TIOCMSET = 0xffffffff8004746d + TIOCM_CAR = 0x40 + TIOCM_CD = 0x40 + TIOCM_CTS = 0x20 + TIOCM_DSR = 0x100 + TIOCM_DTR = 0x2 + TIOCM_LE = 0x1 + TIOCM_RI = 0x80 + TIOCM_RNG = 0x80 + TIOCM_RTS = 0x4 + TIOCM_SR = 0x10 + TIOCM_ST = 0x8 + TIOCNOTTY = 0x20007471 + TIOCNXCL = 0x2000740e + TIOCOUTQ = 0x40047473 + TIOCPKT = 0xffffffff80047470 + TIOCPKT_DATA = 0x0 + TIOCPKT_DOSTOP = 0x20 + TIOCPKT_FLUSHREAD = 0x1 + TIOCPKT_FLUSHWRITE = 0x2 + TIOCPKT_NOSTOP = 0x10 + TIOCPKT_START = 0x8 + TIOCPKT_STOP = 0x4 + TIOCREMOTE = 0xffffffff80047469 + TIOCSBRK = 0x2000747b + TIOCSDTR = 0x20007479 + TIOCSETC = 0xffffffff80067411 + TIOCSETD = 0xffffffff80047401 + TIOCSETN = 0xffffffff8006740a + TIOCSETP = 0xffffffff80067409 + TIOCSLTC = 0xffffffff80067475 + TIOCSPGRP = 0xffffffff80047476 + TIOCSSIZE = 0xffffffff80087467 + TIOCSTART = 0x2000746e + TIOCSTI = 0xffffffff80017472 + TIOCSTOP = 0x2000746f + TIOCSWINSZ = 0xffffffff80087467 + TIOCUCNTL = 0xffffffff80047466 + TOSTOP = 0x10000 + UTIME_NOW = -0x2 + UTIME_OMIT = -0x3 + VDISCRD = 0xc + VDSUSP = 0xa + VEOF = 0x4 + VEOL = 0x5 + VEOL2 = 0x6 + VERASE = 0x2 + VINTR = 0x0 + VKILL = 0x3 + VLNEXT = 0xe + VMIN = 0x4 + VQUIT = 0x1 + VREPRINT = 0xb + VSTART = 0x7 + VSTOP = 0x8 + VSTRT = 0x7 + VSUSP = 0x9 + VT0 = 0x0 + VT1 = 0x8000 + VTDELAY = 0x2000 + VTDLY = 0x8000 + VTIME = 0x5 + VWERSE = 0xd + WPARSTART = 0x1 + WPARSTOP = 0x2 + WPARTTYNAME = "Global" + XCASE = 0x4 + XTABS = 0xc00 + _FDATAFLUSH = 0x2000000000 +) + +// Errors +const ( + E2BIG = syscall.Errno(0x7) + EACCES = syscall.Errno(0xd) + EADDRINUSE = syscall.Errno(0x43) + EADDRNOTAVAIL = syscall.Errno(0x44) + EAFNOSUPPORT = syscall.Errno(0x42) + EAGAIN = syscall.Errno(0xb) + EALREADY = syscall.Errno(0x38) + EBADF = syscall.Errno(0x9) + EBADMSG = syscall.Errno(0x78) + EBUSY = syscall.Errno(0x10) + ECANCELED = syscall.Errno(0x75) + ECHILD = syscall.Errno(0xa) + ECHRNG = syscall.Errno(0x25) + ECLONEME = syscall.Errno(0x52) + ECONNABORTED = syscall.Errno(0x48) + ECONNREFUSED = syscall.Errno(0x4f) + ECONNRESET = syscall.Errno(0x49) + ECORRUPT = syscall.Errno(0x59) + EDEADLK = syscall.Errno(0x2d) + EDESTADDREQ = syscall.Errno(0x3a) + EDESTADDRREQ = syscall.Errno(0x3a) + EDIST = syscall.Errno(0x35) + EDOM = syscall.Errno(0x21) + EDQUOT = syscall.Errno(0x58) + EEXIST = syscall.Errno(0x11) + EFAULT = syscall.Errno(0xe) + EFBIG = syscall.Errno(0x1b) + EFORMAT = syscall.Errno(0x30) + EHOSTDOWN = syscall.Errno(0x50) + EHOSTUNREACH = syscall.Errno(0x51) + EIDRM = syscall.Errno(0x24) + EILSEQ = syscall.Errno(0x74) + EINPROGRESS = syscall.Errno(0x37) + EINTR = syscall.Errno(0x4) + EINVAL = syscall.Errno(0x16) + EIO = syscall.Errno(0x5) + EISCONN = syscall.Errno(0x4b) + EISDIR = syscall.Errno(0x15) + EL2HLT = syscall.Errno(0x2c) + EL2NSYNC = syscall.Errno(0x26) + EL3HLT = syscall.Errno(0x27) + EL3RST = syscall.Errno(0x28) + ELNRNG = syscall.Errno(0x29) + ELOOP = syscall.Errno(0x55) + EMEDIA = syscall.Errno(0x6e) + EMFILE = syscall.Errno(0x18) + EMLINK = syscall.Errno(0x1f) + EMSGSIZE = syscall.Errno(0x3b) + EMULTIHOP = syscall.Errno(0x7d) + ENAMETOOLONG = syscall.Errno(0x56) + ENETDOWN = syscall.Errno(0x45) + ENETRESET = syscall.Errno(0x47) + ENETUNREACH = syscall.Errno(0x46) + ENFILE = syscall.Errno(0x17) + ENOATTR = syscall.Errno(0x70) + ENOBUFS = syscall.Errno(0x4a) + ENOCONNECT = syscall.Errno(0x32) + ENOCSI = syscall.Errno(0x2b) + ENODATA = syscall.Errno(0x7a) + ENODEV = syscall.Errno(0x13) + ENOENT = syscall.Errno(0x2) + ENOEXEC = syscall.Errno(0x8) + ENOLCK = syscall.Errno(0x31) + ENOLINK = syscall.Errno(0x7e) + ENOMEM = syscall.Errno(0xc) + ENOMSG = syscall.Errno(0x23) + ENOPROTOOPT = syscall.Errno(0x3d) + ENOSPC = syscall.Errno(0x1c) + ENOSR = syscall.Errno(0x76) + ENOSTR = syscall.Errno(0x7b) + ENOSYS = syscall.Errno(0x6d) + ENOTBLK = syscall.Errno(0xf) + ENOTCONN = syscall.Errno(0x4c) + ENOTDIR = syscall.Errno(0x14) + ENOTEMPTY = syscall.Errno(0x11) + ENOTREADY = syscall.Errno(0x2e) + ENOTRECOVERABLE = syscall.Errno(0x5e) + ENOTRUST = syscall.Errno(0x72) + ENOTSOCK = syscall.Errno(0x39) + ENOTSUP = syscall.Errno(0x7c) + ENOTTY = syscall.Errno(0x19) + ENXIO = syscall.Errno(0x6) + EOPNOTSUPP = syscall.Errno(0x40) + EOVERFLOW = syscall.Errno(0x7f) + EOWNERDEAD = syscall.Errno(0x5f) + EPERM = syscall.Errno(0x1) + EPFNOSUPPORT = syscall.Errno(0x41) + EPIPE = syscall.Errno(0x20) + EPROCLIM = syscall.Errno(0x53) + EPROTO = syscall.Errno(0x79) + EPROTONOSUPPORT = syscall.Errno(0x3e) + EPROTOTYPE = syscall.Errno(0x3c) + ERANGE = syscall.Errno(0x22) + EREMOTE = syscall.Errno(0x5d) + ERESTART = syscall.Errno(0x52) + EROFS = syscall.Errno(0x1e) + ESAD = syscall.Errno(0x71) + ESHUTDOWN = syscall.Errno(0x4d) + ESOCKTNOSUPPORT = syscall.Errno(0x3f) + ESOFT = syscall.Errno(0x6f) + ESPIPE = syscall.Errno(0x1d) + ESRCH = syscall.Errno(0x3) + ESTALE = syscall.Errno(0x34) + ESYSERROR = syscall.Errno(0x5a) + ETIME = syscall.Errno(0x77) + ETIMEDOUT = syscall.Errno(0x4e) + ETOOMANYREFS = syscall.Errno(0x73) + ETXTBSY = syscall.Errno(0x1a) + EUNATCH = syscall.Errno(0x2a) + EUSERS = syscall.Errno(0x54) + EWOULDBLOCK = syscall.Errno(0xb) + EWRPROTECT = syscall.Errno(0x2f) + EXDEV = syscall.Errno(0x12) +) + +// Signals +const ( + SIGABRT = syscall.Signal(0x6) + SIGAIO = syscall.Signal(0x17) + SIGALRM = syscall.Signal(0xe) + SIGALRM1 = syscall.Signal(0x26) + SIGBUS = syscall.Signal(0xa) + SIGCAPI = syscall.Signal(0x31) + SIGCHLD = syscall.Signal(0x14) + SIGCLD = syscall.Signal(0x14) + SIGCONT = syscall.Signal(0x13) + SIGCPUFAIL = syscall.Signal(0x3b) + SIGDANGER = syscall.Signal(0x21) + SIGEMT = syscall.Signal(0x7) + SIGFPE = syscall.Signal(0x8) + SIGGRANT = syscall.Signal(0x3c) + SIGHUP = syscall.Signal(0x1) + SIGILL = syscall.Signal(0x4) + SIGINT = syscall.Signal(0x2) + SIGIO = syscall.Signal(0x17) + SIGIOINT = syscall.Signal(0x10) + SIGIOT = syscall.Signal(0x6) + SIGKAP = syscall.Signal(0x3c) + SIGKILL = syscall.Signal(0x9) + SIGLOST = syscall.Signal(0x6) + SIGMAX = syscall.Signal(0xff) + SIGMAX32 = syscall.Signal(0x3f) + SIGMIGRATE = syscall.Signal(0x23) + SIGMSG = syscall.Signal(0x1b) + SIGPIPE = syscall.Signal(0xd) + SIGPOLL = syscall.Signal(0x17) + SIGPRE = syscall.Signal(0x24) + SIGPROF = syscall.Signal(0x20) + SIGPTY = syscall.Signal(0x17) + SIGPWR = syscall.Signal(0x1d) + SIGQUIT = syscall.Signal(0x3) + SIGRECONFIG = syscall.Signal(0x3a) + SIGRETRACT = syscall.Signal(0x3d) + SIGSAK = syscall.Signal(0x3f) + SIGSEGV = syscall.Signal(0xb) + SIGSOUND = syscall.Signal(0x3e) + SIGSTOP = syscall.Signal(0x11) + SIGSYS = syscall.Signal(0xc) + SIGSYSERROR = syscall.Signal(0x30) + SIGTALRM = syscall.Signal(0x26) + SIGTERM = syscall.Signal(0xf) + SIGTRAP = syscall.Signal(0x5) + SIGTSTP = syscall.Signal(0x12) + SIGTTIN = syscall.Signal(0x15) + SIGTTOU = syscall.Signal(0x16) + SIGURG = syscall.Signal(0x10) + SIGUSR1 = syscall.Signal(0x1e) + SIGUSR2 = syscall.Signal(0x1f) + SIGVIRT = syscall.Signal(0x25) + SIGVTALRM = syscall.Signal(0x22) + SIGWAITING = syscall.Signal(0x27) + SIGWINCH = syscall.Signal(0x1c) + SIGXCPU = syscall.Signal(0x18) + SIGXFSZ = syscall.Signal(0x19) +) + +// Error table +var errorList = [...]struct { + num syscall.Errno + name string + desc string +}{ + {1, "EPERM", "not owner"}, + {2, "ENOENT", "no such file or directory"}, + {3, "ESRCH", "no such process"}, + {4, "EINTR", "interrupted system call"}, + {5, "EIO", "I/O error"}, + {6, "ENXIO", "no such device or address"}, + {7, "E2BIG", "arg list too long"}, + {8, "ENOEXEC", "exec format error"}, + {9, "EBADF", "bad file number"}, + {10, "ECHILD", "no child processes"}, + {11, "EWOULDBLOCK", "resource temporarily unavailable"}, + {12, "ENOMEM", "not enough space"}, + {13, "EACCES", "permission denied"}, + {14, "EFAULT", "bad address"}, + {15, "ENOTBLK", "block device required"}, + {16, "EBUSY", "device busy"}, + {17, "ENOTEMPTY", "file exists"}, + {18, "EXDEV", "cross-device link"}, + {19, "ENODEV", "no such device"}, + {20, "ENOTDIR", "not a directory"}, + {21, "EISDIR", "is a directory"}, + {22, "EINVAL", "invalid argument"}, + {23, "ENFILE", "file table overflow"}, + {24, "EMFILE", "too many open files"}, + {25, "ENOTTY", "not a typewriter"}, + {26, "ETXTBSY", "text file busy"}, + {27, "EFBIG", "file too large"}, + {28, "ENOSPC", "no space left on device"}, + {29, "ESPIPE", "illegal seek"}, + {30, "EROFS", "read-only file system"}, + {31, "EMLINK", "too many links"}, + {32, "EPIPE", "broken pipe"}, + {33, "EDOM", "argument out of domain"}, + {34, "ERANGE", "result too large"}, + {35, "ENOMSG", "no message of desired type"}, + {36, "EIDRM", "identifier removed"}, + {37, "ECHRNG", "channel number out of range"}, + {38, "EL2NSYNC", "level 2 not synchronized"}, + {39, "EL3HLT", "level 3 halted"}, + {40, "EL3RST", "level 3 reset"}, + {41, "ELNRNG", "link number out of range"}, + {42, "EUNATCH", "protocol driver not attached"}, + {43, "ENOCSI", "no CSI structure available"}, + {44, "EL2HLT", "level 2 halted"}, + {45, "EDEADLK", "deadlock condition if locked"}, + {46, "ENOTREADY", "device not ready"}, + {47, "EWRPROTECT", "write-protected media"}, + {48, "EFORMAT", "unformatted or incompatible media"}, + {49, "ENOLCK", "no locks available"}, + {50, "ENOCONNECT", "cannot Establish Connection"}, + {52, "ESTALE", "missing file or filesystem"}, + {53, "EDIST", "requests blocked by Administrator"}, + {55, "EINPROGRESS", "operation now in progress"}, + {56, "EALREADY", "operation already in progress"}, + {57, "ENOTSOCK", "socket operation on non-socket"}, + {58, "EDESTADDREQ", "destination address required"}, + {59, "EMSGSIZE", "message too long"}, + {60, "EPROTOTYPE", "protocol wrong type for socket"}, + {61, "ENOPROTOOPT", "protocol not available"}, + {62, "EPROTONOSUPPORT", "protocol not supported"}, + {63, "ESOCKTNOSUPPORT", "socket type not supported"}, + {64, "EOPNOTSUPP", "operation not supported on socket"}, + {65, "EPFNOSUPPORT", "protocol family not supported"}, + {66, "EAFNOSUPPORT", "addr family not supported by protocol"}, + {67, "EADDRINUSE", "address already in use"}, + {68, "EADDRNOTAVAIL", "can't assign requested address"}, + {69, "ENETDOWN", "network is down"}, + {70, "ENETUNREACH", "network is unreachable"}, + {71, "ENETRESET", "network dropped connection on reset"}, + {72, "ECONNABORTED", "software caused connection abort"}, + {73, "ECONNRESET", "connection reset by peer"}, + {74, "ENOBUFS", "no buffer space available"}, + {75, "EISCONN", "socket is already connected"}, + {76, "ENOTCONN", "socket is not connected"}, + {77, "ESHUTDOWN", "can't send after socket shutdown"}, + {78, "ETIMEDOUT", "connection timed out"}, + {79, "ECONNREFUSED", "connection refused"}, + {80, "EHOSTDOWN", "host is down"}, + {81, "EHOSTUNREACH", "no route to host"}, + {82, "ERESTART", "restart the system call"}, + {83, "EPROCLIM", "too many processes"}, + {84, "EUSERS", "too many users"}, + {85, "ELOOP", "too many levels of symbolic links"}, + {86, "ENAMETOOLONG", "file name too long"}, + {88, "EDQUOT", "disk quota exceeded"}, + {89, "ECORRUPT", "invalid file system control data detected"}, + {90, "ESYSERROR", "for future use "}, + {93, "EREMOTE", "item is not local to host"}, + {94, "ENOTRECOVERABLE", "state not recoverable "}, + {95, "EOWNERDEAD", "previous owner died "}, + {109, "ENOSYS", "function not implemented"}, + {110, "EMEDIA", "media surface error"}, + {111, "ESOFT", "I/O completed, but needs relocation"}, + {112, "ENOATTR", "no attribute found"}, + {113, "ESAD", "security Authentication Denied"}, + {114, "ENOTRUST", "not a Trusted Program"}, + {115, "ETOOMANYREFS", "too many references: can't splice"}, + {116, "EILSEQ", "invalid wide character"}, + {117, "ECANCELED", "asynchronous I/O cancelled"}, + {118, "ENOSR", "out of STREAMS resources"}, + {119, "ETIME", "system call timed out"}, + {120, "EBADMSG", "next message has wrong type"}, + {121, "EPROTO", "error in protocol"}, + {122, "ENODATA", "no message on stream head read q"}, + {123, "ENOSTR", "fd not associated with a stream"}, + {124, "ENOTSUP", "unsupported attribute value"}, + {125, "EMULTIHOP", "multihop is not allowed"}, + {126, "ENOLINK", "the server link has been severed"}, + {127, "EOVERFLOW", "value too large to be stored in data type"}, +} + +// Signal table +var signalList = [...]struct { + num syscall.Signal + name string + desc string +}{ + {1, "SIGHUP", "hangup"}, + {2, "SIGINT", "interrupt"}, + {3, "SIGQUIT", "quit"}, + {4, "SIGILL", "illegal instruction"}, + {5, "SIGTRAP", "trace/BPT trap"}, + {6, "SIGIOT", "IOT/Abort trap"}, + {7, "SIGEMT", "EMT trap"}, + {8, "SIGFPE", "floating point exception"}, + {9, "SIGKILL", "killed"}, + {10, "SIGBUS", "bus error"}, + {11, "SIGSEGV", "segmentation fault"}, + {12, "SIGSYS", "bad system call"}, + {13, "SIGPIPE", "broken pipe"}, + {14, "SIGALRM", "alarm clock"}, + {15, "SIGTERM", "terminated"}, + {16, "SIGURG", "urgent I/O condition"}, + {17, "SIGSTOP", "stopped (signal)"}, + {18, "SIGTSTP", "stopped"}, + {19, "SIGCONT", "continued"}, + {20, "SIGCHLD", "child exited"}, + {21, "SIGTTIN", "stopped (tty input)"}, + {22, "SIGTTOU", "stopped (tty output)"}, + {23, "SIGIO", "I/O possible/complete"}, + {24, "SIGXCPU", "cputime limit exceeded"}, + {25, "SIGXFSZ", "filesize limit exceeded"}, + {27, "SIGMSG", "input device data"}, + {28, "SIGWINCH", "window size changes"}, + {29, "SIGPWR", "power-failure"}, + {30, "SIGUSR1", "user defined signal 1"}, + {31, "SIGUSR2", "user defined signal 2"}, + {32, "SIGPROF", "profiling timer expired"}, + {33, "SIGDANGER", "paging space low"}, + {34, "SIGVTALRM", "virtual timer expired"}, + {35, "SIGMIGRATE", "signal 35"}, + {36, "SIGPRE", "signal 36"}, + {37, "SIGVIRT", "signal 37"}, + {38, "SIGTALRM", "signal 38"}, + {39, "SIGWAITING", "signal 39"}, + {48, "SIGSYSERROR", "signal 48"}, + {49, "SIGCAPI", "signal 49"}, + {58, "SIGRECONFIG", "signal 58"}, + {59, "SIGCPUFAIL", "CPU Failure Predicted"}, + {60, "SIGGRANT", "monitor mode granted"}, + {61, "SIGRETRACT", "monitor mode retracted"}, + {62, "SIGSOUND", "sound completed"}, + {63, "SIGMAX32", "secure attention"}, + {255, "SIGMAX", "signal 255"}, +} diff --git a/vendor/golang.org/x/sys/unix/zerrors_darwin_386.go b/vendor/golang.org/x/sys/unix/zerrors_darwin_386.go index c90ebcf7a2..3b39d7408a 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_darwin_386.go +++ b/vendor/golang.org/x/sys/unix/zerrors_darwin_386.go @@ -249,6 +249,8 @@ const ( CSTOP = 0x13 CSTOPB = 0x400 CSUSP = 0x1a + CTL_HW = 0x6 + CTL_KERN = 0x1 CTL_MAXNAME = 0xc CTL_NET = 0x4 DLT_A429 = 0xb8 @@ -532,6 +534,7 @@ const ( F_VOLPOSMODE = 0x4 F_WRLCK = 0x3 HUPCL = 0x4000 + HW_MACHINE = 0x1 ICANON = 0x100 ICMP6_FILTER = 0x12 ICRNL = 0x100 @@ -878,6 +881,10 @@ const ( IXANY = 0x800 IXOFF = 0x400 IXON = 0x200 + KERN_HOSTNAME = 0xa + KERN_OSRELEASE = 0x2 + KERN_OSTYPE = 0x1 + KERN_VERSION = 0x4 LOCK_EX = 0x2 LOCK_NB = 0x4 LOCK_SH = 0x1 @@ -1466,6 +1473,12 @@ const ( WORDSIZE = 0x20 WSTOPPED = 0x8 WUNTRACED = 0x2 + XATTR_CREATE = 0x2 + XATTR_NODEFAULT = 0x10 + XATTR_NOFOLLOW = 0x1 + XATTR_NOSECURITY = 0x8 + XATTR_REPLACE = 0x4 + XATTR_SHOWCOMPRESSION = 0x20 ) // Errors @@ -1617,146 +1630,154 @@ const ( ) // Error table -var errors = [...]string{ - 1: "operation not permitted", - 2: "no such file or directory", - 3: "no such process", - 4: "interrupted system call", - 5: "input/output error", - 6: "device not configured", - 7: "argument list too long", - 8: "exec format error", - 9: "bad file descriptor", - 10: "no child processes", - 11: "resource deadlock avoided", - 12: "cannot allocate memory", - 13: "permission denied", - 14: "bad address", - 15: "block device required", - 16: "resource busy", - 17: "file exists", - 18: "cross-device link", - 19: "operation not supported by device", - 20: "not a directory", - 21: "is a directory", - 22: "invalid argument", - 23: "too many open files in system", - 24: "too many open files", - 25: "inappropriate ioctl for device", - 26: "text file busy", - 27: "file too large", - 28: "no space left on device", - 29: "illegal seek", - 30: "read-only file system", - 31: "too many links", - 32: "broken pipe", - 33: "numerical argument out of domain", - 34: "result too large", - 35: "resource temporarily unavailable", - 36: "operation now in progress", - 37: "operation already in progress", - 38: "socket operation on non-socket", - 39: "destination address required", - 40: "message too long", - 41: "protocol wrong type for socket", - 42: "protocol not available", - 43: "protocol not supported", - 44: "socket type not supported", - 45: "operation not supported", - 46: "protocol family not supported", - 47: "address family not supported by protocol family", - 48: "address already in use", - 49: "can't assign requested address", - 50: "network is down", - 51: "network is unreachable", - 52: "network dropped connection on reset", - 53: "software caused connection abort", - 54: "connection reset by peer", - 55: "no buffer space available", - 56: "socket is already connected", - 57: "socket is not connected", - 58: "can't send after socket shutdown", - 59: "too many references: can't splice", - 60: "operation timed out", - 61: "connection refused", - 62: "too many levels of symbolic links", - 63: "file name too long", - 64: "host is down", - 65: "no route to host", - 66: "directory not empty", - 67: "too many processes", - 68: "too many users", - 69: "disc quota exceeded", - 70: "stale NFS file handle", - 71: "too many levels of remote in path", - 72: "RPC struct is bad", - 73: "RPC version wrong", - 74: "RPC prog. not avail", - 75: "program version wrong", - 76: "bad procedure for program", - 77: "no locks available", - 78: "function not implemented", - 79: "inappropriate file type or format", - 80: "authentication error", - 81: "need authenticator", - 82: "device power is off", - 83: "device error", - 84: "value too large to be stored in data type", - 85: "bad executable (or shared library)", - 86: "bad CPU type in executable", - 87: "shared library version mismatch", - 88: "malformed Mach-o file", - 89: "operation canceled", - 90: "identifier removed", - 91: "no message of desired type", - 92: "illegal byte sequence", - 93: "attribute not found", - 94: "bad message", - 95: "EMULTIHOP (Reserved)", - 96: "no message available on STREAM", - 97: "ENOLINK (Reserved)", - 98: "no STREAM resources", - 99: "not a STREAM", - 100: "protocol error", - 101: "STREAM ioctl timeout", - 102: "operation not supported on socket", - 103: "policy not found", - 104: "state not recoverable", - 105: "previous owner died", - 106: "interface output queue is full", +var errorList = [...]struct { + num syscall.Errno + name string + desc string +}{ + {1, "EPERM", "operation not permitted"}, + {2, "ENOENT", "no such file or directory"}, + {3, "ESRCH", "no such process"}, + {4, "EINTR", "interrupted system call"}, + {5, "EIO", "input/output error"}, + {6, "ENXIO", "device not configured"}, + {7, "E2BIG", "argument list too long"}, + {8, "ENOEXEC", "exec format error"}, + {9, "EBADF", "bad file descriptor"}, + {10, "ECHILD", "no child processes"}, + {11, "EDEADLK", "resource deadlock avoided"}, + {12, "ENOMEM", "cannot allocate memory"}, + {13, "EACCES", "permission denied"}, + {14, "EFAULT", "bad address"}, + {15, "ENOTBLK", "block device required"}, + {16, "EBUSY", "resource busy"}, + {17, "EEXIST", "file exists"}, + {18, "EXDEV", "cross-device link"}, + {19, "ENODEV", "operation not supported by device"}, + {20, "ENOTDIR", "not a directory"}, + {21, "EISDIR", "is a directory"}, + {22, "EINVAL", "invalid argument"}, + {23, "ENFILE", "too many open files in system"}, + {24, "EMFILE", "too many open files"}, + {25, "ENOTTY", "inappropriate ioctl for device"}, + {26, "ETXTBSY", "text file busy"}, + {27, "EFBIG", "file too large"}, + {28, "ENOSPC", "no space left on device"}, + {29, "ESPIPE", "illegal seek"}, + {30, "EROFS", "read-only file system"}, + {31, "EMLINK", "too many links"}, + {32, "EPIPE", "broken pipe"}, + {33, "EDOM", "numerical argument out of domain"}, + {34, "ERANGE", "result too large"}, + {35, "EAGAIN", "resource temporarily unavailable"}, + {36, "EINPROGRESS", "operation now in progress"}, + {37, "EALREADY", "operation already in progress"}, + {38, "ENOTSOCK", "socket operation on non-socket"}, + {39, "EDESTADDRREQ", "destination address required"}, + {40, "EMSGSIZE", "message too long"}, + {41, "EPROTOTYPE", "protocol wrong type for socket"}, + {42, "ENOPROTOOPT", "protocol not available"}, + {43, "EPROTONOSUPPORT", "protocol not supported"}, + {44, "ESOCKTNOSUPPORT", "socket type not supported"}, + {45, "ENOTSUP", "operation not supported"}, + {46, "EPFNOSUPPORT", "protocol family not supported"}, + {47, "EAFNOSUPPORT", "address family not supported by protocol family"}, + {48, "EADDRINUSE", "address already in use"}, + {49, "EADDRNOTAVAIL", "can't assign requested address"}, + {50, "ENETDOWN", "network is down"}, + {51, "ENETUNREACH", "network is unreachable"}, + {52, "ENETRESET", "network dropped connection on reset"}, + {53, "ECONNABORTED", "software caused connection abort"}, + {54, "ECONNRESET", "connection reset by peer"}, + {55, "ENOBUFS", "no buffer space available"}, + {56, "EISCONN", "socket is already connected"}, + {57, "ENOTCONN", "socket is not connected"}, + {58, "ESHUTDOWN", "can't send after socket shutdown"}, + {59, "ETOOMANYREFS", "too many references: can't splice"}, + {60, "ETIMEDOUT", "operation timed out"}, + {61, "ECONNREFUSED", "connection refused"}, + {62, "ELOOP", "too many levels of symbolic links"}, + {63, "ENAMETOOLONG", "file name too long"}, + {64, "EHOSTDOWN", "host is down"}, + {65, "EHOSTUNREACH", "no route to host"}, + {66, "ENOTEMPTY", "directory not empty"}, + {67, "EPROCLIM", "too many processes"}, + {68, "EUSERS", "too many users"}, + {69, "EDQUOT", "disc quota exceeded"}, + {70, "ESTALE", "stale NFS file handle"}, + {71, "EREMOTE", "too many levels of remote in path"}, + {72, "EBADRPC", "RPC struct is bad"}, + {73, "ERPCMISMATCH", "RPC version wrong"}, + {74, "EPROGUNAVAIL", "RPC prog. not avail"}, + {75, "EPROGMISMATCH", "program version wrong"}, + {76, "EPROCUNAVAIL", "bad procedure for program"}, + {77, "ENOLCK", "no locks available"}, + {78, "ENOSYS", "function not implemented"}, + {79, "EFTYPE", "inappropriate file type or format"}, + {80, "EAUTH", "authentication error"}, + {81, "ENEEDAUTH", "need authenticator"}, + {82, "EPWROFF", "device power is off"}, + {83, "EDEVERR", "device error"}, + {84, "EOVERFLOW", "value too large to be stored in data type"}, + {85, "EBADEXEC", "bad executable (or shared library)"}, + {86, "EBADARCH", "bad CPU type in executable"}, + {87, "ESHLIBVERS", "shared library version mismatch"}, + {88, "EBADMACHO", "malformed Mach-o file"}, + {89, "ECANCELED", "operation canceled"}, + {90, "EIDRM", "identifier removed"}, + {91, "ENOMSG", "no message of desired type"}, + {92, "EILSEQ", "illegal byte sequence"}, + {93, "ENOATTR", "attribute not found"}, + {94, "EBADMSG", "bad message"}, + {95, "EMULTIHOP", "EMULTIHOP (Reserved)"}, + {96, "ENODATA", "no message available on STREAM"}, + {97, "ENOLINK", "ENOLINK (Reserved)"}, + {98, "ENOSR", "no STREAM resources"}, + {99, "ENOSTR", "not a STREAM"}, + {100, "EPROTO", "protocol error"}, + {101, "ETIME", "STREAM ioctl timeout"}, + {102, "EOPNOTSUPP", "operation not supported on socket"}, + {103, "ENOPOLICY", "policy not found"}, + {104, "ENOTRECOVERABLE", "state not recoverable"}, + {105, "EOWNERDEAD", "previous owner died"}, + {106, "EQFULL", "interface output queue is full"}, } // Signal table -var signals = [...]string{ - 1: "hangup", - 2: "interrupt", - 3: "quit", - 4: "illegal instruction", - 5: "trace/BPT trap", - 6: "abort trap", - 7: "EMT trap", - 8: "floating point exception", - 9: "killed", - 10: "bus error", - 11: "segmentation fault", - 12: "bad system call", - 13: "broken pipe", - 14: "alarm clock", - 15: "terminated", - 16: "urgent I/O condition", - 17: "suspended (signal)", - 18: "suspended", - 19: "continued", - 20: "child exited", - 21: "stopped (tty input)", - 22: "stopped (tty output)", - 23: "I/O possible", - 24: "cputime limit exceeded", - 25: "filesize limit exceeded", - 26: "virtual timer expired", - 27: "profiling timer expired", - 28: "window size changes", - 29: "information request", - 30: "user defined signal 1", - 31: "user defined signal 2", +var signalList = [...]struct { + num syscall.Signal + name string + desc string +}{ + {1, "SIGHUP", "hangup"}, + {2, "SIGINT", "interrupt"}, + {3, "SIGQUIT", "quit"}, + {4, "SIGILL", "illegal instruction"}, + {5, "SIGTRAP", "trace/BPT trap"}, + {6, "SIGABRT", "abort trap"}, + {7, "SIGEMT", "EMT trap"}, + {8, "SIGFPE", "floating point exception"}, + {9, "SIGKILL", "killed"}, + {10, "SIGBUS", "bus error"}, + {11, "SIGSEGV", "segmentation fault"}, + {12, "SIGSYS", "bad system call"}, + {13, "SIGPIPE", "broken pipe"}, + {14, "SIGALRM", "alarm clock"}, + {15, "SIGTERM", "terminated"}, + {16, "SIGURG", "urgent I/O condition"}, + {17, "SIGSTOP", "suspended (signal)"}, + {18, "SIGTSTP", "suspended"}, + {19, "SIGCONT", "continued"}, + {20, "SIGCHLD", "child exited"}, + {21, "SIGTTIN", "stopped (tty input)"}, + {22, "SIGTTOU", "stopped (tty output)"}, + {23, "SIGIO", "I/O possible"}, + {24, "SIGXCPU", "cputime limit exceeded"}, + {25, "SIGXFSZ", "filesize limit exceeded"}, + {26, "SIGVTALRM", "virtual timer expired"}, + {27, "SIGPROF", "profiling timer expired"}, + {28, "SIGWINCH", "window size changes"}, + {29, "SIGINFO", "information request"}, + {30, "SIGUSR1", "user defined signal 1"}, + {31, "SIGUSR2", "user defined signal 2"}, } diff --git a/vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go index 8991948649..8fe5547775 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go @@ -249,6 +249,8 @@ const ( CSTOP = 0x13 CSTOPB = 0x400 CSUSP = 0x1a + CTL_HW = 0x6 + CTL_KERN = 0x1 CTL_MAXNAME = 0xc CTL_NET = 0x4 DLT_A429 = 0xb8 @@ -532,6 +534,7 @@ const ( F_VOLPOSMODE = 0x4 F_WRLCK = 0x3 HUPCL = 0x4000 + HW_MACHINE = 0x1 ICANON = 0x100 ICMP6_FILTER = 0x12 ICRNL = 0x100 @@ -878,6 +881,10 @@ const ( IXANY = 0x800 IXOFF = 0x400 IXON = 0x200 + KERN_HOSTNAME = 0xa + KERN_OSRELEASE = 0x2 + KERN_OSTYPE = 0x1 + KERN_VERSION = 0x4 LOCK_EX = 0x2 LOCK_NB = 0x4 LOCK_SH = 0x1 @@ -1466,6 +1473,12 @@ const ( WORDSIZE = 0x40 WSTOPPED = 0x8 WUNTRACED = 0x2 + XATTR_CREATE = 0x2 + XATTR_NODEFAULT = 0x10 + XATTR_NOFOLLOW = 0x1 + XATTR_NOSECURITY = 0x8 + XATTR_REPLACE = 0x4 + XATTR_SHOWCOMPRESSION = 0x20 ) // Errors @@ -1617,146 +1630,154 @@ const ( ) // Error table -var errors = [...]string{ - 1: "operation not permitted", - 2: "no such file or directory", - 3: "no such process", - 4: "interrupted system call", - 5: "input/output error", - 6: "device not configured", - 7: "argument list too long", - 8: "exec format error", - 9: "bad file descriptor", - 10: "no child processes", - 11: "resource deadlock avoided", - 12: "cannot allocate memory", - 13: "permission denied", - 14: "bad address", - 15: "block device required", - 16: "resource busy", - 17: "file exists", - 18: "cross-device link", - 19: "operation not supported by device", - 20: "not a directory", - 21: "is a directory", - 22: "invalid argument", - 23: "too many open files in system", - 24: "too many open files", - 25: "inappropriate ioctl for device", - 26: "text file busy", - 27: "file too large", - 28: "no space left on device", - 29: "illegal seek", - 30: "read-only file system", - 31: "too many links", - 32: "broken pipe", - 33: "numerical argument out of domain", - 34: "result too large", - 35: "resource temporarily unavailable", - 36: "operation now in progress", - 37: "operation already in progress", - 38: "socket operation on non-socket", - 39: "destination address required", - 40: "message too long", - 41: "protocol wrong type for socket", - 42: "protocol not available", - 43: "protocol not supported", - 44: "socket type not supported", - 45: "operation not supported", - 46: "protocol family not supported", - 47: "address family not supported by protocol family", - 48: "address already in use", - 49: "can't assign requested address", - 50: "network is down", - 51: "network is unreachable", - 52: "network dropped connection on reset", - 53: "software caused connection abort", - 54: "connection reset by peer", - 55: "no buffer space available", - 56: "socket is already connected", - 57: "socket is not connected", - 58: "can't send after socket shutdown", - 59: "too many references: can't splice", - 60: "operation timed out", - 61: "connection refused", - 62: "too many levels of symbolic links", - 63: "file name too long", - 64: "host is down", - 65: "no route to host", - 66: "directory not empty", - 67: "too many processes", - 68: "too many users", - 69: "disc quota exceeded", - 70: "stale NFS file handle", - 71: "too many levels of remote in path", - 72: "RPC struct is bad", - 73: "RPC version wrong", - 74: "RPC prog. not avail", - 75: "program version wrong", - 76: "bad procedure for program", - 77: "no locks available", - 78: "function not implemented", - 79: "inappropriate file type or format", - 80: "authentication error", - 81: "need authenticator", - 82: "device power is off", - 83: "device error", - 84: "value too large to be stored in data type", - 85: "bad executable (or shared library)", - 86: "bad CPU type in executable", - 87: "shared library version mismatch", - 88: "malformed Mach-o file", - 89: "operation canceled", - 90: "identifier removed", - 91: "no message of desired type", - 92: "illegal byte sequence", - 93: "attribute not found", - 94: "bad message", - 95: "EMULTIHOP (Reserved)", - 96: "no message available on STREAM", - 97: "ENOLINK (Reserved)", - 98: "no STREAM resources", - 99: "not a STREAM", - 100: "protocol error", - 101: "STREAM ioctl timeout", - 102: "operation not supported on socket", - 103: "policy not found", - 104: "state not recoverable", - 105: "previous owner died", - 106: "interface output queue is full", +var errorList = [...]struct { + num syscall.Errno + name string + desc string +}{ + {1, "EPERM", "operation not permitted"}, + {2, "ENOENT", "no such file or directory"}, + {3, "ESRCH", "no such process"}, + {4, "EINTR", "interrupted system call"}, + {5, "EIO", "input/output error"}, + {6, "ENXIO", "device not configured"}, + {7, "E2BIG", "argument list too long"}, + {8, "ENOEXEC", "exec format error"}, + {9, "EBADF", "bad file descriptor"}, + {10, "ECHILD", "no child processes"}, + {11, "EDEADLK", "resource deadlock avoided"}, + {12, "ENOMEM", "cannot allocate memory"}, + {13, "EACCES", "permission denied"}, + {14, "EFAULT", "bad address"}, + {15, "ENOTBLK", "block device required"}, + {16, "EBUSY", "resource busy"}, + {17, "EEXIST", "file exists"}, + {18, "EXDEV", "cross-device link"}, + {19, "ENODEV", "operation not supported by device"}, + {20, "ENOTDIR", "not a directory"}, + {21, "EISDIR", "is a directory"}, + {22, "EINVAL", "invalid argument"}, + {23, "ENFILE", "too many open files in system"}, + {24, "EMFILE", "too many open files"}, + {25, "ENOTTY", "inappropriate ioctl for device"}, + {26, "ETXTBSY", "text file busy"}, + {27, "EFBIG", "file too large"}, + {28, "ENOSPC", "no space left on device"}, + {29, "ESPIPE", "illegal seek"}, + {30, "EROFS", "read-only file system"}, + {31, "EMLINK", "too many links"}, + {32, "EPIPE", "broken pipe"}, + {33, "EDOM", "numerical argument out of domain"}, + {34, "ERANGE", "result too large"}, + {35, "EAGAIN", "resource temporarily unavailable"}, + {36, "EINPROGRESS", "operation now in progress"}, + {37, "EALREADY", "operation already in progress"}, + {38, "ENOTSOCK", "socket operation on non-socket"}, + {39, "EDESTADDRREQ", "destination address required"}, + {40, "EMSGSIZE", "message too long"}, + {41, "EPROTOTYPE", "protocol wrong type for socket"}, + {42, "ENOPROTOOPT", "protocol not available"}, + {43, "EPROTONOSUPPORT", "protocol not supported"}, + {44, "ESOCKTNOSUPPORT", "socket type not supported"}, + {45, "ENOTSUP", "operation not supported"}, + {46, "EPFNOSUPPORT", "protocol family not supported"}, + {47, "EAFNOSUPPORT", "address family not supported by protocol family"}, + {48, "EADDRINUSE", "address already in use"}, + {49, "EADDRNOTAVAIL", "can't assign requested address"}, + {50, "ENETDOWN", "network is down"}, + {51, "ENETUNREACH", "network is unreachable"}, + {52, "ENETRESET", "network dropped connection on reset"}, + {53, "ECONNABORTED", "software caused connection abort"}, + {54, "ECONNRESET", "connection reset by peer"}, + {55, "ENOBUFS", "no buffer space available"}, + {56, "EISCONN", "socket is already connected"}, + {57, "ENOTCONN", "socket is not connected"}, + {58, "ESHUTDOWN", "can't send after socket shutdown"}, + {59, "ETOOMANYREFS", "too many references: can't splice"}, + {60, "ETIMEDOUT", "operation timed out"}, + {61, "ECONNREFUSED", "connection refused"}, + {62, "ELOOP", "too many levels of symbolic links"}, + {63, "ENAMETOOLONG", "file name too long"}, + {64, "EHOSTDOWN", "host is down"}, + {65, "EHOSTUNREACH", "no route to host"}, + {66, "ENOTEMPTY", "directory not empty"}, + {67, "EPROCLIM", "too many processes"}, + {68, "EUSERS", "too many users"}, + {69, "EDQUOT", "disc quota exceeded"}, + {70, "ESTALE", "stale NFS file handle"}, + {71, "EREMOTE", "too many levels of remote in path"}, + {72, "EBADRPC", "RPC struct is bad"}, + {73, "ERPCMISMATCH", "RPC version wrong"}, + {74, "EPROGUNAVAIL", "RPC prog. not avail"}, + {75, "EPROGMISMATCH", "program version wrong"}, + {76, "EPROCUNAVAIL", "bad procedure for program"}, + {77, "ENOLCK", "no locks available"}, + {78, "ENOSYS", "function not implemented"}, + {79, "EFTYPE", "inappropriate file type or format"}, + {80, "EAUTH", "authentication error"}, + {81, "ENEEDAUTH", "need authenticator"}, + {82, "EPWROFF", "device power is off"}, + {83, "EDEVERR", "device error"}, + {84, "EOVERFLOW", "value too large to be stored in data type"}, + {85, "EBADEXEC", "bad executable (or shared library)"}, + {86, "EBADARCH", "bad CPU type in executable"}, + {87, "ESHLIBVERS", "shared library version mismatch"}, + {88, "EBADMACHO", "malformed Mach-o file"}, + {89, "ECANCELED", "operation canceled"}, + {90, "EIDRM", "identifier removed"}, + {91, "ENOMSG", "no message of desired type"}, + {92, "EILSEQ", "illegal byte sequence"}, + {93, "ENOATTR", "attribute not found"}, + {94, "EBADMSG", "bad message"}, + {95, "EMULTIHOP", "EMULTIHOP (Reserved)"}, + {96, "ENODATA", "no message available on STREAM"}, + {97, "ENOLINK", "ENOLINK (Reserved)"}, + {98, "ENOSR", "no STREAM resources"}, + {99, "ENOSTR", "not a STREAM"}, + {100, "EPROTO", "protocol error"}, + {101, "ETIME", "STREAM ioctl timeout"}, + {102, "EOPNOTSUPP", "operation not supported on socket"}, + {103, "ENOPOLICY", "policy not found"}, + {104, "ENOTRECOVERABLE", "state not recoverable"}, + {105, "EOWNERDEAD", "previous owner died"}, + {106, "EQFULL", "interface output queue is full"}, } // Signal table -var signals = [...]string{ - 1: "hangup", - 2: "interrupt", - 3: "quit", - 4: "illegal instruction", - 5: "trace/BPT trap", - 6: "abort trap", - 7: "EMT trap", - 8: "floating point exception", - 9: "killed", - 10: "bus error", - 11: "segmentation fault", - 12: "bad system call", - 13: "broken pipe", - 14: "alarm clock", - 15: "terminated", - 16: "urgent I/O condition", - 17: "suspended (signal)", - 18: "suspended", - 19: "continued", - 20: "child exited", - 21: "stopped (tty input)", - 22: "stopped (tty output)", - 23: "I/O possible", - 24: "cputime limit exceeded", - 25: "filesize limit exceeded", - 26: "virtual timer expired", - 27: "profiling timer expired", - 28: "window size changes", - 29: "information request", - 30: "user defined signal 1", - 31: "user defined signal 2", +var signalList = [...]struct { + num syscall.Signal + name string + desc string +}{ + {1, "SIGHUP", "hangup"}, + {2, "SIGINT", "interrupt"}, + {3, "SIGQUIT", "quit"}, + {4, "SIGILL", "illegal instruction"}, + {5, "SIGTRAP", "trace/BPT trap"}, + {6, "SIGABRT", "abort trap"}, + {7, "SIGEMT", "EMT trap"}, + {8, "SIGFPE", "floating point exception"}, + {9, "SIGKILL", "killed"}, + {10, "SIGBUS", "bus error"}, + {11, "SIGSEGV", "segmentation fault"}, + {12, "SIGSYS", "bad system call"}, + {13, "SIGPIPE", "broken pipe"}, + {14, "SIGALRM", "alarm clock"}, + {15, "SIGTERM", "terminated"}, + {16, "SIGURG", "urgent I/O condition"}, + {17, "SIGSTOP", "suspended (signal)"}, + {18, "SIGTSTP", "suspended"}, + {19, "SIGCONT", "continued"}, + {20, "SIGCHLD", "child exited"}, + {21, "SIGTTIN", "stopped (tty input)"}, + {22, "SIGTTOU", "stopped (tty output)"}, + {23, "SIGIO", "I/O possible"}, + {24, "SIGXCPU", "cputime limit exceeded"}, + {25, "SIGXFSZ", "filesize limit exceeded"}, + {26, "SIGVTALRM", "virtual timer expired"}, + {27, "SIGPROF", "profiling timer expired"}, + {28, "SIGWINCH", "window size changes"}, + {29, "SIGINFO", "information request"}, + {30, "SIGUSR1", "user defined signal 1"}, + {31, "SIGUSR2", "user defined signal 2"}, } diff --git a/vendor/golang.org/x/sys/unix/zerrors_darwin_arm.go b/vendor/golang.org/x/sys/unix/zerrors_darwin_arm.go index c41a6b8790..7a977770d0 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_darwin_arm.go +++ b/vendor/golang.org/x/sys/unix/zerrors_darwin_arm.go @@ -249,6 +249,8 @@ const ( CSTOP = 0x13 CSTOPB = 0x400 CSUSP = 0x1a + CTL_HW = 0x6 + CTL_KERN = 0x1 CTL_MAXNAME = 0xc CTL_NET = 0x4 DLT_A429 = 0xb8 @@ -532,6 +534,7 @@ const ( F_VOLPOSMODE = 0x4 F_WRLCK = 0x3 HUPCL = 0x4000 + HW_MACHINE = 0x1 ICANON = 0x100 ICMP6_FILTER = 0x12 ICRNL = 0x100 @@ -878,6 +881,10 @@ const ( IXANY = 0x800 IXOFF = 0x400 IXON = 0x200 + KERN_HOSTNAME = 0xa + KERN_OSRELEASE = 0x2 + KERN_OSTYPE = 0x1 + KERN_VERSION = 0x4 LOCK_EX = 0x2 LOCK_NB = 0x4 LOCK_SH = 0x1 @@ -1466,6 +1473,12 @@ const ( WORDSIZE = 0x40 WSTOPPED = 0x8 WUNTRACED = 0x2 + XATTR_CREATE = 0x2 + XATTR_NODEFAULT = 0x10 + XATTR_NOFOLLOW = 0x1 + XATTR_NOSECURITY = 0x8 + XATTR_REPLACE = 0x4 + XATTR_SHOWCOMPRESSION = 0x20 ) // Errors @@ -1617,146 +1630,154 @@ const ( ) // Error table -var errors = [...]string{ - 1: "operation not permitted", - 2: "no such file or directory", - 3: "no such process", - 4: "interrupted system call", - 5: "input/output error", - 6: "device not configured", - 7: "argument list too long", - 8: "exec format error", - 9: "bad file descriptor", - 10: "no child processes", - 11: "resource deadlock avoided", - 12: "cannot allocate memory", - 13: "permission denied", - 14: "bad address", - 15: "block device required", - 16: "resource busy", - 17: "file exists", - 18: "cross-device link", - 19: "operation not supported by device", - 20: "not a directory", - 21: "is a directory", - 22: "invalid argument", - 23: "too many open files in system", - 24: "too many open files", - 25: "inappropriate ioctl for device", - 26: "text file busy", - 27: "file too large", - 28: "no space left on device", - 29: "illegal seek", - 30: "read-only file system", - 31: "too many links", - 32: "broken pipe", - 33: "numerical argument out of domain", - 34: "result too large", - 35: "resource temporarily unavailable", - 36: "operation now in progress", - 37: "operation already in progress", - 38: "socket operation on non-socket", - 39: "destination address required", - 40: "message too long", - 41: "protocol wrong type for socket", - 42: "protocol not available", - 43: "protocol not supported", - 44: "socket type not supported", - 45: "operation not supported", - 46: "protocol family not supported", - 47: "address family not supported by protocol family", - 48: "address already in use", - 49: "can't assign requested address", - 50: "network is down", - 51: "network is unreachable", - 52: "network dropped connection on reset", - 53: "software caused connection abort", - 54: "connection reset by peer", - 55: "no buffer space available", - 56: "socket is already connected", - 57: "socket is not connected", - 58: "can't send after socket shutdown", - 59: "too many references: can't splice", - 60: "operation timed out", - 61: "connection refused", - 62: "too many levels of symbolic links", - 63: "file name too long", - 64: "host is down", - 65: "no route to host", - 66: "directory not empty", - 67: "too many processes", - 68: "too many users", - 69: "disc quota exceeded", - 70: "stale NFS file handle", - 71: "too many levels of remote in path", - 72: "RPC struct is bad", - 73: "RPC version wrong", - 74: "RPC prog. not avail", - 75: "program version wrong", - 76: "bad procedure for program", - 77: "no locks available", - 78: "function not implemented", - 79: "inappropriate file type or format", - 80: "authentication error", - 81: "need authenticator", - 82: "device power is off", - 83: "device error", - 84: "value too large to be stored in data type", - 85: "bad executable (or shared library)", - 86: "bad CPU type in executable", - 87: "shared library version mismatch", - 88: "malformed Mach-o file", - 89: "operation canceled", - 90: "identifier removed", - 91: "no message of desired type", - 92: "illegal byte sequence", - 93: "attribute not found", - 94: "bad message", - 95: "EMULTIHOP (Reserved)", - 96: "no message available on STREAM", - 97: "ENOLINK (Reserved)", - 98: "no STREAM resources", - 99: "not a STREAM", - 100: "protocol error", - 101: "STREAM ioctl timeout", - 102: "operation not supported on socket", - 103: "policy not found", - 104: "state not recoverable", - 105: "previous owner died", - 106: "interface output queue is full", +var errorList = [...]struct { + num syscall.Errno + name string + desc string +}{ + {1, "EPERM", "operation not permitted"}, + {2, "ENOENT", "no such file or directory"}, + {3, "ESRCH", "no such process"}, + {4, "EINTR", "interrupted system call"}, + {5, "EIO", "input/output error"}, + {6, "ENXIO", "device not configured"}, + {7, "E2BIG", "argument list too long"}, + {8, "ENOEXEC", "exec format error"}, + {9, "EBADF", "bad file descriptor"}, + {10, "ECHILD", "no child processes"}, + {11, "EDEADLK", "resource deadlock avoided"}, + {12, "ENOMEM", "cannot allocate memory"}, + {13, "EACCES", "permission denied"}, + {14, "EFAULT", "bad address"}, + {15, "ENOTBLK", "block device required"}, + {16, "EBUSY", "resource busy"}, + {17, "EEXIST", "file exists"}, + {18, "EXDEV", "cross-device link"}, + {19, "ENODEV", "operation not supported by device"}, + {20, "ENOTDIR", "not a directory"}, + {21, "EISDIR", "is a directory"}, + {22, "EINVAL", "invalid argument"}, + {23, "ENFILE", "too many open files in system"}, + {24, "EMFILE", "too many open files"}, + {25, "ENOTTY", "inappropriate ioctl for device"}, + {26, "ETXTBSY", "text file busy"}, + {27, "EFBIG", "file too large"}, + {28, "ENOSPC", "no space left on device"}, + {29, "ESPIPE", "illegal seek"}, + {30, "EROFS", "read-only file system"}, + {31, "EMLINK", "too many links"}, + {32, "EPIPE", "broken pipe"}, + {33, "EDOM", "numerical argument out of domain"}, + {34, "ERANGE", "result too large"}, + {35, "EAGAIN", "resource temporarily unavailable"}, + {36, "EINPROGRESS", "operation now in progress"}, + {37, "EALREADY", "operation already in progress"}, + {38, "ENOTSOCK", "socket operation on non-socket"}, + {39, "EDESTADDRREQ", "destination address required"}, + {40, "EMSGSIZE", "message too long"}, + {41, "EPROTOTYPE", "protocol wrong type for socket"}, + {42, "ENOPROTOOPT", "protocol not available"}, + {43, "EPROTONOSUPPORT", "protocol not supported"}, + {44, "ESOCKTNOSUPPORT", "socket type not supported"}, + {45, "ENOTSUP", "operation not supported"}, + {46, "EPFNOSUPPORT", "protocol family not supported"}, + {47, "EAFNOSUPPORT", "address family not supported by protocol family"}, + {48, "EADDRINUSE", "address already in use"}, + {49, "EADDRNOTAVAIL", "can't assign requested address"}, + {50, "ENETDOWN", "network is down"}, + {51, "ENETUNREACH", "network is unreachable"}, + {52, "ENETRESET", "network dropped connection on reset"}, + {53, "ECONNABORTED", "software caused connection abort"}, + {54, "ECONNRESET", "connection reset by peer"}, + {55, "ENOBUFS", "no buffer space available"}, + {56, "EISCONN", "socket is already connected"}, + {57, "ENOTCONN", "socket is not connected"}, + {58, "ESHUTDOWN", "can't send after socket shutdown"}, + {59, "ETOOMANYREFS", "too many references: can't splice"}, + {60, "ETIMEDOUT", "operation timed out"}, + {61, "ECONNREFUSED", "connection refused"}, + {62, "ELOOP", "too many levels of symbolic links"}, + {63, "ENAMETOOLONG", "file name too long"}, + {64, "EHOSTDOWN", "host is down"}, + {65, "EHOSTUNREACH", "no route to host"}, + {66, "ENOTEMPTY", "directory not empty"}, + {67, "EPROCLIM", "too many processes"}, + {68, "EUSERS", "too many users"}, + {69, "EDQUOT", "disc quota exceeded"}, + {70, "ESTALE", "stale NFS file handle"}, + {71, "EREMOTE", "too many levels of remote in path"}, + {72, "EBADRPC", "RPC struct is bad"}, + {73, "ERPCMISMATCH", "RPC version wrong"}, + {74, "EPROGUNAVAIL", "RPC prog. not avail"}, + {75, "EPROGMISMATCH", "program version wrong"}, + {76, "EPROCUNAVAIL", "bad procedure for program"}, + {77, "ENOLCK", "no locks available"}, + {78, "ENOSYS", "function not implemented"}, + {79, "EFTYPE", "inappropriate file type or format"}, + {80, "EAUTH", "authentication error"}, + {81, "ENEEDAUTH", "need authenticator"}, + {82, "EPWROFF", "device power is off"}, + {83, "EDEVERR", "device error"}, + {84, "EOVERFLOW", "value too large to be stored in data type"}, + {85, "EBADEXEC", "bad executable (or shared library)"}, + {86, "EBADARCH", "bad CPU type in executable"}, + {87, "ESHLIBVERS", "shared library version mismatch"}, + {88, "EBADMACHO", "malformed Mach-o file"}, + {89, "ECANCELED", "operation canceled"}, + {90, "EIDRM", "identifier removed"}, + {91, "ENOMSG", "no message of desired type"}, + {92, "EILSEQ", "illegal byte sequence"}, + {93, "ENOATTR", "attribute not found"}, + {94, "EBADMSG", "bad message"}, + {95, "EMULTIHOP", "EMULTIHOP (Reserved)"}, + {96, "ENODATA", "no message available on STREAM"}, + {97, "ENOLINK", "ENOLINK (Reserved)"}, + {98, "ENOSR", "no STREAM resources"}, + {99, "ENOSTR", "not a STREAM"}, + {100, "EPROTO", "protocol error"}, + {101, "ETIME", "STREAM ioctl timeout"}, + {102, "EOPNOTSUPP", "operation not supported on socket"}, + {103, "ENOPOLICY", "policy not found"}, + {104, "ENOTRECOVERABLE", "state not recoverable"}, + {105, "EOWNERDEAD", "previous owner died"}, + {106, "EQFULL", "interface output queue is full"}, } // Signal table -var signals = [...]string{ - 1: "hangup", - 2: "interrupt", - 3: "quit", - 4: "illegal instruction", - 5: "trace/BPT trap", - 6: "abort trap", - 7: "EMT trap", - 8: "floating point exception", - 9: "killed", - 10: "bus error", - 11: "segmentation fault", - 12: "bad system call", - 13: "broken pipe", - 14: "alarm clock", - 15: "terminated", - 16: "urgent I/O condition", - 17: "suspended (signal)", - 18: "suspended", - 19: "continued", - 20: "child exited", - 21: "stopped (tty input)", - 22: "stopped (tty output)", - 23: "I/O possible", - 24: "cputime limit exceeded", - 25: "filesize limit exceeded", - 26: "virtual timer expired", - 27: "profiling timer expired", - 28: "window size changes", - 29: "information request", - 30: "user defined signal 1", - 31: "user defined signal 2", +var signalList = [...]struct { + num syscall.Signal + name string + desc string +}{ + {1, "SIGHUP", "hangup"}, + {2, "SIGINT", "interrupt"}, + {3, "SIGQUIT", "quit"}, + {4, "SIGILL", "illegal instruction"}, + {5, "SIGTRAP", "trace/BPT trap"}, + {6, "SIGABRT", "abort trap"}, + {7, "SIGEMT", "EMT trap"}, + {8, "SIGFPE", "floating point exception"}, + {9, "SIGKILL", "killed"}, + {10, "SIGBUS", "bus error"}, + {11, "SIGSEGV", "segmentation fault"}, + {12, "SIGSYS", "bad system call"}, + {13, "SIGPIPE", "broken pipe"}, + {14, "SIGALRM", "alarm clock"}, + {15, "SIGTERM", "terminated"}, + {16, "SIGURG", "urgent I/O condition"}, + {17, "SIGSTOP", "suspended (signal)"}, + {18, "SIGTSTP", "suspended"}, + {19, "SIGCONT", "continued"}, + {20, "SIGCHLD", "child exited"}, + {21, "SIGTTIN", "stopped (tty input)"}, + {22, "SIGTTOU", "stopped (tty output)"}, + {23, "SIGIO", "I/O possible"}, + {24, "SIGXCPU", "cputime limit exceeded"}, + {25, "SIGXFSZ", "filesize limit exceeded"}, + {26, "SIGVTALRM", "virtual timer expired"}, + {27, "SIGPROF", "profiling timer expired"}, + {28, "SIGWINCH", "window size changes"}, + {29, "SIGINFO", "information request"}, + {30, "SIGUSR1", "user defined signal 1"}, + {31, "SIGUSR2", "user defined signal 2"}, } diff --git a/vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go b/vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go index 73f8c8784c..6d56d8a059 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go @@ -249,6 +249,8 @@ const ( CSTOP = 0x13 CSTOPB = 0x400 CSUSP = 0x1a + CTL_HW = 0x6 + CTL_KERN = 0x1 CTL_MAXNAME = 0xc CTL_NET = 0x4 DLT_A429 = 0xb8 @@ -532,6 +534,7 @@ const ( F_VOLPOSMODE = 0x4 F_WRLCK = 0x3 HUPCL = 0x4000 + HW_MACHINE = 0x1 ICANON = 0x100 ICMP6_FILTER = 0x12 ICRNL = 0x100 @@ -878,6 +881,10 @@ const ( IXANY = 0x800 IXOFF = 0x400 IXON = 0x200 + KERN_HOSTNAME = 0xa + KERN_OSRELEASE = 0x2 + KERN_OSTYPE = 0x1 + KERN_VERSION = 0x4 LOCK_EX = 0x2 LOCK_NB = 0x4 LOCK_SH = 0x1 @@ -1466,6 +1473,12 @@ const ( WORDSIZE = 0x40 WSTOPPED = 0x8 WUNTRACED = 0x2 + XATTR_CREATE = 0x2 + XATTR_NODEFAULT = 0x10 + XATTR_NOFOLLOW = 0x1 + XATTR_NOSECURITY = 0x8 + XATTR_REPLACE = 0x4 + XATTR_SHOWCOMPRESSION = 0x20 ) // Errors @@ -1617,146 +1630,154 @@ const ( ) // Error table -var errors = [...]string{ - 1: "operation not permitted", - 2: "no such file or directory", - 3: "no such process", - 4: "interrupted system call", - 5: "input/output error", - 6: "device not configured", - 7: "argument list too long", - 8: "exec format error", - 9: "bad file descriptor", - 10: "no child processes", - 11: "resource deadlock avoided", - 12: "cannot allocate memory", - 13: "permission denied", - 14: "bad address", - 15: "block device required", - 16: "resource busy", - 17: "file exists", - 18: "cross-device link", - 19: "operation not supported by device", - 20: "not a directory", - 21: "is a directory", - 22: "invalid argument", - 23: "too many open files in system", - 24: "too many open files", - 25: "inappropriate ioctl for device", - 26: "text file busy", - 27: "file too large", - 28: "no space left on device", - 29: "illegal seek", - 30: "read-only file system", - 31: "too many links", - 32: "broken pipe", - 33: "numerical argument out of domain", - 34: "result too large", - 35: "resource temporarily unavailable", - 36: "operation now in progress", - 37: "operation already in progress", - 38: "socket operation on non-socket", - 39: "destination address required", - 40: "message too long", - 41: "protocol wrong type for socket", - 42: "protocol not available", - 43: "protocol not supported", - 44: "socket type not supported", - 45: "operation not supported", - 46: "protocol family not supported", - 47: "address family not supported by protocol family", - 48: "address already in use", - 49: "can't assign requested address", - 50: "network is down", - 51: "network is unreachable", - 52: "network dropped connection on reset", - 53: "software caused connection abort", - 54: "connection reset by peer", - 55: "no buffer space available", - 56: "socket is already connected", - 57: "socket is not connected", - 58: "can't send after socket shutdown", - 59: "too many references: can't splice", - 60: "operation timed out", - 61: "connection refused", - 62: "too many levels of symbolic links", - 63: "file name too long", - 64: "host is down", - 65: "no route to host", - 66: "directory not empty", - 67: "too many processes", - 68: "too many users", - 69: "disc quota exceeded", - 70: "stale NFS file handle", - 71: "too many levels of remote in path", - 72: "RPC struct is bad", - 73: "RPC version wrong", - 74: "RPC prog. not avail", - 75: "program version wrong", - 76: "bad procedure for program", - 77: "no locks available", - 78: "function not implemented", - 79: "inappropriate file type or format", - 80: "authentication error", - 81: "need authenticator", - 82: "device power is off", - 83: "device error", - 84: "value too large to be stored in data type", - 85: "bad executable (or shared library)", - 86: "bad CPU type in executable", - 87: "shared library version mismatch", - 88: "malformed Mach-o file", - 89: "operation canceled", - 90: "identifier removed", - 91: "no message of desired type", - 92: "illegal byte sequence", - 93: "attribute not found", - 94: "bad message", - 95: "EMULTIHOP (Reserved)", - 96: "no message available on STREAM", - 97: "ENOLINK (Reserved)", - 98: "no STREAM resources", - 99: "not a STREAM", - 100: "protocol error", - 101: "STREAM ioctl timeout", - 102: "operation not supported on socket", - 103: "policy not found", - 104: "state not recoverable", - 105: "previous owner died", - 106: "interface output queue is full", +var errorList = [...]struct { + num syscall.Errno + name string + desc string +}{ + {1, "EPERM", "operation not permitted"}, + {2, "ENOENT", "no such file or directory"}, + {3, "ESRCH", "no such process"}, + {4, "EINTR", "interrupted system call"}, + {5, "EIO", "input/output error"}, + {6, "ENXIO", "device not configured"}, + {7, "E2BIG", "argument list too long"}, + {8, "ENOEXEC", "exec format error"}, + {9, "EBADF", "bad file descriptor"}, + {10, "ECHILD", "no child processes"}, + {11, "EDEADLK", "resource deadlock avoided"}, + {12, "ENOMEM", "cannot allocate memory"}, + {13, "EACCES", "permission denied"}, + {14, "EFAULT", "bad address"}, + {15, "ENOTBLK", "block device required"}, + {16, "EBUSY", "resource busy"}, + {17, "EEXIST", "file exists"}, + {18, "EXDEV", "cross-device link"}, + {19, "ENODEV", "operation not supported by device"}, + {20, "ENOTDIR", "not a directory"}, + {21, "EISDIR", "is a directory"}, + {22, "EINVAL", "invalid argument"}, + {23, "ENFILE", "too many open files in system"}, + {24, "EMFILE", "too many open files"}, + {25, "ENOTTY", "inappropriate ioctl for device"}, + {26, "ETXTBSY", "text file busy"}, + {27, "EFBIG", "file too large"}, + {28, "ENOSPC", "no space left on device"}, + {29, "ESPIPE", "illegal seek"}, + {30, "EROFS", "read-only file system"}, + {31, "EMLINK", "too many links"}, + {32, "EPIPE", "broken pipe"}, + {33, "EDOM", "numerical argument out of domain"}, + {34, "ERANGE", "result too large"}, + {35, "EAGAIN", "resource temporarily unavailable"}, + {36, "EINPROGRESS", "operation now in progress"}, + {37, "EALREADY", "operation already in progress"}, + {38, "ENOTSOCK", "socket operation on non-socket"}, + {39, "EDESTADDRREQ", "destination address required"}, + {40, "EMSGSIZE", "message too long"}, + {41, "EPROTOTYPE", "protocol wrong type for socket"}, + {42, "ENOPROTOOPT", "protocol not available"}, + {43, "EPROTONOSUPPORT", "protocol not supported"}, + {44, "ESOCKTNOSUPPORT", "socket type not supported"}, + {45, "ENOTSUP", "operation not supported"}, + {46, "EPFNOSUPPORT", "protocol family not supported"}, + {47, "EAFNOSUPPORT", "address family not supported by protocol family"}, + {48, "EADDRINUSE", "address already in use"}, + {49, "EADDRNOTAVAIL", "can't assign requested address"}, + {50, "ENETDOWN", "network is down"}, + {51, "ENETUNREACH", "network is unreachable"}, + {52, "ENETRESET", "network dropped connection on reset"}, + {53, "ECONNABORTED", "software caused connection abort"}, + {54, "ECONNRESET", "connection reset by peer"}, + {55, "ENOBUFS", "no buffer space available"}, + {56, "EISCONN", "socket is already connected"}, + {57, "ENOTCONN", "socket is not connected"}, + {58, "ESHUTDOWN", "can't send after socket shutdown"}, + {59, "ETOOMANYREFS", "too many references: can't splice"}, + {60, "ETIMEDOUT", "operation timed out"}, + {61, "ECONNREFUSED", "connection refused"}, + {62, "ELOOP", "too many levels of symbolic links"}, + {63, "ENAMETOOLONG", "file name too long"}, + {64, "EHOSTDOWN", "host is down"}, + {65, "EHOSTUNREACH", "no route to host"}, + {66, "ENOTEMPTY", "directory not empty"}, + {67, "EPROCLIM", "too many processes"}, + {68, "EUSERS", "too many users"}, + {69, "EDQUOT", "disc quota exceeded"}, + {70, "ESTALE", "stale NFS file handle"}, + {71, "EREMOTE", "too many levels of remote in path"}, + {72, "EBADRPC", "RPC struct is bad"}, + {73, "ERPCMISMATCH", "RPC version wrong"}, + {74, "EPROGUNAVAIL", "RPC prog. not avail"}, + {75, "EPROGMISMATCH", "program version wrong"}, + {76, "EPROCUNAVAIL", "bad procedure for program"}, + {77, "ENOLCK", "no locks available"}, + {78, "ENOSYS", "function not implemented"}, + {79, "EFTYPE", "inappropriate file type or format"}, + {80, "EAUTH", "authentication error"}, + {81, "ENEEDAUTH", "need authenticator"}, + {82, "EPWROFF", "device power is off"}, + {83, "EDEVERR", "device error"}, + {84, "EOVERFLOW", "value too large to be stored in data type"}, + {85, "EBADEXEC", "bad executable (or shared library)"}, + {86, "EBADARCH", "bad CPU type in executable"}, + {87, "ESHLIBVERS", "shared library version mismatch"}, + {88, "EBADMACHO", "malformed Mach-o file"}, + {89, "ECANCELED", "operation canceled"}, + {90, "EIDRM", "identifier removed"}, + {91, "ENOMSG", "no message of desired type"}, + {92, "EILSEQ", "illegal byte sequence"}, + {93, "ENOATTR", "attribute not found"}, + {94, "EBADMSG", "bad message"}, + {95, "EMULTIHOP", "EMULTIHOP (Reserved)"}, + {96, "ENODATA", "no message available on STREAM"}, + {97, "ENOLINK", "ENOLINK (Reserved)"}, + {98, "ENOSR", "no STREAM resources"}, + {99, "ENOSTR", "not a STREAM"}, + {100, "EPROTO", "protocol error"}, + {101, "ETIME", "STREAM ioctl timeout"}, + {102, "EOPNOTSUPP", "operation not supported on socket"}, + {103, "ENOPOLICY", "policy not found"}, + {104, "ENOTRECOVERABLE", "state not recoverable"}, + {105, "EOWNERDEAD", "previous owner died"}, + {106, "EQFULL", "interface output queue is full"}, } // Signal table -var signals = [...]string{ - 1: "hangup", - 2: "interrupt", - 3: "quit", - 4: "illegal instruction", - 5: "trace/BPT trap", - 6: "abort trap", - 7: "EMT trap", - 8: "floating point exception", - 9: "killed", - 10: "bus error", - 11: "segmentation fault", - 12: "bad system call", - 13: "broken pipe", - 14: "alarm clock", - 15: "terminated", - 16: "urgent I/O condition", - 17: "suspended (signal)", - 18: "suspended", - 19: "continued", - 20: "child exited", - 21: "stopped (tty input)", - 22: "stopped (tty output)", - 23: "I/O possible", - 24: "cputime limit exceeded", - 25: "filesize limit exceeded", - 26: "virtual timer expired", - 27: "profiling timer expired", - 28: "window size changes", - 29: "information request", - 30: "user defined signal 1", - 31: "user defined signal 2", +var signalList = [...]struct { + num syscall.Signal + name string + desc string +}{ + {1, "SIGHUP", "hangup"}, + {2, "SIGINT", "interrupt"}, + {3, "SIGQUIT", "quit"}, + {4, "SIGILL", "illegal instruction"}, + {5, "SIGTRAP", "trace/BPT trap"}, + {6, "SIGABRT", "abort trap"}, + {7, "SIGEMT", "EMT trap"}, + {8, "SIGFPE", "floating point exception"}, + {9, "SIGKILL", "killed"}, + {10, "SIGBUS", "bus error"}, + {11, "SIGSEGV", "segmentation fault"}, + {12, "SIGSYS", "bad system call"}, + {13, "SIGPIPE", "broken pipe"}, + {14, "SIGALRM", "alarm clock"}, + {15, "SIGTERM", "terminated"}, + {16, "SIGURG", "urgent I/O condition"}, + {17, "SIGSTOP", "suspended (signal)"}, + {18, "SIGTSTP", "suspended"}, + {19, "SIGCONT", "continued"}, + {20, "SIGCHLD", "child exited"}, + {21, "SIGTTIN", "stopped (tty input)"}, + {22, "SIGTTOU", "stopped (tty output)"}, + {23, "SIGIO", "I/O possible"}, + {24, "SIGXCPU", "cputime limit exceeded"}, + {25, "SIGXFSZ", "filesize limit exceeded"}, + {26, "SIGVTALRM", "virtual timer expired"}, + {27, "SIGPROF", "profiling timer expired"}, + {28, "SIGWINCH", "window size changes"}, + {29, "SIGINFO", "information request"}, + {30, "SIGUSR1", "user defined signal 1"}, + {31, "SIGUSR2", "user defined signal 2"}, } diff --git a/vendor/golang.org/x/sys/unix/zerrors_dragonfly_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_dragonfly_amd64.go index 8f40598bb3..bbe6089bb7 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_dragonfly_amd64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_dragonfly_amd64.go @@ -3,7 +3,7 @@ // +build amd64,dragonfly -// Created by cgo -godefs - DO NOT EDIT +// Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs -- -m64 _const.go package unix @@ -168,6 +168,8 @@ const ( CSTOP = 0x13 CSTOPB = 0x400 CSUSP = 0x1a + CTL_HW = 0x6 + CTL_KERN = 0x1 CTL_MAXNAME = 0xc CTL_NET = 0x4 DLT_A429 = 0xb8 @@ -353,6 +355,7 @@ const ( F_UNLCK = 0x2 F_WRLCK = 0x3 HUPCL = 0x4000 + HW_MACHINE = 0x1 ICANON = 0x100 ICMP6_FILTER = 0x12 ICRNL = 0x100 @@ -835,6 +838,10 @@ const ( IXANY = 0x800 IXOFF = 0x400 IXON = 0x200 + KERN_HOSTNAME = 0xa + KERN_OSRELEASE = 0x2 + KERN_OSTYPE = 0x1 + KERN_VERSION = 0x4 LOCK_EX = 0x2 LOCK_NB = 0x4 LOCK_SH = 0x1 @@ -873,6 +880,40 @@ const ( MAP_VPAGETABLE = 0x2000 MCL_CURRENT = 0x1 MCL_FUTURE = 0x2 + MNT_ASYNC = 0x40 + MNT_AUTOMOUNTED = 0x20 + MNT_CMDFLAGS = 0xf0000 + MNT_DEFEXPORTED = 0x200 + MNT_DELEXPORT = 0x20000 + MNT_EXKERB = 0x800 + MNT_EXPORTANON = 0x400 + MNT_EXPORTED = 0x100 + MNT_EXPUBLIC = 0x20000000 + MNT_EXRDONLY = 0x80 + MNT_FORCE = 0x80000 + MNT_IGNORE = 0x800000 + MNT_LAZY = 0x4 + MNT_LOCAL = 0x1000 + MNT_NOATIME = 0x10000000 + MNT_NOCLUSTERR = 0x40000000 + MNT_NOCLUSTERW = 0x80000000 + MNT_NODEV = 0x10 + MNT_NOEXEC = 0x4 + MNT_NOSUID = 0x8 + MNT_NOSYMFOLLOW = 0x400000 + MNT_NOWAIT = 0x2 + MNT_QUOTA = 0x2000 + MNT_RDONLY = 0x1 + MNT_RELOAD = 0x40000 + MNT_ROOTFS = 0x4000 + MNT_SOFTDEP = 0x200000 + MNT_SUIDDIR = 0x100000 + MNT_SYNCHRONOUS = 0x2 + MNT_TRIM = 0x1000000 + MNT_UPDATE = 0x10000 + MNT_USER = 0x8000 + MNT_VISFLAGMASK = 0xf1f0ffff + MNT_WAIT = 0x1 MSG_CMSG_CLOEXEC = 0x1000 MSG_CTRUNC = 0x20 MSG_DONTROUTE = 0x4 @@ -973,7 +1014,10 @@ const ( RLIMIT_CPU = 0x0 RLIMIT_DATA = 0x2 RLIMIT_FSIZE = 0x1 + RLIMIT_MEMLOCK = 0x6 RLIMIT_NOFILE = 0x8 + RLIMIT_NPROC = 0x7 + RLIMIT_RSS = 0x5 RLIMIT_STACK = 0x3 RLIM_INFINITY = 0x7fffffffffffffff RTAX_AUTHOR = 0x6 @@ -1158,6 +1202,36 @@ const ( SO_TIMESTAMP = 0x400 SO_TYPE = 0x1008 SO_USELOOPBACK = 0x40 + S_BLKSIZE = 0x200 + S_IEXEC = 0x40 + S_IFBLK = 0x6000 + S_IFCHR = 0x2000 + S_IFDB = 0x9000 + S_IFDIR = 0x4000 + S_IFIFO = 0x1000 + S_IFLNK = 0xa000 + S_IFMT = 0xf000 + S_IFREG = 0x8000 + S_IFSOCK = 0xc000 + S_IFWHT = 0xe000 + S_IREAD = 0x100 + S_IRGRP = 0x20 + S_IROTH = 0x4 + S_IRUSR = 0x100 + S_IRWXG = 0x38 + S_IRWXO = 0x7 + S_IRWXU = 0x1c0 + S_ISGID = 0x400 + S_ISTXT = 0x200 + S_ISUID = 0x800 + S_ISVTX = 0x200 + S_IWGRP = 0x10 + S_IWOTH = 0x2 + S_IWRITE = 0x80 + S_IWUSR = 0x80 + S_IXGRP = 0x8 + S_IXOTH = 0x1 + S_IXUSR = 0x40 TCIFLUSH = 0x1 TCIOFF = 0x3 TCIOFLUSH = 0x3 @@ -1427,142 +1501,150 @@ const ( ) // Error table -var errors = [...]string{ - 1: "operation not permitted", - 2: "no such file or directory", - 3: "no such process", - 4: "interrupted system call", - 5: "input/output error", - 6: "device not configured", - 7: "argument list too long", - 8: "exec format error", - 9: "bad file descriptor", - 10: "no child processes", - 11: "resource deadlock avoided", - 12: "cannot allocate memory", - 13: "permission denied", - 14: "bad address", - 15: "block device required", - 16: "device busy", - 17: "file exists", - 18: "cross-device link", - 19: "operation not supported by device", - 20: "not a directory", - 21: "is a directory", - 22: "invalid argument", - 23: "too many open files in system", - 24: "too many open files", - 25: "inappropriate ioctl for device", - 26: "text file busy", - 27: "file too large", - 28: "no space left on device", - 29: "illegal seek", - 30: "read-only file system", - 31: "too many links", - 32: "broken pipe", - 33: "numerical argument out of domain", - 34: "result too large", - 35: "resource temporarily unavailable", - 36: "operation now in progress", - 37: "operation already in progress", - 38: "socket operation on non-socket", - 39: "destination address required", - 40: "message too long", - 41: "protocol wrong type for socket", - 42: "protocol not available", - 43: "protocol not supported", - 44: "socket type not supported", - 45: "operation not supported", - 46: "protocol family not supported", - 47: "address family not supported by protocol family", - 48: "address already in use", - 49: "can't assign requested address", - 50: "network is down", - 51: "network is unreachable", - 52: "network dropped connection on reset", - 53: "software caused connection abort", - 54: "connection reset by peer", - 55: "no buffer space available", - 56: "socket is already connected", - 57: "socket is not connected", - 58: "can't send after socket shutdown", - 59: "too many references: can't splice", - 60: "operation timed out", - 61: "connection refused", - 62: "too many levels of symbolic links", - 63: "file name too long", - 64: "host is down", - 65: "no route to host", - 66: "directory not empty", - 67: "too many processes", - 68: "too many users", - 69: "disc quota exceeded", - 70: "stale NFS file handle", - 71: "too many levels of remote in path", - 72: "RPC struct is bad", - 73: "RPC version wrong", - 74: "RPC prog. not avail", - 75: "program version wrong", - 76: "bad procedure for program", - 77: "no locks available", - 78: "function not implemented", - 79: "inappropriate file type or format", - 80: "authentication error", - 81: "need authenticator", - 82: "identifier removed", - 83: "no message of desired type", - 84: "value too large to be stored in data type", - 85: "operation canceled", - 86: "illegal byte sequence", - 87: "attribute not found", - 88: "programming error", - 89: "bad message", - 90: "multihop attempted", - 91: "link has been severed", - 92: "protocol error", - 93: "no medium found", - 94: "unknown error: 94", - 95: "unknown error: 95", - 96: "unknown error: 96", - 97: "unknown error: 97", - 98: "unknown error: 98", - 99: "unknown error: 99", +var errorList = [...]struct { + num syscall.Errno + name string + desc string +}{ + {1, "EPERM", "operation not permitted"}, + {2, "ENOENT", "no such file or directory"}, + {3, "ESRCH", "no such process"}, + {4, "EINTR", "interrupted system call"}, + {5, "EIO", "input/output error"}, + {6, "ENXIO", "device not configured"}, + {7, "E2BIG", "argument list too long"}, + {8, "ENOEXEC", "exec format error"}, + {9, "EBADF", "bad file descriptor"}, + {10, "ECHILD", "no child processes"}, + {11, "EDEADLK", "resource deadlock avoided"}, + {12, "ENOMEM", "cannot allocate memory"}, + {13, "EACCES", "permission denied"}, + {14, "EFAULT", "bad address"}, + {15, "ENOTBLK", "block device required"}, + {16, "EBUSY", "device busy"}, + {17, "EEXIST", "file exists"}, + {18, "EXDEV", "cross-device link"}, + {19, "ENODEV", "operation not supported by device"}, + {20, "ENOTDIR", "not a directory"}, + {21, "EISDIR", "is a directory"}, + {22, "EINVAL", "invalid argument"}, + {23, "ENFILE", "too many open files in system"}, + {24, "EMFILE", "too many open files"}, + {25, "ENOTTY", "inappropriate ioctl for device"}, + {26, "ETXTBSY", "text file busy"}, + {27, "EFBIG", "file too large"}, + {28, "ENOSPC", "no space left on device"}, + {29, "ESPIPE", "illegal seek"}, + {30, "EROFS", "read-only file system"}, + {31, "EMLINK", "too many links"}, + {32, "EPIPE", "broken pipe"}, + {33, "EDOM", "numerical argument out of domain"}, + {34, "ERANGE", "result too large"}, + {35, "EWOULDBLOCK", "resource temporarily unavailable"}, + {36, "EINPROGRESS", "operation now in progress"}, + {37, "EALREADY", "operation already in progress"}, + {38, "ENOTSOCK", "socket operation on non-socket"}, + {39, "EDESTADDRREQ", "destination address required"}, + {40, "EMSGSIZE", "message too long"}, + {41, "EPROTOTYPE", "protocol wrong type for socket"}, + {42, "ENOPROTOOPT", "protocol not available"}, + {43, "EPROTONOSUPPORT", "protocol not supported"}, + {44, "ESOCKTNOSUPPORT", "socket type not supported"}, + {45, "EOPNOTSUPP", "operation not supported"}, + {46, "EPFNOSUPPORT", "protocol family not supported"}, + {47, "EAFNOSUPPORT", "address family not supported by protocol family"}, + {48, "EADDRINUSE", "address already in use"}, + {49, "EADDRNOTAVAIL", "can't assign requested address"}, + {50, "ENETDOWN", "network is down"}, + {51, "ENETUNREACH", "network is unreachable"}, + {52, "ENETRESET", "network dropped connection on reset"}, + {53, "ECONNABORTED", "software caused connection abort"}, + {54, "ECONNRESET", "connection reset by peer"}, + {55, "ENOBUFS", "no buffer space available"}, + {56, "EISCONN", "socket is already connected"}, + {57, "ENOTCONN", "socket is not connected"}, + {58, "ESHUTDOWN", "can't send after socket shutdown"}, + {59, "ETOOMANYREFS", "too many references: can't splice"}, + {60, "ETIMEDOUT", "operation timed out"}, + {61, "ECONNREFUSED", "connection refused"}, + {62, "ELOOP", "too many levels of symbolic links"}, + {63, "ENAMETOOLONG", "file name too long"}, + {64, "EHOSTDOWN", "host is down"}, + {65, "EHOSTUNREACH", "no route to host"}, + {66, "ENOTEMPTY", "directory not empty"}, + {67, "EPROCLIM", "too many processes"}, + {68, "EUSERS", "too many users"}, + {69, "EDQUOT", "disc quota exceeded"}, + {70, "ESTALE", "stale NFS file handle"}, + {71, "EREMOTE", "too many levels of remote in path"}, + {72, "EBADRPC", "RPC struct is bad"}, + {73, "ERPCMISMATCH", "RPC version wrong"}, + {74, "EPROGUNAVAIL", "RPC prog. not avail"}, + {75, "EPROGMISMATCH", "program version wrong"}, + {76, "EPROCUNAVAIL", "bad procedure for program"}, + {77, "ENOLCK", "no locks available"}, + {78, "ENOSYS", "function not implemented"}, + {79, "EFTYPE", "inappropriate file type or format"}, + {80, "EAUTH", "authentication error"}, + {81, "ENEEDAUTH", "need authenticator"}, + {82, "EIDRM", "identifier removed"}, + {83, "ENOMSG", "no message of desired type"}, + {84, "EOVERFLOW", "value too large to be stored in data type"}, + {85, "ECANCELED", "operation canceled"}, + {86, "EILSEQ", "illegal byte sequence"}, + {87, "ENOATTR", "attribute not found"}, + {88, "EDOOFUS", "programming error"}, + {89, "EBADMSG", "bad message"}, + {90, "EMULTIHOP", "multihop attempted"}, + {91, "ENOLINK", "link has been severed"}, + {92, "EPROTO", "protocol error"}, + {93, "ENOMEDIUM", "no medium found"}, + {94, "EUNUSED94", "unknown error: 94"}, + {95, "EUNUSED95", "unknown error: 95"}, + {96, "EUNUSED96", "unknown error: 96"}, + {97, "EUNUSED97", "unknown error: 97"}, + {98, "EUNUSED98", "unknown error: 98"}, + {99, "ELAST", "unknown error: 99"}, } // Signal table -var signals = [...]string{ - 1: "hangup", - 2: "interrupt", - 3: "quit", - 4: "illegal instruction", - 5: "trace/BPT trap", - 6: "abort trap", - 7: "EMT trap", - 8: "floating point exception", - 9: "killed", - 10: "bus error", - 11: "segmentation fault", - 12: "bad system call", - 13: "broken pipe", - 14: "alarm clock", - 15: "terminated", - 16: "urgent I/O condition", - 17: "suspended (signal)", - 18: "suspended", - 19: "continued", - 20: "child exited", - 21: "stopped (tty input)", - 22: "stopped (tty output)", - 23: "I/O possible", - 24: "cputime limit exceeded", - 25: "filesize limit exceeded", - 26: "virtual timer expired", - 27: "profiling timer expired", - 28: "window size changes", - 29: "information request", - 30: "user defined signal 1", - 31: "user defined signal 2", - 32: "thread Scheduler", - 33: "checkPoint", - 34: "checkPointExit", +var signalList = [...]struct { + num syscall.Signal + name string + desc string +}{ + {1, "SIGHUP", "hangup"}, + {2, "SIGINT", "interrupt"}, + {3, "SIGQUIT", "quit"}, + {4, "SIGILL", "illegal instruction"}, + {5, "SIGTRAP", "trace/BPT trap"}, + {6, "SIGIOT", "abort trap"}, + {7, "SIGEMT", "EMT trap"}, + {8, "SIGFPE", "floating point exception"}, + {9, "SIGKILL", "killed"}, + {10, "SIGBUS", "bus error"}, + {11, "SIGSEGV", "segmentation fault"}, + {12, "SIGSYS", "bad system call"}, + {13, "SIGPIPE", "broken pipe"}, + {14, "SIGALRM", "alarm clock"}, + {15, "SIGTERM", "terminated"}, + {16, "SIGURG", "urgent I/O condition"}, + {17, "SIGSTOP", "suspended (signal)"}, + {18, "SIGTSTP", "suspended"}, + {19, "SIGCONT", "continued"}, + {20, "SIGCHLD", "child exited"}, + {21, "SIGTTIN", "stopped (tty input)"}, + {22, "SIGTTOU", "stopped (tty output)"}, + {23, "SIGIO", "I/O possible"}, + {24, "SIGXCPU", "cputime limit exceeded"}, + {25, "SIGXFSZ", "filesize limit exceeded"}, + {26, "SIGVTALRM", "virtual timer expired"}, + {27, "SIGPROF", "profiling timer expired"}, + {28, "SIGWINCH", "window size changes"}, + {29, "SIGINFO", "information request"}, + {30, "SIGUSR1", "user defined signal 1"}, + {31, "SIGUSR2", "user defined signal 2"}, + {32, "SIGTHR", "thread Scheduler"}, + {33, "SIGCKPT", "checkPoint"}, + {34, "SIGCKPTEXIT", "checkPointExit"}, } diff --git a/vendor/golang.org/x/sys/unix/zerrors_freebsd_386.go b/vendor/golang.org/x/sys/unix/zerrors_freebsd_386.go index adf5eef0f8..d2bbaabc87 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_freebsd_386.go +++ b/vendor/golang.org/x/sys/unix/zerrors_freebsd_386.go @@ -351,6 +351,8 @@ const ( CSTOP = 0x13 CSTOPB = 0x400 CSUSP = 0x1a + CTL_HW = 0x6 + CTL_KERN = 0x1 CTL_MAXNAME = 0x18 CTL_NET = 0x4 DLT_A429 = 0xb8 @@ -608,6 +610,7 @@ const ( F_UNLCKSYS = 0x4 F_WRLCK = 0x3 HUPCL = 0x4000 + HW_MACHINE = 0x1 ICANON = 0x100 ICMP6_FILTER = 0x12 ICRNL = 0x100 @@ -944,6 +947,10 @@ const ( IXANY = 0x800 IXOFF = 0x400 IXON = 0x200 + KERN_HOSTNAME = 0xa + KERN_OSRELEASE = 0x2 + KERN_OSTYPE = 0x1 + KERN_VERSION = 0x4 LOCK_EX = 0x2 LOCK_NB = 0x4 LOCK_SH = 0x1 @@ -1338,6 +1345,35 @@ const ( SO_USELOOPBACK = 0x40 SO_USER_COOKIE = 0x1015 SO_VENDOR = 0x80000000 + S_BLKSIZE = 0x200 + S_IEXEC = 0x40 + S_IFBLK = 0x6000 + S_IFCHR = 0x2000 + S_IFDIR = 0x4000 + S_IFIFO = 0x1000 + S_IFLNK = 0xa000 + S_IFMT = 0xf000 + S_IFREG = 0x8000 + S_IFSOCK = 0xc000 + S_IFWHT = 0xe000 + S_IREAD = 0x100 + S_IRGRP = 0x20 + S_IROTH = 0x4 + S_IRUSR = 0x100 + S_IRWXG = 0x38 + S_IRWXO = 0x7 + S_IRWXU = 0x1c0 + S_ISGID = 0x400 + S_ISTXT = 0x200 + S_ISUID = 0x800 + S_ISVTX = 0x200 + S_IWGRP = 0x10 + S_IWOTH = 0x2 + S_IWRITE = 0x80 + S_IWUSR = 0x80 + S_IXGRP = 0x8 + S_IXOTH = 0x1 + S_IXUSR = 0x40 TAB0 = 0x0 TAB3 = 0x4 TABDLY = 0x4 @@ -1612,138 +1648,146 @@ const ( ) // Error table -var errors = [...]string{ - 1: "operation not permitted", - 2: "no such file or directory", - 3: "no such process", - 4: "interrupted system call", - 5: "input/output error", - 6: "device not configured", - 7: "argument list too long", - 8: "exec format error", - 9: "bad file descriptor", - 10: "no child processes", - 11: "resource deadlock avoided", - 12: "cannot allocate memory", - 13: "permission denied", - 14: "bad address", - 15: "block device required", - 16: "device busy", - 17: "file exists", - 18: "cross-device link", - 19: "operation not supported by device", - 20: "not a directory", - 21: "is a directory", - 22: "invalid argument", - 23: "too many open files in system", - 24: "too many open files", - 25: "inappropriate ioctl for device", - 26: "text file busy", - 27: "file too large", - 28: "no space left on device", - 29: "illegal seek", - 30: "read-only file system", - 31: "too many links", - 32: "broken pipe", - 33: "numerical argument out of domain", - 34: "result too large", - 35: "resource temporarily unavailable", - 36: "operation now in progress", - 37: "operation already in progress", - 38: "socket operation on non-socket", - 39: "destination address required", - 40: "message too long", - 41: "protocol wrong type for socket", - 42: "protocol not available", - 43: "protocol not supported", - 44: "socket type not supported", - 45: "operation not supported", - 46: "protocol family not supported", - 47: "address family not supported by protocol family", - 48: "address already in use", - 49: "can't assign requested address", - 50: "network is down", - 51: "network is unreachable", - 52: "network dropped connection on reset", - 53: "software caused connection abort", - 54: "connection reset by peer", - 55: "no buffer space available", - 56: "socket is already connected", - 57: "socket is not connected", - 58: "can't send after socket shutdown", - 59: "too many references: can't splice", - 60: "operation timed out", - 61: "connection refused", - 62: "too many levels of symbolic links", - 63: "file name too long", - 64: "host is down", - 65: "no route to host", - 66: "directory not empty", - 67: "too many processes", - 68: "too many users", - 69: "disc quota exceeded", - 70: "stale NFS file handle", - 71: "too many levels of remote in path", - 72: "RPC struct is bad", - 73: "RPC version wrong", - 74: "RPC prog. not avail", - 75: "program version wrong", - 76: "bad procedure for program", - 77: "no locks available", - 78: "function not implemented", - 79: "inappropriate file type or format", - 80: "authentication error", - 81: "need authenticator", - 82: "identifier removed", - 83: "no message of desired type", - 84: "value too large to be stored in data type", - 85: "operation canceled", - 86: "illegal byte sequence", - 87: "attribute not found", - 88: "programming error", - 89: "bad message", - 90: "multihop attempted", - 91: "link has been severed", - 92: "protocol error", - 93: "capabilities insufficient", - 94: "not permitted in capability mode", - 95: "state not recoverable", - 96: "previous owner died", +var errorList = [...]struct { + num syscall.Errno + name string + desc string +}{ + {1, "EPERM", "operation not permitted"}, + {2, "ENOENT", "no such file or directory"}, + {3, "ESRCH", "no such process"}, + {4, "EINTR", "interrupted system call"}, + {5, "EIO", "input/output error"}, + {6, "ENXIO", "device not configured"}, + {7, "E2BIG", "argument list too long"}, + {8, "ENOEXEC", "exec format error"}, + {9, "EBADF", "bad file descriptor"}, + {10, "ECHILD", "no child processes"}, + {11, "EDEADLK", "resource deadlock avoided"}, + {12, "ENOMEM", "cannot allocate memory"}, + {13, "EACCES", "permission denied"}, + {14, "EFAULT", "bad address"}, + {15, "ENOTBLK", "block device required"}, + {16, "EBUSY", "device busy"}, + {17, "EEXIST", "file exists"}, + {18, "EXDEV", "cross-device link"}, + {19, "ENODEV", "operation not supported by device"}, + {20, "ENOTDIR", "not a directory"}, + {21, "EISDIR", "is a directory"}, + {22, "EINVAL", "invalid argument"}, + {23, "ENFILE", "too many open files in system"}, + {24, "EMFILE", "too many open files"}, + {25, "ENOTTY", "inappropriate ioctl for device"}, + {26, "ETXTBSY", "text file busy"}, + {27, "EFBIG", "file too large"}, + {28, "ENOSPC", "no space left on device"}, + {29, "ESPIPE", "illegal seek"}, + {30, "EROFS", "read-only file system"}, + {31, "EMLINK", "too many links"}, + {32, "EPIPE", "broken pipe"}, + {33, "EDOM", "numerical argument out of domain"}, + {34, "ERANGE", "result too large"}, + {35, "EAGAIN", "resource temporarily unavailable"}, + {36, "EINPROGRESS", "operation now in progress"}, + {37, "EALREADY", "operation already in progress"}, + {38, "ENOTSOCK", "socket operation on non-socket"}, + {39, "EDESTADDRREQ", "destination address required"}, + {40, "EMSGSIZE", "message too long"}, + {41, "EPROTOTYPE", "protocol wrong type for socket"}, + {42, "ENOPROTOOPT", "protocol not available"}, + {43, "EPROTONOSUPPORT", "protocol not supported"}, + {44, "ESOCKTNOSUPPORT", "socket type not supported"}, + {45, "EOPNOTSUPP", "operation not supported"}, + {46, "EPFNOSUPPORT", "protocol family not supported"}, + {47, "EAFNOSUPPORT", "address family not supported by protocol family"}, + {48, "EADDRINUSE", "address already in use"}, + {49, "EADDRNOTAVAIL", "can't assign requested address"}, + {50, "ENETDOWN", "network is down"}, + {51, "ENETUNREACH", "network is unreachable"}, + {52, "ENETRESET", "network dropped connection on reset"}, + {53, "ECONNABORTED", "software caused connection abort"}, + {54, "ECONNRESET", "connection reset by peer"}, + {55, "ENOBUFS", "no buffer space available"}, + {56, "EISCONN", "socket is already connected"}, + {57, "ENOTCONN", "socket is not connected"}, + {58, "ESHUTDOWN", "can't send after socket shutdown"}, + {59, "ETOOMANYREFS", "too many references: can't splice"}, + {60, "ETIMEDOUT", "operation timed out"}, + {61, "ECONNREFUSED", "connection refused"}, + {62, "ELOOP", "too many levels of symbolic links"}, + {63, "ENAMETOOLONG", "file name too long"}, + {64, "EHOSTDOWN", "host is down"}, + {65, "EHOSTUNREACH", "no route to host"}, + {66, "ENOTEMPTY", "directory not empty"}, + {67, "EPROCLIM", "too many processes"}, + {68, "EUSERS", "too many users"}, + {69, "EDQUOT", "disc quota exceeded"}, + {70, "ESTALE", "stale NFS file handle"}, + {71, "EREMOTE", "too many levels of remote in path"}, + {72, "EBADRPC", "RPC struct is bad"}, + {73, "ERPCMISMATCH", "RPC version wrong"}, + {74, "EPROGUNAVAIL", "RPC prog. not avail"}, + {75, "EPROGMISMATCH", "program version wrong"}, + {76, "EPROCUNAVAIL", "bad procedure for program"}, + {77, "ENOLCK", "no locks available"}, + {78, "ENOSYS", "function not implemented"}, + {79, "EFTYPE", "inappropriate file type or format"}, + {80, "EAUTH", "authentication error"}, + {81, "ENEEDAUTH", "need authenticator"}, + {82, "EIDRM", "identifier removed"}, + {83, "ENOMSG", "no message of desired type"}, + {84, "EOVERFLOW", "value too large to be stored in data type"}, + {85, "ECANCELED", "operation canceled"}, + {86, "EILSEQ", "illegal byte sequence"}, + {87, "ENOATTR", "attribute not found"}, + {88, "EDOOFUS", "programming error"}, + {89, "EBADMSG", "bad message"}, + {90, "EMULTIHOP", "multihop attempted"}, + {91, "ENOLINK", "link has been severed"}, + {92, "EPROTO", "protocol error"}, + {93, "ENOTCAPABLE", "capabilities insufficient"}, + {94, "ECAPMODE", "not permitted in capability mode"}, + {95, "ENOTRECOVERABLE", "state not recoverable"}, + {96, "EOWNERDEAD", "previous owner died"}, } // Signal table -var signals = [...]string{ - 1: "hangup", - 2: "interrupt", - 3: "quit", - 4: "illegal instruction", - 5: "trace/BPT trap", - 6: "abort trap", - 7: "EMT trap", - 8: "floating point exception", - 9: "killed", - 10: "bus error", - 11: "segmentation fault", - 12: "bad system call", - 13: "broken pipe", - 14: "alarm clock", - 15: "terminated", - 16: "urgent I/O condition", - 17: "suspended (signal)", - 18: "suspended", - 19: "continued", - 20: "child exited", - 21: "stopped (tty input)", - 22: "stopped (tty output)", - 23: "I/O possible", - 24: "cputime limit exceeded", - 25: "filesize limit exceeded", - 26: "virtual timer expired", - 27: "profiling timer expired", - 28: "window size changes", - 29: "information request", - 30: "user defined signal 1", - 31: "user defined signal 2", - 32: "unknown signal", - 33: "unknown signal", +var signalList = [...]struct { + num syscall.Signal + name string + desc string +}{ + {1, "SIGHUP", "hangup"}, + {2, "SIGINT", "interrupt"}, + {3, "SIGQUIT", "quit"}, + {4, "SIGILL", "illegal instruction"}, + {5, "SIGTRAP", "trace/BPT trap"}, + {6, "SIGIOT", "abort trap"}, + {7, "SIGEMT", "EMT trap"}, + {8, "SIGFPE", "floating point exception"}, + {9, "SIGKILL", "killed"}, + {10, "SIGBUS", "bus error"}, + {11, "SIGSEGV", "segmentation fault"}, + {12, "SIGSYS", "bad system call"}, + {13, "SIGPIPE", "broken pipe"}, + {14, "SIGALRM", "alarm clock"}, + {15, "SIGTERM", "terminated"}, + {16, "SIGURG", "urgent I/O condition"}, + {17, "SIGSTOP", "suspended (signal)"}, + {18, "SIGTSTP", "suspended"}, + {19, "SIGCONT", "continued"}, + {20, "SIGCHLD", "child exited"}, + {21, "SIGTTIN", "stopped (tty input)"}, + {22, "SIGTTOU", "stopped (tty output)"}, + {23, "SIGIO", "I/O possible"}, + {24, "SIGXCPU", "cputime limit exceeded"}, + {25, "SIGXFSZ", "filesize limit exceeded"}, + {26, "SIGVTALRM", "virtual timer expired"}, + {27, "SIGPROF", "profiling timer expired"}, + {28, "SIGWINCH", "window size changes"}, + {29, "SIGINFO", "information request"}, + {30, "SIGUSR1", "user defined signal 1"}, + {31, "SIGUSR2", "user defined signal 2"}, + {32, "SIGTHR", "unknown signal"}, + {33, "SIGLIBRT", "unknown signal"}, } diff --git a/vendor/golang.org/x/sys/unix/zerrors_freebsd_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_freebsd_amd64.go index 360caff4f9..4f8db783d3 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_freebsd_amd64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_freebsd_amd64.go @@ -351,6 +351,8 @@ const ( CSTOP = 0x13 CSTOPB = 0x400 CSUSP = 0x1a + CTL_HW = 0x6 + CTL_KERN = 0x1 CTL_MAXNAME = 0x18 CTL_NET = 0x4 DLT_A429 = 0xb8 @@ -608,6 +610,7 @@ const ( F_UNLCKSYS = 0x4 F_WRLCK = 0x3 HUPCL = 0x4000 + HW_MACHINE = 0x1 ICANON = 0x100 ICMP6_FILTER = 0x12 ICRNL = 0x100 @@ -944,6 +947,10 @@ const ( IXANY = 0x800 IXOFF = 0x400 IXON = 0x200 + KERN_HOSTNAME = 0xa + KERN_OSRELEASE = 0x2 + KERN_OSTYPE = 0x1 + KERN_VERSION = 0x4 LOCK_EX = 0x2 LOCK_NB = 0x4 LOCK_SH = 0x1 @@ -1339,6 +1346,35 @@ const ( SO_USELOOPBACK = 0x40 SO_USER_COOKIE = 0x1015 SO_VENDOR = 0x80000000 + S_BLKSIZE = 0x200 + S_IEXEC = 0x40 + S_IFBLK = 0x6000 + S_IFCHR = 0x2000 + S_IFDIR = 0x4000 + S_IFIFO = 0x1000 + S_IFLNK = 0xa000 + S_IFMT = 0xf000 + S_IFREG = 0x8000 + S_IFSOCK = 0xc000 + S_IFWHT = 0xe000 + S_IREAD = 0x100 + S_IRGRP = 0x20 + S_IROTH = 0x4 + S_IRUSR = 0x100 + S_IRWXG = 0x38 + S_IRWXO = 0x7 + S_IRWXU = 0x1c0 + S_ISGID = 0x400 + S_ISTXT = 0x200 + S_ISUID = 0x800 + S_ISVTX = 0x200 + S_IWGRP = 0x10 + S_IWOTH = 0x2 + S_IWRITE = 0x80 + S_IWUSR = 0x80 + S_IXGRP = 0x8 + S_IXOTH = 0x1 + S_IXUSR = 0x40 TAB0 = 0x0 TAB3 = 0x4 TABDLY = 0x4 @@ -1613,138 +1649,146 @@ const ( ) // Error table -var errors = [...]string{ - 1: "operation not permitted", - 2: "no such file or directory", - 3: "no such process", - 4: "interrupted system call", - 5: "input/output error", - 6: "device not configured", - 7: "argument list too long", - 8: "exec format error", - 9: "bad file descriptor", - 10: "no child processes", - 11: "resource deadlock avoided", - 12: "cannot allocate memory", - 13: "permission denied", - 14: "bad address", - 15: "block device required", - 16: "device busy", - 17: "file exists", - 18: "cross-device link", - 19: "operation not supported by device", - 20: "not a directory", - 21: "is a directory", - 22: "invalid argument", - 23: "too many open files in system", - 24: "too many open files", - 25: "inappropriate ioctl for device", - 26: "text file busy", - 27: "file too large", - 28: "no space left on device", - 29: "illegal seek", - 30: "read-only file system", - 31: "too many links", - 32: "broken pipe", - 33: "numerical argument out of domain", - 34: "result too large", - 35: "resource temporarily unavailable", - 36: "operation now in progress", - 37: "operation already in progress", - 38: "socket operation on non-socket", - 39: "destination address required", - 40: "message too long", - 41: "protocol wrong type for socket", - 42: "protocol not available", - 43: "protocol not supported", - 44: "socket type not supported", - 45: "operation not supported", - 46: "protocol family not supported", - 47: "address family not supported by protocol family", - 48: "address already in use", - 49: "can't assign requested address", - 50: "network is down", - 51: "network is unreachable", - 52: "network dropped connection on reset", - 53: "software caused connection abort", - 54: "connection reset by peer", - 55: "no buffer space available", - 56: "socket is already connected", - 57: "socket is not connected", - 58: "can't send after socket shutdown", - 59: "too many references: can't splice", - 60: "operation timed out", - 61: "connection refused", - 62: "too many levels of symbolic links", - 63: "file name too long", - 64: "host is down", - 65: "no route to host", - 66: "directory not empty", - 67: "too many processes", - 68: "too many users", - 69: "disc quota exceeded", - 70: "stale NFS file handle", - 71: "too many levels of remote in path", - 72: "RPC struct is bad", - 73: "RPC version wrong", - 74: "RPC prog. not avail", - 75: "program version wrong", - 76: "bad procedure for program", - 77: "no locks available", - 78: "function not implemented", - 79: "inappropriate file type or format", - 80: "authentication error", - 81: "need authenticator", - 82: "identifier removed", - 83: "no message of desired type", - 84: "value too large to be stored in data type", - 85: "operation canceled", - 86: "illegal byte sequence", - 87: "attribute not found", - 88: "programming error", - 89: "bad message", - 90: "multihop attempted", - 91: "link has been severed", - 92: "protocol error", - 93: "capabilities insufficient", - 94: "not permitted in capability mode", - 95: "state not recoverable", - 96: "previous owner died", +var errorList = [...]struct { + num syscall.Errno + name string + desc string +}{ + {1, "EPERM", "operation not permitted"}, + {2, "ENOENT", "no such file or directory"}, + {3, "ESRCH", "no such process"}, + {4, "EINTR", "interrupted system call"}, + {5, "EIO", "input/output error"}, + {6, "ENXIO", "device not configured"}, + {7, "E2BIG", "argument list too long"}, + {8, "ENOEXEC", "exec format error"}, + {9, "EBADF", "bad file descriptor"}, + {10, "ECHILD", "no child processes"}, + {11, "EDEADLK", "resource deadlock avoided"}, + {12, "ENOMEM", "cannot allocate memory"}, + {13, "EACCES", "permission denied"}, + {14, "EFAULT", "bad address"}, + {15, "ENOTBLK", "block device required"}, + {16, "EBUSY", "device busy"}, + {17, "EEXIST", "file exists"}, + {18, "EXDEV", "cross-device link"}, + {19, "ENODEV", "operation not supported by device"}, + {20, "ENOTDIR", "not a directory"}, + {21, "EISDIR", "is a directory"}, + {22, "EINVAL", "invalid argument"}, + {23, "ENFILE", "too many open files in system"}, + {24, "EMFILE", "too many open files"}, + {25, "ENOTTY", "inappropriate ioctl for device"}, + {26, "ETXTBSY", "text file busy"}, + {27, "EFBIG", "file too large"}, + {28, "ENOSPC", "no space left on device"}, + {29, "ESPIPE", "illegal seek"}, + {30, "EROFS", "read-only file system"}, + {31, "EMLINK", "too many links"}, + {32, "EPIPE", "broken pipe"}, + {33, "EDOM", "numerical argument out of domain"}, + {34, "ERANGE", "result too large"}, + {35, "EAGAIN", "resource temporarily unavailable"}, + {36, "EINPROGRESS", "operation now in progress"}, + {37, "EALREADY", "operation already in progress"}, + {38, "ENOTSOCK", "socket operation on non-socket"}, + {39, "EDESTADDRREQ", "destination address required"}, + {40, "EMSGSIZE", "message too long"}, + {41, "EPROTOTYPE", "protocol wrong type for socket"}, + {42, "ENOPROTOOPT", "protocol not available"}, + {43, "EPROTONOSUPPORT", "protocol not supported"}, + {44, "ESOCKTNOSUPPORT", "socket type not supported"}, + {45, "EOPNOTSUPP", "operation not supported"}, + {46, "EPFNOSUPPORT", "protocol family not supported"}, + {47, "EAFNOSUPPORT", "address family not supported by protocol family"}, + {48, "EADDRINUSE", "address already in use"}, + {49, "EADDRNOTAVAIL", "can't assign requested address"}, + {50, "ENETDOWN", "network is down"}, + {51, "ENETUNREACH", "network is unreachable"}, + {52, "ENETRESET", "network dropped connection on reset"}, + {53, "ECONNABORTED", "software caused connection abort"}, + {54, "ECONNRESET", "connection reset by peer"}, + {55, "ENOBUFS", "no buffer space available"}, + {56, "EISCONN", "socket is already connected"}, + {57, "ENOTCONN", "socket is not connected"}, + {58, "ESHUTDOWN", "can't send after socket shutdown"}, + {59, "ETOOMANYREFS", "too many references: can't splice"}, + {60, "ETIMEDOUT", "operation timed out"}, + {61, "ECONNREFUSED", "connection refused"}, + {62, "ELOOP", "too many levels of symbolic links"}, + {63, "ENAMETOOLONG", "file name too long"}, + {64, "EHOSTDOWN", "host is down"}, + {65, "EHOSTUNREACH", "no route to host"}, + {66, "ENOTEMPTY", "directory not empty"}, + {67, "EPROCLIM", "too many processes"}, + {68, "EUSERS", "too many users"}, + {69, "EDQUOT", "disc quota exceeded"}, + {70, "ESTALE", "stale NFS file handle"}, + {71, "EREMOTE", "too many levels of remote in path"}, + {72, "EBADRPC", "RPC struct is bad"}, + {73, "ERPCMISMATCH", "RPC version wrong"}, + {74, "EPROGUNAVAIL", "RPC prog. not avail"}, + {75, "EPROGMISMATCH", "program version wrong"}, + {76, "EPROCUNAVAIL", "bad procedure for program"}, + {77, "ENOLCK", "no locks available"}, + {78, "ENOSYS", "function not implemented"}, + {79, "EFTYPE", "inappropriate file type or format"}, + {80, "EAUTH", "authentication error"}, + {81, "ENEEDAUTH", "need authenticator"}, + {82, "EIDRM", "identifier removed"}, + {83, "ENOMSG", "no message of desired type"}, + {84, "EOVERFLOW", "value too large to be stored in data type"}, + {85, "ECANCELED", "operation canceled"}, + {86, "EILSEQ", "illegal byte sequence"}, + {87, "ENOATTR", "attribute not found"}, + {88, "EDOOFUS", "programming error"}, + {89, "EBADMSG", "bad message"}, + {90, "EMULTIHOP", "multihop attempted"}, + {91, "ENOLINK", "link has been severed"}, + {92, "EPROTO", "protocol error"}, + {93, "ENOTCAPABLE", "capabilities insufficient"}, + {94, "ECAPMODE", "not permitted in capability mode"}, + {95, "ENOTRECOVERABLE", "state not recoverable"}, + {96, "EOWNERDEAD", "previous owner died"}, } // Signal table -var signals = [...]string{ - 1: "hangup", - 2: "interrupt", - 3: "quit", - 4: "illegal instruction", - 5: "trace/BPT trap", - 6: "abort trap", - 7: "EMT trap", - 8: "floating point exception", - 9: "killed", - 10: "bus error", - 11: "segmentation fault", - 12: "bad system call", - 13: "broken pipe", - 14: "alarm clock", - 15: "terminated", - 16: "urgent I/O condition", - 17: "suspended (signal)", - 18: "suspended", - 19: "continued", - 20: "child exited", - 21: "stopped (tty input)", - 22: "stopped (tty output)", - 23: "I/O possible", - 24: "cputime limit exceeded", - 25: "filesize limit exceeded", - 26: "virtual timer expired", - 27: "profiling timer expired", - 28: "window size changes", - 29: "information request", - 30: "user defined signal 1", - 31: "user defined signal 2", - 32: "unknown signal", - 33: "unknown signal", +var signalList = [...]struct { + num syscall.Signal + name string + desc string +}{ + {1, "SIGHUP", "hangup"}, + {2, "SIGINT", "interrupt"}, + {3, "SIGQUIT", "quit"}, + {4, "SIGILL", "illegal instruction"}, + {5, "SIGTRAP", "trace/BPT trap"}, + {6, "SIGIOT", "abort trap"}, + {7, "SIGEMT", "EMT trap"}, + {8, "SIGFPE", "floating point exception"}, + {9, "SIGKILL", "killed"}, + {10, "SIGBUS", "bus error"}, + {11, "SIGSEGV", "segmentation fault"}, + {12, "SIGSYS", "bad system call"}, + {13, "SIGPIPE", "broken pipe"}, + {14, "SIGALRM", "alarm clock"}, + {15, "SIGTERM", "terminated"}, + {16, "SIGURG", "urgent I/O condition"}, + {17, "SIGSTOP", "suspended (signal)"}, + {18, "SIGTSTP", "suspended"}, + {19, "SIGCONT", "continued"}, + {20, "SIGCHLD", "child exited"}, + {21, "SIGTTIN", "stopped (tty input)"}, + {22, "SIGTTOU", "stopped (tty output)"}, + {23, "SIGIO", "I/O possible"}, + {24, "SIGXCPU", "cputime limit exceeded"}, + {25, "SIGXFSZ", "filesize limit exceeded"}, + {26, "SIGVTALRM", "virtual timer expired"}, + {27, "SIGPROF", "profiling timer expired"}, + {28, "SIGWINCH", "window size changes"}, + {29, "SIGINFO", "information request"}, + {30, "SIGUSR1", "user defined signal 1"}, + {31, "SIGUSR2", "user defined signal 2"}, + {32, "SIGTHR", "unknown signal"}, + {33, "SIGLIBRT", "unknown signal"}, } diff --git a/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go b/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go index 87deda950e..53e5de6051 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go +++ b/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go @@ -351,6 +351,8 @@ const ( CSTOP = 0x13 CSTOPB = 0x400 CSUSP = 0x1a + CTL_HW = 0x6 + CTL_KERN = 0x1 CTL_MAXNAME = 0x18 CTL_NET = 0x4 DLT_A429 = 0xb8 @@ -615,6 +617,7 @@ const ( F_UNLCKSYS = 0x4 F_WRLCK = 0x3 HUPCL = 0x4000 + HW_MACHINE = 0x1 ICANON = 0x100 ICMP6_FILTER = 0x12 ICRNL = 0x100 @@ -951,6 +954,10 @@ const ( IXANY = 0x800 IXOFF = 0x400 IXON = 0x200 + KERN_HOSTNAME = 0xa + KERN_OSRELEASE = 0x2 + KERN_OSTYPE = 0x1 + KERN_VERSION = 0x4 LOCK_EX = 0x2 LOCK_NB = 0x4 LOCK_SH = 0x1 @@ -1347,6 +1354,35 @@ const ( SO_USELOOPBACK = 0x40 SO_USER_COOKIE = 0x1015 SO_VENDOR = 0x80000000 + S_BLKSIZE = 0x200 + S_IEXEC = 0x40 + S_IFBLK = 0x6000 + S_IFCHR = 0x2000 + S_IFDIR = 0x4000 + S_IFIFO = 0x1000 + S_IFLNK = 0xa000 + S_IFMT = 0xf000 + S_IFREG = 0x8000 + S_IFSOCK = 0xc000 + S_IFWHT = 0xe000 + S_IREAD = 0x100 + S_IRGRP = 0x20 + S_IROTH = 0x4 + S_IRUSR = 0x100 + S_IRWXG = 0x38 + S_IRWXO = 0x7 + S_IRWXU = 0x1c0 + S_ISGID = 0x400 + S_ISTXT = 0x200 + S_ISUID = 0x800 + S_ISVTX = 0x200 + S_IWGRP = 0x10 + S_IWOTH = 0x2 + S_IWRITE = 0x80 + S_IWUSR = 0x80 + S_IXGRP = 0x8 + S_IXOTH = 0x1 + S_IXUSR = 0x40 TAB0 = 0x0 TAB3 = 0x4 TABDLY = 0x4 @@ -1621,138 +1657,146 @@ const ( ) // Error table -var errors = [...]string{ - 1: "operation not permitted", - 2: "no such file or directory", - 3: "no such process", - 4: "interrupted system call", - 5: "input/output error", - 6: "device not configured", - 7: "argument list too long", - 8: "exec format error", - 9: "bad file descriptor", - 10: "no child processes", - 11: "resource deadlock avoided", - 12: "cannot allocate memory", - 13: "permission denied", - 14: "bad address", - 15: "block device required", - 16: "device busy", - 17: "file exists", - 18: "cross-device link", - 19: "operation not supported by device", - 20: "not a directory", - 21: "is a directory", - 22: "invalid argument", - 23: "too many open files in system", - 24: "too many open files", - 25: "inappropriate ioctl for device", - 26: "text file busy", - 27: "file too large", - 28: "no space left on device", - 29: "illegal seek", - 30: "read-only file system", - 31: "too many links", - 32: "broken pipe", - 33: "numerical argument out of domain", - 34: "result too large", - 35: "resource temporarily unavailable", - 36: "operation now in progress", - 37: "operation already in progress", - 38: "socket operation on non-socket", - 39: "destination address required", - 40: "message too long", - 41: "protocol wrong type for socket", - 42: "protocol not available", - 43: "protocol not supported", - 44: "socket type not supported", - 45: "operation not supported", - 46: "protocol family not supported", - 47: "address family not supported by protocol family", - 48: "address already in use", - 49: "can't assign requested address", - 50: "network is down", - 51: "network is unreachable", - 52: "network dropped connection on reset", - 53: "software caused connection abort", - 54: "connection reset by peer", - 55: "no buffer space available", - 56: "socket is already connected", - 57: "socket is not connected", - 58: "can't send after socket shutdown", - 59: "too many references: can't splice", - 60: "operation timed out", - 61: "connection refused", - 62: "too many levels of symbolic links", - 63: "file name too long", - 64: "host is down", - 65: "no route to host", - 66: "directory not empty", - 67: "too many processes", - 68: "too many users", - 69: "disc quota exceeded", - 70: "stale NFS file handle", - 71: "too many levels of remote in path", - 72: "RPC struct is bad", - 73: "RPC version wrong", - 74: "RPC prog. not avail", - 75: "program version wrong", - 76: "bad procedure for program", - 77: "no locks available", - 78: "function not implemented", - 79: "inappropriate file type or format", - 80: "authentication error", - 81: "need authenticator", - 82: "identifier removed", - 83: "no message of desired type", - 84: "value too large to be stored in data type", - 85: "operation canceled", - 86: "illegal byte sequence", - 87: "attribute not found", - 88: "programming error", - 89: "bad message", - 90: "multihop attempted", - 91: "link has been severed", - 92: "protocol error", - 93: "capabilities insufficient", - 94: "not permitted in capability mode", - 95: "state not recoverable", - 96: "previous owner died", +var errorList = [...]struct { + num syscall.Errno + name string + desc string +}{ + {1, "EPERM", "operation not permitted"}, + {2, "ENOENT", "no such file or directory"}, + {3, "ESRCH", "no such process"}, + {4, "EINTR", "interrupted system call"}, + {5, "EIO", "input/output error"}, + {6, "ENXIO", "device not configured"}, + {7, "E2BIG", "argument list too long"}, + {8, "ENOEXEC", "exec format error"}, + {9, "EBADF", "bad file descriptor"}, + {10, "ECHILD", "no child processes"}, + {11, "EDEADLK", "resource deadlock avoided"}, + {12, "ENOMEM", "cannot allocate memory"}, + {13, "EACCES", "permission denied"}, + {14, "EFAULT", "bad address"}, + {15, "ENOTBLK", "block device required"}, + {16, "EBUSY", "device busy"}, + {17, "EEXIST", "file exists"}, + {18, "EXDEV", "cross-device link"}, + {19, "ENODEV", "operation not supported by device"}, + {20, "ENOTDIR", "not a directory"}, + {21, "EISDIR", "is a directory"}, + {22, "EINVAL", "invalid argument"}, + {23, "ENFILE", "too many open files in system"}, + {24, "EMFILE", "too many open files"}, + {25, "ENOTTY", "inappropriate ioctl for device"}, + {26, "ETXTBSY", "text file busy"}, + {27, "EFBIG", "file too large"}, + {28, "ENOSPC", "no space left on device"}, + {29, "ESPIPE", "illegal seek"}, + {30, "EROFS", "read-only file system"}, + {31, "EMLINK", "too many links"}, + {32, "EPIPE", "broken pipe"}, + {33, "EDOM", "numerical argument out of domain"}, + {34, "ERANGE", "result too large"}, + {35, "EAGAIN", "resource temporarily unavailable"}, + {36, "EINPROGRESS", "operation now in progress"}, + {37, "EALREADY", "operation already in progress"}, + {38, "ENOTSOCK", "socket operation on non-socket"}, + {39, "EDESTADDRREQ", "destination address required"}, + {40, "EMSGSIZE", "message too long"}, + {41, "EPROTOTYPE", "protocol wrong type for socket"}, + {42, "ENOPROTOOPT", "protocol not available"}, + {43, "EPROTONOSUPPORT", "protocol not supported"}, + {44, "ESOCKTNOSUPPORT", "socket type not supported"}, + {45, "EOPNOTSUPP", "operation not supported"}, + {46, "EPFNOSUPPORT", "protocol family not supported"}, + {47, "EAFNOSUPPORT", "address family not supported by protocol family"}, + {48, "EADDRINUSE", "address already in use"}, + {49, "EADDRNOTAVAIL", "can't assign requested address"}, + {50, "ENETDOWN", "network is down"}, + {51, "ENETUNREACH", "network is unreachable"}, + {52, "ENETRESET", "network dropped connection on reset"}, + {53, "ECONNABORTED", "software caused connection abort"}, + {54, "ECONNRESET", "connection reset by peer"}, + {55, "ENOBUFS", "no buffer space available"}, + {56, "EISCONN", "socket is already connected"}, + {57, "ENOTCONN", "socket is not connected"}, + {58, "ESHUTDOWN", "can't send after socket shutdown"}, + {59, "ETOOMANYREFS", "too many references: can't splice"}, + {60, "ETIMEDOUT", "operation timed out"}, + {61, "ECONNREFUSED", "connection refused"}, + {62, "ELOOP", "too many levels of symbolic links"}, + {63, "ENAMETOOLONG", "file name too long"}, + {64, "EHOSTDOWN", "host is down"}, + {65, "EHOSTUNREACH", "no route to host"}, + {66, "ENOTEMPTY", "directory not empty"}, + {67, "EPROCLIM", "too many processes"}, + {68, "EUSERS", "too many users"}, + {69, "EDQUOT", "disc quota exceeded"}, + {70, "ESTALE", "stale NFS file handle"}, + {71, "EREMOTE", "too many levels of remote in path"}, + {72, "EBADRPC", "RPC struct is bad"}, + {73, "ERPCMISMATCH", "RPC version wrong"}, + {74, "EPROGUNAVAIL", "RPC prog. not avail"}, + {75, "EPROGMISMATCH", "program version wrong"}, + {76, "EPROCUNAVAIL", "bad procedure for program"}, + {77, "ENOLCK", "no locks available"}, + {78, "ENOSYS", "function not implemented"}, + {79, "EFTYPE", "inappropriate file type or format"}, + {80, "EAUTH", "authentication error"}, + {81, "ENEEDAUTH", "need authenticator"}, + {82, "EIDRM", "identifier removed"}, + {83, "ENOMSG", "no message of desired type"}, + {84, "EOVERFLOW", "value too large to be stored in data type"}, + {85, "ECANCELED", "operation canceled"}, + {86, "EILSEQ", "illegal byte sequence"}, + {87, "ENOATTR", "attribute not found"}, + {88, "EDOOFUS", "programming error"}, + {89, "EBADMSG", "bad message"}, + {90, "EMULTIHOP", "multihop attempted"}, + {91, "ENOLINK", "link has been severed"}, + {92, "EPROTO", "protocol error"}, + {93, "ENOTCAPABLE", "capabilities insufficient"}, + {94, "ECAPMODE", "not permitted in capability mode"}, + {95, "ENOTRECOVERABLE", "state not recoverable"}, + {96, "EOWNERDEAD", "previous owner died"}, } // Signal table -var signals = [...]string{ - 1: "hangup", - 2: "interrupt", - 3: "quit", - 4: "illegal instruction", - 5: "trace/BPT trap", - 6: "abort trap", - 7: "EMT trap", - 8: "floating point exception", - 9: "killed", - 10: "bus error", - 11: "segmentation fault", - 12: "bad system call", - 13: "broken pipe", - 14: "alarm clock", - 15: "terminated", - 16: "urgent I/O condition", - 17: "suspended (signal)", - 18: "suspended", - 19: "continued", - 20: "child exited", - 21: "stopped (tty input)", - 22: "stopped (tty output)", - 23: "I/O possible", - 24: "cputime limit exceeded", - 25: "filesize limit exceeded", - 26: "virtual timer expired", - 27: "profiling timer expired", - 28: "window size changes", - 29: "information request", - 30: "user defined signal 1", - 31: "user defined signal 2", - 32: "unknown signal", - 33: "unknown signal", +var signalList = [...]struct { + num syscall.Signal + name string + desc string +}{ + {1, "SIGHUP", "hangup"}, + {2, "SIGINT", "interrupt"}, + {3, "SIGQUIT", "quit"}, + {4, "SIGILL", "illegal instruction"}, + {5, "SIGTRAP", "trace/BPT trap"}, + {6, "SIGIOT", "abort trap"}, + {7, "SIGEMT", "EMT trap"}, + {8, "SIGFPE", "floating point exception"}, + {9, "SIGKILL", "killed"}, + {10, "SIGBUS", "bus error"}, + {11, "SIGSEGV", "segmentation fault"}, + {12, "SIGSYS", "bad system call"}, + {13, "SIGPIPE", "broken pipe"}, + {14, "SIGALRM", "alarm clock"}, + {15, "SIGTERM", "terminated"}, + {16, "SIGURG", "urgent I/O condition"}, + {17, "SIGSTOP", "suspended (signal)"}, + {18, "SIGTSTP", "suspended"}, + {19, "SIGCONT", "continued"}, + {20, "SIGCHLD", "child exited"}, + {21, "SIGTTIN", "stopped (tty input)"}, + {22, "SIGTTOU", "stopped (tty output)"}, + {23, "SIGIO", "I/O possible"}, + {24, "SIGXCPU", "cputime limit exceeded"}, + {25, "SIGXFSZ", "filesize limit exceeded"}, + {26, "SIGVTALRM", "virtual timer expired"}, + {27, "SIGPROF", "profiling timer expired"}, + {28, "SIGWINCH", "window size changes"}, + {29, "SIGINFO", "information request"}, + {30, "SIGUSR1", "user defined signal 1"}, + {31, "SIGUSR2", "user defined signal 2"}, + {32, "SIGTHR", "unknown signal"}, + {33, "SIGLIBRT", "unknown signal"}, } diff --git a/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm64.go b/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm64.go new file mode 100644 index 0000000000..d4a192fefe --- /dev/null +++ b/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm64.go @@ -0,0 +1,1794 @@ +// mkerrors.sh -m64 +// Code generated by the command above; see README.md. DO NOT EDIT. + +// +build arm64,freebsd + +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs -- -m64 _const.go + +package unix + +import "syscall" + +const ( + AF_APPLETALK = 0x10 + AF_ARP = 0x23 + AF_ATM = 0x1e + AF_BLUETOOTH = 0x24 + AF_CCITT = 0xa + AF_CHAOS = 0x5 + AF_CNT = 0x15 + AF_COIP = 0x14 + AF_DATAKIT = 0x9 + AF_DECnet = 0xc + AF_DLI = 0xd + AF_E164 = 0x1a + AF_ECMA = 0x8 + AF_HYLINK = 0xf + AF_IEEE80211 = 0x25 + AF_IMPLINK = 0x3 + AF_INET = 0x2 + AF_INET6 = 0x1c + AF_INET6_SDP = 0x2a + AF_INET_SDP = 0x28 + AF_IPX = 0x17 + AF_ISDN = 0x1a + AF_ISO = 0x7 + AF_LAT = 0xe + AF_LINK = 0x12 + AF_LOCAL = 0x1 + AF_MAX = 0x2a + AF_NATM = 0x1d + AF_NETBIOS = 0x6 + AF_NETGRAPH = 0x20 + AF_OSI = 0x7 + AF_PUP = 0x4 + AF_ROUTE = 0x11 + AF_SCLUSTER = 0x22 + AF_SIP = 0x18 + AF_SLOW = 0x21 + AF_SNA = 0xb + AF_UNIX = 0x1 + AF_UNSPEC = 0x0 + AF_VENDOR00 = 0x27 + AF_VENDOR01 = 0x29 + AF_VENDOR02 = 0x2b + AF_VENDOR03 = 0x2d + AF_VENDOR04 = 0x2f + AF_VENDOR05 = 0x31 + AF_VENDOR06 = 0x33 + AF_VENDOR07 = 0x35 + AF_VENDOR08 = 0x37 + AF_VENDOR09 = 0x39 + AF_VENDOR10 = 0x3b + AF_VENDOR11 = 0x3d + AF_VENDOR12 = 0x3f + AF_VENDOR13 = 0x41 + AF_VENDOR14 = 0x43 + AF_VENDOR15 = 0x45 + AF_VENDOR16 = 0x47 + AF_VENDOR17 = 0x49 + AF_VENDOR18 = 0x4b + AF_VENDOR19 = 0x4d + AF_VENDOR20 = 0x4f + AF_VENDOR21 = 0x51 + AF_VENDOR22 = 0x53 + AF_VENDOR23 = 0x55 + AF_VENDOR24 = 0x57 + AF_VENDOR25 = 0x59 + AF_VENDOR26 = 0x5b + AF_VENDOR27 = 0x5d + AF_VENDOR28 = 0x5f + AF_VENDOR29 = 0x61 + AF_VENDOR30 = 0x63 + AF_VENDOR31 = 0x65 + AF_VENDOR32 = 0x67 + AF_VENDOR33 = 0x69 + AF_VENDOR34 = 0x6b + AF_VENDOR35 = 0x6d + AF_VENDOR36 = 0x6f + AF_VENDOR37 = 0x71 + AF_VENDOR38 = 0x73 + AF_VENDOR39 = 0x75 + AF_VENDOR40 = 0x77 + AF_VENDOR41 = 0x79 + AF_VENDOR42 = 0x7b + AF_VENDOR43 = 0x7d + AF_VENDOR44 = 0x7f + AF_VENDOR45 = 0x81 + AF_VENDOR46 = 0x83 + AF_VENDOR47 = 0x85 + ALTWERASE = 0x200 + B0 = 0x0 + B110 = 0x6e + B115200 = 0x1c200 + B1200 = 0x4b0 + B134 = 0x86 + B14400 = 0x3840 + B150 = 0x96 + B1800 = 0x708 + B19200 = 0x4b00 + B200 = 0xc8 + B230400 = 0x38400 + B2400 = 0x960 + B28800 = 0x7080 + B300 = 0x12c + B38400 = 0x9600 + B460800 = 0x70800 + B4800 = 0x12c0 + B50 = 0x32 + B57600 = 0xe100 + B600 = 0x258 + B7200 = 0x1c20 + B75 = 0x4b + B76800 = 0x12c00 + B921600 = 0xe1000 + B9600 = 0x2580 + BIOCFEEDBACK = 0x8004427c + BIOCFLUSH = 0x20004268 + BIOCGBLEN = 0x40044266 + BIOCGDIRECTION = 0x40044276 + BIOCGDLT = 0x4004426a + BIOCGDLTLIST = 0xc0104279 + BIOCGETBUFMODE = 0x4004427d + BIOCGETIF = 0x4020426b + BIOCGETZMAX = 0x4008427f + BIOCGHDRCMPLT = 0x40044274 + BIOCGRSIG = 0x40044272 + BIOCGRTIMEOUT = 0x4010426e + BIOCGSEESENT = 0x40044276 + BIOCGSTATS = 0x4008426f + BIOCGTSTAMP = 0x40044283 + BIOCIMMEDIATE = 0x80044270 + BIOCLOCK = 0x2000427a + BIOCPROMISC = 0x20004269 + BIOCROTZBUF = 0x40184280 + BIOCSBLEN = 0xc0044266 + BIOCSDIRECTION = 0x80044277 + BIOCSDLT = 0x80044278 + BIOCSETBUFMODE = 0x8004427e + BIOCSETF = 0x80104267 + BIOCSETFNR = 0x80104282 + BIOCSETIF = 0x8020426c + BIOCSETWF = 0x8010427b + BIOCSETZBUF = 0x80184281 + BIOCSHDRCMPLT = 0x80044275 + BIOCSRSIG = 0x80044273 + BIOCSRTIMEOUT = 0x8010426d + BIOCSSEESENT = 0x80044277 + BIOCSTSTAMP = 0x80044284 + BIOCVERSION = 0x40044271 + BPF_A = 0x10 + BPF_ABS = 0x20 + BPF_ADD = 0x0 + BPF_ALIGNMENT = 0x8 + BPF_ALU = 0x4 + BPF_AND = 0x50 + BPF_B = 0x10 + BPF_BUFMODE_BUFFER = 0x1 + BPF_BUFMODE_ZBUF = 0x2 + BPF_DIV = 0x30 + BPF_H = 0x8 + BPF_IMM = 0x0 + BPF_IND = 0x40 + BPF_JA = 0x0 + BPF_JEQ = 0x10 + BPF_JGE = 0x30 + BPF_JGT = 0x20 + BPF_JMP = 0x5 + BPF_JSET = 0x40 + BPF_K = 0x0 + BPF_LD = 0x0 + BPF_LDX = 0x1 + BPF_LEN = 0x80 + BPF_LSH = 0x60 + BPF_MAJOR_VERSION = 0x1 + BPF_MAXBUFSIZE = 0x80000 + BPF_MAXINSNS = 0x200 + BPF_MEM = 0x60 + BPF_MEMWORDS = 0x10 + BPF_MINBUFSIZE = 0x20 + BPF_MINOR_VERSION = 0x1 + BPF_MISC = 0x7 + BPF_MOD = 0x90 + BPF_MSH = 0xa0 + BPF_MUL = 0x20 + BPF_NEG = 0x80 + BPF_OR = 0x40 + BPF_RELEASE = 0x30bb6 + BPF_RET = 0x6 + BPF_RSH = 0x70 + BPF_ST = 0x2 + BPF_STX = 0x3 + BPF_SUB = 0x10 + BPF_TAX = 0x0 + BPF_TXA = 0x80 + BPF_T_BINTIME = 0x2 + BPF_T_BINTIME_FAST = 0x102 + BPF_T_BINTIME_MONOTONIC = 0x202 + BPF_T_BINTIME_MONOTONIC_FAST = 0x302 + BPF_T_FAST = 0x100 + BPF_T_FLAG_MASK = 0x300 + BPF_T_FORMAT_MASK = 0x3 + BPF_T_MICROTIME = 0x0 + BPF_T_MICROTIME_FAST = 0x100 + BPF_T_MICROTIME_MONOTONIC = 0x200 + BPF_T_MICROTIME_MONOTONIC_FAST = 0x300 + BPF_T_MONOTONIC = 0x200 + BPF_T_MONOTONIC_FAST = 0x300 + BPF_T_NANOTIME = 0x1 + BPF_T_NANOTIME_FAST = 0x101 + BPF_T_NANOTIME_MONOTONIC = 0x201 + BPF_T_NANOTIME_MONOTONIC_FAST = 0x301 + BPF_T_NONE = 0x3 + BPF_T_NORMAL = 0x0 + BPF_W = 0x0 + BPF_X = 0x8 + BPF_XOR = 0xa0 + BRKINT = 0x2 + CAP_ACCEPT = 0x200000020000000 + CAP_ACL_CHECK = 0x400000000010000 + CAP_ACL_DELETE = 0x400000000020000 + CAP_ACL_GET = 0x400000000040000 + CAP_ACL_SET = 0x400000000080000 + CAP_ALL0 = 0x20007ffffffffff + CAP_ALL1 = 0x4000000001fffff + CAP_BIND = 0x200000040000000 + CAP_BINDAT = 0x200008000000400 + CAP_CHFLAGSAT = 0x200000000001400 + CAP_CONNECT = 0x200000080000000 + CAP_CONNECTAT = 0x200010000000400 + CAP_CREATE = 0x200000000000040 + CAP_EVENT = 0x400000000000020 + CAP_EXTATTR_DELETE = 0x400000000001000 + CAP_EXTATTR_GET = 0x400000000002000 + CAP_EXTATTR_LIST = 0x400000000004000 + CAP_EXTATTR_SET = 0x400000000008000 + CAP_FCHDIR = 0x200000000000800 + CAP_FCHFLAGS = 0x200000000001000 + CAP_FCHMOD = 0x200000000002000 + CAP_FCHMODAT = 0x200000000002400 + CAP_FCHOWN = 0x200000000004000 + CAP_FCHOWNAT = 0x200000000004400 + CAP_FCNTL = 0x200000000008000 + CAP_FCNTL_ALL = 0x78 + CAP_FCNTL_GETFL = 0x8 + CAP_FCNTL_GETOWN = 0x20 + CAP_FCNTL_SETFL = 0x10 + CAP_FCNTL_SETOWN = 0x40 + CAP_FEXECVE = 0x200000000000080 + CAP_FLOCK = 0x200000000010000 + CAP_FPATHCONF = 0x200000000020000 + CAP_FSCK = 0x200000000040000 + CAP_FSTAT = 0x200000000080000 + CAP_FSTATAT = 0x200000000080400 + CAP_FSTATFS = 0x200000000100000 + CAP_FSYNC = 0x200000000000100 + CAP_FTRUNCATE = 0x200000000000200 + CAP_FUTIMES = 0x200000000200000 + CAP_FUTIMESAT = 0x200000000200400 + CAP_GETPEERNAME = 0x200000100000000 + CAP_GETSOCKNAME = 0x200000200000000 + CAP_GETSOCKOPT = 0x200000400000000 + CAP_IOCTL = 0x400000000000080 + CAP_IOCTLS_ALL = 0x7fffffffffffffff + CAP_KQUEUE = 0x400000000100040 + CAP_KQUEUE_CHANGE = 0x400000000100000 + CAP_KQUEUE_EVENT = 0x400000000000040 + CAP_LINKAT_SOURCE = 0x200020000000400 + CAP_LINKAT_TARGET = 0x200000000400400 + CAP_LISTEN = 0x200000800000000 + CAP_LOOKUP = 0x200000000000400 + CAP_MAC_GET = 0x400000000000001 + CAP_MAC_SET = 0x400000000000002 + CAP_MKDIRAT = 0x200000000800400 + CAP_MKFIFOAT = 0x200000001000400 + CAP_MKNODAT = 0x200000002000400 + CAP_MMAP = 0x200000000000010 + CAP_MMAP_R = 0x20000000000001d + CAP_MMAP_RW = 0x20000000000001f + CAP_MMAP_RWX = 0x20000000000003f + CAP_MMAP_RX = 0x20000000000003d + CAP_MMAP_W = 0x20000000000001e + CAP_MMAP_WX = 0x20000000000003e + CAP_MMAP_X = 0x20000000000003c + CAP_PDGETPID = 0x400000000000200 + CAP_PDKILL = 0x400000000000800 + CAP_PDWAIT = 0x400000000000400 + CAP_PEELOFF = 0x200001000000000 + CAP_POLL_EVENT = 0x400000000000020 + CAP_PREAD = 0x20000000000000d + CAP_PWRITE = 0x20000000000000e + CAP_READ = 0x200000000000001 + CAP_RECV = 0x200000000000001 + CAP_RENAMEAT_SOURCE = 0x200000004000400 + CAP_RENAMEAT_TARGET = 0x200040000000400 + CAP_RIGHTS_VERSION = 0x0 + CAP_RIGHTS_VERSION_00 = 0x0 + CAP_SEEK = 0x20000000000000c + CAP_SEEK_TELL = 0x200000000000004 + CAP_SEM_GETVALUE = 0x400000000000004 + CAP_SEM_POST = 0x400000000000008 + CAP_SEM_WAIT = 0x400000000000010 + CAP_SEND = 0x200000000000002 + CAP_SETSOCKOPT = 0x200002000000000 + CAP_SHUTDOWN = 0x200004000000000 + CAP_SOCK_CLIENT = 0x200007780000003 + CAP_SOCK_SERVER = 0x200007f60000003 + CAP_SYMLINKAT = 0x200000008000400 + CAP_TTYHOOK = 0x400000000000100 + CAP_UNLINKAT = 0x200000010000400 + CAP_UNUSED0_44 = 0x200080000000000 + CAP_UNUSED0_57 = 0x300000000000000 + CAP_UNUSED1_22 = 0x400000000200000 + CAP_UNUSED1_57 = 0x500000000000000 + CAP_WRITE = 0x200000000000002 + CFLUSH = 0xf + CLOCAL = 0x8000 + CLOCK_MONOTONIC = 0x4 + CLOCK_MONOTONIC_FAST = 0xc + CLOCK_MONOTONIC_PRECISE = 0xb + CLOCK_PROCESS_CPUTIME_ID = 0xf + CLOCK_PROF = 0x2 + CLOCK_REALTIME = 0x0 + CLOCK_REALTIME_FAST = 0xa + CLOCK_REALTIME_PRECISE = 0x9 + CLOCK_SECOND = 0xd + CLOCK_THREAD_CPUTIME_ID = 0xe + CLOCK_UPTIME = 0x5 + CLOCK_UPTIME_FAST = 0x8 + CLOCK_UPTIME_PRECISE = 0x7 + CLOCK_VIRTUAL = 0x1 + CREAD = 0x800 + CRTSCTS = 0x30000 + CS5 = 0x0 + CS6 = 0x100 + CS7 = 0x200 + CS8 = 0x300 + CSIZE = 0x300 + CSTART = 0x11 + CSTATUS = 0x14 + CSTOP = 0x13 + CSTOPB = 0x400 + CSUSP = 0x1a + CTL_HW = 0x6 + CTL_KERN = 0x1 + CTL_MAXNAME = 0x18 + CTL_NET = 0x4 + DLT_A429 = 0xb8 + DLT_A653_ICM = 0xb9 + DLT_AIRONET_HEADER = 0x78 + DLT_AOS = 0xde + DLT_APPLE_IP_OVER_IEEE1394 = 0x8a + DLT_ARCNET = 0x7 + DLT_ARCNET_LINUX = 0x81 + DLT_ATM_CLIP = 0x13 + DLT_ATM_RFC1483 = 0xb + DLT_AURORA = 0x7e + DLT_AX25 = 0x3 + DLT_AX25_KISS = 0xca + DLT_BACNET_MS_TP = 0xa5 + DLT_BLUETOOTH_BREDR_BB = 0xff + DLT_BLUETOOTH_HCI_H4 = 0xbb + DLT_BLUETOOTH_HCI_H4_WITH_PHDR = 0xc9 + DLT_BLUETOOTH_LE_LL = 0xfb + DLT_BLUETOOTH_LE_LL_WITH_PHDR = 0x100 + DLT_BLUETOOTH_LINUX_MONITOR = 0xfe + DLT_CAN20B = 0xbe + DLT_CAN_SOCKETCAN = 0xe3 + DLT_CHAOS = 0x5 + DLT_CHDLC = 0x68 + DLT_CISCO_IOS = 0x76 + DLT_C_HDLC = 0x68 + DLT_C_HDLC_WITH_DIR = 0xcd + DLT_DBUS = 0xe7 + DLT_DECT = 0xdd + DLT_DOCSIS = 0x8f + DLT_DVB_CI = 0xeb + DLT_ECONET = 0x73 + DLT_EN10MB = 0x1 + DLT_EN3MB = 0x2 + DLT_ENC = 0x6d + DLT_EPON = 0x103 + DLT_ERF = 0xc5 + DLT_ERF_ETH = 0xaf + DLT_ERF_POS = 0xb0 + DLT_FC_2 = 0xe0 + DLT_FC_2_WITH_FRAME_DELIMS = 0xe1 + DLT_FDDI = 0xa + DLT_FLEXRAY = 0xd2 + DLT_FRELAY = 0x6b + DLT_FRELAY_WITH_DIR = 0xce + DLT_GCOM_SERIAL = 0xad + DLT_GCOM_T1E1 = 0xac + DLT_GPF_F = 0xab + DLT_GPF_T = 0xaa + DLT_GPRS_LLC = 0xa9 + DLT_GSMTAP_ABIS = 0xda + DLT_GSMTAP_UM = 0xd9 + DLT_HHDLC = 0x79 + DLT_IBM_SN = 0x92 + DLT_IBM_SP = 0x91 + DLT_IEEE802 = 0x6 + DLT_IEEE802_11 = 0x69 + DLT_IEEE802_11_RADIO = 0x7f + DLT_IEEE802_11_RADIO_AVS = 0xa3 + DLT_IEEE802_15_4 = 0xc3 + DLT_IEEE802_15_4_LINUX = 0xbf + DLT_IEEE802_15_4_NOFCS = 0xe6 + DLT_IEEE802_15_4_NONASK_PHY = 0xd7 + DLT_IEEE802_16_MAC_CPS = 0xbc + DLT_IEEE802_16_MAC_CPS_RADIO = 0xc1 + DLT_INFINIBAND = 0xf7 + DLT_IPFILTER = 0x74 + DLT_IPMB = 0xc7 + DLT_IPMB_LINUX = 0xd1 + DLT_IPMI_HPM_2 = 0x104 + DLT_IPNET = 0xe2 + DLT_IPOIB = 0xf2 + DLT_IPV4 = 0xe4 + DLT_IPV6 = 0xe5 + DLT_IP_OVER_FC = 0x7a + DLT_JUNIPER_ATM1 = 0x89 + DLT_JUNIPER_ATM2 = 0x87 + DLT_JUNIPER_ATM_CEMIC = 0xee + DLT_JUNIPER_CHDLC = 0xb5 + DLT_JUNIPER_ES = 0x84 + DLT_JUNIPER_ETHER = 0xb2 + DLT_JUNIPER_FIBRECHANNEL = 0xea + DLT_JUNIPER_FRELAY = 0xb4 + DLT_JUNIPER_GGSN = 0x85 + DLT_JUNIPER_ISM = 0xc2 + DLT_JUNIPER_MFR = 0x86 + DLT_JUNIPER_MLFR = 0x83 + DLT_JUNIPER_MLPPP = 0x82 + DLT_JUNIPER_MONITOR = 0xa4 + DLT_JUNIPER_PIC_PEER = 0xae + DLT_JUNIPER_PPP = 0xb3 + DLT_JUNIPER_PPPOE = 0xa7 + DLT_JUNIPER_PPPOE_ATM = 0xa8 + DLT_JUNIPER_SERVICES = 0x88 + DLT_JUNIPER_SRX_E2E = 0xe9 + DLT_JUNIPER_ST = 0xc8 + DLT_JUNIPER_VP = 0xb7 + DLT_JUNIPER_VS = 0xe8 + DLT_LAPB_WITH_DIR = 0xcf + DLT_LAPD = 0xcb + DLT_LIN = 0xd4 + DLT_LINUX_EVDEV = 0xd8 + DLT_LINUX_IRDA = 0x90 + DLT_LINUX_LAPD = 0xb1 + DLT_LINUX_PPP_WITHDIRECTION = 0xa6 + DLT_LINUX_SLL = 0x71 + DLT_LOOP = 0x6c + DLT_LTALK = 0x72 + DLT_MATCHING_MAX = 0x104 + DLT_MATCHING_MIN = 0x68 + DLT_MFR = 0xb6 + DLT_MOST = 0xd3 + DLT_MPEG_2_TS = 0xf3 + DLT_MPLS = 0xdb + DLT_MTP2 = 0x8c + DLT_MTP2_WITH_PHDR = 0x8b + DLT_MTP3 = 0x8d + DLT_MUX27010 = 0xec + DLT_NETANALYZER = 0xf0 + DLT_NETANALYZER_TRANSPARENT = 0xf1 + DLT_NETLINK = 0xfd + DLT_NFC_LLCP = 0xf5 + DLT_NFLOG = 0xef + DLT_NG40 = 0xf4 + DLT_NULL = 0x0 + DLT_PCI_EXP = 0x7d + DLT_PFLOG = 0x75 + DLT_PFSYNC = 0x79 + DLT_PKTAP = 0x102 + DLT_PPI = 0xc0 + DLT_PPP = 0x9 + DLT_PPP_BSDOS = 0x10 + DLT_PPP_ETHER = 0x33 + DLT_PPP_PPPD = 0xa6 + DLT_PPP_SERIAL = 0x32 + DLT_PPP_WITH_DIR = 0xcc + DLT_PPP_WITH_DIRECTION = 0xa6 + DLT_PRISM_HEADER = 0x77 + DLT_PROFIBUS_DL = 0x101 + DLT_PRONET = 0x4 + DLT_RAIF1 = 0xc6 + DLT_RAW = 0xc + DLT_RIO = 0x7c + DLT_RTAC_SERIAL = 0xfa + DLT_SCCP = 0x8e + DLT_SCTP = 0xf8 + DLT_SITA = 0xc4 + DLT_SLIP = 0x8 + DLT_SLIP_BSDOS = 0xf + DLT_STANAG_5066_D_PDU = 0xed + DLT_SUNATM = 0x7b + DLT_SYMANTEC_FIREWALL = 0x63 + DLT_TZSP = 0x80 + DLT_USB = 0xba + DLT_USBPCAP = 0xf9 + DLT_USB_LINUX = 0xbd + DLT_USB_LINUX_MMAPPED = 0xdc + DLT_USER0 = 0x93 + DLT_USER1 = 0x94 + DLT_USER10 = 0x9d + DLT_USER11 = 0x9e + DLT_USER12 = 0x9f + DLT_USER13 = 0xa0 + DLT_USER14 = 0xa1 + DLT_USER15 = 0xa2 + DLT_USER2 = 0x95 + DLT_USER3 = 0x96 + DLT_USER4 = 0x97 + DLT_USER5 = 0x98 + DLT_USER6 = 0x99 + DLT_USER7 = 0x9a + DLT_USER8 = 0x9b + DLT_USER9 = 0x9c + DLT_WIHART = 0xdf + DLT_WIRESHARK_UPPER_PDU = 0xfc + DLT_X2E_SERIAL = 0xd5 + DLT_X2E_XORAYA = 0xd6 + DT_BLK = 0x6 + DT_CHR = 0x2 + DT_DIR = 0x4 + DT_FIFO = 0x1 + DT_LNK = 0xa + DT_REG = 0x8 + DT_SOCK = 0xc + DT_UNKNOWN = 0x0 + DT_WHT = 0xe + ECHO = 0x8 + ECHOCTL = 0x40 + ECHOE = 0x2 + ECHOK = 0x4 + ECHOKE = 0x1 + ECHONL = 0x10 + ECHOPRT = 0x20 + EVFILT_AIO = -0x3 + EVFILT_FS = -0x9 + EVFILT_LIO = -0xa + EVFILT_PROC = -0x5 + EVFILT_PROCDESC = -0x8 + EVFILT_READ = -0x1 + EVFILT_SENDFILE = -0xc + EVFILT_SIGNAL = -0x6 + EVFILT_SYSCOUNT = 0xc + EVFILT_TIMER = -0x7 + EVFILT_USER = -0xb + EVFILT_VNODE = -0x4 + EVFILT_WRITE = -0x2 + EV_ADD = 0x1 + EV_CLEAR = 0x20 + EV_DELETE = 0x2 + EV_DISABLE = 0x8 + EV_DISPATCH = 0x80 + EV_DROP = 0x1000 + EV_ENABLE = 0x4 + EV_EOF = 0x8000 + EV_ERROR = 0x4000 + EV_FLAG1 = 0x2000 + EV_FLAG2 = 0x4000 + EV_FORCEONESHOT = 0x100 + EV_ONESHOT = 0x10 + EV_RECEIPT = 0x40 + EV_SYSFLAGS = 0xf000 + EXTA = 0x4b00 + EXTATTR_NAMESPACE_EMPTY = 0x0 + EXTATTR_NAMESPACE_SYSTEM = 0x2 + EXTATTR_NAMESPACE_USER = 0x1 + EXTB = 0x9600 + EXTPROC = 0x800 + FD_CLOEXEC = 0x1 + FD_SETSIZE = 0x400 + FLUSHO = 0x800000 + F_CANCEL = 0x5 + F_DUP2FD = 0xa + F_DUP2FD_CLOEXEC = 0x12 + F_DUPFD = 0x0 + F_DUPFD_CLOEXEC = 0x11 + F_GETFD = 0x1 + F_GETFL = 0x3 + F_GETLK = 0xb + F_GETOWN = 0x5 + F_OGETLK = 0x7 + F_OK = 0x0 + F_OSETLK = 0x8 + F_OSETLKW = 0x9 + F_RDAHEAD = 0x10 + F_RDLCK = 0x1 + F_READAHEAD = 0xf + F_SETFD = 0x2 + F_SETFL = 0x4 + F_SETLK = 0xc + F_SETLKW = 0xd + F_SETLK_REMOTE = 0xe + F_SETOWN = 0x6 + F_UNLCK = 0x2 + F_UNLCKSYS = 0x4 + F_WRLCK = 0x3 + HUPCL = 0x4000 + HW_MACHINE = 0x1 + ICANON = 0x100 + ICMP6_FILTER = 0x12 + ICRNL = 0x100 + IEXTEN = 0x400 + IFAN_ARRIVAL = 0x0 + IFAN_DEPARTURE = 0x1 + IFF_ALLMULTI = 0x200 + IFF_ALTPHYS = 0x4000 + IFF_BROADCAST = 0x2 + IFF_CANTCHANGE = 0x218f52 + IFF_CANTCONFIG = 0x10000 + IFF_DEBUG = 0x4 + IFF_DRV_OACTIVE = 0x400 + IFF_DRV_RUNNING = 0x40 + IFF_DYING = 0x200000 + IFF_LINK0 = 0x1000 + IFF_LINK1 = 0x2000 + IFF_LINK2 = 0x4000 + IFF_LOOPBACK = 0x8 + IFF_MONITOR = 0x40000 + IFF_MULTICAST = 0x8000 + IFF_NOARP = 0x80 + IFF_OACTIVE = 0x400 + IFF_POINTOPOINT = 0x10 + IFF_PPROMISC = 0x20000 + IFF_PROMISC = 0x100 + IFF_RENAMING = 0x400000 + IFF_RUNNING = 0x40 + IFF_SIMPLEX = 0x800 + IFF_STATICARP = 0x80000 + IFF_UP = 0x1 + IFNAMSIZ = 0x10 + IFT_BRIDGE = 0xd1 + IFT_CARP = 0xf8 + IFT_IEEE1394 = 0x90 + IFT_INFINIBAND = 0xc7 + IFT_L2VLAN = 0x87 + IFT_L3IPVLAN = 0x88 + IFT_PPP = 0x17 + IFT_PROPVIRTUAL = 0x35 + IGNBRK = 0x1 + IGNCR = 0x80 + IGNPAR = 0x4 + IMAXBEL = 0x2000 + INLCR = 0x40 + INPCK = 0x10 + IN_CLASSA_HOST = 0xffffff + IN_CLASSA_MAX = 0x80 + IN_CLASSA_NET = 0xff000000 + IN_CLASSA_NSHIFT = 0x18 + IN_CLASSB_HOST = 0xffff + IN_CLASSB_MAX = 0x10000 + IN_CLASSB_NET = 0xffff0000 + IN_CLASSB_NSHIFT = 0x10 + IN_CLASSC_HOST = 0xff + IN_CLASSC_NET = 0xffffff00 + IN_CLASSC_NSHIFT = 0x8 + IN_CLASSD_HOST = 0xfffffff + IN_CLASSD_NET = 0xf0000000 + IN_CLASSD_NSHIFT = 0x1c + IN_LOOPBACKNET = 0x7f + IN_RFC3021_MASK = 0xfffffffe + IPPROTO_3PC = 0x22 + IPPROTO_ADFS = 0x44 + IPPROTO_AH = 0x33 + IPPROTO_AHIP = 0x3d + IPPROTO_APES = 0x63 + IPPROTO_ARGUS = 0xd + IPPROTO_AX25 = 0x5d + IPPROTO_BHA = 0x31 + IPPROTO_BLT = 0x1e + IPPROTO_BRSATMON = 0x4c + IPPROTO_CARP = 0x70 + IPPROTO_CFTP = 0x3e + IPPROTO_CHAOS = 0x10 + IPPROTO_CMTP = 0x26 + IPPROTO_CPHB = 0x49 + IPPROTO_CPNX = 0x48 + IPPROTO_DDP = 0x25 + IPPROTO_DGP = 0x56 + IPPROTO_DIVERT = 0x102 + IPPROTO_DONE = 0x101 + IPPROTO_DSTOPTS = 0x3c + IPPROTO_EGP = 0x8 + IPPROTO_EMCON = 0xe + IPPROTO_ENCAP = 0x62 + IPPROTO_EON = 0x50 + IPPROTO_ESP = 0x32 + IPPROTO_ETHERIP = 0x61 + IPPROTO_FRAGMENT = 0x2c + IPPROTO_GGP = 0x3 + IPPROTO_GMTP = 0x64 + IPPROTO_GRE = 0x2f + IPPROTO_HELLO = 0x3f + IPPROTO_HIP = 0x8b + IPPROTO_HMP = 0x14 + IPPROTO_HOPOPTS = 0x0 + IPPROTO_ICMP = 0x1 + IPPROTO_ICMPV6 = 0x3a + IPPROTO_IDP = 0x16 + IPPROTO_IDPR = 0x23 + IPPROTO_IDRP = 0x2d + IPPROTO_IGMP = 0x2 + IPPROTO_IGP = 0x55 + IPPROTO_IGRP = 0x58 + IPPROTO_IL = 0x28 + IPPROTO_INLSP = 0x34 + IPPROTO_INP = 0x20 + IPPROTO_IP = 0x0 + IPPROTO_IPCOMP = 0x6c + IPPROTO_IPCV = 0x47 + IPPROTO_IPEIP = 0x5e + IPPROTO_IPIP = 0x4 + IPPROTO_IPPC = 0x43 + IPPROTO_IPV4 = 0x4 + IPPROTO_IPV6 = 0x29 + IPPROTO_IRTP = 0x1c + IPPROTO_KRYPTOLAN = 0x41 + IPPROTO_LARP = 0x5b + IPPROTO_LEAF1 = 0x19 + IPPROTO_LEAF2 = 0x1a + IPPROTO_MAX = 0x100 + IPPROTO_MEAS = 0x13 + IPPROTO_MH = 0x87 + IPPROTO_MHRP = 0x30 + IPPROTO_MICP = 0x5f + IPPROTO_MOBILE = 0x37 + IPPROTO_MPLS = 0x89 + IPPROTO_MTP = 0x5c + IPPROTO_MUX = 0x12 + IPPROTO_ND = 0x4d + IPPROTO_NHRP = 0x36 + IPPROTO_NONE = 0x3b + IPPROTO_NSP = 0x1f + IPPROTO_NVPII = 0xb + IPPROTO_OLD_DIVERT = 0xfe + IPPROTO_OSPFIGP = 0x59 + IPPROTO_PFSYNC = 0xf0 + IPPROTO_PGM = 0x71 + IPPROTO_PIGP = 0x9 + IPPROTO_PIM = 0x67 + IPPROTO_PRM = 0x15 + IPPROTO_PUP = 0xc + IPPROTO_PVP = 0x4b + IPPROTO_RAW = 0xff + IPPROTO_RCCMON = 0xa + IPPROTO_RDP = 0x1b + IPPROTO_RESERVED_253 = 0xfd + IPPROTO_RESERVED_254 = 0xfe + IPPROTO_ROUTING = 0x2b + IPPROTO_RSVP = 0x2e + IPPROTO_RVD = 0x42 + IPPROTO_SATEXPAK = 0x40 + IPPROTO_SATMON = 0x45 + IPPROTO_SCCSP = 0x60 + IPPROTO_SCTP = 0x84 + IPPROTO_SDRP = 0x2a + IPPROTO_SEND = 0x103 + IPPROTO_SEP = 0x21 + IPPROTO_SHIM6 = 0x8c + IPPROTO_SKIP = 0x39 + IPPROTO_SPACER = 0x7fff + IPPROTO_SRPC = 0x5a + IPPROTO_ST = 0x7 + IPPROTO_SVMTP = 0x52 + IPPROTO_SWIPE = 0x35 + IPPROTO_TCF = 0x57 + IPPROTO_TCP = 0x6 + IPPROTO_TLSP = 0x38 + IPPROTO_TP = 0x1d + IPPROTO_TPXX = 0x27 + IPPROTO_TRUNK1 = 0x17 + IPPROTO_TRUNK2 = 0x18 + IPPROTO_TTP = 0x54 + IPPROTO_UDP = 0x11 + IPPROTO_UDPLITE = 0x88 + IPPROTO_VINES = 0x53 + IPPROTO_VISA = 0x46 + IPPROTO_VMTP = 0x51 + IPPROTO_WBEXPAK = 0x4f + IPPROTO_WBMON = 0x4e + IPPROTO_WSN = 0x4a + IPPROTO_XNET = 0xf + IPPROTO_XTP = 0x24 + IPV6_AUTOFLOWLABEL = 0x3b + IPV6_BINDANY = 0x40 + IPV6_BINDMULTI = 0x41 + IPV6_BINDV6ONLY = 0x1b + IPV6_CHECKSUM = 0x1a + IPV6_DEFAULT_MULTICAST_HOPS = 0x1 + IPV6_DEFAULT_MULTICAST_LOOP = 0x1 + IPV6_DEFHLIM = 0x40 + IPV6_DONTFRAG = 0x3e + IPV6_DSTOPTS = 0x32 + IPV6_FLOWID = 0x43 + IPV6_FLOWINFO_MASK = 0xffffff0f + IPV6_FLOWLABEL_MASK = 0xffff0f00 + IPV6_FLOWTYPE = 0x44 + IPV6_FRAGTTL = 0x78 + IPV6_FW_ADD = 0x1e + IPV6_FW_DEL = 0x1f + IPV6_FW_FLUSH = 0x20 + IPV6_FW_GET = 0x22 + IPV6_FW_ZERO = 0x21 + IPV6_HLIMDEC = 0x1 + IPV6_HOPLIMIT = 0x2f + IPV6_HOPOPTS = 0x31 + IPV6_IPSEC_POLICY = 0x1c + IPV6_JOIN_GROUP = 0xc + IPV6_LEAVE_GROUP = 0xd + IPV6_MAXHLIM = 0xff + IPV6_MAXOPTHDR = 0x800 + IPV6_MAXPACKET = 0xffff + IPV6_MAX_GROUP_SRC_FILTER = 0x200 + IPV6_MAX_MEMBERSHIPS = 0xfff + IPV6_MAX_SOCK_SRC_FILTER = 0x80 + IPV6_MIN_MEMBERSHIPS = 0x1f + IPV6_MMTU = 0x500 + IPV6_MSFILTER = 0x4a + IPV6_MULTICAST_HOPS = 0xa + IPV6_MULTICAST_IF = 0x9 + IPV6_MULTICAST_LOOP = 0xb + IPV6_NEXTHOP = 0x30 + IPV6_PATHMTU = 0x2c + IPV6_PKTINFO = 0x2e + IPV6_PORTRANGE = 0xe + IPV6_PORTRANGE_DEFAULT = 0x0 + IPV6_PORTRANGE_HIGH = 0x1 + IPV6_PORTRANGE_LOW = 0x2 + IPV6_PREFER_TEMPADDR = 0x3f + IPV6_RECVDSTOPTS = 0x28 + IPV6_RECVFLOWID = 0x46 + IPV6_RECVHOPLIMIT = 0x25 + IPV6_RECVHOPOPTS = 0x27 + IPV6_RECVPATHMTU = 0x2b + IPV6_RECVPKTINFO = 0x24 + IPV6_RECVRSSBUCKETID = 0x47 + IPV6_RECVRTHDR = 0x26 + IPV6_RECVTCLASS = 0x39 + IPV6_RSSBUCKETID = 0x45 + IPV6_RSS_LISTEN_BUCKET = 0x42 + IPV6_RTHDR = 0x33 + IPV6_RTHDRDSTOPTS = 0x23 + IPV6_RTHDR_LOOSE = 0x0 + IPV6_RTHDR_STRICT = 0x1 + IPV6_RTHDR_TYPE_0 = 0x0 + IPV6_SOCKOPT_RESERVED1 = 0x3 + IPV6_TCLASS = 0x3d + IPV6_UNICAST_HOPS = 0x4 + IPV6_USE_MIN_MTU = 0x2a + IPV6_V6ONLY = 0x1b + IPV6_VERSION = 0x60 + IPV6_VERSION_MASK = 0xf0 + IP_ADD_MEMBERSHIP = 0xc + IP_ADD_SOURCE_MEMBERSHIP = 0x46 + IP_BINDANY = 0x18 + IP_BINDMULTI = 0x19 + IP_BLOCK_SOURCE = 0x48 + IP_DEFAULT_MULTICAST_LOOP = 0x1 + IP_DEFAULT_MULTICAST_TTL = 0x1 + IP_DF = 0x4000 + IP_DONTFRAG = 0x43 + IP_DROP_MEMBERSHIP = 0xd + IP_DROP_SOURCE_MEMBERSHIP = 0x47 + IP_DUMMYNET3 = 0x31 + IP_DUMMYNET_CONFIGURE = 0x3c + IP_DUMMYNET_DEL = 0x3d + IP_DUMMYNET_FLUSH = 0x3e + IP_DUMMYNET_GET = 0x40 + IP_FLOWID = 0x5a + IP_FLOWTYPE = 0x5b + IP_FW3 = 0x30 + IP_FW_ADD = 0x32 + IP_FW_DEL = 0x33 + IP_FW_FLUSH = 0x34 + IP_FW_GET = 0x36 + IP_FW_NAT_CFG = 0x38 + IP_FW_NAT_DEL = 0x39 + IP_FW_NAT_GET_CONFIG = 0x3a + IP_FW_NAT_GET_LOG = 0x3b + IP_FW_RESETLOG = 0x37 + IP_FW_TABLE_ADD = 0x28 + IP_FW_TABLE_DEL = 0x29 + IP_FW_TABLE_FLUSH = 0x2a + IP_FW_TABLE_GETSIZE = 0x2b + IP_FW_TABLE_LIST = 0x2c + IP_FW_ZERO = 0x35 + IP_HDRINCL = 0x2 + IP_IPSEC_POLICY = 0x15 + IP_MAXPACKET = 0xffff + IP_MAX_GROUP_SRC_FILTER = 0x200 + IP_MAX_MEMBERSHIPS = 0xfff + IP_MAX_SOCK_MUTE_FILTER = 0x80 + IP_MAX_SOCK_SRC_FILTER = 0x80 + IP_MAX_SOURCE_FILTER = 0x400 + IP_MF = 0x2000 + IP_MINTTL = 0x42 + IP_MIN_MEMBERSHIPS = 0x1f + IP_MSFILTER = 0x4a + IP_MSS = 0x240 + IP_MULTICAST_IF = 0x9 + IP_MULTICAST_LOOP = 0xb + IP_MULTICAST_TTL = 0xa + IP_MULTICAST_VIF = 0xe + IP_OFFMASK = 0x1fff + IP_ONESBCAST = 0x17 + IP_OPTIONS = 0x1 + IP_PORTRANGE = 0x13 + IP_PORTRANGE_DEFAULT = 0x0 + IP_PORTRANGE_HIGH = 0x1 + IP_PORTRANGE_LOW = 0x2 + IP_RECVDSTADDR = 0x7 + IP_RECVFLOWID = 0x5d + IP_RECVIF = 0x14 + IP_RECVOPTS = 0x5 + IP_RECVRETOPTS = 0x6 + IP_RECVRSSBUCKETID = 0x5e + IP_RECVTOS = 0x44 + IP_RECVTTL = 0x41 + IP_RETOPTS = 0x8 + IP_RF = 0x8000 + IP_RSSBUCKETID = 0x5c + IP_RSS_LISTEN_BUCKET = 0x1a + IP_RSVP_OFF = 0x10 + IP_RSVP_ON = 0xf + IP_RSVP_VIF_OFF = 0x12 + IP_RSVP_VIF_ON = 0x11 + IP_SENDSRCADDR = 0x7 + IP_TOS = 0x3 + IP_TTL = 0x4 + IP_UNBLOCK_SOURCE = 0x49 + ISIG = 0x80 + ISTRIP = 0x20 + IXANY = 0x800 + IXOFF = 0x400 + IXON = 0x200 + KERN_HOSTNAME = 0xa + KERN_OSRELEASE = 0x2 + KERN_OSTYPE = 0x1 + KERN_VERSION = 0x4 + LOCK_EX = 0x2 + LOCK_NB = 0x4 + LOCK_SH = 0x1 + LOCK_UN = 0x8 + MADV_AUTOSYNC = 0x7 + MADV_CORE = 0x9 + MADV_DONTNEED = 0x4 + MADV_FREE = 0x5 + MADV_NOCORE = 0x8 + MADV_NORMAL = 0x0 + MADV_NOSYNC = 0x6 + MADV_PROTECT = 0xa + MADV_RANDOM = 0x1 + MADV_SEQUENTIAL = 0x2 + MADV_WILLNEED = 0x3 + MAP_32BIT = 0x80000 + MAP_ALIGNED_SUPER = 0x1000000 + MAP_ALIGNMENT_MASK = -0x1000000 + MAP_ALIGNMENT_SHIFT = 0x18 + MAP_ANON = 0x1000 + MAP_ANONYMOUS = 0x1000 + MAP_COPY = 0x2 + MAP_EXCL = 0x4000 + MAP_FILE = 0x0 + MAP_FIXED = 0x10 + MAP_HASSEMAPHORE = 0x200 + MAP_NOCORE = 0x20000 + MAP_NOSYNC = 0x800 + MAP_PREFAULT_READ = 0x40000 + MAP_PRIVATE = 0x2 + MAP_RESERVED0020 = 0x20 + MAP_RESERVED0040 = 0x40 + MAP_RESERVED0080 = 0x80 + MAP_RESERVED0100 = 0x100 + MAP_SHARED = 0x1 + MAP_STACK = 0x400 + MCL_CURRENT = 0x1 + MCL_FUTURE = 0x2 + MNT_ACLS = 0x8000000 + MNT_ASYNC = 0x40 + MNT_AUTOMOUNTED = 0x200000000 + MNT_BYFSID = 0x8000000 + MNT_CMDFLAGS = 0xd0f0000 + MNT_DEFEXPORTED = 0x200 + MNT_DELEXPORT = 0x20000 + MNT_EXKERB = 0x800 + MNT_EXPORTANON = 0x400 + MNT_EXPORTED = 0x100 + MNT_EXPUBLIC = 0x20000000 + MNT_EXRDONLY = 0x80 + MNT_FORCE = 0x80000 + MNT_GJOURNAL = 0x2000000 + MNT_IGNORE = 0x800000 + MNT_LAZY = 0x3 + MNT_LOCAL = 0x1000 + MNT_MULTILABEL = 0x4000000 + MNT_NFS4ACLS = 0x10 + MNT_NOATIME = 0x10000000 + MNT_NOCLUSTERR = 0x40000000 + MNT_NOCLUSTERW = 0x80000000 + MNT_NOEXEC = 0x4 + MNT_NONBUSY = 0x4000000 + MNT_NOSUID = 0x8 + MNT_NOSYMFOLLOW = 0x400000 + MNT_NOWAIT = 0x2 + MNT_QUOTA = 0x2000 + MNT_RDONLY = 0x1 + MNT_RELOAD = 0x40000 + MNT_ROOTFS = 0x4000 + MNT_SNAPSHOT = 0x1000000 + MNT_SOFTDEP = 0x200000 + MNT_SUIDDIR = 0x100000 + MNT_SUJ = 0x100000000 + MNT_SUSPEND = 0x4 + MNT_SYNCHRONOUS = 0x2 + MNT_UNION = 0x20 + MNT_UPDATE = 0x10000 + MNT_UPDATEMASK = 0x2d8d0807e + MNT_USER = 0x8000 + MNT_VISFLAGMASK = 0x3fef0ffff + MNT_WAIT = 0x1 + MSG_CMSG_CLOEXEC = 0x40000 + MSG_COMPAT = 0x8000 + MSG_CTRUNC = 0x20 + MSG_DONTROUTE = 0x4 + MSG_DONTWAIT = 0x80 + MSG_EOF = 0x100 + MSG_EOR = 0x8 + MSG_NBIO = 0x4000 + MSG_NOSIGNAL = 0x20000 + MSG_NOTIFICATION = 0x2000 + MSG_OOB = 0x1 + MSG_PEEK = 0x2 + MSG_TRUNC = 0x10 + MSG_WAITALL = 0x40 + MSG_WAITFORONE = 0x80000 + MS_ASYNC = 0x1 + MS_INVALIDATE = 0x2 + MS_SYNC = 0x0 + NAME_MAX = 0xff + NET_RT_DUMP = 0x1 + NET_RT_FLAGS = 0x2 + NET_RT_IFLIST = 0x3 + NET_RT_IFLISTL = 0x5 + NET_RT_IFMALIST = 0x4 + NOFLSH = 0x80000000 + NOKERNINFO = 0x2000000 + NOTE_ATTRIB = 0x8 + NOTE_CHILD = 0x4 + NOTE_CLOSE = 0x100 + NOTE_CLOSE_WRITE = 0x200 + NOTE_DELETE = 0x1 + NOTE_EXEC = 0x20000000 + NOTE_EXIT = 0x80000000 + NOTE_EXTEND = 0x4 + NOTE_FFAND = 0x40000000 + NOTE_FFCOPY = 0xc0000000 + NOTE_FFCTRLMASK = 0xc0000000 + NOTE_FFLAGSMASK = 0xffffff + NOTE_FFNOP = 0x0 + NOTE_FFOR = 0x80000000 + NOTE_FILE_POLL = 0x2 + NOTE_FORK = 0x40000000 + NOTE_LINK = 0x10 + NOTE_LOWAT = 0x1 + NOTE_MSECONDS = 0x2 + NOTE_NSECONDS = 0x8 + NOTE_OPEN = 0x80 + NOTE_PCTRLMASK = 0xf0000000 + NOTE_PDATAMASK = 0xfffff + NOTE_READ = 0x400 + NOTE_RENAME = 0x20 + NOTE_REVOKE = 0x40 + NOTE_SECONDS = 0x1 + NOTE_TRACK = 0x1 + NOTE_TRACKERR = 0x2 + NOTE_TRIGGER = 0x1000000 + NOTE_USECONDS = 0x4 + NOTE_WRITE = 0x2 + OCRNL = 0x10 + ONLCR = 0x2 + ONLRET = 0x40 + ONOCR = 0x20 + ONOEOT = 0x8 + OPOST = 0x1 + OXTABS = 0x4 + O_ACCMODE = 0x3 + O_APPEND = 0x8 + O_ASYNC = 0x40 + O_CLOEXEC = 0x100000 + O_CREAT = 0x200 + O_DIRECT = 0x10000 + O_DIRECTORY = 0x20000 + O_EXCL = 0x800 + O_EXEC = 0x40000 + O_EXLOCK = 0x20 + O_FSYNC = 0x80 + O_NDELAY = 0x4 + O_NOCTTY = 0x8000 + O_NOFOLLOW = 0x100 + O_NONBLOCK = 0x4 + O_RDONLY = 0x0 + O_RDWR = 0x2 + O_SHLOCK = 0x10 + O_SYNC = 0x80 + O_TRUNC = 0x400 + O_TTY_INIT = 0x80000 + O_VERIFY = 0x200000 + O_WRONLY = 0x1 + PARENB = 0x1000 + PARMRK = 0x8 + PARODD = 0x2000 + PENDIN = 0x20000000 + PRIO_PGRP = 0x1 + PRIO_PROCESS = 0x0 + PRIO_USER = 0x2 + PROT_EXEC = 0x4 + PROT_NONE = 0x0 + PROT_READ = 0x1 + PROT_WRITE = 0x2 + RLIMIT_AS = 0xa + RLIMIT_CORE = 0x4 + RLIMIT_CPU = 0x0 + RLIMIT_DATA = 0x2 + RLIMIT_FSIZE = 0x1 + RLIMIT_MEMLOCK = 0x6 + RLIMIT_NOFILE = 0x8 + RLIMIT_NPROC = 0x7 + RLIMIT_RSS = 0x5 + RLIMIT_STACK = 0x3 + RLIM_INFINITY = 0x7fffffffffffffff + RTAX_AUTHOR = 0x6 + RTAX_BRD = 0x7 + RTAX_DST = 0x0 + RTAX_GATEWAY = 0x1 + RTAX_GENMASK = 0x3 + RTAX_IFA = 0x5 + RTAX_IFP = 0x4 + RTAX_MAX = 0x8 + RTAX_NETMASK = 0x2 + RTA_AUTHOR = 0x40 + RTA_BRD = 0x80 + RTA_DST = 0x1 + RTA_GATEWAY = 0x2 + RTA_GENMASK = 0x8 + RTA_IFA = 0x20 + RTA_IFP = 0x10 + RTA_NETMASK = 0x4 + RTF_BLACKHOLE = 0x1000 + RTF_BROADCAST = 0x400000 + RTF_DONE = 0x40 + RTF_DYNAMIC = 0x10 + RTF_FIXEDMTU = 0x80000 + RTF_FMASK = 0x1004d808 + RTF_GATEWAY = 0x2 + RTF_GWFLAG_COMPAT = 0x80000000 + RTF_HOST = 0x4 + RTF_LLDATA = 0x400 + RTF_LLINFO = 0x400 + RTF_LOCAL = 0x200000 + RTF_MODIFIED = 0x20 + RTF_MULTICAST = 0x800000 + RTF_PINNED = 0x100000 + RTF_PROTO1 = 0x8000 + RTF_PROTO2 = 0x4000 + RTF_PROTO3 = 0x40000 + RTF_REJECT = 0x8 + RTF_RNH_LOCKED = 0x40000000 + RTF_STATIC = 0x800 + RTF_STICKY = 0x10000000 + RTF_UP = 0x1 + RTF_XRESOLVE = 0x200 + RTM_ADD = 0x1 + RTM_CHANGE = 0x3 + RTM_DELADDR = 0xd + RTM_DELETE = 0x2 + RTM_DELMADDR = 0x10 + RTM_GET = 0x4 + RTM_IEEE80211 = 0x12 + RTM_IFANNOUNCE = 0x11 + RTM_IFINFO = 0xe + RTM_LOCK = 0x8 + RTM_LOSING = 0x5 + RTM_MISS = 0x7 + RTM_NEWADDR = 0xc + RTM_NEWMADDR = 0xf + RTM_REDIRECT = 0x6 + RTM_RESOLVE = 0xb + RTM_RTTUNIT = 0xf4240 + RTM_VERSION = 0x5 + RTV_EXPIRE = 0x4 + RTV_HOPCOUNT = 0x2 + RTV_MTU = 0x1 + RTV_RPIPE = 0x8 + RTV_RTT = 0x40 + RTV_RTTVAR = 0x80 + RTV_SPIPE = 0x10 + RTV_SSTHRESH = 0x20 + RTV_WEIGHT = 0x100 + RT_ALL_FIBS = -0x1 + RT_BLACKHOLE = 0x40 + RT_CACHING_CONTEXT = 0x1 + RT_DEFAULT_FIB = 0x0 + RT_HAS_GW = 0x80 + RT_HAS_HEADER = 0x10 + RT_HAS_HEADER_BIT = 0x4 + RT_L2_ME = 0x4 + RT_L2_ME_BIT = 0x2 + RT_LLE_CACHE = 0x100 + RT_MAY_LOOP = 0x8 + RT_MAY_LOOP_BIT = 0x3 + RT_NORTREF = 0x2 + RT_REJECT = 0x20 + RUSAGE_CHILDREN = -0x1 + RUSAGE_SELF = 0x0 + RUSAGE_THREAD = 0x1 + SCM_BINTIME = 0x4 + SCM_CREDS = 0x3 + SCM_RIGHTS = 0x1 + SCM_TIMESTAMP = 0x2 + SHUT_RD = 0x0 + SHUT_RDWR = 0x2 + SHUT_WR = 0x1 + SIOCADDMULTI = 0x80206931 + SIOCAIFADDR = 0x8040691a + SIOCAIFGROUP = 0x80286987 + SIOCATMARK = 0x40047307 + SIOCDELMULTI = 0x80206932 + SIOCDIFADDR = 0x80206919 + SIOCDIFGROUP = 0x80286989 + SIOCDIFPHYADDR = 0x80206949 + SIOCGDRVSPEC = 0xc028697b + SIOCGETSGCNT = 0xc0207210 + SIOCGETVIFCNT = 0xc028720f + SIOCGHIWAT = 0x40047301 + SIOCGI2C = 0xc020693d + SIOCGIFADDR = 0xc0206921 + SIOCGIFBRDADDR = 0xc0206923 + SIOCGIFCAP = 0xc020691f + SIOCGIFCONF = 0xc0106924 + SIOCGIFDESCR = 0xc020692a + SIOCGIFDSTADDR = 0xc0206922 + SIOCGIFFIB = 0xc020695c + SIOCGIFFLAGS = 0xc0206911 + SIOCGIFGENERIC = 0xc020693a + SIOCGIFGMEMB = 0xc028698a + SIOCGIFGROUP = 0xc0286988 + SIOCGIFINDEX = 0xc0206920 + SIOCGIFMAC = 0xc0206926 + SIOCGIFMEDIA = 0xc0306938 + SIOCGIFMETRIC = 0xc0206917 + SIOCGIFMTU = 0xc0206933 + SIOCGIFNETMASK = 0xc0206925 + SIOCGIFPDSTADDR = 0xc0206948 + SIOCGIFPHYS = 0xc0206935 + SIOCGIFPSRCADDR = 0xc0206947 + SIOCGIFSTATUS = 0xc331693b + SIOCGIFXMEDIA = 0xc030698b + SIOCGLOWAT = 0x40047303 + SIOCGPGRP = 0x40047309 + SIOCGPRIVATE_0 = 0xc0206950 + SIOCGPRIVATE_1 = 0xc0206951 + SIOCGTUNFIB = 0xc020695e + SIOCIFCREATE = 0xc020697a + SIOCIFCREATE2 = 0xc020697c + SIOCIFDESTROY = 0x80206979 + SIOCIFGCLONERS = 0xc0106978 + SIOCSDRVSPEC = 0x8028697b + SIOCSHIWAT = 0x80047300 + SIOCSIFADDR = 0x8020690c + SIOCSIFBRDADDR = 0x80206913 + SIOCSIFCAP = 0x8020691e + SIOCSIFDESCR = 0x80206929 + SIOCSIFDSTADDR = 0x8020690e + SIOCSIFFIB = 0x8020695d + SIOCSIFFLAGS = 0x80206910 + SIOCSIFGENERIC = 0x80206939 + SIOCSIFLLADDR = 0x8020693c + SIOCSIFMAC = 0x80206927 + SIOCSIFMEDIA = 0xc0206937 + SIOCSIFMETRIC = 0x80206918 + SIOCSIFMTU = 0x80206934 + SIOCSIFNAME = 0x80206928 + SIOCSIFNETMASK = 0x80206916 + SIOCSIFPHYADDR = 0x80406946 + SIOCSIFPHYS = 0x80206936 + SIOCSIFRVNET = 0xc020695b + SIOCSIFVNET = 0xc020695a + SIOCSLOWAT = 0x80047302 + SIOCSPGRP = 0x80047308 + SIOCSTUNFIB = 0x8020695f + SOCK_CLOEXEC = 0x10000000 + SOCK_DGRAM = 0x2 + SOCK_MAXADDRLEN = 0xff + SOCK_NONBLOCK = 0x20000000 + SOCK_RAW = 0x3 + SOCK_RDM = 0x4 + SOCK_SEQPACKET = 0x5 + SOCK_STREAM = 0x1 + SOL_SOCKET = 0xffff + SOMAXCONN = 0x80 + SO_ACCEPTCONN = 0x2 + SO_ACCEPTFILTER = 0x1000 + SO_BINTIME = 0x2000 + SO_BROADCAST = 0x20 + SO_DEBUG = 0x1 + SO_DONTROUTE = 0x10 + SO_ERROR = 0x1007 + SO_KEEPALIVE = 0x8 + SO_LABEL = 0x1009 + SO_LINGER = 0x80 + SO_LISTENINCQLEN = 0x1013 + SO_LISTENQLEN = 0x1012 + SO_LISTENQLIMIT = 0x1011 + SO_NOSIGPIPE = 0x800 + SO_NO_DDP = 0x8000 + SO_NO_OFFLOAD = 0x4000 + SO_OOBINLINE = 0x100 + SO_PEERLABEL = 0x1010 + SO_PROTOCOL = 0x1016 + SO_PROTOTYPE = 0x1016 + SO_RCVBUF = 0x1002 + SO_RCVLOWAT = 0x1004 + SO_RCVTIMEO = 0x1006 + SO_REUSEADDR = 0x4 + SO_REUSEPORT = 0x200 + SO_SETFIB = 0x1014 + SO_SNDBUF = 0x1001 + SO_SNDLOWAT = 0x1003 + SO_SNDTIMEO = 0x1005 + SO_TIMESTAMP = 0x400 + SO_TYPE = 0x1008 + SO_USELOOPBACK = 0x40 + SO_USER_COOKIE = 0x1015 + SO_VENDOR = 0x80000000 + S_BLKSIZE = 0x200 + S_IEXEC = 0x40 + S_IFBLK = 0x6000 + S_IFCHR = 0x2000 + S_IFDIR = 0x4000 + S_IFIFO = 0x1000 + S_IFLNK = 0xa000 + S_IFMT = 0xf000 + S_IFREG = 0x8000 + S_IFSOCK = 0xc000 + S_IFWHT = 0xe000 + S_IREAD = 0x100 + S_IRGRP = 0x20 + S_IROTH = 0x4 + S_IRUSR = 0x100 + S_IRWXG = 0x38 + S_IRWXO = 0x7 + S_IRWXU = 0x1c0 + S_ISGID = 0x400 + S_ISTXT = 0x200 + S_ISUID = 0x800 + S_ISVTX = 0x200 + S_IWGRP = 0x10 + S_IWOTH = 0x2 + S_IWRITE = 0x80 + S_IWUSR = 0x80 + S_IXGRP = 0x8 + S_IXOTH = 0x1 + S_IXUSR = 0x40 + TAB0 = 0x0 + TAB3 = 0x4 + TABDLY = 0x4 + TCIFLUSH = 0x1 + TCIOFF = 0x3 + TCIOFLUSH = 0x3 + TCION = 0x4 + TCOFLUSH = 0x2 + TCOOFF = 0x1 + TCOON = 0x2 + TCP_CA_NAME_MAX = 0x10 + TCP_CCALGOOPT = 0x41 + TCP_CONGESTION = 0x40 + TCP_FASTOPEN = 0x401 + TCP_FUNCTION_BLK = 0x2000 + TCP_FUNCTION_NAME_LEN_MAX = 0x20 + TCP_INFO = 0x20 + TCP_KEEPCNT = 0x400 + TCP_KEEPIDLE = 0x100 + TCP_KEEPINIT = 0x80 + TCP_KEEPINTVL = 0x200 + TCP_MAXBURST = 0x4 + TCP_MAXHLEN = 0x3c + TCP_MAXOLEN = 0x28 + TCP_MAXSEG = 0x2 + TCP_MAXWIN = 0xffff + TCP_MAX_SACK = 0x4 + TCP_MAX_WINSHIFT = 0xe + TCP_MD5SIG = 0x10 + TCP_MINMSS = 0xd8 + TCP_MSS = 0x218 + TCP_NODELAY = 0x1 + TCP_NOOPT = 0x8 + TCP_NOPUSH = 0x4 + TCP_PCAP_IN = 0x1000 + TCP_PCAP_OUT = 0x800 + TCP_VENDOR = 0x80000000 + TCSAFLUSH = 0x2 + TIOCCBRK = 0x2000747a + TIOCCDTR = 0x20007478 + TIOCCONS = 0x80047462 + TIOCDRAIN = 0x2000745e + TIOCEXCL = 0x2000740d + TIOCEXT = 0x80047460 + TIOCFLUSH = 0x80047410 + TIOCGDRAINWAIT = 0x40047456 + TIOCGETA = 0x402c7413 + TIOCGETD = 0x4004741a + TIOCGPGRP = 0x40047477 + TIOCGPTN = 0x4004740f + TIOCGSID = 0x40047463 + TIOCGWINSZ = 0x40087468 + TIOCMBIC = 0x8004746b + TIOCMBIS = 0x8004746c + TIOCMGDTRWAIT = 0x4004745a + TIOCMGET = 0x4004746a + TIOCMSDTRWAIT = 0x8004745b + TIOCMSET = 0x8004746d + TIOCM_CAR = 0x40 + TIOCM_CD = 0x40 + TIOCM_CTS = 0x20 + TIOCM_DCD = 0x40 + TIOCM_DSR = 0x100 + TIOCM_DTR = 0x2 + TIOCM_LE = 0x1 + TIOCM_RI = 0x80 + TIOCM_RNG = 0x80 + TIOCM_RTS = 0x4 + TIOCM_SR = 0x10 + TIOCM_ST = 0x8 + TIOCNOTTY = 0x20007471 + TIOCNXCL = 0x2000740e + TIOCOUTQ = 0x40047473 + TIOCPKT = 0x80047470 + TIOCPKT_DATA = 0x0 + TIOCPKT_DOSTOP = 0x20 + TIOCPKT_FLUSHREAD = 0x1 + TIOCPKT_FLUSHWRITE = 0x2 + TIOCPKT_IOCTL = 0x40 + TIOCPKT_NOSTOP = 0x10 + TIOCPKT_START = 0x8 + TIOCPKT_STOP = 0x4 + TIOCPTMASTER = 0x2000741c + TIOCSBRK = 0x2000747b + TIOCSCTTY = 0x20007461 + TIOCSDRAINWAIT = 0x80047457 + TIOCSDTR = 0x20007479 + TIOCSETA = 0x802c7414 + TIOCSETAF = 0x802c7416 + TIOCSETAW = 0x802c7415 + TIOCSETD = 0x8004741b + TIOCSIG = 0x2004745f + TIOCSPGRP = 0x80047476 + TIOCSTART = 0x2000746e + TIOCSTAT = 0x20007465 + TIOCSTI = 0x80017472 + TIOCSTOP = 0x2000746f + TIOCSWINSZ = 0x80087467 + TIOCTIMESTAMP = 0x40107459 + TIOCUCNTL = 0x80047466 + TOSTOP = 0x400000 + VDISCARD = 0xf + VDSUSP = 0xb + VEOF = 0x0 + VEOL = 0x1 + VEOL2 = 0x2 + VERASE = 0x3 + VERASE2 = 0x7 + VINTR = 0x8 + VKILL = 0x5 + VLNEXT = 0xe + VMIN = 0x10 + VQUIT = 0x9 + VREPRINT = 0x6 + VSTART = 0xc + VSTATUS = 0x12 + VSTOP = 0xd + VSUSP = 0xa + VTIME = 0x11 + VWERASE = 0x4 + WCONTINUED = 0x4 + WCOREFLAG = 0x80 + WEXITED = 0x10 + WLINUXCLONE = 0x80000000 + WNOHANG = 0x1 + WNOWAIT = 0x8 + WSTOPPED = 0x2 + WTRAPPED = 0x20 + WUNTRACED = 0x2 +) + +// Errors +const ( + E2BIG = syscall.Errno(0x7) + EACCES = syscall.Errno(0xd) + EADDRINUSE = syscall.Errno(0x30) + EADDRNOTAVAIL = syscall.Errno(0x31) + EAFNOSUPPORT = syscall.Errno(0x2f) + EAGAIN = syscall.Errno(0x23) + EALREADY = syscall.Errno(0x25) + EAUTH = syscall.Errno(0x50) + EBADF = syscall.Errno(0x9) + EBADMSG = syscall.Errno(0x59) + EBADRPC = syscall.Errno(0x48) + EBUSY = syscall.Errno(0x10) + ECANCELED = syscall.Errno(0x55) + ECAPMODE = syscall.Errno(0x5e) + ECHILD = syscall.Errno(0xa) + ECONNABORTED = syscall.Errno(0x35) + ECONNREFUSED = syscall.Errno(0x3d) + ECONNRESET = syscall.Errno(0x36) + EDEADLK = syscall.Errno(0xb) + EDESTADDRREQ = syscall.Errno(0x27) + EDOM = syscall.Errno(0x21) + EDOOFUS = syscall.Errno(0x58) + EDQUOT = syscall.Errno(0x45) + EEXIST = syscall.Errno(0x11) + EFAULT = syscall.Errno(0xe) + EFBIG = syscall.Errno(0x1b) + EFTYPE = syscall.Errno(0x4f) + EHOSTDOWN = syscall.Errno(0x40) + EHOSTUNREACH = syscall.Errno(0x41) + EIDRM = syscall.Errno(0x52) + EILSEQ = syscall.Errno(0x56) + EINPROGRESS = syscall.Errno(0x24) + EINTR = syscall.Errno(0x4) + EINVAL = syscall.Errno(0x16) + EIO = syscall.Errno(0x5) + EISCONN = syscall.Errno(0x38) + EISDIR = syscall.Errno(0x15) + ELAST = syscall.Errno(0x60) + ELOOP = syscall.Errno(0x3e) + EMFILE = syscall.Errno(0x18) + EMLINK = syscall.Errno(0x1f) + EMSGSIZE = syscall.Errno(0x28) + EMULTIHOP = syscall.Errno(0x5a) + ENAMETOOLONG = syscall.Errno(0x3f) + ENEEDAUTH = syscall.Errno(0x51) + ENETDOWN = syscall.Errno(0x32) + ENETRESET = syscall.Errno(0x34) + ENETUNREACH = syscall.Errno(0x33) + ENFILE = syscall.Errno(0x17) + ENOATTR = syscall.Errno(0x57) + ENOBUFS = syscall.Errno(0x37) + ENODEV = syscall.Errno(0x13) + ENOENT = syscall.Errno(0x2) + ENOEXEC = syscall.Errno(0x8) + ENOLCK = syscall.Errno(0x4d) + ENOLINK = syscall.Errno(0x5b) + ENOMEM = syscall.Errno(0xc) + ENOMSG = syscall.Errno(0x53) + ENOPROTOOPT = syscall.Errno(0x2a) + ENOSPC = syscall.Errno(0x1c) + ENOSYS = syscall.Errno(0x4e) + ENOTBLK = syscall.Errno(0xf) + ENOTCAPABLE = syscall.Errno(0x5d) + ENOTCONN = syscall.Errno(0x39) + ENOTDIR = syscall.Errno(0x14) + ENOTEMPTY = syscall.Errno(0x42) + ENOTRECOVERABLE = syscall.Errno(0x5f) + ENOTSOCK = syscall.Errno(0x26) + ENOTSUP = syscall.Errno(0x2d) + ENOTTY = syscall.Errno(0x19) + ENXIO = syscall.Errno(0x6) + EOPNOTSUPP = syscall.Errno(0x2d) + EOVERFLOW = syscall.Errno(0x54) + EOWNERDEAD = syscall.Errno(0x60) + EPERM = syscall.Errno(0x1) + EPFNOSUPPORT = syscall.Errno(0x2e) + EPIPE = syscall.Errno(0x20) + EPROCLIM = syscall.Errno(0x43) + EPROCUNAVAIL = syscall.Errno(0x4c) + EPROGMISMATCH = syscall.Errno(0x4b) + EPROGUNAVAIL = syscall.Errno(0x4a) + EPROTO = syscall.Errno(0x5c) + EPROTONOSUPPORT = syscall.Errno(0x2b) + EPROTOTYPE = syscall.Errno(0x29) + ERANGE = syscall.Errno(0x22) + EREMOTE = syscall.Errno(0x47) + EROFS = syscall.Errno(0x1e) + ERPCMISMATCH = syscall.Errno(0x49) + ESHUTDOWN = syscall.Errno(0x3a) + ESOCKTNOSUPPORT = syscall.Errno(0x2c) + ESPIPE = syscall.Errno(0x1d) + ESRCH = syscall.Errno(0x3) + ESTALE = syscall.Errno(0x46) + ETIMEDOUT = syscall.Errno(0x3c) + ETOOMANYREFS = syscall.Errno(0x3b) + ETXTBSY = syscall.Errno(0x1a) + EUSERS = syscall.Errno(0x44) + EWOULDBLOCK = syscall.Errno(0x23) + EXDEV = syscall.Errno(0x12) +) + +// Signals +const ( + SIGABRT = syscall.Signal(0x6) + SIGALRM = syscall.Signal(0xe) + SIGBUS = syscall.Signal(0xa) + SIGCHLD = syscall.Signal(0x14) + SIGCONT = syscall.Signal(0x13) + SIGEMT = syscall.Signal(0x7) + SIGFPE = syscall.Signal(0x8) + SIGHUP = syscall.Signal(0x1) + SIGILL = syscall.Signal(0x4) + SIGINFO = syscall.Signal(0x1d) + SIGINT = syscall.Signal(0x2) + SIGIO = syscall.Signal(0x17) + SIGIOT = syscall.Signal(0x6) + SIGKILL = syscall.Signal(0x9) + SIGLIBRT = syscall.Signal(0x21) + SIGLWP = syscall.Signal(0x20) + SIGPIPE = syscall.Signal(0xd) + SIGPROF = syscall.Signal(0x1b) + SIGQUIT = syscall.Signal(0x3) + SIGSEGV = syscall.Signal(0xb) + SIGSTOP = syscall.Signal(0x11) + SIGSYS = syscall.Signal(0xc) + SIGTERM = syscall.Signal(0xf) + SIGTHR = syscall.Signal(0x20) + SIGTRAP = syscall.Signal(0x5) + SIGTSTP = syscall.Signal(0x12) + SIGTTIN = syscall.Signal(0x15) + SIGTTOU = syscall.Signal(0x16) + SIGURG = syscall.Signal(0x10) + SIGUSR1 = syscall.Signal(0x1e) + SIGUSR2 = syscall.Signal(0x1f) + SIGVTALRM = syscall.Signal(0x1a) + SIGWINCH = syscall.Signal(0x1c) + SIGXCPU = syscall.Signal(0x18) + SIGXFSZ = syscall.Signal(0x19) +) + +// Error table +var errorList = [...]struct { + num syscall.Errno + name string + desc string +}{ + {1, "EPERM", "operation not permitted"}, + {2, "ENOENT", "no such file or directory"}, + {3, "ESRCH", "no such process"}, + {4, "EINTR", "interrupted system call"}, + {5, "EIO", "input/output error"}, + {6, "ENXIO", "device not configured"}, + {7, "E2BIG", "argument list too long"}, + {8, "ENOEXEC", "exec format error"}, + {9, "EBADF", "bad file descriptor"}, + {10, "ECHILD", "no child processes"}, + {11, "EDEADLK", "resource deadlock avoided"}, + {12, "ENOMEM", "cannot allocate memory"}, + {13, "EACCES", "permission denied"}, + {14, "EFAULT", "bad address"}, + {15, "ENOTBLK", "block device required"}, + {16, "EBUSY", "device busy"}, + {17, "EEXIST", "file exists"}, + {18, "EXDEV", "cross-device link"}, + {19, "ENODEV", "operation not supported by device"}, + {20, "ENOTDIR", "not a directory"}, + {21, "EISDIR", "is a directory"}, + {22, "EINVAL", "invalid argument"}, + {23, "ENFILE", "too many open files in system"}, + {24, "EMFILE", "too many open files"}, + {25, "ENOTTY", "inappropriate ioctl for device"}, + {26, "ETXTBSY", "text file busy"}, + {27, "EFBIG", "file too large"}, + {28, "ENOSPC", "no space left on device"}, + {29, "ESPIPE", "illegal seek"}, + {30, "EROFS", "read-only file system"}, + {31, "EMLINK", "too many links"}, + {32, "EPIPE", "broken pipe"}, + {33, "EDOM", "numerical argument out of domain"}, + {34, "ERANGE", "result too large"}, + {35, "EAGAIN", "resource temporarily unavailable"}, + {36, "EINPROGRESS", "operation now in progress"}, + {37, "EALREADY", "operation already in progress"}, + {38, "ENOTSOCK", "socket operation on non-socket"}, + {39, "EDESTADDRREQ", "destination address required"}, + {40, "EMSGSIZE", "message too long"}, + {41, "EPROTOTYPE", "protocol wrong type for socket"}, + {42, "ENOPROTOOPT", "protocol not available"}, + {43, "EPROTONOSUPPORT", "protocol not supported"}, + {44, "ESOCKTNOSUPPORT", "socket type not supported"}, + {45, "EOPNOTSUPP", "operation not supported"}, + {46, "EPFNOSUPPORT", "protocol family not supported"}, + {47, "EAFNOSUPPORT", "address family not supported by protocol family"}, + {48, "EADDRINUSE", "address already in use"}, + {49, "EADDRNOTAVAIL", "can't assign requested address"}, + {50, "ENETDOWN", "network is down"}, + {51, "ENETUNREACH", "network is unreachable"}, + {52, "ENETRESET", "network dropped connection on reset"}, + {53, "ECONNABORTED", "software caused connection abort"}, + {54, "ECONNRESET", "connection reset by peer"}, + {55, "ENOBUFS", "no buffer space available"}, + {56, "EISCONN", "socket is already connected"}, + {57, "ENOTCONN", "socket is not connected"}, + {58, "ESHUTDOWN", "can't send after socket shutdown"}, + {59, "ETOOMANYREFS", "too many references: can't splice"}, + {60, "ETIMEDOUT", "operation timed out"}, + {61, "ECONNREFUSED", "connection refused"}, + {62, "ELOOP", "too many levels of symbolic links"}, + {63, "ENAMETOOLONG", "file name too long"}, + {64, "EHOSTDOWN", "host is down"}, + {65, "EHOSTUNREACH", "no route to host"}, + {66, "ENOTEMPTY", "directory not empty"}, + {67, "EPROCLIM", "too many processes"}, + {68, "EUSERS", "too many users"}, + {69, "EDQUOT", "disc quota exceeded"}, + {70, "ESTALE", "stale NFS file handle"}, + {71, "EREMOTE", "too many levels of remote in path"}, + {72, "EBADRPC", "RPC struct is bad"}, + {73, "ERPCMISMATCH", "RPC version wrong"}, + {74, "EPROGUNAVAIL", "RPC prog. not avail"}, + {75, "EPROGMISMATCH", "program version wrong"}, + {76, "EPROCUNAVAIL", "bad procedure for program"}, + {77, "ENOLCK", "no locks available"}, + {78, "ENOSYS", "function not implemented"}, + {79, "EFTYPE", "inappropriate file type or format"}, + {80, "EAUTH", "authentication error"}, + {81, "ENEEDAUTH", "need authenticator"}, + {82, "EIDRM", "identifier removed"}, + {83, "ENOMSG", "no message of desired type"}, + {84, "EOVERFLOW", "value too large to be stored in data type"}, + {85, "ECANCELED", "operation canceled"}, + {86, "EILSEQ", "illegal byte sequence"}, + {87, "ENOATTR", "attribute not found"}, + {88, "EDOOFUS", "programming error"}, + {89, "EBADMSG", "bad message"}, + {90, "EMULTIHOP", "multihop attempted"}, + {91, "ENOLINK", "link has been severed"}, + {92, "EPROTO", "protocol error"}, + {93, "ENOTCAPABLE", "capabilities insufficient"}, + {94, "ECAPMODE", "not permitted in capability mode"}, + {95, "ENOTRECOVERABLE", "state not recoverable"}, + {96, "EOWNERDEAD", "previous owner died"}, +} + +// Signal table +var signalList = [...]struct { + num syscall.Signal + name string + desc string +}{ + {1, "SIGHUP", "hangup"}, + {2, "SIGINT", "interrupt"}, + {3, "SIGQUIT", "quit"}, + {4, "SIGILL", "illegal instruction"}, + {5, "SIGTRAP", "trace/BPT trap"}, + {6, "SIGIOT", "abort trap"}, + {7, "SIGEMT", "EMT trap"}, + {8, "SIGFPE", "floating point exception"}, + {9, "SIGKILL", "killed"}, + {10, "SIGBUS", "bus error"}, + {11, "SIGSEGV", "segmentation fault"}, + {12, "SIGSYS", "bad system call"}, + {13, "SIGPIPE", "broken pipe"}, + {14, "SIGALRM", "alarm clock"}, + {15, "SIGTERM", "terminated"}, + {16, "SIGURG", "urgent I/O condition"}, + {17, "SIGSTOP", "suspended (signal)"}, + {18, "SIGTSTP", "suspended"}, + {19, "SIGCONT", "continued"}, + {20, "SIGCHLD", "child exited"}, + {21, "SIGTTIN", "stopped (tty input)"}, + {22, "SIGTTOU", "stopped (tty output)"}, + {23, "SIGIO", "I/O possible"}, + {24, "SIGXCPU", "cputime limit exceeded"}, + {25, "SIGXFSZ", "filesize limit exceeded"}, + {26, "SIGVTALRM", "virtual timer expired"}, + {27, "SIGPROF", "profiling timer expired"}, + {28, "SIGWINCH", "window size changes"}, + {29, "SIGINFO", "information request"}, + {30, "SIGUSR1", "user defined signal 1"}, + {31, "SIGUSR2", "user defined signal 2"}, + {32, "SIGTHR", "unknown signal"}, + {33, "SIGLIBRT", "unknown signal"}, +} diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_386.go b/vendor/golang.org/x/sys/unix/zerrors_linux_386.go index 8947248f68..cb89df8f54 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_386.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_386.go @@ -3,7 +3,7 @@ // +build 386,linux -// Created by cgo -godefs - DO NOT EDIT +// Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs -- -Wall -Werror -static -I/tmp/include -m32 _const.go package unix @@ -11,6 +11,11 @@ package unix import "syscall" const ( + AAFS_MAGIC = 0x5a3c69f0 + ADFS_SUPER_MAGIC = 0xadf5 + AFFS_SUPER_MAGIC = 0xadff + AFS_FS_MAGIC = 0x6b414653 + AFS_SUPER_MAGIC = 0x5346414f AF_ALG = 0x26 AF_APPLETALK = 0x5 AF_ASH = 0x12 @@ -36,7 +41,7 @@ const ( AF_KEY = 0xf AF_LLC = 0x1a AF_LOCAL = 0x1 - AF_MAX = 0x2c + AF_MAX = 0x2d AF_MPLS = 0x1c AF_NETBEUI = 0xd AF_NETLINK = 0x10 @@ -59,6 +64,7 @@ const ( AF_VSOCK = 0x28 AF_WANPIPE = 0x19 AF_X25 = 0x9 + AF_XDP = 0x2c ALG_OP_DECRYPT = 0x0 ALG_OP_ENCRYPT = 0x1 ALG_SET_AEAD_ASSOCLEN = 0x4 @@ -66,6 +72,7 @@ const ( ALG_SET_IV = 0x2 ALG_SET_KEY = 0x1 ALG_SET_OP = 0x3 + ANON_INODE_FS_MAGIC = 0x9041934 ARPHRD_6LOWPAN = 0x339 ARPHRD_ADAPT = 0x108 ARPHRD_APPLETLK = 0x8 @@ -121,6 +128,7 @@ const ( ARPHRD_PPP = 0x200 ARPHRD_PRONET = 0x4 ARPHRD_RAWHDLC = 0x206 + ARPHRD_RAWIP = 0x207 ARPHRD_ROSE = 0x10e ARPHRD_RSRVD = 0x104 ARPHRD_SIT = 0x308 @@ -132,6 +140,7 @@ const ( ARPHRD_VOID = 0xffff ARPHRD_VSOCKMON = 0x33a ARPHRD_X25 = 0x10f + AUTOFS_SUPER_MAGIC = 0x187 B0 = 0x0 B1000000 = 0x1008 B110 = 0x3 @@ -163,6 +172,9 @@ const ( B75 = 0x2 B921600 = 0x1007 B9600 = 0xd + BALLOON_KVM_MAGIC = 0x13661366 + BDEVFS_MAGIC = 0x62646576 + BINFMTFS_MAGIC = 0x42494e4d BLKBSZGET = 0x80041270 BLKBSZSET = 0x40041271 BLKFLSBUF = 0x1261 @@ -187,6 +199,7 @@ const ( BPF_AND = 0x50 BPF_B = 0x10 BPF_DIV = 0x30 + BPF_FS_MAGIC = 0xcafe4a11 BPF_H = 0x8 BPF_IMM = 0x0 BPF_IND = 0x40 @@ -228,6 +241,8 @@ const ( BS0 = 0x0 BS1 = 0x2000 BSDLY = 0x2000 + BTRFS_SUPER_MAGIC = 0x9123683e + BTRFS_TEST_MAGIC = 0x73727279 CAN_BCM = 0x2 CAN_EFF_FLAG = 0x80000000 CAN_EFF_ID_BITS = 0x1d @@ -251,6 +266,8 @@ const ( CBAUD = 0x100f CBAUDEX = 0x1000 CFLUSH = 0xf + CGROUP2_SUPER_MAGIC = 0x63677270 + CGROUP_SUPER_MAGIC = 0x27e0eb CIBAUD = 0x100f0000 CLOCAL = 0x800 CLOCK_BOOTTIME = 0x7 @@ -293,10 +310,12 @@ const ( CLONE_VFORK = 0x4000 CLONE_VM = 0x100 CMSPAR = 0x40000000 + CODA_SUPER_MAGIC = 0x73757245 CR0 = 0x0 CR1 = 0x200 CR2 = 0x400 CR3 = 0x600 + CRAMFS_MAGIC = 0x28cd3d45 CRDLY = 0x600 CREAD = 0x80 CRTSCTS = 0x80000000 @@ -311,6 +330,9 @@ const ( CSTOP = 0x13 CSTOPB = 0x40 CSUSP = 0x1a + DAXFS_MAGIC = 0x64646178 + DEBUGFS_MAGIC = 0x64626720 + DEVPTS_SUPER_MAGIC = 0x1cd1 DT_BLK = 0x6 DT_CHR = 0x2 DT_DIR = 0x4 @@ -327,9 +349,12 @@ const ( ECHOKE = 0x800 ECHONL = 0x40 ECHOPRT = 0x400 + ECRYPTFS_SUPER_MAGIC = 0xf15f EFD_CLOEXEC = 0x80000 EFD_NONBLOCK = 0x800 EFD_SEMAPHORE = 0x1 + EFIVARFS_MAGIC = 0xde5e81e4 + EFS_SUPER_MAGIC = 0x414a53 ENCODING_DEFAULT = 0x0 ENCODING_FM_MARK = 0x3 ENCODING_FM_SPACE = 0x4 @@ -390,6 +415,8 @@ const ( ETH_P_DSA = 0x1b ETH_P_ECONET = 0x18 ETH_P_EDSA = 0xdada + ETH_P_ERSPAN = 0x88be + ETH_P_ERSPAN2 = 0x22eb ETH_P_FCOE = 0x8906 ETH_P_FIP = 0x8914 ETH_P_HDLC = 0x19 @@ -398,6 +425,7 @@ const ( ETH_P_IEEE802154 = 0xf6 ETH_P_IEEEPUP = 0xa00 ETH_P_IEEEPUPAT = 0xa01 + ETH_P_IFE = 0xed3e ETH_P_IP = 0x800 ETH_P_IPV6 = 0x86dd ETH_P_IPX = 0x8137 @@ -408,11 +436,13 @@ const ( ETH_P_LOOP = 0x60 ETH_P_LOOPBACK = 0x9000 ETH_P_MACSEC = 0x88e5 + ETH_P_MAP = 0xf9 ETH_P_MOBITEX = 0x15 ETH_P_MPLS_MC = 0x8848 ETH_P_MPLS_UC = 0x8847 ETH_P_MVRP = 0x88f5 ETH_P_NCSI = 0x88f8 + ETH_P_NSH = 0x894f ETH_P_PAE = 0x888e ETH_P_PAUSE = 0x8808 ETH_P_PHONET = 0xf5 @@ -420,6 +450,7 @@ const ( ETH_P_PPP_DISC = 0x8863 ETH_P_PPP_MP = 0x8 ETH_P_PPP_SES = 0x8864 + ETH_P_PREAUTH = 0x88c7 ETH_P_PRP = 0x88fb ETH_P_PUP = 0x200 ETH_P_PUPAT = 0x201 @@ -440,9 +471,14 @@ const ( ETH_P_WCCP = 0x883e ETH_P_X25 = 0x805 ETH_P_XDSA = 0xf8 + EXABYTE_ENABLE_NEST = 0xf0 + EXT2_SUPER_MAGIC = 0xef53 + EXT3_SUPER_MAGIC = 0xef53 + EXT4_SUPER_MAGIC = 0xef53 EXTA = 0xe EXTB = 0xf EXTPROC = 0x10000 + F2FS_SUPER_MAGIC = 0xf2f52010 FALLOC_FL_COLLAPSE_RANGE = 0x8 FALLOC_FL_INSERT_RANGE = 0x20 FALLOC_FL_KEEP_SIZE = 0x1 @@ -456,6 +492,7 @@ const ( FF1 = 0x8000 FFDLY = 0x8000 FLUSHO = 0x1000 + FP_XSTATE_MAGIC2 = 0x46505845 FS_ENCRYPTION_MODE_AES_128_CBC = 0x5 FS_ENCRYPTION_MODE_AES_128_CTS = 0x6 FS_ENCRYPTION_MODE_AES_256_CBC = 0x3 @@ -463,6 +500,8 @@ const ( FS_ENCRYPTION_MODE_AES_256_GCM = 0x2 FS_ENCRYPTION_MODE_AES_256_XTS = 0x1 FS_ENCRYPTION_MODE_INVALID = 0x0 + FS_ENCRYPTION_MODE_SPECK128_256_CTS = 0x8 + FS_ENCRYPTION_MODE_SPECK128_256_XTS = 0x7 FS_IOC_GET_ENCRYPTION_POLICY = 0x400c6615 FS_IOC_GET_ENCRYPTION_PWSALT = 0x40106614 FS_IOC_SET_ENCRYPTION_POLICY = 0x800c6613 @@ -476,6 +515,8 @@ const ( FS_POLICY_FLAGS_PAD_8 = 0x1 FS_POLICY_FLAGS_PAD_MASK = 0x3 FS_POLICY_FLAGS_VALID = 0x3 + FUTEXFS_SUPER_MAGIC = 0xbad1dea + F_ADD_SEALS = 0x409 F_DUPFD = 0x0 F_DUPFD_CLOEXEC = 0x406 F_EXLCK = 0x4 @@ -488,6 +529,9 @@ const ( F_GETOWN_EX = 0x10 F_GETPIPE_SZ = 0x408 F_GETSIG = 0xb + F_GET_FILE_RW_HINT = 0x40d + F_GET_RW_HINT = 0x40b + F_GET_SEALS = 0x40a F_LOCK = 0x1 F_NOTIFY = 0x402 F_OFD_GETLK = 0x24 @@ -495,6 +539,10 @@ const ( F_OFD_SETLKW = 0x26 F_OK = 0x0 F_RDLCK = 0x0 + F_SEAL_GROW = 0x4 + F_SEAL_SEAL = 0x1 + F_SEAL_SHRINK = 0x2 + F_SEAL_WRITE = 0x8 F_SETFD = 0x2 F_SETFL = 0x4 F_SETLEASE = 0x400 @@ -506,6 +554,8 @@ const ( F_SETOWN_EX = 0xf F_SETPIPE_SZ = 0x407 F_SETSIG = 0xa + F_SET_FILE_RW_HINT = 0x40e + F_SET_RW_HINT = 0x40c F_SHLCK = 0x8 F_TEST = 0x3 F_TLOCK = 0x2 @@ -527,6 +577,49 @@ const ( GENL_UNS_ADMIN_PERM = 0x10 GRND_NONBLOCK = 0x1 GRND_RANDOM = 0x2 + HDIO_DRIVE_CMD = 0x31f + HDIO_DRIVE_CMD_AEB = 0x31e + HDIO_DRIVE_CMD_HDR_SIZE = 0x4 + HDIO_DRIVE_HOB_HDR_SIZE = 0x8 + HDIO_DRIVE_RESET = 0x31c + HDIO_DRIVE_TASK = 0x31e + HDIO_DRIVE_TASKFILE = 0x31d + HDIO_DRIVE_TASK_HDR_SIZE = 0x8 + HDIO_GETGEO = 0x301 + HDIO_GET_32BIT = 0x309 + HDIO_GET_ACOUSTIC = 0x30f + HDIO_GET_ADDRESS = 0x310 + HDIO_GET_BUSSTATE = 0x31a + HDIO_GET_DMA = 0x30b + HDIO_GET_IDENTITY = 0x30d + HDIO_GET_KEEPSETTINGS = 0x308 + HDIO_GET_MULTCOUNT = 0x304 + HDIO_GET_NICE = 0x30c + HDIO_GET_NOWERR = 0x30a + HDIO_GET_QDMA = 0x305 + HDIO_GET_UNMASKINTR = 0x302 + HDIO_GET_WCACHE = 0x30e + HDIO_OBSOLETE_IDENTITY = 0x307 + HDIO_SCAN_HWIF = 0x328 + HDIO_SET_32BIT = 0x324 + HDIO_SET_ACOUSTIC = 0x32c + HDIO_SET_ADDRESS = 0x32f + HDIO_SET_BUSSTATE = 0x32d + HDIO_SET_DMA = 0x326 + HDIO_SET_KEEPSETTINGS = 0x323 + HDIO_SET_MULTCOUNT = 0x321 + HDIO_SET_NICE = 0x329 + HDIO_SET_NOWERR = 0x325 + HDIO_SET_PIO_MODE = 0x327 + HDIO_SET_QDMA = 0x32e + HDIO_SET_UNMASKINTR = 0x322 + HDIO_SET_WCACHE = 0x32b + HDIO_SET_XFER = 0x306 + HDIO_TRISTATE_HWIF = 0x31b + HDIO_UNREGISTER_HWIF = 0x32a + HOSTFS_SUPER_MAGIC = 0xc0ffee + HPFS_SUPER_MAGIC = 0xf995e849 + HUGETLBFS_MAGIC = 0x958458f6 HUPCL = 0x400 IBSHIFT = 0x10 ICANON = 0x2 @@ -546,7 +639,7 @@ const ( IFA_F_STABLE_PRIVACY = 0x800 IFA_F_TEMPORARY = 0x1 IFA_F_TENTATIVE = 0x40 - IFA_MAX = 0x8 + IFA_MAX = 0xa IFF_ALLMULTI = 0x200 IFF_ATTACH_QUEUE = 0x200 IFF_AUTOMEDIA = 0x4000 @@ -561,6 +654,8 @@ const ( IFF_MASTER = 0x400 IFF_MULTICAST = 0x1000 IFF_MULTI_QUEUE = 0x100 + IFF_NAPI = 0x10 + IFF_NAPI_FRAGS = 0x20 IFF_NOARP = 0x80 IFF_NOFILTER = 0x1000 IFF_NOTRAILERS = 0x20 @@ -612,6 +707,7 @@ const ( IN_ISDIR = 0x40000000 IN_LOOPBACKNET = 0x7f IN_MASK_ADD = 0x20000000 + IN_MASK_CREATE = 0x10000000 IN_MODIFY = 0x2 IN_MOVE = 0xc0 IN_MOVED_FROM = 0x40 @@ -671,6 +767,7 @@ const ( IPV6_DONTFRAG = 0x3e IPV6_DROP_MEMBERSHIP = 0x15 IPV6_DSTOPTS = 0x3b + IPV6_FREEBIND = 0x4e IPV6_HDRINCL = 0x24 IPV6_HOPLIMIT = 0x34 IPV6_HOPOPTS = 0x36 @@ -682,6 +779,7 @@ const ( IPV6_MINHOPCOUNT = 0x49 IPV6_MTU = 0x18 IPV6_MTU_DISCOVER = 0x17 + IPV6_MULTICAST_ALL = 0x1d IPV6_MULTICAST_HOPS = 0x12 IPV6_MULTICAST_IF = 0x11 IPV6_MULTICAST_LOOP = 0x13 @@ -775,12 +873,34 @@ const ( IP_UNICAST_IF = 0x32 IP_XFRM_POLICY = 0x11 ISIG = 0x1 + ISOFS_SUPER_MAGIC = 0x9660 ISTRIP = 0x20 IUCLC = 0x200 IUTF8 = 0x4000 IXANY = 0x800 IXOFF = 0x1000 IXON = 0x400 + JFFS2_SUPER_MAGIC = 0x72b6 + KEXEC_ARCH_386 = 0x30000 + KEXEC_ARCH_68K = 0x40000 + KEXEC_ARCH_AARCH64 = 0xb70000 + KEXEC_ARCH_ARM = 0x280000 + KEXEC_ARCH_DEFAULT = 0x0 + KEXEC_ARCH_IA_64 = 0x320000 + KEXEC_ARCH_MASK = 0xffff0000 + KEXEC_ARCH_MIPS = 0x80000 + KEXEC_ARCH_MIPS_LE = 0xa0000 + KEXEC_ARCH_PPC = 0x140000 + KEXEC_ARCH_PPC64 = 0x150000 + KEXEC_ARCH_S390 = 0x160000 + KEXEC_ARCH_SH = 0x2a0000 + KEXEC_ARCH_X86_64 = 0x3e0000 + KEXEC_FILE_NO_INITRAMFS = 0x4 + KEXEC_FILE_ON_CRASH = 0x2 + KEXEC_FILE_UNLOAD = 0x1 + KEXEC_ON_CRASH = 0x1 + KEXEC_PRESERVE_CONTEXT = 0x2 + KEXEC_SEGMENT_MAX = 0x10 KEYCTL_ASSUME_AUTHORITY = 0x10 KEYCTL_CHOWN = 0x4 KEYCTL_CLEAR = 0x7 @@ -795,6 +915,11 @@ const ( KEYCTL_JOIN_SESSION_KEYRING = 0x1 KEYCTL_LINK = 0x8 KEYCTL_NEGATE = 0xd + KEYCTL_PKEY_DECRYPT = 0x1a + KEYCTL_PKEY_ENCRYPT = 0x19 + KEYCTL_PKEY_QUERY = 0x18 + KEYCTL_PKEY_SIGN = 0x1b + KEYCTL_PKEY_VERIFY = 0x1c KEYCTL_READ = 0xb KEYCTL_REJECT = 0x13 KEYCTL_RESTRICT_KEYRING = 0x1d @@ -804,6 +929,10 @@ const ( KEYCTL_SETPERM = 0x5 KEYCTL_SET_REQKEY_KEYRING = 0xe KEYCTL_SET_TIMEOUT = 0xf + KEYCTL_SUPPORTS_DECRYPT = 0x2 + KEYCTL_SUPPORTS_ENCRYPT = 0x1 + KEYCTL_SUPPORTS_SIGN = 0x4 + KEYCTL_SUPPORTS_VERIFY = 0x8 KEYCTL_UNLINK = 0x9 KEYCTL_UPDATE = 0x2 KEY_REQKEY_DEFL_DEFAULT = 0x0 @@ -845,6 +974,7 @@ const ( MADV_FREE = 0x8 MADV_HUGEPAGE = 0xe MADV_HWPOISON = 0x64 + MADV_KEEPONFORK = 0x13 MADV_MERGEABLE = 0xc MADV_NOHUGEPAGE = 0xf MADV_NORMAL = 0x0 @@ -853,6 +983,7 @@ const ( MADV_SEQUENTIAL = 0x2 MADV_UNMERGEABLE = 0xd MADV_WILLNEED = 0x3 + MADV_WIPEONFORK = 0x12 MAP_32BIT = 0x40 MAP_ANON = 0x20 MAP_ANONYMOUS = 0x20 @@ -860,6 +991,7 @@ const ( MAP_EXECUTABLE = 0x1000 MAP_FILE = 0x0 MAP_FIXED = 0x10 + MAP_FIXED_NOREPLACE = 0x100000 MAP_GROWSDOWN = 0x100 MAP_HUGETLB = 0x40000 MAP_HUGE_MASK = 0x3f @@ -870,14 +1002,41 @@ const ( MAP_POPULATE = 0x8000 MAP_PRIVATE = 0x2 MAP_SHARED = 0x1 + MAP_SHARED_VALIDATE = 0x3 MAP_STACK = 0x20000 + MAP_SYNC = 0x80000 MAP_TYPE = 0xf MCL_CURRENT = 0x1 MCL_FUTURE = 0x2 MCL_ONFAULT = 0x4 + MFD_ALLOW_SEALING = 0x2 + MFD_CLOEXEC = 0x1 + MFD_HUGETLB = 0x4 + MFD_HUGE_16GB = -0x78000000 + MFD_HUGE_16MB = 0x60000000 + MFD_HUGE_1GB = 0x78000000 + MFD_HUGE_1MB = 0x50000000 + MFD_HUGE_256MB = 0x70000000 + MFD_HUGE_2GB = 0x7c000000 + MFD_HUGE_2MB = 0x54000000 + MFD_HUGE_32MB = 0x64000000 + MFD_HUGE_512KB = 0x4c000000 + MFD_HUGE_512MB = 0x74000000 + MFD_HUGE_64KB = 0x40000000 + MFD_HUGE_8MB = 0x5c000000 + MFD_HUGE_MASK = 0x3f + MFD_HUGE_SHIFT = 0x1a + MINIX2_SUPER_MAGIC = 0x2468 + MINIX2_SUPER_MAGIC2 = 0x2478 + MINIX3_SUPER_MAGIC = 0x4d5a + MINIX_SUPER_MAGIC = 0x137f + MINIX_SUPER_MAGIC2 = 0x138f MNT_DETACH = 0x2 MNT_EXPIRE = 0x4 MNT_FORCE = 0x1 + MODULE_INIT_IGNORE_MODVERSIONS = 0x1 + MODULE_INIT_IGNORE_VERMAGIC = 0x2 + MSDOS_SUPER_MAGIC = 0x4d44 MSG_BATCH = 0x40000 MSG_CMSG_CLOEXEC = 0x40000000 MSG_CONFIRM = 0x800 @@ -899,6 +1058,7 @@ const ( MSG_TRYHARD = 0x4 MSG_WAITALL = 0x100 MSG_WAITFORONE = 0x10000 + MSG_ZEROCOPY = 0x4000000 MS_ACTIVE = 0x40000000 MS_ASYNC = 0x1 MS_BIND = 0x1000 @@ -936,7 +1096,9 @@ const ( MS_SYNCHRONOUS = 0x10 MS_UNBINDABLE = 0x20000 MS_VERBOSE = 0x8000 + MTD_INODE_FS_MAGIC = 0x11307854 NAME_MAX = 0xff + NCP_SUPER_MAGIC = 0x564c NETLINK_ADD_MEMBERSHIP = 0x1 NETLINK_AUDIT = 0x9 NETLINK_BROADCAST_ERROR = 0x4 @@ -950,6 +1112,7 @@ const ( NETLINK_FIB_LOOKUP = 0xa NETLINK_FIREWALL = 0x3 NETLINK_GENERIC = 0x10 + NETLINK_GET_STRICT_CHK = 0xc NETLINK_INET_DIAG = 0x4 NETLINK_IP6_FW = 0xd NETLINK_ISCSI = 0x8 @@ -971,6 +1134,39 @@ const ( NETLINK_UNUSED = 0x1 NETLINK_USERSOCK = 0x2 NETLINK_XFRM = 0x6 + NETNSA_MAX = 0x3 + NETNSA_NSID_NOT_ASSIGNED = -0x1 + NFNETLINK_V0 = 0x0 + NFNLGRP_ACCT_QUOTA = 0x8 + NFNLGRP_CONNTRACK_DESTROY = 0x3 + NFNLGRP_CONNTRACK_EXP_DESTROY = 0x6 + NFNLGRP_CONNTRACK_EXP_NEW = 0x4 + NFNLGRP_CONNTRACK_EXP_UPDATE = 0x5 + NFNLGRP_CONNTRACK_NEW = 0x1 + NFNLGRP_CONNTRACK_UPDATE = 0x2 + NFNLGRP_MAX = 0x9 + NFNLGRP_NFTABLES = 0x7 + NFNLGRP_NFTRACE = 0x9 + NFNLGRP_NONE = 0x0 + NFNL_BATCH_MAX = 0x1 + NFNL_MSG_BATCH_BEGIN = 0x10 + NFNL_MSG_BATCH_END = 0x11 + NFNL_NFA_NEST = 0x8000 + NFNL_SUBSYS_ACCT = 0x7 + NFNL_SUBSYS_COUNT = 0xc + NFNL_SUBSYS_CTHELPER = 0x9 + NFNL_SUBSYS_CTNETLINK = 0x1 + NFNL_SUBSYS_CTNETLINK_EXP = 0x2 + NFNL_SUBSYS_CTNETLINK_TIMEOUT = 0x8 + NFNL_SUBSYS_IPSET = 0x6 + NFNL_SUBSYS_NFTABLES = 0xa + NFNL_SUBSYS_NFT_COMPAT = 0xb + NFNL_SUBSYS_NONE = 0x0 + NFNL_SUBSYS_OSF = 0x5 + NFNL_SUBSYS_QUEUE = 0x3 + NFNL_SUBSYS_ULOG = 0x4 + NFS_SUPER_MAGIC = 0x6969 + NILFS_SUPER_MAGIC = 0x3434 NL0 = 0x0 NL1 = 0x100 NLA_ALIGNTO = 0x4 @@ -998,10 +1194,13 @@ const ( NLM_F_EXCL = 0x200 NLM_F_MATCH = 0x200 NLM_F_MULTI = 0x2 + NLM_F_NONREC = 0x100 NLM_F_REPLACE = 0x100 NLM_F_REQUEST = 0x1 NLM_F_ROOT = 0x100 NOFLSH = 0x80 + NSFS_MAGIC = 0x6e736673 + OCFS2_SUPER_MAGIC = 0x7461636f OCRNL = 0x8 OFDEL = 0x80 OFILL = 0x40 @@ -1009,7 +1208,9 @@ const ( ONLCR = 0x4 ONLRET = 0x20 ONOCR = 0x10 + OPENPROM_SUPER_MAGIC = 0x9fa1 OPOST = 0x1 + OVERLAYFS_SUPER_MAGIC = 0x794c7630 O_ACCMODE = 0x3 O_APPEND = 0x400 O_ASYNC = 0x2000 @@ -1055,6 +1256,7 @@ const ( PACKET_FASTROUTE = 0x6 PACKET_HDRLEN = 0xb PACKET_HOST = 0x0 + PACKET_IGNORE_OUTGOING = 0x17 PACKET_KERNEL = 0x7 PACKET_LOOPBACK = 0x5 PACKET_LOSS = 0xe @@ -1094,16 +1296,50 @@ const ( PERF_EVENT_IOC_DISABLE = 0x2401 PERF_EVENT_IOC_ENABLE = 0x2400 PERF_EVENT_IOC_ID = 0x80042407 + PERF_EVENT_IOC_MODIFY_ATTRIBUTES = 0x4004240b PERF_EVENT_IOC_PAUSE_OUTPUT = 0x40042409 PERF_EVENT_IOC_PERIOD = 0x40082404 + PERF_EVENT_IOC_QUERY_BPF = 0xc004240a PERF_EVENT_IOC_REFRESH = 0x2402 PERF_EVENT_IOC_RESET = 0x2403 PERF_EVENT_IOC_SET_BPF = 0x40042408 PERF_EVENT_IOC_SET_FILTER = 0x40042406 PERF_EVENT_IOC_SET_OUTPUT = 0x2405 + PIPEFS_MAGIC = 0x50495045 + PPPIOCATTACH = 0x4004743d + PPPIOCATTCHAN = 0x40047438 + PPPIOCCONNECT = 0x4004743a + PPPIOCDETACH = 0x4004743c + PPPIOCDISCONN = 0x7439 + PPPIOCGASYNCMAP = 0x80047458 + PPPIOCGCHAN = 0x80047437 + PPPIOCGDEBUG = 0x80047441 + PPPIOCGFLAGS = 0x8004745a + PPPIOCGIDLE = 0x8008743f + PPPIOCGL2TPSTATS = 0x80487436 + PPPIOCGMRU = 0x80047453 + PPPIOCGNPMODE = 0xc008744c + PPPIOCGRASYNCMAP = 0x80047455 + PPPIOCGUNIT = 0x80047456 + PPPIOCGXASYNCMAP = 0x80207450 + PPPIOCNEWUNIT = 0xc004743e + PPPIOCSACTIVE = 0x40087446 + PPPIOCSASYNCMAP = 0x40047457 + PPPIOCSCOMPRESS = 0x400c744d + PPPIOCSDEBUG = 0x40047440 + PPPIOCSFLAGS = 0x40047459 + PPPIOCSMAXCID = 0x40047451 + PPPIOCSMRRU = 0x4004743b + PPPIOCSMRU = 0x40047452 + PPPIOCSNPMODE = 0x4008744b + PPPIOCSPASS = 0x40087447 + PPPIOCSRASYNCMAP = 0x40047454 + PPPIOCSXASYNCMAP = 0x4020744f + PPPIOCXFERUNIT = 0x744e PRIO_PGRP = 0x1 PRIO_PROCESS = 0x0 PRIO_USER = 0x2 + PROC_SUPER_MAGIC = 0x9fa0 PROT_EXEC = 0x4 PROT_GROWSDOWN = 0x1000000 PROT_GROWSUP = 0x2000000 @@ -1146,6 +1382,7 @@ const ( PR_GET_PDEATHSIG = 0x2 PR_GET_SECCOMP = 0x15 PR_GET_SECUREBITS = 0x1b + PR_GET_SPECULATION_CTRL = 0x34 PR_GET_THP_DISABLE = 0x2a PR_GET_TID_ADDRESS = 0x28 PR_GET_TIMERSLACK = 0x1e @@ -1191,11 +1428,24 @@ const ( PR_SET_PTRACER_ANY = 0xffffffff PR_SET_SECCOMP = 0x16 PR_SET_SECUREBITS = 0x1c + PR_SET_SPECULATION_CTRL = 0x35 PR_SET_THP_DISABLE = 0x29 PR_SET_TIMERSLACK = 0x1d PR_SET_TIMING = 0xe PR_SET_TSC = 0x1a PR_SET_UNALIGN = 0x6 + PR_SPEC_DISABLE = 0x4 + PR_SPEC_ENABLE = 0x2 + PR_SPEC_FORCE_DISABLE = 0x8 + PR_SPEC_INDIRECT_BRANCH = 0x1 + PR_SPEC_NOT_AFFECTED = 0x0 + PR_SPEC_PRCTL = 0x1 + PR_SPEC_STORE_BYPASS = 0x0 + PR_SVE_GET_VL = 0x33 + PR_SVE_SET_VL = 0x32 + PR_SVE_SET_VL_ONEXEC = 0x40000 + PR_SVE_VL_INHERIT = 0x20000 + PR_SVE_VL_LEN_MASK = 0xffff PR_TASK_PERF_EVENTS_DISABLE = 0x1f PR_TASK_PERF_EVENTS_ENABLE = 0x20 PR_TIMING_STATISTICAL = 0x0 @@ -1204,6 +1454,7 @@ const ( PR_TSC_SIGSEGV = 0x2 PR_UNALIGN_NOPRINT = 0x1 PR_UNALIGN_SIGBUS = 0x2 + PSTOREFS_MAGIC = 0x6165676c PTRACE_ATTACH = 0x10 PTRACE_CONT = 0x7 PTRACE_DETACH = 0x11 @@ -1247,6 +1498,7 @@ const ( PTRACE_POKETEXT = 0x4 PTRACE_POKEUSR = 0x6 PTRACE_SECCOMP_GET_FILTER = 0x420c + PTRACE_SECCOMP_GET_METADATA = 0x420d PTRACE_SEIZE = 0x4206 PTRACE_SETFPREGS = 0xf PTRACE_SETFPXREGS = 0x13 @@ -1262,6 +1514,14 @@ const ( PTRACE_SYSEMU = 0x1f PTRACE_SYSEMU_SINGLESTEP = 0x20 PTRACE_TRACEME = 0x0 + QNX4_SUPER_MAGIC = 0x2f + QNX6_SUPER_MAGIC = 0x68191122 + RAMFS_MAGIC = 0x858458f6 + RDTGROUP_SUPER_MAGIC = 0x7655821 + REISERFS_SUPER_MAGIC = 0x52654973 + RENAME_EXCHANGE = 0x2 + RENAME_NOREPLACE = 0x1 + RENAME_WHITEOUT = 0x4 RLIMIT_AS = 0x9 RLIMIT_CORE = 0x4 RLIMIT_CPU = 0x0 @@ -1279,9 +1539,17 @@ const ( RLIMIT_SIGPENDING = 0xb RLIMIT_STACK = 0x3 RLIM_INFINITY = 0xffffffffffffffff + RNDADDENTROPY = 0x40085203 + RNDADDTOENTCNT = 0x40045201 + RNDCLEARPOOL = 0x5206 + RNDGETENTCNT = 0x80045200 + RNDGETPOOL = 0x80085202 + RNDRESEEDCRNG = 0x5207 + RNDZAPENTCNT = 0x5204 RTAX_ADVMSS = 0x8 RTAX_CC_ALGO = 0x10 RTAX_CWND = 0x7 + RTAX_FASTOPEN_NO_COOKIE = 0x11 RTAX_FEATURES = 0xc RTAX_FEATURE_ALLFRAG = 0x8 RTAX_FEATURE_ECN = 0x1 @@ -1292,7 +1560,7 @@ const ( RTAX_INITCWND = 0xb RTAX_INITRWND = 0xe RTAX_LOCK = 0x1 - RTAX_MAX = 0x10 + RTAX_MAX = 0x11 RTAX_MTU = 0x2 RTAX_QUICKACK = 0xf RTAX_REORDERING = 0x9 @@ -1303,13 +1571,40 @@ const ( RTAX_UNSPEC = 0x0 RTAX_WINDOW = 0x3 RTA_ALIGNTO = 0x4 - RTA_MAX = 0x1a + RTA_MAX = 0x1d RTCF_DIRECTSRC = 0x4000000 RTCF_DOREDIRECT = 0x1000000 RTCF_LOG = 0x2000000 RTCF_MASQ = 0x400000 RTCF_NAT = 0x800000 RTCF_VALVE = 0x200000 + RTC_AF = 0x20 + RTC_AIE_OFF = 0x7002 + RTC_AIE_ON = 0x7001 + RTC_ALM_READ = 0x80247008 + RTC_ALM_SET = 0x40247007 + RTC_EPOCH_READ = 0x8004700d + RTC_EPOCH_SET = 0x4004700e + RTC_IRQF = 0x80 + RTC_IRQP_READ = 0x8004700b + RTC_IRQP_SET = 0x4004700c + RTC_MAX_FREQ = 0x2000 + RTC_PF = 0x40 + RTC_PIE_OFF = 0x7006 + RTC_PIE_ON = 0x7005 + RTC_PLL_GET = 0x801c7011 + RTC_PLL_SET = 0x401c7012 + RTC_RD_TIME = 0x80247009 + RTC_SET_TIME = 0x4024700a + RTC_UF = 0x10 + RTC_UIE_OFF = 0x7004 + RTC_UIE_ON = 0x7003 + RTC_VL_CLR = 0x7014 + RTC_VL_READ = 0x80047013 + RTC_WIE_OFF = 0x7010 + RTC_WIE_ON = 0x700f + RTC_WKALM_RD = 0x80287010 + RTC_WKALM_SET = 0x4028700f RTF_ADDRCLASSMASK = 0xf8000000 RTF_ADDRCONF = 0x40000 RTF_ALLONLINK = 0x20000 @@ -1344,6 +1639,7 @@ const ( RTM_DELACTION = 0x31 RTM_DELADDR = 0x15 RTM_DELADDRLABEL = 0x49 + RTM_DELCHAIN = 0x65 RTM_DELLINK = 0x11 RTM_DELMDB = 0x55 RTM_DELNEIGH = 0x1d @@ -1364,6 +1660,7 @@ const ( RTM_GETADDR = 0x16 RTM_GETADDRLABEL = 0x4a RTM_GETANYCAST = 0x3e + RTM_GETCHAIN = 0x66 RTM_GETDCB = 0x4e RTM_GETLINK = 0x12 RTM_GETMDB = 0x56 @@ -1378,11 +1675,12 @@ const ( RTM_GETSTATS = 0x5e RTM_GETTCLASS = 0x2a RTM_GETTFILTER = 0x2e - RTM_MAX = 0x63 + RTM_MAX = 0x67 RTM_NEWACTION = 0x30 RTM_NEWADDR = 0x14 RTM_NEWADDRLABEL = 0x48 RTM_NEWCACHEREPORT = 0x60 + RTM_NEWCHAIN = 0x64 RTM_NEWLINK = 0x10 RTM_NEWMDB = 0x54 RTM_NEWNDUSEROPT = 0x44 @@ -1397,8 +1695,8 @@ const ( RTM_NEWSTATS = 0x5c RTM_NEWTCLASS = 0x28 RTM_NEWTFILTER = 0x2c - RTM_NR_FAMILIES = 0x15 - RTM_NR_MSGTYPES = 0x54 + RTM_NR_FAMILIES = 0x16 + RTM_NR_MSGTYPES = 0x58 RTM_SETDCB = 0x4f RTM_SETLINK = 0x13 RTM_SETNEIGHTBL = 0x43 @@ -1412,17 +1710,22 @@ const ( RTNH_F_UNRESOLVED = 0x20 RTN_MAX = 0xb RTPROT_BABEL = 0x2a + RTPROT_BGP = 0xba RTPROT_BIRD = 0xc RTPROT_BOOT = 0x3 RTPROT_DHCP = 0x10 RTPROT_DNROUTED = 0xd + RTPROT_EIGRP = 0xc0 RTPROT_GATED = 0x8 + RTPROT_ISIS = 0xbb RTPROT_KERNEL = 0x2 RTPROT_MROUTED = 0x11 RTPROT_MRT = 0xa RTPROT_NTK = 0xf + RTPROT_OSPF = 0xbc RTPROT_RA = 0x9 RTPROT_REDIRECT = 0x1 + RTPROT_RIP = 0xbd RTPROT_STATIC = 0x4 RTPROT_UNSPEC = 0x0 RTPROT_XORP = 0xe @@ -1442,10 +1745,16 @@ const ( SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SC_LOG_FLUSH = 0x100000 SECCOMP_MODE_DISABLED = 0x0 SECCOMP_MODE_FILTER = 0x2 SECCOMP_MODE_STRICT = 0x1 + SECURITYFS_MAGIC = 0x73636673 + SELINUX_MAGIC = 0xf97cff8c + SFD_CLOEXEC = 0x80000 + SFD_NONBLOCK = 0x800 SHUT_RD = 0x0 SHUT_RDWR = 0x2 SHUT_WR = 0x1 @@ -1496,6 +1805,9 @@ const ( SIOCGMIIPHY = 0x8947 SIOCGMIIREG = 0x8948 SIOCGPGRP = 0x8904 + SIOCGPPPCSTATS = 0x89f2 + SIOCGPPPSTATS = 0x89f0 + SIOCGPPPVER = 0x89f1 SIOCGRARP = 0x8961 SIOCGSKNS = 0x894c SIOCGSTAMP = 0x8906 @@ -1530,6 +1842,23 @@ const ( SIOCSPGRP = 0x8902 SIOCSRARP = 0x8962 SIOCWANDEV = 0x894a + SMACK_MAGIC = 0x43415d53 + SMART_AUTOSAVE = 0xd2 + SMART_AUTO_OFFLINE = 0xdb + SMART_DISABLE = 0xd9 + SMART_ENABLE = 0xd8 + SMART_HCYL_PASS = 0xc2 + SMART_IMMEDIATE_OFFLINE = 0xd4 + SMART_LCYL_PASS = 0x4f + SMART_READ_LOG_SECTOR = 0xd5 + SMART_READ_THRESHOLDS = 0xd1 + SMART_READ_VALUES = 0xd0 + SMART_SAVE = 0xd3 + SMART_STATUS = 0xda + SMART_WRITE_LOG_SECTOR = 0xd6 + SMART_WRITE_THRESHOLDS = 0xd7 + SMB_SUPER_MAGIC = 0x517b + SOCKFS_MAGIC = 0x534f434b SOCK_CLOEXEC = 0x80000 SOCK_DCCP = 0x6 SOCK_DGRAM = 0x2 @@ -1566,7 +1895,9 @@ const ( SOL_SOCKET = 0x1 SOL_TCP = 0x6 SOL_TIPC = 0x10f + SOL_TLS = 0x11a SOL_X25 = 0x106 + SOL_XDP = 0x11b SOMAXCONN = 0x80 SO_ACCEPTCONN = 0x1e SO_ATTACH_BPF = 0x32 @@ -1585,6 +1916,17 @@ const ( SO_DETACH_FILTER = 0x1b SO_DOMAIN = 0x27 SO_DONTROUTE = 0x5 + SO_EE_CODE_TXTIME_INVALID_PARAM = 0x1 + SO_EE_CODE_TXTIME_MISSED = 0x2 + SO_EE_CODE_ZEROCOPY_COPIED = 0x1 + SO_EE_ORIGIN_ICMP = 0x2 + SO_EE_ORIGIN_ICMP6 = 0x3 + SO_EE_ORIGIN_LOCAL = 0x1 + SO_EE_ORIGIN_NONE = 0x0 + SO_EE_ORIGIN_TIMESTAMPING = 0x4 + SO_EE_ORIGIN_TXSTATUS = 0x4 + SO_EE_ORIGIN_TXTIME = 0x6 + SO_EE_ORIGIN_ZEROCOPY = 0x5 SO_ERROR = 0x4 SO_GET_FILTER = 0x1a SO_INCOMING_CPU = 0x31 @@ -1625,6 +1967,7 @@ const ( SO_TIMESTAMP = 0x1d SO_TIMESTAMPING = 0x25 SO_TIMESTAMPNS = 0x23 + SO_TXTIME = 0x3d SO_TYPE = 0x3 SO_VM_SOCKETS_BUFFER_MAX_SIZE = 0x2 SO_VM_SOCKETS_BUFFER_MIN_SIZE = 0x1 @@ -1634,10 +1977,38 @@ const ( SO_VM_SOCKETS_PEER_HOST_VM_ID = 0x3 SO_VM_SOCKETS_TRUSTED = 0x5 SO_WIFI_STATUS = 0x29 + SO_ZEROCOPY = 0x3c SPLICE_F_GIFT = 0x8 SPLICE_F_MORE = 0x4 SPLICE_F_MOVE = 0x1 SPLICE_F_NONBLOCK = 0x2 + SQUASHFS_MAGIC = 0x73717368 + STACK_END_MAGIC = 0x57ac6e9d + STATX_ALL = 0xfff + STATX_ATIME = 0x20 + STATX_ATTR_APPEND = 0x20 + STATX_ATTR_AUTOMOUNT = 0x1000 + STATX_ATTR_COMPRESSED = 0x4 + STATX_ATTR_ENCRYPTED = 0x800 + STATX_ATTR_IMMUTABLE = 0x10 + STATX_ATTR_NODUMP = 0x40 + STATX_BASIC_STATS = 0x7ff + STATX_BLOCKS = 0x400 + STATX_BTIME = 0x800 + STATX_CTIME = 0x80 + STATX_GID = 0x10 + STATX_INO = 0x100 + STATX_MODE = 0x2 + STATX_MTIME = 0x40 + STATX_NLINK = 0x4 + STATX_SIZE = 0x200 + STATX_TYPE = 0x1 + STATX_UID = 0x8 + STATX__RESERVED = 0x80000000 + SYNC_FILE_RANGE_WAIT_AFTER = 0x4 + SYNC_FILE_RANGE_WAIT_BEFORE = 0x1 + SYNC_FILE_RANGE_WRITE = 0x2 + SYSFS_MAGIC = 0x62656572 S_BLKSIZE = 0x200 S_IEXEC = 0x40 S_IFBLK = 0x6000 @@ -1675,7 +2046,7 @@ const ( TASKSTATS_GENL_NAME = "TASKSTATS" TASKSTATS_GENL_VERSION = 0x1 TASKSTATS_TYPE_MAX = 0x6 - TASKSTATS_VERSION = 0x8 + TASKSTATS_VERSION = 0x9 TCFLSH = 0x540b TCGETA = 0x5405 TCGETS = 0x5401 @@ -1689,6 +2060,7 @@ const ( TCOOFF = 0x0 TCOON = 0x1 TCP_CC_INFO = 0x1a + TCP_CM_INQ = 0x24 TCP_CONGESTION = 0xd TCP_COOKIE_IN_ALWAYS = 0x1 TCP_COOKIE_MAX = 0x10 @@ -1700,7 +2072,10 @@ const ( TCP_DEFER_ACCEPT = 0x9 TCP_FASTOPEN = 0x17 TCP_FASTOPEN_CONNECT = 0x1e + TCP_FASTOPEN_KEY = 0x21 + TCP_FASTOPEN_NO_COOKIE = 0x22 TCP_INFO = 0xb + TCP_INQ = 0x24 TCP_KEEPCNT = 0x6 TCP_KEEPIDLE = 0x4 TCP_KEEPINTVL = 0x5 @@ -1709,6 +2084,8 @@ const ( TCP_MAXWIN = 0xffff TCP_MAX_WINSHIFT = 0xe TCP_MD5SIG = 0xe + TCP_MD5SIG_EXT = 0x20 + TCP_MD5SIG_FLAG_PREFIX = 0x1 TCP_MD5SIG_MAXKEYLEN = 0x50 TCP_MSS = 0x200 TCP_MSS_DEFAULT = 0x218 @@ -1718,6 +2095,9 @@ const ( TCP_QUEUE_SEQ = 0x15 TCP_QUICKACK = 0xc TCP_REPAIR = 0x13 + TCP_REPAIR_OFF = 0x0 + TCP_REPAIR_OFF_NO_WP = -0x1 + TCP_REPAIR_ON = 0x1 TCP_REPAIR_OPTIONS = 0x16 TCP_REPAIR_QUEUE = 0x14 TCP_REPAIR_WINDOW = 0x1d @@ -1729,8 +2109,10 @@ const ( TCP_THIN_DUPACK = 0x11 TCP_THIN_LINEAR_TIMEOUTS = 0x10 TCP_TIMESTAMP = 0x18 + TCP_ULP = 0x1f TCP_USER_TIMEOUT = 0x12 TCP_WINDOW_CLAMP = 0xa + TCP_ZEROCOPY_RECEIVE = 0x23 TCSAFLUSH = 0x2 TCSBRK = 0x5409 TCSBRKP = 0x5425 @@ -1747,6 +2129,7 @@ const ( TCSETXF = 0x5434 TCSETXW = 0x5435 TCXONC = 0x540a + TIMER_ABSTIME = 0x1 TIOCCBRK = 0x5428 TIOCCONS = 0x541d TIOCEXCL = 0x540c @@ -1754,6 +2137,7 @@ const ( TIOCGETD = 0x5424 TIOCGEXCL = 0x80045440 TIOCGICOUNT = 0x545d + TIOCGISO7816 = 0x80285442 TIOCGLCKTRMIOS = 0x5456 TIOCGPGRP = 0x540f TIOCGPKT = 0x80045438 @@ -1807,6 +2191,7 @@ const ( TIOCSER_TEMT = 0x1 TIOCSETD = 0x5423 TIOCSIG = 0x40045436 + TIOCSISO7816 = 0xc0285443 TIOCSLCKTRMIOS = 0x5457 TIOCSPGRP = 0x5410 TIOCSPTLCK = 0x40045431 @@ -1816,7 +2201,27 @@ const ( TIOCSTI = 0x5412 TIOCSWINSZ = 0x5414 TIOCVHANGUP = 0x5437 + TMPFS_MAGIC = 0x1021994 TOSTOP = 0x100 + TPACKET_ALIGNMENT = 0x10 + TPACKET_HDRLEN = 0x34 + TP_STATUS_AVAILABLE = 0x0 + TP_STATUS_BLK_TMO = 0x20 + TP_STATUS_COPY = 0x2 + TP_STATUS_CSUMNOTREADY = 0x8 + TP_STATUS_CSUM_VALID = 0x80 + TP_STATUS_KERNEL = 0x0 + TP_STATUS_LOSING = 0x4 + TP_STATUS_SENDING = 0x2 + TP_STATUS_SEND_REQUEST = 0x1 + TP_STATUS_TS_RAW_HARDWARE = -0x80000000 + TP_STATUS_TS_SOFTWARE = 0x20000000 + TP_STATUS_TS_SYS_HARDWARE = 0x40000000 + TP_STATUS_USER = 0x1 + TP_STATUS_VLAN_TPID_VALID = 0x40 + TP_STATUS_VLAN_VALID = 0x10 + TP_STATUS_WRONG_FORMAT = 0x4 + TRACEFS_MAGIC = 0x74726163 TS_COMM_LEN = 0x20 TUNATTACHFILTER = 0x400854d5 TUNDETACHFILTER = 0x400854d6 @@ -1828,6 +2233,7 @@ const ( TUNGETVNETHDRSZ = 0x800454d7 TUNGETVNETLE = 0x800454dd TUNSETDEBUG = 0x400454c9 + TUNSETFILTEREBPF = 0x800454e1 TUNSETGROUP = 0x400454ce TUNSETIFF = 0x400454ca TUNSETIFINDEX = 0x400454da @@ -1838,13 +2244,32 @@ const ( TUNSETPERSIST = 0x400454cb TUNSETQUEUE = 0x400454d9 TUNSETSNDBUF = 0x400454d4 + TUNSETSTEERINGEBPF = 0x800454e0 TUNSETTXFILTER = 0x400454d1 TUNSETVNETBE = 0x400454de TUNSETVNETHDRSZ = 0x400454d8 TUNSETVNETLE = 0x400454dc + UBI_IOCATT = 0x40186f40 + UBI_IOCDET = 0x40046f41 + UBI_IOCEBCH = 0x40044f02 + UBI_IOCEBER = 0x40044f01 + UBI_IOCEBISMAP = 0x80044f05 + UBI_IOCEBMAP = 0x40084f03 + UBI_IOCEBUNMAP = 0x40044f04 + UBI_IOCMKVOL = 0x40986f00 + UBI_IOCRMVOL = 0x40046f01 + UBI_IOCRNVOL = 0x51106f03 + UBI_IOCRSVOL = 0x400c6f02 + UBI_IOCSETVOLPROP = 0x40104f06 + UBI_IOCVOLCRBLK = 0x40804f07 + UBI_IOCVOLRMBLK = 0x4f08 + UBI_IOCVOLUP = 0x40084f00 + UDF_SUPER_MAGIC = 0x15013346 UMOUNT_NOFOLLOW = 0x8 + USBDEVICE_SUPER_MAGIC = 0x9fa2 UTIME_NOW = 0x3fffffff UTIME_OMIT = 0x3ffffffe + V9FS_MAGIC = 0x1021997 VDISCARD = 0xd VEOF = 0x4 VEOL = 0xb @@ -1886,16 +2311,120 @@ const ( WDIOC_SETPRETIMEOUT = 0xc0045708 WDIOC_SETTIMEOUT = 0xc0045706 WEXITED = 0x4 + WIN_ACKMEDIACHANGE = 0xdb + WIN_CHECKPOWERMODE1 = 0xe5 + WIN_CHECKPOWERMODE2 = 0x98 + WIN_DEVICE_RESET = 0x8 + WIN_DIAGNOSE = 0x90 + WIN_DOORLOCK = 0xde + WIN_DOORUNLOCK = 0xdf + WIN_DOWNLOAD_MICROCODE = 0x92 + WIN_FLUSH_CACHE = 0xe7 + WIN_FLUSH_CACHE_EXT = 0xea + WIN_FORMAT = 0x50 + WIN_GETMEDIASTATUS = 0xda + WIN_IDENTIFY = 0xec + WIN_IDENTIFY_DMA = 0xee + WIN_IDLEIMMEDIATE = 0xe1 + WIN_INIT = 0x60 + WIN_MEDIAEJECT = 0xed + WIN_MULTREAD = 0xc4 + WIN_MULTREAD_EXT = 0x29 + WIN_MULTWRITE = 0xc5 + WIN_MULTWRITE_EXT = 0x39 + WIN_NOP = 0x0 + WIN_PACKETCMD = 0xa0 + WIN_PIDENTIFY = 0xa1 + WIN_POSTBOOT = 0xdc + WIN_PREBOOT = 0xdd + WIN_QUEUED_SERVICE = 0xa2 + WIN_READ = 0x20 + WIN_READDMA = 0xc8 + WIN_READDMA_EXT = 0x25 + WIN_READDMA_ONCE = 0xc9 + WIN_READDMA_QUEUED = 0xc7 + WIN_READDMA_QUEUED_EXT = 0x26 + WIN_READ_BUFFER = 0xe4 + WIN_READ_EXT = 0x24 + WIN_READ_LONG = 0x22 + WIN_READ_LONG_ONCE = 0x23 + WIN_READ_NATIVE_MAX = 0xf8 + WIN_READ_NATIVE_MAX_EXT = 0x27 + WIN_READ_ONCE = 0x21 + WIN_RECAL = 0x10 + WIN_RESTORE = 0x10 + WIN_SECURITY_DISABLE = 0xf6 + WIN_SECURITY_ERASE_PREPARE = 0xf3 + WIN_SECURITY_ERASE_UNIT = 0xf4 + WIN_SECURITY_FREEZE_LOCK = 0xf5 + WIN_SECURITY_SET_PASS = 0xf1 + WIN_SECURITY_UNLOCK = 0xf2 + WIN_SEEK = 0x70 + WIN_SETFEATURES = 0xef + WIN_SETIDLE1 = 0xe3 + WIN_SETIDLE2 = 0x97 + WIN_SETMULT = 0xc6 + WIN_SET_MAX = 0xf9 + WIN_SET_MAX_EXT = 0x37 + WIN_SLEEPNOW1 = 0xe6 + WIN_SLEEPNOW2 = 0x99 + WIN_SMART = 0xb0 + WIN_SPECIFY = 0x91 + WIN_SRST = 0x8 + WIN_STANDBY = 0xe2 + WIN_STANDBY2 = 0x96 + WIN_STANDBYNOW1 = 0xe0 + WIN_STANDBYNOW2 = 0x94 + WIN_VERIFY = 0x40 + WIN_VERIFY_EXT = 0x42 + WIN_VERIFY_ONCE = 0x41 + WIN_WRITE = 0x30 + WIN_WRITEDMA = 0xca + WIN_WRITEDMA_EXT = 0x35 + WIN_WRITEDMA_ONCE = 0xcb + WIN_WRITEDMA_QUEUED = 0xcc + WIN_WRITEDMA_QUEUED_EXT = 0x36 + WIN_WRITE_BUFFER = 0xe8 + WIN_WRITE_EXT = 0x34 + WIN_WRITE_LONG = 0x32 + WIN_WRITE_LONG_ONCE = 0x33 + WIN_WRITE_ONCE = 0x31 + WIN_WRITE_SAME = 0xe9 + WIN_WRITE_VERIFY = 0x3c WNOHANG = 0x1 WNOTHREAD = 0x20000000 WNOWAIT = 0x1000000 WORDSIZE = 0x20 WSTOPPED = 0x2 WUNTRACED = 0x2 + X86_FXSR_MAGIC = 0x0 XATTR_CREATE = 0x1 XATTR_REPLACE = 0x2 XCASE = 0x4 + XDP_COPY = 0x2 + XDP_FLAGS_DRV_MODE = 0x4 + XDP_FLAGS_HW_MODE = 0x8 + XDP_FLAGS_MASK = 0xf + XDP_FLAGS_MODES = 0xe + XDP_FLAGS_SKB_MODE = 0x2 + XDP_FLAGS_UPDATE_IF_NOEXIST = 0x1 + XDP_MMAP_OFFSETS = 0x1 + XDP_PGOFF_RX_RING = 0x0 + XDP_PGOFF_TX_RING = 0x80000000 + XDP_RX_RING = 0x2 + XDP_SHARED_UMEM = 0x1 + XDP_STATISTICS = 0x7 + XDP_TX_RING = 0x3 + XDP_UMEM_COMPLETION_RING = 0x6 + XDP_UMEM_FILL_RING = 0x5 + XDP_UMEM_PGOFF_COMPLETION_RING = 0x180000000 + XDP_UMEM_PGOFF_FILL_RING = 0x100000000 + XDP_UMEM_REG = 0x4 + XDP_ZEROCOPY = 0x4 + XENFS_SUPER_MAGIC = 0xabba1974 + XFS_SUPER_MAGIC = 0x58465342 XTABS = 0x1800 + ZSMALLOC_MAGIC = 0x58295829 ) // Errors @@ -2075,171 +2604,179 @@ const ( ) // Error table -var errors = [...]string{ - 1: "operation not permitted", - 2: "no such file or directory", - 3: "no such process", - 4: "interrupted system call", - 5: "input/output error", - 6: "no such device or address", - 7: "argument list too long", - 8: "exec format error", - 9: "bad file descriptor", - 10: "no child processes", - 11: "resource temporarily unavailable", - 12: "cannot allocate memory", - 13: "permission denied", - 14: "bad address", - 15: "block device required", - 16: "device or resource busy", - 17: "file exists", - 18: "invalid cross-device link", - 19: "no such device", - 20: "not a directory", - 21: "is a directory", - 22: "invalid argument", - 23: "too many open files in system", - 24: "too many open files", - 25: "inappropriate ioctl for device", - 26: "text file busy", - 27: "file too large", - 28: "no space left on device", - 29: "illegal seek", - 30: "read-only file system", - 31: "too many links", - 32: "broken pipe", - 33: "numerical argument out of domain", - 34: "numerical result out of range", - 35: "resource deadlock avoided", - 36: "file name too long", - 37: "no locks available", - 38: "function not implemented", - 39: "directory not empty", - 40: "too many levels of symbolic links", - 42: "no message of desired type", - 43: "identifier removed", - 44: "channel number out of range", - 45: "level 2 not synchronized", - 46: "level 3 halted", - 47: "level 3 reset", - 48: "link number out of range", - 49: "protocol driver not attached", - 50: "no CSI structure available", - 51: "level 2 halted", - 52: "invalid exchange", - 53: "invalid request descriptor", - 54: "exchange full", - 55: "no anode", - 56: "invalid request code", - 57: "invalid slot", - 59: "bad font file format", - 60: "device not a stream", - 61: "no data available", - 62: "timer expired", - 63: "out of streams resources", - 64: "machine is not on the network", - 65: "package not installed", - 66: "object is remote", - 67: "link has been severed", - 68: "advertise error", - 69: "srmount error", - 70: "communication error on send", - 71: "protocol error", - 72: "multihop attempted", - 73: "RFS specific error", - 74: "bad message", - 75: "value too large for defined data type", - 76: "name not unique on network", - 77: "file descriptor in bad state", - 78: "remote address changed", - 79: "can not access a needed shared library", - 80: "accessing a corrupted shared library", - 81: ".lib section in a.out corrupted", - 82: "attempting to link in too many shared libraries", - 83: "cannot exec a shared library directly", - 84: "invalid or incomplete multibyte or wide character", - 85: "interrupted system call should be restarted", - 86: "streams pipe error", - 87: "too many users", - 88: "socket operation on non-socket", - 89: "destination address required", - 90: "message too long", - 91: "protocol wrong type for socket", - 92: "protocol not available", - 93: "protocol not supported", - 94: "socket type not supported", - 95: "operation not supported", - 96: "protocol family not supported", - 97: "address family not supported by protocol", - 98: "address already in use", - 99: "cannot assign requested address", - 100: "network is down", - 101: "network is unreachable", - 102: "network dropped connection on reset", - 103: "software caused connection abort", - 104: "connection reset by peer", - 105: "no buffer space available", - 106: "transport endpoint is already connected", - 107: "transport endpoint is not connected", - 108: "cannot send after transport endpoint shutdown", - 109: "too many references: cannot splice", - 110: "connection timed out", - 111: "connection refused", - 112: "host is down", - 113: "no route to host", - 114: "operation already in progress", - 115: "operation now in progress", - 116: "stale file handle", - 117: "structure needs cleaning", - 118: "not a XENIX named type file", - 119: "no XENIX semaphores available", - 120: "is a named type file", - 121: "remote I/O error", - 122: "disk quota exceeded", - 123: "no medium found", - 124: "wrong medium type", - 125: "operation canceled", - 126: "required key not available", - 127: "key has expired", - 128: "key has been revoked", - 129: "key was rejected by service", - 130: "owner died", - 131: "state not recoverable", - 132: "operation not possible due to RF-kill", - 133: "memory page has hardware error", +var errorList = [...]struct { + num syscall.Errno + name string + desc string +}{ + {1, "EPERM", "operation not permitted"}, + {2, "ENOENT", "no such file or directory"}, + {3, "ESRCH", "no such process"}, + {4, "EINTR", "interrupted system call"}, + {5, "EIO", "input/output error"}, + {6, "ENXIO", "no such device or address"}, + {7, "E2BIG", "argument list too long"}, + {8, "ENOEXEC", "exec format error"}, + {9, "EBADF", "bad file descriptor"}, + {10, "ECHILD", "no child processes"}, + {11, "EAGAIN", "resource temporarily unavailable"}, + {12, "ENOMEM", "cannot allocate memory"}, + {13, "EACCES", "permission denied"}, + {14, "EFAULT", "bad address"}, + {15, "ENOTBLK", "block device required"}, + {16, "EBUSY", "device or resource busy"}, + {17, "EEXIST", "file exists"}, + {18, "EXDEV", "invalid cross-device link"}, + {19, "ENODEV", "no such device"}, + {20, "ENOTDIR", "not a directory"}, + {21, "EISDIR", "is a directory"}, + {22, "EINVAL", "invalid argument"}, + {23, "ENFILE", "too many open files in system"}, + {24, "EMFILE", "too many open files"}, + {25, "ENOTTY", "inappropriate ioctl for device"}, + {26, "ETXTBSY", "text file busy"}, + {27, "EFBIG", "file too large"}, + {28, "ENOSPC", "no space left on device"}, + {29, "ESPIPE", "illegal seek"}, + {30, "EROFS", "read-only file system"}, + {31, "EMLINK", "too many links"}, + {32, "EPIPE", "broken pipe"}, + {33, "EDOM", "numerical argument out of domain"}, + {34, "ERANGE", "numerical result out of range"}, + {35, "EDEADLK", "resource deadlock avoided"}, + {36, "ENAMETOOLONG", "file name too long"}, + {37, "ENOLCK", "no locks available"}, + {38, "ENOSYS", "function not implemented"}, + {39, "ENOTEMPTY", "directory not empty"}, + {40, "ELOOP", "too many levels of symbolic links"}, + {42, "ENOMSG", "no message of desired type"}, + {43, "EIDRM", "identifier removed"}, + {44, "ECHRNG", "channel number out of range"}, + {45, "EL2NSYNC", "level 2 not synchronized"}, + {46, "EL3HLT", "level 3 halted"}, + {47, "EL3RST", "level 3 reset"}, + {48, "ELNRNG", "link number out of range"}, + {49, "EUNATCH", "protocol driver not attached"}, + {50, "ENOCSI", "no CSI structure available"}, + {51, "EL2HLT", "level 2 halted"}, + {52, "EBADE", "invalid exchange"}, + {53, "EBADR", "invalid request descriptor"}, + {54, "EXFULL", "exchange full"}, + {55, "ENOANO", "no anode"}, + {56, "EBADRQC", "invalid request code"}, + {57, "EBADSLT", "invalid slot"}, + {59, "EBFONT", "bad font file format"}, + {60, "ENOSTR", "device not a stream"}, + {61, "ENODATA", "no data available"}, + {62, "ETIME", "timer expired"}, + {63, "ENOSR", "out of streams resources"}, + {64, "ENONET", "machine is not on the network"}, + {65, "ENOPKG", "package not installed"}, + {66, "EREMOTE", "object is remote"}, + {67, "ENOLINK", "link has been severed"}, + {68, "EADV", "advertise error"}, + {69, "ESRMNT", "srmount error"}, + {70, "ECOMM", "communication error on send"}, + {71, "EPROTO", "protocol error"}, + {72, "EMULTIHOP", "multihop attempted"}, + {73, "EDOTDOT", "RFS specific error"}, + {74, "EBADMSG", "bad message"}, + {75, "EOVERFLOW", "value too large for defined data type"}, + {76, "ENOTUNIQ", "name not unique on network"}, + {77, "EBADFD", "file descriptor in bad state"}, + {78, "EREMCHG", "remote address changed"}, + {79, "ELIBACC", "can not access a needed shared library"}, + {80, "ELIBBAD", "accessing a corrupted shared library"}, + {81, "ELIBSCN", ".lib section in a.out corrupted"}, + {82, "ELIBMAX", "attempting to link in too many shared libraries"}, + {83, "ELIBEXEC", "cannot exec a shared library directly"}, + {84, "EILSEQ", "invalid or incomplete multibyte or wide character"}, + {85, "ERESTART", "interrupted system call should be restarted"}, + {86, "ESTRPIPE", "streams pipe error"}, + {87, "EUSERS", "too many users"}, + {88, "ENOTSOCK", "socket operation on non-socket"}, + {89, "EDESTADDRREQ", "destination address required"}, + {90, "EMSGSIZE", "message too long"}, + {91, "EPROTOTYPE", "protocol wrong type for socket"}, + {92, "ENOPROTOOPT", "protocol not available"}, + {93, "EPROTONOSUPPORT", "protocol not supported"}, + {94, "ESOCKTNOSUPPORT", "socket type not supported"}, + {95, "ENOTSUP", "operation not supported"}, + {96, "EPFNOSUPPORT", "protocol family not supported"}, + {97, "EAFNOSUPPORT", "address family not supported by protocol"}, + {98, "EADDRINUSE", "address already in use"}, + {99, "EADDRNOTAVAIL", "cannot assign requested address"}, + {100, "ENETDOWN", "network is down"}, + {101, "ENETUNREACH", "network is unreachable"}, + {102, "ENETRESET", "network dropped connection on reset"}, + {103, "ECONNABORTED", "software caused connection abort"}, + {104, "ECONNRESET", "connection reset by peer"}, + {105, "ENOBUFS", "no buffer space available"}, + {106, "EISCONN", "transport endpoint is already connected"}, + {107, "ENOTCONN", "transport endpoint is not connected"}, + {108, "ESHUTDOWN", "cannot send after transport endpoint shutdown"}, + {109, "ETOOMANYREFS", "too many references: cannot splice"}, + {110, "ETIMEDOUT", "connection timed out"}, + {111, "ECONNREFUSED", "connection refused"}, + {112, "EHOSTDOWN", "host is down"}, + {113, "EHOSTUNREACH", "no route to host"}, + {114, "EALREADY", "operation already in progress"}, + {115, "EINPROGRESS", "operation now in progress"}, + {116, "ESTALE", "stale file handle"}, + {117, "EUCLEAN", "structure needs cleaning"}, + {118, "ENOTNAM", "not a XENIX named type file"}, + {119, "ENAVAIL", "no XENIX semaphores available"}, + {120, "EISNAM", "is a named type file"}, + {121, "EREMOTEIO", "remote I/O error"}, + {122, "EDQUOT", "disk quota exceeded"}, + {123, "ENOMEDIUM", "no medium found"}, + {124, "EMEDIUMTYPE", "wrong medium type"}, + {125, "ECANCELED", "operation canceled"}, + {126, "ENOKEY", "required key not available"}, + {127, "EKEYEXPIRED", "key has expired"}, + {128, "EKEYREVOKED", "key has been revoked"}, + {129, "EKEYREJECTED", "key was rejected by service"}, + {130, "EOWNERDEAD", "owner died"}, + {131, "ENOTRECOVERABLE", "state not recoverable"}, + {132, "ERFKILL", "operation not possible due to RF-kill"}, + {133, "EHWPOISON", "memory page has hardware error"}, } // Signal table -var signals = [...]string{ - 1: "hangup", - 2: "interrupt", - 3: "quit", - 4: "illegal instruction", - 5: "trace/breakpoint trap", - 6: "aborted", - 7: "bus error", - 8: "floating point exception", - 9: "killed", - 10: "user defined signal 1", - 11: "segmentation fault", - 12: "user defined signal 2", - 13: "broken pipe", - 14: "alarm clock", - 15: "terminated", - 16: "stack fault", - 17: "child exited", - 18: "continued", - 19: "stopped (signal)", - 20: "stopped", - 21: "stopped (tty input)", - 22: "stopped (tty output)", - 23: "urgent I/O condition", - 24: "CPU time limit exceeded", - 25: "file size limit exceeded", - 26: "virtual timer expired", - 27: "profiling timer expired", - 28: "window changed", - 29: "I/O possible", - 30: "power failure", - 31: "bad system call", +var signalList = [...]struct { + num syscall.Signal + name string + desc string +}{ + {1, "SIGHUP", "hangup"}, + {2, "SIGINT", "interrupt"}, + {3, "SIGQUIT", "quit"}, + {4, "SIGILL", "illegal instruction"}, + {5, "SIGTRAP", "trace/breakpoint trap"}, + {6, "SIGABRT", "aborted"}, + {7, "SIGBUS", "bus error"}, + {8, "SIGFPE", "floating point exception"}, + {9, "SIGKILL", "killed"}, + {10, "SIGUSR1", "user defined signal 1"}, + {11, "SIGSEGV", "segmentation fault"}, + {12, "SIGUSR2", "user defined signal 2"}, + {13, "SIGPIPE", "broken pipe"}, + {14, "SIGALRM", "alarm clock"}, + {15, "SIGTERM", "terminated"}, + {16, "SIGSTKFLT", "stack fault"}, + {17, "SIGCHLD", "child exited"}, + {18, "SIGCONT", "continued"}, + {19, "SIGSTOP", "stopped (signal)"}, + {20, "SIGTSTP", "stopped"}, + {21, "SIGTTIN", "stopped (tty input)"}, + {22, "SIGTTOU", "stopped (tty output)"}, + {23, "SIGURG", "urgent I/O condition"}, + {24, "SIGXCPU", "CPU time limit exceeded"}, + {25, "SIGXFSZ", "file size limit exceeded"}, + {26, "SIGVTALRM", "virtual timer expired"}, + {27, "SIGPROF", "profiling timer expired"}, + {28, "SIGWINCH", "window changed"}, + {29, "SIGIO", "I/O possible"}, + {30, "SIGPWR", "power failure"}, + {31, "SIGSYS", "bad system call"}, } diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go index 4083cb2a86..73c9b88ca7 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go @@ -3,7 +3,7 @@ // +build amd64,linux -// Created by cgo -godefs - DO NOT EDIT +// Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs -- -Wall -Werror -static -I/tmp/include -m64 _const.go package unix @@ -11,6 +11,11 @@ package unix import "syscall" const ( + AAFS_MAGIC = 0x5a3c69f0 + ADFS_SUPER_MAGIC = 0xadf5 + AFFS_SUPER_MAGIC = 0xadff + AFS_FS_MAGIC = 0x6b414653 + AFS_SUPER_MAGIC = 0x5346414f AF_ALG = 0x26 AF_APPLETALK = 0x5 AF_ASH = 0x12 @@ -36,7 +41,7 @@ const ( AF_KEY = 0xf AF_LLC = 0x1a AF_LOCAL = 0x1 - AF_MAX = 0x2c + AF_MAX = 0x2d AF_MPLS = 0x1c AF_NETBEUI = 0xd AF_NETLINK = 0x10 @@ -59,6 +64,7 @@ const ( AF_VSOCK = 0x28 AF_WANPIPE = 0x19 AF_X25 = 0x9 + AF_XDP = 0x2c ALG_OP_DECRYPT = 0x0 ALG_OP_ENCRYPT = 0x1 ALG_SET_AEAD_ASSOCLEN = 0x4 @@ -66,6 +72,7 @@ const ( ALG_SET_IV = 0x2 ALG_SET_KEY = 0x1 ALG_SET_OP = 0x3 + ANON_INODE_FS_MAGIC = 0x9041934 ARPHRD_6LOWPAN = 0x339 ARPHRD_ADAPT = 0x108 ARPHRD_APPLETLK = 0x8 @@ -121,6 +128,7 @@ const ( ARPHRD_PPP = 0x200 ARPHRD_PRONET = 0x4 ARPHRD_RAWHDLC = 0x206 + ARPHRD_RAWIP = 0x207 ARPHRD_ROSE = 0x10e ARPHRD_RSRVD = 0x104 ARPHRD_SIT = 0x308 @@ -132,6 +140,7 @@ const ( ARPHRD_VOID = 0xffff ARPHRD_VSOCKMON = 0x33a ARPHRD_X25 = 0x10f + AUTOFS_SUPER_MAGIC = 0x187 B0 = 0x0 B1000000 = 0x1008 B110 = 0x3 @@ -163,6 +172,9 @@ const ( B75 = 0x2 B921600 = 0x1007 B9600 = 0xd + BALLOON_KVM_MAGIC = 0x13661366 + BDEVFS_MAGIC = 0x62646576 + BINFMTFS_MAGIC = 0x42494e4d BLKBSZGET = 0x80081270 BLKBSZSET = 0x40081271 BLKFLSBUF = 0x1261 @@ -187,6 +199,7 @@ const ( BPF_AND = 0x50 BPF_B = 0x10 BPF_DIV = 0x30 + BPF_FS_MAGIC = 0xcafe4a11 BPF_H = 0x8 BPF_IMM = 0x0 BPF_IND = 0x40 @@ -228,6 +241,8 @@ const ( BS0 = 0x0 BS1 = 0x2000 BSDLY = 0x2000 + BTRFS_SUPER_MAGIC = 0x9123683e + BTRFS_TEST_MAGIC = 0x73727279 CAN_BCM = 0x2 CAN_EFF_FLAG = 0x80000000 CAN_EFF_ID_BITS = 0x1d @@ -251,6 +266,8 @@ const ( CBAUD = 0x100f CBAUDEX = 0x1000 CFLUSH = 0xf + CGROUP2_SUPER_MAGIC = 0x63677270 + CGROUP_SUPER_MAGIC = 0x27e0eb CIBAUD = 0x100f0000 CLOCAL = 0x800 CLOCK_BOOTTIME = 0x7 @@ -293,10 +310,12 @@ const ( CLONE_VFORK = 0x4000 CLONE_VM = 0x100 CMSPAR = 0x40000000 + CODA_SUPER_MAGIC = 0x73757245 CR0 = 0x0 CR1 = 0x200 CR2 = 0x400 CR3 = 0x600 + CRAMFS_MAGIC = 0x28cd3d45 CRDLY = 0x600 CREAD = 0x80 CRTSCTS = 0x80000000 @@ -311,6 +330,9 @@ const ( CSTOP = 0x13 CSTOPB = 0x40 CSUSP = 0x1a + DAXFS_MAGIC = 0x64646178 + DEBUGFS_MAGIC = 0x64626720 + DEVPTS_SUPER_MAGIC = 0x1cd1 DT_BLK = 0x6 DT_CHR = 0x2 DT_DIR = 0x4 @@ -327,9 +349,12 @@ const ( ECHOKE = 0x800 ECHONL = 0x40 ECHOPRT = 0x400 + ECRYPTFS_SUPER_MAGIC = 0xf15f EFD_CLOEXEC = 0x80000 EFD_NONBLOCK = 0x800 EFD_SEMAPHORE = 0x1 + EFIVARFS_MAGIC = 0xde5e81e4 + EFS_SUPER_MAGIC = 0x414a53 ENCODING_DEFAULT = 0x0 ENCODING_FM_MARK = 0x3 ENCODING_FM_SPACE = 0x4 @@ -390,6 +415,8 @@ const ( ETH_P_DSA = 0x1b ETH_P_ECONET = 0x18 ETH_P_EDSA = 0xdada + ETH_P_ERSPAN = 0x88be + ETH_P_ERSPAN2 = 0x22eb ETH_P_FCOE = 0x8906 ETH_P_FIP = 0x8914 ETH_P_HDLC = 0x19 @@ -398,6 +425,7 @@ const ( ETH_P_IEEE802154 = 0xf6 ETH_P_IEEEPUP = 0xa00 ETH_P_IEEEPUPAT = 0xa01 + ETH_P_IFE = 0xed3e ETH_P_IP = 0x800 ETH_P_IPV6 = 0x86dd ETH_P_IPX = 0x8137 @@ -408,11 +436,13 @@ const ( ETH_P_LOOP = 0x60 ETH_P_LOOPBACK = 0x9000 ETH_P_MACSEC = 0x88e5 + ETH_P_MAP = 0xf9 ETH_P_MOBITEX = 0x15 ETH_P_MPLS_MC = 0x8848 ETH_P_MPLS_UC = 0x8847 ETH_P_MVRP = 0x88f5 ETH_P_NCSI = 0x88f8 + ETH_P_NSH = 0x894f ETH_P_PAE = 0x888e ETH_P_PAUSE = 0x8808 ETH_P_PHONET = 0xf5 @@ -420,6 +450,7 @@ const ( ETH_P_PPP_DISC = 0x8863 ETH_P_PPP_MP = 0x8 ETH_P_PPP_SES = 0x8864 + ETH_P_PREAUTH = 0x88c7 ETH_P_PRP = 0x88fb ETH_P_PUP = 0x200 ETH_P_PUPAT = 0x201 @@ -440,9 +471,14 @@ const ( ETH_P_WCCP = 0x883e ETH_P_X25 = 0x805 ETH_P_XDSA = 0xf8 + EXABYTE_ENABLE_NEST = 0xf0 + EXT2_SUPER_MAGIC = 0xef53 + EXT3_SUPER_MAGIC = 0xef53 + EXT4_SUPER_MAGIC = 0xef53 EXTA = 0xe EXTB = 0xf EXTPROC = 0x10000 + F2FS_SUPER_MAGIC = 0xf2f52010 FALLOC_FL_COLLAPSE_RANGE = 0x8 FALLOC_FL_INSERT_RANGE = 0x20 FALLOC_FL_KEEP_SIZE = 0x1 @@ -456,6 +492,7 @@ const ( FF1 = 0x8000 FFDLY = 0x8000 FLUSHO = 0x1000 + FP_XSTATE_MAGIC2 = 0x46505845 FS_ENCRYPTION_MODE_AES_128_CBC = 0x5 FS_ENCRYPTION_MODE_AES_128_CTS = 0x6 FS_ENCRYPTION_MODE_AES_256_CBC = 0x3 @@ -463,6 +500,8 @@ const ( FS_ENCRYPTION_MODE_AES_256_GCM = 0x2 FS_ENCRYPTION_MODE_AES_256_XTS = 0x1 FS_ENCRYPTION_MODE_INVALID = 0x0 + FS_ENCRYPTION_MODE_SPECK128_256_CTS = 0x8 + FS_ENCRYPTION_MODE_SPECK128_256_XTS = 0x7 FS_IOC_GET_ENCRYPTION_POLICY = 0x400c6615 FS_IOC_GET_ENCRYPTION_PWSALT = 0x40106614 FS_IOC_SET_ENCRYPTION_POLICY = 0x800c6613 @@ -476,6 +515,8 @@ const ( FS_POLICY_FLAGS_PAD_8 = 0x1 FS_POLICY_FLAGS_PAD_MASK = 0x3 FS_POLICY_FLAGS_VALID = 0x3 + FUTEXFS_SUPER_MAGIC = 0xbad1dea + F_ADD_SEALS = 0x409 F_DUPFD = 0x0 F_DUPFD_CLOEXEC = 0x406 F_EXLCK = 0x4 @@ -488,6 +529,9 @@ const ( F_GETOWN_EX = 0x10 F_GETPIPE_SZ = 0x408 F_GETSIG = 0xb + F_GET_FILE_RW_HINT = 0x40d + F_GET_RW_HINT = 0x40b + F_GET_SEALS = 0x40a F_LOCK = 0x1 F_NOTIFY = 0x402 F_OFD_GETLK = 0x24 @@ -495,6 +539,10 @@ const ( F_OFD_SETLKW = 0x26 F_OK = 0x0 F_RDLCK = 0x0 + F_SEAL_GROW = 0x4 + F_SEAL_SEAL = 0x1 + F_SEAL_SHRINK = 0x2 + F_SEAL_WRITE = 0x8 F_SETFD = 0x2 F_SETFL = 0x4 F_SETLEASE = 0x400 @@ -506,6 +554,8 @@ const ( F_SETOWN_EX = 0xf F_SETPIPE_SZ = 0x407 F_SETSIG = 0xa + F_SET_FILE_RW_HINT = 0x40e + F_SET_RW_HINT = 0x40c F_SHLCK = 0x8 F_TEST = 0x3 F_TLOCK = 0x2 @@ -527,6 +577,49 @@ const ( GENL_UNS_ADMIN_PERM = 0x10 GRND_NONBLOCK = 0x1 GRND_RANDOM = 0x2 + HDIO_DRIVE_CMD = 0x31f + HDIO_DRIVE_CMD_AEB = 0x31e + HDIO_DRIVE_CMD_HDR_SIZE = 0x4 + HDIO_DRIVE_HOB_HDR_SIZE = 0x8 + HDIO_DRIVE_RESET = 0x31c + HDIO_DRIVE_TASK = 0x31e + HDIO_DRIVE_TASKFILE = 0x31d + HDIO_DRIVE_TASK_HDR_SIZE = 0x8 + HDIO_GETGEO = 0x301 + HDIO_GET_32BIT = 0x309 + HDIO_GET_ACOUSTIC = 0x30f + HDIO_GET_ADDRESS = 0x310 + HDIO_GET_BUSSTATE = 0x31a + HDIO_GET_DMA = 0x30b + HDIO_GET_IDENTITY = 0x30d + HDIO_GET_KEEPSETTINGS = 0x308 + HDIO_GET_MULTCOUNT = 0x304 + HDIO_GET_NICE = 0x30c + HDIO_GET_NOWERR = 0x30a + HDIO_GET_QDMA = 0x305 + HDIO_GET_UNMASKINTR = 0x302 + HDIO_GET_WCACHE = 0x30e + HDIO_OBSOLETE_IDENTITY = 0x307 + HDIO_SCAN_HWIF = 0x328 + HDIO_SET_32BIT = 0x324 + HDIO_SET_ACOUSTIC = 0x32c + HDIO_SET_ADDRESS = 0x32f + HDIO_SET_BUSSTATE = 0x32d + HDIO_SET_DMA = 0x326 + HDIO_SET_KEEPSETTINGS = 0x323 + HDIO_SET_MULTCOUNT = 0x321 + HDIO_SET_NICE = 0x329 + HDIO_SET_NOWERR = 0x325 + HDIO_SET_PIO_MODE = 0x327 + HDIO_SET_QDMA = 0x32e + HDIO_SET_UNMASKINTR = 0x322 + HDIO_SET_WCACHE = 0x32b + HDIO_SET_XFER = 0x306 + HDIO_TRISTATE_HWIF = 0x31b + HDIO_UNREGISTER_HWIF = 0x32a + HOSTFS_SUPER_MAGIC = 0xc0ffee + HPFS_SUPER_MAGIC = 0xf995e849 + HUGETLBFS_MAGIC = 0x958458f6 HUPCL = 0x400 IBSHIFT = 0x10 ICANON = 0x2 @@ -546,7 +639,7 @@ const ( IFA_F_STABLE_PRIVACY = 0x800 IFA_F_TEMPORARY = 0x1 IFA_F_TENTATIVE = 0x40 - IFA_MAX = 0x8 + IFA_MAX = 0xa IFF_ALLMULTI = 0x200 IFF_ATTACH_QUEUE = 0x200 IFF_AUTOMEDIA = 0x4000 @@ -561,6 +654,8 @@ const ( IFF_MASTER = 0x400 IFF_MULTICAST = 0x1000 IFF_MULTI_QUEUE = 0x100 + IFF_NAPI = 0x10 + IFF_NAPI_FRAGS = 0x20 IFF_NOARP = 0x80 IFF_NOFILTER = 0x1000 IFF_NOTRAILERS = 0x20 @@ -612,6 +707,7 @@ const ( IN_ISDIR = 0x40000000 IN_LOOPBACKNET = 0x7f IN_MASK_ADD = 0x20000000 + IN_MASK_CREATE = 0x10000000 IN_MODIFY = 0x2 IN_MOVE = 0xc0 IN_MOVED_FROM = 0x40 @@ -671,6 +767,7 @@ const ( IPV6_DONTFRAG = 0x3e IPV6_DROP_MEMBERSHIP = 0x15 IPV6_DSTOPTS = 0x3b + IPV6_FREEBIND = 0x4e IPV6_HDRINCL = 0x24 IPV6_HOPLIMIT = 0x34 IPV6_HOPOPTS = 0x36 @@ -682,6 +779,7 @@ const ( IPV6_MINHOPCOUNT = 0x49 IPV6_MTU = 0x18 IPV6_MTU_DISCOVER = 0x17 + IPV6_MULTICAST_ALL = 0x1d IPV6_MULTICAST_HOPS = 0x12 IPV6_MULTICAST_IF = 0x11 IPV6_MULTICAST_LOOP = 0x13 @@ -775,12 +873,34 @@ const ( IP_UNICAST_IF = 0x32 IP_XFRM_POLICY = 0x11 ISIG = 0x1 + ISOFS_SUPER_MAGIC = 0x9660 ISTRIP = 0x20 IUCLC = 0x200 IUTF8 = 0x4000 IXANY = 0x800 IXOFF = 0x1000 IXON = 0x400 + JFFS2_SUPER_MAGIC = 0x72b6 + KEXEC_ARCH_386 = 0x30000 + KEXEC_ARCH_68K = 0x40000 + KEXEC_ARCH_AARCH64 = 0xb70000 + KEXEC_ARCH_ARM = 0x280000 + KEXEC_ARCH_DEFAULT = 0x0 + KEXEC_ARCH_IA_64 = 0x320000 + KEXEC_ARCH_MASK = 0xffff0000 + KEXEC_ARCH_MIPS = 0x80000 + KEXEC_ARCH_MIPS_LE = 0xa0000 + KEXEC_ARCH_PPC = 0x140000 + KEXEC_ARCH_PPC64 = 0x150000 + KEXEC_ARCH_S390 = 0x160000 + KEXEC_ARCH_SH = 0x2a0000 + KEXEC_ARCH_X86_64 = 0x3e0000 + KEXEC_FILE_NO_INITRAMFS = 0x4 + KEXEC_FILE_ON_CRASH = 0x2 + KEXEC_FILE_UNLOAD = 0x1 + KEXEC_ON_CRASH = 0x1 + KEXEC_PRESERVE_CONTEXT = 0x2 + KEXEC_SEGMENT_MAX = 0x10 KEYCTL_ASSUME_AUTHORITY = 0x10 KEYCTL_CHOWN = 0x4 KEYCTL_CLEAR = 0x7 @@ -795,6 +915,11 @@ const ( KEYCTL_JOIN_SESSION_KEYRING = 0x1 KEYCTL_LINK = 0x8 KEYCTL_NEGATE = 0xd + KEYCTL_PKEY_DECRYPT = 0x1a + KEYCTL_PKEY_ENCRYPT = 0x19 + KEYCTL_PKEY_QUERY = 0x18 + KEYCTL_PKEY_SIGN = 0x1b + KEYCTL_PKEY_VERIFY = 0x1c KEYCTL_READ = 0xb KEYCTL_REJECT = 0x13 KEYCTL_RESTRICT_KEYRING = 0x1d @@ -804,6 +929,10 @@ const ( KEYCTL_SETPERM = 0x5 KEYCTL_SET_REQKEY_KEYRING = 0xe KEYCTL_SET_TIMEOUT = 0xf + KEYCTL_SUPPORTS_DECRYPT = 0x2 + KEYCTL_SUPPORTS_ENCRYPT = 0x1 + KEYCTL_SUPPORTS_SIGN = 0x4 + KEYCTL_SUPPORTS_VERIFY = 0x8 KEYCTL_UNLINK = 0x9 KEYCTL_UPDATE = 0x2 KEY_REQKEY_DEFL_DEFAULT = 0x0 @@ -845,6 +974,7 @@ const ( MADV_FREE = 0x8 MADV_HUGEPAGE = 0xe MADV_HWPOISON = 0x64 + MADV_KEEPONFORK = 0x13 MADV_MERGEABLE = 0xc MADV_NOHUGEPAGE = 0xf MADV_NORMAL = 0x0 @@ -853,6 +983,7 @@ const ( MADV_SEQUENTIAL = 0x2 MADV_UNMERGEABLE = 0xd MADV_WILLNEED = 0x3 + MADV_WIPEONFORK = 0x12 MAP_32BIT = 0x40 MAP_ANON = 0x20 MAP_ANONYMOUS = 0x20 @@ -860,6 +991,7 @@ const ( MAP_EXECUTABLE = 0x1000 MAP_FILE = 0x0 MAP_FIXED = 0x10 + MAP_FIXED_NOREPLACE = 0x100000 MAP_GROWSDOWN = 0x100 MAP_HUGETLB = 0x40000 MAP_HUGE_MASK = 0x3f @@ -870,14 +1002,41 @@ const ( MAP_POPULATE = 0x8000 MAP_PRIVATE = 0x2 MAP_SHARED = 0x1 + MAP_SHARED_VALIDATE = 0x3 MAP_STACK = 0x20000 + MAP_SYNC = 0x80000 MAP_TYPE = 0xf MCL_CURRENT = 0x1 MCL_FUTURE = 0x2 MCL_ONFAULT = 0x4 + MFD_ALLOW_SEALING = 0x2 + MFD_CLOEXEC = 0x1 + MFD_HUGETLB = 0x4 + MFD_HUGE_16GB = -0x78000000 + MFD_HUGE_16MB = 0x60000000 + MFD_HUGE_1GB = 0x78000000 + MFD_HUGE_1MB = 0x50000000 + MFD_HUGE_256MB = 0x70000000 + MFD_HUGE_2GB = 0x7c000000 + MFD_HUGE_2MB = 0x54000000 + MFD_HUGE_32MB = 0x64000000 + MFD_HUGE_512KB = 0x4c000000 + MFD_HUGE_512MB = 0x74000000 + MFD_HUGE_64KB = 0x40000000 + MFD_HUGE_8MB = 0x5c000000 + MFD_HUGE_MASK = 0x3f + MFD_HUGE_SHIFT = 0x1a + MINIX2_SUPER_MAGIC = 0x2468 + MINIX2_SUPER_MAGIC2 = 0x2478 + MINIX3_SUPER_MAGIC = 0x4d5a + MINIX_SUPER_MAGIC = 0x137f + MINIX_SUPER_MAGIC2 = 0x138f MNT_DETACH = 0x2 MNT_EXPIRE = 0x4 MNT_FORCE = 0x1 + MODULE_INIT_IGNORE_MODVERSIONS = 0x1 + MODULE_INIT_IGNORE_VERMAGIC = 0x2 + MSDOS_SUPER_MAGIC = 0x4d44 MSG_BATCH = 0x40000 MSG_CMSG_CLOEXEC = 0x40000000 MSG_CONFIRM = 0x800 @@ -899,6 +1058,7 @@ const ( MSG_TRYHARD = 0x4 MSG_WAITALL = 0x100 MSG_WAITFORONE = 0x10000 + MSG_ZEROCOPY = 0x4000000 MS_ACTIVE = 0x40000000 MS_ASYNC = 0x1 MS_BIND = 0x1000 @@ -936,7 +1096,9 @@ const ( MS_SYNCHRONOUS = 0x10 MS_UNBINDABLE = 0x20000 MS_VERBOSE = 0x8000 + MTD_INODE_FS_MAGIC = 0x11307854 NAME_MAX = 0xff + NCP_SUPER_MAGIC = 0x564c NETLINK_ADD_MEMBERSHIP = 0x1 NETLINK_AUDIT = 0x9 NETLINK_BROADCAST_ERROR = 0x4 @@ -950,6 +1112,7 @@ const ( NETLINK_FIB_LOOKUP = 0xa NETLINK_FIREWALL = 0x3 NETLINK_GENERIC = 0x10 + NETLINK_GET_STRICT_CHK = 0xc NETLINK_INET_DIAG = 0x4 NETLINK_IP6_FW = 0xd NETLINK_ISCSI = 0x8 @@ -971,6 +1134,39 @@ const ( NETLINK_UNUSED = 0x1 NETLINK_USERSOCK = 0x2 NETLINK_XFRM = 0x6 + NETNSA_MAX = 0x3 + NETNSA_NSID_NOT_ASSIGNED = -0x1 + NFNETLINK_V0 = 0x0 + NFNLGRP_ACCT_QUOTA = 0x8 + NFNLGRP_CONNTRACK_DESTROY = 0x3 + NFNLGRP_CONNTRACK_EXP_DESTROY = 0x6 + NFNLGRP_CONNTRACK_EXP_NEW = 0x4 + NFNLGRP_CONNTRACK_EXP_UPDATE = 0x5 + NFNLGRP_CONNTRACK_NEW = 0x1 + NFNLGRP_CONNTRACK_UPDATE = 0x2 + NFNLGRP_MAX = 0x9 + NFNLGRP_NFTABLES = 0x7 + NFNLGRP_NFTRACE = 0x9 + NFNLGRP_NONE = 0x0 + NFNL_BATCH_MAX = 0x1 + NFNL_MSG_BATCH_BEGIN = 0x10 + NFNL_MSG_BATCH_END = 0x11 + NFNL_NFA_NEST = 0x8000 + NFNL_SUBSYS_ACCT = 0x7 + NFNL_SUBSYS_COUNT = 0xc + NFNL_SUBSYS_CTHELPER = 0x9 + NFNL_SUBSYS_CTNETLINK = 0x1 + NFNL_SUBSYS_CTNETLINK_EXP = 0x2 + NFNL_SUBSYS_CTNETLINK_TIMEOUT = 0x8 + NFNL_SUBSYS_IPSET = 0x6 + NFNL_SUBSYS_NFTABLES = 0xa + NFNL_SUBSYS_NFT_COMPAT = 0xb + NFNL_SUBSYS_NONE = 0x0 + NFNL_SUBSYS_OSF = 0x5 + NFNL_SUBSYS_QUEUE = 0x3 + NFNL_SUBSYS_ULOG = 0x4 + NFS_SUPER_MAGIC = 0x6969 + NILFS_SUPER_MAGIC = 0x3434 NL0 = 0x0 NL1 = 0x100 NLA_ALIGNTO = 0x4 @@ -998,10 +1194,13 @@ const ( NLM_F_EXCL = 0x200 NLM_F_MATCH = 0x200 NLM_F_MULTI = 0x2 + NLM_F_NONREC = 0x100 NLM_F_REPLACE = 0x100 NLM_F_REQUEST = 0x1 NLM_F_ROOT = 0x100 NOFLSH = 0x80 + NSFS_MAGIC = 0x6e736673 + OCFS2_SUPER_MAGIC = 0x7461636f OCRNL = 0x8 OFDEL = 0x80 OFILL = 0x40 @@ -1009,7 +1208,9 @@ const ( ONLCR = 0x4 ONLRET = 0x20 ONOCR = 0x10 + OPENPROM_SUPER_MAGIC = 0x9fa1 OPOST = 0x1 + OVERLAYFS_SUPER_MAGIC = 0x794c7630 O_ACCMODE = 0x3 O_APPEND = 0x400 O_ASYNC = 0x2000 @@ -1055,6 +1256,7 @@ const ( PACKET_FASTROUTE = 0x6 PACKET_HDRLEN = 0xb PACKET_HOST = 0x0 + PACKET_IGNORE_OUTGOING = 0x17 PACKET_KERNEL = 0x7 PACKET_LOOPBACK = 0x5 PACKET_LOSS = 0xe @@ -1094,16 +1296,50 @@ const ( PERF_EVENT_IOC_DISABLE = 0x2401 PERF_EVENT_IOC_ENABLE = 0x2400 PERF_EVENT_IOC_ID = 0x80082407 + PERF_EVENT_IOC_MODIFY_ATTRIBUTES = 0x4008240b PERF_EVENT_IOC_PAUSE_OUTPUT = 0x40042409 PERF_EVENT_IOC_PERIOD = 0x40082404 + PERF_EVENT_IOC_QUERY_BPF = 0xc008240a PERF_EVENT_IOC_REFRESH = 0x2402 PERF_EVENT_IOC_RESET = 0x2403 PERF_EVENT_IOC_SET_BPF = 0x40042408 PERF_EVENT_IOC_SET_FILTER = 0x40082406 PERF_EVENT_IOC_SET_OUTPUT = 0x2405 + PIPEFS_MAGIC = 0x50495045 + PPPIOCATTACH = 0x4004743d + PPPIOCATTCHAN = 0x40047438 + PPPIOCCONNECT = 0x4004743a + PPPIOCDETACH = 0x4004743c + PPPIOCDISCONN = 0x7439 + PPPIOCGASYNCMAP = 0x80047458 + PPPIOCGCHAN = 0x80047437 + PPPIOCGDEBUG = 0x80047441 + PPPIOCGFLAGS = 0x8004745a + PPPIOCGIDLE = 0x8010743f + PPPIOCGL2TPSTATS = 0x80487436 + PPPIOCGMRU = 0x80047453 + PPPIOCGNPMODE = 0xc008744c + PPPIOCGRASYNCMAP = 0x80047455 + PPPIOCGUNIT = 0x80047456 + PPPIOCGXASYNCMAP = 0x80207450 + PPPIOCNEWUNIT = 0xc004743e + PPPIOCSACTIVE = 0x40107446 + PPPIOCSASYNCMAP = 0x40047457 + PPPIOCSCOMPRESS = 0x4010744d + PPPIOCSDEBUG = 0x40047440 + PPPIOCSFLAGS = 0x40047459 + PPPIOCSMAXCID = 0x40047451 + PPPIOCSMRRU = 0x4004743b + PPPIOCSMRU = 0x40047452 + PPPIOCSNPMODE = 0x4008744b + PPPIOCSPASS = 0x40107447 + PPPIOCSRASYNCMAP = 0x40047454 + PPPIOCSXASYNCMAP = 0x4020744f + PPPIOCXFERUNIT = 0x744e PRIO_PGRP = 0x1 PRIO_PROCESS = 0x0 PRIO_USER = 0x2 + PROC_SUPER_MAGIC = 0x9fa0 PROT_EXEC = 0x4 PROT_GROWSDOWN = 0x1000000 PROT_GROWSUP = 0x2000000 @@ -1146,6 +1382,7 @@ const ( PR_GET_PDEATHSIG = 0x2 PR_GET_SECCOMP = 0x15 PR_GET_SECUREBITS = 0x1b + PR_GET_SPECULATION_CTRL = 0x34 PR_GET_THP_DISABLE = 0x2a PR_GET_TID_ADDRESS = 0x28 PR_GET_TIMERSLACK = 0x1e @@ -1191,11 +1428,24 @@ const ( PR_SET_PTRACER_ANY = 0xffffffffffffffff PR_SET_SECCOMP = 0x16 PR_SET_SECUREBITS = 0x1c + PR_SET_SPECULATION_CTRL = 0x35 PR_SET_THP_DISABLE = 0x29 PR_SET_TIMERSLACK = 0x1d PR_SET_TIMING = 0xe PR_SET_TSC = 0x1a PR_SET_UNALIGN = 0x6 + PR_SPEC_DISABLE = 0x4 + PR_SPEC_ENABLE = 0x2 + PR_SPEC_FORCE_DISABLE = 0x8 + PR_SPEC_INDIRECT_BRANCH = 0x1 + PR_SPEC_NOT_AFFECTED = 0x0 + PR_SPEC_PRCTL = 0x1 + PR_SPEC_STORE_BYPASS = 0x0 + PR_SVE_GET_VL = 0x33 + PR_SVE_SET_VL = 0x32 + PR_SVE_SET_VL_ONEXEC = 0x40000 + PR_SVE_VL_INHERIT = 0x20000 + PR_SVE_VL_LEN_MASK = 0xffff PR_TASK_PERF_EVENTS_DISABLE = 0x1f PR_TASK_PERF_EVENTS_ENABLE = 0x20 PR_TIMING_STATISTICAL = 0x0 @@ -1204,6 +1454,7 @@ const ( PR_TSC_SIGSEGV = 0x2 PR_UNALIGN_NOPRINT = 0x1 PR_UNALIGN_SIGBUS = 0x2 + PSTOREFS_MAGIC = 0x6165676c PTRACE_ARCH_PRCTL = 0x1e PTRACE_ATTACH = 0x10 PTRACE_CONT = 0x7 @@ -1248,6 +1499,7 @@ const ( PTRACE_POKETEXT = 0x4 PTRACE_POKEUSR = 0x6 PTRACE_SECCOMP_GET_FILTER = 0x420c + PTRACE_SECCOMP_GET_METADATA = 0x420d PTRACE_SEIZE = 0x4206 PTRACE_SETFPREGS = 0xf PTRACE_SETFPXREGS = 0x13 @@ -1263,6 +1515,14 @@ const ( PTRACE_SYSEMU = 0x1f PTRACE_SYSEMU_SINGLESTEP = 0x20 PTRACE_TRACEME = 0x0 + QNX4_SUPER_MAGIC = 0x2f + QNX6_SUPER_MAGIC = 0x68191122 + RAMFS_MAGIC = 0x858458f6 + RDTGROUP_SUPER_MAGIC = 0x7655821 + REISERFS_SUPER_MAGIC = 0x52654973 + RENAME_EXCHANGE = 0x2 + RENAME_NOREPLACE = 0x1 + RENAME_WHITEOUT = 0x4 RLIMIT_AS = 0x9 RLIMIT_CORE = 0x4 RLIMIT_CPU = 0x0 @@ -1280,9 +1540,17 @@ const ( RLIMIT_SIGPENDING = 0xb RLIMIT_STACK = 0x3 RLIM_INFINITY = 0xffffffffffffffff + RNDADDENTROPY = 0x40085203 + RNDADDTOENTCNT = 0x40045201 + RNDCLEARPOOL = 0x5206 + RNDGETENTCNT = 0x80045200 + RNDGETPOOL = 0x80085202 + RNDRESEEDCRNG = 0x5207 + RNDZAPENTCNT = 0x5204 RTAX_ADVMSS = 0x8 RTAX_CC_ALGO = 0x10 RTAX_CWND = 0x7 + RTAX_FASTOPEN_NO_COOKIE = 0x11 RTAX_FEATURES = 0xc RTAX_FEATURE_ALLFRAG = 0x8 RTAX_FEATURE_ECN = 0x1 @@ -1293,7 +1561,7 @@ const ( RTAX_INITCWND = 0xb RTAX_INITRWND = 0xe RTAX_LOCK = 0x1 - RTAX_MAX = 0x10 + RTAX_MAX = 0x11 RTAX_MTU = 0x2 RTAX_QUICKACK = 0xf RTAX_REORDERING = 0x9 @@ -1304,13 +1572,40 @@ const ( RTAX_UNSPEC = 0x0 RTAX_WINDOW = 0x3 RTA_ALIGNTO = 0x4 - RTA_MAX = 0x1a + RTA_MAX = 0x1d RTCF_DIRECTSRC = 0x4000000 RTCF_DOREDIRECT = 0x1000000 RTCF_LOG = 0x2000000 RTCF_MASQ = 0x400000 RTCF_NAT = 0x800000 RTCF_VALVE = 0x200000 + RTC_AF = 0x20 + RTC_AIE_OFF = 0x7002 + RTC_AIE_ON = 0x7001 + RTC_ALM_READ = 0x80247008 + RTC_ALM_SET = 0x40247007 + RTC_EPOCH_READ = 0x8008700d + RTC_EPOCH_SET = 0x4008700e + RTC_IRQF = 0x80 + RTC_IRQP_READ = 0x8008700b + RTC_IRQP_SET = 0x4008700c + RTC_MAX_FREQ = 0x2000 + RTC_PF = 0x40 + RTC_PIE_OFF = 0x7006 + RTC_PIE_ON = 0x7005 + RTC_PLL_GET = 0x80207011 + RTC_PLL_SET = 0x40207012 + RTC_RD_TIME = 0x80247009 + RTC_SET_TIME = 0x4024700a + RTC_UF = 0x10 + RTC_UIE_OFF = 0x7004 + RTC_UIE_ON = 0x7003 + RTC_VL_CLR = 0x7014 + RTC_VL_READ = 0x80047013 + RTC_WIE_OFF = 0x7010 + RTC_WIE_ON = 0x700f + RTC_WKALM_RD = 0x80287010 + RTC_WKALM_SET = 0x4028700f RTF_ADDRCLASSMASK = 0xf8000000 RTF_ADDRCONF = 0x40000 RTF_ALLONLINK = 0x20000 @@ -1345,6 +1640,7 @@ const ( RTM_DELACTION = 0x31 RTM_DELADDR = 0x15 RTM_DELADDRLABEL = 0x49 + RTM_DELCHAIN = 0x65 RTM_DELLINK = 0x11 RTM_DELMDB = 0x55 RTM_DELNEIGH = 0x1d @@ -1365,6 +1661,7 @@ const ( RTM_GETADDR = 0x16 RTM_GETADDRLABEL = 0x4a RTM_GETANYCAST = 0x3e + RTM_GETCHAIN = 0x66 RTM_GETDCB = 0x4e RTM_GETLINK = 0x12 RTM_GETMDB = 0x56 @@ -1379,11 +1676,12 @@ const ( RTM_GETSTATS = 0x5e RTM_GETTCLASS = 0x2a RTM_GETTFILTER = 0x2e - RTM_MAX = 0x63 + RTM_MAX = 0x67 RTM_NEWACTION = 0x30 RTM_NEWADDR = 0x14 RTM_NEWADDRLABEL = 0x48 RTM_NEWCACHEREPORT = 0x60 + RTM_NEWCHAIN = 0x64 RTM_NEWLINK = 0x10 RTM_NEWMDB = 0x54 RTM_NEWNDUSEROPT = 0x44 @@ -1398,8 +1696,8 @@ const ( RTM_NEWSTATS = 0x5c RTM_NEWTCLASS = 0x28 RTM_NEWTFILTER = 0x2c - RTM_NR_FAMILIES = 0x15 - RTM_NR_MSGTYPES = 0x54 + RTM_NR_FAMILIES = 0x16 + RTM_NR_MSGTYPES = 0x58 RTM_SETDCB = 0x4f RTM_SETLINK = 0x13 RTM_SETNEIGHTBL = 0x43 @@ -1413,17 +1711,22 @@ const ( RTNH_F_UNRESOLVED = 0x20 RTN_MAX = 0xb RTPROT_BABEL = 0x2a + RTPROT_BGP = 0xba RTPROT_BIRD = 0xc RTPROT_BOOT = 0x3 RTPROT_DHCP = 0x10 RTPROT_DNROUTED = 0xd + RTPROT_EIGRP = 0xc0 RTPROT_GATED = 0x8 + RTPROT_ISIS = 0xbb RTPROT_KERNEL = 0x2 RTPROT_MROUTED = 0x11 RTPROT_MRT = 0xa RTPROT_NTK = 0xf + RTPROT_OSPF = 0xbc RTPROT_RA = 0x9 RTPROT_REDIRECT = 0x1 + RTPROT_RIP = 0xbd RTPROT_STATIC = 0x4 RTPROT_UNSPEC = 0x0 RTPROT_XORP = 0xe @@ -1443,10 +1746,16 @@ const ( SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SC_LOG_FLUSH = 0x100000 SECCOMP_MODE_DISABLED = 0x0 SECCOMP_MODE_FILTER = 0x2 SECCOMP_MODE_STRICT = 0x1 + SECURITYFS_MAGIC = 0x73636673 + SELINUX_MAGIC = 0xf97cff8c + SFD_CLOEXEC = 0x80000 + SFD_NONBLOCK = 0x800 SHUT_RD = 0x0 SHUT_RDWR = 0x2 SHUT_WR = 0x1 @@ -1497,6 +1806,9 @@ const ( SIOCGMIIPHY = 0x8947 SIOCGMIIREG = 0x8948 SIOCGPGRP = 0x8904 + SIOCGPPPCSTATS = 0x89f2 + SIOCGPPPSTATS = 0x89f0 + SIOCGPPPVER = 0x89f1 SIOCGRARP = 0x8961 SIOCGSKNS = 0x894c SIOCGSTAMP = 0x8906 @@ -1531,6 +1843,23 @@ const ( SIOCSPGRP = 0x8902 SIOCSRARP = 0x8962 SIOCWANDEV = 0x894a + SMACK_MAGIC = 0x43415d53 + SMART_AUTOSAVE = 0xd2 + SMART_AUTO_OFFLINE = 0xdb + SMART_DISABLE = 0xd9 + SMART_ENABLE = 0xd8 + SMART_HCYL_PASS = 0xc2 + SMART_IMMEDIATE_OFFLINE = 0xd4 + SMART_LCYL_PASS = 0x4f + SMART_READ_LOG_SECTOR = 0xd5 + SMART_READ_THRESHOLDS = 0xd1 + SMART_READ_VALUES = 0xd0 + SMART_SAVE = 0xd3 + SMART_STATUS = 0xda + SMART_WRITE_LOG_SECTOR = 0xd6 + SMART_WRITE_THRESHOLDS = 0xd7 + SMB_SUPER_MAGIC = 0x517b + SOCKFS_MAGIC = 0x534f434b SOCK_CLOEXEC = 0x80000 SOCK_DCCP = 0x6 SOCK_DGRAM = 0x2 @@ -1567,7 +1896,9 @@ const ( SOL_SOCKET = 0x1 SOL_TCP = 0x6 SOL_TIPC = 0x10f + SOL_TLS = 0x11a SOL_X25 = 0x106 + SOL_XDP = 0x11b SOMAXCONN = 0x80 SO_ACCEPTCONN = 0x1e SO_ATTACH_BPF = 0x32 @@ -1586,6 +1917,17 @@ const ( SO_DETACH_FILTER = 0x1b SO_DOMAIN = 0x27 SO_DONTROUTE = 0x5 + SO_EE_CODE_TXTIME_INVALID_PARAM = 0x1 + SO_EE_CODE_TXTIME_MISSED = 0x2 + SO_EE_CODE_ZEROCOPY_COPIED = 0x1 + SO_EE_ORIGIN_ICMP = 0x2 + SO_EE_ORIGIN_ICMP6 = 0x3 + SO_EE_ORIGIN_LOCAL = 0x1 + SO_EE_ORIGIN_NONE = 0x0 + SO_EE_ORIGIN_TIMESTAMPING = 0x4 + SO_EE_ORIGIN_TXSTATUS = 0x4 + SO_EE_ORIGIN_TXTIME = 0x6 + SO_EE_ORIGIN_ZEROCOPY = 0x5 SO_ERROR = 0x4 SO_GET_FILTER = 0x1a SO_INCOMING_CPU = 0x31 @@ -1626,6 +1968,7 @@ const ( SO_TIMESTAMP = 0x1d SO_TIMESTAMPING = 0x25 SO_TIMESTAMPNS = 0x23 + SO_TXTIME = 0x3d SO_TYPE = 0x3 SO_VM_SOCKETS_BUFFER_MAX_SIZE = 0x2 SO_VM_SOCKETS_BUFFER_MIN_SIZE = 0x1 @@ -1635,10 +1978,38 @@ const ( SO_VM_SOCKETS_PEER_HOST_VM_ID = 0x3 SO_VM_SOCKETS_TRUSTED = 0x5 SO_WIFI_STATUS = 0x29 + SO_ZEROCOPY = 0x3c SPLICE_F_GIFT = 0x8 SPLICE_F_MORE = 0x4 SPLICE_F_MOVE = 0x1 SPLICE_F_NONBLOCK = 0x2 + SQUASHFS_MAGIC = 0x73717368 + STACK_END_MAGIC = 0x57ac6e9d + STATX_ALL = 0xfff + STATX_ATIME = 0x20 + STATX_ATTR_APPEND = 0x20 + STATX_ATTR_AUTOMOUNT = 0x1000 + STATX_ATTR_COMPRESSED = 0x4 + STATX_ATTR_ENCRYPTED = 0x800 + STATX_ATTR_IMMUTABLE = 0x10 + STATX_ATTR_NODUMP = 0x40 + STATX_BASIC_STATS = 0x7ff + STATX_BLOCKS = 0x400 + STATX_BTIME = 0x800 + STATX_CTIME = 0x80 + STATX_GID = 0x10 + STATX_INO = 0x100 + STATX_MODE = 0x2 + STATX_MTIME = 0x40 + STATX_NLINK = 0x4 + STATX_SIZE = 0x200 + STATX_TYPE = 0x1 + STATX_UID = 0x8 + STATX__RESERVED = 0x80000000 + SYNC_FILE_RANGE_WAIT_AFTER = 0x4 + SYNC_FILE_RANGE_WAIT_BEFORE = 0x1 + SYNC_FILE_RANGE_WRITE = 0x2 + SYSFS_MAGIC = 0x62656572 S_BLKSIZE = 0x200 S_IEXEC = 0x40 S_IFBLK = 0x6000 @@ -1676,7 +2047,7 @@ const ( TASKSTATS_GENL_NAME = "TASKSTATS" TASKSTATS_GENL_VERSION = 0x1 TASKSTATS_TYPE_MAX = 0x6 - TASKSTATS_VERSION = 0x8 + TASKSTATS_VERSION = 0x9 TCFLSH = 0x540b TCGETA = 0x5405 TCGETS = 0x5401 @@ -1690,6 +2061,7 @@ const ( TCOOFF = 0x0 TCOON = 0x1 TCP_CC_INFO = 0x1a + TCP_CM_INQ = 0x24 TCP_CONGESTION = 0xd TCP_COOKIE_IN_ALWAYS = 0x1 TCP_COOKIE_MAX = 0x10 @@ -1701,7 +2073,10 @@ const ( TCP_DEFER_ACCEPT = 0x9 TCP_FASTOPEN = 0x17 TCP_FASTOPEN_CONNECT = 0x1e + TCP_FASTOPEN_KEY = 0x21 + TCP_FASTOPEN_NO_COOKIE = 0x22 TCP_INFO = 0xb + TCP_INQ = 0x24 TCP_KEEPCNT = 0x6 TCP_KEEPIDLE = 0x4 TCP_KEEPINTVL = 0x5 @@ -1710,6 +2085,8 @@ const ( TCP_MAXWIN = 0xffff TCP_MAX_WINSHIFT = 0xe TCP_MD5SIG = 0xe + TCP_MD5SIG_EXT = 0x20 + TCP_MD5SIG_FLAG_PREFIX = 0x1 TCP_MD5SIG_MAXKEYLEN = 0x50 TCP_MSS = 0x200 TCP_MSS_DEFAULT = 0x218 @@ -1719,6 +2096,9 @@ const ( TCP_QUEUE_SEQ = 0x15 TCP_QUICKACK = 0xc TCP_REPAIR = 0x13 + TCP_REPAIR_OFF = 0x0 + TCP_REPAIR_OFF_NO_WP = -0x1 + TCP_REPAIR_ON = 0x1 TCP_REPAIR_OPTIONS = 0x16 TCP_REPAIR_QUEUE = 0x14 TCP_REPAIR_WINDOW = 0x1d @@ -1730,8 +2110,10 @@ const ( TCP_THIN_DUPACK = 0x11 TCP_THIN_LINEAR_TIMEOUTS = 0x10 TCP_TIMESTAMP = 0x18 + TCP_ULP = 0x1f TCP_USER_TIMEOUT = 0x12 TCP_WINDOW_CLAMP = 0xa + TCP_ZEROCOPY_RECEIVE = 0x23 TCSAFLUSH = 0x2 TCSBRK = 0x5409 TCSBRKP = 0x5425 @@ -1748,6 +2130,7 @@ const ( TCSETXF = 0x5434 TCSETXW = 0x5435 TCXONC = 0x540a + TIMER_ABSTIME = 0x1 TIOCCBRK = 0x5428 TIOCCONS = 0x541d TIOCEXCL = 0x540c @@ -1755,6 +2138,7 @@ const ( TIOCGETD = 0x5424 TIOCGEXCL = 0x80045440 TIOCGICOUNT = 0x545d + TIOCGISO7816 = 0x80285442 TIOCGLCKTRMIOS = 0x5456 TIOCGPGRP = 0x540f TIOCGPKT = 0x80045438 @@ -1808,6 +2192,7 @@ const ( TIOCSER_TEMT = 0x1 TIOCSETD = 0x5423 TIOCSIG = 0x40045436 + TIOCSISO7816 = 0xc0285443 TIOCSLCKTRMIOS = 0x5457 TIOCSPGRP = 0x5410 TIOCSPTLCK = 0x40045431 @@ -1817,7 +2202,27 @@ const ( TIOCSTI = 0x5412 TIOCSWINSZ = 0x5414 TIOCVHANGUP = 0x5437 + TMPFS_MAGIC = 0x1021994 TOSTOP = 0x100 + TPACKET_ALIGNMENT = 0x10 + TPACKET_HDRLEN = 0x34 + TP_STATUS_AVAILABLE = 0x0 + TP_STATUS_BLK_TMO = 0x20 + TP_STATUS_COPY = 0x2 + TP_STATUS_CSUMNOTREADY = 0x8 + TP_STATUS_CSUM_VALID = 0x80 + TP_STATUS_KERNEL = 0x0 + TP_STATUS_LOSING = 0x4 + TP_STATUS_SENDING = 0x2 + TP_STATUS_SEND_REQUEST = 0x1 + TP_STATUS_TS_RAW_HARDWARE = -0x80000000 + TP_STATUS_TS_SOFTWARE = 0x20000000 + TP_STATUS_TS_SYS_HARDWARE = 0x40000000 + TP_STATUS_USER = 0x1 + TP_STATUS_VLAN_TPID_VALID = 0x40 + TP_STATUS_VLAN_VALID = 0x10 + TP_STATUS_WRONG_FORMAT = 0x4 + TRACEFS_MAGIC = 0x74726163 TS_COMM_LEN = 0x20 TUNATTACHFILTER = 0x401054d5 TUNDETACHFILTER = 0x401054d6 @@ -1829,6 +2234,7 @@ const ( TUNGETVNETHDRSZ = 0x800454d7 TUNGETVNETLE = 0x800454dd TUNSETDEBUG = 0x400454c9 + TUNSETFILTEREBPF = 0x800454e1 TUNSETGROUP = 0x400454ce TUNSETIFF = 0x400454ca TUNSETIFINDEX = 0x400454da @@ -1839,13 +2245,32 @@ const ( TUNSETPERSIST = 0x400454cb TUNSETQUEUE = 0x400454d9 TUNSETSNDBUF = 0x400454d4 + TUNSETSTEERINGEBPF = 0x800454e0 TUNSETTXFILTER = 0x400454d1 TUNSETVNETBE = 0x400454de TUNSETVNETHDRSZ = 0x400454d8 TUNSETVNETLE = 0x400454dc + UBI_IOCATT = 0x40186f40 + UBI_IOCDET = 0x40046f41 + UBI_IOCEBCH = 0x40044f02 + UBI_IOCEBER = 0x40044f01 + UBI_IOCEBISMAP = 0x80044f05 + UBI_IOCEBMAP = 0x40084f03 + UBI_IOCEBUNMAP = 0x40044f04 + UBI_IOCMKVOL = 0x40986f00 + UBI_IOCRMVOL = 0x40046f01 + UBI_IOCRNVOL = 0x51106f03 + UBI_IOCRSVOL = 0x400c6f02 + UBI_IOCSETVOLPROP = 0x40104f06 + UBI_IOCVOLCRBLK = 0x40804f07 + UBI_IOCVOLRMBLK = 0x4f08 + UBI_IOCVOLUP = 0x40084f00 + UDF_SUPER_MAGIC = 0x15013346 UMOUNT_NOFOLLOW = 0x8 + USBDEVICE_SUPER_MAGIC = 0x9fa2 UTIME_NOW = 0x3fffffff UTIME_OMIT = 0x3ffffffe + V9FS_MAGIC = 0x1021997 VDISCARD = 0xd VEOF = 0x4 VEOL = 0xb @@ -1887,6 +2312,86 @@ const ( WDIOC_SETPRETIMEOUT = 0xc0045708 WDIOC_SETTIMEOUT = 0xc0045706 WEXITED = 0x4 + WIN_ACKMEDIACHANGE = 0xdb + WIN_CHECKPOWERMODE1 = 0xe5 + WIN_CHECKPOWERMODE2 = 0x98 + WIN_DEVICE_RESET = 0x8 + WIN_DIAGNOSE = 0x90 + WIN_DOORLOCK = 0xde + WIN_DOORUNLOCK = 0xdf + WIN_DOWNLOAD_MICROCODE = 0x92 + WIN_FLUSH_CACHE = 0xe7 + WIN_FLUSH_CACHE_EXT = 0xea + WIN_FORMAT = 0x50 + WIN_GETMEDIASTATUS = 0xda + WIN_IDENTIFY = 0xec + WIN_IDENTIFY_DMA = 0xee + WIN_IDLEIMMEDIATE = 0xe1 + WIN_INIT = 0x60 + WIN_MEDIAEJECT = 0xed + WIN_MULTREAD = 0xc4 + WIN_MULTREAD_EXT = 0x29 + WIN_MULTWRITE = 0xc5 + WIN_MULTWRITE_EXT = 0x39 + WIN_NOP = 0x0 + WIN_PACKETCMD = 0xa0 + WIN_PIDENTIFY = 0xa1 + WIN_POSTBOOT = 0xdc + WIN_PREBOOT = 0xdd + WIN_QUEUED_SERVICE = 0xa2 + WIN_READ = 0x20 + WIN_READDMA = 0xc8 + WIN_READDMA_EXT = 0x25 + WIN_READDMA_ONCE = 0xc9 + WIN_READDMA_QUEUED = 0xc7 + WIN_READDMA_QUEUED_EXT = 0x26 + WIN_READ_BUFFER = 0xe4 + WIN_READ_EXT = 0x24 + WIN_READ_LONG = 0x22 + WIN_READ_LONG_ONCE = 0x23 + WIN_READ_NATIVE_MAX = 0xf8 + WIN_READ_NATIVE_MAX_EXT = 0x27 + WIN_READ_ONCE = 0x21 + WIN_RECAL = 0x10 + WIN_RESTORE = 0x10 + WIN_SECURITY_DISABLE = 0xf6 + WIN_SECURITY_ERASE_PREPARE = 0xf3 + WIN_SECURITY_ERASE_UNIT = 0xf4 + WIN_SECURITY_FREEZE_LOCK = 0xf5 + WIN_SECURITY_SET_PASS = 0xf1 + WIN_SECURITY_UNLOCK = 0xf2 + WIN_SEEK = 0x70 + WIN_SETFEATURES = 0xef + WIN_SETIDLE1 = 0xe3 + WIN_SETIDLE2 = 0x97 + WIN_SETMULT = 0xc6 + WIN_SET_MAX = 0xf9 + WIN_SET_MAX_EXT = 0x37 + WIN_SLEEPNOW1 = 0xe6 + WIN_SLEEPNOW2 = 0x99 + WIN_SMART = 0xb0 + WIN_SPECIFY = 0x91 + WIN_SRST = 0x8 + WIN_STANDBY = 0xe2 + WIN_STANDBY2 = 0x96 + WIN_STANDBYNOW1 = 0xe0 + WIN_STANDBYNOW2 = 0x94 + WIN_VERIFY = 0x40 + WIN_VERIFY_EXT = 0x42 + WIN_VERIFY_ONCE = 0x41 + WIN_WRITE = 0x30 + WIN_WRITEDMA = 0xca + WIN_WRITEDMA_EXT = 0x35 + WIN_WRITEDMA_ONCE = 0xcb + WIN_WRITEDMA_QUEUED = 0xcc + WIN_WRITEDMA_QUEUED_EXT = 0x36 + WIN_WRITE_BUFFER = 0xe8 + WIN_WRITE_EXT = 0x34 + WIN_WRITE_LONG = 0x32 + WIN_WRITE_LONG_ONCE = 0x33 + WIN_WRITE_ONCE = 0x31 + WIN_WRITE_SAME = 0xe9 + WIN_WRITE_VERIFY = 0x3c WNOHANG = 0x1 WNOTHREAD = 0x20000000 WNOWAIT = 0x1000000 @@ -1896,7 +2401,30 @@ const ( XATTR_CREATE = 0x1 XATTR_REPLACE = 0x2 XCASE = 0x4 + XDP_COPY = 0x2 + XDP_FLAGS_DRV_MODE = 0x4 + XDP_FLAGS_HW_MODE = 0x8 + XDP_FLAGS_MASK = 0xf + XDP_FLAGS_MODES = 0xe + XDP_FLAGS_SKB_MODE = 0x2 + XDP_FLAGS_UPDATE_IF_NOEXIST = 0x1 + XDP_MMAP_OFFSETS = 0x1 + XDP_PGOFF_RX_RING = 0x0 + XDP_PGOFF_TX_RING = 0x80000000 + XDP_RX_RING = 0x2 + XDP_SHARED_UMEM = 0x1 + XDP_STATISTICS = 0x7 + XDP_TX_RING = 0x3 + XDP_UMEM_COMPLETION_RING = 0x6 + XDP_UMEM_FILL_RING = 0x5 + XDP_UMEM_PGOFF_COMPLETION_RING = 0x180000000 + XDP_UMEM_PGOFF_FILL_RING = 0x100000000 + XDP_UMEM_REG = 0x4 + XDP_ZEROCOPY = 0x4 + XENFS_SUPER_MAGIC = 0xabba1974 + XFS_SUPER_MAGIC = 0x58465342 XTABS = 0x1800 + ZSMALLOC_MAGIC = 0x58295829 ) // Errors @@ -2076,171 +2604,179 @@ const ( ) // Error table -var errors = [...]string{ - 1: "operation not permitted", - 2: "no such file or directory", - 3: "no such process", - 4: "interrupted system call", - 5: "input/output error", - 6: "no such device or address", - 7: "argument list too long", - 8: "exec format error", - 9: "bad file descriptor", - 10: "no child processes", - 11: "resource temporarily unavailable", - 12: "cannot allocate memory", - 13: "permission denied", - 14: "bad address", - 15: "block device required", - 16: "device or resource busy", - 17: "file exists", - 18: "invalid cross-device link", - 19: "no such device", - 20: "not a directory", - 21: "is a directory", - 22: "invalid argument", - 23: "too many open files in system", - 24: "too many open files", - 25: "inappropriate ioctl for device", - 26: "text file busy", - 27: "file too large", - 28: "no space left on device", - 29: "illegal seek", - 30: "read-only file system", - 31: "too many links", - 32: "broken pipe", - 33: "numerical argument out of domain", - 34: "numerical result out of range", - 35: "resource deadlock avoided", - 36: "file name too long", - 37: "no locks available", - 38: "function not implemented", - 39: "directory not empty", - 40: "too many levels of symbolic links", - 42: "no message of desired type", - 43: "identifier removed", - 44: "channel number out of range", - 45: "level 2 not synchronized", - 46: "level 3 halted", - 47: "level 3 reset", - 48: "link number out of range", - 49: "protocol driver not attached", - 50: "no CSI structure available", - 51: "level 2 halted", - 52: "invalid exchange", - 53: "invalid request descriptor", - 54: "exchange full", - 55: "no anode", - 56: "invalid request code", - 57: "invalid slot", - 59: "bad font file format", - 60: "device not a stream", - 61: "no data available", - 62: "timer expired", - 63: "out of streams resources", - 64: "machine is not on the network", - 65: "package not installed", - 66: "object is remote", - 67: "link has been severed", - 68: "advertise error", - 69: "srmount error", - 70: "communication error on send", - 71: "protocol error", - 72: "multihop attempted", - 73: "RFS specific error", - 74: "bad message", - 75: "value too large for defined data type", - 76: "name not unique on network", - 77: "file descriptor in bad state", - 78: "remote address changed", - 79: "can not access a needed shared library", - 80: "accessing a corrupted shared library", - 81: ".lib section in a.out corrupted", - 82: "attempting to link in too many shared libraries", - 83: "cannot exec a shared library directly", - 84: "invalid or incomplete multibyte or wide character", - 85: "interrupted system call should be restarted", - 86: "streams pipe error", - 87: "too many users", - 88: "socket operation on non-socket", - 89: "destination address required", - 90: "message too long", - 91: "protocol wrong type for socket", - 92: "protocol not available", - 93: "protocol not supported", - 94: "socket type not supported", - 95: "operation not supported", - 96: "protocol family not supported", - 97: "address family not supported by protocol", - 98: "address already in use", - 99: "cannot assign requested address", - 100: "network is down", - 101: "network is unreachable", - 102: "network dropped connection on reset", - 103: "software caused connection abort", - 104: "connection reset by peer", - 105: "no buffer space available", - 106: "transport endpoint is already connected", - 107: "transport endpoint is not connected", - 108: "cannot send after transport endpoint shutdown", - 109: "too many references: cannot splice", - 110: "connection timed out", - 111: "connection refused", - 112: "host is down", - 113: "no route to host", - 114: "operation already in progress", - 115: "operation now in progress", - 116: "stale file handle", - 117: "structure needs cleaning", - 118: "not a XENIX named type file", - 119: "no XENIX semaphores available", - 120: "is a named type file", - 121: "remote I/O error", - 122: "disk quota exceeded", - 123: "no medium found", - 124: "wrong medium type", - 125: "operation canceled", - 126: "required key not available", - 127: "key has expired", - 128: "key has been revoked", - 129: "key was rejected by service", - 130: "owner died", - 131: "state not recoverable", - 132: "operation not possible due to RF-kill", - 133: "memory page has hardware error", +var errorList = [...]struct { + num syscall.Errno + name string + desc string +}{ + {1, "EPERM", "operation not permitted"}, + {2, "ENOENT", "no such file or directory"}, + {3, "ESRCH", "no such process"}, + {4, "EINTR", "interrupted system call"}, + {5, "EIO", "input/output error"}, + {6, "ENXIO", "no such device or address"}, + {7, "E2BIG", "argument list too long"}, + {8, "ENOEXEC", "exec format error"}, + {9, "EBADF", "bad file descriptor"}, + {10, "ECHILD", "no child processes"}, + {11, "EAGAIN", "resource temporarily unavailable"}, + {12, "ENOMEM", "cannot allocate memory"}, + {13, "EACCES", "permission denied"}, + {14, "EFAULT", "bad address"}, + {15, "ENOTBLK", "block device required"}, + {16, "EBUSY", "device or resource busy"}, + {17, "EEXIST", "file exists"}, + {18, "EXDEV", "invalid cross-device link"}, + {19, "ENODEV", "no such device"}, + {20, "ENOTDIR", "not a directory"}, + {21, "EISDIR", "is a directory"}, + {22, "EINVAL", "invalid argument"}, + {23, "ENFILE", "too many open files in system"}, + {24, "EMFILE", "too many open files"}, + {25, "ENOTTY", "inappropriate ioctl for device"}, + {26, "ETXTBSY", "text file busy"}, + {27, "EFBIG", "file too large"}, + {28, "ENOSPC", "no space left on device"}, + {29, "ESPIPE", "illegal seek"}, + {30, "EROFS", "read-only file system"}, + {31, "EMLINK", "too many links"}, + {32, "EPIPE", "broken pipe"}, + {33, "EDOM", "numerical argument out of domain"}, + {34, "ERANGE", "numerical result out of range"}, + {35, "EDEADLK", "resource deadlock avoided"}, + {36, "ENAMETOOLONG", "file name too long"}, + {37, "ENOLCK", "no locks available"}, + {38, "ENOSYS", "function not implemented"}, + {39, "ENOTEMPTY", "directory not empty"}, + {40, "ELOOP", "too many levels of symbolic links"}, + {42, "ENOMSG", "no message of desired type"}, + {43, "EIDRM", "identifier removed"}, + {44, "ECHRNG", "channel number out of range"}, + {45, "EL2NSYNC", "level 2 not synchronized"}, + {46, "EL3HLT", "level 3 halted"}, + {47, "EL3RST", "level 3 reset"}, + {48, "ELNRNG", "link number out of range"}, + {49, "EUNATCH", "protocol driver not attached"}, + {50, "ENOCSI", "no CSI structure available"}, + {51, "EL2HLT", "level 2 halted"}, + {52, "EBADE", "invalid exchange"}, + {53, "EBADR", "invalid request descriptor"}, + {54, "EXFULL", "exchange full"}, + {55, "ENOANO", "no anode"}, + {56, "EBADRQC", "invalid request code"}, + {57, "EBADSLT", "invalid slot"}, + {59, "EBFONT", "bad font file format"}, + {60, "ENOSTR", "device not a stream"}, + {61, "ENODATA", "no data available"}, + {62, "ETIME", "timer expired"}, + {63, "ENOSR", "out of streams resources"}, + {64, "ENONET", "machine is not on the network"}, + {65, "ENOPKG", "package not installed"}, + {66, "EREMOTE", "object is remote"}, + {67, "ENOLINK", "link has been severed"}, + {68, "EADV", "advertise error"}, + {69, "ESRMNT", "srmount error"}, + {70, "ECOMM", "communication error on send"}, + {71, "EPROTO", "protocol error"}, + {72, "EMULTIHOP", "multihop attempted"}, + {73, "EDOTDOT", "RFS specific error"}, + {74, "EBADMSG", "bad message"}, + {75, "EOVERFLOW", "value too large for defined data type"}, + {76, "ENOTUNIQ", "name not unique on network"}, + {77, "EBADFD", "file descriptor in bad state"}, + {78, "EREMCHG", "remote address changed"}, + {79, "ELIBACC", "can not access a needed shared library"}, + {80, "ELIBBAD", "accessing a corrupted shared library"}, + {81, "ELIBSCN", ".lib section in a.out corrupted"}, + {82, "ELIBMAX", "attempting to link in too many shared libraries"}, + {83, "ELIBEXEC", "cannot exec a shared library directly"}, + {84, "EILSEQ", "invalid or incomplete multibyte or wide character"}, + {85, "ERESTART", "interrupted system call should be restarted"}, + {86, "ESTRPIPE", "streams pipe error"}, + {87, "EUSERS", "too many users"}, + {88, "ENOTSOCK", "socket operation on non-socket"}, + {89, "EDESTADDRREQ", "destination address required"}, + {90, "EMSGSIZE", "message too long"}, + {91, "EPROTOTYPE", "protocol wrong type for socket"}, + {92, "ENOPROTOOPT", "protocol not available"}, + {93, "EPROTONOSUPPORT", "protocol not supported"}, + {94, "ESOCKTNOSUPPORT", "socket type not supported"}, + {95, "ENOTSUP", "operation not supported"}, + {96, "EPFNOSUPPORT", "protocol family not supported"}, + {97, "EAFNOSUPPORT", "address family not supported by protocol"}, + {98, "EADDRINUSE", "address already in use"}, + {99, "EADDRNOTAVAIL", "cannot assign requested address"}, + {100, "ENETDOWN", "network is down"}, + {101, "ENETUNREACH", "network is unreachable"}, + {102, "ENETRESET", "network dropped connection on reset"}, + {103, "ECONNABORTED", "software caused connection abort"}, + {104, "ECONNRESET", "connection reset by peer"}, + {105, "ENOBUFS", "no buffer space available"}, + {106, "EISCONN", "transport endpoint is already connected"}, + {107, "ENOTCONN", "transport endpoint is not connected"}, + {108, "ESHUTDOWN", "cannot send after transport endpoint shutdown"}, + {109, "ETOOMANYREFS", "too many references: cannot splice"}, + {110, "ETIMEDOUT", "connection timed out"}, + {111, "ECONNREFUSED", "connection refused"}, + {112, "EHOSTDOWN", "host is down"}, + {113, "EHOSTUNREACH", "no route to host"}, + {114, "EALREADY", "operation already in progress"}, + {115, "EINPROGRESS", "operation now in progress"}, + {116, "ESTALE", "stale file handle"}, + {117, "EUCLEAN", "structure needs cleaning"}, + {118, "ENOTNAM", "not a XENIX named type file"}, + {119, "ENAVAIL", "no XENIX semaphores available"}, + {120, "EISNAM", "is a named type file"}, + {121, "EREMOTEIO", "remote I/O error"}, + {122, "EDQUOT", "disk quota exceeded"}, + {123, "ENOMEDIUM", "no medium found"}, + {124, "EMEDIUMTYPE", "wrong medium type"}, + {125, "ECANCELED", "operation canceled"}, + {126, "ENOKEY", "required key not available"}, + {127, "EKEYEXPIRED", "key has expired"}, + {128, "EKEYREVOKED", "key has been revoked"}, + {129, "EKEYREJECTED", "key was rejected by service"}, + {130, "EOWNERDEAD", "owner died"}, + {131, "ENOTRECOVERABLE", "state not recoverable"}, + {132, "ERFKILL", "operation not possible due to RF-kill"}, + {133, "EHWPOISON", "memory page has hardware error"}, } // Signal table -var signals = [...]string{ - 1: "hangup", - 2: "interrupt", - 3: "quit", - 4: "illegal instruction", - 5: "trace/breakpoint trap", - 6: "aborted", - 7: "bus error", - 8: "floating point exception", - 9: "killed", - 10: "user defined signal 1", - 11: "segmentation fault", - 12: "user defined signal 2", - 13: "broken pipe", - 14: "alarm clock", - 15: "terminated", - 16: "stack fault", - 17: "child exited", - 18: "continued", - 19: "stopped (signal)", - 20: "stopped", - 21: "stopped (tty input)", - 22: "stopped (tty output)", - 23: "urgent I/O condition", - 24: "CPU time limit exceeded", - 25: "file size limit exceeded", - 26: "virtual timer expired", - 27: "profiling timer expired", - 28: "window changed", - 29: "I/O possible", - 30: "power failure", - 31: "bad system call", +var signalList = [...]struct { + num syscall.Signal + name string + desc string +}{ + {1, "SIGHUP", "hangup"}, + {2, "SIGINT", "interrupt"}, + {3, "SIGQUIT", "quit"}, + {4, "SIGILL", "illegal instruction"}, + {5, "SIGTRAP", "trace/breakpoint trap"}, + {6, "SIGABRT", "aborted"}, + {7, "SIGBUS", "bus error"}, + {8, "SIGFPE", "floating point exception"}, + {9, "SIGKILL", "killed"}, + {10, "SIGUSR1", "user defined signal 1"}, + {11, "SIGSEGV", "segmentation fault"}, + {12, "SIGUSR2", "user defined signal 2"}, + {13, "SIGPIPE", "broken pipe"}, + {14, "SIGALRM", "alarm clock"}, + {15, "SIGTERM", "terminated"}, + {16, "SIGSTKFLT", "stack fault"}, + {17, "SIGCHLD", "child exited"}, + {18, "SIGCONT", "continued"}, + {19, "SIGSTOP", "stopped (signal)"}, + {20, "SIGTSTP", "stopped"}, + {21, "SIGTTIN", "stopped (tty input)"}, + {22, "SIGTTOU", "stopped (tty output)"}, + {23, "SIGURG", "urgent I/O condition"}, + {24, "SIGXCPU", "CPU time limit exceeded"}, + {25, "SIGXFSZ", "file size limit exceeded"}, + {26, "SIGVTALRM", "virtual timer expired"}, + {27, "SIGPROF", "profiling timer expired"}, + {28, "SIGWINCH", "window changed"}, + {29, "SIGIO", "I/O possible"}, + {30, "SIGPWR", "power failure"}, + {31, "SIGSYS", "bad system call"}, } diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go index 27d38352bd..f1ef82f57e 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go @@ -3,7 +3,7 @@ // +build arm,linux -// Created by cgo -godefs - DO NOT EDIT +// Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go package unix @@ -11,6 +11,11 @@ package unix import "syscall" const ( + AAFS_MAGIC = 0x5a3c69f0 + ADFS_SUPER_MAGIC = 0xadf5 + AFFS_SUPER_MAGIC = 0xadff + AFS_FS_MAGIC = 0x6b414653 + AFS_SUPER_MAGIC = 0x5346414f AF_ALG = 0x26 AF_APPLETALK = 0x5 AF_ASH = 0x12 @@ -36,7 +41,7 @@ const ( AF_KEY = 0xf AF_LLC = 0x1a AF_LOCAL = 0x1 - AF_MAX = 0x2c + AF_MAX = 0x2d AF_MPLS = 0x1c AF_NETBEUI = 0xd AF_NETLINK = 0x10 @@ -59,6 +64,7 @@ const ( AF_VSOCK = 0x28 AF_WANPIPE = 0x19 AF_X25 = 0x9 + AF_XDP = 0x2c ALG_OP_DECRYPT = 0x0 ALG_OP_ENCRYPT = 0x1 ALG_SET_AEAD_ASSOCLEN = 0x4 @@ -66,6 +72,7 @@ const ( ALG_SET_IV = 0x2 ALG_SET_KEY = 0x1 ALG_SET_OP = 0x3 + ANON_INODE_FS_MAGIC = 0x9041934 ARPHRD_6LOWPAN = 0x339 ARPHRD_ADAPT = 0x108 ARPHRD_APPLETLK = 0x8 @@ -121,6 +128,7 @@ const ( ARPHRD_PPP = 0x200 ARPHRD_PRONET = 0x4 ARPHRD_RAWHDLC = 0x206 + ARPHRD_RAWIP = 0x207 ARPHRD_ROSE = 0x10e ARPHRD_RSRVD = 0x104 ARPHRD_SIT = 0x308 @@ -132,6 +140,7 @@ const ( ARPHRD_VOID = 0xffff ARPHRD_VSOCKMON = 0x33a ARPHRD_X25 = 0x10f + AUTOFS_SUPER_MAGIC = 0x187 B0 = 0x0 B1000000 = 0x1008 B110 = 0x3 @@ -163,6 +172,9 @@ const ( B75 = 0x2 B921600 = 0x1007 B9600 = 0xd + BALLOON_KVM_MAGIC = 0x13661366 + BDEVFS_MAGIC = 0x62646576 + BINFMTFS_MAGIC = 0x42494e4d BLKBSZGET = 0x80041270 BLKBSZSET = 0x40041271 BLKFLSBUF = 0x1261 @@ -187,6 +199,7 @@ const ( BPF_AND = 0x50 BPF_B = 0x10 BPF_DIV = 0x30 + BPF_FS_MAGIC = 0xcafe4a11 BPF_H = 0x8 BPF_IMM = 0x0 BPF_IND = 0x40 @@ -228,6 +241,8 @@ const ( BS0 = 0x0 BS1 = 0x2000 BSDLY = 0x2000 + BTRFS_SUPER_MAGIC = 0x9123683e + BTRFS_TEST_MAGIC = 0x73727279 CAN_BCM = 0x2 CAN_EFF_FLAG = 0x80000000 CAN_EFF_ID_BITS = 0x1d @@ -251,6 +266,8 @@ const ( CBAUD = 0x100f CBAUDEX = 0x1000 CFLUSH = 0xf + CGROUP2_SUPER_MAGIC = 0x63677270 + CGROUP_SUPER_MAGIC = 0x27e0eb CIBAUD = 0x100f0000 CLOCAL = 0x800 CLOCK_BOOTTIME = 0x7 @@ -293,10 +310,12 @@ const ( CLONE_VFORK = 0x4000 CLONE_VM = 0x100 CMSPAR = 0x40000000 + CODA_SUPER_MAGIC = 0x73757245 CR0 = 0x0 CR1 = 0x200 CR2 = 0x400 CR3 = 0x600 + CRAMFS_MAGIC = 0x28cd3d45 CRDLY = 0x600 CREAD = 0x80 CRTSCTS = 0x80000000 @@ -311,6 +330,9 @@ const ( CSTOP = 0x13 CSTOPB = 0x40 CSUSP = 0x1a + DAXFS_MAGIC = 0x64646178 + DEBUGFS_MAGIC = 0x64626720 + DEVPTS_SUPER_MAGIC = 0x1cd1 DT_BLK = 0x6 DT_CHR = 0x2 DT_DIR = 0x4 @@ -327,9 +349,12 @@ const ( ECHOKE = 0x800 ECHONL = 0x40 ECHOPRT = 0x400 + ECRYPTFS_SUPER_MAGIC = 0xf15f EFD_CLOEXEC = 0x80000 EFD_NONBLOCK = 0x800 EFD_SEMAPHORE = 0x1 + EFIVARFS_MAGIC = 0xde5e81e4 + EFS_SUPER_MAGIC = 0x414a53 ENCODING_DEFAULT = 0x0 ENCODING_FM_MARK = 0x3 ENCODING_FM_SPACE = 0x4 @@ -390,6 +415,8 @@ const ( ETH_P_DSA = 0x1b ETH_P_ECONET = 0x18 ETH_P_EDSA = 0xdada + ETH_P_ERSPAN = 0x88be + ETH_P_ERSPAN2 = 0x22eb ETH_P_FCOE = 0x8906 ETH_P_FIP = 0x8914 ETH_P_HDLC = 0x19 @@ -398,6 +425,7 @@ const ( ETH_P_IEEE802154 = 0xf6 ETH_P_IEEEPUP = 0xa00 ETH_P_IEEEPUPAT = 0xa01 + ETH_P_IFE = 0xed3e ETH_P_IP = 0x800 ETH_P_IPV6 = 0x86dd ETH_P_IPX = 0x8137 @@ -408,11 +436,13 @@ const ( ETH_P_LOOP = 0x60 ETH_P_LOOPBACK = 0x9000 ETH_P_MACSEC = 0x88e5 + ETH_P_MAP = 0xf9 ETH_P_MOBITEX = 0x15 ETH_P_MPLS_MC = 0x8848 ETH_P_MPLS_UC = 0x8847 ETH_P_MVRP = 0x88f5 ETH_P_NCSI = 0x88f8 + ETH_P_NSH = 0x894f ETH_P_PAE = 0x888e ETH_P_PAUSE = 0x8808 ETH_P_PHONET = 0xf5 @@ -420,6 +450,7 @@ const ( ETH_P_PPP_DISC = 0x8863 ETH_P_PPP_MP = 0x8 ETH_P_PPP_SES = 0x8864 + ETH_P_PREAUTH = 0x88c7 ETH_P_PRP = 0x88fb ETH_P_PUP = 0x200 ETH_P_PUPAT = 0x201 @@ -440,9 +471,14 @@ const ( ETH_P_WCCP = 0x883e ETH_P_X25 = 0x805 ETH_P_XDSA = 0xf8 + EXABYTE_ENABLE_NEST = 0xf0 + EXT2_SUPER_MAGIC = 0xef53 + EXT3_SUPER_MAGIC = 0xef53 + EXT4_SUPER_MAGIC = 0xef53 EXTA = 0xe EXTB = 0xf EXTPROC = 0x10000 + F2FS_SUPER_MAGIC = 0xf2f52010 FALLOC_FL_COLLAPSE_RANGE = 0x8 FALLOC_FL_INSERT_RANGE = 0x20 FALLOC_FL_KEEP_SIZE = 0x1 @@ -463,6 +499,8 @@ const ( FS_ENCRYPTION_MODE_AES_256_GCM = 0x2 FS_ENCRYPTION_MODE_AES_256_XTS = 0x1 FS_ENCRYPTION_MODE_INVALID = 0x0 + FS_ENCRYPTION_MODE_SPECK128_256_CTS = 0x8 + FS_ENCRYPTION_MODE_SPECK128_256_XTS = 0x7 FS_IOC_GET_ENCRYPTION_POLICY = 0x400c6615 FS_IOC_GET_ENCRYPTION_PWSALT = 0x40106614 FS_IOC_SET_ENCRYPTION_POLICY = 0x800c6613 @@ -476,6 +514,8 @@ const ( FS_POLICY_FLAGS_PAD_8 = 0x1 FS_POLICY_FLAGS_PAD_MASK = 0x3 FS_POLICY_FLAGS_VALID = 0x3 + FUTEXFS_SUPER_MAGIC = 0xbad1dea + F_ADD_SEALS = 0x409 F_DUPFD = 0x0 F_DUPFD_CLOEXEC = 0x406 F_EXLCK = 0x4 @@ -488,6 +528,9 @@ const ( F_GETOWN_EX = 0x10 F_GETPIPE_SZ = 0x408 F_GETSIG = 0xb + F_GET_FILE_RW_HINT = 0x40d + F_GET_RW_HINT = 0x40b + F_GET_SEALS = 0x40a F_LOCK = 0x1 F_NOTIFY = 0x402 F_OFD_GETLK = 0x24 @@ -495,6 +538,10 @@ const ( F_OFD_SETLKW = 0x26 F_OK = 0x0 F_RDLCK = 0x0 + F_SEAL_GROW = 0x4 + F_SEAL_SEAL = 0x1 + F_SEAL_SHRINK = 0x2 + F_SEAL_WRITE = 0x8 F_SETFD = 0x2 F_SETFL = 0x4 F_SETLEASE = 0x400 @@ -506,6 +553,8 @@ const ( F_SETOWN_EX = 0xf F_SETPIPE_SZ = 0x407 F_SETSIG = 0xa + F_SET_FILE_RW_HINT = 0x40e + F_SET_RW_HINT = 0x40c F_SHLCK = 0x8 F_TEST = 0x3 F_TLOCK = 0x2 @@ -527,6 +576,49 @@ const ( GENL_UNS_ADMIN_PERM = 0x10 GRND_NONBLOCK = 0x1 GRND_RANDOM = 0x2 + HDIO_DRIVE_CMD = 0x31f + HDIO_DRIVE_CMD_AEB = 0x31e + HDIO_DRIVE_CMD_HDR_SIZE = 0x4 + HDIO_DRIVE_HOB_HDR_SIZE = 0x8 + HDIO_DRIVE_RESET = 0x31c + HDIO_DRIVE_TASK = 0x31e + HDIO_DRIVE_TASKFILE = 0x31d + HDIO_DRIVE_TASK_HDR_SIZE = 0x8 + HDIO_GETGEO = 0x301 + HDIO_GET_32BIT = 0x309 + HDIO_GET_ACOUSTIC = 0x30f + HDIO_GET_ADDRESS = 0x310 + HDIO_GET_BUSSTATE = 0x31a + HDIO_GET_DMA = 0x30b + HDIO_GET_IDENTITY = 0x30d + HDIO_GET_KEEPSETTINGS = 0x308 + HDIO_GET_MULTCOUNT = 0x304 + HDIO_GET_NICE = 0x30c + HDIO_GET_NOWERR = 0x30a + HDIO_GET_QDMA = 0x305 + HDIO_GET_UNMASKINTR = 0x302 + HDIO_GET_WCACHE = 0x30e + HDIO_OBSOLETE_IDENTITY = 0x307 + HDIO_SCAN_HWIF = 0x328 + HDIO_SET_32BIT = 0x324 + HDIO_SET_ACOUSTIC = 0x32c + HDIO_SET_ADDRESS = 0x32f + HDIO_SET_BUSSTATE = 0x32d + HDIO_SET_DMA = 0x326 + HDIO_SET_KEEPSETTINGS = 0x323 + HDIO_SET_MULTCOUNT = 0x321 + HDIO_SET_NICE = 0x329 + HDIO_SET_NOWERR = 0x325 + HDIO_SET_PIO_MODE = 0x327 + HDIO_SET_QDMA = 0x32e + HDIO_SET_UNMASKINTR = 0x322 + HDIO_SET_WCACHE = 0x32b + HDIO_SET_XFER = 0x306 + HDIO_TRISTATE_HWIF = 0x31b + HDIO_UNREGISTER_HWIF = 0x32a + HOSTFS_SUPER_MAGIC = 0xc0ffee + HPFS_SUPER_MAGIC = 0xf995e849 + HUGETLBFS_MAGIC = 0x958458f6 HUPCL = 0x400 IBSHIFT = 0x10 ICANON = 0x2 @@ -546,7 +638,7 @@ const ( IFA_F_STABLE_PRIVACY = 0x800 IFA_F_TEMPORARY = 0x1 IFA_F_TENTATIVE = 0x40 - IFA_MAX = 0x8 + IFA_MAX = 0xa IFF_ALLMULTI = 0x200 IFF_ATTACH_QUEUE = 0x200 IFF_AUTOMEDIA = 0x4000 @@ -561,6 +653,8 @@ const ( IFF_MASTER = 0x400 IFF_MULTICAST = 0x1000 IFF_MULTI_QUEUE = 0x100 + IFF_NAPI = 0x10 + IFF_NAPI_FRAGS = 0x20 IFF_NOARP = 0x80 IFF_NOFILTER = 0x1000 IFF_NOTRAILERS = 0x20 @@ -612,6 +706,7 @@ const ( IN_ISDIR = 0x40000000 IN_LOOPBACKNET = 0x7f IN_MASK_ADD = 0x20000000 + IN_MASK_CREATE = 0x10000000 IN_MODIFY = 0x2 IN_MOVE = 0xc0 IN_MOVED_FROM = 0x40 @@ -671,6 +766,7 @@ const ( IPV6_DONTFRAG = 0x3e IPV6_DROP_MEMBERSHIP = 0x15 IPV6_DSTOPTS = 0x3b + IPV6_FREEBIND = 0x4e IPV6_HDRINCL = 0x24 IPV6_HOPLIMIT = 0x34 IPV6_HOPOPTS = 0x36 @@ -682,6 +778,7 @@ const ( IPV6_MINHOPCOUNT = 0x49 IPV6_MTU = 0x18 IPV6_MTU_DISCOVER = 0x17 + IPV6_MULTICAST_ALL = 0x1d IPV6_MULTICAST_HOPS = 0x12 IPV6_MULTICAST_IF = 0x11 IPV6_MULTICAST_LOOP = 0x13 @@ -775,12 +872,34 @@ const ( IP_UNICAST_IF = 0x32 IP_XFRM_POLICY = 0x11 ISIG = 0x1 + ISOFS_SUPER_MAGIC = 0x9660 ISTRIP = 0x20 IUCLC = 0x200 IUTF8 = 0x4000 IXANY = 0x800 IXOFF = 0x1000 IXON = 0x400 + JFFS2_SUPER_MAGIC = 0x72b6 + KEXEC_ARCH_386 = 0x30000 + KEXEC_ARCH_68K = 0x40000 + KEXEC_ARCH_AARCH64 = 0xb70000 + KEXEC_ARCH_ARM = 0x280000 + KEXEC_ARCH_DEFAULT = 0x0 + KEXEC_ARCH_IA_64 = 0x320000 + KEXEC_ARCH_MASK = 0xffff0000 + KEXEC_ARCH_MIPS = 0x80000 + KEXEC_ARCH_MIPS_LE = 0xa0000 + KEXEC_ARCH_PPC = 0x140000 + KEXEC_ARCH_PPC64 = 0x150000 + KEXEC_ARCH_S390 = 0x160000 + KEXEC_ARCH_SH = 0x2a0000 + KEXEC_ARCH_X86_64 = 0x3e0000 + KEXEC_FILE_NO_INITRAMFS = 0x4 + KEXEC_FILE_ON_CRASH = 0x2 + KEXEC_FILE_UNLOAD = 0x1 + KEXEC_ON_CRASH = 0x1 + KEXEC_PRESERVE_CONTEXT = 0x2 + KEXEC_SEGMENT_MAX = 0x10 KEYCTL_ASSUME_AUTHORITY = 0x10 KEYCTL_CHOWN = 0x4 KEYCTL_CLEAR = 0x7 @@ -795,6 +914,11 @@ const ( KEYCTL_JOIN_SESSION_KEYRING = 0x1 KEYCTL_LINK = 0x8 KEYCTL_NEGATE = 0xd + KEYCTL_PKEY_DECRYPT = 0x1a + KEYCTL_PKEY_ENCRYPT = 0x19 + KEYCTL_PKEY_QUERY = 0x18 + KEYCTL_PKEY_SIGN = 0x1b + KEYCTL_PKEY_VERIFY = 0x1c KEYCTL_READ = 0xb KEYCTL_REJECT = 0x13 KEYCTL_RESTRICT_KEYRING = 0x1d @@ -804,6 +928,10 @@ const ( KEYCTL_SETPERM = 0x5 KEYCTL_SET_REQKEY_KEYRING = 0xe KEYCTL_SET_TIMEOUT = 0xf + KEYCTL_SUPPORTS_DECRYPT = 0x2 + KEYCTL_SUPPORTS_ENCRYPT = 0x1 + KEYCTL_SUPPORTS_SIGN = 0x4 + KEYCTL_SUPPORTS_VERIFY = 0x8 KEYCTL_UNLINK = 0x9 KEYCTL_UPDATE = 0x2 KEY_REQKEY_DEFL_DEFAULT = 0x0 @@ -845,6 +973,7 @@ const ( MADV_FREE = 0x8 MADV_HUGEPAGE = 0xe MADV_HWPOISON = 0x64 + MADV_KEEPONFORK = 0x13 MADV_MERGEABLE = 0xc MADV_NOHUGEPAGE = 0xf MADV_NORMAL = 0x0 @@ -853,12 +982,14 @@ const ( MADV_SEQUENTIAL = 0x2 MADV_UNMERGEABLE = 0xd MADV_WILLNEED = 0x3 + MADV_WIPEONFORK = 0x12 MAP_ANON = 0x20 MAP_ANONYMOUS = 0x20 MAP_DENYWRITE = 0x800 MAP_EXECUTABLE = 0x1000 MAP_FILE = 0x0 MAP_FIXED = 0x10 + MAP_FIXED_NOREPLACE = 0x100000 MAP_GROWSDOWN = 0x100 MAP_HUGETLB = 0x40000 MAP_HUGE_MASK = 0x3f @@ -869,14 +1000,41 @@ const ( MAP_POPULATE = 0x8000 MAP_PRIVATE = 0x2 MAP_SHARED = 0x1 + MAP_SHARED_VALIDATE = 0x3 MAP_STACK = 0x20000 + MAP_SYNC = 0x80000 MAP_TYPE = 0xf MCL_CURRENT = 0x1 MCL_FUTURE = 0x2 MCL_ONFAULT = 0x4 + MFD_ALLOW_SEALING = 0x2 + MFD_CLOEXEC = 0x1 + MFD_HUGETLB = 0x4 + MFD_HUGE_16GB = -0x78000000 + MFD_HUGE_16MB = 0x60000000 + MFD_HUGE_1GB = 0x78000000 + MFD_HUGE_1MB = 0x50000000 + MFD_HUGE_256MB = 0x70000000 + MFD_HUGE_2GB = 0x7c000000 + MFD_HUGE_2MB = 0x54000000 + MFD_HUGE_32MB = 0x64000000 + MFD_HUGE_512KB = 0x4c000000 + MFD_HUGE_512MB = 0x74000000 + MFD_HUGE_64KB = 0x40000000 + MFD_HUGE_8MB = 0x5c000000 + MFD_HUGE_MASK = 0x3f + MFD_HUGE_SHIFT = 0x1a + MINIX2_SUPER_MAGIC = 0x2468 + MINIX2_SUPER_MAGIC2 = 0x2478 + MINIX3_SUPER_MAGIC = 0x4d5a + MINIX_SUPER_MAGIC = 0x137f + MINIX_SUPER_MAGIC2 = 0x138f MNT_DETACH = 0x2 MNT_EXPIRE = 0x4 MNT_FORCE = 0x1 + MODULE_INIT_IGNORE_MODVERSIONS = 0x1 + MODULE_INIT_IGNORE_VERMAGIC = 0x2 + MSDOS_SUPER_MAGIC = 0x4d44 MSG_BATCH = 0x40000 MSG_CMSG_CLOEXEC = 0x40000000 MSG_CONFIRM = 0x800 @@ -898,6 +1056,7 @@ const ( MSG_TRYHARD = 0x4 MSG_WAITALL = 0x100 MSG_WAITFORONE = 0x10000 + MSG_ZEROCOPY = 0x4000000 MS_ACTIVE = 0x40000000 MS_ASYNC = 0x1 MS_BIND = 0x1000 @@ -935,7 +1094,9 @@ const ( MS_SYNCHRONOUS = 0x10 MS_UNBINDABLE = 0x20000 MS_VERBOSE = 0x8000 + MTD_INODE_FS_MAGIC = 0x11307854 NAME_MAX = 0xff + NCP_SUPER_MAGIC = 0x564c NETLINK_ADD_MEMBERSHIP = 0x1 NETLINK_AUDIT = 0x9 NETLINK_BROADCAST_ERROR = 0x4 @@ -949,6 +1110,7 @@ const ( NETLINK_FIB_LOOKUP = 0xa NETLINK_FIREWALL = 0x3 NETLINK_GENERIC = 0x10 + NETLINK_GET_STRICT_CHK = 0xc NETLINK_INET_DIAG = 0x4 NETLINK_IP6_FW = 0xd NETLINK_ISCSI = 0x8 @@ -970,6 +1132,39 @@ const ( NETLINK_UNUSED = 0x1 NETLINK_USERSOCK = 0x2 NETLINK_XFRM = 0x6 + NETNSA_MAX = 0x3 + NETNSA_NSID_NOT_ASSIGNED = -0x1 + NFNETLINK_V0 = 0x0 + NFNLGRP_ACCT_QUOTA = 0x8 + NFNLGRP_CONNTRACK_DESTROY = 0x3 + NFNLGRP_CONNTRACK_EXP_DESTROY = 0x6 + NFNLGRP_CONNTRACK_EXP_NEW = 0x4 + NFNLGRP_CONNTRACK_EXP_UPDATE = 0x5 + NFNLGRP_CONNTRACK_NEW = 0x1 + NFNLGRP_CONNTRACK_UPDATE = 0x2 + NFNLGRP_MAX = 0x9 + NFNLGRP_NFTABLES = 0x7 + NFNLGRP_NFTRACE = 0x9 + NFNLGRP_NONE = 0x0 + NFNL_BATCH_MAX = 0x1 + NFNL_MSG_BATCH_BEGIN = 0x10 + NFNL_MSG_BATCH_END = 0x11 + NFNL_NFA_NEST = 0x8000 + NFNL_SUBSYS_ACCT = 0x7 + NFNL_SUBSYS_COUNT = 0xc + NFNL_SUBSYS_CTHELPER = 0x9 + NFNL_SUBSYS_CTNETLINK = 0x1 + NFNL_SUBSYS_CTNETLINK_EXP = 0x2 + NFNL_SUBSYS_CTNETLINK_TIMEOUT = 0x8 + NFNL_SUBSYS_IPSET = 0x6 + NFNL_SUBSYS_NFTABLES = 0xa + NFNL_SUBSYS_NFT_COMPAT = 0xb + NFNL_SUBSYS_NONE = 0x0 + NFNL_SUBSYS_OSF = 0x5 + NFNL_SUBSYS_QUEUE = 0x3 + NFNL_SUBSYS_ULOG = 0x4 + NFS_SUPER_MAGIC = 0x6969 + NILFS_SUPER_MAGIC = 0x3434 NL0 = 0x0 NL1 = 0x100 NLA_ALIGNTO = 0x4 @@ -997,10 +1192,13 @@ const ( NLM_F_EXCL = 0x200 NLM_F_MATCH = 0x200 NLM_F_MULTI = 0x2 + NLM_F_NONREC = 0x100 NLM_F_REPLACE = 0x100 NLM_F_REQUEST = 0x1 NLM_F_ROOT = 0x100 NOFLSH = 0x80 + NSFS_MAGIC = 0x6e736673 + OCFS2_SUPER_MAGIC = 0x7461636f OCRNL = 0x8 OFDEL = 0x80 OFILL = 0x40 @@ -1008,7 +1206,9 @@ const ( ONLCR = 0x4 ONLRET = 0x20 ONOCR = 0x10 + OPENPROM_SUPER_MAGIC = 0x9fa1 OPOST = 0x1 + OVERLAYFS_SUPER_MAGIC = 0x794c7630 O_ACCMODE = 0x3 O_APPEND = 0x400 O_ASYNC = 0x2000 @@ -1054,6 +1254,7 @@ const ( PACKET_FASTROUTE = 0x6 PACKET_HDRLEN = 0xb PACKET_HOST = 0x0 + PACKET_IGNORE_OUTGOING = 0x17 PACKET_KERNEL = 0x7 PACKET_LOOPBACK = 0x5 PACKET_LOSS = 0xe @@ -1093,16 +1294,50 @@ const ( PERF_EVENT_IOC_DISABLE = 0x2401 PERF_EVENT_IOC_ENABLE = 0x2400 PERF_EVENT_IOC_ID = 0x80042407 + PERF_EVENT_IOC_MODIFY_ATTRIBUTES = 0x4004240b PERF_EVENT_IOC_PAUSE_OUTPUT = 0x40042409 PERF_EVENT_IOC_PERIOD = 0x40082404 + PERF_EVENT_IOC_QUERY_BPF = 0xc004240a PERF_EVENT_IOC_REFRESH = 0x2402 PERF_EVENT_IOC_RESET = 0x2403 PERF_EVENT_IOC_SET_BPF = 0x40042408 PERF_EVENT_IOC_SET_FILTER = 0x40042406 PERF_EVENT_IOC_SET_OUTPUT = 0x2405 + PIPEFS_MAGIC = 0x50495045 + PPPIOCATTACH = 0x4004743d + PPPIOCATTCHAN = 0x40047438 + PPPIOCCONNECT = 0x4004743a + PPPIOCDETACH = 0x4004743c + PPPIOCDISCONN = 0x7439 + PPPIOCGASYNCMAP = 0x80047458 + PPPIOCGCHAN = 0x80047437 + PPPIOCGDEBUG = 0x80047441 + PPPIOCGFLAGS = 0x8004745a + PPPIOCGIDLE = 0x8008743f + PPPIOCGL2TPSTATS = 0x80487436 + PPPIOCGMRU = 0x80047453 + PPPIOCGNPMODE = 0xc008744c + PPPIOCGRASYNCMAP = 0x80047455 + PPPIOCGUNIT = 0x80047456 + PPPIOCGXASYNCMAP = 0x80207450 + PPPIOCNEWUNIT = 0xc004743e + PPPIOCSACTIVE = 0x40087446 + PPPIOCSASYNCMAP = 0x40047457 + PPPIOCSCOMPRESS = 0x400c744d + PPPIOCSDEBUG = 0x40047440 + PPPIOCSFLAGS = 0x40047459 + PPPIOCSMAXCID = 0x40047451 + PPPIOCSMRRU = 0x4004743b + PPPIOCSMRU = 0x40047452 + PPPIOCSNPMODE = 0x4008744b + PPPIOCSPASS = 0x40087447 + PPPIOCSRASYNCMAP = 0x40047454 + PPPIOCSXASYNCMAP = 0x4020744f + PPPIOCXFERUNIT = 0x744e PRIO_PGRP = 0x1 PRIO_PROCESS = 0x0 PRIO_USER = 0x2 + PROC_SUPER_MAGIC = 0x9fa0 PROT_EXEC = 0x4 PROT_GROWSDOWN = 0x1000000 PROT_GROWSUP = 0x2000000 @@ -1145,6 +1380,7 @@ const ( PR_GET_PDEATHSIG = 0x2 PR_GET_SECCOMP = 0x15 PR_GET_SECUREBITS = 0x1b + PR_GET_SPECULATION_CTRL = 0x34 PR_GET_THP_DISABLE = 0x2a PR_GET_TID_ADDRESS = 0x28 PR_GET_TIMERSLACK = 0x1e @@ -1190,11 +1426,24 @@ const ( PR_SET_PTRACER_ANY = 0xffffffff PR_SET_SECCOMP = 0x16 PR_SET_SECUREBITS = 0x1c + PR_SET_SPECULATION_CTRL = 0x35 PR_SET_THP_DISABLE = 0x29 PR_SET_TIMERSLACK = 0x1d PR_SET_TIMING = 0xe PR_SET_TSC = 0x1a PR_SET_UNALIGN = 0x6 + PR_SPEC_DISABLE = 0x4 + PR_SPEC_ENABLE = 0x2 + PR_SPEC_FORCE_DISABLE = 0x8 + PR_SPEC_INDIRECT_BRANCH = 0x1 + PR_SPEC_NOT_AFFECTED = 0x0 + PR_SPEC_PRCTL = 0x1 + PR_SPEC_STORE_BYPASS = 0x0 + PR_SVE_GET_VL = 0x33 + PR_SVE_SET_VL = 0x32 + PR_SVE_SET_VL_ONEXEC = 0x40000 + PR_SVE_VL_INHERIT = 0x20000 + PR_SVE_VL_LEN_MASK = 0xffff PR_TASK_PERF_EVENTS_DISABLE = 0x1f PR_TASK_PERF_EVENTS_ENABLE = 0x20 PR_TIMING_STATISTICAL = 0x0 @@ -1203,6 +1452,7 @@ const ( PR_TSC_SIGSEGV = 0x2 PR_UNALIGN_NOPRINT = 0x1 PR_UNALIGN_SIGBUS = 0x2 + PSTOREFS_MAGIC = 0x6165676c PTRACE_ATTACH = 0x10 PTRACE_CONT = 0x7 PTRACE_DETACH = 0x11 @@ -1216,6 +1466,9 @@ const ( PTRACE_EVENT_VFORK_DONE = 0x5 PTRACE_GETCRUNCHREGS = 0x19 PTRACE_GETEVENTMSG = 0x4201 + PTRACE_GETFDPIC = 0x1f + PTRACE_GETFDPIC_EXEC = 0x0 + PTRACE_GETFDPIC_INTERP = 0x1 PTRACE_GETFPREGS = 0xe PTRACE_GETHBPREGS = 0x1d PTRACE_GETREGS = 0xc @@ -1249,6 +1502,7 @@ const ( PTRACE_POKETEXT = 0x4 PTRACE_POKEUSR = 0x6 PTRACE_SECCOMP_GET_FILTER = 0x420c + PTRACE_SECCOMP_GET_METADATA = 0x420d PTRACE_SEIZE = 0x4206 PTRACE_SETCRUNCHREGS = 0x1a PTRACE_SETFPREGS = 0xf @@ -1267,6 +1521,14 @@ const ( PT_DATA_ADDR = 0x10004 PT_TEXT_ADDR = 0x10000 PT_TEXT_END_ADDR = 0x10008 + QNX4_SUPER_MAGIC = 0x2f + QNX6_SUPER_MAGIC = 0x68191122 + RAMFS_MAGIC = 0x858458f6 + RDTGROUP_SUPER_MAGIC = 0x7655821 + REISERFS_SUPER_MAGIC = 0x52654973 + RENAME_EXCHANGE = 0x2 + RENAME_NOREPLACE = 0x1 + RENAME_WHITEOUT = 0x4 RLIMIT_AS = 0x9 RLIMIT_CORE = 0x4 RLIMIT_CPU = 0x0 @@ -1284,9 +1546,17 @@ const ( RLIMIT_SIGPENDING = 0xb RLIMIT_STACK = 0x3 RLIM_INFINITY = 0xffffffffffffffff + RNDADDENTROPY = 0x40085203 + RNDADDTOENTCNT = 0x40045201 + RNDCLEARPOOL = 0x5206 + RNDGETENTCNT = 0x80045200 + RNDGETPOOL = 0x80085202 + RNDRESEEDCRNG = 0x5207 + RNDZAPENTCNT = 0x5204 RTAX_ADVMSS = 0x8 RTAX_CC_ALGO = 0x10 RTAX_CWND = 0x7 + RTAX_FASTOPEN_NO_COOKIE = 0x11 RTAX_FEATURES = 0xc RTAX_FEATURE_ALLFRAG = 0x8 RTAX_FEATURE_ECN = 0x1 @@ -1297,7 +1567,7 @@ const ( RTAX_INITCWND = 0xb RTAX_INITRWND = 0xe RTAX_LOCK = 0x1 - RTAX_MAX = 0x10 + RTAX_MAX = 0x11 RTAX_MTU = 0x2 RTAX_QUICKACK = 0xf RTAX_REORDERING = 0x9 @@ -1308,13 +1578,40 @@ const ( RTAX_UNSPEC = 0x0 RTAX_WINDOW = 0x3 RTA_ALIGNTO = 0x4 - RTA_MAX = 0x1a + RTA_MAX = 0x1d RTCF_DIRECTSRC = 0x4000000 RTCF_DOREDIRECT = 0x1000000 RTCF_LOG = 0x2000000 RTCF_MASQ = 0x400000 RTCF_NAT = 0x800000 RTCF_VALVE = 0x200000 + RTC_AF = 0x20 + RTC_AIE_OFF = 0x7002 + RTC_AIE_ON = 0x7001 + RTC_ALM_READ = 0x80247008 + RTC_ALM_SET = 0x40247007 + RTC_EPOCH_READ = 0x8004700d + RTC_EPOCH_SET = 0x4004700e + RTC_IRQF = 0x80 + RTC_IRQP_READ = 0x8004700b + RTC_IRQP_SET = 0x4004700c + RTC_MAX_FREQ = 0x2000 + RTC_PF = 0x40 + RTC_PIE_OFF = 0x7006 + RTC_PIE_ON = 0x7005 + RTC_PLL_GET = 0x801c7011 + RTC_PLL_SET = 0x401c7012 + RTC_RD_TIME = 0x80247009 + RTC_SET_TIME = 0x4024700a + RTC_UF = 0x10 + RTC_UIE_OFF = 0x7004 + RTC_UIE_ON = 0x7003 + RTC_VL_CLR = 0x7014 + RTC_VL_READ = 0x80047013 + RTC_WIE_OFF = 0x7010 + RTC_WIE_ON = 0x700f + RTC_WKALM_RD = 0x80287010 + RTC_WKALM_SET = 0x4028700f RTF_ADDRCLASSMASK = 0xf8000000 RTF_ADDRCONF = 0x40000 RTF_ALLONLINK = 0x20000 @@ -1349,6 +1646,7 @@ const ( RTM_DELACTION = 0x31 RTM_DELADDR = 0x15 RTM_DELADDRLABEL = 0x49 + RTM_DELCHAIN = 0x65 RTM_DELLINK = 0x11 RTM_DELMDB = 0x55 RTM_DELNEIGH = 0x1d @@ -1369,6 +1667,7 @@ const ( RTM_GETADDR = 0x16 RTM_GETADDRLABEL = 0x4a RTM_GETANYCAST = 0x3e + RTM_GETCHAIN = 0x66 RTM_GETDCB = 0x4e RTM_GETLINK = 0x12 RTM_GETMDB = 0x56 @@ -1383,11 +1682,12 @@ const ( RTM_GETSTATS = 0x5e RTM_GETTCLASS = 0x2a RTM_GETTFILTER = 0x2e - RTM_MAX = 0x63 + RTM_MAX = 0x67 RTM_NEWACTION = 0x30 RTM_NEWADDR = 0x14 RTM_NEWADDRLABEL = 0x48 RTM_NEWCACHEREPORT = 0x60 + RTM_NEWCHAIN = 0x64 RTM_NEWLINK = 0x10 RTM_NEWMDB = 0x54 RTM_NEWNDUSEROPT = 0x44 @@ -1402,8 +1702,8 @@ const ( RTM_NEWSTATS = 0x5c RTM_NEWTCLASS = 0x28 RTM_NEWTFILTER = 0x2c - RTM_NR_FAMILIES = 0x15 - RTM_NR_MSGTYPES = 0x54 + RTM_NR_FAMILIES = 0x16 + RTM_NR_MSGTYPES = 0x58 RTM_SETDCB = 0x4f RTM_SETLINK = 0x13 RTM_SETNEIGHTBL = 0x43 @@ -1417,17 +1717,22 @@ const ( RTNH_F_UNRESOLVED = 0x20 RTN_MAX = 0xb RTPROT_BABEL = 0x2a + RTPROT_BGP = 0xba RTPROT_BIRD = 0xc RTPROT_BOOT = 0x3 RTPROT_DHCP = 0x10 RTPROT_DNROUTED = 0xd + RTPROT_EIGRP = 0xc0 RTPROT_GATED = 0x8 + RTPROT_ISIS = 0xbb RTPROT_KERNEL = 0x2 RTPROT_MROUTED = 0x11 RTPROT_MRT = 0xa RTPROT_NTK = 0xf + RTPROT_OSPF = 0xbc RTPROT_RA = 0x9 RTPROT_REDIRECT = 0x1 + RTPROT_RIP = 0xbd RTPROT_STATIC = 0x4 RTPROT_UNSPEC = 0x0 RTPROT_XORP = 0xe @@ -1447,10 +1752,16 @@ const ( SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SC_LOG_FLUSH = 0x100000 SECCOMP_MODE_DISABLED = 0x0 SECCOMP_MODE_FILTER = 0x2 SECCOMP_MODE_STRICT = 0x1 + SECURITYFS_MAGIC = 0x73636673 + SELINUX_MAGIC = 0xf97cff8c + SFD_CLOEXEC = 0x80000 + SFD_NONBLOCK = 0x800 SHUT_RD = 0x0 SHUT_RDWR = 0x2 SHUT_WR = 0x1 @@ -1501,6 +1812,9 @@ const ( SIOCGMIIPHY = 0x8947 SIOCGMIIREG = 0x8948 SIOCGPGRP = 0x8904 + SIOCGPPPCSTATS = 0x89f2 + SIOCGPPPSTATS = 0x89f0 + SIOCGPPPVER = 0x89f1 SIOCGRARP = 0x8961 SIOCGSKNS = 0x894c SIOCGSTAMP = 0x8906 @@ -1535,6 +1849,23 @@ const ( SIOCSPGRP = 0x8902 SIOCSRARP = 0x8962 SIOCWANDEV = 0x894a + SMACK_MAGIC = 0x43415d53 + SMART_AUTOSAVE = 0xd2 + SMART_AUTO_OFFLINE = 0xdb + SMART_DISABLE = 0xd9 + SMART_ENABLE = 0xd8 + SMART_HCYL_PASS = 0xc2 + SMART_IMMEDIATE_OFFLINE = 0xd4 + SMART_LCYL_PASS = 0x4f + SMART_READ_LOG_SECTOR = 0xd5 + SMART_READ_THRESHOLDS = 0xd1 + SMART_READ_VALUES = 0xd0 + SMART_SAVE = 0xd3 + SMART_STATUS = 0xda + SMART_WRITE_LOG_SECTOR = 0xd6 + SMART_WRITE_THRESHOLDS = 0xd7 + SMB_SUPER_MAGIC = 0x517b + SOCKFS_MAGIC = 0x534f434b SOCK_CLOEXEC = 0x80000 SOCK_DCCP = 0x6 SOCK_DGRAM = 0x2 @@ -1571,7 +1902,9 @@ const ( SOL_SOCKET = 0x1 SOL_TCP = 0x6 SOL_TIPC = 0x10f + SOL_TLS = 0x11a SOL_X25 = 0x106 + SOL_XDP = 0x11b SOMAXCONN = 0x80 SO_ACCEPTCONN = 0x1e SO_ATTACH_BPF = 0x32 @@ -1590,6 +1923,17 @@ const ( SO_DETACH_FILTER = 0x1b SO_DOMAIN = 0x27 SO_DONTROUTE = 0x5 + SO_EE_CODE_TXTIME_INVALID_PARAM = 0x1 + SO_EE_CODE_TXTIME_MISSED = 0x2 + SO_EE_CODE_ZEROCOPY_COPIED = 0x1 + SO_EE_ORIGIN_ICMP = 0x2 + SO_EE_ORIGIN_ICMP6 = 0x3 + SO_EE_ORIGIN_LOCAL = 0x1 + SO_EE_ORIGIN_NONE = 0x0 + SO_EE_ORIGIN_TIMESTAMPING = 0x4 + SO_EE_ORIGIN_TXSTATUS = 0x4 + SO_EE_ORIGIN_TXTIME = 0x6 + SO_EE_ORIGIN_ZEROCOPY = 0x5 SO_ERROR = 0x4 SO_GET_FILTER = 0x1a SO_INCOMING_CPU = 0x31 @@ -1630,6 +1974,7 @@ const ( SO_TIMESTAMP = 0x1d SO_TIMESTAMPING = 0x25 SO_TIMESTAMPNS = 0x23 + SO_TXTIME = 0x3d SO_TYPE = 0x3 SO_VM_SOCKETS_BUFFER_MAX_SIZE = 0x2 SO_VM_SOCKETS_BUFFER_MIN_SIZE = 0x1 @@ -1639,10 +1984,38 @@ const ( SO_VM_SOCKETS_PEER_HOST_VM_ID = 0x3 SO_VM_SOCKETS_TRUSTED = 0x5 SO_WIFI_STATUS = 0x29 + SO_ZEROCOPY = 0x3c SPLICE_F_GIFT = 0x8 SPLICE_F_MORE = 0x4 SPLICE_F_MOVE = 0x1 SPLICE_F_NONBLOCK = 0x2 + SQUASHFS_MAGIC = 0x73717368 + STACK_END_MAGIC = 0x57ac6e9d + STATX_ALL = 0xfff + STATX_ATIME = 0x20 + STATX_ATTR_APPEND = 0x20 + STATX_ATTR_AUTOMOUNT = 0x1000 + STATX_ATTR_COMPRESSED = 0x4 + STATX_ATTR_ENCRYPTED = 0x800 + STATX_ATTR_IMMUTABLE = 0x10 + STATX_ATTR_NODUMP = 0x40 + STATX_BASIC_STATS = 0x7ff + STATX_BLOCKS = 0x400 + STATX_BTIME = 0x800 + STATX_CTIME = 0x80 + STATX_GID = 0x10 + STATX_INO = 0x100 + STATX_MODE = 0x2 + STATX_MTIME = 0x40 + STATX_NLINK = 0x4 + STATX_SIZE = 0x200 + STATX_TYPE = 0x1 + STATX_UID = 0x8 + STATX__RESERVED = 0x80000000 + SYNC_FILE_RANGE_WAIT_AFTER = 0x4 + SYNC_FILE_RANGE_WAIT_BEFORE = 0x1 + SYNC_FILE_RANGE_WRITE = 0x2 + SYSFS_MAGIC = 0x62656572 S_BLKSIZE = 0x200 S_IEXEC = 0x40 S_IFBLK = 0x6000 @@ -1680,7 +2053,7 @@ const ( TASKSTATS_GENL_NAME = "TASKSTATS" TASKSTATS_GENL_VERSION = 0x1 TASKSTATS_TYPE_MAX = 0x6 - TASKSTATS_VERSION = 0x8 + TASKSTATS_VERSION = 0x9 TCFLSH = 0x540b TCGETA = 0x5405 TCGETS = 0x5401 @@ -1694,6 +2067,7 @@ const ( TCOOFF = 0x0 TCOON = 0x1 TCP_CC_INFO = 0x1a + TCP_CM_INQ = 0x24 TCP_CONGESTION = 0xd TCP_COOKIE_IN_ALWAYS = 0x1 TCP_COOKIE_MAX = 0x10 @@ -1705,7 +2079,10 @@ const ( TCP_DEFER_ACCEPT = 0x9 TCP_FASTOPEN = 0x17 TCP_FASTOPEN_CONNECT = 0x1e + TCP_FASTOPEN_KEY = 0x21 + TCP_FASTOPEN_NO_COOKIE = 0x22 TCP_INFO = 0xb + TCP_INQ = 0x24 TCP_KEEPCNT = 0x6 TCP_KEEPIDLE = 0x4 TCP_KEEPINTVL = 0x5 @@ -1714,6 +2091,8 @@ const ( TCP_MAXWIN = 0xffff TCP_MAX_WINSHIFT = 0xe TCP_MD5SIG = 0xe + TCP_MD5SIG_EXT = 0x20 + TCP_MD5SIG_FLAG_PREFIX = 0x1 TCP_MD5SIG_MAXKEYLEN = 0x50 TCP_MSS = 0x200 TCP_MSS_DEFAULT = 0x218 @@ -1723,6 +2102,9 @@ const ( TCP_QUEUE_SEQ = 0x15 TCP_QUICKACK = 0xc TCP_REPAIR = 0x13 + TCP_REPAIR_OFF = 0x0 + TCP_REPAIR_OFF_NO_WP = -0x1 + TCP_REPAIR_ON = 0x1 TCP_REPAIR_OPTIONS = 0x16 TCP_REPAIR_QUEUE = 0x14 TCP_REPAIR_WINDOW = 0x1d @@ -1734,8 +2116,10 @@ const ( TCP_THIN_DUPACK = 0x11 TCP_THIN_LINEAR_TIMEOUTS = 0x10 TCP_TIMESTAMP = 0x18 + TCP_ULP = 0x1f TCP_USER_TIMEOUT = 0x12 TCP_WINDOW_CLAMP = 0xa + TCP_ZEROCOPY_RECEIVE = 0x23 TCSAFLUSH = 0x2 TCSBRK = 0x5409 TCSBRKP = 0x5425 @@ -1752,6 +2136,7 @@ const ( TCSETXF = 0x5434 TCSETXW = 0x5435 TCXONC = 0x540a + TIMER_ABSTIME = 0x1 TIOCCBRK = 0x5428 TIOCCONS = 0x541d TIOCEXCL = 0x540c @@ -1759,6 +2144,7 @@ const ( TIOCGETD = 0x5424 TIOCGEXCL = 0x80045440 TIOCGICOUNT = 0x545d + TIOCGISO7816 = 0x80285442 TIOCGLCKTRMIOS = 0x5456 TIOCGPGRP = 0x540f TIOCGPKT = 0x80045438 @@ -1812,6 +2198,7 @@ const ( TIOCSER_TEMT = 0x1 TIOCSETD = 0x5423 TIOCSIG = 0x40045436 + TIOCSISO7816 = 0xc0285443 TIOCSLCKTRMIOS = 0x5457 TIOCSPGRP = 0x5410 TIOCSPTLCK = 0x40045431 @@ -1821,7 +2208,27 @@ const ( TIOCSTI = 0x5412 TIOCSWINSZ = 0x5414 TIOCVHANGUP = 0x5437 + TMPFS_MAGIC = 0x1021994 TOSTOP = 0x100 + TPACKET_ALIGNMENT = 0x10 + TPACKET_HDRLEN = 0x34 + TP_STATUS_AVAILABLE = 0x0 + TP_STATUS_BLK_TMO = 0x20 + TP_STATUS_COPY = 0x2 + TP_STATUS_CSUMNOTREADY = 0x8 + TP_STATUS_CSUM_VALID = 0x80 + TP_STATUS_KERNEL = 0x0 + TP_STATUS_LOSING = 0x4 + TP_STATUS_SENDING = 0x2 + TP_STATUS_SEND_REQUEST = 0x1 + TP_STATUS_TS_RAW_HARDWARE = -0x80000000 + TP_STATUS_TS_SOFTWARE = 0x20000000 + TP_STATUS_TS_SYS_HARDWARE = 0x40000000 + TP_STATUS_USER = 0x1 + TP_STATUS_VLAN_TPID_VALID = 0x40 + TP_STATUS_VLAN_VALID = 0x10 + TP_STATUS_WRONG_FORMAT = 0x4 + TRACEFS_MAGIC = 0x74726163 TS_COMM_LEN = 0x20 TUNATTACHFILTER = 0x400854d5 TUNDETACHFILTER = 0x400854d6 @@ -1833,6 +2240,7 @@ const ( TUNGETVNETHDRSZ = 0x800454d7 TUNGETVNETLE = 0x800454dd TUNSETDEBUG = 0x400454c9 + TUNSETFILTEREBPF = 0x800454e1 TUNSETGROUP = 0x400454ce TUNSETIFF = 0x400454ca TUNSETIFINDEX = 0x400454da @@ -1843,13 +2251,32 @@ const ( TUNSETPERSIST = 0x400454cb TUNSETQUEUE = 0x400454d9 TUNSETSNDBUF = 0x400454d4 + TUNSETSTEERINGEBPF = 0x800454e0 TUNSETTXFILTER = 0x400454d1 TUNSETVNETBE = 0x400454de TUNSETVNETHDRSZ = 0x400454d8 TUNSETVNETLE = 0x400454dc + UBI_IOCATT = 0x40186f40 + UBI_IOCDET = 0x40046f41 + UBI_IOCEBCH = 0x40044f02 + UBI_IOCEBER = 0x40044f01 + UBI_IOCEBISMAP = 0x80044f05 + UBI_IOCEBMAP = 0x40084f03 + UBI_IOCEBUNMAP = 0x40044f04 + UBI_IOCMKVOL = 0x40986f00 + UBI_IOCRMVOL = 0x40046f01 + UBI_IOCRNVOL = 0x51106f03 + UBI_IOCRSVOL = 0x400c6f02 + UBI_IOCSETVOLPROP = 0x40104f06 + UBI_IOCVOLCRBLK = 0x40804f07 + UBI_IOCVOLRMBLK = 0x4f08 + UBI_IOCVOLUP = 0x40084f00 + UDF_SUPER_MAGIC = 0x15013346 UMOUNT_NOFOLLOW = 0x8 + USBDEVICE_SUPER_MAGIC = 0x9fa2 UTIME_NOW = 0x3fffffff UTIME_OMIT = 0x3ffffffe + V9FS_MAGIC = 0x1021997 VDISCARD = 0xd VEOF = 0x4 VEOL = 0xb @@ -1891,6 +2318,86 @@ const ( WDIOC_SETPRETIMEOUT = 0xc0045708 WDIOC_SETTIMEOUT = 0xc0045706 WEXITED = 0x4 + WIN_ACKMEDIACHANGE = 0xdb + WIN_CHECKPOWERMODE1 = 0xe5 + WIN_CHECKPOWERMODE2 = 0x98 + WIN_DEVICE_RESET = 0x8 + WIN_DIAGNOSE = 0x90 + WIN_DOORLOCK = 0xde + WIN_DOORUNLOCK = 0xdf + WIN_DOWNLOAD_MICROCODE = 0x92 + WIN_FLUSH_CACHE = 0xe7 + WIN_FLUSH_CACHE_EXT = 0xea + WIN_FORMAT = 0x50 + WIN_GETMEDIASTATUS = 0xda + WIN_IDENTIFY = 0xec + WIN_IDENTIFY_DMA = 0xee + WIN_IDLEIMMEDIATE = 0xe1 + WIN_INIT = 0x60 + WIN_MEDIAEJECT = 0xed + WIN_MULTREAD = 0xc4 + WIN_MULTREAD_EXT = 0x29 + WIN_MULTWRITE = 0xc5 + WIN_MULTWRITE_EXT = 0x39 + WIN_NOP = 0x0 + WIN_PACKETCMD = 0xa0 + WIN_PIDENTIFY = 0xa1 + WIN_POSTBOOT = 0xdc + WIN_PREBOOT = 0xdd + WIN_QUEUED_SERVICE = 0xa2 + WIN_READ = 0x20 + WIN_READDMA = 0xc8 + WIN_READDMA_EXT = 0x25 + WIN_READDMA_ONCE = 0xc9 + WIN_READDMA_QUEUED = 0xc7 + WIN_READDMA_QUEUED_EXT = 0x26 + WIN_READ_BUFFER = 0xe4 + WIN_READ_EXT = 0x24 + WIN_READ_LONG = 0x22 + WIN_READ_LONG_ONCE = 0x23 + WIN_READ_NATIVE_MAX = 0xf8 + WIN_READ_NATIVE_MAX_EXT = 0x27 + WIN_READ_ONCE = 0x21 + WIN_RECAL = 0x10 + WIN_RESTORE = 0x10 + WIN_SECURITY_DISABLE = 0xf6 + WIN_SECURITY_ERASE_PREPARE = 0xf3 + WIN_SECURITY_ERASE_UNIT = 0xf4 + WIN_SECURITY_FREEZE_LOCK = 0xf5 + WIN_SECURITY_SET_PASS = 0xf1 + WIN_SECURITY_UNLOCK = 0xf2 + WIN_SEEK = 0x70 + WIN_SETFEATURES = 0xef + WIN_SETIDLE1 = 0xe3 + WIN_SETIDLE2 = 0x97 + WIN_SETMULT = 0xc6 + WIN_SET_MAX = 0xf9 + WIN_SET_MAX_EXT = 0x37 + WIN_SLEEPNOW1 = 0xe6 + WIN_SLEEPNOW2 = 0x99 + WIN_SMART = 0xb0 + WIN_SPECIFY = 0x91 + WIN_SRST = 0x8 + WIN_STANDBY = 0xe2 + WIN_STANDBY2 = 0x96 + WIN_STANDBYNOW1 = 0xe0 + WIN_STANDBYNOW2 = 0x94 + WIN_VERIFY = 0x40 + WIN_VERIFY_EXT = 0x42 + WIN_VERIFY_ONCE = 0x41 + WIN_WRITE = 0x30 + WIN_WRITEDMA = 0xca + WIN_WRITEDMA_EXT = 0x35 + WIN_WRITEDMA_ONCE = 0xcb + WIN_WRITEDMA_QUEUED = 0xcc + WIN_WRITEDMA_QUEUED_EXT = 0x36 + WIN_WRITE_BUFFER = 0xe8 + WIN_WRITE_EXT = 0x34 + WIN_WRITE_LONG = 0x32 + WIN_WRITE_LONG_ONCE = 0x33 + WIN_WRITE_ONCE = 0x31 + WIN_WRITE_SAME = 0xe9 + WIN_WRITE_VERIFY = 0x3c WNOHANG = 0x1 WNOTHREAD = 0x20000000 WNOWAIT = 0x1000000 @@ -1900,7 +2407,30 @@ const ( XATTR_CREATE = 0x1 XATTR_REPLACE = 0x2 XCASE = 0x4 + XDP_COPY = 0x2 + XDP_FLAGS_DRV_MODE = 0x4 + XDP_FLAGS_HW_MODE = 0x8 + XDP_FLAGS_MASK = 0xf + XDP_FLAGS_MODES = 0xe + XDP_FLAGS_SKB_MODE = 0x2 + XDP_FLAGS_UPDATE_IF_NOEXIST = 0x1 + XDP_MMAP_OFFSETS = 0x1 + XDP_PGOFF_RX_RING = 0x0 + XDP_PGOFF_TX_RING = 0x80000000 + XDP_RX_RING = 0x2 + XDP_SHARED_UMEM = 0x1 + XDP_STATISTICS = 0x7 + XDP_TX_RING = 0x3 + XDP_UMEM_COMPLETION_RING = 0x6 + XDP_UMEM_FILL_RING = 0x5 + XDP_UMEM_PGOFF_COMPLETION_RING = 0x180000000 + XDP_UMEM_PGOFF_FILL_RING = 0x100000000 + XDP_UMEM_REG = 0x4 + XDP_ZEROCOPY = 0x4 + XENFS_SUPER_MAGIC = 0xabba1974 + XFS_SUPER_MAGIC = 0x58465342 XTABS = 0x1800 + ZSMALLOC_MAGIC = 0x58295829 ) // Errors @@ -2080,171 +2610,179 @@ const ( ) // Error table -var errors = [...]string{ - 1: "operation not permitted", - 2: "no such file or directory", - 3: "no such process", - 4: "interrupted system call", - 5: "input/output error", - 6: "no such device or address", - 7: "argument list too long", - 8: "exec format error", - 9: "bad file descriptor", - 10: "no child processes", - 11: "resource temporarily unavailable", - 12: "cannot allocate memory", - 13: "permission denied", - 14: "bad address", - 15: "block device required", - 16: "device or resource busy", - 17: "file exists", - 18: "invalid cross-device link", - 19: "no such device", - 20: "not a directory", - 21: "is a directory", - 22: "invalid argument", - 23: "too many open files in system", - 24: "too many open files", - 25: "inappropriate ioctl for device", - 26: "text file busy", - 27: "file too large", - 28: "no space left on device", - 29: "illegal seek", - 30: "read-only file system", - 31: "too many links", - 32: "broken pipe", - 33: "numerical argument out of domain", - 34: "numerical result out of range", - 35: "resource deadlock avoided", - 36: "file name too long", - 37: "no locks available", - 38: "function not implemented", - 39: "directory not empty", - 40: "too many levels of symbolic links", - 42: "no message of desired type", - 43: "identifier removed", - 44: "channel number out of range", - 45: "level 2 not synchronized", - 46: "level 3 halted", - 47: "level 3 reset", - 48: "link number out of range", - 49: "protocol driver not attached", - 50: "no CSI structure available", - 51: "level 2 halted", - 52: "invalid exchange", - 53: "invalid request descriptor", - 54: "exchange full", - 55: "no anode", - 56: "invalid request code", - 57: "invalid slot", - 59: "bad font file format", - 60: "device not a stream", - 61: "no data available", - 62: "timer expired", - 63: "out of streams resources", - 64: "machine is not on the network", - 65: "package not installed", - 66: "object is remote", - 67: "link has been severed", - 68: "advertise error", - 69: "srmount error", - 70: "communication error on send", - 71: "protocol error", - 72: "multihop attempted", - 73: "RFS specific error", - 74: "bad message", - 75: "value too large for defined data type", - 76: "name not unique on network", - 77: "file descriptor in bad state", - 78: "remote address changed", - 79: "can not access a needed shared library", - 80: "accessing a corrupted shared library", - 81: ".lib section in a.out corrupted", - 82: "attempting to link in too many shared libraries", - 83: "cannot exec a shared library directly", - 84: "invalid or incomplete multibyte or wide character", - 85: "interrupted system call should be restarted", - 86: "streams pipe error", - 87: "too many users", - 88: "socket operation on non-socket", - 89: "destination address required", - 90: "message too long", - 91: "protocol wrong type for socket", - 92: "protocol not available", - 93: "protocol not supported", - 94: "socket type not supported", - 95: "operation not supported", - 96: "protocol family not supported", - 97: "address family not supported by protocol", - 98: "address already in use", - 99: "cannot assign requested address", - 100: "network is down", - 101: "network is unreachable", - 102: "network dropped connection on reset", - 103: "software caused connection abort", - 104: "connection reset by peer", - 105: "no buffer space available", - 106: "transport endpoint is already connected", - 107: "transport endpoint is not connected", - 108: "cannot send after transport endpoint shutdown", - 109: "too many references: cannot splice", - 110: "connection timed out", - 111: "connection refused", - 112: "host is down", - 113: "no route to host", - 114: "operation already in progress", - 115: "operation now in progress", - 116: "stale file handle", - 117: "structure needs cleaning", - 118: "not a XENIX named type file", - 119: "no XENIX semaphores available", - 120: "is a named type file", - 121: "remote I/O error", - 122: "disk quota exceeded", - 123: "no medium found", - 124: "wrong medium type", - 125: "operation canceled", - 126: "required key not available", - 127: "key has expired", - 128: "key has been revoked", - 129: "key was rejected by service", - 130: "owner died", - 131: "state not recoverable", - 132: "operation not possible due to RF-kill", - 133: "memory page has hardware error", +var errorList = [...]struct { + num syscall.Errno + name string + desc string +}{ + {1, "EPERM", "operation not permitted"}, + {2, "ENOENT", "no such file or directory"}, + {3, "ESRCH", "no such process"}, + {4, "EINTR", "interrupted system call"}, + {5, "EIO", "input/output error"}, + {6, "ENXIO", "no such device or address"}, + {7, "E2BIG", "argument list too long"}, + {8, "ENOEXEC", "exec format error"}, + {9, "EBADF", "bad file descriptor"}, + {10, "ECHILD", "no child processes"}, + {11, "EAGAIN", "resource temporarily unavailable"}, + {12, "ENOMEM", "cannot allocate memory"}, + {13, "EACCES", "permission denied"}, + {14, "EFAULT", "bad address"}, + {15, "ENOTBLK", "block device required"}, + {16, "EBUSY", "device or resource busy"}, + {17, "EEXIST", "file exists"}, + {18, "EXDEV", "invalid cross-device link"}, + {19, "ENODEV", "no such device"}, + {20, "ENOTDIR", "not a directory"}, + {21, "EISDIR", "is a directory"}, + {22, "EINVAL", "invalid argument"}, + {23, "ENFILE", "too many open files in system"}, + {24, "EMFILE", "too many open files"}, + {25, "ENOTTY", "inappropriate ioctl for device"}, + {26, "ETXTBSY", "text file busy"}, + {27, "EFBIG", "file too large"}, + {28, "ENOSPC", "no space left on device"}, + {29, "ESPIPE", "illegal seek"}, + {30, "EROFS", "read-only file system"}, + {31, "EMLINK", "too many links"}, + {32, "EPIPE", "broken pipe"}, + {33, "EDOM", "numerical argument out of domain"}, + {34, "ERANGE", "numerical result out of range"}, + {35, "EDEADLK", "resource deadlock avoided"}, + {36, "ENAMETOOLONG", "file name too long"}, + {37, "ENOLCK", "no locks available"}, + {38, "ENOSYS", "function not implemented"}, + {39, "ENOTEMPTY", "directory not empty"}, + {40, "ELOOP", "too many levels of symbolic links"}, + {42, "ENOMSG", "no message of desired type"}, + {43, "EIDRM", "identifier removed"}, + {44, "ECHRNG", "channel number out of range"}, + {45, "EL2NSYNC", "level 2 not synchronized"}, + {46, "EL3HLT", "level 3 halted"}, + {47, "EL3RST", "level 3 reset"}, + {48, "ELNRNG", "link number out of range"}, + {49, "EUNATCH", "protocol driver not attached"}, + {50, "ENOCSI", "no CSI structure available"}, + {51, "EL2HLT", "level 2 halted"}, + {52, "EBADE", "invalid exchange"}, + {53, "EBADR", "invalid request descriptor"}, + {54, "EXFULL", "exchange full"}, + {55, "ENOANO", "no anode"}, + {56, "EBADRQC", "invalid request code"}, + {57, "EBADSLT", "invalid slot"}, + {59, "EBFONT", "bad font file format"}, + {60, "ENOSTR", "device not a stream"}, + {61, "ENODATA", "no data available"}, + {62, "ETIME", "timer expired"}, + {63, "ENOSR", "out of streams resources"}, + {64, "ENONET", "machine is not on the network"}, + {65, "ENOPKG", "package not installed"}, + {66, "EREMOTE", "object is remote"}, + {67, "ENOLINK", "link has been severed"}, + {68, "EADV", "advertise error"}, + {69, "ESRMNT", "srmount error"}, + {70, "ECOMM", "communication error on send"}, + {71, "EPROTO", "protocol error"}, + {72, "EMULTIHOP", "multihop attempted"}, + {73, "EDOTDOT", "RFS specific error"}, + {74, "EBADMSG", "bad message"}, + {75, "EOVERFLOW", "value too large for defined data type"}, + {76, "ENOTUNIQ", "name not unique on network"}, + {77, "EBADFD", "file descriptor in bad state"}, + {78, "EREMCHG", "remote address changed"}, + {79, "ELIBACC", "can not access a needed shared library"}, + {80, "ELIBBAD", "accessing a corrupted shared library"}, + {81, "ELIBSCN", ".lib section in a.out corrupted"}, + {82, "ELIBMAX", "attempting to link in too many shared libraries"}, + {83, "ELIBEXEC", "cannot exec a shared library directly"}, + {84, "EILSEQ", "invalid or incomplete multibyte or wide character"}, + {85, "ERESTART", "interrupted system call should be restarted"}, + {86, "ESTRPIPE", "streams pipe error"}, + {87, "EUSERS", "too many users"}, + {88, "ENOTSOCK", "socket operation on non-socket"}, + {89, "EDESTADDRREQ", "destination address required"}, + {90, "EMSGSIZE", "message too long"}, + {91, "EPROTOTYPE", "protocol wrong type for socket"}, + {92, "ENOPROTOOPT", "protocol not available"}, + {93, "EPROTONOSUPPORT", "protocol not supported"}, + {94, "ESOCKTNOSUPPORT", "socket type not supported"}, + {95, "ENOTSUP", "operation not supported"}, + {96, "EPFNOSUPPORT", "protocol family not supported"}, + {97, "EAFNOSUPPORT", "address family not supported by protocol"}, + {98, "EADDRINUSE", "address already in use"}, + {99, "EADDRNOTAVAIL", "cannot assign requested address"}, + {100, "ENETDOWN", "network is down"}, + {101, "ENETUNREACH", "network is unreachable"}, + {102, "ENETRESET", "network dropped connection on reset"}, + {103, "ECONNABORTED", "software caused connection abort"}, + {104, "ECONNRESET", "connection reset by peer"}, + {105, "ENOBUFS", "no buffer space available"}, + {106, "EISCONN", "transport endpoint is already connected"}, + {107, "ENOTCONN", "transport endpoint is not connected"}, + {108, "ESHUTDOWN", "cannot send after transport endpoint shutdown"}, + {109, "ETOOMANYREFS", "too many references: cannot splice"}, + {110, "ETIMEDOUT", "connection timed out"}, + {111, "ECONNREFUSED", "connection refused"}, + {112, "EHOSTDOWN", "host is down"}, + {113, "EHOSTUNREACH", "no route to host"}, + {114, "EALREADY", "operation already in progress"}, + {115, "EINPROGRESS", "operation now in progress"}, + {116, "ESTALE", "stale file handle"}, + {117, "EUCLEAN", "structure needs cleaning"}, + {118, "ENOTNAM", "not a XENIX named type file"}, + {119, "ENAVAIL", "no XENIX semaphores available"}, + {120, "EISNAM", "is a named type file"}, + {121, "EREMOTEIO", "remote I/O error"}, + {122, "EDQUOT", "disk quota exceeded"}, + {123, "ENOMEDIUM", "no medium found"}, + {124, "EMEDIUMTYPE", "wrong medium type"}, + {125, "ECANCELED", "operation canceled"}, + {126, "ENOKEY", "required key not available"}, + {127, "EKEYEXPIRED", "key has expired"}, + {128, "EKEYREVOKED", "key has been revoked"}, + {129, "EKEYREJECTED", "key was rejected by service"}, + {130, "EOWNERDEAD", "owner died"}, + {131, "ENOTRECOVERABLE", "state not recoverable"}, + {132, "ERFKILL", "operation not possible due to RF-kill"}, + {133, "EHWPOISON", "memory page has hardware error"}, } // Signal table -var signals = [...]string{ - 1: "hangup", - 2: "interrupt", - 3: "quit", - 4: "illegal instruction", - 5: "trace/breakpoint trap", - 6: "aborted", - 7: "bus error", - 8: "floating point exception", - 9: "killed", - 10: "user defined signal 1", - 11: "segmentation fault", - 12: "user defined signal 2", - 13: "broken pipe", - 14: "alarm clock", - 15: "terminated", - 16: "stack fault", - 17: "child exited", - 18: "continued", - 19: "stopped (signal)", - 20: "stopped", - 21: "stopped (tty input)", - 22: "stopped (tty output)", - 23: "urgent I/O condition", - 24: "CPU time limit exceeded", - 25: "file size limit exceeded", - 26: "virtual timer expired", - 27: "profiling timer expired", - 28: "window changed", - 29: "I/O possible", - 30: "power failure", - 31: "bad system call", +var signalList = [...]struct { + num syscall.Signal + name string + desc string +}{ + {1, "SIGHUP", "hangup"}, + {2, "SIGINT", "interrupt"}, + {3, "SIGQUIT", "quit"}, + {4, "SIGILL", "illegal instruction"}, + {5, "SIGTRAP", "trace/breakpoint trap"}, + {6, "SIGABRT", "aborted"}, + {7, "SIGBUS", "bus error"}, + {8, "SIGFPE", "floating point exception"}, + {9, "SIGKILL", "killed"}, + {10, "SIGUSR1", "user defined signal 1"}, + {11, "SIGSEGV", "segmentation fault"}, + {12, "SIGUSR2", "user defined signal 2"}, + {13, "SIGPIPE", "broken pipe"}, + {14, "SIGALRM", "alarm clock"}, + {15, "SIGTERM", "terminated"}, + {16, "SIGSTKFLT", "stack fault"}, + {17, "SIGCHLD", "child exited"}, + {18, "SIGCONT", "continued"}, + {19, "SIGSTOP", "stopped (signal)"}, + {20, "SIGTSTP", "stopped"}, + {21, "SIGTTIN", "stopped (tty input)"}, + {22, "SIGTTOU", "stopped (tty output)"}, + {23, "SIGURG", "urgent I/O condition"}, + {24, "SIGXCPU", "CPU time limit exceeded"}, + {25, "SIGXFSZ", "file size limit exceeded"}, + {26, "SIGVTALRM", "virtual timer expired"}, + {27, "SIGPROF", "profiling timer expired"}, + {28, "SIGWINCH", "window changed"}, + {29, "SIGIO", "I/O possible"}, + {30, "SIGPWR", "power failure"}, + {31, "SIGSYS", "bad system call"}, } diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go index 69ad31470d..cf17c99069 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go @@ -3,7 +3,7 @@ // +build arm64,linux -// Created by cgo -godefs - DO NOT EDIT +// Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs -- -Wall -Werror -static -I/tmp/include -fsigned-char _const.go package unix @@ -11,6 +11,11 @@ package unix import "syscall" const ( + AAFS_MAGIC = 0x5a3c69f0 + ADFS_SUPER_MAGIC = 0xadf5 + AFFS_SUPER_MAGIC = 0xadff + AFS_FS_MAGIC = 0x6b414653 + AFS_SUPER_MAGIC = 0x5346414f AF_ALG = 0x26 AF_APPLETALK = 0x5 AF_ASH = 0x12 @@ -36,7 +41,7 @@ const ( AF_KEY = 0xf AF_LLC = 0x1a AF_LOCAL = 0x1 - AF_MAX = 0x2c + AF_MAX = 0x2d AF_MPLS = 0x1c AF_NETBEUI = 0xd AF_NETLINK = 0x10 @@ -59,6 +64,7 @@ const ( AF_VSOCK = 0x28 AF_WANPIPE = 0x19 AF_X25 = 0x9 + AF_XDP = 0x2c ALG_OP_DECRYPT = 0x0 ALG_OP_ENCRYPT = 0x1 ALG_SET_AEAD_ASSOCLEN = 0x4 @@ -66,6 +72,7 @@ const ( ALG_SET_IV = 0x2 ALG_SET_KEY = 0x1 ALG_SET_OP = 0x3 + ANON_INODE_FS_MAGIC = 0x9041934 ARPHRD_6LOWPAN = 0x339 ARPHRD_ADAPT = 0x108 ARPHRD_APPLETLK = 0x8 @@ -121,6 +128,7 @@ const ( ARPHRD_PPP = 0x200 ARPHRD_PRONET = 0x4 ARPHRD_RAWHDLC = 0x206 + ARPHRD_RAWIP = 0x207 ARPHRD_ROSE = 0x10e ARPHRD_RSRVD = 0x104 ARPHRD_SIT = 0x308 @@ -132,6 +140,7 @@ const ( ARPHRD_VOID = 0xffff ARPHRD_VSOCKMON = 0x33a ARPHRD_X25 = 0x10f + AUTOFS_SUPER_MAGIC = 0x187 B0 = 0x0 B1000000 = 0x1008 B110 = 0x3 @@ -163,6 +172,9 @@ const ( B75 = 0x2 B921600 = 0x1007 B9600 = 0xd + BALLOON_KVM_MAGIC = 0x13661366 + BDEVFS_MAGIC = 0x62646576 + BINFMTFS_MAGIC = 0x42494e4d BLKBSZGET = 0x80081270 BLKBSZSET = 0x40081271 BLKFLSBUF = 0x1261 @@ -187,6 +199,7 @@ const ( BPF_AND = 0x50 BPF_B = 0x10 BPF_DIV = 0x30 + BPF_FS_MAGIC = 0xcafe4a11 BPF_H = 0x8 BPF_IMM = 0x0 BPF_IND = 0x40 @@ -228,6 +241,8 @@ const ( BS0 = 0x0 BS1 = 0x2000 BSDLY = 0x2000 + BTRFS_SUPER_MAGIC = 0x9123683e + BTRFS_TEST_MAGIC = 0x73727279 CAN_BCM = 0x2 CAN_EFF_FLAG = 0x80000000 CAN_EFF_ID_BITS = 0x1d @@ -251,6 +266,8 @@ const ( CBAUD = 0x100f CBAUDEX = 0x1000 CFLUSH = 0xf + CGROUP2_SUPER_MAGIC = 0x63677270 + CGROUP_SUPER_MAGIC = 0x27e0eb CIBAUD = 0x100f0000 CLOCAL = 0x800 CLOCK_BOOTTIME = 0x7 @@ -293,10 +310,12 @@ const ( CLONE_VFORK = 0x4000 CLONE_VM = 0x100 CMSPAR = 0x40000000 + CODA_SUPER_MAGIC = 0x73757245 CR0 = 0x0 CR1 = 0x200 CR2 = 0x400 CR3 = 0x600 + CRAMFS_MAGIC = 0x28cd3d45 CRDLY = 0x600 CREAD = 0x80 CRTSCTS = 0x80000000 @@ -311,6 +330,9 @@ const ( CSTOP = 0x13 CSTOPB = 0x40 CSUSP = 0x1a + DAXFS_MAGIC = 0x64646178 + DEBUGFS_MAGIC = 0x64626720 + DEVPTS_SUPER_MAGIC = 0x1cd1 DT_BLK = 0x6 DT_CHR = 0x2 DT_DIR = 0x4 @@ -327,9 +349,12 @@ const ( ECHOKE = 0x800 ECHONL = 0x40 ECHOPRT = 0x400 + ECRYPTFS_SUPER_MAGIC = 0xf15f EFD_CLOEXEC = 0x80000 EFD_NONBLOCK = 0x800 EFD_SEMAPHORE = 0x1 + EFIVARFS_MAGIC = 0xde5e81e4 + EFS_SUPER_MAGIC = 0x414a53 ENCODING_DEFAULT = 0x0 ENCODING_FM_MARK = 0x3 ENCODING_FM_SPACE = 0x4 @@ -391,6 +416,8 @@ const ( ETH_P_DSA = 0x1b ETH_P_ECONET = 0x18 ETH_P_EDSA = 0xdada + ETH_P_ERSPAN = 0x88be + ETH_P_ERSPAN2 = 0x22eb ETH_P_FCOE = 0x8906 ETH_P_FIP = 0x8914 ETH_P_HDLC = 0x19 @@ -399,6 +426,7 @@ const ( ETH_P_IEEE802154 = 0xf6 ETH_P_IEEEPUP = 0xa00 ETH_P_IEEEPUPAT = 0xa01 + ETH_P_IFE = 0xed3e ETH_P_IP = 0x800 ETH_P_IPV6 = 0x86dd ETH_P_IPX = 0x8137 @@ -409,11 +437,13 @@ const ( ETH_P_LOOP = 0x60 ETH_P_LOOPBACK = 0x9000 ETH_P_MACSEC = 0x88e5 + ETH_P_MAP = 0xf9 ETH_P_MOBITEX = 0x15 ETH_P_MPLS_MC = 0x8848 ETH_P_MPLS_UC = 0x8847 ETH_P_MVRP = 0x88f5 ETH_P_NCSI = 0x88f8 + ETH_P_NSH = 0x894f ETH_P_PAE = 0x888e ETH_P_PAUSE = 0x8808 ETH_P_PHONET = 0xf5 @@ -421,6 +451,7 @@ const ( ETH_P_PPP_DISC = 0x8863 ETH_P_PPP_MP = 0x8 ETH_P_PPP_SES = 0x8864 + ETH_P_PREAUTH = 0x88c7 ETH_P_PRP = 0x88fb ETH_P_PUP = 0x200 ETH_P_PUPAT = 0x201 @@ -441,10 +472,15 @@ const ( ETH_P_WCCP = 0x883e ETH_P_X25 = 0x805 ETH_P_XDSA = 0xf8 + EXABYTE_ENABLE_NEST = 0xf0 + EXT2_SUPER_MAGIC = 0xef53 + EXT3_SUPER_MAGIC = 0xef53 + EXT4_SUPER_MAGIC = 0xef53 EXTA = 0xe EXTB = 0xf EXTPROC = 0x10000 EXTRA_MAGIC = 0x45585401 + F2FS_SUPER_MAGIC = 0xf2f52010 FALLOC_FL_COLLAPSE_RANGE = 0x8 FALLOC_FL_INSERT_RANGE = 0x20 FALLOC_FL_KEEP_SIZE = 0x1 @@ -458,6 +494,7 @@ const ( FF1 = 0x8000 FFDLY = 0x8000 FLUSHO = 0x1000 + FPSIMD_MAGIC = 0x46508001 FS_ENCRYPTION_MODE_AES_128_CBC = 0x5 FS_ENCRYPTION_MODE_AES_128_CTS = 0x6 FS_ENCRYPTION_MODE_AES_256_CBC = 0x3 @@ -465,6 +502,8 @@ const ( FS_ENCRYPTION_MODE_AES_256_GCM = 0x2 FS_ENCRYPTION_MODE_AES_256_XTS = 0x1 FS_ENCRYPTION_MODE_INVALID = 0x0 + FS_ENCRYPTION_MODE_SPECK128_256_CTS = 0x8 + FS_ENCRYPTION_MODE_SPECK128_256_XTS = 0x7 FS_IOC_GET_ENCRYPTION_POLICY = 0x400c6615 FS_IOC_GET_ENCRYPTION_PWSALT = 0x40106614 FS_IOC_SET_ENCRYPTION_POLICY = 0x800c6613 @@ -478,6 +517,8 @@ const ( FS_POLICY_FLAGS_PAD_8 = 0x1 FS_POLICY_FLAGS_PAD_MASK = 0x3 FS_POLICY_FLAGS_VALID = 0x3 + FUTEXFS_SUPER_MAGIC = 0xbad1dea + F_ADD_SEALS = 0x409 F_DUPFD = 0x0 F_DUPFD_CLOEXEC = 0x406 F_EXLCK = 0x4 @@ -490,6 +531,9 @@ const ( F_GETOWN_EX = 0x10 F_GETPIPE_SZ = 0x408 F_GETSIG = 0xb + F_GET_FILE_RW_HINT = 0x40d + F_GET_RW_HINT = 0x40b + F_GET_SEALS = 0x40a F_LOCK = 0x1 F_NOTIFY = 0x402 F_OFD_GETLK = 0x24 @@ -497,6 +541,10 @@ const ( F_OFD_SETLKW = 0x26 F_OK = 0x0 F_RDLCK = 0x0 + F_SEAL_GROW = 0x4 + F_SEAL_SEAL = 0x1 + F_SEAL_SHRINK = 0x2 + F_SEAL_WRITE = 0x8 F_SETFD = 0x2 F_SETFL = 0x4 F_SETLEASE = 0x400 @@ -508,6 +556,8 @@ const ( F_SETOWN_EX = 0xf F_SETPIPE_SZ = 0x407 F_SETSIG = 0xa + F_SET_FILE_RW_HINT = 0x40e + F_SET_RW_HINT = 0x40c F_SHLCK = 0x8 F_TEST = 0x3 F_TLOCK = 0x2 @@ -529,6 +579,49 @@ const ( GENL_UNS_ADMIN_PERM = 0x10 GRND_NONBLOCK = 0x1 GRND_RANDOM = 0x2 + HDIO_DRIVE_CMD = 0x31f + HDIO_DRIVE_CMD_AEB = 0x31e + HDIO_DRIVE_CMD_HDR_SIZE = 0x4 + HDIO_DRIVE_HOB_HDR_SIZE = 0x8 + HDIO_DRIVE_RESET = 0x31c + HDIO_DRIVE_TASK = 0x31e + HDIO_DRIVE_TASKFILE = 0x31d + HDIO_DRIVE_TASK_HDR_SIZE = 0x8 + HDIO_GETGEO = 0x301 + HDIO_GET_32BIT = 0x309 + HDIO_GET_ACOUSTIC = 0x30f + HDIO_GET_ADDRESS = 0x310 + HDIO_GET_BUSSTATE = 0x31a + HDIO_GET_DMA = 0x30b + HDIO_GET_IDENTITY = 0x30d + HDIO_GET_KEEPSETTINGS = 0x308 + HDIO_GET_MULTCOUNT = 0x304 + HDIO_GET_NICE = 0x30c + HDIO_GET_NOWERR = 0x30a + HDIO_GET_QDMA = 0x305 + HDIO_GET_UNMASKINTR = 0x302 + HDIO_GET_WCACHE = 0x30e + HDIO_OBSOLETE_IDENTITY = 0x307 + HDIO_SCAN_HWIF = 0x328 + HDIO_SET_32BIT = 0x324 + HDIO_SET_ACOUSTIC = 0x32c + HDIO_SET_ADDRESS = 0x32f + HDIO_SET_BUSSTATE = 0x32d + HDIO_SET_DMA = 0x326 + HDIO_SET_KEEPSETTINGS = 0x323 + HDIO_SET_MULTCOUNT = 0x321 + HDIO_SET_NICE = 0x329 + HDIO_SET_NOWERR = 0x325 + HDIO_SET_PIO_MODE = 0x327 + HDIO_SET_QDMA = 0x32e + HDIO_SET_UNMASKINTR = 0x322 + HDIO_SET_WCACHE = 0x32b + HDIO_SET_XFER = 0x306 + HDIO_TRISTATE_HWIF = 0x31b + HDIO_UNREGISTER_HWIF = 0x32a + HOSTFS_SUPER_MAGIC = 0xc0ffee + HPFS_SUPER_MAGIC = 0xf995e849 + HUGETLBFS_MAGIC = 0x958458f6 HUPCL = 0x400 IBSHIFT = 0x10 ICANON = 0x2 @@ -548,7 +641,7 @@ const ( IFA_F_STABLE_PRIVACY = 0x800 IFA_F_TEMPORARY = 0x1 IFA_F_TENTATIVE = 0x40 - IFA_MAX = 0x8 + IFA_MAX = 0xa IFF_ALLMULTI = 0x200 IFF_ATTACH_QUEUE = 0x200 IFF_AUTOMEDIA = 0x4000 @@ -563,6 +656,8 @@ const ( IFF_MASTER = 0x400 IFF_MULTICAST = 0x1000 IFF_MULTI_QUEUE = 0x100 + IFF_NAPI = 0x10 + IFF_NAPI_FRAGS = 0x20 IFF_NOARP = 0x80 IFF_NOFILTER = 0x1000 IFF_NOTRAILERS = 0x20 @@ -614,6 +709,7 @@ const ( IN_ISDIR = 0x40000000 IN_LOOPBACKNET = 0x7f IN_MASK_ADD = 0x20000000 + IN_MASK_CREATE = 0x10000000 IN_MODIFY = 0x2 IN_MOVE = 0xc0 IN_MOVED_FROM = 0x40 @@ -673,6 +769,7 @@ const ( IPV6_DONTFRAG = 0x3e IPV6_DROP_MEMBERSHIP = 0x15 IPV6_DSTOPTS = 0x3b + IPV6_FREEBIND = 0x4e IPV6_HDRINCL = 0x24 IPV6_HOPLIMIT = 0x34 IPV6_HOPOPTS = 0x36 @@ -684,6 +781,7 @@ const ( IPV6_MINHOPCOUNT = 0x49 IPV6_MTU = 0x18 IPV6_MTU_DISCOVER = 0x17 + IPV6_MULTICAST_ALL = 0x1d IPV6_MULTICAST_HOPS = 0x12 IPV6_MULTICAST_IF = 0x11 IPV6_MULTICAST_LOOP = 0x13 @@ -777,12 +875,34 @@ const ( IP_UNICAST_IF = 0x32 IP_XFRM_POLICY = 0x11 ISIG = 0x1 + ISOFS_SUPER_MAGIC = 0x9660 ISTRIP = 0x20 IUCLC = 0x200 IUTF8 = 0x4000 IXANY = 0x800 IXOFF = 0x1000 IXON = 0x400 + JFFS2_SUPER_MAGIC = 0x72b6 + KEXEC_ARCH_386 = 0x30000 + KEXEC_ARCH_68K = 0x40000 + KEXEC_ARCH_AARCH64 = 0xb70000 + KEXEC_ARCH_ARM = 0x280000 + KEXEC_ARCH_DEFAULT = 0x0 + KEXEC_ARCH_IA_64 = 0x320000 + KEXEC_ARCH_MASK = 0xffff0000 + KEXEC_ARCH_MIPS = 0x80000 + KEXEC_ARCH_MIPS_LE = 0xa0000 + KEXEC_ARCH_PPC = 0x140000 + KEXEC_ARCH_PPC64 = 0x150000 + KEXEC_ARCH_S390 = 0x160000 + KEXEC_ARCH_SH = 0x2a0000 + KEXEC_ARCH_X86_64 = 0x3e0000 + KEXEC_FILE_NO_INITRAMFS = 0x4 + KEXEC_FILE_ON_CRASH = 0x2 + KEXEC_FILE_UNLOAD = 0x1 + KEXEC_ON_CRASH = 0x1 + KEXEC_PRESERVE_CONTEXT = 0x2 + KEXEC_SEGMENT_MAX = 0x10 KEYCTL_ASSUME_AUTHORITY = 0x10 KEYCTL_CHOWN = 0x4 KEYCTL_CLEAR = 0x7 @@ -797,6 +917,11 @@ const ( KEYCTL_JOIN_SESSION_KEYRING = 0x1 KEYCTL_LINK = 0x8 KEYCTL_NEGATE = 0xd + KEYCTL_PKEY_DECRYPT = 0x1a + KEYCTL_PKEY_ENCRYPT = 0x19 + KEYCTL_PKEY_QUERY = 0x18 + KEYCTL_PKEY_SIGN = 0x1b + KEYCTL_PKEY_VERIFY = 0x1c KEYCTL_READ = 0xb KEYCTL_REJECT = 0x13 KEYCTL_RESTRICT_KEYRING = 0x1d @@ -806,6 +931,10 @@ const ( KEYCTL_SETPERM = 0x5 KEYCTL_SET_REQKEY_KEYRING = 0xe KEYCTL_SET_TIMEOUT = 0xf + KEYCTL_SUPPORTS_DECRYPT = 0x2 + KEYCTL_SUPPORTS_ENCRYPT = 0x1 + KEYCTL_SUPPORTS_SIGN = 0x4 + KEYCTL_SUPPORTS_VERIFY = 0x8 KEYCTL_UNLINK = 0x9 KEYCTL_UPDATE = 0x2 KEY_REQKEY_DEFL_DEFAULT = 0x0 @@ -847,6 +976,7 @@ const ( MADV_FREE = 0x8 MADV_HUGEPAGE = 0xe MADV_HWPOISON = 0x64 + MADV_KEEPONFORK = 0x13 MADV_MERGEABLE = 0xc MADV_NOHUGEPAGE = 0xf MADV_NORMAL = 0x0 @@ -855,12 +985,14 @@ const ( MADV_SEQUENTIAL = 0x2 MADV_UNMERGEABLE = 0xd MADV_WILLNEED = 0x3 + MADV_WIPEONFORK = 0x12 MAP_ANON = 0x20 MAP_ANONYMOUS = 0x20 MAP_DENYWRITE = 0x800 MAP_EXECUTABLE = 0x1000 MAP_FILE = 0x0 MAP_FIXED = 0x10 + MAP_FIXED_NOREPLACE = 0x100000 MAP_GROWSDOWN = 0x100 MAP_HUGETLB = 0x40000 MAP_HUGE_MASK = 0x3f @@ -871,14 +1003,41 @@ const ( MAP_POPULATE = 0x8000 MAP_PRIVATE = 0x2 MAP_SHARED = 0x1 + MAP_SHARED_VALIDATE = 0x3 MAP_STACK = 0x20000 + MAP_SYNC = 0x80000 MAP_TYPE = 0xf MCL_CURRENT = 0x1 MCL_FUTURE = 0x2 MCL_ONFAULT = 0x4 + MFD_ALLOW_SEALING = 0x2 + MFD_CLOEXEC = 0x1 + MFD_HUGETLB = 0x4 + MFD_HUGE_16GB = -0x78000000 + MFD_HUGE_16MB = 0x60000000 + MFD_HUGE_1GB = 0x78000000 + MFD_HUGE_1MB = 0x50000000 + MFD_HUGE_256MB = 0x70000000 + MFD_HUGE_2GB = 0x7c000000 + MFD_HUGE_2MB = 0x54000000 + MFD_HUGE_32MB = 0x64000000 + MFD_HUGE_512KB = 0x4c000000 + MFD_HUGE_512MB = 0x74000000 + MFD_HUGE_64KB = 0x40000000 + MFD_HUGE_8MB = 0x5c000000 + MFD_HUGE_MASK = 0x3f + MFD_HUGE_SHIFT = 0x1a + MINIX2_SUPER_MAGIC = 0x2468 + MINIX2_SUPER_MAGIC2 = 0x2478 + MINIX3_SUPER_MAGIC = 0x4d5a + MINIX_SUPER_MAGIC = 0x137f + MINIX_SUPER_MAGIC2 = 0x138f MNT_DETACH = 0x2 MNT_EXPIRE = 0x4 MNT_FORCE = 0x1 + MODULE_INIT_IGNORE_MODVERSIONS = 0x1 + MODULE_INIT_IGNORE_VERMAGIC = 0x2 + MSDOS_SUPER_MAGIC = 0x4d44 MSG_BATCH = 0x40000 MSG_CMSG_CLOEXEC = 0x40000000 MSG_CONFIRM = 0x800 @@ -900,6 +1059,7 @@ const ( MSG_TRYHARD = 0x4 MSG_WAITALL = 0x100 MSG_WAITFORONE = 0x10000 + MSG_ZEROCOPY = 0x4000000 MS_ACTIVE = 0x40000000 MS_ASYNC = 0x1 MS_BIND = 0x1000 @@ -937,7 +1097,9 @@ const ( MS_SYNCHRONOUS = 0x10 MS_UNBINDABLE = 0x20000 MS_VERBOSE = 0x8000 + MTD_INODE_FS_MAGIC = 0x11307854 NAME_MAX = 0xff + NCP_SUPER_MAGIC = 0x564c NETLINK_ADD_MEMBERSHIP = 0x1 NETLINK_AUDIT = 0x9 NETLINK_BROADCAST_ERROR = 0x4 @@ -951,6 +1113,7 @@ const ( NETLINK_FIB_LOOKUP = 0xa NETLINK_FIREWALL = 0x3 NETLINK_GENERIC = 0x10 + NETLINK_GET_STRICT_CHK = 0xc NETLINK_INET_DIAG = 0x4 NETLINK_IP6_FW = 0xd NETLINK_ISCSI = 0x8 @@ -972,6 +1135,39 @@ const ( NETLINK_UNUSED = 0x1 NETLINK_USERSOCK = 0x2 NETLINK_XFRM = 0x6 + NETNSA_MAX = 0x3 + NETNSA_NSID_NOT_ASSIGNED = -0x1 + NFNETLINK_V0 = 0x0 + NFNLGRP_ACCT_QUOTA = 0x8 + NFNLGRP_CONNTRACK_DESTROY = 0x3 + NFNLGRP_CONNTRACK_EXP_DESTROY = 0x6 + NFNLGRP_CONNTRACK_EXP_NEW = 0x4 + NFNLGRP_CONNTRACK_EXP_UPDATE = 0x5 + NFNLGRP_CONNTRACK_NEW = 0x1 + NFNLGRP_CONNTRACK_UPDATE = 0x2 + NFNLGRP_MAX = 0x9 + NFNLGRP_NFTABLES = 0x7 + NFNLGRP_NFTRACE = 0x9 + NFNLGRP_NONE = 0x0 + NFNL_BATCH_MAX = 0x1 + NFNL_MSG_BATCH_BEGIN = 0x10 + NFNL_MSG_BATCH_END = 0x11 + NFNL_NFA_NEST = 0x8000 + NFNL_SUBSYS_ACCT = 0x7 + NFNL_SUBSYS_COUNT = 0xc + NFNL_SUBSYS_CTHELPER = 0x9 + NFNL_SUBSYS_CTNETLINK = 0x1 + NFNL_SUBSYS_CTNETLINK_EXP = 0x2 + NFNL_SUBSYS_CTNETLINK_TIMEOUT = 0x8 + NFNL_SUBSYS_IPSET = 0x6 + NFNL_SUBSYS_NFTABLES = 0xa + NFNL_SUBSYS_NFT_COMPAT = 0xb + NFNL_SUBSYS_NONE = 0x0 + NFNL_SUBSYS_OSF = 0x5 + NFNL_SUBSYS_QUEUE = 0x3 + NFNL_SUBSYS_ULOG = 0x4 + NFS_SUPER_MAGIC = 0x6969 + NILFS_SUPER_MAGIC = 0x3434 NL0 = 0x0 NL1 = 0x100 NLA_ALIGNTO = 0x4 @@ -999,10 +1195,13 @@ const ( NLM_F_EXCL = 0x200 NLM_F_MATCH = 0x200 NLM_F_MULTI = 0x2 + NLM_F_NONREC = 0x100 NLM_F_REPLACE = 0x100 NLM_F_REQUEST = 0x1 NLM_F_ROOT = 0x100 NOFLSH = 0x80 + NSFS_MAGIC = 0x6e736673 + OCFS2_SUPER_MAGIC = 0x7461636f OCRNL = 0x8 OFDEL = 0x80 OFILL = 0x40 @@ -1010,7 +1209,9 @@ const ( ONLCR = 0x4 ONLRET = 0x20 ONOCR = 0x10 + OPENPROM_SUPER_MAGIC = 0x9fa1 OPOST = 0x1 + OVERLAYFS_SUPER_MAGIC = 0x794c7630 O_ACCMODE = 0x3 O_APPEND = 0x400 O_ASYNC = 0x2000 @@ -1056,6 +1257,7 @@ const ( PACKET_FASTROUTE = 0x6 PACKET_HDRLEN = 0xb PACKET_HOST = 0x0 + PACKET_IGNORE_OUTGOING = 0x17 PACKET_KERNEL = 0x7 PACKET_LOOPBACK = 0x5 PACKET_LOSS = 0xe @@ -1095,16 +1297,50 @@ const ( PERF_EVENT_IOC_DISABLE = 0x2401 PERF_EVENT_IOC_ENABLE = 0x2400 PERF_EVENT_IOC_ID = 0x80082407 + PERF_EVENT_IOC_MODIFY_ATTRIBUTES = 0x4008240b PERF_EVENT_IOC_PAUSE_OUTPUT = 0x40042409 PERF_EVENT_IOC_PERIOD = 0x40082404 + PERF_EVENT_IOC_QUERY_BPF = 0xc008240a PERF_EVENT_IOC_REFRESH = 0x2402 PERF_EVENT_IOC_RESET = 0x2403 PERF_EVENT_IOC_SET_BPF = 0x40042408 PERF_EVENT_IOC_SET_FILTER = 0x40082406 PERF_EVENT_IOC_SET_OUTPUT = 0x2405 + PIPEFS_MAGIC = 0x50495045 + PPPIOCATTACH = 0x4004743d + PPPIOCATTCHAN = 0x40047438 + PPPIOCCONNECT = 0x4004743a + PPPIOCDETACH = 0x4004743c + PPPIOCDISCONN = 0x7439 + PPPIOCGASYNCMAP = 0x80047458 + PPPIOCGCHAN = 0x80047437 + PPPIOCGDEBUG = 0x80047441 + PPPIOCGFLAGS = 0x8004745a + PPPIOCGIDLE = 0x8010743f + PPPIOCGL2TPSTATS = 0x80487436 + PPPIOCGMRU = 0x80047453 + PPPIOCGNPMODE = 0xc008744c + PPPIOCGRASYNCMAP = 0x80047455 + PPPIOCGUNIT = 0x80047456 + PPPIOCGXASYNCMAP = 0x80207450 + PPPIOCNEWUNIT = 0xc004743e + PPPIOCSACTIVE = 0x40107446 + PPPIOCSASYNCMAP = 0x40047457 + PPPIOCSCOMPRESS = 0x4010744d + PPPIOCSDEBUG = 0x40047440 + PPPIOCSFLAGS = 0x40047459 + PPPIOCSMAXCID = 0x40047451 + PPPIOCSMRRU = 0x4004743b + PPPIOCSMRU = 0x40047452 + PPPIOCSNPMODE = 0x4008744b + PPPIOCSPASS = 0x40107447 + PPPIOCSRASYNCMAP = 0x40047454 + PPPIOCSXASYNCMAP = 0x4020744f + PPPIOCXFERUNIT = 0x744e PRIO_PGRP = 0x1 PRIO_PROCESS = 0x0 PRIO_USER = 0x2 + PROC_SUPER_MAGIC = 0x9fa0 PROT_EXEC = 0x4 PROT_GROWSDOWN = 0x1000000 PROT_GROWSUP = 0x2000000 @@ -1147,6 +1383,7 @@ const ( PR_GET_PDEATHSIG = 0x2 PR_GET_SECCOMP = 0x15 PR_GET_SECUREBITS = 0x1b + PR_GET_SPECULATION_CTRL = 0x34 PR_GET_THP_DISABLE = 0x2a PR_GET_TID_ADDRESS = 0x28 PR_GET_TIMERSLACK = 0x1e @@ -1192,11 +1429,24 @@ const ( PR_SET_PTRACER_ANY = 0xffffffffffffffff PR_SET_SECCOMP = 0x16 PR_SET_SECUREBITS = 0x1c + PR_SET_SPECULATION_CTRL = 0x35 PR_SET_THP_DISABLE = 0x29 PR_SET_TIMERSLACK = 0x1d PR_SET_TIMING = 0xe PR_SET_TSC = 0x1a PR_SET_UNALIGN = 0x6 + PR_SPEC_DISABLE = 0x4 + PR_SPEC_ENABLE = 0x2 + PR_SPEC_FORCE_DISABLE = 0x8 + PR_SPEC_INDIRECT_BRANCH = 0x1 + PR_SPEC_NOT_AFFECTED = 0x0 + PR_SPEC_PRCTL = 0x1 + PR_SPEC_STORE_BYPASS = 0x0 + PR_SVE_GET_VL = 0x33 + PR_SVE_SET_VL = 0x32 + PR_SVE_SET_VL_ONEXEC = 0x40000 + PR_SVE_VL_INHERIT = 0x20000 + PR_SVE_VL_LEN_MASK = 0xffff PR_TASK_PERF_EVENTS_DISABLE = 0x1f PR_TASK_PERF_EVENTS_ENABLE = 0x20 PR_TIMING_STATISTICAL = 0x0 @@ -1205,6 +1455,7 @@ const ( PR_TSC_SIGSEGV = 0x2 PR_UNALIGN_NOPRINT = 0x1 PR_UNALIGN_SIGBUS = 0x2 + PSTOREFS_MAGIC = 0x6165676c PTRACE_ATTACH = 0x10 PTRACE_CONT = 0x7 PTRACE_DETACH = 0x11 @@ -1244,6 +1495,7 @@ const ( PTRACE_POKETEXT = 0x4 PTRACE_POKEUSR = 0x6 PTRACE_SECCOMP_GET_FILTER = 0x420c + PTRACE_SECCOMP_GET_METADATA = 0x420d PTRACE_SEIZE = 0x4206 PTRACE_SETOPTIONS = 0x4200 PTRACE_SETREGS = 0xd @@ -1253,6 +1505,14 @@ const ( PTRACE_SINGLESTEP = 0x9 PTRACE_SYSCALL = 0x18 PTRACE_TRACEME = 0x0 + QNX4_SUPER_MAGIC = 0x2f + QNX6_SUPER_MAGIC = 0x68191122 + RAMFS_MAGIC = 0x858458f6 + RDTGROUP_SUPER_MAGIC = 0x7655821 + REISERFS_SUPER_MAGIC = 0x52654973 + RENAME_EXCHANGE = 0x2 + RENAME_NOREPLACE = 0x1 + RENAME_WHITEOUT = 0x4 RLIMIT_AS = 0x9 RLIMIT_CORE = 0x4 RLIMIT_CPU = 0x0 @@ -1270,9 +1530,17 @@ const ( RLIMIT_SIGPENDING = 0xb RLIMIT_STACK = 0x3 RLIM_INFINITY = 0xffffffffffffffff + RNDADDENTROPY = 0x40085203 + RNDADDTOENTCNT = 0x40045201 + RNDCLEARPOOL = 0x5206 + RNDGETENTCNT = 0x80045200 + RNDGETPOOL = 0x80085202 + RNDRESEEDCRNG = 0x5207 + RNDZAPENTCNT = 0x5204 RTAX_ADVMSS = 0x8 RTAX_CC_ALGO = 0x10 RTAX_CWND = 0x7 + RTAX_FASTOPEN_NO_COOKIE = 0x11 RTAX_FEATURES = 0xc RTAX_FEATURE_ALLFRAG = 0x8 RTAX_FEATURE_ECN = 0x1 @@ -1283,7 +1551,7 @@ const ( RTAX_INITCWND = 0xb RTAX_INITRWND = 0xe RTAX_LOCK = 0x1 - RTAX_MAX = 0x10 + RTAX_MAX = 0x11 RTAX_MTU = 0x2 RTAX_QUICKACK = 0xf RTAX_REORDERING = 0x9 @@ -1294,13 +1562,40 @@ const ( RTAX_UNSPEC = 0x0 RTAX_WINDOW = 0x3 RTA_ALIGNTO = 0x4 - RTA_MAX = 0x1a + RTA_MAX = 0x1d RTCF_DIRECTSRC = 0x4000000 RTCF_DOREDIRECT = 0x1000000 RTCF_LOG = 0x2000000 RTCF_MASQ = 0x400000 RTCF_NAT = 0x800000 RTCF_VALVE = 0x200000 + RTC_AF = 0x20 + RTC_AIE_OFF = 0x7002 + RTC_AIE_ON = 0x7001 + RTC_ALM_READ = 0x80247008 + RTC_ALM_SET = 0x40247007 + RTC_EPOCH_READ = 0x8008700d + RTC_EPOCH_SET = 0x4008700e + RTC_IRQF = 0x80 + RTC_IRQP_READ = 0x8008700b + RTC_IRQP_SET = 0x4008700c + RTC_MAX_FREQ = 0x2000 + RTC_PF = 0x40 + RTC_PIE_OFF = 0x7006 + RTC_PIE_ON = 0x7005 + RTC_PLL_GET = 0x80207011 + RTC_PLL_SET = 0x40207012 + RTC_RD_TIME = 0x80247009 + RTC_SET_TIME = 0x4024700a + RTC_UF = 0x10 + RTC_UIE_OFF = 0x7004 + RTC_UIE_ON = 0x7003 + RTC_VL_CLR = 0x7014 + RTC_VL_READ = 0x80047013 + RTC_WIE_OFF = 0x7010 + RTC_WIE_ON = 0x700f + RTC_WKALM_RD = 0x80287010 + RTC_WKALM_SET = 0x4028700f RTF_ADDRCLASSMASK = 0xf8000000 RTF_ADDRCONF = 0x40000 RTF_ALLONLINK = 0x20000 @@ -1335,6 +1630,7 @@ const ( RTM_DELACTION = 0x31 RTM_DELADDR = 0x15 RTM_DELADDRLABEL = 0x49 + RTM_DELCHAIN = 0x65 RTM_DELLINK = 0x11 RTM_DELMDB = 0x55 RTM_DELNEIGH = 0x1d @@ -1355,6 +1651,7 @@ const ( RTM_GETADDR = 0x16 RTM_GETADDRLABEL = 0x4a RTM_GETANYCAST = 0x3e + RTM_GETCHAIN = 0x66 RTM_GETDCB = 0x4e RTM_GETLINK = 0x12 RTM_GETMDB = 0x56 @@ -1369,11 +1666,12 @@ const ( RTM_GETSTATS = 0x5e RTM_GETTCLASS = 0x2a RTM_GETTFILTER = 0x2e - RTM_MAX = 0x63 + RTM_MAX = 0x67 RTM_NEWACTION = 0x30 RTM_NEWADDR = 0x14 RTM_NEWADDRLABEL = 0x48 RTM_NEWCACHEREPORT = 0x60 + RTM_NEWCHAIN = 0x64 RTM_NEWLINK = 0x10 RTM_NEWMDB = 0x54 RTM_NEWNDUSEROPT = 0x44 @@ -1388,8 +1686,8 @@ const ( RTM_NEWSTATS = 0x5c RTM_NEWTCLASS = 0x28 RTM_NEWTFILTER = 0x2c - RTM_NR_FAMILIES = 0x15 - RTM_NR_MSGTYPES = 0x54 + RTM_NR_FAMILIES = 0x16 + RTM_NR_MSGTYPES = 0x58 RTM_SETDCB = 0x4f RTM_SETLINK = 0x13 RTM_SETNEIGHTBL = 0x43 @@ -1403,17 +1701,22 @@ const ( RTNH_F_UNRESOLVED = 0x20 RTN_MAX = 0xb RTPROT_BABEL = 0x2a + RTPROT_BGP = 0xba RTPROT_BIRD = 0xc RTPROT_BOOT = 0x3 RTPROT_DHCP = 0x10 RTPROT_DNROUTED = 0xd + RTPROT_EIGRP = 0xc0 RTPROT_GATED = 0x8 + RTPROT_ISIS = 0xbb RTPROT_KERNEL = 0x2 RTPROT_MROUTED = 0x11 RTPROT_MRT = 0xa RTPROT_NTK = 0xf + RTPROT_OSPF = 0xbc RTPROT_RA = 0x9 RTPROT_REDIRECT = 0x1 + RTPROT_RIP = 0xbd RTPROT_STATIC = 0x4 RTPROT_UNSPEC = 0x0 RTPROT_XORP = 0xe @@ -1433,10 +1736,16 @@ const ( SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SC_LOG_FLUSH = 0x100000 SECCOMP_MODE_DISABLED = 0x0 SECCOMP_MODE_FILTER = 0x2 SECCOMP_MODE_STRICT = 0x1 + SECURITYFS_MAGIC = 0x73636673 + SELINUX_MAGIC = 0xf97cff8c + SFD_CLOEXEC = 0x80000 + SFD_NONBLOCK = 0x800 SHUT_RD = 0x0 SHUT_RDWR = 0x2 SHUT_WR = 0x1 @@ -1487,6 +1796,9 @@ const ( SIOCGMIIPHY = 0x8947 SIOCGMIIREG = 0x8948 SIOCGPGRP = 0x8904 + SIOCGPPPCSTATS = 0x89f2 + SIOCGPPPSTATS = 0x89f0 + SIOCGPPPVER = 0x89f1 SIOCGRARP = 0x8961 SIOCGSKNS = 0x894c SIOCGSTAMP = 0x8906 @@ -1521,6 +1833,23 @@ const ( SIOCSPGRP = 0x8902 SIOCSRARP = 0x8962 SIOCWANDEV = 0x894a + SMACK_MAGIC = 0x43415d53 + SMART_AUTOSAVE = 0xd2 + SMART_AUTO_OFFLINE = 0xdb + SMART_DISABLE = 0xd9 + SMART_ENABLE = 0xd8 + SMART_HCYL_PASS = 0xc2 + SMART_IMMEDIATE_OFFLINE = 0xd4 + SMART_LCYL_PASS = 0x4f + SMART_READ_LOG_SECTOR = 0xd5 + SMART_READ_THRESHOLDS = 0xd1 + SMART_READ_VALUES = 0xd0 + SMART_SAVE = 0xd3 + SMART_STATUS = 0xda + SMART_WRITE_LOG_SECTOR = 0xd6 + SMART_WRITE_THRESHOLDS = 0xd7 + SMB_SUPER_MAGIC = 0x517b + SOCKFS_MAGIC = 0x534f434b SOCK_CLOEXEC = 0x80000 SOCK_DCCP = 0x6 SOCK_DGRAM = 0x2 @@ -1557,7 +1886,9 @@ const ( SOL_SOCKET = 0x1 SOL_TCP = 0x6 SOL_TIPC = 0x10f + SOL_TLS = 0x11a SOL_X25 = 0x106 + SOL_XDP = 0x11b SOMAXCONN = 0x80 SO_ACCEPTCONN = 0x1e SO_ATTACH_BPF = 0x32 @@ -1576,6 +1907,17 @@ const ( SO_DETACH_FILTER = 0x1b SO_DOMAIN = 0x27 SO_DONTROUTE = 0x5 + SO_EE_CODE_TXTIME_INVALID_PARAM = 0x1 + SO_EE_CODE_TXTIME_MISSED = 0x2 + SO_EE_CODE_ZEROCOPY_COPIED = 0x1 + SO_EE_ORIGIN_ICMP = 0x2 + SO_EE_ORIGIN_ICMP6 = 0x3 + SO_EE_ORIGIN_LOCAL = 0x1 + SO_EE_ORIGIN_NONE = 0x0 + SO_EE_ORIGIN_TIMESTAMPING = 0x4 + SO_EE_ORIGIN_TXSTATUS = 0x4 + SO_EE_ORIGIN_TXTIME = 0x6 + SO_EE_ORIGIN_ZEROCOPY = 0x5 SO_ERROR = 0x4 SO_GET_FILTER = 0x1a SO_INCOMING_CPU = 0x31 @@ -1616,6 +1958,7 @@ const ( SO_TIMESTAMP = 0x1d SO_TIMESTAMPING = 0x25 SO_TIMESTAMPNS = 0x23 + SO_TXTIME = 0x3d SO_TYPE = 0x3 SO_VM_SOCKETS_BUFFER_MAX_SIZE = 0x2 SO_VM_SOCKETS_BUFFER_MIN_SIZE = 0x1 @@ -1625,10 +1968,39 @@ const ( SO_VM_SOCKETS_PEER_HOST_VM_ID = 0x3 SO_VM_SOCKETS_TRUSTED = 0x5 SO_WIFI_STATUS = 0x29 + SO_ZEROCOPY = 0x3c SPLICE_F_GIFT = 0x8 SPLICE_F_MORE = 0x4 SPLICE_F_MOVE = 0x1 SPLICE_F_NONBLOCK = 0x2 + SQUASHFS_MAGIC = 0x73717368 + STACK_END_MAGIC = 0x57ac6e9d + STATX_ALL = 0xfff + STATX_ATIME = 0x20 + STATX_ATTR_APPEND = 0x20 + STATX_ATTR_AUTOMOUNT = 0x1000 + STATX_ATTR_COMPRESSED = 0x4 + STATX_ATTR_ENCRYPTED = 0x800 + STATX_ATTR_IMMUTABLE = 0x10 + STATX_ATTR_NODUMP = 0x40 + STATX_BASIC_STATS = 0x7ff + STATX_BLOCKS = 0x400 + STATX_BTIME = 0x800 + STATX_CTIME = 0x80 + STATX_GID = 0x10 + STATX_INO = 0x100 + STATX_MODE = 0x2 + STATX_MTIME = 0x40 + STATX_NLINK = 0x4 + STATX_SIZE = 0x200 + STATX_TYPE = 0x1 + STATX_UID = 0x8 + STATX__RESERVED = 0x80000000 + SVE_MAGIC = 0x53564501 + SYNC_FILE_RANGE_WAIT_AFTER = 0x4 + SYNC_FILE_RANGE_WAIT_BEFORE = 0x1 + SYNC_FILE_RANGE_WRITE = 0x2 + SYSFS_MAGIC = 0x62656572 S_BLKSIZE = 0x200 S_IEXEC = 0x40 S_IFBLK = 0x6000 @@ -1666,7 +2038,7 @@ const ( TASKSTATS_GENL_NAME = "TASKSTATS" TASKSTATS_GENL_VERSION = 0x1 TASKSTATS_TYPE_MAX = 0x6 - TASKSTATS_VERSION = 0x8 + TASKSTATS_VERSION = 0x9 TCFLSH = 0x540b TCGETA = 0x5405 TCGETS = 0x5401 @@ -1680,6 +2052,7 @@ const ( TCOOFF = 0x0 TCOON = 0x1 TCP_CC_INFO = 0x1a + TCP_CM_INQ = 0x24 TCP_CONGESTION = 0xd TCP_COOKIE_IN_ALWAYS = 0x1 TCP_COOKIE_MAX = 0x10 @@ -1691,7 +2064,10 @@ const ( TCP_DEFER_ACCEPT = 0x9 TCP_FASTOPEN = 0x17 TCP_FASTOPEN_CONNECT = 0x1e + TCP_FASTOPEN_KEY = 0x21 + TCP_FASTOPEN_NO_COOKIE = 0x22 TCP_INFO = 0xb + TCP_INQ = 0x24 TCP_KEEPCNT = 0x6 TCP_KEEPIDLE = 0x4 TCP_KEEPINTVL = 0x5 @@ -1700,6 +2076,8 @@ const ( TCP_MAXWIN = 0xffff TCP_MAX_WINSHIFT = 0xe TCP_MD5SIG = 0xe + TCP_MD5SIG_EXT = 0x20 + TCP_MD5SIG_FLAG_PREFIX = 0x1 TCP_MD5SIG_MAXKEYLEN = 0x50 TCP_MSS = 0x200 TCP_MSS_DEFAULT = 0x218 @@ -1709,6 +2087,9 @@ const ( TCP_QUEUE_SEQ = 0x15 TCP_QUICKACK = 0xc TCP_REPAIR = 0x13 + TCP_REPAIR_OFF = 0x0 + TCP_REPAIR_OFF_NO_WP = -0x1 + TCP_REPAIR_ON = 0x1 TCP_REPAIR_OPTIONS = 0x16 TCP_REPAIR_QUEUE = 0x14 TCP_REPAIR_WINDOW = 0x1d @@ -1720,8 +2101,10 @@ const ( TCP_THIN_DUPACK = 0x11 TCP_THIN_LINEAR_TIMEOUTS = 0x10 TCP_TIMESTAMP = 0x18 + TCP_ULP = 0x1f TCP_USER_TIMEOUT = 0x12 TCP_WINDOW_CLAMP = 0xa + TCP_ZEROCOPY_RECEIVE = 0x23 TCSAFLUSH = 0x2 TCSBRK = 0x5409 TCSBRKP = 0x5425 @@ -1738,6 +2121,7 @@ const ( TCSETXF = 0x5434 TCSETXW = 0x5435 TCXONC = 0x540a + TIMER_ABSTIME = 0x1 TIOCCBRK = 0x5428 TIOCCONS = 0x541d TIOCEXCL = 0x540c @@ -1745,6 +2129,7 @@ const ( TIOCGETD = 0x5424 TIOCGEXCL = 0x80045440 TIOCGICOUNT = 0x545d + TIOCGISO7816 = 0x80285442 TIOCGLCKTRMIOS = 0x5456 TIOCGPGRP = 0x540f TIOCGPKT = 0x80045438 @@ -1798,6 +2183,7 @@ const ( TIOCSER_TEMT = 0x1 TIOCSETD = 0x5423 TIOCSIG = 0x40045436 + TIOCSISO7816 = 0xc0285443 TIOCSLCKTRMIOS = 0x5457 TIOCSPGRP = 0x5410 TIOCSPTLCK = 0x40045431 @@ -1807,7 +2193,27 @@ const ( TIOCSTI = 0x5412 TIOCSWINSZ = 0x5414 TIOCVHANGUP = 0x5437 + TMPFS_MAGIC = 0x1021994 TOSTOP = 0x100 + TPACKET_ALIGNMENT = 0x10 + TPACKET_HDRLEN = 0x34 + TP_STATUS_AVAILABLE = 0x0 + TP_STATUS_BLK_TMO = 0x20 + TP_STATUS_COPY = 0x2 + TP_STATUS_CSUMNOTREADY = 0x8 + TP_STATUS_CSUM_VALID = 0x80 + TP_STATUS_KERNEL = 0x0 + TP_STATUS_LOSING = 0x4 + TP_STATUS_SENDING = 0x2 + TP_STATUS_SEND_REQUEST = 0x1 + TP_STATUS_TS_RAW_HARDWARE = -0x80000000 + TP_STATUS_TS_SOFTWARE = 0x20000000 + TP_STATUS_TS_SYS_HARDWARE = 0x40000000 + TP_STATUS_USER = 0x1 + TP_STATUS_VLAN_TPID_VALID = 0x40 + TP_STATUS_VLAN_VALID = 0x10 + TP_STATUS_WRONG_FORMAT = 0x4 + TRACEFS_MAGIC = 0x74726163 TS_COMM_LEN = 0x20 TUNATTACHFILTER = 0x401054d5 TUNDETACHFILTER = 0x401054d6 @@ -1819,6 +2225,7 @@ const ( TUNGETVNETHDRSZ = 0x800454d7 TUNGETVNETLE = 0x800454dd TUNSETDEBUG = 0x400454c9 + TUNSETFILTEREBPF = 0x800454e1 TUNSETGROUP = 0x400454ce TUNSETIFF = 0x400454ca TUNSETIFINDEX = 0x400454da @@ -1829,13 +2236,32 @@ const ( TUNSETPERSIST = 0x400454cb TUNSETQUEUE = 0x400454d9 TUNSETSNDBUF = 0x400454d4 + TUNSETSTEERINGEBPF = 0x800454e0 TUNSETTXFILTER = 0x400454d1 TUNSETVNETBE = 0x400454de TUNSETVNETHDRSZ = 0x400454d8 TUNSETVNETLE = 0x400454dc + UBI_IOCATT = 0x40186f40 + UBI_IOCDET = 0x40046f41 + UBI_IOCEBCH = 0x40044f02 + UBI_IOCEBER = 0x40044f01 + UBI_IOCEBISMAP = 0x80044f05 + UBI_IOCEBMAP = 0x40084f03 + UBI_IOCEBUNMAP = 0x40044f04 + UBI_IOCMKVOL = 0x40986f00 + UBI_IOCRMVOL = 0x40046f01 + UBI_IOCRNVOL = 0x51106f03 + UBI_IOCRSVOL = 0x400c6f02 + UBI_IOCSETVOLPROP = 0x40104f06 + UBI_IOCVOLCRBLK = 0x40804f07 + UBI_IOCVOLRMBLK = 0x4f08 + UBI_IOCVOLUP = 0x40084f00 + UDF_SUPER_MAGIC = 0x15013346 UMOUNT_NOFOLLOW = 0x8 + USBDEVICE_SUPER_MAGIC = 0x9fa2 UTIME_NOW = 0x3fffffff UTIME_OMIT = 0x3ffffffe + V9FS_MAGIC = 0x1021997 VDISCARD = 0xd VEOF = 0x4 VEOL = 0xb @@ -1877,6 +2303,86 @@ const ( WDIOC_SETPRETIMEOUT = 0xc0045708 WDIOC_SETTIMEOUT = 0xc0045706 WEXITED = 0x4 + WIN_ACKMEDIACHANGE = 0xdb + WIN_CHECKPOWERMODE1 = 0xe5 + WIN_CHECKPOWERMODE2 = 0x98 + WIN_DEVICE_RESET = 0x8 + WIN_DIAGNOSE = 0x90 + WIN_DOORLOCK = 0xde + WIN_DOORUNLOCK = 0xdf + WIN_DOWNLOAD_MICROCODE = 0x92 + WIN_FLUSH_CACHE = 0xe7 + WIN_FLUSH_CACHE_EXT = 0xea + WIN_FORMAT = 0x50 + WIN_GETMEDIASTATUS = 0xda + WIN_IDENTIFY = 0xec + WIN_IDENTIFY_DMA = 0xee + WIN_IDLEIMMEDIATE = 0xe1 + WIN_INIT = 0x60 + WIN_MEDIAEJECT = 0xed + WIN_MULTREAD = 0xc4 + WIN_MULTREAD_EXT = 0x29 + WIN_MULTWRITE = 0xc5 + WIN_MULTWRITE_EXT = 0x39 + WIN_NOP = 0x0 + WIN_PACKETCMD = 0xa0 + WIN_PIDENTIFY = 0xa1 + WIN_POSTBOOT = 0xdc + WIN_PREBOOT = 0xdd + WIN_QUEUED_SERVICE = 0xa2 + WIN_READ = 0x20 + WIN_READDMA = 0xc8 + WIN_READDMA_EXT = 0x25 + WIN_READDMA_ONCE = 0xc9 + WIN_READDMA_QUEUED = 0xc7 + WIN_READDMA_QUEUED_EXT = 0x26 + WIN_READ_BUFFER = 0xe4 + WIN_READ_EXT = 0x24 + WIN_READ_LONG = 0x22 + WIN_READ_LONG_ONCE = 0x23 + WIN_READ_NATIVE_MAX = 0xf8 + WIN_READ_NATIVE_MAX_EXT = 0x27 + WIN_READ_ONCE = 0x21 + WIN_RECAL = 0x10 + WIN_RESTORE = 0x10 + WIN_SECURITY_DISABLE = 0xf6 + WIN_SECURITY_ERASE_PREPARE = 0xf3 + WIN_SECURITY_ERASE_UNIT = 0xf4 + WIN_SECURITY_FREEZE_LOCK = 0xf5 + WIN_SECURITY_SET_PASS = 0xf1 + WIN_SECURITY_UNLOCK = 0xf2 + WIN_SEEK = 0x70 + WIN_SETFEATURES = 0xef + WIN_SETIDLE1 = 0xe3 + WIN_SETIDLE2 = 0x97 + WIN_SETMULT = 0xc6 + WIN_SET_MAX = 0xf9 + WIN_SET_MAX_EXT = 0x37 + WIN_SLEEPNOW1 = 0xe6 + WIN_SLEEPNOW2 = 0x99 + WIN_SMART = 0xb0 + WIN_SPECIFY = 0x91 + WIN_SRST = 0x8 + WIN_STANDBY = 0xe2 + WIN_STANDBY2 = 0x96 + WIN_STANDBYNOW1 = 0xe0 + WIN_STANDBYNOW2 = 0x94 + WIN_VERIFY = 0x40 + WIN_VERIFY_EXT = 0x42 + WIN_VERIFY_ONCE = 0x41 + WIN_WRITE = 0x30 + WIN_WRITEDMA = 0xca + WIN_WRITEDMA_EXT = 0x35 + WIN_WRITEDMA_ONCE = 0xcb + WIN_WRITEDMA_QUEUED = 0xcc + WIN_WRITEDMA_QUEUED_EXT = 0x36 + WIN_WRITE_BUFFER = 0xe8 + WIN_WRITE_EXT = 0x34 + WIN_WRITE_LONG = 0x32 + WIN_WRITE_LONG_ONCE = 0x33 + WIN_WRITE_ONCE = 0x31 + WIN_WRITE_SAME = 0xe9 + WIN_WRITE_VERIFY = 0x3c WNOHANG = 0x1 WNOTHREAD = 0x20000000 WNOWAIT = 0x1000000 @@ -1886,7 +2392,30 @@ const ( XATTR_CREATE = 0x1 XATTR_REPLACE = 0x2 XCASE = 0x4 + XDP_COPY = 0x2 + XDP_FLAGS_DRV_MODE = 0x4 + XDP_FLAGS_HW_MODE = 0x8 + XDP_FLAGS_MASK = 0xf + XDP_FLAGS_MODES = 0xe + XDP_FLAGS_SKB_MODE = 0x2 + XDP_FLAGS_UPDATE_IF_NOEXIST = 0x1 + XDP_MMAP_OFFSETS = 0x1 + XDP_PGOFF_RX_RING = 0x0 + XDP_PGOFF_TX_RING = 0x80000000 + XDP_RX_RING = 0x2 + XDP_SHARED_UMEM = 0x1 + XDP_STATISTICS = 0x7 + XDP_TX_RING = 0x3 + XDP_UMEM_COMPLETION_RING = 0x6 + XDP_UMEM_FILL_RING = 0x5 + XDP_UMEM_PGOFF_COMPLETION_RING = 0x180000000 + XDP_UMEM_PGOFF_FILL_RING = 0x100000000 + XDP_UMEM_REG = 0x4 + XDP_ZEROCOPY = 0x4 + XENFS_SUPER_MAGIC = 0xabba1974 + XFS_SUPER_MAGIC = 0x58465342 XTABS = 0x1800 + ZSMALLOC_MAGIC = 0x58295829 ) // Errors @@ -2066,171 +2595,179 @@ const ( ) // Error table -var errors = [...]string{ - 1: "operation not permitted", - 2: "no such file or directory", - 3: "no such process", - 4: "interrupted system call", - 5: "input/output error", - 6: "no such device or address", - 7: "argument list too long", - 8: "exec format error", - 9: "bad file descriptor", - 10: "no child processes", - 11: "resource temporarily unavailable", - 12: "cannot allocate memory", - 13: "permission denied", - 14: "bad address", - 15: "block device required", - 16: "device or resource busy", - 17: "file exists", - 18: "invalid cross-device link", - 19: "no such device", - 20: "not a directory", - 21: "is a directory", - 22: "invalid argument", - 23: "too many open files in system", - 24: "too many open files", - 25: "inappropriate ioctl for device", - 26: "text file busy", - 27: "file too large", - 28: "no space left on device", - 29: "illegal seek", - 30: "read-only file system", - 31: "too many links", - 32: "broken pipe", - 33: "numerical argument out of domain", - 34: "numerical result out of range", - 35: "resource deadlock avoided", - 36: "file name too long", - 37: "no locks available", - 38: "function not implemented", - 39: "directory not empty", - 40: "too many levels of symbolic links", - 42: "no message of desired type", - 43: "identifier removed", - 44: "channel number out of range", - 45: "level 2 not synchronized", - 46: "level 3 halted", - 47: "level 3 reset", - 48: "link number out of range", - 49: "protocol driver not attached", - 50: "no CSI structure available", - 51: "level 2 halted", - 52: "invalid exchange", - 53: "invalid request descriptor", - 54: "exchange full", - 55: "no anode", - 56: "invalid request code", - 57: "invalid slot", - 59: "bad font file format", - 60: "device not a stream", - 61: "no data available", - 62: "timer expired", - 63: "out of streams resources", - 64: "machine is not on the network", - 65: "package not installed", - 66: "object is remote", - 67: "link has been severed", - 68: "advertise error", - 69: "srmount error", - 70: "communication error on send", - 71: "protocol error", - 72: "multihop attempted", - 73: "RFS specific error", - 74: "bad message", - 75: "value too large for defined data type", - 76: "name not unique on network", - 77: "file descriptor in bad state", - 78: "remote address changed", - 79: "can not access a needed shared library", - 80: "accessing a corrupted shared library", - 81: ".lib section in a.out corrupted", - 82: "attempting to link in too many shared libraries", - 83: "cannot exec a shared library directly", - 84: "invalid or incomplete multibyte or wide character", - 85: "interrupted system call should be restarted", - 86: "streams pipe error", - 87: "too many users", - 88: "socket operation on non-socket", - 89: "destination address required", - 90: "message too long", - 91: "protocol wrong type for socket", - 92: "protocol not available", - 93: "protocol not supported", - 94: "socket type not supported", - 95: "operation not supported", - 96: "protocol family not supported", - 97: "address family not supported by protocol", - 98: "address already in use", - 99: "cannot assign requested address", - 100: "network is down", - 101: "network is unreachable", - 102: "network dropped connection on reset", - 103: "software caused connection abort", - 104: "connection reset by peer", - 105: "no buffer space available", - 106: "transport endpoint is already connected", - 107: "transport endpoint is not connected", - 108: "cannot send after transport endpoint shutdown", - 109: "too many references: cannot splice", - 110: "connection timed out", - 111: "connection refused", - 112: "host is down", - 113: "no route to host", - 114: "operation already in progress", - 115: "operation now in progress", - 116: "stale file handle", - 117: "structure needs cleaning", - 118: "not a XENIX named type file", - 119: "no XENIX semaphores available", - 120: "is a named type file", - 121: "remote I/O error", - 122: "disk quota exceeded", - 123: "no medium found", - 124: "wrong medium type", - 125: "operation canceled", - 126: "required key not available", - 127: "key has expired", - 128: "key has been revoked", - 129: "key was rejected by service", - 130: "owner died", - 131: "state not recoverable", - 132: "operation not possible due to RF-kill", - 133: "memory page has hardware error", +var errorList = [...]struct { + num syscall.Errno + name string + desc string +}{ + {1, "EPERM", "operation not permitted"}, + {2, "ENOENT", "no such file or directory"}, + {3, "ESRCH", "no such process"}, + {4, "EINTR", "interrupted system call"}, + {5, "EIO", "input/output error"}, + {6, "ENXIO", "no such device or address"}, + {7, "E2BIG", "argument list too long"}, + {8, "ENOEXEC", "exec format error"}, + {9, "EBADF", "bad file descriptor"}, + {10, "ECHILD", "no child processes"}, + {11, "EAGAIN", "resource temporarily unavailable"}, + {12, "ENOMEM", "cannot allocate memory"}, + {13, "EACCES", "permission denied"}, + {14, "EFAULT", "bad address"}, + {15, "ENOTBLK", "block device required"}, + {16, "EBUSY", "device or resource busy"}, + {17, "EEXIST", "file exists"}, + {18, "EXDEV", "invalid cross-device link"}, + {19, "ENODEV", "no such device"}, + {20, "ENOTDIR", "not a directory"}, + {21, "EISDIR", "is a directory"}, + {22, "EINVAL", "invalid argument"}, + {23, "ENFILE", "too many open files in system"}, + {24, "EMFILE", "too many open files"}, + {25, "ENOTTY", "inappropriate ioctl for device"}, + {26, "ETXTBSY", "text file busy"}, + {27, "EFBIG", "file too large"}, + {28, "ENOSPC", "no space left on device"}, + {29, "ESPIPE", "illegal seek"}, + {30, "EROFS", "read-only file system"}, + {31, "EMLINK", "too many links"}, + {32, "EPIPE", "broken pipe"}, + {33, "EDOM", "numerical argument out of domain"}, + {34, "ERANGE", "numerical result out of range"}, + {35, "EDEADLK", "resource deadlock avoided"}, + {36, "ENAMETOOLONG", "file name too long"}, + {37, "ENOLCK", "no locks available"}, + {38, "ENOSYS", "function not implemented"}, + {39, "ENOTEMPTY", "directory not empty"}, + {40, "ELOOP", "too many levels of symbolic links"}, + {42, "ENOMSG", "no message of desired type"}, + {43, "EIDRM", "identifier removed"}, + {44, "ECHRNG", "channel number out of range"}, + {45, "EL2NSYNC", "level 2 not synchronized"}, + {46, "EL3HLT", "level 3 halted"}, + {47, "EL3RST", "level 3 reset"}, + {48, "ELNRNG", "link number out of range"}, + {49, "EUNATCH", "protocol driver not attached"}, + {50, "ENOCSI", "no CSI structure available"}, + {51, "EL2HLT", "level 2 halted"}, + {52, "EBADE", "invalid exchange"}, + {53, "EBADR", "invalid request descriptor"}, + {54, "EXFULL", "exchange full"}, + {55, "ENOANO", "no anode"}, + {56, "EBADRQC", "invalid request code"}, + {57, "EBADSLT", "invalid slot"}, + {59, "EBFONT", "bad font file format"}, + {60, "ENOSTR", "device not a stream"}, + {61, "ENODATA", "no data available"}, + {62, "ETIME", "timer expired"}, + {63, "ENOSR", "out of streams resources"}, + {64, "ENONET", "machine is not on the network"}, + {65, "ENOPKG", "package not installed"}, + {66, "EREMOTE", "object is remote"}, + {67, "ENOLINK", "link has been severed"}, + {68, "EADV", "advertise error"}, + {69, "ESRMNT", "srmount error"}, + {70, "ECOMM", "communication error on send"}, + {71, "EPROTO", "protocol error"}, + {72, "EMULTIHOP", "multihop attempted"}, + {73, "EDOTDOT", "RFS specific error"}, + {74, "EBADMSG", "bad message"}, + {75, "EOVERFLOW", "value too large for defined data type"}, + {76, "ENOTUNIQ", "name not unique on network"}, + {77, "EBADFD", "file descriptor in bad state"}, + {78, "EREMCHG", "remote address changed"}, + {79, "ELIBACC", "can not access a needed shared library"}, + {80, "ELIBBAD", "accessing a corrupted shared library"}, + {81, "ELIBSCN", ".lib section in a.out corrupted"}, + {82, "ELIBMAX", "attempting to link in too many shared libraries"}, + {83, "ELIBEXEC", "cannot exec a shared library directly"}, + {84, "EILSEQ", "invalid or incomplete multibyte or wide character"}, + {85, "ERESTART", "interrupted system call should be restarted"}, + {86, "ESTRPIPE", "streams pipe error"}, + {87, "EUSERS", "too many users"}, + {88, "ENOTSOCK", "socket operation on non-socket"}, + {89, "EDESTADDRREQ", "destination address required"}, + {90, "EMSGSIZE", "message too long"}, + {91, "EPROTOTYPE", "protocol wrong type for socket"}, + {92, "ENOPROTOOPT", "protocol not available"}, + {93, "EPROTONOSUPPORT", "protocol not supported"}, + {94, "ESOCKTNOSUPPORT", "socket type not supported"}, + {95, "ENOTSUP", "operation not supported"}, + {96, "EPFNOSUPPORT", "protocol family not supported"}, + {97, "EAFNOSUPPORT", "address family not supported by protocol"}, + {98, "EADDRINUSE", "address already in use"}, + {99, "EADDRNOTAVAIL", "cannot assign requested address"}, + {100, "ENETDOWN", "network is down"}, + {101, "ENETUNREACH", "network is unreachable"}, + {102, "ENETRESET", "network dropped connection on reset"}, + {103, "ECONNABORTED", "software caused connection abort"}, + {104, "ECONNRESET", "connection reset by peer"}, + {105, "ENOBUFS", "no buffer space available"}, + {106, "EISCONN", "transport endpoint is already connected"}, + {107, "ENOTCONN", "transport endpoint is not connected"}, + {108, "ESHUTDOWN", "cannot send after transport endpoint shutdown"}, + {109, "ETOOMANYREFS", "too many references: cannot splice"}, + {110, "ETIMEDOUT", "connection timed out"}, + {111, "ECONNREFUSED", "connection refused"}, + {112, "EHOSTDOWN", "host is down"}, + {113, "EHOSTUNREACH", "no route to host"}, + {114, "EALREADY", "operation already in progress"}, + {115, "EINPROGRESS", "operation now in progress"}, + {116, "ESTALE", "stale file handle"}, + {117, "EUCLEAN", "structure needs cleaning"}, + {118, "ENOTNAM", "not a XENIX named type file"}, + {119, "ENAVAIL", "no XENIX semaphores available"}, + {120, "EISNAM", "is a named type file"}, + {121, "EREMOTEIO", "remote I/O error"}, + {122, "EDQUOT", "disk quota exceeded"}, + {123, "ENOMEDIUM", "no medium found"}, + {124, "EMEDIUMTYPE", "wrong medium type"}, + {125, "ECANCELED", "operation canceled"}, + {126, "ENOKEY", "required key not available"}, + {127, "EKEYEXPIRED", "key has expired"}, + {128, "EKEYREVOKED", "key has been revoked"}, + {129, "EKEYREJECTED", "key was rejected by service"}, + {130, "EOWNERDEAD", "owner died"}, + {131, "ENOTRECOVERABLE", "state not recoverable"}, + {132, "ERFKILL", "operation not possible due to RF-kill"}, + {133, "EHWPOISON", "memory page has hardware error"}, } // Signal table -var signals = [...]string{ - 1: "hangup", - 2: "interrupt", - 3: "quit", - 4: "illegal instruction", - 5: "trace/breakpoint trap", - 6: "aborted", - 7: "bus error", - 8: "floating point exception", - 9: "killed", - 10: "user defined signal 1", - 11: "segmentation fault", - 12: "user defined signal 2", - 13: "broken pipe", - 14: "alarm clock", - 15: "terminated", - 16: "stack fault", - 17: "child exited", - 18: "continued", - 19: "stopped (signal)", - 20: "stopped", - 21: "stopped (tty input)", - 22: "stopped (tty output)", - 23: "urgent I/O condition", - 24: "CPU time limit exceeded", - 25: "file size limit exceeded", - 26: "virtual timer expired", - 27: "profiling timer expired", - 28: "window changed", - 29: "I/O possible", - 30: "power failure", - 31: "bad system call", +var signalList = [...]struct { + num syscall.Signal + name string + desc string +}{ + {1, "SIGHUP", "hangup"}, + {2, "SIGINT", "interrupt"}, + {3, "SIGQUIT", "quit"}, + {4, "SIGILL", "illegal instruction"}, + {5, "SIGTRAP", "trace/breakpoint trap"}, + {6, "SIGABRT", "aborted"}, + {7, "SIGBUS", "bus error"}, + {8, "SIGFPE", "floating point exception"}, + {9, "SIGKILL", "killed"}, + {10, "SIGUSR1", "user defined signal 1"}, + {11, "SIGSEGV", "segmentation fault"}, + {12, "SIGUSR2", "user defined signal 2"}, + {13, "SIGPIPE", "broken pipe"}, + {14, "SIGALRM", "alarm clock"}, + {15, "SIGTERM", "terminated"}, + {16, "SIGSTKFLT", "stack fault"}, + {17, "SIGCHLD", "child exited"}, + {18, "SIGCONT", "continued"}, + {19, "SIGSTOP", "stopped (signal)"}, + {20, "SIGTSTP", "stopped"}, + {21, "SIGTTIN", "stopped (tty input)"}, + {22, "SIGTTOU", "stopped (tty output)"}, + {23, "SIGURG", "urgent I/O condition"}, + {24, "SIGXCPU", "CPU time limit exceeded"}, + {25, "SIGXFSZ", "file size limit exceeded"}, + {26, "SIGVTALRM", "virtual timer expired"}, + {27, "SIGPROF", "profiling timer expired"}, + {28, "SIGWINCH", "window changed"}, + {29, "SIGIO", "I/O possible"}, + {30, "SIGPWR", "power failure"}, + {31, "SIGSYS", "bad system call"}, } diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go index d131a4cc51..380913c4fc 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go @@ -3,7 +3,7 @@ // +build mips,linux -// Created by cgo -godefs - DO NOT EDIT +// Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go package unix @@ -11,6 +11,11 @@ package unix import "syscall" const ( + AAFS_MAGIC = 0x5a3c69f0 + ADFS_SUPER_MAGIC = 0xadf5 + AFFS_SUPER_MAGIC = 0xadff + AFS_FS_MAGIC = 0x6b414653 + AFS_SUPER_MAGIC = 0x5346414f AF_ALG = 0x26 AF_APPLETALK = 0x5 AF_ASH = 0x12 @@ -36,7 +41,7 @@ const ( AF_KEY = 0xf AF_LLC = 0x1a AF_LOCAL = 0x1 - AF_MAX = 0x2c + AF_MAX = 0x2d AF_MPLS = 0x1c AF_NETBEUI = 0xd AF_NETLINK = 0x10 @@ -59,6 +64,7 @@ const ( AF_VSOCK = 0x28 AF_WANPIPE = 0x19 AF_X25 = 0x9 + AF_XDP = 0x2c ALG_OP_DECRYPT = 0x0 ALG_OP_ENCRYPT = 0x1 ALG_SET_AEAD_ASSOCLEN = 0x4 @@ -66,6 +72,7 @@ const ( ALG_SET_IV = 0x2 ALG_SET_KEY = 0x1 ALG_SET_OP = 0x3 + ANON_INODE_FS_MAGIC = 0x9041934 ARPHRD_6LOWPAN = 0x339 ARPHRD_ADAPT = 0x108 ARPHRD_APPLETLK = 0x8 @@ -121,6 +128,7 @@ const ( ARPHRD_PPP = 0x200 ARPHRD_PRONET = 0x4 ARPHRD_RAWHDLC = 0x206 + ARPHRD_RAWIP = 0x207 ARPHRD_ROSE = 0x10e ARPHRD_RSRVD = 0x104 ARPHRD_SIT = 0x308 @@ -132,6 +140,7 @@ const ( ARPHRD_VOID = 0xffff ARPHRD_VSOCKMON = 0x33a ARPHRD_X25 = 0x10f + AUTOFS_SUPER_MAGIC = 0x187 B0 = 0x0 B1000000 = 0x1008 B110 = 0x3 @@ -163,6 +172,9 @@ const ( B75 = 0x2 B921600 = 0x1007 B9600 = 0xd + BALLOON_KVM_MAGIC = 0x13661366 + BDEVFS_MAGIC = 0x62646576 + BINFMTFS_MAGIC = 0x42494e4d BLKBSZGET = 0x40041270 BLKBSZSET = 0x80041271 BLKFLSBUF = 0x20001261 @@ -187,6 +199,7 @@ const ( BPF_AND = 0x50 BPF_B = 0x10 BPF_DIV = 0x30 + BPF_FS_MAGIC = 0xcafe4a11 BPF_H = 0x8 BPF_IMM = 0x0 BPF_IND = 0x40 @@ -228,6 +241,8 @@ const ( BS0 = 0x0 BS1 = 0x2000 BSDLY = 0x2000 + BTRFS_SUPER_MAGIC = 0x9123683e + BTRFS_TEST_MAGIC = 0x73727279 CAN_BCM = 0x2 CAN_EFF_FLAG = 0x80000000 CAN_EFF_ID_BITS = 0x1d @@ -251,6 +266,8 @@ const ( CBAUD = 0x100f CBAUDEX = 0x1000 CFLUSH = 0xf + CGROUP2_SUPER_MAGIC = 0x63677270 + CGROUP_SUPER_MAGIC = 0x27e0eb CIBAUD = 0x100f0000 CLOCAL = 0x800 CLOCK_BOOTTIME = 0x7 @@ -293,10 +310,12 @@ const ( CLONE_VFORK = 0x4000 CLONE_VM = 0x100 CMSPAR = 0x40000000 + CODA_SUPER_MAGIC = 0x73757245 CR0 = 0x0 CR1 = 0x200 CR2 = 0x400 CR3 = 0x600 + CRAMFS_MAGIC = 0x28cd3d45 CRDLY = 0x600 CREAD = 0x80 CRTSCTS = 0x80000000 @@ -311,6 +330,9 @@ const ( CSTOP = 0x13 CSTOPB = 0x40 CSUSP = 0x1a + DAXFS_MAGIC = 0x64646178 + DEBUGFS_MAGIC = 0x64626720 + DEVPTS_SUPER_MAGIC = 0x1cd1 DT_BLK = 0x6 DT_CHR = 0x2 DT_DIR = 0x4 @@ -327,9 +349,12 @@ const ( ECHOKE = 0x800 ECHONL = 0x40 ECHOPRT = 0x400 + ECRYPTFS_SUPER_MAGIC = 0xf15f EFD_CLOEXEC = 0x80000 EFD_NONBLOCK = 0x80 EFD_SEMAPHORE = 0x1 + EFIVARFS_MAGIC = 0xde5e81e4 + EFS_SUPER_MAGIC = 0x414a53 ENCODING_DEFAULT = 0x0 ENCODING_FM_MARK = 0x3 ENCODING_FM_SPACE = 0x4 @@ -390,6 +415,8 @@ const ( ETH_P_DSA = 0x1b ETH_P_ECONET = 0x18 ETH_P_EDSA = 0xdada + ETH_P_ERSPAN = 0x88be + ETH_P_ERSPAN2 = 0x22eb ETH_P_FCOE = 0x8906 ETH_P_FIP = 0x8914 ETH_P_HDLC = 0x19 @@ -398,6 +425,7 @@ const ( ETH_P_IEEE802154 = 0xf6 ETH_P_IEEEPUP = 0xa00 ETH_P_IEEEPUPAT = 0xa01 + ETH_P_IFE = 0xed3e ETH_P_IP = 0x800 ETH_P_IPV6 = 0x86dd ETH_P_IPX = 0x8137 @@ -408,11 +436,13 @@ const ( ETH_P_LOOP = 0x60 ETH_P_LOOPBACK = 0x9000 ETH_P_MACSEC = 0x88e5 + ETH_P_MAP = 0xf9 ETH_P_MOBITEX = 0x15 ETH_P_MPLS_MC = 0x8848 ETH_P_MPLS_UC = 0x8847 ETH_P_MVRP = 0x88f5 ETH_P_NCSI = 0x88f8 + ETH_P_NSH = 0x894f ETH_P_PAE = 0x888e ETH_P_PAUSE = 0x8808 ETH_P_PHONET = 0xf5 @@ -420,6 +450,7 @@ const ( ETH_P_PPP_DISC = 0x8863 ETH_P_PPP_MP = 0x8 ETH_P_PPP_SES = 0x8864 + ETH_P_PREAUTH = 0x88c7 ETH_P_PRP = 0x88fb ETH_P_PUP = 0x200 ETH_P_PUPAT = 0x201 @@ -440,9 +471,14 @@ const ( ETH_P_WCCP = 0x883e ETH_P_X25 = 0x805 ETH_P_XDSA = 0xf8 + EXABYTE_ENABLE_NEST = 0xf0 + EXT2_SUPER_MAGIC = 0xef53 + EXT3_SUPER_MAGIC = 0xef53 + EXT4_SUPER_MAGIC = 0xef53 EXTA = 0xe EXTB = 0xf EXTPROC = 0x10000 + F2FS_SUPER_MAGIC = 0xf2f52010 FALLOC_FL_COLLAPSE_RANGE = 0x8 FALLOC_FL_INSERT_RANGE = 0x20 FALLOC_FL_KEEP_SIZE = 0x1 @@ -463,6 +499,8 @@ const ( FS_ENCRYPTION_MODE_AES_256_GCM = 0x2 FS_ENCRYPTION_MODE_AES_256_XTS = 0x1 FS_ENCRYPTION_MODE_INVALID = 0x0 + FS_ENCRYPTION_MODE_SPECK128_256_CTS = 0x8 + FS_ENCRYPTION_MODE_SPECK128_256_XTS = 0x7 FS_IOC_GET_ENCRYPTION_POLICY = 0x800c6615 FS_IOC_GET_ENCRYPTION_PWSALT = 0x80106614 FS_IOC_SET_ENCRYPTION_POLICY = 0x400c6613 @@ -476,6 +514,8 @@ const ( FS_POLICY_FLAGS_PAD_8 = 0x1 FS_POLICY_FLAGS_PAD_MASK = 0x3 FS_POLICY_FLAGS_VALID = 0x3 + FUTEXFS_SUPER_MAGIC = 0xbad1dea + F_ADD_SEALS = 0x409 F_DUPFD = 0x0 F_DUPFD_CLOEXEC = 0x406 F_EXLCK = 0x4 @@ -488,6 +528,9 @@ const ( F_GETOWN_EX = 0x10 F_GETPIPE_SZ = 0x408 F_GETSIG = 0xb + F_GET_FILE_RW_HINT = 0x40d + F_GET_RW_HINT = 0x40b + F_GET_SEALS = 0x40a F_LOCK = 0x1 F_NOTIFY = 0x402 F_OFD_GETLK = 0x24 @@ -495,6 +538,10 @@ const ( F_OFD_SETLKW = 0x26 F_OK = 0x0 F_RDLCK = 0x0 + F_SEAL_GROW = 0x4 + F_SEAL_SEAL = 0x1 + F_SEAL_SHRINK = 0x2 + F_SEAL_WRITE = 0x8 F_SETFD = 0x2 F_SETFL = 0x4 F_SETLEASE = 0x400 @@ -506,6 +553,8 @@ const ( F_SETOWN_EX = 0xf F_SETPIPE_SZ = 0x407 F_SETSIG = 0xa + F_SET_FILE_RW_HINT = 0x40e + F_SET_RW_HINT = 0x40c F_SHLCK = 0x8 F_TEST = 0x3 F_TLOCK = 0x2 @@ -527,6 +576,49 @@ const ( GENL_UNS_ADMIN_PERM = 0x10 GRND_NONBLOCK = 0x1 GRND_RANDOM = 0x2 + HDIO_DRIVE_CMD = 0x31f + HDIO_DRIVE_CMD_AEB = 0x31e + HDIO_DRIVE_CMD_HDR_SIZE = 0x4 + HDIO_DRIVE_HOB_HDR_SIZE = 0x8 + HDIO_DRIVE_RESET = 0x31c + HDIO_DRIVE_TASK = 0x31e + HDIO_DRIVE_TASKFILE = 0x31d + HDIO_DRIVE_TASK_HDR_SIZE = 0x8 + HDIO_GETGEO = 0x301 + HDIO_GET_32BIT = 0x309 + HDIO_GET_ACOUSTIC = 0x30f + HDIO_GET_ADDRESS = 0x310 + HDIO_GET_BUSSTATE = 0x31a + HDIO_GET_DMA = 0x30b + HDIO_GET_IDENTITY = 0x30d + HDIO_GET_KEEPSETTINGS = 0x308 + HDIO_GET_MULTCOUNT = 0x304 + HDIO_GET_NICE = 0x30c + HDIO_GET_NOWERR = 0x30a + HDIO_GET_QDMA = 0x305 + HDIO_GET_UNMASKINTR = 0x302 + HDIO_GET_WCACHE = 0x30e + HDIO_OBSOLETE_IDENTITY = 0x307 + HDIO_SCAN_HWIF = 0x328 + HDIO_SET_32BIT = 0x324 + HDIO_SET_ACOUSTIC = 0x32c + HDIO_SET_ADDRESS = 0x32f + HDIO_SET_BUSSTATE = 0x32d + HDIO_SET_DMA = 0x326 + HDIO_SET_KEEPSETTINGS = 0x323 + HDIO_SET_MULTCOUNT = 0x321 + HDIO_SET_NICE = 0x329 + HDIO_SET_NOWERR = 0x325 + HDIO_SET_PIO_MODE = 0x327 + HDIO_SET_QDMA = 0x32e + HDIO_SET_UNMASKINTR = 0x322 + HDIO_SET_WCACHE = 0x32b + HDIO_SET_XFER = 0x306 + HDIO_TRISTATE_HWIF = 0x31b + HDIO_UNREGISTER_HWIF = 0x32a + HOSTFS_SUPER_MAGIC = 0xc0ffee + HPFS_SUPER_MAGIC = 0xf995e849 + HUGETLBFS_MAGIC = 0x958458f6 HUPCL = 0x400 IBSHIFT = 0x10 ICANON = 0x2 @@ -546,7 +638,7 @@ const ( IFA_F_STABLE_PRIVACY = 0x800 IFA_F_TEMPORARY = 0x1 IFA_F_TENTATIVE = 0x40 - IFA_MAX = 0x8 + IFA_MAX = 0xa IFF_ALLMULTI = 0x200 IFF_ATTACH_QUEUE = 0x200 IFF_AUTOMEDIA = 0x4000 @@ -561,6 +653,8 @@ const ( IFF_MASTER = 0x400 IFF_MULTICAST = 0x1000 IFF_MULTI_QUEUE = 0x100 + IFF_NAPI = 0x10 + IFF_NAPI_FRAGS = 0x20 IFF_NOARP = 0x80 IFF_NOFILTER = 0x1000 IFF_NOTRAILERS = 0x20 @@ -612,6 +706,7 @@ const ( IN_ISDIR = 0x40000000 IN_LOOPBACKNET = 0x7f IN_MASK_ADD = 0x20000000 + IN_MASK_CREATE = 0x10000000 IN_MODIFY = 0x2 IN_MOVE = 0xc0 IN_MOVED_FROM = 0x40 @@ -671,6 +766,7 @@ const ( IPV6_DONTFRAG = 0x3e IPV6_DROP_MEMBERSHIP = 0x15 IPV6_DSTOPTS = 0x3b + IPV6_FREEBIND = 0x4e IPV6_HDRINCL = 0x24 IPV6_HOPLIMIT = 0x34 IPV6_HOPOPTS = 0x36 @@ -682,6 +778,7 @@ const ( IPV6_MINHOPCOUNT = 0x49 IPV6_MTU = 0x18 IPV6_MTU_DISCOVER = 0x17 + IPV6_MULTICAST_ALL = 0x1d IPV6_MULTICAST_HOPS = 0x12 IPV6_MULTICAST_IF = 0x11 IPV6_MULTICAST_LOOP = 0x13 @@ -775,12 +872,34 @@ const ( IP_UNICAST_IF = 0x32 IP_XFRM_POLICY = 0x11 ISIG = 0x1 + ISOFS_SUPER_MAGIC = 0x9660 ISTRIP = 0x20 IUCLC = 0x200 IUTF8 = 0x4000 IXANY = 0x800 IXOFF = 0x1000 IXON = 0x400 + JFFS2_SUPER_MAGIC = 0x72b6 + KEXEC_ARCH_386 = 0x30000 + KEXEC_ARCH_68K = 0x40000 + KEXEC_ARCH_AARCH64 = 0xb70000 + KEXEC_ARCH_ARM = 0x280000 + KEXEC_ARCH_DEFAULT = 0x0 + KEXEC_ARCH_IA_64 = 0x320000 + KEXEC_ARCH_MASK = 0xffff0000 + KEXEC_ARCH_MIPS = 0x80000 + KEXEC_ARCH_MIPS_LE = 0xa0000 + KEXEC_ARCH_PPC = 0x140000 + KEXEC_ARCH_PPC64 = 0x150000 + KEXEC_ARCH_S390 = 0x160000 + KEXEC_ARCH_SH = 0x2a0000 + KEXEC_ARCH_X86_64 = 0x3e0000 + KEXEC_FILE_NO_INITRAMFS = 0x4 + KEXEC_FILE_ON_CRASH = 0x2 + KEXEC_FILE_UNLOAD = 0x1 + KEXEC_ON_CRASH = 0x1 + KEXEC_PRESERVE_CONTEXT = 0x2 + KEXEC_SEGMENT_MAX = 0x10 KEYCTL_ASSUME_AUTHORITY = 0x10 KEYCTL_CHOWN = 0x4 KEYCTL_CLEAR = 0x7 @@ -795,6 +914,11 @@ const ( KEYCTL_JOIN_SESSION_KEYRING = 0x1 KEYCTL_LINK = 0x8 KEYCTL_NEGATE = 0xd + KEYCTL_PKEY_DECRYPT = 0x1a + KEYCTL_PKEY_ENCRYPT = 0x19 + KEYCTL_PKEY_QUERY = 0x18 + KEYCTL_PKEY_SIGN = 0x1b + KEYCTL_PKEY_VERIFY = 0x1c KEYCTL_READ = 0xb KEYCTL_REJECT = 0x13 KEYCTL_RESTRICT_KEYRING = 0x1d @@ -804,6 +928,10 @@ const ( KEYCTL_SETPERM = 0x5 KEYCTL_SET_REQKEY_KEYRING = 0xe KEYCTL_SET_TIMEOUT = 0xf + KEYCTL_SUPPORTS_DECRYPT = 0x2 + KEYCTL_SUPPORTS_ENCRYPT = 0x1 + KEYCTL_SUPPORTS_SIGN = 0x4 + KEYCTL_SUPPORTS_VERIFY = 0x8 KEYCTL_UNLINK = 0x9 KEYCTL_UPDATE = 0x2 KEY_REQKEY_DEFL_DEFAULT = 0x0 @@ -845,6 +973,7 @@ const ( MADV_FREE = 0x8 MADV_HUGEPAGE = 0xe MADV_HWPOISON = 0x64 + MADV_KEEPONFORK = 0x13 MADV_MERGEABLE = 0xc MADV_NOHUGEPAGE = 0xf MADV_NORMAL = 0x0 @@ -853,12 +982,14 @@ const ( MADV_SEQUENTIAL = 0x2 MADV_UNMERGEABLE = 0xd MADV_WILLNEED = 0x3 + MADV_WIPEONFORK = 0x12 MAP_ANON = 0x800 MAP_ANONYMOUS = 0x800 MAP_DENYWRITE = 0x2000 MAP_EXECUTABLE = 0x4000 MAP_FILE = 0x0 MAP_FIXED = 0x10 + MAP_FIXED_NOREPLACE = 0x100000 MAP_GROWSDOWN = 0x1000 MAP_HUGETLB = 0x80000 MAP_HUGE_MASK = 0x3f @@ -870,14 +1001,40 @@ const ( MAP_PRIVATE = 0x2 MAP_RENAME = 0x800 MAP_SHARED = 0x1 + MAP_SHARED_VALIDATE = 0x3 MAP_STACK = 0x40000 MAP_TYPE = 0xf MCL_CURRENT = 0x1 MCL_FUTURE = 0x2 MCL_ONFAULT = 0x4 + MFD_ALLOW_SEALING = 0x2 + MFD_CLOEXEC = 0x1 + MFD_HUGETLB = 0x4 + MFD_HUGE_16GB = -0x78000000 + MFD_HUGE_16MB = 0x60000000 + MFD_HUGE_1GB = 0x78000000 + MFD_HUGE_1MB = 0x50000000 + MFD_HUGE_256MB = 0x70000000 + MFD_HUGE_2GB = 0x7c000000 + MFD_HUGE_2MB = 0x54000000 + MFD_HUGE_32MB = 0x64000000 + MFD_HUGE_512KB = 0x4c000000 + MFD_HUGE_512MB = 0x74000000 + MFD_HUGE_64KB = 0x40000000 + MFD_HUGE_8MB = 0x5c000000 + MFD_HUGE_MASK = 0x3f + MFD_HUGE_SHIFT = 0x1a + MINIX2_SUPER_MAGIC = 0x2468 + MINIX2_SUPER_MAGIC2 = 0x2478 + MINIX3_SUPER_MAGIC = 0x4d5a + MINIX_SUPER_MAGIC = 0x137f + MINIX_SUPER_MAGIC2 = 0x138f MNT_DETACH = 0x2 MNT_EXPIRE = 0x4 MNT_FORCE = 0x1 + MODULE_INIT_IGNORE_MODVERSIONS = 0x1 + MODULE_INIT_IGNORE_VERMAGIC = 0x2 + MSDOS_SUPER_MAGIC = 0x4d44 MSG_BATCH = 0x40000 MSG_CMSG_CLOEXEC = 0x40000000 MSG_CONFIRM = 0x800 @@ -899,6 +1056,7 @@ const ( MSG_TRYHARD = 0x4 MSG_WAITALL = 0x100 MSG_WAITFORONE = 0x10000 + MSG_ZEROCOPY = 0x4000000 MS_ACTIVE = 0x40000000 MS_ASYNC = 0x1 MS_BIND = 0x1000 @@ -936,7 +1094,9 @@ const ( MS_SYNCHRONOUS = 0x10 MS_UNBINDABLE = 0x20000 MS_VERBOSE = 0x8000 + MTD_INODE_FS_MAGIC = 0x11307854 NAME_MAX = 0xff + NCP_SUPER_MAGIC = 0x564c NETLINK_ADD_MEMBERSHIP = 0x1 NETLINK_AUDIT = 0x9 NETLINK_BROADCAST_ERROR = 0x4 @@ -950,6 +1110,7 @@ const ( NETLINK_FIB_LOOKUP = 0xa NETLINK_FIREWALL = 0x3 NETLINK_GENERIC = 0x10 + NETLINK_GET_STRICT_CHK = 0xc NETLINK_INET_DIAG = 0x4 NETLINK_IP6_FW = 0xd NETLINK_ISCSI = 0x8 @@ -971,6 +1132,39 @@ const ( NETLINK_UNUSED = 0x1 NETLINK_USERSOCK = 0x2 NETLINK_XFRM = 0x6 + NETNSA_MAX = 0x3 + NETNSA_NSID_NOT_ASSIGNED = -0x1 + NFNETLINK_V0 = 0x0 + NFNLGRP_ACCT_QUOTA = 0x8 + NFNLGRP_CONNTRACK_DESTROY = 0x3 + NFNLGRP_CONNTRACK_EXP_DESTROY = 0x6 + NFNLGRP_CONNTRACK_EXP_NEW = 0x4 + NFNLGRP_CONNTRACK_EXP_UPDATE = 0x5 + NFNLGRP_CONNTRACK_NEW = 0x1 + NFNLGRP_CONNTRACK_UPDATE = 0x2 + NFNLGRP_MAX = 0x9 + NFNLGRP_NFTABLES = 0x7 + NFNLGRP_NFTRACE = 0x9 + NFNLGRP_NONE = 0x0 + NFNL_BATCH_MAX = 0x1 + NFNL_MSG_BATCH_BEGIN = 0x10 + NFNL_MSG_BATCH_END = 0x11 + NFNL_NFA_NEST = 0x8000 + NFNL_SUBSYS_ACCT = 0x7 + NFNL_SUBSYS_COUNT = 0xc + NFNL_SUBSYS_CTHELPER = 0x9 + NFNL_SUBSYS_CTNETLINK = 0x1 + NFNL_SUBSYS_CTNETLINK_EXP = 0x2 + NFNL_SUBSYS_CTNETLINK_TIMEOUT = 0x8 + NFNL_SUBSYS_IPSET = 0x6 + NFNL_SUBSYS_NFTABLES = 0xa + NFNL_SUBSYS_NFT_COMPAT = 0xb + NFNL_SUBSYS_NONE = 0x0 + NFNL_SUBSYS_OSF = 0x5 + NFNL_SUBSYS_QUEUE = 0x3 + NFNL_SUBSYS_ULOG = 0x4 + NFS_SUPER_MAGIC = 0x6969 + NILFS_SUPER_MAGIC = 0x3434 NL0 = 0x0 NL1 = 0x100 NLA_ALIGNTO = 0x4 @@ -998,10 +1192,13 @@ const ( NLM_F_EXCL = 0x200 NLM_F_MATCH = 0x200 NLM_F_MULTI = 0x2 + NLM_F_NONREC = 0x100 NLM_F_REPLACE = 0x100 NLM_F_REQUEST = 0x1 NLM_F_ROOT = 0x100 NOFLSH = 0x80 + NSFS_MAGIC = 0x6e736673 + OCFS2_SUPER_MAGIC = 0x7461636f OCRNL = 0x8 OFDEL = 0x80 OFILL = 0x40 @@ -1009,7 +1206,9 @@ const ( ONLCR = 0x4 ONLRET = 0x20 ONOCR = 0x10 + OPENPROM_SUPER_MAGIC = 0x9fa1 OPOST = 0x1 + OVERLAYFS_SUPER_MAGIC = 0x794c7630 O_ACCMODE = 0x3 O_APPEND = 0x8 O_ASYNC = 0x1000 @@ -1055,6 +1254,7 @@ const ( PACKET_FASTROUTE = 0x6 PACKET_HDRLEN = 0xb PACKET_HOST = 0x0 + PACKET_IGNORE_OUTGOING = 0x17 PACKET_KERNEL = 0x7 PACKET_LOOPBACK = 0x5 PACKET_LOSS = 0xe @@ -1094,16 +1294,50 @@ const ( PERF_EVENT_IOC_DISABLE = 0x20002401 PERF_EVENT_IOC_ENABLE = 0x20002400 PERF_EVENT_IOC_ID = 0x40042407 + PERF_EVENT_IOC_MODIFY_ATTRIBUTES = 0x8004240b PERF_EVENT_IOC_PAUSE_OUTPUT = 0x80042409 PERF_EVENT_IOC_PERIOD = 0x80082404 + PERF_EVENT_IOC_QUERY_BPF = 0xc004240a PERF_EVENT_IOC_REFRESH = 0x20002402 PERF_EVENT_IOC_RESET = 0x20002403 PERF_EVENT_IOC_SET_BPF = 0x80042408 PERF_EVENT_IOC_SET_FILTER = 0x80042406 PERF_EVENT_IOC_SET_OUTPUT = 0x20002405 + PIPEFS_MAGIC = 0x50495045 + PPPIOCATTACH = 0x8004743d + PPPIOCATTCHAN = 0x80047438 + PPPIOCCONNECT = 0x8004743a + PPPIOCDETACH = 0x8004743c + PPPIOCDISCONN = 0x20007439 + PPPIOCGASYNCMAP = 0x40047458 + PPPIOCGCHAN = 0x40047437 + PPPIOCGDEBUG = 0x40047441 + PPPIOCGFLAGS = 0x4004745a + PPPIOCGIDLE = 0x4008743f + PPPIOCGL2TPSTATS = 0x40487436 + PPPIOCGMRU = 0x40047453 + PPPIOCGNPMODE = 0xc008744c + PPPIOCGRASYNCMAP = 0x40047455 + PPPIOCGUNIT = 0x40047456 + PPPIOCGXASYNCMAP = 0x40207450 + PPPIOCNEWUNIT = 0xc004743e + PPPIOCSACTIVE = 0x80087446 + PPPIOCSASYNCMAP = 0x80047457 + PPPIOCSCOMPRESS = 0x800c744d + PPPIOCSDEBUG = 0x80047440 + PPPIOCSFLAGS = 0x80047459 + PPPIOCSMAXCID = 0x80047451 + PPPIOCSMRRU = 0x8004743b + PPPIOCSMRU = 0x80047452 + PPPIOCSNPMODE = 0x8008744b + PPPIOCSPASS = 0x80087447 + PPPIOCSRASYNCMAP = 0x80047454 + PPPIOCSXASYNCMAP = 0x8020744f + PPPIOCXFERUNIT = 0x2000744e PRIO_PGRP = 0x1 PRIO_PROCESS = 0x0 PRIO_USER = 0x2 + PROC_SUPER_MAGIC = 0x9fa0 PROT_EXEC = 0x4 PROT_GROWSDOWN = 0x1000000 PROT_GROWSUP = 0x2000000 @@ -1146,6 +1380,7 @@ const ( PR_GET_PDEATHSIG = 0x2 PR_GET_SECCOMP = 0x15 PR_GET_SECUREBITS = 0x1b + PR_GET_SPECULATION_CTRL = 0x34 PR_GET_THP_DISABLE = 0x2a PR_GET_TID_ADDRESS = 0x28 PR_GET_TIMERSLACK = 0x1e @@ -1191,11 +1426,24 @@ const ( PR_SET_PTRACER_ANY = 0xffffffff PR_SET_SECCOMP = 0x16 PR_SET_SECUREBITS = 0x1c + PR_SET_SPECULATION_CTRL = 0x35 PR_SET_THP_DISABLE = 0x29 PR_SET_TIMERSLACK = 0x1d PR_SET_TIMING = 0xe PR_SET_TSC = 0x1a PR_SET_UNALIGN = 0x6 + PR_SPEC_DISABLE = 0x4 + PR_SPEC_ENABLE = 0x2 + PR_SPEC_FORCE_DISABLE = 0x8 + PR_SPEC_INDIRECT_BRANCH = 0x1 + PR_SPEC_NOT_AFFECTED = 0x0 + PR_SPEC_PRCTL = 0x1 + PR_SPEC_STORE_BYPASS = 0x0 + PR_SVE_GET_VL = 0x33 + PR_SVE_SET_VL = 0x32 + PR_SVE_SET_VL_ONEXEC = 0x40000 + PR_SVE_VL_INHERIT = 0x20000 + PR_SVE_VL_LEN_MASK = 0xffff PR_TASK_PERF_EVENTS_DISABLE = 0x1f PR_TASK_PERF_EVENTS_ENABLE = 0x20 PR_TIMING_STATISTICAL = 0x0 @@ -1204,6 +1452,7 @@ const ( PR_TSC_SIGSEGV = 0x2 PR_UNALIGN_NOPRINT = 0x1 PR_UNALIGN_SIGBUS = 0x2 + PSTOREFS_MAGIC = 0x6165676c PTRACE_ATTACH = 0x10 PTRACE_CONT = 0x7 PTRACE_DETACH = 0x11 @@ -1252,6 +1501,7 @@ const ( PTRACE_POKETEXT_3264 = 0xc2 PTRACE_POKEUSR = 0x6 PTRACE_SECCOMP_GET_FILTER = 0x420c + PTRACE_SECCOMP_GET_METADATA = 0x420d PTRACE_SEIZE = 0x4206 PTRACE_SETFPREGS = 0xf PTRACE_SETOPTIONS = 0x4200 @@ -1264,6 +1514,14 @@ const ( PTRACE_SINGLESTEP = 0x9 PTRACE_SYSCALL = 0x18 PTRACE_TRACEME = 0x0 + QNX4_SUPER_MAGIC = 0x2f + QNX6_SUPER_MAGIC = 0x68191122 + RAMFS_MAGIC = 0x858458f6 + RDTGROUP_SUPER_MAGIC = 0x7655821 + REISERFS_SUPER_MAGIC = 0x52654973 + RENAME_EXCHANGE = 0x2 + RENAME_NOREPLACE = 0x1 + RENAME_WHITEOUT = 0x4 RLIMIT_AS = 0x6 RLIMIT_CORE = 0x4 RLIMIT_CPU = 0x0 @@ -1281,9 +1539,17 @@ const ( RLIMIT_SIGPENDING = 0xb RLIMIT_STACK = 0x3 RLIM_INFINITY = 0xffffffffffffffff + RNDADDENTROPY = 0x80085203 + RNDADDTOENTCNT = 0x80045201 + RNDCLEARPOOL = 0x20005206 + RNDGETENTCNT = 0x40045200 + RNDGETPOOL = 0x40085202 + RNDRESEEDCRNG = 0x20005207 + RNDZAPENTCNT = 0x20005204 RTAX_ADVMSS = 0x8 RTAX_CC_ALGO = 0x10 RTAX_CWND = 0x7 + RTAX_FASTOPEN_NO_COOKIE = 0x11 RTAX_FEATURES = 0xc RTAX_FEATURE_ALLFRAG = 0x8 RTAX_FEATURE_ECN = 0x1 @@ -1294,7 +1560,7 @@ const ( RTAX_INITCWND = 0xb RTAX_INITRWND = 0xe RTAX_LOCK = 0x1 - RTAX_MAX = 0x10 + RTAX_MAX = 0x11 RTAX_MTU = 0x2 RTAX_QUICKACK = 0xf RTAX_REORDERING = 0x9 @@ -1305,13 +1571,40 @@ const ( RTAX_UNSPEC = 0x0 RTAX_WINDOW = 0x3 RTA_ALIGNTO = 0x4 - RTA_MAX = 0x1a + RTA_MAX = 0x1d RTCF_DIRECTSRC = 0x4000000 RTCF_DOREDIRECT = 0x1000000 RTCF_LOG = 0x2000000 RTCF_MASQ = 0x400000 RTCF_NAT = 0x800000 RTCF_VALVE = 0x200000 + RTC_AF = 0x20 + RTC_AIE_OFF = 0x20007002 + RTC_AIE_ON = 0x20007001 + RTC_ALM_READ = 0x40247008 + RTC_ALM_SET = 0x80247007 + RTC_EPOCH_READ = 0x4004700d + RTC_EPOCH_SET = 0x8004700e + RTC_IRQF = 0x80 + RTC_IRQP_READ = 0x4004700b + RTC_IRQP_SET = 0x8004700c + RTC_MAX_FREQ = 0x2000 + RTC_PF = 0x40 + RTC_PIE_OFF = 0x20007006 + RTC_PIE_ON = 0x20007005 + RTC_PLL_GET = 0x401c7011 + RTC_PLL_SET = 0x801c7012 + RTC_RD_TIME = 0x40247009 + RTC_SET_TIME = 0x8024700a + RTC_UF = 0x10 + RTC_UIE_OFF = 0x20007004 + RTC_UIE_ON = 0x20007003 + RTC_VL_CLR = 0x20007014 + RTC_VL_READ = 0x40047013 + RTC_WIE_OFF = 0x20007010 + RTC_WIE_ON = 0x2000700f + RTC_WKALM_RD = 0x40287010 + RTC_WKALM_SET = 0x8028700f RTF_ADDRCLASSMASK = 0xf8000000 RTF_ADDRCONF = 0x40000 RTF_ALLONLINK = 0x20000 @@ -1346,6 +1639,7 @@ const ( RTM_DELACTION = 0x31 RTM_DELADDR = 0x15 RTM_DELADDRLABEL = 0x49 + RTM_DELCHAIN = 0x65 RTM_DELLINK = 0x11 RTM_DELMDB = 0x55 RTM_DELNEIGH = 0x1d @@ -1366,6 +1660,7 @@ const ( RTM_GETADDR = 0x16 RTM_GETADDRLABEL = 0x4a RTM_GETANYCAST = 0x3e + RTM_GETCHAIN = 0x66 RTM_GETDCB = 0x4e RTM_GETLINK = 0x12 RTM_GETMDB = 0x56 @@ -1380,11 +1675,12 @@ const ( RTM_GETSTATS = 0x5e RTM_GETTCLASS = 0x2a RTM_GETTFILTER = 0x2e - RTM_MAX = 0x63 + RTM_MAX = 0x67 RTM_NEWACTION = 0x30 RTM_NEWADDR = 0x14 RTM_NEWADDRLABEL = 0x48 RTM_NEWCACHEREPORT = 0x60 + RTM_NEWCHAIN = 0x64 RTM_NEWLINK = 0x10 RTM_NEWMDB = 0x54 RTM_NEWNDUSEROPT = 0x44 @@ -1399,8 +1695,8 @@ const ( RTM_NEWSTATS = 0x5c RTM_NEWTCLASS = 0x28 RTM_NEWTFILTER = 0x2c - RTM_NR_FAMILIES = 0x15 - RTM_NR_MSGTYPES = 0x54 + RTM_NR_FAMILIES = 0x16 + RTM_NR_MSGTYPES = 0x58 RTM_SETDCB = 0x4f RTM_SETLINK = 0x13 RTM_SETNEIGHTBL = 0x43 @@ -1414,17 +1710,22 @@ const ( RTNH_F_UNRESOLVED = 0x20 RTN_MAX = 0xb RTPROT_BABEL = 0x2a + RTPROT_BGP = 0xba RTPROT_BIRD = 0xc RTPROT_BOOT = 0x3 RTPROT_DHCP = 0x10 RTPROT_DNROUTED = 0xd + RTPROT_EIGRP = 0xc0 RTPROT_GATED = 0x8 + RTPROT_ISIS = 0xbb RTPROT_KERNEL = 0x2 RTPROT_MROUTED = 0x11 RTPROT_MRT = 0xa RTPROT_NTK = 0xf + RTPROT_OSPF = 0xbc RTPROT_RA = 0x9 RTPROT_REDIRECT = 0x1 + RTPROT_RIP = 0xbd RTPROT_STATIC = 0x4 RTPROT_UNSPEC = 0x0 RTPROT_XORP = 0xe @@ -1444,10 +1745,16 @@ const ( SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SC_LOG_FLUSH = 0x100000 SECCOMP_MODE_DISABLED = 0x0 SECCOMP_MODE_FILTER = 0x2 SECCOMP_MODE_STRICT = 0x1 + SECURITYFS_MAGIC = 0x73636673 + SELINUX_MAGIC = 0xf97cff8c + SFD_CLOEXEC = 0x80000 + SFD_NONBLOCK = 0x80 SHUT_RD = 0x0 SHUT_RDWR = 0x2 SHUT_WR = 0x1 @@ -1498,6 +1805,9 @@ const ( SIOCGMIIPHY = 0x8947 SIOCGMIIREG = 0x8948 SIOCGPGRP = 0x40047309 + SIOCGPPPCSTATS = 0x89f2 + SIOCGPPPSTATS = 0x89f0 + SIOCGPPPVER = 0x89f1 SIOCGRARP = 0x8961 SIOCGSKNS = 0x894c SIOCGSTAMP = 0x8906 @@ -1532,6 +1842,23 @@ const ( SIOCSPGRP = 0x80047308 SIOCSRARP = 0x8962 SIOCWANDEV = 0x894a + SMACK_MAGIC = 0x43415d53 + SMART_AUTOSAVE = 0xd2 + SMART_AUTO_OFFLINE = 0xdb + SMART_DISABLE = 0xd9 + SMART_ENABLE = 0xd8 + SMART_HCYL_PASS = 0xc2 + SMART_IMMEDIATE_OFFLINE = 0xd4 + SMART_LCYL_PASS = 0x4f + SMART_READ_LOG_SECTOR = 0xd5 + SMART_READ_THRESHOLDS = 0xd1 + SMART_READ_VALUES = 0xd0 + SMART_SAVE = 0xd3 + SMART_STATUS = 0xda + SMART_WRITE_LOG_SECTOR = 0xd6 + SMART_WRITE_THRESHOLDS = 0xd7 + SMB_SUPER_MAGIC = 0x517b + SOCKFS_MAGIC = 0x534f434b SOCK_CLOEXEC = 0x80000 SOCK_DCCP = 0x6 SOCK_DGRAM = 0x1 @@ -1568,7 +1895,9 @@ const ( SOL_SOCKET = 0xffff SOL_TCP = 0x6 SOL_TIPC = 0x10f + SOL_TLS = 0x11a SOL_X25 = 0x106 + SOL_XDP = 0x11b SOMAXCONN = 0x80 SO_ACCEPTCONN = 0x1009 SO_ATTACH_BPF = 0x32 @@ -1587,6 +1916,17 @@ const ( SO_DETACH_FILTER = 0x1b SO_DOMAIN = 0x1029 SO_DONTROUTE = 0x10 + SO_EE_CODE_TXTIME_INVALID_PARAM = 0x1 + SO_EE_CODE_TXTIME_MISSED = 0x2 + SO_EE_CODE_ZEROCOPY_COPIED = 0x1 + SO_EE_ORIGIN_ICMP = 0x2 + SO_EE_ORIGIN_ICMP6 = 0x3 + SO_EE_ORIGIN_LOCAL = 0x1 + SO_EE_ORIGIN_NONE = 0x0 + SO_EE_ORIGIN_TIMESTAMPING = 0x4 + SO_EE_ORIGIN_TXSTATUS = 0x4 + SO_EE_ORIGIN_TXTIME = 0x6 + SO_EE_ORIGIN_ZEROCOPY = 0x5 SO_ERROR = 0x1007 SO_GET_FILTER = 0x1a SO_INCOMING_CPU = 0x31 @@ -1628,6 +1968,7 @@ const ( SO_TIMESTAMP = 0x1d SO_TIMESTAMPING = 0x25 SO_TIMESTAMPNS = 0x23 + SO_TXTIME = 0x3d SO_TYPE = 0x1008 SO_VM_SOCKETS_BUFFER_MAX_SIZE = 0x2 SO_VM_SOCKETS_BUFFER_MIN_SIZE = 0x1 @@ -1637,10 +1978,38 @@ const ( SO_VM_SOCKETS_PEER_HOST_VM_ID = 0x3 SO_VM_SOCKETS_TRUSTED = 0x5 SO_WIFI_STATUS = 0x29 + SO_ZEROCOPY = 0x3c SPLICE_F_GIFT = 0x8 SPLICE_F_MORE = 0x4 SPLICE_F_MOVE = 0x1 SPLICE_F_NONBLOCK = 0x2 + SQUASHFS_MAGIC = 0x73717368 + STACK_END_MAGIC = 0x57ac6e9d + STATX_ALL = 0xfff + STATX_ATIME = 0x20 + STATX_ATTR_APPEND = 0x20 + STATX_ATTR_AUTOMOUNT = 0x1000 + STATX_ATTR_COMPRESSED = 0x4 + STATX_ATTR_ENCRYPTED = 0x800 + STATX_ATTR_IMMUTABLE = 0x10 + STATX_ATTR_NODUMP = 0x40 + STATX_BASIC_STATS = 0x7ff + STATX_BLOCKS = 0x400 + STATX_BTIME = 0x800 + STATX_CTIME = 0x80 + STATX_GID = 0x10 + STATX_INO = 0x100 + STATX_MODE = 0x2 + STATX_MTIME = 0x40 + STATX_NLINK = 0x4 + STATX_SIZE = 0x200 + STATX_TYPE = 0x1 + STATX_UID = 0x8 + STATX__RESERVED = 0x80000000 + SYNC_FILE_RANGE_WAIT_AFTER = 0x4 + SYNC_FILE_RANGE_WAIT_BEFORE = 0x1 + SYNC_FILE_RANGE_WRITE = 0x2 + SYSFS_MAGIC = 0x62656572 S_BLKSIZE = 0x200 S_IEXEC = 0x40 S_IFBLK = 0x6000 @@ -1678,7 +2047,7 @@ const ( TASKSTATS_GENL_NAME = "TASKSTATS" TASKSTATS_GENL_VERSION = 0x1 TASKSTATS_TYPE_MAX = 0x6 - TASKSTATS_VERSION = 0x8 + TASKSTATS_VERSION = 0x9 TCFLSH = 0x5407 TCGETA = 0x5401 TCGETS = 0x540d @@ -1691,6 +2060,7 @@ const ( TCOOFF = 0x0 TCOON = 0x1 TCP_CC_INFO = 0x1a + TCP_CM_INQ = 0x24 TCP_CONGESTION = 0xd TCP_COOKIE_IN_ALWAYS = 0x1 TCP_COOKIE_MAX = 0x10 @@ -1702,7 +2072,10 @@ const ( TCP_DEFER_ACCEPT = 0x9 TCP_FASTOPEN = 0x17 TCP_FASTOPEN_CONNECT = 0x1e + TCP_FASTOPEN_KEY = 0x21 + TCP_FASTOPEN_NO_COOKIE = 0x22 TCP_INFO = 0xb + TCP_INQ = 0x24 TCP_KEEPCNT = 0x6 TCP_KEEPIDLE = 0x4 TCP_KEEPINTVL = 0x5 @@ -1711,6 +2084,8 @@ const ( TCP_MAXWIN = 0xffff TCP_MAX_WINSHIFT = 0xe TCP_MD5SIG = 0xe + TCP_MD5SIG_EXT = 0x20 + TCP_MD5SIG_FLAG_PREFIX = 0x1 TCP_MD5SIG_MAXKEYLEN = 0x50 TCP_MSS = 0x200 TCP_MSS_DEFAULT = 0x218 @@ -1720,6 +2095,9 @@ const ( TCP_QUEUE_SEQ = 0x15 TCP_QUICKACK = 0xc TCP_REPAIR = 0x13 + TCP_REPAIR_OFF = 0x0 + TCP_REPAIR_OFF_NO_WP = -0x1 + TCP_REPAIR_ON = 0x1 TCP_REPAIR_OPTIONS = 0x16 TCP_REPAIR_QUEUE = 0x14 TCP_REPAIR_WINDOW = 0x1d @@ -1731,8 +2109,10 @@ const ( TCP_THIN_DUPACK = 0x11 TCP_THIN_LINEAR_TIMEOUTS = 0x10 TCP_TIMESTAMP = 0x18 + TCP_ULP = 0x1f TCP_USER_TIMEOUT = 0x12 TCP_WINDOW_CLAMP = 0xa + TCP_ZEROCOPY_RECEIVE = 0x23 TCSAFLUSH = 0x5410 TCSBRK = 0x5405 TCSBRKP = 0x5486 @@ -1746,6 +2126,7 @@ const ( TCSETSW = 0x540f TCSETSW2 = 0x8030542c TCXONC = 0x5406 + TIMER_ABSTIME = 0x1 TIOCCBRK = 0x5428 TIOCCONS = 0x80047478 TIOCEXCL = 0x740d @@ -1754,6 +2135,7 @@ const ( TIOCGETP = 0x7408 TIOCGEXCL = 0x40045440 TIOCGICOUNT = 0x5492 + TIOCGISO7816 = 0x40285442 TIOCGLCKTRMIOS = 0x548b TIOCGLTC = 0x7474 TIOCGPGRP = 0x40047477 @@ -1810,6 +2192,7 @@ const ( TIOCSETN = 0x740a TIOCSETP = 0x7409 TIOCSIG = 0x80045436 + TIOCSISO7816 = 0xc0285443 TIOCSLCKTRMIOS = 0x548c TIOCSLTC = 0x7475 TIOCSPGRP = 0x80047476 @@ -1820,7 +2203,27 @@ const ( TIOCSTI = 0x5472 TIOCSWINSZ = 0x80087467 TIOCVHANGUP = 0x5437 + TMPFS_MAGIC = 0x1021994 TOSTOP = 0x8000 + TPACKET_ALIGNMENT = 0x10 + TPACKET_HDRLEN = 0x34 + TP_STATUS_AVAILABLE = 0x0 + TP_STATUS_BLK_TMO = 0x20 + TP_STATUS_COPY = 0x2 + TP_STATUS_CSUMNOTREADY = 0x8 + TP_STATUS_CSUM_VALID = 0x80 + TP_STATUS_KERNEL = 0x0 + TP_STATUS_LOSING = 0x4 + TP_STATUS_SENDING = 0x2 + TP_STATUS_SEND_REQUEST = 0x1 + TP_STATUS_TS_RAW_HARDWARE = -0x80000000 + TP_STATUS_TS_SOFTWARE = 0x20000000 + TP_STATUS_TS_SYS_HARDWARE = 0x40000000 + TP_STATUS_USER = 0x1 + TP_STATUS_VLAN_TPID_VALID = 0x40 + TP_STATUS_VLAN_VALID = 0x10 + TP_STATUS_WRONG_FORMAT = 0x4 + TRACEFS_MAGIC = 0x74726163 TS_COMM_LEN = 0x20 TUNATTACHFILTER = 0x800854d5 TUNDETACHFILTER = 0x800854d6 @@ -1832,6 +2235,7 @@ const ( TUNGETVNETHDRSZ = 0x400454d7 TUNGETVNETLE = 0x400454dd TUNSETDEBUG = 0x800454c9 + TUNSETFILTEREBPF = 0x400454e1 TUNSETGROUP = 0x800454ce TUNSETIFF = 0x800454ca TUNSETIFINDEX = 0x800454da @@ -1842,13 +2246,32 @@ const ( TUNSETPERSIST = 0x800454cb TUNSETQUEUE = 0x800454d9 TUNSETSNDBUF = 0x800454d4 + TUNSETSTEERINGEBPF = 0x400454e0 TUNSETTXFILTER = 0x800454d1 TUNSETVNETBE = 0x800454de TUNSETVNETHDRSZ = 0x800454d8 TUNSETVNETLE = 0x800454dc + UBI_IOCATT = 0x80186f40 + UBI_IOCDET = 0x80046f41 + UBI_IOCEBCH = 0x80044f02 + UBI_IOCEBER = 0x80044f01 + UBI_IOCEBISMAP = 0x40044f05 + UBI_IOCEBMAP = 0x80084f03 + UBI_IOCEBUNMAP = 0x80044f04 + UBI_IOCMKVOL = 0x80986f00 + UBI_IOCRMVOL = 0x80046f01 + UBI_IOCRNVOL = 0x91106f03 + UBI_IOCRSVOL = 0x800c6f02 + UBI_IOCSETVOLPROP = 0x80104f06 + UBI_IOCVOLCRBLK = 0x80804f07 + UBI_IOCVOLRMBLK = 0x20004f08 + UBI_IOCVOLUP = 0x80084f00 + UDF_SUPER_MAGIC = 0x15013346 UMOUNT_NOFOLLOW = 0x8 + USBDEVICE_SUPER_MAGIC = 0x9fa2 UTIME_NOW = 0x3fffffff UTIME_OMIT = 0x3ffffffe + V9FS_MAGIC = 0x1021997 VDISCARD = 0xd VEOF = 0x10 VEOL = 0x11 @@ -1891,6 +2314,86 @@ const ( WDIOC_SETPRETIMEOUT = 0xc0045708 WDIOC_SETTIMEOUT = 0xc0045706 WEXITED = 0x4 + WIN_ACKMEDIACHANGE = 0xdb + WIN_CHECKPOWERMODE1 = 0xe5 + WIN_CHECKPOWERMODE2 = 0x98 + WIN_DEVICE_RESET = 0x8 + WIN_DIAGNOSE = 0x90 + WIN_DOORLOCK = 0xde + WIN_DOORUNLOCK = 0xdf + WIN_DOWNLOAD_MICROCODE = 0x92 + WIN_FLUSH_CACHE = 0xe7 + WIN_FLUSH_CACHE_EXT = 0xea + WIN_FORMAT = 0x50 + WIN_GETMEDIASTATUS = 0xda + WIN_IDENTIFY = 0xec + WIN_IDENTIFY_DMA = 0xee + WIN_IDLEIMMEDIATE = 0xe1 + WIN_INIT = 0x60 + WIN_MEDIAEJECT = 0xed + WIN_MULTREAD = 0xc4 + WIN_MULTREAD_EXT = 0x29 + WIN_MULTWRITE = 0xc5 + WIN_MULTWRITE_EXT = 0x39 + WIN_NOP = 0x0 + WIN_PACKETCMD = 0xa0 + WIN_PIDENTIFY = 0xa1 + WIN_POSTBOOT = 0xdc + WIN_PREBOOT = 0xdd + WIN_QUEUED_SERVICE = 0xa2 + WIN_READ = 0x20 + WIN_READDMA = 0xc8 + WIN_READDMA_EXT = 0x25 + WIN_READDMA_ONCE = 0xc9 + WIN_READDMA_QUEUED = 0xc7 + WIN_READDMA_QUEUED_EXT = 0x26 + WIN_READ_BUFFER = 0xe4 + WIN_READ_EXT = 0x24 + WIN_READ_LONG = 0x22 + WIN_READ_LONG_ONCE = 0x23 + WIN_READ_NATIVE_MAX = 0xf8 + WIN_READ_NATIVE_MAX_EXT = 0x27 + WIN_READ_ONCE = 0x21 + WIN_RECAL = 0x10 + WIN_RESTORE = 0x10 + WIN_SECURITY_DISABLE = 0xf6 + WIN_SECURITY_ERASE_PREPARE = 0xf3 + WIN_SECURITY_ERASE_UNIT = 0xf4 + WIN_SECURITY_FREEZE_LOCK = 0xf5 + WIN_SECURITY_SET_PASS = 0xf1 + WIN_SECURITY_UNLOCK = 0xf2 + WIN_SEEK = 0x70 + WIN_SETFEATURES = 0xef + WIN_SETIDLE1 = 0xe3 + WIN_SETIDLE2 = 0x97 + WIN_SETMULT = 0xc6 + WIN_SET_MAX = 0xf9 + WIN_SET_MAX_EXT = 0x37 + WIN_SLEEPNOW1 = 0xe6 + WIN_SLEEPNOW2 = 0x99 + WIN_SMART = 0xb0 + WIN_SPECIFY = 0x91 + WIN_SRST = 0x8 + WIN_STANDBY = 0xe2 + WIN_STANDBY2 = 0x96 + WIN_STANDBYNOW1 = 0xe0 + WIN_STANDBYNOW2 = 0x94 + WIN_VERIFY = 0x40 + WIN_VERIFY_EXT = 0x42 + WIN_VERIFY_ONCE = 0x41 + WIN_WRITE = 0x30 + WIN_WRITEDMA = 0xca + WIN_WRITEDMA_EXT = 0x35 + WIN_WRITEDMA_ONCE = 0xcb + WIN_WRITEDMA_QUEUED = 0xcc + WIN_WRITEDMA_QUEUED_EXT = 0x36 + WIN_WRITE_BUFFER = 0xe8 + WIN_WRITE_EXT = 0x34 + WIN_WRITE_LONG = 0x32 + WIN_WRITE_LONG_ONCE = 0x33 + WIN_WRITE_ONCE = 0x31 + WIN_WRITE_SAME = 0xe9 + WIN_WRITE_VERIFY = 0x3c WNOHANG = 0x1 WNOTHREAD = 0x20000000 WNOWAIT = 0x1000000 @@ -1900,7 +2403,30 @@ const ( XATTR_CREATE = 0x1 XATTR_REPLACE = 0x2 XCASE = 0x4 + XDP_COPY = 0x2 + XDP_FLAGS_DRV_MODE = 0x4 + XDP_FLAGS_HW_MODE = 0x8 + XDP_FLAGS_MASK = 0xf + XDP_FLAGS_MODES = 0xe + XDP_FLAGS_SKB_MODE = 0x2 + XDP_FLAGS_UPDATE_IF_NOEXIST = 0x1 + XDP_MMAP_OFFSETS = 0x1 + XDP_PGOFF_RX_RING = 0x0 + XDP_PGOFF_TX_RING = 0x80000000 + XDP_RX_RING = 0x2 + XDP_SHARED_UMEM = 0x1 + XDP_STATISTICS = 0x7 + XDP_TX_RING = 0x3 + XDP_UMEM_COMPLETION_RING = 0x6 + XDP_UMEM_FILL_RING = 0x5 + XDP_UMEM_PGOFF_COMPLETION_RING = 0x180000000 + XDP_UMEM_PGOFF_FILL_RING = 0x100000000 + XDP_UMEM_REG = 0x4 + XDP_ZEROCOPY = 0x4 + XENFS_SUPER_MAGIC = 0xabba1974 + XFS_SUPER_MAGIC = 0x58465342 XTABS = 0x1800 + ZSMALLOC_MAGIC = 0x58295829 ) // Errors @@ -2082,174 +2608,182 @@ const ( ) // Error table -var errors = [...]string{ - 1: "operation not permitted", - 2: "no such file or directory", - 3: "no such process", - 4: "interrupted system call", - 5: "input/output error", - 6: "no such device or address", - 7: "argument list too long", - 8: "exec format error", - 9: "bad file descriptor", - 10: "no child processes", - 11: "resource temporarily unavailable", - 12: "cannot allocate memory", - 13: "permission denied", - 14: "bad address", - 15: "block device required", - 16: "device or resource busy", - 17: "file exists", - 18: "invalid cross-device link", - 19: "no such device", - 20: "not a directory", - 21: "is a directory", - 22: "invalid argument", - 23: "too many open files in system", - 24: "too many open files", - 25: "inappropriate ioctl for device", - 26: "text file busy", - 27: "file too large", - 28: "no space left on device", - 29: "illegal seek", - 30: "read-only file system", - 31: "too many links", - 32: "broken pipe", - 33: "numerical argument out of domain", - 34: "numerical result out of range", - 35: "no message of desired type", - 36: "identifier removed", - 37: "channel number out of range", - 38: "level 2 not synchronized", - 39: "level 3 halted", - 40: "level 3 reset", - 41: "link number out of range", - 42: "protocol driver not attached", - 43: "no CSI structure available", - 44: "level 2 halted", - 45: "resource deadlock avoided", - 46: "no locks available", - 50: "invalid exchange", - 51: "invalid request descriptor", - 52: "exchange full", - 53: "no anode", - 54: "invalid request code", - 55: "invalid slot", - 56: "file locking deadlock error", - 59: "bad font file format", - 60: "device not a stream", - 61: "no data available", - 62: "timer expired", - 63: "out of streams resources", - 64: "machine is not on the network", - 65: "package not installed", - 66: "object is remote", - 67: "link has been severed", - 68: "advertise error", - 69: "srmount error", - 70: "communication error on send", - 71: "protocol error", - 73: "RFS specific error", - 74: "multihop attempted", - 77: "bad message", - 78: "file name too long", - 79: "value too large for defined data type", - 80: "name not unique on network", - 81: "file descriptor in bad state", - 82: "remote address changed", - 83: "can not access a needed shared library", - 84: "accessing a corrupted shared library", - 85: ".lib section in a.out corrupted", - 86: "attempting to link in too many shared libraries", - 87: "cannot exec a shared library directly", - 88: "invalid or incomplete multibyte or wide character", - 89: "function not implemented", - 90: "too many levels of symbolic links", - 91: "interrupted system call should be restarted", - 92: "streams pipe error", - 93: "directory not empty", - 94: "too many users", - 95: "socket operation on non-socket", - 96: "destination address required", - 97: "message too long", - 98: "protocol wrong type for socket", - 99: "protocol not available", - 120: "protocol not supported", - 121: "socket type not supported", - 122: "operation not supported", - 123: "protocol family not supported", - 124: "address family not supported by protocol", - 125: "address already in use", - 126: "cannot assign requested address", - 127: "network is down", - 128: "network is unreachable", - 129: "network dropped connection on reset", - 130: "software caused connection abort", - 131: "connection reset by peer", - 132: "no buffer space available", - 133: "transport endpoint is already connected", - 134: "transport endpoint is not connected", - 135: "structure needs cleaning", - 137: "not a XENIX named type file", - 138: "no XENIX semaphores available", - 139: "is a named type file", - 140: "remote I/O error", - 141: "unknown error 141", - 142: "unknown error 142", - 143: "cannot send after transport endpoint shutdown", - 144: "too many references: cannot splice", - 145: "connection timed out", - 146: "connection refused", - 147: "host is down", - 148: "no route to host", - 149: "operation already in progress", - 150: "operation now in progress", - 151: "stale file handle", - 158: "operation canceled", - 159: "no medium found", - 160: "wrong medium type", - 161: "required key not available", - 162: "key has expired", - 163: "key has been revoked", - 164: "key was rejected by service", - 165: "owner died", - 166: "state not recoverable", - 167: "operation not possible due to RF-kill", - 168: "memory page has hardware error", - 1133: "disk quota exceeded", +var errorList = [...]struct { + num syscall.Errno + name string + desc string +}{ + {1, "EPERM", "operation not permitted"}, + {2, "ENOENT", "no such file or directory"}, + {3, "ESRCH", "no such process"}, + {4, "EINTR", "interrupted system call"}, + {5, "EIO", "input/output error"}, + {6, "ENXIO", "no such device or address"}, + {7, "E2BIG", "argument list too long"}, + {8, "ENOEXEC", "exec format error"}, + {9, "EBADF", "bad file descriptor"}, + {10, "ECHILD", "no child processes"}, + {11, "EAGAIN", "resource temporarily unavailable"}, + {12, "ENOMEM", "cannot allocate memory"}, + {13, "EACCES", "permission denied"}, + {14, "EFAULT", "bad address"}, + {15, "ENOTBLK", "block device required"}, + {16, "EBUSY", "device or resource busy"}, + {17, "EEXIST", "file exists"}, + {18, "EXDEV", "invalid cross-device link"}, + {19, "ENODEV", "no such device"}, + {20, "ENOTDIR", "not a directory"}, + {21, "EISDIR", "is a directory"}, + {22, "EINVAL", "invalid argument"}, + {23, "ENFILE", "too many open files in system"}, + {24, "EMFILE", "too many open files"}, + {25, "ENOTTY", "inappropriate ioctl for device"}, + {26, "ETXTBSY", "text file busy"}, + {27, "EFBIG", "file too large"}, + {28, "ENOSPC", "no space left on device"}, + {29, "ESPIPE", "illegal seek"}, + {30, "EROFS", "read-only file system"}, + {31, "EMLINK", "too many links"}, + {32, "EPIPE", "broken pipe"}, + {33, "EDOM", "numerical argument out of domain"}, + {34, "ERANGE", "numerical result out of range"}, + {35, "ENOMSG", "no message of desired type"}, + {36, "EIDRM", "identifier removed"}, + {37, "ECHRNG", "channel number out of range"}, + {38, "EL2NSYNC", "level 2 not synchronized"}, + {39, "EL3HLT", "level 3 halted"}, + {40, "EL3RST", "level 3 reset"}, + {41, "ELNRNG", "link number out of range"}, + {42, "EUNATCH", "protocol driver not attached"}, + {43, "ENOCSI", "no CSI structure available"}, + {44, "EL2HLT", "level 2 halted"}, + {45, "EDEADLK", "resource deadlock avoided"}, + {46, "ENOLCK", "no locks available"}, + {50, "EBADE", "invalid exchange"}, + {51, "EBADR", "invalid request descriptor"}, + {52, "EXFULL", "exchange full"}, + {53, "ENOANO", "no anode"}, + {54, "EBADRQC", "invalid request code"}, + {55, "EBADSLT", "invalid slot"}, + {56, "EDEADLOCK", "file locking deadlock error"}, + {59, "EBFONT", "bad font file format"}, + {60, "ENOSTR", "device not a stream"}, + {61, "ENODATA", "no data available"}, + {62, "ETIME", "timer expired"}, + {63, "ENOSR", "out of streams resources"}, + {64, "ENONET", "machine is not on the network"}, + {65, "ENOPKG", "package not installed"}, + {66, "EREMOTE", "object is remote"}, + {67, "ENOLINK", "link has been severed"}, + {68, "EADV", "advertise error"}, + {69, "ESRMNT", "srmount error"}, + {70, "ECOMM", "communication error on send"}, + {71, "EPROTO", "protocol error"}, + {73, "EDOTDOT", "RFS specific error"}, + {74, "EMULTIHOP", "multihop attempted"}, + {77, "EBADMSG", "bad message"}, + {78, "ENAMETOOLONG", "file name too long"}, + {79, "EOVERFLOW", "value too large for defined data type"}, + {80, "ENOTUNIQ", "name not unique on network"}, + {81, "EBADFD", "file descriptor in bad state"}, + {82, "EREMCHG", "remote address changed"}, + {83, "ELIBACC", "can not access a needed shared library"}, + {84, "ELIBBAD", "accessing a corrupted shared library"}, + {85, "ELIBSCN", ".lib section in a.out corrupted"}, + {86, "ELIBMAX", "attempting to link in too many shared libraries"}, + {87, "ELIBEXEC", "cannot exec a shared library directly"}, + {88, "EILSEQ", "invalid or incomplete multibyte or wide character"}, + {89, "ENOSYS", "function not implemented"}, + {90, "ELOOP", "too many levels of symbolic links"}, + {91, "ERESTART", "interrupted system call should be restarted"}, + {92, "ESTRPIPE", "streams pipe error"}, + {93, "ENOTEMPTY", "directory not empty"}, + {94, "EUSERS", "too many users"}, + {95, "ENOTSOCK", "socket operation on non-socket"}, + {96, "EDESTADDRREQ", "destination address required"}, + {97, "EMSGSIZE", "message too long"}, + {98, "EPROTOTYPE", "protocol wrong type for socket"}, + {99, "ENOPROTOOPT", "protocol not available"}, + {120, "EPROTONOSUPPORT", "protocol not supported"}, + {121, "ESOCKTNOSUPPORT", "socket type not supported"}, + {122, "ENOTSUP", "operation not supported"}, + {123, "EPFNOSUPPORT", "protocol family not supported"}, + {124, "EAFNOSUPPORT", "address family not supported by protocol"}, + {125, "EADDRINUSE", "address already in use"}, + {126, "EADDRNOTAVAIL", "cannot assign requested address"}, + {127, "ENETDOWN", "network is down"}, + {128, "ENETUNREACH", "network is unreachable"}, + {129, "ENETRESET", "network dropped connection on reset"}, + {130, "ECONNABORTED", "software caused connection abort"}, + {131, "ECONNRESET", "connection reset by peer"}, + {132, "ENOBUFS", "no buffer space available"}, + {133, "EISCONN", "transport endpoint is already connected"}, + {134, "ENOTCONN", "transport endpoint is not connected"}, + {135, "EUCLEAN", "structure needs cleaning"}, + {137, "ENOTNAM", "not a XENIX named type file"}, + {138, "ENAVAIL", "no XENIX semaphores available"}, + {139, "EISNAM", "is a named type file"}, + {140, "EREMOTEIO", "remote I/O error"}, + {141, "EINIT", "unknown error 141"}, + {142, "EREMDEV", "unknown error 142"}, + {143, "ESHUTDOWN", "cannot send after transport endpoint shutdown"}, + {144, "ETOOMANYREFS", "too many references: cannot splice"}, + {145, "ETIMEDOUT", "connection timed out"}, + {146, "ECONNREFUSED", "connection refused"}, + {147, "EHOSTDOWN", "host is down"}, + {148, "EHOSTUNREACH", "no route to host"}, + {149, "EALREADY", "operation already in progress"}, + {150, "EINPROGRESS", "operation now in progress"}, + {151, "ESTALE", "stale file handle"}, + {158, "ECANCELED", "operation canceled"}, + {159, "ENOMEDIUM", "no medium found"}, + {160, "EMEDIUMTYPE", "wrong medium type"}, + {161, "ENOKEY", "required key not available"}, + {162, "EKEYEXPIRED", "key has expired"}, + {163, "EKEYREVOKED", "key has been revoked"}, + {164, "EKEYREJECTED", "key was rejected by service"}, + {165, "EOWNERDEAD", "owner died"}, + {166, "ENOTRECOVERABLE", "state not recoverable"}, + {167, "ERFKILL", "operation not possible due to RF-kill"}, + {168, "EHWPOISON", "memory page has hardware error"}, + {1133, "EDQUOT", "disk quota exceeded"}, } // Signal table -var signals = [...]string{ - 1: "hangup", - 2: "interrupt", - 3: "quit", - 4: "illegal instruction", - 5: "trace/breakpoint trap", - 6: "aborted", - 7: "EMT trap", - 8: "floating point exception", - 9: "killed", - 10: "bus error", - 11: "segmentation fault", - 12: "bad system call", - 13: "broken pipe", - 14: "alarm clock", - 15: "terminated", - 16: "user defined signal 1", - 17: "user defined signal 2", - 18: "child exited", - 19: "power failure", - 20: "window changed", - 21: "urgent I/O condition", - 22: "I/O possible", - 23: "stopped (signal)", - 24: "stopped", - 25: "continued", - 26: "stopped (tty input)", - 27: "stopped (tty output)", - 28: "virtual timer expired", - 29: "profiling timer expired", - 30: "CPU time limit exceeded", - 31: "file size limit exceeded", +var signalList = [...]struct { + num syscall.Signal + name string + desc string +}{ + {1, "SIGHUP", "hangup"}, + {2, "SIGINT", "interrupt"}, + {3, "SIGQUIT", "quit"}, + {4, "SIGILL", "illegal instruction"}, + {5, "SIGTRAP", "trace/breakpoint trap"}, + {6, "SIGABRT", "aborted"}, + {7, "SIGEMT", "EMT trap"}, + {8, "SIGFPE", "floating point exception"}, + {9, "SIGKILL", "killed"}, + {10, "SIGBUS", "bus error"}, + {11, "SIGSEGV", "segmentation fault"}, + {12, "SIGSYS", "bad system call"}, + {13, "SIGPIPE", "broken pipe"}, + {14, "SIGALRM", "alarm clock"}, + {15, "SIGTERM", "terminated"}, + {16, "SIGUSR1", "user defined signal 1"}, + {17, "SIGUSR2", "user defined signal 2"}, + {18, "SIGCHLD", "child exited"}, + {19, "SIGPWR", "power failure"}, + {20, "SIGWINCH", "window changed"}, + {21, "SIGURG", "urgent I/O condition"}, + {22, "SIGIO", "I/O possible"}, + {23, "SIGSTOP", "stopped (signal)"}, + {24, "SIGTSTP", "stopped"}, + {25, "SIGCONT", "continued"}, + {26, "SIGTTIN", "stopped (tty input)"}, + {27, "SIGTTOU", "stopped (tty output)"}, + {28, "SIGVTALRM", "virtual timer expired"}, + {29, "SIGPROF", "profiling timer expired"}, + {30, "SIGXCPU", "CPU time limit exceeded"}, + {31, "SIGXFSZ", "file size limit exceeded"}, } diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go index 62dd20352b..fb82529ac9 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go @@ -3,7 +3,7 @@ // +build mips64,linux -// Created by cgo -godefs - DO NOT EDIT +// Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go package unix @@ -11,6 +11,11 @@ package unix import "syscall" const ( + AAFS_MAGIC = 0x5a3c69f0 + ADFS_SUPER_MAGIC = 0xadf5 + AFFS_SUPER_MAGIC = 0xadff + AFS_FS_MAGIC = 0x6b414653 + AFS_SUPER_MAGIC = 0x5346414f AF_ALG = 0x26 AF_APPLETALK = 0x5 AF_ASH = 0x12 @@ -36,7 +41,7 @@ const ( AF_KEY = 0xf AF_LLC = 0x1a AF_LOCAL = 0x1 - AF_MAX = 0x2c + AF_MAX = 0x2d AF_MPLS = 0x1c AF_NETBEUI = 0xd AF_NETLINK = 0x10 @@ -59,6 +64,7 @@ const ( AF_VSOCK = 0x28 AF_WANPIPE = 0x19 AF_X25 = 0x9 + AF_XDP = 0x2c ALG_OP_DECRYPT = 0x0 ALG_OP_ENCRYPT = 0x1 ALG_SET_AEAD_ASSOCLEN = 0x4 @@ -66,6 +72,7 @@ const ( ALG_SET_IV = 0x2 ALG_SET_KEY = 0x1 ALG_SET_OP = 0x3 + ANON_INODE_FS_MAGIC = 0x9041934 ARPHRD_6LOWPAN = 0x339 ARPHRD_ADAPT = 0x108 ARPHRD_APPLETLK = 0x8 @@ -121,6 +128,7 @@ const ( ARPHRD_PPP = 0x200 ARPHRD_PRONET = 0x4 ARPHRD_RAWHDLC = 0x206 + ARPHRD_RAWIP = 0x207 ARPHRD_ROSE = 0x10e ARPHRD_RSRVD = 0x104 ARPHRD_SIT = 0x308 @@ -132,6 +140,7 @@ const ( ARPHRD_VOID = 0xffff ARPHRD_VSOCKMON = 0x33a ARPHRD_X25 = 0x10f + AUTOFS_SUPER_MAGIC = 0x187 B0 = 0x0 B1000000 = 0x1008 B110 = 0x3 @@ -163,6 +172,9 @@ const ( B75 = 0x2 B921600 = 0x1007 B9600 = 0xd + BALLOON_KVM_MAGIC = 0x13661366 + BDEVFS_MAGIC = 0x62646576 + BINFMTFS_MAGIC = 0x42494e4d BLKBSZGET = 0x40081270 BLKBSZSET = 0x80081271 BLKFLSBUF = 0x20001261 @@ -187,6 +199,7 @@ const ( BPF_AND = 0x50 BPF_B = 0x10 BPF_DIV = 0x30 + BPF_FS_MAGIC = 0xcafe4a11 BPF_H = 0x8 BPF_IMM = 0x0 BPF_IND = 0x40 @@ -228,6 +241,8 @@ const ( BS0 = 0x0 BS1 = 0x2000 BSDLY = 0x2000 + BTRFS_SUPER_MAGIC = 0x9123683e + BTRFS_TEST_MAGIC = 0x73727279 CAN_BCM = 0x2 CAN_EFF_FLAG = 0x80000000 CAN_EFF_ID_BITS = 0x1d @@ -251,6 +266,8 @@ const ( CBAUD = 0x100f CBAUDEX = 0x1000 CFLUSH = 0xf + CGROUP2_SUPER_MAGIC = 0x63677270 + CGROUP_SUPER_MAGIC = 0x27e0eb CIBAUD = 0x100f0000 CLOCAL = 0x800 CLOCK_BOOTTIME = 0x7 @@ -293,10 +310,12 @@ const ( CLONE_VFORK = 0x4000 CLONE_VM = 0x100 CMSPAR = 0x40000000 + CODA_SUPER_MAGIC = 0x73757245 CR0 = 0x0 CR1 = 0x200 CR2 = 0x400 CR3 = 0x600 + CRAMFS_MAGIC = 0x28cd3d45 CRDLY = 0x600 CREAD = 0x80 CRTSCTS = 0x80000000 @@ -311,6 +330,9 @@ const ( CSTOP = 0x13 CSTOPB = 0x40 CSUSP = 0x1a + DAXFS_MAGIC = 0x64646178 + DEBUGFS_MAGIC = 0x64626720 + DEVPTS_SUPER_MAGIC = 0x1cd1 DT_BLK = 0x6 DT_CHR = 0x2 DT_DIR = 0x4 @@ -327,9 +349,12 @@ const ( ECHOKE = 0x800 ECHONL = 0x40 ECHOPRT = 0x400 + ECRYPTFS_SUPER_MAGIC = 0xf15f EFD_CLOEXEC = 0x80000 EFD_NONBLOCK = 0x80 EFD_SEMAPHORE = 0x1 + EFIVARFS_MAGIC = 0xde5e81e4 + EFS_SUPER_MAGIC = 0x414a53 ENCODING_DEFAULT = 0x0 ENCODING_FM_MARK = 0x3 ENCODING_FM_SPACE = 0x4 @@ -390,6 +415,8 @@ const ( ETH_P_DSA = 0x1b ETH_P_ECONET = 0x18 ETH_P_EDSA = 0xdada + ETH_P_ERSPAN = 0x88be + ETH_P_ERSPAN2 = 0x22eb ETH_P_FCOE = 0x8906 ETH_P_FIP = 0x8914 ETH_P_HDLC = 0x19 @@ -398,6 +425,7 @@ const ( ETH_P_IEEE802154 = 0xf6 ETH_P_IEEEPUP = 0xa00 ETH_P_IEEEPUPAT = 0xa01 + ETH_P_IFE = 0xed3e ETH_P_IP = 0x800 ETH_P_IPV6 = 0x86dd ETH_P_IPX = 0x8137 @@ -408,11 +436,13 @@ const ( ETH_P_LOOP = 0x60 ETH_P_LOOPBACK = 0x9000 ETH_P_MACSEC = 0x88e5 + ETH_P_MAP = 0xf9 ETH_P_MOBITEX = 0x15 ETH_P_MPLS_MC = 0x8848 ETH_P_MPLS_UC = 0x8847 ETH_P_MVRP = 0x88f5 ETH_P_NCSI = 0x88f8 + ETH_P_NSH = 0x894f ETH_P_PAE = 0x888e ETH_P_PAUSE = 0x8808 ETH_P_PHONET = 0xf5 @@ -420,6 +450,7 @@ const ( ETH_P_PPP_DISC = 0x8863 ETH_P_PPP_MP = 0x8 ETH_P_PPP_SES = 0x8864 + ETH_P_PREAUTH = 0x88c7 ETH_P_PRP = 0x88fb ETH_P_PUP = 0x200 ETH_P_PUPAT = 0x201 @@ -440,9 +471,14 @@ const ( ETH_P_WCCP = 0x883e ETH_P_X25 = 0x805 ETH_P_XDSA = 0xf8 + EXABYTE_ENABLE_NEST = 0xf0 + EXT2_SUPER_MAGIC = 0xef53 + EXT3_SUPER_MAGIC = 0xef53 + EXT4_SUPER_MAGIC = 0xef53 EXTA = 0xe EXTB = 0xf EXTPROC = 0x10000 + F2FS_SUPER_MAGIC = 0xf2f52010 FALLOC_FL_COLLAPSE_RANGE = 0x8 FALLOC_FL_INSERT_RANGE = 0x20 FALLOC_FL_KEEP_SIZE = 0x1 @@ -463,6 +499,8 @@ const ( FS_ENCRYPTION_MODE_AES_256_GCM = 0x2 FS_ENCRYPTION_MODE_AES_256_XTS = 0x1 FS_ENCRYPTION_MODE_INVALID = 0x0 + FS_ENCRYPTION_MODE_SPECK128_256_CTS = 0x8 + FS_ENCRYPTION_MODE_SPECK128_256_XTS = 0x7 FS_IOC_GET_ENCRYPTION_POLICY = 0x800c6615 FS_IOC_GET_ENCRYPTION_PWSALT = 0x80106614 FS_IOC_SET_ENCRYPTION_POLICY = 0x400c6613 @@ -476,6 +514,8 @@ const ( FS_POLICY_FLAGS_PAD_8 = 0x1 FS_POLICY_FLAGS_PAD_MASK = 0x3 FS_POLICY_FLAGS_VALID = 0x3 + FUTEXFS_SUPER_MAGIC = 0xbad1dea + F_ADD_SEALS = 0x409 F_DUPFD = 0x0 F_DUPFD_CLOEXEC = 0x406 F_EXLCK = 0x4 @@ -488,6 +528,9 @@ const ( F_GETOWN_EX = 0x10 F_GETPIPE_SZ = 0x408 F_GETSIG = 0xb + F_GET_FILE_RW_HINT = 0x40d + F_GET_RW_HINT = 0x40b + F_GET_SEALS = 0x40a F_LOCK = 0x1 F_NOTIFY = 0x402 F_OFD_GETLK = 0x24 @@ -495,6 +538,10 @@ const ( F_OFD_SETLKW = 0x26 F_OK = 0x0 F_RDLCK = 0x0 + F_SEAL_GROW = 0x4 + F_SEAL_SEAL = 0x1 + F_SEAL_SHRINK = 0x2 + F_SEAL_WRITE = 0x8 F_SETFD = 0x2 F_SETFL = 0x4 F_SETLEASE = 0x400 @@ -506,6 +553,8 @@ const ( F_SETOWN_EX = 0xf F_SETPIPE_SZ = 0x407 F_SETSIG = 0xa + F_SET_FILE_RW_HINT = 0x40e + F_SET_RW_HINT = 0x40c F_SHLCK = 0x8 F_TEST = 0x3 F_TLOCK = 0x2 @@ -527,6 +576,49 @@ const ( GENL_UNS_ADMIN_PERM = 0x10 GRND_NONBLOCK = 0x1 GRND_RANDOM = 0x2 + HDIO_DRIVE_CMD = 0x31f + HDIO_DRIVE_CMD_AEB = 0x31e + HDIO_DRIVE_CMD_HDR_SIZE = 0x4 + HDIO_DRIVE_HOB_HDR_SIZE = 0x8 + HDIO_DRIVE_RESET = 0x31c + HDIO_DRIVE_TASK = 0x31e + HDIO_DRIVE_TASKFILE = 0x31d + HDIO_DRIVE_TASK_HDR_SIZE = 0x8 + HDIO_GETGEO = 0x301 + HDIO_GET_32BIT = 0x309 + HDIO_GET_ACOUSTIC = 0x30f + HDIO_GET_ADDRESS = 0x310 + HDIO_GET_BUSSTATE = 0x31a + HDIO_GET_DMA = 0x30b + HDIO_GET_IDENTITY = 0x30d + HDIO_GET_KEEPSETTINGS = 0x308 + HDIO_GET_MULTCOUNT = 0x304 + HDIO_GET_NICE = 0x30c + HDIO_GET_NOWERR = 0x30a + HDIO_GET_QDMA = 0x305 + HDIO_GET_UNMASKINTR = 0x302 + HDIO_GET_WCACHE = 0x30e + HDIO_OBSOLETE_IDENTITY = 0x307 + HDIO_SCAN_HWIF = 0x328 + HDIO_SET_32BIT = 0x324 + HDIO_SET_ACOUSTIC = 0x32c + HDIO_SET_ADDRESS = 0x32f + HDIO_SET_BUSSTATE = 0x32d + HDIO_SET_DMA = 0x326 + HDIO_SET_KEEPSETTINGS = 0x323 + HDIO_SET_MULTCOUNT = 0x321 + HDIO_SET_NICE = 0x329 + HDIO_SET_NOWERR = 0x325 + HDIO_SET_PIO_MODE = 0x327 + HDIO_SET_QDMA = 0x32e + HDIO_SET_UNMASKINTR = 0x322 + HDIO_SET_WCACHE = 0x32b + HDIO_SET_XFER = 0x306 + HDIO_TRISTATE_HWIF = 0x31b + HDIO_UNREGISTER_HWIF = 0x32a + HOSTFS_SUPER_MAGIC = 0xc0ffee + HPFS_SUPER_MAGIC = 0xf995e849 + HUGETLBFS_MAGIC = 0x958458f6 HUPCL = 0x400 IBSHIFT = 0x10 ICANON = 0x2 @@ -546,7 +638,7 @@ const ( IFA_F_STABLE_PRIVACY = 0x800 IFA_F_TEMPORARY = 0x1 IFA_F_TENTATIVE = 0x40 - IFA_MAX = 0x8 + IFA_MAX = 0xa IFF_ALLMULTI = 0x200 IFF_ATTACH_QUEUE = 0x200 IFF_AUTOMEDIA = 0x4000 @@ -561,6 +653,8 @@ const ( IFF_MASTER = 0x400 IFF_MULTICAST = 0x1000 IFF_MULTI_QUEUE = 0x100 + IFF_NAPI = 0x10 + IFF_NAPI_FRAGS = 0x20 IFF_NOARP = 0x80 IFF_NOFILTER = 0x1000 IFF_NOTRAILERS = 0x20 @@ -612,6 +706,7 @@ const ( IN_ISDIR = 0x40000000 IN_LOOPBACKNET = 0x7f IN_MASK_ADD = 0x20000000 + IN_MASK_CREATE = 0x10000000 IN_MODIFY = 0x2 IN_MOVE = 0xc0 IN_MOVED_FROM = 0x40 @@ -671,6 +766,7 @@ const ( IPV6_DONTFRAG = 0x3e IPV6_DROP_MEMBERSHIP = 0x15 IPV6_DSTOPTS = 0x3b + IPV6_FREEBIND = 0x4e IPV6_HDRINCL = 0x24 IPV6_HOPLIMIT = 0x34 IPV6_HOPOPTS = 0x36 @@ -682,6 +778,7 @@ const ( IPV6_MINHOPCOUNT = 0x49 IPV6_MTU = 0x18 IPV6_MTU_DISCOVER = 0x17 + IPV6_MULTICAST_ALL = 0x1d IPV6_MULTICAST_HOPS = 0x12 IPV6_MULTICAST_IF = 0x11 IPV6_MULTICAST_LOOP = 0x13 @@ -775,12 +872,34 @@ const ( IP_UNICAST_IF = 0x32 IP_XFRM_POLICY = 0x11 ISIG = 0x1 + ISOFS_SUPER_MAGIC = 0x9660 ISTRIP = 0x20 IUCLC = 0x200 IUTF8 = 0x4000 IXANY = 0x800 IXOFF = 0x1000 IXON = 0x400 + JFFS2_SUPER_MAGIC = 0x72b6 + KEXEC_ARCH_386 = 0x30000 + KEXEC_ARCH_68K = 0x40000 + KEXEC_ARCH_AARCH64 = 0xb70000 + KEXEC_ARCH_ARM = 0x280000 + KEXEC_ARCH_DEFAULT = 0x0 + KEXEC_ARCH_IA_64 = 0x320000 + KEXEC_ARCH_MASK = 0xffff0000 + KEXEC_ARCH_MIPS = 0x80000 + KEXEC_ARCH_MIPS_LE = 0xa0000 + KEXEC_ARCH_PPC = 0x140000 + KEXEC_ARCH_PPC64 = 0x150000 + KEXEC_ARCH_S390 = 0x160000 + KEXEC_ARCH_SH = 0x2a0000 + KEXEC_ARCH_X86_64 = 0x3e0000 + KEXEC_FILE_NO_INITRAMFS = 0x4 + KEXEC_FILE_ON_CRASH = 0x2 + KEXEC_FILE_UNLOAD = 0x1 + KEXEC_ON_CRASH = 0x1 + KEXEC_PRESERVE_CONTEXT = 0x2 + KEXEC_SEGMENT_MAX = 0x10 KEYCTL_ASSUME_AUTHORITY = 0x10 KEYCTL_CHOWN = 0x4 KEYCTL_CLEAR = 0x7 @@ -795,6 +914,11 @@ const ( KEYCTL_JOIN_SESSION_KEYRING = 0x1 KEYCTL_LINK = 0x8 KEYCTL_NEGATE = 0xd + KEYCTL_PKEY_DECRYPT = 0x1a + KEYCTL_PKEY_ENCRYPT = 0x19 + KEYCTL_PKEY_QUERY = 0x18 + KEYCTL_PKEY_SIGN = 0x1b + KEYCTL_PKEY_VERIFY = 0x1c KEYCTL_READ = 0xb KEYCTL_REJECT = 0x13 KEYCTL_RESTRICT_KEYRING = 0x1d @@ -804,6 +928,10 @@ const ( KEYCTL_SETPERM = 0x5 KEYCTL_SET_REQKEY_KEYRING = 0xe KEYCTL_SET_TIMEOUT = 0xf + KEYCTL_SUPPORTS_DECRYPT = 0x2 + KEYCTL_SUPPORTS_ENCRYPT = 0x1 + KEYCTL_SUPPORTS_SIGN = 0x4 + KEYCTL_SUPPORTS_VERIFY = 0x8 KEYCTL_UNLINK = 0x9 KEYCTL_UPDATE = 0x2 KEY_REQKEY_DEFL_DEFAULT = 0x0 @@ -845,6 +973,7 @@ const ( MADV_FREE = 0x8 MADV_HUGEPAGE = 0xe MADV_HWPOISON = 0x64 + MADV_KEEPONFORK = 0x13 MADV_MERGEABLE = 0xc MADV_NOHUGEPAGE = 0xf MADV_NORMAL = 0x0 @@ -853,12 +982,14 @@ const ( MADV_SEQUENTIAL = 0x2 MADV_UNMERGEABLE = 0xd MADV_WILLNEED = 0x3 + MADV_WIPEONFORK = 0x12 MAP_ANON = 0x800 MAP_ANONYMOUS = 0x800 MAP_DENYWRITE = 0x2000 MAP_EXECUTABLE = 0x4000 MAP_FILE = 0x0 MAP_FIXED = 0x10 + MAP_FIXED_NOREPLACE = 0x100000 MAP_GROWSDOWN = 0x1000 MAP_HUGETLB = 0x80000 MAP_HUGE_MASK = 0x3f @@ -870,14 +1001,40 @@ const ( MAP_PRIVATE = 0x2 MAP_RENAME = 0x800 MAP_SHARED = 0x1 + MAP_SHARED_VALIDATE = 0x3 MAP_STACK = 0x40000 MAP_TYPE = 0xf MCL_CURRENT = 0x1 MCL_FUTURE = 0x2 MCL_ONFAULT = 0x4 + MFD_ALLOW_SEALING = 0x2 + MFD_CLOEXEC = 0x1 + MFD_HUGETLB = 0x4 + MFD_HUGE_16GB = -0x78000000 + MFD_HUGE_16MB = 0x60000000 + MFD_HUGE_1GB = 0x78000000 + MFD_HUGE_1MB = 0x50000000 + MFD_HUGE_256MB = 0x70000000 + MFD_HUGE_2GB = 0x7c000000 + MFD_HUGE_2MB = 0x54000000 + MFD_HUGE_32MB = 0x64000000 + MFD_HUGE_512KB = 0x4c000000 + MFD_HUGE_512MB = 0x74000000 + MFD_HUGE_64KB = 0x40000000 + MFD_HUGE_8MB = 0x5c000000 + MFD_HUGE_MASK = 0x3f + MFD_HUGE_SHIFT = 0x1a + MINIX2_SUPER_MAGIC = 0x2468 + MINIX2_SUPER_MAGIC2 = 0x2478 + MINIX3_SUPER_MAGIC = 0x4d5a + MINIX_SUPER_MAGIC = 0x137f + MINIX_SUPER_MAGIC2 = 0x138f MNT_DETACH = 0x2 MNT_EXPIRE = 0x4 MNT_FORCE = 0x1 + MODULE_INIT_IGNORE_MODVERSIONS = 0x1 + MODULE_INIT_IGNORE_VERMAGIC = 0x2 + MSDOS_SUPER_MAGIC = 0x4d44 MSG_BATCH = 0x40000 MSG_CMSG_CLOEXEC = 0x40000000 MSG_CONFIRM = 0x800 @@ -899,6 +1056,7 @@ const ( MSG_TRYHARD = 0x4 MSG_WAITALL = 0x100 MSG_WAITFORONE = 0x10000 + MSG_ZEROCOPY = 0x4000000 MS_ACTIVE = 0x40000000 MS_ASYNC = 0x1 MS_BIND = 0x1000 @@ -936,7 +1094,9 @@ const ( MS_SYNCHRONOUS = 0x10 MS_UNBINDABLE = 0x20000 MS_VERBOSE = 0x8000 + MTD_INODE_FS_MAGIC = 0x11307854 NAME_MAX = 0xff + NCP_SUPER_MAGIC = 0x564c NETLINK_ADD_MEMBERSHIP = 0x1 NETLINK_AUDIT = 0x9 NETLINK_BROADCAST_ERROR = 0x4 @@ -950,6 +1110,7 @@ const ( NETLINK_FIB_LOOKUP = 0xa NETLINK_FIREWALL = 0x3 NETLINK_GENERIC = 0x10 + NETLINK_GET_STRICT_CHK = 0xc NETLINK_INET_DIAG = 0x4 NETLINK_IP6_FW = 0xd NETLINK_ISCSI = 0x8 @@ -971,6 +1132,39 @@ const ( NETLINK_UNUSED = 0x1 NETLINK_USERSOCK = 0x2 NETLINK_XFRM = 0x6 + NETNSA_MAX = 0x3 + NETNSA_NSID_NOT_ASSIGNED = -0x1 + NFNETLINK_V0 = 0x0 + NFNLGRP_ACCT_QUOTA = 0x8 + NFNLGRP_CONNTRACK_DESTROY = 0x3 + NFNLGRP_CONNTRACK_EXP_DESTROY = 0x6 + NFNLGRP_CONNTRACK_EXP_NEW = 0x4 + NFNLGRP_CONNTRACK_EXP_UPDATE = 0x5 + NFNLGRP_CONNTRACK_NEW = 0x1 + NFNLGRP_CONNTRACK_UPDATE = 0x2 + NFNLGRP_MAX = 0x9 + NFNLGRP_NFTABLES = 0x7 + NFNLGRP_NFTRACE = 0x9 + NFNLGRP_NONE = 0x0 + NFNL_BATCH_MAX = 0x1 + NFNL_MSG_BATCH_BEGIN = 0x10 + NFNL_MSG_BATCH_END = 0x11 + NFNL_NFA_NEST = 0x8000 + NFNL_SUBSYS_ACCT = 0x7 + NFNL_SUBSYS_COUNT = 0xc + NFNL_SUBSYS_CTHELPER = 0x9 + NFNL_SUBSYS_CTNETLINK = 0x1 + NFNL_SUBSYS_CTNETLINK_EXP = 0x2 + NFNL_SUBSYS_CTNETLINK_TIMEOUT = 0x8 + NFNL_SUBSYS_IPSET = 0x6 + NFNL_SUBSYS_NFTABLES = 0xa + NFNL_SUBSYS_NFT_COMPAT = 0xb + NFNL_SUBSYS_NONE = 0x0 + NFNL_SUBSYS_OSF = 0x5 + NFNL_SUBSYS_QUEUE = 0x3 + NFNL_SUBSYS_ULOG = 0x4 + NFS_SUPER_MAGIC = 0x6969 + NILFS_SUPER_MAGIC = 0x3434 NL0 = 0x0 NL1 = 0x100 NLA_ALIGNTO = 0x4 @@ -998,10 +1192,13 @@ const ( NLM_F_EXCL = 0x200 NLM_F_MATCH = 0x200 NLM_F_MULTI = 0x2 + NLM_F_NONREC = 0x100 NLM_F_REPLACE = 0x100 NLM_F_REQUEST = 0x1 NLM_F_ROOT = 0x100 NOFLSH = 0x80 + NSFS_MAGIC = 0x6e736673 + OCFS2_SUPER_MAGIC = 0x7461636f OCRNL = 0x8 OFDEL = 0x80 OFILL = 0x40 @@ -1009,7 +1206,9 @@ const ( ONLCR = 0x4 ONLRET = 0x20 ONOCR = 0x10 + OPENPROM_SUPER_MAGIC = 0x9fa1 OPOST = 0x1 + OVERLAYFS_SUPER_MAGIC = 0x794c7630 O_ACCMODE = 0x3 O_APPEND = 0x8 O_ASYNC = 0x1000 @@ -1055,6 +1254,7 @@ const ( PACKET_FASTROUTE = 0x6 PACKET_HDRLEN = 0xb PACKET_HOST = 0x0 + PACKET_IGNORE_OUTGOING = 0x17 PACKET_KERNEL = 0x7 PACKET_LOOPBACK = 0x5 PACKET_LOSS = 0xe @@ -1094,16 +1294,50 @@ const ( PERF_EVENT_IOC_DISABLE = 0x20002401 PERF_EVENT_IOC_ENABLE = 0x20002400 PERF_EVENT_IOC_ID = 0x40082407 + PERF_EVENT_IOC_MODIFY_ATTRIBUTES = 0x8008240b PERF_EVENT_IOC_PAUSE_OUTPUT = 0x80042409 PERF_EVENT_IOC_PERIOD = 0x80082404 + PERF_EVENT_IOC_QUERY_BPF = 0xc008240a PERF_EVENT_IOC_REFRESH = 0x20002402 PERF_EVENT_IOC_RESET = 0x20002403 PERF_EVENT_IOC_SET_BPF = 0x80042408 PERF_EVENT_IOC_SET_FILTER = 0x80082406 PERF_EVENT_IOC_SET_OUTPUT = 0x20002405 + PIPEFS_MAGIC = 0x50495045 + PPPIOCATTACH = 0x8004743d + PPPIOCATTCHAN = 0x80047438 + PPPIOCCONNECT = 0x8004743a + PPPIOCDETACH = 0x8004743c + PPPIOCDISCONN = 0x20007439 + PPPIOCGASYNCMAP = 0x40047458 + PPPIOCGCHAN = 0x40047437 + PPPIOCGDEBUG = 0x40047441 + PPPIOCGFLAGS = 0x4004745a + PPPIOCGIDLE = 0x4010743f + PPPIOCGL2TPSTATS = 0x40487436 + PPPIOCGMRU = 0x40047453 + PPPIOCGNPMODE = 0xc008744c + PPPIOCGRASYNCMAP = 0x40047455 + PPPIOCGUNIT = 0x40047456 + PPPIOCGXASYNCMAP = 0x40207450 + PPPIOCNEWUNIT = 0xc004743e + PPPIOCSACTIVE = 0x80107446 + PPPIOCSASYNCMAP = 0x80047457 + PPPIOCSCOMPRESS = 0x8010744d + PPPIOCSDEBUG = 0x80047440 + PPPIOCSFLAGS = 0x80047459 + PPPIOCSMAXCID = 0x80047451 + PPPIOCSMRRU = 0x8004743b + PPPIOCSMRU = 0x80047452 + PPPIOCSNPMODE = 0x8008744b + PPPIOCSPASS = 0x80107447 + PPPIOCSRASYNCMAP = 0x80047454 + PPPIOCSXASYNCMAP = 0x8020744f + PPPIOCXFERUNIT = 0x2000744e PRIO_PGRP = 0x1 PRIO_PROCESS = 0x0 PRIO_USER = 0x2 + PROC_SUPER_MAGIC = 0x9fa0 PROT_EXEC = 0x4 PROT_GROWSDOWN = 0x1000000 PROT_GROWSUP = 0x2000000 @@ -1146,6 +1380,7 @@ const ( PR_GET_PDEATHSIG = 0x2 PR_GET_SECCOMP = 0x15 PR_GET_SECUREBITS = 0x1b + PR_GET_SPECULATION_CTRL = 0x34 PR_GET_THP_DISABLE = 0x2a PR_GET_TID_ADDRESS = 0x28 PR_GET_TIMERSLACK = 0x1e @@ -1191,11 +1426,24 @@ const ( PR_SET_PTRACER_ANY = 0xffffffffffffffff PR_SET_SECCOMP = 0x16 PR_SET_SECUREBITS = 0x1c + PR_SET_SPECULATION_CTRL = 0x35 PR_SET_THP_DISABLE = 0x29 PR_SET_TIMERSLACK = 0x1d PR_SET_TIMING = 0xe PR_SET_TSC = 0x1a PR_SET_UNALIGN = 0x6 + PR_SPEC_DISABLE = 0x4 + PR_SPEC_ENABLE = 0x2 + PR_SPEC_FORCE_DISABLE = 0x8 + PR_SPEC_INDIRECT_BRANCH = 0x1 + PR_SPEC_NOT_AFFECTED = 0x0 + PR_SPEC_PRCTL = 0x1 + PR_SPEC_STORE_BYPASS = 0x0 + PR_SVE_GET_VL = 0x33 + PR_SVE_SET_VL = 0x32 + PR_SVE_SET_VL_ONEXEC = 0x40000 + PR_SVE_VL_INHERIT = 0x20000 + PR_SVE_VL_LEN_MASK = 0xffff PR_TASK_PERF_EVENTS_DISABLE = 0x1f PR_TASK_PERF_EVENTS_ENABLE = 0x20 PR_TIMING_STATISTICAL = 0x0 @@ -1204,6 +1452,7 @@ const ( PR_TSC_SIGSEGV = 0x2 PR_UNALIGN_NOPRINT = 0x1 PR_UNALIGN_SIGBUS = 0x2 + PSTOREFS_MAGIC = 0x6165676c PTRACE_ATTACH = 0x10 PTRACE_CONT = 0x7 PTRACE_DETACH = 0x11 @@ -1252,6 +1501,7 @@ const ( PTRACE_POKETEXT_3264 = 0xc2 PTRACE_POKEUSR = 0x6 PTRACE_SECCOMP_GET_FILTER = 0x420c + PTRACE_SECCOMP_GET_METADATA = 0x420d PTRACE_SEIZE = 0x4206 PTRACE_SETFPREGS = 0xf PTRACE_SETOPTIONS = 0x4200 @@ -1264,6 +1514,14 @@ const ( PTRACE_SINGLESTEP = 0x9 PTRACE_SYSCALL = 0x18 PTRACE_TRACEME = 0x0 + QNX4_SUPER_MAGIC = 0x2f + QNX6_SUPER_MAGIC = 0x68191122 + RAMFS_MAGIC = 0x858458f6 + RDTGROUP_SUPER_MAGIC = 0x7655821 + REISERFS_SUPER_MAGIC = 0x52654973 + RENAME_EXCHANGE = 0x2 + RENAME_NOREPLACE = 0x1 + RENAME_WHITEOUT = 0x4 RLIMIT_AS = 0x6 RLIMIT_CORE = 0x4 RLIMIT_CPU = 0x0 @@ -1281,9 +1539,17 @@ const ( RLIMIT_SIGPENDING = 0xb RLIMIT_STACK = 0x3 RLIM_INFINITY = 0xffffffffffffffff + RNDADDENTROPY = 0x80085203 + RNDADDTOENTCNT = 0x80045201 + RNDCLEARPOOL = 0x20005206 + RNDGETENTCNT = 0x40045200 + RNDGETPOOL = 0x40085202 + RNDRESEEDCRNG = 0x20005207 + RNDZAPENTCNT = 0x20005204 RTAX_ADVMSS = 0x8 RTAX_CC_ALGO = 0x10 RTAX_CWND = 0x7 + RTAX_FASTOPEN_NO_COOKIE = 0x11 RTAX_FEATURES = 0xc RTAX_FEATURE_ALLFRAG = 0x8 RTAX_FEATURE_ECN = 0x1 @@ -1294,7 +1560,7 @@ const ( RTAX_INITCWND = 0xb RTAX_INITRWND = 0xe RTAX_LOCK = 0x1 - RTAX_MAX = 0x10 + RTAX_MAX = 0x11 RTAX_MTU = 0x2 RTAX_QUICKACK = 0xf RTAX_REORDERING = 0x9 @@ -1305,13 +1571,40 @@ const ( RTAX_UNSPEC = 0x0 RTAX_WINDOW = 0x3 RTA_ALIGNTO = 0x4 - RTA_MAX = 0x1a + RTA_MAX = 0x1d RTCF_DIRECTSRC = 0x4000000 RTCF_DOREDIRECT = 0x1000000 RTCF_LOG = 0x2000000 RTCF_MASQ = 0x400000 RTCF_NAT = 0x800000 RTCF_VALVE = 0x200000 + RTC_AF = 0x20 + RTC_AIE_OFF = 0x20007002 + RTC_AIE_ON = 0x20007001 + RTC_ALM_READ = 0x40247008 + RTC_ALM_SET = 0x80247007 + RTC_EPOCH_READ = 0x4008700d + RTC_EPOCH_SET = 0x8008700e + RTC_IRQF = 0x80 + RTC_IRQP_READ = 0x4008700b + RTC_IRQP_SET = 0x8008700c + RTC_MAX_FREQ = 0x2000 + RTC_PF = 0x40 + RTC_PIE_OFF = 0x20007006 + RTC_PIE_ON = 0x20007005 + RTC_PLL_GET = 0x40207011 + RTC_PLL_SET = 0x80207012 + RTC_RD_TIME = 0x40247009 + RTC_SET_TIME = 0x8024700a + RTC_UF = 0x10 + RTC_UIE_OFF = 0x20007004 + RTC_UIE_ON = 0x20007003 + RTC_VL_CLR = 0x20007014 + RTC_VL_READ = 0x40047013 + RTC_WIE_OFF = 0x20007010 + RTC_WIE_ON = 0x2000700f + RTC_WKALM_RD = 0x40287010 + RTC_WKALM_SET = 0x8028700f RTF_ADDRCLASSMASK = 0xf8000000 RTF_ADDRCONF = 0x40000 RTF_ALLONLINK = 0x20000 @@ -1346,6 +1639,7 @@ const ( RTM_DELACTION = 0x31 RTM_DELADDR = 0x15 RTM_DELADDRLABEL = 0x49 + RTM_DELCHAIN = 0x65 RTM_DELLINK = 0x11 RTM_DELMDB = 0x55 RTM_DELNEIGH = 0x1d @@ -1366,6 +1660,7 @@ const ( RTM_GETADDR = 0x16 RTM_GETADDRLABEL = 0x4a RTM_GETANYCAST = 0x3e + RTM_GETCHAIN = 0x66 RTM_GETDCB = 0x4e RTM_GETLINK = 0x12 RTM_GETMDB = 0x56 @@ -1380,11 +1675,12 @@ const ( RTM_GETSTATS = 0x5e RTM_GETTCLASS = 0x2a RTM_GETTFILTER = 0x2e - RTM_MAX = 0x63 + RTM_MAX = 0x67 RTM_NEWACTION = 0x30 RTM_NEWADDR = 0x14 RTM_NEWADDRLABEL = 0x48 RTM_NEWCACHEREPORT = 0x60 + RTM_NEWCHAIN = 0x64 RTM_NEWLINK = 0x10 RTM_NEWMDB = 0x54 RTM_NEWNDUSEROPT = 0x44 @@ -1399,8 +1695,8 @@ const ( RTM_NEWSTATS = 0x5c RTM_NEWTCLASS = 0x28 RTM_NEWTFILTER = 0x2c - RTM_NR_FAMILIES = 0x15 - RTM_NR_MSGTYPES = 0x54 + RTM_NR_FAMILIES = 0x16 + RTM_NR_MSGTYPES = 0x58 RTM_SETDCB = 0x4f RTM_SETLINK = 0x13 RTM_SETNEIGHTBL = 0x43 @@ -1414,17 +1710,22 @@ const ( RTNH_F_UNRESOLVED = 0x20 RTN_MAX = 0xb RTPROT_BABEL = 0x2a + RTPROT_BGP = 0xba RTPROT_BIRD = 0xc RTPROT_BOOT = 0x3 RTPROT_DHCP = 0x10 RTPROT_DNROUTED = 0xd + RTPROT_EIGRP = 0xc0 RTPROT_GATED = 0x8 + RTPROT_ISIS = 0xbb RTPROT_KERNEL = 0x2 RTPROT_MROUTED = 0x11 RTPROT_MRT = 0xa RTPROT_NTK = 0xf + RTPROT_OSPF = 0xbc RTPROT_RA = 0x9 RTPROT_REDIRECT = 0x1 + RTPROT_RIP = 0xbd RTPROT_STATIC = 0x4 RTPROT_UNSPEC = 0x0 RTPROT_XORP = 0xe @@ -1444,10 +1745,16 @@ const ( SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SC_LOG_FLUSH = 0x100000 SECCOMP_MODE_DISABLED = 0x0 SECCOMP_MODE_FILTER = 0x2 SECCOMP_MODE_STRICT = 0x1 + SECURITYFS_MAGIC = 0x73636673 + SELINUX_MAGIC = 0xf97cff8c + SFD_CLOEXEC = 0x80000 + SFD_NONBLOCK = 0x80 SHUT_RD = 0x0 SHUT_RDWR = 0x2 SHUT_WR = 0x1 @@ -1498,6 +1805,9 @@ const ( SIOCGMIIPHY = 0x8947 SIOCGMIIREG = 0x8948 SIOCGPGRP = 0x40047309 + SIOCGPPPCSTATS = 0x89f2 + SIOCGPPPSTATS = 0x89f0 + SIOCGPPPVER = 0x89f1 SIOCGRARP = 0x8961 SIOCGSKNS = 0x894c SIOCGSTAMP = 0x8906 @@ -1532,6 +1842,23 @@ const ( SIOCSPGRP = 0x80047308 SIOCSRARP = 0x8962 SIOCWANDEV = 0x894a + SMACK_MAGIC = 0x43415d53 + SMART_AUTOSAVE = 0xd2 + SMART_AUTO_OFFLINE = 0xdb + SMART_DISABLE = 0xd9 + SMART_ENABLE = 0xd8 + SMART_HCYL_PASS = 0xc2 + SMART_IMMEDIATE_OFFLINE = 0xd4 + SMART_LCYL_PASS = 0x4f + SMART_READ_LOG_SECTOR = 0xd5 + SMART_READ_THRESHOLDS = 0xd1 + SMART_READ_VALUES = 0xd0 + SMART_SAVE = 0xd3 + SMART_STATUS = 0xda + SMART_WRITE_LOG_SECTOR = 0xd6 + SMART_WRITE_THRESHOLDS = 0xd7 + SMB_SUPER_MAGIC = 0x517b + SOCKFS_MAGIC = 0x534f434b SOCK_CLOEXEC = 0x80000 SOCK_DCCP = 0x6 SOCK_DGRAM = 0x1 @@ -1568,7 +1895,9 @@ const ( SOL_SOCKET = 0xffff SOL_TCP = 0x6 SOL_TIPC = 0x10f + SOL_TLS = 0x11a SOL_X25 = 0x106 + SOL_XDP = 0x11b SOMAXCONN = 0x80 SO_ACCEPTCONN = 0x1009 SO_ATTACH_BPF = 0x32 @@ -1587,6 +1916,17 @@ const ( SO_DETACH_FILTER = 0x1b SO_DOMAIN = 0x1029 SO_DONTROUTE = 0x10 + SO_EE_CODE_TXTIME_INVALID_PARAM = 0x1 + SO_EE_CODE_TXTIME_MISSED = 0x2 + SO_EE_CODE_ZEROCOPY_COPIED = 0x1 + SO_EE_ORIGIN_ICMP = 0x2 + SO_EE_ORIGIN_ICMP6 = 0x3 + SO_EE_ORIGIN_LOCAL = 0x1 + SO_EE_ORIGIN_NONE = 0x0 + SO_EE_ORIGIN_TIMESTAMPING = 0x4 + SO_EE_ORIGIN_TXSTATUS = 0x4 + SO_EE_ORIGIN_TXTIME = 0x6 + SO_EE_ORIGIN_ZEROCOPY = 0x5 SO_ERROR = 0x1007 SO_GET_FILTER = 0x1a SO_INCOMING_CPU = 0x31 @@ -1628,6 +1968,7 @@ const ( SO_TIMESTAMP = 0x1d SO_TIMESTAMPING = 0x25 SO_TIMESTAMPNS = 0x23 + SO_TXTIME = 0x3d SO_TYPE = 0x1008 SO_VM_SOCKETS_BUFFER_MAX_SIZE = 0x2 SO_VM_SOCKETS_BUFFER_MIN_SIZE = 0x1 @@ -1637,10 +1978,38 @@ const ( SO_VM_SOCKETS_PEER_HOST_VM_ID = 0x3 SO_VM_SOCKETS_TRUSTED = 0x5 SO_WIFI_STATUS = 0x29 + SO_ZEROCOPY = 0x3c SPLICE_F_GIFT = 0x8 SPLICE_F_MORE = 0x4 SPLICE_F_MOVE = 0x1 SPLICE_F_NONBLOCK = 0x2 + SQUASHFS_MAGIC = 0x73717368 + STACK_END_MAGIC = 0x57ac6e9d + STATX_ALL = 0xfff + STATX_ATIME = 0x20 + STATX_ATTR_APPEND = 0x20 + STATX_ATTR_AUTOMOUNT = 0x1000 + STATX_ATTR_COMPRESSED = 0x4 + STATX_ATTR_ENCRYPTED = 0x800 + STATX_ATTR_IMMUTABLE = 0x10 + STATX_ATTR_NODUMP = 0x40 + STATX_BASIC_STATS = 0x7ff + STATX_BLOCKS = 0x400 + STATX_BTIME = 0x800 + STATX_CTIME = 0x80 + STATX_GID = 0x10 + STATX_INO = 0x100 + STATX_MODE = 0x2 + STATX_MTIME = 0x40 + STATX_NLINK = 0x4 + STATX_SIZE = 0x200 + STATX_TYPE = 0x1 + STATX_UID = 0x8 + STATX__RESERVED = 0x80000000 + SYNC_FILE_RANGE_WAIT_AFTER = 0x4 + SYNC_FILE_RANGE_WAIT_BEFORE = 0x1 + SYNC_FILE_RANGE_WRITE = 0x2 + SYSFS_MAGIC = 0x62656572 S_BLKSIZE = 0x200 S_IEXEC = 0x40 S_IFBLK = 0x6000 @@ -1678,7 +2047,7 @@ const ( TASKSTATS_GENL_NAME = "TASKSTATS" TASKSTATS_GENL_VERSION = 0x1 TASKSTATS_TYPE_MAX = 0x6 - TASKSTATS_VERSION = 0x8 + TASKSTATS_VERSION = 0x9 TCFLSH = 0x5407 TCGETA = 0x5401 TCGETS = 0x540d @@ -1691,6 +2060,7 @@ const ( TCOOFF = 0x0 TCOON = 0x1 TCP_CC_INFO = 0x1a + TCP_CM_INQ = 0x24 TCP_CONGESTION = 0xd TCP_COOKIE_IN_ALWAYS = 0x1 TCP_COOKIE_MAX = 0x10 @@ -1702,7 +2072,10 @@ const ( TCP_DEFER_ACCEPT = 0x9 TCP_FASTOPEN = 0x17 TCP_FASTOPEN_CONNECT = 0x1e + TCP_FASTOPEN_KEY = 0x21 + TCP_FASTOPEN_NO_COOKIE = 0x22 TCP_INFO = 0xb + TCP_INQ = 0x24 TCP_KEEPCNT = 0x6 TCP_KEEPIDLE = 0x4 TCP_KEEPINTVL = 0x5 @@ -1711,6 +2084,8 @@ const ( TCP_MAXWIN = 0xffff TCP_MAX_WINSHIFT = 0xe TCP_MD5SIG = 0xe + TCP_MD5SIG_EXT = 0x20 + TCP_MD5SIG_FLAG_PREFIX = 0x1 TCP_MD5SIG_MAXKEYLEN = 0x50 TCP_MSS = 0x200 TCP_MSS_DEFAULT = 0x218 @@ -1720,6 +2095,9 @@ const ( TCP_QUEUE_SEQ = 0x15 TCP_QUICKACK = 0xc TCP_REPAIR = 0x13 + TCP_REPAIR_OFF = 0x0 + TCP_REPAIR_OFF_NO_WP = -0x1 + TCP_REPAIR_ON = 0x1 TCP_REPAIR_OPTIONS = 0x16 TCP_REPAIR_QUEUE = 0x14 TCP_REPAIR_WINDOW = 0x1d @@ -1731,8 +2109,10 @@ const ( TCP_THIN_DUPACK = 0x11 TCP_THIN_LINEAR_TIMEOUTS = 0x10 TCP_TIMESTAMP = 0x18 + TCP_ULP = 0x1f TCP_USER_TIMEOUT = 0x12 TCP_WINDOW_CLAMP = 0xa + TCP_ZEROCOPY_RECEIVE = 0x23 TCSAFLUSH = 0x5410 TCSBRK = 0x5405 TCSBRKP = 0x5486 @@ -1746,6 +2126,7 @@ const ( TCSETSW = 0x540f TCSETSW2 = 0x8030542c TCXONC = 0x5406 + TIMER_ABSTIME = 0x1 TIOCCBRK = 0x5428 TIOCCONS = 0x80047478 TIOCEXCL = 0x740d @@ -1754,6 +2135,7 @@ const ( TIOCGETP = 0x7408 TIOCGEXCL = 0x40045440 TIOCGICOUNT = 0x5492 + TIOCGISO7816 = 0x40285442 TIOCGLCKTRMIOS = 0x548b TIOCGLTC = 0x7474 TIOCGPGRP = 0x40047477 @@ -1810,6 +2192,7 @@ const ( TIOCSETN = 0x740a TIOCSETP = 0x7409 TIOCSIG = 0x80045436 + TIOCSISO7816 = 0xc0285443 TIOCSLCKTRMIOS = 0x548c TIOCSLTC = 0x7475 TIOCSPGRP = 0x80047476 @@ -1820,7 +2203,27 @@ const ( TIOCSTI = 0x5472 TIOCSWINSZ = 0x80087467 TIOCVHANGUP = 0x5437 + TMPFS_MAGIC = 0x1021994 TOSTOP = 0x8000 + TPACKET_ALIGNMENT = 0x10 + TPACKET_HDRLEN = 0x34 + TP_STATUS_AVAILABLE = 0x0 + TP_STATUS_BLK_TMO = 0x20 + TP_STATUS_COPY = 0x2 + TP_STATUS_CSUMNOTREADY = 0x8 + TP_STATUS_CSUM_VALID = 0x80 + TP_STATUS_KERNEL = 0x0 + TP_STATUS_LOSING = 0x4 + TP_STATUS_SENDING = 0x2 + TP_STATUS_SEND_REQUEST = 0x1 + TP_STATUS_TS_RAW_HARDWARE = -0x80000000 + TP_STATUS_TS_SOFTWARE = 0x20000000 + TP_STATUS_TS_SYS_HARDWARE = 0x40000000 + TP_STATUS_USER = 0x1 + TP_STATUS_VLAN_TPID_VALID = 0x40 + TP_STATUS_VLAN_VALID = 0x10 + TP_STATUS_WRONG_FORMAT = 0x4 + TRACEFS_MAGIC = 0x74726163 TS_COMM_LEN = 0x20 TUNATTACHFILTER = 0x801054d5 TUNDETACHFILTER = 0x801054d6 @@ -1832,6 +2235,7 @@ const ( TUNGETVNETHDRSZ = 0x400454d7 TUNGETVNETLE = 0x400454dd TUNSETDEBUG = 0x800454c9 + TUNSETFILTEREBPF = 0x400454e1 TUNSETGROUP = 0x800454ce TUNSETIFF = 0x800454ca TUNSETIFINDEX = 0x800454da @@ -1842,13 +2246,32 @@ const ( TUNSETPERSIST = 0x800454cb TUNSETQUEUE = 0x800454d9 TUNSETSNDBUF = 0x800454d4 + TUNSETSTEERINGEBPF = 0x400454e0 TUNSETTXFILTER = 0x800454d1 TUNSETVNETBE = 0x800454de TUNSETVNETHDRSZ = 0x800454d8 TUNSETVNETLE = 0x800454dc + UBI_IOCATT = 0x80186f40 + UBI_IOCDET = 0x80046f41 + UBI_IOCEBCH = 0x80044f02 + UBI_IOCEBER = 0x80044f01 + UBI_IOCEBISMAP = 0x40044f05 + UBI_IOCEBMAP = 0x80084f03 + UBI_IOCEBUNMAP = 0x80044f04 + UBI_IOCMKVOL = 0x80986f00 + UBI_IOCRMVOL = 0x80046f01 + UBI_IOCRNVOL = 0x91106f03 + UBI_IOCRSVOL = 0x800c6f02 + UBI_IOCSETVOLPROP = 0x80104f06 + UBI_IOCVOLCRBLK = 0x80804f07 + UBI_IOCVOLRMBLK = 0x20004f08 + UBI_IOCVOLUP = 0x80084f00 + UDF_SUPER_MAGIC = 0x15013346 UMOUNT_NOFOLLOW = 0x8 + USBDEVICE_SUPER_MAGIC = 0x9fa2 UTIME_NOW = 0x3fffffff UTIME_OMIT = 0x3ffffffe + V9FS_MAGIC = 0x1021997 VDISCARD = 0xd VEOF = 0x10 VEOL = 0x11 @@ -1891,6 +2314,86 @@ const ( WDIOC_SETPRETIMEOUT = 0xc0045708 WDIOC_SETTIMEOUT = 0xc0045706 WEXITED = 0x4 + WIN_ACKMEDIACHANGE = 0xdb + WIN_CHECKPOWERMODE1 = 0xe5 + WIN_CHECKPOWERMODE2 = 0x98 + WIN_DEVICE_RESET = 0x8 + WIN_DIAGNOSE = 0x90 + WIN_DOORLOCK = 0xde + WIN_DOORUNLOCK = 0xdf + WIN_DOWNLOAD_MICROCODE = 0x92 + WIN_FLUSH_CACHE = 0xe7 + WIN_FLUSH_CACHE_EXT = 0xea + WIN_FORMAT = 0x50 + WIN_GETMEDIASTATUS = 0xda + WIN_IDENTIFY = 0xec + WIN_IDENTIFY_DMA = 0xee + WIN_IDLEIMMEDIATE = 0xe1 + WIN_INIT = 0x60 + WIN_MEDIAEJECT = 0xed + WIN_MULTREAD = 0xc4 + WIN_MULTREAD_EXT = 0x29 + WIN_MULTWRITE = 0xc5 + WIN_MULTWRITE_EXT = 0x39 + WIN_NOP = 0x0 + WIN_PACKETCMD = 0xa0 + WIN_PIDENTIFY = 0xa1 + WIN_POSTBOOT = 0xdc + WIN_PREBOOT = 0xdd + WIN_QUEUED_SERVICE = 0xa2 + WIN_READ = 0x20 + WIN_READDMA = 0xc8 + WIN_READDMA_EXT = 0x25 + WIN_READDMA_ONCE = 0xc9 + WIN_READDMA_QUEUED = 0xc7 + WIN_READDMA_QUEUED_EXT = 0x26 + WIN_READ_BUFFER = 0xe4 + WIN_READ_EXT = 0x24 + WIN_READ_LONG = 0x22 + WIN_READ_LONG_ONCE = 0x23 + WIN_READ_NATIVE_MAX = 0xf8 + WIN_READ_NATIVE_MAX_EXT = 0x27 + WIN_READ_ONCE = 0x21 + WIN_RECAL = 0x10 + WIN_RESTORE = 0x10 + WIN_SECURITY_DISABLE = 0xf6 + WIN_SECURITY_ERASE_PREPARE = 0xf3 + WIN_SECURITY_ERASE_UNIT = 0xf4 + WIN_SECURITY_FREEZE_LOCK = 0xf5 + WIN_SECURITY_SET_PASS = 0xf1 + WIN_SECURITY_UNLOCK = 0xf2 + WIN_SEEK = 0x70 + WIN_SETFEATURES = 0xef + WIN_SETIDLE1 = 0xe3 + WIN_SETIDLE2 = 0x97 + WIN_SETMULT = 0xc6 + WIN_SET_MAX = 0xf9 + WIN_SET_MAX_EXT = 0x37 + WIN_SLEEPNOW1 = 0xe6 + WIN_SLEEPNOW2 = 0x99 + WIN_SMART = 0xb0 + WIN_SPECIFY = 0x91 + WIN_SRST = 0x8 + WIN_STANDBY = 0xe2 + WIN_STANDBY2 = 0x96 + WIN_STANDBYNOW1 = 0xe0 + WIN_STANDBYNOW2 = 0x94 + WIN_VERIFY = 0x40 + WIN_VERIFY_EXT = 0x42 + WIN_VERIFY_ONCE = 0x41 + WIN_WRITE = 0x30 + WIN_WRITEDMA = 0xca + WIN_WRITEDMA_EXT = 0x35 + WIN_WRITEDMA_ONCE = 0xcb + WIN_WRITEDMA_QUEUED = 0xcc + WIN_WRITEDMA_QUEUED_EXT = 0x36 + WIN_WRITE_BUFFER = 0xe8 + WIN_WRITE_EXT = 0x34 + WIN_WRITE_LONG = 0x32 + WIN_WRITE_LONG_ONCE = 0x33 + WIN_WRITE_ONCE = 0x31 + WIN_WRITE_SAME = 0xe9 + WIN_WRITE_VERIFY = 0x3c WNOHANG = 0x1 WNOTHREAD = 0x20000000 WNOWAIT = 0x1000000 @@ -1900,7 +2403,30 @@ const ( XATTR_CREATE = 0x1 XATTR_REPLACE = 0x2 XCASE = 0x4 + XDP_COPY = 0x2 + XDP_FLAGS_DRV_MODE = 0x4 + XDP_FLAGS_HW_MODE = 0x8 + XDP_FLAGS_MASK = 0xf + XDP_FLAGS_MODES = 0xe + XDP_FLAGS_SKB_MODE = 0x2 + XDP_FLAGS_UPDATE_IF_NOEXIST = 0x1 + XDP_MMAP_OFFSETS = 0x1 + XDP_PGOFF_RX_RING = 0x0 + XDP_PGOFF_TX_RING = 0x80000000 + XDP_RX_RING = 0x2 + XDP_SHARED_UMEM = 0x1 + XDP_STATISTICS = 0x7 + XDP_TX_RING = 0x3 + XDP_UMEM_COMPLETION_RING = 0x6 + XDP_UMEM_FILL_RING = 0x5 + XDP_UMEM_PGOFF_COMPLETION_RING = 0x180000000 + XDP_UMEM_PGOFF_FILL_RING = 0x100000000 + XDP_UMEM_REG = 0x4 + XDP_ZEROCOPY = 0x4 + XENFS_SUPER_MAGIC = 0xabba1974 + XFS_SUPER_MAGIC = 0x58465342 XTABS = 0x1800 + ZSMALLOC_MAGIC = 0x58295829 ) // Errors @@ -2082,174 +2608,182 @@ const ( ) // Error table -var errors = [...]string{ - 1: "operation not permitted", - 2: "no such file or directory", - 3: "no such process", - 4: "interrupted system call", - 5: "input/output error", - 6: "no such device or address", - 7: "argument list too long", - 8: "exec format error", - 9: "bad file descriptor", - 10: "no child processes", - 11: "resource temporarily unavailable", - 12: "cannot allocate memory", - 13: "permission denied", - 14: "bad address", - 15: "block device required", - 16: "device or resource busy", - 17: "file exists", - 18: "invalid cross-device link", - 19: "no such device", - 20: "not a directory", - 21: "is a directory", - 22: "invalid argument", - 23: "too many open files in system", - 24: "too many open files", - 25: "inappropriate ioctl for device", - 26: "text file busy", - 27: "file too large", - 28: "no space left on device", - 29: "illegal seek", - 30: "read-only file system", - 31: "too many links", - 32: "broken pipe", - 33: "numerical argument out of domain", - 34: "numerical result out of range", - 35: "no message of desired type", - 36: "identifier removed", - 37: "channel number out of range", - 38: "level 2 not synchronized", - 39: "level 3 halted", - 40: "level 3 reset", - 41: "link number out of range", - 42: "protocol driver not attached", - 43: "no CSI structure available", - 44: "level 2 halted", - 45: "resource deadlock avoided", - 46: "no locks available", - 50: "invalid exchange", - 51: "invalid request descriptor", - 52: "exchange full", - 53: "no anode", - 54: "invalid request code", - 55: "invalid slot", - 56: "file locking deadlock error", - 59: "bad font file format", - 60: "device not a stream", - 61: "no data available", - 62: "timer expired", - 63: "out of streams resources", - 64: "machine is not on the network", - 65: "package not installed", - 66: "object is remote", - 67: "link has been severed", - 68: "advertise error", - 69: "srmount error", - 70: "communication error on send", - 71: "protocol error", - 73: "RFS specific error", - 74: "multihop attempted", - 77: "bad message", - 78: "file name too long", - 79: "value too large for defined data type", - 80: "name not unique on network", - 81: "file descriptor in bad state", - 82: "remote address changed", - 83: "can not access a needed shared library", - 84: "accessing a corrupted shared library", - 85: ".lib section in a.out corrupted", - 86: "attempting to link in too many shared libraries", - 87: "cannot exec a shared library directly", - 88: "invalid or incomplete multibyte or wide character", - 89: "function not implemented", - 90: "too many levels of symbolic links", - 91: "interrupted system call should be restarted", - 92: "streams pipe error", - 93: "directory not empty", - 94: "too many users", - 95: "socket operation on non-socket", - 96: "destination address required", - 97: "message too long", - 98: "protocol wrong type for socket", - 99: "protocol not available", - 120: "protocol not supported", - 121: "socket type not supported", - 122: "operation not supported", - 123: "protocol family not supported", - 124: "address family not supported by protocol", - 125: "address already in use", - 126: "cannot assign requested address", - 127: "network is down", - 128: "network is unreachable", - 129: "network dropped connection on reset", - 130: "software caused connection abort", - 131: "connection reset by peer", - 132: "no buffer space available", - 133: "transport endpoint is already connected", - 134: "transport endpoint is not connected", - 135: "structure needs cleaning", - 137: "not a XENIX named type file", - 138: "no XENIX semaphores available", - 139: "is a named type file", - 140: "remote I/O error", - 141: "unknown error 141", - 142: "unknown error 142", - 143: "cannot send after transport endpoint shutdown", - 144: "too many references: cannot splice", - 145: "connection timed out", - 146: "connection refused", - 147: "host is down", - 148: "no route to host", - 149: "operation already in progress", - 150: "operation now in progress", - 151: "stale file handle", - 158: "operation canceled", - 159: "no medium found", - 160: "wrong medium type", - 161: "required key not available", - 162: "key has expired", - 163: "key has been revoked", - 164: "key was rejected by service", - 165: "owner died", - 166: "state not recoverable", - 167: "operation not possible due to RF-kill", - 168: "memory page has hardware error", - 1133: "disk quota exceeded", +var errorList = [...]struct { + num syscall.Errno + name string + desc string +}{ + {1, "EPERM", "operation not permitted"}, + {2, "ENOENT", "no such file or directory"}, + {3, "ESRCH", "no such process"}, + {4, "EINTR", "interrupted system call"}, + {5, "EIO", "input/output error"}, + {6, "ENXIO", "no such device or address"}, + {7, "E2BIG", "argument list too long"}, + {8, "ENOEXEC", "exec format error"}, + {9, "EBADF", "bad file descriptor"}, + {10, "ECHILD", "no child processes"}, + {11, "EAGAIN", "resource temporarily unavailable"}, + {12, "ENOMEM", "cannot allocate memory"}, + {13, "EACCES", "permission denied"}, + {14, "EFAULT", "bad address"}, + {15, "ENOTBLK", "block device required"}, + {16, "EBUSY", "device or resource busy"}, + {17, "EEXIST", "file exists"}, + {18, "EXDEV", "invalid cross-device link"}, + {19, "ENODEV", "no such device"}, + {20, "ENOTDIR", "not a directory"}, + {21, "EISDIR", "is a directory"}, + {22, "EINVAL", "invalid argument"}, + {23, "ENFILE", "too many open files in system"}, + {24, "EMFILE", "too many open files"}, + {25, "ENOTTY", "inappropriate ioctl for device"}, + {26, "ETXTBSY", "text file busy"}, + {27, "EFBIG", "file too large"}, + {28, "ENOSPC", "no space left on device"}, + {29, "ESPIPE", "illegal seek"}, + {30, "EROFS", "read-only file system"}, + {31, "EMLINK", "too many links"}, + {32, "EPIPE", "broken pipe"}, + {33, "EDOM", "numerical argument out of domain"}, + {34, "ERANGE", "numerical result out of range"}, + {35, "ENOMSG", "no message of desired type"}, + {36, "EIDRM", "identifier removed"}, + {37, "ECHRNG", "channel number out of range"}, + {38, "EL2NSYNC", "level 2 not synchronized"}, + {39, "EL3HLT", "level 3 halted"}, + {40, "EL3RST", "level 3 reset"}, + {41, "ELNRNG", "link number out of range"}, + {42, "EUNATCH", "protocol driver not attached"}, + {43, "ENOCSI", "no CSI structure available"}, + {44, "EL2HLT", "level 2 halted"}, + {45, "EDEADLK", "resource deadlock avoided"}, + {46, "ENOLCK", "no locks available"}, + {50, "EBADE", "invalid exchange"}, + {51, "EBADR", "invalid request descriptor"}, + {52, "EXFULL", "exchange full"}, + {53, "ENOANO", "no anode"}, + {54, "EBADRQC", "invalid request code"}, + {55, "EBADSLT", "invalid slot"}, + {56, "EDEADLOCK", "file locking deadlock error"}, + {59, "EBFONT", "bad font file format"}, + {60, "ENOSTR", "device not a stream"}, + {61, "ENODATA", "no data available"}, + {62, "ETIME", "timer expired"}, + {63, "ENOSR", "out of streams resources"}, + {64, "ENONET", "machine is not on the network"}, + {65, "ENOPKG", "package not installed"}, + {66, "EREMOTE", "object is remote"}, + {67, "ENOLINK", "link has been severed"}, + {68, "EADV", "advertise error"}, + {69, "ESRMNT", "srmount error"}, + {70, "ECOMM", "communication error on send"}, + {71, "EPROTO", "protocol error"}, + {73, "EDOTDOT", "RFS specific error"}, + {74, "EMULTIHOP", "multihop attempted"}, + {77, "EBADMSG", "bad message"}, + {78, "ENAMETOOLONG", "file name too long"}, + {79, "EOVERFLOW", "value too large for defined data type"}, + {80, "ENOTUNIQ", "name not unique on network"}, + {81, "EBADFD", "file descriptor in bad state"}, + {82, "EREMCHG", "remote address changed"}, + {83, "ELIBACC", "can not access a needed shared library"}, + {84, "ELIBBAD", "accessing a corrupted shared library"}, + {85, "ELIBSCN", ".lib section in a.out corrupted"}, + {86, "ELIBMAX", "attempting to link in too many shared libraries"}, + {87, "ELIBEXEC", "cannot exec a shared library directly"}, + {88, "EILSEQ", "invalid or incomplete multibyte or wide character"}, + {89, "ENOSYS", "function not implemented"}, + {90, "ELOOP", "too many levels of symbolic links"}, + {91, "ERESTART", "interrupted system call should be restarted"}, + {92, "ESTRPIPE", "streams pipe error"}, + {93, "ENOTEMPTY", "directory not empty"}, + {94, "EUSERS", "too many users"}, + {95, "ENOTSOCK", "socket operation on non-socket"}, + {96, "EDESTADDRREQ", "destination address required"}, + {97, "EMSGSIZE", "message too long"}, + {98, "EPROTOTYPE", "protocol wrong type for socket"}, + {99, "ENOPROTOOPT", "protocol not available"}, + {120, "EPROTONOSUPPORT", "protocol not supported"}, + {121, "ESOCKTNOSUPPORT", "socket type not supported"}, + {122, "ENOTSUP", "operation not supported"}, + {123, "EPFNOSUPPORT", "protocol family not supported"}, + {124, "EAFNOSUPPORT", "address family not supported by protocol"}, + {125, "EADDRINUSE", "address already in use"}, + {126, "EADDRNOTAVAIL", "cannot assign requested address"}, + {127, "ENETDOWN", "network is down"}, + {128, "ENETUNREACH", "network is unreachable"}, + {129, "ENETRESET", "network dropped connection on reset"}, + {130, "ECONNABORTED", "software caused connection abort"}, + {131, "ECONNRESET", "connection reset by peer"}, + {132, "ENOBUFS", "no buffer space available"}, + {133, "EISCONN", "transport endpoint is already connected"}, + {134, "ENOTCONN", "transport endpoint is not connected"}, + {135, "EUCLEAN", "structure needs cleaning"}, + {137, "ENOTNAM", "not a XENIX named type file"}, + {138, "ENAVAIL", "no XENIX semaphores available"}, + {139, "EISNAM", "is a named type file"}, + {140, "EREMOTEIO", "remote I/O error"}, + {141, "EINIT", "unknown error 141"}, + {142, "EREMDEV", "unknown error 142"}, + {143, "ESHUTDOWN", "cannot send after transport endpoint shutdown"}, + {144, "ETOOMANYREFS", "too many references: cannot splice"}, + {145, "ETIMEDOUT", "connection timed out"}, + {146, "ECONNREFUSED", "connection refused"}, + {147, "EHOSTDOWN", "host is down"}, + {148, "EHOSTUNREACH", "no route to host"}, + {149, "EALREADY", "operation already in progress"}, + {150, "EINPROGRESS", "operation now in progress"}, + {151, "ESTALE", "stale file handle"}, + {158, "ECANCELED", "operation canceled"}, + {159, "ENOMEDIUM", "no medium found"}, + {160, "EMEDIUMTYPE", "wrong medium type"}, + {161, "ENOKEY", "required key not available"}, + {162, "EKEYEXPIRED", "key has expired"}, + {163, "EKEYREVOKED", "key has been revoked"}, + {164, "EKEYREJECTED", "key was rejected by service"}, + {165, "EOWNERDEAD", "owner died"}, + {166, "ENOTRECOVERABLE", "state not recoverable"}, + {167, "ERFKILL", "operation not possible due to RF-kill"}, + {168, "EHWPOISON", "memory page has hardware error"}, + {1133, "EDQUOT", "disk quota exceeded"}, } // Signal table -var signals = [...]string{ - 1: "hangup", - 2: "interrupt", - 3: "quit", - 4: "illegal instruction", - 5: "trace/breakpoint trap", - 6: "aborted", - 7: "EMT trap", - 8: "floating point exception", - 9: "killed", - 10: "bus error", - 11: "segmentation fault", - 12: "bad system call", - 13: "broken pipe", - 14: "alarm clock", - 15: "terminated", - 16: "user defined signal 1", - 17: "user defined signal 2", - 18: "child exited", - 19: "power failure", - 20: "window changed", - 21: "urgent I/O condition", - 22: "I/O possible", - 23: "stopped (signal)", - 24: "stopped", - 25: "continued", - 26: "stopped (tty input)", - 27: "stopped (tty output)", - 28: "virtual timer expired", - 29: "profiling timer expired", - 30: "CPU time limit exceeded", - 31: "file size limit exceeded", +var signalList = [...]struct { + num syscall.Signal + name string + desc string +}{ + {1, "SIGHUP", "hangup"}, + {2, "SIGINT", "interrupt"}, + {3, "SIGQUIT", "quit"}, + {4, "SIGILL", "illegal instruction"}, + {5, "SIGTRAP", "trace/breakpoint trap"}, + {6, "SIGABRT", "aborted"}, + {7, "SIGEMT", "EMT trap"}, + {8, "SIGFPE", "floating point exception"}, + {9, "SIGKILL", "killed"}, + {10, "SIGBUS", "bus error"}, + {11, "SIGSEGV", "segmentation fault"}, + {12, "SIGSYS", "bad system call"}, + {13, "SIGPIPE", "broken pipe"}, + {14, "SIGALRM", "alarm clock"}, + {15, "SIGTERM", "terminated"}, + {16, "SIGUSR1", "user defined signal 1"}, + {17, "SIGUSR2", "user defined signal 2"}, + {18, "SIGCHLD", "child exited"}, + {19, "SIGPWR", "power failure"}, + {20, "SIGWINCH", "window changed"}, + {21, "SIGURG", "urgent I/O condition"}, + {22, "SIGIO", "I/O possible"}, + {23, "SIGSTOP", "stopped (signal)"}, + {24, "SIGTSTP", "stopped"}, + {25, "SIGCONT", "continued"}, + {26, "SIGTTIN", "stopped (tty input)"}, + {27, "SIGTTOU", "stopped (tty output)"}, + {28, "SIGVTALRM", "virtual timer expired"}, + {29, "SIGPROF", "profiling timer expired"}, + {30, "SIGXCPU", "CPU time limit exceeded"}, + {31, "SIGXFSZ", "file size limit exceeded"}, } diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go index dc8e56e30c..677d904562 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go @@ -3,7 +3,7 @@ // +build mips64le,linux -// Created by cgo -godefs - DO NOT EDIT +// Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go package unix @@ -11,6 +11,11 @@ package unix import "syscall" const ( + AAFS_MAGIC = 0x5a3c69f0 + ADFS_SUPER_MAGIC = 0xadf5 + AFFS_SUPER_MAGIC = 0xadff + AFS_FS_MAGIC = 0x6b414653 + AFS_SUPER_MAGIC = 0x5346414f AF_ALG = 0x26 AF_APPLETALK = 0x5 AF_ASH = 0x12 @@ -36,7 +41,7 @@ const ( AF_KEY = 0xf AF_LLC = 0x1a AF_LOCAL = 0x1 - AF_MAX = 0x2c + AF_MAX = 0x2d AF_MPLS = 0x1c AF_NETBEUI = 0xd AF_NETLINK = 0x10 @@ -59,6 +64,7 @@ const ( AF_VSOCK = 0x28 AF_WANPIPE = 0x19 AF_X25 = 0x9 + AF_XDP = 0x2c ALG_OP_DECRYPT = 0x0 ALG_OP_ENCRYPT = 0x1 ALG_SET_AEAD_ASSOCLEN = 0x4 @@ -66,6 +72,7 @@ const ( ALG_SET_IV = 0x2 ALG_SET_KEY = 0x1 ALG_SET_OP = 0x3 + ANON_INODE_FS_MAGIC = 0x9041934 ARPHRD_6LOWPAN = 0x339 ARPHRD_ADAPT = 0x108 ARPHRD_APPLETLK = 0x8 @@ -121,6 +128,7 @@ const ( ARPHRD_PPP = 0x200 ARPHRD_PRONET = 0x4 ARPHRD_RAWHDLC = 0x206 + ARPHRD_RAWIP = 0x207 ARPHRD_ROSE = 0x10e ARPHRD_RSRVD = 0x104 ARPHRD_SIT = 0x308 @@ -132,6 +140,7 @@ const ( ARPHRD_VOID = 0xffff ARPHRD_VSOCKMON = 0x33a ARPHRD_X25 = 0x10f + AUTOFS_SUPER_MAGIC = 0x187 B0 = 0x0 B1000000 = 0x1008 B110 = 0x3 @@ -163,6 +172,9 @@ const ( B75 = 0x2 B921600 = 0x1007 B9600 = 0xd + BALLOON_KVM_MAGIC = 0x13661366 + BDEVFS_MAGIC = 0x62646576 + BINFMTFS_MAGIC = 0x42494e4d BLKBSZGET = 0x40081270 BLKBSZSET = 0x80081271 BLKFLSBUF = 0x20001261 @@ -187,6 +199,7 @@ const ( BPF_AND = 0x50 BPF_B = 0x10 BPF_DIV = 0x30 + BPF_FS_MAGIC = 0xcafe4a11 BPF_H = 0x8 BPF_IMM = 0x0 BPF_IND = 0x40 @@ -228,6 +241,8 @@ const ( BS0 = 0x0 BS1 = 0x2000 BSDLY = 0x2000 + BTRFS_SUPER_MAGIC = 0x9123683e + BTRFS_TEST_MAGIC = 0x73727279 CAN_BCM = 0x2 CAN_EFF_FLAG = 0x80000000 CAN_EFF_ID_BITS = 0x1d @@ -251,6 +266,8 @@ const ( CBAUD = 0x100f CBAUDEX = 0x1000 CFLUSH = 0xf + CGROUP2_SUPER_MAGIC = 0x63677270 + CGROUP_SUPER_MAGIC = 0x27e0eb CIBAUD = 0x100f0000 CLOCAL = 0x800 CLOCK_BOOTTIME = 0x7 @@ -293,10 +310,12 @@ const ( CLONE_VFORK = 0x4000 CLONE_VM = 0x100 CMSPAR = 0x40000000 + CODA_SUPER_MAGIC = 0x73757245 CR0 = 0x0 CR1 = 0x200 CR2 = 0x400 CR3 = 0x600 + CRAMFS_MAGIC = 0x28cd3d45 CRDLY = 0x600 CREAD = 0x80 CRTSCTS = 0x80000000 @@ -311,6 +330,9 @@ const ( CSTOP = 0x13 CSTOPB = 0x40 CSUSP = 0x1a + DAXFS_MAGIC = 0x64646178 + DEBUGFS_MAGIC = 0x64626720 + DEVPTS_SUPER_MAGIC = 0x1cd1 DT_BLK = 0x6 DT_CHR = 0x2 DT_DIR = 0x4 @@ -327,9 +349,12 @@ const ( ECHOKE = 0x800 ECHONL = 0x40 ECHOPRT = 0x400 + ECRYPTFS_SUPER_MAGIC = 0xf15f EFD_CLOEXEC = 0x80000 EFD_NONBLOCK = 0x80 EFD_SEMAPHORE = 0x1 + EFIVARFS_MAGIC = 0xde5e81e4 + EFS_SUPER_MAGIC = 0x414a53 ENCODING_DEFAULT = 0x0 ENCODING_FM_MARK = 0x3 ENCODING_FM_SPACE = 0x4 @@ -390,6 +415,8 @@ const ( ETH_P_DSA = 0x1b ETH_P_ECONET = 0x18 ETH_P_EDSA = 0xdada + ETH_P_ERSPAN = 0x88be + ETH_P_ERSPAN2 = 0x22eb ETH_P_FCOE = 0x8906 ETH_P_FIP = 0x8914 ETH_P_HDLC = 0x19 @@ -398,6 +425,7 @@ const ( ETH_P_IEEE802154 = 0xf6 ETH_P_IEEEPUP = 0xa00 ETH_P_IEEEPUPAT = 0xa01 + ETH_P_IFE = 0xed3e ETH_P_IP = 0x800 ETH_P_IPV6 = 0x86dd ETH_P_IPX = 0x8137 @@ -408,11 +436,13 @@ const ( ETH_P_LOOP = 0x60 ETH_P_LOOPBACK = 0x9000 ETH_P_MACSEC = 0x88e5 + ETH_P_MAP = 0xf9 ETH_P_MOBITEX = 0x15 ETH_P_MPLS_MC = 0x8848 ETH_P_MPLS_UC = 0x8847 ETH_P_MVRP = 0x88f5 ETH_P_NCSI = 0x88f8 + ETH_P_NSH = 0x894f ETH_P_PAE = 0x888e ETH_P_PAUSE = 0x8808 ETH_P_PHONET = 0xf5 @@ -420,6 +450,7 @@ const ( ETH_P_PPP_DISC = 0x8863 ETH_P_PPP_MP = 0x8 ETH_P_PPP_SES = 0x8864 + ETH_P_PREAUTH = 0x88c7 ETH_P_PRP = 0x88fb ETH_P_PUP = 0x200 ETH_P_PUPAT = 0x201 @@ -440,9 +471,14 @@ const ( ETH_P_WCCP = 0x883e ETH_P_X25 = 0x805 ETH_P_XDSA = 0xf8 + EXABYTE_ENABLE_NEST = 0xf0 + EXT2_SUPER_MAGIC = 0xef53 + EXT3_SUPER_MAGIC = 0xef53 + EXT4_SUPER_MAGIC = 0xef53 EXTA = 0xe EXTB = 0xf EXTPROC = 0x10000 + F2FS_SUPER_MAGIC = 0xf2f52010 FALLOC_FL_COLLAPSE_RANGE = 0x8 FALLOC_FL_INSERT_RANGE = 0x20 FALLOC_FL_KEEP_SIZE = 0x1 @@ -463,6 +499,8 @@ const ( FS_ENCRYPTION_MODE_AES_256_GCM = 0x2 FS_ENCRYPTION_MODE_AES_256_XTS = 0x1 FS_ENCRYPTION_MODE_INVALID = 0x0 + FS_ENCRYPTION_MODE_SPECK128_256_CTS = 0x8 + FS_ENCRYPTION_MODE_SPECK128_256_XTS = 0x7 FS_IOC_GET_ENCRYPTION_POLICY = 0x800c6615 FS_IOC_GET_ENCRYPTION_PWSALT = 0x80106614 FS_IOC_SET_ENCRYPTION_POLICY = 0x400c6613 @@ -476,6 +514,8 @@ const ( FS_POLICY_FLAGS_PAD_8 = 0x1 FS_POLICY_FLAGS_PAD_MASK = 0x3 FS_POLICY_FLAGS_VALID = 0x3 + FUTEXFS_SUPER_MAGIC = 0xbad1dea + F_ADD_SEALS = 0x409 F_DUPFD = 0x0 F_DUPFD_CLOEXEC = 0x406 F_EXLCK = 0x4 @@ -488,6 +528,9 @@ const ( F_GETOWN_EX = 0x10 F_GETPIPE_SZ = 0x408 F_GETSIG = 0xb + F_GET_FILE_RW_HINT = 0x40d + F_GET_RW_HINT = 0x40b + F_GET_SEALS = 0x40a F_LOCK = 0x1 F_NOTIFY = 0x402 F_OFD_GETLK = 0x24 @@ -495,6 +538,10 @@ const ( F_OFD_SETLKW = 0x26 F_OK = 0x0 F_RDLCK = 0x0 + F_SEAL_GROW = 0x4 + F_SEAL_SEAL = 0x1 + F_SEAL_SHRINK = 0x2 + F_SEAL_WRITE = 0x8 F_SETFD = 0x2 F_SETFL = 0x4 F_SETLEASE = 0x400 @@ -506,6 +553,8 @@ const ( F_SETOWN_EX = 0xf F_SETPIPE_SZ = 0x407 F_SETSIG = 0xa + F_SET_FILE_RW_HINT = 0x40e + F_SET_RW_HINT = 0x40c F_SHLCK = 0x8 F_TEST = 0x3 F_TLOCK = 0x2 @@ -527,6 +576,49 @@ const ( GENL_UNS_ADMIN_PERM = 0x10 GRND_NONBLOCK = 0x1 GRND_RANDOM = 0x2 + HDIO_DRIVE_CMD = 0x31f + HDIO_DRIVE_CMD_AEB = 0x31e + HDIO_DRIVE_CMD_HDR_SIZE = 0x4 + HDIO_DRIVE_HOB_HDR_SIZE = 0x8 + HDIO_DRIVE_RESET = 0x31c + HDIO_DRIVE_TASK = 0x31e + HDIO_DRIVE_TASKFILE = 0x31d + HDIO_DRIVE_TASK_HDR_SIZE = 0x8 + HDIO_GETGEO = 0x301 + HDIO_GET_32BIT = 0x309 + HDIO_GET_ACOUSTIC = 0x30f + HDIO_GET_ADDRESS = 0x310 + HDIO_GET_BUSSTATE = 0x31a + HDIO_GET_DMA = 0x30b + HDIO_GET_IDENTITY = 0x30d + HDIO_GET_KEEPSETTINGS = 0x308 + HDIO_GET_MULTCOUNT = 0x304 + HDIO_GET_NICE = 0x30c + HDIO_GET_NOWERR = 0x30a + HDIO_GET_QDMA = 0x305 + HDIO_GET_UNMASKINTR = 0x302 + HDIO_GET_WCACHE = 0x30e + HDIO_OBSOLETE_IDENTITY = 0x307 + HDIO_SCAN_HWIF = 0x328 + HDIO_SET_32BIT = 0x324 + HDIO_SET_ACOUSTIC = 0x32c + HDIO_SET_ADDRESS = 0x32f + HDIO_SET_BUSSTATE = 0x32d + HDIO_SET_DMA = 0x326 + HDIO_SET_KEEPSETTINGS = 0x323 + HDIO_SET_MULTCOUNT = 0x321 + HDIO_SET_NICE = 0x329 + HDIO_SET_NOWERR = 0x325 + HDIO_SET_PIO_MODE = 0x327 + HDIO_SET_QDMA = 0x32e + HDIO_SET_UNMASKINTR = 0x322 + HDIO_SET_WCACHE = 0x32b + HDIO_SET_XFER = 0x306 + HDIO_TRISTATE_HWIF = 0x31b + HDIO_UNREGISTER_HWIF = 0x32a + HOSTFS_SUPER_MAGIC = 0xc0ffee + HPFS_SUPER_MAGIC = 0xf995e849 + HUGETLBFS_MAGIC = 0x958458f6 HUPCL = 0x400 IBSHIFT = 0x10 ICANON = 0x2 @@ -546,7 +638,7 @@ const ( IFA_F_STABLE_PRIVACY = 0x800 IFA_F_TEMPORARY = 0x1 IFA_F_TENTATIVE = 0x40 - IFA_MAX = 0x8 + IFA_MAX = 0xa IFF_ALLMULTI = 0x200 IFF_ATTACH_QUEUE = 0x200 IFF_AUTOMEDIA = 0x4000 @@ -561,6 +653,8 @@ const ( IFF_MASTER = 0x400 IFF_MULTICAST = 0x1000 IFF_MULTI_QUEUE = 0x100 + IFF_NAPI = 0x10 + IFF_NAPI_FRAGS = 0x20 IFF_NOARP = 0x80 IFF_NOFILTER = 0x1000 IFF_NOTRAILERS = 0x20 @@ -612,6 +706,7 @@ const ( IN_ISDIR = 0x40000000 IN_LOOPBACKNET = 0x7f IN_MASK_ADD = 0x20000000 + IN_MASK_CREATE = 0x10000000 IN_MODIFY = 0x2 IN_MOVE = 0xc0 IN_MOVED_FROM = 0x40 @@ -671,6 +766,7 @@ const ( IPV6_DONTFRAG = 0x3e IPV6_DROP_MEMBERSHIP = 0x15 IPV6_DSTOPTS = 0x3b + IPV6_FREEBIND = 0x4e IPV6_HDRINCL = 0x24 IPV6_HOPLIMIT = 0x34 IPV6_HOPOPTS = 0x36 @@ -682,6 +778,7 @@ const ( IPV6_MINHOPCOUNT = 0x49 IPV6_MTU = 0x18 IPV6_MTU_DISCOVER = 0x17 + IPV6_MULTICAST_ALL = 0x1d IPV6_MULTICAST_HOPS = 0x12 IPV6_MULTICAST_IF = 0x11 IPV6_MULTICAST_LOOP = 0x13 @@ -775,12 +872,34 @@ const ( IP_UNICAST_IF = 0x32 IP_XFRM_POLICY = 0x11 ISIG = 0x1 + ISOFS_SUPER_MAGIC = 0x9660 ISTRIP = 0x20 IUCLC = 0x200 IUTF8 = 0x4000 IXANY = 0x800 IXOFF = 0x1000 IXON = 0x400 + JFFS2_SUPER_MAGIC = 0x72b6 + KEXEC_ARCH_386 = 0x30000 + KEXEC_ARCH_68K = 0x40000 + KEXEC_ARCH_AARCH64 = 0xb70000 + KEXEC_ARCH_ARM = 0x280000 + KEXEC_ARCH_DEFAULT = 0x0 + KEXEC_ARCH_IA_64 = 0x320000 + KEXEC_ARCH_MASK = 0xffff0000 + KEXEC_ARCH_MIPS = 0x80000 + KEXEC_ARCH_MIPS_LE = 0xa0000 + KEXEC_ARCH_PPC = 0x140000 + KEXEC_ARCH_PPC64 = 0x150000 + KEXEC_ARCH_S390 = 0x160000 + KEXEC_ARCH_SH = 0x2a0000 + KEXEC_ARCH_X86_64 = 0x3e0000 + KEXEC_FILE_NO_INITRAMFS = 0x4 + KEXEC_FILE_ON_CRASH = 0x2 + KEXEC_FILE_UNLOAD = 0x1 + KEXEC_ON_CRASH = 0x1 + KEXEC_PRESERVE_CONTEXT = 0x2 + KEXEC_SEGMENT_MAX = 0x10 KEYCTL_ASSUME_AUTHORITY = 0x10 KEYCTL_CHOWN = 0x4 KEYCTL_CLEAR = 0x7 @@ -795,6 +914,11 @@ const ( KEYCTL_JOIN_SESSION_KEYRING = 0x1 KEYCTL_LINK = 0x8 KEYCTL_NEGATE = 0xd + KEYCTL_PKEY_DECRYPT = 0x1a + KEYCTL_PKEY_ENCRYPT = 0x19 + KEYCTL_PKEY_QUERY = 0x18 + KEYCTL_PKEY_SIGN = 0x1b + KEYCTL_PKEY_VERIFY = 0x1c KEYCTL_READ = 0xb KEYCTL_REJECT = 0x13 KEYCTL_RESTRICT_KEYRING = 0x1d @@ -804,6 +928,10 @@ const ( KEYCTL_SETPERM = 0x5 KEYCTL_SET_REQKEY_KEYRING = 0xe KEYCTL_SET_TIMEOUT = 0xf + KEYCTL_SUPPORTS_DECRYPT = 0x2 + KEYCTL_SUPPORTS_ENCRYPT = 0x1 + KEYCTL_SUPPORTS_SIGN = 0x4 + KEYCTL_SUPPORTS_VERIFY = 0x8 KEYCTL_UNLINK = 0x9 KEYCTL_UPDATE = 0x2 KEY_REQKEY_DEFL_DEFAULT = 0x0 @@ -845,6 +973,7 @@ const ( MADV_FREE = 0x8 MADV_HUGEPAGE = 0xe MADV_HWPOISON = 0x64 + MADV_KEEPONFORK = 0x13 MADV_MERGEABLE = 0xc MADV_NOHUGEPAGE = 0xf MADV_NORMAL = 0x0 @@ -853,12 +982,14 @@ const ( MADV_SEQUENTIAL = 0x2 MADV_UNMERGEABLE = 0xd MADV_WILLNEED = 0x3 + MADV_WIPEONFORK = 0x12 MAP_ANON = 0x800 MAP_ANONYMOUS = 0x800 MAP_DENYWRITE = 0x2000 MAP_EXECUTABLE = 0x4000 MAP_FILE = 0x0 MAP_FIXED = 0x10 + MAP_FIXED_NOREPLACE = 0x100000 MAP_GROWSDOWN = 0x1000 MAP_HUGETLB = 0x80000 MAP_HUGE_MASK = 0x3f @@ -870,14 +1001,40 @@ const ( MAP_PRIVATE = 0x2 MAP_RENAME = 0x800 MAP_SHARED = 0x1 + MAP_SHARED_VALIDATE = 0x3 MAP_STACK = 0x40000 MAP_TYPE = 0xf MCL_CURRENT = 0x1 MCL_FUTURE = 0x2 MCL_ONFAULT = 0x4 + MFD_ALLOW_SEALING = 0x2 + MFD_CLOEXEC = 0x1 + MFD_HUGETLB = 0x4 + MFD_HUGE_16GB = -0x78000000 + MFD_HUGE_16MB = 0x60000000 + MFD_HUGE_1GB = 0x78000000 + MFD_HUGE_1MB = 0x50000000 + MFD_HUGE_256MB = 0x70000000 + MFD_HUGE_2GB = 0x7c000000 + MFD_HUGE_2MB = 0x54000000 + MFD_HUGE_32MB = 0x64000000 + MFD_HUGE_512KB = 0x4c000000 + MFD_HUGE_512MB = 0x74000000 + MFD_HUGE_64KB = 0x40000000 + MFD_HUGE_8MB = 0x5c000000 + MFD_HUGE_MASK = 0x3f + MFD_HUGE_SHIFT = 0x1a + MINIX2_SUPER_MAGIC = 0x2468 + MINIX2_SUPER_MAGIC2 = 0x2478 + MINIX3_SUPER_MAGIC = 0x4d5a + MINIX_SUPER_MAGIC = 0x137f + MINIX_SUPER_MAGIC2 = 0x138f MNT_DETACH = 0x2 MNT_EXPIRE = 0x4 MNT_FORCE = 0x1 + MODULE_INIT_IGNORE_MODVERSIONS = 0x1 + MODULE_INIT_IGNORE_VERMAGIC = 0x2 + MSDOS_SUPER_MAGIC = 0x4d44 MSG_BATCH = 0x40000 MSG_CMSG_CLOEXEC = 0x40000000 MSG_CONFIRM = 0x800 @@ -899,6 +1056,7 @@ const ( MSG_TRYHARD = 0x4 MSG_WAITALL = 0x100 MSG_WAITFORONE = 0x10000 + MSG_ZEROCOPY = 0x4000000 MS_ACTIVE = 0x40000000 MS_ASYNC = 0x1 MS_BIND = 0x1000 @@ -936,7 +1094,9 @@ const ( MS_SYNCHRONOUS = 0x10 MS_UNBINDABLE = 0x20000 MS_VERBOSE = 0x8000 + MTD_INODE_FS_MAGIC = 0x11307854 NAME_MAX = 0xff + NCP_SUPER_MAGIC = 0x564c NETLINK_ADD_MEMBERSHIP = 0x1 NETLINK_AUDIT = 0x9 NETLINK_BROADCAST_ERROR = 0x4 @@ -950,6 +1110,7 @@ const ( NETLINK_FIB_LOOKUP = 0xa NETLINK_FIREWALL = 0x3 NETLINK_GENERIC = 0x10 + NETLINK_GET_STRICT_CHK = 0xc NETLINK_INET_DIAG = 0x4 NETLINK_IP6_FW = 0xd NETLINK_ISCSI = 0x8 @@ -971,6 +1132,39 @@ const ( NETLINK_UNUSED = 0x1 NETLINK_USERSOCK = 0x2 NETLINK_XFRM = 0x6 + NETNSA_MAX = 0x3 + NETNSA_NSID_NOT_ASSIGNED = -0x1 + NFNETLINK_V0 = 0x0 + NFNLGRP_ACCT_QUOTA = 0x8 + NFNLGRP_CONNTRACK_DESTROY = 0x3 + NFNLGRP_CONNTRACK_EXP_DESTROY = 0x6 + NFNLGRP_CONNTRACK_EXP_NEW = 0x4 + NFNLGRP_CONNTRACK_EXP_UPDATE = 0x5 + NFNLGRP_CONNTRACK_NEW = 0x1 + NFNLGRP_CONNTRACK_UPDATE = 0x2 + NFNLGRP_MAX = 0x9 + NFNLGRP_NFTABLES = 0x7 + NFNLGRP_NFTRACE = 0x9 + NFNLGRP_NONE = 0x0 + NFNL_BATCH_MAX = 0x1 + NFNL_MSG_BATCH_BEGIN = 0x10 + NFNL_MSG_BATCH_END = 0x11 + NFNL_NFA_NEST = 0x8000 + NFNL_SUBSYS_ACCT = 0x7 + NFNL_SUBSYS_COUNT = 0xc + NFNL_SUBSYS_CTHELPER = 0x9 + NFNL_SUBSYS_CTNETLINK = 0x1 + NFNL_SUBSYS_CTNETLINK_EXP = 0x2 + NFNL_SUBSYS_CTNETLINK_TIMEOUT = 0x8 + NFNL_SUBSYS_IPSET = 0x6 + NFNL_SUBSYS_NFTABLES = 0xa + NFNL_SUBSYS_NFT_COMPAT = 0xb + NFNL_SUBSYS_NONE = 0x0 + NFNL_SUBSYS_OSF = 0x5 + NFNL_SUBSYS_QUEUE = 0x3 + NFNL_SUBSYS_ULOG = 0x4 + NFS_SUPER_MAGIC = 0x6969 + NILFS_SUPER_MAGIC = 0x3434 NL0 = 0x0 NL1 = 0x100 NLA_ALIGNTO = 0x4 @@ -998,10 +1192,13 @@ const ( NLM_F_EXCL = 0x200 NLM_F_MATCH = 0x200 NLM_F_MULTI = 0x2 + NLM_F_NONREC = 0x100 NLM_F_REPLACE = 0x100 NLM_F_REQUEST = 0x1 NLM_F_ROOT = 0x100 NOFLSH = 0x80 + NSFS_MAGIC = 0x6e736673 + OCFS2_SUPER_MAGIC = 0x7461636f OCRNL = 0x8 OFDEL = 0x80 OFILL = 0x40 @@ -1009,7 +1206,9 @@ const ( ONLCR = 0x4 ONLRET = 0x20 ONOCR = 0x10 + OPENPROM_SUPER_MAGIC = 0x9fa1 OPOST = 0x1 + OVERLAYFS_SUPER_MAGIC = 0x794c7630 O_ACCMODE = 0x3 O_APPEND = 0x8 O_ASYNC = 0x1000 @@ -1055,6 +1254,7 @@ const ( PACKET_FASTROUTE = 0x6 PACKET_HDRLEN = 0xb PACKET_HOST = 0x0 + PACKET_IGNORE_OUTGOING = 0x17 PACKET_KERNEL = 0x7 PACKET_LOOPBACK = 0x5 PACKET_LOSS = 0xe @@ -1094,16 +1294,50 @@ const ( PERF_EVENT_IOC_DISABLE = 0x20002401 PERF_EVENT_IOC_ENABLE = 0x20002400 PERF_EVENT_IOC_ID = 0x40082407 + PERF_EVENT_IOC_MODIFY_ATTRIBUTES = 0x8008240b PERF_EVENT_IOC_PAUSE_OUTPUT = 0x80042409 PERF_EVENT_IOC_PERIOD = 0x80082404 + PERF_EVENT_IOC_QUERY_BPF = 0xc008240a PERF_EVENT_IOC_REFRESH = 0x20002402 PERF_EVENT_IOC_RESET = 0x20002403 PERF_EVENT_IOC_SET_BPF = 0x80042408 PERF_EVENT_IOC_SET_FILTER = 0x80082406 PERF_EVENT_IOC_SET_OUTPUT = 0x20002405 + PIPEFS_MAGIC = 0x50495045 + PPPIOCATTACH = 0x8004743d + PPPIOCATTCHAN = 0x80047438 + PPPIOCCONNECT = 0x8004743a + PPPIOCDETACH = 0x8004743c + PPPIOCDISCONN = 0x20007439 + PPPIOCGASYNCMAP = 0x40047458 + PPPIOCGCHAN = 0x40047437 + PPPIOCGDEBUG = 0x40047441 + PPPIOCGFLAGS = 0x4004745a + PPPIOCGIDLE = 0x4010743f + PPPIOCGL2TPSTATS = 0x40487436 + PPPIOCGMRU = 0x40047453 + PPPIOCGNPMODE = 0xc008744c + PPPIOCGRASYNCMAP = 0x40047455 + PPPIOCGUNIT = 0x40047456 + PPPIOCGXASYNCMAP = 0x40207450 + PPPIOCNEWUNIT = 0xc004743e + PPPIOCSACTIVE = 0x80107446 + PPPIOCSASYNCMAP = 0x80047457 + PPPIOCSCOMPRESS = 0x8010744d + PPPIOCSDEBUG = 0x80047440 + PPPIOCSFLAGS = 0x80047459 + PPPIOCSMAXCID = 0x80047451 + PPPIOCSMRRU = 0x8004743b + PPPIOCSMRU = 0x80047452 + PPPIOCSNPMODE = 0x8008744b + PPPIOCSPASS = 0x80107447 + PPPIOCSRASYNCMAP = 0x80047454 + PPPIOCSXASYNCMAP = 0x8020744f + PPPIOCXFERUNIT = 0x2000744e PRIO_PGRP = 0x1 PRIO_PROCESS = 0x0 PRIO_USER = 0x2 + PROC_SUPER_MAGIC = 0x9fa0 PROT_EXEC = 0x4 PROT_GROWSDOWN = 0x1000000 PROT_GROWSUP = 0x2000000 @@ -1146,6 +1380,7 @@ const ( PR_GET_PDEATHSIG = 0x2 PR_GET_SECCOMP = 0x15 PR_GET_SECUREBITS = 0x1b + PR_GET_SPECULATION_CTRL = 0x34 PR_GET_THP_DISABLE = 0x2a PR_GET_TID_ADDRESS = 0x28 PR_GET_TIMERSLACK = 0x1e @@ -1191,11 +1426,24 @@ const ( PR_SET_PTRACER_ANY = 0xffffffffffffffff PR_SET_SECCOMP = 0x16 PR_SET_SECUREBITS = 0x1c + PR_SET_SPECULATION_CTRL = 0x35 PR_SET_THP_DISABLE = 0x29 PR_SET_TIMERSLACK = 0x1d PR_SET_TIMING = 0xe PR_SET_TSC = 0x1a PR_SET_UNALIGN = 0x6 + PR_SPEC_DISABLE = 0x4 + PR_SPEC_ENABLE = 0x2 + PR_SPEC_FORCE_DISABLE = 0x8 + PR_SPEC_INDIRECT_BRANCH = 0x1 + PR_SPEC_NOT_AFFECTED = 0x0 + PR_SPEC_PRCTL = 0x1 + PR_SPEC_STORE_BYPASS = 0x0 + PR_SVE_GET_VL = 0x33 + PR_SVE_SET_VL = 0x32 + PR_SVE_SET_VL_ONEXEC = 0x40000 + PR_SVE_VL_INHERIT = 0x20000 + PR_SVE_VL_LEN_MASK = 0xffff PR_TASK_PERF_EVENTS_DISABLE = 0x1f PR_TASK_PERF_EVENTS_ENABLE = 0x20 PR_TIMING_STATISTICAL = 0x0 @@ -1204,6 +1452,7 @@ const ( PR_TSC_SIGSEGV = 0x2 PR_UNALIGN_NOPRINT = 0x1 PR_UNALIGN_SIGBUS = 0x2 + PSTOREFS_MAGIC = 0x6165676c PTRACE_ATTACH = 0x10 PTRACE_CONT = 0x7 PTRACE_DETACH = 0x11 @@ -1252,6 +1501,7 @@ const ( PTRACE_POKETEXT_3264 = 0xc2 PTRACE_POKEUSR = 0x6 PTRACE_SECCOMP_GET_FILTER = 0x420c + PTRACE_SECCOMP_GET_METADATA = 0x420d PTRACE_SEIZE = 0x4206 PTRACE_SETFPREGS = 0xf PTRACE_SETOPTIONS = 0x4200 @@ -1264,6 +1514,14 @@ const ( PTRACE_SINGLESTEP = 0x9 PTRACE_SYSCALL = 0x18 PTRACE_TRACEME = 0x0 + QNX4_SUPER_MAGIC = 0x2f + QNX6_SUPER_MAGIC = 0x68191122 + RAMFS_MAGIC = 0x858458f6 + RDTGROUP_SUPER_MAGIC = 0x7655821 + REISERFS_SUPER_MAGIC = 0x52654973 + RENAME_EXCHANGE = 0x2 + RENAME_NOREPLACE = 0x1 + RENAME_WHITEOUT = 0x4 RLIMIT_AS = 0x6 RLIMIT_CORE = 0x4 RLIMIT_CPU = 0x0 @@ -1281,9 +1539,17 @@ const ( RLIMIT_SIGPENDING = 0xb RLIMIT_STACK = 0x3 RLIM_INFINITY = 0xffffffffffffffff + RNDADDENTROPY = 0x80085203 + RNDADDTOENTCNT = 0x80045201 + RNDCLEARPOOL = 0x20005206 + RNDGETENTCNT = 0x40045200 + RNDGETPOOL = 0x40085202 + RNDRESEEDCRNG = 0x20005207 + RNDZAPENTCNT = 0x20005204 RTAX_ADVMSS = 0x8 RTAX_CC_ALGO = 0x10 RTAX_CWND = 0x7 + RTAX_FASTOPEN_NO_COOKIE = 0x11 RTAX_FEATURES = 0xc RTAX_FEATURE_ALLFRAG = 0x8 RTAX_FEATURE_ECN = 0x1 @@ -1294,7 +1560,7 @@ const ( RTAX_INITCWND = 0xb RTAX_INITRWND = 0xe RTAX_LOCK = 0x1 - RTAX_MAX = 0x10 + RTAX_MAX = 0x11 RTAX_MTU = 0x2 RTAX_QUICKACK = 0xf RTAX_REORDERING = 0x9 @@ -1305,13 +1571,40 @@ const ( RTAX_UNSPEC = 0x0 RTAX_WINDOW = 0x3 RTA_ALIGNTO = 0x4 - RTA_MAX = 0x1a + RTA_MAX = 0x1d RTCF_DIRECTSRC = 0x4000000 RTCF_DOREDIRECT = 0x1000000 RTCF_LOG = 0x2000000 RTCF_MASQ = 0x400000 RTCF_NAT = 0x800000 RTCF_VALVE = 0x200000 + RTC_AF = 0x20 + RTC_AIE_OFF = 0x20007002 + RTC_AIE_ON = 0x20007001 + RTC_ALM_READ = 0x40247008 + RTC_ALM_SET = 0x80247007 + RTC_EPOCH_READ = 0x4008700d + RTC_EPOCH_SET = 0x8008700e + RTC_IRQF = 0x80 + RTC_IRQP_READ = 0x4008700b + RTC_IRQP_SET = 0x8008700c + RTC_MAX_FREQ = 0x2000 + RTC_PF = 0x40 + RTC_PIE_OFF = 0x20007006 + RTC_PIE_ON = 0x20007005 + RTC_PLL_GET = 0x40207011 + RTC_PLL_SET = 0x80207012 + RTC_RD_TIME = 0x40247009 + RTC_SET_TIME = 0x8024700a + RTC_UF = 0x10 + RTC_UIE_OFF = 0x20007004 + RTC_UIE_ON = 0x20007003 + RTC_VL_CLR = 0x20007014 + RTC_VL_READ = 0x40047013 + RTC_WIE_OFF = 0x20007010 + RTC_WIE_ON = 0x2000700f + RTC_WKALM_RD = 0x40287010 + RTC_WKALM_SET = 0x8028700f RTF_ADDRCLASSMASK = 0xf8000000 RTF_ADDRCONF = 0x40000 RTF_ALLONLINK = 0x20000 @@ -1346,6 +1639,7 @@ const ( RTM_DELACTION = 0x31 RTM_DELADDR = 0x15 RTM_DELADDRLABEL = 0x49 + RTM_DELCHAIN = 0x65 RTM_DELLINK = 0x11 RTM_DELMDB = 0x55 RTM_DELNEIGH = 0x1d @@ -1366,6 +1660,7 @@ const ( RTM_GETADDR = 0x16 RTM_GETADDRLABEL = 0x4a RTM_GETANYCAST = 0x3e + RTM_GETCHAIN = 0x66 RTM_GETDCB = 0x4e RTM_GETLINK = 0x12 RTM_GETMDB = 0x56 @@ -1380,11 +1675,12 @@ const ( RTM_GETSTATS = 0x5e RTM_GETTCLASS = 0x2a RTM_GETTFILTER = 0x2e - RTM_MAX = 0x63 + RTM_MAX = 0x67 RTM_NEWACTION = 0x30 RTM_NEWADDR = 0x14 RTM_NEWADDRLABEL = 0x48 RTM_NEWCACHEREPORT = 0x60 + RTM_NEWCHAIN = 0x64 RTM_NEWLINK = 0x10 RTM_NEWMDB = 0x54 RTM_NEWNDUSEROPT = 0x44 @@ -1399,8 +1695,8 @@ const ( RTM_NEWSTATS = 0x5c RTM_NEWTCLASS = 0x28 RTM_NEWTFILTER = 0x2c - RTM_NR_FAMILIES = 0x15 - RTM_NR_MSGTYPES = 0x54 + RTM_NR_FAMILIES = 0x16 + RTM_NR_MSGTYPES = 0x58 RTM_SETDCB = 0x4f RTM_SETLINK = 0x13 RTM_SETNEIGHTBL = 0x43 @@ -1414,17 +1710,22 @@ const ( RTNH_F_UNRESOLVED = 0x20 RTN_MAX = 0xb RTPROT_BABEL = 0x2a + RTPROT_BGP = 0xba RTPROT_BIRD = 0xc RTPROT_BOOT = 0x3 RTPROT_DHCP = 0x10 RTPROT_DNROUTED = 0xd + RTPROT_EIGRP = 0xc0 RTPROT_GATED = 0x8 + RTPROT_ISIS = 0xbb RTPROT_KERNEL = 0x2 RTPROT_MROUTED = 0x11 RTPROT_MRT = 0xa RTPROT_NTK = 0xf + RTPROT_OSPF = 0xbc RTPROT_RA = 0x9 RTPROT_REDIRECT = 0x1 + RTPROT_RIP = 0xbd RTPROT_STATIC = 0x4 RTPROT_UNSPEC = 0x0 RTPROT_XORP = 0xe @@ -1444,10 +1745,16 @@ const ( SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SC_LOG_FLUSH = 0x100000 SECCOMP_MODE_DISABLED = 0x0 SECCOMP_MODE_FILTER = 0x2 SECCOMP_MODE_STRICT = 0x1 + SECURITYFS_MAGIC = 0x73636673 + SELINUX_MAGIC = 0xf97cff8c + SFD_CLOEXEC = 0x80000 + SFD_NONBLOCK = 0x80 SHUT_RD = 0x0 SHUT_RDWR = 0x2 SHUT_WR = 0x1 @@ -1498,6 +1805,9 @@ const ( SIOCGMIIPHY = 0x8947 SIOCGMIIREG = 0x8948 SIOCGPGRP = 0x40047309 + SIOCGPPPCSTATS = 0x89f2 + SIOCGPPPSTATS = 0x89f0 + SIOCGPPPVER = 0x89f1 SIOCGRARP = 0x8961 SIOCGSKNS = 0x894c SIOCGSTAMP = 0x8906 @@ -1532,6 +1842,23 @@ const ( SIOCSPGRP = 0x80047308 SIOCSRARP = 0x8962 SIOCWANDEV = 0x894a + SMACK_MAGIC = 0x43415d53 + SMART_AUTOSAVE = 0xd2 + SMART_AUTO_OFFLINE = 0xdb + SMART_DISABLE = 0xd9 + SMART_ENABLE = 0xd8 + SMART_HCYL_PASS = 0xc2 + SMART_IMMEDIATE_OFFLINE = 0xd4 + SMART_LCYL_PASS = 0x4f + SMART_READ_LOG_SECTOR = 0xd5 + SMART_READ_THRESHOLDS = 0xd1 + SMART_READ_VALUES = 0xd0 + SMART_SAVE = 0xd3 + SMART_STATUS = 0xda + SMART_WRITE_LOG_SECTOR = 0xd6 + SMART_WRITE_THRESHOLDS = 0xd7 + SMB_SUPER_MAGIC = 0x517b + SOCKFS_MAGIC = 0x534f434b SOCK_CLOEXEC = 0x80000 SOCK_DCCP = 0x6 SOCK_DGRAM = 0x1 @@ -1568,7 +1895,9 @@ const ( SOL_SOCKET = 0xffff SOL_TCP = 0x6 SOL_TIPC = 0x10f + SOL_TLS = 0x11a SOL_X25 = 0x106 + SOL_XDP = 0x11b SOMAXCONN = 0x80 SO_ACCEPTCONN = 0x1009 SO_ATTACH_BPF = 0x32 @@ -1587,6 +1916,17 @@ const ( SO_DETACH_FILTER = 0x1b SO_DOMAIN = 0x1029 SO_DONTROUTE = 0x10 + SO_EE_CODE_TXTIME_INVALID_PARAM = 0x1 + SO_EE_CODE_TXTIME_MISSED = 0x2 + SO_EE_CODE_ZEROCOPY_COPIED = 0x1 + SO_EE_ORIGIN_ICMP = 0x2 + SO_EE_ORIGIN_ICMP6 = 0x3 + SO_EE_ORIGIN_LOCAL = 0x1 + SO_EE_ORIGIN_NONE = 0x0 + SO_EE_ORIGIN_TIMESTAMPING = 0x4 + SO_EE_ORIGIN_TXSTATUS = 0x4 + SO_EE_ORIGIN_TXTIME = 0x6 + SO_EE_ORIGIN_ZEROCOPY = 0x5 SO_ERROR = 0x1007 SO_GET_FILTER = 0x1a SO_INCOMING_CPU = 0x31 @@ -1628,6 +1968,7 @@ const ( SO_TIMESTAMP = 0x1d SO_TIMESTAMPING = 0x25 SO_TIMESTAMPNS = 0x23 + SO_TXTIME = 0x3d SO_TYPE = 0x1008 SO_VM_SOCKETS_BUFFER_MAX_SIZE = 0x2 SO_VM_SOCKETS_BUFFER_MIN_SIZE = 0x1 @@ -1637,10 +1978,38 @@ const ( SO_VM_SOCKETS_PEER_HOST_VM_ID = 0x3 SO_VM_SOCKETS_TRUSTED = 0x5 SO_WIFI_STATUS = 0x29 + SO_ZEROCOPY = 0x3c SPLICE_F_GIFT = 0x8 SPLICE_F_MORE = 0x4 SPLICE_F_MOVE = 0x1 SPLICE_F_NONBLOCK = 0x2 + SQUASHFS_MAGIC = 0x73717368 + STACK_END_MAGIC = 0x57ac6e9d + STATX_ALL = 0xfff + STATX_ATIME = 0x20 + STATX_ATTR_APPEND = 0x20 + STATX_ATTR_AUTOMOUNT = 0x1000 + STATX_ATTR_COMPRESSED = 0x4 + STATX_ATTR_ENCRYPTED = 0x800 + STATX_ATTR_IMMUTABLE = 0x10 + STATX_ATTR_NODUMP = 0x40 + STATX_BASIC_STATS = 0x7ff + STATX_BLOCKS = 0x400 + STATX_BTIME = 0x800 + STATX_CTIME = 0x80 + STATX_GID = 0x10 + STATX_INO = 0x100 + STATX_MODE = 0x2 + STATX_MTIME = 0x40 + STATX_NLINK = 0x4 + STATX_SIZE = 0x200 + STATX_TYPE = 0x1 + STATX_UID = 0x8 + STATX__RESERVED = 0x80000000 + SYNC_FILE_RANGE_WAIT_AFTER = 0x4 + SYNC_FILE_RANGE_WAIT_BEFORE = 0x1 + SYNC_FILE_RANGE_WRITE = 0x2 + SYSFS_MAGIC = 0x62656572 S_BLKSIZE = 0x200 S_IEXEC = 0x40 S_IFBLK = 0x6000 @@ -1678,7 +2047,7 @@ const ( TASKSTATS_GENL_NAME = "TASKSTATS" TASKSTATS_GENL_VERSION = 0x1 TASKSTATS_TYPE_MAX = 0x6 - TASKSTATS_VERSION = 0x8 + TASKSTATS_VERSION = 0x9 TCFLSH = 0x5407 TCGETA = 0x5401 TCGETS = 0x540d @@ -1691,6 +2060,7 @@ const ( TCOOFF = 0x0 TCOON = 0x1 TCP_CC_INFO = 0x1a + TCP_CM_INQ = 0x24 TCP_CONGESTION = 0xd TCP_COOKIE_IN_ALWAYS = 0x1 TCP_COOKIE_MAX = 0x10 @@ -1702,7 +2072,10 @@ const ( TCP_DEFER_ACCEPT = 0x9 TCP_FASTOPEN = 0x17 TCP_FASTOPEN_CONNECT = 0x1e + TCP_FASTOPEN_KEY = 0x21 + TCP_FASTOPEN_NO_COOKIE = 0x22 TCP_INFO = 0xb + TCP_INQ = 0x24 TCP_KEEPCNT = 0x6 TCP_KEEPIDLE = 0x4 TCP_KEEPINTVL = 0x5 @@ -1711,6 +2084,8 @@ const ( TCP_MAXWIN = 0xffff TCP_MAX_WINSHIFT = 0xe TCP_MD5SIG = 0xe + TCP_MD5SIG_EXT = 0x20 + TCP_MD5SIG_FLAG_PREFIX = 0x1 TCP_MD5SIG_MAXKEYLEN = 0x50 TCP_MSS = 0x200 TCP_MSS_DEFAULT = 0x218 @@ -1720,6 +2095,9 @@ const ( TCP_QUEUE_SEQ = 0x15 TCP_QUICKACK = 0xc TCP_REPAIR = 0x13 + TCP_REPAIR_OFF = 0x0 + TCP_REPAIR_OFF_NO_WP = -0x1 + TCP_REPAIR_ON = 0x1 TCP_REPAIR_OPTIONS = 0x16 TCP_REPAIR_QUEUE = 0x14 TCP_REPAIR_WINDOW = 0x1d @@ -1731,8 +2109,10 @@ const ( TCP_THIN_DUPACK = 0x11 TCP_THIN_LINEAR_TIMEOUTS = 0x10 TCP_TIMESTAMP = 0x18 + TCP_ULP = 0x1f TCP_USER_TIMEOUT = 0x12 TCP_WINDOW_CLAMP = 0xa + TCP_ZEROCOPY_RECEIVE = 0x23 TCSAFLUSH = 0x5410 TCSBRK = 0x5405 TCSBRKP = 0x5486 @@ -1746,6 +2126,7 @@ const ( TCSETSW = 0x540f TCSETSW2 = 0x8030542c TCXONC = 0x5406 + TIMER_ABSTIME = 0x1 TIOCCBRK = 0x5428 TIOCCONS = 0x80047478 TIOCEXCL = 0x740d @@ -1754,6 +2135,7 @@ const ( TIOCGETP = 0x7408 TIOCGEXCL = 0x40045440 TIOCGICOUNT = 0x5492 + TIOCGISO7816 = 0x40285442 TIOCGLCKTRMIOS = 0x548b TIOCGLTC = 0x7474 TIOCGPGRP = 0x40047477 @@ -1810,6 +2192,7 @@ const ( TIOCSETN = 0x740a TIOCSETP = 0x7409 TIOCSIG = 0x80045436 + TIOCSISO7816 = 0xc0285443 TIOCSLCKTRMIOS = 0x548c TIOCSLTC = 0x7475 TIOCSPGRP = 0x80047476 @@ -1820,7 +2203,27 @@ const ( TIOCSTI = 0x5472 TIOCSWINSZ = 0x80087467 TIOCVHANGUP = 0x5437 + TMPFS_MAGIC = 0x1021994 TOSTOP = 0x8000 + TPACKET_ALIGNMENT = 0x10 + TPACKET_HDRLEN = 0x34 + TP_STATUS_AVAILABLE = 0x0 + TP_STATUS_BLK_TMO = 0x20 + TP_STATUS_COPY = 0x2 + TP_STATUS_CSUMNOTREADY = 0x8 + TP_STATUS_CSUM_VALID = 0x80 + TP_STATUS_KERNEL = 0x0 + TP_STATUS_LOSING = 0x4 + TP_STATUS_SENDING = 0x2 + TP_STATUS_SEND_REQUEST = 0x1 + TP_STATUS_TS_RAW_HARDWARE = -0x80000000 + TP_STATUS_TS_SOFTWARE = 0x20000000 + TP_STATUS_TS_SYS_HARDWARE = 0x40000000 + TP_STATUS_USER = 0x1 + TP_STATUS_VLAN_TPID_VALID = 0x40 + TP_STATUS_VLAN_VALID = 0x10 + TP_STATUS_WRONG_FORMAT = 0x4 + TRACEFS_MAGIC = 0x74726163 TS_COMM_LEN = 0x20 TUNATTACHFILTER = 0x801054d5 TUNDETACHFILTER = 0x801054d6 @@ -1832,6 +2235,7 @@ const ( TUNGETVNETHDRSZ = 0x400454d7 TUNGETVNETLE = 0x400454dd TUNSETDEBUG = 0x800454c9 + TUNSETFILTEREBPF = 0x400454e1 TUNSETGROUP = 0x800454ce TUNSETIFF = 0x800454ca TUNSETIFINDEX = 0x800454da @@ -1842,13 +2246,32 @@ const ( TUNSETPERSIST = 0x800454cb TUNSETQUEUE = 0x800454d9 TUNSETSNDBUF = 0x800454d4 + TUNSETSTEERINGEBPF = 0x400454e0 TUNSETTXFILTER = 0x800454d1 TUNSETVNETBE = 0x800454de TUNSETVNETHDRSZ = 0x800454d8 TUNSETVNETLE = 0x800454dc + UBI_IOCATT = 0x80186f40 + UBI_IOCDET = 0x80046f41 + UBI_IOCEBCH = 0x80044f02 + UBI_IOCEBER = 0x80044f01 + UBI_IOCEBISMAP = 0x40044f05 + UBI_IOCEBMAP = 0x80084f03 + UBI_IOCEBUNMAP = 0x80044f04 + UBI_IOCMKVOL = 0x80986f00 + UBI_IOCRMVOL = 0x80046f01 + UBI_IOCRNVOL = 0x91106f03 + UBI_IOCRSVOL = 0x800c6f02 + UBI_IOCSETVOLPROP = 0x80104f06 + UBI_IOCVOLCRBLK = 0x80804f07 + UBI_IOCVOLRMBLK = 0x20004f08 + UBI_IOCVOLUP = 0x80084f00 + UDF_SUPER_MAGIC = 0x15013346 UMOUNT_NOFOLLOW = 0x8 + USBDEVICE_SUPER_MAGIC = 0x9fa2 UTIME_NOW = 0x3fffffff UTIME_OMIT = 0x3ffffffe + V9FS_MAGIC = 0x1021997 VDISCARD = 0xd VEOF = 0x10 VEOL = 0x11 @@ -1891,6 +2314,86 @@ const ( WDIOC_SETPRETIMEOUT = 0xc0045708 WDIOC_SETTIMEOUT = 0xc0045706 WEXITED = 0x4 + WIN_ACKMEDIACHANGE = 0xdb + WIN_CHECKPOWERMODE1 = 0xe5 + WIN_CHECKPOWERMODE2 = 0x98 + WIN_DEVICE_RESET = 0x8 + WIN_DIAGNOSE = 0x90 + WIN_DOORLOCK = 0xde + WIN_DOORUNLOCK = 0xdf + WIN_DOWNLOAD_MICROCODE = 0x92 + WIN_FLUSH_CACHE = 0xe7 + WIN_FLUSH_CACHE_EXT = 0xea + WIN_FORMAT = 0x50 + WIN_GETMEDIASTATUS = 0xda + WIN_IDENTIFY = 0xec + WIN_IDENTIFY_DMA = 0xee + WIN_IDLEIMMEDIATE = 0xe1 + WIN_INIT = 0x60 + WIN_MEDIAEJECT = 0xed + WIN_MULTREAD = 0xc4 + WIN_MULTREAD_EXT = 0x29 + WIN_MULTWRITE = 0xc5 + WIN_MULTWRITE_EXT = 0x39 + WIN_NOP = 0x0 + WIN_PACKETCMD = 0xa0 + WIN_PIDENTIFY = 0xa1 + WIN_POSTBOOT = 0xdc + WIN_PREBOOT = 0xdd + WIN_QUEUED_SERVICE = 0xa2 + WIN_READ = 0x20 + WIN_READDMA = 0xc8 + WIN_READDMA_EXT = 0x25 + WIN_READDMA_ONCE = 0xc9 + WIN_READDMA_QUEUED = 0xc7 + WIN_READDMA_QUEUED_EXT = 0x26 + WIN_READ_BUFFER = 0xe4 + WIN_READ_EXT = 0x24 + WIN_READ_LONG = 0x22 + WIN_READ_LONG_ONCE = 0x23 + WIN_READ_NATIVE_MAX = 0xf8 + WIN_READ_NATIVE_MAX_EXT = 0x27 + WIN_READ_ONCE = 0x21 + WIN_RECAL = 0x10 + WIN_RESTORE = 0x10 + WIN_SECURITY_DISABLE = 0xf6 + WIN_SECURITY_ERASE_PREPARE = 0xf3 + WIN_SECURITY_ERASE_UNIT = 0xf4 + WIN_SECURITY_FREEZE_LOCK = 0xf5 + WIN_SECURITY_SET_PASS = 0xf1 + WIN_SECURITY_UNLOCK = 0xf2 + WIN_SEEK = 0x70 + WIN_SETFEATURES = 0xef + WIN_SETIDLE1 = 0xe3 + WIN_SETIDLE2 = 0x97 + WIN_SETMULT = 0xc6 + WIN_SET_MAX = 0xf9 + WIN_SET_MAX_EXT = 0x37 + WIN_SLEEPNOW1 = 0xe6 + WIN_SLEEPNOW2 = 0x99 + WIN_SMART = 0xb0 + WIN_SPECIFY = 0x91 + WIN_SRST = 0x8 + WIN_STANDBY = 0xe2 + WIN_STANDBY2 = 0x96 + WIN_STANDBYNOW1 = 0xe0 + WIN_STANDBYNOW2 = 0x94 + WIN_VERIFY = 0x40 + WIN_VERIFY_EXT = 0x42 + WIN_VERIFY_ONCE = 0x41 + WIN_WRITE = 0x30 + WIN_WRITEDMA = 0xca + WIN_WRITEDMA_EXT = 0x35 + WIN_WRITEDMA_ONCE = 0xcb + WIN_WRITEDMA_QUEUED = 0xcc + WIN_WRITEDMA_QUEUED_EXT = 0x36 + WIN_WRITE_BUFFER = 0xe8 + WIN_WRITE_EXT = 0x34 + WIN_WRITE_LONG = 0x32 + WIN_WRITE_LONG_ONCE = 0x33 + WIN_WRITE_ONCE = 0x31 + WIN_WRITE_SAME = 0xe9 + WIN_WRITE_VERIFY = 0x3c WNOHANG = 0x1 WNOTHREAD = 0x20000000 WNOWAIT = 0x1000000 @@ -1900,7 +2403,30 @@ const ( XATTR_CREATE = 0x1 XATTR_REPLACE = 0x2 XCASE = 0x4 + XDP_COPY = 0x2 + XDP_FLAGS_DRV_MODE = 0x4 + XDP_FLAGS_HW_MODE = 0x8 + XDP_FLAGS_MASK = 0xf + XDP_FLAGS_MODES = 0xe + XDP_FLAGS_SKB_MODE = 0x2 + XDP_FLAGS_UPDATE_IF_NOEXIST = 0x1 + XDP_MMAP_OFFSETS = 0x1 + XDP_PGOFF_RX_RING = 0x0 + XDP_PGOFF_TX_RING = 0x80000000 + XDP_RX_RING = 0x2 + XDP_SHARED_UMEM = 0x1 + XDP_STATISTICS = 0x7 + XDP_TX_RING = 0x3 + XDP_UMEM_COMPLETION_RING = 0x6 + XDP_UMEM_FILL_RING = 0x5 + XDP_UMEM_PGOFF_COMPLETION_RING = 0x180000000 + XDP_UMEM_PGOFF_FILL_RING = 0x100000000 + XDP_UMEM_REG = 0x4 + XDP_ZEROCOPY = 0x4 + XENFS_SUPER_MAGIC = 0xabba1974 + XFS_SUPER_MAGIC = 0x58465342 XTABS = 0x1800 + ZSMALLOC_MAGIC = 0x58295829 ) // Errors @@ -2082,174 +2608,182 @@ const ( ) // Error table -var errors = [...]string{ - 1: "operation not permitted", - 2: "no such file or directory", - 3: "no such process", - 4: "interrupted system call", - 5: "input/output error", - 6: "no such device or address", - 7: "argument list too long", - 8: "exec format error", - 9: "bad file descriptor", - 10: "no child processes", - 11: "resource temporarily unavailable", - 12: "cannot allocate memory", - 13: "permission denied", - 14: "bad address", - 15: "block device required", - 16: "device or resource busy", - 17: "file exists", - 18: "invalid cross-device link", - 19: "no such device", - 20: "not a directory", - 21: "is a directory", - 22: "invalid argument", - 23: "too many open files in system", - 24: "too many open files", - 25: "inappropriate ioctl for device", - 26: "text file busy", - 27: "file too large", - 28: "no space left on device", - 29: "illegal seek", - 30: "read-only file system", - 31: "too many links", - 32: "broken pipe", - 33: "numerical argument out of domain", - 34: "numerical result out of range", - 35: "no message of desired type", - 36: "identifier removed", - 37: "channel number out of range", - 38: "level 2 not synchronized", - 39: "level 3 halted", - 40: "level 3 reset", - 41: "link number out of range", - 42: "protocol driver not attached", - 43: "no CSI structure available", - 44: "level 2 halted", - 45: "resource deadlock avoided", - 46: "no locks available", - 50: "invalid exchange", - 51: "invalid request descriptor", - 52: "exchange full", - 53: "no anode", - 54: "invalid request code", - 55: "invalid slot", - 56: "file locking deadlock error", - 59: "bad font file format", - 60: "device not a stream", - 61: "no data available", - 62: "timer expired", - 63: "out of streams resources", - 64: "machine is not on the network", - 65: "package not installed", - 66: "object is remote", - 67: "link has been severed", - 68: "advertise error", - 69: "srmount error", - 70: "communication error on send", - 71: "protocol error", - 73: "RFS specific error", - 74: "multihop attempted", - 77: "bad message", - 78: "file name too long", - 79: "value too large for defined data type", - 80: "name not unique on network", - 81: "file descriptor in bad state", - 82: "remote address changed", - 83: "can not access a needed shared library", - 84: "accessing a corrupted shared library", - 85: ".lib section in a.out corrupted", - 86: "attempting to link in too many shared libraries", - 87: "cannot exec a shared library directly", - 88: "invalid or incomplete multibyte or wide character", - 89: "function not implemented", - 90: "too many levels of symbolic links", - 91: "interrupted system call should be restarted", - 92: "streams pipe error", - 93: "directory not empty", - 94: "too many users", - 95: "socket operation on non-socket", - 96: "destination address required", - 97: "message too long", - 98: "protocol wrong type for socket", - 99: "protocol not available", - 120: "protocol not supported", - 121: "socket type not supported", - 122: "operation not supported", - 123: "protocol family not supported", - 124: "address family not supported by protocol", - 125: "address already in use", - 126: "cannot assign requested address", - 127: "network is down", - 128: "network is unreachable", - 129: "network dropped connection on reset", - 130: "software caused connection abort", - 131: "connection reset by peer", - 132: "no buffer space available", - 133: "transport endpoint is already connected", - 134: "transport endpoint is not connected", - 135: "structure needs cleaning", - 137: "not a XENIX named type file", - 138: "no XENIX semaphores available", - 139: "is a named type file", - 140: "remote I/O error", - 141: "unknown error 141", - 142: "unknown error 142", - 143: "cannot send after transport endpoint shutdown", - 144: "too many references: cannot splice", - 145: "connection timed out", - 146: "connection refused", - 147: "host is down", - 148: "no route to host", - 149: "operation already in progress", - 150: "operation now in progress", - 151: "stale file handle", - 158: "operation canceled", - 159: "no medium found", - 160: "wrong medium type", - 161: "required key not available", - 162: "key has expired", - 163: "key has been revoked", - 164: "key was rejected by service", - 165: "owner died", - 166: "state not recoverable", - 167: "operation not possible due to RF-kill", - 168: "memory page has hardware error", - 1133: "disk quota exceeded", +var errorList = [...]struct { + num syscall.Errno + name string + desc string +}{ + {1, "EPERM", "operation not permitted"}, + {2, "ENOENT", "no such file or directory"}, + {3, "ESRCH", "no such process"}, + {4, "EINTR", "interrupted system call"}, + {5, "EIO", "input/output error"}, + {6, "ENXIO", "no such device or address"}, + {7, "E2BIG", "argument list too long"}, + {8, "ENOEXEC", "exec format error"}, + {9, "EBADF", "bad file descriptor"}, + {10, "ECHILD", "no child processes"}, + {11, "EAGAIN", "resource temporarily unavailable"}, + {12, "ENOMEM", "cannot allocate memory"}, + {13, "EACCES", "permission denied"}, + {14, "EFAULT", "bad address"}, + {15, "ENOTBLK", "block device required"}, + {16, "EBUSY", "device or resource busy"}, + {17, "EEXIST", "file exists"}, + {18, "EXDEV", "invalid cross-device link"}, + {19, "ENODEV", "no such device"}, + {20, "ENOTDIR", "not a directory"}, + {21, "EISDIR", "is a directory"}, + {22, "EINVAL", "invalid argument"}, + {23, "ENFILE", "too many open files in system"}, + {24, "EMFILE", "too many open files"}, + {25, "ENOTTY", "inappropriate ioctl for device"}, + {26, "ETXTBSY", "text file busy"}, + {27, "EFBIG", "file too large"}, + {28, "ENOSPC", "no space left on device"}, + {29, "ESPIPE", "illegal seek"}, + {30, "EROFS", "read-only file system"}, + {31, "EMLINK", "too many links"}, + {32, "EPIPE", "broken pipe"}, + {33, "EDOM", "numerical argument out of domain"}, + {34, "ERANGE", "numerical result out of range"}, + {35, "ENOMSG", "no message of desired type"}, + {36, "EIDRM", "identifier removed"}, + {37, "ECHRNG", "channel number out of range"}, + {38, "EL2NSYNC", "level 2 not synchronized"}, + {39, "EL3HLT", "level 3 halted"}, + {40, "EL3RST", "level 3 reset"}, + {41, "ELNRNG", "link number out of range"}, + {42, "EUNATCH", "protocol driver not attached"}, + {43, "ENOCSI", "no CSI structure available"}, + {44, "EL2HLT", "level 2 halted"}, + {45, "EDEADLK", "resource deadlock avoided"}, + {46, "ENOLCK", "no locks available"}, + {50, "EBADE", "invalid exchange"}, + {51, "EBADR", "invalid request descriptor"}, + {52, "EXFULL", "exchange full"}, + {53, "ENOANO", "no anode"}, + {54, "EBADRQC", "invalid request code"}, + {55, "EBADSLT", "invalid slot"}, + {56, "EDEADLOCK", "file locking deadlock error"}, + {59, "EBFONT", "bad font file format"}, + {60, "ENOSTR", "device not a stream"}, + {61, "ENODATA", "no data available"}, + {62, "ETIME", "timer expired"}, + {63, "ENOSR", "out of streams resources"}, + {64, "ENONET", "machine is not on the network"}, + {65, "ENOPKG", "package not installed"}, + {66, "EREMOTE", "object is remote"}, + {67, "ENOLINK", "link has been severed"}, + {68, "EADV", "advertise error"}, + {69, "ESRMNT", "srmount error"}, + {70, "ECOMM", "communication error on send"}, + {71, "EPROTO", "protocol error"}, + {73, "EDOTDOT", "RFS specific error"}, + {74, "EMULTIHOP", "multihop attempted"}, + {77, "EBADMSG", "bad message"}, + {78, "ENAMETOOLONG", "file name too long"}, + {79, "EOVERFLOW", "value too large for defined data type"}, + {80, "ENOTUNIQ", "name not unique on network"}, + {81, "EBADFD", "file descriptor in bad state"}, + {82, "EREMCHG", "remote address changed"}, + {83, "ELIBACC", "can not access a needed shared library"}, + {84, "ELIBBAD", "accessing a corrupted shared library"}, + {85, "ELIBSCN", ".lib section in a.out corrupted"}, + {86, "ELIBMAX", "attempting to link in too many shared libraries"}, + {87, "ELIBEXEC", "cannot exec a shared library directly"}, + {88, "EILSEQ", "invalid or incomplete multibyte or wide character"}, + {89, "ENOSYS", "function not implemented"}, + {90, "ELOOP", "too many levels of symbolic links"}, + {91, "ERESTART", "interrupted system call should be restarted"}, + {92, "ESTRPIPE", "streams pipe error"}, + {93, "ENOTEMPTY", "directory not empty"}, + {94, "EUSERS", "too many users"}, + {95, "ENOTSOCK", "socket operation on non-socket"}, + {96, "EDESTADDRREQ", "destination address required"}, + {97, "EMSGSIZE", "message too long"}, + {98, "EPROTOTYPE", "protocol wrong type for socket"}, + {99, "ENOPROTOOPT", "protocol not available"}, + {120, "EPROTONOSUPPORT", "protocol not supported"}, + {121, "ESOCKTNOSUPPORT", "socket type not supported"}, + {122, "ENOTSUP", "operation not supported"}, + {123, "EPFNOSUPPORT", "protocol family not supported"}, + {124, "EAFNOSUPPORT", "address family not supported by protocol"}, + {125, "EADDRINUSE", "address already in use"}, + {126, "EADDRNOTAVAIL", "cannot assign requested address"}, + {127, "ENETDOWN", "network is down"}, + {128, "ENETUNREACH", "network is unreachable"}, + {129, "ENETRESET", "network dropped connection on reset"}, + {130, "ECONNABORTED", "software caused connection abort"}, + {131, "ECONNRESET", "connection reset by peer"}, + {132, "ENOBUFS", "no buffer space available"}, + {133, "EISCONN", "transport endpoint is already connected"}, + {134, "ENOTCONN", "transport endpoint is not connected"}, + {135, "EUCLEAN", "structure needs cleaning"}, + {137, "ENOTNAM", "not a XENIX named type file"}, + {138, "ENAVAIL", "no XENIX semaphores available"}, + {139, "EISNAM", "is a named type file"}, + {140, "EREMOTEIO", "remote I/O error"}, + {141, "EINIT", "unknown error 141"}, + {142, "EREMDEV", "unknown error 142"}, + {143, "ESHUTDOWN", "cannot send after transport endpoint shutdown"}, + {144, "ETOOMANYREFS", "too many references: cannot splice"}, + {145, "ETIMEDOUT", "connection timed out"}, + {146, "ECONNREFUSED", "connection refused"}, + {147, "EHOSTDOWN", "host is down"}, + {148, "EHOSTUNREACH", "no route to host"}, + {149, "EALREADY", "operation already in progress"}, + {150, "EINPROGRESS", "operation now in progress"}, + {151, "ESTALE", "stale file handle"}, + {158, "ECANCELED", "operation canceled"}, + {159, "ENOMEDIUM", "no medium found"}, + {160, "EMEDIUMTYPE", "wrong medium type"}, + {161, "ENOKEY", "required key not available"}, + {162, "EKEYEXPIRED", "key has expired"}, + {163, "EKEYREVOKED", "key has been revoked"}, + {164, "EKEYREJECTED", "key was rejected by service"}, + {165, "EOWNERDEAD", "owner died"}, + {166, "ENOTRECOVERABLE", "state not recoverable"}, + {167, "ERFKILL", "operation not possible due to RF-kill"}, + {168, "EHWPOISON", "memory page has hardware error"}, + {1133, "EDQUOT", "disk quota exceeded"}, } // Signal table -var signals = [...]string{ - 1: "hangup", - 2: "interrupt", - 3: "quit", - 4: "illegal instruction", - 5: "trace/breakpoint trap", - 6: "aborted", - 7: "EMT trap", - 8: "floating point exception", - 9: "killed", - 10: "bus error", - 11: "segmentation fault", - 12: "bad system call", - 13: "broken pipe", - 14: "alarm clock", - 15: "terminated", - 16: "user defined signal 1", - 17: "user defined signal 2", - 18: "child exited", - 19: "power failure", - 20: "window changed", - 21: "urgent I/O condition", - 22: "I/O possible", - 23: "stopped (signal)", - 24: "stopped", - 25: "continued", - 26: "stopped (tty input)", - 27: "stopped (tty output)", - 28: "virtual timer expired", - 29: "profiling timer expired", - 30: "CPU time limit exceeded", - 31: "file size limit exceeded", +var signalList = [...]struct { + num syscall.Signal + name string + desc string +}{ + {1, "SIGHUP", "hangup"}, + {2, "SIGINT", "interrupt"}, + {3, "SIGQUIT", "quit"}, + {4, "SIGILL", "illegal instruction"}, + {5, "SIGTRAP", "trace/breakpoint trap"}, + {6, "SIGABRT", "aborted"}, + {7, "SIGEMT", "EMT trap"}, + {8, "SIGFPE", "floating point exception"}, + {9, "SIGKILL", "killed"}, + {10, "SIGBUS", "bus error"}, + {11, "SIGSEGV", "segmentation fault"}, + {12, "SIGSYS", "bad system call"}, + {13, "SIGPIPE", "broken pipe"}, + {14, "SIGALRM", "alarm clock"}, + {15, "SIGTERM", "terminated"}, + {16, "SIGUSR1", "user defined signal 1"}, + {17, "SIGUSR2", "user defined signal 2"}, + {18, "SIGCHLD", "child exited"}, + {19, "SIGPWR", "power failure"}, + {20, "SIGWINCH", "window changed"}, + {21, "SIGURG", "urgent I/O condition"}, + {22, "SIGIO", "I/O possible"}, + {23, "SIGSTOP", "stopped (signal)"}, + {24, "SIGTSTP", "stopped"}, + {25, "SIGCONT", "continued"}, + {26, "SIGTTIN", "stopped (tty input)"}, + {27, "SIGTTOU", "stopped (tty output)"}, + {28, "SIGVTALRM", "virtual timer expired"}, + {29, "SIGPROF", "profiling timer expired"}, + {30, "SIGXCPU", "CPU time limit exceeded"}, + {31, "SIGXFSZ", "file size limit exceeded"}, } diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go index 906766254c..7ddd09d782 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go @@ -3,7 +3,7 @@ // +build mipsle,linux -// Created by cgo -godefs - DO NOT EDIT +// Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go package unix @@ -11,6 +11,11 @@ package unix import "syscall" const ( + AAFS_MAGIC = 0x5a3c69f0 + ADFS_SUPER_MAGIC = 0xadf5 + AFFS_SUPER_MAGIC = 0xadff + AFS_FS_MAGIC = 0x6b414653 + AFS_SUPER_MAGIC = 0x5346414f AF_ALG = 0x26 AF_APPLETALK = 0x5 AF_ASH = 0x12 @@ -36,7 +41,7 @@ const ( AF_KEY = 0xf AF_LLC = 0x1a AF_LOCAL = 0x1 - AF_MAX = 0x2c + AF_MAX = 0x2d AF_MPLS = 0x1c AF_NETBEUI = 0xd AF_NETLINK = 0x10 @@ -59,6 +64,7 @@ const ( AF_VSOCK = 0x28 AF_WANPIPE = 0x19 AF_X25 = 0x9 + AF_XDP = 0x2c ALG_OP_DECRYPT = 0x0 ALG_OP_ENCRYPT = 0x1 ALG_SET_AEAD_ASSOCLEN = 0x4 @@ -66,6 +72,7 @@ const ( ALG_SET_IV = 0x2 ALG_SET_KEY = 0x1 ALG_SET_OP = 0x3 + ANON_INODE_FS_MAGIC = 0x9041934 ARPHRD_6LOWPAN = 0x339 ARPHRD_ADAPT = 0x108 ARPHRD_APPLETLK = 0x8 @@ -121,6 +128,7 @@ const ( ARPHRD_PPP = 0x200 ARPHRD_PRONET = 0x4 ARPHRD_RAWHDLC = 0x206 + ARPHRD_RAWIP = 0x207 ARPHRD_ROSE = 0x10e ARPHRD_RSRVD = 0x104 ARPHRD_SIT = 0x308 @@ -132,6 +140,7 @@ const ( ARPHRD_VOID = 0xffff ARPHRD_VSOCKMON = 0x33a ARPHRD_X25 = 0x10f + AUTOFS_SUPER_MAGIC = 0x187 B0 = 0x0 B1000000 = 0x1008 B110 = 0x3 @@ -163,6 +172,9 @@ const ( B75 = 0x2 B921600 = 0x1007 B9600 = 0xd + BALLOON_KVM_MAGIC = 0x13661366 + BDEVFS_MAGIC = 0x62646576 + BINFMTFS_MAGIC = 0x42494e4d BLKBSZGET = 0x40041270 BLKBSZSET = 0x80041271 BLKFLSBUF = 0x20001261 @@ -187,6 +199,7 @@ const ( BPF_AND = 0x50 BPF_B = 0x10 BPF_DIV = 0x30 + BPF_FS_MAGIC = 0xcafe4a11 BPF_H = 0x8 BPF_IMM = 0x0 BPF_IND = 0x40 @@ -228,6 +241,8 @@ const ( BS0 = 0x0 BS1 = 0x2000 BSDLY = 0x2000 + BTRFS_SUPER_MAGIC = 0x9123683e + BTRFS_TEST_MAGIC = 0x73727279 CAN_BCM = 0x2 CAN_EFF_FLAG = 0x80000000 CAN_EFF_ID_BITS = 0x1d @@ -251,6 +266,8 @@ const ( CBAUD = 0x100f CBAUDEX = 0x1000 CFLUSH = 0xf + CGROUP2_SUPER_MAGIC = 0x63677270 + CGROUP_SUPER_MAGIC = 0x27e0eb CIBAUD = 0x100f0000 CLOCAL = 0x800 CLOCK_BOOTTIME = 0x7 @@ -293,10 +310,12 @@ const ( CLONE_VFORK = 0x4000 CLONE_VM = 0x100 CMSPAR = 0x40000000 + CODA_SUPER_MAGIC = 0x73757245 CR0 = 0x0 CR1 = 0x200 CR2 = 0x400 CR3 = 0x600 + CRAMFS_MAGIC = 0x28cd3d45 CRDLY = 0x600 CREAD = 0x80 CRTSCTS = 0x80000000 @@ -311,6 +330,9 @@ const ( CSTOP = 0x13 CSTOPB = 0x40 CSUSP = 0x1a + DAXFS_MAGIC = 0x64646178 + DEBUGFS_MAGIC = 0x64626720 + DEVPTS_SUPER_MAGIC = 0x1cd1 DT_BLK = 0x6 DT_CHR = 0x2 DT_DIR = 0x4 @@ -327,9 +349,12 @@ const ( ECHOKE = 0x800 ECHONL = 0x40 ECHOPRT = 0x400 + ECRYPTFS_SUPER_MAGIC = 0xf15f EFD_CLOEXEC = 0x80000 EFD_NONBLOCK = 0x80 EFD_SEMAPHORE = 0x1 + EFIVARFS_MAGIC = 0xde5e81e4 + EFS_SUPER_MAGIC = 0x414a53 ENCODING_DEFAULT = 0x0 ENCODING_FM_MARK = 0x3 ENCODING_FM_SPACE = 0x4 @@ -390,6 +415,8 @@ const ( ETH_P_DSA = 0x1b ETH_P_ECONET = 0x18 ETH_P_EDSA = 0xdada + ETH_P_ERSPAN = 0x88be + ETH_P_ERSPAN2 = 0x22eb ETH_P_FCOE = 0x8906 ETH_P_FIP = 0x8914 ETH_P_HDLC = 0x19 @@ -398,6 +425,7 @@ const ( ETH_P_IEEE802154 = 0xf6 ETH_P_IEEEPUP = 0xa00 ETH_P_IEEEPUPAT = 0xa01 + ETH_P_IFE = 0xed3e ETH_P_IP = 0x800 ETH_P_IPV6 = 0x86dd ETH_P_IPX = 0x8137 @@ -408,11 +436,13 @@ const ( ETH_P_LOOP = 0x60 ETH_P_LOOPBACK = 0x9000 ETH_P_MACSEC = 0x88e5 + ETH_P_MAP = 0xf9 ETH_P_MOBITEX = 0x15 ETH_P_MPLS_MC = 0x8848 ETH_P_MPLS_UC = 0x8847 ETH_P_MVRP = 0x88f5 ETH_P_NCSI = 0x88f8 + ETH_P_NSH = 0x894f ETH_P_PAE = 0x888e ETH_P_PAUSE = 0x8808 ETH_P_PHONET = 0xf5 @@ -420,6 +450,7 @@ const ( ETH_P_PPP_DISC = 0x8863 ETH_P_PPP_MP = 0x8 ETH_P_PPP_SES = 0x8864 + ETH_P_PREAUTH = 0x88c7 ETH_P_PRP = 0x88fb ETH_P_PUP = 0x200 ETH_P_PUPAT = 0x201 @@ -440,9 +471,14 @@ const ( ETH_P_WCCP = 0x883e ETH_P_X25 = 0x805 ETH_P_XDSA = 0xf8 + EXABYTE_ENABLE_NEST = 0xf0 + EXT2_SUPER_MAGIC = 0xef53 + EXT3_SUPER_MAGIC = 0xef53 + EXT4_SUPER_MAGIC = 0xef53 EXTA = 0xe EXTB = 0xf EXTPROC = 0x10000 + F2FS_SUPER_MAGIC = 0xf2f52010 FALLOC_FL_COLLAPSE_RANGE = 0x8 FALLOC_FL_INSERT_RANGE = 0x20 FALLOC_FL_KEEP_SIZE = 0x1 @@ -463,6 +499,8 @@ const ( FS_ENCRYPTION_MODE_AES_256_GCM = 0x2 FS_ENCRYPTION_MODE_AES_256_XTS = 0x1 FS_ENCRYPTION_MODE_INVALID = 0x0 + FS_ENCRYPTION_MODE_SPECK128_256_CTS = 0x8 + FS_ENCRYPTION_MODE_SPECK128_256_XTS = 0x7 FS_IOC_GET_ENCRYPTION_POLICY = 0x800c6615 FS_IOC_GET_ENCRYPTION_PWSALT = 0x80106614 FS_IOC_SET_ENCRYPTION_POLICY = 0x400c6613 @@ -476,6 +514,8 @@ const ( FS_POLICY_FLAGS_PAD_8 = 0x1 FS_POLICY_FLAGS_PAD_MASK = 0x3 FS_POLICY_FLAGS_VALID = 0x3 + FUTEXFS_SUPER_MAGIC = 0xbad1dea + F_ADD_SEALS = 0x409 F_DUPFD = 0x0 F_DUPFD_CLOEXEC = 0x406 F_EXLCK = 0x4 @@ -488,6 +528,9 @@ const ( F_GETOWN_EX = 0x10 F_GETPIPE_SZ = 0x408 F_GETSIG = 0xb + F_GET_FILE_RW_HINT = 0x40d + F_GET_RW_HINT = 0x40b + F_GET_SEALS = 0x40a F_LOCK = 0x1 F_NOTIFY = 0x402 F_OFD_GETLK = 0x24 @@ -495,6 +538,10 @@ const ( F_OFD_SETLKW = 0x26 F_OK = 0x0 F_RDLCK = 0x0 + F_SEAL_GROW = 0x4 + F_SEAL_SEAL = 0x1 + F_SEAL_SHRINK = 0x2 + F_SEAL_WRITE = 0x8 F_SETFD = 0x2 F_SETFL = 0x4 F_SETLEASE = 0x400 @@ -506,6 +553,8 @@ const ( F_SETOWN_EX = 0xf F_SETPIPE_SZ = 0x407 F_SETSIG = 0xa + F_SET_FILE_RW_HINT = 0x40e + F_SET_RW_HINT = 0x40c F_SHLCK = 0x8 F_TEST = 0x3 F_TLOCK = 0x2 @@ -527,6 +576,49 @@ const ( GENL_UNS_ADMIN_PERM = 0x10 GRND_NONBLOCK = 0x1 GRND_RANDOM = 0x2 + HDIO_DRIVE_CMD = 0x31f + HDIO_DRIVE_CMD_AEB = 0x31e + HDIO_DRIVE_CMD_HDR_SIZE = 0x4 + HDIO_DRIVE_HOB_HDR_SIZE = 0x8 + HDIO_DRIVE_RESET = 0x31c + HDIO_DRIVE_TASK = 0x31e + HDIO_DRIVE_TASKFILE = 0x31d + HDIO_DRIVE_TASK_HDR_SIZE = 0x8 + HDIO_GETGEO = 0x301 + HDIO_GET_32BIT = 0x309 + HDIO_GET_ACOUSTIC = 0x30f + HDIO_GET_ADDRESS = 0x310 + HDIO_GET_BUSSTATE = 0x31a + HDIO_GET_DMA = 0x30b + HDIO_GET_IDENTITY = 0x30d + HDIO_GET_KEEPSETTINGS = 0x308 + HDIO_GET_MULTCOUNT = 0x304 + HDIO_GET_NICE = 0x30c + HDIO_GET_NOWERR = 0x30a + HDIO_GET_QDMA = 0x305 + HDIO_GET_UNMASKINTR = 0x302 + HDIO_GET_WCACHE = 0x30e + HDIO_OBSOLETE_IDENTITY = 0x307 + HDIO_SCAN_HWIF = 0x328 + HDIO_SET_32BIT = 0x324 + HDIO_SET_ACOUSTIC = 0x32c + HDIO_SET_ADDRESS = 0x32f + HDIO_SET_BUSSTATE = 0x32d + HDIO_SET_DMA = 0x326 + HDIO_SET_KEEPSETTINGS = 0x323 + HDIO_SET_MULTCOUNT = 0x321 + HDIO_SET_NICE = 0x329 + HDIO_SET_NOWERR = 0x325 + HDIO_SET_PIO_MODE = 0x327 + HDIO_SET_QDMA = 0x32e + HDIO_SET_UNMASKINTR = 0x322 + HDIO_SET_WCACHE = 0x32b + HDIO_SET_XFER = 0x306 + HDIO_TRISTATE_HWIF = 0x31b + HDIO_UNREGISTER_HWIF = 0x32a + HOSTFS_SUPER_MAGIC = 0xc0ffee + HPFS_SUPER_MAGIC = 0xf995e849 + HUGETLBFS_MAGIC = 0x958458f6 HUPCL = 0x400 IBSHIFT = 0x10 ICANON = 0x2 @@ -546,7 +638,7 @@ const ( IFA_F_STABLE_PRIVACY = 0x800 IFA_F_TEMPORARY = 0x1 IFA_F_TENTATIVE = 0x40 - IFA_MAX = 0x8 + IFA_MAX = 0xa IFF_ALLMULTI = 0x200 IFF_ATTACH_QUEUE = 0x200 IFF_AUTOMEDIA = 0x4000 @@ -561,6 +653,8 @@ const ( IFF_MASTER = 0x400 IFF_MULTICAST = 0x1000 IFF_MULTI_QUEUE = 0x100 + IFF_NAPI = 0x10 + IFF_NAPI_FRAGS = 0x20 IFF_NOARP = 0x80 IFF_NOFILTER = 0x1000 IFF_NOTRAILERS = 0x20 @@ -612,6 +706,7 @@ const ( IN_ISDIR = 0x40000000 IN_LOOPBACKNET = 0x7f IN_MASK_ADD = 0x20000000 + IN_MASK_CREATE = 0x10000000 IN_MODIFY = 0x2 IN_MOVE = 0xc0 IN_MOVED_FROM = 0x40 @@ -671,6 +766,7 @@ const ( IPV6_DONTFRAG = 0x3e IPV6_DROP_MEMBERSHIP = 0x15 IPV6_DSTOPTS = 0x3b + IPV6_FREEBIND = 0x4e IPV6_HDRINCL = 0x24 IPV6_HOPLIMIT = 0x34 IPV6_HOPOPTS = 0x36 @@ -682,6 +778,7 @@ const ( IPV6_MINHOPCOUNT = 0x49 IPV6_MTU = 0x18 IPV6_MTU_DISCOVER = 0x17 + IPV6_MULTICAST_ALL = 0x1d IPV6_MULTICAST_HOPS = 0x12 IPV6_MULTICAST_IF = 0x11 IPV6_MULTICAST_LOOP = 0x13 @@ -775,12 +872,34 @@ const ( IP_UNICAST_IF = 0x32 IP_XFRM_POLICY = 0x11 ISIG = 0x1 + ISOFS_SUPER_MAGIC = 0x9660 ISTRIP = 0x20 IUCLC = 0x200 IUTF8 = 0x4000 IXANY = 0x800 IXOFF = 0x1000 IXON = 0x400 + JFFS2_SUPER_MAGIC = 0x72b6 + KEXEC_ARCH_386 = 0x30000 + KEXEC_ARCH_68K = 0x40000 + KEXEC_ARCH_AARCH64 = 0xb70000 + KEXEC_ARCH_ARM = 0x280000 + KEXEC_ARCH_DEFAULT = 0x0 + KEXEC_ARCH_IA_64 = 0x320000 + KEXEC_ARCH_MASK = 0xffff0000 + KEXEC_ARCH_MIPS = 0x80000 + KEXEC_ARCH_MIPS_LE = 0xa0000 + KEXEC_ARCH_PPC = 0x140000 + KEXEC_ARCH_PPC64 = 0x150000 + KEXEC_ARCH_S390 = 0x160000 + KEXEC_ARCH_SH = 0x2a0000 + KEXEC_ARCH_X86_64 = 0x3e0000 + KEXEC_FILE_NO_INITRAMFS = 0x4 + KEXEC_FILE_ON_CRASH = 0x2 + KEXEC_FILE_UNLOAD = 0x1 + KEXEC_ON_CRASH = 0x1 + KEXEC_PRESERVE_CONTEXT = 0x2 + KEXEC_SEGMENT_MAX = 0x10 KEYCTL_ASSUME_AUTHORITY = 0x10 KEYCTL_CHOWN = 0x4 KEYCTL_CLEAR = 0x7 @@ -795,6 +914,11 @@ const ( KEYCTL_JOIN_SESSION_KEYRING = 0x1 KEYCTL_LINK = 0x8 KEYCTL_NEGATE = 0xd + KEYCTL_PKEY_DECRYPT = 0x1a + KEYCTL_PKEY_ENCRYPT = 0x19 + KEYCTL_PKEY_QUERY = 0x18 + KEYCTL_PKEY_SIGN = 0x1b + KEYCTL_PKEY_VERIFY = 0x1c KEYCTL_READ = 0xb KEYCTL_REJECT = 0x13 KEYCTL_RESTRICT_KEYRING = 0x1d @@ -804,6 +928,10 @@ const ( KEYCTL_SETPERM = 0x5 KEYCTL_SET_REQKEY_KEYRING = 0xe KEYCTL_SET_TIMEOUT = 0xf + KEYCTL_SUPPORTS_DECRYPT = 0x2 + KEYCTL_SUPPORTS_ENCRYPT = 0x1 + KEYCTL_SUPPORTS_SIGN = 0x4 + KEYCTL_SUPPORTS_VERIFY = 0x8 KEYCTL_UNLINK = 0x9 KEYCTL_UPDATE = 0x2 KEY_REQKEY_DEFL_DEFAULT = 0x0 @@ -845,6 +973,7 @@ const ( MADV_FREE = 0x8 MADV_HUGEPAGE = 0xe MADV_HWPOISON = 0x64 + MADV_KEEPONFORK = 0x13 MADV_MERGEABLE = 0xc MADV_NOHUGEPAGE = 0xf MADV_NORMAL = 0x0 @@ -853,12 +982,14 @@ const ( MADV_SEQUENTIAL = 0x2 MADV_UNMERGEABLE = 0xd MADV_WILLNEED = 0x3 + MADV_WIPEONFORK = 0x12 MAP_ANON = 0x800 MAP_ANONYMOUS = 0x800 MAP_DENYWRITE = 0x2000 MAP_EXECUTABLE = 0x4000 MAP_FILE = 0x0 MAP_FIXED = 0x10 + MAP_FIXED_NOREPLACE = 0x100000 MAP_GROWSDOWN = 0x1000 MAP_HUGETLB = 0x80000 MAP_HUGE_MASK = 0x3f @@ -870,14 +1001,40 @@ const ( MAP_PRIVATE = 0x2 MAP_RENAME = 0x800 MAP_SHARED = 0x1 + MAP_SHARED_VALIDATE = 0x3 MAP_STACK = 0x40000 MAP_TYPE = 0xf MCL_CURRENT = 0x1 MCL_FUTURE = 0x2 MCL_ONFAULT = 0x4 + MFD_ALLOW_SEALING = 0x2 + MFD_CLOEXEC = 0x1 + MFD_HUGETLB = 0x4 + MFD_HUGE_16GB = -0x78000000 + MFD_HUGE_16MB = 0x60000000 + MFD_HUGE_1GB = 0x78000000 + MFD_HUGE_1MB = 0x50000000 + MFD_HUGE_256MB = 0x70000000 + MFD_HUGE_2GB = 0x7c000000 + MFD_HUGE_2MB = 0x54000000 + MFD_HUGE_32MB = 0x64000000 + MFD_HUGE_512KB = 0x4c000000 + MFD_HUGE_512MB = 0x74000000 + MFD_HUGE_64KB = 0x40000000 + MFD_HUGE_8MB = 0x5c000000 + MFD_HUGE_MASK = 0x3f + MFD_HUGE_SHIFT = 0x1a + MINIX2_SUPER_MAGIC = 0x2468 + MINIX2_SUPER_MAGIC2 = 0x2478 + MINIX3_SUPER_MAGIC = 0x4d5a + MINIX_SUPER_MAGIC = 0x137f + MINIX_SUPER_MAGIC2 = 0x138f MNT_DETACH = 0x2 MNT_EXPIRE = 0x4 MNT_FORCE = 0x1 + MODULE_INIT_IGNORE_MODVERSIONS = 0x1 + MODULE_INIT_IGNORE_VERMAGIC = 0x2 + MSDOS_SUPER_MAGIC = 0x4d44 MSG_BATCH = 0x40000 MSG_CMSG_CLOEXEC = 0x40000000 MSG_CONFIRM = 0x800 @@ -899,6 +1056,7 @@ const ( MSG_TRYHARD = 0x4 MSG_WAITALL = 0x100 MSG_WAITFORONE = 0x10000 + MSG_ZEROCOPY = 0x4000000 MS_ACTIVE = 0x40000000 MS_ASYNC = 0x1 MS_BIND = 0x1000 @@ -936,7 +1094,9 @@ const ( MS_SYNCHRONOUS = 0x10 MS_UNBINDABLE = 0x20000 MS_VERBOSE = 0x8000 + MTD_INODE_FS_MAGIC = 0x11307854 NAME_MAX = 0xff + NCP_SUPER_MAGIC = 0x564c NETLINK_ADD_MEMBERSHIP = 0x1 NETLINK_AUDIT = 0x9 NETLINK_BROADCAST_ERROR = 0x4 @@ -950,6 +1110,7 @@ const ( NETLINK_FIB_LOOKUP = 0xa NETLINK_FIREWALL = 0x3 NETLINK_GENERIC = 0x10 + NETLINK_GET_STRICT_CHK = 0xc NETLINK_INET_DIAG = 0x4 NETLINK_IP6_FW = 0xd NETLINK_ISCSI = 0x8 @@ -971,6 +1132,39 @@ const ( NETLINK_UNUSED = 0x1 NETLINK_USERSOCK = 0x2 NETLINK_XFRM = 0x6 + NETNSA_MAX = 0x3 + NETNSA_NSID_NOT_ASSIGNED = -0x1 + NFNETLINK_V0 = 0x0 + NFNLGRP_ACCT_QUOTA = 0x8 + NFNLGRP_CONNTRACK_DESTROY = 0x3 + NFNLGRP_CONNTRACK_EXP_DESTROY = 0x6 + NFNLGRP_CONNTRACK_EXP_NEW = 0x4 + NFNLGRP_CONNTRACK_EXP_UPDATE = 0x5 + NFNLGRP_CONNTRACK_NEW = 0x1 + NFNLGRP_CONNTRACK_UPDATE = 0x2 + NFNLGRP_MAX = 0x9 + NFNLGRP_NFTABLES = 0x7 + NFNLGRP_NFTRACE = 0x9 + NFNLGRP_NONE = 0x0 + NFNL_BATCH_MAX = 0x1 + NFNL_MSG_BATCH_BEGIN = 0x10 + NFNL_MSG_BATCH_END = 0x11 + NFNL_NFA_NEST = 0x8000 + NFNL_SUBSYS_ACCT = 0x7 + NFNL_SUBSYS_COUNT = 0xc + NFNL_SUBSYS_CTHELPER = 0x9 + NFNL_SUBSYS_CTNETLINK = 0x1 + NFNL_SUBSYS_CTNETLINK_EXP = 0x2 + NFNL_SUBSYS_CTNETLINK_TIMEOUT = 0x8 + NFNL_SUBSYS_IPSET = 0x6 + NFNL_SUBSYS_NFTABLES = 0xa + NFNL_SUBSYS_NFT_COMPAT = 0xb + NFNL_SUBSYS_NONE = 0x0 + NFNL_SUBSYS_OSF = 0x5 + NFNL_SUBSYS_QUEUE = 0x3 + NFNL_SUBSYS_ULOG = 0x4 + NFS_SUPER_MAGIC = 0x6969 + NILFS_SUPER_MAGIC = 0x3434 NL0 = 0x0 NL1 = 0x100 NLA_ALIGNTO = 0x4 @@ -998,10 +1192,13 @@ const ( NLM_F_EXCL = 0x200 NLM_F_MATCH = 0x200 NLM_F_MULTI = 0x2 + NLM_F_NONREC = 0x100 NLM_F_REPLACE = 0x100 NLM_F_REQUEST = 0x1 NLM_F_ROOT = 0x100 NOFLSH = 0x80 + NSFS_MAGIC = 0x6e736673 + OCFS2_SUPER_MAGIC = 0x7461636f OCRNL = 0x8 OFDEL = 0x80 OFILL = 0x40 @@ -1009,7 +1206,9 @@ const ( ONLCR = 0x4 ONLRET = 0x20 ONOCR = 0x10 + OPENPROM_SUPER_MAGIC = 0x9fa1 OPOST = 0x1 + OVERLAYFS_SUPER_MAGIC = 0x794c7630 O_ACCMODE = 0x3 O_APPEND = 0x8 O_ASYNC = 0x1000 @@ -1055,6 +1254,7 @@ const ( PACKET_FASTROUTE = 0x6 PACKET_HDRLEN = 0xb PACKET_HOST = 0x0 + PACKET_IGNORE_OUTGOING = 0x17 PACKET_KERNEL = 0x7 PACKET_LOOPBACK = 0x5 PACKET_LOSS = 0xe @@ -1094,16 +1294,50 @@ const ( PERF_EVENT_IOC_DISABLE = 0x20002401 PERF_EVENT_IOC_ENABLE = 0x20002400 PERF_EVENT_IOC_ID = 0x40042407 + PERF_EVENT_IOC_MODIFY_ATTRIBUTES = 0x8004240b PERF_EVENT_IOC_PAUSE_OUTPUT = 0x80042409 PERF_EVENT_IOC_PERIOD = 0x80082404 + PERF_EVENT_IOC_QUERY_BPF = 0xc004240a PERF_EVENT_IOC_REFRESH = 0x20002402 PERF_EVENT_IOC_RESET = 0x20002403 PERF_EVENT_IOC_SET_BPF = 0x80042408 PERF_EVENT_IOC_SET_FILTER = 0x80042406 PERF_EVENT_IOC_SET_OUTPUT = 0x20002405 + PIPEFS_MAGIC = 0x50495045 + PPPIOCATTACH = 0x8004743d + PPPIOCATTCHAN = 0x80047438 + PPPIOCCONNECT = 0x8004743a + PPPIOCDETACH = 0x8004743c + PPPIOCDISCONN = 0x20007439 + PPPIOCGASYNCMAP = 0x40047458 + PPPIOCGCHAN = 0x40047437 + PPPIOCGDEBUG = 0x40047441 + PPPIOCGFLAGS = 0x4004745a + PPPIOCGIDLE = 0x4008743f + PPPIOCGL2TPSTATS = 0x40487436 + PPPIOCGMRU = 0x40047453 + PPPIOCGNPMODE = 0xc008744c + PPPIOCGRASYNCMAP = 0x40047455 + PPPIOCGUNIT = 0x40047456 + PPPIOCGXASYNCMAP = 0x40207450 + PPPIOCNEWUNIT = 0xc004743e + PPPIOCSACTIVE = 0x80087446 + PPPIOCSASYNCMAP = 0x80047457 + PPPIOCSCOMPRESS = 0x800c744d + PPPIOCSDEBUG = 0x80047440 + PPPIOCSFLAGS = 0x80047459 + PPPIOCSMAXCID = 0x80047451 + PPPIOCSMRRU = 0x8004743b + PPPIOCSMRU = 0x80047452 + PPPIOCSNPMODE = 0x8008744b + PPPIOCSPASS = 0x80087447 + PPPIOCSRASYNCMAP = 0x80047454 + PPPIOCSXASYNCMAP = 0x8020744f + PPPIOCXFERUNIT = 0x2000744e PRIO_PGRP = 0x1 PRIO_PROCESS = 0x0 PRIO_USER = 0x2 + PROC_SUPER_MAGIC = 0x9fa0 PROT_EXEC = 0x4 PROT_GROWSDOWN = 0x1000000 PROT_GROWSUP = 0x2000000 @@ -1146,6 +1380,7 @@ const ( PR_GET_PDEATHSIG = 0x2 PR_GET_SECCOMP = 0x15 PR_GET_SECUREBITS = 0x1b + PR_GET_SPECULATION_CTRL = 0x34 PR_GET_THP_DISABLE = 0x2a PR_GET_TID_ADDRESS = 0x28 PR_GET_TIMERSLACK = 0x1e @@ -1191,11 +1426,24 @@ const ( PR_SET_PTRACER_ANY = 0xffffffff PR_SET_SECCOMP = 0x16 PR_SET_SECUREBITS = 0x1c + PR_SET_SPECULATION_CTRL = 0x35 PR_SET_THP_DISABLE = 0x29 PR_SET_TIMERSLACK = 0x1d PR_SET_TIMING = 0xe PR_SET_TSC = 0x1a PR_SET_UNALIGN = 0x6 + PR_SPEC_DISABLE = 0x4 + PR_SPEC_ENABLE = 0x2 + PR_SPEC_FORCE_DISABLE = 0x8 + PR_SPEC_INDIRECT_BRANCH = 0x1 + PR_SPEC_NOT_AFFECTED = 0x0 + PR_SPEC_PRCTL = 0x1 + PR_SPEC_STORE_BYPASS = 0x0 + PR_SVE_GET_VL = 0x33 + PR_SVE_SET_VL = 0x32 + PR_SVE_SET_VL_ONEXEC = 0x40000 + PR_SVE_VL_INHERIT = 0x20000 + PR_SVE_VL_LEN_MASK = 0xffff PR_TASK_PERF_EVENTS_DISABLE = 0x1f PR_TASK_PERF_EVENTS_ENABLE = 0x20 PR_TIMING_STATISTICAL = 0x0 @@ -1204,6 +1452,7 @@ const ( PR_TSC_SIGSEGV = 0x2 PR_UNALIGN_NOPRINT = 0x1 PR_UNALIGN_SIGBUS = 0x2 + PSTOREFS_MAGIC = 0x6165676c PTRACE_ATTACH = 0x10 PTRACE_CONT = 0x7 PTRACE_DETACH = 0x11 @@ -1252,6 +1501,7 @@ const ( PTRACE_POKETEXT_3264 = 0xc2 PTRACE_POKEUSR = 0x6 PTRACE_SECCOMP_GET_FILTER = 0x420c + PTRACE_SECCOMP_GET_METADATA = 0x420d PTRACE_SEIZE = 0x4206 PTRACE_SETFPREGS = 0xf PTRACE_SETOPTIONS = 0x4200 @@ -1264,6 +1514,14 @@ const ( PTRACE_SINGLESTEP = 0x9 PTRACE_SYSCALL = 0x18 PTRACE_TRACEME = 0x0 + QNX4_SUPER_MAGIC = 0x2f + QNX6_SUPER_MAGIC = 0x68191122 + RAMFS_MAGIC = 0x858458f6 + RDTGROUP_SUPER_MAGIC = 0x7655821 + REISERFS_SUPER_MAGIC = 0x52654973 + RENAME_EXCHANGE = 0x2 + RENAME_NOREPLACE = 0x1 + RENAME_WHITEOUT = 0x4 RLIMIT_AS = 0x6 RLIMIT_CORE = 0x4 RLIMIT_CPU = 0x0 @@ -1281,9 +1539,17 @@ const ( RLIMIT_SIGPENDING = 0xb RLIMIT_STACK = 0x3 RLIM_INFINITY = 0xffffffffffffffff + RNDADDENTROPY = 0x80085203 + RNDADDTOENTCNT = 0x80045201 + RNDCLEARPOOL = 0x20005206 + RNDGETENTCNT = 0x40045200 + RNDGETPOOL = 0x40085202 + RNDRESEEDCRNG = 0x20005207 + RNDZAPENTCNT = 0x20005204 RTAX_ADVMSS = 0x8 RTAX_CC_ALGO = 0x10 RTAX_CWND = 0x7 + RTAX_FASTOPEN_NO_COOKIE = 0x11 RTAX_FEATURES = 0xc RTAX_FEATURE_ALLFRAG = 0x8 RTAX_FEATURE_ECN = 0x1 @@ -1294,7 +1560,7 @@ const ( RTAX_INITCWND = 0xb RTAX_INITRWND = 0xe RTAX_LOCK = 0x1 - RTAX_MAX = 0x10 + RTAX_MAX = 0x11 RTAX_MTU = 0x2 RTAX_QUICKACK = 0xf RTAX_REORDERING = 0x9 @@ -1305,13 +1571,40 @@ const ( RTAX_UNSPEC = 0x0 RTAX_WINDOW = 0x3 RTA_ALIGNTO = 0x4 - RTA_MAX = 0x1a + RTA_MAX = 0x1d RTCF_DIRECTSRC = 0x4000000 RTCF_DOREDIRECT = 0x1000000 RTCF_LOG = 0x2000000 RTCF_MASQ = 0x400000 RTCF_NAT = 0x800000 RTCF_VALVE = 0x200000 + RTC_AF = 0x20 + RTC_AIE_OFF = 0x20007002 + RTC_AIE_ON = 0x20007001 + RTC_ALM_READ = 0x40247008 + RTC_ALM_SET = 0x80247007 + RTC_EPOCH_READ = 0x4004700d + RTC_EPOCH_SET = 0x8004700e + RTC_IRQF = 0x80 + RTC_IRQP_READ = 0x4004700b + RTC_IRQP_SET = 0x8004700c + RTC_MAX_FREQ = 0x2000 + RTC_PF = 0x40 + RTC_PIE_OFF = 0x20007006 + RTC_PIE_ON = 0x20007005 + RTC_PLL_GET = 0x401c7011 + RTC_PLL_SET = 0x801c7012 + RTC_RD_TIME = 0x40247009 + RTC_SET_TIME = 0x8024700a + RTC_UF = 0x10 + RTC_UIE_OFF = 0x20007004 + RTC_UIE_ON = 0x20007003 + RTC_VL_CLR = 0x20007014 + RTC_VL_READ = 0x40047013 + RTC_WIE_OFF = 0x20007010 + RTC_WIE_ON = 0x2000700f + RTC_WKALM_RD = 0x40287010 + RTC_WKALM_SET = 0x8028700f RTF_ADDRCLASSMASK = 0xf8000000 RTF_ADDRCONF = 0x40000 RTF_ALLONLINK = 0x20000 @@ -1346,6 +1639,7 @@ const ( RTM_DELACTION = 0x31 RTM_DELADDR = 0x15 RTM_DELADDRLABEL = 0x49 + RTM_DELCHAIN = 0x65 RTM_DELLINK = 0x11 RTM_DELMDB = 0x55 RTM_DELNEIGH = 0x1d @@ -1366,6 +1660,7 @@ const ( RTM_GETADDR = 0x16 RTM_GETADDRLABEL = 0x4a RTM_GETANYCAST = 0x3e + RTM_GETCHAIN = 0x66 RTM_GETDCB = 0x4e RTM_GETLINK = 0x12 RTM_GETMDB = 0x56 @@ -1380,11 +1675,12 @@ const ( RTM_GETSTATS = 0x5e RTM_GETTCLASS = 0x2a RTM_GETTFILTER = 0x2e - RTM_MAX = 0x63 + RTM_MAX = 0x67 RTM_NEWACTION = 0x30 RTM_NEWADDR = 0x14 RTM_NEWADDRLABEL = 0x48 RTM_NEWCACHEREPORT = 0x60 + RTM_NEWCHAIN = 0x64 RTM_NEWLINK = 0x10 RTM_NEWMDB = 0x54 RTM_NEWNDUSEROPT = 0x44 @@ -1399,8 +1695,8 @@ const ( RTM_NEWSTATS = 0x5c RTM_NEWTCLASS = 0x28 RTM_NEWTFILTER = 0x2c - RTM_NR_FAMILIES = 0x15 - RTM_NR_MSGTYPES = 0x54 + RTM_NR_FAMILIES = 0x16 + RTM_NR_MSGTYPES = 0x58 RTM_SETDCB = 0x4f RTM_SETLINK = 0x13 RTM_SETNEIGHTBL = 0x43 @@ -1414,17 +1710,22 @@ const ( RTNH_F_UNRESOLVED = 0x20 RTN_MAX = 0xb RTPROT_BABEL = 0x2a + RTPROT_BGP = 0xba RTPROT_BIRD = 0xc RTPROT_BOOT = 0x3 RTPROT_DHCP = 0x10 RTPROT_DNROUTED = 0xd + RTPROT_EIGRP = 0xc0 RTPROT_GATED = 0x8 + RTPROT_ISIS = 0xbb RTPROT_KERNEL = 0x2 RTPROT_MROUTED = 0x11 RTPROT_MRT = 0xa RTPROT_NTK = 0xf + RTPROT_OSPF = 0xbc RTPROT_RA = 0x9 RTPROT_REDIRECT = 0x1 + RTPROT_RIP = 0xbd RTPROT_STATIC = 0x4 RTPROT_UNSPEC = 0x0 RTPROT_XORP = 0xe @@ -1444,10 +1745,16 @@ const ( SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SC_LOG_FLUSH = 0x100000 SECCOMP_MODE_DISABLED = 0x0 SECCOMP_MODE_FILTER = 0x2 SECCOMP_MODE_STRICT = 0x1 + SECURITYFS_MAGIC = 0x73636673 + SELINUX_MAGIC = 0xf97cff8c + SFD_CLOEXEC = 0x80000 + SFD_NONBLOCK = 0x80 SHUT_RD = 0x0 SHUT_RDWR = 0x2 SHUT_WR = 0x1 @@ -1498,6 +1805,9 @@ const ( SIOCGMIIPHY = 0x8947 SIOCGMIIREG = 0x8948 SIOCGPGRP = 0x40047309 + SIOCGPPPCSTATS = 0x89f2 + SIOCGPPPSTATS = 0x89f0 + SIOCGPPPVER = 0x89f1 SIOCGRARP = 0x8961 SIOCGSKNS = 0x894c SIOCGSTAMP = 0x8906 @@ -1532,6 +1842,23 @@ const ( SIOCSPGRP = 0x80047308 SIOCSRARP = 0x8962 SIOCWANDEV = 0x894a + SMACK_MAGIC = 0x43415d53 + SMART_AUTOSAVE = 0xd2 + SMART_AUTO_OFFLINE = 0xdb + SMART_DISABLE = 0xd9 + SMART_ENABLE = 0xd8 + SMART_HCYL_PASS = 0xc2 + SMART_IMMEDIATE_OFFLINE = 0xd4 + SMART_LCYL_PASS = 0x4f + SMART_READ_LOG_SECTOR = 0xd5 + SMART_READ_THRESHOLDS = 0xd1 + SMART_READ_VALUES = 0xd0 + SMART_SAVE = 0xd3 + SMART_STATUS = 0xda + SMART_WRITE_LOG_SECTOR = 0xd6 + SMART_WRITE_THRESHOLDS = 0xd7 + SMB_SUPER_MAGIC = 0x517b + SOCKFS_MAGIC = 0x534f434b SOCK_CLOEXEC = 0x80000 SOCK_DCCP = 0x6 SOCK_DGRAM = 0x1 @@ -1568,7 +1895,9 @@ const ( SOL_SOCKET = 0xffff SOL_TCP = 0x6 SOL_TIPC = 0x10f + SOL_TLS = 0x11a SOL_X25 = 0x106 + SOL_XDP = 0x11b SOMAXCONN = 0x80 SO_ACCEPTCONN = 0x1009 SO_ATTACH_BPF = 0x32 @@ -1587,6 +1916,17 @@ const ( SO_DETACH_FILTER = 0x1b SO_DOMAIN = 0x1029 SO_DONTROUTE = 0x10 + SO_EE_CODE_TXTIME_INVALID_PARAM = 0x1 + SO_EE_CODE_TXTIME_MISSED = 0x2 + SO_EE_CODE_ZEROCOPY_COPIED = 0x1 + SO_EE_ORIGIN_ICMP = 0x2 + SO_EE_ORIGIN_ICMP6 = 0x3 + SO_EE_ORIGIN_LOCAL = 0x1 + SO_EE_ORIGIN_NONE = 0x0 + SO_EE_ORIGIN_TIMESTAMPING = 0x4 + SO_EE_ORIGIN_TXSTATUS = 0x4 + SO_EE_ORIGIN_TXTIME = 0x6 + SO_EE_ORIGIN_ZEROCOPY = 0x5 SO_ERROR = 0x1007 SO_GET_FILTER = 0x1a SO_INCOMING_CPU = 0x31 @@ -1628,6 +1968,7 @@ const ( SO_TIMESTAMP = 0x1d SO_TIMESTAMPING = 0x25 SO_TIMESTAMPNS = 0x23 + SO_TXTIME = 0x3d SO_TYPE = 0x1008 SO_VM_SOCKETS_BUFFER_MAX_SIZE = 0x2 SO_VM_SOCKETS_BUFFER_MIN_SIZE = 0x1 @@ -1637,10 +1978,38 @@ const ( SO_VM_SOCKETS_PEER_HOST_VM_ID = 0x3 SO_VM_SOCKETS_TRUSTED = 0x5 SO_WIFI_STATUS = 0x29 + SO_ZEROCOPY = 0x3c SPLICE_F_GIFT = 0x8 SPLICE_F_MORE = 0x4 SPLICE_F_MOVE = 0x1 SPLICE_F_NONBLOCK = 0x2 + SQUASHFS_MAGIC = 0x73717368 + STACK_END_MAGIC = 0x57ac6e9d + STATX_ALL = 0xfff + STATX_ATIME = 0x20 + STATX_ATTR_APPEND = 0x20 + STATX_ATTR_AUTOMOUNT = 0x1000 + STATX_ATTR_COMPRESSED = 0x4 + STATX_ATTR_ENCRYPTED = 0x800 + STATX_ATTR_IMMUTABLE = 0x10 + STATX_ATTR_NODUMP = 0x40 + STATX_BASIC_STATS = 0x7ff + STATX_BLOCKS = 0x400 + STATX_BTIME = 0x800 + STATX_CTIME = 0x80 + STATX_GID = 0x10 + STATX_INO = 0x100 + STATX_MODE = 0x2 + STATX_MTIME = 0x40 + STATX_NLINK = 0x4 + STATX_SIZE = 0x200 + STATX_TYPE = 0x1 + STATX_UID = 0x8 + STATX__RESERVED = 0x80000000 + SYNC_FILE_RANGE_WAIT_AFTER = 0x4 + SYNC_FILE_RANGE_WAIT_BEFORE = 0x1 + SYNC_FILE_RANGE_WRITE = 0x2 + SYSFS_MAGIC = 0x62656572 S_BLKSIZE = 0x200 S_IEXEC = 0x40 S_IFBLK = 0x6000 @@ -1678,7 +2047,7 @@ const ( TASKSTATS_GENL_NAME = "TASKSTATS" TASKSTATS_GENL_VERSION = 0x1 TASKSTATS_TYPE_MAX = 0x6 - TASKSTATS_VERSION = 0x8 + TASKSTATS_VERSION = 0x9 TCFLSH = 0x5407 TCGETA = 0x5401 TCGETS = 0x540d @@ -1691,6 +2060,7 @@ const ( TCOOFF = 0x0 TCOON = 0x1 TCP_CC_INFO = 0x1a + TCP_CM_INQ = 0x24 TCP_CONGESTION = 0xd TCP_COOKIE_IN_ALWAYS = 0x1 TCP_COOKIE_MAX = 0x10 @@ -1702,7 +2072,10 @@ const ( TCP_DEFER_ACCEPT = 0x9 TCP_FASTOPEN = 0x17 TCP_FASTOPEN_CONNECT = 0x1e + TCP_FASTOPEN_KEY = 0x21 + TCP_FASTOPEN_NO_COOKIE = 0x22 TCP_INFO = 0xb + TCP_INQ = 0x24 TCP_KEEPCNT = 0x6 TCP_KEEPIDLE = 0x4 TCP_KEEPINTVL = 0x5 @@ -1711,6 +2084,8 @@ const ( TCP_MAXWIN = 0xffff TCP_MAX_WINSHIFT = 0xe TCP_MD5SIG = 0xe + TCP_MD5SIG_EXT = 0x20 + TCP_MD5SIG_FLAG_PREFIX = 0x1 TCP_MD5SIG_MAXKEYLEN = 0x50 TCP_MSS = 0x200 TCP_MSS_DEFAULT = 0x218 @@ -1720,6 +2095,9 @@ const ( TCP_QUEUE_SEQ = 0x15 TCP_QUICKACK = 0xc TCP_REPAIR = 0x13 + TCP_REPAIR_OFF = 0x0 + TCP_REPAIR_OFF_NO_WP = -0x1 + TCP_REPAIR_ON = 0x1 TCP_REPAIR_OPTIONS = 0x16 TCP_REPAIR_QUEUE = 0x14 TCP_REPAIR_WINDOW = 0x1d @@ -1731,8 +2109,10 @@ const ( TCP_THIN_DUPACK = 0x11 TCP_THIN_LINEAR_TIMEOUTS = 0x10 TCP_TIMESTAMP = 0x18 + TCP_ULP = 0x1f TCP_USER_TIMEOUT = 0x12 TCP_WINDOW_CLAMP = 0xa + TCP_ZEROCOPY_RECEIVE = 0x23 TCSAFLUSH = 0x5410 TCSBRK = 0x5405 TCSBRKP = 0x5486 @@ -1746,6 +2126,7 @@ const ( TCSETSW = 0x540f TCSETSW2 = 0x8030542c TCXONC = 0x5406 + TIMER_ABSTIME = 0x1 TIOCCBRK = 0x5428 TIOCCONS = 0x80047478 TIOCEXCL = 0x740d @@ -1754,6 +2135,7 @@ const ( TIOCGETP = 0x7408 TIOCGEXCL = 0x40045440 TIOCGICOUNT = 0x5492 + TIOCGISO7816 = 0x40285442 TIOCGLCKTRMIOS = 0x548b TIOCGLTC = 0x7474 TIOCGPGRP = 0x40047477 @@ -1810,6 +2192,7 @@ const ( TIOCSETN = 0x740a TIOCSETP = 0x7409 TIOCSIG = 0x80045436 + TIOCSISO7816 = 0xc0285443 TIOCSLCKTRMIOS = 0x548c TIOCSLTC = 0x7475 TIOCSPGRP = 0x80047476 @@ -1820,7 +2203,27 @@ const ( TIOCSTI = 0x5472 TIOCSWINSZ = 0x80087467 TIOCVHANGUP = 0x5437 + TMPFS_MAGIC = 0x1021994 TOSTOP = 0x8000 + TPACKET_ALIGNMENT = 0x10 + TPACKET_HDRLEN = 0x34 + TP_STATUS_AVAILABLE = 0x0 + TP_STATUS_BLK_TMO = 0x20 + TP_STATUS_COPY = 0x2 + TP_STATUS_CSUMNOTREADY = 0x8 + TP_STATUS_CSUM_VALID = 0x80 + TP_STATUS_KERNEL = 0x0 + TP_STATUS_LOSING = 0x4 + TP_STATUS_SENDING = 0x2 + TP_STATUS_SEND_REQUEST = 0x1 + TP_STATUS_TS_RAW_HARDWARE = -0x80000000 + TP_STATUS_TS_SOFTWARE = 0x20000000 + TP_STATUS_TS_SYS_HARDWARE = 0x40000000 + TP_STATUS_USER = 0x1 + TP_STATUS_VLAN_TPID_VALID = 0x40 + TP_STATUS_VLAN_VALID = 0x10 + TP_STATUS_WRONG_FORMAT = 0x4 + TRACEFS_MAGIC = 0x74726163 TS_COMM_LEN = 0x20 TUNATTACHFILTER = 0x800854d5 TUNDETACHFILTER = 0x800854d6 @@ -1832,6 +2235,7 @@ const ( TUNGETVNETHDRSZ = 0x400454d7 TUNGETVNETLE = 0x400454dd TUNSETDEBUG = 0x800454c9 + TUNSETFILTEREBPF = 0x400454e1 TUNSETGROUP = 0x800454ce TUNSETIFF = 0x800454ca TUNSETIFINDEX = 0x800454da @@ -1842,13 +2246,32 @@ const ( TUNSETPERSIST = 0x800454cb TUNSETQUEUE = 0x800454d9 TUNSETSNDBUF = 0x800454d4 + TUNSETSTEERINGEBPF = 0x400454e0 TUNSETTXFILTER = 0x800454d1 TUNSETVNETBE = 0x800454de TUNSETVNETHDRSZ = 0x800454d8 TUNSETVNETLE = 0x800454dc + UBI_IOCATT = 0x80186f40 + UBI_IOCDET = 0x80046f41 + UBI_IOCEBCH = 0x80044f02 + UBI_IOCEBER = 0x80044f01 + UBI_IOCEBISMAP = 0x40044f05 + UBI_IOCEBMAP = 0x80084f03 + UBI_IOCEBUNMAP = 0x80044f04 + UBI_IOCMKVOL = 0x80986f00 + UBI_IOCRMVOL = 0x80046f01 + UBI_IOCRNVOL = 0x91106f03 + UBI_IOCRSVOL = 0x800c6f02 + UBI_IOCSETVOLPROP = 0x80104f06 + UBI_IOCVOLCRBLK = 0x80804f07 + UBI_IOCVOLRMBLK = 0x20004f08 + UBI_IOCVOLUP = 0x80084f00 + UDF_SUPER_MAGIC = 0x15013346 UMOUNT_NOFOLLOW = 0x8 + USBDEVICE_SUPER_MAGIC = 0x9fa2 UTIME_NOW = 0x3fffffff UTIME_OMIT = 0x3ffffffe + V9FS_MAGIC = 0x1021997 VDISCARD = 0xd VEOF = 0x10 VEOL = 0x11 @@ -1891,6 +2314,86 @@ const ( WDIOC_SETPRETIMEOUT = 0xc0045708 WDIOC_SETTIMEOUT = 0xc0045706 WEXITED = 0x4 + WIN_ACKMEDIACHANGE = 0xdb + WIN_CHECKPOWERMODE1 = 0xe5 + WIN_CHECKPOWERMODE2 = 0x98 + WIN_DEVICE_RESET = 0x8 + WIN_DIAGNOSE = 0x90 + WIN_DOORLOCK = 0xde + WIN_DOORUNLOCK = 0xdf + WIN_DOWNLOAD_MICROCODE = 0x92 + WIN_FLUSH_CACHE = 0xe7 + WIN_FLUSH_CACHE_EXT = 0xea + WIN_FORMAT = 0x50 + WIN_GETMEDIASTATUS = 0xda + WIN_IDENTIFY = 0xec + WIN_IDENTIFY_DMA = 0xee + WIN_IDLEIMMEDIATE = 0xe1 + WIN_INIT = 0x60 + WIN_MEDIAEJECT = 0xed + WIN_MULTREAD = 0xc4 + WIN_MULTREAD_EXT = 0x29 + WIN_MULTWRITE = 0xc5 + WIN_MULTWRITE_EXT = 0x39 + WIN_NOP = 0x0 + WIN_PACKETCMD = 0xa0 + WIN_PIDENTIFY = 0xa1 + WIN_POSTBOOT = 0xdc + WIN_PREBOOT = 0xdd + WIN_QUEUED_SERVICE = 0xa2 + WIN_READ = 0x20 + WIN_READDMA = 0xc8 + WIN_READDMA_EXT = 0x25 + WIN_READDMA_ONCE = 0xc9 + WIN_READDMA_QUEUED = 0xc7 + WIN_READDMA_QUEUED_EXT = 0x26 + WIN_READ_BUFFER = 0xe4 + WIN_READ_EXT = 0x24 + WIN_READ_LONG = 0x22 + WIN_READ_LONG_ONCE = 0x23 + WIN_READ_NATIVE_MAX = 0xf8 + WIN_READ_NATIVE_MAX_EXT = 0x27 + WIN_READ_ONCE = 0x21 + WIN_RECAL = 0x10 + WIN_RESTORE = 0x10 + WIN_SECURITY_DISABLE = 0xf6 + WIN_SECURITY_ERASE_PREPARE = 0xf3 + WIN_SECURITY_ERASE_UNIT = 0xf4 + WIN_SECURITY_FREEZE_LOCK = 0xf5 + WIN_SECURITY_SET_PASS = 0xf1 + WIN_SECURITY_UNLOCK = 0xf2 + WIN_SEEK = 0x70 + WIN_SETFEATURES = 0xef + WIN_SETIDLE1 = 0xe3 + WIN_SETIDLE2 = 0x97 + WIN_SETMULT = 0xc6 + WIN_SET_MAX = 0xf9 + WIN_SET_MAX_EXT = 0x37 + WIN_SLEEPNOW1 = 0xe6 + WIN_SLEEPNOW2 = 0x99 + WIN_SMART = 0xb0 + WIN_SPECIFY = 0x91 + WIN_SRST = 0x8 + WIN_STANDBY = 0xe2 + WIN_STANDBY2 = 0x96 + WIN_STANDBYNOW1 = 0xe0 + WIN_STANDBYNOW2 = 0x94 + WIN_VERIFY = 0x40 + WIN_VERIFY_EXT = 0x42 + WIN_VERIFY_ONCE = 0x41 + WIN_WRITE = 0x30 + WIN_WRITEDMA = 0xca + WIN_WRITEDMA_EXT = 0x35 + WIN_WRITEDMA_ONCE = 0xcb + WIN_WRITEDMA_QUEUED = 0xcc + WIN_WRITEDMA_QUEUED_EXT = 0x36 + WIN_WRITE_BUFFER = 0xe8 + WIN_WRITE_EXT = 0x34 + WIN_WRITE_LONG = 0x32 + WIN_WRITE_LONG_ONCE = 0x33 + WIN_WRITE_ONCE = 0x31 + WIN_WRITE_SAME = 0xe9 + WIN_WRITE_VERIFY = 0x3c WNOHANG = 0x1 WNOTHREAD = 0x20000000 WNOWAIT = 0x1000000 @@ -1900,7 +2403,30 @@ const ( XATTR_CREATE = 0x1 XATTR_REPLACE = 0x2 XCASE = 0x4 + XDP_COPY = 0x2 + XDP_FLAGS_DRV_MODE = 0x4 + XDP_FLAGS_HW_MODE = 0x8 + XDP_FLAGS_MASK = 0xf + XDP_FLAGS_MODES = 0xe + XDP_FLAGS_SKB_MODE = 0x2 + XDP_FLAGS_UPDATE_IF_NOEXIST = 0x1 + XDP_MMAP_OFFSETS = 0x1 + XDP_PGOFF_RX_RING = 0x0 + XDP_PGOFF_TX_RING = 0x80000000 + XDP_RX_RING = 0x2 + XDP_SHARED_UMEM = 0x1 + XDP_STATISTICS = 0x7 + XDP_TX_RING = 0x3 + XDP_UMEM_COMPLETION_RING = 0x6 + XDP_UMEM_FILL_RING = 0x5 + XDP_UMEM_PGOFF_COMPLETION_RING = 0x180000000 + XDP_UMEM_PGOFF_FILL_RING = 0x100000000 + XDP_UMEM_REG = 0x4 + XDP_ZEROCOPY = 0x4 + XENFS_SUPER_MAGIC = 0xabba1974 + XFS_SUPER_MAGIC = 0x58465342 XTABS = 0x1800 + ZSMALLOC_MAGIC = 0x58295829 ) // Errors @@ -2082,174 +2608,182 @@ const ( ) // Error table -var errors = [...]string{ - 1: "operation not permitted", - 2: "no such file or directory", - 3: "no such process", - 4: "interrupted system call", - 5: "input/output error", - 6: "no such device or address", - 7: "argument list too long", - 8: "exec format error", - 9: "bad file descriptor", - 10: "no child processes", - 11: "resource temporarily unavailable", - 12: "cannot allocate memory", - 13: "permission denied", - 14: "bad address", - 15: "block device required", - 16: "device or resource busy", - 17: "file exists", - 18: "invalid cross-device link", - 19: "no such device", - 20: "not a directory", - 21: "is a directory", - 22: "invalid argument", - 23: "too many open files in system", - 24: "too many open files", - 25: "inappropriate ioctl for device", - 26: "text file busy", - 27: "file too large", - 28: "no space left on device", - 29: "illegal seek", - 30: "read-only file system", - 31: "too many links", - 32: "broken pipe", - 33: "numerical argument out of domain", - 34: "numerical result out of range", - 35: "no message of desired type", - 36: "identifier removed", - 37: "channel number out of range", - 38: "level 2 not synchronized", - 39: "level 3 halted", - 40: "level 3 reset", - 41: "link number out of range", - 42: "protocol driver not attached", - 43: "no CSI structure available", - 44: "level 2 halted", - 45: "resource deadlock avoided", - 46: "no locks available", - 50: "invalid exchange", - 51: "invalid request descriptor", - 52: "exchange full", - 53: "no anode", - 54: "invalid request code", - 55: "invalid slot", - 56: "file locking deadlock error", - 59: "bad font file format", - 60: "device not a stream", - 61: "no data available", - 62: "timer expired", - 63: "out of streams resources", - 64: "machine is not on the network", - 65: "package not installed", - 66: "object is remote", - 67: "link has been severed", - 68: "advertise error", - 69: "srmount error", - 70: "communication error on send", - 71: "protocol error", - 73: "RFS specific error", - 74: "multihop attempted", - 77: "bad message", - 78: "file name too long", - 79: "value too large for defined data type", - 80: "name not unique on network", - 81: "file descriptor in bad state", - 82: "remote address changed", - 83: "can not access a needed shared library", - 84: "accessing a corrupted shared library", - 85: ".lib section in a.out corrupted", - 86: "attempting to link in too many shared libraries", - 87: "cannot exec a shared library directly", - 88: "invalid or incomplete multibyte or wide character", - 89: "function not implemented", - 90: "too many levels of symbolic links", - 91: "interrupted system call should be restarted", - 92: "streams pipe error", - 93: "directory not empty", - 94: "too many users", - 95: "socket operation on non-socket", - 96: "destination address required", - 97: "message too long", - 98: "protocol wrong type for socket", - 99: "protocol not available", - 120: "protocol not supported", - 121: "socket type not supported", - 122: "operation not supported", - 123: "protocol family not supported", - 124: "address family not supported by protocol", - 125: "address already in use", - 126: "cannot assign requested address", - 127: "network is down", - 128: "network is unreachable", - 129: "network dropped connection on reset", - 130: "software caused connection abort", - 131: "connection reset by peer", - 132: "no buffer space available", - 133: "transport endpoint is already connected", - 134: "transport endpoint is not connected", - 135: "structure needs cleaning", - 137: "not a XENIX named type file", - 138: "no XENIX semaphores available", - 139: "is a named type file", - 140: "remote I/O error", - 141: "unknown error 141", - 142: "unknown error 142", - 143: "cannot send after transport endpoint shutdown", - 144: "too many references: cannot splice", - 145: "connection timed out", - 146: "connection refused", - 147: "host is down", - 148: "no route to host", - 149: "operation already in progress", - 150: "operation now in progress", - 151: "stale file handle", - 158: "operation canceled", - 159: "no medium found", - 160: "wrong medium type", - 161: "required key not available", - 162: "key has expired", - 163: "key has been revoked", - 164: "key was rejected by service", - 165: "owner died", - 166: "state not recoverable", - 167: "operation not possible due to RF-kill", - 168: "memory page has hardware error", - 1133: "disk quota exceeded", +var errorList = [...]struct { + num syscall.Errno + name string + desc string +}{ + {1, "EPERM", "operation not permitted"}, + {2, "ENOENT", "no such file or directory"}, + {3, "ESRCH", "no such process"}, + {4, "EINTR", "interrupted system call"}, + {5, "EIO", "input/output error"}, + {6, "ENXIO", "no such device or address"}, + {7, "E2BIG", "argument list too long"}, + {8, "ENOEXEC", "exec format error"}, + {9, "EBADF", "bad file descriptor"}, + {10, "ECHILD", "no child processes"}, + {11, "EAGAIN", "resource temporarily unavailable"}, + {12, "ENOMEM", "cannot allocate memory"}, + {13, "EACCES", "permission denied"}, + {14, "EFAULT", "bad address"}, + {15, "ENOTBLK", "block device required"}, + {16, "EBUSY", "device or resource busy"}, + {17, "EEXIST", "file exists"}, + {18, "EXDEV", "invalid cross-device link"}, + {19, "ENODEV", "no such device"}, + {20, "ENOTDIR", "not a directory"}, + {21, "EISDIR", "is a directory"}, + {22, "EINVAL", "invalid argument"}, + {23, "ENFILE", "too many open files in system"}, + {24, "EMFILE", "too many open files"}, + {25, "ENOTTY", "inappropriate ioctl for device"}, + {26, "ETXTBSY", "text file busy"}, + {27, "EFBIG", "file too large"}, + {28, "ENOSPC", "no space left on device"}, + {29, "ESPIPE", "illegal seek"}, + {30, "EROFS", "read-only file system"}, + {31, "EMLINK", "too many links"}, + {32, "EPIPE", "broken pipe"}, + {33, "EDOM", "numerical argument out of domain"}, + {34, "ERANGE", "numerical result out of range"}, + {35, "ENOMSG", "no message of desired type"}, + {36, "EIDRM", "identifier removed"}, + {37, "ECHRNG", "channel number out of range"}, + {38, "EL2NSYNC", "level 2 not synchronized"}, + {39, "EL3HLT", "level 3 halted"}, + {40, "EL3RST", "level 3 reset"}, + {41, "ELNRNG", "link number out of range"}, + {42, "EUNATCH", "protocol driver not attached"}, + {43, "ENOCSI", "no CSI structure available"}, + {44, "EL2HLT", "level 2 halted"}, + {45, "EDEADLK", "resource deadlock avoided"}, + {46, "ENOLCK", "no locks available"}, + {50, "EBADE", "invalid exchange"}, + {51, "EBADR", "invalid request descriptor"}, + {52, "EXFULL", "exchange full"}, + {53, "ENOANO", "no anode"}, + {54, "EBADRQC", "invalid request code"}, + {55, "EBADSLT", "invalid slot"}, + {56, "EDEADLOCK", "file locking deadlock error"}, + {59, "EBFONT", "bad font file format"}, + {60, "ENOSTR", "device not a stream"}, + {61, "ENODATA", "no data available"}, + {62, "ETIME", "timer expired"}, + {63, "ENOSR", "out of streams resources"}, + {64, "ENONET", "machine is not on the network"}, + {65, "ENOPKG", "package not installed"}, + {66, "EREMOTE", "object is remote"}, + {67, "ENOLINK", "link has been severed"}, + {68, "EADV", "advertise error"}, + {69, "ESRMNT", "srmount error"}, + {70, "ECOMM", "communication error on send"}, + {71, "EPROTO", "protocol error"}, + {73, "EDOTDOT", "RFS specific error"}, + {74, "EMULTIHOP", "multihop attempted"}, + {77, "EBADMSG", "bad message"}, + {78, "ENAMETOOLONG", "file name too long"}, + {79, "EOVERFLOW", "value too large for defined data type"}, + {80, "ENOTUNIQ", "name not unique on network"}, + {81, "EBADFD", "file descriptor in bad state"}, + {82, "EREMCHG", "remote address changed"}, + {83, "ELIBACC", "can not access a needed shared library"}, + {84, "ELIBBAD", "accessing a corrupted shared library"}, + {85, "ELIBSCN", ".lib section in a.out corrupted"}, + {86, "ELIBMAX", "attempting to link in too many shared libraries"}, + {87, "ELIBEXEC", "cannot exec a shared library directly"}, + {88, "EILSEQ", "invalid or incomplete multibyte or wide character"}, + {89, "ENOSYS", "function not implemented"}, + {90, "ELOOP", "too many levels of symbolic links"}, + {91, "ERESTART", "interrupted system call should be restarted"}, + {92, "ESTRPIPE", "streams pipe error"}, + {93, "ENOTEMPTY", "directory not empty"}, + {94, "EUSERS", "too many users"}, + {95, "ENOTSOCK", "socket operation on non-socket"}, + {96, "EDESTADDRREQ", "destination address required"}, + {97, "EMSGSIZE", "message too long"}, + {98, "EPROTOTYPE", "protocol wrong type for socket"}, + {99, "ENOPROTOOPT", "protocol not available"}, + {120, "EPROTONOSUPPORT", "protocol not supported"}, + {121, "ESOCKTNOSUPPORT", "socket type not supported"}, + {122, "ENOTSUP", "operation not supported"}, + {123, "EPFNOSUPPORT", "protocol family not supported"}, + {124, "EAFNOSUPPORT", "address family not supported by protocol"}, + {125, "EADDRINUSE", "address already in use"}, + {126, "EADDRNOTAVAIL", "cannot assign requested address"}, + {127, "ENETDOWN", "network is down"}, + {128, "ENETUNREACH", "network is unreachable"}, + {129, "ENETRESET", "network dropped connection on reset"}, + {130, "ECONNABORTED", "software caused connection abort"}, + {131, "ECONNRESET", "connection reset by peer"}, + {132, "ENOBUFS", "no buffer space available"}, + {133, "EISCONN", "transport endpoint is already connected"}, + {134, "ENOTCONN", "transport endpoint is not connected"}, + {135, "EUCLEAN", "structure needs cleaning"}, + {137, "ENOTNAM", "not a XENIX named type file"}, + {138, "ENAVAIL", "no XENIX semaphores available"}, + {139, "EISNAM", "is a named type file"}, + {140, "EREMOTEIO", "remote I/O error"}, + {141, "EINIT", "unknown error 141"}, + {142, "EREMDEV", "unknown error 142"}, + {143, "ESHUTDOWN", "cannot send after transport endpoint shutdown"}, + {144, "ETOOMANYREFS", "too many references: cannot splice"}, + {145, "ETIMEDOUT", "connection timed out"}, + {146, "ECONNREFUSED", "connection refused"}, + {147, "EHOSTDOWN", "host is down"}, + {148, "EHOSTUNREACH", "no route to host"}, + {149, "EALREADY", "operation already in progress"}, + {150, "EINPROGRESS", "operation now in progress"}, + {151, "ESTALE", "stale file handle"}, + {158, "ECANCELED", "operation canceled"}, + {159, "ENOMEDIUM", "no medium found"}, + {160, "EMEDIUMTYPE", "wrong medium type"}, + {161, "ENOKEY", "required key not available"}, + {162, "EKEYEXPIRED", "key has expired"}, + {163, "EKEYREVOKED", "key has been revoked"}, + {164, "EKEYREJECTED", "key was rejected by service"}, + {165, "EOWNERDEAD", "owner died"}, + {166, "ENOTRECOVERABLE", "state not recoverable"}, + {167, "ERFKILL", "operation not possible due to RF-kill"}, + {168, "EHWPOISON", "memory page has hardware error"}, + {1133, "EDQUOT", "disk quota exceeded"}, } // Signal table -var signals = [...]string{ - 1: "hangup", - 2: "interrupt", - 3: "quit", - 4: "illegal instruction", - 5: "trace/breakpoint trap", - 6: "aborted", - 7: "EMT trap", - 8: "floating point exception", - 9: "killed", - 10: "bus error", - 11: "segmentation fault", - 12: "bad system call", - 13: "broken pipe", - 14: "alarm clock", - 15: "terminated", - 16: "user defined signal 1", - 17: "user defined signal 2", - 18: "child exited", - 19: "power failure", - 20: "window changed", - 21: "urgent I/O condition", - 22: "I/O possible", - 23: "stopped (signal)", - 24: "stopped", - 25: "continued", - 26: "stopped (tty input)", - 27: "stopped (tty output)", - 28: "virtual timer expired", - 29: "profiling timer expired", - 30: "CPU time limit exceeded", - 31: "file size limit exceeded", +var signalList = [...]struct { + num syscall.Signal + name string + desc string +}{ + {1, "SIGHUP", "hangup"}, + {2, "SIGINT", "interrupt"}, + {3, "SIGQUIT", "quit"}, + {4, "SIGILL", "illegal instruction"}, + {5, "SIGTRAP", "trace/breakpoint trap"}, + {6, "SIGABRT", "aborted"}, + {7, "SIGEMT", "EMT trap"}, + {8, "SIGFPE", "floating point exception"}, + {9, "SIGKILL", "killed"}, + {10, "SIGBUS", "bus error"}, + {11, "SIGSEGV", "segmentation fault"}, + {12, "SIGSYS", "bad system call"}, + {13, "SIGPIPE", "broken pipe"}, + {14, "SIGALRM", "alarm clock"}, + {15, "SIGTERM", "terminated"}, + {16, "SIGUSR1", "user defined signal 1"}, + {17, "SIGUSR2", "user defined signal 2"}, + {18, "SIGCHLD", "child exited"}, + {19, "SIGPWR", "power failure"}, + {20, "SIGWINCH", "window changed"}, + {21, "SIGURG", "urgent I/O condition"}, + {22, "SIGIO", "I/O possible"}, + {23, "SIGSTOP", "stopped (signal)"}, + {24, "SIGTSTP", "stopped"}, + {25, "SIGCONT", "continued"}, + {26, "SIGTTIN", "stopped (tty input)"}, + {27, "SIGTTOU", "stopped (tty output)"}, + {28, "SIGVTALRM", "virtual timer expired"}, + {29, "SIGPROF", "profiling timer expired"}, + {30, "SIGXCPU", "CPU time limit exceeded"}, + {31, "SIGXFSZ", "file size limit exceeded"}, } diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go index f6ca82c715..ebaca417b4 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go @@ -3,7 +3,7 @@ // +build ppc64,linux -// Created by cgo -godefs - DO NOT EDIT +// Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go package unix @@ -11,6 +11,11 @@ package unix import "syscall" const ( + AAFS_MAGIC = 0x5a3c69f0 + ADFS_SUPER_MAGIC = 0xadf5 + AFFS_SUPER_MAGIC = 0xadff + AFS_FS_MAGIC = 0x6b414653 + AFS_SUPER_MAGIC = 0x5346414f AF_ALG = 0x26 AF_APPLETALK = 0x5 AF_ASH = 0x12 @@ -36,7 +41,7 @@ const ( AF_KEY = 0xf AF_LLC = 0x1a AF_LOCAL = 0x1 - AF_MAX = 0x2c + AF_MAX = 0x2d AF_MPLS = 0x1c AF_NETBEUI = 0xd AF_NETLINK = 0x10 @@ -59,6 +64,7 @@ const ( AF_VSOCK = 0x28 AF_WANPIPE = 0x19 AF_X25 = 0x9 + AF_XDP = 0x2c ALG_OP_DECRYPT = 0x0 ALG_OP_ENCRYPT = 0x1 ALG_SET_AEAD_ASSOCLEN = 0x4 @@ -66,6 +72,7 @@ const ( ALG_SET_IV = 0x2 ALG_SET_KEY = 0x1 ALG_SET_OP = 0x3 + ANON_INODE_FS_MAGIC = 0x9041934 ARPHRD_6LOWPAN = 0x339 ARPHRD_ADAPT = 0x108 ARPHRD_APPLETLK = 0x8 @@ -121,6 +128,7 @@ const ( ARPHRD_PPP = 0x200 ARPHRD_PRONET = 0x4 ARPHRD_RAWHDLC = 0x206 + ARPHRD_RAWIP = 0x207 ARPHRD_ROSE = 0x10e ARPHRD_RSRVD = 0x104 ARPHRD_SIT = 0x308 @@ -132,6 +140,7 @@ const ( ARPHRD_VOID = 0xffff ARPHRD_VSOCKMON = 0x33a ARPHRD_X25 = 0x10f + AUTOFS_SUPER_MAGIC = 0x187 B0 = 0x0 B1000000 = 0x17 B110 = 0x3 @@ -163,6 +172,9 @@ const ( B75 = 0x2 B921600 = 0x16 B9600 = 0xd + BALLOON_KVM_MAGIC = 0x13661366 + BDEVFS_MAGIC = 0x62646576 + BINFMTFS_MAGIC = 0x42494e4d BLKBSZGET = 0x40081270 BLKBSZSET = 0x80081271 BLKFLSBUF = 0x20001261 @@ -187,6 +199,7 @@ const ( BPF_AND = 0x50 BPF_B = 0x10 BPF_DIV = 0x30 + BPF_FS_MAGIC = 0xcafe4a11 BPF_H = 0x8 BPF_IMM = 0x0 BPF_IND = 0x40 @@ -228,6 +241,8 @@ const ( BS0 = 0x0 BS1 = 0x8000 BSDLY = 0x8000 + BTRFS_SUPER_MAGIC = 0x9123683e + BTRFS_TEST_MAGIC = 0x73727279 CAN_BCM = 0x2 CAN_EFF_FLAG = 0x80000000 CAN_EFF_ID_BITS = 0x1d @@ -251,6 +266,8 @@ const ( CBAUD = 0xff CBAUDEX = 0x0 CFLUSH = 0xf + CGROUP2_SUPER_MAGIC = 0x63677270 + CGROUP_SUPER_MAGIC = 0x27e0eb CIBAUD = 0xff0000 CLOCAL = 0x8000 CLOCK_BOOTTIME = 0x7 @@ -293,10 +310,12 @@ const ( CLONE_VFORK = 0x4000 CLONE_VM = 0x100 CMSPAR = 0x40000000 + CODA_SUPER_MAGIC = 0x73757245 CR0 = 0x0 CR1 = 0x1000 CR2 = 0x2000 CR3 = 0x3000 + CRAMFS_MAGIC = 0x28cd3d45 CRDLY = 0x3000 CREAD = 0x800 CRTSCTS = 0x80000000 @@ -311,6 +330,9 @@ const ( CSTOP = 0x13 CSTOPB = 0x400 CSUSP = 0x1a + DAXFS_MAGIC = 0x64646178 + DEBUGFS_MAGIC = 0x64626720 + DEVPTS_SUPER_MAGIC = 0x1cd1 DT_BLK = 0x6 DT_CHR = 0x2 DT_DIR = 0x4 @@ -327,9 +349,12 @@ const ( ECHOKE = 0x1 ECHONL = 0x10 ECHOPRT = 0x20 + ECRYPTFS_SUPER_MAGIC = 0xf15f EFD_CLOEXEC = 0x80000 EFD_NONBLOCK = 0x800 EFD_SEMAPHORE = 0x1 + EFIVARFS_MAGIC = 0xde5e81e4 + EFS_SUPER_MAGIC = 0x414a53 ENCODING_DEFAULT = 0x0 ENCODING_FM_MARK = 0x3 ENCODING_FM_SPACE = 0x4 @@ -390,6 +415,8 @@ const ( ETH_P_DSA = 0x1b ETH_P_ECONET = 0x18 ETH_P_EDSA = 0xdada + ETH_P_ERSPAN = 0x88be + ETH_P_ERSPAN2 = 0x22eb ETH_P_FCOE = 0x8906 ETH_P_FIP = 0x8914 ETH_P_HDLC = 0x19 @@ -398,6 +425,7 @@ const ( ETH_P_IEEE802154 = 0xf6 ETH_P_IEEEPUP = 0xa00 ETH_P_IEEEPUPAT = 0xa01 + ETH_P_IFE = 0xed3e ETH_P_IP = 0x800 ETH_P_IPV6 = 0x86dd ETH_P_IPX = 0x8137 @@ -408,11 +436,13 @@ const ( ETH_P_LOOP = 0x60 ETH_P_LOOPBACK = 0x9000 ETH_P_MACSEC = 0x88e5 + ETH_P_MAP = 0xf9 ETH_P_MOBITEX = 0x15 ETH_P_MPLS_MC = 0x8848 ETH_P_MPLS_UC = 0x8847 ETH_P_MVRP = 0x88f5 ETH_P_NCSI = 0x88f8 + ETH_P_NSH = 0x894f ETH_P_PAE = 0x888e ETH_P_PAUSE = 0x8808 ETH_P_PHONET = 0xf5 @@ -420,6 +450,7 @@ const ( ETH_P_PPP_DISC = 0x8863 ETH_P_PPP_MP = 0x8 ETH_P_PPP_SES = 0x8864 + ETH_P_PREAUTH = 0x88c7 ETH_P_PRP = 0x88fb ETH_P_PUP = 0x200 ETH_P_PUPAT = 0x201 @@ -440,9 +471,14 @@ const ( ETH_P_WCCP = 0x883e ETH_P_X25 = 0x805 ETH_P_XDSA = 0xf8 + EXABYTE_ENABLE_NEST = 0xf0 + EXT2_SUPER_MAGIC = 0xef53 + EXT3_SUPER_MAGIC = 0xef53 + EXT4_SUPER_MAGIC = 0xef53 EXTA = 0xe EXTB = 0xf EXTPROC = 0x10000000 + F2FS_SUPER_MAGIC = 0xf2f52010 FALLOC_FL_COLLAPSE_RANGE = 0x8 FALLOC_FL_INSERT_RANGE = 0x20 FALLOC_FL_KEEP_SIZE = 0x1 @@ -463,6 +499,8 @@ const ( FS_ENCRYPTION_MODE_AES_256_GCM = 0x2 FS_ENCRYPTION_MODE_AES_256_XTS = 0x1 FS_ENCRYPTION_MODE_INVALID = 0x0 + FS_ENCRYPTION_MODE_SPECK128_256_CTS = 0x8 + FS_ENCRYPTION_MODE_SPECK128_256_XTS = 0x7 FS_IOC_GET_ENCRYPTION_POLICY = 0x800c6615 FS_IOC_GET_ENCRYPTION_PWSALT = 0x80106614 FS_IOC_SET_ENCRYPTION_POLICY = 0x400c6613 @@ -476,6 +514,8 @@ const ( FS_POLICY_FLAGS_PAD_8 = 0x1 FS_POLICY_FLAGS_PAD_MASK = 0x3 FS_POLICY_FLAGS_VALID = 0x3 + FUTEXFS_SUPER_MAGIC = 0xbad1dea + F_ADD_SEALS = 0x409 F_DUPFD = 0x0 F_DUPFD_CLOEXEC = 0x406 F_EXLCK = 0x4 @@ -488,6 +528,9 @@ const ( F_GETOWN_EX = 0x10 F_GETPIPE_SZ = 0x408 F_GETSIG = 0xb + F_GET_FILE_RW_HINT = 0x40d + F_GET_RW_HINT = 0x40b + F_GET_SEALS = 0x40a F_LOCK = 0x1 F_NOTIFY = 0x402 F_OFD_GETLK = 0x24 @@ -495,6 +538,10 @@ const ( F_OFD_SETLKW = 0x26 F_OK = 0x0 F_RDLCK = 0x0 + F_SEAL_GROW = 0x4 + F_SEAL_SEAL = 0x1 + F_SEAL_SHRINK = 0x2 + F_SEAL_WRITE = 0x8 F_SETFD = 0x2 F_SETFL = 0x4 F_SETLEASE = 0x400 @@ -506,6 +553,8 @@ const ( F_SETOWN_EX = 0xf F_SETPIPE_SZ = 0x407 F_SETSIG = 0xa + F_SET_FILE_RW_HINT = 0x40e + F_SET_RW_HINT = 0x40c F_SHLCK = 0x8 F_TEST = 0x3 F_TLOCK = 0x2 @@ -527,6 +576,49 @@ const ( GENL_UNS_ADMIN_PERM = 0x10 GRND_NONBLOCK = 0x1 GRND_RANDOM = 0x2 + HDIO_DRIVE_CMD = 0x31f + HDIO_DRIVE_CMD_AEB = 0x31e + HDIO_DRIVE_CMD_HDR_SIZE = 0x4 + HDIO_DRIVE_HOB_HDR_SIZE = 0x8 + HDIO_DRIVE_RESET = 0x31c + HDIO_DRIVE_TASK = 0x31e + HDIO_DRIVE_TASKFILE = 0x31d + HDIO_DRIVE_TASK_HDR_SIZE = 0x8 + HDIO_GETGEO = 0x301 + HDIO_GET_32BIT = 0x309 + HDIO_GET_ACOUSTIC = 0x30f + HDIO_GET_ADDRESS = 0x310 + HDIO_GET_BUSSTATE = 0x31a + HDIO_GET_DMA = 0x30b + HDIO_GET_IDENTITY = 0x30d + HDIO_GET_KEEPSETTINGS = 0x308 + HDIO_GET_MULTCOUNT = 0x304 + HDIO_GET_NICE = 0x30c + HDIO_GET_NOWERR = 0x30a + HDIO_GET_QDMA = 0x305 + HDIO_GET_UNMASKINTR = 0x302 + HDIO_GET_WCACHE = 0x30e + HDIO_OBSOLETE_IDENTITY = 0x307 + HDIO_SCAN_HWIF = 0x328 + HDIO_SET_32BIT = 0x324 + HDIO_SET_ACOUSTIC = 0x32c + HDIO_SET_ADDRESS = 0x32f + HDIO_SET_BUSSTATE = 0x32d + HDIO_SET_DMA = 0x326 + HDIO_SET_KEEPSETTINGS = 0x323 + HDIO_SET_MULTCOUNT = 0x321 + HDIO_SET_NICE = 0x329 + HDIO_SET_NOWERR = 0x325 + HDIO_SET_PIO_MODE = 0x327 + HDIO_SET_QDMA = 0x32e + HDIO_SET_UNMASKINTR = 0x322 + HDIO_SET_WCACHE = 0x32b + HDIO_SET_XFER = 0x306 + HDIO_TRISTATE_HWIF = 0x31b + HDIO_UNREGISTER_HWIF = 0x32a + HOSTFS_SUPER_MAGIC = 0xc0ffee + HPFS_SUPER_MAGIC = 0xf995e849 + HUGETLBFS_MAGIC = 0x958458f6 HUPCL = 0x4000 IBSHIFT = 0x10 ICANON = 0x100 @@ -546,7 +638,7 @@ const ( IFA_F_STABLE_PRIVACY = 0x800 IFA_F_TEMPORARY = 0x1 IFA_F_TENTATIVE = 0x40 - IFA_MAX = 0x8 + IFA_MAX = 0xa IFF_ALLMULTI = 0x200 IFF_ATTACH_QUEUE = 0x200 IFF_AUTOMEDIA = 0x4000 @@ -561,6 +653,8 @@ const ( IFF_MASTER = 0x400 IFF_MULTICAST = 0x1000 IFF_MULTI_QUEUE = 0x100 + IFF_NAPI = 0x10 + IFF_NAPI_FRAGS = 0x20 IFF_NOARP = 0x80 IFF_NOFILTER = 0x1000 IFF_NOTRAILERS = 0x20 @@ -612,6 +706,7 @@ const ( IN_ISDIR = 0x40000000 IN_LOOPBACKNET = 0x7f IN_MASK_ADD = 0x20000000 + IN_MASK_CREATE = 0x10000000 IN_MODIFY = 0x2 IN_MOVE = 0xc0 IN_MOVED_FROM = 0x40 @@ -671,6 +766,7 @@ const ( IPV6_DONTFRAG = 0x3e IPV6_DROP_MEMBERSHIP = 0x15 IPV6_DSTOPTS = 0x3b + IPV6_FREEBIND = 0x4e IPV6_HDRINCL = 0x24 IPV6_HOPLIMIT = 0x34 IPV6_HOPOPTS = 0x36 @@ -682,6 +778,7 @@ const ( IPV6_MINHOPCOUNT = 0x49 IPV6_MTU = 0x18 IPV6_MTU_DISCOVER = 0x17 + IPV6_MULTICAST_ALL = 0x1d IPV6_MULTICAST_HOPS = 0x12 IPV6_MULTICAST_IF = 0x11 IPV6_MULTICAST_LOOP = 0x13 @@ -775,12 +872,34 @@ const ( IP_UNICAST_IF = 0x32 IP_XFRM_POLICY = 0x11 ISIG = 0x80 + ISOFS_SUPER_MAGIC = 0x9660 ISTRIP = 0x20 IUCLC = 0x1000 IUTF8 = 0x4000 IXANY = 0x800 IXOFF = 0x400 IXON = 0x200 + JFFS2_SUPER_MAGIC = 0x72b6 + KEXEC_ARCH_386 = 0x30000 + KEXEC_ARCH_68K = 0x40000 + KEXEC_ARCH_AARCH64 = 0xb70000 + KEXEC_ARCH_ARM = 0x280000 + KEXEC_ARCH_DEFAULT = 0x0 + KEXEC_ARCH_IA_64 = 0x320000 + KEXEC_ARCH_MASK = 0xffff0000 + KEXEC_ARCH_MIPS = 0x80000 + KEXEC_ARCH_MIPS_LE = 0xa0000 + KEXEC_ARCH_PPC = 0x140000 + KEXEC_ARCH_PPC64 = 0x150000 + KEXEC_ARCH_S390 = 0x160000 + KEXEC_ARCH_SH = 0x2a0000 + KEXEC_ARCH_X86_64 = 0x3e0000 + KEXEC_FILE_NO_INITRAMFS = 0x4 + KEXEC_FILE_ON_CRASH = 0x2 + KEXEC_FILE_UNLOAD = 0x1 + KEXEC_ON_CRASH = 0x1 + KEXEC_PRESERVE_CONTEXT = 0x2 + KEXEC_SEGMENT_MAX = 0x10 KEYCTL_ASSUME_AUTHORITY = 0x10 KEYCTL_CHOWN = 0x4 KEYCTL_CLEAR = 0x7 @@ -795,6 +914,11 @@ const ( KEYCTL_JOIN_SESSION_KEYRING = 0x1 KEYCTL_LINK = 0x8 KEYCTL_NEGATE = 0xd + KEYCTL_PKEY_DECRYPT = 0x1a + KEYCTL_PKEY_ENCRYPT = 0x19 + KEYCTL_PKEY_QUERY = 0x18 + KEYCTL_PKEY_SIGN = 0x1b + KEYCTL_PKEY_VERIFY = 0x1c KEYCTL_READ = 0xb KEYCTL_REJECT = 0x13 KEYCTL_RESTRICT_KEYRING = 0x1d @@ -804,6 +928,10 @@ const ( KEYCTL_SETPERM = 0x5 KEYCTL_SET_REQKEY_KEYRING = 0xe KEYCTL_SET_TIMEOUT = 0xf + KEYCTL_SUPPORTS_DECRYPT = 0x2 + KEYCTL_SUPPORTS_ENCRYPT = 0x1 + KEYCTL_SUPPORTS_SIGN = 0x4 + KEYCTL_SUPPORTS_VERIFY = 0x8 KEYCTL_UNLINK = 0x9 KEYCTL_UPDATE = 0x2 KEY_REQKEY_DEFL_DEFAULT = 0x0 @@ -845,6 +973,7 @@ const ( MADV_FREE = 0x8 MADV_HUGEPAGE = 0xe MADV_HWPOISON = 0x64 + MADV_KEEPONFORK = 0x13 MADV_MERGEABLE = 0xc MADV_NOHUGEPAGE = 0xf MADV_NORMAL = 0x0 @@ -853,12 +982,14 @@ const ( MADV_SEQUENTIAL = 0x2 MADV_UNMERGEABLE = 0xd MADV_WILLNEED = 0x3 + MADV_WIPEONFORK = 0x12 MAP_ANON = 0x20 MAP_ANONYMOUS = 0x20 MAP_DENYWRITE = 0x800 MAP_EXECUTABLE = 0x1000 MAP_FILE = 0x0 MAP_FIXED = 0x10 + MAP_FIXED_NOREPLACE = 0x100000 MAP_GROWSDOWN = 0x100 MAP_HUGETLB = 0x40000 MAP_HUGE_MASK = 0x3f @@ -869,14 +1000,40 @@ const ( MAP_POPULATE = 0x8000 MAP_PRIVATE = 0x2 MAP_SHARED = 0x1 + MAP_SHARED_VALIDATE = 0x3 MAP_STACK = 0x20000 MAP_TYPE = 0xf MCL_CURRENT = 0x2000 MCL_FUTURE = 0x4000 MCL_ONFAULT = 0x8000 + MFD_ALLOW_SEALING = 0x2 + MFD_CLOEXEC = 0x1 + MFD_HUGETLB = 0x4 + MFD_HUGE_16GB = -0x78000000 + MFD_HUGE_16MB = 0x60000000 + MFD_HUGE_1GB = 0x78000000 + MFD_HUGE_1MB = 0x50000000 + MFD_HUGE_256MB = 0x70000000 + MFD_HUGE_2GB = 0x7c000000 + MFD_HUGE_2MB = 0x54000000 + MFD_HUGE_32MB = 0x64000000 + MFD_HUGE_512KB = 0x4c000000 + MFD_HUGE_512MB = 0x74000000 + MFD_HUGE_64KB = 0x40000000 + MFD_HUGE_8MB = 0x5c000000 + MFD_HUGE_MASK = 0x3f + MFD_HUGE_SHIFT = 0x1a + MINIX2_SUPER_MAGIC = 0x2468 + MINIX2_SUPER_MAGIC2 = 0x2478 + MINIX3_SUPER_MAGIC = 0x4d5a + MINIX_SUPER_MAGIC = 0x137f + MINIX_SUPER_MAGIC2 = 0x138f MNT_DETACH = 0x2 MNT_EXPIRE = 0x4 MNT_FORCE = 0x1 + MODULE_INIT_IGNORE_MODVERSIONS = 0x1 + MODULE_INIT_IGNORE_VERMAGIC = 0x2 + MSDOS_SUPER_MAGIC = 0x4d44 MSG_BATCH = 0x40000 MSG_CMSG_CLOEXEC = 0x40000000 MSG_CONFIRM = 0x800 @@ -898,6 +1055,7 @@ const ( MSG_TRYHARD = 0x4 MSG_WAITALL = 0x100 MSG_WAITFORONE = 0x10000 + MSG_ZEROCOPY = 0x4000000 MS_ACTIVE = 0x40000000 MS_ASYNC = 0x1 MS_BIND = 0x1000 @@ -935,7 +1093,9 @@ const ( MS_SYNCHRONOUS = 0x10 MS_UNBINDABLE = 0x20000 MS_VERBOSE = 0x8000 + MTD_INODE_FS_MAGIC = 0x11307854 NAME_MAX = 0xff + NCP_SUPER_MAGIC = 0x564c NETLINK_ADD_MEMBERSHIP = 0x1 NETLINK_AUDIT = 0x9 NETLINK_BROADCAST_ERROR = 0x4 @@ -949,6 +1109,7 @@ const ( NETLINK_FIB_LOOKUP = 0xa NETLINK_FIREWALL = 0x3 NETLINK_GENERIC = 0x10 + NETLINK_GET_STRICT_CHK = 0xc NETLINK_INET_DIAG = 0x4 NETLINK_IP6_FW = 0xd NETLINK_ISCSI = 0x8 @@ -970,6 +1131,39 @@ const ( NETLINK_UNUSED = 0x1 NETLINK_USERSOCK = 0x2 NETLINK_XFRM = 0x6 + NETNSA_MAX = 0x3 + NETNSA_NSID_NOT_ASSIGNED = -0x1 + NFNETLINK_V0 = 0x0 + NFNLGRP_ACCT_QUOTA = 0x8 + NFNLGRP_CONNTRACK_DESTROY = 0x3 + NFNLGRP_CONNTRACK_EXP_DESTROY = 0x6 + NFNLGRP_CONNTRACK_EXP_NEW = 0x4 + NFNLGRP_CONNTRACK_EXP_UPDATE = 0x5 + NFNLGRP_CONNTRACK_NEW = 0x1 + NFNLGRP_CONNTRACK_UPDATE = 0x2 + NFNLGRP_MAX = 0x9 + NFNLGRP_NFTABLES = 0x7 + NFNLGRP_NFTRACE = 0x9 + NFNLGRP_NONE = 0x0 + NFNL_BATCH_MAX = 0x1 + NFNL_MSG_BATCH_BEGIN = 0x10 + NFNL_MSG_BATCH_END = 0x11 + NFNL_NFA_NEST = 0x8000 + NFNL_SUBSYS_ACCT = 0x7 + NFNL_SUBSYS_COUNT = 0xc + NFNL_SUBSYS_CTHELPER = 0x9 + NFNL_SUBSYS_CTNETLINK = 0x1 + NFNL_SUBSYS_CTNETLINK_EXP = 0x2 + NFNL_SUBSYS_CTNETLINK_TIMEOUT = 0x8 + NFNL_SUBSYS_IPSET = 0x6 + NFNL_SUBSYS_NFTABLES = 0xa + NFNL_SUBSYS_NFT_COMPAT = 0xb + NFNL_SUBSYS_NONE = 0x0 + NFNL_SUBSYS_OSF = 0x5 + NFNL_SUBSYS_QUEUE = 0x3 + NFNL_SUBSYS_ULOG = 0x4 + NFS_SUPER_MAGIC = 0x6969 + NILFS_SUPER_MAGIC = 0x3434 NL0 = 0x0 NL1 = 0x100 NL2 = 0x200 @@ -999,10 +1193,13 @@ const ( NLM_F_EXCL = 0x200 NLM_F_MATCH = 0x200 NLM_F_MULTI = 0x2 + NLM_F_NONREC = 0x100 NLM_F_REPLACE = 0x100 NLM_F_REQUEST = 0x1 NLM_F_ROOT = 0x100 NOFLSH = 0x80000000 + NSFS_MAGIC = 0x6e736673 + OCFS2_SUPER_MAGIC = 0x7461636f OCRNL = 0x8 OFDEL = 0x80 OFILL = 0x40 @@ -1010,7 +1207,9 @@ const ( ONLCR = 0x2 ONLRET = 0x20 ONOCR = 0x10 + OPENPROM_SUPER_MAGIC = 0x9fa1 OPOST = 0x1 + OVERLAYFS_SUPER_MAGIC = 0x794c7630 O_ACCMODE = 0x3 O_APPEND = 0x400 O_ASYNC = 0x2000 @@ -1056,6 +1255,7 @@ const ( PACKET_FASTROUTE = 0x6 PACKET_HDRLEN = 0xb PACKET_HOST = 0x0 + PACKET_IGNORE_OUTGOING = 0x17 PACKET_KERNEL = 0x7 PACKET_LOOPBACK = 0x5 PACKET_LOSS = 0xe @@ -1095,16 +1295,50 @@ const ( PERF_EVENT_IOC_DISABLE = 0x20002401 PERF_EVENT_IOC_ENABLE = 0x20002400 PERF_EVENT_IOC_ID = 0x40082407 + PERF_EVENT_IOC_MODIFY_ATTRIBUTES = 0x8008240b PERF_EVENT_IOC_PAUSE_OUTPUT = 0x80042409 PERF_EVENT_IOC_PERIOD = 0x80082404 + PERF_EVENT_IOC_QUERY_BPF = 0xc008240a PERF_EVENT_IOC_REFRESH = 0x20002402 PERF_EVENT_IOC_RESET = 0x20002403 PERF_EVENT_IOC_SET_BPF = 0x80042408 PERF_EVENT_IOC_SET_FILTER = 0x80082406 PERF_EVENT_IOC_SET_OUTPUT = 0x20002405 + PIPEFS_MAGIC = 0x50495045 + PPPIOCATTACH = 0x8004743d + PPPIOCATTCHAN = 0x80047438 + PPPIOCCONNECT = 0x8004743a + PPPIOCDETACH = 0x8004743c + PPPIOCDISCONN = 0x20007439 + PPPIOCGASYNCMAP = 0x40047458 + PPPIOCGCHAN = 0x40047437 + PPPIOCGDEBUG = 0x40047441 + PPPIOCGFLAGS = 0x4004745a + PPPIOCGIDLE = 0x4010743f + PPPIOCGL2TPSTATS = 0x40487436 + PPPIOCGMRU = 0x40047453 + PPPIOCGNPMODE = 0xc008744c + PPPIOCGRASYNCMAP = 0x40047455 + PPPIOCGUNIT = 0x40047456 + PPPIOCGXASYNCMAP = 0x40207450 + PPPIOCNEWUNIT = 0xc004743e + PPPIOCSACTIVE = 0x80107446 + PPPIOCSASYNCMAP = 0x80047457 + PPPIOCSCOMPRESS = 0x8010744d + PPPIOCSDEBUG = 0x80047440 + PPPIOCSFLAGS = 0x80047459 + PPPIOCSMAXCID = 0x80047451 + PPPIOCSMRRU = 0x8004743b + PPPIOCSMRU = 0x80047452 + PPPIOCSNPMODE = 0x8008744b + PPPIOCSPASS = 0x80107447 + PPPIOCSRASYNCMAP = 0x80047454 + PPPIOCSXASYNCMAP = 0x8020744f + PPPIOCXFERUNIT = 0x2000744e PRIO_PGRP = 0x1 PRIO_PROCESS = 0x0 PRIO_USER = 0x2 + PROC_SUPER_MAGIC = 0x9fa0 PROT_EXEC = 0x4 PROT_GROWSDOWN = 0x1000000 PROT_GROWSUP = 0x2000000 @@ -1148,6 +1382,7 @@ const ( PR_GET_PDEATHSIG = 0x2 PR_GET_SECCOMP = 0x15 PR_GET_SECUREBITS = 0x1b + PR_GET_SPECULATION_CTRL = 0x34 PR_GET_THP_DISABLE = 0x2a PR_GET_TID_ADDRESS = 0x28 PR_GET_TIMERSLACK = 0x1e @@ -1193,11 +1428,24 @@ const ( PR_SET_PTRACER_ANY = 0xffffffffffffffff PR_SET_SECCOMP = 0x16 PR_SET_SECUREBITS = 0x1c + PR_SET_SPECULATION_CTRL = 0x35 PR_SET_THP_DISABLE = 0x29 PR_SET_TIMERSLACK = 0x1d PR_SET_TIMING = 0xe PR_SET_TSC = 0x1a PR_SET_UNALIGN = 0x6 + PR_SPEC_DISABLE = 0x4 + PR_SPEC_ENABLE = 0x2 + PR_SPEC_FORCE_DISABLE = 0x8 + PR_SPEC_INDIRECT_BRANCH = 0x1 + PR_SPEC_NOT_AFFECTED = 0x0 + PR_SPEC_PRCTL = 0x1 + PR_SPEC_STORE_BYPASS = 0x0 + PR_SVE_GET_VL = 0x33 + PR_SVE_SET_VL = 0x32 + PR_SVE_SET_VL_ONEXEC = 0x40000 + PR_SVE_VL_INHERIT = 0x20000 + PR_SVE_VL_LEN_MASK = 0xffff PR_TASK_PERF_EVENTS_DISABLE = 0x1f PR_TASK_PERF_EVENTS_ENABLE = 0x20 PR_TIMING_STATISTICAL = 0x0 @@ -1206,6 +1454,7 @@ const ( PR_TSC_SIGSEGV = 0x2 PR_UNALIGN_NOPRINT = 0x1 PR_UNALIGN_SIGBUS = 0x2 + PSTOREFS_MAGIC = 0x6165676c PTRACE_ATTACH = 0x10 PTRACE_CONT = 0x7 PTRACE_DETACH = 0x11 @@ -1251,6 +1500,7 @@ const ( PTRACE_POKETEXT = 0x4 PTRACE_POKEUSR = 0x6 PTRACE_SECCOMP_GET_FILTER = 0x420c + PTRACE_SECCOMP_GET_METADATA = 0x420d PTRACE_SEIZE = 0x4206 PTRACE_SETEVRREGS = 0x15 PTRACE_SETFPREGS = 0xf @@ -1266,6 +1516,8 @@ const ( PTRACE_SINGLEBLOCK = 0x100 PTRACE_SINGLESTEP = 0x9 PTRACE_SYSCALL = 0x18 + PTRACE_SYSEMU = 0x1d + PTRACE_SYSEMU_SINGLESTEP = 0x1e PTRACE_TRACEME = 0x0 PT_CCR = 0x26 PT_CTR = 0x23 @@ -1320,6 +1572,14 @@ const ( PT_VSR0 = 0x96 PT_VSR31 = 0xd4 PT_XER = 0x25 + QNX4_SUPER_MAGIC = 0x2f + QNX6_SUPER_MAGIC = 0x68191122 + RAMFS_MAGIC = 0x858458f6 + RDTGROUP_SUPER_MAGIC = 0x7655821 + REISERFS_SUPER_MAGIC = 0x52654973 + RENAME_EXCHANGE = 0x2 + RENAME_NOREPLACE = 0x1 + RENAME_WHITEOUT = 0x4 RLIMIT_AS = 0x9 RLIMIT_CORE = 0x4 RLIMIT_CPU = 0x0 @@ -1337,9 +1597,17 @@ const ( RLIMIT_SIGPENDING = 0xb RLIMIT_STACK = 0x3 RLIM_INFINITY = 0xffffffffffffffff + RNDADDENTROPY = 0x80085203 + RNDADDTOENTCNT = 0x80045201 + RNDCLEARPOOL = 0x20005206 + RNDGETENTCNT = 0x40045200 + RNDGETPOOL = 0x40085202 + RNDRESEEDCRNG = 0x20005207 + RNDZAPENTCNT = 0x20005204 RTAX_ADVMSS = 0x8 RTAX_CC_ALGO = 0x10 RTAX_CWND = 0x7 + RTAX_FASTOPEN_NO_COOKIE = 0x11 RTAX_FEATURES = 0xc RTAX_FEATURE_ALLFRAG = 0x8 RTAX_FEATURE_ECN = 0x1 @@ -1350,7 +1618,7 @@ const ( RTAX_INITCWND = 0xb RTAX_INITRWND = 0xe RTAX_LOCK = 0x1 - RTAX_MAX = 0x10 + RTAX_MAX = 0x11 RTAX_MTU = 0x2 RTAX_QUICKACK = 0xf RTAX_REORDERING = 0x9 @@ -1361,13 +1629,40 @@ const ( RTAX_UNSPEC = 0x0 RTAX_WINDOW = 0x3 RTA_ALIGNTO = 0x4 - RTA_MAX = 0x1a + RTA_MAX = 0x1d RTCF_DIRECTSRC = 0x4000000 RTCF_DOREDIRECT = 0x1000000 RTCF_LOG = 0x2000000 RTCF_MASQ = 0x400000 RTCF_NAT = 0x800000 RTCF_VALVE = 0x200000 + RTC_AF = 0x20 + RTC_AIE_OFF = 0x20007002 + RTC_AIE_ON = 0x20007001 + RTC_ALM_READ = 0x40247008 + RTC_ALM_SET = 0x80247007 + RTC_EPOCH_READ = 0x4008700d + RTC_EPOCH_SET = 0x8008700e + RTC_IRQF = 0x80 + RTC_IRQP_READ = 0x4008700b + RTC_IRQP_SET = 0x8008700c + RTC_MAX_FREQ = 0x2000 + RTC_PF = 0x40 + RTC_PIE_OFF = 0x20007006 + RTC_PIE_ON = 0x20007005 + RTC_PLL_GET = 0x40207011 + RTC_PLL_SET = 0x80207012 + RTC_RD_TIME = 0x40247009 + RTC_SET_TIME = 0x8024700a + RTC_UF = 0x10 + RTC_UIE_OFF = 0x20007004 + RTC_UIE_ON = 0x20007003 + RTC_VL_CLR = 0x20007014 + RTC_VL_READ = 0x40047013 + RTC_WIE_OFF = 0x20007010 + RTC_WIE_ON = 0x2000700f + RTC_WKALM_RD = 0x40287010 + RTC_WKALM_SET = 0x8028700f RTF_ADDRCLASSMASK = 0xf8000000 RTF_ADDRCONF = 0x40000 RTF_ALLONLINK = 0x20000 @@ -1402,6 +1697,7 @@ const ( RTM_DELACTION = 0x31 RTM_DELADDR = 0x15 RTM_DELADDRLABEL = 0x49 + RTM_DELCHAIN = 0x65 RTM_DELLINK = 0x11 RTM_DELMDB = 0x55 RTM_DELNEIGH = 0x1d @@ -1422,6 +1718,7 @@ const ( RTM_GETADDR = 0x16 RTM_GETADDRLABEL = 0x4a RTM_GETANYCAST = 0x3e + RTM_GETCHAIN = 0x66 RTM_GETDCB = 0x4e RTM_GETLINK = 0x12 RTM_GETMDB = 0x56 @@ -1436,11 +1733,12 @@ const ( RTM_GETSTATS = 0x5e RTM_GETTCLASS = 0x2a RTM_GETTFILTER = 0x2e - RTM_MAX = 0x63 + RTM_MAX = 0x67 RTM_NEWACTION = 0x30 RTM_NEWADDR = 0x14 RTM_NEWADDRLABEL = 0x48 RTM_NEWCACHEREPORT = 0x60 + RTM_NEWCHAIN = 0x64 RTM_NEWLINK = 0x10 RTM_NEWMDB = 0x54 RTM_NEWNDUSEROPT = 0x44 @@ -1455,8 +1753,8 @@ const ( RTM_NEWSTATS = 0x5c RTM_NEWTCLASS = 0x28 RTM_NEWTFILTER = 0x2c - RTM_NR_FAMILIES = 0x15 - RTM_NR_MSGTYPES = 0x54 + RTM_NR_FAMILIES = 0x16 + RTM_NR_MSGTYPES = 0x58 RTM_SETDCB = 0x4f RTM_SETLINK = 0x13 RTM_SETNEIGHTBL = 0x43 @@ -1470,17 +1768,22 @@ const ( RTNH_F_UNRESOLVED = 0x20 RTN_MAX = 0xb RTPROT_BABEL = 0x2a + RTPROT_BGP = 0xba RTPROT_BIRD = 0xc RTPROT_BOOT = 0x3 RTPROT_DHCP = 0x10 RTPROT_DNROUTED = 0xd + RTPROT_EIGRP = 0xc0 RTPROT_GATED = 0x8 + RTPROT_ISIS = 0xbb RTPROT_KERNEL = 0x2 RTPROT_MROUTED = 0x11 RTPROT_MRT = 0xa RTPROT_NTK = 0xf + RTPROT_OSPF = 0xbc RTPROT_RA = 0x9 RTPROT_REDIRECT = 0x1 + RTPROT_RIP = 0xbd RTPROT_STATIC = 0x4 RTPROT_UNSPEC = 0x0 RTPROT_XORP = 0xe @@ -1500,10 +1803,16 @@ const ( SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SC_LOG_FLUSH = 0x100000 SECCOMP_MODE_DISABLED = 0x0 SECCOMP_MODE_FILTER = 0x2 SECCOMP_MODE_STRICT = 0x1 + SECURITYFS_MAGIC = 0x73636673 + SELINUX_MAGIC = 0xf97cff8c + SFD_CLOEXEC = 0x80000 + SFD_NONBLOCK = 0x800 SHUT_RD = 0x0 SHUT_RDWR = 0x2 SHUT_WR = 0x1 @@ -1554,6 +1863,9 @@ const ( SIOCGMIIPHY = 0x8947 SIOCGMIIREG = 0x8948 SIOCGPGRP = 0x8904 + SIOCGPPPCSTATS = 0x89f2 + SIOCGPPPSTATS = 0x89f0 + SIOCGPPPVER = 0x89f1 SIOCGRARP = 0x8961 SIOCGSKNS = 0x894c SIOCGSTAMP = 0x8906 @@ -1588,6 +1900,23 @@ const ( SIOCSPGRP = 0x8902 SIOCSRARP = 0x8962 SIOCWANDEV = 0x894a + SMACK_MAGIC = 0x43415d53 + SMART_AUTOSAVE = 0xd2 + SMART_AUTO_OFFLINE = 0xdb + SMART_DISABLE = 0xd9 + SMART_ENABLE = 0xd8 + SMART_HCYL_PASS = 0xc2 + SMART_IMMEDIATE_OFFLINE = 0xd4 + SMART_LCYL_PASS = 0x4f + SMART_READ_LOG_SECTOR = 0xd5 + SMART_READ_THRESHOLDS = 0xd1 + SMART_READ_VALUES = 0xd0 + SMART_SAVE = 0xd3 + SMART_STATUS = 0xda + SMART_WRITE_LOG_SECTOR = 0xd6 + SMART_WRITE_THRESHOLDS = 0xd7 + SMB_SUPER_MAGIC = 0x517b + SOCKFS_MAGIC = 0x534f434b SOCK_CLOEXEC = 0x80000 SOCK_DCCP = 0x6 SOCK_DGRAM = 0x2 @@ -1624,7 +1953,9 @@ const ( SOL_SOCKET = 0x1 SOL_TCP = 0x6 SOL_TIPC = 0x10f + SOL_TLS = 0x11a SOL_X25 = 0x106 + SOL_XDP = 0x11b SOMAXCONN = 0x80 SO_ACCEPTCONN = 0x1e SO_ATTACH_BPF = 0x32 @@ -1643,6 +1974,17 @@ const ( SO_DETACH_FILTER = 0x1b SO_DOMAIN = 0x27 SO_DONTROUTE = 0x5 + SO_EE_CODE_TXTIME_INVALID_PARAM = 0x1 + SO_EE_CODE_TXTIME_MISSED = 0x2 + SO_EE_CODE_ZEROCOPY_COPIED = 0x1 + SO_EE_ORIGIN_ICMP = 0x2 + SO_EE_ORIGIN_ICMP6 = 0x3 + SO_EE_ORIGIN_LOCAL = 0x1 + SO_EE_ORIGIN_NONE = 0x0 + SO_EE_ORIGIN_TIMESTAMPING = 0x4 + SO_EE_ORIGIN_TXSTATUS = 0x4 + SO_EE_ORIGIN_TXTIME = 0x6 + SO_EE_ORIGIN_ZEROCOPY = 0x5 SO_ERROR = 0x4 SO_GET_FILTER = 0x1a SO_INCOMING_CPU = 0x31 @@ -1683,6 +2025,7 @@ const ( SO_TIMESTAMP = 0x1d SO_TIMESTAMPING = 0x25 SO_TIMESTAMPNS = 0x23 + SO_TXTIME = 0x3d SO_TYPE = 0x3 SO_VM_SOCKETS_BUFFER_MAX_SIZE = 0x2 SO_VM_SOCKETS_BUFFER_MIN_SIZE = 0x1 @@ -1692,10 +2035,38 @@ const ( SO_VM_SOCKETS_PEER_HOST_VM_ID = 0x3 SO_VM_SOCKETS_TRUSTED = 0x5 SO_WIFI_STATUS = 0x29 + SO_ZEROCOPY = 0x3c SPLICE_F_GIFT = 0x8 SPLICE_F_MORE = 0x4 SPLICE_F_MOVE = 0x1 SPLICE_F_NONBLOCK = 0x2 + SQUASHFS_MAGIC = 0x73717368 + STACK_END_MAGIC = 0x57ac6e9d + STATX_ALL = 0xfff + STATX_ATIME = 0x20 + STATX_ATTR_APPEND = 0x20 + STATX_ATTR_AUTOMOUNT = 0x1000 + STATX_ATTR_COMPRESSED = 0x4 + STATX_ATTR_ENCRYPTED = 0x800 + STATX_ATTR_IMMUTABLE = 0x10 + STATX_ATTR_NODUMP = 0x40 + STATX_BASIC_STATS = 0x7ff + STATX_BLOCKS = 0x400 + STATX_BTIME = 0x800 + STATX_CTIME = 0x80 + STATX_GID = 0x10 + STATX_INO = 0x100 + STATX_MODE = 0x2 + STATX_MTIME = 0x40 + STATX_NLINK = 0x4 + STATX_SIZE = 0x200 + STATX_TYPE = 0x1 + STATX_UID = 0x8 + STATX__RESERVED = 0x80000000 + SYNC_FILE_RANGE_WAIT_AFTER = 0x4 + SYNC_FILE_RANGE_WAIT_BEFORE = 0x1 + SYNC_FILE_RANGE_WRITE = 0x2 + SYSFS_MAGIC = 0x62656572 S_BLKSIZE = 0x200 S_IEXEC = 0x40 S_IFBLK = 0x6000 @@ -1733,7 +2104,7 @@ const ( TASKSTATS_GENL_NAME = "TASKSTATS" TASKSTATS_GENL_VERSION = 0x1 TASKSTATS_TYPE_MAX = 0x6 - TASKSTATS_VERSION = 0x8 + TASKSTATS_VERSION = 0x9 TCFLSH = 0x2000741f TCGETA = 0x40147417 TCGETS = 0x402c7413 @@ -1745,6 +2116,7 @@ const ( TCOOFF = 0x0 TCOON = 0x1 TCP_CC_INFO = 0x1a + TCP_CM_INQ = 0x24 TCP_CONGESTION = 0xd TCP_COOKIE_IN_ALWAYS = 0x1 TCP_COOKIE_MAX = 0x10 @@ -1756,7 +2128,10 @@ const ( TCP_DEFER_ACCEPT = 0x9 TCP_FASTOPEN = 0x17 TCP_FASTOPEN_CONNECT = 0x1e + TCP_FASTOPEN_KEY = 0x21 + TCP_FASTOPEN_NO_COOKIE = 0x22 TCP_INFO = 0xb + TCP_INQ = 0x24 TCP_KEEPCNT = 0x6 TCP_KEEPIDLE = 0x4 TCP_KEEPINTVL = 0x5 @@ -1765,6 +2140,8 @@ const ( TCP_MAXWIN = 0xffff TCP_MAX_WINSHIFT = 0xe TCP_MD5SIG = 0xe + TCP_MD5SIG_EXT = 0x20 + TCP_MD5SIG_FLAG_PREFIX = 0x1 TCP_MD5SIG_MAXKEYLEN = 0x50 TCP_MSS = 0x200 TCP_MSS_DEFAULT = 0x218 @@ -1774,6 +2151,9 @@ const ( TCP_QUEUE_SEQ = 0x15 TCP_QUICKACK = 0xc TCP_REPAIR = 0x13 + TCP_REPAIR_OFF = 0x0 + TCP_REPAIR_OFF_NO_WP = -0x1 + TCP_REPAIR_ON = 0x1 TCP_REPAIR_OPTIONS = 0x16 TCP_REPAIR_QUEUE = 0x14 TCP_REPAIR_WINDOW = 0x1d @@ -1785,8 +2165,10 @@ const ( TCP_THIN_DUPACK = 0x11 TCP_THIN_LINEAR_TIMEOUTS = 0x10 TCP_TIMESTAMP = 0x18 + TCP_ULP = 0x1f TCP_USER_TIMEOUT = 0x12 TCP_WINDOW_CLAMP = 0xa + TCP_ZEROCOPY_RECEIVE = 0x23 TCSAFLUSH = 0x2 TCSBRK = 0x2000741d TCSBRKP = 0x5425 @@ -1797,6 +2179,7 @@ const ( TCSETSF = 0x802c7416 TCSETSW = 0x802c7415 TCXONC = 0x2000741e + TIMER_ABSTIME = 0x1 TIOCCBRK = 0x5428 TIOCCONS = 0x541d TIOCEXCL = 0x540c @@ -1806,6 +2189,7 @@ const ( TIOCGETP = 0x40067408 TIOCGEXCL = 0x40045440 TIOCGICOUNT = 0x545d + TIOCGISO7816 = 0x40285442 TIOCGLCKTRMIOS = 0x5456 TIOCGLTC = 0x40067474 TIOCGPGRP = 0x40047477 @@ -1866,6 +2250,7 @@ const ( TIOCSETN = 0x8006740a TIOCSETP = 0x80067409 TIOCSIG = 0x80045436 + TIOCSISO7816 = 0xc0285443 TIOCSLCKTRMIOS = 0x5457 TIOCSLTC = 0x80067475 TIOCSPGRP = 0x80047476 @@ -1878,7 +2263,27 @@ const ( TIOCSTOP = 0x2000746f TIOCSWINSZ = 0x80087467 TIOCVHANGUP = 0x5437 + TMPFS_MAGIC = 0x1021994 TOSTOP = 0x400000 + TPACKET_ALIGNMENT = 0x10 + TPACKET_HDRLEN = 0x34 + TP_STATUS_AVAILABLE = 0x0 + TP_STATUS_BLK_TMO = 0x20 + TP_STATUS_COPY = 0x2 + TP_STATUS_CSUMNOTREADY = 0x8 + TP_STATUS_CSUM_VALID = 0x80 + TP_STATUS_KERNEL = 0x0 + TP_STATUS_LOSING = 0x4 + TP_STATUS_SENDING = 0x2 + TP_STATUS_SEND_REQUEST = 0x1 + TP_STATUS_TS_RAW_HARDWARE = -0x80000000 + TP_STATUS_TS_SOFTWARE = 0x20000000 + TP_STATUS_TS_SYS_HARDWARE = 0x40000000 + TP_STATUS_USER = 0x1 + TP_STATUS_VLAN_TPID_VALID = 0x40 + TP_STATUS_VLAN_VALID = 0x10 + TP_STATUS_WRONG_FORMAT = 0x4 + TRACEFS_MAGIC = 0x74726163 TS_COMM_LEN = 0x20 TUNATTACHFILTER = 0x801054d5 TUNDETACHFILTER = 0x801054d6 @@ -1890,6 +2295,7 @@ const ( TUNGETVNETHDRSZ = 0x400454d7 TUNGETVNETLE = 0x400454dd TUNSETDEBUG = 0x800454c9 + TUNSETFILTEREBPF = 0x400454e1 TUNSETGROUP = 0x800454ce TUNSETIFF = 0x800454ca TUNSETIFINDEX = 0x800454da @@ -1900,13 +2306,32 @@ const ( TUNSETPERSIST = 0x800454cb TUNSETQUEUE = 0x800454d9 TUNSETSNDBUF = 0x800454d4 + TUNSETSTEERINGEBPF = 0x400454e0 TUNSETTXFILTER = 0x800454d1 TUNSETVNETBE = 0x800454de TUNSETVNETHDRSZ = 0x800454d8 TUNSETVNETLE = 0x800454dc + UBI_IOCATT = 0x80186f40 + UBI_IOCDET = 0x80046f41 + UBI_IOCEBCH = 0x80044f02 + UBI_IOCEBER = 0x80044f01 + UBI_IOCEBISMAP = 0x40044f05 + UBI_IOCEBMAP = 0x80084f03 + UBI_IOCEBUNMAP = 0x80044f04 + UBI_IOCMKVOL = 0x80986f00 + UBI_IOCRMVOL = 0x80046f01 + UBI_IOCRNVOL = 0x91106f03 + UBI_IOCRSVOL = 0x800c6f02 + UBI_IOCSETVOLPROP = 0x80104f06 + UBI_IOCVOLCRBLK = 0x80804f07 + UBI_IOCVOLRMBLK = 0x20004f08 + UBI_IOCVOLUP = 0x80084f00 + UDF_SUPER_MAGIC = 0x15013346 UMOUNT_NOFOLLOW = 0x8 + USBDEVICE_SUPER_MAGIC = 0x9fa2 UTIME_NOW = 0x3fffffff UTIME_OMIT = 0x3ffffffe + V9FS_MAGIC = 0x1021997 VDISCARD = 0x10 VEOF = 0x4 VEOL = 0x6 @@ -1948,6 +2373,86 @@ const ( WDIOC_SETPRETIMEOUT = 0xc0045708 WDIOC_SETTIMEOUT = 0xc0045706 WEXITED = 0x4 + WIN_ACKMEDIACHANGE = 0xdb + WIN_CHECKPOWERMODE1 = 0xe5 + WIN_CHECKPOWERMODE2 = 0x98 + WIN_DEVICE_RESET = 0x8 + WIN_DIAGNOSE = 0x90 + WIN_DOORLOCK = 0xde + WIN_DOORUNLOCK = 0xdf + WIN_DOWNLOAD_MICROCODE = 0x92 + WIN_FLUSH_CACHE = 0xe7 + WIN_FLUSH_CACHE_EXT = 0xea + WIN_FORMAT = 0x50 + WIN_GETMEDIASTATUS = 0xda + WIN_IDENTIFY = 0xec + WIN_IDENTIFY_DMA = 0xee + WIN_IDLEIMMEDIATE = 0xe1 + WIN_INIT = 0x60 + WIN_MEDIAEJECT = 0xed + WIN_MULTREAD = 0xc4 + WIN_MULTREAD_EXT = 0x29 + WIN_MULTWRITE = 0xc5 + WIN_MULTWRITE_EXT = 0x39 + WIN_NOP = 0x0 + WIN_PACKETCMD = 0xa0 + WIN_PIDENTIFY = 0xa1 + WIN_POSTBOOT = 0xdc + WIN_PREBOOT = 0xdd + WIN_QUEUED_SERVICE = 0xa2 + WIN_READ = 0x20 + WIN_READDMA = 0xc8 + WIN_READDMA_EXT = 0x25 + WIN_READDMA_ONCE = 0xc9 + WIN_READDMA_QUEUED = 0xc7 + WIN_READDMA_QUEUED_EXT = 0x26 + WIN_READ_BUFFER = 0xe4 + WIN_READ_EXT = 0x24 + WIN_READ_LONG = 0x22 + WIN_READ_LONG_ONCE = 0x23 + WIN_READ_NATIVE_MAX = 0xf8 + WIN_READ_NATIVE_MAX_EXT = 0x27 + WIN_READ_ONCE = 0x21 + WIN_RECAL = 0x10 + WIN_RESTORE = 0x10 + WIN_SECURITY_DISABLE = 0xf6 + WIN_SECURITY_ERASE_PREPARE = 0xf3 + WIN_SECURITY_ERASE_UNIT = 0xf4 + WIN_SECURITY_FREEZE_LOCK = 0xf5 + WIN_SECURITY_SET_PASS = 0xf1 + WIN_SECURITY_UNLOCK = 0xf2 + WIN_SEEK = 0x70 + WIN_SETFEATURES = 0xef + WIN_SETIDLE1 = 0xe3 + WIN_SETIDLE2 = 0x97 + WIN_SETMULT = 0xc6 + WIN_SET_MAX = 0xf9 + WIN_SET_MAX_EXT = 0x37 + WIN_SLEEPNOW1 = 0xe6 + WIN_SLEEPNOW2 = 0x99 + WIN_SMART = 0xb0 + WIN_SPECIFY = 0x91 + WIN_SRST = 0x8 + WIN_STANDBY = 0xe2 + WIN_STANDBY2 = 0x96 + WIN_STANDBYNOW1 = 0xe0 + WIN_STANDBYNOW2 = 0x94 + WIN_VERIFY = 0x40 + WIN_VERIFY_EXT = 0x42 + WIN_VERIFY_ONCE = 0x41 + WIN_WRITE = 0x30 + WIN_WRITEDMA = 0xca + WIN_WRITEDMA_EXT = 0x35 + WIN_WRITEDMA_ONCE = 0xcb + WIN_WRITEDMA_QUEUED = 0xcc + WIN_WRITEDMA_QUEUED_EXT = 0x36 + WIN_WRITE_BUFFER = 0xe8 + WIN_WRITE_EXT = 0x34 + WIN_WRITE_LONG = 0x32 + WIN_WRITE_LONG_ONCE = 0x33 + WIN_WRITE_ONCE = 0x31 + WIN_WRITE_SAME = 0xe9 + WIN_WRITE_VERIFY = 0x3c WNOHANG = 0x1 WNOTHREAD = 0x20000000 WNOWAIT = 0x1000000 @@ -1957,7 +2462,30 @@ const ( XATTR_CREATE = 0x1 XATTR_REPLACE = 0x2 XCASE = 0x4000 + XDP_COPY = 0x2 + XDP_FLAGS_DRV_MODE = 0x4 + XDP_FLAGS_HW_MODE = 0x8 + XDP_FLAGS_MASK = 0xf + XDP_FLAGS_MODES = 0xe + XDP_FLAGS_SKB_MODE = 0x2 + XDP_FLAGS_UPDATE_IF_NOEXIST = 0x1 + XDP_MMAP_OFFSETS = 0x1 + XDP_PGOFF_RX_RING = 0x0 + XDP_PGOFF_TX_RING = 0x80000000 + XDP_RX_RING = 0x2 + XDP_SHARED_UMEM = 0x1 + XDP_STATISTICS = 0x7 + XDP_TX_RING = 0x3 + XDP_UMEM_COMPLETION_RING = 0x6 + XDP_UMEM_FILL_RING = 0x5 + XDP_UMEM_PGOFF_COMPLETION_RING = 0x180000000 + XDP_UMEM_PGOFF_FILL_RING = 0x100000000 + XDP_UMEM_REG = 0x4 + XDP_ZEROCOPY = 0x4 + XENFS_SUPER_MAGIC = 0xabba1974 + XFS_SUPER_MAGIC = 0x58465342 XTABS = 0xc00 + ZSMALLOC_MAGIC = 0x58295829 ) // Errors @@ -2137,172 +2665,180 @@ const ( ) // Error table -var errors = [...]string{ - 1: "operation not permitted", - 2: "no such file or directory", - 3: "no such process", - 4: "interrupted system call", - 5: "input/output error", - 6: "no such device or address", - 7: "argument list too long", - 8: "exec format error", - 9: "bad file descriptor", - 10: "no child processes", - 11: "resource temporarily unavailable", - 12: "cannot allocate memory", - 13: "permission denied", - 14: "bad address", - 15: "block device required", - 16: "device or resource busy", - 17: "file exists", - 18: "invalid cross-device link", - 19: "no such device", - 20: "not a directory", - 21: "is a directory", - 22: "invalid argument", - 23: "too many open files in system", - 24: "too many open files", - 25: "inappropriate ioctl for device", - 26: "text file busy", - 27: "file too large", - 28: "no space left on device", - 29: "illegal seek", - 30: "read-only file system", - 31: "too many links", - 32: "broken pipe", - 33: "numerical argument out of domain", - 34: "numerical result out of range", - 35: "resource deadlock avoided", - 36: "file name too long", - 37: "no locks available", - 38: "function not implemented", - 39: "directory not empty", - 40: "too many levels of symbolic links", - 42: "no message of desired type", - 43: "identifier removed", - 44: "channel number out of range", - 45: "level 2 not synchronized", - 46: "level 3 halted", - 47: "level 3 reset", - 48: "link number out of range", - 49: "protocol driver not attached", - 50: "no CSI structure available", - 51: "level 2 halted", - 52: "invalid exchange", - 53: "invalid request descriptor", - 54: "exchange full", - 55: "no anode", - 56: "invalid request code", - 57: "invalid slot", - 58: "file locking deadlock error", - 59: "bad font file format", - 60: "device not a stream", - 61: "no data available", - 62: "timer expired", - 63: "out of streams resources", - 64: "machine is not on the network", - 65: "package not installed", - 66: "object is remote", - 67: "link has been severed", - 68: "advertise error", - 69: "srmount error", - 70: "communication error on send", - 71: "protocol error", - 72: "multihop attempted", - 73: "RFS specific error", - 74: "bad message", - 75: "value too large for defined data type", - 76: "name not unique on network", - 77: "file descriptor in bad state", - 78: "remote address changed", - 79: "can not access a needed shared library", - 80: "accessing a corrupted shared library", - 81: ".lib section in a.out corrupted", - 82: "attempting to link in too many shared libraries", - 83: "cannot exec a shared library directly", - 84: "invalid or incomplete multibyte or wide character", - 85: "interrupted system call should be restarted", - 86: "streams pipe error", - 87: "too many users", - 88: "socket operation on non-socket", - 89: "destination address required", - 90: "message too long", - 91: "protocol wrong type for socket", - 92: "protocol not available", - 93: "protocol not supported", - 94: "socket type not supported", - 95: "operation not supported", - 96: "protocol family not supported", - 97: "address family not supported by protocol", - 98: "address already in use", - 99: "cannot assign requested address", - 100: "network is down", - 101: "network is unreachable", - 102: "network dropped connection on reset", - 103: "software caused connection abort", - 104: "connection reset by peer", - 105: "no buffer space available", - 106: "transport endpoint is already connected", - 107: "transport endpoint is not connected", - 108: "cannot send after transport endpoint shutdown", - 109: "too many references: cannot splice", - 110: "connection timed out", - 111: "connection refused", - 112: "host is down", - 113: "no route to host", - 114: "operation already in progress", - 115: "operation now in progress", - 116: "stale file handle", - 117: "structure needs cleaning", - 118: "not a XENIX named type file", - 119: "no XENIX semaphores available", - 120: "is a named type file", - 121: "remote I/O error", - 122: "disk quota exceeded", - 123: "no medium found", - 124: "wrong medium type", - 125: "operation canceled", - 126: "required key not available", - 127: "key has expired", - 128: "key has been revoked", - 129: "key was rejected by service", - 130: "owner died", - 131: "state not recoverable", - 132: "operation not possible due to RF-kill", - 133: "memory page has hardware error", +var errorList = [...]struct { + num syscall.Errno + name string + desc string +}{ + {1, "EPERM", "operation not permitted"}, + {2, "ENOENT", "no such file or directory"}, + {3, "ESRCH", "no such process"}, + {4, "EINTR", "interrupted system call"}, + {5, "EIO", "input/output error"}, + {6, "ENXIO", "no such device or address"}, + {7, "E2BIG", "argument list too long"}, + {8, "ENOEXEC", "exec format error"}, + {9, "EBADF", "bad file descriptor"}, + {10, "ECHILD", "no child processes"}, + {11, "EAGAIN", "resource temporarily unavailable"}, + {12, "ENOMEM", "cannot allocate memory"}, + {13, "EACCES", "permission denied"}, + {14, "EFAULT", "bad address"}, + {15, "ENOTBLK", "block device required"}, + {16, "EBUSY", "device or resource busy"}, + {17, "EEXIST", "file exists"}, + {18, "EXDEV", "invalid cross-device link"}, + {19, "ENODEV", "no such device"}, + {20, "ENOTDIR", "not a directory"}, + {21, "EISDIR", "is a directory"}, + {22, "EINVAL", "invalid argument"}, + {23, "ENFILE", "too many open files in system"}, + {24, "EMFILE", "too many open files"}, + {25, "ENOTTY", "inappropriate ioctl for device"}, + {26, "ETXTBSY", "text file busy"}, + {27, "EFBIG", "file too large"}, + {28, "ENOSPC", "no space left on device"}, + {29, "ESPIPE", "illegal seek"}, + {30, "EROFS", "read-only file system"}, + {31, "EMLINK", "too many links"}, + {32, "EPIPE", "broken pipe"}, + {33, "EDOM", "numerical argument out of domain"}, + {34, "ERANGE", "numerical result out of range"}, + {35, "EDEADLK", "resource deadlock avoided"}, + {36, "ENAMETOOLONG", "file name too long"}, + {37, "ENOLCK", "no locks available"}, + {38, "ENOSYS", "function not implemented"}, + {39, "ENOTEMPTY", "directory not empty"}, + {40, "ELOOP", "too many levels of symbolic links"}, + {42, "ENOMSG", "no message of desired type"}, + {43, "EIDRM", "identifier removed"}, + {44, "ECHRNG", "channel number out of range"}, + {45, "EL2NSYNC", "level 2 not synchronized"}, + {46, "EL3HLT", "level 3 halted"}, + {47, "EL3RST", "level 3 reset"}, + {48, "ELNRNG", "link number out of range"}, + {49, "EUNATCH", "protocol driver not attached"}, + {50, "ENOCSI", "no CSI structure available"}, + {51, "EL2HLT", "level 2 halted"}, + {52, "EBADE", "invalid exchange"}, + {53, "EBADR", "invalid request descriptor"}, + {54, "EXFULL", "exchange full"}, + {55, "ENOANO", "no anode"}, + {56, "EBADRQC", "invalid request code"}, + {57, "EBADSLT", "invalid slot"}, + {58, "EDEADLOCK", "file locking deadlock error"}, + {59, "EBFONT", "bad font file format"}, + {60, "ENOSTR", "device not a stream"}, + {61, "ENODATA", "no data available"}, + {62, "ETIME", "timer expired"}, + {63, "ENOSR", "out of streams resources"}, + {64, "ENONET", "machine is not on the network"}, + {65, "ENOPKG", "package not installed"}, + {66, "EREMOTE", "object is remote"}, + {67, "ENOLINK", "link has been severed"}, + {68, "EADV", "advertise error"}, + {69, "ESRMNT", "srmount error"}, + {70, "ECOMM", "communication error on send"}, + {71, "EPROTO", "protocol error"}, + {72, "EMULTIHOP", "multihop attempted"}, + {73, "EDOTDOT", "RFS specific error"}, + {74, "EBADMSG", "bad message"}, + {75, "EOVERFLOW", "value too large for defined data type"}, + {76, "ENOTUNIQ", "name not unique on network"}, + {77, "EBADFD", "file descriptor in bad state"}, + {78, "EREMCHG", "remote address changed"}, + {79, "ELIBACC", "can not access a needed shared library"}, + {80, "ELIBBAD", "accessing a corrupted shared library"}, + {81, "ELIBSCN", ".lib section in a.out corrupted"}, + {82, "ELIBMAX", "attempting to link in too many shared libraries"}, + {83, "ELIBEXEC", "cannot exec a shared library directly"}, + {84, "EILSEQ", "invalid or incomplete multibyte or wide character"}, + {85, "ERESTART", "interrupted system call should be restarted"}, + {86, "ESTRPIPE", "streams pipe error"}, + {87, "EUSERS", "too many users"}, + {88, "ENOTSOCK", "socket operation on non-socket"}, + {89, "EDESTADDRREQ", "destination address required"}, + {90, "EMSGSIZE", "message too long"}, + {91, "EPROTOTYPE", "protocol wrong type for socket"}, + {92, "ENOPROTOOPT", "protocol not available"}, + {93, "EPROTONOSUPPORT", "protocol not supported"}, + {94, "ESOCKTNOSUPPORT", "socket type not supported"}, + {95, "ENOTSUP", "operation not supported"}, + {96, "EPFNOSUPPORT", "protocol family not supported"}, + {97, "EAFNOSUPPORT", "address family not supported by protocol"}, + {98, "EADDRINUSE", "address already in use"}, + {99, "EADDRNOTAVAIL", "cannot assign requested address"}, + {100, "ENETDOWN", "network is down"}, + {101, "ENETUNREACH", "network is unreachable"}, + {102, "ENETRESET", "network dropped connection on reset"}, + {103, "ECONNABORTED", "software caused connection abort"}, + {104, "ECONNRESET", "connection reset by peer"}, + {105, "ENOBUFS", "no buffer space available"}, + {106, "EISCONN", "transport endpoint is already connected"}, + {107, "ENOTCONN", "transport endpoint is not connected"}, + {108, "ESHUTDOWN", "cannot send after transport endpoint shutdown"}, + {109, "ETOOMANYREFS", "too many references: cannot splice"}, + {110, "ETIMEDOUT", "connection timed out"}, + {111, "ECONNREFUSED", "connection refused"}, + {112, "EHOSTDOWN", "host is down"}, + {113, "EHOSTUNREACH", "no route to host"}, + {114, "EALREADY", "operation already in progress"}, + {115, "EINPROGRESS", "operation now in progress"}, + {116, "ESTALE", "stale file handle"}, + {117, "EUCLEAN", "structure needs cleaning"}, + {118, "ENOTNAM", "not a XENIX named type file"}, + {119, "ENAVAIL", "no XENIX semaphores available"}, + {120, "EISNAM", "is a named type file"}, + {121, "EREMOTEIO", "remote I/O error"}, + {122, "EDQUOT", "disk quota exceeded"}, + {123, "ENOMEDIUM", "no medium found"}, + {124, "EMEDIUMTYPE", "wrong medium type"}, + {125, "ECANCELED", "operation canceled"}, + {126, "ENOKEY", "required key not available"}, + {127, "EKEYEXPIRED", "key has expired"}, + {128, "EKEYREVOKED", "key has been revoked"}, + {129, "EKEYREJECTED", "key was rejected by service"}, + {130, "EOWNERDEAD", "owner died"}, + {131, "ENOTRECOVERABLE", "state not recoverable"}, + {132, "ERFKILL", "operation not possible due to RF-kill"}, + {133, "EHWPOISON", "memory page has hardware error"}, } // Signal table -var signals = [...]string{ - 1: "hangup", - 2: "interrupt", - 3: "quit", - 4: "illegal instruction", - 5: "trace/breakpoint trap", - 6: "aborted", - 7: "bus error", - 8: "floating point exception", - 9: "killed", - 10: "user defined signal 1", - 11: "segmentation fault", - 12: "user defined signal 2", - 13: "broken pipe", - 14: "alarm clock", - 15: "terminated", - 16: "stack fault", - 17: "child exited", - 18: "continued", - 19: "stopped (signal)", - 20: "stopped", - 21: "stopped (tty input)", - 22: "stopped (tty output)", - 23: "urgent I/O condition", - 24: "CPU time limit exceeded", - 25: "file size limit exceeded", - 26: "virtual timer expired", - 27: "profiling timer expired", - 28: "window changed", - 29: "I/O possible", - 30: "power failure", - 31: "bad system call", +var signalList = [...]struct { + num syscall.Signal + name string + desc string +}{ + {1, "SIGHUP", "hangup"}, + {2, "SIGINT", "interrupt"}, + {3, "SIGQUIT", "quit"}, + {4, "SIGILL", "illegal instruction"}, + {5, "SIGTRAP", "trace/breakpoint trap"}, + {6, "SIGABRT", "aborted"}, + {7, "SIGBUS", "bus error"}, + {8, "SIGFPE", "floating point exception"}, + {9, "SIGKILL", "killed"}, + {10, "SIGUSR1", "user defined signal 1"}, + {11, "SIGSEGV", "segmentation fault"}, + {12, "SIGUSR2", "user defined signal 2"}, + {13, "SIGPIPE", "broken pipe"}, + {14, "SIGALRM", "alarm clock"}, + {15, "SIGTERM", "terminated"}, + {16, "SIGSTKFLT", "stack fault"}, + {17, "SIGCHLD", "child exited"}, + {18, "SIGCONT", "continued"}, + {19, "SIGSTOP", "stopped (signal)"}, + {20, "SIGTSTP", "stopped"}, + {21, "SIGTTIN", "stopped (tty input)"}, + {22, "SIGTTOU", "stopped (tty output)"}, + {23, "SIGURG", "urgent I/O condition"}, + {24, "SIGXCPU", "CPU time limit exceeded"}, + {25, "SIGXFSZ", "file size limit exceeded"}, + {26, "SIGVTALRM", "virtual timer expired"}, + {27, "SIGPROF", "profiling timer expired"}, + {28, "SIGWINCH", "window changed"}, + {29, "SIGIO", "I/O possible"}, + {30, "SIGPWR", "power failure"}, + {31, "SIGSYS", "bad system call"}, } diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go index ddd256254f..02938cb6ed 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go @@ -3,7 +3,7 @@ // +build ppc64le,linux -// Created by cgo -godefs - DO NOT EDIT +// Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go package unix @@ -11,6 +11,11 @@ package unix import "syscall" const ( + AAFS_MAGIC = 0x5a3c69f0 + ADFS_SUPER_MAGIC = 0xadf5 + AFFS_SUPER_MAGIC = 0xadff + AFS_FS_MAGIC = 0x6b414653 + AFS_SUPER_MAGIC = 0x5346414f AF_ALG = 0x26 AF_APPLETALK = 0x5 AF_ASH = 0x12 @@ -36,7 +41,7 @@ const ( AF_KEY = 0xf AF_LLC = 0x1a AF_LOCAL = 0x1 - AF_MAX = 0x2c + AF_MAX = 0x2d AF_MPLS = 0x1c AF_NETBEUI = 0xd AF_NETLINK = 0x10 @@ -59,6 +64,7 @@ const ( AF_VSOCK = 0x28 AF_WANPIPE = 0x19 AF_X25 = 0x9 + AF_XDP = 0x2c ALG_OP_DECRYPT = 0x0 ALG_OP_ENCRYPT = 0x1 ALG_SET_AEAD_ASSOCLEN = 0x4 @@ -66,6 +72,7 @@ const ( ALG_SET_IV = 0x2 ALG_SET_KEY = 0x1 ALG_SET_OP = 0x3 + ANON_INODE_FS_MAGIC = 0x9041934 ARPHRD_6LOWPAN = 0x339 ARPHRD_ADAPT = 0x108 ARPHRD_APPLETLK = 0x8 @@ -121,6 +128,7 @@ const ( ARPHRD_PPP = 0x200 ARPHRD_PRONET = 0x4 ARPHRD_RAWHDLC = 0x206 + ARPHRD_RAWIP = 0x207 ARPHRD_ROSE = 0x10e ARPHRD_RSRVD = 0x104 ARPHRD_SIT = 0x308 @@ -132,6 +140,7 @@ const ( ARPHRD_VOID = 0xffff ARPHRD_VSOCKMON = 0x33a ARPHRD_X25 = 0x10f + AUTOFS_SUPER_MAGIC = 0x187 B0 = 0x0 B1000000 = 0x17 B110 = 0x3 @@ -163,6 +172,9 @@ const ( B75 = 0x2 B921600 = 0x16 B9600 = 0xd + BALLOON_KVM_MAGIC = 0x13661366 + BDEVFS_MAGIC = 0x62646576 + BINFMTFS_MAGIC = 0x42494e4d BLKBSZGET = 0x40081270 BLKBSZSET = 0x80081271 BLKFLSBUF = 0x20001261 @@ -187,6 +199,7 @@ const ( BPF_AND = 0x50 BPF_B = 0x10 BPF_DIV = 0x30 + BPF_FS_MAGIC = 0xcafe4a11 BPF_H = 0x8 BPF_IMM = 0x0 BPF_IND = 0x40 @@ -228,6 +241,8 @@ const ( BS0 = 0x0 BS1 = 0x8000 BSDLY = 0x8000 + BTRFS_SUPER_MAGIC = 0x9123683e + BTRFS_TEST_MAGIC = 0x73727279 CAN_BCM = 0x2 CAN_EFF_FLAG = 0x80000000 CAN_EFF_ID_BITS = 0x1d @@ -251,6 +266,8 @@ const ( CBAUD = 0xff CBAUDEX = 0x0 CFLUSH = 0xf + CGROUP2_SUPER_MAGIC = 0x63677270 + CGROUP_SUPER_MAGIC = 0x27e0eb CIBAUD = 0xff0000 CLOCAL = 0x8000 CLOCK_BOOTTIME = 0x7 @@ -293,10 +310,12 @@ const ( CLONE_VFORK = 0x4000 CLONE_VM = 0x100 CMSPAR = 0x40000000 + CODA_SUPER_MAGIC = 0x73757245 CR0 = 0x0 CR1 = 0x1000 CR2 = 0x2000 CR3 = 0x3000 + CRAMFS_MAGIC = 0x28cd3d45 CRDLY = 0x3000 CREAD = 0x800 CRTSCTS = 0x80000000 @@ -311,6 +330,9 @@ const ( CSTOP = 0x13 CSTOPB = 0x400 CSUSP = 0x1a + DAXFS_MAGIC = 0x64646178 + DEBUGFS_MAGIC = 0x64626720 + DEVPTS_SUPER_MAGIC = 0x1cd1 DT_BLK = 0x6 DT_CHR = 0x2 DT_DIR = 0x4 @@ -327,9 +349,12 @@ const ( ECHOKE = 0x1 ECHONL = 0x10 ECHOPRT = 0x20 + ECRYPTFS_SUPER_MAGIC = 0xf15f EFD_CLOEXEC = 0x80000 EFD_NONBLOCK = 0x800 EFD_SEMAPHORE = 0x1 + EFIVARFS_MAGIC = 0xde5e81e4 + EFS_SUPER_MAGIC = 0x414a53 ENCODING_DEFAULT = 0x0 ENCODING_FM_MARK = 0x3 ENCODING_FM_SPACE = 0x4 @@ -390,6 +415,8 @@ const ( ETH_P_DSA = 0x1b ETH_P_ECONET = 0x18 ETH_P_EDSA = 0xdada + ETH_P_ERSPAN = 0x88be + ETH_P_ERSPAN2 = 0x22eb ETH_P_FCOE = 0x8906 ETH_P_FIP = 0x8914 ETH_P_HDLC = 0x19 @@ -398,6 +425,7 @@ const ( ETH_P_IEEE802154 = 0xf6 ETH_P_IEEEPUP = 0xa00 ETH_P_IEEEPUPAT = 0xa01 + ETH_P_IFE = 0xed3e ETH_P_IP = 0x800 ETH_P_IPV6 = 0x86dd ETH_P_IPX = 0x8137 @@ -408,11 +436,13 @@ const ( ETH_P_LOOP = 0x60 ETH_P_LOOPBACK = 0x9000 ETH_P_MACSEC = 0x88e5 + ETH_P_MAP = 0xf9 ETH_P_MOBITEX = 0x15 ETH_P_MPLS_MC = 0x8848 ETH_P_MPLS_UC = 0x8847 ETH_P_MVRP = 0x88f5 ETH_P_NCSI = 0x88f8 + ETH_P_NSH = 0x894f ETH_P_PAE = 0x888e ETH_P_PAUSE = 0x8808 ETH_P_PHONET = 0xf5 @@ -420,6 +450,7 @@ const ( ETH_P_PPP_DISC = 0x8863 ETH_P_PPP_MP = 0x8 ETH_P_PPP_SES = 0x8864 + ETH_P_PREAUTH = 0x88c7 ETH_P_PRP = 0x88fb ETH_P_PUP = 0x200 ETH_P_PUPAT = 0x201 @@ -440,9 +471,14 @@ const ( ETH_P_WCCP = 0x883e ETH_P_X25 = 0x805 ETH_P_XDSA = 0xf8 + EXABYTE_ENABLE_NEST = 0xf0 + EXT2_SUPER_MAGIC = 0xef53 + EXT3_SUPER_MAGIC = 0xef53 + EXT4_SUPER_MAGIC = 0xef53 EXTA = 0xe EXTB = 0xf EXTPROC = 0x10000000 + F2FS_SUPER_MAGIC = 0xf2f52010 FALLOC_FL_COLLAPSE_RANGE = 0x8 FALLOC_FL_INSERT_RANGE = 0x20 FALLOC_FL_KEEP_SIZE = 0x1 @@ -463,6 +499,8 @@ const ( FS_ENCRYPTION_MODE_AES_256_GCM = 0x2 FS_ENCRYPTION_MODE_AES_256_XTS = 0x1 FS_ENCRYPTION_MODE_INVALID = 0x0 + FS_ENCRYPTION_MODE_SPECK128_256_CTS = 0x8 + FS_ENCRYPTION_MODE_SPECK128_256_XTS = 0x7 FS_IOC_GET_ENCRYPTION_POLICY = 0x800c6615 FS_IOC_GET_ENCRYPTION_PWSALT = 0x80106614 FS_IOC_SET_ENCRYPTION_POLICY = 0x400c6613 @@ -476,6 +514,8 @@ const ( FS_POLICY_FLAGS_PAD_8 = 0x1 FS_POLICY_FLAGS_PAD_MASK = 0x3 FS_POLICY_FLAGS_VALID = 0x3 + FUTEXFS_SUPER_MAGIC = 0xbad1dea + F_ADD_SEALS = 0x409 F_DUPFD = 0x0 F_DUPFD_CLOEXEC = 0x406 F_EXLCK = 0x4 @@ -488,6 +528,9 @@ const ( F_GETOWN_EX = 0x10 F_GETPIPE_SZ = 0x408 F_GETSIG = 0xb + F_GET_FILE_RW_HINT = 0x40d + F_GET_RW_HINT = 0x40b + F_GET_SEALS = 0x40a F_LOCK = 0x1 F_NOTIFY = 0x402 F_OFD_GETLK = 0x24 @@ -495,6 +538,10 @@ const ( F_OFD_SETLKW = 0x26 F_OK = 0x0 F_RDLCK = 0x0 + F_SEAL_GROW = 0x4 + F_SEAL_SEAL = 0x1 + F_SEAL_SHRINK = 0x2 + F_SEAL_WRITE = 0x8 F_SETFD = 0x2 F_SETFL = 0x4 F_SETLEASE = 0x400 @@ -506,6 +553,8 @@ const ( F_SETOWN_EX = 0xf F_SETPIPE_SZ = 0x407 F_SETSIG = 0xa + F_SET_FILE_RW_HINT = 0x40e + F_SET_RW_HINT = 0x40c F_SHLCK = 0x8 F_TEST = 0x3 F_TLOCK = 0x2 @@ -527,6 +576,49 @@ const ( GENL_UNS_ADMIN_PERM = 0x10 GRND_NONBLOCK = 0x1 GRND_RANDOM = 0x2 + HDIO_DRIVE_CMD = 0x31f + HDIO_DRIVE_CMD_AEB = 0x31e + HDIO_DRIVE_CMD_HDR_SIZE = 0x4 + HDIO_DRIVE_HOB_HDR_SIZE = 0x8 + HDIO_DRIVE_RESET = 0x31c + HDIO_DRIVE_TASK = 0x31e + HDIO_DRIVE_TASKFILE = 0x31d + HDIO_DRIVE_TASK_HDR_SIZE = 0x8 + HDIO_GETGEO = 0x301 + HDIO_GET_32BIT = 0x309 + HDIO_GET_ACOUSTIC = 0x30f + HDIO_GET_ADDRESS = 0x310 + HDIO_GET_BUSSTATE = 0x31a + HDIO_GET_DMA = 0x30b + HDIO_GET_IDENTITY = 0x30d + HDIO_GET_KEEPSETTINGS = 0x308 + HDIO_GET_MULTCOUNT = 0x304 + HDIO_GET_NICE = 0x30c + HDIO_GET_NOWERR = 0x30a + HDIO_GET_QDMA = 0x305 + HDIO_GET_UNMASKINTR = 0x302 + HDIO_GET_WCACHE = 0x30e + HDIO_OBSOLETE_IDENTITY = 0x307 + HDIO_SCAN_HWIF = 0x328 + HDIO_SET_32BIT = 0x324 + HDIO_SET_ACOUSTIC = 0x32c + HDIO_SET_ADDRESS = 0x32f + HDIO_SET_BUSSTATE = 0x32d + HDIO_SET_DMA = 0x326 + HDIO_SET_KEEPSETTINGS = 0x323 + HDIO_SET_MULTCOUNT = 0x321 + HDIO_SET_NICE = 0x329 + HDIO_SET_NOWERR = 0x325 + HDIO_SET_PIO_MODE = 0x327 + HDIO_SET_QDMA = 0x32e + HDIO_SET_UNMASKINTR = 0x322 + HDIO_SET_WCACHE = 0x32b + HDIO_SET_XFER = 0x306 + HDIO_TRISTATE_HWIF = 0x31b + HDIO_UNREGISTER_HWIF = 0x32a + HOSTFS_SUPER_MAGIC = 0xc0ffee + HPFS_SUPER_MAGIC = 0xf995e849 + HUGETLBFS_MAGIC = 0x958458f6 HUPCL = 0x4000 IBSHIFT = 0x10 ICANON = 0x100 @@ -546,7 +638,7 @@ const ( IFA_F_STABLE_PRIVACY = 0x800 IFA_F_TEMPORARY = 0x1 IFA_F_TENTATIVE = 0x40 - IFA_MAX = 0x8 + IFA_MAX = 0xa IFF_ALLMULTI = 0x200 IFF_ATTACH_QUEUE = 0x200 IFF_AUTOMEDIA = 0x4000 @@ -561,6 +653,8 @@ const ( IFF_MASTER = 0x400 IFF_MULTICAST = 0x1000 IFF_MULTI_QUEUE = 0x100 + IFF_NAPI = 0x10 + IFF_NAPI_FRAGS = 0x20 IFF_NOARP = 0x80 IFF_NOFILTER = 0x1000 IFF_NOTRAILERS = 0x20 @@ -612,6 +706,7 @@ const ( IN_ISDIR = 0x40000000 IN_LOOPBACKNET = 0x7f IN_MASK_ADD = 0x20000000 + IN_MASK_CREATE = 0x10000000 IN_MODIFY = 0x2 IN_MOVE = 0xc0 IN_MOVED_FROM = 0x40 @@ -671,6 +766,7 @@ const ( IPV6_DONTFRAG = 0x3e IPV6_DROP_MEMBERSHIP = 0x15 IPV6_DSTOPTS = 0x3b + IPV6_FREEBIND = 0x4e IPV6_HDRINCL = 0x24 IPV6_HOPLIMIT = 0x34 IPV6_HOPOPTS = 0x36 @@ -682,6 +778,7 @@ const ( IPV6_MINHOPCOUNT = 0x49 IPV6_MTU = 0x18 IPV6_MTU_DISCOVER = 0x17 + IPV6_MULTICAST_ALL = 0x1d IPV6_MULTICAST_HOPS = 0x12 IPV6_MULTICAST_IF = 0x11 IPV6_MULTICAST_LOOP = 0x13 @@ -775,12 +872,34 @@ const ( IP_UNICAST_IF = 0x32 IP_XFRM_POLICY = 0x11 ISIG = 0x80 + ISOFS_SUPER_MAGIC = 0x9660 ISTRIP = 0x20 IUCLC = 0x1000 IUTF8 = 0x4000 IXANY = 0x800 IXOFF = 0x400 IXON = 0x200 + JFFS2_SUPER_MAGIC = 0x72b6 + KEXEC_ARCH_386 = 0x30000 + KEXEC_ARCH_68K = 0x40000 + KEXEC_ARCH_AARCH64 = 0xb70000 + KEXEC_ARCH_ARM = 0x280000 + KEXEC_ARCH_DEFAULT = 0x0 + KEXEC_ARCH_IA_64 = 0x320000 + KEXEC_ARCH_MASK = 0xffff0000 + KEXEC_ARCH_MIPS = 0x80000 + KEXEC_ARCH_MIPS_LE = 0xa0000 + KEXEC_ARCH_PPC = 0x140000 + KEXEC_ARCH_PPC64 = 0x150000 + KEXEC_ARCH_S390 = 0x160000 + KEXEC_ARCH_SH = 0x2a0000 + KEXEC_ARCH_X86_64 = 0x3e0000 + KEXEC_FILE_NO_INITRAMFS = 0x4 + KEXEC_FILE_ON_CRASH = 0x2 + KEXEC_FILE_UNLOAD = 0x1 + KEXEC_ON_CRASH = 0x1 + KEXEC_PRESERVE_CONTEXT = 0x2 + KEXEC_SEGMENT_MAX = 0x10 KEYCTL_ASSUME_AUTHORITY = 0x10 KEYCTL_CHOWN = 0x4 KEYCTL_CLEAR = 0x7 @@ -795,6 +914,11 @@ const ( KEYCTL_JOIN_SESSION_KEYRING = 0x1 KEYCTL_LINK = 0x8 KEYCTL_NEGATE = 0xd + KEYCTL_PKEY_DECRYPT = 0x1a + KEYCTL_PKEY_ENCRYPT = 0x19 + KEYCTL_PKEY_QUERY = 0x18 + KEYCTL_PKEY_SIGN = 0x1b + KEYCTL_PKEY_VERIFY = 0x1c KEYCTL_READ = 0xb KEYCTL_REJECT = 0x13 KEYCTL_RESTRICT_KEYRING = 0x1d @@ -804,6 +928,10 @@ const ( KEYCTL_SETPERM = 0x5 KEYCTL_SET_REQKEY_KEYRING = 0xe KEYCTL_SET_TIMEOUT = 0xf + KEYCTL_SUPPORTS_DECRYPT = 0x2 + KEYCTL_SUPPORTS_ENCRYPT = 0x1 + KEYCTL_SUPPORTS_SIGN = 0x4 + KEYCTL_SUPPORTS_VERIFY = 0x8 KEYCTL_UNLINK = 0x9 KEYCTL_UPDATE = 0x2 KEY_REQKEY_DEFL_DEFAULT = 0x0 @@ -845,6 +973,7 @@ const ( MADV_FREE = 0x8 MADV_HUGEPAGE = 0xe MADV_HWPOISON = 0x64 + MADV_KEEPONFORK = 0x13 MADV_MERGEABLE = 0xc MADV_NOHUGEPAGE = 0xf MADV_NORMAL = 0x0 @@ -853,12 +982,14 @@ const ( MADV_SEQUENTIAL = 0x2 MADV_UNMERGEABLE = 0xd MADV_WILLNEED = 0x3 + MADV_WIPEONFORK = 0x12 MAP_ANON = 0x20 MAP_ANONYMOUS = 0x20 MAP_DENYWRITE = 0x800 MAP_EXECUTABLE = 0x1000 MAP_FILE = 0x0 MAP_FIXED = 0x10 + MAP_FIXED_NOREPLACE = 0x100000 MAP_GROWSDOWN = 0x100 MAP_HUGETLB = 0x40000 MAP_HUGE_MASK = 0x3f @@ -869,14 +1000,40 @@ const ( MAP_POPULATE = 0x8000 MAP_PRIVATE = 0x2 MAP_SHARED = 0x1 + MAP_SHARED_VALIDATE = 0x3 MAP_STACK = 0x20000 MAP_TYPE = 0xf MCL_CURRENT = 0x2000 MCL_FUTURE = 0x4000 MCL_ONFAULT = 0x8000 + MFD_ALLOW_SEALING = 0x2 + MFD_CLOEXEC = 0x1 + MFD_HUGETLB = 0x4 + MFD_HUGE_16GB = -0x78000000 + MFD_HUGE_16MB = 0x60000000 + MFD_HUGE_1GB = 0x78000000 + MFD_HUGE_1MB = 0x50000000 + MFD_HUGE_256MB = 0x70000000 + MFD_HUGE_2GB = 0x7c000000 + MFD_HUGE_2MB = 0x54000000 + MFD_HUGE_32MB = 0x64000000 + MFD_HUGE_512KB = 0x4c000000 + MFD_HUGE_512MB = 0x74000000 + MFD_HUGE_64KB = 0x40000000 + MFD_HUGE_8MB = 0x5c000000 + MFD_HUGE_MASK = 0x3f + MFD_HUGE_SHIFT = 0x1a + MINIX2_SUPER_MAGIC = 0x2468 + MINIX2_SUPER_MAGIC2 = 0x2478 + MINIX3_SUPER_MAGIC = 0x4d5a + MINIX_SUPER_MAGIC = 0x137f + MINIX_SUPER_MAGIC2 = 0x138f MNT_DETACH = 0x2 MNT_EXPIRE = 0x4 MNT_FORCE = 0x1 + MODULE_INIT_IGNORE_MODVERSIONS = 0x1 + MODULE_INIT_IGNORE_VERMAGIC = 0x2 + MSDOS_SUPER_MAGIC = 0x4d44 MSG_BATCH = 0x40000 MSG_CMSG_CLOEXEC = 0x40000000 MSG_CONFIRM = 0x800 @@ -898,6 +1055,7 @@ const ( MSG_TRYHARD = 0x4 MSG_WAITALL = 0x100 MSG_WAITFORONE = 0x10000 + MSG_ZEROCOPY = 0x4000000 MS_ACTIVE = 0x40000000 MS_ASYNC = 0x1 MS_BIND = 0x1000 @@ -935,7 +1093,9 @@ const ( MS_SYNCHRONOUS = 0x10 MS_UNBINDABLE = 0x20000 MS_VERBOSE = 0x8000 + MTD_INODE_FS_MAGIC = 0x11307854 NAME_MAX = 0xff + NCP_SUPER_MAGIC = 0x564c NETLINK_ADD_MEMBERSHIP = 0x1 NETLINK_AUDIT = 0x9 NETLINK_BROADCAST_ERROR = 0x4 @@ -949,6 +1109,7 @@ const ( NETLINK_FIB_LOOKUP = 0xa NETLINK_FIREWALL = 0x3 NETLINK_GENERIC = 0x10 + NETLINK_GET_STRICT_CHK = 0xc NETLINK_INET_DIAG = 0x4 NETLINK_IP6_FW = 0xd NETLINK_ISCSI = 0x8 @@ -970,6 +1131,39 @@ const ( NETLINK_UNUSED = 0x1 NETLINK_USERSOCK = 0x2 NETLINK_XFRM = 0x6 + NETNSA_MAX = 0x3 + NETNSA_NSID_NOT_ASSIGNED = -0x1 + NFNETLINK_V0 = 0x0 + NFNLGRP_ACCT_QUOTA = 0x8 + NFNLGRP_CONNTRACK_DESTROY = 0x3 + NFNLGRP_CONNTRACK_EXP_DESTROY = 0x6 + NFNLGRP_CONNTRACK_EXP_NEW = 0x4 + NFNLGRP_CONNTRACK_EXP_UPDATE = 0x5 + NFNLGRP_CONNTRACK_NEW = 0x1 + NFNLGRP_CONNTRACK_UPDATE = 0x2 + NFNLGRP_MAX = 0x9 + NFNLGRP_NFTABLES = 0x7 + NFNLGRP_NFTRACE = 0x9 + NFNLGRP_NONE = 0x0 + NFNL_BATCH_MAX = 0x1 + NFNL_MSG_BATCH_BEGIN = 0x10 + NFNL_MSG_BATCH_END = 0x11 + NFNL_NFA_NEST = 0x8000 + NFNL_SUBSYS_ACCT = 0x7 + NFNL_SUBSYS_COUNT = 0xc + NFNL_SUBSYS_CTHELPER = 0x9 + NFNL_SUBSYS_CTNETLINK = 0x1 + NFNL_SUBSYS_CTNETLINK_EXP = 0x2 + NFNL_SUBSYS_CTNETLINK_TIMEOUT = 0x8 + NFNL_SUBSYS_IPSET = 0x6 + NFNL_SUBSYS_NFTABLES = 0xa + NFNL_SUBSYS_NFT_COMPAT = 0xb + NFNL_SUBSYS_NONE = 0x0 + NFNL_SUBSYS_OSF = 0x5 + NFNL_SUBSYS_QUEUE = 0x3 + NFNL_SUBSYS_ULOG = 0x4 + NFS_SUPER_MAGIC = 0x6969 + NILFS_SUPER_MAGIC = 0x3434 NL0 = 0x0 NL1 = 0x100 NL2 = 0x200 @@ -999,10 +1193,13 @@ const ( NLM_F_EXCL = 0x200 NLM_F_MATCH = 0x200 NLM_F_MULTI = 0x2 + NLM_F_NONREC = 0x100 NLM_F_REPLACE = 0x100 NLM_F_REQUEST = 0x1 NLM_F_ROOT = 0x100 NOFLSH = 0x80000000 + NSFS_MAGIC = 0x6e736673 + OCFS2_SUPER_MAGIC = 0x7461636f OCRNL = 0x8 OFDEL = 0x80 OFILL = 0x40 @@ -1010,7 +1207,9 @@ const ( ONLCR = 0x2 ONLRET = 0x20 ONOCR = 0x10 + OPENPROM_SUPER_MAGIC = 0x9fa1 OPOST = 0x1 + OVERLAYFS_SUPER_MAGIC = 0x794c7630 O_ACCMODE = 0x3 O_APPEND = 0x400 O_ASYNC = 0x2000 @@ -1056,6 +1255,7 @@ const ( PACKET_FASTROUTE = 0x6 PACKET_HDRLEN = 0xb PACKET_HOST = 0x0 + PACKET_IGNORE_OUTGOING = 0x17 PACKET_KERNEL = 0x7 PACKET_LOOPBACK = 0x5 PACKET_LOSS = 0xe @@ -1095,16 +1295,50 @@ const ( PERF_EVENT_IOC_DISABLE = 0x20002401 PERF_EVENT_IOC_ENABLE = 0x20002400 PERF_EVENT_IOC_ID = 0x40082407 + PERF_EVENT_IOC_MODIFY_ATTRIBUTES = 0x8008240b PERF_EVENT_IOC_PAUSE_OUTPUT = 0x80042409 PERF_EVENT_IOC_PERIOD = 0x80082404 + PERF_EVENT_IOC_QUERY_BPF = 0xc008240a PERF_EVENT_IOC_REFRESH = 0x20002402 PERF_EVENT_IOC_RESET = 0x20002403 PERF_EVENT_IOC_SET_BPF = 0x80042408 PERF_EVENT_IOC_SET_FILTER = 0x80082406 PERF_EVENT_IOC_SET_OUTPUT = 0x20002405 + PIPEFS_MAGIC = 0x50495045 + PPPIOCATTACH = 0x8004743d + PPPIOCATTCHAN = 0x80047438 + PPPIOCCONNECT = 0x8004743a + PPPIOCDETACH = 0x8004743c + PPPIOCDISCONN = 0x20007439 + PPPIOCGASYNCMAP = 0x40047458 + PPPIOCGCHAN = 0x40047437 + PPPIOCGDEBUG = 0x40047441 + PPPIOCGFLAGS = 0x4004745a + PPPIOCGIDLE = 0x4010743f + PPPIOCGL2TPSTATS = 0x40487436 + PPPIOCGMRU = 0x40047453 + PPPIOCGNPMODE = 0xc008744c + PPPIOCGRASYNCMAP = 0x40047455 + PPPIOCGUNIT = 0x40047456 + PPPIOCGXASYNCMAP = 0x40207450 + PPPIOCNEWUNIT = 0xc004743e + PPPIOCSACTIVE = 0x80107446 + PPPIOCSASYNCMAP = 0x80047457 + PPPIOCSCOMPRESS = 0x8010744d + PPPIOCSDEBUG = 0x80047440 + PPPIOCSFLAGS = 0x80047459 + PPPIOCSMAXCID = 0x80047451 + PPPIOCSMRRU = 0x8004743b + PPPIOCSMRU = 0x80047452 + PPPIOCSNPMODE = 0x8008744b + PPPIOCSPASS = 0x80107447 + PPPIOCSRASYNCMAP = 0x80047454 + PPPIOCSXASYNCMAP = 0x8020744f + PPPIOCXFERUNIT = 0x2000744e PRIO_PGRP = 0x1 PRIO_PROCESS = 0x0 PRIO_USER = 0x2 + PROC_SUPER_MAGIC = 0x9fa0 PROT_EXEC = 0x4 PROT_GROWSDOWN = 0x1000000 PROT_GROWSUP = 0x2000000 @@ -1148,6 +1382,7 @@ const ( PR_GET_PDEATHSIG = 0x2 PR_GET_SECCOMP = 0x15 PR_GET_SECUREBITS = 0x1b + PR_GET_SPECULATION_CTRL = 0x34 PR_GET_THP_DISABLE = 0x2a PR_GET_TID_ADDRESS = 0x28 PR_GET_TIMERSLACK = 0x1e @@ -1193,11 +1428,24 @@ const ( PR_SET_PTRACER_ANY = 0xffffffffffffffff PR_SET_SECCOMP = 0x16 PR_SET_SECUREBITS = 0x1c + PR_SET_SPECULATION_CTRL = 0x35 PR_SET_THP_DISABLE = 0x29 PR_SET_TIMERSLACK = 0x1d PR_SET_TIMING = 0xe PR_SET_TSC = 0x1a PR_SET_UNALIGN = 0x6 + PR_SPEC_DISABLE = 0x4 + PR_SPEC_ENABLE = 0x2 + PR_SPEC_FORCE_DISABLE = 0x8 + PR_SPEC_INDIRECT_BRANCH = 0x1 + PR_SPEC_NOT_AFFECTED = 0x0 + PR_SPEC_PRCTL = 0x1 + PR_SPEC_STORE_BYPASS = 0x0 + PR_SVE_GET_VL = 0x33 + PR_SVE_SET_VL = 0x32 + PR_SVE_SET_VL_ONEXEC = 0x40000 + PR_SVE_VL_INHERIT = 0x20000 + PR_SVE_VL_LEN_MASK = 0xffff PR_TASK_PERF_EVENTS_DISABLE = 0x1f PR_TASK_PERF_EVENTS_ENABLE = 0x20 PR_TIMING_STATISTICAL = 0x0 @@ -1206,6 +1454,7 @@ const ( PR_TSC_SIGSEGV = 0x2 PR_UNALIGN_NOPRINT = 0x1 PR_UNALIGN_SIGBUS = 0x2 + PSTOREFS_MAGIC = 0x6165676c PTRACE_ATTACH = 0x10 PTRACE_CONT = 0x7 PTRACE_DETACH = 0x11 @@ -1251,6 +1500,7 @@ const ( PTRACE_POKETEXT = 0x4 PTRACE_POKEUSR = 0x6 PTRACE_SECCOMP_GET_FILTER = 0x420c + PTRACE_SECCOMP_GET_METADATA = 0x420d PTRACE_SEIZE = 0x4206 PTRACE_SETEVRREGS = 0x15 PTRACE_SETFPREGS = 0xf @@ -1266,6 +1516,8 @@ const ( PTRACE_SINGLEBLOCK = 0x100 PTRACE_SINGLESTEP = 0x9 PTRACE_SYSCALL = 0x18 + PTRACE_SYSEMU = 0x1d + PTRACE_SYSEMU_SINGLESTEP = 0x1e PTRACE_TRACEME = 0x0 PT_CCR = 0x26 PT_CTR = 0x23 @@ -1320,6 +1572,14 @@ const ( PT_VSR0 = 0x96 PT_VSR31 = 0xd4 PT_XER = 0x25 + QNX4_SUPER_MAGIC = 0x2f + QNX6_SUPER_MAGIC = 0x68191122 + RAMFS_MAGIC = 0x858458f6 + RDTGROUP_SUPER_MAGIC = 0x7655821 + REISERFS_SUPER_MAGIC = 0x52654973 + RENAME_EXCHANGE = 0x2 + RENAME_NOREPLACE = 0x1 + RENAME_WHITEOUT = 0x4 RLIMIT_AS = 0x9 RLIMIT_CORE = 0x4 RLIMIT_CPU = 0x0 @@ -1337,9 +1597,17 @@ const ( RLIMIT_SIGPENDING = 0xb RLIMIT_STACK = 0x3 RLIM_INFINITY = 0xffffffffffffffff + RNDADDENTROPY = 0x80085203 + RNDADDTOENTCNT = 0x80045201 + RNDCLEARPOOL = 0x20005206 + RNDGETENTCNT = 0x40045200 + RNDGETPOOL = 0x40085202 + RNDRESEEDCRNG = 0x20005207 + RNDZAPENTCNT = 0x20005204 RTAX_ADVMSS = 0x8 RTAX_CC_ALGO = 0x10 RTAX_CWND = 0x7 + RTAX_FASTOPEN_NO_COOKIE = 0x11 RTAX_FEATURES = 0xc RTAX_FEATURE_ALLFRAG = 0x8 RTAX_FEATURE_ECN = 0x1 @@ -1350,7 +1618,7 @@ const ( RTAX_INITCWND = 0xb RTAX_INITRWND = 0xe RTAX_LOCK = 0x1 - RTAX_MAX = 0x10 + RTAX_MAX = 0x11 RTAX_MTU = 0x2 RTAX_QUICKACK = 0xf RTAX_REORDERING = 0x9 @@ -1361,13 +1629,40 @@ const ( RTAX_UNSPEC = 0x0 RTAX_WINDOW = 0x3 RTA_ALIGNTO = 0x4 - RTA_MAX = 0x1a + RTA_MAX = 0x1d RTCF_DIRECTSRC = 0x4000000 RTCF_DOREDIRECT = 0x1000000 RTCF_LOG = 0x2000000 RTCF_MASQ = 0x400000 RTCF_NAT = 0x800000 RTCF_VALVE = 0x200000 + RTC_AF = 0x20 + RTC_AIE_OFF = 0x20007002 + RTC_AIE_ON = 0x20007001 + RTC_ALM_READ = 0x40247008 + RTC_ALM_SET = 0x80247007 + RTC_EPOCH_READ = 0x4008700d + RTC_EPOCH_SET = 0x8008700e + RTC_IRQF = 0x80 + RTC_IRQP_READ = 0x4008700b + RTC_IRQP_SET = 0x8008700c + RTC_MAX_FREQ = 0x2000 + RTC_PF = 0x40 + RTC_PIE_OFF = 0x20007006 + RTC_PIE_ON = 0x20007005 + RTC_PLL_GET = 0x40207011 + RTC_PLL_SET = 0x80207012 + RTC_RD_TIME = 0x40247009 + RTC_SET_TIME = 0x8024700a + RTC_UF = 0x10 + RTC_UIE_OFF = 0x20007004 + RTC_UIE_ON = 0x20007003 + RTC_VL_CLR = 0x20007014 + RTC_VL_READ = 0x40047013 + RTC_WIE_OFF = 0x20007010 + RTC_WIE_ON = 0x2000700f + RTC_WKALM_RD = 0x40287010 + RTC_WKALM_SET = 0x8028700f RTF_ADDRCLASSMASK = 0xf8000000 RTF_ADDRCONF = 0x40000 RTF_ALLONLINK = 0x20000 @@ -1402,6 +1697,7 @@ const ( RTM_DELACTION = 0x31 RTM_DELADDR = 0x15 RTM_DELADDRLABEL = 0x49 + RTM_DELCHAIN = 0x65 RTM_DELLINK = 0x11 RTM_DELMDB = 0x55 RTM_DELNEIGH = 0x1d @@ -1422,6 +1718,7 @@ const ( RTM_GETADDR = 0x16 RTM_GETADDRLABEL = 0x4a RTM_GETANYCAST = 0x3e + RTM_GETCHAIN = 0x66 RTM_GETDCB = 0x4e RTM_GETLINK = 0x12 RTM_GETMDB = 0x56 @@ -1436,11 +1733,12 @@ const ( RTM_GETSTATS = 0x5e RTM_GETTCLASS = 0x2a RTM_GETTFILTER = 0x2e - RTM_MAX = 0x63 + RTM_MAX = 0x67 RTM_NEWACTION = 0x30 RTM_NEWADDR = 0x14 RTM_NEWADDRLABEL = 0x48 RTM_NEWCACHEREPORT = 0x60 + RTM_NEWCHAIN = 0x64 RTM_NEWLINK = 0x10 RTM_NEWMDB = 0x54 RTM_NEWNDUSEROPT = 0x44 @@ -1455,8 +1753,8 @@ const ( RTM_NEWSTATS = 0x5c RTM_NEWTCLASS = 0x28 RTM_NEWTFILTER = 0x2c - RTM_NR_FAMILIES = 0x15 - RTM_NR_MSGTYPES = 0x54 + RTM_NR_FAMILIES = 0x16 + RTM_NR_MSGTYPES = 0x58 RTM_SETDCB = 0x4f RTM_SETLINK = 0x13 RTM_SETNEIGHTBL = 0x43 @@ -1470,17 +1768,22 @@ const ( RTNH_F_UNRESOLVED = 0x20 RTN_MAX = 0xb RTPROT_BABEL = 0x2a + RTPROT_BGP = 0xba RTPROT_BIRD = 0xc RTPROT_BOOT = 0x3 RTPROT_DHCP = 0x10 RTPROT_DNROUTED = 0xd + RTPROT_EIGRP = 0xc0 RTPROT_GATED = 0x8 + RTPROT_ISIS = 0xbb RTPROT_KERNEL = 0x2 RTPROT_MROUTED = 0x11 RTPROT_MRT = 0xa RTPROT_NTK = 0xf + RTPROT_OSPF = 0xbc RTPROT_RA = 0x9 RTPROT_REDIRECT = 0x1 + RTPROT_RIP = 0xbd RTPROT_STATIC = 0x4 RTPROT_UNSPEC = 0x0 RTPROT_XORP = 0xe @@ -1500,10 +1803,16 @@ const ( SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SC_LOG_FLUSH = 0x100000 SECCOMP_MODE_DISABLED = 0x0 SECCOMP_MODE_FILTER = 0x2 SECCOMP_MODE_STRICT = 0x1 + SECURITYFS_MAGIC = 0x73636673 + SELINUX_MAGIC = 0xf97cff8c + SFD_CLOEXEC = 0x80000 + SFD_NONBLOCK = 0x800 SHUT_RD = 0x0 SHUT_RDWR = 0x2 SHUT_WR = 0x1 @@ -1554,6 +1863,9 @@ const ( SIOCGMIIPHY = 0x8947 SIOCGMIIREG = 0x8948 SIOCGPGRP = 0x8904 + SIOCGPPPCSTATS = 0x89f2 + SIOCGPPPSTATS = 0x89f0 + SIOCGPPPVER = 0x89f1 SIOCGRARP = 0x8961 SIOCGSKNS = 0x894c SIOCGSTAMP = 0x8906 @@ -1588,6 +1900,23 @@ const ( SIOCSPGRP = 0x8902 SIOCSRARP = 0x8962 SIOCWANDEV = 0x894a + SMACK_MAGIC = 0x43415d53 + SMART_AUTOSAVE = 0xd2 + SMART_AUTO_OFFLINE = 0xdb + SMART_DISABLE = 0xd9 + SMART_ENABLE = 0xd8 + SMART_HCYL_PASS = 0xc2 + SMART_IMMEDIATE_OFFLINE = 0xd4 + SMART_LCYL_PASS = 0x4f + SMART_READ_LOG_SECTOR = 0xd5 + SMART_READ_THRESHOLDS = 0xd1 + SMART_READ_VALUES = 0xd0 + SMART_SAVE = 0xd3 + SMART_STATUS = 0xda + SMART_WRITE_LOG_SECTOR = 0xd6 + SMART_WRITE_THRESHOLDS = 0xd7 + SMB_SUPER_MAGIC = 0x517b + SOCKFS_MAGIC = 0x534f434b SOCK_CLOEXEC = 0x80000 SOCK_DCCP = 0x6 SOCK_DGRAM = 0x2 @@ -1624,7 +1953,9 @@ const ( SOL_SOCKET = 0x1 SOL_TCP = 0x6 SOL_TIPC = 0x10f + SOL_TLS = 0x11a SOL_X25 = 0x106 + SOL_XDP = 0x11b SOMAXCONN = 0x80 SO_ACCEPTCONN = 0x1e SO_ATTACH_BPF = 0x32 @@ -1643,6 +1974,17 @@ const ( SO_DETACH_FILTER = 0x1b SO_DOMAIN = 0x27 SO_DONTROUTE = 0x5 + SO_EE_CODE_TXTIME_INVALID_PARAM = 0x1 + SO_EE_CODE_TXTIME_MISSED = 0x2 + SO_EE_CODE_ZEROCOPY_COPIED = 0x1 + SO_EE_ORIGIN_ICMP = 0x2 + SO_EE_ORIGIN_ICMP6 = 0x3 + SO_EE_ORIGIN_LOCAL = 0x1 + SO_EE_ORIGIN_NONE = 0x0 + SO_EE_ORIGIN_TIMESTAMPING = 0x4 + SO_EE_ORIGIN_TXSTATUS = 0x4 + SO_EE_ORIGIN_TXTIME = 0x6 + SO_EE_ORIGIN_ZEROCOPY = 0x5 SO_ERROR = 0x4 SO_GET_FILTER = 0x1a SO_INCOMING_CPU = 0x31 @@ -1683,6 +2025,7 @@ const ( SO_TIMESTAMP = 0x1d SO_TIMESTAMPING = 0x25 SO_TIMESTAMPNS = 0x23 + SO_TXTIME = 0x3d SO_TYPE = 0x3 SO_VM_SOCKETS_BUFFER_MAX_SIZE = 0x2 SO_VM_SOCKETS_BUFFER_MIN_SIZE = 0x1 @@ -1692,10 +2035,38 @@ const ( SO_VM_SOCKETS_PEER_HOST_VM_ID = 0x3 SO_VM_SOCKETS_TRUSTED = 0x5 SO_WIFI_STATUS = 0x29 + SO_ZEROCOPY = 0x3c SPLICE_F_GIFT = 0x8 SPLICE_F_MORE = 0x4 SPLICE_F_MOVE = 0x1 SPLICE_F_NONBLOCK = 0x2 + SQUASHFS_MAGIC = 0x73717368 + STACK_END_MAGIC = 0x57ac6e9d + STATX_ALL = 0xfff + STATX_ATIME = 0x20 + STATX_ATTR_APPEND = 0x20 + STATX_ATTR_AUTOMOUNT = 0x1000 + STATX_ATTR_COMPRESSED = 0x4 + STATX_ATTR_ENCRYPTED = 0x800 + STATX_ATTR_IMMUTABLE = 0x10 + STATX_ATTR_NODUMP = 0x40 + STATX_BASIC_STATS = 0x7ff + STATX_BLOCKS = 0x400 + STATX_BTIME = 0x800 + STATX_CTIME = 0x80 + STATX_GID = 0x10 + STATX_INO = 0x100 + STATX_MODE = 0x2 + STATX_MTIME = 0x40 + STATX_NLINK = 0x4 + STATX_SIZE = 0x200 + STATX_TYPE = 0x1 + STATX_UID = 0x8 + STATX__RESERVED = 0x80000000 + SYNC_FILE_RANGE_WAIT_AFTER = 0x4 + SYNC_FILE_RANGE_WAIT_BEFORE = 0x1 + SYNC_FILE_RANGE_WRITE = 0x2 + SYSFS_MAGIC = 0x62656572 S_BLKSIZE = 0x200 S_IEXEC = 0x40 S_IFBLK = 0x6000 @@ -1733,7 +2104,7 @@ const ( TASKSTATS_GENL_NAME = "TASKSTATS" TASKSTATS_GENL_VERSION = 0x1 TASKSTATS_TYPE_MAX = 0x6 - TASKSTATS_VERSION = 0x8 + TASKSTATS_VERSION = 0x9 TCFLSH = 0x2000741f TCGETA = 0x40147417 TCGETS = 0x402c7413 @@ -1745,6 +2116,7 @@ const ( TCOOFF = 0x0 TCOON = 0x1 TCP_CC_INFO = 0x1a + TCP_CM_INQ = 0x24 TCP_CONGESTION = 0xd TCP_COOKIE_IN_ALWAYS = 0x1 TCP_COOKIE_MAX = 0x10 @@ -1756,7 +2128,10 @@ const ( TCP_DEFER_ACCEPT = 0x9 TCP_FASTOPEN = 0x17 TCP_FASTOPEN_CONNECT = 0x1e + TCP_FASTOPEN_KEY = 0x21 + TCP_FASTOPEN_NO_COOKIE = 0x22 TCP_INFO = 0xb + TCP_INQ = 0x24 TCP_KEEPCNT = 0x6 TCP_KEEPIDLE = 0x4 TCP_KEEPINTVL = 0x5 @@ -1765,6 +2140,8 @@ const ( TCP_MAXWIN = 0xffff TCP_MAX_WINSHIFT = 0xe TCP_MD5SIG = 0xe + TCP_MD5SIG_EXT = 0x20 + TCP_MD5SIG_FLAG_PREFIX = 0x1 TCP_MD5SIG_MAXKEYLEN = 0x50 TCP_MSS = 0x200 TCP_MSS_DEFAULT = 0x218 @@ -1774,6 +2151,9 @@ const ( TCP_QUEUE_SEQ = 0x15 TCP_QUICKACK = 0xc TCP_REPAIR = 0x13 + TCP_REPAIR_OFF = 0x0 + TCP_REPAIR_OFF_NO_WP = -0x1 + TCP_REPAIR_ON = 0x1 TCP_REPAIR_OPTIONS = 0x16 TCP_REPAIR_QUEUE = 0x14 TCP_REPAIR_WINDOW = 0x1d @@ -1785,8 +2165,10 @@ const ( TCP_THIN_DUPACK = 0x11 TCP_THIN_LINEAR_TIMEOUTS = 0x10 TCP_TIMESTAMP = 0x18 + TCP_ULP = 0x1f TCP_USER_TIMEOUT = 0x12 TCP_WINDOW_CLAMP = 0xa + TCP_ZEROCOPY_RECEIVE = 0x23 TCSAFLUSH = 0x2 TCSBRK = 0x2000741d TCSBRKP = 0x5425 @@ -1797,6 +2179,7 @@ const ( TCSETSF = 0x802c7416 TCSETSW = 0x802c7415 TCXONC = 0x2000741e + TIMER_ABSTIME = 0x1 TIOCCBRK = 0x5428 TIOCCONS = 0x541d TIOCEXCL = 0x540c @@ -1806,6 +2189,7 @@ const ( TIOCGETP = 0x40067408 TIOCGEXCL = 0x40045440 TIOCGICOUNT = 0x545d + TIOCGISO7816 = 0x40285442 TIOCGLCKTRMIOS = 0x5456 TIOCGLTC = 0x40067474 TIOCGPGRP = 0x40047477 @@ -1866,6 +2250,7 @@ const ( TIOCSETN = 0x8006740a TIOCSETP = 0x80067409 TIOCSIG = 0x80045436 + TIOCSISO7816 = 0xc0285443 TIOCSLCKTRMIOS = 0x5457 TIOCSLTC = 0x80067475 TIOCSPGRP = 0x80047476 @@ -1878,7 +2263,27 @@ const ( TIOCSTOP = 0x2000746f TIOCSWINSZ = 0x80087467 TIOCVHANGUP = 0x5437 + TMPFS_MAGIC = 0x1021994 TOSTOP = 0x400000 + TPACKET_ALIGNMENT = 0x10 + TPACKET_HDRLEN = 0x34 + TP_STATUS_AVAILABLE = 0x0 + TP_STATUS_BLK_TMO = 0x20 + TP_STATUS_COPY = 0x2 + TP_STATUS_CSUMNOTREADY = 0x8 + TP_STATUS_CSUM_VALID = 0x80 + TP_STATUS_KERNEL = 0x0 + TP_STATUS_LOSING = 0x4 + TP_STATUS_SENDING = 0x2 + TP_STATUS_SEND_REQUEST = 0x1 + TP_STATUS_TS_RAW_HARDWARE = -0x80000000 + TP_STATUS_TS_SOFTWARE = 0x20000000 + TP_STATUS_TS_SYS_HARDWARE = 0x40000000 + TP_STATUS_USER = 0x1 + TP_STATUS_VLAN_TPID_VALID = 0x40 + TP_STATUS_VLAN_VALID = 0x10 + TP_STATUS_WRONG_FORMAT = 0x4 + TRACEFS_MAGIC = 0x74726163 TS_COMM_LEN = 0x20 TUNATTACHFILTER = 0x801054d5 TUNDETACHFILTER = 0x801054d6 @@ -1890,6 +2295,7 @@ const ( TUNGETVNETHDRSZ = 0x400454d7 TUNGETVNETLE = 0x400454dd TUNSETDEBUG = 0x800454c9 + TUNSETFILTEREBPF = 0x400454e1 TUNSETGROUP = 0x800454ce TUNSETIFF = 0x800454ca TUNSETIFINDEX = 0x800454da @@ -1900,13 +2306,32 @@ const ( TUNSETPERSIST = 0x800454cb TUNSETQUEUE = 0x800454d9 TUNSETSNDBUF = 0x800454d4 + TUNSETSTEERINGEBPF = 0x400454e0 TUNSETTXFILTER = 0x800454d1 TUNSETVNETBE = 0x800454de TUNSETVNETHDRSZ = 0x800454d8 TUNSETVNETLE = 0x800454dc + UBI_IOCATT = 0x80186f40 + UBI_IOCDET = 0x80046f41 + UBI_IOCEBCH = 0x80044f02 + UBI_IOCEBER = 0x80044f01 + UBI_IOCEBISMAP = 0x40044f05 + UBI_IOCEBMAP = 0x80084f03 + UBI_IOCEBUNMAP = 0x80044f04 + UBI_IOCMKVOL = 0x80986f00 + UBI_IOCRMVOL = 0x80046f01 + UBI_IOCRNVOL = 0x91106f03 + UBI_IOCRSVOL = 0x800c6f02 + UBI_IOCSETVOLPROP = 0x80104f06 + UBI_IOCVOLCRBLK = 0x80804f07 + UBI_IOCVOLRMBLK = 0x20004f08 + UBI_IOCVOLUP = 0x80084f00 + UDF_SUPER_MAGIC = 0x15013346 UMOUNT_NOFOLLOW = 0x8 + USBDEVICE_SUPER_MAGIC = 0x9fa2 UTIME_NOW = 0x3fffffff UTIME_OMIT = 0x3ffffffe + V9FS_MAGIC = 0x1021997 VDISCARD = 0x10 VEOF = 0x4 VEOL = 0x6 @@ -1948,6 +2373,86 @@ const ( WDIOC_SETPRETIMEOUT = 0xc0045708 WDIOC_SETTIMEOUT = 0xc0045706 WEXITED = 0x4 + WIN_ACKMEDIACHANGE = 0xdb + WIN_CHECKPOWERMODE1 = 0xe5 + WIN_CHECKPOWERMODE2 = 0x98 + WIN_DEVICE_RESET = 0x8 + WIN_DIAGNOSE = 0x90 + WIN_DOORLOCK = 0xde + WIN_DOORUNLOCK = 0xdf + WIN_DOWNLOAD_MICROCODE = 0x92 + WIN_FLUSH_CACHE = 0xe7 + WIN_FLUSH_CACHE_EXT = 0xea + WIN_FORMAT = 0x50 + WIN_GETMEDIASTATUS = 0xda + WIN_IDENTIFY = 0xec + WIN_IDENTIFY_DMA = 0xee + WIN_IDLEIMMEDIATE = 0xe1 + WIN_INIT = 0x60 + WIN_MEDIAEJECT = 0xed + WIN_MULTREAD = 0xc4 + WIN_MULTREAD_EXT = 0x29 + WIN_MULTWRITE = 0xc5 + WIN_MULTWRITE_EXT = 0x39 + WIN_NOP = 0x0 + WIN_PACKETCMD = 0xa0 + WIN_PIDENTIFY = 0xa1 + WIN_POSTBOOT = 0xdc + WIN_PREBOOT = 0xdd + WIN_QUEUED_SERVICE = 0xa2 + WIN_READ = 0x20 + WIN_READDMA = 0xc8 + WIN_READDMA_EXT = 0x25 + WIN_READDMA_ONCE = 0xc9 + WIN_READDMA_QUEUED = 0xc7 + WIN_READDMA_QUEUED_EXT = 0x26 + WIN_READ_BUFFER = 0xe4 + WIN_READ_EXT = 0x24 + WIN_READ_LONG = 0x22 + WIN_READ_LONG_ONCE = 0x23 + WIN_READ_NATIVE_MAX = 0xf8 + WIN_READ_NATIVE_MAX_EXT = 0x27 + WIN_READ_ONCE = 0x21 + WIN_RECAL = 0x10 + WIN_RESTORE = 0x10 + WIN_SECURITY_DISABLE = 0xf6 + WIN_SECURITY_ERASE_PREPARE = 0xf3 + WIN_SECURITY_ERASE_UNIT = 0xf4 + WIN_SECURITY_FREEZE_LOCK = 0xf5 + WIN_SECURITY_SET_PASS = 0xf1 + WIN_SECURITY_UNLOCK = 0xf2 + WIN_SEEK = 0x70 + WIN_SETFEATURES = 0xef + WIN_SETIDLE1 = 0xe3 + WIN_SETIDLE2 = 0x97 + WIN_SETMULT = 0xc6 + WIN_SET_MAX = 0xf9 + WIN_SET_MAX_EXT = 0x37 + WIN_SLEEPNOW1 = 0xe6 + WIN_SLEEPNOW2 = 0x99 + WIN_SMART = 0xb0 + WIN_SPECIFY = 0x91 + WIN_SRST = 0x8 + WIN_STANDBY = 0xe2 + WIN_STANDBY2 = 0x96 + WIN_STANDBYNOW1 = 0xe0 + WIN_STANDBYNOW2 = 0x94 + WIN_VERIFY = 0x40 + WIN_VERIFY_EXT = 0x42 + WIN_VERIFY_ONCE = 0x41 + WIN_WRITE = 0x30 + WIN_WRITEDMA = 0xca + WIN_WRITEDMA_EXT = 0x35 + WIN_WRITEDMA_ONCE = 0xcb + WIN_WRITEDMA_QUEUED = 0xcc + WIN_WRITEDMA_QUEUED_EXT = 0x36 + WIN_WRITE_BUFFER = 0xe8 + WIN_WRITE_EXT = 0x34 + WIN_WRITE_LONG = 0x32 + WIN_WRITE_LONG_ONCE = 0x33 + WIN_WRITE_ONCE = 0x31 + WIN_WRITE_SAME = 0xe9 + WIN_WRITE_VERIFY = 0x3c WNOHANG = 0x1 WNOTHREAD = 0x20000000 WNOWAIT = 0x1000000 @@ -1957,7 +2462,30 @@ const ( XATTR_CREATE = 0x1 XATTR_REPLACE = 0x2 XCASE = 0x4000 + XDP_COPY = 0x2 + XDP_FLAGS_DRV_MODE = 0x4 + XDP_FLAGS_HW_MODE = 0x8 + XDP_FLAGS_MASK = 0xf + XDP_FLAGS_MODES = 0xe + XDP_FLAGS_SKB_MODE = 0x2 + XDP_FLAGS_UPDATE_IF_NOEXIST = 0x1 + XDP_MMAP_OFFSETS = 0x1 + XDP_PGOFF_RX_RING = 0x0 + XDP_PGOFF_TX_RING = 0x80000000 + XDP_RX_RING = 0x2 + XDP_SHARED_UMEM = 0x1 + XDP_STATISTICS = 0x7 + XDP_TX_RING = 0x3 + XDP_UMEM_COMPLETION_RING = 0x6 + XDP_UMEM_FILL_RING = 0x5 + XDP_UMEM_PGOFF_COMPLETION_RING = 0x180000000 + XDP_UMEM_PGOFF_FILL_RING = 0x100000000 + XDP_UMEM_REG = 0x4 + XDP_ZEROCOPY = 0x4 + XENFS_SUPER_MAGIC = 0xabba1974 + XFS_SUPER_MAGIC = 0x58465342 XTABS = 0xc00 + ZSMALLOC_MAGIC = 0x58295829 ) // Errors @@ -2137,172 +2665,180 @@ const ( ) // Error table -var errors = [...]string{ - 1: "operation not permitted", - 2: "no such file or directory", - 3: "no such process", - 4: "interrupted system call", - 5: "input/output error", - 6: "no such device or address", - 7: "argument list too long", - 8: "exec format error", - 9: "bad file descriptor", - 10: "no child processes", - 11: "resource temporarily unavailable", - 12: "cannot allocate memory", - 13: "permission denied", - 14: "bad address", - 15: "block device required", - 16: "device or resource busy", - 17: "file exists", - 18: "invalid cross-device link", - 19: "no such device", - 20: "not a directory", - 21: "is a directory", - 22: "invalid argument", - 23: "too many open files in system", - 24: "too many open files", - 25: "inappropriate ioctl for device", - 26: "text file busy", - 27: "file too large", - 28: "no space left on device", - 29: "illegal seek", - 30: "read-only file system", - 31: "too many links", - 32: "broken pipe", - 33: "numerical argument out of domain", - 34: "numerical result out of range", - 35: "resource deadlock avoided", - 36: "file name too long", - 37: "no locks available", - 38: "function not implemented", - 39: "directory not empty", - 40: "too many levels of symbolic links", - 42: "no message of desired type", - 43: "identifier removed", - 44: "channel number out of range", - 45: "level 2 not synchronized", - 46: "level 3 halted", - 47: "level 3 reset", - 48: "link number out of range", - 49: "protocol driver not attached", - 50: "no CSI structure available", - 51: "level 2 halted", - 52: "invalid exchange", - 53: "invalid request descriptor", - 54: "exchange full", - 55: "no anode", - 56: "invalid request code", - 57: "invalid slot", - 58: "file locking deadlock error", - 59: "bad font file format", - 60: "device not a stream", - 61: "no data available", - 62: "timer expired", - 63: "out of streams resources", - 64: "machine is not on the network", - 65: "package not installed", - 66: "object is remote", - 67: "link has been severed", - 68: "advertise error", - 69: "srmount error", - 70: "communication error on send", - 71: "protocol error", - 72: "multihop attempted", - 73: "RFS specific error", - 74: "bad message", - 75: "value too large for defined data type", - 76: "name not unique on network", - 77: "file descriptor in bad state", - 78: "remote address changed", - 79: "can not access a needed shared library", - 80: "accessing a corrupted shared library", - 81: ".lib section in a.out corrupted", - 82: "attempting to link in too many shared libraries", - 83: "cannot exec a shared library directly", - 84: "invalid or incomplete multibyte or wide character", - 85: "interrupted system call should be restarted", - 86: "streams pipe error", - 87: "too many users", - 88: "socket operation on non-socket", - 89: "destination address required", - 90: "message too long", - 91: "protocol wrong type for socket", - 92: "protocol not available", - 93: "protocol not supported", - 94: "socket type not supported", - 95: "operation not supported", - 96: "protocol family not supported", - 97: "address family not supported by protocol", - 98: "address already in use", - 99: "cannot assign requested address", - 100: "network is down", - 101: "network is unreachable", - 102: "network dropped connection on reset", - 103: "software caused connection abort", - 104: "connection reset by peer", - 105: "no buffer space available", - 106: "transport endpoint is already connected", - 107: "transport endpoint is not connected", - 108: "cannot send after transport endpoint shutdown", - 109: "too many references: cannot splice", - 110: "connection timed out", - 111: "connection refused", - 112: "host is down", - 113: "no route to host", - 114: "operation already in progress", - 115: "operation now in progress", - 116: "stale file handle", - 117: "structure needs cleaning", - 118: "not a XENIX named type file", - 119: "no XENIX semaphores available", - 120: "is a named type file", - 121: "remote I/O error", - 122: "disk quota exceeded", - 123: "no medium found", - 124: "wrong medium type", - 125: "operation canceled", - 126: "required key not available", - 127: "key has expired", - 128: "key has been revoked", - 129: "key was rejected by service", - 130: "owner died", - 131: "state not recoverable", - 132: "operation not possible due to RF-kill", - 133: "memory page has hardware error", +var errorList = [...]struct { + num syscall.Errno + name string + desc string +}{ + {1, "EPERM", "operation not permitted"}, + {2, "ENOENT", "no such file or directory"}, + {3, "ESRCH", "no such process"}, + {4, "EINTR", "interrupted system call"}, + {5, "EIO", "input/output error"}, + {6, "ENXIO", "no such device or address"}, + {7, "E2BIG", "argument list too long"}, + {8, "ENOEXEC", "exec format error"}, + {9, "EBADF", "bad file descriptor"}, + {10, "ECHILD", "no child processes"}, + {11, "EAGAIN", "resource temporarily unavailable"}, + {12, "ENOMEM", "cannot allocate memory"}, + {13, "EACCES", "permission denied"}, + {14, "EFAULT", "bad address"}, + {15, "ENOTBLK", "block device required"}, + {16, "EBUSY", "device or resource busy"}, + {17, "EEXIST", "file exists"}, + {18, "EXDEV", "invalid cross-device link"}, + {19, "ENODEV", "no such device"}, + {20, "ENOTDIR", "not a directory"}, + {21, "EISDIR", "is a directory"}, + {22, "EINVAL", "invalid argument"}, + {23, "ENFILE", "too many open files in system"}, + {24, "EMFILE", "too many open files"}, + {25, "ENOTTY", "inappropriate ioctl for device"}, + {26, "ETXTBSY", "text file busy"}, + {27, "EFBIG", "file too large"}, + {28, "ENOSPC", "no space left on device"}, + {29, "ESPIPE", "illegal seek"}, + {30, "EROFS", "read-only file system"}, + {31, "EMLINK", "too many links"}, + {32, "EPIPE", "broken pipe"}, + {33, "EDOM", "numerical argument out of domain"}, + {34, "ERANGE", "numerical result out of range"}, + {35, "EDEADLK", "resource deadlock avoided"}, + {36, "ENAMETOOLONG", "file name too long"}, + {37, "ENOLCK", "no locks available"}, + {38, "ENOSYS", "function not implemented"}, + {39, "ENOTEMPTY", "directory not empty"}, + {40, "ELOOP", "too many levels of symbolic links"}, + {42, "ENOMSG", "no message of desired type"}, + {43, "EIDRM", "identifier removed"}, + {44, "ECHRNG", "channel number out of range"}, + {45, "EL2NSYNC", "level 2 not synchronized"}, + {46, "EL3HLT", "level 3 halted"}, + {47, "EL3RST", "level 3 reset"}, + {48, "ELNRNG", "link number out of range"}, + {49, "EUNATCH", "protocol driver not attached"}, + {50, "ENOCSI", "no CSI structure available"}, + {51, "EL2HLT", "level 2 halted"}, + {52, "EBADE", "invalid exchange"}, + {53, "EBADR", "invalid request descriptor"}, + {54, "EXFULL", "exchange full"}, + {55, "ENOANO", "no anode"}, + {56, "EBADRQC", "invalid request code"}, + {57, "EBADSLT", "invalid slot"}, + {58, "EDEADLOCK", "file locking deadlock error"}, + {59, "EBFONT", "bad font file format"}, + {60, "ENOSTR", "device not a stream"}, + {61, "ENODATA", "no data available"}, + {62, "ETIME", "timer expired"}, + {63, "ENOSR", "out of streams resources"}, + {64, "ENONET", "machine is not on the network"}, + {65, "ENOPKG", "package not installed"}, + {66, "EREMOTE", "object is remote"}, + {67, "ENOLINK", "link has been severed"}, + {68, "EADV", "advertise error"}, + {69, "ESRMNT", "srmount error"}, + {70, "ECOMM", "communication error on send"}, + {71, "EPROTO", "protocol error"}, + {72, "EMULTIHOP", "multihop attempted"}, + {73, "EDOTDOT", "RFS specific error"}, + {74, "EBADMSG", "bad message"}, + {75, "EOVERFLOW", "value too large for defined data type"}, + {76, "ENOTUNIQ", "name not unique on network"}, + {77, "EBADFD", "file descriptor in bad state"}, + {78, "EREMCHG", "remote address changed"}, + {79, "ELIBACC", "can not access a needed shared library"}, + {80, "ELIBBAD", "accessing a corrupted shared library"}, + {81, "ELIBSCN", ".lib section in a.out corrupted"}, + {82, "ELIBMAX", "attempting to link in too many shared libraries"}, + {83, "ELIBEXEC", "cannot exec a shared library directly"}, + {84, "EILSEQ", "invalid or incomplete multibyte or wide character"}, + {85, "ERESTART", "interrupted system call should be restarted"}, + {86, "ESTRPIPE", "streams pipe error"}, + {87, "EUSERS", "too many users"}, + {88, "ENOTSOCK", "socket operation on non-socket"}, + {89, "EDESTADDRREQ", "destination address required"}, + {90, "EMSGSIZE", "message too long"}, + {91, "EPROTOTYPE", "protocol wrong type for socket"}, + {92, "ENOPROTOOPT", "protocol not available"}, + {93, "EPROTONOSUPPORT", "protocol not supported"}, + {94, "ESOCKTNOSUPPORT", "socket type not supported"}, + {95, "ENOTSUP", "operation not supported"}, + {96, "EPFNOSUPPORT", "protocol family not supported"}, + {97, "EAFNOSUPPORT", "address family not supported by protocol"}, + {98, "EADDRINUSE", "address already in use"}, + {99, "EADDRNOTAVAIL", "cannot assign requested address"}, + {100, "ENETDOWN", "network is down"}, + {101, "ENETUNREACH", "network is unreachable"}, + {102, "ENETRESET", "network dropped connection on reset"}, + {103, "ECONNABORTED", "software caused connection abort"}, + {104, "ECONNRESET", "connection reset by peer"}, + {105, "ENOBUFS", "no buffer space available"}, + {106, "EISCONN", "transport endpoint is already connected"}, + {107, "ENOTCONN", "transport endpoint is not connected"}, + {108, "ESHUTDOWN", "cannot send after transport endpoint shutdown"}, + {109, "ETOOMANYREFS", "too many references: cannot splice"}, + {110, "ETIMEDOUT", "connection timed out"}, + {111, "ECONNREFUSED", "connection refused"}, + {112, "EHOSTDOWN", "host is down"}, + {113, "EHOSTUNREACH", "no route to host"}, + {114, "EALREADY", "operation already in progress"}, + {115, "EINPROGRESS", "operation now in progress"}, + {116, "ESTALE", "stale file handle"}, + {117, "EUCLEAN", "structure needs cleaning"}, + {118, "ENOTNAM", "not a XENIX named type file"}, + {119, "ENAVAIL", "no XENIX semaphores available"}, + {120, "EISNAM", "is a named type file"}, + {121, "EREMOTEIO", "remote I/O error"}, + {122, "EDQUOT", "disk quota exceeded"}, + {123, "ENOMEDIUM", "no medium found"}, + {124, "EMEDIUMTYPE", "wrong medium type"}, + {125, "ECANCELED", "operation canceled"}, + {126, "ENOKEY", "required key not available"}, + {127, "EKEYEXPIRED", "key has expired"}, + {128, "EKEYREVOKED", "key has been revoked"}, + {129, "EKEYREJECTED", "key was rejected by service"}, + {130, "EOWNERDEAD", "owner died"}, + {131, "ENOTRECOVERABLE", "state not recoverable"}, + {132, "ERFKILL", "operation not possible due to RF-kill"}, + {133, "EHWPOISON", "memory page has hardware error"}, } // Signal table -var signals = [...]string{ - 1: "hangup", - 2: "interrupt", - 3: "quit", - 4: "illegal instruction", - 5: "trace/breakpoint trap", - 6: "aborted", - 7: "bus error", - 8: "floating point exception", - 9: "killed", - 10: "user defined signal 1", - 11: "segmentation fault", - 12: "user defined signal 2", - 13: "broken pipe", - 14: "alarm clock", - 15: "terminated", - 16: "stack fault", - 17: "child exited", - 18: "continued", - 19: "stopped (signal)", - 20: "stopped", - 21: "stopped (tty input)", - 22: "stopped (tty output)", - 23: "urgent I/O condition", - 24: "CPU time limit exceeded", - 25: "file size limit exceeded", - 26: "virtual timer expired", - 27: "profiling timer expired", - 28: "window changed", - 29: "I/O possible", - 30: "power failure", - 31: "bad system call", +var signalList = [...]struct { + num syscall.Signal + name string + desc string +}{ + {1, "SIGHUP", "hangup"}, + {2, "SIGINT", "interrupt"}, + {3, "SIGQUIT", "quit"}, + {4, "SIGILL", "illegal instruction"}, + {5, "SIGTRAP", "trace/breakpoint trap"}, + {6, "SIGABRT", "aborted"}, + {7, "SIGBUS", "bus error"}, + {8, "SIGFPE", "floating point exception"}, + {9, "SIGKILL", "killed"}, + {10, "SIGUSR1", "user defined signal 1"}, + {11, "SIGSEGV", "segmentation fault"}, + {12, "SIGUSR2", "user defined signal 2"}, + {13, "SIGPIPE", "broken pipe"}, + {14, "SIGALRM", "alarm clock"}, + {15, "SIGTERM", "terminated"}, + {16, "SIGSTKFLT", "stack fault"}, + {17, "SIGCHLD", "child exited"}, + {18, "SIGCONT", "continued"}, + {19, "SIGSTOP", "stopped (signal)"}, + {20, "SIGTSTP", "stopped"}, + {21, "SIGTTIN", "stopped (tty input)"}, + {22, "SIGTTOU", "stopped (tty output)"}, + {23, "SIGURG", "urgent I/O condition"}, + {24, "SIGXCPU", "CPU time limit exceeded"}, + {25, "SIGXFSZ", "file size limit exceeded"}, + {26, "SIGVTALRM", "virtual timer expired"}, + {27, "SIGPROF", "profiling timer expired"}, + {28, "SIGWINCH", "window changed"}, + {29, "SIGIO", "I/O possible"}, + {30, "SIGPWR", "power failure"}, + {31, "SIGSYS", "bad system call"}, } diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go new file mode 100644 index 0000000000..5aea4b9093 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go @@ -0,0 +1,2769 @@ +// mkerrors.sh -Wall -Werror -static -I/tmp/include +// Code generated by the command above; see README.md. DO NOT EDIT. + +// +build riscv64,linux + +// Code generated by cmd/cgo -godefs; DO NOT EDIT. +// cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go + +package unix + +import "syscall" + +const ( + AAFS_MAGIC = 0x5a3c69f0 + ADFS_SUPER_MAGIC = 0xadf5 + AFFS_SUPER_MAGIC = 0xadff + AFS_FS_MAGIC = 0x6b414653 + AFS_SUPER_MAGIC = 0x5346414f + AF_ALG = 0x26 + AF_APPLETALK = 0x5 + AF_ASH = 0x12 + AF_ATMPVC = 0x8 + AF_ATMSVC = 0x14 + AF_AX25 = 0x3 + AF_BLUETOOTH = 0x1f + AF_BRIDGE = 0x7 + AF_CAIF = 0x25 + AF_CAN = 0x1d + AF_DECnet = 0xc + AF_ECONET = 0x13 + AF_FILE = 0x1 + AF_IB = 0x1b + AF_IEEE802154 = 0x24 + AF_INET = 0x2 + AF_INET6 = 0xa + AF_IPX = 0x4 + AF_IRDA = 0x17 + AF_ISDN = 0x22 + AF_IUCV = 0x20 + AF_KCM = 0x29 + AF_KEY = 0xf + AF_LLC = 0x1a + AF_LOCAL = 0x1 + AF_MAX = 0x2d + AF_MPLS = 0x1c + AF_NETBEUI = 0xd + AF_NETLINK = 0x10 + AF_NETROM = 0x6 + AF_NFC = 0x27 + AF_PACKET = 0x11 + AF_PHONET = 0x23 + AF_PPPOX = 0x18 + AF_QIPCRTR = 0x2a + AF_RDS = 0x15 + AF_ROSE = 0xb + AF_ROUTE = 0x10 + AF_RXRPC = 0x21 + AF_SECURITY = 0xe + AF_SMC = 0x2b + AF_SNA = 0x16 + AF_TIPC = 0x1e + AF_UNIX = 0x1 + AF_UNSPEC = 0x0 + AF_VSOCK = 0x28 + AF_WANPIPE = 0x19 + AF_X25 = 0x9 + AF_XDP = 0x2c + ALG_OP_DECRYPT = 0x0 + ALG_OP_ENCRYPT = 0x1 + ALG_SET_AEAD_ASSOCLEN = 0x4 + ALG_SET_AEAD_AUTHSIZE = 0x5 + ALG_SET_IV = 0x2 + ALG_SET_KEY = 0x1 + ALG_SET_OP = 0x3 + ANON_INODE_FS_MAGIC = 0x9041934 + ARPHRD_6LOWPAN = 0x339 + ARPHRD_ADAPT = 0x108 + ARPHRD_APPLETLK = 0x8 + ARPHRD_ARCNET = 0x7 + ARPHRD_ASH = 0x30d + ARPHRD_ATM = 0x13 + ARPHRD_AX25 = 0x3 + ARPHRD_BIF = 0x307 + ARPHRD_CAIF = 0x336 + ARPHRD_CAN = 0x118 + ARPHRD_CHAOS = 0x5 + ARPHRD_CISCO = 0x201 + ARPHRD_CSLIP = 0x101 + ARPHRD_CSLIP6 = 0x103 + ARPHRD_DDCMP = 0x205 + ARPHRD_DLCI = 0xf + ARPHRD_ECONET = 0x30e + ARPHRD_EETHER = 0x2 + ARPHRD_ETHER = 0x1 + ARPHRD_EUI64 = 0x1b + ARPHRD_FCAL = 0x311 + ARPHRD_FCFABRIC = 0x313 + ARPHRD_FCPL = 0x312 + ARPHRD_FCPP = 0x310 + ARPHRD_FDDI = 0x306 + ARPHRD_FRAD = 0x302 + ARPHRD_HDLC = 0x201 + ARPHRD_HIPPI = 0x30c + ARPHRD_HWX25 = 0x110 + ARPHRD_IEEE1394 = 0x18 + ARPHRD_IEEE802 = 0x6 + ARPHRD_IEEE80211 = 0x321 + ARPHRD_IEEE80211_PRISM = 0x322 + ARPHRD_IEEE80211_RADIOTAP = 0x323 + ARPHRD_IEEE802154 = 0x324 + ARPHRD_IEEE802154_MONITOR = 0x325 + ARPHRD_IEEE802_TR = 0x320 + ARPHRD_INFINIBAND = 0x20 + ARPHRD_IP6GRE = 0x337 + ARPHRD_IPDDP = 0x309 + ARPHRD_IPGRE = 0x30a + ARPHRD_IRDA = 0x30f + ARPHRD_LAPB = 0x204 + ARPHRD_LOCALTLK = 0x305 + ARPHRD_LOOPBACK = 0x304 + ARPHRD_METRICOM = 0x17 + ARPHRD_NETLINK = 0x338 + ARPHRD_NETROM = 0x0 + ARPHRD_NONE = 0xfffe + ARPHRD_PHONET = 0x334 + ARPHRD_PHONET_PIPE = 0x335 + ARPHRD_PIMREG = 0x30b + ARPHRD_PPP = 0x200 + ARPHRD_PRONET = 0x4 + ARPHRD_RAWHDLC = 0x206 + ARPHRD_RAWIP = 0x207 + ARPHRD_ROSE = 0x10e + ARPHRD_RSRVD = 0x104 + ARPHRD_SIT = 0x308 + ARPHRD_SKIP = 0x303 + ARPHRD_SLIP = 0x100 + ARPHRD_SLIP6 = 0x102 + ARPHRD_TUNNEL = 0x300 + ARPHRD_TUNNEL6 = 0x301 + ARPHRD_VOID = 0xffff + ARPHRD_VSOCKMON = 0x33a + ARPHRD_X25 = 0x10f + AUTOFS_SUPER_MAGIC = 0x187 + B0 = 0x0 + B1000000 = 0x1008 + B110 = 0x3 + B115200 = 0x1002 + B1152000 = 0x1009 + B1200 = 0x9 + B134 = 0x4 + B150 = 0x5 + B1500000 = 0x100a + B1800 = 0xa + B19200 = 0xe + B200 = 0x6 + B2000000 = 0x100b + B230400 = 0x1003 + B2400 = 0xb + B2500000 = 0x100c + B300 = 0x7 + B3000000 = 0x100d + B3500000 = 0x100e + B38400 = 0xf + B4000000 = 0x100f + B460800 = 0x1004 + B4800 = 0xc + B50 = 0x1 + B500000 = 0x1005 + B57600 = 0x1001 + B576000 = 0x1006 + B600 = 0x8 + B75 = 0x2 + B921600 = 0x1007 + B9600 = 0xd + BALLOON_KVM_MAGIC = 0x13661366 + BDEVFS_MAGIC = 0x62646576 + BINFMTFS_MAGIC = 0x42494e4d + BLKBSZGET = 0x80081270 + BLKBSZSET = 0x40081271 + BLKFLSBUF = 0x1261 + BLKFRAGET = 0x1265 + BLKFRASET = 0x1264 + BLKGETSIZE = 0x1260 + BLKGETSIZE64 = 0x80081272 + BLKPBSZGET = 0x127b + BLKRAGET = 0x1263 + BLKRASET = 0x1262 + BLKROGET = 0x125e + BLKROSET = 0x125d + BLKRRPART = 0x125f + BLKSECTGET = 0x1267 + BLKSECTSET = 0x1266 + BLKSSZGET = 0x1268 + BOTHER = 0x1000 + BPF_A = 0x10 + BPF_ABS = 0x20 + BPF_ADD = 0x0 + BPF_ALU = 0x4 + BPF_AND = 0x50 + BPF_B = 0x10 + BPF_DIV = 0x30 + BPF_FS_MAGIC = 0xcafe4a11 + BPF_H = 0x8 + BPF_IMM = 0x0 + BPF_IND = 0x40 + BPF_JA = 0x0 + BPF_JEQ = 0x10 + BPF_JGE = 0x30 + BPF_JGT = 0x20 + BPF_JMP = 0x5 + BPF_JSET = 0x40 + BPF_K = 0x0 + BPF_LD = 0x0 + BPF_LDX = 0x1 + BPF_LEN = 0x80 + BPF_LL_OFF = -0x200000 + BPF_LSH = 0x60 + BPF_MAJOR_VERSION = 0x1 + BPF_MAXINSNS = 0x1000 + BPF_MEM = 0x60 + BPF_MEMWORDS = 0x10 + BPF_MINOR_VERSION = 0x1 + BPF_MISC = 0x7 + BPF_MOD = 0x90 + BPF_MSH = 0xa0 + BPF_MUL = 0x20 + BPF_NEG = 0x80 + BPF_NET_OFF = -0x100000 + BPF_OR = 0x40 + BPF_RET = 0x6 + BPF_RSH = 0x70 + BPF_ST = 0x2 + BPF_STX = 0x3 + BPF_SUB = 0x10 + BPF_TAX = 0x0 + BPF_TXA = 0x80 + BPF_W = 0x0 + BPF_X = 0x8 + BPF_XOR = 0xa0 + BRKINT = 0x2 + BS0 = 0x0 + BS1 = 0x2000 + BSDLY = 0x2000 + BTRFS_SUPER_MAGIC = 0x9123683e + BTRFS_TEST_MAGIC = 0x73727279 + CAN_BCM = 0x2 + CAN_EFF_FLAG = 0x80000000 + CAN_EFF_ID_BITS = 0x1d + CAN_EFF_MASK = 0x1fffffff + CAN_ERR_FLAG = 0x20000000 + CAN_ERR_MASK = 0x1fffffff + CAN_INV_FILTER = 0x20000000 + CAN_ISOTP = 0x6 + CAN_MAX_DLC = 0x8 + CAN_MAX_DLEN = 0x8 + CAN_MCNET = 0x5 + CAN_MTU = 0x10 + CAN_NPROTO = 0x7 + CAN_RAW = 0x1 + CAN_RAW_FILTER_MAX = 0x200 + CAN_RTR_FLAG = 0x40000000 + CAN_SFF_ID_BITS = 0xb + CAN_SFF_MASK = 0x7ff + CAN_TP16 = 0x3 + CAN_TP20 = 0x4 + CBAUD = 0x100f + CBAUDEX = 0x1000 + CFLUSH = 0xf + CGROUP2_SUPER_MAGIC = 0x63677270 + CGROUP_SUPER_MAGIC = 0x27e0eb + CIBAUD = 0x100f0000 + CLOCAL = 0x800 + CLOCK_BOOTTIME = 0x7 + CLOCK_BOOTTIME_ALARM = 0x9 + CLOCK_DEFAULT = 0x0 + CLOCK_EXT = 0x1 + CLOCK_INT = 0x2 + CLOCK_MONOTONIC = 0x1 + CLOCK_MONOTONIC_COARSE = 0x6 + CLOCK_MONOTONIC_RAW = 0x4 + CLOCK_PROCESS_CPUTIME_ID = 0x2 + CLOCK_REALTIME = 0x0 + CLOCK_REALTIME_ALARM = 0x8 + CLOCK_REALTIME_COARSE = 0x5 + CLOCK_TAI = 0xb + CLOCK_THREAD_CPUTIME_ID = 0x3 + CLOCK_TXFROMRX = 0x4 + CLOCK_TXINT = 0x3 + CLONE_CHILD_CLEARTID = 0x200000 + CLONE_CHILD_SETTID = 0x1000000 + CLONE_DETACHED = 0x400000 + CLONE_FILES = 0x400 + CLONE_FS = 0x200 + CLONE_IO = 0x80000000 + CLONE_NEWCGROUP = 0x2000000 + CLONE_NEWIPC = 0x8000000 + CLONE_NEWNET = 0x40000000 + CLONE_NEWNS = 0x20000 + CLONE_NEWPID = 0x20000000 + CLONE_NEWUSER = 0x10000000 + CLONE_NEWUTS = 0x4000000 + CLONE_PARENT = 0x8000 + CLONE_PARENT_SETTID = 0x100000 + CLONE_PTRACE = 0x2000 + CLONE_SETTLS = 0x80000 + CLONE_SIGHAND = 0x800 + CLONE_SYSVSEM = 0x40000 + CLONE_THREAD = 0x10000 + CLONE_UNTRACED = 0x800000 + CLONE_VFORK = 0x4000 + CLONE_VM = 0x100 + CMSPAR = 0x40000000 + CODA_SUPER_MAGIC = 0x73757245 + CR0 = 0x0 + CR1 = 0x200 + CR2 = 0x400 + CR3 = 0x600 + CRAMFS_MAGIC = 0x28cd3d45 + CRDLY = 0x600 + CREAD = 0x80 + CRTSCTS = 0x80000000 + CS5 = 0x0 + CS6 = 0x10 + CS7 = 0x20 + CS8 = 0x30 + CSIGNAL = 0xff + CSIZE = 0x30 + CSTART = 0x11 + CSTATUS = 0x0 + CSTOP = 0x13 + CSTOPB = 0x40 + CSUSP = 0x1a + DAXFS_MAGIC = 0x64646178 + DEBUGFS_MAGIC = 0x64626720 + DEVPTS_SUPER_MAGIC = 0x1cd1 + DT_BLK = 0x6 + DT_CHR = 0x2 + DT_DIR = 0x4 + DT_FIFO = 0x1 + DT_LNK = 0xa + DT_REG = 0x8 + DT_SOCK = 0xc + DT_UNKNOWN = 0x0 + DT_WHT = 0xe + ECHO = 0x8 + ECHOCTL = 0x200 + ECHOE = 0x10 + ECHOK = 0x20 + ECHOKE = 0x800 + ECHONL = 0x40 + ECHOPRT = 0x400 + ECRYPTFS_SUPER_MAGIC = 0xf15f + EFD_CLOEXEC = 0x80000 + EFD_NONBLOCK = 0x800 + EFD_SEMAPHORE = 0x1 + EFIVARFS_MAGIC = 0xde5e81e4 + EFS_SUPER_MAGIC = 0x414a53 + ENCODING_DEFAULT = 0x0 + ENCODING_FM_MARK = 0x3 + ENCODING_FM_SPACE = 0x4 + ENCODING_MANCHESTER = 0x5 + ENCODING_NRZ = 0x1 + ENCODING_NRZI = 0x2 + EPOLLERR = 0x8 + EPOLLET = 0x80000000 + EPOLLEXCLUSIVE = 0x10000000 + EPOLLHUP = 0x10 + EPOLLIN = 0x1 + EPOLLMSG = 0x400 + EPOLLONESHOT = 0x40000000 + EPOLLOUT = 0x4 + EPOLLPRI = 0x2 + EPOLLRDBAND = 0x80 + EPOLLRDHUP = 0x2000 + EPOLLRDNORM = 0x40 + EPOLLWAKEUP = 0x20000000 + EPOLLWRBAND = 0x200 + EPOLLWRNORM = 0x100 + EPOLL_CLOEXEC = 0x80000 + EPOLL_CTL_ADD = 0x1 + EPOLL_CTL_DEL = 0x2 + EPOLL_CTL_MOD = 0x3 + ETH_P_1588 = 0x88f7 + ETH_P_8021AD = 0x88a8 + ETH_P_8021AH = 0x88e7 + ETH_P_8021Q = 0x8100 + ETH_P_80221 = 0x8917 + ETH_P_802_2 = 0x4 + ETH_P_802_3 = 0x1 + ETH_P_802_3_MIN = 0x600 + ETH_P_802_EX1 = 0x88b5 + ETH_P_AARP = 0x80f3 + ETH_P_AF_IUCV = 0xfbfb + ETH_P_ALL = 0x3 + ETH_P_AOE = 0x88a2 + ETH_P_ARCNET = 0x1a + ETH_P_ARP = 0x806 + ETH_P_ATALK = 0x809b + ETH_P_ATMFATE = 0x8884 + ETH_P_ATMMPOA = 0x884c + ETH_P_AX25 = 0x2 + ETH_P_BATMAN = 0x4305 + ETH_P_BPQ = 0x8ff + ETH_P_CAIF = 0xf7 + ETH_P_CAN = 0xc + ETH_P_CANFD = 0xd + ETH_P_CONTROL = 0x16 + ETH_P_CUST = 0x6006 + ETH_P_DDCMP = 0x6 + ETH_P_DEC = 0x6000 + ETH_P_DIAG = 0x6005 + ETH_P_DNA_DL = 0x6001 + ETH_P_DNA_RC = 0x6002 + ETH_P_DNA_RT = 0x6003 + ETH_P_DSA = 0x1b + ETH_P_ECONET = 0x18 + ETH_P_EDSA = 0xdada + ETH_P_ERSPAN = 0x88be + ETH_P_ERSPAN2 = 0x22eb + ETH_P_FCOE = 0x8906 + ETH_P_FIP = 0x8914 + ETH_P_HDLC = 0x19 + ETH_P_HSR = 0x892f + ETH_P_IBOE = 0x8915 + ETH_P_IEEE802154 = 0xf6 + ETH_P_IEEEPUP = 0xa00 + ETH_P_IEEEPUPAT = 0xa01 + ETH_P_IFE = 0xed3e + ETH_P_IP = 0x800 + ETH_P_IPV6 = 0x86dd + ETH_P_IPX = 0x8137 + ETH_P_IRDA = 0x17 + ETH_P_LAT = 0x6004 + ETH_P_LINK_CTL = 0x886c + ETH_P_LOCALTALK = 0x9 + ETH_P_LOOP = 0x60 + ETH_P_LOOPBACK = 0x9000 + ETH_P_MACSEC = 0x88e5 + ETH_P_MAP = 0xf9 + ETH_P_MOBITEX = 0x15 + ETH_P_MPLS_MC = 0x8848 + ETH_P_MPLS_UC = 0x8847 + ETH_P_MVRP = 0x88f5 + ETH_P_NCSI = 0x88f8 + ETH_P_NSH = 0x894f + ETH_P_PAE = 0x888e + ETH_P_PAUSE = 0x8808 + ETH_P_PHONET = 0xf5 + ETH_P_PPPTALK = 0x10 + ETH_P_PPP_DISC = 0x8863 + ETH_P_PPP_MP = 0x8 + ETH_P_PPP_SES = 0x8864 + ETH_P_PREAUTH = 0x88c7 + ETH_P_PRP = 0x88fb + ETH_P_PUP = 0x200 + ETH_P_PUPAT = 0x201 + ETH_P_QINQ1 = 0x9100 + ETH_P_QINQ2 = 0x9200 + ETH_P_QINQ3 = 0x9300 + ETH_P_RARP = 0x8035 + ETH_P_SCA = 0x6007 + ETH_P_SLOW = 0x8809 + ETH_P_SNAP = 0x5 + ETH_P_TDLS = 0x890d + ETH_P_TEB = 0x6558 + ETH_P_TIPC = 0x88ca + ETH_P_TRAILER = 0x1c + ETH_P_TR_802_2 = 0x11 + ETH_P_TSN = 0x22f0 + ETH_P_WAN_PPP = 0x7 + ETH_P_WCCP = 0x883e + ETH_P_X25 = 0x805 + ETH_P_XDSA = 0xf8 + EXABYTE_ENABLE_NEST = 0xf0 + EXT2_SUPER_MAGIC = 0xef53 + EXT3_SUPER_MAGIC = 0xef53 + EXT4_SUPER_MAGIC = 0xef53 + EXTA = 0xe + EXTB = 0xf + EXTPROC = 0x10000 + F2FS_SUPER_MAGIC = 0xf2f52010 + FALLOC_FL_COLLAPSE_RANGE = 0x8 + FALLOC_FL_INSERT_RANGE = 0x20 + FALLOC_FL_KEEP_SIZE = 0x1 + FALLOC_FL_NO_HIDE_STALE = 0x4 + FALLOC_FL_PUNCH_HOLE = 0x2 + FALLOC_FL_UNSHARE_RANGE = 0x40 + FALLOC_FL_ZERO_RANGE = 0x10 + FD_CLOEXEC = 0x1 + FD_SETSIZE = 0x400 + FF0 = 0x0 + FF1 = 0x8000 + FFDLY = 0x8000 + FLUSHO = 0x1000 + FS_ENCRYPTION_MODE_AES_128_CBC = 0x5 + FS_ENCRYPTION_MODE_AES_128_CTS = 0x6 + FS_ENCRYPTION_MODE_AES_256_CBC = 0x3 + FS_ENCRYPTION_MODE_AES_256_CTS = 0x4 + FS_ENCRYPTION_MODE_AES_256_GCM = 0x2 + FS_ENCRYPTION_MODE_AES_256_XTS = 0x1 + FS_ENCRYPTION_MODE_INVALID = 0x0 + FS_ENCRYPTION_MODE_SPECK128_256_CTS = 0x8 + FS_ENCRYPTION_MODE_SPECK128_256_XTS = 0x7 + FS_IOC_GET_ENCRYPTION_POLICY = 0x400c6615 + FS_IOC_GET_ENCRYPTION_PWSALT = 0x40106614 + FS_IOC_SET_ENCRYPTION_POLICY = 0x800c6613 + FS_KEY_DESCRIPTOR_SIZE = 0x8 + FS_KEY_DESC_PREFIX = "fscrypt:" + FS_KEY_DESC_PREFIX_SIZE = 0x8 + FS_MAX_KEY_SIZE = 0x40 + FS_POLICY_FLAGS_PAD_16 = 0x2 + FS_POLICY_FLAGS_PAD_32 = 0x3 + FS_POLICY_FLAGS_PAD_4 = 0x0 + FS_POLICY_FLAGS_PAD_8 = 0x1 + FS_POLICY_FLAGS_PAD_MASK = 0x3 + FS_POLICY_FLAGS_VALID = 0x3 + FUTEXFS_SUPER_MAGIC = 0xbad1dea + F_ADD_SEALS = 0x409 + F_DUPFD = 0x0 + F_DUPFD_CLOEXEC = 0x406 + F_EXLCK = 0x4 + F_GETFD = 0x1 + F_GETFL = 0x3 + F_GETLEASE = 0x401 + F_GETLK = 0x5 + F_GETLK64 = 0x5 + F_GETOWN = 0x9 + F_GETOWN_EX = 0x10 + F_GETPIPE_SZ = 0x408 + F_GETSIG = 0xb + F_GET_FILE_RW_HINT = 0x40d + F_GET_RW_HINT = 0x40b + F_GET_SEALS = 0x40a + F_LOCK = 0x1 + F_NOTIFY = 0x402 + F_OFD_GETLK = 0x24 + F_OFD_SETLK = 0x25 + F_OFD_SETLKW = 0x26 + F_OK = 0x0 + F_RDLCK = 0x0 + F_SEAL_GROW = 0x4 + F_SEAL_SEAL = 0x1 + F_SEAL_SHRINK = 0x2 + F_SEAL_WRITE = 0x8 + F_SETFD = 0x2 + F_SETFL = 0x4 + F_SETLEASE = 0x400 + F_SETLK = 0x6 + F_SETLK64 = 0x6 + F_SETLKW = 0x7 + F_SETLKW64 = 0x7 + F_SETOWN = 0x8 + F_SETOWN_EX = 0xf + F_SETPIPE_SZ = 0x407 + F_SETSIG = 0xa + F_SET_FILE_RW_HINT = 0x40e + F_SET_RW_HINT = 0x40c + F_SHLCK = 0x8 + F_TEST = 0x3 + F_TLOCK = 0x2 + F_ULOCK = 0x0 + F_UNLCK = 0x2 + F_WRLCK = 0x1 + GENL_ADMIN_PERM = 0x1 + GENL_CMD_CAP_DO = 0x2 + GENL_CMD_CAP_DUMP = 0x4 + GENL_CMD_CAP_HASPOL = 0x8 + GENL_HDRLEN = 0x4 + GENL_ID_CTRL = 0x10 + GENL_ID_PMCRAID = 0x12 + GENL_ID_VFS_DQUOT = 0x11 + GENL_MAX_ID = 0x3ff + GENL_MIN_ID = 0x10 + GENL_NAMSIZ = 0x10 + GENL_START_ALLOC = 0x13 + GENL_UNS_ADMIN_PERM = 0x10 + GRND_NONBLOCK = 0x1 + GRND_RANDOM = 0x2 + HDIO_DRIVE_CMD = 0x31f + HDIO_DRIVE_CMD_AEB = 0x31e + HDIO_DRIVE_CMD_HDR_SIZE = 0x4 + HDIO_DRIVE_HOB_HDR_SIZE = 0x8 + HDIO_DRIVE_RESET = 0x31c + HDIO_DRIVE_TASK = 0x31e + HDIO_DRIVE_TASKFILE = 0x31d + HDIO_DRIVE_TASK_HDR_SIZE = 0x8 + HDIO_GETGEO = 0x301 + HDIO_GET_32BIT = 0x309 + HDIO_GET_ACOUSTIC = 0x30f + HDIO_GET_ADDRESS = 0x310 + HDIO_GET_BUSSTATE = 0x31a + HDIO_GET_DMA = 0x30b + HDIO_GET_IDENTITY = 0x30d + HDIO_GET_KEEPSETTINGS = 0x308 + HDIO_GET_MULTCOUNT = 0x304 + HDIO_GET_NICE = 0x30c + HDIO_GET_NOWERR = 0x30a + HDIO_GET_QDMA = 0x305 + HDIO_GET_UNMASKINTR = 0x302 + HDIO_GET_WCACHE = 0x30e + HDIO_OBSOLETE_IDENTITY = 0x307 + HDIO_SCAN_HWIF = 0x328 + HDIO_SET_32BIT = 0x324 + HDIO_SET_ACOUSTIC = 0x32c + HDIO_SET_ADDRESS = 0x32f + HDIO_SET_BUSSTATE = 0x32d + HDIO_SET_DMA = 0x326 + HDIO_SET_KEEPSETTINGS = 0x323 + HDIO_SET_MULTCOUNT = 0x321 + HDIO_SET_NICE = 0x329 + HDIO_SET_NOWERR = 0x325 + HDIO_SET_PIO_MODE = 0x327 + HDIO_SET_QDMA = 0x32e + HDIO_SET_UNMASKINTR = 0x322 + HDIO_SET_WCACHE = 0x32b + HDIO_SET_XFER = 0x306 + HDIO_TRISTATE_HWIF = 0x31b + HDIO_UNREGISTER_HWIF = 0x32a + HOSTFS_SUPER_MAGIC = 0xc0ffee + HPFS_SUPER_MAGIC = 0xf995e849 + HUGETLBFS_MAGIC = 0x958458f6 + HUPCL = 0x400 + IBSHIFT = 0x10 + ICANON = 0x2 + ICMPV6_FILTER = 0x1 + ICRNL = 0x100 + IEXTEN = 0x8000 + IFA_F_DADFAILED = 0x8 + IFA_F_DEPRECATED = 0x20 + IFA_F_HOMEADDRESS = 0x10 + IFA_F_MANAGETEMPADDR = 0x100 + IFA_F_MCAUTOJOIN = 0x400 + IFA_F_NODAD = 0x2 + IFA_F_NOPREFIXROUTE = 0x200 + IFA_F_OPTIMISTIC = 0x4 + IFA_F_PERMANENT = 0x80 + IFA_F_SECONDARY = 0x1 + IFA_F_STABLE_PRIVACY = 0x800 + IFA_F_TEMPORARY = 0x1 + IFA_F_TENTATIVE = 0x40 + IFA_MAX = 0xa + IFF_ALLMULTI = 0x200 + IFF_ATTACH_QUEUE = 0x200 + IFF_AUTOMEDIA = 0x4000 + IFF_BROADCAST = 0x2 + IFF_DEBUG = 0x4 + IFF_DETACH_QUEUE = 0x400 + IFF_DORMANT = 0x20000 + IFF_DYNAMIC = 0x8000 + IFF_ECHO = 0x40000 + IFF_LOOPBACK = 0x8 + IFF_LOWER_UP = 0x10000 + IFF_MASTER = 0x400 + IFF_MULTICAST = 0x1000 + IFF_MULTI_QUEUE = 0x100 + IFF_NAPI = 0x10 + IFF_NAPI_FRAGS = 0x20 + IFF_NOARP = 0x80 + IFF_NOFILTER = 0x1000 + IFF_NOTRAILERS = 0x20 + IFF_NO_PI = 0x1000 + IFF_ONE_QUEUE = 0x2000 + IFF_PERSIST = 0x800 + IFF_POINTOPOINT = 0x10 + IFF_PORTSEL = 0x2000 + IFF_PROMISC = 0x100 + IFF_RUNNING = 0x40 + IFF_SLAVE = 0x800 + IFF_TAP = 0x2 + IFF_TUN = 0x1 + IFF_TUN_EXCL = 0x8000 + IFF_UP = 0x1 + IFF_VNET_HDR = 0x4000 + IFF_VOLATILE = 0x70c5a + IFNAMSIZ = 0x10 + IGNBRK = 0x1 + IGNCR = 0x80 + IGNPAR = 0x4 + IMAXBEL = 0x2000 + INLCR = 0x40 + INPCK = 0x10 + IN_ACCESS = 0x1 + IN_ALL_EVENTS = 0xfff + IN_ATTRIB = 0x4 + IN_CLASSA_HOST = 0xffffff + IN_CLASSA_MAX = 0x80 + IN_CLASSA_NET = 0xff000000 + IN_CLASSA_NSHIFT = 0x18 + IN_CLASSB_HOST = 0xffff + IN_CLASSB_MAX = 0x10000 + IN_CLASSB_NET = 0xffff0000 + IN_CLASSB_NSHIFT = 0x10 + IN_CLASSC_HOST = 0xff + IN_CLASSC_NET = 0xffffff00 + IN_CLASSC_NSHIFT = 0x8 + IN_CLOEXEC = 0x80000 + IN_CLOSE = 0x18 + IN_CLOSE_NOWRITE = 0x10 + IN_CLOSE_WRITE = 0x8 + IN_CREATE = 0x100 + IN_DELETE = 0x200 + IN_DELETE_SELF = 0x400 + IN_DONT_FOLLOW = 0x2000000 + IN_EXCL_UNLINK = 0x4000000 + IN_IGNORED = 0x8000 + IN_ISDIR = 0x40000000 + IN_LOOPBACKNET = 0x7f + IN_MASK_ADD = 0x20000000 + IN_MASK_CREATE = 0x10000000 + IN_MODIFY = 0x2 + IN_MOVE = 0xc0 + IN_MOVED_FROM = 0x40 + IN_MOVED_TO = 0x80 + IN_MOVE_SELF = 0x800 + IN_NONBLOCK = 0x800 + IN_ONESHOT = 0x80000000 + IN_ONLYDIR = 0x1000000 + IN_OPEN = 0x20 + IN_Q_OVERFLOW = 0x4000 + IN_UNMOUNT = 0x2000 + IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9 + IPPROTO_AH = 0x33 + IPPROTO_BEETPH = 0x5e + IPPROTO_COMP = 0x6c + IPPROTO_DCCP = 0x21 + IPPROTO_DSTOPTS = 0x3c + IPPROTO_EGP = 0x8 + IPPROTO_ENCAP = 0x62 + IPPROTO_ESP = 0x32 + IPPROTO_FRAGMENT = 0x2c + IPPROTO_GRE = 0x2f + IPPROTO_HOPOPTS = 0x0 + IPPROTO_ICMP = 0x1 + IPPROTO_ICMPV6 = 0x3a + IPPROTO_IDP = 0x16 + IPPROTO_IGMP = 0x2 + IPPROTO_IP = 0x0 + IPPROTO_IPIP = 0x4 + IPPROTO_IPV6 = 0x29 + IPPROTO_MH = 0x87 + IPPROTO_MPLS = 0x89 + IPPROTO_MTP = 0x5c + IPPROTO_NONE = 0x3b + IPPROTO_PIM = 0x67 + IPPROTO_PUP = 0xc + IPPROTO_RAW = 0xff + IPPROTO_ROUTING = 0x2b + IPPROTO_RSVP = 0x2e + IPPROTO_SCTP = 0x84 + IPPROTO_TCP = 0x6 + IPPROTO_TP = 0x1d + IPPROTO_UDP = 0x11 + IPPROTO_UDPLITE = 0x88 + IPV6_2292DSTOPTS = 0x4 + IPV6_2292HOPLIMIT = 0x8 + IPV6_2292HOPOPTS = 0x3 + IPV6_2292PKTINFO = 0x2 + IPV6_2292PKTOPTIONS = 0x6 + IPV6_2292RTHDR = 0x5 + IPV6_ADDRFORM = 0x1 + IPV6_ADDR_PREFERENCES = 0x48 + IPV6_ADD_MEMBERSHIP = 0x14 + IPV6_AUTHHDR = 0xa + IPV6_AUTOFLOWLABEL = 0x46 + IPV6_CHECKSUM = 0x7 + IPV6_DONTFRAG = 0x3e + IPV6_DROP_MEMBERSHIP = 0x15 + IPV6_DSTOPTS = 0x3b + IPV6_FREEBIND = 0x4e + IPV6_HDRINCL = 0x24 + IPV6_HOPLIMIT = 0x34 + IPV6_HOPOPTS = 0x36 + IPV6_IPSEC_POLICY = 0x22 + IPV6_JOIN_ANYCAST = 0x1b + IPV6_JOIN_GROUP = 0x14 + IPV6_LEAVE_ANYCAST = 0x1c + IPV6_LEAVE_GROUP = 0x15 + IPV6_MINHOPCOUNT = 0x49 + IPV6_MTU = 0x18 + IPV6_MTU_DISCOVER = 0x17 + IPV6_MULTICAST_ALL = 0x1d + IPV6_MULTICAST_HOPS = 0x12 + IPV6_MULTICAST_IF = 0x11 + IPV6_MULTICAST_LOOP = 0x13 + IPV6_NEXTHOP = 0x9 + IPV6_ORIGDSTADDR = 0x4a + IPV6_PATHMTU = 0x3d + IPV6_PKTINFO = 0x32 + IPV6_PMTUDISC_DO = 0x2 + IPV6_PMTUDISC_DONT = 0x0 + IPV6_PMTUDISC_INTERFACE = 0x4 + IPV6_PMTUDISC_OMIT = 0x5 + IPV6_PMTUDISC_PROBE = 0x3 + IPV6_PMTUDISC_WANT = 0x1 + IPV6_RECVDSTOPTS = 0x3a + IPV6_RECVERR = 0x19 + IPV6_RECVFRAGSIZE = 0x4d + IPV6_RECVHOPLIMIT = 0x33 + IPV6_RECVHOPOPTS = 0x35 + IPV6_RECVORIGDSTADDR = 0x4a + IPV6_RECVPATHMTU = 0x3c + IPV6_RECVPKTINFO = 0x31 + IPV6_RECVRTHDR = 0x38 + IPV6_RECVTCLASS = 0x42 + IPV6_ROUTER_ALERT = 0x16 + IPV6_RTHDR = 0x39 + IPV6_RTHDRDSTOPTS = 0x37 + IPV6_RTHDR_LOOSE = 0x0 + IPV6_RTHDR_STRICT = 0x1 + IPV6_RTHDR_TYPE_0 = 0x0 + IPV6_RXDSTOPTS = 0x3b + IPV6_RXHOPOPTS = 0x36 + IPV6_TCLASS = 0x43 + IPV6_TRANSPARENT = 0x4b + IPV6_UNICAST_HOPS = 0x10 + IPV6_UNICAST_IF = 0x4c + IPV6_V6ONLY = 0x1a + IPV6_XFRM_POLICY = 0x23 + IP_ADD_MEMBERSHIP = 0x23 + IP_ADD_SOURCE_MEMBERSHIP = 0x27 + IP_BIND_ADDRESS_NO_PORT = 0x18 + IP_BLOCK_SOURCE = 0x26 + IP_CHECKSUM = 0x17 + IP_DEFAULT_MULTICAST_LOOP = 0x1 + IP_DEFAULT_MULTICAST_TTL = 0x1 + IP_DF = 0x4000 + IP_DROP_MEMBERSHIP = 0x24 + IP_DROP_SOURCE_MEMBERSHIP = 0x28 + IP_FREEBIND = 0xf + IP_HDRINCL = 0x3 + IP_IPSEC_POLICY = 0x10 + IP_MAXPACKET = 0xffff + IP_MAX_MEMBERSHIPS = 0x14 + IP_MF = 0x2000 + IP_MINTTL = 0x15 + IP_MSFILTER = 0x29 + IP_MSS = 0x240 + IP_MTU = 0xe + IP_MTU_DISCOVER = 0xa + IP_MULTICAST_ALL = 0x31 + IP_MULTICAST_IF = 0x20 + IP_MULTICAST_LOOP = 0x22 + IP_MULTICAST_TTL = 0x21 + IP_NODEFRAG = 0x16 + IP_OFFMASK = 0x1fff + IP_OPTIONS = 0x4 + IP_ORIGDSTADDR = 0x14 + IP_PASSSEC = 0x12 + IP_PKTINFO = 0x8 + IP_PKTOPTIONS = 0x9 + IP_PMTUDISC = 0xa + IP_PMTUDISC_DO = 0x2 + IP_PMTUDISC_DONT = 0x0 + IP_PMTUDISC_INTERFACE = 0x4 + IP_PMTUDISC_OMIT = 0x5 + IP_PMTUDISC_PROBE = 0x3 + IP_PMTUDISC_WANT = 0x1 + IP_RECVERR = 0xb + IP_RECVFRAGSIZE = 0x19 + IP_RECVOPTS = 0x6 + IP_RECVORIGDSTADDR = 0x14 + IP_RECVRETOPTS = 0x7 + IP_RECVTOS = 0xd + IP_RECVTTL = 0xc + IP_RETOPTS = 0x7 + IP_RF = 0x8000 + IP_ROUTER_ALERT = 0x5 + IP_TOS = 0x1 + IP_TRANSPARENT = 0x13 + IP_TTL = 0x2 + IP_UNBLOCK_SOURCE = 0x25 + IP_UNICAST_IF = 0x32 + IP_XFRM_POLICY = 0x11 + ISIG = 0x1 + ISOFS_SUPER_MAGIC = 0x9660 + ISTRIP = 0x20 + IUCLC = 0x200 + IUTF8 = 0x4000 + IXANY = 0x800 + IXOFF = 0x1000 + IXON = 0x400 + JFFS2_SUPER_MAGIC = 0x72b6 + KEXEC_ARCH_386 = 0x30000 + KEXEC_ARCH_68K = 0x40000 + KEXEC_ARCH_AARCH64 = 0xb70000 + KEXEC_ARCH_ARM = 0x280000 + KEXEC_ARCH_DEFAULT = 0x0 + KEXEC_ARCH_IA_64 = 0x320000 + KEXEC_ARCH_MASK = 0xffff0000 + KEXEC_ARCH_MIPS = 0x80000 + KEXEC_ARCH_MIPS_LE = 0xa0000 + KEXEC_ARCH_PPC = 0x140000 + KEXEC_ARCH_PPC64 = 0x150000 + KEXEC_ARCH_S390 = 0x160000 + KEXEC_ARCH_SH = 0x2a0000 + KEXEC_ARCH_X86_64 = 0x3e0000 + KEXEC_FILE_NO_INITRAMFS = 0x4 + KEXEC_FILE_ON_CRASH = 0x2 + KEXEC_FILE_UNLOAD = 0x1 + KEXEC_ON_CRASH = 0x1 + KEXEC_PRESERVE_CONTEXT = 0x2 + KEXEC_SEGMENT_MAX = 0x10 + KEYCTL_ASSUME_AUTHORITY = 0x10 + KEYCTL_CHOWN = 0x4 + KEYCTL_CLEAR = 0x7 + KEYCTL_DESCRIBE = 0x6 + KEYCTL_DH_COMPUTE = 0x17 + KEYCTL_GET_KEYRING_ID = 0x0 + KEYCTL_GET_PERSISTENT = 0x16 + KEYCTL_GET_SECURITY = 0x11 + KEYCTL_INSTANTIATE = 0xc + KEYCTL_INSTANTIATE_IOV = 0x14 + KEYCTL_INVALIDATE = 0x15 + KEYCTL_JOIN_SESSION_KEYRING = 0x1 + KEYCTL_LINK = 0x8 + KEYCTL_NEGATE = 0xd + KEYCTL_PKEY_DECRYPT = 0x1a + KEYCTL_PKEY_ENCRYPT = 0x19 + KEYCTL_PKEY_QUERY = 0x18 + KEYCTL_PKEY_SIGN = 0x1b + KEYCTL_PKEY_VERIFY = 0x1c + KEYCTL_READ = 0xb + KEYCTL_REJECT = 0x13 + KEYCTL_RESTRICT_KEYRING = 0x1d + KEYCTL_REVOKE = 0x3 + KEYCTL_SEARCH = 0xa + KEYCTL_SESSION_TO_PARENT = 0x12 + KEYCTL_SETPERM = 0x5 + KEYCTL_SET_REQKEY_KEYRING = 0xe + KEYCTL_SET_TIMEOUT = 0xf + KEYCTL_SUPPORTS_DECRYPT = 0x2 + KEYCTL_SUPPORTS_ENCRYPT = 0x1 + KEYCTL_SUPPORTS_SIGN = 0x4 + KEYCTL_SUPPORTS_VERIFY = 0x8 + KEYCTL_UNLINK = 0x9 + KEYCTL_UPDATE = 0x2 + KEY_REQKEY_DEFL_DEFAULT = 0x0 + KEY_REQKEY_DEFL_GROUP_KEYRING = 0x6 + KEY_REQKEY_DEFL_NO_CHANGE = -0x1 + KEY_REQKEY_DEFL_PROCESS_KEYRING = 0x2 + KEY_REQKEY_DEFL_REQUESTOR_KEYRING = 0x7 + KEY_REQKEY_DEFL_SESSION_KEYRING = 0x3 + KEY_REQKEY_DEFL_THREAD_KEYRING = 0x1 + KEY_REQKEY_DEFL_USER_KEYRING = 0x4 + KEY_REQKEY_DEFL_USER_SESSION_KEYRING = 0x5 + KEY_SPEC_GROUP_KEYRING = -0x6 + KEY_SPEC_PROCESS_KEYRING = -0x2 + KEY_SPEC_REQKEY_AUTH_KEY = -0x7 + KEY_SPEC_REQUESTOR_KEYRING = -0x8 + KEY_SPEC_SESSION_KEYRING = -0x3 + KEY_SPEC_THREAD_KEYRING = -0x1 + KEY_SPEC_USER_KEYRING = -0x4 + KEY_SPEC_USER_SESSION_KEYRING = -0x5 + LINUX_REBOOT_CMD_CAD_OFF = 0x0 + LINUX_REBOOT_CMD_CAD_ON = 0x89abcdef + LINUX_REBOOT_CMD_HALT = 0xcdef0123 + LINUX_REBOOT_CMD_KEXEC = 0x45584543 + LINUX_REBOOT_CMD_POWER_OFF = 0x4321fedc + LINUX_REBOOT_CMD_RESTART = 0x1234567 + LINUX_REBOOT_CMD_RESTART2 = 0xa1b2c3d4 + LINUX_REBOOT_CMD_SW_SUSPEND = 0xd000fce2 + LINUX_REBOOT_MAGIC1 = 0xfee1dead + LINUX_REBOOT_MAGIC2 = 0x28121969 + LOCK_EX = 0x2 + LOCK_NB = 0x4 + LOCK_SH = 0x1 + LOCK_UN = 0x8 + MADV_DODUMP = 0x11 + MADV_DOFORK = 0xb + MADV_DONTDUMP = 0x10 + MADV_DONTFORK = 0xa + MADV_DONTNEED = 0x4 + MADV_FREE = 0x8 + MADV_HUGEPAGE = 0xe + MADV_HWPOISON = 0x64 + MADV_KEEPONFORK = 0x13 + MADV_MERGEABLE = 0xc + MADV_NOHUGEPAGE = 0xf + MADV_NORMAL = 0x0 + MADV_RANDOM = 0x1 + MADV_REMOVE = 0x9 + MADV_SEQUENTIAL = 0x2 + MADV_UNMERGEABLE = 0xd + MADV_WILLNEED = 0x3 + MADV_WIPEONFORK = 0x12 + MAP_ANON = 0x20 + MAP_ANONYMOUS = 0x20 + MAP_DENYWRITE = 0x800 + MAP_EXECUTABLE = 0x1000 + MAP_FILE = 0x0 + MAP_FIXED = 0x10 + MAP_FIXED_NOREPLACE = 0x100000 + MAP_GROWSDOWN = 0x100 + MAP_HUGETLB = 0x40000 + MAP_HUGE_MASK = 0x3f + MAP_HUGE_SHIFT = 0x1a + MAP_LOCKED = 0x2000 + MAP_NONBLOCK = 0x10000 + MAP_NORESERVE = 0x4000 + MAP_POPULATE = 0x8000 + MAP_PRIVATE = 0x2 + MAP_SHARED = 0x1 + MAP_SHARED_VALIDATE = 0x3 + MAP_STACK = 0x20000 + MAP_SYNC = 0x80000 + MAP_TYPE = 0xf + MCL_CURRENT = 0x1 + MCL_FUTURE = 0x2 + MCL_ONFAULT = 0x4 + MFD_ALLOW_SEALING = 0x2 + MFD_CLOEXEC = 0x1 + MFD_HUGETLB = 0x4 + MFD_HUGE_16GB = -0x78000000 + MFD_HUGE_16MB = 0x60000000 + MFD_HUGE_1GB = 0x78000000 + MFD_HUGE_1MB = 0x50000000 + MFD_HUGE_256MB = 0x70000000 + MFD_HUGE_2GB = 0x7c000000 + MFD_HUGE_2MB = 0x54000000 + MFD_HUGE_32MB = 0x64000000 + MFD_HUGE_512KB = 0x4c000000 + MFD_HUGE_512MB = 0x74000000 + MFD_HUGE_64KB = 0x40000000 + MFD_HUGE_8MB = 0x5c000000 + MFD_HUGE_MASK = 0x3f + MFD_HUGE_SHIFT = 0x1a + MINIX2_SUPER_MAGIC = 0x2468 + MINIX2_SUPER_MAGIC2 = 0x2478 + MINIX3_SUPER_MAGIC = 0x4d5a + MINIX_SUPER_MAGIC = 0x137f + MINIX_SUPER_MAGIC2 = 0x138f + MNT_DETACH = 0x2 + MNT_EXPIRE = 0x4 + MNT_FORCE = 0x1 + MODULE_INIT_IGNORE_MODVERSIONS = 0x1 + MODULE_INIT_IGNORE_VERMAGIC = 0x2 + MSDOS_SUPER_MAGIC = 0x4d44 + MSG_BATCH = 0x40000 + MSG_CMSG_CLOEXEC = 0x40000000 + MSG_CONFIRM = 0x800 + MSG_CTRUNC = 0x8 + MSG_DONTROUTE = 0x4 + MSG_DONTWAIT = 0x40 + MSG_EOR = 0x80 + MSG_ERRQUEUE = 0x2000 + MSG_FASTOPEN = 0x20000000 + MSG_FIN = 0x200 + MSG_MORE = 0x8000 + MSG_NOSIGNAL = 0x4000 + MSG_OOB = 0x1 + MSG_PEEK = 0x2 + MSG_PROXY = 0x10 + MSG_RST = 0x1000 + MSG_SYN = 0x400 + MSG_TRUNC = 0x20 + MSG_TRYHARD = 0x4 + MSG_WAITALL = 0x100 + MSG_WAITFORONE = 0x10000 + MSG_ZEROCOPY = 0x4000000 + MS_ACTIVE = 0x40000000 + MS_ASYNC = 0x1 + MS_BIND = 0x1000 + MS_BORN = 0x20000000 + MS_DIRSYNC = 0x80 + MS_INVALIDATE = 0x2 + MS_I_VERSION = 0x800000 + MS_KERNMOUNT = 0x400000 + MS_LAZYTIME = 0x2000000 + MS_MANDLOCK = 0x40 + MS_MGC_MSK = 0xffff0000 + MS_MGC_VAL = 0xc0ed0000 + MS_MOVE = 0x2000 + MS_NOATIME = 0x400 + MS_NODEV = 0x4 + MS_NODIRATIME = 0x800 + MS_NOEXEC = 0x8 + MS_NOREMOTELOCK = 0x8000000 + MS_NOSEC = 0x10000000 + MS_NOSUID = 0x2 + MS_NOUSER = -0x80000000 + MS_POSIXACL = 0x10000 + MS_PRIVATE = 0x40000 + MS_RDONLY = 0x1 + MS_REC = 0x4000 + MS_RELATIME = 0x200000 + MS_REMOUNT = 0x20 + MS_RMT_MASK = 0x2800051 + MS_SHARED = 0x100000 + MS_SILENT = 0x8000 + MS_SLAVE = 0x80000 + MS_STRICTATIME = 0x1000000 + MS_SUBMOUNT = 0x4000000 + MS_SYNC = 0x4 + MS_SYNCHRONOUS = 0x10 + MS_UNBINDABLE = 0x20000 + MS_VERBOSE = 0x8000 + MTD_INODE_FS_MAGIC = 0x11307854 + NAME_MAX = 0xff + NCP_SUPER_MAGIC = 0x564c + NETLINK_ADD_MEMBERSHIP = 0x1 + NETLINK_AUDIT = 0x9 + NETLINK_BROADCAST_ERROR = 0x4 + NETLINK_CAP_ACK = 0xa + NETLINK_CONNECTOR = 0xb + NETLINK_CRYPTO = 0x15 + NETLINK_DNRTMSG = 0xe + NETLINK_DROP_MEMBERSHIP = 0x2 + NETLINK_ECRYPTFS = 0x13 + NETLINK_EXT_ACK = 0xb + NETLINK_FIB_LOOKUP = 0xa + NETLINK_FIREWALL = 0x3 + NETLINK_GENERIC = 0x10 + NETLINK_GET_STRICT_CHK = 0xc + NETLINK_INET_DIAG = 0x4 + NETLINK_IP6_FW = 0xd + NETLINK_ISCSI = 0x8 + NETLINK_KOBJECT_UEVENT = 0xf + NETLINK_LISTEN_ALL_NSID = 0x8 + NETLINK_LIST_MEMBERSHIPS = 0x9 + NETLINK_NETFILTER = 0xc + NETLINK_NFLOG = 0x5 + NETLINK_NO_ENOBUFS = 0x5 + NETLINK_PKTINFO = 0x3 + NETLINK_RDMA = 0x14 + NETLINK_ROUTE = 0x0 + NETLINK_RX_RING = 0x6 + NETLINK_SCSITRANSPORT = 0x12 + NETLINK_SELINUX = 0x7 + NETLINK_SMC = 0x16 + NETLINK_SOCK_DIAG = 0x4 + NETLINK_TX_RING = 0x7 + NETLINK_UNUSED = 0x1 + NETLINK_USERSOCK = 0x2 + NETLINK_XFRM = 0x6 + NETNSA_MAX = 0x3 + NETNSA_NSID_NOT_ASSIGNED = -0x1 + NFNETLINK_V0 = 0x0 + NFNLGRP_ACCT_QUOTA = 0x8 + NFNLGRP_CONNTRACK_DESTROY = 0x3 + NFNLGRP_CONNTRACK_EXP_DESTROY = 0x6 + NFNLGRP_CONNTRACK_EXP_NEW = 0x4 + NFNLGRP_CONNTRACK_EXP_UPDATE = 0x5 + NFNLGRP_CONNTRACK_NEW = 0x1 + NFNLGRP_CONNTRACK_UPDATE = 0x2 + NFNLGRP_MAX = 0x9 + NFNLGRP_NFTABLES = 0x7 + NFNLGRP_NFTRACE = 0x9 + NFNLGRP_NONE = 0x0 + NFNL_BATCH_MAX = 0x1 + NFNL_MSG_BATCH_BEGIN = 0x10 + NFNL_MSG_BATCH_END = 0x11 + NFNL_NFA_NEST = 0x8000 + NFNL_SUBSYS_ACCT = 0x7 + NFNL_SUBSYS_COUNT = 0xc + NFNL_SUBSYS_CTHELPER = 0x9 + NFNL_SUBSYS_CTNETLINK = 0x1 + NFNL_SUBSYS_CTNETLINK_EXP = 0x2 + NFNL_SUBSYS_CTNETLINK_TIMEOUT = 0x8 + NFNL_SUBSYS_IPSET = 0x6 + NFNL_SUBSYS_NFTABLES = 0xa + NFNL_SUBSYS_NFT_COMPAT = 0xb + NFNL_SUBSYS_NONE = 0x0 + NFNL_SUBSYS_OSF = 0x5 + NFNL_SUBSYS_QUEUE = 0x3 + NFNL_SUBSYS_ULOG = 0x4 + NFS_SUPER_MAGIC = 0x6969 + NILFS_SUPER_MAGIC = 0x3434 + NL0 = 0x0 + NL1 = 0x100 + NLA_ALIGNTO = 0x4 + NLA_F_NESTED = 0x8000 + NLA_F_NET_BYTEORDER = 0x4000 + NLA_HDRLEN = 0x4 + NLDLY = 0x100 + NLMSG_ALIGNTO = 0x4 + NLMSG_DONE = 0x3 + NLMSG_ERROR = 0x2 + NLMSG_HDRLEN = 0x10 + NLMSG_MIN_TYPE = 0x10 + NLMSG_NOOP = 0x1 + NLMSG_OVERRUN = 0x4 + NLM_F_ACK = 0x4 + NLM_F_ACK_TLVS = 0x200 + NLM_F_APPEND = 0x800 + NLM_F_ATOMIC = 0x400 + NLM_F_CAPPED = 0x100 + NLM_F_CREATE = 0x400 + NLM_F_DUMP = 0x300 + NLM_F_DUMP_FILTERED = 0x20 + NLM_F_DUMP_INTR = 0x10 + NLM_F_ECHO = 0x8 + NLM_F_EXCL = 0x200 + NLM_F_MATCH = 0x200 + NLM_F_MULTI = 0x2 + NLM_F_NONREC = 0x100 + NLM_F_REPLACE = 0x100 + NLM_F_REQUEST = 0x1 + NLM_F_ROOT = 0x100 + NOFLSH = 0x80 + NSFS_MAGIC = 0x6e736673 + OCFS2_SUPER_MAGIC = 0x7461636f + OCRNL = 0x8 + OFDEL = 0x80 + OFILL = 0x40 + OLCUC = 0x2 + ONLCR = 0x4 + ONLRET = 0x20 + ONOCR = 0x10 + OPENPROM_SUPER_MAGIC = 0x9fa1 + OPOST = 0x1 + OVERLAYFS_SUPER_MAGIC = 0x794c7630 + O_ACCMODE = 0x3 + O_APPEND = 0x400 + O_ASYNC = 0x2000 + O_CLOEXEC = 0x80000 + O_CREAT = 0x40 + O_DIRECT = 0x4000 + O_DIRECTORY = 0x10000 + O_DSYNC = 0x1000 + O_EXCL = 0x80 + O_FSYNC = 0x101000 + O_LARGEFILE = 0x0 + O_NDELAY = 0x800 + O_NOATIME = 0x40000 + O_NOCTTY = 0x100 + O_NOFOLLOW = 0x20000 + O_NONBLOCK = 0x800 + O_PATH = 0x200000 + O_RDONLY = 0x0 + O_RDWR = 0x2 + O_RSYNC = 0x101000 + O_SYNC = 0x101000 + O_TMPFILE = 0x410000 + O_TRUNC = 0x200 + O_WRONLY = 0x1 + PACKET_ADD_MEMBERSHIP = 0x1 + PACKET_AUXDATA = 0x8 + PACKET_BROADCAST = 0x1 + PACKET_COPY_THRESH = 0x7 + PACKET_DROP_MEMBERSHIP = 0x2 + PACKET_FANOUT = 0x12 + PACKET_FANOUT_CBPF = 0x6 + PACKET_FANOUT_CPU = 0x2 + PACKET_FANOUT_DATA = 0x16 + PACKET_FANOUT_EBPF = 0x7 + PACKET_FANOUT_FLAG_DEFRAG = 0x8000 + PACKET_FANOUT_FLAG_ROLLOVER = 0x1000 + PACKET_FANOUT_FLAG_UNIQUEID = 0x2000 + PACKET_FANOUT_HASH = 0x0 + PACKET_FANOUT_LB = 0x1 + PACKET_FANOUT_QM = 0x5 + PACKET_FANOUT_RND = 0x4 + PACKET_FANOUT_ROLLOVER = 0x3 + PACKET_FASTROUTE = 0x6 + PACKET_HDRLEN = 0xb + PACKET_HOST = 0x0 + PACKET_IGNORE_OUTGOING = 0x17 + PACKET_KERNEL = 0x7 + PACKET_LOOPBACK = 0x5 + PACKET_LOSS = 0xe + PACKET_MR_ALLMULTI = 0x2 + PACKET_MR_MULTICAST = 0x0 + PACKET_MR_PROMISC = 0x1 + PACKET_MR_UNICAST = 0x3 + PACKET_MULTICAST = 0x2 + PACKET_ORIGDEV = 0x9 + PACKET_OTHERHOST = 0x3 + PACKET_OUTGOING = 0x4 + PACKET_QDISC_BYPASS = 0x14 + PACKET_RECV_OUTPUT = 0x3 + PACKET_RESERVE = 0xc + PACKET_ROLLOVER_STATS = 0x15 + PACKET_RX_RING = 0x5 + PACKET_STATISTICS = 0x6 + PACKET_TIMESTAMP = 0x11 + PACKET_TX_HAS_OFF = 0x13 + PACKET_TX_RING = 0xd + PACKET_TX_TIMESTAMP = 0x10 + PACKET_USER = 0x6 + PACKET_VERSION = 0xa + PACKET_VNET_HDR = 0xf + PARENB = 0x100 + PARITY_CRC16_PR0 = 0x2 + PARITY_CRC16_PR0_CCITT = 0x4 + PARITY_CRC16_PR1 = 0x3 + PARITY_CRC16_PR1_CCITT = 0x5 + PARITY_CRC32_PR0_CCITT = 0x6 + PARITY_CRC32_PR1_CCITT = 0x7 + PARITY_DEFAULT = 0x0 + PARITY_NONE = 0x1 + PARMRK = 0x8 + PARODD = 0x200 + PENDIN = 0x4000 + PERF_EVENT_IOC_DISABLE = 0x2401 + PERF_EVENT_IOC_ENABLE = 0x2400 + PERF_EVENT_IOC_ID = 0x80082407 + PERF_EVENT_IOC_MODIFY_ATTRIBUTES = 0x4008240b + PERF_EVENT_IOC_PAUSE_OUTPUT = 0x40042409 + PERF_EVENT_IOC_PERIOD = 0x40082404 + PERF_EVENT_IOC_QUERY_BPF = 0xc008240a + PERF_EVENT_IOC_REFRESH = 0x2402 + PERF_EVENT_IOC_RESET = 0x2403 + PERF_EVENT_IOC_SET_BPF = 0x40042408 + PERF_EVENT_IOC_SET_FILTER = 0x40082406 + PERF_EVENT_IOC_SET_OUTPUT = 0x2405 + PIPEFS_MAGIC = 0x50495045 + PPPIOCATTACH = 0x4004743d + PPPIOCATTCHAN = 0x40047438 + PPPIOCCONNECT = 0x4004743a + PPPIOCDETACH = 0x4004743c + PPPIOCDISCONN = 0x7439 + PPPIOCGASYNCMAP = 0x80047458 + PPPIOCGCHAN = 0x80047437 + PPPIOCGDEBUG = 0x80047441 + PPPIOCGFLAGS = 0x8004745a + PPPIOCGIDLE = 0x8010743f + PPPIOCGL2TPSTATS = 0x80487436 + PPPIOCGMRU = 0x80047453 + PPPIOCGNPMODE = 0xc008744c + PPPIOCGRASYNCMAP = 0x80047455 + PPPIOCGUNIT = 0x80047456 + PPPIOCGXASYNCMAP = 0x80207450 + PPPIOCNEWUNIT = 0xc004743e + PPPIOCSACTIVE = 0x40107446 + PPPIOCSASYNCMAP = 0x40047457 + PPPIOCSCOMPRESS = 0x4010744d + PPPIOCSDEBUG = 0x40047440 + PPPIOCSFLAGS = 0x40047459 + PPPIOCSMAXCID = 0x40047451 + PPPIOCSMRRU = 0x4004743b + PPPIOCSMRU = 0x40047452 + PPPIOCSNPMODE = 0x4008744b + PPPIOCSPASS = 0x40107447 + PPPIOCSRASYNCMAP = 0x40047454 + PPPIOCSXASYNCMAP = 0x4020744f + PPPIOCXFERUNIT = 0x744e + PRIO_PGRP = 0x1 + PRIO_PROCESS = 0x0 + PRIO_USER = 0x2 + PROC_SUPER_MAGIC = 0x9fa0 + PROT_EXEC = 0x4 + PROT_GROWSDOWN = 0x1000000 + PROT_GROWSUP = 0x2000000 + PROT_NONE = 0x0 + PROT_READ = 0x1 + PROT_WRITE = 0x2 + PR_CAPBSET_DROP = 0x18 + PR_CAPBSET_READ = 0x17 + PR_CAP_AMBIENT = 0x2f + PR_CAP_AMBIENT_CLEAR_ALL = 0x4 + PR_CAP_AMBIENT_IS_SET = 0x1 + PR_CAP_AMBIENT_LOWER = 0x3 + PR_CAP_AMBIENT_RAISE = 0x2 + PR_ENDIAN_BIG = 0x0 + PR_ENDIAN_LITTLE = 0x1 + PR_ENDIAN_PPC_LITTLE = 0x2 + PR_FPEMU_NOPRINT = 0x1 + PR_FPEMU_SIGFPE = 0x2 + PR_FP_EXC_ASYNC = 0x2 + PR_FP_EXC_DISABLED = 0x0 + PR_FP_EXC_DIV = 0x10000 + PR_FP_EXC_INV = 0x100000 + PR_FP_EXC_NONRECOV = 0x1 + PR_FP_EXC_OVF = 0x20000 + PR_FP_EXC_PRECISE = 0x3 + PR_FP_EXC_RES = 0x80000 + PR_FP_EXC_SW_ENABLE = 0x80 + PR_FP_EXC_UND = 0x40000 + PR_FP_MODE_FR = 0x1 + PR_FP_MODE_FRE = 0x2 + PR_GET_CHILD_SUBREAPER = 0x25 + PR_GET_DUMPABLE = 0x3 + PR_GET_ENDIAN = 0x13 + PR_GET_FPEMU = 0x9 + PR_GET_FPEXC = 0xb + PR_GET_FP_MODE = 0x2e + PR_GET_KEEPCAPS = 0x7 + PR_GET_NAME = 0x10 + PR_GET_NO_NEW_PRIVS = 0x27 + PR_GET_PDEATHSIG = 0x2 + PR_GET_SECCOMP = 0x15 + PR_GET_SECUREBITS = 0x1b + PR_GET_SPECULATION_CTRL = 0x34 + PR_GET_THP_DISABLE = 0x2a + PR_GET_TID_ADDRESS = 0x28 + PR_GET_TIMERSLACK = 0x1e + PR_GET_TIMING = 0xd + PR_GET_TSC = 0x19 + PR_GET_UNALIGN = 0x5 + PR_MCE_KILL = 0x21 + PR_MCE_KILL_CLEAR = 0x0 + PR_MCE_KILL_DEFAULT = 0x2 + PR_MCE_KILL_EARLY = 0x1 + PR_MCE_KILL_GET = 0x22 + PR_MCE_KILL_LATE = 0x0 + PR_MCE_KILL_SET = 0x1 + PR_MPX_DISABLE_MANAGEMENT = 0x2c + PR_MPX_ENABLE_MANAGEMENT = 0x2b + PR_SET_CHILD_SUBREAPER = 0x24 + PR_SET_DUMPABLE = 0x4 + PR_SET_ENDIAN = 0x14 + PR_SET_FPEMU = 0xa + PR_SET_FPEXC = 0xc + PR_SET_FP_MODE = 0x2d + PR_SET_KEEPCAPS = 0x8 + PR_SET_MM = 0x23 + PR_SET_MM_ARG_END = 0x9 + PR_SET_MM_ARG_START = 0x8 + PR_SET_MM_AUXV = 0xc + PR_SET_MM_BRK = 0x7 + PR_SET_MM_END_CODE = 0x2 + PR_SET_MM_END_DATA = 0x4 + PR_SET_MM_ENV_END = 0xb + PR_SET_MM_ENV_START = 0xa + PR_SET_MM_EXE_FILE = 0xd + PR_SET_MM_MAP = 0xe + PR_SET_MM_MAP_SIZE = 0xf + PR_SET_MM_START_BRK = 0x6 + PR_SET_MM_START_CODE = 0x1 + PR_SET_MM_START_DATA = 0x3 + PR_SET_MM_START_STACK = 0x5 + PR_SET_NAME = 0xf + PR_SET_NO_NEW_PRIVS = 0x26 + PR_SET_PDEATHSIG = 0x1 + PR_SET_PTRACER = 0x59616d61 + PR_SET_PTRACER_ANY = 0xffffffffffffffff + PR_SET_SECCOMP = 0x16 + PR_SET_SECUREBITS = 0x1c + PR_SET_SPECULATION_CTRL = 0x35 + PR_SET_THP_DISABLE = 0x29 + PR_SET_TIMERSLACK = 0x1d + PR_SET_TIMING = 0xe + PR_SET_TSC = 0x1a + PR_SET_UNALIGN = 0x6 + PR_SPEC_DISABLE = 0x4 + PR_SPEC_ENABLE = 0x2 + PR_SPEC_FORCE_DISABLE = 0x8 + PR_SPEC_INDIRECT_BRANCH = 0x1 + PR_SPEC_NOT_AFFECTED = 0x0 + PR_SPEC_PRCTL = 0x1 + PR_SPEC_STORE_BYPASS = 0x0 + PR_SVE_GET_VL = 0x33 + PR_SVE_SET_VL = 0x32 + PR_SVE_SET_VL_ONEXEC = 0x40000 + PR_SVE_VL_INHERIT = 0x20000 + PR_SVE_VL_LEN_MASK = 0xffff + PR_TASK_PERF_EVENTS_DISABLE = 0x1f + PR_TASK_PERF_EVENTS_ENABLE = 0x20 + PR_TIMING_STATISTICAL = 0x0 + PR_TIMING_TIMESTAMP = 0x1 + PR_TSC_ENABLE = 0x1 + PR_TSC_SIGSEGV = 0x2 + PR_UNALIGN_NOPRINT = 0x1 + PR_UNALIGN_SIGBUS = 0x2 + PSTOREFS_MAGIC = 0x6165676c + PTRACE_ATTACH = 0x10 + PTRACE_CONT = 0x7 + PTRACE_DETACH = 0x11 + PTRACE_EVENT_CLONE = 0x3 + PTRACE_EVENT_EXEC = 0x4 + PTRACE_EVENT_EXIT = 0x6 + PTRACE_EVENT_FORK = 0x1 + PTRACE_EVENT_SECCOMP = 0x7 + PTRACE_EVENT_STOP = 0x80 + PTRACE_EVENT_VFORK = 0x2 + PTRACE_EVENT_VFORK_DONE = 0x5 + PTRACE_GETEVENTMSG = 0x4201 + PTRACE_GETREGS = 0xc + PTRACE_GETREGSET = 0x4204 + PTRACE_GETSIGINFO = 0x4202 + PTRACE_GETSIGMASK = 0x420a + PTRACE_INTERRUPT = 0x4207 + PTRACE_KILL = 0x8 + PTRACE_LISTEN = 0x4208 + PTRACE_O_EXITKILL = 0x100000 + PTRACE_O_MASK = 0x3000ff + PTRACE_O_SUSPEND_SECCOMP = 0x200000 + PTRACE_O_TRACECLONE = 0x8 + PTRACE_O_TRACEEXEC = 0x10 + PTRACE_O_TRACEEXIT = 0x40 + PTRACE_O_TRACEFORK = 0x2 + PTRACE_O_TRACESECCOMP = 0x80 + PTRACE_O_TRACESYSGOOD = 0x1 + PTRACE_O_TRACEVFORK = 0x4 + PTRACE_O_TRACEVFORKDONE = 0x20 + PTRACE_PEEKDATA = 0x2 + PTRACE_PEEKSIGINFO = 0x4209 + PTRACE_PEEKSIGINFO_SHARED = 0x1 + PTRACE_PEEKTEXT = 0x1 + PTRACE_PEEKUSR = 0x3 + PTRACE_POKEDATA = 0x5 + PTRACE_POKETEXT = 0x4 + PTRACE_POKEUSR = 0x6 + PTRACE_SECCOMP_GET_FILTER = 0x420c + PTRACE_SECCOMP_GET_METADATA = 0x420d + PTRACE_SEIZE = 0x4206 + PTRACE_SETOPTIONS = 0x4200 + PTRACE_SETREGS = 0xd + PTRACE_SETREGSET = 0x4205 + PTRACE_SETSIGINFO = 0x4203 + PTRACE_SETSIGMASK = 0x420b + PTRACE_SINGLESTEP = 0x9 + PTRACE_SYSCALL = 0x18 + PTRACE_TRACEME = 0x0 + QNX4_SUPER_MAGIC = 0x2f + QNX6_SUPER_MAGIC = 0x68191122 + RAMFS_MAGIC = 0x858458f6 + RDTGROUP_SUPER_MAGIC = 0x7655821 + REISERFS_SUPER_MAGIC = 0x52654973 + RENAME_EXCHANGE = 0x2 + RENAME_NOREPLACE = 0x1 + RENAME_WHITEOUT = 0x4 + RLIMIT_AS = 0x9 + RLIMIT_CORE = 0x4 + RLIMIT_CPU = 0x0 + RLIMIT_DATA = 0x2 + RLIMIT_FSIZE = 0x1 + RLIMIT_LOCKS = 0xa + RLIMIT_MEMLOCK = 0x8 + RLIMIT_MSGQUEUE = 0xc + RLIMIT_NICE = 0xd + RLIMIT_NOFILE = 0x7 + RLIMIT_NPROC = 0x6 + RLIMIT_RSS = 0x5 + RLIMIT_RTPRIO = 0xe + RLIMIT_RTTIME = 0xf + RLIMIT_SIGPENDING = 0xb + RLIMIT_STACK = 0x3 + RLIM_INFINITY = 0xffffffffffffffff + RNDADDENTROPY = 0x40085203 + RNDADDTOENTCNT = 0x40045201 + RNDCLEARPOOL = 0x5206 + RNDGETENTCNT = 0x80045200 + RNDGETPOOL = 0x80085202 + RNDRESEEDCRNG = 0x5207 + RNDZAPENTCNT = 0x5204 + RTAX_ADVMSS = 0x8 + RTAX_CC_ALGO = 0x10 + RTAX_CWND = 0x7 + RTAX_FASTOPEN_NO_COOKIE = 0x11 + RTAX_FEATURES = 0xc + RTAX_FEATURE_ALLFRAG = 0x8 + RTAX_FEATURE_ECN = 0x1 + RTAX_FEATURE_MASK = 0xf + RTAX_FEATURE_SACK = 0x2 + RTAX_FEATURE_TIMESTAMP = 0x4 + RTAX_HOPLIMIT = 0xa + RTAX_INITCWND = 0xb + RTAX_INITRWND = 0xe + RTAX_LOCK = 0x1 + RTAX_MAX = 0x11 + RTAX_MTU = 0x2 + RTAX_QUICKACK = 0xf + RTAX_REORDERING = 0x9 + RTAX_RTO_MIN = 0xd + RTAX_RTT = 0x4 + RTAX_RTTVAR = 0x5 + RTAX_SSTHRESH = 0x6 + RTAX_UNSPEC = 0x0 + RTAX_WINDOW = 0x3 + RTA_ALIGNTO = 0x4 + RTA_MAX = 0x1d + RTCF_DIRECTSRC = 0x4000000 + RTCF_DOREDIRECT = 0x1000000 + RTCF_LOG = 0x2000000 + RTCF_MASQ = 0x400000 + RTCF_NAT = 0x800000 + RTCF_VALVE = 0x200000 + RTC_AF = 0x20 + RTC_AIE_OFF = 0x7002 + RTC_AIE_ON = 0x7001 + RTC_ALM_READ = 0x80247008 + RTC_ALM_SET = 0x40247007 + RTC_EPOCH_READ = 0x8008700d + RTC_EPOCH_SET = 0x4008700e + RTC_IRQF = 0x80 + RTC_IRQP_READ = 0x8008700b + RTC_IRQP_SET = 0x4008700c + RTC_MAX_FREQ = 0x2000 + RTC_PF = 0x40 + RTC_PIE_OFF = 0x7006 + RTC_PIE_ON = 0x7005 + RTC_PLL_GET = 0x80207011 + RTC_PLL_SET = 0x40207012 + RTC_RD_TIME = 0x80247009 + RTC_SET_TIME = 0x4024700a + RTC_UF = 0x10 + RTC_UIE_OFF = 0x7004 + RTC_UIE_ON = 0x7003 + RTC_VL_CLR = 0x7014 + RTC_VL_READ = 0x80047013 + RTC_WIE_OFF = 0x7010 + RTC_WIE_ON = 0x700f + RTC_WKALM_RD = 0x80287010 + RTC_WKALM_SET = 0x4028700f + RTF_ADDRCLASSMASK = 0xf8000000 + RTF_ADDRCONF = 0x40000 + RTF_ALLONLINK = 0x20000 + RTF_BROADCAST = 0x10000000 + RTF_CACHE = 0x1000000 + RTF_DEFAULT = 0x10000 + RTF_DYNAMIC = 0x10 + RTF_FLOW = 0x2000000 + RTF_GATEWAY = 0x2 + RTF_HOST = 0x4 + RTF_INTERFACE = 0x40000000 + RTF_IRTT = 0x100 + RTF_LINKRT = 0x100000 + RTF_LOCAL = 0x80000000 + RTF_MODIFIED = 0x20 + RTF_MSS = 0x40 + RTF_MTU = 0x40 + RTF_MULTICAST = 0x20000000 + RTF_NAT = 0x8000000 + RTF_NOFORWARD = 0x1000 + RTF_NONEXTHOP = 0x200000 + RTF_NOPMTUDISC = 0x4000 + RTF_POLICY = 0x4000000 + RTF_REINSTATE = 0x8 + RTF_REJECT = 0x200 + RTF_STATIC = 0x400 + RTF_THROW = 0x2000 + RTF_UP = 0x1 + RTF_WINDOW = 0x80 + RTF_XRESOLVE = 0x800 + RTM_BASE = 0x10 + RTM_DELACTION = 0x31 + RTM_DELADDR = 0x15 + RTM_DELADDRLABEL = 0x49 + RTM_DELCHAIN = 0x65 + RTM_DELLINK = 0x11 + RTM_DELMDB = 0x55 + RTM_DELNEIGH = 0x1d + RTM_DELNETCONF = 0x51 + RTM_DELNSID = 0x59 + RTM_DELQDISC = 0x25 + RTM_DELROUTE = 0x19 + RTM_DELRULE = 0x21 + RTM_DELTCLASS = 0x29 + RTM_DELTFILTER = 0x2d + RTM_F_CLONED = 0x200 + RTM_F_EQUALIZE = 0x400 + RTM_F_FIB_MATCH = 0x2000 + RTM_F_LOOKUP_TABLE = 0x1000 + RTM_F_NOTIFY = 0x100 + RTM_F_PREFIX = 0x800 + RTM_GETACTION = 0x32 + RTM_GETADDR = 0x16 + RTM_GETADDRLABEL = 0x4a + RTM_GETANYCAST = 0x3e + RTM_GETCHAIN = 0x66 + RTM_GETDCB = 0x4e + RTM_GETLINK = 0x12 + RTM_GETMDB = 0x56 + RTM_GETMULTICAST = 0x3a + RTM_GETNEIGH = 0x1e + RTM_GETNEIGHTBL = 0x42 + RTM_GETNETCONF = 0x52 + RTM_GETNSID = 0x5a + RTM_GETQDISC = 0x26 + RTM_GETROUTE = 0x1a + RTM_GETRULE = 0x22 + RTM_GETSTATS = 0x5e + RTM_GETTCLASS = 0x2a + RTM_GETTFILTER = 0x2e + RTM_MAX = 0x67 + RTM_NEWACTION = 0x30 + RTM_NEWADDR = 0x14 + RTM_NEWADDRLABEL = 0x48 + RTM_NEWCACHEREPORT = 0x60 + RTM_NEWCHAIN = 0x64 + RTM_NEWLINK = 0x10 + RTM_NEWMDB = 0x54 + RTM_NEWNDUSEROPT = 0x44 + RTM_NEWNEIGH = 0x1c + RTM_NEWNEIGHTBL = 0x40 + RTM_NEWNETCONF = 0x50 + RTM_NEWNSID = 0x58 + RTM_NEWPREFIX = 0x34 + RTM_NEWQDISC = 0x24 + RTM_NEWROUTE = 0x18 + RTM_NEWRULE = 0x20 + RTM_NEWSTATS = 0x5c + RTM_NEWTCLASS = 0x28 + RTM_NEWTFILTER = 0x2c + RTM_NR_FAMILIES = 0x16 + RTM_NR_MSGTYPES = 0x58 + RTM_SETDCB = 0x4f + RTM_SETLINK = 0x13 + RTM_SETNEIGHTBL = 0x43 + RTNH_ALIGNTO = 0x4 + RTNH_COMPARE_MASK = 0x19 + RTNH_F_DEAD = 0x1 + RTNH_F_LINKDOWN = 0x10 + RTNH_F_OFFLOAD = 0x8 + RTNH_F_ONLINK = 0x4 + RTNH_F_PERVASIVE = 0x2 + RTNH_F_UNRESOLVED = 0x20 + RTN_MAX = 0xb + RTPROT_BABEL = 0x2a + RTPROT_BGP = 0xba + RTPROT_BIRD = 0xc + RTPROT_BOOT = 0x3 + RTPROT_DHCP = 0x10 + RTPROT_DNROUTED = 0xd + RTPROT_EIGRP = 0xc0 + RTPROT_GATED = 0x8 + RTPROT_ISIS = 0xbb + RTPROT_KERNEL = 0x2 + RTPROT_MROUTED = 0x11 + RTPROT_MRT = 0xa + RTPROT_NTK = 0xf + RTPROT_OSPF = 0xbc + RTPROT_RA = 0x9 + RTPROT_REDIRECT = 0x1 + RTPROT_RIP = 0xbd + RTPROT_STATIC = 0x4 + RTPROT_UNSPEC = 0x0 + RTPROT_XORP = 0xe + RTPROT_ZEBRA = 0xb + RT_CLASS_DEFAULT = 0xfd + RT_CLASS_LOCAL = 0xff + RT_CLASS_MAIN = 0xfe + RT_CLASS_MAX = 0xff + RT_CLASS_UNSPEC = 0x0 + RUSAGE_CHILDREN = -0x1 + RUSAGE_SELF = 0x0 + RUSAGE_THREAD = 0x1 + SCM_CREDENTIALS = 0x2 + SCM_RIGHTS = 0x1 + SCM_TIMESTAMP = 0x1d + SCM_TIMESTAMPING = 0x25 + SCM_TIMESTAMPING_OPT_STATS = 0x36 + SCM_TIMESTAMPING_PKTINFO = 0x3a + SCM_TIMESTAMPNS = 0x23 + SCM_TXTIME = 0x3d + SCM_WIFI_STATUS = 0x29 + SC_LOG_FLUSH = 0x100000 + SECCOMP_MODE_DISABLED = 0x0 + SECCOMP_MODE_FILTER = 0x2 + SECCOMP_MODE_STRICT = 0x1 + SECURITYFS_MAGIC = 0x73636673 + SELINUX_MAGIC = 0xf97cff8c + SFD_CLOEXEC = 0x80000 + SFD_NONBLOCK = 0x800 + SHUT_RD = 0x0 + SHUT_RDWR = 0x2 + SHUT_WR = 0x1 + SIOCADDDLCI = 0x8980 + SIOCADDMULTI = 0x8931 + SIOCADDRT = 0x890b + SIOCATMARK = 0x8905 + SIOCBONDCHANGEACTIVE = 0x8995 + SIOCBONDENSLAVE = 0x8990 + SIOCBONDINFOQUERY = 0x8994 + SIOCBONDRELEASE = 0x8991 + SIOCBONDSETHWADDR = 0x8992 + SIOCBONDSLAVEINFOQUERY = 0x8993 + SIOCBRADDBR = 0x89a0 + SIOCBRADDIF = 0x89a2 + SIOCBRDELBR = 0x89a1 + SIOCBRDELIF = 0x89a3 + SIOCDARP = 0x8953 + SIOCDELDLCI = 0x8981 + SIOCDELMULTI = 0x8932 + SIOCDELRT = 0x890c + SIOCDEVPRIVATE = 0x89f0 + SIOCDIFADDR = 0x8936 + SIOCDRARP = 0x8960 + SIOCETHTOOL = 0x8946 + SIOCGARP = 0x8954 + SIOCGHWTSTAMP = 0x89b1 + SIOCGIFADDR = 0x8915 + SIOCGIFBR = 0x8940 + SIOCGIFBRDADDR = 0x8919 + SIOCGIFCONF = 0x8912 + SIOCGIFCOUNT = 0x8938 + SIOCGIFDSTADDR = 0x8917 + SIOCGIFENCAP = 0x8925 + SIOCGIFFLAGS = 0x8913 + SIOCGIFHWADDR = 0x8927 + SIOCGIFINDEX = 0x8933 + SIOCGIFMAP = 0x8970 + SIOCGIFMEM = 0x891f + SIOCGIFMETRIC = 0x891d + SIOCGIFMTU = 0x8921 + SIOCGIFNAME = 0x8910 + SIOCGIFNETMASK = 0x891b + SIOCGIFPFLAGS = 0x8935 + SIOCGIFSLAVE = 0x8929 + SIOCGIFTXQLEN = 0x8942 + SIOCGIFVLAN = 0x8982 + SIOCGMIIPHY = 0x8947 + SIOCGMIIREG = 0x8948 + SIOCGPGRP = 0x8904 + SIOCGPPPCSTATS = 0x89f2 + SIOCGPPPSTATS = 0x89f0 + SIOCGPPPVER = 0x89f1 + SIOCGRARP = 0x8961 + SIOCGSKNS = 0x894c + SIOCGSTAMP = 0x8906 + SIOCGSTAMPNS = 0x8907 + SIOCINQ = 0x541b + SIOCOUTQ = 0x5411 + SIOCOUTQNSD = 0x894b + SIOCPROTOPRIVATE = 0x89e0 + SIOCRTMSG = 0x890d + SIOCSARP = 0x8955 + SIOCSHWTSTAMP = 0x89b0 + SIOCSIFADDR = 0x8916 + SIOCSIFBR = 0x8941 + SIOCSIFBRDADDR = 0x891a + SIOCSIFDSTADDR = 0x8918 + SIOCSIFENCAP = 0x8926 + SIOCSIFFLAGS = 0x8914 + SIOCSIFHWADDR = 0x8924 + SIOCSIFHWBROADCAST = 0x8937 + SIOCSIFLINK = 0x8911 + SIOCSIFMAP = 0x8971 + SIOCSIFMEM = 0x8920 + SIOCSIFMETRIC = 0x891e + SIOCSIFMTU = 0x8922 + SIOCSIFNAME = 0x8923 + SIOCSIFNETMASK = 0x891c + SIOCSIFPFLAGS = 0x8934 + SIOCSIFSLAVE = 0x8930 + SIOCSIFTXQLEN = 0x8943 + SIOCSIFVLAN = 0x8983 + SIOCSMIIREG = 0x8949 + SIOCSPGRP = 0x8902 + SIOCSRARP = 0x8962 + SIOCWANDEV = 0x894a + SMACK_MAGIC = 0x43415d53 + SMART_AUTOSAVE = 0xd2 + SMART_AUTO_OFFLINE = 0xdb + SMART_DISABLE = 0xd9 + SMART_ENABLE = 0xd8 + SMART_HCYL_PASS = 0xc2 + SMART_IMMEDIATE_OFFLINE = 0xd4 + SMART_LCYL_PASS = 0x4f + SMART_READ_LOG_SECTOR = 0xd5 + SMART_READ_THRESHOLDS = 0xd1 + SMART_READ_VALUES = 0xd0 + SMART_SAVE = 0xd3 + SMART_STATUS = 0xda + SMART_WRITE_LOG_SECTOR = 0xd6 + SMART_WRITE_THRESHOLDS = 0xd7 + SMB_SUPER_MAGIC = 0x517b + SOCKFS_MAGIC = 0x534f434b + SOCK_CLOEXEC = 0x80000 + SOCK_DCCP = 0x6 + SOCK_DGRAM = 0x2 + SOCK_IOC_TYPE = 0x89 + SOCK_NONBLOCK = 0x800 + SOCK_PACKET = 0xa + SOCK_RAW = 0x3 + SOCK_RDM = 0x4 + SOCK_SEQPACKET = 0x5 + SOCK_STREAM = 0x1 + SOL_AAL = 0x109 + SOL_ALG = 0x117 + SOL_ATM = 0x108 + SOL_CAIF = 0x116 + SOL_CAN_BASE = 0x64 + SOL_DCCP = 0x10d + SOL_DECNET = 0x105 + SOL_ICMPV6 = 0x3a + SOL_IP = 0x0 + SOL_IPV6 = 0x29 + SOL_IRDA = 0x10a + SOL_IUCV = 0x115 + SOL_KCM = 0x119 + SOL_LLC = 0x10c + SOL_NETBEUI = 0x10b + SOL_NETLINK = 0x10e + SOL_NFC = 0x118 + SOL_PACKET = 0x107 + SOL_PNPIPE = 0x113 + SOL_PPPOL2TP = 0x111 + SOL_RAW = 0xff + SOL_RDS = 0x114 + SOL_RXRPC = 0x110 + SOL_SOCKET = 0x1 + SOL_TCP = 0x6 + SOL_TIPC = 0x10f + SOL_TLS = 0x11a + SOL_X25 = 0x106 + SOL_XDP = 0x11b + SOMAXCONN = 0x80 + SO_ACCEPTCONN = 0x1e + SO_ATTACH_BPF = 0x32 + SO_ATTACH_FILTER = 0x1a + SO_ATTACH_REUSEPORT_CBPF = 0x33 + SO_ATTACH_REUSEPORT_EBPF = 0x34 + SO_BINDTODEVICE = 0x19 + SO_BPF_EXTENSIONS = 0x30 + SO_BROADCAST = 0x6 + SO_BSDCOMPAT = 0xe + SO_BUSY_POLL = 0x2e + SO_CNX_ADVICE = 0x35 + SO_COOKIE = 0x39 + SO_DEBUG = 0x1 + SO_DETACH_BPF = 0x1b + SO_DETACH_FILTER = 0x1b + SO_DOMAIN = 0x27 + SO_DONTROUTE = 0x5 + SO_EE_CODE_TXTIME_INVALID_PARAM = 0x1 + SO_EE_CODE_TXTIME_MISSED = 0x2 + SO_EE_CODE_ZEROCOPY_COPIED = 0x1 + SO_EE_ORIGIN_ICMP = 0x2 + SO_EE_ORIGIN_ICMP6 = 0x3 + SO_EE_ORIGIN_LOCAL = 0x1 + SO_EE_ORIGIN_NONE = 0x0 + SO_EE_ORIGIN_TIMESTAMPING = 0x4 + SO_EE_ORIGIN_TXSTATUS = 0x4 + SO_EE_ORIGIN_TXTIME = 0x6 + SO_EE_ORIGIN_ZEROCOPY = 0x5 + SO_ERROR = 0x4 + SO_GET_FILTER = 0x1a + SO_INCOMING_CPU = 0x31 + SO_INCOMING_NAPI_ID = 0x38 + SO_KEEPALIVE = 0x9 + SO_LINGER = 0xd + SO_LOCK_FILTER = 0x2c + SO_MARK = 0x24 + SO_MAX_PACING_RATE = 0x2f + SO_MEMINFO = 0x37 + SO_NOFCS = 0x2b + SO_NO_CHECK = 0xb + SO_OOBINLINE = 0xa + SO_PASSCRED = 0x10 + SO_PASSSEC = 0x22 + SO_PEEK_OFF = 0x2a + SO_PEERCRED = 0x11 + SO_PEERGROUPS = 0x3b + SO_PEERNAME = 0x1c + SO_PEERSEC = 0x1f + SO_PRIORITY = 0xc + SO_PROTOCOL = 0x26 + SO_RCVBUF = 0x8 + SO_RCVBUFFORCE = 0x21 + SO_RCVLOWAT = 0x12 + SO_RCVTIMEO = 0x14 + SO_REUSEADDR = 0x2 + SO_REUSEPORT = 0xf + SO_RXQ_OVFL = 0x28 + SO_SECURITY_AUTHENTICATION = 0x16 + SO_SECURITY_ENCRYPTION_NETWORK = 0x18 + SO_SECURITY_ENCRYPTION_TRANSPORT = 0x17 + SO_SELECT_ERR_QUEUE = 0x2d + SO_SNDBUF = 0x7 + SO_SNDBUFFORCE = 0x20 + SO_SNDLOWAT = 0x13 + SO_SNDTIMEO = 0x15 + SO_TIMESTAMP = 0x1d + SO_TIMESTAMPING = 0x25 + SO_TIMESTAMPNS = 0x23 + SO_TXTIME = 0x3d + SO_TYPE = 0x3 + SO_VM_SOCKETS_BUFFER_MAX_SIZE = 0x2 + SO_VM_SOCKETS_BUFFER_MIN_SIZE = 0x1 + SO_VM_SOCKETS_BUFFER_SIZE = 0x0 + SO_VM_SOCKETS_CONNECT_TIMEOUT = 0x6 + SO_VM_SOCKETS_NONBLOCK_TXRX = 0x7 + SO_VM_SOCKETS_PEER_HOST_VM_ID = 0x3 + SO_VM_SOCKETS_TRUSTED = 0x5 + SO_WIFI_STATUS = 0x29 + SO_ZEROCOPY = 0x3c + SPLICE_F_GIFT = 0x8 + SPLICE_F_MORE = 0x4 + SPLICE_F_MOVE = 0x1 + SPLICE_F_NONBLOCK = 0x2 + SQUASHFS_MAGIC = 0x73717368 + STACK_END_MAGIC = 0x57ac6e9d + STATX_ALL = 0xfff + STATX_ATIME = 0x20 + STATX_ATTR_APPEND = 0x20 + STATX_ATTR_AUTOMOUNT = 0x1000 + STATX_ATTR_COMPRESSED = 0x4 + STATX_ATTR_ENCRYPTED = 0x800 + STATX_ATTR_IMMUTABLE = 0x10 + STATX_ATTR_NODUMP = 0x40 + STATX_BASIC_STATS = 0x7ff + STATX_BLOCKS = 0x400 + STATX_BTIME = 0x800 + STATX_CTIME = 0x80 + STATX_GID = 0x10 + STATX_INO = 0x100 + STATX_MODE = 0x2 + STATX_MTIME = 0x40 + STATX_NLINK = 0x4 + STATX_SIZE = 0x200 + STATX_TYPE = 0x1 + STATX_UID = 0x8 + STATX__RESERVED = 0x80000000 + SYNC_FILE_RANGE_WAIT_AFTER = 0x4 + SYNC_FILE_RANGE_WAIT_BEFORE = 0x1 + SYNC_FILE_RANGE_WRITE = 0x2 + SYSFS_MAGIC = 0x62656572 + S_BLKSIZE = 0x200 + S_IEXEC = 0x40 + S_IFBLK = 0x6000 + S_IFCHR = 0x2000 + S_IFDIR = 0x4000 + S_IFIFO = 0x1000 + S_IFLNK = 0xa000 + S_IFMT = 0xf000 + S_IFREG = 0x8000 + S_IFSOCK = 0xc000 + S_IREAD = 0x100 + S_IRGRP = 0x20 + S_IROTH = 0x4 + S_IRUSR = 0x100 + S_IRWXG = 0x38 + S_IRWXO = 0x7 + S_IRWXU = 0x1c0 + S_ISGID = 0x400 + S_ISUID = 0x800 + S_ISVTX = 0x200 + S_IWGRP = 0x10 + S_IWOTH = 0x2 + S_IWRITE = 0x80 + S_IWUSR = 0x80 + S_IXGRP = 0x8 + S_IXOTH = 0x1 + S_IXUSR = 0x40 + TAB0 = 0x0 + TAB1 = 0x800 + TAB2 = 0x1000 + TAB3 = 0x1800 + TABDLY = 0x1800 + TASKSTATS_CMD_ATTR_MAX = 0x4 + TASKSTATS_CMD_MAX = 0x2 + TASKSTATS_GENL_NAME = "TASKSTATS" + TASKSTATS_GENL_VERSION = 0x1 + TASKSTATS_TYPE_MAX = 0x6 + TASKSTATS_VERSION = 0x9 + TCFLSH = 0x540b + TCGETA = 0x5405 + TCGETS = 0x5401 + TCGETS2 = 0x802c542a + TCGETX = 0x5432 + TCIFLUSH = 0x0 + TCIOFF = 0x2 + TCIOFLUSH = 0x2 + TCION = 0x3 + TCOFLUSH = 0x1 + TCOOFF = 0x0 + TCOON = 0x1 + TCP_CC_INFO = 0x1a + TCP_CM_INQ = 0x24 + TCP_CONGESTION = 0xd + TCP_COOKIE_IN_ALWAYS = 0x1 + TCP_COOKIE_MAX = 0x10 + TCP_COOKIE_MIN = 0x8 + TCP_COOKIE_OUT_NEVER = 0x2 + TCP_COOKIE_PAIR_SIZE = 0x20 + TCP_COOKIE_TRANSACTIONS = 0xf + TCP_CORK = 0x3 + TCP_DEFER_ACCEPT = 0x9 + TCP_FASTOPEN = 0x17 + TCP_FASTOPEN_CONNECT = 0x1e + TCP_FASTOPEN_KEY = 0x21 + TCP_FASTOPEN_NO_COOKIE = 0x22 + TCP_INFO = 0xb + TCP_INQ = 0x24 + TCP_KEEPCNT = 0x6 + TCP_KEEPIDLE = 0x4 + TCP_KEEPINTVL = 0x5 + TCP_LINGER2 = 0x8 + TCP_MAXSEG = 0x2 + TCP_MAXWIN = 0xffff + TCP_MAX_WINSHIFT = 0xe + TCP_MD5SIG = 0xe + TCP_MD5SIG_EXT = 0x20 + TCP_MD5SIG_FLAG_PREFIX = 0x1 + TCP_MD5SIG_MAXKEYLEN = 0x50 + TCP_MSS = 0x200 + TCP_MSS_DEFAULT = 0x218 + TCP_MSS_DESIRED = 0x4c4 + TCP_NODELAY = 0x1 + TCP_NOTSENT_LOWAT = 0x19 + TCP_QUEUE_SEQ = 0x15 + TCP_QUICKACK = 0xc + TCP_REPAIR = 0x13 + TCP_REPAIR_OFF = 0x0 + TCP_REPAIR_OFF_NO_WP = -0x1 + TCP_REPAIR_ON = 0x1 + TCP_REPAIR_OPTIONS = 0x16 + TCP_REPAIR_QUEUE = 0x14 + TCP_REPAIR_WINDOW = 0x1d + TCP_SAVED_SYN = 0x1c + TCP_SAVE_SYN = 0x1b + TCP_SYNCNT = 0x7 + TCP_S_DATA_IN = 0x4 + TCP_S_DATA_OUT = 0x8 + TCP_THIN_DUPACK = 0x11 + TCP_THIN_LINEAR_TIMEOUTS = 0x10 + TCP_TIMESTAMP = 0x18 + TCP_ULP = 0x1f + TCP_USER_TIMEOUT = 0x12 + TCP_WINDOW_CLAMP = 0xa + TCP_ZEROCOPY_RECEIVE = 0x23 + TCSAFLUSH = 0x2 + TCSBRK = 0x5409 + TCSBRKP = 0x5425 + TCSETA = 0x5406 + TCSETAF = 0x5408 + TCSETAW = 0x5407 + TCSETS = 0x5402 + TCSETS2 = 0x402c542b + TCSETSF = 0x5404 + TCSETSF2 = 0x402c542d + TCSETSW = 0x5403 + TCSETSW2 = 0x402c542c + TCSETX = 0x5433 + TCSETXF = 0x5434 + TCSETXW = 0x5435 + TCXONC = 0x540a + TIMER_ABSTIME = 0x1 + TIOCCBRK = 0x5428 + TIOCCONS = 0x541d + TIOCEXCL = 0x540c + TIOCGDEV = 0x80045432 + TIOCGETD = 0x5424 + TIOCGEXCL = 0x80045440 + TIOCGICOUNT = 0x545d + TIOCGISO7816 = 0x80285442 + TIOCGLCKTRMIOS = 0x5456 + TIOCGPGRP = 0x540f + TIOCGPKT = 0x80045438 + TIOCGPTLCK = 0x80045439 + TIOCGPTN = 0x80045430 + TIOCGPTPEER = 0x5441 + TIOCGRS485 = 0x542e + TIOCGSERIAL = 0x541e + TIOCGSID = 0x5429 + TIOCGSOFTCAR = 0x5419 + TIOCGWINSZ = 0x5413 + TIOCINQ = 0x541b + TIOCLINUX = 0x541c + TIOCMBIC = 0x5417 + TIOCMBIS = 0x5416 + TIOCMGET = 0x5415 + TIOCMIWAIT = 0x545c + TIOCMSET = 0x5418 + TIOCM_CAR = 0x40 + TIOCM_CD = 0x40 + TIOCM_CTS = 0x20 + TIOCM_DSR = 0x100 + TIOCM_DTR = 0x2 + TIOCM_LE = 0x1 + TIOCM_RI = 0x80 + TIOCM_RNG = 0x80 + TIOCM_RTS = 0x4 + TIOCM_SR = 0x10 + TIOCM_ST = 0x8 + TIOCNOTTY = 0x5422 + TIOCNXCL = 0x540d + TIOCOUTQ = 0x5411 + TIOCPKT = 0x5420 + TIOCPKT_DATA = 0x0 + TIOCPKT_DOSTOP = 0x20 + TIOCPKT_FLUSHREAD = 0x1 + TIOCPKT_FLUSHWRITE = 0x2 + TIOCPKT_IOCTL = 0x40 + TIOCPKT_NOSTOP = 0x10 + TIOCPKT_START = 0x8 + TIOCPKT_STOP = 0x4 + TIOCSBRK = 0x5427 + TIOCSCTTY = 0x540e + TIOCSERCONFIG = 0x5453 + TIOCSERGETLSR = 0x5459 + TIOCSERGETMULTI = 0x545a + TIOCSERGSTRUCT = 0x5458 + TIOCSERGWILD = 0x5454 + TIOCSERSETMULTI = 0x545b + TIOCSERSWILD = 0x5455 + TIOCSER_TEMT = 0x1 + TIOCSETD = 0x5423 + TIOCSIG = 0x40045436 + TIOCSISO7816 = 0xc0285443 + TIOCSLCKTRMIOS = 0x5457 + TIOCSPGRP = 0x5410 + TIOCSPTLCK = 0x40045431 + TIOCSRS485 = 0x542f + TIOCSSERIAL = 0x541f + TIOCSSOFTCAR = 0x541a + TIOCSTI = 0x5412 + TIOCSWINSZ = 0x5414 + TIOCVHANGUP = 0x5437 + TMPFS_MAGIC = 0x1021994 + TOSTOP = 0x100 + TPACKET_ALIGNMENT = 0x10 + TPACKET_HDRLEN = 0x34 + TP_STATUS_AVAILABLE = 0x0 + TP_STATUS_BLK_TMO = 0x20 + TP_STATUS_COPY = 0x2 + TP_STATUS_CSUMNOTREADY = 0x8 + TP_STATUS_CSUM_VALID = 0x80 + TP_STATUS_KERNEL = 0x0 + TP_STATUS_LOSING = 0x4 + TP_STATUS_SENDING = 0x2 + TP_STATUS_SEND_REQUEST = 0x1 + TP_STATUS_TS_RAW_HARDWARE = -0x80000000 + TP_STATUS_TS_SOFTWARE = 0x20000000 + TP_STATUS_TS_SYS_HARDWARE = 0x40000000 + TP_STATUS_USER = 0x1 + TP_STATUS_VLAN_TPID_VALID = 0x40 + TP_STATUS_VLAN_VALID = 0x10 + TP_STATUS_WRONG_FORMAT = 0x4 + TRACEFS_MAGIC = 0x74726163 + TS_COMM_LEN = 0x20 + TUNATTACHFILTER = 0x401054d5 + TUNDETACHFILTER = 0x401054d6 + TUNGETFEATURES = 0x800454cf + TUNGETFILTER = 0x801054db + TUNGETIFF = 0x800454d2 + TUNGETSNDBUF = 0x800454d3 + TUNGETVNETBE = 0x800454df + TUNGETVNETHDRSZ = 0x800454d7 + TUNGETVNETLE = 0x800454dd + TUNSETDEBUG = 0x400454c9 + TUNSETFILTEREBPF = 0x800454e1 + TUNSETGROUP = 0x400454ce + TUNSETIFF = 0x400454ca + TUNSETIFINDEX = 0x400454da + TUNSETLINK = 0x400454cd + TUNSETNOCSUM = 0x400454c8 + TUNSETOFFLOAD = 0x400454d0 + TUNSETOWNER = 0x400454cc + TUNSETPERSIST = 0x400454cb + TUNSETQUEUE = 0x400454d9 + TUNSETSNDBUF = 0x400454d4 + TUNSETSTEERINGEBPF = 0x800454e0 + TUNSETTXFILTER = 0x400454d1 + TUNSETVNETBE = 0x400454de + TUNSETVNETHDRSZ = 0x400454d8 + TUNSETVNETLE = 0x400454dc + UBI_IOCATT = 0x40186f40 + UBI_IOCDET = 0x40046f41 + UBI_IOCEBCH = 0x40044f02 + UBI_IOCEBER = 0x40044f01 + UBI_IOCEBISMAP = 0x80044f05 + UBI_IOCEBMAP = 0x40084f03 + UBI_IOCEBUNMAP = 0x40044f04 + UBI_IOCMKVOL = 0x40986f00 + UBI_IOCRMVOL = 0x40046f01 + UBI_IOCRNVOL = 0x51106f03 + UBI_IOCRSVOL = 0x400c6f02 + UBI_IOCSETVOLPROP = 0x40104f06 + UBI_IOCVOLCRBLK = 0x40804f07 + UBI_IOCVOLRMBLK = 0x4f08 + UBI_IOCVOLUP = 0x40084f00 + UDF_SUPER_MAGIC = 0x15013346 + UMOUNT_NOFOLLOW = 0x8 + USBDEVICE_SUPER_MAGIC = 0x9fa2 + UTIME_NOW = 0x3fffffff + UTIME_OMIT = 0x3ffffffe + V9FS_MAGIC = 0x1021997 + VDISCARD = 0xd + VEOF = 0x4 + VEOL = 0xb + VEOL2 = 0x10 + VERASE = 0x2 + VINTR = 0x0 + VKILL = 0x3 + VLNEXT = 0xf + VMADDR_CID_ANY = 0xffffffff + VMADDR_CID_HOST = 0x2 + VMADDR_CID_HYPERVISOR = 0x0 + VMADDR_CID_RESERVED = 0x1 + VMADDR_PORT_ANY = 0xffffffff + VMIN = 0x6 + VM_SOCKETS_INVALID_VERSION = 0xffffffff + VQUIT = 0x1 + VREPRINT = 0xc + VSTART = 0x8 + VSTOP = 0x9 + VSUSP = 0xa + VSWTC = 0x7 + VT0 = 0x0 + VT1 = 0x4000 + VTDLY = 0x4000 + VTIME = 0x5 + VWERASE = 0xe + WALL = 0x40000000 + WCLONE = 0x80000000 + WCONTINUED = 0x8 + WDIOC_GETBOOTSTATUS = 0x80045702 + WDIOC_GETPRETIMEOUT = 0x80045709 + WDIOC_GETSTATUS = 0x80045701 + WDIOC_GETSUPPORT = 0x80285700 + WDIOC_GETTEMP = 0x80045703 + WDIOC_GETTIMELEFT = 0x8004570a + WDIOC_GETTIMEOUT = 0x80045707 + WDIOC_KEEPALIVE = 0x80045705 + WDIOC_SETOPTIONS = 0x80045704 + WDIOC_SETPRETIMEOUT = 0xc0045708 + WDIOC_SETTIMEOUT = 0xc0045706 + WEXITED = 0x4 + WIN_ACKMEDIACHANGE = 0xdb + WIN_CHECKPOWERMODE1 = 0xe5 + WIN_CHECKPOWERMODE2 = 0x98 + WIN_DEVICE_RESET = 0x8 + WIN_DIAGNOSE = 0x90 + WIN_DOORLOCK = 0xde + WIN_DOORUNLOCK = 0xdf + WIN_DOWNLOAD_MICROCODE = 0x92 + WIN_FLUSH_CACHE = 0xe7 + WIN_FLUSH_CACHE_EXT = 0xea + WIN_FORMAT = 0x50 + WIN_GETMEDIASTATUS = 0xda + WIN_IDENTIFY = 0xec + WIN_IDENTIFY_DMA = 0xee + WIN_IDLEIMMEDIATE = 0xe1 + WIN_INIT = 0x60 + WIN_MEDIAEJECT = 0xed + WIN_MULTREAD = 0xc4 + WIN_MULTREAD_EXT = 0x29 + WIN_MULTWRITE = 0xc5 + WIN_MULTWRITE_EXT = 0x39 + WIN_NOP = 0x0 + WIN_PACKETCMD = 0xa0 + WIN_PIDENTIFY = 0xa1 + WIN_POSTBOOT = 0xdc + WIN_PREBOOT = 0xdd + WIN_QUEUED_SERVICE = 0xa2 + WIN_READ = 0x20 + WIN_READDMA = 0xc8 + WIN_READDMA_EXT = 0x25 + WIN_READDMA_ONCE = 0xc9 + WIN_READDMA_QUEUED = 0xc7 + WIN_READDMA_QUEUED_EXT = 0x26 + WIN_READ_BUFFER = 0xe4 + WIN_READ_EXT = 0x24 + WIN_READ_LONG = 0x22 + WIN_READ_LONG_ONCE = 0x23 + WIN_READ_NATIVE_MAX = 0xf8 + WIN_READ_NATIVE_MAX_EXT = 0x27 + WIN_READ_ONCE = 0x21 + WIN_RECAL = 0x10 + WIN_RESTORE = 0x10 + WIN_SECURITY_DISABLE = 0xf6 + WIN_SECURITY_ERASE_PREPARE = 0xf3 + WIN_SECURITY_ERASE_UNIT = 0xf4 + WIN_SECURITY_FREEZE_LOCK = 0xf5 + WIN_SECURITY_SET_PASS = 0xf1 + WIN_SECURITY_UNLOCK = 0xf2 + WIN_SEEK = 0x70 + WIN_SETFEATURES = 0xef + WIN_SETIDLE1 = 0xe3 + WIN_SETIDLE2 = 0x97 + WIN_SETMULT = 0xc6 + WIN_SET_MAX = 0xf9 + WIN_SET_MAX_EXT = 0x37 + WIN_SLEEPNOW1 = 0xe6 + WIN_SLEEPNOW2 = 0x99 + WIN_SMART = 0xb0 + WIN_SPECIFY = 0x91 + WIN_SRST = 0x8 + WIN_STANDBY = 0xe2 + WIN_STANDBY2 = 0x96 + WIN_STANDBYNOW1 = 0xe0 + WIN_STANDBYNOW2 = 0x94 + WIN_VERIFY = 0x40 + WIN_VERIFY_EXT = 0x42 + WIN_VERIFY_ONCE = 0x41 + WIN_WRITE = 0x30 + WIN_WRITEDMA = 0xca + WIN_WRITEDMA_EXT = 0x35 + WIN_WRITEDMA_ONCE = 0xcb + WIN_WRITEDMA_QUEUED = 0xcc + WIN_WRITEDMA_QUEUED_EXT = 0x36 + WIN_WRITE_BUFFER = 0xe8 + WIN_WRITE_EXT = 0x34 + WIN_WRITE_LONG = 0x32 + WIN_WRITE_LONG_ONCE = 0x33 + WIN_WRITE_ONCE = 0x31 + WIN_WRITE_SAME = 0xe9 + WIN_WRITE_VERIFY = 0x3c + WNOHANG = 0x1 + WNOTHREAD = 0x20000000 + WNOWAIT = 0x1000000 + WORDSIZE = 0x40 + WSTOPPED = 0x2 + WUNTRACED = 0x2 + XATTR_CREATE = 0x1 + XATTR_REPLACE = 0x2 + XCASE = 0x4 + XDP_COPY = 0x2 + XDP_FLAGS_DRV_MODE = 0x4 + XDP_FLAGS_HW_MODE = 0x8 + XDP_FLAGS_MASK = 0xf + XDP_FLAGS_MODES = 0xe + XDP_FLAGS_SKB_MODE = 0x2 + XDP_FLAGS_UPDATE_IF_NOEXIST = 0x1 + XDP_MMAP_OFFSETS = 0x1 + XDP_PGOFF_RX_RING = 0x0 + XDP_PGOFF_TX_RING = 0x80000000 + XDP_RX_RING = 0x2 + XDP_SHARED_UMEM = 0x1 + XDP_STATISTICS = 0x7 + XDP_TX_RING = 0x3 + XDP_UMEM_COMPLETION_RING = 0x6 + XDP_UMEM_FILL_RING = 0x5 + XDP_UMEM_PGOFF_COMPLETION_RING = 0x180000000 + XDP_UMEM_PGOFF_FILL_RING = 0x100000000 + XDP_UMEM_REG = 0x4 + XDP_ZEROCOPY = 0x4 + XENFS_SUPER_MAGIC = 0xabba1974 + XFS_SUPER_MAGIC = 0x58465342 + XTABS = 0x1800 + ZSMALLOC_MAGIC = 0x58295829 +) + +// Errors +const ( + E2BIG = syscall.Errno(0x7) + EACCES = syscall.Errno(0xd) + EADDRINUSE = syscall.Errno(0x62) + EADDRNOTAVAIL = syscall.Errno(0x63) + EADV = syscall.Errno(0x44) + EAFNOSUPPORT = syscall.Errno(0x61) + EAGAIN = syscall.Errno(0xb) + EALREADY = syscall.Errno(0x72) + EBADE = syscall.Errno(0x34) + EBADF = syscall.Errno(0x9) + EBADFD = syscall.Errno(0x4d) + EBADMSG = syscall.Errno(0x4a) + EBADR = syscall.Errno(0x35) + EBADRQC = syscall.Errno(0x38) + EBADSLT = syscall.Errno(0x39) + EBFONT = syscall.Errno(0x3b) + EBUSY = syscall.Errno(0x10) + ECANCELED = syscall.Errno(0x7d) + ECHILD = syscall.Errno(0xa) + ECHRNG = syscall.Errno(0x2c) + ECOMM = syscall.Errno(0x46) + ECONNABORTED = syscall.Errno(0x67) + ECONNREFUSED = syscall.Errno(0x6f) + ECONNRESET = syscall.Errno(0x68) + EDEADLK = syscall.Errno(0x23) + EDEADLOCK = syscall.Errno(0x23) + EDESTADDRREQ = syscall.Errno(0x59) + EDOM = syscall.Errno(0x21) + EDOTDOT = syscall.Errno(0x49) + EDQUOT = syscall.Errno(0x7a) + EEXIST = syscall.Errno(0x11) + EFAULT = syscall.Errno(0xe) + EFBIG = syscall.Errno(0x1b) + EHOSTDOWN = syscall.Errno(0x70) + EHOSTUNREACH = syscall.Errno(0x71) + EHWPOISON = syscall.Errno(0x85) + EIDRM = syscall.Errno(0x2b) + EILSEQ = syscall.Errno(0x54) + EINPROGRESS = syscall.Errno(0x73) + EINTR = syscall.Errno(0x4) + EINVAL = syscall.Errno(0x16) + EIO = syscall.Errno(0x5) + EISCONN = syscall.Errno(0x6a) + EISDIR = syscall.Errno(0x15) + EISNAM = syscall.Errno(0x78) + EKEYEXPIRED = syscall.Errno(0x7f) + EKEYREJECTED = syscall.Errno(0x81) + EKEYREVOKED = syscall.Errno(0x80) + EL2HLT = syscall.Errno(0x33) + EL2NSYNC = syscall.Errno(0x2d) + EL3HLT = syscall.Errno(0x2e) + EL3RST = syscall.Errno(0x2f) + ELIBACC = syscall.Errno(0x4f) + ELIBBAD = syscall.Errno(0x50) + ELIBEXEC = syscall.Errno(0x53) + ELIBMAX = syscall.Errno(0x52) + ELIBSCN = syscall.Errno(0x51) + ELNRNG = syscall.Errno(0x30) + ELOOP = syscall.Errno(0x28) + EMEDIUMTYPE = syscall.Errno(0x7c) + EMFILE = syscall.Errno(0x18) + EMLINK = syscall.Errno(0x1f) + EMSGSIZE = syscall.Errno(0x5a) + EMULTIHOP = syscall.Errno(0x48) + ENAMETOOLONG = syscall.Errno(0x24) + ENAVAIL = syscall.Errno(0x77) + ENETDOWN = syscall.Errno(0x64) + ENETRESET = syscall.Errno(0x66) + ENETUNREACH = syscall.Errno(0x65) + ENFILE = syscall.Errno(0x17) + ENOANO = syscall.Errno(0x37) + ENOBUFS = syscall.Errno(0x69) + ENOCSI = syscall.Errno(0x32) + ENODATA = syscall.Errno(0x3d) + ENODEV = syscall.Errno(0x13) + ENOENT = syscall.Errno(0x2) + ENOEXEC = syscall.Errno(0x8) + ENOKEY = syscall.Errno(0x7e) + ENOLCK = syscall.Errno(0x25) + ENOLINK = syscall.Errno(0x43) + ENOMEDIUM = syscall.Errno(0x7b) + ENOMEM = syscall.Errno(0xc) + ENOMSG = syscall.Errno(0x2a) + ENONET = syscall.Errno(0x40) + ENOPKG = syscall.Errno(0x41) + ENOPROTOOPT = syscall.Errno(0x5c) + ENOSPC = syscall.Errno(0x1c) + ENOSR = syscall.Errno(0x3f) + ENOSTR = syscall.Errno(0x3c) + ENOSYS = syscall.Errno(0x26) + ENOTBLK = syscall.Errno(0xf) + ENOTCONN = syscall.Errno(0x6b) + ENOTDIR = syscall.Errno(0x14) + ENOTEMPTY = syscall.Errno(0x27) + ENOTNAM = syscall.Errno(0x76) + ENOTRECOVERABLE = syscall.Errno(0x83) + ENOTSOCK = syscall.Errno(0x58) + ENOTSUP = syscall.Errno(0x5f) + ENOTTY = syscall.Errno(0x19) + ENOTUNIQ = syscall.Errno(0x4c) + ENXIO = syscall.Errno(0x6) + EOPNOTSUPP = syscall.Errno(0x5f) + EOVERFLOW = syscall.Errno(0x4b) + EOWNERDEAD = syscall.Errno(0x82) + EPERM = syscall.Errno(0x1) + EPFNOSUPPORT = syscall.Errno(0x60) + EPIPE = syscall.Errno(0x20) + EPROTO = syscall.Errno(0x47) + EPROTONOSUPPORT = syscall.Errno(0x5d) + EPROTOTYPE = syscall.Errno(0x5b) + ERANGE = syscall.Errno(0x22) + EREMCHG = syscall.Errno(0x4e) + EREMOTE = syscall.Errno(0x42) + EREMOTEIO = syscall.Errno(0x79) + ERESTART = syscall.Errno(0x55) + ERFKILL = syscall.Errno(0x84) + EROFS = syscall.Errno(0x1e) + ESHUTDOWN = syscall.Errno(0x6c) + ESOCKTNOSUPPORT = syscall.Errno(0x5e) + ESPIPE = syscall.Errno(0x1d) + ESRCH = syscall.Errno(0x3) + ESRMNT = syscall.Errno(0x45) + ESTALE = syscall.Errno(0x74) + ESTRPIPE = syscall.Errno(0x56) + ETIME = syscall.Errno(0x3e) + ETIMEDOUT = syscall.Errno(0x6e) + ETOOMANYREFS = syscall.Errno(0x6d) + ETXTBSY = syscall.Errno(0x1a) + EUCLEAN = syscall.Errno(0x75) + EUNATCH = syscall.Errno(0x31) + EUSERS = syscall.Errno(0x57) + EWOULDBLOCK = syscall.Errno(0xb) + EXDEV = syscall.Errno(0x12) + EXFULL = syscall.Errno(0x36) +) + +// Signals +const ( + SIGABRT = syscall.Signal(0x6) + SIGALRM = syscall.Signal(0xe) + SIGBUS = syscall.Signal(0x7) + SIGCHLD = syscall.Signal(0x11) + SIGCLD = syscall.Signal(0x11) + SIGCONT = syscall.Signal(0x12) + SIGFPE = syscall.Signal(0x8) + SIGHUP = syscall.Signal(0x1) + SIGILL = syscall.Signal(0x4) + SIGINT = syscall.Signal(0x2) + SIGIO = syscall.Signal(0x1d) + SIGIOT = syscall.Signal(0x6) + SIGKILL = syscall.Signal(0x9) + SIGPIPE = syscall.Signal(0xd) + SIGPOLL = syscall.Signal(0x1d) + SIGPROF = syscall.Signal(0x1b) + SIGPWR = syscall.Signal(0x1e) + SIGQUIT = syscall.Signal(0x3) + SIGSEGV = syscall.Signal(0xb) + SIGSTKFLT = syscall.Signal(0x10) + SIGSTOP = syscall.Signal(0x13) + SIGSYS = syscall.Signal(0x1f) + SIGTERM = syscall.Signal(0xf) + SIGTRAP = syscall.Signal(0x5) + SIGTSTP = syscall.Signal(0x14) + SIGTTIN = syscall.Signal(0x15) + SIGTTOU = syscall.Signal(0x16) + SIGURG = syscall.Signal(0x17) + SIGUSR1 = syscall.Signal(0xa) + SIGUSR2 = syscall.Signal(0xc) + SIGVTALRM = syscall.Signal(0x1a) + SIGWINCH = syscall.Signal(0x1c) + SIGXCPU = syscall.Signal(0x18) + SIGXFSZ = syscall.Signal(0x19) +) + +// Error table +var errorList = [...]struct { + num syscall.Errno + name string + desc string +}{ + {1, "EPERM", "operation not permitted"}, + {2, "ENOENT", "no such file or directory"}, + {3, "ESRCH", "no such process"}, + {4, "EINTR", "interrupted system call"}, + {5, "EIO", "input/output error"}, + {6, "ENXIO", "no such device or address"}, + {7, "E2BIG", "argument list too long"}, + {8, "ENOEXEC", "exec format error"}, + {9, "EBADF", "bad file descriptor"}, + {10, "ECHILD", "no child processes"}, + {11, "EAGAIN", "resource temporarily unavailable"}, + {12, "ENOMEM", "cannot allocate memory"}, + {13, "EACCES", "permission denied"}, + {14, "EFAULT", "bad address"}, + {15, "ENOTBLK", "block device required"}, + {16, "EBUSY", "device or resource busy"}, + {17, "EEXIST", "file exists"}, + {18, "EXDEV", "invalid cross-device link"}, + {19, "ENODEV", "no such device"}, + {20, "ENOTDIR", "not a directory"}, + {21, "EISDIR", "is a directory"}, + {22, "EINVAL", "invalid argument"}, + {23, "ENFILE", "too many open files in system"}, + {24, "EMFILE", "too many open files"}, + {25, "ENOTTY", "inappropriate ioctl for device"}, + {26, "ETXTBSY", "text file busy"}, + {27, "EFBIG", "file too large"}, + {28, "ENOSPC", "no space left on device"}, + {29, "ESPIPE", "illegal seek"}, + {30, "EROFS", "read-only file system"}, + {31, "EMLINK", "too many links"}, + {32, "EPIPE", "broken pipe"}, + {33, "EDOM", "numerical argument out of domain"}, + {34, "ERANGE", "numerical result out of range"}, + {35, "EDEADLK", "resource deadlock avoided"}, + {36, "ENAMETOOLONG", "file name too long"}, + {37, "ENOLCK", "no locks available"}, + {38, "ENOSYS", "function not implemented"}, + {39, "ENOTEMPTY", "directory not empty"}, + {40, "ELOOP", "too many levels of symbolic links"}, + {42, "ENOMSG", "no message of desired type"}, + {43, "EIDRM", "identifier removed"}, + {44, "ECHRNG", "channel number out of range"}, + {45, "EL2NSYNC", "level 2 not synchronized"}, + {46, "EL3HLT", "level 3 halted"}, + {47, "EL3RST", "level 3 reset"}, + {48, "ELNRNG", "link number out of range"}, + {49, "EUNATCH", "protocol driver not attached"}, + {50, "ENOCSI", "no CSI structure available"}, + {51, "EL2HLT", "level 2 halted"}, + {52, "EBADE", "invalid exchange"}, + {53, "EBADR", "invalid request descriptor"}, + {54, "EXFULL", "exchange full"}, + {55, "ENOANO", "no anode"}, + {56, "EBADRQC", "invalid request code"}, + {57, "EBADSLT", "invalid slot"}, + {59, "EBFONT", "bad font file format"}, + {60, "ENOSTR", "device not a stream"}, + {61, "ENODATA", "no data available"}, + {62, "ETIME", "timer expired"}, + {63, "ENOSR", "out of streams resources"}, + {64, "ENONET", "machine is not on the network"}, + {65, "ENOPKG", "package not installed"}, + {66, "EREMOTE", "object is remote"}, + {67, "ENOLINK", "link has been severed"}, + {68, "EADV", "advertise error"}, + {69, "ESRMNT", "srmount error"}, + {70, "ECOMM", "communication error on send"}, + {71, "EPROTO", "protocol error"}, + {72, "EMULTIHOP", "multihop attempted"}, + {73, "EDOTDOT", "RFS specific error"}, + {74, "EBADMSG", "bad message"}, + {75, "EOVERFLOW", "value too large for defined data type"}, + {76, "ENOTUNIQ", "name not unique on network"}, + {77, "EBADFD", "file descriptor in bad state"}, + {78, "EREMCHG", "remote address changed"}, + {79, "ELIBACC", "can not access a needed shared library"}, + {80, "ELIBBAD", "accessing a corrupted shared library"}, + {81, "ELIBSCN", ".lib section in a.out corrupted"}, + {82, "ELIBMAX", "attempting to link in too many shared libraries"}, + {83, "ELIBEXEC", "cannot exec a shared library directly"}, + {84, "EILSEQ", "invalid or incomplete multibyte or wide character"}, + {85, "ERESTART", "interrupted system call should be restarted"}, + {86, "ESTRPIPE", "streams pipe error"}, + {87, "EUSERS", "too many users"}, + {88, "ENOTSOCK", "socket operation on non-socket"}, + {89, "EDESTADDRREQ", "destination address required"}, + {90, "EMSGSIZE", "message too long"}, + {91, "EPROTOTYPE", "protocol wrong type for socket"}, + {92, "ENOPROTOOPT", "protocol not available"}, + {93, "EPROTONOSUPPORT", "protocol not supported"}, + {94, "ESOCKTNOSUPPORT", "socket type not supported"}, + {95, "ENOTSUP", "operation not supported"}, + {96, "EPFNOSUPPORT", "protocol family not supported"}, + {97, "EAFNOSUPPORT", "address family not supported by protocol"}, + {98, "EADDRINUSE", "address already in use"}, + {99, "EADDRNOTAVAIL", "cannot assign requested address"}, + {100, "ENETDOWN", "network is down"}, + {101, "ENETUNREACH", "network is unreachable"}, + {102, "ENETRESET", "network dropped connection on reset"}, + {103, "ECONNABORTED", "software caused connection abort"}, + {104, "ECONNRESET", "connection reset by peer"}, + {105, "ENOBUFS", "no buffer space available"}, + {106, "EISCONN", "transport endpoint is already connected"}, + {107, "ENOTCONN", "transport endpoint is not connected"}, + {108, "ESHUTDOWN", "cannot send after transport endpoint shutdown"}, + {109, "ETOOMANYREFS", "too many references: cannot splice"}, + {110, "ETIMEDOUT", "connection timed out"}, + {111, "ECONNREFUSED", "connection refused"}, + {112, "EHOSTDOWN", "host is down"}, + {113, "EHOSTUNREACH", "no route to host"}, + {114, "EALREADY", "operation already in progress"}, + {115, "EINPROGRESS", "operation now in progress"}, + {116, "ESTALE", "stale file handle"}, + {117, "EUCLEAN", "structure needs cleaning"}, + {118, "ENOTNAM", "not a XENIX named type file"}, + {119, "ENAVAIL", "no XENIX semaphores available"}, + {120, "EISNAM", "is a named type file"}, + {121, "EREMOTEIO", "remote I/O error"}, + {122, "EDQUOT", "disk quota exceeded"}, + {123, "ENOMEDIUM", "no medium found"}, + {124, "EMEDIUMTYPE", "wrong medium type"}, + {125, "ECANCELED", "operation canceled"}, + {126, "ENOKEY", "required key not available"}, + {127, "EKEYEXPIRED", "key has expired"}, + {128, "EKEYREVOKED", "key has been revoked"}, + {129, "EKEYREJECTED", "key was rejected by service"}, + {130, "EOWNERDEAD", "owner died"}, + {131, "ENOTRECOVERABLE", "state not recoverable"}, + {132, "ERFKILL", "operation not possible due to RF-kill"}, + {133, "EHWPOISON", "memory page has hardware error"}, +} + +// Signal table +var signalList = [...]struct { + num syscall.Signal + name string + desc string +}{ + {1, "SIGHUP", "hangup"}, + {2, "SIGINT", "interrupt"}, + {3, "SIGQUIT", "quit"}, + {4, "SIGILL", "illegal instruction"}, + {5, "SIGTRAP", "trace/breakpoint trap"}, + {6, "SIGABRT", "aborted"}, + {7, "SIGBUS", "bus error"}, + {8, "SIGFPE", "floating point exception"}, + {9, "SIGKILL", "killed"}, + {10, "SIGUSR1", "user defined signal 1"}, + {11, "SIGSEGV", "segmentation fault"}, + {12, "SIGUSR2", "user defined signal 2"}, + {13, "SIGPIPE", "broken pipe"}, + {14, "SIGALRM", "alarm clock"}, + {15, "SIGTERM", "terminated"}, + {16, "SIGSTKFLT", "stack fault"}, + {17, "SIGCHLD", "child exited"}, + {18, "SIGCONT", "continued"}, + {19, "SIGSTOP", "stopped (signal)"}, + {20, "SIGTSTP", "stopped"}, + {21, "SIGTTIN", "stopped (tty input)"}, + {22, "SIGTTOU", "stopped (tty output)"}, + {23, "SIGURG", "urgent I/O condition"}, + {24, "SIGXCPU", "CPU time limit exceeded"}, + {25, "SIGXFSZ", "file size limit exceeded"}, + {26, "SIGVTALRM", "virtual timer expired"}, + {27, "SIGPROF", "profiling timer expired"}, + {28, "SIGWINCH", "window changed"}, + {29, "SIGIO", "I/O possible"}, + {30, "SIGPWR", "power failure"}, + {31, "SIGSYS", "bad system call"}, +} diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go b/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go index fc304a68f6..7f7c2e3e2f 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go @@ -3,7 +3,7 @@ // +build s390x,linux -// Created by cgo -godefs - DO NOT EDIT +// Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs -- -Wall -Werror -static -I/tmp/include -fsigned-char _const.go package unix @@ -11,6 +11,11 @@ package unix import "syscall" const ( + AAFS_MAGIC = 0x5a3c69f0 + ADFS_SUPER_MAGIC = 0xadf5 + AFFS_SUPER_MAGIC = 0xadff + AFS_FS_MAGIC = 0x6b414653 + AFS_SUPER_MAGIC = 0x5346414f AF_ALG = 0x26 AF_APPLETALK = 0x5 AF_ASH = 0x12 @@ -36,7 +41,7 @@ const ( AF_KEY = 0xf AF_LLC = 0x1a AF_LOCAL = 0x1 - AF_MAX = 0x2c + AF_MAX = 0x2d AF_MPLS = 0x1c AF_NETBEUI = 0xd AF_NETLINK = 0x10 @@ -59,6 +64,7 @@ const ( AF_VSOCK = 0x28 AF_WANPIPE = 0x19 AF_X25 = 0x9 + AF_XDP = 0x2c ALG_OP_DECRYPT = 0x0 ALG_OP_ENCRYPT = 0x1 ALG_SET_AEAD_ASSOCLEN = 0x4 @@ -66,6 +72,7 @@ const ( ALG_SET_IV = 0x2 ALG_SET_KEY = 0x1 ALG_SET_OP = 0x3 + ANON_INODE_FS_MAGIC = 0x9041934 ARPHRD_6LOWPAN = 0x339 ARPHRD_ADAPT = 0x108 ARPHRD_APPLETLK = 0x8 @@ -121,6 +128,7 @@ const ( ARPHRD_PPP = 0x200 ARPHRD_PRONET = 0x4 ARPHRD_RAWHDLC = 0x206 + ARPHRD_RAWIP = 0x207 ARPHRD_ROSE = 0x10e ARPHRD_RSRVD = 0x104 ARPHRD_SIT = 0x308 @@ -132,6 +140,7 @@ const ( ARPHRD_VOID = 0xffff ARPHRD_VSOCKMON = 0x33a ARPHRD_X25 = 0x10f + AUTOFS_SUPER_MAGIC = 0x187 B0 = 0x0 B1000000 = 0x1008 B110 = 0x3 @@ -163,6 +172,9 @@ const ( B75 = 0x2 B921600 = 0x1007 B9600 = 0xd + BALLOON_KVM_MAGIC = 0x13661366 + BDEVFS_MAGIC = 0x62646576 + BINFMTFS_MAGIC = 0x42494e4d BLKBSZGET = 0x80081270 BLKBSZSET = 0x40081271 BLKFLSBUF = 0x1261 @@ -187,6 +199,7 @@ const ( BPF_AND = 0x50 BPF_B = 0x10 BPF_DIV = 0x30 + BPF_FS_MAGIC = 0xcafe4a11 BPF_H = 0x8 BPF_IMM = 0x0 BPF_IND = 0x40 @@ -228,6 +241,8 @@ const ( BS0 = 0x0 BS1 = 0x2000 BSDLY = 0x2000 + BTRFS_SUPER_MAGIC = 0x9123683e + BTRFS_TEST_MAGIC = 0x73727279 CAN_BCM = 0x2 CAN_EFF_FLAG = 0x80000000 CAN_EFF_ID_BITS = 0x1d @@ -251,6 +266,8 @@ const ( CBAUD = 0x100f CBAUDEX = 0x1000 CFLUSH = 0xf + CGROUP2_SUPER_MAGIC = 0x63677270 + CGROUP_SUPER_MAGIC = 0x27e0eb CIBAUD = 0x100f0000 CLOCAL = 0x800 CLOCK_BOOTTIME = 0x7 @@ -293,10 +310,12 @@ const ( CLONE_VFORK = 0x4000 CLONE_VM = 0x100 CMSPAR = 0x40000000 + CODA_SUPER_MAGIC = 0x73757245 CR0 = 0x0 CR1 = 0x200 CR2 = 0x400 CR3 = 0x600 + CRAMFS_MAGIC = 0x28cd3d45 CRDLY = 0x600 CREAD = 0x80 CRTSCTS = 0x80000000 @@ -311,6 +330,9 @@ const ( CSTOP = 0x13 CSTOPB = 0x40 CSUSP = 0x1a + DAXFS_MAGIC = 0x64646178 + DEBUGFS_MAGIC = 0x64626720 + DEVPTS_SUPER_MAGIC = 0x1cd1 DT_BLK = 0x6 DT_CHR = 0x2 DT_DIR = 0x4 @@ -327,9 +349,12 @@ const ( ECHOKE = 0x800 ECHONL = 0x40 ECHOPRT = 0x400 + ECRYPTFS_SUPER_MAGIC = 0xf15f EFD_CLOEXEC = 0x80000 EFD_NONBLOCK = 0x800 EFD_SEMAPHORE = 0x1 + EFIVARFS_MAGIC = 0xde5e81e4 + EFS_SUPER_MAGIC = 0x414a53 ENCODING_DEFAULT = 0x0 ENCODING_FM_MARK = 0x3 ENCODING_FM_SPACE = 0x4 @@ -390,6 +415,8 @@ const ( ETH_P_DSA = 0x1b ETH_P_ECONET = 0x18 ETH_P_EDSA = 0xdada + ETH_P_ERSPAN = 0x88be + ETH_P_ERSPAN2 = 0x22eb ETH_P_FCOE = 0x8906 ETH_P_FIP = 0x8914 ETH_P_HDLC = 0x19 @@ -398,6 +425,7 @@ const ( ETH_P_IEEE802154 = 0xf6 ETH_P_IEEEPUP = 0xa00 ETH_P_IEEEPUPAT = 0xa01 + ETH_P_IFE = 0xed3e ETH_P_IP = 0x800 ETH_P_IPV6 = 0x86dd ETH_P_IPX = 0x8137 @@ -408,11 +436,13 @@ const ( ETH_P_LOOP = 0x60 ETH_P_LOOPBACK = 0x9000 ETH_P_MACSEC = 0x88e5 + ETH_P_MAP = 0xf9 ETH_P_MOBITEX = 0x15 ETH_P_MPLS_MC = 0x8848 ETH_P_MPLS_UC = 0x8847 ETH_P_MVRP = 0x88f5 ETH_P_NCSI = 0x88f8 + ETH_P_NSH = 0x894f ETH_P_PAE = 0x888e ETH_P_PAUSE = 0x8808 ETH_P_PHONET = 0xf5 @@ -420,6 +450,7 @@ const ( ETH_P_PPP_DISC = 0x8863 ETH_P_PPP_MP = 0x8 ETH_P_PPP_SES = 0x8864 + ETH_P_PREAUTH = 0x88c7 ETH_P_PRP = 0x88fb ETH_P_PUP = 0x200 ETH_P_PUPAT = 0x201 @@ -440,9 +471,14 @@ const ( ETH_P_WCCP = 0x883e ETH_P_X25 = 0x805 ETH_P_XDSA = 0xf8 + EXABYTE_ENABLE_NEST = 0xf0 + EXT2_SUPER_MAGIC = 0xef53 + EXT3_SUPER_MAGIC = 0xef53 + EXT4_SUPER_MAGIC = 0xef53 EXTA = 0xe EXTB = 0xf EXTPROC = 0x10000 + F2FS_SUPER_MAGIC = 0xf2f52010 FALLOC_FL_COLLAPSE_RANGE = 0x8 FALLOC_FL_INSERT_RANGE = 0x20 FALLOC_FL_KEEP_SIZE = 0x1 @@ -463,6 +499,8 @@ const ( FS_ENCRYPTION_MODE_AES_256_GCM = 0x2 FS_ENCRYPTION_MODE_AES_256_XTS = 0x1 FS_ENCRYPTION_MODE_INVALID = 0x0 + FS_ENCRYPTION_MODE_SPECK128_256_CTS = 0x8 + FS_ENCRYPTION_MODE_SPECK128_256_XTS = 0x7 FS_IOC_GET_ENCRYPTION_POLICY = 0x400c6615 FS_IOC_GET_ENCRYPTION_PWSALT = 0x40106614 FS_IOC_SET_ENCRYPTION_POLICY = 0x800c6613 @@ -476,6 +514,8 @@ const ( FS_POLICY_FLAGS_PAD_8 = 0x1 FS_POLICY_FLAGS_PAD_MASK = 0x3 FS_POLICY_FLAGS_VALID = 0x3 + FUTEXFS_SUPER_MAGIC = 0xbad1dea + F_ADD_SEALS = 0x409 F_DUPFD = 0x0 F_DUPFD_CLOEXEC = 0x406 F_EXLCK = 0x4 @@ -488,6 +528,9 @@ const ( F_GETOWN_EX = 0x10 F_GETPIPE_SZ = 0x408 F_GETSIG = 0xb + F_GET_FILE_RW_HINT = 0x40d + F_GET_RW_HINT = 0x40b + F_GET_SEALS = 0x40a F_LOCK = 0x1 F_NOTIFY = 0x402 F_OFD_GETLK = 0x24 @@ -495,6 +538,10 @@ const ( F_OFD_SETLKW = 0x26 F_OK = 0x0 F_RDLCK = 0x0 + F_SEAL_GROW = 0x4 + F_SEAL_SEAL = 0x1 + F_SEAL_SHRINK = 0x2 + F_SEAL_WRITE = 0x8 F_SETFD = 0x2 F_SETFL = 0x4 F_SETLEASE = 0x400 @@ -506,6 +553,8 @@ const ( F_SETOWN_EX = 0xf F_SETPIPE_SZ = 0x407 F_SETSIG = 0xa + F_SET_FILE_RW_HINT = 0x40e + F_SET_RW_HINT = 0x40c F_SHLCK = 0x8 F_TEST = 0x3 F_TLOCK = 0x2 @@ -527,6 +576,49 @@ const ( GENL_UNS_ADMIN_PERM = 0x10 GRND_NONBLOCK = 0x1 GRND_RANDOM = 0x2 + HDIO_DRIVE_CMD = 0x31f + HDIO_DRIVE_CMD_AEB = 0x31e + HDIO_DRIVE_CMD_HDR_SIZE = 0x4 + HDIO_DRIVE_HOB_HDR_SIZE = 0x8 + HDIO_DRIVE_RESET = 0x31c + HDIO_DRIVE_TASK = 0x31e + HDIO_DRIVE_TASKFILE = 0x31d + HDIO_DRIVE_TASK_HDR_SIZE = 0x8 + HDIO_GETGEO = 0x301 + HDIO_GET_32BIT = 0x309 + HDIO_GET_ACOUSTIC = 0x30f + HDIO_GET_ADDRESS = 0x310 + HDIO_GET_BUSSTATE = 0x31a + HDIO_GET_DMA = 0x30b + HDIO_GET_IDENTITY = 0x30d + HDIO_GET_KEEPSETTINGS = 0x308 + HDIO_GET_MULTCOUNT = 0x304 + HDIO_GET_NICE = 0x30c + HDIO_GET_NOWERR = 0x30a + HDIO_GET_QDMA = 0x305 + HDIO_GET_UNMASKINTR = 0x302 + HDIO_GET_WCACHE = 0x30e + HDIO_OBSOLETE_IDENTITY = 0x307 + HDIO_SCAN_HWIF = 0x328 + HDIO_SET_32BIT = 0x324 + HDIO_SET_ACOUSTIC = 0x32c + HDIO_SET_ADDRESS = 0x32f + HDIO_SET_BUSSTATE = 0x32d + HDIO_SET_DMA = 0x326 + HDIO_SET_KEEPSETTINGS = 0x323 + HDIO_SET_MULTCOUNT = 0x321 + HDIO_SET_NICE = 0x329 + HDIO_SET_NOWERR = 0x325 + HDIO_SET_PIO_MODE = 0x327 + HDIO_SET_QDMA = 0x32e + HDIO_SET_UNMASKINTR = 0x322 + HDIO_SET_WCACHE = 0x32b + HDIO_SET_XFER = 0x306 + HDIO_TRISTATE_HWIF = 0x31b + HDIO_UNREGISTER_HWIF = 0x32a + HOSTFS_SUPER_MAGIC = 0xc0ffee + HPFS_SUPER_MAGIC = 0xf995e849 + HUGETLBFS_MAGIC = 0x958458f6 HUPCL = 0x400 IBSHIFT = 0x10 ICANON = 0x2 @@ -546,7 +638,7 @@ const ( IFA_F_STABLE_PRIVACY = 0x800 IFA_F_TEMPORARY = 0x1 IFA_F_TENTATIVE = 0x40 - IFA_MAX = 0x8 + IFA_MAX = 0xa IFF_ALLMULTI = 0x200 IFF_ATTACH_QUEUE = 0x200 IFF_AUTOMEDIA = 0x4000 @@ -561,6 +653,8 @@ const ( IFF_MASTER = 0x400 IFF_MULTICAST = 0x1000 IFF_MULTI_QUEUE = 0x100 + IFF_NAPI = 0x10 + IFF_NAPI_FRAGS = 0x20 IFF_NOARP = 0x80 IFF_NOFILTER = 0x1000 IFF_NOTRAILERS = 0x20 @@ -612,6 +706,7 @@ const ( IN_ISDIR = 0x40000000 IN_LOOPBACKNET = 0x7f IN_MASK_ADD = 0x20000000 + IN_MASK_CREATE = 0x10000000 IN_MODIFY = 0x2 IN_MOVE = 0xc0 IN_MOVED_FROM = 0x40 @@ -671,6 +766,7 @@ const ( IPV6_DONTFRAG = 0x3e IPV6_DROP_MEMBERSHIP = 0x15 IPV6_DSTOPTS = 0x3b + IPV6_FREEBIND = 0x4e IPV6_HDRINCL = 0x24 IPV6_HOPLIMIT = 0x34 IPV6_HOPOPTS = 0x36 @@ -682,6 +778,7 @@ const ( IPV6_MINHOPCOUNT = 0x49 IPV6_MTU = 0x18 IPV6_MTU_DISCOVER = 0x17 + IPV6_MULTICAST_ALL = 0x1d IPV6_MULTICAST_HOPS = 0x12 IPV6_MULTICAST_IF = 0x11 IPV6_MULTICAST_LOOP = 0x13 @@ -775,12 +872,34 @@ const ( IP_UNICAST_IF = 0x32 IP_XFRM_POLICY = 0x11 ISIG = 0x1 + ISOFS_SUPER_MAGIC = 0x9660 ISTRIP = 0x20 IUCLC = 0x200 IUTF8 = 0x4000 IXANY = 0x800 IXOFF = 0x1000 IXON = 0x400 + JFFS2_SUPER_MAGIC = 0x72b6 + KEXEC_ARCH_386 = 0x30000 + KEXEC_ARCH_68K = 0x40000 + KEXEC_ARCH_AARCH64 = 0xb70000 + KEXEC_ARCH_ARM = 0x280000 + KEXEC_ARCH_DEFAULT = 0x0 + KEXEC_ARCH_IA_64 = 0x320000 + KEXEC_ARCH_MASK = 0xffff0000 + KEXEC_ARCH_MIPS = 0x80000 + KEXEC_ARCH_MIPS_LE = 0xa0000 + KEXEC_ARCH_PPC = 0x140000 + KEXEC_ARCH_PPC64 = 0x150000 + KEXEC_ARCH_S390 = 0x160000 + KEXEC_ARCH_SH = 0x2a0000 + KEXEC_ARCH_X86_64 = 0x3e0000 + KEXEC_FILE_NO_INITRAMFS = 0x4 + KEXEC_FILE_ON_CRASH = 0x2 + KEXEC_FILE_UNLOAD = 0x1 + KEXEC_ON_CRASH = 0x1 + KEXEC_PRESERVE_CONTEXT = 0x2 + KEXEC_SEGMENT_MAX = 0x10 KEYCTL_ASSUME_AUTHORITY = 0x10 KEYCTL_CHOWN = 0x4 KEYCTL_CLEAR = 0x7 @@ -795,6 +914,11 @@ const ( KEYCTL_JOIN_SESSION_KEYRING = 0x1 KEYCTL_LINK = 0x8 KEYCTL_NEGATE = 0xd + KEYCTL_PKEY_DECRYPT = 0x1a + KEYCTL_PKEY_ENCRYPT = 0x19 + KEYCTL_PKEY_QUERY = 0x18 + KEYCTL_PKEY_SIGN = 0x1b + KEYCTL_PKEY_VERIFY = 0x1c KEYCTL_READ = 0xb KEYCTL_REJECT = 0x13 KEYCTL_RESTRICT_KEYRING = 0x1d @@ -804,6 +928,10 @@ const ( KEYCTL_SETPERM = 0x5 KEYCTL_SET_REQKEY_KEYRING = 0xe KEYCTL_SET_TIMEOUT = 0xf + KEYCTL_SUPPORTS_DECRYPT = 0x2 + KEYCTL_SUPPORTS_ENCRYPT = 0x1 + KEYCTL_SUPPORTS_SIGN = 0x4 + KEYCTL_SUPPORTS_VERIFY = 0x8 KEYCTL_UNLINK = 0x9 KEYCTL_UPDATE = 0x2 KEY_REQKEY_DEFL_DEFAULT = 0x0 @@ -845,6 +973,7 @@ const ( MADV_FREE = 0x8 MADV_HUGEPAGE = 0xe MADV_HWPOISON = 0x64 + MADV_KEEPONFORK = 0x13 MADV_MERGEABLE = 0xc MADV_NOHUGEPAGE = 0xf MADV_NORMAL = 0x0 @@ -853,12 +982,14 @@ const ( MADV_SEQUENTIAL = 0x2 MADV_UNMERGEABLE = 0xd MADV_WILLNEED = 0x3 + MADV_WIPEONFORK = 0x12 MAP_ANON = 0x20 MAP_ANONYMOUS = 0x20 MAP_DENYWRITE = 0x800 MAP_EXECUTABLE = 0x1000 MAP_FILE = 0x0 MAP_FIXED = 0x10 + MAP_FIXED_NOREPLACE = 0x100000 MAP_GROWSDOWN = 0x100 MAP_HUGETLB = 0x40000 MAP_HUGE_MASK = 0x3f @@ -869,14 +1000,41 @@ const ( MAP_POPULATE = 0x8000 MAP_PRIVATE = 0x2 MAP_SHARED = 0x1 + MAP_SHARED_VALIDATE = 0x3 MAP_STACK = 0x20000 + MAP_SYNC = 0x80000 MAP_TYPE = 0xf MCL_CURRENT = 0x1 MCL_FUTURE = 0x2 MCL_ONFAULT = 0x4 + MFD_ALLOW_SEALING = 0x2 + MFD_CLOEXEC = 0x1 + MFD_HUGETLB = 0x4 + MFD_HUGE_16GB = -0x78000000 + MFD_HUGE_16MB = 0x60000000 + MFD_HUGE_1GB = 0x78000000 + MFD_HUGE_1MB = 0x50000000 + MFD_HUGE_256MB = 0x70000000 + MFD_HUGE_2GB = 0x7c000000 + MFD_HUGE_2MB = 0x54000000 + MFD_HUGE_32MB = 0x64000000 + MFD_HUGE_512KB = 0x4c000000 + MFD_HUGE_512MB = 0x74000000 + MFD_HUGE_64KB = 0x40000000 + MFD_HUGE_8MB = 0x5c000000 + MFD_HUGE_MASK = 0x3f + MFD_HUGE_SHIFT = 0x1a + MINIX2_SUPER_MAGIC = 0x2468 + MINIX2_SUPER_MAGIC2 = 0x2478 + MINIX3_SUPER_MAGIC = 0x4d5a + MINIX_SUPER_MAGIC = 0x137f + MINIX_SUPER_MAGIC2 = 0x138f MNT_DETACH = 0x2 MNT_EXPIRE = 0x4 MNT_FORCE = 0x1 + MODULE_INIT_IGNORE_MODVERSIONS = 0x1 + MODULE_INIT_IGNORE_VERMAGIC = 0x2 + MSDOS_SUPER_MAGIC = 0x4d44 MSG_BATCH = 0x40000 MSG_CMSG_CLOEXEC = 0x40000000 MSG_CONFIRM = 0x800 @@ -898,6 +1056,7 @@ const ( MSG_TRYHARD = 0x4 MSG_WAITALL = 0x100 MSG_WAITFORONE = 0x10000 + MSG_ZEROCOPY = 0x4000000 MS_ACTIVE = 0x40000000 MS_ASYNC = 0x1 MS_BIND = 0x1000 @@ -935,7 +1094,9 @@ const ( MS_SYNCHRONOUS = 0x10 MS_UNBINDABLE = 0x20000 MS_VERBOSE = 0x8000 + MTD_INODE_FS_MAGIC = 0x11307854 NAME_MAX = 0xff + NCP_SUPER_MAGIC = 0x564c NETLINK_ADD_MEMBERSHIP = 0x1 NETLINK_AUDIT = 0x9 NETLINK_BROADCAST_ERROR = 0x4 @@ -949,6 +1110,7 @@ const ( NETLINK_FIB_LOOKUP = 0xa NETLINK_FIREWALL = 0x3 NETLINK_GENERIC = 0x10 + NETLINK_GET_STRICT_CHK = 0xc NETLINK_INET_DIAG = 0x4 NETLINK_IP6_FW = 0xd NETLINK_ISCSI = 0x8 @@ -970,6 +1132,39 @@ const ( NETLINK_UNUSED = 0x1 NETLINK_USERSOCK = 0x2 NETLINK_XFRM = 0x6 + NETNSA_MAX = 0x3 + NETNSA_NSID_NOT_ASSIGNED = -0x1 + NFNETLINK_V0 = 0x0 + NFNLGRP_ACCT_QUOTA = 0x8 + NFNLGRP_CONNTRACK_DESTROY = 0x3 + NFNLGRP_CONNTRACK_EXP_DESTROY = 0x6 + NFNLGRP_CONNTRACK_EXP_NEW = 0x4 + NFNLGRP_CONNTRACK_EXP_UPDATE = 0x5 + NFNLGRP_CONNTRACK_NEW = 0x1 + NFNLGRP_CONNTRACK_UPDATE = 0x2 + NFNLGRP_MAX = 0x9 + NFNLGRP_NFTABLES = 0x7 + NFNLGRP_NFTRACE = 0x9 + NFNLGRP_NONE = 0x0 + NFNL_BATCH_MAX = 0x1 + NFNL_MSG_BATCH_BEGIN = 0x10 + NFNL_MSG_BATCH_END = 0x11 + NFNL_NFA_NEST = 0x8000 + NFNL_SUBSYS_ACCT = 0x7 + NFNL_SUBSYS_COUNT = 0xc + NFNL_SUBSYS_CTHELPER = 0x9 + NFNL_SUBSYS_CTNETLINK = 0x1 + NFNL_SUBSYS_CTNETLINK_EXP = 0x2 + NFNL_SUBSYS_CTNETLINK_TIMEOUT = 0x8 + NFNL_SUBSYS_IPSET = 0x6 + NFNL_SUBSYS_NFTABLES = 0xa + NFNL_SUBSYS_NFT_COMPAT = 0xb + NFNL_SUBSYS_NONE = 0x0 + NFNL_SUBSYS_OSF = 0x5 + NFNL_SUBSYS_QUEUE = 0x3 + NFNL_SUBSYS_ULOG = 0x4 + NFS_SUPER_MAGIC = 0x6969 + NILFS_SUPER_MAGIC = 0x3434 NL0 = 0x0 NL1 = 0x100 NLA_ALIGNTO = 0x4 @@ -997,10 +1192,13 @@ const ( NLM_F_EXCL = 0x200 NLM_F_MATCH = 0x200 NLM_F_MULTI = 0x2 + NLM_F_NONREC = 0x100 NLM_F_REPLACE = 0x100 NLM_F_REQUEST = 0x1 NLM_F_ROOT = 0x100 NOFLSH = 0x80 + NSFS_MAGIC = 0x6e736673 + OCFS2_SUPER_MAGIC = 0x7461636f OCRNL = 0x8 OFDEL = 0x80 OFILL = 0x40 @@ -1008,7 +1206,9 @@ const ( ONLCR = 0x4 ONLRET = 0x20 ONOCR = 0x10 + OPENPROM_SUPER_MAGIC = 0x9fa1 OPOST = 0x1 + OVERLAYFS_SUPER_MAGIC = 0x794c7630 O_ACCMODE = 0x3 O_APPEND = 0x400 O_ASYNC = 0x2000 @@ -1054,6 +1254,7 @@ const ( PACKET_FASTROUTE = 0x6 PACKET_HDRLEN = 0xb PACKET_HOST = 0x0 + PACKET_IGNORE_OUTGOING = 0x17 PACKET_KERNEL = 0x7 PACKET_LOOPBACK = 0x5 PACKET_LOSS = 0xe @@ -1093,16 +1294,50 @@ const ( PERF_EVENT_IOC_DISABLE = 0x2401 PERF_EVENT_IOC_ENABLE = 0x2400 PERF_EVENT_IOC_ID = 0x80082407 + PERF_EVENT_IOC_MODIFY_ATTRIBUTES = 0x4008240b PERF_EVENT_IOC_PAUSE_OUTPUT = 0x40042409 PERF_EVENT_IOC_PERIOD = 0x40082404 + PERF_EVENT_IOC_QUERY_BPF = 0xc008240a PERF_EVENT_IOC_REFRESH = 0x2402 PERF_EVENT_IOC_RESET = 0x2403 PERF_EVENT_IOC_SET_BPF = 0x40042408 PERF_EVENT_IOC_SET_FILTER = 0x40082406 PERF_EVENT_IOC_SET_OUTPUT = 0x2405 + PIPEFS_MAGIC = 0x50495045 + PPPIOCATTACH = 0x4004743d + PPPIOCATTCHAN = 0x40047438 + PPPIOCCONNECT = 0x4004743a + PPPIOCDETACH = 0x4004743c + PPPIOCDISCONN = 0x7439 + PPPIOCGASYNCMAP = 0x80047458 + PPPIOCGCHAN = 0x80047437 + PPPIOCGDEBUG = 0x80047441 + PPPIOCGFLAGS = 0x8004745a + PPPIOCGIDLE = 0x8010743f + PPPIOCGL2TPSTATS = 0x80487436 + PPPIOCGMRU = 0x80047453 + PPPIOCGNPMODE = 0xc008744c + PPPIOCGRASYNCMAP = 0x80047455 + PPPIOCGUNIT = 0x80047456 + PPPIOCGXASYNCMAP = 0x80207450 + PPPIOCNEWUNIT = 0xc004743e + PPPIOCSACTIVE = 0x40107446 + PPPIOCSASYNCMAP = 0x40047457 + PPPIOCSCOMPRESS = 0x4010744d + PPPIOCSDEBUG = 0x40047440 + PPPIOCSFLAGS = 0x40047459 + PPPIOCSMAXCID = 0x40047451 + PPPIOCSMRRU = 0x4004743b + PPPIOCSMRU = 0x40047452 + PPPIOCSNPMODE = 0x4008744b + PPPIOCSPASS = 0x40107447 + PPPIOCSRASYNCMAP = 0x40047454 + PPPIOCSXASYNCMAP = 0x4020744f + PPPIOCXFERUNIT = 0x744e PRIO_PGRP = 0x1 PRIO_PROCESS = 0x0 PRIO_USER = 0x2 + PROC_SUPER_MAGIC = 0x9fa0 PROT_EXEC = 0x4 PROT_GROWSDOWN = 0x1000000 PROT_GROWSUP = 0x2000000 @@ -1145,6 +1380,7 @@ const ( PR_GET_PDEATHSIG = 0x2 PR_GET_SECCOMP = 0x15 PR_GET_SECUREBITS = 0x1b + PR_GET_SPECULATION_CTRL = 0x34 PR_GET_THP_DISABLE = 0x2a PR_GET_TID_ADDRESS = 0x28 PR_GET_TIMERSLACK = 0x1e @@ -1190,11 +1426,24 @@ const ( PR_SET_PTRACER_ANY = 0xffffffffffffffff PR_SET_SECCOMP = 0x16 PR_SET_SECUREBITS = 0x1c + PR_SET_SPECULATION_CTRL = 0x35 PR_SET_THP_DISABLE = 0x29 PR_SET_TIMERSLACK = 0x1d PR_SET_TIMING = 0xe PR_SET_TSC = 0x1a PR_SET_UNALIGN = 0x6 + PR_SPEC_DISABLE = 0x4 + PR_SPEC_ENABLE = 0x2 + PR_SPEC_FORCE_DISABLE = 0x8 + PR_SPEC_INDIRECT_BRANCH = 0x1 + PR_SPEC_NOT_AFFECTED = 0x0 + PR_SPEC_PRCTL = 0x1 + PR_SPEC_STORE_BYPASS = 0x0 + PR_SVE_GET_VL = 0x33 + PR_SVE_SET_VL = 0x32 + PR_SVE_SET_VL_ONEXEC = 0x40000 + PR_SVE_VL_INHERIT = 0x20000 + PR_SVE_VL_LEN_MASK = 0xffff PR_TASK_PERF_EVENTS_DISABLE = 0x1f PR_TASK_PERF_EVENTS_ENABLE = 0x20 PR_TIMING_STATISTICAL = 0x0 @@ -1203,6 +1452,7 @@ const ( PR_TSC_SIGSEGV = 0x2 PR_UNALIGN_NOPRINT = 0x1 PR_UNALIGN_SIGBUS = 0x2 + PSTOREFS_MAGIC = 0x6165676c PTRACE_ATTACH = 0x10 PTRACE_CONT = 0x7 PTRACE_DETACH = 0x11 @@ -1255,6 +1505,7 @@ const ( PTRACE_POKE_SYSTEM_CALL = 0x5008 PTRACE_PROT = 0x15 PTRACE_SECCOMP_GET_FILTER = 0x420c + PTRACE_SECCOMP_GET_METADATA = 0x420d PTRACE_SEIZE = 0x4206 PTRACE_SETOPTIONS = 0x4200 PTRACE_SETREGS = 0xd @@ -1324,6 +1575,14 @@ const ( PT_ORIGGPR2 = 0xd0 PT_PSWADDR = 0x8 PT_PSWMASK = 0x0 + QNX4_SUPER_MAGIC = 0x2f + QNX6_SUPER_MAGIC = 0x68191122 + RAMFS_MAGIC = 0x858458f6 + RDTGROUP_SUPER_MAGIC = 0x7655821 + REISERFS_SUPER_MAGIC = 0x52654973 + RENAME_EXCHANGE = 0x2 + RENAME_NOREPLACE = 0x1 + RENAME_WHITEOUT = 0x4 RLIMIT_AS = 0x9 RLIMIT_CORE = 0x4 RLIMIT_CPU = 0x0 @@ -1341,9 +1600,17 @@ const ( RLIMIT_SIGPENDING = 0xb RLIMIT_STACK = 0x3 RLIM_INFINITY = 0xffffffffffffffff + RNDADDENTROPY = 0x40085203 + RNDADDTOENTCNT = 0x40045201 + RNDCLEARPOOL = 0x5206 + RNDGETENTCNT = 0x80045200 + RNDGETPOOL = 0x80085202 + RNDRESEEDCRNG = 0x5207 + RNDZAPENTCNT = 0x5204 RTAX_ADVMSS = 0x8 RTAX_CC_ALGO = 0x10 RTAX_CWND = 0x7 + RTAX_FASTOPEN_NO_COOKIE = 0x11 RTAX_FEATURES = 0xc RTAX_FEATURE_ALLFRAG = 0x8 RTAX_FEATURE_ECN = 0x1 @@ -1354,7 +1621,7 @@ const ( RTAX_INITCWND = 0xb RTAX_INITRWND = 0xe RTAX_LOCK = 0x1 - RTAX_MAX = 0x10 + RTAX_MAX = 0x11 RTAX_MTU = 0x2 RTAX_QUICKACK = 0xf RTAX_REORDERING = 0x9 @@ -1365,13 +1632,40 @@ const ( RTAX_UNSPEC = 0x0 RTAX_WINDOW = 0x3 RTA_ALIGNTO = 0x4 - RTA_MAX = 0x1a + RTA_MAX = 0x1d RTCF_DIRECTSRC = 0x4000000 RTCF_DOREDIRECT = 0x1000000 RTCF_LOG = 0x2000000 RTCF_MASQ = 0x400000 RTCF_NAT = 0x800000 RTCF_VALVE = 0x200000 + RTC_AF = 0x20 + RTC_AIE_OFF = 0x7002 + RTC_AIE_ON = 0x7001 + RTC_ALM_READ = 0x80247008 + RTC_ALM_SET = 0x40247007 + RTC_EPOCH_READ = 0x8008700d + RTC_EPOCH_SET = 0x4008700e + RTC_IRQF = 0x80 + RTC_IRQP_READ = 0x8008700b + RTC_IRQP_SET = 0x4008700c + RTC_MAX_FREQ = 0x2000 + RTC_PF = 0x40 + RTC_PIE_OFF = 0x7006 + RTC_PIE_ON = 0x7005 + RTC_PLL_GET = 0x80207011 + RTC_PLL_SET = 0x40207012 + RTC_RD_TIME = 0x80247009 + RTC_SET_TIME = 0x4024700a + RTC_UF = 0x10 + RTC_UIE_OFF = 0x7004 + RTC_UIE_ON = 0x7003 + RTC_VL_CLR = 0x7014 + RTC_VL_READ = 0x80047013 + RTC_WIE_OFF = 0x7010 + RTC_WIE_ON = 0x700f + RTC_WKALM_RD = 0x80287010 + RTC_WKALM_SET = 0x4028700f RTF_ADDRCLASSMASK = 0xf8000000 RTF_ADDRCONF = 0x40000 RTF_ALLONLINK = 0x20000 @@ -1406,6 +1700,7 @@ const ( RTM_DELACTION = 0x31 RTM_DELADDR = 0x15 RTM_DELADDRLABEL = 0x49 + RTM_DELCHAIN = 0x65 RTM_DELLINK = 0x11 RTM_DELMDB = 0x55 RTM_DELNEIGH = 0x1d @@ -1426,6 +1721,7 @@ const ( RTM_GETADDR = 0x16 RTM_GETADDRLABEL = 0x4a RTM_GETANYCAST = 0x3e + RTM_GETCHAIN = 0x66 RTM_GETDCB = 0x4e RTM_GETLINK = 0x12 RTM_GETMDB = 0x56 @@ -1440,11 +1736,12 @@ const ( RTM_GETSTATS = 0x5e RTM_GETTCLASS = 0x2a RTM_GETTFILTER = 0x2e - RTM_MAX = 0x63 + RTM_MAX = 0x67 RTM_NEWACTION = 0x30 RTM_NEWADDR = 0x14 RTM_NEWADDRLABEL = 0x48 RTM_NEWCACHEREPORT = 0x60 + RTM_NEWCHAIN = 0x64 RTM_NEWLINK = 0x10 RTM_NEWMDB = 0x54 RTM_NEWNDUSEROPT = 0x44 @@ -1459,8 +1756,8 @@ const ( RTM_NEWSTATS = 0x5c RTM_NEWTCLASS = 0x28 RTM_NEWTFILTER = 0x2c - RTM_NR_FAMILIES = 0x15 - RTM_NR_MSGTYPES = 0x54 + RTM_NR_FAMILIES = 0x16 + RTM_NR_MSGTYPES = 0x58 RTM_SETDCB = 0x4f RTM_SETLINK = 0x13 RTM_SETNEIGHTBL = 0x43 @@ -1474,17 +1771,22 @@ const ( RTNH_F_UNRESOLVED = 0x20 RTN_MAX = 0xb RTPROT_BABEL = 0x2a + RTPROT_BGP = 0xba RTPROT_BIRD = 0xc RTPROT_BOOT = 0x3 RTPROT_DHCP = 0x10 RTPROT_DNROUTED = 0xd + RTPROT_EIGRP = 0xc0 RTPROT_GATED = 0x8 + RTPROT_ISIS = 0xbb RTPROT_KERNEL = 0x2 RTPROT_MROUTED = 0x11 RTPROT_MRT = 0xa RTPROT_NTK = 0xf + RTPROT_OSPF = 0xbc RTPROT_RA = 0x9 RTPROT_REDIRECT = 0x1 + RTPROT_RIP = 0xbd RTPROT_STATIC = 0x4 RTPROT_UNSPEC = 0x0 RTPROT_XORP = 0xe @@ -1504,10 +1806,16 @@ const ( SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SC_LOG_FLUSH = 0x100000 SECCOMP_MODE_DISABLED = 0x0 SECCOMP_MODE_FILTER = 0x2 SECCOMP_MODE_STRICT = 0x1 + SECURITYFS_MAGIC = 0x73636673 + SELINUX_MAGIC = 0xf97cff8c + SFD_CLOEXEC = 0x80000 + SFD_NONBLOCK = 0x800 SHUT_RD = 0x0 SHUT_RDWR = 0x2 SHUT_WR = 0x1 @@ -1558,6 +1866,9 @@ const ( SIOCGMIIPHY = 0x8947 SIOCGMIIREG = 0x8948 SIOCGPGRP = 0x8904 + SIOCGPPPCSTATS = 0x89f2 + SIOCGPPPSTATS = 0x89f0 + SIOCGPPPVER = 0x89f1 SIOCGRARP = 0x8961 SIOCGSKNS = 0x894c SIOCGSTAMP = 0x8906 @@ -1592,6 +1903,23 @@ const ( SIOCSPGRP = 0x8902 SIOCSRARP = 0x8962 SIOCWANDEV = 0x894a + SMACK_MAGIC = 0x43415d53 + SMART_AUTOSAVE = 0xd2 + SMART_AUTO_OFFLINE = 0xdb + SMART_DISABLE = 0xd9 + SMART_ENABLE = 0xd8 + SMART_HCYL_PASS = 0xc2 + SMART_IMMEDIATE_OFFLINE = 0xd4 + SMART_LCYL_PASS = 0x4f + SMART_READ_LOG_SECTOR = 0xd5 + SMART_READ_THRESHOLDS = 0xd1 + SMART_READ_VALUES = 0xd0 + SMART_SAVE = 0xd3 + SMART_STATUS = 0xda + SMART_WRITE_LOG_SECTOR = 0xd6 + SMART_WRITE_THRESHOLDS = 0xd7 + SMB_SUPER_MAGIC = 0x517b + SOCKFS_MAGIC = 0x534f434b SOCK_CLOEXEC = 0x80000 SOCK_DCCP = 0x6 SOCK_DGRAM = 0x2 @@ -1628,7 +1956,9 @@ const ( SOL_SOCKET = 0x1 SOL_TCP = 0x6 SOL_TIPC = 0x10f + SOL_TLS = 0x11a SOL_X25 = 0x106 + SOL_XDP = 0x11b SOMAXCONN = 0x80 SO_ACCEPTCONN = 0x1e SO_ATTACH_BPF = 0x32 @@ -1647,6 +1977,17 @@ const ( SO_DETACH_FILTER = 0x1b SO_DOMAIN = 0x27 SO_DONTROUTE = 0x5 + SO_EE_CODE_TXTIME_INVALID_PARAM = 0x1 + SO_EE_CODE_TXTIME_MISSED = 0x2 + SO_EE_CODE_ZEROCOPY_COPIED = 0x1 + SO_EE_ORIGIN_ICMP = 0x2 + SO_EE_ORIGIN_ICMP6 = 0x3 + SO_EE_ORIGIN_LOCAL = 0x1 + SO_EE_ORIGIN_NONE = 0x0 + SO_EE_ORIGIN_TIMESTAMPING = 0x4 + SO_EE_ORIGIN_TXSTATUS = 0x4 + SO_EE_ORIGIN_TXTIME = 0x6 + SO_EE_ORIGIN_ZEROCOPY = 0x5 SO_ERROR = 0x4 SO_GET_FILTER = 0x1a SO_INCOMING_CPU = 0x31 @@ -1687,6 +2028,7 @@ const ( SO_TIMESTAMP = 0x1d SO_TIMESTAMPING = 0x25 SO_TIMESTAMPNS = 0x23 + SO_TXTIME = 0x3d SO_TYPE = 0x3 SO_VM_SOCKETS_BUFFER_MAX_SIZE = 0x2 SO_VM_SOCKETS_BUFFER_MIN_SIZE = 0x1 @@ -1696,10 +2038,38 @@ const ( SO_VM_SOCKETS_PEER_HOST_VM_ID = 0x3 SO_VM_SOCKETS_TRUSTED = 0x5 SO_WIFI_STATUS = 0x29 + SO_ZEROCOPY = 0x3c SPLICE_F_GIFT = 0x8 SPLICE_F_MORE = 0x4 SPLICE_F_MOVE = 0x1 SPLICE_F_NONBLOCK = 0x2 + SQUASHFS_MAGIC = 0x73717368 + STACK_END_MAGIC = 0x57ac6e9d + STATX_ALL = 0xfff + STATX_ATIME = 0x20 + STATX_ATTR_APPEND = 0x20 + STATX_ATTR_AUTOMOUNT = 0x1000 + STATX_ATTR_COMPRESSED = 0x4 + STATX_ATTR_ENCRYPTED = 0x800 + STATX_ATTR_IMMUTABLE = 0x10 + STATX_ATTR_NODUMP = 0x40 + STATX_BASIC_STATS = 0x7ff + STATX_BLOCKS = 0x400 + STATX_BTIME = 0x800 + STATX_CTIME = 0x80 + STATX_GID = 0x10 + STATX_INO = 0x100 + STATX_MODE = 0x2 + STATX_MTIME = 0x40 + STATX_NLINK = 0x4 + STATX_SIZE = 0x200 + STATX_TYPE = 0x1 + STATX_UID = 0x8 + STATX__RESERVED = 0x80000000 + SYNC_FILE_RANGE_WAIT_AFTER = 0x4 + SYNC_FILE_RANGE_WAIT_BEFORE = 0x1 + SYNC_FILE_RANGE_WRITE = 0x2 + SYSFS_MAGIC = 0x62656572 S_BLKSIZE = 0x200 S_IEXEC = 0x40 S_IFBLK = 0x6000 @@ -1737,7 +2107,7 @@ const ( TASKSTATS_GENL_NAME = "TASKSTATS" TASKSTATS_GENL_VERSION = 0x1 TASKSTATS_TYPE_MAX = 0x6 - TASKSTATS_VERSION = 0x8 + TASKSTATS_VERSION = 0x9 TCFLSH = 0x540b TCGETA = 0x5405 TCGETS = 0x5401 @@ -1751,6 +2121,7 @@ const ( TCOOFF = 0x0 TCOON = 0x1 TCP_CC_INFO = 0x1a + TCP_CM_INQ = 0x24 TCP_CONGESTION = 0xd TCP_COOKIE_IN_ALWAYS = 0x1 TCP_COOKIE_MAX = 0x10 @@ -1762,7 +2133,10 @@ const ( TCP_DEFER_ACCEPT = 0x9 TCP_FASTOPEN = 0x17 TCP_FASTOPEN_CONNECT = 0x1e + TCP_FASTOPEN_KEY = 0x21 + TCP_FASTOPEN_NO_COOKIE = 0x22 TCP_INFO = 0xb + TCP_INQ = 0x24 TCP_KEEPCNT = 0x6 TCP_KEEPIDLE = 0x4 TCP_KEEPINTVL = 0x5 @@ -1771,6 +2145,8 @@ const ( TCP_MAXWIN = 0xffff TCP_MAX_WINSHIFT = 0xe TCP_MD5SIG = 0xe + TCP_MD5SIG_EXT = 0x20 + TCP_MD5SIG_FLAG_PREFIX = 0x1 TCP_MD5SIG_MAXKEYLEN = 0x50 TCP_MSS = 0x200 TCP_MSS_DEFAULT = 0x218 @@ -1780,6 +2156,9 @@ const ( TCP_QUEUE_SEQ = 0x15 TCP_QUICKACK = 0xc TCP_REPAIR = 0x13 + TCP_REPAIR_OFF = 0x0 + TCP_REPAIR_OFF_NO_WP = -0x1 + TCP_REPAIR_ON = 0x1 TCP_REPAIR_OPTIONS = 0x16 TCP_REPAIR_QUEUE = 0x14 TCP_REPAIR_WINDOW = 0x1d @@ -1791,8 +2170,10 @@ const ( TCP_THIN_DUPACK = 0x11 TCP_THIN_LINEAR_TIMEOUTS = 0x10 TCP_TIMESTAMP = 0x18 + TCP_ULP = 0x1f TCP_USER_TIMEOUT = 0x12 TCP_WINDOW_CLAMP = 0xa + TCP_ZEROCOPY_RECEIVE = 0x23 TCSAFLUSH = 0x2 TCSBRK = 0x5409 TCSBRKP = 0x5425 @@ -1809,6 +2190,7 @@ const ( TCSETXF = 0x5434 TCSETXW = 0x5435 TCXONC = 0x540a + TIMER_ABSTIME = 0x1 TIOCCBRK = 0x5428 TIOCCONS = 0x541d TIOCEXCL = 0x540c @@ -1816,6 +2198,7 @@ const ( TIOCGETD = 0x5424 TIOCGEXCL = 0x80045440 TIOCGICOUNT = 0x545d + TIOCGISO7816 = 0x80285442 TIOCGLCKTRMIOS = 0x5456 TIOCGPGRP = 0x540f TIOCGPKT = 0x80045438 @@ -1869,6 +2252,7 @@ const ( TIOCSER_TEMT = 0x1 TIOCSETD = 0x5423 TIOCSIG = 0x40045436 + TIOCSISO7816 = 0xc0285443 TIOCSLCKTRMIOS = 0x5457 TIOCSPGRP = 0x5410 TIOCSPTLCK = 0x40045431 @@ -1878,7 +2262,27 @@ const ( TIOCSTI = 0x5412 TIOCSWINSZ = 0x5414 TIOCVHANGUP = 0x5437 + TMPFS_MAGIC = 0x1021994 TOSTOP = 0x100 + TPACKET_ALIGNMENT = 0x10 + TPACKET_HDRLEN = 0x34 + TP_STATUS_AVAILABLE = 0x0 + TP_STATUS_BLK_TMO = 0x20 + TP_STATUS_COPY = 0x2 + TP_STATUS_CSUMNOTREADY = 0x8 + TP_STATUS_CSUM_VALID = 0x80 + TP_STATUS_KERNEL = 0x0 + TP_STATUS_LOSING = 0x4 + TP_STATUS_SENDING = 0x2 + TP_STATUS_SEND_REQUEST = 0x1 + TP_STATUS_TS_RAW_HARDWARE = -0x80000000 + TP_STATUS_TS_SOFTWARE = 0x20000000 + TP_STATUS_TS_SYS_HARDWARE = 0x40000000 + TP_STATUS_USER = 0x1 + TP_STATUS_VLAN_TPID_VALID = 0x40 + TP_STATUS_VLAN_VALID = 0x10 + TP_STATUS_WRONG_FORMAT = 0x4 + TRACEFS_MAGIC = 0x74726163 TS_COMM_LEN = 0x20 TUNATTACHFILTER = 0x401054d5 TUNDETACHFILTER = 0x401054d6 @@ -1890,6 +2294,7 @@ const ( TUNGETVNETHDRSZ = 0x800454d7 TUNGETVNETLE = 0x800454dd TUNSETDEBUG = 0x400454c9 + TUNSETFILTEREBPF = 0x800454e1 TUNSETGROUP = 0x400454ce TUNSETIFF = 0x400454ca TUNSETIFINDEX = 0x400454da @@ -1900,13 +2305,32 @@ const ( TUNSETPERSIST = 0x400454cb TUNSETQUEUE = 0x400454d9 TUNSETSNDBUF = 0x400454d4 + TUNSETSTEERINGEBPF = 0x800454e0 TUNSETTXFILTER = 0x400454d1 TUNSETVNETBE = 0x400454de TUNSETVNETHDRSZ = 0x400454d8 TUNSETVNETLE = 0x400454dc + UBI_IOCATT = 0x40186f40 + UBI_IOCDET = 0x40046f41 + UBI_IOCEBCH = 0x40044f02 + UBI_IOCEBER = 0x40044f01 + UBI_IOCEBISMAP = 0x80044f05 + UBI_IOCEBMAP = 0x40084f03 + UBI_IOCEBUNMAP = 0x40044f04 + UBI_IOCMKVOL = 0x40986f00 + UBI_IOCRMVOL = 0x40046f01 + UBI_IOCRNVOL = 0x51106f03 + UBI_IOCRSVOL = 0x400c6f02 + UBI_IOCSETVOLPROP = 0x40104f06 + UBI_IOCVOLCRBLK = 0x40804f07 + UBI_IOCVOLRMBLK = 0x4f08 + UBI_IOCVOLUP = 0x40084f00 + UDF_SUPER_MAGIC = 0x15013346 UMOUNT_NOFOLLOW = 0x8 + USBDEVICE_SUPER_MAGIC = 0x9fa2 UTIME_NOW = 0x3fffffff UTIME_OMIT = 0x3ffffffe + V9FS_MAGIC = 0x1021997 VDISCARD = 0xd VEOF = 0x4 VEOL = 0xb @@ -1948,6 +2372,86 @@ const ( WDIOC_SETPRETIMEOUT = 0xc0045708 WDIOC_SETTIMEOUT = 0xc0045706 WEXITED = 0x4 + WIN_ACKMEDIACHANGE = 0xdb + WIN_CHECKPOWERMODE1 = 0xe5 + WIN_CHECKPOWERMODE2 = 0x98 + WIN_DEVICE_RESET = 0x8 + WIN_DIAGNOSE = 0x90 + WIN_DOORLOCK = 0xde + WIN_DOORUNLOCK = 0xdf + WIN_DOWNLOAD_MICROCODE = 0x92 + WIN_FLUSH_CACHE = 0xe7 + WIN_FLUSH_CACHE_EXT = 0xea + WIN_FORMAT = 0x50 + WIN_GETMEDIASTATUS = 0xda + WIN_IDENTIFY = 0xec + WIN_IDENTIFY_DMA = 0xee + WIN_IDLEIMMEDIATE = 0xe1 + WIN_INIT = 0x60 + WIN_MEDIAEJECT = 0xed + WIN_MULTREAD = 0xc4 + WIN_MULTREAD_EXT = 0x29 + WIN_MULTWRITE = 0xc5 + WIN_MULTWRITE_EXT = 0x39 + WIN_NOP = 0x0 + WIN_PACKETCMD = 0xa0 + WIN_PIDENTIFY = 0xa1 + WIN_POSTBOOT = 0xdc + WIN_PREBOOT = 0xdd + WIN_QUEUED_SERVICE = 0xa2 + WIN_READ = 0x20 + WIN_READDMA = 0xc8 + WIN_READDMA_EXT = 0x25 + WIN_READDMA_ONCE = 0xc9 + WIN_READDMA_QUEUED = 0xc7 + WIN_READDMA_QUEUED_EXT = 0x26 + WIN_READ_BUFFER = 0xe4 + WIN_READ_EXT = 0x24 + WIN_READ_LONG = 0x22 + WIN_READ_LONG_ONCE = 0x23 + WIN_READ_NATIVE_MAX = 0xf8 + WIN_READ_NATIVE_MAX_EXT = 0x27 + WIN_READ_ONCE = 0x21 + WIN_RECAL = 0x10 + WIN_RESTORE = 0x10 + WIN_SECURITY_DISABLE = 0xf6 + WIN_SECURITY_ERASE_PREPARE = 0xf3 + WIN_SECURITY_ERASE_UNIT = 0xf4 + WIN_SECURITY_FREEZE_LOCK = 0xf5 + WIN_SECURITY_SET_PASS = 0xf1 + WIN_SECURITY_UNLOCK = 0xf2 + WIN_SEEK = 0x70 + WIN_SETFEATURES = 0xef + WIN_SETIDLE1 = 0xe3 + WIN_SETIDLE2 = 0x97 + WIN_SETMULT = 0xc6 + WIN_SET_MAX = 0xf9 + WIN_SET_MAX_EXT = 0x37 + WIN_SLEEPNOW1 = 0xe6 + WIN_SLEEPNOW2 = 0x99 + WIN_SMART = 0xb0 + WIN_SPECIFY = 0x91 + WIN_SRST = 0x8 + WIN_STANDBY = 0xe2 + WIN_STANDBY2 = 0x96 + WIN_STANDBYNOW1 = 0xe0 + WIN_STANDBYNOW2 = 0x94 + WIN_VERIFY = 0x40 + WIN_VERIFY_EXT = 0x42 + WIN_VERIFY_ONCE = 0x41 + WIN_WRITE = 0x30 + WIN_WRITEDMA = 0xca + WIN_WRITEDMA_EXT = 0x35 + WIN_WRITEDMA_ONCE = 0xcb + WIN_WRITEDMA_QUEUED = 0xcc + WIN_WRITEDMA_QUEUED_EXT = 0x36 + WIN_WRITE_BUFFER = 0xe8 + WIN_WRITE_EXT = 0x34 + WIN_WRITE_LONG = 0x32 + WIN_WRITE_LONG_ONCE = 0x33 + WIN_WRITE_ONCE = 0x31 + WIN_WRITE_SAME = 0xe9 + WIN_WRITE_VERIFY = 0x3c WNOHANG = 0x1 WNOTHREAD = 0x20000000 WNOWAIT = 0x1000000 @@ -1957,7 +2461,30 @@ const ( XATTR_CREATE = 0x1 XATTR_REPLACE = 0x2 XCASE = 0x4 + XDP_COPY = 0x2 + XDP_FLAGS_DRV_MODE = 0x4 + XDP_FLAGS_HW_MODE = 0x8 + XDP_FLAGS_MASK = 0xf + XDP_FLAGS_MODES = 0xe + XDP_FLAGS_SKB_MODE = 0x2 + XDP_FLAGS_UPDATE_IF_NOEXIST = 0x1 + XDP_MMAP_OFFSETS = 0x1 + XDP_PGOFF_RX_RING = 0x0 + XDP_PGOFF_TX_RING = 0x80000000 + XDP_RX_RING = 0x2 + XDP_SHARED_UMEM = 0x1 + XDP_STATISTICS = 0x7 + XDP_TX_RING = 0x3 + XDP_UMEM_COMPLETION_RING = 0x6 + XDP_UMEM_FILL_RING = 0x5 + XDP_UMEM_PGOFF_COMPLETION_RING = 0x180000000 + XDP_UMEM_PGOFF_FILL_RING = 0x100000000 + XDP_UMEM_REG = 0x4 + XDP_ZEROCOPY = 0x4 + XENFS_SUPER_MAGIC = 0xabba1974 + XFS_SUPER_MAGIC = 0x58465342 XTABS = 0x1800 + ZSMALLOC_MAGIC = 0x58295829 ) // Errors @@ -2137,171 +2664,179 @@ const ( ) // Error table -var errors = [...]string{ - 1: "operation not permitted", - 2: "no such file or directory", - 3: "no such process", - 4: "interrupted system call", - 5: "input/output error", - 6: "no such device or address", - 7: "argument list too long", - 8: "exec format error", - 9: "bad file descriptor", - 10: "no child processes", - 11: "resource temporarily unavailable", - 12: "cannot allocate memory", - 13: "permission denied", - 14: "bad address", - 15: "block device required", - 16: "device or resource busy", - 17: "file exists", - 18: "invalid cross-device link", - 19: "no such device", - 20: "not a directory", - 21: "is a directory", - 22: "invalid argument", - 23: "too many open files in system", - 24: "too many open files", - 25: "inappropriate ioctl for device", - 26: "text file busy", - 27: "file too large", - 28: "no space left on device", - 29: "illegal seek", - 30: "read-only file system", - 31: "too many links", - 32: "broken pipe", - 33: "numerical argument out of domain", - 34: "numerical result out of range", - 35: "resource deadlock avoided", - 36: "file name too long", - 37: "no locks available", - 38: "function not implemented", - 39: "directory not empty", - 40: "too many levels of symbolic links", - 42: "no message of desired type", - 43: "identifier removed", - 44: "channel number out of range", - 45: "level 2 not synchronized", - 46: "level 3 halted", - 47: "level 3 reset", - 48: "link number out of range", - 49: "protocol driver not attached", - 50: "no CSI structure available", - 51: "level 2 halted", - 52: "invalid exchange", - 53: "invalid request descriptor", - 54: "exchange full", - 55: "no anode", - 56: "invalid request code", - 57: "invalid slot", - 59: "bad font file format", - 60: "device not a stream", - 61: "no data available", - 62: "timer expired", - 63: "out of streams resources", - 64: "machine is not on the network", - 65: "package not installed", - 66: "object is remote", - 67: "link has been severed", - 68: "advertise error", - 69: "srmount error", - 70: "communication error on send", - 71: "protocol error", - 72: "multihop attempted", - 73: "RFS specific error", - 74: "bad message", - 75: "value too large for defined data type", - 76: "name not unique on network", - 77: "file descriptor in bad state", - 78: "remote address changed", - 79: "can not access a needed shared library", - 80: "accessing a corrupted shared library", - 81: ".lib section in a.out corrupted", - 82: "attempting to link in too many shared libraries", - 83: "cannot exec a shared library directly", - 84: "invalid or incomplete multibyte or wide character", - 85: "interrupted system call should be restarted", - 86: "streams pipe error", - 87: "too many users", - 88: "socket operation on non-socket", - 89: "destination address required", - 90: "message too long", - 91: "protocol wrong type for socket", - 92: "protocol not available", - 93: "protocol not supported", - 94: "socket type not supported", - 95: "operation not supported", - 96: "protocol family not supported", - 97: "address family not supported by protocol", - 98: "address already in use", - 99: "cannot assign requested address", - 100: "network is down", - 101: "network is unreachable", - 102: "network dropped connection on reset", - 103: "software caused connection abort", - 104: "connection reset by peer", - 105: "no buffer space available", - 106: "transport endpoint is already connected", - 107: "transport endpoint is not connected", - 108: "cannot send after transport endpoint shutdown", - 109: "too many references: cannot splice", - 110: "connection timed out", - 111: "connection refused", - 112: "host is down", - 113: "no route to host", - 114: "operation already in progress", - 115: "operation now in progress", - 116: "stale file handle", - 117: "structure needs cleaning", - 118: "not a XENIX named type file", - 119: "no XENIX semaphores available", - 120: "is a named type file", - 121: "remote I/O error", - 122: "disk quota exceeded", - 123: "no medium found", - 124: "wrong medium type", - 125: "operation canceled", - 126: "required key not available", - 127: "key has expired", - 128: "key has been revoked", - 129: "key was rejected by service", - 130: "owner died", - 131: "state not recoverable", - 132: "operation not possible due to RF-kill", - 133: "memory page has hardware error", +var errorList = [...]struct { + num syscall.Errno + name string + desc string +}{ + {1, "EPERM", "operation not permitted"}, + {2, "ENOENT", "no such file or directory"}, + {3, "ESRCH", "no such process"}, + {4, "EINTR", "interrupted system call"}, + {5, "EIO", "input/output error"}, + {6, "ENXIO", "no such device or address"}, + {7, "E2BIG", "argument list too long"}, + {8, "ENOEXEC", "exec format error"}, + {9, "EBADF", "bad file descriptor"}, + {10, "ECHILD", "no child processes"}, + {11, "EAGAIN", "resource temporarily unavailable"}, + {12, "ENOMEM", "cannot allocate memory"}, + {13, "EACCES", "permission denied"}, + {14, "EFAULT", "bad address"}, + {15, "ENOTBLK", "block device required"}, + {16, "EBUSY", "device or resource busy"}, + {17, "EEXIST", "file exists"}, + {18, "EXDEV", "invalid cross-device link"}, + {19, "ENODEV", "no such device"}, + {20, "ENOTDIR", "not a directory"}, + {21, "EISDIR", "is a directory"}, + {22, "EINVAL", "invalid argument"}, + {23, "ENFILE", "too many open files in system"}, + {24, "EMFILE", "too many open files"}, + {25, "ENOTTY", "inappropriate ioctl for device"}, + {26, "ETXTBSY", "text file busy"}, + {27, "EFBIG", "file too large"}, + {28, "ENOSPC", "no space left on device"}, + {29, "ESPIPE", "illegal seek"}, + {30, "EROFS", "read-only file system"}, + {31, "EMLINK", "too many links"}, + {32, "EPIPE", "broken pipe"}, + {33, "EDOM", "numerical argument out of domain"}, + {34, "ERANGE", "numerical result out of range"}, + {35, "EDEADLK", "resource deadlock avoided"}, + {36, "ENAMETOOLONG", "file name too long"}, + {37, "ENOLCK", "no locks available"}, + {38, "ENOSYS", "function not implemented"}, + {39, "ENOTEMPTY", "directory not empty"}, + {40, "ELOOP", "too many levels of symbolic links"}, + {42, "ENOMSG", "no message of desired type"}, + {43, "EIDRM", "identifier removed"}, + {44, "ECHRNG", "channel number out of range"}, + {45, "EL2NSYNC", "level 2 not synchronized"}, + {46, "EL3HLT", "level 3 halted"}, + {47, "EL3RST", "level 3 reset"}, + {48, "ELNRNG", "link number out of range"}, + {49, "EUNATCH", "protocol driver not attached"}, + {50, "ENOCSI", "no CSI structure available"}, + {51, "EL2HLT", "level 2 halted"}, + {52, "EBADE", "invalid exchange"}, + {53, "EBADR", "invalid request descriptor"}, + {54, "EXFULL", "exchange full"}, + {55, "ENOANO", "no anode"}, + {56, "EBADRQC", "invalid request code"}, + {57, "EBADSLT", "invalid slot"}, + {59, "EBFONT", "bad font file format"}, + {60, "ENOSTR", "device not a stream"}, + {61, "ENODATA", "no data available"}, + {62, "ETIME", "timer expired"}, + {63, "ENOSR", "out of streams resources"}, + {64, "ENONET", "machine is not on the network"}, + {65, "ENOPKG", "package not installed"}, + {66, "EREMOTE", "object is remote"}, + {67, "ENOLINK", "link has been severed"}, + {68, "EADV", "advertise error"}, + {69, "ESRMNT", "srmount error"}, + {70, "ECOMM", "communication error on send"}, + {71, "EPROTO", "protocol error"}, + {72, "EMULTIHOP", "multihop attempted"}, + {73, "EDOTDOT", "RFS specific error"}, + {74, "EBADMSG", "bad message"}, + {75, "EOVERFLOW", "value too large for defined data type"}, + {76, "ENOTUNIQ", "name not unique on network"}, + {77, "EBADFD", "file descriptor in bad state"}, + {78, "EREMCHG", "remote address changed"}, + {79, "ELIBACC", "can not access a needed shared library"}, + {80, "ELIBBAD", "accessing a corrupted shared library"}, + {81, "ELIBSCN", ".lib section in a.out corrupted"}, + {82, "ELIBMAX", "attempting to link in too many shared libraries"}, + {83, "ELIBEXEC", "cannot exec a shared library directly"}, + {84, "EILSEQ", "invalid or incomplete multibyte or wide character"}, + {85, "ERESTART", "interrupted system call should be restarted"}, + {86, "ESTRPIPE", "streams pipe error"}, + {87, "EUSERS", "too many users"}, + {88, "ENOTSOCK", "socket operation on non-socket"}, + {89, "EDESTADDRREQ", "destination address required"}, + {90, "EMSGSIZE", "message too long"}, + {91, "EPROTOTYPE", "protocol wrong type for socket"}, + {92, "ENOPROTOOPT", "protocol not available"}, + {93, "EPROTONOSUPPORT", "protocol not supported"}, + {94, "ESOCKTNOSUPPORT", "socket type not supported"}, + {95, "ENOTSUP", "operation not supported"}, + {96, "EPFNOSUPPORT", "protocol family not supported"}, + {97, "EAFNOSUPPORT", "address family not supported by protocol"}, + {98, "EADDRINUSE", "address already in use"}, + {99, "EADDRNOTAVAIL", "cannot assign requested address"}, + {100, "ENETDOWN", "network is down"}, + {101, "ENETUNREACH", "network is unreachable"}, + {102, "ENETRESET", "network dropped connection on reset"}, + {103, "ECONNABORTED", "software caused connection abort"}, + {104, "ECONNRESET", "connection reset by peer"}, + {105, "ENOBUFS", "no buffer space available"}, + {106, "EISCONN", "transport endpoint is already connected"}, + {107, "ENOTCONN", "transport endpoint is not connected"}, + {108, "ESHUTDOWN", "cannot send after transport endpoint shutdown"}, + {109, "ETOOMANYREFS", "too many references: cannot splice"}, + {110, "ETIMEDOUT", "connection timed out"}, + {111, "ECONNREFUSED", "connection refused"}, + {112, "EHOSTDOWN", "host is down"}, + {113, "EHOSTUNREACH", "no route to host"}, + {114, "EALREADY", "operation already in progress"}, + {115, "EINPROGRESS", "operation now in progress"}, + {116, "ESTALE", "stale file handle"}, + {117, "EUCLEAN", "structure needs cleaning"}, + {118, "ENOTNAM", "not a XENIX named type file"}, + {119, "ENAVAIL", "no XENIX semaphores available"}, + {120, "EISNAM", "is a named type file"}, + {121, "EREMOTEIO", "remote I/O error"}, + {122, "EDQUOT", "disk quota exceeded"}, + {123, "ENOMEDIUM", "no medium found"}, + {124, "EMEDIUMTYPE", "wrong medium type"}, + {125, "ECANCELED", "operation canceled"}, + {126, "ENOKEY", "required key not available"}, + {127, "EKEYEXPIRED", "key has expired"}, + {128, "EKEYREVOKED", "key has been revoked"}, + {129, "EKEYREJECTED", "key was rejected by service"}, + {130, "EOWNERDEAD", "owner died"}, + {131, "ENOTRECOVERABLE", "state not recoverable"}, + {132, "ERFKILL", "operation not possible due to RF-kill"}, + {133, "EHWPOISON", "memory page has hardware error"}, } // Signal table -var signals = [...]string{ - 1: "hangup", - 2: "interrupt", - 3: "quit", - 4: "illegal instruction", - 5: "trace/breakpoint trap", - 6: "aborted", - 7: "bus error", - 8: "floating point exception", - 9: "killed", - 10: "user defined signal 1", - 11: "segmentation fault", - 12: "user defined signal 2", - 13: "broken pipe", - 14: "alarm clock", - 15: "terminated", - 16: "stack fault", - 17: "child exited", - 18: "continued", - 19: "stopped (signal)", - 20: "stopped", - 21: "stopped (tty input)", - 22: "stopped (tty output)", - 23: "urgent I/O condition", - 24: "CPU time limit exceeded", - 25: "file size limit exceeded", - 26: "virtual timer expired", - 27: "profiling timer expired", - 28: "window changed", - 29: "I/O possible", - 30: "power failure", - 31: "bad system call", +var signalList = [...]struct { + num syscall.Signal + name string + desc string +}{ + {1, "SIGHUP", "hangup"}, + {2, "SIGINT", "interrupt"}, + {3, "SIGQUIT", "quit"}, + {4, "SIGILL", "illegal instruction"}, + {5, "SIGTRAP", "trace/breakpoint trap"}, + {6, "SIGABRT", "aborted"}, + {7, "SIGBUS", "bus error"}, + {8, "SIGFPE", "floating point exception"}, + {9, "SIGKILL", "killed"}, + {10, "SIGUSR1", "user defined signal 1"}, + {11, "SIGSEGV", "segmentation fault"}, + {12, "SIGUSR2", "user defined signal 2"}, + {13, "SIGPIPE", "broken pipe"}, + {14, "SIGALRM", "alarm clock"}, + {15, "SIGTERM", "terminated"}, + {16, "SIGSTKFLT", "stack fault"}, + {17, "SIGCHLD", "child exited"}, + {18, "SIGCONT", "continued"}, + {19, "SIGSTOP", "stopped (signal)"}, + {20, "SIGTSTP", "stopped"}, + {21, "SIGTTIN", "stopped (tty input)"}, + {22, "SIGTTOU", "stopped (tty output)"}, + {23, "SIGURG", "urgent I/O condition"}, + {24, "SIGXCPU", "CPU time limit exceeded"}, + {25, "SIGXFSZ", "file size limit exceeded"}, + {26, "SIGVTALRM", "virtual timer expired"}, + {27, "SIGPROF", "profiling timer expired"}, + {28, "SIGWINCH", "window changed"}, + {29, "SIGIO", "I/O possible"}, + {30, "SIGPWR", "power failure"}, + {31, "SIGSYS", "bad system call"}, } diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go index 95de199fc4..968e21fd68 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go @@ -1,1792 +1,2480 @@ -// mkerrors.sh -m64 -// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// mkerrors.sh -Wall -Werror -static -I/tmp/include +// Code generated by the command above; see README.md. DO NOT EDIT. // +build sparc64,linux -// Created by cgo -godefs - DO NOT EDIT -// cgo -godefs -- -m64 _const.go +// Code generated by cmd/cgo -godefs; DO NOT EDIT. +// cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go package unix import "syscall" const ( - AF_ALG = 0x26 - AF_APPLETALK = 0x5 - AF_ASH = 0x12 - AF_ATMPVC = 0x8 - AF_ATMSVC = 0x14 - AF_AX25 = 0x3 - AF_BLUETOOTH = 0x1f - AF_BRIDGE = 0x7 - AF_CAIF = 0x25 - AF_CAN = 0x1d - AF_DECnet = 0xc - AF_ECONET = 0x13 - AF_FILE = 0x1 - AF_IB = 0x1b - AF_IEEE802154 = 0x24 - AF_INET = 0x2 - AF_INET6 = 0xa - AF_IPX = 0x4 - AF_IRDA = 0x17 - AF_ISDN = 0x22 - AF_IUCV = 0x20 - AF_KCM = 0x29 - AF_KEY = 0xf - AF_LLC = 0x1a - AF_LOCAL = 0x1 - AF_MAX = 0x2a - AF_MPLS = 0x1c - AF_NETBEUI = 0xd - AF_NETLINK = 0x10 - AF_NETROM = 0x6 - AF_NFC = 0x27 - AF_PACKET = 0x11 - AF_PHONET = 0x23 - AF_PPPOX = 0x18 - AF_RDS = 0x15 - AF_ROSE = 0xb - AF_ROUTE = 0x10 - AF_RXRPC = 0x21 - AF_SECURITY = 0xe - AF_SNA = 0x16 - AF_TIPC = 0x1e - AF_UNIX = 0x1 - AF_UNSPEC = 0x0 - AF_VSOCK = 0x28 - AF_WANPIPE = 0x19 - AF_X25 = 0x9 - ALG_OP_DECRYPT = 0x0 - ALG_OP_ENCRYPT = 0x1 - ALG_SET_AEAD_ASSOCLEN = 0x4 - ALG_SET_AEAD_AUTHSIZE = 0x5 - ALG_SET_IV = 0x2 - ALG_SET_KEY = 0x1 - ALG_SET_OP = 0x3 - ARPHRD_6LOWPAN = 0x339 - ARPHRD_ADAPT = 0x108 - ARPHRD_APPLETLK = 0x8 - ARPHRD_ARCNET = 0x7 - ARPHRD_ASH = 0x30d - ARPHRD_ATM = 0x13 - ARPHRD_AX25 = 0x3 - ARPHRD_BIF = 0x307 - ARPHRD_CAIF = 0x336 - ARPHRD_CAN = 0x118 - ARPHRD_CHAOS = 0x5 - ARPHRD_CISCO = 0x201 - ARPHRD_CSLIP = 0x101 - ARPHRD_CSLIP6 = 0x103 - ARPHRD_DDCMP = 0x205 - ARPHRD_DLCI = 0xf - ARPHRD_ECONET = 0x30e - ARPHRD_EETHER = 0x2 - ARPHRD_ETHER = 0x1 - ARPHRD_EUI64 = 0x1b - ARPHRD_FCAL = 0x311 - ARPHRD_FCFABRIC = 0x313 - ARPHRD_FCPL = 0x312 - ARPHRD_FCPP = 0x310 - ARPHRD_FDDI = 0x306 - ARPHRD_FRAD = 0x302 - ARPHRD_HDLC = 0x201 - ARPHRD_HIPPI = 0x30c - ARPHRD_HWX25 = 0x110 - ARPHRD_IEEE1394 = 0x18 - ARPHRD_IEEE802 = 0x6 - ARPHRD_IEEE80211 = 0x321 - ARPHRD_IEEE80211_PRISM = 0x322 - ARPHRD_IEEE80211_RADIOTAP = 0x323 - ARPHRD_IEEE802154 = 0x324 - ARPHRD_IEEE802154_MONITOR = 0x325 - ARPHRD_IEEE802_TR = 0x320 - ARPHRD_INFINIBAND = 0x20 - ARPHRD_IP6GRE = 0x337 - ARPHRD_IPDDP = 0x309 - ARPHRD_IPGRE = 0x30a - ARPHRD_IRDA = 0x30f - ARPHRD_LAPB = 0x204 - ARPHRD_LOCALTLK = 0x305 - ARPHRD_LOOPBACK = 0x304 - ARPHRD_METRICOM = 0x17 - ARPHRD_NETLINK = 0x338 - ARPHRD_NETROM = 0x0 - ARPHRD_NONE = 0xfffe - ARPHRD_PHONET = 0x334 - ARPHRD_PHONET_PIPE = 0x335 - ARPHRD_PIMREG = 0x30b - ARPHRD_PPP = 0x200 - ARPHRD_PRONET = 0x4 - ARPHRD_RAWHDLC = 0x206 - ARPHRD_ROSE = 0x10e - ARPHRD_RSRVD = 0x104 - ARPHRD_SIT = 0x308 - ARPHRD_SKIP = 0x303 - ARPHRD_SLIP = 0x100 - ARPHRD_SLIP6 = 0x102 - ARPHRD_TUNNEL = 0x300 - ARPHRD_TUNNEL6 = 0x301 - ARPHRD_VOID = 0xffff - ARPHRD_X25 = 0x10f - ASI_LEON_DFLUSH = 0x11 - ASI_LEON_IFLUSH = 0x10 - ASI_LEON_MMUFLUSH = 0x18 - B0 = 0x0 - B1000000 = 0x100c - B110 = 0x3 - B115200 = 0x1002 - B1152000 = 0x100d - B1200 = 0x9 - B134 = 0x4 - B150 = 0x5 - B1500000 = 0x100e - B153600 = 0x1006 - B1800 = 0xa - B19200 = 0xe - B200 = 0x6 - B2000000 = 0x100f - B230400 = 0x1003 - B2400 = 0xb - B300 = 0x7 - B307200 = 0x1007 - B38400 = 0xf - B460800 = 0x1004 - B4800 = 0xc - B50 = 0x1 - B500000 = 0x100a - B57600 = 0x1001 - B576000 = 0x100b - B600 = 0x8 - B614400 = 0x1008 - B75 = 0x2 - B76800 = 0x1005 - B921600 = 0x1009 - B9600 = 0xd - BLKBSZGET = 0x80081270 - BLKBSZSET = 0x40081271 - BLKFLSBUF = 0x1261 - BLKFRAGET = 0x1265 - BLKFRASET = 0x1264 - BLKGETSIZE = 0x1260 - BLKGETSIZE64 = 0x80081272 - BLKRAGET = 0x1263 - BLKRASET = 0x1262 - BLKROGET = 0x125e - BLKROSET = 0x125d - BLKRRPART = 0x125f - BLKSECTGET = 0x1267 - BLKSECTSET = 0x1266 - BLKSSZGET = 0x1268 - BOTHER = 0x1000 - BPF_A = 0x10 - BPF_ABS = 0x20 - BPF_ADD = 0x0 - BPF_ALU = 0x4 - BPF_AND = 0x50 - BPF_B = 0x10 - BPF_DIV = 0x30 - BPF_H = 0x8 - BPF_IMM = 0x0 - BPF_IND = 0x40 - BPF_JA = 0x0 - BPF_JEQ = 0x10 - BPF_JGE = 0x30 - BPF_JGT = 0x20 - BPF_JMP = 0x5 - BPF_JSET = 0x40 - BPF_K = 0x0 - BPF_LD = 0x0 - BPF_LDX = 0x1 - BPF_LEN = 0x80 - BPF_LL_OFF = -0x200000 - BPF_LSH = 0x60 - BPF_MAJOR_VERSION = 0x1 - BPF_MAXINSNS = 0x1000 - BPF_MEM = 0x60 - BPF_MEMWORDS = 0x10 - BPF_MINOR_VERSION = 0x1 - BPF_MISC = 0x7 - BPF_MOD = 0x90 - BPF_MSH = 0xa0 - BPF_MUL = 0x20 - BPF_NEG = 0x80 - BPF_NET_OFF = -0x100000 - BPF_OR = 0x40 - BPF_RET = 0x6 - BPF_RSH = 0x70 - BPF_ST = 0x2 - BPF_STX = 0x3 - BPF_SUB = 0x10 - BPF_TAX = 0x0 - BPF_TXA = 0x80 - BPF_W = 0x0 - BPF_X = 0x8 - BPF_XOR = 0xa0 - BRKINT = 0x2 - BS0 = 0x0 - BS1 = 0x2000 - BSDLY = 0x2000 - CAN_BCM = 0x2 - CAN_EFF_FLAG = 0x80000000 - CAN_EFF_ID_BITS = 0x1d - CAN_EFF_MASK = 0x1fffffff - CAN_ERR_FLAG = 0x20000000 - CAN_ERR_MASK = 0x1fffffff - CAN_INV_FILTER = 0x20000000 - CAN_ISOTP = 0x6 - CAN_MAX_DLC = 0x8 - CAN_MAX_DLEN = 0x8 - CAN_MCNET = 0x5 - CAN_MTU = 0x10 - CAN_NPROTO = 0x7 - CAN_RAW = 0x1 - CAN_RTR_FLAG = 0x40000000 - CAN_SFF_ID_BITS = 0xb - CAN_SFF_MASK = 0x7ff - CAN_TP16 = 0x3 - CAN_TP20 = 0x4 - CBAUD = 0x100f - CBAUDEX = 0x1000 - CFLUSH = 0xf - CIBAUD = 0x100f0000 - CLOCAL = 0x800 - CLOCK_BOOTTIME = 0x7 - CLOCK_BOOTTIME_ALARM = 0x9 - CLOCK_DEFAULT = 0x0 - CLOCK_EXT = 0x1 - CLOCK_INT = 0x2 - CLOCK_MONOTONIC = 0x1 - CLOCK_MONOTONIC_COARSE = 0x6 - CLOCK_MONOTONIC_RAW = 0x4 - CLOCK_PROCESS_CPUTIME_ID = 0x2 - CLOCK_REALTIME = 0x0 - CLOCK_REALTIME_ALARM = 0x8 - CLOCK_REALTIME_COARSE = 0x5 - CLOCK_TAI = 0xb - CLOCK_THREAD_CPUTIME_ID = 0x3 - CLOCK_TXFROMRX = 0x4 - CLOCK_TXINT = 0x3 - CLONE_CHILD_CLEARTID = 0x200000 - CLONE_CHILD_SETTID = 0x1000000 - CLONE_DETACHED = 0x400000 - CLONE_FILES = 0x400 - CLONE_FS = 0x200 - CLONE_IO = 0x80000000 - CLONE_NEWCGROUP = 0x2000000 - CLONE_NEWIPC = 0x8000000 - CLONE_NEWNET = 0x40000000 - CLONE_NEWNS = 0x20000 - CLONE_NEWPID = 0x20000000 - CLONE_NEWUSER = 0x10000000 - CLONE_NEWUTS = 0x4000000 - CLONE_PARENT = 0x8000 - CLONE_PARENT_SETTID = 0x100000 - CLONE_PTRACE = 0x2000 - CLONE_SETTLS = 0x80000 - CLONE_SIGHAND = 0x800 - CLONE_SYSVSEM = 0x40000 - CLONE_THREAD = 0x10000 - CLONE_UNTRACED = 0x800000 - CLONE_VFORK = 0x4000 - CLONE_VM = 0x100 - CMSPAR = 0x40000000 - CR0 = 0x0 - CR1 = 0x200 - CR2 = 0x400 - CR3 = 0x600 - CRDLY = 0x600 - CREAD = 0x80 - CRTSCTS = 0x80000000 - CS5 = 0x0 - CS6 = 0x10 - CS7 = 0x20 - CS8 = 0x30 - CSIGNAL = 0xff - CSIZE = 0x30 - CSTART = 0x11 - CSTATUS = 0x0 - CSTOP = 0x13 - CSTOPB = 0x40 - CSUSP = 0x1a - DT_BLK = 0x6 - DT_CHR = 0x2 - DT_DIR = 0x4 - DT_FIFO = 0x1 - DT_LNK = 0xa - DT_REG = 0x8 - DT_SOCK = 0xc - DT_UNKNOWN = 0x0 - DT_WHT = 0xe - ECHO = 0x8 - ECHOCTL = 0x200 - ECHOE = 0x10 - ECHOK = 0x20 - ECHOKE = 0x800 - ECHONL = 0x40 - ECHOPRT = 0x400 - EMT_TAGOVF = 0x1 - ENCODING_DEFAULT = 0x0 - ENCODING_FM_MARK = 0x3 - ENCODING_FM_SPACE = 0x4 - ENCODING_MANCHESTER = 0x5 - ENCODING_NRZ = 0x1 - ENCODING_NRZI = 0x2 - EPOLLERR = 0x8 - EPOLLET = 0x80000000 - EPOLLEXCLUSIVE = 0x10000000 - EPOLLHUP = 0x10 - EPOLLIN = 0x1 - EPOLLMSG = 0x400 - EPOLLONESHOT = 0x40000000 - EPOLLOUT = 0x4 - EPOLLPRI = 0x2 - EPOLLRDBAND = 0x80 - EPOLLRDHUP = 0x2000 - EPOLLRDNORM = 0x40 - EPOLLWAKEUP = 0x20000000 - EPOLLWRBAND = 0x200 - EPOLLWRNORM = 0x100 - EPOLL_CLOEXEC = 0x400000 - EPOLL_CTL_ADD = 0x1 - EPOLL_CTL_DEL = 0x2 - EPOLL_CTL_MOD = 0x3 - ETH_P_1588 = 0x88f7 - ETH_P_8021AD = 0x88a8 - ETH_P_8021AH = 0x88e7 - ETH_P_8021Q = 0x8100 - ETH_P_80221 = 0x8917 - ETH_P_802_2 = 0x4 - ETH_P_802_3 = 0x1 - ETH_P_802_3_MIN = 0x600 - ETH_P_802_EX1 = 0x88b5 - ETH_P_AARP = 0x80f3 - ETH_P_AF_IUCV = 0xfbfb - ETH_P_ALL = 0x3 - ETH_P_AOE = 0x88a2 - ETH_P_ARCNET = 0x1a - ETH_P_ARP = 0x806 - ETH_P_ATALK = 0x809b - ETH_P_ATMFATE = 0x8884 - ETH_P_ATMMPOA = 0x884c - ETH_P_AX25 = 0x2 - ETH_P_BATMAN = 0x4305 - ETH_P_BPQ = 0x8ff - ETH_P_CAIF = 0xf7 - ETH_P_CAN = 0xc - ETH_P_CANFD = 0xd - ETH_P_CONTROL = 0x16 - ETH_P_CUST = 0x6006 - ETH_P_DDCMP = 0x6 - ETH_P_DEC = 0x6000 - ETH_P_DIAG = 0x6005 - ETH_P_DNA_DL = 0x6001 - ETH_P_DNA_RC = 0x6002 - ETH_P_DNA_RT = 0x6003 - ETH_P_DSA = 0x1b - ETH_P_ECONET = 0x18 - ETH_P_EDSA = 0xdada - ETH_P_FCOE = 0x8906 - ETH_P_FIP = 0x8914 - ETH_P_HDLC = 0x19 - ETH_P_HSR = 0x892f - ETH_P_IEEE802154 = 0xf6 - ETH_P_IEEEPUP = 0xa00 - ETH_P_IEEEPUPAT = 0xa01 - ETH_P_IP = 0x800 - ETH_P_IPV6 = 0x86dd - ETH_P_IPX = 0x8137 - ETH_P_IRDA = 0x17 - ETH_P_LAT = 0x6004 - ETH_P_LINK_CTL = 0x886c - ETH_P_LOCALTALK = 0x9 - ETH_P_LOOP = 0x60 - ETH_P_LOOPBACK = 0x9000 - ETH_P_MACSEC = 0x88e5 - ETH_P_MOBITEX = 0x15 - ETH_P_MPLS_MC = 0x8848 - ETH_P_MPLS_UC = 0x8847 - ETH_P_MVRP = 0x88f5 - ETH_P_PAE = 0x888e - ETH_P_PAUSE = 0x8808 - ETH_P_PHONET = 0xf5 - ETH_P_PPPTALK = 0x10 - ETH_P_PPP_DISC = 0x8863 - ETH_P_PPP_MP = 0x8 - ETH_P_PPP_SES = 0x8864 - ETH_P_PRP = 0x88fb - ETH_P_PUP = 0x200 - ETH_P_PUPAT = 0x201 - ETH_P_QINQ1 = 0x9100 - ETH_P_QINQ2 = 0x9200 - ETH_P_QINQ3 = 0x9300 - ETH_P_RARP = 0x8035 - ETH_P_SCA = 0x6007 - ETH_P_SLOW = 0x8809 - ETH_P_SNAP = 0x5 - ETH_P_TDLS = 0x890d - ETH_P_TEB = 0x6558 - ETH_P_TIPC = 0x88ca - ETH_P_TRAILER = 0x1c - ETH_P_TR_802_2 = 0x11 - ETH_P_TSN = 0x22f0 - ETH_P_WAN_PPP = 0x7 - ETH_P_WCCP = 0x883e - ETH_P_X25 = 0x805 - ETH_P_XDSA = 0xf8 - EXTA = 0xe - EXTB = 0xf - EXTPROC = 0x10000 - FALLOC_FL_COLLAPSE_RANGE = 0x8 - FALLOC_FL_INSERT_RANGE = 0x20 - FALLOC_FL_KEEP_SIZE = 0x1 - FALLOC_FL_NO_HIDE_STALE = 0x4 - FALLOC_FL_PUNCH_HOLE = 0x2 - FALLOC_FL_ZERO_RANGE = 0x10 - FD_CLOEXEC = 0x1 - FD_SETSIZE = 0x400 - FF0 = 0x0 - FF1 = 0x8000 - FFDLY = 0x8000 - FLUSHO = 0x2000 - F_DUPFD = 0x0 - F_DUPFD_CLOEXEC = 0x406 - F_EXLCK = 0x4 - F_GETFD = 0x1 - F_GETFL = 0x3 - F_GETLEASE = 0x401 - F_GETLK = 0x7 - F_GETLK64 = 0x7 - F_GETOWN = 0x5 - F_GETOWN_EX = 0x10 - F_GETPIPE_SZ = 0x408 - F_GETSIG = 0xb - F_LOCK = 0x1 - F_NOTIFY = 0x402 - F_OFD_GETLK = 0x24 - F_OFD_SETLK = 0x25 - F_OFD_SETLKW = 0x26 - F_OK = 0x0 - F_RDLCK = 0x1 - F_SETFD = 0x2 - F_SETFL = 0x4 - F_SETLEASE = 0x400 - F_SETLK = 0x8 - F_SETLK64 = 0x8 - F_SETLKW = 0x9 - F_SETLKW64 = 0x9 - F_SETOWN = 0x6 - F_SETOWN_EX = 0xf - F_SETPIPE_SZ = 0x407 - F_SETSIG = 0xa - F_SHLCK = 0x8 - F_TEST = 0x3 - F_TLOCK = 0x2 - F_ULOCK = 0x0 - F_UNLCK = 0x3 - F_WRLCK = 0x2 - GRND_NONBLOCK = 0x1 - GRND_RANDOM = 0x2 - HUPCL = 0x400 - IBSHIFT = 0x10 - ICANON = 0x2 - ICMPV6_FILTER = 0x1 - ICRNL = 0x100 - IEXTEN = 0x8000 - IFA_F_DADFAILED = 0x8 - IFA_F_DEPRECATED = 0x20 - IFA_F_HOMEADDRESS = 0x10 - IFA_F_MANAGETEMPADDR = 0x100 - IFA_F_MCAUTOJOIN = 0x400 - IFA_F_NODAD = 0x2 - IFA_F_NOPREFIXROUTE = 0x200 - IFA_F_OPTIMISTIC = 0x4 - IFA_F_PERMANENT = 0x80 - IFA_F_SECONDARY = 0x1 - IFA_F_STABLE_PRIVACY = 0x800 - IFA_F_TEMPORARY = 0x1 - IFA_F_TENTATIVE = 0x40 - IFA_MAX = 0x8 - IFF_ALLMULTI = 0x200 - IFF_ATTACH_QUEUE = 0x200 - IFF_AUTOMEDIA = 0x4000 - IFF_BROADCAST = 0x2 - IFF_DEBUG = 0x4 - IFF_DETACH_QUEUE = 0x400 - IFF_DORMANT = 0x20000 - IFF_DYNAMIC = 0x8000 - IFF_ECHO = 0x40000 - IFF_LOOPBACK = 0x8 - IFF_LOWER_UP = 0x10000 - IFF_MASTER = 0x400 - IFF_MULTICAST = 0x1000 - IFF_MULTI_QUEUE = 0x100 - IFF_NOARP = 0x80 - IFF_NOFILTER = 0x1000 - IFF_NOTRAILERS = 0x20 - IFF_NO_PI = 0x1000 - IFF_ONE_QUEUE = 0x2000 - IFF_PERSIST = 0x800 - IFF_POINTOPOINT = 0x10 - IFF_PORTSEL = 0x2000 - IFF_PROMISC = 0x100 - IFF_RUNNING = 0x40 - IFF_SLAVE = 0x800 - IFF_TAP = 0x2 - IFF_TUN = 0x1 - IFF_TUN_EXCL = 0x8000 - IFF_UP = 0x1 - IFF_VNET_HDR = 0x4000 - IFF_VOLATILE = 0x70c5a - IFNAMSIZ = 0x10 - IGNBRK = 0x1 - IGNCR = 0x80 - IGNPAR = 0x4 - IMAXBEL = 0x2000 - INLCR = 0x40 - INPCK = 0x10 - IN_ACCESS = 0x1 - IN_ALL_EVENTS = 0xfff - IN_ATTRIB = 0x4 - IN_CLASSA_HOST = 0xffffff - IN_CLASSA_MAX = 0x80 - IN_CLASSA_NET = 0xff000000 - IN_CLASSA_NSHIFT = 0x18 - IN_CLASSB_HOST = 0xffff - IN_CLASSB_MAX = 0x10000 - IN_CLASSB_NET = 0xffff0000 - IN_CLASSB_NSHIFT = 0x10 - IN_CLASSC_HOST = 0xff - IN_CLASSC_NET = 0xffffff00 - IN_CLASSC_NSHIFT = 0x8 - IN_CLOEXEC = 0x400000 - IN_CLOSE = 0x18 - IN_CLOSE_NOWRITE = 0x10 - IN_CLOSE_WRITE = 0x8 - IN_CREATE = 0x100 - IN_DELETE = 0x200 - IN_DELETE_SELF = 0x400 - IN_DONT_FOLLOW = 0x2000000 - IN_EXCL_UNLINK = 0x4000000 - IN_IGNORED = 0x8000 - IN_ISDIR = 0x40000000 - IN_LOOPBACKNET = 0x7f - IN_MASK_ADD = 0x20000000 - IN_MODIFY = 0x2 - IN_MOVE = 0xc0 - IN_MOVED_FROM = 0x40 - IN_MOVED_TO = 0x80 - IN_MOVE_SELF = 0x800 - IN_NONBLOCK = 0x4000 - IN_ONESHOT = 0x80000000 - IN_ONLYDIR = 0x1000000 - IN_OPEN = 0x20 - IN_Q_OVERFLOW = 0x4000 - IN_UNMOUNT = 0x2000 - IPPROTO_AH = 0x33 - IPPROTO_BEETPH = 0x5e - IPPROTO_COMP = 0x6c - IPPROTO_DCCP = 0x21 - IPPROTO_DSTOPTS = 0x3c - IPPROTO_EGP = 0x8 - IPPROTO_ENCAP = 0x62 - IPPROTO_ESP = 0x32 - IPPROTO_FRAGMENT = 0x2c - IPPROTO_GRE = 0x2f - IPPROTO_HOPOPTS = 0x0 - IPPROTO_ICMP = 0x1 - IPPROTO_ICMPV6 = 0x3a - IPPROTO_IDP = 0x16 - IPPROTO_IGMP = 0x2 - IPPROTO_IP = 0x0 - IPPROTO_IPIP = 0x4 - IPPROTO_IPV6 = 0x29 - IPPROTO_MH = 0x87 - IPPROTO_MPLS = 0x89 - IPPROTO_MTP = 0x5c - IPPROTO_NONE = 0x3b - IPPROTO_PIM = 0x67 - IPPROTO_PUP = 0xc - IPPROTO_RAW = 0xff - IPPROTO_ROUTING = 0x2b - IPPROTO_RSVP = 0x2e - IPPROTO_SCTP = 0x84 - IPPROTO_TCP = 0x6 - IPPROTO_TP = 0x1d - IPPROTO_UDP = 0x11 - IPPROTO_UDPLITE = 0x88 - IPV6_2292DSTOPTS = 0x4 - IPV6_2292HOPLIMIT = 0x8 - IPV6_2292HOPOPTS = 0x3 - IPV6_2292PKTINFO = 0x2 - IPV6_2292PKTOPTIONS = 0x6 - IPV6_2292RTHDR = 0x5 - IPV6_ADDRFORM = 0x1 - IPV6_ADD_MEMBERSHIP = 0x14 - IPV6_AUTHHDR = 0xa - IPV6_CHECKSUM = 0x7 - IPV6_DONTFRAG = 0x3e - IPV6_DROP_MEMBERSHIP = 0x15 - IPV6_DSTOPTS = 0x3b - IPV6_HDRINCL = 0x24 - IPV6_HOPLIMIT = 0x34 - IPV6_HOPOPTS = 0x36 - IPV6_IPSEC_POLICY = 0x22 - IPV6_JOIN_ANYCAST = 0x1b - IPV6_JOIN_GROUP = 0x14 - IPV6_LEAVE_ANYCAST = 0x1c - IPV6_LEAVE_GROUP = 0x15 - IPV6_MTU = 0x18 - IPV6_MTU_DISCOVER = 0x17 - IPV6_MULTICAST_HOPS = 0x12 - IPV6_MULTICAST_IF = 0x11 - IPV6_MULTICAST_LOOP = 0x13 - IPV6_NEXTHOP = 0x9 - IPV6_PATHMTU = 0x3d - IPV6_PKTINFO = 0x32 - IPV6_PMTUDISC_DO = 0x2 - IPV6_PMTUDISC_DONT = 0x0 - IPV6_PMTUDISC_INTERFACE = 0x4 - IPV6_PMTUDISC_OMIT = 0x5 - IPV6_PMTUDISC_PROBE = 0x3 - IPV6_PMTUDISC_WANT = 0x1 - IPV6_RECVDSTOPTS = 0x3a - IPV6_RECVERR = 0x19 - IPV6_RECVHOPLIMIT = 0x33 - IPV6_RECVHOPOPTS = 0x35 - IPV6_RECVPATHMTU = 0x3c - IPV6_RECVPKTINFO = 0x31 - IPV6_RECVRTHDR = 0x38 - IPV6_RECVTCLASS = 0x42 - IPV6_ROUTER_ALERT = 0x16 - IPV6_RTHDR = 0x39 - IPV6_RTHDRDSTOPTS = 0x37 - IPV6_RTHDR_LOOSE = 0x0 - IPV6_RTHDR_STRICT = 0x1 - IPV6_RTHDR_TYPE_0 = 0x0 - IPV6_RXDSTOPTS = 0x3b - IPV6_RXHOPOPTS = 0x36 - IPV6_TCLASS = 0x43 - IPV6_UNICAST_HOPS = 0x10 - IPV6_V6ONLY = 0x1a - IPV6_XFRM_POLICY = 0x23 - IP_ADD_MEMBERSHIP = 0x23 - IP_ADD_SOURCE_MEMBERSHIP = 0x27 - IP_BIND_ADDRESS_NO_PORT = 0x18 - IP_BLOCK_SOURCE = 0x26 - IP_CHECKSUM = 0x17 - IP_DEFAULT_MULTICAST_LOOP = 0x1 - IP_DEFAULT_MULTICAST_TTL = 0x1 - IP_DF = 0x4000 - IP_DROP_MEMBERSHIP = 0x24 - IP_DROP_SOURCE_MEMBERSHIP = 0x28 - IP_FREEBIND = 0xf - IP_HDRINCL = 0x3 - IP_IPSEC_POLICY = 0x10 - IP_MAXPACKET = 0xffff - IP_MAX_MEMBERSHIPS = 0x14 - IP_MF = 0x2000 - IP_MINTTL = 0x15 - IP_MSFILTER = 0x29 - IP_MSS = 0x240 - IP_MTU = 0xe - IP_MTU_DISCOVER = 0xa - IP_MULTICAST_ALL = 0x31 - IP_MULTICAST_IF = 0x20 - IP_MULTICAST_LOOP = 0x22 - IP_MULTICAST_TTL = 0x21 - IP_NODEFRAG = 0x16 - IP_OFFMASK = 0x1fff - IP_OPTIONS = 0x4 - IP_ORIGDSTADDR = 0x14 - IP_PASSSEC = 0x12 - IP_PKTINFO = 0x8 - IP_PKTOPTIONS = 0x9 - IP_PMTUDISC = 0xa - IP_PMTUDISC_DO = 0x2 - IP_PMTUDISC_DONT = 0x0 - IP_PMTUDISC_INTERFACE = 0x4 - IP_PMTUDISC_OMIT = 0x5 - IP_PMTUDISC_PROBE = 0x3 - IP_PMTUDISC_WANT = 0x1 - IP_RECVERR = 0xb - IP_RECVOPTS = 0x6 - IP_RECVORIGDSTADDR = 0x14 - IP_RECVRETOPTS = 0x7 - IP_RECVTOS = 0xd - IP_RECVTTL = 0xc - IP_RETOPTS = 0x7 - IP_RF = 0x8000 - IP_ROUTER_ALERT = 0x5 - IP_TOS = 0x1 - IP_TRANSPARENT = 0x13 - IP_TTL = 0x2 - IP_UNBLOCK_SOURCE = 0x25 - IP_UNICAST_IF = 0x32 - IP_XFRM_POLICY = 0x11 - ISIG = 0x1 - ISTRIP = 0x20 - IUCLC = 0x200 - IUTF8 = 0x4000 - IXANY = 0x800 - IXOFF = 0x1000 - IXON = 0x400 - LINUX_REBOOT_CMD_CAD_OFF = 0x0 - LINUX_REBOOT_CMD_CAD_ON = 0x89abcdef - LINUX_REBOOT_CMD_HALT = 0xcdef0123 - LINUX_REBOOT_CMD_KEXEC = 0x45584543 - LINUX_REBOOT_CMD_POWER_OFF = 0x4321fedc - LINUX_REBOOT_CMD_RESTART = 0x1234567 - LINUX_REBOOT_CMD_RESTART2 = 0xa1b2c3d4 - LINUX_REBOOT_CMD_SW_SUSPEND = 0xd000fce2 - LINUX_REBOOT_MAGIC1 = 0xfee1dead - LINUX_REBOOT_MAGIC2 = 0x28121969 - LOCK_EX = 0x2 - LOCK_NB = 0x4 - LOCK_SH = 0x1 - LOCK_UN = 0x8 - MADV_DODUMP = 0x11 - MADV_DOFORK = 0xb - MADV_DONTDUMP = 0x10 - MADV_DONTFORK = 0xa - MADV_DONTNEED = 0x4 - MADV_FREE = 0x8 - MADV_HUGEPAGE = 0xe - MADV_HWPOISON = 0x64 - MADV_MERGEABLE = 0xc - MADV_NOHUGEPAGE = 0xf - MADV_NORMAL = 0x0 - MADV_RANDOM = 0x1 - MADV_REMOVE = 0x9 - MADV_SEQUENTIAL = 0x2 - MADV_UNMERGEABLE = 0xd - MADV_WILLNEED = 0x3 - MAP_ANON = 0x20 - MAP_ANONYMOUS = 0x20 - MAP_DENYWRITE = 0x800 - MAP_EXECUTABLE = 0x1000 - MAP_FILE = 0x0 - MAP_FIXED = 0x10 - MAP_GROWSDOWN = 0x200 - MAP_HUGETLB = 0x40000 - MAP_HUGE_MASK = 0x3f - MAP_HUGE_SHIFT = 0x1a - MAP_LOCKED = 0x100 - MAP_NONBLOCK = 0x10000 - MAP_NORESERVE = 0x40 - MAP_POPULATE = 0x8000 - MAP_PRIVATE = 0x2 - MAP_RENAME = 0x20 - MAP_SHARED = 0x1 - MAP_STACK = 0x20000 - MAP_TYPE = 0xf - MCL_CURRENT = 0x2000 - MCL_FUTURE = 0x4000 - MCL_ONFAULT = 0x8000 - MNT_DETACH = 0x2 - MNT_EXPIRE = 0x4 - MNT_FORCE = 0x1 - MSG_BATCH = 0x40000 - MSG_CMSG_CLOEXEC = 0x40000000 - MSG_CONFIRM = 0x800 - MSG_CTRUNC = 0x8 - MSG_DONTROUTE = 0x4 - MSG_DONTWAIT = 0x40 - MSG_EOR = 0x80 - MSG_ERRQUEUE = 0x2000 - MSG_FASTOPEN = 0x20000000 - MSG_FIN = 0x200 - MSG_MORE = 0x8000 - MSG_NOSIGNAL = 0x4000 - MSG_OOB = 0x1 - MSG_PEEK = 0x2 - MSG_PROXY = 0x10 - MSG_RST = 0x1000 - MSG_SYN = 0x400 - MSG_TRUNC = 0x20 - MSG_TRYHARD = 0x4 - MSG_WAITALL = 0x100 - MSG_WAITFORONE = 0x10000 - MS_ACTIVE = 0x40000000 - MS_ASYNC = 0x1 - MS_BIND = 0x1000 - MS_DIRSYNC = 0x80 - MS_INVALIDATE = 0x2 - MS_I_VERSION = 0x800000 - MS_KERNMOUNT = 0x400000 - MS_LAZYTIME = 0x2000000 - MS_MANDLOCK = 0x40 - MS_MGC_MSK = 0xffff0000 - MS_MGC_VAL = 0xc0ed0000 - MS_MOVE = 0x2000 - MS_NOATIME = 0x400 - MS_NODEV = 0x4 - MS_NODIRATIME = 0x800 - MS_NOEXEC = 0x8 - MS_NOSUID = 0x2 - MS_NOUSER = -0x80000000 - MS_POSIXACL = 0x10000 - MS_PRIVATE = 0x40000 - MS_RDONLY = 0x1 - MS_REC = 0x4000 - MS_RELATIME = 0x200000 - MS_REMOUNT = 0x20 - MS_RMT_MASK = 0x2800051 - MS_SHARED = 0x100000 - MS_SILENT = 0x8000 - MS_SLAVE = 0x80000 - MS_STRICTATIME = 0x1000000 - MS_SYNC = 0x4 - MS_SYNCHRONOUS = 0x10 - MS_UNBINDABLE = 0x20000 - NAME_MAX = 0xff - NETLINK_ADD_MEMBERSHIP = 0x1 - NETLINK_AUDIT = 0x9 - NETLINK_BROADCAST_ERROR = 0x4 - NETLINK_CAP_ACK = 0xa - NETLINK_CONNECTOR = 0xb - NETLINK_CRYPTO = 0x15 - NETLINK_DNRTMSG = 0xe - NETLINK_DROP_MEMBERSHIP = 0x2 - NETLINK_ECRYPTFS = 0x13 - NETLINK_FIB_LOOKUP = 0xa - NETLINK_FIREWALL = 0x3 - NETLINK_GENERIC = 0x10 - NETLINK_INET_DIAG = 0x4 - NETLINK_IP6_FW = 0xd - NETLINK_ISCSI = 0x8 - NETLINK_KOBJECT_UEVENT = 0xf - NETLINK_LISTEN_ALL_NSID = 0x8 - NETLINK_LIST_MEMBERSHIPS = 0x9 - NETLINK_NETFILTER = 0xc - NETLINK_NFLOG = 0x5 - NETLINK_NO_ENOBUFS = 0x5 - NETLINK_PKTINFO = 0x3 - NETLINK_RDMA = 0x14 - NETLINK_ROUTE = 0x0 - NETLINK_RX_RING = 0x6 - NETLINK_SCSITRANSPORT = 0x12 - NETLINK_SELINUX = 0x7 - NETLINK_SOCK_DIAG = 0x4 - NETLINK_TX_RING = 0x7 - NETLINK_UNUSED = 0x1 - NETLINK_USERSOCK = 0x2 - NETLINK_XFRM = 0x6 - NL0 = 0x0 - NL1 = 0x100 - NLA_ALIGNTO = 0x4 - NLA_F_NESTED = 0x8000 - NLA_F_NET_BYTEORDER = 0x4000 - NLA_HDRLEN = 0x4 - NLDLY = 0x100 - NLMSG_ALIGNTO = 0x4 - NLMSG_DONE = 0x3 - NLMSG_ERROR = 0x2 - NLMSG_HDRLEN = 0x10 - NLMSG_MIN_TYPE = 0x10 - NLMSG_NOOP = 0x1 - NLMSG_OVERRUN = 0x4 - NLM_F_ACK = 0x4 - NLM_F_APPEND = 0x800 - NLM_F_ATOMIC = 0x400 - NLM_F_CREATE = 0x400 - NLM_F_DUMP = 0x300 - NLM_F_DUMP_FILTERED = 0x20 - NLM_F_DUMP_INTR = 0x10 - NLM_F_ECHO = 0x8 - NLM_F_EXCL = 0x200 - NLM_F_MATCH = 0x200 - NLM_F_MULTI = 0x2 - NLM_F_REPLACE = 0x100 - NLM_F_REQUEST = 0x1 - NLM_F_ROOT = 0x100 - NOFLSH = 0x80 - OCRNL = 0x8 - OFDEL = 0x80 - OFILL = 0x40 - OLCUC = 0x2 - ONLCR = 0x4 - ONLRET = 0x20 - ONOCR = 0x10 - OPOST = 0x1 - O_ACCMODE = 0x3 - O_APPEND = 0x8 - O_ASYNC = 0x40 - O_CLOEXEC = 0x400000 - O_CREAT = 0x200 - O_DIRECT = 0x100000 - O_DIRECTORY = 0x10000 - O_DSYNC = 0x2000 - O_EXCL = 0x800 - O_FSYNC = 0x802000 - O_LARGEFILE = 0x0 - O_NDELAY = 0x4004 - O_NOATIME = 0x200000 - O_NOCTTY = 0x8000 - O_NOFOLLOW = 0x20000 - O_NONBLOCK = 0x4000 - O_PATH = 0x1000000 - O_RDONLY = 0x0 - O_RDWR = 0x2 - O_RSYNC = 0x802000 - O_SYNC = 0x802000 - O_TMPFILE = 0x2010000 - O_TRUNC = 0x400 - O_WRONLY = 0x1 - PACKET_ADD_MEMBERSHIP = 0x1 - PACKET_AUXDATA = 0x8 - PACKET_BROADCAST = 0x1 - PACKET_COPY_THRESH = 0x7 - PACKET_DROP_MEMBERSHIP = 0x2 - PACKET_FANOUT = 0x12 - PACKET_FANOUT_CBPF = 0x6 - PACKET_FANOUT_CPU = 0x2 - PACKET_FANOUT_DATA = 0x16 - PACKET_FANOUT_EBPF = 0x7 - PACKET_FANOUT_FLAG_DEFRAG = 0x8000 - PACKET_FANOUT_FLAG_ROLLOVER = 0x1000 - PACKET_FANOUT_HASH = 0x0 - PACKET_FANOUT_LB = 0x1 - PACKET_FANOUT_QM = 0x5 - PACKET_FANOUT_RND = 0x4 - PACKET_FANOUT_ROLLOVER = 0x3 - PACKET_FASTROUTE = 0x6 - PACKET_HDRLEN = 0xb - PACKET_HOST = 0x0 - PACKET_KERNEL = 0x7 - PACKET_LOOPBACK = 0x5 - PACKET_LOSS = 0xe - PACKET_MR_ALLMULTI = 0x2 - PACKET_MR_MULTICAST = 0x0 - PACKET_MR_PROMISC = 0x1 - PACKET_MR_UNICAST = 0x3 - PACKET_MULTICAST = 0x2 - PACKET_ORIGDEV = 0x9 - PACKET_OTHERHOST = 0x3 - PACKET_OUTGOING = 0x4 - PACKET_QDISC_BYPASS = 0x14 - PACKET_RECV_OUTPUT = 0x3 - PACKET_RESERVE = 0xc - PACKET_ROLLOVER_STATS = 0x15 - PACKET_RX_RING = 0x5 - PACKET_STATISTICS = 0x6 - PACKET_TIMESTAMP = 0x11 - PACKET_TX_HAS_OFF = 0x13 - PACKET_TX_RING = 0xd - PACKET_TX_TIMESTAMP = 0x10 - PACKET_USER = 0x6 - PACKET_VERSION = 0xa - PACKET_VNET_HDR = 0xf - PARENB = 0x100 - PARITY_CRC16_PR0 = 0x2 - PARITY_CRC16_PR0_CCITT = 0x4 - PARITY_CRC16_PR1 = 0x3 - PARITY_CRC16_PR1_CCITT = 0x5 - PARITY_CRC32_PR0_CCITT = 0x6 - PARITY_CRC32_PR1_CCITT = 0x7 - PARITY_DEFAULT = 0x0 - PARITY_NONE = 0x1 - PARMRK = 0x8 - PARODD = 0x200 - PENDIN = 0x4000 - PRIO_PGRP = 0x1 - PRIO_PROCESS = 0x0 - PRIO_USER = 0x2 - PROT_EXEC = 0x4 - PROT_GROWSDOWN = 0x1000000 - PROT_GROWSUP = 0x2000000 - PROT_NONE = 0x0 - PROT_READ = 0x1 - PROT_WRITE = 0x2 - PR_CAPBSET_DROP = 0x18 - PR_CAPBSET_READ = 0x17 - PR_CAP_AMBIENT = 0x2f - PR_CAP_AMBIENT_CLEAR_ALL = 0x4 - PR_CAP_AMBIENT_IS_SET = 0x1 - PR_CAP_AMBIENT_LOWER = 0x3 - PR_CAP_AMBIENT_RAISE = 0x2 - PR_ENDIAN_BIG = 0x0 - PR_ENDIAN_LITTLE = 0x1 - PR_ENDIAN_PPC_LITTLE = 0x2 - PR_FPEMU_NOPRINT = 0x1 - PR_FPEMU_SIGFPE = 0x2 - PR_FP_EXC_ASYNC = 0x2 - PR_FP_EXC_DISABLED = 0x0 - PR_FP_EXC_DIV = 0x10000 - PR_FP_EXC_INV = 0x100000 - PR_FP_EXC_NONRECOV = 0x1 - PR_FP_EXC_OVF = 0x20000 - PR_FP_EXC_PRECISE = 0x3 - PR_FP_EXC_RES = 0x80000 - PR_FP_EXC_SW_ENABLE = 0x80 - PR_FP_EXC_UND = 0x40000 - PR_FP_MODE_FR = 0x1 - PR_FP_MODE_FRE = 0x2 - PR_GET_CHILD_SUBREAPER = 0x25 - PR_GET_DUMPABLE = 0x3 - PR_GET_ENDIAN = 0x13 - PR_GET_FPEMU = 0x9 - PR_GET_FPEXC = 0xb - PR_GET_FP_MODE = 0x2e - PR_GET_KEEPCAPS = 0x7 - PR_GET_NAME = 0x10 - PR_GET_NO_NEW_PRIVS = 0x27 - PR_GET_PDEATHSIG = 0x2 - PR_GET_SECCOMP = 0x15 - PR_GET_SECUREBITS = 0x1b - PR_GET_THP_DISABLE = 0x2a - PR_GET_TID_ADDRESS = 0x28 - PR_GET_TIMERSLACK = 0x1e - PR_GET_TIMING = 0xd - PR_GET_TSC = 0x19 - PR_GET_UNALIGN = 0x5 - PR_MCE_KILL = 0x21 - PR_MCE_KILL_CLEAR = 0x0 - PR_MCE_KILL_DEFAULT = 0x2 - PR_MCE_KILL_EARLY = 0x1 - PR_MCE_KILL_GET = 0x22 - PR_MCE_KILL_LATE = 0x0 - PR_MCE_KILL_SET = 0x1 - PR_MPX_DISABLE_MANAGEMENT = 0x2c - PR_MPX_ENABLE_MANAGEMENT = 0x2b - PR_SET_CHILD_SUBREAPER = 0x24 - PR_SET_DUMPABLE = 0x4 - PR_SET_ENDIAN = 0x14 - PR_SET_FPEMU = 0xa - PR_SET_FPEXC = 0xc - PR_SET_FP_MODE = 0x2d - PR_SET_KEEPCAPS = 0x8 - PR_SET_MM = 0x23 - PR_SET_MM_ARG_END = 0x9 - PR_SET_MM_ARG_START = 0x8 - PR_SET_MM_AUXV = 0xc - PR_SET_MM_BRK = 0x7 - PR_SET_MM_END_CODE = 0x2 - PR_SET_MM_END_DATA = 0x4 - PR_SET_MM_ENV_END = 0xb - PR_SET_MM_ENV_START = 0xa - PR_SET_MM_EXE_FILE = 0xd - PR_SET_MM_MAP = 0xe - PR_SET_MM_MAP_SIZE = 0xf - PR_SET_MM_START_BRK = 0x6 - PR_SET_MM_START_CODE = 0x1 - PR_SET_MM_START_DATA = 0x3 - PR_SET_MM_START_STACK = 0x5 - PR_SET_NAME = 0xf - PR_SET_NO_NEW_PRIVS = 0x26 - PR_SET_PDEATHSIG = 0x1 - PR_SET_PTRACER = 0x59616d61 - PR_SET_PTRACER_ANY = -0x1 - PR_SET_SECCOMP = 0x16 - PR_SET_SECUREBITS = 0x1c - PR_SET_THP_DISABLE = 0x29 - PR_SET_TIMERSLACK = 0x1d - PR_SET_TIMING = 0xe - PR_SET_TSC = 0x1a - PR_SET_UNALIGN = 0x6 - PR_TASK_PERF_EVENTS_DISABLE = 0x1f - PR_TASK_PERF_EVENTS_ENABLE = 0x20 - PR_TIMING_STATISTICAL = 0x0 - PR_TIMING_TIMESTAMP = 0x1 - PR_TSC_ENABLE = 0x1 - PR_TSC_SIGSEGV = 0x2 - PR_UNALIGN_NOPRINT = 0x1 - PR_UNALIGN_SIGBUS = 0x2 - PTRACE_ATTACH = 0x10 - PTRACE_CONT = 0x7 - PTRACE_DETACH = 0x11 - PTRACE_EVENT_CLONE = 0x3 - PTRACE_EVENT_EXEC = 0x4 - PTRACE_EVENT_EXIT = 0x6 - PTRACE_EVENT_FORK = 0x1 - PTRACE_EVENT_SECCOMP = 0x7 - PTRACE_EVENT_STOP = 0x80 - PTRACE_EVENT_VFORK = 0x2 - PTRACE_EVENT_VFORK_DONE = 0x5 - PTRACE_GETEVENTMSG = 0x4201 - PTRACE_GETFPAREGS = 0x14 - PTRACE_GETFPREGS = 0xe - PTRACE_GETFPREGS64 = 0x19 - PTRACE_GETREGS = 0xc - PTRACE_GETREGS64 = 0x16 - PTRACE_GETREGSET = 0x4204 - PTRACE_GETSIGINFO = 0x4202 - PTRACE_GETSIGMASK = 0x420a - PTRACE_INTERRUPT = 0x4207 - PTRACE_KILL = 0x8 - PTRACE_LISTEN = 0x4208 - PTRACE_O_EXITKILL = 0x100000 - PTRACE_O_MASK = 0x3000ff - PTRACE_O_SUSPEND_SECCOMP = 0x200000 - PTRACE_O_TRACECLONE = 0x8 - PTRACE_O_TRACEEXEC = 0x10 - PTRACE_O_TRACEEXIT = 0x40 - PTRACE_O_TRACEFORK = 0x2 - PTRACE_O_TRACESECCOMP = 0x80 - PTRACE_O_TRACESYSGOOD = 0x1 - PTRACE_O_TRACEVFORK = 0x4 - PTRACE_O_TRACEVFORKDONE = 0x20 - PTRACE_PEEKDATA = 0x2 - PTRACE_PEEKSIGINFO = 0x4209 - PTRACE_PEEKSIGINFO_SHARED = 0x1 - PTRACE_PEEKTEXT = 0x1 - PTRACE_PEEKUSR = 0x3 - PTRACE_POKEDATA = 0x5 - PTRACE_POKETEXT = 0x4 - PTRACE_POKEUSR = 0x6 - PTRACE_READDATA = 0x10 - PTRACE_READTEXT = 0x12 - PTRACE_SECCOMP_GET_FILTER = 0x420c - PTRACE_SEIZE = 0x4206 - PTRACE_SETFPAREGS = 0x15 - PTRACE_SETFPREGS = 0xf - PTRACE_SETFPREGS64 = 0x1a - PTRACE_SETOPTIONS = 0x4200 - PTRACE_SETREGS = 0xd - PTRACE_SETREGS64 = 0x17 - PTRACE_SETREGSET = 0x4205 - PTRACE_SETSIGINFO = 0x4203 - PTRACE_SETSIGMASK = 0x420b - PTRACE_SINGLESTEP = 0x9 - PTRACE_SPARC_DETACH = 0xb - PTRACE_SYSCALL = 0x18 - PTRACE_TRACEME = 0x0 - PTRACE_WRITEDATA = 0x11 - PTRACE_WRITETEXT = 0x13 - PT_FP = 0x48 - PT_G0 = 0x10 - PT_G1 = 0x14 - PT_G2 = 0x18 - PT_G3 = 0x1c - PT_G4 = 0x20 - PT_G5 = 0x24 - PT_G6 = 0x28 - PT_G7 = 0x2c - PT_I0 = 0x30 - PT_I1 = 0x34 - PT_I2 = 0x38 - PT_I3 = 0x3c - PT_I4 = 0x40 - PT_I5 = 0x44 - PT_I6 = 0x48 - PT_I7 = 0x4c - PT_NPC = 0x8 - PT_PC = 0x4 - PT_PSR = 0x0 - PT_REGS_MAGIC = 0x57ac6c00 - PT_TNPC = 0x90 - PT_TPC = 0x88 - PT_TSTATE = 0x80 - PT_V9_FP = 0x70 - PT_V9_G0 = 0x0 - PT_V9_G1 = 0x8 - PT_V9_G2 = 0x10 - PT_V9_G3 = 0x18 - PT_V9_G4 = 0x20 - PT_V9_G5 = 0x28 - PT_V9_G6 = 0x30 - PT_V9_G7 = 0x38 - PT_V9_I0 = 0x40 - PT_V9_I1 = 0x48 - PT_V9_I2 = 0x50 - PT_V9_I3 = 0x58 - PT_V9_I4 = 0x60 - PT_V9_I5 = 0x68 - PT_V9_I6 = 0x70 - PT_V9_I7 = 0x78 - PT_V9_MAGIC = 0x9c - PT_V9_TNPC = 0x90 - PT_V9_TPC = 0x88 - PT_V9_TSTATE = 0x80 - PT_V9_Y = 0x98 - PT_WIM = 0x10 - PT_Y = 0xc - RLIMIT_AS = 0x9 - RLIMIT_CORE = 0x4 - RLIMIT_CPU = 0x0 - RLIMIT_DATA = 0x2 - RLIMIT_FSIZE = 0x1 - RLIMIT_NOFILE = 0x6 - RLIMIT_STACK = 0x3 - RLIM_INFINITY = -0x1 - RTAX_ADVMSS = 0x8 - RTAX_CC_ALGO = 0x10 - RTAX_CWND = 0x7 - RTAX_FEATURES = 0xc - RTAX_FEATURE_ALLFRAG = 0x8 - RTAX_FEATURE_ECN = 0x1 - RTAX_FEATURE_MASK = 0xf - RTAX_FEATURE_SACK = 0x2 - RTAX_FEATURE_TIMESTAMP = 0x4 - RTAX_HOPLIMIT = 0xa - RTAX_INITCWND = 0xb - RTAX_INITRWND = 0xe - RTAX_LOCK = 0x1 - RTAX_MAX = 0x10 - RTAX_MTU = 0x2 - RTAX_QUICKACK = 0xf - RTAX_REORDERING = 0x9 - RTAX_RTO_MIN = 0xd - RTAX_RTT = 0x4 - RTAX_RTTVAR = 0x5 - RTAX_SSTHRESH = 0x6 - RTAX_UNSPEC = 0x0 - RTAX_WINDOW = 0x3 - RTA_ALIGNTO = 0x4 - RTA_MAX = 0x18 - RTCF_DIRECTSRC = 0x4000000 - RTCF_DOREDIRECT = 0x1000000 - RTCF_LOG = 0x2000000 - RTCF_MASQ = 0x400000 - RTCF_NAT = 0x800000 - RTCF_VALVE = 0x200000 - RTF_ADDRCLASSMASK = 0xf8000000 - RTF_ADDRCONF = 0x40000 - RTF_ALLONLINK = 0x20000 - RTF_BROADCAST = 0x10000000 - RTF_CACHE = 0x1000000 - RTF_DEFAULT = 0x10000 - RTF_DYNAMIC = 0x10 - RTF_FLOW = 0x2000000 - RTF_GATEWAY = 0x2 - RTF_HOST = 0x4 - RTF_INTERFACE = 0x40000000 - RTF_IRTT = 0x100 - RTF_LINKRT = 0x100000 - RTF_LOCAL = 0x80000000 - RTF_MODIFIED = 0x20 - RTF_MSS = 0x40 - RTF_MTU = 0x40 - RTF_MULTICAST = 0x20000000 - RTF_NAT = 0x8000000 - RTF_NOFORWARD = 0x1000 - RTF_NONEXTHOP = 0x200000 - RTF_NOPMTUDISC = 0x4000 - RTF_POLICY = 0x4000000 - RTF_REINSTATE = 0x8 - RTF_REJECT = 0x200 - RTF_STATIC = 0x400 - RTF_THROW = 0x2000 - RTF_UP = 0x1 - RTF_WINDOW = 0x80 - RTF_XRESOLVE = 0x800 - RTM_BASE = 0x10 - RTM_DELACTION = 0x31 - RTM_DELADDR = 0x15 - RTM_DELADDRLABEL = 0x49 - RTM_DELLINK = 0x11 - RTM_DELMDB = 0x55 - RTM_DELNEIGH = 0x1d - RTM_DELNSID = 0x59 - RTM_DELQDISC = 0x25 - RTM_DELROUTE = 0x19 - RTM_DELRULE = 0x21 - RTM_DELTCLASS = 0x29 - RTM_DELTFILTER = 0x2d - RTM_F_CLONED = 0x200 - RTM_F_EQUALIZE = 0x400 - RTM_F_LOOKUP_TABLE = 0x1000 - RTM_F_NOTIFY = 0x100 - RTM_F_PREFIX = 0x800 - RTM_GETACTION = 0x32 - RTM_GETADDR = 0x16 - RTM_GETADDRLABEL = 0x4a - RTM_GETANYCAST = 0x3e - RTM_GETDCB = 0x4e - RTM_GETLINK = 0x12 - RTM_GETMDB = 0x56 - RTM_GETMULTICAST = 0x3a - RTM_GETNEIGH = 0x1e - RTM_GETNEIGHTBL = 0x42 - RTM_GETNETCONF = 0x52 - RTM_GETNSID = 0x5a - RTM_GETQDISC = 0x26 - RTM_GETROUTE = 0x1a - RTM_GETRULE = 0x22 - RTM_GETSTATS = 0x5e - RTM_GETTCLASS = 0x2a - RTM_GETTFILTER = 0x2e - RTM_MAX = 0x5f - RTM_NEWACTION = 0x30 - RTM_NEWADDR = 0x14 - RTM_NEWADDRLABEL = 0x48 - RTM_NEWLINK = 0x10 - RTM_NEWMDB = 0x54 - RTM_NEWNDUSEROPT = 0x44 - RTM_NEWNEIGH = 0x1c - RTM_NEWNEIGHTBL = 0x40 - RTM_NEWNETCONF = 0x50 - RTM_NEWNSID = 0x58 - RTM_NEWPREFIX = 0x34 - RTM_NEWQDISC = 0x24 - RTM_NEWROUTE = 0x18 - RTM_NEWRULE = 0x20 - RTM_NEWSTATS = 0x5c - RTM_NEWTCLASS = 0x28 - RTM_NEWTFILTER = 0x2c - RTM_NR_FAMILIES = 0x14 - RTM_NR_MSGTYPES = 0x50 - RTM_SETDCB = 0x4f - RTM_SETLINK = 0x13 - RTM_SETNEIGHTBL = 0x43 - RTNH_ALIGNTO = 0x4 - RTNH_COMPARE_MASK = 0x11 - RTNH_F_DEAD = 0x1 - RTNH_F_LINKDOWN = 0x10 - RTNH_F_OFFLOAD = 0x8 - RTNH_F_ONLINK = 0x4 - RTNH_F_PERVASIVE = 0x2 - RTN_MAX = 0xb - RTPROT_BABEL = 0x2a - RTPROT_BIRD = 0xc - RTPROT_BOOT = 0x3 - RTPROT_DHCP = 0x10 - RTPROT_DNROUTED = 0xd - RTPROT_GATED = 0x8 - RTPROT_KERNEL = 0x2 - RTPROT_MROUTED = 0x11 - RTPROT_MRT = 0xa - RTPROT_NTK = 0xf - RTPROT_RA = 0x9 - RTPROT_REDIRECT = 0x1 - RTPROT_STATIC = 0x4 - RTPROT_UNSPEC = 0x0 - RTPROT_XORP = 0xe - RTPROT_ZEBRA = 0xb - RT_CLASS_DEFAULT = 0xfd - RT_CLASS_LOCAL = 0xff - RT_CLASS_MAIN = 0xfe - RT_CLASS_MAX = 0xff - RT_CLASS_UNSPEC = 0x0 - RUSAGE_CHILDREN = -0x1 - RUSAGE_SELF = 0x0 - RUSAGE_THREAD = 0x1 - SCM_CREDENTIALS = 0x2 - SCM_RIGHTS = 0x1 - SCM_TIMESTAMP = 0x1d - SCM_TIMESTAMPING = 0x23 - SCM_TIMESTAMPNS = 0x21 - SCM_WIFI_STATUS = 0x25 - SHUT_RD = 0x0 - SHUT_RDWR = 0x2 - SHUT_WR = 0x1 - SIOCADDDLCI = 0x8980 - SIOCADDMULTI = 0x8931 - SIOCADDRT = 0x890b - SIOCATMARK = 0x8905 - SIOCBONDCHANGEACTIVE = 0x8995 - SIOCBONDENSLAVE = 0x8990 - SIOCBONDINFOQUERY = 0x8994 - SIOCBONDRELEASE = 0x8991 - SIOCBONDSETHWADDR = 0x8992 - SIOCBONDSLAVEINFOQUERY = 0x8993 - SIOCBRADDBR = 0x89a0 - SIOCBRADDIF = 0x89a2 - SIOCBRDELBR = 0x89a1 - SIOCBRDELIF = 0x89a3 - SIOCDARP = 0x8953 - SIOCDELDLCI = 0x8981 - SIOCDELMULTI = 0x8932 - SIOCDELRT = 0x890c - SIOCDEVPRIVATE = 0x89f0 - SIOCDIFADDR = 0x8936 - SIOCDRARP = 0x8960 - SIOCETHTOOL = 0x8946 - SIOCGARP = 0x8954 - SIOCGHWTSTAMP = 0x89b1 - SIOCGIFADDR = 0x8915 - SIOCGIFBR = 0x8940 - SIOCGIFBRDADDR = 0x8919 - SIOCGIFCONF = 0x8912 - SIOCGIFCOUNT = 0x8938 - SIOCGIFDSTADDR = 0x8917 - SIOCGIFENCAP = 0x8925 - SIOCGIFFLAGS = 0x8913 - SIOCGIFHWADDR = 0x8927 - SIOCGIFINDEX = 0x8933 - SIOCGIFMAP = 0x8970 - SIOCGIFMEM = 0x891f - SIOCGIFMETRIC = 0x891d - SIOCGIFMTU = 0x8921 - SIOCGIFNAME = 0x8910 - SIOCGIFNETMASK = 0x891b - SIOCGIFPFLAGS = 0x8935 - SIOCGIFSLAVE = 0x8929 - SIOCGIFTXQLEN = 0x8942 - SIOCGIFVLAN = 0x8982 - SIOCGMIIPHY = 0x8947 - SIOCGMIIREG = 0x8948 - SIOCGPGRP = 0x8904 - SIOCGRARP = 0x8961 - SIOCGSTAMP = 0x8906 - SIOCGSTAMPNS = 0x8907 - SIOCINQ = 0x4004667f - SIOCOUTQ = 0x40047473 - SIOCOUTQNSD = 0x894b - SIOCPROTOPRIVATE = 0x89e0 - SIOCRTMSG = 0x890d - SIOCSARP = 0x8955 - SIOCSHWTSTAMP = 0x89b0 - SIOCSIFADDR = 0x8916 - SIOCSIFBR = 0x8941 - SIOCSIFBRDADDR = 0x891a - SIOCSIFDSTADDR = 0x8918 - SIOCSIFENCAP = 0x8926 - SIOCSIFFLAGS = 0x8914 - SIOCSIFHWADDR = 0x8924 - SIOCSIFHWBROADCAST = 0x8937 - SIOCSIFLINK = 0x8911 - SIOCSIFMAP = 0x8971 - SIOCSIFMEM = 0x8920 - SIOCSIFMETRIC = 0x891e - SIOCSIFMTU = 0x8922 - SIOCSIFNAME = 0x8923 - SIOCSIFNETMASK = 0x891c - SIOCSIFPFLAGS = 0x8934 - SIOCSIFSLAVE = 0x8930 - SIOCSIFTXQLEN = 0x8943 - SIOCSIFVLAN = 0x8983 - SIOCSMIIREG = 0x8949 - SIOCSPGRP = 0x8902 - SIOCSRARP = 0x8962 - SIOCWANDEV = 0x894a - SOCK_CLOEXEC = 0x400000 - SOCK_DCCP = 0x6 - SOCK_DGRAM = 0x2 - SOCK_NONBLOCK = 0x4000 - SOCK_PACKET = 0xa - SOCK_RAW = 0x3 - SOCK_RDM = 0x4 - SOCK_SEQPACKET = 0x5 - SOCK_STREAM = 0x1 - SOL_AAL = 0x109 - SOL_ALG = 0x117 - SOL_ATM = 0x108 - SOL_CAIF = 0x116 - SOL_DCCP = 0x10d - SOL_DECNET = 0x105 - SOL_ICMPV6 = 0x3a - SOL_IP = 0x0 - SOL_IPV6 = 0x29 - SOL_IRDA = 0x10a - SOL_IUCV = 0x115 - SOL_KCM = 0x119 - SOL_LLC = 0x10c - SOL_NETBEUI = 0x10b - SOL_NETLINK = 0x10e - SOL_NFC = 0x118 - SOL_PACKET = 0x107 - SOL_PNPIPE = 0x113 - SOL_PPPOL2TP = 0x111 - SOL_RAW = 0xff - SOL_RDS = 0x114 - SOL_RXRPC = 0x110 - SOL_SOCKET = 0xffff - SOL_TCP = 0x6 - SOL_TIPC = 0x10f - SOL_X25 = 0x106 - SOMAXCONN = 0x80 - SO_ACCEPTCONN = 0x8000 - SO_ATTACH_BPF = 0x34 - SO_ATTACH_FILTER = 0x1a - SO_ATTACH_REUSEPORT_CBPF = 0x35 - SO_ATTACH_REUSEPORT_EBPF = 0x36 - SO_BINDTODEVICE = 0xd - SO_BPF_EXTENSIONS = 0x32 - SO_BROADCAST = 0x20 - SO_BSDCOMPAT = 0x400 - SO_BUSY_POLL = 0x30 - SO_CNX_ADVICE = 0x37 - SO_DEBUG = 0x1 - SO_DETACH_BPF = 0x1b - SO_DETACH_FILTER = 0x1b - SO_DOMAIN = 0x1029 - SO_DONTROUTE = 0x10 - SO_ERROR = 0x1007 - SO_GET_FILTER = 0x1a - SO_INCOMING_CPU = 0x33 - SO_KEEPALIVE = 0x8 - SO_LINGER = 0x80 - SO_LOCK_FILTER = 0x28 - SO_MARK = 0x22 - SO_MAX_PACING_RATE = 0x31 - SO_NOFCS = 0x27 - SO_NO_CHECK = 0xb - SO_OOBINLINE = 0x100 - SO_PASSCRED = 0x2 - SO_PASSSEC = 0x1f - SO_PEEK_OFF = 0x26 - SO_PEERCRED = 0x40 - SO_PEERNAME = 0x1c - SO_PEERSEC = 0x1e - SO_PRIORITY = 0xc - SO_PROTOCOL = 0x1028 - SO_RCVBUF = 0x1002 - SO_RCVBUFFORCE = 0x100b - SO_RCVLOWAT = 0x800 - SO_RCVTIMEO = 0x2000 - SO_REUSEADDR = 0x4 - SO_REUSEPORT = 0x200 - SO_RXQ_OVFL = 0x24 - SO_SECURITY_AUTHENTICATION = 0x5001 - SO_SECURITY_ENCRYPTION_NETWORK = 0x5004 - SO_SECURITY_ENCRYPTION_TRANSPORT = 0x5002 - SO_SELECT_ERR_QUEUE = 0x29 - SO_SNDBUF = 0x1001 - SO_SNDBUFFORCE = 0x100a - SO_SNDLOWAT = 0x1000 - SO_SNDTIMEO = 0x4000 - SO_TIMESTAMP = 0x1d - SO_TIMESTAMPING = 0x23 - SO_TIMESTAMPNS = 0x21 - SO_TYPE = 0x1008 - SO_VM_SOCKETS_BUFFER_MAX_SIZE = 0x2 - SO_VM_SOCKETS_BUFFER_MIN_SIZE = 0x1 - SO_VM_SOCKETS_BUFFER_SIZE = 0x0 - SO_VM_SOCKETS_CONNECT_TIMEOUT = 0x6 - SO_VM_SOCKETS_NONBLOCK_TXRX = 0x7 - SO_VM_SOCKETS_PEER_HOST_VM_ID = 0x3 - SO_VM_SOCKETS_TRUSTED = 0x5 - SO_WIFI_STATUS = 0x25 - SPLICE_F_GIFT = 0x8 - SPLICE_F_MORE = 0x4 - SPLICE_F_MOVE = 0x1 - SPLICE_F_NONBLOCK = 0x2 - S_BLKSIZE = 0x200 - S_IEXEC = 0x40 - S_IFBLK = 0x6000 - S_IFCHR = 0x2000 - S_IFDIR = 0x4000 - S_IFIFO = 0x1000 - S_IFLNK = 0xa000 - S_IFMT = 0xf000 - S_IFREG = 0x8000 - S_IFSOCK = 0xc000 - S_IREAD = 0x100 - S_IRGRP = 0x20 - S_IROTH = 0x4 - S_IRUSR = 0x100 - S_IRWXG = 0x38 - S_IRWXO = 0x7 - S_IRWXU = 0x1c0 - S_ISGID = 0x400 - S_ISUID = 0x800 - S_ISVTX = 0x200 - S_IWGRP = 0x10 - S_IWOTH = 0x2 - S_IWRITE = 0x80 - S_IWUSR = 0x80 - S_IXGRP = 0x8 - S_IXOTH = 0x1 - S_IXUSR = 0x40 - TAB0 = 0x0 - TAB1 = 0x800 - TAB2 = 0x1000 - TAB3 = 0x1800 - TABDLY = 0x1800 - TCFLSH = 0x20005407 - TCGETA = 0x40125401 - TCGETS = 0x40245408 - TCGETS2 = 0x402c540c - TCIFLUSH = 0x0 - TCIOFF = 0x2 - TCIOFLUSH = 0x2 - TCION = 0x3 - TCOFLUSH = 0x1 - TCOOFF = 0x0 - TCOON = 0x1 - TCP_CC_INFO = 0x1a - TCP_CONGESTION = 0xd - TCP_COOKIE_IN_ALWAYS = 0x1 - TCP_COOKIE_MAX = 0x10 - TCP_COOKIE_MIN = 0x8 - TCP_COOKIE_OUT_NEVER = 0x2 - TCP_COOKIE_PAIR_SIZE = 0x20 - TCP_COOKIE_TRANSACTIONS = 0xf - TCP_CORK = 0x3 - TCP_DEFER_ACCEPT = 0x9 - TCP_FASTOPEN = 0x17 - TCP_INFO = 0xb - TCP_KEEPCNT = 0x6 - TCP_KEEPIDLE = 0x4 - TCP_KEEPINTVL = 0x5 - TCP_LINGER2 = 0x8 - TCP_MAXSEG = 0x2 - TCP_MAXWIN = 0xffff - TCP_MAX_WINSHIFT = 0xe - TCP_MD5SIG = 0xe - TCP_MD5SIG_MAXKEYLEN = 0x50 - TCP_MSS = 0x200 - TCP_MSS_DEFAULT = 0x218 - TCP_MSS_DESIRED = 0x4c4 - TCP_NODELAY = 0x1 - TCP_NOTSENT_LOWAT = 0x19 - TCP_QUEUE_SEQ = 0x15 - TCP_QUICKACK = 0xc - TCP_REPAIR = 0x13 - TCP_REPAIR_OPTIONS = 0x16 - TCP_REPAIR_QUEUE = 0x14 - TCP_SAVED_SYN = 0x1c - TCP_SAVE_SYN = 0x1b - TCP_SYNCNT = 0x7 - TCP_S_DATA_IN = 0x4 - TCP_S_DATA_OUT = 0x8 - TCP_THIN_DUPACK = 0x11 - TCP_THIN_LINEAR_TIMEOUTS = 0x10 - TCP_TIMESTAMP = 0x18 - TCP_USER_TIMEOUT = 0x12 - TCP_WINDOW_CLAMP = 0xa - TCSAFLUSH = 0x2 - TCSBRK = 0x20005405 - TCSBRKP = 0x5425 - TCSETA = 0x80125402 - TCSETAF = 0x80125404 - TCSETAW = 0x80125403 - TCSETS = 0x80245409 - TCSETS2 = 0x802c540d - TCSETSF = 0x8024540b - TCSETSF2 = 0x802c540f - TCSETSW = 0x8024540a - TCSETSW2 = 0x802c540e - TCXONC = 0x20005406 - TIOCCBRK = 0x2000747a - TIOCCONS = 0x20007424 - TIOCEXCL = 0x2000740d - TIOCGDEV = 0x40045432 - TIOCGETD = 0x40047400 - TIOCGEXCL = 0x40045440 - TIOCGICOUNT = 0x545d - TIOCGLCKTRMIOS = 0x5456 - TIOCGPGRP = 0x40047483 - TIOCGPKT = 0x40045438 - TIOCGPTLCK = 0x40045439 - TIOCGPTN = 0x40047486 - TIOCGRS485 = 0x40205441 - TIOCGSERIAL = 0x541e - TIOCGSID = 0x40047485 - TIOCGSOFTCAR = 0x40047464 - TIOCGWINSZ = 0x40087468 - TIOCINQ = 0x4004667f - TIOCLINUX = 0x541c - TIOCMBIC = 0x8004746b - TIOCMBIS = 0x8004746c - TIOCMGET = 0x4004746a - TIOCMIWAIT = 0x545c - TIOCMSET = 0x8004746d - TIOCM_CAR = 0x40 - TIOCM_CD = 0x40 - TIOCM_CTS = 0x20 - TIOCM_DSR = 0x100 - TIOCM_DTR = 0x2 - TIOCM_LE = 0x1 - TIOCM_LOOP = 0x8000 - TIOCM_OUT1 = 0x2000 - TIOCM_OUT2 = 0x4000 - TIOCM_RI = 0x80 - TIOCM_RNG = 0x80 - TIOCM_RTS = 0x4 - TIOCM_SR = 0x10 - TIOCM_ST = 0x8 - TIOCNOTTY = 0x20007471 - TIOCNXCL = 0x2000740e - TIOCOUTQ = 0x40047473 - TIOCPKT = 0x80047470 - TIOCPKT_DATA = 0x0 - TIOCPKT_DOSTOP = 0x20 - TIOCPKT_FLUSHREAD = 0x1 - TIOCPKT_FLUSHWRITE = 0x2 - TIOCPKT_IOCTL = 0x40 - TIOCPKT_NOSTOP = 0x10 - TIOCPKT_START = 0x8 - TIOCPKT_STOP = 0x4 - TIOCSBRK = 0x2000747b - TIOCSCTTY = 0x20007484 - TIOCSERCONFIG = 0x5453 - TIOCSERGETLSR = 0x5459 - TIOCSERGETMULTI = 0x545a - TIOCSERGSTRUCT = 0x5458 - TIOCSERGWILD = 0x5454 - TIOCSERSETMULTI = 0x545b - TIOCSERSWILD = 0x5455 - TIOCSER_TEMT = 0x1 - TIOCSETD = 0x80047401 - TIOCSIG = 0x80047488 - TIOCSLCKTRMIOS = 0x5457 - TIOCSPGRP = 0x80047482 - TIOCSPTLCK = 0x80047487 - TIOCSRS485 = 0xc0205442 - TIOCSSERIAL = 0x541f - TIOCSSOFTCAR = 0x80047465 - TIOCSTART = 0x2000746e - TIOCSTI = 0x80017472 - TIOCSTOP = 0x2000746f - TIOCSWINSZ = 0x80087467 - TIOCVHANGUP = 0x20005437 - TOSTOP = 0x100 - TUNATTACHFILTER = 0x801054d5 - TUNDETACHFILTER = 0x801054d6 - TUNGETFEATURES = 0x400454cf - TUNGETFILTER = 0x401054db - TUNGETIFF = 0x400454d2 - TUNGETSNDBUF = 0x400454d3 - TUNGETVNETBE = 0x400454df - TUNGETVNETHDRSZ = 0x400454d7 - TUNGETVNETLE = 0x400454dd - TUNSETDEBUG = 0x800454c9 - TUNSETGROUP = 0x800454ce - TUNSETIFF = 0x800454ca - TUNSETIFINDEX = 0x800454da - TUNSETLINK = 0x800454cd - TUNSETNOCSUM = 0x800454c8 - TUNSETOFFLOAD = 0x800454d0 - TUNSETOWNER = 0x800454cc - TUNSETPERSIST = 0x800454cb - TUNSETQUEUE = 0x800454d9 - TUNSETSNDBUF = 0x800454d4 - TUNSETTXFILTER = 0x800454d1 - TUNSETVNETBE = 0x800454de - TUNSETVNETHDRSZ = 0x800454d8 - TUNSETVNETLE = 0x800454dc - VDISCARD = 0xd - VDSUSP = 0xb - VEOF = 0x4 - VEOL = 0x5 - VEOL2 = 0x6 - VERASE = 0x2 - VINTR = 0x0 - VKILL = 0x3 - VLNEXT = 0xf - VMADDR_CID_ANY = 0xffffffff - VMADDR_CID_HOST = 0x2 - VMADDR_CID_HYPERVISOR = 0x0 - VMADDR_CID_RESERVED = 0x1 - VMADDR_PORT_ANY = 0xffffffff - VMIN = 0x4 - VQUIT = 0x1 - VREPRINT = 0xc - VSTART = 0x8 - VSTOP = 0x9 - VSUSP = 0xa - VSWTC = 0x7 - VT0 = 0x0 - VT1 = 0x4000 - VTDLY = 0x4000 - VTIME = 0x5 - VWERASE = 0xe - WALL = 0x40000000 - WCLONE = 0x80000000 - WCONTINUED = 0x8 - WEXITED = 0x4 - WNOHANG = 0x1 - WNOTHREAD = 0x20000000 - WNOWAIT = 0x1000000 - WORDSIZE = 0x40 - WRAP = 0x20000 - WSTOPPED = 0x2 - WUNTRACED = 0x2 - XCASE = 0x4 - XTABS = 0x1800 - __TIOCFLUSH = 0x80047410 + AAFS_MAGIC = 0x5a3c69f0 + ADFS_SUPER_MAGIC = 0xadf5 + AFFS_SUPER_MAGIC = 0xadff + AFS_FS_MAGIC = 0x6b414653 + AFS_SUPER_MAGIC = 0x5346414f + AF_ALG = 0x26 + AF_APPLETALK = 0x5 + AF_ASH = 0x12 + AF_ATMPVC = 0x8 + AF_ATMSVC = 0x14 + AF_AX25 = 0x3 + AF_BLUETOOTH = 0x1f + AF_BRIDGE = 0x7 + AF_CAIF = 0x25 + AF_CAN = 0x1d + AF_DECnet = 0xc + AF_ECONET = 0x13 + AF_FILE = 0x1 + AF_IB = 0x1b + AF_IEEE802154 = 0x24 + AF_INET = 0x2 + AF_INET6 = 0xa + AF_IPX = 0x4 + AF_IRDA = 0x17 + AF_ISDN = 0x22 + AF_IUCV = 0x20 + AF_KCM = 0x29 + AF_KEY = 0xf + AF_LLC = 0x1a + AF_LOCAL = 0x1 + AF_MAX = 0x2d + AF_MPLS = 0x1c + AF_NETBEUI = 0xd + AF_NETLINK = 0x10 + AF_NETROM = 0x6 + AF_NFC = 0x27 + AF_PACKET = 0x11 + AF_PHONET = 0x23 + AF_PPPOX = 0x18 + AF_QIPCRTR = 0x2a + AF_RDS = 0x15 + AF_ROSE = 0xb + AF_ROUTE = 0x10 + AF_RXRPC = 0x21 + AF_SECURITY = 0xe + AF_SMC = 0x2b + AF_SNA = 0x16 + AF_TIPC = 0x1e + AF_UNIX = 0x1 + AF_UNSPEC = 0x0 + AF_VSOCK = 0x28 + AF_WANPIPE = 0x19 + AF_X25 = 0x9 + AF_XDP = 0x2c + ALG_OP_DECRYPT = 0x0 + ALG_OP_ENCRYPT = 0x1 + ALG_SET_AEAD_ASSOCLEN = 0x4 + ALG_SET_AEAD_AUTHSIZE = 0x5 + ALG_SET_IV = 0x2 + ALG_SET_KEY = 0x1 + ALG_SET_OP = 0x3 + ANON_INODE_FS_MAGIC = 0x9041934 + ARPHRD_6LOWPAN = 0x339 + ARPHRD_ADAPT = 0x108 + ARPHRD_APPLETLK = 0x8 + ARPHRD_ARCNET = 0x7 + ARPHRD_ASH = 0x30d + ARPHRD_ATM = 0x13 + ARPHRD_AX25 = 0x3 + ARPHRD_BIF = 0x307 + ARPHRD_CAIF = 0x336 + ARPHRD_CAN = 0x118 + ARPHRD_CHAOS = 0x5 + ARPHRD_CISCO = 0x201 + ARPHRD_CSLIP = 0x101 + ARPHRD_CSLIP6 = 0x103 + ARPHRD_DDCMP = 0x205 + ARPHRD_DLCI = 0xf + ARPHRD_ECONET = 0x30e + ARPHRD_EETHER = 0x2 + ARPHRD_ETHER = 0x1 + ARPHRD_EUI64 = 0x1b + ARPHRD_FCAL = 0x311 + ARPHRD_FCFABRIC = 0x313 + ARPHRD_FCPL = 0x312 + ARPHRD_FCPP = 0x310 + ARPHRD_FDDI = 0x306 + ARPHRD_FRAD = 0x302 + ARPHRD_HDLC = 0x201 + ARPHRD_HIPPI = 0x30c + ARPHRD_HWX25 = 0x110 + ARPHRD_IEEE1394 = 0x18 + ARPHRD_IEEE802 = 0x6 + ARPHRD_IEEE80211 = 0x321 + ARPHRD_IEEE80211_PRISM = 0x322 + ARPHRD_IEEE80211_RADIOTAP = 0x323 + ARPHRD_IEEE802154 = 0x324 + ARPHRD_IEEE802154_MONITOR = 0x325 + ARPHRD_IEEE802_TR = 0x320 + ARPHRD_INFINIBAND = 0x20 + ARPHRD_IP6GRE = 0x337 + ARPHRD_IPDDP = 0x309 + ARPHRD_IPGRE = 0x30a + ARPHRD_IRDA = 0x30f + ARPHRD_LAPB = 0x204 + ARPHRD_LOCALTLK = 0x305 + ARPHRD_LOOPBACK = 0x304 + ARPHRD_METRICOM = 0x17 + ARPHRD_NETLINK = 0x338 + ARPHRD_NETROM = 0x0 + ARPHRD_NONE = 0xfffe + ARPHRD_PHONET = 0x334 + ARPHRD_PHONET_PIPE = 0x335 + ARPHRD_PIMREG = 0x30b + ARPHRD_PPP = 0x200 + ARPHRD_PRONET = 0x4 + ARPHRD_RAWHDLC = 0x206 + ARPHRD_RAWIP = 0x207 + ARPHRD_ROSE = 0x10e + ARPHRD_RSRVD = 0x104 + ARPHRD_SIT = 0x308 + ARPHRD_SKIP = 0x303 + ARPHRD_SLIP = 0x100 + ARPHRD_SLIP6 = 0x102 + ARPHRD_TUNNEL = 0x300 + ARPHRD_TUNNEL6 = 0x301 + ARPHRD_VOID = 0xffff + ARPHRD_VSOCKMON = 0x33a + ARPHRD_X25 = 0x10f + ASI_LEON_DFLUSH = 0x11 + ASI_LEON_IFLUSH = 0x10 + ASI_LEON_MMUFLUSH = 0x18 + AUTOFS_SUPER_MAGIC = 0x187 + B0 = 0x0 + B1000000 = 0x1008 + B110 = 0x3 + B115200 = 0x1002 + B1152000 = 0x1009 + B1200 = 0x9 + B134 = 0x4 + B150 = 0x5 + B1500000 = 0x100a + B1800 = 0xa + B19200 = 0xe + B200 = 0x6 + B2000000 = 0x100b + B230400 = 0x1003 + B2400 = 0xb + B2500000 = 0x100c + B300 = 0x7 + B3000000 = 0x100d + B3500000 = 0x100e + B38400 = 0xf + B4000000 = 0x100f + B460800 = 0x1004 + B4800 = 0xc + B50 = 0x1 + B500000 = 0x1005 + B57600 = 0x1001 + B576000 = 0x1006 + B600 = 0x8 + B75 = 0x2 + B921600 = 0x1007 + B9600 = 0xd + BALLOON_KVM_MAGIC = 0x13661366 + BDEVFS_MAGIC = 0x62646576 + BINFMTFS_MAGIC = 0x42494e4d + BLKBSZGET = 0x40081270 + BLKBSZSET = 0x80081271 + BLKFLSBUF = 0x20001261 + BLKFRAGET = 0x20001265 + BLKFRASET = 0x20001264 + BLKGETSIZE = 0x20001260 + BLKGETSIZE64 = 0x40081272 + BLKPBSZGET = 0x2000127b + BLKRAGET = 0x20001263 + BLKRASET = 0x20001262 + BLKROGET = 0x2000125e + BLKROSET = 0x2000125d + BLKRRPART = 0x2000125f + BLKSECTGET = 0x20001267 + BLKSECTSET = 0x20001266 + BLKSSZGET = 0x20001268 + BOTHER = 0x1000 + BPF_A = 0x10 + BPF_ABS = 0x20 + BPF_ADD = 0x0 + BPF_ALU = 0x4 + BPF_AND = 0x50 + BPF_B = 0x10 + BPF_DIV = 0x30 + BPF_FS_MAGIC = 0xcafe4a11 + BPF_H = 0x8 + BPF_IMM = 0x0 + BPF_IND = 0x40 + BPF_JA = 0x0 + BPF_JEQ = 0x10 + BPF_JGE = 0x30 + BPF_JGT = 0x20 + BPF_JMP = 0x5 + BPF_JSET = 0x40 + BPF_K = 0x0 + BPF_LD = 0x0 + BPF_LDX = 0x1 + BPF_LEN = 0x80 + BPF_LL_OFF = -0x200000 + BPF_LSH = 0x60 + BPF_MAJOR_VERSION = 0x1 + BPF_MAXINSNS = 0x1000 + BPF_MEM = 0x60 + BPF_MEMWORDS = 0x10 + BPF_MINOR_VERSION = 0x1 + BPF_MISC = 0x7 + BPF_MOD = 0x90 + BPF_MSH = 0xa0 + BPF_MUL = 0x20 + BPF_NEG = 0x80 + BPF_NET_OFF = -0x100000 + BPF_OR = 0x40 + BPF_RET = 0x6 + BPF_RSH = 0x70 + BPF_ST = 0x2 + BPF_STX = 0x3 + BPF_SUB = 0x10 + BPF_TAX = 0x0 + BPF_TXA = 0x80 + BPF_W = 0x0 + BPF_X = 0x8 + BPF_XOR = 0xa0 + BRKINT = 0x2 + BS0 = 0x0 + BS1 = 0x2000 + BSDLY = 0x2000 + BTRFS_SUPER_MAGIC = 0x9123683e + BTRFS_TEST_MAGIC = 0x73727279 + CAN_BCM = 0x2 + CAN_EFF_FLAG = 0x80000000 + CAN_EFF_ID_BITS = 0x1d + CAN_EFF_MASK = 0x1fffffff + CAN_ERR_FLAG = 0x20000000 + CAN_ERR_MASK = 0x1fffffff + CAN_INV_FILTER = 0x20000000 + CAN_ISOTP = 0x6 + CAN_MAX_DLC = 0x8 + CAN_MAX_DLEN = 0x8 + CAN_MCNET = 0x5 + CAN_MTU = 0x10 + CAN_NPROTO = 0x7 + CAN_RAW = 0x1 + CAN_RAW_FILTER_MAX = 0x200 + CAN_RTR_FLAG = 0x40000000 + CAN_SFF_ID_BITS = 0xb + CAN_SFF_MASK = 0x7ff + CAN_TP16 = 0x3 + CAN_TP20 = 0x4 + CBAUD = 0x100f + CBAUDEX = 0x1000 + CFLUSH = 0xf + CGROUP2_SUPER_MAGIC = 0x63677270 + CGROUP_SUPER_MAGIC = 0x27e0eb + CIBAUD = 0x100f0000 + CLOCAL = 0x800 + CLOCK_BOOTTIME = 0x7 + CLOCK_BOOTTIME_ALARM = 0x9 + CLOCK_DEFAULT = 0x0 + CLOCK_EXT = 0x1 + CLOCK_INT = 0x2 + CLOCK_MONOTONIC = 0x1 + CLOCK_MONOTONIC_COARSE = 0x6 + CLOCK_MONOTONIC_RAW = 0x4 + CLOCK_PROCESS_CPUTIME_ID = 0x2 + CLOCK_REALTIME = 0x0 + CLOCK_REALTIME_ALARM = 0x8 + CLOCK_REALTIME_COARSE = 0x5 + CLOCK_TAI = 0xb + CLOCK_THREAD_CPUTIME_ID = 0x3 + CLOCK_TXFROMRX = 0x4 + CLOCK_TXINT = 0x3 + CLONE_CHILD_CLEARTID = 0x200000 + CLONE_CHILD_SETTID = 0x1000000 + CLONE_DETACHED = 0x400000 + CLONE_FILES = 0x400 + CLONE_FS = 0x200 + CLONE_IO = 0x80000000 + CLONE_NEWCGROUP = 0x2000000 + CLONE_NEWIPC = 0x8000000 + CLONE_NEWNET = 0x40000000 + CLONE_NEWNS = 0x20000 + CLONE_NEWPID = 0x20000000 + CLONE_NEWUSER = 0x10000000 + CLONE_NEWUTS = 0x4000000 + CLONE_PARENT = 0x8000 + CLONE_PARENT_SETTID = 0x100000 + CLONE_PTRACE = 0x2000 + CLONE_SETTLS = 0x80000 + CLONE_SIGHAND = 0x800 + CLONE_SYSVSEM = 0x40000 + CLONE_THREAD = 0x10000 + CLONE_UNTRACED = 0x800000 + CLONE_VFORK = 0x4000 + CLONE_VM = 0x100 + CMSPAR = 0x40000000 + CODA_SUPER_MAGIC = 0x73757245 + CR0 = 0x0 + CR1 = 0x200 + CR2 = 0x400 + CR3 = 0x600 + CRAMFS_MAGIC = 0x28cd3d45 + CRDLY = 0x600 + CREAD = 0x80 + CRTSCTS = 0x80000000 + CS5 = 0x0 + CS6 = 0x10 + CS7 = 0x20 + CS8 = 0x30 + CSIGNAL = 0xff + CSIZE = 0x30 + CSTART = 0x11 + CSTATUS = 0x0 + CSTOP = 0x13 + CSTOPB = 0x40 + CSUSP = 0x1a + DAXFS_MAGIC = 0x64646178 + DEBUGFS_MAGIC = 0x64626720 + DEVPTS_SUPER_MAGIC = 0x1cd1 + DT_BLK = 0x6 + DT_CHR = 0x2 + DT_DIR = 0x4 + DT_FIFO = 0x1 + DT_LNK = 0xa + DT_REG = 0x8 + DT_SOCK = 0xc + DT_UNKNOWN = 0x0 + DT_WHT = 0xe + ECHO = 0x8 + ECHOCTL = 0x200 + ECHOE = 0x10 + ECHOK = 0x20 + ECHOKE = 0x800 + ECHONL = 0x40 + ECHOPRT = 0x400 + ECRYPTFS_SUPER_MAGIC = 0xf15f + EFD_CLOEXEC = 0x400000 + EFD_NONBLOCK = 0x4000 + EFD_SEMAPHORE = 0x1 + EFIVARFS_MAGIC = 0xde5e81e4 + EFS_SUPER_MAGIC = 0x414a53 + EMT_TAGOVF = 0x1 + ENCODING_DEFAULT = 0x0 + ENCODING_FM_MARK = 0x3 + ENCODING_FM_SPACE = 0x4 + ENCODING_MANCHESTER = 0x5 + ENCODING_NRZ = 0x1 + ENCODING_NRZI = 0x2 + EPOLLERR = 0x8 + EPOLLET = 0x80000000 + EPOLLEXCLUSIVE = 0x10000000 + EPOLLHUP = 0x10 + EPOLLIN = 0x1 + EPOLLMSG = 0x400 + EPOLLONESHOT = 0x40000000 + EPOLLOUT = 0x4 + EPOLLPRI = 0x2 + EPOLLRDBAND = 0x80 + EPOLLRDHUP = 0x2000 + EPOLLRDNORM = 0x40 + EPOLLWAKEUP = 0x20000000 + EPOLLWRBAND = 0x200 + EPOLLWRNORM = 0x100 + EPOLL_CLOEXEC = 0x400000 + EPOLL_CTL_ADD = 0x1 + EPOLL_CTL_DEL = 0x2 + EPOLL_CTL_MOD = 0x3 + ETH_P_1588 = 0x88f7 + ETH_P_8021AD = 0x88a8 + ETH_P_8021AH = 0x88e7 + ETH_P_8021Q = 0x8100 + ETH_P_80221 = 0x8917 + ETH_P_802_2 = 0x4 + ETH_P_802_3 = 0x1 + ETH_P_802_3_MIN = 0x600 + ETH_P_802_EX1 = 0x88b5 + ETH_P_AARP = 0x80f3 + ETH_P_AF_IUCV = 0xfbfb + ETH_P_ALL = 0x3 + ETH_P_AOE = 0x88a2 + ETH_P_ARCNET = 0x1a + ETH_P_ARP = 0x806 + ETH_P_ATALK = 0x809b + ETH_P_ATMFATE = 0x8884 + ETH_P_ATMMPOA = 0x884c + ETH_P_AX25 = 0x2 + ETH_P_BATMAN = 0x4305 + ETH_P_BPQ = 0x8ff + ETH_P_CAIF = 0xf7 + ETH_P_CAN = 0xc + ETH_P_CANFD = 0xd + ETH_P_CONTROL = 0x16 + ETH_P_CUST = 0x6006 + ETH_P_DDCMP = 0x6 + ETH_P_DEC = 0x6000 + ETH_P_DIAG = 0x6005 + ETH_P_DNA_DL = 0x6001 + ETH_P_DNA_RC = 0x6002 + ETH_P_DNA_RT = 0x6003 + ETH_P_DSA = 0x1b + ETH_P_ECONET = 0x18 + ETH_P_EDSA = 0xdada + ETH_P_ERSPAN = 0x88be + ETH_P_ERSPAN2 = 0x22eb + ETH_P_FCOE = 0x8906 + ETH_P_FIP = 0x8914 + ETH_P_HDLC = 0x19 + ETH_P_HSR = 0x892f + ETH_P_IBOE = 0x8915 + ETH_P_IEEE802154 = 0xf6 + ETH_P_IEEEPUP = 0xa00 + ETH_P_IEEEPUPAT = 0xa01 + ETH_P_IFE = 0xed3e + ETH_P_IP = 0x800 + ETH_P_IPV6 = 0x86dd + ETH_P_IPX = 0x8137 + ETH_P_IRDA = 0x17 + ETH_P_LAT = 0x6004 + ETH_P_LINK_CTL = 0x886c + ETH_P_LOCALTALK = 0x9 + ETH_P_LOOP = 0x60 + ETH_P_LOOPBACK = 0x9000 + ETH_P_MACSEC = 0x88e5 + ETH_P_MAP = 0xf9 + ETH_P_MOBITEX = 0x15 + ETH_P_MPLS_MC = 0x8848 + ETH_P_MPLS_UC = 0x8847 + ETH_P_MVRP = 0x88f5 + ETH_P_NCSI = 0x88f8 + ETH_P_NSH = 0x894f + ETH_P_PAE = 0x888e + ETH_P_PAUSE = 0x8808 + ETH_P_PHONET = 0xf5 + ETH_P_PPPTALK = 0x10 + ETH_P_PPP_DISC = 0x8863 + ETH_P_PPP_MP = 0x8 + ETH_P_PPP_SES = 0x8864 + ETH_P_PREAUTH = 0x88c7 + ETH_P_PRP = 0x88fb + ETH_P_PUP = 0x200 + ETH_P_PUPAT = 0x201 + ETH_P_QINQ1 = 0x9100 + ETH_P_QINQ2 = 0x9200 + ETH_P_QINQ3 = 0x9300 + ETH_P_RARP = 0x8035 + ETH_P_SCA = 0x6007 + ETH_P_SLOW = 0x8809 + ETH_P_SNAP = 0x5 + ETH_P_TDLS = 0x890d + ETH_P_TEB = 0x6558 + ETH_P_TIPC = 0x88ca + ETH_P_TRAILER = 0x1c + ETH_P_TR_802_2 = 0x11 + ETH_P_TSN = 0x22f0 + ETH_P_WAN_PPP = 0x7 + ETH_P_WCCP = 0x883e + ETH_P_X25 = 0x805 + ETH_P_XDSA = 0xf8 + EXABYTE_ENABLE_NEST = 0xf0 + EXT2_SUPER_MAGIC = 0xef53 + EXT3_SUPER_MAGIC = 0xef53 + EXT4_SUPER_MAGIC = 0xef53 + EXTA = 0xe + EXTB = 0xf + EXTPROC = 0x10000 + F2FS_SUPER_MAGIC = 0xf2f52010 + FALLOC_FL_COLLAPSE_RANGE = 0x8 + FALLOC_FL_INSERT_RANGE = 0x20 + FALLOC_FL_KEEP_SIZE = 0x1 + FALLOC_FL_NO_HIDE_STALE = 0x4 + FALLOC_FL_PUNCH_HOLE = 0x2 + FALLOC_FL_UNSHARE_RANGE = 0x40 + FALLOC_FL_ZERO_RANGE = 0x10 + FD_CLOEXEC = 0x1 + FD_SETSIZE = 0x400 + FF0 = 0x0 + FF1 = 0x8000 + FFDLY = 0x8000 + FLUSHO = 0x1000 + FS_ENCRYPTION_MODE_AES_128_CBC = 0x5 + FS_ENCRYPTION_MODE_AES_128_CTS = 0x6 + FS_ENCRYPTION_MODE_AES_256_CBC = 0x3 + FS_ENCRYPTION_MODE_AES_256_CTS = 0x4 + FS_ENCRYPTION_MODE_AES_256_GCM = 0x2 + FS_ENCRYPTION_MODE_AES_256_XTS = 0x1 + FS_ENCRYPTION_MODE_INVALID = 0x0 + FS_ENCRYPTION_MODE_SPECK128_256_CTS = 0x8 + FS_ENCRYPTION_MODE_SPECK128_256_XTS = 0x7 + FS_IOC_GET_ENCRYPTION_POLICY = 0x800c6615 + FS_IOC_GET_ENCRYPTION_PWSALT = 0x80106614 + FS_IOC_SET_ENCRYPTION_POLICY = 0x400c6613 + FS_KEY_DESCRIPTOR_SIZE = 0x8 + FS_KEY_DESC_PREFIX = "fscrypt:" + FS_KEY_DESC_PREFIX_SIZE = 0x8 + FS_MAX_KEY_SIZE = 0x40 + FS_POLICY_FLAGS_PAD_16 = 0x2 + FS_POLICY_FLAGS_PAD_32 = 0x3 + FS_POLICY_FLAGS_PAD_4 = 0x0 + FS_POLICY_FLAGS_PAD_8 = 0x1 + FS_POLICY_FLAGS_PAD_MASK = 0x3 + FS_POLICY_FLAGS_VALID = 0x3 + FUTEXFS_SUPER_MAGIC = 0xbad1dea + F_ADD_SEALS = 0x409 + F_DUPFD = 0x0 + F_DUPFD_CLOEXEC = 0x406 + F_EXLCK = 0x4 + F_GETFD = 0x1 + F_GETFL = 0x3 + F_GETLEASE = 0x401 + F_GETLK = 0x7 + F_GETLK64 = 0x7 + F_GETOWN = 0x5 + F_GETOWN_EX = 0x10 + F_GETPIPE_SZ = 0x408 + F_GETSIG = 0xb + F_GET_FILE_RW_HINT = 0x40d + F_GET_RW_HINT = 0x40b + F_GET_SEALS = 0x40a + F_LOCK = 0x1 + F_NOTIFY = 0x402 + F_OFD_GETLK = 0x24 + F_OFD_SETLK = 0x25 + F_OFD_SETLKW = 0x26 + F_OK = 0x0 + F_RDLCK = 0x1 + F_SEAL_GROW = 0x4 + F_SEAL_SEAL = 0x1 + F_SEAL_SHRINK = 0x2 + F_SEAL_WRITE = 0x8 + F_SETFD = 0x2 + F_SETFL = 0x4 + F_SETLEASE = 0x400 + F_SETLK = 0x8 + F_SETLK64 = 0x8 + F_SETLKW = 0x9 + F_SETLKW64 = 0x9 + F_SETOWN = 0x6 + F_SETOWN_EX = 0xf + F_SETPIPE_SZ = 0x407 + F_SETSIG = 0xa + F_SET_FILE_RW_HINT = 0x40e + F_SET_RW_HINT = 0x40c + F_SHLCK = 0x8 + F_TEST = 0x3 + F_TLOCK = 0x2 + F_ULOCK = 0x0 + F_UNLCK = 0x3 + F_WRLCK = 0x2 + GENL_ADMIN_PERM = 0x1 + GENL_CMD_CAP_DO = 0x2 + GENL_CMD_CAP_DUMP = 0x4 + GENL_CMD_CAP_HASPOL = 0x8 + GENL_HDRLEN = 0x4 + GENL_ID_CTRL = 0x10 + GENL_ID_PMCRAID = 0x12 + GENL_ID_VFS_DQUOT = 0x11 + GENL_MAX_ID = 0x3ff + GENL_MIN_ID = 0x10 + GENL_NAMSIZ = 0x10 + GENL_START_ALLOC = 0x13 + GENL_UNS_ADMIN_PERM = 0x10 + GRND_NONBLOCK = 0x1 + GRND_RANDOM = 0x2 + HDIO_DRIVE_CMD = 0x31f + HDIO_DRIVE_CMD_AEB = 0x31e + HDIO_DRIVE_CMD_HDR_SIZE = 0x4 + HDIO_DRIVE_HOB_HDR_SIZE = 0x8 + HDIO_DRIVE_RESET = 0x31c + HDIO_DRIVE_TASK = 0x31e + HDIO_DRIVE_TASKFILE = 0x31d + HDIO_DRIVE_TASK_HDR_SIZE = 0x8 + HDIO_GETGEO = 0x301 + HDIO_GET_32BIT = 0x309 + HDIO_GET_ACOUSTIC = 0x30f + HDIO_GET_ADDRESS = 0x310 + HDIO_GET_BUSSTATE = 0x31a + HDIO_GET_DMA = 0x30b + HDIO_GET_IDENTITY = 0x30d + HDIO_GET_KEEPSETTINGS = 0x308 + HDIO_GET_MULTCOUNT = 0x304 + HDIO_GET_NICE = 0x30c + HDIO_GET_NOWERR = 0x30a + HDIO_GET_QDMA = 0x305 + HDIO_GET_UNMASKINTR = 0x302 + HDIO_GET_WCACHE = 0x30e + HDIO_OBSOLETE_IDENTITY = 0x307 + HDIO_SCAN_HWIF = 0x328 + HDIO_SET_32BIT = 0x324 + HDIO_SET_ACOUSTIC = 0x32c + HDIO_SET_ADDRESS = 0x32f + HDIO_SET_BUSSTATE = 0x32d + HDIO_SET_DMA = 0x326 + HDIO_SET_KEEPSETTINGS = 0x323 + HDIO_SET_MULTCOUNT = 0x321 + HDIO_SET_NICE = 0x329 + HDIO_SET_NOWERR = 0x325 + HDIO_SET_PIO_MODE = 0x327 + HDIO_SET_QDMA = 0x32e + HDIO_SET_UNMASKINTR = 0x322 + HDIO_SET_WCACHE = 0x32b + HDIO_SET_XFER = 0x306 + HDIO_TRISTATE_HWIF = 0x31b + HDIO_UNREGISTER_HWIF = 0x32a + HOSTFS_SUPER_MAGIC = 0xc0ffee + HPFS_SUPER_MAGIC = 0xf995e849 + HUGETLBFS_MAGIC = 0x958458f6 + HUPCL = 0x400 + IBSHIFT = 0x10 + ICANON = 0x2 + ICMPV6_FILTER = 0x1 + ICRNL = 0x100 + IEXTEN = 0x8000 + IFA_F_DADFAILED = 0x8 + IFA_F_DEPRECATED = 0x20 + IFA_F_HOMEADDRESS = 0x10 + IFA_F_MANAGETEMPADDR = 0x100 + IFA_F_MCAUTOJOIN = 0x400 + IFA_F_NODAD = 0x2 + IFA_F_NOPREFIXROUTE = 0x200 + IFA_F_OPTIMISTIC = 0x4 + IFA_F_PERMANENT = 0x80 + IFA_F_SECONDARY = 0x1 + IFA_F_STABLE_PRIVACY = 0x800 + IFA_F_TEMPORARY = 0x1 + IFA_F_TENTATIVE = 0x40 + IFA_MAX = 0xa + IFF_ALLMULTI = 0x200 + IFF_ATTACH_QUEUE = 0x200 + IFF_AUTOMEDIA = 0x4000 + IFF_BROADCAST = 0x2 + IFF_DEBUG = 0x4 + IFF_DETACH_QUEUE = 0x400 + IFF_DORMANT = 0x20000 + IFF_DYNAMIC = 0x8000 + IFF_ECHO = 0x40000 + IFF_LOOPBACK = 0x8 + IFF_LOWER_UP = 0x10000 + IFF_MASTER = 0x400 + IFF_MULTICAST = 0x1000 + IFF_MULTI_QUEUE = 0x100 + IFF_NAPI = 0x10 + IFF_NAPI_FRAGS = 0x20 + IFF_NOARP = 0x80 + IFF_NOFILTER = 0x1000 + IFF_NOTRAILERS = 0x20 + IFF_NO_PI = 0x1000 + IFF_ONE_QUEUE = 0x2000 + IFF_PERSIST = 0x800 + IFF_POINTOPOINT = 0x10 + IFF_PORTSEL = 0x2000 + IFF_PROMISC = 0x100 + IFF_RUNNING = 0x40 + IFF_SLAVE = 0x800 + IFF_TAP = 0x2 + IFF_TUN = 0x1 + IFF_TUN_EXCL = 0x8000 + IFF_UP = 0x1 + IFF_VNET_HDR = 0x4000 + IFF_VOLATILE = 0x70c5a + IFNAMSIZ = 0x10 + IGNBRK = 0x1 + IGNCR = 0x80 + IGNPAR = 0x4 + IMAXBEL = 0x2000 + INLCR = 0x40 + INPCK = 0x10 + IN_ACCESS = 0x1 + IN_ALL_EVENTS = 0xfff + IN_ATTRIB = 0x4 + IN_CLASSA_HOST = 0xffffff + IN_CLASSA_MAX = 0x80 + IN_CLASSA_NET = 0xff000000 + IN_CLASSA_NSHIFT = 0x18 + IN_CLASSB_HOST = 0xffff + IN_CLASSB_MAX = 0x10000 + IN_CLASSB_NET = 0xffff0000 + IN_CLASSB_NSHIFT = 0x10 + IN_CLASSC_HOST = 0xff + IN_CLASSC_NET = 0xffffff00 + IN_CLASSC_NSHIFT = 0x8 + IN_CLOEXEC = 0x400000 + IN_CLOSE = 0x18 + IN_CLOSE_NOWRITE = 0x10 + IN_CLOSE_WRITE = 0x8 + IN_CREATE = 0x100 + IN_DELETE = 0x200 + IN_DELETE_SELF = 0x400 + IN_DONT_FOLLOW = 0x2000000 + IN_EXCL_UNLINK = 0x4000000 + IN_IGNORED = 0x8000 + IN_ISDIR = 0x40000000 + IN_LOOPBACKNET = 0x7f + IN_MASK_ADD = 0x20000000 + IN_MASK_CREATE = 0x10000000 + IN_MODIFY = 0x2 + IN_MOVE = 0xc0 + IN_MOVED_FROM = 0x40 + IN_MOVED_TO = 0x80 + IN_MOVE_SELF = 0x800 + IN_NONBLOCK = 0x4000 + IN_ONESHOT = 0x80000000 + IN_ONLYDIR = 0x1000000 + IN_OPEN = 0x20 + IN_Q_OVERFLOW = 0x4000 + IN_UNMOUNT = 0x2000 + IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9 + IPPROTO_AH = 0x33 + IPPROTO_BEETPH = 0x5e + IPPROTO_COMP = 0x6c + IPPROTO_DCCP = 0x21 + IPPROTO_DSTOPTS = 0x3c + IPPROTO_EGP = 0x8 + IPPROTO_ENCAP = 0x62 + IPPROTO_ESP = 0x32 + IPPROTO_FRAGMENT = 0x2c + IPPROTO_GRE = 0x2f + IPPROTO_HOPOPTS = 0x0 + IPPROTO_ICMP = 0x1 + IPPROTO_ICMPV6 = 0x3a + IPPROTO_IDP = 0x16 + IPPROTO_IGMP = 0x2 + IPPROTO_IP = 0x0 + IPPROTO_IPIP = 0x4 + IPPROTO_IPV6 = 0x29 + IPPROTO_MH = 0x87 + IPPROTO_MPLS = 0x89 + IPPROTO_MTP = 0x5c + IPPROTO_NONE = 0x3b + IPPROTO_PIM = 0x67 + IPPROTO_PUP = 0xc + IPPROTO_RAW = 0xff + IPPROTO_ROUTING = 0x2b + IPPROTO_RSVP = 0x2e + IPPROTO_SCTP = 0x84 + IPPROTO_TCP = 0x6 + IPPROTO_TP = 0x1d + IPPROTO_UDP = 0x11 + IPPROTO_UDPLITE = 0x88 + IPV6_2292DSTOPTS = 0x4 + IPV6_2292HOPLIMIT = 0x8 + IPV6_2292HOPOPTS = 0x3 + IPV6_2292PKTINFO = 0x2 + IPV6_2292PKTOPTIONS = 0x6 + IPV6_2292RTHDR = 0x5 + IPV6_ADDRFORM = 0x1 + IPV6_ADDR_PREFERENCES = 0x48 + IPV6_ADD_MEMBERSHIP = 0x14 + IPV6_AUTHHDR = 0xa + IPV6_AUTOFLOWLABEL = 0x46 + IPV6_CHECKSUM = 0x7 + IPV6_DONTFRAG = 0x3e + IPV6_DROP_MEMBERSHIP = 0x15 + IPV6_DSTOPTS = 0x3b + IPV6_FREEBIND = 0x4e + IPV6_HDRINCL = 0x24 + IPV6_HOPLIMIT = 0x34 + IPV6_HOPOPTS = 0x36 + IPV6_IPSEC_POLICY = 0x22 + IPV6_JOIN_ANYCAST = 0x1b + IPV6_JOIN_GROUP = 0x14 + IPV6_LEAVE_ANYCAST = 0x1c + IPV6_LEAVE_GROUP = 0x15 + IPV6_MINHOPCOUNT = 0x49 + IPV6_MTU = 0x18 + IPV6_MTU_DISCOVER = 0x17 + IPV6_MULTICAST_ALL = 0x1d + IPV6_MULTICAST_HOPS = 0x12 + IPV6_MULTICAST_IF = 0x11 + IPV6_MULTICAST_LOOP = 0x13 + IPV6_NEXTHOP = 0x9 + IPV6_ORIGDSTADDR = 0x4a + IPV6_PATHMTU = 0x3d + IPV6_PKTINFO = 0x32 + IPV6_PMTUDISC_DO = 0x2 + IPV6_PMTUDISC_DONT = 0x0 + IPV6_PMTUDISC_INTERFACE = 0x4 + IPV6_PMTUDISC_OMIT = 0x5 + IPV6_PMTUDISC_PROBE = 0x3 + IPV6_PMTUDISC_WANT = 0x1 + IPV6_RECVDSTOPTS = 0x3a + IPV6_RECVERR = 0x19 + IPV6_RECVFRAGSIZE = 0x4d + IPV6_RECVHOPLIMIT = 0x33 + IPV6_RECVHOPOPTS = 0x35 + IPV6_RECVORIGDSTADDR = 0x4a + IPV6_RECVPATHMTU = 0x3c + IPV6_RECVPKTINFO = 0x31 + IPV6_RECVRTHDR = 0x38 + IPV6_RECVTCLASS = 0x42 + IPV6_ROUTER_ALERT = 0x16 + IPV6_RTHDR = 0x39 + IPV6_RTHDRDSTOPTS = 0x37 + IPV6_RTHDR_LOOSE = 0x0 + IPV6_RTHDR_STRICT = 0x1 + IPV6_RTHDR_TYPE_0 = 0x0 + IPV6_RXDSTOPTS = 0x3b + IPV6_RXHOPOPTS = 0x36 + IPV6_TCLASS = 0x43 + IPV6_TRANSPARENT = 0x4b + IPV6_UNICAST_HOPS = 0x10 + IPV6_UNICAST_IF = 0x4c + IPV6_V6ONLY = 0x1a + IPV6_XFRM_POLICY = 0x23 + IP_ADD_MEMBERSHIP = 0x23 + IP_ADD_SOURCE_MEMBERSHIP = 0x27 + IP_BIND_ADDRESS_NO_PORT = 0x18 + IP_BLOCK_SOURCE = 0x26 + IP_CHECKSUM = 0x17 + IP_DEFAULT_MULTICAST_LOOP = 0x1 + IP_DEFAULT_MULTICAST_TTL = 0x1 + IP_DF = 0x4000 + IP_DROP_MEMBERSHIP = 0x24 + IP_DROP_SOURCE_MEMBERSHIP = 0x28 + IP_FREEBIND = 0xf + IP_HDRINCL = 0x3 + IP_IPSEC_POLICY = 0x10 + IP_MAXPACKET = 0xffff + IP_MAX_MEMBERSHIPS = 0x14 + IP_MF = 0x2000 + IP_MINTTL = 0x15 + IP_MSFILTER = 0x29 + IP_MSS = 0x240 + IP_MTU = 0xe + IP_MTU_DISCOVER = 0xa + IP_MULTICAST_ALL = 0x31 + IP_MULTICAST_IF = 0x20 + IP_MULTICAST_LOOP = 0x22 + IP_MULTICAST_TTL = 0x21 + IP_NODEFRAG = 0x16 + IP_OFFMASK = 0x1fff + IP_OPTIONS = 0x4 + IP_ORIGDSTADDR = 0x14 + IP_PASSSEC = 0x12 + IP_PKTINFO = 0x8 + IP_PKTOPTIONS = 0x9 + IP_PMTUDISC = 0xa + IP_PMTUDISC_DO = 0x2 + IP_PMTUDISC_DONT = 0x0 + IP_PMTUDISC_INTERFACE = 0x4 + IP_PMTUDISC_OMIT = 0x5 + IP_PMTUDISC_PROBE = 0x3 + IP_PMTUDISC_WANT = 0x1 + IP_RECVERR = 0xb + IP_RECVFRAGSIZE = 0x19 + IP_RECVOPTS = 0x6 + IP_RECVORIGDSTADDR = 0x14 + IP_RECVRETOPTS = 0x7 + IP_RECVTOS = 0xd + IP_RECVTTL = 0xc + IP_RETOPTS = 0x7 + IP_RF = 0x8000 + IP_ROUTER_ALERT = 0x5 + IP_TOS = 0x1 + IP_TRANSPARENT = 0x13 + IP_TTL = 0x2 + IP_UNBLOCK_SOURCE = 0x25 + IP_UNICAST_IF = 0x32 + IP_XFRM_POLICY = 0x11 + ISIG = 0x1 + ISOFS_SUPER_MAGIC = 0x9660 + ISTRIP = 0x20 + IUCLC = 0x200 + IUTF8 = 0x4000 + IXANY = 0x800 + IXOFF = 0x1000 + IXON = 0x400 + JFFS2_SUPER_MAGIC = 0x72b6 + KEXEC_ARCH_386 = 0x30000 + KEXEC_ARCH_68K = 0x40000 + KEXEC_ARCH_AARCH64 = 0xb70000 + KEXEC_ARCH_ARM = 0x280000 + KEXEC_ARCH_DEFAULT = 0x0 + KEXEC_ARCH_IA_64 = 0x320000 + KEXEC_ARCH_MASK = 0xffff0000 + KEXEC_ARCH_MIPS = 0x80000 + KEXEC_ARCH_MIPS_LE = 0xa0000 + KEXEC_ARCH_PPC = 0x140000 + KEXEC_ARCH_PPC64 = 0x150000 + KEXEC_ARCH_S390 = 0x160000 + KEXEC_ARCH_SH = 0x2a0000 + KEXEC_ARCH_X86_64 = 0x3e0000 + KEXEC_FILE_NO_INITRAMFS = 0x4 + KEXEC_FILE_ON_CRASH = 0x2 + KEXEC_FILE_UNLOAD = 0x1 + KEXEC_ON_CRASH = 0x1 + KEXEC_PRESERVE_CONTEXT = 0x2 + KEXEC_SEGMENT_MAX = 0x10 + KEYCTL_ASSUME_AUTHORITY = 0x10 + KEYCTL_CHOWN = 0x4 + KEYCTL_CLEAR = 0x7 + KEYCTL_DESCRIBE = 0x6 + KEYCTL_DH_COMPUTE = 0x17 + KEYCTL_GET_KEYRING_ID = 0x0 + KEYCTL_GET_PERSISTENT = 0x16 + KEYCTL_GET_SECURITY = 0x11 + KEYCTL_INSTANTIATE = 0xc + KEYCTL_INSTANTIATE_IOV = 0x14 + KEYCTL_INVALIDATE = 0x15 + KEYCTL_JOIN_SESSION_KEYRING = 0x1 + KEYCTL_LINK = 0x8 + KEYCTL_NEGATE = 0xd + KEYCTL_PKEY_DECRYPT = 0x1a + KEYCTL_PKEY_ENCRYPT = 0x19 + KEYCTL_PKEY_QUERY = 0x18 + KEYCTL_PKEY_SIGN = 0x1b + KEYCTL_PKEY_VERIFY = 0x1c + KEYCTL_READ = 0xb + KEYCTL_REJECT = 0x13 + KEYCTL_RESTRICT_KEYRING = 0x1d + KEYCTL_REVOKE = 0x3 + KEYCTL_SEARCH = 0xa + KEYCTL_SESSION_TO_PARENT = 0x12 + KEYCTL_SETPERM = 0x5 + KEYCTL_SET_REQKEY_KEYRING = 0xe + KEYCTL_SET_TIMEOUT = 0xf + KEYCTL_SUPPORTS_DECRYPT = 0x2 + KEYCTL_SUPPORTS_ENCRYPT = 0x1 + KEYCTL_SUPPORTS_SIGN = 0x4 + KEYCTL_SUPPORTS_VERIFY = 0x8 + KEYCTL_UNLINK = 0x9 + KEYCTL_UPDATE = 0x2 + KEY_REQKEY_DEFL_DEFAULT = 0x0 + KEY_REQKEY_DEFL_GROUP_KEYRING = 0x6 + KEY_REQKEY_DEFL_NO_CHANGE = -0x1 + KEY_REQKEY_DEFL_PROCESS_KEYRING = 0x2 + KEY_REQKEY_DEFL_REQUESTOR_KEYRING = 0x7 + KEY_REQKEY_DEFL_SESSION_KEYRING = 0x3 + KEY_REQKEY_DEFL_THREAD_KEYRING = 0x1 + KEY_REQKEY_DEFL_USER_KEYRING = 0x4 + KEY_REQKEY_DEFL_USER_SESSION_KEYRING = 0x5 + KEY_SPEC_GROUP_KEYRING = -0x6 + KEY_SPEC_PROCESS_KEYRING = -0x2 + KEY_SPEC_REQKEY_AUTH_KEY = -0x7 + KEY_SPEC_REQUESTOR_KEYRING = -0x8 + KEY_SPEC_SESSION_KEYRING = -0x3 + KEY_SPEC_THREAD_KEYRING = -0x1 + KEY_SPEC_USER_KEYRING = -0x4 + KEY_SPEC_USER_SESSION_KEYRING = -0x5 + LINUX_REBOOT_CMD_CAD_OFF = 0x0 + LINUX_REBOOT_CMD_CAD_ON = 0x89abcdef + LINUX_REBOOT_CMD_HALT = 0xcdef0123 + LINUX_REBOOT_CMD_KEXEC = 0x45584543 + LINUX_REBOOT_CMD_POWER_OFF = 0x4321fedc + LINUX_REBOOT_CMD_RESTART = 0x1234567 + LINUX_REBOOT_CMD_RESTART2 = 0xa1b2c3d4 + LINUX_REBOOT_CMD_SW_SUSPEND = 0xd000fce2 + LINUX_REBOOT_MAGIC1 = 0xfee1dead + LINUX_REBOOT_MAGIC2 = 0x28121969 + LOCK_EX = 0x2 + LOCK_NB = 0x4 + LOCK_SH = 0x1 + LOCK_UN = 0x8 + MADV_DODUMP = 0x11 + MADV_DOFORK = 0xb + MADV_DONTDUMP = 0x10 + MADV_DONTFORK = 0xa + MADV_DONTNEED = 0x4 + MADV_FREE = 0x8 + MADV_HUGEPAGE = 0xe + MADV_HWPOISON = 0x64 + MADV_KEEPONFORK = 0x13 + MADV_MERGEABLE = 0xc + MADV_NOHUGEPAGE = 0xf + MADV_NORMAL = 0x0 + MADV_RANDOM = 0x1 + MADV_REMOVE = 0x9 + MADV_SEQUENTIAL = 0x2 + MADV_UNMERGEABLE = 0xd + MADV_WILLNEED = 0x3 + MADV_WIPEONFORK = 0x12 + MAP_ANON = 0x20 + MAP_ANONYMOUS = 0x20 + MAP_DENYWRITE = 0x800 + MAP_EXECUTABLE = 0x1000 + MAP_FILE = 0x0 + MAP_FIXED = 0x10 + MAP_FIXED_NOREPLACE = 0x100000 + MAP_GROWSDOWN = 0x200 + MAP_HUGETLB = 0x40000 + MAP_HUGE_MASK = 0x3f + MAP_HUGE_SHIFT = 0x1a + MAP_LOCKED = 0x100 + MAP_NONBLOCK = 0x10000 + MAP_NORESERVE = 0x40 + MAP_POPULATE = 0x8000 + MAP_PRIVATE = 0x2 + MAP_RENAME = 0x20 + MAP_SHARED = 0x1 + MAP_SHARED_VALIDATE = 0x3 + MAP_STACK = 0x20000 + MAP_TYPE = 0xf + MCL_CURRENT = 0x2000 + MCL_FUTURE = 0x4000 + MCL_ONFAULT = 0x8000 + MFD_ALLOW_SEALING = 0x2 + MFD_CLOEXEC = 0x1 + MFD_HUGETLB = 0x4 + MFD_HUGE_16GB = -0x78000000 + MFD_HUGE_16MB = 0x60000000 + MFD_HUGE_1GB = 0x78000000 + MFD_HUGE_1MB = 0x50000000 + MFD_HUGE_256MB = 0x70000000 + MFD_HUGE_2GB = 0x7c000000 + MFD_HUGE_2MB = 0x54000000 + MFD_HUGE_32MB = 0x64000000 + MFD_HUGE_512KB = 0x4c000000 + MFD_HUGE_512MB = 0x74000000 + MFD_HUGE_64KB = 0x40000000 + MFD_HUGE_8MB = 0x5c000000 + MFD_HUGE_MASK = 0x3f + MFD_HUGE_SHIFT = 0x1a + MINIX2_SUPER_MAGIC = 0x2468 + MINIX2_SUPER_MAGIC2 = 0x2478 + MINIX3_SUPER_MAGIC = 0x4d5a + MINIX_SUPER_MAGIC = 0x137f + MINIX_SUPER_MAGIC2 = 0x138f + MNT_DETACH = 0x2 + MNT_EXPIRE = 0x4 + MNT_FORCE = 0x1 + MODULE_INIT_IGNORE_MODVERSIONS = 0x1 + MODULE_INIT_IGNORE_VERMAGIC = 0x2 + MSDOS_SUPER_MAGIC = 0x4d44 + MSG_BATCH = 0x40000 + MSG_CMSG_CLOEXEC = 0x40000000 + MSG_CONFIRM = 0x800 + MSG_CTRUNC = 0x8 + MSG_DONTROUTE = 0x4 + MSG_DONTWAIT = 0x40 + MSG_EOR = 0x80 + MSG_ERRQUEUE = 0x2000 + MSG_FASTOPEN = 0x20000000 + MSG_FIN = 0x200 + MSG_MORE = 0x8000 + MSG_NOSIGNAL = 0x4000 + MSG_OOB = 0x1 + MSG_PEEK = 0x2 + MSG_PROXY = 0x10 + MSG_RST = 0x1000 + MSG_SYN = 0x400 + MSG_TRUNC = 0x20 + MSG_TRYHARD = 0x4 + MSG_WAITALL = 0x100 + MSG_WAITFORONE = 0x10000 + MSG_ZEROCOPY = 0x4000000 + MS_ACTIVE = 0x40000000 + MS_ASYNC = 0x1 + MS_BIND = 0x1000 + MS_BORN = 0x20000000 + MS_DIRSYNC = 0x80 + MS_INVALIDATE = 0x2 + MS_I_VERSION = 0x800000 + MS_KERNMOUNT = 0x400000 + MS_LAZYTIME = 0x2000000 + MS_MANDLOCK = 0x40 + MS_MGC_MSK = 0xffff0000 + MS_MGC_VAL = 0xc0ed0000 + MS_MOVE = 0x2000 + MS_NOATIME = 0x400 + MS_NODEV = 0x4 + MS_NODIRATIME = 0x800 + MS_NOEXEC = 0x8 + MS_NOREMOTELOCK = 0x8000000 + MS_NOSEC = 0x10000000 + MS_NOSUID = 0x2 + MS_NOUSER = -0x80000000 + MS_POSIXACL = 0x10000 + MS_PRIVATE = 0x40000 + MS_RDONLY = 0x1 + MS_REC = 0x4000 + MS_RELATIME = 0x200000 + MS_REMOUNT = 0x20 + MS_RMT_MASK = 0x2800051 + MS_SHARED = 0x100000 + MS_SILENT = 0x8000 + MS_SLAVE = 0x80000 + MS_STRICTATIME = 0x1000000 + MS_SUBMOUNT = 0x4000000 + MS_SYNC = 0x4 + MS_SYNCHRONOUS = 0x10 + MS_UNBINDABLE = 0x20000 + MS_VERBOSE = 0x8000 + MTD_INODE_FS_MAGIC = 0x11307854 + NAME_MAX = 0xff + NCP_SUPER_MAGIC = 0x564c + NETLINK_ADD_MEMBERSHIP = 0x1 + NETLINK_AUDIT = 0x9 + NETLINK_BROADCAST_ERROR = 0x4 + NETLINK_CAP_ACK = 0xa + NETLINK_CONNECTOR = 0xb + NETLINK_CRYPTO = 0x15 + NETLINK_DNRTMSG = 0xe + NETLINK_DROP_MEMBERSHIP = 0x2 + NETLINK_ECRYPTFS = 0x13 + NETLINK_EXT_ACK = 0xb + NETLINK_FIB_LOOKUP = 0xa + NETLINK_FIREWALL = 0x3 + NETLINK_GENERIC = 0x10 + NETLINK_GET_STRICT_CHK = 0xc + NETLINK_INET_DIAG = 0x4 + NETLINK_IP6_FW = 0xd + NETLINK_ISCSI = 0x8 + NETLINK_KOBJECT_UEVENT = 0xf + NETLINK_LISTEN_ALL_NSID = 0x8 + NETLINK_LIST_MEMBERSHIPS = 0x9 + NETLINK_NETFILTER = 0xc + NETLINK_NFLOG = 0x5 + NETLINK_NO_ENOBUFS = 0x5 + NETLINK_PKTINFO = 0x3 + NETLINK_RDMA = 0x14 + NETLINK_ROUTE = 0x0 + NETLINK_RX_RING = 0x6 + NETLINK_SCSITRANSPORT = 0x12 + NETLINK_SELINUX = 0x7 + NETLINK_SMC = 0x16 + NETLINK_SOCK_DIAG = 0x4 + NETLINK_TX_RING = 0x7 + NETLINK_UNUSED = 0x1 + NETLINK_USERSOCK = 0x2 + NETLINK_XFRM = 0x6 + NETNSA_MAX = 0x3 + NETNSA_NSID_NOT_ASSIGNED = -0x1 + NFNETLINK_V0 = 0x0 + NFNLGRP_ACCT_QUOTA = 0x8 + NFNLGRP_CONNTRACK_DESTROY = 0x3 + NFNLGRP_CONNTRACK_EXP_DESTROY = 0x6 + NFNLGRP_CONNTRACK_EXP_NEW = 0x4 + NFNLGRP_CONNTRACK_EXP_UPDATE = 0x5 + NFNLGRP_CONNTRACK_NEW = 0x1 + NFNLGRP_CONNTRACK_UPDATE = 0x2 + NFNLGRP_MAX = 0x9 + NFNLGRP_NFTABLES = 0x7 + NFNLGRP_NFTRACE = 0x9 + NFNLGRP_NONE = 0x0 + NFNL_BATCH_MAX = 0x1 + NFNL_MSG_BATCH_BEGIN = 0x10 + NFNL_MSG_BATCH_END = 0x11 + NFNL_NFA_NEST = 0x8000 + NFNL_SUBSYS_ACCT = 0x7 + NFNL_SUBSYS_COUNT = 0xc + NFNL_SUBSYS_CTHELPER = 0x9 + NFNL_SUBSYS_CTNETLINK = 0x1 + NFNL_SUBSYS_CTNETLINK_EXP = 0x2 + NFNL_SUBSYS_CTNETLINK_TIMEOUT = 0x8 + NFNL_SUBSYS_IPSET = 0x6 + NFNL_SUBSYS_NFTABLES = 0xa + NFNL_SUBSYS_NFT_COMPAT = 0xb + NFNL_SUBSYS_NONE = 0x0 + NFNL_SUBSYS_OSF = 0x5 + NFNL_SUBSYS_QUEUE = 0x3 + NFNL_SUBSYS_ULOG = 0x4 + NFS_SUPER_MAGIC = 0x6969 + NILFS_SUPER_MAGIC = 0x3434 + NL0 = 0x0 + NL1 = 0x100 + NLA_ALIGNTO = 0x4 + NLA_F_NESTED = 0x8000 + NLA_F_NET_BYTEORDER = 0x4000 + NLA_HDRLEN = 0x4 + NLDLY = 0x100 + NLMSG_ALIGNTO = 0x4 + NLMSG_DONE = 0x3 + NLMSG_ERROR = 0x2 + NLMSG_HDRLEN = 0x10 + NLMSG_MIN_TYPE = 0x10 + NLMSG_NOOP = 0x1 + NLMSG_OVERRUN = 0x4 + NLM_F_ACK = 0x4 + NLM_F_ACK_TLVS = 0x200 + NLM_F_APPEND = 0x800 + NLM_F_ATOMIC = 0x400 + NLM_F_CAPPED = 0x100 + NLM_F_CREATE = 0x400 + NLM_F_DUMP = 0x300 + NLM_F_DUMP_FILTERED = 0x20 + NLM_F_DUMP_INTR = 0x10 + NLM_F_ECHO = 0x8 + NLM_F_EXCL = 0x200 + NLM_F_MATCH = 0x200 + NLM_F_MULTI = 0x2 + NLM_F_NONREC = 0x100 + NLM_F_REPLACE = 0x100 + NLM_F_REQUEST = 0x1 + NLM_F_ROOT = 0x100 + NOFLSH = 0x80 + NSFS_MAGIC = 0x6e736673 + OCFS2_SUPER_MAGIC = 0x7461636f + OCRNL = 0x8 + OFDEL = 0x80 + OFILL = 0x40 + OLCUC = 0x2 + ONLCR = 0x4 + ONLRET = 0x20 + ONOCR = 0x10 + OPENPROM_SUPER_MAGIC = 0x9fa1 + OPOST = 0x1 + OVERLAYFS_SUPER_MAGIC = 0x794c7630 + O_ACCMODE = 0x3 + O_APPEND = 0x8 + O_ASYNC = 0x40 + O_CLOEXEC = 0x400000 + O_CREAT = 0x200 + O_DIRECT = 0x100000 + O_DIRECTORY = 0x10000 + O_DSYNC = 0x2000 + O_EXCL = 0x800 + O_FSYNC = 0x802000 + O_LARGEFILE = 0x0 + O_NDELAY = 0x4004 + O_NOATIME = 0x200000 + O_NOCTTY = 0x8000 + O_NOFOLLOW = 0x20000 + O_NONBLOCK = 0x4000 + O_PATH = 0x1000000 + O_RDONLY = 0x0 + O_RDWR = 0x2 + O_RSYNC = 0x802000 + O_SYNC = 0x802000 + O_TMPFILE = 0x2010000 + O_TRUNC = 0x400 + O_WRONLY = 0x1 + PACKET_ADD_MEMBERSHIP = 0x1 + PACKET_AUXDATA = 0x8 + PACKET_BROADCAST = 0x1 + PACKET_COPY_THRESH = 0x7 + PACKET_DROP_MEMBERSHIP = 0x2 + PACKET_FANOUT = 0x12 + PACKET_FANOUT_CBPF = 0x6 + PACKET_FANOUT_CPU = 0x2 + PACKET_FANOUT_DATA = 0x16 + PACKET_FANOUT_EBPF = 0x7 + PACKET_FANOUT_FLAG_DEFRAG = 0x8000 + PACKET_FANOUT_FLAG_ROLLOVER = 0x1000 + PACKET_FANOUT_FLAG_UNIQUEID = 0x2000 + PACKET_FANOUT_HASH = 0x0 + PACKET_FANOUT_LB = 0x1 + PACKET_FANOUT_QM = 0x5 + PACKET_FANOUT_RND = 0x4 + PACKET_FANOUT_ROLLOVER = 0x3 + PACKET_FASTROUTE = 0x6 + PACKET_HDRLEN = 0xb + PACKET_HOST = 0x0 + PACKET_IGNORE_OUTGOING = 0x17 + PACKET_KERNEL = 0x7 + PACKET_LOOPBACK = 0x5 + PACKET_LOSS = 0xe + PACKET_MR_ALLMULTI = 0x2 + PACKET_MR_MULTICAST = 0x0 + PACKET_MR_PROMISC = 0x1 + PACKET_MR_UNICAST = 0x3 + PACKET_MULTICAST = 0x2 + PACKET_ORIGDEV = 0x9 + PACKET_OTHERHOST = 0x3 + PACKET_OUTGOING = 0x4 + PACKET_QDISC_BYPASS = 0x14 + PACKET_RECV_OUTPUT = 0x3 + PACKET_RESERVE = 0xc + PACKET_ROLLOVER_STATS = 0x15 + PACKET_RX_RING = 0x5 + PACKET_STATISTICS = 0x6 + PACKET_TIMESTAMP = 0x11 + PACKET_TX_HAS_OFF = 0x13 + PACKET_TX_RING = 0xd + PACKET_TX_TIMESTAMP = 0x10 + PACKET_USER = 0x6 + PACKET_VERSION = 0xa + PACKET_VNET_HDR = 0xf + PARENB = 0x100 + PARITY_CRC16_PR0 = 0x2 + PARITY_CRC16_PR0_CCITT = 0x4 + PARITY_CRC16_PR1 = 0x3 + PARITY_CRC16_PR1_CCITT = 0x5 + PARITY_CRC32_PR0_CCITT = 0x6 + PARITY_CRC32_PR1_CCITT = 0x7 + PARITY_DEFAULT = 0x0 + PARITY_NONE = 0x1 + PARMRK = 0x8 + PARODD = 0x200 + PENDIN = 0x4000 + PERF_EVENT_IOC_DISABLE = 0x20002401 + PERF_EVENT_IOC_ENABLE = 0x20002400 + PERF_EVENT_IOC_ID = 0x40082407 + PERF_EVENT_IOC_MODIFY_ATTRIBUTES = 0x8008240b + PERF_EVENT_IOC_PAUSE_OUTPUT = 0x80042409 + PERF_EVENT_IOC_PERIOD = 0x80082404 + PERF_EVENT_IOC_QUERY_BPF = 0xc008240a + PERF_EVENT_IOC_REFRESH = 0x20002402 + PERF_EVENT_IOC_RESET = 0x20002403 + PERF_EVENT_IOC_SET_BPF = 0x80042408 + PERF_EVENT_IOC_SET_FILTER = 0x80082406 + PERF_EVENT_IOC_SET_OUTPUT = 0x20002405 + PIPEFS_MAGIC = 0x50495045 + PPPIOCATTACH = 0x8004743d + PPPIOCATTCHAN = 0x80047438 + PPPIOCCONNECT = 0x8004743a + PPPIOCDETACH = 0x8004743c + PPPIOCDISCONN = 0x20007439 + PPPIOCGASYNCMAP = 0x40047458 + PPPIOCGCHAN = 0x40047437 + PPPIOCGDEBUG = 0x40047441 + PPPIOCGFLAGS = 0x4004745a + PPPIOCGIDLE = 0x4010743f + PPPIOCGL2TPSTATS = 0x40487436 + PPPIOCGMRU = 0x40047453 + PPPIOCGNPMODE = 0xc008744c + PPPIOCGRASYNCMAP = 0x40047455 + PPPIOCGUNIT = 0x40047456 + PPPIOCGXASYNCMAP = 0x40207450 + PPPIOCNEWUNIT = 0xc004743e + PPPIOCSACTIVE = 0x80107446 + PPPIOCSASYNCMAP = 0x80047457 + PPPIOCSCOMPRESS = 0x8010744d + PPPIOCSDEBUG = 0x80047440 + PPPIOCSFLAGS = 0x80047459 + PPPIOCSMAXCID = 0x80047451 + PPPIOCSMRRU = 0x8004743b + PPPIOCSMRU = 0x80047452 + PPPIOCSNPMODE = 0x8008744b + PPPIOCSPASS = 0x80107447 + PPPIOCSRASYNCMAP = 0x80047454 + PPPIOCSXASYNCMAP = 0x8020744f + PPPIOCXFERUNIT = 0x2000744e + PRIO_PGRP = 0x1 + PRIO_PROCESS = 0x0 + PRIO_USER = 0x2 + PROC_SUPER_MAGIC = 0x9fa0 + PROT_EXEC = 0x4 + PROT_GROWSDOWN = 0x1000000 + PROT_GROWSUP = 0x2000000 + PROT_NONE = 0x0 + PROT_READ = 0x1 + PROT_WRITE = 0x2 + PR_CAPBSET_DROP = 0x18 + PR_CAPBSET_READ = 0x17 + PR_CAP_AMBIENT = 0x2f + PR_CAP_AMBIENT_CLEAR_ALL = 0x4 + PR_CAP_AMBIENT_IS_SET = 0x1 + PR_CAP_AMBIENT_LOWER = 0x3 + PR_CAP_AMBIENT_RAISE = 0x2 + PR_ENDIAN_BIG = 0x0 + PR_ENDIAN_LITTLE = 0x1 + PR_ENDIAN_PPC_LITTLE = 0x2 + PR_FPEMU_NOPRINT = 0x1 + PR_FPEMU_SIGFPE = 0x2 + PR_FP_EXC_ASYNC = 0x2 + PR_FP_EXC_DISABLED = 0x0 + PR_FP_EXC_DIV = 0x10000 + PR_FP_EXC_INV = 0x100000 + PR_FP_EXC_NONRECOV = 0x1 + PR_FP_EXC_OVF = 0x20000 + PR_FP_EXC_PRECISE = 0x3 + PR_FP_EXC_RES = 0x80000 + PR_FP_EXC_SW_ENABLE = 0x80 + PR_FP_EXC_UND = 0x40000 + PR_FP_MODE_FR = 0x1 + PR_FP_MODE_FRE = 0x2 + PR_GET_CHILD_SUBREAPER = 0x25 + PR_GET_DUMPABLE = 0x3 + PR_GET_ENDIAN = 0x13 + PR_GET_FPEMU = 0x9 + PR_GET_FPEXC = 0xb + PR_GET_FP_MODE = 0x2e + PR_GET_KEEPCAPS = 0x7 + PR_GET_NAME = 0x10 + PR_GET_NO_NEW_PRIVS = 0x27 + PR_GET_PDEATHSIG = 0x2 + PR_GET_SECCOMP = 0x15 + PR_GET_SECUREBITS = 0x1b + PR_GET_SPECULATION_CTRL = 0x34 + PR_GET_THP_DISABLE = 0x2a + PR_GET_TID_ADDRESS = 0x28 + PR_GET_TIMERSLACK = 0x1e + PR_GET_TIMING = 0xd + PR_GET_TSC = 0x19 + PR_GET_UNALIGN = 0x5 + PR_MCE_KILL = 0x21 + PR_MCE_KILL_CLEAR = 0x0 + PR_MCE_KILL_DEFAULT = 0x2 + PR_MCE_KILL_EARLY = 0x1 + PR_MCE_KILL_GET = 0x22 + PR_MCE_KILL_LATE = 0x0 + PR_MCE_KILL_SET = 0x1 + PR_MPX_DISABLE_MANAGEMENT = 0x2c + PR_MPX_ENABLE_MANAGEMENT = 0x2b + PR_SET_CHILD_SUBREAPER = 0x24 + PR_SET_DUMPABLE = 0x4 + PR_SET_ENDIAN = 0x14 + PR_SET_FPEMU = 0xa + PR_SET_FPEXC = 0xc + PR_SET_FP_MODE = 0x2d + PR_SET_KEEPCAPS = 0x8 + PR_SET_MM = 0x23 + PR_SET_MM_ARG_END = 0x9 + PR_SET_MM_ARG_START = 0x8 + PR_SET_MM_AUXV = 0xc + PR_SET_MM_BRK = 0x7 + PR_SET_MM_END_CODE = 0x2 + PR_SET_MM_END_DATA = 0x4 + PR_SET_MM_ENV_END = 0xb + PR_SET_MM_ENV_START = 0xa + PR_SET_MM_EXE_FILE = 0xd + PR_SET_MM_MAP = 0xe + PR_SET_MM_MAP_SIZE = 0xf + PR_SET_MM_START_BRK = 0x6 + PR_SET_MM_START_CODE = 0x1 + PR_SET_MM_START_DATA = 0x3 + PR_SET_MM_START_STACK = 0x5 + PR_SET_NAME = 0xf + PR_SET_NO_NEW_PRIVS = 0x26 + PR_SET_PDEATHSIG = 0x1 + PR_SET_PTRACER = 0x59616d61 + PR_SET_PTRACER_ANY = 0xffffffffffffffff + PR_SET_SECCOMP = 0x16 + PR_SET_SECUREBITS = 0x1c + PR_SET_SPECULATION_CTRL = 0x35 + PR_SET_THP_DISABLE = 0x29 + PR_SET_TIMERSLACK = 0x1d + PR_SET_TIMING = 0xe + PR_SET_TSC = 0x1a + PR_SET_UNALIGN = 0x6 + PR_SPEC_DISABLE = 0x4 + PR_SPEC_ENABLE = 0x2 + PR_SPEC_FORCE_DISABLE = 0x8 + PR_SPEC_INDIRECT_BRANCH = 0x1 + PR_SPEC_NOT_AFFECTED = 0x0 + PR_SPEC_PRCTL = 0x1 + PR_SPEC_STORE_BYPASS = 0x0 + PR_SVE_GET_VL = 0x33 + PR_SVE_SET_VL = 0x32 + PR_SVE_SET_VL_ONEXEC = 0x40000 + PR_SVE_VL_INHERIT = 0x20000 + PR_SVE_VL_LEN_MASK = 0xffff + PR_TASK_PERF_EVENTS_DISABLE = 0x1f + PR_TASK_PERF_EVENTS_ENABLE = 0x20 + PR_TIMING_STATISTICAL = 0x0 + PR_TIMING_TIMESTAMP = 0x1 + PR_TSC_ENABLE = 0x1 + PR_TSC_SIGSEGV = 0x2 + PR_UNALIGN_NOPRINT = 0x1 + PR_UNALIGN_SIGBUS = 0x2 + PSTOREFS_MAGIC = 0x6165676c + PTRACE_ATTACH = 0x10 + PTRACE_CONT = 0x7 + PTRACE_DETACH = 0x11 + PTRACE_EVENT_CLONE = 0x3 + PTRACE_EVENT_EXEC = 0x4 + PTRACE_EVENT_EXIT = 0x6 + PTRACE_EVENT_FORK = 0x1 + PTRACE_EVENT_SECCOMP = 0x7 + PTRACE_EVENT_STOP = 0x80 + PTRACE_EVENT_VFORK = 0x2 + PTRACE_EVENT_VFORK_DONE = 0x5 + PTRACE_GETEVENTMSG = 0x4201 + PTRACE_GETFPAREGS = 0x14 + PTRACE_GETFPREGS = 0xe + PTRACE_GETFPREGS64 = 0x19 + PTRACE_GETREGS = 0xc + PTRACE_GETREGS64 = 0x16 + PTRACE_GETREGSET = 0x4204 + PTRACE_GETSIGINFO = 0x4202 + PTRACE_GETSIGMASK = 0x420a + PTRACE_INTERRUPT = 0x4207 + PTRACE_KILL = 0x8 + PTRACE_LISTEN = 0x4208 + PTRACE_O_EXITKILL = 0x100000 + PTRACE_O_MASK = 0x3000ff + PTRACE_O_SUSPEND_SECCOMP = 0x200000 + PTRACE_O_TRACECLONE = 0x8 + PTRACE_O_TRACEEXEC = 0x10 + PTRACE_O_TRACEEXIT = 0x40 + PTRACE_O_TRACEFORK = 0x2 + PTRACE_O_TRACESECCOMP = 0x80 + PTRACE_O_TRACESYSGOOD = 0x1 + PTRACE_O_TRACEVFORK = 0x4 + PTRACE_O_TRACEVFORKDONE = 0x20 + PTRACE_PEEKDATA = 0x2 + PTRACE_PEEKSIGINFO = 0x4209 + PTRACE_PEEKSIGINFO_SHARED = 0x1 + PTRACE_PEEKTEXT = 0x1 + PTRACE_PEEKUSR = 0x3 + PTRACE_POKEDATA = 0x5 + PTRACE_POKETEXT = 0x4 + PTRACE_POKEUSR = 0x6 + PTRACE_READDATA = 0x10 + PTRACE_READTEXT = 0x12 + PTRACE_SECCOMP_GET_FILTER = 0x420c + PTRACE_SECCOMP_GET_METADATA = 0x420d + PTRACE_SEIZE = 0x4206 + PTRACE_SETFPAREGS = 0x15 + PTRACE_SETFPREGS = 0xf + PTRACE_SETFPREGS64 = 0x1a + PTRACE_SETOPTIONS = 0x4200 + PTRACE_SETREGS = 0xd + PTRACE_SETREGS64 = 0x17 + PTRACE_SETREGSET = 0x4205 + PTRACE_SETSIGINFO = 0x4203 + PTRACE_SETSIGMASK = 0x420b + PTRACE_SINGLESTEP = 0x9 + PTRACE_SPARC_DETACH = 0xb + PTRACE_SYSCALL = 0x18 + PTRACE_TRACEME = 0x0 + PTRACE_WRITEDATA = 0x11 + PTRACE_WRITETEXT = 0x13 + PT_FP = 0x48 + PT_G0 = 0x10 + PT_G1 = 0x14 + PT_G2 = 0x18 + PT_G3 = 0x1c + PT_G4 = 0x20 + PT_G5 = 0x24 + PT_G6 = 0x28 + PT_G7 = 0x2c + PT_I0 = 0x30 + PT_I1 = 0x34 + PT_I2 = 0x38 + PT_I3 = 0x3c + PT_I4 = 0x40 + PT_I5 = 0x44 + PT_I6 = 0x48 + PT_I7 = 0x4c + PT_NPC = 0x8 + PT_PC = 0x4 + PT_PSR = 0x0 + PT_REGS_MAGIC = 0x57ac6c00 + PT_TNPC = 0x90 + PT_TPC = 0x88 + PT_TSTATE = 0x80 + PT_V9_FP = 0x70 + PT_V9_G0 = 0x0 + PT_V9_G1 = 0x8 + PT_V9_G2 = 0x10 + PT_V9_G3 = 0x18 + PT_V9_G4 = 0x20 + PT_V9_G5 = 0x28 + PT_V9_G6 = 0x30 + PT_V9_G7 = 0x38 + PT_V9_I0 = 0x40 + PT_V9_I1 = 0x48 + PT_V9_I2 = 0x50 + PT_V9_I3 = 0x58 + PT_V9_I4 = 0x60 + PT_V9_I5 = 0x68 + PT_V9_I6 = 0x70 + PT_V9_I7 = 0x78 + PT_V9_MAGIC = 0x9c + PT_V9_TNPC = 0x90 + PT_V9_TPC = 0x88 + PT_V9_TSTATE = 0x80 + PT_V9_Y = 0x98 + PT_WIM = 0x10 + PT_Y = 0xc + QNX4_SUPER_MAGIC = 0x2f + QNX6_SUPER_MAGIC = 0x68191122 + RAMFS_MAGIC = 0x858458f6 + RDTGROUP_SUPER_MAGIC = 0x7655821 + REISERFS_SUPER_MAGIC = 0x52654973 + RENAME_EXCHANGE = 0x2 + RENAME_NOREPLACE = 0x1 + RENAME_WHITEOUT = 0x4 + RLIMIT_AS = 0x9 + RLIMIT_CORE = 0x4 + RLIMIT_CPU = 0x0 + RLIMIT_DATA = 0x2 + RLIMIT_FSIZE = 0x1 + RLIMIT_LOCKS = 0xa + RLIMIT_MEMLOCK = 0x8 + RLIMIT_MSGQUEUE = 0xc + RLIMIT_NICE = 0xd + RLIMIT_NOFILE = 0x6 + RLIMIT_NPROC = 0x7 + RLIMIT_RSS = 0x5 + RLIMIT_RTPRIO = 0xe + RLIMIT_RTTIME = 0xf + RLIMIT_SIGPENDING = 0xb + RLIMIT_STACK = 0x3 + RLIM_INFINITY = 0xffffffffffffffff + RNDADDENTROPY = 0x80085203 + RNDADDTOENTCNT = 0x80045201 + RNDCLEARPOOL = 0x20005206 + RNDGETENTCNT = 0x40045200 + RNDGETPOOL = 0x40085202 + RNDRESEEDCRNG = 0x20005207 + RNDZAPENTCNT = 0x20005204 + RTAX_ADVMSS = 0x8 + RTAX_CC_ALGO = 0x10 + RTAX_CWND = 0x7 + RTAX_FASTOPEN_NO_COOKIE = 0x11 + RTAX_FEATURES = 0xc + RTAX_FEATURE_ALLFRAG = 0x8 + RTAX_FEATURE_ECN = 0x1 + RTAX_FEATURE_MASK = 0xf + RTAX_FEATURE_SACK = 0x2 + RTAX_FEATURE_TIMESTAMP = 0x4 + RTAX_HOPLIMIT = 0xa + RTAX_INITCWND = 0xb + RTAX_INITRWND = 0xe + RTAX_LOCK = 0x1 + RTAX_MAX = 0x11 + RTAX_MTU = 0x2 + RTAX_QUICKACK = 0xf + RTAX_REORDERING = 0x9 + RTAX_RTO_MIN = 0xd + RTAX_RTT = 0x4 + RTAX_RTTVAR = 0x5 + RTAX_SSTHRESH = 0x6 + RTAX_UNSPEC = 0x0 + RTAX_WINDOW = 0x3 + RTA_ALIGNTO = 0x4 + RTA_MAX = 0x1d + RTCF_DIRECTSRC = 0x4000000 + RTCF_DOREDIRECT = 0x1000000 + RTCF_LOG = 0x2000000 + RTCF_MASQ = 0x400000 + RTCF_NAT = 0x800000 + RTCF_VALVE = 0x200000 + RTC_AF = 0x20 + RTC_AIE_OFF = 0x20007002 + RTC_AIE_ON = 0x20007001 + RTC_ALM_READ = 0x40247008 + RTC_ALM_SET = 0x80247007 + RTC_EPOCH_READ = 0x4008700d + RTC_EPOCH_SET = 0x8008700e + RTC_IRQF = 0x80 + RTC_IRQP_READ = 0x4008700b + RTC_IRQP_SET = 0x8008700c + RTC_MAX_FREQ = 0x2000 + RTC_PF = 0x40 + RTC_PIE_OFF = 0x20007006 + RTC_PIE_ON = 0x20007005 + RTC_PLL_GET = 0x40207011 + RTC_PLL_SET = 0x80207012 + RTC_RD_TIME = 0x40247009 + RTC_SET_TIME = 0x8024700a + RTC_UF = 0x10 + RTC_UIE_OFF = 0x20007004 + RTC_UIE_ON = 0x20007003 + RTC_VL_CLR = 0x20007014 + RTC_VL_READ = 0x40047013 + RTC_WIE_OFF = 0x20007010 + RTC_WIE_ON = 0x2000700f + RTC_WKALM_RD = 0x40287010 + RTC_WKALM_SET = 0x8028700f + RTF_ADDRCLASSMASK = 0xf8000000 + RTF_ADDRCONF = 0x40000 + RTF_ALLONLINK = 0x20000 + RTF_BROADCAST = 0x10000000 + RTF_CACHE = 0x1000000 + RTF_DEFAULT = 0x10000 + RTF_DYNAMIC = 0x10 + RTF_FLOW = 0x2000000 + RTF_GATEWAY = 0x2 + RTF_HOST = 0x4 + RTF_INTERFACE = 0x40000000 + RTF_IRTT = 0x100 + RTF_LINKRT = 0x100000 + RTF_LOCAL = 0x80000000 + RTF_MODIFIED = 0x20 + RTF_MSS = 0x40 + RTF_MTU = 0x40 + RTF_MULTICAST = 0x20000000 + RTF_NAT = 0x8000000 + RTF_NOFORWARD = 0x1000 + RTF_NONEXTHOP = 0x200000 + RTF_NOPMTUDISC = 0x4000 + RTF_POLICY = 0x4000000 + RTF_REINSTATE = 0x8 + RTF_REJECT = 0x200 + RTF_STATIC = 0x400 + RTF_THROW = 0x2000 + RTF_UP = 0x1 + RTF_WINDOW = 0x80 + RTF_XRESOLVE = 0x800 + RTM_BASE = 0x10 + RTM_DELACTION = 0x31 + RTM_DELADDR = 0x15 + RTM_DELADDRLABEL = 0x49 + RTM_DELCHAIN = 0x65 + RTM_DELLINK = 0x11 + RTM_DELMDB = 0x55 + RTM_DELNEIGH = 0x1d + RTM_DELNETCONF = 0x51 + RTM_DELNSID = 0x59 + RTM_DELQDISC = 0x25 + RTM_DELROUTE = 0x19 + RTM_DELRULE = 0x21 + RTM_DELTCLASS = 0x29 + RTM_DELTFILTER = 0x2d + RTM_F_CLONED = 0x200 + RTM_F_EQUALIZE = 0x400 + RTM_F_FIB_MATCH = 0x2000 + RTM_F_LOOKUP_TABLE = 0x1000 + RTM_F_NOTIFY = 0x100 + RTM_F_PREFIX = 0x800 + RTM_GETACTION = 0x32 + RTM_GETADDR = 0x16 + RTM_GETADDRLABEL = 0x4a + RTM_GETANYCAST = 0x3e + RTM_GETCHAIN = 0x66 + RTM_GETDCB = 0x4e + RTM_GETLINK = 0x12 + RTM_GETMDB = 0x56 + RTM_GETMULTICAST = 0x3a + RTM_GETNEIGH = 0x1e + RTM_GETNEIGHTBL = 0x42 + RTM_GETNETCONF = 0x52 + RTM_GETNSID = 0x5a + RTM_GETQDISC = 0x26 + RTM_GETROUTE = 0x1a + RTM_GETRULE = 0x22 + RTM_GETSTATS = 0x5e + RTM_GETTCLASS = 0x2a + RTM_GETTFILTER = 0x2e + RTM_MAX = 0x67 + RTM_NEWACTION = 0x30 + RTM_NEWADDR = 0x14 + RTM_NEWADDRLABEL = 0x48 + RTM_NEWCACHEREPORT = 0x60 + RTM_NEWCHAIN = 0x64 + RTM_NEWLINK = 0x10 + RTM_NEWMDB = 0x54 + RTM_NEWNDUSEROPT = 0x44 + RTM_NEWNEIGH = 0x1c + RTM_NEWNEIGHTBL = 0x40 + RTM_NEWNETCONF = 0x50 + RTM_NEWNSID = 0x58 + RTM_NEWPREFIX = 0x34 + RTM_NEWQDISC = 0x24 + RTM_NEWROUTE = 0x18 + RTM_NEWRULE = 0x20 + RTM_NEWSTATS = 0x5c + RTM_NEWTCLASS = 0x28 + RTM_NEWTFILTER = 0x2c + RTM_NR_FAMILIES = 0x16 + RTM_NR_MSGTYPES = 0x58 + RTM_SETDCB = 0x4f + RTM_SETLINK = 0x13 + RTM_SETNEIGHTBL = 0x43 + RTNH_ALIGNTO = 0x4 + RTNH_COMPARE_MASK = 0x19 + RTNH_F_DEAD = 0x1 + RTNH_F_LINKDOWN = 0x10 + RTNH_F_OFFLOAD = 0x8 + RTNH_F_ONLINK = 0x4 + RTNH_F_PERVASIVE = 0x2 + RTNH_F_UNRESOLVED = 0x20 + RTN_MAX = 0xb + RTPROT_BABEL = 0x2a + RTPROT_BGP = 0xba + RTPROT_BIRD = 0xc + RTPROT_BOOT = 0x3 + RTPROT_DHCP = 0x10 + RTPROT_DNROUTED = 0xd + RTPROT_EIGRP = 0xc0 + RTPROT_GATED = 0x8 + RTPROT_ISIS = 0xbb + RTPROT_KERNEL = 0x2 + RTPROT_MROUTED = 0x11 + RTPROT_MRT = 0xa + RTPROT_NTK = 0xf + RTPROT_OSPF = 0xbc + RTPROT_RA = 0x9 + RTPROT_REDIRECT = 0x1 + RTPROT_RIP = 0xbd + RTPROT_STATIC = 0x4 + RTPROT_UNSPEC = 0x0 + RTPROT_XORP = 0xe + RTPROT_ZEBRA = 0xb + RT_CLASS_DEFAULT = 0xfd + RT_CLASS_LOCAL = 0xff + RT_CLASS_MAIN = 0xfe + RT_CLASS_MAX = 0xff + RT_CLASS_UNSPEC = 0x0 + RUSAGE_CHILDREN = -0x1 + RUSAGE_SELF = 0x0 + RUSAGE_THREAD = 0x1 + SCM_CREDENTIALS = 0x2 + SCM_RIGHTS = 0x1 + SCM_TIMESTAMP = 0x1d + SCM_TIMESTAMPING = 0x23 + SCM_TIMESTAMPING_OPT_STATS = 0x38 + SCM_TIMESTAMPING_PKTINFO = 0x3c + SCM_TIMESTAMPNS = 0x21 + SCM_TXTIME = 0x3f + SCM_WIFI_STATUS = 0x25 + SC_LOG_FLUSH = 0x100000 + SECCOMP_MODE_DISABLED = 0x0 + SECCOMP_MODE_FILTER = 0x2 + SECCOMP_MODE_STRICT = 0x1 + SECURITYFS_MAGIC = 0x73636673 + SELINUX_MAGIC = 0xf97cff8c + SFD_CLOEXEC = 0x400000 + SFD_NONBLOCK = 0x4000 + SHUT_RD = 0x0 + SHUT_RDWR = 0x2 + SHUT_WR = 0x1 + SIOCADDDLCI = 0x8980 + SIOCADDMULTI = 0x8931 + SIOCADDRT = 0x890b + SIOCATMARK = 0x8905 + SIOCBONDCHANGEACTIVE = 0x8995 + SIOCBONDENSLAVE = 0x8990 + SIOCBONDINFOQUERY = 0x8994 + SIOCBONDRELEASE = 0x8991 + SIOCBONDSETHWADDR = 0x8992 + SIOCBONDSLAVEINFOQUERY = 0x8993 + SIOCBRADDBR = 0x89a0 + SIOCBRADDIF = 0x89a2 + SIOCBRDELBR = 0x89a1 + SIOCBRDELIF = 0x89a3 + SIOCDARP = 0x8953 + SIOCDELDLCI = 0x8981 + SIOCDELMULTI = 0x8932 + SIOCDELRT = 0x890c + SIOCDEVPRIVATE = 0x89f0 + SIOCDIFADDR = 0x8936 + SIOCDRARP = 0x8960 + SIOCETHTOOL = 0x8946 + SIOCGARP = 0x8954 + SIOCGHWTSTAMP = 0x89b1 + SIOCGIFADDR = 0x8915 + SIOCGIFBR = 0x8940 + SIOCGIFBRDADDR = 0x8919 + SIOCGIFCONF = 0x8912 + SIOCGIFCOUNT = 0x8938 + SIOCGIFDSTADDR = 0x8917 + SIOCGIFENCAP = 0x8925 + SIOCGIFFLAGS = 0x8913 + SIOCGIFHWADDR = 0x8927 + SIOCGIFINDEX = 0x8933 + SIOCGIFMAP = 0x8970 + SIOCGIFMEM = 0x891f + SIOCGIFMETRIC = 0x891d + SIOCGIFMTU = 0x8921 + SIOCGIFNAME = 0x8910 + SIOCGIFNETMASK = 0x891b + SIOCGIFPFLAGS = 0x8935 + SIOCGIFSLAVE = 0x8929 + SIOCGIFTXQLEN = 0x8942 + SIOCGIFVLAN = 0x8982 + SIOCGMIIPHY = 0x8947 + SIOCGMIIREG = 0x8948 + SIOCGPGRP = 0x8904 + SIOCGPPPCSTATS = 0x89f2 + SIOCGPPPSTATS = 0x89f0 + SIOCGPPPVER = 0x89f1 + SIOCGRARP = 0x8961 + SIOCGSKNS = 0x894c + SIOCGSTAMP = 0x8906 + SIOCGSTAMPNS = 0x8907 + SIOCINQ = 0x4004667f + SIOCOUTQ = 0x40047473 + SIOCOUTQNSD = 0x894b + SIOCPROTOPRIVATE = 0x89e0 + SIOCRTMSG = 0x890d + SIOCSARP = 0x8955 + SIOCSHWTSTAMP = 0x89b0 + SIOCSIFADDR = 0x8916 + SIOCSIFBR = 0x8941 + SIOCSIFBRDADDR = 0x891a + SIOCSIFDSTADDR = 0x8918 + SIOCSIFENCAP = 0x8926 + SIOCSIFFLAGS = 0x8914 + SIOCSIFHWADDR = 0x8924 + SIOCSIFHWBROADCAST = 0x8937 + SIOCSIFLINK = 0x8911 + SIOCSIFMAP = 0x8971 + SIOCSIFMEM = 0x8920 + SIOCSIFMETRIC = 0x891e + SIOCSIFMTU = 0x8922 + SIOCSIFNAME = 0x8923 + SIOCSIFNETMASK = 0x891c + SIOCSIFPFLAGS = 0x8934 + SIOCSIFSLAVE = 0x8930 + SIOCSIFTXQLEN = 0x8943 + SIOCSIFVLAN = 0x8983 + SIOCSMIIREG = 0x8949 + SIOCSPGRP = 0x8902 + SIOCSRARP = 0x8962 + SIOCWANDEV = 0x894a + SMACK_MAGIC = 0x43415d53 + SMART_AUTOSAVE = 0xd2 + SMART_AUTO_OFFLINE = 0xdb + SMART_DISABLE = 0xd9 + SMART_ENABLE = 0xd8 + SMART_HCYL_PASS = 0xc2 + SMART_IMMEDIATE_OFFLINE = 0xd4 + SMART_LCYL_PASS = 0x4f + SMART_READ_LOG_SECTOR = 0xd5 + SMART_READ_THRESHOLDS = 0xd1 + SMART_READ_VALUES = 0xd0 + SMART_SAVE = 0xd3 + SMART_STATUS = 0xda + SMART_WRITE_LOG_SECTOR = 0xd6 + SMART_WRITE_THRESHOLDS = 0xd7 + SMB_SUPER_MAGIC = 0x517b + SOCKFS_MAGIC = 0x534f434b + SOCK_CLOEXEC = 0x400000 + SOCK_DCCP = 0x6 + SOCK_DGRAM = 0x2 + SOCK_IOC_TYPE = 0x89 + SOCK_NONBLOCK = 0x4000 + SOCK_PACKET = 0xa + SOCK_RAW = 0x3 + SOCK_RDM = 0x4 + SOCK_SEQPACKET = 0x5 + SOCK_STREAM = 0x1 + SOL_AAL = 0x109 + SOL_ALG = 0x117 + SOL_ATM = 0x108 + SOL_CAIF = 0x116 + SOL_CAN_BASE = 0x64 + SOL_DCCP = 0x10d + SOL_DECNET = 0x105 + SOL_ICMPV6 = 0x3a + SOL_IP = 0x0 + SOL_IPV6 = 0x29 + SOL_IRDA = 0x10a + SOL_IUCV = 0x115 + SOL_KCM = 0x119 + SOL_LLC = 0x10c + SOL_NETBEUI = 0x10b + SOL_NETLINK = 0x10e + SOL_NFC = 0x118 + SOL_PACKET = 0x107 + SOL_PNPIPE = 0x113 + SOL_PPPOL2TP = 0x111 + SOL_RAW = 0xff + SOL_RDS = 0x114 + SOL_RXRPC = 0x110 + SOL_SOCKET = 0xffff + SOL_TCP = 0x6 + SOL_TIPC = 0x10f + SOL_TLS = 0x11a + SOL_X25 = 0x106 + SOL_XDP = 0x11b + SOMAXCONN = 0x80 + SO_ACCEPTCONN = 0x8000 + SO_ATTACH_BPF = 0x34 + SO_ATTACH_FILTER = 0x1a + SO_ATTACH_REUSEPORT_CBPF = 0x35 + SO_ATTACH_REUSEPORT_EBPF = 0x36 + SO_BINDTODEVICE = 0xd + SO_BPF_EXTENSIONS = 0x32 + SO_BROADCAST = 0x20 + SO_BSDCOMPAT = 0x400 + SO_BUSY_POLL = 0x30 + SO_CNX_ADVICE = 0x37 + SO_COOKIE = 0x3b + SO_DEBUG = 0x1 + SO_DETACH_BPF = 0x1b + SO_DETACH_FILTER = 0x1b + SO_DOMAIN = 0x1029 + SO_DONTROUTE = 0x10 + SO_EE_CODE_TXTIME_INVALID_PARAM = 0x1 + SO_EE_CODE_TXTIME_MISSED = 0x2 + SO_EE_CODE_ZEROCOPY_COPIED = 0x1 + SO_EE_ORIGIN_ICMP = 0x2 + SO_EE_ORIGIN_ICMP6 = 0x3 + SO_EE_ORIGIN_LOCAL = 0x1 + SO_EE_ORIGIN_NONE = 0x0 + SO_EE_ORIGIN_TIMESTAMPING = 0x4 + SO_EE_ORIGIN_TXSTATUS = 0x4 + SO_EE_ORIGIN_TXTIME = 0x6 + SO_EE_ORIGIN_ZEROCOPY = 0x5 + SO_ERROR = 0x1007 + SO_GET_FILTER = 0x1a + SO_INCOMING_CPU = 0x33 + SO_INCOMING_NAPI_ID = 0x3a + SO_KEEPALIVE = 0x8 + SO_LINGER = 0x80 + SO_LOCK_FILTER = 0x28 + SO_MARK = 0x22 + SO_MAX_PACING_RATE = 0x31 + SO_MEMINFO = 0x39 + SO_NOFCS = 0x27 + SO_NO_CHECK = 0xb + SO_OOBINLINE = 0x100 + SO_PASSCRED = 0x2 + SO_PASSSEC = 0x1f + SO_PEEK_OFF = 0x26 + SO_PEERCRED = 0x40 + SO_PEERGROUPS = 0x3d + SO_PEERNAME = 0x1c + SO_PEERSEC = 0x1e + SO_PRIORITY = 0xc + SO_PROTOCOL = 0x1028 + SO_RCVBUF = 0x1002 + SO_RCVBUFFORCE = 0x100b + SO_RCVLOWAT = 0x800 + SO_RCVTIMEO = 0x2000 + SO_REUSEADDR = 0x4 + SO_REUSEPORT = 0x200 + SO_RXQ_OVFL = 0x24 + SO_SECURITY_AUTHENTICATION = 0x5001 + SO_SECURITY_ENCRYPTION_NETWORK = 0x5004 + SO_SECURITY_ENCRYPTION_TRANSPORT = 0x5002 + SO_SELECT_ERR_QUEUE = 0x29 + SO_SNDBUF = 0x1001 + SO_SNDBUFFORCE = 0x100a + SO_SNDLOWAT = 0x1000 + SO_SNDTIMEO = 0x4000 + SO_TIMESTAMP = 0x1d + SO_TIMESTAMPING = 0x23 + SO_TIMESTAMPNS = 0x21 + SO_TXTIME = 0x3f + SO_TYPE = 0x1008 + SO_VM_SOCKETS_BUFFER_MAX_SIZE = 0x2 + SO_VM_SOCKETS_BUFFER_MIN_SIZE = 0x1 + SO_VM_SOCKETS_BUFFER_SIZE = 0x0 + SO_VM_SOCKETS_CONNECT_TIMEOUT = 0x6 + SO_VM_SOCKETS_NONBLOCK_TXRX = 0x7 + SO_VM_SOCKETS_PEER_HOST_VM_ID = 0x3 + SO_VM_SOCKETS_TRUSTED = 0x5 + SO_WIFI_STATUS = 0x25 + SO_ZEROCOPY = 0x3e + SPLICE_F_GIFT = 0x8 + SPLICE_F_MORE = 0x4 + SPLICE_F_MOVE = 0x1 + SPLICE_F_NONBLOCK = 0x2 + SQUASHFS_MAGIC = 0x73717368 + STACK_END_MAGIC = 0x57ac6e9d + STATX_ALL = 0xfff + STATX_ATIME = 0x20 + STATX_ATTR_APPEND = 0x20 + STATX_ATTR_AUTOMOUNT = 0x1000 + STATX_ATTR_COMPRESSED = 0x4 + STATX_ATTR_ENCRYPTED = 0x800 + STATX_ATTR_IMMUTABLE = 0x10 + STATX_ATTR_NODUMP = 0x40 + STATX_BASIC_STATS = 0x7ff + STATX_BLOCKS = 0x400 + STATX_BTIME = 0x800 + STATX_CTIME = 0x80 + STATX_GID = 0x10 + STATX_INO = 0x100 + STATX_MODE = 0x2 + STATX_MTIME = 0x40 + STATX_NLINK = 0x4 + STATX_SIZE = 0x200 + STATX_TYPE = 0x1 + STATX_UID = 0x8 + STATX__RESERVED = 0x80000000 + SYNC_FILE_RANGE_WAIT_AFTER = 0x4 + SYNC_FILE_RANGE_WAIT_BEFORE = 0x1 + SYNC_FILE_RANGE_WRITE = 0x2 + SYSFS_MAGIC = 0x62656572 + S_BLKSIZE = 0x200 + S_IEXEC = 0x40 + S_IFBLK = 0x6000 + S_IFCHR = 0x2000 + S_IFDIR = 0x4000 + S_IFIFO = 0x1000 + S_IFLNK = 0xa000 + S_IFMT = 0xf000 + S_IFREG = 0x8000 + S_IFSOCK = 0xc000 + S_IREAD = 0x100 + S_IRGRP = 0x20 + S_IROTH = 0x4 + S_IRUSR = 0x100 + S_IRWXG = 0x38 + S_IRWXO = 0x7 + S_IRWXU = 0x1c0 + S_ISGID = 0x400 + S_ISUID = 0x800 + S_ISVTX = 0x200 + S_IWGRP = 0x10 + S_IWOTH = 0x2 + S_IWRITE = 0x80 + S_IWUSR = 0x80 + S_IXGRP = 0x8 + S_IXOTH = 0x1 + S_IXUSR = 0x40 + TAB0 = 0x0 + TAB1 = 0x800 + TAB2 = 0x1000 + TAB3 = 0x1800 + TABDLY = 0x1800 + TASKSTATS_CMD_ATTR_MAX = 0x4 + TASKSTATS_CMD_MAX = 0x2 + TASKSTATS_GENL_NAME = "TASKSTATS" + TASKSTATS_GENL_VERSION = 0x1 + TASKSTATS_TYPE_MAX = 0x6 + TASKSTATS_VERSION = 0x9 + TCFLSH = 0x20005407 + TCGETA = 0x40125401 + TCGETS = 0x40245408 + TCGETS2 = 0x402c540c + TCIFLUSH = 0x0 + TCIOFF = 0x2 + TCIOFLUSH = 0x2 + TCION = 0x3 + TCOFLUSH = 0x1 + TCOOFF = 0x0 + TCOON = 0x1 + TCP_CC_INFO = 0x1a + TCP_CM_INQ = 0x24 + TCP_CONGESTION = 0xd + TCP_COOKIE_IN_ALWAYS = 0x1 + TCP_COOKIE_MAX = 0x10 + TCP_COOKIE_MIN = 0x8 + TCP_COOKIE_OUT_NEVER = 0x2 + TCP_COOKIE_PAIR_SIZE = 0x20 + TCP_COOKIE_TRANSACTIONS = 0xf + TCP_CORK = 0x3 + TCP_DEFER_ACCEPT = 0x9 + TCP_FASTOPEN = 0x17 + TCP_FASTOPEN_CONNECT = 0x1e + TCP_FASTOPEN_KEY = 0x21 + TCP_FASTOPEN_NO_COOKIE = 0x22 + TCP_INFO = 0xb + TCP_INQ = 0x24 + TCP_KEEPCNT = 0x6 + TCP_KEEPIDLE = 0x4 + TCP_KEEPINTVL = 0x5 + TCP_LINGER2 = 0x8 + TCP_MAXSEG = 0x2 + TCP_MAXWIN = 0xffff + TCP_MAX_WINSHIFT = 0xe + TCP_MD5SIG = 0xe + TCP_MD5SIG_EXT = 0x20 + TCP_MD5SIG_FLAG_PREFIX = 0x1 + TCP_MD5SIG_MAXKEYLEN = 0x50 + TCP_MSS = 0x200 + TCP_MSS_DEFAULT = 0x218 + TCP_MSS_DESIRED = 0x4c4 + TCP_NODELAY = 0x1 + TCP_NOTSENT_LOWAT = 0x19 + TCP_QUEUE_SEQ = 0x15 + TCP_QUICKACK = 0xc + TCP_REPAIR = 0x13 + TCP_REPAIR_OFF = 0x0 + TCP_REPAIR_OFF_NO_WP = -0x1 + TCP_REPAIR_ON = 0x1 + TCP_REPAIR_OPTIONS = 0x16 + TCP_REPAIR_QUEUE = 0x14 + TCP_REPAIR_WINDOW = 0x1d + TCP_SAVED_SYN = 0x1c + TCP_SAVE_SYN = 0x1b + TCP_SYNCNT = 0x7 + TCP_S_DATA_IN = 0x4 + TCP_S_DATA_OUT = 0x8 + TCP_THIN_DUPACK = 0x11 + TCP_THIN_LINEAR_TIMEOUTS = 0x10 + TCP_TIMESTAMP = 0x18 + TCP_ULP = 0x1f + TCP_USER_TIMEOUT = 0x12 + TCP_WINDOW_CLAMP = 0xa + TCP_ZEROCOPY_RECEIVE = 0x23 + TCSAFLUSH = 0x2 + TCSBRK = 0x20005405 + TCSBRKP = 0x5425 + TCSETA = 0x80125402 + TCSETAF = 0x80125404 + TCSETAW = 0x80125403 + TCSETS = 0x80245409 + TCSETS2 = 0x802c540d + TCSETSF = 0x8024540b + TCSETSF2 = 0x802c540f + TCSETSW = 0x8024540a + TCSETSW2 = 0x802c540e + TCXONC = 0x20005406 + TIMER_ABSTIME = 0x1 + TIOCCBRK = 0x2000747a + TIOCCONS = 0x20007424 + TIOCEXCL = 0x2000740d + TIOCGDEV = 0x40045432 + TIOCGETD = 0x40047400 + TIOCGEXCL = 0x40045440 + TIOCGICOUNT = 0x545d + TIOCGISO7816 = 0x40285443 + TIOCGLCKTRMIOS = 0x5456 + TIOCGPGRP = 0x40047483 + TIOCGPKT = 0x40045438 + TIOCGPTLCK = 0x40045439 + TIOCGPTN = 0x40047486 + TIOCGPTPEER = 0x20007489 + TIOCGRS485 = 0x40205441 + TIOCGSERIAL = 0x541e + TIOCGSID = 0x40047485 + TIOCGSOFTCAR = 0x40047464 + TIOCGWINSZ = 0x40087468 + TIOCINQ = 0x4004667f + TIOCLINUX = 0x541c + TIOCMBIC = 0x8004746b + TIOCMBIS = 0x8004746c + TIOCMGET = 0x4004746a + TIOCMIWAIT = 0x545c + TIOCMSET = 0x8004746d + TIOCM_CAR = 0x40 + TIOCM_CD = 0x40 + TIOCM_CTS = 0x20 + TIOCM_DSR = 0x100 + TIOCM_DTR = 0x2 + TIOCM_LE = 0x1 + TIOCM_RI = 0x80 + TIOCM_RNG = 0x80 + TIOCM_RTS = 0x4 + TIOCM_SR = 0x10 + TIOCM_ST = 0x8 + TIOCNOTTY = 0x20007471 + TIOCNXCL = 0x2000740e + TIOCOUTQ = 0x40047473 + TIOCPKT = 0x80047470 + TIOCPKT_DATA = 0x0 + TIOCPKT_DOSTOP = 0x20 + TIOCPKT_FLUSHREAD = 0x1 + TIOCPKT_FLUSHWRITE = 0x2 + TIOCPKT_IOCTL = 0x40 + TIOCPKT_NOSTOP = 0x10 + TIOCPKT_START = 0x8 + TIOCPKT_STOP = 0x4 + TIOCSBRK = 0x2000747b + TIOCSCTTY = 0x20007484 + TIOCSERCONFIG = 0x5453 + TIOCSERGETLSR = 0x5459 + TIOCSERGETMULTI = 0x545a + TIOCSERGSTRUCT = 0x5458 + TIOCSERGWILD = 0x5454 + TIOCSERSETMULTI = 0x545b + TIOCSERSWILD = 0x5455 + TIOCSETD = 0x80047401 + TIOCSIG = 0x80047488 + TIOCSISO7816 = 0xc0285444 + TIOCSLCKTRMIOS = 0x5457 + TIOCSPGRP = 0x80047482 + TIOCSPTLCK = 0x80047487 + TIOCSRS485 = 0xc0205442 + TIOCSSERIAL = 0x541f + TIOCSSOFTCAR = 0x80047465 + TIOCSTART = 0x2000746e + TIOCSTI = 0x80017472 + TIOCSTOP = 0x2000746f + TIOCSWINSZ = 0x80087467 + TIOCVHANGUP = 0x20005437 + TMPFS_MAGIC = 0x1021994 + TOSTOP = 0x100 + TPACKET_ALIGNMENT = 0x10 + TPACKET_HDRLEN = 0x34 + TP_STATUS_AVAILABLE = 0x0 + TP_STATUS_BLK_TMO = 0x20 + TP_STATUS_COPY = 0x2 + TP_STATUS_CSUMNOTREADY = 0x8 + TP_STATUS_CSUM_VALID = 0x80 + TP_STATUS_KERNEL = 0x0 + TP_STATUS_LOSING = 0x4 + TP_STATUS_SENDING = 0x2 + TP_STATUS_SEND_REQUEST = 0x1 + TP_STATUS_TS_RAW_HARDWARE = -0x80000000 + TP_STATUS_TS_SOFTWARE = 0x20000000 + TP_STATUS_TS_SYS_HARDWARE = 0x40000000 + TP_STATUS_USER = 0x1 + TP_STATUS_VLAN_TPID_VALID = 0x40 + TP_STATUS_VLAN_VALID = 0x10 + TP_STATUS_WRONG_FORMAT = 0x4 + TRACEFS_MAGIC = 0x74726163 + TS_COMM_LEN = 0x20 + TUNATTACHFILTER = 0x801054d5 + TUNDETACHFILTER = 0x801054d6 + TUNGETFEATURES = 0x400454cf + TUNGETFILTER = 0x401054db + TUNGETIFF = 0x400454d2 + TUNGETSNDBUF = 0x400454d3 + TUNGETVNETBE = 0x400454df + TUNGETVNETHDRSZ = 0x400454d7 + TUNGETVNETLE = 0x400454dd + TUNSETDEBUG = 0x800454c9 + TUNSETFILTEREBPF = 0x400454e1 + TUNSETGROUP = 0x800454ce + TUNSETIFF = 0x800454ca + TUNSETIFINDEX = 0x800454da + TUNSETLINK = 0x800454cd + TUNSETNOCSUM = 0x800454c8 + TUNSETOFFLOAD = 0x800454d0 + TUNSETOWNER = 0x800454cc + TUNSETPERSIST = 0x800454cb + TUNSETQUEUE = 0x800454d9 + TUNSETSNDBUF = 0x800454d4 + TUNSETSTEERINGEBPF = 0x400454e0 + TUNSETTXFILTER = 0x800454d1 + TUNSETVNETBE = 0x800454de + TUNSETVNETHDRSZ = 0x800454d8 + TUNSETVNETLE = 0x800454dc + UBI_IOCATT = 0x80186f40 + UBI_IOCDET = 0x80046f41 + UBI_IOCEBCH = 0x80044f02 + UBI_IOCEBER = 0x80044f01 + UBI_IOCEBISMAP = 0x40044f05 + UBI_IOCEBMAP = 0x80084f03 + UBI_IOCEBUNMAP = 0x80044f04 + UBI_IOCMKVOL = 0x80986f00 + UBI_IOCRMVOL = 0x80046f01 + UBI_IOCRNVOL = 0x91106f03 + UBI_IOCRSVOL = 0x800c6f02 + UBI_IOCSETVOLPROP = 0x80104f06 + UBI_IOCVOLCRBLK = 0x80804f07 + UBI_IOCVOLRMBLK = 0x20004f08 + UBI_IOCVOLUP = 0x80084f00 + UDF_SUPER_MAGIC = 0x15013346 + UMOUNT_NOFOLLOW = 0x8 + USBDEVICE_SUPER_MAGIC = 0x9fa2 + UTIME_NOW = 0x3fffffff + UTIME_OMIT = 0x3ffffffe + V9FS_MAGIC = 0x1021997 + VDISCARD = 0xd + VEOF = 0x4 + VEOL = 0xb + VEOL2 = 0x10 + VERASE = 0x2 + VINTR = 0x0 + VKILL = 0x3 + VLNEXT = 0xf + VMADDR_CID_ANY = 0xffffffff + VMADDR_CID_HOST = 0x2 + VMADDR_CID_HYPERVISOR = 0x0 + VMADDR_CID_RESERVED = 0x1 + VMADDR_PORT_ANY = 0xffffffff + VMIN = 0x6 + VM_SOCKETS_INVALID_VERSION = 0xffffffff + VQUIT = 0x1 + VREPRINT = 0xc + VSTART = 0x8 + VSTOP = 0x9 + VSUSP = 0xa + VSWTC = 0x7 + VT0 = 0x0 + VT1 = 0x4000 + VTDLY = 0x4000 + VTIME = 0x5 + VWERASE = 0xe + WALL = 0x40000000 + WCLONE = 0x80000000 + WCONTINUED = 0x8 + WDIOC_GETBOOTSTATUS = 0x40045702 + WDIOC_GETPRETIMEOUT = 0x40045709 + WDIOC_GETSTATUS = 0x40045701 + WDIOC_GETSUPPORT = 0x40285700 + WDIOC_GETTEMP = 0x40045703 + WDIOC_GETTIMELEFT = 0x4004570a + WDIOC_GETTIMEOUT = 0x40045707 + WDIOC_KEEPALIVE = 0x40045705 + WDIOC_SETOPTIONS = 0x40045704 + WDIOC_SETPRETIMEOUT = 0xc0045708 + WDIOC_SETTIMEOUT = 0xc0045706 + WEXITED = 0x4 + WIN_ACKMEDIACHANGE = 0xdb + WIN_CHECKPOWERMODE1 = 0xe5 + WIN_CHECKPOWERMODE2 = 0x98 + WIN_DEVICE_RESET = 0x8 + WIN_DIAGNOSE = 0x90 + WIN_DOORLOCK = 0xde + WIN_DOORUNLOCK = 0xdf + WIN_DOWNLOAD_MICROCODE = 0x92 + WIN_FLUSH_CACHE = 0xe7 + WIN_FLUSH_CACHE_EXT = 0xea + WIN_FORMAT = 0x50 + WIN_GETMEDIASTATUS = 0xda + WIN_IDENTIFY = 0xec + WIN_IDENTIFY_DMA = 0xee + WIN_IDLEIMMEDIATE = 0xe1 + WIN_INIT = 0x60 + WIN_MEDIAEJECT = 0xed + WIN_MULTREAD = 0xc4 + WIN_MULTREAD_EXT = 0x29 + WIN_MULTWRITE = 0xc5 + WIN_MULTWRITE_EXT = 0x39 + WIN_NOP = 0x0 + WIN_PACKETCMD = 0xa0 + WIN_PIDENTIFY = 0xa1 + WIN_POSTBOOT = 0xdc + WIN_PREBOOT = 0xdd + WIN_QUEUED_SERVICE = 0xa2 + WIN_READ = 0x20 + WIN_READDMA = 0xc8 + WIN_READDMA_EXT = 0x25 + WIN_READDMA_ONCE = 0xc9 + WIN_READDMA_QUEUED = 0xc7 + WIN_READDMA_QUEUED_EXT = 0x26 + WIN_READ_BUFFER = 0xe4 + WIN_READ_EXT = 0x24 + WIN_READ_LONG = 0x22 + WIN_READ_LONG_ONCE = 0x23 + WIN_READ_NATIVE_MAX = 0xf8 + WIN_READ_NATIVE_MAX_EXT = 0x27 + WIN_READ_ONCE = 0x21 + WIN_RECAL = 0x10 + WIN_RESTORE = 0x10 + WIN_SECURITY_DISABLE = 0xf6 + WIN_SECURITY_ERASE_PREPARE = 0xf3 + WIN_SECURITY_ERASE_UNIT = 0xf4 + WIN_SECURITY_FREEZE_LOCK = 0xf5 + WIN_SECURITY_SET_PASS = 0xf1 + WIN_SECURITY_UNLOCK = 0xf2 + WIN_SEEK = 0x70 + WIN_SETFEATURES = 0xef + WIN_SETIDLE1 = 0xe3 + WIN_SETIDLE2 = 0x97 + WIN_SETMULT = 0xc6 + WIN_SET_MAX = 0xf9 + WIN_SET_MAX_EXT = 0x37 + WIN_SLEEPNOW1 = 0xe6 + WIN_SLEEPNOW2 = 0x99 + WIN_SMART = 0xb0 + WIN_SPECIFY = 0x91 + WIN_SRST = 0x8 + WIN_STANDBY = 0xe2 + WIN_STANDBY2 = 0x96 + WIN_STANDBYNOW1 = 0xe0 + WIN_STANDBYNOW2 = 0x94 + WIN_VERIFY = 0x40 + WIN_VERIFY_EXT = 0x42 + WIN_VERIFY_ONCE = 0x41 + WIN_WRITE = 0x30 + WIN_WRITEDMA = 0xca + WIN_WRITEDMA_EXT = 0x35 + WIN_WRITEDMA_ONCE = 0xcb + WIN_WRITEDMA_QUEUED = 0xcc + WIN_WRITEDMA_QUEUED_EXT = 0x36 + WIN_WRITE_BUFFER = 0xe8 + WIN_WRITE_EXT = 0x34 + WIN_WRITE_LONG = 0x32 + WIN_WRITE_LONG_ONCE = 0x33 + WIN_WRITE_ONCE = 0x31 + WIN_WRITE_SAME = 0xe9 + WIN_WRITE_VERIFY = 0x3c + WNOHANG = 0x1 + WNOTHREAD = 0x20000000 + WNOWAIT = 0x1000000 + WORDSIZE = 0x40 + WSTOPPED = 0x2 + WUNTRACED = 0x2 + XATTR_CREATE = 0x1 + XATTR_REPLACE = 0x2 + XCASE = 0x4 + XDP_COPY = 0x2 + XDP_FLAGS_DRV_MODE = 0x4 + XDP_FLAGS_HW_MODE = 0x8 + XDP_FLAGS_MASK = 0xf + XDP_FLAGS_MODES = 0xe + XDP_FLAGS_SKB_MODE = 0x2 + XDP_FLAGS_UPDATE_IF_NOEXIST = 0x1 + XDP_MMAP_OFFSETS = 0x1 + XDP_PGOFF_RX_RING = 0x0 + XDP_PGOFF_TX_RING = 0x80000000 + XDP_RX_RING = 0x2 + XDP_SHARED_UMEM = 0x1 + XDP_STATISTICS = 0x7 + XDP_TX_RING = 0x3 + XDP_UMEM_COMPLETION_RING = 0x6 + XDP_UMEM_FILL_RING = 0x5 + XDP_UMEM_PGOFF_COMPLETION_RING = 0x180000000 + XDP_UMEM_PGOFF_FILL_RING = 0x100000000 + XDP_UMEM_REG = 0x4 + XDP_ZEROCOPY = 0x4 + XENFS_SUPER_MAGIC = 0xabba1974 + XFS_SUPER_MAGIC = 0x58465342 + XTABS = 0x1800 + ZSMALLOC_MAGIC = 0x58295829 + __TIOCFLUSH = 0x80047410 ) // Errors @@ -1969,174 +2657,182 @@ const ( ) // Error table -var errors = [...]string{ - 1: "operation not permitted", - 2: "no such file or directory", - 3: "no such process", - 4: "interrupted system call", - 5: "input/output error", - 6: "no such device or address", - 7: "argument list too long", - 8: "exec format error", - 9: "bad file descriptor", - 10: "no child processes", - 11: "resource temporarily unavailable", - 12: "cannot allocate memory", - 13: "permission denied", - 14: "bad address", - 15: "block device required", - 16: "device or resource busy", - 17: "file exists", - 18: "invalid cross-device link", - 19: "no such device", - 20: "not a directory", - 21: "is a directory", - 22: "invalid argument", - 23: "too many open files in system", - 24: "too many open files", - 25: "inappropriate ioctl for device", - 26: "text file busy", - 27: "file too large", - 28: "no space left on device", - 29: "illegal seek", - 30: "read-only file system", - 31: "too many links", - 32: "broken pipe", - 33: "numerical argument out of domain", - 34: "numerical result out of range", - 36: "operation now in progress", - 37: "operation already in progress", - 38: "socket operation on non-socket", - 39: "destination address required", - 40: "message too long", - 41: "protocol wrong type for socket", - 42: "protocol not available", - 43: "protocol not supported", - 44: "socket type not supported", - 45: "operation not supported", - 46: "protocol family not supported", - 47: "address family not supported by protocol", - 48: "address already in use", - 49: "cannot assign requested address", - 50: "network is down", - 51: "network is unreachable", - 52: "network dropped connection on reset", - 53: "software caused connection abort", - 54: "connection reset by peer", - 55: "no buffer space available", - 56: "transport endpoint is already connected", - 57: "transport endpoint is not connected", - 58: "cannot send after transport endpoint shutdown", - 59: "too many references: cannot splice", - 60: "connection timed out", - 61: "connection refused", - 62: "too many levels of symbolic links", - 63: "file name too long", - 64: "host is down", - 65: "no route to host", - 66: "directory not empty", - 67: "too many processes", - 68: "too many users", - 69: "disk quota exceeded", - 70: "stale file handle", - 71: "object is remote", - 72: "device not a stream", - 73: "timer expired", - 74: "out of streams resources", - 75: "no message of desired type", - 76: "bad message", - 77: "identifier removed", - 78: "resource deadlock avoided", - 79: "no locks available", - 80: "machine is not on the network", - 81: "unknown error 81", - 82: "link has been severed", - 83: "advertise error", - 84: "srmount error", - 85: "communication error on send", - 86: "protocol error", - 87: "multihop attempted", - 88: "RFS specific error", - 89: "remote address changed", - 90: "function not implemented", - 91: "streams pipe error", - 92: "value too large for defined data type", - 93: "file descriptor in bad state", - 94: "channel number out of range", - 95: "level 2 not synchronized", - 96: "level 3 halted", - 97: "level 3 reset", - 98: "link number out of range", - 99: "protocol driver not attached", - 100: "no CSI structure available", - 101: "level 2 halted", - 102: "invalid exchange", - 103: "invalid request descriptor", - 104: "exchange full", - 105: "no anode", - 106: "invalid request code", - 107: "invalid slot", - 108: "file locking deadlock error", - 109: "bad font file format", - 110: "cannot exec a shared library directly", - 111: "no data available", - 112: "accessing a corrupted shared library", - 113: "package not installed", - 114: "can not access a needed shared library", - 115: "name not unique on network", - 116: "interrupted system call should be restarted", - 117: "structure needs cleaning", - 118: "not a XENIX named type file", - 119: "no XENIX semaphores available", - 120: "is a named type file", - 121: "remote I/O error", - 122: "invalid or incomplete multibyte or wide character", - 123: "attempting to link in too many shared libraries", - 124: ".lib section in a.out corrupted", - 125: "no medium found", - 126: "wrong medium type", - 127: "operation canceled", - 128: "required key not available", - 129: "key has expired", - 130: "key has been revoked", - 131: "key was rejected by service", - 132: "owner died", - 133: "state not recoverable", - 134: "operation not possible due to RF-kill", - 135: "memory page has hardware error", +var errorList = [...]struct { + num syscall.Errno + name string + desc string +}{ + {1, "EPERM", "operation not permitted"}, + {2, "ENOENT", "no such file or directory"}, + {3, "ESRCH", "no such process"}, + {4, "EINTR", "interrupted system call"}, + {5, "EIO", "input/output error"}, + {6, "ENXIO", "no such device or address"}, + {7, "E2BIG", "argument list too long"}, + {8, "ENOEXEC", "exec format error"}, + {9, "EBADF", "bad file descriptor"}, + {10, "ECHILD", "no child processes"}, + {11, "EAGAIN", "resource temporarily unavailable"}, + {12, "ENOMEM", "cannot allocate memory"}, + {13, "EACCES", "permission denied"}, + {14, "EFAULT", "bad address"}, + {15, "ENOTBLK", "block device required"}, + {16, "EBUSY", "device or resource busy"}, + {17, "EEXIST", "file exists"}, + {18, "EXDEV", "invalid cross-device link"}, + {19, "ENODEV", "no such device"}, + {20, "ENOTDIR", "not a directory"}, + {21, "EISDIR", "is a directory"}, + {22, "EINVAL", "invalid argument"}, + {23, "ENFILE", "too many open files in system"}, + {24, "EMFILE", "too many open files"}, + {25, "ENOTTY", "inappropriate ioctl for device"}, + {26, "ETXTBSY", "text file busy"}, + {27, "EFBIG", "file too large"}, + {28, "ENOSPC", "no space left on device"}, + {29, "ESPIPE", "illegal seek"}, + {30, "EROFS", "read-only file system"}, + {31, "EMLINK", "too many links"}, + {32, "EPIPE", "broken pipe"}, + {33, "EDOM", "numerical argument out of domain"}, + {34, "ERANGE", "numerical result out of range"}, + {36, "EINPROGRESS", "operation now in progress"}, + {37, "EALREADY", "operation already in progress"}, + {38, "ENOTSOCK", "socket operation on non-socket"}, + {39, "EDESTADDRREQ", "destination address required"}, + {40, "EMSGSIZE", "message too long"}, + {41, "EPROTOTYPE", "protocol wrong type for socket"}, + {42, "ENOPROTOOPT", "protocol not available"}, + {43, "EPROTONOSUPPORT", "protocol not supported"}, + {44, "ESOCKTNOSUPPORT", "socket type not supported"}, + {45, "ENOTSUP", "operation not supported"}, + {46, "EPFNOSUPPORT", "protocol family not supported"}, + {47, "EAFNOSUPPORT", "address family not supported by protocol"}, + {48, "EADDRINUSE", "address already in use"}, + {49, "EADDRNOTAVAIL", "cannot assign requested address"}, + {50, "ENETDOWN", "network is down"}, + {51, "ENETUNREACH", "network is unreachable"}, + {52, "ENETRESET", "network dropped connection on reset"}, + {53, "ECONNABORTED", "software caused connection abort"}, + {54, "ECONNRESET", "connection reset by peer"}, + {55, "ENOBUFS", "no buffer space available"}, + {56, "EISCONN", "transport endpoint is already connected"}, + {57, "ENOTCONN", "transport endpoint is not connected"}, + {58, "ESHUTDOWN", "cannot send after transport endpoint shutdown"}, + {59, "ETOOMANYREFS", "too many references: cannot splice"}, + {60, "ETIMEDOUT", "connection timed out"}, + {61, "ECONNREFUSED", "connection refused"}, + {62, "ELOOP", "too many levels of symbolic links"}, + {63, "ENAMETOOLONG", "file name too long"}, + {64, "EHOSTDOWN", "host is down"}, + {65, "EHOSTUNREACH", "no route to host"}, + {66, "ENOTEMPTY", "directory not empty"}, + {67, "EPROCLIM", "too many processes"}, + {68, "EUSERS", "too many users"}, + {69, "EDQUOT", "disk quota exceeded"}, + {70, "ESTALE", "stale file handle"}, + {71, "EREMOTE", "object is remote"}, + {72, "ENOSTR", "device not a stream"}, + {73, "ETIME", "timer expired"}, + {74, "ENOSR", "out of streams resources"}, + {75, "ENOMSG", "no message of desired type"}, + {76, "EBADMSG", "bad message"}, + {77, "EIDRM", "identifier removed"}, + {78, "EDEADLK", "resource deadlock avoided"}, + {79, "ENOLCK", "no locks available"}, + {80, "ENONET", "machine is not on the network"}, + {81, "ERREMOTE", "unknown error 81"}, + {82, "ENOLINK", "link has been severed"}, + {83, "EADV", "advertise error"}, + {84, "ESRMNT", "srmount error"}, + {85, "ECOMM", "communication error on send"}, + {86, "EPROTO", "protocol error"}, + {87, "EMULTIHOP", "multihop attempted"}, + {88, "EDOTDOT", "RFS specific error"}, + {89, "EREMCHG", "remote address changed"}, + {90, "ENOSYS", "function not implemented"}, + {91, "ESTRPIPE", "streams pipe error"}, + {92, "EOVERFLOW", "value too large for defined data type"}, + {93, "EBADFD", "file descriptor in bad state"}, + {94, "ECHRNG", "channel number out of range"}, + {95, "EL2NSYNC", "level 2 not synchronized"}, + {96, "EL3HLT", "level 3 halted"}, + {97, "EL3RST", "level 3 reset"}, + {98, "ELNRNG", "link number out of range"}, + {99, "EUNATCH", "protocol driver not attached"}, + {100, "ENOCSI", "no CSI structure available"}, + {101, "EL2HLT", "level 2 halted"}, + {102, "EBADE", "invalid exchange"}, + {103, "EBADR", "invalid request descriptor"}, + {104, "EXFULL", "exchange full"}, + {105, "ENOANO", "no anode"}, + {106, "EBADRQC", "invalid request code"}, + {107, "EBADSLT", "invalid slot"}, + {108, "EDEADLOCK", "file locking deadlock error"}, + {109, "EBFONT", "bad font file format"}, + {110, "ELIBEXEC", "cannot exec a shared library directly"}, + {111, "ENODATA", "no data available"}, + {112, "ELIBBAD", "accessing a corrupted shared library"}, + {113, "ENOPKG", "package not installed"}, + {114, "ELIBACC", "can not access a needed shared library"}, + {115, "ENOTUNIQ", "name not unique on network"}, + {116, "ERESTART", "interrupted system call should be restarted"}, + {117, "EUCLEAN", "structure needs cleaning"}, + {118, "ENOTNAM", "not a XENIX named type file"}, + {119, "ENAVAIL", "no XENIX semaphores available"}, + {120, "EISNAM", "is a named type file"}, + {121, "EREMOTEIO", "remote I/O error"}, + {122, "EILSEQ", "invalid or incomplete multibyte or wide character"}, + {123, "ELIBMAX", "attempting to link in too many shared libraries"}, + {124, "ELIBSCN", ".lib section in a.out corrupted"}, + {125, "ENOMEDIUM", "no medium found"}, + {126, "EMEDIUMTYPE", "wrong medium type"}, + {127, "ECANCELED", "operation canceled"}, + {128, "ENOKEY", "required key not available"}, + {129, "EKEYEXPIRED", "key has expired"}, + {130, "EKEYREVOKED", "key has been revoked"}, + {131, "EKEYREJECTED", "key was rejected by service"}, + {132, "EOWNERDEAD", "owner died"}, + {133, "ENOTRECOVERABLE", "state not recoverable"}, + {134, "ERFKILL", "operation not possible due to RF-kill"}, + {135, "EHWPOISON", "memory page has hardware error"}, } // Signal table -var signals = [...]string{ - 1: "hangup", - 2: "interrupt", - 3: "quit", - 4: "illegal instruction", - 5: "trace/breakpoint trap", - 6: "aborted", - 7: "EMT trap", - 8: "floating point exception", - 9: "killed", - 10: "bus error", - 11: "segmentation fault", - 12: "bad system call", - 13: "broken pipe", - 14: "alarm clock", - 15: "terminated", - 16: "urgent I/O condition", - 17: "stopped (signal)", - 18: "stopped", - 19: "continued", - 20: "child exited", - 21: "stopped (tty input)", - 22: "stopped (tty output)", - 23: "I/O possible", - 24: "CPU time limit exceeded", - 25: "file size limit exceeded", - 26: "virtual timer expired", - 27: "profiling timer expired", - 28: "window changed", - 29: "resource lost", - 30: "user defined signal 1", - 31: "user defined signal 2", +var signalList = [...]struct { + num syscall.Signal + name string + desc string +}{ + {1, "SIGHUP", "hangup"}, + {2, "SIGINT", "interrupt"}, + {3, "SIGQUIT", "quit"}, + {4, "SIGILL", "illegal instruction"}, + {5, "SIGTRAP", "trace/breakpoint trap"}, + {6, "SIGABRT", "aborted"}, + {7, "SIGEMT", "EMT trap"}, + {8, "SIGFPE", "floating point exception"}, + {9, "SIGKILL", "killed"}, + {10, "SIGBUS", "bus error"}, + {11, "SIGSEGV", "segmentation fault"}, + {12, "SIGSYS", "bad system call"}, + {13, "SIGPIPE", "broken pipe"}, + {14, "SIGALRM", "alarm clock"}, + {15, "SIGTERM", "terminated"}, + {16, "SIGURG", "urgent I/O condition"}, + {17, "SIGSTOP", "stopped (signal)"}, + {18, "SIGTSTP", "stopped"}, + {19, "SIGCONT", "continued"}, + {20, "SIGCHLD", "child exited"}, + {21, "SIGTTIN", "stopped (tty input)"}, + {22, "SIGTTOU", "stopped (tty output)"}, + {23, "SIGIO", "I/O possible"}, + {24, "SIGXCPU", "CPU time limit exceeded"}, + {25, "SIGXFSZ", "file size limit exceeded"}, + {26, "SIGVTALRM", "virtual timer expired"}, + {27, "SIGPROF", "profiling timer expired"}, + {28, "SIGWINCH", "window changed"}, + {29, "SIGLOST", "power failure"}, + {30, "SIGUSR1", "user defined signal 1"}, + {31, "SIGUSR2", "user defined signal 2"}, } diff --git a/vendor/golang.org/x/sys/unix/zerrors_netbsd_386.go b/vendor/golang.org/x/sys/unix/zerrors_netbsd_386.go index b4338d5f26..78cc04ea6d 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_netbsd_386.go +++ b/vendor/golang.org/x/sys/unix/zerrors_netbsd_386.go @@ -1,5 +1,5 @@ // mkerrors.sh -m32 -// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// Code generated by the command above; see README.md. DO NOT EDIT. // +build 386,netbsd @@ -159,6 +159,7 @@ const ( CLONE_VFORK = 0x4000 CLONE_VM = 0x100 CREAD = 0x800 + CRTSCTS = 0x10000 CS5 = 0x0 CS6 = 0x100 CS7 = 0x200 @@ -169,6 +170,8 @@ const ( CSTOP = 0x13 CSTOPB = 0x400 CSUSP = 0x1a + CTL_HW = 0x6 + CTL_KERN = 0x1 CTL_MAXNAME = 0xc CTL_NET = 0x4 CTL_QUERY = -0x2 @@ -547,6 +550,10 @@ const ( EV_ONESHOT = 0x10 EV_SYSFLAGS = 0xf000 EXTA = 0x4b00 + EXTATTR_CMD_START = 0x1 + EXTATTR_CMD_STOP = 0x2 + EXTATTR_NAMESPACE_SYSTEM = 0x2 + EXTATTR_NAMESPACE_USER = 0x1 EXTB = 0x9600 EXTPROC = 0x800 FD_CLOEXEC = 0x1 @@ -581,6 +588,7 @@ const ( F_UNLCK = 0x2 F_WRLCK = 0x3 HUPCL = 0x4000 + HW_MACHINE = 0x1 ICANON = 0x100 ICMP6_FILTER = 0x12 ICRNL = 0x100 @@ -970,6 +978,10 @@ const ( IXANY = 0x800 IXOFF = 0x400 IXON = 0x200 + KERN_HOSTNAME = 0xa + KERN_OSRELEASE = 0x2 + KERN_OSTYPE = 0x1 + KERN_VERSION = 0x4 LOCK_EX = 0x2 LOCK_NB = 0x4 LOCK_SH = 0x1 @@ -1008,6 +1020,43 @@ const ( MAP_WIRED = 0x800 MCL_CURRENT = 0x1 MCL_FUTURE = 0x2 + MNT_ASYNC = 0x40 + MNT_BASIC_FLAGS = 0xe782807f + MNT_DEFEXPORTED = 0x200 + MNT_DISCARD = 0x800000 + MNT_EXKERB = 0x800 + MNT_EXNORESPORT = 0x8000000 + MNT_EXPORTANON = 0x400 + MNT_EXPORTED = 0x100 + MNT_EXPUBLIC = 0x10000000 + MNT_EXRDONLY = 0x80 + MNT_EXTATTR = 0x1000000 + MNT_FORCE = 0x80000 + MNT_GETARGS = 0x400000 + MNT_IGNORE = 0x100000 + MNT_LAZY = 0x3 + MNT_LOCAL = 0x1000 + MNT_LOG = 0x2000000 + MNT_NOATIME = 0x4000000 + MNT_NOCOREDUMP = 0x8000 + MNT_NODEV = 0x10 + MNT_NODEVMTIME = 0x40000000 + MNT_NOEXEC = 0x4 + MNT_NOSUID = 0x8 + MNT_NOWAIT = 0x2 + MNT_OP_FLAGS = 0x4d0000 + MNT_QUOTA = 0x2000 + MNT_RDONLY = 0x1 + MNT_RELATIME = 0x20000 + MNT_RELOAD = 0x40000 + MNT_ROOTFS = 0x4000 + MNT_SOFTDEP = 0x80000000 + MNT_SYMPERM = 0x20000000 + MNT_SYNCHRONOUS = 0x2 + MNT_UNION = 0x20 + MNT_UPDATE = 0x10000 + MNT_VISFLAGMASK = 0xff90ffff + MNT_WAIT = 0x1 MSG_BCAST = 0x100 MSG_CMSG_CLOEXEC = 0x800 MSG_CONTROLMBUF = 0x2000000 @@ -1101,7 +1150,10 @@ const ( RLIMIT_CPU = 0x0 RLIMIT_DATA = 0x2 RLIMIT_FSIZE = 0x1 + RLIMIT_MEMLOCK = 0x6 RLIMIT_NOFILE = 0x8 + RLIMIT_NPROC = 0x7 + RLIMIT_RSS = 0x5 RLIMIT_STACK = 0x3 RLIM_INFINITY = 0x7fffffffffffffff RTAX_AUTHOR = 0x6 @@ -1576,137 +1628,145 @@ const ( ) // Error table -var errors = [...]string{ - 1: "operation not permitted", - 2: "no such file or directory", - 3: "no such process", - 4: "interrupted system call", - 5: "input/output error", - 6: "device not configured", - 7: "argument list too long", - 8: "exec format error", - 9: "bad file descriptor", - 10: "no child processes", - 11: "resource deadlock avoided", - 12: "cannot allocate memory", - 13: "permission denied", - 14: "bad address", - 15: "block device required", - 16: "device busy", - 17: "file exists", - 18: "cross-device link", - 19: "operation not supported by device", - 20: "not a directory", - 21: "is a directory", - 22: "invalid argument", - 23: "too many open files in system", - 24: "too many open files", - 25: "inappropriate ioctl for device", - 26: "text file busy", - 27: "file too large", - 28: "no space left on device", - 29: "illegal seek", - 30: "read-only file system", - 31: "too many links", - 32: "broken pipe", - 33: "numerical argument out of domain", - 34: "result too large or too small", - 35: "resource temporarily unavailable", - 36: "operation now in progress", - 37: "operation already in progress", - 38: "socket operation on non-socket", - 39: "destination address required", - 40: "message too long", - 41: "protocol wrong type for socket", - 42: "protocol option not available", - 43: "protocol not supported", - 44: "socket type not supported", - 45: "operation not supported", - 46: "protocol family not supported", - 47: "address family not supported by protocol family", - 48: "address already in use", - 49: "can't assign requested address", - 50: "network is down", - 51: "network is unreachable", - 52: "network dropped connection on reset", - 53: "software caused connection abort", - 54: "connection reset by peer", - 55: "no buffer space available", - 56: "socket is already connected", - 57: "socket is not connected", - 58: "can't send after socket shutdown", - 59: "too many references: can't splice", - 60: "connection timed out", - 61: "connection refused", - 62: "too many levels of symbolic links", - 63: "file name too long", - 64: "host is down", - 65: "no route to host", - 66: "directory not empty", - 67: "too many processes", - 68: "too many users", - 69: "disc quota exceeded", - 70: "stale NFS file handle", - 71: "too many levels of remote in path", - 72: "RPC struct is bad", - 73: "RPC version wrong", - 74: "RPC prog. not avail", - 75: "program version wrong", - 76: "bad procedure for program", - 77: "no locks available", - 78: "function not implemented", - 79: "inappropriate file type or format", - 80: "authentication error", - 81: "need authenticator", - 82: "identifier removed", - 83: "no message of desired type", - 84: "value too large to be stored in data type", - 85: "illegal byte sequence", - 86: "not supported", - 87: "operation Canceled", - 88: "bad or Corrupt message", - 89: "no message available", - 90: "no STREAM resources", - 91: "not a STREAM", - 92: "STREAM ioctl timeout", - 93: "attribute not found", - 94: "multihop attempted", - 95: "link has been severed", - 96: "protocol error", +var errorList = [...]struct { + num syscall.Errno + name string + desc string +}{ + {1, "EPERM", "operation not permitted"}, + {2, "ENOENT", "no such file or directory"}, + {3, "ESRCH", "no such process"}, + {4, "EINTR", "interrupted system call"}, + {5, "EIO", "input/output error"}, + {6, "ENXIO", "device not configured"}, + {7, "E2BIG", "argument list too long"}, + {8, "ENOEXEC", "exec format error"}, + {9, "EBADF", "bad file descriptor"}, + {10, "ECHILD", "no child processes"}, + {11, "EDEADLK", "resource deadlock avoided"}, + {12, "ENOMEM", "cannot allocate memory"}, + {13, "EACCES", "permission denied"}, + {14, "EFAULT", "bad address"}, + {15, "ENOTBLK", "block device required"}, + {16, "EBUSY", "device busy"}, + {17, "EEXIST", "file exists"}, + {18, "EXDEV", "cross-device link"}, + {19, "ENODEV", "operation not supported by device"}, + {20, "ENOTDIR", "not a directory"}, + {21, "EISDIR", "is a directory"}, + {22, "EINVAL", "invalid argument"}, + {23, "ENFILE", "too many open files in system"}, + {24, "EMFILE", "too many open files"}, + {25, "ENOTTY", "inappropriate ioctl for device"}, + {26, "ETXTBSY", "text file busy"}, + {27, "EFBIG", "file too large"}, + {28, "ENOSPC", "no space left on device"}, + {29, "ESPIPE", "illegal seek"}, + {30, "EROFS", "read-only file system"}, + {31, "EMLINK", "too many links"}, + {32, "EPIPE", "broken pipe"}, + {33, "EDOM", "numerical argument out of domain"}, + {34, "ERANGE", "result too large or too small"}, + {35, "EAGAIN", "resource temporarily unavailable"}, + {36, "EINPROGRESS", "operation now in progress"}, + {37, "EALREADY", "operation already in progress"}, + {38, "ENOTSOCK", "socket operation on non-socket"}, + {39, "EDESTADDRREQ", "destination address required"}, + {40, "EMSGSIZE", "message too long"}, + {41, "EPROTOTYPE", "protocol wrong type for socket"}, + {42, "ENOPROTOOPT", "protocol option not available"}, + {43, "EPROTONOSUPPORT", "protocol not supported"}, + {44, "ESOCKTNOSUPPORT", "socket type not supported"}, + {45, "EOPNOTSUPP", "operation not supported"}, + {46, "EPFNOSUPPORT", "protocol family not supported"}, + {47, "EAFNOSUPPORT", "address family not supported by protocol family"}, + {48, "EADDRINUSE", "address already in use"}, + {49, "EADDRNOTAVAIL", "can't assign requested address"}, + {50, "ENETDOWN", "network is down"}, + {51, "ENETUNREACH", "network is unreachable"}, + {52, "ENETRESET", "network dropped connection on reset"}, + {53, "ECONNABORTED", "software caused connection abort"}, + {54, "ECONNRESET", "connection reset by peer"}, + {55, "ENOBUFS", "no buffer space available"}, + {56, "EISCONN", "socket is already connected"}, + {57, "ENOTCONN", "socket is not connected"}, + {58, "ESHUTDOWN", "can't send after socket shutdown"}, + {59, "ETOOMANYREFS", "too many references: can't splice"}, + {60, "ETIMEDOUT", "connection timed out"}, + {61, "ECONNREFUSED", "connection refused"}, + {62, "ELOOP", "too many levels of symbolic links"}, + {63, "ENAMETOOLONG", "file name too long"}, + {64, "EHOSTDOWN", "host is down"}, + {65, "EHOSTUNREACH", "no route to host"}, + {66, "ENOTEMPTY", "directory not empty"}, + {67, "EPROCLIM", "too many processes"}, + {68, "EUSERS", "too many users"}, + {69, "EDQUOT", "disc quota exceeded"}, + {70, "ESTALE", "stale NFS file handle"}, + {71, "EREMOTE", "too many levels of remote in path"}, + {72, "EBADRPC", "RPC struct is bad"}, + {73, "ERPCMISMATCH", "RPC version wrong"}, + {74, "EPROGUNAVAIL", "RPC prog. not avail"}, + {75, "EPROGMISMATCH", "program version wrong"}, + {76, "EPROCUNAVAIL", "bad procedure for program"}, + {77, "ENOLCK", "no locks available"}, + {78, "ENOSYS", "function not implemented"}, + {79, "EFTYPE", "inappropriate file type or format"}, + {80, "EAUTH", "authentication error"}, + {81, "ENEEDAUTH", "need authenticator"}, + {82, "EIDRM", "identifier removed"}, + {83, "ENOMSG", "no message of desired type"}, + {84, "EOVERFLOW", "value too large to be stored in data type"}, + {85, "EILSEQ", "illegal byte sequence"}, + {86, "ENOTSUP", "not supported"}, + {87, "ECANCELED", "operation Canceled"}, + {88, "EBADMSG", "bad or Corrupt message"}, + {89, "ENODATA", "no message available"}, + {90, "ENOSR", "no STREAM resources"}, + {91, "ENOSTR", "not a STREAM"}, + {92, "ETIME", "STREAM ioctl timeout"}, + {93, "ENOATTR", "attribute not found"}, + {94, "EMULTIHOP", "multihop attempted"}, + {95, "ENOLINK", "link has been severed"}, + {96, "ELAST", "protocol error"}, } // Signal table -var signals = [...]string{ - 1: "hangup", - 2: "interrupt", - 3: "quit", - 4: "illegal instruction", - 5: "trace/BPT trap", - 6: "abort trap", - 7: "EMT trap", - 8: "floating point exception", - 9: "killed", - 10: "bus error", - 11: "segmentation fault", - 12: "bad system call", - 13: "broken pipe", - 14: "alarm clock", - 15: "terminated", - 16: "urgent I/O condition", - 17: "stopped (signal)", - 18: "stopped", - 19: "continued", - 20: "child exited", - 21: "stopped (tty input)", - 22: "stopped (tty output)", - 23: "I/O possible", - 24: "cputime limit exceeded", - 25: "filesize limit exceeded", - 26: "virtual timer expired", - 27: "profiling timer expired", - 28: "window size changes", - 29: "information request", - 30: "user defined signal 1", - 31: "user defined signal 2", - 32: "power fail/restart", +var signalList = [...]struct { + num syscall.Signal + name string + desc string +}{ + {1, "SIGHUP", "hangup"}, + {2, "SIGINT", "interrupt"}, + {3, "SIGQUIT", "quit"}, + {4, "SIGILL", "illegal instruction"}, + {5, "SIGTRAP", "trace/BPT trap"}, + {6, "SIGIOT", "abort trap"}, + {7, "SIGEMT", "EMT trap"}, + {8, "SIGFPE", "floating point exception"}, + {9, "SIGKILL", "killed"}, + {10, "SIGBUS", "bus error"}, + {11, "SIGSEGV", "segmentation fault"}, + {12, "SIGSYS", "bad system call"}, + {13, "SIGPIPE", "broken pipe"}, + {14, "SIGALRM", "alarm clock"}, + {15, "SIGTERM", "terminated"}, + {16, "SIGURG", "urgent I/O condition"}, + {17, "SIGSTOP", "stopped (signal)"}, + {18, "SIGTSTP", "stopped"}, + {19, "SIGCONT", "continued"}, + {20, "SIGCHLD", "child exited"}, + {21, "SIGTTIN", "stopped (tty input)"}, + {22, "SIGTTOU", "stopped (tty output)"}, + {23, "SIGIO", "I/O possible"}, + {24, "SIGXCPU", "cputime limit exceeded"}, + {25, "SIGXFSZ", "filesize limit exceeded"}, + {26, "SIGVTALRM", "virtual timer expired"}, + {27, "SIGPROF", "profiling timer expired"}, + {28, "SIGWINCH", "window size changes"}, + {29, "SIGINFO", "information request"}, + {30, "SIGUSR1", "user defined signal 1"}, + {31, "SIGUSR2", "user defined signal 2"}, + {32, "SIGPWR", "power fail/restart"}, } diff --git a/vendor/golang.org/x/sys/unix/zerrors_netbsd_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_netbsd_amd64.go index 4994437b63..92185e693f 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_netbsd_amd64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_netbsd_amd64.go @@ -1,5 +1,5 @@ // mkerrors.sh -m64 -// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// Code generated by the command above; see README.md. DO NOT EDIT. // +build amd64,netbsd @@ -159,6 +159,7 @@ const ( CLONE_VFORK = 0x4000 CLONE_VM = 0x100 CREAD = 0x800 + CRTSCTS = 0x10000 CS5 = 0x0 CS6 = 0x100 CS7 = 0x200 @@ -169,6 +170,8 @@ const ( CSTOP = 0x13 CSTOPB = 0x400 CSUSP = 0x1a + CTL_HW = 0x6 + CTL_KERN = 0x1 CTL_MAXNAME = 0xc CTL_NET = 0x4 CTL_QUERY = -0x2 @@ -537,6 +540,10 @@ const ( EV_ONESHOT = 0x10 EV_SYSFLAGS = 0xf000 EXTA = 0x4b00 + EXTATTR_CMD_START = 0x1 + EXTATTR_CMD_STOP = 0x2 + EXTATTR_NAMESPACE_SYSTEM = 0x2 + EXTATTR_NAMESPACE_USER = 0x1 EXTB = 0x9600 EXTPROC = 0x800 FD_CLOEXEC = 0x1 @@ -571,6 +578,7 @@ const ( F_UNLCK = 0x2 F_WRLCK = 0x3 HUPCL = 0x4000 + HW_MACHINE = 0x1 ICANON = 0x100 ICMP6_FILTER = 0x12 ICRNL = 0x100 @@ -960,6 +968,10 @@ const ( IXANY = 0x800 IXOFF = 0x400 IXON = 0x200 + KERN_HOSTNAME = 0xa + KERN_OSRELEASE = 0x2 + KERN_OSTYPE = 0x1 + KERN_VERSION = 0x4 LOCK_EX = 0x2 LOCK_NB = 0x4 LOCK_SH = 0x1 @@ -998,6 +1010,43 @@ const ( MAP_WIRED = 0x800 MCL_CURRENT = 0x1 MCL_FUTURE = 0x2 + MNT_ASYNC = 0x40 + MNT_BASIC_FLAGS = 0xe782807f + MNT_DEFEXPORTED = 0x200 + MNT_DISCARD = 0x800000 + MNT_EXKERB = 0x800 + MNT_EXNORESPORT = 0x8000000 + MNT_EXPORTANON = 0x400 + MNT_EXPORTED = 0x100 + MNT_EXPUBLIC = 0x10000000 + MNT_EXRDONLY = 0x80 + MNT_EXTATTR = 0x1000000 + MNT_FORCE = 0x80000 + MNT_GETARGS = 0x400000 + MNT_IGNORE = 0x100000 + MNT_LAZY = 0x3 + MNT_LOCAL = 0x1000 + MNT_LOG = 0x2000000 + MNT_NOATIME = 0x4000000 + MNT_NOCOREDUMP = 0x8000 + MNT_NODEV = 0x10 + MNT_NODEVMTIME = 0x40000000 + MNT_NOEXEC = 0x4 + MNT_NOSUID = 0x8 + MNT_NOWAIT = 0x2 + MNT_OP_FLAGS = 0x4d0000 + MNT_QUOTA = 0x2000 + MNT_RDONLY = 0x1 + MNT_RELATIME = 0x20000 + MNT_RELOAD = 0x40000 + MNT_ROOTFS = 0x4000 + MNT_SOFTDEP = 0x80000000 + MNT_SYMPERM = 0x20000000 + MNT_SYNCHRONOUS = 0x2 + MNT_UNION = 0x20 + MNT_UPDATE = 0x10000 + MNT_VISFLAGMASK = 0xff90ffff + MNT_WAIT = 0x1 MSG_BCAST = 0x100 MSG_CMSG_CLOEXEC = 0x800 MSG_CONTROLMBUF = 0x2000000 @@ -1091,7 +1140,10 @@ const ( RLIMIT_CPU = 0x0 RLIMIT_DATA = 0x2 RLIMIT_FSIZE = 0x1 + RLIMIT_MEMLOCK = 0x6 RLIMIT_NOFILE = 0x8 + RLIMIT_NPROC = 0x7 + RLIMIT_RSS = 0x5 RLIMIT_STACK = 0x3 RLIM_INFINITY = 0x7fffffffffffffff RTAX_AUTHOR = 0x6 @@ -1566,137 +1618,145 @@ const ( ) // Error table -var errors = [...]string{ - 1: "operation not permitted", - 2: "no such file or directory", - 3: "no such process", - 4: "interrupted system call", - 5: "input/output error", - 6: "device not configured", - 7: "argument list too long", - 8: "exec format error", - 9: "bad file descriptor", - 10: "no child processes", - 11: "resource deadlock avoided", - 12: "cannot allocate memory", - 13: "permission denied", - 14: "bad address", - 15: "block device required", - 16: "device busy", - 17: "file exists", - 18: "cross-device link", - 19: "operation not supported by device", - 20: "not a directory", - 21: "is a directory", - 22: "invalid argument", - 23: "too many open files in system", - 24: "too many open files", - 25: "inappropriate ioctl for device", - 26: "text file busy", - 27: "file too large", - 28: "no space left on device", - 29: "illegal seek", - 30: "read-only file system", - 31: "too many links", - 32: "broken pipe", - 33: "numerical argument out of domain", - 34: "result too large or too small", - 35: "resource temporarily unavailable", - 36: "operation now in progress", - 37: "operation already in progress", - 38: "socket operation on non-socket", - 39: "destination address required", - 40: "message too long", - 41: "protocol wrong type for socket", - 42: "protocol option not available", - 43: "protocol not supported", - 44: "socket type not supported", - 45: "operation not supported", - 46: "protocol family not supported", - 47: "address family not supported by protocol family", - 48: "address already in use", - 49: "can't assign requested address", - 50: "network is down", - 51: "network is unreachable", - 52: "network dropped connection on reset", - 53: "software caused connection abort", - 54: "connection reset by peer", - 55: "no buffer space available", - 56: "socket is already connected", - 57: "socket is not connected", - 58: "can't send after socket shutdown", - 59: "too many references: can't splice", - 60: "connection timed out", - 61: "connection refused", - 62: "too many levels of symbolic links", - 63: "file name too long", - 64: "host is down", - 65: "no route to host", - 66: "directory not empty", - 67: "too many processes", - 68: "too many users", - 69: "disc quota exceeded", - 70: "stale NFS file handle", - 71: "too many levels of remote in path", - 72: "RPC struct is bad", - 73: "RPC version wrong", - 74: "RPC prog. not avail", - 75: "program version wrong", - 76: "bad procedure for program", - 77: "no locks available", - 78: "function not implemented", - 79: "inappropriate file type or format", - 80: "authentication error", - 81: "need authenticator", - 82: "identifier removed", - 83: "no message of desired type", - 84: "value too large to be stored in data type", - 85: "illegal byte sequence", - 86: "not supported", - 87: "operation Canceled", - 88: "bad or Corrupt message", - 89: "no message available", - 90: "no STREAM resources", - 91: "not a STREAM", - 92: "STREAM ioctl timeout", - 93: "attribute not found", - 94: "multihop attempted", - 95: "link has been severed", - 96: "protocol error", +var errorList = [...]struct { + num syscall.Errno + name string + desc string +}{ + {1, "EPERM", "operation not permitted"}, + {2, "ENOENT", "no such file or directory"}, + {3, "ESRCH", "no such process"}, + {4, "EINTR", "interrupted system call"}, + {5, "EIO", "input/output error"}, + {6, "ENXIO", "device not configured"}, + {7, "E2BIG", "argument list too long"}, + {8, "ENOEXEC", "exec format error"}, + {9, "EBADF", "bad file descriptor"}, + {10, "ECHILD", "no child processes"}, + {11, "EDEADLK", "resource deadlock avoided"}, + {12, "ENOMEM", "cannot allocate memory"}, + {13, "EACCES", "permission denied"}, + {14, "EFAULT", "bad address"}, + {15, "ENOTBLK", "block device required"}, + {16, "EBUSY", "device busy"}, + {17, "EEXIST", "file exists"}, + {18, "EXDEV", "cross-device link"}, + {19, "ENODEV", "operation not supported by device"}, + {20, "ENOTDIR", "not a directory"}, + {21, "EISDIR", "is a directory"}, + {22, "EINVAL", "invalid argument"}, + {23, "ENFILE", "too many open files in system"}, + {24, "EMFILE", "too many open files"}, + {25, "ENOTTY", "inappropriate ioctl for device"}, + {26, "ETXTBSY", "text file busy"}, + {27, "EFBIG", "file too large"}, + {28, "ENOSPC", "no space left on device"}, + {29, "ESPIPE", "illegal seek"}, + {30, "EROFS", "read-only file system"}, + {31, "EMLINK", "too many links"}, + {32, "EPIPE", "broken pipe"}, + {33, "EDOM", "numerical argument out of domain"}, + {34, "ERANGE", "result too large or too small"}, + {35, "EAGAIN", "resource temporarily unavailable"}, + {36, "EINPROGRESS", "operation now in progress"}, + {37, "EALREADY", "operation already in progress"}, + {38, "ENOTSOCK", "socket operation on non-socket"}, + {39, "EDESTADDRREQ", "destination address required"}, + {40, "EMSGSIZE", "message too long"}, + {41, "EPROTOTYPE", "protocol wrong type for socket"}, + {42, "ENOPROTOOPT", "protocol option not available"}, + {43, "EPROTONOSUPPORT", "protocol not supported"}, + {44, "ESOCKTNOSUPPORT", "socket type not supported"}, + {45, "EOPNOTSUPP", "operation not supported"}, + {46, "EPFNOSUPPORT", "protocol family not supported"}, + {47, "EAFNOSUPPORT", "address family not supported by protocol family"}, + {48, "EADDRINUSE", "address already in use"}, + {49, "EADDRNOTAVAIL", "can't assign requested address"}, + {50, "ENETDOWN", "network is down"}, + {51, "ENETUNREACH", "network is unreachable"}, + {52, "ENETRESET", "network dropped connection on reset"}, + {53, "ECONNABORTED", "software caused connection abort"}, + {54, "ECONNRESET", "connection reset by peer"}, + {55, "ENOBUFS", "no buffer space available"}, + {56, "EISCONN", "socket is already connected"}, + {57, "ENOTCONN", "socket is not connected"}, + {58, "ESHUTDOWN", "can't send after socket shutdown"}, + {59, "ETOOMANYREFS", "too many references: can't splice"}, + {60, "ETIMEDOUT", "connection timed out"}, + {61, "ECONNREFUSED", "connection refused"}, + {62, "ELOOP", "too many levels of symbolic links"}, + {63, "ENAMETOOLONG", "file name too long"}, + {64, "EHOSTDOWN", "host is down"}, + {65, "EHOSTUNREACH", "no route to host"}, + {66, "ENOTEMPTY", "directory not empty"}, + {67, "EPROCLIM", "too many processes"}, + {68, "EUSERS", "too many users"}, + {69, "EDQUOT", "disc quota exceeded"}, + {70, "ESTALE", "stale NFS file handle"}, + {71, "EREMOTE", "too many levels of remote in path"}, + {72, "EBADRPC", "RPC struct is bad"}, + {73, "ERPCMISMATCH", "RPC version wrong"}, + {74, "EPROGUNAVAIL", "RPC prog. not avail"}, + {75, "EPROGMISMATCH", "program version wrong"}, + {76, "EPROCUNAVAIL", "bad procedure for program"}, + {77, "ENOLCK", "no locks available"}, + {78, "ENOSYS", "function not implemented"}, + {79, "EFTYPE", "inappropriate file type or format"}, + {80, "EAUTH", "authentication error"}, + {81, "ENEEDAUTH", "need authenticator"}, + {82, "EIDRM", "identifier removed"}, + {83, "ENOMSG", "no message of desired type"}, + {84, "EOVERFLOW", "value too large to be stored in data type"}, + {85, "EILSEQ", "illegal byte sequence"}, + {86, "ENOTSUP", "not supported"}, + {87, "ECANCELED", "operation Canceled"}, + {88, "EBADMSG", "bad or Corrupt message"}, + {89, "ENODATA", "no message available"}, + {90, "ENOSR", "no STREAM resources"}, + {91, "ENOSTR", "not a STREAM"}, + {92, "ETIME", "STREAM ioctl timeout"}, + {93, "ENOATTR", "attribute not found"}, + {94, "EMULTIHOP", "multihop attempted"}, + {95, "ENOLINK", "link has been severed"}, + {96, "ELAST", "protocol error"}, } // Signal table -var signals = [...]string{ - 1: "hangup", - 2: "interrupt", - 3: "quit", - 4: "illegal instruction", - 5: "trace/BPT trap", - 6: "abort trap", - 7: "EMT trap", - 8: "floating point exception", - 9: "killed", - 10: "bus error", - 11: "segmentation fault", - 12: "bad system call", - 13: "broken pipe", - 14: "alarm clock", - 15: "terminated", - 16: "urgent I/O condition", - 17: "stopped (signal)", - 18: "stopped", - 19: "continued", - 20: "child exited", - 21: "stopped (tty input)", - 22: "stopped (tty output)", - 23: "I/O possible", - 24: "cputime limit exceeded", - 25: "filesize limit exceeded", - 26: "virtual timer expired", - 27: "profiling timer expired", - 28: "window size changes", - 29: "information request", - 30: "user defined signal 1", - 31: "user defined signal 2", - 32: "power fail/restart", +var signalList = [...]struct { + num syscall.Signal + name string + desc string +}{ + {1, "SIGHUP", "hangup"}, + {2, "SIGINT", "interrupt"}, + {3, "SIGQUIT", "quit"}, + {4, "SIGILL", "illegal instruction"}, + {5, "SIGTRAP", "trace/BPT trap"}, + {6, "SIGIOT", "abort trap"}, + {7, "SIGEMT", "EMT trap"}, + {8, "SIGFPE", "floating point exception"}, + {9, "SIGKILL", "killed"}, + {10, "SIGBUS", "bus error"}, + {11, "SIGSEGV", "segmentation fault"}, + {12, "SIGSYS", "bad system call"}, + {13, "SIGPIPE", "broken pipe"}, + {14, "SIGALRM", "alarm clock"}, + {15, "SIGTERM", "terminated"}, + {16, "SIGURG", "urgent I/O condition"}, + {17, "SIGSTOP", "stopped (signal)"}, + {18, "SIGTSTP", "stopped"}, + {19, "SIGCONT", "continued"}, + {20, "SIGCHLD", "child exited"}, + {21, "SIGTTIN", "stopped (tty input)"}, + {22, "SIGTTOU", "stopped (tty output)"}, + {23, "SIGIO", "I/O possible"}, + {24, "SIGXCPU", "cputime limit exceeded"}, + {25, "SIGXFSZ", "filesize limit exceeded"}, + {26, "SIGVTALRM", "virtual timer expired"}, + {27, "SIGPROF", "profiling timer expired"}, + {28, "SIGWINCH", "window size changes"}, + {29, "SIGINFO", "information request"}, + {30, "SIGUSR1", "user defined signal 1"}, + {31, "SIGUSR2", "user defined signal 2"}, + {32, "SIGPWR", "power fail/restart"}, } diff --git a/vendor/golang.org/x/sys/unix/zerrors_netbsd_arm.go b/vendor/golang.org/x/sys/unix/zerrors_netbsd_arm.go index 206c75f094..373ad4543d 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_netbsd_arm.go +++ b/vendor/golang.org/x/sys/unix/zerrors_netbsd_arm.go @@ -1,5 +1,5 @@ // mkerrors.sh -marm -// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// Code generated by the command above; see README.md. DO NOT EDIT. // +build arm,netbsd @@ -151,6 +151,7 @@ const ( CFLUSH = 0xf CLOCAL = 0x8000 CREAD = 0x800 + CRTSCTS = 0x10000 CS5 = 0x0 CS6 = 0x100 CS7 = 0x200 @@ -161,6 +162,8 @@ const ( CSTOP = 0x13 CSTOPB = 0x400 CSUSP = 0x1a + CTL_HW = 0x6 + CTL_KERN = 0x1 CTL_MAXNAME = 0xc CTL_NET = 0x4 CTL_QUERY = -0x2 @@ -529,6 +532,10 @@ const ( EV_ONESHOT = 0x10 EV_SYSFLAGS = 0xf000 EXTA = 0x4b00 + EXTATTR_CMD_START = 0x1 + EXTATTR_CMD_STOP = 0x2 + EXTATTR_NAMESPACE_SYSTEM = 0x2 + EXTATTR_NAMESPACE_USER = 0x1 EXTB = 0x9600 EXTPROC = 0x800 FD_CLOEXEC = 0x1 @@ -563,6 +570,7 @@ const ( F_UNLCK = 0x2 F_WRLCK = 0x3 HUPCL = 0x4000 + HW_MACHINE = 0x1 ICANON = 0x100 ICMP6_FILTER = 0x12 ICRNL = 0x100 @@ -952,6 +960,10 @@ const ( IXANY = 0x800 IXOFF = 0x400 IXON = 0x200 + KERN_HOSTNAME = 0xa + KERN_OSRELEASE = 0x2 + KERN_OSTYPE = 0x1 + KERN_VERSION = 0x4 LOCK_EX = 0x2 LOCK_NB = 0x4 LOCK_SH = 0x1 @@ -988,6 +1000,43 @@ const ( MAP_STACK = 0x2000 MAP_TRYFIXED = 0x400 MAP_WIRED = 0x800 + MNT_ASYNC = 0x40 + MNT_BASIC_FLAGS = 0xe782807f + MNT_DEFEXPORTED = 0x200 + MNT_DISCARD = 0x800000 + MNT_EXKERB = 0x800 + MNT_EXNORESPORT = 0x8000000 + MNT_EXPORTANON = 0x400 + MNT_EXPORTED = 0x100 + MNT_EXPUBLIC = 0x10000000 + MNT_EXRDONLY = 0x80 + MNT_EXTATTR = 0x1000000 + MNT_FORCE = 0x80000 + MNT_GETARGS = 0x400000 + MNT_IGNORE = 0x100000 + MNT_LAZY = 0x3 + MNT_LOCAL = 0x1000 + MNT_LOG = 0x2000000 + MNT_NOATIME = 0x4000000 + MNT_NOCOREDUMP = 0x8000 + MNT_NODEV = 0x10 + MNT_NODEVMTIME = 0x40000000 + MNT_NOEXEC = 0x4 + MNT_NOSUID = 0x8 + MNT_NOWAIT = 0x2 + MNT_OP_FLAGS = 0x4d0000 + MNT_QUOTA = 0x2000 + MNT_RDONLY = 0x1 + MNT_RELATIME = 0x20000 + MNT_RELOAD = 0x40000 + MNT_ROOTFS = 0x4000 + MNT_SOFTDEP = 0x80000000 + MNT_SYMPERM = 0x20000000 + MNT_SYNCHRONOUS = 0x2 + MNT_UNION = 0x20 + MNT_UPDATE = 0x10000 + MNT_VISFLAGMASK = 0xff90ffff + MNT_WAIT = 0x1 MSG_BCAST = 0x100 MSG_CMSG_CLOEXEC = 0x800 MSG_CONTROLMBUF = 0x2000000 @@ -1081,7 +1130,10 @@ const ( RLIMIT_CPU = 0x0 RLIMIT_DATA = 0x2 RLIMIT_FSIZE = 0x1 + RLIMIT_MEMLOCK = 0x6 RLIMIT_NOFILE = 0x8 + RLIMIT_NPROC = 0x7 + RLIMIT_RSS = 0x5 RLIMIT_STACK = 0x3 RLIM_INFINITY = 0x7fffffffffffffff RTAX_AUTHOR = 0x6 @@ -1555,137 +1607,145 @@ const ( ) // Error table -var errors = [...]string{ - 1: "operation not permitted", - 2: "no such file or directory", - 3: "no such process", - 4: "interrupted system call", - 5: "input/output error", - 6: "device not configured", - 7: "argument list too long", - 8: "exec format error", - 9: "bad file descriptor", - 10: "no child processes", - 11: "resource deadlock avoided", - 12: "cannot allocate memory", - 13: "permission denied", - 14: "bad address", - 15: "block device required", - 16: "device busy", - 17: "file exists", - 18: "cross-device link", - 19: "operation not supported by device", - 20: "not a directory", - 21: "is a directory", - 22: "invalid argument", - 23: "too many open files in system", - 24: "too many open files", - 25: "inappropriate ioctl for device", - 26: "text file busy", - 27: "file too large", - 28: "no space left on device", - 29: "illegal seek", - 30: "read-only file system", - 31: "too many links", - 32: "broken pipe", - 33: "numerical argument out of domain", - 34: "result too large or too small", - 35: "resource temporarily unavailable", - 36: "operation now in progress", - 37: "operation already in progress", - 38: "socket operation on non-socket", - 39: "destination address required", - 40: "message too long", - 41: "protocol wrong type for socket", - 42: "protocol option not available", - 43: "protocol not supported", - 44: "socket type not supported", - 45: "operation not supported", - 46: "protocol family not supported", - 47: "address family not supported by protocol family", - 48: "address already in use", - 49: "can't assign requested address", - 50: "network is down", - 51: "network is unreachable", - 52: "network dropped connection on reset", - 53: "software caused connection abort", - 54: "connection reset by peer", - 55: "no buffer space available", - 56: "socket is already connected", - 57: "socket is not connected", - 58: "can't send after socket shutdown", - 59: "too many references: can't splice", - 60: "connection timed out", - 61: "connection refused", - 62: "too many levels of symbolic links", - 63: "file name too long", - 64: "host is down", - 65: "no route to host", - 66: "directory not empty", - 67: "too many processes", - 68: "too many users", - 69: "disc quota exceeded", - 70: "stale NFS file handle", - 71: "too many levels of remote in path", - 72: "RPC struct is bad", - 73: "RPC version wrong", - 74: "RPC prog. not avail", - 75: "program version wrong", - 76: "bad procedure for program", - 77: "no locks available", - 78: "function not implemented", - 79: "inappropriate file type or format", - 80: "authentication error", - 81: "need authenticator", - 82: "identifier removed", - 83: "no message of desired type", - 84: "value too large to be stored in data type", - 85: "illegal byte sequence", - 86: "not supported", - 87: "operation Canceled", - 88: "bad or Corrupt message", - 89: "no message available", - 90: "no STREAM resources", - 91: "not a STREAM", - 92: "STREAM ioctl timeout", - 93: "attribute not found", - 94: "multihop attempted", - 95: "link has been severed", - 96: "protocol error", +var errorList = [...]struct { + num syscall.Errno + name string + desc string +}{ + {1, "EPERM", "operation not permitted"}, + {2, "ENOENT", "no such file or directory"}, + {3, "ESRCH", "no such process"}, + {4, "EINTR", "interrupted system call"}, + {5, "EIO", "input/output error"}, + {6, "ENXIO", "device not configured"}, + {7, "E2BIG", "argument list too long"}, + {8, "ENOEXEC", "exec format error"}, + {9, "EBADF", "bad file descriptor"}, + {10, "ECHILD", "no child processes"}, + {11, "EDEADLK", "resource deadlock avoided"}, + {12, "ENOMEM", "cannot allocate memory"}, + {13, "EACCES", "permission denied"}, + {14, "EFAULT", "bad address"}, + {15, "ENOTBLK", "block device required"}, + {16, "EBUSY", "device busy"}, + {17, "EEXIST", "file exists"}, + {18, "EXDEV", "cross-device link"}, + {19, "ENODEV", "operation not supported by device"}, + {20, "ENOTDIR", "not a directory"}, + {21, "EISDIR", "is a directory"}, + {22, "EINVAL", "invalid argument"}, + {23, "ENFILE", "too many open files in system"}, + {24, "EMFILE", "too many open files"}, + {25, "ENOTTY", "inappropriate ioctl for device"}, + {26, "ETXTBSY", "text file busy"}, + {27, "EFBIG", "file too large"}, + {28, "ENOSPC", "no space left on device"}, + {29, "ESPIPE", "illegal seek"}, + {30, "EROFS", "read-only file system"}, + {31, "EMLINK", "too many links"}, + {32, "EPIPE", "broken pipe"}, + {33, "EDOM", "numerical argument out of domain"}, + {34, "ERANGE", "result too large or too small"}, + {35, "EAGAIN", "resource temporarily unavailable"}, + {36, "EINPROGRESS", "operation now in progress"}, + {37, "EALREADY", "operation already in progress"}, + {38, "ENOTSOCK", "socket operation on non-socket"}, + {39, "EDESTADDRREQ", "destination address required"}, + {40, "EMSGSIZE", "message too long"}, + {41, "EPROTOTYPE", "protocol wrong type for socket"}, + {42, "ENOPROTOOPT", "protocol option not available"}, + {43, "EPROTONOSUPPORT", "protocol not supported"}, + {44, "ESOCKTNOSUPPORT", "socket type not supported"}, + {45, "EOPNOTSUPP", "operation not supported"}, + {46, "EPFNOSUPPORT", "protocol family not supported"}, + {47, "EAFNOSUPPORT", "address family not supported by protocol family"}, + {48, "EADDRINUSE", "address already in use"}, + {49, "EADDRNOTAVAIL", "can't assign requested address"}, + {50, "ENETDOWN", "network is down"}, + {51, "ENETUNREACH", "network is unreachable"}, + {52, "ENETRESET", "network dropped connection on reset"}, + {53, "ECONNABORTED", "software caused connection abort"}, + {54, "ECONNRESET", "connection reset by peer"}, + {55, "ENOBUFS", "no buffer space available"}, + {56, "EISCONN", "socket is already connected"}, + {57, "ENOTCONN", "socket is not connected"}, + {58, "ESHUTDOWN", "can't send after socket shutdown"}, + {59, "ETOOMANYREFS", "too many references: can't splice"}, + {60, "ETIMEDOUT", "connection timed out"}, + {61, "ECONNREFUSED", "connection refused"}, + {62, "ELOOP", "too many levels of symbolic links"}, + {63, "ENAMETOOLONG", "file name too long"}, + {64, "EHOSTDOWN", "host is down"}, + {65, "EHOSTUNREACH", "no route to host"}, + {66, "ENOTEMPTY", "directory not empty"}, + {67, "EPROCLIM", "too many processes"}, + {68, "EUSERS", "too many users"}, + {69, "EDQUOT", "disc quota exceeded"}, + {70, "ESTALE", "stale NFS file handle"}, + {71, "EREMOTE", "too many levels of remote in path"}, + {72, "EBADRPC", "RPC struct is bad"}, + {73, "ERPCMISMATCH", "RPC version wrong"}, + {74, "EPROGUNAVAIL", "RPC prog. not avail"}, + {75, "EPROGMISMATCH", "program version wrong"}, + {76, "EPROCUNAVAIL", "bad procedure for program"}, + {77, "ENOLCK", "no locks available"}, + {78, "ENOSYS", "function not implemented"}, + {79, "EFTYPE", "inappropriate file type or format"}, + {80, "EAUTH", "authentication error"}, + {81, "ENEEDAUTH", "need authenticator"}, + {82, "EIDRM", "identifier removed"}, + {83, "ENOMSG", "no message of desired type"}, + {84, "EOVERFLOW", "value too large to be stored in data type"}, + {85, "EILSEQ", "illegal byte sequence"}, + {86, "ENOTSUP", "not supported"}, + {87, "ECANCELED", "operation Canceled"}, + {88, "EBADMSG", "bad or Corrupt message"}, + {89, "ENODATA", "no message available"}, + {90, "ENOSR", "no STREAM resources"}, + {91, "ENOSTR", "not a STREAM"}, + {92, "ETIME", "STREAM ioctl timeout"}, + {93, "ENOATTR", "attribute not found"}, + {94, "EMULTIHOP", "multihop attempted"}, + {95, "ENOLINK", "link has been severed"}, + {96, "ELAST", "protocol error"}, } // Signal table -var signals = [...]string{ - 1: "hangup", - 2: "interrupt", - 3: "quit", - 4: "illegal instruction", - 5: "trace/BPT trap", - 6: "abort trap", - 7: "EMT trap", - 8: "floating point exception", - 9: "killed", - 10: "bus error", - 11: "segmentation fault", - 12: "bad system call", - 13: "broken pipe", - 14: "alarm clock", - 15: "terminated", - 16: "urgent I/O condition", - 17: "stopped (signal)", - 18: "stopped", - 19: "continued", - 20: "child exited", - 21: "stopped (tty input)", - 22: "stopped (tty output)", - 23: "I/O possible", - 24: "cputime limit exceeded", - 25: "filesize limit exceeded", - 26: "virtual timer expired", - 27: "profiling timer expired", - 28: "window size changes", - 29: "information request", - 30: "user defined signal 1", - 31: "user defined signal 2", - 32: "power fail/restart", +var signalList = [...]struct { + num syscall.Signal + name string + desc string +}{ + {1, "SIGHUP", "hangup"}, + {2, "SIGINT", "interrupt"}, + {3, "SIGQUIT", "quit"}, + {4, "SIGILL", "illegal instruction"}, + {5, "SIGTRAP", "trace/BPT trap"}, + {6, "SIGIOT", "abort trap"}, + {7, "SIGEMT", "EMT trap"}, + {8, "SIGFPE", "floating point exception"}, + {9, "SIGKILL", "killed"}, + {10, "SIGBUS", "bus error"}, + {11, "SIGSEGV", "segmentation fault"}, + {12, "SIGSYS", "bad system call"}, + {13, "SIGPIPE", "broken pipe"}, + {14, "SIGALRM", "alarm clock"}, + {15, "SIGTERM", "terminated"}, + {16, "SIGURG", "urgent I/O condition"}, + {17, "SIGSTOP", "stopped (signal)"}, + {18, "SIGTSTP", "stopped"}, + {19, "SIGCONT", "continued"}, + {20, "SIGCHLD", "child exited"}, + {21, "SIGTTIN", "stopped (tty input)"}, + {22, "SIGTTOU", "stopped (tty output)"}, + {23, "SIGIO", "I/O possible"}, + {24, "SIGXCPU", "cputime limit exceeded"}, + {25, "SIGXFSZ", "filesize limit exceeded"}, + {26, "SIGVTALRM", "virtual timer expired"}, + {27, "SIGPROF", "profiling timer expired"}, + {28, "SIGWINCH", "window size changes"}, + {29, "SIGINFO", "information request"}, + {30, "SIGUSR1", "user defined signal 1"}, + {31, "SIGUSR2", "user defined signal 2"}, + {32, "SIGPWR", "power fail/restart"}, } diff --git a/vendor/golang.org/x/sys/unix/zerrors_netbsd_arm64.go b/vendor/golang.org/x/sys/unix/zerrors_netbsd_arm64.go new file mode 100644 index 0000000000..fb6c60441d --- /dev/null +++ b/vendor/golang.org/x/sys/unix/zerrors_netbsd_arm64.go @@ -0,0 +1,1762 @@ +// mkerrors.sh -m64 +// Code generated by the command above; see README.md. DO NOT EDIT. + +// +build arm64,netbsd + +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs -- -m64 _const.go + +package unix + +import "syscall" + +const ( + AF_APPLETALK = 0x10 + AF_ARP = 0x1c + AF_BLUETOOTH = 0x1f + AF_CCITT = 0xa + AF_CHAOS = 0x5 + AF_CNT = 0x15 + AF_COIP = 0x14 + AF_DATAKIT = 0x9 + AF_DECnet = 0xc + AF_DLI = 0xd + AF_E164 = 0x1a + AF_ECMA = 0x8 + AF_HYLINK = 0xf + AF_IEEE80211 = 0x20 + AF_IMPLINK = 0x3 + AF_INET = 0x2 + AF_INET6 = 0x18 + AF_IPX = 0x17 + AF_ISDN = 0x1a + AF_ISO = 0x7 + AF_LAT = 0xe + AF_LINK = 0x12 + AF_LOCAL = 0x1 + AF_MAX = 0x23 + AF_MPLS = 0x21 + AF_NATM = 0x1b + AF_NS = 0x6 + AF_OROUTE = 0x11 + AF_OSI = 0x7 + AF_PUP = 0x4 + AF_ROUTE = 0x22 + AF_SNA = 0xb + AF_UNIX = 0x1 + AF_UNSPEC = 0x0 + ARPHRD_ARCNET = 0x7 + ARPHRD_ETHER = 0x1 + ARPHRD_FRELAY = 0xf + ARPHRD_IEEE1394 = 0x18 + ARPHRD_IEEE802 = 0x6 + ARPHRD_STRIP = 0x17 + B0 = 0x0 + B110 = 0x6e + B115200 = 0x1c200 + B1200 = 0x4b0 + B134 = 0x86 + B14400 = 0x3840 + B150 = 0x96 + B1800 = 0x708 + B19200 = 0x4b00 + B200 = 0xc8 + B230400 = 0x38400 + B2400 = 0x960 + B28800 = 0x7080 + B300 = 0x12c + B38400 = 0x9600 + B460800 = 0x70800 + B4800 = 0x12c0 + B50 = 0x32 + B57600 = 0xe100 + B600 = 0x258 + B7200 = 0x1c20 + B75 = 0x4b + B76800 = 0x12c00 + B921600 = 0xe1000 + B9600 = 0x2580 + BIOCFEEDBACK = 0x8004427d + BIOCFLUSH = 0x20004268 + BIOCGBLEN = 0x40044266 + BIOCGDLT = 0x4004426a + BIOCGDLTLIST = 0xc0104277 + BIOCGETIF = 0x4090426b + BIOCGFEEDBACK = 0x4004427c + BIOCGHDRCMPLT = 0x40044274 + BIOCGRTIMEOUT = 0x4010427b + BIOCGSEESENT = 0x40044278 + BIOCGSTATS = 0x4080426f + BIOCGSTATSOLD = 0x4008426f + BIOCIMMEDIATE = 0x80044270 + BIOCPROMISC = 0x20004269 + BIOCSBLEN = 0xc0044266 + BIOCSDLT = 0x80044276 + BIOCSETF = 0x80104267 + BIOCSETIF = 0x8090426c + BIOCSFEEDBACK = 0x8004427d + BIOCSHDRCMPLT = 0x80044275 + BIOCSRTIMEOUT = 0x8010427a + BIOCSSEESENT = 0x80044279 + BIOCSTCPF = 0x80104272 + BIOCSUDPF = 0x80104273 + BIOCVERSION = 0x40044271 + BPF_A = 0x10 + BPF_ABS = 0x20 + BPF_ADD = 0x0 + BPF_ALIGNMENT = 0x8 + BPF_ALIGNMENT32 = 0x4 + BPF_ALU = 0x4 + BPF_AND = 0x50 + BPF_B = 0x10 + BPF_DFLTBUFSIZE = 0x100000 + BPF_DIV = 0x30 + BPF_H = 0x8 + BPF_IMM = 0x0 + BPF_IND = 0x40 + BPF_JA = 0x0 + BPF_JEQ = 0x10 + BPF_JGE = 0x30 + BPF_JGT = 0x20 + BPF_JMP = 0x5 + BPF_JSET = 0x40 + BPF_K = 0x0 + BPF_LD = 0x0 + BPF_LDX = 0x1 + BPF_LEN = 0x80 + BPF_LSH = 0x60 + BPF_MAJOR_VERSION = 0x1 + BPF_MAXBUFSIZE = 0x1000000 + BPF_MAXINSNS = 0x200 + BPF_MEM = 0x60 + BPF_MEMWORDS = 0x10 + BPF_MINBUFSIZE = 0x20 + BPF_MINOR_VERSION = 0x1 + BPF_MISC = 0x7 + BPF_MSH = 0xa0 + BPF_MUL = 0x20 + BPF_NEG = 0x80 + BPF_OR = 0x40 + BPF_RELEASE = 0x30bb6 + BPF_RET = 0x6 + BPF_RSH = 0x70 + BPF_ST = 0x2 + BPF_STX = 0x3 + BPF_SUB = 0x10 + BPF_TAX = 0x0 + BPF_TXA = 0x80 + BPF_W = 0x0 + BPF_X = 0x8 + BRKINT = 0x2 + CFLUSH = 0xf + CLOCAL = 0x8000 + CLONE_CSIGNAL = 0xff + CLONE_FILES = 0x400 + CLONE_FS = 0x200 + CLONE_PID = 0x1000 + CLONE_PTRACE = 0x2000 + CLONE_SIGHAND = 0x800 + CLONE_VFORK = 0x4000 + CLONE_VM = 0x100 + CREAD = 0x800 + CRTSCTS = 0x10000 + CS5 = 0x0 + CS6 = 0x100 + CS7 = 0x200 + CS8 = 0x300 + CSIZE = 0x300 + CSTART = 0x11 + CSTATUS = 0x14 + CSTOP = 0x13 + CSTOPB = 0x400 + CSUSP = 0x1a + CTL_HW = 0x6 + CTL_KERN = 0x1 + CTL_MAXNAME = 0xc + CTL_NET = 0x4 + CTL_QUERY = -0x2 + DIOCBSFLUSH = 0x20006478 + DLT_A429 = 0xb8 + DLT_A653_ICM = 0xb9 + DLT_AIRONET_HEADER = 0x78 + DLT_AOS = 0xde + DLT_APPLE_IP_OVER_IEEE1394 = 0x8a + DLT_ARCNET = 0x7 + DLT_ARCNET_LINUX = 0x81 + DLT_ATM_CLIP = 0x13 + DLT_ATM_RFC1483 = 0xb + DLT_AURORA = 0x7e + DLT_AX25 = 0x3 + DLT_AX25_KISS = 0xca + DLT_BACNET_MS_TP = 0xa5 + DLT_BLUETOOTH_HCI_H4 = 0xbb + DLT_BLUETOOTH_HCI_H4_WITH_PHDR = 0xc9 + DLT_CAN20B = 0xbe + DLT_CAN_SOCKETCAN = 0xe3 + DLT_CHAOS = 0x5 + DLT_CISCO_IOS = 0x76 + DLT_C_HDLC = 0x68 + DLT_C_HDLC_WITH_DIR = 0xcd + DLT_DECT = 0xdd + DLT_DOCSIS = 0x8f + DLT_ECONET = 0x73 + DLT_EN10MB = 0x1 + DLT_EN3MB = 0x2 + DLT_ENC = 0x6d + DLT_ERF = 0xc5 + DLT_ERF_ETH = 0xaf + DLT_ERF_POS = 0xb0 + DLT_FC_2 = 0xe0 + DLT_FC_2_WITH_FRAME_DELIMS = 0xe1 + DLT_FDDI = 0xa + DLT_FLEXRAY = 0xd2 + DLT_FRELAY = 0x6b + DLT_FRELAY_WITH_DIR = 0xce + DLT_GCOM_SERIAL = 0xad + DLT_GCOM_T1E1 = 0xac + DLT_GPF_F = 0xab + DLT_GPF_T = 0xaa + DLT_GPRS_LLC = 0xa9 + DLT_GSMTAP_ABIS = 0xda + DLT_GSMTAP_UM = 0xd9 + DLT_HDLC = 0x10 + DLT_HHDLC = 0x79 + DLT_HIPPI = 0xf + DLT_IBM_SN = 0x92 + DLT_IBM_SP = 0x91 + DLT_IEEE802 = 0x6 + DLT_IEEE802_11 = 0x69 + DLT_IEEE802_11_RADIO = 0x7f + DLT_IEEE802_11_RADIO_AVS = 0xa3 + DLT_IEEE802_15_4 = 0xc3 + DLT_IEEE802_15_4_LINUX = 0xbf + DLT_IEEE802_15_4_NONASK_PHY = 0xd7 + DLT_IEEE802_16_MAC_CPS = 0xbc + DLT_IEEE802_16_MAC_CPS_RADIO = 0xc1 + DLT_IPMB = 0xc7 + DLT_IPMB_LINUX = 0xd1 + DLT_IPNET = 0xe2 + DLT_IPV4 = 0xe4 + DLT_IPV6 = 0xe5 + DLT_IP_OVER_FC = 0x7a + DLT_JUNIPER_ATM1 = 0x89 + DLT_JUNIPER_ATM2 = 0x87 + DLT_JUNIPER_CHDLC = 0xb5 + DLT_JUNIPER_ES = 0x84 + DLT_JUNIPER_ETHER = 0xb2 + DLT_JUNIPER_FRELAY = 0xb4 + DLT_JUNIPER_GGSN = 0x85 + DLT_JUNIPER_ISM = 0xc2 + DLT_JUNIPER_MFR = 0x86 + DLT_JUNIPER_MLFR = 0x83 + DLT_JUNIPER_MLPPP = 0x82 + DLT_JUNIPER_MONITOR = 0xa4 + DLT_JUNIPER_PIC_PEER = 0xae + DLT_JUNIPER_PPP = 0xb3 + DLT_JUNIPER_PPPOE = 0xa7 + DLT_JUNIPER_PPPOE_ATM = 0xa8 + DLT_JUNIPER_SERVICES = 0x88 + DLT_JUNIPER_ST = 0xc8 + DLT_JUNIPER_VP = 0xb7 + DLT_LAPB_WITH_DIR = 0xcf + DLT_LAPD = 0xcb + DLT_LIN = 0xd4 + DLT_LINUX_EVDEV = 0xd8 + DLT_LINUX_IRDA = 0x90 + DLT_LINUX_LAPD = 0xb1 + DLT_LINUX_SLL = 0x71 + DLT_LOOP = 0x6c + DLT_LTALK = 0x72 + DLT_MFR = 0xb6 + DLT_MOST = 0xd3 + DLT_MPLS = 0xdb + DLT_MTP2 = 0x8c + DLT_MTP2_WITH_PHDR = 0x8b + DLT_MTP3 = 0x8d + DLT_NULL = 0x0 + DLT_PCI_EXP = 0x7d + DLT_PFLOG = 0x75 + DLT_PFSYNC = 0x12 + DLT_PPI = 0xc0 + DLT_PPP = 0x9 + DLT_PPP_BSDOS = 0xe + DLT_PPP_ETHER = 0x33 + DLT_PPP_PPPD = 0xa6 + DLT_PPP_SERIAL = 0x32 + DLT_PPP_WITH_DIR = 0xcc + DLT_PRISM_HEADER = 0x77 + DLT_PRONET = 0x4 + DLT_RAIF1 = 0xc6 + DLT_RAW = 0xc + DLT_RAWAF_MASK = 0x2240000 + DLT_RIO = 0x7c + DLT_SCCP = 0x8e + DLT_SITA = 0xc4 + DLT_SLIP = 0x8 + DLT_SLIP_BSDOS = 0xd + DLT_SUNATM = 0x7b + DLT_SYMANTEC_FIREWALL = 0x63 + DLT_TZSP = 0x80 + DLT_USB = 0xba + DLT_USB_LINUX = 0xbd + DLT_USB_LINUX_MMAPPED = 0xdc + DLT_WIHART = 0xdf + DLT_X2E_SERIAL = 0xd5 + DLT_X2E_XORAYA = 0xd6 + DT_BLK = 0x6 + DT_CHR = 0x2 + DT_DIR = 0x4 + DT_FIFO = 0x1 + DT_LNK = 0xa + DT_REG = 0x8 + DT_SOCK = 0xc + DT_UNKNOWN = 0x0 + DT_WHT = 0xe + ECHO = 0x8 + ECHOCTL = 0x40 + ECHOE = 0x2 + ECHOK = 0x4 + ECHOKE = 0x1 + ECHONL = 0x10 + ECHOPRT = 0x20 + EMUL_LINUX = 0x1 + EMUL_LINUX32 = 0x5 + EMUL_MAXID = 0x6 + ETHERCAP_JUMBO_MTU = 0x4 + ETHERCAP_VLAN_HWTAGGING = 0x2 + ETHERCAP_VLAN_MTU = 0x1 + ETHERMIN = 0x2e + ETHERMTU = 0x5dc + ETHERMTU_JUMBO = 0x2328 + ETHERTYPE_8023 = 0x4 + ETHERTYPE_AARP = 0x80f3 + ETHERTYPE_ACCTON = 0x8390 + ETHERTYPE_AEONIC = 0x8036 + ETHERTYPE_ALPHA = 0x814a + ETHERTYPE_AMBER = 0x6008 + ETHERTYPE_AMOEBA = 0x8145 + ETHERTYPE_APOLLO = 0x80f7 + ETHERTYPE_APOLLODOMAIN = 0x8019 + ETHERTYPE_APPLETALK = 0x809b + ETHERTYPE_APPLITEK = 0x80c7 + ETHERTYPE_ARGONAUT = 0x803a + ETHERTYPE_ARP = 0x806 + ETHERTYPE_AT = 0x809b + ETHERTYPE_ATALK = 0x809b + ETHERTYPE_ATOMIC = 0x86df + ETHERTYPE_ATT = 0x8069 + ETHERTYPE_ATTSTANFORD = 0x8008 + ETHERTYPE_AUTOPHON = 0x806a + ETHERTYPE_AXIS = 0x8856 + ETHERTYPE_BCLOOP = 0x9003 + ETHERTYPE_BOFL = 0x8102 + ETHERTYPE_CABLETRON = 0x7034 + ETHERTYPE_CHAOS = 0x804 + ETHERTYPE_COMDESIGN = 0x806c + ETHERTYPE_COMPUGRAPHIC = 0x806d + ETHERTYPE_COUNTERPOINT = 0x8062 + ETHERTYPE_CRONUS = 0x8004 + ETHERTYPE_CRONUSVLN = 0x8003 + ETHERTYPE_DCA = 0x1234 + ETHERTYPE_DDE = 0x807b + ETHERTYPE_DEBNI = 0xaaaa + ETHERTYPE_DECAM = 0x8048 + ETHERTYPE_DECCUST = 0x6006 + ETHERTYPE_DECDIAG = 0x6005 + ETHERTYPE_DECDNS = 0x803c + ETHERTYPE_DECDTS = 0x803e + ETHERTYPE_DECEXPER = 0x6000 + ETHERTYPE_DECLAST = 0x8041 + ETHERTYPE_DECLTM = 0x803f + ETHERTYPE_DECMUMPS = 0x6009 + ETHERTYPE_DECNETBIOS = 0x8040 + ETHERTYPE_DELTACON = 0x86de + ETHERTYPE_DIDDLE = 0x4321 + ETHERTYPE_DLOG1 = 0x660 + ETHERTYPE_DLOG2 = 0x661 + ETHERTYPE_DN = 0x6003 + ETHERTYPE_DOGFIGHT = 0x1989 + ETHERTYPE_DSMD = 0x8039 + ETHERTYPE_ECMA = 0x803 + ETHERTYPE_ENCRYPT = 0x803d + ETHERTYPE_ES = 0x805d + ETHERTYPE_EXCELAN = 0x8010 + ETHERTYPE_EXPERDATA = 0x8049 + ETHERTYPE_FLIP = 0x8146 + ETHERTYPE_FLOWCONTROL = 0x8808 + ETHERTYPE_FRARP = 0x808 + ETHERTYPE_GENDYN = 0x8068 + ETHERTYPE_HAYES = 0x8130 + ETHERTYPE_HIPPI_FP = 0x8180 + ETHERTYPE_HITACHI = 0x8820 + ETHERTYPE_HP = 0x8005 + ETHERTYPE_IEEEPUP = 0xa00 + ETHERTYPE_IEEEPUPAT = 0xa01 + ETHERTYPE_IMLBL = 0x4c42 + ETHERTYPE_IMLBLDIAG = 0x424c + ETHERTYPE_IP = 0x800 + ETHERTYPE_IPAS = 0x876c + ETHERTYPE_IPV6 = 0x86dd + ETHERTYPE_IPX = 0x8137 + ETHERTYPE_IPXNEW = 0x8037 + ETHERTYPE_KALPANA = 0x8582 + ETHERTYPE_LANBRIDGE = 0x8038 + ETHERTYPE_LANPROBE = 0x8888 + ETHERTYPE_LAT = 0x6004 + ETHERTYPE_LBACK = 0x9000 + ETHERTYPE_LITTLE = 0x8060 + ETHERTYPE_LOGICRAFT = 0x8148 + ETHERTYPE_LOOPBACK = 0x9000 + ETHERTYPE_MATRA = 0x807a + ETHERTYPE_MAX = 0xffff + ETHERTYPE_MERIT = 0x807c + ETHERTYPE_MICP = 0x873a + ETHERTYPE_MOPDL = 0x6001 + ETHERTYPE_MOPRC = 0x6002 + ETHERTYPE_MOTOROLA = 0x818d + ETHERTYPE_MPLS = 0x8847 + ETHERTYPE_MPLS_MCAST = 0x8848 + ETHERTYPE_MUMPS = 0x813f + ETHERTYPE_NBPCC = 0x3c04 + ETHERTYPE_NBPCLAIM = 0x3c09 + ETHERTYPE_NBPCLREQ = 0x3c05 + ETHERTYPE_NBPCLRSP = 0x3c06 + ETHERTYPE_NBPCREQ = 0x3c02 + ETHERTYPE_NBPCRSP = 0x3c03 + ETHERTYPE_NBPDG = 0x3c07 + ETHERTYPE_NBPDGB = 0x3c08 + ETHERTYPE_NBPDLTE = 0x3c0a + ETHERTYPE_NBPRAR = 0x3c0c + ETHERTYPE_NBPRAS = 0x3c0b + ETHERTYPE_NBPRST = 0x3c0d + ETHERTYPE_NBPSCD = 0x3c01 + ETHERTYPE_NBPVCD = 0x3c00 + ETHERTYPE_NBS = 0x802 + ETHERTYPE_NCD = 0x8149 + ETHERTYPE_NESTAR = 0x8006 + ETHERTYPE_NETBEUI = 0x8191 + ETHERTYPE_NOVELL = 0x8138 + ETHERTYPE_NS = 0x600 + ETHERTYPE_NSAT = 0x601 + ETHERTYPE_NSCOMPAT = 0x807 + ETHERTYPE_NTRAILER = 0x10 + ETHERTYPE_OS9 = 0x7007 + ETHERTYPE_OS9NET = 0x7009 + ETHERTYPE_PACER = 0x80c6 + ETHERTYPE_PAE = 0x888e + ETHERTYPE_PCS = 0x4242 + ETHERTYPE_PLANNING = 0x8044 + ETHERTYPE_PPP = 0x880b + ETHERTYPE_PPPOE = 0x8864 + ETHERTYPE_PPPOEDISC = 0x8863 + ETHERTYPE_PRIMENTS = 0x7031 + ETHERTYPE_PUP = 0x200 + ETHERTYPE_PUPAT = 0x200 + ETHERTYPE_RACAL = 0x7030 + ETHERTYPE_RATIONAL = 0x8150 + ETHERTYPE_RAWFR = 0x6559 + ETHERTYPE_RCL = 0x1995 + ETHERTYPE_RDP = 0x8739 + ETHERTYPE_RETIX = 0x80f2 + ETHERTYPE_REVARP = 0x8035 + ETHERTYPE_SCA = 0x6007 + ETHERTYPE_SECTRA = 0x86db + ETHERTYPE_SECUREDATA = 0x876d + ETHERTYPE_SGITW = 0x817e + ETHERTYPE_SG_BOUNCE = 0x8016 + ETHERTYPE_SG_DIAG = 0x8013 + ETHERTYPE_SG_NETGAMES = 0x8014 + ETHERTYPE_SG_RESV = 0x8015 + ETHERTYPE_SIMNET = 0x5208 + ETHERTYPE_SLOWPROTOCOLS = 0x8809 + ETHERTYPE_SNA = 0x80d5 + ETHERTYPE_SNMP = 0x814c + ETHERTYPE_SONIX = 0xfaf5 + ETHERTYPE_SPIDER = 0x809f + ETHERTYPE_SPRITE = 0x500 + ETHERTYPE_STP = 0x8181 + ETHERTYPE_TALARIS = 0x812b + ETHERTYPE_TALARISMC = 0x852b + ETHERTYPE_TCPCOMP = 0x876b + ETHERTYPE_TCPSM = 0x9002 + ETHERTYPE_TEC = 0x814f + ETHERTYPE_TIGAN = 0x802f + ETHERTYPE_TRAIL = 0x1000 + ETHERTYPE_TRANSETHER = 0x6558 + ETHERTYPE_TYMSHARE = 0x802e + ETHERTYPE_UBBST = 0x7005 + ETHERTYPE_UBDEBUG = 0x900 + ETHERTYPE_UBDIAGLOOP = 0x7002 + ETHERTYPE_UBDL = 0x7000 + ETHERTYPE_UBNIU = 0x7001 + ETHERTYPE_UBNMC = 0x7003 + ETHERTYPE_VALID = 0x1600 + ETHERTYPE_VARIAN = 0x80dd + ETHERTYPE_VAXELN = 0x803b + ETHERTYPE_VEECO = 0x8067 + ETHERTYPE_VEXP = 0x805b + ETHERTYPE_VGLAB = 0x8131 + ETHERTYPE_VINES = 0xbad + ETHERTYPE_VINESECHO = 0xbaf + ETHERTYPE_VINESLOOP = 0xbae + ETHERTYPE_VITAL = 0xff00 + ETHERTYPE_VLAN = 0x8100 + ETHERTYPE_VLTLMAN = 0x8080 + ETHERTYPE_VPROD = 0x805c + ETHERTYPE_VURESERVED = 0x8147 + ETHERTYPE_WATERLOO = 0x8130 + ETHERTYPE_WELLFLEET = 0x8103 + ETHERTYPE_X25 = 0x805 + ETHERTYPE_X75 = 0x801 + ETHERTYPE_XNSSM = 0x9001 + ETHERTYPE_XTP = 0x817d + ETHER_ADDR_LEN = 0x6 + ETHER_CRC_LEN = 0x4 + ETHER_CRC_POLY_BE = 0x4c11db6 + ETHER_CRC_POLY_LE = 0xedb88320 + ETHER_HDR_LEN = 0xe + ETHER_MAX_LEN = 0x5ee + ETHER_MAX_LEN_JUMBO = 0x233a + ETHER_MIN_LEN = 0x40 + ETHER_PPPOE_ENCAP_LEN = 0x8 + ETHER_TYPE_LEN = 0x2 + ETHER_VLAN_ENCAP_LEN = 0x4 + EVFILT_AIO = 0x2 + EVFILT_PROC = 0x4 + EVFILT_READ = 0x0 + EVFILT_SIGNAL = 0x5 + EVFILT_SYSCOUNT = 0x7 + EVFILT_TIMER = 0x6 + EVFILT_VNODE = 0x3 + EVFILT_WRITE = 0x1 + EV_ADD = 0x1 + EV_CLEAR = 0x20 + EV_DELETE = 0x2 + EV_DISABLE = 0x8 + EV_ENABLE = 0x4 + EV_EOF = 0x8000 + EV_ERROR = 0x4000 + EV_FLAG1 = 0x2000 + EV_ONESHOT = 0x10 + EV_SYSFLAGS = 0xf000 + EXTA = 0x4b00 + EXTATTR_CMD_START = 0x1 + EXTATTR_CMD_STOP = 0x2 + EXTATTR_NAMESPACE_SYSTEM = 0x2 + EXTATTR_NAMESPACE_USER = 0x1 + EXTB = 0x9600 + EXTPROC = 0x800 + FD_CLOEXEC = 0x1 + FD_SETSIZE = 0x100 + FLUSHO = 0x800000 + F_CLOSEM = 0xa + F_DUPFD = 0x0 + F_DUPFD_CLOEXEC = 0xc + F_FSCTL = -0x80000000 + F_FSDIRMASK = 0x70000000 + F_FSIN = 0x10000000 + F_FSINOUT = 0x30000000 + F_FSOUT = 0x20000000 + F_FSPRIV = 0x8000 + F_FSVOID = 0x40000000 + F_GETFD = 0x1 + F_GETFL = 0x3 + F_GETLK = 0x7 + F_GETNOSIGPIPE = 0xd + F_GETOWN = 0x5 + F_MAXFD = 0xb + F_OK = 0x0 + F_PARAM_MASK = 0xfff + F_PARAM_MAX = 0xfff + F_RDLCK = 0x1 + F_SETFD = 0x2 + F_SETFL = 0x4 + F_SETLK = 0x8 + F_SETLKW = 0x9 + F_SETNOSIGPIPE = 0xe + F_SETOWN = 0x6 + F_UNLCK = 0x2 + F_WRLCK = 0x3 + HUPCL = 0x4000 + HW_MACHINE = 0x1 + ICANON = 0x100 + ICMP6_FILTER = 0x12 + ICRNL = 0x100 + IEXTEN = 0x400 + IFAN_ARRIVAL = 0x0 + IFAN_DEPARTURE = 0x1 + IFA_ROUTE = 0x1 + IFF_ALLMULTI = 0x200 + IFF_BROADCAST = 0x2 + IFF_CANTCHANGE = 0x8f52 + IFF_DEBUG = 0x4 + IFF_LINK0 = 0x1000 + IFF_LINK1 = 0x2000 + IFF_LINK2 = 0x4000 + IFF_LOOPBACK = 0x8 + IFF_MULTICAST = 0x8000 + IFF_NOARP = 0x80 + IFF_NOTRAILERS = 0x20 + IFF_OACTIVE = 0x400 + IFF_POINTOPOINT = 0x10 + IFF_PROMISC = 0x100 + IFF_RUNNING = 0x40 + IFF_SIMPLEX = 0x800 + IFF_UP = 0x1 + IFNAMSIZ = 0x10 + IFT_1822 = 0x2 + IFT_A12MPPSWITCH = 0x82 + IFT_AAL2 = 0xbb + IFT_AAL5 = 0x31 + IFT_ADSL = 0x5e + IFT_AFLANE8023 = 0x3b + IFT_AFLANE8025 = 0x3c + IFT_ARAP = 0x58 + IFT_ARCNET = 0x23 + IFT_ARCNETPLUS = 0x24 + IFT_ASYNC = 0x54 + IFT_ATM = 0x25 + IFT_ATMDXI = 0x69 + IFT_ATMFUNI = 0x6a + IFT_ATMIMA = 0x6b + IFT_ATMLOGICAL = 0x50 + IFT_ATMRADIO = 0xbd + IFT_ATMSUBINTERFACE = 0x86 + IFT_ATMVCIENDPT = 0xc2 + IFT_ATMVIRTUAL = 0x95 + IFT_BGPPOLICYACCOUNTING = 0xa2 + IFT_BRIDGE = 0xd1 + IFT_BSC = 0x53 + IFT_CARP = 0xf8 + IFT_CCTEMUL = 0x3d + IFT_CEPT = 0x13 + IFT_CES = 0x85 + IFT_CHANNEL = 0x46 + IFT_CNR = 0x55 + IFT_COFFEE = 0x84 + IFT_COMPOSITELINK = 0x9b + IFT_DCN = 0x8d + IFT_DIGITALPOWERLINE = 0x8a + IFT_DIGITALWRAPPEROVERHEADCHANNEL = 0xba + IFT_DLSW = 0x4a + IFT_DOCSCABLEDOWNSTREAM = 0x80 + IFT_DOCSCABLEMACLAYER = 0x7f + IFT_DOCSCABLEUPSTREAM = 0x81 + IFT_DOCSCABLEUPSTREAMCHANNEL = 0xcd + IFT_DS0 = 0x51 + IFT_DS0BUNDLE = 0x52 + IFT_DS1FDL = 0xaa + IFT_DS3 = 0x1e + IFT_DTM = 0x8c + IFT_DVBASILN = 0xac + IFT_DVBASIOUT = 0xad + IFT_DVBRCCDOWNSTREAM = 0x93 + IFT_DVBRCCMACLAYER = 0x92 + IFT_DVBRCCUPSTREAM = 0x94 + IFT_ECONET = 0xce + IFT_EON = 0x19 + IFT_EPLRS = 0x57 + IFT_ESCON = 0x49 + IFT_ETHER = 0x6 + IFT_FAITH = 0xf2 + IFT_FAST = 0x7d + IFT_FASTETHER = 0x3e + IFT_FASTETHERFX = 0x45 + IFT_FDDI = 0xf + IFT_FIBRECHANNEL = 0x38 + IFT_FRAMERELAYINTERCONNECT = 0x3a + IFT_FRAMERELAYMPI = 0x5c + IFT_FRDLCIENDPT = 0xc1 + IFT_FRELAY = 0x20 + IFT_FRELAYDCE = 0x2c + IFT_FRF16MFRBUNDLE = 0xa3 + IFT_FRFORWARD = 0x9e + IFT_G703AT2MB = 0x43 + IFT_G703AT64K = 0x42 + IFT_GIF = 0xf0 + IFT_GIGABITETHERNET = 0x75 + IFT_GR303IDT = 0xb2 + IFT_GR303RDT = 0xb1 + IFT_H323GATEKEEPER = 0xa4 + IFT_H323PROXY = 0xa5 + IFT_HDH1822 = 0x3 + IFT_HDLC = 0x76 + IFT_HDSL2 = 0xa8 + IFT_HIPERLAN2 = 0xb7 + IFT_HIPPI = 0x2f + IFT_HIPPIINTERFACE = 0x39 + IFT_HOSTPAD = 0x5a + IFT_HSSI = 0x2e + IFT_HY = 0xe + IFT_IBM370PARCHAN = 0x48 + IFT_IDSL = 0x9a + IFT_IEEE1394 = 0x90 + IFT_IEEE80211 = 0x47 + IFT_IEEE80212 = 0x37 + IFT_IEEE8023ADLAG = 0xa1 + IFT_IFGSN = 0x91 + IFT_IMT = 0xbe + IFT_INFINIBAND = 0xc7 + IFT_INTERLEAVE = 0x7c + IFT_IP = 0x7e + IFT_IPFORWARD = 0x8e + IFT_IPOVERATM = 0x72 + IFT_IPOVERCDLC = 0x6d + IFT_IPOVERCLAW = 0x6e + IFT_IPSWITCH = 0x4e + IFT_ISDN = 0x3f + IFT_ISDNBASIC = 0x14 + IFT_ISDNPRIMARY = 0x15 + IFT_ISDNS = 0x4b + IFT_ISDNU = 0x4c + IFT_ISO88022LLC = 0x29 + IFT_ISO88023 = 0x7 + IFT_ISO88024 = 0x8 + IFT_ISO88025 = 0x9 + IFT_ISO88025CRFPINT = 0x62 + IFT_ISO88025DTR = 0x56 + IFT_ISO88025FIBER = 0x73 + IFT_ISO88026 = 0xa + IFT_ISUP = 0xb3 + IFT_L2VLAN = 0x87 + IFT_L3IPVLAN = 0x88 + IFT_L3IPXVLAN = 0x89 + IFT_LAPB = 0x10 + IFT_LAPD = 0x4d + IFT_LAPF = 0x77 + IFT_LINEGROUP = 0xd2 + IFT_LOCALTALK = 0x2a + IFT_LOOP = 0x18 + IFT_MEDIAMAILOVERIP = 0x8b + IFT_MFSIGLINK = 0xa7 + IFT_MIOX25 = 0x26 + IFT_MODEM = 0x30 + IFT_MPC = 0x71 + IFT_MPLS = 0xa6 + IFT_MPLSTUNNEL = 0x96 + IFT_MSDSL = 0x8f + IFT_MVL = 0xbf + IFT_MYRINET = 0x63 + IFT_NFAS = 0xaf + IFT_NSIP = 0x1b + IFT_OPTICALCHANNEL = 0xc3 + IFT_OPTICALTRANSPORT = 0xc4 + IFT_OTHER = 0x1 + IFT_P10 = 0xc + IFT_P80 = 0xd + IFT_PARA = 0x22 + IFT_PFLOG = 0xf5 + IFT_PFSYNC = 0xf6 + IFT_PLC = 0xae + IFT_PON155 = 0xcf + IFT_PON622 = 0xd0 + IFT_POS = 0xab + IFT_PPP = 0x17 + IFT_PPPMULTILINKBUNDLE = 0x6c + IFT_PROPATM = 0xc5 + IFT_PROPBWAP2MP = 0xb8 + IFT_PROPCNLS = 0x59 + IFT_PROPDOCSWIRELESSDOWNSTREAM = 0xb5 + IFT_PROPDOCSWIRELESSMACLAYER = 0xb4 + IFT_PROPDOCSWIRELESSUPSTREAM = 0xb6 + IFT_PROPMUX = 0x36 + IFT_PROPVIRTUAL = 0x35 + IFT_PROPWIRELESSP2P = 0x9d + IFT_PTPSERIAL = 0x16 + IFT_PVC = 0xf1 + IFT_Q2931 = 0xc9 + IFT_QLLC = 0x44 + IFT_RADIOMAC = 0xbc + IFT_RADSL = 0x5f + IFT_REACHDSL = 0xc0 + IFT_RFC1483 = 0x9f + IFT_RS232 = 0x21 + IFT_RSRB = 0x4f + IFT_SDLC = 0x11 + IFT_SDSL = 0x60 + IFT_SHDSL = 0xa9 + IFT_SIP = 0x1f + IFT_SIPSIG = 0xcc + IFT_SIPTG = 0xcb + IFT_SLIP = 0x1c + IFT_SMDSDXI = 0x2b + IFT_SMDSICIP = 0x34 + IFT_SONET = 0x27 + IFT_SONETOVERHEADCHANNEL = 0xb9 + IFT_SONETPATH = 0x32 + IFT_SONETVT = 0x33 + IFT_SRP = 0x97 + IFT_SS7SIGLINK = 0x9c + IFT_STACKTOSTACK = 0x6f + IFT_STARLAN = 0xb + IFT_STF = 0xd7 + IFT_T1 = 0x12 + IFT_TDLC = 0x74 + IFT_TELINK = 0xc8 + IFT_TERMPAD = 0x5b + IFT_TR008 = 0xb0 + IFT_TRANSPHDLC = 0x7b + IFT_TUNNEL = 0x83 + IFT_ULTRA = 0x1d + IFT_USB = 0xa0 + IFT_V11 = 0x40 + IFT_V35 = 0x2d + IFT_V36 = 0x41 + IFT_V37 = 0x78 + IFT_VDSL = 0x61 + IFT_VIRTUALIPADDRESS = 0x70 + IFT_VIRTUALTG = 0xca + IFT_VOICEDID = 0xd5 + IFT_VOICEEM = 0x64 + IFT_VOICEEMFGD = 0xd3 + IFT_VOICEENCAP = 0x67 + IFT_VOICEFGDEANA = 0xd4 + IFT_VOICEFXO = 0x65 + IFT_VOICEFXS = 0x66 + IFT_VOICEOVERATM = 0x98 + IFT_VOICEOVERCABLE = 0xc6 + IFT_VOICEOVERFRAMERELAY = 0x99 + IFT_VOICEOVERIP = 0x68 + IFT_X213 = 0x5d + IFT_X25 = 0x5 + IFT_X25DDN = 0x4 + IFT_X25HUNTGROUP = 0x7a + IFT_X25MLP = 0x79 + IFT_X25PLE = 0x28 + IFT_XETHER = 0x1a + IGNBRK = 0x1 + IGNCR = 0x80 + IGNPAR = 0x4 + IMAXBEL = 0x2000 + INLCR = 0x40 + INPCK = 0x10 + IN_CLASSA_HOST = 0xffffff + IN_CLASSA_MAX = 0x80 + IN_CLASSA_NET = 0xff000000 + IN_CLASSA_NSHIFT = 0x18 + IN_CLASSB_HOST = 0xffff + IN_CLASSB_MAX = 0x10000 + IN_CLASSB_NET = 0xffff0000 + IN_CLASSB_NSHIFT = 0x10 + IN_CLASSC_HOST = 0xff + IN_CLASSC_NET = 0xffffff00 + IN_CLASSC_NSHIFT = 0x8 + IN_CLASSD_HOST = 0xfffffff + IN_CLASSD_NET = 0xf0000000 + IN_CLASSD_NSHIFT = 0x1c + IN_LOOPBACKNET = 0x7f + IPPROTO_AH = 0x33 + IPPROTO_CARP = 0x70 + IPPROTO_DONE = 0x101 + IPPROTO_DSTOPTS = 0x3c + IPPROTO_EGP = 0x8 + IPPROTO_ENCAP = 0x62 + IPPROTO_EON = 0x50 + IPPROTO_ESP = 0x32 + IPPROTO_ETHERIP = 0x61 + IPPROTO_FRAGMENT = 0x2c + IPPROTO_GGP = 0x3 + IPPROTO_GRE = 0x2f + IPPROTO_HOPOPTS = 0x0 + IPPROTO_ICMP = 0x1 + IPPROTO_ICMPV6 = 0x3a + IPPROTO_IDP = 0x16 + IPPROTO_IGMP = 0x2 + IPPROTO_IP = 0x0 + IPPROTO_IPCOMP = 0x6c + IPPROTO_IPIP = 0x4 + IPPROTO_IPV4 = 0x4 + IPPROTO_IPV6 = 0x29 + IPPROTO_IPV6_ICMP = 0x3a + IPPROTO_MAX = 0x100 + IPPROTO_MAXID = 0x34 + IPPROTO_MOBILE = 0x37 + IPPROTO_NONE = 0x3b + IPPROTO_PFSYNC = 0xf0 + IPPROTO_PIM = 0x67 + IPPROTO_PUP = 0xc + IPPROTO_RAW = 0xff + IPPROTO_ROUTING = 0x2b + IPPROTO_RSVP = 0x2e + IPPROTO_TCP = 0x6 + IPPROTO_TP = 0x1d + IPPROTO_UDP = 0x11 + IPPROTO_VRRP = 0x70 + IPV6_CHECKSUM = 0x1a + IPV6_DEFAULT_MULTICAST_HOPS = 0x1 + IPV6_DEFAULT_MULTICAST_LOOP = 0x1 + IPV6_DEFHLIM = 0x40 + IPV6_DONTFRAG = 0x3e + IPV6_DSTOPTS = 0x32 + IPV6_FAITH = 0x1d + IPV6_FLOWINFO_MASK = 0xffffff0f + IPV6_FLOWLABEL_MASK = 0xffff0f00 + IPV6_FRAGTTL = 0x78 + IPV6_HLIMDEC = 0x1 + IPV6_HOPLIMIT = 0x2f + IPV6_HOPOPTS = 0x31 + IPV6_IPSEC_POLICY = 0x1c + IPV6_JOIN_GROUP = 0xc + IPV6_LEAVE_GROUP = 0xd + IPV6_MAXHLIM = 0xff + IPV6_MAXPACKET = 0xffff + IPV6_MMTU = 0x500 + IPV6_MULTICAST_HOPS = 0xa + IPV6_MULTICAST_IF = 0x9 + IPV6_MULTICAST_LOOP = 0xb + IPV6_NEXTHOP = 0x30 + IPV6_PATHMTU = 0x2c + IPV6_PKTINFO = 0x2e + IPV6_PORTRANGE = 0xe + IPV6_PORTRANGE_DEFAULT = 0x0 + IPV6_PORTRANGE_HIGH = 0x1 + IPV6_PORTRANGE_LOW = 0x2 + IPV6_RECVDSTOPTS = 0x28 + IPV6_RECVHOPLIMIT = 0x25 + IPV6_RECVHOPOPTS = 0x27 + IPV6_RECVPATHMTU = 0x2b + IPV6_RECVPKTINFO = 0x24 + IPV6_RECVRTHDR = 0x26 + IPV6_RECVTCLASS = 0x39 + IPV6_RTHDR = 0x33 + IPV6_RTHDRDSTOPTS = 0x23 + IPV6_RTHDR_LOOSE = 0x0 + IPV6_RTHDR_STRICT = 0x1 + IPV6_RTHDR_TYPE_0 = 0x0 + IPV6_SOCKOPT_RESERVED1 = 0x3 + IPV6_TCLASS = 0x3d + IPV6_UNICAST_HOPS = 0x4 + IPV6_USE_MIN_MTU = 0x2a + IPV6_V6ONLY = 0x1b + IPV6_VERSION = 0x60 + IPV6_VERSION_MASK = 0xf0 + IP_ADD_MEMBERSHIP = 0xc + IP_DEFAULT_MULTICAST_LOOP = 0x1 + IP_DEFAULT_MULTICAST_TTL = 0x1 + IP_DF = 0x4000 + IP_DROP_MEMBERSHIP = 0xd + IP_EF = 0x8000 + IP_ERRORMTU = 0x15 + IP_HDRINCL = 0x2 + IP_IPSEC_POLICY = 0x16 + IP_MAXPACKET = 0xffff + IP_MAX_MEMBERSHIPS = 0x14 + IP_MF = 0x2000 + IP_MINFRAGSIZE = 0x45 + IP_MINTTL = 0x18 + IP_MSS = 0x240 + IP_MULTICAST_IF = 0x9 + IP_MULTICAST_LOOP = 0xb + IP_MULTICAST_TTL = 0xa + IP_OFFMASK = 0x1fff + IP_OPTIONS = 0x1 + IP_PORTRANGE = 0x13 + IP_PORTRANGE_DEFAULT = 0x0 + IP_PORTRANGE_HIGH = 0x1 + IP_PORTRANGE_LOW = 0x2 + IP_RECVDSTADDR = 0x7 + IP_RECVIF = 0x14 + IP_RECVOPTS = 0x5 + IP_RECVRETOPTS = 0x6 + IP_RECVTTL = 0x17 + IP_RETOPTS = 0x8 + IP_RF = 0x8000 + IP_TOS = 0x3 + IP_TTL = 0x4 + ISIG = 0x80 + ISTRIP = 0x20 + IXANY = 0x800 + IXOFF = 0x400 + IXON = 0x200 + KERN_HOSTNAME = 0xa + KERN_OSRELEASE = 0x2 + KERN_OSTYPE = 0x1 + KERN_VERSION = 0x4 + LOCK_EX = 0x2 + LOCK_NB = 0x4 + LOCK_SH = 0x1 + LOCK_UN = 0x8 + MADV_DONTNEED = 0x4 + MADV_FREE = 0x6 + MADV_NORMAL = 0x0 + MADV_RANDOM = 0x1 + MADV_SEQUENTIAL = 0x2 + MADV_SPACEAVAIL = 0x5 + MADV_WILLNEED = 0x3 + MAP_ALIGNMENT_16MB = 0x18000000 + MAP_ALIGNMENT_1TB = 0x28000000 + MAP_ALIGNMENT_256TB = 0x30000000 + MAP_ALIGNMENT_4GB = 0x20000000 + MAP_ALIGNMENT_64KB = 0x10000000 + MAP_ALIGNMENT_64PB = 0x38000000 + MAP_ALIGNMENT_MASK = -0x1000000 + MAP_ALIGNMENT_SHIFT = 0x18 + MAP_ANON = 0x1000 + MAP_FILE = 0x0 + MAP_FIXED = 0x10 + MAP_HASSEMAPHORE = 0x200 + MAP_INHERIT = 0x80 + MAP_INHERIT_COPY = 0x1 + MAP_INHERIT_DEFAULT = 0x1 + MAP_INHERIT_DONATE_COPY = 0x3 + MAP_INHERIT_NONE = 0x2 + MAP_INHERIT_SHARE = 0x0 + MAP_NORESERVE = 0x40 + MAP_PRIVATE = 0x2 + MAP_RENAME = 0x20 + MAP_SHARED = 0x1 + MAP_STACK = 0x2000 + MAP_TRYFIXED = 0x400 + MAP_WIRED = 0x800 + MCL_CURRENT = 0x1 + MCL_FUTURE = 0x2 + MNT_ASYNC = 0x40 + MNT_BASIC_FLAGS = 0xe782807f + MNT_DEFEXPORTED = 0x200 + MNT_DISCARD = 0x800000 + MNT_EXKERB = 0x800 + MNT_EXNORESPORT = 0x8000000 + MNT_EXPORTANON = 0x400 + MNT_EXPORTED = 0x100 + MNT_EXPUBLIC = 0x10000000 + MNT_EXRDONLY = 0x80 + MNT_EXTATTR = 0x1000000 + MNT_FORCE = 0x80000 + MNT_GETARGS = 0x400000 + MNT_IGNORE = 0x100000 + MNT_LAZY = 0x3 + MNT_LOCAL = 0x1000 + MNT_LOG = 0x2000000 + MNT_NOATIME = 0x4000000 + MNT_NOCOREDUMP = 0x8000 + MNT_NODEV = 0x10 + MNT_NODEVMTIME = 0x40000000 + MNT_NOEXEC = 0x4 + MNT_NOSUID = 0x8 + MNT_NOWAIT = 0x2 + MNT_OP_FLAGS = 0x4d0000 + MNT_QUOTA = 0x2000 + MNT_RDONLY = 0x1 + MNT_RELATIME = 0x20000 + MNT_RELOAD = 0x40000 + MNT_ROOTFS = 0x4000 + MNT_SOFTDEP = 0x80000000 + MNT_SYMPERM = 0x20000000 + MNT_SYNCHRONOUS = 0x2 + MNT_UNION = 0x20 + MNT_UPDATE = 0x10000 + MNT_VISFLAGMASK = 0xff90ffff + MNT_WAIT = 0x1 + MSG_BCAST = 0x100 + MSG_CMSG_CLOEXEC = 0x800 + MSG_CONTROLMBUF = 0x2000000 + MSG_CTRUNC = 0x20 + MSG_DONTROUTE = 0x4 + MSG_DONTWAIT = 0x80 + MSG_EOR = 0x8 + MSG_IOVUSRSPACE = 0x4000000 + MSG_LENUSRSPACE = 0x8000000 + MSG_MCAST = 0x200 + MSG_NAMEMBUF = 0x1000000 + MSG_NBIO = 0x1000 + MSG_NOSIGNAL = 0x400 + MSG_OOB = 0x1 + MSG_PEEK = 0x2 + MSG_TRUNC = 0x10 + MSG_USERFLAGS = 0xffffff + MSG_WAITALL = 0x40 + MS_ASYNC = 0x1 + MS_INVALIDATE = 0x2 + MS_SYNC = 0x4 + NAME_MAX = 0x1ff + NET_RT_DUMP = 0x1 + NET_RT_FLAGS = 0x2 + NET_RT_IFLIST = 0x5 + NET_RT_MAXID = 0x6 + NET_RT_OIFLIST = 0x4 + NET_RT_OOIFLIST = 0x3 + NOFLSH = 0x80000000 + NOTE_ATTRIB = 0x8 + NOTE_CHILD = 0x4 + NOTE_DELETE = 0x1 + NOTE_EXEC = 0x20000000 + NOTE_EXIT = 0x80000000 + NOTE_EXTEND = 0x4 + NOTE_FORK = 0x40000000 + NOTE_LINK = 0x10 + NOTE_LOWAT = 0x1 + NOTE_PCTRLMASK = 0xf0000000 + NOTE_PDATAMASK = 0xfffff + NOTE_RENAME = 0x20 + NOTE_REVOKE = 0x40 + NOTE_TRACK = 0x1 + NOTE_TRACKERR = 0x2 + NOTE_WRITE = 0x2 + OCRNL = 0x10 + OFIOGETBMAP = 0xc004667a + ONLCR = 0x2 + ONLRET = 0x40 + ONOCR = 0x20 + ONOEOT = 0x8 + OPOST = 0x1 + O_ACCMODE = 0x3 + O_ALT_IO = 0x40000 + O_APPEND = 0x8 + O_ASYNC = 0x40 + O_CLOEXEC = 0x400000 + O_CREAT = 0x200 + O_DIRECT = 0x80000 + O_DIRECTORY = 0x200000 + O_DSYNC = 0x10000 + O_EXCL = 0x800 + O_EXLOCK = 0x20 + O_FSYNC = 0x80 + O_NDELAY = 0x4 + O_NOCTTY = 0x8000 + O_NOFOLLOW = 0x100 + O_NONBLOCK = 0x4 + O_NOSIGPIPE = 0x1000000 + O_RDONLY = 0x0 + O_RDWR = 0x2 + O_RSYNC = 0x20000 + O_SHLOCK = 0x10 + O_SYNC = 0x80 + O_TRUNC = 0x400 + O_WRONLY = 0x1 + PARENB = 0x1000 + PARMRK = 0x8 + PARODD = 0x2000 + PENDIN = 0x20000000 + PRIO_PGRP = 0x1 + PRIO_PROCESS = 0x0 + PRIO_USER = 0x2 + PRI_IOFLUSH = 0x7c + PROT_EXEC = 0x4 + PROT_NONE = 0x0 + PROT_READ = 0x1 + PROT_WRITE = 0x2 + RLIMIT_AS = 0xa + RLIMIT_CORE = 0x4 + RLIMIT_CPU = 0x0 + RLIMIT_DATA = 0x2 + RLIMIT_FSIZE = 0x1 + RLIMIT_MEMLOCK = 0x6 + RLIMIT_NOFILE = 0x8 + RLIMIT_NPROC = 0x7 + RLIMIT_RSS = 0x5 + RLIMIT_STACK = 0x3 + RLIM_INFINITY = 0x7fffffffffffffff + RTAX_AUTHOR = 0x6 + RTAX_BRD = 0x7 + RTAX_DST = 0x0 + RTAX_GATEWAY = 0x1 + RTAX_GENMASK = 0x3 + RTAX_IFA = 0x5 + RTAX_IFP = 0x4 + RTAX_MAX = 0x9 + RTAX_NETMASK = 0x2 + RTAX_TAG = 0x8 + RTA_AUTHOR = 0x40 + RTA_BRD = 0x80 + RTA_DST = 0x1 + RTA_GATEWAY = 0x2 + RTA_GENMASK = 0x8 + RTA_IFA = 0x20 + RTA_IFP = 0x10 + RTA_NETMASK = 0x4 + RTA_TAG = 0x100 + RTF_ANNOUNCE = 0x20000 + RTF_BLACKHOLE = 0x1000 + RTF_CLONED = 0x2000 + RTF_CLONING = 0x100 + RTF_DONE = 0x40 + RTF_DYNAMIC = 0x10 + RTF_GATEWAY = 0x2 + RTF_HOST = 0x4 + RTF_LLINFO = 0x400 + RTF_MASK = 0x80 + RTF_MODIFIED = 0x20 + RTF_PROTO1 = 0x8000 + RTF_PROTO2 = 0x4000 + RTF_REJECT = 0x8 + RTF_SRC = 0x10000 + RTF_STATIC = 0x800 + RTF_UP = 0x1 + RTF_XRESOLVE = 0x200 + RTM_ADD = 0x1 + RTM_CHANGE = 0x3 + RTM_CHGADDR = 0x15 + RTM_DELADDR = 0xd + RTM_DELETE = 0x2 + RTM_GET = 0x4 + RTM_IEEE80211 = 0x11 + RTM_IFANNOUNCE = 0x10 + RTM_IFINFO = 0x14 + RTM_LLINFO_UPD = 0x13 + RTM_LOCK = 0x8 + RTM_LOSING = 0x5 + RTM_MISS = 0x7 + RTM_NEWADDR = 0xc + RTM_OIFINFO = 0xf + RTM_OLDADD = 0x9 + RTM_OLDDEL = 0xa + RTM_OOIFINFO = 0xe + RTM_REDIRECT = 0x6 + RTM_RESOLVE = 0xb + RTM_RTTUNIT = 0xf4240 + RTM_SETGATE = 0x12 + RTM_VERSION = 0x4 + RTV_EXPIRE = 0x4 + RTV_HOPCOUNT = 0x2 + RTV_MTU = 0x1 + RTV_RPIPE = 0x8 + RTV_RTT = 0x40 + RTV_RTTVAR = 0x80 + RTV_SPIPE = 0x10 + RTV_SSTHRESH = 0x20 + RUSAGE_CHILDREN = -0x1 + RUSAGE_SELF = 0x0 + SCM_CREDS = 0x4 + SCM_RIGHTS = 0x1 + SCM_TIMESTAMP = 0x8 + SHUT_RD = 0x0 + SHUT_RDWR = 0x2 + SHUT_WR = 0x1 + SIOCADDMULTI = 0x80906931 + SIOCADDRT = 0x8038720a + SIOCAIFADDR = 0x8040691a + SIOCALIFADDR = 0x8118691c + SIOCATMARK = 0x40047307 + SIOCDELMULTI = 0x80906932 + SIOCDELRT = 0x8038720b + SIOCDIFADDR = 0x80906919 + SIOCDIFPHYADDR = 0x80906949 + SIOCDLIFADDR = 0x8118691e + SIOCGDRVSPEC = 0xc028697b + SIOCGETPFSYNC = 0xc09069f8 + SIOCGETSGCNT = 0xc0207534 + SIOCGETVIFCNT = 0xc0287533 + SIOCGHIWAT = 0x40047301 + SIOCGIFADDR = 0xc0906921 + SIOCGIFADDRPREF = 0xc0986920 + SIOCGIFALIAS = 0xc040691b + SIOCGIFBRDADDR = 0xc0906923 + SIOCGIFCAP = 0xc0206976 + SIOCGIFCONF = 0xc0106926 + SIOCGIFDATA = 0xc0986985 + SIOCGIFDLT = 0xc0906977 + SIOCGIFDSTADDR = 0xc0906922 + SIOCGIFFLAGS = 0xc0906911 + SIOCGIFGENERIC = 0xc090693a + SIOCGIFMEDIA = 0xc0306936 + SIOCGIFMETRIC = 0xc0906917 + SIOCGIFMTU = 0xc090697e + SIOCGIFNETMASK = 0xc0906925 + SIOCGIFPDSTADDR = 0xc0906948 + SIOCGIFPSRCADDR = 0xc0906947 + SIOCGLIFADDR = 0xc118691d + SIOCGLIFPHYADDR = 0xc118694b + SIOCGLINKSTR = 0xc0286987 + SIOCGLOWAT = 0x40047303 + SIOCGPGRP = 0x40047309 + SIOCGVH = 0xc0906983 + SIOCIFCREATE = 0x8090697a + SIOCIFDESTROY = 0x80906979 + SIOCIFGCLONERS = 0xc0106978 + SIOCINITIFADDR = 0xc0706984 + SIOCSDRVSPEC = 0x8028697b + SIOCSETPFSYNC = 0x809069f7 + SIOCSHIWAT = 0x80047300 + SIOCSIFADDR = 0x8090690c + SIOCSIFADDRPREF = 0x8098691f + SIOCSIFBRDADDR = 0x80906913 + SIOCSIFCAP = 0x80206975 + SIOCSIFDSTADDR = 0x8090690e + SIOCSIFFLAGS = 0x80906910 + SIOCSIFGENERIC = 0x80906939 + SIOCSIFMEDIA = 0xc0906935 + SIOCSIFMETRIC = 0x80906918 + SIOCSIFMTU = 0x8090697f + SIOCSIFNETMASK = 0x80906916 + SIOCSIFPHYADDR = 0x80406946 + SIOCSLIFPHYADDR = 0x8118694a + SIOCSLINKSTR = 0x80286988 + SIOCSLOWAT = 0x80047302 + SIOCSPGRP = 0x80047308 + SIOCSVH = 0xc0906982 + SIOCZIFDATA = 0xc0986986 + SOCK_CLOEXEC = 0x10000000 + SOCK_DGRAM = 0x2 + SOCK_FLAGS_MASK = 0xf0000000 + SOCK_NONBLOCK = 0x20000000 + SOCK_NOSIGPIPE = 0x40000000 + SOCK_RAW = 0x3 + SOCK_RDM = 0x4 + SOCK_SEQPACKET = 0x5 + SOCK_STREAM = 0x1 + SOL_SOCKET = 0xffff + SOMAXCONN = 0x80 + SO_ACCEPTCONN = 0x2 + SO_ACCEPTFILTER = 0x1000 + SO_BROADCAST = 0x20 + SO_DEBUG = 0x1 + SO_DONTROUTE = 0x10 + SO_ERROR = 0x1007 + SO_KEEPALIVE = 0x8 + SO_LINGER = 0x80 + SO_NOHEADER = 0x100a + SO_NOSIGPIPE = 0x800 + SO_OOBINLINE = 0x100 + SO_OVERFLOWED = 0x1009 + SO_RCVBUF = 0x1002 + SO_RCVLOWAT = 0x1004 + SO_RCVTIMEO = 0x100c + SO_REUSEADDR = 0x4 + SO_REUSEPORT = 0x200 + SO_SNDBUF = 0x1001 + SO_SNDLOWAT = 0x1003 + SO_SNDTIMEO = 0x100b + SO_TIMESTAMP = 0x2000 + SO_TYPE = 0x1008 + SO_USELOOPBACK = 0x40 + SYSCTL_VERSION = 0x1000000 + SYSCTL_VERS_0 = 0x0 + SYSCTL_VERS_1 = 0x1000000 + SYSCTL_VERS_MASK = 0xff000000 + S_ARCH1 = 0x10000 + S_ARCH2 = 0x20000 + S_BLKSIZE = 0x200 + S_IEXEC = 0x40 + S_IFBLK = 0x6000 + S_IFCHR = 0x2000 + S_IFDIR = 0x4000 + S_IFIFO = 0x1000 + S_IFLNK = 0xa000 + S_IFMT = 0xf000 + S_IFREG = 0x8000 + S_IFSOCK = 0xc000 + S_IFWHT = 0xe000 + S_IREAD = 0x100 + S_IRGRP = 0x20 + S_IROTH = 0x4 + S_IRUSR = 0x100 + S_IRWXG = 0x38 + S_IRWXO = 0x7 + S_IRWXU = 0x1c0 + S_ISGID = 0x400 + S_ISTXT = 0x200 + S_ISUID = 0x800 + S_ISVTX = 0x200 + S_IWGRP = 0x10 + S_IWOTH = 0x2 + S_IWRITE = 0x80 + S_IWUSR = 0x80 + S_IXGRP = 0x8 + S_IXOTH = 0x1 + S_IXUSR = 0x40 + S_LOGIN_SET = 0x1 + TCIFLUSH = 0x1 + TCIOFLUSH = 0x3 + TCOFLUSH = 0x2 + TCP_CONGCTL = 0x20 + TCP_KEEPCNT = 0x6 + TCP_KEEPIDLE = 0x3 + TCP_KEEPINIT = 0x7 + TCP_KEEPINTVL = 0x5 + TCP_MAXBURST = 0x4 + TCP_MAXSEG = 0x2 + TCP_MAXWIN = 0xffff + TCP_MAX_WINSHIFT = 0xe + TCP_MD5SIG = 0x10 + TCP_MINMSS = 0xd8 + TCP_MSS = 0x218 + TCP_NODELAY = 0x1 + TCSAFLUSH = 0x2 + TIOCCBRK = 0x2000747a + TIOCCDTR = 0x20007478 + TIOCCONS = 0x80047462 + TIOCDCDTIMESTAMP = 0x40107458 + TIOCDRAIN = 0x2000745e + TIOCEXCL = 0x2000740d + TIOCEXT = 0x80047460 + TIOCFLAG_CDTRCTS = 0x10 + TIOCFLAG_CLOCAL = 0x2 + TIOCFLAG_CRTSCTS = 0x4 + TIOCFLAG_MDMBUF = 0x8 + TIOCFLAG_SOFTCAR = 0x1 + TIOCFLUSH = 0x80047410 + TIOCGETA = 0x402c7413 + TIOCGETD = 0x4004741a + TIOCGFLAGS = 0x4004745d + TIOCGLINED = 0x40207442 + TIOCGPGRP = 0x40047477 + TIOCGQSIZE = 0x40047481 + TIOCGRANTPT = 0x20007447 + TIOCGSID = 0x40047463 + TIOCGSIZE = 0x40087468 + TIOCGWINSZ = 0x40087468 + TIOCMBIC = 0x8004746b + TIOCMBIS = 0x8004746c + TIOCMGET = 0x4004746a + TIOCMSET = 0x8004746d + TIOCM_CAR = 0x40 + TIOCM_CD = 0x40 + TIOCM_CTS = 0x20 + TIOCM_DSR = 0x100 + TIOCM_DTR = 0x2 + TIOCM_LE = 0x1 + TIOCM_RI = 0x80 + TIOCM_RNG = 0x80 + TIOCM_RTS = 0x4 + TIOCM_SR = 0x10 + TIOCM_ST = 0x8 + TIOCNOTTY = 0x20007471 + TIOCNXCL = 0x2000740e + TIOCOUTQ = 0x40047473 + TIOCPKT = 0x80047470 + TIOCPKT_DATA = 0x0 + TIOCPKT_DOSTOP = 0x20 + TIOCPKT_FLUSHREAD = 0x1 + TIOCPKT_FLUSHWRITE = 0x2 + TIOCPKT_IOCTL = 0x40 + TIOCPKT_NOSTOP = 0x10 + TIOCPKT_START = 0x8 + TIOCPKT_STOP = 0x4 + TIOCPTMGET = 0x40287446 + TIOCPTSNAME = 0x40287448 + TIOCRCVFRAME = 0x80087445 + TIOCREMOTE = 0x80047469 + TIOCSBRK = 0x2000747b + TIOCSCTTY = 0x20007461 + TIOCSDTR = 0x20007479 + TIOCSETA = 0x802c7414 + TIOCSETAF = 0x802c7416 + TIOCSETAW = 0x802c7415 + TIOCSETD = 0x8004741b + TIOCSFLAGS = 0x8004745c + TIOCSIG = 0x2000745f + TIOCSLINED = 0x80207443 + TIOCSPGRP = 0x80047476 + TIOCSQSIZE = 0x80047480 + TIOCSSIZE = 0x80087467 + TIOCSTART = 0x2000746e + TIOCSTAT = 0x80047465 + TIOCSTI = 0x80017472 + TIOCSTOP = 0x2000746f + TIOCSWINSZ = 0x80087467 + TIOCUCNTL = 0x80047466 + TIOCXMTFRAME = 0x80087444 + TOSTOP = 0x400000 + VDISCARD = 0xf + VDSUSP = 0xb + VEOF = 0x0 + VEOL = 0x1 + VEOL2 = 0x2 + VERASE = 0x3 + VINTR = 0x8 + VKILL = 0x5 + VLNEXT = 0xe + VMIN = 0x10 + VQUIT = 0x9 + VREPRINT = 0x6 + VSTART = 0xc + VSTATUS = 0x12 + VSTOP = 0xd + VSUSP = 0xa + VTIME = 0x11 + VWERASE = 0x4 + WALL = 0x8 + WALLSIG = 0x8 + WALTSIG = 0x4 + WCLONE = 0x4 + WCOREFLAG = 0x80 + WNOHANG = 0x1 + WNOWAIT = 0x10000 + WNOZOMBIE = 0x20000 + WOPTSCHECKED = 0x40000 + WSTOPPED = 0x7f + WUNTRACED = 0x2 +) + +// Errors +const ( + E2BIG = syscall.Errno(0x7) + EACCES = syscall.Errno(0xd) + EADDRINUSE = syscall.Errno(0x30) + EADDRNOTAVAIL = syscall.Errno(0x31) + EAFNOSUPPORT = syscall.Errno(0x2f) + EAGAIN = syscall.Errno(0x23) + EALREADY = syscall.Errno(0x25) + EAUTH = syscall.Errno(0x50) + EBADF = syscall.Errno(0x9) + EBADMSG = syscall.Errno(0x58) + EBADRPC = syscall.Errno(0x48) + EBUSY = syscall.Errno(0x10) + ECANCELED = syscall.Errno(0x57) + ECHILD = syscall.Errno(0xa) + ECONNABORTED = syscall.Errno(0x35) + ECONNREFUSED = syscall.Errno(0x3d) + ECONNRESET = syscall.Errno(0x36) + EDEADLK = syscall.Errno(0xb) + EDESTADDRREQ = syscall.Errno(0x27) + EDOM = syscall.Errno(0x21) + EDQUOT = syscall.Errno(0x45) + EEXIST = syscall.Errno(0x11) + EFAULT = syscall.Errno(0xe) + EFBIG = syscall.Errno(0x1b) + EFTYPE = syscall.Errno(0x4f) + EHOSTDOWN = syscall.Errno(0x40) + EHOSTUNREACH = syscall.Errno(0x41) + EIDRM = syscall.Errno(0x52) + EILSEQ = syscall.Errno(0x55) + EINPROGRESS = syscall.Errno(0x24) + EINTR = syscall.Errno(0x4) + EINVAL = syscall.Errno(0x16) + EIO = syscall.Errno(0x5) + EISCONN = syscall.Errno(0x38) + EISDIR = syscall.Errno(0x15) + ELAST = syscall.Errno(0x60) + ELOOP = syscall.Errno(0x3e) + EMFILE = syscall.Errno(0x18) + EMLINK = syscall.Errno(0x1f) + EMSGSIZE = syscall.Errno(0x28) + EMULTIHOP = syscall.Errno(0x5e) + ENAMETOOLONG = syscall.Errno(0x3f) + ENEEDAUTH = syscall.Errno(0x51) + ENETDOWN = syscall.Errno(0x32) + ENETRESET = syscall.Errno(0x34) + ENETUNREACH = syscall.Errno(0x33) + ENFILE = syscall.Errno(0x17) + ENOATTR = syscall.Errno(0x5d) + ENOBUFS = syscall.Errno(0x37) + ENODATA = syscall.Errno(0x59) + ENODEV = syscall.Errno(0x13) + ENOENT = syscall.Errno(0x2) + ENOEXEC = syscall.Errno(0x8) + ENOLCK = syscall.Errno(0x4d) + ENOLINK = syscall.Errno(0x5f) + ENOMEM = syscall.Errno(0xc) + ENOMSG = syscall.Errno(0x53) + ENOPROTOOPT = syscall.Errno(0x2a) + ENOSPC = syscall.Errno(0x1c) + ENOSR = syscall.Errno(0x5a) + ENOSTR = syscall.Errno(0x5b) + ENOSYS = syscall.Errno(0x4e) + ENOTBLK = syscall.Errno(0xf) + ENOTCONN = syscall.Errno(0x39) + ENOTDIR = syscall.Errno(0x14) + ENOTEMPTY = syscall.Errno(0x42) + ENOTSOCK = syscall.Errno(0x26) + ENOTSUP = syscall.Errno(0x56) + ENOTTY = syscall.Errno(0x19) + ENXIO = syscall.Errno(0x6) + EOPNOTSUPP = syscall.Errno(0x2d) + EOVERFLOW = syscall.Errno(0x54) + EPERM = syscall.Errno(0x1) + EPFNOSUPPORT = syscall.Errno(0x2e) + EPIPE = syscall.Errno(0x20) + EPROCLIM = syscall.Errno(0x43) + EPROCUNAVAIL = syscall.Errno(0x4c) + EPROGMISMATCH = syscall.Errno(0x4b) + EPROGUNAVAIL = syscall.Errno(0x4a) + EPROTO = syscall.Errno(0x60) + EPROTONOSUPPORT = syscall.Errno(0x2b) + EPROTOTYPE = syscall.Errno(0x29) + ERANGE = syscall.Errno(0x22) + EREMOTE = syscall.Errno(0x47) + EROFS = syscall.Errno(0x1e) + ERPCMISMATCH = syscall.Errno(0x49) + ESHUTDOWN = syscall.Errno(0x3a) + ESOCKTNOSUPPORT = syscall.Errno(0x2c) + ESPIPE = syscall.Errno(0x1d) + ESRCH = syscall.Errno(0x3) + ESTALE = syscall.Errno(0x46) + ETIME = syscall.Errno(0x5c) + ETIMEDOUT = syscall.Errno(0x3c) + ETOOMANYREFS = syscall.Errno(0x3b) + ETXTBSY = syscall.Errno(0x1a) + EUSERS = syscall.Errno(0x44) + EWOULDBLOCK = syscall.Errno(0x23) + EXDEV = syscall.Errno(0x12) +) + +// Signals +const ( + SIGABRT = syscall.Signal(0x6) + SIGALRM = syscall.Signal(0xe) + SIGBUS = syscall.Signal(0xa) + SIGCHLD = syscall.Signal(0x14) + SIGCONT = syscall.Signal(0x13) + SIGEMT = syscall.Signal(0x7) + SIGFPE = syscall.Signal(0x8) + SIGHUP = syscall.Signal(0x1) + SIGILL = syscall.Signal(0x4) + SIGINFO = syscall.Signal(0x1d) + SIGINT = syscall.Signal(0x2) + SIGIO = syscall.Signal(0x17) + SIGIOT = syscall.Signal(0x6) + SIGKILL = syscall.Signal(0x9) + SIGPIPE = syscall.Signal(0xd) + SIGPROF = syscall.Signal(0x1b) + SIGPWR = syscall.Signal(0x20) + SIGQUIT = syscall.Signal(0x3) + SIGSEGV = syscall.Signal(0xb) + SIGSTOP = syscall.Signal(0x11) + SIGSYS = syscall.Signal(0xc) + SIGTERM = syscall.Signal(0xf) + SIGTRAP = syscall.Signal(0x5) + SIGTSTP = syscall.Signal(0x12) + SIGTTIN = syscall.Signal(0x15) + SIGTTOU = syscall.Signal(0x16) + SIGURG = syscall.Signal(0x10) + SIGUSR1 = syscall.Signal(0x1e) + SIGUSR2 = syscall.Signal(0x1f) + SIGVTALRM = syscall.Signal(0x1a) + SIGWINCH = syscall.Signal(0x1c) + SIGXCPU = syscall.Signal(0x18) + SIGXFSZ = syscall.Signal(0x19) +) + +// Error table +var errorList = [...]struct { + num syscall.Errno + name string + desc string +}{ + {1, "EPERM", "operation not permitted"}, + {2, "ENOENT", "no such file or directory"}, + {3, "ESRCH", "no such process"}, + {4, "EINTR", "interrupted system call"}, + {5, "EIO", "input/output error"}, + {6, "ENXIO", "device not configured"}, + {7, "E2BIG", "argument list too long"}, + {8, "ENOEXEC", "exec format error"}, + {9, "EBADF", "bad file descriptor"}, + {10, "ECHILD", "no child processes"}, + {11, "EDEADLK", "resource deadlock avoided"}, + {12, "ENOMEM", "cannot allocate memory"}, + {13, "EACCES", "permission denied"}, + {14, "EFAULT", "bad address"}, + {15, "ENOTBLK", "block device required"}, + {16, "EBUSY", "device busy"}, + {17, "EEXIST", "file exists"}, + {18, "EXDEV", "cross-device link"}, + {19, "ENODEV", "operation not supported by device"}, + {20, "ENOTDIR", "not a directory"}, + {21, "EISDIR", "is a directory"}, + {22, "EINVAL", "invalid argument"}, + {23, "ENFILE", "too many open files in system"}, + {24, "EMFILE", "too many open files"}, + {25, "ENOTTY", "inappropriate ioctl for device"}, + {26, "ETXTBSY", "text file busy"}, + {27, "EFBIG", "file too large"}, + {28, "ENOSPC", "no space left on device"}, + {29, "ESPIPE", "illegal seek"}, + {30, "EROFS", "read-only file system"}, + {31, "EMLINK", "too many links"}, + {32, "EPIPE", "broken pipe"}, + {33, "EDOM", "numerical argument out of domain"}, + {34, "ERANGE", "result too large or too small"}, + {35, "EAGAIN", "resource temporarily unavailable"}, + {36, "EINPROGRESS", "operation now in progress"}, + {37, "EALREADY", "operation already in progress"}, + {38, "ENOTSOCK", "socket operation on non-socket"}, + {39, "EDESTADDRREQ", "destination address required"}, + {40, "EMSGSIZE", "message too long"}, + {41, "EPROTOTYPE", "protocol wrong type for socket"}, + {42, "ENOPROTOOPT", "protocol option not available"}, + {43, "EPROTONOSUPPORT", "protocol not supported"}, + {44, "ESOCKTNOSUPPORT", "socket type not supported"}, + {45, "EOPNOTSUPP", "operation not supported"}, + {46, "EPFNOSUPPORT", "protocol family not supported"}, + {47, "EAFNOSUPPORT", "address family not supported by protocol family"}, + {48, "EADDRINUSE", "address already in use"}, + {49, "EADDRNOTAVAIL", "can't assign requested address"}, + {50, "ENETDOWN", "network is down"}, + {51, "ENETUNREACH", "network is unreachable"}, + {52, "ENETRESET", "network dropped connection on reset"}, + {53, "ECONNABORTED", "software caused connection abort"}, + {54, "ECONNRESET", "connection reset by peer"}, + {55, "ENOBUFS", "no buffer space available"}, + {56, "EISCONN", "socket is already connected"}, + {57, "ENOTCONN", "socket is not connected"}, + {58, "ESHUTDOWN", "can't send after socket shutdown"}, + {59, "ETOOMANYREFS", "too many references: can't splice"}, + {60, "ETIMEDOUT", "connection timed out"}, + {61, "ECONNREFUSED", "connection refused"}, + {62, "ELOOP", "too many levels of symbolic links"}, + {63, "ENAMETOOLONG", "file name too long"}, + {64, "EHOSTDOWN", "host is down"}, + {65, "EHOSTUNREACH", "no route to host"}, + {66, "ENOTEMPTY", "directory not empty"}, + {67, "EPROCLIM", "too many processes"}, + {68, "EUSERS", "too many users"}, + {69, "EDQUOT", "disc quota exceeded"}, + {70, "ESTALE", "stale NFS file handle"}, + {71, "EREMOTE", "too many levels of remote in path"}, + {72, "EBADRPC", "RPC struct is bad"}, + {73, "ERPCMISMATCH", "RPC version wrong"}, + {74, "EPROGUNAVAIL", "RPC prog. not avail"}, + {75, "EPROGMISMATCH", "program version wrong"}, + {76, "EPROCUNAVAIL", "bad procedure for program"}, + {77, "ENOLCK", "no locks available"}, + {78, "ENOSYS", "function not implemented"}, + {79, "EFTYPE", "inappropriate file type or format"}, + {80, "EAUTH", "authentication error"}, + {81, "ENEEDAUTH", "need authenticator"}, + {82, "EIDRM", "identifier removed"}, + {83, "ENOMSG", "no message of desired type"}, + {84, "EOVERFLOW", "value too large to be stored in data type"}, + {85, "EILSEQ", "illegal byte sequence"}, + {86, "ENOTSUP", "not supported"}, + {87, "ECANCELED", "operation Canceled"}, + {88, "EBADMSG", "bad or Corrupt message"}, + {89, "ENODATA", "no message available"}, + {90, "ENOSR", "no STREAM resources"}, + {91, "ENOSTR", "not a STREAM"}, + {92, "ETIME", "STREAM ioctl timeout"}, + {93, "ENOATTR", "attribute not found"}, + {94, "EMULTIHOP", "multihop attempted"}, + {95, "ENOLINK", "link has been severed"}, + {96, "ELAST", "protocol error"}, +} + +// Signal table +var signalList = [...]struct { + num syscall.Signal + name string + desc string +}{ + {1, "SIGHUP", "hangup"}, + {2, "SIGINT", "interrupt"}, + {3, "SIGQUIT", "quit"}, + {4, "SIGILL", "illegal instruction"}, + {5, "SIGTRAP", "trace/BPT trap"}, + {6, "SIGIOT", "abort trap"}, + {7, "SIGEMT", "EMT trap"}, + {8, "SIGFPE", "floating point exception"}, + {9, "SIGKILL", "killed"}, + {10, "SIGBUS", "bus error"}, + {11, "SIGSEGV", "segmentation fault"}, + {12, "SIGSYS", "bad system call"}, + {13, "SIGPIPE", "broken pipe"}, + {14, "SIGALRM", "alarm clock"}, + {15, "SIGTERM", "terminated"}, + {16, "SIGURG", "urgent I/O condition"}, + {17, "SIGSTOP", "stopped (signal)"}, + {18, "SIGTSTP", "stopped"}, + {19, "SIGCONT", "continued"}, + {20, "SIGCHLD", "child exited"}, + {21, "SIGTTIN", "stopped (tty input)"}, + {22, "SIGTTOU", "stopped (tty output)"}, + {23, "SIGIO", "I/O possible"}, + {24, "SIGXCPU", "cputime limit exceeded"}, + {25, "SIGXFSZ", "filesize limit exceeded"}, + {26, "SIGVTALRM", "virtual timer expired"}, + {27, "SIGPROF", "profiling timer expired"}, + {28, "SIGWINCH", "window size changes"}, + {29, "SIGINFO", "information request"}, + {30, "SIGUSR1", "user defined signal 1"}, + {31, "SIGUSR2", "user defined signal 2"}, + {32, "SIGPWR", "power fail/restart"}, +} diff --git a/vendor/golang.org/x/sys/unix/zerrors_openbsd_386.go b/vendor/golang.org/x/sys/unix/zerrors_openbsd_386.go index 3322e998d3..d8be045189 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_openbsd_386.go +++ b/vendor/golang.org/x/sys/unix/zerrors_openbsd_386.go @@ -1,5 +1,5 @@ // mkerrors.sh -m32 -// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// Code generated by the command above; see README.md. DO NOT EDIT. // +build 386,openbsd @@ -147,6 +147,7 @@ const ( CFLUSH = 0xf CLOCAL = 0x8000 CREAD = 0x800 + CRTSCTS = 0x10000 CS5 = 0x0 CS6 = 0x100 CS7 = 0x200 @@ -157,6 +158,8 @@ const ( CSTOP = 0x13 CSTOPB = 0x400 CSUSP = 0x1a + CTL_HW = 0x6 + CTL_KERN = 0x1 CTL_MAXNAME = 0xc CTL_NET = 0x4 DIOCOSFPFLUSH = 0x2000444e @@ -442,6 +445,7 @@ const ( F_UNLCK = 0x2 F_WRLCK = 0x3 HUPCL = 0x4000 + HW_MACHINE = 0x1 ICANON = 0x100 ICMP6_FILTER = 0x12 ICRNL = 0x100 @@ -860,6 +864,10 @@ const ( IXANY = 0x800 IXOFF = 0x400 IXON = 0x200 + KERN_HOSTNAME = 0xa + KERN_OSRELEASE = 0x2 + KERN_OSTYPE = 0x1 + KERN_VERSION = 0x4 LCNT_OVERLOAD_FLUSH = 0x6 LOCK_EX = 0x2 LOCK_NB = 0x4 @@ -891,6 +899,32 @@ const ( MAP_TRYFIXED = 0x400 MCL_CURRENT = 0x1 MCL_FUTURE = 0x2 + MNT_ASYNC = 0x40 + MNT_DEFEXPORTED = 0x200 + MNT_DELEXPORT = 0x20000 + MNT_DOOMED = 0x8000000 + MNT_EXPORTANON = 0x400 + MNT_EXPORTED = 0x100 + MNT_EXRDONLY = 0x80 + MNT_FORCE = 0x80000 + MNT_LAZY = 0x3 + MNT_LOCAL = 0x1000 + MNT_NOATIME = 0x8000 + MNT_NODEV = 0x10 + MNT_NOEXEC = 0x4 + MNT_NOSUID = 0x8 + MNT_NOWAIT = 0x2 + MNT_QUOTA = 0x2000 + MNT_RDONLY = 0x1 + MNT_RELOAD = 0x40000 + MNT_ROOTFS = 0x4000 + MNT_SOFTDEP = 0x4000000 + MNT_SYNCHRONOUS = 0x2 + MNT_UPDATE = 0x10000 + MNT_VISFLAGMASK = 0x400ffff + MNT_WAIT = 0x1 + MNT_WANTRDWR = 0x2000000 + MNT_WXALLOWED = 0x800 MSG_BCAST = 0x100 MSG_CTRUNC = 0x20 MSG_DONTROUTE = 0x4 @@ -1210,6 +1244,34 @@ const ( SO_TIMESTAMP = 0x800 SO_TYPE = 0x1008 SO_USELOOPBACK = 0x40 + S_BLKSIZE = 0x200 + S_IEXEC = 0x40 + S_IFBLK = 0x6000 + S_IFCHR = 0x2000 + S_IFDIR = 0x4000 + S_IFIFO = 0x1000 + S_IFLNK = 0xa000 + S_IFMT = 0xf000 + S_IFREG = 0x8000 + S_IFSOCK = 0xc000 + S_IREAD = 0x100 + S_IRGRP = 0x20 + S_IROTH = 0x4 + S_IRUSR = 0x100 + S_IRWXG = 0x38 + S_IRWXO = 0x7 + S_IRWXU = 0x1c0 + S_ISGID = 0x400 + S_ISTXT = 0x200 + S_ISUID = 0x800 + S_ISVTX = 0x200 + S_IWGRP = 0x10 + S_IWOTH = 0x2 + S_IWRITE = 0x80 + S_IWUSR = 0x80 + S_IXGRP = 0x8 + S_IXOTH = 0x1 + S_IXUSR = 0x40 TCIFLUSH = 0x1 TCIOFLUSH = 0x3 TCOFLUSH = 0x2 @@ -1453,132 +1515,140 @@ const ( ) // Error table -var errors = [...]string{ - 1: "operation not permitted", - 2: "no such file or directory", - 3: "no such process", - 4: "interrupted system call", - 5: "input/output error", - 6: "device not configured", - 7: "argument list too long", - 8: "exec format error", - 9: "bad file descriptor", - 10: "no child processes", - 11: "resource deadlock avoided", - 12: "cannot allocate memory", - 13: "permission denied", - 14: "bad address", - 15: "block device required", - 16: "device busy", - 17: "file exists", - 18: "cross-device link", - 19: "operation not supported by device", - 20: "not a directory", - 21: "is a directory", - 22: "invalid argument", - 23: "too many open files in system", - 24: "too many open files", - 25: "inappropriate ioctl for device", - 26: "text file busy", - 27: "file too large", - 28: "no space left on device", - 29: "illegal seek", - 30: "read-only file system", - 31: "too many links", - 32: "broken pipe", - 33: "numerical argument out of domain", - 34: "result too large", - 35: "resource temporarily unavailable", - 36: "operation now in progress", - 37: "operation already in progress", - 38: "socket operation on non-socket", - 39: "destination address required", - 40: "message too long", - 41: "protocol wrong type for socket", - 42: "protocol not available", - 43: "protocol not supported", - 44: "socket type not supported", - 45: "operation not supported", - 46: "protocol family not supported", - 47: "address family not supported by protocol family", - 48: "address already in use", - 49: "can't assign requested address", - 50: "network is down", - 51: "network is unreachable", - 52: "network dropped connection on reset", - 53: "software caused connection abort", - 54: "connection reset by peer", - 55: "no buffer space available", - 56: "socket is already connected", - 57: "socket is not connected", - 58: "can't send after socket shutdown", - 59: "too many references: can't splice", - 60: "connection timed out", - 61: "connection refused", - 62: "too many levels of symbolic links", - 63: "file name too long", - 64: "host is down", - 65: "no route to host", - 66: "directory not empty", - 67: "too many processes", - 68: "too many users", - 69: "disc quota exceeded", - 70: "stale NFS file handle", - 71: "too many levels of remote in path", - 72: "RPC struct is bad", - 73: "RPC version wrong", - 74: "RPC prog. not avail", - 75: "program version wrong", - 76: "bad procedure for program", - 77: "no locks available", - 78: "function not implemented", - 79: "inappropriate file type or format", - 80: "authentication error", - 81: "need authenticator", - 82: "IPsec processing failure", - 83: "attribute not found", - 84: "illegal byte sequence", - 85: "no medium found", - 86: "wrong medium type", - 87: "value too large to be stored in data type", - 88: "operation canceled", - 89: "identifier removed", - 90: "no message of desired type", - 91: "not supported", +var errorList = [...]struct { + num syscall.Errno + name string + desc string +}{ + {1, "EPERM", "operation not permitted"}, + {2, "ENOENT", "no such file or directory"}, + {3, "ESRCH", "no such process"}, + {4, "EINTR", "interrupted system call"}, + {5, "EIO", "input/output error"}, + {6, "ENXIO", "device not configured"}, + {7, "E2BIG", "argument list too long"}, + {8, "ENOEXEC", "exec format error"}, + {9, "EBADF", "bad file descriptor"}, + {10, "ECHILD", "no child processes"}, + {11, "EDEADLK", "resource deadlock avoided"}, + {12, "ENOMEM", "cannot allocate memory"}, + {13, "EACCES", "permission denied"}, + {14, "EFAULT", "bad address"}, + {15, "ENOTBLK", "block device required"}, + {16, "EBUSY", "device busy"}, + {17, "EEXIST", "file exists"}, + {18, "EXDEV", "cross-device link"}, + {19, "ENODEV", "operation not supported by device"}, + {20, "ENOTDIR", "not a directory"}, + {21, "EISDIR", "is a directory"}, + {22, "EINVAL", "invalid argument"}, + {23, "ENFILE", "too many open files in system"}, + {24, "EMFILE", "too many open files"}, + {25, "ENOTTY", "inappropriate ioctl for device"}, + {26, "ETXTBSY", "text file busy"}, + {27, "EFBIG", "file too large"}, + {28, "ENOSPC", "no space left on device"}, + {29, "ESPIPE", "illegal seek"}, + {30, "EROFS", "read-only file system"}, + {31, "EMLINK", "too many links"}, + {32, "EPIPE", "broken pipe"}, + {33, "EDOM", "numerical argument out of domain"}, + {34, "ERANGE", "result too large"}, + {35, "EWOULDBLOCK", "resource temporarily unavailable"}, + {36, "EINPROGRESS", "operation now in progress"}, + {37, "EALREADY", "operation already in progress"}, + {38, "ENOTSOCK", "socket operation on non-socket"}, + {39, "EDESTADDRREQ", "destination address required"}, + {40, "EMSGSIZE", "message too long"}, + {41, "EPROTOTYPE", "protocol wrong type for socket"}, + {42, "ENOPROTOOPT", "protocol not available"}, + {43, "EPROTONOSUPPORT", "protocol not supported"}, + {44, "ESOCKTNOSUPPORT", "socket type not supported"}, + {45, "EOPNOTSUPP", "operation not supported"}, + {46, "EPFNOSUPPORT", "protocol family not supported"}, + {47, "EAFNOSUPPORT", "address family not supported by protocol family"}, + {48, "EADDRINUSE", "address already in use"}, + {49, "EADDRNOTAVAIL", "can't assign requested address"}, + {50, "ENETDOWN", "network is down"}, + {51, "ENETUNREACH", "network is unreachable"}, + {52, "ENETRESET", "network dropped connection on reset"}, + {53, "ECONNABORTED", "software caused connection abort"}, + {54, "ECONNRESET", "connection reset by peer"}, + {55, "ENOBUFS", "no buffer space available"}, + {56, "EISCONN", "socket is already connected"}, + {57, "ENOTCONN", "socket is not connected"}, + {58, "ESHUTDOWN", "can't send after socket shutdown"}, + {59, "ETOOMANYREFS", "too many references: can't splice"}, + {60, "ETIMEDOUT", "operation timed out"}, + {61, "ECONNREFUSED", "connection refused"}, + {62, "ELOOP", "too many levels of symbolic links"}, + {63, "ENAMETOOLONG", "file name too long"}, + {64, "EHOSTDOWN", "host is down"}, + {65, "EHOSTUNREACH", "no route to host"}, + {66, "ENOTEMPTY", "directory not empty"}, + {67, "EPROCLIM", "too many processes"}, + {68, "EUSERS", "too many users"}, + {69, "EDQUOT", "disk quota exceeded"}, + {70, "ESTALE", "stale NFS file handle"}, + {71, "EREMOTE", "too many levels of remote in path"}, + {72, "EBADRPC", "RPC struct is bad"}, + {73, "ERPCMISMATCH", "RPC version wrong"}, + {74, "EPROGUNAVAIL", "RPC program not available"}, + {75, "EPROGMISMATCH", "program version wrong"}, + {76, "EPROCUNAVAIL", "bad procedure for program"}, + {77, "ENOLCK", "no locks available"}, + {78, "ENOSYS", "function not implemented"}, + {79, "EFTYPE", "inappropriate file type or format"}, + {80, "EAUTH", "authentication error"}, + {81, "ENEEDAUTH", "need authenticator"}, + {82, "EIPSEC", "IPsec processing failure"}, + {83, "ENOATTR", "attribute not found"}, + {84, "EILSEQ", "illegal byte sequence"}, + {85, "ENOMEDIUM", "no medium found"}, + {86, "EMEDIUMTYPE", "wrong medium type"}, + {87, "EOVERFLOW", "value too large to be stored in data type"}, + {88, "ECANCELED", "operation canceled"}, + {89, "EIDRM", "identifier removed"}, + {90, "ENOMSG", "no message of desired type"}, + {91, "ELAST", "not supported"}, } // Signal table -var signals = [...]string{ - 1: "hangup", - 2: "interrupt", - 3: "quit", - 4: "illegal instruction", - 5: "trace/BPT trap", - 6: "abort trap", - 7: "EMT trap", - 8: "floating point exception", - 9: "killed", - 10: "bus error", - 11: "segmentation fault", - 12: "bad system call", - 13: "broken pipe", - 14: "alarm clock", - 15: "terminated", - 16: "urgent I/O condition", - 17: "stopped (signal)", - 18: "stopped", - 19: "continued", - 20: "child exited", - 21: "stopped (tty input)", - 22: "stopped (tty output)", - 23: "I/O possible", - 24: "cputime limit exceeded", - 25: "filesize limit exceeded", - 26: "virtual timer expired", - 27: "profiling timer expired", - 28: "window size changes", - 29: "information request", - 30: "user defined signal 1", - 31: "user defined signal 2", - 32: "thread AST", +var signalList = [...]struct { + num syscall.Signal + name string + desc string +}{ + {1, "SIGHUP", "hangup"}, + {2, "SIGINT", "interrupt"}, + {3, "SIGQUIT", "quit"}, + {4, "SIGILL", "illegal instruction"}, + {5, "SIGTRAP", "trace/BPT trap"}, + {6, "SIGABRT", "abort trap"}, + {7, "SIGEMT", "EMT trap"}, + {8, "SIGFPE", "floating point exception"}, + {9, "SIGKILL", "killed"}, + {10, "SIGBUS", "bus error"}, + {11, "SIGSEGV", "segmentation fault"}, + {12, "SIGSYS", "bad system call"}, + {13, "SIGPIPE", "broken pipe"}, + {14, "SIGALRM", "alarm clock"}, + {15, "SIGTERM", "terminated"}, + {16, "SIGURG", "urgent I/O condition"}, + {17, "SIGSTOP", "suspended (signal)"}, + {18, "SIGTSTP", "suspended"}, + {19, "SIGCONT", "continued"}, + {20, "SIGCHLD", "child exited"}, + {21, "SIGTTIN", "stopped (tty input)"}, + {22, "SIGTTOU", "stopped (tty output)"}, + {23, "SIGIO", "I/O possible"}, + {24, "SIGXCPU", "cputime limit exceeded"}, + {25, "SIGXFSZ", "filesize limit exceeded"}, + {26, "SIGVTALRM", "virtual timer expired"}, + {27, "SIGPROF", "profiling timer expired"}, + {28, "SIGWINCH", "window size changes"}, + {29, "SIGINFO", "information request"}, + {30, "SIGUSR1", "user defined signal 1"}, + {31, "SIGUSR2", "user defined signal 2"}, + {32, "SIGTHR", "thread AST"}, } diff --git a/vendor/golang.org/x/sys/unix/zerrors_openbsd_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_openbsd_amd64.go index 1758ecca93..1f9e8a29ea 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_openbsd_amd64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_openbsd_amd64.go @@ -1,5 +1,5 @@ // mkerrors.sh -m64 -// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// Code generated by the command above; see README.md. DO NOT EDIT. // +build amd64,openbsd @@ -45,6 +45,7 @@ const ( AF_SNA = 0xb AF_UNIX = 0x1 AF_UNSPEC = 0x0 + ALTWERASE = 0x200 ARPHRD_ETHER = 0x1 ARPHRD_FRELAY = 0xf ARPHRD_IEEE1394 = 0x18 @@ -146,7 +147,14 @@ const ( BRKINT = 0x2 CFLUSH = 0xf CLOCAL = 0x8000 + CLOCK_BOOTTIME = 0x6 + CLOCK_MONOTONIC = 0x3 + CLOCK_PROCESS_CPUTIME_ID = 0x2 + CLOCK_REALTIME = 0x0 + CLOCK_THREAD_CPUTIME_ID = 0x4 + CLOCK_UPTIME = 0x5 CREAD = 0x800 + CRTSCTS = 0x10000 CS5 = 0x0 CS6 = 0x100 CS7 = 0x200 @@ -157,6 +165,8 @@ const ( CSTOP = 0x13 CSTOPB = 0x400 CSUSP = 0x1a + CTL_HW = 0x6 + CTL_KERN = 0x1 CTL_MAXNAME = 0xc CTL_NET = 0x4 DIOCOSFPFLUSH = 0x2000444e @@ -175,6 +185,7 @@ const ( DLT_LOOP = 0xc DLT_MPLS = 0xdb DLT_NULL = 0x0 + DLT_OPENFLOW = 0x10b DLT_PFLOG = 0x75 DLT_PFSYNC = 0x12 DLT_PPP = 0x9 @@ -185,6 +196,23 @@ const ( DLT_RAW = 0xe DLT_SLIP = 0x8 DLT_SLIP_BSDOS = 0xf + DLT_USBPCAP = 0xf9 + DLT_USER0 = 0x93 + DLT_USER1 = 0x94 + DLT_USER10 = 0x9d + DLT_USER11 = 0x9e + DLT_USER12 = 0x9f + DLT_USER13 = 0xa0 + DLT_USER14 = 0xa1 + DLT_USER15 = 0xa2 + DLT_USER2 = 0x95 + DLT_USER3 = 0x96 + DLT_USER4 = 0x97 + DLT_USER5 = 0x98 + DLT_USER6 = 0x99 + DLT_USER7 = 0x9a + DLT_USER8 = 0x9b + DLT_USER9 = 0x9c DT_BLK = 0x6 DT_CHR = 0x2 DT_DIR = 0x4 @@ -398,27 +426,38 @@ const ( ETHER_CRC_POLY_LE = 0xedb88320 ETHER_HDR_LEN = 0xe ETHER_MAX_DIX_LEN = 0x600 + ETHER_MAX_HARDMTU_LEN = 0xff9b ETHER_MAX_LEN = 0x5ee ETHER_MIN_LEN = 0x40 ETHER_TYPE_LEN = 0x2 ETHER_VLAN_ENCAP_LEN = 0x4 EVFILT_AIO = -0x3 + EVFILT_DEVICE = -0x8 EVFILT_PROC = -0x5 EVFILT_READ = -0x1 EVFILT_SIGNAL = -0x6 - EVFILT_SYSCOUNT = 0x7 + EVFILT_SYSCOUNT = 0x8 EVFILT_TIMER = -0x7 EVFILT_VNODE = -0x4 EVFILT_WRITE = -0x2 + EVL_ENCAPLEN = 0x4 + EVL_PRIO_BITS = 0xd + EVL_PRIO_MAX = 0x7 + EVL_VLID_MASK = 0xfff + EVL_VLID_MAX = 0xffe + EVL_VLID_MIN = 0x1 + EVL_VLID_NULL = 0x0 EV_ADD = 0x1 EV_CLEAR = 0x20 EV_DELETE = 0x2 EV_DISABLE = 0x8 + EV_DISPATCH = 0x80 EV_ENABLE = 0x4 EV_EOF = 0x8000 EV_ERROR = 0x4000 EV_FLAG1 = 0x2000 EV_ONESHOT = 0x10 + EV_RECEIPT = 0x40 EV_SYSFLAGS = 0xf000 EXTA = 0x4b00 EXTB = 0x9600 @@ -432,6 +471,7 @@ const ( F_GETFL = 0x3 F_GETLK = 0x7 F_GETOWN = 0x5 + F_ISATTY = 0xb F_OK = 0x0 F_RDLCK = 0x1 F_SETFD = 0x2 @@ -442,13 +482,13 @@ const ( F_UNLCK = 0x2 F_WRLCK = 0x3 HUPCL = 0x4000 + HW_MACHINE = 0x1 ICANON = 0x100 ICMP6_FILTER = 0x12 ICRNL = 0x100 IEXTEN = 0x400 IFAN_ARRIVAL = 0x0 IFAN_DEPARTURE = 0x1 - IFA_ROUTE = 0x1 IFF_ALLMULTI = 0x200 IFF_BROADCAST = 0x2 IFF_CANTCHANGE = 0x8e52 @@ -459,12 +499,12 @@ const ( IFF_LOOPBACK = 0x8 IFF_MULTICAST = 0x8000 IFF_NOARP = 0x80 - IFF_NOTRAILERS = 0x20 IFF_OACTIVE = 0x400 IFF_POINTOPOINT = 0x10 IFF_PROMISC = 0x100 IFF_RUNNING = 0x40 IFF_SIMPLEX = 0x800 + IFF_STATICARP = 0x20 IFF_UP = 0x1 IFNAMSIZ = 0x10 IFT_1822 = 0x2 @@ -593,6 +633,7 @@ const ( IFT_LINEGROUP = 0xd2 IFT_LOCALTALK = 0x2a IFT_LOOP = 0x18 + IFT_MBIM = 0xfa IFT_MEDIAMAILOVERIP = 0x8b IFT_MFSIGLINK = 0xa7 IFT_MIOX25 = 0x26 @@ -717,8 +758,6 @@ const ( IPPROTO_AH = 0x33 IPPROTO_CARP = 0x70 IPPROTO_DIVERT = 0x102 - IPPROTO_DIVERT_INIT = 0x2 - IPPROTO_DIVERT_RESP = 0x1 IPPROTO_DONE = 0x101 IPPROTO_DSTOPTS = 0x3c IPPROTO_EGP = 0x8 @@ -775,6 +814,7 @@ const ( IPV6_LEAVE_GROUP = 0xd IPV6_MAXHLIM = 0xff IPV6_MAXPACKET = 0xffff + IPV6_MINHOPCOUNT = 0x41 IPV6_MMTU = 0x500 IPV6_MULTICAST_HOPS = 0xa IPV6_MULTICAST_IF = 0x9 @@ -814,12 +854,12 @@ const ( IP_DEFAULT_MULTICAST_LOOP = 0x1 IP_DEFAULT_MULTICAST_TTL = 0x1 IP_DF = 0x4000 - IP_DIVERTFL = 0x1022 IP_DROP_MEMBERSHIP = 0xd IP_ESP_NETWORK_LEVEL = 0x16 IP_ESP_TRANS_LEVEL = 0x15 IP_HDRINCL = 0x2 IP_IPCOMP_LEVEL = 0x1d + IP_IPDEFTTL = 0x25 IP_IPSECFLOWINFO = 0x24 IP_IPSEC_LOCAL_AUTH = 0x1b IP_IPSEC_LOCAL_CRED = 0x19 @@ -853,13 +893,19 @@ const ( IP_RETOPTS = 0x8 IP_RF = 0x8000 IP_RTABLE = 0x1021 + IP_SENDSRCADDR = 0x7 IP_TOS = 0x3 IP_TTL = 0x4 ISIG = 0x80 ISTRIP = 0x20 + IUCLC = 0x1000 IXANY = 0x800 IXOFF = 0x400 IXON = 0x200 + KERN_HOSTNAME = 0xa + KERN_OSRELEASE = 0x2 + KERN_OSTYPE = 0x1 + KERN_VERSION = 0x4 LCNT_OVERLOAD_FLUSH = 0x6 LOCK_EX = 0x2 LOCK_NB = 0x4 @@ -873,25 +919,56 @@ const ( MADV_SPACEAVAIL = 0x5 MADV_WILLNEED = 0x3 MAP_ANON = 0x1000 - MAP_COPY = 0x4 + MAP_ANONYMOUS = 0x1000 + MAP_COPY = 0x2 MAP_FILE = 0x0 MAP_FIXED = 0x10 - MAP_FLAGMASK = 0x1ff7 - MAP_HASSEMAPHORE = 0x200 - MAP_INHERIT = 0x80 + MAP_FLAGMASK = 0x7ff7 + MAP_HASSEMAPHORE = 0x0 + MAP_INHERIT = 0x0 MAP_INHERIT_COPY = 0x1 - MAP_INHERIT_DONATE_COPY = 0x3 MAP_INHERIT_NONE = 0x2 MAP_INHERIT_SHARE = 0x0 - MAP_NOEXTEND = 0x100 - MAP_NORESERVE = 0x40 + MAP_INHERIT_ZERO = 0x3 + MAP_NOEXTEND = 0x0 + MAP_NORESERVE = 0x0 MAP_PRIVATE = 0x2 - MAP_RENAME = 0x20 + MAP_RENAME = 0x0 MAP_SHARED = 0x1 - MAP_TRYFIXED = 0x400 + MAP_STACK = 0x4000 + MAP_TRYFIXED = 0x0 MCL_CURRENT = 0x1 MCL_FUTURE = 0x2 + MNT_ASYNC = 0x40 + MNT_DEFEXPORTED = 0x200 + MNT_DELEXPORT = 0x20000 + MNT_DOOMED = 0x8000000 + MNT_EXPORTANON = 0x400 + MNT_EXPORTED = 0x100 + MNT_EXRDONLY = 0x80 + MNT_FORCE = 0x80000 + MNT_LAZY = 0x3 + MNT_LOCAL = 0x1000 + MNT_NOATIME = 0x8000 + MNT_NODEV = 0x10 + MNT_NOEXEC = 0x4 + MNT_NOPERM = 0x20 + MNT_NOSUID = 0x8 + MNT_NOWAIT = 0x2 + MNT_QUOTA = 0x2000 + MNT_RDONLY = 0x1 + MNT_RELOAD = 0x40000 + MNT_ROOTFS = 0x4000 + MNT_SOFTDEP = 0x4000000 + MNT_STALLED = 0x100000 + MNT_SYNCHRONOUS = 0x2 + MNT_UPDATE = 0x10000 + MNT_VISFLAGMASK = 0x400ffff + MNT_WAIT = 0x1 + MNT_WANTRDWR = 0x2000000 + MNT_WXALLOWED = 0x800 MSG_BCAST = 0x100 + MSG_CMSG_CLOEXEC = 0x800 MSG_CTRUNC = 0x20 MSG_DONTROUTE = 0x4 MSG_DONTWAIT = 0x80 @@ -909,11 +986,14 @@ const ( NET_RT_DUMP = 0x1 NET_RT_FLAGS = 0x2 NET_RT_IFLIST = 0x3 - NET_RT_MAXID = 0x6 + NET_RT_IFNAMES = 0x6 + NET_RT_MAXID = 0x7 NET_RT_STATS = 0x4 NET_RT_TABLE = 0x5 NOFLSH = 0x80000000 + NOKERNINFO = 0x2000000 NOTE_ATTRIB = 0x8 + NOTE_CHANGE = 0x1 NOTE_CHILD = 0x4 NOTE_DELETE = 0x1 NOTE_EOF = 0x2 @@ -932,11 +1012,13 @@ const ( NOTE_TRUNCATE = 0x80 NOTE_WRITE = 0x2 OCRNL = 0x10 + OLCUC = 0x20 ONLCR = 0x2 ONLRET = 0x80 ONOCR = 0x40 ONOEOT = 0x8 OPOST = 0x1 + OXTABS = 0x4 O_ACCMODE = 0x3 O_APPEND = 0x8 O_ASYNC = 0x40 @@ -974,23 +1056,32 @@ const ( RLIMIT_CPU = 0x0 RLIMIT_DATA = 0x2 RLIMIT_FSIZE = 0x1 + RLIMIT_MEMLOCK = 0x6 RLIMIT_NOFILE = 0x8 + RLIMIT_NPROC = 0x7 + RLIMIT_RSS = 0x5 RLIMIT_STACK = 0x3 RLIM_INFINITY = 0x7fffffffffffffff RTAX_AUTHOR = 0x6 + RTAX_BFD = 0xb RTAX_BRD = 0x7 + RTAX_DNS = 0xc RTAX_DST = 0x0 RTAX_GATEWAY = 0x1 RTAX_GENMASK = 0x3 RTAX_IFA = 0x5 RTAX_IFP = 0x4 RTAX_LABEL = 0xa - RTAX_MAX = 0xb + RTAX_MAX = 0xf RTAX_NETMASK = 0x2 + RTAX_SEARCH = 0xe RTAX_SRC = 0x8 RTAX_SRCMASK = 0x9 + RTAX_STATIC = 0xd RTA_AUTHOR = 0x40 + RTA_BFD = 0x800 RTA_BRD = 0x80 + RTA_DNS = 0x1000 RTA_DST = 0x1 RTA_GATEWAY = 0x2 RTA_GENMASK = 0x8 @@ -998,34 +1089,39 @@ const ( RTA_IFP = 0x10 RTA_LABEL = 0x400 RTA_NETMASK = 0x4 + RTA_SEARCH = 0x4000 RTA_SRC = 0x100 RTA_SRCMASK = 0x200 + RTA_STATIC = 0x2000 RTF_ANNOUNCE = 0x4000 + RTF_BFD = 0x1000000 RTF_BLACKHOLE = 0x1000 + RTF_BROADCAST = 0x400000 + RTF_CACHED = 0x20000 RTF_CLONED = 0x10000 RTF_CLONING = 0x100 + RTF_CONNECTED = 0x800000 RTF_DONE = 0x40 RTF_DYNAMIC = 0x10 - RTF_FMASK = 0x10f808 + RTF_FMASK = 0x110fc08 RTF_GATEWAY = 0x2 RTF_HOST = 0x4 RTF_LLINFO = 0x400 - RTF_MASK = 0x80 + RTF_LOCAL = 0x200000 RTF_MODIFIED = 0x20 RTF_MPATH = 0x40000 RTF_MPLS = 0x100000 + RTF_MULTICAST = 0x200 RTF_PERMANENT_ARP = 0x2000 RTF_PROTO1 = 0x8000 RTF_PROTO2 = 0x4000 RTF_PROTO3 = 0x2000 RTF_REJECT = 0x8 - RTF_SOURCE = 0x20000 RTF_STATIC = 0x800 - RTF_TUNNEL = 0x100000 RTF_UP = 0x1 RTF_USETRAILERS = 0x8000 - RTF_XRESOLVE = 0x200 RTM_ADD = 0x1 + RTM_BFD = 0x12 RTM_CHANGE = 0x3 RTM_DELADDR = 0xd RTM_DELETE = 0x2 @@ -1033,11 +1129,13 @@ const ( RTM_GET = 0x4 RTM_IFANNOUNCE = 0xf RTM_IFINFO = 0xe + RTM_INVALIDATE = 0x11 RTM_LOCK = 0x8 RTM_LOSING = 0x5 RTM_MAXSIZE = 0x800 RTM_MISS = 0x7 RTM_NEWADDR = 0xc + RTM_PROPOSAL = 0x13 RTM_REDIRECT = 0x6 RTM_RESOLVE = 0xb RTM_RTTUNIT = 0xf4240 @@ -1050,6 +1148,8 @@ const ( RTV_RTTVAR = 0x80 RTV_SPIPE = 0x10 RTV_SSTHRESH = 0x20 + RT_TABLEID_BITS = 0x8 + RT_TABLEID_MASK = 0xff RT_TABLEID_MAX = 0xff RUSAGE_CHILDREN = -0x1 RUSAGE_SELF = 0x0 @@ -1062,55 +1162,55 @@ const ( SIOCADDMULTI = 0x80206931 SIOCAIFADDR = 0x8040691a SIOCAIFGROUP = 0x80286987 - SIOCALIFADDR = 0x8218691c SIOCATMARK = 0x40047307 - SIOCBRDGADD = 0x8058693c - SIOCBRDGADDS = 0x80586941 - SIOCBRDGARL = 0x806e694d + SIOCBRDGADD = 0x8060693c + SIOCBRDGADDL = 0x80606949 + SIOCBRDGADDS = 0x80606941 + SIOCBRDGARL = 0x808c694d SIOCBRDGDADDR = 0x81286947 - SIOCBRDGDEL = 0x8058693d - SIOCBRDGDELS = 0x80586942 - SIOCBRDGFLUSH = 0x80586948 - SIOCBRDGFRL = 0x806e694e - SIOCBRDGGCACHE = 0xc0146941 - SIOCBRDGGFD = 0xc0146952 - SIOCBRDGGHT = 0xc0146951 - SIOCBRDGGIFFLGS = 0xc058693e - SIOCBRDGGMA = 0xc0146953 + SIOCBRDGDEL = 0x8060693d + SIOCBRDGDELS = 0x80606942 + SIOCBRDGFLUSH = 0x80606948 + SIOCBRDGFRL = 0x808c694e + SIOCBRDGGCACHE = 0xc0186941 + SIOCBRDGGFD = 0xc0186952 + SIOCBRDGGHT = 0xc0186951 + SIOCBRDGGIFFLGS = 0xc060693e + SIOCBRDGGMA = 0xc0186953 SIOCBRDGGPARAM = 0xc0406958 - SIOCBRDGGPRI = 0xc0146950 + SIOCBRDGGPRI = 0xc0186950 SIOCBRDGGRL = 0xc030694f - SIOCBRDGGSIFS = 0xc058693c - SIOCBRDGGTO = 0xc0146946 - SIOCBRDGIFS = 0xc0586942 + SIOCBRDGGTO = 0xc0186946 + SIOCBRDGIFS = 0xc0606942 SIOCBRDGRTS = 0xc0206943 SIOCBRDGSADDR = 0xc1286944 - SIOCBRDGSCACHE = 0x80146940 - SIOCBRDGSFD = 0x80146952 - SIOCBRDGSHT = 0x80146951 - SIOCBRDGSIFCOST = 0x80586955 - SIOCBRDGSIFFLGS = 0x8058693f - SIOCBRDGSIFPRIO = 0x80586954 - SIOCBRDGSMA = 0x80146953 - SIOCBRDGSPRI = 0x80146950 - SIOCBRDGSPROTO = 0x8014695a - SIOCBRDGSTO = 0x80146945 - SIOCBRDGSTXHC = 0x80146959 + SIOCBRDGSCACHE = 0x80186940 + SIOCBRDGSFD = 0x80186952 + SIOCBRDGSHT = 0x80186951 + SIOCBRDGSIFCOST = 0x80606955 + SIOCBRDGSIFFLGS = 0x8060693f + SIOCBRDGSIFPRIO = 0x80606954 + SIOCBRDGSIFPROT = 0x8060694a + SIOCBRDGSMA = 0x80186953 + SIOCBRDGSPRI = 0x80186950 + SIOCBRDGSPROTO = 0x8018695a + SIOCBRDGSTO = 0x80186945 + SIOCBRDGSTXHC = 0x80186959 SIOCDELMULTI = 0x80206932 SIOCDIFADDR = 0x80206919 SIOCDIFGROUP = 0x80286989 + SIOCDIFPARENT = 0x802069b4 SIOCDIFPHYADDR = 0x80206949 - SIOCDLIFADDR = 0x8218691e + SIOCDVNETID = 0x802069af SIOCGETKALIVE = 0xc01869a4 SIOCGETLABEL = 0x8020699a + SIOCGETMPWCFG = 0xc02069ae SIOCGETPFLOW = 0xc02069fe SIOCGETPFSYNC = 0xc02069f8 SIOCGETSGCNT = 0xc0207534 SIOCGETVIFCNT = 0xc0287533 SIOCGETVLAN = 0xc0206990 - SIOCGHIWAT = 0x40047301 SIOCGIFADDR = 0xc0206921 - SIOCGIFASYNCMAP = 0xc020697c SIOCGIFBRDADDR = 0xc0206923 SIOCGIFCONF = 0xc0106924 SIOCGIFDATA = 0xc020691b @@ -1122,37 +1222,41 @@ const ( SIOCGIFGMEMB = 0xc028698a SIOCGIFGROUP = 0xc0286988 SIOCGIFHARDMTU = 0xc02069a5 - SIOCGIFMEDIA = 0xc0306936 + SIOCGIFLLPRIO = 0xc02069b6 + SIOCGIFMEDIA = 0xc0406938 SIOCGIFMETRIC = 0xc0206917 SIOCGIFMTU = 0xc020697e SIOCGIFNETMASK = 0xc0206925 - SIOCGIFPDSTADDR = 0xc0206948 + SIOCGIFPAIR = 0xc02069b1 + SIOCGIFPARENT = 0xc02069b3 SIOCGIFPRIORITY = 0xc020699c - SIOCGIFPSRCADDR = 0xc0206947 SIOCGIFRDOMAIN = 0xc02069a0 SIOCGIFRTLABEL = 0xc0206983 - SIOCGIFTIMESLOT = 0xc0206986 + SIOCGIFRXR = 0x802069aa SIOCGIFXFLAGS = 0xc020699e - SIOCGLIFADDR = 0xc218691d SIOCGLIFPHYADDR = 0xc218694b + SIOCGLIFPHYDF = 0xc02069c2 SIOCGLIFPHYRTABLE = 0xc02069a2 SIOCGLIFPHYTTL = 0xc02069a9 - SIOCGLOWAT = 0x40047303 SIOCGPGRP = 0x40047309 SIOCGSPPPPARAMS = 0xc0206994 + SIOCGUMBINFO = 0xc02069be + SIOCGUMBPARAM = 0xc02069c0 SIOCGVH = 0xc02069f6 + SIOCGVNETFLOWID = 0xc02069c4 SIOCGVNETID = 0xc02069a7 + SIOCIFAFATTACH = 0x801169ab + SIOCIFAFDETACH = 0x801169ac SIOCIFCREATE = 0x8020697a SIOCIFDESTROY = 0x80206979 SIOCIFGCLONERS = 0xc0106978 SIOCSETKALIVE = 0x801869a3 SIOCSETLABEL = 0x80206999 + SIOCSETMPWCFG = 0x802069ad SIOCSETPFLOW = 0x802069fd SIOCSETPFSYNC = 0x802069f7 SIOCSETVLAN = 0x8020698f - SIOCSHIWAT = 0x80047300 SIOCSIFADDR = 0x8020690c - SIOCSIFASYNCMAP = 0x8020697d SIOCSIFBRDADDR = 0x80206913 SIOCSIFDESCR = 0x80206980 SIOCSIFDSTADDR = 0x8020690e @@ -1160,25 +1264,36 @@ const ( SIOCSIFGATTR = 0x8028698c SIOCSIFGENERIC = 0x80206939 SIOCSIFLLADDR = 0x8020691f - SIOCSIFMEDIA = 0xc0206935 + SIOCSIFLLPRIO = 0x802069b5 + SIOCSIFMEDIA = 0xc0206937 SIOCSIFMETRIC = 0x80206918 SIOCSIFMTU = 0x8020697f SIOCSIFNETMASK = 0x80206916 - SIOCSIFPHYADDR = 0x80406946 + SIOCSIFPAIR = 0x802069b0 + SIOCSIFPARENT = 0x802069b2 SIOCSIFPRIORITY = 0x8020699b SIOCSIFRDOMAIN = 0x8020699f SIOCSIFRTLABEL = 0x80206982 - SIOCSIFTIMESLOT = 0x80206985 SIOCSIFXFLAGS = 0x8020699d SIOCSLIFPHYADDR = 0x8218694a + SIOCSLIFPHYDF = 0x802069c1 SIOCSLIFPHYRTABLE = 0x802069a1 SIOCSLIFPHYTTL = 0x802069a8 - SIOCSLOWAT = 0x80047302 SIOCSPGRP = 0x80047308 SIOCSSPPPPARAMS = 0x80206993 + SIOCSUMBPARAM = 0x802069bf SIOCSVH = 0xc02069f5 + SIOCSVNETFLOWID = 0x802069c3 SIOCSVNETID = 0x802069a6 + SIOCSWGDPID = 0xc018695b + SIOCSWGMAXFLOW = 0xc0186960 + SIOCSWGMAXGROUP = 0xc018695d + SIOCSWSDPID = 0x8018695c + SIOCSWSPORTNO = 0xc060695f + SOCK_CLOEXEC = 0x8000 SOCK_DGRAM = 0x2 + SOCK_DNS = 0x1000 + SOCK_NONBLOCK = 0x4000 SOCK_RAW = 0x3 SOCK_RDM = 0x4 SOCK_SEQPACKET = 0x5 @@ -1209,9 +1324,42 @@ const ( SO_TIMESTAMP = 0x800 SO_TYPE = 0x1008 SO_USELOOPBACK = 0x40 + SO_ZEROIZE = 0x2000 + S_BLKSIZE = 0x200 + S_IEXEC = 0x40 + S_IFBLK = 0x6000 + S_IFCHR = 0x2000 + S_IFDIR = 0x4000 + S_IFIFO = 0x1000 + S_IFLNK = 0xa000 + S_IFMT = 0xf000 + S_IFREG = 0x8000 + S_IFSOCK = 0xc000 + S_IREAD = 0x100 + S_IRGRP = 0x20 + S_IROTH = 0x4 + S_IRUSR = 0x100 + S_IRWXG = 0x38 + S_IRWXO = 0x7 + S_IRWXU = 0x1c0 + S_ISGID = 0x400 + S_ISTXT = 0x200 + S_ISUID = 0x800 + S_ISVTX = 0x200 + S_IWGRP = 0x10 + S_IWOTH = 0x2 + S_IWRITE = 0x80 + S_IWUSR = 0x80 + S_IXGRP = 0x8 + S_IXOTH = 0x1 + S_IXUSR = 0x40 TCIFLUSH = 0x1 + TCIOFF = 0x3 TCIOFLUSH = 0x3 + TCION = 0x4 TCOFLUSH = 0x2 + TCOOFF = 0x1 + TCOON = 0x2 TCP_MAXBURST = 0x4 TCP_MAXSEG = 0x2 TCP_MAXWIN = 0xffff @@ -1221,11 +1369,12 @@ const ( TCP_MSS = 0x200 TCP_NODELAY = 0x1 TCP_NOPUSH = 0x10 - TCP_NSTATES = 0xb TCP_SACK_ENABLE = 0x8 TCSAFLUSH = 0x2 TIOCCBRK = 0x2000747a TIOCCDTR = 0x20007478 + TIOCCHKVERAUTH = 0x2000741e + TIOCCLRVERAUTH = 0x2000741d TIOCCONS = 0x80047462 TIOCDRAIN = 0x2000745e TIOCEXCL = 0x2000740d @@ -1280,17 +1429,22 @@ const ( TIOCSETAF = 0x802c7416 TIOCSETAW = 0x802c7415 TIOCSETD = 0x8004741b + TIOCSETVERAUTH = 0x8004741c TIOCSFLAGS = 0x8004745c TIOCSIG = 0x8004745f TIOCSPGRP = 0x80047476 TIOCSTART = 0x2000746e - TIOCSTAT = 0x80047465 + TIOCSTAT = 0x20007465 TIOCSTI = 0x80017472 TIOCSTOP = 0x2000746f TIOCSTSTAMP = 0x8008745a TIOCSWINSZ = 0x80087467 TIOCUCNTL = 0x80047466 + TIOCUCNTL_CBRK = 0x7a + TIOCUCNTL_SBRK = 0x7b TOSTOP = 0x400000 + UTIME_NOW = -0x2 + UTIME_OMIT = -0x1 VDISCARD = 0xf VDSUSP = 0xb VEOF = 0x0 @@ -1301,6 +1455,18 @@ const ( VKILL = 0x5 VLNEXT = 0xe VMIN = 0x10 + VM_ANONMIN = 0x7 + VM_LOADAVG = 0x2 + VM_MAXID = 0xc + VM_MAXSLP = 0xa + VM_METER = 0x1 + VM_NKMEMPAGES = 0x6 + VM_PSSTRINGS = 0x3 + VM_SWAPENCRYPT = 0x5 + VM_USPACE = 0xb + VM_UVMEXP = 0x4 + VM_VNODEMIN = 0x9 + VM_VTEXTMIN = 0x8 VQUIT = 0x9 VREPRINT = 0x6 VSTART = 0xc @@ -1313,8 +1479,8 @@ const ( WCONTINUED = 0x8 WCOREFLAG = 0x80 WNOHANG = 0x1 - WSTOPPED = 0x7f WUNTRACED = 0x2 + XCASE = 0x1000000 ) // Errors @@ -1328,6 +1494,7 @@ const ( EALREADY = syscall.Errno(0x25) EAUTH = syscall.Errno(0x50) EBADF = syscall.Errno(0x9) + EBADMSG = syscall.Errno(0x5c) EBADRPC = syscall.Errno(0x48) EBUSY = syscall.Errno(0x10) ECANCELED = syscall.Errno(0x58) @@ -1354,7 +1521,7 @@ const ( EIPSEC = syscall.Errno(0x52) EISCONN = syscall.Errno(0x38) EISDIR = syscall.Errno(0x15) - ELAST = syscall.Errno(0x5b) + ELAST = syscall.Errno(0x5f) ELOOP = syscall.Errno(0x3e) EMEDIUMTYPE = syscall.Errno(0x56) EMFILE = syscall.Errno(0x18) @@ -1382,12 +1549,14 @@ const ( ENOTCONN = syscall.Errno(0x39) ENOTDIR = syscall.Errno(0x14) ENOTEMPTY = syscall.Errno(0x42) + ENOTRECOVERABLE = syscall.Errno(0x5d) ENOTSOCK = syscall.Errno(0x26) ENOTSUP = syscall.Errno(0x5b) ENOTTY = syscall.Errno(0x19) ENXIO = syscall.Errno(0x6) EOPNOTSUPP = syscall.Errno(0x2d) EOVERFLOW = syscall.Errno(0x57) + EOWNERDEAD = syscall.Errno(0x5e) EPERM = syscall.Errno(0x1) EPFNOSUPPORT = syscall.Errno(0x2e) EPIPE = syscall.Errno(0x20) @@ -1395,6 +1564,7 @@ const ( EPROCUNAVAIL = syscall.Errno(0x4c) EPROGMISMATCH = syscall.Errno(0x4b) EPROGUNAVAIL = syscall.Errno(0x4a) + EPROTO = syscall.Errno(0x5f) EPROTONOSUPPORT = syscall.Errno(0x2b) EPROTOTYPE = syscall.Errno(0x29) ERANGE = syscall.Errno(0x22) @@ -1452,132 +1622,144 @@ const ( ) // Error table -var errors = [...]string{ - 1: "operation not permitted", - 2: "no such file or directory", - 3: "no such process", - 4: "interrupted system call", - 5: "input/output error", - 6: "device not configured", - 7: "argument list too long", - 8: "exec format error", - 9: "bad file descriptor", - 10: "no child processes", - 11: "resource deadlock avoided", - 12: "cannot allocate memory", - 13: "permission denied", - 14: "bad address", - 15: "block device required", - 16: "device busy", - 17: "file exists", - 18: "cross-device link", - 19: "operation not supported by device", - 20: "not a directory", - 21: "is a directory", - 22: "invalid argument", - 23: "too many open files in system", - 24: "too many open files", - 25: "inappropriate ioctl for device", - 26: "text file busy", - 27: "file too large", - 28: "no space left on device", - 29: "illegal seek", - 30: "read-only file system", - 31: "too many links", - 32: "broken pipe", - 33: "numerical argument out of domain", - 34: "result too large", - 35: "resource temporarily unavailable", - 36: "operation now in progress", - 37: "operation already in progress", - 38: "socket operation on non-socket", - 39: "destination address required", - 40: "message too long", - 41: "protocol wrong type for socket", - 42: "protocol not available", - 43: "protocol not supported", - 44: "socket type not supported", - 45: "operation not supported", - 46: "protocol family not supported", - 47: "address family not supported by protocol family", - 48: "address already in use", - 49: "can't assign requested address", - 50: "network is down", - 51: "network is unreachable", - 52: "network dropped connection on reset", - 53: "software caused connection abort", - 54: "connection reset by peer", - 55: "no buffer space available", - 56: "socket is already connected", - 57: "socket is not connected", - 58: "can't send after socket shutdown", - 59: "too many references: can't splice", - 60: "connection timed out", - 61: "connection refused", - 62: "too many levels of symbolic links", - 63: "file name too long", - 64: "host is down", - 65: "no route to host", - 66: "directory not empty", - 67: "too many processes", - 68: "too many users", - 69: "disc quota exceeded", - 70: "stale NFS file handle", - 71: "too many levels of remote in path", - 72: "RPC struct is bad", - 73: "RPC version wrong", - 74: "RPC prog. not avail", - 75: "program version wrong", - 76: "bad procedure for program", - 77: "no locks available", - 78: "function not implemented", - 79: "inappropriate file type or format", - 80: "authentication error", - 81: "need authenticator", - 82: "IPsec processing failure", - 83: "attribute not found", - 84: "illegal byte sequence", - 85: "no medium found", - 86: "wrong medium type", - 87: "value too large to be stored in data type", - 88: "operation canceled", - 89: "identifier removed", - 90: "no message of desired type", - 91: "not supported", +var errorList = [...]struct { + num syscall.Errno + name string + desc string +}{ + {1, "EPERM", "operation not permitted"}, + {2, "ENOENT", "no such file or directory"}, + {3, "ESRCH", "no such process"}, + {4, "EINTR", "interrupted system call"}, + {5, "EIO", "input/output error"}, + {6, "ENXIO", "device not configured"}, + {7, "E2BIG", "argument list too long"}, + {8, "ENOEXEC", "exec format error"}, + {9, "EBADF", "bad file descriptor"}, + {10, "ECHILD", "no child processes"}, + {11, "EDEADLK", "resource deadlock avoided"}, + {12, "ENOMEM", "cannot allocate memory"}, + {13, "EACCES", "permission denied"}, + {14, "EFAULT", "bad address"}, + {15, "ENOTBLK", "block device required"}, + {16, "EBUSY", "device busy"}, + {17, "EEXIST", "file exists"}, + {18, "EXDEV", "cross-device link"}, + {19, "ENODEV", "operation not supported by device"}, + {20, "ENOTDIR", "not a directory"}, + {21, "EISDIR", "is a directory"}, + {22, "EINVAL", "invalid argument"}, + {23, "ENFILE", "too many open files in system"}, + {24, "EMFILE", "too many open files"}, + {25, "ENOTTY", "inappropriate ioctl for device"}, + {26, "ETXTBSY", "text file busy"}, + {27, "EFBIG", "file too large"}, + {28, "ENOSPC", "no space left on device"}, + {29, "ESPIPE", "illegal seek"}, + {30, "EROFS", "read-only file system"}, + {31, "EMLINK", "too many links"}, + {32, "EPIPE", "broken pipe"}, + {33, "EDOM", "numerical argument out of domain"}, + {34, "ERANGE", "result too large"}, + {35, "EAGAIN", "resource temporarily unavailable"}, + {36, "EINPROGRESS", "operation now in progress"}, + {37, "EALREADY", "operation already in progress"}, + {38, "ENOTSOCK", "socket operation on non-socket"}, + {39, "EDESTADDRREQ", "destination address required"}, + {40, "EMSGSIZE", "message too long"}, + {41, "EPROTOTYPE", "protocol wrong type for socket"}, + {42, "ENOPROTOOPT", "protocol not available"}, + {43, "EPROTONOSUPPORT", "protocol not supported"}, + {44, "ESOCKTNOSUPPORT", "socket type not supported"}, + {45, "EOPNOTSUPP", "operation not supported"}, + {46, "EPFNOSUPPORT", "protocol family not supported"}, + {47, "EAFNOSUPPORT", "address family not supported by protocol family"}, + {48, "EADDRINUSE", "address already in use"}, + {49, "EADDRNOTAVAIL", "can't assign requested address"}, + {50, "ENETDOWN", "network is down"}, + {51, "ENETUNREACH", "network is unreachable"}, + {52, "ENETRESET", "network dropped connection on reset"}, + {53, "ECONNABORTED", "software caused connection abort"}, + {54, "ECONNRESET", "connection reset by peer"}, + {55, "ENOBUFS", "no buffer space available"}, + {56, "EISCONN", "socket is already connected"}, + {57, "ENOTCONN", "socket is not connected"}, + {58, "ESHUTDOWN", "can't send after socket shutdown"}, + {59, "ETOOMANYREFS", "too many references: can't splice"}, + {60, "ETIMEDOUT", "operation timed out"}, + {61, "ECONNREFUSED", "connection refused"}, + {62, "ELOOP", "too many levels of symbolic links"}, + {63, "ENAMETOOLONG", "file name too long"}, + {64, "EHOSTDOWN", "host is down"}, + {65, "EHOSTUNREACH", "no route to host"}, + {66, "ENOTEMPTY", "directory not empty"}, + {67, "EPROCLIM", "too many processes"}, + {68, "EUSERS", "too many users"}, + {69, "EDQUOT", "disk quota exceeded"}, + {70, "ESTALE", "stale NFS file handle"}, + {71, "EREMOTE", "too many levels of remote in path"}, + {72, "EBADRPC", "RPC struct is bad"}, + {73, "ERPCMISMATCH", "RPC version wrong"}, + {74, "EPROGUNAVAIL", "RPC program not available"}, + {75, "EPROGMISMATCH", "program version wrong"}, + {76, "EPROCUNAVAIL", "bad procedure for program"}, + {77, "ENOLCK", "no locks available"}, + {78, "ENOSYS", "function not implemented"}, + {79, "EFTYPE", "inappropriate file type or format"}, + {80, "EAUTH", "authentication error"}, + {81, "ENEEDAUTH", "need authenticator"}, + {82, "EIPSEC", "IPsec processing failure"}, + {83, "ENOATTR", "attribute not found"}, + {84, "EILSEQ", "illegal byte sequence"}, + {85, "ENOMEDIUM", "no medium found"}, + {86, "EMEDIUMTYPE", "wrong medium type"}, + {87, "EOVERFLOW", "value too large to be stored in data type"}, + {88, "ECANCELED", "operation canceled"}, + {89, "EIDRM", "identifier removed"}, + {90, "ENOMSG", "no message of desired type"}, + {91, "ENOTSUP", "not supported"}, + {92, "EBADMSG", "bad message"}, + {93, "ENOTRECOVERABLE", "state not recoverable"}, + {94, "EOWNERDEAD", "previous owner died"}, + {95, "ELAST", "protocol error"}, } // Signal table -var signals = [...]string{ - 1: "hangup", - 2: "interrupt", - 3: "quit", - 4: "illegal instruction", - 5: "trace/BPT trap", - 6: "abort trap", - 7: "EMT trap", - 8: "floating point exception", - 9: "killed", - 10: "bus error", - 11: "segmentation fault", - 12: "bad system call", - 13: "broken pipe", - 14: "alarm clock", - 15: "terminated", - 16: "urgent I/O condition", - 17: "stopped (signal)", - 18: "stopped", - 19: "continued", - 20: "child exited", - 21: "stopped (tty input)", - 22: "stopped (tty output)", - 23: "I/O possible", - 24: "cputime limit exceeded", - 25: "filesize limit exceeded", - 26: "virtual timer expired", - 27: "profiling timer expired", - 28: "window size changes", - 29: "information request", - 30: "user defined signal 1", - 31: "user defined signal 2", - 32: "thread AST", +var signalList = [...]struct { + num syscall.Signal + name string + desc string +}{ + {1, "SIGHUP", "hangup"}, + {2, "SIGINT", "interrupt"}, + {3, "SIGQUIT", "quit"}, + {4, "SIGILL", "illegal instruction"}, + {5, "SIGTRAP", "trace/BPT trap"}, + {6, "SIGABRT", "abort trap"}, + {7, "SIGEMT", "EMT trap"}, + {8, "SIGFPE", "floating point exception"}, + {9, "SIGKILL", "killed"}, + {10, "SIGBUS", "bus error"}, + {11, "SIGSEGV", "segmentation fault"}, + {12, "SIGSYS", "bad system call"}, + {13, "SIGPIPE", "broken pipe"}, + {14, "SIGALRM", "alarm clock"}, + {15, "SIGTERM", "terminated"}, + {16, "SIGURG", "urgent I/O condition"}, + {17, "SIGSTOP", "suspended (signal)"}, + {18, "SIGTSTP", "suspended"}, + {19, "SIGCONT", "continued"}, + {20, "SIGCHLD", "child exited"}, + {21, "SIGTTIN", "stopped (tty input)"}, + {22, "SIGTTOU", "stopped (tty output)"}, + {23, "SIGIO", "I/O possible"}, + {24, "SIGXCPU", "cputime limit exceeded"}, + {25, "SIGXFSZ", "filesize limit exceeded"}, + {26, "SIGVTALRM", "virtual timer expired"}, + {27, "SIGPROF", "profiling timer expired"}, + {28, "SIGWINCH", "window size changes"}, + {29, "SIGINFO", "information request"}, + {30, "SIGUSR1", "user defined signal 1"}, + {31, "SIGUSR2", "user defined signal 2"}, + {32, "SIGTHR", "thread AST"}, } diff --git a/vendor/golang.org/x/sys/unix/zerrors_openbsd_arm.go b/vendor/golang.org/x/sys/unix/zerrors_openbsd_arm.go index 3ed0b2602f..79d5695c37 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_openbsd_arm.go +++ b/vendor/golang.org/x/sys/unix/zerrors_openbsd_arm.go @@ -1,5 +1,5 @@ // mkerrors.sh -// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// Code generated by the command above; see README.md. DO NOT EDIT. // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- _const.go @@ -147,6 +147,7 @@ const ( CFLUSH = 0xf CLOCAL = 0x8000 CREAD = 0x800 + CRTSCTS = 0x10000 CS5 = 0x0 CS6 = 0x100 CS7 = 0x200 @@ -157,6 +158,8 @@ const ( CSTOP = 0x13 CSTOPB = 0x400 CSUSP = 0x1a + CTL_HW = 0x6 + CTL_KERN = 0x1 CTL_MAXNAME = 0xc CTL_NET = 0x4 DIOCOSFPFLUSH = 0x2000444e @@ -441,6 +444,7 @@ const ( F_UNLCK = 0x2 F_WRLCK = 0x3 HUPCL = 0x4000 + HW_MACHINE = 0x1 ICANON = 0x100 ICMP6_FILTER = 0x12 ICRNL = 0x100 @@ -859,6 +863,10 @@ const ( IXANY = 0x800 IXOFF = 0x400 IXON = 0x200 + KERN_HOSTNAME = 0xa + KERN_OSRELEASE = 0x2 + KERN_OSTYPE = 0x1 + KERN_VERSION = 0x4 LCNT_OVERLOAD_FLUSH = 0x6 LOCK_EX = 0x2 LOCK_NB = 0x4 @@ -891,6 +899,32 @@ const ( MAP_TRYFIXED = 0x0 MCL_CURRENT = 0x1 MCL_FUTURE = 0x2 + MNT_ASYNC = 0x40 + MNT_DEFEXPORTED = 0x200 + MNT_DELEXPORT = 0x20000 + MNT_DOOMED = 0x8000000 + MNT_EXPORTANON = 0x400 + MNT_EXPORTED = 0x100 + MNT_EXRDONLY = 0x80 + MNT_FORCE = 0x80000 + MNT_LAZY = 0x3 + MNT_LOCAL = 0x1000 + MNT_NOATIME = 0x8000 + MNT_NODEV = 0x10 + MNT_NOEXEC = 0x4 + MNT_NOSUID = 0x8 + MNT_NOWAIT = 0x2 + MNT_QUOTA = 0x2000 + MNT_RDONLY = 0x1 + MNT_RELOAD = 0x40000 + MNT_ROOTFS = 0x4000 + MNT_SOFTDEP = 0x4000000 + MNT_SYNCHRONOUS = 0x2 + MNT_UPDATE = 0x10000 + MNT_VISFLAGMASK = 0x400ffff + MNT_WAIT = 0x1 + MNT_WANTRDWR = 0x2000000 + MNT_WXALLOWED = 0x800 MSG_BCAST = 0x100 MSG_CMSG_CLOEXEC = 0x800 MSG_CTRUNC = 0x20 @@ -1213,6 +1247,34 @@ const ( SO_TIMESTAMP = 0x800 SO_TYPE = 0x1008 SO_USELOOPBACK = 0x40 + S_BLKSIZE = 0x200 + S_IEXEC = 0x40 + S_IFBLK = 0x6000 + S_IFCHR = 0x2000 + S_IFDIR = 0x4000 + S_IFIFO = 0x1000 + S_IFLNK = 0xa000 + S_IFMT = 0xf000 + S_IFREG = 0x8000 + S_IFSOCK = 0xc000 + S_IREAD = 0x100 + S_IRGRP = 0x20 + S_IROTH = 0x4 + S_IRUSR = 0x100 + S_IRWXG = 0x38 + S_IRWXO = 0x7 + S_IRWXU = 0x1c0 + S_ISGID = 0x400 + S_ISTXT = 0x200 + S_ISUID = 0x800 + S_ISVTX = 0x200 + S_IWGRP = 0x10 + S_IWOTH = 0x2 + S_IWRITE = 0x80 + S_IWUSR = 0x80 + S_IXGRP = 0x8 + S_IXOTH = 0x1 + S_IXUSR = 0x40 TCIFLUSH = 0x1 TCIOFLUSH = 0x3 TCOFLUSH = 0x2 @@ -1455,132 +1517,140 @@ const ( ) // Error table -var errors = [...]string{ - 1: "operation not permitted", - 2: "no such file or directory", - 3: "no such process", - 4: "interrupted system call", - 5: "input/output error", - 6: "device not configured", - 7: "argument list too long", - 8: "exec format error", - 9: "bad file descriptor", - 10: "no child processes", - 11: "resource deadlock avoided", - 12: "cannot allocate memory", - 13: "permission denied", - 14: "bad address", - 15: "block device required", - 16: "device busy", - 17: "file exists", - 18: "cross-device link", - 19: "operation not supported by device", - 20: "not a directory", - 21: "is a directory", - 22: "invalid argument", - 23: "too many open files in system", - 24: "too many open files", - 25: "inappropriate ioctl for device", - 26: "text file busy", - 27: "file too large", - 28: "no space left on device", - 29: "illegal seek", - 30: "read-only file system", - 31: "too many links", - 32: "broken pipe", - 33: "numerical argument out of domain", - 34: "result too large", - 35: "resource temporarily unavailable", - 36: "operation now in progress", - 37: "operation already in progress", - 38: "socket operation on non-socket", - 39: "destination address required", - 40: "message too long", - 41: "protocol wrong type for socket", - 42: "protocol not available", - 43: "protocol not supported", - 44: "socket type not supported", - 45: "operation not supported", - 46: "protocol family not supported", - 47: "address family not supported by protocol family", - 48: "address already in use", - 49: "can't assign requested address", - 50: "network is down", - 51: "network is unreachable", - 52: "network dropped connection on reset", - 53: "software caused connection abort", - 54: "connection reset by peer", - 55: "no buffer space available", - 56: "socket is already connected", - 57: "socket is not connected", - 58: "can't send after socket shutdown", - 59: "too many references: can't splice", - 60: "connection timed out", - 61: "connection refused", - 62: "too many levels of symbolic links", - 63: "file name too long", - 64: "host is down", - 65: "no route to host", - 66: "directory not empty", - 67: "too many processes", - 68: "too many users", - 69: "disc quota exceeded", - 70: "stale NFS file handle", - 71: "too many levels of remote in path", - 72: "RPC struct is bad", - 73: "RPC version wrong", - 74: "RPC prog. not avail", - 75: "program version wrong", - 76: "bad procedure for program", - 77: "no locks available", - 78: "function not implemented", - 79: "inappropriate file type or format", - 80: "authentication error", - 81: "need authenticator", - 82: "IPsec processing failure", - 83: "attribute not found", - 84: "illegal byte sequence", - 85: "no medium found", - 86: "wrong medium type", - 87: "value too large to be stored in data type", - 88: "operation canceled", - 89: "identifier removed", - 90: "no message of desired type", - 91: "not supported", +var errorList = [...]struct { + num syscall.Errno + name string + desc string +}{ + {1, "EPERM", "operation not permitted"}, + {2, "ENOENT", "no such file or directory"}, + {3, "ESRCH", "no such process"}, + {4, "EINTR", "interrupted system call"}, + {5, "EIO", "input/output error"}, + {6, "ENXIO", "device not configured"}, + {7, "E2BIG", "argument list too long"}, + {8, "ENOEXEC", "exec format error"}, + {9, "EBADF", "bad file descriptor"}, + {10, "ECHILD", "no child processes"}, + {11, "EDEADLK", "resource deadlock avoided"}, + {12, "ENOMEM", "cannot allocate memory"}, + {13, "EACCES", "permission denied"}, + {14, "EFAULT", "bad address"}, + {15, "ENOTBLK", "block device required"}, + {16, "EBUSY", "device busy"}, + {17, "EEXIST", "file exists"}, + {18, "EXDEV", "cross-device link"}, + {19, "ENODEV", "operation not supported by device"}, + {20, "ENOTDIR", "not a directory"}, + {21, "EISDIR", "is a directory"}, + {22, "EINVAL", "invalid argument"}, + {23, "ENFILE", "too many open files in system"}, + {24, "EMFILE", "too many open files"}, + {25, "ENOTTY", "inappropriate ioctl for device"}, + {26, "ETXTBSY", "text file busy"}, + {27, "EFBIG", "file too large"}, + {28, "ENOSPC", "no space left on device"}, + {29, "ESPIPE", "illegal seek"}, + {30, "EROFS", "read-only file system"}, + {31, "EMLINK", "too many links"}, + {32, "EPIPE", "broken pipe"}, + {33, "EDOM", "numerical argument out of domain"}, + {34, "ERANGE", "result too large"}, + {35, "EWOULDBLOCK", "resource temporarily unavailable"}, + {36, "EINPROGRESS", "operation now in progress"}, + {37, "EALREADY", "operation already in progress"}, + {38, "ENOTSOCK", "socket operation on non-socket"}, + {39, "EDESTADDRREQ", "destination address required"}, + {40, "EMSGSIZE", "message too long"}, + {41, "EPROTOTYPE", "protocol wrong type for socket"}, + {42, "ENOPROTOOPT", "protocol not available"}, + {43, "EPROTONOSUPPORT", "protocol not supported"}, + {44, "ESOCKTNOSUPPORT", "socket type not supported"}, + {45, "EOPNOTSUPP", "operation not supported"}, + {46, "EPFNOSUPPORT", "protocol family not supported"}, + {47, "EAFNOSUPPORT", "address family not supported by protocol family"}, + {48, "EADDRINUSE", "address already in use"}, + {49, "EADDRNOTAVAIL", "can't assign requested address"}, + {50, "ENETDOWN", "network is down"}, + {51, "ENETUNREACH", "network is unreachable"}, + {52, "ENETRESET", "network dropped connection on reset"}, + {53, "ECONNABORTED", "software caused connection abort"}, + {54, "ECONNRESET", "connection reset by peer"}, + {55, "ENOBUFS", "no buffer space available"}, + {56, "EISCONN", "socket is already connected"}, + {57, "ENOTCONN", "socket is not connected"}, + {58, "ESHUTDOWN", "can't send after socket shutdown"}, + {59, "ETOOMANYREFS", "too many references: can't splice"}, + {60, "ETIMEDOUT", "operation timed out"}, + {61, "ECONNREFUSED", "connection refused"}, + {62, "ELOOP", "too many levels of symbolic links"}, + {63, "ENAMETOOLONG", "file name too long"}, + {64, "EHOSTDOWN", "host is down"}, + {65, "EHOSTUNREACH", "no route to host"}, + {66, "ENOTEMPTY", "directory not empty"}, + {67, "EPROCLIM", "too many processes"}, + {68, "EUSERS", "too many users"}, + {69, "EDQUOT", "disk quota exceeded"}, + {70, "ESTALE", "stale NFS file handle"}, + {71, "EREMOTE", "too many levels of remote in path"}, + {72, "EBADRPC", "RPC struct is bad"}, + {73, "ERPCMISMATCH", "RPC version wrong"}, + {74, "EPROGUNAVAIL", "RPC program not available"}, + {75, "EPROGMISMATCH", "program version wrong"}, + {76, "EPROCUNAVAIL", "bad procedure for program"}, + {77, "ENOLCK", "no locks available"}, + {78, "ENOSYS", "function not implemented"}, + {79, "EFTYPE", "inappropriate file type or format"}, + {80, "EAUTH", "authentication error"}, + {81, "ENEEDAUTH", "need authenticator"}, + {82, "EIPSEC", "IPsec processing failure"}, + {83, "ENOATTR", "attribute not found"}, + {84, "EILSEQ", "illegal byte sequence"}, + {85, "ENOMEDIUM", "no medium found"}, + {86, "EMEDIUMTYPE", "wrong medium type"}, + {87, "EOVERFLOW", "value too large to be stored in data type"}, + {88, "ECANCELED", "operation canceled"}, + {89, "EIDRM", "identifier removed"}, + {90, "ENOMSG", "no message of desired type"}, + {91, "ELAST", "not supported"}, } // Signal table -var signals = [...]string{ - 1: "hangup", - 2: "interrupt", - 3: "quit", - 4: "illegal instruction", - 5: "trace/BPT trap", - 6: "abort trap", - 7: "EMT trap", - 8: "floating point exception", - 9: "killed", - 10: "bus error", - 11: "segmentation fault", - 12: "bad system call", - 13: "broken pipe", - 14: "alarm clock", - 15: "terminated", - 16: "urgent I/O condition", - 17: "stopped (signal)", - 18: "stopped", - 19: "continued", - 20: "child exited", - 21: "stopped (tty input)", - 22: "stopped (tty output)", - 23: "I/O possible", - 24: "cputime limit exceeded", - 25: "filesize limit exceeded", - 26: "virtual timer expired", - 27: "profiling timer expired", - 28: "window size changes", - 29: "information request", - 30: "user defined signal 1", - 31: "user defined signal 2", - 32: "thread AST", +var signalList = [...]struct { + num syscall.Signal + name string + desc string +}{ + {1, "SIGHUP", "hangup"}, + {2, "SIGINT", "interrupt"}, + {3, "SIGQUIT", "quit"}, + {4, "SIGILL", "illegal instruction"}, + {5, "SIGTRAP", "trace/BPT trap"}, + {6, "SIGABRT", "abort trap"}, + {7, "SIGEMT", "EMT trap"}, + {8, "SIGFPE", "floating point exception"}, + {9, "SIGKILL", "killed"}, + {10, "SIGBUS", "bus error"}, + {11, "SIGSEGV", "segmentation fault"}, + {12, "SIGSYS", "bad system call"}, + {13, "SIGPIPE", "broken pipe"}, + {14, "SIGALRM", "alarm clock"}, + {15, "SIGTERM", "terminated"}, + {16, "SIGURG", "urgent I/O condition"}, + {17, "SIGSTOP", "suspended (signal)"}, + {18, "SIGTSTP", "suspended"}, + {19, "SIGCONT", "continued"}, + {20, "SIGCHLD", "child exited"}, + {21, "SIGTTIN", "stopped (tty input)"}, + {22, "SIGTTOU", "stopped (tty output)"}, + {23, "SIGIO", "I/O possible"}, + {24, "SIGXCPU", "cputime limit exceeded"}, + {25, "SIGXFSZ", "filesize limit exceeded"}, + {26, "SIGVTALRM", "virtual timer expired"}, + {27, "SIGPROF", "profiling timer expired"}, + {28, "SIGWINCH", "window size changes"}, + {29, "SIGINFO", "information request"}, + {30, "SIGUSR1", "user defined signal 1"}, + {31, "SIGUSR2", "user defined signal 2"}, + {32, "SIGTHR", "thread AST"}, } diff --git a/vendor/golang.org/x/sys/unix/zerrors_solaris_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_solaris_amd64.go index 09eedb0093..22569db31d 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_solaris_amd64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_solaris_amd64.go @@ -996,6 +996,39 @@ const ( SO_USELOOPBACK = 0x40 SO_VRRP = 0x1017 SO_WROFF = 0x2 + S_ENFMT = 0x400 + S_IAMB = 0x1ff + S_IEXEC = 0x40 + S_IFBLK = 0x6000 + S_IFCHR = 0x2000 + S_IFDIR = 0x4000 + S_IFDOOR = 0xd000 + S_IFIFO = 0x1000 + S_IFLNK = 0xa000 + S_IFMT = 0xf000 + S_IFNAM = 0x5000 + S_IFPORT = 0xe000 + S_IFREG = 0x8000 + S_IFSOCK = 0xc000 + S_INSEM = 0x1 + S_INSHD = 0x2 + S_IREAD = 0x100 + S_IRGRP = 0x20 + S_IROTH = 0x4 + S_IRUSR = 0x100 + S_IRWXG = 0x38 + S_IRWXO = 0x7 + S_IRWXU = 0x1c0 + S_ISGID = 0x400 + S_ISUID = 0x800 + S_ISVTX = 0x200 + S_IWGRP = 0x10 + S_IWOTH = 0x2 + S_IWRITE = 0x80 + S_IWUSR = 0x80 + S_IXGRP = 0x8 + S_IXOTH = 0x1 + S_IXUSR = 0x40 TAB0 = 0x0 TAB1 = 0x800 TAB2 = 0x1000 @@ -1102,6 +1135,8 @@ const ( TIOCSTOP = 0x746f TIOCSWINSZ = 0x5467 TOSTOP = 0x100 + UTIME_NOW = -0x1 + UTIME_OMIT = -0x2 VCEOF = 0x8 VCEOL = 0x9 VDISCARD = 0xd @@ -1319,171 +1354,179 @@ const ( ) // Error table -var errors = [...]string{ - 1: "not owner", - 2: "no such file or directory", - 3: "no such process", - 4: "interrupted system call", - 5: "I/O error", - 6: "no such device or address", - 7: "arg list too long", - 8: "exec format error", - 9: "bad file number", - 10: "no child processes", - 11: "resource temporarily unavailable", - 12: "not enough space", - 13: "permission denied", - 14: "bad address", - 15: "block device required", - 16: "device busy", - 17: "file exists", - 18: "cross-device link", - 19: "no such device", - 20: "not a directory", - 21: "is a directory", - 22: "invalid argument", - 23: "file table overflow", - 24: "too many open files", - 25: "inappropriate ioctl for device", - 26: "text file busy", - 27: "file too large", - 28: "no space left on device", - 29: "illegal seek", - 30: "read-only file system", - 31: "too many links", - 32: "broken pipe", - 33: "argument out of domain", - 34: "result too large", - 35: "no message of desired type", - 36: "identifier removed", - 37: "channel number out of range", - 38: "level 2 not synchronized", - 39: "level 3 halted", - 40: "level 3 reset", - 41: "link number out of range", - 42: "protocol driver not attached", - 43: "no CSI structure available", - 44: "level 2 halted", - 45: "deadlock situation detected/avoided", - 46: "no record locks available", - 47: "operation canceled", - 48: "operation not supported", - 49: "disc quota exceeded", - 50: "bad exchange descriptor", - 51: "bad request descriptor", - 52: "message tables full", - 53: "anode table overflow", - 54: "bad request code", - 55: "invalid slot", - 56: "file locking deadlock", - 57: "bad font file format", - 58: "owner of the lock died", - 59: "lock is not recoverable", - 60: "not a stream device", - 61: "no data available", - 62: "timer expired", - 63: "out of stream resources", - 64: "machine is not on the network", - 65: "package not installed", - 66: "object is remote", - 67: "link has been severed", - 68: "advertise error", - 69: "srmount error", - 70: "communication error on send", - 71: "protocol error", - 72: "locked lock was unmapped ", - 73: "facility is not active", - 74: "multihop attempted", - 77: "not a data message", - 78: "file name too long", - 79: "value too large for defined data type", - 80: "name not unique on network", - 81: "file descriptor in bad state", - 82: "remote address changed", - 83: "can not access a needed shared library", - 84: "accessing a corrupted shared library", - 85: ".lib section in a.out corrupted", - 86: "attempting to link in more shared libraries than system limit", - 87: "can not exec a shared library directly", - 88: "illegal byte sequence", - 89: "operation not applicable", - 90: "number of symbolic links encountered during path name traversal exceeds MAXSYMLINKS", - 91: "error 91", - 92: "error 92", - 93: "directory not empty", - 94: "too many users", - 95: "socket operation on non-socket", - 96: "destination address required", - 97: "message too long", - 98: "protocol wrong type for socket", - 99: "option not supported by protocol", - 120: "protocol not supported", - 121: "socket type not supported", - 122: "operation not supported on transport endpoint", - 123: "protocol family not supported", - 124: "address family not supported by protocol family", - 125: "address already in use", - 126: "cannot assign requested address", - 127: "network is down", - 128: "network is unreachable", - 129: "network dropped connection because of reset", - 130: "software caused connection abort", - 131: "connection reset by peer", - 132: "no buffer space available", - 133: "transport endpoint is already connected", - 134: "transport endpoint is not connected", - 143: "cannot send after socket shutdown", - 144: "too many references: cannot splice", - 145: "connection timed out", - 146: "connection refused", - 147: "host is down", - 148: "no route to host", - 149: "operation already in progress", - 150: "operation now in progress", - 151: "stale NFS file handle", +var errorList = [...]struct { + num syscall.Errno + name string + desc string +}{ + {1, "EPERM", "not owner"}, + {2, "ENOENT", "no such file or directory"}, + {3, "ESRCH", "no such process"}, + {4, "EINTR", "interrupted system call"}, + {5, "EIO", "I/O error"}, + {6, "ENXIO", "no such device or address"}, + {7, "E2BIG", "arg list too long"}, + {8, "ENOEXEC", "exec format error"}, + {9, "EBADF", "bad file number"}, + {10, "ECHILD", "no child processes"}, + {11, "EAGAIN", "resource temporarily unavailable"}, + {12, "ENOMEM", "not enough space"}, + {13, "EACCES", "permission denied"}, + {14, "EFAULT", "bad address"}, + {15, "ENOTBLK", "block device required"}, + {16, "EBUSY", "device busy"}, + {17, "EEXIST", "file exists"}, + {18, "EXDEV", "cross-device link"}, + {19, "ENODEV", "no such device"}, + {20, "ENOTDIR", "not a directory"}, + {21, "EISDIR", "is a directory"}, + {22, "EINVAL", "invalid argument"}, + {23, "ENFILE", "file table overflow"}, + {24, "EMFILE", "too many open files"}, + {25, "ENOTTY", "inappropriate ioctl for device"}, + {26, "ETXTBSY", "text file busy"}, + {27, "EFBIG", "file too large"}, + {28, "ENOSPC", "no space left on device"}, + {29, "ESPIPE", "illegal seek"}, + {30, "EROFS", "read-only file system"}, + {31, "EMLINK", "too many links"}, + {32, "EPIPE", "broken pipe"}, + {33, "EDOM", "argument out of domain"}, + {34, "ERANGE", "result too large"}, + {35, "ENOMSG", "no message of desired type"}, + {36, "EIDRM", "identifier removed"}, + {37, "ECHRNG", "channel number out of range"}, + {38, "EL2NSYNC", "level 2 not synchronized"}, + {39, "EL3HLT", "level 3 halted"}, + {40, "EL3RST", "level 3 reset"}, + {41, "ELNRNG", "link number out of range"}, + {42, "EUNATCH", "protocol driver not attached"}, + {43, "ENOCSI", "no CSI structure available"}, + {44, "EL2HLT", "level 2 halted"}, + {45, "EDEADLK", "deadlock situation detected/avoided"}, + {46, "ENOLCK", "no record locks available"}, + {47, "ECANCELED", "operation canceled"}, + {48, "ENOTSUP", "operation not supported"}, + {49, "EDQUOT", "disc quota exceeded"}, + {50, "EBADE", "bad exchange descriptor"}, + {51, "EBADR", "bad request descriptor"}, + {52, "EXFULL", "message tables full"}, + {53, "ENOANO", "anode table overflow"}, + {54, "EBADRQC", "bad request code"}, + {55, "EBADSLT", "invalid slot"}, + {56, "EDEADLOCK", "file locking deadlock"}, + {57, "EBFONT", "bad font file format"}, + {58, "EOWNERDEAD", "owner of the lock died"}, + {59, "ENOTRECOVERABLE", "lock is not recoverable"}, + {60, "ENOSTR", "not a stream device"}, + {61, "ENODATA", "no data available"}, + {62, "ETIME", "timer expired"}, + {63, "ENOSR", "out of stream resources"}, + {64, "ENONET", "machine is not on the network"}, + {65, "ENOPKG", "package not installed"}, + {66, "EREMOTE", "object is remote"}, + {67, "ENOLINK", "link has been severed"}, + {68, "EADV", "advertise error"}, + {69, "ESRMNT", "srmount error"}, + {70, "ECOMM", "communication error on send"}, + {71, "EPROTO", "protocol error"}, + {72, "ELOCKUNMAPPED", "locked lock was unmapped "}, + {73, "ENOTACTIVE", "facility is not active"}, + {74, "EMULTIHOP", "multihop attempted"}, + {77, "EBADMSG", "not a data message"}, + {78, "ENAMETOOLONG", "file name too long"}, + {79, "EOVERFLOW", "value too large for defined data type"}, + {80, "ENOTUNIQ", "name not unique on network"}, + {81, "EBADFD", "file descriptor in bad state"}, + {82, "EREMCHG", "remote address changed"}, + {83, "ELIBACC", "can not access a needed shared library"}, + {84, "ELIBBAD", "accessing a corrupted shared library"}, + {85, "ELIBSCN", ".lib section in a.out corrupted"}, + {86, "ELIBMAX", "attempting to link in more shared libraries than system limit"}, + {87, "ELIBEXEC", "can not exec a shared library directly"}, + {88, "EILSEQ", "illegal byte sequence"}, + {89, "ENOSYS", "operation not applicable"}, + {90, "ELOOP", "number of symbolic links encountered during path name traversal exceeds MAXSYMLINKS"}, + {91, "ERESTART", "error 91"}, + {92, "ESTRPIPE", "error 92"}, + {93, "ENOTEMPTY", "directory not empty"}, + {94, "EUSERS", "too many users"}, + {95, "ENOTSOCK", "socket operation on non-socket"}, + {96, "EDESTADDRREQ", "destination address required"}, + {97, "EMSGSIZE", "message too long"}, + {98, "EPROTOTYPE", "protocol wrong type for socket"}, + {99, "ENOPROTOOPT", "option not supported by protocol"}, + {120, "EPROTONOSUPPORT", "protocol not supported"}, + {121, "ESOCKTNOSUPPORT", "socket type not supported"}, + {122, "EOPNOTSUPP", "operation not supported on transport endpoint"}, + {123, "EPFNOSUPPORT", "protocol family not supported"}, + {124, "EAFNOSUPPORT", "address family not supported by protocol family"}, + {125, "EADDRINUSE", "address already in use"}, + {126, "EADDRNOTAVAIL", "cannot assign requested address"}, + {127, "ENETDOWN", "network is down"}, + {128, "ENETUNREACH", "network is unreachable"}, + {129, "ENETRESET", "network dropped connection because of reset"}, + {130, "ECONNABORTED", "software caused connection abort"}, + {131, "ECONNRESET", "connection reset by peer"}, + {132, "ENOBUFS", "no buffer space available"}, + {133, "EISCONN", "transport endpoint is already connected"}, + {134, "ENOTCONN", "transport endpoint is not connected"}, + {143, "ESHUTDOWN", "cannot send after socket shutdown"}, + {144, "ETOOMANYREFS", "too many references: cannot splice"}, + {145, "ETIMEDOUT", "connection timed out"}, + {146, "ECONNREFUSED", "connection refused"}, + {147, "EHOSTDOWN", "host is down"}, + {148, "EHOSTUNREACH", "no route to host"}, + {149, "EALREADY", "operation already in progress"}, + {150, "EINPROGRESS", "operation now in progress"}, + {151, "ESTALE", "stale NFS file handle"}, } // Signal table -var signals = [...]string{ - 1: "hangup", - 2: "interrupt", - 3: "quit", - 4: "illegal Instruction", - 5: "trace/Breakpoint Trap", - 6: "abort", - 7: "emulation Trap", - 8: "arithmetic Exception", - 9: "killed", - 10: "bus Error", - 11: "segmentation Fault", - 12: "bad System Call", - 13: "broken Pipe", - 14: "alarm Clock", - 15: "terminated", - 16: "user Signal 1", - 17: "user Signal 2", - 18: "child Status Changed", - 19: "power-Fail/Restart", - 20: "window Size Change", - 21: "urgent Socket Condition", - 22: "pollable Event", - 23: "stopped (signal)", - 24: "stopped (user)", - 25: "continued", - 26: "stopped (tty input)", - 27: "stopped (tty output)", - 28: "virtual Timer Expired", - 29: "profiling Timer Expired", - 30: "cpu Limit Exceeded", - 31: "file Size Limit Exceeded", - 32: "no runnable lwp", - 33: "inter-lwp signal", - 34: "checkpoint Freeze", - 35: "checkpoint Thaw", - 36: "thread Cancellation", - 37: "resource Lost", - 38: "resource Control Exceeded", - 39: "reserved for JVM 1", - 40: "reserved for JVM 2", - 41: "information Request", +var signalList = [...]struct { + num syscall.Signal + name string + desc string +}{ + {1, "SIGHUP", "hangup"}, + {2, "SIGINT", "interrupt"}, + {3, "SIGQUIT", "quit"}, + {4, "SIGILL", "illegal Instruction"}, + {5, "SIGTRAP", "trace/Breakpoint Trap"}, + {6, "SIGABRT", "abort"}, + {7, "SIGEMT", "emulation Trap"}, + {8, "SIGFPE", "arithmetic Exception"}, + {9, "SIGKILL", "killed"}, + {10, "SIGBUS", "bus Error"}, + {11, "SIGSEGV", "segmentation Fault"}, + {12, "SIGSYS", "bad System Call"}, + {13, "SIGPIPE", "broken Pipe"}, + {14, "SIGALRM", "alarm Clock"}, + {15, "SIGTERM", "terminated"}, + {16, "SIGUSR1", "user Signal 1"}, + {17, "SIGUSR2", "user Signal 2"}, + {18, "SIGCHLD", "child Status Changed"}, + {19, "SIGPWR", "power-Fail/Restart"}, + {20, "SIGWINCH", "window Size Change"}, + {21, "SIGURG", "urgent Socket Condition"}, + {22, "SIGIO", "pollable Event"}, + {23, "SIGSTOP", "stopped (signal)"}, + {24, "SIGTSTP", "stopped (user)"}, + {25, "SIGCONT", "continued"}, + {26, "SIGTTIN", "stopped (tty input)"}, + {27, "SIGTTOU", "stopped (tty output)"}, + {28, "SIGVTALRM", "virtual Timer Expired"}, + {29, "SIGPROF", "profiling Timer Expired"}, + {30, "SIGXCPU", "cpu Limit Exceeded"}, + {31, "SIGXFSZ", "file Size Limit Exceeded"}, + {32, "SIGWAITING", "no runnable lwp"}, + {33, "SIGLWP", "inter-lwp signal"}, + {34, "SIGFREEZE", "checkpoint Freeze"}, + {35, "SIGTHAW", "checkpoint Thaw"}, + {36, "SIGCANCEL", "thread Cancellation"}, + {37, "SIGLOST", "resource Lost"}, + {38, "SIGXRES", "resource Control Exceeded"}, + {39, "SIGJVM1", "reserved for JVM 1"}, + {40, "SIGJVM2", "reserved for JVM 2"}, + {41, "SIGINFO", "information Request"}, } diff --git a/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc.go b/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc.go new file mode 100644 index 0000000000..79f6e0566e --- /dev/null +++ b/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc.go @@ -0,0 +1,1450 @@ +// go run mksyscall_aix_ppc.go -aix -tags aix,ppc syscall_aix.go syscall_aix_ppc.go +// Code generated by the command above; see README.md. DO NOT EDIT. + +// +build aix,ppc + +package unix + +/* +#include +#include +int utimes(uintptr_t, uintptr_t); +int utimensat(int, uintptr_t, uintptr_t, int); +int getcwd(uintptr_t, size_t); +int accept(int, uintptr_t, uintptr_t); +int getdirent(int, uintptr_t, size_t); +int wait4(int, uintptr_t, int, uintptr_t); +int ioctl(int, int, uintptr_t); +int fcntl(uintptr_t, int, uintptr_t); +int acct(uintptr_t); +int chdir(uintptr_t); +int chroot(uintptr_t); +int close(int); +int dup(int); +void exit(int); +int faccessat(int, uintptr_t, unsigned int, int); +int fchdir(int); +int fchmod(int, unsigned int); +int fchmodat(int, uintptr_t, unsigned int, int); +int fchownat(int, uintptr_t, int, int, int); +int fdatasync(int); +int fsync(int); +int getpgid(int); +int getpgrp(); +int getpid(); +int getppid(); +int getpriority(int, int); +int getrusage(int, uintptr_t); +int getsid(int); +int kill(int, int); +int syslog(int, uintptr_t, size_t); +int mkdir(int, uintptr_t, unsigned int); +int mkdirat(int, uintptr_t, unsigned int); +int mkfifo(uintptr_t, unsigned int); +int mknod(uintptr_t, unsigned int, int); +int mknodat(int, uintptr_t, unsigned int, int); +int nanosleep(uintptr_t, uintptr_t); +int open64(uintptr_t, int, unsigned int); +int openat(int, uintptr_t, int, unsigned int); +int read(int, uintptr_t, size_t); +int readlink(uintptr_t, uintptr_t, size_t); +int renameat(int, uintptr_t, int, uintptr_t); +int setdomainname(uintptr_t, size_t); +int sethostname(uintptr_t, size_t); +int setpgid(int, int); +int setsid(); +int settimeofday(uintptr_t); +int setuid(int); +int setgid(int); +int setpriority(int, int, int); +int statx(int, uintptr_t, int, int, uintptr_t); +int sync(); +uintptr_t times(uintptr_t); +int umask(int); +int uname(uintptr_t); +int unlink(uintptr_t); +int unlinkat(int, uintptr_t, int); +int ustat(int, uintptr_t); +int write(int, uintptr_t, size_t); +int dup2(int, int); +int posix_fadvise64(int, long long, long long, int); +int fchown(int, int, int); +int fstat(int, uintptr_t); +int fstatat(int, uintptr_t, uintptr_t, int); +int fstatfs(int, uintptr_t); +int ftruncate(int, long long); +int getegid(); +int geteuid(); +int getgid(); +int getuid(); +int lchown(uintptr_t, int, int); +int listen(int, int); +int lstat(uintptr_t, uintptr_t); +int pause(); +int pread64(int, uintptr_t, size_t, long long); +int pwrite64(int, uintptr_t, size_t, long long); +int pselect(int, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t); +int setregid(int, int); +int setreuid(int, int); +int shutdown(int, int); +long long splice(int, uintptr_t, int, uintptr_t, int, int); +int stat(uintptr_t, uintptr_t); +int statfs(uintptr_t, uintptr_t); +int truncate(uintptr_t, long long); +int bind(int, uintptr_t, uintptr_t); +int connect(int, uintptr_t, uintptr_t); +int getgroups(int, uintptr_t); +int setgroups(int, uintptr_t); +int getsockopt(int, int, int, uintptr_t, uintptr_t); +int setsockopt(int, int, int, uintptr_t, uintptr_t); +int socket(int, int, int); +int socketpair(int, int, int, uintptr_t); +int getpeername(int, uintptr_t, uintptr_t); +int getsockname(int, uintptr_t, uintptr_t); +int recvfrom(int, uintptr_t, size_t, int, uintptr_t, uintptr_t); +int sendto(int, uintptr_t, size_t, int, uintptr_t, uintptr_t); +int recvmsg(int, uintptr_t, int); +int sendmsg(int, uintptr_t, int); +int munmap(uintptr_t, uintptr_t); +int madvise(uintptr_t, size_t, int); +int mprotect(uintptr_t, size_t, int); +int mlock(uintptr_t, size_t); +int mlockall(int); +int msync(uintptr_t, size_t, int); +int munlock(uintptr_t, size_t); +int munlockall(); +int pipe(uintptr_t); +int poll(uintptr_t, int, int); +int gettimeofday(uintptr_t, uintptr_t); +int time(uintptr_t); +int utime(uintptr_t, uintptr_t); +int getrlimit64(int, uintptr_t); +int setrlimit64(int, uintptr_t); +long long lseek64(int, long long, int); +uintptr_t mmap(uintptr_t, uintptr_t, int, int, int, long long); + +*/ +import "C" +import ( + "unsafe" +) + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func utimes(path string, times *[2]Timeval) (err error) { + _p0 := uintptr(unsafe.Pointer(C.CString(path))) + r0, er := C.utimes(C.uintptr_t(_p0), C.uintptr_t(uintptr(unsafe.Pointer(times)))) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func utimensat(dirfd int, path string, times *[2]Timespec, flag int) (err error) { + _p0 := uintptr(unsafe.Pointer(C.CString(path))) + r0, er := C.utimensat(C.int(dirfd), C.uintptr_t(_p0), C.uintptr_t(uintptr(unsafe.Pointer(times))), C.int(flag)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getcwd(buf []byte) (err error) { + var _p0 *byte + if len(buf) > 0 { + _p0 = &buf[0] + } + var _p1 int + _p1 = len(buf) + r0, er := C.getcwd(C.uintptr_t(uintptr(unsafe.Pointer(_p0))), C.size_t(_p1)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { + r0, er := C.accept(C.int(s), C.uintptr_t(uintptr(unsafe.Pointer(rsa))), C.uintptr_t(uintptr(unsafe.Pointer(addrlen)))) + fd = int(r0) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getdirent(fd int, buf []byte) (n int, err error) { + var _p0 *byte + if len(buf) > 0 { + _p0 = &buf[0] + } + var _p1 int + _p1 = len(buf) + r0, er := C.getdirent(C.int(fd), C.uintptr_t(uintptr(unsafe.Pointer(_p0))), C.size_t(_p1)) + n = int(r0) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func wait4(pid Pid_t, status *_C_int, options int, rusage *Rusage) (wpid Pid_t, err error) { + r0, er := C.wait4(C.int(pid), C.uintptr_t(uintptr(unsafe.Pointer(status))), C.int(options), C.uintptr_t(uintptr(unsafe.Pointer(rusage)))) + wpid = Pid_t(r0) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ioctl(fd int, req uint, arg uintptr) (err error) { + r0, er := C.ioctl(C.int(fd), C.int(req), C.uintptr_t(arg)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func FcntlInt(fd uintptr, cmd int, arg int) (r int, err error) { + r0, er := C.fcntl(C.uintptr_t(fd), C.int(cmd), C.uintptr_t(arg)) + r = int(r0) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) (err error) { + r0, er := C.fcntl(C.uintptr_t(fd), C.int(cmd), C.uintptr_t(uintptr(unsafe.Pointer(lk)))) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fcntl(fd int, cmd int, arg int) (val int, err error) { + r0, er := C.fcntl(C.uintptr_t(fd), C.int(cmd), C.uintptr_t(arg)) + val = int(r0) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Acct(path string) (err error) { + _p0 := uintptr(unsafe.Pointer(C.CString(path))) + r0, er := C.acct(C.uintptr_t(_p0)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chdir(path string) (err error) { + _p0 := uintptr(unsafe.Pointer(C.CString(path))) + r0, er := C.chdir(C.uintptr_t(_p0)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chroot(path string) (err error) { + _p0 := uintptr(unsafe.Pointer(C.CString(path))) + r0, er := C.chroot(C.uintptr_t(_p0)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Close(fd int) (err error) { + r0, er := C.close(C.int(fd)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Dup(oldfd int) (fd int, err error) { + r0, er := C.dup(C.int(oldfd)) + fd = int(r0) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Exit(code int) { + C.exit(C.int(code)) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { + _p0 := uintptr(unsafe.Pointer(C.CString(path))) + r0, er := C.faccessat(C.int(dirfd), C.uintptr_t(_p0), C.uint(mode), C.int(flags)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchdir(fd int) (err error) { + r0, er := C.fchdir(C.int(fd)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchmod(fd int, mode uint32) (err error) { + r0, er := C.fchmod(C.int(fd), C.uint(mode)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { + _p0 := uintptr(unsafe.Pointer(C.CString(path))) + r0, er := C.fchmodat(C.int(dirfd), C.uintptr_t(_p0), C.uint(mode), C.int(flags)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { + _p0 := uintptr(unsafe.Pointer(C.CString(path))) + r0, er := C.fchownat(C.int(dirfd), C.uintptr_t(_p0), C.int(uid), C.int(gid), C.int(flags)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fdatasync(fd int) (err error) { + r0, er := C.fdatasync(C.int(fd)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fsync(fd int) (err error) { + r0, er := C.fsync(C.int(fd)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpgid(pid int) (pgid int, err error) { + r0, er := C.getpgid(C.int(pid)) + pgid = int(r0) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpgrp() (pid int) { + r0, _ := C.getpgrp() + pid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpid() (pid int) { + r0, _ := C.getpid() + pid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getppid() (ppid int) { + r0, _ := C.getppid() + ppid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpriority(which int, who int) (prio int, err error) { + r0, er := C.getpriority(C.int(which), C.int(who)) + prio = int(r0) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getrusage(who int, rusage *Rusage) (err error) { + r0, er := C.getrusage(C.int(who), C.uintptr_t(uintptr(unsafe.Pointer(rusage)))) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getsid(pid int) (sid int, err error) { + r0, er := C.getsid(C.int(pid)) + sid = int(r0) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Kill(pid int, sig Signal) (err error) { + r0, er := C.kill(C.int(pid), C.int(sig)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Klogctl(typ int, buf []byte) (n int, err error) { + var _p0 *byte + if len(buf) > 0 { + _p0 = &buf[0] + } + var _p1 int + _p1 = len(buf) + r0, er := C.syslog(C.int(typ), C.uintptr_t(uintptr(unsafe.Pointer(_p0))), C.size_t(_p1)) + n = int(r0) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mkdir(dirfd int, path string, mode uint32) (err error) { + _p0 := uintptr(unsafe.Pointer(C.CString(path))) + r0, er := C.mkdir(C.int(dirfd), C.uintptr_t(_p0), C.uint(mode)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mkdirat(dirfd int, path string, mode uint32) (err error) { + _p0 := uintptr(unsafe.Pointer(C.CString(path))) + r0, er := C.mkdirat(C.int(dirfd), C.uintptr_t(_p0), C.uint(mode)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mkfifo(path string, mode uint32) (err error) { + _p0 := uintptr(unsafe.Pointer(C.CString(path))) + r0, er := C.mkfifo(C.uintptr_t(_p0), C.uint(mode)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mknod(path string, mode uint32, dev int) (err error) { + _p0 := uintptr(unsafe.Pointer(C.CString(path))) + r0, er := C.mknod(C.uintptr_t(_p0), C.uint(mode), C.int(dev)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) { + _p0 := uintptr(unsafe.Pointer(C.CString(path))) + r0, er := C.mknodat(C.int(dirfd), C.uintptr_t(_p0), C.uint(mode), C.int(dev)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Nanosleep(time *Timespec, leftover *Timespec) (err error) { + r0, er := C.nanosleep(C.uintptr_t(uintptr(unsafe.Pointer(time))), C.uintptr_t(uintptr(unsafe.Pointer(leftover)))) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Open(path string, mode int, perm uint32) (fd int, err error) { + _p0 := uintptr(unsafe.Pointer(C.CString(path))) + r0, er := C.open64(C.uintptr_t(_p0), C.int(mode), C.uint(perm)) + fd = int(r0) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) { + _p0 := uintptr(unsafe.Pointer(C.CString(path))) + r0, er := C.openat(C.int(dirfd), C.uintptr_t(_p0), C.int(flags), C.uint(mode)) + fd = int(r0) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func read(fd int, p []byte) (n int, err error) { + var _p0 *byte + if len(p) > 0 { + _p0 = &p[0] + } + var _p1 int + _p1 = len(p) + r0, er := C.read(C.int(fd), C.uintptr_t(uintptr(unsafe.Pointer(_p0))), C.size_t(_p1)) + n = int(r0) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Readlink(path string, buf []byte) (n int, err error) { + _p0 := uintptr(unsafe.Pointer(C.CString(path))) + var _p1 *byte + if len(buf) > 0 { + _p1 = &buf[0] + } + var _p2 int + _p2 = len(buf) + r0, er := C.readlink(C.uintptr_t(_p0), C.uintptr_t(uintptr(unsafe.Pointer(_p1))), C.size_t(_p2)) + n = int(r0) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { + _p0 := uintptr(unsafe.Pointer(C.CString(oldpath))) + _p1 := uintptr(unsafe.Pointer(C.CString(newpath))) + r0, er := C.renameat(C.int(olddirfd), C.uintptr_t(_p0), C.int(newdirfd), C.uintptr_t(_p1)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setdomainname(p []byte) (err error) { + var _p0 *byte + if len(p) > 0 { + _p0 = &p[0] + } + var _p1 int + _p1 = len(p) + r0, er := C.setdomainname(C.uintptr_t(uintptr(unsafe.Pointer(_p0))), C.size_t(_p1)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Sethostname(p []byte) (err error) { + var _p0 *byte + if len(p) > 0 { + _p0 = &p[0] + } + var _p1 int + _p1 = len(p) + r0, er := C.sethostname(C.uintptr_t(uintptr(unsafe.Pointer(_p0))), C.size_t(_p1)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setpgid(pid int, pgid int) (err error) { + r0, er := C.setpgid(C.int(pid), C.int(pgid)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setsid() (pid int, err error) { + r0, er := C.setsid() + pid = int(r0) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Settimeofday(tv *Timeval) (err error) { + r0, er := C.settimeofday(C.uintptr_t(uintptr(unsafe.Pointer(tv)))) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setuid(uid int) (err error) { + r0, er := C.setuid(C.int(uid)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setgid(uid int) (err error) { + r0, er := C.setgid(C.int(uid)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setpriority(which int, who int, prio int) (err error) { + r0, er := C.setpriority(C.int(which), C.int(who), C.int(prio)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Statx(dirfd int, path string, flags int, mask int, stat *Statx_t) (err error) { + _p0 := uintptr(unsafe.Pointer(C.CString(path))) + r0, er := C.statx(C.int(dirfd), C.uintptr_t(_p0), C.int(flags), C.int(mask), C.uintptr_t(uintptr(unsafe.Pointer(stat)))) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Sync() { + C.sync() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Times(tms *Tms) (ticks uintptr, err error) { + r0, er := C.times(C.uintptr_t(uintptr(unsafe.Pointer(tms)))) + ticks = uintptr(r0) + if uintptr(r0) == ^uintptr(0) && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Umask(mask int) (oldmask int) { + r0, _ := C.umask(C.int(mask)) + oldmask = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Uname(buf *Utsname) (err error) { + r0, er := C.uname(C.uintptr_t(uintptr(unsafe.Pointer(buf)))) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Unlink(path string) (err error) { + _p0 := uintptr(unsafe.Pointer(C.CString(path))) + r0, er := C.unlink(C.uintptr_t(_p0)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Unlinkat(dirfd int, path string, flags int) (err error) { + _p0 := uintptr(unsafe.Pointer(C.CString(path))) + r0, er := C.unlinkat(C.int(dirfd), C.uintptr_t(_p0), C.int(flags)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Ustat(dev int, ubuf *Ustat_t) (err error) { + r0, er := C.ustat(C.int(dev), C.uintptr_t(uintptr(unsafe.Pointer(ubuf)))) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func write(fd int, p []byte) (n int, err error) { + var _p0 *byte + if len(p) > 0 { + _p0 = &p[0] + } + var _p1 int + _p1 = len(p) + r0, er := C.write(C.int(fd), C.uintptr_t(uintptr(unsafe.Pointer(_p0))), C.size_t(_p1)) + n = int(r0) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func readlen(fd int, p *byte, np int) (n int, err error) { + r0, er := C.read(C.int(fd), C.uintptr_t(uintptr(unsafe.Pointer(p))), C.size_t(np)) + n = int(r0) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func writelen(fd int, p *byte, np int) (n int, err error) { + r0, er := C.write(C.int(fd), C.uintptr_t(uintptr(unsafe.Pointer(p))), C.size_t(np)) + n = int(r0) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Dup2(oldfd int, newfd int) (err error) { + r0, er := C.dup2(C.int(oldfd), C.int(newfd)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fadvise(fd int, offset int64, length int64, advice int) (err error) { + r0, er := C.posix_fadvise64(C.int(fd), C.longlong(offset), C.longlong(length), C.int(advice)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchown(fd int, uid int, gid int) (err error) { + r0, er := C.fchown(C.int(fd), C.int(uid), C.int(gid)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstat(fd int, stat *Stat_t) (err error) { + r0, er := C.fstat(C.int(fd), C.uintptr_t(uintptr(unsafe.Pointer(stat)))) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) { + _p0 := uintptr(unsafe.Pointer(C.CString(path))) + r0, er := C.fstatat(C.int(dirfd), C.uintptr_t(_p0), C.uintptr_t(uintptr(unsafe.Pointer(stat))), C.int(flags)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstatfs(fd int, buf *Statfs_t) (err error) { + r0, er := C.fstatfs(C.int(fd), C.uintptr_t(uintptr(unsafe.Pointer(buf)))) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Ftruncate(fd int, length int64) (err error) { + r0, er := C.ftruncate(C.int(fd), C.longlong(length)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getegid() (egid int) { + r0, _ := C.getegid() + egid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Geteuid() (euid int) { + r0, _ := C.geteuid() + euid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getgid() (gid int) { + r0, _ := C.getgid() + gid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getuid() (uid int) { + r0, _ := C.getuid() + uid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Lchown(path string, uid int, gid int) (err error) { + _p0 := uintptr(unsafe.Pointer(C.CString(path))) + r0, er := C.lchown(C.uintptr_t(_p0), C.int(uid), C.int(gid)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Listen(s int, n int) (err error) { + r0, er := C.listen(C.int(s), C.int(n)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Lstat(path string, stat *Stat_t) (err error) { + _p0 := uintptr(unsafe.Pointer(C.CString(path))) + r0, er := C.lstat(C.uintptr_t(_p0), C.uintptr_t(uintptr(unsafe.Pointer(stat)))) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pause() (err error) { + r0, er := C.pause() + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pread(fd int, p []byte, offset int64) (n int, err error) { + var _p0 *byte + if len(p) > 0 { + _p0 = &p[0] + } + var _p1 int + _p1 = len(p) + r0, er := C.pread64(C.int(fd), C.uintptr_t(uintptr(unsafe.Pointer(_p0))), C.size_t(_p1), C.longlong(offset)) + n = int(r0) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pwrite(fd int, p []byte, offset int64) (n int, err error) { + var _p0 *byte + if len(p) > 0 { + _p0 = &p[0] + } + var _p1 int + _p1 = len(p) + r0, er := C.pwrite64(C.int(fd), C.uintptr_t(uintptr(unsafe.Pointer(_p0))), C.size_t(_p1), C.longlong(offset)) + n = int(r0) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pselect(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *Sigset_t) (n int, err error) { + r0, er := C.pselect(C.int(nfd), C.uintptr_t(uintptr(unsafe.Pointer(r))), C.uintptr_t(uintptr(unsafe.Pointer(w))), C.uintptr_t(uintptr(unsafe.Pointer(e))), C.uintptr_t(uintptr(unsafe.Pointer(timeout))), C.uintptr_t(uintptr(unsafe.Pointer(sigmask)))) + n = int(r0) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setregid(rgid int, egid int) (err error) { + r0, er := C.setregid(C.int(rgid), C.int(egid)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setreuid(ruid int, euid int) (err error) { + r0, er := C.setreuid(C.int(ruid), C.int(euid)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Shutdown(fd int, how int) (err error) { + r0, er := C.shutdown(C.int(fd), C.int(how)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error) { + r0, er := C.splice(C.int(rfd), C.uintptr_t(uintptr(unsafe.Pointer(roff))), C.int(wfd), C.uintptr_t(uintptr(unsafe.Pointer(woff))), C.int(len), C.int(flags)) + n = int64(r0) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Stat(path string, stat *Stat_t) (err error) { + _p0 := uintptr(unsafe.Pointer(C.CString(path))) + r0, er := C.stat(C.uintptr_t(_p0), C.uintptr_t(uintptr(unsafe.Pointer(stat)))) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Statfs(path string, buf *Statfs_t) (err error) { + _p0 := uintptr(unsafe.Pointer(C.CString(path))) + r0, er := C.statfs(C.uintptr_t(_p0), C.uintptr_t(uintptr(unsafe.Pointer(buf)))) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Truncate(path string, length int64) (err error) { + _p0 := uintptr(unsafe.Pointer(C.CString(path))) + r0, er := C.truncate(C.uintptr_t(_p0), C.longlong(length)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { + r0, er := C.bind(C.int(s), C.uintptr_t(uintptr(addr)), C.uintptr_t(uintptr(addrlen))) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { + r0, er := C.connect(C.int(s), C.uintptr_t(uintptr(addr)), C.uintptr_t(uintptr(addrlen))) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getgroups(n int, list *_Gid_t) (nn int, err error) { + r0, er := C.getgroups(C.int(n), C.uintptr_t(uintptr(unsafe.Pointer(list)))) + nn = int(r0) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setgroups(n int, list *_Gid_t) (err error) { + r0, er := C.setgroups(C.int(n), C.uintptr_t(uintptr(unsafe.Pointer(list)))) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) { + r0, er := C.getsockopt(C.int(s), C.int(level), C.int(name), C.uintptr_t(uintptr(val)), C.uintptr_t(uintptr(unsafe.Pointer(vallen)))) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) { + r0, er := C.setsockopt(C.int(s), C.int(level), C.int(name), C.uintptr_t(uintptr(val)), C.uintptr_t(vallen)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func socket(domain int, typ int, proto int) (fd int, err error) { + r0, er := C.socket(C.int(domain), C.int(typ), C.int(proto)) + fd = int(r0) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) { + r0, er := C.socketpair(C.int(domain), C.int(typ), C.int(proto), C.uintptr_t(uintptr(unsafe.Pointer(fd)))) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { + r0, er := C.getpeername(C.int(fd), C.uintptr_t(uintptr(unsafe.Pointer(rsa))), C.uintptr_t(uintptr(unsafe.Pointer(addrlen)))) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { + r0, er := C.getsockname(C.int(fd), C.uintptr_t(uintptr(unsafe.Pointer(rsa))), C.uintptr_t(uintptr(unsafe.Pointer(addrlen)))) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) { + var _p0 *byte + if len(p) > 0 { + _p0 = &p[0] + } + var _p1 int + _p1 = len(p) + r0, er := C.recvfrom(C.int(fd), C.uintptr_t(uintptr(unsafe.Pointer(_p0))), C.size_t(_p1), C.int(flags), C.uintptr_t(uintptr(unsafe.Pointer(from))), C.uintptr_t(uintptr(unsafe.Pointer(fromlen)))) + n = int(r0) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) { + var _p0 *byte + if len(buf) > 0 { + _p0 = &buf[0] + } + var _p1 int + _p1 = len(buf) + r0, er := C.sendto(C.int(s), C.uintptr_t(uintptr(unsafe.Pointer(_p0))), C.size_t(_p1), C.int(flags), C.uintptr_t(uintptr(to)), C.uintptr_t(uintptr(addrlen))) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) { + r0, er := C.recvmsg(C.int(s), C.uintptr_t(uintptr(unsafe.Pointer(msg))), C.int(flags)) + n = int(r0) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) { + r0, er := C.sendmsg(C.int(s), C.uintptr_t(uintptr(unsafe.Pointer(msg))), C.int(flags)) + n = int(r0) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func munmap(addr uintptr, length uintptr) (err error) { + r0, er := C.munmap(C.uintptr_t(addr), C.uintptr_t(length)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Madvise(b []byte, advice int) (err error) { + var _p0 *byte + if len(b) > 0 { + _p0 = &b[0] + } + var _p1 int + _p1 = len(b) + r0, er := C.madvise(C.uintptr_t(uintptr(unsafe.Pointer(_p0))), C.size_t(_p1), C.int(advice)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mprotect(b []byte, prot int) (err error) { + var _p0 *byte + if len(b) > 0 { + _p0 = &b[0] + } + var _p1 int + _p1 = len(b) + r0, er := C.mprotect(C.uintptr_t(uintptr(unsafe.Pointer(_p0))), C.size_t(_p1), C.int(prot)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mlock(b []byte) (err error) { + var _p0 *byte + if len(b) > 0 { + _p0 = &b[0] + } + var _p1 int + _p1 = len(b) + r0, er := C.mlock(C.uintptr_t(uintptr(unsafe.Pointer(_p0))), C.size_t(_p1)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mlockall(flags int) (err error) { + r0, er := C.mlockall(C.int(flags)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Msync(b []byte, flags int) (err error) { + var _p0 *byte + if len(b) > 0 { + _p0 = &b[0] + } + var _p1 int + _p1 = len(b) + r0, er := C.msync(C.uintptr_t(uintptr(unsafe.Pointer(_p0))), C.size_t(_p1), C.int(flags)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Munlock(b []byte) (err error) { + var _p0 *byte + if len(b) > 0 { + _p0 = &b[0] + } + var _p1 int + _p1 = len(b) + r0, er := C.munlock(C.uintptr_t(uintptr(unsafe.Pointer(_p0))), C.size_t(_p1)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Munlockall() (err error) { + r0, er := C.munlockall() + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func pipe(p *[2]_C_int) (err error) { + r0, er := C.pipe(C.uintptr_t(uintptr(unsafe.Pointer(p)))) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { + r0, er := C.poll(C.uintptr_t(uintptr(unsafe.Pointer(fds))), C.int(nfds), C.int(timeout)) + n = int(r0) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func gettimeofday(tv *Timeval, tzp *Timezone) (err error) { + r0, er := C.gettimeofday(C.uintptr_t(uintptr(unsafe.Pointer(tv))), C.uintptr_t(uintptr(unsafe.Pointer(tzp)))) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Time(t *Time_t) (tt Time_t, err error) { + r0, er := C.time(C.uintptr_t(uintptr(unsafe.Pointer(t)))) + tt = Time_t(r0) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Utime(path string, buf *Utimbuf) (err error) { + _p0 := uintptr(unsafe.Pointer(C.CString(path))) + r0, er := C.utime(C.uintptr_t(_p0), C.uintptr_t(uintptr(unsafe.Pointer(buf)))) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getrlimit(resource int, rlim *Rlimit) (err error) { + r0, er := C.getrlimit64(C.int(resource), C.uintptr_t(uintptr(unsafe.Pointer(rlim)))) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setrlimit(resource int, rlim *Rlimit) (err error) { + r0, er := C.setrlimit64(C.int(resource), C.uintptr_t(uintptr(unsafe.Pointer(rlim)))) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Seek(fd int, offset int64, whence int) (off int64, err error) { + r0, er := C.lseek64(C.int(fd), C.longlong(offset), C.int(whence)) + off = int64(r0) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) { + r0, er := C.mmap(C.uintptr_t(addr), C.uintptr_t(length), C.int(prot), C.int(flags), C.int(fd), C.longlong(offset)) + xaddr = uintptr(r0) + if uintptr(r0) == ^uintptr(0) && er != nil { + err = er + } + return +} diff --git a/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64.go b/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64.go new file mode 100644 index 0000000000..e645a05cbe --- /dev/null +++ b/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64.go @@ -0,0 +1,1408 @@ +// go run mksyscall_aix_ppc64.go -aix -tags aix,ppc64 syscall_aix.go syscall_aix_ppc64.go +// Code generated by the command above; see README.md. DO NOT EDIT. + +// +build aix,ppc64 + +package unix + +import ( + "unsafe" +) + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func utimes(path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, e1 := callutimes(uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func utimensat(dirfd int, path string, times *[2]Timespec, flag int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, e1 := callutimensat(dirfd, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), flag) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getcwd(buf []byte) (err error) { + var _p0 *byte + if len(buf) > 0 { + _p0 = &buf[0] + } + _, e1 := callgetcwd(uintptr(unsafe.Pointer(_p0)), len(buf)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { + r0, e1 := callaccept(s, uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getdirent(fd int, buf []byte) (n int, err error) { + var _p0 *byte + if len(buf) > 0 { + _p0 = &buf[0] + } + r0, e1 := callgetdirent(fd, uintptr(unsafe.Pointer(_p0)), len(buf)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func wait4(pid Pid_t, status *_C_int, options int, rusage *Rusage) (wpid Pid_t, err error) { + r0, e1 := callwait4(int(pid), uintptr(unsafe.Pointer(status)), options, uintptr(unsafe.Pointer(rusage))) + wpid = Pid_t(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ioctl(fd int, req uint, arg uintptr) (err error) { + _, e1 := callioctl(fd, int(req), arg) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func FcntlInt(fd uintptr, cmd int, arg int) (r int, err error) { + r0, e1 := callfcntl(fd, cmd, uintptr(arg)) + r = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) (err error) { + _, e1 := callfcntl(fd, cmd, uintptr(unsafe.Pointer(lk))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fcntl(fd int, cmd int, arg int) (val int, err error) { + r0, e1 := callfcntl(uintptr(fd), cmd, uintptr(arg)) + val = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Acct(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, e1 := callacct(uintptr(unsafe.Pointer(_p0))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chdir(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, e1 := callchdir(uintptr(unsafe.Pointer(_p0))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chroot(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, e1 := callchroot(uintptr(unsafe.Pointer(_p0))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Close(fd int) (err error) { + _, e1 := callclose(fd) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Dup(oldfd int) (fd int, err error) { + r0, e1 := calldup(oldfd) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Exit(code int) { + callexit(code) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, e1 := callfaccessat(dirfd, uintptr(unsafe.Pointer(_p0)), mode, flags) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchdir(fd int) (err error) { + _, e1 := callfchdir(fd) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchmod(fd int, mode uint32) (err error) { + _, e1 := callfchmod(fd, mode) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, e1 := callfchmodat(dirfd, uintptr(unsafe.Pointer(_p0)), mode, flags) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, e1 := callfchownat(dirfd, uintptr(unsafe.Pointer(_p0)), uid, gid, flags) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fdatasync(fd int) (err error) { + _, e1 := callfdatasync(fd) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fsync(fd int) (err error) { + _, e1 := callfsync(fd) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpgid(pid int) (pgid int, err error) { + r0, e1 := callgetpgid(pid) + pgid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpgrp() (pid int) { + r0, _ := callgetpgrp() + pid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpid() (pid int) { + r0, _ := callgetpid() + pid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getppid() (ppid int) { + r0, _ := callgetppid() + ppid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpriority(which int, who int) (prio int, err error) { + r0, e1 := callgetpriority(which, who) + prio = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getrusage(who int, rusage *Rusage) (err error) { + _, e1 := callgetrusage(who, uintptr(unsafe.Pointer(rusage))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getsid(pid int) (sid int, err error) { + r0, e1 := callgetsid(pid) + sid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Kill(pid int, sig Signal) (err error) { + _, e1 := callkill(pid, int(sig)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Klogctl(typ int, buf []byte) (n int, err error) { + var _p0 *byte + if len(buf) > 0 { + _p0 = &buf[0] + } + r0, e1 := callsyslog(typ, uintptr(unsafe.Pointer(_p0)), len(buf)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mkdir(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, e1 := callmkdir(dirfd, uintptr(unsafe.Pointer(_p0)), mode) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mkdirat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, e1 := callmkdirat(dirfd, uintptr(unsafe.Pointer(_p0)), mode) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mkfifo(path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, e1 := callmkfifo(uintptr(unsafe.Pointer(_p0)), mode) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mknod(path string, mode uint32, dev int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, e1 := callmknod(uintptr(unsafe.Pointer(_p0)), mode, dev) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, e1 := callmknodat(dirfd, uintptr(unsafe.Pointer(_p0)), mode, dev) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Nanosleep(time *Timespec, leftover *Timespec) (err error) { + _, e1 := callnanosleep(uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Open(path string, mode int, perm uint32) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, e1 := callopen64(uintptr(unsafe.Pointer(_p0)), mode, perm) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, e1 := callopenat(dirfd, uintptr(unsafe.Pointer(_p0)), flags, mode) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func read(fd int, p []byte) (n int, err error) { + var _p0 *byte + if len(p) > 0 { + _p0 = &p[0] + } + r0, e1 := callread(fd, uintptr(unsafe.Pointer(_p0)), len(p)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Readlink(path string, buf []byte) (n int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + if len(buf) > 0 { + _p1 = &buf[0] + } + r0, e1 := callreadlink(uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), len(buf)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, e1 := callrenameat(olddirfd, uintptr(unsafe.Pointer(_p0)), newdirfd, uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setdomainname(p []byte) (err error) { + var _p0 *byte + if len(p) > 0 { + _p0 = &p[0] + } + _, e1 := callsetdomainname(uintptr(unsafe.Pointer(_p0)), len(p)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Sethostname(p []byte) (err error) { + var _p0 *byte + if len(p) > 0 { + _p0 = &p[0] + } + _, e1 := callsethostname(uintptr(unsafe.Pointer(_p0)), len(p)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setpgid(pid int, pgid int) (err error) { + _, e1 := callsetpgid(pid, pgid) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setsid() (pid int, err error) { + r0, e1 := callsetsid() + pid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Settimeofday(tv *Timeval) (err error) { + _, e1 := callsettimeofday(uintptr(unsafe.Pointer(tv))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setuid(uid int) (err error) { + _, e1 := callsetuid(uid) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setgid(uid int) (err error) { + _, e1 := callsetgid(uid) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setpriority(which int, who int, prio int) (err error) { + _, e1 := callsetpriority(which, who, prio) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Statx(dirfd int, path string, flags int, mask int, stat *Statx_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, e1 := callstatx(dirfd, uintptr(unsafe.Pointer(_p0)), flags, mask, uintptr(unsafe.Pointer(stat))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Sync() { + callsync() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Times(tms *Tms) (ticks uintptr, err error) { + r0, e1 := calltimes(uintptr(unsafe.Pointer(tms))) + ticks = uintptr(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Umask(mask int) (oldmask int) { + r0, _ := callumask(mask) + oldmask = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Uname(buf *Utsname) (err error) { + _, e1 := calluname(uintptr(unsafe.Pointer(buf))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Unlink(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, e1 := callunlink(uintptr(unsafe.Pointer(_p0))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Unlinkat(dirfd int, path string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, e1 := callunlinkat(dirfd, uintptr(unsafe.Pointer(_p0)), flags) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Ustat(dev int, ubuf *Ustat_t) (err error) { + _, e1 := callustat(dev, uintptr(unsafe.Pointer(ubuf))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func write(fd int, p []byte) (n int, err error) { + var _p0 *byte + if len(p) > 0 { + _p0 = &p[0] + } + r0, e1 := callwrite(fd, uintptr(unsafe.Pointer(_p0)), len(p)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func readlen(fd int, p *byte, np int) (n int, err error) { + r0, e1 := callread(fd, uintptr(unsafe.Pointer(p)), np) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func writelen(fd int, p *byte, np int) (n int, err error) { + r0, e1 := callwrite(fd, uintptr(unsafe.Pointer(p)), np) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Dup2(oldfd int, newfd int) (err error) { + _, e1 := calldup2(oldfd, newfd) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fadvise(fd int, offset int64, length int64, advice int) (err error) { + _, e1 := callposix_fadvise64(fd, offset, length, advice) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchown(fd int, uid int, gid int) (err error) { + _, e1 := callfchown(fd, uid, gid) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstat(fd int, stat *Stat_t) (err error) { + _, e1 := callfstat(fd, uintptr(unsafe.Pointer(stat))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, e1 := callfstatat(dirfd, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), flags) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstatfs(fd int, buf *Statfs_t) (err error) { + _, e1 := callfstatfs(fd, uintptr(unsafe.Pointer(buf))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Ftruncate(fd int, length int64) (err error) { + _, e1 := callftruncate(fd, length) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getegid() (egid int) { + r0, _ := callgetegid() + egid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Geteuid() (euid int) { + r0, _ := callgeteuid() + euid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getgid() (gid int) { + r0, _ := callgetgid() + gid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getuid() (uid int) { + r0, _ := callgetuid() + uid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Lchown(path string, uid int, gid int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, e1 := calllchown(uintptr(unsafe.Pointer(_p0)), uid, gid) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Listen(s int, n int) (err error) { + _, e1 := calllisten(s, n) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Lstat(path string, stat *Stat_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, e1 := calllstat(uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pause() (err error) { + _, e1 := callpause() + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pread(fd int, p []byte, offset int64) (n int, err error) { + var _p0 *byte + if len(p) > 0 { + _p0 = &p[0] + } + r0, e1 := callpread64(fd, uintptr(unsafe.Pointer(_p0)), len(p), offset) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pwrite(fd int, p []byte, offset int64) (n int, err error) { + var _p0 *byte + if len(p) > 0 { + _p0 = &p[0] + } + r0, e1 := callpwrite64(fd, uintptr(unsafe.Pointer(_p0)), len(p), offset) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pselect(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *Sigset_t) (n int, err error) { + r0, e1 := callpselect(nfd, uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setregid(rgid int, egid int) (err error) { + _, e1 := callsetregid(rgid, egid) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setreuid(ruid int, euid int) (err error) { + _, e1 := callsetreuid(ruid, euid) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Shutdown(fd int, how int) (err error) { + _, e1 := callshutdown(fd, how) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error) { + r0, e1 := callsplice(rfd, uintptr(unsafe.Pointer(roff)), wfd, uintptr(unsafe.Pointer(woff)), len, flags) + n = int64(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Stat(path string, stat *Stat_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, e1 := callstat(uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Statfs(path string, buf *Statfs_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, e1 := callstatfs(uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Truncate(path string, length int64) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, e1 := calltruncate(uintptr(unsafe.Pointer(_p0)), length) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { + _, e1 := callbind(s, uintptr(addr), uintptr(addrlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { + _, e1 := callconnect(s, uintptr(addr), uintptr(addrlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getgroups(n int, list *_Gid_t) (nn int, err error) { + r0, e1 := callgetgroups(n, uintptr(unsafe.Pointer(list))) + nn = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setgroups(n int, list *_Gid_t) (err error) { + _, e1 := callsetgroups(n, uintptr(unsafe.Pointer(list))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) { + _, e1 := callgetsockopt(s, level, name, uintptr(val), uintptr(unsafe.Pointer(vallen))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) { + _, e1 := callsetsockopt(s, level, name, uintptr(val), vallen) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func socket(domain int, typ int, proto int) (fd int, err error) { + r0, e1 := callsocket(domain, typ, proto) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) { + _, e1 := callsocketpair(domain, typ, proto, uintptr(unsafe.Pointer(fd))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { + _, e1 := callgetpeername(fd, uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { + _, e1 := callgetsockname(fd, uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) { + var _p0 *byte + if len(p) > 0 { + _p0 = &p[0] + } + r0, e1 := callrecvfrom(fd, uintptr(unsafe.Pointer(_p0)), len(p), flags, uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) { + var _p0 *byte + if len(buf) > 0 { + _p0 = &buf[0] + } + _, e1 := callsendto(s, uintptr(unsafe.Pointer(_p0)), len(buf), flags, uintptr(to), uintptr(addrlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) { + r0, e1 := callrecvmsg(s, uintptr(unsafe.Pointer(msg)), flags) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) { + r0, e1 := callsendmsg(s, uintptr(unsafe.Pointer(msg)), flags) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func munmap(addr uintptr, length uintptr) (err error) { + _, e1 := callmunmap(addr, length) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Madvise(b []byte, advice int) (err error) { + var _p0 *byte + if len(b) > 0 { + _p0 = &b[0] + } + _, e1 := callmadvise(uintptr(unsafe.Pointer(_p0)), len(b), advice) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mprotect(b []byte, prot int) (err error) { + var _p0 *byte + if len(b) > 0 { + _p0 = &b[0] + } + _, e1 := callmprotect(uintptr(unsafe.Pointer(_p0)), len(b), prot) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mlock(b []byte) (err error) { + var _p0 *byte + if len(b) > 0 { + _p0 = &b[0] + } + _, e1 := callmlock(uintptr(unsafe.Pointer(_p0)), len(b)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mlockall(flags int) (err error) { + _, e1 := callmlockall(flags) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Msync(b []byte, flags int) (err error) { + var _p0 *byte + if len(b) > 0 { + _p0 = &b[0] + } + _, e1 := callmsync(uintptr(unsafe.Pointer(_p0)), len(b), flags) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Munlock(b []byte) (err error) { + var _p0 *byte + if len(b) > 0 { + _p0 = &b[0] + } + _, e1 := callmunlock(uintptr(unsafe.Pointer(_p0)), len(b)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Munlockall() (err error) { + _, e1 := callmunlockall() + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func pipe(p *[2]_C_int) (err error) { + _, e1 := callpipe(uintptr(unsafe.Pointer(p))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { + r0, e1 := callpoll(uintptr(unsafe.Pointer(fds)), nfds, timeout) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func gettimeofday(tv *Timeval, tzp *Timezone) (err error) { + _, e1 := callgettimeofday(uintptr(unsafe.Pointer(tv)), uintptr(unsafe.Pointer(tzp))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Time(t *Time_t) (tt Time_t, err error) { + r0, e1 := calltime(uintptr(unsafe.Pointer(t))) + tt = Time_t(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Utime(path string, buf *Utimbuf) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, e1 := callutime(uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getrlimit(resource int, rlim *Rlimit) (err error) { + _, e1 := callgetrlimit(resource, uintptr(unsafe.Pointer(rlim))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setrlimit(resource int, rlim *Rlimit) (err error) { + _, e1 := callsetrlimit(resource, uintptr(unsafe.Pointer(rlim))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Seek(fd int, offset int64, whence int) (off int64, err error) { + r0, e1 := calllseek(fd, offset, whence) + off = int64(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) { + r0, e1 := callmmap64(addr, length, prot, flags, fd, offset) + xaddr = uintptr(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gc.go b/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gc.go new file mode 100644 index 0000000000..0b8eb72102 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gc.go @@ -0,0 +1,1162 @@ +// go run mksyscall_aix_ppc64.go -aix -tags aix,ppc64 syscall_aix.go syscall_aix_ppc64.go +// Code generated by the command above; see README.md. DO NOT EDIT. + +// +build aix,ppc64 +// +build !gccgo + +package unix + +import ( + "unsafe" +) + +//go:cgo_import_dynamic libc_utimes utimes "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_utimensat utimensat "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_getcwd getcwd "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_accept accept "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_getdirent getdirent "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_wait4 wait4 "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_ioctl ioctl "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_fcntl fcntl "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_acct acct "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_chdir chdir "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_chroot chroot "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_close close "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_dup dup "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_exit exit "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_faccessat faccessat "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_fchdir fchdir "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_fchmod fchmod "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_fchmodat fchmodat "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_fchownat fchownat "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_fdatasync fdatasync "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_fsync fsync "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_getpgid getpgid "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_getpgrp getpgrp "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_getpid getpid "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_getppid getppid "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_getpriority getpriority "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_getrusage getrusage "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_getsid getsid "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_kill kill "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_syslog syslog "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_mkdir mkdir "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_mkdirat mkdirat "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_mkfifo mkfifo "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_mknod mknod "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_mknodat mknodat "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_nanosleep nanosleep "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_open64 open64 "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_openat openat "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_read read "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_readlink readlink "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_renameat renameat "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_setdomainname setdomainname "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_sethostname sethostname "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_setpgid setpgid "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_setsid setsid "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_settimeofday settimeofday "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_setuid setuid "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_setgid setgid "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_setpriority setpriority "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_statx statx "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_sync sync "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_times times "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_umask umask "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_uname uname "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_unlink unlink "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_unlinkat unlinkat "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_ustat ustat "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_write write "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_dup2 dup2 "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_posix_fadvise64 posix_fadvise64 "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_fchown fchown "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_fstat fstat "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_fstatat fstatat "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_fstatfs fstatfs "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_ftruncate ftruncate "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_getegid getegid "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_geteuid geteuid "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_getgid getgid "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_getuid getuid "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_lchown lchown "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_listen listen "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_lstat lstat "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_pause pause "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_pread64 pread64 "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_pwrite64 pwrite64 "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_pselect pselect "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_setregid setregid "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_setreuid setreuid "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_shutdown shutdown "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_splice splice "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_stat stat "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_statfs statfs "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_truncate truncate "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_bind bind "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_connect connect "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_getgroups getgroups "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_setgroups setgroups "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_getsockopt getsockopt "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_setsockopt setsockopt "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_socket socket "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_socketpair socketpair "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_getpeername getpeername "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_getsockname getsockname "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_recvfrom recvfrom "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_sendto sendto "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_recvmsg recvmsg "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_sendmsg sendmsg "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_munmap munmap "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_madvise madvise "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_mprotect mprotect "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_mlock mlock "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_mlockall mlockall "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_msync msync "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_munlock munlock "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_munlockall munlockall "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_pipe pipe "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_poll poll "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_gettimeofday gettimeofday "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_time time "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_utime utime "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_getrlimit getrlimit "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_setrlimit setrlimit "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_lseek lseek "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_mmap64 mmap64 "libc.a/shr_64.o" + +//go:linkname libc_utimes libc_utimes +//go:linkname libc_utimensat libc_utimensat +//go:linkname libc_getcwd libc_getcwd +//go:linkname libc_accept libc_accept +//go:linkname libc_getdirent libc_getdirent +//go:linkname libc_wait4 libc_wait4 +//go:linkname libc_ioctl libc_ioctl +//go:linkname libc_fcntl libc_fcntl +//go:linkname libc_acct libc_acct +//go:linkname libc_chdir libc_chdir +//go:linkname libc_chroot libc_chroot +//go:linkname libc_close libc_close +//go:linkname libc_dup libc_dup +//go:linkname libc_exit libc_exit +//go:linkname libc_faccessat libc_faccessat +//go:linkname libc_fchdir libc_fchdir +//go:linkname libc_fchmod libc_fchmod +//go:linkname libc_fchmodat libc_fchmodat +//go:linkname libc_fchownat libc_fchownat +//go:linkname libc_fdatasync libc_fdatasync +//go:linkname libc_fsync libc_fsync +//go:linkname libc_getpgid libc_getpgid +//go:linkname libc_getpgrp libc_getpgrp +//go:linkname libc_getpid libc_getpid +//go:linkname libc_getppid libc_getppid +//go:linkname libc_getpriority libc_getpriority +//go:linkname libc_getrusage libc_getrusage +//go:linkname libc_getsid libc_getsid +//go:linkname libc_kill libc_kill +//go:linkname libc_syslog libc_syslog +//go:linkname libc_mkdir libc_mkdir +//go:linkname libc_mkdirat libc_mkdirat +//go:linkname libc_mkfifo libc_mkfifo +//go:linkname libc_mknod libc_mknod +//go:linkname libc_mknodat libc_mknodat +//go:linkname libc_nanosleep libc_nanosleep +//go:linkname libc_open64 libc_open64 +//go:linkname libc_openat libc_openat +//go:linkname libc_read libc_read +//go:linkname libc_readlink libc_readlink +//go:linkname libc_renameat libc_renameat +//go:linkname libc_setdomainname libc_setdomainname +//go:linkname libc_sethostname libc_sethostname +//go:linkname libc_setpgid libc_setpgid +//go:linkname libc_setsid libc_setsid +//go:linkname libc_settimeofday libc_settimeofday +//go:linkname libc_setuid libc_setuid +//go:linkname libc_setgid libc_setgid +//go:linkname libc_setpriority libc_setpriority +//go:linkname libc_statx libc_statx +//go:linkname libc_sync libc_sync +//go:linkname libc_times libc_times +//go:linkname libc_umask libc_umask +//go:linkname libc_uname libc_uname +//go:linkname libc_unlink libc_unlink +//go:linkname libc_unlinkat libc_unlinkat +//go:linkname libc_ustat libc_ustat +//go:linkname libc_write libc_write +//go:linkname libc_dup2 libc_dup2 +//go:linkname libc_posix_fadvise64 libc_posix_fadvise64 +//go:linkname libc_fchown libc_fchown +//go:linkname libc_fstat libc_fstat +//go:linkname libc_fstatat libc_fstatat +//go:linkname libc_fstatfs libc_fstatfs +//go:linkname libc_ftruncate libc_ftruncate +//go:linkname libc_getegid libc_getegid +//go:linkname libc_geteuid libc_geteuid +//go:linkname libc_getgid libc_getgid +//go:linkname libc_getuid libc_getuid +//go:linkname libc_lchown libc_lchown +//go:linkname libc_listen libc_listen +//go:linkname libc_lstat libc_lstat +//go:linkname libc_pause libc_pause +//go:linkname libc_pread64 libc_pread64 +//go:linkname libc_pwrite64 libc_pwrite64 +//go:linkname libc_pselect libc_pselect +//go:linkname libc_setregid libc_setregid +//go:linkname libc_setreuid libc_setreuid +//go:linkname libc_shutdown libc_shutdown +//go:linkname libc_splice libc_splice +//go:linkname libc_stat libc_stat +//go:linkname libc_statfs libc_statfs +//go:linkname libc_truncate libc_truncate +//go:linkname libc_bind libc_bind +//go:linkname libc_connect libc_connect +//go:linkname libc_getgroups libc_getgroups +//go:linkname libc_setgroups libc_setgroups +//go:linkname libc_getsockopt libc_getsockopt +//go:linkname libc_setsockopt libc_setsockopt +//go:linkname libc_socket libc_socket +//go:linkname libc_socketpair libc_socketpair +//go:linkname libc_getpeername libc_getpeername +//go:linkname libc_getsockname libc_getsockname +//go:linkname libc_recvfrom libc_recvfrom +//go:linkname libc_sendto libc_sendto +//go:linkname libc_recvmsg libc_recvmsg +//go:linkname libc_sendmsg libc_sendmsg +//go:linkname libc_munmap libc_munmap +//go:linkname libc_madvise libc_madvise +//go:linkname libc_mprotect libc_mprotect +//go:linkname libc_mlock libc_mlock +//go:linkname libc_mlockall libc_mlockall +//go:linkname libc_msync libc_msync +//go:linkname libc_munlock libc_munlock +//go:linkname libc_munlockall libc_munlockall +//go:linkname libc_pipe libc_pipe +//go:linkname libc_poll libc_poll +//go:linkname libc_gettimeofday libc_gettimeofday +//go:linkname libc_time libc_time +//go:linkname libc_utime libc_utime +//go:linkname libc_getrlimit libc_getrlimit +//go:linkname libc_setrlimit libc_setrlimit +//go:linkname libc_lseek libc_lseek +//go:linkname libc_mmap64 libc_mmap64 + +type syscallFunc uintptr + +var ( + libc_utimes, + libc_utimensat, + libc_getcwd, + libc_accept, + libc_getdirent, + libc_wait4, + libc_ioctl, + libc_fcntl, + libc_acct, + libc_chdir, + libc_chroot, + libc_close, + libc_dup, + libc_exit, + libc_faccessat, + libc_fchdir, + libc_fchmod, + libc_fchmodat, + libc_fchownat, + libc_fdatasync, + libc_fsync, + libc_getpgid, + libc_getpgrp, + libc_getpid, + libc_getppid, + libc_getpriority, + libc_getrusage, + libc_getsid, + libc_kill, + libc_syslog, + libc_mkdir, + libc_mkdirat, + libc_mkfifo, + libc_mknod, + libc_mknodat, + libc_nanosleep, + libc_open64, + libc_openat, + libc_read, + libc_readlink, + libc_renameat, + libc_setdomainname, + libc_sethostname, + libc_setpgid, + libc_setsid, + libc_settimeofday, + libc_setuid, + libc_setgid, + libc_setpriority, + libc_statx, + libc_sync, + libc_times, + libc_umask, + libc_uname, + libc_unlink, + libc_unlinkat, + libc_ustat, + libc_write, + libc_dup2, + libc_posix_fadvise64, + libc_fchown, + libc_fstat, + libc_fstatat, + libc_fstatfs, + libc_ftruncate, + libc_getegid, + libc_geteuid, + libc_getgid, + libc_getuid, + libc_lchown, + libc_listen, + libc_lstat, + libc_pause, + libc_pread64, + libc_pwrite64, + libc_pselect, + libc_setregid, + libc_setreuid, + libc_shutdown, + libc_splice, + libc_stat, + libc_statfs, + libc_truncate, + libc_bind, + libc_connect, + libc_getgroups, + libc_setgroups, + libc_getsockopt, + libc_setsockopt, + libc_socket, + libc_socketpair, + libc_getpeername, + libc_getsockname, + libc_recvfrom, + libc_sendto, + libc_recvmsg, + libc_sendmsg, + libc_munmap, + libc_madvise, + libc_mprotect, + libc_mlock, + libc_mlockall, + libc_msync, + libc_munlock, + libc_munlockall, + libc_pipe, + libc_poll, + libc_gettimeofday, + libc_time, + libc_utime, + libc_getrlimit, + libc_setrlimit, + libc_lseek, + libc_mmap64 syscallFunc +) + +// Implemented in runtime/syscall_aix.go. +func rawSyscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) +func syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callutimes(_p0 uintptr, times uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_utimes)), 2, _p0, times, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callutimensat(dirfd int, _p0 uintptr, times uintptr, flag int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_utimensat)), 4, uintptr(dirfd), _p0, times, uintptr(flag), 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgetcwd(_p0 uintptr, _lenp0 int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_getcwd)), 2, _p0, uintptr(_lenp0), 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callaccept(s int, rsa uintptr, addrlen uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_accept)), 3, uintptr(s), rsa, addrlen, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgetdirent(fd int, _p0 uintptr, _lenp0 int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_getdirent)), 3, uintptr(fd), _p0, uintptr(_lenp0), 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callwait4(pid int, status uintptr, options int, rusage uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_wait4)), 4, uintptr(pid), status, uintptr(options), rusage, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callioctl(fd int, req int, arg uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_ioctl)), 3, uintptr(fd), uintptr(req), arg, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callfcntl(fd uintptr, cmd int, arg uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_fcntl)), 3, fd, uintptr(cmd), arg, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callacct(_p0 uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_acct)), 1, _p0, 0, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callchdir(_p0 uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_chdir)), 1, _p0, 0, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callchroot(_p0 uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_chroot)), 1, _p0, 0, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callclose(fd int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_close)), 1, uintptr(fd), 0, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func calldup(oldfd int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_dup)), 1, uintptr(oldfd), 0, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callexit(code int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_exit)), 1, uintptr(code), 0, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callfaccessat(dirfd int, _p0 uintptr, mode uint32, flags int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_faccessat)), 4, uintptr(dirfd), _p0, uintptr(mode), uintptr(flags), 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callfchdir(fd int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_fchdir)), 1, uintptr(fd), 0, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callfchmod(fd int, mode uint32) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_fchmod)), 2, uintptr(fd), uintptr(mode), 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callfchmodat(dirfd int, _p0 uintptr, mode uint32, flags int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_fchmodat)), 4, uintptr(dirfd), _p0, uintptr(mode), uintptr(flags), 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callfchownat(dirfd int, _p0 uintptr, uid int, gid int, flags int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_fchownat)), 5, uintptr(dirfd), _p0, uintptr(uid), uintptr(gid), uintptr(flags), 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callfdatasync(fd int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_fdatasync)), 1, uintptr(fd), 0, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callfsync(fd int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_fsync)), 1, uintptr(fd), 0, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgetpgid(pid int) (r1 uintptr, e1 Errno) { + r1, _, e1 = rawSyscall6(uintptr(unsafe.Pointer(&libc_getpgid)), 1, uintptr(pid), 0, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgetpgrp() (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_getpgrp)), 0, 0, 0, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgetpid() (r1 uintptr, e1 Errno) { + r1, _, e1 = rawSyscall6(uintptr(unsafe.Pointer(&libc_getpid)), 0, 0, 0, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgetppid() (r1 uintptr, e1 Errno) { + r1, _, e1 = rawSyscall6(uintptr(unsafe.Pointer(&libc_getppid)), 0, 0, 0, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgetpriority(which int, who int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_getpriority)), 2, uintptr(which), uintptr(who), 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgetrusage(who int, rusage uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = rawSyscall6(uintptr(unsafe.Pointer(&libc_getrusage)), 2, uintptr(who), rusage, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgetsid(pid int) (r1 uintptr, e1 Errno) { + r1, _, e1 = rawSyscall6(uintptr(unsafe.Pointer(&libc_getsid)), 1, uintptr(pid), 0, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callkill(pid int, sig int) (r1 uintptr, e1 Errno) { + r1, _, e1 = rawSyscall6(uintptr(unsafe.Pointer(&libc_kill)), 2, uintptr(pid), uintptr(sig), 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsyslog(typ int, _p0 uintptr, _lenp0 int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_syslog)), 3, uintptr(typ), _p0, uintptr(_lenp0), 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callmkdir(dirfd int, _p0 uintptr, mode uint32) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_mkdir)), 3, uintptr(dirfd), _p0, uintptr(mode), 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callmkdirat(dirfd int, _p0 uintptr, mode uint32) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_mkdirat)), 3, uintptr(dirfd), _p0, uintptr(mode), 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callmkfifo(_p0 uintptr, mode uint32) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_mkfifo)), 2, _p0, uintptr(mode), 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callmknod(_p0 uintptr, mode uint32, dev int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_mknod)), 3, _p0, uintptr(mode), uintptr(dev), 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callmknodat(dirfd int, _p0 uintptr, mode uint32, dev int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_mknodat)), 4, uintptr(dirfd), _p0, uintptr(mode), uintptr(dev), 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callnanosleep(time uintptr, leftover uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_nanosleep)), 2, time, leftover, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callopen64(_p0 uintptr, mode int, perm uint32) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_open64)), 3, _p0, uintptr(mode), uintptr(perm), 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callopenat(dirfd int, _p0 uintptr, flags int, mode uint32) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_openat)), 4, uintptr(dirfd), _p0, uintptr(flags), uintptr(mode), 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callread(fd int, _p0 uintptr, _lenp0 int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_read)), 3, uintptr(fd), _p0, uintptr(_lenp0), 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callreadlink(_p0 uintptr, _p1 uintptr, _lenp1 int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_readlink)), 3, _p0, _p1, uintptr(_lenp1), 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callrenameat(olddirfd int, _p0 uintptr, newdirfd int, _p1 uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_renameat)), 4, uintptr(olddirfd), _p0, uintptr(newdirfd), _p1, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsetdomainname(_p0 uintptr, _lenp0 int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_setdomainname)), 2, _p0, uintptr(_lenp0), 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsethostname(_p0 uintptr, _lenp0 int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_sethostname)), 2, _p0, uintptr(_lenp0), 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsetpgid(pid int, pgid int) (r1 uintptr, e1 Errno) { + r1, _, e1 = rawSyscall6(uintptr(unsafe.Pointer(&libc_setpgid)), 2, uintptr(pid), uintptr(pgid), 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsetsid() (r1 uintptr, e1 Errno) { + r1, _, e1 = rawSyscall6(uintptr(unsafe.Pointer(&libc_setsid)), 0, 0, 0, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsettimeofday(tv uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = rawSyscall6(uintptr(unsafe.Pointer(&libc_settimeofday)), 1, tv, 0, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsetuid(uid int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_setuid)), 1, uintptr(uid), 0, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsetgid(uid int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_setgid)), 1, uintptr(uid), 0, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsetpriority(which int, who int, prio int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_setpriority)), 3, uintptr(which), uintptr(who), uintptr(prio), 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callstatx(dirfd int, _p0 uintptr, flags int, mask int, stat uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_statx)), 5, uintptr(dirfd), _p0, uintptr(flags), uintptr(mask), stat, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsync() (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_sync)), 0, 0, 0, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func calltimes(tms uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = rawSyscall6(uintptr(unsafe.Pointer(&libc_times)), 1, tms, 0, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callumask(mask int) (r1 uintptr, e1 Errno) { + r1, _, e1 = rawSyscall6(uintptr(unsafe.Pointer(&libc_umask)), 1, uintptr(mask), 0, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func calluname(buf uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = rawSyscall6(uintptr(unsafe.Pointer(&libc_uname)), 1, buf, 0, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callunlink(_p0 uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_unlink)), 1, _p0, 0, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callunlinkat(dirfd int, _p0 uintptr, flags int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_unlinkat)), 3, uintptr(dirfd), _p0, uintptr(flags), 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callustat(dev int, ubuf uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_ustat)), 2, uintptr(dev), ubuf, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callwrite(fd int, _p0 uintptr, _lenp0 int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_write)), 3, uintptr(fd), _p0, uintptr(_lenp0), 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func calldup2(oldfd int, newfd int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_dup2)), 2, uintptr(oldfd), uintptr(newfd), 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callposix_fadvise64(fd int, offset int64, length int64, advice int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_posix_fadvise64)), 4, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callfchown(fd int, uid int, gid int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_fchown)), 3, uintptr(fd), uintptr(uid), uintptr(gid), 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callfstat(fd int, stat uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_fstat)), 2, uintptr(fd), stat, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callfstatat(dirfd int, _p0 uintptr, stat uintptr, flags int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_fstatat)), 4, uintptr(dirfd), _p0, stat, uintptr(flags), 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callfstatfs(fd int, buf uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_fstatfs)), 2, uintptr(fd), buf, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callftruncate(fd int, length int64) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_ftruncate)), 2, uintptr(fd), uintptr(length), 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgetegid() (r1 uintptr, e1 Errno) { + r1, _, e1 = rawSyscall6(uintptr(unsafe.Pointer(&libc_getegid)), 0, 0, 0, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgeteuid() (r1 uintptr, e1 Errno) { + r1, _, e1 = rawSyscall6(uintptr(unsafe.Pointer(&libc_geteuid)), 0, 0, 0, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgetgid() (r1 uintptr, e1 Errno) { + r1, _, e1 = rawSyscall6(uintptr(unsafe.Pointer(&libc_getgid)), 0, 0, 0, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgetuid() (r1 uintptr, e1 Errno) { + r1, _, e1 = rawSyscall6(uintptr(unsafe.Pointer(&libc_getuid)), 0, 0, 0, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func calllchown(_p0 uintptr, uid int, gid int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_lchown)), 3, _p0, uintptr(uid), uintptr(gid), 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func calllisten(s int, n int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_listen)), 2, uintptr(s), uintptr(n), 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func calllstat(_p0 uintptr, stat uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_lstat)), 2, _p0, stat, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callpause() (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_pause)), 0, 0, 0, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callpread64(fd int, _p0 uintptr, _lenp0 int, offset int64) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_pread64)), 4, uintptr(fd), _p0, uintptr(_lenp0), uintptr(offset), 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callpwrite64(fd int, _p0 uintptr, _lenp0 int, offset int64) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_pwrite64)), 4, uintptr(fd), _p0, uintptr(_lenp0), uintptr(offset), 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callpselect(nfd int, r uintptr, w uintptr, e uintptr, timeout uintptr, sigmask uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_pselect)), 6, uintptr(nfd), r, w, e, timeout, sigmask) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsetregid(rgid int, egid int) (r1 uintptr, e1 Errno) { + r1, _, e1 = rawSyscall6(uintptr(unsafe.Pointer(&libc_setregid)), 2, uintptr(rgid), uintptr(egid), 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsetreuid(ruid int, euid int) (r1 uintptr, e1 Errno) { + r1, _, e1 = rawSyscall6(uintptr(unsafe.Pointer(&libc_setreuid)), 2, uintptr(ruid), uintptr(euid), 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callshutdown(fd int, how int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_shutdown)), 2, uintptr(fd), uintptr(how), 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsplice(rfd int, roff uintptr, wfd int, woff uintptr, len int, flags int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_splice)), 6, uintptr(rfd), roff, uintptr(wfd), woff, uintptr(len), uintptr(flags)) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callstat(_p0 uintptr, stat uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_stat)), 2, _p0, stat, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callstatfs(_p0 uintptr, buf uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_statfs)), 2, _p0, buf, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func calltruncate(_p0 uintptr, length int64) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_truncate)), 2, _p0, uintptr(length), 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callbind(s int, addr uintptr, addrlen uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_bind)), 3, uintptr(s), addr, addrlen, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callconnect(s int, addr uintptr, addrlen uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_connect)), 3, uintptr(s), addr, addrlen, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgetgroups(n int, list uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = rawSyscall6(uintptr(unsafe.Pointer(&libc_getgroups)), 2, uintptr(n), list, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsetgroups(n int, list uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = rawSyscall6(uintptr(unsafe.Pointer(&libc_setgroups)), 2, uintptr(n), list, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgetsockopt(s int, level int, name int, val uintptr, vallen uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_getsockopt)), 5, uintptr(s), uintptr(level), uintptr(name), val, vallen, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsetsockopt(s int, level int, name int, val uintptr, vallen uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_setsockopt)), 5, uintptr(s), uintptr(level), uintptr(name), val, vallen, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsocket(domain int, typ int, proto int) (r1 uintptr, e1 Errno) { + r1, _, e1 = rawSyscall6(uintptr(unsafe.Pointer(&libc_socket)), 3, uintptr(domain), uintptr(typ), uintptr(proto), 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsocketpair(domain int, typ int, proto int, fd uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = rawSyscall6(uintptr(unsafe.Pointer(&libc_socketpair)), 4, uintptr(domain), uintptr(typ), uintptr(proto), fd, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgetpeername(fd int, rsa uintptr, addrlen uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = rawSyscall6(uintptr(unsafe.Pointer(&libc_getpeername)), 3, uintptr(fd), rsa, addrlen, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgetsockname(fd int, rsa uintptr, addrlen uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = rawSyscall6(uintptr(unsafe.Pointer(&libc_getsockname)), 3, uintptr(fd), rsa, addrlen, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callrecvfrom(fd int, _p0 uintptr, _lenp0 int, flags int, from uintptr, fromlen uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_recvfrom)), 6, uintptr(fd), _p0, uintptr(_lenp0), uintptr(flags), from, fromlen) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsendto(s int, _p0 uintptr, _lenp0 int, flags int, to uintptr, addrlen uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_sendto)), 6, uintptr(s), _p0, uintptr(_lenp0), uintptr(flags), to, addrlen) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callrecvmsg(s int, msg uintptr, flags int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_recvmsg)), 3, uintptr(s), msg, uintptr(flags), 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsendmsg(s int, msg uintptr, flags int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_sendmsg)), 3, uintptr(s), msg, uintptr(flags), 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callmunmap(addr uintptr, length uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_munmap)), 2, addr, length, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callmadvise(_p0 uintptr, _lenp0 int, advice int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_madvise)), 3, _p0, uintptr(_lenp0), uintptr(advice), 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callmprotect(_p0 uintptr, _lenp0 int, prot int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_mprotect)), 3, _p0, uintptr(_lenp0), uintptr(prot), 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callmlock(_p0 uintptr, _lenp0 int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_mlock)), 2, _p0, uintptr(_lenp0), 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callmlockall(flags int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_mlockall)), 1, uintptr(flags), 0, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callmsync(_p0 uintptr, _lenp0 int, flags int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_msync)), 3, _p0, uintptr(_lenp0), uintptr(flags), 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callmunlock(_p0 uintptr, _lenp0 int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_munlock)), 2, _p0, uintptr(_lenp0), 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callmunlockall() (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_munlockall)), 0, 0, 0, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callpipe(p uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = rawSyscall6(uintptr(unsafe.Pointer(&libc_pipe)), 1, p, 0, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callpoll(fds uintptr, nfds int, timeout int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_poll)), 3, fds, uintptr(nfds), uintptr(timeout), 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgettimeofday(tv uintptr, tzp uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_gettimeofday)), 2, tv, tzp, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func calltime(t uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = rawSyscall6(uintptr(unsafe.Pointer(&libc_time)), 1, t, 0, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callutime(_p0 uintptr, buf uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_utime)), 2, _p0, buf, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgetrlimit(resource int, rlim uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = rawSyscall6(uintptr(unsafe.Pointer(&libc_getrlimit)), 2, uintptr(resource), rlim, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsetrlimit(resource int, rlim uintptr) (r1 uintptr, e1 Errno) { + r1, _, e1 = rawSyscall6(uintptr(unsafe.Pointer(&libc_setrlimit)), 2, uintptr(resource), rlim, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func calllseek(fd int, offset int64, whence int) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_lseek)), 3, uintptr(fd), uintptr(offset), uintptr(whence), 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callmmap64(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_mmap64)), 6, addr, length, uintptr(prot), uintptr(flags), uintptr(fd), uintptr(offset)) + return +} diff --git a/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gccgo.go b/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gccgo.go new file mode 100644 index 0000000000..e88a442787 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gccgo.go @@ -0,0 +1,1042 @@ +// go run mksyscall_aix_ppc64.go -aix -tags aix,ppc64 syscall_aix.go syscall_aix_ppc64.go +// Code generated by the command above; see README.md. DO NOT EDIT. + +// +build aix,ppc64 +// +build gccgo + +package unix + +/* +#include +int utimes(uintptr_t, uintptr_t); +int utimensat(int, uintptr_t, uintptr_t, int); +int getcwd(uintptr_t, size_t); +int accept(int, uintptr_t, uintptr_t); +int getdirent(int, uintptr_t, size_t); +int wait4(int, uintptr_t, int, uintptr_t); +int ioctl(int, int, uintptr_t); +int fcntl(uintptr_t, int, uintptr_t); +int acct(uintptr_t); +int chdir(uintptr_t); +int chroot(uintptr_t); +int close(int); +int dup(int); +void exit(int); +int faccessat(int, uintptr_t, unsigned int, int); +int fchdir(int); +int fchmod(int, unsigned int); +int fchmodat(int, uintptr_t, unsigned int, int); +int fchownat(int, uintptr_t, int, int, int); +int fdatasync(int); +int fsync(int); +int getpgid(int); +int getpgrp(); +int getpid(); +int getppid(); +int getpriority(int, int); +int getrusage(int, uintptr_t); +int getsid(int); +int kill(int, int); +int syslog(int, uintptr_t, size_t); +int mkdir(int, uintptr_t, unsigned int); +int mkdirat(int, uintptr_t, unsigned int); +int mkfifo(uintptr_t, unsigned int); +int mknod(uintptr_t, unsigned int, int); +int mknodat(int, uintptr_t, unsigned int, int); +int nanosleep(uintptr_t, uintptr_t); +int open64(uintptr_t, int, unsigned int); +int openat(int, uintptr_t, int, unsigned int); +int read(int, uintptr_t, size_t); +int readlink(uintptr_t, uintptr_t, size_t); +int renameat(int, uintptr_t, int, uintptr_t); +int setdomainname(uintptr_t, size_t); +int sethostname(uintptr_t, size_t); +int setpgid(int, int); +int setsid(); +int settimeofday(uintptr_t); +int setuid(int); +int setgid(int); +int setpriority(int, int, int); +int statx(int, uintptr_t, int, int, uintptr_t); +int sync(); +uintptr_t times(uintptr_t); +int umask(int); +int uname(uintptr_t); +int unlink(uintptr_t); +int unlinkat(int, uintptr_t, int); +int ustat(int, uintptr_t); +int write(int, uintptr_t, size_t); +int dup2(int, int); +int posix_fadvise64(int, long long, long long, int); +int fchown(int, int, int); +int fstat(int, uintptr_t); +int fstatat(int, uintptr_t, uintptr_t, int); +int fstatfs(int, uintptr_t); +int ftruncate(int, long long); +int getegid(); +int geteuid(); +int getgid(); +int getuid(); +int lchown(uintptr_t, int, int); +int listen(int, int); +int lstat(uintptr_t, uintptr_t); +int pause(); +int pread64(int, uintptr_t, size_t, long long); +int pwrite64(int, uintptr_t, size_t, long long); +int pselect(int, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t); +int setregid(int, int); +int setreuid(int, int); +int shutdown(int, int); +long long splice(int, uintptr_t, int, uintptr_t, int, int); +int stat(uintptr_t, uintptr_t); +int statfs(uintptr_t, uintptr_t); +int truncate(uintptr_t, long long); +int bind(int, uintptr_t, uintptr_t); +int connect(int, uintptr_t, uintptr_t); +int getgroups(int, uintptr_t); +int setgroups(int, uintptr_t); +int getsockopt(int, int, int, uintptr_t, uintptr_t); +int setsockopt(int, int, int, uintptr_t, uintptr_t); +int socket(int, int, int); +int socketpair(int, int, int, uintptr_t); +int getpeername(int, uintptr_t, uintptr_t); +int getsockname(int, uintptr_t, uintptr_t); +int recvfrom(int, uintptr_t, size_t, int, uintptr_t, uintptr_t); +int sendto(int, uintptr_t, size_t, int, uintptr_t, uintptr_t); +int recvmsg(int, uintptr_t, int); +int sendmsg(int, uintptr_t, int); +int munmap(uintptr_t, uintptr_t); +int madvise(uintptr_t, size_t, int); +int mprotect(uintptr_t, size_t, int); +int mlock(uintptr_t, size_t); +int mlockall(int); +int msync(uintptr_t, size_t, int); +int munlock(uintptr_t, size_t); +int munlockall(); +int pipe(uintptr_t); +int poll(uintptr_t, int, int); +int gettimeofday(uintptr_t, uintptr_t); +int time(uintptr_t); +int utime(uintptr_t, uintptr_t); +int getrlimit(int, uintptr_t); +int setrlimit(int, uintptr_t); +long long lseek(int, long long, int); +uintptr_t mmap64(uintptr_t, uintptr_t, int, int, int, long long); + +*/ +import "C" +import ( + "syscall" +) + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callutimes(_p0 uintptr, times uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.utimes(C.uintptr_t(_p0), C.uintptr_t(times))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callutimensat(dirfd int, _p0 uintptr, times uintptr, flag int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.utimensat(C.int(dirfd), C.uintptr_t(_p0), C.uintptr_t(times), C.int(flag))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgetcwd(_p0 uintptr, _lenp0 int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.getcwd(C.uintptr_t(_p0), C.size_t(_lenp0))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callaccept(s int, rsa uintptr, addrlen uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.accept(C.int(s), C.uintptr_t(rsa), C.uintptr_t(addrlen))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgetdirent(fd int, _p0 uintptr, _lenp0 int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.getdirent(C.int(fd), C.uintptr_t(_p0), C.size_t(_lenp0))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callwait4(pid int, status uintptr, options int, rusage uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.wait4(C.int(pid), C.uintptr_t(status), C.int(options), C.uintptr_t(rusage))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callioctl(fd int, req int, arg uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.ioctl(C.int(fd), C.int(req), C.uintptr_t(arg))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callfcntl(fd uintptr, cmd int, arg uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.fcntl(C.uintptr_t(fd), C.int(cmd), C.uintptr_t(arg))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callacct(_p0 uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.acct(C.uintptr_t(_p0))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callchdir(_p0 uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.chdir(C.uintptr_t(_p0))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callchroot(_p0 uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.chroot(C.uintptr_t(_p0))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callclose(fd int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.close(C.int(fd))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func calldup(oldfd int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.dup(C.int(oldfd))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callexit(code int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.exit(C.int(code))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callfaccessat(dirfd int, _p0 uintptr, mode uint32, flags int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.faccessat(C.int(dirfd), C.uintptr_t(_p0), C.uint(mode), C.int(flags))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callfchdir(fd int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.fchdir(C.int(fd))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callfchmod(fd int, mode uint32) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.fchmod(C.int(fd), C.uint(mode))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callfchmodat(dirfd int, _p0 uintptr, mode uint32, flags int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.fchmodat(C.int(dirfd), C.uintptr_t(_p0), C.uint(mode), C.int(flags))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callfchownat(dirfd int, _p0 uintptr, uid int, gid int, flags int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.fchownat(C.int(dirfd), C.uintptr_t(_p0), C.int(uid), C.int(gid), C.int(flags))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callfdatasync(fd int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.fdatasync(C.int(fd))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callfsync(fd int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.fsync(C.int(fd))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgetpgid(pid int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.getpgid(C.int(pid))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgetpgrp() (r1 uintptr, e1 Errno) { + r1 = uintptr(C.getpgrp()) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgetpid() (r1 uintptr, e1 Errno) { + r1 = uintptr(C.getpid()) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgetppid() (r1 uintptr, e1 Errno) { + r1 = uintptr(C.getppid()) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgetpriority(which int, who int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.getpriority(C.int(which), C.int(who))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgetrusage(who int, rusage uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.getrusage(C.int(who), C.uintptr_t(rusage))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgetsid(pid int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.getsid(C.int(pid))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callkill(pid int, sig int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.kill(C.int(pid), C.int(sig))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsyslog(typ int, _p0 uintptr, _lenp0 int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.syslog(C.int(typ), C.uintptr_t(_p0), C.size_t(_lenp0))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callmkdir(dirfd int, _p0 uintptr, mode uint32) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.mkdir(C.int(dirfd), C.uintptr_t(_p0), C.uint(mode))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callmkdirat(dirfd int, _p0 uintptr, mode uint32) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.mkdirat(C.int(dirfd), C.uintptr_t(_p0), C.uint(mode))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callmkfifo(_p0 uintptr, mode uint32) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.mkfifo(C.uintptr_t(_p0), C.uint(mode))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callmknod(_p0 uintptr, mode uint32, dev int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.mknod(C.uintptr_t(_p0), C.uint(mode), C.int(dev))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callmknodat(dirfd int, _p0 uintptr, mode uint32, dev int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.mknodat(C.int(dirfd), C.uintptr_t(_p0), C.uint(mode), C.int(dev))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callnanosleep(time uintptr, leftover uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.nanosleep(C.uintptr_t(time), C.uintptr_t(leftover))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callopen64(_p0 uintptr, mode int, perm uint32) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.open64(C.uintptr_t(_p0), C.int(mode), C.uint(perm))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callopenat(dirfd int, _p0 uintptr, flags int, mode uint32) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.openat(C.int(dirfd), C.uintptr_t(_p0), C.int(flags), C.uint(mode))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callread(fd int, _p0 uintptr, _lenp0 int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.read(C.int(fd), C.uintptr_t(_p0), C.size_t(_lenp0))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callreadlink(_p0 uintptr, _p1 uintptr, _lenp1 int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.readlink(C.uintptr_t(_p0), C.uintptr_t(_p1), C.size_t(_lenp1))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callrenameat(olddirfd int, _p0 uintptr, newdirfd int, _p1 uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.renameat(C.int(olddirfd), C.uintptr_t(_p0), C.int(newdirfd), C.uintptr_t(_p1))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsetdomainname(_p0 uintptr, _lenp0 int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.setdomainname(C.uintptr_t(_p0), C.size_t(_lenp0))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsethostname(_p0 uintptr, _lenp0 int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.sethostname(C.uintptr_t(_p0), C.size_t(_lenp0))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsetpgid(pid int, pgid int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.setpgid(C.int(pid), C.int(pgid))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsetsid() (r1 uintptr, e1 Errno) { + r1 = uintptr(C.setsid()) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsettimeofday(tv uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.settimeofday(C.uintptr_t(tv))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsetuid(uid int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.setuid(C.int(uid))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsetgid(uid int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.setgid(C.int(uid))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsetpriority(which int, who int, prio int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.setpriority(C.int(which), C.int(who), C.int(prio))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callstatx(dirfd int, _p0 uintptr, flags int, mask int, stat uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.statx(C.int(dirfd), C.uintptr_t(_p0), C.int(flags), C.int(mask), C.uintptr_t(stat))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsync() (r1 uintptr, e1 Errno) { + r1 = uintptr(C.sync()) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func calltimes(tms uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.times(C.uintptr_t(tms))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callumask(mask int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.umask(C.int(mask))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func calluname(buf uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.uname(C.uintptr_t(buf))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callunlink(_p0 uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.unlink(C.uintptr_t(_p0))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callunlinkat(dirfd int, _p0 uintptr, flags int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.unlinkat(C.int(dirfd), C.uintptr_t(_p0), C.int(flags))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callustat(dev int, ubuf uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.ustat(C.int(dev), C.uintptr_t(ubuf))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callwrite(fd int, _p0 uintptr, _lenp0 int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.write(C.int(fd), C.uintptr_t(_p0), C.size_t(_lenp0))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func calldup2(oldfd int, newfd int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.dup2(C.int(oldfd), C.int(newfd))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callposix_fadvise64(fd int, offset int64, length int64, advice int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.posix_fadvise64(C.int(fd), C.longlong(offset), C.longlong(length), C.int(advice))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callfchown(fd int, uid int, gid int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.fchown(C.int(fd), C.int(uid), C.int(gid))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callfstat(fd int, stat uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.fstat(C.int(fd), C.uintptr_t(stat))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callfstatat(dirfd int, _p0 uintptr, stat uintptr, flags int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.fstatat(C.int(dirfd), C.uintptr_t(_p0), C.uintptr_t(stat), C.int(flags))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callfstatfs(fd int, buf uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.fstatfs(C.int(fd), C.uintptr_t(buf))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callftruncate(fd int, length int64) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.ftruncate(C.int(fd), C.longlong(length))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgetegid() (r1 uintptr, e1 Errno) { + r1 = uintptr(C.getegid()) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgeteuid() (r1 uintptr, e1 Errno) { + r1 = uintptr(C.geteuid()) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgetgid() (r1 uintptr, e1 Errno) { + r1 = uintptr(C.getgid()) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgetuid() (r1 uintptr, e1 Errno) { + r1 = uintptr(C.getuid()) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func calllchown(_p0 uintptr, uid int, gid int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.lchown(C.uintptr_t(_p0), C.int(uid), C.int(gid))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func calllisten(s int, n int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.listen(C.int(s), C.int(n))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func calllstat(_p0 uintptr, stat uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.lstat(C.uintptr_t(_p0), C.uintptr_t(stat))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callpause() (r1 uintptr, e1 Errno) { + r1 = uintptr(C.pause()) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callpread64(fd int, _p0 uintptr, _lenp0 int, offset int64) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.pread64(C.int(fd), C.uintptr_t(_p0), C.size_t(_lenp0), C.longlong(offset))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callpwrite64(fd int, _p0 uintptr, _lenp0 int, offset int64) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.pwrite64(C.int(fd), C.uintptr_t(_p0), C.size_t(_lenp0), C.longlong(offset))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callpselect(nfd int, r uintptr, w uintptr, e uintptr, timeout uintptr, sigmask uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.pselect(C.int(nfd), C.uintptr_t(r), C.uintptr_t(w), C.uintptr_t(e), C.uintptr_t(timeout), C.uintptr_t(sigmask))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsetregid(rgid int, egid int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.setregid(C.int(rgid), C.int(egid))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsetreuid(ruid int, euid int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.setreuid(C.int(ruid), C.int(euid))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callshutdown(fd int, how int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.shutdown(C.int(fd), C.int(how))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsplice(rfd int, roff uintptr, wfd int, woff uintptr, len int, flags int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.splice(C.int(rfd), C.uintptr_t(roff), C.int(wfd), C.uintptr_t(woff), C.int(len), C.int(flags))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callstat(_p0 uintptr, stat uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.stat(C.uintptr_t(_p0), C.uintptr_t(stat))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callstatfs(_p0 uintptr, buf uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.statfs(C.uintptr_t(_p0), C.uintptr_t(buf))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func calltruncate(_p0 uintptr, length int64) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.truncate(C.uintptr_t(_p0), C.longlong(length))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callbind(s int, addr uintptr, addrlen uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.bind(C.int(s), C.uintptr_t(addr), C.uintptr_t(addrlen))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callconnect(s int, addr uintptr, addrlen uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.connect(C.int(s), C.uintptr_t(addr), C.uintptr_t(addrlen))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgetgroups(n int, list uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.getgroups(C.int(n), C.uintptr_t(list))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsetgroups(n int, list uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.setgroups(C.int(n), C.uintptr_t(list))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgetsockopt(s int, level int, name int, val uintptr, vallen uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.getsockopt(C.int(s), C.int(level), C.int(name), C.uintptr_t(val), C.uintptr_t(vallen))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsetsockopt(s int, level int, name int, val uintptr, vallen uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.setsockopt(C.int(s), C.int(level), C.int(name), C.uintptr_t(val), C.uintptr_t(vallen))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsocket(domain int, typ int, proto int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.socket(C.int(domain), C.int(typ), C.int(proto))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsocketpair(domain int, typ int, proto int, fd uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.socketpair(C.int(domain), C.int(typ), C.int(proto), C.uintptr_t(fd))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgetpeername(fd int, rsa uintptr, addrlen uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.getpeername(C.int(fd), C.uintptr_t(rsa), C.uintptr_t(addrlen))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgetsockname(fd int, rsa uintptr, addrlen uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.getsockname(C.int(fd), C.uintptr_t(rsa), C.uintptr_t(addrlen))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callrecvfrom(fd int, _p0 uintptr, _lenp0 int, flags int, from uintptr, fromlen uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.recvfrom(C.int(fd), C.uintptr_t(_p0), C.size_t(_lenp0), C.int(flags), C.uintptr_t(from), C.uintptr_t(fromlen))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsendto(s int, _p0 uintptr, _lenp0 int, flags int, to uintptr, addrlen uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.sendto(C.int(s), C.uintptr_t(_p0), C.size_t(_lenp0), C.int(flags), C.uintptr_t(to), C.uintptr_t(addrlen))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callrecvmsg(s int, msg uintptr, flags int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.recvmsg(C.int(s), C.uintptr_t(msg), C.int(flags))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsendmsg(s int, msg uintptr, flags int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.sendmsg(C.int(s), C.uintptr_t(msg), C.int(flags))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callmunmap(addr uintptr, length uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.munmap(C.uintptr_t(addr), C.uintptr_t(length))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callmadvise(_p0 uintptr, _lenp0 int, advice int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.madvise(C.uintptr_t(_p0), C.size_t(_lenp0), C.int(advice))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callmprotect(_p0 uintptr, _lenp0 int, prot int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.mprotect(C.uintptr_t(_p0), C.size_t(_lenp0), C.int(prot))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callmlock(_p0 uintptr, _lenp0 int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.mlock(C.uintptr_t(_p0), C.size_t(_lenp0))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callmlockall(flags int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.mlockall(C.int(flags))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callmsync(_p0 uintptr, _lenp0 int, flags int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.msync(C.uintptr_t(_p0), C.size_t(_lenp0), C.int(flags))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callmunlock(_p0 uintptr, _lenp0 int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.munlock(C.uintptr_t(_p0), C.size_t(_lenp0))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callmunlockall() (r1 uintptr, e1 Errno) { + r1 = uintptr(C.munlockall()) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callpipe(p uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.pipe(C.uintptr_t(p))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callpoll(fds uintptr, nfds int, timeout int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.poll(C.uintptr_t(fds), C.int(nfds), C.int(timeout))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgettimeofday(tv uintptr, tzp uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.gettimeofday(C.uintptr_t(tv), C.uintptr_t(tzp))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func calltime(t uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.time(C.uintptr_t(t))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callutime(_p0 uintptr, buf uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.utime(C.uintptr_t(_p0), C.uintptr_t(buf))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callgetrlimit(resource int, rlim uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.getrlimit(C.int(resource), C.uintptr_t(rlim))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callsetrlimit(resource int, rlim uintptr) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.setrlimit(C.int(resource), C.uintptr_t(rlim))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func calllseek(fd int, offset int64, whence int) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.lseek(C.int(fd), C.longlong(offset), C.int(whence))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func callmmap64(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.mmap64(C.uintptr_t(addr), C.uintptr_t(length), C.int(prot), C.int(flags), C.int(fd), C.longlong(offset))) + e1 = syscall.GetErrno() + return +} diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.1_11.go b/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.1_11.go new file mode 100644 index 0000000000..c4ec7ff87c --- /dev/null +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.1_11.go @@ -0,0 +1,1810 @@ +// go run mksyscall.go -l32 -tags darwin,386,!go1.12 syscall_bsd.go syscall_darwin.go syscall_darwin_386.go +// Code generated by the command above; see README.md. DO NOT EDIT. + +// +build darwin,386,!go1.12 + +package unix + +import ( + "syscall" + "unsafe" +) + +var _ syscall.Errno + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getgroups(ngid int, gid *_Gid_t) (n int, err error) { + r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setgroups(ngid int, gid *_Gid_t) (err error) { + _, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) { + r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0) + wpid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { + r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { + _, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { + _, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func socket(domain int, typ int, proto int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto)) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) { + _, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) { + _, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { + _, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { + _, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Shutdown(s int, how int) (err error) { + _, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) { + _, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) { + r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) { + r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) { + r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) { + var _p0 unsafe.Pointer + if len(mib) > 0 { + _p0 = unsafe.Pointer(&mib[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func utimes(path string, timeval *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func futimes(fd int, timeval *[2]Timeval) (err error) { + _, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fcntl(fd int, cmd int, arg int) (val int, err error) { + r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg)) + val = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { + r0, _, e1 := Syscall(SYS_POLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Madvise(b []byte, behav int) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(behav)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mlock(b []byte) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mlockall(flags int) (err error) { + _, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mprotect(b []byte, prot int) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Msync(b []byte, flags int) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MSYNC, uintptr(_p0), uintptr(len(b)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Munlock(b []byte) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Munlockall() (err error) { + _, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) { + _, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error) { + _, _, e1 := Syscall6(SYS_GETATTRLIST, uintptr(unsafe.Pointer(path)), uintptr(list), uintptr(buf), uintptr(size), uintptr(options), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func pipe() (r int, w int, err error) { + r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0) + r = int(r0) + w = int(r1) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getxattr(path string, attr string, dest *byte, size int, position uint32, options int) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(position), uintptr(options)) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fgetxattr(fd int, attr string, dest *byte, size int, position uint32, options int) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_FGETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(position), uintptr(options)) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setxattr(path string, attr string, data *byte, size int, position uint32, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(data)), uintptr(size), uintptr(position), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fsetxattr(fd int, attr string, data *byte, size int, position uint32, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FSETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(data)), uintptr(size), uintptr(position), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func removexattr(path string, attr string, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_REMOVEXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fremovexattr(fd int, attr string, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FREMOVEXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func listxattr(path string, dest *byte, size int, options int) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_LISTXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(options), 0, 0) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func flistxattr(fd int, dest *byte, size int, options int) (sz int, err error) { + r0, _, e1 := Syscall6(SYS_FLISTXATTR, uintptr(fd), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(options), 0, 0) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error) { + _, _, e1 := Syscall6(SYS_SETATTRLIST, uintptr(unsafe.Pointer(path)), uintptr(list), uintptr(buf), uintptr(size), uintptr(options), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func kill(pid int, signum int, posix int) (err error) { + _, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), uintptr(posix)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ioctl(fd int, req uint, arg uintptr) (err error) { + _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) { + _, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(offset), uintptr(offset>>32), uintptr(unsafe.Pointer(len)), uintptr(hdtr), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Access(path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Adjtime(delta *Timeval, olddelta *Timeval) (err error) { + _, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chdir(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chflags(path string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chmod(path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chown(path string, uid int, gid int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chroot(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Close(fd int) (err error) { + _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Dup(fd int) (nfd int, err error) { + r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0) + nfd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Dup2(from int, to int) (err error) { + _, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Exchangedata(path1 string, path2 string, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path1) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(path2) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_EXCHANGEDATA, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Exit(code int) { + Syscall(SYS_EXIT, uintptr(code), 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchdir(fd int) (err error) { + _, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchflags(fd int, flags int) (err error) { + _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchmod(fd int, mode uint32) (err error) { + _, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchown(fd int, uid int, gid int) (err error) { + _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Flock(fd int, how int) (err error) { + _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fpathconf(fd int, name int) (val int, err error) { + r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0) + val = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fsync(fd int) (err error) { + _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Ftruncate(fd int, length int64) (err error) { + _, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), uintptr(length>>32)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getdtablesize() (size int) { + r0, _, _ := Syscall(SYS_GETDTABLESIZE, 0, 0, 0) + size = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getegid() (egid int) { + r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0) + egid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Geteuid() (uid int) { + r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0) + uid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getgid() (gid int) { + r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0) + gid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpgid(pid int) (pgid int, err error) { + r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0) + pgid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpgrp() (pgrp int) { + r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0) + pgrp = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpid() (pid int) { + r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0) + pid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getppid() (ppid int) { + r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0) + ppid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpriority(which int, who int) (prio int, err error) { + r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0) + prio = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getrlimit(which int, lim *Rlimit) (err error) { + _, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getrusage(who int, rusage *Rusage) (err error) { + _, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getsid(pid int) (sid int, err error) { + r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0) + sid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getuid() (uid int) { + r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0) + uid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Issetugid() (tainted bool) { + r0, _, _ := RawSyscall(SYS_ISSETUGID, 0, 0, 0) + tainted = bool(r0 != 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Kqueue() (fd int, err error) { + r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Lchown(path string, uid int, gid int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Link(path string, link string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(link) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(link) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_LINKAT, uintptr(pathfd), uintptr(unsafe.Pointer(_p0)), uintptr(linkfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Listen(s int, backlog int) (err error) { + _, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mkdir(path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mkdirat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mkfifo(path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mknod(path string, mode uint32, dev int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Open(path string, mode int, perm uint32) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pathconf(path string, name int) (val int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) + val = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pread(fd int, p []byte, offset int64) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pwrite(fd int, p []byte, offset int64) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func read(fd int, p []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Readlink(path string, buf []byte) (n int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(buf) > 0 { + _p1 = unsafe.Pointer(&buf[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(buf) > 0 { + _p1 = unsafe.Pointer(&buf[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_READLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Rename(from string, to string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(from) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(to) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Renameat(fromfd int, from string, tofd int, to string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(from) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(to) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(fromfd), uintptr(unsafe.Pointer(_p0)), uintptr(tofd), uintptr(unsafe.Pointer(_p1)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Revoke(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Rmdir(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { + r0, r1, e1 := Syscall6(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(offset>>32), uintptr(whence), 0, 0) + newoffset = int64(int64(r1)<<32 | int64(r0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) { + _, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setegid(egid int) (err error) { + _, _, e1 := Syscall(SYS_SETEGID, uintptr(egid), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Seteuid(euid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setgid(gid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setlogin(name string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(name) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setpgid(pid int, pgid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setpriority(which int, who int, prio int) (err error) { + _, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setprivexec(flag int) (err error) { + _, _, e1 := Syscall(SYS_SETPRIVEXEC, uintptr(flag), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setregid(rgid int, egid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setreuid(ruid int, euid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setrlimit(which int, lim *Rlimit) (err error) { + _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setsid() (pid int, err error) { + r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0) + pid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Settimeofday(tp *Timeval) (err error) { + _, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setuid(uid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Symlink(path string, link string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(link) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_SYMLINKAT, uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Sync() (err error) { + _, _, e1 := Syscall(SYS_SYNC, 0, 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Truncate(path string, length int64) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), uintptr(length>>32)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Umask(newmask int) (oldmask int) { + r0, _, _ := Syscall(SYS_UMASK, uintptr(newmask), 0, 0) + oldmask = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Undelete(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Unlink(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Unlinkat(dirfd int, path string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Unmount(path string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func write(fd int, p []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) { + r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos), uintptr(pos>>32), 0, 0) + ret = uintptr(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func munmap(addr uintptr, length uintptr) (err error) { + _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func readlen(fd int, buf *byte, nbuf int) (n int, err error) { + r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func writelen(fd int, buf *byte, nbuf int) (n int, err error) { + r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func gettimeofday(tp *Timeval) (sec int32, usec int32, err error) { + r0, r1, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0) + sec = int32(r0) + usec = int32(r1) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstat(fd int, stat *Stat_t) (err error) { + _, _, e1 := Syscall(SYS_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FSTATAT64, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstatfs(fd int, stat *Statfs_t) (err error) { + _, _, e1 := Syscall(SYS_FSTATFS64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_GETDIRENTRIES64, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) { + r0, _, e1 := Syscall(SYS_GETFSSTAT64, uintptr(buf), uintptr(size), uintptr(flags)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Lstat(path string, stat *Stat_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Stat(path string, stat *Stat_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Statfs(path string, stat *Statfs_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.go b/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.go index 763ae4fbb9..23346dc68f 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.go @@ -1,7 +1,7 @@ -// mksyscall.pl -l32 -tags darwin,386 syscall_bsd.go syscall_darwin.go syscall_darwin_386.go +// go run mksyscall.go -l32 -tags darwin,386,go1.12 syscall_bsd.go syscall_darwin.go syscall_darwin_386.go // Code generated by the command above; see README.md. DO NOT EDIT. -// +build darwin,386 +// +build darwin,386,go1.12 package unix @@ -15,7 +15,7 @@ var _ syscall.Errno // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getgroups(ngid int, gid *_Gid_t) (n int, err error) { - r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) + r0, _, e1 := syscall_rawSyscall(funcPC(libc_getgroups_trampoline), uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -23,20 +23,30 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) { return } +func libc_getgroups_trampoline() + +//go:linkname libc_getgroups libc_getgroups +//go:cgo_import_dynamic libc_getgroups getgroups "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func setgroups(ngid int, gid *_Gid_t) (err error) { - _, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_setgroups_trampoline), uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setgroups_trampoline() + +//go:linkname libc_setgroups libc_setgroups +//go:cgo_import_dynamic libc_setgroups setgroups "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) { - r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0) + r0, _, e1 := syscall_syscall6(funcPC(libc_wait4_trampoline), uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0) wpid = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -44,10 +54,15 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err return } +func libc_wait4_trampoline() + +//go:linkname libc_wait4 libc_wait4 +//go:cgo_import_dynamic libc_wait4 wait4 "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { - r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + r0, _, e1 := syscall_syscall(funcPC(libc_accept_trampoline), uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -55,30 +70,45 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { return } +func libc_accept_trampoline() + +//go:linkname libc_accept libc_accept +//go:cgo_import_dynamic libc_accept accept "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { - _, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen)) + _, _, e1 := syscall_syscall(funcPC(libc_bind_trampoline), uintptr(s), uintptr(addr), uintptr(addrlen)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_bind_trampoline() + +//go:linkname libc_bind libc_bind +//go:cgo_import_dynamic libc_bind bind "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { - _, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen)) + _, _, e1 := syscall_syscall(funcPC(libc_connect_trampoline), uintptr(s), uintptr(addr), uintptr(addrlen)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_connect_trampoline() + +//go:linkname libc_connect libc_connect +//go:cgo_import_dynamic libc_connect connect "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func socket(domain int, typ int, proto int) (fd int, err error) { - r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto)) + r0, _, e1 := syscall_rawSyscall(funcPC(libc_socket_trampoline), uintptr(domain), uintptr(typ), uintptr(proto)) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -86,66 +116,101 @@ func socket(domain int, typ int, proto int) (fd int, err error) { return } +func libc_socket_trampoline() + +//go:linkname libc_socket libc_socket +//go:cgo_import_dynamic libc_socket socket "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) { - _, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0) + _, _, e1 := syscall_syscall6(funcPC(libc_getsockopt_trampoline), uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_getsockopt_trampoline() + +//go:linkname libc_getsockopt libc_getsockopt +//go:cgo_import_dynamic libc_getsockopt getsockopt "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) { - _, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0) + _, _, e1 := syscall_syscall6(funcPC(libc_setsockopt_trampoline), uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setsockopt_trampoline() + +//go:linkname libc_setsockopt libc_setsockopt +//go:cgo_import_dynamic libc_setsockopt setsockopt "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { - _, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + _, _, e1 := syscall_rawSyscall(funcPC(libc_getpeername_trampoline), uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) if e1 != 0 { err = errnoErr(e1) } return } +func libc_getpeername_trampoline() + +//go:linkname libc_getpeername libc_getpeername +//go:cgo_import_dynamic libc_getpeername getpeername "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { - _, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + _, _, e1 := syscall_rawSyscall(funcPC(libc_getsockname_trampoline), uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) if e1 != 0 { err = errnoErr(e1) } return } +func libc_getsockname_trampoline() + +//go:linkname libc_getsockname libc_getsockname +//go:cgo_import_dynamic libc_getsockname getsockname "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Shutdown(s int, how int) (err error) { - _, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0) + _, _, e1 := syscall_syscall(funcPC(libc_shutdown_trampoline), uintptr(s), uintptr(how), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_shutdown_trampoline() + +//go:linkname libc_shutdown libc_shutdown +//go:cgo_import_dynamic libc_shutdown shutdown "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) { - _, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0) + _, _, e1 := syscall_rawSyscall6(funcPC(libc_socketpair_trampoline), uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_socketpair_trampoline() + +//go:linkname libc_socketpair libc_socketpair +//go:cgo_import_dynamic libc_socketpair socketpair "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) { @@ -155,7 +220,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen))) + r0, _, e1 := syscall_syscall6(funcPC(libc_recvfrom_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -163,6 +228,11 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl return } +func libc_recvfrom_trampoline() + +//go:linkname libc_recvfrom libc_recvfrom +//go:cgo_import_dynamic libc_recvfrom recvfrom "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) { @@ -172,17 +242,22 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) ( } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen)) + _, _, e1 := syscall_syscall6(funcPC(libc_sendto_trampoline), uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_sendto_trampoline() + +//go:linkname libc_sendto libc_sendto +//go:cgo_import_dynamic libc_sendto sendto "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) { - r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + r0, _, e1 := syscall_syscall(funcPC(libc_recvmsg_trampoline), uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -190,10 +265,15 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) { return } +func libc_recvmsg_trampoline() + +//go:linkname libc_recvmsg libc_recvmsg +//go:cgo_import_dynamic libc_recvmsg recvmsg "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) { - r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + r0, _, e1 := syscall_syscall(funcPC(libc_sendmsg_trampoline), uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -201,10 +281,15 @@ func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) { return } +func libc_sendmsg_trampoline() + +//go:linkname libc_sendmsg libc_sendmsg +//go:cgo_import_dynamic libc_sendmsg sendmsg "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) { - r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout))) + r0, _, e1 := syscall_syscall6(funcPC(libc_kevent_trampoline), uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -212,6 +297,11 @@ func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, ne return } +func libc_kevent_trampoline() + +//go:linkname libc_kevent libc_kevent +//go:cgo_import_dynamic libc_kevent kevent "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) { @@ -221,13 +311,18 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) + _, _, e1 := syscall_syscall6(funcPC(libc___sysctl_trampoline), uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) if e1 != 0 { err = errnoErr(e1) } return } +func libc___sysctl_trampoline() + +//go:linkname libc___sysctl libc___sysctl +//go:cgo_import_dynamic libc___sysctl __sysctl "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func utimes(path string, timeval *[2]Timeval) (err error) { @@ -236,27 +331,37 @@ func utimes(path string, timeval *[2]Timeval) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) + _, _, e1 := syscall_syscall(funcPC(libc_utimes_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_utimes_trampoline() + +//go:linkname libc_utimes libc_utimes +//go:cgo_import_dynamic libc_utimes utimes "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func futimes(fd int, timeval *[2]Timeval) (err error) { - _, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0) + _, _, e1 := syscall_syscall(funcPC(libc_futimes_trampoline), uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_futimes_trampoline() + +//go:linkname libc_futimes libc_futimes +//go:cgo_import_dynamic libc_futimes futimes "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func fcntl(fd int, cmd int, arg int) (val int, err error) { - r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg)) + r0, _, e1 := syscall_syscall(funcPC(libc_fcntl_trampoline), uintptr(fd), uintptr(cmd), uintptr(arg)) val = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -264,10 +369,15 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) { return } +func libc_fcntl_trampoline() + +//go:linkname libc_fcntl libc_fcntl +//go:cgo_import_dynamic libc_fcntl fcntl "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { - r0, _, e1 := Syscall(SYS_POLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout)) + r0, _, e1 := syscall_syscall(funcPC(libc_poll_trampoline), uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -275,6 +385,11 @@ func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { return } +func libc_poll_trampoline() + +//go:linkname libc_poll libc_poll +//go:cgo_import_dynamic libc_poll poll "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Madvise(b []byte, behav int) (err error) { @@ -284,13 +399,18 @@ func Madvise(b []byte, behav int) (err error) { } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(behav)) + _, _, e1 := syscall_syscall(funcPC(libc_madvise_trampoline), uintptr(_p0), uintptr(len(b)), uintptr(behav)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_madvise_trampoline() + +//go:linkname libc_madvise libc_madvise +//go:cgo_import_dynamic libc_madvise madvise "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mlock(b []byte) (err error) { @@ -300,23 +420,33 @@ func Mlock(b []byte) (err error) { } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0) + _, _, e1 := syscall_syscall(funcPC(libc_mlock_trampoline), uintptr(_p0), uintptr(len(b)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_mlock_trampoline() + +//go:linkname libc_mlock libc_mlock +//go:cgo_import_dynamic libc_mlock mlock "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mlockall(flags int) (err error) { - _, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_mlockall_trampoline), uintptr(flags), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_mlockall_trampoline() + +//go:linkname libc_mlockall libc_mlockall +//go:cgo_import_dynamic libc_mlockall mlockall "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mprotect(b []byte, prot int) (err error) { @@ -326,13 +456,18 @@ func Mprotect(b []byte, prot int) (err error) { } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot)) + _, _, e1 := syscall_syscall(funcPC(libc_mprotect_trampoline), uintptr(_p0), uintptr(len(b)), uintptr(prot)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_mprotect_trampoline() + +//go:linkname libc_mprotect libc_mprotect +//go:cgo_import_dynamic libc_mprotect mprotect "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Msync(b []byte, flags int) (err error) { @@ -342,13 +477,18 @@ func Msync(b []byte, flags int) (err error) { } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall(SYS_MSYNC, uintptr(_p0), uintptr(len(b)), uintptr(flags)) + _, _, e1 := syscall_syscall(funcPC(libc_msync_trampoline), uintptr(_p0), uintptr(len(b)), uintptr(flags)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_msync_trampoline() + +//go:linkname libc_msync libc_msync +//go:cgo_import_dynamic libc_msync msync "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Munlock(b []byte) (err error) { @@ -358,37 +498,67 @@ func Munlock(b []byte) (err error) { } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0) + _, _, e1 := syscall_syscall(funcPC(libc_munlock_trampoline), uintptr(_p0), uintptr(len(b)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_munlock_trampoline() + +//go:linkname libc_munlock libc_munlock +//go:cgo_import_dynamic libc_munlock munlock "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Munlockall() (err error) { - _, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_munlockall_trampoline), 0, 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_munlockall_trampoline() + +//go:linkname libc_munlockall libc_munlockall +//go:cgo_import_dynamic libc_munlockall munlockall "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) { - _, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0) + _, _, e1 := syscall_syscall6(funcPC(libc_ptrace_trampoline), uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_ptrace_trampoline() + +//go:linkname libc_ptrace libc_ptrace +//go:cgo_import_dynamic libc_ptrace ptrace "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error) { + _, _, e1 := syscall_syscall6(funcPC(libc_getattrlist_trampoline), uintptr(unsafe.Pointer(path)), uintptr(list), uintptr(buf), uintptr(size), uintptr(options), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_getattrlist_trampoline() + +//go:linkname libc_getattrlist libc_getattrlist +//go:cgo_import_dynamic libc_getattrlist getattrlist "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func pipe() (r int, w int, err error) { - r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0) + r0, r1, e1 := syscall_rawSyscall(funcPC(libc_pipe_trampoline), 0, 0, 0) r = int(r0) w = int(r1) if e1 != 0 { @@ -397,26 +567,245 @@ func pipe() (r int, w int, err error) { return } +func libc_pipe_trampoline() + +//go:linkname libc_pipe libc_pipe +//go:cgo_import_dynamic libc_pipe pipe "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func kill(pid int, signum int, posix int) (err error) { - _, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), uintptr(posix)) +func getxattr(path string, attr string, dest *byte, size int, position uint32, options int) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + r0, _, e1 := syscall_syscall6(funcPC(libc_getxattr_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(position), uintptr(options)) + sz = int(r0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_getxattr_trampoline() + +//go:linkname libc_getxattr libc_getxattr +//go:cgo_import_dynamic libc_getxattr getxattr "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fgetxattr(fd int, attr string, dest *byte, size int, position uint32, options int) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + r0, _, e1 := syscall_syscall6(funcPC(libc_fgetxattr_trampoline), uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(position), uintptr(options)) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_fgetxattr_trampoline() + +//go:linkname libc_fgetxattr libc_fgetxattr +//go:cgo_import_dynamic libc_fgetxattr fgetxattr "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setxattr(path string, attr string, data *byte, size int, position uint32, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := syscall_syscall6(funcPC(libc_setxattr_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(data)), uintptr(size), uintptr(position), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_setxattr_trampoline() + +//go:linkname libc_setxattr libc_setxattr +//go:cgo_import_dynamic libc_setxattr setxattr "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fsetxattr(fd int, attr string, data *byte, size int, position uint32, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := syscall_syscall6(funcPC(libc_fsetxattr_trampoline), uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(data)), uintptr(size), uintptr(position), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_fsetxattr_trampoline() + +//go:linkname libc_fsetxattr libc_fsetxattr +//go:cgo_import_dynamic libc_fsetxattr fsetxattr "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func removexattr(path string, attr string, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := syscall_syscall(funcPC(libc_removexattr_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_removexattr_trampoline() + +//go:linkname libc_removexattr libc_removexattr +//go:cgo_import_dynamic libc_removexattr removexattr "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fremovexattr(fd int, attr string, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := syscall_syscall(funcPC(libc_fremovexattr_trampoline), uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_fremovexattr_trampoline() + +//go:linkname libc_fremovexattr libc_fremovexattr +//go:cgo_import_dynamic libc_fremovexattr fremovexattr "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func listxattr(path string, dest *byte, size int, options int) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := syscall_syscall6(funcPC(libc_listxattr_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(options), 0, 0) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_listxattr_trampoline() + +//go:linkname libc_listxattr libc_listxattr +//go:cgo_import_dynamic libc_listxattr listxattr "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func flistxattr(fd int, dest *byte, size int, options int) (sz int, err error) { + r0, _, e1 := syscall_syscall6(funcPC(libc_flistxattr_trampoline), uintptr(fd), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(options), 0, 0) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_flistxattr_trampoline() + +//go:linkname libc_flistxattr libc_flistxattr +//go:cgo_import_dynamic libc_flistxattr flistxattr "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error) { + _, _, e1 := syscall_syscall6(funcPC(libc_setattrlist_trampoline), uintptr(unsafe.Pointer(path)), uintptr(list), uintptr(buf), uintptr(size), uintptr(options), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_setattrlist_trampoline() + +//go:linkname libc_setattrlist libc_setattrlist +//go:cgo_import_dynamic libc_setattrlist setattrlist "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func kill(pid int, signum int, posix int) (err error) { + _, _, e1 := syscall_syscall(funcPC(libc_kill_trampoline), uintptr(pid), uintptr(signum), uintptr(posix)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_kill_trampoline() + +//go:linkname libc_kill libc_kill +//go:cgo_import_dynamic libc_kill kill "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func ioctl(fd int, req uint, arg uintptr) (err error) { - _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg)) + _, _, e1 := syscall_syscall(funcPC(libc_ioctl_trampoline), uintptr(fd), uintptr(req), uintptr(arg)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_ioctl_trampoline() + +//go:linkname libc_ioctl libc_ioctl +//go:cgo_import_dynamic libc_ioctl ioctl "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) { + _, _, e1 := syscall_syscall9(funcPC(libc_sendfile_trampoline), uintptr(infd), uintptr(outfd), uintptr(offset), uintptr(offset>>32), uintptr(unsafe.Pointer(len)), uintptr(hdtr), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_sendfile_trampoline() + +//go:linkname libc_sendfile libc_sendfile +//go:cgo_import_dynamic libc_sendfile sendfile "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Access(path string, mode uint32) (err error) { @@ -425,23 +814,33 @@ func Access(path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + _, _, e1 := syscall_syscall(funcPC(libc_access_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_access_trampoline() + +//go:linkname libc_access libc_access +//go:cgo_import_dynamic libc_access access "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Adjtime(delta *Timeval, olddelta *Timeval) (err error) { - _, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0) + _, _, e1 := syscall_syscall(funcPC(libc_adjtime_trampoline), uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_adjtime_trampoline() + +//go:linkname libc_adjtime libc_adjtime +//go:cgo_import_dynamic libc_adjtime adjtime "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Chdir(path string) (err error) { @@ -450,13 +849,18 @@ func Chdir(path string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_chdir_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_chdir_trampoline() + +//go:linkname libc_chdir libc_chdir +//go:cgo_import_dynamic libc_chdir chdir "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Chflags(path string, flags int) (err error) { @@ -465,13 +869,18 @@ func Chflags(path string, flags int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + _, _, e1 := syscall_syscall(funcPC(libc_chflags_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_chflags_trampoline() + +//go:linkname libc_chflags libc_chflags +//go:cgo_import_dynamic libc_chflags chflags "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Chmod(path string, mode uint32) (err error) { @@ -480,13 +889,18 @@ func Chmod(path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + _, _, e1 := syscall_syscall(funcPC(libc_chmod_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_chmod_trampoline() + +//go:linkname libc_chmod libc_chmod +//go:cgo_import_dynamic libc_chmod chmod "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Chown(path string, uid int, gid int) (err error) { @@ -495,13 +909,18 @@ func Chown(path string, uid int, gid int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + _, _, e1 := syscall_syscall(funcPC(libc_chown_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_chown_trampoline() + +//go:linkname libc_chown libc_chown +//go:cgo_import_dynamic libc_chown chown "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Chroot(path string) (err error) { @@ -510,27 +929,37 @@ func Chroot(path string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_chroot_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_chroot_trampoline() + +//go:linkname libc_chroot libc_chroot +//go:cgo_import_dynamic libc_chroot chroot "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Close(fd int) (err error) { - _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_close_trampoline), uintptr(fd), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_close_trampoline() + +//go:linkname libc_close libc_close +//go:cgo_import_dynamic libc_close close "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Dup(fd int) (nfd int, err error) { - r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0) + r0, _, e1 := syscall_syscall(funcPC(libc_dup_trampoline), uintptr(fd), 0, 0) nfd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -538,16 +967,26 @@ func Dup(fd int) (nfd int, err error) { return } +func libc_dup_trampoline() + +//go:linkname libc_dup libc_dup +//go:cgo_import_dynamic libc_dup dup "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Dup2(from int, to int) (err error) { - _, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0) + _, _, e1 := syscall_syscall(funcPC(libc_dup2_trampoline), uintptr(from), uintptr(to), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_dup2_trampoline() + +//go:linkname libc_dup2 libc_dup2 +//go:cgo_import_dynamic libc_dup2 dup2 "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Exchangedata(path1 string, path2 string, options int) (err error) { @@ -561,20 +1000,30 @@ func Exchangedata(path1 string, path2 string, options int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_EXCHANGEDATA, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) + _, _, e1 := syscall_syscall(funcPC(libc_exchangedata_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_exchangedata_trampoline() + +//go:linkname libc_exchangedata libc_exchangedata +//go:cgo_import_dynamic libc_exchangedata exchangedata "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Exit(code int) { - Syscall(SYS_EXIT, uintptr(code), 0, 0) + syscall_syscall(funcPC(libc_exit_trampoline), uintptr(code), 0, 0) return } +func libc_exit_trampoline() + +//go:linkname libc_exit libc_exit +//go:cgo_import_dynamic libc_exit exit "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { @@ -583,43 +1032,63 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { if err != nil { return } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + _, _, e1 := syscall_syscall6(funcPC(libc_faccessat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_faccessat_trampoline() + +//go:linkname libc_faccessat libc_faccessat +//go:cgo_import_dynamic libc_faccessat faccessat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchdir(fd int) (err error) { - _, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_fchdir_trampoline), uintptr(fd), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_fchdir_trampoline() + +//go:linkname libc_fchdir libc_fchdir +//go:cgo_import_dynamic libc_fchdir fchdir "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchflags(fd int, flags int) (err error) { - _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0) + _, _, e1 := syscall_syscall(funcPC(libc_fchflags_trampoline), uintptr(fd), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_fchflags_trampoline() + +//go:linkname libc_fchflags libc_fchflags +//go:cgo_import_dynamic libc_fchflags fchflags "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchmod(fd int, mode uint32) (err error) { - _, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0) + _, _, e1 := syscall_syscall(funcPC(libc_fchmod_trampoline), uintptr(fd), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_fchmod_trampoline() + +//go:linkname libc_fchmod libc_fchmod +//go:cgo_import_dynamic libc_fchmod fchmod "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { @@ -628,23 +1097,33 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { if err != nil { return } - _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + _, _, e1 := syscall_syscall6(funcPC(libc_fchmodat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_fchmodat_trampoline() + +//go:linkname libc_fchmodat libc_fchmodat +//go:cgo_import_dynamic libc_fchmodat fchmodat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchown(fd int, uid int, gid int) (err error) { - _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)) + _, _, e1 := syscall_syscall(funcPC(libc_fchown_trampoline), uintptr(fd), uintptr(uid), uintptr(gid)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_fchown_trampoline() + +//go:linkname libc_fchown libc_fchown +//go:cgo_import_dynamic libc_fchown fchown "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { @@ -653,27 +1132,37 @@ func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { if err != nil { return } - _, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0) + _, _, e1 := syscall_syscall6(funcPC(libc_fchownat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_fchownat_trampoline() + +//go:linkname libc_fchownat libc_fchownat +//go:cgo_import_dynamic libc_fchownat fchownat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Flock(fd int, how int) (err error) { - _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0) + _, _, e1 := syscall_syscall(funcPC(libc_flock_trampoline), uintptr(fd), uintptr(how), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_flock_trampoline() + +//go:linkname libc_flock libc_flock +//go:cgo_import_dynamic libc_flock flock "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fpathconf(fd int, name int) (val int, err error) { - r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0) + r0, _, e1 := syscall_syscall(funcPC(libc_fpathconf_trampoline), uintptr(fd), uintptr(name), 0) val = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -681,99 +1170,97 @@ func Fpathconf(fd int, name int) (val int, err error) { return } -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func libc_fpathconf_trampoline() -func Fstat(fd int, stat *Stat_t) (err error) { - _, _, e1 := Syscall(SYS_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Fstatfs(fd int, stat *Statfs_t) (err error) { - _, _, e1 := Syscall(SYS_FSTATFS64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} +//go:linkname libc_fpathconf libc_fpathconf +//go:cgo_import_dynamic libc_fpathconf fpathconf "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fsync(fd int) (err error) { - _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_fsync_trampoline), uintptr(fd), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_fsync_trampoline() + +//go:linkname libc_fsync libc_fsync +//go:cgo_import_dynamic libc_fsync fsync "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Ftruncate(fd int, length int64) (err error) { - _, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), uintptr(length>>32)) + _, _, e1 := syscall_syscall(funcPC(libc_ftruncate_trampoline), uintptr(fd), uintptr(length), uintptr(length>>32)) if e1 != 0 { err = errnoErr(e1) } return } -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func libc_ftruncate_trampoline() -func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { - var _p0 unsafe.Pointer - if len(buf) > 0 { - _p0 = unsafe.Pointer(&buf[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall6(SYS_GETDIRENTRIES64, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} +//go:linkname libc_ftruncate libc_ftruncate +//go:cgo_import_dynamic libc_ftruncate ftruncate "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getdtablesize() (size int) { - r0, _, _ := Syscall(SYS_GETDTABLESIZE, 0, 0, 0) + r0, _, _ := syscall_syscall(funcPC(libc_getdtablesize_trampoline), 0, 0, 0) size = int(r0) return } +func libc_getdtablesize_trampoline() + +//go:linkname libc_getdtablesize libc_getdtablesize +//go:cgo_import_dynamic libc_getdtablesize getdtablesize "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getegid() (egid int) { - r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(funcPC(libc_getegid_trampoline), 0, 0, 0) egid = int(r0) return } +func libc_getegid_trampoline() + +//go:linkname libc_getegid libc_getegid +//go:cgo_import_dynamic libc_getegid getegid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Geteuid() (uid int) { - r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(funcPC(libc_geteuid_trampoline), 0, 0, 0) uid = int(r0) return } +func libc_geteuid_trampoline() + +//go:linkname libc_geteuid libc_geteuid +//go:cgo_import_dynamic libc_geteuid geteuid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getgid() (gid int) { - r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(funcPC(libc_getgid_trampoline), 0, 0, 0) gid = int(r0) return } +func libc_getgid_trampoline() + +//go:linkname libc_getgid libc_getgid +//go:cgo_import_dynamic libc_getgid getgid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpgid(pid int) (pgid int, err error) { - r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0) + r0, _, e1 := syscall_rawSyscall(funcPC(libc_getpgid_trampoline), uintptr(pid), 0, 0) pgid = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -781,34 +1268,54 @@ func Getpgid(pid int) (pgid int, err error) { return } +func libc_getpgid_trampoline() + +//go:linkname libc_getpgid libc_getpgid +//go:cgo_import_dynamic libc_getpgid getpgid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpgrp() (pgrp int) { - r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(funcPC(libc_getpgrp_trampoline), 0, 0, 0) pgrp = int(r0) return } +func libc_getpgrp_trampoline() + +//go:linkname libc_getpgrp libc_getpgrp +//go:cgo_import_dynamic libc_getpgrp getpgrp "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpid() (pid int) { - r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(funcPC(libc_getpid_trampoline), 0, 0, 0) pid = int(r0) return } +func libc_getpid_trampoline() + +//go:linkname libc_getpid libc_getpid +//go:cgo_import_dynamic libc_getpid getpid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getppid() (ppid int) { - r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(funcPC(libc_getppid_trampoline), 0, 0, 0) ppid = int(r0) return } +func libc_getppid_trampoline() + +//go:linkname libc_getppid libc_getppid +//go:cgo_import_dynamic libc_getppid getppid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpriority(which int, who int) (prio int, err error) { - r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0) + r0, _, e1 := syscall_syscall(funcPC(libc_getpriority_trampoline), uintptr(which), uintptr(who), 0) prio = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -816,30 +1323,45 @@ func Getpriority(which int, who int) (prio int, err error) { return } +func libc_getpriority_trampoline() + +//go:linkname libc_getpriority libc_getpriority +//go:cgo_import_dynamic libc_getpriority getpriority "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getrlimit(which int, lim *Rlimit) (err error) { - _, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_getrlimit_trampoline), uintptr(which), uintptr(unsafe.Pointer(lim)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_getrlimit_trampoline() + +//go:linkname libc_getrlimit libc_getrlimit +//go:cgo_import_dynamic libc_getrlimit getrlimit "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getrusage(who int, rusage *Rusage) (err error) { - _, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_getrusage_trampoline), uintptr(who), uintptr(unsafe.Pointer(rusage)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_getrusage_trampoline() + +//go:linkname libc_getrusage libc_getrusage +//go:cgo_import_dynamic libc_getrusage getrusage "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getsid(pid int) (sid int, err error) { - r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0) + r0, _, e1 := syscall_rawSyscall(funcPC(libc_getsid_trampoline), uintptr(pid), 0, 0) sid = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -847,26 +1369,41 @@ func Getsid(pid int) (sid int, err error) { return } +func libc_getsid_trampoline() + +//go:linkname libc_getsid libc_getsid +//go:cgo_import_dynamic libc_getsid getsid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getuid() (uid int) { - r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(funcPC(libc_getuid_trampoline), 0, 0, 0) uid = int(r0) return } +func libc_getuid_trampoline() + +//go:linkname libc_getuid libc_getuid +//go:cgo_import_dynamic libc_getuid getuid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Issetugid() (tainted bool) { - r0, _, _ := RawSyscall(SYS_ISSETUGID, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(funcPC(libc_issetugid_trampoline), 0, 0, 0) tainted = bool(r0 != 0) return } +func libc_issetugid_trampoline() + +//go:linkname libc_issetugid libc_issetugid +//go:cgo_import_dynamic libc_issetugid issetugid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Kqueue() (fd int, err error) { - r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0) + r0, _, e1 := syscall_syscall(funcPC(libc_kqueue_trampoline), 0, 0, 0) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -874,6 +1411,11 @@ func Kqueue() (fd int, err error) { return } +func libc_kqueue_trampoline() + +//go:linkname libc_kqueue libc_kqueue +//go:cgo_import_dynamic libc_kqueue kqueue "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Lchown(path string, uid int, gid int) (err error) { @@ -882,13 +1424,18 @@ func Lchown(path string, uid int, gid int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + _, _, e1 := syscall_syscall(funcPC(libc_lchown_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_lchown_trampoline() + +//go:linkname libc_lchown libc_lchown +//go:cgo_import_dynamic libc_lchown lchown "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Link(path string, link string) (err error) { @@ -902,13 +1449,18 @@ func Link(path string, link string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + _, _, e1 := syscall_syscall(funcPC(libc_link_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_link_trampoline() + +//go:linkname libc_link libc_link +//go:cgo_import_dynamic libc_link link "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error) { @@ -922,37 +1474,32 @@ func Linkat(pathfd int, path string, linkfd int, link string, flags int) (err er if err != nil { return } - _, _, e1 := Syscall6(SYS_LINKAT, uintptr(pathfd), uintptr(unsafe.Pointer(_p0)), uintptr(linkfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) + _, _, e1 := syscall_syscall6(funcPC(libc_linkat_trampoline), uintptr(pathfd), uintptr(unsafe.Pointer(_p0)), uintptr(linkfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_linkat_trampoline() + +//go:linkname libc_linkat libc_linkat +//go:cgo_import_dynamic libc_linkat linkat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Listen(s int, backlog int) (err error) { - _, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0) + _, _, e1 := syscall_syscall(funcPC(libc_listen_trampoline), uintptr(s), uintptr(backlog), 0) if e1 != 0 { err = errnoErr(e1) } return } -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func libc_listen_trampoline() -func Lstat(path string, stat *Stat_t) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} +//go:linkname libc_listen libc_listen +//go:cgo_import_dynamic libc_listen listen "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT @@ -962,13 +1509,18 @@ func Mkdir(path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + _, _, e1 := syscall_syscall(funcPC(libc_mkdir_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_mkdir_trampoline() + +//go:linkname libc_mkdir libc_mkdir +//go:cgo_import_dynamic libc_mkdir mkdir "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mkdirat(dirfd int, path string, mode uint32) (err error) { @@ -977,13 +1529,18 @@ func Mkdirat(dirfd int, path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + _, _, e1 := syscall_syscall(funcPC(libc_mkdirat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_mkdirat_trampoline() + +//go:linkname libc_mkdirat libc_mkdirat +//go:cgo_import_dynamic libc_mkdirat mkdirat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mkfifo(path string, mode uint32) (err error) { @@ -992,13 +1549,18 @@ func Mkfifo(path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + _, _, e1 := syscall_syscall(funcPC(libc_mkfifo_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_mkfifo_trampoline() + +//go:linkname libc_mkfifo libc_mkfifo +//go:cgo_import_dynamic libc_mkfifo mkfifo "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mknod(path string, mode uint32, dev int) (err error) { @@ -1007,13 +1569,18 @@ func Mknod(path string, mode uint32, dev int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) + _, _, e1 := syscall_syscall(funcPC(libc_mknod_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_mknod_trampoline() + +//go:linkname libc_mknod libc_mknod +//go:cgo_import_dynamic libc_mknod mknod "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Open(path string, mode int, perm uint32) (fd int, err error) { @@ -1022,7 +1589,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { if err != nil { return } - r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) + r0, _, e1 := syscall_syscall(funcPC(libc_open_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1030,6 +1597,11 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { return } +func libc_open_trampoline() + +//go:linkname libc_open libc_open +//go:cgo_import_dynamic libc_open open "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) { @@ -1038,7 +1610,7 @@ func Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) { if err != nil { return } - r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0) + r0, _, e1 := syscall_syscall6(funcPC(libc_openat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1046,6 +1618,11 @@ func Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) { return } +func libc_openat_trampoline() + +//go:linkname libc_openat libc_openat +//go:cgo_import_dynamic libc_openat openat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Pathconf(path string, name int) (val int, err error) { @@ -1054,7 +1631,7 @@ func Pathconf(path string, name int) (val int, err error) { if err != nil { return } - r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) + r0, _, e1 := syscall_syscall(funcPC(libc_pathconf_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) val = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1062,6 +1639,11 @@ func Pathconf(path string, name int) (val int, err error) { return } +func libc_pathconf_trampoline() + +//go:linkname libc_pathconf libc_pathconf +//go:cgo_import_dynamic libc_pathconf pathconf "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Pread(fd int, p []byte, offset int64) (n int, err error) { @@ -1071,7 +1653,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0) + r0, _, e1 := syscall_syscall6(funcPC(libc_pread_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1079,6 +1661,11 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) { return } +func libc_pread_trampoline() + +//go:linkname libc_pread libc_pread +//go:cgo_import_dynamic libc_pread pread "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Pwrite(fd int, p []byte, offset int64) (n int, err error) { @@ -1088,7 +1675,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0) + r0, _, e1 := syscall_syscall6(funcPC(libc_pwrite_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1096,6 +1683,11 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) { return } +func libc_pwrite_trampoline() + +//go:linkname libc_pwrite libc_pwrite +//go:cgo_import_dynamic libc_pwrite pwrite "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func read(fd int, p []byte) (n int, err error) { @@ -1105,7 +1697,7 @@ func read(fd int, p []byte) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p))) + r0, _, e1 := syscall_syscall(funcPC(libc_read_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1113,6 +1705,11 @@ func read(fd int, p []byte) (n int, err error) { return } +func libc_read_trampoline() + +//go:linkname libc_read libc_read +//go:cgo_import_dynamic libc_read read "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Readlink(path string, buf []byte) (n int, err error) { @@ -1127,7 +1724,7 @@ func Readlink(path string, buf []byte) (n int, err error) { } else { _p1 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) + r0, _, e1 := syscall_syscall(funcPC(libc_readlink_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1135,6 +1732,11 @@ func Readlink(path string, buf []byte) (n int, err error) { return } +func libc_readlink_trampoline() + +//go:linkname libc_readlink libc_readlink +//go:cgo_import_dynamic libc_readlink readlink "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { @@ -1149,7 +1751,7 @@ func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { } else { _p1 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall6(SYS_READLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0) + r0, _, e1 := syscall_syscall6(funcPC(libc_readlinkat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1157,6 +1759,11 @@ func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { return } +func libc_readlinkat_trampoline() + +//go:linkname libc_readlinkat libc_readlinkat +//go:cgo_import_dynamic libc_readlinkat readlinkat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Rename(from string, to string) (err error) { @@ -1170,13 +1777,18 @@ func Rename(from string, to string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + _, _, e1 := syscall_syscall(funcPC(libc_rename_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_rename_trampoline() + +//go:linkname libc_rename libc_rename +//go:cgo_import_dynamic libc_rename rename "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Renameat(fromfd int, from string, tofd int, to string) (err error) { @@ -1190,13 +1802,18 @@ func Renameat(fromfd int, from string, tofd int, to string) (err error) { if err != nil { return } - _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(fromfd), uintptr(unsafe.Pointer(_p0)), uintptr(tofd), uintptr(unsafe.Pointer(_p1)), 0, 0) + _, _, e1 := syscall_syscall6(funcPC(libc_renameat_trampoline), uintptr(fromfd), uintptr(unsafe.Pointer(_p0)), uintptr(tofd), uintptr(unsafe.Pointer(_p1)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_renameat_trampoline() + +//go:linkname libc_renameat libc_renameat +//go:cgo_import_dynamic libc_renameat renameat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Revoke(path string) (err error) { @@ -1205,13 +1822,18 @@ func Revoke(path string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_revoke_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_revoke_trampoline() + +//go:linkname libc_revoke libc_revoke +//go:cgo_import_dynamic libc_revoke revoke "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Rmdir(path string) (err error) { @@ -1220,17 +1842,22 @@ func Rmdir(path string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_rmdir_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_rmdir_trampoline() + +//go:linkname libc_rmdir libc_rmdir +//go:cgo_import_dynamic libc_rmdir rmdir "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { - r0, r1, e1 := Syscall6(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(offset>>32), uintptr(whence), 0, 0) + r0, r1, e1 := syscall_syscall6(funcPC(libc_lseek_trampoline), uintptr(fd), uintptr(offset), uintptr(offset>>32), uintptr(whence), 0, 0) newoffset = int64(int64(r1)<<32 | int64(r0)) if e1 != 0 { err = errnoErr(e1) @@ -1238,46 +1865,71 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { return } +func libc_lseek_trampoline() + +//go:linkname libc_lseek libc_lseek +//go:cgo_import_dynamic libc_lseek lseek "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) { - _, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0) + _, _, e1 := syscall_syscall6(funcPC(libc_select_trampoline), uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_select_trampoline() + +//go:linkname libc_select libc_select +//go:cgo_import_dynamic libc_select select "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setegid(egid int) (err error) { - _, _, e1 := Syscall(SYS_SETEGID, uintptr(egid), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_setegid_trampoline), uintptr(egid), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setegid_trampoline() + +//go:linkname libc_setegid libc_setegid +//go:cgo_import_dynamic libc_setegid setegid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Seteuid(euid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_seteuid_trampoline), uintptr(euid), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_seteuid_trampoline() + +//go:linkname libc_seteuid libc_seteuid +//go:cgo_import_dynamic libc_seteuid seteuid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setgid(gid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_setgid_trampoline), uintptr(gid), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setgid_trampoline() + +//go:linkname libc_setgid libc_setgid +//go:cgo_import_dynamic libc_setgid setgid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setlogin(name string) (err error) { @@ -1286,77 +1938,112 @@ func Setlogin(name string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_setlogin_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setlogin_trampoline() + +//go:linkname libc_setlogin libc_setlogin +//go:cgo_import_dynamic libc_setlogin setlogin "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setpgid(pid int, pgid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_setpgid_trampoline), uintptr(pid), uintptr(pgid), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setpgid_trampoline() + +//go:linkname libc_setpgid libc_setpgid +//go:cgo_import_dynamic libc_setpgid setpgid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setpriority(which int, who int, prio int) (err error) { - _, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio)) + _, _, e1 := syscall_syscall(funcPC(libc_setpriority_trampoline), uintptr(which), uintptr(who), uintptr(prio)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setpriority_trampoline() + +//go:linkname libc_setpriority libc_setpriority +//go:cgo_import_dynamic libc_setpriority setpriority "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setprivexec(flag int) (err error) { - _, _, e1 := Syscall(SYS_SETPRIVEXEC, uintptr(flag), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_setprivexec_trampoline), uintptr(flag), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setprivexec_trampoline() + +//go:linkname libc_setprivexec libc_setprivexec +//go:cgo_import_dynamic libc_setprivexec setprivexec "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setregid(rgid int, egid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_setregid_trampoline), uintptr(rgid), uintptr(egid), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setregid_trampoline() + +//go:linkname libc_setregid libc_setregid +//go:cgo_import_dynamic libc_setregid setregid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setreuid(ruid int, euid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_setreuid_trampoline), uintptr(ruid), uintptr(euid), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setreuid_trampoline() + +//go:linkname libc_setreuid libc_setreuid +//go:cgo_import_dynamic libc_setreuid setreuid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setrlimit(which int, lim *Rlimit) (err error) { - _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_setrlimit_trampoline), uintptr(which), uintptr(unsafe.Pointer(lim)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setrlimit_trampoline() + +//go:linkname libc_setrlimit libc_setrlimit +//go:cgo_import_dynamic libc_setrlimit setrlimit "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setsid() (pid int, err error) { - r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0) + r0, _, e1 := syscall_rawSyscall(funcPC(libc_setsid_trampoline), 0, 0, 0) pid = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1364,55 +2051,40 @@ func Setsid() (pid int, err error) { return } +func libc_setsid_trampoline() + +//go:linkname libc_setsid libc_setsid +//go:cgo_import_dynamic libc_setsid setsid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Settimeofday(tp *Timeval) (err error) { - _, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_settimeofday_trampoline), uintptr(unsafe.Pointer(tp)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_settimeofday_trampoline() + +//go:linkname libc_settimeofday libc_settimeofday +//go:cgo_import_dynamic libc_settimeofday settimeofday "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setuid(uid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_setuid_trampoline), uintptr(uid), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func libc_setuid_trampoline() -func Stat(path string, stat *Stat_t) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Statfs(path string, stat *Statfs_t) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} +//go:linkname libc_setuid libc_setuid +//go:cgo_import_dynamic libc_setuid setuid "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT @@ -1427,13 +2099,18 @@ func Symlink(path string, link string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + _, _, e1 := syscall_syscall(funcPC(libc_symlink_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_symlink_trampoline() + +//go:linkname libc_symlink libc_symlink +//go:cgo_import_dynamic libc_symlink symlink "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) { @@ -1447,23 +2124,33 @@ func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_SYMLINKAT, uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1))) + _, _, e1 := syscall_syscall(funcPC(libc_symlinkat_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1))) if e1 != 0 { err = errnoErr(e1) } return } +func libc_symlinkat_trampoline() + +//go:linkname libc_symlinkat libc_symlinkat +//go:cgo_import_dynamic libc_symlinkat symlinkat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Sync() (err error) { - _, _, e1 := Syscall(SYS_SYNC, 0, 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_sync_trampoline), 0, 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_sync_trampoline() + +//go:linkname libc_sync libc_sync +//go:cgo_import_dynamic libc_sync sync "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Truncate(path string, length int64) (err error) { @@ -1472,21 +2159,31 @@ func Truncate(path string, length int64) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), uintptr(length>>32)) + _, _, e1 := syscall_syscall(funcPC(libc_truncate_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(length), uintptr(length>>32)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_truncate_trampoline() + +//go:linkname libc_truncate libc_truncate +//go:cgo_import_dynamic libc_truncate truncate "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Umask(newmask int) (oldmask int) { - r0, _, _ := Syscall(SYS_UMASK, uintptr(newmask), 0, 0) + r0, _, _ := syscall_syscall(funcPC(libc_umask_trampoline), uintptr(newmask), 0, 0) oldmask = int(r0) return } +func libc_umask_trampoline() + +//go:linkname libc_umask libc_umask +//go:cgo_import_dynamic libc_umask umask "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Undelete(path string) (err error) { @@ -1495,13 +2192,18 @@ func Undelete(path string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_undelete_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_undelete_trampoline() + +//go:linkname libc_undelete libc_undelete +//go:cgo_import_dynamic libc_undelete undelete "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Unlink(path string) (err error) { @@ -1510,13 +2212,18 @@ func Unlink(path string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_unlink_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_unlink_trampoline() + +//go:linkname libc_unlink libc_unlink +//go:cgo_import_dynamic libc_unlink unlink "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Unlinkat(dirfd int, path string, flags int) (err error) { @@ -1525,13 +2232,18 @@ func Unlinkat(dirfd int, path string, flags int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + _, _, e1 := syscall_syscall(funcPC(libc_unlinkat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_unlinkat_trampoline() + +//go:linkname libc_unlinkat libc_unlinkat +//go:cgo_import_dynamic libc_unlinkat unlinkat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Unmount(path string, flags int) (err error) { @@ -1540,13 +2252,18 @@ func Unmount(path string, flags int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + _, _, e1 := syscall_syscall(funcPC(libc_unmount_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_unmount_trampoline() + +//go:linkname libc_unmount libc_unmount +//go:cgo_import_dynamic libc_unmount unmount "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func write(fd int, p []byte) (n int, err error) { @@ -1556,7 +2273,7 @@ func write(fd int, p []byte) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p))) + r0, _, e1 := syscall_syscall(funcPC(libc_write_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1564,10 +2281,15 @@ func write(fd int, p []byte) (n int, err error) { return } +func libc_write_trampoline() + +//go:linkname libc_write libc_write +//go:cgo_import_dynamic libc_write write "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) { - r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos), uintptr(pos>>32), 0, 0) + r0, _, e1 := syscall_syscall9(funcPC(libc_mmap_trampoline), uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos), uintptr(pos>>32), 0, 0) ret = uintptr(r0) if e1 != 0 { err = errnoErr(e1) @@ -1575,20 +2297,30 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) ( return } +func libc_mmap_trampoline() + +//go:linkname libc_mmap libc_mmap +//go:cgo_import_dynamic libc_mmap mmap "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func munmap(addr uintptr, length uintptr) (err error) { - _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0) + _, _, e1 := syscall_syscall(funcPC(libc_munmap_trampoline), uintptr(addr), uintptr(length), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_munmap_trampoline() + +//go:linkname libc_munmap libc_munmap +//go:cgo_import_dynamic libc_munmap munmap "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func readlen(fd int, buf *byte, nbuf int) (n int, err error) { - r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) + r0, _, e1 := syscall_syscall(funcPC(libc_read_trampoline), uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1599,7 +2331,7 @@ func readlen(fd int, buf *byte, nbuf int) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func writelen(fd int, buf *byte, nbuf int) (n int, err error) { - r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) + r0, _, e1 := syscall_syscall(funcPC(libc_write_trampoline), uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1610,7 +2342,7 @@ func writelen(fd int, buf *byte, nbuf int) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func gettimeofday(tp *Timeval) (sec int32, usec int32, err error) { - r0, r1, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0) + r0, r1, e1 := syscall_rawSyscall(funcPC(libc_gettimeofday_trampoline), uintptr(unsafe.Pointer(tp)), 0, 0) sec = int32(r0) usec = int32(r1) if e1 != 0 { @@ -1618,3 +2350,156 @@ func gettimeofday(tp *Timeval) (sec int32, usec int32, err error) { } return } + +func libc_gettimeofday_trampoline() + +//go:linkname libc_gettimeofday libc_gettimeofday +//go:cgo_import_dynamic libc_gettimeofday gettimeofday "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstat(fd int, stat *Stat_t) (err error) { + _, _, e1 := syscall_syscall(funcPC(libc_fstat64_trampoline), uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_fstat64_trampoline() + +//go:linkname libc_fstat64 libc_fstat64 +//go:cgo_import_dynamic libc_fstat64 fstat64 "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := syscall_syscall6(funcPC(libc_fstatat64_trampoline), uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_fstatat64_trampoline() + +//go:linkname libc_fstatat64 libc_fstatat64 +//go:cgo_import_dynamic libc_fstatat64 fstatat64 "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstatfs(fd int, stat *Statfs_t) (err error) { + _, _, e1 := syscall_syscall(funcPC(libc_fstatfs64_trampoline), uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_fstatfs64_trampoline() + +//go:linkname libc_fstatfs64 libc_fstatfs64 +//go:cgo_import_dynamic libc_fstatfs64 fstatfs64 "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := syscall_syscall6(funcPC(libc___getdirentries64_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc___getdirentries64_trampoline() + +//go:linkname libc___getdirentries64 libc___getdirentries64 +//go:cgo_import_dynamic libc___getdirentries64 __getdirentries64 "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) { + r0, _, e1 := syscall_syscall(funcPC(libc_getfsstat64_trampoline), uintptr(buf), uintptr(size), uintptr(flags)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_getfsstat64_trampoline() + +//go:linkname libc_getfsstat64 libc_getfsstat64 +//go:cgo_import_dynamic libc_getfsstat64 getfsstat64 "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Lstat(path string, stat *Stat_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := syscall_syscall(funcPC(libc_lstat64_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_lstat64_trampoline() + +//go:linkname libc_lstat64 libc_lstat64 +//go:cgo_import_dynamic libc_lstat64 lstat64 "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Stat(path string, stat *Stat_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := syscall_syscall(funcPC(libc_stat64_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_stat64_trampoline() + +//go:linkname libc_stat64 libc_stat64 +//go:cgo_import_dynamic libc_stat64 stat64 "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Statfs(path string, stat *Statfs_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := syscall_syscall(funcPC(libc_statfs64_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_statfs64_trampoline() + +//go:linkname libc_statfs64 libc_statfs64 +//go:cgo_import_dynamic libc_statfs64 statfs64 "/usr/lib/libSystem.B.dylib" diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.s b/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.s new file mode 100644 index 0000000000..37b85b4f61 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.s @@ -0,0 +1,284 @@ +// go run mkasm_darwin.go 386 +// Code generated by the command above; DO NOT EDIT. + +// +build go1.12 + +#include "textflag.h" +TEXT ·libc_getgroups_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getgroups(SB) +TEXT ·libc_setgroups_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setgroups(SB) +TEXT ·libc_wait4_trampoline(SB),NOSPLIT,$0-0 + JMP libc_wait4(SB) +TEXT ·libc_accept_trampoline(SB),NOSPLIT,$0-0 + JMP libc_accept(SB) +TEXT ·libc_bind_trampoline(SB),NOSPLIT,$0-0 + JMP libc_bind(SB) +TEXT ·libc_connect_trampoline(SB),NOSPLIT,$0-0 + JMP libc_connect(SB) +TEXT ·libc_socket_trampoline(SB),NOSPLIT,$0-0 + JMP libc_socket(SB) +TEXT ·libc_getsockopt_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getsockopt(SB) +TEXT ·libc_setsockopt_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setsockopt(SB) +TEXT ·libc_getpeername_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getpeername(SB) +TEXT ·libc_getsockname_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getsockname(SB) +TEXT ·libc_shutdown_trampoline(SB),NOSPLIT,$0-0 + JMP libc_shutdown(SB) +TEXT ·libc_socketpair_trampoline(SB),NOSPLIT,$0-0 + JMP libc_socketpair(SB) +TEXT ·libc_recvfrom_trampoline(SB),NOSPLIT,$0-0 + JMP libc_recvfrom(SB) +TEXT ·libc_sendto_trampoline(SB),NOSPLIT,$0-0 + JMP libc_sendto(SB) +TEXT ·libc_recvmsg_trampoline(SB),NOSPLIT,$0-0 + JMP libc_recvmsg(SB) +TEXT ·libc_sendmsg_trampoline(SB),NOSPLIT,$0-0 + JMP libc_sendmsg(SB) +TEXT ·libc_kevent_trampoline(SB),NOSPLIT,$0-0 + JMP libc_kevent(SB) +TEXT ·libc___sysctl_trampoline(SB),NOSPLIT,$0-0 + JMP libc___sysctl(SB) +TEXT ·libc_utimes_trampoline(SB),NOSPLIT,$0-0 + JMP libc_utimes(SB) +TEXT ·libc_futimes_trampoline(SB),NOSPLIT,$0-0 + JMP libc_futimes(SB) +TEXT ·libc_fcntl_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fcntl(SB) +TEXT ·libc_poll_trampoline(SB),NOSPLIT,$0-0 + JMP libc_poll(SB) +TEXT ·libc_madvise_trampoline(SB),NOSPLIT,$0-0 + JMP libc_madvise(SB) +TEXT ·libc_mlock_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mlock(SB) +TEXT ·libc_mlockall_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mlockall(SB) +TEXT ·libc_mprotect_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mprotect(SB) +TEXT ·libc_msync_trampoline(SB),NOSPLIT,$0-0 + JMP libc_msync(SB) +TEXT ·libc_munlock_trampoline(SB),NOSPLIT,$0-0 + JMP libc_munlock(SB) +TEXT ·libc_munlockall_trampoline(SB),NOSPLIT,$0-0 + JMP libc_munlockall(SB) +TEXT ·libc_ptrace_trampoline(SB),NOSPLIT,$0-0 + JMP libc_ptrace(SB) +TEXT ·libc_getattrlist_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getattrlist(SB) +TEXT ·libc_pipe_trampoline(SB),NOSPLIT,$0-0 + JMP libc_pipe(SB) +TEXT ·libc_getxattr_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getxattr(SB) +TEXT ·libc_fgetxattr_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fgetxattr(SB) +TEXT ·libc_setxattr_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setxattr(SB) +TEXT ·libc_fsetxattr_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fsetxattr(SB) +TEXT ·libc_removexattr_trampoline(SB),NOSPLIT,$0-0 + JMP libc_removexattr(SB) +TEXT ·libc_fremovexattr_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fremovexattr(SB) +TEXT ·libc_listxattr_trampoline(SB),NOSPLIT,$0-0 + JMP libc_listxattr(SB) +TEXT ·libc_flistxattr_trampoline(SB),NOSPLIT,$0-0 + JMP libc_flistxattr(SB) +TEXT ·libc_setattrlist_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setattrlist(SB) +TEXT ·libc_kill_trampoline(SB),NOSPLIT,$0-0 + JMP libc_kill(SB) +TEXT ·libc_ioctl_trampoline(SB),NOSPLIT,$0-0 + JMP libc_ioctl(SB) +TEXT ·libc_sendfile_trampoline(SB),NOSPLIT,$0-0 + JMP libc_sendfile(SB) +TEXT ·libc_access_trampoline(SB),NOSPLIT,$0-0 + JMP libc_access(SB) +TEXT ·libc_adjtime_trampoline(SB),NOSPLIT,$0-0 + JMP libc_adjtime(SB) +TEXT ·libc_chdir_trampoline(SB),NOSPLIT,$0-0 + JMP libc_chdir(SB) +TEXT ·libc_chflags_trampoline(SB),NOSPLIT,$0-0 + JMP libc_chflags(SB) +TEXT ·libc_chmod_trampoline(SB),NOSPLIT,$0-0 + JMP libc_chmod(SB) +TEXT ·libc_chown_trampoline(SB),NOSPLIT,$0-0 + JMP libc_chown(SB) +TEXT ·libc_chroot_trampoline(SB),NOSPLIT,$0-0 + JMP libc_chroot(SB) +TEXT ·libc_close_trampoline(SB),NOSPLIT,$0-0 + JMP libc_close(SB) +TEXT ·libc_dup_trampoline(SB),NOSPLIT,$0-0 + JMP libc_dup(SB) +TEXT ·libc_dup2_trampoline(SB),NOSPLIT,$0-0 + JMP libc_dup2(SB) +TEXT ·libc_exchangedata_trampoline(SB),NOSPLIT,$0-0 + JMP libc_exchangedata(SB) +TEXT ·libc_exit_trampoline(SB),NOSPLIT,$0-0 + JMP libc_exit(SB) +TEXT ·libc_faccessat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_faccessat(SB) +TEXT ·libc_fchdir_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fchdir(SB) +TEXT ·libc_fchflags_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fchflags(SB) +TEXT ·libc_fchmod_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fchmod(SB) +TEXT ·libc_fchmodat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fchmodat(SB) +TEXT ·libc_fchown_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fchown(SB) +TEXT ·libc_fchownat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fchownat(SB) +TEXT ·libc_flock_trampoline(SB),NOSPLIT,$0-0 + JMP libc_flock(SB) +TEXT ·libc_fpathconf_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fpathconf(SB) +TEXT ·libc_fsync_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fsync(SB) +TEXT ·libc_ftruncate_trampoline(SB),NOSPLIT,$0-0 + JMP libc_ftruncate(SB) +TEXT ·libc_getdtablesize_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getdtablesize(SB) +TEXT ·libc_getegid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getegid(SB) +TEXT ·libc_geteuid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_geteuid(SB) +TEXT ·libc_getgid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getgid(SB) +TEXT ·libc_getpgid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getpgid(SB) +TEXT ·libc_getpgrp_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getpgrp(SB) +TEXT ·libc_getpid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getpid(SB) +TEXT ·libc_getppid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getppid(SB) +TEXT ·libc_getpriority_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getpriority(SB) +TEXT ·libc_getrlimit_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getrlimit(SB) +TEXT ·libc_getrusage_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getrusage(SB) +TEXT ·libc_getsid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getsid(SB) +TEXT ·libc_getuid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getuid(SB) +TEXT ·libc_issetugid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_issetugid(SB) +TEXT ·libc_kqueue_trampoline(SB),NOSPLIT,$0-0 + JMP libc_kqueue(SB) +TEXT ·libc_lchown_trampoline(SB),NOSPLIT,$0-0 + JMP libc_lchown(SB) +TEXT ·libc_link_trampoline(SB),NOSPLIT,$0-0 + JMP libc_link(SB) +TEXT ·libc_linkat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_linkat(SB) +TEXT ·libc_listen_trampoline(SB),NOSPLIT,$0-0 + JMP libc_listen(SB) +TEXT ·libc_mkdir_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mkdir(SB) +TEXT ·libc_mkdirat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mkdirat(SB) +TEXT ·libc_mkfifo_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mkfifo(SB) +TEXT ·libc_mknod_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mknod(SB) +TEXT ·libc_open_trampoline(SB),NOSPLIT,$0-0 + JMP libc_open(SB) +TEXT ·libc_openat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_openat(SB) +TEXT ·libc_pathconf_trampoline(SB),NOSPLIT,$0-0 + JMP libc_pathconf(SB) +TEXT ·libc_pread_trampoline(SB),NOSPLIT,$0-0 + JMP libc_pread(SB) +TEXT ·libc_pwrite_trampoline(SB),NOSPLIT,$0-0 + JMP libc_pwrite(SB) +TEXT ·libc_read_trampoline(SB),NOSPLIT,$0-0 + JMP libc_read(SB) +TEXT ·libc_readlink_trampoline(SB),NOSPLIT,$0-0 + JMP libc_readlink(SB) +TEXT ·libc_readlinkat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_readlinkat(SB) +TEXT ·libc_rename_trampoline(SB),NOSPLIT,$0-0 + JMP libc_rename(SB) +TEXT ·libc_renameat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_renameat(SB) +TEXT ·libc_revoke_trampoline(SB),NOSPLIT,$0-0 + JMP libc_revoke(SB) +TEXT ·libc_rmdir_trampoline(SB),NOSPLIT,$0-0 + JMP libc_rmdir(SB) +TEXT ·libc_lseek_trampoline(SB),NOSPLIT,$0-0 + JMP libc_lseek(SB) +TEXT ·libc_select_trampoline(SB),NOSPLIT,$0-0 + JMP libc_select(SB) +TEXT ·libc_setegid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setegid(SB) +TEXT ·libc_seteuid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_seteuid(SB) +TEXT ·libc_setgid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setgid(SB) +TEXT ·libc_setlogin_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setlogin(SB) +TEXT ·libc_setpgid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setpgid(SB) +TEXT ·libc_setpriority_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setpriority(SB) +TEXT ·libc_setprivexec_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setprivexec(SB) +TEXT ·libc_setregid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setregid(SB) +TEXT ·libc_setreuid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setreuid(SB) +TEXT ·libc_setrlimit_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setrlimit(SB) +TEXT ·libc_setsid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setsid(SB) +TEXT ·libc_settimeofday_trampoline(SB),NOSPLIT,$0-0 + JMP libc_settimeofday(SB) +TEXT ·libc_setuid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setuid(SB) +TEXT ·libc_symlink_trampoline(SB),NOSPLIT,$0-0 + JMP libc_symlink(SB) +TEXT ·libc_symlinkat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_symlinkat(SB) +TEXT ·libc_sync_trampoline(SB),NOSPLIT,$0-0 + JMP libc_sync(SB) +TEXT ·libc_truncate_trampoline(SB),NOSPLIT,$0-0 + JMP libc_truncate(SB) +TEXT ·libc_umask_trampoline(SB),NOSPLIT,$0-0 + JMP libc_umask(SB) +TEXT ·libc_undelete_trampoline(SB),NOSPLIT,$0-0 + JMP libc_undelete(SB) +TEXT ·libc_unlink_trampoline(SB),NOSPLIT,$0-0 + JMP libc_unlink(SB) +TEXT ·libc_unlinkat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_unlinkat(SB) +TEXT ·libc_unmount_trampoline(SB),NOSPLIT,$0-0 + JMP libc_unmount(SB) +TEXT ·libc_write_trampoline(SB),NOSPLIT,$0-0 + JMP libc_write(SB) +TEXT ·libc_mmap_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mmap(SB) +TEXT ·libc_munmap_trampoline(SB),NOSPLIT,$0-0 + JMP libc_munmap(SB) +TEXT ·libc_gettimeofday_trampoline(SB),NOSPLIT,$0-0 + JMP libc_gettimeofday(SB) +TEXT ·libc_fstat64_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fstat64(SB) +TEXT ·libc_fstatat64_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fstatat64(SB) +TEXT ·libc_fstatfs64_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fstatfs64(SB) +TEXT ·libc___getdirentries64_trampoline(SB),NOSPLIT,$0-0 + JMP libc___getdirentries64(SB) +TEXT ·libc_getfsstat64_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getfsstat64(SB) +TEXT ·libc_lstat64_trampoline(SB),NOSPLIT,$0-0 + JMP libc_lstat64(SB) +TEXT ·libc_stat64_trampoline(SB),NOSPLIT,$0-0 + JMP libc_stat64(SB) +TEXT ·libc_statfs64_trampoline(SB),NOSPLIT,$0-0 + JMP libc_statfs64(SB) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.1_11.go b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.1_11.go new file mode 100644 index 0000000000..2581e8960f --- /dev/null +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.1_11.go @@ -0,0 +1,1810 @@ +// go run mksyscall.go -tags darwin,amd64,!go1.12 syscall_bsd.go syscall_darwin.go syscall_darwin_amd64.go +// Code generated by the command above; see README.md. DO NOT EDIT. + +// +build darwin,amd64,!go1.12 + +package unix + +import ( + "syscall" + "unsafe" +) + +var _ syscall.Errno + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getgroups(ngid int, gid *_Gid_t) (n int, err error) { + r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setgroups(ngid int, gid *_Gid_t) (err error) { + _, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) { + r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0) + wpid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { + r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { + _, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { + _, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func socket(domain int, typ int, proto int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto)) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) { + _, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) { + _, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { + _, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { + _, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Shutdown(s int, how int) (err error) { + _, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) { + _, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) { + r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) { + r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) { + r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) { + var _p0 unsafe.Pointer + if len(mib) > 0 { + _p0 = unsafe.Pointer(&mib[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func utimes(path string, timeval *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func futimes(fd int, timeval *[2]Timeval) (err error) { + _, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fcntl(fd int, cmd int, arg int) (val int, err error) { + r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg)) + val = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { + r0, _, e1 := Syscall(SYS_POLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Madvise(b []byte, behav int) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(behav)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mlock(b []byte) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mlockall(flags int) (err error) { + _, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mprotect(b []byte, prot int) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Msync(b []byte, flags int) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MSYNC, uintptr(_p0), uintptr(len(b)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Munlock(b []byte) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Munlockall() (err error) { + _, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) { + _, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error) { + _, _, e1 := Syscall6(SYS_GETATTRLIST, uintptr(unsafe.Pointer(path)), uintptr(list), uintptr(buf), uintptr(size), uintptr(options), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func pipe() (r int, w int, err error) { + r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0) + r = int(r0) + w = int(r1) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getxattr(path string, attr string, dest *byte, size int, position uint32, options int) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(position), uintptr(options)) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fgetxattr(fd int, attr string, dest *byte, size int, position uint32, options int) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_FGETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(position), uintptr(options)) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setxattr(path string, attr string, data *byte, size int, position uint32, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(data)), uintptr(size), uintptr(position), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fsetxattr(fd int, attr string, data *byte, size int, position uint32, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FSETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(data)), uintptr(size), uintptr(position), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func removexattr(path string, attr string, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_REMOVEXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fremovexattr(fd int, attr string, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FREMOVEXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func listxattr(path string, dest *byte, size int, options int) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_LISTXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(options), 0, 0) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func flistxattr(fd int, dest *byte, size int, options int) (sz int, err error) { + r0, _, e1 := Syscall6(SYS_FLISTXATTR, uintptr(fd), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(options), 0, 0) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error) { + _, _, e1 := Syscall6(SYS_SETATTRLIST, uintptr(unsafe.Pointer(path)), uintptr(list), uintptr(buf), uintptr(size), uintptr(options), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func kill(pid int, signum int, posix int) (err error) { + _, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), uintptr(posix)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ioctl(fd int, req uint, arg uintptr) (err error) { + _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) { + _, _, e1 := Syscall6(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(offset), uintptr(unsafe.Pointer(len)), uintptr(hdtr), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Access(path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Adjtime(delta *Timeval, olddelta *Timeval) (err error) { + _, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chdir(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chflags(path string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chmod(path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chown(path string, uid int, gid int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chroot(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Close(fd int) (err error) { + _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Dup(fd int) (nfd int, err error) { + r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0) + nfd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Dup2(from int, to int) (err error) { + _, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Exchangedata(path1 string, path2 string, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path1) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(path2) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_EXCHANGEDATA, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Exit(code int) { + Syscall(SYS_EXIT, uintptr(code), 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchdir(fd int) (err error) { + _, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchflags(fd int, flags int) (err error) { + _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchmod(fd int, mode uint32) (err error) { + _, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchown(fd int, uid int, gid int) (err error) { + _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Flock(fd int, how int) (err error) { + _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fpathconf(fd int, name int) (val int, err error) { + r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0) + val = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fsync(fd int) (err error) { + _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Ftruncate(fd int, length int64) (err error) { + _, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getdtablesize() (size int) { + r0, _, _ := Syscall(SYS_GETDTABLESIZE, 0, 0, 0) + size = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getegid() (egid int) { + r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0) + egid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Geteuid() (uid int) { + r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0) + uid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getgid() (gid int) { + r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0) + gid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpgid(pid int) (pgid int, err error) { + r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0) + pgid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpgrp() (pgrp int) { + r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0) + pgrp = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpid() (pid int) { + r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0) + pid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getppid() (ppid int) { + r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0) + ppid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpriority(which int, who int) (prio int, err error) { + r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0) + prio = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getrlimit(which int, lim *Rlimit) (err error) { + _, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getrusage(who int, rusage *Rusage) (err error) { + _, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getsid(pid int) (sid int, err error) { + r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0) + sid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getuid() (uid int) { + r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0) + uid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Issetugid() (tainted bool) { + r0, _, _ := RawSyscall(SYS_ISSETUGID, 0, 0, 0) + tainted = bool(r0 != 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Kqueue() (fd int, err error) { + r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Lchown(path string, uid int, gid int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Link(path string, link string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(link) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(link) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_LINKAT, uintptr(pathfd), uintptr(unsafe.Pointer(_p0)), uintptr(linkfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Listen(s int, backlog int) (err error) { + _, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mkdir(path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mkdirat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mkfifo(path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mknod(path string, mode uint32, dev int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Open(path string, mode int, perm uint32) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pathconf(path string, name int) (val int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) + val = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pread(fd int, p []byte, offset int64) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pwrite(fd int, p []byte, offset int64) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func read(fd int, p []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Readlink(path string, buf []byte) (n int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(buf) > 0 { + _p1 = unsafe.Pointer(&buf[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(buf) > 0 { + _p1 = unsafe.Pointer(&buf[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_READLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Rename(from string, to string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(from) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(to) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Renameat(fromfd int, from string, tofd int, to string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(from) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(to) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(fromfd), uintptr(unsafe.Pointer(_p0)), uintptr(tofd), uintptr(unsafe.Pointer(_p1)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Revoke(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Rmdir(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { + r0, _, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence)) + newoffset = int64(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) { + _, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setegid(egid int) (err error) { + _, _, e1 := Syscall(SYS_SETEGID, uintptr(egid), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Seteuid(euid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setgid(gid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setlogin(name string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(name) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setpgid(pid int, pgid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setpriority(which int, who int, prio int) (err error) { + _, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setprivexec(flag int) (err error) { + _, _, e1 := Syscall(SYS_SETPRIVEXEC, uintptr(flag), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setregid(rgid int, egid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setreuid(ruid int, euid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setrlimit(which int, lim *Rlimit) (err error) { + _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setsid() (pid int, err error) { + r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0) + pid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Settimeofday(tp *Timeval) (err error) { + _, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setuid(uid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Symlink(path string, link string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(link) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_SYMLINKAT, uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Sync() (err error) { + _, _, e1 := Syscall(SYS_SYNC, 0, 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Truncate(path string, length int64) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Umask(newmask int) (oldmask int) { + r0, _, _ := Syscall(SYS_UMASK, uintptr(newmask), 0, 0) + oldmask = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Undelete(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Unlink(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Unlinkat(dirfd int, path string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Unmount(path string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func write(fd int, p []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) { + r0, _, e1 := Syscall6(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos)) + ret = uintptr(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func munmap(addr uintptr, length uintptr) (err error) { + _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func readlen(fd int, buf *byte, nbuf int) (n int, err error) { + r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func writelen(fd int, buf *byte, nbuf int) (n int, err error) { + r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func gettimeofday(tp *Timeval) (sec int64, usec int32, err error) { + r0, r1, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0) + sec = int64(r0) + usec = int32(r1) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstat(fd int, stat *Stat_t) (err error) { + _, _, e1 := Syscall(SYS_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FSTATAT64, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstatfs(fd int, stat *Statfs_t) (err error) { + _, _, e1 := Syscall(SYS_FSTATFS64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_GETDIRENTRIES64, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) { + r0, _, e1 := Syscall(SYS_GETFSSTAT64, uintptr(buf), uintptr(size), uintptr(flags)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Lstat(path string, stat *Stat_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Stat(path string, stat *Stat_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Statfs(path string, stat *Statfs_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go index d6808e072d..c142e33e92 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go @@ -1,7 +1,7 @@ -// mksyscall.pl -tags darwin,amd64 syscall_bsd.go syscall_darwin.go syscall_darwin_amd64.go +// go run mksyscall.go -tags darwin,amd64,go1.12 syscall_bsd.go syscall_darwin.go syscall_darwin_amd64.go // Code generated by the command above; see README.md. DO NOT EDIT. -// +build darwin,amd64 +// +build darwin,amd64,go1.12 package unix @@ -15,7 +15,7 @@ var _ syscall.Errno // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getgroups(ngid int, gid *_Gid_t) (n int, err error) { - r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) + r0, _, e1 := syscall_rawSyscall(funcPC(libc_getgroups_trampoline), uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -23,20 +23,30 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) { return } +func libc_getgroups_trampoline() + +//go:linkname libc_getgroups libc_getgroups +//go:cgo_import_dynamic libc_getgroups getgroups "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func setgroups(ngid int, gid *_Gid_t) (err error) { - _, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_setgroups_trampoline), uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setgroups_trampoline() + +//go:linkname libc_setgroups libc_setgroups +//go:cgo_import_dynamic libc_setgroups setgroups "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) { - r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0) + r0, _, e1 := syscall_syscall6(funcPC(libc_wait4_trampoline), uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0) wpid = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -44,10 +54,15 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err return } +func libc_wait4_trampoline() + +//go:linkname libc_wait4 libc_wait4 +//go:cgo_import_dynamic libc_wait4 wait4 "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { - r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + r0, _, e1 := syscall_syscall(funcPC(libc_accept_trampoline), uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -55,30 +70,45 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { return } +func libc_accept_trampoline() + +//go:linkname libc_accept libc_accept +//go:cgo_import_dynamic libc_accept accept "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { - _, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen)) + _, _, e1 := syscall_syscall(funcPC(libc_bind_trampoline), uintptr(s), uintptr(addr), uintptr(addrlen)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_bind_trampoline() + +//go:linkname libc_bind libc_bind +//go:cgo_import_dynamic libc_bind bind "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { - _, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen)) + _, _, e1 := syscall_syscall(funcPC(libc_connect_trampoline), uintptr(s), uintptr(addr), uintptr(addrlen)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_connect_trampoline() + +//go:linkname libc_connect libc_connect +//go:cgo_import_dynamic libc_connect connect "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func socket(domain int, typ int, proto int) (fd int, err error) { - r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto)) + r0, _, e1 := syscall_rawSyscall(funcPC(libc_socket_trampoline), uintptr(domain), uintptr(typ), uintptr(proto)) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -86,66 +116,101 @@ func socket(domain int, typ int, proto int) (fd int, err error) { return } +func libc_socket_trampoline() + +//go:linkname libc_socket libc_socket +//go:cgo_import_dynamic libc_socket socket "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) { - _, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0) + _, _, e1 := syscall_syscall6(funcPC(libc_getsockopt_trampoline), uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_getsockopt_trampoline() + +//go:linkname libc_getsockopt libc_getsockopt +//go:cgo_import_dynamic libc_getsockopt getsockopt "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) { - _, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0) + _, _, e1 := syscall_syscall6(funcPC(libc_setsockopt_trampoline), uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setsockopt_trampoline() + +//go:linkname libc_setsockopt libc_setsockopt +//go:cgo_import_dynamic libc_setsockopt setsockopt "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { - _, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + _, _, e1 := syscall_rawSyscall(funcPC(libc_getpeername_trampoline), uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) if e1 != 0 { err = errnoErr(e1) } return } +func libc_getpeername_trampoline() + +//go:linkname libc_getpeername libc_getpeername +//go:cgo_import_dynamic libc_getpeername getpeername "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { - _, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + _, _, e1 := syscall_rawSyscall(funcPC(libc_getsockname_trampoline), uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) if e1 != 0 { err = errnoErr(e1) } return } +func libc_getsockname_trampoline() + +//go:linkname libc_getsockname libc_getsockname +//go:cgo_import_dynamic libc_getsockname getsockname "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Shutdown(s int, how int) (err error) { - _, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0) + _, _, e1 := syscall_syscall(funcPC(libc_shutdown_trampoline), uintptr(s), uintptr(how), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_shutdown_trampoline() + +//go:linkname libc_shutdown libc_shutdown +//go:cgo_import_dynamic libc_shutdown shutdown "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) { - _, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0) + _, _, e1 := syscall_rawSyscall6(funcPC(libc_socketpair_trampoline), uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_socketpair_trampoline() + +//go:linkname libc_socketpair libc_socketpair +//go:cgo_import_dynamic libc_socketpair socketpair "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) { @@ -155,7 +220,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen))) + r0, _, e1 := syscall_syscall6(funcPC(libc_recvfrom_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -163,6 +228,11 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl return } +func libc_recvfrom_trampoline() + +//go:linkname libc_recvfrom libc_recvfrom +//go:cgo_import_dynamic libc_recvfrom recvfrom "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) { @@ -172,17 +242,22 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) ( } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen)) + _, _, e1 := syscall_syscall6(funcPC(libc_sendto_trampoline), uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_sendto_trampoline() + +//go:linkname libc_sendto libc_sendto +//go:cgo_import_dynamic libc_sendto sendto "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) { - r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + r0, _, e1 := syscall_syscall(funcPC(libc_recvmsg_trampoline), uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -190,10 +265,15 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) { return } +func libc_recvmsg_trampoline() + +//go:linkname libc_recvmsg libc_recvmsg +//go:cgo_import_dynamic libc_recvmsg recvmsg "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) { - r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + r0, _, e1 := syscall_syscall(funcPC(libc_sendmsg_trampoline), uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -201,10 +281,15 @@ func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) { return } +func libc_sendmsg_trampoline() + +//go:linkname libc_sendmsg libc_sendmsg +//go:cgo_import_dynamic libc_sendmsg sendmsg "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) { - r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout))) + r0, _, e1 := syscall_syscall6(funcPC(libc_kevent_trampoline), uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -212,6 +297,11 @@ func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, ne return } +func libc_kevent_trampoline() + +//go:linkname libc_kevent libc_kevent +//go:cgo_import_dynamic libc_kevent kevent "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) { @@ -221,13 +311,18 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) + _, _, e1 := syscall_syscall6(funcPC(libc___sysctl_trampoline), uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) if e1 != 0 { err = errnoErr(e1) } return } +func libc___sysctl_trampoline() + +//go:linkname libc___sysctl libc___sysctl +//go:cgo_import_dynamic libc___sysctl __sysctl "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func utimes(path string, timeval *[2]Timeval) (err error) { @@ -236,27 +331,37 @@ func utimes(path string, timeval *[2]Timeval) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) + _, _, e1 := syscall_syscall(funcPC(libc_utimes_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_utimes_trampoline() + +//go:linkname libc_utimes libc_utimes +//go:cgo_import_dynamic libc_utimes utimes "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func futimes(fd int, timeval *[2]Timeval) (err error) { - _, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0) + _, _, e1 := syscall_syscall(funcPC(libc_futimes_trampoline), uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_futimes_trampoline() + +//go:linkname libc_futimes libc_futimes +//go:cgo_import_dynamic libc_futimes futimes "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func fcntl(fd int, cmd int, arg int) (val int, err error) { - r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg)) + r0, _, e1 := syscall_syscall(funcPC(libc_fcntl_trampoline), uintptr(fd), uintptr(cmd), uintptr(arg)) val = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -264,10 +369,15 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) { return } +func libc_fcntl_trampoline() + +//go:linkname libc_fcntl libc_fcntl +//go:cgo_import_dynamic libc_fcntl fcntl "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { - r0, _, e1 := Syscall(SYS_POLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout)) + r0, _, e1 := syscall_syscall(funcPC(libc_poll_trampoline), uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -275,6 +385,11 @@ func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { return } +func libc_poll_trampoline() + +//go:linkname libc_poll libc_poll +//go:cgo_import_dynamic libc_poll poll "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Madvise(b []byte, behav int) (err error) { @@ -284,13 +399,18 @@ func Madvise(b []byte, behav int) (err error) { } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(behav)) + _, _, e1 := syscall_syscall(funcPC(libc_madvise_trampoline), uintptr(_p0), uintptr(len(b)), uintptr(behav)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_madvise_trampoline() + +//go:linkname libc_madvise libc_madvise +//go:cgo_import_dynamic libc_madvise madvise "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mlock(b []byte) (err error) { @@ -300,23 +420,33 @@ func Mlock(b []byte) (err error) { } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0) + _, _, e1 := syscall_syscall(funcPC(libc_mlock_trampoline), uintptr(_p0), uintptr(len(b)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_mlock_trampoline() + +//go:linkname libc_mlock libc_mlock +//go:cgo_import_dynamic libc_mlock mlock "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mlockall(flags int) (err error) { - _, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_mlockall_trampoline), uintptr(flags), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_mlockall_trampoline() + +//go:linkname libc_mlockall libc_mlockall +//go:cgo_import_dynamic libc_mlockall mlockall "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mprotect(b []byte, prot int) (err error) { @@ -326,13 +456,18 @@ func Mprotect(b []byte, prot int) (err error) { } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot)) + _, _, e1 := syscall_syscall(funcPC(libc_mprotect_trampoline), uintptr(_p0), uintptr(len(b)), uintptr(prot)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_mprotect_trampoline() + +//go:linkname libc_mprotect libc_mprotect +//go:cgo_import_dynamic libc_mprotect mprotect "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Msync(b []byte, flags int) (err error) { @@ -342,13 +477,18 @@ func Msync(b []byte, flags int) (err error) { } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall(SYS_MSYNC, uintptr(_p0), uintptr(len(b)), uintptr(flags)) + _, _, e1 := syscall_syscall(funcPC(libc_msync_trampoline), uintptr(_p0), uintptr(len(b)), uintptr(flags)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_msync_trampoline() + +//go:linkname libc_msync libc_msync +//go:cgo_import_dynamic libc_msync msync "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Munlock(b []byte) (err error) { @@ -358,37 +498,67 @@ func Munlock(b []byte) (err error) { } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0) + _, _, e1 := syscall_syscall(funcPC(libc_munlock_trampoline), uintptr(_p0), uintptr(len(b)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_munlock_trampoline() + +//go:linkname libc_munlock libc_munlock +//go:cgo_import_dynamic libc_munlock munlock "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Munlockall() (err error) { - _, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_munlockall_trampoline), 0, 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_munlockall_trampoline() + +//go:linkname libc_munlockall libc_munlockall +//go:cgo_import_dynamic libc_munlockall munlockall "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) { - _, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0) + _, _, e1 := syscall_syscall6(funcPC(libc_ptrace_trampoline), uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_ptrace_trampoline() + +//go:linkname libc_ptrace libc_ptrace +//go:cgo_import_dynamic libc_ptrace ptrace "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error) { + _, _, e1 := syscall_syscall6(funcPC(libc_getattrlist_trampoline), uintptr(unsafe.Pointer(path)), uintptr(list), uintptr(buf), uintptr(size), uintptr(options), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_getattrlist_trampoline() + +//go:linkname libc_getattrlist libc_getattrlist +//go:cgo_import_dynamic libc_getattrlist getattrlist "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func pipe() (r int, w int, err error) { - r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0) + r0, r1, e1 := syscall_rawSyscall(funcPC(libc_pipe_trampoline), 0, 0, 0) r = int(r0) w = int(r1) if e1 != 0 { @@ -397,26 +567,245 @@ func pipe() (r int, w int, err error) { return } +func libc_pipe_trampoline() + +//go:linkname libc_pipe libc_pipe +//go:cgo_import_dynamic libc_pipe pipe "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func kill(pid int, signum int, posix int) (err error) { - _, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), uintptr(posix)) +func getxattr(path string, attr string, dest *byte, size int, position uint32, options int) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + r0, _, e1 := syscall_syscall6(funcPC(libc_getxattr_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(position), uintptr(options)) + sz = int(r0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_getxattr_trampoline() + +//go:linkname libc_getxattr libc_getxattr +//go:cgo_import_dynamic libc_getxattr getxattr "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fgetxattr(fd int, attr string, dest *byte, size int, position uint32, options int) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + r0, _, e1 := syscall_syscall6(funcPC(libc_fgetxattr_trampoline), uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(position), uintptr(options)) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_fgetxattr_trampoline() + +//go:linkname libc_fgetxattr libc_fgetxattr +//go:cgo_import_dynamic libc_fgetxattr fgetxattr "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setxattr(path string, attr string, data *byte, size int, position uint32, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := syscall_syscall6(funcPC(libc_setxattr_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(data)), uintptr(size), uintptr(position), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_setxattr_trampoline() + +//go:linkname libc_setxattr libc_setxattr +//go:cgo_import_dynamic libc_setxattr setxattr "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fsetxattr(fd int, attr string, data *byte, size int, position uint32, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := syscall_syscall6(funcPC(libc_fsetxattr_trampoline), uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(data)), uintptr(size), uintptr(position), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_fsetxattr_trampoline() + +//go:linkname libc_fsetxattr libc_fsetxattr +//go:cgo_import_dynamic libc_fsetxattr fsetxattr "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func removexattr(path string, attr string, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := syscall_syscall(funcPC(libc_removexattr_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_removexattr_trampoline() + +//go:linkname libc_removexattr libc_removexattr +//go:cgo_import_dynamic libc_removexattr removexattr "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fremovexattr(fd int, attr string, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := syscall_syscall(funcPC(libc_fremovexattr_trampoline), uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_fremovexattr_trampoline() + +//go:linkname libc_fremovexattr libc_fremovexattr +//go:cgo_import_dynamic libc_fremovexattr fremovexattr "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func listxattr(path string, dest *byte, size int, options int) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := syscall_syscall6(funcPC(libc_listxattr_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(options), 0, 0) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_listxattr_trampoline() + +//go:linkname libc_listxattr libc_listxattr +//go:cgo_import_dynamic libc_listxattr listxattr "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func flistxattr(fd int, dest *byte, size int, options int) (sz int, err error) { + r0, _, e1 := syscall_syscall6(funcPC(libc_flistxattr_trampoline), uintptr(fd), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(options), 0, 0) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_flistxattr_trampoline() + +//go:linkname libc_flistxattr libc_flistxattr +//go:cgo_import_dynamic libc_flistxattr flistxattr "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error) { + _, _, e1 := syscall_syscall6(funcPC(libc_setattrlist_trampoline), uintptr(unsafe.Pointer(path)), uintptr(list), uintptr(buf), uintptr(size), uintptr(options), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_setattrlist_trampoline() + +//go:linkname libc_setattrlist libc_setattrlist +//go:cgo_import_dynamic libc_setattrlist setattrlist "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func kill(pid int, signum int, posix int) (err error) { + _, _, e1 := syscall_syscall(funcPC(libc_kill_trampoline), uintptr(pid), uintptr(signum), uintptr(posix)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_kill_trampoline() + +//go:linkname libc_kill libc_kill +//go:cgo_import_dynamic libc_kill kill "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func ioctl(fd int, req uint, arg uintptr) (err error) { - _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg)) + _, _, e1 := syscall_syscall(funcPC(libc_ioctl_trampoline), uintptr(fd), uintptr(req), uintptr(arg)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_ioctl_trampoline() + +//go:linkname libc_ioctl libc_ioctl +//go:cgo_import_dynamic libc_ioctl ioctl "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) { + _, _, e1 := syscall_syscall6(funcPC(libc_sendfile_trampoline), uintptr(infd), uintptr(outfd), uintptr(offset), uintptr(unsafe.Pointer(len)), uintptr(hdtr), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_sendfile_trampoline() + +//go:linkname libc_sendfile libc_sendfile +//go:cgo_import_dynamic libc_sendfile sendfile "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Access(path string, mode uint32) (err error) { @@ -425,23 +814,33 @@ func Access(path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + _, _, e1 := syscall_syscall(funcPC(libc_access_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_access_trampoline() + +//go:linkname libc_access libc_access +//go:cgo_import_dynamic libc_access access "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Adjtime(delta *Timeval, olddelta *Timeval) (err error) { - _, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0) + _, _, e1 := syscall_syscall(funcPC(libc_adjtime_trampoline), uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_adjtime_trampoline() + +//go:linkname libc_adjtime libc_adjtime +//go:cgo_import_dynamic libc_adjtime adjtime "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Chdir(path string) (err error) { @@ -450,13 +849,18 @@ func Chdir(path string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_chdir_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_chdir_trampoline() + +//go:linkname libc_chdir libc_chdir +//go:cgo_import_dynamic libc_chdir chdir "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Chflags(path string, flags int) (err error) { @@ -465,13 +869,18 @@ func Chflags(path string, flags int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + _, _, e1 := syscall_syscall(funcPC(libc_chflags_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_chflags_trampoline() + +//go:linkname libc_chflags libc_chflags +//go:cgo_import_dynamic libc_chflags chflags "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Chmod(path string, mode uint32) (err error) { @@ -480,13 +889,18 @@ func Chmod(path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + _, _, e1 := syscall_syscall(funcPC(libc_chmod_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_chmod_trampoline() + +//go:linkname libc_chmod libc_chmod +//go:cgo_import_dynamic libc_chmod chmod "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Chown(path string, uid int, gid int) (err error) { @@ -495,13 +909,18 @@ func Chown(path string, uid int, gid int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + _, _, e1 := syscall_syscall(funcPC(libc_chown_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_chown_trampoline() + +//go:linkname libc_chown libc_chown +//go:cgo_import_dynamic libc_chown chown "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Chroot(path string) (err error) { @@ -510,27 +929,52 @@ func Chroot(path string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_chroot_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_chroot_trampoline() + +//go:linkname libc_chroot libc_chroot +//go:cgo_import_dynamic libc_chroot chroot "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ClockGettime(clockid int32, time *Timespec) (err error) { + _, _, e1 := syscall_syscall(funcPC(libc_clock_gettime_trampoline), uintptr(clockid), uintptr(unsafe.Pointer(time)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_clock_gettime_trampoline() + +//go:linkname libc_clock_gettime libc_clock_gettime +//go:cgo_import_dynamic libc_clock_gettime clock_gettime "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Close(fd int) (err error) { - _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_close_trampoline), uintptr(fd), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_close_trampoline() + +//go:linkname libc_close libc_close +//go:cgo_import_dynamic libc_close close "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Dup(fd int) (nfd int, err error) { - r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0) + r0, _, e1 := syscall_syscall(funcPC(libc_dup_trampoline), uintptr(fd), 0, 0) nfd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -538,16 +982,26 @@ func Dup(fd int) (nfd int, err error) { return } +func libc_dup_trampoline() + +//go:linkname libc_dup libc_dup +//go:cgo_import_dynamic libc_dup dup "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Dup2(from int, to int) (err error) { - _, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0) + _, _, e1 := syscall_syscall(funcPC(libc_dup2_trampoline), uintptr(from), uintptr(to), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_dup2_trampoline() + +//go:linkname libc_dup2 libc_dup2 +//go:cgo_import_dynamic libc_dup2 dup2 "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Exchangedata(path1 string, path2 string, options int) (err error) { @@ -561,20 +1015,30 @@ func Exchangedata(path1 string, path2 string, options int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_EXCHANGEDATA, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) + _, _, e1 := syscall_syscall(funcPC(libc_exchangedata_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_exchangedata_trampoline() + +//go:linkname libc_exchangedata libc_exchangedata +//go:cgo_import_dynamic libc_exchangedata exchangedata "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Exit(code int) { - Syscall(SYS_EXIT, uintptr(code), 0, 0) + syscall_syscall(funcPC(libc_exit_trampoline), uintptr(code), 0, 0) return } +func libc_exit_trampoline() + +//go:linkname libc_exit libc_exit +//go:cgo_import_dynamic libc_exit exit "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { @@ -583,43 +1047,63 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { if err != nil { return } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + _, _, e1 := syscall_syscall6(funcPC(libc_faccessat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_faccessat_trampoline() + +//go:linkname libc_faccessat libc_faccessat +//go:cgo_import_dynamic libc_faccessat faccessat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchdir(fd int) (err error) { - _, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_fchdir_trampoline), uintptr(fd), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_fchdir_trampoline() + +//go:linkname libc_fchdir libc_fchdir +//go:cgo_import_dynamic libc_fchdir fchdir "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchflags(fd int, flags int) (err error) { - _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0) + _, _, e1 := syscall_syscall(funcPC(libc_fchflags_trampoline), uintptr(fd), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_fchflags_trampoline() + +//go:linkname libc_fchflags libc_fchflags +//go:cgo_import_dynamic libc_fchflags fchflags "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchmod(fd int, mode uint32) (err error) { - _, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0) + _, _, e1 := syscall_syscall(funcPC(libc_fchmod_trampoline), uintptr(fd), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_fchmod_trampoline() + +//go:linkname libc_fchmod libc_fchmod +//go:cgo_import_dynamic libc_fchmod fchmod "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { @@ -628,23 +1112,33 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { if err != nil { return } - _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + _, _, e1 := syscall_syscall6(funcPC(libc_fchmodat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_fchmodat_trampoline() + +//go:linkname libc_fchmodat libc_fchmodat +//go:cgo_import_dynamic libc_fchmodat fchmodat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchown(fd int, uid int, gid int) (err error) { - _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)) + _, _, e1 := syscall_syscall(funcPC(libc_fchown_trampoline), uintptr(fd), uintptr(uid), uintptr(gid)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_fchown_trampoline() + +//go:linkname libc_fchown libc_fchown +//go:cgo_import_dynamic libc_fchown fchown "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { @@ -653,27 +1147,37 @@ func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { if err != nil { return } - _, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0) + _, _, e1 := syscall_syscall6(funcPC(libc_fchownat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_fchownat_trampoline() + +//go:linkname libc_fchownat libc_fchownat +//go:cgo_import_dynamic libc_fchownat fchownat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Flock(fd int, how int) (err error) { - _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0) + _, _, e1 := syscall_syscall(funcPC(libc_flock_trampoline), uintptr(fd), uintptr(how), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_flock_trampoline() + +//go:linkname libc_flock libc_flock +//go:cgo_import_dynamic libc_flock flock "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fpathconf(fd int, name int) (val int, err error) { - r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0) + r0, _, e1 := syscall_syscall(funcPC(libc_fpathconf_trampoline), uintptr(fd), uintptr(name), 0) val = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -681,99 +1185,97 @@ func Fpathconf(fd int, name int) (val int, err error) { return } -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func libc_fpathconf_trampoline() -func Fstat(fd int, stat *Stat_t) (err error) { - _, _, e1 := Syscall(SYS_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Fstatfs(fd int, stat *Statfs_t) (err error) { - _, _, e1 := Syscall(SYS_FSTATFS64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} +//go:linkname libc_fpathconf libc_fpathconf +//go:cgo_import_dynamic libc_fpathconf fpathconf "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fsync(fd int) (err error) { - _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_fsync_trampoline), uintptr(fd), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_fsync_trampoline() + +//go:linkname libc_fsync libc_fsync +//go:cgo_import_dynamic libc_fsync fsync "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Ftruncate(fd int, length int64) (err error) { - _, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), 0) + _, _, e1 := syscall_syscall(funcPC(libc_ftruncate_trampoline), uintptr(fd), uintptr(length), 0) if e1 != 0 { err = errnoErr(e1) } return } -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func libc_ftruncate_trampoline() -func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { - var _p0 unsafe.Pointer - if len(buf) > 0 { - _p0 = unsafe.Pointer(&buf[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall6(SYS_GETDIRENTRIES64, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} +//go:linkname libc_ftruncate libc_ftruncate +//go:cgo_import_dynamic libc_ftruncate ftruncate "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getdtablesize() (size int) { - r0, _, _ := Syscall(SYS_GETDTABLESIZE, 0, 0, 0) + r0, _, _ := syscall_syscall(funcPC(libc_getdtablesize_trampoline), 0, 0, 0) size = int(r0) return } +func libc_getdtablesize_trampoline() + +//go:linkname libc_getdtablesize libc_getdtablesize +//go:cgo_import_dynamic libc_getdtablesize getdtablesize "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getegid() (egid int) { - r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(funcPC(libc_getegid_trampoline), 0, 0, 0) egid = int(r0) return } +func libc_getegid_trampoline() + +//go:linkname libc_getegid libc_getegid +//go:cgo_import_dynamic libc_getegid getegid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Geteuid() (uid int) { - r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(funcPC(libc_geteuid_trampoline), 0, 0, 0) uid = int(r0) return } +func libc_geteuid_trampoline() + +//go:linkname libc_geteuid libc_geteuid +//go:cgo_import_dynamic libc_geteuid geteuid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getgid() (gid int) { - r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(funcPC(libc_getgid_trampoline), 0, 0, 0) gid = int(r0) return } +func libc_getgid_trampoline() + +//go:linkname libc_getgid libc_getgid +//go:cgo_import_dynamic libc_getgid getgid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpgid(pid int) (pgid int, err error) { - r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0) + r0, _, e1 := syscall_rawSyscall(funcPC(libc_getpgid_trampoline), uintptr(pid), 0, 0) pgid = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -781,34 +1283,54 @@ func Getpgid(pid int) (pgid int, err error) { return } +func libc_getpgid_trampoline() + +//go:linkname libc_getpgid libc_getpgid +//go:cgo_import_dynamic libc_getpgid getpgid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpgrp() (pgrp int) { - r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(funcPC(libc_getpgrp_trampoline), 0, 0, 0) pgrp = int(r0) return } +func libc_getpgrp_trampoline() + +//go:linkname libc_getpgrp libc_getpgrp +//go:cgo_import_dynamic libc_getpgrp getpgrp "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpid() (pid int) { - r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(funcPC(libc_getpid_trampoline), 0, 0, 0) pid = int(r0) return } +func libc_getpid_trampoline() + +//go:linkname libc_getpid libc_getpid +//go:cgo_import_dynamic libc_getpid getpid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getppid() (ppid int) { - r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(funcPC(libc_getppid_trampoline), 0, 0, 0) ppid = int(r0) return } +func libc_getppid_trampoline() + +//go:linkname libc_getppid libc_getppid +//go:cgo_import_dynamic libc_getppid getppid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpriority(which int, who int) (prio int, err error) { - r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0) + r0, _, e1 := syscall_syscall(funcPC(libc_getpriority_trampoline), uintptr(which), uintptr(who), 0) prio = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -816,30 +1338,45 @@ func Getpriority(which int, who int) (prio int, err error) { return } +func libc_getpriority_trampoline() + +//go:linkname libc_getpriority libc_getpriority +//go:cgo_import_dynamic libc_getpriority getpriority "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getrlimit(which int, lim *Rlimit) (err error) { - _, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_getrlimit_trampoline), uintptr(which), uintptr(unsafe.Pointer(lim)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_getrlimit_trampoline() + +//go:linkname libc_getrlimit libc_getrlimit +//go:cgo_import_dynamic libc_getrlimit getrlimit "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getrusage(who int, rusage *Rusage) (err error) { - _, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_getrusage_trampoline), uintptr(who), uintptr(unsafe.Pointer(rusage)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_getrusage_trampoline() + +//go:linkname libc_getrusage libc_getrusage +//go:cgo_import_dynamic libc_getrusage getrusage "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getsid(pid int) (sid int, err error) { - r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0) + r0, _, e1 := syscall_rawSyscall(funcPC(libc_getsid_trampoline), uintptr(pid), 0, 0) sid = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -847,26 +1384,41 @@ func Getsid(pid int) (sid int, err error) { return } +func libc_getsid_trampoline() + +//go:linkname libc_getsid libc_getsid +//go:cgo_import_dynamic libc_getsid getsid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getuid() (uid int) { - r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(funcPC(libc_getuid_trampoline), 0, 0, 0) uid = int(r0) return } +func libc_getuid_trampoline() + +//go:linkname libc_getuid libc_getuid +//go:cgo_import_dynamic libc_getuid getuid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Issetugid() (tainted bool) { - r0, _, _ := RawSyscall(SYS_ISSETUGID, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(funcPC(libc_issetugid_trampoline), 0, 0, 0) tainted = bool(r0 != 0) return } +func libc_issetugid_trampoline() + +//go:linkname libc_issetugid libc_issetugid +//go:cgo_import_dynamic libc_issetugid issetugid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Kqueue() (fd int, err error) { - r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0) + r0, _, e1 := syscall_syscall(funcPC(libc_kqueue_trampoline), 0, 0, 0) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -874,6 +1426,11 @@ func Kqueue() (fd int, err error) { return } +func libc_kqueue_trampoline() + +//go:linkname libc_kqueue libc_kqueue +//go:cgo_import_dynamic libc_kqueue kqueue "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Lchown(path string, uid int, gid int) (err error) { @@ -882,13 +1439,18 @@ func Lchown(path string, uid int, gid int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + _, _, e1 := syscall_syscall(funcPC(libc_lchown_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_lchown_trampoline() + +//go:linkname libc_lchown libc_lchown +//go:cgo_import_dynamic libc_lchown lchown "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Link(path string, link string) (err error) { @@ -902,13 +1464,18 @@ func Link(path string, link string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + _, _, e1 := syscall_syscall(funcPC(libc_link_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_link_trampoline() + +//go:linkname libc_link libc_link +//go:cgo_import_dynamic libc_link link "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error) { @@ -922,37 +1489,32 @@ func Linkat(pathfd int, path string, linkfd int, link string, flags int) (err er if err != nil { return } - _, _, e1 := Syscall6(SYS_LINKAT, uintptr(pathfd), uintptr(unsafe.Pointer(_p0)), uintptr(linkfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) + _, _, e1 := syscall_syscall6(funcPC(libc_linkat_trampoline), uintptr(pathfd), uintptr(unsafe.Pointer(_p0)), uintptr(linkfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_linkat_trampoline() + +//go:linkname libc_linkat libc_linkat +//go:cgo_import_dynamic libc_linkat linkat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Listen(s int, backlog int) (err error) { - _, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0) + _, _, e1 := syscall_syscall(funcPC(libc_listen_trampoline), uintptr(s), uintptr(backlog), 0) if e1 != 0 { err = errnoErr(e1) } return } -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func libc_listen_trampoline() -func Lstat(path string, stat *Stat_t) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} +//go:linkname libc_listen libc_listen +//go:cgo_import_dynamic libc_listen listen "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT @@ -962,13 +1524,18 @@ func Mkdir(path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + _, _, e1 := syscall_syscall(funcPC(libc_mkdir_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_mkdir_trampoline() + +//go:linkname libc_mkdir libc_mkdir +//go:cgo_import_dynamic libc_mkdir mkdir "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mkdirat(dirfd int, path string, mode uint32) (err error) { @@ -977,13 +1544,18 @@ func Mkdirat(dirfd int, path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + _, _, e1 := syscall_syscall(funcPC(libc_mkdirat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_mkdirat_trampoline() + +//go:linkname libc_mkdirat libc_mkdirat +//go:cgo_import_dynamic libc_mkdirat mkdirat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mkfifo(path string, mode uint32) (err error) { @@ -992,13 +1564,18 @@ func Mkfifo(path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + _, _, e1 := syscall_syscall(funcPC(libc_mkfifo_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_mkfifo_trampoline() + +//go:linkname libc_mkfifo libc_mkfifo +//go:cgo_import_dynamic libc_mkfifo mkfifo "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mknod(path string, mode uint32, dev int) (err error) { @@ -1007,13 +1584,18 @@ func Mknod(path string, mode uint32, dev int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) + _, _, e1 := syscall_syscall(funcPC(libc_mknod_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_mknod_trampoline() + +//go:linkname libc_mknod libc_mknod +//go:cgo_import_dynamic libc_mknod mknod "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Open(path string, mode int, perm uint32) (fd int, err error) { @@ -1022,7 +1604,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { if err != nil { return } - r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) + r0, _, e1 := syscall_syscall(funcPC(libc_open_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1030,6 +1612,11 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { return } +func libc_open_trampoline() + +//go:linkname libc_open libc_open +//go:cgo_import_dynamic libc_open open "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) { @@ -1038,7 +1625,7 @@ func Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) { if err != nil { return } - r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0) + r0, _, e1 := syscall_syscall6(funcPC(libc_openat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1046,6 +1633,11 @@ func Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) { return } +func libc_openat_trampoline() + +//go:linkname libc_openat libc_openat +//go:cgo_import_dynamic libc_openat openat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Pathconf(path string, name int) (val int, err error) { @@ -1054,7 +1646,7 @@ func Pathconf(path string, name int) (val int, err error) { if err != nil { return } - r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) + r0, _, e1 := syscall_syscall(funcPC(libc_pathconf_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) val = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1062,6 +1654,11 @@ func Pathconf(path string, name int) (val int, err error) { return } +func libc_pathconf_trampoline() + +//go:linkname libc_pathconf libc_pathconf +//go:cgo_import_dynamic libc_pathconf pathconf "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Pread(fd int, p []byte, offset int64) (n int, err error) { @@ -1071,7 +1668,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0) + r0, _, e1 := syscall_syscall6(funcPC(libc_pread_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1079,6 +1676,11 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) { return } +func libc_pread_trampoline() + +//go:linkname libc_pread libc_pread +//go:cgo_import_dynamic libc_pread pread "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Pwrite(fd int, p []byte, offset int64) (n int, err error) { @@ -1088,7 +1690,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0) + r0, _, e1 := syscall_syscall6(funcPC(libc_pwrite_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1096,6 +1698,11 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) { return } +func libc_pwrite_trampoline() + +//go:linkname libc_pwrite libc_pwrite +//go:cgo_import_dynamic libc_pwrite pwrite "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func read(fd int, p []byte) (n int, err error) { @@ -1105,7 +1712,7 @@ func read(fd int, p []byte) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p))) + r0, _, e1 := syscall_syscall(funcPC(libc_read_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1113,6 +1720,11 @@ func read(fd int, p []byte) (n int, err error) { return } +func libc_read_trampoline() + +//go:linkname libc_read libc_read +//go:cgo_import_dynamic libc_read read "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Readlink(path string, buf []byte) (n int, err error) { @@ -1127,7 +1739,7 @@ func Readlink(path string, buf []byte) (n int, err error) { } else { _p1 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) + r0, _, e1 := syscall_syscall(funcPC(libc_readlink_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1135,6 +1747,11 @@ func Readlink(path string, buf []byte) (n int, err error) { return } +func libc_readlink_trampoline() + +//go:linkname libc_readlink libc_readlink +//go:cgo_import_dynamic libc_readlink readlink "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { @@ -1149,7 +1766,7 @@ func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { } else { _p1 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall6(SYS_READLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0) + r0, _, e1 := syscall_syscall6(funcPC(libc_readlinkat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1157,6 +1774,11 @@ func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { return } +func libc_readlinkat_trampoline() + +//go:linkname libc_readlinkat libc_readlinkat +//go:cgo_import_dynamic libc_readlinkat readlinkat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Rename(from string, to string) (err error) { @@ -1170,13 +1792,18 @@ func Rename(from string, to string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + _, _, e1 := syscall_syscall(funcPC(libc_rename_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_rename_trampoline() + +//go:linkname libc_rename libc_rename +//go:cgo_import_dynamic libc_rename rename "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Renameat(fromfd int, from string, tofd int, to string) (err error) { @@ -1190,13 +1817,18 @@ func Renameat(fromfd int, from string, tofd int, to string) (err error) { if err != nil { return } - _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(fromfd), uintptr(unsafe.Pointer(_p0)), uintptr(tofd), uintptr(unsafe.Pointer(_p1)), 0, 0) + _, _, e1 := syscall_syscall6(funcPC(libc_renameat_trampoline), uintptr(fromfd), uintptr(unsafe.Pointer(_p0)), uintptr(tofd), uintptr(unsafe.Pointer(_p1)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_renameat_trampoline() + +//go:linkname libc_renameat libc_renameat +//go:cgo_import_dynamic libc_renameat renameat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Revoke(path string) (err error) { @@ -1205,13 +1837,18 @@ func Revoke(path string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_revoke_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_revoke_trampoline() + +//go:linkname libc_revoke libc_revoke +//go:cgo_import_dynamic libc_revoke revoke "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Rmdir(path string) (err error) { @@ -1220,17 +1857,22 @@ func Rmdir(path string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_rmdir_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_rmdir_trampoline() + +//go:linkname libc_rmdir libc_rmdir +//go:cgo_import_dynamic libc_rmdir rmdir "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { - r0, _, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence)) + r0, _, e1 := syscall_syscall(funcPC(libc_lseek_trampoline), uintptr(fd), uintptr(offset), uintptr(whence)) newoffset = int64(r0) if e1 != 0 { err = errnoErr(e1) @@ -1238,46 +1880,71 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { return } +func libc_lseek_trampoline() + +//go:linkname libc_lseek libc_lseek +//go:cgo_import_dynamic libc_lseek lseek "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) { - _, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0) + _, _, e1 := syscall_syscall6(funcPC(libc_select_trampoline), uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_select_trampoline() + +//go:linkname libc_select libc_select +//go:cgo_import_dynamic libc_select select "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setegid(egid int) (err error) { - _, _, e1 := Syscall(SYS_SETEGID, uintptr(egid), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_setegid_trampoline), uintptr(egid), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setegid_trampoline() + +//go:linkname libc_setegid libc_setegid +//go:cgo_import_dynamic libc_setegid setegid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Seteuid(euid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_seteuid_trampoline), uintptr(euid), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_seteuid_trampoline() + +//go:linkname libc_seteuid libc_seteuid +//go:cgo_import_dynamic libc_seteuid seteuid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setgid(gid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_setgid_trampoline), uintptr(gid), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setgid_trampoline() + +//go:linkname libc_setgid libc_setgid +//go:cgo_import_dynamic libc_setgid setgid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setlogin(name string) (err error) { @@ -1286,77 +1953,112 @@ func Setlogin(name string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_setlogin_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setlogin_trampoline() + +//go:linkname libc_setlogin libc_setlogin +//go:cgo_import_dynamic libc_setlogin setlogin "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setpgid(pid int, pgid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_setpgid_trampoline), uintptr(pid), uintptr(pgid), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setpgid_trampoline() + +//go:linkname libc_setpgid libc_setpgid +//go:cgo_import_dynamic libc_setpgid setpgid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setpriority(which int, who int, prio int) (err error) { - _, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio)) + _, _, e1 := syscall_syscall(funcPC(libc_setpriority_trampoline), uintptr(which), uintptr(who), uintptr(prio)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setpriority_trampoline() + +//go:linkname libc_setpriority libc_setpriority +//go:cgo_import_dynamic libc_setpriority setpriority "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setprivexec(flag int) (err error) { - _, _, e1 := Syscall(SYS_SETPRIVEXEC, uintptr(flag), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_setprivexec_trampoline), uintptr(flag), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setprivexec_trampoline() + +//go:linkname libc_setprivexec libc_setprivexec +//go:cgo_import_dynamic libc_setprivexec setprivexec "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setregid(rgid int, egid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_setregid_trampoline), uintptr(rgid), uintptr(egid), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setregid_trampoline() + +//go:linkname libc_setregid libc_setregid +//go:cgo_import_dynamic libc_setregid setregid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setreuid(ruid int, euid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_setreuid_trampoline), uintptr(ruid), uintptr(euid), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setreuid_trampoline() + +//go:linkname libc_setreuid libc_setreuid +//go:cgo_import_dynamic libc_setreuid setreuid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setrlimit(which int, lim *Rlimit) (err error) { - _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_setrlimit_trampoline), uintptr(which), uintptr(unsafe.Pointer(lim)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setrlimit_trampoline() + +//go:linkname libc_setrlimit libc_setrlimit +//go:cgo_import_dynamic libc_setrlimit setrlimit "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setsid() (pid int, err error) { - r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0) + r0, _, e1 := syscall_rawSyscall(funcPC(libc_setsid_trampoline), 0, 0, 0) pid = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1364,55 +2066,40 @@ func Setsid() (pid int, err error) { return } +func libc_setsid_trampoline() + +//go:linkname libc_setsid libc_setsid +//go:cgo_import_dynamic libc_setsid setsid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Settimeofday(tp *Timeval) (err error) { - _, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_settimeofday_trampoline), uintptr(unsafe.Pointer(tp)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_settimeofday_trampoline() + +//go:linkname libc_settimeofday libc_settimeofday +//go:cgo_import_dynamic libc_settimeofday settimeofday "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setuid(uid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_setuid_trampoline), uintptr(uid), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func libc_setuid_trampoline() -func Stat(path string, stat *Stat_t) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Statfs(path string, stat *Statfs_t) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} +//go:linkname libc_setuid libc_setuid +//go:cgo_import_dynamic libc_setuid setuid "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT @@ -1427,13 +2114,18 @@ func Symlink(path string, link string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + _, _, e1 := syscall_syscall(funcPC(libc_symlink_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_symlink_trampoline() + +//go:linkname libc_symlink libc_symlink +//go:cgo_import_dynamic libc_symlink symlink "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) { @@ -1447,23 +2139,33 @@ func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_SYMLINKAT, uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1))) + _, _, e1 := syscall_syscall(funcPC(libc_symlinkat_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1))) if e1 != 0 { err = errnoErr(e1) } return } +func libc_symlinkat_trampoline() + +//go:linkname libc_symlinkat libc_symlinkat +//go:cgo_import_dynamic libc_symlinkat symlinkat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Sync() (err error) { - _, _, e1 := Syscall(SYS_SYNC, 0, 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_sync_trampoline), 0, 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_sync_trampoline() + +//go:linkname libc_sync libc_sync +//go:cgo_import_dynamic libc_sync sync "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Truncate(path string, length int64) (err error) { @@ -1472,21 +2174,31 @@ func Truncate(path string, length int64) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0) + _, _, e1 := syscall_syscall(funcPC(libc_truncate_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(length), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_truncate_trampoline() + +//go:linkname libc_truncate libc_truncate +//go:cgo_import_dynamic libc_truncate truncate "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Umask(newmask int) (oldmask int) { - r0, _, _ := Syscall(SYS_UMASK, uintptr(newmask), 0, 0) + r0, _, _ := syscall_syscall(funcPC(libc_umask_trampoline), uintptr(newmask), 0, 0) oldmask = int(r0) return } +func libc_umask_trampoline() + +//go:linkname libc_umask libc_umask +//go:cgo_import_dynamic libc_umask umask "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Undelete(path string) (err error) { @@ -1495,13 +2207,18 @@ func Undelete(path string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_undelete_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_undelete_trampoline() + +//go:linkname libc_undelete libc_undelete +//go:cgo_import_dynamic libc_undelete undelete "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Unlink(path string) (err error) { @@ -1510,13 +2227,18 @@ func Unlink(path string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_unlink_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_unlink_trampoline() + +//go:linkname libc_unlink libc_unlink +//go:cgo_import_dynamic libc_unlink unlink "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Unlinkat(dirfd int, path string, flags int) (err error) { @@ -1525,13 +2247,18 @@ func Unlinkat(dirfd int, path string, flags int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + _, _, e1 := syscall_syscall(funcPC(libc_unlinkat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_unlinkat_trampoline() + +//go:linkname libc_unlinkat libc_unlinkat +//go:cgo_import_dynamic libc_unlinkat unlinkat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Unmount(path string, flags int) (err error) { @@ -1540,13 +2267,18 @@ func Unmount(path string, flags int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + _, _, e1 := syscall_syscall(funcPC(libc_unmount_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_unmount_trampoline() + +//go:linkname libc_unmount libc_unmount +//go:cgo_import_dynamic libc_unmount unmount "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func write(fd int, p []byte) (n int, err error) { @@ -1556,7 +2288,7 @@ func write(fd int, p []byte) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p))) + r0, _, e1 := syscall_syscall(funcPC(libc_write_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1564,10 +2296,15 @@ func write(fd int, p []byte) (n int, err error) { return } +func libc_write_trampoline() + +//go:linkname libc_write libc_write +//go:cgo_import_dynamic libc_write write "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) { - r0, _, e1 := Syscall6(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos)) + r0, _, e1 := syscall_syscall6(funcPC(libc_mmap_trampoline), uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos)) ret = uintptr(r0) if e1 != 0 { err = errnoErr(e1) @@ -1575,20 +2312,30 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) ( return } +func libc_mmap_trampoline() + +//go:linkname libc_mmap libc_mmap +//go:cgo_import_dynamic libc_mmap mmap "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func munmap(addr uintptr, length uintptr) (err error) { - _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0) + _, _, e1 := syscall_syscall(funcPC(libc_munmap_trampoline), uintptr(addr), uintptr(length), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_munmap_trampoline() + +//go:linkname libc_munmap libc_munmap +//go:cgo_import_dynamic libc_munmap munmap "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func readlen(fd int, buf *byte, nbuf int) (n int, err error) { - r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) + r0, _, e1 := syscall_syscall(funcPC(libc_read_trampoline), uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1599,7 +2346,7 @@ func readlen(fd int, buf *byte, nbuf int) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func writelen(fd int, buf *byte, nbuf int) (n int, err error) { - r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) + r0, _, e1 := syscall_syscall(funcPC(libc_write_trampoline), uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1610,7 +2357,7 @@ func writelen(fd int, buf *byte, nbuf int) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func gettimeofday(tp *Timeval) (sec int64, usec int32, err error) { - r0, r1, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0) + r0, r1, e1 := syscall_rawSyscall(funcPC(libc_gettimeofday_trampoline), uintptr(unsafe.Pointer(tp)), 0, 0) sec = int64(r0) usec = int32(r1) if e1 != 0 { @@ -1618,3 +2365,156 @@ func gettimeofday(tp *Timeval) (sec int64, usec int32, err error) { } return } + +func libc_gettimeofday_trampoline() + +//go:linkname libc_gettimeofday libc_gettimeofday +//go:cgo_import_dynamic libc_gettimeofday gettimeofday "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstat(fd int, stat *Stat_t) (err error) { + _, _, e1 := syscall_syscall(funcPC(libc_fstat64_trampoline), uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_fstat64_trampoline() + +//go:linkname libc_fstat64 libc_fstat64 +//go:cgo_import_dynamic libc_fstat64 fstat64 "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := syscall_syscall6(funcPC(libc_fstatat64_trampoline), uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_fstatat64_trampoline() + +//go:linkname libc_fstatat64 libc_fstatat64 +//go:cgo_import_dynamic libc_fstatat64 fstatat64 "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstatfs(fd int, stat *Statfs_t) (err error) { + _, _, e1 := syscall_syscall(funcPC(libc_fstatfs64_trampoline), uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_fstatfs64_trampoline() + +//go:linkname libc_fstatfs64 libc_fstatfs64 +//go:cgo_import_dynamic libc_fstatfs64 fstatfs64 "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := syscall_syscall6(funcPC(libc___getdirentries64_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc___getdirentries64_trampoline() + +//go:linkname libc___getdirentries64 libc___getdirentries64 +//go:cgo_import_dynamic libc___getdirentries64 __getdirentries64 "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) { + r0, _, e1 := syscall_syscall(funcPC(libc_getfsstat64_trampoline), uintptr(buf), uintptr(size), uintptr(flags)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_getfsstat64_trampoline() + +//go:linkname libc_getfsstat64 libc_getfsstat64 +//go:cgo_import_dynamic libc_getfsstat64 getfsstat64 "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Lstat(path string, stat *Stat_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := syscall_syscall(funcPC(libc_lstat64_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_lstat64_trampoline() + +//go:linkname libc_lstat64 libc_lstat64 +//go:cgo_import_dynamic libc_lstat64 lstat64 "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Stat(path string, stat *Stat_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := syscall_syscall(funcPC(libc_stat64_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_stat64_trampoline() + +//go:linkname libc_stat64 libc_stat64 +//go:cgo_import_dynamic libc_stat64 stat64 "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Statfs(path string, stat *Statfs_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := syscall_syscall(funcPC(libc_statfs64_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_statfs64_trampoline() + +//go:linkname libc_statfs64 libc_statfs64 +//go:cgo_import_dynamic libc_statfs64 statfs64 "/usr/lib/libSystem.B.dylib" diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s new file mode 100644 index 0000000000..1a3915197d --- /dev/null +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s @@ -0,0 +1,286 @@ +// go run mkasm_darwin.go amd64 +// Code generated by the command above; DO NOT EDIT. + +// +build go1.12 + +#include "textflag.h" +TEXT ·libc_getgroups_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getgroups(SB) +TEXT ·libc_setgroups_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setgroups(SB) +TEXT ·libc_wait4_trampoline(SB),NOSPLIT,$0-0 + JMP libc_wait4(SB) +TEXT ·libc_accept_trampoline(SB),NOSPLIT,$0-0 + JMP libc_accept(SB) +TEXT ·libc_bind_trampoline(SB),NOSPLIT,$0-0 + JMP libc_bind(SB) +TEXT ·libc_connect_trampoline(SB),NOSPLIT,$0-0 + JMP libc_connect(SB) +TEXT ·libc_socket_trampoline(SB),NOSPLIT,$0-0 + JMP libc_socket(SB) +TEXT ·libc_getsockopt_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getsockopt(SB) +TEXT ·libc_setsockopt_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setsockopt(SB) +TEXT ·libc_getpeername_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getpeername(SB) +TEXT ·libc_getsockname_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getsockname(SB) +TEXT ·libc_shutdown_trampoline(SB),NOSPLIT,$0-0 + JMP libc_shutdown(SB) +TEXT ·libc_socketpair_trampoline(SB),NOSPLIT,$0-0 + JMP libc_socketpair(SB) +TEXT ·libc_recvfrom_trampoline(SB),NOSPLIT,$0-0 + JMP libc_recvfrom(SB) +TEXT ·libc_sendto_trampoline(SB),NOSPLIT,$0-0 + JMP libc_sendto(SB) +TEXT ·libc_recvmsg_trampoline(SB),NOSPLIT,$0-0 + JMP libc_recvmsg(SB) +TEXT ·libc_sendmsg_trampoline(SB),NOSPLIT,$0-0 + JMP libc_sendmsg(SB) +TEXT ·libc_kevent_trampoline(SB),NOSPLIT,$0-0 + JMP libc_kevent(SB) +TEXT ·libc___sysctl_trampoline(SB),NOSPLIT,$0-0 + JMP libc___sysctl(SB) +TEXT ·libc_utimes_trampoline(SB),NOSPLIT,$0-0 + JMP libc_utimes(SB) +TEXT ·libc_futimes_trampoline(SB),NOSPLIT,$0-0 + JMP libc_futimes(SB) +TEXT ·libc_fcntl_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fcntl(SB) +TEXT ·libc_poll_trampoline(SB),NOSPLIT,$0-0 + JMP libc_poll(SB) +TEXT ·libc_madvise_trampoline(SB),NOSPLIT,$0-0 + JMP libc_madvise(SB) +TEXT ·libc_mlock_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mlock(SB) +TEXT ·libc_mlockall_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mlockall(SB) +TEXT ·libc_mprotect_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mprotect(SB) +TEXT ·libc_msync_trampoline(SB),NOSPLIT,$0-0 + JMP libc_msync(SB) +TEXT ·libc_munlock_trampoline(SB),NOSPLIT,$0-0 + JMP libc_munlock(SB) +TEXT ·libc_munlockall_trampoline(SB),NOSPLIT,$0-0 + JMP libc_munlockall(SB) +TEXT ·libc_ptrace_trampoline(SB),NOSPLIT,$0-0 + JMP libc_ptrace(SB) +TEXT ·libc_getattrlist_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getattrlist(SB) +TEXT ·libc_pipe_trampoline(SB),NOSPLIT,$0-0 + JMP libc_pipe(SB) +TEXT ·libc_getxattr_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getxattr(SB) +TEXT ·libc_fgetxattr_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fgetxattr(SB) +TEXT ·libc_setxattr_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setxattr(SB) +TEXT ·libc_fsetxattr_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fsetxattr(SB) +TEXT ·libc_removexattr_trampoline(SB),NOSPLIT,$0-0 + JMP libc_removexattr(SB) +TEXT ·libc_fremovexattr_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fremovexattr(SB) +TEXT ·libc_listxattr_trampoline(SB),NOSPLIT,$0-0 + JMP libc_listxattr(SB) +TEXT ·libc_flistxattr_trampoline(SB),NOSPLIT,$0-0 + JMP libc_flistxattr(SB) +TEXT ·libc_setattrlist_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setattrlist(SB) +TEXT ·libc_kill_trampoline(SB),NOSPLIT,$0-0 + JMP libc_kill(SB) +TEXT ·libc_ioctl_trampoline(SB),NOSPLIT,$0-0 + JMP libc_ioctl(SB) +TEXT ·libc_sendfile_trampoline(SB),NOSPLIT,$0-0 + JMP libc_sendfile(SB) +TEXT ·libc_access_trampoline(SB),NOSPLIT,$0-0 + JMP libc_access(SB) +TEXT ·libc_adjtime_trampoline(SB),NOSPLIT,$0-0 + JMP libc_adjtime(SB) +TEXT ·libc_chdir_trampoline(SB),NOSPLIT,$0-0 + JMP libc_chdir(SB) +TEXT ·libc_chflags_trampoline(SB),NOSPLIT,$0-0 + JMP libc_chflags(SB) +TEXT ·libc_chmod_trampoline(SB),NOSPLIT,$0-0 + JMP libc_chmod(SB) +TEXT ·libc_chown_trampoline(SB),NOSPLIT,$0-0 + JMP libc_chown(SB) +TEXT ·libc_chroot_trampoline(SB),NOSPLIT,$0-0 + JMP libc_chroot(SB) +TEXT ·libc_clock_gettime_trampoline(SB),NOSPLIT,$0-0 + JMP libc_clock_gettime(SB) +TEXT ·libc_close_trampoline(SB),NOSPLIT,$0-0 + JMP libc_close(SB) +TEXT ·libc_dup_trampoline(SB),NOSPLIT,$0-0 + JMP libc_dup(SB) +TEXT ·libc_dup2_trampoline(SB),NOSPLIT,$0-0 + JMP libc_dup2(SB) +TEXT ·libc_exchangedata_trampoline(SB),NOSPLIT,$0-0 + JMP libc_exchangedata(SB) +TEXT ·libc_exit_trampoline(SB),NOSPLIT,$0-0 + JMP libc_exit(SB) +TEXT ·libc_faccessat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_faccessat(SB) +TEXT ·libc_fchdir_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fchdir(SB) +TEXT ·libc_fchflags_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fchflags(SB) +TEXT ·libc_fchmod_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fchmod(SB) +TEXT ·libc_fchmodat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fchmodat(SB) +TEXT ·libc_fchown_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fchown(SB) +TEXT ·libc_fchownat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fchownat(SB) +TEXT ·libc_flock_trampoline(SB),NOSPLIT,$0-0 + JMP libc_flock(SB) +TEXT ·libc_fpathconf_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fpathconf(SB) +TEXT ·libc_fsync_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fsync(SB) +TEXT ·libc_ftruncate_trampoline(SB),NOSPLIT,$0-0 + JMP libc_ftruncate(SB) +TEXT ·libc_getdtablesize_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getdtablesize(SB) +TEXT ·libc_getegid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getegid(SB) +TEXT ·libc_geteuid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_geteuid(SB) +TEXT ·libc_getgid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getgid(SB) +TEXT ·libc_getpgid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getpgid(SB) +TEXT ·libc_getpgrp_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getpgrp(SB) +TEXT ·libc_getpid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getpid(SB) +TEXT ·libc_getppid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getppid(SB) +TEXT ·libc_getpriority_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getpriority(SB) +TEXT ·libc_getrlimit_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getrlimit(SB) +TEXT ·libc_getrusage_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getrusage(SB) +TEXT ·libc_getsid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getsid(SB) +TEXT ·libc_getuid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getuid(SB) +TEXT ·libc_issetugid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_issetugid(SB) +TEXT ·libc_kqueue_trampoline(SB),NOSPLIT,$0-0 + JMP libc_kqueue(SB) +TEXT ·libc_lchown_trampoline(SB),NOSPLIT,$0-0 + JMP libc_lchown(SB) +TEXT ·libc_link_trampoline(SB),NOSPLIT,$0-0 + JMP libc_link(SB) +TEXT ·libc_linkat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_linkat(SB) +TEXT ·libc_listen_trampoline(SB),NOSPLIT,$0-0 + JMP libc_listen(SB) +TEXT ·libc_mkdir_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mkdir(SB) +TEXT ·libc_mkdirat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mkdirat(SB) +TEXT ·libc_mkfifo_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mkfifo(SB) +TEXT ·libc_mknod_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mknod(SB) +TEXT ·libc_open_trampoline(SB),NOSPLIT,$0-0 + JMP libc_open(SB) +TEXT ·libc_openat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_openat(SB) +TEXT ·libc_pathconf_trampoline(SB),NOSPLIT,$0-0 + JMP libc_pathconf(SB) +TEXT ·libc_pread_trampoline(SB),NOSPLIT,$0-0 + JMP libc_pread(SB) +TEXT ·libc_pwrite_trampoline(SB),NOSPLIT,$0-0 + JMP libc_pwrite(SB) +TEXT ·libc_read_trampoline(SB),NOSPLIT,$0-0 + JMP libc_read(SB) +TEXT ·libc_readlink_trampoline(SB),NOSPLIT,$0-0 + JMP libc_readlink(SB) +TEXT ·libc_readlinkat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_readlinkat(SB) +TEXT ·libc_rename_trampoline(SB),NOSPLIT,$0-0 + JMP libc_rename(SB) +TEXT ·libc_renameat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_renameat(SB) +TEXT ·libc_revoke_trampoline(SB),NOSPLIT,$0-0 + JMP libc_revoke(SB) +TEXT ·libc_rmdir_trampoline(SB),NOSPLIT,$0-0 + JMP libc_rmdir(SB) +TEXT ·libc_lseek_trampoline(SB),NOSPLIT,$0-0 + JMP libc_lseek(SB) +TEXT ·libc_select_trampoline(SB),NOSPLIT,$0-0 + JMP libc_select(SB) +TEXT ·libc_setegid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setegid(SB) +TEXT ·libc_seteuid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_seteuid(SB) +TEXT ·libc_setgid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setgid(SB) +TEXT ·libc_setlogin_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setlogin(SB) +TEXT ·libc_setpgid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setpgid(SB) +TEXT ·libc_setpriority_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setpriority(SB) +TEXT ·libc_setprivexec_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setprivexec(SB) +TEXT ·libc_setregid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setregid(SB) +TEXT ·libc_setreuid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setreuid(SB) +TEXT ·libc_setrlimit_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setrlimit(SB) +TEXT ·libc_setsid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setsid(SB) +TEXT ·libc_settimeofday_trampoline(SB),NOSPLIT,$0-0 + JMP libc_settimeofday(SB) +TEXT ·libc_setuid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setuid(SB) +TEXT ·libc_symlink_trampoline(SB),NOSPLIT,$0-0 + JMP libc_symlink(SB) +TEXT ·libc_symlinkat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_symlinkat(SB) +TEXT ·libc_sync_trampoline(SB),NOSPLIT,$0-0 + JMP libc_sync(SB) +TEXT ·libc_truncate_trampoline(SB),NOSPLIT,$0-0 + JMP libc_truncate(SB) +TEXT ·libc_umask_trampoline(SB),NOSPLIT,$0-0 + JMP libc_umask(SB) +TEXT ·libc_undelete_trampoline(SB),NOSPLIT,$0-0 + JMP libc_undelete(SB) +TEXT ·libc_unlink_trampoline(SB),NOSPLIT,$0-0 + JMP libc_unlink(SB) +TEXT ·libc_unlinkat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_unlinkat(SB) +TEXT ·libc_unmount_trampoline(SB),NOSPLIT,$0-0 + JMP libc_unmount(SB) +TEXT ·libc_write_trampoline(SB),NOSPLIT,$0-0 + JMP libc_write(SB) +TEXT ·libc_mmap_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mmap(SB) +TEXT ·libc_munmap_trampoline(SB),NOSPLIT,$0-0 + JMP libc_munmap(SB) +TEXT ·libc_gettimeofday_trampoline(SB),NOSPLIT,$0-0 + JMP libc_gettimeofday(SB) +TEXT ·libc_fstat64_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fstat64(SB) +TEXT ·libc_fstatat64_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fstatat64(SB) +TEXT ·libc_fstatfs64_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fstatfs64(SB) +TEXT ·libc___getdirentries64_trampoline(SB),NOSPLIT,$0-0 + JMP libc___getdirentries64(SB) +TEXT ·libc_getfsstat64_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getfsstat64(SB) +TEXT ·libc_lstat64_trampoline(SB),NOSPLIT,$0-0 + JMP libc_lstat64(SB) +TEXT ·libc_stat64_trampoline(SB),NOSPLIT,$0-0 + JMP libc_stat64(SB) +TEXT ·libc_statfs64_trampoline(SB),NOSPLIT,$0-0 + JMP libc_statfs64(SB) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.1_11.go b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.1_11.go new file mode 100644 index 0000000000..f8caecef02 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.1_11.go @@ -0,0 +1,1793 @@ +// go run mksyscall.go -l32 -tags darwin,arm,!go1.12 syscall_bsd.go syscall_darwin.go syscall_darwin_arm.go +// Code generated by the command above; see README.md. DO NOT EDIT. + +// +build darwin,arm,!go1.12 + +package unix + +import ( + "syscall" + "unsafe" +) + +var _ syscall.Errno + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getgroups(ngid int, gid *_Gid_t) (n int, err error) { + r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setgroups(ngid int, gid *_Gid_t) (err error) { + _, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) { + r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0) + wpid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { + r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { + _, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { + _, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func socket(domain int, typ int, proto int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto)) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) { + _, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) { + _, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { + _, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { + _, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Shutdown(s int, how int) (err error) { + _, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) { + _, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) { + r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) { + r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) { + r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) { + var _p0 unsafe.Pointer + if len(mib) > 0 { + _p0 = unsafe.Pointer(&mib[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func utimes(path string, timeval *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func futimes(fd int, timeval *[2]Timeval) (err error) { + _, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fcntl(fd int, cmd int, arg int) (val int, err error) { + r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg)) + val = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { + r0, _, e1 := Syscall(SYS_POLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Madvise(b []byte, behav int) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(behav)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mlock(b []byte) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mlockall(flags int) (err error) { + _, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mprotect(b []byte, prot int) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Msync(b []byte, flags int) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MSYNC, uintptr(_p0), uintptr(len(b)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Munlock(b []byte) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Munlockall() (err error) { + _, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) { + _, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error) { + _, _, e1 := Syscall6(SYS_GETATTRLIST, uintptr(unsafe.Pointer(path)), uintptr(list), uintptr(buf), uintptr(size), uintptr(options), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func pipe() (r int, w int, err error) { + r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0) + r = int(r0) + w = int(r1) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getxattr(path string, attr string, dest *byte, size int, position uint32, options int) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(position), uintptr(options)) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fgetxattr(fd int, attr string, dest *byte, size int, position uint32, options int) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_FGETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(position), uintptr(options)) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setxattr(path string, attr string, data *byte, size int, position uint32, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(data)), uintptr(size), uintptr(position), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fsetxattr(fd int, attr string, data *byte, size int, position uint32, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FSETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(data)), uintptr(size), uintptr(position), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func removexattr(path string, attr string, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_REMOVEXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fremovexattr(fd int, attr string, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FREMOVEXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func listxattr(path string, dest *byte, size int, options int) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_LISTXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(options), 0, 0) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func flistxattr(fd int, dest *byte, size int, options int) (sz int, err error) { + r0, _, e1 := Syscall6(SYS_FLISTXATTR, uintptr(fd), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(options), 0, 0) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error) { + _, _, e1 := Syscall6(SYS_SETATTRLIST, uintptr(unsafe.Pointer(path)), uintptr(list), uintptr(buf), uintptr(size), uintptr(options), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func kill(pid int, signum int, posix int) (err error) { + _, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), uintptr(posix)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ioctl(fd int, req uint, arg uintptr) (err error) { + _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) { + _, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(offset), uintptr(offset>>32), uintptr(unsafe.Pointer(len)), uintptr(hdtr), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Access(path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Adjtime(delta *Timeval, olddelta *Timeval) (err error) { + _, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chdir(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chflags(path string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chmod(path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chown(path string, uid int, gid int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chroot(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Close(fd int) (err error) { + _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Dup(fd int) (nfd int, err error) { + r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0) + nfd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Dup2(from int, to int) (err error) { + _, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Exchangedata(path1 string, path2 string, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path1) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(path2) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_EXCHANGEDATA, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Exit(code int) { + Syscall(SYS_EXIT, uintptr(code), 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchdir(fd int) (err error) { + _, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchflags(fd int, flags int) (err error) { + _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchmod(fd int, mode uint32) (err error) { + _, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchown(fd int, uid int, gid int) (err error) { + _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Flock(fd int, how int) (err error) { + _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fpathconf(fd int, name int) (val int, err error) { + r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0) + val = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fsync(fd int) (err error) { + _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Ftruncate(fd int, length int64) (err error) { + _, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), uintptr(length>>32)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getdtablesize() (size int) { + r0, _, _ := Syscall(SYS_GETDTABLESIZE, 0, 0, 0) + size = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getegid() (egid int) { + r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0) + egid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Geteuid() (uid int) { + r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0) + uid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getgid() (gid int) { + r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0) + gid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpgid(pid int) (pgid int, err error) { + r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0) + pgid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpgrp() (pgrp int) { + r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0) + pgrp = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpid() (pid int) { + r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0) + pid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getppid() (ppid int) { + r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0) + ppid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpriority(which int, who int) (prio int, err error) { + r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0) + prio = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getrlimit(which int, lim *Rlimit) (err error) { + _, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getrusage(who int, rusage *Rusage) (err error) { + _, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getsid(pid int) (sid int, err error) { + r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0) + sid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getuid() (uid int) { + r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0) + uid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Issetugid() (tainted bool) { + r0, _, _ := RawSyscall(SYS_ISSETUGID, 0, 0, 0) + tainted = bool(r0 != 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Kqueue() (fd int, err error) { + r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Lchown(path string, uid int, gid int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Link(path string, link string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(link) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(link) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_LINKAT, uintptr(pathfd), uintptr(unsafe.Pointer(_p0)), uintptr(linkfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Listen(s int, backlog int) (err error) { + _, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mkdir(path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mkdirat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mkfifo(path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mknod(path string, mode uint32, dev int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Open(path string, mode int, perm uint32) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pathconf(path string, name int) (val int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) + val = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pread(fd int, p []byte, offset int64) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pwrite(fd int, p []byte, offset int64) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func read(fd int, p []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Readlink(path string, buf []byte) (n int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(buf) > 0 { + _p1 = unsafe.Pointer(&buf[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(buf) > 0 { + _p1 = unsafe.Pointer(&buf[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_READLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Rename(from string, to string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(from) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(to) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Renameat(fromfd int, from string, tofd int, to string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(from) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(to) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(fromfd), uintptr(unsafe.Pointer(_p0)), uintptr(tofd), uintptr(unsafe.Pointer(_p1)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Revoke(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Rmdir(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { + r0, r1, e1 := Syscall6(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(offset>>32), uintptr(whence), 0, 0) + newoffset = int64(int64(r1)<<32 | int64(r0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) { + _, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setegid(egid int) (err error) { + _, _, e1 := Syscall(SYS_SETEGID, uintptr(egid), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Seteuid(euid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setgid(gid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setlogin(name string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(name) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setpgid(pid int, pgid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setpriority(which int, who int, prio int) (err error) { + _, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setprivexec(flag int) (err error) { + _, _, e1 := Syscall(SYS_SETPRIVEXEC, uintptr(flag), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setregid(rgid int, egid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setreuid(ruid int, euid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setrlimit(which int, lim *Rlimit) (err error) { + _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setsid() (pid int, err error) { + r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0) + pid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Settimeofday(tp *Timeval) (err error) { + _, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setuid(uid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Symlink(path string, link string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(link) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_SYMLINKAT, uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Sync() (err error) { + _, _, e1 := Syscall(SYS_SYNC, 0, 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Truncate(path string, length int64) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), uintptr(length>>32)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Umask(newmask int) (oldmask int) { + r0, _, _ := Syscall(SYS_UMASK, uintptr(newmask), 0, 0) + oldmask = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Undelete(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Unlink(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Unlinkat(dirfd int, path string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Unmount(path string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func write(fd int, p []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) { + r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos), uintptr(pos>>32), 0, 0) + ret = uintptr(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func munmap(addr uintptr, length uintptr) (err error) { + _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func readlen(fd int, buf *byte, nbuf int) (n int, err error) { + r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func writelen(fd int, buf *byte, nbuf int) (n int, err error) { + r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func gettimeofday(tp *Timeval) (sec int32, usec int32, err error) { + r0, r1, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0) + sec = int32(r0) + usec = int32(r1) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstat(fd int, stat *Stat_t) (err error) { + _, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FSTATAT, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstatfs(fd int, stat *Statfs_t) (err error) { + _, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) { + r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(buf), uintptr(size), uintptr(flags)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Lstat(path string, stat *Stat_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Stat(path string, stat *Stat_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Statfs(path string, stat *Statfs_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.go b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.go index 6ae95e6b9a..01cffbf46c 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.go @@ -1,7 +1,7 @@ -// mksyscall.pl -tags darwin,arm syscall_bsd.go syscall_darwin.go syscall_darwin_arm.go +// go run mksyscall.go -l32 -tags darwin,arm,go1.12 syscall_bsd.go syscall_darwin.go syscall_darwin_arm.go // Code generated by the command above; see README.md. DO NOT EDIT. -// +build darwin,arm +// +build darwin,arm,go1.12 package unix @@ -15,7 +15,7 @@ var _ syscall.Errno // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getgroups(ngid int, gid *_Gid_t) (n int, err error) { - r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) + r0, _, e1 := syscall_rawSyscall(funcPC(libc_getgroups_trampoline), uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -23,20 +23,30 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) { return } +func libc_getgroups_trampoline() + +//go:linkname libc_getgroups libc_getgroups +//go:cgo_import_dynamic libc_getgroups getgroups "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func setgroups(ngid int, gid *_Gid_t) (err error) { - _, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_setgroups_trampoline), uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setgroups_trampoline() + +//go:linkname libc_setgroups libc_setgroups +//go:cgo_import_dynamic libc_setgroups setgroups "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) { - r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0) + r0, _, e1 := syscall_syscall6(funcPC(libc_wait4_trampoline), uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0) wpid = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -44,10 +54,15 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err return } +func libc_wait4_trampoline() + +//go:linkname libc_wait4 libc_wait4 +//go:cgo_import_dynamic libc_wait4 wait4 "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { - r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + r0, _, e1 := syscall_syscall(funcPC(libc_accept_trampoline), uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -55,30 +70,45 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { return } +func libc_accept_trampoline() + +//go:linkname libc_accept libc_accept +//go:cgo_import_dynamic libc_accept accept "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { - _, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen)) + _, _, e1 := syscall_syscall(funcPC(libc_bind_trampoline), uintptr(s), uintptr(addr), uintptr(addrlen)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_bind_trampoline() + +//go:linkname libc_bind libc_bind +//go:cgo_import_dynamic libc_bind bind "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { - _, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen)) + _, _, e1 := syscall_syscall(funcPC(libc_connect_trampoline), uintptr(s), uintptr(addr), uintptr(addrlen)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_connect_trampoline() + +//go:linkname libc_connect libc_connect +//go:cgo_import_dynamic libc_connect connect "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func socket(domain int, typ int, proto int) (fd int, err error) { - r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto)) + r0, _, e1 := syscall_rawSyscall(funcPC(libc_socket_trampoline), uintptr(domain), uintptr(typ), uintptr(proto)) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -86,66 +116,101 @@ func socket(domain int, typ int, proto int) (fd int, err error) { return } +func libc_socket_trampoline() + +//go:linkname libc_socket libc_socket +//go:cgo_import_dynamic libc_socket socket "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) { - _, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0) + _, _, e1 := syscall_syscall6(funcPC(libc_getsockopt_trampoline), uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_getsockopt_trampoline() + +//go:linkname libc_getsockopt libc_getsockopt +//go:cgo_import_dynamic libc_getsockopt getsockopt "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) { - _, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0) + _, _, e1 := syscall_syscall6(funcPC(libc_setsockopt_trampoline), uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setsockopt_trampoline() + +//go:linkname libc_setsockopt libc_setsockopt +//go:cgo_import_dynamic libc_setsockopt setsockopt "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { - _, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + _, _, e1 := syscall_rawSyscall(funcPC(libc_getpeername_trampoline), uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) if e1 != 0 { err = errnoErr(e1) } return } +func libc_getpeername_trampoline() + +//go:linkname libc_getpeername libc_getpeername +//go:cgo_import_dynamic libc_getpeername getpeername "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { - _, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + _, _, e1 := syscall_rawSyscall(funcPC(libc_getsockname_trampoline), uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) if e1 != 0 { err = errnoErr(e1) } return } +func libc_getsockname_trampoline() + +//go:linkname libc_getsockname libc_getsockname +//go:cgo_import_dynamic libc_getsockname getsockname "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Shutdown(s int, how int) (err error) { - _, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0) + _, _, e1 := syscall_syscall(funcPC(libc_shutdown_trampoline), uintptr(s), uintptr(how), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_shutdown_trampoline() + +//go:linkname libc_shutdown libc_shutdown +//go:cgo_import_dynamic libc_shutdown shutdown "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) { - _, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0) + _, _, e1 := syscall_rawSyscall6(funcPC(libc_socketpair_trampoline), uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_socketpair_trampoline() + +//go:linkname libc_socketpair libc_socketpair +//go:cgo_import_dynamic libc_socketpair socketpair "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) { @@ -155,7 +220,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen))) + r0, _, e1 := syscall_syscall6(funcPC(libc_recvfrom_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -163,6 +228,11 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl return } +func libc_recvfrom_trampoline() + +//go:linkname libc_recvfrom libc_recvfrom +//go:cgo_import_dynamic libc_recvfrom recvfrom "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) { @@ -172,17 +242,22 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) ( } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen)) + _, _, e1 := syscall_syscall6(funcPC(libc_sendto_trampoline), uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_sendto_trampoline() + +//go:linkname libc_sendto libc_sendto +//go:cgo_import_dynamic libc_sendto sendto "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) { - r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + r0, _, e1 := syscall_syscall(funcPC(libc_recvmsg_trampoline), uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -190,10 +265,15 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) { return } +func libc_recvmsg_trampoline() + +//go:linkname libc_recvmsg libc_recvmsg +//go:cgo_import_dynamic libc_recvmsg recvmsg "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) { - r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + r0, _, e1 := syscall_syscall(funcPC(libc_sendmsg_trampoline), uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -201,10 +281,15 @@ func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) { return } +func libc_sendmsg_trampoline() + +//go:linkname libc_sendmsg libc_sendmsg +//go:cgo_import_dynamic libc_sendmsg sendmsg "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) { - r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout))) + r0, _, e1 := syscall_syscall6(funcPC(libc_kevent_trampoline), uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -212,6 +297,11 @@ func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, ne return } +func libc_kevent_trampoline() + +//go:linkname libc_kevent libc_kevent +//go:cgo_import_dynamic libc_kevent kevent "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) { @@ -221,13 +311,18 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) + _, _, e1 := syscall_syscall6(funcPC(libc___sysctl_trampoline), uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) if e1 != 0 { err = errnoErr(e1) } return } +func libc___sysctl_trampoline() + +//go:linkname libc___sysctl libc___sysctl +//go:cgo_import_dynamic libc___sysctl __sysctl "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func utimes(path string, timeval *[2]Timeval) (err error) { @@ -236,27 +331,37 @@ func utimes(path string, timeval *[2]Timeval) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) + _, _, e1 := syscall_syscall(funcPC(libc_utimes_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_utimes_trampoline() + +//go:linkname libc_utimes libc_utimes +//go:cgo_import_dynamic libc_utimes utimes "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func futimes(fd int, timeval *[2]Timeval) (err error) { - _, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0) + _, _, e1 := syscall_syscall(funcPC(libc_futimes_trampoline), uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_futimes_trampoline() + +//go:linkname libc_futimes libc_futimes +//go:cgo_import_dynamic libc_futimes futimes "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func fcntl(fd int, cmd int, arg int) (val int, err error) { - r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg)) + r0, _, e1 := syscall_syscall(funcPC(libc_fcntl_trampoline), uintptr(fd), uintptr(cmd), uintptr(arg)) val = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -264,10 +369,15 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) { return } +func libc_fcntl_trampoline() + +//go:linkname libc_fcntl libc_fcntl +//go:cgo_import_dynamic libc_fcntl fcntl "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { - r0, _, e1 := Syscall(SYS_POLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout)) + r0, _, e1 := syscall_syscall(funcPC(libc_poll_trampoline), uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -275,6 +385,11 @@ func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { return } +func libc_poll_trampoline() + +//go:linkname libc_poll libc_poll +//go:cgo_import_dynamic libc_poll poll "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Madvise(b []byte, behav int) (err error) { @@ -284,13 +399,18 @@ func Madvise(b []byte, behav int) (err error) { } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(behav)) + _, _, e1 := syscall_syscall(funcPC(libc_madvise_trampoline), uintptr(_p0), uintptr(len(b)), uintptr(behav)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_madvise_trampoline() + +//go:linkname libc_madvise libc_madvise +//go:cgo_import_dynamic libc_madvise madvise "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mlock(b []byte) (err error) { @@ -300,23 +420,33 @@ func Mlock(b []byte) (err error) { } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0) + _, _, e1 := syscall_syscall(funcPC(libc_mlock_trampoline), uintptr(_p0), uintptr(len(b)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_mlock_trampoline() + +//go:linkname libc_mlock libc_mlock +//go:cgo_import_dynamic libc_mlock mlock "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mlockall(flags int) (err error) { - _, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_mlockall_trampoline), uintptr(flags), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_mlockall_trampoline() + +//go:linkname libc_mlockall libc_mlockall +//go:cgo_import_dynamic libc_mlockall mlockall "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mprotect(b []byte, prot int) (err error) { @@ -326,13 +456,18 @@ func Mprotect(b []byte, prot int) (err error) { } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot)) + _, _, e1 := syscall_syscall(funcPC(libc_mprotect_trampoline), uintptr(_p0), uintptr(len(b)), uintptr(prot)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_mprotect_trampoline() + +//go:linkname libc_mprotect libc_mprotect +//go:cgo_import_dynamic libc_mprotect mprotect "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Msync(b []byte, flags int) (err error) { @@ -342,13 +477,18 @@ func Msync(b []byte, flags int) (err error) { } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall(SYS_MSYNC, uintptr(_p0), uintptr(len(b)), uintptr(flags)) + _, _, e1 := syscall_syscall(funcPC(libc_msync_trampoline), uintptr(_p0), uintptr(len(b)), uintptr(flags)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_msync_trampoline() + +//go:linkname libc_msync libc_msync +//go:cgo_import_dynamic libc_msync msync "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Munlock(b []byte) (err error) { @@ -358,37 +498,67 @@ func Munlock(b []byte) (err error) { } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0) + _, _, e1 := syscall_syscall(funcPC(libc_munlock_trampoline), uintptr(_p0), uintptr(len(b)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_munlock_trampoline() + +//go:linkname libc_munlock libc_munlock +//go:cgo_import_dynamic libc_munlock munlock "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Munlockall() (err error) { - _, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_munlockall_trampoline), 0, 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_munlockall_trampoline() + +//go:linkname libc_munlockall libc_munlockall +//go:cgo_import_dynamic libc_munlockall munlockall "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) { - _, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0) + _, _, e1 := syscall_syscall6(funcPC(libc_ptrace_trampoline), uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_ptrace_trampoline() + +//go:linkname libc_ptrace libc_ptrace +//go:cgo_import_dynamic libc_ptrace ptrace "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error) { + _, _, e1 := syscall_syscall6(funcPC(libc_getattrlist_trampoline), uintptr(unsafe.Pointer(path)), uintptr(list), uintptr(buf), uintptr(size), uintptr(options), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_getattrlist_trampoline() + +//go:linkname libc_getattrlist libc_getattrlist +//go:cgo_import_dynamic libc_getattrlist getattrlist "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func pipe() (r int, w int, err error) { - r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0) + r0, r1, e1 := syscall_rawSyscall(funcPC(libc_pipe_trampoline), 0, 0, 0) r = int(r0) w = int(r1) if e1 != 0 { @@ -397,26 +567,245 @@ func pipe() (r int, w int, err error) { return } +func libc_pipe_trampoline() + +//go:linkname libc_pipe libc_pipe +//go:cgo_import_dynamic libc_pipe pipe "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func kill(pid int, signum int, posix int) (err error) { - _, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), uintptr(posix)) +func getxattr(path string, attr string, dest *byte, size int, position uint32, options int) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + r0, _, e1 := syscall_syscall6(funcPC(libc_getxattr_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(position), uintptr(options)) + sz = int(r0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_getxattr_trampoline() + +//go:linkname libc_getxattr libc_getxattr +//go:cgo_import_dynamic libc_getxattr getxattr "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fgetxattr(fd int, attr string, dest *byte, size int, position uint32, options int) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + r0, _, e1 := syscall_syscall6(funcPC(libc_fgetxattr_trampoline), uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(position), uintptr(options)) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_fgetxattr_trampoline() + +//go:linkname libc_fgetxattr libc_fgetxattr +//go:cgo_import_dynamic libc_fgetxattr fgetxattr "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setxattr(path string, attr string, data *byte, size int, position uint32, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := syscall_syscall6(funcPC(libc_setxattr_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(data)), uintptr(size), uintptr(position), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_setxattr_trampoline() + +//go:linkname libc_setxattr libc_setxattr +//go:cgo_import_dynamic libc_setxattr setxattr "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fsetxattr(fd int, attr string, data *byte, size int, position uint32, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := syscall_syscall6(funcPC(libc_fsetxattr_trampoline), uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(data)), uintptr(size), uintptr(position), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_fsetxattr_trampoline() + +//go:linkname libc_fsetxattr libc_fsetxattr +//go:cgo_import_dynamic libc_fsetxattr fsetxattr "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func removexattr(path string, attr string, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := syscall_syscall(funcPC(libc_removexattr_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_removexattr_trampoline() + +//go:linkname libc_removexattr libc_removexattr +//go:cgo_import_dynamic libc_removexattr removexattr "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fremovexattr(fd int, attr string, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := syscall_syscall(funcPC(libc_fremovexattr_trampoline), uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_fremovexattr_trampoline() + +//go:linkname libc_fremovexattr libc_fremovexattr +//go:cgo_import_dynamic libc_fremovexattr fremovexattr "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func listxattr(path string, dest *byte, size int, options int) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := syscall_syscall6(funcPC(libc_listxattr_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(options), 0, 0) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_listxattr_trampoline() + +//go:linkname libc_listxattr libc_listxattr +//go:cgo_import_dynamic libc_listxattr listxattr "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func flistxattr(fd int, dest *byte, size int, options int) (sz int, err error) { + r0, _, e1 := syscall_syscall6(funcPC(libc_flistxattr_trampoline), uintptr(fd), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(options), 0, 0) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_flistxattr_trampoline() + +//go:linkname libc_flistxattr libc_flistxattr +//go:cgo_import_dynamic libc_flistxattr flistxattr "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error) { + _, _, e1 := syscall_syscall6(funcPC(libc_setattrlist_trampoline), uintptr(unsafe.Pointer(path)), uintptr(list), uintptr(buf), uintptr(size), uintptr(options), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_setattrlist_trampoline() + +//go:linkname libc_setattrlist libc_setattrlist +//go:cgo_import_dynamic libc_setattrlist setattrlist "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func kill(pid int, signum int, posix int) (err error) { + _, _, e1 := syscall_syscall(funcPC(libc_kill_trampoline), uintptr(pid), uintptr(signum), uintptr(posix)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_kill_trampoline() + +//go:linkname libc_kill libc_kill +//go:cgo_import_dynamic libc_kill kill "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func ioctl(fd int, req uint, arg uintptr) (err error) { - _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg)) + _, _, e1 := syscall_syscall(funcPC(libc_ioctl_trampoline), uintptr(fd), uintptr(req), uintptr(arg)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_ioctl_trampoline() + +//go:linkname libc_ioctl libc_ioctl +//go:cgo_import_dynamic libc_ioctl ioctl "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) { + _, _, e1 := syscall_syscall9(funcPC(libc_sendfile_trampoline), uintptr(infd), uintptr(outfd), uintptr(offset), uintptr(offset>>32), uintptr(unsafe.Pointer(len)), uintptr(hdtr), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_sendfile_trampoline() + +//go:linkname libc_sendfile libc_sendfile +//go:cgo_import_dynamic libc_sendfile sendfile "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Access(path string, mode uint32) (err error) { @@ -425,23 +814,33 @@ func Access(path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + _, _, e1 := syscall_syscall(funcPC(libc_access_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_access_trampoline() + +//go:linkname libc_access libc_access +//go:cgo_import_dynamic libc_access access "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Adjtime(delta *Timeval, olddelta *Timeval) (err error) { - _, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0) + _, _, e1 := syscall_syscall(funcPC(libc_adjtime_trampoline), uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_adjtime_trampoline() + +//go:linkname libc_adjtime libc_adjtime +//go:cgo_import_dynamic libc_adjtime adjtime "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Chdir(path string) (err error) { @@ -450,13 +849,18 @@ func Chdir(path string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_chdir_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_chdir_trampoline() + +//go:linkname libc_chdir libc_chdir +//go:cgo_import_dynamic libc_chdir chdir "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Chflags(path string, flags int) (err error) { @@ -465,13 +869,18 @@ func Chflags(path string, flags int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + _, _, e1 := syscall_syscall(funcPC(libc_chflags_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_chflags_trampoline() + +//go:linkname libc_chflags libc_chflags +//go:cgo_import_dynamic libc_chflags chflags "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Chmod(path string, mode uint32) (err error) { @@ -480,13 +889,18 @@ func Chmod(path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + _, _, e1 := syscall_syscall(funcPC(libc_chmod_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_chmod_trampoline() + +//go:linkname libc_chmod libc_chmod +//go:cgo_import_dynamic libc_chmod chmod "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Chown(path string, uid int, gid int) (err error) { @@ -495,13 +909,18 @@ func Chown(path string, uid int, gid int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + _, _, e1 := syscall_syscall(funcPC(libc_chown_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_chown_trampoline() + +//go:linkname libc_chown libc_chown +//go:cgo_import_dynamic libc_chown chown "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Chroot(path string) (err error) { @@ -510,27 +929,37 @@ func Chroot(path string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_chroot_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_chroot_trampoline() + +//go:linkname libc_chroot libc_chroot +//go:cgo_import_dynamic libc_chroot chroot "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Close(fd int) (err error) { - _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_close_trampoline), uintptr(fd), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_close_trampoline() + +//go:linkname libc_close libc_close +//go:cgo_import_dynamic libc_close close "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Dup(fd int) (nfd int, err error) { - r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0) + r0, _, e1 := syscall_syscall(funcPC(libc_dup_trampoline), uintptr(fd), 0, 0) nfd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -538,16 +967,26 @@ func Dup(fd int) (nfd int, err error) { return } +func libc_dup_trampoline() + +//go:linkname libc_dup libc_dup +//go:cgo_import_dynamic libc_dup dup "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Dup2(from int, to int) (err error) { - _, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0) + _, _, e1 := syscall_syscall(funcPC(libc_dup2_trampoline), uintptr(from), uintptr(to), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_dup2_trampoline() + +//go:linkname libc_dup2 libc_dup2 +//go:cgo_import_dynamic libc_dup2 dup2 "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Exchangedata(path1 string, path2 string, options int) (err error) { @@ -561,20 +1000,30 @@ func Exchangedata(path1 string, path2 string, options int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_EXCHANGEDATA, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) + _, _, e1 := syscall_syscall(funcPC(libc_exchangedata_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_exchangedata_trampoline() + +//go:linkname libc_exchangedata libc_exchangedata +//go:cgo_import_dynamic libc_exchangedata exchangedata "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Exit(code int) { - Syscall(SYS_EXIT, uintptr(code), 0, 0) + syscall_syscall(funcPC(libc_exit_trampoline), uintptr(code), 0, 0) return } +func libc_exit_trampoline() + +//go:linkname libc_exit libc_exit +//go:cgo_import_dynamic libc_exit exit "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { @@ -583,43 +1032,63 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { if err != nil { return } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + _, _, e1 := syscall_syscall6(funcPC(libc_faccessat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_faccessat_trampoline() + +//go:linkname libc_faccessat libc_faccessat +//go:cgo_import_dynamic libc_faccessat faccessat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchdir(fd int) (err error) { - _, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_fchdir_trampoline), uintptr(fd), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_fchdir_trampoline() + +//go:linkname libc_fchdir libc_fchdir +//go:cgo_import_dynamic libc_fchdir fchdir "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchflags(fd int, flags int) (err error) { - _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0) + _, _, e1 := syscall_syscall(funcPC(libc_fchflags_trampoline), uintptr(fd), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_fchflags_trampoline() + +//go:linkname libc_fchflags libc_fchflags +//go:cgo_import_dynamic libc_fchflags fchflags "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchmod(fd int, mode uint32) (err error) { - _, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0) + _, _, e1 := syscall_syscall(funcPC(libc_fchmod_trampoline), uintptr(fd), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_fchmod_trampoline() + +//go:linkname libc_fchmod libc_fchmod +//go:cgo_import_dynamic libc_fchmod fchmod "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { @@ -628,23 +1097,33 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { if err != nil { return } - _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + _, _, e1 := syscall_syscall6(funcPC(libc_fchmodat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_fchmodat_trampoline() + +//go:linkname libc_fchmodat libc_fchmodat +//go:cgo_import_dynamic libc_fchmodat fchmodat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchown(fd int, uid int, gid int) (err error) { - _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)) + _, _, e1 := syscall_syscall(funcPC(libc_fchown_trampoline), uintptr(fd), uintptr(uid), uintptr(gid)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_fchown_trampoline() + +//go:linkname libc_fchown libc_fchown +//go:cgo_import_dynamic libc_fchown fchown "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { @@ -653,27 +1132,37 @@ func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { if err != nil { return } - _, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0) + _, _, e1 := syscall_syscall6(funcPC(libc_fchownat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_fchownat_trampoline() + +//go:linkname libc_fchownat libc_fchownat +//go:cgo_import_dynamic libc_fchownat fchownat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Flock(fd int, how int) (err error) { - _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0) + _, _, e1 := syscall_syscall(funcPC(libc_flock_trampoline), uintptr(fd), uintptr(how), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_flock_trampoline() + +//go:linkname libc_flock libc_flock +//go:cgo_import_dynamic libc_flock flock "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fpathconf(fd int, name int) (val int, err error) { - r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0) + r0, _, e1 := syscall_syscall(funcPC(libc_fpathconf_trampoline), uintptr(fd), uintptr(name), 0) val = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -681,99 +1170,97 @@ func Fpathconf(fd int, name int) (val int, err error) { return } -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func libc_fpathconf_trampoline() -func Fstat(fd int, stat *Stat_t) (err error) { - _, _, e1 := Syscall(SYS_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Fstatfs(fd int, stat *Statfs_t) (err error) { - _, _, e1 := Syscall(SYS_FSTATFS64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} +//go:linkname libc_fpathconf libc_fpathconf +//go:cgo_import_dynamic libc_fpathconf fpathconf "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fsync(fd int) (err error) { - _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_fsync_trampoline), uintptr(fd), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_fsync_trampoline() + +//go:linkname libc_fsync libc_fsync +//go:cgo_import_dynamic libc_fsync fsync "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Ftruncate(fd int, length int64) (err error) { - _, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), uintptr(length>>32)) + _, _, e1 := syscall_syscall(funcPC(libc_ftruncate_trampoline), uintptr(fd), uintptr(length), uintptr(length>>32)) if e1 != 0 { err = errnoErr(e1) } return } -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func libc_ftruncate_trampoline() -func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { - var _p0 unsafe.Pointer - if len(buf) > 0 { - _p0 = unsafe.Pointer(&buf[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall6(SYS_GETDIRENTRIES64, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} +//go:linkname libc_ftruncate libc_ftruncate +//go:cgo_import_dynamic libc_ftruncate ftruncate "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getdtablesize() (size int) { - r0, _, _ := Syscall(SYS_GETDTABLESIZE, 0, 0, 0) + r0, _, _ := syscall_syscall(funcPC(libc_getdtablesize_trampoline), 0, 0, 0) size = int(r0) return } +func libc_getdtablesize_trampoline() + +//go:linkname libc_getdtablesize libc_getdtablesize +//go:cgo_import_dynamic libc_getdtablesize getdtablesize "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getegid() (egid int) { - r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(funcPC(libc_getegid_trampoline), 0, 0, 0) egid = int(r0) return } +func libc_getegid_trampoline() + +//go:linkname libc_getegid libc_getegid +//go:cgo_import_dynamic libc_getegid getegid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Geteuid() (uid int) { - r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(funcPC(libc_geteuid_trampoline), 0, 0, 0) uid = int(r0) return } +func libc_geteuid_trampoline() + +//go:linkname libc_geteuid libc_geteuid +//go:cgo_import_dynamic libc_geteuid geteuid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getgid() (gid int) { - r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(funcPC(libc_getgid_trampoline), 0, 0, 0) gid = int(r0) return } +func libc_getgid_trampoline() + +//go:linkname libc_getgid libc_getgid +//go:cgo_import_dynamic libc_getgid getgid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpgid(pid int) (pgid int, err error) { - r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0) + r0, _, e1 := syscall_rawSyscall(funcPC(libc_getpgid_trampoline), uintptr(pid), 0, 0) pgid = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -781,34 +1268,54 @@ func Getpgid(pid int) (pgid int, err error) { return } +func libc_getpgid_trampoline() + +//go:linkname libc_getpgid libc_getpgid +//go:cgo_import_dynamic libc_getpgid getpgid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpgrp() (pgrp int) { - r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(funcPC(libc_getpgrp_trampoline), 0, 0, 0) pgrp = int(r0) return } +func libc_getpgrp_trampoline() + +//go:linkname libc_getpgrp libc_getpgrp +//go:cgo_import_dynamic libc_getpgrp getpgrp "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpid() (pid int) { - r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(funcPC(libc_getpid_trampoline), 0, 0, 0) pid = int(r0) return } +func libc_getpid_trampoline() + +//go:linkname libc_getpid libc_getpid +//go:cgo_import_dynamic libc_getpid getpid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getppid() (ppid int) { - r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(funcPC(libc_getppid_trampoline), 0, 0, 0) ppid = int(r0) return } +func libc_getppid_trampoline() + +//go:linkname libc_getppid libc_getppid +//go:cgo_import_dynamic libc_getppid getppid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpriority(which int, who int) (prio int, err error) { - r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0) + r0, _, e1 := syscall_syscall(funcPC(libc_getpriority_trampoline), uintptr(which), uintptr(who), 0) prio = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -816,30 +1323,45 @@ func Getpriority(which int, who int) (prio int, err error) { return } +func libc_getpriority_trampoline() + +//go:linkname libc_getpriority libc_getpriority +//go:cgo_import_dynamic libc_getpriority getpriority "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getrlimit(which int, lim *Rlimit) (err error) { - _, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_getrlimit_trampoline), uintptr(which), uintptr(unsafe.Pointer(lim)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_getrlimit_trampoline() + +//go:linkname libc_getrlimit libc_getrlimit +//go:cgo_import_dynamic libc_getrlimit getrlimit "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getrusage(who int, rusage *Rusage) (err error) { - _, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_getrusage_trampoline), uintptr(who), uintptr(unsafe.Pointer(rusage)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_getrusage_trampoline() + +//go:linkname libc_getrusage libc_getrusage +//go:cgo_import_dynamic libc_getrusage getrusage "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getsid(pid int) (sid int, err error) { - r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0) + r0, _, e1 := syscall_rawSyscall(funcPC(libc_getsid_trampoline), uintptr(pid), 0, 0) sid = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -847,26 +1369,41 @@ func Getsid(pid int) (sid int, err error) { return } +func libc_getsid_trampoline() + +//go:linkname libc_getsid libc_getsid +//go:cgo_import_dynamic libc_getsid getsid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getuid() (uid int) { - r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(funcPC(libc_getuid_trampoline), 0, 0, 0) uid = int(r0) return } +func libc_getuid_trampoline() + +//go:linkname libc_getuid libc_getuid +//go:cgo_import_dynamic libc_getuid getuid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Issetugid() (tainted bool) { - r0, _, _ := RawSyscall(SYS_ISSETUGID, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(funcPC(libc_issetugid_trampoline), 0, 0, 0) tainted = bool(r0 != 0) return } +func libc_issetugid_trampoline() + +//go:linkname libc_issetugid libc_issetugid +//go:cgo_import_dynamic libc_issetugid issetugid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Kqueue() (fd int, err error) { - r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0) + r0, _, e1 := syscall_syscall(funcPC(libc_kqueue_trampoline), 0, 0, 0) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -874,6 +1411,11 @@ func Kqueue() (fd int, err error) { return } +func libc_kqueue_trampoline() + +//go:linkname libc_kqueue libc_kqueue +//go:cgo_import_dynamic libc_kqueue kqueue "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Lchown(path string, uid int, gid int) (err error) { @@ -882,13 +1424,18 @@ func Lchown(path string, uid int, gid int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + _, _, e1 := syscall_syscall(funcPC(libc_lchown_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_lchown_trampoline() + +//go:linkname libc_lchown libc_lchown +//go:cgo_import_dynamic libc_lchown lchown "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Link(path string, link string) (err error) { @@ -902,13 +1449,18 @@ func Link(path string, link string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + _, _, e1 := syscall_syscall(funcPC(libc_link_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_link_trampoline() + +//go:linkname libc_link libc_link +//go:cgo_import_dynamic libc_link link "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error) { @@ -922,37 +1474,32 @@ func Linkat(pathfd int, path string, linkfd int, link string, flags int) (err er if err != nil { return } - _, _, e1 := Syscall6(SYS_LINKAT, uintptr(pathfd), uintptr(unsafe.Pointer(_p0)), uintptr(linkfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) + _, _, e1 := syscall_syscall6(funcPC(libc_linkat_trampoline), uintptr(pathfd), uintptr(unsafe.Pointer(_p0)), uintptr(linkfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_linkat_trampoline() + +//go:linkname libc_linkat libc_linkat +//go:cgo_import_dynamic libc_linkat linkat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Listen(s int, backlog int) (err error) { - _, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0) + _, _, e1 := syscall_syscall(funcPC(libc_listen_trampoline), uintptr(s), uintptr(backlog), 0) if e1 != 0 { err = errnoErr(e1) } return } -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func libc_listen_trampoline() -func Lstat(path string, stat *Stat_t) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} +//go:linkname libc_listen libc_listen +//go:cgo_import_dynamic libc_listen listen "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT @@ -962,13 +1509,18 @@ func Mkdir(path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + _, _, e1 := syscall_syscall(funcPC(libc_mkdir_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_mkdir_trampoline() + +//go:linkname libc_mkdir libc_mkdir +//go:cgo_import_dynamic libc_mkdir mkdir "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mkdirat(dirfd int, path string, mode uint32) (err error) { @@ -977,13 +1529,18 @@ func Mkdirat(dirfd int, path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + _, _, e1 := syscall_syscall(funcPC(libc_mkdirat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_mkdirat_trampoline() + +//go:linkname libc_mkdirat libc_mkdirat +//go:cgo_import_dynamic libc_mkdirat mkdirat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mkfifo(path string, mode uint32) (err error) { @@ -992,13 +1549,18 @@ func Mkfifo(path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + _, _, e1 := syscall_syscall(funcPC(libc_mkfifo_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_mkfifo_trampoline() + +//go:linkname libc_mkfifo libc_mkfifo +//go:cgo_import_dynamic libc_mkfifo mkfifo "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mknod(path string, mode uint32, dev int) (err error) { @@ -1007,13 +1569,18 @@ func Mknod(path string, mode uint32, dev int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) + _, _, e1 := syscall_syscall(funcPC(libc_mknod_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_mknod_trampoline() + +//go:linkname libc_mknod libc_mknod +//go:cgo_import_dynamic libc_mknod mknod "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Open(path string, mode int, perm uint32) (fd int, err error) { @@ -1022,7 +1589,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { if err != nil { return } - r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) + r0, _, e1 := syscall_syscall(funcPC(libc_open_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1030,6 +1597,11 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { return } +func libc_open_trampoline() + +//go:linkname libc_open libc_open +//go:cgo_import_dynamic libc_open open "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) { @@ -1038,7 +1610,7 @@ func Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) { if err != nil { return } - r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0) + r0, _, e1 := syscall_syscall6(funcPC(libc_openat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1046,6 +1618,11 @@ func Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) { return } +func libc_openat_trampoline() + +//go:linkname libc_openat libc_openat +//go:cgo_import_dynamic libc_openat openat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Pathconf(path string, name int) (val int, err error) { @@ -1054,7 +1631,7 @@ func Pathconf(path string, name int) (val int, err error) { if err != nil { return } - r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) + r0, _, e1 := syscall_syscall(funcPC(libc_pathconf_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) val = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1062,6 +1639,11 @@ func Pathconf(path string, name int) (val int, err error) { return } +func libc_pathconf_trampoline() + +//go:linkname libc_pathconf libc_pathconf +//go:cgo_import_dynamic libc_pathconf pathconf "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Pread(fd int, p []byte, offset int64) (n int, err error) { @@ -1071,7 +1653,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0) + r0, _, e1 := syscall_syscall6(funcPC(libc_pread_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1079,6 +1661,11 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) { return } +func libc_pread_trampoline() + +//go:linkname libc_pread libc_pread +//go:cgo_import_dynamic libc_pread pread "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Pwrite(fd int, p []byte, offset int64) (n int, err error) { @@ -1088,7 +1675,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0) + r0, _, e1 := syscall_syscall6(funcPC(libc_pwrite_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1096,6 +1683,11 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) { return } +func libc_pwrite_trampoline() + +//go:linkname libc_pwrite libc_pwrite +//go:cgo_import_dynamic libc_pwrite pwrite "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func read(fd int, p []byte) (n int, err error) { @@ -1105,7 +1697,7 @@ func read(fd int, p []byte) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p))) + r0, _, e1 := syscall_syscall(funcPC(libc_read_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1113,6 +1705,11 @@ func read(fd int, p []byte) (n int, err error) { return } +func libc_read_trampoline() + +//go:linkname libc_read libc_read +//go:cgo_import_dynamic libc_read read "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Readlink(path string, buf []byte) (n int, err error) { @@ -1127,7 +1724,7 @@ func Readlink(path string, buf []byte) (n int, err error) { } else { _p1 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) + r0, _, e1 := syscall_syscall(funcPC(libc_readlink_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1135,6 +1732,11 @@ func Readlink(path string, buf []byte) (n int, err error) { return } +func libc_readlink_trampoline() + +//go:linkname libc_readlink libc_readlink +//go:cgo_import_dynamic libc_readlink readlink "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { @@ -1149,7 +1751,7 @@ func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { } else { _p1 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall6(SYS_READLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0) + r0, _, e1 := syscall_syscall6(funcPC(libc_readlinkat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1157,6 +1759,11 @@ func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { return } +func libc_readlinkat_trampoline() + +//go:linkname libc_readlinkat libc_readlinkat +//go:cgo_import_dynamic libc_readlinkat readlinkat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Rename(from string, to string) (err error) { @@ -1170,13 +1777,18 @@ func Rename(from string, to string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + _, _, e1 := syscall_syscall(funcPC(libc_rename_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_rename_trampoline() + +//go:linkname libc_rename libc_rename +//go:cgo_import_dynamic libc_rename rename "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Renameat(fromfd int, from string, tofd int, to string) (err error) { @@ -1190,13 +1802,18 @@ func Renameat(fromfd int, from string, tofd int, to string) (err error) { if err != nil { return } - _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(fromfd), uintptr(unsafe.Pointer(_p0)), uintptr(tofd), uintptr(unsafe.Pointer(_p1)), 0, 0) + _, _, e1 := syscall_syscall6(funcPC(libc_renameat_trampoline), uintptr(fromfd), uintptr(unsafe.Pointer(_p0)), uintptr(tofd), uintptr(unsafe.Pointer(_p1)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_renameat_trampoline() + +//go:linkname libc_renameat libc_renameat +//go:cgo_import_dynamic libc_renameat renameat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Revoke(path string) (err error) { @@ -1205,13 +1822,18 @@ func Revoke(path string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_revoke_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_revoke_trampoline() + +//go:linkname libc_revoke libc_revoke +//go:cgo_import_dynamic libc_revoke revoke "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Rmdir(path string) (err error) { @@ -1220,17 +1842,22 @@ func Rmdir(path string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_rmdir_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_rmdir_trampoline() + +//go:linkname libc_rmdir libc_rmdir +//go:cgo_import_dynamic libc_rmdir rmdir "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { - r0, r1, e1 := Syscall6(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(offset>>32), uintptr(whence), 0, 0) + r0, r1, e1 := syscall_syscall6(funcPC(libc_lseek_trampoline), uintptr(fd), uintptr(offset), uintptr(offset>>32), uintptr(whence), 0, 0) newoffset = int64(int64(r1)<<32 | int64(r0)) if e1 != 0 { err = errnoErr(e1) @@ -1238,46 +1865,71 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { return } +func libc_lseek_trampoline() + +//go:linkname libc_lseek libc_lseek +//go:cgo_import_dynamic libc_lseek lseek "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) { - _, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0) + _, _, e1 := syscall_syscall6(funcPC(libc_select_trampoline), uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_select_trampoline() + +//go:linkname libc_select libc_select +//go:cgo_import_dynamic libc_select select "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setegid(egid int) (err error) { - _, _, e1 := Syscall(SYS_SETEGID, uintptr(egid), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_setegid_trampoline), uintptr(egid), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setegid_trampoline() + +//go:linkname libc_setegid libc_setegid +//go:cgo_import_dynamic libc_setegid setegid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Seteuid(euid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_seteuid_trampoline), uintptr(euid), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_seteuid_trampoline() + +//go:linkname libc_seteuid libc_seteuid +//go:cgo_import_dynamic libc_seteuid seteuid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setgid(gid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_setgid_trampoline), uintptr(gid), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setgid_trampoline() + +//go:linkname libc_setgid libc_setgid +//go:cgo_import_dynamic libc_setgid setgid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setlogin(name string) (err error) { @@ -1286,77 +1938,112 @@ func Setlogin(name string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_setlogin_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setlogin_trampoline() + +//go:linkname libc_setlogin libc_setlogin +//go:cgo_import_dynamic libc_setlogin setlogin "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setpgid(pid int, pgid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_setpgid_trampoline), uintptr(pid), uintptr(pgid), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setpgid_trampoline() + +//go:linkname libc_setpgid libc_setpgid +//go:cgo_import_dynamic libc_setpgid setpgid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setpriority(which int, who int, prio int) (err error) { - _, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio)) + _, _, e1 := syscall_syscall(funcPC(libc_setpriority_trampoline), uintptr(which), uintptr(who), uintptr(prio)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setpriority_trampoline() + +//go:linkname libc_setpriority libc_setpriority +//go:cgo_import_dynamic libc_setpriority setpriority "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setprivexec(flag int) (err error) { - _, _, e1 := Syscall(SYS_SETPRIVEXEC, uintptr(flag), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_setprivexec_trampoline), uintptr(flag), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setprivexec_trampoline() + +//go:linkname libc_setprivexec libc_setprivexec +//go:cgo_import_dynamic libc_setprivexec setprivexec "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setregid(rgid int, egid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_setregid_trampoline), uintptr(rgid), uintptr(egid), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setregid_trampoline() + +//go:linkname libc_setregid libc_setregid +//go:cgo_import_dynamic libc_setregid setregid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setreuid(ruid int, euid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_setreuid_trampoline), uintptr(ruid), uintptr(euid), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setreuid_trampoline() + +//go:linkname libc_setreuid libc_setreuid +//go:cgo_import_dynamic libc_setreuid setreuid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setrlimit(which int, lim *Rlimit) (err error) { - _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_setrlimit_trampoline), uintptr(which), uintptr(unsafe.Pointer(lim)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setrlimit_trampoline() + +//go:linkname libc_setrlimit libc_setrlimit +//go:cgo_import_dynamic libc_setrlimit setrlimit "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setsid() (pid int, err error) { - r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0) + r0, _, e1 := syscall_rawSyscall(funcPC(libc_setsid_trampoline), 0, 0, 0) pid = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1364,55 +2051,40 @@ func Setsid() (pid int, err error) { return } +func libc_setsid_trampoline() + +//go:linkname libc_setsid libc_setsid +//go:cgo_import_dynamic libc_setsid setsid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Settimeofday(tp *Timeval) (err error) { - _, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_settimeofday_trampoline), uintptr(unsafe.Pointer(tp)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_settimeofday_trampoline() + +//go:linkname libc_settimeofday libc_settimeofday +//go:cgo_import_dynamic libc_settimeofday settimeofday "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setuid(uid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_setuid_trampoline), uintptr(uid), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func libc_setuid_trampoline() -func Stat(path string, stat *Stat_t) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Statfs(path string, stat *Statfs_t) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} +//go:linkname libc_setuid libc_setuid +//go:cgo_import_dynamic libc_setuid setuid "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT @@ -1427,13 +2099,18 @@ func Symlink(path string, link string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + _, _, e1 := syscall_syscall(funcPC(libc_symlink_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_symlink_trampoline() + +//go:linkname libc_symlink libc_symlink +//go:cgo_import_dynamic libc_symlink symlink "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) { @@ -1447,23 +2124,33 @@ func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_SYMLINKAT, uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1))) + _, _, e1 := syscall_syscall(funcPC(libc_symlinkat_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1))) if e1 != 0 { err = errnoErr(e1) } return } +func libc_symlinkat_trampoline() + +//go:linkname libc_symlinkat libc_symlinkat +//go:cgo_import_dynamic libc_symlinkat symlinkat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Sync() (err error) { - _, _, e1 := Syscall(SYS_SYNC, 0, 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_sync_trampoline), 0, 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_sync_trampoline() + +//go:linkname libc_sync libc_sync +//go:cgo_import_dynamic libc_sync sync "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Truncate(path string, length int64) (err error) { @@ -1472,21 +2159,31 @@ func Truncate(path string, length int64) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), uintptr(length>>32)) + _, _, e1 := syscall_syscall(funcPC(libc_truncate_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(length), uintptr(length>>32)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_truncate_trampoline() + +//go:linkname libc_truncate libc_truncate +//go:cgo_import_dynamic libc_truncate truncate "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Umask(newmask int) (oldmask int) { - r0, _, _ := Syscall(SYS_UMASK, uintptr(newmask), 0, 0) + r0, _, _ := syscall_syscall(funcPC(libc_umask_trampoline), uintptr(newmask), 0, 0) oldmask = int(r0) return } +func libc_umask_trampoline() + +//go:linkname libc_umask libc_umask +//go:cgo_import_dynamic libc_umask umask "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Undelete(path string) (err error) { @@ -1495,13 +2192,18 @@ func Undelete(path string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_undelete_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_undelete_trampoline() + +//go:linkname libc_undelete libc_undelete +//go:cgo_import_dynamic libc_undelete undelete "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Unlink(path string) (err error) { @@ -1510,13 +2212,18 @@ func Unlink(path string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_unlink_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_unlink_trampoline() + +//go:linkname libc_unlink libc_unlink +//go:cgo_import_dynamic libc_unlink unlink "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Unlinkat(dirfd int, path string, flags int) (err error) { @@ -1525,13 +2232,18 @@ func Unlinkat(dirfd int, path string, flags int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + _, _, e1 := syscall_syscall(funcPC(libc_unlinkat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_unlinkat_trampoline() + +//go:linkname libc_unlinkat libc_unlinkat +//go:cgo_import_dynamic libc_unlinkat unlinkat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Unmount(path string, flags int) (err error) { @@ -1540,13 +2252,18 @@ func Unmount(path string, flags int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + _, _, e1 := syscall_syscall(funcPC(libc_unmount_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_unmount_trampoline() + +//go:linkname libc_unmount libc_unmount +//go:cgo_import_dynamic libc_unmount unmount "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func write(fd int, p []byte) (n int, err error) { @@ -1556,7 +2273,7 @@ func write(fd int, p []byte) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p))) + r0, _, e1 := syscall_syscall(funcPC(libc_write_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1564,10 +2281,15 @@ func write(fd int, p []byte) (n int, err error) { return } +func libc_write_trampoline() + +//go:linkname libc_write libc_write +//go:cgo_import_dynamic libc_write write "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) { - r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos), uintptr(pos>>32), 0, 0) + r0, _, e1 := syscall_syscall9(funcPC(libc_mmap_trampoline), uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos), uintptr(pos>>32), 0, 0) ret = uintptr(r0) if e1 != 0 { err = errnoErr(e1) @@ -1575,20 +2297,30 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) ( return } +func libc_mmap_trampoline() + +//go:linkname libc_mmap libc_mmap +//go:cgo_import_dynamic libc_mmap mmap "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func munmap(addr uintptr, length uintptr) (err error) { - _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0) + _, _, e1 := syscall_syscall(funcPC(libc_munmap_trampoline), uintptr(addr), uintptr(length), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_munmap_trampoline() + +//go:linkname libc_munmap libc_munmap +//go:cgo_import_dynamic libc_munmap munmap "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func readlen(fd int, buf *byte, nbuf int) (n int, err error) { - r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) + r0, _, e1 := syscall_syscall(funcPC(libc_read_trampoline), uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1599,7 +2331,7 @@ func readlen(fd int, buf *byte, nbuf int) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func writelen(fd int, buf *byte, nbuf int) (n int, err error) { - r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) + r0, _, e1 := syscall_syscall(funcPC(libc_write_trampoline), uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1610,7 +2342,7 @@ func writelen(fd int, buf *byte, nbuf int) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func gettimeofday(tp *Timeval) (sec int32, usec int32, err error) { - r0, r1, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0) + r0, r1, e1 := syscall_rawSyscall(funcPC(libc_gettimeofday_trampoline), uintptr(unsafe.Pointer(tp)), 0, 0) sec = int32(r0) usec = int32(r1) if e1 != 0 { @@ -1618,3 +2350,134 @@ func gettimeofday(tp *Timeval) (sec int32, usec int32, err error) { } return } + +func libc_gettimeofday_trampoline() + +//go:linkname libc_gettimeofday libc_gettimeofday +//go:cgo_import_dynamic libc_gettimeofday gettimeofday "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstat(fd int, stat *Stat_t) (err error) { + _, _, e1 := syscall_syscall(funcPC(libc_fstat_trampoline), uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_fstat_trampoline() + +//go:linkname libc_fstat libc_fstat +//go:cgo_import_dynamic libc_fstat fstat "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := syscall_syscall6(funcPC(libc_fstatat_trampoline), uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_fstatat_trampoline() + +//go:linkname libc_fstatat libc_fstatat +//go:cgo_import_dynamic libc_fstatat fstatat "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstatfs(fd int, stat *Statfs_t) (err error) { + _, _, e1 := syscall_syscall(funcPC(libc_fstatfs_trampoline), uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_fstatfs_trampoline() + +//go:linkname libc_fstatfs libc_fstatfs +//go:cgo_import_dynamic libc_fstatfs fstatfs "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) { + r0, _, e1 := syscall_syscall(funcPC(libc_getfsstat_trampoline), uintptr(buf), uintptr(size), uintptr(flags)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_getfsstat_trampoline() + +//go:linkname libc_getfsstat libc_getfsstat +//go:cgo_import_dynamic libc_getfsstat getfsstat "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Lstat(path string, stat *Stat_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := syscall_syscall(funcPC(libc_lstat_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_lstat_trampoline() + +//go:linkname libc_lstat libc_lstat +//go:cgo_import_dynamic libc_lstat lstat "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Stat(path string, stat *Stat_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := syscall_syscall(funcPC(libc_stat_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_stat_trampoline() + +//go:linkname libc_stat libc_stat +//go:cgo_import_dynamic libc_stat stat "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Statfs(path string, stat *Statfs_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := syscall_syscall(funcPC(libc_statfs_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_statfs_trampoline() + +//go:linkname libc_statfs libc_statfs +//go:cgo_import_dynamic libc_statfs statfs "/usr/lib/libSystem.B.dylib" diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.s b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.s new file mode 100644 index 0000000000..994056f359 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.s @@ -0,0 +1,282 @@ +// go run mkasm_darwin.go arm +// Code generated by the command above; DO NOT EDIT. + +// +build go1.12 + +#include "textflag.h" +TEXT ·libc_getgroups_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getgroups(SB) +TEXT ·libc_setgroups_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setgroups(SB) +TEXT ·libc_wait4_trampoline(SB),NOSPLIT,$0-0 + JMP libc_wait4(SB) +TEXT ·libc_accept_trampoline(SB),NOSPLIT,$0-0 + JMP libc_accept(SB) +TEXT ·libc_bind_trampoline(SB),NOSPLIT,$0-0 + JMP libc_bind(SB) +TEXT ·libc_connect_trampoline(SB),NOSPLIT,$0-0 + JMP libc_connect(SB) +TEXT ·libc_socket_trampoline(SB),NOSPLIT,$0-0 + JMP libc_socket(SB) +TEXT ·libc_getsockopt_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getsockopt(SB) +TEXT ·libc_setsockopt_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setsockopt(SB) +TEXT ·libc_getpeername_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getpeername(SB) +TEXT ·libc_getsockname_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getsockname(SB) +TEXT ·libc_shutdown_trampoline(SB),NOSPLIT,$0-0 + JMP libc_shutdown(SB) +TEXT ·libc_socketpair_trampoline(SB),NOSPLIT,$0-0 + JMP libc_socketpair(SB) +TEXT ·libc_recvfrom_trampoline(SB),NOSPLIT,$0-0 + JMP libc_recvfrom(SB) +TEXT ·libc_sendto_trampoline(SB),NOSPLIT,$0-0 + JMP libc_sendto(SB) +TEXT ·libc_recvmsg_trampoline(SB),NOSPLIT,$0-0 + JMP libc_recvmsg(SB) +TEXT ·libc_sendmsg_trampoline(SB),NOSPLIT,$0-0 + JMP libc_sendmsg(SB) +TEXT ·libc_kevent_trampoline(SB),NOSPLIT,$0-0 + JMP libc_kevent(SB) +TEXT ·libc___sysctl_trampoline(SB),NOSPLIT,$0-0 + JMP libc___sysctl(SB) +TEXT ·libc_utimes_trampoline(SB),NOSPLIT,$0-0 + JMP libc_utimes(SB) +TEXT ·libc_futimes_trampoline(SB),NOSPLIT,$0-0 + JMP libc_futimes(SB) +TEXT ·libc_fcntl_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fcntl(SB) +TEXT ·libc_poll_trampoline(SB),NOSPLIT,$0-0 + JMP libc_poll(SB) +TEXT ·libc_madvise_trampoline(SB),NOSPLIT,$0-0 + JMP libc_madvise(SB) +TEXT ·libc_mlock_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mlock(SB) +TEXT ·libc_mlockall_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mlockall(SB) +TEXT ·libc_mprotect_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mprotect(SB) +TEXT ·libc_msync_trampoline(SB),NOSPLIT,$0-0 + JMP libc_msync(SB) +TEXT ·libc_munlock_trampoline(SB),NOSPLIT,$0-0 + JMP libc_munlock(SB) +TEXT ·libc_munlockall_trampoline(SB),NOSPLIT,$0-0 + JMP libc_munlockall(SB) +TEXT ·libc_ptrace_trampoline(SB),NOSPLIT,$0-0 + JMP libc_ptrace(SB) +TEXT ·libc_getattrlist_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getattrlist(SB) +TEXT ·libc_pipe_trampoline(SB),NOSPLIT,$0-0 + JMP libc_pipe(SB) +TEXT ·libc_getxattr_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getxattr(SB) +TEXT ·libc_fgetxattr_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fgetxattr(SB) +TEXT ·libc_setxattr_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setxattr(SB) +TEXT ·libc_fsetxattr_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fsetxattr(SB) +TEXT ·libc_removexattr_trampoline(SB),NOSPLIT,$0-0 + JMP libc_removexattr(SB) +TEXT ·libc_fremovexattr_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fremovexattr(SB) +TEXT ·libc_listxattr_trampoline(SB),NOSPLIT,$0-0 + JMP libc_listxattr(SB) +TEXT ·libc_flistxattr_trampoline(SB),NOSPLIT,$0-0 + JMP libc_flistxattr(SB) +TEXT ·libc_setattrlist_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setattrlist(SB) +TEXT ·libc_kill_trampoline(SB),NOSPLIT,$0-0 + JMP libc_kill(SB) +TEXT ·libc_ioctl_trampoline(SB),NOSPLIT,$0-0 + JMP libc_ioctl(SB) +TEXT ·libc_sendfile_trampoline(SB),NOSPLIT,$0-0 + JMP libc_sendfile(SB) +TEXT ·libc_access_trampoline(SB),NOSPLIT,$0-0 + JMP libc_access(SB) +TEXT ·libc_adjtime_trampoline(SB),NOSPLIT,$0-0 + JMP libc_adjtime(SB) +TEXT ·libc_chdir_trampoline(SB),NOSPLIT,$0-0 + JMP libc_chdir(SB) +TEXT ·libc_chflags_trampoline(SB),NOSPLIT,$0-0 + JMP libc_chflags(SB) +TEXT ·libc_chmod_trampoline(SB),NOSPLIT,$0-0 + JMP libc_chmod(SB) +TEXT ·libc_chown_trampoline(SB),NOSPLIT,$0-0 + JMP libc_chown(SB) +TEXT ·libc_chroot_trampoline(SB),NOSPLIT,$0-0 + JMP libc_chroot(SB) +TEXT ·libc_close_trampoline(SB),NOSPLIT,$0-0 + JMP libc_close(SB) +TEXT ·libc_dup_trampoline(SB),NOSPLIT,$0-0 + JMP libc_dup(SB) +TEXT ·libc_dup2_trampoline(SB),NOSPLIT,$0-0 + JMP libc_dup2(SB) +TEXT ·libc_exchangedata_trampoline(SB),NOSPLIT,$0-0 + JMP libc_exchangedata(SB) +TEXT ·libc_exit_trampoline(SB),NOSPLIT,$0-0 + JMP libc_exit(SB) +TEXT ·libc_faccessat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_faccessat(SB) +TEXT ·libc_fchdir_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fchdir(SB) +TEXT ·libc_fchflags_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fchflags(SB) +TEXT ·libc_fchmod_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fchmod(SB) +TEXT ·libc_fchmodat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fchmodat(SB) +TEXT ·libc_fchown_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fchown(SB) +TEXT ·libc_fchownat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fchownat(SB) +TEXT ·libc_flock_trampoline(SB),NOSPLIT,$0-0 + JMP libc_flock(SB) +TEXT ·libc_fpathconf_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fpathconf(SB) +TEXT ·libc_fsync_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fsync(SB) +TEXT ·libc_ftruncate_trampoline(SB),NOSPLIT,$0-0 + JMP libc_ftruncate(SB) +TEXT ·libc_getdtablesize_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getdtablesize(SB) +TEXT ·libc_getegid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getegid(SB) +TEXT ·libc_geteuid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_geteuid(SB) +TEXT ·libc_getgid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getgid(SB) +TEXT ·libc_getpgid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getpgid(SB) +TEXT ·libc_getpgrp_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getpgrp(SB) +TEXT ·libc_getpid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getpid(SB) +TEXT ·libc_getppid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getppid(SB) +TEXT ·libc_getpriority_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getpriority(SB) +TEXT ·libc_getrlimit_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getrlimit(SB) +TEXT ·libc_getrusage_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getrusage(SB) +TEXT ·libc_getsid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getsid(SB) +TEXT ·libc_getuid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getuid(SB) +TEXT ·libc_issetugid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_issetugid(SB) +TEXT ·libc_kqueue_trampoline(SB),NOSPLIT,$0-0 + JMP libc_kqueue(SB) +TEXT ·libc_lchown_trampoline(SB),NOSPLIT,$0-0 + JMP libc_lchown(SB) +TEXT ·libc_link_trampoline(SB),NOSPLIT,$0-0 + JMP libc_link(SB) +TEXT ·libc_linkat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_linkat(SB) +TEXT ·libc_listen_trampoline(SB),NOSPLIT,$0-0 + JMP libc_listen(SB) +TEXT ·libc_mkdir_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mkdir(SB) +TEXT ·libc_mkdirat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mkdirat(SB) +TEXT ·libc_mkfifo_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mkfifo(SB) +TEXT ·libc_mknod_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mknod(SB) +TEXT ·libc_open_trampoline(SB),NOSPLIT,$0-0 + JMP libc_open(SB) +TEXT ·libc_openat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_openat(SB) +TEXT ·libc_pathconf_trampoline(SB),NOSPLIT,$0-0 + JMP libc_pathconf(SB) +TEXT ·libc_pread_trampoline(SB),NOSPLIT,$0-0 + JMP libc_pread(SB) +TEXT ·libc_pwrite_trampoline(SB),NOSPLIT,$0-0 + JMP libc_pwrite(SB) +TEXT ·libc_read_trampoline(SB),NOSPLIT,$0-0 + JMP libc_read(SB) +TEXT ·libc_readlink_trampoline(SB),NOSPLIT,$0-0 + JMP libc_readlink(SB) +TEXT ·libc_readlinkat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_readlinkat(SB) +TEXT ·libc_rename_trampoline(SB),NOSPLIT,$0-0 + JMP libc_rename(SB) +TEXT ·libc_renameat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_renameat(SB) +TEXT ·libc_revoke_trampoline(SB),NOSPLIT,$0-0 + JMP libc_revoke(SB) +TEXT ·libc_rmdir_trampoline(SB),NOSPLIT,$0-0 + JMP libc_rmdir(SB) +TEXT ·libc_lseek_trampoline(SB),NOSPLIT,$0-0 + JMP libc_lseek(SB) +TEXT ·libc_select_trampoline(SB),NOSPLIT,$0-0 + JMP libc_select(SB) +TEXT ·libc_setegid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setegid(SB) +TEXT ·libc_seteuid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_seteuid(SB) +TEXT ·libc_setgid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setgid(SB) +TEXT ·libc_setlogin_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setlogin(SB) +TEXT ·libc_setpgid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setpgid(SB) +TEXT ·libc_setpriority_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setpriority(SB) +TEXT ·libc_setprivexec_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setprivexec(SB) +TEXT ·libc_setregid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setregid(SB) +TEXT ·libc_setreuid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setreuid(SB) +TEXT ·libc_setrlimit_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setrlimit(SB) +TEXT ·libc_setsid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setsid(SB) +TEXT ·libc_settimeofday_trampoline(SB),NOSPLIT,$0-0 + JMP libc_settimeofday(SB) +TEXT ·libc_setuid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setuid(SB) +TEXT ·libc_symlink_trampoline(SB),NOSPLIT,$0-0 + JMP libc_symlink(SB) +TEXT ·libc_symlinkat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_symlinkat(SB) +TEXT ·libc_sync_trampoline(SB),NOSPLIT,$0-0 + JMP libc_sync(SB) +TEXT ·libc_truncate_trampoline(SB),NOSPLIT,$0-0 + JMP libc_truncate(SB) +TEXT ·libc_umask_trampoline(SB),NOSPLIT,$0-0 + JMP libc_umask(SB) +TEXT ·libc_undelete_trampoline(SB),NOSPLIT,$0-0 + JMP libc_undelete(SB) +TEXT ·libc_unlink_trampoline(SB),NOSPLIT,$0-0 + JMP libc_unlink(SB) +TEXT ·libc_unlinkat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_unlinkat(SB) +TEXT ·libc_unmount_trampoline(SB),NOSPLIT,$0-0 + JMP libc_unmount(SB) +TEXT ·libc_write_trampoline(SB),NOSPLIT,$0-0 + JMP libc_write(SB) +TEXT ·libc_mmap_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mmap(SB) +TEXT ·libc_munmap_trampoline(SB),NOSPLIT,$0-0 + JMP libc_munmap(SB) +TEXT ·libc_gettimeofday_trampoline(SB),NOSPLIT,$0-0 + JMP libc_gettimeofday(SB) +TEXT ·libc_fstat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fstat(SB) +TEXT ·libc_fstatat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fstatat(SB) +TEXT ·libc_fstatfs_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fstatfs(SB) +TEXT ·libc_getfsstat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getfsstat(SB) +TEXT ·libc_lstat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_lstat(SB) +TEXT ·libc_stat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_stat(SB) +TEXT ·libc_statfs_trampoline(SB),NOSPLIT,$0-0 + JMP libc_statfs(SB) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.1_11.go b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.1_11.go new file mode 100644 index 0000000000..3fd0f3c854 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.1_11.go @@ -0,0 +1,1793 @@ +// go run mksyscall.go -tags darwin,arm64,!go1.12 syscall_bsd.go syscall_darwin.go syscall_darwin_arm64.go +// Code generated by the command above; see README.md. DO NOT EDIT. + +// +build darwin,arm64,!go1.12 + +package unix + +import ( + "syscall" + "unsafe" +) + +var _ syscall.Errno + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getgroups(ngid int, gid *_Gid_t) (n int, err error) { + r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setgroups(ngid int, gid *_Gid_t) (err error) { + _, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) { + r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0) + wpid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { + r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { + _, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { + _, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func socket(domain int, typ int, proto int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto)) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) { + _, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) { + _, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { + _, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { + _, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Shutdown(s int, how int) (err error) { + _, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) { + _, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) { + r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) { + r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) { + r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) { + var _p0 unsafe.Pointer + if len(mib) > 0 { + _p0 = unsafe.Pointer(&mib[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func utimes(path string, timeval *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func futimes(fd int, timeval *[2]Timeval) (err error) { + _, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fcntl(fd int, cmd int, arg int) (val int, err error) { + r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg)) + val = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { + r0, _, e1 := Syscall(SYS_POLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Madvise(b []byte, behav int) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(behav)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mlock(b []byte) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mlockall(flags int) (err error) { + _, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mprotect(b []byte, prot int) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Msync(b []byte, flags int) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MSYNC, uintptr(_p0), uintptr(len(b)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Munlock(b []byte) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Munlockall() (err error) { + _, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) { + _, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error) { + _, _, e1 := Syscall6(SYS_GETATTRLIST, uintptr(unsafe.Pointer(path)), uintptr(list), uintptr(buf), uintptr(size), uintptr(options), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func pipe() (r int, w int, err error) { + r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0) + r = int(r0) + w = int(r1) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getxattr(path string, attr string, dest *byte, size int, position uint32, options int) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(position), uintptr(options)) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fgetxattr(fd int, attr string, dest *byte, size int, position uint32, options int) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_FGETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(position), uintptr(options)) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setxattr(path string, attr string, data *byte, size int, position uint32, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(data)), uintptr(size), uintptr(position), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fsetxattr(fd int, attr string, data *byte, size int, position uint32, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FSETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(data)), uintptr(size), uintptr(position), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func removexattr(path string, attr string, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_REMOVEXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fremovexattr(fd int, attr string, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FREMOVEXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func listxattr(path string, dest *byte, size int, options int) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_LISTXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(options), 0, 0) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func flistxattr(fd int, dest *byte, size int, options int) (sz int, err error) { + r0, _, e1 := Syscall6(SYS_FLISTXATTR, uintptr(fd), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(options), 0, 0) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error) { + _, _, e1 := Syscall6(SYS_SETATTRLIST, uintptr(unsafe.Pointer(path)), uintptr(list), uintptr(buf), uintptr(size), uintptr(options), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func kill(pid int, signum int, posix int) (err error) { + _, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), uintptr(posix)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ioctl(fd int, req uint, arg uintptr) (err error) { + _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) { + _, _, e1 := Syscall6(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(offset), uintptr(unsafe.Pointer(len)), uintptr(hdtr), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Access(path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Adjtime(delta *Timeval, olddelta *Timeval) (err error) { + _, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chdir(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chflags(path string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chmod(path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chown(path string, uid int, gid int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chroot(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Close(fd int) (err error) { + _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Dup(fd int) (nfd int, err error) { + r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0) + nfd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Dup2(from int, to int) (err error) { + _, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Exchangedata(path1 string, path2 string, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path1) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(path2) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_EXCHANGEDATA, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Exit(code int) { + Syscall(SYS_EXIT, uintptr(code), 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchdir(fd int) (err error) { + _, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchflags(fd int, flags int) (err error) { + _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchmod(fd int, mode uint32) (err error) { + _, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchown(fd int, uid int, gid int) (err error) { + _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Flock(fd int, how int) (err error) { + _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fpathconf(fd int, name int) (val int, err error) { + r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0) + val = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fsync(fd int) (err error) { + _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Ftruncate(fd int, length int64) (err error) { + _, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getdtablesize() (size int) { + r0, _, _ := Syscall(SYS_GETDTABLESIZE, 0, 0, 0) + size = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getegid() (egid int) { + r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0) + egid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Geteuid() (uid int) { + r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0) + uid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getgid() (gid int) { + r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0) + gid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpgid(pid int) (pgid int, err error) { + r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0) + pgid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpgrp() (pgrp int) { + r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0) + pgrp = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpid() (pid int) { + r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0) + pid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getppid() (ppid int) { + r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0) + ppid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpriority(which int, who int) (prio int, err error) { + r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0) + prio = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getrlimit(which int, lim *Rlimit) (err error) { + _, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getrusage(who int, rusage *Rusage) (err error) { + _, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getsid(pid int) (sid int, err error) { + r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0) + sid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getuid() (uid int) { + r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0) + uid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Issetugid() (tainted bool) { + r0, _, _ := RawSyscall(SYS_ISSETUGID, 0, 0, 0) + tainted = bool(r0 != 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Kqueue() (fd int, err error) { + r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Lchown(path string, uid int, gid int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Link(path string, link string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(link) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(link) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_LINKAT, uintptr(pathfd), uintptr(unsafe.Pointer(_p0)), uintptr(linkfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Listen(s int, backlog int) (err error) { + _, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mkdir(path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mkdirat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mkfifo(path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mknod(path string, mode uint32, dev int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Open(path string, mode int, perm uint32) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pathconf(path string, name int) (val int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) + val = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pread(fd int, p []byte, offset int64) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pwrite(fd int, p []byte, offset int64) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func read(fd int, p []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Readlink(path string, buf []byte) (n int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(buf) > 0 { + _p1 = unsafe.Pointer(&buf[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(buf) > 0 { + _p1 = unsafe.Pointer(&buf[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_READLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Rename(from string, to string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(from) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(to) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Renameat(fromfd int, from string, tofd int, to string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(from) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(to) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(fromfd), uintptr(unsafe.Pointer(_p0)), uintptr(tofd), uintptr(unsafe.Pointer(_p1)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Revoke(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Rmdir(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { + r0, _, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence)) + newoffset = int64(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) { + _, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setegid(egid int) (err error) { + _, _, e1 := Syscall(SYS_SETEGID, uintptr(egid), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Seteuid(euid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setgid(gid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setlogin(name string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(name) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setpgid(pid int, pgid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setpriority(which int, who int, prio int) (err error) { + _, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setprivexec(flag int) (err error) { + _, _, e1 := Syscall(SYS_SETPRIVEXEC, uintptr(flag), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setregid(rgid int, egid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setreuid(ruid int, euid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setrlimit(which int, lim *Rlimit) (err error) { + _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setsid() (pid int, err error) { + r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0) + pid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Settimeofday(tp *Timeval) (err error) { + _, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setuid(uid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Symlink(path string, link string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(link) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_SYMLINKAT, uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Sync() (err error) { + _, _, e1 := Syscall(SYS_SYNC, 0, 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Truncate(path string, length int64) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Umask(newmask int) (oldmask int) { + r0, _, _ := Syscall(SYS_UMASK, uintptr(newmask), 0, 0) + oldmask = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Undelete(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Unlink(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Unlinkat(dirfd int, path string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Unmount(path string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func write(fd int, p []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) { + r0, _, e1 := Syscall6(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos)) + ret = uintptr(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func munmap(addr uintptr, length uintptr) (err error) { + _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func readlen(fd int, buf *byte, nbuf int) (n int, err error) { + r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func writelen(fd int, buf *byte, nbuf int) (n int, err error) { + r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func gettimeofday(tp *Timeval) (sec int64, usec int32, err error) { + r0, r1, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0) + sec = int64(r0) + usec = int32(r1) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstat(fd int, stat *Stat_t) (err error) { + _, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FSTATAT, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstatfs(fd int, stat *Statfs_t) (err error) { + _, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) { + r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(buf), uintptr(size), uintptr(flags)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Lstat(path string, stat *Stat_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Stat(path string, stat *Stat_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Statfs(path string, stat *Statfs_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go index ca6a7ea8b7..8f2691deea 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go @@ -1,7 +1,7 @@ -// mksyscall.pl -tags darwin,arm64 syscall_bsd.go syscall_darwin.go syscall_darwin_arm64.go +// go run mksyscall.go -tags darwin,arm64,go1.12 syscall_bsd.go syscall_darwin.go syscall_darwin_arm64.go // Code generated by the command above; see README.md. DO NOT EDIT. -// +build darwin,arm64 +// +build darwin,arm64,go1.12 package unix @@ -15,7 +15,7 @@ var _ syscall.Errno // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getgroups(ngid int, gid *_Gid_t) (n int, err error) { - r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) + r0, _, e1 := syscall_rawSyscall(funcPC(libc_getgroups_trampoline), uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -23,20 +23,30 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) { return } +func libc_getgroups_trampoline() + +//go:linkname libc_getgroups libc_getgroups +//go:cgo_import_dynamic libc_getgroups getgroups "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func setgroups(ngid int, gid *_Gid_t) (err error) { - _, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_setgroups_trampoline), uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setgroups_trampoline() + +//go:linkname libc_setgroups libc_setgroups +//go:cgo_import_dynamic libc_setgroups setgroups "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) { - r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0) + r0, _, e1 := syscall_syscall6(funcPC(libc_wait4_trampoline), uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0) wpid = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -44,10 +54,15 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err return } +func libc_wait4_trampoline() + +//go:linkname libc_wait4 libc_wait4 +//go:cgo_import_dynamic libc_wait4 wait4 "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { - r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + r0, _, e1 := syscall_syscall(funcPC(libc_accept_trampoline), uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -55,30 +70,45 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { return } +func libc_accept_trampoline() + +//go:linkname libc_accept libc_accept +//go:cgo_import_dynamic libc_accept accept "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { - _, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen)) + _, _, e1 := syscall_syscall(funcPC(libc_bind_trampoline), uintptr(s), uintptr(addr), uintptr(addrlen)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_bind_trampoline() + +//go:linkname libc_bind libc_bind +//go:cgo_import_dynamic libc_bind bind "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { - _, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen)) + _, _, e1 := syscall_syscall(funcPC(libc_connect_trampoline), uintptr(s), uintptr(addr), uintptr(addrlen)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_connect_trampoline() + +//go:linkname libc_connect libc_connect +//go:cgo_import_dynamic libc_connect connect "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func socket(domain int, typ int, proto int) (fd int, err error) { - r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto)) + r0, _, e1 := syscall_rawSyscall(funcPC(libc_socket_trampoline), uintptr(domain), uintptr(typ), uintptr(proto)) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -86,66 +116,101 @@ func socket(domain int, typ int, proto int) (fd int, err error) { return } +func libc_socket_trampoline() + +//go:linkname libc_socket libc_socket +//go:cgo_import_dynamic libc_socket socket "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) { - _, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0) + _, _, e1 := syscall_syscall6(funcPC(libc_getsockopt_trampoline), uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_getsockopt_trampoline() + +//go:linkname libc_getsockopt libc_getsockopt +//go:cgo_import_dynamic libc_getsockopt getsockopt "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) { - _, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0) + _, _, e1 := syscall_syscall6(funcPC(libc_setsockopt_trampoline), uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setsockopt_trampoline() + +//go:linkname libc_setsockopt libc_setsockopt +//go:cgo_import_dynamic libc_setsockopt setsockopt "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { - _, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + _, _, e1 := syscall_rawSyscall(funcPC(libc_getpeername_trampoline), uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) if e1 != 0 { err = errnoErr(e1) } return } +func libc_getpeername_trampoline() + +//go:linkname libc_getpeername libc_getpeername +//go:cgo_import_dynamic libc_getpeername getpeername "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { - _, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + _, _, e1 := syscall_rawSyscall(funcPC(libc_getsockname_trampoline), uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) if e1 != 0 { err = errnoErr(e1) } return } +func libc_getsockname_trampoline() + +//go:linkname libc_getsockname libc_getsockname +//go:cgo_import_dynamic libc_getsockname getsockname "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Shutdown(s int, how int) (err error) { - _, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0) + _, _, e1 := syscall_syscall(funcPC(libc_shutdown_trampoline), uintptr(s), uintptr(how), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_shutdown_trampoline() + +//go:linkname libc_shutdown libc_shutdown +//go:cgo_import_dynamic libc_shutdown shutdown "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) { - _, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0) + _, _, e1 := syscall_rawSyscall6(funcPC(libc_socketpair_trampoline), uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_socketpair_trampoline() + +//go:linkname libc_socketpair libc_socketpair +//go:cgo_import_dynamic libc_socketpair socketpair "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) { @@ -155,7 +220,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen))) + r0, _, e1 := syscall_syscall6(funcPC(libc_recvfrom_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -163,6 +228,11 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl return } +func libc_recvfrom_trampoline() + +//go:linkname libc_recvfrom libc_recvfrom +//go:cgo_import_dynamic libc_recvfrom recvfrom "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) { @@ -172,17 +242,22 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) ( } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen)) + _, _, e1 := syscall_syscall6(funcPC(libc_sendto_trampoline), uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_sendto_trampoline() + +//go:linkname libc_sendto libc_sendto +//go:cgo_import_dynamic libc_sendto sendto "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) { - r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + r0, _, e1 := syscall_syscall(funcPC(libc_recvmsg_trampoline), uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -190,10 +265,15 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) { return } +func libc_recvmsg_trampoline() + +//go:linkname libc_recvmsg libc_recvmsg +//go:cgo_import_dynamic libc_recvmsg recvmsg "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) { - r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + r0, _, e1 := syscall_syscall(funcPC(libc_sendmsg_trampoline), uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -201,10 +281,15 @@ func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) { return } +func libc_sendmsg_trampoline() + +//go:linkname libc_sendmsg libc_sendmsg +//go:cgo_import_dynamic libc_sendmsg sendmsg "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) { - r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout))) + r0, _, e1 := syscall_syscall6(funcPC(libc_kevent_trampoline), uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -212,6 +297,11 @@ func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, ne return } +func libc_kevent_trampoline() + +//go:linkname libc_kevent libc_kevent +//go:cgo_import_dynamic libc_kevent kevent "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) { @@ -221,13 +311,18 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) + _, _, e1 := syscall_syscall6(funcPC(libc___sysctl_trampoline), uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) if e1 != 0 { err = errnoErr(e1) } return } +func libc___sysctl_trampoline() + +//go:linkname libc___sysctl libc___sysctl +//go:cgo_import_dynamic libc___sysctl __sysctl "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func utimes(path string, timeval *[2]Timeval) (err error) { @@ -236,27 +331,37 @@ func utimes(path string, timeval *[2]Timeval) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) + _, _, e1 := syscall_syscall(funcPC(libc_utimes_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_utimes_trampoline() + +//go:linkname libc_utimes libc_utimes +//go:cgo_import_dynamic libc_utimes utimes "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func futimes(fd int, timeval *[2]Timeval) (err error) { - _, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0) + _, _, e1 := syscall_syscall(funcPC(libc_futimes_trampoline), uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_futimes_trampoline() + +//go:linkname libc_futimes libc_futimes +//go:cgo_import_dynamic libc_futimes futimes "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func fcntl(fd int, cmd int, arg int) (val int, err error) { - r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg)) + r0, _, e1 := syscall_syscall(funcPC(libc_fcntl_trampoline), uintptr(fd), uintptr(cmd), uintptr(arg)) val = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -264,10 +369,15 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) { return } +func libc_fcntl_trampoline() + +//go:linkname libc_fcntl libc_fcntl +//go:cgo_import_dynamic libc_fcntl fcntl "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { - r0, _, e1 := Syscall(SYS_POLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout)) + r0, _, e1 := syscall_syscall(funcPC(libc_poll_trampoline), uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -275,6 +385,11 @@ func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { return } +func libc_poll_trampoline() + +//go:linkname libc_poll libc_poll +//go:cgo_import_dynamic libc_poll poll "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Madvise(b []byte, behav int) (err error) { @@ -284,13 +399,18 @@ func Madvise(b []byte, behav int) (err error) { } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(behav)) + _, _, e1 := syscall_syscall(funcPC(libc_madvise_trampoline), uintptr(_p0), uintptr(len(b)), uintptr(behav)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_madvise_trampoline() + +//go:linkname libc_madvise libc_madvise +//go:cgo_import_dynamic libc_madvise madvise "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mlock(b []byte) (err error) { @@ -300,23 +420,33 @@ func Mlock(b []byte) (err error) { } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0) + _, _, e1 := syscall_syscall(funcPC(libc_mlock_trampoline), uintptr(_p0), uintptr(len(b)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_mlock_trampoline() + +//go:linkname libc_mlock libc_mlock +//go:cgo_import_dynamic libc_mlock mlock "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mlockall(flags int) (err error) { - _, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_mlockall_trampoline), uintptr(flags), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_mlockall_trampoline() + +//go:linkname libc_mlockall libc_mlockall +//go:cgo_import_dynamic libc_mlockall mlockall "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mprotect(b []byte, prot int) (err error) { @@ -326,13 +456,18 @@ func Mprotect(b []byte, prot int) (err error) { } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot)) + _, _, e1 := syscall_syscall(funcPC(libc_mprotect_trampoline), uintptr(_p0), uintptr(len(b)), uintptr(prot)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_mprotect_trampoline() + +//go:linkname libc_mprotect libc_mprotect +//go:cgo_import_dynamic libc_mprotect mprotect "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Msync(b []byte, flags int) (err error) { @@ -342,13 +477,18 @@ func Msync(b []byte, flags int) (err error) { } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall(SYS_MSYNC, uintptr(_p0), uintptr(len(b)), uintptr(flags)) + _, _, e1 := syscall_syscall(funcPC(libc_msync_trampoline), uintptr(_p0), uintptr(len(b)), uintptr(flags)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_msync_trampoline() + +//go:linkname libc_msync libc_msync +//go:cgo_import_dynamic libc_msync msync "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Munlock(b []byte) (err error) { @@ -358,37 +498,67 @@ func Munlock(b []byte) (err error) { } else { _p0 = unsafe.Pointer(&_zero) } - _, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0) + _, _, e1 := syscall_syscall(funcPC(libc_munlock_trampoline), uintptr(_p0), uintptr(len(b)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_munlock_trampoline() + +//go:linkname libc_munlock libc_munlock +//go:cgo_import_dynamic libc_munlock munlock "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Munlockall() (err error) { - _, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_munlockall_trampoline), 0, 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_munlockall_trampoline() + +//go:linkname libc_munlockall libc_munlockall +//go:cgo_import_dynamic libc_munlockall munlockall "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) { - _, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0) + _, _, e1 := syscall_syscall6(funcPC(libc_ptrace_trampoline), uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_ptrace_trampoline() + +//go:linkname libc_ptrace libc_ptrace +//go:cgo_import_dynamic libc_ptrace ptrace "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error) { + _, _, e1 := syscall_syscall6(funcPC(libc_getattrlist_trampoline), uintptr(unsafe.Pointer(path)), uintptr(list), uintptr(buf), uintptr(size), uintptr(options), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_getattrlist_trampoline() + +//go:linkname libc_getattrlist libc_getattrlist +//go:cgo_import_dynamic libc_getattrlist getattrlist "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func pipe() (r int, w int, err error) { - r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0) + r0, r1, e1 := syscall_rawSyscall(funcPC(libc_pipe_trampoline), 0, 0, 0) r = int(r0) w = int(r1) if e1 != 0 { @@ -397,26 +567,245 @@ func pipe() (r int, w int, err error) { return } +func libc_pipe_trampoline() + +//go:linkname libc_pipe libc_pipe +//go:cgo_import_dynamic libc_pipe pipe "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func kill(pid int, signum int, posix int) (err error) { - _, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), uintptr(posix)) +func getxattr(path string, attr string, dest *byte, size int, position uint32, options int) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + r0, _, e1 := syscall_syscall6(funcPC(libc_getxattr_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(position), uintptr(options)) + sz = int(r0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_getxattr_trampoline() + +//go:linkname libc_getxattr libc_getxattr +//go:cgo_import_dynamic libc_getxattr getxattr "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fgetxattr(fd int, attr string, dest *byte, size int, position uint32, options int) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + r0, _, e1 := syscall_syscall6(funcPC(libc_fgetxattr_trampoline), uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(position), uintptr(options)) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_fgetxattr_trampoline() + +//go:linkname libc_fgetxattr libc_fgetxattr +//go:cgo_import_dynamic libc_fgetxattr fgetxattr "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setxattr(path string, attr string, data *byte, size int, position uint32, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := syscall_syscall6(funcPC(libc_setxattr_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(data)), uintptr(size), uintptr(position), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_setxattr_trampoline() + +//go:linkname libc_setxattr libc_setxattr +//go:cgo_import_dynamic libc_setxattr setxattr "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fsetxattr(fd int, attr string, data *byte, size int, position uint32, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := syscall_syscall6(funcPC(libc_fsetxattr_trampoline), uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(data)), uintptr(size), uintptr(position), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_fsetxattr_trampoline() + +//go:linkname libc_fsetxattr libc_fsetxattr +//go:cgo_import_dynamic libc_fsetxattr fsetxattr "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func removexattr(path string, attr string, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := syscall_syscall(funcPC(libc_removexattr_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_removexattr_trampoline() + +//go:linkname libc_removexattr libc_removexattr +//go:cgo_import_dynamic libc_removexattr removexattr "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fremovexattr(fd int, attr string, options int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := syscall_syscall(funcPC(libc_fremovexattr_trampoline), uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(options)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_fremovexattr_trampoline() + +//go:linkname libc_fremovexattr libc_fremovexattr +//go:cgo_import_dynamic libc_fremovexattr fremovexattr "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func listxattr(path string, dest *byte, size int, options int) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := syscall_syscall6(funcPC(libc_listxattr_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(options), 0, 0) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_listxattr_trampoline() + +//go:linkname libc_listxattr libc_listxattr +//go:cgo_import_dynamic libc_listxattr listxattr "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func flistxattr(fd int, dest *byte, size int, options int) (sz int, err error) { + r0, _, e1 := syscall_syscall6(funcPC(libc_flistxattr_trampoline), uintptr(fd), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(options), 0, 0) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_flistxattr_trampoline() + +//go:linkname libc_flistxattr libc_flistxattr +//go:cgo_import_dynamic libc_flistxattr flistxattr "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error) { + _, _, e1 := syscall_syscall6(funcPC(libc_setattrlist_trampoline), uintptr(unsafe.Pointer(path)), uintptr(list), uintptr(buf), uintptr(size), uintptr(options), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_setattrlist_trampoline() + +//go:linkname libc_setattrlist libc_setattrlist +//go:cgo_import_dynamic libc_setattrlist setattrlist "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func kill(pid int, signum int, posix int) (err error) { + _, _, e1 := syscall_syscall(funcPC(libc_kill_trampoline), uintptr(pid), uintptr(signum), uintptr(posix)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_kill_trampoline() + +//go:linkname libc_kill libc_kill +//go:cgo_import_dynamic libc_kill kill "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func ioctl(fd int, req uint, arg uintptr) (err error) { - _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg)) + _, _, e1 := syscall_syscall(funcPC(libc_ioctl_trampoline), uintptr(fd), uintptr(req), uintptr(arg)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_ioctl_trampoline() + +//go:linkname libc_ioctl libc_ioctl +//go:cgo_import_dynamic libc_ioctl ioctl "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) { + _, _, e1 := syscall_syscall6(funcPC(libc_sendfile_trampoline), uintptr(infd), uintptr(outfd), uintptr(offset), uintptr(unsafe.Pointer(len)), uintptr(hdtr), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_sendfile_trampoline() + +//go:linkname libc_sendfile libc_sendfile +//go:cgo_import_dynamic libc_sendfile sendfile "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Access(path string, mode uint32) (err error) { @@ -425,23 +814,33 @@ func Access(path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + _, _, e1 := syscall_syscall(funcPC(libc_access_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_access_trampoline() + +//go:linkname libc_access libc_access +//go:cgo_import_dynamic libc_access access "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Adjtime(delta *Timeval, olddelta *Timeval) (err error) { - _, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0) + _, _, e1 := syscall_syscall(funcPC(libc_adjtime_trampoline), uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_adjtime_trampoline() + +//go:linkname libc_adjtime libc_adjtime +//go:cgo_import_dynamic libc_adjtime adjtime "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Chdir(path string) (err error) { @@ -450,13 +849,18 @@ func Chdir(path string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_chdir_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_chdir_trampoline() + +//go:linkname libc_chdir libc_chdir +//go:cgo_import_dynamic libc_chdir chdir "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Chflags(path string, flags int) (err error) { @@ -465,13 +869,18 @@ func Chflags(path string, flags int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + _, _, e1 := syscall_syscall(funcPC(libc_chflags_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_chflags_trampoline() + +//go:linkname libc_chflags libc_chflags +//go:cgo_import_dynamic libc_chflags chflags "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Chmod(path string, mode uint32) (err error) { @@ -480,13 +889,18 @@ func Chmod(path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + _, _, e1 := syscall_syscall(funcPC(libc_chmod_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_chmod_trampoline() + +//go:linkname libc_chmod libc_chmod +//go:cgo_import_dynamic libc_chmod chmod "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Chown(path string, uid int, gid int) (err error) { @@ -495,13 +909,18 @@ func Chown(path string, uid int, gid int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + _, _, e1 := syscall_syscall(funcPC(libc_chown_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_chown_trampoline() + +//go:linkname libc_chown libc_chown +//go:cgo_import_dynamic libc_chown chown "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Chroot(path string) (err error) { @@ -510,27 +929,37 @@ func Chroot(path string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_chroot_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_chroot_trampoline() + +//go:linkname libc_chroot libc_chroot +//go:cgo_import_dynamic libc_chroot chroot "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Close(fd int) (err error) { - _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_close_trampoline), uintptr(fd), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_close_trampoline() + +//go:linkname libc_close libc_close +//go:cgo_import_dynamic libc_close close "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Dup(fd int) (nfd int, err error) { - r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0) + r0, _, e1 := syscall_syscall(funcPC(libc_dup_trampoline), uintptr(fd), 0, 0) nfd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -538,16 +967,26 @@ func Dup(fd int) (nfd int, err error) { return } +func libc_dup_trampoline() + +//go:linkname libc_dup libc_dup +//go:cgo_import_dynamic libc_dup dup "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Dup2(from int, to int) (err error) { - _, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0) + _, _, e1 := syscall_syscall(funcPC(libc_dup2_trampoline), uintptr(from), uintptr(to), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_dup2_trampoline() + +//go:linkname libc_dup2 libc_dup2 +//go:cgo_import_dynamic libc_dup2 dup2 "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Exchangedata(path1 string, path2 string, options int) (err error) { @@ -561,20 +1000,30 @@ func Exchangedata(path1 string, path2 string, options int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_EXCHANGEDATA, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) + _, _, e1 := syscall_syscall(funcPC(libc_exchangedata_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_exchangedata_trampoline() + +//go:linkname libc_exchangedata libc_exchangedata +//go:cgo_import_dynamic libc_exchangedata exchangedata "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Exit(code int) { - Syscall(SYS_EXIT, uintptr(code), 0, 0) + syscall_syscall(funcPC(libc_exit_trampoline), uintptr(code), 0, 0) return } +func libc_exit_trampoline() + +//go:linkname libc_exit libc_exit +//go:cgo_import_dynamic libc_exit exit "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { @@ -583,43 +1032,63 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { if err != nil { return } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + _, _, e1 := syscall_syscall6(funcPC(libc_faccessat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_faccessat_trampoline() + +//go:linkname libc_faccessat libc_faccessat +//go:cgo_import_dynamic libc_faccessat faccessat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchdir(fd int) (err error) { - _, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_fchdir_trampoline), uintptr(fd), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_fchdir_trampoline() + +//go:linkname libc_fchdir libc_fchdir +//go:cgo_import_dynamic libc_fchdir fchdir "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchflags(fd int, flags int) (err error) { - _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0) + _, _, e1 := syscall_syscall(funcPC(libc_fchflags_trampoline), uintptr(fd), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_fchflags_trampoline() + +//go:linkname libc_fchflags libc_fchflags +//go:cgo_import_dynamic libc_fchflags fchflags "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchmod(fd int, mode uint32) (err error) { - _, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0) + _, _, e1 := syscall_syscall(funcPC(libc_fchmod_trampoline), uintptr(fd), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_fchmod_trampoline() + +//go:linkname libc_fchmod libc_fchmod +//go:cgo_import_dynamic libc_fchmod fchmod "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { @@ -628,23 +1097,33 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { if err != nil { return } - _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + _, _, e1 := syscall_syscall6(funcPC(libc_fchmodat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_fchmodat_trampoline() + +//go:linkname libc_fchmodat libc_fchmodat +//go:cgo_import_dynamic libc_fchmodat fchmodat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchown(fd int, uid int, gid int) (err error) { - _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)) + _, _, e1 := syscall_syscall(funcPC(libc_fchown_trampoline), uintptr(fd), uintptr(uid), uintptr(gid)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_fchown_trampoline() + +//go:linkname libc_fchown libc_fchown +//go:cgo_import_dynamic libc_fchown fchown "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { @@ -653,27 +1132,37 @@ func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { if err != nil { return } - _, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0) + _, _, e1 := syscall_syscall6(funcPC(libc_fchownat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_fchownat_trampoline() + +//go:linkname libc_fchownat libc_fchownat +//go:cgo_import_dynamic libc_fchownat fchownat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Flock(fd int, how int) (err error) { - _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0) + _, _, e1 := syscall_syscall(funcPC(libc_flock_trampoline), uintptr(fd), uintptr(how), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_flock_trampoline() + +//go:linkname libc_flock libc_flock +//go:cgo_import_dynamic libc_flock flock "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fpathconf(fd int, name int) (val int, err error) { - r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0) + r0, _, e1 := syscall_syscall(funcPC(libc_fpathconf_trampoline), uintptr(fd), uintptr(name), 0) val = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -681,99 +1170,97 @@ func Fpathconf(fd int, name int) (val int, err error) { return } -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func libc_fpathconf_trampoline() -func Fstat(fd int, stat *Stat_t) (err error) { - _, _, e1 := Syscall(SYS_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Fstatfs(fd int, stat *Statfs_t) (err error) { - _, _, e1 := Syscall(SYS_FSTATFS64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} +//go:linkname libc_fpathconf libc_fpathconf +//go:cgo_import_dynamic libc_fpathconf fpathconf "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Fsync(fd int) (err error) { - _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_fsync_trampoline), uintptr(fd), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_fsync_trampoline() + +//go:linkname libc_fsync libc_fsync +//go:cgo_import_dynamic libc_fsync fsync "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Ftruncate(fd int, length int64) (err error) { - _, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), 0) + _, _, e1 := syscall_syscall(funcPC(libc_ftruncate_trampoline), uintptr(fd), uintptr(length), 0) if e1 != 0 { err = errnoErr(e1) } return } -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func libc_ftruncate_trampoline() -func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { - var _p0 unsafe.Pointer - if len(buf) > 0 { - _p0 = unsafe.Pointer(&buf[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall6(SYS_GETDIRENTRIES64, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} +//go:linkname libc_ftruncate libc_ftruncate +//go:cgo_import_dynamic libc_ftruncate ftruncate "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getdtablesize() (size int) { - r0, _, _ := Syscall(SYS_GETDTABLESIZE, 0, 0, 0) + r0, _, _ := syscall_syscall(funcPC(libc_getdtablesize_trampoline), 0, 0, 0) size = int(r0) return } +func libc_getdtablesize_trampoline() + +//go:linkname libc_getdtablesize libc_getdtablesize +//go:cgo_import_dynamic libc_getdtablesize getdtablesize "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getegid() (egid int) { - r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(funcPC(libc_getegid_trampoline), 0, 0, 0) egid = int(r0) return } +func libc_getegid_trampoline() + +//go:linkname libc_getegid libc_getegid +//go:cgo_import_dynamic libc_getegid getegid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Geteuid() (uid int) { - r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(funcPC(libc_geteuid_trampoline), 0, 0, 0) uid = int(r0) return } +func libc_geteuid_trampoline() + +//go:linkname libc_geteuid libc_geteuid +//go:cgo_import_dynamic libc_geteuid geteuid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getgid() (gid int) { - r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(funcPC(libc_getgid_trampoline), 0, 0, 0) gid = int(r0) return } +func libc_getgid_trampoline() + +//go:linkname libc_getgid libc_getgid +//go:cgo_import_dynamic libc_getgid getgid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpgid(pid int) (pgid int, err error) { - r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0) + r0, _, e1 := syscall_rawSyscall(funcPC(libc_getpgid_trampoline), uintptr(pid), 0, 0) pgid = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -781,34 +1268,54 @@ func Getpgid(pid int) (pgid int, err error) { return } +func libc_getpgid_trampoline() + +//go:linkname libc_getpgid libc_getpgid +//go:cgo_import_dynamic libc_getpgid getpgid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpgrp() (pgrp int) { - r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(funcPC(libc_getpgrp_trampoline), 0, 0, 0) pgrp = int(r0) return } +func libc_getpgrp_trampoline() + +//go:linkname libc_getpgrp libc_getpgrp +//go:cgo_import_dynamic libc_getpgrp getpgrp "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpid() (pid int) { - r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(funcPC(libc_getpid_trampoline), 0, 0, 0) pid = int(r0) return } +func libc_getpid_trampoline() + +//go:linkname libc_getpid libc_getpid +//go:cgo_import_dynamic libc_getpid getpid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getppid() (ppid int) { - r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(funcPC(libc_getppid_trampoline), 0, 0, 0) ppid = int(r0) return } +func libc_getppid_trampoline() + +//go:linkname libc_getppid libc_getppid +//go:cgo_import_dynamic libc_getppid getppid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpriority(which int, who int) (prio int, err error) { - r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0) + r0, _, e1 := syscall_syscall(funcPC(libc_getpriority_trampoline), uintptr(which), uintptr(who), 0) prio = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -816,30 +1323,45 @@ func Getpriority(which int, who int) (prio int, err error) { return } +func libc_getpriority_trampoline() + +//go:linkname libc_getpriority libc_getpriority +//go:cgo_import_dynamic libc_getpriority getpriority "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getrlimit(which int, lim *Rlimit) (err error) { - _, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_getrlimit_trampoline), uintptr(which), uintptr(unsafe.Pointer(lim)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_getrlimit_trampoline() + +//go:linkname libc_getrlimit libc_getrlimit +//go:cgo_import_dynamic libc_getrlimit getrlimit "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getrusage(who int, rusage *Rusage) (err error) { - _, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_getrusage_trampoline), uintptr(who), uintptr(unsafe.Pointer(rusage)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_getrusage_trampoline() + +//go:linkname libc_getrusage libc_getrusage +//go:cgo_import_dynamic libc_getrusage getrusage "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getsid(pid int) (sid int, err error) { - r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0) + r0, _, e1 := syscall_rawSyscall(funcPC(libc_getsid_trampoline), uintptr(pid), 0, 0) sid = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -847,26 +1369,41 @@ func Getsid(pid int) (sid int, err error) { return } +func libc_getsid_trampoline() + +//go:linkname libc_getsid libc_getsid +//go:cgo_import_dynamic libc_getsid getsid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getuid() (uid int) { - r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(funcPC(libc_getuid_trampoline), 0, 0, 0) uid = int(r0) return } +func libc_getuid_trampoline() + +//go:linkname libc_getuid libc_getuid +//go:cgo_import_dynamic libc_getuid getuid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Issetugid() (tainted bool) { - r0, _, _ := RawSyscall(SYS_ISSETUGID, 0, 0, 0) + r0, _, _ := syscall_rawSyscall(funcPC(libc_issetugid_trampoline), 0, 0, 0) tainted = bool(r0 != 0) return } +func libc_issetugid_trampoline() + +//go:linkname libc_issetugid libc_issetugid +//go:cgo_import_dynamic libc_issetugid issetugid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Kqueue() (fd int, err error) { - r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0) + r0, _, e1 := syscall_syscall(funcPC(libc_kqueue_trampoline), 0, 0, 0) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -874,6 +1411,11 @@ func Kqueue() (fd int, err error) { return } +func libc_kqueue_trampoline() + +//go:linkname libc_kqueue libc_kqueue +//go:cgo_import_dynamic libc_kqueue kqueue "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Lchown(path string, uid int, gid int) (err error) { @@ -882,13 +1424,18 @@ func Lchown(path string, uid int, gid int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + _, _, e1 := syscall_syscall(funcPC(libc_lchown_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_lchown_trampoline() + +//go:linkname libc_lchown libc_lchown +//go:cgo_import_dynamic libc_lchown lchown "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Link(path string, link string) (err error) { @@ -902,13 +1449,18 @@ func Link(path string, link string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + _, _, e1 := syscall_syscall(funcPC(libc_link_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_link_trampoline() + +//go:linkname libc_link libc_link +//go:cgo_import_dynamic libc_link link "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error) { @@ -922,37 +1474,32 @@ func Linkat(pathfd int, path string, linkfd int, link string, flags int) (err er if err != nil { return } - _, _, e1 := Syscall6(SYS_LINKAT, uintptr(pathfd), uintptr(unsafe.Pointer(_p0)), uintptr(linkfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) + _, _, e1 := syscall_syscall6(funcPC(libc_linkat_trampoline), uintptr(pathfd), uintptr(unsafe.Pointer(_p0)), uintptr(linkfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_linkat_trampoline() + +//go:linkname libc_linkat libc_linkat +//go:cgo_import_dynamic libc_linkat linkat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Listen(s int, backlog int) (err error) { - _, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0) + _, _, e1 := syscall_syscall(funcPC(libc_listen_trampoline), uintptr(s), uintptr(backlog), 0) if e1 != 0 { err = errnoErr(e1) } return } -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func libc_listen_trampoline() -func Lstat(path string, stat *Stat_t) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} +//go:linkname libc_listen libc_listen +//go:cgo_import_dynamic libc_listen listen "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT @@ -962,13 +1509,18 @@ func Mkdir(path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + _, _, e1 := syscall_syscall(funcPC(libc_mkdir_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_mkdir_trampoline() + +//go:linkname libc_mkdir libc_mkdir +//go:cgo_import_dynamic libc_mkdir mkdir "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mkdirat(dirfd int, path string, mode uint32) (err error) { @@ -977,13 +1529,18 @@ func Mkdirat(dirfd int, path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + _, _, e1 := syscall_syscall(funcPC(libc_mkdirat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_mkdirat_trampoline() + +//go:linkname libc_mkdirat libc_mkdirat +//go:cgo_import_dynamic libc_mkdirat mkdirat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mkfifo(path string, mode uint32) (err error) { @@ -992,13 +1549,18 @@ func Mkfifo(path string, mode uint32) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + _, _, e1 := syscall_syscall(funcPC(libc_mkfifo_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_mkfifo_trampoline() + +//go:linkname libc_mkfifo libc_mkfifo +//go:cgo_import_dynamic libc_mkfifo mkfifo "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Mknod(path string, mode uint32, dev int) (err error) { @@ -1007,13 +1569,18 @@ func Mknod(path string, mode uint32, dev int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) + _, _, e1 := syscall_syscall(funcPC(libc_mknod_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_mknod_trampoline() + +//go:linkname libc_mknod libc_mknod +//go:cgo_import_dynamic libc_mknod mknod "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Open(path string, mode int, perm uint32) (fd int, err error) { @@ -1022,7 +1589,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { if err != nil { return } - r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) + r0, _, e1 := syscall_syscall(funcPC(libc_open_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1030,6 +1597,11 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { return } +func libc_open_trampoline() + +//go:linkname libc_open libc_open +//go:cgo_import_dynamic libc_open open "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) { @@ -1038,7 +1610,7 @@ func Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) { if err != nil { return } - r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0) + r0, _, e1 := syscall_syscall6(funcPC(libc_openat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0) fd = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1046,6 +1618,11 @@ func Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) { return } +func libc_openat_trampoline() + +//go:linkname libc_openat libc_openat +//go:cgo_import_dynamic libc_openat openat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Pathconf(path string, name int) (val int, err error) { @@ -1054,7 +1631,7 @@ func Pathconf(path string, name int) (val int, err error) { if err != nil { return } - r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) + r0, _, e1 := syscall_syscall(funcPC(libc_pathconf_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) val = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1062,6 +1639,11 @@ func Pathconf(path string, name int) (val int, err error) { return } +func libc_pathconf_trampoline() + +//go:linkname libc_pathconf libc_pathconf +//go:cgo_import_dynamic libc_pathconf pathconf "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Pread(fd int, p []byte, offset int64) (n int, err error) { @@ -1071,7 +1653,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0) + r0, _, e1 := syscall_syscall6(funcPC(libc_pread_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1079,6 +1661,11 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) { return } +func libc_pread_trampoline() + +//go:linkname libc_pread libc_pread +//go:cgo_import_dynamic libc_pread pread "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Pwrite(fd int, p []byte, offset int64) (n int, err error) { @@ -1088,7 +1675,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0) + r0, _, e1 := syscall_syscall6(funcPC(libc_pwrite_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1096,6 +1683,11 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) { return } +func libc_pwrite_trampoline() + +//go:linkname libc_pwrite libc_pwrite +//go:cgo_import_dynamic libc_pwrite pwrite "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func read(fd int, p []byte) (n int, err error) { @@ -1105,7 +1697,7 @@ func read(fd int, p []byte) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p))) + r0, _, e1 := syscall_syscall(funcPC(libc_read_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1113,6 +1705,11 @@ func read(fd int, p []byte) (n int, err error) { return } +func libc_read_trampoline() + +//go:linkname libc_read libc_read +//go:cgo_import_dynamic libc_read read "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Readlink(path string, buf []byte) (n int, err error) { @@ -1127,7 +1724,7 @@ func Readlink(path string, buf []byte) (n int, err error) { } else { _p1 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) + r0, _, e1 := syscall_syscall(funcPC(libc_readlink_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1135,6 +1732,11 @@ func Readlink(path string, buf []byte) (n int, err error) { return } +func libc_readlink_trampoline() + +//go:linkname libc_readlink libc_readlink +//go:cgo_import_dynamic libc_readlink readlink "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { @@ -1149,7 +1751,7 @@ func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { } else { _p1 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall6(SYS_READLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0) + r0, _, e1 := syscall_syscall6(funcPC(libc_readlinkat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1157,6 +1759,11 @@ func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { return } +func libc_readlinkat_trampoline() + +//go:linkname libc_readlinkat libc_readlinkat +//go:cgo_import_dynamic libc_readlinkat readlinkat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Rename(from string, to string) (err error) { @@ -1170,13 +1777,18 @@ func Rename(from string, to string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + _, _, e1 := syscall_syscall(funcPC(libc_rename_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_rename_trampoline() + +//go:linkname libc_rename libc_rename +//go:cgo_import_dynamic libc_rename rename "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Renameat(fromfd int, from string, tofd int, to string) (err error) { @@ -1190,13 +1802,18 @@ func Renameat(fromfd int, from string, tofd int, to string) (err error) { if err != nil { return } - _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(fromfd), uintptr(unsafe.Pointer(_p0)), uintptr(tofd), uintptr(unsafe.Pointer(_p1)), 0, 0) + _, _, e1 := syscall_syscall6(funcPC(libc_renameat_trampoline), uintptr(fromfd), uintptr(unsafe.Pointer(_p0)), uintptr(tofd), uintptr(unsafe.Pointer(_p1)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_renameat_trampoline() + +//go:linkname libc_renameat libc_renameat +//go:cgo_import_dynamic libc_renameat renameat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Revoke(path string) (err error) { @@ -1205,13 +1822,18 @@ func Revoke(path string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_revoke_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_revoke_trampoline() + +//go:linkname libc_revoke libc_revoke +//go:cgo_import_dynamic libc_revoke revoke "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Rmdir(path string) (err error) { @@ -1220,17 +1842,22 @@ func Rmdir(path string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_rmdir_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_rmdir_trampoline() + +//go:linkname libc_rmdir libc_rmdir +//go:cgo_import_dynamic libc_rmdir rmdir "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { - r0, _, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence)) + r0, _, e1 := syscall_syscall(funcPC(libc_lseek_trampoline), uintptr(fd), uintptr(offset), uintptr(whence)) newoffset = int64(r0) if e1 != 0 { err = errnoErr(e1) @@ -1238,46 +1865,71 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { return } +func libc_lseek_trampoline() + +//go:linkname libc_lseek libc_lseek +//go:cgo_import_dynamic libc_lseek lseek "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) { - _, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0) + _, _, e1 := syscall_syscall6(funcPC(libc_select_trampoline), uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_select_trampoline() + +//go:linkname libc_select libc_select +//go:cgo_import_dynamic libc_select select "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setegid(egid int) (err error) { - _, _, e1 := Syscall(SYS_SETEGID, uintptr(egid), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_setegid_trampoline), uintptr(egid), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setegid_trampoline() + +//go:linkname libc_setegid libc_setegid +//go:cgo_import_dynamic libc_setegid setegid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Seteuid(euid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_seteuid_trampoline), uintptr(euid), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_seteuid_trampoline() + +//go:linkname libc_seteuid libc_seteuid +//go:cgo_import_dynamic libc_seteuid seteuid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setgid(gid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_setgid_trampoline), uintptr(gid), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setgid_trampoline() + +//go:linkname libc_setgid libc_setgid +//go:cgo_import_dynamic libc_setgid setgid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setlogin(name string) (err error) { @@ -1286,77 +1938,112 @@ func Setlogin(name string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_setlogin_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setlogin_trampoline() + +//go:linkname libc_setlogin libc_setlogin +//go:cgo_import_dynamic libc_setlogin setlogin "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setpgid(pid int, pgid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_setpgid_trampoline), uintptr(pid), uintptr(pgid), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setpgid_trampoline() + +//go:linkname libc_setpgid libc_setpgid +//go:cgo_import_dynamic libc_setpgid setpgid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setpriority(which int, who int, prio int) (err error) { - _, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio)) + _, _, e1 := syscall_syscall(funcPC(libc_setpriority_trampoline), uintptr(which), uintptr(who), uintptr(prio)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setpriority_trampoline() + +//go:linkname libc_setpriority libc_setpriority +//go:cgo_import_dynamic libc_setpriority setpriority "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setprivexec(flag int) (err error) { - _, _, e1 := Syscall(SYS_SETPRIVEXEC, uintptr(flag), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_setprivexec_trampoline), uintptr(flag), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setprivexec_trampoline() + +//go:linkname libc_setprivexec libc_setprivexec +//go:cgo_import_dynamic libc_setprivexec setprivexec "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setregid(rgid int, egid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_setregid_trampoline), uintptr(rgid), uintptr(egid), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setregid_trampoline() + +//go:linkname libc_setregid libc_setregid +//go:cgo_import_dynamic libc_setregid setregid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setreuid(ruid int, euid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_setreuid_trampoline), uintptr(ruid), uintptr(euid), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setreuid_trampoline() + +//go:linkname libc_setreuid libc_setreuid +//go:cgo_import_dynamic libc_setreuid setreuid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setrlimit(which int, lim *Rlimit) (err error) { - _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_setrlimit_trampoline), uintptr(which), uintptr(unsafe.Pointer(lim)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_setrlimit_trampoline() + +//go:linkname libc_setrlimit libc_setrlimit +//go:cgo_import_dynamic libc_setrlimit setrlimit "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setsid() (pid int, err error) { - r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0) + r0, _, e1 := syscall_rawSyscall(funcPC(libc_setsid_trampoline), 0, 0, 0) pid = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1364,55 +2051,40 @@ func Setsid() (pid int, err error) { return } +func libc_setsid_trampoline() + +//go:linkname libc_setsid libc_setsid +//go:cgo_import_dynamic libc_setsid setsid "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Settimeofday(tp *Timeval) (err error) { - _, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_settimeofday_trampoline), uintptr(unsafe.Pointer(tp)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_settimeofday_trampoline() + +//go:linkname libc_settimeofday libc_settimeofday +//go:cgo_import_dynamic libc_settimeofday settimeofday "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Setuid(uid int) (err error) { - _, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0) + _, _, e1 := syscall_rawSyscall(funcPC(libc_setuid_trampoline), uintptr(uid), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func libc_setuid_trampoline() -func Stat(path string, stat *Stat_t) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Statfs(path string, stat *Statfs_t) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} +//go:linkname libc_setuid libc_setuid +//go:cgo_import_dynamic libc_setuid setuid "/usr/lib/libSystem.B.dylib" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT @@ -1427,13 +2099,18 @@ func Symlink(path string, link string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + _, _, e1 := syscall_syscall(funcPC(libc_symlink_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_symlink_trampoline() + +//go:linkname libc_symlink libc_symlink +//go:cgo_import_dynamic libc_symlink symlink "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) { @@ -1447,23 +2124,33 @@ func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_SYMLINKAT, uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1))) + _, _, e1 := syscall_syscall(funcPC(libc_symlinkat_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1))) if e1 != 0 { err = errnoErr(e1) } return } +func libc_symlinkat_trampoline() + +//go:linkname libc_symlinkat libc_symlinkat +//go:cgo_import_dynamic libc_symlinkat symlinkat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Sync() (err error) { - _, _, e1 := Syscall(SYS_SYNC, 0, 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_sync_trampoline), 0, 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_sync_trampoline() + +//go:linkname libc_sync libc_sync +//go:cgo_import_dynamic libc_sync sync "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Truncate(path string, length int64) (err error) { @@ -1472,21 +2159,31 @@ func Truncate(path string, length int64) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0) + _, _, e1 := syscall_syscall(funcPC(libc_truncate_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(length), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_truncate_trampoline() + +//go:linkname libc_truncate libc_truncate +//go:cgo_import_dynamic libc_truncate truncate "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Umask(newmask int) (oldmask int) { - r0, _, _ := Syscall(SYS_UMASK, uintptr(newmask), 0, 0) + r0, _, _ := syscall_syscall(funcPC(libc_umask_trampoline), uintptr(newmask), 0, 0) oldmask = int(r0) return } +func libc_umask_trampoline() + +//go:linkname libc_umask libc_umask +//go:cgo_import_dynamic libc_umask umask "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Undelete(path string) (err error) { @@ -1495,13 +2192,18 @@ func Undelete(path string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_undelete_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_undelete_trampoline() + +//go:linkname libc_undelete libc_undelete +//go:cgo_import_dynamic libc_undelete undelete "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Unlink(path string) (err error) { @@ -1510,13 +2212,18 @@ func Unlink(path string) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0) + _, _, e1 := syscall_syscall(funcPC(libc_unlink_trampoline), uintptr(unsafe.Pointer(_p0)), 0, 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_unlink_trampoline() + +//go:linkname libc_unlink libc_unlink +//go:cgo_import_dynamic libc_unlink unlink "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Unlinkat(dirfd int, path string, flags int) (err error) { @@ -1525,13 +2232,18 @@ func Unlinkat(dirfd int, path string, flags int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + _, _, e1 := syscall_syscall(funcPC(libc_unlinkat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) if e1 != 0 { err = errnoErr(e1) } return } +func libc_unlinkat_trampoline() + +//go:linkname libc_unlinkat libc_unlinkat +//go:cgo_import_dynamic libc_unlinkat unlinkat "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Unmount(path string, flags int) (err error) { @@ -1540,13 +2252,18 @@ func Unmount(path string, flags int) (err error) { if err != nil { return } - _, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + _, _, e1 := syscall_syscall(funcPC(libc_unmount_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_unmount_trampoline() + +//go:linkname libc_unmount libc_unmount +//go:cgo_import_dynamic libc_unmount unmount "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func write(fd int, p []byte) (n int, err error) { @@ -1556,7 +2273,7 @@ func write(fd int, p []byte) (n int, err error) { } else { _p0 = unsafe.Pointer(&_zero) } - r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p))) + r0, _, e1 := syscall_syscall(funcPC(libc_write_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p))) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1564,10 +2281,15 @@ func write(fd int, p []byte) (n int, err error) { return } +func libc_write_trampoline() + +//go:linkname libc_write libc_write +//go:cgo_import_dynamic libc_write write "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) { - r0, _, e1 := Syscall6(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos)) + r0, _, e1 := syscall_syscall6(funcPC(libc_mmap_trampoline), uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos)) ret = uintptr(r0) if e1 != 0 { err = errnoErr(e1) @@ -1575,20 +2297,30 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) ( return } +func libc_mmap_trampoline() + +//go:linkname libc_mmap libc_mmap +//go:cgo_import_dynamic libc_mmap mmap "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func munmap(addr uintptr, length uintptr) (err error) { - _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0) + _, _, e1 := syscall_syscall(funcPC(libc_munmap_trampoline), uintptr(addr), uintptr(length), 0) if e1 != 0 { err = errnoErr(e1) } return } +func libc_munmap_trampoline() + +//go:linkname libc_munmap libc_munmap +//go:cgo_import_dynamic libc_munmap munmap "/usr/lib/libSystem.B.dylib" + // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func readlen(fd int, buf *byte, nbuf int) (n int, err error) { - r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) + r0, _, e1 := syscall_syscall(funcPC(libc_read_trampoline), uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1599,7 +2331,7 @@ func readlen(fd int, buf *byte, nbuf int) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func writelen(fd int, buf *byte, nbuf int) (n int, err error) { - r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) + r0, _, e1 := syscall_syscall(funcPC(libc_write_trampoline), uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) n = int(r0) if e1 != 0 { err = errnoErr(e1) @@ -1610,7 +2342,7 @@ func writelen(fd int, buf *byte, nbuf int) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func gettimeofday(tp *Timeval) (sec int64, usec int32, err error) { - r0, r1, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0) + r0, r1, e1 := syscall_rawSyscall(funcPC(libc_gettimeofday_trampoline), uintptr(unsafe.Pointer(tp)), 0, 0) sec = int64(r0) usec = int32(r1) if e1 != 0 { @@ -1618,3 +2350,134 @@ func gettimeofday(tp *Timeval) (sec int64, usec int32, err error) { } return } + +func libc_gettimeofday_trampoline() + +//go:linkname libc_gettimeofday libc_gettimeofday +//go:cgo_import_dynamic libc_gettimeofday gettimeofday "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstat(fd int, stat *Stat_t) (err error) { + _, _, e1 := syscall_syscall(funcPC(libc_fstat_trampoline), uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_fstat_trampoline() + +//go:linkname libc_fstat libc_fstat +//go:cgo_import_dynamic libc_fstat fstat "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := syscall_syscall6(funcPC(libc_fstatat_trampoline), uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_fstatat_trampoline() + +//go:linkname libc_fstatat libc_fstatat +//go:cgo_import_dynamic libc_fstatat fstatat "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstatfs(fd int, stat *Statfs_t) (err error) { + _, _, e1 := syscall_syscall(funcPC(libc_fstatfs_trampoline), uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_fstatfs_trampoline() + +//go:linkname libc_fstatfs libc_fstatfs +//go:cgo_import_dynamic libc_fstatfs fstatfs "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) { + r0, _, e1 := syscall_syscall(funcPC(libc_getfsstat_trampoline), uintptr(buf), uintptr(size), uintptr(flags)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_getfsstat_trampoline() + +//go:linkname libc_getfsstat libc_getfsstat +//go:cgo_import_dynamic libc_getfsstat getfsstat "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Lstat(path string, stat *Stat_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := syscall_syscall(funcPC(libc_lstat_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_lstat_trampoline() + +//go:linkname libc_lstat libc_lstat +//go:cgo_import_dynamic libc_lstat lstat "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Stat(path string, stat *Stat_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := syscall_syscall(funcPC(libc_stat_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_stat_trampoline() + +//go:linkname libc_stat libc_stat +//go:cgo_import_dynamic libc_stat stat "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Statfs(path string, stat *Statfs_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := syscall_syscall(funcPC(libc_statfs_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_statfs_trampoline() + +//go:linkname libc_statfs libc_statfs +//go:cgo_import_dynamic libc_statfs statfs "/usr/lib/libSystem.B.dylib" diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s new file mode 100644 index 0000000000..61dc0d4c12 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s @@ -0,0 +1,282 @@ +// go run mkasm_darwin.go arm64 +// Code generated by the command above; DO NOT EDIT. + +// +build go1.12 + +#include "textflag.h" +TEXT ·libc_getgroups_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getgroups(SB) +TEXT ·libc_setgroups_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setgroups(SB) +TEXT ·libc_wait4_trampoline(SB),NOSPLIT,$0-0 + JMP libc_wait4(SB) +TEXT ·libc_accept_trampoline(SB),NOSPLIT,$0-0 + JMP libc_accept(SB) +TEXT ·libc_bind_trampoline(SB),NOSPLIT,$0-0 + JMP libc_bind(SB) +TEXT ·libc_connect_trampoline(SB),NOSPLIT,$0-0 + JMP libc_connect(SB) +TEXT ·libc_socket_trampoline(SB),NOSPLIT,$0-0 + JMP libc_socket(SB) +TEXT ·libc_getsockopt_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getsockopt(SB) +TEXT ·libc_setsockopt_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setsockopt(SB) +TEXT ·libc_getpeername_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getpeername(SB) +TEXT ·libc_getsockname_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getsockname(SB) +TEXT ·libc_shutdown_trampoline(SB),NOSPLIT,$0-0 + JMP libc_shutdown(SB) +TEXT ·libc_socketpair_trampoline(SB),NOSPLIT,$0-0 + JMP libc_socketpair(SB) +TEXT ·libc_recvfrom_trampoline(SB),NOSPLIT,$0-0 + JMP libc_recvfrom(SB) +TEXT ·libc_sendto_trampoline(SB),NOSPLIT,$0-0 + JMP libc_sendto(SB) +TEXT ·libc_recvmsg_trampoline(SB),NOSPLIT,$0-0 + JMP libc_recvmsg(SB) +TEXT ·libc_sendmsg_trampoline(SB),NOSPLIT,$0-0 + JMP libc_sendmsg(SB) +TEXT ·libc_kevent_trampoline(SB),NOSPLIT,$0-0 + JMP libc_kevent(SB) +TEXT ·libc___sysctl_trampoline(SB),NOSPLIT,$0-0 + JMP libc___sysctl(SB) +TEXT ·libc_utimes_trampoline(SB),NOSPLIT,$0-0 + JMP libc_utimes(SB) +TEXT ·libc_futimes_trampoline(SB),NOSPLIT,$0-0 + JMP libc_futimes(SB) +TEXT ·libc_fcntl_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fcntl(SB) +TEXT ·libc_poll_trampoline(SB),NOSPLIT,$0-0 + JMP libc_poll(SB) +TEXT ·libc_madvise_trampoline(SB),NOSPLIT,$0-0 + JMP libc_madvise(SB) +TEXT ·libc_mlock_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mlock(SB) +TEXT ·libc_mlockall_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mlockall(SB) +TEXT ·libc_mprotect_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mprotect(SB) +TEXT ·libc_msync_trampoline(SB),NOSPLIT,$0-0 + JMP libc_msync(SB) +TEXT ·libc_munlock_trampoline(SB),NOSPLIT,$0-0 + JMP libc_munlock(SB) +TEXT ·libc_munlockall_trampoline(SB),NOSPLIT,$0-0 + JMP libc_munlockall(SB) +TEXT ·libc_ptrace_trampoline(SB),NOSPLIT,$0-0 + JMP libc_ptrace(SB) +TEXT ·libc_getattrlist_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getattrlist(SB) +TEXT ·libc_pipe_trampoline(SB),NOSPLIT,$0-0 + JMP libc_pipe(SB) +TEXT ·libc_getxattr_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getxattr(SB) +TEXT ·libc_fgetxattr_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fgetxattr(SB) +TEXT ·libc_setxattr_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setxattr(SB) +TEXT ·libc_fsetxattr_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fsetxattr(SB) +TEXT ·libc_removexattr_trampoline(SB),NOSPLIT,$0-0 + JMP libc_removexattr(SB) +TEXT ·libc_fremovexattr_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fremovexattr(SB) +TEXT ·libc_listxattr_trampoline(SB),NOSPLIT,$0-0 + JMP libc_listxattr(SB) +TEXT ·libc_flistxattr_trampoline(SB),NOSPLIT,$0-0 + JMP libc_flistxattr(SB) +TEXT ·libc_setattrlist_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setattrlist(SB) +TEXT ·libc_kill_trampoline(SB),NOSPLIT,$0-0 + JMP libc_kill(SB) +TEXT ·libc_ioctl_trampoline(SB),NOSPLIT,$0-0 + JMP libc_ioctl(SB) +TEXT ·libc_sendfile_trampoline(SB),NOSPLIT,$0-0 + JMP libc_sendfile(SB) +TEXT ·libc_access_trampoline(SB),NOSPLIT,$0-0 + JMP libc_access(SB) +TEXT ·libc_adjtime_trampoline(SB),NOSPLIT,$0-0 + JMP libc_adjtime(SB) +TEXT ·libc_chdir_trampoline(SB),NOSPLIT,$0-0 + JMP libc_chdir(SB) +TEXT ·libc_chflags_trampoline(SB),NOSPLIT,$0-0 + JMP libc_chflags(SB) +TEXT ·libc_chmod_trampoline(SB),NOSPLIT,$0-0 + JMP libc_chmod(SB) +TEXT ·libc_chown_trampoline(SB),NOSPLIT,$0-0 + JMP libc_chown(SB) +TEXT ·libc_chroot_trampoline(SB),NOSPLIT,$0-0 + JMP libc_chroot(SB) +TEXT ·libc_close_trampoline(SB),NOSPLIT,$0-0 + JMP libc_close(SB) +TEXT ·libc_dup_trampoline(SB),NOSPLIT,$0-0 + JMP libc_dup(SB) +TEXT ·libc_dup2_trampoline(SB),NOSPLIT,$0-0 + JMP libc_dup2(SB) +TEXT ·libc_exchangedata_trampoline(SB),NOSPLIT,$0-0 + JMP libc_exchangedata(SB) +TEXT ·libc_exit_trampoline(SB),NOSPLIT,$0-0 + JMP libc_exit(SB) +TEXT ·libc_faccessat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_faccessat(SB) +TEXT ·libc_fchdir_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fchdir(SB) +TEXT ·libc_fchflags_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fchflags(SB) +TEXT ·libc_fchmod_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fchmod(SB) +TEXT ·libc_fchmodat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fchmodat(SB) +TEXT ·libc_fchown_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fchown(SB) +TEXT ·libc_fchownat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fchownat(SB) +TEXT ·libc_flock_trampoline(SB),NOSPLIT,$0-0 + JMP libc_flock(SB) +TEXT ·libc_fpathconf_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fpathconf(SB) +TEXT ·libc_fsync_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fsync(SB) +TEXT ·libc_ftruncate_trampoline(SB),NOSPLIT,$0-0 + JMP libc_ftruncate(SB) +TEXT ·libc_getdtablesize_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getdtablesize(SB) +TEXT ·libc_getegid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getegid(SB) +TEXT ·libc_geteuid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_geteuid(SB) +TEXT ·libc_getgid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getgid(SB) +TEXT ·libc_getpgid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getpgid(SB) +TEXT ·libc_getpgrp_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getpgrp(SB) +TEXT ·libc_getpid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getpid(SB) +TEXT ·libc_getppid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getppid(SB) +TEXT ·libc_getpriority_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getpriority(SB) +TEXT ·libc_getrlimit_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getrlimit(SB) +TEXT ·libc_getrusage_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getrusage(SB) +TEXT ·libc_getsid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getsid(SB) +TEXT ·libc_getuid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getuid(SB) +TEXT ·libc_issetugid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_issetugid(SB) +TEXT ·libc_kqueue_trampoline(SB),NOSPLIT,$0-0 + JMP libc_kqueue(SB) +TEXT ·libc_lchown_trampoline(SB),NOSPLIT,$0-0 + JMP libc_lchown(SB) +TEXT ·libc_link_trampoline(SB),NOSPLIT,$0-0 + JMP libc_link(SB) +TEXT ·libc_linkat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_linkat(SB) +TEXT ·libc_listen_trampoline(SB),NOSPLIT,$0-0 + JMP libc_listen(SB) +TEXT ·libc_mkdir_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mkdir(SB) +TEXT ·libc_mkdirat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mkdirat(SB) +TEXT ·libc_mkfifo_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mkfifo(SB) +TEXT ·libc_mknod_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mknod(SB) +TEXT ·libc_open_trampoline(SB),NOSPLIT,$0-0 + JMP libc_open(SB) +TEXT ·libc_openat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_openat(SB) +TEXT ·libc_pathconf_trampoline(SB),NOSPLIT,$0-0 + JMP libc_pathconf(SB) +TEXT ·libc_pread_trampoline(SB),NOSPLIT,$0-0 + JMP libc_pread(SB) +TEXT ·libc_pwrite_trampoline(SB),NOSPLIT,$0-0 + JMP libc_pwrite(SB) +TEXT ·libc_read_trampoline(SB),NOSPLIT,$0-0 + JMP libc_read(SB) +TEXT ·libc_readlink_trampoline(SB),NOSPLIT,$0-0 + JMP libc_readlink(SB) +TEXT ·libc_readlinkat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_readlinkat(SB) +TEXT ·libc_rename_trampoline(SB),NOSPLIT,$0-0 + JMP libc_rename(SB) +TEXT ·libc_renameat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_renameat(SB) +TEXT ·libc_revoke_trampoline(SB),NOSPLIT,$0-0 + JMP libc_revoke(SB) +TEXT ·libc_rmdir_trampoline(SB),NOSPLIT,$0-0 + JMP libc_rmdir(SB) +TEXT ·libc_lseek_trampoline(SB),NOSPLIT,$0-0 + JMP libc_lseek(SB) +TEXT ·libc_select_trampoline(SB),NOSPLIT,$0-0 + JMP libc_select(SB) +TEXT ·libc_setegid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setegid(SB) +TEXT ·libc_seteuid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_seteuid(SB) +TEXT ·libc_setgid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setgid(SB) +TEXT ·libc_setlogin_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setlogin(SB) +TEXT ·libc_setpgid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setpgid(SB) +TEXT ·libc_setpriority_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setpriority(SB) +TEXT ·libc_setprivexec_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setprivexec(SB) +TEXT ·libc_setregid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setregid(SB) +TEXT ·libc_setreuid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setreuid(SB) +TEXT ·libc_setrlimit_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setrlimit(SB) +TEXT ·libc_setsid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setsid(SB) +TEXT ·libc_settimeofday_trampoline(SB),NOSPLIT,$0-0 + JMP libc_settimeofday(SB) +TEXT ·libc_setuid_trampoline(SB),NOSPLIT,$0-0 + JMP libc_setuid(SB) +TEXT ·libc_symlink_trampoline(SB),NOSPLIT,$0-0 + JMP libc_symlink(SB) +TEXT ·libc_symlinkat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_symlinkat(SB) +TEXT ·libc_sync_trampoline(SB),NOSPLIT,$0-0 + JMP libc_sync(SB) +TEXT ·libc_truncate_trampoline(SB),NOSPLIT,$0-0 + JMP libc_truncate(SB) +TEXT ·libc_umask_trampoline(SB),NOSPLIT,$0-0 + JMP libc_umask(SB) +TEXT ·libc_undelete_trampoline(SB),NOSPLIT,$0-0 + JMP libc_undelete(SB) +TEXT ·libc_unlink_trampoline(SB),NOSPLIT,$0-0 + JMP libc_unlink(SB) +TEXT ·libc_unlinkat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_unlinkat(SB) +TEXT ·libc_unmount_trampoline(SB),NOSPLIT,$0-0 + JMP libc_unmount(SB) +TEXT ·libc_write_trampoline(SB),NOSPLIT,$0-0 + JMP libc_write(SB) +TEXT ·libc_mmap_trampoline(SB),NOSPLIT,$0-0 + JMP libc_mmap(SB) +TEXT ·libc_munmap_trampoline(SB),NOSPLIT,$0-0 + JMP libc_munmap(SB) +TEXT ·libc_gettimeofday_trampoline(SB),NOSPLIT,$0-0 + JMP libc_gettimeofday(SB) +TEXT ·libc_fstat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fstat(SB) +TEXT ·libc_fstatat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fstatat(SB) +TEXT ·libc_fstatfs_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fstatfs(SB) +TEXT ·libc_getfsstat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_getfsstat(SB) +TEXT ·libc_lstat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_lstat(SB) +TEXT ·libc_stat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_stat(SB) +TEXT ·libc_statfs_trampoline(SB),NOSPLIT,$0-0 + JMP libc_statfs(SB) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_dragonfly_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_dragonfly_amd64.go index 2ed340fd18..ae9f1a21e6 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_dragonfly_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_dragonfly_amd64.go @@ -1,4 +1,4 @@ -// mksyscall.pl -dragonfly -tags dragonfly,amd64 syscall_bsd.go syscall_dragonfly.go syscall_dragonfly_amd64.go +// go run mksyscall.go -dragonfly -tags dragonfly,amd64 syscall_bsd.go syscall_dragonfly.go syscall_dragonfly_amd64.go // Code generated by the command above; see README.md. DO NOT EDIT. // +build dragonfly,amd64 @@ -423,6 +423,23 @@ func extpwrite(fd int, p []byte, flags int, offset int64) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Getcwd(buf []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS___GETCWD, uintptr(_p0), uintptr(len(buf)), 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func ioctl(fd int, req uint, arg uintptr) (err error) { _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg)) if e1 != 0 { @@ -571,6 +588,21 @@ func Exit(code int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fchdir(fd int) (err error) { _, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0) if e1 != 0 { @@ -601,6 +633,21 @@ func Fchmod(fd int, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fchown(fd int, uid int, gid int) (err error) { _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)) if e1 != 0 { @@ -611,6 +658,21 @@ func Fchown(fd int, uid int, gid int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Flock(fd int, how int) (err error) { _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0) if e1 != 0 { @@ -642,6 +704,21 @@ func Fstat(fd int, stat *Stat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FSTATAT, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fstatfs(fd int, stat *Statfs_t) (err error) { _, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) if e1 != 0 { @@ -880,6 +957,26 @@ func Link(path string, link string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(link) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_LINKAT, uintptr(pathfd), uintptr(unsafe.Pointer(_p0)), uintptr(linkfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Listen(s int, backlog int) (err error) { _, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0) if e1 != 0 { @@ -920,6 +1017,21 @@ func Mkdir(path string, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Mkdirat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Mkfifo(path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -950,6 +1062,21 @@ func Mknod(path string, mode uint32, dev int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Mknodat(fd int, path string, mode uint32, dev int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_MKNODAT, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Nanosleep(time *Timespec, leftover *Timespec) (err error) { _, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0) if e1 != 0 { @@ -976,6 +1103,22 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Pathconf(path string, name int) (val int, err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -1051,6 +1194,26 @@ func Rename(from string, to string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Renameat(fromfd int, from string, tofd int, to string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(from) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(to) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(fromfd), uintptr(unsafe.Pointer(_p0)), uintptr(tofd), uintptr(unsafe.Pointer(_p1)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Revoke(path string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -1298,6 +1461,26 @@ func Symlink(path string, link string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_SYMLINKAT, uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Sync() (err error) { _, _, e1 := Syscall(SYS_SYNC, 0, 0, 0) if e1 != 0 { @@ -1361,6 +1544,21 @@ func Unlink(path string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Unlinkat(dirfd int, path string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Unmount(path string, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_freebsd_386.go b/vendor/golang.org/x/sys/unix/zsyscall_freebsd_386.go index 8bcecfb9b6..80903e47b6 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_freebsd_386.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_freebsd_386.go @@ -1,4 +1,4 @@ -// mksyscall.pl -l32 -tags freebsd,386 syscall_bsd.go syscall_freebsd.go syscall_freebsd_386.go +// go run mksyscall.go -l32 -tags freebsd,386 syscall_bsd.go syscall_freebsd.go syscall_freebsd_386.go // Code generated by the command above; see README.md. DO NOT EDIT. // +build freebsd,386 @@ -377,10 +377,25 @@ func Munlockall() (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func pipe() (r int, w int, err error) { - r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0) - r = int(r0) - w = int(r1) +func pipe2(p *[2]_C_int, flags int) (err error) { + _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getcwd(buf []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS___GETCWD, uintptr(_p0), uintptr(len(buf)), 0) + n = int(r0) if e1 != 0 { err = errnoErr(e1) } @@ -897,7 +912,7 @@ func Fpathconf(fd int, name int) (val int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Fstat(fd int, stat *Stat_t) (err error) { +func fstat(fd int, stat *stat_freebsd11_t) (err error) { _, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) if e1 != 0 { err = errnoErr(e1) @@ -907,7 +922,47 @@ func Fstat(fd int, stat *Stat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Fstatfs(fd int, stat *Statfs_t) (err error) { +func fstat_freebsd12(fd int, stat *Stat_t) (err error) { + _, _, e1 := Syscall(SYS_FSTAT_FREEBSD12, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fstatat(fd int, path string, stat *stat_freebsd11_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FSTATAT, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fstatat_freebsd12(fd int, path string, stat *Stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FSTATAT_FREEBSD12, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fstatfs(fd int, stat *statfs_freebsd11_t) (err error) { _, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) if e1 != 0 { err = errnoErr(e1) @@ -917,6 +972,16 @@ func Fstatfs(fd int, stat *Statfs_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func fstatfs_freebsd12(fd int, stat *Statfs_t) (err error) { + _, _, e1 := Syscall(SYS_FSTATFS_FREEBSD12, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fsync(fd int) (err error) { _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0) if e1 != 0 { @@ -937,7 +1002,7 @@ func Ftruncate(fd int, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { +func getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { _p0 = unsafe.Pointer(&buf[0]) @@ -954,6 +1019,23 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func getdirentries_freebsd12(fd int, buf []byte, basep *uintptr) (n int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_GETDIRENTRIES_FREEBSD12, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Getdtablesize() (size int) { r0, _, _ := Syscall(SYS_GETDTABLESIZE, 0, 0, 0) size = int(r0) @@ -1175,7 +1257,7 @@ func Listen(s int, backlog int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Lstat(path string, stat *Stat_t) (err error) { +func lstat(path string, stat *stat_freebsd11_t) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) if err != nil { @@ -1235,7 +1317,7 @@ func Mkfifo(path string, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Mknod(path string, mode uint32, dev int) (err error) { +func mknod(path string, mode uint32, dev int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) if err != nil { @@ -1250,6 +1332,36 @@ func Mknod(path string, mode uint32, dev int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func mknodat(fd int, path string, mode uint32, dev int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_MKNODAT, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func mknodat_freebsd12(fd int, path string, mode uint32, dev uint64) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_MKNODAT_FREEBSD12, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Nanosleep(time *Timespec, leftover *Timespec) (err error) { _, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0) if e1 != 0 { @@ -1640,7 +1752,7 @@ func Setuid(uid int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Stat(path string, stat *Stat_t) (err error) { +func stat(path string, stat *stat_freebsd11_t) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) if err != nil { @@ -1655,7 +1767,7 @@ func Stat(path string, stat *Stat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Statfs(path string, stat *Statfs_t) (err error) { +func statfs(path string, stat *statfs_freebsd11_t) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) if err != nil { @@ -1670,6 +1782,21 @@ func Statfs(path string, stat *Statfs_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func statfs_freebsd12(path string, stat *Statfs_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_STATFS_FREEBSD12, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Symlink(path string, link string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_freebsd_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_freebsd_amd64.go index 61c0cf99bb..cd250ff0e2 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_freebsd_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_freebsd_amd64.go @@ -1,4 +1,4 @@ -// mksyscall.pl -tags freebsd,amd64 syscall_bsd.go syscall_freebsd.go syscall_freebsd_amd64.go +// go run mksyscall.go -tags freebsd,amd64 syscall_bsd.go syscall_freebsd.go syscall_freebsd_amd64.go // Code generated by the command above; see README.md. DO NOT EDIT. // +build freebsd,amd64 @@ -377,10 +377,25 @@ func Munlockall() (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func pipe() (r int, w int, err error) { - r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0) - r = int(r0) - w = int(r1) +func pipe2(p *[2]_C_int, flags int) (err error) { + _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getcwd(buf []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS___GETCWD, uintptr(_p0), uintptr(len(buf)), 0) + n = int(r0) if e1 != 0 { err = errnoErr(e1) } @@ -897,7 +912,7 @@ func Fpathconf(fd int, name int) (val int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Fstat(fd int, stat *Stat_t) (err error) { +func fstat(fd int, stat *stat_freebsd11_t) (err error) { _, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) if e1 != 0 { err = errnoErr(e1) @@ -907,7 +922,47 @@ func Fstat(fd int, stat *Stat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Fstatfs(fd int, stat *Statfs_t) (err error) { +func fstat_freebsd12(fd int, stat *Stat_t) (err error) { + _, _, e1 := Syscall(SYS_FSTAT_FREEBSD12, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fstatat(fd int, path string, stat *stat_freebsd11_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FSTATAT, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fstatat_freebsd12(fd int, path string, stat *Stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FSTATAT_FREEBSD12, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fstatfs(fd int, stat *statfs_freebsd11_t) (err error) { _, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) if e1 != 0 { err = errnoErr(e1) @@ -917,6 +972,16 @@ func Fstatfs(fd int, stat *Statfs_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func fstatfs_freebsd12(fd int, stat *Statfs_t) (err error) { + _, _, e1 := Syscall(SYS_FSTATFS_FREEBSD12, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fsync(fd int) (err error) { _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0) if e1 != 0 { @@ -937,7 +1002,7 @@ func Ftruncate(fd int, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { +func getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { _p0 = unsafe.Pointer(&buf[0]) @@ -954,6 +1019,23 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func getdirentries_freebsd12(fd int, buf []byte, basep *uintptr) (n int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_GETDIRENTRIES_FREEBSD12, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Getdtablesize() (size int) { r0, _, _ := Syscall(SYS_GETDTABLESIZE, 0, 0, 0) size = int(r0) @@ -1175,7 +1257,7 @@ func Listen(s int, backlog int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Lstat(path string, stat *Stat_t) (err error) { +func lstat(path string, stat *stat_freebsd11_t) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) if err != nil { @@ -1235,7 +1317,7 @@ func Mkfifo(path string, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Mknod(path string, mode uint32, dev int) (err error) { +func mknod(path string, mode uint32, dev int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) if err != nil { @@ -1250,6 +1332,36 @@ func Mknod(path string, mode uint32, dev int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func mknodat(fd int, path string, mode uint32, dev int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_MKNODAT, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func mknodat_freebsd12(fd int, path string, mode uint32, dev uint64) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_MKNODAT_FREEBSD12, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Nanosleep(time *Timespec, leftover *Timespec) (err error) { _, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0) if e1 != 0 { @@ -1640,7 +1752,7 @@ func Setuid(uid int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Stat(path string, stat *Stat_t) (err error) { +func stat(path string, stat *stat_freebsd11_t) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) if err != nil { @@ -1655,7 +1767,7 @@ func Stat(path string, stat *Stat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Statfs(path string, stat *Statfs_t) (err error) { +func statfs(path string, stat *statfs_freebsd11_t) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) if err != nil { @@ -1670,6 +1782,21 @@ func Statfs(path string, stat *Statfs_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func statfs_freebsd12(path string, stat *Statfs_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_STATFS_FREEBSD12, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Symlink(path string, link string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm.go b/vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm.go index ffd01073c1..290a9c2cb0 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm.go @@ -1,4 +1,4 @@ -// mksyscall.pl -l32 -arm -tags freebsd,arm syscall_bsd.go syscall_freebsd.go syscall_freebsd_arm.go +// go run mksyscall.go -l32 -arm -tags freebsd,arm syscall_bsd.go syscall_freebsd.go syscall_freebsd_arm.go // Code generated by the command above; see README.md. DO NOT EDIT. // +build freebsd,arm @@ -377,10 +377,25 @@ func Munlockall() (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func pipe() (r int, w int, err error) { - r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0) - r = int(r0) - w = int(r1) +func pipe2(p *[2]_C_int, flags int) (err error) { + _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getcwd(buf []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS___GETCWD, uintptr(_p0), uintptr(len(buf)), 0) + n = int(r0) if e1 != 0 { err = errnoErr(e1) } @@ -897,7 +912,7 @@ func Fpathconf(fd int, name int) (val int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Fstat(fd int, stat *Stat_t) (err error) { +func fstat(fd int, stat *stat_freebsd11_t) (err error) { _, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) if e1 != 0 { err = errnoErr(e1) @@ -907,7 +922,47 @@ func Fstat(fd int, stat *Stat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Fstatfs(fd int, stat *Statfs_t) (err error) { +func fstat_freebsd12(fd int, stat *Stat_t) (err error) { + _, _, e1 := Syscall(SYS_FSTAT_FREEBSD12, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fstatat(fd int, path string, stat *stat_freebsd11_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FSTATAT, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fstatat_freebsd12(fd int, path string, stat *Stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FSTATAT_FREEBSD12, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fstatfs(fd int, stat *statfs_freebsd11_t) (err error) { _, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) if e1 != 0 { err = errnoErr(e1) @@ -917,6 +972,16 @@ func Fstatfs(fd int, stat *Statfs_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func fstatfs_freebsd12(fd int, stat *Statfs_t) (err error) { + _, _, e1 := Syscall(SYS_FSTATFS_FREEBSD12, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fsync(fd int) (err error) { _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0) if e1 != 0 { @@ -937,7 +1002,7 @@ func Ftruncate(fd int, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { +func getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { _p0 = unsafe.Pointer(&buf[0]) @@ -954,6 +1019,23 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func getdirentries_freebsd12(fd int, buf []byte, basep *uintptr) (n int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_GETDIRENTRIES_FREEBSD12, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Getdtablesize() (size int) { r0, _, _ := Syscall(SYS_GETDTABLESIZE, 0, 0, 0) size = int(r0) @@ -1175,7 +1257,7 @@ func Listen(s int, backlog int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Lstat(path string, stat *Stat_t) (err error) { +func lstat(path string, stat *stat_freebsd11_t) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) if err != nil { @@ -1235,7 +1317,7 @@ func Mkfifo(path string, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Mknod(path string, mode uint32, dev int) (err error) { +func mknod(path string, mode uint32, dev int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) if err != nil { @@ -1250,6 +1332,36 @@ func Mknod(path string, mode uint32, dev int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func mknodat(fd int, path string, mode uint32, dev int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_MKNODAT, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func mknodat_freebsd12(fd int, path string, mode uint32, dev uint64) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_MKNODAT_FREEBSD12, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Nanosleep(time *Timespec, leftover *Timespec) (err error) { _, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0) if e1 != 0 { @@ -1640,7 +1752,7 @@ func Setuid(uid int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Stat(path string, stat *Stat_t) (err error) { +func stat(path string, stat *stat_freebsd11_t) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) if err != nil { @@ -1655,7 +1767,7 @@ func Stat(path string, stat *Stat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Statfs(path string, stat *Statfs_t) (err error) { +func statfs(path string, stat *statfs_freebsd11_t) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) if err != nil { @@ -1670,6 +1782,21 @@ func Statfs(path string, stat *Statfs_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func statfs_freebsd12(path string, stat *Statfs_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_STATFS_FREEBSD12, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Symlink(path string, link string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm64.go b/vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm64.go new file mode 100644 index 0000000000..c6df9d2e8f --- /dev/null +++ b/vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm64.go @@ -0,0 +1,2015 @@ +// go run mksyscall.go -tags freebsd,arm64 -- syscall_bsd.go syscall_freebsd.go syscall_freebsd_arm64.go +// Code generated by the command above; see README.md. DO NOT EDIT. + +// +build freebsd,arm64 + +package unix + +import ( + "syscall" + "unsafe" +) + +var _ syscall.Errno + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getgroups(ngid int, gid *_Gid_t) (n int, err error) { + r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setgroups(ngid int, gid *_Gid_t) (err error) { + _, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) { + r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0) + wpid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { + r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { + _, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { + _, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func socket(domain int, typ int, proto int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto)) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) { + _, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) { + _, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { + _, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { + _, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Shutdown(s int, how int) (err error) { + _, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) { + _, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) { + r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) { + r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) { + r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) { + var _p0 unsafe.Pointer + if len(mib) > 0 { + _p0 = unsafe.Pointer(&mib[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func utimes(path string, timeval *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func futimes(fd int, timeval *[2]Timeval) (err error) { + _, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fcntl(fd int, cmd int, arg int) (val int, err error) { + r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg)) + val = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { + r0, _, e1 := Syscall(SYS_POLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Madvise(b []byte, behav int) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(behav)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mlock(b []byte) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mlockall(flags int) (err error) { + _, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mprotect(b []byte, prot int) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Msync(b []byte, flags int) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MSYNC, uintptr(_p0), uintptr(len(b)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Munlock(b []byte) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Munlockall() (err error) { + _, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func pipe2(p *[2]_C_int, flags int) (err error) { + _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getcwd(buf []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS___GETCWD, uintptr(_p0), uintptr(len(buf)), 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ioctl(fd int, req uint, arg uintptr) (err error) { + _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Access(path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Adjtime(delta *Timeval, olddelta *Timeval) (err error) { + _, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func CapEnter() (err error) { + _, _, e1 := Syscall(SYS_CAP_ENTER, 0, 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func capRightsGet(version int, fd int, rightsp *CapRights) (err error) { + _, _, e1 := Syscall(SYS___CAP_RIGHTS_GET, uintptr(version), uintptr(fd), uintptr(unsafe.Pointer(rightsp))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func capRightsLimit(fd int, rightsp *CapRights) (err error) { + _, _, e1 := Syscall(SYS_CAP_RIGHTS_LIMIT, uintptr(fd), uintptr(unsafe.Pointer(rightsp)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chdir(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chflags(path string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chmod(path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chown(path string, uid int, gid int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chroot(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Close(fd int) (err error) { + _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Dup(fd int) (nfd int, err error) { + r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0) + nfd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Dup2(from int, to int) (err error) { + _, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Exit(code int) { + Syscall(SYS_EXIT, uintptr(code), 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrGetFd(fd int, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attrname) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_GET_FD, uintptr(fd), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p0)), uintptr(data), uintptr(nbytes), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrSetFd(fd int, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attrname) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_SET_FD, uintptr(fd), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p0)), uintptr(data), uintptr(nbytes), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrDeleteFd(fd int, attrnamespace int, attrname string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attrname) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_EXTATTR_DELETE_FD, uintptr(fd), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p0))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrListFd(fd int, attrnamespace int, data uintptr, nbytes int) (ret int, err error) { + r0, _, e1 := Syscall6(SYS_EXTATTR_LIST_FD, uintptr(fd), uintptr(attrnamespace), uintptr(data), uintptr(nbytes), 0, 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrGetFile(file string, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(file) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attrname) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_GET_FILE, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p1)), uintptr(data), uintptr(nbytes), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrSetFile(file string, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(file) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attrname) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_SET_FILE, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p1)), uintptr(data), uintptr(nbytes), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrDeleteFile(file string, attrnamespace int, attrname string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(file) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attrname) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_EXTATTR_DELETE_FILE, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrListFile(file string, attrnamespace int, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(file) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_LIST_FILE, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(data), uintptr(nbytes), 0, 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrGetLink(link string, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(link) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attrname) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_GET_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p1)), uintptr(data), uintptr(nbytes), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrSetLink(link string, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(link) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attrname) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_SET_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p1)), uintptr(data), uintptr(nbytes), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrDeleteLink(link string, attrnamespace int, attrname string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(link) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attrname) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_EXTATTR_DELETE_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrListLink(link string, attrnamespace int, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(link) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_LIST_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(data), uintptr(nbytes), 0, 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fadvise(fd int, offset int64, length int64, advice int) (err error) { + _, _, e1 := Syscall6(SYS_POSIX_FADVISE, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchdir(fd int) (err error) { + _, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchflags(fd int, flags int) (err error) { + _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchmod(fd int, mode uint32) (err error) { + _, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchown(fd int, uid int, gid int) (err error) { + _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Flock(fd int, how int) (err error) { + _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fpathconf(fd int, name int) (val int, err error) { + r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0) + val = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fstat(fd int, stat *stat_freebsd11_t) (err error) { + _, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fstat_freebsd12(fd int, stat *Stat_t) (err error) { + _, _, e1 := Syscall(SYS_FSTAT_FREEBSD12, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fstatat(fd int, path string, stat *stat_freebsd11_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FSTATAT, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fstatat_freebsd12(fd int, path string, stat *Stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FSTATAT_FREEBSD12, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fstatfs(fd int, stat *statfs_freebsd11_t) (err error) { + _, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fstatfs_freebsd12(fd int, stat *Statfs_t) (err error) { + _, _, e1 := Syscall(SYS_FSTATFS_FREEBSD12, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fsync(fd int) (err error) { + _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Ftruncate(fd int, length int64) (err error) { + _, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_GETDIRENTRIES, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getdirentries_freebsd12(fd int, buf []byte, basep *uintptr) (n int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_GETDIRENTRIES_FREEBSD12, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getdtablesize() (size int) { + r0, _, _ := Syscall(SYS_GETDTABLESIZE, 0, 0, 0) + size = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getegid() (egid int) { + r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0) + egid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Geteuid() (uid int) { + r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0) + uid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getgid() (gid int) { + r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0) + gid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpgid(pid int) (pgid int, err error) { + r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0) + pgid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpgrp() (pgrp int) { + r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0) + pgrp = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpid() (pid int) { + r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0) + pid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getppid() (ppid int) { + r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0) + ppid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpriority(which int, who int) (prio int, err error) { + r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0) + prio = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getrlimit(which int, lim *Rlimit) (err error) { + _, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getrusage(who int, rusage *Rusage) (err error) { + _, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getsid(pid int) (sid int, err error) { + r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0) + sid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Gettimeofday(tv *Timeval) (err error) { + _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getuid() (uid int) { + r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0) + uid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Issetugid() (tainted bool) { + r0, _, _ := Syscall(SYS_ISSETUGID, 0, 0, 0) + tainted = bool(r0 != 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Kill(pid int, signum syscall.Signal) (err error) { + _, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Kqueue() (fd int, err error) { + r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Lchown(path string, uid int, gid int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Link(path string, link string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(link) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(link) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_LINKAT, uintptr(pathfd), uintptr(unsafe.Pointer(_p0)), uintptr(linkfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Listen(s int, backlog int) (err error) { + _, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func lstat(path string, stat *stat_freebsd11_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mkdir(path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mkdirat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mkfifo(path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func mknod(path string, mode uint32, dev int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func mknodat(fd int, path string, mode uint32, dev int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_MKNODAT, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func mknodat_freebsd12(fd int, path string, mode uint32, dev uint64) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_MKNODAT_FREEBSD12, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Nanosleep(time *Timespec, leftover *Timespec) (err error) { + _, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Open(path string, mode int, perm uint32) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Openat(fdat int, path string, mode int, perm uint32) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(fdat), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pathconf(path string, name int) (val int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) + val = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pread(fd int, p []byte, offset int64) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pwrite(fd int, p []byte, offset int64) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func read(fd int, p []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Readlink(path string, buf []byte) (n int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(buf) > 0 { + _p1 = unsafe.Pointer(&buf[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(buf) > 0 { + _p1 = unsafe.Pointer(&buf[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_READLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Rename(from string, to string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(from) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(to) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Renameat(fromfd int, from string, tofd int, to string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(from) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(to) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(fromfd), uintptr(unsafe.Pointer(_p0)), uintptr(tofd), uintptr(unsafe.Pointer(_p1)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Revoke(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Rmdir(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { + r0, _, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence)) + newoffset = int64(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) { + _, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setegid(egid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETEGID, uintptr(egid), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Seteuid(euid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setgid(gid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setlogin(name string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(name) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setpgid(pid int, pgid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setpriority(which int, who int, prio int) (err error) { + _, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setregid(rgid int, egid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setreuid(ruid int, euid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setresgid(rgid int, egid int, sgid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETRESGID, uintptr(rgid), uintptr(egid), uintptr(sgid)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setresuid(ruid int, euid int, suid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETRESUID, uintptr(ruid), uintptr(euid), uintptr(suid)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setrlimit(which int, lim *Rlimit) (err error) { + _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setsid() (pid int, err error) { + r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0) + pid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Settimeofday(tp *Timeval) (err error) { + _, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setuid(uid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func stat(path string, stat *stat_freebsd11_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func statfs(path string, stat *statfs_freebsd11_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func statfs_freebsd12(path string, stat *Statfs_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_STATFS_FREEBSD12, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Symlink(path string, link string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(link) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_SYMLINKAT, uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Sync() (err error) { + _, _, e1 := Syscall(SYS_SYNC, 0, 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Truncate(path string, length int64) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Umask(newmask int) (oldmask int) { + r0, _, _ := Syscall(SYS_UMASK, uintptr(newmask), 0, 0) + oldmask = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Undelete(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Unlink(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Unlinkat(dirfd int, path string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Unmount(path string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func write(fd int, p []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) { + r0, _, e1 := Syscall6(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos)) + ret = uintptr(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func munmap(addr uintptr, length uintptr) (err error) { + _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func readlen(fd int, buf *byte, nbuf int) (n int, err error) { + r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func writelen(fd int, buf *byte, nbuf int) (n int, err error) { + r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func accept4(fd int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (nfd int, err error) { + r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0) + nfd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_UTIMENSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go index 85a2907e5d..c8b451000b 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go @@ -1,4 +1,4 @@ -// mksyscall.pl -l32 -tags linux,386 syscall_linux.go syscall_linux_386.go +// go run mksyscall.go -l32 -tags linux,386 syscall_linux.go syscall_linux_386.go // Code generated by the command above; see README.md. DO NOT EDIT. // +build linux,386 @@ -143,21 +143,6 @@ func Unlinkat(dirfd int, path string, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func utimes(path string, times *[2]Timeval) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -173,16 +158,6 @@ func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) { - _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times))) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Getcwd(buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { @@ -442,6 +417,16 @@ func Chroot(path string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func ClockGetres(clockid int32, res *Timespec) (err error) { + _, _, e1 := Syscall(SYS_CLOCK_GETRES, uintptr(clockid), uintptr(unsafe.Pointer(res)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func ClockGettime(clockid int32, time *Timespec) (err error) { _, _, e1 := Syscall(SYS_CLOCK_GETTIME, uintptr(clockid), uintptr(unsafe.Pointer(time)), 0) if e1 != 0 { @@ -452,6 +437,16 @@ func ClockGettime(clockid int32, time *Timespec) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func ClockNanosleep(clockid int32, flags int, request *Timespec, remain *Timespec) (err error) { + _, _, e1 := Syscall6(SYS_CLOCK_NANOSLEEP, uintptr(clockid), uintptr(flags), uintptr(unsafe.Pointer(request)), uintptr(unsafe.Pointer(remain)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Close(fd int) (err error) { _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0) if e1 != 0 { @@ -473,6 +468,21 @@ func CopyFileRange(rfd int, roff *int64, wfd int, woff *int64, len int, flags in // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func DeleteModule(name string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(name) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_DELETE_MODULE, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Dup(oldfd int) (fd int, err error) { r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), 0, 0) fd = int(r0) @@ -494,17 +504,6 @@ func Dup3(oldfd int, newfd int, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollCreate(size int) (fd int, err error) { - r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func EpollCreate1(flag int) (fd int, err error) { r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0) fd = int(r0) @@ -538,22 +537,7 @@ func Eventfd(initval uint, flags int) (fd int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Exit(code int) { - Syscall(SYS_EXIT_GROUP, uintptr(code), 0, 0) - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } + SyscallNoError(SYS_EXIT_GROUP, uintptr(code), 0, 0) return } @@ -625,6 +609,60 @@ func Fdatasync(fd int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fgetxattr(fd int, attr string, dest []byte) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(dest) > 0 { + _p1 = unsafe.Pointer(&dest[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_FGETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)), 0, 0) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func FinitModule(fd int, params string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(params) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FINIT_MODULE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Flistxattr(fd int, dest []byte) (sz int, err error) { + var _p0 unsafe.Pointer + if len(dest) > 0 { + _p0 = unsafe.Pointer(&dest[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_FLISTXATTR, uintptr(fd), uintptr(_p0), uintptr(len(dest))) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Flock(fd int, how int) (err error) { _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0) if e1 != 0 { @@ -635,6 +673,42 @@ func Flock(fd int, how int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fremovexattr(fd int, attr string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FREMOVEXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fsetxattr(fd int, attr string, dest []byte, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(dest) > 0 { + _p1 = unsafe.Pointer(&dest[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS_FSETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fsync(fd int) (err error) { _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0) if e1 != 0 { @@ -674,7 +748,7 @@ func Getpgid(pid int) (pgid int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpid() (pid int) { - r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETPID, 0, 0, 0) pid = int(r0) return } @@ -682,7 +756,7 @@ func Getpid() (pid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getppid() (ppid int) { - r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETPPID, 0, 0, 0) ppid = int(r0) return } @@ -739,7 +813,7 @@ func Getsid(pid int) (sid int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Gettid() (tid int) { - r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETTID, 0, 0, 0) tid = int(r0) return } @@ -773,6 +847,27 @@ func Getxattr(path string, attr string, dest []byte) (sz int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func InitModule(moduleImage []byte, params string) (err error) { + var _p0 unsafe.Pointer + if len(moduleImage) > 0 { + _p0 = unsafe.Pointer(&moduleImage[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + var _p1 *byte + _p1, err = BytePtrFromString(params) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_INIT_MODULE, uintptr(_p0), uintptr(len(moduleImage)), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err error) { var _p0 *byte _p0, err = BytePtrFromString(pathname) @@ -955,6 +1050,22 @@ func Lsetxattr(path string, attr string, data []byte, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func MemfdCreate(name string, flags int) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(name) + if err != nil { + return + } + r0, _, e1 := Syscall(SYS_MEMFD_CREATE, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Mkdirat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -995,6 +1106,17 @@ func Nanosleep(time *Timespec, leftover *Timespec) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error) { + r0, _, e1 := Syscall6(SYS_PERF_EVENT_OPEN, uintptr(unsafe.Pointer(attr)), uintptr(pid), uintptr(cpu), uintptr(groupFd), uintptr(flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func PivotRoot(newroot string, putold string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(newroot) @@ -1083,7 +1205,7 @@ func Removexattr(path string, attr string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { +func Renameat2(olddirfd int, oldpath string, newdirfd int, newpath string, flags uint) (err error) { var _p0 *byte _p0, err = BytePtrFromString(oldpath) if err != nil { @@ -1094,7 +1216,7 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e if err != nil { return } - _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0) + _, _, e1 := Syscall6(SYS_RENAMEAT2, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } @@ -1238,8 +1360,30 @@ func Setxattr(path string, attr string, data []byte, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Signalfd(fd int, mask *Sigset_t, flags int) { + SyscallNoError(SYS_SIGNALFD4, uintptr(fd), uintptr(unsafe.Pointer(mask)), uintptr(flags)) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Statx(dirfd int, path string, flags int, mask int, stat *Statx_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_STATX, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), uintptr(mask), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Sync() { - Syscall(SYS_SYNC, 0, 0, 0) + SyscallNoError(SYS_SYNC, 0, 0, 0) return } @@ -1298,7 +1442,7 @@ func Times(tms *Tms) (ticks uintptr, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Umask(mask int) (oldmask int) { - r0, _, _ := RawSyscall(SYS_UMASK, uintptr(mask), 0, 0) + r0, _ := RawSyscallNoError(SYS_UMASK, uintptr(mask), 0, 0) oldmask = int(r0) return } @@ -1340,16 +1484,6 @@ func Unshare(flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Ustat(dev int, ubuf *Ustat_t) (err error) { - _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func write(fd int, p []byte) (n int, err error) { var _p0 unsafe.Pointer if len(p) > 0 { @@ -1509,6 +1643,21 @@ func Munlockall() (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func faccessat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func pipe(p *[2]_C_int) (err error) { _, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0) if e1 != 0 { @@ -1539,6 +1688,34 @@ func Dup2(oldfd int, newfd int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func EpollCreate(size int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { + var _p0 unsafe.Pointer + if len(events) > 0 { + _p0 = unsafe.Pointer(&events[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fadvise(fd int, offset int64, length int64, advice int) (err error) { _, _, e1 := Syscall6(SYS_FADVISE64_64, uintptr(fd), uintptr(offset), uintptr(offset>>32), uintptr(length), uintptr(length>>32), uintptr(advice)) if e1 != 0 { @@ -1569,6 +1746,21 @@ func Fstat(fd int, stat *Stat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FSTATAT64, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Ftruncate(fd int, length int64) (err error) { _, _, e1 := Syscall(SYS_FTRUNCATE64, uintptr(fd), uintptr(length), uintptr(length>>32)) if e1 != 0 { @@ -1580,7 +1772,7 @@ func Ftruncate(fd int, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getegid() (egid int) { - r0, _, _ := RawSyscall(SYS_GETEGID32, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETEGID32, 0, 0, 0) egid = int(r0) return } @@ -1588,7 +1780,7 @@ func Getegid() (egid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Geteuid() (euid int) { - r0, _, _ := RawSyscall(SYS_GETEUID32, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETEUID32, 0, 0, 0) euid = int(r0) return } @@ -1596,7 +1788,7 @@ func Geteuid() (euid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getgid() (gid int) { - r0, _, _ := RawSyscall(SYS_GETGID32, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETGID32, 0, 0, 0) gid = int(r0) return } @@ -1604,7 +1796,7 @@ func Getgid() (gid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getuid() (uid int) { - r0, _, _ := RawSyscall(SYS_GETUID32, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETUID32, 0, 0, 0) uid = int(r0) return } @@ -1706,6 +1898,26 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { r0, _, e1 := Syscall6(SYS_SENDFILE64, uintptr(outfd), uintptr(infd), uintptr(unsafe.Pointer(offset)), uintptr(count), 0, 0) written = int(r0) @@ -1828,6 +2040,16 @@ func Truncate(path string, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Ustat(dev int, ubuf *Ustat_t) (err error) { + _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func getgroups(n int, list *_Gid_t) (nn int, err error) { r0, _, e1 := RawSyscall(SYS_GETGROUPS32, uintptr(n), uintptr(unsafe.Pointer(list)), 0) nn = int(r0) @@ -1871,23 +2093,6 @@ func mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { - var _p0 unsafe.Pointer - if len(events) > 0 { - _p0 = unsafe.Pointer(&events[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Pause() (err error) { _, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0) if e1 != 0 { @@ -1918,6 +2123,21 @@ func setrlimit(resource int, rlim *rlimit32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func futimesat(dirfd int, path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Gettimeofday(tv *Timeval) (err error) { _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0) if e1 != 0 { @@ -1954,6 +2174,21 @@ func Utime(path string, buf *Utimbuf) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func utimes(path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { r0, _, e1 := Syscall(SYS_POLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout)) n = int(r0) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go index 8e2be97d36..2aac3184bc 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go @@ -1,4 +1,4 @@ -// mksyscall.pl -tags linux,amd64 syscall_linux.go syscall_linux_amd64.go +// go run mksyscall.go -tags linux,amd64 syscall_linux.go syscall_linux_amd64.go // Code generated by the command above; see README.md. DO NOT EDIT. // +build linux,amd64 @@ -143,21 +143,6 @@ func Unlinkat(dirfd int, path string, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func utimes(path string, times *[2]Timeval) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -173,16 +158,6 @@ func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) { - _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times))) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Getcwd(buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { @@ -442,6 +417,16 @@ func Chroot(path string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func ClockGetres(clockid int32, res *Timespec) (err error) { + _, _, e1 := Syscall(SYS_CLOCK_GETRES, uintptr(clockid), uintptr(unsafe.Pointer(res)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func ClockGettime(clockid int32, time *Timespec) (err error) { _, _, e1 := Syscall(SYS_CLOCK_GETTIME, uintptr(clockid), uintptr(unsafe.Pointer(time)), 0) if e1 != 0 { @@ -452,6 +437,16 @@ func ClockGettime(clockid int32, time *Timespec) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func ClockNanosleep(clockid int32, flags int, request *Timespec, remain *Timespec) (err error) { + _, _, e1 := Syscall6(SYS_CLOCK_NANOSLEEP, uintptr(clockid), uintptr(flags), uintptr(unsafe.Pointer(request)), uintptr(unsafe.Pointer(remain)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Close(fd int) (err error) { _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0) if e1 != 0 { @@ -473,6 +468,21 @@ func CopyFileRange(rfd int, roff *int64, wfd int, woff *int64, len int, flags in // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func DeleteModule(name string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(name) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_DELETE_MODULE, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Dup(oldfd int) (fd int, err error) { r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), 0, 0) fd = int(r0) @@ -494,17 +504,6 @@ func Dup3(oldfd int, newfd int, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollCreate(size int) (fd int, err error) { - r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func EpollCreate1(flag int) (fd int, err error) { r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0) fd = int(r0) @@ -538,22 +537,7 @@ func Eventfd(initval uint, flags int) (fd int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Exit(code int) { - Syscall(SYS_EXIT_GROUP, uintptr(code), 0, 0) - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } + SyscallNoError(SYS_EXIT_GROUP, uintptr(code), 0, 0) return } @@ -625,6 +609,60 @@ func Fdatasync(fd int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fgetxattr(fd int, attr string, dest []byte) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(dest) > 0 { + _p1 = unsafe.Pointer(&dest[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_FGETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)), 0, 0) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func FinitModule(fd int, params string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(params) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FINIT_MODULE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Flistxattr(fd int, dest []byte) (sz int, err error) { + var _p0 unsafe.Pointer + if len(dest) > 0 { + _p0 = unsafe.Pointer(&dest[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_FLISTXATTR, uintptr(fd), uintptr(_p0), uintptr(len(dest))) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Flock(fd int, how int) (err error) { _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0) if e1 != 0 { @@ -635,6 +673,42 @@ func Flock(fd int, how int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fremovexattr(fd int, attr string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FREMOVEXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fsetxattr(fd int, attr string, dest []byte, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(dest) > 0 { + _p1 = unsafe.Pointer(&dest[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS_FSETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fsync(fd int) (err error) { _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0) if e1 != 0 { @@ -674,7 +748,7 @@ func Getpgid(pid int) (pgid int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpid() (pid int) { - r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETPID, 0, 0, 0) pid = int(r0) return } @@ -682,7 +756,7 @@ func Getpid() (pid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getppid() (ppid int) { - r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETPPID, 0, 0, 0) ppid = int(r0) return } @@ -739,7 +813,7 @@ func Getsid(pid int) (sid int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Gettid() (tid int) { - r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETTID, 0, 0, 0) tid = int(r0) return } @@ -773,6 +847,27 @@ func Getxattr(path string, attr string, dest []byte) (sz int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func InitModule(moduleImage []byte, params string) (err error) { + var _p0 unsafe.Pointer + if len(moduleImage) > 0 { + _p0 = unsafe.Pointer(&moduleImage[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + var _p1 *byte + _p1, err = BytePtrFromString(params) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_INIT_MODULE, uintptr(_p0), uintptr(len(moduleImage)), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err error) { var _p0 *byte _p0, err = BytePtrFromString(pathname) @@ -955,6 +1050,22 @@ func Lsetxattr(path string, attr string, data []byte, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func MemfdCreate(name string, flags int) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(name) + if err != nil { + return + } + r0, _, e1 := Syscall(SYS_MEMFD_CREATE, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Mkdirat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -995,6 +1106,17 @@ func Nanosleep(time *Timespec, leftover *Timespec) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error) { + r0, _, e1 := Syscall6(SYS_PERF_EVENT_OPEN, uintptr(unsafe.Pointer(attr)), uintptr(pid), uintptr(cpu), uintptr(groupFd), uintptr(flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func PivotRoot(newroot string, putold string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(newroot) @@ -1083,7 +1205,7 @@ func Removexattr(path string, attr string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { +func Renameat2(olddirfd int, oldpath string, newdirfd int, newpath string, flags uint) (err error) { var _p0 *byte _p0, err = BytePtrFromString(oldpath) if err != nil { @@ -1094,7 +1216,7 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e if err != nil { return } - _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0) + _, _, e1 := Syscall6(SYS_RENAMEAT2, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } @@ -1238,8 +1360,30 @@ func Setxattr(path string, attr string, data []byte, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Signalfd(fd int, mask *Sigset_t, flags int) { + SyscallNoError(SYS_SIGNALFD4, uintptr(fd), uintptr(unsafe.Pointer(mask)), uintptr(flags)) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Statx(dirfd int, path string, flags int, mask int, stat *Statx_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_STATX, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), uintptr(mask), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Sync() { - Syscall(SYS_SYNC, 0, 0, 0) + SyscallNoError(SYS_SYNC, 0, 0, 0) return } @@ -1298,7 +1442,7 @@ func Times(tms *Tms) (ticks uintptr, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Umask(mask int) (oldmask int) { - r0, _, _ := RawSyscall(SYS_UMASK, uintptr(mask), 0, 0) + r0, _ := RawSyscallNoError(SYS_UMASK, uintptr(mask), 0, 0) oldmask = int(r0) return } @@ -1340,16 +1484,6 @@ func Unshare(flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Ustat(dev int, ubuf *Ustat_t) (err error) { - _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func write(fd int, p []byte) (n int, err error) { var _p0 unsafe.Pointer if len(p) > 0 { @@ -1509,6 +1643,21 @@ func Munlockall() (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func faccessat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Dup2(oldfd int, newfd int) (err error) { _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0) if e1 != 0 { @@ -1519,6 +1668,17 @@ func Dup2(oldfd int, newfd int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func EpollCreate(size int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { var _p0 unsafe.Pointer if len(events) > 0 { @@ -1566,6 +1726,21 @@ func Fstat(fd int, stat *Stat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_NEWFSTATAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fstatfs(fd int, buf *Statfs_t) (err error) { _, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(buf)), 0) if e1 != 0 { @@ -1587,7 +1762,7 @@ func Ftruncate(fd int, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getegid() (egid int) { - r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETEGID, 0, 0, 0) egid = int(r0) return } @@ -1595,7 +1770,7 @@ func Getegid() (egid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Geteuid() (euid int) { - r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETEUID, 0, 0, 0) euid = int(r0) return } @@ -1603,7 +1778,7 @@ func Geteuid() (euid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getgid() (gid int) { - r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETGID, 0, 0, 0) gid = int(r0) return } @@ -1621,14 +1796,14 @@ func Getrlimit(resource int, rlim *Rlimit) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getuid() (uid int) { - r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETUID, 0, 0, 0) uid = int(r0) return } // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func InotifyInit() (fd int, err error) { +func inotifyInit() (fd int, err error) { r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0) fd = int(r0) if e1 != 0 { @@ -1684,21 +1859,6 @@ func Listen(s int, n int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Lstat(path string, stat *Stat_t) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Pause() (err error) { _, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0) if e1 != 0 { @@ -1743,9 +1903,18 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Seek(fd int, offset int64, whence int) (off int64, err error) { - r0, _, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence)) - off = int64(r0) +func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0) if e1 != 0 { err = errnoErr(e1) } @@ -1754,9 +1923,9 @@ func Seek(fd int, offset int64, whence int) (off int64, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) { - r0, _, e1 := Syscall6(SYS_SELECT, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0) - n = int(r0) +func Seek(fd int, offset int64, whence int) (off int64, err error) { + r0, _, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence)) + off = int64(r0) if e1 != 0 { err = errnoErr(e1) } @@ -1867,21 +2036,6 @@ func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n i // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Stat(path string, stat *Stat_t) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Statfs(path string, buf *Statfs_t) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -1922,6 +2076,16 @@ func Truncate(path string, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Ustat(dev int, ubuf *Ustat_t) (err error) { + _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) fd = int(r0) @@ -2112,6 +2276,21 @@ func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int6 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func futimesat(dirfd int, path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Utime(path string, buf *Utimbuf) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -2127,6 +2306,21 @@ func Utime(path string, buf *Utimbuf) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func utimes(path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func pipe(p *[2]_C_int) (err error) { _, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0) if e1 != 0 { @@ -2155,3 +2349,18 @@ func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { } return } + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(cmdline) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_KEXEC_FILE_LOAD, uintptr(kernelFd), uintptr(initrdFd), uintptr(cmdlineLen), uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go index 5ff0637fde..13c06c2815 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go @@ -1,4 +1,4 @@ -// mksyscall.pl -l32 -arm -tags linux,arm syscall_linux.go syscall_linux_arm.go +// go run mksyscall.go -l32 -arm -tags linux,arm syscall_linux.go syscall_linux_arm.go // Code generated by the command above; see README.md. DO NOT EDIT. // +build linux,arm @@ -143,21 +143,6 @@ func Unlinkat(dirfd int, path string, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func utimes(path string, times *[2]Timeval) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -173,16 +158,6 @@ func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) { - _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times))) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Getcwd(buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { @@ -442,6 +417,16 @@ func Chroot(path string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func ClockGetres(clockid int32, res *Timespec) (err error) { + _, _, e1 := Syscall(SYS_CLOCK_GETRES, uintptr(clockid), uintptr(unsafe.Pointer(res)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func ClockGettime(clockid int32, time *Timespec) (err error) { _, _, e1 := Syscall(SYS_CLOCK_GETTIME, uintptr(clockid), uintptr(unsafe.Pointer(time)), 0) if e1 != 0 { @@ -452,6 +437,16 @@ func ClockGettime(clockid int32, time *Timespec) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func ClockNanosleep(clockid int32, flags int, request *Timespec, remain *Timespec) (err error) { + _, _, e1 := Syscall6(SYS_CLOCK_NANOSLEEP, uintptr(clockid), uintptr(flags), uintptr(unsafe.Pointer(request)), uintptr(unsafe.Pointer(remain)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Close(fd int) (err error) { _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0) if e1 != 0 { @@ -473,6 +468,21 @@ func CopyFileRange(rfd int, roff *int64, wfd int, woff *int64, len int, flags in // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func DeleteModule(name string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(name) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_DELETE_MODULE, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Dup(oldfd int) (fd int, err error) { r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), 0, 0) fd = int(r0) @@ -494,17 +504,6 @@ func Dup3(oldfd int, newfd int, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollCreate(size int) (fd int, err error) { - r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func EpollCreate1(flag int) (fd int, err error) { r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0) fd = int(r0) @@ -538,22 +537,7 @@ func Eventfd(initval uint, flags int) (fd int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Exit(code int) { - Syscall(SYS_EXIT_GROUP, uintptr(code), 0, 0) - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } + SyscallNoError(SYS_EXIT_GROUP, uintptr(code), 0, 0) return } @@ -625,6 +609,60 @@ func Fdatasync(fd int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fgetxattr(fd int, attr string, dest []byte) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(dest) > 0 { + _p1 = unsafe.Pointer(&dest[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_FGETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)), 0, 0) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func FinitModule(fd int, params string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(params) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FINIT_MODULE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Flistxattr(fd int, dest []byte) (sz int, err error) { + var _p0 unsafe.Pointer + if len(dest) > 0 { + _p0 = unsafe.Pointer(&dest[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_FLISTXATTR, uintptr(fd), uintptr(_p0), uintptr(len(dest))) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Flock(fd int, how int) (err error) { _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0) if e1 != 0 { @@ -635,6 +673,42 @@ func Flock(fd int, how int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fremovexattr(fd int, attr string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FREMOVEXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fsetxattr(fd int, attr string, dest []byte, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(dest) > 0 { + _p1 = unsafe.Pointer(&dest[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS_FSETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fsync(fd int) (err error) { _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0) if e1 != 0 { @@ -674,7 +748,7 @@ func Getpgid(pid int) (pgid int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpid() (pid int) { - r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETPID, 0, 0, 0) pid = int(r0) return } @@ -682,7 +756,7 @@ func Getpid() (pid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getppid() (ppid int) { - r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETPPID, 0, 0, 0) ppid = int(r0) return } @@ -739,7 +813,7 @@ func Getsid(pid int) (sid int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Gettid() (tid int) { - r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETTID, 0, 0, 0) tid = int(r0) return } @@ -773,6 +847,27 @@ func Getxattr(path string, attr string, dest []byte) (sz int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func InitModule(moduleImage []byte, params string) (err error) { + var _p0 unsafe.Pointer + if len(moduleImage) > 0 { + _p0 = unsafe.Pointer(&moduleImage[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + var _p1 *byte + _p1, err = BytePtrFromString(params) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_INIT_MODULE, uintptr(_p0), uintptr(len(moduleImage)), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err error) { var _p0 *byte _p0, err = BytePtrFromString(pathname) @@ -955,6 +1050,22 @@ func Lsetxattr(path string, attr string, data []byte, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func MemfdCreate(name string, flags int) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(name) + if err != nil { + return + } + r0, _, e1 := Syscall(SYS_MEMFD_CREATE, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Mkdirat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -995,6 +1106,17 @@ func Nanosleep(time *Timespec, leftover *Timespec) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error) { + r0, _, e1 := Syscall6(SYS_PERF_EVENT_OPEN, uintptr(unsafe.Pointer(attr)), uintptr(pid), uintptr(cpu), uintptr(groupFd), uintptr(flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func PivotRoot(newroot string, putold string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(newroot) @@ -1083,7 +1205,7 @@ func Removexattr(path string, attr string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { +func Renameat2(olddirfd int, oldpath string, newdirfd int, newpath string, flags uint) (err error) { var _p0 *byte _p0, err = BytePtrFromString(oldpath) if err != nil { @@ -1094,7 +1216,7 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e if err != nil { return } - _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0) + _, _, e1 := Syscall6(SYS_RENAMEAT2, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } @@ -1238,8 +1360,30 @@ func Setxattr(path string, attr string, data []byte, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Signalfd(fd int, mask *Sigset_t, flags int) { + SyscallNoError(SYS_SIGNALFD4, uintptr(fd), uintptr(unsafe.Pointer(mask)), uintptr(flags)) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Statx(dirfd int, path string, flags int, mask int, stat *Statx_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_STATX, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), uintptr(mask), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Sync() { - Syscall(SYS_SYNC, 0, 0, 0) + SyscallNoError(SYS_SYNC, 0, 0, 0) return } @@ -1298,7 +1442,7 @@ func Times(tms *Tms) (ticks uintptr, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Umask(mask int) (oldmask int) { - r0, _, _ := RawSyscall(SYS_UMASK, uintptr(mask), 0, 0) + r0, _ := RawSyscallNoError(SYS_UMASK, uintptr(mask), 0, 0) oldmask = int(r0) return } @@ -1340,16 +1484,6 @@ func Unshare(flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Ustat(dev int, ubuf *Ustat_t) (err error) { - _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func write(fd int, p []byte) (n int, err error) { var _p0 unsafe.Pointer if len(p) > 0 { @@ -1509,6 +1643,21 @@ func Munlockall() (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func faccessat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func pipe2(p *[2]_C_int, flags int) (err error) { _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0) if e1 != 0 { @@ -1708,6 +1857,34 @@ func Dup2(oldfd int, newfd int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func EpollCreate(size int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { + var _p0 unsafe.Pointer + if len(events) > 0 { + _p0 = unsafe.Pointer(&events[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fchown(fd int, uid int, gid int) (err error) { _, _, e1 := Syscall(SYS_FCHOWN32, uintptr(fd), uintptr(uid), uintptr(gid)) if e1 != 0 { @@ -1728,8 +1905,23 @@ func Fstat(fd int, stat *Stat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FSTATAT64, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Getegid() (egid int) { - r0, _, _ := RawSyscall(SYS_GETEGID32, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETEGID32, 0, 0, 0) egid = int(r0) return } @@ -1737,7 +1929,7 @@ func Getegid() (egid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Geteuid() (euid int) { - r0, _, _ := RawSyscall(SYS_GETEUID32, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETEUID32, 0, 0, 0) euid = int(r0) return } @@ -1745,7 +1937,7 @@ func Geteuid() (euid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getgid() (gid int) { - r0, _, _ := RawSyscall(SYS_GETGID32, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETGID32, 0, 0, 0) gid = int(r0) return } @@ -1753,7 +1945,7 @@ func Getgid() (gid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getuid() (uid int) { - r0, _, _ := RawSyscall(SYS_GETUID32, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETUID32, 0, 0, 0) uid = int(r0) return } @@ -1811,6 +2003,36 @@ func Lstat(path string, stat *Stat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Pause() (err error) { + _, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { r0, _, e1 := Syscall6(SYS_SENDFILE64, uintptr(outfd), uintptr(infd), uintptr(unsafe.Pointer(offset)), uintptr(count), 0, 0) written = int(r0) @@ -1929,6 +2151,31 @@ func Stat(path string, stat *Stat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Ustat(dev int, ubuf *Ustat_t) (err error) { + _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func futimesat(dirfd int, path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Gettimeofday(tv *Timeval) (err error) { _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0) if e1 != 0 { @@ -1939,25 +2186,13 @@ func Gettimeofday(tv *Timeval) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { - var _p0 unsafe.Pointer - if len(events) > 0 { - _p0 = unsafe.Pointer(&events[0]) - } else { - _p0 = unsafe.Pointer(&_zero) +func utimes(path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return } - r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Pause() (err error) { - _, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0) + _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) if e1 != 0 { err = errnoErr(e1) } @@ -2064,3 +2299,13 @@ func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { } return } + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func armSyncFileRange(fd int, flags int, off int64, n int64) (err error) { + _, _, e1 := Syscall6(SYS_ARM_SYNC_FILE_RANGE, uintptr(fd), uintptr(flags), uintptr(off), uintptr(off>>32), uintptr(n), uintptr(n>>32)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go index 40760110f3..737fa8d181 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go @@ -1,4 +1,4 @@ -// mksyscall.pl -tags linux,arm64 syscall_linux.go syscall_linux_arm64.go +// go run mksyscall.go -tags linux,arm64 syscall_linux.go syscall_linux_arm64.go // Code generated by the command above; see README.md. DO NOT EDIT. // +build linux,arm64 @@ -143,21 +143,6 @@ func Unlinkat(dirfd int, path string, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func utimes(path string, times *[2]Timeval) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -173,16 +158,6 @@ func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) { - _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times))) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Getcwd(buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { @@ -442,6 +417,16 @@ func Chroot(path string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func ClockGetres(clockid int32, res *Timespec) (err error) { + _, _, e1 := Syscall(SYS_CLOCK_GETRES, uintptr(clockid), uintptr(unsafe.Pointer(res)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func ClockGettime(clockid int32, time *Timespec) (err error) { _, _, e1 := Syscall(SYS_CLOCK_GETTIME, uintptr(clockid), uintptr(unsafe.Pointer(time)), 0) if e1 != 0 { @@ -452,6 +437,16 @@ func ClockGettime(clockid int32, time *Timespec) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func ClockNanosleep(clockid int32, flags int, request *Timespec, remain *Timespec) (err error) { + _, _, e1 := Syscall6(SYS_CLOCK_NANOSLEEP, uintptr(clockid), uintptr(flags), uintptr(unsafe.Pointer(request)), uintptr(unsafe.Pointer(remain)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Close(fd int) (err error) { _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0) if e1 != 0 { @@ -473,6 +468,21 @@ func CopyFileRange(rfd int, roff *int64, wfd int, woff *int64, len int, flags in // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func DeleteModule(name string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(name) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_DELETE_MODULE, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Dup(oldfd int) (fd int, err error) { r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), 0, 0) fd = int(r0) @@ -494,17 +504,6 @@ func Dup3(oldfd int, newfd int, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollCreate(size int) (fd int, err error) { - r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func EpollCreate1(flag int) (fd int, err error) { r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0) fd = int(r0) @@ -538,22 +537,7 @@ func Eventfd(initval uint, flags int) (fd int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Exit(code int) { - Syscall(SYS_EXIT_GROUP, uintptr(code), 0, 0) - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } + SyscallNoError(SYS_EXIT_GROUP, uintptr(code), 0, 0) return } @@ -625,6 +609,60 @@ func Fdatasync(fd int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fgetxattr(fd int, attr string, dest []byte) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(dest) > 0 { + _p1 = unsafe.Pointer(&dest[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_FGETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)), 0, 0) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func FinitModule(fd int, params string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(params) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FINIT_MODULE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Flistxattr(fd int, dest []byte) (sz int, err error) { + var _p0 unsafe.Pointer + if len(dest) > 0 { + _p0 = unsafe.Pointer(&dest[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_FLISTXATTR, uintptr(fd), uintptr(_p0), uintptr(len(dest))) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Flock(fd int, how int) (err error) { _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0) if e1 != 0 { @@ -635,6 +673,42 @@ func Flock(fd int, how int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fremovexattr(fd int, attr string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FREMOVEXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fsetxattr(fd int, attr string, dest []byte, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(dest) > 0 { + _p1 = unsafe.Pointer(&dest[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS_FSETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fsync(fd int) (err error) { _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0) if e1 != 0 { @@ -674,7 +748,7 @@ func Getpgid(pid int) (pgid int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpid() (pid int) { - r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETPID, 0, 0, 0) pid = int(r0) return } @@ -682,7 +756,7 @@ func Getpid() (pid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getppid() (ppid int) { - r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETPPID, 0, 0, 0) ppid = int(r0) return } @@ -739,7 +813,7 @@ func Getsid(pid int) (sid int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Gettid() (tid int) { - r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETTID, 0, 0, 0) tid = int(r0) return } @@ -773,6 +847,27 @@ func Getxattr(path string, attr string, dest []byte) (sz int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func InitModule(moduleImage []byte, params string) (err error) { + var _p0 unsafe.Pointer + if len(moduleImage) > 0 { + _p0 = unsafe.Pointer(&moduleImage[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + var _p1 *byte + _p1, err = BytePtrFromString(params) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_INIT_MODULE, uintptr(_p0), uintptr(len(moduleImage)), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err error) { var _p0 *byte _p0, err = BytePtrFromString(pathname) @@ -955,6 +1050,22 @@ func Lsetxattr(path string, attr string, data []byte, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func MemfdCreate(name string, flags int) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(name) + if err != nil { + return + } + r0, _, e1 := Syscall(SYS_MEMFD_CREATE, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Mkdirat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -995,6 +1106,17 @@ func Nanosleep(time *Timespec, leftover *Timespec) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error) { + r0, _, e1 := Syscall6(SYS_PERF_EVENT_OPEN, uintptr(unsafe.Pointer(attr)), uintptr(pid), uintptr(cpu), uintptr(groupFd), uintptr(flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func PivotRoot(newroot string, putold string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(newroot) @@ -1083,7 +1205,7 @@ func Removexattr(path string, attr string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { +func Renameat2(olddirfd int, oldpath string, newdirfd int, newpath string, flags uint) (err error) { var _p0 *byte _p0, err = BytePtrFromString(oldpath) if err != nil { @@ -1094,7 +1216,7 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e if err != nil { return } - _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0) + _, _, e1 := Syscall6(SYS_RENAMEAT2, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } @@ -1238,8 +1360,30 @@ func Setxattr(path string, attr string, data []byte, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Signalfd(fd int, mask *Sigset_t, flags int) { + SyscallNoError(SYS_SIGNALFD4, uintptr(fd), uintptr(unsafe.Pointer(mask)), uintptr(flags)) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Statx(dirfd int, path string, flags int, mask int, stat *Statx_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_STATX, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), uintptr(mask), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Sync() { - Syscall(SYS_SYNC, 0, 0, 0) + SyscallNoError(SYS_SYNC, 0, 0, 0) return } @@ -1298,7 +1442,7 @@ func Times(tms *Tms) (ticks uintptr, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Umask(mask int) (oldmask int) { - r0, _, _ := RawSyscall(SYS_UMASK, uintptr(mask), 0, 0) + r0, _ := RawSyscallNoError(SYS_UMASK, uintptr(mask), 0, 0) oldmask = int(r0) return } @@ -1340,16 +1484,6 @@ func Unshare(flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Ustat(dev int, ubuf *Ustat_t) (err error) { - _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func write(fd int, p []byte) (n int, err error) { var _p0 unsafe.Pointer if len(p) > 0 { @@ -1509,6 +1643,21 @@ func Munlockall() (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func faccessat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { var _p0 unsafe.Pointer if len(events) > 0 { @@ -1526,6 +1675,16 @@ func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fadvise(fd int, offset int64, length int64, advice int) (err error) { + _, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fchown(fd int, uid int, gid int) (err error) { _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)) if e1 != 0 { @@ -1582,7 +1741,7 @@ func Ftruncate(fd int, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getegid() (egid int) { - r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETEGID, 0, 0, 0) egid = int(r0) return } @@ -1590,7 +1749,7 @@ func Getegid() (egid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Geteuid() (euid int) { - r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETEUID, 0, 0, 0) euid = int(r0) return } @@ -1598,7 +1757,7 @@ func Geteuid() (euid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getgid() (gid int) { - r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETGID, 0, 0, 0) gid = int(r0) return } @@ -1616,7 +1775,7 @@ func Getrlimit(resource int, rlim *Rlimit) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getuid() (uid int) { - r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETUID, 0, 0, 0) uid = int(r0) return } @@ -1667,6 +1826,26 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Seek(fd int, offset int64, whence int) (off int64, err error) { r0, _, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence)) off = int64(r0) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go index 984e561733..0a85f3f8db 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go @@ -1,4 +1,4 @@ -// mksyscall.pl -b32 -arm -tags linux,mips syscall_linux.go syscall_linux_mipsx.go +// go run mksyscall.go -b32 -arm -tags linux,mips syscall_linux.go syscall_linux_mipsx.go // Code generated by the command above; see README.md. DO NOT EDIT. // +build linux,mips @@ -143,21 +143,6 @@ func Unlinkat(dirfd int, path string, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func utimes(path string, times *[2]Timeval) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -173,16 +158,6 @@ func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) { - _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times))) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Getcwd(buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { @@ -442,6 +417,16 @@ func Chroot(path string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func ClockGetres(clockid int32, res *Timespec) (err error) { + _, _, e1 := Syscall(SYS_CLOCK_GETRES, uintptr(clockid), uintptr(unsafe.Pointer(res)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func ClockGettime(clockid int32, time *Timespec) (err error) { _, _, e1 := Syscall(SYS_CLOCK_GETTIME, uintptr(clockid), uintptr(unsafe.Pointer(time)), 0) if e1 != 0 { @@ -452,6 +437,16 @@ func ClockGettime(clockid int32, time *Timespec) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func ClockNanosleep(clockid int32, flags int, request *Timespec, remain *Timespec) (err error) { + _, _, e1 := Syscall6(SYS_CLOCK_NANOSLEEP, uintptr(clockid), uintptr(flags), uintptr(unsafe.Pointer(request)), uintptr(unsafe.Pointer(remain)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Close(fd int) (err error) { _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0) if e1 != 0 { @@ -473,6 +468,21 @@ func CopyFileRange(rfd int, roff *int64, wfd int, woff *int64, len int, flags in // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func DeleteModule(name string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(name) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_DELETE_MODULE, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Dup(oldfd int) (fd int, err error) { r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), 0, 0) fd = int(r0) @@ -494,17 +504,6 @@ func Dup3(oldfd int, newfd int, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollCreate(size int) (fd int, err error) { - r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func EpollCreate1(flag int) (fd int, err error) { r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0) fd = int(r0) @@ -538,22 +537,7 @@ func Eventfd(initval uint, flags int) (fd int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Exit(code int) { - Syscall(SYS_EXIT_GROUP, uintptr(code), 0, 0) - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } + SyscallNoError(SYS_EXIT_GROUP, uintptr(code), 0, 0) return } @@ -625,6 +609,60 @@ func Fdatasync(fd int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fgetxattr(fd int, attr string, dest []byte) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(dest) > 0 { + _p1 = unsafe.Pointer(&dest[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_FGETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)), 0, 0) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func FinitModule(fd int, params string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(params) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FINIT_MODULE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Flistxattr(fd int, dest []byte) (sz int, err error) { + var _p0 unsafe.Pointer + if len(dest) > 0 { + _p0 = unsafe.Pointer(&dest[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_FLISTXATTR, uintptr(fd), uintptr(_p0), uintptr(len(dest))) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Flock(fd int, how int) (err error) { _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0) if e1 != 0 { @@ -635,6 +673,42 @@ func Flock(fd int, how int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fremovexattr(fd int, attr string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FREMOVEXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fsetxattr(fd int, attr string, dest []byte, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(dest) > 0 { + _p1 = unsafe.Pointer(&dest[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS_FSETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fsync(fd int) (err error) { _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0) if e1 != 0 { @@ -674,7 +748,7 @@ func Getpgid(pid int) (pgid int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpid() (pid int) { - r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETPID, 0, 0, 0) pid = int(r0) return } @@ -682,7 +756,7 @@ func Getpid() (pid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getppid() (ppid int) { - r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETPPID, 0, 0, 0) ppid = int(r0) return } @@ -739,7 +813,7 @@ func Getsid(pid int) (sid int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Gettid() (tid int) { - r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETTID, 0, 0, 0) tid = int(r0) return } @@ -773,6 +847,27 @@ func Getxattr(path string, attr string, dest []byte) (sz int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func InitModule(moduleImage []byte, params string) (err error) { + var _p0 unsafe.Pointer + if len(moduleImage) > 0 { + _p0 = unsafe.Pointer(&moduleImage[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + var _p1 *byte + _p1, err = BytePtrFromString(params) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_INIT_MODULE, uintptr(_p0), uintptr(len(moduleImage)), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err error) { var _p0 *byte _p0, err = BytePtrFromString(pathname) @@ -955,6 +1050,22 @@ func Lsetxattr(path string, attr string, data []byte, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func MemfdCreate(name string, flags int) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(name) + if err != nil { + return + } + r0, _, e1 := Syscall(SYS_MEMFD_CREATE, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Mkdirat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -995,6 +1106,17 @@ func Nanosleep(time *Timespec, leftover *Timespec) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error) { + r0, _, e1 := Syscall6(SYS_PERF_EVENT_OPEN, uintptr(unsafe.Pointer(attr)), uintptr(pid), uintptr(cpu), uintptr(groupFd), uintptr(flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func PivotRoot(newroot string, putold string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(newroot) @@ -1083,7 +1205,7 @@ func Removexattr(path string, attr string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { +func Renameat2(olddirfd int, oldpath string, newdirfd int, newpath string, flags uint) (err error) { var _p0 *byte _p0, err = BytePtrFromString(oldpath) if err != nil { @@ -1094,7 +1216,7 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e if err != nil { return } - _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0) + _, _, e1 := Syscall6(SYS_RENAMEAT2, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } @@ -1238,8 +1360,30 @@ func Setxattr(path string, attr string, data []byte, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Signalfd(fd int, mask *Sigset_t, flags int) { + SyscallNoError(SYS_SIGNALFD4, uintptr(fd), uintptr(unsafe.Pointer(mask)), uintptr(flags)) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Statx(dirfd int, path string, flags int, mask int, stat *Statx_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_STATX, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), uintptr(mask), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Sync() { - Syscall(SYS_SYNC, 0, 0, 0) + SyscallNoError(SYS_SYNC, 0, 0, 0) return } @@ -1298,7 +1442,7 @@ func Times(tms *Tms) (ticks uintptr, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Umask(mask int) (oldmask int) { - r0, _, _ := RawSyscall(SYS_UMASK, uintptr(mask), 0, 0) + r0, _ := RawSyscallNoError(SYS_UMASK, uintptr(mask), 0, 0) oldmask = int(r0) return } @@ -1340,16 +1484,6 @@ func Unshare(flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Ustat(dev int, ubuf *Ustat_t) (err error) { - _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func write(fd int, p []byte) (n int, err error) { var _p0 unsafe.Pointer if len(p) > 0 { @@ -1509,6 +1643,21 @@ func Munlockall() (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func faccessat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Dup2(oldfd int, newfd int) (err error) { _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0) if e1 != 0 { @@ -1519,6 +1668,44 @@ func Dup2(oldfd int, newfd int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func EpollCreate(size int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { + var _p0 unsafe.Pointer + if len(events) > 0 { + _p0 = unsafe.Pointer(&events[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fadvise(fd int, offset int64, length int64, advice int) (err error) { + _, _, e1 := Syscall9(SYS_FADVISE64, uintptr(fd), 0, uintptr(offset>>32), uintptr(offset), uintptr(length>>32), uintptr(length), uintptr(advice), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fchown(fd int, uid int, gid int) (err error) { _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)) if e1 != 0 { @@ -1540,7 +1727,7 @@ func Ftruncate(fd int, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getegid() (egid int) { - r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETEGID, 0, 0, 0) egid = int(r0) return } @@ -1548,7 +1735,7 @@ func Getegid() (egid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Geteuid() (euid int) { - r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETEUID, 0, 0, 0) euid = int(r0) return } @@ -1556,7 +1743,7 @@ func Geteuid() (euid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getgid() (gid int) { - r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETGID, 0, 0, 0) gid = int(r0) return } @@ -1564,7 +1751,7 @@ func Getgid() (gid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getuid() (uid int) { - r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETUID, 0, 0, 0) uid = int(r0) return } @@ -1630,6 +1817,26 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) { r0, _, e1 := Syscall6(SYS__NEWSELECT, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0) n = int(r0) @@ -1722,9 +1929,9 @@ func Shutdown(fd int, how int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error) { - r0, r1, e1 := Syscall6(SYS_SPLICE, uintptr(rfd), uintptr(unsafe.Pointer(roff)), uintptr(wfd), uintptr(unsafe.Pointer(woff)), uintptr(len), uintptr(flags)) - n = int64(int64(r0)<<32 | int64(r1)) +func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, err error) { + r0, _, e1 := Syscall6(SYS_SPLICE, uintptr(rfd), uintptr(unsafe.Pointer(roff)), uintptr(wfd), uintptr(unsafe.Pointer(woff)), uintptr(len), uintptr(flags)) + n = int(r0) if e1 != 0 { err = errnoErr(e1) } @@ -1758,6 +1965,16 @@ func Truncate(path string, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Ustat(dev int, ubuf *Ustat_t) (err error) { + _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) fd = int(r0) @@ -1968,6 +2185,21 @@ func Iopl(level int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func futimesat(dirfd int, path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Gettimeofday(tv *Timeval) (err error) { _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0) if e1 != 0 { @@ -1989,6 +2221,36 @@ func Time(t *Time_t) (tt Time_t, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Utime(path string, buf *Utimbuf) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func utimes(path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Lstat(path string, stat *Stat_t) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -2014,6 +2276,21 @@ func Fstat(fd int, stat *Stat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FSTATAT64, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Stat(path string, stat *Stat_t) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -2029,38 +2306,6 @@ func Stat(path string, stat *Stat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Utime(path string, buf *Utimbuf) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { - var _p0 unsafe.Pointer - if len(events) > 0 { - _p0 = unsafe.Pointer(&events[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Pause() (err error) { _, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0) if e1 != 0 { @@ -2081,6 +2326,18 @@ func pipe2(p *[2]_C_int, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func pipe() (p1 int, p2 int, err error) { + r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0) + p1 = int(r0) + p2 = int(r1) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, err error) { r0, _, e1 := Syscall6(SYS_MMAP2, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(pageOffset)) xaddr = uintptr(r0) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go index f98194e245..ec7007e781 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go @@ -1,4 +1,4 @@ -// mksyscall.pl -tags linux,mips64 syscall_linux.go syscall_linux_mips64x.go +// go run mksyscall.go -tags linux,mips64 syscall_linux.go syscall_linux_mips64x.go // Code generated by the command above; see README.md. DO NOT EDIT. // +build linux,mips64 @@ -143,21 +143,6 @@ func Unlinkat(dirfd int, path string, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func utimes(path string, times *[2]Timeval) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -173,16 +158,6 @@ func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) { - _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times))) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Getcwd(buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { @@ -442,6 +417,16 @@ func Chroot(path string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func ClockGetres(clockid int32, res *Timespec) (err error) { + _, _, e1 := Syscall(SYS_CLOCK_GETRES, uintptr(clockid), uintptr(unsafe.Pointer(res)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func ClockGettime(clockid int32, time *Timespec) (err error) { _, _, e1 := Syscall(SYS_CLOCK_GETTIME, uintptr(clockid), uintptr(unsafe.Pointer(time)), 0) if e1 != 0 { @@ -452,6 +437,16 @@ func ClockGettime(clockid int32, time *Timespec) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func ClockNanosleep(clockid int32, flags int, request *Timespec, remain *Timespec) (err error) { + _, _, e1 := Syscall6(SYS_CLOCK_NANOSLEEP, uintptr(clockid), uintptr(flags), uintptr(unsafe.Pointer(request)), uintptr(unsafe.Pointer(remain)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Close(fd int) (err error) { _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0) if e1 != 0 { @@ -473,6 +468,21 @@ func CopyFileRange(rfd int, roff *int64, wfd int, woff *int64, len int, flags in // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func DeleteModule(name string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(name) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_DELETE_MODULE, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Dup(oldfd int) (fd int, err error) { r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), 0, 0) fd = int(r0) @@ -494,17 +504,6 @@ func Dup3(oldfd int, newfd int, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollCreate(size int) (fd int, err error) { - r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func EpollCreate1(flag int) (fd int, err error) { r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0) fd = int(r0) @@ -538,22 +537,7 @@ func Eventfd(initval uint, flags int) (fd int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Exit(code int) { - Syscall(SYS_EXIT_GROUP, uintptr(code), 0, 0) - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } + SyscallNoError(SYS_EXIT_GROUP, uintptr(code), 0, 0) return } @@ -625,6 +609,60 @@ func Fdatasync(fd int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fgetxattr(fd int, attr string, dest []byte) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(dest) > 0 { + _p1 = unsafe.Pointer(&dest[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_FGETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)), 0, 0) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func FinitModule(fd int, params string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(params) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FINIT_MODULE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Flistxattr(fd int, dest []byte) (sz int, err error) { + var _p0 unsafe.Pointer + if len(dest) > 0 { + _p0 = unsafe.Pointer(&dest[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_FLISTXATTR, uintptr(fd), uintptr(_p0), uintptr(len(dest))) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Flock(fd int, how int) (err error) { _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0) if e1 != 0 { @@ -635,6 +673,42 @@ func Flock(fd int, how int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fremovexattr(fd int, attr string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FREMOVEXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fsetxattr(fd int, attr string, dest []byte, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(dest) > 0 { + _p1 = unsafe.Pointer(&dest[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS_FSETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fsync(fd int) (err error) { _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0) if e1 != 0 { @@ -674,7 +748,7 @@ func Getpgid(pid int) (pgid int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpid() (pid int) { - r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETPID, 0, 0, 0) pid = int(r0) return } @@ -682,7 +756,7 @@ func Getpid() (pid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getppid() (ppid int) { - r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETPPID, 0, 0, 0) ppid = int(r0) return } @@ -739,7 +813,7 @@ func Getsid(pid int) (sid int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Gettid() (tid int) { - r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETTID, 0, 0, 0) tid = int(r0) return } @@ -773,6 +847,27 @@ func Getxattr(path string, attr string, dest []byte) (sz int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func InitModule(moduleImage []byte, params string) (err error) { + var _p0 unsafe.Pointer + if len(moduleImage) > 0 { + _p0 = unsafe.Pointer(&moduleImage[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + var _p1 *byte + _p1, err = BytePtrFromString(params) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_INIT_MODULE, uintptr(_p0), uintptr(len(moduleImage)), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err error) { var _p0 *byte _p0, err = BytePtrFromString(pathname) @@ -955,6 +1050,22 @@ func Lsetxattr(path string, attr string, data []byte, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func MemfdCreate(name string, flags int) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(name) + if err != nil { + return + } + r0, _, e1 := Syscall(SYS_MEMFD_CREATE, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Mkdirat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -995,6 +1106,17 @@ func Nanosleep(time *Timespec, leftover *Timespec) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error) { + r0, _, e1 := Syscall6(SYS_PERF_EVENT_OPEN, uintptr(unsafe.Pointer(attr)), uintptr(pid), uintptr(cpu), uintptr(groupFd), uintptr(flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func PivotRoot(newroot string, putold string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(newroot) @@ -1083,7 +1205,7 @@ func Removexattr(path string, attr string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { +func Renameat2(olddirfd int, oldpath string, newdirfd int, newpath string, flags uint) (err error) { var _p0 *byte _p0, err = BytePtrFromString(oldpath) if err != nil { @@ -1094,7 +1216,7 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e if err != nil { return } - _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0) + _, _, e1 := Syscall6(SYS_RENAMEAT2, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } @@ -1238,8 +1360,30 @@ func Setxattr(path string, attr string, data []byte, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Signalfd(fd int, mask *Sigset_t, flags int) { + SyscallNoError(SYS_SIGNALFD4, uintptr(fd), uintptr(unsafe.Pointer(mask)), uintptr(flags)) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Statx(dirfd int, path string, flags int, mask int, stat *Statx_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_STATX, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), uintptr(mask), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Sync() { - Syscall(SYS_SYNC, 0, 0, 0) + SyscallNoError(SYS_SYNC, 0, 0, 0) return } @@ -1298,7 +1442,7 @@ func Times(tms *Tms) (ticks uintptr, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Umask(mask int) (oldmask int) { - r0, _, _ := RawSyscall(SYS_UMASK, uintptr(mask), 0, 0) + r0, _ := RawSyscallNoError(SYS_UMASK, uintptr(mask), 0, 0) oldmask = int(r0) return } @@ -1340,16 +1484,6 @@ func Unshare(flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Ustat(dev int, ubuf *Ustat_t) (err error) { - _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func write(fd int, p []byte) (n int, err error) { var _p0 unsafe.Pointer if len(p) > 0 { @@ -1509,6 +1643,21 @@ func Munlockall() (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func faccessat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Dup2(oldfd int, newfd int) (err error) { _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0) if e1 != 0 { @@ -1519,6 +1668,17 @@ func Dup2(oldfd int, newfd int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func EpollCreate(size int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { var _p0 unsafe.Pointer if len(events) > 0 { @@ -1536,6 +1696,16 @@ func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fadvise(fd int, offset int64, length int64, advice int) (err error) { + _, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fchown(fd int, uid int, gid int) (err error) { _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)) if e1 != 0 { @@ -1567,7 +1737,7 @@ func Ftruncate(fd int, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getegid() (egid int) { - r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETEGID, 0, 0, 0) egid = int(r0) return } @@ -1575,7 +1745,7 @@ func Getegid() (egid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Geteuid() (euid int) { - r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETEUID, 0, 0, 0) euid = int(r0) return } @@ -1583,7 +1753,7 @@ func Geteuid() (euid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getgid() (gid int) { - r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETGID, 0, 0, 0) gid = int(r0) return } @@ -1601,7 +1771,7 @@ func Getrlimit(resource int, rlim *Rlimit) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getuid() (uid int) { - r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETUID, 0, 0, 0) uid = int(r0) return } @@ -1677,6 +1847,26 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Seek(fd int, offset int64, whence int) (off int64, err error) { r0, _, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence)) off = int64(r0) @@ -1830,6 +2020,16 @@ func Truncate(path string, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Ustat(dev int, ubuf *Ustat_t) (err error) { + _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) fd = int(r0) @@ -2020,6 +2220,21 @@ func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int6 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func futimesat(dirfd int, path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Gettimeofday(tv *Timeval) (err error) { _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0) if e1 != 0 { @@ -2045,6 +2260,21 @@ func Utime(path string, buf *Utimbuf) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func utimes(path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func pipe2(p *[2]_C_int, flags int) (err error) { _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0) if e1 != 0 { @@ -2065,6 +2295,21 @@ func fstat(fd int, st *stat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func fstatat(dirfd int, path string, st *stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_NEWFSTATAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(st)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func lstat(path string, st *stat_t) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go index f30267019b..c5bb25d964 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go @@ -1,4 +1,4 @@ -// mksyscall.pl -tags linux,mips64le syscall_linux.go syscall_linux_mips64x.go +// go run mksyscall.go -tags linux,mips64le syscall_linux.go syscall_linux_mips64x.go // Code generated by the command above; see README.md. DO NOT EDIT. // +build linux,mips64le @@ -143,21 +143,6 @@ func Unlinkat(dirfd int, path string, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func utimes(path string, times *[2]Timeval) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -173,16 +158,6 @@ func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) { - _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times))) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Getcwd(buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { @@ -442,6 +417,16 @@ func Chroot(path string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func ClockGetres(clockid int32, res *Timespec) (err error) { + _, _, e1 := Syscall(SYS_CLOCK_GETRES, uintptr(clockid), uintptr(unsafe.Pointer(res)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func ClockGettime(clockid int32, time *Timespec) (err error) { _, _, e1 := Syscall(SYS_CLOCK_GETTIME, uintptr(clockid), uintptr(unsafe.Pointer(time)), 0) if e1 != 0 { @@ -452,6 +437,16 @@ func ClockGettime(clockid int32, time *Timespec) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func ClockNanosleep(clockid int32, flags int, request *Timespec, remain *Timespec) (err error) { + _, _, e1 := Syscall6(SYS_CLOCK_NANOSLEEP, uintptr(clockid), uintptr(flags), uintptr(unsafe.Pointer(request)), uintptr(unsafe.Pointer(remain)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Close(fd int) (err error) { _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0) if e1 != 0 { @@ -473,6 +468,21 @@ func CopyFileRange(rfd int, roff *int64, wfd int, woff *int64, len int, flags in // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func DeleteModule(name string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(name) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_DELETE_MODULE, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Dup(oldfd int) (fd int, err error) { r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), 0, 0) fd = int(r0) @@ -494,17 +504,6 @@ func Dup3(oldfd int, newfd int, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollCreate(size int) (fd int, err error) { - r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func EpollCreate1(flag int) (fd int, err error) { r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0) fd = int(r0) @@ -538,22 +537,7 @@ func Eventfd(initval uint, flags int) (fd int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Exit(code int) { - Syscall(SYS_EXIT_GROUP, uintptr(code), 0, 0) - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } + SyscallNoError(SYS_EXIT_GROUP, uintptr(code), 0, 0) return } @@ -625,6 +609,60 @@ func Fdatasync(fd int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fgetxattr(fd int, attr string, dest []byte) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(dest) > 0 { + _p1 = unsafe.Pointer(&dest[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_FGETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)), 0, 0) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func FinitModule(fd int, params string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(params) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FINIT_MODULE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Flistxattr(fd int, dest []byte) (sz int, err error) { + var _p0 unsafe.Pointer + if len(dest) > 0 { + _p0 = unsafe.Pointer(&dest[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_FLISTXATTR, uintptr(fd), uintptr(_p0), uintptr(len(dest))) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Flock(fd int, how int) (err error) { _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0) if e1 != 0 { @@ -635,6 +673,42 @@ func Flock(fd int, how int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fremovexattr(fd int, attr string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FREMOVEXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fsetxattr(fd int, attr string, dest []byte, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(dest) > 0 { + _p1 = unsafe.Pointer(&dest[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS_FSETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fsync(fd int) (err error) { _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0) if e1 != 0 { @@ -674,7 +748,7 @@ func Getpgid(pid int) (pgid int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpid() (pid int) { - r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETPID, 0, 0, 0) pid = int(r0) return } @@ -682,7 +756,7 @@ func Getpid() (pid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getppid() (ppid int) { - r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETPPID, 0, 0, 0) ppid = int(r0) return } @@ -739,7 +813,7 @@ func Getsid(pid int) (sid int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Gettid() (tid int) { - r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETTID, 0, 0, 0) tid = int(r0) return } @@ -773,6 +847,27 @@ func Getxattr(path string, attr string, dest []byte) (sz int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func InitModule(moduleImage []byte, params string) (err error) { + var _p0 unsafe.Pointer + if len(moduleImage) > 0 { + _p0 = unsafe.Pointer(&moduleImage[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + var _p1 *byte + _p1, err = BytePtrFromString(params) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_INIT_MODULE, uintptr(_p0), uintptr(len(moduleImage)), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err error) { var _p0 *byte _p0, err = BytePtrFromString(pathname) @@ -955,6 +1050,22 @@ func Lsetxattr(path string, attr string, data []byte, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func MemfdCreate(name string, flags int) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(name) + if err != nil { + return + } + r0, _, e1 := Syscall(SYS_MEMFD_CREATE, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Mkdirat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -995,6 +1106,17 @@ func Nanosleep(time *Timespec, leftover *Timespec) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error) { + r0, _, e1 := Syscall6(SYS_PERF_EVENT_OPEN, uintptr(unsafe.Pointer(attr)), uintptr(pid), uintptr(cpu), uintptr(groupFd), uintptr(flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func PivotRoot(newroot string, putold string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(newroot) @@ -1083,7 +1205,7 @@ func Removexattr(path string, attr string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { +func Renameat2(olddirfd int, oldpath string, newdirfd int, newpath string, flags uint) (err error) { var _p0 *byte _p0, err = BytePtrFromString(oldpath) if err != nil { @@ -1094,7 +1216,7 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e if err != nil { return } - _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0) + _, _, e1 := Syscall6(SYS_RENAMEAT2, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } @@ -1238,8 +1360,30 @@ func Setxattr(path string, attr string, data []byte, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Signalfd(fd int, mask *Sigset_t, flags int) { + SyscallNoError(SYS_SIGNALFD4, uintptr(fd), uintptr(unsafe.Pointer(mask)), uintptr(flags)) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Statx(dirfd int, path string, flags int, mask int, stat *Statx_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_STATX, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), uintptr(mask), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Sync() { - Syscall(SYS_SYNC, 0, 0, 0) + SyscallNoError(SYS_SYNC, 0, 0, 0) return } @@ -1298,7 +1442,7 @@ func Times(tms *Tms) (ticks uintptr, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Umask(mask int) (oldmask int) { - r0, _, _ := RawSyscall(SYS_UMASK, uintptr(mask), 0, 0) + r0, _ := RawSyscallNoError(SYS_UMASK, uintptr(mask), 0, 0) oldmask = int(r0) return } @@ -1340,16 +1484,6 @@ func Unshare(flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Ustat(dev int, ubuf *Ustat_t) (err error) { - _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func write(fd int, p []byte) (n int, err error) { var _p0 unsafe.Pointer if len(p) > 0 { @@ -1509,6 +1643,21 @@ func Munlockall() (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func faccessat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Dup2(oldfd int, newfd int) (err error) { _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0) if e1 != 0 { @@ -1519,6 +1668,17 @@ func Dup2(oldfd int, newfd int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func EpollCreate(size int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { var _p0 unsafe.Pointer if len(events) > 0 { @@ -1536,6 +1696,16 @@ func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fadvise(fd int, offset int64, length int64, advice int) (err error) { + _, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fchown(fd int, uid int, gid int) (err error) { _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)) if e1 != 0 { @@ -1567,7 +1737,7 @@ func Ftruncate(fd int, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getegid() (egid int) { - r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETEGID, 0, 0, 0) egid = int(r0) return } @@ -1575,7 +1745,7 @@ func Getegid() (egid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Geteuid() (euid int) { - r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETEUID, 0, 0, 0) euid = int(r0) return } @@ -1583,7 +1753,7 @@ func Geteuid() (euid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getgid() (gid int) { - r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETGID, 0, 0, 0) gid = int(r0) return } @@ -1601,7 +1771,7 @@ func Getrlimit(resource int, rlim *Rlimit) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getuid() (uid int) { - r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETUID, 0, 0, 0) uid = int(r0) return } @@ -1677,6 +1847,26 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Seek(fd int, offset int64, whence int) (off int64, err error) { r0, _, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence)) off = int64(r0) @@ -1830,6 +2020,16 @@ func Truncate(path string, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Ustat(dev int, ubuf *Ustat_t) (err error) { + _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) fd = int(r0) @@ -2020,6 +2220,21 @@ func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int6 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func futimesat(dirfd int, path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Gettimeofday(tv *Timeval) (err error) { _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0) if e1 != 0 { @@ -2045,6 +2260,21 @@ func Utime(path string, buf *Utimbuf) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func utimes(path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func pipe2(p *[2]_C_int, flags int) (err error) { _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0) if e1 != 0 { @@ -2065,6 +2295,21 @@ func fstat(fd int, st *stat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func fstatat(dirfd int, path string, st *stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_NEWFSTATAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(st)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func lstat(path string, st *stat_t) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go index f18c5e4a76..26ada0478f 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go @@ -1,4 +1,4 @@ -// mksyscall.pl -l32 -arm -tags linux,mipsle syscall_linux.go syscall_linux_mipsx.go +// go run mksyscall.go -l32 -arm -tags linux,mipsle syscall_linux.go syscall_linux_mipsx.go // Code generated by the command above; see README.md. DO NOT EDIT. // +build linux,mipsle @@ -143,21 +143,6 @@ func Unlinkat(dirfd int, path string, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func utimes(path string, times *[2]Timeval) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -173,16 +158,6 @@ func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) { - _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times))) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Getcwd(buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { @@ -442,6 +417,16 @@ func Chroot(path string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func ClockGetres(clockid int32, res *Timespec) (err error) { + _, _, e1 := Syscall(SYS_CLOCK_GETRES, uintptr(clockid), uintptr(unsafe.Pointer(res)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func ClockGettime(clockid int32, time *Timespec) (err error) { _, _, e1 := Syscall(SYS_CLOCK_GETTIME, uintptr(clockid), uintptr(unsafe.Pointer(time)), 0) if e1 != 0 { @@ -452,6 +437,16 @@ func ClockGettime(clockid int32, time *Timespec) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func ClockNanosleep(clockid int32, flags int, request *Timespec, remain *Timespec) (err error) { + _, _, e1 := Syscall6(SYS_CLOCK_NANOSLEEP, uintptr(clockid), uintptr(flags), uintptr(unsafe.Pointer(request)), uintptr(unsafe.Pointer(remain)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Close(fd int) (err error) { _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0) if e1 != 0 { @@ -473,6 +468,21 @@ func CopyFileRange(rfd int, roff *int64, wfd int, woff *int64, len int, flags in // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func DeleteModule(name string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(name) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_DELETE_MODULE, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Dup(oldfd int) (fd int, err error) { r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), 0, 0) fd = int(r0) @@ -494,17 +504,6 @@ func Dup3(oldfd int, newfd int, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollCreate(size int) (fd int, err error) { - r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func EpollCreate1(flag int) (fd int, err error) { r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0) fd = int(r0) @@ -538,22 +537,7 @@ func Eventfd(initval uint, flags int) (fd int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Exit(code int) { - Syscall(SYS_EXIT_GROUP, uintptr(code), 0, 0) - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } + SyscallNoError(SYS_EXIT_GROUP, uintptr(code), 0, 0) return } @@ -625,6 +609,60 @@ func Fdatasync(fd int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fgetxattr(fd int, attr string, dest []byte) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(dest) > 0 { + _p1 = unsafe.Pointer(&dest[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_FGETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)), 0, 0) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func FinitModule(fd int, params string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(params) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FINIT_MODULE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Flistxattr(fd int, dest []byte) (sz int, err error) { + var _p0 unsafe.Pointer + if len(dest) > 0 { + _p0 = unsafe.Pointer(&dest[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_FLISTXATTR, uintptr(fd), uintptr(_p0), uintptr(len(dest))) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Flock(fd int, how int) (err error) { _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0) if e1 != 0 { @@ -635,6 +673,42 @@ func Flock(fd int, how int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fremovexattr(fd int, attr string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FREMOVEXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fsetxattr(fd int, attr string, dest []byte, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(dest) > 0 { + _p1 = unsafe.Pointer(&dest[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS_FSETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fsync(fd int) (err error) { _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0) if e1 != 0 { @@ -674,7 +748,7 @@ func Getpgid(pid int) (pgid int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpid() (pid int) { - r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETPID, 0, 0, 0) pid = int(r0) return } @@ -682,7 +756,7 @@ func Getpid() (pid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getppid() (ppid int) { - r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETPPID, 0, 0, 0) ppid = int(r0) return } @@ -739,7 +813,7 @@ func Getsid(pid int) (sid int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Gettid() (tid int) { - r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETTID, 0, 0, 0) tid = int(r0) return } @@ -773,6 +847,27 @@ func Getxattr(path string, attr string, dest []byte) (sz int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func InitModule(moduleImage []byte, params string) (err error) { + var _p0 unsafe.Pointer + if len(moduleImage) > 0 { + _p0 = unsafe.Pointer(&moduleImage[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + var _p1 *byte + _p1, err = BytePtrFromString(params) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_INIT_MODULE, uintptr(_p0), uintptr(len(moduleImage)), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err error) { var _p0 *byte _p0, err = BytePtrFromString(pathname) @@ -955,6 +1050,22 @@ func Lsetxattr(path string, attr string, data []byte, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func MemfdCreate(name string, flags int) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(name) + if err != nil { + return + } + r0, _, e1 := Syscall(SYS_MEMFD_CREATE, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Mkdirat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -995,6 +1106,17 @@ func Nanosleep(time *Timespec, leftover *Timespec) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error) { + r0, _, e1 := Syscall6(SYS_PERF_EVENT_OPEN, uintptr(unsafe.Pointer(attr)), uintptr(pid), uintptr(cpu), uintptr(groupFd), uintptr(flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func PivotRoot(newroot string, putold string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(newroot) @@ -1083,7 +1205,7 @@ func Removexattr(path string, attr string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { +func Renameat2(olddirfd int, oldpath string, newdirfd int, newpath string, flags uint) (err error) { var _p0 *byte _p0, err = BytePtrFromString(oldpath) if err != nil { @@ -1094,7 +1216,7 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e if err != nil { return } - _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0) + _, _, e1 := Syscall6(SYS_RENAMEAT2, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } @@ -1238,8 +1360,30 @@ func Setxattr(path string, attr string, data []byte, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Signalfd(fd int, mask *Sigset_t, flags int) { + SyscallNoError(SYS_SIGNALFD4, uintptr(fd), uintptr(unsafe.Pointer(mask)), uintptr(flags)) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Statx(dirfd int, path string, flags int, mask int, stat *Statx_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_STATX, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), uintptr(mask), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Sync() { - Syscall(SYS_SYNC, 0, 0, 0) + SyscallNoError(SYS_SYNC, 0, 0, 0) return } @@ -1298,7 +1442,7 @@ func Times(tms *Tms) (ticks uintptr, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Umask(mask int) (oldmask int) { - r0, _, _ := RawSyscall(SYS_UMASK, uintptr(mask), 0, 0) + r0, _ := RawSyscallNoError(SYS_UMASK, uintptr(mask), 0, 0) oldmask = int(r0) return } @@ -1340,16 +1484,6 @@ func Unshare(flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Ustat(dev int, ubuf *Ustat_t) (err error) { - _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func write(fd int, p []byte) (n int, err error) { var _p0 unsafe.Pointer if len(p) > 0 { @@ -1509,6 +1643,21 @@ func Munlockall() (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func faccessat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Dup2(oldfd int, newfd int) (err error) { _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0) if e1 != 0 { @@ -1519,6 +1668,44 @@ func Dup2(oldfd int, newfd int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func EpollCreate(size int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { + var _p0 unsafe.Pointer + if len(events) > 0 { + _p0 = unsafe.Pointer(&events[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fadvise(fd int, offset int64, length int64, advice int) (err error) { + _, _, e1 := Syscall9(SYS_FADVISE64, uintptr(fd), 0, uintptr(offset), uintptr(offset>>32), uintptr(length), uintptr(length>>32), uintptr(advice), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fchown(fd int, uid int, gid int) (err error) { _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)) if e1 != 0 { @@ -1540,7 +1727,7 @@ func Ftruncate(fd int, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getegid() (egid int) { - r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETEGID, 0, 0, 0) egid = int(r0) return } @@ -1548,7 +1735,7 @@ func Getegid() (egid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Geteuid() (euid int) { - r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETEUID, 0, 0, 0) euid = int(r0) return } @@ -1556,7 +1743,7 @@ func Geteuid() (euid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getgid() (gid int) { - r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETGID, 0, 0, 0) gid = int(r0) return } @@ -1564,7 +1751,7 @@ func Getgid() (gid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getuid() (uid int) { - r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETUID, 0, 0, 0) uid = int(r0) return } @@ -1630,6 +1817,26 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) { r0, _, e1 := Syscall6(SYS__NEWSELECT, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0) n = int(r0) @@ -1722,9 +1929,9 @@ func Shutdown(fd int, how int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error) { - r0, r1, e1 := Syscall6(SYS_SPLICE, uintptr(rfd), uintptr(unsafe.Pointer(roff)), uintptr(wfd), uintptr(unsafe.Pointer(woff)), uintptr(len), uintptr(flags)) - n = int64(int64(r1)<<32 | int64(r0)) +func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, err error) { + r0, _, e1 := Syscall6(SYS_SPLICE, uintptr(rfd), uintptr(unsafe.Pointer(roff)), uintptr(wfd), uintptr(unsafe.Pointer(woff)), uintptr(len), uintptr(flags)) + n = int(r0) if e1 != 0 { err = errnoErr(e1) } @@ -1758,6 +1965,16 @@ func Truncate(path string, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Ustat(dev int, ubuf *Ustat_t) (err error) { + _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) fd = int(r0) @@ -1968,6 +2185,21 @@ func Iopl(level int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func futimesat(dirfd int, path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Gettimeofday(tv *Timeval) (err error) { _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0) if e1 != 0 { @@ -1989,6 +2221,36 @@ func Time(t *Time_t) (tt Time_t, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Utime(path string, buf *Utimbuf) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func utimes(path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Lstat(path string, stat *Stat_t) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -2014,6 +2276,21 @@ func Fstat(fd int, stat *Stat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FSTATAT64, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Stat(path string, stat *Stat_t) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -2029,38 +2306,6 @@ func Stat(path string, stat *Stat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Utime(path string, buf *Utimbuf) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { - var _p0 unsafe.Pointer - if len(events) > 0 { - _p0 = unsafe.Pointer(&events[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Pause() (err error) { _, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0) if e1 != 0 { @@ -2081,6 +2326,18 @@ func pipe2(p *[2]_C_int, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func pipe() (p1 int, p2 int, err error) { + r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0) + p1 = int(r0) + p2 = int(r1) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, err error) { r0, _, e1 := Syscall6(SYS_MMAP2, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(pageOffset)) xaddr = uintptr(r0) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go index bc268243cf..2da9cb700a 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go @@ -1,4 +1,4 @@ -// mksyscall.pl -tags linux,ppc64 syscall_linux.go syscall_linux_ppc64x.go +// go run mksyscall.go -tags linux,ppc64 syscall_linux.go syscall_linux_ppc64x.go // Code generated by the command above; see README.md. DO NOT EDIT. // +build linux,ppc64 @@ -143,21 +143,6 @@ func Unlinkat(dirfd int, path string, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func utimes(path string, times *[2]Timeval) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -173,16 +158,6 @@ func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) { - _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times))) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Getcwd(buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { @@ -442,6 +417,16 @@ func Chroot(path string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func ClockGetres(clockid int32, res *Timespec) (err error) { + _, _, e1 := Syscall(SYS_CLOCK_GETRES, uintptr(clockid), uintptr(unsafe.Pointer(res)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func ClockGettime(clockid int32, time *Timespec) (err error) { _, _, e1 := Syscall(SYS_CLOCK_GETTIME, uintptr(clockid), uintptr(unsafe.Pointer(time)), 0) if e1 != 0 { @@ -452,6 +437,16 @@ func ClockGettime(clockid int32, time *Timespec) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func ClockNanosleep(clockid int32, flags int, request *Timespec, remain *Timespec) (err error) { + _, _, e1 := Syscall6(SYS_CLOCK_NANOSLEEP, uintptr(clockid), uintptr(flags), uintptr(unsafe.Pointer(request)), uintptr(unsafe.Pointer(remain)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Close(fd int) (err error) { _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0) if e1 != 0 { @@ -473,6 +468,21 @@ func CopyFileRange(rfd int, roff *int64, wfd int, woff *int64, len int, flags in // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func DeleteModule(name string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(name) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_DELETE_MODULE, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Dup(oldfd int) (fd int, err error) { r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), 0, 0) fd = int(r0) @@ -494,17 +504,6 @@ func Dup3(oldfd int, newfd int, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollCreate(size int) (fd int, err error) { - r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func EpollCreate1(flag int) (fd int, err error) { r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0) fd = int(r0) @@ -538,22 +537,7 @@ func Eventfd(initval uint, flags int) (fd int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Exit(code int) { - Syscall(SYS_EXIT_GROUP, uintptr(code), 0, 0) - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } + SyscallNoError(SYS_EXIT_GROUP, uintptr(code), 0, 0) return } @@ -625,6 +609,60 @@ func Fdatasync(fd int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fgetxattr(fd int, attr string, dest []byte) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(dest) > 0 { + _p1 = unsafe.Pointer(&dest[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_FGETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)), 0, 0) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func FinitModule(fd int, params string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(params) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FINIT_MODULE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Flistxattr(fd int, dest []byte) (sz int, err error) { + var _p0 unsafe.Pointer + if len(dest) > 0 { + _p0 = unsafe.Pointer(&dest[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_FLISTXATTR, uintptr(fd), uintptr(_p0), uintptr(len(dest))) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Flock(fd int, how int) (err error) { _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0) if e1 != 0 { @@ -635,6 +673,42 @@ func Flock(fd int, how int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fremovexattr(fd int, attr string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FREMOVEXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fsetxattr(fd int, attr string, dest []byte, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(dest) > 0 { + _p1 = unsafe.Pointer(&dest[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS_FSETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fsync(fd int) (err error) { _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0) if e1 != 0 { @@ -674,7 +748,7 @@ func Getpgid(pid int) (pgid int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpid() (pid int) { - r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETPID, 0, 0, 0) pid = int(r0) return } @@ -682,7 +756,7 @@ func Getpid() (pid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getppid() (ppid int) { - r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETPPID, 0, 0, 0) ppid = int(r0) return } @@ -739,7 +813,7 @@ func Getsid(pid int) (sid int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Gettid() (tid int) { - r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETTID, 0, 0, 0) tid = int(r0) return } @@ -773,6 +847,27 @@ func Getxattr(path string, attr string, dest []byte) (sz int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func InitModule(moduleImage []byte, params string) (err error) { + var _p0 unsafe.Pointer + if len(moduleImage) > 0 { + _p0 = unsafe.Pointer(&moduleImage[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + var _p1 *byte + _p1, err = BytePtrFromString(params) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_INIT_MODULE, uintptr(_p0), uintptr(len(moduleImage)), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err error) { var _p0 *byte _p0, err = BytePtrFromString(pathname) @@ -955,6 +1050,22 @@ func Lsetxattr(path string, attr string, data []byte, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func MemfdCreate(name string, flags int) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(name) + if err != nil { + return + } + r0, _, e1 := Syscall(SYS_MEMFD_CREATE, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Mkdirat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -995,6 +1106,17 @@ func Nanosleep(time *Timespec, leftover *Timespec) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error) { + r0, _, e1 := Syscall6(SYS_PERF_EVENT_OPEN, uintptr(unsafe.Pointer(attr)), uintptr(pid), uintptr(cpu), uintptr(groupFd), uintptr(flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func PivotRoot(newroot string, putold string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(newroot) @@ -1083,7 +1205,7 @@ func Removexattr(path string, attr string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { +func Renameat2(olddirfd int, oldpath string, newdirfd int, newpath string, flags uint) (err error) { var _p0 *byte _p0, err = BytePtrFromString(oldpath) if err != nil { @@ -1094,7 +1216,7 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e if err != nil { return } - _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0) + _, _, e1 := Syscall6(SYS_RENAMEAT2, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } @@ -1238,8 +1360,30 @@ func Setxattr(path string, attr string, data []byte, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Signalfd(fd int, mask *Sigset_t, flags int) { + SyscallNoError(SYS_SIGNALFD4, uintptr(fd), uintptr(unsafe.Pointer(mask)), uintptr(flags)) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Statx(dirfd int, path string, flags int, mask int, stat *Statx_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_STATX, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), uintptr(mask), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Sync() { - Syscall(SYS_SYNC, 0, 0, 0) + SyscallNoError(SYS_SYNC, 0, 0, 0) return } @@ -1298,7 +1442,7 @@ func Times(tms *Tms) (ticks uintptr, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Umask(mask int) (oldmask int) { - r0, _, _ := RawSyscall(SYS_UMASK, uintptr(mask), 0, 0) + r0, _ := RawSyscallNoError(SYS_UMASK, uintptr(mask), 0, 0) oldmask = int(r0) return } @@ -1340,16 +1484,6 @@ func Unshare(flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Ustat(dev int, ubuf *Ustat_t) (err error) { - _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func write(fd int, p []byte) (n int, err error) { var _p0 unsafe.Pointer if len(p) > 0 { @@ -1509,6 +1643,42 @@ func Munlockall() (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func faccessat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Dup2(oldfd int, newfd int) (err error) { + _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func EpollCreate(size int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { var _p0 unsafe.Pointer if len(events) > 0 { @@ -1526,8 +1696,8 @@ func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Dup2(oldfd int, newfd int) (err error) { - _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0) +func Fadvise(fd int, offset int64, length int64, advice int) (err error) { + _, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0) if e1 != 0 { err = errnoErr(e1) } @@ -1556,6 +1726,21 @@ func Fstat(fd int, stat *Stat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_NEWFSTATAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fstatfs(fd int, buf *Statfs_t) (err error) { _, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(buf)), 0) if e1 != 0 { @@ -1577,7 +1762,7 @@ func Ftruncate(fd int, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getegid() (egid int) { - r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETEGID, 0, 0, 0) egid = int(r0) return } @@ -1585,7 +1770,7 @@ func Getegid() (egid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Geteuid() (euid int) { - r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETEUID, 0, 0, 0) euid = int(r0) return } @@ -1593,7 +1778,7 @@ func Geteuid() (euid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getgid() (gid int) { - r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETGID, 0, 0, 0) gid = int(r0) return } @@ -1611,7 +1796,7 @@ func Getrlimit(resource int, rlim *Rlimit) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getuid() (uid int) { - r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETUID, 0, 0, 0) uid = int(r0) return } @@ -1733,6 +1918,26 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Seek(fd int, offset int64, whence int) (off int64, err error) { r0, _, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence)) off = int64(r0) @@ -1887,8 +2092,13 @@ func Statfs(path string, buf *Statfs_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func SyncFileRange(fd int, off int64, n int64, flags int) (err error) { - _, _, e1 := Syscall6(SYS_SYNC_FILE_RANGE2, uintptr(fd), uintptr(off), uintptr(n), uintptr(flags), 0, 0) +func Truncate(path string, length int64) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0) if e1 != 0 { err = errnoErr(e1) } @@ -1897,13 +2107,8 @@ func SyncFileRange(fd int, off int64, n int64, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Truncate(path string, length int64) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0) +func Ustat(dev int, ubuf *Ustat_t) (err error) { + _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) if e1 != 0 { err = errnoErr(e1) } @@ -2102,6 +2307,21 @@ func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int6 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func futimesat(dirfd int, path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Gettimeofday(tv *Timeval) (err error) { _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0) if e1 != 0 { @@ -2138,6 +2358,21 @@ func Utime(path string, buf *Utimbuf) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func utimes(path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func pipe(p *[2]_C_int) (err error) { _, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0) if e1 != 0 { @@ -2166,3 +2401,28 @@ func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { } return } + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func syncFileRange2(fd int, flags int, off int64, n int64) (err error) { + _, _, e1 := Syscall6(SYS_SYNC_FILE_RANGE2, uintptr(fd), uintptr(flags), uintptr(off), uintptr(n), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(cmdline) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_KEXEC_FILE_LOAD, uintptr(kernelFd), uintptr(initrdFd), uintptr(cmdlineLen), uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go index 8d874cbcdc..772733d83f 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go @@ -1,4 +1,4 @@ -// mksyscall.pl -tags linux,ppc64le syscall_linux.go syscall_linux_ppc64x.go +// go run mksyscall.go -tags linux,ppc64le syscall_linux.go syscall_linux_ppc64x.go // Code generated by the command above; see README.md. DO NOT EDIT. // +build linux,ppc64le @@ -143,21 +143,6 @@ func Unlinkat(dirfd int, path string, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func utimes(path string, times *[2]Timeval) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -173,16 +158,6 @@ func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) { - _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times))) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Getcwd(buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { @@ -442,6 +417,16 @@ func Chroot(path string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func ClockGetres(clockid int32, res *Timespec) (err error) { + _, _, e1 := Syscall(SYS_CLOCK_GETRES, uintptr(clockid), uintptr(unsafe.Pointer(res)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func ClockGettime(clockid int32, time *Timespec) (err error) { _, _, e1 := Syscall(SYS_CLOCK_GETTIME, uintptr(clockid), uintptr(unsafe.Pointer(time)), 0) if e1 != 0 { @@ -452,6 +437,16 @@ func ClockGettime(clockid int32, time *Timespec) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func ClockNanosleep(clockid int32, flags int, request *Timespec, remain *Timespec) (err error) { + _, _, e1 := Syscall6(SYS_CLOCK_NANOSLEEP, uintptr(clockid), uintptr(flags), uintptr(unsafe.Pointer(request)), uintptr(unsafe.Pointer(remain)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Close(fd int) (err error) { _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0) if e1 != 0 { @@ -473,6 +468,21 @@ func CopyFileRange(rfd int, roff *int64, wfd int, woff *int64, len int, flags in // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func DeleteModule(name string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(name) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_DELETE_MODULE, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Dup(oldfd int) (fd int, err error) { r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), 0, 0) fd = int(r0) @@ -494,17 +504,6 @@ func Dup3(oldfd int, newfd int, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollCreate(size int) (fd int, err error) { - r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func EpollCreate1(flag int) (fd int, err error) { r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0) fd = int(r0) @@ -538,22 +537,7 @@ func Eventfd(initval uint, flags int) (fd int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Exit(code int) { - Syscall(SYS_EXIT_GROUP, uintptr(code), 0, 0) - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } + SyscallNoError(SYS_EXIT_GROUP, uintptr(code), 0, 0) return } @@ -625,6 +609,60 @@ func Fdatasync(fd int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fgetxattr(fd int, attr string, dest []byte) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(dest) > 0 { + _p1 = unsafe.Pointer(&dest[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_FGETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)), 0, 0) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func FinitModule(fd int, params string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(params) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FINIT_MODULE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Flistxattr(fd int, dest []byte) (sz int, err error) { + var _p0 unsafe.Pointer + if len(dest) > 0 { + _p0 = unsafe.Pointer(&dest[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_FLISTXATTR, uintptr(fd), uintptr(_p0), uintptr(len(dest))) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Flock(fd int, how int) (err error) { _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0) if e1 != 0 { @@ -635,6 +673,42 @@ func Flock(fd int, how int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fremovexattr(fd int, attr string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FREMOVEXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fsetxattr(fd int, attr string, dest []byte, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(dest) > 0 { + _p1 = unsafe.Pointer(&dest[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS_FSETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fsync(fd int) (err error) { _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0) if e1 != 0 { @@ -674,7 +748,7 @@ func Getpgid(pid int) (pgid int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpid() (pid int) { - r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETPID, 0, 0, 0) pid = int(r0) return } @@ -682,7 +756,7 @@ func Getpid() (pid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getppid() (ppid int) { - r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETPPID, 0, 0, 0) ppid = int(r0) return } @@ -739,7 +813,7 @@ func Getsid(pid int) (sid int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Gettid() (tid int) { - r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETTID, 0, 0, 0) tid = int(r0) return } @@ -773,6 +847,27 @@ func Getxattr(path string, attr string, dest []byte) (sz int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func InitModule(moduleImage []byte, params string) (err error) { + var _p0 unsafe.Pointer + if len(moduleImage) > 0 { + _p0 = unsafe.Pointer(&moduleImage[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + var _p1 *byte + _p1, err = BytePtrFromString(params) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_INIT_MODULE, uintptr(_p0), uintptr(len(moduleImage)), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err error) { var _p0 *byte _p0, err = BytePtrFromString(pathname) @@ -955,6 +1050,22 @@ func Lsetxattr(path string, attr string, data []byte, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func MemfdCreate(name string, flags int) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(name) + if err != nil { + return + } + r0, _, e1 := Syscall(SYS_MEMFD_CREATE, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Mkdirat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -995,6 +1106,17 @@ func Nanosleep(time *Timespec, leftover *Timespec) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error) { + r0, _, e1 := Syscall6(SYS_PERF_EVENT_OPEN, uintptr(unsafe.Pointer(attr)), uintptr(pid), uintptr(cpu), uintptr(groupFd), uintptr(flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func PivotRoot(newroot string, putold string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(newroot) @@ -1083,7 +1205,7 @@ func Removexattr(path string, attr string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { +func Renameat2(olddirfd int, oldpath string, newdirfd int, newpath string, flags uint) (err error) { var _p0 *byte _p0, err = BytePtrFromString(oldpath) if err != nil { @@ -1094,7 +1216,7 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e if err != nil { return } - _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0) + _, _, e1 := Syscall6(SYS_RENAMEAT2, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } @@ -1238,8 +1360,30 @@ func Setxattr(path string, attr string, data []byte, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Signalfd(fd int, mask *Sigset_t, flags int) { + SyscallNoError(SYS_SIGNALFD4, uintptr(fd), uintptr(unsafe.Pointer(mask)), uintptr(flags)) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Statx(dirfd int, path string, flags int, mask int, stat *Statx_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_STATX, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), uintptr(mask), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Sync() { - Syscall(SYS_SYNC, 0, 0, 0) + SyscallNoError(SYS_SYNC, 0, 0, 0) return } @@ -1298,7 +1442,7 @@ func Times(tms *Tms) (ticks uintptr, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Umask(mask int) (oldmask int) { - r0, _, _ := RawSyscall(SYS_UMASK, uintptr(mask), 0, 0) + r0, _ := RawSyscallNoError(SYS_UMASK, uintptr(mask), 0, 0) oldmask = int(r0) return } @@ -1340,16 +1484,6 @@ func Unshare(flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Ustat(dev int, ubuf *Ustat_t) (err error) { - _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func write(fd int, p []byte) (n int, err error) { var _p0 unsafe.Pointer if len(p) > 0 { @@ -1509,6 +1643,42 @@ func Munlockall() (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func faccessat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Dup2(oldfd int, newfd int) (err error) { + _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func EpollCreate(size int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { var _p0 unsafe.Pointer if len(events) > 0 { @@ -1526,8 +1696,8 @@ func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Dup2(oldfd int, newfd int) (err error) { - _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0) +func Fadvise(fd int, offset int64, length int64, advice int) (err error) { + _, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0) if e1 != 0 { err = errnoErr(e1) } @@ -1556,6 +1726,21 @@ func Fstat(fd int, stat *Stat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_NEWFSTATAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fstatfs(fd int, buf *Statfs_t) (err error) { _, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(buf)), 0) if e1 != 0 { @@ -1577,7 +1762,7 @@ func Ftruncate(fd int, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getegid() (egid int) { - r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETEGID, 0, 0, 0) egid = int(r0) return } @@ -1585,7 +1770,7 @@ func Getegid() (egid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Geteuid() (euid int) { - r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETEUID, 0, 0, 0) euid = int(r0) return } @@ -1593,7 +1778,7 @@ func Geteuid() (euid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getgid() (gid int) { - r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETGID, 0, 0, 0) gid = int(r0) return } @@ -1611,7 +1796,7 @@ func Getrlimit(resource int, rlim *Rlimit) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getuid() (uid int) { - r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETUID, 0, 0, 0) uid = int(r0) return } @@ -1733,6 +1918,26 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Seek(fd int, offset int64, whence int) (off int64, err error) { r0, _, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence)) off = int64(r0) @@ -1887,8 +2092,13 @@ func Statfs(path string, buf *Statfs_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func SyncFileRange(fd int, off int64, n int64, flags int) (err error) { - _, _, e1 := Syscall6(SYS_SYNC_FILE_RANGE2, uintptr(fd), uintptr(off), uintptr(n), uintptr(flags), 0, 0) +func Truncate(path string, length int64) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0) if e1 != 0 { err = errnoErr(e1) } @@ -1897,13 +2107,8 @@ func SyncFileRange(fd int, off int64, n int64, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Truncate(path string, length int64) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0) +func Ustat(dev int, ubuf *Ustat_t) (err error) { + _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) if e1 != 0 { err = errnoErr(e1) } @@ -2102,6 +2307,21 @@ func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int6 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func futimesat(dirfd int, path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Gettimeofday(tv *Timeval) (err error) { _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0) if e1 != 0 { @@ -2138,6 +2358,21 @@ func Utime(path string, buf *Utimbuf) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func utimes(path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func pipe(p *[2]_C_int) (err error) { _, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0) if e1 != 0 { @@ -2166,3 +2401,28 @@ func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { } return } + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func syncFileRange2(fd int, flags int, off int64, n int64) (err error) { + _, _, e1 := Syscall6(SYS_SYNC_FILE_RANGE2, uintptr(fd), uintptr(flags), uintptr(off), uintptr(n), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(cmdline) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_KEXEC_FILE_LOAD, uintptr(kernelFd), uintptr(initrdFd), uintptr(cmdlineLen), uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go new file mode 100644 index 0000000000..996eba517a --- /dev/null +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go @@ -0,0 +1,2188 @@ +// go run mksyscall.go -tags linux,riscv64 syscall_linux.go syscall_linux_riscv64.go +// Code generated by the command above; see README.md. DO NOT EDIT. + +// +build linux,riscv64 + +package unix + +import ( + "syscall" + "unsafe" +) + +var _ syscall.Errno + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fchmodat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ioctl(fd int, req uint, arg uintptr) (err error) { + _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_LINKAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), uintptr(mode), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ppoll(fds *PollFd, nfds int, timeout *Timespec, sigmask *Sigset_t) (n int, err error) { + r0, _, e1 := Syscall6(SYS_PPOLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(buf) > 0 { + _p1 = unsafe.Pointer(&buf[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_READLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_SYMLINKAT, uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Unlinkat(dirfd int, path string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_UTIMENSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getcwd(buf []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_GETCWD, uintptr(_p0), uintptr(len(buf)), 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) { + r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0) + wpid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func KeyctlInt(cmd int, arg2 int, arg3 int, arg4 int, arg5 int) (ret int, err error) { + r0, _, e1 := Syscall6(SYS_KEYCTL, uintptr(cmd), uintptr(arg2), uintptr(arg3), uintptr(arg4), uintptr(arg5), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func KeyctlBuffer(cmd int, arg2 int, buf []byte, arg5 int) (ret int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_KEYCTL, uintptr(cmd), uintptr(arg2), uintptr(_p0), uintptr(len(buf)), uintptr(arg5), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func keyctlJoin(cmd int, arg2 string) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(arg2) + if err != nil { + return + } + r0, _, e1 := Syscall(SYS_KEYCTL, uintptr(cmd), uintptr(unsafe.Pointer(_p0)), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func keyctlSearch(cmd int, arg2 int, arg3 string, arg4 string, arg5 int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(arg3) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(arg4) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_KEYCTL, uintptr(cmd), uintptr(arg2), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(arg5), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func keyctlIOV(cmd int, arg2 int, payload []Iovec, arg5 int) (err error) { + var _p0 unsafe.Pointer + if len(payload) > 0 { + _p0 = unsafe.Pointer(&payload[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS_KEYCTL, uintptr(cmd), uintptr(arg2), uintptr(_p0), uintptr(len(payload)), uintptr(arg5), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func keyctlDH(cmd int, arg2 *KeyctlDHParams, buf []byte) (ret int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_KEYCTL, uintptr(cmd), uintptr(unsafe.Pointer(arg2)), uintptr(_p0), uintptr(len(buf)), 0, 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) { + _, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(arg) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_REBOOT, uintptr(magic1), uintptr(magic2), uintptr(cmd), uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func mount(source string, target string, fstype string, flags uintptr, data *byte) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(source) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(target) + if err != nil { + return + } + var _p2 *byte + _p2, err = BytePtrFromString(fstype) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_MOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(_p2)), uintptr(flags), uintptr(unsafe.Pointer(data)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Acct(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func AddKey(keyType string, description string, payload []byte, ringid int) (id int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(keyType) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(description) + if err != nil { + return + } + var _p2 unsafe.Pointer + if len(payload) > 0 { + _p2 = unsafe.Pointer(&payload[0]) + } else { + _p2 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_ADD_KEY, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(payload)), uintptr(ringid), 0) + id = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Adjtimex(buf *Timex) (state int, err error) { + r0, _, e1 := Syscall(SYS_ADJTIMEX, uintptr(unsafe.Pointer(buf)), 0, 0) + state = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chdir(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chroot(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ClockGetres(clockid int32, res *Timespec) (err error) { + _, _, e1 := Syscall(SYS_CLOCK_GETRES, uintptr(clockid), uintptr(unsafe.Pointer(res)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ClockGettime(clockid int32, time *Timespec) (err error) { + _, _, e1 := Syscall(SYS_CLOCK_GETTIME, uintptr(clockid), uintptr(unsafe.Pointer(time)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ClockNanosleep(clockid int32, flags int, request *Timespec, remain *Timespec) (err error) { + _, _, e1 := Syscall6(SYS_CLOCK_NANOSLEEP, uintptr(clockid), uintptr(flags), uintptr(unsafe.Pointer(request)), uintptr(unsafe.Pointer(remain)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Close(fd int) (err error) { + _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func CopyFileRange(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, err error) { + r0, _, e1 := Syscall6(SYS_COPY_FILE_RANGE, uintptr(rfd), uintptr(unsafe.Pointer(roff)), uintptr(wfd), uintptr(unsafe.Pointer(woff)), uintptr(len), uintptr(flags)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func DeleteModule(name string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(name) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_DELETE_MODULE, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Dup(oldfd int) (fd int, err error) { + r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Dup3(oldfd int, newfd int, flags int) (err error) { + _, _, e1 := Syscall(SYS_DUP3, uintptr(oldfd), uintptr(newfd), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func EpollCreate1(flag int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) { + _, _, e1 := RawSyscall6(SYS_EPOLL_CTL, uintptr(epfd), uintptr(op), uintptr(fd), uintptr(unsafe.Pointer(event)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Eventfd(initval uint, flags int) (fd int, err error) { + r0, _, e1 := Syscall(SYS_EVENTFD2, uintptr(initval), uintptr(flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Exit(code int) { + SyscallNoError(SYS_EXIT_GROUP, uintptr(code), 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fallocate(fd int, mode uint32, off int64, len int64) (err error) { + _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(len), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchdir(fd int) (err error) { + _, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchmod(fd int, mode uint32) (err error) { + _, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fcntl(fd int, cmd int, arg int) (val int, err error) { + r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg)) + val = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fdatasync(fd int) (err error) { + _, _, e1 := Syscall(SYS_FDATASYNC, uintptr(fd), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fgetxattr(fd int, attr string, dest []byte) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(dest) > 0 { + _p1 = unsafe.Pointer(&dest[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_FGETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)), 0, 0) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func FinitModule(fd int, params string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(params) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FINIT_MODULE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Flistxattr(fd int, dest []byte) (sz int, err error) { + var _p0 unsafe.Pointer + if len(dest) > 0 { + _p0 = unsafe.Pointer(&dest[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_FLISTXATTR, uintptr(fd), uintptr(_p0), uintptr(len(dest))) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Flock(fd int, how int) (err error) { + _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fremovexattr(fd int, attr string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FREMOVEXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fsetxattr(fd int, attr string, dest []byte, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(dest) > 0 { + _p1 = unsafe.Pointer(&dest[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS_FSETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fsync(fd int) (err error) { + _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getdents(fd int, buf []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpgid(pid int) (pgid int, err error) { + r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0) + pgid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpid() (pid int) { + r0, _ := RawSyscallNoError(SYS_GETPID, 0, 0, 0) + pid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getppid() (ppid int) { + r0, _ := RawSyscallNoError(SYS_GETPPID, 0, 0, 0) + ppid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpriority(which int, who int) (prio int, err error) { + r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0) + prio = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getrandom(buf []byte, flags int) (n int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_GETRANDOM, uintptr(_p0), uintptr(len(buf)), uintptr(flags)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getrusage(who int, rusage *Rusage) (err error) { + _, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getsid(pid int) (sid int, err error) { + r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0) + sid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Gettid() (tid int) { + r0, _ := RawSyscallNoError(SYS_GETTID, 0, 0, 0) + tid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getxattr(path string, attr string, dest []byte) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p2 unsafe.Pointer + if len(dest) > 0 { + _p2 = unsafe.Pointer(&dest[0]) + } else { + _p2 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(dest)), 0, 0) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func InitModule(moduleImage []byte, params string) (err error) { + var _p0 unsafe.Pointer + if len(moduleImage) > 0 { + _p0 = unsafe.Pointer(&moduleImage[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + var _p1 *byte + _p1, err = BytePtrFromString(params) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_INIT_MODULE, uintptr(_p0), uintptr(len(moduleImage)), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(pathname) + if err != nil { + return + } + r0, _, e1 := Syscall(SYS_INOTIFY_ADD_WATCH, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(mask)) + watchdesc = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func InotifyInit1(flags int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT1, uintptr(flags), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func InotifyRmWatch(fd int, watchdesc uint32) (success int, err error) { + r0, _, e1 := RawSyscall(SYS_INOTIFY_RM_WATCH, uintptr(fd), uintptr(watchdesc), 0) + success = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Kill(pid int, sig syscall.Signal) (err error) { + _, _, e1 := RawSyscall(SYS_KILL, uintptr(pid), uintptr(sig), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Klogctl(typ int, buf []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_SYSLOG, uintptr(typ), uintptr(_p0), uintptr(len(buf))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Lgetxattr(path string, attr string, dest []byte) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p2 unsafe.Pointer + if len(dest) > 0 { + _p2 = unsafe.Pointer(&dest[0]) + } else { + _p2 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_LGETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(dest)), 0, 0) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Listxattr(path string, dest []byte) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(dest) > 0 { + _p1 = unsafe.Pointer(&dest[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_LISTXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest))) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Llistxattr(path string, dest []byte) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(dest) > 0 { + _p1 = unsafe.Pointer(&dest[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_LLISTXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest))) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Lremovexattr(path string, attr string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_LREMOVEXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Lsetxattr(path string, attr string, data []byte, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p2 unsafe.Pointer + if len(data) > 0 { + _p2 = unsafe.Pointer(&data[0]) + } else { + _p2 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS_LSETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(data)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func MemfdCreate(name string, flags int) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(name) + if err != nil { + return + } + r0, _, e1 := Syscall(SYS_MEMFD_CREATE, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mkdirat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_MKNODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Nanosleep(time *Timespec, leftover *Timespec) (err error) { + _, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error) { + r0, _, e1 := Syscall6(SYS_PERF_EVENT_OPEN, uintptr(unsafe.Pointer(attr)), uintptr(pid), uintptr(cpu), uintptr(groupFd), uintptr(flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func PivotRoot(newroot string, putold string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(newroot) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(putold) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_PIVOT_ROOT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { + _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Prctl(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uintptr) (err error) { + _, _, e1 := Syscall6(SYS_PRCTL, uintptr(option), uintptr(arg2), uintptr(arg3), uintptr(arg4), uintptr(arg5), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pselect(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *Sigset_t) (n int, err error) { + r0, _, e1 := Syscall6(SYS_PSELECT6, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func read(fd int, p []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Removexattr(path string, attr string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_REMOVEXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Renameat2(olddirfd int, oldpath string, newdirfd int, newpath string, flags uint) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_RENAMEAT2, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func RequestKey(keyType string, description string, callback string, destRingid int) (id int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(keyType) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(description) + if err != nil { + return + } + var _p2 *byte + _p2, err = BytePtrFromString(callback) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_REQUEST_KEY, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(_p2)), uintptr(destRingid), 0, 0) + id = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setdomainname(p []byte) (err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_SETDOMAINNAME, uintptr(_p0), uintptr(len(p)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Sethostname(p []byte) (err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_SETHOSTNAME, uintptr(_p0), uintptr(len(p)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setpgid(pid int, pgid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setsid() (pid int, err error) { + r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0) + pid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Settimeofday(tv *Timeval) (err error) { + _, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setns(fd int, nstype int) (err error) { + _, _, e1 := Syscall(SYS_SETNS, uintptr(fd), uintptr(nstype), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setpriority(which int, who int, prio int) (err error) { + _, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setxattr(path string, attr string, data []byte, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p2 unsafe.Pointer + if len(data) > 0 { + _p2 = unsafe.Pointer(&data[0]) + } else { + _p2 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(data)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Signalfd(fd int, mask *Sigset_t, flags int) { + SyscallNoError(SYS_SIGNALFD4, uintptr(fd), uintptr(unsafe.Pointer(mask)), uintptr(flags)) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Statx(dirfd int, path string, flags int, mask int, stat *Statx_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_STATX, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), uintptr(mask), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Sync() { + SyscallNoError(SYS_SYNC, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Syncfs(fd int) (err error) { + _, _, e1 := Syscall(SYS_SYNCFS, uintptr(fd), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Sysinfo(info *Sysinfo_t) (err error) { + _, _, e1 := RawSyscall(SYS_SYSINFO, uintptr(unsafe.Pointer(info)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) { + r0, _, e1 := Syscall6(SYS_TEE, uintptr(rfd), uintptr(wfd), uintptr(len), uintptr(flags), 0, 0) + n = int64(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Tgkill(tgid int, tid int, sig syscall.Signal) (err error) { + _, _, e1 := RawSyscall(SYS_TGKILL, uintptr(tgid), uintptr(tid), uintptr(sig)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Times(tms *Tms) (ticks uintptr, err error) { + r0, _, e1 := RawSyscall(SYS_TIMES, uintptr(unsafe.Pointer(tms)), 0, 0) + ticks = uintptr(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Umask(mask int) (oldmask int) { + r0, _ := RawSyscallNoError(SYS_UMASK, uintptr(mask), 0, 0) + oldmask = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Uname(buf *Utsname) (err error) { + _, _, e1 := RawSyscall(SYS_UNAME, uintptr(unsafe.Pointer(buf)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Unmount(target string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(target) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Unshare(flags int) (err error) { + _, _, e1 := Syscall(SYS_UNSHARE, uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func write(fd int, p []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func exitThread(code int) (err error) { + _, _, e1 := Syscall(SYS_EXIT, uintptr(code), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func readlen(fd int, p *byte, np int) (n int, err error) { + r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func writelen(fd int, p *byte, np int) (n int, err error) { + r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func munmap(addr uintptr, length uintptr) (err error) { + _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Madvise(b []byte, advice int) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(advice)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mprotect(b []byte, prot int) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mlock(b []byte) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mlockall(flags int) (err error) { + _, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Msync(b []byte, flags int) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MSYNC, uintptr(_p0), uintptr(len(b)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Munlock(b []byte) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Munlockall() (err error) { + _, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func faccessat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { + var _p0 unsafe.Pointer + if len(events) > 0 { + _p0 = unsafe.Pointer(&events[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_EPOLL_PWAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fadvise(fd int, offset int64, length int64, advice int) (err error) { + _, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchown(fd int, uid int, gid int) (err error) { + _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstat(fd int, stat *Stat_t) (err error) { + _, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FSTATAT, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstatfs(fd int, buf *Statfs_t) (err error) { + _, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(buf)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Ftruncate(fd int, length int64) (err error) { + _, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getegid() (egid int) { + r0, _ := RawSyscallNoError(SYS_GETEGID, 0, 0, 0) + egid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Geteuid() (euid int) { + r0, _ := RawSyscallNoError(SYS_GETEUID, 0, 0, 0) + euid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getgid() (gid int) { + r0, _ := RawSyscallNoError(SYS_GETGID, 0, 0, 0) + gid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getrlimit(resource int, rlim *Rlimit) (err error) { + _, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getuid() (uid int) { + r0, _ := RawSyscallNoError(SYS_GETUID, 0, 0, 0) + uid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Listen(s int, n int) (err error) { + _, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(n), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pread(fd int, p []byte, offset int64) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_PREAD64, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pwrite(fd int, p []byte, offset int64) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_PWRITE64, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Seek(fd int, offset int64, whence int) (off int64, err error) { + r0, _, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence)) + off = int64(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { + r0, _, e1 := Syscall6(SYS_SENDFILE, uintptr(outfd), uintptr(infd), uintptr(unsafe.Pointer(offset)), uintptr(count), 0, 0) + written = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setfsgid(gid int) (err error) { + _, _, e1 := Syscall(SYS_SETFSGID, uintptr(gid), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setfsuid(uid int) (err error) { + _, _, e1 := Syscall(SYS_SETFSUID, uintptr(uid), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setregid(rgid int, egid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setresgid(rgid int, egid int, sgid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETRESGID, uintptr(rgid), uintptr(egid), uintptr(sgid)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setresuid(ruid int, euid int, suid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETRESUID, uintptr(ruid), uintptr(euid), uintptr(suid)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setrlimit(resource int, rlim *Rlimit) (err error) { + _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setreuid(ruid int, euid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Shutdown(fd int, how int) (err error) { + _, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(fd), uintptr(how), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error) { + r0, _, e1 := Syscall6(SYS_SPLICE, uintptr(rfd), uintptr(unsafe.Pointer(roff)), uintptr(wfd), uintptr(unsafe.Pointer(woff)), uintptr(len), uintptr(flags)) + n = int64(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Statfs(path string, buf *Statfs_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func SyncFileRange(fd int, off int64, n int64, flags int) (err error) { + _, _, e1 := Syscall6(SYS_SYNC_FILE_RANGE, uintptr(fd), uintptr(off), uintptr(n), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Truncate(path string, length int64) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { + r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) { + r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { + _, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { + _, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getgroups(n int, list *_Gid_t) (nn int, err error) { + r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0) + nn = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setgroups(n int, list *_Gid_t) (err error) { + _, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) { + _, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) { + _, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func socket(domain int, typ int, proto int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto)) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) { + _, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { + _, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { + _, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) { + r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) { + r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) { + r0, _, e1 := Syscall6(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(offset)) + xaddr = uintptr(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Gettimeofday(tv *Timeval) (err error) { + _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func pipe2(p *[2]_C_int, flags int) (err error) { + _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go index 169321273d..cb9072a33a 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go @@ -1,4 +1,4 @@ -// mksyscall.pl -tags linux,s390x syscall_linux.go syscall_linux_s390x.go +// go run mksyscall.go -tags linux,s390x syscall_linux.go syscall_linux_s390x.go // Code generated by the command above; see README.md. DO NOT EDIT. // +build linux,s390x @@ -143,21 +143,6 @@ func Unlinkat(dirfd int, path string, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func utimes(path string, times *[2]Timeval) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -173,16 +158,6 @@ func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) { - _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times))) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Getcwd(buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { @@ -442,6 +417,16 @@ func Chroot(path string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func ClockGetres(clockid int32, res *Timespec) (err error) { + _, _, e1 := Syscall(SYS_CLOCK_GETRES, uintptr(clockid), uintptr(unsafe.Pointer(res)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func ClockGettime(clockid int32, time *Timespec) (err error) { _, _, e1 := Syscall(SYS_CLOCK_GETTIME, uintptr(clockid), uintptr(unsafe.Pointer(time)), 0) if e1 != 0 { @@ -452,6 +437,16 @@ func ClockGettime(clockid int32, time *Timespec) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func ClockNanosleep(clockid int32, flags int, request *Timespec, remain *Timespec) (err error) { + _, _, e1 := Syscall6(SYS_CLOCK_NANOSLEEP, uintptr(clockid), uintptr(flags), uintptr(unsafe.Pointer(request)), uintptr(unsafe.Pointer(remain)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Close(fd int) (err error) { _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0) if e1 != 0 { @@ -473,6 +468,21 @@ func CopyFileRange(rfd int, roff *int64, wfd int, woff *int64, len int, flags in // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func DeleteModule(name string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(name) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_DELETE_MODULE, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Dup(oldfd int) (fd int, err error) { r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), 0, 0) fd = int(r0) @@ -494,17 +504,6 @@ func Dup3(oldfd int, newfd int, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollCreate(size int) (fd int, err error) { - r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func EpollCreate1(flag int) (fd int, err error) { r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0) fd = int(r0) @@ -538,22 +537,7 @@ func Eventfd(initval uint, flags int) (fd int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Exit(code int) { - Syscall(SYS_EXIT_GROUP, uintptr(code), 0, 0) - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } + SyscallNoError(SYS_EXIT_GROUP, uintptr(code), 0, 0) return } @@ -625,6 +609,60 @@ func Fdatasync(fd int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fgetxattr(fd int, attr string, dest []byte) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(dest) > 0 { + _p1 = unsafe.Pointer(&dest[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_FGETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)), 0, 0) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func FinitModule(fd int, params string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(params) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FINIT_MODULE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Flistxattr(fd int, dest []byte) (sz int, err error) { + var _p0 unsafe.Pointer + if len(dest) > 0 { + _p0 = unsafe.Pointer(&dest[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_FLISTXATTR, uintptr(fd), uintptr(_p0), uintptr(len(dest))) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Flock(fd int, how int) (err error) { _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0) if e1 != 0 { @@ -635,6 +673,42 @@ func Flock(fd int, how int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fremovexattr(fd int, attr string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FREMOVEXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fsetxattr(fd int, attr string, dest []byte, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(dest) > 0 { + _p1 = unsafe.Pointer(&dest[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS_FSETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fsync(fd int) (err error) { _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0) if e1 != 0 { @@ -674,7 +748,7 @@ func Getpgid(pid int) (pgid int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpid() (pid int) { - r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETPID, 0, 0, 0) pid = int(r0) return } @@ -682,7 +756,7 @@ func Getpid() (pid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getppid() (ppid int) { - r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETPPID, 0, 0, 0) ppid = int(r0) return } @@ -739,7 +813,7 @@ func Getsid(pid int) (sid int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Gettid() (tid int) { - r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETTID, 0, 0, 0) tid = int(r0) return } @@ -773,6 +847,27 @@ func Getxattr(path string, attr string, dest []byte) (sz int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func InitModule(moduleImage []byte, params string) (err error) { + var _p0 unsafe.Pointer + if len(moduleImage) > 0 { + _p0 = unsafe.Pointer(&moduleImage[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + var _p1 *byte + _p1, err = BytePtrFromString(params) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_INIT_MODULE, uintptr(_p0), uintptr(len(moduleImage)), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err error) { var _p0 *byte _p0, err = BytePtrFromString(pathname) @@ -955,6 +1050,22 @@ func Lsetxattr(path string, attr string, data []byte, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func MemfdCreate(name string, flags int) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(name) + if err != nil { + return + } + r0, _, e1 := Syscall(SYS_MEMFD_CREATE, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Mkdirat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -995,6 +1106,17 @@ func Nanosleep(time *Timespec, leftover *Timespec) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error) { + r0, _, e1 := Syscall6(SYS_PERF_EVENT_OPEN, uintptr(unsafe.Pointer(attr)), uintptr(pid), uintptr(cpu), uintptr(groupFd), uintptr(flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func PivotRoot(newroot string, putold string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(newroot) @@ -1083,7 +1205,7 @@ func Removexattr(path string, attr string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { +func Renameat2(olddirfd int, oldpath string, newdirfd int, newpath string, flags uint) (err error) { var _p0 *byte _p0, err = BytePtrFromString(oldpath) if err != nil { @@ -1094,7 +1216,7 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e if err != nil { return } - _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0) + _, _, e1 := Syscall6(SYS_RENAMEAT2, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) if e1 != 0 { err = errnoErr(e1) } @@ -1238,8 +1360,30 @@ func Setxattr(path string, attr string, data []byte, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Signalfd(fd int, mask *Sigset_t, flags int) { + SyscallNoError(SYS_SIGNALFD4, uintptr(fd), uintptr(unsafe.Pointer(mask)), uintptr(flags)) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Statx(dirfd int, path string, flags int, mask int, stat *Statx_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_STATX, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), uintptr(mask), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Sync() { - Syscall(SYS_SYNC, 0, 0, 0) + SyscallNoError(SYS_SYNC, 0, 0, 0) return } @@ -1298,7 +1442,7 @@ func Times(tms *Tms) (ticks uintptr, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Umask(mask int) (oldmask int) { - r0, _, _ := RawSyscall(SYS_UMASK, uintptr(mask), 0, 0) + r0, _ := RawSyscallNoError(SYS_UMASK, uintptr(mask), 0, 0) oldmask = int(r0) return } @@ -1340,16 +1484,6 @@ func Unshare(flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Ustat(dev int, ubuf *Ustat_t) (err error) { - _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func write(fd int, p []byte) (n int, err error) { var _p0 unsafe.Pointer if len(p) > 0 { @@ -1509,6 +1643,21 @@ func Munlockall() (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func faccessat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Dup2(oldfd int, newfd int) (err error) { _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0) if e1 != 0 { @@ -1519,6 +1668,17 @@ func Dup2(oldfd int, newfd int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func EpollCreate(size int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { var _p0 unsafe.Pointer if len(events) > 0 { @@ -1566,6 +1726,21 @@ func Fstat(fd int, stat *Stat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_NEWFSTATAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fstatfs(fd int, buf *Statfs_t) (err error) { _, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(buf)), 0) if e1 != 0 { @@ -1587,7 +1762,7 @@ func Ftruncate(fd int, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getegid() (egid int) { - r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETEGID, 0, 0, 0) egid = int(r0) return } @@ -1595,7 +1770,7 @@ func Getegid() (egid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Geteuid() (euid int) { - r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETEUID, 0, 0, 0) euid = int(r0) return } @@ -1603,7 +1778,7 @@ func Geteuid() (euid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getgid() (gid int) { - r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETGID, 0, 0, 0) gid = int(r0) return } @@ -1621,7 +1796,7 @@ func Getrlimit(resource int, rlim *Rlimit) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getuid() (uid int) { - r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETUID, 0, 0, 0) uid = int(r0) return } @@ -1713,6 +1888,26 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Seek(fd int, offset int64, whence int) (off int64, err error) { r0, _, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence)) off = int64(r0) @@ -1882,6 +2077,16 @@ func Truncate(path string, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Ustat(dev int, ubuf *Ustat_t) (err error) { + _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func getgroups(n int, list *_Gid_t) (nn int, err error) { r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0) nn = int(r0) @@ -1903,6 +2108,21 @@ func setgroups(n int, list *_Gid_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func futimesat(dirfd int, path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Gettimeofday(tv *Timeval) (err error) { _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0) if e1 != 0 { @@ -1928,6 +2148,21 @@ func Utime(path string, buf *Utimbuf) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func utimes(path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func pipe2(p *[2]_C_int, flags int) (err error) { _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0) if e1 != 0 { @@ -1946,3 +2181,18 @@ func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { } return } + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(cmdline) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_KEXEC_FILE_LOAD, uintptr(kernelFd), uintptr(initrdFd), uintptr(cmdlineLen), uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go index 2dd98434ea..5e48a1001b 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go @@ -1,4 +1,4 @@ -// mksyscall.pl -tags linux,sparc64 syscall_linux.go syscall_linux_sparc64.go +// go run mksyscall.go -tags linux,sparc64 syscall_linux.go syscall_linux_sparc64.go // Code generated by the command above; see README.md. DO NOT EDIT. // +build linux,sparc64 @@ -14,6 +14,31 @@ var _ syscall.Errno // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func fchmodat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ioctl(fd int, req uint, arg uintptr) (err error) { + _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(oldpath) @@ -118,21 +143,6 @@ func Unlinkat(dirfd int, path string, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func utimes(path string, times *[2]Timeval) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -148,16 +158,6 @@ func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) { - _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times))) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Getcwd(buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { @@ -186,6 +186,104 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func KeyctlInt(cmd int, arg2 int, arg3 int, arg4 int, arg5 int) (ret int, err error) { + r0, _, e1 := Syscall6(SYS_KEYCTL, uintptr(cmd), uintptr(arg2), uintptr(arg3), uintptr(arg4), uintptr(arg5), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func KeyctlBuffer(cmd int, arg2 int, buf []byte, arg5 int) (ret int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_KEYCTL, uintptr(cmd), uintptr(arg2), uintptr(_p0), uintptr(len(buf)), uintptr(arg5), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func keyctlJoin(cmd int, arg2 string) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(arg2) + if err != nil { + return + } + r0, _, e1 := Syscall(SYS_KEYCTL, uintptr(cmd), uintptr(unsafe.Pointer(_p0)), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func keyctlSearch(cmd int, arg2 int, arg3 string, arg4 string, arg5 int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(arg3) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(arg4) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_KEYCTL, uintptr(cmd), uintptr(arg2), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(arg5), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func keyctlIOV(cmd int, arg2 int, payload []Iovec, arg5 int) (err error) { + var _p0 unsafe.Pointer + if len(payload) > 0 { + _p0 = unsafe.Pointer(&payload[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS_KEYCTL, uintptr(cmd), uintptr(arg2), uintptr(_p0), uintptr(len(payload)), uintptr(arg5), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func keyctlDH(cmd int, arg2 *KeyctlDHParams, buf []byte) (ret int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_KEYCTL, uintptr(cmd), uintptr(unsafe.Pointer(arg2)), uintptr(_p0), uintptr(len(buf)), 0, 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) { _, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0) if e1 != 0 { @@ -251,6 +349,33 @@ func Acct(path string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func AddKey(keyType string, description string, payload []byte, ringid int) (id int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(keyType) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(description) + if err != nil { + return + } + var _p2 unsafe.Pointer + if len(payload) > 0 { + _p2 = unsafe.Pointer(&payload[0]) + } else { + _p2 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_ADD_KEY, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(payload)), uintptr(ringid), 0) + id = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Adjtimex(buf *Timex) (state int, err error) { r0, _, e1 := Syscall(SYS_ADJTIMEX, uintptr(unsafe.Pointer(buf)), 0, 0) state = int(r0) @@ -292,6 +417,16 @@ func Chroot(path string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func ClockGetres(clockid int32, res *Timespec) (err error) { + _, _, e1 := Syscall(SYS_CLOCK_GETRES, uintptr(clockid), uintptr(unsafe.Pointer(res)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func ClockGettime(clockid int32, time *Timespec) (err error) { _, _, e1 := Syscall(SYS_CLOCK_GETTIME, uintptr(clockid), uintptr(unsafe.Pointer(time)), 0) if e1 != 0 { @@ -302,6 +437,16 @@ func ClockGettime(clockid int32, time *Timespec) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func ClockNanosleep(clockid int32, flags int, request *Timespec, remain *Timespec) (err error) { + _, _, e1 := Syscall6(SYS_CLOCK_NANOSLEEP, uintptr(clockid), uintptr(flags), uintptr(unsafe.Pointer(request)), uintptr(unsafe.Pointer(remain)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Close(fd int) (err error) { _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0) if e1 != 0 { @@ -323,6 +468,21 @@ func CopyFileRange(rfd int, roff *int64, wfd int, woff *int64, len int, flags in // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func DeleteModule(name string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(name) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_DELETE_MODULE, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Dup(oldfd int) (fd int, err error) { r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), 0, 0) fd = int(r0) @@ -344,17 +504,6 @@ func Dup3(oldfd int, newfd int, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollCreate(size int) (fd int, err error) { - r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func EpollCreate1(flag int) (fd int, err error) { r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0) fd = int(r0) @@ -376,23 +525,19 @@ func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Exit(code int) { - Syscall(SYS_EXIT_GROUP, uintptr(code), 0, 0) +func Eventfd(initval uint, flags int) (fd int, err error) { + r0, _, e1 := Syscall(SYS_EVENTFD2, uintptr(initval), uintptr(flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } return } // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } +func Exit(code int) { + SyscallNoError(SYS_EXIT_GROUP, uintptr(code), 0, 0) return } @@ -428,21 +573,6 @@ func Fchmod(fd int, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -479,6 +609,60 @@ func Fdatasync(fd int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fgetxattr(fd int, attr string, dest []byte) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(dest) > 0 { + _p1 = unsafe.Pointer(&dest[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_FGETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)), 0, 0) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func FinitModule(fd int, params string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(params) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FINIT_MODULE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Flistxattr(fd int, dest []byte) (sz int, err error) { + var _p0 unsafe.Pointer + if len(dest) > 0 { + _p0 = unsafe.Pointer(&dest[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_FLISTXATTR, uintptr(fd), uintptr(_p0), uintptr(len(dest))) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Flock(fd int, how int) (err error) { _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0) if e1 != 0 { @@ -489,6 +673,42 @@ func Flock(fd int, how int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fremovexattr(fd int, attr string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FREMOVEXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fsetxattr(fd int, attr string, dest []byte, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(dest) > 0 { + _p1 = unsafe.Pointer(&dest[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS_FSETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fsync(fd int) (err error) { _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0) if e1 != 0 { @@ -528,7 +748,7 @@ func Getpgid(pid int) (pgid int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpid() (pid int) { - r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETPID, 0, 0, 0) pid = int(r0) return } @@ -536,7 +756,7 @@ func Getpid() (pid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getppid() (ppid int) { - r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETPPID, 0, 0, 0) ppid = int(r0) return } @@ -593,7 +813,7 @@ func Getsid(pid int) (sid int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Gettid() (tid int) { - r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETTID, 0, 0, 0) tid = int(r0) return } @@ -627,6 +847,27 @@ func Getxattr(path string, attr string, dest []byte) (sz int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func InitModule(moduleImage []byte, params string) (err error) { + var _p0 unsafe.Pointer + if len(moduleImage) > 0 { + _p0 = unsafe.Pointer(&moduleImage[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + var _p1 *byte + _p1, err = BytePtrFromString(params) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_INIT_MODULE, uintptr(_p0), uintptr(len(moduleImage)), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err error) { var _p0 *byte _p0, err = BytePtrFromString(pathname) @@ -692,6 +933,33 @@ func Klogctl(typ int, buf []byte) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Lgetxattr(path string, attr string, dest []byte) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p2 unsafe.Pointer + if len(dest) > 0 { + _p2 = unsafe.Pointer(&dest[0]) + } else { + _p2 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_LGETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(dest)), 0, 0) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Listxattr(path string, dest []byte) (sz int, err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -714,6 +982,90 @@ func Listxattr(path string, dest []byte) (sz int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Llistxattr(path string, dest []byte) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(dest) > 0 { + _p1 = unsafe.Pointer(&dest[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_LLISTXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest))) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Lremovexattr(path string, attr string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_LREMOVEXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Lsetxattr(path string, attr string, data []byte, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p2 unsafe.Pointer + if len(data) > 0 { + _p2 = unsafe.Pointer(&data[0]) + } else { + _p2 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS_LSETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(data)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func MemfdCreate(name string, flags int) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(name) + if err != nil { + return + } + r0, _, e1 := Syscall(SYS_MEMFD_CREATE, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Mkdirat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -754,6 +1106,17 @@ func Nanosleep(time *Timespec, leftover *Timespec) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error) { + r0, _, e1 := Syscall6(SYS_PERF_EVENT_OPEN, uintptr(unsafe.Pointer(attr)), uintptr(pid), uintptr(cpu), uintptr(groupFd), uintptr(flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func PivotRoot(newroot string, putold string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(newroot) @@ -794,6 +1157,17 @@ func Prctl(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uintptr) ( // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Pselect(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *Sigset_t) (n int, err error) { + r0, _, e1 := Syscall6(SYS_PSELECT6, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func read(fd int, p []byte) (n int, err error) { var _p0 unsafe.Pointer if len(p) > 0 { @@ -831,7 +1205,7 @@ func Removexattr(path string, attr string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { +func Renameat2(olddirfd int, oldpath string, newdirfd int, newpath string, flags uint) (err error) { var _p0 *byte _p0, err = BytePtrFromString(oldpath) if err != nil { @@ -842,7 +1216,33 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e if err != nil { return } - _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0) + _, _, e1 := Syscall6(SYS_RENAMEAT2, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func RequestKey(keyType string, description string, callback string, destRingid int) (id int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(keyType) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(description) + if err != nil { + return + } + var _p2 *byte + _p2, err = BytePtrFromString(callback) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_REQUEST_KEY, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(_p2)), uintptr(destRingid), 0, 0) + id = int(r0) if e1 != 0 { err = errnoErr(e1) } @@ -960,8 +1360,40 @@ func Setxattr(path string, attr string, data []byte, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Signalfd(fd int, mask *Sigset_t, flags int) { + SyscallNoError(SYS_SIGNALFD4, uintptr(fd), uintptr(unsafe.Pointer(mask)), uintptr(flags)) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Statx(dirfd int, path string, flags int, mask int, stat *Statx_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_STATX, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), uintptr(mask), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Sync() { - Syscall(SYS_SYNC, 0, 0, 0) + SyscallNoError(SYS_SYNC, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Syncfs(fd int) (err error) { + _, _, e1 := Syscall(SYS_SYNCFS, uintptr(fd), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } return } @@ -1010,7 +1442,7 @@ func Times(tms *Tms) (ticks uintptr, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Umask(mask int) (oldmask int) { - r0, _, _ := RawSyscall(SYS_UMASK, uintptr(mask), 0, 0) + r0, _ := RawSyscallNoError(SYS_UMASK, uintptr(mask), 0, 0) oldmask = int(r0) return } @@ -1052,16 +1484,6 @@ func Unshare(flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Ustat(dev int, ubuf *Ustat_t) (err error) { - _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func write(fd int, p []byte) (n int, err error) { var _p0 unsafe.Pointer if len(p) > 0 { @@ -1169,14 +1591,8 @@ func Mlock(b []byte) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Munlock(b []byte) (err error) { - var _p0 unsafe.Pointer - if len(b) > 0 { - _p0 = unsafe.Pointer(&b[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - _, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0) +func Mlockall(flags int) (err error) { + _, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0) if e1 != 0 { err = errnoErr(e1) } @@ -1185,8 +1601,30 @@ func Munlock(b []byte) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Mlockall(flags int) (err error) { - _, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0) +func Msync(b []byte, flags int) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MSYNC, uintptr(_p0), uintptr(len(b)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Munlock(b []byte) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0) if e1 != 0 { err = errnoErr(e1) } @@ -1205,6 +1643,21 @@ func Munlockall() (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func faccessat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { var _p0 unsafe.Pointer if len(events) > 0 { @@ -1222,6 +1675,16 @@ func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fadvise(fd int, offset int64, length int64, advice int) (err error) { + _, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Dup2(oldfd int, newfd int) (err error) { _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0) if e1 != 0 { @@ -1252,6 +1715,21 @@ func Fstat(fd int, stat *Stat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FSTATAT64, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fstatfs(fd int, buf *Statfs_t) (err error) { _, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(buf)), 0) if e1 != 0 { @@ -1273,7 +1751,7 @@ func Ftruncate(fd int, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getegid() (egid int) { - r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETEGID, 0, 0, 0) egid = int(r0) return } @@ -1281,7 +1759,7 @@ func Getegid() (egid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Geteuid() (euid int) { - r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETEUID, 0, 0, 0) euid = int(r0) return } @@ -1289,7 +1767,7 @@ func Geteuid() (euid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getgid() (gid int) { - r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETGID, 0, 0, 0) gid = int(r0) return } @@ -1307,7 +1785,7 @@ func Getrlimit(resource int, rlim *Rlimit) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getuid() (uid int) { - r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETUID, 0, 0, 0) uid = int(r0) return } @@ -1409,6 +1887,26 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Seek(fd int, offset int64, whence int) (off int64, err error) { r0, _, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence)) off = int64(r0) @@ -1778,6 +2276,21 @@ func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int6 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func futimesat(dirfd int, path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Gettimeofday(tv *Timeval) (err error) { _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0) if e1 != 0 { @@ -1803,6 +2316,21 @@ func Utime(path string, buf *Utimbuf) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func utimes(path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func pipe(p *[2]_C_int) (err error) { _, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0) if e1 != 0 { diff --git a/vendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go b/vendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go index 04a1ace9d0..642db7670a 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go @@ -1,4 +1,4 @@ -// mksyscall.pl -l32 -netbsd -tags netbsd,386 syscall_bsd.go syscall_netbsd.go syscall_netbsd_386.go +// go run mksyscall.go -l32 -netbsd -tags netbsd,386 syscall_bsd.go syscall_netbsd.go syscall_netbsd_386.go // Code generated by the command above; see README.md. DO NOT EDIT. // +build netbsd,386 @@ -406,6 +406,23 @@ func getdents(fd int, buf []byte) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Getcwd(buf []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS___GETCWD, uintptr(_p0), uintptr(len(buf)), 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func ioctl(fd int, req uint, arg uintptr) (err error) { _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg)) if e1 != 0 { @@ -554,6 +571,245 @@ func Exit(code int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func ExtattrGetFd(fd int, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attrname) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_GET_FD, uintptr(fd), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p0)), uintptr(data), uintptr(nbytes), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrSetFd(fd int, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attrname) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_SET_FD, uintptr(fd), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p0)), uintptr(data), uintptr(nbytes), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrDeleteFd(fd int, attrnamespace int, attrname string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attrname) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_EXTATTR_DELETE_FD, uintptr(fd), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p0))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrListFd(fd int, attrnamespace int, data uintptr, nbytes int) (ret int, err error) { + r0, _, e1 := Syscall6(SYS_EXTATTR_LIST_FD, uintptr(fd), uintptr(attrnamespace), uintptr(data), uintptr(nbytes), 0, 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrGetFile(file string, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(file) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attrname) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_GET_FILE, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p1)), uintptr(data), uintptr(nbytes), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrSetFile(file string, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(file) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attrname) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_SET_FILE, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p1)), uintptr(data), uintptr(nbytes), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrDeleteFile(file string, attrnamespace int, attrname string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(file) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attrname) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_EXTATTR_DELETE_FILE, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrListFile(file string, attrnamespace int, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(file) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_LIST_FILE, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(data), uintptr(nbytes), 0, 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrGetLink(link string, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(link) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attrname) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_GET_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p1)), uintptr(data), uintptr(nbytes), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrSetLink(link string, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(link) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attrname) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_SET_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p1)), uintptr(data), uintptr(nbytes), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrDeleteLink(link string, attrnamespace int, attrname string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(link) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attrname) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_EXTATTR_DELETE_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrListLink(link string, attrnamespace int, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(link) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_LIST_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(data), uintptr(nbytes), 0, 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fadvise(fd int, offset int64, length int64, advice int) (err error) { + _, _, e1 := Syscall9(SYS_POSIX_FADVISE, uintptr(fd), 0, uintptr(offset), uintptr(offset>>32), 0, uintptr(length), uintptr(length>>32), uintptr(advice), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fchdir(fd int) (err error) { _, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0) if e1 != 0 { @@ -584,6 +840,21 @@ func Fchmod(fd int, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fchown(fd int, uid int, gid int) (err error) { _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)) if e1 != 0 { @@ -594,6 +865,21 @@ func Fchown(fd int, uid int, gid int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Flock(fd int, how int) (err error) { _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0) if e1 != 0 { @@ -625,6 +911,21 @@ func Fstat(fd int, stat *Stat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FSTATAT, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fsync(fd int) (err error) { _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0) if e1 != 0 { @@ -828,6 +1129,26 @@ func Link(path string, link string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(link) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_LINKAT, uintptr(pathfd), uintptr(unsafe.Pointer(_p0)), uintptr(linkfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Listen(s int, backlog int) (err error) { _, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0) if e1 != 0 { @@ -868,6 +1189,21 @@ func Mkdir(path string, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Mkdirat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Mkfifo(path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -883,6 +1219,21 @@ func Mkfifo(path string, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Mkfifoat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKFIFOAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Mknod(path string, mode uint32, dev int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -898,6 +1249,21 @@ func Mknod(path string, mode uint32, dev int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_MKNODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Nanosleep(time *Timespec, leftover *Timespec) (err error) { _, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0) if e1 != 0 { @@ -924,6 +1290,22 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Pathconf(path string, name int) (val int, err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -1013,6 +1395,28 @@ func Readlink(path string, buf []byte) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(buf) > 0 { + _p1 = unsafe.Pointer(&buf[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_READLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Rename(from string, to string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(from) @@ -1033,6 +1437,26 @@ func Rename(from string, to string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Renameat(fromfd int, from string, tofd int, to string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(from) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(to) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(fromfd), uintptr(unsafe.Pointer(_p0)), uintptr(tofd), uintptr(unsafe.Pointer(_p1)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Revoke(path string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -1230,6 +1654,26 @@ func Symlink(path string, link string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_SYMLINKAT, uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Sync() (err error) { _, _, e1 := Syscall(SYS_SYNC, 0, 0, 0) if e1 != 0 { @@ -1278,6 +1722,21 @@ func Unlink(path string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Unlinkat(dirfd int, path string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Unmount(path string, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go index 079824a71a..59585fee35 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go @@ -1,4 +1,4 @@ -// mksyscall.pl -netbsd -tags netbsd,amd64 syscall_bsd.go syscall_netbsd.go syscall_netbsd_amd64.go +// go run mksyscall.go -netbsd -tags netbsd,amd64 syscall_bsd.go syscall_netbsd.go syscall_netbsd_amd64.go // Code generated by the command above; see README.md. DO NOT EDIT. // +build netbsd,amd64 @@ -406,6 +406,23 @@ func getdents(fd int, buf []byte) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Getcwd(buf []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS___GETCWD, uintptr(_p0), uintptr(len(buf)), 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func ioctl(fd int, req uint, arg uintptr) (err error) { _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg)) if e1 != 0 { @@ -554,6 +571,245 @@ func Exit(code int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func ExtattrGetFd(fd int, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attrname) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_GET_FD, uintptr(fd), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p0)), uintptr(data), uintptr(nbytes), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrSetFd(fd int, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attrname) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_SET_FD, uintptr(fd), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p0)), uintptr(data), uintptr(nbytes), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrDeleteFd(fd int, attrnamespace int, attrname string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attrname) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_EXTATTR_DELETE_FD, uintptr(fd), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p0))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrListFd(fd int, attrnamespace int, data uintptr, nbytes int) (ret int, err error) { + r0, _, e1 := Syscall6(SYS_EXTATTR_LIST_FD, uintptr(fd), uintptr(attrnamespace), uintptr(data), uintptr(nbytes), 0, 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrGetFile(file string, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(file) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attrname) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_GET_FILE, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p1)), uintptr(data), uintptr(nbytes), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrSetFile(file string, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(file) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attrname) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_SET_FILE, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p1)), uintptr(data), uintptr(nbytes), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrDeleteFile(file string, attrnamespace int, attrname string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(file) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attrname) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_EXTATTR_DELETE_FILE, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrListFile(file string, attrnamespace int, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(file) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_LIST_FILE, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(data), uintptr(nbytes), 0, 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrGetLink(link string, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(link) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attrname) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_GET_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p1)), uintptr(data), uintptr(nbytes), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrSetLink(link string, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(link) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attrname) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_SET_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p1)), uintptr(data), uintptr(nbytes), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrDeleteLink(link string, attrnamespace int, attrname string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(link) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attrname) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_EXTATTR_DELETE_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrListLink(link string, attrnamespace int, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(link) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_LIST_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(data), uintptr(nbytes), 0, 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fadvise(fd int, offset int64, length int64, advice int) (err error) { + _, _, e1 := Syscall6(SYS_POSIX_FADVISE, uintptr(fd), 0, uintptr(offset), 0, uintptr(length), uintptr(advice)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fchdir(fd int) (err error) { _, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0) if e1 != 0 { @@ -584,6 +840,21 @@ func Fchmod(fd int, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fchown(fd int, uid int, gid int) (err error) { _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)) if e1 != 0 { @@ -594,6 +865,21 @@ func Fchown(fd int, uid int, gid int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Flock(fd int, how int) (err error) { _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0) if e1 != 0 { @@ -625,6 +911,21 @@ func Fstat(fd int, stat *Stat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FSTATAT, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fsync(fd int) (err error) { _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0) if e1 != 0 { @@ -828,6 +1129,26 @@ func Link(path string, link string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(link) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_LINKAT, uintptr(pathfd), uintptr(unsafe.Pointer(_p0)), uintptr(linkfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Listen(s int, backlog int) (err error) { _, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0) if e1 != 0 { @@ -868,6 +1189,21 @@ func Mkdir(path string, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Mkdirat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Mkfifo(path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -883,6 +1219,21 @@ func Mkfifo(path string, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Mkfifoat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKFIFOAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Mknod(path string, mode uint32, dev int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -898,6 +1249,21 @@ func Mknod(path string, mode uint32, dev int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_MKNODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Nanosleep(time *Timespec, leftover *Timespec) (err error) { _, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0) if e1 != 0 { @@ -924,6 +1290,22 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Pathconf(path string, name int) (val int, err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -1013,6 +1395,28 @@ func Readlink(path string, buf []byte) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(buf) > 0 { + _p1 = unsafe.Pointer(&buf[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_READLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Rename(from string, to string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(from) @@ -1033,6 +1437,26 @@ func Rename(from string, to string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Renameat(fromfd int, from string, tofd int, to string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(from) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(to) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(fromfd), uintptr(unsafe.Pointer(_p0)), uintptr(tofd), uintptr(unsafe.Pointer(_p1)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Revoke(path string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -1230,6 +1654,26 @@ func Symlink(path string, link string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_SYMLINKAT, uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Sync() (err error) { _, _, e1 := Syscall(SYS_SYNC, 0, 0, 0) if e1 != 0 { @@ -1278,6 +1722,21 @@ func Unlink(path string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Unlinkat(dirfd int, path string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Unmount(path string, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go b/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go index 05f8b496a8..6ec31434b2 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go @@ -1,4 +1,4 @@ -// mksyscall.pl -l32 -netbsd -arm -tags netbsd,arm syscall_bsd.go syscall_netbsd.go syscall_netbsd_arm.go +// go run mksyscall.go -l32 -netbsd -arm -tags netbsd,arm syscall_bsd.go syscall_netbsd.go syscall_netbsd_arm.go // Code generated by the command above; see README.md. DO NOT EDIT. // +build netbsd,arm @@ -406,6 +406,23 @@ func getdents(fd int, buf []byte) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Getcwd(buf []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS___GETCWD, uintptr(_p0), uintptr(len(buf)), 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func ioctl(fd int, req uint, arg uintptr) (err error) { _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg)) if e1 != 0 { @@ -554,6 +571,245 @@ func Exit(code int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func ExtattrGetFd(fd int, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attrname) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_GET_FD, uintptr(fd), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p0)), uintptr(data), uintptr(nbytes), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrSetFd(fd int, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attrname) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_SET_FD, uintptr(fd), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p0)), uintptr(data), uintptr(nbytes), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrDeleteFd(fd int, attrnamespace int, attrname string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attrname) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_EXTATTR_DELETE_FD, uintptr(fd), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p0))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrListFd(fd int, attrnamespace int, data uintptr, nbytes int) (ret int, err error) { + r0, _, e1 := Syscall6(SYS_EXTATTR_LIST_FD, uintptr(fd), uintptr(attrnamespace), uintptr(data), uintptr(nbytes), 0, 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrGetFile(file string, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(file) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attrname) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_GET_FILE, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p1)), uintptr(data), uintptr(nbytes), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrSetFile(file string, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(file) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attrname) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_SET_FILE, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p1)), uintptr(data), uintptr(nbytes), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrDeleteFile(file string, attrnamespace int, attrname string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(file) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attrname) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_EXTATTR_DELETE_FILE, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrListFile(file string, attrnamespace int, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(file) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_LIST_FILE, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(data), uintptr(nbytes), 0, 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrGetLink(link string, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(link) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attrname) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_GET_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p1)), uintptr(data), uintptr(nbytes), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrSetLink(link string, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(link) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attrname) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_SET_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p1)), uintptr(data), uintptr(nbytes), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrDeleteLink(link string, attrnamespace int, attrname string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(link) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attrname) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_EXTATTR_DELETE_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrListLink(link string, attrnamespace int, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(link) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_LIST_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(data), uintptr(nbytes), 0, 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fadvise(fd int, offset int64, length int64, advice int) (err error) { + _, _, e1 := Syscall9(SYS_POSIX_FADVISE, uintptr(fd), 0, uintptr(offset), uintptr(offset>>32), 0, uintptr(length), uintptr(length>>32), uintptr(advice), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fchdir(fd int) (err error) { _, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0) if e1 != 0 { @@ -584,6 +840,21 @@ func Fchmod(fd int, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fchown(fd int, uid int, gid int) (err error) { _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)) if e1 != 0 { @@ -594,6 +865,21 @@ func Fchown(fd int, uid int, gid int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Flock(fd int, how int) (err error) { _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0) if e1 != 0 { @@ -625,6 +911,21 @@ func Fstat(fd int, stat *Stat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FSTATAT, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fsync(fd int) (err error) { _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0) if e1 != 0 { @@ -828,6 +1129,26 @@ func Link(path string, link string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(link) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_LINKAT, uintptr(pathfd), uintptr(unsafe.Pointer(_p0)), uintptr(linkfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Listen(s int, backlog int) (err error) { _, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0) if e1 != 0 { @@ -868,6 +1189,21 @@ func Mkdir(path string, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Mkdirat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Mkfifo(path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -883,6 +1219,21 @@ func Mkfifo(path string, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Mkfifoat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKFIFOAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Mknod(path string, mode uint32, dev int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -898,6 +1249,21 @@ func Mknod(path string, mode uint32, dev int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_MKNODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Nanosleep(time *Timespec, leftover *Timespec) (err error) { _, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0) if e1 != 0 { @@ -924,6 +1290,22 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Pathconf(path string, name int) (val int, err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -1013,6 +1395,28 @@ func Readlink(path string, buf []byte) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(buf) > 0 { + _p1 = unsafe.Pointer(&buf[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_READLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Rename(from string, to string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(from) @@ -1033,6 +1437,26 @@ func Rename(from string, to string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Renameat(fromfd int, from string, tofd int, to string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(from) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(to) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(fromfd), uintptr(unsafe.Pointer(_p0)), uintptr(tofd), uintptr(unsafe.Pointer(_p1)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Revoke(path string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -1230,6 +1654,26 @@ func Symlink(path string, link string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_SYMLINKAT, uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Sync() (err error) { _, _, e1 := Syscall(SYS_SYNC, 0, 0, 0) if e1 != 0 { @@ -1278,6 +1722,21 @@ func Unlink(path string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Unlinkat(dirfd int, path string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Unmount(path string, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm64.go b/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm64.go new file mode 100644 index 0000000000..603d144334 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm64.go @@ -0,0 +1,1826 @@ +// go run mksyscall.go -netbsd -tags netbsd,arm64 syscall_bsd.go syscall_netbsd.go syscall_netbsd_arm64.go +// Code generated by the command above; see README.md. DO NOT EDIT. + +// +build netbsd,arm64 + +package unix + +import ( + "syscall" + "unsafe" +) + +var _ syscall.Errno + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getgroups(ngid int, gid *_Gid_t) (n int, err error) { + r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setgroups(ngid int, gid *_Gid_t) (err error) { + _, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) { + r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0) + wpid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { + r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { + _, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { + _, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func socket(domain int, typ int, proto int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto)) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) { + _, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) { + _, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { + _, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { + _, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Shutdown(s int, how int) (err error) { + _, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) { + _, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) { + r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) { + r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) { + r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) { + var _p0 unsafe.Pointer + if len(mib) > 0 { + _p0 = unsafe.Pointer(&mib[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func utimes(path string, timeval *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func futimes(fd int, timeval *[2]Timeval) (err error) { + _, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fcntl(fd int, cmd int, arg int) (val int, err error) { + r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg)) + val = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { + r0, _, e1 := Syscall(SYS_POLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Madvise(b []byte, behav int) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(behav)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mlock(b []byte) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mlockall(flags int) (err error) { + _, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mprotect(b []byte, prot int) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Msync(b []byte, flags int) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MSYNC, uintptr(_p0), uintptr(len(b)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Munlock(b []byte) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Munlockall() (err error) { + _, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func pipe() (fd1 int, fd2 int, err error) { + r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0) + fd1 = int(r0) + fd2 = int(r1) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getdents(fd int, buf []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_GETDENTS, uintptr(fd), uintptr(_p0), uintptr(len(buf))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getcwd(buf []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS___GETCWD, uintptr(_p0), uintptr(len(buf)), 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ioctl(fd int, req uint, arg uintptr) (err error) { + _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Access(path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Adjtime(delta *Timeval, olddelta *Timeval) (err error) { + _, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chdir(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chflags(path string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chmod(path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chown(path string, uid int, gid int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chroot(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Close(fd int) (err error) { + _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Dup(fd int) (nfd int, err error) { + r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0) + nfd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Dup2(from int, to int) (err error) { + _, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Exit(code int) { + Syscall(SYS_EXIT, uintptr(code), 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrGetFd(fd int, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attrname) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_GET_FD, uintptr(fd), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p0)), uintptr(data), uintptr(nbytes), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrSetFd(fd int, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attrname) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_SET_FD, uintptr(fd), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p0)), uintptr(data), uintptr(nbytes), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrDeleteFd(fd int, attrnamespace int, attrname string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(attrname) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_EXTATTR_DELETE_FD, uintptr(fd), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p0))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrListFd(fd int, attrnamespace int, data uintptr, nbytes int) (ret int, err error) { + r0, _, e1 := Syscall6(SYS_EXTATTR_LIST_FD, uintptr(fd), uintptr(attrnamespace), uintptr(data), uintptr(nbytes), 0, 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrGetFile(file string, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(file) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attrname) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_GET_FILE, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p1)), uintptr(data), uintptr(nbytes), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrSetFile(file string, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(file) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attrname) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_SET_FILE, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p1)), uintptr(data), uintptr(nbytes), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrDeleteFile(file string, attrnamespace int, attrname string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(file) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attrname) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_EXTATTR_DELETE_FILE, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrListFile(file string, attrnamespace int, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(file) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_LIST_FILE, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(data), uintptr(nbytes), 0, 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrGetLink(link string, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(link) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attrname) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_GET_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p1)), uintptr(data), uintptr(nbytes), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrSetLink(link string, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(link) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attrname) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_SET_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p1)), uintptr(data), uintptr(nbytes), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrDeleteLink(link string, attrnamespace int, attrname string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(link) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attrname) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_EXTATTR_DELETE_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ExtattrListLink(link string, attrnamespace int, data uintptr, nbytes int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(link) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_EXTATTR_LIST_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(attrnamespace), uintptr(data), uintptr(nbytes), 0, 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fadvise(fd int, offset int64, length int64, advice int) (err error) { + _, _, e1 := Syscall6(SYS_POSIX_FADVISE, uintptr(fd), 0, uintptr(offset), 0, uintptr(length), uintptr(advice)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchdir(fd int) (err error) { + _, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchflags(fd int, flags int) (err error) { + _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchmod(fd int, mode uint32) (err error) { + _, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchown(fd int, uid int, gid int) (err error) { + _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Flock(fd int, how int) (err error) { + _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fpathconf(fd int, name int) (val int, err error) { + r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0) + val = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstat(fd int, stat *Stat_t) (err error) { + _, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FSTATAT, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fsync(fd int) (err error) { + _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Ftruncate(fd int, length int64) (err error) { + _, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), 0, uintptr(length)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getegid() (egid int) { + r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0) + egid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Geteuid() (uid int) { + r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0) + uid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getgid() (gid int) { + r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0) + gid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpgid(pid int) (pgid int, err error) { + r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0) + pgid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpgrp() (pgrp int) { + r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0) + pgrp = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpid() (pid int) { + r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0) + pid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getppid() (ppid int) { + r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0) + ppid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpriority(which int, who int) (prio int, err error) { + r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0) + prio = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getrlimit(which int, lim *Rlimit) (err error) { + _, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getrusage(who int, rusage *Rusage) (err error) { + _, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getsid(pid int) (sid int, err error) { + r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0) + sid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Gettimeofday(tv *Timeval) (err error) { + _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getuid() (uid int) { + r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0) + uid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Issetugid() (tainted bool) { + r0, _, _ := Syscall(SYS_ISSETUGID, 0, 0, 0) + tainted = bool(r0 != 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Kill(pid int, signum syscall.Signal) (err error) { + _, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Kqueue() (fd int, err error) { + r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Lchown(path string, uid int, gid int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Link(path string, link string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(link) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(link) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_LINKAT, uintptr(pathfd), uintptr(unsafe.Pointer(_p0)), uintptr(linkfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Listen(s int, backlog int) (err error) { + _, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Lstat(path string, stat *Stat_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mkdir(path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mkdirat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mkfifo(path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mkfifoat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKFIFOAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mknod(path string, mode uint32, dev int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_MKNODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Nanosleep(time *Timespec, leftover *Timespec) (err error) { + _, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Open(path string, mode int, perm uint32) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pathconf(path string, name int) (val int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) + val = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pread(fd int, p []byte, offset int64) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pwrite(fd int, p []byte, offset int64) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func read(fd int, p []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Readlink(path string, buf []byte) (n int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(buf) > 0 { + _p1 = unsafe.Pointer(&buf[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(buf) > 0 { + _p1 = unsafe.Pointer(&buf[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_READLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Rename(from string, to string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(from) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(to) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Renameat(fromfd int, from string, tofd int, to string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(from) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(to) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(fromfd), uintptr(unsafe.Pointer(_p0)), uintptr(tofd), uintptr(unsafe.Pointer(_p1)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Revoke(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Rmdir(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { + r0, _, e1 := Syscall6(SYS_LSEEK, uintptr(fd), 0, uintptr(offset), uintptr(whence), 0, 0) + newoffset = int64(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) { + _, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setegid(egid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETEGID, uintptr(egid), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Seteuid(euid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setgid(gid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setpgid(pid int, pgid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setpriority(which int, who int, prio int) (err error) { + _, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setregid(rgid int, egid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setreuid(ruid int, euid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setrlimit(which int, lim *Rlimit) (err error) { + _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setsid() (pid int, err error) { + r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0) + pid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Settimeofday(tp *Timeval) (err error) { + _, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setuid(uid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Stat(path string, stat *Stat_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Symlink(path string, link string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(link) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_SYMLINKAT, uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Sync() (err error) { + _, _, e1 := Syscall(SYS_SYNC, 0, 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Truncate(path string, length int64) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Umask(newmask int) (oldmask int) { + r0, _, _ := Syscall(SYS_UMASK, uintptr(newmask), 0, 0) + oldmask = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Unlink(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Unlinkat(dirfd int, path string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Unmount(path string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func write(fd int, p []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) { + r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), 0, uintptr(pos), 0, 0) + ret = uintptr(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func munmap(addr uintptr, length uintptr) (err error) { + _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func readlen(fd int, buf *byte, nbuf int) (n int, err error) { + r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func writelen(fd int, buf *byte, nbuf int) (n int, err error) { + r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_UTIMENSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go index 3b55544df7..6a489fac0a 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go @@ -1,4 +1,4 @@ -// mksyscall.pl -l32 -openbsd -tags openbsd,386 syscall_bsd.go syscall_openbsd.go syscall_openbsd_386.go +// go run mksyscall.go -l32 -openbsd -tags openbsd,386 syscall_bsd.go syscall_openbsd.go syscall_openbsd_386.go // Code generated by the command above; see README.md. DO NOT EDIT. // +build openbsd,386 @@ -404,6 +404,23 @@ func getdents(fd int, buf []byte) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Getcwd(buf []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS___GETCWD, uintptr(_p0), uintptr(len(buf)), 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func ioctl(fd int, req uint, arg uintptr) (err error) { _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg)) if e1 != 0 { @@ -414,6 +431,17 @@ func ioctl(fd int, req uint, arg uintptr) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func ppoll(fds *PollFd, nfds int, timeout *Timespec, sigmask *Sigset_t) (n int, err error) { + r0, _, e1 := Syscall6(SYS_PPOLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Access(path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -552,6 +580,21 @@ func Exit(code int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fchdir(fd int) (err error) { _, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0) if e1 != 0 { @@ -582,6 +625,21 @@ func Fchmod(fd int, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fchown(fd int, uid int, gid int) (err error) { _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)) if e1 != 0 { @@ -592,6 +650,21 @@ func Fchown(fd int, uid int, gid int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Flock(fd int, how int) (err error) { _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0) if e1 != 0 { @@ -623,6 +696,21 @@ func Fstat(fd int, stat *Stat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FSTATAT, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fstatfs(fd int, stat *Statfs_t) (err error) { _, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) if e1 != 0 { @@ -733,6 +821,17 @@ func Getrlimit(which int, lim *Rlimit) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Getrtable() (rtable int, err error) { + r0, _, e1 := RawSyscall(SYS_GETRTABLE, 0, 0, 0) + rtable = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Getrusage(who int, rusage *Rusage) (err error) { _, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0) if e1 != 0 { @@ -836,6 +935,26 @@ func Link(path string, link string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(link) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_LINKAT, uintptr(pathfd), uintptr(unsafe.Pointer(_p0)), uintptr(linkfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Listen(s int, backlog int) (err error) { _, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0) if e1 != 0 { @@ -876,6 +995,21 @@ func Mkdir(path string, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Mkdirat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Mkfifo(path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -891,6 +1025,21 @@ func Mkfifo(path string, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Mkfifoat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKFIFOAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Mknod(path string, mode uint32, dev int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -906,6 +1055,21 @@ func Mknod(path string, mode uint32, dev int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_MKNODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Nanosleep(time *Timespec, leftover *Timespec) (err error) { _, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0) if e1 != 0 { @@ -932,6 +1096,22 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Pathconf(path string, name int) (val int, err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -1021,6 +1201,28 @@ func Readlink(path string, buf []byte) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(buf) > 0 { + _p1 = unsafe.Pointer(&buf[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_READLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Rename(from string, to string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(from) @@ -1041,6 +1243,26 @@ func Rename(from string, to string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Renameat(fromfd int, from string, tofd int, to string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(from) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(to) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(fromfd), uintptr(unsafe.Pointer(_p0)), uintptr(tofd), uintptr(unsafe.Pointer(_p1)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Revoke(path string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -1207,6 +1429,16 @@ func Setrlimit(which int, lim *Rlimit) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Setrtable(rtable int) (err error) { + _, _, e1 := RawSyscall(SYS_SETRTABLE, uintptr(rtable), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Setsid() (pid int, err error) { r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0) pid = int(r0) @@ -1288,6 +1520,26 @@ func Symlink(path string, link string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_SYMLINKAT, uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Sync() (err error) { _, _, e1 := Syscall(SYS_SYNC, 0, 0, 0) if e1 != 0 { @@ -1336,6 +1588,21 @@ func Unlink(path string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Unlinkat(dirfd int, path string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Unmount(path string, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go index cdaf4ef4c1..30cba4347c 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go @@ -1,4 +1,4 @@ -// mksyscall.pl -openbsd -tags openbsd,amd64 syscall_bsd.go syscall_openbsd.go syscall_openbsd_amd64.go +// go run mksyscall.go -openbsd -tags openbsd,amd64 syscall_bsd.go syscall_openbsd.go syscall_openbsd_amd64.go // Code generated by the command above; see README.md. DO NOT EDIT. // +build openbsd,amd64 @@ -404,6 +404,23 @@ func getdents(fd int, buf []byte) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Getcwd(buf []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS___GETCWD, uintptr(_p0), uintptr(len(buf)), 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func ioctl(fd int, req uint, arg uintptr) (err error) { _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg)) if e1 != 0 { @@ -414,6 +431,17 @@ func ioctl(fd int, req uint, arg uintptr) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func ppoll(fds *PollFd, nfds int, timeout *Timespec, sigmask *Sigset_t) (n int, err error) { + r0, _, e1 := Syscall6(SYS_PPOLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Access(path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -552,6 +580,21 @@ func Exit(code int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fchdir(fd int) (err error) { _, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0) if e1 != 0 { @@ -582,6 +625,21 @@ func Fchmod(fd int, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fchown(fd int, uid int, gid int) (err error) { _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)) if e1 != 0 { @@ -592,6 +650,21 @@ func Fchown(fd int, uid int, gid int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Flock(fd int, how int) (err error) { _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0) if e1 != 0 { @@ -623,6 +696,21 @@ func Fstat(fd int, stat *Stat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FSTATAT, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fstatfs(fd int, stat *Statfs_t) (err error) { _, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) if e1 != 0 { @@ -733,6 +821,17 @@ func Getrlimit(which int, lim *Rlimit) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Getrtable() (rtable int, err error) { + r0, _, e1 := RawSyscall(SYS_GETRTABLE, 0, 0, 0) + rtable = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Getrusage(who int, rusage *Rusage) (err error) { _, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0) if e1 != 0 { @@ -836,6 +935,26 @@ func Link(path string, link string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(link) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_LINKAT, uintptr(pathfd), uintptr(unsafe.Pointer(_p0)), uintptr(linkfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Listen(s int, backlog int) (err error) { _, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0) if e1 != 0 { @@ -876,6 +995,21 @@ func Mkdir(path string, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Mkdirat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Mkfifo(path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -891,6 +1025,21 @@ func Mkfifo(path string, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Mkfifoat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKFIFOAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Mknod(path string, mode uint32, dev int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -906,6 +1055,21 @@ func Mknod(path string, mode uint32, dev int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_MKNODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Nanosleep(time *Timespec, leftover *Timespec) (err error) { _, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0) if e1 != 0 { @@ -932,6 +1096,22 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Pathconf(path string, name int) (val int, err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -1021,6 +1201,28 @@ func Readlink(path string, buf []byte) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(buf) > 0 { + _p1 = unsafe.Pointer(&buf[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_READLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Rename(from string, to string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(from) @@ -1041,6 +1243,26 @@ func Rename(from string, to string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Renameat(fromfd int, from string, tofd int, to string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(from) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(to) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(fromfd), uintptr(unsafe.Pointer(_p0)), uintptr(tofd), uintptr(unsafe.Pointer(_p1)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Revoke(path string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -1207,6 +1429,16 @@ func Setrlimit(which int, lim *Rlimit) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Setrtable(rtable int) (err error) { + _, _, e1 := RawSyscall(SYS_SETRTABLE, uintptr(rtable), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Setsid() (pid int, err error) { r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0) pid = int(r0) @@ -1288,6 +1520,26 @@ func Symlink(path string, link string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_SYMLINKAT, uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Sync() (err error) { _, _, e1 := Syscall(SYS_SYNC, 0, 0, 0) if e1 != 0 { @@ -1336,6 +1588,21 @@ func Unlink(path string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Unlinkat(dirfd int, path string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Unmount(path string, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go index 6c4dc8a9fb..fa1beda33e 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go @@ -1,4 +1,4 @@ -// mksyscall.pl -l32 -openbsd -arm -tags openbsd,arm syscall_bsd.go syscall_openbsd.go syscall_openbsd_arm.go +// go run mksyscall.go -l32 -openbsd -arm -tags openbsd,arm syscall_bsd.go syscall_openbsd.go syscall_openbsd_arm.go // Code generated by the command above; see README.md. DO NOT EDIT. // +build openbsd,arm @@ -404,6 +404,23 @@ func getdents(fd int, buf []byte) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Getcwd(buf []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS___GETCWD, uintptr(_p0), uintptr(len(buf)), 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func ioctl(fd int, req uint, arg uintptr) (err error) { _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg)) if e1 != 0 { @@ -414,6 +431,17 @@ func ioctl(fd int, req uint, arg uintptr) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func ppoll(fds *PollFd, nfds int, timeout *Timespec, sigmask *Sigset_t) (n int, err error) { + r0, _, e1 := Syscall6(SYS_PPOLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Access(path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -552,6 +580,21 @@ func Exit(code int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fchdir(fd int) (err error) { _, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0) if e1 != 0 { @@ -582,6 +625,21 @@ func Fchmod(fd int, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fchown(fd int, uid int, gid int) (err error) { _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)) if e1 != 0 { @@ -592,6 +650,21 @@ func Fchown(fd int, uid int, gid int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Flock(fd int, how int) (err error) { _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0) if e1 != 0 { @@ -623,6 +696,21 @@ func Fstat(fd int, stat *Stat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FSTATAT, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fstatfs(fd int, stat *Statfs_t) (err error) { _, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) if e1 != 0 { @@ -733,6 +821,17 @@ func Getrlimit(which int, lim *Rlimit) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Getrtable() (rtable int, err error) { + r0, _, e1 := RawSyscall(SYS_GETRTABLE, 0, 0, 0) + rtable = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Getrusage(who int, rusage *Rusage) (err error) { _, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0) if e1 != 0 { @@ -836,6 +935,26 @@ func Link(path string, link string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(link) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_LINKAT, uintptr(pathfd), uintptr(unsafe.Pointer(_p0)), uintptr(linkfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Listen(s int, backlog int) (err error) { _, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0) if e1 != 0 { @@ -876,6 +995,21 @@ func Mkdir(path string, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Mkdirat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Mkfifo(path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -891,6 +1025,21 @@ func Mkfifo(path string, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Mkfifoat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKFIFOAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Mknod(path string, mode uint32, dev int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -906,6 +1055,21 @@ func Mknod(path string, mode uint32, dev int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_MKNODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Nanosleep(time *Timespec, leftover *Timespec) (err error) { _, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0) if e1 != 0 { @@ -932,6 +1096,22 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Pathconf(path string, name int) (val int, err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -1021,6 +1201,28 @@ func Readlink(path string, buf []byte) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(buf) > 0 { + _p1 = unsafe.Pointer(&buf[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_READLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Rename(from string, to string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(from) @@ -1041,6 +1243,26 @@ func Rename(from string, to string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Renameat(fromfd int, from string, tofd int, to string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(from) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(to) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(fromfd), uintptr(unsafe.Pointer(_p0)), uintptr(tofd), uintptr(unsafe.Pointer(_p1)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Revoke(path string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -1207,6 +1429,16 @@ func Setrlimit(which int, lim *Rlimit) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Setrtable(rtable int) (err error) { + _, _, e1 := RawSyscall(SYS_SETRTABLE, uintptr(rtable), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Setsid() (pid int, err error) { r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0) pid = int(r0) @@ -1288,6 +1520,26 @@ func Symlink(path string, link string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_SYMLINKAT, uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Sync() (err error) { _, _, e1 := Syscall(SYS_SYNC, 0, 0, 0) if e1 != 0 { @@ -1336,6 +1588,21 @@ func Unlink(path string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Unlinkat(dirfd int, path string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Unmount(path string, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go index 1d45276498..5f614760c6 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go @@ -1,4 +1,4 @@ -// mksyscall_solaris.pl -tags solaris,amd64 syscall_solaris.go syscall_solaris_amd64.go +// go run mksyscall_solaris.go -tags solaris,amd64 syscall_solaris.go syscall_solaris_amd64.go // Code generated by the command above; see README.md. DO NOT EDIT. // +build solaris,amd64 @@ -41,6 +41,7 @@ import ( //go:cgo_import_dynamic libc_dup dup "libc.so" //go:cgo_import_dynamic libc_dup2 dup2 "libc.so" //go:cgo_import_dynamic libc_exit exit "libc.so" +//go:cgo_import_dynamic libc_faccessat faccessat "libc.so" //go:cgo_import_dynamic libc_fchdir fchdir "libc.so" //go:cgo_import_dynamic libc_fchmod fchmod "libc.so" //go:cgo_import_dynamic libc_fchmodat fchmodat "libc.so" @@ -50,6 +51,7 @@ import ( //go:cgo_import_dynamic libc_flock flock "libc.so" //go:cgo_import_dynamic libc_fpathconf fpathconf "libc.so" //go:cgo_import_dynamic libc_fstat fstat "libc.so" +//go:cgo_import_dynamic libc_fstatat fstatat "libc.so" //go:cgo_import_dynamic libc_fstatvfs fstatvfs "libc.so" //go:cgo_import_dynamic libc_getdents getdents "libc.so" //go:cgo_import_dynamic libc_getgid getgid "libc.so" @@ -95,6 +97,7 @@ import ( //go:cgo_import_dynamic libc_renameat renameat "libc.so" //go:cgo_import_dynamic libc_rmdir rmdir "libc.so" //go:cgo_import_dynamic libc_lseek lseek "libc.so" +//go:cgo_import_dynamic libc_select select "libc.so" //go:cgo_import_dynamic libc_setegid setegid "libc.so" //go:cgo_import_dynamic libc_seteuid seteuid "libc.so" //go:cgo_import_dynamic libc_setgid setgid "libc.so" @@ -126,6 +129,7 @@ import ( //go:cgo_import_dynamic libc___xnet_connect __xnet_connect "libsocket.so" //go:cgo_import_dynamic libc_mmap mmap "libc.so" //go:cgo_import_dynamic libc_munmap munmap "libc.so" +//go:cgo_import_dynamic libc_sendfile sendfile "libsendfile.so" //go:cgo_import_dynamic libc___xnet_sendto __xnet_sendto "libsocket.so" //go:cgo_import_dynamic libc___xnet_socket __xnet_socket "libsocket.so" //go:cgo_import_dynamic libc___xnet_socketpair __xnet_socketpair "libsocket.so" @@ -166,6 +170,7 @@ import ( //go:linkname procDup libc_dup //go:linkname procDup2 libc_dup2 //go:linkname procExit libc_exit +//go:linkname procFaccessat libc_faccessat //go:linkname procFchdir libc_fchdir //go:linkname procFchmod libc_fchmod //go:linkname procFchmodat libc_fchmodat @@ -175,6 +180,7 @@ import ( //go:linkname procFlock libc_flock //go:linkname procFpathconf libc_fpathconf //go:linkname procFstat libc_fstat +//go:linkname procFstatat libc_fstatat //go:linkname procFstatvfs libc_fstatvfs //go:linkname procGetdents libc_getdents //go:linkname procGetgid libc_getgid @@ -220,6 +226,7 @@ import ( //go:linkname procRenameat libc_renameat //go:linkname procRmdir libc_rmdir //go:linkname proclseek libc_lseek +//go:linkname procSelect libc_select //go:linkname procSetegid libc_setegid //go:linkname procSeteuid libc_seteuid //go:linkname procSetgid libc_setgid @@ -251,6 +258,7 @@ import ( //go:linkname proc__xnet_connect libc___xnet_connect //go:linkname procmmap libc_mmap //go:linkname procmunmap libc_munmap +//go:linkname procsendfile libc_sendfile //go:linkname proc__xnet_sendto libc___xnet_sendto //go:linkname proc__xnet_socket libc___xnet_socket //go:linkname proc__xnet_socketpair libc___xnet_socketpair @@ -292,6 +300,7 @@ var ( procDup, procDup2, procExit, + procFaccessat, procFchdir, procFchmod, procFchmodat, @@ -301,6 +310,7 @@ var ( procFlock, procFpathconf, procFstat, + procFstatat, procFstatvfs, procGetdents, procGetgid, @@ -346,6 +356,7 @@ var ( procRenameat, procRmdir, proclseek, + procSelect, procSetegid, procSeteuid, procSetgid, @@ -377,6 +388,7 @@ var ( proc__xnet_connect, procmmap, procmunmap, + procsendfile, proc__xnet_sendto, proc__xnet_socket, proc__xnet_socketpair, @@ -387,6 +399,8 @@ var ( procrecvfrom syscallFunc ) +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func pipe(p *[2]_C_int) (n int, err error) { r0, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&procpipe)), 1, uintptr(unsafe.Pointer(p)), 0, 0, 0, 0, 0) n = int(r0) @@ -396,6 +410,8 @@ func pipe(p *[2]_C_int) (n int, err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procgetsockname)), 3, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0) if e1 != 0 { @@ -404,6 +420,8 @@ func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Getcwd(buf []byte) (n int, err error) { var _p0 *byte if len(buf) > 0 { @@ -417,6 +435,8 @@ func Getcwd(buf []byte) (n int, err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func getgroups(ngid int, gid *_Gid_t) (n int, err error) { r0, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&procgetgroups)), 2, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0, 0, 0, 0) n = int(r0) @@ -426,6 +446,8 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func setgroups(ngid int, gid *_Gid_t) (err error) { _, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&procsetgroups)), 2, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0, 0, 0, 0) if e1 != 0 { @@ -434,6 +456,8 @@ func setgroups(ngid int, gid *_Gid_t) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func wait4(pid int32, statusp *_C_int, options int, rusage *Rusage) (wpid int32, err error) { r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procwait4)), 4, uintptr(pid), uintptr(unsafe.Pointer(statusp)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0) wpid = int32(r0) @@ -443,6 +467,8 @@ func wait4(pid int32, statusp *_C_int, options int, rusage *Rusage) (wpid int32, return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func gethostname(buf []byte) (n int, err error) { var _p0 *byte if len(buf) > 0 { @@ -456,6 +482,8 @@ func gethostname(buf []byte) (n int, err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func utimes(path string, times *[2]Timeval) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -469,6 +497,8 @@ func utimes(path string, times *[2]Timeval) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func utimensat(fd int, path string, times *[2]Timespec, flag int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -482,6 +512,8 @@ func utimensat(fd int, path string, times *[2]Timespec, flag int) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func fcntl(fd int, cmd int, arg int) (val int, err error) { r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procfcntl)), 3, uintptr(fd), uintptr(cmd), uintptr(arg), 0, 0, 0) val = int(r0) @@ -491,6 +523,8 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func futimesat(fildes int, path *byte, times *[2]Timeval) (err error) { _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procfutimesat)), 3, uintptr(fildes), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times)), 0, 0, 0) if e1 != 0 { @@ -499,6 +533,8 @@ func futimesat(fildes int, path *byte, times *[2]Timeval) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procaccept)), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0) fd = int(r0) @@ -508,6 +544,8 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) { r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&proc__xnet_recvmsg)), 3, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0) n = int(r0) @@ -517,6 +555,8 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) { r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&proc__xnet_sendmsg)), 3, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0) n = int(r0) @@ -526,6 +566,8 @@ func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func acct(path *byte) (err error) { _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procacct)), 1, uintptr(unsafe.Pointer(path)), 0, 0, 0, 0, 0) if e1 != 0 { @@ -534,24 +576,32 @@ func acct(path *byte) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func __makedev(version int, major uint, minor uint) (val uint64) { r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&proc__makedev)), 3, uintptr(version), uintptr(major), uintptr(minor), 0, 0, 0) val = uint64(r0) return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func __major(version int, dev uint64) (val uint) { r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&proc__major)), 2, uintptr(version), uintptr(dev), 0, 0, 0, 0) val = uint(r0) return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func __minor(version int, dev uint64) (val uint) { r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&proc__minor)), 2, uintptr(version), uintptr(dev), 0, 0, 0, 0) val = uint(r0) return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func ioctl(fd int, req uint, arg uintptr) (err error) { _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procioctl)), 3, uintptr(fd), uintptr(req), uintptr(arg), 0, 0, 0) if e1 != 0 { @@ -560,6 +610,8 @@ func ioctl(fd int, req uint, arg uintptr) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procpoll)), 3, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout), 0, 0, 0) n = int(r0) @@ -569,6 +621,8 @@ func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Access(path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -582,6 +636,8 @@ func Access(path string, mode uint32) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Adjtime(delta *Timeval, olddelta *Timeval) (err error) { _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procAdjtime)), 2, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0, 0, 0, 0) if e1 != 0 { @@ -590,6 +646,8 @@ func Adjtime(delta *Timeval, olddelta *Timeval) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Chdir(path string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -603,6 +661,8 @@ func Chdir(path string) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Chmod(path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -616,6 +676,8 @@ func Chmod(path string, mode uint32) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Chown(path string, uid int, gid int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -629,6 +691,8 @@ func Chown(path string, uid int, gid int) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Chroot(path string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -642,6 +706,8 @@ func Chroot(path string) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Close(fd int) (err error) { _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procClose)), 1, uintptr(fd), 0, 0, 0, 0, 0) if e1 != 0 { @@ -650,6 +716,8 @@ func Close(fd int) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Creat(path string, mode uint32) (fd int, err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -664,6 +732,8 @@ func Creat(path string, mode uint32) (fd int, err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Dup(fd int) (nfd int, err error) { r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procDup)), 1, uintptr(fd), 0, 0, 0, 0, 0) nfd = int(r0) @@ -673,6 +743,8 @@ func Dup(fd int) (nfd int, err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Dup2(oldfd int, newfd int) (err error) { _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procDup2)), 2, uintptr(oldfd), uintptr(newfd), 0, 0, 0, 0) if e1 != 0 { @@ -681,11 +753,30 @@ func Dup2(oldfd int, newfd int) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Exit(code int) { sysvicall6(uintptr(unsafe.Pointer(&procExit)), 1, uintptr(code), 0, 0, 0, 0, 0) return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procFaccessat)), 4, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = e1 + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fchdir(fd int) (err error) { _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procFchdir)), 1, uintptr(fd), 0, 0, 0, 0, 0) if e1 != 0 { @@ -694,6 +785,8 @@ func Fchdir(fd int) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fchmod(fd int, mode uint32) (err error) { _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procFchmod)), 2, uintptr(fd), uintptr(mode), 0, 0, 0, 0) if e1 != 0 { @@ -702,6 +795,8 @@ func Fchmod(fd int, mode uint32) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -715,6 +810,8 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fchown(fd int, uid int, gid int) (err error) { _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procFchown)), 3, uintptr(fd), uintptr(uid), uintptr(gid), 0, 0, 0) if e1 != 0 { @@ -723,6 +820,8 @@ func Fchown(fd int, uid int, gid int) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -736,6 +835,8 @@ func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fdatasync(fd int) (err error) { _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procFdatasync)), 1, uintptr(fd), 0, 0, 0, 0, 0) if e1 != 0 { @@ -744,6 +845,8 @@ func Fdatasync(fd int) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Flock(fd int, how int) (err error) { _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procFlock)), 2, uintptr(fd), uintptr(how), 0, 0, 0, 0) if e1 != 0 { @@ -752,6 +855,8 @@ func Flock(fd int, how int) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fpathconf(fd int, name int) (val int, err error) { r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procFpathconf)), 2, uintptr(fd), uintptr(name), 0, 0, 0, 0) val = int(r0) @@ -761,6 +866,8 @@ func Fpathconf(fd int, name int) (val int, err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fstat(fd int, stat *Stat_t) (err error) { _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procFstat)), 2, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0) if e1 != 0 { @@ -769,6 +876,23 @@ func Fstat(fd int, stat *Stat_t) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procFstatat)), 4, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = e1 + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fstatvfs(fd int, vfsstat *Statvfs_t) (err error) { _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procFstatvfs)), 2, uintptr(fd), uintptr(unsafe.Pointer(vfsstat)), 0, 0, 0, 0) if e1 != 0 { @@ -777,6 +901,8 @@ func Fstatvfs(fd int, vfsstat *Statvfs_t) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Getdents(fd int, buf []byte, basep *uintptr) (n int, err error) { var _p0 *byte if len(buf) > 0 { @@ -790,18 +916,24 @@ func Getdents(fd int, buf []byte, basep *uintptr) (n int, err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Getgid() (gid int) { r0, _, _ := rawSysvicall6(uintptr(unsafe.Pointer(&procGetgid)), 0, 0, 0, 0, 0, 0, 0) gid = int(r0) return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Getpid() (pid int) { r0, _, _ := rawSysvicall6(uintptr(unsafe.Pointer(&procGetpid)), 0, 0, 0, 0, 0, 0, 0) pid = int(r0) return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Getpgid(pid int) (pgid int, err error) { r0, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&procGetpgid)), 1, uintptr(pid), 0, 0, 0, 0, 0) pgid = int(r0) @@ -811,6 +943,8 @@ func Getpgid(pid int) (pgid int, err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Getpgrp() (pgid int, err error) { r0, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&procGetpgrp)), 0, 0, 0, 0, 0, 0, 0) pgid = int(r0) @@ -820,24 +954,32 @@ func Getpgrp() (pgid int, err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Geteuid() (euid int) { r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&procGeteuid)), 0, 0, 0, 0, 0, 0, 0) euid = int(r0) return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Getegid() (egid int) { r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&procGetegid)), 0, 0, 0, 0, 0, 0, 0) egid = int(r0) return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Getppid() (ppid int) { r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&procGetppid)), 0, 0, 0, 0, 0, 0, 0) ppid = int(r0) return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Getpriority(which int, who int) (n int, err error) { r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procGetpriority)), 2, uintptr(which), uintptr(who), 0, 0, 0, 0) n = int(r0) @@ -847,6 +989,8 @@ func Getpriority(which int, who int) (n int, err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Getrlimit(which int, lim *Rlimit) (err error) { _, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&procGetrlimit)), 2, uintptr(which), uintptr(unsafe.Pointer(lim)), 0, 0, 0, 0) if e1 != 0 { @@ -855,6 +999,8 @@ func Getrlimit(which int, lim *Rlimit) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Getrusage(who int, rusage *Rusage) (err error) { _, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&procGetrusage)), 2, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0, 0, 0, 0) if e1 != 0 { @@ -863,6 +1009,8 @@ func Getrusage(who int, rusage *Rusage) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Gettimeofday(tv *Timeval) (err error) { _, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&procGettimeofday)), 1, uintptr(unsafe.Pointer(tv)), 0, 0, 0, 0, 0) if e1 != 0 { @@ -871,12 +1019,16 @@ func Gettimeofday(tv *Timeval) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Getuid() (uid int) { r0, _, _ := rawSysvicall6(uintptr(unsafe.Pointer(&procGetuid)), 0, 0, 0, 0, 0, 0, 0) uid = int(r0) return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Kill(pid int, signum syscall.Signal) (err error) { _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procKill)), 2, uintptr(pid), uintptr(signum), 0, 0, 0, 0) if e1 != 0 { @@ -885,6 +1037,8 @@ func Kill(pid int, signum syscall.Signal) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Lchown(path string, uid int, gid int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -898,6 +1052,8 @@ func Lchown(path string, uid int, gid int) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Link(path string, link string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -916,6 +1072,8 @@ func Link(path string, link string) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Listen(s int, backlog int) (err error) { _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&proc__xnet_llisten)), 2, uintptr(s), uintptr(backlog), 0, 0, 0, 0) if e1 != 0 { @@ -924,6 +1082,8 @@ func Listen(s int, backlog int) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Lstat(path string, stat *Stat_t) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -937,6 +1097,8 @@ func Lstat(path string, stat *Stat_t) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Madvise(b []byte, advice int) (err error) { var _p0 *byte if len(b) > 0 { @@ -949,6 +1111,8 @@ func Madvise(b []byte, advice int) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Mkdir(path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -962,6 +1126,8 @@ func Mkdir(path string, mode uint32) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Mkdirat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -975,6 +1141,8 @@ func Mkdirat(dirfd int, path string, mode uint32) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Mkfifo(path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -988,6 +1156,8 @@ func Mkfifo(path string, mode uint32) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Mkfifoat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -1001,6 +1171,8 @@ func Mkfifoat(dirfd int, path string, mode uint32) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Mknod(path string, mode uint32, dev int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -1014,6 +1186,8 @@ func Mknod(path string, mode uint32, dev int) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -1027,6 +1201,8 @@ func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Mlock(b []byte) (err error) { var _p0 *byte if len(b) > 0 { @@ -1039,6 +1215,8 @@ func Mlock(b []byte) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Mlockall(flags int) (err error) { _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procMlockall)), 1, uintptr(flags), 0, 0, 0, 0, 0) if e1 != 0 { @@ -1047,6 +1225,8 @@ func Mlockall(flags int) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Mprotect(b []byte, prot int) (err error) { var _p0 *byte if len(b) > 0 { @@ -1059,6 +1239,8 @@ func Mprotect(b []byte, prot int) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Msync(b []byte, flags int) (err error) { var _p0 *byte if len(b) > 0 { @@ -1071,6 +1253,8 @@ func Msync(b []byte, flags int) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Munlock(b []byte) (err error) { var _p0 *byte if len(b) > 0 { @@ -1083,6 +1267,8 @@ func Munlock(b []byte) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Munlockall() (err error) { _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procMunlockall)), 0, 0, 0, 0, 0, 0, 0) if e1 != 0 { @@ -1091,6 +1277,8 @@ func Munlockall() (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Nanosleep(time *Timespec, leftover *Timespec) (err error) { _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procNanosleep)), 2, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0, 0, 0, 0) if e1 != 0 { @@ -1099,6 +1287,8 @@ func Nanosleep(time *Timespec, leftover *Timespec) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Open(path string, mode int, perm uint32) (fd int, err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -1113,6 +1303,8 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -1127,6 +1319,8 @@ func Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Pathconf(path string, name int) (val int, err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -1141,6 +1335,8 @@ func Pathconf(path string, name int) (val int, err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Pause() (err error) { _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procPause)), 0, 0, 0, 0, 0, 0, 0) if e1 != 0 { @@ -1149,6 +1345,8 @@ func Pause() (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Pread(fd int, p []byte, offset int64) (n int, err error) { var _p0 *byte if len(p) > 0 { @@ -1162,6 +1360,8 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Pwrite(fd int, p []byte, offset int64) (n int, err error) { var _p0 *byte if len(p) > 0 { @@ -1175,6 +1375,8 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func read(fd int, p []byte) (n int, err error) { var _p0 *byte if len(p) > 0 { @@ -1188,6 +1390,8 @@ func read(fd int, p []byte) (n int, err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Readlink(path string, buf []byte) (n int, err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -1206,6 +1410,8 @@ func Readlink(path string, buf []byte) (n int, err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Rename(from string, to string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(from) @@ -1224,6 +1430,8 @@ func Rename(from string, to string) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(oldpath) @@ -1242,6 +1450,8 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Rmdir(path string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -1255,6 +1465,8 @@ func Rmdir(path string) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&proclseek)), 3, uintptr(fd), uintptr(offset), uintptr(whence), 0, 0, 0) newoffset = int64(r0) @@ -1264,6 +1476,18 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) { + _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procSelect)), 5, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0) + if e1 != 0 { + err = e1 + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Setegid(egid int) (err error) { _, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&procSetegid)), 1, uintptr(egid), 0, 0, 0, 0, 0) if e1 != 0 { @@ -1272,6 +1496,8 @@ func Setegid(egid int) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Seteuid(euid int) (err error) { _, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&procSeteuid)), 1, uintptr(euid), 0, 0, 0, 0, 0) if e1 != 0 { @@ -1280,6 +1506,8 @@ func Seteuid(euid int) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Setgid(gid int) (err error) { _, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&procSetgid)), 1, uintptr(gid), 0, 0, 0, 0, 0) if e1 != 0 { @@ -1288,6 +1516,8 @@ func Setgid(gid int) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Sethostname(p []byte) (err error) { var _p0 *byte if len(p) > 0 { @@ -1300,6 +1530,8 @@ func Sethostname(p []byte) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Setpgid(pid int, pgid int) (err error) { _, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&procSetpgid)), 2, uintptr(pid), uintptr(pgid), 0, 0, 0, 0) if e1 != 0 { @@ -1308,6 +1540,8 @@ func Setpgid(pid int, pgid int) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Setpriority(which int, who int, prio int) (err error) { _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procSetpriority)), 3, uintptr(which), uintptr(who), uintptr(prio), 0, 0, 0) if e1 != 0 { @@ -1316,6 +1550,8 @@ func Setpriority(which int, who int, prio int) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Setregid(rgid int, egid int) (err error) { _, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&procSetregid)), 2, uintptr(rgid), uintptr(egid), 0, 0, 0, 0) if e1 != 0 { @@ -1324,6 +1560,8 @@ func Setregid(rgid int, egid int) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Setreuid(ruid int, euid int) (err error) { _, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&procSetreuid)), 2, uintptr(ruid), uintptr(euid), 0, 0, 0, 0) if e1 != 0 { @@ -1332,6 +1570,8 @@ func Setreuid(ruid int, euid int) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Setrlimit(which int, lim *Rlimit) (err error) { _, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&procSetrlimit)), 2, uintptr(which), uintptr(unsafe.Pointer(lim)), 0, 0, 0, 0) if e1 != 0 { @@ -1340,6 +1580,8 @@ func Setrlimit(which int, lim *Rlimit) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Setsid() (pid int, err error) { r0, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&procSetsid)), 0, 0, 0, 0, 0, 0, 0) pid = int(r0) @@ -1349,6 +1591,8 @@ func Setsid() (pid int, err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Setuid(uid int) (err error) { _, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&procSetuid)), 1, uintptr(uid), 0, 0, 0, 0, 0) if e1 != 0 { @@ -1357,6 +1601,8 @@ func Setuid(uid int) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Shutdown(s int, how int) (err error) { _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procshutdown)), 2, uintptr(s), uintptr(how), 0, 0, 0, 0) if e1 != 0 { @@ -1365,6 +1611,8 @@ func Shutdown(s int, how int) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Stat(path string, stat *Stat_t) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -1378,6 +1626,8 @@ func Stat(path string, stat *Stat_t) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Statvfs(path string, vfsstat *Statvfs_t) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -1391,6 +1641,8 @@ func Statvfs(path string, vfsstat *Statvfs_t) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Symlink(path string, link string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -1409,6 +1661,8 @@ func Symlink(path string, link string) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Sync() (err error) { _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procSync)), 0, 0, 0, 0, 0, 0, 0) if e1 != 0 { @@ -1417,6 +1671,8 @@ func Sync() (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Times(tms *Tms) (ticks uintptr, err error) { r0, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&procTimes)), 1, uintptr(unsafe.Pointer(tms)), 0, 0, 0, 0, 0) ticks = uintptr(r0) @@ -1426,6 +1682,8 @@ func Times(tms *Tms) (ticks uintptr, err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Truncate(path string, length int64) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -1439,6 +1697,8 @@ func Truncate(path string, length int64) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fsync(fd int) (err error) { _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procFsync)), 1, uintptr(fd), 0, 0, 0, 0, 0) if e1 != 0 { @@ -1447,6 +1707,8 @@ func Fsync(fd int) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Ftruncate(fd int, length int64) (err error) { _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procFtruncate)), 2, uintptr(fd), uintptr(length), 0, 0, 0, 0) if e1 != 0 { @@ -1455,12 +1717,16 @@ func Ftruncate(fd int, length int64) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Umask(mask int) (oldmask int) { r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&procUmask)), 1, uintptr(mask), 0, 0, 0, 0, 0) oldmask = int(r0) return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Uname(buf *Utsname) (err error) { _, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&procUname)), 1, uintptr(unsafe.Pointer(buf)), 0, 0, 0, 0, 0) if e1 != 0 { @@ -1469,6 +1735,8 @@ func Uname(buf *Utsname) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Unmount(target string, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(target) @@ -1482,6 +1750,8 @@ func Unmount(target string, flags int) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Unlink(path string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -1495,6 +1765,8 @@ func Unlink(path string) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Unlinkat(dirfd int, path string, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -1508,6 +1780,8 @@ func Unlinkat(dirfd int, path string, flags int) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Ustat(dev int, ubuf *Ustat_t) (err error) { _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procUstat)), 2, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0, 0, 0, 0) if e1 != 0 { @@ -1516,6 +1790,8 @@ func Ustat(dev int, ubuf *Ustat_t) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Utime(path string, buf *Utimbuf) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -1529,6 +1805,8 @@ func Utime(path string, buf *Utimbuf) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&proc__xnet_bind)), 3, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0) if e1 != 0 { @@ -1537,6 +1815,8 @@ func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&proc__xnet_connect)), 3, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0) if e1 != 0 { @@ -1545,6 +1825,8 @@ func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) { r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procmmap)), 6, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos)) ret = uintptr(r0) @@ -1554,6 +1836,8 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) ( return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func munmap(addr uintptr, length uintptr) (err error) { _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procmunmap)), 2, uintptr(addr), uintptr(length), 0, 0, 0, 0) if e1 != 0 { @@ -1562,6 +1846,19 @@ func munmap(addr uintptr, length uintptr) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { + r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procsendfile)), 4, uintptr(outfd), uintptr(infd), uintptr(unsafe.Pointer(offset)), uintptr(count), 0, 0) + written = int(r0) + if e1 != 0 { + err = e1 + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) { var _p0 *byte if len(buf) > 0 { @@ -1574,6 +1871,8 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) ( return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func socket(domain int, typ int, proto int) (fd int, err error) { r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&proc__xnet_socket)), 3, uintptr(domain), uintptr(typ), uintptr(proto), 0, 0, 0) fd = int(r0) @@ -1583,6 +1882,8 @@ func socket(domain int, typ int, proto int) (fd int, err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) { _, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&proc__xnet_socketpair)), 4, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0) if e1 != 0 { @@ -1591,6 +1892,8 @@ func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func write(fd int, p []byte) (n int, err error) { var _p0 *byte if len(p) > 0 { @@ -1604,6 +1907,8 @@ func write(fd int, p []byte) (n int, err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) { _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&proc__xnet_getsockopt)), 5, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0) if e1 != 0 { @@ -1612,6 +1917,8 @@ func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { _, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&procgetpeername)), 3, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0) if e1 != 0 { @@ -1620,6 +1927,8 @@ func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) { _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procsetsockopt)), 5, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0) if e1 != 0 { @@ -1628,6 +1937,8 @@ func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) return } +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) { var _p0 *byte if len(p) > 0 { diff --git a/vendor/golang.org/x/sys/unix/zsysctl_openbsd_386.go b/vendor/golang.org/x/sys/unix/zsysctl_openbsd_386.go index 83bb935b91..b005031abe 100644 --- a/vendor/golang.org/x/sys/unix/zsysctl_openbsd_386.go +++ b/vendor/golang.org/x/sys/unix/zsysctl_openbsd_386.go @@ -1,5 +1,5 @@ // mksysctl_openbsd.pl -// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// Code generated by the command above; DO NOT EDIT. package unix diff --git a/vendor/golang.org/x/sys/unix/zsysctl_openbsd_amd64.go b/vendor/golang.org/x/sys/unix/zsysctl_openbsd_amd64.go index 83bb935b91..d014451c9d 100644 --- a/vendor/golang.org/x/sys/unix/zsysctl_openbsd_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsysctl_openbsd_amd64.go @@ -1,5 +1,7 @@ // mksysctl_openbsd.pl -// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// Code generated by the command above; DO NOT EDIT. + +// +build amd64,openbsd package unix @@ -14,6 +16,7 @@ var sysctlMib = []mibentry{ {"ddb.max_line", []_C_int{9, 3}}, {"ddb.max_width", []_C_int{9, 2}}, {"ddb.panic", []_C_int{9, 5}}, + {"ddb.profile", []_C_int{9, 9}}, {"ddb.radix", []_C_int{9, 1}}, {"ddb.tab_stop_width", []_C_int{9, 4}}, {"ddb.trigger", []_C_int{9, 8}}, @@ -29,6 +32,7 @@ var sysctlMib = []mibentry{ {"hw.ncpu", []_C_int{6, 3}}, {"hw.ncpufound", []_C_int{6, 21}}, {"hw.pagesize", []_C_int{6, 7}}, + {"hw.perfpolicy", []_C_int{6, 23}}, {"hw.physmem", []_C_int{6, 19}}, {"hw.product", []_C_int{6, 15}}, {"hw.serialno", []_C_int{6, 17}}, @@ -37,7 +41,7 @@ var sysctlMib = []mibentry{ {"hw.uuid", []_C_int{6, 18}}, {"hw.vendor", []_C_int{6, 14}}, {"hw.version", []_C_int{6, 16}}, - {"kern.arandom", []_C_int{1, 37}}, + {"kern.allowkmem", []_C_int{1, 52}}, {"kern.argmax", []_C_int{1, 8}}, {"kern.boottime", []_C_int{1, 21}}, {"kern.bufcachepercent", []_C_int{1, 72}}, @@ -46,12 +50,13 @@ var sysctlMib = []mibentry{ {"kern.consdev", []_C_int{1, 75}}, {"kern.cp_time", []_C_int{1, 40}}, {"kern.cp_time2", []_C_int{1, 71}}, - {"kern.cryptodevallowsoft", []_C_int{1, 53}}, + {"kern.dnsjackport", []_C_int{1, 13}}, {"kern.domainname", []_C_int{1, 22}}, {"kern.file", []_C_int{1, 73}}, {"kern.forkstat", []_C_int{1, 42}}, {"kern.fscale", []_C_int{1, 46}}, {"kern.fsync", []_C_int{1, 33}}, + {"kern.global_ptrace", []_C_int{1, 81}}, {"kern.hostid", []_C_int{1, 11}}, {"kern.hostname", []_C_int{1, 10}}, {"kern.intrcnt.nintrcnt", []_C_int{1, 63, 1}}, @@ -84,7 +89,6 @@ var sysctlMib = []mibentry{ {"kern.pool_debug", []_C_int{1, 77}}, {"kern.posix1version", []_C_int{1, 17}}, {"kern.proc", []_C_int{1, 66}}, - {"kern.random", []_C_int{1, 31}}, {"kern.rawpartition", []_C_int{1, 24}}, {"kern.saved_ids", []_C_int{1, 20}}, {"kern.securelevel", []_C_int{1, 9}}, @@ -102,21 +106,16 @@ var sysctlMib = []mibentry{ {"kern.timecounter.hardware", []_C_int{1, 69, 3}}, {"kern.timecounter.tick", []_C_int{1, 69, 1}}, {"kern.timecounter.timestepwarnings", []_C_int{1, 69, 2}}, - {"kern.tty.maxptys", []_C_int{1, 44, 6}}, - {"kern.tty.nptys", []_C_int{1, 44, 7}}, {"kern.tty.tk_cancc", []_C_int{1, 44, 4}}, {"kern.tty.tk_nin", []_C_int{1, 44, 1}}, {"kern.tty.tk_nout", []_C_int{1, 44, 2}}, {"kern.tty.tk_rawcc", []_C_int{1, 44, 3}}, {"kern.tty.ttyinfo", []_C_int{1, 44, 5}}, {"kern.ttycount", []_C_int{1, 57}}, - {"kern.userasymcrypto", []_C_int{1, 60}}, - {"kern.usercrypto", []_C_int{1, 52}}, - {"kern.usermount", []_C_int{1, 30}}, {"kern.version", []_C_int{1, 4}}, - {"kern.vnode", []_C_int{1, 13}}, {"kern.watchdog.auto", []_C_int{1, 64, 2}}, {"kern.watchdog.period", []_C_int{1, 64, 1}}, + {"kern.wxabort", []_C_int{1, 74}}, {"net.bpf.bufsize", []_C_int{4, 31, 1}}, {"net.bpf.maxbufsize", []_C_int{4, 31, 2}}, {"net.inet.ah.enable", []_C_int{4, 2, 51, 1}}, @@ -144,7 +143,9 @@ var sysctlMib = []mibentry{ {"net.inet.icmp.stats", []_C_int{4, 2, 1, 7}}, {"net.inet.icmp.tstamprepl", []_C_int{4, 2, 1, 6}}, {"net.inet.igmp.stats", []_C_int{4, 2, 2, 1}}, + {"net.inet.ip.arpdown", []_C_int{4, 2, 0, 40}}, {"net.inet.ip.arpqueued", []_C_int{4, 2, 0, 36}}, + {"net.inet.ip.arptimeout", []_C_int{4, 2, 0, 39}}, {"net.inet.ip.encdebug", []_C_int{4, 2, 0, 12}}, {"net.inet.ip.forwarding", []_C_int{4, 2, 0, 1}}, {"net.inet.ip.ifq.congestion", []_C_int{4, 2, 0, 30, 4}}, @@ -153,8 +154,10 @@ var sysctlMib = []mibentry{ {"net.inet.ip.ifq.maxlen", []_C_int{4, 2, 0, 30, 2}}, {"net.inet.ip.maxqueue", []_C_int{4, 2, 0, 11}}, {"net.inet.ip.mforwarding", []_C_int{4, 2, 0, 31}}, + {"net.inet.ip.mrtmfc", []_C_int{4, 2, 0, 37}}, {"net.inet.ip.mrtproto", []_C_int{4, 2, 0, 34}}, {"net.inet.ip.mrtstats", []_C_int{4, 2, 0, 35}}, + {"net.inet.ip.mrtvif", []_C_int{4, 2, 0, 38}}, {"net.inet.ip.mtu", []_C_int{4, 2, 0, 4}}, {"net.inet.ip.mtudisc", []_C_int{4, 2, 0, 27}}, {"net.inet.ip.mtudisctimeout", []_C_int{4, 2, 0, 28}}, @@ -173,7 +176,6 @@ var sysctlMib = []mibentry{ {"net.inet.ipip.stats", []_C_int{4, 2, 4, 2}}, {"net.inet.mobileip.allow", []_C_int{4, 2, 55, 1}}, {"net.inet.pfsync.stats", []_C_int{4, 2, 240, 1}}, - {"net.inet.pim.stats", []_C_int{4, 2, 103, 1}}, {"net.inet.tcp.ackonpush", []_C_int{4, 2, 6, 13}}, {"net.inet.tcp.always_keepalive", []_C_int{4, 2, 6, 22}}, {"net.inet.tcp.baddynamic", []_C_int{4, 2, 6, 6}}, @@ -187,6 +189,7 @@ var sysctlMib = []mibentry{ {"net.inet.tcp.reasslimit", []_C_int{4, 2, 6, 18}}, {"net.inet.tcp.rfc1323", []_C_int{4, 2, 6, 1}}, {"net.inet.tcp.rfc3390", []_C_int{4, 2, 6, 17}}, + {"net.inet.tcp.rootonly", []_C_int{4, 2, 6, 24}}, {"net.inet.tcp.rstppslimit", []_C_int{4, 2, 6, 12}}, {"net.inet.tcp.sack", []_C_int{4, 2, 6, 10}}, {"net.inet.tcp.sackholelimit", []_C_int{4, 2, 6, 20}}, @@ -194,9 +197,12 @@ var sysctlMib = []mibentry{ {"net.inet.tcp.stats", []_C_int{4, 2, 6, 21}}, {"net.inet.tcp.synbucketlimit", []_C_int{4, 2, 6, 16}}, {"net.inet.tcp.syncachelimit", []_C_int{4, 2, 6, 15}}, + {"net.inet.tcp.synhashsize", []_C_int{4, 2, 6, 25}}, + {"net.inet.tcp.synuselimit", []_C_int{4, 2, 6, 23}}, {"net.inet.udp.baddynamic", []_C_int{4, 2, 17, 2}}, {"net.inet.udp.checksum", []_C_int{4, 2, 17, 1}}, {"net.inet.udp.recvspace", []_C_int{4, 2, 17, 3}}, + {"net.inet.udp.rootonly", []_C_int{4, 2, 17, 6}}, {"net.inet.udp.sendspace", []_C_int{4, 2, 17, 4}}, {"net.inet.udp.stats", []_C_int{4, 2, 17, 5}}, {"net.inet6.divert.recvspace", []_C_int{4, 24, 86, 1}}, @@ -209,13 +215,8 @@ var sysctlMib = []mibentry{ {"net.inet6.icmp6.nd6_delay", []_C_int{4, 24, 30, 8}}, {"net.inet6.icmp6.nd6_maxnudhint", []_C_int{4, 24, 30, 15}}, {"net.inet6.icmp6.nd6_mmaxtries", []_C_int{4, 24, 30, 10}}, - {"net.inet6.icmp6.nd6_prune", []_C_int{4, 24, 30, 6}}, {"net.inet6.icmp6.nd6_umaxtries", []_C_int{4, 24, 30, 9}}, - {"net.inet6.icmp6.nd6_useloopback", []_C_int{4, 24, 30, 11}}, - {"net.inet6.icmp6.nodeinfo", []_C_int{4, 24, 30, 13}}, - {"net.inet6.icmp6.rediraccept", []_C_int{4, 24, 30, 2}}, {"net.inet6.icmp6.redirtimeout", []_C_int{4, 24, 30, 3}}, - {"net.inet6.ip6.accept_rtadv", []_C_int{4, 24, 17, 12}}, {"net.inet6.ip6.auto_flowlabel", []_C_int{4, 24, 17, 17}}, {"net.inet6.ip6.dad_count", []_C_int{4, 24, 17, 16}}, {"net.inet6.ip6.dad_pending", []_C_int{4, 24, 17, 49}}, @@ -228,20 +229,19 @@ var sysctlMib = []mibentry{ {"net.inet6.ip6.maxdynroutes", []_C_int{4, 24, 17, 48}}, {"net.inet6.ip6.maxfragpackets", []_C_int{4, 24, 17, 9}}, {"net.inet6.ip6.maxfrags", []_C_int{4, 24, 17, 41}}, - {"net.inet6.ip6.maxifdefrouters", []_C_int{4, 24, 17, 47}}, - {"net.inet6.ip6.maxifprefixes", []_C_int{4, 24, 17, 46}}, {"net.inet6.ip6.mforwarding", []_C_int{4, 24, 17, 42}}, + {"net.inet6.ip6.mrtmfc", []_C_int{4, 24, 17, 53}}, + {"net.inet6.ip6.mrtmif", []_C_int{4, 24, 17, 52}}, {"net.inet6.ip6.mrtproto", []_C_int{4, 24, 17, 8}}, {"net.inet6.ip6.mtudisctimeout", []_C_int{4, 24, 17, 50}}, {"net.inet6.ip6.multicast_mtudisc", []_C_int{4, 24, 17, 44}}, {"net.inet6.ip6.multipath", []_C_int{4, 24, 17, 43}}, {"net.inet6.ip6.neighborgcthresh", []_C_int{4, 24, 17, 45}}, {"net.inet6.ip6.redirect", []_C_int{4, 24, 17, 2}}, - {"net.inet6.ip6.rr_prune", []_C_int{4, 24, 17, 22}}, + {"net.inet6.ip6.soiikey", []_C_int{4, 24, 17, 54}}, {"net.inet6.ip6.sourcecheck", []_C_int{4, 24, 17, 10}}, {"net.inet6.ip6.sourcecheck_logint", []_C_int{4, 24, 17, 11}}, {"net.inet6.ip6.use_deprecated", []_C_int{4, 24, 17, 21}}, - {"net.inet6.ip6.v6only", []_C_int{4, 24, 17, 24}}, {"net.key.sadb_dump", []_C_int{4, 30, 1}}, {"net.key.spd_dump", []_C_int{4, 30, 2}}, {"net.mpls.ifq.congestion", []_C_int{4, 33, 3, 4}}, diff --git a/vendor/golang.org/x/sys/unix/zsysctl_openbsd_arm.go b/vendor/golang.org/x/sys/unix/zsysctl_openbsd_arm.go index 83bb935b91..b005031abe 100644 --- a/vendor/golang.org/x/sys/unix/zsysctl_openbsd_arm.go +++ b/vendor/golang.org/x/sys/unix/zsysctl_openbsd_arm.go @@ -1,5 +1,5 @@ // mksysctl_openbsd.pl -// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// Code generated by the command above; DO NOT EDIT. package unix diff --git a/vendor/golang.org/x/sys/unix/zsysnum_darwin_386.go b/vendor/golang.org/x/sys/unix/zsysnum_darwin_386.go index d1d36da3f5..f33614532f 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_darwin_386.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_darwin_386.go @@ -1,4 +1,4 @@ -// mksysnum_darwin.pl /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/usr/include/sys/syscall.h +// go run mksysnum.go /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/usr/include/sys/syscall.h // Code generated by the command above; see README.md. DO NOT EDIT. // +build 386,darwin diff --git a/vendor/golang.org/x/sys/unix/zsysnum_darwin_amd64.go b/vendor/golang.org/x/sys/unix/zsysnum_darwin_amd64.go index e35de4145e..654dd3da3b 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_darwin_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_darwin_amd64.go @@ -1,4 +1,4 @@ -// mksysnum_darwin.pl /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/usr/include/sys/syscall.h +// go run mksysnum.go /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/include/sys/syscall.h // Code generated by the command above; see README.md. DO NOT EDIT. // +build amd64,darwin @@ -431,6 +431,8 @@ const ( SYS_NTP_ADJTIME = 527 SYS_NTP_GETTIME = 528 SYS_OS_FAULT_WITH_PAYLOAD = 529 - SYS_MAXSYSCALL = 530 + SYS_KQUEUE_WORKLOOP_CTL = 530 + SYS___MACH_BRIDGE_REMOTE_TIME = 531 + SYS_MAXSYSCALL = 532 SYS_INVALID = 63 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_darwin_arm.go b/vendor/golang.org/x/sys/unix/zsysnum_darwin_arm.go index f2df27db2c..103a72ed1c 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_darwin_arm.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_darwin_arm.go @@ -1,4 +1,4 @@ -// mksysnum_darwin.pl /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.1.sdk/usr/include/sys/syscall.h +// go run mksysnum.go /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.1.sdk/usr/include/sys/syscall.h // Code generated by the command above; see README.md. DO NOT EDIT. // +build arm,darwin diff --git a/vendor/golang.org/x/sys/unix/zsysnum_darwin_arm64.go b/vendor/golang.org/x/sys/unix/zsysnum_darwin_arm64.go index 9694630232..7ab2130b96 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_darwin_arm64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_darwin_arm64.go @@ -1,4 +1,4 @@ -// mksysnum_darwin.pl /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.1.sdk/usr/include/sys/syscall.h +// go run mksysnum.go /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.1.sdk/usr/include/sys/syscall.h // Code generated by the command above; see README.md. DO NOT EDIT. // +build arm64,darwin diff --git a/vendor/golang.org/x/sys/unix/zsysnum_dragonfly_amd64.go b/vendor/golang.org/x/sys/unix/zsysnum_dragonfly_amd64.go index b2c9ef81b8..464c9a9832 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_dragonfly_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_dragonfly_amd64.go @@ -1,4 +1,4 @@ -// mksysnum_dragonfly.pl +// go run mksysnum.go https://gitweb.dragonflybsd.org/dragonfly.git/blob_plain/HEAD:/sys/kern/syscalls.master // Code generated by the command above; see README.md. DO NOT EDIT. // +build amd64,dragonfly @@ -13,7 +13,7 @@ const ( SYS_WRITE = 4 // { ssize_t write(int fd, const void *buf, size_t nbyte); } SYS_OPEN = 5 // { int open(char *path, int flags, int mode); } SYS_CLOSE = 6 // { int close(int fd); } - SYS_WAIT4 = 7 // { int wait4(int pid, int *status, int options, \ + SYS_WAIT4 = 7 // { int wait4(int pid, int *status, int options, struct rusage *rusage); } wait4 wait_args int SYS_LINK = 9 // { int link(char *path, char *link); } SYS_UNLINK = 10 // { int unlink(char *path); } SYS_CHDIR = 12 // { int chdir(char *path); } @@ -22,17 +22,17 @@ const ( SYS_CHMOD = 15 // { int chmod(char *path, int mode); } SYS_CHOWN = 16 // { int chown(char *path, int uid, int gid); } SYS_OBREAK = 17 // { int obreak(char *nsize); } break obreak_args int - SYS_GETFSSTAT = 18 // { int getfsstat(struct statfs *buf, long bufsize, \ + SYS_GETFSSTAT = 18 // { int getfsstat(struct statfs *buf, long bufsize, int flags); } SYS_GETPID = 20 // { pid_t getpid(void); } - SYS_MOUNT = 21 // { int mount(char *type, char *path, int flags, \ + SYS_MOUNT = 21 // { int mount(char *type, char *path, int flags, caddr_t data); } SYS_UNMOUNT = 22 // { int unmount(char *path, int flags); } SYS_SETUID = 23 // { int setuid(uid_t uid); } SYS_GETUID = 24 // { uid_t getuid(void); } SYS_GETEUID = 25 // { uid_t geteuid(void); } - SYS_PTRACE = 26 // { int ptrace(int req, pid_t pid, caddr_t addr, \ + SYS_PTRACE = 26 // { int ptrace(int req, pid_t pid, caddr_t addr, int data); } SYS_RECVMSG = 27 // { int recvmsg(int s, struct msghdr *msg, int flags); } SYS_SENDMSG = 28 // { int sendmsg(int s, caddr_t msg, int flags); } - SYS_RECVFROM = 29 // { int recvfrom(int s, caddr_t buf, size_t len, \ + SYS_RECVFROM = 29 // { int recvfrom(int s, caddr_t buf, size_t len, int flags, caddr_t from, int *fromlenaddr); } SYS_ACCEPT = 30 // { int accept(int s, caddr_t name, int *anamelen); } SYS_GETPEERNAME = 31 // { int getpeername(int fdes, caddr_t asa, int *alen); } SYS_GETSOCKNAME = 32 // { int getsockname(int fdes, caddr_t asa, int *alen); } @@ -45,8 +45,8 @@ const ( SYS_DUP = 41 // { int dup(int fd); } SYS_PIPE = 42 // { int pipe(void); } SYS_GETEGID = 43 // { gid_t getegid(void); } - SYS_PROFIL = 44 // { int profil(caddr_t samples, size_t size, \ - SYS_KTRACE = 45 // { int ktrace(const char *fname, int ops, int facs, \ + SYS_PROFIL = 44 // { int profil(caddr_t samples, size_t size, size_t offset, u_int scale); } + SYS_KTRACE = 45 // { int ktrace(const char *fname, int ops, int facs, int pid); } SYS_GETGID = 47 // { gid_t getgid(void); } SYS_GETLOGIN = 49 // { int getlogin(char *namebuf, u_int namelen); } SYS_SETLOGIN = 50 // { int setlogin(char *namebuf); } @@ -67,32 +67,32 @@ const ( SYS_MUNMAP = 73 // { int munmap(void *addr, size_t len); } SYS_MPROTECT = 74 // { int mprotect(void *addr, size_t len, int prot); } SYS_MADVISE = 75 // { int madvise(void *addr, size_t len, int behav); } - SYS_MINCORE = 78 // { int mincore(const void *addr, size_t len, \ + SYS_MINCORE = 78 // { int mincore(const void *addr, size_t len, char *vec); } SYS_GETGROUPS = 79 // { int getgroups(u_int gidsetsize, gid_t *gidset); } SYS_SETGROUPS = 80 // { int setgroups(u_int gidsetsize, gid_t *gidset); } SYS_GETPGRP = 81 // { int getpgrp(void); } SYS_SETPGID = 82 // { int setpgid(int pid, int pgid); } - SYS_SETITIMER = 83 // { int setitimer(u_int which, struct itimerval *itv, \ + SYS_SETITIMER = 83 // { int setitimer(u_int which, struct itimerval *itv, struct itimerval *oitv); } SYS_SWAPON = 85 // { int swapon(char *name); } SYS_GETITIMER = 86 // { int getitimer(u_int which, struct itimerval *itv); } SYS_GETDTABLESIZE = 89 // { int getdtablesize(void); } SYS_DUP2 = 90 // { int dup2(int from, int to); } SYS_FCNTL = 92 // { int fcntl(int fd, int cmd, long arg); } - SYS_SELECT = 93 // { int select(int nd, fd_set *in, fd_set *ou, \ + SYS_SELECT = 93 // { int select(int nd, fd_set *in, fd_set *ou, fd_set *ex, struct timeval *tv); } SYS_FSYNC = 95 // { int fsync(int fd); } SYS_SETPRIORITY = 96 // { int setpriority(int which, int who, int prio); } SYS_SOCKET = 97 // { int socket(int domain, int type, int protocol); } SYS_CONNECT = 98 // { int connect(int s, caddr_t name, int namelen); } SYS_GETPRIORITY = 100 // { int getpriority(int which, int who); } SYS_BIND = 104 // { int bind(int s, caddr_t name, int namelen); } - SYS_SETSOCKOPT = 105 // { int setsockopt(int s, int level, int name, \ + SYS_SETSOCKOPT = 105 // { int setsockopt(int s, int level, int name, caddr_t val, int valsize); } SYS_LISTEN = 106 // { int listen(int s, int backlog); } - SYS_GETTIMEOFDAY = 116 // { int gettimeofday(struct timeval *tp, \ + SYS_GETTIMEOFDAY = 116 // { int gettimeofday(struct timeval *tp, struct timezone *tzp); } SYS_GETRUSAGE = 117 // { int getrusage(int who, struct rusage *rusage); } - SYS_GETSOCKOPT = 118 // { int getsockopt(int s, int level, int name, \ + SYS_GETSOCKOPT = 118 // { int getsockopt(int s, int level, int name, caddr_t val, int *avalsize); } SYS_READV = 120 // { int readv(int fd, struct iovec *iovp, u_int iovcnt); } - SYS_WRITEV = 121 // { int writev(int fd, struct iovec *iovp, \ - SYS_SETTIMEOFDAY = 122 // { int settimeofday(struct timeval *tv, \ + SYS_WRITEV = 121 // { int writev(int fd, struct iovec *iovp, u_int iovcnt); } + SYS_SETTIMEOFDAY = 122 // { int settimeofday(struct timeval *tv, struct timezone *tzp); } SYS_FCHOWN = 123 // { int fchown(int fd, int uid, int gid); } SYS_FCHMOD = 124 // { int fchmod(int fd, int mode); } SYS_SETREUID = 126 // { int setreuid(int ruid, int euid); } @@ -100,15 +100,15 @@ const ( SYS_RENAME = 128 // { int rename(char *from, char *to); } SYS_FLOCK = 131 // { int flock(int fd, int how); } SYS_MKFIFO = 132 // { int mkfifo(char *path, int mode); } - SYS_SENDTO = 133 // { int sendto(int s, caddr_t buf, size_t len, \ + SYS_SENDTO = 133 // { int sendto(int s, caddr_t buf, size_t len, int flags, caddr_t to, int tolen); } SYS_SHUTDOWN = 134 // { int shutdown(int s, int how); } - SYS_SOCKETPAIR = 135 // { int socketpair(int domain, int type, int protocol, \ + SYS_SOCKETPAIR = 135 // { int socketpair(int domain, int type, int protocol, int *rsv); } SYS_MKDIR = 136 // { int mkdir(char *path, int mode); } SYS_RMDIR = 137 // { int rmdir(char *path); } SYS_UTIMES = 138 // { int utimes(char *path, struct timeval *tptr); } - SYS_ADJTIME = 140 // { int adjtime(struct timeval *delta, \ + SYS_ADJTIME = 140 // { int adjtime(struct timeval *delta, struct timeval *olddelta); } SYS_SETSID = 147 // { int setsid(void); } - SYS_QUOTACTL = 148 // { int quotactl(char *path, int cmd, int uid, \ + SYS_QUOTACTL = 148 // { int quotactl(char *path, int cmd, int uid, caddr_t arg); } SYS_STATFS = 157 // { int statfs(char *path, struct statfs *buf); } SYS_FSTATFS = 158 // { int fstatfs(int fd, struct statfs *buf); } SYS_GETFH = 161 // { int getfh(char *fname, struct fhandle *fhp); } @@ -116,53 +116,53 @@ const ( SYS_SETDOMAINNAME = 163 // { int setdomainname(char *domainname, int len); } SYS_UNAME = 164 // { int uname(struct utsname *name); } SYS_SYSARCH = 165 // { int sysarch(int op, char *parms); } - SYS_RTPRIO = 166 // { int rtprio(int function, pid_t pid, \ - SYS_EXTPREAD = 173 // { ssize_t extpread(int fd, void *buf, \ - SYS_EXTPWRITE = 174 // { ssize_t extpwrite(int fd, const void *buf, \ + SYS_RTPRIO = 166 // { int rtprio(int function, pid_t pid, struct rtprio *rtp); } + SYS_EXTPREAD = 173 // { ssize_t extpread(int fd, void *buf, size_t nbyte, int flags, off_t offset); } + SYS_EXTPWRITE = 174 // { ssize_t extpwrite(int fd, const void *buf, size_t nbyte, int flags, off_t offset); } SYS_NTP_ADJTIME = 176 // { int ntp_adjtime(struct timex *tp); } SYS_SETGID = 181 // { int setgid(gid_t gid); } SYS_SETEGID = 182 // { int setegid(gid_t egid); } SYS_SETEUID = 183 // { int seteuid(uid_t euid); } SYS_PATHCONF = 191 // { int pathconf(char *path, int name); } SYS_FPATHCONF = 192 // { int fpathconf(int fd, int name); } - SYS_GETRLIMIT = 194 // { int getrlimit(u_int which, \ - SYS_SETRLIMIT = 195 // { int setrlimit(u_int which, \ - SYS_MMAP = 197 // { caddr_t mmap(caddr_t addr, size_t len, int prot, \ + SYS_GETRLIMIT = 194 // { int getrlimit(u_int which, struct rlimit *rlp); } getrlimit __getrlimit_args int + SYS_SETRLIMIT = 195 // { int setrlimit(u_int which, struct rlimit *rlp); } setrlimit __setrlimit_args int + SYS_MMAP = 197 // { caddr_t mmap(caddr_t addr, size_t len, int prot, int flags, int fd, int pad, off_t pos); } // SYS_NOSYS = 198; // { int nosys(void); } __syscall __syscall_args int - SYS_LSEEK = 199 // { off_t lseek(int fd, int pad, off_t offset, \ + SYS_LSEEK = 199 // { off_t lseek(int fd, int pad, off_t offset, int whence); } SYS_TRUNCATE = 200 // { int truncate(char *path, int pad, off_t length); } SYS_FTRUNCATE = 201 // { int ftruncate(int fd, int pad, off_t length); } - SYS___SYSCTL = 202 // { int __sysctl(int *name, u_int namelen, void *old, \ + SYS___SYSCTL = 202 // { int __sysctl(int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen); } __sysctl sysctl_args int SYS_MLOCK = 203 // { int mlock(const void *addr, size_t len); } SYS_MUNLOCK = 204 // { int munlock(const void *addr, size_t len); } SYS_UNDELETE = 205 // { int undelete(char *path); } SYS_FUTIMES = 206 // { int futimes(int fd, struct timeval *tptr); } SYS_GETPGID = 207 // { int getpgid(pid_t pid); } - SYS_POLL = 209 // { int poll(struct pollfd *fds, u_int nfds, \ - SYS___SEMCTL = 220 // { int __semctl(int semid, int semnum, int cmd, \ + SYS_POLL = 209 // { int poll(struct pollfd *fds, u_int nfds, int timeout); } + SYS___SEMCTL = 220 // { int __semctl(int semid, int semnum, int cmd, union semun *arg); } SYS_SEMGET = 221 // { int semget(key_t key, int nsems, int semflg); } - SYS_SEMOP = 222 // { int semop(int semid, struct sembuf *sops, \ - SYS_MSGCTL = 224 // { int msgctl(int msqid, int cmd, \ + SYS_SEMOP = 222 // { int semop(int semid, struct sembuf *sops, u_int nsops); } + SYS_MSGCTL = 224 // { int msgctl(int msqid, int cmd, struct msqid_ds *buf); } SYS_MSGGET = 225 // { int msgget(key_t key, int msgflg); } - SYS_MSGSND = 226 // { int msgsnd(int msqid, const void *msgp, size_t msgsz, \ - SYS_MSGRCV = 227 // { int msgrcv(int msqid, void *msgp, size_t msgsz, \ - SYS_SHMAT = 228 // { caddr_t shmat(int shmid, const void *shmaddr, \ - SYS_SHMCTL = 229 // { int shmctl(int shmid, int cmd, \ + SYS_MSGSND = 226 // { int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); } + SYS_MSGRCV = 227 // { int msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); } + SYS_SHMAT = 228 // { caddr_t shmat(int shmid, const void *shmaddr, int shmflg); } + SYS_SHMCTL = 229 // { int shmctl(int shmid, int cmd, struct shmid_ds *buf); } SYS_SHMDT = 230 // { int shmdt(const void *shmaddr); } SYS_SHMGET = 231 // { int shmget(key_t key, size_t size, int shmflg); } - SYS_CLOCK_GETTIME = 232 // { int clock_gettime(clockid_t clock_id, \ - SYS_CLOCK_SETTIME = 233 // { int clock_settime(clockid_t clock_id, \ - SYS_CLOCK_GETRES = 234 // { int clock_getres(clockid_t clock_id, \ - SYS_NANOSLEEP = 240 // { int nanosleep(const struct timespec *rqtp, \ + SYS_CLOCK_GETTIME = 232 // { int clock_gettime(clockid_t clock_id, struct timespec *tp); } + SYS_CLOCK_SETTIME = 233 // { int clock_settime(clockid_t clock_id, const struct timespec *tp); } + SYS_CLOCK_GETRES = 234 // { int clock_getres(clockid_t clock_id, struct timespec *tp); } + SYS_NANOSLEEP = 240 // { int nanosleep(const struct timespec *rqtp, struct timespec *rmtp); } SYS_MINHERIT = 250 // { int minherit(void *addr, size_t len, int inherit); } SYS_RFORK = 251 // { int rfork(int flags); } - SYS_OPENBSD_POLL = 252 // { int openbsd_poll(struct pollfd *fds, u_int nfds, \ + SYS_OPENBSD_POLL = 252 // { int openbsd_poll(struct pollfd *fds, u_int nfds, int timeout); } SYS_ISSETUGID = 253 // { int issetugid(void); } SYS_LCHOWN = 254 // { int lchown(char *path, int uid, int gid); } SYS_LCHMOD = 274 // { int lchmod(char *path, mode_t mode); } SYS_LUTIMES = 276 // { int lutimes(char *path, struct timeval *tptr); } - SYS_EXTPREADV = 289 // { ssize_t extpreadv(int fd, struct iovec *iovp, \ - SYS_EXTPWRITEV = 290 // { ssize_t extpwritev(int fd, struct iovec *iovp,\ + SYS_EXTPREADV = 289 // { ssize_t extpreadv(int fd, struct iovec *iovp, u_int iovcnt, int flags, off_t offset); } + SYS_EXTPWRITEV = 290 // { ssize_t extpwritev(int fd, struct iovec *iovp,u_int iovcnt, int flags, off_t offset); } SYS_FHSTATFS = 297 // { int fhstatfs(const struct fhandle *u_fhp, struct statfs *buf); } SYS_FHOPEN = 298 // { int fhopen(const struct fhandle *u_fhp, int flags); } SYS_MODNEXT = 300 // { int modnext(int modid); } @@ -200,34 +200,34 @@ const ( SYS_UTRACE = 335 // { int utrace(const void *addr, size_t len); } SYS_KLDSYM = 337 // { int kldsym(int fileid, int cmd, void *data); } SYS_JAIL = 338 // { int jail(struct jail *jail); } - SYS_SIGPROCMASK = 340 // { int sigprocmask(int how, const sigset_t *set, \ + SYS_SIGPROCMASK = 340 // { int sigprocmask(int how, const sigset_t *set, sigset_t *oset); } SYS_SIGSUSPEND = 341 // { int sigsuspend(const sigset_t *sigmask); } - SYS_SIGACTION = 342 // { int sigaction(int sig, const struct sigaction *act, \ + SYS_SIGACTION = 342 // { int sigaction(int sig, const struct sigaction *act, struct sigaction *oact); } SYS_SIGPENDING = 343 // { int sigpending(sigset_t *set); } SYS_SIGRETURN = 344 // { int sigreturn(ucontext_t *sigcntxp); } - SYS_SIGTIMEDWAIT = 345 // { int sigtimedwait(const sigset_t *set,\ - SYS_SIGWAITINFO = 346 // { int sigwaitinfo(const sigset_t *set,\ - SYS___ACL_GET_FILE = 347 // { int __acl_get_file(const char *path, \ - SYS___ACL_SET_FILE = 348 // { int __acl_set_file(const char *path, \ - SYS___ACL_GET_FD = 349 // { int __acl_get_fd(int filedes, acl_type_t type, \ - SYS___ACL_SET_FD = 350 // { int __acl_set_fd(int filedes, acl_type_t type, \ - SYS___ACL_DELETE_FILE = 351 // { int __acl_delete_file(const char *path, \ + SYS_SIGTIMEDWAIT = 345 // { int sigtimedwait(const sigset_t *set,siginfo_t *info, const struct timespec *timeout); } + SYS_SIGWAITINFO = 346 // { int sigwaitinfo(const sigset_t *set,siginfo_t *info); } + SYS___ACL_GET_FILE = 347 // { int __acl_get_file(const char *path, acl_type_t type, struct acl *aclp); } + SYS___ACL_SET_FILE = 348 // { int __acl_set_file(const char *path, acl_type_t type, struct acl *aclp); } + SYS___ACL_GET_FD = 349 // { int __acl_get_fd(int filedes, acl_type_t type, struct acl *aclp); } + SYS___ACL_SET_FD = 350 // { int __acl_set_fd(int filedes, acl_type_t type, struct acl *aclp); } + SYS___ACL_DELETE_FILE = 351 // { int __acl_delete_file(const char *path, acl_type_t type); } SYS___ACL_DELETE_FD = 352 // { int __acl_delete_fd(int filedes, acl_type_t type); } - SYS___ACL_ACLCHECK_FILE = 353 // { int __acl_aclcheck_file(const char *path, \ - SYS___ACL_ACLCHECK_FD = 354 // { int __acl_aclcheck_fd(int filedes, acl_type_t type, \ - SYS_EXTATTRCTL = 355 // { int extattrctl(const char *path, int cmd, \ - SYS_EXTATTR_SET_FILE = 356 // { int extattr_set_file(const char *path, \ - SYS_EXTATTR_GET_FILE = 357 // { int extattr_get_file(const char *path, \ - SYS_EXTATTR_DELETE_FILE = 358 // { int extattr_delete_file(const char *path, \ + SYS___ACL_ACLCHECK_FILE = 353 // { int __acl_aclcheck_file(const char *path, acl_type_t type, struct acl *aclp); } + SYS___ACL_ACLCHECK_FD = 354 // { int __acl_aclcheck_fd(int filedes, acl_type_t type, struct acl *aclp); } + SYS_EXTATTRCTL = 355 // { int extattrctl(const char *path, int cmd, const char *filename, int attrnamespace, const char *attrname); } + SYS_EXTATTR_SET_FILE = 356 // { int extattr_set_file(const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes); } + SYS_EXTATTR_GET_FILE = 357 // { int extattr_get_file(const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes); } + SYS_EXTATTR_DELETE_FILE = 358 // { int extattr_delete_file(const char *path, int attrnamespace, const char *attrname); } SYS_AIO_WAITCOMPLETE = 359 // { int aio_waitcomplete(struct aiocb **aiocbp, struct timespec *timeout); } SYS_GETRESUID = 360 // { int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); } SYS_GETRESGID = 361 // { int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); } SYS_KQUEUE = 362 // { int kqueue(void); } - SYS_KEVENT = 363 // { int kevent(int fd, \ + SYS_KEVENT = 363 // { int kevent(int fd, const struct kevent *changelist, int nchanges, struct kevent *eventlist, int nevents, const struct timespec *timeout); } SYS_KENV = 390 // { int kenv(int what, const char *name, char *value, int len); } SYS_LCHFLAGS = 391 // { int lchflags(char *path, int flags); } SYS_UUIDGEN = 392 // { int uuidgen(struct uuid *store, int count); } - SYS_SENDFILE = 393 // { int sendfile(int fd, int s, off_t offset, size_t nbytes, \ + SYS_SENDFILE = 393 // { int sendfile(int fd, int s, off_t offset, size_t nbytes, struct sf_hdtr *hdtr, off_t *sbytes, int flags); } SYS_VARSYM_SET = 450 // { int varsym_set(int level, const char *name, const char *data); } SYS_VARSYM_GET = 451 // { int varsym_get(int mask, const char *wild, char *buf, int bufsize); } SYS_VARSYM_LIST = 452 // { int varsym_list(int level, char *buf, int maxsize, int *marker); } @@ -245,58 +245,58 @@ const ( SYS_FSTAT = 476 // { int fstat(int fd, struct stat *sb); } SYS_LSTAT = 477 // { int lstat(const char *path, struct stat *ub); } SYS_FHSTAT = 478 // { int fhstat(const struct fhandle *u_fhp, struct stat *sb); } - SYS_GETDIRENTRIES = 479 // { int getdirentries(int fd, char *buf, u_int count, \ + SYS_GETDIRENTRIES = 479 // { int getdirentries(int fd, char *buf, u_int count, long *basep); } SYS_GETDENTS = 480 // { int getdents(int fd, char *buf, size_t count); } - SYS_USCHED_SET = 481 // { int usched_set(pid_t pid, int cmd, void *data, \ + SYS_USCHED_SET = 481 // { int usched_set(pid_t pid, int cmd, void *data, int bytes); } SYS_EXTACCEPT = 482 // { int extaccept(int s, int flags, caddr_t name, int *anamelen); } SYS_EXTCONNECT = 483 // { int extconnect(int s, int flags, caddr_t name, int namelen); } SYS_MCONTROL = 485 // { int mcontrol(void *addr, size_t len, int behav, off_t value); } SYS_VMSPACE_CREATE = 486 // { int vmspace_create(void *id, int type, void *data); } SYS_VMSPACE_DESTROY = 487 // { int vmspace_destroy(void *id); } - SYS_VMSPACE_CTL = 488 // { int vmspace_ctl(void *id, int cmd, \ - SYS_VMSPACE_MMAP = 489 // { int vmspace_mmap(void *id, void *addr, size_t len, \ - SYS_VMSPACE_MUNMAP = 490 // { int vmspace_munmap(void *id, void *addr, \ - SYS_VMSPACE_MCONTROL = 491 // { int vmspace_mcontrol(void *id, void *addr, \ - SYS_VMSPACE_PREAD = 492 // { ssize_t vmspace_pread(void *id, void *buf, \ - SYS_VMSPACE_PWRITE = 493 // { ssize_t vmspace_pwrite(void *id, const void *buf, \ + SYS_VMSPACE_CTL = 488 // { int vmspace_ctl(void *id, int cmd, struct trapframe *tframe, struct vextframe *vframe); } + SYS_VMSPACE_MMAP = 489 // { int vmspace_mmap(void *id, void *addr, size_t len, int prot, int flags, int fd, off_t offset); } + SYS_VMSPACE_MUNMAP = 490 // { int vmspace_munmap(void *id, void *addr, size_t len); } + SYS_VMSPACE_MCONTROL = 491 // { int vmspace_mcontrol(void *id, void *addr, size_t len, int behav, off_t value); } + SYS_VMSPACE_PREAD = 492 // { ssize_t vmspace_pread(void *id, void *buf, size_t nbyte, int flags, off_t offset); } + SYS_VMSPACE_PWRITE = 493 // { ssize_t vmspace_pwrite(void *id, const void *buf, size_t nbyte, int flags, off_t offset); } SYS_EXTEXIT = 494 // { void extexit(int how, int status, void *addr); } SYS_LWP_CREATE = 495 // { int lwp_create(struct lwp_params *params); } SYS_LWP_GETTID = 496 // { lwpid_t lwp_gettid(void); } SYS_LWP_KILL = 497 // { int lwp_kill(pid_t pid, lwpid_t tid, int signum); } SYS_LWP_RTPRIO = 498 // { int lwp_rtprio(int function, pid_t pid, lwpid_t tid, struct rtprio *rtp); } - SYS_PSELECT = 499 // { int pselect(int nd, fd_set *in, fd_set *ou, \ + SYS_PSELECT = 499 // { int pselect(int nd, fd_set *in, fd_set *ou, fd_set *ex, const struct timespec *ts, const sigset_t *sigmask); } SYS_STATVFS = 500 // { int statvfs(const char *path, struct statvfs *buf); } SYS_FSTATVFS = 501 // { int fstatvfs(int fd, struct statvfs *buf); } SYS_FHSTATVFS = 502 // { int fhstatvfs(const struct fhandle *u_fhp, struct statvfs *buf); } - SYS_GETVFSSTAT = 503 // { int getvfsstat(struct statfs *buf, \ + SYS_GETVFSSTAT = 503 // { int getvfsstat(struct statfs *buf, struct statvfs *vbuf, long vbufsize, int flags); } SYS_OPENAT = 504 // { int openat(int fd, char *path, int flags, int mode); } - SYS_FSTATAT = 505 // { int fstatat(int fd, char *path, \ - SYS_FCHMODAT = 506 // { int fchmodat(int fd, char *path, int mode, \ - SYS_FCHOWNAT = 507 // { int fchownat(int fd, char *path, int uid, int gid, \ + SYS_FSTATAT = 505 // { int fstatat(int fd, char *path, struct stat *sb, int flags); } + SYS_FCHMODAT = 506 // { int fchmodat(int fd, char *path, int mode, int flags); } + SYS_FCHOWNAT = 507 // { int fchownat(int fd, char *path, int uid, int gid, int flags); } SYS_UNLINKAT = 508 // { int unlinkat(int fd, char *path, int flags); } - SYS_FACCESSAT = 509 // { int faccessat(int fd, char *path, int amode, \ - SYS_MQ_OPEN = 510 // { mqd_t mq_open(const char * name, int oflag, \ + SYS_FACCESSAT = 509 // { int faccessat(int fd, char *path, int amode, int flags); } + SYS_MQ_OPEN = 510 // { mqd_t mq_open(const char * name, int oflag, mode_t mode, struct mq_attr *attr); } SYS_MQ_CLOSE = 511 // { int mq_close(mqd_t mqdes); } SYS_MQ_UNLINK = 512 // { int mq_unlink(const char *name); } - SYS_MQ_GETATTR = 513 // { int mq_getattr(mqd_t mqdes, \ - SYS_MQ_SETATTR = 514 // { int mq_setattr(mqd_t mqdes, \ - SYS_MQ_NOTIFY = 515 // { int mq_notify(mqd_t mqdes, \ - SYS_MQ_SEND = 516 // { int mq_send(mqd_t mqdes, const char *msg_ptr, \ - SYS_MQ_RECEIVE = 517 // { ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, \ - SYS_MQ_TIMEDSEND = 518 // { int mq_timedsend(mqd_t mqdes, \ - SYS_MQ_TIMEDRECEIVE = 519 // { ssize_t mq_timedreceive(mqd_t mqdes, \ + SYS_MQ_GETATTR = 513 // { int mq_getattr(mqd_t mqdes, struct mq_attr *mqstat); } + SYS_MQ_SETATTR = 514 // { int mq_setattr(mqd_t mqdes, const struct mq_attr *mqstat, struct mq_attr *omqstat); } + SYS_MQ_NOTIFY = 515 // { int mq_notify(mqd_t mqdes, const struct sigevent *notification); } + SYS_MQ_SEND = 516 // { int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio); } + SYS_MQ_RECEIVE = 517 // { ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio); } + SYS_MQ_TIMEDSEND = 518 // { int mq_timedsend(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio, const struct timespec *abs_timeout); } + SYS_MQ_TIMEDRECEIVE = 519 // { ssize_t mq_timedreceive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio, const struct timespec *abs_timeout); } SYS_IOPRIO_SET = 520 // { int ioprio_set(int which, int who, int prio); } SYS_IOPRIO_GET = 521 // { int ioprio_get(int which, int who); } SYS_CHROOT_KERNEL = 522 // { int chroot_kernel(char *path); } - SYS_RENAMEAT = 523 // { int renameat(int oldfd, char *old, int newfd, \ + SYS_RENAMEAT = 523 // { int renameat(int oldfd, char *old, int newfd, char *new); } SYS_MKDIRAT = 524 // { int mkdirat(int fd, char *path, mode_t mode); } SYS_MKFIFOAT = 525 // { int mkfifoat(int fd, char *path, mode_t mode); } - SYS_MKNODAT = 526 // { int mknodat(int fd, char *path, mode_t mode, \ - SYS_READLINKAT = 527 // { int readlinkat(int fd, char *path, char *buf, \ + SYS_MKNODAT = 526 // { int mknodat(int fd, char *path, mode_t mode, dev_t dev); } + SYS_READLINKAT = 527 // { int readlinkat(int fd, char *path, char *buf, size_t bufsize); } SYS_SYMLINKAT = 528 // { int symlinkat(char *path1, int fd, char *path2); } SYS_SWAPOFF = 529 // { int swapoff(char *name); } - SYS_VQUOTACTL = 530 // { int vquotactl(const char *path, \ - SYS_LINKAT = 531 // { int linkat(int fd1, char *path1, int fd2, \ + SYS_VQUOTACTL = 530 // { int vquotactl(const char *path, struct plistref *pref); } + SYS_LINKAT = 531 // { int linkat(int fd1, char *path1, int fd2, char *path2, int flags); } SYS_EACCESS = 532 // { int eaccess(char *path, int flags); } SYS_LPATHCONF = 533 // { int lpathconf(char *path, int name); } SYS_VMM_GUEST_CTL = 534 // { int vmm_guest_ctl(int op, struct vmm_guest_options *options); } @@ -308,7 +308,7 @@ const ( SYS_FUTIMENS = 540 // { int futimens(int fd, const struct timespec *ts); } SYS_ACCEPT4 = 541 // { int accept4(int s, caddr_t name, int *anamelen, int flags); } SYS_LWP_SETNAME = 542 // { int lwp_setname(lwpid_t tid, const char *name); } - SYS_PPOLL = 543 // { int ppoll(struct pollfd *fds, u_int nfds, \ + SYS_PPOLL = 543 // { int ppoll(struct pollfd *fds, u_int nfds, const struct timespec *ts, const sigset_t *sigmask); } SYS_LWP_SETAFFINITY = 544 // { int lwp_setaffinity(pid_t pid, lwpid_t tid, const cpumask_t *mask); } SYS_LWP_GETAFFINITY = 545 // { int lwp_getaffinity(pid_t pid, lwpid_t tid, cpumask_t *mask); } SYS_LWP_CREATE2 = 546 // { int lwp_create2(struct lwp_params *params, const cpumask_t *mask); } diff --git a/vendor/golang.org/x/sys/unix/zsysnum_freebsd_386.go b/vendor/golang.org/x/sys/unix/zsysnum_freebsd_386.go index b64a8122ce..55c3a32945 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_freebsd_386.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_freebsd_386.go @@ -1,4 +1,4 @@ -// mksysnum_freebsd.pl +// go run mksysnum.go https://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master // Code generated by the command above; see README.md. DO NOT EDIT. // +build 386,freebsd @@ -7,347 +7,397 @@ package unix const ( // SYS_NOSYS = 0; // { int nosys(void); } syscall nosys_args int - SYS_EXIT = 1 // { void sys_exit(int rval); } exit \ - SYS_FORK = 2 // { int fork(void); } - SYS_READ = 3 // { ssize_t read(int fd, void *buf, \ - SYS_WRITE = 4 // { ssize_t write(int fd, const void *buf, \ - SYS_OPEN = 5 // { int open(char *path, int flags, int mode); } - SYS_CLOSE = 6 // { int close(int fd); } - SYS_WAIT4 = 7 // { int wait4(int pid, int *status, \ - SYS_LINK = 9 // { int link(char *path, char *link); } - SYS_UNLINK = 10 // { int unlink(char *path); } - SYS_CHDIR = 12 // { int chdir(char *path); } - SYS_FCHDIR = 13 // { int fchdir(int fd); } - SYS_MKNOD = 14 // { int mknod(char *path, int mode, int dev); } - SYS_CHMOD = 15 // { int chmod(char *path, int mode); } - SYS_CHOWN = 16 // { int chown(char *path, int uid, int gid); } - SYS_OBREAK = 17 // { int obreak(char *nsize); } break \ - SYS_GETPID = 20 // { pid_t getpid(void); } - SYS_MOUNT = 21 // { int mount(char *type, char *path, \ - SYS_UNMOUNT = 22 // { int unmount(char *path, int flags); } - SYS_SETUID = 23 // { int setuid(uid_t uid); } - SYS_GETUID = 24 // { uid_t getuid(void); } - SYS_GETEUID = 25 // { uid_t geteuid(void); } - SYS_PTRACE = 26 // { int ptrace(int req, pid_t pid, \ - SYS_RECVMSG = 27 // { int recvmsg(int s, struct msghdr *msg, \ - SYS_SENDMSG = 28 // { int sendmsg(int s, struct msghdr *msg, \ - SYS_RECVFROM = 29 // { int recvfrom(int s, caddr_t buf, \ - SYS_ACCEPT = 30 // { int accept(int s, \ - SYS_GETPEERNAME = 31 // { int getpeername(int fdes, \ - SYS_GETSOCKNAME = 32 // { int getsockname(int fdes, \ - SYS_ACCESS = 33 // { int access(char *path, int amode); } - SYS_CHFLAGS = 34 // { int chflags(const char *path, u_long flags); } - SYS_FCHFLAGS = 35 // { int fchflags(int fd, u_long flags); } - SYS_SYNC = 36 // { int sync(void); } - SYS_KILL = 37 // { int kill(int pid, int signum); } - SYS_GETPPID = 39 // { pid_t getppid(void); } - SYS_DUP = 41 // { int dup(u_int fd); } - SYS_PIPE = 42 // { int pipe(void); } - SYS_GETEGID = 43 // { gid_t getegid(void); } - SYS_PROFIL = 44 // { int profil(caddr_t samples, size_t size, \ - SYS_KTRACE = 45 // { int ktrace(const char *fname, int ops, \ - SYS_GETGID = 47 // { gid_t getgid(void); } - SYS_GETLOGIN = 49 // { int getlogin(char *namebuf, u_int \ - SYS_SETLOGIN = 50 // { int setlogin(char *namebuf); } - SYS_ACCT = 51 // { int acct(char *path); } - SYS_SIGALTSTACK = 53 // { int sigaltstack(stack_t *ss, \ - SYS_IOCTL = 54 // { int ioctl(int fd, u_long com, \ - SYS_REBOOT = 55 // { int reboot(int opt); } - SYS_REVOKE = 56 // { int revoke(char *path); } - SYS_SYMLINK = 57 // { int symlink(char *path, char *link); } - SYS_READLINK = 58 // { ssize_t readlink(char *path, char *buf, \ - SYS_EXECVE = 59 // { int execve(char *fname, char **argv, \ - SYS_UMASK = 60 // { int umask(int newmask); } umask umask_args \ - SYS_CHROOT = 61 // { int chroot(char *path); } - SYS_MSYNC = 65 // { int msync(void *addr, size_t len, \ - SYS_VFORK = 66 // { int vfork(void); } - SYS_SBRK = 69 // { int sbrk(int incr); } - SYS_SSTK = 70 // { int sstk(int incr); } - SYS_OVADVISE = 72 // { int ovadvise(int anom); } vadvise \ - SYS_MUNMAP = 73 // { int munmap(void *addr, size_t len); } - SYS_MPROTECT = 74 // { int mprotect(const void *addr, size_t len, \ - SYS_MADVISE = 75 // { int madvise(void *addr, size_t len, \ - SYS_MINCORE = 78 // { int mincore(const void *addr, size_t len, \ - SYS_GETGROUPS = 79 // { int getgroups(u_int gidsetsize, \ - SYS_SETGROUPS = 80 // { int setgroups(u_int gidsetsize, \ - SYS_GETPGRP = 81 // { int getpgrp(void); } - SYS_SETPGID = 82 // { int setpgid(int pid, int pgid); } - SYS_SETITIMER = 83 // { int setitimer(u_int which, struct \ - SYS_SWAPON = 85 // { int swapon(char *name); } - SYS_GETITIMER = 86 // { int getitimer(u_int which, \ - SYS_GETDTABLESIZE = 89 // { int getdtablesize(void); } - SYS_DUP2 = 90 // { int dup2(u_int from, u_int to); } - SYS_FCNTL = 92 // { int fcntl(int fd, int cmd, long arg); } - SYS_SELECT = 93 // { int select(int nd, fd_set *in, fd_set *ou, \ - SYS_FSYNC = 95 // { int fsync(int fd); } - SYS_SETPRIORITY = 96 // { int setpriority(int which, int who, \ - SYS_SOCKET = 97 // { int socket(int domain, int type, \ - SYS_CONNECT = 98 // { int connect(int s, caddr_t name, \ - SYS_GETPRIORITY = 100 // { int getpriority(int which, int who); } - SYS_BIND = 104 // { int bind(int s, caddr_t name, \ - SYS_SETSOCKOPT = 105 // { int setsockopt(int s, int level, int name, \ - SYS_LISTEN = 106 // { int listen(int s, int backlog); } - SYS_GETTIMEOFDAY = 116 // { int gettimeofday(struct timeval *tp, \ - SYS_GETRUSAGE = 117 // { int getrusage(int who, \ - SYS_GETSOCKOPT = 118 // { int getsockopt(int s, int level, int name, \ - SYS_READV = 120 // { int readv(int fd, struct iovec *iovp, \ - SYS_WRITEV = 121 // { int writev(int fd, struct iovec *iovp, \ - SYS_SETTIMEOFDAY = 122 // { int settimeofday(struct timeval *tv, \ - SYS_FCHOWN = 123 // { int fchown(int fd, int uid, int gid); } - SYS_FCHMOD = 124 // { int fchmod(int fd, int mode); } - SYS_SETREUID = 126 // { int setreuid(int ruid, int euid); } - SYS_SETREGID = 127 // { int setregid(int rgid, int egid); } - SYS_RENAME = 128 // { int rename(char *from, char *to); } - SYS_FLOCK = 131 // { int flock(int fd, int how); } - SYS_MKFIFO = 132 // { int mkfifo(char *path, int mode); } - SYS_SENDTO = 133 // { int sendto(int s, caddr_t buf, size_t len, \ - SYS_SHUTDOWN = 134 // { int shutdown(int s, int how); } - SYS_SOCKETPAIR = 135 // { int socketpair(int domain, int type, \ - SYS_MKDIR = 136 // { int mkdir(char *path, int mode); } - SYS_RMDIR = 137 // { int rmdir(char *path); } - SYS_UTIMES = 138 // { int utimes(char *path, \ - SYS_ADJTIME = 140 // { int adjtime(struct timeval *delta, \ - SYS_SETSID = 147 // { int setsid(void); } - SYS_QUOTACTL = 148 // { int quotactl(char *path, int cmd, int uid, \ - SYS_LGETFH = 160 // { int lgetfh(char *fname, \ - SYS_GETFH = 161 // { int getfh(char *fname, \ - SYS_SYSARCH = 165 // { int sysarch(int op, char *parms); } - SYS_RTPRIO = 166 // { int rtprio(int function, pid_t pid, \ - SYS_FREEBSD6_PREAD = 173 // { ssize_t freebsd6_pread(int fd, void *buf, \ - SYS_FREEBSD6_PWRITE = 174 // { ssize_t freebsd6_pwrite(int fd, \ - SYS_SETFIB = 175 // { int setfib(int fibnum); } - SYS_NTP_ADJTIME = 176 // { int ntp_adjtime(struct timex *tp); } - SYS_SETGID = 181 // { int setgid(gid_t gid); } - SYS_SETEGID = 182 // { int setegid(gid_t egid); } - SYS_SETEUID = 183 // { int seteuid(uid_t euid); } - SYS_STAT = 188 // { int stat(char *path, struct stat *ub); } - SYS_FSTAT = 189 // { int fstat(int fd, struct stat *sb); } - SYS_LSTAT = 190 // { int lstat(char *path, struct stat *ub); } - SYS_PATHCONF = 191 // { int pathconf(char *path, int name); } - SYS_FPATHCONF = 192 // { int fpathconf(int fd, int name); } - SYS_GETRLIMIT = 194 // { int getrlimit(u_int which, \ - SYS_SETRLIMIT = 195 // { int setrlimit(u_int which, \ - SYS_GETDIRENTRIES = 196 // { int getdirentries(int fd, char *buf, \ - SYS_FREEBSD6_MMAP = 197 // { caddr_t freebsd6_mmap(caddr_t addr, \ - SYS_FREEBSD6_LSEEK = 199 // { off_t freebsd6_lseek(int fd, int pad, \ - SYS_FREEBSD6_TRUNCATE = 200 // { int freebsd6_truncate(char *path, int pad, \ - SYS_FREEBSD6_FTRUNCATE = 201 // { int freebsd6_ftruncate(int fd, int pad, \ - SYS___SYSCTL = 202 // { int __sysctl(int *name, u_int namelen, \ - SYS_MLOCK = 203 // { int mlock(const void *addr, size_t len); } - SYS_MUNLOCK = 204 // { int munlock(const void *addr, size_t len); } - SYS_UNDELETE = 205 // { int undelete(char *path); } - SYS_FUTIMES = 206 // { int futimes(int fd, struct timeval *tptr); } - SYS_GETPGID = 207 // { int getpgid(pid_t pid); } - SYS_POLL = 209 // { int poll(struct pollfd *fds, u_int nfds, \ - SYS_CLOCK_GETTIME = 232 // { int clock_gettime(clockid_t clock_id, \ - SYS_CLOCK_SETTIME = 233 // { int clock_settime( \ - SYS_CLOCK_GETRES = 234 // { int clock_getres(clockid_t clock_id, \ - SYS_KTIMER_CREATE = 235 // { int ktimer_create(clockid_t clock_id, \ - SYS_KTIMER_DELETE = 236 // { int ktimer_delete(int timerid); } - SYS_KTIMER_SETTIME = 237 // { int ktimer_settime(int timerid, int flags, \ - SYS_KTIMER_GETTIME = 238 // { int ktimer_gettime(int timerid, struct \ - SYS_KTIMER_GETOVERRUN = 239 // { int ktimer_getoverrun(int timerid); } - SYS_NANOSLEEP = 240 // { int nanosleep(const struct timespec *rqtp, \ - SYS_FFCLOCK_GETCOUNTER = 241 // { int ffclock_getcounter(ffcounter *ffcount); } - SYS_FFCLOCK_SETESTIMATE = 242 // { int ffclock_setestimate( \ - SYS_FFCLOCK_GETESTIMATE = 243 // { int ffclock_getestimate( \ - SYS_CLOCK_GETCPUCLOCKID2 = 247 // { int clock_getcpuclockid2(id_t id,\ - SYS_NTP_GETTIME = 248 // { int ntp_gettime(struct ntptimeval *ntvp); } - SYS_MINHERIT = 250 // { int minherit(void *addr, size_t len, \ - SYS_RFORK = 251 // { int rfork(int flags); } - SYS_OPENBSD_POLL = 252 // { int openbsd_poll(struct pollfd *fds, \ - SYS_ISSETUGID = 253 // { int issetugid(void); } - SYS_LCHOWN = 254 // { int lchown(char *path, int uid, int gid); } - SYS_GETDENTS = 272 // { int getdents(int fd, char *buf, \ - SYS_LCHMOD = 274 // { int lchmod(char *path, mode_t mode); } - SYS_LUTIMES = 276 // { int lutimes(char *path, \ - SYS_NSTAT = 278 // { int nstat(char *path, struct nstat *ub); } - SYS_NFSTAT = 279 // { int nfstat(int fd, struct nstat *sb); } - SYS_NLSTAT = 280 // { int nlstat(char *path, struct nstat *ub); } - SYS_PREADV = 289 // { ssize_t preadv(int fd, struct iovec *iovp, \ - SYS_PWRITEV = 290 // { ssize_t pwritev(int fd, struct iovec *iovp, \ - SYS_FHOPEN = 298 // { int fhopen(const struct fhandle *u_fhp, \ - SYS_FHSTAT = 299 // { int fhstat(const struct fhandle *u_fhp, \ - SYS_MODNEXT = 300 // { int modnext(int modid); } - SYS_MODSTAT = 301 // { int modstat(int modid, \ - SYS_MODFNEXT = 302 // { int modfnext(int modid); } - SYS_MODFIND = 303 // { int modfind(const char *name); } - SYS_KLDLOAD = 304 // { int kldload(const char *file); } - SYS_KLDUNLOAD = 305 // { int kldunload(int fileid); } - SYS_KLDFIND = 306 // { int kldfind(const char *file); } - SYS_KLDNEXT = 307 // { int kldnext(int fileid); } - SYS_KLDSTAT = 308 // { int kldstat(int fileid, struct \ - SYS_KLDFIRSTMOD = 309 // { int kldfirstmod(int fileid); } - SYS_GETSID = 310 // { int getsid(pid_t pid); } - SYS_SETRESUID = 311 // { int setresuid(uid_t ruid, uid_t euid, \ - SYS_SETRESGID = 312 // { int setresgid(gid_t rgid, gid_t egid, \ - SYS_YIELD = 321 // { int yield(void); } - SYS_MLOCKALL = 324 // { int mlockall(int how); } - SYS_MUNLOCKALL = 325 // { int munlockall(void); } - SYS___GETCWD = 326 // { int __getcwd(char *buf, u_int buflen); } - SYS_SCHED_SETPARAM = 327 // { int sched_setparam (pid_t pid, \ - SYS_SCHED_GETPARAM = 328 // { int sched_getparam (pid_t pid, struct \ - SYS_SCHED_SETSCHEDULER = 329 // { int sched_setscheduler (pid_t pid, int \ - SYS_SCHED_GETSCHEDULER = 330 // { int sched_getscheduler (pid_t pid); } - SYS_SCHED_YIELD = 331 // { int sched_yield (void); } - SYS_SCHED_GET_PRIORITY_MAX = 332 // { int sched_get_priority_max (int policy); } - SYS_SCHED_GET_PRIORITY_MIN = 333 // { int sched_get_priority_min (int policy); } - SYS_SCHED_RR_GET_INTERVAL = 334 // { int sched_rr_get_interval (pid_t pid, \ - SYS_UTRACE = 335 // { int utrace(const void *addr, size_t len); } - SYS_KLDSYM = 337 // { int kldsym(int fileid, int cmd, \ - SYS_JAIL = 338 // { int jail(struct jail *jail); } - SYS_SIGPROCMASK = 340 // { int sigprocmask(int how, \ - SYS_SIGSUSPEND = 341 // { int sigsuspend(const sigset_t *sigmask); } - SYS_SIGPENDING = 343 // { int sigpending(sigset_t *set); } - SYS_SIGTIMEDWAIT = 345 // { int sigtimedwait(const sigset_t *set, \ - SYS_SIGWAITINFO = 346 // { int sigwaitinfo(const sigset_t *set, \ - SYS___ACL_GET_FILE = 347 // { int __acl_get_file(const char *path, \ - SYS___ACL_SET_FILE = 348 // { int __acl_set_file(const char *path, \ - SYS___ACL_GET_FD = 349 // { int __acl_get_fd(int filedes, \ - SYS___ACL_SET_FD = 350 // { int __acl_set_fd(int filedes, \ - SYS___ACL_DELETE_FILE = 351 // { int __acl_delete_file(const char *path, \ - SYS___ACL_DELETE_FD = 352 // { int __acl_delete_fd(int filedes, \ - SYS___ACL_ACLCHECK_FILE = 353 // { int __acl_aclcheck_file(const char *path, \ - SYS___ACL_ACLCHECK_FD = 354 // { int __acl_aclcheck_fd(int filedes, \ - SYS_EXTATTRCTL = 355 // { int extattrctl(const char *path, int cmd, \ - SYS_EXTATTR_SET_FILE = 356 // { ssize_t extattr_set_file( \ - SYS_EXTATTR_GET_FILE = 357 // { ssize_t extattr_get_file( \ - SYS_EXTATTR_DELETE_FILE = 358 // { int extattr_delete_file(const char *path, \ - SYS_GETRESUID = 360 // { int getresuid(uid_t *ruid, uid_t *euid, \ - SYS_GETRESGID = 361 // { int getresgid(gid_t *rgid, gid_t *egid, \ - SYS_KQUEUE = 362 // { int kqueue(void); } - SYS_KEVENT = 363 // { int kevent(int fd, \ - SYS_EXTATTR_SET_FD = 371 // { ssize_t extattr_set_fd(int fd, \ - SYS_EXTATTR_GET_FD = 372 // { ssize_t extattr_get_fd(int fd, \ - SYS_EXTATTR_DELETE_FD = 373 // { int extattr_delete_fd(int fd, \ - SYS___SETUGID = 374 // { int __setugid(int flag); } - SYS_EACCESS = 376 // { int eaccess(char *path, int amode); } - SYS_NMOUNT = 378 // { int nmount(struct iovec *iovp, \ - SYS___MAC_GET_PROC = 384 // { int __mac_get_proc(struct mac *mac_p); } - SYS___MAC_SET_PROC = 385 // { int __mac_set_proc(struct mac *mac_p); } - SYS___MAC_GET_FD = 386 // { int __mac_get_fd(int fd, \ - SYS___MAC_GET_FILE = 387 // { int __mac_get_file(const char *path_p, \ - SYS___MAC_SET_FD = 388 // { int __mac_set_fd(int fd, \ - SYS___MAC_SET_FILE = 389 // { int __mac_set_file(const char *path_p, \ - SYS_KENV = 390 // { int kenv(int what, const char *name, \ - SYS_LCHFLAGS = 391 // { int lchflags(const char *path, \ - SYS_UUIDGEN = 392 // { int uuidgen(struct uuid *store, \ - SYS_SENDFILE = 393 // { int sendfile(int fd, int s, off_t offset, \ - SYS_MAC_SYSCALL = 394 // { int mac_syscall(const char *policy, \ - SYS_GETFSSTAT = 395 // { int getfsstat(struct statfs *buf, \ - SYS_STATFS = 396 // { int statfs(char *path, \ - SYS_FSTATFS = 397 // { int fstatfs(int fd, struct statfs *buf); } - SYS_FHSTATFS = 398 // { int fhstatfs(const struct fhandle *u_fhp, \ - SYS___MAC_GET_PID = 409 // { int __mac_get_pid(pid_t pid, \ - SYS___MAC_GET_LINK = 410 // { int __mac_get_link(const char *path_p, \ - SYS___MAC_SET_LINK = 411 // { int __mac_set_link(const char *path_p, \ - SYS_EXTATTR_SET_LINK = 412 // { ssize_t extattr_set_link( \ - SYS_EXTATTR_GET_LINK = 413 // { ssize_t extattr_get_link( \ - SYS_EXTATTR_DELETE_LINK = 414 // { int extattr_delete_link( \ - SYS___MAC_EXECVE = 415 // { int __mac_execve(char *fname, char **argv, \ - SYS_SIGACTION = 416 // { int sigaction(int sig, \ - SYS_SIGRETURN = 417 // { int sigreturn( \ - SYS_GETCONTEXT = 421 // { int getcontext(struct __ucontext *ucp); } - SYS_SETCONTEXT = 422 // { int setcontext( \ - SYS_SWAPCONTEXT = 423 // { int swapcontext(struct __ucontext *oucp, \ - SYS_SWAPOFF = 424 // { int swapoff(const char *name); } - SYS___ACL_GET_LINK = 425 // { int __acl_get_link(const char *path, \ - SYS___ACL_SET_LINK = 426 // { int __acl_set_link(const char *path, \ - SYS___ACL_DELETE_LINK = 427 // { int __acl_delete_link(const char *path, \ - SYS___ACL_ACLCHECK_LINK = 428 // { int __acl_aclcheck_link(const char *path, \ - SYS_SIGWAIT = 429 // { int sigwait(const sigset_t *set, \ - SYS_THR_CREATE = 430 // { int thr_create(ucontext_t *ctx, long *id, \ - SYS_THR_EXIT = 431 // { void thr_exit(long *state); } - SYS_THR_SELF = 432 // { int thr_self(long *id); } - SYS_THR_KILL = 433 // { int thr_kill(long id, int sig); } - SYS__UMTX_LOCK = 434 // { int _umtx_lock(struct umtx *umtx); } - SYS__UMTX_UNLOCK = 435 // { int _umtx_unlock(struct umtx *umtx); } - SYS_JAIL_ATTACH = 436 // { int jail_attach(int jid); } - SYS_EXTATTR_LIST_FD = 437 // { ssize_t extattr_list_fd(int fd, \ - SYS_EXTATTR_LIST_FILE = 438 // { ssize_t extattr_list_file( \ - SYS_EXTATTR_LIST_LINK = 439 // { ssize_t extattr_list_link( \ - SYS_THR_SUSPEND = 442 // { int thr_suspend( \ - SYS_THR_WAKE = 443 // { int thr_wake(long id); } - SYS_KLDUNLOADF = 444 // { int kldunloadf(int fileid, int flags); } - SYS_AUDIT = 445 // { int audit(const void *record, \ - SYS_AUDITON = 446 // { int auditon(int cmd, void *data, \ - SYS_GETAUID = 447 // { int getauid(uid_t *auid); } - SYS_SETAUID = 448 // { int setauid(uid_t *auid); } - SYS_GETAUDIT = 449 // { int getaudit(struct auditinfo *auditinfo); } - SYS_SETAUDIT = 450 // { int setaudit(struct auditinfo *auditinfo); } - SYS_GETAUDIT_ADDR = 451 // { int getaudit_addr( \ - SYS_SETAUDIT_ADDR = 452 // { int setaudit_addr( \ - SYS_AUDITCTL = 453 // { int auditctl(char *path); } - SYS__UMTX_OP = 454 // { int _umtx_op(void *obj, int op, \ - SYS_THR_NEW = 455 // { int thr_new(struct thr_param *param, \ - SYS_SIGQUEUE = 456 // { int sigqueue(pid_t pid, int signum, void *value); } - SYS_ABORT2 = 463 // { int abort2(const char *why, int nargs, void **args); } - SYS_THR_SET_NAME = 464 // { int thr_set_name(long id, const char *name); } - SYS_RTPRIO_THREAD = 466 // { int rtprio_thread(int function, \ - SYS_PREAD = 475 // { ssize_t pread(int fd, void *buf, \ - SYS_PWRITE = 476 // { ssize_t pwrite(int fd, const void *buf, \ - SYS_MMAP = 477 // { caddr_t mmap(caddr_t addr, size_t len, \ - SYS_LSEEK = 478 // { off_t lseek(int fd, off_t offset, \ - SYS_TRUNCATE = 479 // { int truncate(char *path, off_t length); } - SYS_FTRUNCATE = 480 // { int ftruncate(int fd, off_t length); } - SYS_THR_KILL2 = 481 // { int thr_kill2(pid_t pid, long id, int sig); } - SYS_SHM_OPEN = 482 // { int shm_open(const char *path, int flags, \ - SYS_SHM_UNLINK = 483 // { int shm_unlink(const char *path); } - SYS_CPUSET = 484 // { int cpuset(cpusetid_t *setid); } - SYS_CPUSET_SETID = 485 // { int cpuset_setid(cpuwhich_t which, id_t id, \ - SYS_CPUSET_GETID = 486 // { int cpuset_getid(cpulevel_t level, \ - SYS_CPUSET_GETAFFINITY = 487 // { int cpuset_getaffinity(cpulevel_t level, \ - SYS_CPUSET_SETAFFINITY = 488 // { int cpuset_setaffinity(cpulevel_t level, \ - SYS_FACCESSAT = 489 // { int faccessat(int fd, char *path, int amode, \ - SYS_FCHMODAT = 490 // { int fchmodat(int fd, char *path, mode_t mode, \ - SYS_FCHOWNAT = 491 // { int fchownat(int fd, char *path, uid_t uid, \ - SYS_FEXECVE = 492 // { int fexecve(int fd, char **argv, \ - SYS_FSTATAT = 493 // { int fstatat(int fd, char *path, \ - SYS_FUTIMESAT = 494 // { int futimesat(int fd, char *path, \ - SYS_LINKAT = 495 // { int linkat(int fd1, char *path1, int fd2, \ - SYS_MKDIRAT = 496 // { int mkdirat(int fd, char *path, mode_t mode); } - SYS_MKFIFOAT = 497 // { int mkfifoat(int fd, char *path, mode_t mode); } - SYS_MKNODAT = 498 // { int mknodat(int fd, char *path, mode_t mode, \ - SYS_OPENAT = 499 // { int openat(int fd, char *path, int flag, \ - SYS_READLINKAT = 500 // { int readlinkat(int fd, char *path, char *buf, \ - SYS_RENAMEAT = 501 // { int renameat(int oldfd, char *old, int newfd, \ - SYS_SYMLINKAT = 502 // { int symlinkat(char *path1, int fd, \ - SYS_UNLINKAT = 503 // { int unlinkat(int fd, char *path, int flag); } - SYS_POSIX_OPENPT = 504 // { int posix_openpt(int flags); } - SYS_JAIL_GET = 506 // { int jail_get(struct iovec *iovp, \ - SYS_JAIL_SET = 507 // { int jail_set(struct iovec *iovp, \ - SYS_JAIL_REMOVE = 508 // { int jail_remove(int jid); } - SYS_CLOSEFROM = 509 // { int closefrom(int lowfd); } - SYS_LPATHCONF = 513 // { int lpathconf(char *path, int name); } - SYS___CAP_RIGHTS_GET = 515 // { int __cap_rights_get(int version, \ - SYS_CAP_ENTER = 516 // { int cap_enter(void); } - SYS_CAP_GETMODE = 517 // { int cap_getmode(u_int *modep); } - SYS_PDFORK = 518 // { int pdfork(int *fdp, int flags); } - SYS_PDKILL = 519 // { int pdkill(int fd, int signum); } - SYS_PDGETPID = 520 // { int pdgetpid(int fd, pid_t *pidp); } - SYS_PSELECT = 522 // { int pselect(int nd, fd_set *in, \ - SYS_GETLOGINCLASS = 523 // { int getloginclass(char *namebuf, \ - SYS_SETLOGINCLASS = 524 // { int setloginclass(const char *namebuf); } - SYS_RCTL_GET_RACCT = 525 // { int rctl_get_racct(const void *inbufp, \ - SYS_RCTL_GET_RULES = 526 // { int rctl_get_rules(const void *inbufp, \ - SYS_RCTL_GET_LIMITS = 527 // { int rctl_get_limits(const void *inbufp, \ - SYS_RCTL_ADD_RULE = 528 // { int rctl_add_rule(const void *inbufp, \ - SYS_RCTL_REMOVE_RULE = 529 // { int rctl_remove_rule(const void *inbufp, \ - SYS_POSIX_FALLOCATE = 530 // { int posix_fallocate(int fd, \ - SYS_POSIX_FADVISE = 531 // { int posix_fadvise(int fd, off_t offset, \ - SYS_WAIT6 = 532 // { int wait6(idtype_t idtype, id_t id, \ - SYS_CAP_RIGHTS_LIMIT = 533 // { int cap_rights_limit(int fd, \ - SYS_CAP_IOCTLS_LIMIT = 534 // { int cap_ioctls_limit(int fd, \ - SYS_CAP_IOCTLS_GET = 535 // { ssize_t cap_ioctls_get(int fd, \ - SYS_CAP_FCNTLS_LIMIT = 536 // { int cap_fcntls_limit(int fd, \ - SYS_CAP_FCNTLS_GET = 537 // { int cap_fcntls_get(int fd, \ - SYS_BINDAT = 538 // { int bindat(int fd, int s, caddr_t name, \ - SYS_CONNECTAT = 539 // { int connectat(int fd, int s, caddr_t name, \ - SYS_CHFLAGSAT = 540 // { int chflagsat(int fd, const char *path, \ - SYS_ACCEPT4 = 541 // { int accept4(int s, \ - SYS_PIPE2 = 542 // { int pipe2(int *fildes, int flags); } - SYS_PROCCTL = 544 // { int procctl(idtype_t idtype, id_t id, \ - SYS_PPOLL = 545 // { int ppoll(struct pollfd *fds, u_int nfds, \ - SYS_FUTIMENS = 546 // { int futimens(int fd, \ - SYS_UTIMENSAT = 547 // { int utimensat(int fd, \ + SYS_EXIT = 1 // { void sys_exit(int rval); } exit sys_exit_args void + SYS_FORK = 2 // { int fork(void); } + SYS_READ = 3 // { ssize_t read(int fd, void *buf, size_t nbyte); } + SYS_WRITE = 4 // { ssize_t write(int fd, const void *buf, size_t nbyte); } + SYS_OPEN = 5 // { int open(char *path, int flags, int mode); } + SYS_CLOSE = 6 // { int close(int fd); } + SYS_WAIT4 = 7 // { int wait4(int pid, int *status, int options, struct rusage *rusage); } + SYS_LINK = 9 // { int link(char *path, char *link); } + SYS_UNLINK = 10 // { int unlink(char *path); } + SYS_CHDIR = 12 // { int chdir(char *path); } + SYS_FCHDIR = 13 // { int fchdir(int fd); } + SYS_MKNOD = 14 // { int mknod(char *path, int mode, int dev); } + SYS_CHMOD = 15 // { int chmod(char *path, int mode); } + SYS_CHOWN = 16 // { int chown(char *path, int uid, int gid); } + SYS_OBREAK = 17 // { int obreak(char *nsize); } break obreak_args int + SYS_GETPID = 20 // { pid_t getpid(void); } + SYS_MOUNT = 21 // { int mount(char *type, char *path, int flags, caddr_t data); } + SYS_UNMOUNT = 22 // { int unmount(char *path, int flags); } + SYS_SETUID = 23 // { int setuid(uid_t uid); } + SYS_GETUID = 24 // { uid_t getuid(void); } + SYS_GETEUID = 25 // { uid_t geteuid(void); } + SYS_PTRACE = 26 // { int ptrace(int req, pid_t pid, caddr_t addr, int data); } + SYS_RECVMSG = 27 // { int recvmsg(int s, struct msghdr *msg, int flags); } + SYS_SENDMSG = 28 // { int sendmsg(int s, struct msghdr *msg, int flags); } + SYS_RECVFROM = 29 // { int recvfrom(int s, caddr_t buf, size_t len, int flags, struct sockaddr * __restrict from, __socklen_t * __restrict fromlenaddr); } + SYS_ACCEPT = 30 // { int accept(int s, struct sockaddr * __restrict name, __socklen_t * __restrict anamelen); } + SYS_GETPEERNAME = 31 // { int getpeername(int fdes, struct sockaddr * __restrict asa, __socklen_t * __restrict alen); } + SYS_GETSOCKNAME = 32 // { int getsockname(int fdes, struct sockaddr * __restrict asa, __socklen_t * __restrict alen); } + SYS_ACCESS = 33 // { int access(char *path, int amode); } + SYS_CHFLAGS = 34 // { int chflags(const char *path, u_long flags); } + SYS_FCHFLAGS = 35 // { int fchflags(int fd, u_long flags); } + SYS_SYNC = 36 // { int sync(void); } + SYS_KILL = 37 // { int kill(int pid, int signum); } + SYS_GETPPID = 39 // { pid_t getppid(void); } + SYS_DUP = 41 // { int dup(u_int fd); } + SYS_PIPE = 42 // { int pipe(void); } + SYS_GETEGID = 43 // { gid_t getegid(void); } + SYS_PROFIL = 44 // { int profil(caddr_t samples, size_t size, size_t offset, u_int scale); } + SYS_KTRACE = 45 // { int ktrace(const char *fname, int ops, int facs, int pid); } + SYS_GETGID = 47 // { gid_t getgid(void); } + SYS_GETLOGIN = 49 // { int getlogin(char *namebuf, u_int namelen); } + SYS_SETLOGIN = 50 // { int setlogin(char *namebuf); } + SYS_ACCT = 51 // { int acct(char *path); } + SYS_SIGALTSTACK = 53 // { int sigaltstack(stack_t *ss, stack_t *oss); } + SYS_IOCTL = 54 // { int ioctl(int fd, u_long com, caddr_t data); } + SYS_REBOOT = 55 // { int reboot(int opt); } + SYS_REVOKE = 56 // { int revoke(char *path); } + SYS_SYMLINK = 57 // { int symlink(char *path, char *link); } + SYS_READLINK = 58 // { ssize_t readlink(char *path, char *buf, size_t count); } + SYS_EXECVE = 59 // { int execve(char *fname, char **argv, char **envv); } + SYS_UMASK = 60 // { int umask(int newmask); } umask umask_args int + SYS_CHROOT = 61 // { int chroot(char *path); } + SYS_MSYNC = 65 // { int msync(void *addr, size_t len, int flags); } + SYS_VFORK = 66 // { int vfork(void); } + SYS_SBRK = 69 // { int sbrk(int incr); } + SYS_SSTK = 70 // { int sstk(int incr); } + SYS_OVADVISE = 72 // { int ovadvise(int anom); } vadvise ovadvise_args int + SYS_MUNMAP = 73 // { int munmap(void *addr, size_t len); } + SYS_MPROTECT = 74 // { int mprotect(const void *addr, size_t len, int prot); } + SYS_MADVISE = 75 // { int madvise(void *addr, size_t len, int behav); } + SYS_MINCORE = 78 // { int mincore(const void *addr, size_t len, char *vec); } + SYS_GETGROUPS = 79 // { int getgroups(u_int gidsetsize, gid_t *gidset); } + SYS_SETGROUPS = 80 // { int setgroups(u_int gidsetsize, gid_t *gidset); } + SYS_GETPGRP = 81 // { int getpgrp(void); } + SYS_SETPGID = 82 // { int setpgid(int pid, int pgid); } + SYS_SETITIMER = 83 // { int setitimer(u_int which, struct itimerval *itv, struct itimerval *oitv); } + SYS_SWAPON = 85 // { int swapon(char *name); } + SYS_GETITIMER = 86 // { int getitimer(u_int which, struct itimerval *itv); } + SYS_GETDTABLESIZE = 89 // { int getdtablesize(void); } + SYS_DUP2 = 90 // { int dup2(u_int from, u_int to); } + SYS_FCNTL = 92 // { int fcntl(int fd, int cmd, long arg); } + SYS_SELECT = 93 // { int select(int nd, fd_set *in, fd_set *ou, fd_set *ex, struct timeval *tv); } + SYS_FSYNC = 95 // { int fsync(int fd); } + SYS_SETPRIORITY = 96 // { int setpriority(int which, int who, int prio); } + SYS_SOCKET = 97 // { int socket(int domain, int type, int protocol); } + SYS_CONNECT = 98 // { int connect(int s, caddr_t name, int namelen); } + SYS_GETPRIORITY = 100 // { int getpriority(int which, int who); } + SYS_BIND = 104 // { int bind(int s, caddr_t name, int namelen); } + SYS_SETSOCKOPT = 105 // { int setsockopt(int s, int level, int name, caddr_t val, int valsize); } + SYS_LISTEN = 106 // { int listen(int s, int backlog); } + SYS_GETTIMEOFDAY = 116 // { int gettimeofday(struct timeval *tp, struct timezone *tzp); } + SYS_GETRUSAGE = 117 // { int getrusage(int who, struct rusage *rusage); } + SYS_GETSOCKOPT = 118 // { int getsockopt(int s, int level, int name, caddr_t val, int *avalsize); } + SYS_READV = 120 // { int readv(int fd, struct iovec *iovp, u_int iovcnt); } + SYS_WRITEV = 121 // { int writev(int fd, struct iovec *iovp, u_int iovcnt); } + SYS_SETTIMEOFDAY = 122 // { int settimeofday(struct timeval *tv, struct timezone *tzp); } + SYS_FCHOWN = 123 // { int fchown(int fd, int uid, int gid); } + SYS_FCHMOD = 124 // { int fchmod(int fd, int mode); } + SYS_SETREUID = 126 // { int setreuid(int ruid, int euid); } + SYS_SETREGID = 127 // { int setregid(int rgid, int egid); } + SYS_RENAME = 128 // { int rename(char *from, char *to); } + SYS_FLOCK = 131 // { int flock(int fd, int how); } + SYS_MKFIFO = 132 // { int mkfifo(char *path, int mode); } + SYS_SENDTO = 133 // { int sendto(int s, caddr_t buf, size_t len, int flags, caddr_t to, int tolen); } + SYS_SHUTDOWN = 134 // { int shutdown(int s, int how); } + SYS_SOCKETPAIR = 135 // { int socketpair(int domain, int type, int protocol, int *rsv); } + SYS_MKDIR = 136 // { int mkdir(char *path, int mode); } + SYS_RMDIR = 137 // { int rmdir(char *path); } + SYS_UTIMES = 138 // { int utimes(char *path, struct timeval *tptr); } + SYS_ADJTIME = 140 // { int adjtime(struct timeval *delta, struct timeval *olddelta); } + SYS_SETSID = 147 // { int setsid(void); } + SYS_QUOTACTL = 148 // { int quotactl(char *path, int cmd, int uid, caddr_t arg); } + SYS_NLM_SYSCALL = 154 // { int nlm_syscall(int debug_level, int grace_period, int addr_count, char **addrs); } + SYS_NFSSVC = 155 // { int nfssvc(int flag, caddr_t argp); } + SYS_LGETFH = 160 // { int lgetfh(char *fname, struct fhandle *fhp); } + SYS_GETFH = 161 // { int getfh(char *fname, struct fhandle *fhp); } + SYS_SYSARCH = 165 // { int sysarch(int op, char *parms); } + SYS_RTPRIO = 166 // { int rtprio(int function, pid_t pid, struct rtprio *rtp); } + SYS_SEMSYS = 169 // { int semsys(int which, int a2, int a3, int a4, int a5); } + SYS_MSGSYS = 170 // { int msgsys(int which, int a2, int a3, int a4, int a5, int a6); } + SYS_SHMSYS = 171 // { int shmsys(int which, int a2, int a3, int a4); } + SYS_FREEBSD6_PREAD = 173 // { ssize_t freebsd6_pread(int fd, void *buf, size_t nbyte, int pad, off_t offset); } + SYS_FREEBSD6_PWRITE = 174 // { ssize_t freebsd6_pwrite(int fd, const void *buf, size_t nbyte, int pad, off_t offset); } + SYS_SETFIB = 175 // { int setfib(int fibnum); } + SYS_NTP_ADJTIME = 176 // { int ntp_adjtime(struct timex *tp); } + SYS_SETGID = 181 // { int setgid(gid_t gid); } + SYS_SETEGID = 182 // { int setegid(gid_t egid); } + SYS_SETEUID = 183 // { int seteuid(uid_t euid); } + SYS_STAT = 188 // { int stat(char *path, struct stat *ub); } + SYS_FSTAT = 189 // { int fstat(int fd, struct stat *sb); } + SYS_LSTAT = 190 // { int lstat(char *path, struct stat *ub); } + SYS_PATHCONF = 191 // { int pathconf(char *path, int name); } + SYS_FPATHCONF = 192 // { int fpathconf(int fd, int name); } + SYS_GETRLIMIT = 194 // { int getrlimit(u_int which, struct rlimit *rlp); } getrlimit __getrlimit_args int + SYS_SETRLIMIT = 195 // { int setrlimit(u_int which, struct rlimit *rlp); } setrlimit __setrlimit_args int + SYS_GETDIRENTRIES = 196 // { int getdirentries(int fd, char *buf, u_int count, long *basep); } + SYS_FREEBSD6_MMAP = 197 // { caddr_t freebsd6_mmap(caddr_t addr, size_t len, int prot, int flags, int fd, int pad, off_t pos); } + SYS_FREEBSD6_LSEEK = 199 // { off_t freebsd6_lseek(int fd, int pad, off_t offset, int whence); } + SYS_FREEBSD6_TRUNCATE = 200 // { int freebsd6_truncate(char *path, int pad, off_t length); } + SYS_FREEBSD6_FTRUNCATE = 201 // { int freebsd6_ftruncate(int fd, int pad, off_t length); } + SYS___SYSCTL = 202 // { int __sysctl(int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen); } __sysctl sysctl_args int + SYS_MLOCK = 203 // { int mlock(const void *addr, size_t len); } + SYS_MUNLOCK = 204 // { int munlock(const void *addr, size_t len); } + SYS_UNDELETE = 205 // { int undelete(char *path); } + SYS_FUTIMES = 206 // { int futimes(int fd, struct timeval *tptr); } + SYS_GETPGID = 207 // { int getpgid(pid_t pid); } + SYS_POLL = 209 // { int poll(struct pollfd *fds, u_int nfds, int timeout); } + SYS_SEMGET = 221 // { int semget(key_t key, int nsems, int semflg); } + SYS_SEMOP = 222 // { int semop(int semid, struct sembuf *sops, size_t nsops); } + SYS_MSGGET = 225 // { int msgget(key_t key, int msgflg); } + SYS_MSGSND = 226 // { int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); } + SYS_MSGRCV = 227 // { int msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); } + SYS_SHMAT = 228 // { int shmat(int shmid, const void *shmaddr, int shmflg); } + SYS_SHMDT = 230 // { int shmdt(const void *shmaddr); } + SYS_SHMGET = 231 // { int shmget(key_t key, size_t size, int shmflg); } + SYS_CLOCK_GETTIME = 232 // { int clock_gettime(clockid_t clock_id, struct timespec *tp); } + SYS_CLOCK_SETTIME = 233 // { int clock_settime( clockid_t clock_id, const struct timespec *tp); } + SYS_CLOCK_GETRES = 234 // { int clock_getres(clockid_t clock_id, struct timespec *tp); } + SYS_KTIMER_CREATE = 235 // { int ktimer_create(clockid_t clock_id, struct sigevent *evp, int *timerid); } + SYS_KTIMER_DELETE = 236 // { int ktimer_delete(int timerid); } + SYS_KTIMER_SETTIME = 237 // { int ktimer_settime(int timerid, int flags, const struct itimerspec *value, struct itimerspec *ovalue); } + SYS_KTIMER_GETTIME = 238 // { int ktimer_gettime(int timerid, struct itimerspec *value); } + SYS_KTIMER_GETOVERRUN = 239 // { int ktimer_getoverrun(int timerid); } + SYS_NANOSLEEP = 240 // { int nanosleep(const struct timespec *rqtp, struct timespec *rmtp); } + SYS_FFCLOCK_GETCOUNTER = 241 // { int ffclock_getcounter(ffcounter *ffcount); } + SYS_FFCLOCK_SETESTIMATE = 242 // { int ffclock_setestimate( struct ffclock_estimate *cest); } + SYS_FFCLOCK_GETESTIMATE = 243 // { int ffclock_getestimate( struct ffclock_estimate *cest); } + SYS_CLOCK_GETCPUCLOCKID2 = 247 // { int clock_getcpuclockid2(id_t id,int which, clockid_t *clock_id); } + SYS_NTP_GETTIME = 248 // { int ntp_gettime(struct ntptimeval *ntvp); } + SYS_MINHERIT = 250 // { int minherit(void *addr, size_t len, int inherit); } + SYS_RFORK = 251 // { int rfork(int flags); } + SYS_OPENBSD_POLL = 252 // { int openbsd_poll(struct pollfd *fds, u_int nfds, int timeout); } + SYS_ISSETUGID = 253 // { int issetugid(void); } + SYS_LCHOWN = 254 // { int lchown(char *path, int uid, int gid); } + SYS_AIO_READ = 255 // { int aio_read(struct aiocb *aiocbp); } + SYS_AIO_WRITE = 256 // { int aio_write(struct aiocb *aiocbp); } + SYS_LIO_LISTIO = 257 // { int lio_listio(int mode, struct aiocb * const *acb_list, int nent, struct sigevent *sig); } + SYS_GETDENTS = 272 // { int getdents(int fd, char *buf, size_t count); } + SYS_LCHMOD = 274 // { int lchmod(char *path, mode_t mode); } + SYS_LUTIMES = 276 // { int lutimes(char *path, struct timeval *tptr); } + SYS_NSTAT = 278 // { int nstat(char *path, struct nstat *ub); } + SYS_NFSTAT = 279 // { int nfstat(int fd, struct nstat *sb); } + SYS_NLSTAT = 280 // { int nlstat(char *path, struct nstat *ub); } + SYS_PREADV = 289 // { ssize_t preadv(int fd, struct iovec *iovp, u_int iovcnt, off_t offset); } + SYS_PWRITEV = 290 // { ssize_t pwritev(int fd, struct iovec *iovp, u_int iovcnt, off_t offset); } + SYS_FHOPEN = 298 // { int fhopen(const struct fhandle *u_fhp, int flags); } + SYS_FHSTAT = 299 // { int fhstat(const struct fhandle *u_fhp, struct stat *sb); } + SYS_MODNEXT = 300 // { int modnext(int modid); } + SYS_MODSTAT = 301 // { int modstat(int modid, struct module_stat *stat); } + SYS_MODFNEXT = 302 // { int modfnext(int modid); } + SYS_MODFIND = 303 // { int modfind(const char *name); } + SYS_KLDLOAD = 304 // { int kldload(const char *file); } + SYS_KLDUNLOAD = 305 // { int kldunload(int fileid); } + SYS_KLDFIND = 306 // { int kldfind(const char *file); } + SYS_KLDNEXT = 307 // { int kldnext(int fileid); } + SYS_KLDSTAT = 308 // { int kldstat(int fileid, struct kld_file_stat* stat); } + SYS_KLDFIRSTMOD = 309 // { int kldfirstmod(int fileid); } + SYS_GETSID = 310 // { int getsid(pid_t pid); } + SYS_SETRESUID = 311 // { int setresuid(uid_t ruid, uid_t euid, uid_t suid); } + SYS_SETRESGID = 312 // { int setresgid(gid_t rgid, gid_t egid, gid_t sgid); } + SYS_AIO_RETURN = 314 // { int aio_return(struct aiocb *aiocbp); } + SYS_AIO_SUSPEND = 315 // { int aio_suspend( struct aiocb * const * aiocbp, int nent, const struct timespec *timeout); } + SYS_AIO_CANCEL = 316 // { int aio_cancel(int fd, struct aiocb *aiocbp); } + SYS_AIO_ERROR = 317 // { int aio_error(struct aiocb *aiocbp); } + SYS_OAIO_READ = 318 // { int oaio_read(struct oaiocb *aiocbp); } + SYS_OAIO_WRITE = 319 // { int oaio_write(struct oaiocb *aiocbp); } + SYS_OLIO_LISTIO = 320 // { int olio_listio(int mode, struct oaiocb * const *acb_list, int nent, struct osigevent *sig); } + SYS_YIELD = 321 // { int yield(void); } + SYS_MLOCKALL = 324 // { int mlockall(int how); } + SYS_MUNLOCKALL = 325 // { int munlockall(void); } + SYS___GETCWD = 326 // { int __getcwd(char *buf, u_int buflen); } + SYS_SCHED_SETPARAM = 327 // { int sched_setparam (pid_t pid, const struct sched_param *param); } + SYS_SCHED_GETPARAM = 328 // { int sched_getparam (pid_t pid, struct sched_param *param); } + SYS_SCHED_SETSCHEDULER = 329 // { int sched_setscheduler (pid_t pid, int policy, const struct sched_param *param); } + SYS_SCHED_GETSCHEDULER = 330 // { int sched_getscheduler (pid_t pid); } + SYS_SCHED_YIELD = 331 // { int sched_yield (void); } + SYS_SCHED_GET_PRIORITY_MAX = 332 // { int sched_get_priority_max (int policy); } + SYS_SCHED_GET_PRIORITY_MIN = 333 // { int sched_get_priority_min (int policy); } + SYS_SCHED_RR_GET_INTERVAL = 334 // { int sched_rr_get_interval (pid_t pid, struct timespec *interval); } + SYS_UTRACE = 335 // { int utrace(const void *addr, size_t len); } + SYS_KLDSYM = 337 // { int kldsym(int fileid, int cmd, void *data); } + SYS_JAIL = 338 // { int jail(struct jail *jail); } + SYS_SIGPROCMASK = 340 // { int sigprocmask(int how, const sigset_t *set, sigset_t *oset); } + SYS_SIGSUSPEND = 341 // { int sigsuspend(const sigset_t *sigmask); } + SYS_SIGPENDING = 343 // { int sigpending(sigset_t *set); } + SYS_SIGTIMEDWAIT = 345 // { int sigtimedwait(const sigset_t *set, siginfo_t *info, const struct timespec *timeout); } + SYS_SIGWAITINFO = 346 // { int sigwaitinfo(const sigset_t *set, siginfo_t *info); } + SYS___ACL_GET_FILE = 347 // { int __acl_get_file(const char *path, acl_type_t type, struct acl *aclp); } + SYS___ACL_SET_FILE = 348 // { int __acl_set_file(const char *path, acl_type_t type, struct acl *aclp); } + SYS___ACL_GET_FD = 349 // { int __acl_get_fd(int filedes, acl_type_t type, struct acl *aclp); } + SYS___ACL_SET_FD = 350 // { int __acl_set_fd(int filedes, acl_type_t type, struct acl *aclp); } + SYS___ACL_DELETE_FILE = 351 // { int __acl_delete_file(const char *path, acl_type_t type); } + SYS___ACL_DELETE_FD = 352 // { int __acl_delete_fd(int filedes, acl_type_t type); } + SYS___ACL_ACLCHECK_FILE = 353 // { int __acl_aclcheck_file(const char *path, acl_type_t type, struct acl *aclp); } + SYS___ACL_ACLCHECK_FD = 354 // { int __acl_aclcheck_fd(int filedes, acl_type_t type, struct acl *aclp); } + SYS_EXTATTRCTL = 355 // { int extattrctl(const char *path, int cmd, const char *filename, int attrnamespace, const char *attrname); } + SYS_EXTATTR_SET_FILE = 356 // { ssize_t extattr_set_file( const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes); } + SYS_EXTATTR_GET_FILE = 357 // { ssize_t extattr_get_file( const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes); } + SYS_EXTATTR_DELETE_FILE = 358 // { int extattr_delete_file(const char *path, int attrnamespace, const char *attrname); } + SYS_AIO_WAITCOMPLETE = 359 // { int aio_waitcomplete( struct aiocb **aiocbp, struct timespec *timeout); } + SYS_GETRESUID = 360 // { int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); } + SYS_GETRESGID = 361 // { int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); } + SYS_KQUEUE = 362 // { int kqueue(void); } + SYS_KEVENT = 363 // { int kevent(int fd, struct kevent *changelist, int nchanges, struct kevent *eventlist, int nevents, const struct timespec *timeout); } + SYS_EXTATTR_SET_FD = 371 // { ssize_t extattr_set_fd(int fd, int attrnamespace, const char *attrname, void *data, size_t nbytes); } + SYS_EXTATTR_GET_FD = 372 // { ssize_t extattr_get_fd(int fd, int attrnamespace, const char *attrname, void *data, size_t nbytes); } + SYS_EXTATTR_DELETE_FD = 373 // { int extattr_delete_fd(int fd, int attrnamespace, const char *attrname); } + SYS___SETUGID = 374 // { int __setugid(int flag); } + SYS_EACCESS = 376 // { int eaccess(char *path, int amode); } + SYS_NMOUNT = 378 // { int nmount(struct iovec *iovp, unsigned int iovcnt, int flags); } + SYS___MAC_GET_PROC = 384 // { int __mac_get_proc(struct mac *mac_p); } + SYS___MAC_SET_PROC = 385 // { int __mac_set_proc(struct mac *mac_p); } + SYS___MAC_GET_FD = 386 // { int __mac_get_fd(int fd, struct mac *mac_p); } + SYS___MAC_GET_FILE = 387 // { int __mac_get_file(const char *path_p, struct mac *mac_p); } + SYS___MAC_SET_FD = 388 // { int __mac_set_fd(int fd, struct mac *mac_p); } + SYS___MAC_SET_FILE = 389 // { int __mac_set_file(const char *path_p, struct mac *mac_p); } + SYS_KENV = 390 // { int kenv(int what, const char *name, char *value, int len); } + SYS_LCHFLAGS = 391 // { int lchflags(const char *path, u_long flags); } + SYS_UUIDGEN = 392 // { int uuidgen(struct uuid *store, int count); } + SYS_SENDFILE = 393 // { int sendfile(int fd, int s, off_t offset, size_t nbytes, struct sf_hdtr *hdtr, off_t *sbytes, int flags); } + SYS_MAC_SYSCALL = 394 // { int mac_syscall(const char *policy, int call, void *arg); } + SYS_GETFSSTAT = 395 // { int getfsstat(struct statfs *buf, long bufsize, int flags); } + SYS_STATFS = 396 // { int statfs(char *path, struct statfs *buf); } + SYS_FSTATFS = 397 // { int fstatfs(int fd, struct statfs *buf); } + SYS_FHSTATFS = 398 // { int fhstatfs(const struct fhandle *u_fhp, struct statfs *buf); } + SYS_KSEM_CLOSE = 400 // { int ksem_close(semid_t id); } + SYS_KSEM_POST = 401 // { int ksem_post(semid_t id); } + SYS_KSEM_WAIT = 402 // { int ksem_wait(semid_t id); } + SYS_KSEM_TRYWAIT = 403 // { int ksem_trywait(semid_t id); } + SYS_KSEM_INIT = 404 // { int ksem_init(semid_t *idp, unsigned int value); } + SYS_KSEM_OPEN = 405 // { int ksem_open(semid_t *idp, const char *name, int oflag, mode_t mode, unsigned int value); } + SYS_KSEM_UNLINK = 406 // { int ksem_unlink(const char *name); } + SYS_KSEM_GETVALUE = 407 // { int ksem_getvalue(semid_t id, int *val); } + SYS_KSEM_DESTROY = 408 // { int ksem_destroy(semid_t id); } + SYS___MAC_GET_PID = 409 // { int __mac_get_pid(pid_t pid, struct mac *mac_p); } + SYS___MAC_GET_LINK = 410 // { int __mac_get_link(const char *path_p, struct mac *mac_p); } + SYS___MAC_SET_LINK = 411 // { int __mac_set_link(const char *path_p, struct mac *mac_p); } + SYS_EXTATTR_SET_LINK = 412 // { ssize_t extattr_set_link( const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes); } + SYS_EXTATTR_GET_LINK = 413 // { ssize_t extattr_get_link( const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes); } + SYS_EXTATTR_DELETE_LINK = 414 // { int extattr_delete_link( const char *path, int attrnamespace, const char *attrname); } + SYS___MAC_EXECVE = 415 // { int __mac_execve(char *fname, char **argv, char **envv, struct mac *mac_p); } + SYS_SIGACTION = 416 // { int sigaction(int sig, const struct sigaction *act, struct sigaction *oact); } + SYS_SIGRETURN = 417 // { int sigreturn( const struct __ucontext *sigcntxp); } + SYS_GETCONTEXT = 421 // { int getcontext(struct __ucontext *ucp); } + SYS_SETCONTEXT = 422 // { int setcontext( const struct __ucontext *ucp); } + SYS_SWAPCONTEXT = 423 // { int swapcontext(struct __ucontext *oucp, const struct __ucontext *ucp); } + SYS_SWAPOFF = 424 // { int swapoff(const char *name); } + SYS___ACL_GET_LINK = 425 // { int __acl_get_link(const char *path, acl_type_t type, struct acl *aclp); } + SYS___ACL_SET_LINK = 426 // { int __acl_set_link(const char *path, acl_type_t type, struct acl *aclp); } + SYS___ACL_DELETE_LINK = 427 // { int __acl_delete_link(const char *path, acl_type_t type); } + SYS___ACL_ACLCHECK_LINK = 428 // { int __acl_aclcheck_link(const char *path, acl_type_t type, struct acl *aclp); } + SYS_SIGWAIT = 429 // { int sigwait(const sigset_t *set, int *sig); } + SYS_THR_CREATE = 430 // { int thr_create(ucontext_t *ctx, long *id, int flags); } + SYS_THR_EXIT = 431 // { void thr_exit(long *state); } + SYS_THR_SELF = 432 // { int thr_self(long *id); } + SYS_THR_KILL = 433 // { int thr_kill(long id, int sig); } + SYS__UMTX_LOCK = 434 // { int _umtx_lock(struct umtx *umtx); } + SYS__UMTX_UNLOCK = 435 // { int _umtx_unlock(struct umtx *umtx); } + SYS_JAIL_ATTACH = 436 // { int jail_attach(int jid); } + SYS_EXTATTR_LIST_FD = 437 // { ssize_t extattr_list_fd(int fd, int attrnamespace, void *data, size_t nbytes); } + SYS_EXTATTR_LIST_FILE = 438 // { ssize_t extattr_list_file( const char *path, int attrnamespace, void *data, size_t nbytes); } + SYS_EXTATTR_LIST_LINK = 439 // { ssize_t extattr_list_link( const char *path, int attrnamespace, void *data, size_t nbytes); } + SYS_KSEM_TIMEDWAIT = 441 // { int ksem_timedwait(semid_t id, const struct timespec *abstime); } + SYS_THR_SUSPEND = 442 // { int thr_suspend( const struct timespec *timeout); } + SYS_THR_WAKE = 443 // { int thr_wake(long id); } + SYS_KLDUNLOADF = 444 // { int kldunloadf(int fileid, int flags); } + SYS_AUDIT = 445 // { int audit(const void *record, u_int length); } + SYS_AUDITON = 446 // { int auditon(int cmd, void *data, u_int length); } + SYS_GETAUID = 447 // { int getauid(uid_t *auid); } + SYS_SETAUID = 448 // { int setauid(uid_t *auid); } + SYS_GETAUDIT = 449 // { int getaudit(struct auditinfo *auditinfo); } + SYS_SETAUDIT = 450 // { int setaudit(struct auditinfo *auditinfo); } + SYS_GETAUDIT_ADDR = 451 // { int getaudit_addr( struct auditinfo_addr *auditinfo_addr, u_int length); } + SYS_SETAUDIT_ADDR = 452 // { int setaudit_addr( struct auditinfo_addr *auditinfo_addr, u_int length); } + SYS_AUDITCTL = 453 // { int auditctl(char *path); } + SYS__UMTX_OP = 454 // { int _umtx_op(void *obj, int op, u_long val, void *uaddr1, void *uaddr2); } + SYS_THR_NEW = 455 // { int thr_new(struct thr_param *param, int param_size); } + SYS_SIGQUEUE = 456 // { int sigqueue(pid_t pid, int signum, void *value); } + SYS_KMQ_OPEN = 457 // { int kmq_open(const char *path, int flags, mode_t mode, const struct mq_attr *attr); } + SYS_KMQ_SETATTR = 458 // { int kmq_setattr(int mqd, const struct mq_attr *attr, struct mq_attr *oattr); } + SYS_KMQ_TIMEDRECEIVE = 459 // { int kmq_timedreceive(int mqd, char *msg_ptr, size_t msg_len, unsigned *msg_prio, const struct timespec *abs_timeout); } + SYS_KMQ_TIMEDSEND = 460 // { int kmq_timedsend(int mqd, const char *msg_ptr, size_t msg_len,unsigned msg_prio, const struct timespec *abs_timeout);} + SYS_KMQ_NOTIFY = 461 // { int kmq_notify(int mqd, const struct sigevent *sigev); } + SYS_KMQ_UNLINK = 462 // { int kmq_unlink(const char *path); } + SYS_ABORT2 = 463 // { int abort2(const char *why, int nargs, void **args); } + SYS_THR_SET_NAME = 464 // { int thr_set_name(long id, const char *name); } + SYS_AIO_FSYNC = 465 // { int aio_fsync(int op, struct aiocb *aiocbp); } + SYS_RTPRIO_THREAD = 466 // { int rtprio_thread(int function, lwpid_t lwpid, struct rtprio *rtp); } + SYS_SCTP_PEELOFF = 471 // { int sctp_peeloff(int sd, uint32_t name); } + SYS_SCTP_GENERIC_SENDMSG = 472 // { int sctp_generic_sendmsg(int sd, caddr_t msg, int mlen, caddr_t to, __socklen_t tolen, struct sctp_sndrcvinfo *sinfo, int flags); } + SYS_SCTP_GENERIC_SENDMSG_IOV = 473 // { int sctp_generic_sendmsg_iov(int sd, struct iovec *iov, int iovlen, caddr_t to, __socklen_t tolen, struct sctp_sndrcvinfo *sinfo, int flags); } + SYS_SCTP_GENERIC_RECVMSG = 474 // { int sctp_generic_recvmsg(int sd, struct iovec *iov, int iovlen, struct sockaddr * from, __socklen_t *fromlenaddr, struct sctp_sndrcvinfo *sinfo, int *msg_flags); } + SYS_PREAD = 475 // { ssize_t pread(int fd, void *buf, size_t nbyte, off_t offset); } + SYS_PWRITE = 476 // { ssize_t pwrite(int fd, const void *buf, size_t nbyte, off_t offset); } + SYS_MMAP = 477 // { caddr_t mmap(caddr_t addr, size_t len, int prot, int flags, int fd, off_t pos); } + SYS_LSEEK = 478 // { off_t lseek(int fd, off_t offset, int whence); } + SYS_TRUNCATE = 479 // { int truncate(char *path, off_t length); } + SYS_FTRUNCATE = 480 // { int ftruncate(int fd, off_t length); } + SYS_THR_KILL2 = 481 // { int thr_kill2(pid_t pid, long id, int sig); } + SYS_SHM_OPEN = 482 // { int shm_open(const char *path, int flags, mode_t mode); } + SYS_SHM_UNLINK = 483 // { int shm_unlink(const char *path); } + SYS_CPUSET = 484 // { int cpuset(cpusetid_t *setid); } + SYS_CPUSET_SETID = 485 // { int cpuset_setid(cpuwhich_t which, id_t id, cpusetid_t setid); } + SYS_CPUSET_GETID = 486 // { int cpuset_getid(cpulevel_t level, cpuwhich_t which, id_t id, cpusetid_t *setid); } + SYS_CPUSET_GETAFFINITY = 487 // { int cpuset_getaffinity(cpulevel_t level, cpuwhich_t which, id_t id, size_t cpusetsize, cpuset_t *mask); } + SYS_CPUSET_SETAFFINITY = 488 // { int cpuset_setaffinity(cpulevel_t level, cpuwhich_t which, id_t id, size_t cpusetsize, const cpuset_t *mask); } + SYS_FACCESSAT = 489 // { int faccessat(int fd, char *path, int amode, int flag); } + SYS_FCHMODAT = 490 // { int fchmodat(int fd, char *path, mode_t mode, int flag); } + SYS_FCHOWNAT = 491 // { int fchownat(int fd, char *path, uid_t uid, gid_t gid, int flag); } + SYS_FEXECVE = 492 // { int fexecve(int fd, char **argv, char **envv); } + SYS_FSTATAT = 493 // { int fstatat(int fd, char *path, struct stat *buf, int flag); } + SYS_FUTIMESAT = 494 // { int futimesat(int fd, char *path, struct timeval *times); } + SYS_LINKAT = 495 // { int linkat(int fd1, char *path1, int fd2, char *path2, int flag); } + SYS_MKDIRAT = 496 // { int mkdirat(int fd, char *path, mode_t mode); } + SYS_MKFIFOAT = 497 // { int mkfifoat(int fd, char *path, mode_t mode); } + SYS_MKNODAT = 498 // { int mknodat(int fd, char *path, mode_t mode, dev_t dev); } + SYS_OPENAT = 499 // { int openat(int fd, char *path, int flag, mode_t mode); } + SYS_READLINKAT = 500 // { int readlinkat(int fd, char *path, char *buf, size_t bufsize); } + SYS_RENAMEAT = 501 // { int renameat(int oldfd, char *old, int newfd, char *new); } + SYS_SYMLINKAT = 502 // { int symlinkat(char *path1, int fd, char *path2); } + SYS_UNLINKAT = 503 // { int unlinkat(int fd, char *path, int flag); } + SYS_POSIX_OPENPT = 504 // { int posix_openpt(int flags); } + SYS_GSSD_SYSCALL = 505 // { int gssd_syscall(char *path); } + SYS_JAIL_GET = 506 // { int jail_get(struct iovec *iovp, unsigned int iovcnt, int flags); } + SYS_JAIL_SET = 507 // { int jail_set(struct iovec *iovp, unsigned int iovcnt, int flags); } + SYS_JAIL_REMOVE = 508 // { int jail_remove(int jid); } + SYS_CLOSEFROM = 509 // { int closefrom(int lowfd); } + SYS___SEMCTL = 510 // { int __semctl(int semid, int semnum, int cmd, union semun *arg); } + SYS_MSGCTL = 511 // { int msgctl(int msqid, int cmd, struct msqid_ds *buf); } + SYS_SHMCTL = 512 // { int shmctl(int shmid, int cmd, struct shmid_ds *buf); } + SYS_LPATHCONF = 513 // { int lpathconf(char *path, int name); } + SYS___CAP_RIGHTS_GET = 515 // { int __cap_rights_get(int version, int fd, cap_rights_t *rightsp); } + SYS_CAP_ENTER = 516 // { int cap_enter(void); } + SYS_CAP_GETMODE = 517 // { int cap_getmode(u_int *modep); } + SYS_PDFORK = 518 // { int pdfork(int *fdp, int flags); } + SYS_PDKILL = 519 // { int pdkill(int fd, int signum); } + SYS_PDGETPID = 520 // { int pdgetpid(int fd, pid_t *pidp); } + SYS_PSELECT = 522 // { int pselect(int nd, fd_set *in, fd_set *ou, fd_set *ex, const struct timespec *ts, const sigset_t *sm); } + SYS_GETLOGINCLASS = 523 // { int getloginclass(char *namebuf, size_t namelen); } + SYS_SETLOGINCLASS = 524 // { int setloginclass(const char *namebuf); } + SYS_RCTL_GET_RACCT = 525 // { int rctl_get_racct(const void *inbufp, size_t inbuflen, void *outbufp, size_t outbuflen); } + SYS_RCTL_GET_RULES = 526 // { int rctl_get_rules(const void *inbufp, size_t inbuflen, void *outbufp, size_t outbuflen); } + SYS_RCTL_GET_LIMITS = 527 // { int rctl_get_limits(const void *inbufp, size_t inbuflen, void *outbufp, size_t outbuflen); } + SYS_RCTL_ADD_RULE = 528 // { int rctl_add_rule(const void *inbufp, size_t inbuflen, void *outbufp, size_t outbuflen); } + SYS_RCTL_REMOVE_RULE = 529 // { int rctl_remove_rule(const void *inbufp, size_t inbuflen, void *outbufp, size_t outbuflen); } + SYS_POSIX_FALLOCATE = 530 // { int posix_fallocate(int fd, off_t offset, off_t len); } + SYS_POSIX_FADVISE = 531 // { int posix_fadvise(int fd, off_t offset, off_t len, int advice); } + SYS_WAIT6 = 532 // { int wait6(idtype_t idtype, id_t id, int *status, int options, struct __wrusage *wrusage, siginfo_t *info); } + SYS_CAP_RIGHTS_LIMIT = 533 // { int cap_rights_limit(int fd, cap_rights_t *rightsp); } + SYS_CAP_IOCTLS_LIMIT = 534 // { int cap_ioctls_limit(int fd, const u_long *cmds, size_t ncmds); } + SYS_CAP_IOCTLS_GET = 535 // { ssize_t cap_ioctls_get(int fd, u_long *cmds, size_t maxcmds); } + SYS_CAP_FCNTLS_LIMIT = 536 // { int cap_fcntls_limit(int fd, uint32_t fcntlrights); } + SYS_CAP_FCNTLS_GET = 537 // { int cap_fcntls_get(int fd, uint32_t *fcntlrightsp); } + SYS_BINDAT = 538 // { int bindat(int fd, int s, caddr_t name, int namelen); } + SYS_CONNECTAT = 539 // { int connectat(int fd, int s, caddr_t name, int namelen); } + SYS_CHFLAGSAT = 540 // { int chflagsat(int fd, const char *path, u_long flags, int atflag); } + SYS_ACCEPT4 = 541 // { int accept4(int s, struct sockaddr * __restrict name, __socklen_t * __restrict anamelen, int flags); } + SYS_PIPE2 = 542 // { int pipe2(int *fildes, int flags); } + SYS_AIO_MLOCK = 543 // { int aio_mlock(struct aiocb *aiocbp); } + SYS_PROCCTL = 544 // { int procctl(idtype_t idtype, id_t id, int com, void *data); } + SYS_PPOLL = 545 // { int ppoll(struct pollfd *fds, u_int nfds, const struct timespec *ts, const sigset_t *set); } + SYS_FUTIMENS = 546 // { int futimens(int fd, struct timespec *times); } + SYS_UTIMENSAT = 547 // { int utimensat(int fd, char *path, struct timespec *times, int flag); } ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_freebsd_amd64.go b/vendor/golang.org/x/sys/unix/zsysnum_freebsd_amd64.go index 81722ac9f3..b39be6cb8f 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_freebsd_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_freebsd_amd64.go @@ -1,4 +1,4 @@ -// mksysnum_freebsd.pl +// go run mksysnum.go https://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master // Code generated by the command above; see README.md. DO NOT EDIT. // +build amd64,freebsd @@ -7,347 +7,397 @@ package unix const ( // SYS_NOSYS = 0; // { int nosys(void); } syscall nosys_args int - SYS_EXIT = 1 // { void sys_exit(int rval); } exit \ - SYS_FORK = 2 // { int fork(void); } - SYS_READ = 3 // { ssize_t read(int fd, void *buf, \ - SYS_WRITE = 4 // { ssize_t write(int fd, const void *buf, \ - SYS_OPEN = 5 // { int open(char *path, int flags, int mode); } - SYS_CLOSE = 6 // { int close(int fd); } - SYS_WAIT4 = 7 // { int wait4(int pid, int *status, \ - SYS_LINK = 9 // { int link(char *path, char *link); } - SYS_UNLINK = 10 // { int unlink(char *path); } - SYS_CHDIR = 12 // { int chdir(char *path); } - SYS_FCHDIR = 13 // { int fchdir(int fd); } - SYS_MKNOD = 14 // { int mknod(char *path, int mode, int dev); } - SYS_CHMOD = 15 // { int chmod(char *path, int mode); } - SYS_CHOWN = 16 // { int chown(char *path, int uid, int gid); } - SYS_OBREAK = 17 // { int obreak(char *nsize); } break \ - SYS_GETPID = 20 // { pid_t getpid(void); } - SYS_MOUNT = 21 // { int mount(char *type, char *path, \ - SYS_UNMOUNT = 22 // { int unmount(char *path, int flags); } - SYS_SETUID = 23 // { int setuid(uid_t uid); } - SYS_GETUID = 24 // { uid_t getuid(void); } - SYS_GETEUID = 25 // { uid_t geteuid(void); } - SYS_PTRACE = 26 // { int ptrace(int req, pid_t pid, \ - SYS_RECVMSG = 27 // { int recvmsg(int s, struct msghdr *msg, \ - SYS_SENDMSG = 28 // { int sendmsg(int s, struct msghdr *msg, \ - SYS_RECVFROM = 29 // { int recvfrom(int s, caddr_t buf, \ - SYS_ACCEPT = 30 // { int accept(int s, \ - SYS_GETPEERNAME = 31 // { int getpeername(int fdes, \ - SYS_GETSOCKNAME = 32 // { int getsockname(int fdes, \ - SYS_ACCESS = 33 // { int access(char *path, int amode); } - SYS_CHFLAGS = 34 // { int chflags(const char *path, u_long flags); } - SYS_FCHFLAGS = 35 // { int fchflags(int fd, u_long flags); } - SYS_SYNC = 36 // { int sync(void); } - SYS_KILL = 37 // { int kill(int pid, int signum); } - SYS_GETPPID = 39 // { pid_t getppid(void); } - SYS_DUP = 41 // { int dup(u_int fd); } - SYS_PIPE = 42 // { int pipe(void); } - SYS_GETEGID = 43 // { gid_t getegid(void); } - SYS_PROFIL = 44 // { int profil(caddr_t samples, size_t size, \ - SYS_KTRACE = 45 // { int ktrace(const char *fname, int ops, \ - SYS_GETGID = 47 // { gid_t getgid(void); } - SYS_GETLOGIN = 49 // { int getlogin(char *namebuf, u_int \ - SYS_SETLOGIN = 50 // { int setlogin(char *namebuf); } - SYS_ACCT = 51 // { int acct(char *path); } - SYS_SIGALTSTACK = 53 // { int sigaltstack(stack_t *ss, \ - SYS_IOCTL = 54 // { int ioctl(int fd, u_long com, \ - SYS_REBOOT = 55 // { int reboot(int opt); } - SYS_REVOKE = 56 // { int revoke(char *path); } - SYS_SYMLINK = 57 // { int symlink(char *path, char *link); } - SYS_READLINK = 58 // { ssize_t readlink(char *path, char *buf, \ - SYS_EXECVE = 59 // { int execve(char *fname, char **argv, \ - SYS_UMASK = 60 // { int umask(int newmask); } umask umask_args \ - SYS_CHROOT = 61 // { int chroot(char *path); } - SYS_MSYNC = 65 // { int msync(void *addr, size_t len, \ - SYS_VFORK = 66 // { int vfork(void); } - SYS_SBRK = 69 // { int sbrk(int incr); } - SYS_SSTK = 70 // { int sstk(int incr); } - SYS_OVADVISE = 72 // { int ovadvise(int anom); } vadvise \ - SYS_MUNMAP = 73 // { int munmap(void *addr, size_t len); } - SYS_MPROTECT = 74 // { int mprotect(const void *addr, size_t len, \ - SYS_MADVISE = 75 // { int madvise(void *addr, size_t len, \ - SYS_MINCORE = 78 // { int mincore(const void *addr, size_t len, \ - SYS_GETGROUPS = 79 // { int getgroups(u_int gidsetsize, \ - SYS_SETGROUPS = 80 // { int setgroups(u_int gidsetsize, \ - SYS_GETPGRP = 81 // { int getpgrp(void); } - SYS_SETPGID = 82 // { int setpgid(int pid, int pgid); } - SYS_SETITIMER = 83 // { int setitimer(u_int which, struct \ - SYS_SWAPON = 85 // { int swapon(char *name); } - SYS_GETITIMER = 86 // { int getitimer(u_int which, \ - SYS_GETDTABLESIZE = 89 // { int getdtablesize(void); } - SYS_DUP2 = 90 // { int dup2(u_int from, u_int to); } - SYS_FCNTL = 92 // { int fcntl(int fd, int cmd, long arg); } - SYS_SELECT = 93 // { int select(int nd, fd_set *in, fd_set *ou, \ - SYS_FSYNC = 95 // { int fsync(int fd); } - SYS_SETPRIORITY = 96 // { int setpriority(int which, int who, \ - SYS_SOCKET = 97 // { int socket(int domain, int type, \ - SYS_CONNECT = 98 // { int connect(int s, caddr_t name, \ - SYS_GETPRIORITY = 100 // { int getpriority(int which, int who); } - SYS_BIND = 104 // { int bind(int s, caddr_t name, \ - SYS_SETSOCKOPT = 105 // { int setsockopt(int s, int level, int name, \ - SYS_LISTEN = 106 // { int listen(int s, int backlog); } - SYS_GETTIMEOFDAY = 116 // { int gettimeofday(struct timeval *tp, \ - SYS_GETRUSAGE = 117 // { int getrusage(int who, \ - SYS_GETSOCKOPT = 118 // { int getsockopt(int s, int level, int name, \ - SYS_READV = 120 // { int readv(int fd, struct iovec *iovp, \ - SYS_WRITEV = 121 // { int writev(int fd, struct iovec *iovp, \ - SYS_SETTIMEOFDAY = 122 // { int settimeofday(struct timeval *tv, \ - SYS_FCHOWN = 123 // { int fchown(int fd, int uid, int gid); } - SYS_FCHMOD = 124 // { int fchmod(int fd, int mode); } - SYS_SETREUID = 126 // { int setreuid(int ruid, int euid); } - SYS_SETREGID = 127 // { int setregid(int rgid, int egid); } - SYS_RENAME = 128 // { int rename(char *from, char *to); } - SYS_FLOCK = 131 // { int flock(int fd, int how); } - SYS_MKFIFO = 132 // { int mkfifo(char *path, int mode); } - SYS_SENDTO = 133 // { int sendto(int s, caddr_t buf, size_t len, \ - SYS_SHUTDOWN = 134 // { int shutdown(int s, int how); } - SYS_SOCKETPAIR = 135 // { int socketpair(int domain, int type, \ - SYS_MKDIR = 136 // { int mkdir(char *path, int mode); } - SYS_RMDIR = 137 // { int rmdir(char *path); } - SYS_UTIMES = 138 // { int utimes(char *path, \ - SYS_ADJTIME = 140 // { int adjtime(struct timeval *delta, \ - SYS_SETSID = 147 // { int setsid(void); } - SYS_QUOTACTL = 148 // { int quotactl(char *path, int cmd, int uid, \ - SYS_LGETFH = 160 // { int lgetfh(char *fname, \ - SYS_GETFH = 161 // { int getfh(char *fname, \ - SYS_SYSARCH = 165 // { int sysarch(int op, char *parms); } - SYS_RTPRIO = 166 // { int rtprio(int function, pid_t pid, \ - SYS_FREEBSD6_PREAD = 173 // { ssize_t freebsd6_pread(int fd, void *buf, \ - SYS_FREEBSD6_PWRITE = 174 // { ssize_t freebsd6_pwrite(int fd, \ - SYS_SETFIB = 175 // { int setfib(int fibnum); } - SYS_NTP_ADJTIME = 176 // { int ntp_adjtime(struct timex *tp); } - SYS_SETGID = 181 // { int setgid(gid_t gid); } - SYS_SETEGID = 182 // { int setegid(gid_t egid); } - SYS_SETEUID = 183 // { int seteuid(uid_t euid); } - SYS_STAT = 188 // { int stat(char *path, struct stat *ub); } - SYS_FSTAT = 189 // { int fstat(int fd, struct stat *sb); } - SYS_LSTAT = 190 // { int lstat(char *path, struct stat *ub); } - SYS_PATHCONF = 191 // { int pathconf(char *path, int name); } - SYS_FPATHCONF = 192 // { int fpathconf(int fd, int name); } - SYS_GETRLIMIT = 194 // { int getrlimit(u_int which, \ - SYS_SETRLIMIT = 195 // { int setrlimit(u_int which, \ - SYS_GETDIRENTRIES = 196 // { int getdirentries(int fd, char *buf, \ - SYS_FREEBSD6_MMAP = 197 // { caddr_t freebsd6_mmap(caddr_t addr, \ - SYS_FREEBSD6_LSEEK = 199 // { off_t freebsd6_lseek(int fd, int pad, \ - SYS_FREEBSD6_TRUNCATE = 200 // { int freebsd6_truncate(char *path, int pad, \ - SYS_FREEBSD6_FTRUNCATE = 201 // { int freebsd6_ftruncate(int fd, int pad, \ - SYS___SYSCTL = 202 // { int __sysctl(int *name, u_int namelen, \ - SYS_MLOCK = 203 // { int mlock(const void *addr, size_t len); } - SYS_MUNLOCK = 204 // { int munlock(const void *addr, size_t len); } - SYS_UNDELETE = 205 // { int undelete(char *path); } - SYS_FUTIMES = 206 // { int futimes(int fd, struct timeval *tptr); } - SYS_GETPGID = 207 // { int getpgid(pid_t pid); } - SYS_POLL = 209 // { int poll(struct pollfd *fds, u_int nfds, \ - SYS_CLOCK_GETTIME = 232 // { int clock_gettime(clockid_t clock_id, \ - SYS_CLOCK_SETTIME = 233 // { int clock_settime( \ - SYS_CLOCK_GETRES = 234 // { int clock_getres(clockid_t clock_id, \ - SYS_KTIMER_CREATE = 235 // { int ktimer_create(clockid_t clock_id, \ - SYS_KTIMER_DELETE = 236 // { int ktimer_delete(int timerid); } - SYS_KTIMER_SETTIME = 237 // { int ktimer_settime(int timerid, int flags, \ - SYS_KTIMER_GETTIME = 238 // { int ktimer_gettime(int timerid, struct \ - SYS_KTIMER_GETOVERRUN = 239 // { int ktimer_getoverrun(int timerid); } - SYS_NANOSLEEP = 240 // { int nanosleep(const struct timespec *rqtp, \ - SYS_FFCLOCK_GETCOUNTER = 241 // { int ffclock_getcounter(ffcounter *ffcount); } - SYS_FFCLOCK_SETESTIMATE = 242 // { int ffclock_setestimate( \ - SYS_FFCLOCK_GETESTIMATE = 243 // { int ffclock_getestimate( \ - SYS_CLOCK_GETCPUCLOCKID2 = 247 // { int clock_getcpuclockid2(id_t id,\ - SYS_NTP_GETTIME = 248 // { int ntp_gettime(struct ntptimeval *ntvp); } - SYS_MINHERIT = 250 // { int minherit(void *addr, size_t len, \ - SYS_RFORK = 251 // { int rfork(int flags); } - SYS_OPENBSD_POLL = 252 // { int openbsd_poll(struct pollfd *fds, \ - SYS_ISSETUGID = 253 // { int issetugid(void); } - SYS_LCHOWN = 254 // { int lchown(char *path, int uid, int gid); } - SYS_GETDENTS = 272 // { int getdents(int fd, char *buf, \ - SYS_LCHMOD = 274 // { int lchmod(char *path, mode_t mode); } - SYS_LUTIMES = 276 // { int lutimes(char *path, \ - SYS_NSTAT = 278 // { int nstat(char *path, struct nstat *ub); } - SYS_NFSTAT = 279 // { int nfstat(int fd, struct nstat *sb); } - SYS_NLSTAT = 280 // { int nlstat(char *path, struct nstat *ub); } - SYS_PREADV = 289 // { ssize_t preadv(int fd, struct iovec *iovp, \ - SYS_PWRITEV = 290 // { ssize_t pwritev(int fd, struct iovec *iovp, \ - SYS_FHOPEN = 298 // { int fhopen(const struct fhandle *u_fhp, \ - SYS_FHSTAT = 299 // { int fhstat(const struct fhandle *u_fhp, \ - SYS_MODNEXT = 300 // { int modnext(int modid); } - SYS_MODSTAT = 301 // { int modstat(int modid, \ - SYS_MODFNEXT = 302 // { int modfnext(int modid); } - SYS_MODFIND = 303 // { int modfind(const char *name); } - SYS_KLDLOAD = 304 // { int kldload(const char *file); } - SYS_KLDUNLOAD = 305 // { int kldunload(int fileid); } - SYS_KLDFIND = 306 // { int kldfind(const char *file); } - SYS_KLDNEXT = 307 // { int kldnext(int fileid); } - SYS_KLDSTAT = 308 // { int kldstat(int fileid, struct \ - SYS_KLDFIRSTMOD = 309 // { int kldfirstmod(int fileid); } - SYS_GETSID = 310 // { int getsid(pid_t pid); } - SYS_SETRESUID = 311 // { int setresuid(uid_t ruid, uid_t euid, \ - SYS_SETRESGID = 312 // { int setresgid(gid_t rgid, gid_t egid, \ - SYS_YIELD = 321 // { int yield(void); } - SYS_MLOCKALL = 324 // { int mlockall(int how); } - SYS_MUNLOCKALL = 325 // { int munlockall(void); } - SYS___GETCWD = 326 // { int __getcwd(char *buf, u_int buflen); } - SYS_SCHED_SETPARAM = 327 // { int sched_setparam (pid_t pid, \ - SYS_SCHED_GETPARAM = 328 // { int sched_getparam (pid_t pid, struct \ - SYS_SCHED_SETSCHEDULER = 329 // { int sched_setscheduler (pid_t pid, int \ - SYS_SCHED_GETSCHEDULER = 330 // { int sched_getscheduler (pid_t pid); } - SYS_SCHED_YIELD = 331 // { int sched_yield (void); } - SYS_SCHED_GET_PRIORITY_MAX = 332 // { int sched_get_priority_max (int policy); } - SYS_SCHED_GET_PRIORITY_MIN = 333 // { int sched_get_priority_min (int policy); } - SYS_SCHED_RR_GET_INTERVAL = 334 // { int sched_rr_get_interval (pid_t pid, \ - SYS_UTRACE = 335 // { int utrace(const void *addr, size_t len); } - SYS_KLDSYM = 337 // { int kldsym(int fileid, int cmd, \ - SYS_JAIL = 338 // { int jail(struct jail *jail); } - SYS_SIGPROCMASK = 340 // { int sigprocmask(int how, \ - SYS_SIGSUSPEND = 341 // { int sigsuspend(const sigset_t *sigmask); } - SYS_SIGPENDING = 343 // { int sigpending(sigset_t *set); } - SYS_SIGTIMEDWAIT = 345 // { int sigtimedwait(const sigset_t *set, \ - SYS_SIGWAITINFO = 346 // { int sigwaitinfo(const sigset_t *set, \ - SYS___ACL_GET_FILE = 347 // { int __acl_get_file(const char *path, \ - SYS___ACL_SET_FILE = 348 // { int __acl_set_file(const char *path, \ - SYS___ACL_GET_FD = 349 // { int __acl_get_fd(int filedes, \ - SYS___ACL_SET_FD = 350 // { int __acl_set_fd(int filedes, \ - SYS___ACL_DELETE_FILE = 351 // { int __acl_delete_file(const char *path, \ - SYS___ACL_DELETE_FD = 352 // { int __acl_delete_fd(int filedes, \ - SYS___ACL_ACLCHECK_FILE = 353 // { int __acl_aclcheck_file(const char *path, \ - SYS___ACL_ACLCHECK_FD = 354 // { int __acl_aclcheck_fd(int filedes, \ - SYS_EXTATTRCTL = 355 // { int extattrctl(const char *path, int cmd, \ - SYS_EXTATTR_SET_FILE = 356 // { ssize_t extattr_set_file( \ - SYS_EXTATTR_GET_FILE = 357 // { ssize_t extattr_get_file( \ - SYS_EXTATTR_DELETE_FILE = 358 // { int extattr_delete_file(const char *path, \ - SYS_GETRESUID = 360 // { int getresuid(uid_t *ruid, uid_t *euid, \ - SYS_GETRESGID = 361 // { int getresgid(gid_t *rgid, gid_t *egid, \ - SYS_KQUEUE = 362 // { int kqueue(void); } - SYS_KEVENT = 363 // { int kevent(int fd, \ - SYS_EXTATTR_SET_FD = 371 // { ssize_t extattr_set_fd(int fd, \ - SYS_EXTATTR_GET_FD = 372 // { ssize_t extattr_get_fd(int fd, \ - SYS_EXTATTR_DELETE_FD = 373 // { int extattr_delete_fd(int fd, \ - SYS___SETUGID = 374 // { int __setugid(int flag); } - SYS_EACCESS = 376 // { int eaccess(char *path, int amode); } - SYS_NMOUNT = 378 // { int nmount(struct iovec *iovp, \ - SYS___MAC_GET_PROC = 384 // { int __mac_get_proc(struct mac *mac_p); } - SYS___MAC_SET_PROC = 385 // { int __mac_set_proc(struct mac *mac_p); } - SYS___MAC_GET_FD = 386 // { int __mac_get_fd(int fd, \ - SYS___MAC_GET_FILE = 387 // { int __mac_get_file(const char *path_p, \ - SYS___MAC_SET_FD = 388 // { int __mac_set_fd(int fd, \ - SYS___MAC_SET_FILE = 389 // { int __mac_set_file(const char *path_p, \ - SYS_KENV = 390 // { int kenv(int what, const char *name, \ - SYS_LCHFLAGS = 391 // { int lchflags(const char *path, \ - SYS_UUIDGEN = 392 // { int uuidgen(struct uuid *store, \ - SYS_SENDFILE = 393 // { int sendfile(int fd, int s, off_t offset, \ - SYS_MAC_SYSCALL = 394 // { int mac_syscall(const char *policy, \ - SYS_GETFSSTAT = 395 // { int getfsstat(struct statfs *buf, \ - SYS_STATFS = 396 // { int statfs(char *path, \ - SYS_FSTATFS = 397 // { int fstatfs(int fd, struct statfs *buf); } - SYS_FHSTATFS = 398 // { int fhstatfs(const struct fhandle *u_fhp, \ - SYS___MAC_GET_PID = 409 // { int __mac_get_pid(pid_t pid, \ - SYS___MAC_GET_LINK = 410 // { int __mac_get_link(const char *path_p, \ - SYS___MAC_SET_LINK = 411 // { int __mac_set_link(const char *path_p, \ - SYS_EXTATTR_SET_LINK = 412 // { ssize_t extattr_set_link( \ - SYS_EXTATTR_GET_LINK = 413 // { ssize_t extattr_get_link( \ - SYS_EXTATTR_DELETE_LINK = 414 // { int extattr_delete_link( \ - SYS___MAC_EXECVE = 415 // { int __mac_execve(char *fname, char **argv, \ - SYS_SIGACTION = 416 // { int sigaction(int sig, \ - SYS_SIGRETURN = 417 // { int sigreturn( \ - SYS_GETCONTEXT = 421 // { int getcontext(struct __ucontext *ucp); } - SYS_SETCONTEXT = 422 // { int setcontext( \ - SYS_SWAPCONTEXT = 423 // { int swapcontext(struct __ucontext *oucp, \ - SYS_SWAPOFF = 424 // { int swapoff(const char *name); } - SYS___ACL_GET_LINK = 425 // { int __acl_get_link(const char *path, \ - SYS___ACL_SET_LINK = 426 // { int __acl_set_link(const char *path, \ - SYS___ACL_DELETE_LINK = 427 // { int __acl_delete_link(const char *path, \ - SYS___ACL_ACLCHECK_LINK = 428 // { int __acl_aclcheck_link(const char *path, \ - SYS_SIGWAIT = 429 // { int sigwait(const sigset_t *set, \ - SYS_THR_CREATE = 430 // { int thr_create(ucontext_t *ctx, long *id, \ - SYS_THR_EXIT = 431 // { void thr_exit(long *state); } - SYS_THR_SELF = 432 // { int thr_self(long *id); } - SYS_THR_KILL = 433 // { int thr_kill(long id, int sig); } - SYS__UMTX_LOCK = 434 // { int _umtx_lock(struct umtx *umtx); } - SYS__UMTX_UNLOCK = 435 // { int _umtx_unlock(struct umtx *umtx); } - SYS_JAIL_ATTACH = 436 // { int jail_attach(int jid); } - SYS_EXTATTR_LIST_FD = 437 // { ssize_t extattr_list_fd(int fd, \ - SYS_EXTATTR_LIST_FILE = 438 // { ssize_t extattr_list_file( \ - SYS_EXTATTR_LIST_LINK = 439 // { ssize_t extattr_list_link( \ - SYS_THR_SUSPEND = 442 // { int thr_suspend( \ - SYS_THR_WAKE = 443 // { int thr_wake(long id); } - SYS_KLDUNLOADF = 444 // { int kldunloadf(int fileid, int flags); } - SYS_AUDIT = 445 // { int audit(const void *record, \ - SYS_AUDITON = 446 // { int auditon(int cmd, void *data, \ - SYS_GETAUID = 447 // { int getauid(uid_t *auid); } - SYS_SETAUID = 448 // { int setauid(uid_t *auid); } - SYS_GETAUDIT = 449 // { int getaudit(struct auditinfo *auditinfo); } - SYS_SETAUDIT = 450 // { int setaudit(struct auditinfo *auditinfo); } - SYS_GETAUDIT_ADDR = 451 // { int getaudit_addr( \ - SYS_SETAUDIT_ADDR = 452 // { int setaudit_addr( \ - SYS_AUDITCTL = 453 // { int auditctl(char *path); } - SYS__UMTX_OP = 454 // { int _umtx_op(void *obj, int op, \ - SYS_THR_NEW = 455 // { int thr_new(struct thr_param *param, \ - SYS_SIGQUEUE = 456 // { int sigqueue(pid_t pid, int signum, void *value); } - SYS_ABORT2 = 463 // { int abort2(const char *why, int nargs, void **args); } - SYS_THR_SET_NAME = 464 // { int thr_set_name(long id, const char *name); } - SYS_RTPRIO_THREAD = 466 // { int rtprio_thread(int function, \ - SYS_PREAD = 475 // { ssize_t pread(int fd, void *buf, \ - SYS_PWRITE = 476 // { ssize_t pwrite(int fd, const void *buf, \ - SYS_MMAP = 477 // { caddr_t mmap(caddr_t addr, size_t len, \ - SYS_LSEEK = 478 // { off_t lseek(int fd, off_t offset, \ - SYS_TRUNCATE = 479 // { int truncate(char *path, off_t length); } - SYS_FTRUNCATE = 480 // { int ftruncate(int fd, off_t length); } - SYS_THR_KILL2 = 481 // { int thr_kill2(pid_t pid, long id, int sig); } - SYS_SHM_OPEN = 482 // { int shm_open(const char *path, int flags, \ - SYS_SHM_UNLINK = 483 // { int shm_unlink(const char *path); } - SYS_CPUSET = 484 // { int cpuset(cpusetid_t *setid); } - SYS_CPUSET_SETID = 485 // { int cpuset_setid(cpuwhich_t which, id_t id, \ - SYS_CPUSET_GETID = 486 // { int cpuset_getid(cpulevel_t level, \ - SYS_CPUSET_GETAFFINITY = 487 // { int cpuset_getaffinity(cpulevel_t level, \ - SYS_CPUSET_SETAFFINITY = 488 // { int cpuset_setaffinity(cpulevel_t level, \ - SYS_FACCESSAT = 489 // { int faccessat(int fd, char *path, int amode, \ - SYS_FCHMODAT = 490 // { int fchmodat(int fd, char *path, mode_t mode, \ - SYS_FCHOWNAT = 491 // { int fchownat(int fd, char *path, uid_t uid, \ - SYS_FEXECVE = 492 // { int fexecve(int fd, char **argv, \ - SYS_FSTATAT = 493 // { int fstatat(int fd, char *path, \ - SYS_FUTIMESAT = 494 // { int futimesat(int fd, char *path, \ - SYS_LINKAT = 495 // { int linkat(int fd1, char *path1, int fd2, \ - SYS_MKDIRAT = 496 // { int mkdirat(int fd, char *path, mode_t mode); } - SYS_MKFIFOAT = 497 // { int mkfifoat(int fd, char *path, mode_t mode); } - SYS_MKNODAT = 498 // { int mknodat(int fd, char *path, mode_t mode, \ - SYS_OPENAT = 499 // { int openat(int fd, char *path, int flag, \ - SYS_READLINKAT = 500 // { int readlinkat(int fd, char *path, char *buf, \ - SYS_RENAMEAT = 501 // { int renameat(int oldfd, char *old, int newfd, \ - SYS_SYMLINKAT = 502 // { int symlinkat(char *path1, int fd, \ - SYS_UNLINKAT = 503 // { int unlinkat(int fd, char *path, int flag); } - SYS_POSIX_OPENPT = 504 // { int posix_openpt(int flags); } - SYS_JAIL_GET = 506 // { int jail_get(struct iovec *iovp, \ - SYS_JAIL_SET = 507 // { int jail_set(struct iovec *iovp, \ - SYS_JAIL_REMOVE = 508 // { int jail_remove(int jid); } - SYS_CLOSEFROM = 509 // { int closefrom(int lowfd); } - SYS_LPATHCONF = 513 // { int lpathconf(char *path, int name); } - SYS___CAP_RIGHTS_GET = 515 // { int __cap_rights_get(int version, \ - SYS_CAP_ENTER = 516 // { int cap_enter(void); } - SYS_CAP_GETMODE = 517 // { int cap_getmode(u_int *modep); } - SYS_PDFORK = 518 // { int pdfork(int *fdp, int flags); } - SYS_PDKILL = 519 // { int pdkill(int fd, int signum); } - SYS_PDGETPID = 520 // { int pdgetpid(int fd, pid_t *pidp); } - SYS_PSELECT = 522 // { int pselect(int nd, fd_set *in, \ - SYS_GETLOGINCLASS = 523 // { int getloginclass(char *namebuf, \ - SYS_SETLOGINCLASS = 524 // { int setloginclass(const char *namebuf); } - SYS_RCTL_GET_RACCT = 525 // { int rctl_get_racct(const void *inbufp, \ - SYS_RCTL_GET_RULES = 526 // { int rctl_get_rules(const void *inbufp, \ - SYS_RCTL_GET_LIMITS = 527 // { int rctl_get_limits(const void *inbufp, \ - SYS_RCTL_ADD_RULE = 528 // { int rctl_add_rule(const void *inbufp, \ - SYS_RCTL_REMOVE_RULE = 529 // { int rctl_remove_rule(const void *inbufp, \ - SYS_POSIX_FALLOCATE = 530 // { int posix_fallocate(int fd, \ - SYS_POSIX_FADVISE = 531 // { int posix_fadvise(int fd, off_t offset, \ - SYS_WAIT6 = 532 // { int wait6(idtype_t idtype, id_t id, \ - SYS_CAP_RIGHTS_LIMIT = 533 // { int cap_rights_limit(int fd, \ - SYS_CAP_IOCTLS_LIMIT = 534 // { int cap_ioctls_limit(int fd, \ - SYS_CAP_IOCTLS_GET = 535 // { ssize_t cap_ioctls_get(int fd, \ - SYS_CAP_FCNTLS_LIMIT = 536 // { int cap_fcntls_limit(int fd, \ - SYS_CAP_FCNTLS_GET = 537 // { int cap_fcntls_get(int fd, \ - SYS_BINDAT = 538 // { int bindat(int fd, int s, caddr_t name, \ - SYS_CONNECTAT = 539 // { int connectat(int fd, int s, caddr_t name, \ - SYS_CHFLAGSAT = 540 // { int chflagsat(int fd, const char *path, \ - SYS_ACCEPT4 = 541 // { int accept4(int s, \ - SYS_PIPE2 = 542 // { int pipe2(int *fildes, int flags); } - SYS_PROCCTL = 544 // { int procctl(idtype_t idtype, id_t id, \ - SYS_PPOLL = 545 // { int ppoll(struct pollfd *fds, u_int nfds, \ - SYS_FUTIMENS = 546 // { int futimens(int fd, \ - SYS_UTIMENSAT = 547 // { int utimensat(int fd, \ + SYS_EXIT = 1 // { void sys_exit(int rval); } exit sys_exit_args void + SYS_FORK = 2 // { int fork(void); } + SYS_READ = 3 // { ssize_t read(int fd, void *buf, size_t nbyte); } + SYS_WRITE = 4 // { ssize_t write(int fd, const void *buf, size_t nbyte); } + SYS_OPEN = 5 // { int open(char *path, int flags, int mode); } + SYS_CLOSE = 6 // { int close(int fd); } + SYS_WAIT4 = 7 // { int wait4(int pid, int *status, int options, struct rusage *rusage); } + SYS_LINK = 9 // { int link(char *path, char *link); } + SYS_UNLINK = 10 // { int unlink(char *path); } + SYS_CHDIR = 12 // { int chdir(char *path); } + SYS_FCHDIR = 13 // { int fchdir(int fd); } + SYS_MKNOD = 14 // { int mknod(char *path, int mode, int dev); } + SYS_CHMOD = 15 // { int chmod(char *path, int mode); } + SYS_CHOWN = 16 // { int chown(char *path, int uid, int gid); } + SYS_OBREAK = 17 // { int obreak(char *nsize); } break obreak_args int + SYS_GETPID = 20 // { pid_t getpid(void); } + SYS_MOUNT = 21 // { int mount(char *type, char *path, int flags, caddr_t data); } + SYS_UNMOUNT = 22 // { int unmount(char *path, int flags); } + SYS_SETUID = 23 // { int setuid(uid_t uid); } + SYS_GETUID = 24 // { uid_t getuid(void); } + SYS_GETEUID = 25 // { uid_t geteuid(void); } + SYS_PTRACE = 26 // { int ptrace(int req, pid_t pid, caddr_t addr, int data); } + SYS_RECVMSG = 27 // { int recvmsg(int s, struct msghdr *msg, int flags); } + SYS_SENDMSG = 28 // { int sendmsg(int s, struct msghdr *msg, int flags); } + SYS_RECVFROM = 29 // { int recvfrom(int s, caddr_t buf, size_t len, int flags, struct sockaddr * __restrict from, __socklen_t * __restrict fromlenaddr); } + SYS_ACCEPT = 30 // { int accept(int s, struct sockaddr * __restrict name, __socklen_t * __restrict anamelen); } + SYS_GETPEERNAME = 31 // { int getpeername(int fdes, struct sockaddr * __restrict asa, __socklen_t * __restrict alen); } + SYS_GETSOCKNAME = 32 // { int getsockname(int fdes, struct sockaddr * __restrict asa, __socklen_t * __restrict alen); } + SYS_ACCESS = 33 // { int access(char *path, int amode); } + SYS_CHFLAGS = 34 // { int chflags(const char *path, u_long flags); } + SYS_FCHFLAGS = 35 // { int fchflags(int fd, u_long flags); } + SYS_SYNC = 36 // { int sync(void); } + SYS_KILL = 37 // { int kill(int pid, int signum); } + SYS_GETPPID = 39 // { pid_t getppid(void); } + SYS_DUP = 41 // { int dup(u_int fd); } + SYS_PIPE = 42 // { int pipe(void); } + SYS_GETEGID = 43 // { gid_t getegid(void); } + SYS_PROFIL = 44 // { int profil(caddr_t samples, size_t size, size_t offset, u_int scale); } + SYS_KTRACE = 45 // { int ktrace(const char *fname, int ops, int facs, int pid); } + SYS_GETGID = 47 // { gid_t getgid(void); } + SYS_GETLOGIN = 49 // { int getlogin(char *namebuf, u_int namelen); } + SYS_SETLOGIN = 50 // { int setlogin(char *namebuf); } + SYS_ACCT = 51 // { int acct(char *path); } + SYS_SIGALTSTACK = 53 // { int sigaltstack(stack_t *ss, stack_t *oss); } + SYS_IOCTL = 54 // { int ioctl(int fd, u_long com, caddr_t data); } + SYS_REBOOT = 55 // { int reboot(int opt); } + SYS_REVOKE = 56 // { int revoke(char *path); } + SYS_SYMLINK = 57 // { int symlink(char *path, char *link); } + SYS_READLINK = 58 // { ssize_t readlink(char *path, char *buf, size_t count); } + SYS_EXECVE = 59 // { int execve(char *fname, char **argv, char **envv); } + SYS_UMASK = 60 // { int umask(int newmask); } umask umask_args int + SYS_CHROOT = 61 // { int chroot(char *path); } + SYS_MSYNC = 65 // { int msync(void *addr, size_t len, int flags); } + SYS_VFORK = 66 // { int vfork(void); } + SYS_SBRK = 69 // { int sbrk(int incr); } + SYS_SSTK = 70 // { int sstk(int incr); } + SYS_OVADVISE = 72 // { int ovadvise(int anom); } vadvise ovadvise_args int + SYS_MUNMAP = 73 // { int munmap(void *addr, size_t len); } + SYS_MPROTECT = 74 // { int mprotect(const void *addr, size_t len, int prot); } + SYS_MADVISE = 75 // { int madvise(void *addr, size_t len, int behav); } + SYS_MINCORE = 78 // { int mincore(const void *addr, size_t len, char *vec); } + SYS_GETGROUPS = 79 // { int getgroups(u_int gidsetsize, gid_t *gidset); } + SYS_SETGROUPS = 80 // { int setgroups(u_int gidsetsize, gid_t *gidset); } + SYS_GETPGRP = 81 // { int getpgrp(void); } + SYS_SETPGID = 82 // { int setpgid(int pid, int pgid); } + SYS_SETITIMER = 83 // { int setitimer(u_int which, struct itimerval *itv, struct itimerval *oitv); } + SYS_SWAPON = 85 // { int swapon(char *name); } + SYS_GETITIMER = 86 // { int getitimer(u_int which, struct itimerval *itv); } + SYS_GETDTABLESIZE = 89 // { int getdtablesize(void); } + SYS_DUP2 = 90 // { int dup2(u_int from, u_int to); } + SYS_FCNTL = 92 // { int fcntl(int fd, int cmd, long arg); } + SYS_SELECT = 93 // { int select(int nd, fd_set *in, fd_set *ou, fd_set *ex, struct timeval *tv); } + SYS_FSYNC = 95 // { int fsync(int fd); } + SYS_SETPRIORITY = 96 // { int setpriority(int which, int who, int prio); } + SYS_SOCKET = 97 // { int socket(int domain, int type, int protocol); } + SYS_CONNECT = 98 // { int connect(int s, caddr_t name, int namelen); } + SYS_GETPRIORITY = 100 // { int getpriority(int which, int who); } + SYS_BIND = 104 // { int bind(int s, caddr_t name, int namelen); } + SYS_SETSOCKOPT = 105 // { int setsockopt(int s, int level, int name, caddr_t val, int valsize); } + SYS_LISTEN = 106 // { int listen(int s, int backlog); } + SYS_GETTIMEOFDAY = 116 // { int gettimeofday(struct timeval *tp, struct timezone *tzp); } + SYS_GETRUSAGE = 117 // { int getrusage(int who, struct rusage *rusage); } + SYS_GETSOCKOPT = 118 // { int getsockopt(int s, int level, int name, caddr_t val, int *avalsize); } + SYS_READV = 120 // { int readv(int fd, struct iovec *iovp, u_int iovcnt); } + SYS_WRITEV = 121 // { int writev(int fd, struct iovec *iovp, u_int iovcnt); } + SYS_SETTIMEOFDAY = 122 // { int settimeofday(struct timeval *tv, struct timezone *tzp); } + SYS_FCHOWN = 123 // { int fchown(int fd, int uid, int gid); } + SYS_FCHMOD = 124 // { int fchmod(int fd, int mode); } + SYS_SETREUID = 126 // { int setreuid(int ruid, int euid); } + SYS_SETREGID = 127 // { int setregid(int rgid, int egid); } + SYS_RENAME = 128 // { int rename(char *from, char *to); } + SYS_FLOCK = 131 // { int flock(int fd, int how); } + SYS_MKFIFO = 132 // { int mkfifo(char *path, int mode); } + SYS_SENDTO = 133 // { int sendto(int s, caddr_t buf, size_t len, int flags, caddr_t to, int tolen); } + SYS_SHUTDOWN = 134 // { int shutdown(int s, int how); } + SYS_SOCKETPAIR = 135 // { int socketpair(int domain, int type, int protocol, int *rsv); } + SYS_MKDIR = 136 // { int mkdir(char *path, int mode); } + SYS_RMDIR = 137 // { int rmdir(char *path); } + SYS_UTIMES = 138 // { int utimes(char *path, struct timeval *tptr); } + SYS_ADJTIME = 140 // { int adjtime(struct timeval *delta, struct timeval *olddelta); } + SYS_SETSID = 147 // { int setsid(void); } + SYS_QUOTACTL = 148 // { int quotactl(char *path, int cmd, int uid, caddr_t arg); } + SYS_NLM_SYSCALL = 154 // { int nlm_syscall(int debug_level, int grace_period, int addr_count, char **addrs); } + SYS_NFSSVC = 155 // { int nfssvc(int flag, caddr_t argp); } + SYS_LGETFH = 160 // { int lgetfh(char *fname, struct fhandle *fhp); } + SYS_GETFH = 161 // { int getfh(char *fname, struct fhandle *fhp); } + SYS_SYSARCH = 165 // { int sysarch(int op, char *parms); } + SYS_RTPRIO = 166 // { int rtprio(int function, pid_t pid, struct rtprio *rtp); } + SYS_SEMSYS = 169 // { int semsys(int which, int a2, int a3, int a4, int a5); } + SYS_MSGSYS = 170 // { int msgsys(int which, int a2, int a3, int a4, int a5, int a6); } + SYS_SHMSYS = 171 // { int shmsys(int which, int a2, int a3, int a4); } + SYS_FREEBSD6_PREAD = 173 // { ssize_t freebsd6_pread(int fd, void *buf, size_t nbyte, int pad, off_t offset); } + SYS_FREEBSD6_PWRITE = 174 // { ssize_t freebsd6_pwrite(int fd, const void *buf, size_t nbyte, int pad, off_t offset); } + SYS_SETFIB = 175 // { int setfib(int fibnum); } + SYS_NTP_ADJTIME = 176 // { int ntp_adjtime(struct timex *tp); } + SYS_SETGID = 181 // { int setgid(gid_t gid); } + SYS_SETEGID = 182 // { int setegid(gid_t egid); } + SYS_SETEUID = 183 // { int seteuid(uid_t euid); } + SYS_STAT = 188 // { int stat(char *path, struct stat *ub); } + SYS_FSTAT = 189 // { int fstat(int fd, struct stat *sb); } + SYS_LSTAT = 190 // { int lstat(char *path, struct stat *ub); } + SYS_PATHCONF = 191 // { int pathconf(char *path, int name); } + SYS_FPATHCONF = 192 // { int fpathconf(int fd, int name); } + SYS_GETRLIMIT = 194 // { int getrlimit(u_int which, struct rlimit *rlp); } getrlimit __getrlimit_args int + SYS_SETRLIMIT = 195 // { int setrlimit(u_int which, struct rlimit *rlp); } setrlimit __setrlimit_args int + SYS_GETDIRENTRIES = 196 // { int getdirentries(int fd, char *buf, u_int count, long *basep); } + SYS_FREEBSD6_MMAP = 197 // { caddr_t freebsd6_mmap(caddr_t addr, size_t len, int prot, int flags, int fd, int pad, off_t pos); } + SYS_FREEBSD6_LSEEK = 199 // { off_t freebsd6_lseek(int fd, int pad, off_t offset, int whence); } + SYS_FREEBSD6_TRUNCATE = 200 // { int freebsd6_truncate(char *path, int pad, off_t length); } + SYS_FREEBSD6_FTRUNCATE = 201 // { int freebsd6_ftruncate(int fd, int pad, off_t length); } + SYS___SYSCTL = 202 // { int __sysctl(int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen); } __sysctl sysctl_args int + SYS_MLOCK = 203 // { int mlock(const void *addr, size_t len); } + SYS_MUNLOCK = 204 // { int munlock(const void *addr, size_t len); } + SYS_UNDELETE = 205 // { int undelete(char *path); } + SYS_FUTIMES = 206 // { int futimes(int fd, struct timeval *tptr); } + SYS_GETPGID = 207 // { int getpgid(pid_t pid); } + SYS_POLL = 209 // { int poll(struct pollfd *fds, u_int nfds, int timeout); } + SYS_SEMGET = 221 // { int semget(key_t key, int nsems, int semflg); } + SYS_SEMOP = 222 // { int semop(int semid, struct sembuf *sops, size_t nsops); } + SYS_MSGGET = 225 // { int msgget(key_t key, int msgflg); } + SYS_MSGSND = 226 // { int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); } + SYS_MSGRCV = 227 // { int msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); } + SYS_SHMAT = 228 // { int shmat(int shmid, const void *shmaddr, int shmflg); } + SYS_SHMDT = 230 // { int shmdt(const void *shmaddr); } + SYS_SHMGET = 231 // { int shmget(key_t key, size_t size, int shmflg); } + SYS_CLOCK_GETTIME = 232 // { int clock_gettime(clockid_t clock_id, struct timespec *tp); } + SYS_CLOCK_SETTIME = 233 // { int clock_settime( clockid_t clock_id, const struct timespec *tp); } + SYS_CLOCK_GETRES = 234 // { int clock_getres(clockid_t clock_id, struct timespec *tp); } + SYS_KTIMER_CREATE = 235 // { int ktimer_create(clockid_t clock_id, struct sigevent *evp, int *timerid); } + SYS_KTIMER_DELETE = 236 // { int ktimer_delete(int timerid); } + SYS_KTIMER_SETTIME = 237 // { int ktimer_settime(int timerid, int flags, const struct itimerspec *value, struct itimerspec *ovalue); } + SYS_KTIMER_GETTIME = 238 // { int ktimer_gettime(int timerid, struct itimerspec *value); } + SYS_KTIMER_GETOVERRUN = 239 // { int ktimer_getoverrun(int timerid); } + SYS_NANOSLEEP = 240 // { int nanosleep(const struct timespec *rqtp, struct timespec *rmtp); } + SYS_FFCLOCK_GETCOUNTER = 241 // { int ffclock_getcounter(ffcounter *ffcount); } + SYS_FFCLOCK_SETESTIMATE = 242 // { int ffclock_setestimate( struct ffclock_estimate *cest); } + SYS_FFCLOCK_GETESTIMATE = 243 // { int ffclock_getestimate( struct ffclock_estimate *cest); } + SYS_CLOCK_GETCPUCLOCKID2 = 247 // { int clock_getcpuclockid2(id_t id,int which, clockid_t *clock_id); } + SYS_NTP_GETTIME = 248 // { int ntp_gettime(struct ntptimeval *ntvp); } + SYS_MINHERIT = 250 // { int minherit(void *addr, size_t len, int inherit); } + SYS_RFORK = 251 // { int rfork(int flags); } + SYS_OPENBSD_POLL = 252 // { int openbsd_poll(struct pollfd *fds, u_int nfds, int timeout); } + SYS_ISSETUGID = 253 // { int issetugid(void); } + SYS_LCHOWN = 254 // { int lchown(char *path, int uid, int gid); } + SYS_AIO_READ = 255 // { int aio_read(struct aiocb *aiocbp); } + SYS_AIO_WRITE = 256 // { int aio_write(struct aiocb *aiocbp); } + SYS_LIO_LISTIO = 257 // { int lio_listio(int mode, struct aiocb * const *acb_list, int nent, struct sigevent *sig); } + SYS_GETDENTS = 272 // { int getdents(int fd, char *buf, size_t count); } + SYS_LCHMOD = 274 // { int lchmod(char *path, mode_t mode); } + SYS_LUTIMES = 276 // { int lutimes(char *path, struct timeval *tptr); } + SYS_NSTAT = 278 // { int nstat(char *path, struct nstat *ub); } + SYS_NFSTAT = 279 // { int nfstat(int fd, struct nstat *sb); } + SYS_NLSTAT = 280 // { int nlstat(char *path, struct nstat *ub); } + SYS_PREADV = 289 // { ssize_t preadv(int fd, struct iovec *iovp, u_int iovcnt, off_t offset); } + SYS_PWRITEV = 290 // { ssize_t pwritev(int fd, struct iovec *iovp, u_int iovcnt, off_t offset); } + SYS_FHOPEN = 298 // { int fhopen(const struct fhandle *u_fhp, int flags); } + SYS_FHSTAT = 299 // { int fhstat(const struct fhandle *u_fhp, struct stat *sb); } + SYS_MODNEXT = 300 // { int modnext(int modid); } + SYS_MODSTAT = 301 // { int modstat(int modid, struct module_stat *stat); } + SYS_MODFNEXT = 302 // { int modfnext(int modid); } + SYS_MODFIND = 303 // { int modfind(const char *name); } + SYS_KLDLOAD = 304 // { int kldload(const char *file); } + SYS_KLDUNLOAD = 305 // { int kldunload(int fileid); } + SYS_KLDFIND = 306 // { int kldfind(const char *file); } + SYS_KLDNEXT = 307 // { int kldnext(int fileid); } + SYS_KLDSTAT = 308 // { int kldstat(int fileid, struct kld_file_stat* stat); } + SYS_KLDFIRSTMOD = 309 // { int kldfirstmod(int fileid); } + SYS_GETSID = 310 // { int getsid(pid_t pid); } + SYS_SETRESUID = 311 // { int setresuid(uid_t ruid, uid_t euid, uid_t suid); } + SYS_SETRESGID = 312 // { int setresgid(gid_t rgid, gid_t egid, gid_t sgid); } + SYS_AIO_RETURN = 314 // { int aio_return(struct aiocb *aiocbp); } + SYS_AIO_SUSPEND = 315 // { int aio_suspend( struct aiocb * const * aiocbp, int nent, const struct timespec *timeout); } + SYS_AIO_CANCEL = 316 // { int aio_cancel(int fd, struct aiocb *aiocbp); } + SYS_AIO_ERROR = 317 // { int aio_error(struct aiocb *aiocbp); } + SYS_OAIO_READ = 318 // { int oaio_read(struct oaiocb *aiocbp); } + SYS_OAIO_WRITE = 319 // { int oaio_write(struct oaiocb *aiocbp); } + SYS_OLIO_LISTIO = 320 // { int olio_listio(int mode, struct oaiocb * const *acb_list, int nent, struct osigevent *sig); } + SYS_YIELD = 321 // { int yield(void); } + SYS_MLOCKALL = 324 // { int mlockall(int how); } + SYS_MUNLOCKALL = 325 // { int munlockall(void); } + SYS___GETCWD = 326 // { int __getcwd(char *buf, u_int buflen); } + SYS_SCHED_SETPARAM = 327 // { int sched_setparam (pid_t pid, const struct sched_param *param); } + SYS_SCHED_GETPARAM = 328 // { int sched_getparam (pid_t pid, struct sched_param *param); } + SYS_SCHED_SETSCHEDULER = 329 // { int sched_setscheduler (pid_t pid, int policy, const struct sched_param *param); } + SYS_SCHED_GETSCHEDULER = 330 // { int sched_getscheduler (pid_t pid); } + SYS_SCHED_YIELD = 331 // { int sched_yield (void); } + SYS_SCHED_GET_PRIORITY_MAX = 332 // { int sched_get_priority_max (int policy); } + SYS_SCHED_GET_PRIORITY_MIN = 333 // { int sched_get_priority_min (int policy); } + SYS_SCHED_RR_GET_INTERVAL = 334 // { int sched_rr_get_interval (pid_t pid, struct timespec *interval); } + SYS_UTRACE = 335 // { int utrace(const void *addr, size_t len); } + SYS_KLDSYM = 337 // { int kldsym(int fileid, int cmd, void *data); } + SYS_JAIL = 338 // { int jail(struct jail *jail); } + SYS_SIGPROCMASK = 340 // { int sigprocmask(int how, const sigset_t *set, sigset_t *oset); } + SYS_SIGSUSPEND = 341 // { int sigsuspend(const sigset_t *sigmask); } + SYS_SIGPENDING = 343 // { int sigpending(sigset_t *set); } + SYS_SIGTIMEDWAIT = 345 // { int sigtimedwait(const sigset_t *set, siginfo_t *info, const struct timespec *timeout); } + SYS_SIGWAITINFO = 346 // { int sigwaitinfo(const sigset_t *set, siginfo_t *info); } + SYS___ACL_GET_FILE = 347 // { int __acl_get_file(const char *path, acl_type_t type, struct acl *aclp); } + SYS___ACL_SET_FILE = 348 // { int __acl_set_file(const char *path, acl_type_t type, struct acl *aclp); } + SYS___ACL_GET_FD = 349 // { int __acl_get_fd(int filedes, acl_type_t type, struct acl *aclp); } + SYS___ACL_SET_FD = 350 // { int __acl_set_fd(int filedes, acl_type_t type, struct acl *aclp); } + SYS___ACL_DELETE_FILE = 351 // { int __acl_delete_file(const char *path, acl_type_t type); } + SYS___ACL_DELETE_FD = 352 // { int __acl_delete_fd(int filedes, acl_type_t type); } + SYS___ACL_ACLCHECK_FILE = 353 // { int __acl_aclcheck_file(const char *path, acl_type_t type, struct acl *aclp); } + SYS___ACL_ACLCHECK_FD = 354 // { int __acl_aclcheck_fd(int filedes, acl_type_t type, struct acl *aclp); } + SYS_EXTATTRCTL = 355 // { int extattrctl(const char *path, int cmd, const char *filename, int attrnamespace, const char *attrname); } + SYS_EXTATTR_SET_FILE = 356 // { ssize_t extattr_set_file( const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes); } + SYS_EXTATTR_GET_FILE = 357 // { ssize_t extattr_get_file( const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes); } + SYS_EXTATTR_DELETE_FILE = 358 // { int extattr_delete_file(const char *path, int attrnamespace, const char *attrname); } + SYS_AIO_WAITCOMPLETE = 359 // { int aio_waitcomplete( struct aiocb **aiocbp, struct timespec *timeout); } + SYS_GETRESUID = 360 // { int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); } + SYS_GETRESGID = 361 // { int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); } + SYS_KQUEUE = 362 // { int kqueue(void); } + SYS_KEVENT = 363 // { int kevent(int fd, struct kevent *changelist, int nchanges, struct kevent *eventlist, int nevents, const struct timespec *timeout); } + SYS_EXTATTR_SET_FD = 371 // { ssize_t extattr_set_fd(int fd, int attrnamespace, const char *attrname, void *data, size_t nbytes); } + SYS_EXTATTR_GET_FD = 372 // { ssize_t extattr_get_fd(int fd, int attrnamespace, const char *attrname, void *data, size_t nbytes); } + SYS_EXTATTR_DELETE_FD = 373 // { int extattr_delete_fd(int fd, int attrnamespace, const char *attrname); } + SYS___SETUGID = 374 // { int __setugid(int flag); } + SYS_EACCESS = 376 // { int eaccess(char *path, int amode); } + SYS_NMOUNT = 378 // { int nmount(struct iovec *iovp, unsigned int iovcnt, int flags); } + SYS___MAC_GET_PROC = 384 // { int __mac_get_proc(struct mac *mac_p); } + SYS___MAC_SET_PROC = 385 // { int __mac_set_proc(struct mac *mac_p); } + SYS___MAC_GET_FD = 386 // { int __mac_get_fd(int fd, struct mac *mac_p); } + SYS___MAC_GET_FILE = 387 // { int __mac_get_file(const char *path_p, struct mac *mac_p); } + SYS___MAC_SET_FD = 388 // { int __mac_set_fd(int fd, struct mac *mac_p); } + SYS___MAC_SET_FILE = 389 // { int __mac_set_file(const char *path_p, struct mac *mac_p); } + SYS_KENV = 390 // { int kenv(int what, const char *name, char *value, int len); } + SYS_LCHFLAGS = 391 // { int lchflags(const char *path, u_long flags); } + SYS_UUIDGEN = 392 // { int uuidgen(struct uuid *store, int count); } + SYS_SENDFILE = 393 // { int sendfile(int fd, int s, off_t offset, size_t nbytes, struct sf_hdtr *hdtr, off_t *sbytes, int flags); } + SYS_MAC_SYSCALL = 394 // { int mac_syscall(const char *policy, int call, void *arg); } + SYS_GETFSSTAT = 395 // { int getfsstat(struct statfs *buf, long bufsize, int flags); } + SYS_STATFS = 396 // { int statfs(char *path, struct statfs *buf); } + SYS_FSTATFS = 397 // { int fstatfs(int fd, struct statfs *buf); } + SYS_FHSTATFS = 398 // { int fhstatfs(const struct fhandle *u_fhp, struct statfs *buf); } + SYS_KSEM_CLOSE = 400 // { int ksem_close(semid_t id); } + SYS_KSEM_POST = 401 // { int ksem_post(semid_t id); } + SYS_KSEM_WAIT = 402 // { int ksem_wait(semid_t id); } + SYS_KSEM_TRYWAIT = 403 // { int ksem_trywait(semid_t id); } + SYS_KSEM_INIT = 404 // { int ksem_init(semid_t *idp, unsigned int value); } + SYS_KSEM_OPEN = 405 // { int ksem_open(semid_t *idp, const char *name, int oflag, mode_t mode, unsigned int value); } + SYS_KSEM_UNLINK = 406 // { int ksem_unlink(const char *name); } + SYS_KSEM_GETVALUE = 407 // { int ksem_getvalue(semid_t id, int *val); } + SYS_KSEM_DESTROY = 408 // { int ksem_destroy(semid_t id); } + SYS___MAC_GET_PID = 409 // { int __mac_get_pid(pid_t pid, struct mac *mac_p); } + SYS___MAC_GET_LINK = 410 // { int __mac_get_link(const char *path_p, struct mac *mac_p); } + SYS___MAC_SET_LINK = 411 // { int __mac_set_link(const char *path_p, struct mac *mac_p); } + SYS_EXTATTR_SET_LINK = 412 // { ssize_t extattr_set_link( const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes); } + SYS_EXTATTR_GET_LINK = 413 // { ssize_t extattr_get_link( const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes); } + SYS_EXTATTR_DELETE_LINK = 414 // { int extattr_delete_link( const char *path, int attrnamespace, const char *attrname); } + SYS___MAC_EXECVE = 415 // { int __mac_execve(char *fname, char **argv, char **envv, struct mac *mac_p); } + SYS_SIGACTION = 416 // { int sigaction(int sig, const struct sigaction *act, struct sigaction *oact); } + SYS_SIGRETURN = 417 // { int sigreturn( const struct __ucontext *sigcntxp); } + SYS_GETCONTEXT = 421 // { int getcontext(struct __ucontext *ucp); } + SYS_SETCONTEXT = 422 // { int setcontext( const struct __ucontext *ucp); } + SYS_SWAPCONTEXT = 423 // { int swapcontext(struct __ucontext *oucp, const struct __ucontext *ucp); } + SYS_SWAPOFF = 424 // { int swapoff(const char *name); } + SYS___ACL_GET_LINK = 425 // { int __acl_get_link(const char *path, acl_type_t type, struct acl *aclp); } + SYS___ACL_SET_LINK = 426 // { int __acl_set_link(const char *path, acl_type_t type, struct acl *aclp); } + SYS___ACL_DELETE_LINK = 427 // { int __acl_delete_link(const char *path, acl_type_t type); } + SYS___ACL_ACLCHECK_LINK = 428 // { int __acl_aclcheck_link(const char *path, acl_type_t type, struct acl *aclp); } + SYS_SIGWAIT = 429 // { int sigwait(const sigset_t *set, int *sig); } + SYS_THR_CREATE = 430 // { int thr_create(ucontext_t *ctx, long *id, int flags); } + SYS_THR_EXIT = 431 // { void thr_exit(long *state); } + SYS_THR_SELF = 432 // { int thr_self(long *id); } + SYS_THR_KILL = 433 // { int thr_kill(long id, int sig); } + SYS__UMTX_LOCK = 434 // { int _umtx_lock(struct umtx *umtx); } + SYS__UMTX_UNLOCK = 435 // { int _umtx_unlock(struct umtx *umtx); } + SYS_JAIL_ATTACH = 436 // { int jail_attach(int jid); } + SYS_EXTATTR_LIST_FD = 437 // { ssize_t extattr_list_fd(int fd, int attrnamespace, void *data, size_t nbytes); } + SYS_EXTATTR_LIST_FILE = 438 // { ssize_t extattr_list_file( const char *path, int attrnamespace, void *data, size_t nbytes); } + SYS_EXTATTR_LIST_LINK = 439 // { ssize_t extattr_list_link( const char *path, int attrnamespace, void *data, size_t nbytes); } + SYS_KSEM_TIMEDWAIT = 441 // { int ksem_timedwait(semid_t id, const struct timespec *abstime); } + SYS_THR_SUSPEND = 442 // { int thr_suspend( const struct timespec *timeout); } + SYS_THR_WAKE = 443 // { int thr_wake(long id); } + SYS_KLDUNLOADF = 444 // { int kldunloadf(int fileid, int flags); } + SYS_AUDIT = 445 // { int audit(const void *record, u_int length); } + SYS_AUDITON = 446 // { int auditon(int cmd, void *data, u_int length); } + SYS_GETAUID = 447 // { int getauid(uid_t *auid); } + SYS_SETAUID = 448 // { int setauid(uid_t *auid); } + SYS_GETAUDIT = 449 // { int getaudit(struct auditinfo *auditinfo); } + SYS_SETAUDIT = 450 // { int setaudit(struct auditinfo *auditinfo); } + SYS_GETAUDIT_ADDR = 451 // { int getaudit_addr( struct auditinfo_addr *auditinfo_addr, u_int length); } + SYS_SETAUDIT_ADDR = 452 // { int setaudit_addr( struct auditinfo_addr *auditinfo_addr, u_int length); } + SYS_AUDITCTL = 453 // { int auditctl(char *path); } + SYS__UMTX_OP = 454 // { int _umtx_op(void *obj, int op, u_long val, void *uaddr1, void *uaddr2); } + SYS_THR_NEW = 455 // { int thr_new(struct thr_param *param, int param_size); } + SYS_SIGQUEUE = 456 // { int sigqueue(pid_t pid, int signum, void *value); } + SYS_KMQ_OPEN = 457 // { int kmq_open(const char *path, int flags, mode_t mode, const struct mq_attr *attr); } + SYS_KMQ_SETATTR = 458 // { int kmq_setattr(int mqd, const struct mq_attr *attr, struct mq_attr *oattr); } + SYS_KMQ_TIMEDRECEIVE = 459 // { int kmq_timedreceive(int mqd, char *msg_ptr, size_t msg_len, unsigned *msg_prio, const struct timespec *abs_timeout); } + SYS_KMQ_TIMEDSEND = 460 // { int kmq_timedsend(int mqd, const char *msg_ptr, size_t msg_len,unsigned msg_prio, const struct timespec *abs_timeout);} + SYS_KMQ_NOTIFY = 461 // { int kmq_notify(int mqd, const struct sigevent *sigev); } + SYS_KMQ_UNLINK = 462 // { int kmq_unlink(const char *path); } + SYS_ABORT2 = 463 // { int abort2(const char *why, int nargs, void **args); } + SYS_THR_SET_NAME = 464 // { int thr_set_name(long id, const char *name); } + SYS_AIO_FSYNC = 465 // { int aio_fsync(int op, struct aiocb *aiocbp); } + SYS_RTPRIO_THREAD = 466 // { int rtprio_thread(int function, lwpid_t lwpid, struct rtprio *rtp); } + SYS_SCTP_PEELOFF = 471 // { int sctp_peeloff(int sd, uint32_t name); } + SYS_SCTP_GENERIC_SENDMSG = 472 // { int sctp_generic_sendmsg(int sd, caddr_t msg, int mlen, caddr_t to, __socklen_t tolen, struct sctp_sndrcvinfo *sinfo, int flags); } + SYS_SCTP_GENERIC_SENDMSG_IOV = 473 // { int sctp_generic_sendmsg_iov(int sd, struct iovec *iov, int iovlen, caddr_t to, __socklen_t tolen, struct sctp_sndrcvinfo *sinfo, int flags); } + SYS_SCTP_GENERIC_RECVMSG = 474 // { int sctp_generic_recvmsg(int sd, struct iovec *iov, int iovlen, struct sockaddr * from, __socklen_t *fromlenaddr, struct sctp_sndrcvinfo *sinfo, int *msg_flags); } + SYS_PREAD = 475 // { ssize_t pread(int fd, void *buf, size_t nbyte, off_t offset); } + SYS_PWRITE = 476 // { ssize_t pwrite(int fd, const void *buf, size_t nbyte, off_t offset); } + SYS_MMAP = 477 // { caddr_t mmap(caddr_t addr, size_t len, int prot, int flags, int fd, off_t pos); } + SYS_LSEEK = 478 // { off_t lseek(int fd, off_t offset, int whence); } + SYS_TRUNCATE = 479 // { int truncate(char *path, off_t length); } + SYS_FTRUNCATE = 480 // { int ftruncate(int fd, off_t length); } + SYS_THR_KILL2 = 481 // { int thr_kill2(pid_t pid, long id, int sig); } + SYS_SHM_OPEN = 482 // { int shm_open(const char *path, int flags, mode_t mode); } + SYS_SHM_UNLINK = 483 // { int shm_unlink(const char *path); } + SYS_CPUSET = 484 // { int cpuset(cpusetid_t *setid); } + SYS_CPUSET_SETID = 485 // { int cpuset_setid(cpuwhich_t which, id_t id, cpusetid_t setid); } + SYS_CPUSET_GETID = 486 // { int cpuset_getid(cpulevel_t level, cpuwhich_t which, id_t id, cpusetid_t *setid); } + SYS_CPUSET_GETAFFINITY = 487 // { int cpuset_getaffinity(cpulevel_t level, cpuwhich_t which, id_t id, size_t cpusetsize, cpuset_t *mask); } + SYS_CPUSET_SETAFFINITY = 488 // { int cpuset_setaffinity(cpulevel_t level, cpuwhich_t which, id_t id, size_t cpusetsize, const cpuset_t *mask); } + SYS_FACCESSAT = 489 // { int faccessat(int fd, char *path, int amode, int flag); } + SYS_FCHMODAT = 490 // { int fchmodat(int fd, char *path, mode_t mode, int flag); } + SYS_FCHOWNAT = 491 // { int fchownat(int fd, char *path, uid_t uid, gid_t gid, int flag); } + SYS_FEXECVE = 492 // { int fexecve(int fd, char **argv, char **envv); } + SYS_FSTATAT = 493 // { int fstatat(int fd, char *path, struct stat *buf, int flag); } + SYS_FUTIMESAT = 494 // { int futimesat(int fd, char *path, struct timeval *times); } + SYS_LINKAT = 495 // { int linkat(int fd1, char *path1, int fd2, char *path2, int flag); } + SYS_MKDIRAT = 496 // { int mkdirat(int fd, char *path, mode_t mode); } + SYS_MKFIFOAT = 497 // { int mkfifoat(int fd, char *path, mode_t mode); } + SYS_MKNODAT = 498 // { int mknodat(int fd, char *path, mode_t mode, dev_t dev); } + SYS_OPENAT = 499 // { int openat(int fd, char *path, int flag, mode_t mode); } + SYS_READLINKAT = 500 // { int readlinkat(int fd, char *path, char *buf, size_t bufsize); } + SYS_RENAMEAT = 501 // { int renameat(int oldfd, char *old, int newfd, char *new); } + SYS_SYMLINKAT = 502 // { int symlinkat(char *path1, int fd, char *path2); } + SYS_UNLINKAT = 503 // { int unlinkat(int fd, char *path, int flag); } + SYS_POSIX_OPENPT = 504 // { int posix_openpt(int flags); } + SYS_GSSD_SYSCALL = 505 // { int gssd_syscall(char *path); } + SYS_JAIL_GET = 506 // { int jail_get(struct iovec *iovp, unsigned int iovcnt, int flags); } + SYS_JAIL_SET = 507 // { int jail_set(struct iovec *iovp, unsigned int iovcnt, int flags); } + SYS_JAIL_REMOVE = 508 // { int jail_remove(int jid); } + SYS_CLOSEFROM = 509 // { int closefrom(int lowfd); } + SYS___SEMCTL = 510 // { int __semctl(int semid, int semnum, int cmd, union semun *arg); } + SYS_MSGCTL = 511 // { int msgctl(int msqid, int cmd, struct msqid_ds *buf); } + SYS_SHMCTL = 512 // { int shmctl(int shmid, int cmd, struct shmid_ds *buf); } + SYS_LPATHCONF = 513 // { int lpathconf(char *path, int name); } + SYS___CAP_RIGHTS_GET = 515 // { int __cap_rights_get(int version, int fd, cap_rights_t *rightsp); } + SYS_CAP_ENTER = 516 // { int cap_enter(void); } + SYS_CAP_GETMODE = 517 // { int cap_getmode(u_int *modep); } + SYS_PDFORK = 518 // { int pdfork(int *fdp, int flags); } + SYS_PDKILL = 519 // { int pdkill(int fd, int signum); } + SYS_PDGETPID = 520 // { int pdgetpid(int fd, pid_t *pidp); } + SYS_PSELECT = 522 // { int pselect(int nd, fd_set *in, fd_set *ou, fd_set *ex, const struct timespec *ts, const sigset_t *sm); } + SYS_GETLOGINCLASS = 523 // { int getloginclass(char *namebuf, size_t namelen); } + SYS_SETLOGINCLASS = 524 // { int setloginclass(const char *namebuf); } + SYS_RCTL_GET_RACCT = 525 // { int rctl_get_racct(const void *inbufp, size_t inbuflen, void *outbufp, size_t outbuflen); } + SYS_RCTL_GET_RULES = 526 // { int rctl_get_rules(const void *inbufp, size_t inbuflen, void *outbufp, size_t outbuflen); } + SYS_RCTL_GET_LIMITS = 527 // { int rctl_get_limits(const void *inbufp, size_t inbuflen, void *outbufp, size_t outbuflen); } + SYS_RCTL_ADD_RULE = 528 // { int rctl_add_rule(const void *inbufp, size_t inbuflen, void *outbufp, size_t outbuflen); } + SYS_RCTL_REMOVE_RULE = 529 // { int rctl_remove_rule(const void *inbufp, size_t inbuflen, void *outbufp, size_t outbuflen); } + SYS_POSIX_FALLOCATE = 530 // { int posix_fallocate(int fd, off_t offset, off_t len); } + SYS_POSIX_FADVISE = 531 // { int posix_fadvise(int fd, off_t offset, off_t len, int advice); } + SYS_WAIT6 = 532 // { int wait6(idtype_t idtype, id_t id, int *status, int options, struct __wrusage *wrusage, siginfo_t *info); } + SYS_CAP_RIGHTS_LIMIT = 533 // { int cap_rights_limit(int fd, cap_rights_t *rightsp); } + SYS_CAP_IOCTLS_LIMIT = 534 // { int cap_ioctls_limit(int fd, const u_long *cmds, size_t ncmds); } + SYS_CAP_IOCTLS_GET = 535 // { ssize_t cap_ioctls_get(int fd, u_long *cmds, size_t maxcmds); } + SYS_CAP_FCNTLS_LIMIT = 536 // { int cap_fcntls_limit(int fd, uint32_t fcntlrights); } + SYS_CAP_FCNTLS_GET = 537 // { int cap_fcntls_get(int fd, uint32_t *fcntlrightsp); } + SYS_BINDAT = 538 // { int bindat(int fd, int s, caddr_t name, int namelen); } + SYS_CONNECTAT = 539 // { int connectat(int fd, int s, caddr_t name, int namelen); } + SYS_CHFLAGSAT = 540 // { int chflagsat(int fd, const char *path, u_long flags, int atflag); } + SYS_ACCEPT4 = 541 // { int accept4(int s, struct sockaddr * __restrict name, __socklen_t * __restrict anamelen, int flags); } + SYS_PIPE2 = 542 // { int pipe2(int *fildes, int flags); } + SYS_AIO_MLOCK = 543 // { int aio_mlock(struct aiocb *aiocbp); } + SYS_PROCCTL = 544 // { int procctl(idtype_t idtype, id_t id, int com, void *data); } + SYS_PPOLL = 545 // { int ppoll(struct pollfd *fds, u_int nfds, const struct timespec *ts, const sigset_t *set); } + SYS_FUTIMENS = 546 // { int futimens(int fd, struct timespec *times); } + SYS_UTIMENSAT = 547 // { int utimensat(int fd, char *path, struct timespec *times, int flag); } ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_freebsd_arm.go b/vendor/golang.org/x/sys/unix/zsysnum_freebsd_arm.go index 4488314181..44ffd4ce5e 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_freebsd_arm.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_freebsd_arm.go @@ -1,4 +1,4 @@ -// mksysnum_freebsd.pl +// go run mksysnum.go https://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master // Code generated by the command above; see README.md. DO NOT EDIT. // +build arm,freebsd @@ -7,347 +7,397 @@ package unix const ( // SYS_NOSYS = 0; // { int nosys(void); } syscall nosys_args int - SYS_EXIT = 1 // { void sys_exit(int rval); } exit \ - SYS_FORK = 2 // { int fork(void); } - SYS_READ = 3 // { ssize_t read(int fd, void *buf, \ - SYS_WRITE = 4 // { ssize_t write(int fd, const void *buf, \ - SYS_OPEN = 5 // { int open(char *path, int flags, int mode); } - SYS_CLOSE = 6 // { int close(int fd); } - SYS_WAIT4 = 7 // { int wait4(int pid, int *status, \ - SYS_LINK = 9 // { int link(char *path, char *link); } - SYS_UNLINK = 10 // { int unlink(char *path); } - SYS_CHDIR = 12 // { int chdir(char *path); } - SYS_FCHDIR = 13 // { int fchdir(int fd); } - SYS_MKNOD = 14 // { int mknod(char *path, int mode, int dev); } - SYS_CHMOD = 15 // { int chmod(char *path, int mode); } - SYS_CHOWN = 16 // { int chown(char *path, int uid, int gid); } - SYS_OBREAK = 17 // { int obreak(char *nsize); } break \ - SYS_GETPID = 20 // { pid_t getpid(void); } - SYS_MOUNT = 21 // { int mount(char *type, char *path, \ - SYS_UNMOUNT = 22 // { int unmount(char *path, int flags); } - SYS_SETUID = 23 // { int setuid(uid_t uid); } - SYS_GETUID = 24 // { uid_t getuid(void); } - SYS_GETEUID = 25 // { uid_t geteuid(void); } - SYS_PTRACE = 26 // { int ptrace(int req, pid_t pid, \ - SYS_RECVMSG = 27 // { int recvmsg(int s, struct msghdr *msg, \ - SYS_SENDMSG = 28 // { int sendmsg(int s, struct msghdr *msg, \ - SYS_RECVFROM = 29 // { int recvfrom(int s, caddr_t buf, \ - SYS_ACCEPT = 30 // { int accept(int s, \ - SYS_GETPEERNAME = 31 // { int getpeername(int fdes, \ - SYS_GETSOCKNAME = 32 // { int getsockname(int fdes, \ - SYS_ACCESS = 33 // { int access(char *path, int amode); } - SYS_CHFLAGS = 34 // { int chflags(const char *path, u_long flags); } - SYS_FCHFLAGS = 35 // { int fchflags(int fd, u_long flags); } - SYS_SYNC = 36 // { int sync(void); } - SYS_KILL = 37 // { int kill(int pid, int signum); } - SYS_GETPPID = 39 // { pid_t getppid(void); } - SYS_DUP = 41 // { int dup(u_int fd); } - SYS_PIPE = 42 // { int pipe(void); } - SYS_GETEGID = 43 // { gid_t getegid(void); } - SYS_PROFIL = 44 // { int profil(caddr_t samples, size_t size, \ - SYS_KTRACE = 45 // { int ktrace(const char *fname, int ops, \ - SYS_GETGID = 47 // { gid_t getgid(void); } - SYS_GETLOGIN = 49 // { int getlogin(char *namebuf, u_int \ - SYS_SETLOGIN = 50 // { int setlogin(char *namebuf); } - SYS_ACCT = 51 // { int acct(char *path); } - SYS_SIGALTSTACK = 53 // { int sigaltstack(stack_t *ss, \ - SYS_IOCTL = 54 // { int ioctl(int fd, u_long com, \ - SYS_REBOOT = 55 // { int reboot(int opt); } - SYS_REVOKE = 56 // { int revoke(char *path); } - SYS_SYMLINK = 57 // { int symlink(char *path, char *link); } - SYS_READLINK = 58 // { ssize_t readlink(char *path, char *buf, \ - SYS_EXECVE = 59 // { int execve(char *fname, char **argv, \ - SYS_UMASK = 60 // { int umask(int newmask); } umask umask_args \ - SYS_CHROOT = 61 // { int chroot(char *path); } - SYS_MSYNC = 65 // { int msync(void *addr, size_t len, \ - SYS_VFORK = 66 // { int vfork(void); } - SYS_SBRK = 69 // { int sbrk(int incr); } - SYS_SSTK = 70 // { int sstk(int incr); } - SYS_OVADVISE = 72 // { int ovadvise(int anom); } vadvise \ - SYS_MUNMAP = 73 // { int munmap(void *addr, size_t len); } - SYS_MPROTECT = 74 // { int mprotect(const void *addr, size_t len, \ - SYS_MADVISE = 75 // { int madvise(void *addr, size_t len, \ - SYS_MINCORE = 78 // { int mincore(const void *addr, size_t len, \ - SYS_GETGROUPS = 79 // { int getgroups(u_int gidsetsize, \ - SYS_SETGROUPS = 80 // { int setgroups(u_int gidsetsize, \ - SYS_GETPGRP = 81 // { int getpgrp(void); } - SYS_SETPGID = 82 // { int setpgid(int pid, int pgid); } - SYS_SETITIMER = 83 // { int setitimer(u_int which, struct \ - SYS_SWAPON = 85 // { int swapon(char *name); } - SYS_GETITIMER = 86 // { int getitimer(u_int which, \ - SYS_GETDTABLESIZE = 89 // { int getdtablesize(void); } - SYS_DUP2 = 90 // { int dup2(u_int from, u_int to); } - SYS_FCNTL = 92 // { int fcntl(int fd, int cmd, long arg); } - SYS_SELECT = 93 // { int select(int nd, fd_set *in, fd_set *ou, \ - SYS_FSYNC = 95 // { int fsync(int fd); } - SYS_SETPRIORITY = 96 // { int setpriority(int which, int who, \ - SYS_SOCKET = 97 // { int socket(int domain, int type, \ - SYS_CONNECT = 98 // { int connect(int s, caddr_t name, \ - SYS_GETPRIORITY = 100 // { int getpriority(int which, int who); } - SYS_BIND = 104 // { int bind(int s, caddr_t name, \ - SYS_SETSOCKOPT = 105 // { int setsockopt(int s, int level, int name, \ - SYS_LISTEN = 106 // { int listen(int s, int backlog); } - SYS_GETTIMEOFDAY = 116 // { int gettimeofday(struct timeval *tp, \ - SYS_GETRUSAGE = 117 // { int getrusage(int who, \ - SYS_GETSOCKOPT = 118 // { int getsockopt(int s, int level, int name, \ - SYS_READV = 120 // { int readv(int fd, struct iovec *iovp, \ - SYS_WRITEV = 121 // { int writev(int fd, struct iovec *iovp, \ - SYS_SETTIMEOFDAY = 122 // { int settimeofday(struct timeval *tv, \ - SYS_FCHOWN = 123 // { int fchown(int fd, int uid, int gid); } - SYS_FCHMOD = 124 // { int fchmod(int fd, int mode); } - SYS_SETREUID = 126 // { int setreuid(int ruid, int euid); } - SYS_SETREGID = 127 // { int setregid(int rgid, int egid); } - SYS_RENAME = 128 // { int rename(char *from, char *to); } - SYS_FLOCK = 131 // { int flock(int fd, int how); } - SYS_MKFIFO = 132 // { int mkfifo(char *path, int mode); } - SYS_SENDTO = 133 // { int sendto(int s, caddr_t buf, size_t len, \ - SYS_SHUTDOWN = 134 // { int shutdown(int s, int how); } - SYS_SOCKETPAIR = 135 // { int socketpair(int domain, int type, \ - SYS_MKDIR = 136 // { int mkdir(char *path, int mode); } - SYS_RMDIR = 137 // { int rmdir(char *path); } - SYS_UTIMES = 138 // { int utimes(char *path, \ - SYS_ADJTIME = 140 // { int adjtime(struct timeval *delta, \ - SYS_SETSID = 147 // { int setsid(void); } - SYS_QUOTACTL = 148 // { int quotactl(char *path, int cmd, int uid, \ - SYS_LGETFH = 160 // { int lgetfh(char *fname, \ - SYS_GETFH = 161 // { int getfh(char *fname, \ - SYS_SYSARCH = 165 // { int sysarch(int op, char *parms); } - SYS_RTPRIO = 166 // { int rtprio(int function, pid_t pid, \ - SYS_FREEBSD6_PREAD = 173 // { ssize_t freebsd6_pread(int fd, void *buf, \ - SYS_FREEBSD6_PWRITE = 174 // { ssize_t freebsd6_pwrite(int fd, \ - SYS_SETFIB = 175 // { int setfib(int fibnum); } - SYS_NTP_ADJTIME = 176 // { int ntp_adjtime(struct timex *tp); } - SYS_SETGID = 181 // { int setgid(gid_t gid); } - SYS_SETEGID = 182 // { int setegid(gid_t egid); } - SYS_SETEUID = 183 // { int seteuid(uid_t euid); } - SYS_STAT = 188 // { int stat(char *path, struct stat *ub); } - SYS_FSTAT = 189 // { int fstat(int fd, struct stat *sb); } - SYS_LSTAT = 190 // { int lstat(char *path, struct stat *ub); } - SYS_PATHCONF = 191 // { int pathconf(char *path, int name); } - SYS_FPATHCONF = 192 // { int fpathconf(int fd, int name); } - SYS_GETRLIMIT = 194 // { int getrlimit(u_int which, \ - SYS_SETRLIMIT = 195 // { int setrlimit(u_int which, \ - SYS_GETDIRENTRIES = 196 // { int getdirentries(int fd, char *buf, \ - SYS_FREEBSD6_MMAP = 197 // { caddr_t freebsd6_mmap(caddr_t addr, \ - SYS_FREEBSD6_LSEEK = 199 // { off_t freebsd6_lseek(int fd, int pad, \ - SYS_FREEBSD6_TRUNCATE = 200 // { int freebsd6_truncate(char *path, int pad, \ - SYS_FREEBSD6_FTRUNCATE = 201 // { int freebsd6_ftruncate(int fd, int pad, \ - SYS___SYSCTL = 202 // { int __sysctl(int *name, u_int namelen, \ - SYS_MLOCK = 203 // { int mlock(const void *addr, size_t len); } - SYS_MUNLOCK = 204 // { int munlock(const void *addr, size_t len); } - SYS_UNDELETE = 205 // { int undelete(char *path); } - SYS_FUTIMES = 206 // { int futimes(int fd, struct timeval *tptr); } - SYS_GETPGID = 207 // { int getpgid(pid_t pid); } - SYS_POLL = 209 // { int poll(struct pollfd *fds, u_int nfds, \ - SYS_CLOCK_GETTIME = 232 // { int clock_gettime(clockid_t clock_id, \ - SYS_CLOCK_SETTIME = 233 // { int clock_settime( \ - SYS_CLOCK_GETRES = 234 // { int clock_getres(clockid_t clock_id, \ - SYS_KTIMER_CREATE = 235 // { int ktimer_create(clockid_t clock_id, \ - SYS_KTIMER_DELETE = 236 // { int ktimer_delete(int timerid); } - SYS_KTIMER_SETTIME = 237 // { int ktimer_settime(int timerid, int flags, \ - SYS_KTIMER_GETTIME = 238 // { int ktimer_gettime(int timerid, struct \ - SYS_KTIMER_GETOVERRUN = 239 // { int ktimer_getoverrun(int timerid); } - SYS_NANOSLEEP = 240 // { int nanosleep(const struct timespec *rqtp, \ - SYS_FFCLOCK_GETCOUNTER = 241 // { int ffclock_getcounter(ffcounter *ffcount); } - SYS_FFCLOCK_SETESTIMATE = 242 // { int ffclock_setestimate( \ - SYS_FFCLOCK_GETESTIMATE = 243 // { int ffclock_getestimate( \ - SYS_CLOCK_GETCPUCLOCKID2 = 247 // { int clock_getcpuclockid2(id_t id,\ - SYS_NTP_GETTIME = 248 // { int ntp_gettime(struct ntptimeval *ntvp); } - SYS_MINHERIT = 250 // { int minherit(void *addr, size_t len, \ - SYS_RFORK = 251 // { int rfork(int flags); } - SYS_OPENBSD_POLL = 252 // { int openbsd_poll(struct pollfd *fds, \ - SYS_ISSETUGID = 253 // { int issetugid(void); } - SYS_LCHOWN = 254 // { int lchown(char *path, int uid, int gid); } - SYS_GETDENTS = 272 // { int getdents(int fd, char *buf, \ - SYS_LCHMOD = 274 // { int lchmod(char *path, mode_t mode); } - SYS_LUTIMES = 276 // { int lutimes(char *path, \ - SYS_NSTAT = 278 // { int nstat(char *path, struct nstat *ub); } - SYS_NFSTAT = 279 // { int nfstat(int fd, struct nstat *sb); } - SYS_NLSTAT = 280 // { int nlstat(char *path, struct nstat *ub); } - SYS_PREADV = 289 // { ssize_t preadv(int fd, struct iovec *iovp, \ - SYS_PWRITEV = 290 // { ssize_t pwritev(int fd, struct iovec *iovp, \ - SYS_FHOPEN = 298 // { int fhopen(const struct fhandle *u_fhp, \ - SYS_FHSTAT = 299 // { int fhstat(const struct fhandle *u_fhp, \ - SYS_MODNEXT = 300 // { int modnext(int modid); } - SYS_MODSTAT = 301 // { int modstat(int modid, \ - SYS_MODFNEXT = 302 // { int modfnext(int modid); } - SYS_MODFIND = 303 // { int modfind(const char *name); } - SYS_KLDLOAD = 304 // { int kldload(const char *file); } - SYS_KLDUNLOAD = 305 // { int kldunload(int fileid); } - SYS_KLDFIND = 306 // { int kldfind(const char *file); } - SYS_KLDNEXT = 307 // { int kldnext(int fileid); } - SYS_KLDSTAT = 308 // { int kldstat(int fileid, struct \ - SYS_KLDFIRSTMOD = 309 // { int kldfirstmod(int fileid); } - SYS_GETSID = 310 // { int getsid(pid_t pid); } - SYS_SETRESUID = 311 // { int setresuid(uid_t ruid, uid_t euid, \ - SYS_SETRESGID = 312 // { int setresgid(gid_t rgid, gid_t egid, \ - SYS_YIELD = 321 // { int yield(void); } - SYS_MLOCKALL = 324 // { int mlockall(int how); } - SYS_MUNLOCKALL = 325 // { int munlockall(void); } - SYS___GETCWD = 326 // { int __getcwd(char *buf, u_int buflen); } - SYS_SCHED_SETPARAM = 327 // { int sched_setparam (pid_t pid, \ - SYS_SCHED_GETPARAM = 328 // { int sched_getparam (pid_t pid, struct \ - SYS_SCHED_SETSCHEDULER = 329 // { int sched_setscheduler (pid_t pid, int \ - SYS_SCHED_GETSCHEDULER = 330 // { int sched_getscheduler (pid_t pid); } - SYS_SCHED_YIELD = 331 // { int sched_yield (void); } - SYS_SCHED_GET_PRIORITY_MAX = 332 // { int sched_get_priority_max (int policy); } - SYS_SCHED_GET_PRIORITY_MIN = 333 // { int sched_get_priority_min (int policy); } - SYS_SCHED_RR_GET_INTERVAL = 334 // { int sched_rr_get_interval (pid_t pid, \ - SYS_UTRACE = 335 // { int utrace(const void *addr, size_t len); } - SYS_KLDSYM = 337 // { int kldsym(int fileid, int cmd, \ - SYS_JAIL = 338 // { int jail(struct jail *jail); } - SYS_SIGPROCMASK = 340 // { int sigprocmask(int how, \ - SYS_SIGSUSPEND = 341 // { int sigsuspend(const sigset_t *sigmask); } - SYS_SIGPENDING = 343 // { int sigpending(sigset_t *set); } - SYS_SIGTIMEDWAIT = 345 // { int sigtimedwait(const sigset_t *set, \ - SYS_SIGWAITINFO = 346 // { int sigwaitinfo(const sigset_t *set, \ - SYS___ACL_GET_FILE = 347 // { int __acl_get_file(const char *path, \ - SYS___ACL_SET_FILE = 348 // { int __acl_set_file(const char *path, \ - SYS___ACL_GET_FD = 349 // { int __acl_get_fd(int filedes, \ - SYS___ACL_SET_FD = 350 // { int __acl_set_fd(int filedes, \ - SYS___ACL_DELETE_FILE = 351 // { int __acl_delete_file(const char *path, \ - SYS___ACL_DELETE_FD = 352 // { int __acl_delete_fd(int filedes, \ - SYS___ACL_ACLCHECK_FILE = 353 // { int __acl_aclcheck_file(const char *path, \ - SYS___ACL_ACLCHECK_FD = 354 // { int __acl_aclcheck_fd(int filedes, \ - SYS_EXTATTRCTL = 355 // { int extattrctl(const char *path, int cmd, \ - SYS_EXTATTR_SET_FILE = 356 // { ssize_t extattr_set_file( \ - SYS_EXTATTR_GET_FILE = 357 // { ssize_t extattr_get_file( \ - SYS_EXTATTR_DELETE_FILE = 358 // { int extattr_delete_file(const char *path, \ - SYS_GETRESUID = 360 // { int getresuid(uid_t *ruid, uid_t *euid, \ - SYS_GETRESGID = 361 // { int getresgid(gid_t *rgid, gid_t *egid, \ - SYS_KQUEUE = 362 // { int kqueue(void); } - SYS_KEVENT = 363 // { int kevent(int fd, \ - SYS_EXTATTR_SET_FD = 371 // { ssize_t extattr_set_fd(int fd, \ - SYS_EXTATTR_GET_FD = 372 // { ssize_t extattr_get_fd(int fd, \ - SYS_EXTATTR_DELETE_FD = 373 // { int extattr_delete_fd(int fd, \ - SYS___SETUGID = 374 // { int __setugid(int flag); } - SYS_EACCESS = 376 // { int eaccess(char *path, int amode); } - SYS_NMOUNT = 378 // { int nmount(struct iovec *iovp, \ - SYS___MAC_GET_PROC = 384 // { int __mac_get_proc(struct mac *mac_p); } - SYS___MAC_SET_PROC = 385 // { int __mac_set_proc(struct mac *mac_p); } - SYS___MAC_GET_FD = 386 // { int __mac_get_fd(int fd, \ - SYS___MAC_GET_FILE = 387 // { int __mac_get_file(const char *path_p, \ - SYS___MAC_SET_FD = 388 // { int __mac_set_fd(int fd, \ - SYS___MAC_SET_FILE = 389 // { int __mac_set_file(const char *path_p, \ - SYS_KENV = 390 // { int kenv(int what, const char *name, \ - SYS_LCHFLAGS = 391 // { int lchflags(const char *path, \ - SYS_UUIDGEN = 392 // { int uuidgen(struct uuid *store, \ - SYS_SENDFILE = 393 // { int sendfile(int fd, int s, off_t offset, \ - SYS_MAC_SYSCALL = 394 // { int mac_syscall(const char *policy, \ - SYS_GETFSSTAT = 395 // { int getfsstat(struct statfs *buf, \ - SYS_STATFS = 396 // { int statfs(char *path, \ - SYS_FSTATFS = 397 // { int fstatfs(int fd, struct statfs *buf); } - SYS_FHSTATFS = 398 // { int fhstatfs(const struct fhandle *u_fhp, \ - SYS___MAC_GET_PID = 409 // { int __mac_get_pid(pid_t pid, \ - SYS___MAC_GET_LINK = 410 // { int __mac_get_link(const char *path_p, \ - SYS___MAC_SET_LINK = 411 // { int __mac_set_link(const char *path_p, \ - SYS_EXTATTR_SET_LINK = 412 // { ssize_t extattr_set_link( \ - SYS_EXTATTR_GET_LINK = 413 // { ssize_t extattr_get_link( \ - SYS_EXTATTR_DELETE_LINK = 414 // { int extattr_delete_link( \ - SYS___MAC_EXECVE = 415 // { int __mac_execve(char *fname, char **argv, \ - SYS_SIGACTION = 416 // { int sigaction(int sig, \ - SYS_SIGRETURN = 417 // { int sigreturn( \ - SYS_GETCONTEXT = 421 // { int getcontext(struct __ucontext *ucp); } - SYS_SETCONTEXT = 422 // { int setcontext( \ - SYS_SWAPCONTEXT = 423 // { int swapcontext(struct __ucontext *oucp, \ - SYS_SWAPOFF = 424 // { int swapoff(const char *name); } - SYS___ACL_GET_LINK = 425 // { int __acl_get_link(const char *path, \ - SYS___ACL_SET_LINK = 426 // { int __acl_set_link(const char *path, \ - SYS___ACL_DELETE_LINK = 427 // { int __acl_delete_link(const char *path, \ - SYS___ACL_ACLCHECK_LINK = 428 // { int __acl_aclcheck_link(const char *path, \ - SYS_SIGWAIT = 429 // { int sigwait(const sigset_t *set, \ - SYS_THR_CREATE = 430 // { int thr_create(ucontext_t *ctx, long *id, \ - SYS_THR_EXIT = 431 // { void thr_exit(long *state); } - SYS_THR_SELF = 432 // { int thr_self(long *id); } - SYS_THR_KILL = 433 // { int thr_kill(long id, int sig); } - SYS__UMTX_LOCK = 434 // { int _umtx_lock(struct umtx *umtx); } - SYS__UMTX_UNLOCK = 435 // { int _umtx_unlock(struct umtx *umtx); } - SYS_JAIL_ATTACH = 436 // { int jail_attach(int jid); } - SYS_EXTATTR_LIST_FD = 437 // { ssize_t extattr_list_fd(int fd, \ - SYS_EXTATTR_LIST_FILE = 438 // { ssize_t extattr_list_file( \ - SYS_EXTATTR_LIST_LINK = 439 // { ssize_t extattr_list_link( \ - SYS_THR_SUSPEND = 442 // { int thr_suspend( \ - SYS_THR_WAKE = 443 // { int thr_wake(long id); } - SYS_KLDUNLOADF = 444 // { int kldunloadf(int fileid, int flags); } - SYS_AUDIT = 445 // { int audit(const void *record, \ - SYS_AUDITON = 446 // { int auditon(int cmd, void *data, \ - SYS_GETAUID = 447 // { int getauid(uid_t *auid); } - SYS_SETAUID = 448 // { int setauid(uid_t *auid); } - SYS_GETAUDIT = 449 // { int getaudit(struct auditinfo *auditinfo); } - SYS_SETAUDIT = 450 // { int setaudit(struct auditinfo *auditinfo); } - SYS_GETAUDIT_ADDR = 451 // { int getaudit_addr( \ - SYS_SETAUDIT_ADDR = 452 // { int setaudit_addr( \ - SYS_AUDITCTL = 453 // { int auditctl(char *path); } - SYS__UMTX_OP = 454 // { int _umtx_op(void *obj, int op, \ - SYS_THR_NEW = 455 // { int thr_new(struct thr_param *param, \ - SYS_SIGQUEUE = 456 // { int sigqueue(pid_t pid, int signum, void *value); } - SYS_ABORT2 = 463 // { int abort2(const char *why, int nargs, void **args); } - SYS_THR_SET_NAME = 464 // { int thr_set_name(long id, const char *name); } - SYS_RTPRIO_THREAD = 466 // { int rtprio_thread(int function, \ - SYS_PREAD = 475 // { ssize_t pread(int fd, void *buf, \ - SYS_PWRITE = 476 // { ssize_t pwrite(int fd, const void *buf, \ - SYS_MMAP = 477 // { caddr_t mmap(caddr_t addr, size_t len, \ - SYS_LSEEK = 478 // { off_t lseek(int fd, off_t offset, \ - SYS_TRUNCATE = 479 // { int truncate(char *path, off_t length); } - SYS_FTRUNCATE = 480 // { int ftruncate(int fd, off_t length); } - SYS_THR_KILL2 = 481 // { int thr_kill2(pid_t pid, long id, int sig); } - SYS_SHM_OPEN = 482 // { int shm_open(const char *path, int flags, \ - SYS_SHM_UNLINK = 483 // { int shm_unlink(const char *path); } - SYS_CPUSET = 484 // { int cpuset(cpusetid_t *setid); } - SYS_CPUSET_SETID = 485 // { int cpuset_setid(cpuwhich_t which, id_t id, \ - SYS_CPUSET_GETID = 486 // { int cpuset_getid(cpulevel_t level, \ - SYS_CPUSET_GETAFFINITY = 487 // { int cpuset_getaffinity(cpulevel_t level, \ - SYS_CPUSET_SETAFFINITY = 488 // { int cpuset_setaffinity(cpulevel_t level, \ - SYS_FACCESSAT = 489 // { int faccessat(int fd, char *path, int amode, \ - SYS_FCHMODAT = 490 // { int fchmodat(int fd, char *path, mode_t mode, \ - SYS_FCHOWNAT = 491 // { int fchownat(int fd, char *path, uid_t uid, \ - SYS_FEXECVE = 492 // { int fexecve(int fd, char **argv, \ - SYS_FSTATAT = 493 // { int fstatat(int fd, char *path, \ - SYS_FUTIMESAT = 494 // { int futimesat(int fd, char *path, \ - SYS_LINKAT = 495 // { int linkat(int fd1, char *path1, int fd2, \ - SYS_MKDIRAT = 496 // { int mkdirat(int fd, char *path, mode_t mode); } - SYS_MKFIFOAT = 497 // { int mkfifoat(int fd, char *path, mode_t mode); } - SYS_MKNODAT = 498 // { int mknodat(int fd, char *path, mode_t mode, \ - SYS_OPENAT = 499 // { int openat(int fd, char *path, int flag, \ - SYS_READLINKAT = 500 // { int readlinkat(int fd, char *path, char *buf, \ - SYS_RENAMEAT = 501 // { int renameat(int oldfd, char *old, int newfd, \ - SYS_SYMLINKAT = 502 // { int symlinkat(char *path1, int fd, \ - SYS_UNLINKAT = 503 // { int unlinkat(int fd, char *path, int flag); } - SYS_POSIX_OPENPT = 504 // { int posix_openpt(int flags); } - SYS_JAIL_GET = 506 // { int jail_get(struct iovec *iovp, \ - SYS_JAIL_SET = 507 // { int jail_set(struct iovec *iovp, \ - SYS_JAIL_REMOVE = 508 // { int jail_remove(int jid); } - SYS_CLOSEFROM = 509 // { int closefrom(int lowfd); } - SYS_LPATHCONF = 513 // { int lpathconf(char *path, int name); } - SYS___CAP_RIGHTS_GET = 515 // { int __cap_rights_get(int version, \ - SYS_CAP_ENTER = 516 // { int cap_enter(void); } - SYS_CAP_GETMODE = 517 // { int cap_getmode(u_int *modep); } - SYS_PDFORK = 518 // { int pdfork(int *fdp, int flags); } - SYS_PDKILL = 519 // { int pdkill(int fd, int signum); } - SYS_PDGETPID = 520 // { int pdgetpid(int fd, pid_t *pidp); } - SYS_PSELECT = 522 // { int pselect(int nd, fd_set *in, \ - SYS_GETLOGINCLASS = 523 // { int getloginclass(char *namebuf, \ - SYS_SETLOGINCLASS = 524 // { int setloginclass(const char *namebuf); } - SYS_RCTL_GET_RACCT = 525 // { int rctl_get_racct(const void *inbufp, \ - SYS_RCTL_GET_RULES = 526 // { int rctl_get_rules(const void *inbufp, \ - SYS_RCTL_GET_LIMITS = 527 // { int rctl_get_limits(const void *inbufp, \ - SYS_RCTL_ADD_RULE = 528 // { int rctl_add_rule(const void *inbufp, \ - SYS_RCTL_REMOVE_RULE = 529 // { int rctl_remove_rule(const void *inbufp, \ - SYS_POSIX_FALLOCATE = 530 // { int posix_fallocate(int fd, \ - SYS_POSIX_FADVISE = 531 // { int posix_fadvise(int fd, off_t offset, \ - SYS_WAIT6 = 532 // { int wait6(idtype_t idtype, id_t id, \ - SYS_CAP_RIGHTS_LIMIT = 533 // { int cap_rights_limit(int fd, \ - SYS_CAP_IOCTLS_LIMIT = 534 // { int cap_ioctls_limit(int fd, \ - SYS_CAP_IOCTLS_GET = 535 // { ssize_t cap_ioctls_get(int fd, \ - SYS_CAP_FCNTLS_LIMIT = 536 // { int cap_fcntls_limit(int fd, \ - SYS_CAP_FCNTLS_GET = 537 // { int cap_fcntls_get(int fd, \ - SYS_BINDAT = 538 // { int bindat(int fd, int s, caddr_t name, \ - SYS_CONNECTAT = 539 // { int connectat(int fd, int s, caddr_t name, \ - SYS_CHFLAGSAT = 540 // { int chflagsat(int fd, const char *path, \ - SYS_ACCEPT4 = 541 // { int accept4(int s, \ - SYS_PIPE2 = 542 // { int pipe2(int *fildes, int flags); } - SYS_PROCCTL = 544 // { int procctl(idtype_t idtype, id_t id, \ - SYS_PPOLL = 545 // { int ppoll(struct pollfd *fds, u_int nfds, \ - SYS_FUTIMENS = 546 // { int futimens(int fd, \ - SYS_UTIMENSAT = 547 // { int utimensat(int fd, \ + SYS_EXIT = 1 // { void sys_exit(int rval); } exit sys_exit_args void + SYS_FORK = 2 // { int fork(void); } + SYS_READ = 3 // { ssize_t read(int fd, void *buf, size_t nbyte); } + SYS_WRITE = 4 // { ssize_t write(int fd, const void *buf, size_t nbyte); } + SYS_OPEN = 5 // { int open(char *path, int flags, int mode); } + SYS_CLOSE = 6 // { int close(int fd); } + SYS_WAIT4 = 7 // { int wait4(int pid, int *status, int options, struct rusage *rusage); } + SYS_LINK = 9 // { int link(char *path, char *link); } + SYS_UNLINK = 10 // { int unlink(char *path); } + SYS_CHDIR = 12 // { int chdir(char *path); } + SYS_FCHDIR = 13 // { int fchdir(int fd); } + SYS_MKNOD = 14 // { int mknod(char *path, int mode, int dev); } + SYS_CHMOD = 15 // { int chmod(char *path, int mode); } + SYS_CHOWN = 16 // { int chown(char *path, int uid, int gid); } + SYS_OBREAK = 17 // { int obreak(char *nsize); } break obreak_args int + SYS_GETPID = 20 // { pid_t getpid(void); } + SYS_MOUNT = 21 // { int mount(char *type, char *path, int flags, caddr_t data); } + SYS_UNMOUNT = 22 // { int unmount(char *path, int flags); } + SYS_SETUID = 23 // { int setuid(uid_t uid); } + SYS_GETUID = 24 // { uid_t getuid(void); } + SYS_GETEUID = 25 // { uid_t geteuid(void); } + SYS_PTRACE = 26 // { int ptrace(int req, pid_t pid, caddr_t addr, int data); } + SYS_RECVMSG = 27 // { int recvmsg(int s, struct msghdr *msg, int flags); } + SYS_SENDMSG = 28 // { int sendmsg(int s, struct msghdr *msg, int flags); } + SYS_RECVFROM = 29 // { int recvfrom(int s, caddr_t buf, size_t len, int flags, struct sockaddr * __restrict from, __socklen_t * __restrict fromlenaddr); } + SYS_ACCEPT = 30 // { int accept(int s, struct sockaddr * __restrict name, __socklen_t * __restrict anamelen); } + SYS_GETPEERNAME = 31 // { int getpeername(int fdes, struct sockaddr * __restrict asa, __socklen_t * __restrict alen); } + SYS_GETSOCKNAME = 32 // { int getsockname(int fdes, struct sockaddr * __restrict asa, __socklen_t * __restrict alen); } + SYS_ACCESS = 33 // { int access(char *path, int amode); } + SYS_CHFLAGS = 34 // { int chflags(const char *path, u_long flags); } + SYS_FCHFLAGS = 35 // { int fchflags(int fd, u_long flags); } + SYS_SYNC = 36 // { int sync(void); } + SYS_KILL = 37 // { int kill(int pid, int signum); } + SYS_GETPPID = 39 // { pid_t getppid(void); } + SYS_DUP = 41 // { int dup(u_int fd); } + SYS_PIPE = 42 // { int pipe(void); } + SYS_GETEGID = 43 // { gid_t getegid(void); } + SYS_PROFIL = 44 // { int profil(caddr_t samples, size_t size, size_t offset, u_int scale); } + SYS_KTRACE = 45 // { int ktrace(const char *fname, int ops, int facs, int pid); } + SYS_GETGID = 47 // { gid_t getgid(void); } + SYS_GETLOGIN = 49 // { int getlogin(char *namebuf, u_int namelen); } + SYS_SETLOGIN = 50 // { int setlogin(char *namebuf); } + SYS_ACCT = 51 // { int acct(char *path); } + SYS_SIGALTSTACK = 53 // { int sigaltstack(stack_t *ss, stack_t *oss); } + SYS_IOCTL = 54 // { int ioctl(int fd, u_long com, caddr_t data); } + SYS_REBOOT = 55 // { int reboot(int opt); } + SYS_REVOKE = 56 // { int revoke(char *path); } + SYS_SYMLINK = 57 // { int symlink(char *path, char *link); } + SYS_READLINK = 58 // { ssize_t readlink(char *path, char *buf, size_t count); } + SYS_EXECVE = 59 // { int execve(char *fname, char **argv, char **envv); } + SYS_UMASK = 60 // { int umask(int newmask); } umask umask_args int + SYS_CHROOT = 61 // { int chroot(char *path); } + SYS_MSYNC = 65 // { int msync(void *addr, size_t len, int flags); } + SYS_VFORK = 66 // { int vfork(void); } + SYS_SBRK = 69 // { int sbrk(int incr); } + SYS_SSTK = 70 // { int sstk(int incr); } + SYS_OVADVISE = 72 // { int ovadvise(int anom); } vadvise ovadvise_args int + SYS_MUNMAP = 73 // { int munmap(void *addr, size_t len); } + SYS_MPROTECT = 74 // { int mprotect(const void *addr, size_t len, int prot); } + SYS_MADVISE = 75 // { int madvise(void *addr, size_t len, int behav); } + SYS_MINCORE = 78 // { int mincore(const void *addr, size_t len, char *vec); } + SYS_GETGROUPS = 79 // { int getgroups(u_int gidsetsize, gid_t *gidset); } + SYS_SETGROUPS = 80 // { int setgroups(u_int gidsetsize, gid_t *gidset); } + SYS_GETPGRP = 81 // { int getpgrp(void); } + SYS_SETPGID = 82 // { int setpgid(int pid, int pgid); } + SYS_SETITIMER = 83 // { int setitimer(u_int which, struct itimerval *itv, struct itimerval *oitv); } + SYS_SWAPON = 85 // { int swapon(char *name); } + SYS_GETITIMER = 86 // { int getitimer(u_int which, struct itimerval *itv); } + SYS_GETDTABLESIZE = 89 // { int getdtablesize(void); } + SYS_DUP2 = 90 // { int dup2(u_int from, u_int to); } + SYS_FCNTL = 92 // { int fcntl(int fd, int cmd, long arg); } + SYS_SELECT = 93 // { int select(int nd, fd_set *in, fd_set *ou, fd_set *ex, struct timeval *tv); } + SYS_FSYNC = 95 // { int fsync(int fd); } + SYS_SETPRIORITY = 96 // { int setpriority(int which, int who, int prio); } + SYS_SOCKET = 97 // { int socket(int domain, int type, int protocol); } + SYS_CONNECT = 98 // { int connect(int s, caddr_t name, int namelen); } + SYS_GETPRIORITY = 100 // { int getpriority(int which, int who); } + SYS_BIND = 104 // { int bind(int s, caddr_t name, int namelen); } + SYS_SETSOCKOPT = 105 // { int setsockopt(int s, int level, int name, caddr_t val, int valsize); } + SYS_LISTEN = 106 // { int listen(int s, int backlog); } + SYS_GETTIMEOFDAY = 116 // { int gettimeofday(struct timeval *tp, struct timezone *tzp); } + SYS_GETRUSAGE = 117 // { int getrusage(int who, struct rusage *rusage); } + SYS_GETSOCKOPT = 118 // { int getsockopt(int s, int level, int name, caddr_t val, int *avalsize); } + SYS_READV = 120 // { int readv(int fd, struct iovec *iovp, u_int iovcnt); } + SYS_WRITEV = 121 // { int writev(int fd, struct iovec *iovp, u_int iovcnt); } + SYS_SETTIMEOFDAY = 122 // { int settimeofday(struct timeval *tv, struct timezone *tzp); } + SYS_FCHOWN = 123 // { int fchown(int fd, int uid, int gid); } + SYS_FCHMOD = 124 // { int fchmod(int fd, int mode); } + SYS_SETREUID = 126 // { int setreuid(int ruid, int euid); } + SYS_SETREGID = 127 // { int setregid(int rgid, int egid); } + SYS_RENAME = 128 // { int rename(char *from, char *to); } + SYS_FLOCK = 131 // { int flock(int fd, int how); } + SYS_MKFIFO = 132 // { int mkfifo(char *path, int mode); } + SYS_SENDTO = 133 // { int sendto(int s, caddr_t buf, size_t len, int flags, caddr_t to, int tolen); } + SYS_SHUTDOWN = 134 // { int shutdown(int s, int how); } + SYS_SOCKETPAIR = 135 // { int socketpair(int domain, int type, int protocol, int *rsv); } + SYS_MKDIR = 136 // { int mkdir(char *path, int mode); } + SYS_RMDIR = 137 // { int rmdir(char *path); } + SYS_UTIMES = 138 // { int utimes(char *path, struct timeval *tptr); } + SYS_ADJTIME = 140 // { int adjtime(struct timeval *delta, struct timeval *olddelta); } + SYS_SETSID = 147 // { int setsid(void); } + SYS_QUOTACTL = 148 // { int quotactl(char *path, int cmd, int uid, caddr_t arg); } + SYS_NLM_SYSCALL = 154 // { int nlm_syscall(int debug_level, int grace_period, int addr_count, char **addrs); } + SYS_NFSSVC = 155 // { int nfssvc(int flag, caddr_t argp); } + SYS_LGETFH = 160 // { int lgetfh(char *fname, struct fhandle *fhp); } + SYS_GETFH = 161 // { int getfh(char *fname, struct fhandle *fhp); } + SYS_SYSARCH = 165 // { int sysarch(int op, char *parms); } + SYS_RTPRIO = 166 // { int rtprio(int function, pid_t pid, struct rtprio *rtp); } + SYS_SEMSYS = 169 // { int semsys(int which, int a2, int a3, int a4, int a5); } + SYS_MSGSYS = 170 // { int msgsys(int which, int a2, int a3, int a4, int a5, int a6); } + SYS_SHMSYS = 171 // { int shmsys(int which, int a2, int a3, int a4); } + SYS_FREEBSD6_PREAD = 173 // { ssize_t freebsd6_pread(int fd, void *buf, size_t nbyte, int pad, off_t offset); } + SYS_FREEBSD6_PWRITE = 174 // { ssize_t freebsd6_pwrite(int fd, const void *buf, size_t nbyte, int pad, off_t offset); } + SYS_SETFIB = 175 // { int setfib(int fibnum); } + SYS_NTP_ADJTIME = 176 // { int ntp_adjtime(struct timex *tp); } + SYS_SETGID = 181 // { int setgid(gid_t gid); } + SYS_SETEGID = 182 // { int setegid(gid_t egid); } + SYS_SETEUID = 183 // { int seteuid(uid_t euid); } + SYS_STAT = 188 // { int stat(char *path, struct stat *ub); } + SYS_FSTAT = 189 // { int fstat(int fd, struct stat *sb); } + SYS_LSTAT = 190 // { int lstat(char *path, struct stat *ub); } + SYS_PATHCONF = 191 // { int pathconf(char *path, int name); } + SYS_FPATHCONF = 192 // { int fpathconf(int fd, int name); } + SYS_GETRLIMIT = 194 // { int getrlimit(u_int which, struct rlimit *rlp); } getrlimit __getrlimit_args int + SYS_SETRLIMIT = 195 // { int setrlimit(u_int which, struct rlimit *rlp); } setrlimit __setrlimit_args int + SYS_GETDIRENTRIES = 196 // { int getdirentries(int fd, char *buf, u_int count, long *basep); } + SYS_FREEBSD6_MMAP = 197 // { caddr_t freebsd6_mmap(caddr_t addr, size_t len, int prot, int flags, int fd, int pad, off_t pos); } + SYS_FREEBSD6_LSEEK = 199 // { off_t freebsd6_lseek(int fd, int pad, off_t offset, int whence); } + SYS_FREEBSD6_TRUNCATE = 200 // { int freebsd6_truncate(char *path, int pad, off_t length); } + SYS_FREEBSD6_FTRUNCATE = 201 // { int freebsd6_ftruncate(int fd, int pad, off_t length); } + SYS___SYSCTL = 202 // { int __sysctl(int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen); } __sysctl sysctl_args int + SYS_MLOCK = 203 // { int mlock(const void *addr, size_t len); } + SYS_MUNLOCK = 204 // { int munlock(const void *addr, size_t len); } + SYS_UNDELETE = 205 // { int undelete(char *path); } + SYS_FUTIMES = 206 // { int futimes(int fd, struct timeval *tptr); } + SYS_GETPGID = 207 // { int getpgid(pid_t pid); } + SYS_POLL = 209 // { int poll(struct pollfd *fds, u_int nfds, int timeout); } + SYS_SEMGET = 221 // { int semget(key_t key, int nsems, int semflg); } + SYS_SEMOP = 222 // { int semop(int semid, struct sembuf *sops, size_t nsops); } + SYS_MSGGET = 225 // { int msgget(key_t key, int msgflg); } + SYS_MSGSND = 226 // { int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); } + SYS_MSGRCV = 227 // { int msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); } + SYS_SHMAT = 228 // { int shmat(int shmid, const void *shmaddr, int shmflg); } + SYS_SHMDT = 230 // { int shmdt(const void *shmaddr); } + SYS_SHMGET = 231 // { int shmget(key_t key, size_t size, int shmflg); } + SYS_CLOCK_GETTIME = 232 // { int clock_gettime(clockid_t clock_id, struct timespec *tp); } + SYS_CLOCK_SETTIME = 233 // { int clock_settime( clockid_t clock_id, const struct timespec *tp); } + SYS_CLOCK_GETRES = 234 // { int clock_getres(clockid_t clock_id, struct timespec *tp); } + SYS_KTIMER_CREATE = 235 // { int ktimer_create(clockid_t clock_id, struct sigevent *evp, int *timerid); } + SYS_KTIMER_DELETE = 236 // { int ktimer_delete(int timerid); } + SYS_KTIMER_SETTIME = 237 // { int ktimer_settime(int timerid, int flags, const struct itimerspec *value, struct itimerspec *ovalue); } + SYS_KTIMER_GETTIME = 238 // { int ktimer_gettime(int timerid, struct itimerspec *value); } + SYS_KTIMER_GETOVERRUN = 239 // { int ktimer_getoverrun(int timerid); } + SYS_NANOSLEEP = 240 // { int nanosleep(const struct timespec *rqtp, struct timespec *rmtp); } + SYS_FFCLOCK_GETCOUNTER = 241 // { int ffclock_getcounter(ffcounter *ffcount); } + SYS_FFCLOCK_SETESTIMATE = 242 // { int ffclock_setestimate( struct ffclock_estimate *cest); } + SYS_FFCLOCK_GETESTIMATE = 243 // { int ffclock_getestimate( struct ffclock_estimate *cest); } + SYS_CLOCK_GETCPUCLOCKID2 = 247 // { int clock_getcpuclockid2(id_t id,int which, clockid_t *clock_id); } + SYS_NTP_GETTIME = 248 // { int ntp_gettime(struct ntptimeval *ntvp); } + SYS_MINHERIT = 250 // { int minherit(void *addr, size_t len, int inherit); } + SYS_RFORK = 251 // { int rfork(int flags); } + SYS_OPENBSD_POLL = 252 // { int openbsd_poll(struct pollfd *fds, u_int nfds, int timeout); } + SYS_ISSETUGID = 253 // { int issetugid(void); } + SYS_LCHOWN = 254 // { int lchown(char *path, int uid, int gid); } + SYS_AIO_READ = 255 // { int aio_read(struct aiocb *aiocbp); } + SYS_AIO_WRITE = 256 // { int aio_write(struct aiocb *aiocbp); } + SYS_LIO_LISTIO = 257 // { int lio_listio(int mode, struct aiocb * const *acb_list, int nent, struct sigevent *sig); } + SYS_GETDENTS = 272 // { int getdents(int fd, char *buf, size_t count); } + SYS_LCHMOD = 274 // { int lchmod(char *path, mode_t mode); } + SYS_LUTIMES = 276 // { int lutimes(char *path, struct timeval *tptr); } + SYS_NSTAT = 278 // { int nstat(char *path, struct nstat *ub); } + SYS_NFSTAT = 279 // { int nfstat(int fd, struct nstat *sb); } + SYS_NLSTAT = 280 // { int nlstat(char *path, struct nstat *ub); } + SYS_PREADV = 289 // { ssize_t preadv(int fd, struct iovec *iovp, u_int iovcnt, off_t offset); } + SYS_PWRITEV = 290 // { ssize_t pwritev(int fd, struct iovec *iovp, u_int iovcnt, off_t offset); } + SYS_FHOPEN = 298 // { int fhopen(const struct fhandle *u_fhp, int flags); } + SYS_FHSTAT = 299 // { int fhstat(const struct fhandle *u_fhp, struct stat *sb); } + SYS_MODNEXT = 300 // { int modnext(int modid); } + SYS_MODSTAT = 301 // { int modstat(int modid, struct module_stat *stat); } + SYS_MODFNEXT = 302 // { int modfnext(int modid); } + SYS_MODFIND = 303 // { int modfind(const char *name); } + SYS_KLDLOAD = 304 // { int kldload(const char *file); } + SYS_KLDUNLOAD = 305 // { int kldunload(int fileid); } + SYS_KLDFIND = 306 // { int kldfind(const char *file); } + SYS_KLDNEXT = 307 // { int kldnext(int fileid); } + SYS_KLDSTAT = 308 // { int kldstat(int fileid, struct kld_file_stat* stat); } + SYS_KLDFIRSTMOD = 309 // { int kldfirstmod(int fileid); } + SYS_GETSID = 310 // { int getsid(pid_t pid); } + SYS_SETRESUID = 311 // { int setresuid(uid_t ruid, uid_t euid, uid_t suid); } + SYS_SETRESGID = 312 // { int setresgid(gid_t rgid, gid_t egid, gid_t sgid); } + SYS_AIO_RETURN = 314 // { int aio_return(struct aiocb *aiocbp); } + SYS_AIO_SUSPEND = 315 // { int aio_suspend( struct aiocb * const * aiocbp, int nent, const struct timespec *timeout); } + SYS_AIO_CANCEL = 316 // { int aio_cancel(int fd, struct aiocb *aiocbp); } + SYS_AIO_ERROR = 317 // { int aio_error(struct aiocb *aiocbp); } + SYS_OAIO_READ = 318 // { int oaio_read(struct oaiocb *aiocbp); } + SYS_OAIO_WRITE = 319 // { int oaio_write(struct oaiocb *aiocbp); } + SYS_OLIO_LISTIO = 320 // { int olio_listio(int mode, struct oaiocb * const *acb_list, int nent, struct osigevent *sig); } + SYS_YIELD = 321 // { int yield(void); } + SYS_MLOCKALL = 324 // { int mlockall(int how); } + SYS_MUNLOCKALL = 325 // { int munlockall(void); } + SYS___GETCWD = 326 // { int __getcwd(char *buf, u_int buflen); } + SYS_SCHED_SETPARAM = 327 // { int sched_setparam (pid_t pid, const struct sched_param *param); } + SYS_SCHED_GETPARAM = 328 // { int sched_getparam (pid_t pid, struct sched_param *param); } + SYS_SCHED_SETSCHEDULER = 329 // { int sched_setscheduler (pid_t pid, int policy, const struct sched_param *param); } + SYS_SCHED_GETSCHEDULER = 330 // { int sched_getscheduler (pid_t pid); } + SYS_SCHED_YIELD = 331 // { int sched_yield (void); } + SYS_SCHED_GET_PRIORITY_MAX = 332 // { int sched_get_priority_max (int policy); } + SYS_SCHED_GET_PRIORITY_MIN = 333 // { int sched_get_priority_min (int policy); } + SYS_SCHED_RR_GET_INTERVAL = 334 // { int sched_rr_get_interval (pid_t pid, struct timespec *interval); } + SYS_UTRACE = 335 // { int utrace(const void *addr, size_t len); } + SYS_KLDSYM = 337 // { int kldsym(int fileid, int cmd, void *data); } + SYS_JAIL = 338 // { int jail(struct jail *jail); } + SYS_SIGPROCMASK = 340 // { int sigprocmask(int how, const sigset_t *set, sigset_t *oset); } + SYS_SIGSUSPEND = 341 // { int sigsuspend(const sigset_t *sigmask); } + SYS_SIGPENDING = 343 // { int sigpending(sigset_t *set); } + SYS_SIGTIMEDWAIT = 345 // { int sigtimedwait(const sigset_t *set, siginfo_t *info, const struct timespec *timeout); } + SYS_SIGWAITINFO = 346 // { int sigwaitinfo(const sigset_t *set, siginfo_t *info); } + SYS___ACL_GET_FILE = 347 // { int __acl_get_file(const char *path, acl_type_t type, struct acl *aclp); } + SYS___ACL_SET_FILE = 348 // { int __acl_set_file(const char *path, acl_type_t type, struct acl *aclp); } + SYS___ACL_GET_FD = 349 // { int __acl_get_fd(int filedes, acl_type_t type, struct acl *aclp); } + SYS___ACL_SET_FD = 350 // { int __acl_set_fd(int filedes, acl_type_t type, struct acl *aclp); } + SYS___ACL_DELETE_FILE = 351 // { int __acl_delete_file(const char *path, acl_type_t type); } + SYS___ACL_DELETE_FD = 352 // { int __acl_delete_fd(int filedes, acl_type_t type); } + SYS___ACL_ACLCHECK_FILE = 353 // { int __acl_aclcheck_file(const char *path, acl_type_t type, struct acl *aclp); } + SYS___ACL_ACLCHECK_FD = 354 // { int __acl_aclcheck_fd(int filedes, acl_type_t type, struct acl *aclp); } + SYS_EXTATTRCTL = 355 // { int extattrctl(const char *path, int cmd, const char *filename, int attrnamespace, const char *attrname); } + SYS_EXTATTR_SET_FILE = 356 // { ssize_t extattr_set_file( const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes); } + SYS_EXTATTR_GET_FILE = 357 // { ssize_t extattr_get_file( const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes); } + SYS_EXTATTR_DELETE_FILE = 358 // { int extattr_delete_file(const char *path, int attrnamespace, const char *attrname); } + SYS_AIO_WAITCOMPLETE = 359 // { int aio_waitcomplete( struct aiocb **aiocbp, struct timespec *timeout); } + SYS_GETRESUID = 360 // { int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); } + SYS_GETRESGID = 361 // { int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); } + SYS_KQUEUE = 362 // { int kqueue(void); } + SYS_KEVENT = 363 // { int kevent(int fd, struct kevent *changelist, int nchanges, struct kevent *eventlist, int nevents, const struct timespec *timeout); } + SYS_EXTATTR_SET_FD = 371 // { ssize_t extattr_set_fd(int fd, int attrnamespace, const char *attrname, void *data, size_t nbytes); } + SYS_EXTATTR_GET_FD = 372 // { ssize_t extattr_get_fd(int fd, int attrnamespace, const char *attrname, void *data, size_t nbytes); } + SYS_EXTATTR_DELETE_FD = 373 // { int extattr_delete_fd(int fd, int attrnamespace, const char *attrname); } + SYS___SETUGID = 374 // { int __setugid(int flag); } + SYS_EACCESS = 376 // { int eaccess(char *path, int amode); } + SYS_NMOUNT = 378 // { int nmount(struct iovec *iovp, unsigned int iovcnt, int flags); } + SYS___MAC_GET_PROC = 384 // { int __mac_get_proc(struct mac *mac_p); } + SYS___MAC_SET_PROC = 385 // { int __mac_set_proc(struct mac *mac_p); } + SYS___MAC_GET_FD = 386 // { int __mac_get_fd(int fd, struct mac *mac_p); } + SYS___MAC_GET_FILE = 387 // { int __mac_get_file(const char *path_p, struct mac *mac_p); } + SYS___MAC_SET_FD = 388 // { int __mac_set_fd(int fd, struct mac *mac_p); } + SYS___MAC_SET_FILE = 389 // { int __mac_set_file(const char *path_p, struct mac *mac_p); } + SYS_KENV = 390 // { int kenv(int what, const char *name, char *value, int len); } + SYS_LCHFLAGS = 391 // { int lchflags(const char *path, u_long flags); } + SYS_UUIDGEN = 392 // { int uuidgen(struct uuid *store, int count); } + SYS_SENDFILE = 393 // { int sendfile(int fd, int s, off_t offset, size_t nbytes, struct sf_hdtr *hdtr, off_t *sbytes, int flags); } + SYS_MAC_SYSCALL = 394 // { int mac_syscall(const char *policy, int call, void *arg); } + SYS_GETFSSTAT = 395 // { int getfsstat(struct statfs *buf, long bufsize, int flags); } + SYS_STATFS = 396 // { int statfs(char *path, struct statfs *buf); } + SYS_FSTATFS = 397 // { int fstatfs(int fd, struct statfs *buf); } + SYS_FHSTATFS = 398 // { int fhstatfs(const struct fhandle *u_fhp, struct statfs *buf); } + SYS_KSEM_CLOSE = 400 // { int ksem_close(semid_t id); } + SYS_KSEM_POST = 401 // { int ksem_post(semid_t id); } + SYS_KSEM_WAIT = 402 // { int ksem_wait(semid_t id); } + SYS_KSEM_TRYWAIT = 403 // { int ksem_trywait(semid_t id); } + SYS_KSEM_INIT = 404 // { int ksem_init(semid_t *idp, unsigned int value); } + SYS_KSEM_OPEN = 405 // { int ksem_open(semid_t *idp, const char *name, int oflag, mode_t mode, unsigned int value); } + SYS_KSEM_UNLINK = 406 // { int ksem_unlink(const char *name); } + SYS_KSEM_GETVALUE = 407 // { int ksem_getvalue(semid_t id, int *val); } + SYS_KSEM_DESTROY = 408 // { int ksem_destroy(semid_t id); } + SYS___MAC_GET_PID = 409 // { int __mac_get_pid(pid_t pid, struct mac *mac_p); } + SYS___MAC_GET_LINK = 410 // { int __mac_get_link(const char *path_p, struct mac *mac_p); } + SYS___MAC_SET_LINK = 411 // { int __mac_set_link(const char *path_p, struct mac *mac_p); } + SYS_EXTATTR_SET_LINK = 412 // { ssize_t extattr_set_link( const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes); } + SYS_EXTATTR_GET_LINK = 413 // { ssize_t extattr_get_link( const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes); } + SYS_EXTATTR_DELETE_LINK = 414 // { int extattr_delete_link( const char *path, int attrnamespace, const char *attrname); } + SYS___MAC_EXECVE = 415 // { int __mac_execve(char *fname, char **argv, char **envv, struct mac *mac_p); } + SYS_SIGACTION = 416 // { int sigaction(int sig, const struct sigaction *act, struct sigaction *oact); } + SYS_SIGRETURN = 417 // { int sigreturn( const struct __ucontext *sigcntxp); } + SYS_GETCONTEXT = 421 // { int getcontext(struct __ucontext *ucp); } + SYS_SETCONTEXT = 422 // { int setcontext( const struct __ucontext *ucp); } + SYS_SWAPCONTEXT = 423 // { int swapcontext(struct __ucontext *oucp, const struct __ucontext *ucp); } + SYS_SWAPOFF = 424 // { int swapoff(const char *name); } + SYS___ACL_GET_LINK = 425 // { int __acl_get_link(const char *path, acl_type_t type, struct acl *aclp); } + SYS___ACL_SET_LINK = 426 // { int __acl_set_link(const char *path, acl_type_t type, struct acl *aclp); } + SYS___ACL_DELETE_LINK = 427 // { int __acl_delete_link(const char *path, acl_type_t type); } + SYS___ACL_ACLCHECK_LINK = 428 // { int __acl_aclcheck_link(const char *path, acl_type_t type, struct acl *aclp); } + SYS_SIGWAIT = 429 // { int sigwait(const sigset_t *set, int *sig); } + SYS_THR_CREATE = 430 // { int thr_create(ucontext_t *ctx, long *id, int flags); } + SYS_THR_EXIT = 431 // { void thr_exit(long *state); } + SYS_THR_SELF = 432 // { int thr_self(long *id); } + SYS_THR_KILL = 433 // { int thr_kill(long id, int sig); } + SYS__UMTX_LOCK = 434 // { int _umtx_lock(struct umtx *umtx); } + SYS__UMTX_UNLOCK = 435 // { int _umtx_unlock(struct umtx *umtx); } + SYS_JAIL_ATTACH = 436 // { int jail_attach(int jid); } + SYS_EXTATTR_LIST_FD = 437 // { ssize_t extattr_list_fd(int fd, int attrnamespace, void *data, size_t nbytes); } + SYS_EXTATTR_LIST_FILE = 438 // { ssize_t extattr_list_file( const char *path, int attrnamespace, void *data, size_t nbytes); } + SYS_EXTATTR_LIST_LINK = 439 // { ssize_t extattr_list_link( const char *path, int attrnamespace, void *data, size_t nbytes); } + SYS_KSEM_TIMEDWAIT = 441 // { int ksem_timedwait(semid_t id, const struct timespec *abstime); } + SYS_THR_SUSPEND = 442 // { int thr_suspend( const struct timespec *timeout); } + SYS_THR_WAKE = 443 // { int thr_wake(long id); } + SYS_KLDUNLOADF = 444 // { int kldunloadf(int fileid, int flags); } + SYS_AUDIT = 445 // { int audit(const void *record, u_int length); } + SYS_AUDITON = 446 // { int auditon(int cmd, void *data, u_int length); } + SYS_GETAUID = 447 // { int getauid(uid_t *auid); } + SYS_SETAUID = 448 // { int setauid(uid_t *auid); } + SYS_GETAUDIT = 449 // { int getaudit(struct auditinfo *auditinfo); } + SYS_SETAUDIT = 450 // { int setaudit(struct auditinfo *auditinfo); } + SYS_GETAUDIT_ADDR = 451 // { int getaudit_addr( struct auditinfo_addr *auditinfo_addr, u_int length); } + SYS_SETAUDIT_ADDR = 452 // { int setaudit_addr( struct auditinfo_addr *auditinfo_addr, u_int length); } + SYS_AUDITCTL = 453 // { int auditctl(char *path); } + SYS__UMTX_OP = 454 // { int _umtx_op(void *obj, int op, u_long val, void *uaddr1, void *uaddr2); } + SYS_THR_NEW = 455 // { int thr_new(struct thr_param *param, int param_size); } + SYS_SIGQUEUE = 456 // { int sigqueue(pid_t pid, int signum, void *value); } + SYS_KMQ_OPEN = 457 // { int kmq_open(const char *path, int flags, mode_t mode, const struct mq_attr *attr); } + SYS_KMQ_SETATTR = 458 // { int kmq_setattr(int mqd, const struct mq_attr *attr, struct mq_attr *oattr); } + SYS_KMQ_TIMEDRECEIVE = 459 // { int kmq_timedreceive(int mqd, char *msg_ptr, size_t msg_len, unsigned *msg_prio, const struct timespec *abs_timeout); } + SYS_KMQ_TIMEDSEND = 460 // { int kmq_timedsend(int mqd, const char *msg_ptr, size_t msg_len,unsigned msg_prio, const struct timespec *abs_timeout);} + SYS_KMQ_NOTIFY = 461 // { int kmq_notify(int mqd, const struct sigevent *sigev); } + SYS_KMQ_UNLINK = 462 // { int kmq_unlink(const char *path); } + SYS_ABORT2 = 463 // { int abort2(const char *why, int nargs, void **args); } + SYS_THR_SET_NAME = 464 // { int thr_set_name(long id, const char *name); } + SYS_AIO_FSYNC = 465 // { int aio_fsync(int op, struct aiocb *aiocbp); } + SYS_RTPRIO_THREAD = 466 // { int rtprio_thread(int function, lwpid_t lwpid, struct rtprio *rtp); } + SYS_SCTP_PEELOFF = 471 // { int sctp_peeloff(int sd, uint32_t name); } + SYS_SCTP_GENERIC_SENDMSG = 472 // { int sctp_generic_sendmsg(int sd, caddr_t msg, int mlen, caddr_t to, __socklen_t tolen, struct sctp_sndrcvinfo *sinfo, int flags); } + SYS_SCTP_GENERIC_SENDMSG_IOV = 473 // { int sctp_generic_sendmsg_iov(int sd, struct iovec *iov, int iovlen, caddr_t to, __socklen_t tolen, struct sctp_sndrcvinfo *sinfo, int flags); } + SYS_SCTP_GENERIC_RECVMSG = 474 // { int sctp_generic_recvmsg(int sd, struct iovec *iov, int iovlen, struct sockaddr * from, __socklen_t *fromlenaddr, struct sctp_sndrcvinfo *sinfo, int *msg_flags); } + SYS_PREAD = 475 // { ssize_t pread(int fd, void *buf, size_t nbyte, off_t offset); } + SYS_PWRITE = 476 // { ssize_t pwrite(int fd, const void *buf, size_t nbyte, off_t offset); } + SYS_MMAP = 477 // { caddr_t mmap(caddr_t addr, size_t len, int prot, int flags, int fd, off_t pos); } + SYS_LSEEK = 478 // { off_t lseek(int fd, off_t offset, int whence); } + SYS_TRUNCATE = 479 // { int truncate(char *path, off_t length); } + SYS_FTRUNCATE = 480 // { int ftruncate(int fd, off_t length); } + SYS_THR_KILL2 = 481 // { int thr_kill2(pid_t pid, long id, int sig); } + SYS_SHM_OPEN = 482 // { int shm_open(const char *path, int flags, mode_t mode); } + SYS_SHM_UNLINK = 483 // { int shm_unlink(const char *path); } + SYS_CPUSET = 484 // { int cpuset(cpusetid_t *setid); } + SYS_CPUSET_SETID = 485 // { int cpuset_setid(cpuwhich_t which, id_t id, cpusetid_t setid); } + SYS_CPUSET_GETID = 486 // { int cpuset_getid(cpulevel_t level, cpuwhich_t which, id_t id, cpusetid_t *setid); } + SYS_CPUSET_GETAFFINITY = 487 // { int cpuset_getaffinity(cpulevel_t level, cpuwhich_t which, id_t id, size_t cpusetsize, cpuset_t *mask); } + SYS_CPUSET_SETAFFINITY = 488 // { int cpuset_setaffinity(cpulevel_t level, cpuwhich_t which, id_t id, size_t cpusetsize, const cpuset_t *mask); } + SYS_FACCESSAT = 489 // { int faccessat(int fd, char *path, int amode, int flag); } + SYS_FCHMODAT = 490 // { int fchmodat(int fd, char *path, mode_t mode, int flag); } + SYS_FCHOWNAT = 491 // { int fchownat(int fd, char *path, uid_t uid, gid_t gid, int flag); } + SYS_FEXECVE = 492 // { int fexecve(int fd, char **argv, char **envv); } + SYS_FSTATAT = 493 // { int fstatat(int fd, char *path, struct stat *buf, int flag); } + SYS_FUTIMESAT = 494 // { int futimesat(int fd, char *path, struct timeval *times); } + SYS_LINKAT = 495 // { int linkat(int fd1, char *path1, int fd2, char *path2, int flag); } + SYS_MKDIRAT = 496 // { int mkdirat(int fd, char *path, mode_t mode); } + SYS_MKFIFOAT = 497 // { int mkfifoat(int fd, char *path, mode_t mode); } + SYS_MKNODAT = 498 // { int mknodat(int fd, char *path, mode_t mode, dev_t dev); } + SYS_OPENAT = 499 // { int openat(int fd, char *path, int flag, mode_t mode); } + SYS_READLINKAT = 500 // { int readlinkat(int fd, char *path, char *buf, size_t bufsize); } + SYS_RENAMEAT = 501 // { int renameat(int oldfd, char *old, int newfd, char *new); } + SYS_SYMLINKAT = 502 // { int symlinkat(char *path1, int fd, char *path2); } + SYS_UNLINKAT = 503 // { int unlinkat(int fd, char *path, int flag); } + SYS_POSIX_OPENPT = 504 // { int posix_openpt(int flags); } + SYS_GSSD_SYSCALL = 505 // { int gssd_syscall(char *path); } + SYS_JAIL_GET = 506 // { int jail_get(struct iovec *iovp, unsigned int iovcnt, int flags); } + SYS_JAIL_SET = 507 // { int jail_set(struct iovec *iovp, unsigned int iovcnt, int flags); } + SYS_JAIL_REMOVE = 508 // { int jail_remove(int jid); } + SYS_CLOSEFROM = 509 // { int closefrom(int lowfd); } + SYS___SEMCTL = 510 // { int __semctl(int semid, int semnum, int cmd, union semun *arg); } + SYS_MSGCTL = 511 // { int msgctl(int msqid, int cmd, struct msqid_ds *buf); } + SYS_SHMCTL = 512 // { int shmctl(int shmid, int cmd, struct shmid_ds *buf); } + SYS_LPATHCONF = 513 // { int lpathconf(char *path, int name); } + SYS___CAP_RIGHTS_GET = 515 // { int __cap_rights_get(int version, int fd, cap_rights_t *rightsp); } + SYS_CAP_ENTER = 516 // { int cap_enter(void); } + SYS_CAP_GETMODE = 517 // { int cap_getmode(u_int *modep); } + SYS_PDFORK = 518 // { int pdfork(int *fdp, int flags); } + SYS_PDKILL = 519 // { int pdkill(int fd, int signum); } + SYS_PDGETPID = 520 // { int pdgetpid(int fd, pid_t *pidp); } + SYS_PSELECT = 522 // { int pselect(int nd, fd_set *in, fd_set *ou, fd_set *ex, const struct timespec *ts, const sigset_t *sm); } + SYS_GETLOGINCLASS = 523 // { int getloginclass(char *namebuf, size_t namelen); } + SYS_SETLOGINCLASS = 524 // { int setloginclass(const char *namebuf); } + SYS_RCTL_GET_RACCT = 525 // { int rctl_get_racct(const void *inbufp, size_t inbuflen, void *outbufp, size_t outbuflen); } + SYS_RCTL_GET_RULES = 526 // { int rctl_get_rules(const void *inbufp, size_t inbuflen, void *outbufp, size_t outbuflen); } + SYS_RCTL_GET_LIMITS = 527 // { int rctl_get_limits(const void *inbufp, size_t inbuflen, void *outbufp, size_t outbuflen); } + SYS_RCTL_ADD_RULE = 528 // { int rctl_add_rule(const void *inbufp, size_t inbuflen, void *outbufp, size_t outbuflen); } + SYS_RCTL_REMOVE_RULE = 529 // { int rctl_remove_rule(const void *inbufp, size_t inbuflen, void *outbufp, size_t outbuflen); } + SYS_POSIX_FALLOCATE = 530 // { int posix_fallocate(int fd, off_t offset, off_t len); } + SYS_POSIX_FADVISE = 531 // { int posix_fadvise(int fd, off_t offset, off_t len, int advice); } + SYS_WAIT6 = 532 // { int wait6(idtype_t idtype, id_t id, int *status, int options, struct __wrusage *wrusage, siginfo_t *info); } + SYS_CAP_RIGHTS_LIMIT = 533 // { int cap_rights_limit(int fd, cap_rights_t *rightsp); } + SYS_CAP_IOCTLS_LIMIT = 534 // { int cap_ioctls_limit(int fd, const u_long *cmds, size_t ncmds); } + SYS_CAP_IOCTLS_GET = 535 // { ssize_t cap_ioctls_get(int fd, u_long *cmds, size_t maxcmds); } + SYS_CAP_FCNTLS_LIMIT = 536 // { int cap_fcntls_limit(int fd, uint32_t fcntlrights); } + SYS_CAP_FCNTLS_GET = 537 // { int cap_fcntls_get(int fd, uint32_t *fcntlrightsp); } + SYS_BINDAT = 538 // { int bindat(int fd, int s, caddr_t name, int namelen); } + SYS_CONNECTAT = 539 // { int connectat(int fd, int s, caddr_t name, int namelen); } + SYS_CHFLAGSAT = 540 // { int chflagsat(int fd, const char *path, u_long flags, int atflag); } + SYS_ACCEPT4 = 541 // { int accept4(int s, struct sockaddr * __restrict name, __socklen_t * __restrict anamelen, int flags); } + SYS_PIPE2 = 542 // { int pipe2(int *fildes, int flags); } + SYS_AIO_MLOCK = 543 // { int aio_mlock(struct aiocb *aiocbp); } + SYS_PROCCTL = 544 // { int procctl(idtype_t idtype, id_t id, int com, void *data); } + SYS_PPOLL = 545 // { int ppoll(struct pollfd *fds, u_int nfds, const struct timespec *ts, const sigset_t *set); } + SYS_FUTIMENS = 546 // { int futimens(int fd, struct timespec *times); } + SYS_UTIMENSAT = 547 // { int utimensat(int fd, char *path, struct timespec *times, int flag); } ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_freebsd_arm64.go b/vendor/golang.org/x/sys/unix/zsysnum_freebsd_arm64.go new file mode 100644 index 0000000000..9f21e9550e --- /dev/null +++ b/vendor/golang.org/x/sys/unix/zsysnum_freebsd_arm64.go @@ -0,0 +1,395 @@ +// go run mksysnum.go https://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master +// Code generated by the command above; see README.md. DO NOT EDIT. + +// +build arm64,freebsd + +package unix + +const ( + // SYS_NOSYS = 0; // { int nosys(void); } syscall nosys_args int + SYS_EXIT = 1 // { void sys_exit(int rval); } exit \ + SYS_FORK = 2 // { int fork(void); } + SYS_READ = 3 // { ssize_t read(int fd, void *buf, \ + SYS_WRITE = 4 // { ssize_t write(int fd, const void *buf, \ + SYS_OPEN = 5 // { int open(char *path, int flags, int mode); } + SYS_CLOSE = 6 // { int close(int fd); } + SYS_WAIT4 = 7 // { int wait4(int pid, int *status, \ + SYS_LINK = 9 // { int link(char *path, char *link); } + SYS_UNLINK = 10 // { int unlink(char *path); } + SYS_CHDIR = 12 // { int chdir(char *path); } + SYS_FCHDIR = 13 // { int fchdir(int fd); } + SYS_MKNOD = 14 // { int mknod(char *path, int mode, int dev); } + SYS_CHMOD = 15 // { int chmod(char *path, int mode); } + SYS_CHOWN = 16 // { int chown(char *path, int uid, int gid); } + SYS_OBREAK = 17 // { int obreak(char *nsize); } break \ + SYS_GETPID = 20 // { pid_t getpid(void); } + SYS_MOUNT = 21 // { int mount(char *type, char *path, \ + SYS_UNMOUNT = 22 // { int unmount(char *path, int flags); } + SYS_SETUID = 23 // { int setuid(uid_t uid); } + SYS_GETUID = 24 // { uid_t getuid(void); } + SYS_GETEUID = 25 // { uid_t geteuid(void); } + SYS_PTRACE = 26 // { int ptrace(int req, pid_t pid, \ + SYS_RECVMSG = 27 // { int recvmsg(int s, struct msghdr *msg, \ + SYS_SENDMSG = 28 // { int sendmsg(int s, struct msghdr *msg, \ + SYS_RECVFROM = 29 // { int recvfrom(int s, caddr_t buf, \ + SYS_ACCEPT = 30 // { int accept(int s, \ + SYS_GETPEERNAME = 31 // { int getpeername(int fdes, \ + SYS_GETSOCKNAME = 32 // { int getsockname(int fdes, \ + SYS_ACCESS = 33 // { int access(char *path, int amode); } + SYS_CHFLAGS = 34 // { int chflags(const char *path, u_long flags); } + SYS_FCHFLAGS = 35 // { int fchflags(int fd, u_long flags); } + SYS_SYNC = 36 // { int sync(void); } + SYS_KILL = 37 // { int kill(int pid, int signum); } + SYS_GETPPID = 39 // { pid_t getppid(void); } + SYS_DUP = 41 // { int dup(u_int fd); } + SYS_GETEGID = 43 // { gid_t getegid(void); } + SYS_PROFIL = 44 // { int profil(caddr_t samples, size_t size, \ + SYS_KTRACE = 45 // { int ktrace(const char *fname, int ops, \ + SYS_GETGID = 47 // { gid_t getgid(void); } + SYS_GETLOGIN = 49 // { int getlogin(char *namebuf, u_int \ + SYS_SETLOGIN = 50 // { int setlogin(char *namebuf); } + SYS_ACCT = 51 // { int acct(char *path); } + SYS_SIGALTSTACK = 53 // { int sigaltstack(stack_t *ss, \ + SYS_IOCTL = 54 // { int ioctl(int fd, u_long com, \ + SYS_REBOOT = 55 // { int reboot(int opt); } + SYS_REVOKE = 56 // { int revoke(char *path); } + SYS_SYMLINK = 57 // { int symlink(char *path, char *link); } + SYS_READLINK = 58 // { ssize_t readlink(char *path, char *buf, \ + SYS_EXECVE = 59 // { int execve(char *fname, char **argv, \ + SYS_UMASK = 60 // { int umask(int newmask); } umask umask_args \ + SYS_CHROOT = 61 // { int chroot(char *path); } + SYS_MSYNC = 65 // { int msync(void *addr, size_t len, \ + SYS_VFORK = 66 // { int vfork(void); } + SYS_SBRK = 69 // { int sbrk(int incr); } + SYS_SSTK = 70 // { int sstk(int incr); } + SYS_OVADVISE = 72 // { int ovadvise(int anom); } vadvise \ + SYS_MUNMAP = 73 // { int munmap(void *addr, size_t len); } + SYS_MPROTECT = 74 // { int mprotect(const void *addr, size_t len, \ + SYS_MADVISE = 75 // { int madvise(void *addr, size_t len, \ + SYS_MINCORE = 78 // { int mincore(const void *addr, size_t len, \ + SYS_GETGROUPS = 79 // { int getgroups(u_int gidsetsize, \ + SYS_SETGROUPS = 80 // { int setgroups(u_int gidsetsize, \ + SYS_GETPGRP = 81 // { int getpgrp(void); } + SYS_SETPGID = 82 // { int setpgid(int pid, int pgid); } + SYS_SETITIMER = 83 // { int setitimer(u_int which, struct \ + SYS_SWAPON = 85 // { int swapon(char *name); } + SYS_GETITIMER = 86 // { int getitimer(u_int which, \ + SYS_GETDTABLESIZE = 89 // { int getdtablesize(void); } + SYS_DUP2 = 90 // { int dup2(u_int from, u_int to); } + SYS_FCNTL = 92 // { int fcntl(int fd, int cmd, long arg); } + SYS_SELECT = 93 // { int select(int nd, fd_set *in, fd_set *ou, \ + SYS_FSYNC = 95 // { int fsync(int fd); } + SYS_SETPRIORITY = 96 // { int setpriority(int which, int who, \ + SYS_SOCKET = 97 // { int socket(int domain, int type, \ + SYS_CONNECT = 98 // { int connect(int s, caddr_t name, \ + SYS_GETPRIORITY = 100 // { int getpriority(int which, int who); } + SYS_BIND = 104 // { int bind(int s, caddr_t name, \ + SYS_SETSOCKOPT = 105 // { int setsockopt(int s, int level, int name, \ + SYS_LISTEN = 106 // { int listen(int s, int backlog); } + SYS_GETTIMEOFDAY = 116 // { int gettimeofday(struct timeval *tp, \ + SYS_GETRUSAGE = 117 // { int getrusage(int who, \ + SYS_GETSOCKOPT = 118 // { int getsockopt(int s, int level, int name, \ + SYS_READV = 120 // { int readv(int fd, struct iovec *iovp, \ + SYS_WRITEV = 121 // { int writev(int fd, struct iovec *iovp, \ + SYS_SETTIMEOFDAY = 122 // { int settimeofday(struct timeval *tv, \ + SYS_FCHOWN = 123 // { int fchown(int fd, int uid, int gid); } + SYS_FCHMOD = 124 // { int fchmod(int fd, int mode); } + SYS_SETREUID = 126 // { int setreuid(int ruid, int euid); } + SYS_SETREGID = 127 // { int setregid(int rgid, int egid); } + SYS_RENAME = 128 // { int rename(char *from, char *to); } + SYS_FLOCK = 131 // { int flock(int fd, int how); } + SYS_MKFIFO = 132 // { int mkfifo(char *path, int mode); } + SYS_SENDTO = 133 // { int sendto(int s, caddr_t buf, size_t len, \ + SYS_SHUTDOWN = 134 // { int shutdown(int s, int how); } + SYS_SOCKETPAIR = 135 // { int socketpair(int domain, int type, \ + SYS_MKDIR = 136 // { int mkdir(char *path, int mode); } + SYS_RMDIR = 137 // { int rmdir(char *path); } + SYS_UTIMES = 138 // { int utimes(char *path, \ + SYS_ADJTIME = 140 // { int adjtime(struct timeval *delta, \ + SYS_SETSID = 147 // { int setsid(void); } + SYS_QUOTACTL = 148 // { int quotactl(char *path, int cmd, int uid, \ + SYS_NLM_SYSCALL = 154 // { int nlm_syscall(int debug_level, int grace_period, int addr_count, char **addrs); } + SYS_NFSSVC = 155 // { int nfssvc(int flag, caddr_t argp); } + SYS_LGETFH = 160 // { int lgetfh(char *fname, \ + SYS_GETFH = 161 // { int getfh(char *fname, \ + SYS_SYSARCH = 165 // { int sysarch(int op, char *parms); } + SYS_RTPRIO = 166 // { int rtprio(int function, pid_t pid, \ + SYS_SEMSYS = 169 // { int semsys(int which, int a2, int a3, \ + SYS_MSGSYS = 170 // { int msgsys(int which, int a2, int a3, \ + SYS_SHMSYS = 171 // { int shmsys(int which, int a2, int a3, \ + SYS_SETFIB = 175 // { int setfib(int fibnum); } + SYS_NTP_ADJTIME = 176 // { int ntp_adjtime(struct timex *tp); } + SYS_SETGID = 181 // { int setgid(gid_t gid); } + SYS_SETEGID = 182 // { int setegid(gid_t egid); } + SYS_SETEUID = 183 // { int seteuid(uid_t euid); } + SYS_STAT = 188 // { int stat(char *path, struct stat *ub); } + SYS_FSTAT = 189 // { int fstat(int fd, struct stat *sb); } + SYS_LSTAT = 190 // { int lstat(char *path, struct stat *ub); } + SYS_PATHCONF = 191 // { int pathconf(char *path, int name); } + SYS_FPATHCONF = 192 // { int fpathconf(int fd, int name); } + SYS_GETRLIMIT = 194 // { int getrlimit(u_int which, \ + SYS_SETRLIMIT = 195 // { int setrlimit(u_int which, \ + SYS_GETDIRENTRIES = 196 // { int getdirentries(int fd, char *buf, \ + SYS___SYSCTL = 202 // { int __sysctl(int *name, u_int namelen, \ + SYS_MLOCK = 203 // { int mlock(const void *addr, size_t len); } + SYS_MUNLOCK = 204 // { int munlock(const void *addr, size_t len); } + SYS_UNDELETE = 205 // { int undelete(char *path); } + SYS_FUTIMES = 206 // { int futimes(int fd, struct timeval *tptr); } + SYS_GETPGID = 207 // { int getpgid(pid_t pid); } + SYS_POLL = 209 // { int poll(struct pollfd *fds, u_int nfds, \ + SYS_SEMGET = 221 // { int semget(key_t key, int nsems, \ + SYS_SEMOP = 222 // { int semop(int semid, struct sembuf *sops, \ + SYS_MSGGET = 225 // { int msgget(key_t key, int msgflg); } + SYS_MSGSND = 226 // { int msgsnd(int msqid, const void *msgp, \ + SYS_MSGRCV = 227 // { int msgrcv(int msqid, void *msgp, \ + SYS_SHMAT = 228 // { int shmat(int shmid, const void *shmaddr, \ + SYS_SHMDT = 230 // { int shmdt(const void *shmaddr); } + SYS_SHMGET = 231 // { int shmget(key_t key, size_t size, \ + SYS_CLOCK_GETTIME = 232 // { int clock_gettime(clockid_t clock_id, \ + SYS_CLOCK_SETTIME = 233 // { int clock_settime( \ + SYS_CLOCK_GETRES = 234 // { int clock_getres(clockid_t clock_id, \ + SYS_KTIMER_CREATE = 235 // { int ktimer_create(clockid_t clock_id, \ + SYS_KTIMER_DELETE = 236 // { int ktimer_delete(int timerid); } + SYS_KTIMER_SETTIME = 237 // { int ktimer_settime(int timerid, int flags, \ + SYS_KTIMER_GETTIME = 238 // { int ktimer_gettime(int timerid, struct \ + SYS_KTIMER_GETOVERRUN = 239 // { int ktimer_getoverrun(int timerid); } + SYS_NANOSLEEP = 240 // { int nanosleep(const struct timespec *rqtp, \ + SYS_FFCLOCK_GETCOUNTER = 241 // { int ffclock_getcounter(ffcounter *ffcount); } + SYS_FFCLOCK_SETESTIMATE = 242 // { int ffclock_setestimate( \ + SYS_FFCLOCK_GETESTIMATE = 243 // { int ffclock_getestimate( \ + SYS_CLOCK_NANOSLEEP = 244 // { int clock_nanosleep(clockid_t clock_id, \ + SYS_CLOCK_GETCPUCLOCKID2 = 247 // { int clock_getcpuclockid2(id_t id,\ + SYS_NTP_GETTIME = 248 // { int ntp_gettime(struct ntptimeval *ntvp); } + SYS_MINHERIT = 250 // { int minherit(void *addr, size_t len, \ + SYS_RFORK = 251 // { int rfork(int flags); } + SYS_OPENBSD_POLL = 252 // { int openbsd_poll(struct pollfd *fds, \ + SYS_ISSETUGID = 253 // { int issetugid(void); } + SYS_LCHOWN = 254 // { int lchown(char *path, int uid, int gid); } + SYS_AIO_READ = 255 // { int aio_read(struct aiocb *aiocbp); } + SYS_AIO_WRITE = 256 // { int aio_write(struct aiocb *aiocbp); } + SYS_LIO_LISTIO = 257 // { int lio_listio(int mode, \ + SYS_GETDENTS = 272 // { int getdents(int fd, char *buf, \ + SYS_LCHMOD = 274 // { int lchmod(char *path, mode_t mode); } + SYS_LUTIMES = 276 // { int lutimes(char *path, \ + SYS_NSTAT = 278 // { int nstat(char *path, struct nstat *ub); } + SYS_NFSTAT = 279 // { int nfstat(int fd, struct nstat *sb); } + SYS_NLSTAT = 280 // { int nlstat(char *path, struct nstat *ub); } + SYS_PREADV = 289 // { ssize_t preadv(int fd, struct iovec *iovp, \ + SYS_PWRITEV = 290 // { ssize_t pwritev(int fd, struct iovec *iovp, \ + SYS_FHOPEN = 298 // { int fhopen(const struct fhandle *u_fhp, \ + SYS_FHSTAT = 299 // { int fhstat(const struct fhandle *u_fhp, \ + SYS_MODNEXT = 300 // { int modnext(int modid); } + SYS_MODSTAT = 301 // { int modstat(int modid, \ + SYS_MODFNEXT = 302 // { int modfnext(int modid); } + SYS_MODFIND = 303 // { int modfind(const char *name); } + SYS_KLDLOAD = 304 // { int kldload(const char *file); } + SYS_KLDUNLOAD = 305 // { int kldunload(int fileid); } + SYS_KLDFIND = 306 // { int kldfind(const char *file); } + SYS_KLDNEXT = 307 // { int kldnext(int fileid); } + SYS_KLDSTAT = 308 // { int kldstat(int fileid, struct \ + SYS_KLDFIRSTMOD = 309 // { int kldfirstmod(int fileid); } + SYS_GETSID = 310 // { int getsid(pid_t pid); } + SYS_SETRESUID = 311 // { int setresuid(uid_t ruid, uid_t euid, \ + SYS_SETRESGID = 312 // { int setresgid(gid_t rgid, gid_t egid, \ + SYS_AIO_RETURN = 314 // { ssize_t aio_return(struct aiocb *aiocbp); } + SYS_AIO_SUSPEND = 315 // { int aio_suspend( \ + SYS_AIO_CANCEL = 316 // { int aio_cancel(int fd, \ + SYS_AIO_ERROR = 317 // { int aio_error(struct aiocb *aiocbp); } + SYS_YIELD = 321 // { int yield(void); } + SYS_MLOCKALL = 324 // { int mlockall(int how); } + SYS_MUNLOCKALL = 325 // { int munlockall(void); } + SYS___GETCWD = 326 // { int __getcwd(char *buf, u_int buflen); } + SYS_SCHED_SETPARAM = 327 // { int sched_setparam (pid_t pid, \ + SYS_SCHED_GETPARAM = 328 // { int sched_getparam (pid_t pid, struct \ + SYS_SCHED_SETSCHEDULER = 329 // { int sched_setscheduler (pid_t pid, int \ + SYS_SCHED_GETSCHEDULER = 330 // { int sched_getscheduler (pid_t pid); } + SYS_SCHED_YIELD = 331 // { int sched_yield (void); } + SYS_SCHED_GET_PRIORITY_MAX = 332 // { int sched_get_priority_max (int policy); } + SYS_SCHED_GET_PRIORITY_MIN = 333 // { int sched_get_priority_min (int policy); } + SYS_SCHED_RR_GET_INTERVAL = 334 // { int sched_rr_get_interval (pid_t pid, \ + SYS_UTRACE = 335 // { int utrace(const void *addr, size_t len); } + SYS_KLDSYM = 337 // { int kldsym(int fileid, int cmd, \ + SYS_JAIL = 338 // { int jail(struct jail *jail); } + SYS_SIGPROCMASK = 340 // { int sigprocmask(int how, \ + SYS_SIGSUSPEND = 341 // { int sigsuspend(const sigset_t *sigmask); } + SYS_SIGPENDING = 343 // { int sigpending(sigset_t *set); } + SYS_SIGTIMEDWAIT = 345 // { int sigtimedwait(const sigset_t *set, \ + SYS_SIGWAITINFO = 346 // { int sigwaitinfo(const sigset_t *set, \ + SYS___ACL_GET_FILE = 347 // { int __acl_get_file(const char *path, \ + SYS___ACL_SET_FILE = 348 // { int __acl_set_file(const char *path, \ + SYS___ACL_GET_FD = 349 // { int __acl_get_fd(int filedes, \ + SYS___ACL_SET_FD = 350 // { int __acl_set_fd(int filedes, \ + SYS___ACL_DELETE_FILE = 351 // { int __acl_delete_file(const char *path, \ + SYS___ACL_DELETE_FD = 352 // { int __acl_delete_fd(int filedes, \ + SYS___ACL_ACLCHECK_FILE = 353 // { int __acl_aclcheck_file(const char *path, \ + SYS___ACL_ACLCHECK_FD = 354 // { int __acl_aclcheck_fd(int filedes, \ + SYS_EXTATTRCTL = 355 // { int extattrctl(const char *path, int cmd, \ + SYS_EXTATTR_SET_FILE = 356 // { ssize_t extattr_set_file( \ + SYS_EXTATTR_GET_FILE = 357 // { ssize_t extattr_get_file( \ + SYS_EXTATTR_DELETE_FILE = 358 // { int extattr_delete_file(const char *path, \ + SYS_AIO_WAITCOMPLETE = 359 // { ssize_t aio_waitcomplete( \ + SYS_GETRESUID = 360 // { int getresuid(uid_t *ruid, uid_t *euid, \ + SYS_GETRESGID = 361 // { int getresgid(gid_t *rgid, gid_t *egid, \ + SYS_KQUEUE = 362 // { int kqueue(void); } + SYS_KEVENT = 363 // { int kevent(int fd, \ + SYS_EXTATTR_SET_FD = 371 // { ssize_t extattr_set_fd(int fd, \ + SYS_EXTATTR_GET_FD = 372 // { ssize_t extattr_get_fd(int fd, \ + SYS_EXTATTR_DELETE_FD = 373 // { int extattr_delete_fd(int fd, \ + SYS___SETUGID = 374 // { int __setugid(int flag); } + SYS_EACCESS = 376 // { int eaccess(char *path, int amode); } + SYS_NMOUNT = 378 // { int nmount(struct iovec *iovp, \ + SYS___MAC_GET_PROC = 384 // { int __mac_get_proc(struct mac *mac_p); } + SYS___MAC_SET_PROC = 385 // { int __mac_set_proc(struct mac *mac_p); } + SYS___MAC_GET_FD = 386 // { int __mac_get_fd(int fd, \ + SYS___MAC_GET_FILE = 387 // { int __mac_get_file(const char *path_p, \ + SYS___MAC_SET_FD = 388 // { int __mac_set_fd(int fd, \ + SYS___MAC_SET_FILE = 389 // { int __mac_set_file(const char *path_p, \ + SYS_KENV = 390 // { int kenv(int what, const char *name, \ + SYS_LCHFLAGS = 391 // { int lchflags(const char *path, \ + SYS_UUIDGEN = 392 // { int uuidgen(struct uuid *store, \ + SYS_SENDFILE = 393 // { int sendfile(int fd, int s, off_t offset, \ + SYS_MAC_SYSCALL = 394 // { int mac_syscall(const char *policy, \ + SYS_GETFSSTAT = 395 // { int getfsstat(struct statfs *buf, \ + SYS_STATFS = 396 // { int statfs(char *path, \ + SYS_FSTATFS = 397 // { int fstatfs(int fd, struct statfs *buf); } + SYS_FHSTATFS = 398 // { int fhstatfs(const struct fhandle *u_fhp, \ + SYS_KSEM_CLOSE = 400 // { int ksem_close(semid_t id); } + SYS_KSEM_POST = 401 // { int ksem_post(semid_t id); } + SYS_KSEM_WAIT = 402 // { int ksem_wait(semid_t id); } + SYS_KSEM_TRYWAIT = 403 // { int ksem_trywait(semid_t id); } + SYS_KSEM_INIT = 404 // { int ksem_init(semid_t *idp, \ + SYS_KSEM_OPEN = 405 // { int ksem_open(semid_t *idp, \ + SYS_KSEM_UNLINK = 406 // { int ksem_unlink(const char *name); } + SYS_KSEM_GETVALUE = 407 // { int ksem_getvalue(semid_t id, int *val); } + SYS_KSEM_DESTROY = 408 // { int ksem_destroy(semid_t id); } + SYS___MAC_GET_PID = 409 // { int __mac_get_pid(pid_t pid, \ + SYS___MAC_GET_LINK = 410 // { int __mac_get_link(const char *path_p, \ + SYS___MAC_SET_LINK = 411 // { int __mac_set_link(const char *path_p, \ + SYS_EXTATTR_SET_LINK = 412 // { ssize_t extattr_set_link( \ + SYS_EXTATTR_GET_LINK = 413 // { ssize_t extattr_get_link( \ + SYS_EXTATTR_DELETE_LINK = 414 // { int extattr_delete_link( \ + SYS___MAC_EXECVE = 415 // { int __mac_execve(char *fname, char **argv, \ + SYS_SIGACTION = 416 // { int sigaction(int sig, \ + SYS_SIGRETURN = 417 // { int sigreturn( \ + SYS_GETCONTEXT = 421 // { int getcontext(struct __ucontext *ucp); } + SYS_SETCONTEXT = 422 // { int setcontext( \ + SYS_SWAPCONTEXT = 423 // { int swapcontext(struct __ucontext *oucp, \ + SYS_SWAPOFF = 424 // { int swapoff(const char *name); } + SYS___ACL_GET_LINK = 425 // { int __acl_get_link(const char *path, \ + SYS___ACL_SET_LINK = 426 // { int __acl_set_link(const char *path, \ + SYS___ACL_DELETE_LINK = 427 // { int __acl_delete_link(const char *path, \ + SYS___ACL_ACLCHECK_LINK = 428 // { int __acl_aclcheck_link(const char *path, \ + SYS_SIGWAIT = 429 // { int sigwait(const sigset_t *set, \ + SYS_THR_CREATE = 430 // { int thr_create(ucontext_t *ctx, long *id, \ + SYS_THR_EXIT = 431 // { void thr_exit(long *state); } + SYS_THR_SELF = 432 // { int thr_self(long *id); } + SYS_THR_KILL = 433 // { int thr_kill(long id, int sig); } + SYS_JAIL_ATTACH = 436 // { int jail_attach(int jid); } + SYS_EXTATTR_LIST_FD = 437 // { ssize_t extattr_list_fd(int fd, \ + SYS_EXTATTR_LIST_FILE = 438 // { ssize_t extattr_list_file( \ + SYS_EXTATTR_LIST_LINK = 439 // { ssize_t extattr_list_link( \ + SYS_KSEM_TIMEDWAIT = 441 // { int ksem_timedwait(semid_t id, \ + SYS_THR_SUSPEND = 442 // { int thr_suspend( \ + SYS_THR_WAKE = 443 // { int thr_wake(long id); } + SYS_KLDUNLOADF = 444 // { int kldunloadf(int fileid, int flags); } + SYS_AUDIT = 445 // { int audit(const void *record, \ + SYS_AUDITON = 446 // { int auditon(int cmd, void *data, \ + SYS_GETAUID = 447 // { int getauid(uid_t *auid); } + SYS_SETAUID = 448 // { int setauid(uid_t *auid); } + SYS_GETAUDIT = 449 // { int getaudit(struct auditinfo *auditinfo); } + SYS_SETAUDIT = 450 // { int setaudit(struct auditinfo *auditinfo); } + SYS_GETAUDIT_ADDR = 451 // { int getaudit_addr( \ + SYS_SETAUDIT_ADDR = 452 // { int setaudit_addr( \ + SYS_AUDITCTL = 453 // { int auditctl(char *path); } + SYS__UMTX_OP = 454 // { int _umtx_op(void *obj, int op, \ + SYS_THR_NEW = 455 // { int thr_new(struct thr_param *param, \ + SYS_SIGQUEUE = 456 // { int sigqueue(pid_t pid, int signum, void *value); } + SYS_KMQ_OPEN = 457 // { int kmq_open(const char *path, int flags, \ + SYS_KMQ_SETATTR = 458 // { int kmq_setattr(int mqd, \ + SYS_KMQ_TIMEDRECEIVE = 459 // { int kmq_timedreceive(int mqd, \ + SYS_KMQ_TIMEDSEND = 460 // { int kmq_timedsend(int mqd, \ + SYS_KMQ_NOTIFY = 461 // { int kmq_notify(int mqd, \ + SYS_KMQ_UNLINK = 462 // { int kmq_unlink(const char *path); } + SYS_ABORT2 = 463 // { int abort2(const char *why, int nargs, void **args); } + SYS_THR_SET_NAME = 464 // { int thr_set_name(long id, const char *name); } + SYS_AIO_FSYNC = 465 // { int aio_fsync(int op, struct aiocb *aiocbp); } + SYS_RTPRIO_THREAD = 466 // { int rtprio_thread(int function, \ + SYS_SCTP_PEELOFF = 471 // { int sctp_peeloff(int sd, uint32_t name); } + SYS_SCTP_GENERIC_SENDMSG = 472 // { int sctp_generic_sendmsg(int sd, caddr_t msg, int mlen, \ + SYS_SCTP_GENERIC_SENDMSG_IOV = 473 // { int sctp_generic_sendmsg_iov(int sd, struct iovec *iov, int iovlen, \ + SYS_SCTP_GENERIC_RECVMSG = 474 // { int sctp_generic_recvmsg(int sd, struct iovec *iov, int iovlen, \ + SYS_PREAD = 475 // { ssize_t pread(int fd, void *buf, \ + SYS_PWRITE = 476 // { ssize_t pwrite(int fd, const void *buf, \ + SYS_MMAP = 477 // { caddr_t mmap(caddr_t addr, size_t len, \ + SYS_LSEEK = 478 // { off_t lseek(int fd, off_t offset, \ + SYS_TRUNCATE = 479 // { int truncate(char *path, off_t length); } + SYS_FTRUNCATE = 480 // { int ftruncate(int fd, off_t length); } + SYS_THR_KILL2 = 481 // { int thr_kill2(pid_t pid, long id, int sig); } + SYS_SHM_OPEN = 482 // { int shm_open(const char *path, int flags, \ + SYS_SHM_UNLINK = 483 // { int shm_unlink(const char *path); } + SYS_CPUSET = 484 // { int cpuset(cpusetid_t *setid); } + SYS_CPUSET_SETID = 485 // { int cpuset_setid(cpuwhich_t which, id_t id, \ + SYS_CPUSET_GETID = 486 // { int cpuset_getid(cpulevel_t level, \ + SYS_CPUSET_GETAFFINITY = 487 // { int cpuset_getaffinity(cpulevel_t level, \ + SYS_CPUSET_SETAFFINITY = 488 // { int cpuset_setaffinity(cpulevel_t level, \ + SYS_FACCESSAT = 489 // { int faccessat(int fd, char *path, int amode, \ + SYS_FCHMODAT = 490 // { int fchmodat(int fd, char *path, mode_t mode, \ + SYS_FCHOWNAT = 491 // { int fchownat(int fd, char *path, uid_t uid, \ + SYS_FEXECVE = 492 // { int fexecve(int fd, char **argv, \ + SYS_FSTATAT = 493 // { int fstatat(int fd, char *path, \ + SYS_FUTIMESAT = 494 // { int futimesat(int fd, char *path, \ + SYS_LINKAT = 495 // { int linkat(int fd1, char *path1, int fd2, \ + SYS_MKDIRAT = 496 // { int mkdirat(int fd, char *path, mode_t mode); } + SYS_MKFIFOAT = 497 // { int mkfifoat(int fd, char *path, mode_t mode); } + SYS_MKNODAT = 498 // { int mknodat(int fd, char *path, mode_t mode, \ + SYS_OPENAT = 499 // { int openat(int fd, char *path, int flag, \ + SYS_READLINKAT = 500 // { int readlinkat(int fd, char *path, char *buf, \ + SYS_RENAMEAT = 501 // { int renameat(int oldfd, char *old, int newfd, \ + SYS_SYMLINKAT = 502 // { int symlinkat(char *path1, int fd, \ + SYS_UNLINKAT = 503 // { int unlinkat(int fd, char *path, int flag); } + SYS_POSIX_OPENPT = 504 // { int posix_openpt(int flags); } + SYS_GSSD_SYSCALL = 505 // { int gssd_syscall(char *path); } + SYS_JAIL_GET = 506 // { int jail_get(struct iovec *iovp, \ + SYS_JAIL_SET = 507 // { int jail_set(struct iovec *iovp, \ + SYS_JAIL_REMOVE = 508 // { int jail_remove(int jid); } + SYS_CLOSEFROM = 509 // { int closefrom(int lowfd); } + SYS___SEMCTL = 510 // { int __semctl(int semid, int semnum, \ + SYS_MSGCTL = 511 // { int msgctl(int msqid, int cmd, \ + SYS_SHMCTL = 512 // { int shmctl(int shmid, int cmd, \ + SYS_LPATHCONF = 513 // { int lpathconf(char *path, int name); } + SYS___CAP_RIGHTS_GET = 515 // { int __cap_rights_get(int version, \ + SYS_CAP_ENTER = 516 // { int cap_enter(void); } + SYS_CAP_GETMODE = 517 // { int cap_getmode(u_int *modep); } + SYS_PDFORK = 518 // { int pdfork(int *fdp, int flags); } + SYS_PDKILL = 519 // { int pdkill(int fd, int signum); } + SYS_PDGETPID = 520 // { int pdgetpid(int fd, pid_t *pidp); } + SYS_PSELECT = 522 // { int pselect(int nd, fd_set *in, \ + SYS_GETLOGINCLASS = 523 // { int getloginclass(char *namebuf, \ + SYS_SETLOGINCLASS = 524 // { int setloginclass(const char *namebuf); } + SYS_RCTL_GET_RACCT = 525 // { int rctl_get_racct(const void *inbufp, \ + SYS_RCTL_GET_RULES = 526 // { int rctl_get_rules(const void *inbufp, \ + SYS_RCTL_GET_LIMITS = 527 // { int rctl_get_limits(const void *inbufp, \ + SYS_RCTL_ADD_RULE = 528 // { int rctl_add_rule(const void *inbufp, \ + SYS_RCTL_REMOVE_RULE = 529 // { int rctl_remove_rule(const void *inbufp, \ + SYS_POSIX_FALLOCATE = 530 // { int posix_fallocate(int fd, \ + SYS_POSIX_FADVISE = 531 // { int posix_fadvise(int fd, off_t offset, \ + SYS_WAIT6 = 532 // { int wait6(idtype_t idtype, id_t id, \ + SYS_CAP_RIGHTS_LIMIT = 533 // { int cap_rights_limit(int fd, \ + SYS_CAP_IOCTLS_LIMIT = 534 // { int cap_ioctls_limit(int fd, \ + SYS_CAP_IOCTLS_GET = 535 // { ssize_t cap_ioctls_get(int fd, \ + SYS_CAP_FCNTLS_LIMIT = 536 // { int cap_fcntls_limit(int fd, \ + SYS_CAP_FCNTLS_GET = 537 // { int cap_fcntls_get(int fd, \ + SYS_BINDAT = 538 // { int bindat(int fd, int s, caddr_t name, \ + SYS_CONNECTAT = 539 // { int connectat(int fd, int s, caddr_t name, \ + SYS_CHFLAGSAT = 540 // { int chflagsat(int fd, const char *path, \ + SYS_ACCEPT4 = 541 // { int accept4(int s, \ + SYS_PIPE2 = 542 // { int pipe2(int *fildes, int flags); } + SYS_AIO_MLOCK = 543 // { int aio_mlock(struct aiocb *aiocbp); } + SYS_PROCCTL = 544 // { int procctl(idtype_t idtype, id_t id, \ + SYS_PPOLL = 545 // { int ppoll(struct pollfd *fds, u_int nfds, \ + SYS_FUTIMENS = 546 // { int futimens(int fd, \ + SYS_UTIMENSAT = 547 // { int utimensat(int fd, \ + SYS_NUMA_GETAFFINITY = 548 // { int numa_getaffinity(cpuwhich_t which, \ + SYS_NUMA_SETAFFINITY = 549 // { int numa_setaffinity(cpuwhich_t which, \ + SYS_FDATASYNC = 550 // { int fdatasync(int fd); } +) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go index 95ab12903e..8d17873de0 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go @@ -1,4 +1,4 @@ -// linux/mksysnum.pl -Wall -Werror -static -I/tmp/include -m32 /tmp/include/asm/unistd.h +// go run linux/mksysnum.go -Wall -Werror -static -I/tmp/include -m32 /tmp/include/asm/unistd.h // Code generated by the command above; see README.md. DO NOT EDIT. // +build 386,linux @@ -387,4 +387,6 @@ const ( SYS_PKEY_FREE = 382 SYS_STATX = 383 SYS_ARCH_PRCTL = 384 + SYS_IO_PGETEVENTS = 385 + SYS_RSEQ = 386 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go index c5dabf2e45..b3d8ad79d4 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go @@ -1,4 +1,4 @@ -// linux/mksysnum.pl -Wall -Werror -static -I/tmp/include -m64 /tmp/include/asm/unistd.h +// go run linux/mksysnum.go -Wall -Werror -static -I/tmp/include -m64 /tmp/include/asm/unistd.h // Code generated by the command above; see README.md. DO NOT EDIT. // +build amd64,linux @@ -339,4 +339,6 @@ const ( SYS_PKEY_ALLOC = 330 SYS_PKEY_FREE = 331 SYS_STATX = 332 + SYS_IO_PGETEVENTS = 333 + SYS_RSEQ = 334 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go index ab7fa5fd39..e092822fba 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go @@ -1,4 +1,4 @@ -// linux/mksysnum.pl -Wall -Werror -static -I/tmp/include /tmp/include/asm/unistd.h +// go run linux/mksysnum.go -Wall -Werror -static -I/tmp/include /tmp/include/asm/unistd.h // Code generated by the command above; see README.md. DO NOT EDIT. // +build arm,linux @@ -359,4 +359,6 @@ const ( SYS_PKEY_ALLOC = 395 SYS_PKEY_FREE = 396 SYS_STATX = 397 + SYS_RSEQ = 398 + SYS_IO_PGETEVENTS = 399 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go index b1c6b4bd3b..3206967896 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go @@ -1,4 +1,4 @@ -// linux/mksysnum.pl -Wall -Werror -static -I/tmp/include -fsigned-char /tmp/include/asm/unistd.h +// go run linux/mksysnum.go -Wall -Werror -static -I/tmp/include -fsigned-char /tmp/include/asm/unistd.h // Code generated by the command above; see README.md. DO NOT EDIT. // +build arm64,linux @@ -283,4 +283,6 @@ const ( SYS_PKEY_ALLOC = 289 SYS_PKEY_FREE = 290 SYS_STATX = 291 + SYS_IO_PGETEVENTS = 292 + SYS_RSEQ = 293 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go index 2e9aa7a3e7..6893a5bd05 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go @@ -1,4 +1,4 @@ -// linux/mksysnum.pl -Wall -Werror -static -I/tmp/include /tmp/include/asm/unistd.h +// go run linux/mksysnum.go -Wall -Werror -static -I/tmp/include /tmp/include/asm/unistd.h // Code generated by the command above; see README.md. DO NOT EDIT. // +build mips,linux @@ -372,4 +372,6 @@ const ( SYS_PKEY_ALLOC = 4364 SYS_PKEY_FREE = 4365 SYS_STATX = 4366 + SYS_RSEQ = 4367 + SYS_IO_PGETEVENTS = 4368 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go index 92827635aa..40164cacdf 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go @@ -1,4 +1,4 @@ -// linux/mksysnum.pl -Wall -Werror -static -I/tmp/include /tmp/include/asm/unistd.h +// go run linux/mksysnum.go -Wall -Werror -static -I/tmp/include /tmp/include/asm/unistd.h // Code generated by the command above; see README.md. DO NOT EDIT. // +build mips64,linux @@ -332,4 +332,6 @@ const ( SYS_PKEY_ALLOC = 5324 SYS_PKEY_FREE = 5325 SYS_STATX = 5326 + SYS_RSEQ = 5327 + SYS_IO_PGETEVENTS = 5328 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go index 45bd3fd6c8..8a909738bc 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go @@ -1,4 +1,4 @@ -// linux/mksysnum.pl -Wall -Werror -static -I/tmp/include /tmp/include/asm/unistd.h +// go run linux/mksysnum.go -Wall -Werror -static -I/tmp/include /tmp/include/asm/unistd.h // Code generated by the command above; see README.md. DO NOT EDIT. // +build mips64le,linux @@ -332,4 +332,6 @@ const ( SYS_PKEY_ALLOC = 5324 SYS_PKEY_FREE = 5325 SYS_STATX = 5326 + SYS_RSEQ = 5327 + SYS_IO_PGETEVENTS = 5328 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go index 62ccac4b74..8d78184224 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go @@ -1,4 +1,4 @@ -// linux/mksysnum.pl -Wall -Werror -static -I/tmp/include /tmp/include/asm/unistd.h +// go run linux/mksysnum.go -Wall -Werror -static -I/tmp/include /tmp/include/asm/unistd.h // Code generated by the command above; see README.md. DO NOT EDIT. // +build mipsle,linux @@ -372,4 +372,6 @@ const ( SYS_PKEY_ALLOC = 4364 SYS_PKEY_FREE = 4365 SYS_STATX = 4366 + SYS_RSEQ = 4367 + SYS_IO_PGETEVENTS = 4368 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go index dfe5dab67e..ec5bde3d56 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go @@ -1,4 +1,4 @@ -// linux/mksysnum.pl -Wall -Werror -static -I/tmp/include /tmp/include/asm/unistd.h +// go run linux/mksysnum.go -Wall -Werror -static -I/tmp/include /tmp/include/asm/unistd.h // Code generated by the command above; see README.md. DO NOT EDIT. // +build ppc64,linux @@ -367,4 +367,9 @@ const ( SYS_PWRITEV2 = 381 SYS_KEXEC_FILE_LOAD = 382 SYS_STATX = 383 + SYS_PKEY_ALLOC = 384 + SYS_PKEY_FREE = 385 + SYS_PKEY_MPROTECT = 386 + SYS_RSEQ = 387 + SYS_IO_PGETEVENTS = 388 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go index eca97f738b..bdbabdbcdb 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go @@ -1,4 +1,4 @@ -// linux/mksysnum.pl -Wall -Werror -static -I/tmp/include /tmp/include/asm/unistd.h +// go run linux/mksysnum.go -Wall -Werror -static -I/tmp/include /tmp/include/asm/unistd.h // Code generated by the command above; see README.md. DO NOT EDIT. // +build ppc64le,linux @@ -367,4 +367,9 @@ const ( SYS_PWRITEV2 = 381 SYS_KEXEC_FILE_LOAD = 382 SYS_STATX = 383 + SYS_PKEY_ALLOC = 384 + SYS_PKEY_FREE = 385 + SYS_PKEY_MPROTECT = 386 + SYS_RSEQ = 387 + SYS_IO_PGETEVENTS = 388 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go new file mode 100644 index 0000000000..473c74613f --- /dev/null +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go @@ -0,0 +1,287 @@ +// go run linux/mksysnum.go -Wall -Werror -static -I/tmp/include /tmp/include/asm/unistd.h +// Code generated by the command above; see README.md. DO NOT EDIT. + +// +build riscv64,linux + +package unix + +const ( + SYS_IO_SETUP = 0 + SYS_IO_DESTROY = 1 + SYS_IO_SUBMIT = 2 + SYS_IO_CANCEL = 3 + SYS_IO_GETEVENTS = 4 + SYS_SETXATTR = 5 + SYS_LSETXATTR = 6 + SYS_FSETXATTR = 7 + SYS_GETXATTR = 8 + SYS_LGETXATTR = 9 + SYS_FGETXATTR = 10 + SYS_LISTXATTR = 11 + SYS_LLISTXATTR = 12 + SYS_FLISTXATTR = 13 + SYS_REMOVEXATTR = 14 + SYS_LREMOVEXATTR = 15 + SYS_FREMOVEXATTR = 16 + SYS_GETCWD = 17 + SYS_LOOKUP_DCOOKIE = 18 + SYS_EVENTFD2 = 19 + SYS_EPOLL_CREATE1 = 20 + SYS_EPOLL_CTL = 21 + SYS_EPOLL_PWAIT = 22 + SYS_DUP = 23 + SYS_DUP3 = 24 + SYS_FCNTL = 25 + SYS_INOTIFY_INIT1 = 26 + SYS_INOTIFY_ADD_WATCH = 27 + SYS_INOTIFY_RM_WATCH = 28 + SYS_IOCTL = 29 + SYS_IOPRIO_SET = 30 + SYS_IOPRIO_GET = 31 + SYS_FLOCK = 32 + SYS_MKNODAT = 33 + SYS_MKDIRAT = 34 + SYS_UNLINKAT = 35 + SYS_SYMLINKAT = 36 + SYS_LINKAT = 37 + SYS_UMOUNT2 = 39 + SYS_MOUNT = 40 + SYS_PIVOT_ROOT = 41 + SYS_NFSSERVCTL = 42 + SYS_STATFS = 43 + SYS_FSTATFS = 44 + SYS_TRUNCATE = 45 + SYS_FTRUNCATE = 46 + SYS_FALLOCATE = 47 + SYS_FACCESSAT = 48 + SYS_CHDIR = 49 + SYS_FCHDIR = 50 + SYS_CHROOT = 51 + SYS_FCHMOD = 52 + SYS_FCHMODAT = 53 + SYS_FCHOWNAT = 54 + SYS_FCHOWN = 55 + SYS_OPENAT = 56 + SYS_CLOSE = 57 + SYS_VHANGUP = 58 + SYS_PIPE2 = 59 + SYS_QUOTACTL = 60 + SYS_GETDENTS64 = 61 + SYS_LSEEK = 62 + SYS_READ = 63 + SYS_WRITE = 64 + SYS_READV = 65 + SYS_WRITEV = 66 + SYS_PREAD64 = 67 + SYS_PWRITE64 = 68 + SYS_PREADV = 69 + SYS_PWRITEV = 70 + SYS_SENDFILE = 71 + SYS_PSELECT6 = 72 + SYS_PPOLL = 73 + SYS_SIGNALFD4 = 74 + SYS_VMSPLICE = 75 + SYS_SPLICE = 76 + SYS_TEE = 77 + SYS_READLINKAT = 78 + SYS_FSTATAT = 79 + SYS_FSTAT = 80 + SYS_SYNC = 81 + SYS_FSYNC = 82 + SYS_FDATASYNC = 83 + SYS_SYNC_FILE_RANGE = 84 + SYS_TIMERFD_CREATE = 85 + SYS_TIMERFD_SETTIME = 86 + SYS_TIMERFD_GETTIME = 87 + SYS_UTIMENSAT = 88 + SYS_ACCT = 89 + SYS_CAPGET = 90 + SYS_CAPSET = 91 + SYS_PERSONALITY = 92 + SYS_EXIT = 93 + SYS_EXIT_GROUP = 94 + SYS_WAITID = 95 + SYS_SET_TID_ADDRESS = 96 + SYS_UNSHARE = 97 + SYS_FUTEX = 98 + SYS_SET_ROBUST_LIST = 99 + SYS_GET_ROBUST_LIST = 100 + SYS_NANOSLEEP = 101 + SYS_GETITIMER = 102 + SYS_SETITIMER = 103 + SYS_KEXEC_LOAD = 104 + SYS_INIT_MODULE = 105 + SYS_DELETE_MODULE = 106 + SYS_TIMER_CREATE = 107 + SYS_TIMER_GETTIME = 108 + SYS_TIMER_GETOVERRUN = 109 + SYS_TIMER_SETTIME = 110 + SYS_TIMER_DELETE = 111 + SYS_CLOCK_SETTIME = 112 + SYS_CLOCK_GETTIME = 113 + SYS_CLOCK_GETRES = 114 + SYS_CLOCK_NANOSLEEP = 115 + SYS_SYSLOG = 116 + SYS_PTRACE = 117 + SYS_SCHED_SETPARAM = 118 + SYS_SCHED_SETSCHEDULER = 119 + SYS_SCHED_GETSCHEDULER = 120 + SYS_SCHED_GETPARAM = 121 + SYS_SCHED_SETAFFINITY = 122 + SYS_SCHED_GETAFFINITY = 123 + SYS_SCHED_YIELD = 124 + SYS_SCHED_GET_PRIORITY_MAX = 125 + SYS_SCHED_GET_PRIORITY_MIN = 126 + SYS_SCHED_RR_GET_INTERVAL = 127 + SYS_RESTART_SYSCALL = 128 + SYS_KILL = 129 + SYS_TKILL = 130 + SYS_TGKILL = 131 + SYS_SIGALTSTACK = 132 + SYS_RT_SIGSUSPEND = 133 + SYS_RT_SIGACTION = 134 + SYS_RT_SIGPROCMASK = 135 + SYS_RT_SIGPENDING = 136 + SYS_RT_SIGTIMEDWAIT = 137 + SYS_RT_SIGQUEUEINFO = 138 + SYS_RT_SIGRETURN = 139 + SYS_SETPRIORITY = 140 + SYS_GETPRIORITY = 141 + SYS_REBOOT = 142 + SYS_SETREGID = 143 + SYS_SETGID = 144 + SYS_SETREUID = 145 + SYS_SETUID = 146 + SYS_SETRESUID = 147 + SYS_GETRESUID = 148 + SYS_SETRESGID = 149 + SYS_GETRESGID = 150 + SYS_SETFSUID = 151 + SYS_SETFSGID = 152 + SYS_TIMES = 153 + SYS_SETPGID = 154 + SYS_GETPGID = 155 + SYS_GETSID = 156 + SYS_SETSID = 157 + SYS_GETGROUPS = 158 + SYS_SETGROUPS = 159 + SYS_UNAME = 160 + SYS_SETHOSTNAME = 161 + SYS_SETDOMAINNAME = 162 + SYS_GETRLIMIT = 163 + SYS_SETRLIMIT = 164 + SYS_GETRUSAGE = 165 + SYS_UMASK = 166 + SYS_PRCTL = 167 + SYS_GETCPU = 168 + SYS_GETTIMEOFDAY = 169 + SYS_SETTIMEOFDAY = 170 + SYS_ADJTIMEX = 171 + SYS_GETPID = 172 + SYS_GETPPID = 173 + SYS_GETUID = 174 + SYS_GETEUID = 175 + SYS_GETGID = 176 + SYS_GETEGID = 177 + SYS_GETTID = 178 + SYS_SYSINFO = 179 + SYS_MQ_OPEN = 180 + SYS_MQ_UNLINK = 181 + SYS_MQ_TIMEDSEND = 182 + SYS_MQ_TIMEDRECEIVE = 183 + SYS_MQ_NOTIFY = 184 + SYS_MQ_GETSETATTR = 185 + SYS_MSGGET = 186 + SYS_MSGCTL = 187 + SYS_MSGRCV = 188 + SYS_MSGSND = 189 + SYS_SEMGET = 190 + SYS_SEMCTL = 191 + SYS_SEMTIMEDOP = 192 + SYS_SEMOP = 193 + SYS_SHMGET = 194 + SYS_SHMCTL = 195 + SYS_SHMAT = 196 + SYS_SHMDT = 197 + SYS_SOCKET = 198 + SYS_SOCKETPAIR = 199 + SYS_BIND = 200 + SYS_LISTEN = 201 + SYS_ACCEPT = 202 + SYS_CONNECT = 203 + SYS_GETSOCKNAME = 204 + SYS_GETPEERNAME = 205 + SYS_SENDTO = 206 + SYS_RECVFROM = 207 + SYS_SETSOCKOPT = 208 + SYS_GETSOCKOPT = 209 + SYS_SHUTDOWN = 210 + SYS_SENDMSG = 211 + SYS_RECVMSG = 212 + SYS_READAHEAD = 213 + SYS_BRK = 214 + SYS_MUNMAP = 215 + SYS_MREMAP = 216 + SYS_ADD_KEY = 217 + SYS_REQUEST_KEY = 218 + SYS_KEYCTL = 219 + SYS_CLONE = 220 + SYS_EXECVE = 221 + SYS_MMAP = 222 + SYS_FADVISE64 = 223 + SYS_SWAPON = 224 + SYS_SWAPOFF = 225 + SYS_MPROTECT = 226 + SYS_MSYNC = 227 + SYS_MLOCK = 228 + SYS_MUNLOCK = 229 + SYS_MLOCKALL = 230 + SYS_MUNLOCKALL = 231 + SYS_MINCORE = 232 + SYS_MADVISE = 233 + SYS_REMAP_FILE_PAGES = 234 + SYS_MBIND = 235 + SYS_GET_MEMPOLICY = 236 + SYS_SET_MEMPOLICY = 237 + SYS_MIGRATE_PAGES = 238 + SYS_MOVE_PAGES = 239 + SYS_RT_TGSIGQUEUEINFO = 240 + SYS_PERF_EVENT_OPEN = 241 + SYS_ACCEPT4 = 242 + SYS_RECVMMSG = 243 + SYS_ARCH_SPECIFIC_SYSCALL = 244 + SYS_WAIT4 = 260 + SYS_PRLIMIT64 = 261 + SYS_FANOTIFY_INIT = 262 + SYS_FANOTIFY_MARK = 263 + SYS_NAME_TO_HANDLE_AT = 264 + SYS_OPEN_BY_HANDLE_AT = 265 + SYS_CLOCK_ADJTIME = 266 + SYS_SYNCFS = 267 + SYS_SETNS = 268 + SYS_SENDMMSG = 269 + SYS_PROCESS_VM_READV = 270 + SYS_PROCESS_VM_WRITEV = 271 + SYS_KCMP = 272 + SYS_FINIT_MODULE = 273 + SYS_SCHED_SETATTR = 274 + SYS_SCHED_GETATTR = 275 + SYS_RENAMEAT2 = 276 + SYS_SECCOMP = 277 + SYS_GETRANDOM = 278 + SYS_MEMFD_CREATE = 279 + SYS_BPF = 280 + SYS_EXECVEAT = 281 + SYS_USERFAULTFD = 282 + SYS_MEMBARRIER = 283 + SYS_MLOCK2 = 284 + SYS_COPY_FILE_RANGE = 285 + SYS_PREADV2 = 286 + SYS_PWRITEV2 = 287 + SYS_PKEY_MPROTECT = 288 + SYS_PKEY_ALLOC = 289 + SYS_PKEY_FREE = 290 + SYS_STATX = 291 + SYS_IO_PGETEVENTS = 292 + SYS_RSEQ = 293 +) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go index 8ea18e6c25..6eb7c257f8 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go @@ -1,4 +1,4 @@ -// linux/mksysnum.pl -Wall -Werror -static -I/tmp/include -fsigned-char /tmp/include/asm/unistd.h +// go run linux/mksysnum.go -Wall -Werror -static -I/tmp/include -fsigned-char /tmp/include/asm/unistd.h // Code generated by the command above; see README.md. DO NOT EDIT. // +build s390x,linux @@ -109,6 +109,7 @@ const ( SYS_PERSONALITY = 136 SYS_AFS_SYSCALL = 137 SYS_GETDENTS = 141 + SYS_SELECT = 142 SYS_FLOCK = 143 SYS_MSYNC = 144 SYS_READV = 145 @@ -151,6 +152,26 @@ const ( SYS_GETPMSG = 188 SYS_PUTPMSG = 189 SYS_VFORK = 190 + SYS_GETRLIMIT = 191 + SYS_LCHOWN = 198 + SYS_GETUID = 199 + SYS_GETGID = 200 + SYS_GETEUID = 201 + SYS_GETEGID = 202 + SYS_SETREUID = 203 + SYS_SETREGID = 204 + SYS_GETGROUPS = 205 + SYS_SETGROUPS = 206 + SYS_FCHOWN = 207 + SYS_SETRESUID = 208 + SYS_GETRESUID = 209 + SYS_SETRESGID = 210 + SYS_GETRESGID = 211 + SYS_CHOWN = 212 + SYS_SETUID = 213 + SYS_SETGID = 214 + SYS_SETFSUID = 215 + SYS_SETFSGID = 216 SYS_PIVOT_ROOT = 217 SYS_MINCORE = 218 SYS_MADVISE = 219 @@ -222,6 +243,7 @@ const ( SYS_MKNODAT = 290 SYS_FCHOWNAT = 291 SYS_FUTIMESAT = 292 + SYS_NEWFSTATAT = 293 SYS_UNLINKAT = 294 SYS_RENAMEAT = 295 SYS_LINKAT = 296 @@ -308,26 +330,8 @@ const ( SYS_PWRITEV2 = 377 SYS_S390_GUARDED_STORAGE = 378 SYS_STATX = 379 - SYS_SELECT = 142 - SYS_GETRLIMIT = 191 - SYS_LCHOWN = 198 - SYS_GETUID = 199 - SYS_GETGID = 200 - SYS_GETEUID = 201 - SYS_GETEGID = 202 - SYS_SETREUID = 203 - SYS_SETREGID = 204 - SYS_GETGROUPS = 205 - SYS_SETGROUPS = 206 - SYS_FCHOWN = 207 - SYS_SETRESUID = 208 - SYS_GETRESUID = 209 - SYS_SETRESGID = 210 - SYS_GETRESGID = 211 - SYS_CHOWN = 212 - SYS_SETUID = 213 - SYS_SETGID = 214 - SYS_SETFSUID = 215 - SYS_SETFSGID = 216 - SYS_NEWFSTATAT = 293 + SYS_S390_STHYI = 380 + SYS_KEXEC_FILE_LOAD = 381 + SYS_IO_PGETEVENTS = 382 + SYS_RSEQ = 383 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go index c9c129dc42..93480fcb16 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go @@ -1,5 +1,5 @@ -// mksysnum_linux.pl -Ilinux/usr/include -m64 -D__arch64__ linux/usr/include/asm/unistd.h -// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// go run linux/mksysnum.go -Wall -Werror -static -I/tmp/include /tmp/include/asm/unistd.h +// Code generated by the command above; see README.md. DO NOT EDIT. // +build sparc64,linux @@ -345,4 +345,6 @@ const ( SYS_COPY_FILE_RANGE = 357 SYS_PREADV2 = 358 SYS_PWRITEV2 = 359 + SYS_STATX = 360 + SYS_IO_PGETEVENTS = 361 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_netbsd_386.go b/vendor/golang.org/x/sys/unix/zsysnum_netbsd_386.go index 8afda9c451..e66a8c9d39 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_netbsd_386.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_netbsd_386.go @@ -1,5 +1,5 @@ -// mksysnum_netbsd.pl -// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// go run mksysnum.go http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master +// Code generated by the command above; see README.md. DO NOT EDIT. // +build 386,netbsd diff --git a/vendor/golang.org/x/sys/unix/zsysnum_netbsd_amd64.go b/vendor/golang.org/x/sys/unix/zsysnum_netbsd_amd64.go index aea8dbec43..42c788f249 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_netbsd_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_netbsd_amd64.go @@ -1,5 +1,5 @@ -// mksysnum_netbsd.pl -// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// go run mksysnum.go http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master +// Code generated by the command above; see README.md. DO NOT EDIT. // +build amd64,netbsd diff --git a/vendor/golang.org/x/sys/unix/zsysnum_netbsd_arm.go b/vendor/golang.org/x/sys/unix/zsysnum_netbsd_arm.go index c6158a7ef9..0a0757179b 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_netbsd_arm.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_netbsd_arm.go @@ -1,5 +1,5 @@ -// mksysnum_netbsd.pl -// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// go run mksysnum.go http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master +// Code generated by the command above; see README.md. DO NOT EDIT. // +build arm,netbsd diff --git a/vendor/golang.org/x/sys/unix/zsysnum_netbsd_arm64.go b/vendor/golang.org/x/sys/unix/zsysnum_netbsd_arm64.go new file mode 100644 index 0000000000..0291c0931b --- /dev/null +++ b/vendor/golang.org/x/sys/unix/zsysnum_netbsd_arm64.go @@ -0,0 +1,274 @@ +// go run mksysnum.go http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master +// Code generated by the command above; DO NOT EDIT. + +// +build arm64,netbsd + +package unix + +const ( + SYS_EXIT = 1 // { void|sys||exit(int rval); } + SYS_FORK = 2 // { int|sys||fork(void); } + SYS_READ = 3 // { ssize_t|sys||read(int fd, void *buf, size_t nbyte); } + SYS_WRITE = 4 // { ssize_t|sys||write(int fd, const void *buf, size_t nbyte); } + SYS_OPEN = 5 // { int|sys||open(const char *path, int flags, ... mode_t mode); } + SYS_CLOSE = 6 // { int|sys||close(int fd); } + SYS_LINK = 9 // { int|sys||link(const char *path, const char *link); } + SYS_UNLINK = 10 // { int|sys||unlink(const char *path); } + SYS_CHDIR = 12 // { int|sys||chdir(const char *path); } + SYS_FCHDIR = 13 // { int|sys||fchdir(int fd); } + SYS_CHMOD = 15 // { int|sys||chmod(const char *path, mode_t mode); } + SYS_CHOWN = 16 // { int|sys||chown(const char *path, uid_t uid, gid_t gid); } + SYS_BREAK = 17 // { int|sys||obreak(char *nsize); } + SYS_GETPID = 20 // { pid_t|sys||getpid_with_ppid(void); } + SYS_UNMOUNT = 22 // { int|sys||unmount(const char *path, int flags); } + SYS_SETUID = 23 // { int|sys||setuid(uid_t uid); } + SYS_GETUID = 24 // { uid_t|sys||getuid_with_euid(void); } + SYS_GETEUID = 25 // { uid_t|sys||geteuid(void); } + SYS_PTRACE = 26 // { int|sys||ptrace(int req, pid_t pid, void *addr, int data); } + SYS_RECVMSG = 27 // { ssize_t|sys||recvmsg(int s, struct msghdr *msg, int flags); } + SYS_SENDMSG = 28 // { ssize_t|sys||sendmsg(int s, const struct msghdr *msg, int flags); } + SYS_RECVFROM = 29 // { ssize_t|sys||recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlenaddr); } + SYS_ACCEPT = 30 // { int|sys||accept(int s, struct sockaddr *name, socklen_t *anamelen); } + SYS_GETPEERNAME = 31 // { int|sys||getpeername(int fdes, struct sockaddr *asa, socklen_t *alen); } + SYS_GETSOCKNAME = 32 // { int|sys||getsockname(int fdes, struct sockaddr *asa, socklen_t *alen); } + SYS_ACCESS = 33 // { int|sys||access(const char *path, int flags); } + SYS_CHFLAGS = 34 // { int|sys||chflags(const char *path, u_long flags); } + SYS_FCHFLAGS = 35 // { int|sys||fchflags(int fd, u_long flags); } + SYS_SYNC = 36 // { void|sys||sync(void); } + SYS_KILL = 37 // { int|sys||kill(pid_t pid, int signum); } + SYS_GETPPID = 39 // { pid_t|sys||getppid(void); } + SYS_DUP = 41 // { int|sys||dup(int fd); } + SYS_PIPE = 42 // { int|sys||pipe(void); } + SYS_GETEGID = 43 // { gid_t|sys||getegid(void); } + SYS_PROFIL = 44 // { int|sys||profil(char *samples, size_t size, u_long offset, u_int scale); } + SYS_KTRACE = 45 // { int|sys||ktrace(const char *fname, int ops, int facs, pid_t pid); } + SYS_GETGID = 47 // { gid_t|sys||getgid_with_egid(void); } + SYS___GETLOGIN = 49 // { int|sys||__getlogin(char *namebuf, size_t namelen); } + SYS___SETLOGIN = 50 // { int|sys||__setlogin(const char *namebuf); } + SYS_ACCT = 51 // { int|sys||acct(const char *path); } + SYS_IOCTL = 54 // { int|sys||ioctl(int fd, u_long com, ... void *data); } + SYS_REVOKE = 56 // { int|sys||revoke(const char *path); } + SYS_SYMLINK = 57 // { int|sys||symlink(const char *path, const char *link); } + SYS_READLINK = 58 // { ssize_t|sys||readlink(const char *path, char *buf, size_t count); } + SYS_EXECVE = 59 // { int|sys||execve(const char *path, char * const *argp, char * const *envp); } + SYS_UMASK = 60 // { mode_t|sys||umask(mode_t newmask); } + SYS_CHROOT = 61 // { int|sys||chroot(const char *path); } + SYS_VFORK = 66 // { int|sys||vfork(void); } + SYS_SBRK = 69 // { int|sys||sbrk(intptr_t incr); } + SYS_SSTK = 70 // { int|sys||sstk(int incr); } + SYS_VADVISE = 72 // { int|sys||ovadvise(int anom); } + SYS_MUNMAP = 73 // { int|sys||munmap(void *addr, size_t len); } + SYS_MPROTECT = 74 // { int|sys||mprotect(void *addr, size_t len, int prot); } + SYS_MADVISE = 75 // { int|sys||madvise(void *addr, size_t len, int behav); } + SYS_MINCORE = 78 // { int|sys||mincore(void *addr, size_t len, char *vec); } + SYS_GETGROUPS = 79 // { int|sys||getgroups(int gidsetsize, gid_t *gidset); } + SYS_SETGROUPS = 80 // { int|sys||setgroups(int gidsetsize, const gid_t *gidset); } + SYS_GETPGRP = 81 // { int|sys||getpgrp(void); } + SYS_SETPGID = 82 // { int|sys||setpgid(pid_t pid, pid_t pgid); } + SYS_DUP2 = 90 // { int|sys||dup2(int from, int to); } + SYS_FCNTL = 92 // { int|sys||fcntl(int fd, int cmd, ... void *arg); } + SYS_FSYNC = 95 // { int|sys||fsync(int fd); } + SYS_SETPRIORITY = 96 // { int|sys||setpriority(int which, id_t who, int prio); } + SYS_CONNECT = 98 // { int|sys||connect(int s, const struct sockaddr *name, socklen_t namelen); } + SYS_GETPRIORITY = 100 // { int|sys||getpriority(int which, id_t who); } + SYS_BIND = 104 // { int|sys||bind(int s, const struct sockaddr *name, socklen_t namelen); } + SYS_SETSOCKOPT = 105 // { int|sys||setsockopt(int s, int level, int name, const void *val, socklen_t valsize); } + SYS_LISTEN = 106 // { int|sys||listen(int s, int backlog); } + SYS_GETSOCKOPT = 118 // { int|sys||getsockopt(int s, int level, int name, void *val, socklen_t *avalsize); } + SYS_READV = 120 // { ssize_t|sys||readv(int fd, const struct iovec *iovp, int iovcnt); } + SYS_WRITEV = 121 // { ssize_t|sys||writev(int fd, const struct iovec *iovp, int iovcnt); } + SYS_FCHOWN = 123 // { int|sys||fchown(int fd, uid_t uid, gid_t gid); } + SYS_FCHMOD = 124 // { int|sys||fchmod(int fd, mode_t mode); } + SYS_SETREUID = 126 // { int|sys||setreuid(uid_t ruid, uid_t euid); } + SYS_SETREGID = 127 // { int|sys||setregid(gid_t rgid, gid_t egid); } + SYS_RENAME = 128 // { int|sys||rename(const char *from, const char *to); } + SYS_FLOCK = 131 // { int|sys||flock(int fd, int how); } + SYS_MKFIFO = 132 // { int|sys||mkfifo(const char *path, mode_t mode); } + SYS_SENDTO = 133 // { ssize_t|sys||sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen); } + SYS_SHUTDOWN = 134 // { int|sys||shutdown(int s, int how); } + SYS_SOCKETPAIR = 135 // { int|sys||socketpair(int domain, int type, int protocol, int *rsv); } + SYS_MKDIR = 136 // { int|sys||mkdir(const char *path, mode_t mode); } + SYS_RMDIR = 137 // { int|sys||rmdir(const char *path); } + SYS_SETSID = 147 // { int|sys||setsid(void); } + SYS_SYSARCH = 165 // { int|sys||sysarch(int op, void *parms); } + SYS_PREAD = 173 // { ssize_t|sys||pread(int fd, void *buf, size_t nbyte, int PAD, off_t offset); } + SYS_PWRITE = 174 // { ssize_t|sys||pwrite(int fd, const void *buf, size_t nbyte, int PAD, off_t offset); } + SYS_NTP_ADJTIME = 176 // { int|sys||ntp_adjtime(struct timex *tp); } + SYS_SETGID = 181 // { int|sys||setgid(gid_t gid); } + SYS_SETEGID = 182 // { int|sys||setegid(gid_t egid); } + SYS_SETEUID = 183 // { int|sys||seteuid(uid_t euid); } + SYS_PATHCONF = 191 // { long|sys||pathconf(const char *path, int name); } + SYS_FPATHCONF = 192 // { long|sys||fpathconf(int fd, int name); } + SYS_GETRLIMIT = 194 // { int|sys||getrlimit(int which, struct rlimit *rlp); } + SYS_SETRLIMIT = 195 // { int|sys||setrlimit(int which, const struct rlimit *rlp); } + SYS_MMAP = 197 // { void *|sys||mmap(void *addr, size_t len, int prot, int flags, int fd, long PAD, off_t pos); } + SYS_LSEEK = 199 // { off_t|sys||lseek(int fd, int PAD, off_t offset, int whence); } + SYS_TRUNCATE = 200 // { int|sys||truncate(const char *path, int PAD, off_t length); } + SYS_FTRUNCATE = 201 // { int|sys||ftruncate(int fd, int PAD, off_t length); } + SYS___SYSCTL = 202 // { int|sys||__sysctl(const int *name, u_int namelen, void *old, size_t *oldlenp, const void *new, size_t newlen); } + SYS_MLOCK = 203 // { int|sys||mlock(const void *addr, size_t len); } + SYS_MUNLOCK = 204 // { int|sys||munlock(const void *addr, size_t len); } + SYS_UNDELETE = 205 // { int|sys||undelete(const char *path); } + SYS_GETPGID = 207 // { pid_t|sys||getpgid(pid_t pid); } + SYS_REBOOT = 208 // { int|sys||reboot(int opt, char *bootstr); } + SYS_POLL = 209 // { int|sys||poll(struct pollfd *fds, u_int nfds, int timeout); } + SYS_SEMGET = 221 // { int|sys||semget(key_t key, int nsems, int semflg); } + SYS_SEMOP = 222 // { int|sys||semop(int semid, struct sembuf *sops, size_t nsops); } + SYS_SEMCONFIG = 223 // { int|sys||semconfig(int flag); } + SYS_MSGGET = 225 // { int|sys||msgget(key_t key, int msgflg); } + SYS_MSGSND = 226 // { int|sys||msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); } + SYS_MSGRCV = 227 // { ssize_t|sys||msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); } + SYS_SHMAT = 228 // { void *|sys||shmat(int shmid, const void *shmaddr, int shmflg); } + SYS_SHMDT = 230 // { int|sys||shmdt(const void *shmaddr); } + SYS_SHMGET = 231 // { int|sys||shmget(key_t key, size_t size, int shmflg); } + SYS_TIMER_CREATE = 235 // { int|sys||timer_create(clockid_t clock_id, struct sigevent *evp, timer_t *timerid); } + SYS_TIMER_DELETE = 236 // { int|sys||timer_delete(timer_t timerid); } + SYS_TIMER_GETOVERRUN = 239 // { int|sys||timer_getoverrun(timer_t timerid); } + SYS_FDATASYNC = 241 // { int|sys||fdatasync(int fd); } + SYS_MLOCKALL = 242 // { int|sys||mlockall(int flags); } + SYS_MUNLOCKALL = 243 // { int|sys||munlockall(void); } + SYS_SIGQUEUEINFO = 245 // { int|sys||sigqueueinfo(pid_t pid, const siginfo_t *info); } + SYS_MODCTL = 246 // { int|sys||modctl(int cmd, void *arg); } + SYS___POSIX_RENAME = 270 // { int|sys||__posix_rename(const char *from, const char *to); } + SYS_SWAPCTL = 271 // { int|sys||swapctl(int cmd, void *arg, int misc); } + SYS_MINHERIT = 273 // { int|sys||minherit(void *addr, size_t len, int inherit); } + SYS_LCHMOD = 274 // { int|sys||lchmod(const char *path, mode_t mode); } + SYS_LCHOWN = 275 // { int|sys||lchown(const char *path, uid_t uid, gid_t gid); } + SYS_MSYNC = 277 // { int|sys|13|msync(void *addr, size_t len, int flags); } + SYS___POSIX_CHOWN = 283 // { int|sys||__posix_chown(const char *path, uid_t uid, gid_t gid); } + SYS___POSIX_FCHOWN = 284 // { int|sys||__posix_fchown(int fd, uid_t uid, gid_t gid); } + SYS___POSIX_LCHOWN = 285 // { int|sys||__posix_lchown(const char *path, uid_t uid, gid_t gid); } + SYS_GETSID = 286 // { pid_t|sys||getsid(pid_t pid); } + SYS___CLONE = 287 // { pid_t|sys||__clone(int flags, void *stack); } + SYS_FKTRACE = 288 // { int|sys||fktrace(int fd, int ops, int facs, pid_t pid); } + SYS_PREADV = 289 // { ssize_t|sys||preadv(int fd, const struct iovec *iovp, int iovcnt, int PAD, off_t offset); } + SYS_PWRITEV = 290 // { ssize_t|sys||pwritev(int fd, const struct iovec *iovp, int iovcnt, int PAD, off_t offset); } + SYS___GETCWD = 296 // { int|sys||__getcwd(char *bufp, size_t length); } + SYS_FCHROOT = 297 // { int|sys||fchroot(int fd); } + SYS_LCHFLAGS = 304 // { int|sys||lchflags(const char *path, u_long flags); } + SYS_ISSETUGID = 305 // { int|sys||issetugid(void); } + SYS_UTRACE = 306 // { int|sys||utrace(const char *label, void *addr, size_t len); } + SYS_GETCONTEXT = 307 // { int|sys||getcontext(struct __ucontext *ucp); } + SYS_SETCONTEXT = 308 // { int|sys||setcontext(const struct __ucontext *ucp); } + SYS__LWP_CREATE = 309 // { int|sys||_lwp_create(const struct __ucontext *ucp, u_long flags, lwpid_t *new_lwp); } + SYS__LWP_EXIT = 310 // { int|sys||_lwp_exit(void); } + SYS__LWP_SELF = 311 // { lwpid_t|sys||_lwp_self(void); } + SYS__LWP_WAIT = 312 // { int|sys||_lwp_wait(lwpid_t wait_for, lwpid_t *departed); } + SYS__LWP_SUSPEND = 313 // { int|sys||_lwp_suspend(lwpid_t target); } + SYS__LWP_CONTINUE = 314 // { int|sys||_lwp_continue(lwpid_t target); } + SYS__LWP_WAKEUP = 315 // { int|sys||_lwp_wakeup(lwpid_t target); } + SYS__LWP_GETPRIVATE = 316 // { void *|sys||_lwp_getprivate(void); } + SYS__LWP_SETPRIVATE = 317 // { void|sys||_lwp_setprivate(void *ptr); } + SYS__LWP_KILL = 318 // { int|sys||_lwp_kill(lwpid_t target, int signo); } + SYS__LWP_DETACH = 319 // { int|sys||_lwp_detach(lwpid_t target); } + SYS__LWP_UNPARK = 321 // { int|sys||_lwp_unpark(lwpid_t target, const void *hint); } + SYS__LWP_UNPARK_ALL = 322 // { ssize_t|sys||_lwp_unpark_all(const lwpid_t *targets, size_t ntargets, const void *hint); } + SYS__LWP_SETNAME = 323 // { int|sys||_lwp_setname(lwpid_t target, const char *name); } + SYS__LWP_GETNAME = 324 // { int|sys||_lwp_getname(lwpid_t target, char *name, size_t len); } + SYS__LWP_CTL = 325 // { int|sys||_lwp_ctl(int features, struct lwpctl **address); } + SYS___SIGACTION_SIGTRAMP = 340 // { int|sys||__sigaction_sigtramp(int signum, const struct sigaction *nsa, struct sigaction *osa, const void *tramp, int vers); } + SYS_PMC_GET_INFO = 341 // { int|sys||pmc_get_info(int ctr, int op, void *args); } + SYS_PMC_CONTROL = 342 // { int|sys||pmc_control(int ctr, int op, void *args); } + SYS_RASCTL = 343 // { int|sys||rasctl(void *addr, size_t len, int op); } + SYS_KQUEUE = 344 // { int|sys||kqueue(void); } + SYS__SCHED_SETPARAM = 346 // { int|sys||_sched_setparam(pid_t pid, lwpid_t lid, int policy, const struct sched_param *params); } + SYS__SCHED_GETPARAM = 347 // { int|sys||_sched_getparam(pid_t pid, lwpid_t lid, int *policy, struct sched_param *params); } + SYS__SCHED_SETAFFINITY = 348 // { int|sys||_sched_setaffinity(pid_t pid, lwpid_t lid, size_t size, const cpuset_t *cpuset); } + SYS__SCHED_GETAFFINITY = 349 // { int|sys||_sched_getaffinity(pid_t pid, lwpid_t lid, size_t size, cpuset_t *cpuset); } + SYS_SCHED_YIELD = 350 // { int|sys||sched_yield(void); } + SYS_FSYNC_RANGE = 354 // { int|sys||fsync_range(int fd, int flags, off_t start, off_t length); } + SYS_UUIDGEN = 355 // { int|sys||uuidgen(struct uuid *store, int count); } + SYS_GETVFSSTAT = 356 // { int|sys||getvfsstat(struct statvfs *buf, size_t bufsize, int flags); } + SYS_STATVFS1 = 357 // { int|sys||statvfs1(const char *path, struct statvfs *buf, int flags); } + SYS_FSTATVFS1 = 358 // { int|sys||fstatvfs1(int fd, struct statvfs *buf, int flags); } + SYS_EXTATTRCTL = 360 // { int|sys||extattrctl(const char *path, int cmd, const char *filename, int attrnamespace, const char *attrname); } + SYS_EXTATTR_SET_FILE = 361 // { int|sys||extattr_set_file(const char *path, int attrnamespace, const char *attrname, const void *data, size_t nbytes); } + SYS_EXTATTR_GET_FILE = 362 // { ssize_t|sys||extattr_get_file(const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes); } + SYS_EXTATTR_DELETE_FILE = 363 // { int|sys||extattr_delete_file(const char *path, int attrnamespace, const char *attrname); } + SYS_EXTATTR_SET_FD = 364 // { int|sys||extattr_set_fd(int fd, int attrnamespace, const char *attrname, const void *data, size_t nbytes); } + SYS_EXTATTR_GET_FD = 365 // { ssize_t|sys||extattr_get_fd(int fd, int attrnamespace, const char *attrname, void *data, size_t nbytes); } + SYS_EXTATTR_DELETE_FD = 366 // { int|sys||extattr_delete_fd(int fd, int attrnamespace, const char *attrname); } + SYS_EXTATTR_SET_LINK = 367 // { int|sys||extattr_set_link(const char *path, int attrnamespace, const char *attrname, const void *data, size_t nbytes); } + SYS_EXTATTR_GET_LINK = 368 // { ssize_t|sys||extattr_get_link(const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes); } + SYS_EXTATTR_DELETE_LINK = 369 // { int|sys||extattr_delete_link(const char *path, int attrnamespace, const char *attrname); } + SYS_EXTATTR_LIST_FD = 370 // { ssize_t|sys||extattr_list_fd(int fd, int attrnamespace, void *data, size_t nbytes); } + SYS_EXTATTR_LIST_FILE = 371 // { ssize_t|sys||extattr_list_file(const char *path, int attrnamespace, void *data, size_t nbytes); } + SYS_EXTATTR_LIST_LINK = 372 // { ssize_t|sys||extattr_list_link(const char *path, int attrnamespace, void *data, size_t nbytes); } + SYS_SETXATTR = 375 // { int|sys||setxattr(const char *path, const char *name, const void *value, size_t size, int flags); } + SYS_LSETXATTR = 376 // { int|sys||lsetxattr(const char *path, const char *name, const void *value, size_t size, int flags); } + SYS_FSETXATTR = 377 // { int|sys||fsetxattr(int fd, const char *name, const void *value, size_t size, int flags); } + SYS_GETXATTR = 378 // { int|sys||getxattr(const char *path, const char *name, void *value, size_t size); } + SYS_LGETXATTR = 379 // { int|sys||lgetxattr(const char *path, const char *name, void *value, size_t size); } + SYS_FGETXATTR = 380 // { int|sys||fgetxattr(int fd, const char *name, void *value, size_t size); } + SYS_LISTXATTR = 381 // { int|sys||listxattr(const char *path, char *list, size_t size); } + SYS_LLISTXATTR = 382 // { int|sys||llistxattr(const char *path, char *list, size_t size); } + SYS_FLISTXATTR = 383 // { int|sys||flistxattr(int fd, char *list, size_t size); } + SYS_REMOVEXATTR = 384 // { int|sys||removexattr(const char *path, const char *name); } + SYS_LREMOVEXATTR = 385 // { int|sys||lremovexattr(const char *path, const char *name); } + SYS_FREMOVEXATTR = 386 // { int|sys||fremovexattr(int fd, const char *name); } + SYS_GETDENTS = 390 // { int|sys|30|getdents(int fd, char *buf, size_t count); } + SYS_SOCKET = 394 // { int|sys|30|socket(int domain, int type, int protocol); } + SYS_GETFH = 395 // { int|sys|30|getfh(const char *fname, void *fhp, size_t *fh_size); } + SYS_MOUNT = 410 // { int|sys|50|mount(const char *type, const char *path, int flags, void *data, size_t data_len); } + SYS_MREMAP = 411 // { void *|sys||mremap(void *old_address, size_t old_size, void *new_address, size_t new_size, int flags); } + SYS_PSET_CREATE = 412 // { int|sys||pset_create(psetid_t *psid); } + SYS_PSET_DESTROY = 413 // { int|sys||pset_destroy(psetid_t psid); } + SYS_PSET_ASSIGN = 414 // { int|sys||pset_assign(psetid_t psid, cpuid_t cpuid, psetid_t *opsid); } + SYS__PSET_BIND = 415 // { int|sys||_pset_bind(idtype_t idtype, id_t first_id, id_t second_id, psetid_t psid, psetid_t *opsid); } + SYS_POSIX_FADVISE = 416 // { int|sys|50|posix_fadvise(int fd, int PAD, off_t offset, off_t len, int advice); } + SYS_SELECT = 417 // { int|sys|50|select(int nd, fd_set *in, fd_set *ou, fd_set *ex, struct timeval *tv); } + SYS_GETTIMEOFDAY = 418 // { int|sys|50|gettimeofday(struct timeval *tp, void *tzp); } + SYS_SETTIMEOFDAY = 419 // { int|sys|50|settimeofday(const struct timeval *tv, const void *tzp); } + SYS_UTIMES = 420 // { int|sys|50|utimes(const char *path, const struct timeval *tptr); } + SYS_ADJTIME = 421 // { int|sys|50|adjtime(const struct timeval *delta, struct timeval *olddelta); } + SYS_FUTIMES = 423 // { int|sys|50|futimes(int fd, const struct timeval *tptr); } + SYS_LUTIMES = 424 // { int|sys|50|lutimes(const char *path, const struct timeval *tptr); } + SYS_SETITIMER = 425 // { int|sys|50|setitimer(int which, const struct itimerval *itv, struct itimerval *oitv); } + SYS_GETITIMER = 426 // { int|sys|50|getitimer(int which, struct itimerval *itv); } + SYS_CLOCK_GETTIME = 427 // { int|sys|50|clock_gettime(clockid_t clock_id, struct timespec *tp); } + SYS_CLOCK_SETTIME = 428 // { int|sys|50|clock_settime(clockid_t clock_id, const struct timespec *tp); } + SYS_CLOCK_GETRES = 429 // { int|sys|50|clock_getres(clockid_t clock_id, struct timespec *tp); } + SYS_NANOSLEEP = 430 // { int|sys|50|nanosleep(const struct timespec *rqtp, struct timespec *rmtp); } + SYS___SIGTIMEDWAIT = 431 // { int|sys|50|__sigtimedwait(const sigset_t *set, siginfo_t *info, struct timespec *timeout); } + SYS__LWP_PARK = 434 // { int|sys|50|_lwp_park(const struct timespec *ts, lwpid_t unpark, const void *hint, const void *unparkhint); } + SYS_KEVENT = 435 // { int|sys|50|kevent(int fd, const struct kevent *changelist, size_t nchanges, struct kevent *eventlist, size_t nevents, const struct timespec *timeout); } + SYS_PSELECT = 436 // { int|sys|50|pselect(int nd, fd_set *in, fd_set *ou, fd_set *ex, const struct timespec *ts, const sigset_t *mask); } + SYS_POLLTS = 437 // { int|sys|50|pollts(struct pollfd *fds, u_int nfds, const struct timespec *ts, const sigset_t *mask); } + SYS_STAT = 439 // { int|sys|50|stat(const char *path, struct stat *ub); } + SYS_FSTAT = 440 // { int|sys|50|fstat(int fd, struct stat *sb); } + SYS_LSTAT = 441 // { int|sys|50|lstat(const char *path, struct stat *ub); } + SYS___SEMCTL = 442 // { int|sys|50|__semctl(int semid, int semnum, int cmd, ... union __semun *arg); } + SYS_SHMCTL = 443 // { int|sys|50|shmctl(int shmid, int cmd, struct shmid_ds *buf); } + SYS_MSGCTL = 444 // { int|sys|50|msgctl(int msqid, int cmd, struct msqid_ds *buf); } + SYS_GETRUSAGE = 445 // { int|sys|50|getrusage(int who, struct rusage *rusage); } + SYS_TIMER_SETTIME = 446 // { int|sys|50|timer_settime(timer_t timerid, int flags, const struct itimerspec *value, struct itimerspec *ovalue); } + SYS_TIMER_GETTIME = 447 // { int|sys|50|timer_gettime(timer_t timerid, struct itimerspec *value); } + SYS_NTP_GETTIME = 448 // { int|sys|50|ntp_gettime(struct ntptimeval *ntvp); } + SYS_WAIT4 = 449 // { int|sys|50|wait4(pid_t pid, int *status, int options, struct rusage *rusage); } + SYS_MKNOD = 450 // { int|sys|50|mknod(const char *path, mode_t mode, dev_t dev); } + SYS_FHSTAT = 451 // { int|sys|50|fhstat(const void *fhp, size_t fh_size, struct stat *sb); } + SYS_PIPE2 = 453 // { int|sys||pipe2(int *fildes, int flags); } + SYS_DUP3 = 454 // { int|sys||dup3(int from, int to, int flags); } + SYS_KQUEUE1 = 455 // { int|sys||kqueue1(int flags); } + SYS_PACCEPT = 456 // { int|sys||paccept(int s, struct sockaddr *name, socklen_t *anamelen, const sigset_t *mask, int flags); } + SYS_LINKAT = 457 // { int|sys||linkat(int fd1, const char *name1, int fd2, const char *name2, int flags); } + SYS_RENAMEAT = 458 // { int|sys||renameat(int fromfd, const char *from, int tofd, const char *to); } + SYS_MKFIFOAT = 459 // { int|sys||mkfifoat(int fd, const char *path, mode_t mode); } + SYS_MKNODAT = 460 // { int|sys||mknodat(int fd, const char *path, mode_t mode, uint32_t dev); } + SYS_MKDIRAT = 461 // { int|sys||mkdirat(int fd, const char *path, mode_t mode); } + SYS_FACCESSAT = 462 // { int|sys||faccessat(int fd, const char *path, int amode, int flag); } + SYS_FCHMODAT = 463 // { int|sys||fchmodat(int fd, const char *path, mode_t mode, int flag); } + SYS_FCHOWNAT = 464 // { int|sys||fchownat(int fd, const char *path, uid_t owner, gid_t group, int flag); } + SYS_FEXECVE = 465 // { int|sys||fexecve(int fd, char * const *argp, char * const *envp); } + SYS_FSTATAT = 466 // { int|sys||fstatat(int fd, const char *path, struct stat *buf, int flag); } + SYS_UTIMENSAT = 467 // { int|sys||utimensat(int fd, const char *path, const struct timespec *tptr, int flag); } + SYS_OPENAT = 468 // { int|sys||openat(int fd, const char *path, int oflags, ... mode_t mode); } + SYS_READLINKAT = 469 // { int|sys||readlinkat(int fd, const char *path, char *buf, size_t bufsize); } + SYS_SYMLINKAT = 470 // { int|sys||symlinkat(const char *path1, int fd, const char *path2); } + SYS_UNLINKAT = 471 // { int|sys||unlinkat(int fd, const char *path, int flag); } + SYS_FUTIMENS = 472 // { int|sys||futimens(int fd, const struct timespec *tptr); } + SYS___QUOTACTL = 473 // { int|sys||__quotactl(const char *path, struct quotactl_args *args); } + SYS_POSIX_SPAWN = 474 // { int|sys||posix_spawn(pid_t *pid, const char *path, const struct posix_spawn_file_actions *file_actions, const struct posix_spawnattr *attrp, char *const *argv, char *const *envp); } + SYS_RECVMMSG = 475 // { int|sys||recvmmsg(int s, struct mmsghdr *mmsg, unsigned int vlen, unsigned int flags, struct timespec *timeout); } + SYS_SENDMMSG = 476 // { int|sys||sendmmsg(int s, struct mmsghdr *mmsg, unsigned int vlen, unsigned int flags); } +) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_openbsd_386.go b/vendor/golang.org/x/sys/unix/zsysnum_openbsd_386.go index 3e8ce2a1dd..b0207d1c9b 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_openbsd_386.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_openbsd_386.go @@ -1,5 +1,5 @@ -// mksysnum_openbsd.pl -// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// go run mksysnum.go https://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master +// Code generated by the command above; see README.md. DO NOT EDIT. // +build 386,openbsd @@ -9,109 +9,119 @@ const ( SYS_EXIT = 1 // { void sys_exit(int rval); } SYS_FORK = 2 // { int sys_fork(void); } SYS_READ = 3 // { ssize_t sys_read(int fd, void *buf, size_t nbyte); } - SYS_WRITE = 4 // { ssize_t sys_write(int fd, const void *buf, \ - SYS_OPEN = 5 // { int sys_open(const char *path, \ + SYS_WRITE = 4 // { ssize_t sys_write(int fd, const void *buf, size_t nbyte); } + SYS_OPEN = 5 // { int sys_open(const char *path, int flags, ... mode_t mode); } SYS_CLOSE = 6 // { int sys_close(int fd); } - SYS___TFORK = 8 // { int sys___tfork(const struct __tfork *param, \ + SYS_GETENTROPY = 7 // { int sys_getentropy(void *buf, size_t nbyte); } + SYS___TFORK = 8 // { int sys___tfork(const struct __tfork *param, size_t psize); } SYS_LINK = 9 // { int sys_link(const char *path, const char *link); } SYS_UNLINK = 10 // { int sys_unlink(const char *path); } - SYS_WAIT4 = 11 // { pid_t sys_wait4(pid_t pid, int *status, \ + SYS_WAIT4 = 11 // { pid_t sys_wait4(pid_t pid, int *status, int options, struct rusage *rusage); } SYS_CHDIR = 12 // { int sys_chdir(const char *path); } SYS_FCHDIR = 13 // { int sys_fchdir(int fd); } - SYS_MKNOD = 14 // { int sys_mknod(const char *path, mode_t mode, \ + SYS_MKNOD = 14 // { int sys_mknod(const char *path, mode_t mode, dev_t dev); } SYS_CHMOD = 15 // { int sys_chmod(const char *path, mode_t mode); } - SYS_CHOWN = 16 // { int sys_chown(const char *path, uid_t uid, \ + SYS_CHOWN = 16 // { int sys_chown(const char *path, uid_t uid, gid_t gid); } SYS_OBREAK = 17 // { int sys_obreak(char *nsize); } break SYS_GETDTABLECOUNT = 18 // { int sys_getdtablecount(void); } - SYS_GETRUSAGE = 19 // { int sys_getrusage(int who, \ + SYS_GETRUSAGE = 19 // { int sys_getrusage(int who, struct rusage *rusage); } SYS_GETPID = 20 // { pid_t sys_getpid(void); } - SYS_MOUNT = 21 // { int sys_mount(const char *type, const char *path, \ + SYS_MOUNT = 21 // { int sys_mount(const char *type, const char *path, int flags, void *data); } SYS_UNMOUNT = 22 // { int sys_unmount(const char *path, int flags); } SYS_SETUID = 23 // { int sys_setuid(uid_t uid); } SYS_GETUID = 24 // { uid_t sys_getuid(void); } SYS_GETEUID = 25 // { uid_t sys_geteuid(void); } - SYS_PTRACE = 26 // { int sys_ptrace(int req, pid_t pid, caddr_t addr, \ - SYS_RECVMSG = 27 // { ssize_t sys_recvmsg(int s, struct msghdr *msg, \ - SYS_SENDMSG = 28 // { ssize_t sys_sendmsg(int s, \ - SYS_RECVFROM = 29 // { ssize_t sys_recvfrom(int s, void *buf, size_t len, \ - SYS_ACCEPT = 30 // { int sys_accept(int s, struct sockaddr *name, \ - SYS_GETPEERNAME = 31 // { int sys_getpeername(int fdes, struct sockaddr *asa, \ - SYS_GETSOCKNAME = 32 // { int sys_getsockname(int fdes, struct sockaddr *asa, \ - SYS_ACCESS = 33 // { int sys_access(const char *path, int flags); } + SYS_PTRACE = 26 // { int sys_ptrace(int req, pid_t pid, caddr_t addr, int data); } + SYS_RECVMSG = 27 // { ssize_t sys_recvmsg(int s, struct msghdr *msg, int flags); } + SYS_SENDMSG = 28 // { ssize_t sys_sendmsg(int s, const struct msghdr *msg, int flags); } + SYS_RECVFROM = 29 // { ssize_t sys_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlenaddr); } + SYS_ACCEPT = 30 // { int sys_accept(int s, struct sockaddr *name, socklen_t *anamelen); } + SYS_GETPEERNAME = 31 // { int sys_getpeername(int fdes, struct sockaddr *asa, socklen_t *alen); } + SYS_GETSOCKNAME = 32 // { int sys_getsockname(int fdes, struct sockaddr *asa, socklen_t *alen); } + SYS_ACCESS = 33 // { int sys_access(const char *path, int amode); } SYS_CHFLAGS = 34 // { int sys_chflags(const char *path, u_int flags); } SYS_FCHFLAGS = 35 // { int sys_fchflags(int fd, u_int flags); } SYS_SYNC = 36 // { void sys_sync(void); } - SYS_KILL = 37 // { int sys_kill(int pid, int signum); } SYS_STAT = 38 // { int sys_stat(const char *path, struct stat *ub); } SYS_GETPPID = 39 // { pid_t sys_getppid(void); } SYS_LSTAT = 40 // { int sys_lstat(const char *path, struct stat *ub); } SYS_DUP = 41 // { int sys_dup(int fd); } - SYS_FSTATAT = 42 // { int sys_fstatat(int fd, const char *path, \ + SYS_FSTATAT = 42 // { int sys_fstatat(int fd, const char *path, struct stat *buf, int flag); } SYS_GETEGID = 43 // { gid_t sys_getegid(void); } - SYS_PROFIL = 44 // { int sys_profil(caddr_t samples, size_t size, \ - SYS_KTRACE = 45 // { int sys_ktrace(const char *fname, int ops, \ - SYS_SIGACTION = 46 // { int sys_sigaction(int signum, \ + SYS_PROFIL = 44 // { int sys_profil(caddr_t samples, size_t size, u_long offset, u_int scale); } + SYS_KTRACE = 45 // { int sys_ktrace(const char *fname, int ops, int facs, pid_t pid); } + SYS_SIGACTION = 46 // { int sys_sigaction(int signum, const struct sigaction *nsa, struct sigaction *osa); } SYS_GETGID = 47 // { gid_t sys_getgid(void); } SYS_SIGPROCMASK = 48 // { int sys_sigprocmask(int how, sigset_t mask); } - SYS_GETLOGIN = 49 // { int sys_getlogin(char *namebuf, u_int namelen); } SYS_SETLOGIN = 50 // { int sys_setlogin(const char *namebuf); } SYS_ACCT = 51 // { int sys_acct(const char *path); } SYS_SIGPENDING = 52 // { int sys_sigpending(void); } SYS_FSTAT = 53 // { int sys_fstat(int fd, struct stat *sb); } - SYS_IOCTL = 54 // { int sys_ioctl(int fd, \ + SYS_IOCTL = 54 // { int sys_ioctl(int fd, u_long com, ... void *data); } SYS_REBOOT = 55 // { int sys_reboot(int opt); } SYS_REVOKE = 56 // { int sys_revoke(const char *path); } - SYS_SYMLINK = 57 // { int sys_symlink(const char *path, \ - SYS_READLINK = 58 // { int sys_readlink(const char *path, char *buf, \ - SYS_EXECVE = 59 // { int sys_execve(const char *path, \ + SYS_SYMLINK = 57 // { int sys_symlink(const char *path, const char *link); } + SYS_READLINK = 58 // { ssize_t sys_readlink(const char *path, char *buf, size_t count); } + SYS_EXECVE = 59 // { int sys_execve(const char *path, char * const *argp, char * const *envp); } SYS_UMASK = 60 // { mode_t sys_umask(mode_t newmask); } SYS_CHROOT = 61 // { int sys_chroot(const char *path); } - SYS_GETFSSTAT = 62 // { int sys_getfsstat(struct statfs *buf, size_t bufsize, \ - SYS_STATFS = 63 // { int sys_statfs(const char *path, \ + SYS_GETFSSTAT = 62 // { int sys_getfsstat(struct statfs *buf, size_t bufsize, int flags); } + SYS_STATFS = 63 // { int sys_statfs(const char *path, struct statfs *buf); } SYS_FSTATFS = 64 // { int sys_fstatfs(int fd, struct statfs *buf); } - SYS_FHSTATFS = 65 // { int sys_fhstatfs(const fhandle_t *fhp, \ + SYS_FHSTATFS = 65 // { int sys_fhstatfs(const fhandle_t *fhp, struct statfs *buf); } SYS_VFORK = 66 // { int sys_vfork(void); } - SYS_GETTIMEOFDAY = 67 // { int sys_gettimeofday(struct timeval *tp, \ - SYS_SETTIMEOFDAY = 68 // { int sys_settimeofday(const struct timeval *tv, \ - SYS_SETITIMER = 69 // { int sys_setitimer(int which, \ - SYS_GETITIMER = 70 // { int sys_getitimer(int which, \ - SYS_SELECT = 71 // { int sys_select(int nd, fd_set *in, fd_set *ou, \ - SYS_KEVENT = 72 // { int sys_kevent(int fd, \ + SYS_GETTIMEOFDAY = 67 // { int sys_gettimeofday(struct timeval *tp, struct timezone *tzp); } + SYS_SETTIMEOFDAY = 68 // { int sys_settimeofday(const struct timeval *tv, const struct timezone *tzp); } + SYS_SETITIMER = 69 // { int sys_setitimer(int which, const struct itimerval *itv, struct itimerval *oitv); } + SYS_GETITIMER = 70 // { int sys_getitimer(int which, struct itimerval *itv); } + SYS_SELECT = 71 // { int sys_select(int nd, fd_set *in, fd_set *ou, fd_set *ex, struct timeval *tv); } + SYS_KEVENT = 72 // { int sys_kevent(int fd, const struct kevent *changelist, int nchanges, struct kevent *eventlist, int nevents, const struct timespec *timeout); } SYS_MUNMAP = 73 // { int sys_munmap(void *addr, size_t len); } - SYS_MPROTECT = 74 // { int sys_mprotect(void *addr, size_t len, \ - SYS_MADVISE = 75 // { int sys_madvise(void *addr, size_t len, \ - SYS_UTIMES = 76 // { int sys_utimes(const char *path, \ - SYS_FUTIMES = 77 // { int sys_futimes(int fd, \ - SYS_MINCORE = 78 // { int sys_mincore(void *addr, size_t len, \ - SYS_GETGROUPS = 79 // { int sys_getgroups(int gidsetsize, \ - SYS_SETGROUPS = 80 // { int sys_setgroups(int gidsetsize, \ + SYS_MPROTECT = 74 // { int sys_mprotect(void *addr, size_t len, int prot); } + SYS_MADVISE = 75 // { int sys_madvise(void *addr, size_t len, int behav); } + SYS_UTIMES = 76 // { int sys_utimes(const char *path, const struct timeval *tptr); } + SYS_FUTIMES = 77 // { int sys_futimes(int fd, const struct timeval *tptr); } + SYS_MINCORE = 78 // { int sys_mincore(void *addr, size_t len, char *vec); } + SYS_GETGROUPS = 79 // { int sys_getgroups(int gidsetsize, gid_t *gidset); } + SYS_SETGROUPS = 80 // { int sys_setgroups(int gidsetsize, const gid_t *gidset); } SYS_GETPGRP = 81 // { int sys_getpgrp(void); } - SYS_SETPGID = 82 // { int sys_setpgid(pid_t pid, int pgid); } - SYS_UTIMENSAT = 84 // { int sys_utimensat(int fd, const char *path, \ - SYS_FUTIMENS = 85 // { int sys_futimens(int fd, \ - SYS_CLOCK_GETTIME = 87 // { int sys_clock_gettime(clockid_t clock_id, \ - SYS_CLOCK_SETTIME = 88 // { int sys_clock_settime(clockid_t clock_id, \ - SYS_CLOCK_GETRES = 89 // { int sys_clock_getres(clockid_t clock_id, \ + SYS_SETPGID = 82 // { int sys_setpgid(pid_t pid, pid_t pgid); } + SYS_FUTEX = 83 // { int sys_futex(uint32_t *f, int op, int val, const struct timespec *timeout, uint32_t *g); } + SYS_UTIMENSAT = 84 // { int sys_utimensat(int fd, const char *path, const struct timespec *times, int flag); } + SYS_FUTIMENS = 85 // { int sys_futimens(int fd, const struct timespec *times); } + SYS_KBIND = 86 // { int sys_kbind(const struct __kbind *param, size_t psize, int64_t proc_cookie); } + SYS_CLOCK_GETTIME = 87 // { int sys_clock_gettime(clockid_t clock_id, struct timespec *tp); } + SYS_CLOCK_SETTIME = 88 // { int sys_clock_settime(clockid_t clock_id, const struct timespec *tp); } + SYS_CLOCK_GETRES = 89 // { int sys_clock_getres(clockid_t clock_id, struct timespec *tp); } SYS_DUP2 = 90 // { int sys_dup2(int from, int to); } - SYS_NANOSLEEP = 91 // { int sys_nanosleep(const struct timespec *rqtp, \ + SYS_NANOSLEEP = 91 // { int sys_nanosleep(const struct timespec *rqtp, struct timespec *rmtp); } SYS_FCNTL = 92 // { int sys_fcntl(int fd, int cmd, ... void *arg); } - SYS___THRSLEEP = 94 // { int sys___thrsleep(const volatile void *ident, \ + SYS_ACCEPT4 = 93 // { int sys_accept4(int s, struct sockaddr *name, socklen_t *anamelen, int flags); } + SYS___THRSLEEP = 94 // { int sys___thrsleep(const volatile void *ident, clockid_t clock_id, const struct timespec *tp, void *lock, const int *abort); } SYS_FSYNC = 95 // { int sys_fsync(int fd); } SYS_SETPRIORITY = 96 // { int sys_setpriority(int which, id_t who, int prio); } SYS_SOCKET = 97 // { int sys_socket(int domain, int type, int protocol); } - SYS_CONNECT = 98 // { int sys_connect(int s, const struct sockaddr *name, \ + SYS_CONNECT = 98 // { int sys_connect(int s, const struct sockaddr *name, socklen_t namelen); } SYS_GETDENTS = 99 // { int sys_getdents(int fd, void *buf, size_t buflen); } SYS_GETPRIORITY = 100 // { int sys_getpriority(int which, id_t who); } + SYS_PIPE2 = 101 // { int sys_pipe2(int *fdp, int flags); } + SYS_DUP3 = 102 // { int sys_dup3(int from, int to, int flags); } SYS_SIGRETURN = 103 // { int sys_sigreturn(struct sigcontext *sigcntxp); } - SYS_BIND = 104 // { int sys_bind(int s, const struct sockaddr *name, \ - SYS_SETSOCKOPT = 105 // { int sys_setsockopt(int s, int level, int name, \ + SYS_BIND = 104 // { int sys_bind(int s, const struct sockaddr *name, socklen_t namelen); } + SYS_SETSOCKOPT = 105 // { int sys_setsockopt(int s, int level, int name, const void *val, socklen_t valsize); } SYS_LISTEN = 106 // { int sys_listen(int s, int backlog); } - SYS_PPOLL = 109 // { int sys_ppoll(struct pollfd *fds, \ - SYS_PSELECT = 110 // { int sys_pselect(int nd, fd_set *in, fd_set *ou, \ + SYS_CHFLAGSAT = 107 // { int sys_chflagsat(int fd, const char *path, u_int flags, int atflags); } + SYS_PLEDGE = 108 // { int sys_pledge(const char *promises, const char *execpromises); } + SYS_PPOLL = 109 // { int sys_ppoll(struct pollfd *fds, u_int nfds, const struct timespec *ts, const sigset_t *mask); } + SYS_PSELECT = 110 // { int sys_pselect(int nd, fd_set *in, fd_set *ou, fd_set *ex, const struct timespec *ts, const sigset_t *mask); } SYS_SIGSUSPEND = 111 // { int sys_sigsuspend(int mask); } - SYS_GETSOCKOPT = 118 // { int sys_getsockopt(int s, int level, int name, \ - SYS_READV = 120 // { ssize_t sys_readv(int fd, \ - SYS_WRITEV = 121 // { ssize_t sys_writev(int fd, \ + SYS_SENDSYSLOG = 112 // { int sys_sendsyslog(const char *buf, size_t nbyte, int flags); } + SYS_UNVEIL = 114 // { int sys_unveil(const char *path, const char *permissions); } + SYS_GETSOCKOPT = 118 // { int sys_getsockopt(int s, int level, int name, void *val, socklen_t *avalsize); } + SYS_THRKILL = 119 // { int sys_thrkill(pid_t tid, int signum, void *tcb); } + SYS_READV = 120 // { ssize_t sys_readv(int fd, const struct iovec *iovp, int iovcnt); } + SYS_WRITEV = 121 // { ssize_t sys_writev(int fd, const struct iovec *iovp, int iovcnt); } + SYS_KILL = 122 // { int sys_kill(int pid, int signum); } SYS_FCHOWN = 123 // { int sys_fchown(int fd, uid_t uid, gid_t gid); } SYS_FCHMOD = 124 // { int sys_fchmod(int fd, mode_t mode); } SYS_SETREUID = 126 // { int sys_setreuid(uid_t ruid, uid_t euid); } @@ -119,89 +129,90 @@ const ( SYS_RENAME = 128 // { int sys_rename(const char *from, const char *to); } SYS_FLOCK = 131 // { int sys_flock(int fd, int how); } SYS_MKFIFO = 132 // { int sys_mkfifo(const char *path, mode_t mode); } - SYS_SENDTO = 133 // { ssize_t sys_sendto(int s, const void *buf, \ + SYS_SENDTO = 133 // { ssize_t sys_sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen); } SYS_SHUTDOWN = 134 // { int sys_shutdown(int s, int how); } - SYS_SOCKETPAIR = 135 // { int sys_socketpair(int domain, int type, \ + SYS_SOCKETPAIR = 135 // { int sys_socketpair(int domain, int type, int protocol, int *rsv); } SYS_MKDIR = 136 // { int sys_mkdir(const char *path, mode_t mode); } SYS_RMDIR = 137 // { int sys_rmdir(const char *path); } - SYS_ADJTIME = 140 // { int sys_adjtime(const struct timeval *delta, \ + SYS_ADJTIME = 140 // { int sys_adjtime(const struct timeval *delta, struct timeval *olddelta); } + SYS_GETLOGIN_R = 141 // { int sys_getlogin_r(char *namebuf, u_int namelen); } SYS_SETSID = 147 // { int sys_setsid(void); } - SYS_QUOTACTL = 148 // { int sys_quotactl(const char *path, int cmd, \ + SYS_QUOTACTL = 148 // { int sys_quotactl(const char *path, int cmd, int uid, char *arg); } SYS_NFSSVC = 155 // { int sys_nfssvc(int flag, void *argp); } SYS_GETFH = 161 // { int sys_getfh(const char *fname, fhandle_t *fhp); } SYS_SYSARCH = 165 // { int sys_sysarch(int op, void *parms); } - SYS_PREAD = 173 // { ssize_t sys_pread(int fd, void *buf, \ - SYS_PWRITE = 174 // { ssize_t sys_pwrite(int fd, const void *buf, \ + SYS_PREAD = 173 // { ssize_t sys_pread(int fd, void *buf, size_t nbyte, int pad, off_t offset); } + SYS_PWRITE = 174 // { ssize_t sys_pwrite(int fd, const void *buf, size_t nbyte, int pad, off_t offset); } SYS_SETGID = 181 // { int sys_setgid(gid_t gid); } SYS_SETEGID = 182 // { int sys_setegid(gid_t egid); } SYS_SETEUID = 183 // { int sys_seteuid(uid_t euid); } SYS_PATHCONF = 191 // { long sys_pathconf(const char *path, int name); } SYS_FPATHCONF = 192 // { long sys_fpathconf(int fd, int name); } SYS_SWAPCTL = 193 // { int sys_swapctl(int cmd, const void *arg, int misc); } - SYS_GETRLIMIT = 194 // { int sys_getrlimit(int which, \ - SYS_SETRLIMIT = 195 // { int sys_setrlimit(int which, \ - SYS_MMAP = 197 // { void *sys_mmap(void *addr, size_t len, int prot, \ - SYS_LSEEK = 199 // { off_t sys_lseek(int fd, int pad, off_t offset, \ - SYS_TRUNCATE = 200 // { int sys_truncate(const char *path, int pad, \ + SYS_GETRLIMIT = 194 // { int sys_getrlimit(int which, struct rlimit *rlp); } + SYS_SETRLIMIT = 195 // { int sys_setrlimit(int which, const struct rlimit *rlp); } + SYS_MMAP = 197 // { void *sys_mmap(void *addr, size_t len, int prot, int flags, int fd, long pad, off_t pos); } + SYS_LSEEK = 199 // { off_t sys_lseek(int fd, int pad, off_t offset, int whence); } + SYS_TRUNCATE = 200 // { int sys_truncate(const char *path, int pad, off_t length); } SYS_FTRUNCATE = 201 // { int sys_ftruncate(int fd, int pad, off_t length); } - SYS___SYSCTL = 202 // { int sys___sysctl(const int *name, u_int namelen, \ + SYS_SYSCTL = 202 // { int sys_sysctl(const int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen); } SYS_MLOCK = 203 // { int sys_mlock(const void *addr, size_t len); } SYS_MUNLOCK = 204 // { int sys_munlock(const void *addr, size_t len); } SYS_GETPGID = 207 // { pid_t sys_getpgid(pid_t pid); } - SYS_UTRACE = 209 // { int sys_utrace(const char *label, const void *addr, \ + SYS_UTRACE = 209 // { int sys_utrace(const char *label, const void *addr, size_t len); } SYS_SEMGET = 221 // { int sys_semget(key_t key, int nsems, int semflg); } SYS_MSGGET = 225 // { int sys_msgget(key_t key, int msgflg); } - SYS_MSGSND = 226 // { int sys_msgsnd(int msqid, const void *msgp, size_t msgsz, \ - SYS_MSGRCV = 227 // { int sys_msgrcv(int msqid, void *msgp, size_t msgsz, \ - SYS_SHMAT = 228 // { void *sys_shmat(int shmid, const void *shmaddr, \ + SYS_MSGSND = 226 // { int sys_msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); } + SYS_MSGRCV = 227 // { int sys_msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); } + SYS_SHMAT = 228 // { void *sys_shmat(int shmid, const void *shmaddr, int shmflg); } SYS_SHMDT = 230 // { int sys_shmdt(const void *shmaddr); } - SYS_MINHERIT = 250 // { int sys_minherit(void *addr, size_t len, \ - SYS_POLL = 252 // { int sys_poll(struct pollfd *fds, \ + SYS_MINHERIT = 250 // { int sys_minherit(void *addr, size_t len, int inherit); } + SYS_POLL = 252 // { int sys_poll(struct pollfd *fds, u_int nfds, int timeout); } SYS_ISSETUGID = 253 // { int sys_issetugid(void); } SYS_LCHOWN = 254 // { int sys_lchown(const char *path, uid_t uid, gid_t gid); } SYS_GETSID = 255 // { pid_t sys_getsid(pid_t pid); } SYS_MSYNC = 256 // { int sys_msync(void *addr, size_t len, int flags); } SYS_PIPE = 263 // { int sys_pipe(int *fdp); } SYS_FHOPEN = 264 // { int sys_fhopen(const fhandle_t *fhp, int flags); } - SYS_PREADV = 267 // { ssize_t sys_preadv(int fd, \ - SYS_PWRITEV = 268 // { ssize_t sys_pwritev(int fd, \ + SYS_PREADV = 267 // { ssize_t sys_preadv(int fd, const struct iovec *iovp, int iovcnt, int pad, off_t offset); } + SYS_PWRITEV = 268 // { ssize_t sys_pwritev(int fd, const struct iovec *iovp, int iovcnt, int pad, off_t offset); } SYS_KQUEUE = 269 // { int sys_kqueue(void); } SYS_MLOCKALL = 271 // { int sys_mlockall(int flags); } SYS_MUNLOCKALL = 272 // { int sys_munlockall(void); } - SYS_GETRESUID = 281 // { int sys_getresuid(uid_t *ruid, uid_t *euid, \ - SYS_SETRESUID = 282 // { int sys_setresuid(uid_t ruid, uid_t euid, \ - SYS_GETRESGID = 283 // { int sys_getresgid(gid_t *rgid, gid_t *egid, \ - SYS_SETRESGID = 284 // { int sys_setresgid(gid_t rgid, gid_t egid, \ - SYS_MQUERY = 286 // { void *sys_mquery(void *addr, size_t len, int prot, \ + SYS_GETRESUID = 281 // { int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); } + SYS_SETRESUID = 282 // { int sys_setresuid(uid_t ruid, uid_t euid, uid_t suid); } + SYS_GETRESGID = 283 // { int sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); } + SYS_SETRESGID = 284 // { int sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid); } + SYS_MQUERY = 286 // { void *sys_mquery(void *addr, size_t len, int prot, int flags, int fd, long pad, off_t pos); } SYS_CLOSEFROM = 287 // { int sys_closefrom(int fd); } - SYS_SIGALTSTACK = 288 // { int sys_sigaltstack(const struct sigaltstack *nss, \ + SYS_SIGALTSTACK = 288 // { int sys_sigaltstack(const struct sigaltstack *nss, struct sigaltstack *oss); } SYS_SHMGET = 289 // { int sys_shmget(key_t key, size_t size, int shmflg); } - SYS_SEMOP = 290 // { int sys_semop(int semid, struct sembuf *sops, \ - SYS_FHSTAT = 294 // { int sys_fhstat(const fhandle_t *fhp, \ - SYS___SEMCTL = 295 // { int sys___semctl(int semid, int semnum, int cmd, \ - SYS_SHMCTL = 296 // { int sys_shmctl(int shmid, int cmd, \ - SYS_MSGCTL = 297 // { int sys_msgctl(int msqid, int cmd, \ + SYS_SEMOP = 290 // { int sys_semop(int semid, struct sembuf *sops, size_t nsops); } + SYS_FHSTAT = 294 // { int sys_fhstat(const fhandle_t *fhp, struct stat *sb); } + SYS___SEMCTL = 295 // { int sys___semctl(int semid, int semnum, int cmd, union semun *arg); } + SYS_SHMCTL = 296 // { int sys_shmctl(int shmid, int cmd, struct shmid_ds *buf); } + SYS_MSGCTL = 297 // { int sys_msgctl(int msqid, int cmd, struct msqid_ds *buf); } SYS_SCHED_YIELD = 298 // { int sys_sched_yield(void); } SYS_GETTHRID = 299 // { pid_t sys_getthrid(void); } - SYS___THRWAKEUP = 301 // { int sys___thrwakeup(const volatile void *ident, \ + SYS___THRWAKEUP = 301 // { int sys___thrwakeup(const volatile void *ident, int n); } SYS___THREXIT = 302 // { void sys___threxit(pid_t *notdead); } - SYS___THRSIGDIVERT = 303 // { int sys___thrsigdivert(sigset_t sigmask, \ + SYS___THRSIGDIVERT = 303 // { int sys___thrsigdivert(sigset_t sigmask, siginfo_t *info, const struct timespec *timeout); } SYS___GETCWD = 304 // { int sys___getcwd(char *buf, size_t len); } - SYS_ADJFREQ = 305 // { int sys_adjfreq(const int64_t *freq, \ + SYS_ADJFREQ = 305 // { int sys_adjfreq(const int64_t *freq, int64_t *oldfreq); } SYS_SETRTABLE = 310 // { int sys_setrtable(int rtableid); } SYS_GETRTABLE = 311 // { int sys_getrtable(void); } - SYS_FACCESSAT = 313 // { int sys_faccessat(int fd, const char *path, \ - SYS_FCHMODAT = 314 // { int sys_fchmodat(int fd, const char *path, \ - SYS_FCHOWNAT = 315 // { int sys_fchownat(int fd, const char *path, \ - SYS_LINKAT = 317 // { int sys_linkat(int fd1, const char *path1, int fd2, \ - SYS_MKDIRAT = 318 // { int sys_mkdirat(int fd, const char *path, \ - SYS_MKFIFOAT = 319 // { int sys_mkfifoat(int fd, const char *path, \ - SYS_MKNODAT = 320 // { int sys_mknodat(int fd, const char *path, \ - SYS_OPENAT = 321 // { int sys_openat(int fd, const char *path, int flags, \ - SYS_READLINKAT = 322 // { ssize_t sys_readlinkat(int fd, const char *path, \ - SYS_RENAMEAT = 323 // { int sys_renameat(int fromfd, const char *from, \ - SYS_SYMLINKAT = 324 // { int sys_symlinkat(const char *path, int fd, \ - SYS_UNLINKAT = 325 // { int sys_unlinkat(int fd, const char *path, \ + SYS_FACCESSAT = 313 // { int sys_faccessat(int fd, const char *path, int amode, int flag); } + SYS_FCHMODAT = 314 // { int sys_fchmodat(int fd, const char *path, mode_t mode, int flag); } + SYS_FCHOWNAT = 315 // { int sys_fchownat(int fd, const char *path, uid_t uid, gid_t gid, int flag); } + SYS_LINKAT = 317 // { int sys_linkat(int fd1, const char *path1, int fd2, const char *path2, int flag); } + SYS_MKDIRAT = 318 // { int sys_mkdirat(int fd, const char *path, mode_t mode); } + SYS_MKFIFOAT = 319 // { int sys_mkfifoat(int fd, const char *path, mode_t mode); } + SYS_MKNODAT = 320 // { int sys_mknodat(int fd, const char *path, mode_t mode, dev_t dev); } + SYS_OPENAT = 321 // { int sys_openat(int fd, const char *path, int flags, ... mode_t mode); } + SYS_READLINKAT = 322 // { ssize_t sys_readlinkat(int fd, const char *path, char *buf, size_t count); } + SYS_RENAMEAT = 323 // { int sys_renameat(int fromfd, const char *from, int tofd, const char *to); } + SYS_SYMLINKAT = 324 // { int sys_symlinkat(const char *path, int fd, const char *link); } + SYS_UNLINKAT = 325 // { int sys_unlinkat(int fd, const char *path, int flag); } SYS___SET_TCB = 329 // { void sys___set_tcb(void *tcb); } SYS___GET_TCB = 330 // { void *sys___get_tcb(void); } ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_openbsd_amd64.go b/vendor/golang.org/x/sys/unix/zsysnum_openbsd_amd64.go index bd28146ddd..f0dec6f0b4 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_openbsd_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_openbsd_amd64.go @@ -1,5 +1,5 @@ -// mksysnum_openbsd.pl -// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// go run mksysnum.go https://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master +// Code generated by the command above; see README.md. DO NOT EDIT. // +build amd64,openbsd @@ -9,109 +9,119 @@ const ( SYS_EXIT = 1 // { void sys_exit(int rval); } SYS_FORK = 2 // { int sys_fork(void); } SYS_READ = 3 // { ssize_t sys_read(int fd, void *buf, size_t nbyte); } - SYS_WRITE = 4 // { ssize_t sys_write(int fd, const void *buf, \ - SYS_OPEN = 5 // { int sys_open(const char *path, \ + SYS_WRITE = 4 // { ssize_t sys_write(int fd, const void *buf, size_t nbyte); } + SYS_OPEN = 5 // { int sys_open(const char *path, int flags, ... mode_t mode); } SYS_CLOSE = 6 // { int sys_close(int fd); } - SYS___TFORK = 8 // { int sys___tfork(const struct __tfork *param, \ + SYS_GETENTROPY = 7 // { int sys_getentropy(void *buf, size_t nbyte); } + SYS___TFORK = 8 // { int sys___tfork(const struct __tfork *param, size_t psize); } SYS_LINK = 9 // { int sys_link(const char *path, const char *link); } SYS_UNLINK = 10 // { int sys_unlink(const char *path); } - SYS_WAIT4 = 11 // { pid_t sys_wait4(pid_t pid, int *status, \ + SYS_WAIT4 = 11 // { pid_t sys_wait4(pid_t pid, int *status, int options, struct rusage *rusage); } SYS_CHDIR = 12 // { int sys_chdir(const char *path); } SYS_FCHDIR = 13 // { int sys_fchdir(int fd); } - SYS_MKNOD = 14 // { int sys_mknod(const char *path, mode_t mode, \ + SYS_MKNOD = 14 // { int sys_mknod(const char *path, mode_t mode, dev_t dev); } SYS_CHMOD = 15 // { int sys_chmod(const char *path, mode_t mode); } - SYS_CHOWN = 16 // { int sys_chown(const char *path, uid_t uid, \ + SYS_CHOWN = 16 // { int sys_chown(const char *path, uid_t uid, gid_t gid); } SYS_OBREAK = 17 // { int sys_obreak(char *nsize); } break SYS_GETDTABLECOUNT = 18 // { int sys_getdtablecount(void); } - SYS_GETRUSAGE = 19 // { int sys_getrusage(int who, \ + SYS_GETRUSAGE = 19 // { int sys_getrusage(int who, struct rusage *rusage); } SYS_GETPID = 20 // { pid_t sys_getpid(void); } - SYS_MOUNT = 21 // { int sys_mount(const char *type, const char *path, \ + SYS_MOUNT = 21 // { int sys_mount(const char *type, const char *path, int flags, void *data); } SYS_UNMOUNT = 22 // { int sys_unmount(const char *path, int flags); } SYS_SETUID = 23 // { int sys_setuid(uid_t uid); } SYS_GETUID = 24 // { uid_t sys_getuid(void); } SYS_GETEUID = 25 // { uid_t sys_geteuid(void); } - SYS_PTRACE = 26 // { int sys_ptrace(int req, pid_t pid, caddr_t addr, \ - SYS_RECVMSG = 27 // { ssize_t sys_recvmsg(int s, struct msghdr *msg, \ - SYS_SENDMSG = 28 // { ssize_t sys_sendmsg(int s, \ - SYS_RECVFROM = 29 // { ssize_t sys_recvfrom(int s, void *buf, size_t len, \ - SYS_ACCEPT = 30 // { int sys_accept(int s, struct sockaddr *name, \ - SYS_GETPEERNAME = 31 // { int sys_getpeername(int fdes, struct sockaddr *asa, \ - SYS_GETSOCKNAME = 32 // { int sys_getsockname(int fdes, struct sockaddr *asa, \ - SYS_ACCESS = 33 // { int sys_access(const char *path, int flags); } + SYS_PTRACE = 26 // { int sys_ptrace(int req, pid_t pid, caddr_t addr, int data); } + SYS_RECVMSG = 27 // { ssize_t sys_recvmsg(int s, struct msghdr *msg, int flags); } + SYS_SENDMSG = 28 // { ssize_t sys_sendmsg(int s, const struct msghdr *msg, int flags); } + SYS_RECVFROM = 29 // { ssize_t sys_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlenaddr); } + SYS_ACCEPT = 30 // { int sys_accept(int s, struct sockaddr *name, socklen_t *anamelen); } + SYS_GETPEERNAME = 31 // { int sys_getpeername(int fdes, struct sockaddr *asa, socklen_t *alen); } + SYS_GETSOCKNAME = 32 // { int sys_getsockname(int fdes, struct sockaddr *asa, socklen_t *alen); } + SYS_ACCESS = 33 // { int sys_access(const char *path, int amode); } SYS_CHFLAGS = 34 // { int sys_chflags(const char *path, u_int flags); } SYS_FCHFLAGS = 35 // { int sys_fchflags(int fd, u_int flags); } SYS_SYNC = 36 // { void sys_sync(void); } - SYS_KILL = 37 // { int sys_kill(int pid, int signum); } SYS_STAT = 38 // { int sys_stat(const char *path, struct stat *ub); } SYS_GETPPID = 39 // { pid_t sys_getppid(void); } SYS_LSTAT = 40 // { int sys_lstat(const char *path, struct stat *ub); } SYS_DUP = 41 // { int sys_dup(int fd); } - SYS_FSTATAT = 42 // { int sys_fstatat(int fd, const char *path, \ + SYS_FSTATAT = 42 // { int sys_fstatat(int fd, const char *path, struct stat *buf, int flag); } SYS_GETEGID = 43 // { gid_t sys_getegid(void); } - SYS_PROFIL = 44 // { int sys_profil(caddr_t samples, size_t size, \ - SYS_KTRACE = 45 // { int sys_ktrace(const char *fname, int ops, \ - SYS_SIGACTION = 46 // { int sys_sigaction(int signum, \ + SYS_PROFIL = 44 // { int sys_profil(caddr_t samples, size_t size, u_long offset, u_int scale); } + SYS_KTRACE = 45 // { int sys_ktrace(const char *fname, int ops, int facs, pid_t pid); } + SYS_SIGACTION = 46 // { int sys_sigaction(int signum, const struct sigaction *nsa, struct sigaction *osa); } SYS_GETGID = 47 // { gid_t sys_getgid(void); } SYS_SIGPROCMASK = 48 // { int sys_sigprocmask(int how, sigset_t mask); } - SYS_GETLOGIN = 49 // { int sys_getlogin(char *namebuf, u_int namelen); } SYS_SETLOGIN = 50 // { int sys_setlogin(const char *namebuf); } SYS_ACCT = 51 // { int sys_acct(const char *path); } SYS_SIGPENDING = 52 // { int sys_sigpending(void); } SYS_FSTAT = 53 // { int sys_fstat(int fd, struct stat *sb); } - SYS_IOCTL = 54 // { int sys_ioctl(int fd, \ + SYS_IOCTL = 54 // { int sys_ioctl(int fd, u_long com, ... void *data); } SYS_REBOOT = 55 // { int sys_reboot(int opt); } SYS_REVOKE = 56 // { int sys_revoke(const char *path); } - SYS_SYMLINK = 57 // { int sys_symlink(const char *path, \ - SYS_READLINK = 58 // { int sys_readlink(const char *path, char *buf, \ - SYS_EXECVE = 59 // { int sys_execve(const char *path, \ + SYS_SYMLINK = 57 // { int sys_symlink(const char *path, const char *link); } + SYS_READLINK = 58 // { ssize_t sys_readlink(const char *path, char *buf, size_t count); } + SYS_EXECVE = 59 // { int sys_execve(const char *path, char * const *argp, char * const *envp); } SYS_UMASK = 60 // { mode_t sys_umask(mode_t newmask); } SYS_CHROOT = 61 // { int sys_chroot(const char *path); } - SYS_GETFSSTAT = 62 // { int sys_getfsstat(struct statfs *buf, size_t bufsize, \ - SYS_STATFS = 63 // { int sys_statfs(const char *path, \ + SYS_GETFSSTAT = 62 // { int sys_getfsstat(struct statfs *buf, size_t bufsize, int flags); } + SYS_STATFS = 63 // { int sys_statfs(const char *path, struct statfs *buf); } SYS_FSTATFS = 64 // { int sys_fstatfs(int fd, struct statfs *buf); } - SYS_FHSTATFS = 65 // { int sys_fhstatfs(const fhandle_t *fhp, \ + SYS_FHSTATFS = 65 // { int sys_fhstatfs(const fhandle_t *fhp, struct statfs *buf); } SYS_VFORK = 66 // { int sys_vfork(void); } - SYS_GETTIMEOFDAY = 67 // { int sys_gettimeofday(struct timeval *tp, \ - SYS_SETTIMEOFDAY = 68 // { int sys_settimeofday(const struct timeval *tv, \ - SYS_SETITIMER = 69 // { int sys_setitimer(int which, \ - SYS_GETITIMER = 70 // { int sys_getitimer(int which, \ - SYS_SELECT = 71 // { int sys_select(int nd, fd_set *in, fd_set *ou, \ - SYS_KEVENT = 72 // { int sys_kevent(int fd, \ + SYS_GETTIMEOFDAY = 67 // { int sys_gettimeofday(struct timeval *tp, struct timezone *tzp); } + SYS_SETTIMEOFDAY = 68 // { int sys_settimeofday(const struct timeval *tv, const struct timezone *tzp); } + SYS_SETITIMER = 69 // { int sys_setitimer(int which, const struct itimerval *itv, struct itimerval *oitv); } + SYS_GETITIMER = 70 // { int sys_getitimer(int which, struct itimerval *itv); } + SYS_SELECT = 71 // { int sys_select(int nd, fd_set *in, fd_set *ou, fd_set *ex, struct timeval *tv); } + SYS_KEVENT = 72 // { int sys_kevent(int fd, const struct kevent *changelist, int nchanges, struct kevent *eventlist, int nevents, const struct timespec *timeout); } SYS_MUNMAP = 73 // { int sys_munmap(void *addr, size_t len); } - SYS_MPROTECT = 74 // { int sys_mprotect(void *addr, size_t len, \ - SYS_MADVISE = 75 // { int sys_madvise(void *addr, size_t len, \ - SYS_UTIMES = 76 // { int sys_utimes(const char *path, \ - SYS_FUTIMES = 77 // { int sys_futimes(int fd, \ - SYS_MINCORE = 78 // { int sys_mincore(void *addr, size_t len, \ - SYS_GETGROUPS = 79 // { int sys_getgroups(int gidsetsize, \ - SYS_SETGROUPS = 80 // { int sys_setgroups(int gidsetsize, \ + SYS_MPROTECT = 74 // { int sys_mprotect(void *addr, size_t len, int prot); } + SYS_MADVISE = 75 // { int sys_madvise(void *addr, size_t len, int behav); } + SYS_UTIMES = 76 // { int sys_utimes(const char *path, const struct timeval *tptr); } + SYS_FUTIMES = 77 // { int sys_futimes(int fd, const struct timeval *tptr); } + SYS_MINCORE = 78 // { int sys_mincore(void *addr, size_t len, char *vec); } + SYS_GETGROUPS = 79 // { int sys_getgroups(int gidsetsize, gid_t *gidset); } + SYS_SETGROUPS = 80 // { int sys_setgroups(int gidsetsize, const gid_t *gidset); } SYS_GETPGRP = 81 // { int sys_getpgrp(void); } - SYS_SETPGID = 82 // { int sys_setpgid(pid_t pid, int pgid); } - SYS_UTIMENSAT = 84 // { int sys_utimensat(int fd, const char *path, \ - SYS_FUTIMENS = 85 // { int sys_futimens(int fd, \ - SYS_CLOCK_GETTIME = 87 // { int sys_clock_gettime(clockid_t clock_id, \ - SYS_CLOCK_SETTIME = 88 // { int sys_clock_settime(clockid_t clock_id, \ - SYS_CLOCK_GETRES = 89 // { int sys_clock_getres(clockid_t clock_id, \ + SYS_SETPGID = 82 // { int sys_setpgid(pid_t pid, pid_t pgid); } + SYS_FUTEX = 83 // { int sys_futex(uint32_t *f, int op, int val, const struct timespec *timeout, uint32_t *g); } + SYS_UTIMENSAT = 84 // { int sys_utimensat(int fd, const char *path, const struct timespec *times, int flag); } + SYS_FUTIMENS = 85 // { int sys_futimens(int fd, const struct timespec *times); } + SYS_KBIND = 86 // { int sys_kbind(const struct __kbind *param, size_t psize, int64_t proc_cookie); } + SYS_CLOCK_GETTIME = 87 // { int sys_clock_gettime(clockid_t clock_id, struct timespec *tp); } + SYS_CLOCK_SETTIME = 88 // { int sys_clock_settime(clockid_t clock_id, const struct timespec *tp); } + SYS_CLOCK_GETRES = 89 // { int sys_clock_getres(clockid_t clock_id, struct timespec *tp); } SYS_DUP2 = 90 // { int sys_dup2(int from, int to); } - SYS_NANOSLEEP = 91 // { int sys_nanosleep(const struct timespec *rqtp, \ + SYS_NANOSLEEP = 91 // { int sys_nanosleep(const struct timespec *rqtp, struct timespec *rmtp); } SYS_FCNTL = 92 // { int sys_fcntl(int fd, int cmd, ... void *arg); } - SYS___THRSLEEP = 94 // { int sys___thrsleep(const volatile void *ident, \ + SYS_ACCEPT4 = 93 // { int sys_accept4(int s, struct sockaddr *name, socklen_t *anamelen, int flags); } + SYS___THRSLEEP = 94 // { int sys___thrsleep(const volatile void *ident, clockid_t clock_id, const struct timespec *tp, void *lock, const int *abort); } SYS_FSYNC = 95 // { int sys_fsync(int fd); } SYS_SETPRIORITY = 96 // { int sys_setpriority(int which, id_t who, int prio); } SYS_SOCKET = 97 // { int sys_socket(int domain, int type, int protocol); } - SYS_CONNECT = 98 // { int sys_connect(int s, const struct sockaddr *name, \ + SYS_CONNECT = 98 // { int sys_connect(int s, const struct sockaddr *name, socklen_t namelen); } SYS_GETDENTS = 99 // { int sys_getdents(int fd, void *buf, size_t buflen); } SYS_GETPRIORITY = 100 // { int sys_getpriority(int which, id_t who); } + SYS_PIPE2 = 101 // { int sys_pipe2(int *fdp, int flags); } + SYS_DUP3 = 102 // { int sys_dup3(int from, int to, int flags); } SYS_SIGRETURN = 103 // { int sys_sigreturn(struct sigcontext *sigcntxp); } - SYS_BIND = 104 // { int sys_bind(int s, const struct sockaddr *name, \ - SYS_SETSOCKOPT = 105 // { int sys_setsockopt(int s, int level, int name, \ + SYS_BIND = 104 // { int sys_bind(int s, const struct sockaddr *name, socklen_t namelen); } + SYS_SETSOCKOPT = 105 // { int sys_setsockopt(int s, int level, int name, const void *val, socklen_t valsize); } SYS_LISTEN = 106 // { int sys_listen(int s, int backlog); } - SYS_PPOLL = 109 // { int sys_ppoll(struct pollfd *fds, \ - SYS_PSELECT = 110 // { int sys_pselect(int nd, fd_set *in, fd_set *ou, \ + SYS_CHFLAGSAT = 107 // { int sys_chflagsat(int fd, const char *path, u_int flags, int atflags); } + SYS_PLEDGE = 108 // { int sys_pledge(const char *promises, const char *execpromises); } + SYS_PPOLL = 109 // { int sys_ppoll(struct pollfd *fds, u_int nfds, const struct timespec *ts, const sigset_t *mask); } + SYS_PSELECT = 110 // { int sys_pselect(int nd, fd_set *in, fd_set *ou, fd_set *ex, const struct timespec *ts, const sigset_t *mask); } SYS_SIGSUSPEND = 111 // { int sys_sigsuspend(int mask); } - SYS_GETSOCKOPT = 118 // { int sys_getsockopt(int s, int level, int name, \ - SYS_READV = 120 // { ssize_t sys_readv(int fd, \ - SYS_WRITEV = 121 // { ssize_t sys_writev(int fd, \ + SYS_SENDSYSLOG = 112 // { int sys_sendsyslog(const char *buf, size_t nbyte, int flags); } + SYS_UNVEIL = 114 // { int sys_unveil(const char *path, const char *permissions); } + SYS_GETSOCKOPT = 118 // { int sys_getsockopt(int s, int level, int name, void *val, socklen_t *avalsize); } + SYS_THRKILL = 119 // { int sys_thrkill(pid_t tid, int signum, void *tcb); } + SYS_READV = 120 // { ssize_t sys_readv(int fd, const struct iovec *iovp, int iovcnt); } + SYS_WRITEV = 121 // { ssize_t sys_writev(int fd, const struct iovec *iovp, int iovcnt); } + SYS_KILL = 122 // { int sys_kill(int pid, int signum); } SYS_FCHOWN = 123 // { int sys_fchown(int fd, uid_t uid, gid_t gid); } SYS_FCHMOD = 124 // { int sys_fchmod(int fd, mode_t mode); } SYS_SETREUID = 126 // { int sys_setreuid(uid_t ruid, uid_t euid); } @@ -119,89 +129,90 @@ const ( SYS_RENAME = 128 // { int sys_rename(const char *from, const char *to); } SYS_FLOCK = 131 // { int sys_flock(int fd, int how); } SYS_MKFIFO = 132 // { int sys_mkfifo(const char *path, mode_t mode); } - SYS_SENDTO = 133 // { ssize_t sys_sendto(int s, const void *buf, \ + SYS_SENDTO = 133 // { ssize_t sys_sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen); } SYS_SHUTDOWN = 134 // { int sys_shutdown(int s, int how); } - SYS_SOCKETPAIR = 135 // { int sys_socketpair(int domain, int type, \ + SYS_SOCKETPAIR = 135 // { int sys_socketpair(int domain, int type, int protocol, int *rsv); } SYS_MKDIR = 136 // { int sys_mkdir(const char *path, mode_t mode); } SYS_RMDIR = 137 // { int sys_rmdir(const char *path); } - SYS_ADJTIME = 140 // { int sys_adjtime(const struct timeval *delta, \ + SYS_ADJTIME = 140 // { int sys_adjtime(const struct timeval *delta, struct timeval *olddelta); } + SYS_GETLOGIN_R = 141 // { int sys_getlogin_r(char *namebuf, u_int namelen); } SYS_SETSID = 147 // { int sys_setsid(void); } - SYS_QUOTACTL = 148 // { int sys_quotactl(const char *path, int cmd, \ + SYS_QUOTACTL = 148 // { int sys_quotactl(const char *path, int cmd, int uid, char *arg); } SYS_NFSSVC = 155 // { int sys_nfssvc(int flag, void *argp); } SYS_GETFH = 161 // { int sys_getfh(const char *fname, fhandle_t *fhp); } SYS_SYSARCH = 165 // { int sys_sysarch(int op, void *parms); } - SYS_PREAD = 173 // { ssize_t sys_pread(int fd, void *buf, \ - SYS_PWRITE = 174 // { ssize_t sys_pwrite(int fd, const void *buf, \ + SYS_PREAD = 173 // { ssize_t sys_pread(int fd, void *buf, size_t nbyte, int pad, off_t offset); } + SYS_PWRITE = 174 // { ssize_t sys_pwrite(int fd, const void *buf, size_t nbyte, int pad, off_t offset); } SYS_SETGID = 181 // { int sys_setgid(gid_t gid); } SYS_SETEGID = 182 // { int sys_setegid(gid_t egid); } SYS_SETEUID = 183 // { int sys_seteuid(uid_t euid); } SYS_PATHCONF = 191 // { long sys_pathconf(const char *path, int name); } SYS_FPATHCONF = 192 // { long sys_fpathconf(int fd, int name); } SYS_SWAPCTL = 193 // { int sys_swapctl(int cmd, const void *arg, int misc); } - SYS_GETRLIMIT = 194 // { int sys_getrlimit(int which, \ - SYS_SETRLIMIT = 195 // { int sys_setrlimit(int which, \ - SYS_MMAP = 197 // { void *sys_mmap(void *addr, size_t len, int prot, \ - SYS_LSEEK = 199 // { off_t sys_lseek(int fd, int pad, off_t offset, \ - SYS_TRUNCATE = 200 // { int sys_truncate(const char *path, int pad, \ + SYS_GETRLIMIT = 194 // { int sys_getrlimit(int which, struct rlimit *rlp); } + SYS_SETRLIMIT = 195 // { int sys_setrlimit(int which, const struct rlimit *rlp); } + SYS_MMAP = 197 // { void *sys_mmap(void *addr, size_t len, int prot, int flags, int fd, long pad, off_t pos); } + SYS_LSEEK = 199 // { off_t sys_lseek(int fd, int pad, off_t offset, int whence); } + SYS_TRUNCATE = 200 // { int sys_truncate(const char *path, int pad, off_t length); } SYS_FTRUNCATE = 201 // { int sys_ftruncate(int fd, int pad, off_t length); } - SYS___SYSCTL = 202 // { int sys___sysctl(const int *name, u_int namelen, \ + SYS_SYSCTL = 202 // { int sys_sysctl(const int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen); } SYS_MLOCK = 203 // { int sys_mlock(const void *addr, size_t len); } SYS_MUNLOCK = 204 // { int sys_munlock(const void *addr, size_t len); } SYS_GETPGID = 207 // { pid_t sys_getpgid(pid_t pid); } - SYS_UTRACE = 209 // { int sys_utrace(const char *label, const void *addr, \ + SYS_UTRACE = 209 // { int sys_utrace(const char *label, const void *addr, size_t len); } SYS_SEMGET = 221 // { int sys_semget(key_t key, int nsems, int semflg); } SYS_MSGGET = 225 // { int sys_msgget(key_t key, int msgflg); } - SYS_MSGSND = 226 // { int sys_msgsnd(int msqid, const void *msgp, size_t msgsz, \ - SYS_MSGRCV = 227 // { int sys_msgrcv(int msqid, void *msgp, size_t msgsz, \ - SYS_SHMAT = 228 // { void *sys_shmat(int shmid, const void *shmaddr, \ + SYS_MSGSND = 226 // { int sys_msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); } + SYS_MSGRCV = 227 // { int sys_msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); } + SYS_SHMAT = 228 // { void *sys_shmat(int shmid, const void *shmaddr, int shmflg); } SYS_SHMDT = 230 // { int sys_shmdt(const void *shmaddr); } - SYS_MINHERIT = 250 // { int sys_minherit(void *addr, size_t len, \ - SYS_POLL = 252 // { int sys_poll(struct pollfd *fds, \ + SYS_MINHERIT = 250 // { int sys_minherit(void *addr, size_t len, int inherit); } + SYS_POLL = 252 // { int sys_poll(struct pollfd *fds, u_int nfds, int timeout); } SYS_ISSETUGID = 253 // { int sys_issetugid(void); } SYS_LCHOWN = 254 // { int sys_lchown(const char *path, uid_t uid, gid_t gid); } SYS_GETSID = 255 // { pid_t sys_getsid(pid_t pid); } SYS_MSYNC = 256 // { int sys_msync(void *addr, size_t len, int flags); } SYS_PIPE = 263 // { int sys_pipe(int *fdp); } SYS_FHOPEN = 264 // { int sys_fhopen(const fhandle_t *fhp, int flags); } - SYS_PREADV = 267 // { ssize_t sys_preadv(int fd, \ - SYS_PWRITEV = 268 // { ssize_t sys_pwritev(int fd, \ + SYS_PREADV = 267 // { ssize_t sys_preadv(int fd, const struct iovec *iovp, int iovcnt, int pad, off_t offset); } + SYS_PWRITEV = 268 // { ssize_t sys_pwritev(int fd, const struct iovec *iovp, int iovcnt, int pad, off_t offset); } SYS_KQUEUE = 269 // { int sys_kqueue(void); } SYS_MLOCKALL = 271 // { int sys_mlockall(int flags); } SYS_MUNLOCKALL = 272 // { int sys_munlockall(void); } - SYS_GETRESUID = 281 // { int sys_getresuid(uid_t *ruid, uid_t *euid, \ - SYS_SETRESUID = 282 // { int sys_setresuid(uid_t ruid, uid_t euid, \ - SYS_GETRESGID = 283 // { int sys_getresgid(gid_t *rgid, gid_t *egid, \ - SYS_SETRESGID = 284 // { int sys_setresgid(gid_t rgid, gid_t egid, \ - SYS_MQUERY = 286 // { void *sys_mquery(void *addr, size_t len, int prot, \ + SYS_GETRESUID = 281 // { int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); } + SYS_SETRESUID = 282 // { int sys_setresuid(uid_t ruid, uid_t euid, uid_t suid); } + SYS_GETRESGID = 283 // { int sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); } + SYS_SETRESGID = 284 // { int sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid); } + SYS_MQUERY = 286 // { void *sys_mquery(void *addr, size_t len, int prot, int flags, int fd, long pad, off_t pos); } SYS_CLOSEFROM = 287 // { int sys_closefrom(int fd); } - SYS_SIGALTSTACK = 288 // { int sys_sigaltstack(const struct sigaltstack *nss, \ + SYS_SIGALTSTACK = 288 // { int sys_sigaltstack(const struct sigaltstack *nss, struct sigaltstack *oss); } SYS_SHMGET = 289 // { int sys_shmget(key_t key, size_t size, int shmflg); } - SYS_SEMOP = 290 // { int sys_semop(int semid, struct sembuf *sops, \ - SYS_FHSTAT = 294 // { int sys_fhstat(const fhandle_t *fhp, \ - SYS___SEMCTL = 295 // { int sys___semctl(int semid, int semnum, int cmd, \ - SYS_SHMCTL = 296 // { int sys_shmctl(int shmid, int cmd, \ - SYS_MSGCTL = 297 // { int sys_msgctl(int msqid, int cmd, \ + SYS_SEMOP = 290 // { int sys_semop(int semid, struct sembuf *sops, size_t nsops); } + SYS_FHSTAT = 294 // { int sys_fhstat(const fhandle_t *fhp, struct stat *sb); } + SYS___SEMCTL = 295 // { int sys___semctl(int semid, int semnum, int cmd, union semun *arg); } + SYS_SHMCTL = 296 // { int sys_shmctl(int shmid, int cmd, struct shmid_ds *buf); } + SYS_MSGCTL = 297 // { int sys_msgctl(int msqid, int cmd, struct msqid_ds *buf); } SYS_SCHED_YIELD = 298 // { int sys_sched_yield(void); } SYS_GETTHRID = 299 // { pid_t sys_getthrid(void); } - SYS___THRWAKEUP = 301 // { int sys___thrwakeup(const volatile void *ident, \ + SYS___THRWAKEUP = 301 // { int sys___thrwakeup(const volatile void *ident, int n); } SYS___THREXIT = 302 // { void sys___threxit(pid_t *notdead); } - SYS___THRSIGDIVERT = 303 // { int sys___thrsigdivert(sigset_t sigmask, \ + SYS___THRSIGDIVERT = 303 // { int sys___thrsigdivert(sigset_t sigmask, siginfo_t *info, const struct timespec *timeout); } SYS___GETCWD = 304 // { int sys___getcwd(char *buf, size_t len); } - SYS_ADJFREQ = 305 // { int sys_adjfreq(const int64_t *freq, \ + SYS_ADJFREQ = 305 // { int sys_adjfreq(const int64_t *freq, int64_t *oldfreq); } SYS_SETRTABLE = 310 // { int sys_setrtable(int rtableid); } SYS_GETRTABLE = 311 // { int sys_getrtable(void); } - SYS_FACCESSAT = 313 // { int sys_faccessat(int fd, const char *path, \ - SYS_FCHMODAT = 314 // { int sys_fchmodat(int fd, const char *path, \ - SYS_FCHOWNAT = 315 // { int sys_fchownat(int fd, const char *path, \ - SYS_LINKAT = 317 // { int sys_linkat(int fd1, const char *path1, int fd2, \ - SYS_MKDIRAT = 318 // { int sys_mkdirat(int fd, const char *path, \ - SYS_MKFIFOAT = 319 // { int sys_mkfifoat(int fd, const char *path, \ - SYS_MKNODAT = 320 // { int sys_mknodat(int fd, const char *path, \ - SYS_OPENAT = 321 // { int sys_openat(int fd, const char *path, int flags, \ - SYS_READLINKAT = 322 // { ssize_t sys_readlinkat(int fd, const char *path, \ - SYS_RENAMEAT = 323 // { int sys_renameat(int fromfd, const char *from, \ - SYS_SYMLINKAT = 324 // { int sys_symlinkat(const char *path, int fd, \ - SYS_UNLINKAT = 325 // { int sys_unlinkat(int fd, const char *path, \ + SYS_FACCESSAT = 313 // { int sys_faccessat(int fd, const char *path, int amode, int flag); } + SYS_FCHMODAT = 314 // { int sys_fchmodat(int fd, const char *path, mode_t mode, int flag); } + SYS_FCHOWNAT = 315 // { int sys_fchownat(int fd, const char *path, uid_t uid, gid_t gid, int flag); } + SYS_LINKAT = 317 // { int sys_linkat(int fd1, const char *path1, int fd2, const char *path2, int flag); } + SYS_MKDIRAT = 318 // { int sys_mkdirat(int fd, const char *path, mode_t mode); } + SYS_MKFIFOAT = 319 // { int sys_mkfifoat(int fd, const char *path, mode_t mode); } + SYS_MKNODAT = 320 // { int sys_mknodat(int fd, const char *path, mode_t mode, dev_t dev); } + SYS_OPENAT = 321 // { int sys_openat(int fd, const char *path, int flags, ... mode_t mode); } + SYS_READLINKAT = 322 // { ssize_t sys_readlinkat(int fd, const char *path, char *buf, size_t count); } + SYS_RENAMEAT = 323 // { int sys_renameat(int fromfd, const char *from, int tofd, const char *to); } + SYS_SYMLINKAT = 324 // { int sys_symlinkat(const char *path, int fd, const char *link); } + SYS_UNLINKAT = 325 // { int sys_unlinkat(int fd, const char *path, int flag); } SYS___SET_TCB = 329 // { void sys___set_tcb(void *tcb); } SYS___GET_TCB = 330 // { void *sys___get_tcb(void); } ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_openbsd_arm.go b/vendor/golang.org/x/sys/unix/zsysnum_openbsd_arm.go index 32653e53c7..33d1dc5404 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_openbsd_arm.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_openbsd_arm.go @@ -1,5 +1,5 @@ -// mksysnum_openbsd.pl -// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// go run mksysnum.go https://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master +// Code generated by the command above; see README.md. DO NOT EDIT. // +build arm,openbsd @@ -9,35 +9,35 @@ const ( SYS_EXIT = 1 // { void sys_exit(int rval); } SYS_FORK = 2 // { int sys_fork(void); } SYS_READ = 3 // { ssize_t sys_read(int fd, void *buf, size_t nbyte); } - SYS_WRITE = 4 // { ssize_t sys_write(int fd, const void *buf, \ - SYS_OPEN = 5 // { int sys_open(const char *path, \ + SYS_WRITE = 4 // { ssize_t sys_write(int fd, const void *buf, size_t nbyte); } + SYS_OPEN = 5 // { int sys_open(const char *path, int flags, ... mode_t mode); } SYS_CLOSE = 6 // { int sys_close(int fd); } SYS_GETENTROPY = 7 // { int sys_getentropy(void *buf, size_t nbyte); } - SYS___TFORK = 8 // { int sys___tfork(const struct __tfork *param, \ + SYS___TFORK = 8 // { int sys___tfork(const struct __tfork *param, size_t psize); } SYS_LINK = 9 // { int sys_link(const char *path, const char *link); } SYS_UNLINK = 10 // { int sys_unlink(const char *path); } - SYS_WAIT4 = 11 // { pid_t sys_wait4(pid_t pid, int *status, \ + SYS_WAIT4 = 11 // { pid_t sys_wait4(pid_t pid, int *status, int options, struct rusage *rusage); } SYS_CHDIR = 12 // { int sys_chdir(const char *path); } SYS_FCHDIR = 13 // { int sys_fchdir(int fd); } - SYS_MKNOD = 14 // { int sys_mknod(const char *path, mode_t mode, \ + SYS_MKNOD = 14 // { int sys_mknod(const char *path, mode_t mode, dev_t dev); } SYS_CHMOD = 15 // { int sys_chmod(const char *path, mode_t mode); } - SYS_CHOWN = 16 // { int sys_chown(const char *path, uid_t uid, \ + SYS_CHOWN = 16 // { int sys_chown(const char *path, uid_t uid, gid_t gid); } SYS_OBREAK = 17 // { int sys_obreak(char *nsize); } break SYS_GETDTABLECOUNT = 18 // { int sys_getdtablecount(void); } - SYS_GETRUSAGE = 19 // { int sys_getrusage(int who, \ + SYS_GETRUSAGE = 19 // { int sys_getrusage(int who, struct rusage *rusage); } SYS_GETPID = 20 // { pid_t sys_getpid(void); } - SYS_MOUNT = 21 // { int sys_mount(const char *type, const char *path, \ + SYS_MOUNT = 21 // { int sys_mount(const char *type, const char *path, int flags, void *data); } SYS_UNMOUNT = 22 // { int sys_unmount(const char *path, int flags); } SYS_SETUID = 23 // { int sys_setuid(uid_t uid); } SYS_GETUID = 24 // { uid_t sys_getuid(void); } SYS_GETEUID = 25 // { uid_t sys_geteuid(void); } - SYS_PTRACE = 26 // { int sys_ptrace(int req, pid_t pid, caddr_t addr, \ - SYS_RECVMSG = 27 // { ssize_t sys_recvmsg(int s, struct msghdr *msg, \ - SYS_SENDMSG = 28 // { ssize_t sys_sendmsg(int s, \ - SYS_RECVFROM = 29 // { ssize_t sys_recvfrom(int s, void *buf, size_t len, \ - SYS_ACCEPT = 30 // { int sys_accept(int s, struct sockaddr *name, \ - SYS_GETPEERNAME = 31 // { int sys_getpeername(int fdes, struct sockaddr *asa, \ - SYS_GETSOCKNAME = 32 // { int sys_getsockname(int fdes, struct sockaddr *asa, \ + SYS_PTRACE = 26 // { int sys_ptrace(int req, pid_t pid, caddr_t addr, int data); } + SYS_RECVMSG = 27 // { ssize_t sys_recvmsg(int s, struct msghdr *msg, int flags); } + SYS_SENDMSG = 28 // { ssize_t sys_sendmsg(int s, const struct msghdr *msg, int flags); } + SYS_RECVFROM = 29 // { ssize_t sys_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlenaddr); } + SYS_ACCEPT = 30 // { int sys_accept(int s, struct sockaddr *name, socklen_t *anamelen); } + SYS_GETPEERNAME = 31 // { int sys_getpeername(int fdes, struct sockaddr *asa, socklen_t *alen); } + SYS_GETSOCKNAME = 32 // { int sys_getsockname(int fdes, struct sockaddr *asa, socklen_t *alen); } SYS_ACCESS = 33 // { int sys_access(const char *path, int amode); } SYS_CHFLAGS = 34 // { int sys_chflags(const char *path, u_int flags); } SYS_FCHFLAGS = 35 // { int sys_fchflags(int fd, u_int flags); } @@ -46,77 +46,81 @@ const ( SYS_GETPPID = 39 // { pid_t sys_getppid(void); } SYS_LSTAT = 40 // { int sys_lstat(const char *path, struct stat *ub); } SYS_DUP = 41 // { int sys_dup(int fd); } - SYS_FSTATAT = 42 // { int sys_fstatat(int fd, const char *path, \ + SYS_FSTATAT = 42 // { int sys_fstatat(int fd, const char *path, struct stat *buf, int flag); } SYS_GETEGID = 43 // { gid_t sys_getegid(void); } - SYS_PROFIL = 44 // { int sys_profil(caddr_t samples, size_t size, \ - SYS_KTRACE = 45 // { int sys_ktrace(const char *fname, int ops, \ - SYS_SIGACTION = 46 // { int sys_sigaction(int signum, \ + SYS_PROFIL = 44 // { int sys_profil(caddr_t samples, size_t size, u_long offset, u_int scale); } + SYS_KTRACE = 45 // { int sys_ktrace(const char *fname, int ops, int facs, pid_t pid); } + SYS_SIGACTION = 46 // { int sys_sigaction(int signum, const struct sigaction *nsa, struct sigaction *osa); } SYS_GETGID = 47 // { gid_t sys_getgid(void); } SYS_SIGPROCMASK = 48 // { int sys_sigprocmask(int how, sigset_t mask); } - SYS_GETLOGIN = 49 // { int sys_getlogin(char *namebuf, u_int namelen); } SYS_SETLOGIN = 50 // { int sys_setlogin(const char *namebuf); } SYS_ACCT = 51 // { int sys_acct(const char *path); } SYS_SIGPENDING = 52 // { int sys_sigpending(void); } SYS_FSTAT = 53 // { int sys_fstat(int fd, struct stat *sb); } - SYS_IOCTL = 54 // { int sys_ioctl(int fd, \ + SYS_IOCTL = 54 // { int sys_ioctl(int fd, u_long com, ... void *data); } SYS_REBOOT = 55 // { int sys_reboot(int opt); } SYS_REVOKE = 56 // { int sys_revoke(const char *path); } - SYS_SYMLINK = 57 // { int sys_symlink(const char *path, \ - SYS_READLINK = 58 // { ssize_t sys_readlink(const char *path, \ - SYS_EXECVE = 59 // { int sys_execve(const char *path, \ + SYS_SYMLINK = 57 // { int sys_symlink(const char *path, const char *link); } + SYS_READLINK = 58 // { ssize_t sys_readlink(const char *path, char *buf, size_t count); } + SYS_EXECVE = 59 // { int sys_execve(const char *path, char * const *argp, char * const *envp); } SYS_UMASK = 60 // { mode_t sys_umask(mode_t newmask); } SYS_CHROOT = 61 // { int sys_chroot(const char *path); } - SYS_GETFSSTAT = 62 // { int sys_getfsstat(struct statfs *buf, size_t bufsize, \ - SYS_STATFS = 63 // { int sys_statfs(const char *path, \ + SYS_GETFSSTAT = 62 // { int sys_getfsstat(struct statfs *buf, size_t bufsize, int flags); } + SYS_STATFS = 63 // { int sys_statfs(const char *path, struct statfs *buf); } SYS_FSTATFS = 64 // { int sys_fstatfs(int fd, struct statfs *buf); } - SYS_FHSTATFS = 65 // { int sys_fhstatfs(const fhandle_t *fhp, \ + SYS_FHSTATFS = 65 // { int sys_fhstatfs(const fhandle_t *fhp, struct statfs *buf); } SYS_VFORK = 66 // { int sys_vfork(void); } - SYS_GETTIMEOFDAY = 67 // { int sys_gettimeofday(struct timeval *tp, \ - SYS_SETTIMEOFDAY = 68 // { int sys_settimeofday(const struct timeval *tv, \ - SYS_SETITIMER = 69 // { int sys_setitimer(int which, \ - SYS_GETITIMER = 70 // { int sys_getitimer(int which, \ - SYS_SELECT = 71 // { int sys_select(int nd, fd_set *in, fd_set *ou, \ - SYS_KEVENT = 72 // { int sys_kevent(int fd, \ + SYS_GETTIMEOFDAY = 67 // { int sys_gettimeofday(struct timeval *tp, struct timezone *tzp); } + SYS_SETTIMEOFDAY = 68 // { int sys_settimeofday(const struct timeval *tv, const struct timezone *tzp); } + SYS_SETITIMER = 69 // { int sys_setitimer(int which, const struct itimerval *itv, struct itimerval *oitv); } + SYS_GETITIMER = 70 // { int sys_getitimer(int which, struct itimerval *itv); } + SYS_SELECT = 71 // { int sys_select(int nd, fd_set *in, fd_set *ou, fd_set *ex, struct timeval *tv); } + SYS_KEVENT = 72 // { int sys_kevent(int fd, const struct kevent *changelist, int nchanges, struct kevent *eventlist, int nevents, const struct timespec *timeout); } SYS_MUNMAP = 73 // { int sys_munmap(void *addr, size_t len); } - SYS_MPROTECT = 74 // { int sys_mprotect(void *addr, size_t len, \ - SYS_MADVISE = 75 // { int sys_madvise(void *addr, size_t len, \ - SYS_UTIMES = 76 // { int sys_utimes(const char *path, \ - SYS_FUTIMES = 77 // { int sys_futimes(int fd, \ - SYS_MINCORE = 78 // { int sys_mincore(void *addr, size_t len, \ - SYS_GETGROUPS = 79 // { int sys_getgroups(int gidsetsize, \ - SYS_SETGROUPS = 80 // { int sys_setgroups(int gidsetsize, \ + SYS_MPROTECT = 74 // { int sys_mprotect(void *addr, size_t len, int prot); } + SYS_MADVISE = 75 // { int sys_madvise(void *addr, size_t len, int behav); } + SYS_UTIMES = 76 // { int sys_utimes(const char *path, const struct timeval *tptr); } + SYS_FUTIMES = 77 // { int sys_futimes(int fd, const struct timeval *tptr); } + SYS_MINCORE = 78 // { int sys_mincore(void *addr, size_t len, char *vec); } + SYS_GETGROUPS = 79 // { int sys_getgroups(int gidsetsize, gid_t *gidset); } + SYS_SETGROUPS = 80 // { int sys_setgroups(int gidsetsize, const gid_t *gidset); } SYS_GETPGRP = 81 // { int sys_getpgrp(void); } SYS_SETPGID = 82 // { int sys_setpgid(pid_t pid, pid_t pgid); } - SYS_SENDSYSLOG = 83 // { int sys_sendsyslog(const void *buf, size_t nbyte); } - SYS_UTIMENSAT = 84 // { int sys_utimensat(int fd, const char *path, \ - SYS_FUTIMENS = 85 // { int sys_futimens(int fd, \ - SYS_CLOCK_GETTIME = 87 // { int sys_clock_gettime(clockid_t clock_id, \ - SYS_CLOCK_SETTIME = 88 // { int sys_clock_settime(clockid_t clock_id, \ - SYS_CLOCK_GETRES = 89 // { int sys_clock_getres(clockid_t clock_id, \ + SYS_FUTEX = 83 // { int sys_futex(uint32_t *f, int op, int val, const struct timespec *timeout, uint32_t *g); } + SYS_UTIMENSAT = 84 // { int sys_utimensat(int fd, const char *path, const struct timespec *times, int flag); } + SYS_FUTIMENS = 85 // { int sys_futimens(int fd, const struct timespec *times); } + SYS_KBIND = 86 // { int sys_kbind(const struct __kbind *param, size_t psize, int64_t proc_cookie); } + SYS_CLOCK_GETTIME = 87 // { int sys_clock_gettime(clockid_t clock_id, struct timespec *tp); } + SYS_CLOCK_SETTIME = 88 // { int sys_clock_settime(clockid_t clock_id, const struct timespec *tp); } + SYS_CLOCK_GETRES = 89 // { int sys_clock_getres(clockid_t clock_id, struct timespec *tp); } SYS_DUP2 = 90 // { int sys_dup2(int from, int to); } - SYS_NANOSLEEP = 91 // { int sys_nanosleep(const struct timespec *rqtp, \ + SYS_NANOSLEEP = 91 // { int sys_nanosleep(const struct timespec *rqtp, struct timespec *rmtp); } SYS_FCNTL = 92 // { int sys_fcntl(int fd, int cmd, ... void *arg); } - SYS_ACCEPT4 = 93 // { int sys_accept4(int s, struct sockaddr *name, \ - SYS___THRSLEEP = 94 // { int sys___thrsleep(const volatile void *ident, \ + SYS_ACCEPT4 = 93 // { int sys_accept4(int s, struct sockaddr *name, socklen_t *anamelen, int flags); } + SYS___THRSLEEP = 94 // { int sys___thrsleep(const volatile void *ident, clockid_t clock_id, const struct timespec *tp, void *lock, const int *abort); } SYS_FSYNC = 95 // { int sys_fsync(int fd); } SYS_SETPRIORITY = 96 // { int sys_setpriority(int which, id_t who, int prio); } SYS_SOCKET = 97 // { int sys_socket(int domain, int type, int protocol); } - SYS_CONNECT = 98 // { int sys_connect(int s, const struct sockaddr *name, \ + SYS_CONNECT = 98 // { int sys_connect(int s, const struct sockaddr *name, socklen_t namelen); } SYS_GETDENTS = 99 // { int sys_getdents(int fd, void *buf, size_t buflen); } SYS_GETPRIORITY = 100 // { int sys_getpriority(int which, id_t who); } SYS_PIPE2 = 101 // { int sys_pipe2(int *fdp, int flags); } SYS_DUP3 = 102 // { int sys_dup3(int from, int to, int flags); } SYS_SIGRETURN = 103 // { int sys_sigreturn(struct sigcontext *sigcntxp); } - SYS_BIND = 104 // { int sys_bind(int s, const struct sockaddr *name, \ - SYS_SETSOCKOPT = 105 // { int sys_setsockopt(int s, int level, int name, \ + SYS_BIND = 104 // { int sys_bind(int s, const struct sockaddr *name, socklen_t namelen); } + SYS_SETSOCKOPT = 105 // { int sys_setsockopt(int s, int level, int name, const void *val, socklen_t valsize); } SYS_LISTEN = 106 // { int sys_listen(int s, int backlog); } - SYS_CHFLAGSAT = 107 // { int sys_chflagsat(int fd, const char *path, \ - SYS_PPOLL = 109 // { int sys_ppoll(struct pollfd *fds, \ - SYS_PSELECT = 110 // { int sys_pselect(int nd, fd_set *in, fd_set *ou, \ + SYS_CHFLAGSAT = 107 // { int sys_chflagsat(int fd, const char *path, u_int flags, int atflags); } + SYS_PLEDGE = 108 // { int sys_pledge(const char *promises, const char *execpromises); } + SYS_PPOLL = 109 // { int sys_ppoll(struct pollfd *fds, u_int nfds, const struct timespec *ts, const sigset_t *mask); } + SYS_PSELECT = 110 // { int sys_pselect(int nd, fd_set *in, fd_set *ou, fd_set *ex, const struct timespec *ts, const sigset_t *mask); } SYS_SIGSUSPEND = 111 // { int sys_sigsuspend(int mask); } - SYS_GETSOCKOPT = 118 // { int sys_getsockopt(int s, int level, int name, \ - SYS_READV = 120 // { ssize_t sys_readv(int fd, \ - SYS_WRITEV = 121 // { ssize_t sys_writev(int fd, \ + SYS_SENDSYSLOG = 112 // { int sys_sendsyslog(const char *buf, size_t nbyte, int flags); } + SYS_UNVEIL = 114 // { int sys_unveil(const char *path, const char *permissions); } + SYS_GETSOCKOPT = 118 // { int sys_getsockopt(int s, int level, int name, void *val, socklen_t *avalsize); } + SYS_THRKILL = 119 // { int sys_thrkill(pid_t tid, int signum, void *tcb); } + SYS_READV = 120 // { ssize_t sys_readv(int fd, const struct iovec *iovp, int iovcnt); } + SYS_WRITEV = 121 // { ssize_t sys_writev(int fd, const struct iovec *iovp, int iovcnt); } SYS_KILL = 122 // { int sys_kill(int pid, int signum); } SYS_FCHOWN = 123 // { int sys_fchown(int fd, uid_t uid, gid_t gid); } SYS_FCHMOD = 124 // { int sys_fchmod(int fd, mode_t mode); } @@ -125,89 +129,90 @@ const ( SYS_RENAME = 128 // { int sys_rename(const char *from, const char *to); } SYS_FLOCK = 131 // { int sys_flock(int fd, int how); } SYS_MKFIFO = 132 // { int sys_mkfifo(const char *path, mode_t mode); } - SYS_SENDTO = 133 // { ssize_t sys_sendto(int s, const void *buf, \ + SYS_SENDTO = 133 // { ssize_t sys_sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen); } SYS_SHUTDOWN = 134 // { int sys_shutdown(int s, int how); } - SYS_SOCKETPAIR = 135 // { int sys_socketpair(int domain, int type, \ + SYS_SOCKETPAIR = 135 // { int sys_socketpair(int domain, int type, int protocol, int *rsv); } SYS_MKDIR = 136 // { int sys_mkdir(const char *path, mode_t mode); } SYS_RMDIR = 137 // { int sys_rmdir(const char *path); } - SYS_ADJTIME = 140 // { int sys_adjtime(const struct timeval *delta, \ + SYS_ADJTIME = 140 // { int sys_adjtime(const struct timeval *delta, struct timeval *olddelta); } + SYS_GETLOGIN_R = 141 // { int sys_getlogin_r(char *namebuf, u_int namelen); } SYS_SETSID = 147 // { int sys_setsid(void); } - SYS_QUOTACTL = 148 // { int sys_quotactl(const char *path, int cmd, \ + SYS_QUOTACTL = 148 // { int sys_quotactl(const char *path, int cmd, int uid, char *arg); } SYS_NFSSVC = 155 // { int sys_nfssvc(int flag, void *argp); } SYS_GETFH = 161 // { int sys_getfh(const char *fname, fhandle_t *fhp); } SYS_SYSARCH = 165 // { int sys_sysarch(int op, void *parms); } - SYS_PREAD = 173 // { ssize_t sys_pread(int fd, void *buf, \ - SYS_PWRITE = 174 // { ssize_t sys_pwrite(int fd, const void *buf, \ + SYS_PREAD = 173 // { ssize_t sys_pread(int fd, void *buf, size_t nbyte, int pad, off_t offset); } + SYS_PWRITE = 174 // { ssize_t sys_pwrite(int fd, const void *buf, size_t nbyte, int pad, off_t offset); } SYS_SETGID = 181 // { int sys_setgid(gid_t gid); } SYS_SETEGID = 182 // { int sys_setegid(gid_t egid); } SYS_SETEUID = 183 // { int sys_seteuid(uid_t euid); } SYS_PATHCONF = 191 // { long sys_pathconf(const char *path, int name); } SYS_FPATHCONF = 192 // { long sys_fpathconf(int fd, int name); } SYS_SWAPCTL = 193 // { int sys_swapctl(int cmd, const void *arg, int misc); } - SYS_GETRLIMIT = 194 // { int sys_getrlimit(int which, \ - SYS_SETRLIMIT = 195 // { int sys_setrlimit(int which, \ - SYS_MMAP = 197 // { void *sys_mmap(void *addr, size_t len, int prot, \ - SYS_LSEEK = 199 // { off_t sys_lseek(int fd, int pad, off_t offset, \ - SYS_TRUNCATE = 200 // { int sys_truncate(const char *path, int pad, \ + SYS_GETRLIMIT = 194 // { int sys_getrlimit(int which, struct rlimit *rlp); } + SYS_SETRLIMIT = 195 // { int sys_setrlimit(int which, const struct rlimit *rlp); } + SYS_MMAP = 197 // { void *sys_mmap(void *addr, size_t len, int prot, int flags, int fd, long pad, off_t pos); } + SYS_LSEEK = 199 // { off_t sys_lseek(int fd, int pad, off_t offset, int whence); } + SYS_TRUNCATE = 200 // { int sys_truncate(const char *path, int pad, off_t length); } SYS_FTRUNCATE = 201 // { int sys_ftruncate(int fd, int pad, off_t length); } - SYS___SYSCTL = 202 // { int sys___sysctl(const int *name, u_int namelen, \ + SYS_SYSCTL = 202 // { int sys_sysctl(const int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen); } SYS_MLOCK = 203 // { int sys_mlock(const void *addr, size_t len); } SYS_MUNLOCK = 204 // { int sys_munlock(const void *addr, size_t len); } SYS_GETPGID = 207 // { pid_t sys_getpgid(pid_t pid); } - SYS_UTRACE = 209 // { int sys_utrace(const char *label, const void *addr, \ + SYS_UTRACE = 209 // { int sys_utrace(const char *label, const void *addr, size_t len); } SYS_SEMGET = 221 // { int sys_semget(key_t key, int nsems, int semflg); } SYS_MSGGET = 225 // { int sys_msgget(key_t key, int msgflg); } - SYS_MSGSND = 226 // { int sys_msgsnd(int msqid, const void *msgp, size_t msgsz, \ - SYS_MSGRCV = 227 // { int sys_msgrcv(int msqid, void *msgp, size_t msgsz, \ - SYS_SHMAT = 228 // { void *sys_shmat(int shmid, const void *shmaddr, \ + SYS_MSGSND = 226 // { int sys_msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); } + SYS_MSGRCV = 227 // { int sys_msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); } + SYS_SHMAT = 228 // { void *sys_shmat(int shmid, const void *shmaddr, int shmflg); } SYS_SHMDT = 230 // { int sys_shmdt(const void *shmaddr); } - SYS_MINHERIT = 250 // { int sys_minherit(void *addr, size_t len, \ - SYS_POLL = 252 // { int sys_poll(struct pollfd *fds, \ + SYS_MINHERIT = 250 // { int sys_minherit(void *addr, size_t len, int inherit); } + SYS_POLL = 252 // { int sys_poll(struct pollfd *fds, u_int nfds, int timeout); } SYS_ISSETUGID = 253 // { int sys_issetugid(void); } SYS_LCHOWN = 254 // { int sys_lchown(const char *path, uid_t uid, gid_t gid); } SYS_GETSID = 255 // { pid_t sys_getsid(pid_t pid); } SYS_MSYNC = 256 // { int sys_msync(void *addr, size_t len, int flags); } SYS_PIPE = 263 // { int sys_pipe(int *fdp); } SYS_FHOPEN = 264 // { int sys_fhopen(const fhandle_t *fhp, int flags); } - SYS_PREADV = 267 // { ssize_t sys_preadv(int fd, \ - SYS_PWRITEV = 268 // { ssize_t sys_pwritev(int fd, \ + SYS_PREADV = 267 // { ssize_t sys_preadv(int fd, const struct iovec *iovp, int iovcnt, int pad, off_t offset); } + SYS_PWRITEV = 268 // { ssize_t sys_pwritev(int fd, const struct iovec *iovp, int iovcnt, int pad, off_t offset); } SYS_KQUEUE = 269 // { int sys_kqueue(void); } SYS_MLOCKALL = 271 // { int sys_mlockall(int flags); } SYS_MUNLOCKALL = 272 // { int sys_munlockall(void); } - SYS_GETRESUID = 281 // { int sys_getresuid(uid_t *ruid, uid_t *euid, \ - SYS_SETRESUID = 282 // { int sys_setresuid(uid_t ruid, uid_t euid, \ - SYS_GETRESGID = 283 // { int sys_getresgid(gid_t *rgid, gid_t *egid, \ - SYS_SETRESGID = 284 // { int sys_setresgid(gid_t rgid, gid_t egid, \ - SYS_MQUERY = 286 // { void *sys_mquery(void *addr, size_t len, int prot, \ + SYS_GETRESUID = 281 // { int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); } + SYS_SETRESUID = 282 // { int sys_setresuid(uid_t ruid, uid_t euid, uid_t suid); } + SYS_GETRESGID = 283 // { int sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); } + SYS_SETRESGID = 284 // { int sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid); } + SYS_MQUERY = 286 // { void *sys_mquery(void *addr, size_t len, int prot, int flags, int fd, long pad, off_t pos); } SYS_CLOSEFROM = 287 // { int sys_closefrom(int fd); } - SYS_SIGALTSTACK = 288 // { int sys_sigaltstack(const struct sigaltstack *nss, \ + SYS_SIGALTSTACK = 288 // { int sys_sigaltstack(const struct sigaltstack *nss, struct sigaltstack *oss); } SYS_SHMGET = 289 // { int sys_shmget(key_t key, size_t size, int shmflg); } - SYS_SEMOP = 290 // { int sys_semop(int semid, struct sembuf *sops, \ - SYS_FHSTAT = 294 // { int sys_fhstat(const fhandle_t *fhp, \ - SYS___SEMCTL = 295 // { int sys___semctl(int semid, int semnum, int cmd, \ - SYS_SHMCTL = 296 // { int sys_shmctl(int shmid, int cmd, \ - SYS_MSGCTL = 297 // { int sys_msgctl(int msqid, int cmd, \ + SYS_SEMOP = 290 // { int sys_semop(int semid, struct sembuf *sops, size_t nsops); } + SYS_FHSTAT = 294 // { int sys_fhstat(const fhandle_t *fhp, struct stat *sb); } + SYS___SEMCTL = 295 // { int sys___semctl(int semid, int semnum, int cmd, union semun *arg); } + SYS_SHMCTL = 296 // { int sys_shmctl(int shmid, int cmd, struct shmid_ds *buf); } + SYS_MSGCTL = 297 // { int sys_msgctl(int msqid, int cmd, struct msqid_ds *buf); } SYS_SCHED_YIELD = 298 // { int sys_sched_yield(void); } SYS_GETTHRID = 299 // { pid_t sys_getthrid(void); } - SYS___THRWAKEUP = 301 // { int sys___thrwakeup(const volatile void *ident, \ + SYS___THRWAKEUP = 301 // { int sys___thrwakeup(const volatile void *ident, int n); } SYS___THREXIT = 302 // { void sys___threxit(pid_t *notdead); } - SYS___THRSIGDIVERT = 303 // { int sys___thrsigdivert(sigset_t sigmask, \ + SYS___THRSIGDIVERT = 303 // { int sys___thrsigdivert(sigset_t sigmask, siginfo_t *info, const struct timespec *timeout); } SYS___GETCWD = 304 // { int sys___getcwd(char *buf, size_t len); } - SYS_ADJFREQ = 305 // { int sys_adjfreq(const int64_t *freq, \ + SYS_ADJFREQ = 305 // { int sys_adjfreq(const int64_t *freq, int64_t *oldfreq); } SYS_SETRTABLE = 310 // { int sys_setrtable(int rtableid); } SYS_GETRTABLE = 311 // { int sys_getrtable(void); } - SYS_FACCESSAT = 313 // { int sys_faccessat(int fd, const char *path, \ - SYS_FCHMODAT = 314 // { int sys_fchmodat(int fd, const char *path, \ - SYS_FCHOWNAT = 315 // { int sys_fchownat(int fd, const char *path, \ - SYS_LINKAT = 317 // { int sys_linkat(int fd1, const char *path1, int fd2, \ - SYS_MKDIRAT = 318 // { int sys_mkdirat(int fd, const char *path, \ - SYS_MKFIFOAT = 319 // { int sys_mkfifoat(int fd, const char *path, \ - SYS_MKNODAT = 320 // { int sys_mknodat(int fd, const char *path, \ - SYS_OPENAT = 321 // { int sys_openat(int fd, const char *path, int flags, \ - SYS_READLINKAT = 322 // { ssize_t sys_readlinkat(int fd, const char *path, \ - SYS_RENAMEAT = 323 // { int sys_renameat(int fromfd, const char *from, \ - SYS_SYMLINKAT = 324 // { int sys_symlinkat(const char *path, int fd, \ - SYS_UNLINKAT = 325 // { int sys_unlinkat(int fd, const char *path, \ + SYS_FACCESSAT = 313 // { int sys_faccessat(int fd, const char *path, int amode, int flag); } + SYS_FCHMODAT = 314 // { int sys_fchmodat(int fd, const char *path, mode_t mode, int flag); } + SYS_FCHOWNAT = 315 // { int sys_fchownat(int fd, const char *path, uid_t uid, gid_t gid, int flag); } + SYS_LINKAT = 317 // { int sys_linkat(int fd1, const char *path1, int fd2, const char *path2, int flag); } + SYS_MKDIRAT = 318 // { int sys_mkdirat(int fd, const char *path, mode_t mode); } + SYS_MKFIFOAT = 319 // { int sys_mkfifoat(int fd, const char *path, mode_t mode); } + SYS_MKNODAT = 320 // { int sys_mknodat(int fd, const char *path, mode_t mode, dev_t dev); } + SYS_OPENAT = 321 // { int sys_openat(int fd, const char *path, int flags, ... mode_t mode); } + SYS_READLINKAT = 322 // { ssize_t sys_readlinkat(int fd, const char *path, char *buf, size_t count); } + SYS_RENAMEAT = 323 // { int sys_renameat(int fromfd, const char *from, int tofd, const char *to); } + SYS_SYMLINKAT = 324 // { int sys_symlinkat(const char *path, int fd, const char *link); } + SYS_UNLINKAT = 325 // { int sys_unlinkat(int fd, const char *path, int flag); } SYS___SET_TCB = 329 // { void sys___set_tcb(void *tcb); } SYS___GET_TCB = 330 // { void *sys___get_tcb(void); } ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_solaris_amd64.go b/vendor/golang.org/x/sys/unix/zsysnum_solaris_amd64.go deleted file mode 100644 index c708659859..0000000000 --- a/vendor/golang.org/x/sys/unix/zsysnum_solaris_amd64.go +++ /dev/null @@ -1,13 +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,solaris - -package unix - -// TODO(aram): remove these before Go 1.3. -const ( - SYS_EXECVE = 59 - SYS_FCNTL = 62 -) diff --git a/vendor/golang.org/x/sys/unix/ztypes_aix_ppc.go b/vendor/golang.org/x/sys/unix/ztypes_aix_ppc.go new file mode 100644 index 0000000000..cedc9b0f26 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/ztypes_aix_ppc.go @@ -0,0 +1,345 @@ +// cgo -godefs types_aix.go | go run mkpost.go +// Code generated by the command above; see README.md. DO NOT EDIT. + +// +build ppc,aix + +package unix + +const ( + SizeofPtr = 0x4 + SizeofShort = 0x2 + SizeofInt = 0x4 + SizeofLong = 0x4 + SizeofLongLong = 0x8 + PathMax = 0x3ff +) + +type ( + _C_short int16 + _C_int int32 + _C_long int32 + _C_long_long int64 +) + +type off64 int64 +type off int32 +type Mode_t uint32 + +type Timespec struct { + Sec int32 + Nsec int32 +} + +type StTimespec struct { + Sec int32 + Nsec int32 +} + +type Timeval struct { + Sec int32 + Usec int32 +} + +type Timeval32 struct { + Sec int32 + Usec int32 +} + +type Timex struct{} + +type Time_t int32 + +type Tms struct{} + +type Utimbuf struct { + Actime int32 + Modtime int32 +} + +type Timezone struct { + Minuteswest int32 + Dsttime int32 +} + +type Rusage struct { + Utime Timeval + Stime Timeval + Maxrss int32 + Ixrss int32 + Idrss int32 + Isrss int32 + Minflt int32 + Majflt int32 + Nswap int32 + Inblock int32 + Oublock int32 + Msgsnd int32 + Msgrcv int32 + Nsignals int32 + Nvcsw int32 + Nivcsw int32 +} + +type Rlimit struct { + Cur uint64 + Max uint64 +} + +type Pid_t int32 + +type _Gid_t uint32 + +type dev_t uint32 + +type Stat_t struct { + Dev uint32 + Ino uint32 + Mode uint32 + Nlink int16 + Flag uint16 + Uid uint32 + Gid uint32 + Rdev uint32 + Size int32 + Atim StTimespec + Mtim StTimespec + Ctim StTimespec + Blksize int32 + Blocks int32 + Vfstype int32 + Vfs uint32 + Type uint32 + Gen uint32 + Reserved [9]uint32 +} + +type StatxTimestamp struct{} + +type Statx_t struct{} + +type Dirent struct { + Offset uint32 + Ino uint32 + Reclen uint16 + Namlen uint16 + Name [256]uint8 +} + +type RawSockaddrInet4 struct { + Len uint8 + Family uint8 + Port uint16 + Addr [4]byte /* in_addr */ + Zero [8]uint8 +} + +type RawSockaddrInet6 struct { + Len uint8 + Family uint8 + Port uint16 + Flowinfo uint32 + Addr [16]byte /* in6_addr */ + Scope_id uint32 +} + +type RawSockaddrUnix struct { + Len uint8 + Family uint8 + Path [1023]uint8 +} + +type RawSockaddr struct { + Len uint8 + Family uint8 + Data [14]uint8 +} + +type RawSockaddrAny struct { + Addr RawSockaddr + Pad [1012]uint8 +} + +type _Socklen uint32 + +type Cmsghdr struct { + Len uint32 + Level int32 + Type int32 +} + +type ICMPv6Filter struct { + Filt [8]uint32 +} + +type Iovec struct { + Base *byte + Len uint32 +} + +type IPMreq struct { + Multiaddr [4]byte /* in_addr */ + Interface [4]byte /* in_addr */ +} + +type IPv6Mreq struct { + Multiaddr [16]byte /* in6_addr */ + Interface uint32 +} + +type IPv6MTUInfo struct { + Addr RawSockaddrInet6 + Mtu uint32 +} + +type Linger struct { + Onoff int32 + Linger int32 +} + +type Msghdr struct { + Name *byte + Namelen uint32 + Iov *Iovec + Iovlen int32 + Control *byte + Controllen uint32 + Flags int32 +} + +const ( + SizeofSockaddrInet4 = 0x10 + SizeofSockaddrInet6 = 0x1c + SizeofSockaddrAny = 0x404 + SizeofSockaddrUnix = 0x401 + SizeofLinger = 0x8 + SizeofIPMreq = 0x8 + SizeofIPv6Mreq = 0x14 + SizeofIPv6MTUInfo = 0x20 + SizeofMsghdr = 0x1c + SizeofCmsghdr = 0xc + SizeofICMPv6Filter = 0x20 +) + +const ( + SizeofIfMsghdr = 0x10 +) + +type IfMsgHdr struct { + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + Addrlen uint8 + _ [1]byte +} + +type FdSet struct { + Bits [2048]int32 +} + +type Utsname struct { + Sysname [32]byte + Nodename [32]byte + Release [32]byte + Version [32]byte + Machine [32]byte +} + +type Ustat_t struct{} + +type Sigset_t struct { + Losigs uint32 + Hisigs uint32 +} + +const ( + AT_FDCWD = -0x2 + AT_REMOVEDIR = 0x1 + AT_SYMLINK_NOFOLLOW = 0x1 +) + +type Termios struct { + Iflag uint32 + Oflag uint32 + Cflag uint32 + Lflag uint32 + Cc [16]uint8 +} + +type Termio struct { + Iflag uint16 + Oflag uint16 + Cflag uint16 + Lflag uint16 + Line uint8 + Cc [8]uint8 + _ [1]byte +} + +type Winsize struct { + Row uint16 + Col uint16 + Xpixel uint16 + Ypixel uint16 +} + +type PollFd struct { + Fd int32 + Events uint16 + Revents uint16 +} + +const ( + POLLERR = 0x4000 + POLLHUP = 0x2000 + POLLIN = 0x1 + POLLNVAL = 0x8000 + POLLOUT = 0x2 + POLLPRI = 0x4 + POLLRDBAND = 0x20 + POLLRDNORM = 0x10 + POLLWRBAND = 0x40 + POLLWRNORM = 0x2 +) + +type Flock_t struct { + Type int16 + Whence int16 + Sysid uint32 + Pid int32 + Vfs int32 + Start int64 + Len int64 +} + +type Fsid_t struct { + Val [2]uint32 +} +type Fsid64_t struct { + Val [2]uint64 +} + +type Statfs_t struct { + Version int32 + Type int32 + Bsize uint32 + Blocks uint32 + Bfree uint32 + Bavail uint32 + Files uint32 + Ffree uint32 + Fsid Fsid_t + Vfstype int32 + Fsize uint32 + Vfsnumber int32 + Vfsoff int32 + Vfslen int32 + Vfsvers int32 + Fname [32]uint8 + Fpack [32]uint8 + Name_max int32 +} + +const RNDGETENTCNT = 0x80045200 diff --git a/vendor/golang.org/x/sys/unix/ztypes_aix_ppc64.go b/vendor/golang.org/x/sys/unix/ztypes_aix_ppc64.go new file mode 100644 index 0000000000..f46482d272 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/ztypes_aix_ppc64.go @@ -0,0 +1,354 @@ +// cgo -godefs types_aix.go | go run mkpost.go +// Code generated by the command above; see README.md. DO NOT EDIT. + +// +build ppc64,aix + +package unix + +const ( + SizeofPtr = 0x8 + SizeofShort = 0x2 + SizeofInt = 0x4 + SizeofLong = 0x8 + SizeofLongLong = 0x8 + PathMax = 0x3ff +) + +type ( + _C_short int16 + _C_int int32 + _C_long int64 + _C_long_long int64 +) + +type off64 int64 +type off int64 +type Mode_t uint32 + +type Timespec struct { + Sec int64 + Nsec int64 +} + +type StTimespec struct { + Sec int64 + Nsec int32 + _ [4]byte +} + +type Timeval struct { + Sec int64 + Usec int32 + _ [4]byte +} + +type Timeval32 struct { + Sec int32 + Usec int32 +} + +type Timex struct{} + +type Time_t int64 + +type Tms struct{} + +type Utimbuf struct { + Actime int64 + Modtime int64 +} + +type Timezone struct { + Minuteswest int32 + Dsttime int32 +} + +type Rusage struct { + Utime Timeval + Stime Timeval + Maxrss int64 + Ixrss int64 + Idrss int64 + Isrss int64 + Minflt int64 + Majflt int64 + Nswap int64 + Inblock int64 + Oublock int64 + Msgsnd int64 + Msgrcv int64 + Nsignals int64 + Nvcsw int64 + Nivcsw int64 +} + +type Rlimit struct { + Cur uint64 + Max uint64 +} + +type Pid_t int32 + +type _Gid_t uint32 + +type dev_t uint64 + +type Stat_t struct { + Dev uint64 + Ino uint64 + Mode uint32 + Nlink int16 + Flag uint16 + Uid uint32 + Gid uint32 + Rdev uint64 + Ssize int32 + _ [4]byte + Atim StTimespec + Mtim StTimespec + Ctim StTimespec + Blksize int64 + Blocks int64 + Vfstype int32 + Vfs uint32 + Type uint32 + Gen uint32 + Reserved [9]uint32 + Padto_ll uint32 + Size int64 +} + +type StatxTimestamp struct{} + +type Statx_t struct{} + +type Dirent struct { + Offset uint64 + Ino uint64 + Reclen uint16 + Namlen uint16 + Name [256]uint8 + _ [4]byte +} + +type RawSockaddrInet4 struct { + Len uint8 + Family uint8 + Port uint16 + Addr [4]byte /* in_addr */ + Zero [8]uint8 +} + +type RawSockaddrInet6 struct { + Len uint8 + Family uint8 + Port uint16 + Flowinfo uint32 + Addr [16]byte /* in6_addr */ + Scope_id uint32 +} + +type RawSockaddrUnix struct { + Len uint8 + Family uint8 + Path [1023]uint8 +} + +type RawSockaddr struct { + Len uint8 + Family uint8 + Data [14]uint8 +} + +type RawSockaddrAny struct { + Addr RawSockaddr + Pad [1012]uint8 +} + +type _Socklen uint32 + +type Cmsghdr struct { + Len uint32 + Level int32 + Type int32 +} + +type ICMPv6Filter struct { + Filt [8]uint32 +} + +type Iovec struct { + Base *byte + Len uint64 +} + +type IPMreq struct { + Multiaddr [4]byte /* in_addr */ + Interface [4]byte /* in_addr */ +} + +type IPv6Mreq struct { + Multiaddr [16]byte /* in6_addr */ + Interface uint32 +} + +type IPv6MTUInfo struct { + Addr RawSockaddrInet6 + Mtu uint32 +} + +type Linger struct { + Onoff int32 + Linger int32 +} + +type Msghdr struct { + Name *byte + Namelen uint32 + _ [4]byte + Iov *Iovec + Iovlen int32 + _ [4]byte + Control *byte + Controllen uint32 + Flags int32 +} + +const ( + SizeofSockaddrInet4 = 0x10 + SizeofSockaddrInet6 = 0x1c + SizeofSockaddrAny = 0x404 + SizeofSockaddrUnix = 0x401 + SizeofLinger = 0x8 + SizeofIPMreq = 0x8 + SizeofIPv6Mreq = 0x14 + SizeofIPv6MTUInfo = 0x20 + SizeofMsghdr = 0x30 + SizeofCmsghdr = 0xc + SizeofICMPv6Filter = 0x20 +) + +const ( + SizeofIfMsghdr = 0x10 +) + +type IfMsgHdr struct { + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + Addrlen uint8 + _ [1]byte +} + +type FdSet struct { + Bits [1024]int64 +} + +type Utsname struct { + Sysname [32]byte + Nodename [32]byte + Release [32]byte + Version [32]byte + Machine [32]byte +} + +type Ustat_t struct{} + +type Sigset_t struct { + Set [4]uint64 +} + +const ( + AT_FDCWD = -0x2 + AT_REMOVEDIR = 0x1 + AT_SYMLINK_NOFOLLOW = 0x1 +) + +type Termios struct { + Iflag uint32 + Oflag uint32 + Cflag uint32 + Lflag uint32 + Cc [16]uint8 +} + +type Termio struct { + Iflag uint16 + Oflag uint16 + Cflag uint16 + Lflag uint16 + Line uint8 + Cc [8]uint8 + _ [1]byte +} + +type Winsize struct { + Row uint16 + Col uint16 + Xpixel uint16 + Ypixel uint16 +} + +type PollFd struct { + Fd int32 + Events uint16 + Revents uint16 +} + +const ( + POLLERR = 0x4000 + POLLHUP = 0x2000 + POLLIN = 0x1 + POLLNVAL = 0x8000 + POLLOUT = 0x2 + POLLPRI = 0x4 + POLLRDBAND = 0x20 + POLLRDNORM = 0x10 + POLLWRBAND = 0x40 + POLLWRNORM = 0x2 +) + +type Flock_t struct { + Type int16 + Whence int16 + Sysid uint32 + Pid int32 + Vfs int32 + Start int64 + Len int64 +} + +type Fsid_t struct { + Val [2]uint32 +} +type Fsid64_t struct { + Val [2]uint64 +} + +type Statfs_t struct { + Version int32 + Type int32 + Bsize uint64 + Blocks uint64 + Bfree uint64 + Bavail uint64 + Files uint64 + Ffree uint64 + Fsid Fsid64_t + Vfstype int32 + _ [4]byte + Fsize uint64 + Vfsnumber int32 + Vfsoff int32 + Vfslen int32 + Vfsvers int32 + Fname [32]uint8 + Fpack [32]uint8 + Name_max int32 + _ [4]byte +} + +const RNDGETENTCNT = 0x80045200 diff --git a/vendor/golang.org/x/sys/unix/ztypes_darwin_386.go b/vendor/golang.org/x/sys/unix/ztypes_darwin_386.go index 4667c7b277..2aeb52a886 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_darwin_386.go +++ b/vendor/golang.org/x/sys/unix/ztypes_darwin_386.go @@ -6,11 +6,11 @@ package unix const ( - sizeofPtr = 0x4 - sizeofShort = 0x2 - sizeofInt = 0x4 - sizeofLong = 0x4 - sizeofLongLong = 0x8 + SizeofPtr = 0x4 + SizeofShort = 0x2 + SizeofInt = 0x4 + SizeofLong = 0x4 + SizeofLongLong = 0x8 ) type ( @@ -136,13 +136,13 @@ type Fsid struct { } type Dirent struct { - Ino uint64 - Seekoff uint64 - Reclen uint16 - Namlen uint16 - Type uint8 - Name [1024]int8 - Pad_cgo_0 [3]byte + Ino uint64 + Seekoff uint64 + Reclen uint16 + Namlen uint16 + Type uint8 + Name [1024]int8 + _ [3]byte } type RawSockaddrInet4 struct { @@ -295,14 +295,14 @@ const ( ) type IfMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Pad_cgo_0 [2]byte - Data IfData + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte + Data IfData } type IfData struct { @@ -338,51 +338,51 @@ type IfData struct { } type IfaMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Pad_cgo_0 [2]byte - Metric int32 + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte + Metric int32 } type IfmaMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Pad_cgo_0 [2]byte + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte } type IfmaMsghdr2 struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Pad_cgo_0 [2]byte - Refcount int32 + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte + Refcount int32 } type RtMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Index uint16 - Pad_cgo_0 [2]byte - Flags int32 - Addrs int32 - Pid int32 - Seq int32 - Errno int32 - Use int32 - Inits uint32 - Rmx RtMetrics + Msglen uint16 + Version uint8 + Type uint8 + Index uint16 + _ [2]byte + Flags int32 + Addrs int32 + Pid int32 + Seq int32 + Errno int32 + Use int32 + Inits uint32 + Rmx RtMetrics } type RtMetrics struct { @@ -430,11 +430,11 @@ type BpfInsn struct { } type BpfHdr struct { - Tstamp Timeval - Caplen uint32 - Datalen uint32 - Hdrlen uint16 - Pad_cgo_0 [2]byte + Tstamp Timeval + Caplen uint32 + Datalen uint32 + Hdrlen uint16 + _ [2]byte } type Termios struct { @@ -479,3 +479,11 @@ const ( POLLWRBAND = 0x100 POLLWRNORM = 0x4 ) + +type Utsname struct { + Sysname [256]byte + Nodename [256]byte + Release [256]byte + Version [256]byte + Machine [256]byte +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go index 3f33b18fc7..0d0d9f2ccb 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go @@ -6,11 +6,11 @@ package unix const ( - sizeofPtr = 0x8 - sizeofShort = 0x2 - sizeofInt = 0x4 - sizeofLong = 0x8 - sizeofLongLong = 0x8 + SizeofPtr = 0x8 + SizeofShort = 0x2 + SizeofInt = 0x4 + SizeofLong = 0x8 + SizeofLongLong = 0x8 ) type ( @@ -26,9 +26,9 @@ type Timespec struct { } type Timeval struct { - Sec int64 - Usec int32 - Pad_cgo_0 [4]byte + Sec int64 + Usec int32 + _ [4]byte } type Timeval32 struct { @@ -70,7 +70,7 @@ type Stat_t struct { Uid uint32 Gid uint32 Rdev int32 - Pad_cgo_0 [4]byte + _ [4]byte Atimespec Timespec Mtimespec Timespec Ctimespec Timespec @@ -120,9 +120,9 @@ type Fstore_t struct { } type Radvisory_t struct { - Offset int64 - Count int32 - Pad_cgo_0 [4]byte + Offset int64 + Count int32 + _ [4]byte } type Fbootstraptransfer_t struct { @@ -132,9 +132,9 @@ type Fbootstraptransfer_t struct { } type Log2phys_t struct { - Flags uint32 - Pad_cgo_0 [8]byte - Pad_cgo_1 [8]byte + Flags uint32 + _ [8]byte + _ [8]byte } type Fsid struct { @@ -142,13 +142,13 @@ type Fsid struct { } type Dirent struct { - Ino uint64 - Seekoff uint64 - Reclen uint16 - Namlen uint16 - Type uint8 - Name [1024]int8 - Pad_cgo_0 [3]byte + Ino uint64 + Seekoff uint64 + Reclen uint16 + Namlen uint16 + Type uint8 + Name [1024]int8 + _ [3]byte } type RawSockaddrInet4 struct { @@ -221,10 +221,10 @@ type IPv6Mreq struct { type Msghdr struct { Name *byte Namelen uint32 - Pad_cgo_0 [4]byte + _ [4]byte Iov *Iovec Iovlen int32 - Pad_cgo_1 [4]byte + _ [4]byte Control *byte Controllen uint32 Flags int32 @@ -303,14 +303,14 @@ const ( ) type IfMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Pad_cgo_0 [2]byte - Data IfData + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte + Data IfData } type IfData struct { @@ -346,51 +346,51 @@ type IfData struct { } type IfaMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Pad_cgo_0 [2]byte - Metric int32 + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte + Metric int32 } type IfmaMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Pad_cgo_0 [2]byte + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte } type IfmaMsghdr2 struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Pad_cgo_0 [2]byte - Refcount int32 + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte + Refcount int32 } type RtMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Index uint16 - Pad_cgo_0 [2]byte - Flags int32 - Addrs int32 - Pid int32 - Seq int32 - Errno int32 - Use int32 - Inits uint32 - Rmx RtMetrics + Msglen uint16 + Version uint8 + Type uint8 + Index uint16 + _ [2]byte + Flags int32 + Addrs int32 + Pid int32 + Seq int32 + Errno int32 + Use int32 + Inits uint32 + Rmx RtMetrics } type RtMetrics struct { @@ -426,9 +426,9 @@ type BpfStat struct { } type BpfProgram struct { - Len uint32 - Pad_cgo_0 [4]byte - Insns *BpfInsn + Len uint32 + _ [4]byte + Insns *BpfInsn } type BpfInsn struct { @@ -439,22 +439,22 @@ type BpfInsn struct { } type BpfHdr struct { - Tstamp Timeval32 - Caplen uint32 - Datalen uint32 - Hdrlen uint16 - Pad_cgo_0 [2]byte + Tstamp Timeval32 + Caplen uint32 + Datalen uint32 + Hdrlen uint16 + _ [2]byte } type Termios struct { - Iflag uint64 - Oflag uint64 - Cflag uint64 - Lflag uint64 - Cc [20]uint8 - Pad_cgo_0 [4]byte - Ispeed uint64 - Ospeed uint64 + Iflag uint64 + Oflag uint64 + Cflag uint64 + Lflag uint64 + Cc [20]uint8 + _ [4]byte + Ispeed uint64 + Ospeed uint64 } type Winsize struct { @@ -489,3 +489,11 @@ const ( POLLWRBAND = 0x100 POLLWRNORM = 0x4 ) + +type Utsname struct { + Sysname [256]byte + Nodename [256]byte + Release [256]byte + Version [256]byte + Machine [256]byte +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_darwin_arm.go b/vendor/golang.org/x/sys/unix/ztypes_darwin_arm.go index 463a28ba6f..04e344b78d 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_darwin_arm.go +++ b/vendor/golang.org/x/sys/unix/ztypes_darwin_arm.go @@ -7,11 +7,11 @@ package unix const ( - sizeofPtr = 0x4 - sizeofShort = 0x2 - sizeofInt = 0x4 - sizeofLong = 0x4 - sizeofLongLong = 0x8 + SizeofPtr = 0x4 + SizeofShort = 0x2 + SizeofInt = 0x4 + SizeofLong = 0x4 + SizeofLongLong = 0x8 ) type ( @@ -137,13 +137,13 @@ type Fsid struct { } type Dirent struct { - Ino uint64 - Seekoff uint64 - Reclen uint16 - Namlen uint16 - Type uint8 - Name [1024]int8 - Pad_cgo_0 [3]byte + Ino uint64 + Seekoff uint64 + Reclen uint16 + Namlen uint16 + Type uint8 + Name [1024]int8 + _ [3]byte } type RawSockaddrInet4 struct { @@ -296,14 +296,14 @@ const ( ) type IfMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Pad_cgo_0 [2]byte - Data IfData + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte + Data IfData } type IfData struct { @@ -339,51 +339,51 @@ type IfData struct { } type IfaMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Pad_cgo_0 [2]byte - Metric int32 + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte + Metric int32 } type IfmaMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Pad_cgo_0 [2]byte + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte } type IfmaMsghdr2 struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Pad_cgo_0 [2]byte - Refcount int32 + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte + Refcount int32 } type RtMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Index uint16 - Pad_cgo_0 [2]byte - Flags int32 - Addrs int32 - Pid int32 - Seq int32 - Errno int32 - Use int32 - Inits uint32 - Rmx RtMetrics + Msglen uint16 + Version uint8 + Type uint8 + Index uint16 + _ [2]byte + Flags int32 + Addrs int32 + Pid int32 + Seq int32 + Errno int32 + Use int32 + Inits uint32 + Rmx RtMetrics } type RtMetrics struct { @@ -431,11 +431,11 @@ type BpfInsn struct { } type BpfHdr struct { - Tstamp Timeval - Caplen uint32 - Datalen uint32 - Hdrlen uint16 - Pad_cgo_0 [2]byte + Tstamp Timeval + Caplen uint32 + Datalen uint32 + Hdrlen uint16 + _ [2]byte } type Termios struct { @@ -480,3 +480,11 @@ const ( POLLWRBAND = 0x100 POLLWRNORM = 0x4 ) + +type Utsname struct { + Sysname [256]byte + Nodename [256]byte + Release [256]byte + Version [256]byte + Machine [256]byte +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go b/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go index 1ec20a0025..9fec185c18 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go @@ -6,11 +6,11 @@ package unix const ( - sizeofPtr = 0x8 - sizeofShort = 0x2 - sizeofInt = 0x4 - sizeofLong = 0x8 - sizeofLongLong = 0x8 + SizeofPtr = 0x8 + SizeofShort = 0x2 + SizeofInt = 0x4 + SizeofLong = 0x8 + SizeofLongLong = 0x8 ) type ( @@ -26,9 +26,9 @@ type Timespec struct { } type Timeval struct { - Sec int64 - Usec int32 - Pad_cgo_0 [4]byte + Sec int64 + Usec int32 + _ [4]byte } type Timeval32 struct { @@ -70,7 +70,7 @@ type Stat_t struct { Uid uint32 Gid uint32 Rdev int32 - Pad_cgo_0 [4]byte + _ [4]byte Atimespec Timespec Mtimespec Timespec Ctimespec Timespec @@ -120,9 +120,9 @@ type Fstore_t struct { } type Radvisory_t struct { - Offset int64 - Count int32 - Pad_cgo_0 [4]byte + Offset int64 + Count int32 + _ [4]byte } type Fbootstraptransfer_t struct { @@ -132,9 +132,9 @@ type Fbootstraptransfer_t struct { } type Log2phys_t struct { - Flags uint32 - Pad_cgo_0 [8]byte - Pad_cgo_1 [8]byte + Flags uint32 + _ [8]byte + _ [8]byte } type Fsid struct { @@ -142,13 +142,13 @@ type Fsid struct { } type Dirent struct { - Ino uint64 - Seekoff uint64 - Reclen uint16 - Namlen uint16 - Type uint8 - Name [1024]int8 - Pad_cgo_0 [3]byte + Ino uint64 + Seekoff uint64 + Reclen uint16 + Namlen uint16 + Type uint8 + Name [1024]int8 + _ [3]byte } type RawSockaddrInet4 struct { @@ -221,10 +221,10 @@ type IPv6Mreq struct { type Msghdr struct { Name *byte Namelen uint32 - Pad_cgo_0 [4]byte + _ [4]byte Iov *Iovec Iovlen int32 - Pad_cgo_1 [4]byte + _ [4]byte Control *byte Controllen uint32 Flags int32 @@ -303,14 +303,14 @@ const ( ) type IfMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Pad_cgo_0 [2]byte - Data IfData + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte + Data IfData } type IfData struct { @@ -346,51 +346,51 @@ type IfData struct { } type IfaMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Pad_cgo_0 [2]byte - Metric int32 + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte + Metric int32 } type IfmaMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Pad_cgo_0 [2]byte + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte } type IfmaMsghdr2 struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Pad_cgo_0 [2]byte - Refcount int32 + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte + Refcount int32 } type RtMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Index uint16 - Pad_cgo_0 [2]byte - Flags int32 - Addrs int32 - Pid int32 - Seq int32 - Errno int32 - Use int32 - Inits uint32 - Rmx RtMetrics + Msglen uint16 + Version uint8 + Type uint8 + Index uint16 + _ [2]byte + Flags int32 + Addrs int32 + Pid int32 + Seq int32 + Errno int32 + Use int32 + Inits uint32 + Rmx RtMetrics } type RtMetrics struct { @@ -426,9 +426,9 @@ type BpfStat struct { } type BpfProgram struct { - Len uint32 - Pad_cgo_0 [4]byte - Insns *BpfInsn + Len uint32 + _ [4]byte + Insns *BpfInsn } type BpfInsn struct { @@ -439,22 +439,22 @@ type BpfInsn struct { } type BpfHdr struct { - Tstamp Timeval32 - Caplen uint32 - Datalen uint32 - Hdrlen uint16 - Pad_cgo_0 [2]byte + Tstamp Timeval32 + Caplen uint32 + Datalen uint32 + Hdrlen uint16 + _ [2]byte } type Termios struct { - Iflag uint64 - Oflag uint64 - Cflag uint64 - Lflag uint64 - Cc [20]uint8 - Pad_cgo_0 [4]byte - Ispeed uint64 - Ospeed uint64 + Iflag uint64 + Oflag uint64 + Cflag uint64 + Lflag uint64 + Cc [20]uint8 + _ [4]byte + Ispeed uint64 + Ospeed uint64 } type Winsize struct { @@ -489,3 +489,11 @@ const ( POLLWRBAND = 0x100 POLLWRNORM = 0x4 ) + +type Utsname struct { + Sysname [256]byte + Nodename [256]byte + Release [256]byte + Version [256]byte + Machine [256]byte +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_dragonfly_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_dragonfly_amd64.go index 1ca0e3ee04..7b34e2e2c6 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_dragonfly_amd64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_dragonfly_amd64.go @@ -6,11 +6,11 @@ package unix const ( - sizeofPtr = 0x8 - sizeofShort = 0x2 - sizeofInt = 0x4 - sizeofLong = 0x8 - sizeofLongLong = 0x8 + SizeofPtr = 0x8 + SizeofShort = 0x2 + SizeofInt = 0x4 + SizeofLong = 0x8 + SizeofLongLong = 0x8 ) type ( @@ -56,23 +56,6 @@ type Rlimit struct { type _Gid_t uint32 -const ( - S_IFMT = 0xf000 - S_IFIFO = 0x1000 - S_IFCHR = 0x2000 - S_IFDIR = 0x4000 - S_IFBLK = 0x6000 - S_IFREG = 0x8000 - S_IFLNK = 0xa000 - S_IFSOCK = 0xc000 - S_ISUID = 0x800 - S_ISGID = 0x400 - S_ISVTX = 0x200 - S_IRUSR = 0x100 - S_IWUSR = 0x80 - S_IXUSR = 0x40 -) - type Stat_t struct { Ino uint64 Nlink uint32 @@ -108,7 +91,7 @@ type Statfs_t struct { Owner uint32 Type int32 Flags int32 - Pad_cgo_0 [4]byte + _ [4]byte Syncwrites int64 Asyncwrites int64 Fstypename [16]int8 @@ -118,7 +101,7 @@ type Statfs_t struct { Spares1 int16 Mntfromname [80]int8 Spares2 int16 - Pad_cgo_1 [4]byte + _ [4]byte Spare [2]int64 } @@ -143,6 +126,10 @@ type Fsid struct { Val [2]int32 } +const ( + PathMax = 0x400 +) + type RawSockaddrInet4 struct { Len uint8 Family uint8 @@ -215,10 +202,10 @@ type IPv6Mreq struct { type Msghdr struct { Name *byte Namelen uint32 - Pad_cgo_0 [4]byte + _ [4]byte Iov *Iovec Iovlen int32 - Pad_cgo_1 [4]byte + _ [4]byte Control *byte Controllen uint32 Flags int32 @@ -290,14 +277,14 @@ const ( ) type IfMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Pad_cgo_0 [2]byte - Data IfData + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte + Data IfData } type IfData struct { @@ -307,7 +294,7 @@ type IfData struct { Hdrlen uint8 Recvquota uint8 Xmitquota uint8 - Pad_cgo_0 [2]byte + _ [2]byte Mtu uint64 Metric uint64 Link_state uint64 @@ -329,24 +316,24 @@ type IfData struct { } type IfaMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Pad_cgo_0 [2]byte - Metric int32 + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte + Metric int32 } type IfmaMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Pad_cgo_0 [2]byte + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte } type IfAnnounceMsghdr struct { @@ -359,19 +346,19 @@ type IfAnnounceMsghdr struct { } type RtMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Index uint16 - Pad_cgo_0 [2]byte - Flags int32 - Addrs int32 - Pid int32 - Seq int32 - Errno int32 - Use int32 - Inits uint64 - Rmx RtMetrics + Msglen uint16 + Version uint8 + Type uint8 + Index uint16 + _ [2]byte + Flags int32 + Addrs int32 + Pid int32 + Seq int32 + Errno int32 + Use int32 + Inits uint64 + Rmx RtMetrics } type RtMetrics struct { @@ -387,7 +374,7 @@ type RtMetrics struct { Hopcount uint64 Mssopt uint16 Pad uint16 - Pad_cgo_0 [4]byte + _ [4]byte Msl uint64 Iwmaxsegs uint64 Iwcapsegs uint64 @@ -412,9 +399,9 @@ type BpfStat struct { } type BpfProgram struct { - Len uint32 - Pad_cgo_0 [4]byte - Insns *BpfInsn + Len uint32 + _ [4]byte + Insns *BpfInsn } type BpfInsn struct { @@ -425,11 +412,11 @@ type BpfInsn struct { } type BpfHdr struct { - Tstamp Timeval - Caplen uint32 - Datalen uint32 - Hdrlen uint16 - Pad_cgo_0 [6]byte + Tstamp Timeval + Caplen uint32 + Datalen uint32 + Hdrlen uint16 + _ [6]byte } type Termios struct { @@ -472,3 +459,11 @@ const ( POLLWRBAND = 0x100 POLLWRNORM = 0x4 ) + +type Utsname struct { + Sysname [32]byte + Nodename [32]byte + Release [32]byte + Version [32]byte + Machine [32]byte +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go b/vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go index 18f7816009..c146c1ad35 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go +++ b/vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go @@ -6,11 +6,11 @@ package unix const ( - sizeofPtr = 0x4 - sizeofShort = 0x2 - sizeofInt = 0x4 - sizeofLong = 0x4 - sizeofLongLong = 0x8 + SizeofPtr = 0x4 + SizeofShort = 0x2 + SizeofInt = 0x4 + SizeofLong = 0x4 + SizeofLongLong = 0x8 ) type ( @@ -57,44 +57,83 @@ type Rlimit struct { type _Gid_t uint32 const ( - S_IFMT = 0xf000 - S_IFIFO = 0x1000 - S_IFCHR = 0x2000 - S_IFDIR = 0x4000 - S_IFBLK = 0x6000 - S_IFREG = 0x8000 - S_IFLNK = 0xa000 - S_IFSOCK = 0xc000 - S_ISUID = 0x800 - S_ISGID = 0x400 - S_ISVTX = 0x200 - S_IRUSR = 0x100 - S_IWUSR = 0x80 - S_IXUSR = 0x40 + _statfsVersion = 0x20140518 + _dirblksiz = 0x400 ) type Stat_t struct { - Dev uint32 - Ino uint32 - Mode uint16 - Nlink uint16 - Uid uint32 - Gid uint32 - Rdev uint32 - Atimespec Timespec - Mtimespec Timespec - Ctimespec Timespec - Size int64 - Blocks int64 - Blksize int32 - Flags uint32 - Gen uint32 - Lspare int32 - Birthtimespec Timespec - Pad_cgo_0 [8]byte + Dev uint64 + Ino uint64 + Nlink uint64 + Mode uint16 + _0 int16 + Uid uint32 + Gid uint32 + _1 int32 + Rdev uint64 + Atim_ext int32 + Atim Timespec + Mtim_ext int32 + Mtim Timespec + Ctim_ext int32 + Ctim Timespec + Btim_ext int32 + Birthtim Timespec + Size int64 + Blocks int64 + Blksize int32 + Flags uint32 + Gen uint64 + Spare [10]uint64 +} + +type stat_freebsd11_t struct { + Dev uint32 + Ino uint32 + Mode uint16 + Nlink uint16 + Uid uint32 + Gid uint32 + Rdev uint32 + Atim Timespec + Mtim Timespec + Ctim Timespec + Size int64 + Blocks int64 + Blksize int32 + Flags uint32 + Gen uint32 + Lspare int32 + Birthtim Timespec + _ [8]byte } type Statfs_t struct { + Version uint32 + Type uint32 + Flags uint64 + Bsize uint64 + Iosize uint64 + Blocks uint64 + Bfree uint64 + Bavail int64 + Files uint64 + Ffree int64 + Syncwrites uint64 + Asyncwrites uint64 + Syncreads uint64 + Asyncreads uint64 + Spare [10]uint64 + Namemax uint32 + Owner uint32 + Fsid Fsid + Charspare [80]int8 + Fstypename [16]int8 + Mntfromname [1024]int8 + Mntonname [1024]int8 +} + +type statfs_freebsd11_t struct { Version uint32 Type uint32 Flags uint64 @@ -129,6 +168,17 @@ type Flock_t struct { } type Dirent struct { + Fileno uint64 + Off int64 + Reclen uint16 + Type uint8 + Pad0 uint8 + Namlen uint16 + Pad1 uint16 + Name [256]int8 +} + +type dirent_freebsd11 struct { Fileno uint32 Reclen uint16 Type uint8 @@ -140,6 +190,10 @@ type Fsid struct { Val [2]int32 } +const ( + PathMax = 0x400 +) + const ( FADV_NORMAL = 0x0 FADV_RANDOM = 0x1 @@ -285,7 +339,7 @@ type Kevent_t struct { } type FdSet struct { - X__fds_bits [32]uint32 + Bits [32]uint32 } const ( @@ -301,53 +355,53 @@ const ( ) type ifMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Pad_cgo_0 [2]byte - Data ifData + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte + Data ifData } type IfMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Pad_cgo_0 [2]byte - Data IfData + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte + Data IfData } type ifData struct { - Type uint8 - Physical uint8 - Addrlen uint8 - Hdrlen uint8 - Link_state uint8 - Vhid uint8 - Datalen uint16 - Mtu uint32 - Metric uint32 - Baudrate uint64 - Ipackets uint64 - Ierrors uint64 - Opackets uint64 - Oerrors uint64 - Collisions uint64 - Ibytes uint64 - Obytes uint64 - Imcasts uint64 - Omcasts uint64 - Iqdrops uint64 - Oqdrops uint64 - Noproto uint64 - Hwassist uint64 - X__ifi_epoch [8]byte - X__ifi_lastchange [16]byte + Type uint8 + Physical uint8 + Addrlen uint8 + Hdrlen uint8 + Link_state uint8 + Vhid uint8 + Datalen uint16 + Mtu uint32 + Metric uint32 + Baudrate uint64 + Ipackets uint64 + Ierrors uint64 + Opackets uint64 + Oerrors uint64 + Collisions uint64 + Ibytes uint64 + Obytes uint64 + Imcasts uint64 + Omcasts uint64 + Iqdrops uint64 + Oqdrops uint64 + Noproto uint64 + Hwassist uint64 + _ [8]byte + _ [16]byte } type IfData struct { @@ -379,24 +433,24 @@ type IfData struct { } type IfaMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Pad_cgo_0 [2]byte - Metric int32 + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte + Metric int32 } type IfmaMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Pad_cgo_0 [2]byte + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte } type IfAnnounceMsghdr struct { @@ -409,19 +463,19 @@ type IfAnnounceMsghdr struct { } type RtMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Index uint16 - Pad_cgo_0 [2]byte - Flags int32 - Addrs int32 - Pid int32 - Seq int32 - Errno int32 - Fmask int32 - Inits uint32 - Rmx RtMetrics + Msglen uint16 + Version uint8 + Type uint8 + Index uint16 + _ [2]byte + Flags int32 + Addrs int32 + Pid int32 + Seq int32 + Errno int32 + Fmask int32 + Inits uint32 + Rmx RtMetrics } type RtMetrics struct { @@ -478,18 +532,18 @@ type BpfInsn struct { } type BpfHdr struct { - Tstamp Timeval - Caplen uint32 - Datalen uint32 - Hdrlen uint16 - Pad_cgo_0 [2]byte + Tstamp Timeval + Caplen uint32 + Datalen uint32 + Hdrlen uint16 + _ [2]byte } type BpfZbufHeader struct { Kernel_gen uint32 Kernel_len uint32 User_gen uint32 - X_bzh_pad [5]uint32 + _ [5]uint32 } type Termios struct { @@ -539,3 +593,11 @@ const ( type CapRights struct { Rights [2]uint64 } + +type Utsname struct { + Sysname [256]byte + Nodename [256]byte + Release [256]byte + Version [256]byte + Machine [256]byte +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go index dd0db2a5ea..ac33a8dd4a 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go @@ -6,11 +6,11 @@ package unix const ( - sizeofPtr = 0x8 - sizeofShort = 0x2 - sizeofInt = 0x4 - sizeofLong = 0x8 - sizeofLongLong = 0x8 + SizeofPtr = 0x8 + SizeofShort = 0x2 + SizeofInt = 0x4 + SizeofLong = 0x8 + SizeofLongLong = 0x8 ) type ( @@ -57,43 +57,78 @@ type Rlimit struct { type _Gid_t uint32 const ( - S_IFMT = 0xf000 - S_IFIFO = 0x1000 - S_IFCHR = 0x2000 - S_IFDIR = 0x4000 - S_IFBLK = 0x6000 - S_IFREG = 0x8000 - S_IFLNK = 0xa000 - S_IFSOCK = 0xc000 - S_ISUID = 0x800 - S_ISGID = 0x400 - S_ISVTX = 0x200 - S_IRUSR = 0x100 - S_IWUSR = 0x80 - S_IXUSR = 0x40 + _statfsVersion = 0x20140518 + _dirblksiz = 0x400 ) type Stat_t struct { - Dev uint32 - Ino uint32 - Mode uint16 - Nlink uint16 - Uid uint32 - Gid uint32 - Rdev uint32 - Atimespec Timespec - Mtimespec Timespec - Ctimespec Timespec - Size int64 - Blocks int64 - Blksize int32 - Flags uint32 - Gen uint32 - Lspare int32 - Birthtimespec Timespec + Dev uint64 + Ino uint64 + Nlink uint64 + Mode uint16 + _0 int16 + Uid uint32 + Gid uint32 + _1 int32 + Rdev uint64 + Atim Timespec + Mtim Timespec + Ctim Timespec + Birthtim Timespec + Size int64 + Blocks int64 + Blksize int32 + Flags uint32 + Gen uint64 + Spare [10]uint64 +} + +type stat_freebsd11_t struct { + Dev uint32 + Ino uint32 + Mode uint16 + Nlink uint16 + Uid uint32 + Gid uint32 + Rdev uint32 + Atim Timespec + Mtim Timespec + Ctim Timespec + Size int64 + Blocks int64 + Blksize int32 + Flags uint32 + Gen uint32 + Lspare int32 + Birthtim Timespec } type Statfs_t struct { + Version uint32 + Type uint32 + Flags uint64 + Bsize uint64 + Iosize uint64 + Blocks uint64 + Bfree uint64 + Bavail int64 + Files uint64 + Ffree int64 + Syncwrites uint64 + Asyncwrites uint64 + Syncreads uint64 + Asyncreads uint64 + Spare [10]uint64 + Namemax uint32 + Owner uint32 + Fsid Fsid + Charspare [80]int8 + Fstypename [16]int8 + Mntfromname [1024]int8 + Mntonname [1024]int8 +} + +type statfs_freebsd11_t struct { Version uint32 Type uint32 Flags uint64 @@ -119,16 +154,27 @@ type Statfs_t struct { } type Flock_t struct { - Start int64 - Len int64 - Pid int32 - Type int16 - Whence int16 - Sysid int32 - Pad_cgo_0 [4]byte + Start int64 + Len int64 + Pid int32 + Type int16 + Whence int16 + Sysid int32 + _ [4]byte } type Dirent struct { + Fileno uint64 + Off int64 + Reclen uint16 + Type uint8 + Pad0 uint8 + Namlen uint16 + Pad1 uint16 + Name [256]int8 +} + +type dirent_freebsd11 struct { Fileno uint32 Reclen uint16 Type uint8 @@ -140,6 +186,10 @@ type Fsid struct { Val [2]int32 } +const ( + PathMax = 0x400 +) + const ( FADV_NORMAL = 0x0 FADV_RANDOM = 0x1 @@ -225,10 +275,10 @@ type IPv6Mreq struct { type Msghdr struct { Name *byte Namelen uint32 - Pad_cgo_0 [4]byte + _ [4]byte Iov *Iovec Iovlen int32 - Pad_cgo_1 [4]byte + _ [4]byte Control *byte Controllen uint32 Flags int32 @@ -287,7 +337,7 @@ type Kevent_t struct { } type FdSet struct { - X__fds_bits [16]uint64 + Bits [16]uint64 } const ( @@ -303,53 +353,53 @@ const ( ) type ifMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Pad_cgo_0 [2]byte - Data ifData + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte + Data ifData } type IfMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Pad_cgo_0 [2]byte - Data IfData + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte + Data IfData } type ifData struct { - Type uint8 - Physical uint8 - Addrlen uint8 - Hdrlen uint8 - Link_state uint8 - Vhid uint8 - Datalen uint16 - Mtu uint32 - Metric uint32 - Baudrate uint64 - Ipackets uint64 - Ierrors uint64 - Opackets uint64 - Oerrors uint64 - Collisions uint64 - Ibytes uint64 - Obytes uint64 - Imcasts uint64 - Omcasts uint64 - Iqdrops uint64 - Oqdrops uint64 - Noproto uint64 - Hwassist uint64 - X__ifi_epoch [8]byte - X__ifi_lastchange [16]byte + Type uint8 + Physical uint8 + Addrlen uint8 + Hdrlen uint8 + Link_state uint8 + Vhid uint8 + Datalen uint16 + Mtu uint32 + Metric uint32 + Baudrate uint64 + Ipackets uint64 + Ierrors uint64 + Opackets uint64 + Oerrors uint64 + Collisions uint64 + Ibytes uint64 + Obytes uint64 + Imcasts uint64 + Omcasts uint64 + Iqdrops uint64 + Oqdrops uint64 + Noproto uint64 + Hwassist uint64 + _ [8]byte + _ [16]byte } type IfData struct { @@ -381,24 +431,24 @@ type IfData struct { } type IfaMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Pad_cgo_0 [2]byte - Metric int32 + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte + Metric int32 } type IfmaMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Pad_cgo_0 [2]byte + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte } type IfAnnounceMsghdr struct { @@ -411,19 +461,19 @@ type IfAnnounceMsghdr struct { } type RtMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Index uint16 - Pad_cgo_0 [2]byte - Flags int32 - Addrs int32 - Pid int32 - Seq int32 - Errno int32 - Fmask int32 - Inits uint64 - Rmx RtMetrics + Msglen uint16 + Version uint8 + Type uint8 + Index uint16 + _ [2]byte + Flags int32 + Addrs int32 + Pid int32 + Seq int32 + Errno int32 + Fmask int32 + Inits uint64 + Rmx RtMetrics } type RtMetrics struct { @@ -468,9 +518,9 @@ type BpfZbuf struct { } type BpfProgram struct { - Len uint32 - Pad_cgo_0 [4]byte - Insns *BpfInsn + Len uint32 + _ [4]byte + Insns *BpfInsn } type BpfInsn struct { @@ -481,18 +531,18 @@ type BpfInsn struct { } type BpfHdr struct { - Tstamp Timeval - Caplen uint32 - Datalen uint32 - Hdrlen uint16 - Pad_cgo_0 [6]byte + Tstamp Timeval + Caplen uint32 + Datalen uint32 + Hdrlen uint16 + _ [6]byte } type BpfZbufHeader struct { Kernel_gen uint32 Kernel_len uint32 User_gen uint32 - X_bzh_pad [5]uint32 + _ [5]uint32 } type Termios struct { @@ -542,3 +592,11 @@ const ( type CapRights struct { Rights [2]uint64 } + +type Utsname struct { + Sysname [256]byte + Nodename [256]byte + Release [256]byte + Version [256]byte + Machine [256]byte +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go b/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go index 473d3dcf08..e27511a642 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go +++ b/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go @@ -6,11 +6,11 @@ package unix const ( - sizeofPtr = 0x4 - sizeofShort = 0x2 - sizeofInt = 0x4 - sizeofLong = 0x4 - sizeofLongLong = 0x8 + SizeofPtr = 0x4 + SizeofShort = 0x2 + SizeofInt = 0x4 + SizeofLong = 0x4 + SizeofLongLong = 0x8 ) type ( @@ -21,15 +21,15 @@ type ( ) type Timespec struct { - Sec int64 - Nsec int32 - Pad_cgo_0 [4]byte + Sec int64 + Nsec int32 + _ [4]byte } type Timeval struct { - Sec int64 - Usec int32 - Pad_cgo_0 [4]byte + Sec int64 + Usec int32 + _ [4]byte } type Rusage struct { @@ -59,43 +59,78 @@ type Rlimit struct { type _Gid_t uint32 const ( - S_IFMT = 0xf000 - S_IFIFO = 0x1000 - S_IFCHR = 0x2000 - S_IFDIR = 0x4000 - S_IFBLK = 0x6000 - S_IFREG = 0x8000 - S_IFLNK = 0xa000 - S_IFSOCK = 0xc000 - S_ISUID = 0x800 - S_ISGID = 0x400 - S_ISVTX = 0x200 - S_IRUSR = 0x100 - S_IWUSR = 0x80 - S_IXUSR = 0x40 + _statfsVersion = 0x20140518 + _dirblksiz = 0x400 ) type Stat_t struct { - Dev uint32 - Ino uint32 - Mode uint16 - Nlink uint16 - Uid uint32 - Gid uint32 - Rdev uint32 - Atimespec Timespec - Mtimespec Timespec - Ctimespec Timespec - Size int64 - Blocks int64 - Blksize int32 - Flags uint32 - Gen uint32 - Lspare int32 - Birthtimespec Timespec + Dev uint64 + Ino uint64 + Nlink uint64 + Mode uint16 + _0 int16 + Uid uint32 + Gid uint32 + _1 int32 + Rdev uint64 + Atim Timespec + Mtim Timespec + Ctim Timespec + Birthtim Timespec + Size int64 + Blocks int64 + Blksize int32 + Flags uint32 + Gen uint64 + Spare [10]uint64 +} + +type stat_freebsd11_t struct { + Dev uint32 + Ino uint32 + Mode uint16 + Nlink uint16 + Uid uint32 + Gid uint32 + Rdev uint32 + Atim Timespec + Mtim Timespec + Ctim Timespec + Size int64 + Blocks int64 + Blksize int32 + Flags uint32 + Gen uint32 + Lspare int32 + Birthtim Timespec } type Statfs_t struct { + Version uint32 + Type uint32 + Flags uint64 + Bsize uint64 + Iosize uint64 + Blocks uint64 + Bfree uint64 + Bavail int64 + Files uint64 + Ffree int64 + Syncwrites uint64 + Asyncwrites uint64 + Syncreads uint64 + Asyncreads uint64 + Spare [10]uint64 + Namemax uint32 + Owner uint32 + Fsid Fsid + Charspare [80]int8 + Fstypename [16]int8 + Mntfromname [1024]int8 + Mntonname [1024]int8 +} + +type statfs_freebsd11_t struct { Version uint32 Type uint32 Flags uint64 @@ -121,16 +156,27 @@ type Statfs_t struct { } type Flock_t struct { - Start int64 - Len int64 - Pid int32 - Type int16 - Whence int16 - Sysid int32 - Pad_cgo_0 [4]byte + Start int64 + Len int64 + Pid int32 + Type int16 + Whence int16 + Sysid int32 + _ [4]byte } type Dirent struct { + Fileno uint64 + Off int64 + Reclen uint16 + Type uint8 + Pad0 uint8 + Namlen uint16 + Pad1 uint16 + Name [256]int8 +} + +type dirent_freebsd11 struct { Fileno uint32 Reclen uint16 Type uint8 @@ -142,6 +188,10 @@ type Fsid struct { Val [2]int32 } +const ( + PathMax = 0x400 +) + const ( FADV_NORMAL = 0x0 FADV_RANDOM = 0x1 @@ -287,7 +337,7 @@ type Kevent_t struct { } type FdSet struct { - X__fds_bits [32]uint32 + Bits [32]uint32 } const ( @@ -303,53 +353,53 @@ const ( ) type ifMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Pad_cgo_0 [2]byte - Data ifData + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte + Data ifData } type IfMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Pad_cgo_0 [2]byte - Data IfData + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte + Data IfData } type ifData struct { - Type uint8 - Physical uint8 - Addrlen uint8 - Hdrlen uint8 - Link_state uint8 - Vhid uint8 - Datalen uint16 - Mtu uint32 - Metric uint32 - Baudrate uint64 - Ipackets uint64 - Ierrors uint64 - Opackets uint64 - Oerrors uint64 - Collisions uint64 - Ibytes uint64 - Obytes uint64 - Imcasts uint64 - Omcasts uint64 - Iqdrops uint64 - Oqdrops uint64 - Noproto uint64 - Hwassist uint64 - X__ifi_epoch [8]byte - X__ifi_lastchange [16]byte + Type uint8 + Physical uint8 + Addrlen uint8 + Hdrlen uint8 + Link_state uint8 + Vhid uint8 + Datalen uint16 + Mtu uint32 + Metric uint32 + Baudrate uint64 + Ipackets uint64 + Ierrors uint64 + Opackets uint64 + Oerrors uint64 + Collisions uint64 + Ibytes uint64 + Obytes uint64 + Imcasts uint64 + Omcasts uint64 + Iqdrops uint64 + Oqdrops uint64 + Noproto uint64 + Hwassist uint64 + _ [8]byte + _ [16]byte } type IfData struct { @@ -376,30 +426,30 @@ type IfData struct { Iqdrops uint32 Noproto uint32 Hwassist uint32 - Pad_cgo_0 [4]byte + _ [4]byte Epoch int64 Lastchange Timeval } type IfaMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Pad_cgo_0 [2]byte - Metric int32 + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte + Metric int32 } type IfmaMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Pad_cgo_0 [2]byte + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte } type IfAnnounceMsghdr struct { @@ -412,19 +462,19 @@ type IfAnnounceMsghdr struct { } type RtMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Index uint16 - Pad_cgo_0 [2]byte - Flags int32 - Addrs int32 - Pid int32 - Seq int32 - Errno int32 - Fmask int32 - Inits uint32 - Rmx RtMetrics + Msglen uint16 + Version uint8 + Type uint8 + Index uint16 + _ [2]byte + Flags int32 + Addrs int32 + Pid int32 + Seq int32 + Errno int32 + Fmask int32 + Inits uint32 + Rmx RtMetrics } type RtMetrics struct { @@ -481,18 +531,18 @@ type BpfInsn struct { } type BpfHdr struct { - Tstamp Timeval - Caplen uint32 - Datalen uint32 - Hdrlen uint16 - Pad_cgo_0 [6]byte + Tstamp Timeval + Caplen uint32 + Datalen uint32 + Hdrlen uint16 + _ [6]byte } type BpfZbufHeader struct { Kernel_gen uint32 Kernel_len uint32 User_gen uint32 - X_bzh_pad [5]uint32 + _ [5]uint32 } type Termios struct { @@ -542,3 +592,11 @@ const ( type CapRights struct { Rights [2]uint64 } + +type Utsname struct { + Sysname [256]byte + Nodename [256]byte + Release [256]byte + Version [256]byte + Machine [256]byte +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go b/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go new file mode 100644 index 0000000000..2aadc1a4d8 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go @@ -0,0 +1,602 @@ +// cgo -godefs types_freebsd.go | go run mkpost.go +// Code generated by the command above; see README.md. DO NOT EDIT. + +// +build arm64,freebsd + +package unix + +const ( + SizeofPtr = 0x8 + SizeofShort = 0x2 + SizeofInt = 0x4 + SizeofLong = 0x8 + SizeofLongLong = 0x8 +) + +type ( + _C_short int16 + _C_int int32 + _C_long int64 + _C_long_long int64 +) + +type Timespec struct { + Sec int64 + Nsec int64 +} + +type Timeval struct { + Sec int64 + Usec int64 +} + +type Rusage struct { + Utime Timeval + Stime Timeval + Maxrss int64 + Ixrss int64 + Idrss int64 + Isrss int64 + Minflt int64 + Majflt int64 + Nswap int64 + Inblock int64 + Oublock int64 + Msgsnd int64 + Msgrcv int64 + Nsignals int64 + Nvcsw int64 + Nivcsw int64 +} + +type Rlimit struct { + Cur int64 + Max int64 +} + +type _Gid_t uint32 + +const ( + _statfsVersion = 0x20140518 + _dirblksiz = 0x400 +) + +type Stat_t struct { + Dev uint64 + Ino uint64 + Nlink uint64 + Mode uint16 + _0 int16 + Uid uint32 + Gid uint32 + _1 int32 + Rdev uint64 + Atim Timespec + Mtim Timespec + Ctim Timespec + Birthtim Timespec + Size int64 + Blocks int64 + Blksize int32 + Flags uint32 + Gen uint64 + Spare [10]uint64 +} + +type stat_freebsd11_t struct { + Dev uint32 + Ino uint32 + Mode uint16 + Nlink uint16 + Uid uint32 + Gid uint32 + Rdev uint32 + Atim Timespec + Mtim Timespec + Ctim Timespec + Size int64 + Blocks int64 + Blksize int32 + Flags uint32 + Gen uint32 + Lspare int32 + Birthtim Timespec +} + +type Statfs_t struct { + Version uint32 + Type uint32 + Flags uint64 + Bsize uint64 + Iosize uint64 + Blocks uint64 + Bfree uint64 + Bavail int64 + Files uint64 + Ffree int64 + Syncwrites uint64 + Asyncwrites uint64 + Syncreads uint64 + Asyncreads uint64 + Spare [10]uint64 + Namemax uint32 + Owner uint32 + Fsid Fsid + Charspare [80]int8 + Fstypename [16]int8 + Mntfromname [1024]int8 + Mntonname [1024]int8 +} + +type statfs_freebsd11_t struct { + Version uint32 + Type uint32 + Flags uint64 + Bsize uint64 + Iosize uint64 + Blocks uint64 + Bfree uint64 + Bavail int64 + Files uint64 + Ffree int64 + Syncwrites uint64 + Asyncwrites uint64 + Syncreads uint64 + Asyncreads uint64 + Spare [10]uint64 + Namemax uint32 + Owner uint32 + Fsid Fsid + Charspare [80]int8 + Fstypename [16]int8 + Mntfromname [88]int8 + Mntonname [88]int8 +} + +type Flock_t struct { + Start int64 + Len int64 + Pid int32 + Type int16 + Whence int16 + Sysid int32 + _ [4]byte +} + +type Dirent struct { + Fileno uint64 + Off int64 + Reclen uint16 + Type uint8 + Pad0 uint8 + Namlen uint16 + Pad1 uint16 + Name [256]int8 +} + +type dirent_freebsd11 struct { + Fileno uint32 + Reclen uint16 + Type uint8 + Namlen uint8 + Name [256]int8 +} + +type Fsid struct { + Val [2]int32 +} + +const ( + PathMax = 0x400 +) + +const ( + FADV_NORMAL = 0x0 + FADV_RANDOM = 0x1 + FADV_SEQUENTIAL = 0x2 + FADV_WILLNEED = 0x3 + FADV_DONTNEED = 0x4 + FADV_NOREUSE = 0x5 +) + +type RawSockaddrInet4 struct { + Len uint8 + Family uint8 + Port uint16 + Addr [4]byte /* in_addr */ + Zero [8]int8 +} + +type RawSockaddrInet6 struct { + Len uint8 + Family uint8 + Port uint16 + Flowinfo uint32 + Addr [16]byte /* in6_addr */ + Scope_id uint32 +} + +type RawSockaddrUnix struct { + Len uint8 + Family uint8 + Path [104]int8 +} + +type RawSockaddrDatalink struct { + Len uint8 + Family uint8 + Index uint16 + Type uint8 + Nlen uint8 + Alen uint8 + Slen uint8 + Data [46]int8 +} + +type RawSockaddr struct { + Len uint8 + Family uint8 + Data [14]int8 +} + +type RawSockaddrAny struct { + Addr RawSockaddr + Pad [92]int8 +} + +type _Socklen uint32 + +type Linger struct { + Onoff int32 + Linger int32 +} + +type Iovec struct { + Base *byte + Len uint64 +} + +type IPMreq struct { + Multiaddr [4]byte /* in_addr */ + Interface [4]byte /* in_addr */ +} + +type IPMreqn struct { + Multiaddr [4]byte /* in_addr */ + Address [4]byte /* in_addr */ + Ifindex int32 +} + +type IPv6Mreq struct { + Multiaddr [16]byte /* in6_addr */ + Interface uint32 +} + +type Msghdr struct { + Name *byte + Namelen uint32 + _ [4]byte + Iov *Iovec + Iovlen int32 + _ [4]byte + Control *byte + Controllen uint32 + Flags int32 +} + +type Cmsghdr struct { + Len uint32 + Level int32 + Type int32 +} + +type Inet6Pktinfo struct { + Addr [16]byte /* in6_addr */ + Ifindex uint32 +} + +type IPv6MTUInfo struct { + Addr RawSockaddrInet6 + Mtu uint32 +} + +type ICMPv6Filter struct { + Filt [8]uint32 +} + +const ( + SizeofSockaddrInet4 = 0x10 + SizeofSockaddrInet6 = 0x1c + SizeofSockaddrAny = 0x6c + SizeofSockaddrUnix = 0x6a + SizeofSockaddrDatalink = 0x36 + SizeofLinger = 0x8 + SizeofIPMreq = 0x8 + SizeofIPMreqn = 0xc + SizeofIPv6Mreq = 0x14 + SizeofMsghdr = 0x30 + SizeofCmsghdr = 0xc + SizeofInet6Pktinfo = 0x14 + SizeofIPv6MTUInfo = 0x20 + SizeofICMPv6Filter = 0x20 +) + +const ( + PTRACE_TRACEME = 0x0 + PTRACE_CONT = 0x7 + PTRACE_KILL = 0x8 +) + +type Kevent_t struct { + Ident uint64 + Filter int16 + Flags uint16 + Fflags uint32 + Data int64 + Udata *byte +} + +type FdSet struct { + Bits [16]uint64 +} + +const ( + sizeofIfMsghdr = 0xa8 + SizeofIfMsghdr = 0xa8 + sizeofIfData = 0x98 + SizeofIfData = 0x98 + SizeofIfaMsghdr = 0x14 + SizeofIfmaMsghdr = 0x10 + SizeofIfAnnounceMsghdr = 0x18 + SizeofRtMsghdr = 0x98 + SizeofRtMetrics = 0x70 +) + +type ifMsghdr struct { + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte + Data ifData +} + +type IfMsghdr struct { + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte + Data IfData +} + +type ifData struct { + Type uint8 + Physical uint8 + Addrlen uint8 + Hdrlen uint8 + Link_state uint8 + Vhid uint8 + Datalen uint16 + Mtu uint32 + Metric uint32 + Baudrate uint64 + Ipackets uint64 + Ierrors uint64 + Opackets uint64 + Oerrors uint64 + Collisions uint64 + Ibytes uint64 + Obytes uint64 + Imcasts uint64 + Omcasts uint64 + Iqdrops uint64 + Oqdrops uint64 + Noproto uint64 + Hwassist uint64 + _ [8]byte + _ [16]byte +} + +type IfData struct { + Type uint8 + Physical uint8 + Addrlen uint8 + Hdrlen uint8 + Link_state uint8 + Spare_char1 uint8 + Spare_char2 uint8 + Datalen uint8 + Mtu uint64 + Metric uint64 + Baudrate uint64 + Ipackets uint64 + Ierrors uint64 + Opackets uint64 + Oerrors uint64 + Collisions uint64 + Ibytes uint64 + Obytes uint64 + Imcasts uint64 + Omcasts uint64 + Iqdrops uint64 + Noproto uint64 + Hwassist uint64 + Epoch int64 + Lastchange Timeval +} + +type IfaMsghdr struct { + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte + Metric int32 +} + +type IfmaMsghdr struct { + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte +} + +type IfAnnounceMsghdr struct { + Msglen uint16 + Version uint8 + Type uint8 + Index uint16 + Name [16]int8 + What uint16 +} + +type RtMsghdr struct { + Msglen uint16 + Version uint8 + Type uint8 + Index uint16 + _ [2]byte + Flags int32 + Addrs int32 + Pid int32 + Seq int32 + Errno int32 + Fmask int32 + Inits uint64 + Rmx RtMetrics +} + +type RtMetrics struct { + Locks uint64 + Mtu uint64 + Hopcount uint64 + Expire uint64 + Recvpipe uint64 + Sendpipe uint64 + Ssthresh uint64 + Rtt uint64 + Rttvar uint64 + Pksent uint64 + Weight uint64 + Filler [3]uint64 +} + +const ( + SizeofBpfVersion = 0x4 + SizeofBpfStat = 0x8 + SizeofBpfZbuf = 0x18 + SizeofBpfProgram = 0x10 + SizeofBpfInsn = 0x8 + SizeofBpfHdr = 0x20 + SizeofBpfZbufHeader = 0x20 +) + +type BpfVersion struct { + Major uint16 + Minor uint16 +} + +type BpfStat struct { + Recv uint32 + Drop uint32 +} + +type BpfZbuf struct { + Bufa *byte + Bufb *byte + Buflen uint64 +} + +type BpfProgram struct { + Len uint32 + _ [4]byte + Insns *BpfInsn +} + +type BpfInsn struct { + Code uint16 + Jt uint8 + Jf uint8 + K uint32 +} + +type BpfHdr struct { + Tstamp Timeval + Caplen uint32 + Datalen uint32 + Hdrlen uint16 + _ [6]byte +} + +type BpfZbufHeader struct { + Kernel_gen uint32 + Kernel_len uint32 + User_gen uint32 + _ [5]uint32 +} + +type Termios struct { + Iflag uint32 + Oflag uint32 + Cflag uint32 + Lflag uint32 + Cc [20]uint8 + Ispeed uint32 + Ospeed uint32 +} + +type Winsize struct { + Row uint16 + Col uint16 + Xpixel uint16 + Ypixel uint16 +} + +const ( + AT_FDCWD = -0x64 + AT_REMOVEDIR = 0x800 + AT_SYMLINK_FOLLOW = 0x400 + AT_SYMLINK_NOFOLLOW = 0x200 +) + +type PollFd struct { + Fd int32 + Events int16 + Revents int16 +} + +const ( + POLLERR = 0x8 + POLLHUP = 0x10 + POLLIN = 0x1 + POLLINIGNEOF = 0x2000 + POLLNVAL = 0x20 + POLLOUT = 0x4 + POLLPRI = 0x2 + POLLRDBAND = 0x80 + POLLRDNORM = 0x40 + POLLWRBAND = 0x100 + POLLWRNORM = 0x4 +) + +type CapRights struct { + Rights [2]uint64 +} + +type Utsname struct { + Sysname [256]byte + Nodename [256]byte + Release [256]byte + Version [256]byte + Machine [256]byte +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_386.go b/vendor/golang.org/x/sys/unix/ztypes_linux_386.go index c6de94269d..d262150cc0 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_386.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_386.go @@ -6,11 +6,11 @@ package unix const ( - sizeofPtr = 0x4 - sizeofShort = 0x2 - sizeofInt = 0x4 - sizeofLong = 0x4 - sizeofLongLong = 0x8 + SizeofPtr = 0x4 + SizeofShort = 0x2 + SizeofInt = 0x4 + SizeofLong = 0x4 + SizeofLongLong = 0x8 PathMax = 0x1000 ) @@ -52,7 +52,7 @@ type Timex struct { Errcnt int32 Stbcnt int32 Tai int32 - Pad_cgo_0 [44]byte + _ [44]byte } type Time_t int32 @@ -96,52 +96,65 @@ type Rlimit struct { type _Gid_t uint32 type Stat_t struct { - Dev uint64 - X__pad1 uint16 - Pad_cgo_0 [2]byte - X__st_ino uint32 - Mode uint32 - Nlink uint32 - Uid uint32 - Gid uint32 - Rdev uint64 - X__pad2 uint16 - Pad_cgo_1 [2]byte - Size int64 - Blksize int32 - Blocks int64 - Atim Timespec - Mtim Timespec - Ctim Timespec - Ino uint64 + Dev uint64 + _ uint16 + _ uint32 + Mode uint32 + Nlink uint32 + Uid uint32 + Gid uint32 + Rdev uint64 + _ uint16 + Size int64 + Blksize int32 + Blocks int64 + Atim Timespec + Mtim Timespec + Ctim Timespec + Ino uint64 } -type Statfs_t struct { - Type int32 - Bsize int32 - Blocks uint64 - Bfree uint64 - Bavail uint64 - Files uint64 - Ffree uint64 - Fsid Fsid - Namelen int32 - Frsize int32 - Flags int32 - Spare [4]int32 +type StatxTimestamp struct { + Sec int64 + Nsec uint32 + _ int32 +} + +type Statx_t struct { + Mask uint32 + Blksize uint32 + Attributes uint64 + Nlink uint32 + Uid uint32 + Gid uint32 + Mode uint16 + _ [1]uint16 + Ino uint64 + Size uint64 + Blocks uint64 + Attributes_mask uint64 + Atime StatxTimestamp + Btime StatxTimestamp + Ctime StatxTimestamp + Mtime StatxTimestamp + Rdev_major uint32 + Rdev_minor uint32 + Dev_major uint32 + Dev_minor uint32 + _ [14]uint64 } type Dirent struct { - Ino uint64 - Off int64 - Reclen uint16 - Type uint8 - Name [256]int8 - Pad_cgo_0 [1]byte + Ino uint64 + Off int64 + Reclen uint16 + Type uint8 + Name [256]int8 + _ [1]byte } type Fsid struct { - X__val [2]int32 + Val [2]int32 } type Flock_t struct { @@ -224,11 +237,26 @@ type RawSockaddrHCI struct { Channel uint16 } +type RawSockaddrL2 struct { + Family uint16 + Psm uint16 + Bdaddr [6]uint8 + Cid uint16 + Bdaddr_type uint8 + _ [1]byte +} + +type RawSockaddrRFCOMM struct { + Family uint16 + Bdaddr [6]uint8 + Channel uint8 + _ [1]byte +} + type RawSockaddrCAN struct { - Family uint16 - Pad_cgo_0 [2]byte - Ifindex int32 - Addr [8]byte + Family uint16 + Ifindex int32 + Addr [8]byte } type RawSockaddrALG struct { @@ -247,6 +275,16 @@ type RawSockaddrVM struct { Zero [4]uint8 } +type RawSockaddrXDP struct { + Family uint16 + Flags uint16 + Ifindex uint32 + Queue_id uint32 + Shared_umem_fd uint32 +} + +type RawSockaddrPPPoX [0x1e]byte + type RawSockaddr struct { Family uint16 Data [14]int8 @@ -341,7 +379,6 @@ type TCPInfo struct { Probes uint8 Backoff uint8 Options uint8 - Pad_cgo_0 [2]byte Rto uint32 Ato uint32 Snd_mss uint32 @@ -376,9 +413,13 @@ const ( SizeofSockaddrLinklayer = 0x14 SizeofSockaddrNetlink = 0xc SizeofSockaddrHCI = 0x6 + SizeofSockaddrL2 = 0xe + SizeofSockaddrRFCOMM = 0xa SizeofSockaddrCAN = 0x10 SizeofSockaddrALG = 0x58 SizeofSockaddrVM = 0x10 + SizeofSockaddrXDP = 0x10 + SizeofSockaddrPPPoX = 0x1e SizeofLinger = 0x8 SizeofIovec = 0x8 SizeofIPMreq = 0x8 @@ -396,97 +437,138 @@ const ( ) const ( - IFA_UNSPEC = 0x0 - IFA_ADDRESS = 0x1 - IFA_LOCAL = 0x2 - IFA_LABEL = 0x3 - IFA_BROADCAST = 0x4 - IFA_ANYCAST = 0x5 - IFA_CACHEINFO = 0x6 - IFA_MULTICAST = 0x7 - IFLA_UNSPEC = 0x0 - IFLA_ADDRESS = 0x1 - IFLA_BROADCAST = 0x2 - IFLA_IFNAME = 0x3 - IFLA_MTU = 0x4 - IFLA_LINK = 0x5 - IFLA_QDISC = 0x6 - IFLA_STATS = 0x7 - IFLA_COST = 0x8 - IFLA_PRIORITY = 0x9 - IFLA_MASTER = 0xa - IFLA_WIRELESS = 0xb - IFLA_PROTINFO = 0xc - IFLA_TXQLEN = 0xd - IFLA_MAP = 0xe - IFLA_WEIGHT = 0xf - IFLA_OPERSTATE = 0x10 - IFLA_LINKMODE = 0x11 - IFLA_LINKINFO = 0x12 - IFLA_NET_NS_PID = 0x13 - IFLA_IFALIAS = 0x14 - IFLA_MAX = 0x2c - RT_SCOPE_UNIVERSE = 0x0 - RT_SCOPE_SITE = 0xc8 - RT_SCOPE_LINK = 0xfd - RT_SCOPE_HOST = 0xfe - RT_SCOPE_NOWHERE = 0xff - RT_TABLE_UNSPEC = 0x0 - RT_TABLE_COMPAT = 0xfc - RT_TABLE_DEFAULT = 0xfd - RT_TABLE_MAIN = 0xfe - RT_TABLE_LOCAL = 0xff - RT_TABLE_MAX = 0xffffffff - RTA_UNSPEC = 0x0 - RTA_DST = 0x1 - RTA_SRC = 0x2 - RTA_IIF = 0x3 - RTA_OIF = 0x4 - RTA_GATEWAY = 0x5 - RTA_PRIORITY = 0x6 - RTA_PREFSRC = 0x7 - RTA_METRICS = 0x8 - RTA_MULTIPATH = 0x9 - RTA_FLOW = 0xb - RTA_CACHEINFO = 0xc - RTA_TABLE = 0xf - RTN_UNSPEC = 0x0 - RTN_UNICAST = 0x1 - RTN_LOCAL = 0x2 - RTN_BROADCAST = 0x3 - RTN_ANYCAST = 0x4 - RTN_MULTICAST = 0x5 - RTN_BLACKHOLE = 0x6 - RTN_UNREACHABLE = 0x7 - RTN_PROHIBIT = 0x8 - RTN_THROW = 0x9 - RTN_NAT = 0xa - RTN_XRESOLVE = 0xb - RTNLGRP_NONE = 0x0 - RTNLGRP_LINK = 0x1 - RTNLGRP_NOTIFY = 0x2 - RTNLGRP_NEIGH = 0x3 - RTNLGRP_TC = 0x4 - RTNLGRP_IPV4_IFADDR = 0x5 - RTNLGRP_IPV4_MROUTE = 0x6 - RTNLGRP_IPV4_ROUTE = 0x7 - RTNLGRP_IPV4_RULE = 0x8 - RTNLGRP_IPV6_IFADDR = 0x9 - RTNLGRP_IPV6_MROUTE = 0xa - RTNLGRP_IPV6_ROUTE = 0xb - RTNLGRP_IPV6_IFINFO = 0xc - RTNLGRP_IPV6_PREFIX = 0x12 - RTNLGRP_IPV6_RULE = 0x13 - RTNLGRP_ND_USEROPT = 0x14 - SizeofNlMsghdr = 0x10 - SizeofNlMsgerr = 0x14 - SizeofRtGenmsg = 0x1 - SizeofNlAttr = 0x4 - SizeofRtAttr = 0x4 - SizeofIfInfomsg = 0x10 - SizeofIfAddrmsg = 0x8 - SizeofRtMsg = 0xc - SizeofRtNexthop = 0x8 + IFA_UNSPEC = 0x0 + IFA_ADDRESS = 0x1 + IFA_LOCAL = 0x2 + IFA_LABEL = 0x3 + IFA_BROADCAST = 0x4 + IFA_ANYCAST = 0x5 + IFA_CACHEINFO = 0x6 + IFA_MULTICAST = 0x7 + IFLA_UNSPEC = 0x0 + IFLA_ADDRESS = 0x1 + IFLA_BROADCAST = 0x2 + IFLA_IFNAME = 0x3 + IFLA_INFO_KIND = 0x1 + IFLA_MTU = 0x4 + IFLA_LINK = 0x5 + IFLA_QDISC = 0x6 + IFLA_STATS = 0x7 + IFLA_COST = 0x8 + IFLA_PRIORITY = 0x9 + IFLA_MASTER = 0xa + IFLA_WIRELESS = 0xb + IFLA_PROTINFO = 0xc + IFLA_TXQLEN = 0xd + IFLA_MAP = 0xe + IFLA_WEIGHT = 0xf + IFLA_OPERSTATE = 0x10 + IFLA_LINKMODE = 0x11 + IFLA_LINKINFO = 0x12 + IFLA_NET_NS_PID = 0x13 + IFLA_IFALIAS = 0x14 + IFLA_NUM_VF = 0x15 + IFLA_VFINFO_LIST = 0x16 + IFLA_STATS64 = 0x17 + IFLA_VF_PORTS = 0x18 + IFLA_PORT_SELF = 0x19 + IFLA_AF_SPEC = 0x1a + IFLA_GROUP = 0x1b + IFLA_NET_NS_FD = 0x1c + IFLA_EXT_MASK = 0x1d + IFLA_PROMISCUITY = 0x1e + IFLA_NUM_TX_QUEUES = 0x1f + IFLA_NUM_RX_QUEUES = 0x20 + IFLA_CARRIER = 0x21 + IFLA_PHYS_PORT_ID = 0x22 + IFLA_CARRIER_CHANGES = 0x23 + IFLA_PHYS_SWITCH_ID = 0x24 + IFLA_LINK_NETNSID = 0x25 + IFLA_PHYS_PORT_NAME = 0x26 + IFLA_PROTO_DOWN = 0x27 + IFLA_GSO_MAX_SEGS = 0x28 + IFLA_GSO_MAX_SIZE = 0x29 + IFLA_PAD = 0x2a + IFLA_XDP = 0x2b + IFLA_EVENT = 0x2c + IFLA_NEW_NETNSID = 0x2d + IFLA_IF_NETNSID = 0x2e + IFLA_MAX = 0x33 + RT_SCOPE_UNIVERSE = 0x0 + RT_SCOPE_SITE = 0xc8 + RT_SCOPE_LINK = 0xfd + RT_SCOPE_HOST = 0xfe + RT_SCOPE_NOWHERE = 0xff + RT_TABLE_UNSPEC = 0x0 + RT_TABLE_COMPAT = 0xfc + RT_TABLE_DEFAULT = 0xfd + RT_TABLE_MAIN = 0xfe + RT_TABLE_LOCAL = 0xff + RT_TABLE_MAX = 0xffffffff + RTA_UNSPEC = 0x0 + RTA_DST = 0x1 + RTA_SRC = 0x2 + RTA_IIF = 0x3 + RTA_OIF = 0x4 + RTA_GATEWAY = 0x5 + RTA_PRIORITY = 0x6 + RTA_PREFSRC = 0x7 + RTA_METRICS = 0x8 + RTA_MULTIPATH = 0x9 + RTA_FLOW = 0xb + RTA_CACHEINFO = 0xc + RTA_TABLE = 0xf + RTA_MARK = 0x10 + RTA_MFC_STATS = 0x11 + RTA_VIA = 0x12 + RTA_NEWDST = 0x13 + RTA_PREF = 0x14 + RTA_ENCAP_TYPE = 0x15 + RTA_ENCAP = 0x16 + RTA_EXPIRES = 0x17 + RTA_PAD = 0x18 + RTA_UID = 0x19 + RTA_TTL_PROPAGATE = 0x1a + RTA_IP_PROTO = 0x1b + RTA_SPORT = 0x1c + RTA_DPORT = 0x1d + RTN_UNSPEC = 0x0 + RTN_UNICAST = 0x1 + RTN_LOCAL = 0x2 + RTN_BROADCAST = 0x3 + RTN_ANYCAST = 0x4 + RTN_MULTICAST = 0x5 + RTN_BLACKHOLE = 0x6 + RTN_UNREACHABLE = 0x7 + RTN_PROHIBIT = 0x8 + RTN_THROW = 0x9 + RTN_NAT = 0xa + RTN_XRESOLVE = 0xb + RTNLGRP_NONE = 0x0 + RTNLGRP_LINK = 0x1 + RTNLGRP_NOTIFY = 0x2 + RTNLGRP_NEIGH = 0x3 + RTNLGRP_TC = 0x4 + RTNLGRP_IPV4_IFADDR = 0x5 + RTNLGRP_IPV4_MROUTE = 0x6 + RTNLGRP_IPV4_ROUTE = 0x7 + RTNLGRP_IPV4_RULE = 0x8 + RTNLGRP_IPV6_IFADDR = 0x9 + RTNLGRP_IPV6_MROUTE = 0xa + RTNLGRP_IPV6_ROUTE = 0xb + RTNLGRP_IPV6_IFINFO = 0xc + RTNLGRP_IPV6_PREFIX = 0x12 + RTNLGRP_IPV6_RULE = 0x13 + RTNLGRP_ND_USEROPT = 0x14 + SizeofNlMsghdr = 0x10 + SizeofNlMsgerr = 0x14 + SizeofRtGenmsg = 0x1 + SizeofNlAttr = 0x4 + SizeofRtAttr = 0x4 + SizeofIfInfomsg = 0x10 + SizeofIfAddrmsg = 0x8 + SizeofRtMsg = 0xc + SizeofRtNexthop = 0x8 ) type NlMsghdr struct { @@ -517,12 +599,12 @@ type RtAttr struct { } type IfInfomsg struct { - Family uint8 - X__ifi_pad uint8 - Type uint16 - Index int32 - Flags uint32 - Change uint32 + Family uint8 + _ uint8 + Type uint16 + Index int32 + Flags uint32 + Change uint32 } type IfAddrmsg struct { @@ -565,9 +647,8 @@ type SockFilter struct { } type SockFprog struct { - Len uint16 - Pad_cgo_0 [2]byte - Filter *SockFilter + Len uint16 + Filter *SockFilter } type InotifyEvent struct { @@ -617,7 +698,7 @@ type Sysinfo_t struct { Totalhigh uint32 Freehigh uint32 Unit uint32 - X_f [8]int8 + _ [8]int8 } type Utsname struct { @@ -643,10 +724,19 @@ type EpollEvent struct { } const ( - AT_FDCWD = -0x64 - AT_REMOVEDIR = 0x200 + AT_EMPTY_PATH = 0x1000 + AT_FDCWD = -0x64 + AT_NO_AUTOMOUNT = 0x800 + AT_REMOVEDIR = 0x200 + + AT_STATX_SYNC_AS_STAT = 0x0 + AT_STATX_FORCE_SYNC = 0x2000 + AT_STATX_DONT_SYNC = 0x4000 + AT_SYMLINK_FOLLOW = 0x400 AT_SYMLINK_NOFOLLOW = 0x100 + + AT_EACCESS = 0x200 ) type PollFd struct { @@ -666,10 +756,33 @@ const ( ) type Sigset_t struct { - X__val [32]uint32 + Val [32]uint32 } -const RNDGETENTCNT = 0x80045200 +type SignalfdSiginfo struct { + Signo uint32 + Errno int32 + Code int32 + Pid uint32 + Uid uint32 + Fd int32 + Tid uint32 + Band uint32 + Overrun uint32 + Trapno uint32 + Status int32 + Int int32 + Ptr uint64 + Utime uint64 + Stime uint64 + Addr uint64 + Addr_lsb uint16 + _ uint16 + Syscall int32 + Call_addr uint64 + Arch uint32 + _ [28]uint8 +} const PERF_IOC_FLAG_GROUP = 0x1 @@ -693,11 +806,10 @@ type Winsize struct { type Taskstats struct { Version uint16 - Pad_cgo_0 [2]byte Ac_exitcode uint32 Ac_flag uint8 Ac_nice uint8 - Pad_cgo_1 [6]byte + _ [4]byte Cpu_count uint64 Cpu_delay_total uint64 Blkio_count uint64 @@ -709,13 +821,13 @@ type Taskstats struct { Ac_comm [32]int8 Ac_sched uint8 Ac_pad [3]uint8 - Pad_cgo_2 [4]byte + _ [4]byte Ac_uid uint32 Ac_gid uint32 Ac_pid uint32 Ac_ppid uint32 Ac_btime uint32 - Pad_cgo_3 [4]byte + _ [4]byte Ac_etime uint64 Ac_utime uint64 Ac_stime uint64 @@ -739,6 +851,8 @@ type Taskstats struct { Cpu_scaled_run_real_total uint64 Freepages_count uint64 Freepages_delay_total uint64 + Thrashing_count uint64 + Thrashing_delay_total uint64 } const ( @@ -759,6 +873,24 @@ const ( TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK = 0x4 ) +type CGroupStats struct { + Sleeping uint64 + Running uint64 + Stopped uint64 + Uninterruptible uint64 + Io_wait uint64 +} + +const ( + CGROUPSTATS_CMD_UNSPEC = 0x3 + CGROUPSTATS_CMD_GET = 0x4 + CGROUPSTATS_CMD_NEW = 0x5 + CGROUPSTATS_TYPE_UNSPEC = 0x0 + CGROUPSTATS_TYPE_CGROUP_STATS = 0x1 + CGROUPSTATS_CMD_ATTR_UNSPEC = 0x0 + CGROUPSTATS_CMD_ATTR_FD = 0x1 +) + type Genlmsghdr struct { Cmd uint8 Version uint8 @@ -791,3 +923,1105 @@ const ( CTRL_ATTR_MCAST_GRP_NAME = 0x1 CTRL_ATTR_MCAST_GRP_ID = 0x2 ) + +type cpuMask uint32 + +const ( + _CPU_SETSIZE = 0x400 + _NCPUBITS = 0x20 +) + +const ( + BDADDR_BREDR = 0x0 + BDADDR_LE_PUBLIC = 0x1 + BDADDR_LE_RANDOM = 0x2 +) + +type PerfEventAttr struct { + Type uint32 + Size uint32 + Config uint64 + Sample uint64 + Sample_type uint64 + Read_format uint64 + Bits uint64 + Wakeup uint32 + Bp_type uint32 + Ext1 uint64 + Ext2 uint64 + Branch_sample_type uint64 + Sample_regs_user uint64 + Sample_stack_user uint32 + Clockid int32 + Sample_regs_intr uint64 + Aux_watermark uint32 + _ uint32 +} + +type PerfEventMmapPage struct { + Version uint32 + Compat_version uint32 + Lock uint32 + Index uint32 + Offset int64 + Time_enabled uint64 + Time_running uint64 + Capabilities uint64 + Pmc_width uint16 + Time_shift uint16 + Time_mult uint32 + Time_offset uint64 + Time_zero uint64 + Size uint32 + _ [948]uint8 + Data_head uint64 + Data_tail uint64 + Data_offset uint64 + Data_size uint64 + Aux_head uint64 + Aux_tail uint64 + Aux_offset uint64 + Aux_size uint64 +} + +const ( + PerfBitDisabled uint64 = CBitFieldMaskBit0 + PerfBitInherit = CBitFieldMaskBit1 + PerfBitPinned = CBitFieldMaskBit2 + PerfBitExclusive = CBitFieldMaskBit3 + PerfBitExcludeUser = CBitFieldMaskBit4 + PerfBitExcludeKernel = CBitFieldMaskBit5 + PerfBitExcludeHv = CBitFieldMaskBit6 + PerfBitExcludeIdle = CBitFieldMaskBit7 + PerfBitMmap = CBitFieldMaskBit8 + PerfBitComm = CBitFieldMaskBit9 + PerfBitFreq = CBitFieldMaskBit10 + PerfBitInheritStat = CBitFieldMaskBit11 + PerfBitEnableOnExec = CBitFieldMaskBit12 + PerfBitTask = CBitFieldMaskBit13 + PerfBitWatermark = CBitFieldMaskBit14 + PerfBitPreciseIPBit1 = CBitFieldMaskBit15 + PerfBitPreciseIPBit2 = CBitFieldMaskBit16 + PerfBitMmapData = CBitFieldMaskBit17 + PerfBitSampleIDAll = CBitFieldMaskBit18 + PerfBitExcludeHost = CBitFieldMaskBit19 + PerfBitExcludeGuest = CBitFieldMaskBit20 + PerfBitExcludeCallchainKernel = CBitFieldMaskBit21 + PerfBitExcludeCallchainUser = CBitFieldMaskBit22 + PerfBitMmap2 = CBitFieldMaskBit23 + PerfBitCommExec = CBitFieldMaskBit24 + PerfBitUseClockID = CBitFieldMaskBit25 + PerfBitContextSwitch = CBitFieldMaskBit26 +) + +const ( + PERF_TYPE_HARDWARE = 0x0 + PERF_TYPE_SOFTWARE = 0x1 + PERF_TYPE_TRACEPOINT = 0x2 + PERF_TYPE_HW_CACHE = 0x3 + PERF_TYPE_RAW = 0x4 + PERF_TYPE_BREAKPOINT = 0x5 + + PERF_COUNT_HW_CPU_CYCLES = 0x0 + PERF_COUNT_HW_INSTRUCTIONS = 0x1 + PERF_COUNT_HW_CACHE_REFERENCES = 0x2 + PERF_COUNT_HW_CACHE_MISSES = 0x3 + PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 0x4 + PERF_COUNT_HW_BRANCH_MISSES = 0x5 + PERF_COUNT_HW_BUS_CYCLES = 0x6 + PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 0x7 + PERF_COUNT_HW_STALLED_CYCLES_BACKEND = 0x8 + PERF_COUNT_HW_REF_CPU_CYCLES = 0x9 + + PERF_COUNT_HW_CACHE_L1D = 0x0 + PERF_COUNT_HW_CACHE_L1I = 0x1 + PERF_COUNT_HW_CACHE_LL = 0x2 + PERF_COUNT_HW_CACHE_DTLB = 0x3 + PERF_COUNT_HW_CACHE_ITLB = 0x4 + PERF_COUNT_HW_CACHE_BPU = 0x5 + PERF_COUNT_HW_CACHE_NODE = 0x6 + + PERF_COUNT_HW_CACHE_OP_READ = 0x0 + PERF_COUNT_HW_CACHE_OP_WRITE = 0x1 + PERF_COUNT_HW_CACHE_OP_PREFETCH = 0x2 + + PERF_COUNT_HW_CACHE_RESULT_ACCESS = 0x0 + PERF_COUNT_HW_CACHE_RESULT_MISS = 0x1 + + PERF_COUNT_SW_CPU_CLOCK = 0x0 + PERF_COUNT_SW_TASK_CLOCK = 0x1 + PERF_COUNT_SW_PAGE_FAULTS = 0x2 + PERF_COUNT_SW_CONTEXT_SWITCHES = 0x3 + PERF_COUNT_SW_CPU_MIGRATIONS = 0x4 + PERF_COUNT_SW_PAGE_FAULTS_MIN = 0x5 + PERF_COUNT_SW_PAGE_FAULTS_MAJ = 0x6 + PERF_COUNT_SW_ALIGNMENT_FAULTS = 0x7 + PERF_COUNT_SW_EMULATION_FAULTS = 0x8 + PERF_COUNT_SW_DUMMY = 0x9 + + PERF_SAMPLE_IP = 0x1 + PERF_SAMPLE_TID = 0x2 + PERF_SAMPLE_TIME = 0x4 + PERF_SAMPLE_ADDR = 0x8 + PERF_SAMPLE_READ = 0x10 + PERF_SAMPLE_CALLCHAIN = 0x20 + PERF_SAMPLE_ID = 0x40 + PERF_SAMPLE_CPU = 0x80 + PERF_SAMPLE_PERIOD = 0x100 + PERF_SAMPLE_STREAM_ID = 0x200 + PERF_SAMPLE_RAW = 0x400 + PERF_SAMPLE_BRANCH_STACK = 0x800 + + PERF_SAMPLE_BRANCH_USER = 0x1 + PERF_SAMPLE_BRANCH_KERNEL = 0x2 + PERF_SAMPLE_BRANCH_HV = 0x4 + PERF_SAMPLE_BRANCH_ANY = 0x8 + PERF_SAMPLE_BRANCH_ANY_CALL = 0x10 + PERF_SAMPLE_BRANCH_ANY_RETURN = 0x20 + PERF_SAMPLE_BRANCH_IND_CALL = 0x40 + + PERF_FORMAT_TOTAL_TIME_ENABLED = 0x1 + PERF_FORMAT_TOTAL_TIME_RUNNING = 0x2 + PERF_FORMAT_ID = 0x4 + PERF_FORMAT_GROUP = 0x8 + + PERF_RECORD_MMAP = 0x1 + PERF_RECORD_LOST = 0x2 + PERF_RECORD_COMM = 0x3 + PERF_RECORD_EXIT = 0x4 + PERF_RECORD_THROTTLE = 0x5 + PERF_RECORD_UNTHROTTLE = 0x6 + PERF_RECORD_FORK = 0x7 + PERF_RECORD_READ = 0x8 + PERF_RECORD_SAMPLE = 0x9 + + PERF_CONTEXT_HV = -0x20 + PERF_CONTEXT_KERNEL = -0x80 + PERF_CONTEXT_USER = -0x200 + + PERF_CONTEXT_GUEST = -0x800 + PERF_CONTEXT_GUEST_KERNEL = -0x880 + PERF_CONTEXT_GUEST_USER = -0xa00 + + PERF_FLAG_FD_NO_GROUP = 0x1 + PERF_FLAG_FD_OUTPUT = 0x2 + PERF_FLAG_PID_CGROUP = 0x4 +) + +const ( + CBitFieldMaskBit0 = 0x1 + CBitFieldMaskBit1 = 0x2 + CBitFieldMaskBit2 = 0x4 + CBitFieldMaskBit3 = 0x8 + CBitFieldMaskBit4 = 0x10 + CBitFieldMaskBit5 = 0x20 + CBitFieldMaskBit6 = 0x40 + CBitFieldMaskBit7 = 0x80 + CBitFieldMaskBit8 = 0x100 + CBitFieldMaskBit9 = 0x200 + CBitFieldMaskBit10 = 0x400 + CBitFieldMaskBit11 = 0x800 + CBitFieldMaskBit12 = 0x1000 + CBitFieldMaskBit13 = 0x2000 + CBitFieldMaskBit14 = 0x4000 + CBitFieldMaskBit15 = 0x8000 + CBitFieldMaskBit16 = 0x10000 + CBitFieldMaskBit17 = 0x20000 + CBitFieldMaskBit18 = 0x40000 + CBitFieldMaskBit19 = 0x80000 + CBitFieldMaskBit20 = 0x100000 + CBitFieldMaskBit21 = 0x200000 + CBitFieldMaskBit22 = 0x400000 + CBitFieldMaskBit23 = 0x800000 + CBitFieldMaskBit24 = 0x1000000 + CBitFieldMaskBit25 = 0x2000000 + CBitFieldMaskBit26 = 0x4000000 + CBitFieldMaskBit27 = 0x8000000 + CBitFieldMaskBit28 = 0x10000000 + CBitFieldMaskBit29 = 0x20000000 + CBitFieldMaskBit30 = 0x40000000 + CBitFieldMaskBit31 = 0x80000000 + CBitFieldMaskBit32 = 0x100000000 + CBitFieldMaskBit33 = 0x200000000 + CBitFieldMaskBit34 = 0x400000000 + CBitFieldMaskBit35 = 0x800000000 + CBitFieldMaskBit36 = 0x1000000000 + CBitFieldMaskBit37 = 0x2000000000 + CBitFieldMaskBit38 = 0x4000000000 + CBitFieldMaskBit39 = 0x8000000000 + CBitFieldMaskBit40 = 0x10000000000 + CBitFieldMaskBit41 = 0x20000000000 + CBitFieldMaskBit42 = 0x40000000000 + CBitFieldMaskBit43 = 0x80000000000 + CBitFieldMaskBit44 = 0x100000000000 + CBitFieldMaskBit45 = 0x200000000000 + CBitFieldMaskBit46 = 0x400000000000 + CBitFieldMaskBit47 = 0x800000000000 + CBitFieldMaskBit48 = 0x1000000000000 + CBitFieldMaskBit49 = 0x2000000000000 + CBitFieldMaskBit50 = 0x4000000000000 + CBitFieldMaskBit51 = 0x8000000000000 + CBitFieldMaskBit52 = 0x10000000000000 + CBitFieldMaskBit53 = 0x20000000000000 + CBitFieldMaskBit54 = 0x40000000000000 + CBitFieldMaskBit55 = 0x80000000000000 + CBitFieldMaskBit56 = 0x100000000000000 + CBitFieldMaskBit57 = 0x200000000000000 + CBitFieldMaskBit58 = 0x400000000000000 + CBitFieldMaskBit59 = 0x800000000000000 + CBitFieldMaskBit60 = 0x1000000000000000 + CBitFieldMaskBit61 = 0x2000000000000000 + CBitFieldMaskBit62 = 0x4000000000000000 + CBitFieldMaskBit63 = 0x8000000000000000 +) + +type SockaddrStorage struct { + Family uint16 + _ [122]int8 + _ uint32 +} + +type TCPMD5Sig struct { + Addr SockaddrStorage + Flags uint8 + Prefixlen uint8 + Keylen uint16 + _ uint32 + Key [80]uint8 +} + +type HDDriveCmdHdr struct { + Command uint8 + Number uint8 + Feature uint8 + Count uint8 +} + +type HDGeometry struct { + Heads uint8 + Sectors uint8 + Cylinders uint16 + Start uint32 +} + +type HDDriveID struct { + Config uint16 + Cyls uint16 + Reserved2 uint16 + Heads uint16 + Track_bytes uint16 + Sector_bytes uint16 + Sectors uint16 + Vendor0 uint16 + Vendor1 uint16 + Vendor2 uint16 + Serial_no [20]uint8 + Buf_type uint16 + Buf_size uint16 + Ecc_bytes uint16 + Fw_rev [8]uint8 + Model [40]uint8 + Max_multsect uint8 + Vendor3 uint8 + Dword_io uint16 + Vendor4 uint8 + Capability uint8 + Reserved50 uint16 + Vendor5 uint8 + TPIO uint8 + Vendor6 uint8 + TDMA uint8 + Field_valid uint16 + Cur_cyls uint16 + Cur_heads uint16 + Cur_sectors uint16 + Cur_capacity0 uint16 + Cur_capacity1 uint16 + Multsect uint8 + Multsect_valid uint8 + Lba_capacity uint32 + Dma_1word uint16 + Dma_mword uint16 + Eide_pio_modes uint16 + Eide_dma_min uint16 + Eide_dma_time uint16 + Eide_pio uint16 + Eide_pio_iordy uint16 + Words69_70 [2]uint16 + Words71_74 [4]uint16 + Queue_depth uint16 + Words76_79 [4]uint16 + Major_rev_num uint16 + Minor_rev_num uint16 + Command_set_1 uint16 + Command_set_2 uint16 + Cfsse uint16 + Cfs_enable_1 uint16 + Cfs_enable_2 uint16 + Csf_default uint16 + Dma_ultra uint16 + Trseuc uint16 + TrsEuc uint16 + CurAPMvalues uint16 + Mprc uint16 + Hw_config uint16 + Acoustic uint16 + Msrqs uint16 + Sxfert uint16 + Sal uint16 + Spg uint32 + Lba_capacity_2 uint64 + Words104_125 [22]uint16 + Last_lun uint16 + Word127 uint16 + Dlf uint16 + Csfo uint16 + Words130_155 [26]uint16 + Word156 uint16 + Words157_159 [3]uint16 + Cfa_power uint16 + Words161_175 [15]uint16 + Words176_205 [30]uint16 + Words206_254 [49]uint16 + Integrity_word uint16 +} + +type Statfs_t struct { + Type int32 + Bsize int32 + Blocks uint64 + Bfree uint64 + Bavail uint64 + Files uint64 + Ffree uint64 + Fsid Fsid + Namelen int32 + Frsize int32 + Flags int32 + Spare [4]int32 +} + +const ( + ST_MANDLOCK = 0x40 + ST_NOATIME = 0x400 + ST_NODEV = 0x4 + ST_NODIRATIME = 0x800 + ST_NOEXEC = 0x8 + ST_NOSUID = 0x2 + ST_RDONLY = 0x1 + ST_RELATIME = 0x1000 + ST_SYNCHRONOUS = 0x10 +) + +type TpacketHdr struct { + Status uint32 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Sec uint32 + Usec uint32 +} + +type Tpacket2Hdr struct { + Status uint32 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Sec uint32 + Nsec uint32 + Vlan_tci uint16 + Vlan_tpid uint16 + _ [4]uint8 +} + +type Tpacket3Hdr struct { + Next_offset uint32 + Sec uint32 + Nsec uint32 + Snaplen uint32 + Len uint32 + Status uint32 + Mac uint16 + Net uint16 + Hv1 TpacketHdrVariant1 + _ [8]uint8 +} + +type TpacketHdrVariant1 struct { + Rxhash uint32 + Vlan_tci uint32 + Vlan_tpid uint16 + _ uint16 +} + +type TpacketBlockDesc struct { + Version uint32 + To_priv uint32 + Hdr [40]byte +} + +type TpacketReq struct { + Block_size uint32 + Block_nr uint32 + Frame_size uint32 + Frame_nr uint32 +} + +type TpacketReq3 struct { + Block_size uint32 + Block_nr uint32 + Frame_size uint32 + Frame_nr uint32 + Retire_blk_tov uint32 + Sizeof_priv uint32 + Feature_req_word uint32 +} + +type TpacketStats struct { + Packets uint32 + Drops uint32 +} + +type TpacketStatsV3 struct { + Packets uint32 + Drops uint32 + Freeze_q_cnt uint32 +} + +type TpacketAuxdata struct { + Status uint32 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Vlan_tci uint16 + Vlan_tpid uint16 +} + +const ( + TPACKET_V1 = 0x0 + TPACKET_V2 = 0x1 + TPACKET_V3 = 0x2 +) + +const ( + SizeofTpacketHdr = 0x18 + SizeofTpacket2Hdr = 0x20 + SizeofTpacket3Hdr = 0x30 +) + +const ( + NF_INET_PRE_ROUTING = 0x0 + NF_INET_LOCAL_IN = 0x1 + NF_INET_FORWARD = 0x2 + NF_INET_LOCAL_OUT = 0x3 + NF_INET_POST_ROUTING = 0x4 + NF_INET_NUMHOOKS = 0x5 +) + +const ( + NF_NETDEV_INGRESS = 0x0 + NF_NETDEV_NUMHOOKS = 0x1 +) + +const ( + NFPROTO_UNSPEC = 0x0 + NFPROTO_INET = 0x1 + NFPROTO_IPV4 = 0x2 + NFPROTO_ARP = 0x3 + NFPROTO_NETDEV = 0x5 + NFPROTO_BRIDGE = 0x7 + NFPROTO_IPV6 = 0xa + NFPROTO_DECNET = 0xc + NFPROTO_NUMPROTO = 0xd +) + +type Nfgenmsg struct { + Nfgen_family uint8 + Version uint8 + Res_id uint16 +} + +const ( + NFNL_BATCH_UNSPEC = 0x0 + NFNL_BATCH_GENID = 0x1 +) + +const ( + NFT_REG_VERDICT = 0x0 + NFT_REG_1 = 0x1 + NFT_REG_2 = 0x2 + NFT_REG_3 = 0x3 + NFT_REG_4 = 0x4 + NFT_REG32_00 = 0x8 + NFT_REG32_01 = 0x9 + NFT_REG32_02 = 0xa + NFT_REG32_03 = 0xb + NFT_REG32_04 = 0xc + NFT_REG32_05 = 0xd + NFT_REG32_06 = 0xe + NFT_REG32_07 = 0xf + NFT_REG32_08 = 0x10 + NFT_REG32_09 = 0x11 + NFT_REG32_10 = 0x12 + NFT_REG32_11 = 0x13 + NFT_REG32_12 = 0x14 + NFT_REG32_13 = 0x15 + NFT_REG32_14 = 0x16 + NFT_REG32_15 = 0x17 + NFT_CONTINUE = -0x1 + NFT_BREAK = -0x2 + NFT_JUMP = -0x3 + NFT_GOTO = -0x4 + NFT_RETURN = -0x5 + NFT_MSG_NEWTABLE = 0x0 + NFT_MSG_GETTABLE = 0x1 + NFT_MSG_DELTABLE = 0x2 + NFT_MSG_NEWCHAIN = 0x3 + NFT_MSG_GETCHAIN = 0x4 + NFT_MSG_DELCHAIN = 0x5 + NFT_MSG_NEWRULE = 0x6 + NFT_MSG_GETRULE = 0x7 + NFT_MSG_DELRULE = 0x8 + NFT_MSG_NEWSET = 0x9 + NFT_MSG_GETSET = 0xa + NFT_MSG_DELSET = 0xb + NFT_MSG_NEWSETELEM = 0xc + NFT_MSG_GETSETELEM = 0xd + NFT_MSG_DELSETELEM = 0xe + NFT_MSG_NEWGEN = 0xf + NFT_MSG_GETGEN = 0x10 + NFT_MSG_TRACE = 0x11 + NFT_MSG_NEWOBJ = 0x12 + NFT_MSG_GETOBJ = 0x13 + NFT_MSG_DELOBJ = 0x14 + NFT_MSG_GETOBJ_RESET = 0x15 + NFT_MSG_MAX = 0x19 + NFTA_LIST_UNPEC = 0x0 + NFTA_LIST_ELEM = 0x1 + NFTA_HOOK_UNSPEC = 0x0 + NFTA_HOOK_HOOKNUM = 0x1 + NFTA_HOOK_PRIORITY = 0x2 + NFTA_HOOK_DEV = 0x3 + NFT_TABLE_F_DORMANT = 0x1 + NFTA_TABLE_UNSPEC = 0x0 + NFTA_TABLE_NAME = 0x1 + NFTA_TABLE_FLAGS = 0x2 + NFTA_TABLE_USE = 0x3 + NFTA_CHAIN_UNSPEC = 0x0 + NFTA_CHAIN_TABLE = 0x1 + NFTA_CHAIN_HANDLE = 0x2 + NFTA_CHAIN_NAME = 0x3 + NFTA_CHAIN_HOOK = 0x4 + NFTA_CHAIN_POLICY = 0x5 + NFTA_CHAIN_USE = 0x6 + NFTA_CHAIN_TYPE = 0x7 + NFTA_CHAIN_COUNTERS = 0x8 + NFTA_CHAIN_PAD = 0x9 + NFTA_RULE_UNSPEC = 0x0 + NFTA_RULE_TABLE = 0x1 + NFTA_RULE_CHAIN = 0x2 + NFTA_RULE_HANDLE = 0x3 + NFTA_RULE_EXPRESSIONS = 0x4 + NFTA_RULE_COMPAT = 0x5 + NFTA_RULE_POSITION = 0x6 + NFTA_RULE_USERDATA = 0x7 + NFTA_RULE_PAD = 0x8 + NFTA_RULE_ID = 0x9 + NFT_RULE_COMPAT_F_INV = 0x2 + NFT_RULE_COMPAT_F_MASK = 0x2 + NFTA_RULE_COMPAT_UNSPEC = 0x0 + NFTA_RULE_COMPAT_PROTO = 0x1 + NFTA_RULE_COMPAT_FLAGS = 0x2 + NFT_SET_ANONYMOUS = 0x1 + NFT_SET_CONSTANT = 0x2 + NFT_SET_INTERVAL = 0x4 + NFT_SET_MAP = 0x8 + NFT_SET_TIMEOUT = 0x10 + NFT_SET_EVAL = 0x20 + NFT_SET_OBJECT = 0x40 + NFT_SET_POL_PERFORMANCE = 0x0 + NFT_SET_POL_MEMORY = 0x1 + NFTA_SET_DESC_UNSPEC = 0x0 + NFTA_SET_DESC_SIZE = 0x1 + NFTA_SET_UNSPEC = 0x0 + NFTA_SET_TABLE = 0x1 + NFTA_SET_NAME = 0x2 + NFTA_SET_FLAGS = 0x3 + NFTA_SET_KEY_TYPE = 0x4 + NFTA_SET_KEY_LEN = 0x5 + NFTA_SET_DATA_TYPE = 0x6 + NFTA_SET_DATA_LEN = 0x7 + NFTA_SET_POLICY = 0x8 + NFTA_SET_DESC = 0x9 + NFTA_SET_ID = 0xa + NFTA_SET_TIMEOUT = 0xb + NFTA_SET_GC_INTERVAL = 0xc + NFTA_SET_USERDATA = 0xd + NFTA_SET_PAD = 0xe + NFTA_SET_OBJ_TYPE = 0xf + NFT_SET_ELEM_INTERVAL_END = 0x1 + NFTA_SET_ELEM_UNSPEC = 0x0 + NFTA_SET_ELEM_KEY = 0x1 + NFTA_SET_ELEM_DATA = 0x2 + NFTA_SET_ELEM_FLAGS = 0x3 + NFTA_SET_ELEM_TIMEOUT = 0x4 + NFTA_SET_ELEM_EXPIRATION = 0x5 + NFTA_SET_ELEM_USERDATA = 0x6 + NFTA_SET_ELEM_EXPR = 0x7 + NFTA_SET_ELEM_PAD = 0x8 + NFTA_SET_ELEM_OBJREF = 0x9 + NFTA_SET_ELEM_LIST_UNSPEC = 0x0 + NFTA_SET_ELEM_LIST_TABLE = 0x1 + NFTA_SET_ELEM_LIST_SET = 0x2 + NFTA_SET_ELEM_LIST_ELEMENTS = 0x3 + NFTA_SET_ELEM_LIST_SET_ID = 0x4 + NFT_DATA_VALUE = 0x0 + NFT_DATA_VERDICT = 0xffffff00 + NFTA_DATA_UNSPEC = 0x0 + NFTA_DATA_VALUE = 0x1 + NFTA_DATA_VERDICT = 0x2 + NFTA_VERDICT_UNSPEC = 0x0 + NFTA_VERDICT_CODE = 0x1 + NFTA_VERDICT_CHAIN = 0x2 + NFTA_EXPR_UNSPEC = 0x0 + NFTA_EXPR_NAME = 0x1 + NFTA_EXPR_DATA = 0x2 + NFTA_IMMEDIATE_UNSPEC = 0x0 + NFTA_IMMEDIATE_DREG = 0x1 + NFTA_IMMEDIATE_DATA = 0x2 + NFTA_BITWISE_UNSPEC = 0x0 + NFTA_BITWISE_SREG = 0x1 + NFTA_BITWISE_DREG = 0x2 + NFTA_BITWISE_LEN = 0x3 + NFTA_BITWISE_MASK = 0x4 + NFTA_BITWISE_XOR = 0x5 + NFT_BYTEORDER_NTOH = 0x0 + NFT_BYTEORDER_HTON = 0x1 + NFTA_BYTEORDER_UNSPEC = 0x0 + NFTA_BYTEORDER_SREG = 0x1 + NFTA_BYTEORDER_DREG = 0x2 + NFTA_BYTEORDER_OP = 0x3 + NFTA_BYTEORDER_LEN = 0x4 + NFTA_BYTEORDER_SIZE = 0x5 + NFT_CMP_EQ = 0x0 + NFT_CMP_NEQ = 0x1 + NFT_CMP_LT = 0x2 + NFT_CMP_LTE = 0x3 + NFT_CMP_GT = 0x4 + NFT_CMP_GTE = 0x5 + NFTA_CMP_UNSPEC = 0x0 + NFTA_CMP_SREG = 0x1 + NFTA_CMP_OP = 0x2 + NFTA_CMP_DATA = 0x3 + NFT_RANGE_EQ = 0x0 + NFT_RANGE_NEQ = 0x1 + NFTA_RANGE_UNSPEC = 0x0 + NFTA_RANGE_SREG = 0x1 + NFTA_RANGE_OP = 0x2 + NFTA_RANGE_FROM_DATA = 0x3 + NFTA_RANGE_TO_DATA = 0x4 + NFT_LOOKUP_F_INV = 0x1 + NFTA_LOOKUP_UNSPEC = 0x0 + NFTA_LOOKUP_SET = 0x1 + NFTA_LOOKUP_SREG = 0x2 + NFTA_LOOKUP_DREG = 0x3 + NFTA_LOOKUP_SET_ID = 0x4 + NFTA_LOOKUP_FLAGS = 0x5 + NFT_DYNSET_OP_ADD = 0x0 + NFT_DYNSET_OP_UPDATE = 0x1 + NFT_DYNSET_F_INV = 0x1 + NFTA_DYNSET_UNSPEC = 0x0 + NFTA_DYNSET_SET_NAME = 0x1 + NFTA_DYNSET_SET_ID = 0x2 + NFTA_DYNSET_OP = 0x3 + NFTA_DYNSET_SREG_KEY = 0x4 + NFTA_DYNSET_SREG_DATA = 0x5 + NFTA_DYNSET_TIMEOUT = 0x6 + NFTA_DYNSET_EXPR = 0x7 + NFTA_DYNSET_PAD = 0x8 + NFTA_DYNSET_FLAGS = 0x9 + NFT_PAYLOAD_LL_HEADER = 0x0 + NFT_PAYLOAD_NETWORK_HEADER = 0x1 + NFT_PAYLOAD_TRANSPORT_HEADER = 0x2 + NFT_PAYLOAD_CSUM_NONE = 0x0 + NFT_PAYLOAD_CSUM_INET = 0x1 + NFT_PAYLOAD_L4CSUM_PSEUDOHDR = 0x1 + NFTA_PAYLOAD_UNSPEC = 0x0 + NFTA_PAYLOAD_DREG = 0x1 + NFTA_PAYLOAD_BASE = 0x2 + NFTA_PAYLOAD_OFFSET = 0x3 + NFTA_PAYLOAD_LEN = 0x4 + NFTA_PAYLOAD_SREG = 0x5 + NFTA_PAYLOAD_CSUM_TYPE = 0x6 + NFTA_PAYLOAD_CSUM_OFFSET = 0x7 + NFTA_PAYLOAD_CSUM_FLAGS = 0x8 + NFT_EXTHDR_F_PRESENT = 0x1 + NFT_EXTHDR_OP_IPV6 = 0x0 + NFT_EXTHDR_OP_TCPOPT = 0x1 + NFTA_EXTHDR_UNSPEC = 0x0 + NFTA_EXTHDR_DREG = 0x1 + NFTA_EXTHDR_TYPE = 0x2 + NFTA_EXTHDR_OFFSET = 0x3 + NFTA_EXTHDR_LEN = 0x4 + NFTA_EXTHDR_FLAGS = 0x5 + NFTA_EXTHDR_OP = 0x6 + NFTA_EXTHDR_SREG = 0x7 + NFT_META_LEN = 0x0 + NFT_META_PROTOCOL = 0x1 + NFT_META_PRIORITY = 0x2 + NFT_META_MARK = 0x3 + NFT_META_IIF = 0x4 + NFT_META_OIF = 0x5 + NFT_META_IIFNAME = 0x6 + NFT_META_OIFNAME = 0x7 + NFT_META_IIFTYPE = 0x8 + NFT_META_OIFTYPE = 0x9 + NFT_META_SKUID = 0xa + NFT_META_SKGID = 0xb + NFT_META_NFTRACE = 0xc + NFT_META_RTCLASSID = 0xd + NFT_META_SECMARK = 0xe + NFT_META_NFPROTO = 0xf + NFT_META_L4PROTO = 0x10 + NFT_META_BRI_IIFNAME = 0x11 + NFT_META_BRI_OIFNAME = 0x12 + NFT_META_PKTTYPE = 0x13 + NFT_META_CPU = 0x14 + NFT_META_IIFGROUP = 0x15 + NFT_META_OIFGROUP = 0x16 + NFT_META_CGROUP = 0x17 + NFT_META_PRANDOM = 0x18 + NFT_RT_CLASSID = 0x0 + NFT_RT_NEXTHOP4 = 0x1 + NFT_RT_NEXTHOP6 = 0x2 + NFT_RT_TCPMSS = 0x3 + NFT_HASH_JENKINS = 0x0 + NFT_HASH_SYM = 0x1 + NFTA_HASH_UNSPEC = 0x0 + NFTA_HASH_SREG = 0x1 + NFTA_HASH_DREG = 0x2 + NFTA_HASH_LEN = 0x3 + NFTA_HASH_MODULUS = 0x4 + NFTA_HASH_SEED = 0x5 + NFTA_HASH_OFFSET = 0x6 + NFTA_HASH_TYPE = 0x7 + NFTA_META_UNSPEC = 0x0 + NFTA_META_DREG = 0x1 + NFTA_META_KEY = 0x2 + NFTA_META_SREG = 0x3 + NFTA_RT_UNSPEC = 0x0 + NFTA_RT_DREG = 0x1 + NFTA_RT_KEY = 0x2 + NFT_CT_STATE = 0x0 + NFT_CT_DIRECTION = 0x1 + NFT_CT_STATUS = 0x2 + NFT_CT_MARK = 0x3 + NFT_CT_SECMARK = 0x4 + NFT_CT_EXPIRATION = 0x5 + NFT_CT_HELPER = 0x6 + NFT_CT_L3PROTOCOL = 0x7 + NFT_CT_SRC = 0x8 + NFT_CT_DST = 0x9 + NFT_CT_PROTOCOL = 0xa + NFT_CT_PROTO_SRC = 0xb + NFT_CT_PROTO_DST = 0xc + NFT_CT_LABELS = 0xd + NFT_CT_PKTS = 0xe + NFT_CT_BYTES = 0xf + NFT_CT_AVGPKT = 0x10 + NFT_CT_ZONE = 0x11 + NFT_CT_EVENTMASK = 0x12 + NFTA_CT_UNSPEC = 0x0 + NFTA_CT_DREG = 0x1 + NFTA_CT_KEY = 0x2 + NFTA_CT_DIRECTION = 0x3 + NFTA_CT_SREG = 0x4 + NFT_LIMIT_PKTS = 0x0 + NFT_LIMIT_PKT_BYTES = 0x1 + NFT_LIMIT_F_INV = 0x1 + NFTA_LIMIT_UNSPEC = 0x0 + NFTA_LIMIT_RATE = 0x1 + NFTA_LIMIT_UNIT = 0x2 + NFTA_LIMIT_BURST = 0x3 + NFTA_LIMIT_TYPE = 0x4 + NFTA_LIMIT_FLAGS = 0x5 + NFTA_LIMIT_PAD = 0x6 + NFTA_COUNTER_UNSPEC = 0x0 + NFTA_COUNTER_BYTES = 0x1 + NFTA_COUNTER_PACKETS = 0x2 + NFTA_COUNTER_PAD = 0x3 + NFTA_LOG_UNSPEC = 0x0 + NFTA_LOG_GROUP = 0x1 + NFTA_LOG_PREFIX = 0x2 + NFTA_LOG_SNAPLEN = 0x3 + NFTA_LOG_QTHRESHOLD = 0x4 + NFTA_LOG_LEVEL = 0x5 + NFTA_LOG_FLAGS = 0x6 + NFTA_QUEUE_UNSPEC = 0x0 + NFTA_QUEUE_NUM = 0x1 + NFTA_QUEUE_TOTAL = 0x2 + NFTA_QUEUE_FLAGS = 0x3 + NFTA_QUEUE_SREG_QNUM = 0x4 + NFT_QUOTA_F_INV = 0x1 + NFT_QUOTA_F_DEPLETED = 0x2 + NFTA_QUOTA_UNSPEC = 0x0 + NFTA_QUOTA_BYTES = 0x1 + NFTA_QUOTA_FLAGS = 0x2 + NFTA_QUOTA_PAD = 0x3 + NFTA_QUOTA_CONSUMED = 0x4 + NFT_REJECT_ICMP_UNREACH = 0x0 + NFT_REJECT_TCP_RST = 0x1 + NFT_REJECT_ICMPX_UNREACH = 0x2 + NFT_REJECT_ICMPX_NO_ROUTE = 0x0 + NFT_REJECT_ICMPX_PORT_UNREACH = 0x1 + NFT_REJECT_ICMPX_HOST_UNREACH = 0x2 + NFT_REJECT_ICMPX_ADMIN_PROHIBITED = 0x3 + NFTA_REJECT_UNSPEC = 0x0 + NFTA_REJECT_TYPE = 0x1 + NFTA_REJECT_ICMP_CODE = 0x2 + NFT_NAT_SNAT = 0x0 + NFT_NAT_DNAT = 0x1 + NFTA_NAT_UNSPEC = 0x0 + NFTA_NAT_TYPE = 0x1 + NFTA_NAT_FAMILY = 0x2 + NFTA_NAT_REG_ADDR_MIN = 0x3 + NFTA_NAT_REG_ADDR_MAX = 0x4 + NFTA_NAT_REG_PROTO_MIN = 0x5 + NFTA_NAT_REG_PROTO_MAX = 0x6 + NFTA_NAT_FLAGS = 0x7 + NFTA_MASQ_UNSPEC = 0x0 + NFTA_MASQ_FLAGS = 0x1 + NFTA_MASQ_REG_PROTO_MIN = 0x2 + NFTA_MASQ_REG_PROTO_MAX = 0x3 + NFTA_REDIR_UNSPEC = 0x0 + NFTA_REDIR_REG_PROTO_MIN = 0x1 + NFTA_REDIR_REG_PROTO_MAX = 0x2 + NFTA_REDIR_FLAGS = 0x3 + NFTA_DUP_UNSPEC = 0x0 + NFTA_DUP_SREG_ADDR = 0x1 + NFTA_DUP_SREG_DEV = 0x2 + NFTA_FWD_UNSPEC = 0x0 + NFTA_FWD_SREG_DEV = 0x1 + NFTA_OBJREF_UNSPEC = 0x0 + NFTA_OBJREF_IMM_TYPE = 0x1 + NFTA_OBJREF_IMM_NAME = 0x2 + NFTA_OBJREF_SET_SREG = 0x3 + NFTA_OBJREF_SET_NAME = 0x4 + NFTA_OBJREF_SET_ID = 0x5 + NFTA_GEN_UNSPEC = 0x0 + NFTA_GEN_ID = 0x1 + NFTA_GEN_PROC_PID = 0x2 + NFTA_GEN_PROC_NAME = 0x3 + NFTA_FIB_UNSPEC = 0x0 + NFTA_FIB_DREG = 0x1 + NFTA_FIB_RESULT = 0x2 + NFTA_FIB_FLAGS = 0x3 + NFT_FIB_RESULT_UNSPEC = 0x0 + NFT_FIB_RESULT_OIF = 0x1 + NFT_FIB_RESULT_OIFNAME = 0x2 + NFT_FIB_RESULT_ADDRTYPE = 0x3 + NFTA_FIB_F_SADDR = 0x1 + NFTA_FIB_F_DADDR = 0x2 + NFTA_FIB_F_MARK = 0x4 + NFTA_FIB_F_IIF = 0x8 + NFTA_FIB_F_OIF = 0x10 + NFTA_FIB_F_PRESENT = 0x20 + NFTA_CT_HELPER_UNSPEC = 0x0 + NFTA_CT_HELPER_NAME = 0x1 + NFTA_CT_HELPER_L3PROTO = 0x2 + NFTA_CT_HELPER_L4PROTO = 0x3 + NFTA_OBJ_UNSPEC = 0x0 + NFTA_OBJ_TABLE = 0x1 + NFTA_OBJ_NAME = 0x2 + NFTA_OBJ_TYPE = 0x3 + NFTA_OBJ_DATA = 0x4 + NFTA_OBJ_USE = 0x5 + NFTA_TRACE_UNSPEC = 0x0 + NFTA_TRACE_TABLE = 0x1 + NFTA_TRACE_CHAIN = 0x2 + NFTA_TRACE_RULE_HANDLE = 0x3 + NFTA_TRACE_TYPE = 0x4 + NFTA_TRACE_VERDICT = 0x5 + NFTA_TRACE_ID = 0x6 + NFTA_TRACE_LL_HEADER = 0x7 + NFTA_TRACE_NETWORK_HEADER = 0x8 + NFTA_TRACE_TRANSPORT_HEADER = 0x9 + NFTA_TRACE_IIF = 0xa + NFTA_TRACE_IIFTYPE = 0xb + NFTA_TRACE_OIF = 0xc + NFTA_TRACE_OIFTYPE = 0xd + NFTA_TRACE_MARK = 0xe + NFTA_TRACE_NFPROTO = 0xf + NFTA_TRACE_POLICY = 0x10 + NFTA_TRACE_PAD = 0x11 + NFT_TRACETYPE_UNSPEC = 0x0 + NFT_TRACETYPE_POLICY = 0x1 + NFT_TRACETYPE_RETURN = 0x2 + NFT_TRACETYPE_RULE = 0x3 + NFTA_NG_UNSPEC = 0x0 + NFTA_NG_DREG = 0x1 + NFTA_NG_MODULUS = 0x2 + NFTA_NG_TYPE = 0x3 + NFTA_NG_OFFSET = 0x4 + NFT_NG_INCREMENTAL = 0x0 + NFT_NG_RANDOM = 0x1 +) + +type RTCTime struct { + Sec int32 + Min int32 + Hour int32 + Mday int32 + Mon int32 + Year int32 + Wday int32 + Yday int32 + Isdst int32 +} + +type RTCWkAlrm struct { + Enabled uint8 + Pending uint8 + Time RTCTime +} + +type RTCPLLInfo struct { + Ctrl int32 + Value int32 + Max int32 + Min int32 + Posmult int32 + Negmult int32 + Clock int32 +} + +type BlkpgIoctlArg struct { + Op int32 + Flags int32 + Datalen int32 + Data *byte +} + +type BlkpgPartition struct { + Start int64 + Length int64 + Pno int32 + Devname [64]uint8 + Volname [64]uint8 +} + +const ( + BLKPG = 0x1269 + BLKPG_ADD_PARTITION = 0x1 + BLKPG_DEL_PARTITION = 0x2 + BLKPG_RESIZE_PARTITION = 0x3 +) + +const ( + NETNSA_NONE = 0x0 + NETNSA_NSID = 0x1 + NETNSA_PID = 0x2 + NETNSA_FD = 0x3 +) + +type XDPRingOffset struct { + Producer uint64 + Consumer uint64 + Desc uint64 +} + +type XDPMmapOffsets struct { + Rx XDPRingOffset + Tx XDPRingOffset + Fr XDPRingOffset + Cr XDPRingOffset +} + +type XDPUmemReg struct { + Addr uint64 + Len uint64 + Size uint32 + Headroom uint32 +} + +type XDPStatistics struct { + Rx_dropped uint64 + Rx_invalid_descs uint64 + Tx_invalid_descs uint64 +} + +type XDPDesc struct { + Addr uint64 + Len uint32 + Options uint32 +} + +const ( + NCSI_CMD_UNSPEC = 0x0 + NCSI_CMD_PKG_INFO = 0x1 + NCSI_CMD_SET_INTERFACE = 0x2 + NCSI_CMD_CLEAR_INTERFACE = 0x3 + NCSI_ATTR_UNSPEC = 0x0 + NCSI_ATTR_IFINDEX = 0x1 + NCSI_ATTR_PACKAGE_LIST = 0x2 + NCSI_ATTR_PACKAGE_ID = 0x3 + NCSI_ATTR_CHANNEL_ID = 0x4 + NCSI_PKG_ATTR_UNSPEC = 0x0 + NCSI_PKG_ATTR = 0x1 + NCSI_PKG_ATTR_ID = 0x2 + NCSI_PKG_ATTR_FORCED = 0x3 + NCSI_PKG_ATTR_CHANNEL_LIST = 0x4 + NCSI_CHANNEL_ATTR_UNSPEC = 0x0 + NCSI_CHANNEL_ATTR = 0x1 + NCSI_CHANNEL_ATTR_ID = 0x2 + NCSI_CHANNEL_ATTR_VERSION_MAJOR = 0x3 + NCSI_CHANNEL_ATTR_VERSION_MINOR = 0x4 + NCSI_CHANNEL_ATTR_VERSION_STR = 0x5 + NCSI_CHANNEL_ATTR_LINK_STATE = 0x6 + NCSI_CHANNEL_ATTR_ACTIVE = 0x7 + NCSI_CHANNEL_ATTR_FORCED = 0x8 + NCSI_CHANNEL_ATTR_VLAN_LIST = 0x9 + NCSI_CHANNEL_ATTR_VLAN_ID = 0xa +) + +type ScmTimestamping struct { + Ts [3]Timespec +} + +const ( + SOF_TIMESTAMPING_TX_HARDWARE = 0x1 + SOF_TIMESTAMPING_TX_SOFTWARE = 0x2 + SOF_TIMESTAMPING_RX_HARDWARE = 0x4 + SOF_TIMESTAMPING_RX_SOFTWARE = 0x8 + SOF_TIMESTAMPING_SOFTWARE = 0x10 + SOF_TIMESTAMPING_SYS_HARDWARE = 0x20 + SOF_TIMESTAMPING_RAW_HARDWARE = 0x40 + SOF_TIMESTAMPING_OPT_ID = 0x80 + SOF_TIMESTAMPING_TX_SCHED = 0x100 + SOF_TIMESTAMPING_TX_ACK = 0x200 + SOF_TIMESTAMPING_OPT_CMSG = 0x400 + SOF_TIMESTAMPING_OPT_TSONLY = 0x800 + SOF_TIMESTAMPING_OPT_STATS = 0x1000 + SOF_TIMESTAMPING_OPT_PKTINFO = 0x2000 + SOF_TIMESTAMPING_OPT_TX_SWHW = 0x4000 + + SOF_TIMESTAMPING_LAST = 0x4000 + SOF_TIMESTAMPING_MASK = 0x7fff + + SCM_TSTAMP_SND = 0x0 + SCM_TSTAMP_SCHED = 0x1 + SCM_TSTAMP_ACK = 0x2 +) + +type SockExtendedErr struct { + Errno uint32 + Origin uint8 + Type uint8 + Code uint8 + Pad uint8 + Info uint32 + Data uint32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go index 4ea42dfc2e..e492caacda 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go @@ -6,11 +6,11 @@ package unix const ( - sizeofPtr = 0x8 - sizeofShort = 0x2 - sizeofInt = 0x4 - sizeofLong = 0x8 - sizeofLongLong = 0x8 + SizeofPtr = 0x8 + SizeofShort = 0x2 + SizeofInt = 0x4 + SizeofLong = 0x8 + SizeofLongLong = 0x8 PathMax = 0x1000 ) @@ -33,13 +33,11 @@ type Timeval struct { type Timex struct { Modes uint32 - Pad_cgo_0 [4]byte Offset int64 Freq int64 Maxerror int64 Esterror int64 Status int32 - Pad_cgo_1 [4]byte Constant int64 Precision int64 Tolerance int64 @@ -48,14 +46,13 @@ type Timex struct { Ppsfreq int64 Jitter int64 Shift int32 - Pad_cgo_2 [4]byte Stabil int64 Jitcnt int64 Calcnt int64 Errcnt int64 Stbcnt int64 Tai int32 - Pad_cgo_3 [44]byte + _ [44]byte } type Time_t int64 @@ -105,7 +102,7 @@ type Stat_t struct { Mode uint32 Uid uint32 Gid uint32 - X__pad0 int32 + _ int32 Rdev uint64 Size int64 Blksize int64 @@ -116,42 +113,56 @@ type Stat_t struct { _ [3]int64 } -type Statfs_t struct { - Type int64 - Bsize int64 - Blocks uint64 - Bfree uint64 - Bavail uint64 - Files uint64 - Ffree uint64 - Fsid Fsid - Namelen int64 - Frsize int64 - Flags int64 - Spare [4]int64 +type StatxTimestamp struct { + Sec int64 + Nsec uint32 + _ int32 +} + +type Statx_t struct { + Mask uint32 + Blksize uint32 + Attributes uint64 + Nlink uint32 + Uid uint32 + Gid uint32 + Mode uint16 + _ [1]uint16 + Ino uint64 + Size uint64 + Blocks uint64 + Attributes_mask uint64 + Atime StatxTimestamp + Btime StatxTimestamp + Ctime StatxTimestamp + Mtime StatxTimestamp + Rdev_major uint32 + Rdev_minor uint32 + Dev_major uint32 + Dev_minor uint32 + _ [14]uint64 } type Dirent struct { - Ino uint64 - Off int64 - Reclen uint16 - Type uint8 - Name [256]int8 - Pad_cgo_0 [5]byte + Ino uint64 + Off int64 + Reclen uint16 + Type uint8 + Name [256]int8 + _ [5]byte } type Fsid struct { - X__val [2]int32 + Val [2]int32 } type Flock_t struct { - Type int16 - Whence int16 - Pad_cgo_0 [4]byte - Start int64 - Len int64 - Pid int32 - Pad_cgo_1 [4]byte + Type int16 + Whence int16 + Start int64 + Len int64 + Pid int32 + _ [4]byte } type FscryptPolicy struct { @@ -226,11 +237,26 @@ type RawSockaddrHCI struct { Channel uint16 } +type RawSockaddrL2 struct { + Family uint16 + Psm uint16 + Bdaddr [6]uint8 + Cid uint16 + Bdaddr_type uint8 + _ [1]byte +} + +type RawSockaddrRFCOMM struct { + Family uint16 + Bdaddr [6]uint8 + Channel uint8 + _ [1]byte +} + type RawSockaddrCAN struct { - Family uint16 - Pad_cgo_0 [2]byte - Ifindex int32 - Addr [8]byte + Family uint16 + Ifindex int32 + Addr [8]byte } type RawSockaddrALG struct { @@ -249,6 +275,16 @@ type RawSockaddrVM struct { Zero [4]uint8 } +type RawSockaddrXDP struct { + Family uint16 + Flags uint16 + Ifindex uint32 + Queue_id uint32 + Shared_umem_fd uint32 +} + +type RawSockaddrPPPoX [0x1e]byte + type RawSockaddr struct { Family uint16 Data [14]int8 @@ -297,13 +333,12 @@ type PacketMreq struct { type Msghdr struct { Name *byte Namelen uint32 - Pad_cgo_0 [4]byte Iov *Iovec Iovlen uint64 Control *byte Controllen uint64 Flags int32 - Pad_cgo_1 [4]byte + _ [4]byte } type Cmsghdr struct { @@ -345,7 +380,6 @@ type TCPInfo struct { Probes uint8 Backoff uint8 Options uint8 - Pad_cgo_0 [2]byte Rto uint32 Ato uint32 Snd_mss uint32 @@ -380,9 +414,13 @@ const ( SizeofSockaddrLinklayer = 0x14 SizeofSockaddrNetlink = 0xc SizeofSockaddrHCI = 0x6 + SizeofSockaddrL2 = 0xe + SizeofSockaddrRFCOMM = 0xa SizeofSockaddrCAN = 0x10 SizeofSockaddrALG = 0x58 SizeofSockaddrVM = 0x10 + SizeofSockaddrXDP = 0x10 + SizeofSockaddrPPPoX = 0x1e SizeofLinger = 0x8 SizeofIovec = 0x10 SizeofIPMreq = 0x8 @@ -400,97 +438,138 @@ const ( ) const ( - IFA_UNSPEC = 0x0 - IFA_ADDRESS = 0x1 - IFA_LOCAL = 0x2 - IFA_LABEL = 0x3 - IFA_BROADCAST = 0x4 - IFA_ANYCAST = 0x5 - IFA_CACHEINFO = 0x6 - IFA_MULTICAST = 0x7 - IFLA_UNSPEC = 0x0 - IFLA_ADDRESS = 0x1 - IFLA_BROADCAST = 0x2 - IFLA_IFNAME = 0x3 - IFLA_MTU = 0x4 - IFLA_LINK = 0x5 - IFLA_QDISC = 0x6 - IFLA_STATS = 0x7 - IFLA_COST = 0x8 - IFLA_PRIORITY = 0x9 - IFLA_MASTER = 0xa - IFLA_WIRELESS = 0xb - IFLA_PROTINFO = 0xc - IFLA_TXQLEN = 0xd - IFLA_MAP = 0xe - IFLA_WEIGHT = 0xf - IFLA_OPERSTATE = 0x10 - IFLA_LINKMODE = 0x11 - IFLA_LINKINFO = 0x12 - IFLA_NET_NS_PID = 0x13 - IFLA_IFALIAS = 0x14 - IFLA_MAX = 0x2c - RT_SCOPE_UNIVERSE = 0x0 - RT_SCOPE_SITE = 0xc8 - RT_SCOPE_LINK = 0xfd - RT_SCOPE_HOST = 0xfe - RT_SCOPE_NOWHERE = 0xff - RT_TABLE_UNSPEC = 0x0 - RT_TABLE_COMPAT = 0xfc - RT_TABLE_DEFAULT = 0xfd - RT_TABLE_MAIN = 0xfe - RT_TABLE_LOCAL = 0xff - RT_TABLE_MAX = 0xffffffff - RTA_UNSPEC = 0x0 - RTA_DST = 0x1 - RTA_SRC = 0x2 - RTA_IIF = 0x3 - RTA_OIF = 0x4 - RTA_GATEWAY = 0x5 - RTA_PRIORITY = 0x6 - RTA_PREFSRC = 0x7 - RTA_METRICS = 0x8 - RTA_MULTIPATH = 0x9 - RTA_FLOW = 0xb - RTA_CACHEINFO = 0xc - RTA_TABLE = 0xf - RTN_UNSPEC = 0x0 - RTN_UNICAST = 0x1 - RTN_LOCAL = 0x2 - RTN_BROADCAST = 0x3 - RTN_ANYCAST = 0x4 - RTN_MULTICAST = 0x5 - RTN_BLACKHOLE = 0x6 - RTN_UNREACHABLE = 0x7 - RTN_PROHIBIT = 0x8 - RTN_THROW = 0x9 - RTN_NAT = 0xa - RTN_XRESOLVE = 0xb - RTNLGRP_NONE = 0x0 - RTNLGRP_LINK = 0x1 - RTNLGRP_NOTIFY = 0x2 - RTNLGRP_NEIGH = 0x3 - RTNLGRP_TC = 0x4 - RTNLGRP_IPV4_IFADDR = 0x5 - RTNLGRP_IPV4_MROUTE = 0x6 - RTNLGRP_IPV4_ROUTE = 0x7 - RTNLGRP_IPV4_RULE = 0x8 - RTNLGRP_IPV6_IFADDR = 0x9 - RTNLGRP_IPV6_MROUTE = 0xa - RTNLGRP_IPV6_ROUTE = 0xb - RTNLGRP_IPV6_IFINFO = 0xc - RTNLGRP_IPV6_PREFIX = 0x12 - RTNLGRP_IPV6_RULE = 0x13 - RTNLGRP_ND_USEROPT = 0x14 - SizeofNlMsghdr = 0x10 - SizeofNlMsgerr = 0x14 - SizeofRtGenmsg = 0x1 - SizeofNlAttr = 0x4 - SizeofRtAttr = 0x4 - SizeofIfInfomsg = 0x10 - SizeofIfAddrmsg = 0x8 - SizeofRtMsg = 0xc - SizeofRtNexthop = 0x8 + IFA_UNSPEC = 0x0 + IFA_ADDRESS = 0x1 + IFA_LOCAL = 0x2 + IFA_LABEL = 0x3 + IFA_BROADCAST = 0x4 + IFA_ANYCAST = 0x5 + IFA_CACHEINFO = 0x6 + IFA_MULTICAST = 0x7 + IFLA_UNSPEC = 0x0 + IFLA_ADDRESS = 0x1 + IFLA_BROADCAST = 0x2 + IFLA_IFNAME = 0x3 + IFLA_INFO_KIND = 0x1 + IFLA_MTU = 0x4 + IFLA_LINK = 0x5 + IFLA_QDISC = 0x6 + IFLA_STATS = 0x7 + IFLA_COST = 0x8 + IFLA_PRIORITY = 0x9 + IFLA_MASTER = 0xa + IFLA_WIRELESS = 0xb + IFLA_PROTINFO = 0xc + IFLA_TXQLEN = 0xd + IFLA_MAP = 0xe + IFLA_WEIGHT = 0xf + IFLA_OPERSTATE = 0x10 + IFLA_LINKMODE = 0x11 + IFLA_LINKINFO = 0x12 + IFLA_NET_NS_PID = 0x13 + IFLA_IFALIAS = 0x14 + IFLA_NUM_VF = 0x15 + IFLA_VFINFO_LIST = 0x16 + IFLA_STATS64 = 0x17 + IFLA_VF_PORTS = 0x18 + IFLA_PORT_SELF = 0x19 + IFLA_AF_SPEC = 0x1a + IFLA_GROUP = 0x1b + IFLA_NET_NS_FD = 0x1c + IFLA_EXT_MASK = 0x1d + IFLA_PROMISCUITY = 0x1e + IFLA_NUM_TX_QUEUES = 0x1f + IFLA_NUM_RX_QUEUES = 0x20 + IFLA_CARRIER = 0x21 + IFLA_PHYS_PORT_ID = 0x22 + IFLA_CARRIER_CHANGES = 0x23 + IFLA_PHYS_SWITCH_ID = 0x24 + IFLA_LINK_NETNSID = 0x25 + IFLA_PHYS_PORT_NAME = 0x26 + IFLA_PROTO_DOWN = 0x27 + IFLA_GSO_MAX_SEGS = 0x28 + IFLA_GSO_MAX_SIZE = 0x29 + IFLA_PAD = 0x2a + IFLA_XDP = 0x2b + IFLA_EVENT = 0x2c + IFLA_NEW_NETNSID = 0x2d + IFLA_IF_NETNSID = 0x2e + IFLA_MAX = 0x33 + RT_SCOPE_UNIVERSE = 0x0 + RT_SCOPE_SITE = 0xc8 + RT_SCOPE_LINK = 0xfd + RT_SCOPE_HOST = 0xfe + RT_SCOPE_NOWHERE = 0xff + RT_TABLE_UNSPEC = 0x0 + RT_TABLE_COMPAT = 0xfc + RT_TABLE_DEFAULT = 0xfd + RT_TABLE_MAIN = 0xfe + RT_TABLE_LOCAL = 0xff + RT_TABLE_MAX = 0xffffffff + RTA_UNSPEC = 0x0 + RTA_DST = 0x1 + RTA_SRC = 0x2 + RTA_IIF = 0x3 + RTA_OIF = 0x4 + RTA_GATEWAY = 0x5 + RTA_PRIORITY = 0x6 + RTA_PREFSRC = 0x7 + RTA_METRICS = 0x8 + RTA_MULTIPATH = 0x9 + RTA_FLOW = 0xb + RTA_CACHEINFO = 0xc + RTA_TABLE = 0xf + RTA_MARK = 0x10 + RTA_MFC_STATS = 0x11 + RTA_VIA = 0x12 + RTA_NEWDST = 0x13 + RTA_PREF = 0x14 + RTA_ENCAP_TYPE = 0x15 + RTA_ENCAP = 0x16 + RTA_EXPIRES = 0x17 + RTA_PAD = 0x18 + RTA_UID = 0x19 + RTA_TTL_PROPAGATE = 0x1a + RTA_IP_PROTO = 0x1b + RTA_SPORT = 0x1c + RTA_DPORT = 0x1d + RTN_UNSPEC = 0x0 + RTN_UNICAST = 0x1 + RTN_LOCAL = 0x2 + RTN_BROADCAST = 0x3 + RTN_ANYCAST = 0x4 + RTN_MULTICAST = 0x5 + RTN_BLACKHOLE = 0x6 + RTN_UNREACHABLE = 0x7 + RTN_PROHIBIT = 0x8 + RTN_THROW = 0x9 + RTN_NAT = 0xa + RTN_XRESOLVE = 0xb + RTNLGRP_NONE = 0x0 + RTNLGRP_LINK = 0x1 + RTNLGRP_NOTIFY = 0x2 + RTNLGRP_NEIGH = 0x3 + RTNLGRP_TC = 0x4 + RTNLGRP_IPV4_IFADDR = 0x5 + RTNLGRP_IPV4_MROUTE = 0x6 + RTNLGRP_IPV4_ROUTE = 0x7 + RTNLGRP_IPV4_RULE = 0x8 + RTNLGRP_IPV6_IFADDR = 0x9 + RTNLGRP_IPV6_MROUTE = 0xa + RTNLGRP_IPV6_ROUTE = 0xb + RTNLGRP_IPV6_IFINFO = 0xc + RTNLGRP_IPV6_PREFIX = 0x12 + RTNLGRP_IPV6_RULE = 0x13 + RTNLGRP_ND_USEROPT = 0x14 + SizeofNlMsghdr = 0x10 + SizeofNlMsgerr = 0x14 + SizeofRtGenmsg = 0x1 + SizeofNlAttr = 0x4 + SizeofRtAttr = 0x4 + SizeofIfInfomsg = 0x10 + SizeofIfAddrmsg = 0x8 + SizeofRtMsg = 0xc + SizeofRtNexthop = 0x8 ) type NlMsghdr struct { @@ -521,12 +600,12 @@ type RtAttr struct { } type IfInfomsg struct { - Family uint8 - X__ifi_pad uint8 - Type uint16 - Index int32 - Flags uint32 - Change uint32 + Family uint8 + _ uint8 + Type uint16 + Index int32 + Flags uint32 + Change uint32 } type IfAddrmsg struct { @@ -569,9 +648,8 @@ type SockFilter struct { } type SockFprog struct { - Len uint16 - Pad_cgo_0 [6]byte - Filter *SockFilter + Len uint16 + Filter *SockFilter } type InotifyEvent struct { @@ -628,12 +706,11 @@ type Sysinfo_t struct { Freeswap uint64 Procs uint16 Pad uint16 - Pad_cgo_0 [4]byte Totalhigh uint64 Freehigh uint64 Unit uint32 - X_f [0]int8 - Pad_cgo_1 [4]byte + _ [0]int8 + _ [4]byte } type Utsname struct { @@ -646,12 +723,11 @@ type Utsname struct { } type Ustat_t struct { - Tfree int32 - Pad_cgo_0 [4]byte - Tinode uint64 - Fname [6]int8 - Fpack [6]int8 - Pad_cgo_1 [4]byte + Tfree int32 + Tinode uint64 + Fname [6]int8 + Fpack [6]int8 + _ [4]byte } type EpollEvent struct { @@ -661,10 +737,19 @@ type EpollEvent struct { } const ( - AT_FDCWD = -0x64 - AT_REMOVEDIR = 0x200 + AT_EMPTY_PATH = 0x1000 + AT_FDCWD = -0x64 + AT_NO_AUTOMOUNT = 0x800 + AT_REMOVEDIR = 0x200 + + AT_STATX_SYNC_AS_STAT = 0x0 + AT_STATX_FORCE_SYNC = 0x2000 + AT_STATX_DONT_SYNC = 0x4000 + AT_SYMLINK_FOLLOW = 0x400 AT_SYMLINK_NOFOLLOW = 0x100 + + AT_EACCESS = 0x200 ) type PollFd struct { @@ -684,10 +769,33 @@ const ( ) type Sigset_t struct { - X__val [16]uint64 + Val [16]uint64 } -const RNDGETENTCNT = 0x80045200 +type SignalfdSiginfo struct { + Signo uint32 + Errno int32 + Code int32 + Pid uint32 + Uid uint32 + Fd int32 + Tid uint32 + Band uint32 + Overrun uint32 + Trapno uint32 + Status int32 + Int int32 + Ptr uint64 + Utime uint64 + Stime uint64 + Addr uint64 + Addr_lsb uint16 + _ uint16 + Syscall int32 + Call_addr uint64 + Arch uint32 + _ [28]uint8 +} const PERF_IOC_FLAG_GROUP = 0x1 @@ -711,11 +819,9 @@ type Winsize struct { type Taskstats struct { Version uint16 - Pad_cgo_0 [2]byte Ac_exitcode uint32 Ac_flag uint8 Ac_nice uint8 - Pad_cgo_1 [6]byte Cpu_count uint64 Cpu_delay_total uint64 Blkio_count uint64 @@ -727,13 +833,12 @@ type Taskstats struct { Ac_comm [32]int8 Ac_sched uint8 Ac_pad [3]uint8 - Pad_cgo_2 [4]byte + _ [4]byte Ac_uid uint32 Ac_gid uint32 Ac_pid uint32 Ac_ppid uint32 Ac_btime uint32 - Pad_cgo_3 [4]byte Ac_etime uint64 Ac_utime uint64 Ac_stime uint64 @@ -757,6 +862,8 @@ type Taskstats struct { Cpu_scaled_run_real_total uint64 Freepages_count uint64 Freepages_delay_total uint64 + Thrashing_count uint64 + Thrashing_delay_total uint64 } const ( @@ -777,6 +884,24 @@ const ( TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK = 0x4 ) +type CGroupStats struct { + Sleeping uint64 + Running uint64 + Stopped uint64 + Uninterruptible uint64 + Io_wait uint64 +} + +const ( + CGROUPSTATS_CMD_UNSPEC = 0x3 + CGROUPSTATS_CMD_GET = 0x4 + CGROUPSTATS_CMD_NEW = 0x5 + CGROUPSTATS_TYPE_UNSPEC = 0x0 + CGROUPSTATS_TYPE_CGROUP_STATS = 0x1 + CGROUPSTATS_CMD_ATTR_UNSPEC = 0x0 + CGROUPSTATS_CMD_ATTR_FD = 0x1 +) + type Genlmsghdr struct { Cmd uint8 Version uint8 @@ -809,3 +934,1107 @@ const ( CTRL_ATTR_MCAST_GRP_NAME = 0x1 CTRL_ATTR_MCAST_GRP_ID = 0x2 ) + +type cpuMask uint64 + +const ( + _CPU_SETSIZE = 0x400 + _NCPUBITS = 0x40 +) + +const ( + BDADDR_BREDR = 0x0 + BDADDR_LE_PUBLIC = 0x1 + BDADDR_LE_RANDOM = 0x2 +) + +type PerfEventAttr struct { + Type uint32 + Size uint32 + Config uint64 + Sample uint64 + Sample_type uint64 + Read_format uint64 + Bits uint64 + Wakeup uint32 + Bp_type uint32 + Ext1 uint64 + Ext2 uint64 + Branch_sample_type uint64 + Sample_regs_user uint64 + Sample_stack_user uint32 + Clockid int32 + Sample_regs_intr uint64 + Aux_watermark uint32 + _ uint32 +} + +type PerfEventMmapPage struct { + Version uint32 + Compat_version uint32 + Lock uint32 + Index uint32 + Offset int64 + Time_enabled uint64 + Time_running uint64 + Capabilities uint64 + Pmc_width uint16 + Time_shift uint16 + Time_mult uint32 + Time_offset uint64 + Time_zero uint64 + Size uint32 + _ [948]uint8 + Data_head uint64 + Data_tail uint64 + Data_offset uint64 + Data_size uint64 + Aux_head uint64 + Aux_tail uint64 + Aux_offset uint64 + Aux_size uint64 +} + +const ( + PerfBitDisabled uint64 = CBitFieldMaskBit0 + PerfBitInherit = CBitFieldMaskBit1 + PerfBitPinned = CBitFieldMaskBit2 + PerfBitExclusive = CBitFieldMaskBit3 + PerfBitExcludeUser = CBitFieldMaskBit4 + PerfBitExcludeKernel = CBitFieldMaskBit5 + PerfBitExcludeHv = CBitFieldMaskBit6 + PerfBitExcludeIdle = CBitFieldMaskBit7 + PerfBitMmap = CBitFieldMaskBit8 + PerfBitComm = CBitFieldMaskBit9 + PerfBitFreq = CBitFieldMaskBit10 + PerfBitInheritStat = CBitFieldMaskBit11 + PerfBitEnableOnExec = CBitFieldMaskBit12 + PerfBitTask = CBitFieldMaskBit13 + PerfBitWatermark = CBitFieldMaskBit14 + PerfBitPreciseIPBit1 = CBitFieldMaskBit15 + PerfBitPreciseIPBit2 = CBitFieldMaskBit16 + PerfBitMmapData = CBitFieldMaskBit17 + PerfBitSampleIDAll = CBitFieldMaskBit18 + PerfBitExcludeHost = CBitFieldMaskBit19 + PerfBitExcludeGuest = CBitFieldMaskBit20 + PerfBitExcludeCallchainKernel = CBitFieldMaskBit21 + PerfBitExcludeCallchainUser = CBitFieldMaskBit22 + PerfBitMmap2 = CBitFieldMaskBit23 + PerfBitCommExec = CBitFieldMaskBit24 + PerfBitUseClockID = CBitFieldMaskBit25 + PerfBitContextSwitch = CBitFieldMaskBit26 +) + +const ( + PERF_TYPE_HARDWARE = 0x0 + PERF_TYPE_SOFTWARE = 0x1 + PERF_TYPE_TRACEPOINT = 0x2 + PERF_TYPE_HW_CACHE = 0x3 + PERF_TYPE_RAW = 0x4 + PERF_TYPE_BREAKPOINT = 0x5 + + PERF_COUNT_HW_CPU_CYCLES = 0x0 + PERF_COUNT_HW_INSTRUCTIONS = 0x1 + PERF_COUNT_HW_CACHE_REFERENCES = 0x2 + PERF_COUNT_HW_CACHE_MISSES = 0x3 + PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 0x4 + PERF_COUNT_HW_BRANCH_MISSES = 0x5 + PERF_COUNT_HW_BUS_CYCLES = 0x6 + PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 0x7 + PERF_COUNT_HW_STALLED_CYCLES_BACKEND = 0x8 + PERF_COUNT_HW_REF_CPU_CYCLES = 0x9 + + PERF_COUNT_HW_CACHE_L1D = 0x0 + PERF_COUNT_HW_CACHE_L1I = 0x1 + PERF_COUNT_HW_CACHE_LL = 0x2 + PERF_COUNT_HW_CACHE_DTLB = 0x3 + PERF_COUNT_HW_CACHE_ITLB = 0x4 + PERF_COUNT_HW_CACHE_BPU = 0x5 + PERF_COUNT_HW_CACHE_NODE = 0x6 + + PERF_COUNT_HW_CACHE_OP_READ = 0x0 + PERF_COUNT_HW_CACHE_OP_WRITE = 0x1 + PERF_COUNT_HW_CACHE_OP_PREFETCH = 0x2 + + PERF_COUNT_HW_CACHE_RESULT_ACCESS = 0x0 + PERF_COUNT_HW_CACHE_RESULT_MISS = 0x1 + + PERF_COUNT_SW_CPU_CLOCK = 0x0 + PERF_COUNT_SW_TASK_CLOCK = 0x1 + PERF_COUNT_SW_PAGE_FAULTS = 0x2 + PERF_COUNT_SW_CONTEXT_SWITCHES = 0x3 + PERF_COUNT_SW_CPU_MIGRATIONS = 0x4 + PERF_COUNT_SW_PAGE_FAULTS_MIN = 0x5 + PERF_COUNT_SW_PAGE_FAULTS_MAJ = 0x6 + PERF_COUNT_SW_ALIGNMENT_FAULTS = 0x7 + PERF_COUNT_SW_EMULATION_FAULTS = 0x8 + PERF_COUNT_SW_DUMMY = 0x9 + + PERF_SAMPLE_IP = 0x1 + PERF_SAMPLE_TID = 0x2 + PERF_SAMPLE_TIME = 0x4 + PERF_SAMPLE_ADDR = 0x8 + PERF_SAMPLE_READ = 0x10 + PERF_SAMPLE_CALLCHAIN = 0x20 + PERF_SAMPLE_ID = 0x40 + PERF_SAMPLE_CPU = 0x80 + PERF_SAMPLE_PERIOD = 0x100 + PERF_SAMPLE_STREAM_ID = 0x200 + PERF_SAMPLE_RAW = 0x400 + PERF_SAMPLE_BRANCH_STACK = 0x800 + + PERF_SAMPLE_BRANCH_USER = 0x1 + PERF_SAMPLE_BRANCH_KERNEL = 0x2 + PERF_SAMPLE_BRANCH_HV = 0x4 + PERF_SAMPLE_BRANCH_ANY = 0x8 + PERF_SAMPLE_BRANCH_ANY_CALL = 0x10 + PERF_SAMPLE_BRANCH_ANY_RETURN = 0x20 + PERF_SAMPLE_BRANCH_IND_CALL = 0x40 + + PERF_FORMAT_TOTAL_TIME_ENABLED = 0x1 + PERF_FORMAT_TOTAL_TIME_RUNNING = 0x2 + PERF_FORMAT_ID = 0x4 + PERF_FORMAT_GROUP = 0x8 + + PERF_RECORD_MMAP = 0x1 + PERF_RECORD_LOST = 0x2 + PERF_RECORD_COMM = 0x3 + PERF_RECORD_EXIT = 0x4 + PERF_RECORD_THROTTLE = 0x5 + PERF_RECORD_UNTHROTTLE = 0x6 + PERF_RECORD_FORK = 0x7 + PERF_RECORD_READ = 0x8 + PERF_RECORD_SAMPLE = 0x9 + + PERF_CONTEXT_HV = -0x20 + PERF_CONTEXT_KERNEL = -0x80 + PERF_CONTEXT_USER = -0x200 + + PERF_CONTEXT_GUEST = -0x800 + PERF_CONTEXT_GUEST_KERNEL = -0x880 + PERF_CONTEXT_GUEST_USER = -0xa00 + + PERF_FLAG_FD_NO_GROUP = 0x1 + PERF_FLAG_FD_OUTPUT = 0x2 + PERF_FLAG_PID_CGROUP = 0x4 +) + +const ( + CBitFieldMaskBit0 = 0x1 + CBitFieldMaskBit1 = 0x2 + CBitFieldMaskBit2 = 0x4 + CBitFieldMaskBit3 = 0x8 + CBitFieldMaskBit4 = 0x10 + CBitFieldMaskBit5 = 0x20 + CBitFieldMaskBit6 = 0x40 + CBitFieldMaskBit7 = 0x80 + CBitFieldMaskBit8 = 0x100 + CBitFieldMaskBit9 = 0x200 + CBitFieldMaskBit10 = 0x400 + CBitFieldMaskBit11 = 0x800 + CBitFieldMaskBit12 = 0x1000 + CBitFieldMaskBit13 = 0x2000 + CBitFieldMaskBit14 = 0x4000 + CBitFieldMaskBit15 = 0x8000 + CBitFieldMaskBit16 = 0x10000 + CBitFieldMaskBit17 = 0x20000 + CBitFieldMaskBit18 = 0x40000 + CBitFieldMaskBit19 = 0x80000 + CBitFieldMaskBit20 = 0x100000 + CBitFieldMaskBit21 = 0x200000 + CBitFieldMaskBit22 = 0x400000 + CBitFieldMaskBit23 = 0x800000 + CBitFieldMaskBit24 = 0x1000000 + CBitFieldMaskBit25 = 0x2000000 + CBitFieldMaskBit26 = 0x4000000 + CBitFieldMaskBit27 = 0x8000000 + CBitFieldMaskBit28 = 0x10000000 + CBitFieldMaskBit29 = 0x20000000 + CBitFieldMaskBit30 = 0x40000000 + CBitFieldMaskBit31 = 0x80000000 + CBitFieldMaskBit32 = 0x100000000 + CBitFieldMaskBit33 = 0x200000000 + CBitFieldMaskBit34 = 0x400000000 + CBitFieldMaskBit35 = 0x800000000 + CBitFieldMaskBit36 = 0x1000000000 + CBitFieldMaskBit37 = 0x2000000000 + CBitFieldMaskBit38 = 0x4000000000 + CBitFieldMaskBit39 = 0x8000000000 + CBitFieldMaskBit40 = 0x10000000000 + CBitFieldMaskBit41 = 0x20000000000 + CBitFieldMaskBit42 = 0x40000000000 + CBitFieldMaskBit43 = 0x80000000000 + CBitFieldMaskBit44 = 0x100000000000 + CBitFieldMaskBit45 = 0x200000000000 + CBitFieldMaskBit46 = 0x400000000000 + CBitFieldMaskBit47 = 0x800000000000 + CBitFieldMaskBit48 = 0x1000000000000 + CBitFieldMaskBit49 = 0x2000000000000 + CBitFieldMaskBit50 = 0x4000000000000 + CBitFieldMaskBit51 = 0x8000000000000 + CBitFieldMaskBit52 = 0x10000000000000 + CBitFieldMaskBit53 = 0x20000000000000 + CBitFieldMaskBit54 = 0x40000000000000 + CBitFieldMaskBit55 = 0x80000000000000 + CBitFieldMaskBit56 = 0x100000000000000 + CBitFieldMaskBit57 = 0x200000000000000 + CBitFieldMaskBit58 = 0x400000000000000 + CBitFieldMaskBit59 = 0x800000000000000 + CBitFieldMaskBit60 = 0x1000000000000000 + CBitFieldMaskBit61 = 0x2000000000000000 + CBitFieldMaskBit62 = 0x4000000000000000 + CBitFieldMaskBit63 = 0x8000000000000000 +) + +type SockaddrStorage struct { + Family uint16 + _ [118]int8 + _ uint64 +} + +type TCPMD5Sig struct { + Addr SockaddrStorage + Flags uint8 + Prefixlen uint8 + Keylen uint16 + _ uint32 + Key [80]uint8 +} + +type HDDriveCmdHdr struct { + Command uint8 + Number uint8 + Feature uint8 + Count uint8 +} + +type HDGeometry struct { + Heads uint8 + Sectors uint8 + Cylinders uint16 + Start uint64 +} + +type HDDriveID struct { + Config uint16 + Cyls uint16 + Reserved2 uint16 + Heads uint16 + Track_bytes uint16 + Sector_bytes uint16 + Sectors uint16 + Vendor0 uint16 + Vendor1 uint16 + Vendor2 uint16 + Serial_no [20]uint8 + Buf_type uint16 + Buf_size uint16 + Ecc_bytes uint16 + Fw_rev [8]uint8 + Model [40]uint8 + Max_multsect uint8 + Vendor3 uint8 + Dword_io uint16 + Vendor4 uint8 + Capability uint8 + Reserved50 uint16 + Vendor5 uint8 + TPIO uint8 + Vendor6 uint8 + TDMA uint8 + Field_valid uint16 + Cur_cyls uint16 + Cur_heads uint16 + Cur_sectors uint16 + Cur_capacity0 uint16 + Cur_capacity1 uint16 + Multsect uint8 + Multsect_valid uint8 + Lba_capacity uint32 + Dma_1word uint16 + Dma_mword uint16 + Eide_pio_modes uint16 + Eide_dma_min uint16 + Eide_dma_time uint16 + Eide_pio uint16 + Eide_pio_iordy uint16 + Words69_70 [2]uint16 + Words71_74 [4]uint16 + Queue_depth uint16 + Words76_79 [4]uint16 + Major_rev_num uint16 + Minor_rev_num uint16 + Command_set_1 uint16 + Command_set_2 uint16 + Cfsse uint16 + Cfs_enable_1 uint16 + Cfs_enable_2 uint16 + Csf_default uint16 + Dma_ultra uint16 + Trseuc uint16 + TrsEuc uint16 + CurAPMvalues uint16 + Mprc uint16 + Hw_config uint16 + Acoustic uint16 + Msrqs uint16 + Sxfert uint16 + Sal uint16 + Spg uint32 + Lba_capacity_2 uint64 + Words104_125 [22]uint16 + Last_lun uint16 + Word127 uint16 + Dlf uint16 + Csfo uint16 + Words130_155 [26]uint16 + Word156 uint16 + Words157_159 [3]uint16 + Cfa_power uint16 + Words161_175 [15]uint16 + Words176_205 [30]uint16 + Words206_254 [49]uint16 + Integrity_word uint16 +} + +type Statfs_t struct { + Type int64 + Bsize int64 + Blocks uint64 + Bfree uint64 + Bavail uint64 + Files uint64 + Ffree uint64 + Fsid Fsid + Namelen int64 + Frsize int64 + Flags int64 + Spare [4]int64 +} + +const ( + ST_MANDLOCK = 0x40 + ST_NOATIME = 0x400 + ST_NODEV = 0x4 + ST_NODIRATIME = 0x800 + ST_NOEXEC = 0x8 + ST_NOSUID = 0x2 + ST_RDONLY = 0x1 + ST_RELATIME = 0x1000 + ST_SYNCHRONOUS = 0x10 +) + +type TpacketHdr struct { + Status uint64 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Sec uint32 + Usec uint32 + _ [4]byte +} + +type Tpacket2Hdr struct { + Status uint32 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Sec uint32 + Nsec uint32 + Vlan_tci uint16 + Vlan_tpid uint16 + _ [4]uint8 +} + +type Tpacket3Hdr struct { + Next_offset uint32 + Sec uint32 + Nsec uint32 + Snaplen uint32 + Len uint32 + Status uint32 + Mac uint16 + Net uint16 + Hv1 TpacketHdrVariant1 + _ [8]uint8 +} + +type TpacketHdrVariant1 struct { + Rxhash uint32 + Vlan_tci uint32 + Vlan_tpid uint16 + _ uint16 +} + +type TpacketBlockDesc struct { + Version uint32 + To_priv uint32 + Hdr [40]byte +} + +type TpacketReq struct { + Block_size uint32 + Block_nr uint32 + Frame_size uint32 + Frame_nr uint32 +} + +type TpacketReq3 struct { + Block_size uint32 + Block_nr uint32 + Frame_size uint32 + Frame_nr uint32 + Retire_blk_tov uint32 + Sizeof_priv uint32 + Feature_req_word uint32 +} + +type TpacketStats struct { + Packets uint32 + Drops uint32 +} + +type TpacketStatsV3 struct { + Packets uint32 + Drops uint32 + Freeze_q_cnt uint32 +} + +type TpacketAuxdata struct { + Status uint32 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Vlan_tci uint16 + Vlan_tpid uint16 +} + +const ( + TPACKET_V1 = 0x0 + TPACKET_V2 = 0x1 + TPACKET_V3 = 0x2 +) + +const ( + SizeofTpacketHdr = 0x20 + SizeofTpacket2Hdr = 0x20 + SizeofTpacket3Hdr = 0x30 +) + +const ( + NF_INET_PRE_ROUTING = 0x0 + NF_INET_LOCAL_IN = 0x1 + NF_INET_FORWARD = 0x2 + NF_INET_LOCAL_OUT = 0x3 + NF_INET_POST_ROUTING = 0x4 + NF_INET_NUMHOOKS = 0x5 +) + +const ( + NF_NETDEV_INGRESS = 0x0 + NF_NETDEV_NUMHOOKS = 0x1 +) + +const ( + NFPROTO_UNSPEC = 0x0 + NFPROTO_INET = 0x1 + NFPROTO_IPV4 = 0x2 + NFPROTO_ARP = 0x3 + NFPROTO_NETDEV = 0x5 + NFPROTO_BRIDGE = 0x7 + NFPROTO_IPV6 = 0xa + NFPROTO_DECNET = 0xc + NFPROTO_NUMPROTO = 0xd +) + +type Nfgenmsg struct { + Nfgen_family uint8 + Version uint8 + Res_id uint16 +} + +const ( + NFNL_BATCH_UNSPEC = 0x0 + NFNL_BATCH_GENID = 0x1 +) + +const ( + NFT_REG_VERDICT = 0x0 + NFT_REG_1 = 0x1 + NFT_REG_2 = 0x2 + NFT_REG_3 = 0x3 + NFT_REG_4 = 0x4 + NFT_REG32_00 = 0x8 + NFT_REG32_01 = 0x9 + NFT_REG32_02 = 0xa + NFT_REG32_03 = 0xb + NFT_REG32_04 = 0xc + NFT_REG32_05 = 0xd + NFT_REG32_06 = 0xe + NFT_REG32_07 = 0xf + NFT_REG32_08 = 0x10 + NFT_REG32_09 = 0x11 + NFT_REG32_10 = 0x12 + NFT_REG32_11 = 0x13 + NFT_REG32_12 = 0x14 + NFT_REG32_13 = 0x15 + NFT_REG32_14 = 0x16 + NFT_REG32_15 = 0x17 + NFT_CONTINUE = -0x1 + NFT_BREAK = -0x2 + NFT_JUMP = -0x3 + NFT_GOTO = -0x4 + NFT_RETURN = -0x5 + NFT_MSG_NEWTABLE = 0x0 + NFT_MSG_GETTABLE = 0x1 + NFT_MSG_DELTABLE = 0x2 + NFT_MSG_NEWCHAIN = 0x3 + NFT_MSG_GETCHAIN = 0x4 + NFT_MSG_DELCHAIN = 0x5 + NFT_MSG_NEWRULE = 0x6 + NFT_MSG_GETRULE = 0x7 + NFT_MSG_DELRULE = 0x8 + NFT_MSG_NEWSET = 0x9 + NFT_MSG_GETSET = 0xa + NFT_MSG_DELSET = 0xb + NFT_MSG_NEWSETELEM = 0xc + NFT_MSG_GETSETELEM = 0xd + NFT_MSG_DELSETELEM = 0xe + NFT_MSG_NEWGEN = 0xf + NFT_MSG_GETGEN = 0x10 + NFT_MSG_TRACE = 0x11 + NFT_MSG_NEWOBJ = 0x12 + NFT_MSG_GETOBJ = 0x13 + NFT_MSG_DELOBJ = 0x14 + NFT_MSG_GETOBJ_RESET = 0x15 + NFT_MSG_MAX = 0x19 + NFTA_LIST_UNPEC = 0x0 + NFTA_LIST_ELEM = 0x1 + NFTA_HOOK_UNSPEC = 0x0 + NFTA_HOOK_HOOKNUM = 0x1 + NFTA_HOOK_PRIORITY = 0x2 + NFTA_HOOK_DEV = 0x3 + NFT_TABLE_F_DORMANT = 0x1 + NFTA_TABLE_UNSPEC = 0x0 + NFTA_TABLE_NAME = 0x1 + NFTA_TABLE_FLAGS = 0x2 + NFTA_TABLE_USE = 0x3 + NFTA_CHAIN_UNSPEC = 0x0 + NFTA_CHAIN_TABLE = 0x1 + NFTA_CHAIN_HANDLE = 0x2 + NFTA_CHAIN_NAME = 0x3 + NFTA_CHAIN_HOOK = 0x4 + NFTA_CHAIN_POLICY = 0x5 + NFTA_CHAIN_USE = 0x6 + NFTA_CHAIN_TYPE = 0x7 + NFTA_CHAIN_COUNTERS = 0x8 + NFTA_CHAIN_PAD = 0x9 + NFTA_RULE_UNSPEC = 0x0 + NFTA_RULE_TABLE = 0x1 + NFTA_RULE_CHAIN = 0x2 + NFTA_RULE_HANDLE = 0x3 + NFTA_RULE_EXPRESSIONS = 0x4 + NFTA_RULE_COMPAT = 0x5 + NFTA_RULE_POSITION = 0x6 + NFTA_RULE_USERDATA = 0x7 + NFTA_RULE_PAD = 0x8 + NFTA_RULE_ID = 0x9 + NFT_RULE_COMPAT_F_INV = 0x2 + NFT_RULE_COMPAT_F_MASK = 0x2 + NFTA_RULE_COMPAT_UNSPEC = 0x0 + NFTA_RULE_COMPAT_PROTO = 0x1 + NFTA_RULE_COMPAT_FLAGS = 0x2 + NFT_SET_ANONYMOUS = 0x1 + NFT_SET_CONSTANT = 0x2 + NFT_SET_INTERVAL = 0x4 + NFT_SET_MAP = 0x8 + NFT_SET_TIMEOUT = 0x10 + NFT_SET_EVAL = 0x20 + NFT_SET_OBJECT = 0x40 + NFT_SET_POL_PERFORMANCE = 0x0 + NFT_SET_POL_MEMORY = 0x1 + NFTA_SET_DESC_UNSPEC = 0x0 + NFTA_SET_DESC_SIZE = 0x1 + NFTA_SET_UNSPEC = 0x0 + NFTA_SET_TABLE = 0x1 + NFTA_SET_NAME = 0x2 + NFTA_SET_FLAGS = 0x3 + NFTA_SET_KEY_TYPE = 0x4 + NFTA_SET_KEY_LEN = 0x5 + NFTA_SET_DATA_TYPE = 0x6 + NFTA_SET_DATA_LEN = 0x7 + NFTA_SET_POLICY = 0x8 + NFTA_SET_DESC = 0x9 + NFTA_SET_ID = 0xa + NFTA_SET_TIMEOUT = 0xb + NFTA_SET_GC_INTERVAL = 0xc + NFTA_SET_USERDATA = 0xd + NFTA_SET_PAD = 0xe + NFTA_SET_OBJ_TYPE = 0xf + NFT_SET_ELEM_INTERVAL_END = 0x1 + NFTA_SET_ELEM_UNSPEC = 0x0 + NFTA_SET_ELEM_KEY = 0x1 + NFTA_SET_ELEM_DATA = 0x2 + NFTA_SET_ELEM_FLAGS = 0x3 + NFTA_SET_ELEM_TIMEOUT = 0x4 + NFTA_SET_ELEM_EXPIRATION = 0x5 + NFTA_SET_ELEM_USERDATA = 0x6 + NFTA_SET_ELEM_EXPR = 0x7 + NFTA_SET_ELEM_PAD = 0x8 + NFTA_SET_ELEM_OBJREF = 0x9 + NFTA_SET_ELEM_LIST_UNSPEC = 0x0 + NFTA_SET_ELEM_LIST_TABLE = 0x1 + NFTA_SET_ELEM_LIST_SET = 0x2 + NFTA_SET_ELEM_LIST_ELEMENTS = 0x3 + NFTA_SET_ELEM_LIST_SET_ID = 0x4 + NFT_DATA_VALUE = 0x0 + NFT_DATA_VERDICT = 0xffffff00 + NFTA_DATA_UNSPEC = 0x0 + NFTA_DATA_VALUE = 0x1 + NFTA_DATA_VERDICT = 0x2 + NFTA_VERDICT_UNSPEC = 0x0 + NFTA_VERDICT_CODE = 0x1 + NFTA_VERDICT_CHAIN = 0x2 + NFTA_EXPR_UNSPEC = 0x0 + NFTA_EXPR_NAME = 0x1 + NFTA_EXPR_DATA = 0x2 + NFTA_IMMEDIATE_UNSPEC = 0x0 + NFTA_IMMEDIATE_DREG = 0x1 + NFTA_IMMEDIATE_DATA = 0x2 + NFTA_BITWISE_UNSPEC = 0x0 + NFTA_BITWISE_SREG = 0x1 + NFTA_BITWISE_DREG = 0x2 + NFTA_BITWISE_LEN = 0x3 + NFTA_BITWISE_MASK = 0x4 + NFTA_BITWISE_XOR = 0x5 + NFT_BYTEORDER_NTOH = 0x0 + NFT_BYTEORDER_HTON = 0x1 + NFTA_BYTEORDER_UNSPEC = 0x0 + NFTA_BYTEORDER_SREG = 0x1 + NFTA_BYTEORDER_DREG = 0x2 + NFTA_BYTEORDER_OP = 0x3 + NFTA_BYTEORDER_LEN = 0x4 + NFTA_BYTEORDER_SIZE = 0x5 + NFT_CMP_EQ = 0x0 + NFT_CMP_NEQ = 0x1 + NFT_CMP_LT = 0x2 + NFT_CMP_LTE = 0x3 + NFT_CMP_GT = 0x4 + NFT_CMP_GTE = 0x5 + NFTA_CMP_UNSPEC = 0x0 + NFTA_CMP_SREG = 0x1 + NFTA_CMP_OP = 0x2 + NFTA_CMP_DATA = 0x3 + NFT_RANGE_EQ = 0x0 + NFT_RANGE_NEQ = 0x1 + NFTA_RANGE_UNSPEC = 0x0 + NFTA_RANGE_SREG = 0x1 + NFTA_RANGE_OP = 0x2 + NFTA_RANGE_FROM_DATA = 0x3 + NFTA_RANGE_TO_DATA = 0x4 + NFT_LOOKUP_F_INV = 0x1 + NFTA_LOOKUP_UNSPEC = 0x0 + NFTA_LOOKUP_SET = 0x1 + NFTA_LOOKUP_SREG = 0x2 + NFTA_LOOKUP_DREG = 0x3 + NFTA_LOOKUP_SET_ID = 0x4 + NFTA_LOOKUP_FLAGS = 0x5 + NFT_DYNSET_OP_ADD = 0x0 + NFT_DYNSET_OP_UPDATE = 0x1 + NFT_DYNSET_F_INV = 0x1 + NFTA_DYNSET_UNSPEC = 0x0 + NFTA_DYNSET_SET_NAME = 0x1 + NFTA_DYNSET_SET_ID = 0x2 + NFTA_DYNSET_OP = 0x3 + NFTA_DYNSET_SREG_KEY = 0x4 + NFTA_DYNSET_SREG_DATA = 0x5 + NFTA_DYNSET_TIMEOUT = 0x6 + NFTA_DYNSET_EXPR = 0x7 + NFTA_DYNSET_PAD = 0x8 + NFTA_DYNSET_FLAGS = 0x9 + NFT_PAYLOAD_LL_HEADER = 0x0 + NFT_PAYLOAD_NETWORK_HEADER = 0x1 + NFT_PAYLOAD_TRANSPORT_HEADER = 0x2 + NFT_PAYLOAD_CSUM_NONE = 0x0 + NFT_PAYLOAD_CSUM_INET = 0x1 + NFT_PAYLOAD_L4CSUM_PSEUDOHDR = 0x1 + NFTA_PAYLOAD_UNSPEC = 0x0 + NFTA_PAYLOAD_DREG = 0x1 + NFTA_PAYLOAD_BASE = 0x2 + NFTA_PAYLOAD_OFFSET = 0x3 + NFTA_PAYLOAD_LEN = 0x4 + NFTA_PAYLOAD_SREG = 0x5 + NFTA_PAYLOAD_CSUM_TYPE = 0x6 + NFTA_PAYLOAD_CSUM_OFFSET = 0x7 + NFTA_PAYLOAD_CSUM_FLAGS = 0x8 + NFT_EXTHDR_F_PRESENT = 0x1 + NFT_EXTHDR_OP_IPV6 = 0x0 + NFT_EXTHDR_OP_TCPOPT = 0x1 + NFTA_EXTHDR_UNSPEC = 0x0 + NFTA_EXTHDR_DREG = 0x1 + NFTA_EXTHDR_TYPE = 0x2 + NFTA_EXTHDR_OFFSET = 0x3 + NFTA_EXTHDR_LEN = 0x4 + NFTA_EXTHDR_FLAGS = 0x5 + NFTA_EXTHDR_OP = 0x6 + NFTA_EXTHDR_SREG = 0x7 + NFT_META_LEN = 0x0 + NFT_META_PROTOCOL = 0x1 + NFT_META_PRIORITY = 0x2 + NFT_META_MARK = 0x3 + NFT_META_IIF = 0x4 + NFT_META_OIF = 0x5 + NFT_META_IIFNAME = 0x6 + NFT_META_OIFNAME = 0x7 + NFT_META_IIFTYPE = 0x8 + NFT_META_OIFTYPE = 0x9 + NFT_META_SKUID = 0xa + NFT_META_SKGID = 0xb + NFT_META_NFTRACE = 0xc + NFT_META_RTCLASSID = 0xd + NFT_META_SECMARK = 0xe + NFT_META_NFPROTO = 0xf + NFT_META_L4PROTO = 0x10 + NFT_META_BRI_IIFNAME = 0x11 + NFT_META_BRI_OIFNAME = 0x12 + NFT_META_PKTTYPE = 0x13 + NFT_META_CPU = 0x14 + NFT_META_IIFGROUP = 0x15 + NFT_META_OIFGROUP = 0x16 + NFT_META_CGROUP = 0x17 + NFT_META_PRANDOM = 0x18 + NFT_RT_CLASSID = 0x0 + NFT_RT_NEXTHOP4 = 0x1 + NFT_RT_NEXTHOP6 = 0x2 + NFT_RT_TCPMSS = 0x3 + NFT_HASH_JENKINS = 0x0 + NFT_HASH_SYM = 0x1 + NFTA_HASH_UNSPEC = 0x0 + NFTA_HASH_SREG = 0x1 + NFTA_HASH_DREG = 0x2 + NFTA_HASH_LEN = 0x3 + NFTA_HASH_MODULUS = 0x4 + NFTA_HASH_SEED = 0x5 + NFTA_HASH_OFFSET = 0x6 + NFTA_HASH_TYPE = 0x7 + NFTA_META_UNSPEC = 0x0 + NFTA_META_DREG = 0x1 + NFTA_META_KEY = 0x2 + NFTA_META_SREG = 0x3 + NFTA_RT_UNSPEC = 0x0 + NFTA_RT_DREG = 0x1 + NFTA_RT_KEY = 0x2 + NFT_CT_STATE = 0x0 + NFT_CT_DIRECTION = 0x1 + NFT_CT_STATUS = 0x2 + NFT_CT_MARK = 0x3 + NFT_CT_SECMARK = 0x4 + NFT_CT_EXPIRATION = 0x5 + NFT_CT_HELPER = 0x6 + NFT_CT_L3PROTOCOL = 0x7 + NFT_CT_SRC = 0x8 + NFT_CT_DST = 0x9 + NFT_CT_PROTOCOL = 0xa + NFT_CT_PROTO_SRC = 0xb + NFT_CT_PROTO_DST = 0xc + NFT_CT_LABELS = 0xd + NFT_CT_PKTS = 0xe + NFT_CT_BYTES = 0xf + NFT_CT_AVGPKT = 0x10 + NFT_CT_ZONE = 0x11 + NFT_CT_EVENTMASK = 0x12 + NFTA_CT_UNSPEC = 0x0 + NFTA_CT_DREG = 0x1 + NFTA_CT_KEY = 0x2 + NFTA_CT_DIRECTION = 0x3 + NFTA_CT_SREG = 0x4 + NFT_LIMIT_PKTS = 0x0 + NFT_LIMIT_PKT_BYTES = 0x1 + NFT_LIMIT_F_INV = 0x1 + NFTA_LIMIT_UNSPEC = 0x0 + NFTA_LIMIT_RATE = 0x1 + NFTA_LIMIT_UNIT = 0x2 + NFTA_LIMIT_BURST = 0x3 + NFTA_LIMIT_TYPE = 0x4 + NFTA_LIMIT_FLAGS = 0x5 + NFTA_LIMIT_PAD = 0x6 + NFTA_COUNTER_UNSPEC = 0x0 + NFTA_COUNTER_BYTES = 0x1 + NFTA_COUNTER_PACKETS = 0x2 + NFTA_COUNTER_PAD = 0x3 + NFTA_LOG_UNSPEC = 0x0 + NFTA_LOG_GROUP = 0x1 + NFTA_LOG_PREFIX = 0x2 + NFTA_LOG_SNAPLEN = 0x3 + NFTA_LOG_QTHRESHOLD = 0x4 + NFTA_LOG_LEVEL = 0x5 + NFTA_LOG_FLAGS = 0x6 + NFTA_QUEUE_UNSPEC = 0x0 + NFTA_QUEUE_NUM = 0x1 + NFTA_QUEUE_TOTAL = 0x2 + NFTA_QUEUE_FLAGS = 0x3 + NFTA_QUEUE_SREG_QNUM = 0x4 + NFT_QUOTA_F_INV = 0x1 + NFT_QUOTA_F_DEPLETED = 0x2 + NFTA_QUOTA_UNSPEC = 0x0 + NFTA_QUOTA_BYTES = 0x1 + NFTA_QUOTA_FLAGS = 0x2 + NFTA_QUOTA_PAD = 0x3 + NFTA_QUOTA_CONSUMED = 0x4 + NFT_REJECT_ICMP_UNREACH = 0x0 + NFT_REJECT_TCP_RST = 0x1 + NFT_REJECT_ICMPX_UNREACH = 0x2 + NFT_REJECT_ICMPX_NO_ROUTE = 0x0 + NFT_REJECT_ICMPX_PORT_UNREACH = 0x1 + NFT_REJECT_ICMPX_HOST_UNREACH = 0x2 + NFT_REJECT_ICMPX_ADMIN_PROHIBITED = 0x3 + NFTA_REJECT_UNSPEC = 0x0 + NFTA_REJECT_TYPE = 0x1 + NFTA_REJECT_ICMP_CODE = 0x2 + NFT_NAT_SNAT = 0x0 + NFT_NAT_DNAT = 0x1 + NFTA_NAT_UNSPEC = 0x0 + NFTA_NAT_TYPE = 0x1 + NFTA_NAT_FAMILY = 0x2 + NFTA_NAT_REG_ADDR_MIN = 0x3 + NFTA_NAT_REG_ADDR_MAX = 0x4 + NFTA_NAT_REG_PROTO_MIN = 0x5 + NFTA_NAT_REG_PROTO_MAX = 0x6 + NFTA_NAT_FLAGS = 0x7 + NFTA_MASQ_UNSPEC = 0x0 + NFTA_MASQ_FLAGS = 0x1 + NFTA_MASQ_REG_PROTO_MIN = 0x2 + NFTA_MASQ_REG_PROTO_MAX = 0x3 + NFTA_REDIR_UNSPEC = 0x0 + NFTA_REDIR_REG_PROTO_MIN = 0x1 + NFTA_REDIR_REG_PROTO_MAX = 0x2 + NFTA_REDIR_FLAGS = 0x3 + NFTA_DUP_UNSPEC = 0x0 + NFTA_DUP_SREG_ADDR = 0x1 + NFTA_DUP_SREG_DEV = 0x2 + NFTA_FWD_UNSPEC = 0x0 + NFTA_FWD_SREG_DEV = 0x1 + NFTA_OBJREF_UNSPEC = 0x0 + NFTA_OBJREF_IMM_TYPE = 0x1 + NFTA_OBJREF_IMM_NAME = 0x2 + NFTA_OBJREF_SET_SREG = 0x3 + NFTA_OBJREF_SET_NAME = 0x4 + NFTA_OBJREF_SET_ID = 0x5 + NFTA_GEN_UNSPEC = 0x0 + NFTA_GEN_ID = 0x1 + NFTA_GEN_PROC_PID = 0x2 + NFTA_GEN_PROC_NAME = 0x3 + NFTA_FIB_UNSPEC = 0x0 + NFTA_FIB_DREG = 0x1 + NFTA_FIB_RESULT = 0x2 + NFTA_FIB_FLAGS = 0x3 + NFT_FIB_RESULT_UNSPEC = 0x0 + NFT_FIB_RESULT_OIF = 0x1 + NFT_FIB_RESULT_OIFNAME = 0x2 + NFT_FIB_RESULT_ADDRTYPE = 0x3 + NFTA_FIB_F_SADDR = 0x1 + NFTA_FIB_F_DADDR = 0x2 + NFTA_FIB_F_MARK = 0x4 + NFTA_FIB_F_IIF = 0x8 + NFTA_FIB_F_OIF = 0x10 + NFTA_FIB_F_PRESENT = 0x20 + NFTA_CT_HELPER_UNSPEC = 0x0 + NFTA_CT_HELPER_NAME = 0x1 + NFTA_CT_HELPER_L3PROTO = 0x2 + NFTA_CT_HELPER_L4PROTO = 0x3 + NFTA_OBJ_UNSPEC = 0x0 + NFTA_OBJ_TABLE = 0x1 + NFTA_OBJ_NAME = 0x2 + NFTA_OBJ_TYPE = 0x3 + NFTA_OBJ_DATA = 0x4 + NFTA_OBJ_USE = 0x5 + NFTA_TRACE_UNSPEC = 0x0 + NFTA_TRACE_TABLE = 0x1 + NFTA_TRACE_CHAIN = 0x2 + NFTA_TRACE_RULE_HANDLE = 0x3 + NFTA_TRACE_TYPE = 0x4 + NFTA_TRACE_VERDICT = 0x5 + NFTA_TRACE_ID = 0x6 + NFTA_TRACE_LL_HEADER = 0x7 + NFTA_TRACE_NETWORK_HEADER = 0x8 + NFTA_TRACE_TRANSPORT_HEADER = 0x9 + NFTA_TRACE_IIF = 0xa + NFTA_TRACE_IIFTYPE = 0xb + NFTA_TRACE_OIF = 0xc + NFTA_TRACE_OIFTYPE = 0xd + NFTA_TRACE_MARK = 0xe + NFTA_TRACE_NFPROTO = 0xf + NFTA_TRACE_POLICY = 0x10 + NFTA_TRACE_PAD = 0x11 + NFT_TRACETYPE_UNSPEC = 0x0 + NFT_TRACETYPE_POLICY = 0x1 + NFT_TRACETYPE_RETURN = 0x2 + NFT_TRACETYPE_RULE = 0x3 + NFTA_NG_UNSPEC = 0x0 + NFTA_NG_DREG = 0x1 + NFTA_NG_MODULUS = 0x2 + NFTA_NG_TYPE = 0x3 + NFTA_NG_OFFSET = 0x4 + NFT_NG_INCREMENTAL = 0x0 + NFT_NG_RANDOM = 0x1 +) + +type RTCTime struct { + Sec int32 + Min int32 + Hour int32 + Mday int32 + Mon int32 + Year int32 + Wday int32 + Yday int32 + Isdst int32 +} + +type RTCWkAlrm struct { + Enabled uint8 + Pending uint8 + Time RTCTime +} + +type RTCPLLInfo struct { + Ctrl int32 + Value int32 + Max int32 + Min int32 + Posmult int32 + Negmult int32 + Clock int64 +} + +type BlkpgIoctlArg struct { + Op int32 + Flags int32 + Datalen int32 + Data *byte +} + +type BlkpgPartition struct { + Start int64 + Length int64 + Pno int32 + Devname [64]uint8 + Volname [64]uint8 + _ [4]byte +} + +const ( + BLKPG = 0x1269 + BLKPG_ADD_PARTITION = 0x1 + BLKPG_DEL_PARTITION = 0x2 + BLKPG_RESIZE_PARTITION = 0x3 +) + +const ( + NETNSA_NONE = 0x0 + NETNSA_NSID = 0x1 + NETNSA_PID = 0x2 + NETNSA_FD = 0x3 +) + +type XDPRingOffset struct { + Producer uint64 + Consumer uint64 + Desc uint64 +} + +type XDPMmapOffsets struct { + Rx XDPRingOffset + Tx XDPRingOffset + Fr XDPRingOffset + Cr XDPRingOffset +} + +type XDPUmemReg struct { + Addr uint64 + Len uint64 + Size uint32 + Headroom uint32 +} + +type XDPStatistics struct { + Rx_dropped uint64 + Rx_invalid_descs uint64 + Tx_invalid_descs uint64 +} + +type XDPDesc struct { + Addr uint64 + Len uint32 + Options uint32 +} + +const ( + NCSI_CMD_UNSPEC = 0x0 + NCSI_CMD_PKG_INFO = 0x1 + NCSI_CMD_SET_INTERFACE = 0x2 + NCSI_CMD_CLEAR_INTERFACE = 0x3 + NCSI_ATTR_UNSPEC = 0x0 + NCSI_ATTR_IFINDEX = 0x1 + NCSI_ATTR_PACKAGE_LIST = 0x2 + NCSI_ATTR_PACKAGE_ID = 0x3 + NCSI_ATTR_CHANNEL_ID = 0x4 + NCSI_PKG_ATTR_UNSPEC = 0x0 + NCSI_PKG_ATTR = 0x1 + NCSI_PKG_ATTR_ID = 0x2 + NCSI_PKG_ATTR_FORCED = 0x3 + NCSI_PKG_ATTR_CHANNEL_LIST = 0x4 + NCSI_CHANNEL_ATTR_UNSPEC = 0x0 + NCSI_CHANNEL_ATTR = 0x1 + NCSI_CHANNEL_ATTR_ID = 0x2 + NCSI_CHANNEL_ATTR_VERSION_MAJOR = 0x3 + NCSI_CHANNEL_ATTR_VERSION_MINOR = 0x4 + NCSI_CHANNEL_ATTR_VERSION_STR = 0x5 + NCSI_CHANNEL_ATTR_LINK_STATE = 0x6 + NCSI_CHANNEL_ATTR_ACTIVE = 0x7 + NCSI_CHANNEL_ATTR_FORCED = 0x8 + NCSI_CHANNEL_ATTR_VLAN_LIST = 0x9 + NCSI_CHANNEL_ATTR_VLAN_ID = 0xa +) + +type ScmTimestamping struct { + Ts [3]Timespec +} + +const ( + SOF_TIMESTAMPING_TX_HARDWARE = 0x1 + SOF_TIMESTAMPING_TX_SOFTWARE = 0x2 + SOF_TIMESTAMPING_RX_HARDWARE = 0x4 + SOF_TIMESTAMPING_RX_SOFTWARE = 0x8 + SOF_TIMESTAMPING_SOFTWARE = 0x10 + SOF_TIMESTAMPING_SYS_HARDWARE = 0x20 + SOF_TIMESTAMPING_RAW_HARDWARE = 0x40 + SOF_TIMESTAMPING_OPT_ID = 0x80 + SOF_TIMESTAMPING_TX_SCHED = 0x100 + SOF_TIMESTAMPING_TX_ACK = 0x200 + SOF_TIMESTAMPING_OPT_CMSG = 0x400 + SOF_TIMESTAMPING_OPT_TSONLY = 0x800 + SOF_TIMESTAMPING_OPT_STATS = 0x1000 + SOF_TIMESTAMPING_OPT_PKTINFO = 0x2000 + SOF_TIMESTAMPING_OPT_TX_SWHW = 0x4000 + + SOF_TIMESTAMPING_LAST = 0x4000 + SOF_TIMESTAMPING_MASK = 0x7fff + + SCM_TSTAMP_SND = 0x0 + SCM_TSTAMP_SCHED = 0x1 + SCM_TSTAMP_ACK = 0x2 +) + +type SockExtendedErr struct { + Errno uint32 + Origin uint8 + Type uint8 + Code uint8 + Pad uint8 + Info uint32 + Data uint32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go b/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go index f86d683882..ad4342156e 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go @@ -6,11 +6,11 @@ package unix const ( - sizeofPtr = 0x4 - sizeofShort = 0x2 - sizeofInt = 0x4 - sizeofLong = 0x4 - sizeofLongLong = 0x8 + SizeofPtr = 0x4 + SizeofShort = 0x2 + SizeofInt = 0x4 + SizeofLong = 0x4 + SizeofLongLong = 0x8 PathMax = 0x1000 ) @@ -52,7 +52,7 @@ type Timex struct { Errcnt int32 Stbcnt int32 Tai int32 - Pad_cgo_0 [44]byte + _ [44]byte } type Time_t int32 @@ -96,64 +96,77 @@ type Rlimit struct { type _Gid_t uint32 type Stat_t struct { - Dev uint64 - X__pad1 uint16 - Pad_cgo_0 [2]byte - X__st_ino uint32 - Mode uint32 - Nlink uint32 - Uid uint32 - Gid uint32 - Rdev uint64 - X__pad2 uint16 - Pad_cgo_1 [6]byte - Size int64 - Blksize int32 - Pad_cgo_2 [4]byte - Blocks int64 - Atim Timespec - Mtim Timespec - Ctim Timespec - Ino uint64 + Dev uint64 + _ uint16 + _ uint32 + Mode uint32 + Nlink uint32 + Uid uint32 + Gid uint32 + Rdev uint64 + _ uint16 + _ [4]byte + Size int64 + Blksize int32 + _ [4]byte + Blocks int64 + Atim Timespec + Mtim Timespec + Ctim Timespec + Ino uint64 } -type Statfs_t struct { - Type int32 - Bsize int32 - Blocks uint64 - Bfree uint64 - Bavail uint64 - Files uint64 - Ffree uint64 - Fsid Fsid - Namelen int32 - Frsize int32 - Flags int32 - Spare [4]int32 - Pad_cgo_0 [4]byte +type StatxTimestamp struct { + Sec int64 + Nsec uint32 + _ int32 +} + +type Statx_t struct { + Mask uint32 + Blksize uint32 + Attributes uint64 + Nlink uint32 + Uid uint32 + Gid uint32 + Mode uint16 + _ [1]uint16 + Ino uint64 + Size uint64 + Blocks uint64 + Attributes_mask uint64 + Atime StatxTimestamp + Btime StatxTimestamp + Ctime StatxTimestamp + Mtime StatxTimestamp + Rdev_major uint32 + Rdev_minor uint32 + Dev_major uint32 + Dev_minor uint32 + _ [14]uint64 } type Dirent struct { - Ino uint64 - Off int64 - Reclen uint16 - Type uint8 - Name [256]uint8 - Pad_cgo_0 [5]byte + Ino uint64 + Off int64 + Reclen uint16 + Type uint8 + Name [256]uint8 + _ [5]byte } type Fsid struct { - X__val [2]int32 + Val [2]int32 } type Flock_t struct { - Type int16 - Whence int16 - Pad_cgo_0 [4]byte - Start int64 - Len int64 - Pid int32 - Pad_cgo_1 [4]byte + Type int16 + Whence int16 + _ [4]byte + Start int64 + Len int64 + Pid int32 + _ [4]byte } type FscryptPolicy struct { @@ -228,11 +241,26 @@ type RawSockaddrHCI struct { Channel uint16 } +type RawSockaddrL2 struct { + Family uint16 + Psm uint16 + Bdaddr [6]uint8 + Cid uint16 + Bdaddr_type uint8 + _ [1]byte +} + +type RawSockaddrRFCOMM struct { + Family uint16 + Bdaddr [6]uint8 + Channel uint8 + _ [1]byte +} + type RawSockaddrCAN struct { - Family uint16 - Pad_cgo_0 [2]byte - Ifindex int32 - Addr [8]byte + Family uint16 + Ifindex int32 + Addr [8]byte } type RawSockaddrALG struct { @@ -251,6 +279,16 @@ type RawSockaddrVM struct { Zero [4]uint8 } +type RawSockaddrXDP struct { + Family uint16 + Flags uint16 + Ifindex uint32 + Queue_id uint32 + Shared_umem_fd uint32 +} + +type RawSockaddrPPPoX [0x1e]byte + type RawSockaddr struct { Family uint16 Data [14]uint8 @@ -345,7 +383,6 @@ type TCPInfo struct { Probes uint8 Backoff uint8 Options uint8 - Pad_cgo_0 [2]byte Rto uint32 Ato uint32 Snd_mss uint32 @@ -380,9 +417,13 @@ const ( SizeofSockaddrLinklayer = 0x14 SizeofSockaddrNetlink = 0xc SizeofSockaddrHCI = 0x6 + SizeofSockaddrL2 = 0xe + SizeofSockaddrRFCOMM = 0xa SizeofSockaddrCAN = 0x10 SizeofSockaddrALG = 0x58 SizeofSockaddrVM = 0x10 + SizeofSockaddrXDP = 0x10 + SizeofSockaddrPPPoX = 0x1e SizeofLinger = 0x8 SizeofIovec = 0x8 SizeofIPMreq = 0x8 @@ -400,97 +441,138 @@ const ( ) const ( - IFA_UNSPEC = 0x0 - IFA_ADDRESS = 0x1 - IFA_LOCAL = 0x2 - IFA_LABEL = 0x3 - IFA_BROADCAST = 0x4 - IFA_ANYCAST = 0x5 - IFA_CACHEINFO = 0x6 - IFA_MULTICAST = 0x7 - IFLA_UNSPEC = 0x0 - IFLA_ADDRESS = 0x1 - IFLA_BROADCAST = 0x2 - IFLA_IFNAME = 0x3 - IFLA_MTU = 0x4 - IFLA_LINK = 0x5 - IFLA_QDISC = 0x6 - IFLA_STATS = 0x7 - IFLA_COST = 0x8 - IFLA_PRIORITY = 0x9 - IFLA_MASTER = 0xa - IFLA_WIRELESS = 0xb - IFLA_PROTINFO = 0xc - IFLA_TXQLEN = 0xd - IFLA_MAP = 0xe - IFLA_WEIGHT = 0xf - IFLA_OPERSTATE = 0x10 - IFLA_LINKMODE = 0x11 - IFLA_LINKINFO = 0x12 - IFLA_NET_NS_PID = 0x13 - IFLA_IFALIAS = 0x14 - IFLA_MAX = 0x2c - RT_SCOPE_UNIVERSE = 0x0 - RT_SCOPE_SITE = 0xc8 - RT_SCOPE_LINK = 0xfd - RT_SCOPE_HOST = 0xfe - RT_SCOPE_NOWHERE = 0xff - RT_TABLE_UNSPEC = 0x0 - RT_TABLE_COMPAT = 0xfc - RT_TABLE_DEFAULT = 0xfd - RT_TABLE_MAIN = 0xfe - RT_TABLE_LOCAL = 0xff - RT_TABLE_MAX = 0xffffffff - RTA_UNSPEC = 0x0 - RTA_DST = 0x1 - RTA_SRC = 0x2 - RTA_IIF = 0x3 - RTA_OIF = 0x4 - RTA_GATEWAY = 0x5 - RTA_PRIORITY = 0x6 - RTA_PREFSRC = 0x7 - RTA_METRICS = 0x8 - RTA_MULTIPATH = 0x9 - RTA_FLOW = 0xb - RTA_CACHEINFO = 0xc - RTA_TABLE = 0xf - RTN_UNSPEC = 0x0 - RTN_UNICAST = 0x1 - RTN_LOCAL = 0x2 - RTN_BROADCAST = 0x3 - RTN_ANYCAST = 0x4 - RTN_MULTICAST = 0x5 - RTN_BLACKHOLE = 0x6 - RTN_UNREACHABLE = 0x7 - RTN_PROHIBIT = 0x8 - RTN_THROW = 0x9 - RTN_NAT = 0xa - RTN_XRESOLVE = 0xb - RTNLGRP_NONE = 0x0 - RTNLGRP_LINK = 0x1 - RTNLGRP_NOTIFY = 0x2 - RTNLGRP_NEIGH = 0x3 - RTNLGRP_TC = 0x4 - RTNLGRP_IPV4_IFADDR = 0x5 - RTNLGRP_IPV4_MROUTE = 0x6 - RTNLGRP_IPV4_ROUTE = 0x7 - RTNLGRP_IPV4_RULE = 0x8 - RTNLGRP_IPV6_IFADDR = 0x9 - RTNLGRP_IPV6_MROUTE = 0xa - RTNLGRP_IPV6_ROUTE = 0xb - RTNLGRP_IPV6_IFINFO = 0xc - RTNLGRP_IPV6_PREFIX = 0x12 - RTNLGRP_IPV6_RULE = 0x13 - RTNLGRP_ND_USEROPT = 0x14 - SizeofNlMsghdr = 0x10 - SizeofNlMsgerr = 0x14 - SizeofRtGenmsg = 0x1 - SizeofNlAttr = 0x4 - SizeofRtAttr = 0x4 - SizeofIfInfomsg = 0x10 - SizeofIfAddrmsg = 0x8 - SizeofRtMsg = 0xc - SizeofRtNexthop = 0x8 + IFA_UNSPEC = 0x0 + IFA_ADDRESS = 0x1 + IFA_LOCAL = 0x2 + IFA_LABEL = 0x3 + IFA_BROADCAST = 0x4 + IFA_ANYCAST = 0x5 + IFA_CACHEINFO = 0x6 + IFA_MULTICAST = 0x7 + IFLA_UNSPEC = 0x0 + IFLA_ADDRESS = 0x1 + IFLA_BROADCAST = 0x2 + IFLA_IFNAME = 0x3 + IFLA_INFO_KIND = 0x1 + IFLA_MTU = 0x4 + IFLA_LINK = 0x5 + IFLA_QDISC = 0x6 + IFLA_STATS = 0x7 + IFLA_COST = 0x8 + IFLA_PRIORITY = 0x9 + IFLA_MASTER = 0xa + IFLA_WIRELESS = 0xb + IFLA_PROTINFO = 0xc + IFLA_TXQLEN = 0xd + IFLA_MAP = 0xe + IFLA_WEIGHT = 0xf + IFLA_OPERSTATE = 0x10 + IFLA_LINKMODE = 0x11 + IFLA_LINKINFO = 0x12 + IFLA_NET_NS_PID = 0x13 + IFLA_IFALIAS = 0x14 + IFLA_NUM_VF = 0x15 + IFLA_VFINFO_LIST = 0x16 + IFLA_STATS64 = 0x17 + IFLA_VF_PORTS = 0x18 + IFLA_PORT_SELF = 0x19 + IFLA_AF_SPEC = 0x1a + IFLA_GROUP = 0x1b + IFLA_NET_NS_FD = 0x1c + IFLA_EXT_MASK = 0x1d + IFLA_PROMISCUITY = 0x1e + IFLA_NUM_TX_QUEUES = 0x1f + IFLA_NUM_RX_QUEUES = 0x20 + IFLA_CARRIER = 0x21 + IFLA_PHYS_PORT_ID = 0x22 + IFLA_CARRIER_CHANGES = 0x23 + IFLA_PHYS_SWITCH_ID = 0x24 + IFLA_LINK_NETNSID = 0x25 + IFLA_PHYS_PORT_NAME = 0x26 + IFLA_PROTO_DOWN = 0x27 + IFLA_GSO_MAX_SEGS = 0x28 + IFLA_GSO_MAX_SIZE = 0x29 + IFLA_PAD = 0x2a + IFLA_XDP = 0x2b + IFLA_EVENT = 0x2c + IFLA_NEW_NETNSID = 0x2d + IFLA_IF_NETNSID = 0x2e + IFLA_MAX = 0x33 + RT_SCOPE_UNIVERSE = 0x0 + RT_SCOPE_SITE = 0xc8 + RT_SCOPE_LINK = 0xfd + RT_SCOPE_HOST = 0xfe + RT_SCOPE_NOWHERE = 0xff + RT_TABLE_UNSPEC = 0x0 + RT_TABLE_COMPAT = 0xfc + RT_TABLE_DEFAULT = 0xfd + RT_TABLE_MAIN = 0xfe + RT_TABLE_LOCAL = 0xff + RT_TABLE_MAX = 0xffffffff + RTA_UNSPEC = 0x0 + RTA_DST = 0x1 + RTA_SRC = 0x2 + RTA_IIF = 0x3 + RTA_OIF = 0x4 + RTA_GATEWAY = 0x5 + RTA_PRIORITY = 0x6 + RTA_PREFSRC = 0x7 + RTA_METRICS = 0x8 + RTA_MULTIPATH = 0x9 + RTA_FLOW = 0xb + RTA_CACHEINFO = 0xc + RTA_TABLE = 0xf + RTA_MARK = 0x10 + RTA_MFC_STATS = 0x11 + RTA_VIA = 0x12 + RTA_NEWDST = 0x13 + RTA_PREF = 0x14 + RTA_ENCAP_TYPE = 0x15 + RTA_ENCAP = 0x16 + RTA_EXPIRES = 0x17 + RTA_PAD = 0x18 + RTA_UID = 0x19 + RTA_TTL_PROPAGATE = 0x1a + RTA_IP_PROTO = 0x1b + RTA_SPORT = 0x1c + RTA_DPORT = 0x1d + RTN_UNSPEC = 0x0 + RTN_UNICAST = 0x1 + RTN_LOCAL = 0x2 + RTN_BROADCAST = 0x3 + RTN_ANYCAST = 0x4 + RTN_MULTICAST = 0x5 + RTN_BLACKHOLE = 0x6 + RTN_UNREACHABLE = 0x7 + RTN_PROHIBIT = 0x8 + RTN_THROW = 0x9 + RTN_NAT = 0xa + RTN_XRESOLVE = 0xb + RTNLGRP_NONE = 0x0 + RTNLGRP_LINK = 0x1 + RTNLGRP_NOTIFY = 0x2 + RTNLGRP_NEIGH = 0x3 + RTNLGRP_TC = 0x4 + RTNLGRP_IPV4_IFADDR = 0x5 + RTNLGRP_IPV4_MROUTE = 0x6 + RTNLGRP_IPV4_ROUTE = 0x7 + RTNLGRP_IPV4_RULE = 0x8 + RTNLGRP_IPV6_IFADDR = 0x9 + RTNLGRP_IPV6_MROUTE = 0xa + RTNLGRP_IPV6_ROUTE = 0xb + RTNLGRP_IPV6_IFINFO = 0xc + RTNLGRP_IPV6_PREFIX = 0x12 + RTNLGRP_IPV6_RULE = 0x13 + RTNLGRP_ND_USEROPT = 0x14 + SizeofNlMsghdr = 0x10 + SizeofNlMsgerr = 0x14 + SizeofRtGenmsg = 0x1 + SizeofNlAttr = 0x4 + SizeofRtAttr = 0x4 + SizeofIfInfomsg = 0x10 + SizeofIfAddrmsg = 0x8 + SizeofRtMsg = 0xc + SizeofRtNexthop = 0x8 ) type NlMsghdr struct { @@ -521,12 +603,12 @@ type RtAttr struct { } type IfInfomsg struct { - Family uint8 - X__ifi_pad uint8 - Type uint16 - Index int32 - Flags uint32 - Change uint32 + Family uint8 + _ uint8 + Type uint16 + Index int32 + Flags uint32 + Change uint32 } type IfAddrmsg struct { @@ -569,9 +651,8 @@ type SockFilter struct { } type SockFprog struct { - Len uint16 - Pad_cgo_0 [2]byte - Filter *SockFilter + Len uint16 + Filter *SockFilter } type InotifyEvent struct { @@ -605,7 +686,7 @@ type Sysinfo_t struct { Totalhigh uint32 Freehigh uint32 Unit uint32 - X_f [8]uint8 + _ [8]uint8 } type Utsname struct { @@ -632,10 +713,19 @@ type EpollEvent struct { } const ( - AT_FDCWD = -0x64 - AT_REMOVEDIR = 0x200 + AT_EMPTY_PATH = 0x1000 + AT_FDCWD = -0x64 + AT_NO_AUTOMOUNT = 0x800 + AT_REMOVEDIR = 0x200 + + AT_STATX_SYNC_AS_STAT = 0x0 + AT_STATX_FORCE_SYNC = 0x2000 + AT_STATX_DONT_SYNC = 0x4000 + AT_SYMLINK_FOLLOW = 0x400 AT_SYMLINK_NOFOLLOW = 0x100 + + AT_EACCESS = 0x200 ) type PollFd struct { @@ -655,10 +745,33 @@ const ( ) type Sigset_t struct { - X__val [32]uint32 + Val [32]uint32 } -const RNDGETENTCNT = 0x80045200 +type SignalfdSiginfo struct { + Signo uint32 + Errno int32 + Code int32 + Pid uint32 + Uid uint32 + Fd int32 + Tid uint32 + Band uint32 + Overrun uint32 + Trapno uint32 + Status int32 + Int int32 + Ptr uint64 + Utime uint64 + Stime uint64 + Addr uint64 + Addr_lsb uint16 + _ uint16 + Syscall int32 + Call_addr uint64 + Arch uint32 + _ [28]uint8 +} const PERF_IOC_FLAG_GROUP = 0x1 @@ -682,11 +795,10 @@ type Winsize struct { type Taskstats struct { Version uint16 - Pad_cgo_0 [2]byte Ac_exitcode uint32 Ac_flag uint8 Ac_nice uint8 - Pad_cgo_1 [6]byte + _ [4]byte Cpu_count uint64 Cpu_delay_total uint64 Blkio_count uint64 @@ -698,13 +810,13 @@ type Taskstats struct { Ac_comm [32]uint8 Ac_sched uint8 Ac_pad [3]uint8 - Pad_cgo_2 [4]byte + _ [4]byte Ac_uid uint32 Ac_gid uint32 Ac_pid uint32 Ac_ppid uint32 Ac_btime uint32 - Pad_cgo_3 [4]byte + _ [4]byte Ac_etime uint64 Ac_utime uint64 Ac_stime uint64 @@ -728,6 +840,8 @@ type Taskstats struct { Cpu_scaled_run_real_total uint64 Freepages_count uint64 Freepages_delay_total uint64 + Thrashing_count uint64 + Thrashing_delay_total uint64 } const ( @@ -748,6 +862,24 @@ const ( TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK = 0x4 ) +type CGroupStats struct { + Sleeping uint64 + Running uint64 + Stopped uint64 + Uninterruptible uint64 + Io_wait uint64 +} + +const ( + CGROUPSTATS_CMD_UNSPEC = 0x3 + CGROUPSTATS_CMD_GET = 0x4 + CGROUPSTATS_CMD_NEW = 0x5 + CGROUPSTATS_TYPE_UNSPEC = 0x0 + CGROUPSTATS_TYPE_CGROUP_STATS = 0x1 + CGROUPSTATS_CMD_ATTR_UNSPEC = 0x0 + CGROUPSTATS_CMD_ATTR_FD = 0x1 +) + type Genlmsghdr struct { Cmd uint8 Version uint8 @@ -780,3 +912,1107 @@ const ( CTRL_ATTR_MCAST_GRP_NAME = 0x1 CTRL_ATTR_MCAST_GRP_ID = 0x2 ) + +type cpuMask uint32 + +const ( + _CPU_SETSIZE = 0x400 + _NCPUBITS = 0x20 +) + +const ( + BDADDR_BREDR = 0x0 + BDADDR_LE_PUBLIC = 0x1 + BDADDR_LE_RANDOM = 0x2 +) + +type PerfEventAttr struct { + Type uint32 + Size uint32 + Config uint64 + Sample uint64 + Sample_type uint64 + Read_format uint64 + Bits uint64 + Wakeup uint32 + Bp_type uint32 + Ext1 uint64 + Ext2 uint64 + Branch_sample_type uint64 + Sample_regs_user uint64 + Sample_stack_user uint32 + Clockid int32 + Sample_regs_intr uint64 + Aux_watermark uint32 + _ uint32 +} + +type PerfEventMmapPage struct { + Version uint32 + Compat_version uint32 + Lock uint32 + Index uint32 + Offset int64 + Time_enabled uint64 + Time_running uint64 + Capabilities uint64 + Pmc_width uint16 + Time_shift uint16 + Time_mult uint32 + Time_offset uint64 + Time_zero uint64 + Size uint32 + _ [948]uint8 + Data_head uint64 + Data_tail uint64 + Data_offset uint64 + Data_size uint64 + Aux_head uint64 + Aux_tail uint64 + Aux_offset uint64 + Aux_size uint64 +} + +const ( + PerfBitDisabled uint64 = CBitFieldMaskBit0 + PerfBitInherit = CBitFieldMaskBit1 + PerfBitPinned = CBitFieldMaskBit2 + PerfBitExclusive = CBitFieldMaskBit3 + PerfBitExcludeUser = CBitFieldMaskBit4 + PerfBitExcludeKernel = CBitFieldMaskBit5 + PerfBitExcludeHv = CBitFieldMaskBit6 + PerfBitExcludeIdle = CBitFieldMaskBit7 + PerfBitMmap = CBitFieldMaskBit8 + PerfBitComm = CBitFieldMaskBit9 + PerfBitFreq = CBitFieldMaskBit10 + PerfBitInheritStat = CBitFieldMaskBit11 + PerfBitEnableOnExec = CBitFieldMaskBit12 + PerfBitTask = CBitFieldMaskBit13 + PerfBitWatermark = CBitFieldMaskBit14 + PerfBitPreciseIPBit1 = CBitFieldMaskBit15 + PerfBitPreciseIPBit2 = CBitFieldMaskBit16 + PerfBitMmapData = CBitFieldMaskBit17 + PerfBitSampleIDAll = CBitFieldMaskBit18 + PerfBitExcludeHost = CBitFieldMaskBit19 + PerfBitExcludeGuest = CBitFieldMaskBit20 + PerfBitExcludeCallchainKernel = CBitFieldMaskBit21 + PerfBitExcludeCallchainUser = CBitFieldMaskBit22 + PerfBitMmap2 = CBitFieldMaskBit23 + PerfBitCommExec = CBitFieldMaskBit24 + PerfBitUseClockID = CBitFieldMaskBit25 + PerfBitContextSwitch = CBitFieldMaskBit26 +) + +const ( + PERF_TYPE_HARDWARE = 0x0 + PERF_TYPE_SOFTWARE = 0x1 + PERF_TYPE_TRACEPOINT = 0x2 + PERF_TYPE_HW_CACHE = 0x3 + PERF_TYPE_RAW = 0x4 + PERF_TYPE_BREAKPOINT = 0x5 + + PERF_COUNT_HW_CPU_CYCLES = 0x0 + PERF_COUNT_HW_INSTRUCTIONS = 0x1 + PERF_COUNT_HW_CACHE_REFERENCES = 0x2 + PERF_COUNT_HW_CACHE_MISSES = 0x3 + PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 0x4 + PERF_COUNT_HW_BRANCH_MISSES = 0x5 + PERF_COUNT_HW_BUS_CYCLES = 0x6 + PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 0x7 + PERF_COUNT_HW_STALLED_CYCLES_BACKEND = 0x8 + PERF_COUNT_HW_REF_CPU_CYCLES = 0x9 + + PERF_COUNT_HW_CACHE_L1D = 0x0 + PERF_COUNT_HW_CACHE_L1I = 0x1 + PERF_COUNT_HW_CACHE_LL = 0x2 + PERF_COUNT_HW_CACHE_DTLB = 0x3 + PERF_COUNT_HW_CACHE_ITLB = 0x4 + PERF_COUNT_HW_CACHE_BPU = 0x5 + PERF_COUNT_HW_CACHE_NODE = 0x6 + + PERF_COUNT_HW_CACHE_OP_READ = 0x0 + PERF_COUNT_HW_CACHE_OP_WRITE = 0x1 + PERF_COUNT_HW_CACHE_OP_PREFETCH = 0x2 + + PERF_COUNT_HW_CACHE_RESULT_ACCESS = 0x0 + PERF_COUNT_HW_CACHE_RESULT_MISS = 0x1 + + PERF_COUNT_SW_CPU_CLOCK = 0x0 + PERF_COUNT_SW_TASK_CLOCK = 0x1 + PERF_COUNT_SW_PAGE_FAULTS = 0x2 + PERF_COUNT_SW_CONTEXT_SWITCHES = 0x3 + PERF_COUNT_SW_CPU_MIGRATIONS = 0x4 + PERF_COUNT_SW_PAGE_FAULTS_MIN = 0x5 + PERF_COUNT_SW_PAGE_FAULTS_MAJ = 0x6 + PERF_COUNT_SW_ALIGNMENT_FAULTS = 0x7 + PERF_COUNT_SW_EMULATION_FAULTS = 0x8 + PERF_COUNT_SW_DUMMY = 0x9 + + PERF_SAMPLE_IP = 0x1 + PERF_SAMPLE_TID = 0x2 + PERF_SAMPLE_TIME = 0x4 + PERF_SAMPLE_ADDR = 0x8 + PERF_SAMPLE_READ = 0x10 + PERF_SAMPLE_CALLCHAIN = 0x20 + PERF_SAMPLE_ID = 0x40 + PERF_SAMPLE_CPU = 0x80 + PERF_SAMPLE_PERIOD = 0x100 + PERF_SAMPLE_STREAM_ID = 0x200 + PERF_SAMPLE_RAW = 0x400 + PERF_SAMPLE_BRANCH_STACK = 0x800 + + PERF_SAMPLE_BRANCH_USER = 0x1 + PERF_SAMPLE_BRANCH_KERNEL = 0x2 + PERF_SAMPLE_BRANCH_HV = 0x4 + PERF_SAMPLE_BRANCH_ANY = 0x8 + PERF_SAMPLE_BRANCH_ANY_CALL = 0x10 + PERF_SAMPLE_BRANCH_ANY_RETURN = 0x20 + PERF_SAMPLE_BRANCH_IND_CALL = 0x40 + + PERF_FORMAT_TOTAL_TIME_ENABLED = 0x1 + PERF_FORMAT_TOTAL_TIME_RUNNING = 0x2 + PERF_FORMAT_ID = 0x4 + PERF_FORMAT_GROUP = 0x8 + + PERF_RECORD_MMAP = 0x1 + PERF_RECORD_LOST = 0x2 + PERF_RECORD_COMM = 0x3 + PERF_RECORD_EXIT = 0x4 + PERF_RECORD_THROTTLE = 0x5 + PERF_RECORD_UNTHROTTLE = 0x6 + PERF_RECORD_FORK = 0x7 + PERF_RECORD_READ = 0x8 + PERF_RECORD_SAMPLE = 0x9 + + PERF_CONTEXT_HV = -0x20 + PERF_CONTEXT_KERNEL = -0x80 + PERF_CONTEXT_USER = -0x200 + + PERF_CONTEXT_GUEST = -0x800 + PERF_CONTEXT_GUEST_KERNEL = -0x880 + PERF_CONTEXT_GUEST_USER = -0xa00 + + PERF_FLAG_FD_NO_GROUP = 0x1 + PERF_FLAG_FD_OUTPUT = 0x2 + PERF_FLAG_PID_CGROUP = 0x4 +) + +const ( + CBitFieldMaskBit0 = 0x1 + CBitFieldMaskBit1 = 0x2 + CBitFieldMaskBit2 = 0x4 + CBitFieldMaskBit3 = 0x8 + CBitFieldMaskBit4 = 0x10 + CBitFieldMaskBit5 = 0x20 + CBitFieldMaskBit6 = 0x40 + CBitFieldMaskBit7 = 0x80 + CBitFieldMaskBit8 = 0x100 + CBitFieldMaskBit9 = 0x200 + CBitFieldMaskBit10 = 0x400 + CBitFieldMaskBit11 = 0x800 + CBitFieldMaskBit12 = 0x1000 + CBitFieldMaskBit13 = 0x2000 + CBitFieldMaskBit14 = 0x4000 + CBitFieldMaskBit15 = 0x8000 + CBitFieldMaskBit16 = 0x10000 + CBitFieldMaskBit17 = 0x20000 + CBitFieldMaskBit18 = 0x40000 + CBitFieldMaskBit19 = 0x80000 + CBitFieldMaskBit20 = 0x100000 + CBitFieldMaskBit21 = 0x200000 + CBitFieldMaskBit22 = 0x400000 + CBitFieldMaskBit23 = 0x800000 + CBitFieldMaskBit24 = 0x1000000 + CBitFieldMaskBit25 = 0x2000000 + CBitFieldMaskBit26 = 0x4000000 + CBitFieldMaskBit27 = 0x8000000 + CBitFieldMaskBit28 = 0x10000000 + CBitFieldMaskBit29 = 0x20000000 + CBitFieldMaskBit30 = 0x40000000 + CBitFieldMaskBit31 = 0x80000000 + CBitFieldMaskBit32 = 0x100000000 + CBitFieldMaskBit33 = 0x200000000 + CBitFieldMaskBit34 = 0x400000000 + CBitFieldMaskBit35 = 0x800000000 + CBitFieldMaskBit36 = 0x1000000000 + CBitFieldMaskBit37 = 0x2000000000 + CBitFieldMaskBit38 = 0x4000000000 + CBitFieldMaskBit39 = 0x8000000000 + CBitFieldMaskBit40 = 0x10000000000 + CBitFieldMaskBit41 = 0x20000000000 + CBitFieldMaskBit42 = 0x40000000000 + CBitFieldMaskBit43 = 0x80000000000 + CBitFieldMaskBit44 = 0x100000000000 + CBitFieldMaskBit45 = 0x200000000000 + CBitFieldMaskBit46 = 0x400000000000 + CBitFieldMaskBit47 = 0x800000000000 + CBitFieldMaskBit48 = 0x1000000000000 + CBitFieldMaskBit49 = 0x2000000000000 + CBitFieldMaskBit50 = 0x4000000000000 + CBitFieldMaskBit51 = 0x8000000000000 + CBitFieldMaskBit52 = 0x10000000000000 + CBitFieldMaskBit53 = 0x20000000000000 + CBitFieldMaskBit54 = 0x40000000000000 + CBitFieldMaskBit55 = 0x80000000000000 + CBitFieldMaskBit56 = 0x100000000000000 + CBitFieldMaskBit57 = 0x200000000000000 + CBitFieldMaskBit58 = 0x400000000000000 + CBitFieldMaskBit59 = 0x800000000000000 + CBitFieldMaskBit60 = 0x1000000000000000 + CBitFieldMaskBit61 = 0x2000000000000000 + CBitFieldMaskBit62 = 0x4000000000000000 + CBitFieldMaskBit63 = 0x8000000000000000 +) + +type SockaddrStorage struct { + Family uint16 + _ [122]uint8 + _ uint32 +} + +type TCPMD5Sig struct { + Addr SockaddrStorage + Flags uint8 + Prefixlen uint8 + Keylen uint16 + _ uint32 + Key [80]uint8 +} + +type HDDriveCmdHdr struct { + Command uint8 + Number uint8 + Feature uint8 + Count uint8 +} + +type HDGeometry struct { + Heads uint8 + Sectors uint8 + Cylinders uint16 + Start uint32 +} + +type HDDriveID struct { + Config uint16 + Cyls uint16 + Reserved2 uint16 + Heads uint16 + Track_bytes uint16 + Sector_bytes uint16 + Sectors uint16 + Vendor0 uint16 + Vendor1 uint16 + Vendor2 uint16 + Serial_no [20]uint8 + Buf_type uint16 + Buf_size uint16 + Ecc_bytes uint16 + Fw_rev [8]uint8 + Model [40]uint8 + Max_multsect uint8 + Vendor3 uint8 + Dword_io uint16 + Vendor4 uint8 + Capability uint8 + Reserved50 uint16 + Vendor5 uint8 + TPIO uint8 + Vendor6 uint8 + TDMA uint8 + Field_valid uint16 + Cur_cyls uint16 + Cur_heads uint16 + Cur_sectors uint16 + Cur_capacity0 uint16 + Cur_capacity1 uint16 + Multsect uint8 + Multsect_valid uint8 + Lba_capacity uint32 + Dma_1word uint16 + Dma_mword uint16 + Eide_pio_modes uint16 + Eide_dma_min uint16 + Eide_dma_time uint16 + Eide_pio uint16 + Eide_pio_iordy uint16 + Words69_70 [2]uint16 + Words71_74 [4]uint16 + Queue_depth uint16 + Words76_79 [4]uint16 + Major_rev_num uint16 + Minor_rev_num uint16 + Command_set_1 uint16 + Command_set_2 uint16 + Cfsse uint16 + Cfs_enable_1 uint16 + Cfs_enable_2 uint16 + Csf_default uint16 + Dma_ultra uint16 + Trseuc uint16 + TrsEuc uint16 + CurAPMvalues uint16 + Mprc uint16 + Hw_config uint16 + Acoustic uint16 + Msrqs uint16 + Sxfert uint16 + Sal uint16 + Spg uint32 + Lba_capacity_2 uint64 + Words104_125 [22]uint16 + Last_lun uint16 + Word127 uint16 + Dlf uint16 + Csfo uint16 + Words130_155 [26]uint16 + Word156 uint16 + Words157_159 [3]uint16 + Cfa_power uint16 + Words161_175 [15]uint16 + Words176_205 [30]uint16 + Words206_254 [49]uint16 + Integrity_word uint16 +} + +type Statfs_t struct { + Type int32 + Bsize int32 + Blocks uint64 + Bfree uint64 + Bavail uint64 + Files uint64 + Ffree uint64 + Fsid Fsid + Namelen int32 + Frsize int32 + Flags int32 + Spare [4]int32 + _ [4]byte +} + +const ( + ST_MANDLOCK = 0x40 + ST_NOATIME = 0x400 + ST_NODEV = 0x4 + ST_NODIRATIME = 0x800 + ST_NOEXEC = 0x8 + ST_NOSUID = 0x2 + ST_RDONLY = 0x1 + ST_RELATIME = 0x1000 + ST_SYNCHRONOUS = 0x10 +) + +type TpacketHdr struct { + Status uint32 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Sec uint32 + Usec uint32 +} + +type Tpacket2Hdr struct { + Status uint32 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Sec uint32 + Nsec uint32 + Vlan_tci uint16 + Vlan_tpid uint16 + _ [4]uint8 +} + +type Tpacket3Hdr struct { + Next_offset uint32 + Sec uint32 + Nsec uint32 + Snaplen uint32 + Len uint32 + Status uint32 + Mac uint16 + Net uint16 + Hv1 TpacketHdrVariant1 + _ [8]uint8 +} + +type TpacketHdrVariant1 struct { + Rxhash uint32 + Vlan_tci uint32 + Vlan_tpid uint16 + _ uint16 +} + +type TpacketBlockDesc struct { + Version uint32 + To_priv uint32 + Hdr [40]byte +} + +type TpacketReq struct { + Block_size uint32 + Block_nr uint32 + Frame_size uint32 + Frame_nr uint32 +} + +type TpacketReq3 struct { + Block_size uint32 + Block_nr uint32 + Frame_size uint32 + Frame_nr uint32 + Retire_blk_tov uint32 + Sizeof_priv uint32 + Feature_req_word uint32 +} + +type TpacketStats struct { + Packets uint32 + Drops uint32 +} + +type TpacketStatsV3 struct { + Packets uint32 + Drops uint32 + Freeze_q_cnt uint32 +} + +type TpacketAuxdata struct { + Status uint32 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Vlan_tci uint16 + Vlan_tpid uint16 +} + +const ( + TPACKET_V1 = 0x0 + TPACKET_V2 = 0x1 + TPACKET_V3 = 0x2 +) + +const ( + SizeofTpacketHdr = 0x18 + SizeofTpacket2Hdr = 0x20 + SizeofTpacket3Hdr = 0x30 +) + +const ( + NF_INET_PRE_ROUTING = 0x0 + NF_INET_LOCAL_IN = 0x1 + NF_INET_FORWARD = 0x2 + NF_INET_LOCAL_OUT = 0x3 + NF_INET_POST_ROUTING = 0x4 + NF_INET_NUMHOOKS = 0x5 +) + +const ( + NF_NETDEV_INGRESS = 0x0 + NF_NETDEV_NUMHOOKS = 0x1 +) + +const ( + NFPROTO_UNSPEC = 0x0 + NFPROTO_INET = 0x1 + NFPROTO_IPV4 = 0x2 + NFPROTO_ARP = 0x3 + NFPROTO_NETDEV = 0x5 + NFPROTO_BRIDGE = 0x7 + NFPROTO_IPV6 = 0xa + NFPROTO_DECNET = 0xc + NFPROTO_NUMPROTO = 0xd +) + +type Nfgenmsg struct { + Nfgen_family uint8 + Version uint8 + Res_id uint16 +} + +const ( + NFNL_BATCH_UNSPEC = 0x0 + NFNL_BATCH_GENID = 0x1 +) + +const ( + NFT_REG_VERDICT = 0x0 + NFT_REG_1 = 0x1 + NFT_REG_2 = 0x2 + NFT_REG_3 = 0x3 + NFT_REG_4 = 0x4 + NFT_REG32_00 = 0x8 + NFT_REG32_01 = 0x9 + NFT_REG32_02 = 0xa + NFT_REG32_03 = 0xb + NFT_REG32_04 = 0xc + NFT_REG32_05 = 0xd + NFT_REG32_06 = 0xe + NFT_REG32_07 = 0xf + NFT_REG32_08 = 0x10 + NFT_REG32_09 = 0x11 + NFT_REG32_10 = 0x12 + NFT_REG32_11 = 0x13 + NFT_REG32_12 = 0x14 + NFT_REG32_13 = 0x15 + NFT_REG32_14 = 0x16 + NFT_REG32_15 = 0x17 + NFT_CONTINUE = -0x1 + NFT_BREAK = -0x2 + NFT_JUMP = -0x3 + NFT_GOTO = -0x4 + NFT_RETURN = -0x5 + NFT_MSG_NEWTABLE = 0x0 + NFT_MSG_GETTABLE = 0x1 + NFT_MSG_DELTABLE = 0x2 + NFT_MSG_NEWCHAIN = 0x3 + NFT_MSG_GETCHAIN = 0x4 + NFT_MSG_DELCHAIN = 0x5 + NFT_MSG_NEWRULE = 0x6 + NFT_MSG_GETRULE = 0x7 + NFT_MSG_DELRULE = 0x8 + NFT_MSG_NEWSET = 0x9 + NFT_MSG_GETSET = 0xa + NFT_MSG_DELSET = 0xb + NFT_MSG_NEWSETELEM = 0xc + NFT_MSG_GETSETELEM = 0xd + NFT_MSG_DELSETELEM = 0xe + NFT_MSG_NEWGEN = 0xf + NFT_MSG_GETGEN = 0x10 + NFT_MSG_TRACE = 0x11 + NFT_MSG_NEWOBJ = 0x12 + NFT_MSG_GETOBJ = 0x13 + NFT_MSG_DELOBJ = 0x14 + NFT_MSG_GETOBJ_RESET = 0x15 + NFT_MSG_MAX = 0x19 + NFTA_LIST_UNPEC = 0x0 + NFTA_LIST_ELEM = 0x1 + NFTA_HOOK_UNSPEC = 0x0 + NFTA_HOOK_HOOKNUM = 0x1 + NFTA_HOOK_PRIORITY = 0x2 + NFTA_HOOK_DEV = 0x3 + NFT_TABLE_F_DORMANT = 0x1 + NFTA_TABLE_UNSPEC = 0x0 + NFTA_TABLE_NAME = 0x1 + NFTA_TABLE_FLAGS = 0x2 + NFTA_TABLE_USE = 0x3 + NFTA_CHAIN_UNSPEC = 0x0 + NFTA_CHAIN_TABLE = 0x1 + NFTA_CHAIN_HANDLE = 0x2 + NFTA_CHAIN_NAME = 0x3 + NFTA_CHAIN_HOOK = 0x4 + NFTA_CHAIN_POLICY = 0x5 + NFTA_CHAIN_USE = 0x6 + NFTA_CHAIN_TYPE = 0x7 + NFTA_CHAIN_COUNTERS = 0x8 + NFTA_CHAIN_PAD = 0x9 + NFTA_RULE_UNSPEC = 0x0 + NFTA_RULE_TABLE = 0x1 + NFTA_RULE_CHAIN = 0x2 + NFTA_RULE_HANDLE = 0x3 + NFTA_RULE_EXPRESSIONS = 0x4 + NFTA_RULE_COMPAT = 0x5 + NFTA_RULE_POSITION = 0x6 + NFTA_RULE_USERDATA = 0x7 + NFTA_RULE_PAD = 0x8 + NFTA_RULE_ID = 0x9 + NFT_RULE_COMPAT_F_INV = 0x2 + NFT_RULE_COMPAT_F_MASK = 0x2 + NFTA_RULE_COMPAT_UNSPEC = 0x0 + NFTA_RULE_COMPAT_PROTO = 0x1 + NFTA_RULE_COMPAT_FLAGS = 0x2 + NFT_SET_ANONYMOUS = 0x1 + NFT_SET_CONSTANT = 0x2 + NFT_SET_INTERVAL = 0x4 + NFT_SET_MAP = 0x8 + NFT_SET_TIMEOUT = 0x10 + NFT_SET_EVAL = 0x20 + NFT_SET_OBJECT = 0x40 + NFT_SET_POL_PERFORMANCE = 0x0 + NFT_SET_POL_MEMORY = 0x1 + NFTA_SET_DESC_UNSPEC = 0x0 + NFTA_SET_DESC_SIZE = 0x1 + NFTA_SET_UNSPEC = 0x0 + NFTA_SET_TABLE = 0x1 + NFTA_SET_NAME = 0x2 + NFTA_SET_FLAGS = 0x3 + NFTA_SET_KEY_TYPE = 0x4 + NFTA_SET_KEY_LEN = 0x5 + NFTA_SET_DATA_TYPE = 0x6 + NFTA_SET_DATA_LEN = 0x7 + NFTA_SET_POLICY = 0x8 + NFTA_SET_DESC = 0x9 + NFTA_SET_ID = 0xa + NFTA_SET_TIMEOUT = 0xb + NFTA_SET_GC_INTERVAL = 0xc + NFTA_SET_USERDATA = 0xd + NFTA_SET_PAD = 0xe + NFTA_SET_OBJ_TYPE = 0xf + NFT_SET_ELEM_INTERVAL_END = 0x1 + NFTA_SET_ELEM_UNSPEC = 0x0 + NFTA_SET_ELEM_KEY = 0x1 + NFTA_SET_ELEM_DATA = 0x2 + NFTA_SET_ELEM_FLAGS = 0x3 + NFTA_SET_ELEM_TIMEOUT = 0x4 + NFTA_SET_ELEM_EXPIRATION = 0x5 + NFTA_SET_ELEM_USERDATA = 0x6 + NFTA_SET_ELEM_EXPR = 0x7 + NFTA_SET_ELEM_PAD = 0x8 + NFTA_SET_ELEM_OBJREF = 0x9 + NFTA_SET_ELEM_LIST_UNSPEC = 0x0 + NFTA_SET_ELEM_LIST_TABLE = 0x1 + NFTA_SET_ELEM_LIST_SET = 0x2 + NFTA_SET_ELEM_LIST_ELEMENTS = 0x3 + NFTA_SET_ELEM_LIST_SET_ID = 0x4 + NFT_DATA_VALUE = 0x0 + NFT_DATA_VERDICT = 0xffffff00 + NFTA_DATA_UNSPEC = 0x0 + NFTA_DATA_VALUE = 0x1 + NFTA_DATA_VERDICT = 0x2 + NFTA_VERDICT_UNSPEC = 0x0 + NFTA_VERDICT_CODE = 0x1 + NFTA_VERDICT_CHAIN = 0x2 + NFTA_EXPR_UNSPEC = 0x0 + NFTA_EXPR_NAME = 0x1 + NFTA_EXPR_DATA = 0x2 + NFTA_IMMEDIATE_UNSPEC = 0x0 + NFTA_IMMEDIATE_DREG = 0x1 + NFTA_IMMEDIATE_DATA = 0x2 + NFTA_BITWISE_UNSPEC = 0x0 + NFTA_BITWISE_SREG = 0x1 + NFTA_BITWISE_DREG = 0x2 + NFTA_BITWISE_LEN = 0x3 + NFTA_BITWISE_MASK = 0x4 + NFTA_BITWISE_XOR = 0x5 + NFT_BYTEORDER_NTOH = 0x0 + NFT_BYTEORDER_HTON = 0x1 + NFTA_BYTEORDER_UNSPEC = 0x0 + NFTA_BYTEORDER_SREG = 0x1 + NFTA_BYTEORDER_DREG = 0x2 + NFTA_BYTEORDER_OP = 0x3 + NFTA_BYTEORDER_LEN = 0x4 + NFTA_BYTEORDER_SIZE = 0x5 + NFT_CMP_EQ = 0x0 + NFT_CMP_NEQ = 0x1 + NFT_CMP_LT = 0x2 + NFT_CMP_LTE = 0x3 + NFT_CMP_GT = 0x4 + NFT_CMP_GTE = 0x5 + NFTA_CMP_UNSPEC = 0x0 + NFTA_CMP_SREG = 0x1 + NFTA_CMP_OP = 0x2 + NFTA_CMP_DATA = 0x3 + NFT_RANGE_EQ = 0x0 + NFT_RANGE_NEQ = 0x1 + NFTA_RANGE_UNSPEC = 0x0 + NFTA_RANGE_SREG = 0x1 + NFTA_RANGE_OP = 0x2 + NFTA_RANGE_FROM_DATA = 0x3 + NFTA_RANGE_TO_DATA = 0x4 + NFT_LOOKUP_F_INV = 0x1 + NFTA_LOOKUP_UNSPEC = 0x0 + NFTA_LOOKUP_SET = 0x1 + NFTA_LOOKUP_SREG = 0x2 + NFTA_LOOKUP_DREG = 0x3 + NFTA_LOOKUP_SET_ID = 0x4 + NFTA_LOOKUP_FLAGS = 0x5 + NFT_DYNSET_OP_ADD = 0x0 + NFT_DYNSET_OP_UPDATE = 0x1 + NFT_DYNSET_F_INV = 0x1 + NFTA_DYNSET_UNSPEC = 0x0 + NFTA_DYNSET_SET_NAME = 0x1 + NFTA_DYNSET_SET_ID = 0x2 + NFTA_DYNSET_OP = 0x3 + NFTA_DYNSET_SREG_KEY = 0x4 + NFTA_DYNSET_SREG_DATA = 0x5 + NFTA_DYNSET_TIMEOUT = 0x6 + NFTA_DYNSET_EXPR = 0x7 + NFTA_DYNSET_PAD = 0x8 + NFTA_DYNSET_FLAGS = 0x9 + NFT_PAYLOAD_LL_HEADER = 0x0 + NFT_PAYLOAD_NETWORK_HEADER = 0x1 + NFT_PAYLOAD_TRANSPORT_HEADER = 0x2 + NFT_PAYLOAD_CSUM_NONE = 0x0 + NFT_PAYLOAD_CSUM_INET = 0x1 + NFT_PAYLOAD_L4CSUM_PSEUDOHDR = 0x1 + NFTA_PAYLOAD_UNSPEC = 0x0 + NFTA_PAYLOAD_DREG = 0x1 + NFTA_PAYLOAD_BASE = 0x2 + NFTA_PAYLOAD_OFFSET = 0x3 + NFTA_PAYLOAD_LEN = 0x4 + NFTA_PAYLOAD_SREG = 0x5 + NFTA_PAYLOAD_CSUM_TYPE = 0x6 + NFTA_PAYLOAD_CSUM_OFFSET = 0x7 + NFTA_PAYLOAD_CSUM_FLAGS = 0x8 + NFT_EXTHDR_F_PRESENT = 0x1 + NFT_EXTHDR_OP_IPV6 = 0x0 + NFT_EXTHDR_OP_TCPOPT = 0x1 + NFTA_EXTHDR_UNSPEC = 0x0 + NFTA_EXTHDR_DREG = 0x1 + NFTA_EXTHDR_TYPE = 0x2 + NFTA_EXTHDR_OFFSET = 0x3 + NFTA_EXTHDR_LEN = 0x4 + NFTA_EXTHDR_FLAGS = 0x5 + NFTA_EXTHDR_OP = 0x6 + NFTA_EXTHDR_SREG = 0x7 + NFT_META_LEN = 0x0 + NFT_META_PROTOCOL = 0x1 + NFT_META_PRIORITY = 0x2 + NFT_META_MARK = 0x3 + NFT_META_IIF = 0x4 + NFT_META_OIF = 0x5 + NFT_META_IIFNAME = 0x6 + NFT_META_OIFNAME = 0x7 + NFT_META_IIFTYPE = 0x8 + NFT_META_OIFTYPE = 0x9 + NFT_META_SKUID = 0xa + NFT_META_SKGID = 0xb + NFT_META_NFTRACE = 0xc + NFT_META_RTCLASSID = 0xd + NFT_META_SECMARK = 0xe + NFT_META_NFPROTO = 0xf + NFT_META_L4PROTO = 0x10 + NFT_META_BRI_IIFNAME = 0x11 + NFT_META_BRI_OIFNAME = 0x12 + NFT_META_PKTTYPE = 0x13 + NFT_META_CPU = 0x14 + NFT_META_IIFGROUP = 0x15 + NFT_META_OIFGROUP = 0x16 + NFT_META_CGROUP = 0x17 + NFT_META_PRANDOM = 0x18 + NFT_RT_CLASSID = 0x0 + NFT_RT_NEXTHOP4 = 0x1 + NFT_RT_NEXTHOP6 = 0x2 + NFT_RT_TCPMSS = 0x3 + NFT_HASH_JENKINS = 0x0 + NFT_HASH_SYM = 0x1 + NFTA_HASH_UNSPEC = 0x0 + NFTA_HASH_SREG = 0x1 + NFTA_HASH_DREG = 0x2 + NFTA_HASH_LEN = 0x3 + NFTA_HASH_MODULUS = 0x4 + NFTA_HASH_SEED = 0x5 + NFTA_HASH_OFFSET = 0x6 + NFTA_HASH_TYPE = 0x7 + NFTA_META_UNSPEC = 0x0 + NFTA_META_DREG = 0x1 + NFTA_META_KEY = 0x2 + NFTA_META_SREG = 0x3 + NFTA_RT_UNSPEC = 0x0 + NFTA_RT_DREG = 0x1 + NFTA_RT_KEY = 0x2 + NFT_CT_STATE = 0x0 + NFT_CT_DIRECTION = 0x1 + NFT_CT_STATUS = 0x2 + NFT_CT_MARK = 0x3 + NFT_CT_SECMARK = 0x4 + NFT_CT_EXPIRATION = 0x5 + NFT_CT_HELPER = 0x6 + NFT_CT_L3PROTOCOL = 0x7 + NFT_CT_SRC = 0x8 + NFT_CT_DST = 0x9 + NFT_CT_PROTOCOL = 0xa + NFT_CT_PROTO_SRC = 0xb + NFT_CT_PROTO_DST = 0xc + NFT_CT_LABELS = 0xd + NFT_CT_PKTS = 0xe + NFT_CT_BYTES = 0xf + NFT_CT_AVGPKT = 0x10 + NFT_CT_ZONE = 0x11 + NFT_CT_EVENTMASK = 0x12 + NFTA_CT_UNSPEC = 0x0 + NFTA_CT_DREG = 0x1 + NFTA_CT_KEY = 0x2 + NFTA_CT_DIRECTION = 0x3 + NFTA_CT_SREG = 0x4 + NFT_LIMIT_PKTS = 0x0 + NFT_LIMIT_PKT_BYTES = 0x1 + NFT_LIMIT_F_INV = 0x1 + NFTA_LIMIT_UNSPEC = 0x0 + NFTA_LIMIT_RATE = 0x1 + NFTA_LIMIT_UNIT = 0x2 + NFTA_LIMIT_BURST = 0x3 + NFTA_LIMIT_TYPE = 0x4 + NFTA_LIMIT_FLAGS = 0x5 + NFTA_LIMIT_PAD = 0x6 + NFTA_COUNTER_UNSPEC = 0x0 + NFTA_COUNTER_BYTES = 0x1 + NFTA_COUNTER_PACKETS = 0x2 + NFTA_COUNTER_PAD = 0x3 + NFTA_LOG_UNSPEC = 0x0 + NFTA_LOG_GROUP = 0x1 + NFTA_LOG_PREFIX = 0x2 + NFTA_LOG_SNAPLEN = 0x3 + NFTA_LOG_QTHRESHOLD = 0x4 + NFTA_LOG_LEVEL = 0x5 + NFTA_LOG_FLAGS = 0x6 + NFTA_QUEUE_UNSPEC = 0x0 + NFTA_QUEUE_NUM = 0x1 + NFTA_QUEUE_TOTAL = 0x2 + NFTA_QUEUE_FLAGS = 0x3 + NFTA_QUEUE_SREG_QNUM = 0x4 + NFT_QUOTA_F_INV = 0x1 + NFT_QUOTA_F_DEPLETED = 0x2 + NFTA_QUOTA_UNSPEC = 0x0 + NFTA_QUOTA_BYTES = 0x1 + NFTA_QUOTA_FLAGS = 0x2 + NFTA_QUOTA_PAD = 0x3 + NFTA_QUOTA_CONSUMED = 0x4 + NFT_REJECT_ICMP_UNREACH = 0x0 + NFT_REJECT_TCP_RST = 0x1 + NFT_REJECT_ICMPX_UNREACH = 0x2 + NFT_REJECT_ICMPX_NO_ROUTE = 0x0 + NFT_REJECT_ICMPX_PORT_UNREACH = 0x1 + NFT_REJECT_ICMPX_HOST_UNREACH = 0x2 + NFT_REJECT_ICMPX_ADMIN_PROHIBITED = 0x3 + NFTA_REJECT_UNSPEC = 0x0 + NFTA_REJECT_TYPE = 0x1 + NFTA_REJECT_ICMP_CODE = 0x2 + NFT_NAT_SNAT = 0x0 + NFT_NAT_DNAT = 0x1 + NFTA_NAT_UNSPEC = 0x0 + NFTA_NAT_TYPE = 0x1 + NFTA_NAT_FAMILY = 0x2 + NFTA_NAT_REG_ADDR_MIN = 0x3 + NFTA_NAT_REG_ADDR_MAX = 0x4 + NFTA_NAT_REG_PROTO_MIN = 0x5 + NFTA_NAT_REG_PROTO_MAX = 0x6 + NFTA_NAT_FLAGS = 0x7 + NFTA_MASQ_UNSPEC = 0x0 + NFTA_MASQ_FLAGS = 0x1 + NFTA_MASQ_REG_PROTO_MIN = 0x2 + NFTA_MASQ_REG_PROTO_MAX = 0x3 + NFTA_REDIR_UNSPEC = 0x0 + NFTA_REDIR_REG_PROTO_MIN = 0x1 + NFTA_REDIR_REG_PROTO_MAX = 0x2 + NFTA_REDIR_FLAGS = 0x3 + NFTA_DUP_UNSPEC = 0x0 + NFTA_DUP_SREG_ADDR = 0x1 + NFTA_DUP_SREG_DEV = 0x2 + NFTA_FWD_UNSPEC = 0x0 + NFTA_FWD_SREG_DEV = 0x1 + NFTA_OBJREF_UNSPEC = 0x0 + NFTA_OBJREF_IMM_TYPE = 0x1 + NFTA_OBJREF_IMM_NAME = 0x2 + NFTA_OBJREF_SET_SREG = 0x3 + NFTA_OBJREF_SET_NAME = 0x4 + NFTA_OBJREF_SET_ID = 0x5 + NFTA_GEN_UNSPEC = 0x0 + NFTA_GEN_ID = 0x1 + NFTA_GEN_PROC_PID = 0x2 + NFTA_GEN_PROC_NAME = 0x3 + NFTA_FIB_UNSPEC = 0x0 + NFTA_FIB_DREG = 0x1 + NFTA_FIB_RESULT = 0x2 + NFTA_FIB_FLAGS = 0x3 + NFT_FIB_RESULT_UNSPEC = 0x0 + NFT_FIB_RESULT_OIF = 0x1 + NFT_FIB_RESULT_OIFNAME = 0x2 + NFT_FIB_RESULT_ADDRTYPE = 0x3 + NFTA_FIB_F_SADDR = 0x1 + NFTA_FIB_F_DADDR = 0x2 + NFTA_FIB_F_MARK = 0x4 + NFTA_FIB_F_IIF = 0x8 + NFTA_FIB_F_OIF = 0x10 + NFTA_FIB_F_PRESENT = 0x20 + NFTA_CT_HELPER_UNSPEC = 0x0 + NFTA_CT_HELPER_NAME = 0x1 + NFTA_CT_HELPER_L3PROTO = 0x2 + NFTA_CT_HELPER_L4PROTO = 0x3 + NFTA_OBJ_UNSPEC = 0x0 + NFTA_OBJ_TABLE = 0x1 + NFTA_OBJ_NAME = 0x2 + NFTA_OBJ_TYPE = 0x3 + NFTA_OBJ_DATA = 0x4 + NFTA_OBJ_USE = 0x5 + NFTA_TRACE_UNSPEC = 0x0 + NFTA_TRACE_TABLE = 0x1 + NFTA_TRACE_CHAIN = 0x2 + NFTA_TRACE_RULE_HANDLE = 0x3 + NFTA_TRACE_TYPE = 0x4 + NFTA_TRACE_VERDICT = 0x5 + NFTA_TRACE_ID = 0x6 + NFTA_TRACE_LL_HEADER = 0x7 + NFTA_TRACE_NETWORK_HEADER = 0x8 + NFTA_TRACE_TRANSPORT_HEADER = 0x9 + NFTA_TRACE_IIF = 0xa + NFTA_TRACE_IIFTYPE = 0xb + NFTA_TRACE_OIF = 0xc + NFTA_TRACE_OIFTYPE = 0xd + NFTA_TRACE_MARK = 0xe + NFTA_TRACE_NFPROTO = 0xf + NFTA_TRACE_POLICY = 0x10 + NFTA_TRACE_PAD = 0x11 + NFT_TRACETYPE_UNSPEC = 0x0 + NFT_TRACETYPE_POLICY = 0x1 + NFT_TRACETYPE_RETURN = 0x2 + NFT_TRACETYPE_RULE = 0x3 + NFTA_NG_UNSPEC = 0x0 + NFTA_NG_DREG = 0x1 + NFTA_NG_MODULUS = 0x2 + NFTA_NG_TYPE = 0x3 + NFTA_NG_OFFSET = 0x4 + NFT_NG_INCREMENTAL = 0x0 + NFT_NG_RANDOM = 0x1 +) + +type RTCTime struct { + Sec int32 + Min int32 + Hour int32 + Mday int32 + Mon int32 + Year int32 + Wday int32 + Yday int32 + Isdst int32 +} + +type RTCWkAlrm struct { + Enabled uint8 + Pending uint8 + Time RTCTime +} + +type RTCPLLInfo struct { + Ctrl int32 + Value int32 + Max int32 + Min int32 + Posmult int32 + Negmult int32 + Clock int32 +} + +type BlkpgIoctlArg struct { + Op int32 + Flags int32 + Datalen int32 + Data *byte +} + +type BlkpgPartition struct { + Start int64 + Length int64 + Pno int32 + Devname [64]uint8 + Volname [64]uint8 + _ [4]byte +} + +const ( + BLKPG = 0x1269 + BLKPG_ADD_PARTITION = 0x1 + BLKPG_DEL_PARTITION = 0x2 + BLKPG_RESIZE_PARTITION = 0x3 +) + +const ( + NETNSA_NONE = 0x0 + NETNSA_NSID = 0x1 + NETNSA_PID = 0x2 + NETNSA_FD = 0x3 +) + +type XDPRingOffset struct { + Producer uint64 + Consumer uint64 + Desc uint64 +} + +type XDPMmapOffsets struct { + Rx XDPRingOffset + Tx XDPRingOffset + Fr XDPRingOffset + Cr XDPRingOffset +} + +type XDPUmemReg struct { + Addr uint64 + Len uint64 + Size uint32 + Headroom uint32 +} + +type XDPStatistics struct { + Rx_dropped uint64 + Rx_invalid_descs uint64 + Tx_invalid_descs uint64 +} + +type XDPDesc struct { + Addr uint64 + Len uint32 + Options uint32 +} + +const ( + NCSI_CMD_UNSPEC = 0x0 + NCSI_CMD_PKG_INFO = 0x1 + NCSI_CMD_SET_INTERFACE = 0x2 + NCSI_CMD_CLEAR_INTERFACE = 0x3 + NCSI_ATTR_UNSPEC = 0x0 + NCSI_ATTR_IFINDEX = 0x1 + NCSI_ATTR_PACKAGE_LIST = 0x2 + NCSI_ATTR_PACKAGE_ID = 0x3 + NCSI_ATTR_CHANNEL_ID = 0x4 + NCSI_PKG_ATTR_UNSPEC = 0x0 + NCSI_PKG_ATTR = 0x1 + NCSI_PKG_ATTR_ID = 0x2 + NCSI_PKG_ATTR_FORCED = 0x3 + NCSI_PKG_ATTR_CHANNEL_LIST = 0x4 + NCSI_CHANNEL_ATTR_UNSPEC = 0x0 + NCSI_CHANNEL_ATTR = 0x1 + NCSI_CHANNEL_ATTR_ID = 0x2 + NCSI_CHANNEL_ATTR_VERSION_MAJOR = 0x3 + NCSI_CHANNEL_ATTR_VERSION_MINOR = 0x4 + NCSI_CHANNEL_ATTR_VERSION_STR = 0x5 + NCSI_CHANNEL_ATTR_LINK_STATE = 0x6 + NCSI_CHANNEL_ATTR_ACTIVE = 0x7 + NCSI_CHANNEL_ATTR_FORCED = 0x8 + NCSI_CHANNEL_ATTR_VLAN_LIST = 0x9 + NCSI_CHANNEL_ATTR_VLAN_ID = 0xa +) + +type ScmTimestamping struct { + Ts [3]Timespec +} + +const ( + SOF_TIMESTAMPING_TX_HARDWARE = 0x1 + SOF_TIMESTAMPING_TX_SOFTWARE = 0x2 + SOF_TIMESTAMPING_RX_HARDWARE = 0x4 + SOF_TIMESTAMPING_RX_SOFTWARE = 0x8 + SOF_TIMESTAMPING_SOFTWARE = 0x10 + SOF_TIMESTAMPING_SYS_HARDWARE = 0x20 + SOF_TIMESTAMPING_RAW_HARDWARE = 0x40 + SOF_TIMESTAMPING_OPT_ID = 0x80 + SOF_TIMESTAMPING_TX_SCHED = 0x100 + SOF_TIMESTAMPING_TX_ACK = 0x200 + SOF_TIMESTAMPING_OPT_CMSG = 0x400 + SOF_TIMESTAMPING_OPT_TSONLY = 0x800 + SOF_TIMESTAMPING_OPT_STATS = 0x1000 + SOF_TIMESTAMPING_OPT_PKTINFO = 0x2000 + SOF_TIMESTAMPING_OPT_TX_SWHW = 0x4000 + + SOF_TIMESTAMPING_LAST = 0x4000 + SOF_TIMESTAMPING_MASK = 0x7fff + + SCM_TSTAMP_SND = 0x0 + SCM_TSTAMP_SCHED = 0x1 + SCM_TSTAMP_ACK = 0x2 +) + +type SockExtendedErr struct { + Errno uint32 + Origin uint8 + Type uint8 + Code uint8 + Pad uint8 + Info uint32 + Data uint32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go index 45c10b7429..ef76a362d9 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go @@ -6,11 +6,11 @@ package unix const ( - sizeofPtr = 0x8 - sizeofShort = 0x2 - sizeofInt = 0x4 - sizeofLong = 0x8 - sizeofLongLong = 0x8 + SizeofPtr = 0x8 + SizeofShort = 0x2 + SizeofInt = 0x4 + SizeofLong = 0x8 + SizeofLongLong = 0x8 PathMax = 0x1000 ) @@ -33,13 +33,11 @@ type Timeval struct { type Timex struct { Modes uint32 - Pad_cgo_0 [4]byte Offset int64 Freq int64 Maxerror int64 Esterror int64 Status int32 - Pad_cgo_1 [4]byte Constant int64 Precision int64 Tolerance int64 @@ -48,14 +46,13 @@ type Timex struct { Ppsfreq int64 Jitter int64 Shift int32 - Pad_cgo_2 [4]byte Stabil int64 Jitcnt int64 Calcnt int64 Errcnt int64 Stbcnt int64 Tai int32 - Pad_cgo_3 [44]byte + _ [44]byte } type Time_t int64 @@ -106,10 +103,10 @@ type Stat_t struct { Uid uint32 Gid uint32 Rdev uint64 - X__pad1 uint64 + _ uint64 Size int64 Blksize int32 - X__pad2 int32 + _ int32 Blocks int64 Atim Timespec Mtim Timespec @@ -117,42 +114,56 @@ type Stat_t struct { _ [2]int32 } -type Statfs_t struct { - Type int64 - Bsize int64 - Blocks uint64 - Bfree uint64 - Bavail uint64 - Files uint64 - Ffree uint64 - Fsid Fsid - Namelen int64 - Frsize int64 - Flags int64 - Spare [4]int64 +type StatxTimestamp struct { + Sec int64 + Nsec uint32 + _ int32 +} + +type Statx_t struct { + Mask uint32 + Blksize uint32 + Attributes uint64 + Nlink uint32 + Uid uint32 + Gid uint32 + Mode uint16 + _ [1]uint16 + Ino uint64 + Size uint64 + Blocks uint64 + Attributes_mask uint64 + Atime StatxTimestamp + Btime StatxTimestamp + Ctime StatxTimestamp + Mtime StatxTimestamp + Rdev_major uint32 + Rdev_minor uint32 + Dev_major uint32 + Dev_minor uint32 + _ [14]uint64 } type Dirent struct { - Ino uint64 - Off int64 - Reclen uint16 - Type uint8 - Name [256]int8 - Pad_cgo_0 [5]byte + Ino uint64 + Off int64 + Reclen uint16 + Type uint8 + Name [256]int8 + _ [5]byte } type Fsid struct { - X__val [2]int32 + Val [2]int32 } type Flock_t struct { - Type int16 - Whence int16 - Pad_cgo_0 [4]byte - Start int64 - Len int64 - Pid int32 - Pad_cgo_1 [4]byte + Type int16 + Whence int16 + Start int64 + Len int64 + Pid int32 + _ [4]byte } type FscryptPolicy struct { @@ -227,11 +238,26 @@ type RawSockaddrHCI struct { Channel uint16 } +type RawSockaddrL2 struct { + Family uint16 + Psm uint16 + Bdaddr [6]uint8 + Cid uint16 + Bdaddr_type uint8 + _ [1]byte +} + +type RawSockaddrRFCOMM struct { + Family uint16 + Bdaddr [6]uint8 + Channel uint8 + _ [1]byte +} + type RawSockaddrCAN struct { - Family uint16 - Pad_cgo_0 [2]byte - Ifindex int32 - Addr [8]byte + Family uint16 + Ifindex int32 + Addr [8]byte } type RawSockaddrALG struct { @@ -250,6 +276,16 @@ type RawSockaddrVM struct { Zero [4]uint8 } +type RawSockaddrXDP struct { + Family uint16 + Flags uint16 + Ifindex uint32 + Queue_id uint32 + Shared_umem_fd uint32 +} + +type RawSockaddrPPPoX [0x1e]byte + type RawSockaddr struct { Family uint16 Data [14]int8 @@ -298,13 +334,12 @@ type PacketMreq struct { type Msghdr struct { Name *byte Namelen uint32 - Pad_cgo_0 [4]byte Iov *Iovec Iovlen uint64 Control *byte Controllen uint64 Flags int32 - Pad_cgo_1 [4]byte + _ [4]byte } type Cmsghdr struct { @@ -346,7 +381,6 @@ type TCPInfo struct { Probes uint8 Backoff uint8 Options uint8 - Pad_cgo_0 [2]byte Rto uint32 Ato uint32 Snd_mss uint32 @@ -381,9 +415,13 @@ const ( SizeofSockaddrLinklayer = 0x14 SizeofSockaddrNetlink = 0xc SizeofSockaddrHCI = 0x6 + SizeofSockaddrL2 = 0xe + SizeofSockaddrRFCOMM = 0xa SizeofSockaddrCAN = 0x10 SizeofSockaddrALG = 0x58 SizeofSockaddrVM = 0x10 + SizeofSockaddrXDP = 0x10 + SizeofSockaddrPPPoX = 0x1e SizeofLinger = 0x8 SizeofIovec = 0x10 SizeofIPMreq = 0x8 @@ -401,97 +439,138 @@ const ( ) const ( - IFA_UNSPEC = 0x0 - IFA_ADDRESS = 0x1 - IFA_LOCAL = 0x2 - IFA_LABEL = 0x3 - IFA_BROADCAST = 0x4 - IFA_ANYCAST = 0x5 - IFA_CACHEINFO = 0x6 - IFA_MULTICAST = 0x7 - IFLA_UNSPEC = 0x0 - IFLA_ADDRESS = 0x1 - IFLA_BROADCAST = 0x2 - IFLA_IFNAME = 0x3 - IFLA_MTU = 0x4 - IFLA_LINK = 0x5 - IFLA_QDISC = 0x6 - IFLA_STATS = 0x7 - IFLA_COST = 0x8 - IFLA_PRIORITY = 0x9 - IFLA_MASTER = 0xa - IFLA_WIRELESS = 0xb - IFLA_PROTINFO = 0xc - IFLA_TXQLEN = 0xd - IFLA_MAP = 0xe - IFLA_WEIGHT = 0xf - IFLA_OPERSTATE = 0x10 - IFLA_LINKMODE = 0x11 - IFLA_LINKINFO = 0x12 - IFLA_NET_NS_PID = 0x13 - IFLA_IFALIAS = 0x14 - IFLA_MAX = 0x2c - RT_SCOPE_UNIVERSE = 0x0 - RT_SCOPE_SITE = 0xc8 - RT_SCOPE_LINK = 0xfd - RT_SCOPE_HOST = 0xfe - RT_SCOPE_NOWHERE = 0xff - RT_TABLE_UNSPEC = 0x0 - RT_TABLE_COMPAT = 0xfc - RT_TABLE_DEFAULT = 0xfd - RT_TABLE_MAIN = 0xfe - RT_TABLE_LOCAL = 0xff - RT_TABLE_MAX = 0xffffffff - RTA_UNSPEC = 0x0 - RTA_DST = 0x1 - RTA_SRC = 0x2 - RTA_IIF = 0x3 - RTA_OIF = 0x4 - RTA_GATEWAY = 0x5 - RTA_PRIORITY = 0x6 - RTA_PREFSRC = 0x7 - RTA_METRICS = 0x8 - RTA_MULTIPATH = 0x9 - RTA_FLOW = 0xb - RTA_CACHEINFO = 0xc - RTA_TABLE = 0xf - RTN_UNSPEC = 0x0 - RTN_UNICAST = 0x1 - RTN_LOCAL = 0x2 - RTN_BROADCAST = 0x3 - RTN_ANYCAST = 0x4 - RTN_MULTICAST = 0x5 - RTN_BLACKHOLE = 0x6 - RTN_UNREACHABLE = 0x7 - RTN_PROHIBIT = 0x8 - RTN_THROW = 0x9 - RTN_NAT = 0xa - RTN_XRESOLVE = 0xb - RTNLGRP_NONE = 0x0 - RTNLGRP_LINK = 0x1 - RTNLGRP_NOTIFY = 0x2 - RTNLGRP_NEIGH = 0x3 - RTNLGRP_TC = 0x4 - RTNLGRP_IPV4_IFADDR = 0x5 - RTNLGRP_IPV4_MROUTE = 0x6 - RTNLGRP_IPV4_ROUTE = 0x7 - RTNLGRP_IPV4_RULE = 0x8 - RTNLGRP_IPV6_IFADDR = 0x9 - RTNLGRP_IPV6_MROUTE = 0xa - RTNLGRP_IPV6_ROUTE = 0xb - RTNLGRP_IPV6_IFINFO = 0xc - RTNLGRP_IPV6_PREFIX = 0x12 - RTNLGRP_IPV6_RULE = 0x13 - RTNLGRP_ND_USEROPT = 0x14 - SizeofNlMsghdr = 0x10 - SizeofNlMsgerr = 0x14 - SizeofRtGenmsg = 0x1 - SizeofNlAttr = 0x4 - SizeofRtAttr = 0x4 - SizeofIfInfomsg = 0x10 - SizeofIfAddrmsg = 0x8 - SizeofRtMsg = 0xc - SizeofRtNexthop = 0x8 + IFA_UNSPEC = 0x0 + IFA_ADDRESS = 0x1 + IFA_LOCAL = 0x2 + IFA_LABEL = 0x3 + IFA_BROADCAST = 0x4 + IFA_ANYCAST = 0x5 + IFA_CACHEINFO = 0x6 + IFA_MULTICAST = 0x7 + IFLA_UNSPEC = 0x0 + IFLA_ADDRESS = 0x1 + IFLA_BROADCAST = 0x2 + IFLA_IFNAME = 0x3 + IFLA_INFO_KIND = 0x1 + IFLA_MTU = 0x4 + IFLA_LINK = 0x5 + IFLA_QDISC = 0x6 + IFLA_STATS = 0x7 + IFLA_COST = 0x8 + IFLA_PRIORITY = 0x9 + IFLA_MASTER = 0xa + IFLA_WIRELESS = 0xb + IFLA_PROTINFO = 0xc + IFLA_TXQLEN = 0xd + IFLA_MAP = 0xe + IFLA_WEIGHT = 0xf + IFLA_OPERSTATE = 0x10 + IFLA_LINKMODE = 0x11 + IFLA_LINKINFO = 0x12 + IFLA_NET_NS_PID = 0x13 + IFLA_IFALIAS = 0x14 + IFLA_NUM_VF = 0x15 + IFLA_VFINFO_LIST = 0x16 + IFLA_STATS64 = 0x17 + IFLA_VF_PORTS = 0x18 + IFLA_PORT_SELF = 0x19 + IFLA_AF_SPEC = 0x1a + IFLA_GROUP = 0x1b + IFLA_NET_NS_FD = 0x1c + IFLA_EXT_MASK = 0x1d + IFLA_PROMISCUITY = 0x1e + IFLA_NUM_TX_QUEUES = 0x1f + IFLA_NUM_RX_QUEUES = 0x20 + IFLA_CARRIER = 0x21 + IFLA_PHYS_PORT_ID = 0x22 + IFLA_CARRIER_CHANGES = 0x23 + IFLA_PHYS_SWITCH_ID = 0x24 + IFLA_LINK_NETNSID = 0x25 + IFLA_PHYS_PORT_NAME = 0x26 + IFLA_PROTO_DOWN = 0x27 + IFLA_GSO_MAX_SEGS = 0x28 + IFLA_GSO_MAX_SIZE = 0x29 + IFLA_PAD = 0x2a + IFLA_XDP = 0x2b + IFLA_EVENT = 0x2c + IFLA_NEW_NETNSID = 0x2d + IFLA_IF_NETNSID = 0x2e + IFLA_MAX = 0x33 + RT_SCOPE_UNIVERSE = 0x0 + RT_SCOPE_SITE = 0xc8 + RT_SCOPE_LINK = 0xfd + RT_SCOPE_HOST = 0xfe + RT_SCOPE_NOWHERE = 0xff + RT_TABLE_UNSPEC = 0x0 + RT_TABLE_COMPAT = 0xfc + RT_TABLE_DEFAULT = 0xfd + RT_TABLE_MAIN = 0xfe + RT_TABLE_LOCAL = 0xff + RT_TABLE_MAX = 0xffffffff + RTA_UNSPEC = 0x0 + RTA_DST = 0x1 + RTA_SRC = 0x2 + RTA_IIF = 0x3 + RTA_OIF = 0x4 + RTA_GATEWAY = 0x5 + RTA_PRIORITY = 0x6 + RTA_PREFSRC = 0x7 + RTA_METRICS = 0x8 + RTA_MULTIPATH = 0x9 + RTA_FLOW = 0xb + RTA_CACHEINFO = 0xc + RTA_TABLE = 0xf + RTA_MARK = 0x10 + RTA_MFC_STATS = 0x11 + RTA_VIA = 0x12 + RTA_NEWDST = 0x13 + RTA_PREF = 0x14 + RTA_ENCAP_TYPE = 0x15 + RTA_ENCAP = 0x16 + RTA_EXPIRES = 0x17 + RTA_PAD = 0x18 + RTA_UID = 0x19 + RTA_TTL_PROPAGATE = 0x1a + RTA_IP_PROTO = 0x1b + RTA_SPORT = 0x1c + RTA_DPORT = 0x1d + RTN_UNSPEC = 0x0 + RTN_UNICAST = 0x1 + RTN_LOCAL = 0x2 + RTN_BROADCAST = 0x3 + RTN_ANYCAST = 0x4 + RTN_MULTICAST = 0x5 + RTN_BLACKHOLE = 0x6 + RTN_UNREACHABLE = 0x7 + RTN_PROHIBIT = 0x8 + RTN_THROW = 0x9 + RTN_NAT = 0xa + RTN_XRESOLVE = 0xb + RTNLGRP_NONE = 0x0 + RTNLGRP_LINK = 0x1 + RTNLGRP_NOTIFY = 0x2 + RTNLGRP_NEIGH = 0x3 + RTNLGRP_TC = 0x4 + RTNLGRP_IPV4_IFADDR = 0x5 + RTNLGRP_IPV4_MROUTE = 0x6 + RTNLGRP_IPV4_ROUTE = 0x7 + RTNLGRP_IPV4_RULE = 0x8 + RTNLGRP_IPV6_IFADDR = 0x9 + RTNLGRP_IPV6_MROUTE = 0xa + RTNLGRP_IPV6_ROUTE = 0xb + RTNLGRP_IPV6_IFINFO = 0xc + RTNLGRP_IPV6_PREFIX = 0x12 + RTNLGRP_IPV6_RULE = 0x13 + RTNLGRP_ND_USEROPT = 0x14 + SizeofNlMsghdr = 0x10 + SizeofNlMsgerr = 0x14 + SizeofRtGenmsg = 0x1 + SizeofNlAttr = 0x4 + SizeofRtAttr = 0x4 + SizeofIfInfomsg = 0x10 + SizeofIfAddrmsg = 0x8 + SizeofRtMsg = 0xc + SizeofRtNexthop = 0x8 ) type NlMsghdr struct { @@ -522,12 +601,12 @@ type RtAttr struct { } type IfInfomsg struct { - Family uint8 - X__ifi_pad uint8 - Type uint16 - Index int32 - Flags uint32 - Change uint32 + Family uint8 + _ uint8 + Type uint16 + Index int32 + Flags uint32 + Change uint32 } type IfAddrmsg struct { @@ -570,9 +649,8 @@ type SockFilter struct { } type SockFprog struct { - Len uint16 - Pad_cgo_0 [6]byte - Filter *SockFilter + Len uint16 + Filter *SockFilter } type InotifyEvent struct { @@ -606,12 +684,11 @@ type Sysinfo_t struct { Freeswap uint64 Procs uint16 Pad uint16 - Pad_cgo_0 [4]byte Totalhigh uint64 Freehigh uint64 Unit uint32 - X_f [0]int8 - Pad_cgo_1 [4]byte + _ [0]int8 + _ [4]byte } type Utsname struct { @@ -624,12 +701,11 @@ type Utsname struct { } type Ustat_t struct { - Tfree int32 - Pad_cgo_0 [4]byte - Tinode uint64 - Fname [6]int8 - Fpack [6]int8 - Pad_cgo_1 [4]byte + Tfree int32 + Tinode uint64 + Fname [6]int8 + Fpack [6]int8 + _ [4]byte } type EpollEvent struct { @@ -640,10 +716,19 @@ type EpollEvent struct { } const ( - AT_FDCWD = -0x64 - AT_REMOVEDIR = 0x200 + AT_EMPTY_PATH = 0x1000 + AT_FDCWD = -0x64 + AT_NO_AUTOMOUNT = 0x800 + AT_REMOVEDIR = 0x200 + + AT_STATX_SYNC_AS_STAT = 0x0 + AT_STATX_FORCE_SYNC = 0x2000 + AT_STATX_DONT_SYNC = 0x4000 + AT_SYMLINK_FOLLOW = 0x400 AT_SYMLINK_NOFOLLOW = 0x100 + + AT_EACCESS = 0x200 ) type PollFd struct { @@ -663,10 +748,33 @@ const ( ) type Sigset_t struct { - X__val [16]uint64 + Val [16]uint64 } -const RNDGETENTCNT = 0x80045200 +type SignalfdSiginfo struct { + Signo uint32 + Errno int32 + Code int32 + Pid uint32 + Uid uint32 + Fd int32 + Tid uint32 + Band uint32 + Overrun uint32 + Trapno uint32 + Status int32 + Int int32 + Ptr uint64 + Utime uint64 + Stime uint64 + Addr uint64 + Addr_lsb uint16 + _ uint16 + Syscall int32 + Call_addr uint64 + Arch uint32 + _ [28]uint8 +} const PERF_IOC_FLAG_GROUP = 0x1 @@ -690,11 +798,9 @@ type Winsize struct { type Taskstats struct { Version uint16 - Pad_cgo_0 [2]byte Ac_exitcode uint32 Ac_flag uint8 Ac_nice uint8 - Pad_cgo_1 [6]byte Cpu_count uint64 Cpu_delay_total uint64 Blkio_count uint64 @@ -706,13 +812,12 @@ type Taskstats struct { Ac_comm [32]int8 Ac_sched uint8 Ac_pad [3]uint8 - Pad_cgo_2 [4]byte + _ [4]byte Ac_uid uint32 Ac_gid uint32 Ac_pid uint32 Ac_ppid uint32 Ac_btime uint32 - Pad_cgo_3 [4]byte Ac_etime uint64 Ac_utime uint64 Ac_stime uint64 @@ -736,6 +841,8 @@ type Taskstats struct { Cpu_scaled_run_real_total uint64 Freepages_count uint64 Freepages_delay_total uint64 + Thrashing_count uint64 + Thrashing_delay_total uint64 } const ( @@ -756,6 +863,24 @@ const ( TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK = 0x4 ) +type CGroupStats struct { + Sleeping uint64 + Running uint64 + Stopped uint64 + Uninterruptible uint64 + Io_wait uint64 +} + +const ( + CGROUPSTATS_CMD_UNSPEC = 0x3 + CGROUPSTATS_CMD_GET = 0x4 + CGROUPSTATS_CMD_NEW = 0x5 + CGROUPSTATS_TYPE_UNSPEC = 0x0 + CGROUPSTATS_TYPE_CGROUP_STATS = 0x1 + CGROUPSTATS_CMD_ATTR_UNSPEC = 0x0 + CGROUPSTATS_CMD_ATTR_FD = 0x1 +) + type Genlmsghdr struct { Cmd uint8 Version uint8 @@ -788,3 +913,1107 @@ const ( CTRL_ATTR_MCAST_GRP_NAME = 0x1 CTRL_ATTR_MCAST_GRP_ID = 0x2 ) + +type cpuMask uint64 + +const ( + _CPU_SETSIZE = 0x400 + _NCPUBITS = 0x40 +) + +const ( + BDADDR_BREDR = 0x0 + BDADDR_LE_PUBLIC = 0x1 + BDADDR_LE_RANDOM = 0x2 +) + +type PerfEventAttr struct { + Type uint32 + Size uint32 + Config uint64 + Sample uint64 + Sample_type uint64 + Read_format uint64 + Bits uint64 + Wakeup uint32 + Bp_type uint32 + Ext1 uint64 + Ext2 uint64 + Branch_sample_type uint64 + Sample_regs_user uint64 + Sample_stack_user uint32 + Clockid int32 + Sample_regs_intr uint64 + Aux_watermark uint32 + _ uint32 +} + +type PerfEventMmapPage struct { + Version uint32 + Compat_version uint32 + Lock uint32 + Index uint32 + Offset int64 + Time_enabled uint64 + Time_running uint64 + Capabilities uint64 + Pmc_width uint16 + Time_shift uint16 + Time_mult uint32 + Time_offset uint64 + Time_zero uint64 + Size uint32 + _ [948]uint8 + Data_head uint64 + Data_tail uint64 + Data_offset uint64 + Data_size uint64 + Aux_head uint64 + Aux_tail uint64 + Aux_offset uint64 + Aux_size uint64 +} + +const ( + PerfBitDisabled uint64 = CBitFieldMaskBit0 + PerfBitInherit = CBitFieldMaskBit1 + PerfBitPinned = CBitFieldMaskBit2 + PerfBitExclusive = CBitFieldMaskBit3 + PerfBitExcludeUser = CBitFieldMaskBit4 + PerfBitExcludeKernel = CBitFieldMaskBit5 + PerfBitExcludeHv = CBitFieldMaskBit6 + PerfBitExcludeIdle = CBitFieldMaskBit7 + PerfBitMmap = CBitFieldMaskBit8 + PerfBitComm = CBitFieldMaskBit9 + PerfBitFreq = CBitFieldMaskBit10 + PerfBitInheritStat = CBitFieldMaskBit11 + PerfBitEnableOnExec = CBitFieldMaskBit12 + PerfBitTask = CBitFieldMaskBit13 + PerfBitWatermark = CBitFieldMaskBit14 + PerfBitPreciseIPBit1 = CBitFieldMaskBit15 + PerfBitPreciseIPBit2 = CBitFieldMaskBit16 + PerfBitMmapData = CBitFieldMaskBit17 + PerfBitSampleIDAll = CBitFieldMaskBit18 + PerfBitExcludeHost = CBitFieldMaskBit19 + PerfBitExcludeGuest = CBitFieldMaskBit20 + PerfBitExcludeCallchainKernel = CBitFieldMaskBit21 + PerfBitExcludeCallchainUser = CBitFieldMaskBit22 + PerfBitMmap2 = CBitFieldMaskBit23 + PerfBitCommExec = CBitFieldMaskBit24 + PerfBitUseClockID = CBitFieldMaskBit25 + PerfBitContextSwitch = CBitFieldMaskBit26 +) + +const ( + PERF_TYPE_HARDWARE = 0x0 + PERF_TYPE_SOFTWARE = 0x1 + PERF_TYPE_TRACEPOINT = 0x2 + PERF_TYPE_HW_CACHE = 0x3 + PERF_TYPE_RAW = 0x4 + PERF_TYPE_BREAKPOINT = 0x5 + + PERF_COUNT_HW_CPU_CYCLES = 0x0 + PERF_COUNT_HW_INSTRUCTIONS = 0x1 + PERF_COUNT_HW_CACHE_REFERENCES = 0x2 + PERF_COUNT_HW_CACHE_MISSES = 0x3 + PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 0x4 + PERF_COUNT_HW_BRANCH_MISSES = 0x5 + PERF_COUNT_HW_BUS_CYCLES = 0x6 + PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 0x7 + PERF_COUNT_HW_STALLED_CYCLES_BACKEND = 0x8 + PERF_COUNT_HW_REF_CPU_CYCLES = 0x9 + + PERF_COUNT_HW_CACHE_L1D = 0x0 + PERF_COUNT_HW_CACHE_L1I = 0x1 + PERF_COUNT_HW_CACHE_LL = 0x2 + PERF_COUNT_HW_CACHE_DTLB = 0x3 + PERF_COUNT_HW_CACHE_ITLB = 0x4 + PERF_COUNT_HW_CACHE_BPU = 0x5 + PERF_COUNT_HW_CACHE_NODE = 0x6 + + PERF_COUNT_HW_CACHE_OP_READ = 0x0 + PERF_COUNT_HW_CACHE_OP_WRITE = 0x1 + PERF_COUNT_HW_CACHE_OP_PREFETCH = 0x2 + + PERF_COUNT_HW_CACHE_RESULT_ACCESS = 0x0 + PERF_COUNT_HW_CACHE_RESULT_MISS = 0x1 + + PERF_COUNT_SW_CPU_CLOCK = 0x0 + PERF_COUNT_SW_TASK_CLOCK = 0x1 + PERF_COUNT_SW_PAGE_FAULTS = 0x2 + PERF_COUNT_SW_CONTEXT_SWITCHES = 0x3 + PERF_COUNT_SW_CPU_MIGRATIONS = 0x4 + PERF_COUNT_SW_PAGE_FAULTS_MIN = 0x5 + PERF_COUNT_SW_PAGE_FAULTS_MAJ = 0x6 + PERF_COUNT_SW_ALIGNMENT_FAULTS = 0x7 + PERF_COUNT_SW_EMULATION_FAULTS = 0x8 + PERF_COUNT_SW_DUMMY = 0x9 + + PERF_SAMPLE_IP = 0x1 + PERF_SAMPLE_TID = 0x2 + PERF_SAMPLE_TIME = 0x4 + PERF_SAMPLE_ADDR = 0x8 + PERF_SAMPLE_READ = 0x10 + PERF_SAMPLE_CALLCHAIN = 0x20 + PERF_SAMPLE_ID = 0x40 + PERF_SAMPLE_CPU = 0x80 + PERF_SAMPLE_PERIOD = 0x100 + PERF_SAMPLE_STREAM_ID = 0x200 + PERF_SAMPLE_RAW = 0x400 + PERF_SAMPLE_BRANCH_STACK = 0x800 + + PERF_SAMPLE_BRANCH_USER = 0x1 + PERF_SAMPLE_BRANCH_KERNEL = 0x2 + PERF_SAMPLE_BRANCH_HV = 0x4 + PERF_SAMPLE_BRANCH_ANY = 0x8 + PERF_SAMPLE_BRANCH_ANY_CALL = 0x10 + PERF_SAMPLE_BRANCH_ANY_RETURN = 0x20 + PERF_SAMPLE_BRANCH_IND_CALL = 0x40 + + PERF_FORMAT_TOTAL_TIME_ENABLED = 0x1 + PERF_FORMAT_TOTAL_TIME_RUNNING = 0x2 + PERF_FORMAT_ID = 0x4 + PERF_FORMAT_GROUP = 0x8 + + PERF_RECORD_MMAP = 0x1 + PERF_RECORD_LOST = 0x2 + PERF_RECORD_COMM = 0x3 + PERF_RECORD_EXIT = 0x4 + PERF_RECORD_THROTTLE = 0x5 + PERF_RECORD_UNTHROTTLE = 0x6 + PERF_RECORD_FORK = 0x7 + PERF_RECORD_READ = 0x8 + PERF_RECORD_SAMPLE = 0x9 + + PERF_CONTEXT_HV = -0x20 + PERF_CONTEXT_KERNEL = -0x80 + PERF_CONTEXT_USER = -0x200 + + PERF_CONTEXT_GUEST = -0x800 + PERF_CONTEXT_GUEST_KERNEL = -0x880 + PERF_CONTEXT_GUEST_USER = -0xa00 + + PERF_FLAG_FD_NO_GROUP = 0x1 + PERF_FLAG_FD_OUTPUT = 0x2 + PERF_FLAG_PID_CGROUP = 0x4 +) + +const ( + CBitFieldMaskBit0 = 0x1 + CBitFieldMaskBit1 = 0x2 + CBitFieldMaskBit2 = 0x4 + CBitFieldMaskBit3 = 0x8 + CBitFieldMaskBit4 = 0x10 + CBitFieldMaskBit5 = 0x20 + CBitFieldMaskBit6 = 0x40 + CBitFieldMaskBit7 = 0x80 + CBitFieldMaskBit8 = 0x100 + CBitFieldMaskBit9 = 0x200 + CBitFieldMaskBit10 = 0x400 + CBitFieldMaskBit11 = 0x800 + CBitFieldMaskBit12 = 0x1000 + CBitFieldMaskBit13 = 0x2000 + CBitFieldMaskBit14 = 0x4000 + CBitFieldMaskBit15 = 0x8000 + CBitFieldMaskBit16 = 0x10000 + CBitFieldMaskBit17 = 0x20000 + CBitFieldMaskBit18 = 0x40000 + CBitFieldMaskBit19 = 0x80000 + CBitFieldMaskBit20 = 0x100000 + CBitFieldMaskBit21 = 0x200000 + CBitFieldMaskBit22 = 0x400000 + CBitFieldMaskBit23 = 0x800000 + CBitFieldMaskBit24 = 0x1000000 + CBitFieldMaskBit25 = 0x2000000 + CBitFieldMaskBit26 = 0x4000000 + CBitFieldMaskBit27 = 0x8000000 + CBitFieldMaskBit28 = 0x10000000 + CBitFieldMaskBit29 = 0x20000000 + CBitFieldMaskBit30 = 0x40000000 + CBitFieldMaskBit31 = 0x80000000 + CBitFieldMaskBit32 = 0x100000000 + CBitFieldMaskBit33 = 0x200000000 + CBitFieldMaskBit34 = 0x400000000 + CBitFieldMaskBit35 = 0x800000000 + CBitFieldMaskBit36 = 0x1000000000 + CBitFieldMaskBit37 = 0x2000000000 + CBitFieldMaskBit38 = 0x4000000000 + CBitFieldMaskBit39 = 0x8000000000 + CBitFieldMaskBit40 = 0x10000000000 + CBitFieldMaskBit41 = 0x20000000000 + CBitFieldMaskBit42 = 0x40000000000 + CBitFieldMaskBit43 = 0x80000000000 + CBitFieldMaskBit44 = 0x100000000000 + CBitFieldMaskBit45 = 0x200000000000 + CBitFieldMaskBit46 = 0x400000000000 + CBitFieldMaskBit47 = 0x800000000000 + CBitFieldMaskBit48 = 0x1000000000000 + CBitFieldMaskBit49 = 0x2000000000000 + CBitFieldMaskBit50 = 0x4000000000000 + CBitFieldMaskBit51 = 0x8000000000000 + CBitFieldMaskBit52 = 0x10000000000000 + CBitFieldMaskBit53 = 0x20000000000000 + CBitFieldMaskBit54 = 0x40000000000000 + CBitFieldMaskBit55 = 0x80000000000000 + CBitFieldMaskBit56 = 0x100000000000000 + CBitFieldMaskBit57 = 0x200000000000000 + CBitFieldMaskBit58 = 0x400000000000000 + CBitFieldMaskBit59 = 0x800000000000000 + CBitFieldMaskBit60 = 0x1000000000000000 + CBitFieldMaskBit61 = 0x2000000000000000 + CBitFieldMaskBit62 = 0x4000000000000000 + CBitFieldMaskBit63 = 0x8000000000000000 +) + +type SockaddrStorage struct { + Family uint16 + _ [118]int8 + _ uint64 +} + +type TCPMD5Sig struct { + Addr SockaddrStorage + Flags uint8 + Prefixlen uint8 + Keylen uint16 + _ uint32 + Key [80]uint8 +} + +type HDDriveCmdHdr struct { + Command uint8 + Number uint8 + Feature uint8 + Count uint8 +} + +type HDGeometry struct { + Heads uint8 + Sectors uint8 + Cylinders uint16 + Start uint64 +} + +type HDDriveID struct { + Config uint16 + Cyls uint16 + Reserved2 uint16 + Heads uint16 + Track_bytes uint16 + Sector_bytes uint16 + Sectors uint16 + Vendor0 uint16 + Vendor1 uint16 + Vendor2 uint16 + Serial_no [20]uint8 + Buf_type uint16 + Buf_size uint16 + Ecc_bytes uint16 + Fw_rev [8]uint8 + Model [40]uint8 + Max_multsect uint8 + Vendor3 uint8 + Dword_io uint16 + Vendor4 uint8 + Capability uint8 + Reserved50 uint16 + Vendor5 uint8 + TPIO uint8 + Vendor6 uint8 + TDMA uint8 + Field_valid uint16 + Cur_cyls uint16 + Cur_heads uint16 + Cur_sectors uint16 + Cur_capacity0 uint16 + Cur_capacity1 uint16 + Multsect uint8 + Multsect_valid uint8 + Lba_capacity uint32 + Dma_1word uint16 + Dma_mword uint16 + Eide_pio_modes uint16 + Eide_dma_min uint16 + Eide_dma_time uint16 + Eide_pio uint16 + Eide_pio_iordy uint16 + Words69_70 [2]uint16 + Words71_74 [4]uint16 + Queue_depth uint16 + Words76_79 [4]uint16 + Major_rev_num uint16 + Minor_rev_num uint16 + Command_set_1 uint16 + Command_set_2 uint16 + Cfsse uint16 + Cfs_enable_1 uint16 + Cfs_enable_2 uint16 + Csf_default uint16 + Dma_ultra uint16 + Trseuc uint16 + TrsEuc uint16 + CurAPMvalues uint16 + Mprc uint16 + Hw_config uint16 + Acoustic uint16 + Msrqs uint16 + Sxfert uint16 + Sal uint16 + Spg uint32 + Lba_capacity_2 uint64 + Words104_125 [22]uint16 + Last_lun uint16 + Word127 uint16 + Dlf uint16 + Csfo uint16 + Words130_155 [26]uint16 + Word156 uint16 + Words157_159 [3]uint16 + Cfa_power uint16 + Words161_175 [15]uint16 + Words176_205 [30]uint16 + Words206_254 [49]uint16 + Integrity_word uint16 +} + +type Statfs_t struct { + Type int64 + Bsize int64 + Blocks uint64 + Bfree uint64 + Bavail uint64 + Files uint64 + Ffree uint64 + Fsid Fsid + Namelen int64 + Frsize int64 + Flags int64 + Spare [4]int64 +} + +const ( + ST_MANDLOCK = 0x40 + ST_NOATIME = 0x400 + ST_NODEV = 0x4 + ST_NODIRATIME = 0x800 + ST_NOEXEC = 0x8 + ST_NOSUID = 0x2 + ST_RDONLY = 0x1 + ST_RELATIME = 0x1000 + ST_SYNCHRONOUS = 0x10 +) + +type TpacketHdr struct { + Status uint64 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Sec uint32 + Usec uint32 + _ [4]byte +} + +type Tpacket2Hdr struct { + Status uint32 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Sec uint32 + Nsec uint32 + Vlan_tci uint16 + Vlan_tpid uint16 + _ [4]uint8 +} + +type Tpacket3Hdr struct { + Next_offset uint32 + Sec uint32 + Nsec uint32 + Snaplen uint32 + Len uint32 + Status uint32 + Mac uint16 + Net uint16 + Hv1 TpacketHdrVariant1 + _ [8]uint8 +} + +type TpacketHdrVariant1 struct { + Rxhash uint32 + Vlan_tci uint32 + Vlan_tpid uint16 + _ uint16 +} + +type TpacketBlockDesc struct { + Version uint32 + To_priv uint32 + Hdr [40]byte +} + +type TpacketReq struct { + Block_size uint32 + Block_nr uint32 + Frame_size uint32 + Frame_nr uint32 +} + +type TpacketReq3 struct { + Block_size uint32 + Block_nr uint32 + Frame_size uint32 + Frame_nr uint32 + Retire_blk_tov uint32 + Sizeof_priv uint32 + Feature_req_word uint32 +} + +type TpacketStats struct { + Packets uint32 + Drops uint32 +} + +type TpacketStatsV3 struct { + Packets uint32 + Drops uint32 + Freeze_q_cnt uint32 +} + +type TpacketAuxdata struct { + Status uint32 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Vlan_tci uint16 + Vlan_tpid uint16 +} + +const ( + TPACKET_V1 = 0x0 + TPACKET_V2 = 0x1 + TPACKET_V3 = 0x2 +) + +const ( + SizeofTpacketHdr = 0x20 + SizeofTpacket2Hdr = 0x20 + SizeofTpacket3Hdr = 0x30 +) + +const ( + NF_INET_PRE_ROUTING = 0x0 + NF_INET_LOCAL_IN = 0x1 + NF_INET_FORWARD = 0x2 + NF_INET_LOCAL_OUT = 0x3 + NF_INET_POST_ROUTING = 0x4 + NF_INET_NUMHOOKS = 0x5 +) + +const ( + NF_NETDEV_INGRESS = 0x0 + NF_NETDEV_NUMHOOKS = 0x1 +) + +const ( + NFPROTO_UNSPEC = 0x0 + NFPROTO_INET = 0x1 + NFPROTO_IPV4 = 0x2 + NFPROTO_ARP = 0x3 + NFPROTO_NETDEV = 0x5 + NFPROTO_BRIDGE = 0x7 + NFPROTO_IPV6 = 0xa + NFPROTO_DECNET = 0xc + NFPROTO_NUMPROTO = 0xd +) + +type Nfgenmsg struct { + Nfgen_family uint8 + Version uint8 + Res_id uint16 +} + +const ( + NFNL_BATCH_UNSPEC = 0x0 + NFNL_BATCH_GENID = 0x1 +) + +const ( + NFT_REG_VERDICT = 0x0 + NFT_REG_1 = 0x1 + NFT_REG_2 = 0x2 + NFT_REG_3 = 0x3 + NFT_REG_4 = 0x4 + NFT_REG32_00 = 0x8 + NFT_REG32_01 = 0x9 + NFT_REG32_02 = 0xa + NFT_REG32_03 = 0xb + NFT_REG32_04 = 0xc + NFT_REG32_05 = 0xd + NFT_REG32_06 = 0xe + NFT_REG32_07 = 0xf + NFT_REG32_08 = 0x10 + NFT_REG32_09 = 0x11 + NFT_REG32_10 = 0x12 + NFT_REG32_11 = 0x13 + NFT_REG32_12 = 0x14 + NFT_REG32_13 = 0x15 + NFT_REG32_14 = 0x16 + NFT_REG32_15 = 0x17 + NFT_CONTINUE = -0x1 + NFT_BREAK = -0x2 + NFT_JUMP = -0x3 + NFT_GOTO = -0x4 + NFT_RETURN = -0x5 + NFT_MSG_NEWTABLE = 0x0 + NFT_MSG_GETTABLE = 0x1 + NFT_MSG_DELTABLE = 0x2 + NFT_MSG_NEWCHAIN = 0x3 + NFT_MSG_GETCHAIN = 0x4 + NFT_MSG_DELCHAIN = 0x5 + NFT_MSG_NEWRULE = 0x6 + NFT_MSG_GETRULE = 0x7 + NFT_MSG_DELRULE = 0x8 + NFT_MSG_NEWSET = 0x9 + NFT_MSG_GETSET = 0xa + NFT_MSG_DELSET = 0xb + NFT_MSG_NEWSETELEM = 0xc + NFT_MSG_GETSETELEM = 0xd + NFT_MSG_DELSETELEM = 0xe + NFT_MSG_NEWGEN = 0xf + NFT_MSG_GETGEN = 0x10 + NFT_MSG_TRACE = 0x11 + NFT_MSG_NEWOBJ = 0x12 + NFT_MSG_GETOBJ = 0x13 + NFT_MSG_DELOBJ = 0x14 + NFT_MSG_GETOBJ_RESET = 0x15 + NFT_MSG_MAX = 0x19 + NFTA_LIST_UNPEC = 0x0 + NFTA_LIST_ELEM = 0x1 + NFTA_HOOK_UNSPEC = 0x0 + NFTA_HOOK_HOOKNUM = 0x1 + NFTA_HOOK_PRIORITY = 0x2 + NFTA_HOOK_DEV = 0x3 + NFT_TABLE_F_DORMANT = 0x1 + NFTA_TABLE_UNSPEC = 0x0 + NFTA_TABLE_NAME = 0x1 + NFTA_TABLE_FLAGS = 0x2 + NFTA_TABLE_USE = 0x3 + NFTA_CHAIN_UNSPEC = 0x0 + NFTA_CHAIN_TABLE = 0x1 + NFTA_CHAIN_HANDLE = 0x2 + NFTA_CHAIN_NAME = 0x3 + NFTA_CHAIN_HOOK = 0x4 + NFTA_CHAIN_POLICY = 0x5 + NFTA_CHAIN_USE = 0x6 + NFTA_CHAIN_TYPE = 0x7 + NFTA_CHAIN_COUNTERS = 0x8 + NFTA_CHAIN_PAD = 0x9 + NFTA_RULE_UNSPEC = 0x0 + NFTA_RULE_TABLE = 0x1 + NFTA_RULE_CHAIN = 0x2 + NFTA_RULE_HANDLE = 0x3 + NFTA_RULE_EXPRESSIONS = 0x4 + NFTA_RULE_COMPAT = 0x5 + NFTA_RULE_POSITION = 0x6 + NFTA_RULE_USERDATA = 0x7 + NFTA_RULE_PAD = 0x8 + NFTA_RULE_ID = 0x9 + NFT_RULE_COMPAT_F_INV = 0x2 + NFT_RULE_COMPAT_F_MASK = 0x2 + NFTA_RULE_COMPAT_UNSPEC = 0x0 + NFTA_RULE_COMPAT_PROTO = 0x1 + NFTA_RULE_COMPAT_FLAGS = 0x2 + NFT_SET_ANONYMOUS = 0x1 + NFT_SET_CONSTANT = 0x2 + NFT_SET_INTERVAL = 0x4 + NFT_SET_MAP = 0x8 + NFT_SET_TIMEOUT = 0x10 + NFT_SET_EVAL = 0x20 + NFT_SET_OBJECT = 0x40 + NFT_SET_POL_PERFORMANCE = 0x0 + NFT_SET_POL_MEMORY = 0x1 + NFTA_SET_DESC_UNSPEC = 0x0 + NFTA_SET_DESC_SIZE = 0x1 + NFTA_SET_UNSPEC = 0x0 + NFTA_SET_TABLE = 0x1 + NFTA_SET_NAME = 0x2 + NFTA_SET_FLAGS = 0x3 + NFTA_SET_KEY_TYPE = 0x4 + NFTA_SET_KEY_LEN = 0x5 + NFTA_SET_DATA_TYPE = 0x6 + NFTA_SET_DATA_LEN = 0x7 + NFTA_SET_POLICY = 0x8 + NFTA_SET_DESC = 0x9 + NFTA_SET_ID = 0xa + NFTA_SET_TIMEOUT = 0xb + NFTA_SET_GC_INTERVAL = 0xc + NFTA_SET_USERDATA = 0xd + NFTA_SET_PAD = 0xe + NFTA_SET_OBJ_TYPE = 0xf + NFT_SET_ELEM_INTERVAL_END = 0x1 + NFTA_SET_ELEM_UNSPEC = 0x0 + NFTA_SET_ELEM_KEY = 0x1 + NFTA_SET_ELEM_DATA = 0x2 + NFTA_SET_ELEM_FLAGS = 0x3 + NFTA_SET_ELEM_TIMEOUT = 0x4 + NFTA_SET_ELEM_EXPIRATION = 0x5 + NFTA_SET_ELEM_USERDATA = 0x6 + NFTA_SET_ELEM_EXPR = 0x7 + NFTA_SET_ELEM_PAD = 0x8 + NFTA_SET_ELEM_OBJREF = 0x9 + NFTA_SET_ELEM_LIST_UNSPEC = 0x0 + NFTA_SET_ELEM_LIST_TABLE = 0x1 + NFTA_SET_ELEM_LIST_SET = 0x2 + NFTA_SET_ELEM_LIST_ELEMENTS = 0x3 + NFTA_SET_ELEM_LIST_SET_ID = 0x4 + NFT_DATA_VALUE = 0x0 + NFT_DATA_VERDICT = 0xffffff00 + NFTA_DATA_UNSPEC = 0x0 + NFTA_DATA_VALUE = 0x1 + NFTA_DATA_VERDICT = 0x2 + NFTA_VERDICT_UNSPEC = 0x0 + NFTA_VERDICT_CODE = 0x1 + NFTA_VERDICT_CHAIN = 0x2 + NFTA_EXPR_UNSPEC = 0x0 + NFTA_EXPR_NAME = 0x1 + NFTA_EXPR_DATA = 0x2 + NFTA_IMMEDIATE_UNSPEC = 0x0 + NFTA_IMMEDIATE_DREG = 0x1 + NFTA_IMMEDIATE_DATA = 0x2 + NFTA_BITWISE_UNSPEC = 0x0 + NFTA_BITWISE_SREG = 0x1 + NFTA_BITWISE_DREG = 0x2 + NFTA_BITWISE_LEN = 0x3 + NFTA_BITWISE_MASK = 0x4 + NFTA_BITWISE_XOR = 0x5 + NFT_BYTEORDER_NTOH = 0x0 + NFT_BYTEORDER_HTON = 0x1 + NFTA_BYTEORDER_UNSPEC = 0x0 + NFTA_BYTEORDER_SREG = 0x1 + NFTA_BYTEORDER_DREG = 0x2 + NFTA_BYTEORDER_OP = 0x3 + NFTA_BYTEORDER_LEN = 0x4 + NFTA_BYTEORDER_SIZE = 0x5 + NFT_CMP_EQ = 0x0 + NFT_CMP_NEQ = 0x1 + NFT_CMP_LT = 0x2 + NFT_CMP_LTE = 0x3 + NFT_CMP_GT = 0x4 + NFT_CMP_GTE = 0x5 + NFTA_CMP_UNSPEC = 0x0 + NFTA_CMP_SREG = 0x1 + NFTA_CMP_OP = 0x2 + NFTA_CMP_DATA = 0x3 + NFT_RANGE_EQ = 0x0 + NFT_RANGE_NEQ = 0x1 + NFTA_RANGE_UNSPEC = 0x0 + NFTA_RANGE_SREG = 0x1 + NFTA_RANGE_OP = 0x2 + NFTA_RANGE_FROM_DATA = 0x3 + NFTA_RANGE_TO_DATA = 0x4 + NFT_LOOKUP_F_INV = 0x1 + NFTA_LOOKUP_UNSPEC = 0x0 + NFTA_LOOKUP_SET = 0x1 + NFTA_LOOKUP_SREG = 0x2 + NFTA_LOOKUP_DREG = 0x3 + NFTA_LOOKUP_SET_ID = 0x4 + NFTA_LOOKUP_FLAGS = 0x5 + NFT_DYNSET_OP_ADD = 0x0 + NFT_DYNSET_OP_UPDATE = 0x1 + NFT_DYNSET_F_INV = 0x1 + NFTA_DYNSET_UNSPEC = 0x0 + NFTA_DYNSET_SET_NAME = 0x1 + NFTA_DYNSET_SET_ID = 0x2 + NFTA_DYNSET_OP = 0x3 + NFTA_DYNSET_SREG_KEY = 0x4 + NFTA_DYNSET_SREG_DATA = 0x5 + NFTA_DYNSET_TIMEOUT = 0x6 + NFTA_DYNSET_EXPR = 0x7 + NFTA_DYNSET_PAD = 0x8 + NFTA_DYNSET_FLAGS = 0x9 + NFT_PAYLOAD_LL_HEADER = 0x0 + NFT_PAYLOAD_NETWORK_HEADER = 0x1 + NFT_PAYLOAD_TRANSPORT_HEADER = 0x2 + NFT_PAYLOAD_CSUM_NONE = 0x0 + NFT_PAYLOAD_CSUM_INET = 0x1 + NFT_PAYLOAD_L4CSUM_PSEUDOHDR = 0x1 + NFTA_PAYLOAD_UNSPEC = 0x0 + NFTA_PAYLOAD_DREG = 0x1 + NFTA_PAYLOAD_BASE = 0x2 + NFTA_PAYLOAD_OFFSET = 0x3 + NFTA_PAYLOAD_LEN = 0x4 + NFTA_PAYLOAD_SREG = 0x5 + NFTA_PAYLOAD_CSUM_TYPE = 0x6 + NFTA_PAYLOAD_CSUM_OFFSET = 0x7 + NFTA_PAYLOAD_CSUM_FLAGS = 0x8 + NFT_EXTHDR_F_PRESENT = 0x1 + NFT_EXTHDR_OP_IPV6 = 0x0 + NFT_EXTHDR_OP_TCPOPT = 0x1 + NFTA_EXTHDR_UNSPEC = 0x0 + NFTA_EXTHDR_DREG = 0x1 + NFTA_EXTHDR_TYPE = 0x2 + NFTA_EXTHDR_OFFSET = 0x3 + NFTA_EXTHDR_LEN = 0x4 + NFTA_EXTHDR_FLAGS = 0x5 + NFTA_EXTHDR_OP = 0x6 + NFTA_EXTHDR_SREG = 0x7 + NFT_META_LEN = 0x0 + NFT_META_PROTOCOL = 0x1 + NFT_META_PRIORITY = 0x2 + NFT_META_MARK = 0x3 + NFT_META_IIF = 0x4 + NFT_META_OIF = 0x5 + NFT_META_IIFNAME = 0x6 + NFT_META_OIFNAME = 0x7 + NFT_META_IIFTYPE = 0x8 + NFT_META_OIFTYPE = 0x9 + NFT_META_SKUID = 0xa + NFT_META_SKGID = 0xb + NFT_META_NFTRACE = 0xc + NFT_META_RTCLASSID = 0xd + NFT_META_SECMARK = 0xe + NFT_META_NFPROTO = 0xf + NFT_META_L4PROTO = 0x10 + NFT_META_BRI_IIFNAME = 0x11 + NFT_META_BRI_OIFNAME = 0x12 + NFT_META_PKTTYPE = 0x13 + NFT_META_CPU = 0x14 + NFT_META_IIFGROUP = 0x15 + NFT_META_OIFGROUP = 0x16 + NFT_META_CGROUP = 0x17 + NFT_META_PRANDOM = 0x18 + NFT_RT_CLASSID = 0x0 + NFT_RT_NEXTHOP4 = 0x1 + NFT_RT_NEXTHOP6 = 0x2 + NFT_RT_TCPMSS = 0x3 + NFT_HASH_JENKINS = 0x0 + NFT_HASH_SYM = 0x1 + NFTA_HASH_UNSPEC = 0x0 + NFTA_HASH_SREG = 0x1 + NFTA_HASH_DREG = 0x2 + NFTA_HASH_LEN = 0x3 + NFTA_HASH_MODULUS = 0x4 + NFTA_HASH_SEED = 0x5 + NFTA_HASH_OFFSET = 0x6 + NFTA_HASH_TYPE = 0x7 + NFTA_META_UNSPEC = 0x0 + NFTA_META_DREG = 0x1 + NFTA_META_KEY = 0x2 + NFTA_META_SREG = 0x3 + NFTA_RT_UNSPEC = 0x0 + NFTA_RT_DREG = 0x1 + NFTA_RT_KEY = 0x2 + NFT_CT_STATE = 0x0 + NFT_CT_DIRECTION = 0x1 + NFT_CT_STATUS = 0x2 + NFT_CT_MARK = 0x3 + NFT_CT_SECMARK = 0x4 + NFT_CT_EXPIRATION = 0x5 + NFT_CT_HELPER = 0x6 + NFT_CT_L3PROTOCOL = 0x7 + NFT_CT_SRC = 0x8 + NFT_CT_DST = 0x9 + NFT_CT_PROTOCOL = 0xa + NFT_CT_PROTO_SRC = 0xb + NFT_CT_PROTO_DST = 0xc + NFT_CT_LABELS = 0xd + NFT_CT_PKTS = 0xe + NFT_CT_BYTES = 0xf + NFT_CT_AVGPKT = 0x10 + NFT_CT_ZONE = 0x11 + NFT_CT_EVENTMASK = 0x12 + NFTA_CT_UNSPEC = 0x0 + NFTA_CT_DREG = 0x1 + NFTA_CT_KEY = 0x2 + NFTA_CT_DIRECTION = 0x3 + NFTA_CT_SREG = 0x4 + NFT_LIMIT_PKTS = 0x0 + NFT_LIMIT_PKT_BYTES = 0x1 + NFT_LIMIT_F_INV = 0x1 + NFTA_LIMIT_UNSPEC = 0x0 + NFTA_LIMIT_RATE = 0x1 + NFTA_LIMIT_UNIT = 0x2 + NFTA_LIMIT_BURST = 0x3 + NFTA_LIMIT_TYPE = 0x4 + NFTA_LIMIT_FLAGS = 0x5 + NFTA_LIMIT_PAD = 0x6 + NFTA_COUNTER_UNSPEC = 0x0 + NFTA_COUNTER_BYTES = 0x1 + NFTA_COUNTER_PACKETS = 0x2 + NFTA_COUNTER_PAD = 0x3 + NFTA_LOG_UNSPEC = 0x0 + NFTA_LOG_GROUP = 0x1 + NFTA_LOG_PREFIX = 0x2 + NFTA_LOG_SNAPLEN = 0x3 + NFTA_LOG_QTHRESHOLD = 0x4 + NFTA_LOG_LEVEL = 0x5 + NFTA_LOG_FLAGS = 0x6 + NFTA_QUEUE_UNSPEC = 0x0 + NFTA_QUEUE_NUM = 0x1 + NFTA_QUEUE_TOTAL = 0x2 + NFTA_QUEUE_FLAGS = 0x3 + NFTA_QUEUE_SREG_QNUM = 0x4 + NFT_QUOTA_F_INV = 0x1 + NFT_QUOTA_F_DEPLETED = 0x2 + NFTA_QUOTA_UNSPEC = 0x0 + NFTA_QUOTA_BYTES = 0x1 + NFTA_QUOTA_FLAGS = 0x2 + NFTA_QUOTA_PAD = 0x3 + NFTA_QUOTA_CONSUMED = 0x4 + NFT_REJECT_ICMP_UNREACH = 0x0 + NFT_REJECT_TCP_RST = 0x1 + NFT_REJECT_ICMPX_UNREACH = 0x2 + NFT_REJECT_ICMPX_NO_ROUTE = 0x0 + NFT_REJECT_ICMPX_PORT_UNREACH = 0x1 + NFT_REJECT_ICMPX_HOST_UNREACH = 0x2 + NFT_REJECT_ICMPX_ADMIN_PROHIBITED = 0x3 + NFTA_REJECT_UNSPEC = 0x0 + NFTA_REJECT_TYPE = 0x1 + NFTA_REJECT_ICMP_CODE = 0x2 + NFT_NAT_SNAT = 0x0 + NFT_NAT_DNAT = 0x1 + NFTA_NAT_UNSPEC = 0x0 + NFTA_NAT_TYPE = 0x1 + NFTA_NAT_FAMILY = 0x2 + NFTA_NAT_REG_ADDR_MIN = 0x3 + NFTA_NAT_REG_ADDR_MAX = 0x4 + NFTA_NAT_REG_PROTO_MIN = 0x5 + NFTA_NAT_REG_PROTO_MAX = 0x6 + NFTA_NAT_FLAGS = 0x7 + NFTA_MASQ_UNSPEC = 0x0 + NFTA_MASQ_FLAGS = 0x1 + NFTA_MASQ_REG_PROTO_MIN = 0x2 + NFTA_MASQ_REG_PROTO_MAX = 0x3 + NFTA_REDIR_UNSPEC = 0x0 + NFTA_REDIR_REG_PROTO_MIN = 0x1 + NFTA_REDIR_REG_PROTO_MAX = 0x2 + NFTA_REDIR_FLAGS = 0x3 + NFTA_DUP_UNSPEC = 0x0 + NFTA_DUP_SREG_ADDR = 0x1 + NFTA_DUP_SREG_DEV = 0x2 + NFTA_FWD_UNSPEC = 0x0 + NFTA_FWD_SREG_DEV = 0x1 + NFTA_OBJREF_UNSPEC = 0x0 + NFTA_OBJREF_IMM_TYPE = 0x1 + NFTA_OBJREF_IMM_NAME = 0x2 + NFTA_OBJREF_SET_SREG = 0x3 + NFTA_OBJREF_SET_NAME = 0x4 + NFTA_OBJREF_SET_ID = 0x5 + NFTA_GEN_UNSPEC = 0x0 + NFTA_GEN_ID = 0x1 + NFTA_GEN_PROC_PID = 0x2 + NFTA_GEN_PROC_NAME = 0x3 + NFTA_FIB_UNSPEC = 0x0 + NFTA_FIB_DREG = 0x1 + NFTA_FIB_RESULT = 0x2 + NFTA_FIB_FLAGS = 0x3 + NFT_FIB_RESULT_UNSPEC = 0x0 + NFT_FIB_RESULT_OIF = 0x1 + NFT_FIB_RESULT_OIFNAME = 0x2 + NFT_FIB_RESULT_ADDRTYPE = 0x3 + NFTA_FIB_F_SADDR = 0x1 + NFTA_FIB_F_DADDR = 0x2 + NFTA_FIB_F_MARK = 0x4 + NFTA_FIB_F_IIF = 0x8 + NFTA_FIB_F_OIF = 0x10 + NFTA_FIB_F_PRESENT = 0x20 + NFTA_CT_HELPER_UNSPEC = 0x0 + NFTA_CT_HELPER_NAME = 0x1 + NFTA_CT_HELPER_L3PROTO = 0x2 + NFTA_CT_HELPER_L4PROTO = 0x3 + NFTA_OBJ_UNSPEC = 0x0 + NFTA_OBJ_TABLE = 0x1 + NFTA_OBJ_NAME = 0x2 + NFTA_OBJ_TYPE = 0x3 + NFTA_OBJ_DATA = 0x4 + NFTA_OBJ_USE = 0x5 + NFTA_TRACE_UNSPEC = 0x0 + NFTA_TRACE_TABLE = 0x1 + NFTA_TRACE_CHAIN = 0x2 + NFTA_TRACE_RULE_HANDLE = 0x3 + NFTA_TRACE_TYPE = 0x4 + NFTA_TRACE_VERDICT = 0x5 + NFTA_TRACE_ID = 0x6 + NFTA_TRACE_LL_HEADER = 0x7 + NFTA_TRACE_NETWORK_HEADER = 0x8 + NFTA_TRACE_TRANSPORT_HEADER = 0x9 + NFTA_TRACE_IIF = 0xa + NFTA_TRACE_IIFTYPE = 0xb + NFTA_TRACE_OIF = 0xc + NFTA_TRACE_OIFTYPE = 0xd + NFTA_TRACE_MARK = 0xe + NFTA_TRACE_NFPROTO = 0xf + NFTA_TRACE_POLICY = 0x10 + NFTA_TRACE_PAD = 0x11 + NFT_TRACETYPE_UNSPEC = 0x0 + NFT_TRACETYPE_POLICY = 0x1 + NFT_TRACETYPE_RETURN = 0x2 + NFT_TRACETYPE_RULE = 0x3 + NFTA_NG_UNSPEC = 0x0 + NFTA_NG_DREG = 0x1 + NFTA_NG_MODULUS = 0x2 + NFTA_NG_TYPE = 0x3 + NFTA_NG_OFFSET = 0x4 + NFT_NG_INCREMENTAL = 0x0 + NFT_NG_RANDOM = 0x1 +) + +type RTCTime struct { + Sec int32 + Min int32 + Hour int32 + Mday int32 + Mon int32 + Year int32 + Wday int32 + Yday int32 + Isdst int32 +} + +type RTCWkAlrm struct { + Enabled uint8 + Pending uint8 + Time RTCTime +} + +type RTCPLLInfo struct { + Ctrl int32 + Value int32 + Max int32 + Min int32 + Posmult int32 + Negmult int32 + Clock int64 +} + +type BlkpgIoctlArg struct { + Op int32 + Flags int32 + Datalen int32 + Data *byte +} + +type BlkpgPartition struct { + Start int64 + Length int64 + Pno int32 + Devname [64]uint8 + Volname [64]uint8 + _ [4]byte +} + +const ( + BLKPG = 0x1269 + BLKPG_ADD_PARTITION = 0x1 + BLKPG_DEL_PARTITION = 0x2 + BLKPG_RESIZE_PARTITION = 0x3 +) + +const ( + NETNSA_NONE = 0x0 + NETNSA_NSID = 0x1 + NETNSA_PID = 0x2 + NETNSA_FD = 0x3 +) + +type XDPRingOffset struct { + Producer uint64 + Consumer uint64 + Desc uint64 +} + +type XDPMmapOffsets struct { + Rx XDPRingOffset + Tx XDPRingOffset + Fr XDPRingOffset + Cr XDPRingOffset +} + +type XDPUmemReg struct { + Addr uint64 + Len uint64 + Size uint32 + Headroom uint32 +} + +type XDPStatistics struct { + Rx_dropped uint64 + Rx_invalid_descs uint64 + Tx_invalid_descs uint64 +} + +type XDPDesc struct { + Addr uint64 + Len uint32 + Options uint32 +} + +const ( + NCSI_CMD_UNSPEC = 0x0 + NCSI_CMD_PKG_INFO = 0x1 + NCSI_CMD_SET_INTERFACE = 0x2 + NCSI_CMD_CLEAR_INTERFACE = 0x3 + NCSI_ATTR_UNSPEC = 0x0 + NCSI_ATTR_IFINDEX = 0x1 + NCSI_ATTR_PACKAGE_LIST = 0x2 + NCSI_ATTR_PACKAGE_ID = 0x3 + NCSI_ATTR_CHANNEL_ID = 0x4 + NCSI_PKG_ATTR_UNSPEC = 0x0 + NCSI_PKG_ATTR = 0x1 + NCSI_PKG_ATTR_ID = 0x2 + NCSI_PKG_ATTR_FORCED = 0x3 + NCSI_PKG_ATTR_CHANNEL_LIST = 0x4 + NCSI_CHANNEL_ATTR_UNSPEC = 0x0 + NCSI_CHANNEL_ATTR = 0x1 + NCSI_CHANNEL_ATTR_ID = 0x2 + NCSI_CHANNEL_ATTR_VERSION_MAJOR = 0x3 + NCSI_CHANNEL_ATTR_VERSION_MINOR = 0x4 + NCSI_CHANNEL_ATTR_VERSION_STR = 0x5 + NCSI_CHANNEL_ATTR_LINK_STATE = 0x6 + NCSI_CHANNEL_ATTR_ACTIVE = 0x7 + NCSI_CHANNEL_ATTR_FORCED = 0x8 + NCSI_CHANNEL_ATTR_VLAN_LIST = 0x9 + NCSI_CHANNEL_ATTR_VLAN_ID = 0xa +) + +type ScmTimestamping struct { + Ts [3]Timespec +} + +const ( + SOF_TIMESTAMPING_TX_HARDWARE = 0x1 + SOF_TIMESTAMPING_TX_SOFTWARE = 0x2 + SOF_TIMESTAMPING_RX_HARDWARE = 0x4 + SOF_TIMESTAMPING_RX_SOFTWARE = 0x8 + SOF_TIMESTAMPING_SOFTWARE = 0x10 + SOF_TIMESTAMPING_SYS_HARDWARE = 0x20 + SOF_TIMESTAMPING_RAW_HARDWARE = 0x40 + SOF_TIMESTAMPING_OPT_ID = 0x80 + SOF_TIMESTAMPING_TX_SCHED = 0x100 + SOF_TIMESTAMPING_TX_ACK = 0x200 + SOF_TIMESTAMPING_OPT_CMSG = 0x400 + SOF_TIMESTAMPING_OPT_TSONLY = 0x800 + SOF_TIMESTAMPING_OPT_STATS = 0x1000 + SOF_TIMESTAMPING_OPT_PKTINFO = 0x2000 + SOF_TIMESTAMPING_OPT_TX_SWHW = 0x4000 + + SOF_TIMESTAMPING_LAST = 0x4000 + SOF_TIMESTAMPING_MASK = 0x7fff + + SCM_TSTAMP_SND = 0x0 + SCM_TSTAMP_SCHED = 0x1 + SCM_TSTAMP_ACK = 0x2 +) + +type SockExtendedErr struct { + Errno uint32 + Origin uint8 + Type uint8 + Code uint8 + Pad uint8 + Info uint32 + Data uint32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go b/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go index 4cc0a1c91f..dbf05903d4 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go @@ -6,11 +6,11 @@ package unix const ( - sizeofPtr = 0x4 - sizeofShort = 0x2 - sizeofInt = 0x4 - sizeofLong = 0x4 - sizeofLongLong = 0x8 + SizeofPtr = 0x4 + SizeofShort = 0x2 + SizeofInt = 0x4 + SizeofLong = 0x4 + SizeofLongLong = 0x8 PathMax = 0x1000 ) @@ -52,7 +52,7 @@ type Timex struct { Errcnt int32 Stbcnt int32 Tai int32 - Pad_cgo_0 [44]byte + _ [44]byte } type Time_t int32 @@ -115,44 +115,57 @@ type Stat_t struct { Pad5 [14]int32 } -type Statfs_t struct { - Type int32 - Bsize int32 - Frsize int32 - Pad_cgo_0 [4]byte - Blocks uint64 - Bfree uint64 - Files uint64 - Ffree uint64 - Bavail uint64 - Fsid Fsid - Namelen int32 - Flags int32 - Spare [5]int32 - Pad_cgo_1 [4]byte +type StatxTimestamp struct { + Sec int64 + Nsec uint32 + _ int32 +} + +type Statx_t struct { + Mask uint32 + Blksize uint32 + Attributes uint64 + Nlink uint32 + Uid uint32 + Gid uint32 + Mode uint16 + _ [1]uint16 + Ino uint64 + Size uint64 + Blocks uint64 + Attributes_mask uint64 + Atime StatxTimestamp + Btime StatxTimestamp + Ctime StatxTimestamp + Mtime StatxTimestamp + Rdev_major uint32 + Rdev_minor uint32 + Dev_major uint32 + Dev_minor uint32 + _ [14]uint64 } type Dirent struct { - Ino uint64 - Off int64 - Reclen uint16 - Type uint8 - Name [256]int8 - Pad_cgo_0 [5]byte + Ino uint64 + Off int64 + Reclen uint16 + Type uint8 + Name [256]int8 + _ [5]byte } type Fsid struct { - X__val [2]int32 + Val [2]int32 } type Flock_t struct { - Type int16 - Whence int16 - Pad_cgo_0 [4]byte - Start int64 - Len int64 - Pid int32 - Pad_cgo_1 [4]byte + Type int16 + Whence int16 + _ [4]byte + Start int64 + Len int64 + Pid int32 + _ [4]byte } type FscryptPolicy struct { @@ -227,11 +240,26 @@ type RawSockaddrHCI struct { Channel uint16 } +type RawSockaddrL2 struct { + Family uint16 + Psm uint16 + Bdaddr [6]uint8 + Cid uint16 + Bdaddr_type uint8 + _ [1]byte +} + +type RawSockaddrRFCOMM struct { + Family uint16 + Bdaddr [6]uint8 + Channel uint8 + _ [1]byte +} + type RawSockaddrCAN struct { - Family uint16 - Pad_cgo_0 [2]byte - Ifindex int32 - Addr [8]byte + Family uint16 + Ifindex int32 + Addr [8]byte } type RawSockaddrALG struct { @@ -250,6 +278,16 @@ type RawSockaddrVM struct { Zero [4]uint8 } +type RawSockaddrXDP struct { + Family uint16 + Flags uint16 + Ifindex uint32 + Queue_id uint32 + Shared_umem_fd uint32 +} + +type RawSockaddrPPPoX [0x1e]byte + type RawSockaddr struct { Family uint16 Data [14]int8 @@ -344,7 +382,6 @@ type TCPInfo struct { Probes uint8 Backoff uint8 Options uint8 - Pad_cgo_0 [2]byte Rto uint32 Ato uint32 Snd_mss uint32 @@ -379,9 +416,13 @@ const ( SizeofSockaddrLinklayer = 0x14 SizeofSockaddrNetlink = 0xc SizeofSockaddrHCI = 0x6 + SizeofSockaddrL2 = 0xe + SizeofSockaddrRFCOMM = 0xa SizeofSockaddrCAN = 0x10 SizeofSockaddrALG = 0x58 SizeofSockaddrVM = 0x10 + SizeofSockaddrXDP = 0x10 + SizeofSockaddrPPPoX = 0x1e SizeofLinger = 0x8 SizeofIovec = 0x8 SizeofIPMreq = 0x8 @@ -399,97 +440,138 @@ const ( ) const ( - IFA_UNSPEC = 0x0 - IFA_ADDRESS = 0x1 - IFA_LOCAL = 0x2 - IFA_LABEL = 0x3 - IFA_BROADCAST = 0x4 - IFA_ANYCAST = 0x5 - IFA_CACHEINFO = 0x6 - IFA_MULTICAST = 0x7 - IFLA_UNSPEC = 0x0 - IFLA_ADDRESS = 0x1 - IFLA_BROADCAST = 0x2 - IFLA_IFNAME = 0x3 - IFLA_MTU = 0x4 - IFLA_LINK = 0x5 - IFLA_QDISC = 0x6 - IFLA_STATS = 0x7 - IFLA_COST = 0x8 - IFLA_PRIORITY = 0x9 - IFLA_MASTER = 0xa - IFLA_WIRELESS = 0xb - IFLA_PROTINFO = 0xc - IFLA_TXQLEN = 0xd - IFLA_MAP = 0xe - IFLA_WEIGHT = 0xf - IFLA_OPERSTATE = 0x10 - IFLA_LINKMODE = 0x11 - IFLA_LINKINFO = 0x12 - IFLA_NET_NS_PID = 0x13 - IFLA_IFALIAS = 0x14 - IFLA_MAX = 0x2c - RT_SCOPE_UNIVERSE = 0x0 - RT_SCOPE_SITE = 0xc8 - RT_SCOPE_LINK = 0xfd - RT_SCOPE_HOST = 0xfe - RT_SCOPE_NOWHERE = 0xff - RT_TABLE_UNSPEC = 0x0 - RT_TABLE_COMPAT = 0xfc - RT_TABLE_DEFAULT = 0xfd - RT_TABLE_MAIN = 0xfe - RT_TABLE_LOCAL = 0xff - RT_TABLE_MAX = 0xffffffff - RTA_UNSPEC = 0x0 - RTA_DST = 0x1 - RTA_SRC = 0x2 - RTA_IIF = 0x3 - RTA_OIF = 0x4 - RTA_GATEWAY = 0x5 - RTA_PRIORITY = 0x6 - RTA_PREFSRC = 0x7 - RTA_METRICS = 0x8 - RTA_MULTIPATH = 0x9 - RTA_FLOW = 0xb - RTA_CACHEINFO = 0xc - RTA_TABLE = 0xf - RTN_UNSPEC = 0x0 - RTN_UNICAST = 0x1 - RTN_LOCAL = 0x2 - RTN_BROADCAST = 0x3 - RTN_ANYCAST = 0x4 - RTN_MULTICAST = 0x5 - RTN_BLACKHOLE = 0x6 - RTN_UNREACHABLE = 0x7 - RTN_PROHIBIT = 0x8 - RTN_THROW = 0x9 - RTN_NAT = 0xa - RTN_XRESOLVE = 0xb - RTNLGRP_NONE = 0x0 - RTNLGRP_LINK = 0x1 - RTNLGRP_NOTIFY = 0x2 - RTNLGRP_NEIGH = 0x3 - RTNLGRP_TC = 0x4 - RTNLGRP_IPV4_IFADDR = 0x5 - RTNLGRP_IPV4_MROUTE = 0x6 - RTNLGRP_IPV4_ROUTE = 0x7 - RTNLGRP_IPV4_RULE = 0x8 - RTNLGRP_IPV6_IFADDR = 0x9 - RTNLGRP_IPV6_MROUTE = 0xa - RTNLGRP_IPV6_ROUTE = 0xb - RTNLGRP_IPV6_IFINFO = 0xc - RTNLGRP_IPV6_PREFIX = 0x12 - RTNLGRP_IPV6_RULE = 0x13 - RTNLGRP_ND_USEROPT = 0x14 - SizeofNlMsghdr = 0x10 - SizeofNlMsgerr = 0x14 - SizeofRtGenmsg = 0x1 - SizeofNlAttr = 0x4 - SizeofRtAttr = 0x4 - SizeofIfInfomsg = 0x10 - SizeofIfAddrmsg = 0x8 - SizeofRtMsg = 0xc - SizeofRtNexthop = 0x8 + IFA_UNSPEC = 0x0 + IFA_ADDRESS = 0x1 + IFA_LOCAL = 0x2 + IFA_LABEL = 0x3 + IFA_BROADCAST = 0x4 + IFA_ANYCAST = 0x5 + IFA_CACHEINFO = 0x6 + IFA_MULTICAST = 0x7 + IFLA_UNSPEC = 0x0 + IFLA_ADDRESS = 0x1 + IFLA_BROADCAST = 0x2 + IFLA_IFNAME = 0x3 + IFLA_INFO_KIND = 0x1 + IFLA_MTU = 0x4 + IFLA_LINK = 0x5 + IFLA_QDISC = 0x6 + IFLA_STATS = 0x7 + IFLA_COST = 0x8 + IFLA_PRIORITY = 0x9 + IFLA_MASTER = 0xa + IFLA_WIRELESS = 0xb + IFLA_PROTINFO = 0xc + IFLA_TXQLEN = 0xd + IFLA_MAP = 0xe + IFLA_WEIGHT = 0xf + IFLA_OPERSTATE = 0x10 + IFLA_LINKMODE = 0x11 + IFLA_LINKINFO = 0x12 + IFLA_NET_NS_PID = 0x13 + IFLA_IFALIAS = 0x14 + IFLA_NUM_VF = 0x15 + IFLA_VFINFO_LIST = 0x16 + IFLA_STATS64 = 0x17 + IFLA_VF_PORTS = 0x18 + IFLA_PORT_SELF = 0x19 + IFLA_AF_SPEC = 0x1a + IFLA_GROUP = 0x1b + IFLA_NET_NS_FD = 0x1c + IFLA_EXT_MASK = 0x1d + IFLA_PROMISCUITY = 0x1e + IFLA_NUM_TX_QUEUES = 0x1f + IFLA_NUM_RX_QUEUES = 0x20 + IFLA_CARRIER = 0x21 + IFLA_PHYS_PORT_ID = 0x22 + IFLA_CARRIER_CHANGES = 0x23 + IFLA_PHYS_SWITCH_ID = 0x24 + IFLA_LINK_NETNSID = 0x25 + IFLA_PHYS_PORT_NAME = 0x26 + IFLA_PROTO_DOWN = 0x27 + IFLA_GSO_MAX_SEGS = 0x28 + IFLA_GSO_MAX_SIZE = 0x29 + IFLA_PAD = 0x2a + IFLA_XDP = 0x2b + IFLA_EVENT = 0x2c + IFLA_NEW_NETNSID = 0x2d + IFLA_IF_NETNSID = 0x2e + IFLA_MAX = 0x33 + RT_SCOPE_UNIVERSE = 0x0 + RT_SCOPE_SITE = 0xc8 + RT_SCOPE_LINK = 0xfd + RT_SCOPE_HOST = 0xfe + RT_SCOPE_NOWHERE = 0xff + RT_TABLE_UNSPEC = 0x0 + RT_TABLE_COMPAT = 0xfc + RT_TABLE_DEFAULT = 0xfd + RT_TABLE_MAIN = 0xfe + RT_TABLE_LOCAL = 0xff + RT_TABLE_MAX = 0xffffffff + RTA_UNSPEC = 0x0 + RTA_DST = 0x1 + RTA_SRC = 0x2 + RTA_IIF = 0x3 + RTA_OIF = 0x4 + RTA_GATEWAY = 0x5 + RTA_PRIORITY = 0x6 + RTA_PREFSRC = 0x7 + RTA_METRICS = 0x8 + RTA_MULTIPATH = 0x9 + RTA_FLOW = 0xb + RTA_CACHEINFO = 0xc + RTA_TABLE = 0xf + RTA_MARK = 0x10 + RTA_MFC_STATS = 0x11 + RTA_VIA = 0x12 + RTA_NEWDST = 0x13 + RTA_PREF = 0x14 + RTA_ENCAP_TYPE = 0x15 + RTA_ENCAP = 0x16 + RTA_EXPIRES = 0x17 + RTA_PAD = 0x18 + RTA_UID = 0x19 + RTA_TTL_PROPAGATE = 0x1a + RTA_IP_PROTO = 0x1b + RTA_SPORT = 0x1c + RTA_DPORT = 0x1d + RTN_UNSPEC = 0x0 + RTN_UNICAST = 0x1 + RTN_LOCAL = 0x2 + RTN_BROADCAST = 0x3 + RTN_ANYCAST = 0x4 + RTN_MULTICAST = 0x5 + RTN_BLACKHOLE = 0x6 + RTN_UNREACHABLE = 0x7 + RTN_PROHIBIT = 0x8 + RTN_THROW = 0x9 + RTN_NAT = 0xa + RTN_XRESOLVE = 0xb + RTNLGRP_NONE = 0x0 + RTNLGRP_LINK = 0x1 + RTNLGRP_NOTIFY = 0x2 + RTNLGRP_NEIGH = 0x3 + RTNLGRP_TC = 0x4 + RTNLGRP_IPV4_IFADDR = 0x5 + RTNLGRP_IPV4_MROUTE = 0x6 + RTNLGRP_IPV4_ROUTE = 0x7 + RTNLGRP_IPV4_RULE = 0x8 + RTNLGRP_IPV6_IFADDR = 0x9 + RTNLGRP_IPV6_MROUTE = 0xa + RTNLGRP_IPV6_ROUTE = 0xb + RTNLGRP_IPV6_IFINFO = 0xc + RTNLGRP_IPV6_PREFIX = 0x12 + RTNLGRP_IPV6_RULE = 0x13 + RTNLGRP_ND_USEROPT = 0x14 + SizeofNlMsghdr = 0x10 + SizeofNlMsgerr = 0x14 + SizeofRtGenmsg = 0x1 + SizeofNlAttr = 0x4 + SizeofRtAttr = 0x4 + SizeofIfInfomsg = 0x10 + SizeofIfAddrmsg = 0x8 + SizeofRtMsg = 0xc + SizeofRtNexthop = 0x8 ) type NlMsghdr struct { @@ -520,12 +602,12 @@ type RtAttr struct { } type IfInfomsg struct { - Family uint8 - X__ifi_pad uint8 - Type uint16 - Index int32 - Flags uint32 - Change uint32 + Family uint8 + _ uint8 + Type uint16 + Index int32 + Flags uint32 + Change uint32 } type IfAddrmsg struct { @@ -568,9 +650,8 @@ type SockFilter struct { } type SockFprog struct { - Len uint16 - Pad_cgo_0 [2]byte - Filter *SockFilter + Len uint16 + Filter *SockFilter } type InotifyEvent struct { @@ -610,7 +691,7 @@ type Sysinfo_t struct { Totalhigh uint32 Freehigh uint32 Unit uint32 - X_f [8]int8 + _ [8]int8 } type Utsname struct { @@ -637,10 +718,19 @@ type EpollEvent struct { } const ( - AT_FDCWD = -0x64 - AT_REMOVEDIR = 0x200 + AT_EMPTY_PATH = 0x1000 + AT_FDCWD = -0x64 + AT_NO_AUTOMOUNT = 0x800 + AT_REMOVEDIR = 0x200 + + AT_STATX_SYNC_AS_STAT = 0x0 + AT_STATX_FORCE_SYNC = 0x2000 + AT_STATX_DONT_SYNC = 0x4000 + AT_SYMLINK_FOLLOW = 0x400 AT_SYMLINK_NOFOLLOW = 0x100 + + AT_EACCESS = 0x200 ) type PollFd struct { @@ -660,10 +750,33 @@ const ( ) type Sigset_t struct { - X__val [32]uint32 + Val [32]uint32 } -const RNDGETENTCNT = 0x40045200 +type SignalfdSiginfo struct { + Signo uint32 + Errno int32 + Code int32 + Pid uint32 + Uid uint32 + Fd int32 + Tid uint32 + Band uint32 + Overrun uint32 + Trapno uint32 + Status int32 + Int int32 + Ptr uint64 + Utime uint64 + Stime uint64 + Addr uint64 + Addr_lsb uint16 + _ uint16 + Syscall int32 + Call_addr uint64 + Arch uint32 + _ [28]uint8 +} const PERF_IOC_FLAG_GROUP = 0x1 @@ -687,11 +800,10 @@ type Winsize struct { type Taskstats struct { Version uint16 - Pad_cgo_0 [2]byte Ac_exitcode uint32 Ac_flag uint8 Ac_nice uint8 - Pad_cgo_1 [6]byte + _ [4]byte Cpu_count uint64 Cpu_delay_total uint64 Blkio_count uint64 @@ -703,13 +815,13 @@ type Taskstats struct { Ac_comm [32]int8 Ac_sched uint8 Ac_pad [3]uint8 - Pad_cgo_2 [4]byte + _ [4]byte Ac_uid uint32 Ac_gid uint32 Ac_pid uint32 Ac_ppid uint32 Ac_btime uint32 - Pad_cgo_3 [4]byte + _ [4]byte Ac_etime uint64 Ac_utime uint64 Ac_stime uint64 @@ -733,6 +845,8 @@ type Taskstats struct { Cpu_scaled_run_real_total uint64 Freepages_count uint64 Freepages_delay_total uint64 + Thrashing_count uint64 + Thrashing_delay_total uint64 } const ( @@ -753,6 +867,24 @@ const ( TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK = 0x4 ) +type CGroupStats struct { + Sleeping uint64 + Running uint64 + Stopped uint64 + Uninterruptible uint64 + Io_wait uint64 +} + +const ( + CGROUPSTATS_CMD_UNSPEC = 0x3 + CGROUPSTATS_CMD_GET = 0x4 + CGROUPSTATS_CMD_NEW = 0x5 + CGROUPSTATS_TYPE_UNSPEC = 0x0 + CGROUPSTATS_TYPE_CGROUP_STATS = 0x1 + CGROUPSTATS_CMD_ATTR_UNSPEC = 0x0 + CGROUPSTATS_CMD_ATTR_FD = 0x1 +) + type Genlmsghdr struct { Cmd uint8 Version uint8 @@ -785,3 +917,1108 @@ const ( CTRL_ATTR_MCAST_GRP_NAME = 0x1 CTRL_ATTR_MCAST_GRP_ID = 0x2 ) + +type cpuMask uint32 + +const ( + _CPU_SETSIZE = 0x400 + _NCPUBITS = 0x20 +) + +const ( + BDADDR_BREDR = 0x0 + BDADDR_LE_PUBLIC = 0x1 + BDADDR_LE_RANDOM = 0x2 +) + +type PerfEventAttr struct { + Type uint32 + Size uint32 + Config uint64 + Sample uint64 + Sample_type uint64 + Read_format uint64 + Bits uint64 + Wakeup uint32 + Bp_type uint32 + Ext1 uint64 + Ext2 uint64 + Branch_sample_type uint64 + Sample_regs_user uint64 + Sample_stack_user uint32 + Clockid int32 + Sample_regs_intr uint64 + Aux_watermark uint32 + _ uint32 +} + +type PerfEventMmapPage struct { + Version uint32 + Compat_version uint32 + Lock uint32 + Index uint32 + Offset int64 + Time_enabled uint64 + Time_running uint64 + Capabilities uint64 + Pmc_width uint16 + Time_shift uint16 + Time_mult uint32 + Time_offset uint64 + Time_zero uint64 + Size uint32 + _ [948]uint8 + Data_head uint64 + Data_tail uint64 + Data_offset uint64 + Data_size uint64 + Aux_head uint64 + Aux_tail uint64 + Aux_offset uint64 + Aux_size uint64 +} + +const ( + PerfBitDisabled uint64 = CBitFieldMaskBit0 + PerfBitInherit = CBitFieldMaskBit1 + PerfBitPinned = CBitFieldMaskBit2 + PerfBitExclusive = CBitFieldMaskBit3 + PerfBitExcludeUser = CBitFieldMaskBit4 + PerfBitExcludeKernel = CBitFieldMaskBit5 + PerfBitExcludeHv = CBitFieldMaskBit6 + PerfBitExcludeIdle = CBitFieldMaskBit7 + PerfBitMmap = CBitFieldMaskBit8 + PerfBitComm = CBitFieldMaskBit9 + PerfBitFreq = CBitFieldMaskBit10 + PerfBitInheritStat = CBitFieldMaskBit11 + PerfBitEnableOnExec = CBitFieldMaskBit12 + PerfBitTask = CBitFieldMaskBit13 + PerfBitWatermark = CBitFieldMaskBit14 + PerfBitPreciseIPBit1 = CBitFieldMaskBit15 + PerfBitPreciseIPBit2 = CBitFieldMaskBit16 + PerfBitMmapData = CBitFieldMaskBit17 + PerfBitSampleIDAll = CBitFieldMaskBit18 + PerfBitExcludeHost = CBitFieldMaskBit19 + PerfBitExcludeGuest = CBitFieldMaskBit20 + PerfBitExcludeCallchainKernel = CBitFieldMaskBit21 + PerfBitExcludeCallchainUser = CBitFieldMaskBit22 + PerfBitMmap2 = CBitFieldMaskBit23 + PerfBitCommExec = CBitFieldMaskBit24 + PerfBitUseClockID = CBitFieldMaskBit25 + PerfBitContextSwitch = CBitFieldMaskBit26 +) + +const ( + PERF_TYPE_HARDWARE = 0x0 + PERF_TYPE_SOFTWARE = 0x1 + PERF_TYPE_TRACEPOINT = 0x2 + PERF_TYPE_HW_CACHE = 0x3 + PERF_TYPE_RAW = 0x4 + PERF_TYPE_BREAKPOINT = 0x5 + + PERF_COUNT_HW_CPU_CYCLES = 0x0 + PERF_COUNT_HW_INSTRUCTIONS = 0x1 + PERF_COUNT_HW_CACHE_REFERENCES = 0x2 + PERF_COUNT_HW_CACHE_MISSES = 0x3 + PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 0x4 + PERF_COUNT_HW_BRANCH_MISSES = 0x5 + PERF_COUNT_HW_BUS_CYCLES = 0x6 + PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 0x7 + PERF_COUNT_HW_STALLED_CYCLES_BACKEND = 0x8 + PERF_COUNT_HW_REF_CPU_CYCLES = 0x9 + + PERF_COUNT_HW_CACHE_L1D = 0x0 + PERF_COUNT_HW_CACHE_L1I = 0x1 + PERF_COUNT_HW_CACHE_LL = 0x2 + PERF_COUNT_HW_CACHE_DTLB = 0x3 + PERF_COUNT_HW_CACHE_ITLB = 0x4 + PERF_COUNT_HW_CACHE_BPU = 0x5 + PERF_COUNT_HW_CACHE_NODE = 0x6 + + PERF_COUNT_HW_CACHE_OP_READ = 0x0 + PERF_COUNT_HW_CACHE_OP_WRITE = 0x1 + PERF_COUNT_HW_CACHE_OP_PREFETCH = 0x2 + + PERF_COUNT_HW_CACHE_RESULT_ACCESS = 0x0 + PERF_COUNT_HW_CACHE_RESULT_MISS = 0x1 + + PERF_COUNT_SW_CPU_CLOCK = 0x0 + PERF_COUNT_SW_TASK_CLOCK = 0x1 + PERF_COUNT_SW_PAGE_FAULTS = 0x2 + PERF_COUNT_SW_CONTEXT_SWITCHES = 0x3 + PERF_COUNT_SW_CPU_MIGRATIONS = 0x4 + PERF_COUNT_SW_PAGE_FAULTS_MIN = 0x5 + PERF_COUNT_SW_PAGE_FAULTS_MAJ = 0x6 + PERF_COUNT_SW_ALIGNMENT_FAULTS = 0x7 + PERF_COUNT_SW_EMULATION_FAULTS = 0x8 + PERF_COUNT_SW_DUMMY = 0x9 + + PERF_SAMPLE_IP = 0x1 + PERF_SAMPLE_TID = 0x2 + PERF_SAMPLE_TIME = 0x4 + PERF_SAMPLE_ADDR = 0x8 + PERF_SAMPLE_READ = 0x10 + PERF_SAMPLE_CALLCHAIN = 0x20 + PERF_SAMPLE_ID = 0x40 + PERF_SAMPLE_CPU = 0x80 + PERF_SAMPLE_PERIOD = 0x100 + PERF_SAMPLE_STREAM_ID = 0x200 + PERF_SAMPLE_RAW = 0x400 + PERF_SAMPLE_BRANCH_STACK = 0x800 + + PERF_SAMPLE_BRANCH_USER = 0x1 + PERF_SAMPLE_BRANCH_KERNEL = 0x2 + PERF_SAMPLE_BRANCH_HV = 0x4 + PERF_SAMPLE_BRANCH_ANY = 0x8 + PERF_SAMPLE_BRANCH_ANY_CALL = 0x10 + PERF_SAMPLE_BRANCH_ANY_RETURN = 0x20 + PERF_SAMPLE_BRANCH_IND_CALL = 0x40 + + PERF_FORMAT_TOTAL_TIME_ENABLED = 0x1 + PERF_FORMAT_TOTAL_TIME_RUNNING = 0x2 + PERF_FORMAT_ID = 0x4 + PERF_FORMAT_GROUP = 0x8 + + PERF_RECORD_MMAP = 0x1 + PERF_RECORD_LOST = 0x2 + PERF_RECORD_COMM = 0x3 + PERF_RECORD_EXIT = 0x4 + PERF_RECORD_THROTTLE = 0x5 + PERF_RECORD_UNTHROTTLE = 0x6 + PERF_RECORD_FORK = 0x7 + PERF_RECORD_READ = 0x8 + PERF_RECORD_SAMPLE = 0x9 + + PERF_CONTEXT_HV = -0x20 + PERF_CONTEXT_KERNEL = -0x80 + PERF_CONTEXT_USER = -0x200 + + PERF_CONTEXT_GUEST = -0x800 + PERF_CONTEXT_GUEST_KERNEL = -0x880 + PERF_CONTEXT_GUEST_USER = -0xa00 + + PERF_FLAG_FD_NO_GROUP = 0x1 + PERF_FLAG_FD_OUTPUT = 0x2 + PERF_FLAG_PID_CGROUP = 0x4 +) + +const ( + CBitFieldMaskBit0 = 0x8000000000000000 + CBitFieldMaskBit1 = 0x4000000000000000 + CBitFieldMaskBit2 = 0x2000000000000000 + CBitFieldMaskBit3 = 0x1000000000000000 + CBitFieldMaskBit4 = 0x800000000000000 + CBitFieldMaskBit5 = 0x400000000000000 + CBitFieldMaskBit6 = 0x200000000000000 + CBitFieldMaskBit7 = 0x100000000000000 + CBitFieldMaskBit8 = 0x80000000000000 + CBitFieldMaskBit9 = 0x40000000000000 + CBitFieldMaskBit10 = 0x20000000000000 + CBitFieldMaskBit11 = 0x10000000000000 + CBitFieldMaskBit12 = 0x8000000000000 + CBitFieldMaskBit13 = 0x4000000000000 + CBitFieldMaskBit14 = 0x2000000000000 + CBitFieldMaskBit15 = 0x1000000000000 + CBitFieldMaskBit16 = 0x800000000000 + CBitFieldMaskBit17 = 0x400000000000 + CBitFieldMaskBit18 = 0x200000000000 + CBitFieldMaskBit19 = 0x100000000000 + CBitFieldMaskBit20 = 0x80000000000 + CBitFieldMaskBit21 = 0x40000000000 + CBitFieldMaskBit22 = 0x20000000000 + CBitFieldMaskBit23 = 0x10000000000 + CBitFieldMaskBit24 = 0x8000000000 + CBitFieldMaskBit25 = 0x4000000000 + CBitFieldMaskBit26 = 0x2000000000 + CBitFieldMaskBit27 = 0x1000000000 + CBitFieldMaskBit28 = 0x800000000 + CBitFieldMaskBit29 = 0x400000000 + CBitFieldMaskBit30 = 0x200000000 + CBitFieldMaskBit31 = 0x100000000 + CBitFieldMaskBit32 = 0x80000000 + CBitFieldMaskBit33 = 0x40000000 + CBitFieldMaskBit34 = 0x20000000 + CBitFieldMaskBit35 = 0x10000000 + CBitFieldMaskBit36 = 0x8000000 + CBitFieldMaskBit37 = 0x4000000 + CBitFieldMaskBit38 = 0x2000000 + CBitFieldMaskBit39 = 0x1000000 + CBitFieldMaskBit40 = 0x800000 + CBitFieldMaskBit41 = 0x400000 + CBitFieldMaskBit42 = 0x200000 + CBitFieldMaskBit43 = 0x100000 + CBitFieldMaskBit44 = 0x80000 + CBitFieldMaskBit45 = 0x40000 + CBitFieldMaskBit46 = 0x20000 + CBitFieldMaskBit47 = 0x10000 + CBitFieldMaskBit48 = 0x8000 + CBitFieldMaskBit49 = 0x4000 + CBitFieldMaskBit50 = 0x2000 + CBitFieldMaskBit51 = 0x1000 + CBitFieldMaskBit52 = 0x800 + CBitFieldMaskBit53 = 0x400 + CBitFieldMaskBit54 = 0x200 + CBitFieldMaskBit55 = 0x100 + CBitFieldMaskBit56 = 0x80 + CBitFieldMaskBit57 = 0x40 + CBitFieldMaskBit58 = 0x20 + CBitFieldMaskBit59 = 0x10 + CBitFieldMaskBit60 = 0x8 + CBitFieldMaskBit61 = 0x4 + CBitFieldMaskBit62 = 0x2 + CBitFieldMaskBit63 = 0x1 +) + +type SockaddrStorage struct { + Family uint16 + _ [122]int8 + _ uint32 +} + +type TCPMD5Sig struct { + Addr SockaddrStorage + Flags uint8 + Prefixlen uint8 + Keylen uint16 + _ uint32 + Key [80]uint8 +} + +type HDDriveCmdHdr struct { + Command uint8 + Number uint8 + Feature uint8 + Count uint8 +} + +type HDGeometry struct { + Heads uint8 + Sectors uint8 + Cylinders uint16 + Start uint32 +} + +type HDDriveID struct { + Config uint16 + Cyls uint16 + Reserved2 uint16 + Heads uint16 + Track_bytes uint16 + Sector_bytes uint16 + Sectors uint16 + Vendor0 uint16 + Vendor1 uint16 + Vendor2 uint16 + Serial_no [20]uint8 + Buf_type uint16 + Buf_size uint16 + Ecc_bytes uint16 + Fw_rev [8]uint8 + Model [40]uint8 + Max_multsect uint8 + Vendor3 uint8 + Dword_io uint16 + Vendor4 uint8 + Capability uint8 + Reserved50 uint16 + Vendor5 uint8 + TPIO uint8 + Vendor6 uint8 + TDMA uint8 + Field_valid uint16 + Cur_cyls uint16 + Cur_heads uint16 + Cur_sectors uint16 + Cur_capacity0 uint16 + Cur_capacity1 uint16 + Multsect uint8 + Multsect_valid uint8 + Lba_capacity uint32 + Dma_1word uint16 + Dma_mword uint16 + Eide_pio_modes uint16 + Eide_dma_min uint16 + Eide_dma_time uint16 + Eide_pio uint16 + Eide_pio_iordy uint16 + Words69_70 [2]uint16 + Words71_74 [4]uint16 + Queue_depth uint16 + Words76_79 [4]uint16 + Major_rev_num uint16 + Minor_rev_num uint16 + Command_set_1 uint16 + Command_set_2 uint16 + Cfsse uint16 + Cfs_enable_1 uint16 + Cfs_enable_2 uint16 + Csf_default uint16 + Dma_ultra uint16 + Trseuc uint16 + TrsEuc uint16 + CurAPMvalues uint16 + Mprc uint16 + Hw_config uint16 + Acoustic uint16 + Msrqs uint16 + Sxfert uint16 + Sal uint16 + Spg uint32 + Lba_capacity_2 uint64 + Words104_125 [22]uint16 + Last_lun uint16 + Word127 uint16 + Dlf uint16 + Csfo uint16 + Words130_155 [26]uint16 + Word156 uint16 + Words157_159 [3]uint16 + Cfa_power uint16 + Words161_175 [15]uint16 + Words176_205 [30]uint16 + Words206_254 [49]uint16 + Integrity_word uint16 +} + +type Statfs_t struct { + Type int32 + Bsize int32 + Frsize int32 + _ [4]byte + Blocks uint64 + Bfree uint64 + Files uint64 + Ffree uint64 + Bavail uint64 + Fsid Fsid + Namelen int32 + Flags int32 + Spare [5]int32 + _ [4]byte +} + +const ( + ST_MANDLOCK = 0x40 + ST_NOATIME = 0x400 + ST_NODEV = 0x4 + ST_NODIRATIME = 0x800 + ST_NOEXEC = 0x8 + ST_NOSUID = 0x2 + ST_RDONLY = 0x1 + ST_RELATIME = 0x1000 + ST_SYNCHRONOUS = 0x10 +) + +type TpacketHdr struct { + Status uint32 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Sec uint32 + Usec uint32 +} + +type Tpacket2Hdr struct { + Status uint32 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Sec uint32 + Nsec uint32 + Vlan_tci uint16 + Vlan_tpid uint16 + _ [4]uint8 +} + +type Tpacket3Hdr struct { + Next_offset uint32 + Sec uint32 + Nsec uint32 + Snaplen uint32 + Len uint32 + Status uint32 + Mac uint16 + Net uint16 + Hv1 TpacketHdrVariant1 + _ [8]uint8 +} + +type TpacketHdrVariant1 struct { + Rxhash uint32 + Vlan_tci uint32 + Vlan_tpid uint16 + _ uint16 +} + +type TpacketBlockDesc struct { + Version uint32 + To_priv uint32 + Hdr [40]byte +} + +type TpacketReq struct { + Block_size uint32 + Block_nr uint32 + Frame_size uint32 + Frame_nr uint32 +} + +type TpacketReq3 struct { + Block_size uint32 + Block_nr uint32 + Frame_size uint32 + Frame_nr uint32 + Retire_blk_tov uint32 + Sizeof_priv uint32 + Feature_req_word uint32 +} + +type TpacketStats struct { + Packets uint32 + Drops uint32 +} + +type TpacketStatsV3 struct { + Packets uint32 + Drops uint32 + Freeze_q_cnt uint32 +} + +type TpacketAuxdata struct { + Status uint32 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Vlan_tci uint16 + Vlan_tpid uint16 +} + +const ( + TPACKET_V1 = 0x0 + TPACKET_V2 = 0x1 + TPACKET_V3 = 0x2 +) + +const ( + SizeofTpacketHdr = 0x18 + SizeofTpacket2Hdr = 0x20 + SizeofTpacket3Hdr = 0x30 +) + +const ( + NF_INET_PRE_ROUTING = 0x0 + NF_INET_LOCAL_IN = 0x1 + NF_INET_FORWARD = 0x2 + NF_INET_LOCAL_OUT = 0x3 + NF_INET_POST_ROUTING = 0x4 + NF_INET_NUMHOOKS = 0x5 +) + +const ( + NF_NETDEV_INGRESS = 0x0 + NF_NETDEV_NUMHOOKS = 0x1 +) + +const ( + NFPROTO_UNSPEC = 0x0 + NFPROTO_INET = 0x1 + NFPROTO_IPV4 = 0x2 + NFPROTO_ARP = 0x3 + NFPROTO_NETDEV = 0x5 + NFPROTO_BRIDGE = 0x7 + NFPROTO_IPV6 = 0xa + NFPROTO_DECNET = 0xc + NFPROTO_NUMPROTO = 0xd +) + +type Nfgenmsg struct { + Nfgen_family uint8 + Version uint8 + Res_id uint16 +} + +const ( + NFNL_BATCH_UNSPEC = 0x0 + NFNL_BATCH_GENID = 0x1 +) + +const ( + NFT_REG_VERDICT = 0x0 + NFT_REG_1 = 0x1 + NFT_REG_2 = 0x2 + NFT_REG_3 = 0x3 + NFT_REG_4 = 0x4 + NFT_REG32_00 = 0x8 + NFT_REG32_01 = 0x9 + NFT_REG32_02 = 0xa + NFT_REG32_03 = 0xb + NFT_REG32_04 = 0xc + NFT_REG32_05 = 0xd + NFT_REG32_06 = 0xe + NFT_REG32_07 = 0xf + NFT_REG32_08 = 0x10 + NFT_REG32_09 = 0x11 + NFT_REG32_10 = 0x12 + NFT_REG32_11 = 0x13 + NFT_REG32_12 = 0x14 + NFT_REG32_13 = 0x15 + NFT_REG32_14 = 0x16 + NFT_REG32_15 = 0x17 + NFT_CONTINUE = -0x1 + NFT_BREAK = -0x2 + NFT_JUMP = -0x3 + NFT_GOTO = -0x4 + NFT_RETURN = -0x5 + NFT_MSG_NEWTABLE = 0x0 + NFT_MSG_GETTABLE = 0x1 + NFT_MSG_DELTABLE = 0x2 + NFT_MSG_NEWCHAIN = 0x3 + NFT_MSG_GETCHAIN = 0x4 + NFT_MSG_DELCHAIN = 0x5 + NFT_MSG_NEWRULE = 0x6 + NFT_MSG_GETRULE = 0x7 + NFT_MSG_DELRULE = 0x8 + NFT_MSG_NEWSET = 0x9 + NFT_MSG_GETSET = 0xa + NFT_MSG_DELSET = 0xb + NFT_MSG_NEWSETELEM = 0xc + NFT_MSG_GETSETELEM = 0xd + NFT_MSG_DELSETELEM = 0xe + NFT_MSG_NEWGEN = 0xf + NFT_MSG_GETGEN = 0x10 + NFT_MSG_TRACE = 0x11 + NFT_MSG_NEWOBJ = 0x12 + NFT_MSG_GETOBJ = 0x13 + NFT_MSG_DELOBJ = 0x14 + NFT_MSG_GETOBJ_RESET = 0x15 + NFT_MSG_MAX = 0x19 + NFTA_LIST_UNPEC = 0x0 + NFTA_LIST_ELEM = 0x1 + NFTA_HOOK_UNSPEC = 0x0 + NFTA_HOOK_HOOKNUM = 0x1 + NFTA_HOOK_PRIORITY = 0x2 + NFTA_HOOK_DEV = 0x3 + NFT_TABLE_F_DORMANT = 0x1 + NFTA_TABLE_UNSPEC = 0x0 + NFTA_TABLE_NAME = 0x1 + NFTA_TABLE_FLAGS = 0x2 + NFTA_TABLE_USE = 0x3 + NFTA_CHAIN_UNSPEC = 0x0 + NFTA_CHAIN_TABLE = 0x1 + NFTA_CHAIN_HANDLE = 0x2 + NFTA_CHAIN_NAME = 0x3 + NFTA_CHAIN_HOOK = 0x4 + NFTA_CHAIN_POLICY = 0x5 + NFTA_CHAIN_USE = 0x6 + NFTA_CHAIN_TYPE = 0x7 + NFTA_CHAIN_COUNTERS = 0x8 + NFTA_CHAIN_PAD = 0x9 + NFTA_RULE_UNSPEC = 0x0 + NFTA_RULE_TABLE = 0x1 + NFTA_RULE_CHAIN = 0x2 + NFTA_RULE_HANDLE = 0x3 + NFTA_RULE_EXPRESSIONS = 0x4 + NFTA_RULE_COMPAT = 0x5 + NFTA_RULE_POSITION = 0x6 + NFTA_RULE_USERDATA = 0x7 + NFTA_RULE_PAD = 0x8 + NFTA_RULE_ID = 0x9 + NFT_RULE_COMPAT_F_INV = 0x2 + NFT_RULE_COMPAT_F_MASK = 0x2 + NFTA_RULE_COMPAT_UNSPEC = 0x0 + NFTA_RULE_COMPAT_PROTO = 0x1 + NFTA_RULE_COMPAT_FLAGS = 0x2 + NFT_SET_ANONYMOUS = 0x1 + NFT_SET_CONSTANT = 0x2 + NFT_SET_INTERVAL = 0x4 + NFT_SET_MAP = 0x8 + NFT_SET_TIMEOUT = 0x10 + NFT_SET_EVAL = 0x20 + NFT_SET_OBJECT = 0x40 + NFT_SET_POL_PERFORMANCE = 0x0 + NFT_SET_POL_MEMORY = 0x1 + NFTA_SET_DESC_UNSPEC = 0x0 + NFTA_SET_DESC_SIZE = 0x1 + NFTA_SET_UNSPEC = 0x0 + NFTA_SET_TABLE = 0x1 + NFTA_SET_NAME = 0x2 + NFTA_SET_FLAGS = 0x3 + NFTA_SET_KEY_TYPE = 0x4 + NFTA_SET_KEY_LEN = 0x5 + NFTA_SET_DATA_TYPE = 0x6 + NFTA_SET_DATA_LEN = 0x7 + NFTA_SET_POLICY = 0x8 + NFTA_SET_DESC = 0x9 + NFTA_SET_ID = 0xa + NFTA_SET_TIMEOUT = 0xb + NFTA_SET_GC_INTERVAL = 0xc + NFTA_SET_USERDATA = 0xd + NFTA_SET_PAD = 0xe + NFTA_SET_OBJ_TYPE = 0xf + NFT_SET_ELEM_INTERVAL_END = 0x1 + NFTA_SET_ELEM_UNSPEC = 0x0 + NFTA_SET_ELEM_KEY = 0x1 + NFTA_SET_ELEM_DATA = 0x2 + NFTA_SET_ELEM_FLAGS = 0x3 + NFTA_SET_ELEM_TIMEOUT = 0x4 + NFTA_SET_ELEM_EXPIRATION = 0x5 + NFTA_SET_ELEM_USERDATA = 0x6 + NFTA_SET_ELEM_EXPR = 0x7 + NFTA_SET_ELEM_PAD = 0x8 + NFTA_SET_ELEM_OBJREF = 0x9 + NFTA_SET_ELEM_LIST_UNSPEC = 0x0 + NFTA_SET_ELEM_LIST_TABLE = 0x1 + NFTA_SET_ELEM_LIST_SET = 0x2 + NFTA_SET_ELEM_LIST_ELEMENTS = 0x3 + NFTA_SET_ELEM_LIST_SET_ID = 0x4 + NFT_DATA_VALUE = 0x0 + NFT_DATA_VERDICT = 0xffffff00 + NFTA_DATA_UNSPEC = 0x0 + NFTA_DATA_VALUE = 0x1 + NFTA_DATA_VERDICT = 0x2 + NFTA_VERDICT_UNSPEC = 0x0 + NFTA_VERDICT_CODE = 0x1 + NFTA_VERDICT_CHAIN = 0x2 + NFTA_EXPR_UNSPEC = 0x0 + NFTA_EXPR_NAME = 0x1 + NFTA_EXPR_DATA = 0x2 + NFTA_IMMEDIATE_UNSPEC = 0x0 + NFTA_IMMEDIATE_DREG = 0x1 + NFTA_IMMEDIATE_DATA = 0x2 + NFTA_BITWISE_UNSPEC = 0x0 + NFTA_BITWISE_SREG = 0x1 + NFTA_BITWISE_DREG = 0x2 + NFTA_BITWISE_LEN = 0x3 + NFTA_BITWISE_MASK = 0x4 + NFTA_BITWISE_XOR = 0x5 + NFT_BYTEORDER_NTOH = 0x0 + NFT_BYTEORDER_HTON = 0x1 + NFTA_BYTEORDER_UNSPEC = 0x0 + NFTA_BYTEORDER_SREG = 0x1 + NFTA_BYTEORDER_DREG = 0x2 + NFTA_BYTEORDER_OP = 0x3 + NFTA_BYTEORDER_LEN = 0x4 + NFTA_BYTEORDER_SIZE = 0x5 + NFT_CMP_EQ = 0x0 + NFT_CMP_NEQ = 0x1 + NFT_CMP_LT = 0x2 + NFT_CMP_LTE = 0x3 + NFT_CMP_GT = 0x4 + NFT_CMP_GTE = 0x5 + NFTA_CMP_UNSPEC = 0x0 + NFTA_CMP_SREG = 0x1 + NFTA_CMP_OP = 0x2 + NFTA_CMP_DATA = 0x3 + NFT_RANGE_EQ = 0x0 + NFT_RANGE_NEQ = 0x1 + NFTA_RANGE_UNSPEC = 0x0 + NFTA_RANGE_SREG = 0x1 + NFTA_RANGE_OP = 0x2 + NFTA_RANGE_FROM_DATA = 0x3 + NFTA_RANGE_TO_DATA = 0x4 + NFT_LOOKUP_F_INV = 0x1 + NFTA_LOOKUP_UNSPEC = 0x0 + NFTA_LOOKUP_SET = 0x1 + NFTA_LOOKUP_SREG = 0x2 + NFTA_LOOKUP_DREG = 0x3 + NFTA_LOOKUP_SET_ID = 0x4 + NFTA_LOOKUP_FLAGS = 0x5 + NFT_DYNSET_OP_ADD = 0x0 + NFT_DYNSET_OP_UPDATE = 0x1 + NFT_DYNSET_F_INV = 0x1 + NFTA_DYNSET_UNSPEC = 0x0 + NFTA_DYNSET_SET_NAME = 0x1 + NFTA_DYNSET_SET_ID = 0x2 + NFTA_DYNSET_OP = 0x3 + NFTA_DYNSET_SREG_KEY = 0x4 + NFTA_DYNSET_SREG_DATA = 0x5 + NFTA_DYNSET_TIMEOUT = 0x6 + NFTA_DYNSET_EXPR = 0x7 + NFTA_DYNSET_PAD = 0x8 + NFTA_DYNSET_FLAGS = 0x9 + NFT_PAYLOAD_LL_HEADER = 0x0 + NFT_PAYLOAD_NETWORK_HEADER = 0x1 + NFT_PAYLOAD_TRANSPORT_HEADER = 0x2 + NFT_PAYLOAD_CSUM_NONE = 0x0 + NFT_PAYLOAD_CSUM_INET = 0x1 + NFT_PAYLOAD_L4CSUM_PSEUDOHDR = 0x1 + NFTA_PAYLOAD_UNSPEC = 0x0 + NFTA_PAYLOAD_DREG = 0x1 + NFTA_PAYLOAD_BASE = 0x2 + NFTA_PAYLOAD_OFFSET = 0x3 + NFTA_PAYLOAD_LEN = 0x4 + NFTA_PAYLOAD_SREG = 0x5 + NFTA_PAYLOAD_CSUM_TYPE = 0x6 + NFTA_PAYLOAD_CSUM_OFFSET = 0x7 + NFTA_PAYLOAD_CSUM_FLAGS = 0x8 + NFT_EXTHDR_F_PRESENT = 0x1 + NFT_EXTHDR_OP_IPV6 = 0x0 + NFT_EXTHDR_OP_TCPOPT = 0x1 + NFTA_EXTHDR_UNSPEC = 0x0 + NFTA_EXTHDR_DREG = 0x1 + NFTA_EXTHDR_TYPE = 0x2 + NFTA_EXTHDR_OFFSET = 0x3 + NFTA_EXTHDR_LEN = 0x4 + NFTA_EXTHDR_FLAGS = 0x5 + NFTA_EXTHDR_OP = 0x6 + NFTA_EXTHDR_SREG = 0x7 + NFT_META_LEN = 0x0 + NFT_META_PROTOCOL = 0x1 + NFT_META_PRIORITY = 0x2 + NFT_META_MARK = 0x3 + NFT_META_IIF = 0x4 + NFT_META_OIF = 0x5 + NFT_META_IIFNAME = 0x6 + NFT_META_OIFNAME = 0x7 + NFT_META_IIFTYPE = 0x8 + NFT_META_OIFTYPE = 0x9 + NFT_META_SKUID = 0xa + NFT_META_SKGID = 0xb + NFT_META_NFTRACE = 0xc + NFT_META_RTCLASSID = 0xd + NFT_META_SECMARK = 0xe + NFT_META_NFPROTO = 0xf + NFT_META_L4PROTO = 0x10 + NFT_META_BRI_IIFNAME = 0x11 + NFT_META_BRI_OIFNAME = 0x12 + NFT_META_PKTTYPE = 0x13 + NFT_META_CPU = 0x14 + NFT_META_IIFGROUP = 0x15 + NFT_META_OIFGROUP = 0x16 + NFT_META_CGROUP = 0x17 + NFT_META_PRANDOM = 0x18 + NFT_RT_CLASSID = 0x0 + NFT_RT_NEXTHOP4 = 0x1 + NFT_RT_NEXTHOP6 = 0x2 + NFT_RT_TCPMSS = 0x3 + NFT_HASH_JENKINS = 0x0 + NFT_HASH_SYM = 0x1 + NFTA_HASH_UNSPEC = 0x0 + NFTA_HASH_SREG = 0x1 + NFTA_HASH_DREG = 0x2 + NFTA_HASH_LEN = 0x3 + NFTA_HASH_MODULUS = 0x4 + NFTA_HASH_SEED = 0x5 + NFTA_HASH_OFFSET = 0x6 + NFTA_HASH_TYPE = 0x7 + NFTA_META_UNSPEC = 0x0 + NFTA_META_DREG = 0x1 + NFTA_META_KEY = 0x2 + NFTA_META_SREG = 0x3 + NFTA_RT_UNSPEC = 0x0 + NFTA_RT_DREG = 0x1 + NFTA_RT_KEY = 0x2 + NFT_CT_STATE = 0x0 + NFT_CT_DIRECTION = 0x1 + NFT_CT_STATUS = 0x2 + NFT_CT_MARK = 0x3 + NFT_CT_SECMARK = 0x4 + NFT_CT_EXPIRATION = 0x5 + NFT_CT_HELPER = 0x6 + NFT_CT_L3PROTOCOL = 0x7 + NFT_CT_SRC = 0x8 + NFT_CT_DST = 0x9 + NFT_CT_PROTOCOL = 0xa + NFT_CT_PROTO_SRC = 0xb + NFT_CT_PROTO_DST = 0xc + NFT_CT_LABELS = 0xd + NFT_CT_PKTS = 0xe + NFT_CT_BYTES = 0xf + NFT_CT_AVGPKT = 0x10 + NFT_CT_ZONE = 0x11 + NFT_CT_EVENTMASK = 0x12 + NFTA_CT_UNSPEC = 0x0 + NFTA_CT_DREG = 0x1 + NFTA_CT_KEY = 0x2 + NFTA_CT_DIRECTION = 0x3 + NFTA_CT_SREG = 0x4 + NFT_LIMIT_PKTS = 0x0 + NFT_LIMIT_PKT_BYTES = 0x1 + NFT_LIMIT_F_INV = 0x1 + NFTA_LIMIT_UNSPEC = 0x0 + NFTA_LIMIT_RATE = 0x1 + NFTA_LIMIT_UNIT = 0x2 + NFTA_LIMIT_BURST = 0x3 + NFTA_LIMIT_TYPE = 0x4 + NFTA_LIMIT_FLAGS = 0x5 + NFTA_LIMIT_PAD = 0x6 + NFTA_COUNTER_UNSPEC = 0x0 + NFTA_COUNTER_BYTES = 0x1 + NFTA_COUNTER_PACKETS = 0x2 + NFTA_COUNTER_PAD = 0x3 + NFTA_LOG_UNSPEC = 0x0 + NFTA_LOG_GROUP = 0x1 + NFTA_LOG_PREFIX = 0x2 + NFTA_LOG_SNAPLEN = 0x3 + NFTA_LOG_QTHRESHOLD = 0x4 + NFTA_LOG_LEVEL = 0x5 + NFTA_LOG_FLAGS = 0x6 + NFTA_QUEUE_UNSPEC = 0x0 + NFTA_QUEUE_NUM = 0x1 + NFTA_QUEUE_TOTAL = 0x2 + NFTA_QUEUE_FLAGS = 0x3 + NFTA_QUEUE_SREG_QNUM = 0x4 + NFT_QUOTA_F_INV = 0x1 + NFT_QUOTA_F_DEPLETED = 0x2 + NFTA_QUOTA_UNSPEC = 0x0 + NFTA_QUOTA_BYTES = 0x1 + NFTA_QUOTA_FLAGS = 0x2 + NFTA_QUOTA_PAD = 0x3 + NFTA_QUOTA_CONSUMED = 0x4 + NFT_REJECT_ICMP_UNREACH = 0x0 + NFT_REJECT_TCP_RST = 0x1 + NFT_REJECT_ICMPX_UNREACH = 0x2 + NFT_REJECT_ICMPX_NO_ROUTE = 0x0 + NFT_REJECT_ICMPX_PORT_UNREACH = 0x1 + NFT_REJECT_ICMPX_HOST_UNREACH = 0x2 + NFT_REJECT_ICMPX_ADMIN_PROHIBITED = 0x3 + NFTA_REJECT_UNSPEC = 0x0 + NFTA_REJECT_TYPE = 0x1 + NFTA_REJECT_ICMP_CODE = 0x2 + NFT_NAT_SNAT = 0x0 + NFT_NAT_DNAT = 0x1 + NFTA_NAT_UNSPEC = 0x0 + NFTA_NAT_TYPE = 0x1 + NFTA_NAT_FAMILY = 0x2 + NFTA_NAT_REG_ADDR_MIN = 0x3 + NFTA_NAT_REG_ADDR_MAX = 0x4 + NFTA_NAT_REG_PROTO_MIN = 0x5 + NFTA_NAT_REG_PROTO_MAX = 0x6 + NFTA_NAT_FLAGS = 0x7 + NFTA_MASQ_UNSPEC = 0x0 + NFTA_MASQ_FLAGS = 0x1 + NFTA_MASQ_REG_PROTO_MIN = 0x2 + NFTA_MASQ_REG_PROTO_MAX = 0x3 + NFTA_REDIR_UNSPEC = 0x0 + NFTA_REDIR_REG_PROTO_MIN = 0x1 + NFTA_REDIR_REG_PROTO_MAX = 0x2 + NFTA_REDIR_FLAGS = 0x3 + NFTA_DUP_UNSPEC = 0x0 + NFTA_DUP_SREG_ADDR = 0x1 + NFTA_DUP_SREG_DEV = 0x2 + NFTA_FWD_UNSPEC = 0x0 + NFTA_FWD_SREG_DEV = 0x1 + NFTA_OBJREF_UNSPEC = 0x0 + NFTA_OBJREF_IMM_TYPE = 0x1 + NFTA_OBJREF_IMM_NAME = 0x2 + NFTA_OBJREF_SET_SREG = 0x3 + NFTA_OBJREF_SET_NAME = 0x4 + NFTA_OBJREF_SET_ID = 0x5 + NFTA_GEN_UNSPEC = 0x0 + NFTA_GEN_ID = 0x1 + NFTA_GEN_PROC_PID = 0x2 + NFTA_GEN_PROC_NAME = 0x3 + NFTA_FIB_UNSPEC = 0x0 + NFTA_FIB_DREG = 0x1 + NFTA_FIB_RESULT = 0x2 + NFTA_FIB_FLAGS = 0x3 + NFT_FIB_RESULT_UNSPEC = 0x0 + NFT_FIB_RESULT_OIF = 0x1 + NFT_FIB_RESULT_OIFNAME = 0x2 + NFT_FIB_RESULT_ADDRTYPE = 0x3 + NFTA_FIB_F_SADDR = 0x1 + NFTA_FIB_F_DADDR = 0x2 + NFTA_FIB_F_MARK = 0x4 + NFTA_FIB_F_IIF = 0x8 + NFTA_FIB_F_OIF = 0x10 + NFTA_FIB_F_PRESENT = 0x20 + NFTA_CT_HELPER_UNSPEC = 0x0 + NFTA_CT_HELPER_NAME = 0x1 + NFTA_CT_HELPER_L3PROTO = 0x2 + NFTA_CT_HELPER_L4PROTO = 0x3 + NFTA_OBJ_UNSPEC = 0x0 + NFTA_OBJ_TABLE = 0x1 + NFTA_OBJ_NAME = 0x2 + NFTA_OBJ_TYPE = 0x3 + NFTA_OBJ_DATA = 0x4 + NFTA_OBJ_USE = 0x5 + NFTA_TRACE_UNSPEC = 0x0 + NFTA_TRACE_TABLE = 0x1 + NFTA_TRACE_CHAIN = 0x2 + NFTA_TRACE_RULE_HANDLE = 0x3 + NFTA_TRACE_TYPE = 0x4 + NFTA_TRACE_VERDICT = 0x5 + NFTA_TRACE_ID = 0x6 + NFTA_TRACE_LL_HEADER = 0x7 + NFTA_TRACE_NETWORK_HEADER = 0x8 + NFTA_TRACE_TRANSPORT_HEADER = 0x9 + NFTA_TRACE_IIF = 0xa + NFTA_TRACE_IIFTYPE = 0xb + NFTA_TRACE_OIF = 0xc + NFTA_TRACE_OIFTYPE = 0xd + NFTA_TRACE_MARK = 0xe + NFTA_TRACE_NFPROTO = 0xf + NFTA_TRACE_POLICY = 0x10 + NFTA_TRACE_PAD = 0x11 + NFT_TRACETYPE_UNSPEC = 0x0 + NFT_TRACETYPE_POLICY = 0x1 + NFT_TRACETYPE_RETURN = 0x2 + NFT_TRACETYPE_RULE = 0x3 + NFTA_NG_UNSPEC = 0x0 + NFTA_NG_DREG = 0x1 + NFTA_NG_MODULUS = 0x2 + NFTA_NG_TYPE = 0x3 + NFTA_NG_OFFSET = 0x4 + NFT_NG_INCREMENTAL = 0x0 + NFT_NG_RANDOM = 0x1 +) + +type RTCTime struct { + Sec int32 + Min int32 + Hour int32 + Mday int32 + Mon int32 + Year int32 + Wday int32 + Yday int32 + Isdst int32 +} + +type RTCWkAlrm struct { + Enabled uint8 + Pending uint8 + Time RTCTime +} + +type RTCPLLInfo struct { + Ctrl int32 + Value int32 + Max int32 + Min int32 + Posmult int32 + Negmult int32 + Clock int32 +} + +type BlkpgIoctlArg struct { + Op int32 + Flags int32 + Datalen int32 + Data *byte +} + +type BlkpgPartition struct { + Start int64 + Length int64 + Pno int32 + Devname [64]uint8 + Volname [64]uint8 + _ [4]byte +} + +const ( + BLKPG = 0x20001269 + BLKPG_ADD_PARTITION = 0x1 + BLKPG_DEL_PARTITION = 0x2 + BLKPG_RESIZE_PARTITION = 0x3 +) + +const ( + NETNSA_NONE = 0x0 + NETNSA_NSID = 0x1 + NETNSA_PID = 0x2 + NETNSA_FD = 0x3 +) + +type XDPRingOffset struct { + Producer uint64 + Consumer uint64 + Desc uint64 +} + +type XDPMmapOffsets struct { + Rx XDPRingOffset + Tx XDPRingOffset + Fr XDPRingOffset + Cr XDPRingOffset +} + +type XDPUmemReg struct { + Addr uint64 + Len uint64 + Size uint32 + Headroom uint32 +} + +type XDPStatistics struct { + Rx_dropped uint64 + Rx_invalid_descs uint64 + Tx_invalid_descs uint64 +} + +type XDPDesc struct { + Addr uint64 + Len uint32 + Options uint32 +} + +const ( + NCSI_CMD_UNSPEC = 0x0 + NCSI_CMD_PKG_INFO = 0x1 + NCSI_CMD_SET_INTERFACE = 0x2 + NCSI_CMD_CLEAR_INTERFACE = 0x3 + NCSI_ATTR_UNSPEC = 0x0 + NCSI_ATTR_IFINDEX = 0x1 + NCSI_ATTR_PACKAGE_LIST = 0x2 + NCSI_ATTR_PACKAGE_ID = 0x3 + NCSI_ATTR_CHANNEL_ID = 0x4 + NCSI_PKG_ATTR_UNSPEC = 0x0 + NCSI_PKG_ATTR = 0x1 + NCSI_PKG_ATTR_ID = 0x2 + NCSI_PKG_ATTR_FORCED = 0x3 + NCSI_PKG_ATTR_CHANNEL_LIST = 0x4 + NCSI_CHANNEL_ATTR_UNSPEC = 0x0 + NCSI_CHANNEL_ATTR = 0x1 + NCSI_CHANNEL_ATTR_ID = 0x2 + NCSI_CHANNEL_ATTR_VERSION_MAJOR = 0x3 + NCSI_CHANNEL_ATTR_VERSION_MINOR = 0x4 + NCSI_CHANNEL_ATTR_VERSION_STR = 0x5 + NCSI_CHANNEL_ATTR_LINK_STATE = 0x6 + NCSI_CHANNEL_ATTR_ACTIVE = 0x7 + NCSI_CHANNEL_ATTR_FORCED = 0x8 + NCSI_CHANNEL_ATTR_VLAN_LIST = 0x9 + NCSI_CHANNEL_ATTR_VLAN_ID = 0xa +) + +type ScmTimestamping struct { + Ts [3]Timespec +} + +const ( + SOF_TIMESTAMPING_TX_HARDWARE = 0x1 + SOF_TIMESTAMPING_TX_SOFTWARE = 0x2 + SOF_TIMESTAMPING_RX_HARDWARE = 0x4 + SOF_TIMESTAMPING_RX_SOFTWARE = 0x8 + SOF_TIMESTAMPING_SOFTWARE = 0x10 + SOF_TIMESTAMPING_SYS_HARDWARE = 0x20 + SOF_TIMESTAMPING_RAW_HARDWARE = 0x40 + SOF_TIMESTAMPING_OPT_ID = 0x80 + SOF_TIMESTAMPING_TX_SCHED = 0x100 + SOF_TIMESTAMPING_TX_ACK = 0x200 + SOF_TIMESTAMPING_OPT_CMSG = 0x400 + SOF_TIMESTAMPING_OPT_TSONLY = 0x800 + SOF_TIMESTAMPING_OPT_STATS = 0x1000 + SOF_TIMESTAMPING_OPT_PKTINFO = 0x2000 + SOF_TIMESTAMPING_OPT_TX_SWHW = 0x4000 + + SOF_TIMESTAMPING_LAST = 0x4000 + SOF_TIMESTAMPING_MASK = 0x7fff + + SCM_TSTAMP_SND = 0x0 + SCM_TSTAMP_SCHED = 0x1 + SCM_TSTAMP_ACK = 0x2 +) + +type SockExtendedErr struct { + Errno uint32 + Origin uint8 + Type uint8 + Code uint8 + Pad uint8 + Info uint32 + Data uint32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go index d9df08789f..1b7e670793 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go @@ -6,11 +6,11 @@ package unix const ( - sizeofPtr = 0x8 - sizeofShort = 0x2 - sizeofInt = 0x4 - sizeofLong = 0x8 - sizeofLongLong = 0x8 + SizeofPtr = 0x8 + SizeofShort = 0x2 + SizeofInt = 0x4 + SizeofLong = 0x8 + SizeofLongLong = 0x8 PathMax = 0x1000 ) @@ -33,13 +33,11 @@ type Timeval struct { type Timex struct { Modes uint32 - Pad_cgo_0 [4]byte Offset int64 Freq int64 Maxerror int64 Esterror int64 Status int32 - Pad_cgo_1 [4]byte Constant int64 Precision int64 Tolerance int64 @@ -48,14 +46,13 @@ type Timex struct { Ppsfreq int64 Jitter int64 Shift int32 - Pad_cgo_2 [4]byte Stabil int64 Jitcnt int64 Calcnt int64 Errcnt int64 Stbcnt int64 Tai int32 - Pad_cgo_3 [44]byte + _ [44]byte } type Time_t int64 @@ -117,42 +114,56 @@ type Stat_t struct { Blocks int64 } -type Statfs_t struct { - Type int64 - Bsize int64 - Frsize int64 - Blocks uint64 - Bfree uint64 - Files uint64 - Ffree uint64 - Bavail uint64 - Fsid Fsid - Namelen int64 - Flags int64 - Spare [5]int64 +type StatxTimestamp struct { + Sec int64 + Nsec uint32 + _ int32 +} + +type Statx_t struct { + Mask uint32 + Blksize uint32 + Attributes uint64 + Nlink uint32 + Uid uint32 + Gid uint32 + Mode uint16 + _ [1]uint16 + Ino uint64 + Size uint64 + Blocks uint64 + Attributes_mask uint64 + Atime StatxTimestamp + Btime StatxTimestamp + Ctime StatxTimestamp + Mtime StatxTimestamp + Rdev_major uint32 + Rdev_minor uint32 + Dev_major uint32 + Dev_minor uint32 + _ [14]uint64 } type Dirent struct { - Ino uint64 - Off int64 - Reclen uint16 - Type uint8 - Name [256]int8 - Pad_cgo_0 [5]byte + Ino uint64 + Off int64 + Reclen uint16 + Type uint8 + Name [256]int8 + _ [5]byte } type Fsid struct { - X__val [2]int32 + Val [2]int32 } type Flock_t struct { - Type int16 - Whence int16 - Pad_cgo_0 [4]byte - Start int64 - Len int64 - Pid int32 - Pad_cgo_1 [4]byte + Type int16 + Whence int16 + Start int64 + Len int64 + Pid int32 + _ [4]byte } type FscryptPolicy struct { @@ -227,11 +238,26 @@ type RawSockaddrHCI struct { Channel uint16 } +type RawSockaddrL2 struct { + Family uint16 + Psm uint16 + Bdaddr [6]uint8 + Cid uint16 + Bdaddr_type uint8 + _ [1]byte +} + +type RawSockaddrRFCOMM struct { + Family uint16 + Bdaddr [6]uint8 + Channel uint8 + _ [1]byte +} + type RawSockaddrCAN struct { - Family uint16 - Pad_cgo_0 [2]byte - Ifindex int32 - Addr [8]byte + Family uint16 + Ifindex int32 + Addr [8]byte } type RawSockaddrALG struct { @@ -250,6 +276,16 @@ type RawSockaddrVM struct { Zero [4]uint8 } +type RawSockaddrXDP struct { + Family uint16 + Flags uint16 + Ifindex uint32 + Queue_id uint32 + Shared_umem_fd uint32 +} + +type RawSockaddrPPPoX [0x1e]byte + type RawSockaddr struct { Family uint16 Data [14]int8 @@ -298,13 +334,12 @@ type PacketMreq struct { type Msghdr struct { Name *byte Namelen uint32 - Pad_cgo_0 [4]byte Iov *Iovec Iovlen uint64 Control *byte Controllen uint64 Flags int32 - Pad_cgo_1 [4]byte + _ [4]byte } type Cmsghdr struct { @@ -346,7 +381,6 @@ type TCPInfo struct { Probes uint8 Backoff uint8 Options uint8 - Pad_cgo_0 [2]byte Rto uint32 Ato uint32 Snd_mss uint32 @@ -381,9 +415,13 @@ const ( SizeofSockaddrLinklayer = 0x14 SizeofSockaddrNetlink = 0xc SizeofSockaddrHCI = 0x6 + SizeofSockaddrL2 = 0xe + SizeofSockaddrRFCOMM = 0xa SizeofSockaddrCAN = 0x10 SizeofSockaddrALG = 0x58 SizeofSockaddrVM = 0x10 + SizeofSockaddrXDP = 0x10 + SizeofSockaddrPPPoX = 0x1e SizeofLinger = 0x8 SizeofIovec = 0x10 SizeofIPMreq = 0x8 @@ -401,97 +439,138 @@ const ( ) const ( - IFA_UNSPEC = 0x0 - IFA_ADDRESS = 0x1 - IFA_LOCAL = 0x2 - IFA_LABEL = 0x3 - IFA_BROADCAST = 0x4 - IFA_ANYCAST = 0x5 - IFA_CACHEINFO = 0x6 - IFA_MULTICAST = 0x7 - IFLA_UNSPEC = 0x0 - IFLA_ADDRESS = 0x1 - IFLA_BROADCAST = 0x2 - IFLA_IFNAME = 0x3 - IFLA_MTU = 0x4 - IFLA_LINK = 0x5 - IFLA_QDISC = 0x6 - IFLA_STATS = 0x7 - IFLA_COST = 0x8 - IFLA_PRIORITY = 0x9 - IFLA_MASTER = 0xa - IFLA_WIRELESS = 0xb - IFLA_PROTINFO = 0xc - IFLA_TXQLEN = 0xd - IFLA_MAP = 0xe - IFLA_WEIGHT = 0xf - IFLA_OPERSTATE = 0x10 - IFLA_LINKMODE = 0x11 - IFLA_LINKINFO = 0x12 - IFLA_NET_NS_PID = 0x13 - IFLA_IFALIAS = 0x14 - IFLA_MAX = 0x2c - RT_SCOPE_UNIVERSE = 0x0 - RT_SCOPE_SITE = 0xc8 - RT_SCOPE_LINK = 0xfd - RT_SCOPE_HOST = 0xfe - RT_SCOPE_NOWHERE = 0xff - RT_TABLE_UNSPEC = 0x0 - RT_TABLE_COMPAT = 0xfc - RT_TABLE_DEFAULT = 0xfd - RT_TABLE_MAIN = 0xfe - RT_TABLE_LOCAL = 0xff - RT_TABLE_MAX = 0xffffffff - RTA_UNSPEC = 0x0 - RTA_DST = 0x1 - RTA_SRC = 0x2 - RTA_IIF = 0x3 - RTA_OIF = 0x4 - RTA_GATEWAY = 0x5 - RTA_PRIORITY = 0x6 - RTA_PREFSRC = 0x7 - RTA_METRICS = 0x8 - RTA_MULTIPATH = 0x9 - RTA_FLOW = 0xb - RTA_CACHEINFO = 0xc - RTA_TABLE = 0xf - RTN_UNSPEC = 0x0 - RTN_UNICAST = 0x1 - RTN_LOCAL = 0x2 - RTN_BROADCAST = 0x3 - RTN_ANYCAST = 0x4 - RTN_MULTICAST = 0x5 - RTN_BLACKHOLE = 0x6 - RTN_UNREACHABLE = 0x7 - RTN_PROHIBIT = 0x8 - RTN_THROW = 0x9 - RTN_NAT = 0xa - RTN_XRESOLVE = 0xb - RTNLGRP_NONE = 0x0 - RTNLGRP_LINK = 0x1 - RTNLGRP_NOTIFY = 0x2 - RTNLGRP_NEIGH = 0x3 - RTNLGRP_TC = 0x4 - RTNLGRP_IPV4_IFADDR = 0x5 - RTNLGRP_IPV4_MROUTE = 0x6 - RTNLGRP_IPV4_ROUTE = 0x7 - RTNLGRP_IPV4_RULE = 0x8 - RTNLGRP_IPV6_IFADDR = 0x9 - RTNLGRP_IPV6_MROUTE = 0xa - RTNLGRP_IPV6_ROUTE = 0xb - RTNLGRP_IPV6_IFINFO = 0xc - RTNLGRP_IPV6_PREFIX = 0x12 - RTNLGRP_IPV6_RULE = 0x13 - RTNLGRP_ND_USEROPT = 0x14 - SizeofNlMsghdr = 0x10 - SizeofNlMsgerr = 0x14 - SizeofRtGenmsg = 0x1 - SizeofNlAttr = 0x4 - SizeofRtAttr = 0x4 - SizeofIfInfomsg = 0x10 - SizeofIfAddrmsg = 0x8 - SizeofRtMsg = 0xc - SizeofRtNexthop = 0x8 + IFA_UNSPEC = 0x0 + IFA_ADDRESS = 0x1 + IFA_LOCAL = 0x2 + IFA_LABEL = 0x3 + IFA_BROADCAST = 0x4 + IFA_ANYCAST = 0x5 + IFA_CACHEINFO = 0x6 + IFA_MULTICAST = 0x7 + IFLA_UNSPEC = 0x0 + IFLA_ADDRESS = 0x1 + IFLA_BROADCAST = 0x2 + IFLA_IFNAME = 0x3 + IFLA_INFO_KIND = 0x1 + IFLA_MTU = 0x4 + IFLA_LINK = 0x5 + IFLA_QDISC = 0x6 + IFLA_STATS = 0x7 + IFLA_COST = 0x8 + IFLA_PRIORITY = 0x9 + IFLA_MASTER = 0xa + IFLA_WIRELESS = 0xb + IFLA_PROTINFO = 0xc + IFLA_TXQLEN = 0xd + IFLA_MAP = 0xe + IFLA_WEIGHT = 0xf + IFLA_OPERSTATE = 0x10 + IFLA_LINKMODE = 0x11 + IFLA_LINKINFO = 0x12 + IFLA_NET_NS_PID = 0x13 + IFLA_IFALIAS = 0x14 + IFLA_NUM_VF = 0x15 + IFLA_VFINFO_LIST = 0x16 + IFLA_STATS64 = 0x17 + IFLA_VF_PORTS = 0x18 + IFLA_PORT_SELF = 0x19 + IFLA_AF_SPEC = 0x1a + IFLA_GROUP = 0x1b + IFLA_NET_NS_FD = 0x1c + IFLA_EXT_MASK = 0x1d + IFLA_PROMISCUITY = 0x1e + IFLA_NUM_TX_QUEUES = 0x1f + IFLA_NUM_RX_QUEUES = 0x20 + IFLA_CARRIER = 0x21 + IFLA_PHYS_PORT_ID = 0x22 + IFLA_CARRIER_CHANGES = 0x23 + IFLA_PHYS_SWITCH_ID = 0x24 + IFLA_LINK_NETNSID = 0x25 + IFLA_PHYS_PORT_NAME = 0x26 + IFLA_PROTO_DOWN = 0x27 + IFLA_GSO_MAX_SEGS = 0x28 + IFLA_GSO_MAX_SIZE = 0x29 + IFLA_PAD = 0x2a + IFLA_XDP = 0x2b + IFLA_EVENT = 0x2c + IFLA_NEW_NETNSID = 0x2d + IFLA_IF_NETNSID = 0x2e + IFLA_MAX = 0x33 + RT_SCOPE_UNIVERSE = 0x0 + RT_SCOPE_SITE = 0xc8 + RT_SCOPE_LINK = 0xfd + RT_SCOPE_HOST = 0xfe + RT_SCOPE_NOWHERE = 0xff + RT_TABLE_UNSPEC = 0x0 + RT_TABLE_COMPAT = 0xfc + RT_TABLE_DEFAULT = 0xfd + RT_TABLE_MAIN = 0xfe + RT_TABLE_LOCAL = 0xff + RT_TABLE_MAX = 0xffffffff + RTA_UNSPEC = 0x0 + RTA_DST = 0x1 + RTA_SRC = 0x2 + RTA_IIF = 0x3 + RTA_OIF = 0x4 + RTA_GATEWAY = 0x5 + RTA_PRIORITY = 0x6 + RTA_PREFSRC = 0x7 + RTA_METRICS = 0x8 + RTA_MULTIPATH = 0x9 + RTA_FLOW = 0xb + RTA_CACHEINFO = 0xc + RTA_TABLE = 0xf + RTA_MARK = 0x10 + RTA_MFC_STATS = 0x11 + RTA_VIA = 0x12 + RTA_NEWDST = 0x13 + RTA_PREF = 0x14 + RTA_ENCAP_TYPE = 0x15 + RTA_ENCAP = 0x16 + RTA_EXPIRES = 0x17 + RTA_PAD = 0x18 + RTA_UID = 0x19 + RTA_TTL_PROPAGATE = 0x1a + RTA_IP_PROTO = 0x1b + RTA_SPORT = 0x1c + RTA_DPORT = 0x1d + RTN_UNSPEC = 0x0 + RTN_UNICAST = 0x1 + RTN_LOCAL = 0x2 + RTN_BROADCAST = 0x3 + RTN_ANYCAST = 0x4 + RTN_MULTICAST = 0x5 + RTN_BLACKHOLE = 0x6 + RTN_UNREACHABLE = 0x7 + RTN_PROHIBIT = 0x8 + RTN_THROW = 0x9 + RTN_NAT = 0xa + RTN_XRESOLVE = 0xb + RTNLGRP_NONE = 0x0 + RTNLGRP_LINK = 0x1 + RTNLGRP_NOTIFY = 0x2 + RTNLGRP_NEIGH = 0x3 + RTNLGRP_TC = 0x4 + RTNLGRP_IPV4_IFADDR = 0x5 + RTNLGRP_IPV4_MROUTE = 0x6 + RTNLGRP_IPV4_ROUTE = 0x7 + RTNLGRP_IPV4_RULE = 0x8 + RTNLGRP_IPV6_IFADDR = 0x9 + RTNLGRP_IPV6_MROUTE = 0xa + RTNLGRP_IPV6_ROUTE = 0xb + RTNLGRP_IPV6_IFINFO = 0xc + RTNLGRP_IPV6_PREFIX = 0x12 + RTNLGRP_IPV6_RULE = 0x13 + RTNLGRP_ND_USEROPT = 0x14 + SizeofNlMsghdr = 0x10 + SizeofNlMsgerr = 0x14 + SizeofRtGenmsg = 0x1 + SizeofNlAttr = 0x4 + SizeofRtAttr = 0x4 + SizeofIfInfomsg = 0x10 + SizeofIfAddrmsg = 0x8 + SizeofRtMsg = 0xc + SizeofRtNexthop = 0x8 ) type NlMsghdr struct { @@ -522,12 +601,12 @@ type RtAttr struct { } type IfInfomsg struct { - Family uint8 - X__ifi_pad uint8 - Type uint16 - Index int32 - Flags uint32 - Change uint32 + Family uint8 + _ uint8 + Type uint16 + Index int32 + Flags uint32 + Change uint32 } type IfAddrmsg struct { @@ -570,9 +649,8 @@ type SockFilter struct { } type SockFprog struct { - Len uint16 - Pad_cgo_0 [6]byte - Filter *SockFilter + Len uint16 + Filter *SockFilter } type InotifyEvent struct { @@ -609,12 +687,11 @@ type Sysinfo_t struct { Freeswap uint64 Procs uint16 Pad uint16 - Pad_cgo_0 [4]byte Totalhigh uint64 Freehigh uint64 Unit uint32 - X_f [0]int8 - Pad_cgo_1 [4]byte + _ [0]int8 + _ [4]byte } type Utsname struct { @@ -627,12 +704,11 @@ type Utsname struct { } type Ustat_t struct { - Tfree int32 - Pad_cgo_0 [4]byte - Tinode uint64 - Fname [6]int8 - Fpack [6]int8 - Pad_cgo_1 [4]byte + Tfree int32 + Tinode uint64 + Fname [6]int8 + Fpack [6]int8 + _ [4]byte } type EpollEvent struct { @@ -642,10 +718,19 @@ type EpollEvent struct { } const ( - AT_FDCWD = -0x64 - AT_REMOVEDIR = 0x200 + AT_EMPTY_PATH = 0x1000 + AT_FDCWD = -0x64 + AT_NO_AUTOMOUNT = 0x800 + AT_REMOVEDIR = 0x200 + + AT_STATX_SYNC_AS_STAT = 0x0 + AT_STATX_FORCE_SYNC = 0x2000 + AT_STATX_DONT_SYNC = 0x4000 + AT_SYMLINK_FOLLOW = 0x400 AT_SYMLINK_NOFOLLOW = 0x100 + + AT_EACCESS = 0x200 ) type PollFd struct { @@ -665,10 +750,33 @@ const ( ) type Sigset_t struct { - X__val [16]uint64 + Val [16]uint64 } -const RNDGETENTCNT = 0x40045200 +type SignalfdSiginfo struct { + Signo uint32 + Errno int32 + Code int32 + Pid uint32 + Uid uint32 + Fd int32 + Tid uint32 + Band uint32 + Overrun uint32 + Trapno uint32 + Status int32 + Int int32 + Ptr uint64 + Utime uint64 + Stime uint64 + Addr uint64 + Addr_lsb uint16 + _ uint16 + Syscall int32 + Call_addr uint64 + Arch uint32 + _ [28]uint8 +} const PERF_IOC_FLAG_GROUP = 0x1 @@ -692,11 +800,9 @@ type Winsize struct { type Taskstats struct { Version uint16 - Pad_cgo_0 [2]byte Ac_exitcode uint32 Ac_flag uint8 Ac_nice uint8 - Pad_cgo_1 [6]byte Cpu_count uint64 Cpu_delay_total uint64 Blkio_count uint64 @@ -708,13 +814,12 @@ type Taskstats struct { Ac_comm [32]int8 Ac_sched uint8 Ac_pad [3]uint8 - Pad_cgo_2 [4]byte + _ [4]byte Ac_uid uint32 Ac_gid uint32 Ac_pid uint32 Ac_ppid uint32 Ac_btime uint32 - Pad_cgo_3 [4]byte Ac_etime uint64 Ac_utime uint64 Ac_stime uint64 @@ -738,6 +843,8 @@ type Taskstats struct { Cpu_scaled_run_real_total uint64 Freepages_count uint64 Freepages_delay_total uint64 + Thrashing_count uint64 + Thrashing_delay_total uint64 } const ( @@ -758,6 +865,24 @@ const ( TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK = 0x4 ) +type CGroupStats struct { + Sleeping uint64 + Running uint64 + Stopped uint64 + Uninterruptible uint64 + Io_wait uint64 +} + +const ( + CGROUPSTATS_CMD_UNSPEC = 0x3 + CGROUPSTATS_CMD_GET = 0x4 + CGROUPSTATS_CMD_NEW = 0x5 + CGROUPSTATS_TYPE_UNSPEC = 0x0 + CGROUPSTATS_TYPE_CGROUP_STATS = 0x1 + CGROUPSTATS_CMD_ATTR_UNSPEC = 0x0 + CGROUPSTATS_CMD_ATTR_FD = 0x1 +) + type Genlmsghdr struct { Cmd uint8 Version uint8 @@ -790,3 +915,1107 @@ const ( CTRL_ATTR_MCAST_GRP_NAME = 0x1 CTRL_ATTR_MCAST_GRP_ID = 0x2 ) + +type cpuMask uint64 + +const ( + _CPU_SETSIZE = 0x400 + _NCPUBITS = 0x40 +) + +const ( + BDADDR_BREDR = 0x0 + BDADDR_LE_PUBLIC = 0x1 + BDADDR_LE_RANDOM = 0x2 +) + +type PerfEventAttr struct { + Type uint32 + Size uint32 + Config uint64 + Sample uint64 + Sample_type uint64 + Read_format uint64 + Bits uint64 + Wakeup uint32 + Bp_type uint32 + Ext1 uint64 + Ext2 uint64 + Branch_sample_type uint64 + Sample_regs_user uint64 + Sample_stack_user uint32 + Clockid int32 + Sample_regs_intr uint64 + Aux_watermark uint32 + _ uint32 +} + +type PerfEventMmapPage struct { + Version uint32 + Compat_version uint32 + Lock uint32 + Index uint32 + Offset int64 + Time_enabled uint64 + Time_running uint64 + Capabilities uint64 + Pmc_width uint16 + Time_shift uint16 + Time_mult uint32 + Time_offset uint64 + Time_zero uint64 + Size uint32 + _ [948]uint8 + Data_head uint64 + Data_tail uint64 + Data_offset uint64 + Data_size uint64 + Aux_head uint64 + Aux_tail uint64 + Aux_offset uint64 + Aux_size uint64 +} + +const ( + PerfBitDisabled uint64 = CBitFieldMaskBit0 + PerfBitInherit = CBitFieldMaskBit1 + PerfBitPinned = CBitFieldMaskBit2 + PerfBitExclusive = CBitFieldMaskBit3 + PerfBitExcludeUser = CBitFieldMaskBit4 + PerfBitExcludeKernel = CBitFieldMaskBit5 + PerfBitExcludeHv = CBitFieldMaskBit6 + PerfBitExcludeIdle = CBitFieldMaskBit7 + PerfBitMmap = CBitFieldMaskBit8 + PerfBitComm = CBitFieldMaskBit9 + PerfBitFreq = CBitFieldMaskBit10 + PerfBitInheritStat = CBitFieldMaskBit11 + PerfBitEnableOnExec = CBitFieldMaskBit12 + PerfBitTask = CBitFieldMaskBit13 + PerfBitWatermark = CBitFieldMaskBit14 + PerfBitPreciseIPBit1 = CBitFieldMaskBit15 + PerfBitPreciseIPBit2 = CBitFieldMaskBit16 + PerfBitMmapData = CBitFieldMaskBit17 + PerfBitSampleIDAll = CBitFieldMaskBit18 + PerfBitExcludeHost = CBitFieldMaskBit19 + PerfBitExcludeGuest = CBitFieldMaskBit20 + PerfBitExcludeCallchainKernel = CBitFieldMaskBit21 + PerfBitExcludeCallchainUser = CBitFieldMaskBit22 + PerfBitMmap2 = CBitFieldMaskBit23 + PerfBitCommExec = CBitFieldMaskBit24 + PerfBitUseClockID = CBitFieldMaskBit25 + PerfBitContextSwitch = CBitFieldMaskBit26 +) + +const ( + PERF_TYPE_HARDWARE = 0x0 + PERF_TYPE_SOFTWARE = 0x1 + PERF_TYPE_TRACEPOINT = 0x2 + PERF_TYPE_HW_CACHE = 0x3 + PERF_TYPE_RAW = 0x4 + PERF_TYPE_BREAKPOINT = 0x5 + + PERF_COUNT_HW_CPU_CYCLES = 0x0 + PERF_COUNT_HW_INSTRUCTIONS = 0x1 + PERF_COUNT_HW_CACHE_REFERENCES = 0x2 + PERF_COUNT_HW_CACHE_MISSES = 0x3 + PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 0x4 + PERF_COUNT_HW_BRANCH_MISSES = 0x5 + PERF_COUNT_HW_BUS_CYCLES = 0x6 + PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 0x7 + PERF_COUNT_HW_STALLED_CYCLES_BACKEND = 0x8 + PERF_COUNT_HW_REF_CPU_CYCLES = 0x9 + + PERF_COUNT_HW_CACHE_L1D = 0x0 + PERF_COUNT_HW_CACHE_L1I = 0x1 + PERF_COUNT_HW_CACHE_LL = 0x2 + PERF_COUNT_HW_CACHE_DTLB = 0x3 + PERF_COUNT_HW_CACHE_ITLB = 0x4 + PERF_COUNT_HW_CACHE_BPU = 0x5 + PERF_COUNT_HW_CACHE_NODE = 0x6 + + PERF_COUNT_HW_CACHE_OP_READ = 0x0 + PERF_COUNT_HW_CACHE_OP_WRITE = 0x1 + PERF_COUNT_HW_CACHE_OP_PREFETCH = 0x2 + + PERF_COUNT_HW_CACHE_RESULT_ACCESS = 0x0 + PERF_COUNT_HW_CACHE_RESULT_MISS = 0x1 + + PERF_COUNT_SW_CPU_CLOCK = 0x0 + PERF_COUNT_SW_TASK_CLOCK = 0x1 + PERF_COUNT_SW_PAGE_FAULTS = 0x2 + PERF_COUNT_SW_CONTEXT_SWITCHES = 0x3 + PERF_COUNT_SW_CPU_MIGRATIONS = 0x4 + PERF_COUNT_SW_PAGE_FAULTS_MIN = 0x5 + PERF_COUNT_SW_PAGE_FAULTS_MAJ = 0x6 + PERF_COUNT_SW_ALIGNMENT_FAULTS = 0x7 + PERF_COUNT_SW_EMULATION_FAULTS = 0x8 + PERF_COUNT_SW_DUMMY = 0x9 + + PERF_SAMPLE_IP = 0x1 + PERF_SAMPLE_TID = 0x2 + PERF_SAMPLE_TIME = 0x4 + PERF_SAMPLE_ADDR = 0x8 + PERF_SAMPLE_READ = 0x10 + PERF_SAMPLE_CALLCHAIN = 0x20 + PERF_SAMPLE_ID = 0x40 + PERF_SAMPLE_CPU = 0x80 + PERF_SAMPLE_PERIOD = 0x100 + PERF_SAMPLE_STREAM_ID = 0x200 + PERF_SAMPLE_RAW = 0x400 + PERF_SAMPLE_BRANCH_STACK = 0x800 + + PERF_SAMPLE_BRANCH_USER = 0x1 + PERF_SAMPLE_BRANCH_KERNEL = 0x2 + PERF_SAMPLE_BRANCH_HV = 0x4 + PERF_SAMPLE_BRANCH_ANY = 0x8 + PERF_SAMPLE_BRANCH_ANY_CALL = 0x10 + PERF_SAMPLE_BRANCH_ANY_RETURN = 0x20 + PERF_SAMPLE_BRANCH_IND_CALL = 0x40 + + PERF_FORMAT_TOTAL_TIME_ENABLED = 0x1 + PERF_FORMAT_TOTAL_TIME_RUNNING = 0x2 + PERF_FORMAT_ID = 0x4 + PERF_FORMAT_GROUP = 0x8 + + PERF_RECORD_MMAP = 0x1 + PERF_RECORD_LOST = 0x2 + PERF_RECORD_COMM = 0x3 + PERF_RECORD_EXIT = 0x4 + PERF_RECORD_THROTTLE = 0x5 + PERF_RECORD_UNTHROTTLE = 0x6 + PERF_RECORD_FORK = 0x7 + PERF_RECORD_READ = 0x8 + PERF_RECORD_SAMPLE = 0x9 + + PERF_CONTEXT_HV = -0x20 + PERF_CONTEXT_KERNEL = -0x80 + PERF_CONTEXT_USER = -0x200 + + PERF_CONTEXT_GUEST = -0x800 + PERF_CONTEXT_GUEST_KERNEL = -0x880 + PERF_CONTEXT_GUEST_USER = -0xa00 + + PERF_FLAG_FD_NO_GROUP = 0x1 + PERF_FLAG_FD_OUTPUT = 0x2 + PERF_FLAG_PID_CGROUP = 0x4 +) + +const ( + CBitFieldMaskBit0 = 0x8000000000000000 + CBitFieldMaskBit1 = 0x4000000000000000 + CBitFieldMaskBit2 = 0x2000000000000000 + CBitFieldMaskBit3 = 0x1000000000000000 + CBitFieldMaskBit4 = 0x800000000000000 + CBitFieldMaskBit5 = 0x400000000000000 + CBitFieldMaskBit6 = 0x200000000000000 + CBitFieldMaskBit7 = 0x100000000000000 + CBitFieldMaskBit8 = 0x80000000000000 + CBitFieldMaskBit9 = 0x40000000000000 + CBitFieldMaskBit10 = 0x20000000000000 + CBitFieldMaskBit11 = 0x10000000000000 + CBitFieldMaskBit12 = 0x8000000000000 + CBitFieldMaskBit13 = 0x4000000000000 + CBitFieldMaskBit14 = 0x2000000000000 + CBitFieldMaskBit15 = 0x1000000000000 + CBitFieldMaskBit16 = 0x800000000000 + CBitFieldMaskBit17 = 0x400000000000 + CBitFieldMaskBit18 = 0x200000000000 + CBitFieldMaskBit19 = 0x100000000000 + CBitFieldMaskBit20 = 0x80000000000 + CBitFieldMaskBit21 = 0x40000000000 + CBitFieldMaskBit22 = 0x20000000000 + CBitFieldMaskBit23 = 0x10000000000 + CBitFieldMaskBit24 = 0x8000000000 + CBitFieldMaskBit25 = 0x4000000000 + CBitFieldMaskBit26 = 0x2000000000 + CBitFieldMaskBit27 = 0x1000000000 + CBitFieldMaskBit28 = 0x800000000 + CBitFieldMaskBit29 = 0x400000000 + CBitFieldMaskBit30 = 0x200000000 + CBitFieldMaskBit31 = 0x100000000 + CBitFieldMaskBit32 = 0x80000000 + CBitFieldMaskBit33 = 0x40000000 + CBitFieldMaskBit34 = 0x20000000 + CBitFieldMaskBit35 = 0x10000000 + CBitFieldMaskBit36 = 0x8000000 + CBitFieldMaskBit37 = 0x4000000 + CBitFieldMaskBit38 = 0x2000000 + CBitFieldMaskBit39 = 0x1000000 + CBitFieldMaskBit40 = 0x800000 + CBitFieldMaskBit41 = 0x400000 + CBitFieldMaskBit42 = 0x200000 + CBitFieldMaskBit43 = 0x100000 + CBitFieldMaskBit44 = 0x80000 + CBitFieldMaskBit45 = 0x40000 + CBitFieldMaskBit46 = 0x20000 + CBitFieldMaskBit47 = 0x10000 + CBitFieldMaskBit48 = 0x8000 + CBitFieldMaskBit49 = 0x4000 + CBitFieldMaskBit50 = 0x2000 + CBitFieldMaskBit51 = 0x1000 + CBitFieldMaskBit52 = 0x800 + CBitFieldMaskBit53 = 0x400 + CBitFieldMaskBit54 = 0x200 + CBitFieldMaskBit55 = 0x100 + CBitFieldMaskBit56 = 0x80 + CBitFieldMaskBit57 = 0x40 + CBitFieldMaskBit58 = 0x20 + CBitFieldMaskBit59 = 0x10 + CBitFieldMaskBit60 = 0x8 + CBitFieldMaskBit61 = 0x4 + CBitFieldMaskBit62 = 0x2 + CBitFieldMaskBit63 = 0x1 +) + +type SockaddrStorage struct { + Family uint16 + _ [118]int8 + _ uint64 +} + +type TCPMD5Sig struct { + Addr SockaddrStorage + Flags uint8 + Prefixlen uint8 + Keylen uint16 + _ uint32 + Key [80]uint8 +} + +type HDDriveCmdHdr struct { + Command uint8 + Number uint8 + Feature uint8 + Count uint8 +} + +type HDGeometry struct { + Heads uint8 + Sectors uint8 + Cylinders uint16 + Start uint64 +} + +type HDDriveID struct { + Config uint16 + Cyls uint16 + Reserved2 uint16 + Heads uint16 + Track_bytes uint16 + Sector_bytes uint16 + Sectors uint16 + Vendor0 uint16 + Vendor1 uint16 + Vendor2 uint16 + Serial_no [20]uint8 + Buf_type uint16 + Buf_size uint16 + Ecc_bytes uint16 + Fw_rev [8]uint8 + Model [40]uint8 + Max_multsect uint8 + Vendor3 uint8 + Dword_io uint16 + Vendor4 uint8 + Capability uint8 + Reserved50 uint16 + Vendor5 uint8 + TPIO uint8 + Vendor6 uint8 + TDMA uint8 + Field_valid uint16 + Cur_cyls uint16 + Cur_heads uint16 + Cur_sectors uint16 + Cur_capacity0 uint16 + Cur_capacity1 uint16 + Multsect uint8 + Multsect_valid uint8 + Lba_capacity uint32 + Dma_1word uint16 + Dma_mword uint16 + Eide_pio_modes uint16 + Eide_dma_min uint16 + Eide_dma_time uint16 + Eide_pio uint16 + Eide_pio_iordy uint16 + Words69_70 [2]uint16 + Words71_74 [4]uint16 + Queue_depth uint16 + Words76_79 [4]uint16 + Major_rev_num uint16 + Minor_rev_num uint16 + Command_set_1 uint16 + Command_set_2 uint16 + Cfsse uint16 + Cfs_enable_1 uint16 + Cfs_enable_2 uint16 + Csf_default uint16 + Dma_ultra uint16 + Trseuc uint16 + TrsEuc uint16 + CurAPMvalues uint16 + Mprc uint16 + Hw_config uint16 + Acoustic uint16 + Msrqs uint16 + Sxfert uint16 + Sal uint16 + Spg uint32 + Lba_capacity_2 uint64 + Words104_125 [22]uint16 + Last_lun uint16 + Word127 uint16 + Dlf uint16 + Csfo uint16 + Words130_155 [26]uint16 + Word156 uint16 + Words157_159 [3]uint16 + Cfa_power uint16 + Words161_175 [15]uint16 + Words176_205 [30]uint16 + Words206_254 [49]uint16 + Integrity_word uint16 +} + +type Statfs_t struct { + Type int64 + Bsize int64 + Frsize int64 + Blocks uint64 + Bfree uint64 + Files uint64 + Ffree uint64 + Bavail uint64 + Fsid Fsid + Namelen int64 + Flags int64 + Spare [5]int64 +} + +const ( + ST_MANDLOCK = 0x40 + ST_NOATIME = 0x400 + ST_NODEV = 0x4 + ST_NODIRATIME = 0x800 + ST_NOEXEC = 0x8 + ST_NOSUID = 0x2 + ST_RDONLY = 0x1 + ST_RELATIME = 0x1000 + ST_SYNCHRONOUS = 0x10 +) + +type TpacketHdr struct { + Status uint64 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Sec uint32 + Usec uint32 + _ [4]byte +} + +type Tpacket2Hdr struct { + Status uint32 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Sec uint32 + Nsec uint32 + Vlan_tci uint16 + Vlan_tpid uint16 + _ [4]uint8 +} + +type Tpacket3Hdr struct { + Next_offset uint32 + Sec uint32 + Nsec uint32 + Snaplen uint32 + Len uint32 + Status uint32 + Mac uint16 + Net uint16 + Hv1 TpacketHdrVariant1 + _ [8]uint8 +} + +type TpacketHdrVariant1 struct { + Rxhash uint32 + Vlan_tci uint32 + Vlan_tpid uint16 + _ uint16 +} + +type TpacketBlockDesc struct { + Version uint32 + To_priv uint32 + Hdr [40]byte +} + +type TpacketReq struct { + Block_size uint32 + Block_nr uint32 + Frame_size uint32 + Frame_nr uint32 +} + +type TpacketReq3 struct { + Block_size uint32 + Block_nr uint32 + Frame_size uint32 + Frame_nr uint32 + Retire_blk_tov uint32 + Sizeof_priv uint32 + Feature_req_word uint32 +} + +type TpacketStats struct { + Packets uint32 + Drops uint32 +} + +type TpacketStatsV3 struct { + Packets uint32 + Drops uint32 + Freeze_q_cnt uint32 +} + +type TpacketAuxdata struct { + Status uint32 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Vlan_tci uint16 + Vlan_tpid uint16 +} + +const ( + TPACKET_V1 = 0x0 + TPACKET_V2 = 0x1 + TPACKET_V3 = 0x2 +) + +const ( + SizeofTpacketHdr = 0x20 + SizeofTpacket2Hdr = 0x20 + SizeofTpacket3Hdr = 0x30 +) + +const ( + NF_INET_PRE_ROUTING = 0x0 + NF_INET_LOCAL_IN = 0x1 + NF_INET_FORWARD = 0x2 + NF_INET_LOCAL_OUT = 0x3 + NF_INET_POST_ROUTING = 0x4 + NF_INET_NUMHOOKS = 0x5 +) + +const ( + NF_NETDEV_INGRESS = 0x0 + NF_NETDEV_NUMHOOKS = 0x1 +) + +const ( + NFPROTO_UNSPEC = 0x0 + NFPROTO_INET = 0x1 + NFPROTO_IPV4 = 0x2 + NFPROTO_ARP = 0x3 + NFPROTO_NETDEV = 0x5 + NFPROTO_BRIDGE = 0x7 + NFPROTO_IPV6 = 0xa + NFPROTO_DECNET = 0xc + NFPROTO_NUMPROTO = 0xd +) + +type Nfgenmsg struct { + Nfgen_family uint8 + Version uint8 + Res_id uint16 +} + +const ( + NFNL_BATCH_UNSPEC = 0x0 + NFNL_BATCH_GENID = 0x1 +) + +const ( + NFT_REG_VERDICT = 0x0 + NFT_REG_1 = 0x1 + NFT_REG_2 = 0x2 + NFT_REG_3 = 0x3 + NFT_REG_4 = 0x4 + NFT_REG32_00 = 0x8 + NFT_REG32_01 = 0x9 + NFT_REG32_02 = 0xa + NFT_REG32_03 = 0xb + NFT_REG32_04 = 0xc + NFT_REG32_05 = 0xd + NFT_REG32_06 = 0xe + NFT_REG32_07 = 0xf + NFT_REG32_08 = 0x10 + NFT_REG32_09 = 0x11 + NFT_REG32_10 = 0x12 + NFT_REG32_11 = 0x13 + NFT_REG32_12 = 0x14 + NFT_REG32_13 = 0x15 + NFT_REG32_14 = 0x16 + NFT_REG32_15 = 0x17 + NFT_CONTINUE = -0x1 + NFT_BREAK = -0x2 + NFT_JUMP = -0x3 + NFT_GOTO = -0x4 + NFT_RETURN = -0x5 + NFT_MSG_NEWTABLE = 0x0 + NFT_MSG_GETTABLE = 0x1 + NFT_MSG_DELTABLE = 0x2 + NFT_MSG_NEWCHAIN = 0x3 + NFT_MSG_GETCHAIN = 0x4 + NFT_MSG_DELCHAIN = 0x5 + NFT_MSG_NEWRULE = 0x6 + NFT_MSG_GETRULE = 0x7 + NFT_MSG_DELRULE = 0x8 + NFT_MSG_NEWSET = 0x9 + NFT_MSG_GETSET = 0xa + NFT_MSG_DELSET = 0xb + NFT_MSG_NEWSETELEM = 0xc + NFT_MSG_GETSETELEM = 0xd + NFT_MSG_DELSETELEM = 0xe + NFT_MSG_NEWGEN = 0xf + NFT_MSG_GETGEN = 0x10 + NFT_MSG_TRACE = 0x11 + NFT_MSG_NEWOBJ = 0x12 + NFT_MSG_GETOBJ = 0x13 + NFT_MSG_DELOBJ = 0x14 + NFT_MSG_GETOBJ_RESET = 0x15 + NFT_MSG_MAX = 0x19 + NFTA_LIST_UNPEC = 0x0 + NFTA_LIST_ELEM = 0x1 + NFTA_HOOK_UNSPEC = 0x0 + NFTA_HOOK_HOOKNUM = 0x1 + NFTA_HOOK_PRIORITY = 0x2 + NFTA_HOOK_DEV = 0x3 + NFT_TABLE_F_DORMANT = 0x1 + NFTA_TABLE_UNSPEC = 0x0 + NFTA_TABLE_NAME = 0x1 + NFTA_TABLE_FLAGS = 0x2 + NFTA_TABLE_USE = 0x3 + NFTA_CHAIN_UNSPEC = 0x0 + NFTA_CHAIN_TABLE = 0x1 + NFTA_CHAIN_HANDLE = 0x2 + NFTA_CHAIN_NAME = 0x3 + NFTA_CHAIN_HOOK = 0x4 + NFTA_CHAIN_POLICY = 0x5 + NFTA_CHAIN_USE = 0x6 + NFTA_CHAIN_TYPE = 0x7 + NFTA_CHAIN_COUNTERS = 0x8 + NFTA_CHAIN_PAD = 0x9 + NFTA_RULE_UNSPEC = 0x0 + NFTA_RULE_TABLE = 0x1 + NFTA_RULE_CHAIN = 0x2 + NFTA_RULE_HANDLE = 0x3 + NFTA_RULE_EXPRESSIONS = 0x4 + NFTA_RULE_COMPAT = 0x5 + NFTA_RULE_POSITION = 0x6 + NFTA_RULE_USERDATA = 0x7 + NFTA_RULE_PAD = 0x8 + NFTA_RULE_ID = 0x9 + NFT_RULE_COMPAT_F_INV = 0x2 + NFT_RULE_COMPAT_F_MASK = 0x2 + NFTA_RULE_COMPAT_UNSPEC = 0x0 + NFTA_RULE_COMPAT_PROTO = 0x1 + NFTA_RULE_COMPAT_FLAGS = 0x2 + NFT_SET_ANONYMOUS = 0x1 + NFT_SET_CONSTANT = 0x2 + NFT_SET_INTERVAL = 0x4 + NFT_SET_MAP = 0x8 + NFT_SET_TIMEOUT = 0x10 + NFT_SET_EVAL = 0x20 + NFT_SET_OBJECT = 0x40 + NFT_SET_POL_PERFORMANCE = 0x0 + NFT_SET_POL_MEMORY = 0x1 + NFTA_SET_DESC_UNSPEC = 0x0 + NFTA_SET_DESC_SIZE = 0x1 + NFTA_SET_UNSPEC = 0x0 + NFTA_SET_TABLE = 0x1 + NFTA_SET_NAME = 0x2 + NFTA_SET_FLAGS = 0x3 + NFTA_SET_KEY_TYPE = 0x4 + NFTA_SET_KEY_LEN = 0x5 + NFTA_SET_DATA_TYPE = 0x6 + NFTA_SET_DATA_LEN = 0x7 + NFTA_SET_POLICY = 0x8 + NFTA_SET_DESC = 0x9 + NFTA_SET_ID = 0xa + NFTA_SET_TIMEOUT = 0xb + NFTA_SET_GC_INTERVAL = 0xc + NFTA_SET_USERDATA = 0xd + NFTA_SET_PAD = 0xe + NFTA_SET_OBJ_TYPE = 0xf + NFT_SET_ELEM_INTERVAL_END = 0x1 + NFTA_SET_ELEM_UNSPEC = 0x0 + NFTA_SET_ELEM_KEY = 0x1 + NFTA_SET_ELEM_DATA = 0x2 + NFTA_SET_ELEM_FLAGS = 0x3 + NFTA_SET_ELEM_TIMEOUT = 0x4 + NFTA_SET_ELEM_EXPIRATION = 0x5 + NFTA_SET_ELEM_USERDATA = 0x6 + NFTA_SET_ELEM_EXPR = 0x7 + NFTA_SET_ELEM_PAD = 0x8 + NFTA_SET_ELEM_OBJREF = 0x9 + NFTA_SET_ELEM_LIST_UNSPEC = 0x0 + NFTA_SET_ELEM_LIST_TABLE = 0x1 + NFTA_SET_ELEM_LIST_SET = 0x2 + NFTA_SET_ELEM_LIST_ELEMENTS = 0x3 + NFTA_SET_ELEM_LIST_SET_ID = 0x4 + NFT_DATA_VALUE = 0x0 + NFT_DATA_VERDICT = 0xffffff00 + NFTA_DATA_UNSPEC = 0x0 + NFTA_DATA_VALUE = 0x1 + NFTA_DATA_VERDICT = 0x2 + NFTA_VERDICT_UNSPEC = 0x0 + NFTA_VERDICT_CODE = 0x1 + NFTA_VERDICT_CHAIN = 0x2 + NFTA_EXPR_UNSPEC = 0x0 + NFTA_EXPR_NAME = 0x1 + NFTA_EXPR_DATA = 0x2 + NFTA_IMMEDIATE_UNSPEC = 0x0 + NFTA_IMMEDIATE_DREG = 0x1 + NFTA_IMMEDIATE_DATA = 0x2 + NFTA_BITWISE_UNSPEC = 0x0 + NFTA_BITWISE_SREG = 0x1 + NFTA_BITWISE_DREG = 0x2 + NFTA_BITWISE_LEN = 0x3 + NFTA_BITWISE_MASK = 0x4 + NFTA_BITWISE_XOR = 0x5 + NFT_BYTEORDER_NTOH = 0x0 + NFT_BYTEORDER_HTON = 0x1 + NFTA_BYTEORDER_UNSPEC = 0x0 + NFTA_BYTEORDER_SREG = 0x1 + NFTA_BYTEORDER_DREG = 0x2 + NFTA_BYTEORDER_OP = 0x3 + NFTA_BYTEORDER_LEN = 0x4 + NFTA_BYTEORDER_SIZE = 0x5 + NFT_CMP_EQ = 0x0 + NFT_CMP_NEQ = 0x1 + NFT_CMP_LT = 0x2 + NFT_CMP_LTE = 0x3 + NFT_CMP_GT = 0x4 + NFT_CMP_GTE = 0x5 + NFTA_CMP_UNSPEC = 0x0 + NFTA_CMP_SREG = 0x1 + NFTA_CMP_OP = 0x2 + NFTA_CMP_DATA = 0x3 + NFT_RANGE_EQ = 0x0 + NFT_RANGE_NEQ = 0x1 + NFTA_RANGE_UNSPEC = 0x0 + NFTA_RANGE_SREG = 0x1 + NFTA_RANGE_OP = 0x2 + NFTA_RANGE_FROM_DATA = 0x3 + NFTA_RANGE_TO_DATA = 0x4 + NFT_LOOKUP_F_INV = 0x1 + NFTA_LOOKUP_UNSPEC = 0x0 + NFTA_LOOKUP_SET = 0x1 + NFTA_LOOKUP_SREG = 0x2 + NFTA_LOOKUP_DREG = 0x3 + NFTA_LOOKUP_SET_ID = 0x4 + NFTA_LOOKUP_FLAGS = 0x5 + NFT_DYNSET_OP_ADD = 0x0 + NFT_DYNSET_OP_UPDATE = 0x1 + NFT_DYNSET_F_INV = 0x1 + NFTA_DYNSET_UNSPEC = 0x0 + NFTA_DYNSET_SET_NAME = 0x1 + NFTA_DYNSET_SET_ID = 0x2 + NFTA_DYNSET_OP = 0x3 + NFTA_DYNSET_SREG_KEY = 0x4 + NFTA_DYNSET_SREG_DATA = 0x5 + NFTA_DYNSET_TIMEOUT = 0x6 + NFTA_DYNSET_EXPR = 0x7 + NFTA_DYNSET_PAD = 0x8 + NFTA_DYNSET_FLAGS = 0x9 + NFT_PAYLOAD_LL_HEADER = 0x0 + NFT_PAYLOAD_NETWORK_HEADER = 0x1 + NFT_PAYLOAD_TRANSPORT_HEADER = 0x2 + NFT_PAYLOAD_CSUM_NONE = 0x0 + NFT_PAYLOAD_CSUM_INET = 0x1 + NFT_PAYLOAD_L4CSUM_PSEUDOHDR = 0x1 + NFTA_PAYLOAD_UNSPEC = 0x0 + NFTA_PAYLOAD_DREG = 0x1 + NFTA_PAYLOAD_BASE = 0x2 + NFTA_PAYLOAD_OFFSET = 0x3 + NFTA_PAYLOAD_LEN = 0x4 + NFTA_PAYLOAD_SREG = 0x5 + NFTA_PAYLOAD_CSUM_TYPE = 0x6 + NFTA_PAYLOAD_CSUM_OFFSET = 0x7 + NFTA_PAYLOAD_CSUM_FLAGS = 0x8 + NFT_EXTHDR_F_PRESENT = 0x1 + NFT_EXTHDR_OP_IPV6 = 0x0 + NFT_EXTHDR_OP_TCPOPT = 0x1 + NFTA_EXTHDR_UNSPEC = 0x0 + NFTA_EXTHDR_DREG = 0x1 + NFTA_EXTHDR_TYPE = 0x2 + NFTA_EXTHDR_OFFSET = 0x3 + NFTA_EXTHDR_LEN = 0x4 + NFTA_EXTHDR_FLAGS = 0x5 + NFTA_EXTHDR_OP = 0x6 + NFTA_EXTHDR_SREG = 0x7 + NFT_META_LEN = 0x0 + NFT_META_PROTOCOL = 0x1 + NFT_META_PRIORITY = 0x2 + NFT_META_MARK = 0x3 + NFT_META_IIF = 0x4 + NFT_META_OIF = 0x5 + NFT_META_IIFNAME = 0x6 + NFT_META_OIFNAME = 0x7 + NFT_META_IIFTYPE = 0x8 + NFT_META_OIFTYPE = 0x9 + NFT_META_SKUID = 0xa + NFT_META_SKGID = 0xb + NFT_META_NFTRACE = 0xc + NFT_META_RTCLASSID = 0xd + NFT_META_SECMARK = 0xe + NFT_META_NFPROTO = 0xf + NFT_META_L4PROTO = 0x10 + NFT_META_BRI_IIFNAME = 0x11 + NFT_META_BRI_OIFNAME = 0x12 + NFT_META_PKTTYPE = 0x13 + NFT_META_CPU = 0x14 + NFT_META_IIFGROUP = 0x15 + NFT_META_OIFGROUP = 0x16 + NFT_META_CGROUP = 0x17 + NFT_META_PRANDOM = 0x18 + NFT_RT_CLASSID = 0x0 + NFT_RT_NEXTHOP4 = 0x1 + NFT_RT_NEXTHOP6 = 0x2 + NFT_RT_TCPMSS = 0x3 + NFT_HASH_JENKINS = 0x0 + NFT_HASH_SYM = 0x1 + NFTA_HASH_UNSPEC = 0x0 + NFTA_HASH_SREG = 0x1 + NFTA_HASH_DREG = 0x2 + NFTA_HASH_LEN = 0x3 + NFTA_HASH_MODULUS = 0x4 + NFTA_HASH_SEED = 0x5 + NFTA_HASH_OFFSET = 0x6 + NFTA_HASH_TYPE = 0x7 + NFTA_META_UNSPEC = 0x0 + NFTA_META_DREG = 0x1 + NFTA_META_KEY = 0x2 + NFTA_META_SREG = 0x3 + NFTA_RT_UNSPEC = 0x0 + NFTA_RT_DREG = 0x1 + NFTA_RT_KEY = 0x2 + NFT_CT_STATE = 0x0 + NFT_CT_DIRECTION = 0x1 + NFT_CT_STATUS = 0x2 + NFT_CT_MARK = 0x3 + NFT_CT_SECMARK = 0x4 + NFT_CT_EXPIRATION = 0x5 + NFT_CT_HELPER = 0x6 + NFT_CT_L3PROTOCOL = 0x7 + NFT_CT_SRC = 0x8 + NFT_CT_DST = 0x9 + NFT_CT_PROTOCOL = 0xa + NFT_CT_PROTO_SRC = 0xb + NFT_CT_PROTO_DST = 0xc + NFT_CT_LABELS = 0xd + NFT_CT_PKTS = 0xe + NFT_CT_BYTES = 0xf + NFT_CT_AVGPKT = 0x10 + NFT_CT_ZONE = 0x11 + NFT_CT_EVENTMASK = 0x12 + NFTA_CT_UNSPEC = 0x0 + NFTA_CT_DREG = 0x1 + NFTA_CT_KEY = 0x2 + NFTA_CT_DIRECTION = 0x3 + NFTA_CT_SREG = 0x4 + NFT_LIMIT_PKTS = 0x0 + NFT_LIMIT_PKT_BYTES = 0x1 + NFT_LIMIT_F_INV = 0x1 + NFTA_LIMIT_UNSPEC = 0x0 + NFTA_LIMIT_RATE = 0x1 + NFTA_LIMIT_UNIT = 0x2 + NFTA_LIMIT_BURST = 0x3 + NFTA_LIMIT_TYPE = 0x4 + NFTA_LIMIT_FLAGS = 0x5 + NFTA_LIMIT_PAD = 0x6 + NFTA_COUNTER_UNSPEC = 0x0 + NFTA_COUNTER_BYTES = 0x1 + NFTA_COUNTER_PACKETS = 0x2 + NFTA_COUNTER_PAD = 0x3 + NFTA_LOG_UNSPEC = 0x0 + NFTA_LOG_GROUP = 0x1 + NFTA_LOG_PREFIX = 0x2 + NFTA_LOG_SNAPLEN = 0x3 + NFTA_LOG_QTHRESHOLD = 0x4 + NFTA_LOG_LEVEL = 0x5 + NFTA_LOG_FLAGS = 0x6 + NFTA_QUEUE_UNSPEC = 0x0 + NFTA_QUEUE_NUM = 0x1 + NFTA_QUEUE_TOTAL = 0x2 + NFTA_QUEUE_FLAGS = 0x3 + NFTA_QUEUE_SREG_QNUM = 0x4 + NFT_QUOTA_F_INV = 0x1 + NFT_QUOTA_F_DEPLETED = 0x2 + NFTA_QUOTA_UNSPEC = 0x0 + NFTA_QUOTA_BYTES = 0x1 + NFTA_QUOTA_FLAGS = 0x2 + NFTA_QUOTA_PAD = 0x3 + NFTA_QUOTA_CONSUMED = 0x4 + NFT_REJECT_ICMP_UNREACH = 0x0 + NFT_REJECT_TCP_RST = 0x1 + NFT_REJECT_ICMPX_UNREACH = 0x2 + NFT_REJECT_ICMPX_NO_ROUTE = 0x0 + NFT_REJECT_ICMPX_PORT_UNREACH = 0x1 + NFT_REJECT_ICMPX_HOST_UNREACH = 0x2 + NFT_REJECT_ICMPX_ADMIN_PROHIBITED = 0x3 + NFTA_REJECT_UNSPEC = 0x0 + NFTA_REJECT_TYPE = 0x1 + NFTA_REJECT_ICMP_CODE = 0x2 + NFT_NAT_SNAT = 0x0 + NFT_NAT_DNAT = 0x1 + NFTA_NAT_UNSPEC = 0x0 + NFTA_NAT_TYPE = 0x1 + NFTA_NAT_FAMILY = 0x2 + NFTA_NAT_REG_ADDR_MIN = 0x3 + NFTA_NAT_REG_ADDR_MAX = 0x4 + NFTA_NAT_REG_PROTO_MIN = 0x5 + NFTA_NAT_REG_PROTO_MAX = 0x6 + NFTA_NAT_FLAGS = 0x7 + NFTA_MASQ_UNSPEC = 0x0 + NFTA_MASQ_FLAGS = 0x1 + NFTA_MASQ_REG_PROTO_MIN = 0x2 + NFTA_MASQ_REG_PROTO_MAX = 0x3 + NFTA_REDIR_UNSPEC = 0x0 + NFTA_REDIR_REG_PROTO_MIN = 0x1 + NFTA_REDIR_REG_PROTO_MAX = 0x2 + NFTA_REDIR_FLAGS = 0x3 + NFTA_DUP_UNSPEC = 0x0 + NFTA_DUP_SREG_ADDR = 0x1 + NFTA_DUP_SREG_DEV = 0x2 + NFTA_FWD_UNSPEC = 0x0 + NFTA_FWD_SREG_DEV = 0x1 + NFTA_OBJREF_UNSPEC = 0x0 + NFTA_OBJREF_IMM_TYPE = 0x1 + NFTA_OBJREF_IMM_NAME = 0x2 + NFTA_OBJREF_SET_SREG = 0x3 + NFTA_OBJREF_SET_NAME = 0x4 + NFTA_OBJREF_SET_ID = 0x5 + NFTA_GEN_UNSPEC = 0x0 + NFTA_GEN_ID = 0x1 + NFTA_GEN_PROC_PID = 0x2 + NFTA_GEN_PROC_NAME = 0x3 + NFTA_FIB_UNSPEC = 0x0 + NFTA_FIB_DREG = 0x1 + NFTA_FIB_RESULT = 0x2 + NFTA_FIB_FLAGS = 0x3 + NFT_FIB_RESULT_UNSPEC = 0x0 + NFT_FIB_RESULT_OIF = 0x1 + NFT_FIB_RESULT_OIFNAME = 0x2 + NFT_FIB_RESULT_ADDRTYPE = 0x3 + NFTA_FIB_F_SADDR = 0x1 + NFTA_FIB_F_DADDR = 0x2 + NFTA_FIB_F_MARK = 0x4 + NFTA_FIB_F_IIF = 0x8 + NFTA_FIB_F_OIF = 0x10 + NFTA_FIB_F_PRESENT = 0x20 + NFTA_CT_HELPER_UNSPEC = 0x0 + NFTA_CT_HELPER_NAME = 0x1 + NFTA_CT_HELPER_L3PROTO = 0x2 + NFTA_CT_HELPER_L4PROTO = 0x3 + NFTA_OBJ_UNSPEC = 0x0 + NFTA_OBJ_TABLE = 0x1 + NFTA_OBJ_NAME = 0x2 + NFTA_OBJ_TYPE = 0x3 + NFTA_OBJ_DATA = 0x4 + NFTA_OBJ_USE = 0x5 + NFTA_TRACE_UNSPEC = 0x0 + NFTA_TRACE_TABLE = 0x1 + NFTA_TRACE_CHAIN = 0x2 + NFTA_TRACE_RULE_HANDLE = 0x3 + NFTA_TRACE_TYPE = 0x4 + NFTA_TRACE_VERDICT = 0x5 + NFTA_TRACE_ID = 0x6 + NFTA_TRACE_LL_HEADER = 0x7 + NFTA_TRACE_NETWORK_HEADER = 0x8 + NFTA_TRACE_TRANSPORT_HEADER = 0x9 + NFTA_TRACE_IIF = 0xa + NFTA_TRACE_IIFTYPE = 0xb + NFTA_TRACE_OIF = 0xc + NFTA_TRACE_OIFTYPE = 0xd + NFTA_TRACE_MARK = 0xe + NFTA_TRACE_NFPROTO = 0xf + NFTA_TRACE_POLICY = 0x10 + NFTA_TRACE_PAD = 0x11 + NFT_TRACETYPE_UNSPEC = 0x0 + NFT_TRACETYPE_POLICY = 0x1 + NFT_TRACETYPE_RETURN = 0x2 + NFT_TRACETYPE_RULE = 0x3 + NFTA_NG_UNSPEC = 0x0 + NFTA_NG_DREG = 0x1 + NFTA_NG_MODULUS = 0x2 + NFTA_NG_TYPE = 0x3 + NFTA_NG_OFFSET = 0x4 + NFT_NG_INCREMENTAL = 0x0 + NFT_NG_RANDOM = 0x1 +) + +type RTCTime struct { + Sec int32 + Min int32 + Hour int32 + Mday int32 + Mon int32 + Year int32 + Wday int32 + Yday int32 + Isdst int32 +} + +type RTCWkAlrm struct { + Enabled uint8 + Pending uint8 + Time RTCTime +} + +type RTCPLLInfo struct { + Ctrl int32 + Value int32 + Max int32 + Min int32 + Posmult int32 + Negmult int32 + Clock int64 +} + +type BlkpgIoctlArg struct { + Op int32 + Flags int32 + Datalen int32 + Data *byte +} + +type BlkpgPartition struct { + Start int64 + Length int64 + Pno int32 + Devname [64]uint8 + Volname [64]uint8 + _ [4]byte +} + +const ( + BLKPG = 0x20001269 + BLKPG_ADD_PARTITION = 0x1 + BLKPG_DEL_PARTITION = 0x2 + BLKPG_RESIZE_PARTITION = 0x3 +) + +const ( + NETNSA_NONE = 0x0 + NETNSA_NSID = 0x1 + NETNSA_PID = 0x2 + NETNSA_FD = 0x3 +) + +type XDPRingOffset struct { + Producer uint64 + Consumer uint64 + Desc uint64 +} + +type XDPMmapOffsets struct { + Rx XDPRingOffset + Tx XDPRingOffset + Fr XDPRingOffset + Cr XDPRingOffset +} + +type XDPUmemReg struct { + Addr uint64 + Len uint64 + Size uint32 + Headroom uint32 +} + +type XDPStatistics struct { + Rx_dropped uint64 + Rx_invalid_descs uint64 + Tx_invalid_descs uint64 +} + +type XDPDesc struct { + Addr uint64 + Len uint32 + Options uint32 +} + +const ( + NCSI_CMD_UNSPEC = 0x0 + NCSI_CMD_PKG_INFO = 0x1 + NCSI_CMD_SET_INTERFACE = 0x2 + NCSI_CMD_CLEAR_INTERFACE = 0x3 + NCSI_ATTR_UNSPEC = 0x0 + NCSI_ATTR_IFINDEX = 0x1 + NCSI_ATTR_PACKAGE_LIST = 0x2 + NCSI_ATTR_PACKAGE_ID = 0x3 + NCSI_ATTR_CHANNEL_ID = 0x4 + NCSI_PKG_ATTR_UNSPEC = 0x0 + NCSI_PKG_ATTR = 0x1 + NCSI_PKG_ATTR_ID = 0x2 + NCSI_PKG_ATTR_FORCED = 0x3 + NCSI_PKG_ATTR_CHANNEL_LIST = 0x4 + NCSI_CHANNEL_ATTR_UNSPEC = 0x0 + NCSI_CHANNEL_ATTR = 0x1 + NCSI_CHANNEL_ATTR_ID = 0x2 + NCSI_CHANNEL_ATTR_VERSION_MAJOR = 0x3 + NCSI_CHANNEL_ATTR_VERSION_MINOR = 0x4 + NCSI_CHANNEL_ATTR_VERSION_STR = 0x5 + NCSI_CHANNEL_ATTR_LINK_STATE = 0x6 + NCSI_CHANNEL_ATTR_ACTIVE = 0x7 + NCSI_CHANNEL_ATTR_FORCED = 0x8 + NCSI_CHANNEL_ATTR_VLAN_LIST = 0x9 + NCSI_CHANNEL_ATTR_VLAN_ID = 0xa +) + +type ScmTimestamping struct { + Ts [3]Timespec +} + +const ( + SOF_TIMESTAMPING_TX_HARDWARE = 0x1 + SOF_TIMESTAMPING_TX_SOFTWARE = 0x2 + SOF_TIMESTAMPING_RX_HARDWARE = 0x4 + SOF_TIMESTAMPING_RX_SOFTWARE = 0x8 + SOF_TIMESTAMPING_SOFTWARE = 0x10 + SOF_TIMESTAMPING_SYS_HARDWARE = 0x20 + SOF_TIMESTAMPING_RAW_HARDWARE = 0x40 + SOF_TIMESTAMPING_OPT_ID = 0x80 + SOF_TIMESTAMPING_TX_SCHED = 0x100 + SOF_TIMESTAMPING_TX_ACK = 0x200 + SOF_TIMESTAMPING_OPT_CMSG = 0x400 + SOF_TIMESTAMPING_OPT_TSONLY = 0x800 + SOF_TIMESTAMPING_OPT_STATS = 0x1000 + SOF_TIMESTAMPING_OPT_PKTINFO = 0x2000 + SOF_TIMESTAMPING_OPT_TX_SWHW = 0x4000 + + SOF_TIMESTAMPING_LAST = 0x4000 + SOF_TIMESTAMPING_MASK = 0x7fff + + SCM_TSTAMP_SND = 0x0 + SCM_TSTAMP_SCHED = 0x1 + SCM_TSTAMP_ACK = 0x2 +) + +type SockExtendedErr struct { + Errno uint32 + Origin uint8 + Type uint8 + Code uint8 + Pad uint8 + Info uint32 + Data uint32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go b/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go index 15e6b4b4b1..57379005b5 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go @@ -6,11 +6,11 @@ package unix const ( - sizeofPtr = 0x8 - sizeofShort = 0x2 - sizeofInt = 0x4 - sizeofLong = 0x8 - sizeofLongLong = 0x8 + SizeofPtr = 0x8 + SizeofShort = 0x2 + SizeofInt = 0x4 + SizeofLong = 0x8 + SizeofLongLong = 0x8 PathMax = 0x1000 ) @@ -33,13 +33,11 @@ type Timeval struct { type Timex struct { Modes uint32 - Pad_cgo_0 [4]byte Offset int64 Freq int64 Maxerror int64 Esterror int64 Status int32 - Pad_cgo_1 [4]byte Constant int64 Precision int64 Tolerance int64 @@ -48,14 +46,13 @@ type Timex struct { Ppsfreq int64 Jitter int64 Shift int32 - Pad_cgo_2 [4]byte Stabil int64 Jitcnt int64 Calcnt int64 Errcnt int64 Stbcnt int64 Tai int32 - Pad_cgo_3 [44]byte + _ [44]byte } type Time_t int64 @@ -117,42 +114,56 @@ type Stat_t struct { Blocks int64 } -type Statfs_t struct { - Type int64 - Bsize int64 - Frsize int64 - Blocks uint64 - Bfree uint64 - Files uint64 - Ffree uint64 - Bavail uint64 - Fsid Fsid - Namelen int64 - Flags int64 - Spare [5]int64 +type StatxTimestamp struct { + Sec int64 + Nsec uint32 + _ int32 +} + +type Statx_t struct { + Mask uint32 + Blksize uint32 + Attributes uint64 + Nlink uint32 + Uid uint32 + Gid uint32 + Mode uint16 + _ [1]uint16 + Ino uint64 + Size uint64 + Blocks uint64 + Attributes_mask uint64 + Atime StatxTimestamp + Btime StatxTimestamp + Ctime StatxTimestamp + Mtime StatxTimestamp + Rdev_major uint32 + Rdev_minor uint32 + Dev_major uint32 + Dev_minor uint32 + _ [14]uint64 } type Dirent struct { - Ino uint64 - Off int64 - Reclen uint16 - Type uint8 - Name [256]int8 - Pad_cgo_0 [5]byte + Ino uint64 + Off int64 + Reclen uint16 + Type uint8 + Name [256]int8 + _ [5]byte } type Fsid struct { - X__val [2]int32 + Val [2]int32 } type Flock_t struct { - Type int16 - Whence int16 - Pad_cgo_0 [4]byte - Start int64 - Len int64 - Pid int32 - Pad_cgo_1 [4]byte + Type int16 + Whence int16 + Start int64 + Len int64 + Pid int32 + _ [4]byte } type FscryptPolicy struct { @@ -227,11 +238,26 @@ type RawSockaddrHCI struct { Channel uint16 } +type RawSockaddrL2 struct { + Family uint16 + Psm uint16 + Bdaddr [6]uint8 + Cid uint16 + Bdaddr_type uint8 + _ [1]byte +} + +type RawSockaddrRFCOMM struct { + Family uint16 + Bdaddr [6]uint8 + Channel uint8 + _ [1]byte +} + type RawSockaddrCAN struct { - Family uint16 - Pad_cgo_0 [2]byte - Ifindex int32 - Addr [8]byte + Family uint16 + Ifindex int32 + Addr [8]byte } type RawSockaddrALG struct { @@ -250,6 +276,16 @@ type RawSockaddrVM struct { Zero [4]uint8 } +type RawSockaddrXDP struct { + Family uint16 + Flags uint16 + Ifindex uint32 + Queue_id uint32 + Shared_umem_fd uint32 +} + +type RawSockaddrPPPoX [0x1e]byte + type RawSockaddr struct { Family uint16 Data [14]int8 @@ -298,13 +334,12 @@ type PacketMreq struct { type Msghdr struct { Name *byte Namelen uint32 - Pad_cgo_0 [4]byte Iov *Iovec Iovlen uint64 Control *byte Controllen uint64 Flags int32 - Pad_cgo_1 [4]byte + _ [4]byte } type Cmsghdr struct { @@ -346,7 +381,6 @@ type TCPInfo struct { Probes uint8 Backoff uint8 Options uint8 - Pad_cgo_0 [2]byte Rto uint32 Ato uint32 Snd_mss uint32 @@ -381,9 +415,13 @@ const ( SizeofSockaddrLinklayer = 0x14 SizeofSockaddrNetlink = 0xc SizeofSockaddrHCI = 0x6 + SizeofSockaddrL2 = 0xe + SizeofSockaddrRFCOMM = 0xa SizeofSockaddrCAN = 0x10 SizeofSockaddrALG = 0x58 SizeofSockaddrVM = 0x10 + SizeofSockaddrXDP = 0x10 + SizeofSockaddrPPPoX = 0x1e SizeofLinger = 0x8 SizeofIovec = 0x10 SizeofIPMreq = 0x8 @@ -401,97 +439,138 @@ const ( ) const ( - IFA_UNSPEC = 0x0 - IFA_ADDRESS = 0x1 - IFA_LOCAL = 0x2 - IFA_LABEL = 0x3 - IFA_BROADCAST = 0x4 - IFA_ANYCAST = 0x5 - IFA_CACHEINFO = 0x6 - IFA_MULTICAST = 0x7 - IFLA_UNSPEC = 0x0 - IFLA_ADDRESS = 0x1 - IFLA_BROADCAST = 0x2 - IFLA_IFNAME = 0x3 - IFLA_MTU = 0x4 - IFLA_LINK = 0x5 - IFLA_QDISC = 0x6 - IFLA_STATS = 0x7 - IFLA_COST = 0x8 - IFLA_PRIORITY = 0x9 - IFLA_MASTER = 0xa - IFLA_WIRELESS = 0xb - IFLA_PROTINFO = 0xc - IFLA_TXQLEN = 0xd - IFLA_MAP = 0xe - IFLA_WEIGHT = 0xf - IFLA_OPERSTATE = 0x10 - IFLA_LINKMODE = 0x11 - IFLA_LINKINFO = 0x12 - IFLA_NET_NS_PID = 0x13 - IFLA_IFALIAS = 0x14 - IFLA_MAX = 0x2c - RT_SCOPE_UNIVERSE = 0x0 - RT_SCOPE_SITE = 0xc8 - RT_SCOPE_LINK = 0xfd - RT_SCOPE_HOST = 0xfe - RT_SCOPE_NOWHERE = 0xff - RT_TABLE_UNSPEC = 0x0 - RT_TABLE_COMPAT = 0xfc - RT_TABLE_DEFAULT = 0xfd - RT_TABLE_MAIN = 0xfe - RT_TABLE_LOCAL = 0xff - RT_TABLE_MAX = 0xffffffff - RTA_UNSPEC = 0x0 - RTA_DST = 0x1 - RTA_SRC = 0x2 - RTA_IIF = 0x3 - RTA_OIF = 0x4 - RTA_GATEWAY = 0x5 - RTA_PRIORITY = 0x6 - RTA_PREFSRC = 0x7 - RTA_METRICS = 0x8 - RTA_MULTIPATH = 0x9 - RTA_FLOW = 0xb - RTA_CACHEINFO = 0xc - RTA_TABLE = 0xf - RTN_UNSPEC = 0x0 - RTN_UNICAST = 0x1 - RTN_LOCAL = 0x2 - RTN_BROADCAST = 0x3 - RTN_ANYCAST = 0x4 - RTN_MULTICAST = 0x5 - RTN_BLACKHOLE = 0x6 - RTN_UNREACHABLE = 0x7 - RTN_PROHIBIT = 0x8 - RTN_THROW = 0x9 - RTN_NAT = 0xa - RTN_XRESOLVE = 0xb - RTNLGRP_NONE = 0x0 - RTNLGRP_LINK = 0x1 - RTNLGRP_NOTIFY = 0x2 - RTNLGRP_NEIGH = 0x3 - RTNLGRP_TC = 0x4 - RTNLGRP_IPV4_IFADDR = 0x5 - RTNLGRP_IPV4_MROUTE = 0x6 - RTNLGRP_IPV4_ROUTE = 0x7 - RTNLGRP_IPV4_RULE = 0x8 - RTNLGRP_IPV6_IFADDR = 0x9 - RTNLGRP_IPV6_MROUTE = 0xa - RTNLGRP_IPV6_ROUTE = 0xb - RTNLGRP_IPV6_IFINFO = 0xc - RTNLGRP_IPV6_PREFIX = 0x12 - RTNLGRP_IPV6_RULE = 0x13 - RTNLGRP_ND_USEROPT = 0x14 - SizeofNlMsghdr = 0x10 - SizeofNlMsgerr = 0x14 - SizeofRtGenmsg = 0x1 - SizeofNlAttr = 0x4 - SizeofRtAttr = 0x4 - SizeofIfInfomsg = 0x10 - SizeofIfAddrmsg = 0x8 - SizeofRtMsg = 0xc - SizeofRtNexthop = 0x8 + IFA_UNSPEC = 0x0 + IFA_ADDRESS = 0x1 + IFA_LOCAL = 0x2 + IFA_LABEL = 0x3 + IFA_BROADCAST = 0x4 + IFA_ANYCAST = 0x5 + IFA_CACHEINFO = 0x6 + IFA_MULTICAST = 0x7 + IFLA_UNSPEC = 0x0 + IFLA_ADDRESS = 0x1 + IFLA_BROADCAST = 0x2 + IFLA_IFNAME = 0x3 + IFLA_INFO_KIND = 0x1 + IFLA_MTU = 0x4 + IFLA_LINK = 0x5 + IFLA_QDISC = 0x6 + IFLA_STATS = 0x7 + IFLA_COST = 0x8 + IFLA_PRIORITY = 0x9 + IFLA_MASTER = 0xa + IFLA_WIRELESS = 0xb + IFLA_PROTINFO = 0xc + IFLA_TXQLEN = 0xd + IFLA_MAP = 0xe + IFLA_WEIGHT = 0xf + IFLA_OPERSTATE = 0x10 + IFLA_LINKMODE = 0x11 + IFLA_LINKINFO = 0x12 + IFLA_NET_NS_PID = 0x13 + IFLA_IFALIAS = 0x14 + IFLA_NUM_VF = 0x15 + IFLA_VFINFO_LIST = 0x16 + IFLA_STATS64 = 0x17 + IFLA_VF_PORTS = 0x18 + IFLA_PORT_SELF = 0x19 + IFLA_AF_SPEC = 0x1a + IFLA_GROUP = 0x1b + IFLA_NET_NS_FD = 0x1c + IFLA_EXT_MASK = 0x1d + IFLA_PROMISCUITY = 0x1e + IFLA_NUM_TX_QUEUES = 0x1f + IFLA_NUM_RX_QUEUES = 0x20 + IFLA_CARRIER = 0x21 + IFLA_PHYS_PORT_ID = 0x22 + IFLA_CARRIER_CHANGES = 0x23 + IFLA_PHYS_SWITCH_ID = 0x24 + IFLA_LINK_NETNSID = 0x25 + IFLA_PHYS_PORT_NAME = 0x26 + IFLA_PROTO_DOWN = 0x27 + IFLA_GSO_MAX_SEGS = 0x28 + IFLA_GSO_MAX_SIZE = 0x29 + IFLA_PAD = 0x2a + IFLA_XDP = 0x2b + IFLA_EVENT = 0x2c + IFLA_NEW_NETNSID = 0x2d + IFLA_IF_NETNSID = 0x2e + IFLA_MAX = 0x33 + RT_SCOPE_UNIVERSE = 0x0 + RT_SCOPE_SITE = 0xc8 + RT_SCOPE_LINK = 0xfd + RT_SCOPE_HOST = 0xfe + RT_SCOPE_NOWHERE = 0xff + RT_TABLE_UNSPEC = 0x0 + RT_TABLE_COMPAT = 0xfc + RT_TABLE_DEFAULT = 0xfd + RT_TABLE_MAIN = 0xfe + RT_TABLE_LOCAL = 0xff + RT_TABLE_MAX = 0xffffffff + RTA_UNSPEC = 0x0 + RTA_DST = 0x1 + RTA_SRC = 0x2 + RTA_IIF = 0x3 + RTA_OIF = 0x4 + RTA_GATEWAY = 0x5 + RTA_PRIORITY = 0x6 + RTA_PREFSRC = 0x7 + RTA_METRICS = 0x8 + RTA_MULTIPATH = 0x9 + RTA_FLOW = 0xb + RTA_CACHEINFO = 0xc + RTA_TABLE = 0xf + RTA_MARK = 0x10 + RTA_MFC_STATS = 0x11 + RTA_VIA = 0x12 + RTA_NEWDST = 0x13 + RTA_PREF = 0x14 + RTA_ENCAP_TYPE = 0x15 + RTA_ENCAP = 0x16 + RTA_EXPIRES = 0x17 + RTA_PAD = 0x18 + RTA_UID = 0x19 + RTA_TTL_PROPAGATE = 0x1a + RTA_IP_PROTO = 0x1b + RTA_SPORT = 0x1c + RTA_DPORT = 0x1d + RTN_UNSPEC = 0x0 + RTN_UNICAST = 0x1 + RTN_LOCAL = 0x2 + RTN_BROADCAST = 0x3 + RTN_ANYCAST = 0x4 + RTN_MULTICAST = 0x5 + RTN_BLACKHOLE = 0x6 + RTN_UNREACHABLE = 0x7 + RTN_PROHIBIT = 0x8 + RTN_THROW = 0x9 + RTN_NAT = 0xa + RTN_XRESOLVE = 0xb + RTNLGRP_NONE = 0x0 + RTNLGRP_LINK = 0x1 + RTNLGRP_NOTIFY = 0x2 + RTNLGRP_NEIGH = 0x3 + RTNLGRP_TC = 0x4 + RTNLGRP_IPV4_IFADDR = 0x5 + RTNLGRP_IPV4_MROUTE = 0x6 + RTNLGRP_IPV4_ROUTE = 0x7 + RTNLGRP_IPV4_RULE = 0x8 + RTNLGRP_IPV6_IFADDR = 0x9 + RTNLGRP_IPV6_MROUTE = 0xa + RTNLGRP_IPV6_ROUTE = 0xb + RTNLGRP_IPV6_IFINFO = 0xc + RTNLGRP_IPV6_PREFIX = 0x12 + RTNLGRP_IPV6_RULE = 0x13 + RTNLGRP_ND_USEROPT = 0x14 + SizeofNlMsghdr = 0x10 + SizeofNlMsgerr = 0x14 + SizeofRtGenmsg = 0x1 + SizeofNlAttr = 0x4 + SizeofRtAttr = 0x4 + SizeofIfInfomsg = 0x10 + SizeofIfAddrmsg = 0x8 + SizeofRtMsg = 0xc + SizeofRtNexthop = 0x8 ) type NlMsghdr struct { @@ -522,12 +601,12 @@ type RtAttr struct { } type IfInfomsg struct { - Family uint8 - X__ifi_pad uint8 - Type uint16 - Index int32 - Flags uint32 - Change uint32 + Family uint8 + _ uint8 + Type uint16 + Index int32 + Flags uint32 + Change uint32 } type IfAddrmsg struct { @@ -570,9 +649,8 @@ type SockFilter struct { } type SockFprog struct { - Len uint16 - Pad_cgo_0 [6]byte - Filter *SockFilter + Len uint16 + Filter *SockFilter } type InotifyEvent struct { @@ -609,12 +687,11 @@ type Sysinfo_t struct { Freeswap uint64 Procs uint16 Pad uint16 - Pad_cgo_0 [4]byte Totalhigh uint64 Freehigh uint64 Unit uint32 - X_f [0]int8 - Pad_cgo_1 [4]byte + _ [0]int8 + _ [4]byte } type Utsname struct { @@ -627,12 +704,11 @@ type Utsname struct { } type Ustat_t struct { - Tfree int32 - Pad_cgo_0 [4]byte - Tinode uint64 - Fname [6]int8 - Fpack [6]int8 - Pad_cgo_1 [4]byte + Tfree int32 + Tinode uint64 + Fname [6]int8 + Fpack [6]int8 + _ [4]byte } type EpollEvent struct { @@ -642,10 +718,19 @@ type EpollEvent struct { } const ( - AT_FDCWD = -0x64 - AT_REMOVEDIR = 0x200 + AT_EMPTY_PATH = 0x1000 + AT_FDCWD = -0x64 + AT_NO_AUTOMOUNT = 0x800 + AT_REMOVEDIR = 0x200 + + AT_STATX_SYNC_AS_STAT = 0x0 + AT_STATX_FORCE_SYNC = 0x2000 + AT_STATX_DONT_SYNC = 0x4000 + AT_SYMLINK_FOLLOW = 0x400 AT_SYMLINK_NOFOLLOW = 0x100 + + AT_EACCESS = 0x200 ) type PollFd struct { @@ -665,10 +750,33 @@ const ( ) type Sigset_t struct { - X__val [16]uint64 + Val [16]uint64 } -const RNDGETENTCNT = 0x40045200 +type SignalfdSiginfo struct { + Signo uint32 + Errno int32 + Code int32 + Pid uint32 + Uid uint32 + Fd int32 + Tid uint32 + Band uint32 + Overrun uint32 + Trapno uint32 + Status int32 + Int int32 + Ptr uint64 + Utime uint64 + Stime uint64 + Addr uint64 + Addr_lsb uint16 + _ uint16 + Syscall int32 + Call_addr uint64 + Arch uint32 + _ [28]uint8 +} const PERF_IOC_FLAG_GROUP = 0x1 @@ -692,11 +800,9 @@ type Winsize struct { type Taskstats struct { Version uint16 - Pad_cgo_0 [2]byte Ac_exitcode uint32 Ac_flag uint8 Ac_nice uint8 - Pad_cgo_1 [6]byte Cpu_count uint64 Cpu_delay_total uint64 Blkio_count uint64 @@ -708,13 +814,12 @@ type Taskstats struct { Ac_comm [32]int8 Ac_sched uint8 Ac_pad [3]uint8 - Pad_cgo_2 [4]byte + _ [4]byte Ac_uid uint32 Ac_gid uint32 Ac_pid uint32 Ac_ppid uint32 Ac_btime uint32 - Pad_cgo_3 [4]byte Ac_etime uint64 Ac_utime uint64 Ac_stime uint64 @@ -738,6 +843,8 @@ type Taskstats struct { Cpu_scaled_run_real_total uint64 Freepages_count uint64 Freepages_delay_total uint64 + Thrashing_count uint64 + Thrashing_delay_total uint64 } const ( @@ -758,6 +865,24 @@ const ( TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK = 0x4 ) +type CGroupStats struct { + Sleeping uint64 + Running uint64 + Stopped uint64 + Uninterruptible uint64 + Io_wait uint64 +} + +const ( + CGROUPSTATS_CMD_UNSPEC = 0x3 + CGROUPSTATS_CMD_GET = 0x4 + CGROUPSTATS_CMD_NEW = 0x5 + CGROUPSTATS_TYPE_UNSPEC = 0x0 + CGROUPSTATS_TYPE_CGROUP_STATS = 0x1 + CGROUPSTATS_CMD_ATTR_UNSPEC = 0x0 + CGROUPSTATS_CMD_ATTR_FD = 0x1 +) + type Genlmsghdr struct { Cmd uint8 Version uint8 @@ -790,3 +915,1107 @@ const ( CTRL_ATTR_MCAST_GRP_NAME = 0x1 CTRL_ATTR_MCAST_GRP_ID = 0x2 ) + +type cpuMask uint64 + +const ( + _CPU_SETSIZE = 0x400 + _NCPUBITS = 0x40 +) + +const ( + BDADDR_BREDR = 0x0 + BDADDR_LE_PUBLIC = 0x1 + BDADDR_LE_RANDOM = 0x2 +) + +type PerfEventAttr struct { + Type uint32 + Size uint32 + Config uint64 + Sample uint64 + Sample_type uint64 + Read_format uint64 + Bits uint64 + Wakeup uint32 + Bp_type uint32 + Ext1 uint64 + Ext2 uint64 + Branch_sample_type uint64 + Sample_regs_user uint64 + Sample_stack_user uint32 + Clockid int32 + Sample_regs_intr uint64 + Aux_watermark uint32 + _ uint32 +} + +type PerfEventMmapPage struct { + Version uint32 + Compat_version uint32 + Lock uint32 + Index uint32 + Offset int64 + Time_enabled uint64 + Time_running uint64 + Capabilities uint64 + Pmc_width uint16 + Time_shift uint16 + Time_mult uint32 + Time_offset uint64 + Time_zero uint64 + Size uint32 + _ [948]uint8 + Data_head uint64 + Data_tail uint64 + Data_offset uint64 + Data_size uint64 + Aux_head uint64 + Aux_tail uint64 + Aux_offset uint64 + Aux_size uint64 +} + +const ( + PerfBitDisabled uint64 = CBitFieldMaskBit0 + PerfBitInherit = CBitFieldMaskBit1 + PerfBitPinned = CBitFieldMaskBit2 + PerfBitExclusive = CBitFieldMaskBit3 + PerfBitExcludeUser = CBitFieldMaskBit4 + PerfBitExcludeKernel = CBitFieldMaskBit5 + PerfBitExcludeHv = CBitFieldMaskBit6 + PerfBitExcludeIdle = CBitFieldMaskBit7 + PerfBitMmap = CBitFieldMaskBit8 + PerfBitComm = CBitFieldMaskBit9 + PerfBitFreq = CBitFieldMaskBit10 + PerfBitInheritStat = CBitFieldMaskBit11 + PerfBitEnableOnExec = CBitFieldMaskBit12 + PerfBitTask = CBitFieldMaskBit13 + PerfBitWatermark = CBitFieldMaskBit14 + PerfBitPreciseIPBit1 = CBitFieldMaskBit15 + PerfBitPreciseIPBit2 = CBitFieldMaskBit16 + PerfBitMmapData = CBitFieldMaskBit17 + PerfBitSampleIDAll = CBitFieldMaskBit18 + PerfBitExcludeHost = CBitFieldMaskBit19 + PerfBitExcludeGuest = CBitFieldMaskBit20 + PerfBitExcludeCallchainKernel = CBitFieldMaskBit21 + PerfBitExcludeCallchainUser = CBitFieldMaskBit22 + PerfBitMmap2 = CBitFieldMaskBit23 + PerfBitCommExec = CBitFieldMaskBit24 + PerfBitUseClockID = CBitFieldMaskBit25 + PerfBitContextSwitch = CBitFieldMaskBit26 +) + +const ( + PERF_TYPE_HARDWARE = 0x0 + PERF_TYPE_SOFTWARE = 0x1 + PERF_TYPE_TRACEPOINT = 0x2 + PERF_TYPE_HW_CACHE = 0x3 + PERF_TYPE_RAW = 0x4 + PERF_TYPE_BREAKPOINT = 0x5 + + PERF_COUNT_HW_CPU_CYCLES = 0x0 + PERF_COUNT_HW_INSTRUCTIONS = 0x1 + PERF_COUNT_HW_CACHE_REFERENCES = 0x2 + PERF_COUNT_HW_CACHE_MISSES = 0x3 + PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 0x4 + PERF_COUNT_HW_BRANCH_MISSES = 0x5 + PERF_COUNT_HW_BUS_CYCLES = 0x6 + PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 0x7 + PERF_COUNT_HW_STALLED_CYCLES_BACKEND = 0x8 + PERF_COUNT_HW_REF_CPU_CYCLES = 0x9 + + PERF_COUNT_HW_CACHE_L1D = 0x0 + PERF_COUNT_HW_CACHE_L1I = 0x1 + PERF_COUNT_HW_CACHE_LL = 0x2 + PERF_COUNT_HW_CACHE_DTLB = 0x3 + PERF_COUNT_HW_CACHE_ITLB = 0x4 + PERF_COUNT_HW_CACHE_BPU = 0x5 + PERF_COUNT_HW_CACHE_NODE = 0x6 + + PERF_COUNT_HW_CACHE_OP_READ = 0x0 + PERF_COUNT_HW_CACHE_OP_WRITE = 0x1 + PERF_COUNT_HW_CACHE_OP_PREFETCH = 0x2 + + PERF_COUNT_HW_CACHE_RESULT_ACCESS = 0x0 + PERF_COUNT_HW_CACHE_RESULT_MISS = 0x1 + + PERF_COUNT_SW_CPU_CLOCK = 0x0 + PERF_COUNT_SW_TASK_CLOCK = 0x1 + PERF_COUNT_SW_PAGE_FAULTS = 0x2 + PERF_COUNT_SW_CONTEXT_SWITCHES = 0x3 + PERF_COUNT_SW_CPU_MIGRATIONS = 0x4 + PERF_COUNT_SW_PAGE_FAULTS_MIN = 0x5 + PERF_COUNT_SW_PAGE_FAULTS_MAJ = 0x6 + PERF_COUNT_SW_ALIGNMENT_FAULTS = 0x7 + PERF_COUNT_SW_EMULATION_FAULTS = 0x8 + PERF_COUNT_SW_DUMMY = 0x9 + + PERF_SAMPLE_IP = 0x1 + PERF_SAMPLE_TID = 0x2 + PERF_SAMPLE_TIME = 0x4 + PERF_SAMPLE_ADDR = 0x8 + PERF_SAMPLE_READ = 0x10 + PERF_SAMPLE_CALLCHAIN = 0x20 + PERF_SAMPLE_ID = 0x40 + PERF_SAMPLE_CPU = 0x80 + PERF_SAMPLE_PERIOD = 0x100 + PERF_SAMPLE_STREAM_ID = 0x200 + PERF_SAMPLE_RAW = 0x400 + PERF_SAMPLE_BRANCH_STACK = 0x800 + + PERF_SAMPLE_BRANCH_USER = 0x1 + PERF_SAMPLE_BRANCH_KERNEL = 0x2 + PERF_SAMPLE_BRANCH_HV = 0x4 + PERF_SAMPLE_BRANCH_ANY = 0x8 + PERF_SAMPLE_BRANCH_ANY_CALL = 0x10 + PERF_SAMPLE_BRANCH_ANY_RETURN = 0x20 + PERF_SAMPLE_BRANCH_IND_CALL = 0x40 + + PERF_FORMAT_TOTAL_TIME_ENABLED = 0x1 + PERF_FORMAT_TOTAL_TIME_RUNNING = 0x2 + PERF_FORMAT_ID = 0x4 + PERF_FORMAT_GROUP = 0x8 + + PERF_RECORD_MMAP = 0x1 + PERF_RECORD_LOST = 0x2 + PERF_RECORD_COMM = 0x3 + PERF_RECORD_EXIT = 0x4 + PERF_RECORD_THROTTLE = 0x5 + PERF_RECORD_UNTHROTTLE = 0x6 + PERF_RECORD_FORK = 0x7 + PERF_RECORD_READ = 0x8 + PERF_RECORD_SAMPLE = 0x9 + + PERF_CONTEXT_HV = -0x20 + PERF_CONTEXT_KERNEL = -0x80 + PERF_CONTEXT_USER = -0x200 + + PERF_CONTEXT_GUEST = -0x800 + PERF_CONTEXT_GUEST_KERNEL = -0x880 + PERF_CONTEXT_GUEST_USER = -0xa00 + + PERF_FLAG_FD_NO_GROUP = 0x1 + PERF_FLAG_FD_OUTPUT = 0x2 + PERF_FLAG_PID_CGROUP = 0x4 +) + +const ( + CBitFieldMaskBit0 = 0x1 + CBitFieldMaskBit1 = 0x2 + CBitFieldMaskBit2 = 0x4 + CBitFieldMaskBit3 = 0x8 + CBitFieldMaskBit4 = 0x10 + CBitFieldMaskBit5 = 0x20 + CBitFieldMaskBit6 = 0x40 + CBitFieldMaskBit7 = 0x80 + CBitFieldMaskBit8 = 0x100 + CBitFieldMaskBit9 = 0x200 + CBitFieldMaskBit10 = 0x400 + CBitFieldMaskBit11 = 0x800 + CBitFieldMaskBit12 = 0x1000 + CBitFieldMaskBit13 = 0x2000 + CBitFieldMaskBit14 = 0x4000 + CBitFieldMaskBit15 = 0x8000 + CBitFieldMaskBit16 = 0x10000 + CBitFieldMaskBit17 = 0x20000 + CBitFieldMaskBit18 = 0x40000 + CBitFieldMaskBit19 = 0x80000 + CBitFieldMaskBit20 = 0x100000 + CBitFieldMaskBit21 = 0x200000 + CBitFieldMaskBit22 = 0x400000 + CBitFieldMaskBit23 = 0x800000 + CBitFieldMaskBit24 = 0x1000000 + CBitFieldMaskBit25 = 0x2000000 + CBitFieldMaskBit26 = 0x4000000 + CBitFieldMaskBit27 = 0x8000000 + CBitFieldMaskBit28 = 0x10000000 + CBitFieldMaskBit29 = 0x20000000 + CBitFieldMaskBit30 = 0x40000000 + CBitFieldMaskBit31 = 0x80000000 + CBitFieldMaskBit32 = 0x100000000 + CBitFieldMaskBit33 = 0x200000000 + CBitFieldMaskBit34 = 0x400000000 + CBitFieldMaskBit35 = 0x800000000 + CBitFieldMaskBit36 = 0x1000000000 + CBitFieldMaskBit37 = 0x2000000000 + CBitFieldMaskBit38 = 0x4000000000 + CBitFieldMaskBit39 = 0x8000000000 + CBitFieldMaskBit40 = 0x10000000000 + CBitFieldMaskBit41 = 0x20000000000 + CBitFieldMaskBit42 = 0x40000000000 + CBitFieldMaskBit43 = 0x80000000000 + CBitFieldMaskBit44 = 0x100000000000 + CBitFieldMaskBit45 = 0x200000000000 + CBitFieldMaskBit46 = 0x400000000000 + CBitFieldMaskBit47 = 0x800000000000 + CBitFieldMaskBit48 = 0x1000000000000 + CBitFieldMaskBit49 = 0x2000000000000 + CBitFieldMaskBit50 = 0x4000000000000 + CBitFieldMaskBit51 = 0x8000000000000 + CBitFieldMaskBit52 = 0x10000000000000 + CBitFieldMaskBit53 = 0x20000000000000 + CBitFieldMaskBit54 = 0x40000000000000 + CBitFieldMaskBit55 = 0x80000000000000 + CBitFieldMaskBit56 = 0x100000000000000 + CBitFieldMaskBit57 = 0x200000000000000 + CBitFieldMaskBit58 = 0x400000000000000 + CBitFieldMaskBit59 = 0x800000000000000 + CBitFieldMaskBit60 = 0x1000000000000000 + CBitFieldMaskBit61 = 0x2000000000000000 + CBitFieldMaskBit62 = 0x4000000000000000 + CBitFieldMaskBit63 = 0x8000000000000000 +) + +type SockaddrStorage struct { + Family uint16 + _ [118]int8 + _ uint64 +} + +type TCPMD5Sig struct { + Addr SockaddrStorage + Flags uint8 + Prefixlen uint8 + Keylen uint16 + _ uint32 + Key [80]uint8 +} + +type HDDriveCmdHdr struct { + Command uint8 + Number uint8 + Feature uint8 + Count uint8 +} + +type HDGeometry struct { + Heads uint8 + Sectors uint8 + Cylinders uint16 + Start uint64 +} + +type HDDriveID struct { + Config uint16 + Cyls uint16 + Reserved2 uint16 + Heads uint16 + Track_bytes uint16 + Sector_bytes uint16 + Sectors uint16 + Vendor0 uint16 + Vendor1 uint16 + Vendor2 uint16 + Serial_no [20]uint8 + Buf_type uint16 + Buf_size uint16 + Ecc_bytes uint16 + Fw_rev [8]uint8 + Model [40]uint8 + Max_multsect uint8 + Vendor3 uint8 + Dword_io uint16 + Vendor4 uint8 + Capability uint8 + Reserved50 uint16 + Vendor5 uint8 + TPIO uint8 + Vendor6 uint8 + TDMA uint8 + Field_valid uint16 + Cur_cyls uint16 + Cur_heads uint16 + Cur_sectors uint16 + Cur_capacity0 uint16 + Cur_capacity1 uint16 + Multsect uint8 + Multsect_valid uint8 + Lba_capacity uint32 + Dma_1word uint16 + Dma_mword uint16 + Eide_pio_modes uint16 + Eide_dma_min uint16 + Eide_dma_time uint16 + Eide_pio uint16 + Eide_pio_iordy uint16 + Words69_70 [2]uint16 + Words71_74 [4]uint16 + Queue_depth uint16 + Words76_79 [4]uint16 + Major_rev_num uint16 + Minor_rev_num uint16 + Command_set_1 uint16 + Command_set_2 uint16 + Cfsse uint16 + Cfs_enable_1 uint16 + Cfs_enable_2 uint16 + Csf_default uint16 + Dma_ultra uint16 + Trseuc uint16 + TrsEuc uint16 + CurAPMvalues uint16 + Mprc uint16 + Hw_config uint16 + Acoustic uint16 + Msrqs uint16 + Sxfert uint16 + Sal uint16 + Spg uint32 + Lba_capacity_2 uint64 + Words104_125 [22]uint16 + Last_lun uint16 + Word127 uint16 + Dlf uint16 + Csfo uint16 + Words130_155 [26]uint16 + Word156 uint16 + Words157_159 [3]uint16 + Cfa_power uint16 + Words161_175 [15]uint16 + Words176_205 [30]uint16 + Words206_254 [49]uint16 + Integrity_word uint16 +} + +type Statfs_t struct { + Type int64 + Bsize int64 + Frsize int64 + Blocks uint64 + Bfree uint64 + Files uint64 + Ffree uint64 + Bavail uint64 + Fsid Fsid + Namelen int64 + Flags int64 + Spare [5]int64 +} + +const ( + ST_MANDLOCK = 0x40 + ST_NOATIME = 0x400 + ST_NODEV = 0x4 + ST_NODIRATIME = 0x800 + ST_NOEXEC = 0x8 + ST_NOSUID = 0x2 + ST_RDONLY = 0x1 + ST_RELATIME = 0x1000 + ST_SYNCHRONOUS = 0x10 +) + +type TpacketHdr struct { + Status uint64 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Sec uint32 + Usec uint32 + _ [4]byte +} + +type Tpacket2Hdr struct { + Status uint32 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Sec uint32 + Nsec uint32 + Vlan_tci uint16 + Vlan_tpid uint16 + _ [4]uint8 +} + +type Tpacket3Hdr struct { + Next_offset uint32 + Sec uint32 + Nsec uint32 + Snaplen uint32 + Len uint32 + Status uint32 + Mac uint16 + Net uint16 + Hv1 TpacketHdrVariant1 + _ [8]uint8 +} + +type TpacketHdrVariant1 struct { + Rxhash uint32 + Vlan_tci uint32 + Vlan_tpid uint16 + _ uint16 +} + +type TpacketBlockDesc struct { + Version uint32 + To_priv uint32 + Hdr [40]byte +} + +type TpacketReq struct { + Block_size uint32 + Block_nr uint32 + Frame_size uint32 + Frame_nr uint32 +} + +type TpacketReq3 struct { + Block_size uint32 + Block_nr uint32 + Frame_size uint32 + Frame_nr uint32 + Retire_blk_tov uint32 + Sizeof_priv uint32 + Feature_req_word uint32 +} + +type TpacketStats struct { + Packets uint32 + Drops uint32 +} + +type TpacketStatsV3 struct { + Packets uint32 + Drops uint32 + Freeze_q_cnt uint32 +} + +type TpacketAuxdata struct { + Status uint32 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Vlan_tci uint16 + Vlan_tpid uint16 +} + +const ( + TPACKET_V1 = 0x0 + TPACKET_V2 = 0x1 + TPACKET_V3 = 0x2 +) + +const ( + SizeofTpacketHdr = 0x20 + SizeofTpacket2Hdr = 0x20 + SizeofTpacket3Hdr = 0x30 +) + +const ( + NF_INET_PRE_ROUTING = 0x0 + NF_INET_LOCAL_IN = 0x1 + NF_INET_FORWARD = 0x2 + NF_INET_LOCAL_OUT = 0x3 + NF_INET_POST_ROUTING = 0x4 + NF_INET_NUMHOOKS = 0x5 +) + +const ( + NF_NETDEV_INGRESS = 0x0 + NF_NETDEV_NUMHOOKS = 0x1 +) + +const ( + NFPROTO_UNSPEC = 0x0 + NFPROTO_INET = 0x1 + NFPROTO_IPV4 = 0x2 + NFPROTO_ARP = 0x3 + NFPROTO_NETDEV = 0x5 + NFPROTO_BRIDGE = 0x7 + NFPROTO_IPV6 = 0xa + NFPROTO_DECNET = 0xc + NFPROTO_NUMPROTO = 0xd +) + +type Nfgenmsg struct { + Nfgen_family uint8 + Version uint8 + Res_id uint16 +} + +const ( + NFNL_BATCH_UNSPEC = 0x0 + NFNL_BATCH_GENID = 0x1 +) + +const ( + NFT_REG_VERDICT = 0x0 + NFT_REG_1 = 0x1 + NFT_REG_2 = 0x2 + NFT_REG_3 = 0x3 + NFT_REG_4 = 0x4 + NFT_REG32_00 = 0x8 + NFT_REG32_01 = 0x9 + NFT_REG32_02 = 0xa + NFT_REG32_03 = 0xb + NFT_REG32_04 = 0xc + NFT_REG32_05 = 0xd + NFT_REG32_06 = 0xe + NFT_REG32_07 = 0xf + NFT_REG32_08 = 0x10 + NFT_REG32_09 = 0x11 + NFT_REG32_10 = 0x12 + NFT_REG32_11 = 0x13 + NFT_REG32_12 = 0x14 + NFT_REG32_13 = 0x15 + NFT_REG32_14 = 0x16 + NFT_REG32_15 = 0x17 + NFT_CONTINUE = -0x1 + NFT_BREAK = -0x2 + NFT_JUMP = -0x3 + NFT_GOTO = -0x4 + NFT_RETURN = -0x5 + NFT_MSG_NEWTABLE = 0x0 + NFT_MSG_GETTABLE = 0x1 + NFT_MSG_DELTABLE = 0x2 + NFT_MSG_NEWCHAIN = 0x3 + NFT_MSG_GETCHAIN = 0x4 + NFT_MSG_DELCHAIN = 0x5 + NFT_MSG_NEWRULE = 0x6 + NFT_MSG_GETRULE = 0x7 + NFT_MSG_DELRULE = 0x8 + NFT_MSG_NEWSET = 0x9 + NFT_MSG_GETSET = 0xa + NFT_MSG_DELSET = 0xb + NFT_MSG_NEWSETELEM = 0xc + NFT_MSG_GETSETELEM = 0xd + NFT_MSG_DELSETELEM = 0xe + NFT_MSG_NEWGEN = 0xf + NFT_MSG_GETGEN = 0x10 + NFT_MSG_TRACE = 0x11 + NFT_MSG_NEWOBJ = 0x12 + NFT_MSG_GETOBJ = 0x13 + NFT_MSG_DELOBJ = 0x14 + NFT_MSG_GETOBJ_RESET = 0x15 + NFT_MSG_MAX = 0x19 + NFTA_LIST_UNPEC = 0x0 + NFTA_LIST_ELEM = 0x1 + NFTA_HOOK_UNSPEC = 0x0 + NFTA_HOOK_HOOKNUM = 0x1 + NFTA_HOOK_PRIORITY = 0x2 + NFTA_HOOK_DEV = 0x3 + NFT_TABLE_F_DORMANT = 0x1 + NFTA_TABLE_UNSPEC = 0x0 + NFTA_TABLE_NAME = 0x1 + NFTA_TABLE_FLAGS = 0x2 + NFTA_TABLE_USE = 0x3 + NFTA_CHAIN_UNSPEC = 0x0 + NFTA_CHAIN_TABLE = 0x1 + NFTA_CHAIN_HANDLE = 0x2 + NFTA_CHAIN_NAME = 0x3 + NFTA_CHAIN_HOOK = 0x4 + NFTA_CHAIN_POLICY = 0x5 + NFTA_CHAIN_USE = 0x6 + NFTA_CHAIN_TYPE = 0x7 + NFTA_CHAIN_COUNTERS = 0x8 + NFTA_CHAIN_PAD = 0x9 + NFTA_RULE_UNSPEC = 0x0 + NFTA_RULE_TABLE = 0x1 + NFTA_RULE_CHAIN = 0x2 + NFTA_RULE_HANDLE = 0x3 + NFTA_RULE_EXPRESSIONS = 0x4 + NFTA_RULE_COMPAT = 0x5 + NFTA_RULE_POSITION = 0x6 + NFTA_RULE_USERDATA = 0x7 + NFTA_RULE_PAD = 0x8 + NFTA_RULE_ID = 0x9 + NFT_RULE_COMPAT_F_INV = 0x2 + NFT_RULE_COMPAT_F_MASK = 0x2 + NFTA_RULE_COMPAT_UNSPEC = 0x0 + NFTA_RULE_COMPAT_PROTO = 0x1 + NFTA_RULE_COMPAT_FLAGS = 0x2 + NFT_SET_ANONYMOUS = 0x1 + NFT_SET_CONSTANT = 0x2 + NFT_SET_INTERVAL = 0x4 + NFT_SET_MAP = 0x8 + NFT_SET_TIMEOUT = 0x10 + NFT_SET_EVAL = 0x20 + NFT_SET_OBJECT = 0x40 + NFT_SET_POL_PERFORMANCE = 0x0 + NFT_SET_POL_MEMORY = 0x1 + NFTA_SET_DESC_UNSPEC = 0x0 + NFTA_SET_DESC_SIZE = 0x1 + NFTA_SET_UNSPEC = 0x0 + NFTA_SET_TABLE = 0x1 + NFTA_SET_NAME = 0x2 + NFTA_SET_FLAGS = 0x3 + NFTA_SET_KEY_TYPE = 0x4 + NFTA_SET_KEY_LEN = 0x5 + NFTA_SET_DATA_TYPE = 0x6 + NFTA_SET_DATA_LEN = 0x7 + NFTA_SET_POLICY = 0x8 + NFTA_SET_DESC = 0x9 + NFTA_SET_ID = 0xa + NFTA_SET_TIMEOUT = 0xb + NFTA_SET_GC_INTERVAL = 0xc + NFTA_SET_USERDATA = 0xd + NFTA_SET_PAD = 0xe + NFTA_SET_OBJ_TYPE = 0xf + NFT_SET_ELEM_INTERVAL_END = 0x1 + NFTA_SET_ELEM_UNSPEC = 0x0 + NFTA_SET_ELEM_KEY = 0x1 + NFTA_SET_ELEM_DATA = 0x2 + NFTA_SET_ELEM_FLAGS = 0x3 + NFTA_SET_ELEM_TIMEOUT = 0x4 + NFTA_SET_ELEM_EXPIRATION = 0x5 + NFTA_SET_ELEM_USERDATA = 0x6 + NFTA_SET_ELEM_EXPR = 0x7 + NFTA_SET_ELEM_PAD = 0x8 + NFTA_SET_ELEM_OBJREF = 0x9 + NFTA_SET_ELEM_LIST_UNSPEC = 0x0 + NFTA_SET_ELEM_LIST_TABLE = 0x1 + NFTA_SET_ELEM_LIST_SET = 0x2 + NFTA_SET_ELEM_LIST_ELEMENTS = 0x3 + NFTA_SET_ELEM_LIST_SET_ID = 0x4 + NFT_DATA_VALUE = 0x0 + NFT_DATA_VERDICT = 0xffffff00 + NFTA_DATA_UNSPEC = 0x0 + NFTA_DATA_VALUE = 0x1 + NFTA_DATA_VERDICT = 0x2 + NFTA_VERDICT_UNSPEC = 0x0 + NFTA_VERDICT_CODE = 0x1 + NFTA_VERDICT_CHAIN = 0x2 + NFTA_EXPR_UNSPEC = 0x0 + NFTA_EXPR_NAME = 0x1 + NFTA_EXPR_DATA = 0x2 + NFTA_IMMEDIATE_UNSPEC = 0x0 + NFTA_IMMEDIATE_DREG = 0x1 + NFTA_IMMEDIATE_DATA = 0x2 + NFTA_BITWISE_UNSPEC = 0x0 + NFTA_BITWISE_SREG = 0x1 + NFTA_BITWISE_DREG = 0x2 + NFTA_BITWISE_LEN = 0x3 + NFTA_BITWISE_MASK = 0x4 + NFTA_BITWISE_XOR = 0x5 + NFT_BYTEORDER_NTOH = 0x0 + NFT_BYTEORDER_HTON = 0x1 + NFTA_BYTEORDER_UNSPEC = 0x0 + NFTA_BYTEORDER_SREG = 0x1 + NFTA_BYTEORDER_DREG = 0x2 + NFTA_BYTEORDER_OP = 0x3 + NFTA_BYTEORDER_LEN = 0x4 + NFTA_BYTEORDER_SIZE = 0x5 + NFT_CMP_EQ = 0x0 + NFT_CMP_NEQ = 0x1 + NFT_CMP_LT = 0x2 + NFT_CMP_LTE = 0x3 + NFT_CMP_GT = 0x4 + NFT_CMP_GTE = 0x5 + NFTA_CMP_UNSPEC = 0x0 + NFTA_CMP_SREG = 0x1 + NFTA_CMP_OP = 0x2 + NFTA_CMP_DATA = 0x3 + NFT_RANGE_EQ = 0x0 + NFT_RANGE_NEQ = 0x1 + NFTA_RANGE_UNSPEC = 0x0 + NFTA_RANGE_SREG = 0x1 + NFTA_RANGE_OP = 0x2 + NFTA_RANGE_FROM_DATA = 0x3 + NFTA_RANGE_TO_DATA = 0x4 + NFT_LOOKUP_F_INV = 0x1 + NFTA_LOOKUP_UNSPEC = 0x0 + NFTA_LOOKUP_SET = 0x1 + NFTA_LOOKUP_SREG = 0x2 + NFTA_LOOKUP_DREG = 0x3 + NFTA_LOOKUP_SET_ID = 0x4 + NFTA_LOOKUP_FLAGS = 0x5 + NFT_DYNSET_OP_ADD = 0x0 + NFT_DYNSET_OP_UPDATE = 0x1 + NFT_DYNSET_F_INV = 0x1 + NFTA_DYNSET_UNSPEC = 0x0 + NFTA_DYNSET_SET_NAME = 0x1 + NFTA_DYNSET_SET_ID = 0x2 + NFTA_DYNSET_OP = 0x3 + NFTA_DYNSET_SREG_KEY = 0x4 + NFTA_DYNSET_SREG_DATA = 0x5 + NFTA_DYNSET_TIMEOUT = 0x6 + NFTA_DYNSET_EXPR = 0x7 + NFTA_DYNSET_PAD = 0x8 + NFTA_DYNSET_FLAGS = 0x9 + NFT_PAYLOAD_LL_HEADER = 0x0 + NFT_PAYLOAD_NETWORK_HEADER = 0x1 + NFT_PAYLOAD_TRANSPORT_HEADER = 0x2 + NFT_PAYLOAD_CSUM_NONE = 0x0 + NFT_PAYLOAD_CSUM_INET = 0x1 + NFT_PAYLOAD_L4CSUM_PSEUDOHDR = 0x1 + NFTA_PAYLOAD_UNSPEC = 0x0 + NFTA_PAYLOAD_DREG = 0x1 + NFTA_PAYLOAD_BASE = 0x2 + NFTA_PAYLOAD_OFFSET = 0x3 + NFTA_PAYLOAD_LEN = 0x4 + NFTA_PAYLOAD_SREG = 0x5 + NFTA_PAYLOAD_CSUM_TYPE = 0x6 + NFTA_PAYLOAD_CSUM_OFFSET = 0x7 + NFTA_PAYLOAD_CSUM_FLAGS = 0x8 + NFT_EXTHDR_F_PRESENT = 0x1 + NFT_EXTHDR_OP_IPV6 = 0x0 + NFT_EXTHDR_OP_TCPOPT = 0x1 + NFTA_EXTHDR_UNSPEC = 0x0 + NFTA_EXTHDR_DREG = 0x1 + NFTA_EXTHDR_TYPE = 0x2 + NFTA_EXTHDR_OFFSET = 0x3 + NFTA_EXTHDR_LEN = 0x4 + NFTA_EXTHDR_FLAGS = 0x5 + NFTA_EXTHDR_OP = 0x6 + NFTA_EXTHDR_SREG = 0x7 + NFT_META_LEN = 0x0 + NFT_META_PROTOCOL = 0x1 + NFT_META_PRIORITY = 0x2 + NFT_META_MARK = 0x3 + NFT_META_IIF = 0x4 + NFT_META_OIF = 0x5 + NFT_META_IIFNAME = 0x6 + NFT_META_OIFNAME = 0x7 + NFT_META_IIFTYPE = 0x8 + NFT_META_OIFTYPE = 0x9 + NFT_META_SKUID = 0xa + NFT_META_SKGID = 0xb + NFT_META_NFTRACE = 0xc + NFT_META_RTCLASSID = 0xd + NFT_META_SECMARK = 0xe + NFT_META_NFPROTO = 0xf + NFT_META_L4PROTO = 0x10 + NFT_META_BRI_IIFNAME = 0x11 + NFT_META_BRI_OIFNAME = 0x12 + NFT_META_PKTTYPE = 0x13 + NFT_META_CPU = 0x14 + NFT_META_IIFGROUP = 0x15 + NFT_META_OIFGROUP = 0x16 + NFT_META_CGROUP = 0x17 + NFT_META_PRANDOM = 0x18 + NFT_RT_CLASSID = 0x0 + NFT_RT_NEXTHOP4 = 0x1 + NFT_RT_NEXTHOP6 = 0x2 + NFT_RT_TCPMSS = 0x3 + NFT_HASH_JENKINS = 0x0 + NFT_HASH_SYM = 0x1 + NFTA_HASH_UNSPEC = 0x0 + NFTA_HASH_SREG = 0x1 + NFTA_HASH_DREG = 0x2 + NFTA_HASH_LEN = 0x3 + NFTA_HASH_MODULUS = 0x4 + NFTA_HASH_SEED = 0x5 + NFTA_HASH_OFFSET = 0x6 + NFTA_HASH_TYPE = 0x7 + NFTA_META_UNSPEC = 0x0 + NFTA_META_DREG = 0x1 + NFTA_META_KEY = 0x2 + NFTA_META_SREG = 0x3 + NFTA_RT_UNSPEC = 0x0 + NFTA_RT_DREG = 0x1 + NFTA_RT_KEY = 0x2 + NFT_CT_STATE = 0x0 + NFT_CT_DIRECTION = 0x1 + NFT_CT_STATUS = 0x2 + NFT_CT_MARK = 0x3 + NFT_CT_SECMARK = 0x4 + NFT_CT_EXPIRATION = 0x5 + NFT_CT_HELPER = 0x6 + NFT_CT_L3PROTOCOL = 0x7 + NFT_CT_SRC = 0x8 + NFT_CT_DST = 0x9 + NFT_CT_PROTOCOL = 0xa + NFT_CT_PROTO_SRC = 0xb + NFT_CT_PROTO_DST = 0xc + NFT_CT_LABELS = 0xd + NFT_CT_PKTS = 0xe + NFT_CT_BYTES = 0xf + NFT_CT_AVGPKT = 0x10 + NFT_CT_ZONE = 0x11 + NFT_CT_EVENTMASK = 0x12 + NFTA_CT_UNSPEC = 0x0 + NFTA_CT_DREG = 0x1 + NFTA_CT_KEY = 0x2 + NFTA_CT_DIRECTION = 0x3 + NFTA_CT_SREG = 0x4 + NFT_LIMIT_PKTS = 0x0 + NFT_LIMIT_PKT_BYTES = 0x1 + NFT_LIMIT_F_INV = 0x1 + NFTA_LIMIT_UNSPEC = 0x0 + NFTA_LIMIT_RATE = 0x1 + NFTA_LIMIT_UNIT = 0x2 + NFTA_LIMIT_BURST = 0x3 + NFTA_LIMIT_TYPE = 0x4 + NFTA_LIMIT_FLAGS = 0x5 + NFTA_LIMIT_PAD = 0x6 + NFTA_COUNTER_UNSPEC = 0x0 + NFTA_COUNTER_BYTES = 0x1 + NFTA_COUNTER_PACKETS = 0x2 + NFTA_COUNTER_PAD = 0x3 + NFTA_LOG_UNSPEC = 0x0 + NFTA_LOG_GROUP = 0x1 + NFTA_LOG_PREFIX = 0x2 + NFTA_LOG_SNAPLEN = 0x3 + NFTA_LOG_QTHRESHOLD = 0x4 + NFTA_LOG_LEVEL = 0x5 + NFTA_LOG_FLAGS = 0x6 + NFTA_QUEUE_UNSPEC = 0x0 + NFTA_QUEUE_NUM = 0x1 + NFTA_QUEUE_TOTAL = 0x2 + NFTA_QUEUE_FLAGS = 0x3 + NFTA_QUEUE_SREG_QNUM = 0x4 + NFT_QUOTA_F_INV = 0x1 + NFT_QUOTA_F_DEPLETED = 0x2 + NFTA_QUOTA_UNSPEC = 0x0 + NFTA_QUOTA_BYTES = 0x1 + NFTA_QUOTA_FLAGS = 0x2 + NFTA_QUOTA_PAD = 0x3 + NFTA_QUOTA_CONSUMED = 0x4 + NFT_REJECT_ICMP_UNREACH = 0x0 + NFT_REJECT_TCP_RST = 0x1 + NFT_REJECT_ICMPX_UNREACH = 0x2 + NFT_REJECT_ICMPX_NO_ROUTE = 0x0 + NFT_REJECT_ICMPX_PORT_UNREACH = 0x1 + NFT_REJECT_ICMPX_HOST_UNREACH = 0x2 + NFT_REJECT_ICMPX_ADMIN_PROHIBITED = 0x3 + NFTA_REJECT_UNSPEC = 0x0 + NFTA_REJECT_TYPE = 0x1 + NFTA_REJECT_ICMP_CODE = 0x2 + NFT_NAT_SNAT = 0x0 + NFT_NAT_DNAT = 0x1 + NFTA_NAT_UNSPEC = 0x0 + NFTA_NAT_TYPE = 0x1 + NFTA_NAT_FAMILY = 0x2 + NFTA_NAT_REG_ADDR_MIN = 0x3 + NFTA_NAT_REG_ADDR_MAX = 0x4 + NFTA_NAT_REG_PROTO_MIN = 0x5 + NFTA_NAT_REG_PROTO_MAX = 0x6 + NFTA_NAT_FLAGS = 0x7 + NFTA_MASQ_UNSPEC = 0x0 + NFTA_MASQ_FLAGS = 0x1 + NFTA_MASQ_REG_PROTO_MIN = 0x2 + NFTA_MASQ_REG_PROTO_MAX = 0x3 + NFTA_REDIR_UNSPEC = 0x0 + NFTA_REDIR_REG_PROTO_MIN = 0x1 + NFTA_REDIR_REG_PROTO_MAX = 0x2 + NFTA_REDIR_FLAGS = 0x3 + NFTA_DUP_UNSPEC = 0x0 + NFTA_DUP_SREG_ADDR = 0x1 + NFTA_DUP_SREG_DEV = 0x2 + NFTA_FWD_UNSPEC = 0x0 + NFTA_FWD_SREG_DEV = 0x1 + NFTA_OBJREF_UNSPEC = 0x0 + NFTA_OBJREF_IMM_TYPE = 0x1 + NFTA_OBJREF_IMM_NAME = 0x2 + NFTA_OBJREF_SET_SREG = 0x3 + NFTA_OBJREF_SET_NAME = 0x4 + NFTA_OBJREF_SET_ID = 0x5 + NFTA_GEN_UNSPEC = 0x0 + NFTA_GEN_ID = 0x1 + NFTA_GEN_PROC_PID = 0x2 + NFTA_GEN_PROC_NAME = 0x3 + NFTA_FIB_UNSPEC = 0x0 + NFTA_FIB_DREG = 0x1 + NFTA_FIB_RESULT = 0x2 + NFTA_FIB_FLAGS = 0x3 + NFT_FIB_RESULT_UNSPEC = 0x0 + NFT_FIB_RESULT_OIF = 0x1 + NFT_FIB_RESULT_OIFNAME = 0x2 + NFT_FIB_RESULT_ADDRTYPE = 0x3 + NFTA_FIB_F_SADDR = 0x1 + NFTA_FIB_F_DADDR = 0x2 + NFTA_FIB_F_MARK = 0x4 + NFTA_FIB_F_IIF = 0x8 + NFTA_FIB_F_OIF = 0x10 + NFTA_FIB_F_PRESENT = 0x20 + NFTA_CT_HELPER_UNSPEC = 0x0 + NFTA_CT_HELPER_NAME = 0x1 + NFTA_CT_HELPER_L3PROTO = 0x2 + NFTA_CT_HELPER_L4PROTO = 0x3 + NFTA_OBJ_UNSPEC = 0x0 + NFTA_OBJ_TABLE = 0x1 + NFTA_OBJ_NAME = 0x2 + NFTA_OBJ_TYPE = 0x3 + NFTA_OBJ_DATA = 0x4 + NFTA_OBJ_USE = 0x5 + NFTA_TRACE_UNSPEC = 0x0 + NFTA_TRACE_TABLE = 0x1 + NFTA_TRACE_CHAIN = 0x2 + NFTA_TRACE_RULE_HANDLE = 0x3 + NFTA_TRACE_TYPE = 0x4 + NFTA_TRACE_VERDICT = 0x5 + NFTA_TRACE_ID = 0x6 + NFTA_TRACE_LL_HEADER = 0x7 + NFTA_TRACE_NETWORK_HEADER = 0x8 + NFTA_TRACE_TRANSPORT_HEADER = 0x9 + NFTA_TRACE_IIF = 0xa + NFTA_TRACE_IIFTYPE = 0xb + NFTA_TRACE_OIF = 0xc + NFTA_TRACE_OIFTYPE = 0xd + NFTA_TRACE_MARK = 0xe + NFTA_TRACE_NFPROTO = 0xf + NFTA_TRACE_POLICY = 0x10 + NFTA_TRACE_PAD = 0x11 + NFT_TRACETYPE_UNSPEC = 0x0 + NFT_TRACETYPE_POLICY = 0x1 + NFT_TRACETYPE_RETURN = 0x2 + NFT_TRACETYPE_RULE = 0x3 + NFTA_NG_UNSPEC = 0x0 + NFTA_NG_DREG = 0x1 + NFTA_NG_MODULUS = 0x2 + NFTA_NG_TYPE = 0x3 + NFTA_NG_OFFSET = 0x4 + NFT_NG_INCREMENTAL = 0x0 + NFT_NG_RANDOM = 0x1 +) + +type RTCTime struct { + Sec int32 + Min int32 + Hour int32 + Mday int32 + Mon int32 + Year int32 + Wday int32 + Yday int32 + Isdst int32 +} + +type RTCWkAlrm struct { + Enabled uint8 + Pending uint8 + Time RTCTime +} + +type RTCPLLInfo struct { + Ctrl int32 + Value int32 + Max int32 + Min int32 + Posmult int32 + Negmult int32 + Clock int64 +} + +type BlkpgIoctlArg struct { + Op int32 + Flags int32 + Datalen int32 + Data *byte +} + +type BlkpgPartition struct { + Start int64 + Length int64 + Pno int32 + Devname [64]uint8 + Volname [64]uint8 + _ [4]byte +} + +const ( + BLKPG = 0x20001269 + BLKPG_ADD_PARTITION = 0x1 + BLKPG_DEL_PARTITION = 0x2 + BLKPG_RESIZE_PARTITION = 0x3 +) + +const ( + NETNSA_NONE = 0x0 + NETNSA_NSID = 0x1 + NETNSA_PID = 0x2 + NETNSA_FD = 0x3 +) + +type XDPRingOffset struct { + Producer uint64 + Consumer uint64 + Desc uint64 +} + +type XDPMmapOffsets struct { + Rx XDPRingOffset + Tx XDPRingOffset + Fr XDPRingOffset + Cr XDPRingOffset +} + +type XDPUmemReg struct { + Addr uint64 + Len uint64 + Size uint32 + Headroom uint32 +} + +type XDPStatistics struct { + Rx_dropped uint64 + Rx_invalid_descs uint64 + Tx_invalid_descs uint64 +} + +type XDPDesc struct { + Addr uint64 + Len uint32 + Options uint32 +} + +const ( + NCSI_CMD_UNSPEC = 0x0 + NCSI_CMD_PKG_INFO = 0x1 + NCSI_CMD_SET_INTERFACE = 0x2 + NCSI_CMD_CLEAR_INTERFACE = 0x3 + NCSI_ATTR_UNSPEC = 0x0 + NCSI_ATTR_IFINDEX = 0x1 + NCSI_ATTR_PACKAGE_LIST = 0x2 + NCSI_ATTR_PACKAGE_ID = 0x3 + NCSI_ATTR_CHANNEL_ID = 0x4 + NCSI_PKG_ATTR_UNSPEC = 0x0 + NCSI_PKG_ATTR = 0x1 + NCSI_PKG_ATTR_ID = 0x2 + NCSI_PKG_ATTR_FORCED = 0x3 + NCSI_PKG_ATTR_CHANNEL_LIST = 0x4 + NCSI_CHANNEL_ATTR_UNSPEC = 0x0 + NCSI_CHANNEL_ATTR = 0x1 + NCSI_CHANNEL_ATTR_ID = 0x2 + NCSI_CHANNEL_ATTR_VERSION_MAJOR = 0x3 + NCSI_CHANNEL_ATTR_VERSION_MINOR = 0x4 + NCSI_CHANNEL_ATTR_VERSION_STR = 0x5 + NCSI_CHANNEL_ATTR_LINK_STATE = 0x6 + NCSI_CHANNEL_ATTR_ACTIVE = 0x7 + NCSI_CHANNEL_ATTR_FORCED = 0x8 + NCSI_CHANNEL_ATTR_VLAN_LIST = 0x9 + NCSI_CHANNEL_ATTR_VLAN_ID = 0xa +) + +type ScmTimestamping struct { + Ts [3]Timespec +} + +const ( + SOF_TIMESTAMPING_TX_HARDWARE = 0x1 + SOF_TIMESTAMPING_TX_SOFTWARE = 0x2 + SOF_TIMESTAMPING_RX_HARDWARE = 0x4 + SOF_TIMESTAMPING_RX_SOFTWARE = 0x8 + SOF_TIMESTAMPING_SOFTWARE = 0x10 + SOF_TIMESTAMPING_SYS_HARDWARE = 0x20 + SOF_TIMESTAMPING_RAW_HARDWARE = 0x40 + SOF_TIMESTAMPING_OPT_ID = 0x80 + SOF_TIMESTAMPING_TX_SCHED = 0x100 + SOF_TIMESTAMPING_TX_ACK = 0x200 + SOF_TIMESTAMPING_OPT_CMSG = 0x400 + SOF_TIMESTAMPING_OPT_TSONLY = 0x800 + SOF_TIMESTAMPING_OPT_STATS = 0x1000 + SOF_TIMESTAMPING_OPT_PKTINFO = 0x2000 + SOF_TIMESTAMPING_OPT_TX_SWHW = 0x4000 + + SOF_TIMESTAMPING_LAST = 0x4000 + SOF_TIMESTAMPING_MASK = 0x7fff + + SCM_TSTAMP_SND = 0x0 + SCM_TSTAMP_SCHED = 0x1 + SCM_TSTAMP_ACK = 0x2 +) + +type SockExtendedErr struct { + Errno uint32 + Origin uint8 + Type uint8 + Code uint8 + Pad uint8 + Info uint32 + Data uint32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go b/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go index b6c2d32dd8..0e88bf47bc 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go @@ -6,11 +6,11 @@ package unix const ( - sizeofPtr = 0x4 - sizeofShort = 0x2 - sizeofInt = 0x4 - sizeofLong = 0x4 - sizeofLongLong = 0x8 + SizeofPtr = 0x4 + SizeofShort = 0x2 + SizeofInt = 0x4 + SizeofLong = 0x4 + SizeofLongLong = 0x8 PathMax = 0x1000 ) @@ -52,7 +52,7 @@ type Timex struct { Errcnt int32 Stbcnt int32 Tai int32 - Pad_cgo_0 [44]byte + _ [44]byte } type Time_t int32 @@ -115,44 +115,57 @@ type Stat_t struct { Pad5 [14]int32 } -type Statfs_t struct { - Type int32 - Bsize int32 - Frsize int32 - Pad_cgo_0 [4]byte - Blocks uint64 - Bfree uint64 - Files uint64 - Ffree uint64 - Bavail uint64 - Fsid Fsid - Namelen int32 - Flags int32 - Spare [5]int32 - Pad_cgo_1 [4]byte +type StatxTimestamp struct { + Sec int64 + Nsec uint32 + _ int32 +} + +type Statx_t struct { + Mask uint32 + Blksize uint32 + Attributes uint64 + Nlink uint32 + Uid uint32 + Gid uint32 + Mode uint16 + _ [1]uint16 + Ino uint64 + Size uint64 + Blocks uint64 + Attributes_mask uint64 + Atime StatxTimestamp + Btime StatxTimestamp + Ctime StatxTimestamp + Mtime StatxTimestamp + Rdev_major uint32 + Rdev_minor uint32 + Dev_major uint32 + Dev_minor uint32 + _ [14]uint64 } type Dirent struct { - Ino uint64 - Off int64 - Reclen uint16 - Type uint8 - Name [256]int8 - Pad_cgo_0 [5]byte + Ino uint64 + Off int64 + Reclen uint16 + Type uint8 + Name [256]int8 + _ [5]byte } type Fsid struct { - X__val [2]int32 + Val [2]int32 } type Flock_t struct { - Type int16 - Whence int16 - Pad_cgo_0 [4]byte - Start int64 - Len int64 - Pid int32 - Pad_cgo_1 [4]byte + Type int16 + Whence int16 + _ [4]byte + Start int64 + Len int64 + Pid int32 + _ [4]byte } type FscryptPolicy struct { @@ -227,11 +240,26 @@ type RawSockaddrHCI struct { Channel uint16 } +type RawSockaddrL2 struct { + Family uint16 + Psm uint16 + Bdaddr [6]uint8 + Cid uint16 + Bdaddr_type uint8 + _ [1]byte +} + +type RawSockaddrRFCOMM struct { + Family uint16 + Bdaddr [6]uint8 + Channel uint8 + _ [1]byte +} + type RawSockaddrCAN struct { - Family uint16 - Pad_cgo_0 [2]byte - Ifindex int32 - Addr [8]byte + Family uint16 + Ifindex int32 + Addr [8]byte } type RawSockaddrALG struct { @@ -250,6 +278,16 @@ type RawSockaddrVM struct { Zero [4]uint8 } +type RawSockaddrXDP struct { + Family uint16 + Flags uint16 + Ifindex uint32 + Queue_id uint32 + Shared_umem_fd uint32 +} + +type RawSockaddrPPPoX [0x1e]byte + type RawSockaddr struct { Family uint16 Data [14]int8 @@ -344,7 +382,6 @@ type TCPInfo struct { Probes uint8 Backoff uint8 Options uint8 - Pad_cgo_0 [2]byte Rto uint32 Ato uint32 Snd_mss uint32 @@ -379,9 +416,13 @@ const ( SizeofSockaddrLinklayer = 0x14 SizeofSockaddrNetlink = 0xc SizeofSockaddrHCI = 0x6 + SizeofSockaddrL2 = 0xe + SizeofSockaddrRFCOMM = 0xa SizeofSockaddrCAN = 0x10 SizeofSockaddrALG = 0x58 SizeofSockaddrVM = 0x10 + SizeofSockaddrXDP = 0x10 + SizeofSockaddrPPPoX = 0x1e SizeofLinger = 0x8 SizeofIovec = 0x8 SizeofIPMreq = 0x8 @@ -399,97 +440,138 @@ const ( ) const ( - IFA_UNSPEC = 0x0 - IFA_ADDRESS = 0x1 - IFA_LOCAL = 0x2 - IFA_LABEL = 0x3 - IFA_BROADCAST = 0x4 - IFA_ANYCAST = 0x5 - IFA_CACHEINFO = 0x6 - IFA_MULTICAST = 0x7 - IFLA_UNSPEC = 0x0 - IFLA_ADDRESS = 0x1 - IFLA_BROADCAST = 0x2 - IFLA_IFNAME = 0x3 - IFLA_MTU = 0x4 - IFLA_LINK = 0x5 - IFLA_QDISC = 0x6 - IFLA_STATS = 0x7 - IFLA_COST = 0x8 - IFLA_PRIORITY = 0x9 - IFLA_MASTER = 0xa - IFLA_WIRELESS = 0xb - IFLA_PROTINFO = 0xc - IFLA_TXQLEN = 0xd - IFLA_MAP = 0xe - IFLA_WEIGHT = 0xf - IFLA_OPERSTATE = 0x10 - IFLA_LINKMODE = 0x11 - IFLA_LINKINFO = 0x12 - IFLA_NET_NS_PID = 0x13 - IFLA_IFALIAS = 0x14 - IFLA_MAX = 0x2c - RT_SCOPE_UNIVERSE = 0x0 - RT_SCOPE_SITE = 0xc8 - RT_SCOPE_LINK = 0xfd - RT_SCOPE_HOST = 0xfe - RT_SCOPE_NOWHERE = 0xff - RT_TABLE_UNSPEC = 0x0 - RT_TABLE_COMPAT = 0xfc - RT_TABLE_DEFAULT = 0xfd - RT_TABLE_MAIN = 0xfe - RT_TABLE_LOCAL = 0xff - RT_TABLE_MAX = 0xffffffff - RTA_UNSPEC = 0x0 - RTA_DST = 0x1 - RTA_SRC = 0x2 - RTA_IIF = 0x3 - RTA_OIF = 0x4 - RTA_GATEWAY = 0x5 - RTA_PRIORITY = 0x6 - RTA_PREFSRC = 0x7 - RTA_METRICS = 0x8 - RTA_MULTIPATH = 0x9 - RTA_FLOW = 0xb - RTA_CACHEINFO = 0xc - RTA_TABLE = 0xf - RTN_UNSPEC = 0x0 - RTN_UNICAST = 0x1 - RTN_LOCAL = 0x2 - RTN_BROADCAST = 0x3 - RTN_ANYCAST = 0x4 - RTN_MULTICAST = 0x5 - RTN_BLACKHOLE = 0x6 - RTN_UNREACHABLE = 0x7 - RTN_PROHIBIT = 0x8 - RTN_THROW = 0x9 - RTN_NAT = 0xa - RTN_XRESOLVE = 0xb - RTNLGRP_NONE = 0x0 - RTNLGRP_LINK = 0x1 - RTNLGRP_NOTIFY = 0x2 - RTNLGRP_NEIGH = 0x3 - RTNLGRP_TC = 0x4 - RTNLGRP_IPV4_IFADDR = 0x5 - RTNLGRP_IPV4_MROUTE = 0x6 - RTNLGRP_IPV4_ROUTE = 0x7 - RTNLGRP_IPV4_RULE = 0x8 - RTNLGRP_IPV6_IFADDR = 0x9 - RTNLGRP_IPV6_MROUTE = 0xa - RTNLGRP_IPV6_ROUTE = 0xb - RTNLGRP_IPV6_IFINFO = 0xc - RTNLGRP_IPV6_PREFIX = 0x12 - RTNLGRP_IPV6_RULE = 0x13 - RTNLGRP_ND_USEROPT = 0x14 - SizeofNlMsghdr = 0x10 - SizeofNlMsgerr = 0x14 - SizeofRtGenmsg = 0x1 - SizeofNlAttr = 0x4 - SizeofRtAttr = 0x4 - SizeofIfInfomsg = 0x10 - SizeofIfAddrmsg = 0x8 - SizeofRtMsg = 0xc - SizeofRtNexthop = 0x8 + IFA_UNSPEC = 0x0 + IFA_ADDRESS = 0x1 + IFA_LOCAL = 0x2 + IFA_LABEL = 0x3 + IFA_BROADCAST = 0x4 + IFA_ANYCAST = 0x5 + IFA_CACHEINFO = 0x6 + IFA_MULTICAST = 0x7 + IFLA_UNSPEC = 0x0 + IFLA_ADDRESS = 0x1 + IFLA_BROADCAST = 0x2 + IFLA_IFNAME = 0x3 + IFLA_INFO_KIND = 0x1 + IFLA_MTU = 0x4 + IFLA_LINK = 0x5 + IFLA_QDISC = 0x6 + IFLA_STATS = 0x7 + IFLA_COST = 0x8 + IFLA_PRIORITY = 0x9 + IFLA_MASTER = 0xa + IFLA_WIRELESS = 0xb + IFLA_PROTINFO = 0xc + IFLA_TXQLEN = 0xd + IFLA_MAP = 0xe + IFLA_WEIGHT = 0xf + IFLA_OPERSTATE = 0x10 + IFLA_LINKMODE = 0x11 + IFLA_LINKINFO = 0x12 + IFLA_NET_NS_PID = 0x13 + IFLA_IFALIAS = 0x14 + IFLA_NUM_VF = 0x15 + IFLA_VFINFO_LIST = 0x16 + IFLA_STATS64 = 0x17 + IFLA_VF_PORTS = 0x18 + IFLA_PORT_SELF = 0x19 + IFLA_AF_SPEC = 0x1a + IFLA_GROUP = 0x1b + IFLA_NET_NS_FD = 0x1c + IFLA_EXT_MASK = 0x1d + IFLA_PROMISCUITY = 0x1e + IFLA_NUM_TX_QUEUES = 0x1f + IFLA_NUM_RX_QUEUES = 0x20 + IFLA_CARRIER = 0x21 + IFLA_PHYS_PORT_ID = 0x22 + IFLA_CARRIER_CHANGES = 0x23 + IFLA_PHYS_SWITCH_ID = 0x24 + IFLA_LINK_NETNSID = 0x25 + IFLA_PHYS_PORT_NAME = 0x26 + IFLA_PROTO_DOWN = 0x27 + IFLA_GSO_MAX_SEGS = 0x28 + IFLA_GSO_MAX_SIZE = 0x29 + IFLA_PAD = 0x2a + IFLA_XDP = 0x2b + IFLA_EVENT = 0x2c + IFLA_NEW_NETNSID = 0x2d + IFLA_IF_NETNSID = 0x2e + IFLA_MAX = 0x33 + RT_SCOPE_UNIVERSE = 0x0 + RT_SCOPE_SITE = 0xc8 + RT_SCOPE_LINK = 0xfd + RT_SCOPE_HOST = 0xfe + RT_SCOPE_NOWHERE = 0xff + RT_TABLE_UNSPEC = 0x0 + RT_TABLE_COMPAT = 0xfc + RT_TABLE_DEFAULT = 0xfd + RT_TABLE_MAIN = 0xfe + RT_TABLE_LOCAL = 0xff + RT_TABLE_MAX = 0xffffffff + RTA_UNSPEC = 0x0 + RTA_DST = 0x1 + RTA_SRC = 0x2 + RTA_IIF = 0x3 + RTA_OIF = 0x4 + RTA_GATEWAY = 0x5 + RTA_PRIORITY = 0x6 + RTA_PREFSRC = 0x7 + RTA_METRICS = 0x8 + RTA_MULTIPATH = 0x9 + RTA_FLOW = 0xb + RTA_CACHEINFO = 0xc + RTA_TABLE = 0xf + RTA_MARK = 0x10 + RTA_MFC_STATS = 0x11 + RTA_VIA = 0x12 + RTA_NEWDST = 0x13 + RTA_PREF = 0x14 + RTA_ENCAP_TYPE = 0x15 + RTA_ENCAP = 0x16 + RTA_EXPIRES = 0x17 + RTA_PAD = 0x18 + RTA_UID = 0x19 + RTA_TTL_PROPAGATE = 0x1a + RTA_IP_PROTO = 0x1b + RTA_SPORT = 0x1c + RTA_DPORT = 0x1d + RTN_UNSPEC = 0x0 + RTN_UNICAST = 0x1 + RTN_LOCAL = 0x2 + RTN_BROADCAST = 0x3 + RTN_ANYCAST = 0x4 + RTN_MULTICAST = 0x5 + RTN_BLACKHOLE = 0x6 + RTN_UNREACHABLE = 0x7 + RTN_PROHIBIT = 0x8 + RTN_THROW = 0x9 + RTN_NAT = 0xa + RTN_XRESOLVE = 0xb + RTNLGRP_NONE = 0x0 + RTNLGRP_LINK = 0x1 + RTNLGRP_NOTIFY = 0x2 + RTNLGRP_NEIGH = 0x3 + RTNLGRP_TC = 0x4 + RTNLGRP_IPV4_IFADDR = 0x5 + RTNLGRP_IPV4_MROUTE = 0x6 + RTNLGRP_IPV4_ROUTE = 0x7 + RTNLGRP_IPV4_RULE = 0x8 + RTNLGRP_IPV6_IFADDR = 0x9 + RTNLGRP_IPV6_MROUTE = 0xa + RTNLGRP_IPV6_ROUTE = 0xb + RTNLGRP_IPV6_IFINFO = 0xc + RTNLGRP_IPV6_PREFIX = 0x12 + RTNLGRP_IPV6_RULE = 0x13 + RTNLGRP_ND_USEROPT = 0x14 + SizeofNlMsghdr = 0x10 + SizeofNlMsgerr = 0x14 + SizeofRtGenmsg = 0x1 + SizeofNlAttr = 0x4 + SizeofRtAttr = 0x4 + SizeofIfInfomsg = 0x10 + SizeofIfAddrmsg = 0x8 + SizeofRtMsg = 0xc + SizeofRtNexthop = 0x8 ) type NlMsghdr struct { @@ -520,12 +602,12 @@ type RtAttr struct { } type IfInfomsg struct { - Family uint8 - X__ifi_pad uint8 - Type uint16 - Index int32 - Flags uint32 - Change uint32 + Family uint8 + _ uint8 + Type uint16 + Index int32 + Flags uint32 + Change uint32 } type IfAddrmsg struct { @@ -568,9 +650,8 @@ type SockFilter struct { } type SockFprog struct { - Len uint16 - Pad_cgo_0 [2]byte - Filter *SockFilter + Len uint16 + Filter *SockFilter } type InotifyEvent struct { @@ -610,7 +691,7 @@ type Sysinfo_t struct { Totalhigh uint32 Freehigh uint32 Unit uint32 - X_f [8]int8 + _ [8]int8 } type Utsname struct { @@ -637,10 +718,19 @@ type EpollEvent struct { } const ( - AT_FDCWD = -0x64 - AT_REMOVEDIR = 0x200 + AT_EMPTY_PATH = 0x1000 + AT_FDCWD = -0x64 + AT_NO_AUTOMOUNT = 0x800 + AT_REMOVEDIR = 0x200 + + AT_STATX_SYNC_AS_STAT = 0x0 + AT_STATX_FORCE_SYNC = 0x2000 + AT_STATX_DONT_SYNC = 0x4000 + AT_SYMLINK_FOLLOW = 0x400 AT_SYMLINK_NOFOLLOW = 0x100 + + AT_EACCESS = 0x200 ) type PollFd struct { @@ -660,10 +750,33 @@ const ( ) type Sigset_t struct { - X__val [32]uint32 + Val [32]uint32 } -const RNDGETENTCNT = 0x40045200 +type SignalfdSiginfo struct { + Signo uint32 + Errno int32 + Code int32 + Pid uint32 + Uid uint32 + Fd int32 + Tid uint32 + Band uint32 + Overrun uint32 + Trapno uint32 + Status int32 + Int int32 + Ptr uint64 + Utime uint64 + Stime uint64 + Addr uint64 + Addr_lsb uint16 + _ uint16 + Syscall int32 + Call_addr uint64 + Arch uint32 + _ [28]uint8 +} const PERF_IOC_FLAG_GROUP = 0x1 @@ -687,11 +800,10 @@ type Winsize struct { type Taskstats struct { Version uint16 - Pad_cgo_0 [2]byte Ac_exitcode uint32 Ac_flag uint8 Ac_nice uint8 - Pad_cgo_1 [6]byte + _ [4]byte Cpu_count uint64 Cpu_delay_total uint64 Blkio_count uint64 @@ -703,13 +815,13 @@ type Taskstats struct { Ac_comm [32]int8 Ac_sched uint8 Ac_pad [3]uint8 - Pad_cgo_2 [4]byte + _ [4]byte Ac_uid uint32 Ac_gid uint32 Ac_pid uint32 Ac_ppid uint32 Ac_btime uint32 - Pad_cgo_3 [4]byte + _ [4]byte Ac_etime uint64 Ac_utime uint64 Ac_stime uint64 @@ -733,6 +845,8 @@ type Taskstats struct { Cpu_scaled_run_real_total uint64 Freepages_count uint64 Freepages_delay_total uint64 + Thrashing_count uint64 + Thrashing_delay_total uint64 } const ( @@ -753,6 +867,24 @@ const ( TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK = 0x4 ) +type CGroupStats struct { + Sleeping uint64 + Running uint64 + Stopped uint64 + Uninterruptible uint64 + Io_wait uint64 +} + +const ( + CGROUPSTATS_CMD_UNSPEC = 0x3 + CGROUPSTATS_CMD_GET = 0x4 + CGROUPSTATS_CMD_NEW = 0x5 + CGROUPSTATS_TYPE_UNSPEC = 0x0 + CGROUPSTATS_TYPE_CGROUP_STATS = 0x1 + CGROUPSTATS_CMD_ATTR_UNSPEC = 0x0 + CGROUPSTATS_CMD_ATTR_FD = 0x1 +) + type Genlmsghdr struct { Cmd uint8 Version uint8 @@ -785,3 +917,1108 @@ const ( CTRL_ATTR_MCAST_GRP_NAME = 0x1 CTRL_ATTR_MCAST_GRP_ID = 0x2 ) + +type cpuMask uint32 + +const ( + _CPU_SETSIZE = 0x400 + _NCPUBITS = 0x20 +) + +const ( + BDADDR_BREDR = 0x0 + BDADDR_LE_PUBLIC = 0x1 + BDADDR_LE_RANDOM = 0x2 +) + +type PerfEventAttr struct { + Type uint32 + Size uint32 + Config uint64 + Sample uint64 + Sample_type uint64 + Read_format uint64 + Bits uint64 + Wakeup uint32 + Bp_type uint32 + Ext1 uint64 + Ext2 uint64 + Branch_sample_type uint64 + Sample_regs_user uint64 + Sample_stack_user uint32 + Clockid int32 + Sample_regs_intr uint64 + Aux_watermark uint32 + _ uint32 +} + +type PerfEventMmapPage struct { + Version uint32 + Compat_version uint32 + Lock uint32 + Index uint32 + Offset int64 + Time_enabled uint64 + Time_running uint64 + Capabilities uint64 + Pmc_width uint16 + Time_shift uint16 + Time_mult uint32 + Time_offset uint64 + Time_zero uint64 + Size uint32 + _ [948]uint8 + Data_head uint64 + Data_tail uint64 + Data_offset uint64 + Data_size uint64 + Aux_head uint64 + Aux_tail uint64 + Aux_offset uint64 + Aux_size uint64 +} + +const ( + PerfBitDisabled uint64 = CBitFieldMaskBit0 + PerfBitInherit = CBitFieldMaskBit1 + PerfBitPinned = CBitFieldMaskBit2 + PerfBitExclusive = CBitFieldMaskBit3 + PerfBitExcludeUser = CBitFieldMaskBit4 + PerfBitExcludeKernel = CBitFieldMaskBit5 + PerfBitExcludeHv = CBitFieldMaskBit6 + PerfBitExcludeIdle = CBitFieldMaskBit7 + PerfBitMmap = CBitFieldMaskBit8 + PerfBitComm = CBitFieldMaskBit9 + PerfBitFreq = CBitFieldMaskBit10 + PerfBitInheritStat = CBitFieldMaskBit11 + PerfBitEnableOnExec = CBitFieldMaskBit12 + PerfBitTask = CBitFieldMaskBit13 + PerfBitWatermark = CBitFieldMaskBit14 + PerfBitPreciseIPBit1 = CBitFieldMaskBit15 + PerfBitPreciseIPBit2 = CBitFieldMaskBit16 + PerfBitMmapData = CBitFieldMaskBit17 + PerfBitSampleIDAll = CBitFieldMaskBit18 + PerfBitExcludeHost = CBitFieldMaskBit19 + PerfBitExcludeGuest = CBitFieldMaskBit20 + PerfBitExcludeCallchainKernel = CBitFieldMaskBit21 + PerfBitExcludeCallchainUser = CBitFieldMaskBit22 + PerfBitMmap2 = CBitFieldMaskBit23 + PerfBitCommExec = CBitFieldMaskBit24 + PerfBitUseClockID = CBitFieldMaskBit25 + PerfBitContextSwitch = CBitFieldMaskBit26 +) + +const ( + PERF_TYPE_HARDWARE = 0x0 + PERF_TYPE_SOFTWARE = 0x1 + PERF_TYPE_TRACEPOINT = 0x2 + PERF_TYPE_HW_CACHE = 0x3 + PERF_TYPE_RAW = 0x4 + PERF_TYPE_BREAKPOINT = 0x5 + + PERF_COUNT_HW_CPU_CYCLES = 0x0 + PERF_COUNT_HW_INSTRUCTIONS = 0x1 + PERF_COUNT_HW_CACHE_REFERENCES = 0x2 + PERF_COUNT_HW_CACHE_MISSES = 0x3 + PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 0x4 + PERF_COUNT_HW_BRANCH_MISSES = 0x5 + PERF_COUNT_HW_BUS_CYCLES = 0x6 + PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 0x7 + PERF_COUNT_HW_STALLED_CYCLES_BACKEND = 0x8 + PERF_COUNT_HW_REF_CPU_CYCLES = 0x9 + + PERF_COUNT_HW_CACHE_L1D = 0x0 + PERF_COUNT_HW_CACHE_L1I = 0x1 + PERF_COUNT_HW_CACHE_LL = 0x2 + PERF_COUNT_HW_CACHE_DTLB = 0x3 + PERF_COUNT_HW_CACHE_ITLB = 0x4 + PERF_COUNT_HW_CACHE_BPU = 0x5 + PERF_COUNT_HW_CACHE_NODE = 0x6 + + PERF_COUNT_HW_CACHE_OP_READ = 0x0 + PERF_COUNT_HW_CACHE_OP_WRITE = 0x1 + PERF_COUNT_HW_CACHE_OP_PREFETCH = 0x2 + + PERF_COUNT_HW_CACHE_RESULT_ACCESS = 0x0 + PERF_COUNT_HW_CACHE_RESULT_MISS = 0x1 + + PERF_COUNT_SW_CPU_CLOCK = 0x0 + PERF_COUNT_SW_TASK_CLOCK = 0x1 + PERF_COUNT_SW_PAGE_FAULTS = 0x2 + PERF_COUNT_SW_CONTEXT_SWITCHES = 0x3 + PERF_COUNT_SW_CPU_MIGRATIONS = 0x4 + PERF_COUNT_SW_PAGE_FAULTS_MIN = 0x5 + PERF_COUNT_SW_PAGE_FAULTS_MAJ = 0x6 + PERF_COUNT_SW_ALIGNMENT_FAULTS = 0x7 + PERF_COUNT_SW_EMULATION_FAULTS = 0x8 + PERF_COUNT_SW_DUMMY = 0x9 + + PERF_SAMPLE_IP = 0x1 + PERF_SAMPLE_TID = 0x2 + PERF_SAMPLE_TIME = 0x4 + PERF_SAMPLE_ADDR = 0x8 + PERF_SAMPLE_READ = 0x10 + PERF_SAMPLE_CALLCHAIN = 0x20 + PERF_SAMPLE_ID = 0x40 + PERF_SAMPLE_CPU = 0x80 + PERF_SAMPLE_PERIOD = 0x100 + PERF_SAMPLE_STREAM_ID = 0x200 + PERF_SAMPLE_RAW = 0x400 + PERF_SAMPLE_BRANCH_STACK = 0x800 + + PERF_SAMPLE_BRANCH_USER = 0x1 + PERF_SAMPLE_BRANCH_KERNEL = 0x2 + PERF_SAMPLE_BRANCH_HV = 0x4 + PERF_SAMPLE_BRANCH_ANY = 0x8 + PERF_SAMPLE_BRANCH_ANY_CALL = 0x10 + PERF_SAMPLE_BRANCH_ANY_RETURN = 0x20 + PERF_SAMPLE_BRANCH_IND_CALL = 0x40 + + PERF_FORMAT_TOTAL_TIME_ENABLED = 0x1 + PERF_FORMAT_TOTAL_TIME_RUNNING = 0x2 + PERF_FORMAT_ID = 0x4 + PERF_FORMAT_GROUP = 0x8 + + PERF_RECORD_MMAP = 0x1 + PERF_RECORD_LOST = 0x2 + PERF_RECORD_COMM = 0x3 + PERF_RECORD_EXIT = 0x4 + PERF_RECORD_THROTTLE = 0x5 + PERF_RECORD_UNTHROTTLE = 0x6 + PERF_RECORD_FORK = 0x7 + PERF_RECORD_READ = 0x8 + PERF_RECORD_SAMPLE = 0x9 + + PERF_CONTEXT_HV = -0x20 + PERF_CONTEXT_KERNEL = -0x80 + PERF_CONTEXT_USER = -0x200 + + PERF_CONTEXT_GUEST = -0x800 + PERF_CONTEXT_GUEST_KERNEL = -0x880 + PERF_CONTEXT_GUEST_USER = -0xa00 + + PERF_FLAG_FD_NO_GROUP = 0x1 + PERF_FLAG_FD_OUTPUT = 0x2 + PERF_FLAG_PID_CGROUP = 0x4 +) + +const ( + CBitFieldMaskBit0 = 0x1 + CBitFieldMaskBit1 = 0x2 + CBitFieldMaskBit2 = 0x4 + CBitFieldMaskBit3 = 0x8 + CBitFieldMaskBit4 = 0x10 + CBitFieldMaskBit5 = 0x20 + CBitFieldMaskBit6 = 0x40 + CBitFieldMaskBit7 = 0x80 + CBitFieldMaskBit8 = 0x100 + CBitFieldMaskBit9 = 0x200 + CBitFieldMaskBit10 = 0x400 + CBitFieldMaskBit11 = 0x800 + CBitFieldMaskBit12 = 0x1000 + CBitFieldMaskBit13 = 0x2000 + CBitFieldMaskBit14 = 0x4000 + CBitFieldMaskBit15 = 0x8000 + CBitFieldMaskBit16 = 0x10000 + CBitFieldMaskBit17 = 0x20000 + CBitFieldMaskBit18 = 0x40000 + CBitFieldMaskBit19 = 0x80000 + CBitFieldMaskBit20 = 0x100000 + CBitFieldMaskBit21 = 0x200000 + CBitFieldMaskBit22 = 0x400000 + CBitFieldMaskBit23 = 0x800000 + CBitFieldMaskBit24 = 0x1000000 + CBitFieldMaskBit25 = 0x2000000 + CBitFieldMaskBit26 = 0x4000000 + CBitFieldMaskBit27 = 0x8000000 + CBitFieldMaskBit28 = 0x10000000 + CBitFieldMaskBit29 = 0x20000000 + CBitFieldMaskBit30 = 0x40000000 + CBitFieldMaskBit31 = 0x80000000 + CBitFieldMaskBit32 = 0x100000000 + CBitFieldMaskBit33 = 0x200000000 + CBitFieldMaskBit34 = 0x400000000 + CBitFieldMaskBit35 = 0x800000000 + CBitFieldMaskBit36 = 0x1000000000 + CBitFieldMaskBit37 = 0x2000000000 + CBitFieldMaskBit38 = 0x4000000000 + CBitFieldMaskBit39 = 0x8000000000 + CBitFieldMaskBit40 = 0x10000000000 + CBitFieldMaskBit41 = 0x20000000000 + CBitFieldMaskBit42 = 0x40000000000 + CBitFieldMaskBit43 = 0x80000000000 + CBitFieldMaskBit44 = 0x100000000000 + CBitFieldMaskBit45 = 0x200000000000 + CBitFieldMaskBit46 = 0x400000000000 + CBitFieldMaskBit47 = 0x800000000000 + CBitFieldMaskBit48 = 0x1000000000000 + CBitFieldMaskBit49 = 0x2000000000000 + CBitFieldMaskBit50 = 0x4000000000000 + CBitFieldMaskBit51 = 0x8000000000000 + CBitFieldMaskBit52 = 0x10000000000000 + CBitFieldMaskBit53 = 0x20000000000000 + CBitFieldMaskBit54 = 0x40000000000000 + CBitFieldMaskBit55 = 0x80000000000000 + CBitFieldMaskBit56 = 0x100000000000000 + CBitFieldMaskBit57 = 0x200000000000000 + CBitFieldMaskBit58 = 0x400000000000000 + CBitFieldMaskBit59 = 0x800000000000000 + CBitFieldMaskBit60 = 0x1000000000000000 + CBitFieldMaskBit61 = 0x2000000000000000 + CBitFieldMaskBit62 = 0x4000000000000000 + CBitFieldMaskBit63 = 0x8000000000000000 +) + +type SockaddrStorage struct { + Family uint16 + _ [122]int8 + _ uint32 +} + +type TCPMD5Sig struct { + Addr SockaddrStorage + Flags uint8 + Prefixlen uint8 + Keylen uint16 + _ uint32 + Key [80]uint8 +} + +type HDDriveCmdHdr struct { + Command uint8 + Number uint8 + Feature uint8 + Count uint8 +} + +type HDGeometry struct { + Heads uint8 + Sectors uint8 + Cylinders uint16 + Start uint32 +} + +type HDDriveID struct { + Config uint16 + Cyls uint16 + Reserved2 uint16 + Heads uint16 + Track_bytes uint16 + Sector_bytes uint16 + Sectors uint16 + Vendor0 uint16 + Vendor1 uint16 + Vendor2 uint16 + Serial_no [20]uint8 + Buf_type uint16 + Buf_size uint16 + Ecc_bytes uint16 + Fw_rev [8]uint8 + Model [40]uint8 + Max_multsect uint8 + Vendor3 uint8 + Dword_io uint16 + Vendor4 uint8 + Capability uint8 + Reserved50 uint16 + Vendor5 uint8 + TPIO uint8 + Vendor6 uint8 + TDMA uint8 + Field_valid uint16 + Cur_cyls uint16 + Cur_heads uint16 + Cur_sectors uint16 + Cur_capacity0 uint16 + Cur_capacity1 uint16 + Multsect uint8 + Multsect_valid uint8 + Lba_capacity uint32 + Dma_1word uint16 + Dma_mword uint16 + Eide_pio_modes uint16 + Eide_dma_min uint16 + Eide_dma_time uint16 + Eide_pio uint16 + Eide_pio_iordy uint16 + Words69_70 [2]uint16 + Words71_74 [4]uint16 + Queue_depth uint16 + Words76_79 [4]uint16 + Major_rev_num uint16 + Minor_rev_num uint16 + Command_set_1 uint16 + Command_set_2 uint16 + Cfsse uint16 + Cfs_enable_1 uint16 + Cfs_enable_2 uint16 + Csf_default uint16 + Dma_ultra uint16 + Trseuc uint16 + TrsEuc uint16 + CurAPMvalues uint16 + Mprc uint16 + Hw_config uint16 + Acoustic uint16 + Msrqs uint16 + Sxfert uint16 + Sal uint16 + Spg uint32 + Lba_capacity_2 uint64 + Words104_125 [22]uint16 + Last_lun uint16 + Word127 uint16 + Dlf uint16 + Csfo uint16 + Words130_155 [26]uint16 + Word156 uint16 + Words157_159 [3]uint16 + Cfa_power uint16 + Words161_175 [15]uint16 + Words176_205 [30]uint16 + Words206_254 [49]uint16 + Integrity_word uint16 +} + +type Statfs_t struct { + Type int32 + Bsize int32 + Frsize int32 + _ [4]byte + Blocks uint64 + Bfree uint64 + Files uint64 + Ffree uint64 + Bavail uint64 + Fsid Fsid + Namelen int32 + Flags int32 + Spare [5]int32 + _ [4]byte +} + +const ( + ST_MANDLOCK = 0x40 + ST_NOATIME = 0x400 + ST_NODEV = 0x4 + ST_NODIRATIME = 0x800 + ST_NOEXEC = 0x8 + ST_NOSUID = 0x2 + ST_RDONLY = 0x1 + ST_RELATIME = 0x1000 + ST_SYNCHRONOUS = 0x10 +) + +type TpacketHdr struct { + Status uint32 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Sec uint32 + Usec uint32 +} + +type Tpacket2Hdr struct { + Status uint32 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Sec uint32 + Nsec uint32 + Vlan_tci uint16 + Vlan_tpid uint16 + _ [4]uint8 +} + +type Tpacket3Hdr struct { + Next_offset uint32 + Sec uint32 + Nsec uint32 + Snaplen uint32 + Len uint32 + Status uint32 + Mac uint16 + Net uint16 + Hv1 TpacketHdrVariant1 + _ [8]uint8 +} + +type TpacketHdrVariant1 struct { + Rxhash uint32 + Vlan_tci uint32 + Vlan_tpid uint16 + _ uint16 +} + +type TpacketBlockDesc struct { + Version uint32 + To_priv uint32 + Hdr [40]byte +} + +type TpacketReq struct { + Block_size uint32 + Block_nr uint32 + Frame_size uint32 + Frame_nr uint32 +} + +type TpacketReq3 struct { + Block_size uint32 + Block_nr uint32 + Frame_size uint32 + Frame_nr uint32 + Retire_blk_tov uint32 + Sizeof_priv uint32 + Feature_req_word uint32 +} + +type TpacketStats struct { + Packets uint32 + Drops uint32 +} + +type TpacketStatsV3 struct { + Packets uint32 + Drops uint32 + Freeze_q_cnt uint32 +} + +type TpacketAuxdata struct { + Status uint32 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Vlan_tci uint16 + Vlan_tpid uint16 +} + +const ( + TPACKET_V1 = 0x0 + TPACKET_V2 = 0x1 + TPACKET_V3 = 0x2 +) + +const ( + SizeofTpacketHdr = 0x18 + SizeofTpacket2Hdr = 0x20 + SizeofTpacket3Hdr = 0x30 +) + +const ( + NF_INET_PRE_ROUTING = 0x0 + NF_INET_LOCAL_IN = 0x1 + NF_INET_FORWARD = 0x2 + NF_INET_LOCAL_OUT = 0x3 + NF_INET_POST_ROUTING = 0x4 + NF_INET_NUMHOOKS = 0x5 +) + +const ( + NF_NETDEV_INGRESS = 0x0 + NF_NETDEV_NUMHOOKS = 0x1 +) + +const ( + NFPROTO_UNSPEC = 0x0 + NFPROTO_INET = 0x1 + NFPROTO_IPV4 = 0x2 + NFPROTO_ARP = 0x3 + NFPROTO_NETDEV = 0x5 + NFPROTO_BRIDGE = 0x7 + NFPROTO_IPV6 = 0xa + NFPROTO_DECNET = 0xc + NFPROTO_NUMPROTO = 0xd +) + +type Nfgenmsg struct { + Nfgen_family uint8 + Version uint8 + Res_id uint16 +} + +const ( + NFNL_BATCH_UNSPEC = 0x0 + NFNL_BATCH_GENID = 0x1 +) + +const ( + NFT_REG_VERDICT = 0x0 + NFT_REG_1 = 0x1 + NFT_REG_2 = 0x2 + NFT_REG_3 = 0x3 + NFT_REG_4 = 0x4 + NFT_REG32_00 = 0x8 + NFT_REG32_01 = 0x9 + NFT_REG32_02 = 0xa + NFT_REG32_03 = 0xb + NFT_REG32_04 = 0xc + NFT_REG32_05 = 0xd + NFT_REG32_06 = 0xe + NFT_REG32_07 = 0xf + NFT_REG32_08 = 0x10 + NFT_REG32_09 = 0x11 + NFT_REG32_10 = 0x12 + NFT_REG32_11 = 0x13 + NFT_REG32_12 = 0x14 + NFT_REG32_13 = 0x15 + NFT_REG32_14 = 0x16 + NFT_REG32_15 = 0x17 + NFT_CONTINUE = -0x1 + NFT_BREAK = -0x2 + NFT_JUMP = -0x3 + NFT_GOTO = -0x4 + NFT_RETURN = -0x5 + NFT_MSG_NEWTABLE = 0x0 + NFT_MSG_GETTABLE = 0x1 + NFT_MSG_DELTABLE = 0x2 + NFT_MSG_NEWCHAIN = 0x3 + NFT_MSG_GETCHAIN = 0x4 + NFT_MSG_DELCHAIN = 0x5 + NFT_MSG_NEWRULE = 0x6 + NFT_MSG_GETRULE = 0x7 + NFT_MSG_DELRULE = 0x8 + NFT_MSG_NEWSET = 0x9 + NFT_MSG_GETSET = 0xa + NFT_MSG_DELSET = 0xb + NFT_MSG_NEWSETELEM = 0xc + NFT_MSG_GETSETELEM = 0xd + NFT_MSG_DELSETELEM = 0xe + NFT_MSG_NEWGEN = 0xf + NFT_MSG_GETGEN = 0x10 + NFT_MSG_TRACE = 0x11 + NFT_MSG_NEWOBJ = 0x12 + NFT_MSG_GETOBJ = 0x13 + NFT_MSG_DELOBJ = 0x14 + NFT_MSG_GETOBJ_RESET = 0x15 + NFT_MSG_MAX = 0x19 + NFTA_LIST_UNPEC = 0x0 + NFTA_LIST_ELEM = 0x1 + NFTA_HOOK_UNSPEC = 0x0 + NFTA_HOOK_HOOKNUM = 0x1 + NFTA_HOOK_PRIORITY = 0x2 + NFTA_HOOK_DEV = 0x3 + NFT_TABLE_F_DORMANT = 0x1 + NFTA_TABLE_UNSPEC = 0x0 + NFTA_TABLE_NAME = 0x1 + NFTA_TABLE_FLAGS = 0x2 + NFTA_TABLE_USE = 0x3 + NFTA_CHAIN_UNSPEC = 0x0 + NFTA_CHAIN_TABLE = 0x1 + NFTA_CHAIN_HANDLE = 0x2 + NFTA_CHAIN_NAME = 0x3 + NFTA_CHAIN_HOOK = 0x4 + NFTA_CHAIN_POLICY = 0x5 + NFTA_CHAIN_USE = 0x6 + NFTA_CHAIN_TYPE = 0x7 + NFTA_CHAIN_COUNTERS = 0x8 + NFTA_CHAIN_PAD = 0x9 + NFTA_RULE_UNSPEC = 0x0 + NFTA_RULE_TABLE = 0x1 + NFTA_RULE_CHAIN = 0x2 + NFTA_RULE_HANDLE = 0x3 + NFTA_RULE_EXPRESSIONS = 0x4 + NFTA_RULE_COMPAT = 0x5 + NFTA_RULE_POSITION = 0x6 + NFTA_RULE_USERDATA = 0x7 + NFTA_RULE_PAD = 0x8 + NFTA_RULE_ID = 0x9 + NFT_RULE_COMPAT_F_INV = 0x2 + NFT_RULE_COMPAT_F_MASK = 0x2 + NFTA_RULE_COMPAT_UNSPEC = 0x0 + NFTA_RULE_COMPAT_PROTO = 0x1 + NFTA_RULE_COMPAT_FLAGS = 0x2 + NFT_SET_ANONYMOUS = 0x1 + NFT_SET_CONSTANT = 0x2 + NFT_SET_INTERVAL = 0x4 + NFT_SET_MAP = 0x8 + NFT_SET_TIMEOUT = 0x10 + NFT_SET_EVAL = 0x20 + NFT_SET_OBJECT = 0x40 + NFT_SET_POL_PERFORMANCE = 0x0 + NFT_SET_POL_MEMORY = 0x1 + NFTA_SET_DESC_UNSPEC = 0x0 + NFTA_SET_DESC_SIZE = 0x1 + NFTA_SET_UNSPEC = 0x0 + NFTA_SET_TABLE = 0x1 + NFTA_SET_NAME = 0x2 + NFTA_SET_FLAGS = 0x3 + NFTA_SET_KEY_TYPE = 0x4 + NFTA_SET_KEY_LEN = 0x5 + NFTA_SET_DATA_TYPE = 0x6 + NFTA_SET_DATA_LEN = 0x7 + NFTA_SET_POLICY = 0x8 + NFTA_SET_DESC = 0x9 + NFTA_SET_ID = 0xa + NFTA_SET_TIMEOUT = 0xb + NFTA_SET_GC_INTERVAL = 0xc + NFTA_SET_USERDATA = 0xd + NFTA_SET_PAD = 0xe + NFTA_SET_OBJ_TYPE = 0xf + NFT_SET_ELEM_INTERVAL_END = 0x1 + NFTA_SET_ELEM_UNSPEC = 0x0 + NFTA_SET_ELEM_KEY = 0x1 + NFTA_SET_ELEM_DATA = 0x2 + NFTA_SET_ELEM_FLAGS = 0x3 + NFTA_SET_ELEM_TIMEOUT = 0x4 + NFTA_SET_ELEM_EXPIRATION = 0x5 + NFTA_SET_ELEM_USERDATA = 0x6 + NFTA_SET_ELEM_EXPR = 0x7 + NFTA_SET_ELEM_PAD = 0x8 + NFTA_SET_ELEM_OBJREF = 0x9 + NFTA_SET_ELEM_LIST_UNSPEC = 0x0 + NFTA_SET_ELEM_LIST_TABLE = 0x1 + NFTA_SET_ELEM_LIST_SET = 0x2 + NFTA_SET_ELEM_LIST_ELEMENTS = 0x3 + NFTA_SET_ELEM_LIST_SET_ID = 0x4 + NFT_DATA_VALUE = 0x0 + NFT_DATA_VERDICT = 0xffffff00 + NFTA_DATA_UNSPEC = 0x0 + NFTA_DATA_VALUE = 0x1 + NFTA_DATA_VERDICT = 0x2 + NFTA_VERDICT_UNSPEC = 0x0 + NFTA_VERDICT_CODE = 0x1 + NFTA_VERDICT_CHAIN = 0x2 + NFTA_EXPR_UNSPEC = 0x0 + NFTA_EXPR_NAME = 0x1 + NFTA_EXPR_DATA = 0x2 + NFTA_IMMEDIATE_UNSPEC = 0x0 + NFTA_IMMEDIATE_DREG = 0x1 + NFTA_IMMEDIATE_DATA = 0x2 + NFTA_BITWISE_UNSPEC = 0x0 + NFTA_BITWISE_SREG = 0x1 + NFTA_BITWISE_DREG = 0x2 + NFTA_BITWISE_LEN = 0x3 + NFTA_BITWISE_MASK = 0x4 + NFTA_BITWISE_XOR = 0x5 + NFT_BYTEORDER_NTOH = 0x0 + NFT_BYTEORDER_HTON = 0x1 + NFTA_BYTEORDER_UNSPEC = 0x0 + NFTA_BYTEORDER_SREG = 0x1 + NFTA_BYTEORDER_DREG = 0x2 + NFTA_BYTEORDER_OP = 0x3 + NFTA_BYTEORDER_LEN = 0x4 + NFTA_BYTEORDER_SIZE = 0x5 + NFT_CMP_EQ = 0x0 + NFT_CMP_NEQ = 0x1 + NFT_CMP_LT = 0x2 + NFT_CMP_LTE = 0x3 + NFT_CMP_GT = 0x4 + NFT_CMP_GTE = 0x5 + NFTA_CMP_UNSPEC = 0x0 + NFTA_CMP_SREG = 0x1 + NFTA_CMP_OP = 0x2 + NFTA_CMP_DATA = 0x3 + NFT_RANGE_EQ = 0x0 + NFT_RANGE_NEQ = 0x1 + NFTA_RANGE_UNSPEC = 0x0 + NFTA_RANGE_SREG = 0x1 + NFTA_RANGE_OP = 0x2 + NFTA_RANGE_FROM_DATA = 0x3 + NFTA_RANGE_TO_DATA = 0x4 + NFT_LOOKUP_F_INV = 0x1 + NFTA_LOOKUP_UNSPEC = 0x0 + NFTA_LOOKUP_SET = 0x1 + NFTA_LOOKUP_SREG = 0x2 + NFTA_LOOKUP_DREG = 0x3 + NFTA_LOOKUP_SET_ID = 0x4 + NFTA_LOOKUP_FLAGS = 0x5 + NFT_DYNSET_OP_ADD = 0x0 + NFT_DYNSET_OP_UPDATE = 0x1 + NFT_DYNSET_F_INV = 0x1 + NFTA_DYNSET_UNSPEC = 0x0 + NFTA_DYNSET_SET_NAME = 0x1 + NFTA_DYNSET_SET_ID = 0x2 + NFTA_DYNSET_OP = 0x3 + NFTA_DYNSET_SREG_KEY = 0x4 + NFTA_DYNSET_SREG_DATA = 0x5 + NFTA_DYNSET_TIMEOUT = 0x6 + NFTA_DYNSET_EXPR = 0x7 + NFTA_DYNSET_PAD = 0x8 + NFTA_DYNSET_FLAGS = 0x9 + NFT_PAYLOAD_LL_HEADER = 0x0 + NFT_PAYLOAD_NETWORK_HEADER = 0x1 + NFT_PAYLOAD_TRANSPORT_HEADER = 0x2 + NFT_PAYLOAD_CSUM_NONE = 0x0 + NFT_PAYLOAD_CSUM_INET = 0x1 + NFT_PAYLOAD_L4CSUM_PSEUDOHDR = 0x1 + NFTA_PAYLOAD_UNSPEC = 0x0 + NFTA_PAYLOAD_DREG = 0x1 + NFTA_PAYLOAD_BASE = 0x2 + NFTA_PAYLOAD_OFFSET = 0x3 + NFTA_PAYLOAD_LEN = 0x4 + NFTA_PAYLOAD_SREG = 0x5 + NFTA_PAYLOAD_CSUM_TYPE = 0x6 + NFTA_PAYLOAD_CSUM_OFFSET = 0x7 + NFTA_PAYLOAD_CSUM_FLAGS = 0x8 + NFT_EXTHDR_F_PRESENT = 0x1 + NFT_EXTHDR_OP_IPV6 = 0x0 + NFT_EXTHDR_OP_TCPOPT = 0x1 + NFTA_EXTHDR_UNSPEC = 0x0 + NFTA_EXTHDR_DREG = 0x1 + NFTA_EXTHDR_TYPE = 0x2 + NFTA_EXTHDR_OFFSET = 0x3 + NFTA_EXTHDR_LEN = 0x4 + NFTA_EXTHDR_FLAGS = 0x5 + NFTA_EXTHDR_OP = 0x6 + NFTA_EXTHDR_SREG = 0x7 + NFT_META_LEN = 0x0 + NFT_META_PROTOCOL = 0x1 + NFT_META_PRIORITY = 0x2 + NFT_META_MARK = 0x3 + NFT_META_IIF = 0x4 + NFT_META_OIF = 0x5 + NFT_META_IIFNAME = 0x6 + NFT_META_OIFNAME = 0x7 + NFT_META_IIFTYPE = 0x8 + NFT_META_OIFTYPE = 0x9 + NFT_META_SKUID = 0xa + NFT_META_SKGID = 0xb + NFT_META_NFTRACE = 0xc + NFT_META_RTCLASSID = 0xd + NFT_META_SECMARK = 0xe + NFT_META_NFPROTO = 0xf + NFT_META_L4PROTO = 0x10 + NFT_META_BRI_IIFNAME = 0x11 + NFT_META_BRI_OIFNAME = 0x12 + NFT_META_PKTTYPE = 0x13 + NFT_META_CPU = 0x14 + NFT_META_IIFGROUP = 0x15 + NFT_META_OIFGROUP = 0x16 + NFT_META_CGROUP = 0x17 + NFT_META_PRANDOM = 0x18 + NFT_RT_CLASSID = 0x0 + NFT_RT_NEXTHOP4 = 0x1 + NFT_RT_NEXTHOP6 = 0x2 + NFT_RT_TCPMSS = 0x3 + NFT_HASH_JENKINS = 0x0 + NFT_HASH_SYM = 0x1 + NFTA_HASH_UNSPEC = 0x0 + NFTA_HASH_SREG = 0x1 + NFTA_HASH_DREG = 0x2 + NFTA_HASH_LEN = 0x3 + NFTA_HASH_MODULUS = 0x4 + NFTA_HASH_SEED = 0x5 + NFTA_HASH_OFFSET = 0x6 + NFTA_HASH_TYPE = 0x7 + NFTA_META_UNSPEC = 0x0 + NFTA_META_DREG = 0x1 + NFTA_META_KEY = 0x2 + NFTA_META_SREG = 0x3 + NFTA_RT_UNSPEC = 0x0 + NFTA_RT_DREG = 0x1 + NFTA_RT_KEY = 0x2 + NFT_CT_STATE = 0x0 + NFT_CT_DIRECTION = 0x1 + NFT_CT_STATUS = 0x2 + NFT_CT_MARK = 0x3 + NFT_CT_SECMARK = 0x4 + NFT_CT_EXPIRATION = 0x5 + NFT_CT_HELPER = 0x6 + NFT_CT_L3PROTOCOL = 0x7 + NFT_CT_SRC = 0x8 + NFT_CT_DST = 0x9 + NFT_CT_PROTOCOL = 0xa + NFT_CT_PROTO_SRC = 0xb + NFT_CT_PROTO_DST = 0xc + NFT_CT_LABELS = 0xd + NFT_CT_PKTS = 0xe + NFT_CT_BYTES = 0xf + NFT_CT_AVGPKT = 0x10 + NFT_CT_ZONE = 0x11 + NFT_CT_EVENTMASK = 0x12 + NFTA_CT_UNSPEC = 0x0 + NFTA_CT_DREG = 0x1 + NFTA_CT_KEY = 0x2 + NFTA_CT_DIRECTION = 0x3 + NFTA_CT_SREG = 0x4 + NFT_LIMIT_PKTS = 0x0 + NFT_LIMIT_PKT_BYTES = 0x1 + NFT_LIMIT_F_INV = 0x1 + NFTA_LIMIT_UNSPEC = 0x0 + NFTA_LIMIT_RATE = 0x1 + NFTA_LIMIT_UNIT = 0x2 + NFTA_LIMIT_BURST = 0x3 + NFTA_LIMIT_TYPE = 0x4 + NFTA_LIMIT_FLAGS = 0x5 + NFTA_LIMIT_PAD = 0x6 + NFTA_COUNTER_UNSPEC = 0x0 + NFTA_COUNTER_BYTES = 0x1 + NFTA_COUNTER_PACKETS = 0x2 + NFTA_COUNTER_PAD = 0x3 + NFTA_LOG_UNSPEC = 0x0 + NFTA_LOG_GROUP = 0x1 + NFTA_LOG_PREFIX = 0x2 + NFTA_LOG_SNAPLEN = 0x3 + NFTA_LOG_QTHRESHOLD = 0x4 + NFTA_LOG_LEVEL = 0x5 + NFTA_LOG_FLAGS = 0x6 + NFTA_QUEUE_UNSPEC = 0x0 + NFTA_QUEUE_NUM = 0x1 + NFTA_QUEUE_TOTAL = 0x2 + NFTA_QUEUE_FLAGS = 0x3 + NFTA_QUEUE_SREG_QNUM = 0x4 + NFT_QUOTA_F_INV = 0x1 + NFT_QUOTA_F_DEPLETED = 0x2 + NFTA_QUOTA_UNSPEC = 0x0 + NFTA_QUOTA_BYTES = 0x1 + NFTA_QUOTA_FLAGS = 0x2 + NFTA_QUOTA_PAD = 0x3 + NFTA_QUOTA_CONSUMED = 0x4 + NFT_REJECT_ICMP_UNREACH = 0x0 + NFT_REJECT_TCP_RST = 0x1 + NFT_REJECT_ICMPX_UNREACH = 0x2 + NFT_REJECT_ICMPX_NO_ROUTE = 0x0 + NFT_REJECT_ICMPX_PORT_UNREACH = 0x1 + NFT_REJECT_ICMPX_HOST_UNREACH = 0x2 + NFT_REJECT_ICMPX_ADMIN_PROHIBITED = 0x3 + NFTA_REJECT_UNSPEC = 0x0 + NFTA_REJECT_TYPE = 0x1 + NFTA_REJECT_ICMP_CODE = 0x2 + NFT_NAT_SNAT = 0x0 + NFT_NAT_DNAT = 0x1 + NFTA_NAT_UNSPEC = 0x0 + NFTA_NAT_TYPE = 0x1 + NFTA_NAT_FAMILY = 0x2 + NFTA_NAT_REG_ADDR_MIN = 0x3 + NFTA_NAT_REG_ADDR_MAX = 0x4 + NFTA_NAT_REG_PROTO_MIN = 0x5 + NFTA_NAT_REG_PROTO_MAX = 0x6 + NFTA_NAT_FLAGS = 0x7 + NFTA_MASQ_UNSPEC = 0x0 + NFTA_MASQ_FLAGS = 0x1 + NFTA_MASQ_REG_PROTO_MIN = 0x2 + NFTA_MASQ_REG_PROTO_MAX = 0x3 + NFTA_REDIR_UNSPEC = 0x0 + NFTA_REDIR_REG_PROTO_MIN = 0x1 + NFTA_REDIR_REG_PROTO_MAX = 0x2 + NFTA_REDIR_FLAGS = 0x3 + NFTA_DUP_UNSPEC = 0x0 + NFTA_DUP_SREG_ADDR = 0x1 + NFTA_DUP_SREG_DEV = 0x2 + NFTA_FWD_UNSPEC = 0x0 + NFTA_FWD_SREG_DEV = 0x1 + NFTA_OBJREF_UNSPEC = 0x0 + NFTA_OBJREF_IMM_TYPE = 0x1 + NFTA_OBJREF_IMM_NAME = 0x2 + NFTA_OBJREF_SET_SREG = 0x3 + NFTA_OBJREF_SET_NAME = 0x4 + NFTA_OBJREF_SET_ID = 0x5 + NFTA_GEN_UNSPEC = 0x0 + NFTA_GEN_ID = 0x1 + NFTA_GEN_PROC_PID = 0x2 + NFTA_GEN_PROC_NAME = 0x3 + NFTA_FIB_UNSPEC = 0x0 + NFTA_FIB_DREG = 0x1 + NFTA_FIB_RESULT = 0x2 + NFTA_FIB_FLAGS = 0x3 + NFT_FIB_RESULT_UNSPEC = 0x0 + NFT_FIB_RESULT_OIF = 0x1 + NFT_FIB_RESULT_OIFNAME = 0x2 + NFT_FIB_RESULT_ADDRTYPE = 0x3 + NFTA_FIB_F_SADDR = 0x1 + NFTA_FIB_F_DADDR = 0x2 + NFTA_FIB_F_MARK = 0x4 + NFTA_FIB_F_IIF = 0x8 + NFTA_FIB_F_OIF = 0x10 + NFTA_FIB_F_PRESENT = 0x20 + NFTA_CT_HELPER_UNSPEC = 0x0 + NFTA_CT_HELPER_NAME = 0x1 + NFTA_CT_HELPER_L3PROTO = 0x2 + NFTA_CT_HELPER_L4PROTO = 0x3 + NFTA_OBJ_UNSPEC = 0x0 + NFTA_OBJ_TABLE = 0x1 + NFTA_OBJ_NAME = 0x2 + NFTA_OBJ_TYPE = 0x3 + NFTA_OBJ_DATA = 0x4 + NFTA_OBJ_USE = 0x5 + NFTA_TRACE_UNSPEC = 0x0 + NFTA_TRACE_TABLE = 0x1 + NFTA_TRACE_CHAIN = 0x2 + NFTA_TRACE_RULE_HANDLE = 0x3 + NFTA_TRACE_TYPE = 0x4 + NFTA_TRACE_VERDICT = 0x5 + NFTA_TRACE_ID = 0x6 + NFTA_TRACE_LL_HEADER = 0x7 + NFTA_TRACE_NETWORK_HEADER = 0x8 + NFTA_TRACE_TRANSPORT_HEADER = 0x9 + NFTA_TRACE_IIF = 0xa + NFTA_TRACE_IIFTYPE = 0xb + NFTA_TRACE_OIF = 0xc + NFTA_TRACE_OIFTYPE = 0xd + NFTA_TRACE_MARK = 0xe + NFTA_TRACE_NFPROTO = 0xf + NFTA_TRACE_POLICY = 0x10 + NFTA_TRACE_PAD = 0x11 + NFT_TRACETYPE_UNSPEC = 0x0 + NFT_TRACETYPE_POLICY = 0x1 + NFT_TRACETYPE_RETURN = 0x2 + NFT_TRACETYPE_RULE = 0x3 + NFTA_NG_UNSPEC = 0x0 + NFTA_NG_DREG = 0x1 + NFTA_NG_MODULUS = 0x2 + NFTA_NG_TYPE = 0x3 + NFTA_NG_OFFSET = 0x4 + NFT_NG_INCREMENTAL = 0x0 + NFT_NG_RANDOM = 0x1 +) + +type RTCTime struct { + Sec int32 + Min int32 + Hour int32 + Mday int32 + Mon int32 + Year int32 + Wday int32 + Yday int32 + Isdst int32 +} + +type RTCWkAlrm struct { + Enabled uint8 + Pending uint8 + Time RTCTime +} + +type RTCPLLInfo struct { + Ctrl int32 + Value int32 + Max int32 + Min int32 + Posmult int32 + Negmult int32 + Clock int32 +} + +type BlkpgIoctlArg struct { + Op int32 + Flags int32 + Datalen int32 + Data *byte +} + +type BlkpgPartition struct { + Start int64 + Length int64 + Pno int32 + Devname [64]uint8 + Volname [64]uint8 + _ [4]byte +} + +const ( + BLKPG = 0x20001269 + BLKPG_ADD_PARTITION = 0x1 + BLKPG_DEL_PARTITION = 0x2 + BLKPG_RESIZE_PARTITION = 0x3 +) + +const ( + NETNSA_NONE = 0x0 + NETNSA_NSID = 0x1 + NETNSA_PID = 0x2 + NETNSA_FD = 0x3 +) + +type XDPRingOffset struct { + Producer uint64 + Consumer uint64 + Desc uint64 +} + +type XDPMmapOffsets struct { + Rx XDPRingOffset + Tx XDPRingOffset + Fr XDPRingOffset + Cr XDPRingOffset +} + +type XDPUmemReg struct { + Addr uint64 + Len uint64 + Size uint32 + Headroom uint32 +} + +type XDPStatistics struct { + Rx_dropped uint64 + Rx_invalid_descs uint64 + Tx_invalid_descs uint64 +} + +type XDPDesc struct { + Addr uint64 + Len uint32 + Options uint32 +} + +const ( + NCSI_CMD_UNSPEC = 0x0 + NCSI_CMD_PKG_INFO = 0x1 + NCSI_CMD_SET_INTERFACE = 0x2 + NCSI_CMD_CLEAR_INTERFACE = 0x3 + NCSI_ATTR_UNSPEC = 0x0 + NCSI_ATTR_IFINDEX = 0x1 + NCSI_ATTR_PACKAGE_LIST = 0x2 + NCSI_ATTR_PACKAGE_ID = 0x3 + NCSI_ATTR_CHANNEL_ID = 0x4 + NCSI_PKG_ATTR_UNSPEC = 0x0 + NCSI_PKG_ATTR = 0x1 + NCSI_PKG_ATTR_ID = 0x2 + NCSI_PKG_ATTR_FORCED = 0x3 + NCSI_PKG_ATTR_CHANNEL_LIST = 0x4 + NCSI_CHANNEL_ATTR_UNSPEC = 0x0 + NCSI_CHANNEL_ATTR = 0x1 + NCSI_CHANNEL_ATTR_ID = 0x2 + NCSI_CHANNEL_ATTR_VERSION_MAJOR = 0x3 + NCSI_CHANNEL_ATTR_VERSION_MINOR = 0x4 + NCSI_CHANNEL_ATTR_VERSION_STR = 0x5 + NCSI_CHANNEL_ATTR_LINK_STATE = 0x6 + NCSI_CHANNEL_ATTR_ACTIVE = 0x7 + NCSI_CHANNEL_ATTR_FORCED = 0x8 + NCSI_CHANNEL_ATTR_VLAN_LIST = 0x9 + NCSI_CHANNEL_ATTR_VLAN_ID = 0xa +) + +type ScmTimestamping struct { + Ts [3]Timespec +} + +const ( + SOF_TIMESTAMPING_TX_HARDWARE = 0x1 + SOF_TIMESTAMPING_TX_SOFTWARE = 0x2 + SOF_TIMESTAMPING_RX_HARDWARE = 0x4 + SOF_TIMESTAMPING_RX_SOFTWARE = 0x8 + SOF_TIMESTAMPING_SOFTWARE = 0x10 + SOF_TIMESTAMPING_SYS_HARDWARE = 0x20 + SOF_TIMESTAMPING_RAW_HARDWARE = 0x40 + SOF_TIMESTAMPING_OPT_ID = 0x80 + SOF_TIMESTAMPING_TX_SCHED = 0x100 + SOF_TIMESTAMPING_TX_ACK = 0x200 + SOF_TIMESTAMPING_OPT_CMSG = 0x400 + SOF_TIMESTAMPING_OPT_TSONLY = 0x800 + SOF_TIMESTAMPING_OPT_STATS = 0x1000 + SOF_TIMESTAMPING_OPT_PKTINFO = 0x2000 + SOF_TIMESTAMPING_OPT_TX_SWHW = 0x4000 + + SOF_TIMESTAMPING_LAST = 0x4000 + SOF_TIMESTAMPING_MASK = 0x7fff + + SCM_TSTAMP_SND = 0x0 + SCM_TSTAMP_SCHED = 0x1 + SCM_TSTAMP_ACK = 0x2 +) + +type SockExtendedErr struct { + Errno uint32 + Origin uint8 + Type uint8 + Code uint8 + Pad uint8 + Info uint32 + Data uint32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go index 3803e1062b..5ac91b3f7a 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go @@ -6,11 +6,11 @@ package unix const ( - sizeofPtr = 0x8 - sizeofShort = 0x2 - sizeofInt = 0x4 - sizeofLong = 0x8 - sizeofLongLong = 0x8 + SizeofPtr = 0x8 + SizeofShort = 0x2 + SizeofInt = 0x4 + SizeofLong = 0x8 + SizeofLongLong = 0x8 PathMax = 0x1000 ) @@ -33,13 +33,11 @@ type Timeval struct { type Timex struct { Modes uint32 - Pad_cgo_0 [4]byte Offset int64 Freq int64 Maxerror int64 Esterror int64 Status int32 - Pad_cgo_1 [4]byte Constant int64 Precision int64 Tolerance int64 @@ -48,14 +46,13 @@ type Timex struct { Ppsfreq int64 Jitter int64 Shift int32 - Pad_cgo_2 [4]byte Stabil int64 Jitcnt int64 Calcnt int64 Errcnt int64 Stbcnt int64 Tai int32 - Pad_cgo_3 [44]byte + _ [44]byte } type Time_t int64 @@ -105,7 +102,7 @@ type Stat_t struct { Mode uint32 Uid uint32 Gid uint32 - X__pad2 int32 + _ int32 Rdev uint64 Size int64 Blksize int64 @@ -118,42 +115,56 @@ type Stat_t struct { _ uint64 } -type Statfs_t struct { - Type int64 - Bsize int64 - Blocks uint64 - Bfree uint64 - Bavail uint64 - Files uint64 - Ffree uint64 - Fsid Fsid - Namelen int64 - Frsize int64 - Flags int64 - Spare [4]int64 +type StatxTimestamp struct { + Sec int64 + Nsec uint32 + _ int32 +} + +type Statx_t struct { + Mask uint32 + Blksize uint32 + Attributes uint64 + Nlink uint32 + Uid uint32 + Gid uint32 + Mode uint16 + _ [1]uint16 + Ino uint64 + Size uint64 + Blocks uint64 + Attributes_mask uint64 + Atime StatxTimestamp + Btime StatxTimestamp + Ctime StatxTimestamp + Mtime StatxTimestamp + Rdev_major uint32 + Rdev_minor uint32 + Dev_major uint32 + Dev_minor uint32 + _ [14]uint64 } type Dirent struct { - Ino uint64 - Off int64 - Reclen uint16 - Type uint8 - Name [256]uint8 - Pad_cgo_0 [5]byte + Ino uint64 + Off int64 + Reclen uint16 + Type uint8 + Name [256]uint8 + _ [5]byte } type Fsid struct { - X__val [2]int32 + Val [2]int32 } type Flock_t struct { - Type int16 - Whence int16 - Pad_cgo_0 [4]byte - Start int64 - Len int64 - Pid int32 - Pad_cgo_1 [4]byte + Type int16 + Whence int16 + Start int64 + Len int64 + Pid int32 + _ [4]byte } type FscryptPolicy struct { @@ -228,11 +239,26 @@ type RawSockaddrHCI struct { Channel uint16 } +type RawSockaddrL2 struct { + Family uint16 + Psm uint16 + Bdaddr [6]uint8 + Cid uint16 + Bdaddr_type uint8 + _ [1]byte +} + +type RawSockaddrRFCOMM struct { + Family uint16 + Bdaddr [6]uint8 + Channel uint8 + _ [1]byte +} + type RawSockaddrCAN struct { - Family uint16 - Pad_cgo_0 [2]byte - Ifindex int32 - Addr [8]byte + Family uint16 + Ifindex int32 + Addr [8]byte } type RawSockaddrALG struct { @@ -251,6 +277,16 @@ type RawSockaddrVM struct { Zero [4]uint8 } +type RawSockaddrXDP struct { + Family uint16 + Flags uint16 + Ifindex uint32 + Queue_id uint32 + Shared_umem_fd uint32 +} + +type RawSockaddrPPPoX [0x1e]byte + type RawSockaddr struct { Family uint16 Data [14]uint8 @@ -299,13 +335,12 @@ type PacketMreq struct { type Msghdr struct { Name *byte Namelen uint32 - Pad_cgo_0 [4]byte Iov *Iovec Iovlen uint64 Control *byte Controllen uint64 Flags int32 - Pad_cgo_1 [4]byte + _ [4]byte } type Cmsghdr struct { @@ -347,7 +382,6 @@ type TCPInfo struct { Probes uint8 Backoff uint8 Options uint8 - Pad_cgo_0 [2]byte Rto uint32 Ato uint32 Snd_mss uint32 @@ -382,9 +416,13 @@ const ( SizeofSockaddrLinklayer = 0x14 SizeofSockaddrNetlink = 0xc SizeofSockaddrHCI = 0x6 + SizeofSockaddrL2 = 0xe + SizeofSockaddrRFCOMM = 0xa SizeofSockaddrCAN = 0x10 SizeofSockaddrALG = 0x58 SizeofSockaddrVM = 0x10 + SizeofSockaddrXDP = 0x10 + SizeofSockaddrPPPoX = 0x1e SizeofLinger = 0x8 SizeofIovec = 0x10 SizeofIPMreq = 0x8 @@ -402,97 +440,138 @@ const ( ) const ( - IFA_UNSPEC = 0x0 - IFA_ADDRESS = 0x1 - IFA_LOCAL = 0x2 - IFA_LABEL = 0x3 - IFA_BROADCAST = 0x4 - IFA_ANYCAST = 0x5 - IFA_CACHEINFO = 0x6 - IFA_MULTICAST = 0x7 - IFLA_UNSPEC = 0x0 - IFLA_ADDRESS = 0x1 - IFLA_BROADCAST = 0x2 - IFLA_IFNAME = 0x3 - IFLA_MTU = 0x4 - IFLA_LINK = 0x5 - IFLA_QDISC = 0x6 - IFLA_STATS = 0x7 - IFLA_COST = 0x8 - IFLA_PRIORITY = 0x9 - IFLA_MASTER = 0xa - IFLA_WIRELESS = 0xb - IFLA_PROTINFO = 0xc - IFLA_TXQLEN = 0xd - IFLA_MAP = 0xe - IFLA_WEIGHT = 0xf - IFLA_OPERSTATE = 0x10 - IFLA_LINKMODE = 0x11 - IFLA_LINKINFO = 0x12 - IFLA_NET_NS_PID = 0x13 - IFLA_IFALIAS = 0x14 - IFLA_MAX = 0x2c - RT_SCOPE_UNIVERSE = 0x0 - RT_SCOPE_SITE = 0xc8 - RT_SCOPE_LINK = 0xfd - RT_SCOPE_HOST = 0xfe - RT_SCOPE_NOWHERE = 0xff - RT_TABLE_UNSPEC = 0x0 - RT_TABLE_COMPAT = 0xfc - RT_TABLE_DEFAULT = 0xfd - RT_TABLE_MAIN = 0xfe - RT_TABLE_LOCAL = 0xff - RT_TABLE_MAX = 0xffffffff - RTA_UNSPEC = 0x0 - RTA_DST = 0x1 - RTA_SRC = 0x2 - RTA_IIF = 0x3 - RTA_OIF = 0x4 - RTA_GATEWAY = 0x5 - RTA_PRIORITY = 0x6 - RTA_PREFSRC = 0x7 - RTA_METRICS = 0x8 - RTA_MULTIPATH = 0x9 - RTA_FLOW = 0xb - RTA_CACHEINFO = 0xc - RTA_TABLE = 0xf - RTN_UNSPEC = 0x0 - RTN_UNICAST = 0x1 - RTN_LOCAL = 0x2 - RTN_BROADCAST = 0x3 - RTN_ANYCAST = 0x4 - RTN_MULTICAST = 0x5 - RTN_BLACKHOLE = 0x6 - RTN_UNREACHABLE = 0x7 - RTN_PROHIBIT = 0x8 - RTN_THROW = 0x9 - RTN_NAT = 0xa - RTN_XRESOLVE = 0xb - RTNLGRP_NONE = 0x0 - RTNLGRP_LINK = 0x1 - RTNLGRP_NOTIFY = 0x2 - RTNLGRP_NEIGH = 0x3 - RTNLGRP_TC = 0x4 - RTNLGRP_IPV4_IFADDR = 0x5 - RTNLGRP_IPV4_MROUTE = 0x6 - RTNLGRP_IPV4_ROUTE = 0x7 - RTNLGRP_IPV4_RULE = 0x8 - RTNLGRP_IPV6_IFADDR = 0x9 - RTNLGRP_IPV6_MROUTE = 0xa - RTNLGRP_IPV6_ROUTE = 0xb - RTNLGRP_IPV6_IFINFO = 0xc - RTNLGRP_IPV6_PREFIX = 0x12 - RTNLGRP_IPV6_RULE = 0x13 - RTNLGRP_ND_USEROPT = 0x14 - SizeofNlMsghdr = 0x10 - SizeofNlMsgerr = 0x14 - SizeofRtGenmsg = 0x1 - SizeofNlAttr = 0x4 - SizeofRtAttr = 0x4 - SizeofIfInfomsg = 0x10 - SizeofIfAddrmsg = 0x8 - SizeofRtMsg = 0xc - SizeofRtNexthop = 0x8 + IFA_UNSPEC = 0x0 + IFA_ADDRESS = 0x1 + IFA_LOCAL = 0x2 + IFA_LABEL = 0x3 + IFA_BROADCAST = 0x4 + IFA_ANYCAST = 0x5 + IFA_CACHEINFO = 0x6 + IFA_MULTICAST = 0x7 + IFLA_UNSPEC = 0x0 + IFLA_ADDRESS = 0x1 + IFLA_BROADCAST = 0x2 + IFLA_IFNAME = 0x3 + IFLA_INFO_KIND = 0x1 + IFLA_MTU = 0x4 + IFLA_LINK = 0x5 + IFLA_QDISC = 0x6 + IFLA_STATS = 0x7 + IFLA_COST = 0x8 + IFLA_PRIORITY = 0x9 + IFLA_MASTER = 0xa + IFLA_WIRELESS = 0xb + IFLA_PROTINFO = 0xc + IFLA_TXQLEN = 0xd + IFLA_MAP = 0xe + IFLA_WEIGHT = 0xf + IFLA_OPERSTATE = 0x10 + IFLA_LINKMODE = 0x11 + IFLA_LINKINFO = 0x12 + IFLA_NET_NS_PID = 0x13 + IFLA_IFALIAS = 0x14 + IFLA_NUM_VF = 0x15 + IFLA_VFINFO_LIST = 0x16 + IFLA_STATS64 = 0x17 + IFLA_VF_PORTS = 0x18 + IFLA_PORT_SELF = 0x19 + IFLA_AF_SPEC = 0x1a + IFLA_GROUP = 0x1b + IFLA_NET_NS_FD = 0x1c + IFLA_EXT_MASK = 0x1d + IFLA_PROMISCUITY = 0x1e + IFLA_NUM_TX_QUEUES = 0x1f + IFLA_NUM_RX_QUEUES = 0x20 + IFLA_CARRIER = 0x21 + IFLA_PHYS_PORT_ID = 0x22 + IFLA_CARRIER_CHANGES = 0x23 + IFLA_PHYS_SWITCH_ID = 0x24 + IFLA_LINK_NETNSID = 0x25 + IFLA_PHYS_PORT_NAME = 0x26 + IFLA_PROTO_DOWN = 0x27 + IFLA_GSO_MAX_SEGS = 0x28 + IFLA_GSO_MAX_SIZE = 0x29 + IFLA_PAD = 0x2a + IFLA_XDP = 0x2b + IFLA_EVENT = 0x2c + IFLA_NEW_NETNSID = 0x2d + IFLA_IF_NETNSID = 0x2e + IFLA_MAX = 0x33 + RT_SCOPE_UNIVERSE = 0x0 + RT_SCOPE_SITE = 0xc8 + RT_SCOPE_LINK = 0xfd + RT_SCOPE_HOST = 0xfe + RT_SCOPE_NOWHERE = 0xff + RT_TABLE_UNSPEC = 0x0 + RT_TABLE_COMPAT = 0xfc + RT_TABLE_DEFAULT = 0xfd + RT_TABLE_MAIN = 0xfe + RT_TABLE_LOCAL = 0xff + RT_TABLE_MAX = 0xffffffff + RTA_UNSPEC = 0x0 + RTA_DST = 0x1 + RTA_SRC = 0x2 + RTA_IIF = 0x3 + RTA_OIF = 0x4 + RTA_GATEWAY = 0x5 + RTA_PRIORITY = 0x6 + RTA_PREFSRC = 0x7 + RTA_METRICS = 0x8 + RTA_MULTIPATH = 0x9 + RTA_FLOW = 0xb + RTA_CACHEINFO = 0xc + RTA_TABLE = 0xf + RTA_MARK = 0x10 + RTA_MFC_STATS = 0x11 + RTA_VIA = 0x12 + RTA_NEWDST = 0x13 + RTA_PREF = 0x14 + RTA_ENCAP_TYPE = 0x15 + RTA_ENCAP = 0x16 + RTA_EXPIRES = 0x17 + RTA_PAD = 0x18 + RTA_UID = 0x19 + RTA_TTL_PROPAGATE = 0x1a + RTA_IP_PROTO = 0x1b + RTA_SPORT = 0x1c + RTA_DPORT = 0x1d + RTN_UNSPEC = 0x0 + RTN_UNICAST = 0x1 + RTN_LOCAL = 0x2 + RTN_BROADCAST = 0x3 + RTN_ANYCAST = 0x4 + RTN_MULTICAST = 0x5 + RTN_BLACKHOLE = 0x6 + RTN_UNREACHABLE = 0x7 + RTN_PROHIBIT = 0x8 + RTN_THROW = 0x9 + RTN_NAT = 0xa + RTN_XRESOLVE = 0xb + RTNLGRP_NONE = 0x0 + RTNLGRP_LINK = 0x1 + RTNLGRP_NOTIFY = 0x2 + RTNLGRP_NEIGH = 0x3 + RTNLGRP_TC = 0x4 + RTNLGRP_IPV4_IFADDR = 0x5 + RTNLGRP_IPV4_MROUTE = 0x6 + RTNLGRP_IPV4_ROUTE = 0x7 + RTNLGRP_IPV4_RULE = 0x8 + RTNLGRP_IPV6_IFADDR = 0x9 + RTNLGRP_IPV6_MROUTE = 0xa + RTNLGRP_IPV6_ROUTE = 0xb + RTNLGRP_IPV6_IFINFO = 0xc + RTNLGRP_IPV6_PREFIX = 0x12 + RTNLGRP_IPV6_RULE = 0x13 + RTNLGRP_ND_USEROPT = 0x14 + SizeofNlMsghdr = 0x10 + SizeofNlMsgerr = 0x14 + SizeofRtGenmsg = 0x1 + SizeofNlAttr = 0x4 + SizeofRtAttr = 0x4 + SizeofIfInfomsg = 0x10 + SizeofIfAddrmsg = 0x8 + SizeofRtMsg = 0xc + SizeofRtNexthop = 0x8 ) type NlMsghdr struct { @@ -523,12 +602,12 @@ type RtAttr struct { } type IfInfomsg struct { - Family uint8 - X__ifi_pad uint8 - Type uint16 - Index int32 - Flags uint32 - Change uint32 + Family uint8 + _ uint8 + Type uint16 + Index int32 + Flags uint32 + Change uint32 } type IfAddrmsg struct { @@ -571,9 +650,8 @@ type SockFilter struct { } type SockFprog struct { - Len uint16 - Pad_cgo_0 [6]byte - Filter *SockFilter + Len uint16 + Filter *SockFilter } type InotifyEvent struct { @@ -616,12 +694,11 @@ type Sysinfo_t struct { Freeswap uint64 Procs uint16 Pad uint16 - Pad_cgo_0 [4]byte Totalhigh uint64 Freehigh uint64 Unit uint32 - X_f [0]uint8 - Pad_cgo_1 [4]byte + _ [0]uint8 + _ [4]byte } type Utsname struct { @@ -634,26 +711,34 @@ type Utsname struct { } type Ustat_t struct { - Tfree int32 - Pad_cgo_0 [4]byte - Tinode uint64 - Fname [6]uint8 - Fpack [6]uint8 - Pad_cgo_1 [4]byte + Tfree int32 + Tinode uint64 + Fname [6]uint8 + Fpack [6]uint8 + _ [4]byte } type EpollEvent struct { - Events uint32 - X_padFd int32 - Fd int32 - Pad int32 + Events uint32 + _ int32 + Fd int32 + Pad int32 } const ( - AT_FDCWD = -0x64 - AT_REMOVEDIR = 0x200 + AT_EMPTY_PATH = 0x1000 + AT_FDCWD = -0x64 + AT_NO_AUTOMOUNT = 0x800 + AT_REMOVEDIR = 0x200 + + AT_STATX_SYNC_AS_STAT = 0x0 + AT_STATX_FORCE_SYNC = 0x2000 + AT_STATX_DONT_SYNC = 0x4000 + AT_SYMLINK_FOLLOW = 0x400 AT_SYMLINK_NOFOLLOW = 0x100 + + AT_EACCESS = 0x200 ) type PollFd struct { @@ -673,10 +758,33 @@ const ( ) type Sigset_t struct { - X__val [16]uint64 + Val [16]uint64 } -const RNDGETENTCNT = 0x40045200 +type SignalfdSiginfo struct { + Signo uint32 + Errno int32 + Code int32 + Pid uint32 + Uid uint32 + Fd int32 + Tid uint32 + Band uint32 + Overrun uint32 + Trapno uint32 + Status int32 + Int int32 + Ptr uint64 + Utime uint64 + Stime uint64 + Addr uint64 + Addr_lsb uint16 + _ uint16 + Syscall int32 + Call_addr uint64 + Arch uint32 + _ [28]uint8 +} const PERF_IOC_FLAG_GROUP = 0x1 @@ -700,11 +808,9 @@ type Winsize struct { type Taskstats struct { Version uint16 - Pad_cgo_0 [2]byte Ac_exitcode uint32 Ac_flag uint8 Ac_nice uint8 - Pad_cgo_1 [6]byte Cpu_count uint64 Cpu_delay_total uint64 Blkio_count uint64 @@ -716,13 +822,12 @@ type Taskstats struct { Ac_comm [32]uint8 Ac_sched uint8 Ac_pad [3]uint8 - Pad_cgo_2 [4]byte + _ [4]byte Ac_uid uint32 Ac_gid uint32 Ac_pid uint32 Ac_ppid uint32 Ac_btime uint32 - Pad_cgo_3 [4]byte Ac_etime uint64 Ac_utime uint64 Ac_stime uint64 @@ -746,6 +851,8 @@ type Taskstats struct { Cpu_scaled_run_real_total uint64 Freepages_count uint64 Freepages_delay_total uint64 + Thrashing_count uint64 + Thrashing_delay_total uint64 } const ( @@ -766,6 +873,24 @@ const ( TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK = 0x4 ) +type CGroupStats struct { + Sleeping uint64 + Running uint64 + Stopped uint64 + Uninterruptible uint64 + Io_wait uint64 +} + +const ( + CGROUPSTATS_CMD_UNSPEC = 0x3 + CGROUPSTATS_CMD_GET = 0x4 + CGROUPSTATS_CMD_NEW = 0x5 + CGROUPSTATS_TYPE_UNSPEC = 0x0 + CGROUPSTATS_TYPE_CGROUP_STATS = 0x1 + CGROUPSTATS_CMD_ATTR_UNSPEC = 0x0 + CGROUPSTATS_CMD_ATTR_FD = 0x1 +) + type Genlmsghdr struct { Cmd uint8 Version uint8 @@ -798,3 +923,1107 @@ const ( CTRL_ATTR_MCAST_GRP_NAME = 0x1 CTRL_ATTR_MCAST_GRP_ID = 0x2 ) + +type cpuMask uint64 + +const ( + _CPU_SETSIZE = 0x400 + _NCPUBITS = 0x40 +) + +const ( + BDADDR_BREDR = 0x0 + BDADDR_LE_PUBLIC = 0x1 + BDADDR_LE_RANDOM = 0x2 +) + +type PerfEventAttr struct { + Type uint32 + Size uint32 + Config uint64 + Sample uint64 + Sample_type uint64 + Read_format uint64 + Bits uint64 + Wakeup uint32 + Bp_type uint32 + Ext1 uint64 + Ext2 uint64 + Branch_sample_type uint64 + Sample_regs_user uint64 + Sample_stack_user uint32 + Clockid int32 + Sample_regs_intr uint64 + Aux_watermark uint32 + _ uint32 +} + +type PerfEventMmapPage struct { + Version uint32 + Compat_version uint32 + Lock uint32 + Index uint32 + Offset int64 + Time_enabled uint64 + Time_running uint64 + Capabilities uint64 + Pmc_width uint16 + Time_shift uint16 + Time_mult uint32 + Time_offset uint64 + Time_zero uint64 + Size uint32 + _ [948]uint8 + Data_head uint64 + Data_tail uint64 + Data_offset uint64 + Data_size uint64 + Aux_head uint64 + Aux_tail uint64 + Aux_offset uint64 + Aux_size uint64 +} + +const ( + PerfBitDisabled uint64 = CBitFieldMaskBit0 + PerfBitInherit = CBitFieldMaskBit1 + PerfBitPinned = CBitFieldMaskBit2 + PerfBitExclusive = CBitFieldMaskBit3 + PerfBitExcludeUser = CBitFieldMaskBit4 + PerfBitExcludeKernel = CBitFieldMaskBit5 + PerfBitExcludeHv = CBitFieldMaskBit6 + PerfBitExcludeIdle = CBitFieldMaskBit7 + PerfBitMmap = CBitFieldMaskBit8 + PerfBitComm = CBitFieldMaskBit9 + PerfBitFreq = CBitFieldMaskBit10 + PerfBitInheritStat = CBitFieldMaskBit11 + PerfBitEnableOnExec = CBitFieldMaskBit12 + PerfBitTask = CBitFieldMaskBit13 + PerfBitWatermark = CBitFieldMaskBit14 + PerfBitPreciseIPBit1 = CBitFieldMaskBit15 + PerfBitPreciseIPBit2 = CBitFieldMaskBit16 + PerfBitMmapData = CBitFieldMaskBit17 + PerfBitSampleIDAll = CBitFieldMaskBit18 + PerfBitExcludeHost = CBitFieldMaskBit19 + PerfBitExcludeGuest = CBitFieldMaskBit20 + PerfBitExcludeCallchainKernel = CBitFieldMaskBit21 + PerfBitExcludeCallchainUser = CBitFieldMaskBit22 + PerfBitMmap2 = CBitFieldMaskBit23 + PerfBitCommExec = CBitFieldMaskBit24 + PerfBitUseClockID = CBitFieldMaskBit25 + PerfBitContextSwitch = CBitFieldMaskBit26 +) + +const ( + PERF_TYPE_HARDWARE = 0x0 + PERF_TYPE_SOFTWARE = 0x1 + PERF_TYPE_TRACEPOINT = 0x2 + PERF_TYPE_HW_CACHE = 0x3 + PERF_TYPE_RAW = 0x4 + PERF_TYPE_BREAKPOINT = 0x5 + + PERF_COUNT_HW_CPU_CYCLES = 0x0 + PERF_COUNT_HW_INSTRUCTIONS = 0x1 + PERF_COUNT_HW_CACHE_REFERENCES = 0x2 + PERF_COUNT_HW_CACHE_MISSES = 0x3 + PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 0x4 + PERF_COUNT_HW_BRANCH_MISSES = 0x5 + PERF_COUNT_HW_BUS_CYCLES = 0x6 + PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 0x7 + PERF_COUNT_HW_STALLED_CYCLES_BACKEND = 0x8 + PERF_COUNT_HW_REF_CPU_CYCLES = 0x9 + + PERF_COUNT_HW_CACHE_L1D = 0x0 + PERF_COUNT_HW_CACHE_L1I = 0x1 + PERF_COUNT_HW_CACHE_LL = 0x2 + PERF_COUNT_HW_CACHE_DTLB = 0x3 + PERF_COUNT_HW_CACHE_ITLB = 0x4 + PERF_COUNT_HW_CACHE_BPU = 0x5 + PERF_COUNT_HW_CACHE_NODE = 0x6 + + PERF_COUNT_HW_CACHE_OP_READ = 0x0 + PERF_COUNT_HW_CACHE_OP_WRITE = 0x1 + PERF_COUNT_HW_CACHE_OP_PREFETCH = 0x2 + + PERF_COUNT_HW_CACHE_RESULT_ACCESS = 0x0 + PERF_COUNT_HW_CACHE_RESULT_MISS = 0x1 + + PERF_COUNT_SW_CPU_CLOCK = 0x0 + PERF_COUNT_SW_TASK_CLOCK = 0x1 + PERF_COUNT_SW_PAGE_FAULTS = 0x2 + PERF_COUNT_SW_CONTEXT_SWITCHES = 0x3 + PERF_COUNT_SW_CPU_MIGRATIONS = 0x4 + PERF_COUNT_SW_PAGE_FAULTS_MIN = 0x5 + PERF_COUNT_SW_PAGE_FAULTS_MAJ = 0x6 + PERF_COUNT_SW_ALIGNMENT_FAULTS = 0x7 + PERF_COUNT_SW_EMULATION_FAULTS = 0x8 + PERF_COUNT_SW_DUMMY = 0x9 + + PERF_SAMPLE_IP = 0x1 + PERF_SAMPLE_TID = 0x2 + PERF_SAMPLE_TIME = 0x4 + PERF_SAMPLE_ADDR = 0x8 + PERF_SAMPLE_READ = 0x10 + PERF_SAMPLE_CALLCHAIN = 0x20 + PERF_SAMPLE_ID = 0x40 + PERF_SAMPLE_CPU = 0x80 + PERF_SAMPLE_PERIOD = 0x100 + PERF_SAMPLE_STREAM_ID = 0x200 + PERF_SAMPLE_RAW = 0x400 + PERF_SAMPLE_BRANCH_STACK = 0x800 + + PERF_SAMPLE_BRANCH_USER = 0x1 + PERF_SAMPLE_BRANCH_KERNEL = 0x2 + PERF_SAMPLE_BRANCH_HV = 0x4 + PERF_SAMPLE_BRANCH_ANY = 0x8 + PERF_SAMPLE_BRANCH_ANY_CALL = 0x10 + PERF_SAMPLE_BRANCH_ANY_RETURN = 0x20 + PERF_SAMPLE_BRANCH_IND_CALL = 0x40 + + PERF_FORMAT_TOTAL_TIME_ENABLED = 0x1 + PERF_FORMAT_TOTAL_TIME_RUNNING = 0x2 + PERF_FORMAT_ID = 0x4 + PERF_FORMAT_GROUP = 0x8 + + PERF_RECORD_MMAP = 0x1 + PERF_RECORD_LOST = 0x2 + PERF_RECORD_COMM = 0x3 + PERF_RECORD_EXIT = 0x4 + PERF_RECORD_THROTTLE = 0x5 + PERF_RECORD_UNTHROTTLE = 0x6 + PERF_RECORD_FORK = 0x7 + PERF_RECORD_READ = 0x8 + PERF_RECORD_SAMPLE = 0x9 + + PERF_CONTEXT_HV = -0x20 + PERF_CONTEXT_KERNEL = -0x80 + PERF_CONTEXT_USER = -0x200 + + PERF_CONTEXT_GUEST = -0x800 + PERF_CONTEXT_GUEST_KERNEL = -0x880 + PERF_CONTEXT_GUEST_USER = -0xa00 + + PERF_FLAG_FD_NO_GROUP = 0x1 + PERF_FLAG_FD_OUTPUT = 0x2 + PERF_FLAG_PID_CGROUP = 0x4 +) + +const ( + CBitFieldMaskBit0 = 0x8000000000000000 + CBitFieldMaskBit1 = 0x4000000000000000 + CBitFieldMaskBit2 = 0x2000000000000000 + CBitFieldMaskBit3 = 0x1000000000000000 + CBitFieldMaskBit4 = 0x800000000000000 + CBitFieldMaskBit5 = 0x400000000000000 + CBitFieldMaskBit6 = 0x200000000000000 + CBitFieldMaskBit7 = 0x100000000000000 + CBitFieldMaskBit8 = 0x80000000000000 + CBitFieldMaskBit9 = 0x40000000000000 + CBitFieldMaskBit10 = 0x20000000000000 + CBitFieldMaskBit11 = 0x10000000000000 + CBitFieldMaskBit12 = 0x8000000000000 + CBitFieldMaskBit13 = 0x4000000000000 + CBitFieldMaskBit14 = 0x2000000000000 + CBitFieldMaskBit15 = 0x1000000000000 + CBitFieldMaskBit16 = 0x800000000000 + CBitFieldMaskBit17 = 0x400000000000 + CBitFieldMaskBit18 = 0x200000000000 + CBitFieldMaskBit19 = 0x100000000000 + CBitFieldMaskBit20 = 0x80000000000 + CBitFieldMaskBit21 = 0x40000000000 + CBitFieldMaskBit22 = 0x20000000000 + CBitFieldMaskBit23 = 0x10000000000 + CBitFieldMaskBit24 = 0x8000000000 + CBitFieldMaskBit25 = 0x4000000000 + CBitFieldMaskBit26 = 0x2000000000 + CBitFieldMaskBit27 = 0x1000000000 + CBitFieldMaskBit28 = 0x800000000 + CBitFieldMaskBit29 = 0x400000000 + CBitFieldMaskBit30 = 0x200000000 + CBitFieldMaskBit31 = 0x100000000 + CBitFieldMaskBit32 = 0x80000000 + CBitFieldMaskBit33 = 0x40000000 + CBitFieldMaskBit34 = 0x20000000 + CBitFieldMaskBit35 = 0x10000000 + CBitFieldMaskBit36 = 0x8000000 + CBitFieldMaskBit37 = 0x4000000 + CBitFieldMaskBit38 = 0x2000000 + CBitFieldMaskBit39 = 0x1000000 + CBitFieldMaskBit40 = 0x800000 + CBitFieldMaskBit41 = 0x400000 + CBitFieldMaskBit42 = 0x200000 + CBitFieldMaskBit43 = 0x100000 + CBitFieldMaskBit44 = 0x80000 + CBitFieldMaskBit45 = 0x40000 + CBitFieldMaskBit46 = 0x20000 + CBitFieldMaskBit47 = 0x10000 + CBitFieldMaskBit48 = 0x8000 + CBitFieldMaskBit49 = 0x4000 + CBitFieldMaskBit50 = 0x2000 + CBitFieldMaskBit51 = 0x1000 + CBitFieldMaskBit52 = 0x800 + CBitFieldMaskBit53 = 0x400 + CBitFieldMaskBit54 = 0x200 + CBitFieldMaskBit55 = 0x100 + CBitFieldMaskBit56 = 0x80 + CBitFieldMaskBit57 = 0x40 + CBitFieldMaskBit58 = 0x20 + CBitFieldMaskBit59 = 0x10 + CBitFieldMaskBit60 = 0x8 + CBitFieldMaskBit61 = 0x4 + CBitFieldMaskBit62 = 0x2 + CBitFieldMaskBit63 = 0x1 +) + +type SockaddrStorage struct { + Family uint16 + _ [118]uint8 + _ uint64 +} + +type TCPMD5Sig struct { + Addr SockaddrStorage + Flags uint8 + Prefixlen uint8 + Keylen uint16 + _ uint32 + Key [80]uint8 +} + +type HDDriveCmdHdr struct { + Command uint8 + Number uint8 + Feature uint8 + Count uint8 +} + +type HDGeometry struct { + Heads uint8 + Sectors uint8 + Cylinders uint16 + Start uint64 +} + +type HDDriveID struct { + Config uint16 + Cyls uint16 + Reserved2 uint16 + Heads uint16 + Track_bytes uint16 + Sector_bytes uint16 + Sectors uint16 + Vendor0 uint16 + Vendor1 uint16 + Vendor2 uint16 + Serial_no [20]uint8 + Buf_type uint16 + Buf_size uint16 + Ecc_bytes uint16 + Fw_rev [8]uint8 + Model [40]uint8 + Max_multsect uint8 + Vendor3 uint8 + Dword_io uint16 + Vendor4 uint8 + Capability uint8 + Reserved50 uint16 + Vendor5 uint8 + TPIO uint8 + Vendor6 uint8 + TDMA uint8 + Field_valid uint16 + Cur_cyls uint16 + Cur_heads uint16 + Cur_sectors uint16 + Cur_capacity0 uint16 + Cur_capacity1 uint16 + Multsect uint8 + Multsect_valid uint8 + Lba_capacity uint32 + Dma_1word uint16 + Dma_mword uint16 + Eide_pio_modes uint16 + Eide_dma_min uint16 + Eide_dma_time uint16 + Eide_pio uint16 + Eide_pio_iordy uint16 + Words69_70 [2]uint16 + Words71_74 [4]uint16 + Queue_depth uint16 + Words76_79 [4]uint16 + Major_rev_num uint16 + Minor_rev_num uint16 + Command_set_1 uint16 + Command_set_2 uint16 + Cfsse uint16 + Cfs_enable_1 uint16 + Cfs_enable_2 uint16 + Csf_default uint16 + Dma_ultra uint16 + Trseuc uint16 + TrsEuc uint16 + CurAPMvalues uint16 + Mprc uint16 + Hw_config uint16 + Acoustic uint16 + Msrqs uint16 + Sxfert uint16 + Sal uint16 + Spg uint32 + Lba_capacity_2 uint64 + Words104_125 [22]uint16 + Last_lun uint16 + Word127 uint16 + Dlf uint16 + Csfo uint16 + Words130_155 [26]uint16 + Word156 uint16 + Words157_159 [3]uint16 + Cfa_power uint16 + Words161_175 [15]uint16 + Words176_205 [30]uint16 + Words206_254 [49]uint16 + Integrity_word uint16 +} + +type Statfs_t struct { + Type int64 + Bsize int64 + Blocks uint64 + Bfree uint64 + Bavail uint64 + Files uint64 + Ffree uint64 + Fsid Fsid + Namelen int64 + Frsize int64 + Flags int64 + Spare [4]int64 +} + +const ( + ST_MANDLOCK = 0x40 + ST_NOATIME = 0x400 + ST_NODEV = 0x4 + ST_NODIRATIME = 0x800 + ST_NOEXEC = 0x8 + ST_NOSUID = 0x2 + ST_RDONLY = 0x1 + ST_RELATIME = 0x1000 + ST_SYNCHRONOUS = 0x10 +) + +type TpacketHdr struct { + Status uint64 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Sec uint32 + Usec uint32 + _ [4]byte +} + +type Tpacket2Hdr struct { + Status uint32 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Sec uint32 + Nsec uint32 + Vlan_tci uint16 + Vlan_tpid uint16 + _ [4]uint8 +} + +type Tpacket3Hdr struct { + Next_offset uint32 + Sec uint32 + Nsec uint32 + Snaplen uint32 + Len uint32 + Status uint32 + Mac uint16 + Net uint16 + Hv1 TpacketHdrVariant1 + _ [8]uint8 +} + +type TpacketHdrVariant1 struct { + Rxhash uint32 + Vlan_tci uint32 + Vlan_tpid uint16 + _ uint16 +} + +type TpacketBlockDesc struct { + Version uint32 + To_priv uint32 + Hdr [40]byte +} + +type TpacketReq struct { + Block_size uint32 + Block_nr uint32 + Frame_size uint32 + Frame_nr uint32 +} + +type TpacketReq3 struct { + Block_size uint32 + Block_nr uint32 + Frame_size uint32 + Frame_nr uint32 + Retire_blk_tov uint32 + Sizeof_priv uint32 + Feature_req_word uint32 +} + +type TpacketStats struct { + Packets uint32 + Drops uint32 +} + +type TpacketStatsV3 struct { + Packets uint32 + Drops uint32 + Freeze_q_cnt uint32 +} + +type TpacketAuxdata struct { + Status uint32 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Vlan_tci uint16 + Vlan_tpid uint16 +} + +const ( + TPACKET_V1 = 0x0 + TPACKET_V2 = 0x1 + TPACKET_V3 = 0x2 +) + +const ( + SizeofTpacketHdr = 0x20 + SizeofTpacket2Hdr = 0x20 + SizeofTpacket3Hdr = 0x30 +) + +const ( + NF_INET_PRE_ROUTING = 0x0 + NF_INET_LOCAL_IN = 0x1 + NF_INET_FORWARD = 0x2 + NF_INET_LOCAL_OUT = 0x3 + NF_INET_POST_ROUTING = 0x4 + NF_INET_NUMHOOKS = 0x5 +) + +const ( + NF_NETDEV_INGRESS = 0x0 + NF_NETDEV_NUMHOOKS = 0x1 +) + +const ( + NFPROTO_UNSPEC = 0x0 + NFPROTO_INET = 0x1 + NFPROTO_IPV4 = 0x2 + NFPROTO_ARP = 0x3 + NFPROTO_NETDEV = 0x5 + NFPROTO_BRIDGE = 0x7 + NFPROTO_IPV6 = 0xa + NFPROTO_DECNET = 0xc + NFPROTO_NUMPROTO = 0xd +) + +type Nfgenmsg struct { + Nfgen_family uint8 + Version uint8 + Res_id uint16 +} + +const ( + NFNL_BATCH_UNSPEC = 0x0 + NFNL_BATCH_GENID = 0x1 +) + +const ( + NFT_REG_VERDICT = 0x0 + NFT_REG_1 = 0x1 + NFT_REG_2 = 0x2 + NFT_REG_3 = 0x3 + NFT_REG_4 = 0x4 + NFT_REG32_00 = 0x8 + NFT_REG32_01 = 0x9 + NFT_REG32_02 = 0xa + NFT_REG32_03 = 0xb + NFT_REG32_04 = 0xc + NFT_REG32_05 = 0xd + NFT_REG32_06 = 0xe + NFT_REG32_07 = 0xf + NFT_REG32_08 = 0x10 + NFT_REG32_09 = 0x11 + NFT_REG32_10 = 0x12 + NFT_REG32_11 = 0x13 + NFT_REG32_12 = 0x14 + NFT_REG32_13 = 0x15 + NFT_REG32_14 = 0x16 + NFT_REG32_15 = 0x17 + NFT_CONTINUE = -0x1 + NFT_BREAK = -0x2 + NFT_JUMP = -0x3 + NFT_GOTO = -0x4 + NFT_RETURN = -0x5 + NFT_MSG_NEWTABLE = 0x0 + NFT_MSG_GETTABLE = 0x1 + NFT_MSG_DELTABLE = 0x2 + NFT_MSG_NEWCHAIN = 0x3 + NFT_MSG_GETCHAIN = 0x4 + NFT_MSG_DELCHAIN = 0x5 + NFT_MSG_NEWRULE = 0x6 + NFT_MSG_GETRULE = 0x7 + NFT_MSG_DELRULE = 0x8 + NFT_MSG_NEWSET = 0x9 + NFT_MSG_GETSET = 0xa + NFT_MSG_DELSET = 0xb + NFT_MSG_NEWSETELEM = 0xc + NFT_MSG_GETSETELEM = 0xd + NFT_MSG_DELSETELEM = 0xe + NFT_MSG_NEWGEN = 0xf + NFT_MSG_GETGEN = 0x10 + NFT_MSG_TRACE = 0x11 + NFT_MSG_NEWOBJ = 0x12 + NFT_MSG_GETOBJ = 0x13 + NFT_MSG_DELOBJ = 0x14 + NFT_MSG_GETOBJ_RESET = 0x15 + NFT_MSG_MAX = 0x19 + NFTA_LIST_UNPEC = 0x0 + NFTA_LIST_ELEM = 0x1 + NFTA_HOOK_UNSPEC = 0x0 + NFTA_HOOK_HOOKNUM = 0x1 + NFTA_HOOK_PRIORITY = 0x2 + NFTA_HOOK_DEV = 0x3 + NFT_TABLE_F_DORMANT = 0x1 + NFTA_TABLE_UNSPEC = 0x0 + NFTA_TABLE_NAME = 0x1 + NFTA_TABLE_FLAGS = 0x2 + NFTA_TABLE_USE = 0x3 + NFTA_CHAIN_UNSPEC = 0x0 + NFTA_CHAIN_TABLE = 0x1 + NFTA_CHAIN_HANDLE = 0x2 + NFTA_CHAIN_NAME = 0x3 + NFTA_CHAIN_HOOK = 0x4 + NFTA_CHAIN_POLICY = 0x5 + NFTA_CHAIN_USE = 0x6 + NFTA_CHAIN_TYPE = 0x7 + NFTA_CHAIN_COUNTERS = 0x8 + NFTA_CHAIN_PAD = 0x9 + NFTA_RULE_UNSPEC = 0x0 + NFTA_RULE_TABLE = 0x1 + NFTA_RULE_CHAIN = 0x2 + NFTA_RULE_HANDLE = 0x3 + NFTA_RULE_EXPRESSIONS = 0x4 + NFTA_RULE_COMPAT = 0x5 + NFTA_RULE_POSITION = 0x6 + NFTA_RULE_USERDATA = 0x7 + NFTA_RULE_PAD = 0x8 + NFTA_RULE_ID = 0x9 + NFT_RULE_COMPAT_F_INV = 0x2 + NFT_RULE_COMPAT_F_MASK = 0x2 + NFTA_RULE_COMPAT_UNSPEC = 0x0 + NFTA_RULE_COMPAT_PROTO = 0x1 + NFTA_RULE_COMPAT_FLAGS = 0x2 + NFT_SET_ANONYMOUS = 0x1 + NFT_SET_CONSTANT = 0x2 + NFT_SET_INTERVAL = 0x4 + NFT_SET_MAP = 0x8 + NFT_SET_TIMEOUT = 0x10 + NFT_SET_EVAL = 0x20 + NFT_SET_OBJECT = 0x40 + NFT_SET_POL_PERFORMANCE = 0x0 + NFT_SET_POL_MEMORY = 0x1 + NFTA_SET_DESC_UNSPEC = 0x0 + NFTA_SET_DESC_SIZE = 0x1 + NFTA_SET_UNSPEC = 0x0 + NFTA_SET_TABLE = 0x1 + NFTA_SET_NAME = 0x2 + NFTA_SET_FLAGS = 0x3 + NFTA_SET_KEY_TYPE = 0x4 + NFTA_SET_KEY_LEN = 0x5 + NFTA_SET_DATA_TYPE = 0x6 + NFTA_SET_DATA_LEN = 0x7 + NFTA_SET_POLICY = 0x8 + NFTA_SET_DESC = 0x9 + NFTA_SET_ID = 0xa + NFTA_SET_TIMEOUT = 0xb + NFTA_SET_GC_INTERVAL = 0xc + NFTA_SET_USERDATA = 0xd + NFTA_SET_PAD = 0xe + NFTA_SET_OBJ_TYPE = 0xf + NFT_SET_ELEM_INTERVAL_END = 0x1 + NFTA_SET_ELEM_UNSPEC = 0x0 + NFTA_SET_ELEM_KEY = 0x1 + NFTA_SET_ELEM_DATA = 0x2 + NFTA_SET_ELEM_FLAGS = 0x3 + NFTA_SET_ELEM_TIMEOUT = 0x4 + NFTA_SET_ELEM_EXPIRATION = 0x5 + NFTA_SET_ELEM_USERDATA = 0x6 + NFTA_SET_ELEM_EXPR = 0x7 + NFTA_SET_ELEM_PAD = 0x8 + NFTA_SET_ELEM_OBJREF = 0x9 + NFTA_SET_ELEM_LIST_UNSPEC = 0x0 + NFTA_SET_ELEM_LIST_TABLE = 0x1 + NFTA_SET_ELEM_LIST_SET = 0x2 + NFTA_SET_ELEM_LIST_ELEMENTS = 0x3 + NFTA_SET_ELEM_LIST_SET_ID = 0x4 + NFT_DATA_VALUE = 0x0 + NFT_DATA_VERDICT = 0xffffff00 + NFTA_DATA_UNSPEC = 0x0 + NFTA_DATA_VALUE = 0x1 + NFTA_DATA_VERDICT = 0x2 + NFTA_VERDICT_UNSPEC = 0x0 + NFTA_VERDICT_CODE = 0x1 + NFTA_VERDICT_CHAIN = 0x2 + NFTA_EXPR_UNSPEC = 0x0 + NFTA_EXPR_NAME = 0x1 + NFTA_EXPR_DATA = 0x2 + NFTA_IMMEDIATE_UNSPEC = 0x0 + NFTA_IMMEDIATE_DREG = 0x1 + NFTA_IMMEDIATE_DATA = 0x2 + NFTA_BITWISE_UNSPEC = 0x0 + NFTA_BITWISE_SREG = 0x1 + NFTA_BITWISE_DREG = 0x2 + NFTA_BITWISE_LEN = 0x3 + NFTA_BITWISE_MASK = 0x4 + NFTA_BITWISE_XOR = 0x5 + NFT_BYTEORDER_NTOH = 0x0 + NFT_BYTEORDER_HTON = 0x1 + NFTA_BYTEORDER_UNSPEC = 0x0 + NFTA_BYTEORDER_SREG = 0x1 + NFTA_BYTEORDER_DREG = 0x2 + NFTA_BYTEORDER_OP = 0x3 + NFTA_BYTEORDER_LEN = 0x4 + NFTA_BYTEORDER_SIZE = 0x5 + NFT_CMP_EQ = 0x0 + NFT_CMP_NEQ = 0x1 + NFT_CMP_LT = 0x2 + NFT_CMP_LTE = 0x3 + NFT_CMP_GT = 0x4 + NFT_CMP_GTE = 0x5 + NFTA_CMP_UNSPEC = 0x0 + NFTA_CMP_SREG = 0x1 + NFTA_CMP_OP = 0x2 + NFTA_CMP_DATA = 0x3 + NFT_RANGE_EQ = 0x0 + NFT_RANGE_NEQ = 0x1 + NFTA_RANGE_UNSPEC = 0x0 + NFTA_RANGE_SREG = 0x1 + NFTA_RANGE_OP = 0x2 + NFTA_RANGE_FROM_DATA = 0x3 + NFTA_RANGE_TO_DATA = 0x4 + NFT_LOOKUP_F_INV = 0x1 + NFTA_LOOKUP_UNSPEC = 0x0 + NFTA_LOOKUP_SET = 0x1 + NFTA_LOOKUP_SREG = 0x2 + NFTA_LOOKUP_DREG = 0x3 + NFTA_LOOKUP_SET_ID = 0x4 + NFTA_LOOKUP_FLAGS = 0x5 + NFT_DYNSET_OP_ADD = 0x0 + NFT_DYNSET_OP_UPDATE = 0x1 + NFT_DYNSET_F_INV = 0x1 + NFTA_DYNSET_UNSPEC = 0x0 + NFTA_DYNSET_SET_NAME = 0x1 + NFTA_DYNSET_SET_ID = 0x2 + NFTA_DYNSET_OP = 0x3 + NFTA_DYNSET_SREG_KEY = 0x4 + NFTA_DYNSET_SREG_DATA = 0x5 + NFTA_DYNSET_TIMEOUT = 0x6 + NFTA_DYNSET_EXPR = 0x7 + NFTA_DYNSET_PAD = 0x8 + NFTA_DYNSET_FLAGS = 0x9 + NFT_PAYLOAD_LL_HEADER = 0x0 + NFT_PAYLOAD_NETWORK_HEADER = 0x1 + NFT_PAYLOAD_TRANSPORT_HEADER = 0x2 + NFT_PAYLOAD_CSUM_NONE = 0x0 + NFT_PAYLOAD_CSUM_INET = 0x1 + NFT_PAYLOAD_L4CSUM_PSEUDOHDR = 0x1 + NFTA_PAYLOAD_UNSPEC = 0x0 + NFTA_PAYLOAD_DREG = 0x1 + NFTA_PAYLOAD_BASE = 0x2 + NFTA_PAYLOAD_OFFSET = 0x3 + NFTA_PAYLOAD_LEN = 0x4 + NFTA_PAYLOAD_SREG = 0x5 + NFTA_PAYLOAD_CSUM_TYPE = 0x6 + NFTA_PAYLOAD_CSUM_OFFSET = 0x7 + NFTA_PAYLOAD_CSUM_FLAGS = 0x8 + NFT_EXTHDR_F_PRESENT = 0x1 + NFT_EXTHDR_OP_IPV6 = 0x0 + NFT_EXTHDR_OP_TCPOPT = 0x1 + NFTA_EXTHDR_UNSPEC = 0x0 + NFTA_EXTHDR_DREG = 0x1 + NFTA_EXTHDR_TYPE = 0x2 + NFTA_EXTHDR_OFFSET = 0x3 + NFTA_EXTHDR_LEN = 0x4 + NFTA_EXTHDR_FLAGS = 0x5 + NFTA_EXTHDR_OP = 0x6 + NFTA_EXTHDR_SREG = 0x7 + NFT_META_LEN = 0x0 + NFT_META_PROTOCOL = 0x1 + NFT_META_PRIORITY = 0x2 + NFT_META_MARK = 0x3 + NFT_META_IIF = 0x4 + NFT_META_OIF = 0x5 + NFT_META_IIFNAME = 0x6 + NFT_META_OIFNAME = 0x7 + NFT_META_IIFTYPE = 0x8 + NFT_META_OIFTYPE = 0x9 + NFT_META_SKUID = 0xa + NFT_META_SKGID = 0xb + NFT_META_NFTRACE = 0xc + NFT_META_RTCLASSID = 0xd + NFT_META_SECMARK = 0xe + NFT_META_NFPROTO = 0xf + NFT_META_L4PROTO = 0x10 + NFT_META_BRI_IIFNAME = 0x11 + NFT_META_BRI_OIFNAME = 0x12 + NFT_META_PKTTYPE = 0x13 + NFT_META_CPU = 0x14 + NFT_META_IIFGROUP = 0x15 + NFT_META_OIFGROUP = 0x16 + NFT_META_CGROUP = 0x17 + NFT_META_PRANDOM = 0x18 + NFT_RT_CLASSID = 0x0 + NFT_RT_NEXTHOP4 = 0x1 + NFT_RT_NEXTHOP6 = 0x2 + NFT_RT_TCPMSS = 0x3 + NFT_HASH_JENKINS = 0x0 + NFT_HASH_SYM = 0x1 + NFTA_HASH_UNSPEC = 0x0 + NFTA_HASH_SREG = 0x1 + NFTA_HASH_DREG = 0x2 + NFTA_HASH_LEN = 0x3 + NFTA_HASH_MODULUS = 0x4 + NFTA_HASH_SEED = 0x5 + NFTA_HASH_OFFSET = 0x6 + NFTA_HASH_TYPE = 0x7 + NFTA_META_UNSPEC = 0x0 + NFTA_META_DREG = 0x1 + NFTA_META_KEY = 0x2 + NFTA_META_SREG = 0x3 + NFTA_RT_UNSPEC = 0x0 + NFTA_RT_DREG = 0x1 + NFTA_RT_KEY = 0x2 + NFT_CT_STATE = 0x0 + NFT_CT_DIRECTION = 0x1 + NFT_CT_STATUS = 0x2 + NFT_CT_MARK = 0x3 + NFT_CT_SECMARK = 0x4 + NFT_CT_EXPIRATION = 0x5 + NFT_CT_HELPER = 0x6 + NFT_CT_L3PROTOCOL = 0x7 + NFT_CT_SRC = 0x8 + NFT_CT_DST = 0x9 + NFT_CT_PROTOCOL = 0xa + NFT_CT_PROTO_SRC = 0xb + NFT_CT_PROTO_DST = 0xc + NFT_CT_LABELS = 0xd + NFT_CT_PKTS = 0xe + NFT_CT_BYTES = 0xf + NFT_CT_AVGPKT = 0x10 + NFT_CT_ZONE = 0x11 + NFT_CT_EVENTMASK = 0x12 + NFTA_CT_UNSPEC = 0x0 + NFTA_CT_DREG = 0x1 + NFTA_CT_KEY = 0x2 + NFTA_CT_DIRECTION = 0x3 + NFTA_CT_SREG = 0x4 + NFT_LIMIT_PKTS = 0x0 + NFT_LIMIT_PKT_BYTES = 0x1 + NFT_LIMIT_F_INV = 0x1 + NFTA_LIMIT_UNSPEC = 0x0 + NFTA_LIMIT_RATE = 0x1 + NFTA_LIMIT_UNIT = 0x2 + NFTA_LIMIT_BURST = 0x3 + NFTA_LIMIT_TYPE = 0x4 + NFTA_LIMIT_FLAGS = 0x5 + NFTA_LIMIT_PAD = 0x6 + NFTA_COUNTER_UNSPEC = 0x0 + NFTA_COUNTER_BYTES = 0x1 + NFTA_COUNTER_PACKETS = 0x2 + NFTA_COUNTER_PAD = 0x3 + NFTA_LOG_UNSPEC = 0x0 + NFTA_LOG_GROUP = 0x1 + NFTA_LOG_PREFIX = 0x2 + NFTA_LOG_SNAPLEN = 0x3 + NFTA_LOG_QTHRESHOLD = 0x4 + NFTA_LOG_LEVEL = 0x5 + NFTA_LOG_FLAGS = 0x6 + NFTA_QUEUE_UNSPEC = 0x0 + NFTA_QUEUE_NUM = 0x1 + NFTA_QUEUE_TOTAL = 0x2 + NFTA_QUEUE_FLAGS = 0x3 + NFTA_QUEUE_SREG_QNUM = 0x4 + NFT_QUOTA_F_INV = 0x1 + NFT_QUOTA_F_DEPLETED = 0x2 + NFTA_QUOTA_UNSPEC = 0x0 + NFTA_QUOTA_BYTES = 0x1 + NFTA_QUOTA_FLAGS = 0x2 + NFTA_QUOTA_PAD = 0x3 + NFTA_QUOTA_CONSUMED = 0x4 + NFT_REJECT_ICMP_UNREACH = 0x0 + NFT_REJECT_TCP_RST = 0x1 + NFT_REJECT_ICMPX_UNREACH = 0x2 + NFT_REJECT_ICMPX_NO_ROUTE = 0x0 + NFT_REJECT_ICMPX_PORT_UNREACH = 0x1 + NFT_REJECT_ICMPX_HOST_UNREACH = 0x2 + NFT_REJECT_ICMPX_ADMIN_PROHIBITED = 0x3 + NFTA_REJECT_UNSPEC = 0x0 + NFTA_REJECT_TYPE = 0x1 + NFTA_REJECT_ICMP_CODE = 0x2 + NFT_NAT_SNAT = 0x0 + NFT_NAT_DNAT = 0x1 + NFTA_NAT_UNSPEC = 0x0 + NFTA_NAT_TYPE = 0x1 + NFTA_NAT_FAMILY = 0x2 + NFTA_NAT_REG_ADDR_MIN = 0x3 + NFTA_NAT_REG_ADDR_MAX = 0x4 + NFTA_NAT_REG_PROTO_MIN = 0x5 + NFTA_NAT_REG_PROTO_MAX = 0x6 + NFTA_NAT_FLAGS = 0x7 + NFTA_MASQ_UNSPEC = 0x0 + NFTA_MASQ_FLAGS = 0x1 + NFTA_MASQ_REG_PROTO_MIN = 0x2 + NFTA_MASQ_REG_PROTO_MAX = 0x3 + NFTA_REDIR_UNSPEC = 0x0 + NFTA_REDIR_REG_PROTO_MIN = 0x1 + NFTA_REDIR_REG_PROTO_MAX = 0x2 + NFTA_REDIR_FLAGS = 0x3 + NFTA_DUP_UNSPEC = 0x0 + NFTA_DUP_SREG_ADDR = 0x1 + NFTA_DUP_SREG_DEV = 0x2 + NFTA_FWD_UNSPEC = 0x0 + NFTA_FWD_SREG_DEV = 0x1 + NFTA_OBJREF_UNSPEC = 0x0 + NFTA_OBJREF_IMM_TYPE = 0x1 + NFTA_OBJREF_IMM_NAME = 0x2 + NFTA_OBJREF_SET_SREG = 0x3 + NFTA_OBJREF_SET_NAME = 0x4 + NFTA_OBJREF_SET_ID = 0x5 + NFTA_GEN_UNSPEC = 0x0 + NFTA_GEN_ID = 0x1 + NFTA_GEN_PROC_PID = 0x2 + NFTA_GEN_PROC_NAME = 0x3 + NFTA_FIB_UNSPEC = 0x0 + NFTA_FIB_DREG = 0x1 + NFTA_FIB_RESULT = 0x2 + NFTA_FIB_FLAGS = 0x3 + NFT_FIB_RESULT_UNSPEC = 0x0 + NFT_FIB_RESULT_OIF = 0x1 + NFT_FIB_RESULT_OIFNAME = 0x2 + NFT_FIB_RESULT_ADDRTYPE = 0x3 + NFTA_FIB_F_SADDR = 0x1 + NFTA_FIB_F_DADDR = 0x2 + NFTA_FIB_F_MARK = 0x4 + NFTA_FIB_F_IIF = 0x8 + NFTA_FIB_F_OIF = 0x10 + NFTA_FIB_F_PRESENT = 0x20 + NFTA_CT_HELPER_UNSPEC = 0x0 + NFTA_CT_HELPER_NAME = 0x1 + NFTA_CT_HELPER_L3PROTO = 0x2 + NFTA_CT_HELPER_L4PROTO = 0x3 + NFTA_OBJ_UNSPEC = 0x0 + NFTA_OBJ_TABLE = 0x1 + NFTA_OBJ_NAME = 0x2 + NFTA_OBJ_TYPE = 0x3 + NFTA_OBJ_DATA = 0x4 + NFTA_OBJ_USE = 0x5 + NFTA_TRACE_UNSPEC = 0x0 + NFTA_TRACE_TABLE = 0x1 + NFTA_TRACE_CHAIN = 0x2 + NFTA_TRACE_RULE_HANDLE = 0x3 + NFTA_TRACE_TYPE = 0x4 + NFTA_TRACE_VERDICT = 0x5 + NFTA_TRACE_ID = 0x6 + NFTA_TRACE_LL_HEADER = 0x7 + NFTA_TRACE_NETWORK_HEADER = 0x8 + NFTA_TRACE_TRANSPORT_HEADER = 0x9 + NFTA_TRACE_IIF = 0xa + NFTA_TRACE_IIFTYPE = 0xb + NFTA_TRACE_OIF = 0xc + NFTA_TRACE_OIFTYPE = 0xd + NFTA_TRACE_MARK = 0xe + NFTA_TRACE_NFPROTO = 0xf + NFTA_TRACE_POLICY = 0x10 + NFTA_TRACE_PAD = 0x11 + NFT_TRACETYPE_UNSPEC = 0x0 + NFT_TRACETYPE_POLICY = 0x1 + NFT_TRACETYPE_RETURN = 0x2 + NFT_TRACETYPE_RULE = 0x3 + NFTA_NG_UNSPEC = 0x0 + NFTA_NG_DREG = 0x1 + NFTA_NG_MODULUS = 0x2 + NFTA_NG_TYPE = 0x3 + NFTA_NG_OFFSET = 0x4 + NFT_NG_INCREMENTAL = 0x0 + NFT_NG_RANDOM = 0x1 +) + +type RTCTime struct { + Sec int32 + Min int32 + Hour int32 + Mday int32 + Mon int32 + Year int32 + Wday int32 + Yday int32 + Isdst int32 +} + +type RTCWkAlrm struct { + Enabled uint8 + Pending uint8 + Time RTCTime +} + +type RTCPLLInfo struct { + Ctrl int32 + Value int32 + Max int32 + Min int32 + Posmult int32 + Negmult int32 + Clock int64 +} + +type BlkpgIoctlArg struct { + Op int32 + Flags int32 + Datalen int32 + Data *byte +} + +type BlkpgPartition struct { + Start int64 + Length int64 + Pno int32 + Devname [64]uint8 + Volname [64]uint8 + _ [4]byte +} + +const ( + BLKPG = 0x20001269 + BLKPG_ADD_PARTITION = 0x1 + BLKPG_DEL_PARTITION = 0x2 + BLKPG_RESIZE_PARTITION = 0x3 +) + +const ( + NETNSA_NONE = 0x0 + NETNSA_NSID = 0x1 + NETNSA_PID = 0x2 + NETNSA_FD = 0x3 +) + +type XDPRingOffset struct { + Producer uint64 + Consumer uint64 + Desc uint64 +} + +type XDPMmapOffsets struct { + Rx XDPRingOffset + Tx XDPRingOffset + Fr XDPRingOffset + Cr XDPRingOffset +} + +type XDPUmemReg struct { + Addr uint64 + Len uint64 + Size uint32 + Headroom uint32 +} + +type XDPStatistics struct { + Rx_dropped uint64 + Rx_invalid_descs uint64 + Tx_invalid_descs uint64 +} + +type XDPDesc struct { + Addr uint64 + Len uint32 + Options uint32 +} + +const ( + NCSI_CMD_UNSPEC = 0x0 + NCSI_CMD_PKG_INFO = 0x1 + NCSI_CMD_SET_INTERFACE = 0x2 + NCSI_CMD_CLEAR_INTERFACE = 0x3 + NCSI_ATTR_UNSPEC = 0x0 + NCSI_ATTR_IFINDEX = 0x1 + NCSI_ATTR_PACKAGE_LIST = 0x2 + NCSI_ATTR_PACKAGE_ID = 0x3 + NCSI_ATTR_CHANNEL_ID = 0x4 + NCSI_PKG_ATTR_UNSPEC = 0x0 + NCSI_PKG_ATTR = 0x1 + NCSI_PKG_ATTR_ID = 0x2 + NCSI_PKG_ATTR_FORCED = 0x3 + NCSI_PKG_ATTR_CHANNEL_LIST = 0x4 + NCSI_CHANNEL_ATTR_UNSPEC = 0x0 + NCSI_CHANNEL_ATTR = 0x1 + NCSI_CHANNEL_ATTR_ID = 0x2 + NCSI_CHANNEL_ATTR_VERSION_MAJOR = 0x3 + NCSI_CHANNEL_ATTR_VERSION_MINOR = 0x4 + NCSI_CHANNEL_ATTR_VERSION_STR = 0x5 + NCSI_CHANNEL_ATTR_LINK_STATE = 0x6 + NCSI_CHANNEL_ATTR_ACTIVE = 0x7 + NCSI_CHANNEL_ATTR_FORCED = 0x8 + NCSI_CHANNEL_ATTR_VLAN_LIST = 0x9 + NCSI_CHANNEL_ATTR_VLAN_ID = 0xa +) + +type ScmTimestamping struct { + Ts [3]Timespec +} + +const ( + SOF_TIMESTAMPING_TX_HARDWARE = 0x1 + SOF_TIMESTAMPING_TX_SOFTWARE = 0x2 + SOF_TIMESTAMPING_RX_HARDWARE = 0x4 + SOF_TIMESTAMPING_RX_SOFTWARE = 0x8 + SOF_TIMESTAMPING_SOFTWARE = 0x10 + SOF_TIMESTAMPING_SYS_HARDWARE = 0x20 + SOF_TIMESTAMPING_RAW_HARDWARE = 0x40 + SOF_TIMESTAMPING_OPT_ID = 0x80 + SOF_TIMESTAMPING_TX_SCHED = 0x100 + SOF_TIMESTAMPING_TX_ACK = 0x200 + SOF_TIMESTAMPING_OPT_CMSG = 0x400 + SOF_TIMESTAMPING_OPT_TSONLY = 0x800 + SOF_TIMESTAMPING_OPT_STATS = 0x1000 + SOF_TIMESTAMPING_OPT_PKTINFO = 0x2000 + SOF_TIMESTAMPING_OPT_TX_SWHW = 0x4000 + + SOF_TIMESTAMPING_LAST = 0x4000 + SOF_TIMESTAMPING_MASK = 0x7fff + + SCM_TSTAMP_SND = 0x0 + SCM_TSTAMP_SCHED = 0x1 + SCM_TSTAMP_ACK = 0x2 +) + +type SockExtendedErr struct { + Errno uint32 + Origin uint8 + Type uint8 + Code uint8 + Pad uint8 + Info uint32 + Data uint32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go index 7ef31fe213..1e59b45068 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go @@ -6,11 +6,11 @@ package unix const ( - sizeofPtr = 0x8 - sizeofShort = 0x2 - sizeofInt = 0x4 - sizeofLong = 0x8 - sizeofLongLong = 0x8 + SizeofPtr = 0x8 + SizeofShort = 0x2 + SizeofInt = 0x4 + SizeofLong = 0x8 + SizeofLongLong = 0x8 PathMax = 0x1000 ) @@ -33,13 +33,11 @@ type Timeval struct { type Timex struct { Modes uint32 - Pad_cgo_0 [4]byte Offset int64 Freq int64 Maxerror int64 Esterror int64 Status int32 - Pad_cgo_1 [4]byte Constant int64 Precision int64 Tolerance int64 @@ -48,14 +46,13 @@ type Timex struct { Ppsfreq int64 Jitter int64 Shift int32 - Pad_cgo_2 [4]byte Stabil int64 Jitcnt int64 Calcnt int64 Errcnt int64 Stbcnt int64 Tai int32 - Pad_cgo_3 [44]byte + _ [44]byte } type Time_t int64 @@ -105,7 +102,7 @@ type Stat_t struct { Mode uint32 Uid uint32 Gid uint32 - X__pad2 int32 + _ int32 Rdev uint64 Size int64 Blksize int64 @@ -118,42 +115,56 @@ type Stat_t struct { _ uint64 } -type Statfs_t struct { - Type int64 - Bsize int64 - Blocks uint64 - Bfree uint64 - Bavail uint64 - Files uint64 - Ffree uint64 - Fsid Fsid - Namelen int64 - Frsize int64 - Flags int64 - Spare [4]int64 +type StatxTimestamp struct { + Sec int64 + Nsec uint32 + _ int32 +} + +type Statx_t struct { + Mask uint32 + Blksize uint32 + Attributes uint64 + Nlink uint32 + Uid uint32 + Gid uint32 + Mode uint16 + _ [1]uint16 + Ino uint64 + Size uint64 + Blocks uint64 + Attributes_mask uint64 + Atime StatxTimestamp + Btime StatxTimestamp + Ctime StatxTimestamp + Mtime StatxTimestamp + Rdev_major uint32 + Rdev_minor uint32 + Dev_major uint32 + Dev_minor uint32 + _ [14]uint64 } type Dirent struct { - Ino uint64 - Off int64 - Reclen uint16 - Type uint8 - Name [256]uint8 - Pad_cgo_0 [5]byte + Ino uint64 + Off int64 + Reclen uint16 + Type uint8 + Name [256]uint8 + _ [5]byte } type Fsid struct { - X__val [2]int32 + Val [2]int32 } type Flock_t struct { - Type int16 - Whence int16 - Pad_cgo_0 [4]byte - Start int64 - Len int64 - Pid int32 - Pad_cgo_1 [4]byte + Type int16 + Whence int16 + Start int64 + Len int64 + Pid int32 + _ [4]byte } type FscryptPolicy struct { @@ -228,11 +239,26 @@ type RawSockaddrHCI struct { Channel uint16 } +type RawSockaddrL2 struct { + Family uint16 + Psm uint16 + Bdaddr [6]uint8 + Cid uint16 + Bdaddr_type uint8 + _ [1]byte +} + +type RawSockaddrRFCOMM struct { + Family uint16 + Bdaddr [6]uint8 + Channel uint8 + _ [1]byte +} + type RawSockaddrCAN struct { - Family uint16 - Pad_cgo_0 [2]byte - Ifindex int32 - Addr [8]byte + Family uint16 + Ifindex int32 + Addr [8]byte } type RawSockaddrALG struct { @@ -251,6 +277,16 @@ type RawSockaddrVM struct { Zero [4]uint8 } +type RawSockaddrXDP struct { + Family uint16 + Flags uint16 + Ifindex uint32 + Queue_id uint32 + Shared_umem_fd uint32 +} + +type RawSockaddrPPPoX [0x1e]byte + type RawSockaddr struct { Family uint16 Data [14]uint8 @@ -299,13 +335,12 @@ type PacketMreq struct { type Msghdr struct { Name *byte Namelen uint32 - Pad_cgo_0 [4]byte Iov *Iovec Iovlen uint64 Control *byte Controllen uint64 Flags int32 - Pad_cgo_1 [4]byte + _ [4]byte } type Cmsghdr struct { @@ -347,7 +382,6 @@ type TCPInfo struct { Probes uint8 Backoff uint8 Options uint8 - Pad_cgo_0 [2]byte Rto uint32 Ato uint32 Snd_mss uint32 @@ -382,9 +416,13 @@ const ( SizeofSockaddrLinklayer = 0x14 SizeofSockaddrNetlink = 0xc SizeofSockaddrHCI = 0x6 + SizeofSockaddrL2 = 0xe + SizeofSockaddrRFCOMM = 0xa SizeofSockaddrCAN = 0x10 SizeofSockaddrALG = 0x58 SizeofSockaddrVM = 0x10 + SizeofSockaddrXDP = 0x10 + SizeofSockaddrPPPoX = 0x1e SizeofLinger = 0x8 SizeofIovec = 0x10 SizeofIPMreq = 0x8 @@ -402,97 +440,138 @@ const ( ) const ( - IFA_UNSPEC = 0x0 - IFA_ADDRESS = 0x1 - IFA_LOCAL = 0x2 - IFA_LABEL = 0x3 - IFA_BROADCAST = 0x4 - IFA_ANYCAST = 0x5 - IFA_CACHEINFO = 0x6 - IFA_MULTICAST = 0x7 - IFLA_UNSPEC = 0x0 - IFLA_ADDRESS = 0x1 - IFLA_BROADCAST = 0x2 - IFLA_IFNAME = 0x3 - IFLA_MTU = 0x4 - IFLA_LINK = 0x5 - IFLA_QDISC = 0x6 - IFLA_STATS = 0x7 - IFLA_COST = 0x8 - IFLA_PRIORITY = 0x9 - IFLA_MASTER = 0xa - IFLA_WIRELESS = 0xb - IFLA_PROTINFO = 0xc - IFLA_TXQLEN = 0xd - IFLA_MAP = 0xe - IFLA_WEIGHT = 0xf - IFLA_OPERSTATE = 0x10 - IFLA_LINKMODE = 0x11 - IFLA_LINKINFO = 0x12 - IFLA_NET_NS_PID = 0x13 - IFLA_IFALIAS = 0x14 - IFLA_MAX = 0x2c - RT_SCOPE_UNIVERSE = 0x0 - RT_SCOPE_SITE = 0xc8 - RT_SCOPE_LINK = 0xfd - RT_SCOPE_HOST = 0xfe - RT_SCOPE_NOWHERE = 0xff - RT_TABLE_UNSPEC = 0x0 - RT_TABLE_COMPAT = 0xfc - RT_TABLE_DEFAULT = 0xfd - RT_TABLE_MAIN = 0xfe - RT_TABLE_LOCAL = 0xff - RT_TABLE_MAX = 0xffffffff - RTA_UNSPEC = 0x0 - RTA_DST = 0x1 - RTA_SRC = 0x2 - RTA_IIF = 0x3 - RTA_OIF = 0x4 - RTA_GATEWAY = 0x5 - RTA_PRIORITY = 0x6 - RTA_PREFSRC = 0x7 - RTA_METRICS = 0x8 - RTA_MULTIPATH = 0x9 - RTA_FLOW = 0xb - RTA_CACHEINFO = 0xc - RTA_TABLE = 0xf - RTN_UNSPEC = 0x0 - RTN_UNICAST = 0x1 - RTN_LOCAL = 0x2 - RTN_BROADCAST = 0x3 - RTN_ANYCAST = 0x4 - RTN_MULTICAST = 0x5 - RTN_BLACKHOLE = 0x6 - RTN_UNREACHABLE = 0x7 - RTN_PROHIBIT = 0x8 - RTN_THROW = 0x9 - RTN_NAT = 0xa - RTN_XRESOLVE = 0xb - RTNLGRP_NONE = 0x0 - RTNLGRP_LINK = 0x1 - RTNLGRP_NOTIFY = 0x2 - RTNLGRP_NEIGH = 0x3 - RTNLGRP_TC = 0x4 - RTNLGRP_IPV4_IFADDR = 0x5 - RTNLGRP_IPV4_MROUTE = 0x6 - RTNLGRP_IPV4_ROUTE = 0x7 - RTNLGRP_IPV4_RULE = 0x8 - RTNLGRP_IPV6_IFADDR = 0x9 - RTNLGRP_IPV6_MROUTE = 0xa - RTNLGRP_IPV6_ROUTE = 0xb - RTNLGRP_IPV6_IFINFO = 0xc - RTNLGRP_IPV6_PREFIX = 0x12 - RTNLGRP_IPV6_RULE = 0x13 - RTNLGRP_ND_USEROPT = 0x14 - SizeofNlMsghdr = 0x10 - SizeofNlMsgerr = 0x14 - SizeofRtGenmsg = 0x1 - SizeofNlAttr = 0x4 - SizeofRtAttr = 0x4 - SizeofIfInfomsg = 0x10 - SizeofIfAddrmsg = 0x8 - SizeofRtMsg = 0xc - SizeofRtNexthop = 0x8 + IFA_UNSPEC = 0x0 + IFA_ADDRESS = 0x1 + IFA_LOCAL = 0x2 + IFA_LABEL = 0x3 + IFA_BROADCAST = 0x4 + IFA_ANYCAST = 0x5 + IFA_CACHEINFO = 0x6 + IFA_MULTICAST = 0x7 + IFLA_UNSPEC = 0x0 + IFLA_ADDRESS = 0x1 + IFLA_BROADCAST = 0x2 + IFLA_IFNAME = 0x3 + IFLA_INFO_KIND = 0x1 + IFLA_MTU = 0x4 + IFLA_LINK = 0x5 + IFLA_QDISC = 0x6 + IFLA_STATS = 0x7 + IFLA_COST = 0x8 + IFLA_PRIORITY = 0x9 + IFLA_MASTER = 0xa + IFLA_WIRELESS = 0xb + IFLA_PROTINFO = 0xc + IFLA_TXQLEN = 0xd + IFLA_MAP = 0xe + IFLA_WEIGHT = 0xf + IFLA_OPERSTATE = 0x10 + IFLA_LINKMODE = 0x11 + IFLA_LINKINFO = 0x12 + IFLA_NET_NS_PID = 0x13 + IFLA_IFALIAS = 0x14 + IFLA_NUM_VF = 0x15 + IFLA_VFINFO_LIST = 0x16 + IFLA_STATS64 = 0x17 + IFLA_VF_PORTS = 0x18 + IFLA_PORT_SELF = 0x19 + IFLA_AF_SPEC = 0x1a + IFLA_GROUP = 0x1b + IFLA_NET_NS_FD = 0x1c + IFLA_EXT_MASK = 0x1d + IFLA_PROMISCUITY = 0x1e + IFLA_NUM_TX_QUEUES = 0x1f + IFLA_NUM_RX_QUEUES = 0x20 + IFLA_CARRIER = 0x21 + IFLA_PHYS_PORT_ID = 0x22 + IFLA_CARRIER_CHANGES = 0x23 + IFLA_PHYS_SWITCH_ID = 0x24 + IFLA_LINK_NETNSID = 0x25 + IFLA_PHYS_PORT_NAME = 0x26 + IFLA_PROTO_DOWN = 0x27 + IFLA_GSO_MAX_SEGS = 0x28 + IFLA_GSO_MAX_SIZE = 0x29 + IFLA_PAD = 0x2a + IFLA_XDP = 0x2b + IFLA_EVENT = 0x2c + IFLA_NEW_NETNSID = 0x2d + IFLA_IF_NETNSID = 0x2e + IFLA_MAX = 0x33 + RT_SCOPE_UNIVERSE = 0x0 + RT_SCOPE_SITE = 0xc8 + RT_SCOPE_LINK = 0xfd + RT_SCOPE_HOST = 0xfe + RT_SCOPE_NOWHERE = 0xff + RT_TABLE_UNSPEC = 0x0 + RT_TABLE_COMPAT = 0xfc + RT_TABLE_DEFAULT = 0xfd + RT_TABLE_MAIN = 0xfe + RT_TABLE_LOCAL = 0xff + RT_TABLE_MAX = 0xffffffff + RTA_UNSPEC = 0x0 + RTA_DST = 0x1 + RTA_SRC = 0x2 + RTA_IIF = 0x3 + RTA_OIF = 0x4 + RTA_GATEWAY = 0x5 + RTA_PRIORITY = 0x6 + RTA_PREFSRC = 0x7 + RTA_METRICS = 0x8 + RTA_MULTIPATH = 0x9 + RTA_FLOW = 0xb + RTA_CACHEINFO = 0xc + RTA_TABLE = 0xf + RTA_MARK = 0x10 + RTA_MFC_STATS = 0x11 + RTA_VIA = 0x12 + RTA_NEWDST = 0x13 + RTA_PREF = 0x14 + RTA_ENCAP_TYPE = 0x15 + RTA_ENCAP = 0x16 + RTA_EXPIRES = 0x17 + RTA_PAD = 0x18 + RTA_UID = 0x19 + RTA_TTL_PROPAGATE = 0x1a + RTA_IP_PROTO = 0x1b + RTA_SPORT = 0x1c + RTA_DPORT = 0x1d + RTN_UNSPEC = 0x0 + RTN_UNICAST = 0x1 + RTN_LOCAL = 0x2 + RTN_BROADCAST = 0x3 + RTN_ANYCAST = 0x4 + RTN_MULTICAST = 0x5 + RTN_BLACKHOLE = 0x6 + RTN_UNREACHABLE = 0x7 + RTN_PROHIBIT = 0x8 + RTN_THROW = 0x9 + RTN_NAT = 0xa + RTN_XRESOLVE = 0xb + RTNLGRP_NONE = 0x0 + RTNLGRP_LINK = 0x1 + RTNLGRP_NOTIFY = 0x2 + RTNLGRP_NEIGH = 0x3 + RTNLGRP_TC = 0x4 + RTNLGRP_IPV4_IFADDR = 0x5 + RTNLGRP_IPV4_MROUTE = 0x6 + RTNLGRP_IPV4_ROUTE = 0x7 + RTNLGRP_IPV4_RULE = 0x8 + RTNLGRP_IPV6_IFADDR = 0x9 + RTNLGRP_IPV6_MROUTE = 0xa + RTNLGRP_IPV6_ROUTE = 0xb + RTNLGRP_IPV6_IFINFO = 0xc + RTNLGRP_IPV6_PREFIX = 0x12 + RTNLGRP_IPV6_RULE = 0x13 + RTNLGRP_ND_USEROPT = 0x14 + SizeofNlMsghdr = 0x10 + SizeofNlMsgerr = 0x14 + SizeofRtGenmsg = 0x1 + SizeofNlAttr = 0x4 + SizeofRtAttr = 0x4 + SizeofIfInfomsg = 0x10 + SizeofIfAddrmsg = 0x8 + SizeofRtMsg = 0xc + SizeofRtNexthop = 0x8 ) type NlMsghdr struct { @@ -523,12 +602,12 @@ type RtAttr struct { } type IfInfomsg struct { - Family uint8 - X__ifi_pad uint8 - Type uint16 - Index int32 - Flags uint32 - Change uint32 + Family uint8 + _ uint8 + Type uint16 + Index int32 + Flags uint32 + Change uint32 } type IfAddrmsg struct { @@ -571,9 +650,8 @@ type SockFilter struct { } type SockFprog struct { - Len uint16 - Pad_cgo_0 [6]byte - Filter *SockFilter + Len uint16 + Filter *SockFilter } type InotifyEvent struct { @@ -616,12 +694,11 @@ type Sysinfo_t struct { Freeswap uint64 Procs uint16 Pad uint16 - Pad_cgo_0 [4]byte Totalhigh uint64 Freehigh uint64 Unit uint32 - X_f [0]uint8 - Pad_cgo_1 [4]byte + _ [0]uint8 + _ [4]byte } type Utsname struct { @@ -634,26 +711,34 @@ type Utsname struct { } type Ustat_t struct { - Tfree int32 - Pad_cgo_0 [4]byte - Tinode uint64 - Fname [6]uint8 - Fpack [6]uint8 - Pad_cgo_1 [4]byte + Tfree int32 + Tinode uint64 + Fname [6]uint8 + Fpack [6]uint8 + _ [4]byte } type EpollEvent struct { - Events uint32 - X_padFd int32 - Fd int32 - Pad int32 + Events uint32 + _ int32 + Fd int32 + Pad int32 } const ( - AT_FDCWD = -0x64 - AT_REMOVEDIR = 0x200 + AT_EMPTY_PATH = 0x1000 + AT_FDCWD = -0x64 + AT_NO_AUTOMOUNT = 0x800 + AT_REMOVEDIR = 0x200 + + AT_STATX_SYNC_AS_STAT = 0x0 + AT_STATX_FORCE_SYNC = 0x2000 + AT_STATX_DONT_SYNC = 0x4000 + AT_SYMLINK_FOLLOW = 0x400 AT_SYMLINK_NOFOLLOW = 0x100 + + AT_EACCESS = 0x200 ) type PollFd struct { @@ -673,10 +758,33 @@ const ( ) type Sigset_t struct { - X__val [16]uint64 + Val [16]uint64 } -const RNDGETENTCNT = 0x40045200 +type SignalfdSiginfo struct { + Signo uint32 + Errno int32 + Code int32 + Pid uint32 + Uid uint32 + Fd int32 + Tid uint32 + Band uint32 + Overrun uint32 + Trapno uint32 + Status int32 + Int int32 + Ptr uint64 + Utime uint64 + Stime uint64 + Addr uint64 + Addr_lsb uint16 + _ uint16 + Syscall int32 + Call_addr uint64 + Arch uint32 + _ [28]uint8 +} const PERF_IOC_FLAG_GROUP = 0x1 @@ -700,11 +808,9 @@ type Winsize struct { type Taskstats struct { Version uint16 - Pad_cgo_0 [2]byte Ac_exitcode uint32 Ac_flag uint8 Ac_nice uint8 - Pad_cgo_1 [6]byte Cpu_count uint64 Cpu_delay_total uint64 Blkio_count uint64 @@ -716,13 +822,12 @@ type Taskstats struct { Ac_comm [32]uint8 Ac_sched uint8 Ac_pad [3]uint8 - Pad_cgo_2 [4]byte + _ [4]byte Ac_uid uint32 Ac_gid uint32 Ac_pid uint32 Ac_ppid uint32 Ac_btime uint32 - Pad_cgo_3 [4]byte Ac_etime uint64 Ac_utime uint64 Ac_stime uint64 @@ -746,6 +851,8 @@ type Taskstats struct { Cpu_scaled_run_real_total uint64 Freepages_count uint64 Freepages_delay_total uint64 + Thrashing_count uint64 + Thrashing_delay_total uint64 } const ( @@ -766,6 +873,24 @@ const ( TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK = 0x4 ) +type CGroupStats struct { + Sleeping uint64 + Running uint64 + Stopped uint64 + Uninterruptible uint64 + Io_wait uint64 +} + +const ( + CGROUPSTATS_CMD_UNSPEC = 0x3 + CGROUPSTATS_CMD_GET = 0x4 + CGROUPSTATS_CMD_NEW = 0x5 + CGROUPSTATS_TYPE_UNSPEC = 0x0 + CGROUPSTATS_TYPE_CGROUP_STATS = 0x1 + CGROUPSTATS_CMD_ATTR_UNSPEC = 0x0 + CGROUPSTATS_CMD_ATTR_FD = 0x1 +) + type Genlmsghdr struct { Cmd uint8 Version uint8 @@ -798,3 +923,1107 @@ const ( CTRL_ATTR_MCAST_GRP_NAME = 0x1 CTRL_ATTR_MCAST_GRP_ID = 0x2 ) + +type cpuMask uint64 + +const ( + _CPU_SETSIZE = 0x400 + _NCPUBITS = 0x40 +) + +const ( + BDADDR_BREDR = 0x0 + BDADDR_LE_PUBLIC = 0x1 + BDADDR_LE_RANDOM = 0x2 +) + +type PerfEventAttr struct { + Type uint32 + Size uint32 + Config uint64 + Sample uint64 + Sample_type uint64 + Read_format uint64 + Bits uint64 + Wakeup uint32 + Bp_type uint32 + Ext1 uint64 + Ext2 uint64 + Branch_sample_type uint64 + Sample_regs_user uint64 + Sample_stack_user uint32 + Clockid int32 + Sample_regs_intr uint64 + Aux_watermark uint32 + _ uint32 +} + +type PerfEventMmapPage struct { + Version uint32 + Compat_version uint32 + Lock uint32 + Index uint32 + Offset int64 + Time_enabled uint64 + Time_running uint64 + Capabilities uint64 + Pmc_width uint16 + Time_shift uint16 + Time_mult uint32 + Time_offset uint64 + Time_zero uint64 + Size uint32 + _ [948]uint8 + Data_head uint64 + Data_tail uint64 + Data_offset uint64 + Data_size uint64 + Aux_head uint64 + Aux_tail uint64 + Aux_offset uint64 + Aux_size uint64 +} + +const ( + PerfBitDisabled uint64 = CBitFieldMaskBit0 + PerfBitInherit = CBitFieldMaskBit1 + PerfBitPinned = CBitFieldMaskBit2 + PerfBitExclusive = CBitFieldMaskBit3 + PerfBitExcludeUser = CBitFieldMaskBit4 + PerfBitExcludeKernel = CBitFieldMaskBit5 + PerfBitExcludeHv = CBitFieldMaskBit6 + PerfBitExcludeIdle = CBitFieldMaskBit7 + PerfBitMmap = CBitFieldMaskBit8 + PerfBitComm = CBitFieldMaskBit9 + PerfBitFreq = CBitFieldMaskBit10 + PerfBitInheritStat = CBitFieldMaskBit11 + PerfBitEnableOnExec = CBitFieldMaskBit12 + PerfBitTask = CBitFieldMaskBit13 + PerfBitWatermark = CBitFieldMaskBit14 + PerfBitPreciseIPBit1 = CBitFieldMaskBit15 + PerfBitPreciseIPBit2 = CBitFieldMaskBit16 + PerfBitMmapData = CBitFieldMaskBit17 + PerfBitSampleIDAll = CBitFieldMaskBit18 + PerfBitExcludeHost = CBitFieldMaskBit19 + PerfBitExcludeGuest = CBitFieldMaskBit20 + PerfBitExcludeCallchainKernel = CBitFieldMaskBit21 + PerfBitExcludeCallchainUser = CBitFieldMaskBit22 + PerfBitMmap2 = CBitFieldMaskBit23 + PerfBitCommExec = CBitFieldMaskBit24 + PerfBitUseClockID = CBitFieldMaskBit25 + PerfBitContextSwitch = CBitFieldMaskBit26 +) + +const ( + PERF_TYPE_HARDWARE = 0x0 + PERF_TYPE_SOFTWARE = 0x1 + PERF_TYPE_TRACEPOINT = 0x2 + PERF_TYPE_HW_CACHE = 0x3 + PERF_TYPE_RAW = 0x4 + PERF_TYPE_BREAKPOINT = 0x5 + + PERF_COUNT_HW_CPU_CYCLES = 0x0 + PERF_COUNT_HW_INSTRUCTIONS = 0x1 + PERF_COUNT_HW_CACHE_REFERENCES = 0x2 + PERF_COUNT_HW_CACHE_MISSES = 0x3 + PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 0x4 + PERF_COUNT_HW_BRANCH_MISSES = 0x5 + PERF_COUNT_HW_BUS_CYCLES = 0x6 + PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 0x7 + PERF_COUNT_HW_STALLED_CYCLES_BACKEND = 0x8 + PERF_COUNT_HW_REF_CPU_CYCLES = 0x9 + + PERF_COUNT_HW_CACHE_L1D = 0x0 + PERF_COUNT_HW_CACHE_L1I = 0x1 + PERF_COUNT_HW_CACHE_LL = 0x2 + PERF_COUNT_HW_CACHE_DTLB = 0x3 + PERF_COUNT_HW_CACHE_ITLB = 0x4 + PERF_COUNT_HW_CACHE_BPU = 0x5 + PERF_COUNT_HW_CACHE_NODE = 0x6 + + PERF_COUNT_HW_CACHE_OP_READ = 0x0 + PERF_COUNT_HW_CACHE_OP_WRITE = 0x1 + PERF_COUNT_HW_CACHE_OP_PREFETCH = 0x2 + + PERF_COUNT_HW_CACHE_RESULT_ACCESS = 0x0 + PERF_COUNT_HW_CACHE_RESULT_MISS = 0x1 + + PERF_COUNT_SW_CPU_CLOCK = 0x0 + PERF_COUNT_SW_TASK_CLOCK = 0x1 + PERF_COUNT_SW_PAGE_FAULTS = 0x2 + PERF_COUNT_SW_CONTEXT_SWITCHES = 0x3 + PERF_COUNT_SW_CPU_MIGRATIONS = 0x4 + PERF_COUNT_SW_PAGE_FAULTS_MIN = 0x5 + PERF_COUNT_SW_PAGE_FAULTS_MAJ = 0x6 + PERF_COUNT_SW_ALIGNMENT_FAULTS = 0x7 + PERF_COUNT_SW_EMULATION_FAULTS = 0x8 + PERF_COUNT_SW_DUMMY = 0x9 + + PERF_SAMPLE_IP = 0x1 + PERF_SAMPLE_TID = 0x2 + PERF_SAMPLE_TIME = 0x4 + PERF_SAMPLE_ADDR = 0x8 + PERF_SAMPLE_READ = 0x10 + PERF_SAMPLE_CALLCHAIN = 0x20 + PERF_SAMPLE_ID = 0x40 + PERF_SAMPLE_CPU = 0x80 + PERF_SAMPLE_PERIOD = 0x100 + PERF_SAMPLE_STREAM_ID = 0x200 + PERF_SAMPLE_RAW = 0x400 + PERF_SAMPLE_BRANCH_STACK = 0x800 + + PERF_SAMPLE_BRANCH_USER = 0x1 + PERF_SAMPLE_BRANCH_KERNEL = 0x2 + PERF_SAMPLE_BRANCH_HV = 0x4 + PERF_SAMPLE_BRANCH_ANY = 0x8 + PERF_SAMPLE_BRANCH_ANY_CALL = 0x10 + PERF_SAMPLE_BRANCH_ANY_RETURN = 0x20 + PERF_SAMPLE_BRANCH_IND_CALL = 0x40 + + PERF_FORMAT_TOTAL_TIME_ENABLED = 0x1 + PERF_FORMAT_TOTAL_TIME_RUNNING = 0x2 + PERF_FORMAT_ID = 0x4 + PERF_FORMAT_GROUP = 0x8 + + PERF_RECORD_MMAP = 0x1 + PERF_RECORD_LOST = 0x2 + PERF_RECORD_COMM = 0x3 + PERF_RECORD_EXIT = 0x4 + PERF_RECORD_THROTTLE = 0x5 + PERF_RECORD_UNTHROTTLE = 0x6 + PERF_RECORD_FORK = 0x7 + PERF_RECORD_READ = 0x8 + PERF_RECORD_SAMPLE = 0x9 + + PERF_CONTEXT_HV = -0x20 + PERF_CONTEXT_KERNEL = -0x80 + PERF_CONTEXT_USER = -0x200 + + PERF_CONTEXT_GUEST = -0x800 + PERF_CONTEXT_GUEST_KERNEL = -0x880 + PERF_CONTEXT_GUEST_USER = -0xa00 + + PERF_FLAG_FD_NO_GROUP = 0x1 + PERF_FLAG_FD_OUTPUT = 0x2 + PERF_FLAG_PID_CGROUP = 0x4 +) + +const ( + CBitFieldMaskBit0 = 0x1 + CBitFieldMaskBit1 = 0x2 + CBitFieldMaskBit2 = 0x4 + CBitFieldMaskBit3 = 0x8 + CBitFieldMaskBit4 = 0x10 + CBitFieldMaskBit5 = 0x20 + CBitFieldMaskBit6 = 0x40 + CBitFieldMaskBit7 = 0x80 + CBitFieldMaskBit8 = 0x100 + CBitFieldMaskBit9 = 0x200 + CBitFieldMaskBit10 = 0x400 + CBitFieldMaskBit11 = 0x800 + CBitFieldMaskBit12 = 0x1000 + CBitFieldMaskBit13 = 0x2000 + CBitFieldMaskBit14 = 0x4000 + CBitFieldMaskBit15 = 0x8000 + CBitFieldMaskBit16 = 0x10000 + CBitFieldMaskBit17 = 0x20000 + CBitFieldMaskBit18 = 0x40000 + CBitFieldMaskBit19 = 0x80000 + CBitFieldMaskBit20 = 0x100000 + CBitFieldMaskBit21 = 0x200000 + CBitFieldMaskBit22 = 0x400000 + CBitFieldMaskBit23 = 0x800000 + CBitFieldMaskBit24 = 0x1000000 + CBitFieldMaskBit25 = 0x2000000 + CBitFieldMaskBit26 = 0x4000000 + CBitFieldMaskBit27 = 0x8000000 + CBitFieldMaskBit28 = 0x10000000 + CBitFieldMaskBit29 = 0x20000000 + CBitFieldMaskBit30 = 0x40000000 + CBitFieldMaskBit31 = 0x80000000 + CBitFieldMaskBit32 = 0x100000000 + CBitFieldMaskBit33 = 0x200000000 + CBitFieldMaskBit34 = 0x400000000 + CBitFieldMaskBit35 = 0x800000000 + CBitFieldMaskBit36 = 0x1000000000 + CBitFieldMaskBit37 = 0x2000000000 + CBitFieldMaskBit38 = 0x4000000000 + CBitFieldMaskBit39 = 0x8000000000 + CBitFieldMaskBit40 = 0x10000000000 + CBitFieldMaskBit41 = 0x20000000000 + CBitFieldMaskBit42 = 0x40000000000 + CBitFieldMaskBit43 = 0x80000000000 + CBitFieldMaskBit44 = 0x100000000000 + CBitFieldMaskBit45 = 0x200000000000 + CBitFieldMaskBit46 = 0x400000000000 + CBitFieldMaskBit47 = 0x800000000000 + CBitFieldMaskBit48 = 0x1000000000000 + CBitFieldMaskBit49 = 0x2000000000000 + CBitFieldMaskBit50 = 0x4000000000000 + CBitFieldMaskBit51 = 0x8000000000000 + CBitFieldMaskBit52 = 0x10000000000000 + CBitFieldMaskBit53 = 0x20000000000000 + CBitFieldMaskBit54 = 0x40000000000000 + CBitFieldMaskBit55 = 0x80000000000000 + CBitFieldMaskBit56 = 0x100000000000000 + CBitFieldMaskBit57 = 0x200000000000000 + CBitFieldMaskBit58 = 0x400000000000000 + CBitFieldMaskBit59 = 0x800000000000000 + CBitFieldMaskBit60 = 0x1000000000000000 + CBitFieldMaskBit61 = 0x2000000000000000 + CBitFieldMaskBit62 = 0x4000000000000000 + CBitFieldMaskBit63 = 0x8000000000000000 +) + +type SockaddrStorage struct { + Family uint16 + _ [118]uint8 + _ uint64 +} + +type TCPMD5Sig struct { + Addr SockaddrStorage + Flags uint8 + Prefixlen uint8 + Keylen uint16 + _ uint32 + Key [80]uint8 +} + +type HDDriveCmdHdr struct { + Command uint8 + Number uint8 + Feature uint8 + Count uint8 +} + +type HDGeometry struct { + Heads uint8 + Sectors uint8 + Cylinders uint16 + Start uint64 +} + +type HDDriveID struct { + Config uint16 + Cyls uint16 + Reserved2 uint16 + Heads uint16 + Track_bytes uint16 + Sector_bytes uint16 + Sectors uint16 + Vendor0 uint16 + Vendor1 uint16 + Vendor2 uint16 + Serial_no [20]uint8 + Buf_type uint16 + Buf_size uint16 + Ecc_bytes uint16 + Fw_rev [8]uint8 + Model [40]uint8 + Max_multsect uint8 + Vendor3 uint8 + Dword_io uint16 + Vendor4 uint8 + Capability uint8 + Reserved50 uint16 + Vendor5 uint8 + TPIO uint8 + Vendor6 uint8 + TDMA uint8 + Field_valid uint16 + Cur_cyls uint16 + Cur_heads uint16 + Cur_sectors uint16 + Cur_capacity0 uint16 + Cur_capacity1 uint16 + Multsect uint8 + Multsect_valid uint8 + Lba_capacity uint32 + Dma_1word uint16 + Dma_mword uint16 + Eide_pio_modes uint16 + Eide_dma_min uint16 + Eide_dma_time uint16 + Eide_pio uint16 + Eide_pio_iordy uint16 + Words69_70 [2]uint16 + Words71_74 [4]uint16 + Queue_depth uint16 + Words76_79 [4]uint16 + Major_rev_num uint16 + Minor_rev_num uint16 + Command_set_1 uint16 + Command_set_2 uint16 + Cfsse uint16 + Cfs_enable_1 uint16 + Cfs_enable_2 uint16 + Csf_default uint16 + Dma_ultra uint16 + Trseuc uint16 + TrsEuc uint16 + CurAPMvalues uint16 + Mprc uint16 + Hw_config uint16 + Acoustic uint16 + Msrqs uint16 + Sxfert uint16 + Sal uint16 + Spg uint32 + Lba_capacity_2 uint64 + Words104_125 [22]uint16 + Last_lun uint16 + Word127 uint16 + Dlf uint16 + Csfo uint16 + Words130_155 [26]uint16 + Word156 uint16 + Words157_159 [3]uint16 + Cfa_power uint16 + Words161_175 [15]uint16 + Words176_205 [30]uint16 + Words206_254 [49]uint16 + Integrity_word uint16 +} + +type Statfs_t struct { + Type int64 + Bsize int64 + Blocks uint64 + Bfree uint64 + Bavail uint64 + Files uint64 + Ffree uint64 + Fsid Fsid + Namelen int64 + Frsize int64 + Flags int64 + Spare [4]int64 +} + +const ( + ST_MANDLOCK = 0x40 + ST_NOATIME = 0x400 + ST_NODEV = 0x4 + ST_NODIRATIME = 0x800 + ST_NOEXEC = 0x8 + ST_NOSUID = 0x2 + ST_RDONLY = 0x1 + ST_RELATIME = 0x1000 + ST_SYNCHRONOUS = 0x10 +) + +type TpacketHdr struct { + Status uint64 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Sec uint32 + Usec uint32 + _ [4]byte +} + +type Tpacket2Hdr struct { + Status uint32 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Sec uint32 + Nsec uint32 + Vlan_tci uint16 + Vlan_tpid uint16 + _ [4]uint8 +} + +type Tpacket3Hdr struct { + Next_offset uint32 + Sec uint32 + Nsec uint32 + Snaplen uint32 + Len uint32 + Status uint32 + Mac uint16 + Net uint16 + Hv1 TpacketHdrVariant1 + _ [8]uint8 +} + +type TpacketHdrVariant1 struct { + Rxhash uint32 + Vlan_tci uint32 + Vlan_tpid uint16 + _ uint16 +} + +type TpacketBlockDesc struct { + Version uint32 + To_priv uint32 + Hdr [40]byte +} + +type TpacketReq struct { + Block_size uint32 + Block_nr uint32 + Frame_size uint32 + Frame_nr uint32 +} + +type TpacketReq3 struct { + Block_size uint32 + Block_nr uint32 + Frame_size uint32 + Frame_nr uint32 + Retire_blk_tov uint32 + Sizeof_priv uint32 + Feature_req_word uint32 +} + +type TpacketStats struct { + Packets uint32 + Drops uint32 +} + +type TpacketStatsV3 struct { + Packets uint32 + Drops uint32 + Freeze_q_cnt uint32 +} + +type TpacketAuxdata struct { + Status uint32 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Vlan_tci uint16 + Vlan_tpid uint16 +} + +const ( + TPACKET_V1 = 0x0 + TPACKET_V2 = 0x1 + TPACKET_V3 = 0x2 +) + +const ( + SizeofTpacketHdr = 0x20 + SizeofTpacket2Hdr = 0x20 + SizeofTpacket3Hdr = 0x30 +) + +const ( + NF_INET_PRE_ROUTING = 0x0 + NF_INET_LOCAL_IN = 0x1 + NF_INET_FORWARD = 0x2 + NF_INET_LOCAL_OUT = 0x3 + NF_INET_POST_ROUTING = 0x4 + NF_INET_NUMHOOKS = 0x5 +) + +const ( + NF_NETDEV_INGRESS = 0x0 + NF_NETDEV_NUMHOOKS = 0x1 +) + +const ( + NFPROTO_UNSPEC = 0x0 + NFPROTO_INET = 0x1 + NFPROTO_IPV4 = 0x2 + NFPROTO_ARP = 0x3 + NFPROTO_NETDEV = 0x5 + NFPROTO_BRIDGE = 0x7 + NFPROTO_IPV6 = 0xa + NFPROTO_DECNET = 0xc + NFPROTO_NUMPROTO = 0xd +) + +type Nfgenmsg struct { + Nfgen_family uint8 + Version uint8 + Res_id uint16 +} + +const ( + NFNL_BATCH_UNSPEC = 0x0 + NFNL_BATCH_GENID = 0x1 +) + +const ( + NFT_REG_VERDICT = 0x0 + NFT_REG_1 = 0x1 + NFT_REG_2 = 0x2 + NFT_REG_3 = 0x3 + NFT_REG_4 = 0x4 + NFT_REG32_00 = 0x8 + NFT_REG32_01 = 0x9 + NFT_REG32_02 = 0xa + NFT_REG32_03 = 0xb + NFT_REG32_04 = 0xc + NFT_REG32_05 = 0xd + NFT_REG32_06 = 0xe + NFT_REG32_07 = 0xf + NFT_REG32_08 = 0x10 + NFT_REG32_09 = 0x11 + NFT_REG32_10 = 0x12 + NFT_REG32_11 = 0x13 + NFT_REG32_12 = 0x14 + NFT_REG32_13 = 0x15 + NFT_REG32_14 = 0x16 + NFT_REG32_15 = 0x17 + NFT_CONTINUE = -0x1 + NFT_BREAK = -0x2 + NFT_JUMP = -0x3 + NFT_GOTO = -0x4 + NFT_RETURN = -0x5 + NFT_MSG_NEWTABLE = 0x0 + NFT_MSG_GETTABLE = 0x1 + NFT_MSG_DELTABLE = 0x2 + NFT_MSG_NEWCHAIN = 0x3 + NFT_MSG_GETCHAIN = 0x4 + NFT_MSG_DELCHAIN = 0x5 + NFT_MSG_NEWRULE = 0x6 + NFT_MSG_GETRULE = 0x7 + NFT_MSG_DELRULE = 0x8 + NFT_MSG_NEWSET = 0x9 + NFT_MSG_GETSET = 0xa + NFT_MSG_DELSET = 0xb + NFT_MSG_NEWSETELEM = 0xc + NFT_MSG_GETSETELEM = 0xd + NFT_MSG_DELSETELEM = 0xe + NFT_MSG_NEWGEN = 0xf + NFT_MSG_GETGEN = 0x10 + NFT_MSG_TRACE = 0x11 + NFT_MSG_NEWOBJ = 0x12 + NFT_MSG_GETOBJ = 0x13 + NFT_MSG_DELOBJ = 0x14 + NFT_MSG_GETOBJ_RESET = 0x15 + NFT_MSG_MAX = 0x19 + NFTA_LIST_UNPEC = 0x0 + NFTA_LIST_ELEM = 0x1 + NFTA_HOOK_UNSPEC = 0x0 + NFTA_HOOK_HOOKNUM = 0x1 + NFTA_HOOK_PRIORITY = 0x2 + NFTA_HOOK_DEV = 0x3 + NFT_TABLE_F_DORMANT = 0x1 + NFTA_TABLE_UNSPEC = 0x0 + NFTA_TABLE_NAME = 0x1 + NFTA_TABLE_FLAGS = 0x2 + NFTA_TABLE_USE = 0x3 + NFTA_CHAIN_UNSPEC = 0x0 + NFTA_CHAIN_TABLE = 0x1 + NFTA_CHAIN_HANDLE = 0x2 + NFTA_CHAIN_NAME = 0x3 + NFTA_CHAIN_HOOK = 0x4 + NFTA_CHAIN_POLICY = 0x5 + NFTA_CHAIN_USE = 0x6 + NFTA_CHAIN_TYPE = 0x7 + NFTA_CHAIN_COUNTERS = 0x8 + NFTA_CHAIN_PAD = 0x9 + NFTA_RULE_UNSPEC = 0x0 + NFTA_RULE_TABLE = 0x1 + NFTA_RULE_CHAIN = 0x2 + NFTA_RULE_HANDLE = 0x3 + NFTA_RULE_EXPRESSIONS = 0x4 + NFTA_RULE_COMPAT = 0x5 + NFTA_RULE_POSITION = 0x6 + NFTA_RULE_USERDATA = 0x7 + NFTA_RULE_PAD = 0x8 + NFTA_RULE_ID = 0x9 + NFT_RULE_COMPAT_F_INV = 0x2 + NFT_RULE_COMPAT_F_MASK = 0x2 + NFTA_RULE_COMPAT_UNSPEC = 0x0 + NFTA_RULE_COMPAT_PROTO = 0x1 + NFTA_RULE_COMPAT_FLAGS = 0x2 + NFT_SET_ANONYMOUS = 0x1 + NFT_SET_CONSTANT = 0x2 + NFT_SET_INTERVAL = 0x4 + NFT_SET_MAP = 0x8 + NFT_SET_TIMEOUT = 0x10 + NFT_SET_EVAL = 0x20 + NFT_SET_OBJECT = 0x40 + NFT_SET_POL_PERFORMANCE = 0x0 + NFT_SET_POL_MEMORY = 0x1 + NFTA_SET_DESC_UNSPEC = 0x0 + NFTA_SET_DESC_SIZE = 0x1 + NFTA_SET_UNSPEC = 0x0 + NFTA_SET_TABLE = 0x1 + NFTA_SET_NAME = 0x2 + NFTA_SET_FLAGS = 0x3 + NFTA_SET_KEY_TYPE = 0x4 + NFTA_SET_KEY_LEN = 0x5 + NFTA_SET_DATA_TYPE = 0x6 + NFTA_SET_DATA_LEN = 0x7 + NFTA_SET_POLICY = 0x8 + NFTA_SET_DESC = 0x9 + NFTA_SET_ID = 0xa + NFTA_SET_TIMEOUT = 0xb + NFTA_SET_GC_INTERVAL = 0xc + NFTA_SET_USERDATA = 0xd + NFTA_SET_PAD = 0xe + NFTA_SET_OBJ_TYPE = 0xf + NFT_SET_ELEM_INTERVAL_END = 0x1 + NFTA_SET_ELEM_UNSPEC = 0x0 + NFTA_SET_ELEM_KEY = 0x1 + NFTA_SET_ELEM_DATA = 0x2 + NFTA_SET_ELEM_FLAGS = 0x3 + NFTA_SET_ELEM_TIMEOUT = 0x4 + NFTA_SET_ELEM_EXPIRATION = 0x5 + NFTA_SET_ELEM_USERDATA = 0x6 + NFTA_SET_ELEM_EXPR = 0x7 + NFTA_SET_ELEM_PAD = 0x8 + NFTA_SET_ELEM_OBJREF = 0x9 + NFTA_SET_ELEM_LIST_UNSPEC = 0x0 + NFTA_SET_ELEM_LIST_TABLE = 0x1 + NFTA_SET_ELEM_LIST_SET = 0x2 + NFTA_SET_ELEM_LIST_ELEMENTS = 0x3 + NFTA_SET_ELEM_LIST_SET_ID = 0x4 + NFT_DATA_VALUE = 0x0 + NFT_DATA_VERDICT = 0xffffff00 + NFTA_DATA_UNSPEC = 0x0 + NFTA_DATA_VALUE = 0x1 + NFTA_DATA_VERDICT = 0x2 + NFTA_VERDICT_UNSPEC = 0x0 + NFTA_VERDICT_CODE = 0x1 + NFTA_VERDICT_CHAIN = 0x2 + NFTA_EXPR_UNSPEC = 0x0 + NFTA_EXPR_NAME = 0x1 + NFTA_EXPR_DATA = 0x2 + NFTA_IMMEDIATE_UNSPEC = 0x0 + NFTA_IMMEDIATE_DREG = 0x1 + NFTA_IMMEDIATE_DATA = 0x2 + NFTA_BITWISE_UNSPEC = 0x0 + NFTA_BITWISE_SREG = 0x1 + NFTA_BITWISE_DREG = 0x2 + NFTA_BITWISE_LEN = 0x3 + NFTA_BITWISE_MASK = 0x4 + NFTA_BITWISE_XOR = 0x5 + NFT_BYTEORDER_NTOH = 0x0 + NFT_BYTEORDER_HTON = 0x1 + NFTA_BYTEORDER_UNSPEC = 0x0 + NFTA_BYTEORDER_SREG = 0x1 + NFTA_BYTEORDER_DREG = 0x2 + NFTA_BYTEORDER_OP = 0x3 + NFTA_BYTEORDER_LEN = 0x4 + NFTA_BYTEORDER_SIZE = 0x5 + NFT_CMP_EQ = 0x0 + NFT_CMP_NEQ = 0x1 + NFT_CMP_LT = 0x2 + NFT_CMP_LTE = 0x3 + NFT_CMP_GT = 0x4 + NFT_CMP_GTE = 0x5 + NFTA_CMP_UNSPEC = 0x0 + NFTA_CMP_SREG = 0x1 + NFTA_CMP_OP = 0x2 + NFTA_CMP_DATA = 0x3 + NFT_RANGE_EQ = 0x0 + NFT_RANGE_NEQ = 0x1 + NFTA_RANGE_UNSPEC = 0x0 + NFTA_RANGE_SREG = 0x1 + NFTA_RANGE_OP = 0x2 + NFTA_RANGE_FROM_DATA = 0x3 + NFTA_RANGE_TO_DATA = 0x4 + NFT_LOOKUP_F_INV = 0x1 + NFTA_LOOKUP_UNSPEC = 0x0 + NFTA_LOOKUP_SET = 0x1 + NFTA_LOOKUP_SREG = 0x2 + NFTA_LOOKUP_DREG = 0x3 + NFTA_LOOKUP_SET_ID = 0x4 + NFTA_LOOKUP_FLAGS = 0x5 + NFT_DYNSET_OP_ADD = 0x0 + NFT_DYNSET_OP_UPDATE = 0x1 + NFT_DYNSET_F_INV = 0x1 + NFTA_DYNSET_UNSPEC = 0x0 + NFTA_DYNSET_SET_NAME = 0x1 + NFTA_DYNSET_SET_ID = 0x2 + NFTA_DYNSET_OP = 0x3 + NFTA_DYNSET_SREG_KEY = 0x4 + NFTA_DYNSET_SREG_DATA = 0x5 + NFTA_DYNSET_TIMEOUT = 0x6 + NFTA_DYNSET_EXPR = 0x7 + NFTA_DYNSET_PAD = 0x8 + NFTA_DYNSET_FLAGS = 0x9 + NFT_PAYLOAD_LL_HEADER = 0x0 + NFT_PAYLOAD_NETWORK_HEADER = 0x1 + NFT_PAYLOAD_TRANSPORT_HEADER = 0x2 + NFT_PAYLOAD_CSUM_NONE = 0x0 + NFT_PAYLOAD_CSUM_INET = 0x1 + NFT_PAYLOAD_L4CSUM_PSEUDOHDR = 0x1 + NFTA_PAYLOAD_UNSPEC = 0x0 + NFTA_PAYLOAD_DREG = 0x1 + NFTA_PAYLOAD_BASE = 0x2 + NFTA_PAYLOAD_OFFSET = 0x3 + NFTA_PAYLOAD_LEN = 0x4 + NFTA_PAYLOAD_SREG = 0x5 + NFTA_PAYLOAD_CSUM_TYPE = 0x6 + NFTA_PAYLOAD_CSUM_OFFSET = 0x7 + NFTA_PAYLOAD_CSUM_FLAGS = 0x8 + NFT_EXTHDR_F_PRESENT = 0x1 + NFT_EXTHDR_OP_IPV6 = 0x0 + NFT_EXTHDR_OP_TCPOPT = 0x1 + NFTA_EXTHDR_UNSPEC = 0x0 + NFTA_EXTHDR_DREG = 0x1 + NFTA_EXTHDR_TYPE = 0x2 + NFTA_EXTHDR_OFFSET = 0x3 + NFTA_EXTHDR_LEN = 0x4 + NFTA_EXTHDR_FLAGS = 0x5 + NFTA_EXTHDR_OP = 0x6 + NFTA_EXTHDR_SREG = 0x7 + NFT_META_LEN = 0x0 + NFT_META_PROTOCOL = 0x1 + NFT_META_PRIORITY = 0x2 + NFT_META_MARK = 0x3 + NFT_META_IIF = 0x4 + NFT_META_OIF = 0x5 + NFT_META_IIFNAME = 0x6 + NFT_META_OIFNAME = 0x7 + NFT_META_IIFTYPE = 0x8 + NFT_META_OIFTYPE = 0x9 + NFT_META_SKUID = 0xa + NFT_META_SKGID = 0xb + NFT_META_NFTRACE = 0xc + NFT_META_RTCLASSID = 0xd + NFT_META_SECMARK = 0xe + NFT_META_NFPROTO = 0xf + NFT_META_L4PROTO = 0x10 + NFT_META_BRI_IIFNAME = 0x11 + NFT_META_BRI_OIFNAME = 0x12 + NFT_META_PKTTYPE = 0x13 + NFT_META_CPU = 0x14 + NFT_META_IIFGROUP = 0x15 + NFT_META_OIFGROUP = 0x16 + NFT_META_CGROUP = 0x17 + NFT_META_PRANDOM = 0x18 + NFT_RT_CLASSID = 0x0 + NFT_RT_NEXTHOP4 = 0x1 + NFT_RT_NEXTHOP6 = 0x2 + NFT_RT_TCPMSS = 0x3 + NFT_HASH_JENKINS = 0x0 + NFT_HASH_SYM = 0x1 + NFTA_HASH_UNSPEC = 0x0 + NFTA_HASH_SREG = 0x1 + NFTA_HASH_DREG = 0x2 + NFTA_HASH_LEN = 0x3 + NFTA_HASH_MODULUS = 0x4 + NFTA_HASH_SEED = 0x5 + NFTA_HASH_OFFSET = 0x6 + NFTA_HASH_TYPE = 0x7 + NFTA_META_UNSPEC = 0x0 + NFTA_META_DREG = 0x1 + NFTA_META_KEY = 0x2 + NFTA_META_SREG = 0x3 + NFTA_RT_UNSPEC = 0x0 + NFTA_RT_DREG = 0x1 + NFTA_RT_KEY = 0x2 + NFT_CT_STATE = 0x0 + NFT_CT_DIRECTION = 0x1 + NFT_CT_STATUS = 0x2 + NFT_CT_MARK = 0x3 + NFT_CT_SECMARK = 0x4 + NFT_CT_EXPIRATION = 0x5 + NFT_CT_HELPER = 0x6 + NFT_CT_L3PROTOCOL = 0x7 + NFT_CT_SRC = 0x8 + NFT_CT_DST = 0x9 + NFT_CT_PROTOCOL = 0xa + NFT_CT_PROTO_SRC = 0xb + NFT_CT_PROTO_DST = 0xc + NFT_CT_LABELS = 0xd + NFT_CT_PKTS = 0xe + NFT_CT_BYTES = 0xf + NFT_CT_AVGPKT = 0x10 + NFT_CT_ZONE = 0x11 + NFT_CT_EVENTMASK = 0x12 + NFTA_CT_UNSPEC = 0x0 + NFTA_CT_DREG = 0x1 + NFTA_CT_KEY = 0x2 + NFTA_CT_DIRECTION = 0x3 + NFTA_CT_SREG = 0x4 + NFT_LIMIT_PKTS = 0x0 + NFT_LIMIT_PKT_BYTES = 0x1 + NFT_LIMIT_F_INV = 0x1 + NFTA_LIMIT_UNSPEC = 0x0 + NFTA_LIMIT_RATE = 0x1 + NFTA_LIMIT_UNIT = 0x2 + NFTA_LIMIT_BURST = 0x3 + NFTA_LIMIT_TYPE = 0x4 + NFTA_LIMIT_FLAGS = 0x5 + NFTA_LIMIT_PAD = 0x6 + NFTA_COUNTER_UNSPEC = 0x0 + NFTA_COUNTER_BYTES = 0x1 + NFTA_COUNTER_PACKETS = 0x2 + NFTA_COUNTER_PAD = 0x3 + NFTA_LOG_UNSPEC = 0x0 + NFTA_LOG_GROUP = 0x1 + NFTA_LOG_PREFIX = 0x2 + NFTA_LOG_SNAPLEN = 0x3 + NFTA_LOG_QTHRESHOLD = 0x4 + NFTA_LOG_LEVEL = 0x5 + NFTA_LOG_FLAGS = 0x6 + NFTA_QUEUE_UNSPEC = 0x0 + NFTA_QUEUE_NUM = 0x1 + NFTA_QUEUE_TOTAL = 0x2 + NFTA_QUEUE_FLAGS = 0x3 + NFTA_QUEUE_SREG_QNUM = 0x4 + NFT_QUOTA_F_INV = 0x1 + NFT_QUOTA_F_DEPLETED = 0x2 + NFTA_QUOTA_UNSPEC = 0x0 + NFTA_QUOTA_BYTES = 0x1 + NFTA_QUOTA_FLAGS = 0x2 + NFTA_QUOTA_PAD = 0x3 + NFTA_QUOTA_CONSUMED = 0x4 + NFT_REJECT_ICMP_UNREACH = 0x0 + NFT_REJECT_TCP_RST = 0x1 + NFT_REJECT_ICMPX_UNREACH = 0x2 + NFT_REJECT_ICMPX_NO_ROUTE = 0x0 + NFT_REJECT_ICMPX_PORT_UNREACH = 0x1 + NFT_REJECT_ICMPX_HOST_UNREACH = 0x2 + NFT_REJECT_ICMPX_ADMIN_PROHIBITED = 0x3 + NFTA_REJECT_UNSPEC = 0x0 + NFTA_REJECT_TYPE = 0x1 + NFTA_REJECT_ICMP_CODE = 0x2 + NFT_NAT_SNAT = 0x0 + NFT_NAT_DNAT = 0x1 + NFTA_NAT_UNSPEC = 0x0 + NFTA_NAT_TYPE = 0x1 + NFTA_NAT_FAMILY = 0x2 + NFTA_NAT_REG_ADDR_MIN = 0x3 + NFTA_NAT_REG_ADDR_MAX = 0x4 + NFTA_NAT_REG_PROTO_MIN = 0x5 + NFTA_NAT_REG_PROTO_MAX = 0x6 + NFTA_NAT_FLAGS = 0x7 + NFTA_MASQ_UNSPEC = 0x0 + NFTA_MASQ_FLAGS = 0x1 + NFTA_MASQ_REG_PROTO_MIN = 0x2 + NFTA_MASQ_REG_PROTO_MAX = 0x3 + NFTA_REDIR_UNSPEC = 0x0 + NFTA_REDIR_REG_PROTO_MIN = 0x1 + NFTA_REDIR_REG_PROTO_MAX = 0x2 + NFTA_REDIR_FLAGS = 0x3 + NFTA_DUP_UNSPEC = 0x0 + NFTA_DUP_SREG_ADDR = 0x1 + NFTA_DUP_SREG_DEV = 0x2 + NFTA_FWD_UNSPEC = 0x0 + NFTA_FWD_SREG_DEV = 0x1 + NFTA_OBJREF_UNSPEC = 0x0 + NFTA_OBJREF_IMM_TYPE = 0x1 + NFTA_OBJREF_IMM_NAME = 0x2 + NFTA_OBJREF_SET_SREG = 0x3 + NFTA_OBJREF_SET_NAME = 0x4 + NFTA_OBJREF_SET_ID = 0x5 + NFTA_GEN_UNSPEC = 0x0 + NFTA_GEN_ID = 0x1 + NFTA_GEN_PROC_PID = 0x2 + NFTA_GEN_PROC_NAME = 0x3 + NFTA_FIB_UNSPEC = 0x0 + NFTA_FIB_DREG = 0x1 + NFTA_FIB_RESULT = 0x2 + NFTA_FIB_FLAGS = 0x3 + NFT_FIB_RESULT_UNSPEC = 0x0 + NFT_FIB_RESULT_OIF = 0x1 + NFT_FIB_RESULT_OIFNAME = 0x2 + NFT_FIB_RESULT_ADDRTYPE = 0x3 + NFTA_FIB_F_SADDR = 0x1 + NFTA_FIB_F_DADDR = 0x2 + NFTA_FIB_F_MARK = 0x4 + NFTA_FIB_F_IIF = 0x8 + NFTA_FIB_F_OIF = 0x10 + NFTA_FIB_F_PRESENT = 0x20 + NFTA_CT_HELPER_UNSPEC = 0x0 + NFTA_CT_HELPER_NAME = 0x1 + NFTA_CT_HELPER_L3PROTO = 0x2 + NFTA_CT_HELPER_L4PROTO = 0x3 + NFTA_OBJ_UNSPEC = 0x0 + NFTA_OBJ_TABLE = 0x1 + NFTA_OBJ_NAME = 0x2 + NFTA_OBJ_TYPE = 0x3 + NFTA_OBJ_DATA = 0x4 + NFTA_OBJ_USE = 0x5 + NFTA_TRACE_UNSPEC = 0x0 + NFTA_TRACE_TABLE = 0x1 + NFTA_TRACE_CHAIN = 0x2 + NFTA_TRACE_RULE_HANDLE = 0x3 + NFTA_TRACE_TYPE = 0x4 + NFTA_TRACE_VERDICT = 0x5 + NFTA_TRACE_ID = 0x6 + NFTA_TRACE_LL_HEADER = 0x7 + NFTA_TRACE_NETWORK_HEADER = 0x8 + NFTA_TRACE_TRANSPORT_HEADER = 0x9 + NFTA_TRACE_IIF = 0xa + NFTA_TRACE_IIFTYPE = 0xb + NFTA_TRACE_OIF = 0xc + NFTA_TRACE_OIFTYPE = 0xd + NFTA_TRACE_MARK = 0xe + NFTA_TRACE_NFPROTO = 0xf + NFTA_TRACE_POLICY = 0x10 + NFTA_TRACE_PAD = 0x11 + NFT_TRACETYPE_UNSPEC = 0x0 + NFT_TRACETYPE_POLICY = 0x1 + NFT_TRACETYPE_RETURN = 0x2 + NFT_TRACETYPE_RULE = 0x3 + NFTA_NG_UNSPEC = 0x0 + NFTA_NG_DREG = 0x1 + NFTA_NG_MODULUS = 0x2 + NFTA_NG_TYPE = 0x3 + NFTA_NG_OFFSET = 0x4 + NFT_NG_INCREMENTAL = 0x0 + NFT_NG_RANDOM = 0x1 +) + +type RTCTime struct { + Sec int32 + Min int32 + Hour int32 + Mday int32 + Mon int32 + Year int32 + Wday int32 + Yday int32 + Isdst int32 +} + +type RTCWkAlrm struct { + Enabled uint8 + Pending uint8 + Time RTCTime +} + +type RTCPLLInfo struct { + Ctrl int32 + Value int32 + Max int32 + Min int32 + Posmult int32 + Negmult int32 + Clock int64 +} + +type BlkpgIoctlArg struct { + Op int32 + Flags int32 + Datalen int32 + Data *byte +} + +type BlkpgPartition struct { + Start int64 + Length int64 + Pno int32 + Devname [64]uint8 + Volname [64]uint8 + _ [4]byte +} + +const ( + BLKPG = 0x20001269 + BLKPG_ADD_PARTITION = 0x1 + BLKPG_DEL_PARTITION = 0x2 + BLKPG_RESIZE_PARTITION = 0x3 +) + +const ( + NETNSA_NONE = 0x0 + NETNSA_NSID = 0x1 + NETNSA_PID = 0x2 + NETNSA_FD = 0x3 +) + +type XDPRingOffset struct { + Producer uint64 + Consumer uint64 + Desc uint64 +} + +type XDPMmapOffsets struct { + Rx XDPRingOffset + Tx XDPRingOffset + Fr XDPRingOffset + Cr XDPRingOffset +} + +type XDPUmemReg struct { + Addr uint64 + Len uint64 + Size uint32 + Headroom uint32 +} + +type XDPStatistics struct { + Rx_dropped uint64 + Rx_invalid_descs uint64 + Tx_invalid_descs uint64 +} + +type XDPDesc struct { + Addr uint64 + Len uint32 + Options uint32 +} + +const ( + NCSI_CMD_UNSPEC = 0x0 + NCSI_CMD_PKG_INFO = 0x1 + NCSI_CMD_SET_INTERFACE = 0x2 + NCSI_CMD_CLEAR_INTERFACE = 0x3 + NCSI_ATTR_UNSPEC = 0x0 + NCSI_ATTR_IFINDEX = 0x1 + NCSI_ATTR_PACKAGE_LIST = 0x2 + NCSI_ATTR_PACKAGE_ID = 0x3 + NCSI_ATTR_CHANNEL_ID = 0x4 + NCSI_PKG_ATTR_UNSPEC = 0x0 + NCSI_PKG_ATTR = 0x1 + NCSI_PKG_ATTR_ID = 0x2 + NCSI_PKG_ATTR_FORCED = 0x3 + NCSI_PKG_ATTR_CHANNEL_LIST = 0x4 + NCSI_CHANNEL_ATTR_UNSPEC = 0x0 + NCSI_CHANNEL_ATTR = 0x1 + NCSI_CHANNEL_ATTR_ID = 0x2 + NCSI_CHANNEL_ATTR_VERSION_MAJOR = 0x3 + NCSI_CHANNEL_ATTR_VERSION_MINOR = 0x4 + NCSI_CHANNEL_ATTR_VERSION_STR = 0x5 + NCSI_CHANNEL_ATTR_LINK_STATE = 0x6 + NCSI_CHANNEL_ATTR_ACTIVE = 0x7 + NCSI_CHANNEL_ATTR_FORCED = 0x8 + NCSI_CHANNEL_ATTR_VLAN_LIST = 0x9 + NCSI_CHANNEL_ATTR_VLAN_ID = 0xa +) + +type ScmTimestamping struct { + Ts [3]Timespec +} + +const ( + SOF_TIMESTAMPING_TX_HARDWARE = 0x1 + SOF_TIMESTAMPING_TX_SOFTWARE = 0x2 + SOF_TIMESTAMPING_RX_HARDWARE = 0x4 + SOF_TIMESTAMPING_RX_SOFTWARE = 0x8 + SOF_TIMESTAMPING_SOFTWARE = 0x10 + SOF_TIMESTAMPING_SYS_HARDWARE = 0x20 + SOF_TIMESTAMPING_RAW_HARDWARE = 0x40 + SOF_TIMESTAMPING_OPT_ID = 0x80 + SOF_TIMESTAMPING_TX_SCHED = 0x100 + SOF_TIMESTAMPING_TX_ACK = 0x200 + SOF_TIMESTAMPING_OPT_CMSG = 0x400 + SOF_TIMESTAMPING_OPT_TSONLY = 0x800 + SOF_TIMESTAMPING_OPT_STATS = 0x1000 + SOF_TIMESTAMPING_OPT_PKTINFO = 0x2000 + SOF_TIMESTAMPING_OPT_TX_SWHW = 0x4000 + + SOF_TIMESTAMPING_LAST = 0x4000 + SOF_TIMESTAMPING_MASK = 0x7fff + + SCM_TSTAMP_SND = 0x0 + SCM_TSTAMP_SCHED = 0x1 + SCM_TSTAMP_ACK = 0x2 +) + +type SockExtendedErr struct { + Errno uint32 + Origin uint8 + Type uint8 + Code uint8 + Pad uint8 + Info uint32 + Data uint32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go new file mode 100644 index 0000000000..508885f11f --- /dev/null +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go @@ -0,0 +1,2046 @@ +// cgo -godefs -- -Wall -Werror -static -I/tmp/include linux/types.go | go run mkpost.go +// Code generated by the command above; see README.md. DO NOT EDIT. + +// +build riscv64,linux + +package unix + +const ( + SizeofPtr = 0x8 + SizeofShort = 0x2 + SizeofInt = 0x4 + SizeofLong = 0x8 + SizeofLongLong = 0x8 + PathMax = 0x1000 +) + +type ( + _C_short int16 + _C_int int32 + _C_long int64 + _C_long_long int64 +) + +type Timespec struct { + Sec int64 + Nsec int64 +} + +type Timeval struct { + Sec int64 + Usec int64 +} + +type Timex struct { + Modes uint32 + Offset int64 + Freq int64 + Maxerror int64 + Esterror int64 + Status int32 + Constant int64 + Precision int64 + Tolerance int64 + Time Timeval + Tick int64 + Ppsfreq int64 + Jitter int64 + Shift int32 + Stabil int64 + Jitcnt int64 + Calcnt int64 + Errcnt int64 + Stbcnt int64 + Tai int32 + _ [44]byte +} + +type Time_t int64 + +type Tms struct { + Utime int64 + Stime int64 + Cutime int64 + Cstime int64 +} + +type Utimbuf struct { + Actime int64 + Modtime int64 +} + +type Rusage struct { + Utime Timeval + Stime Timeval + Maxrss int64 + Ixrss int64 + Idrss int64 + Isrss int64 + Minflt int64 + Majflt int64 + Nswap int64 + Inblock int64 + Oublock int64 + Msgsnd int64 + Msgrcv int64 + Nsignals int64 + Nvcsw int64 + Nivcsw int64 +} + +type Rlimit struct { + Cur uint64 + Max uint64 +} + +type _Gid_t uint32 + +type Stat_t struct { + Dev uint64 + Ino uint64 + Mode uint32 + Nlink uint32 + Uid uint32 + Gid uint32 + Rdev uint64 + _ uint64 + Size int64 + Blksize int32 + _ int32 + Blocks int64 + Atim Timespec + Mtim Timespec + Ctim Timespec + _ [2]int32 +} + +type StatxTimestamp struct { + Sec int64 + Nsec uint32 + _ int32 +} + +type Statx_t struct { + Mask uint32 + Blksize uint32 + Attributes uint64 + Nlink uint32 + Uid uint32 + Gid uint32 + Mode uint16 + _ [1]uint16 + Ino uint64 + Size uint64 + Blocks uint64 + Attributes_mask uint64 + Atime StatxTimestamp + Btime StatxTimestamp + Ctime StatxTimestamp + Mtime StatxTimestamp + Rdev_major uint32 + Rdev_minor uint32 + Dev_major uint32 + Dev_minor uint32 + _ [14]uint64 +} + +type Dirent struct { + Ino uint64 + Off int64 + Reclen uint16 + Type uint8 + Name [256]uint8 + _ [5]byte +} + +type Fsid struct { + Val [2]int32 +} + +type Flock_t struct { + Type int16 + Whence int16 + Start int64 + Len int64 + Pid int32 + _ [4]byte +} + +type FscryptPolicy struct { + Version uint8 + Contents_encryption_mode uint8 + Filenames_encryption_mode uint8 + Flags uint8 + Master_key_descriptor [8]uint8 +} + +type FscryptKey struct { + Mode uint32 + Raw [64]uint8 + Size uint32 +} + +type KeyctlDHParams struct { + Private int32 + Prime int32 + Base int32 +} + +const ( + FADV_NORMAL = 0x0 + FADV_RANDOM = 0x1 + FADV_SEQUENTIAL = 0x2 + FADV_WILLNEED = 0x3 + FADV_DONTNEED = 0x4 + FADV_NOREUSE = 0x5 +) + +type RawSockaddrInet4 struct { + Family uint16 + Port uint16 + Addr [4]byte /* in_addr */ + Zero [8]uint8 +} + +type RawSockaddrInet6 struct { + Family uint16 + Port uint16 + Flowinfo uint32 + Addr [16]byte /* in6_addr */ + Scope_id uint32 +} + +type RawSockaddrUnix struct { + Family uint16 + Path [108]int8 +} + +type RawSockaddrLinklayer struct { + Family uint16 + Protocol uint16 + Ifindex int32 + Hatype uint16 + Pkttype uint8 + Halen uint8 + Addr [8]uint8 +} + +type RawSockaddrNetlink struct { + Family uint16 + Pad uint16 + Pid uint32 + Groups uint32 +} + +type RawSockaddrHCI struct { + Family uint16 + Dev uint16 + Channel uint16 +} + +type RawSockaddrL2 struct { + Family uint16 + Psm uint16 + Bdaddr [6]uint8 + Cid uint16 + Bdaddr_type uint8 + _ [1]byte +} + +type RawSockaddrRFCOMM struct { + Family uint16 + Bdaddr [6]uint8 + Channel uint8 + _ [1]byte +} + +type RawSockaddrCAN struct { + Family uint16 + Ifindex int32 + Addr [8]byte +} + +type RawSockaddrALG struct { + Family uint16 + Type [14]uint8 + Feat uint32 + Mask uint32 + Name [64]uint8 +} + +type RawSockaddrVM struct { + Family uint16 + Reserved1 uint16 + Port uint32 + Cid uint32 + Zero [4]uint8 +} + +type RawSockaddrXDP struct { + Family uint16 + Flags uint16 + Ifindex uint32 + Queue_id uint32 + Shared_umem_fd uint32 +} + +type RawSockaddrPPPoX [0x1e]byte + +type RawSockaddr struct { + Family uint16 + Data [14]uint8 +} + +type RawSockaddrAny struct { + Addr RawSockaddr + Pad [96]uint8 +} + +type _Socklen uint32 + +type Linger struct { + Onoff int32 + Linger int32 +} + +type Iovec struct { + Base *byte + Len uint64 +} + +type IPMreq struct { + Multiaddr [4]byte /* in_addr */ + Interface [4]byte /* in_addr */ +} + +type IPMreqn struct { + Multiaddr [4]byte /* in_addr */ + Address [4]byte /* in_addr */ + Ifindex int32 +} + +type IPv6Mreq struct { + Multiaddr [16]byte /* in6_addr */ + Interface uint32 +} + +type PacketMreq struct { + Ifindex int32 + Type uint16 + Alen uint16 + Address [8]uint8 +} + +type Msghdr struct { + Name *byte + Namelen uint32 + Iov *Iovec + Iovlen uint64 + Control *byte + Controllen uint64 + Flags int32 + _ [4]byte +} + +type Cmsghdr struct { + Len uint64 + Level int32 + Type int32 +} + +type Inet4Pktinfo struct { + Ifindex int32 + Spec_dst [4]byte /* in_addr */ + Addr [4]byte /* in_addr */ +} + +type Inet6Pktinfo struct { + Addr [16]byte /* in6_addr */ + Ifindex uint32 +} + +type IPv6MTUInfo struct { + Addr RawSockaddrInet6 + Mtu uint32 +} + +type ICMPv6Filter struct { + Data [8]uint32 +} + +type Ucred struct { + Pid int32 + Uid uint32 + Gid uint32 +} + +type TCPInfo struct { + State uint8 + Ca_state uint8 + Retransmits uint8 + Probes uint8 + Backoff uint8 + Options uint8 + Rto uint32 + Ato uint32 + Snd_mss uint32 + Rcv_mss uint32 + Unacked uint32 + Sacked uint32 + Lost uint32 + Retrans uint32 + Fackets uint32 + Last_data_sent uint32 + Last_ack_sent uint32 + Last_data_recv uint32 + Last_ack_recv uint32 + Pmtu uint32 + Rcv_ssthresh uint32 + Rtt uint32 + Rttvar uint32 + Snd_ssthresh uint32 + Snd_cwnd uint32 + Advmss uint32 + Reordering uint32 + Rcv_rtt uint32 + Rcv_space uint32 + Total_retrans uint32 +} + +const ( + SizeofSockaddrInet4 = 0x10 + SizeofSockaddrInet6 = 0x1c + SizeofSockaddrAny = 0x70 + SizeofSockaddrUnix = 0x6e + SizeofSockaddrLinklayer = 0x14 + SizeofSockaddrNetlink = 0xc + SizeofSockaddrHCI = 0x6 + SizeofSockaddrL2 = 0xe + SizeofSockaddrRFCOMM = 0xa + SizeofSockaddrCAN = 0x10 + SizeofSockaddrALG = 0x58 + SizeofSockaddrVM = 0x10 + SizeofSockaddrXDP = 0x10 + SizeofSockaddrPPPoX = 0x1e + SizeofLinger = 0x8 + SizeofIovec = 0x10 + SizeofIPMreq = 0x8 + SizeofIPMreqn = 0xc + SizeofIPv6Mreq = 0x14 + SizeofPacketMreq = 0x10 + SizeofMsghdr = 0x38 + SizeofCmsghdr = 0x10 + SizeofInet4Pktinfo = 0xc + SizeofInet6Pktinfo = 0x14 + SizeofIPv6MTUInfo = 0x20 + SizeofICMPv6Filter = 0x20 + SizeofUcred = 0xc + SizeofTCPInfo = 0x68 +) + +const ( + IFA_UNSPEC = 0x0 + IFA_ADDRESS = 0x1 + IFA_LOCAL = 0x2 + IFA_LABEL = 0x3 + IFA_BROADCAST = 0x4 + IFA_ANYCAST = 0x5 + IFA_CACHEINFO = 0x6 + IFA_MULTICAST = 0x7 + IFLA_UNSPEC = 0x0 + IFLA_ADDRESS = 0x1 + IFLA_BROADCAST = 0x2 + IFLA_IFNAME = 0x3 + IFLA_INFO_KIND = 0x1 + IFLA_MTU = 0x4 + IFLA_LINK = 0x5 + IFLA_QDISC = 0x6 + IFLA_STATS = 0x7 + IFLA_COST = 0x8 + IFLA_PRIORITY = 0x9 + IFLA_MASTER = 0xa + IFLA_WIRELESS = 0xb + IFLA_PROTINFO = 0xc + IFLA_TXQLEN = 0xd + IFLA_MAP = 0xe + IFLA_WEIGHT = 0xf + IFLA_OPERSTATE = 0x10 + IFLA_LINKMODE = 0x11 + IFLA_LINKINFO = 0x12 + IFLA_NET_NS_PID = 0x13 + IFLA_IFALIAS = 0x14 + IFLA_NUM_VF = 0x15 + IFLA_VFINFO_LIST = 0x16 + IFLA_STATS64 = 0x17 + IFLA_VF_PORTS = 0x18 + IFLA_PORT_SELF = 0x19 + IFLA_AF_SPEC = 0x1a + IFLA_GROUP = 0x1b + IFLA_NET_NS_FD = 0x1c + IFLA_EXT_MASK = 0x1d + IFLA_PROMISCUITY = 0x1e + IFLA_NUM_TX_QUEUES = 0x1f + IFLA_NUM_RX_QUEUES = 0x20 + IFLA_CARRIER = 0x21 + IFLA_PHYS_PORT_ID = 0x22 + IFLA_CARRIER_CHANGES = 0x23 + IFLA_PHYS_SWITCH_ID = 0x24 + IFLA_LINK_NETNSID = 0x25 + IFLA_PHYS_PORT_NAME = 0x26 + IFLA_PROTO_DOWN = 0x27 + IFLA_GSO_MAX_SEGS = 0x28 + IFLA_GSO_MAX_SIZE = 0x29 + IFLA_PAD = 0x2a + IFLA_XDP = 0x2b + IFLA_EVENT = 0x2c + IFLA_NEW_NETNSID = 0x2d + IFLA_IF_NETNSID = 0x2e + IFLA_MAX = 0x33 + RT_SCOPE_UNIVERSE = 0x0 + RT_SCOPE_SITE = 0xc8 + RT_SCOPE_LINK = 0xfd + RT_SCOPE_HOST = 0xfe + RT_SCOPE_NOWHERE = 0xff + RT_TABLE_UNSPEC = 0x0 + RT_TABLE_COMPAT = 0xfc + RT_TABLE_DEFAULT = 0xfd + RT_TABLE_MAIN = 0xfe + RT_TABLE_LOCAL = 0xff + RT_TABLE_MAX = 0xffffffff + RTA_UNSPEC = 0x0 + RTA_DST = 0x1 + RTA_SRC = 0x2 + RTA_IIF = 0x3 + RTA_OIF = 0x4 + RTA_GATEWAY = 0x5 + RTA_PRIORITY = 0x6 + RTA_PREFSRC = 0x7 + RTA_METRICS = 0x8 + RTA_MULTIPATH = 0x9 + RTA_FLOW = 0xb + RTA_CACHEINFO = 0xc + RTA_TABLE = 0xf + RTA_MARK = 0x10 + RTA_MFC_STATS = 0x11 + RTA_VIA = 0x12 + RTA_NEWDST = 0x13 + RTA_PREF = 0x14 + RTA_ENCAP_TYPE = 0x15 + RTA_ENCAP = 0x16 + RTA_EXPIRES = 0x17 + RTA_PAD = 0x18 + RTA_UID = 0x19 + RTA_TTL_PROPAGATE = 0x1a + RTA_IP_PROTO = 0x1b + RTA_SPORT = 0x1c + RTA_DPORT = 0x1d + RTN_UNSPEC = 0x0 + RTN_UNICAST = 0x1 + RTN_LOCAL = 0x2 + RTN_BROADCAST = 0x3 + RTN_ANYCAST = 0x4 + RTN_MULTICAST = 0x5 + RTN_BLACKHOLE = 0x6 + RTN_UNREACHABLE = 0x7 + RTN_PROHIBIT = 0x8 + RTN_THROW = 0x9 + RTN_NAT = 0xa + RTN_XRESOLVE = 0xb + RTNLGRP_NONE = 0x0 + RTNLGRP_LINK = 0x1 + RTNLGRP_NOTIFY = 0x2 + RTNLGRP_NEIGH = 0x3 + RTNLGRP_TC = 0x4 + RTNLGRP_IPV4_IFADDR = 0x5 + RTNLGRP_IPV4_MROUTE = 0x6 + RTNLGRP_IPV4_ROUTE = 0x7 + RTNLGRP_IPV4_RULE = 0x8 + RTNLGRP_IPV6_IFADDR = 0x9 + RTNLGRP_IPV6_MROUTE = 0xa + RTNLGRP_IPV6_ROUTE = 0xb + RTNLGRP_IPV6_IFINFO = 0xc + RTNLGRP_IPV6_PREFIX = 0x12 + RTNLGRP_IPV6_RULE = 0x13 + RTNLGRP_ND_USEROPT = 0x14 + SizeofNlMsghdr = 0x10 + SizeofNlMsgerr = 0x14 + SizeofRtGenmsg = 0x1 + SizeofNlAttr = 0x4 + SizeofRtAttr = 0x4 + SizeofIfInfomsg = 0x10 + SizeofIfAddrmsg = 0x8 + SizeofRtMsg = 0xc + SizeofRtNexthop = 0x8 +) + +type NlMsghdr struct { + Len uint32 + Type uint16 + Flags uint16 + Seq uint32 + Pid uint32 +} + +type NlMsgerr struct { + Error int32 + Msg NlMsghdr +} + +type RtGenmsg struct { + Family uint8 +} + +type NlAttr struct { + Len uint16 + Type uint16 +} + +type RtAttr struct { + Len uint16 + Type uint16 +} + +type IfInfomsg struct { + Family uint8 + _ uint8 + Type uint16 + Index int32 + Flags uint32 + Change uint32 +} + +type IfAddrmsg struct { + Family uint8 + Prefixlen uint8 + Flags uint8 + Scope uint8 + Index uint32 +} + +type RtMsg struct { + Family uint8 + Dst_len uint8 + Src_len uint8 + Tos uint8 + Table uint8 + Protocol uint8 + Scope uint8 + Type uint8 + Flags uint32 +} + +type RtNexthop struct { + Len uint16 + Flags uint8 + Hops uint8 + Ifindex int32 +} + +const ( + SizeofSockFilter = 0x8 + SizeofSockFprog = 0x10 +) + +type SockFilter struct { + Code uint16 + Jt uint8 + Jf uint8 + K uint32 +} + +type SockFprog struct { + Len uint16 + Filter *SockFilter +} + +type InotifyEvent struct { + Wd int32 + Mask uint32 + Cookie uint32 + Len uint32 +} + +const SizeofInotifyEvent = 0x10 + +type PtraceRegs struct { + Pc uint64 + Ra uint64 + Sp uint64 + Gp uint64 + Tp uint64 + T0 uint64 + T1 uint64 + T2 uint64 + S0 uint64 + S1 uint64 + A0 uint64 + A1 uint64 + A2 uint64 + A3 uint64 + A4 uint64 + A5 uint64 + A6 uint64 + A7 uint64 + S2 uint64 + S3 uint64 + S4 uint64 + S5 uint64 + S6 uint64 + S7 uint64 + S8 uint64 + S9 uint64 + S10 uint64 + S11 uint64 + T3 uint64 + T4 uint64 + T5 uint64 + T6 uint64 +} + +type FdSet struct { + Bits [16]int64 +} + +type Sysinfo_t struct { + Uptime int64 + Loads [3]uint64 + Totalram uint64 + Freeram uint64 + Sharedram uint64 + Bufferram uint64 + Totalswap uint64 + Freeswap uint64 + Procs uint16 + Pad uint16 + Totalhigh uint64 + Freehigh uint64 + Unit uint32 + _ [0]uint8 + _ [4]byte +} + +type Utsname struct { + Sysname [65]byte + Nodename [65]byte + Release [65]byte + Version [65]byte + Machine [65]byte + Domainname [65]byte +} + +type Ustat_t struct { + Tfree int32 + Tinode uint64 + Fname [6]uint8 + Fpack [6]uint8 + _ [4]byte +} + +type EpollEvent struct { + Events uint32 + Fd int32 + Pad int32 +} + +const ( + AT_EMPTY_PATH = 0x1000 + AT_FDCWD = -0x64 + AT_NO_AUTOMOUNT = 0x800 + AT_REMOVEDIR = 0x200 + + AT_STATX_SYNC_AS_STAT = 0x0 + AT_STATX_FORCE_SYNC = 0x2000 + AT_STATX_DONT_SYNC = 0x4000 + + AT_SYMLINK_FOLLOW = 0x400 + AT_SYMLINK_NOFOLLOW = 0x100 + + AT_EACCESS = 0x200 +) + +type PollFd struct { + Fd int32 + Events int16 + Revents int16 +} + +const ( + POLLIN = 0x1 + POLLPRI = 0x2 + POLLOUT = 0x4 + POLLRDHUP = 0x2000 + POLLERR = 0x8 + POLLHUP = 0x10 + POLLNVAL = 0x20 +) + +type Sigset_t struct { + Val [16]uint64 +} + +type SignalfdSiginfo struct { + Signo uint32 + Errno int32 + Code int32 + Pid uint32 + Uid uint32 + Fd int32 + Tid uint32 + Band uint32 + Overrun uint32 + Trapno uint32 + Status int32 + Int int32 + Ptr uint64 + Utime uint64 + Stime uint64 + Addr uint64 + Addr_lsb uint16 + _ uint16 + Syscall int32 + Call_addr uint64 + Arch uint32 + _ [28]uint8 +} + +const PERF_IOC_FLAG_GROUP = 0x1 + +type Termios struct { + Iflag uint32 + Oflag uint32 + Cflag uint32 + Lflag uint32 + Line uint8 + Cc [19]uint8 + Ispeed uint32 + Ospeed uint32 +} + +type Winsize struct { + Row uint16 + Col uint16 + Xpixel uint16 + Ypixel uint16 +} + +type Taskstats struct { + Version uint16 + Ac_exitcode uint32 + Ac_flag uint8 + Ac_nice uint8 + Cpu_count uint64 + Cpu_delay_total uint64 + Blkio_count uint64 + Blkio_delay_total uint64 + Swapin_count uint64 + Swapin_delay_total uint64 + Cpu_run_real_total uint64 + Cpu_run_virtual_total uint64 + Ac_comm [32]uint8 + Ac_sched uint8 + Ac_pad [3]uint8 + _ [4]byte + Ac_uid uint32 + Ac_gid uint32 + Ac_pid uint32 + Ac_ppid uint32 + Ac_btime uint32 + Ac_etime uint64 + Ac_utime uint64 + Ac_stime uint64 + Ac_minflt uint64 + Ac_majflt uint64 + Coremem uint64 + Virtmem uint64 + Hiwater_rss uint64 + Hiwater_vm uint64 + Read_char uint64 + Write_char uint64 + Read_syscalls uint64 + Write_syscalls uint64 + Read_bytes uint64 + Write_bytes uint64 + Cancelled_write_bytes uint64 + Nvcsw uint64 + Nivcsw uint64 + Ac_utimescaled uint64 + Ac_stimescaled uint64 + Cpu_scaled_run_real_total uint64 + Freepages_count uint64 + Freepages_delay_total uint64 + Thrashing_count uint64 + Thrashing_delay_total uint64 +} + +const ( + TASKSTATS_CMD_UNSPEC = 0x0 + TASKSTATS_CMD_GET = 0x1 + TASKSTATS_CMD_NEW = 0x2 + TASKSTATS_TYPE_UNSPEC = 0x0 + TASKSTATS_TYPE_PID = 0x1 + TASKSTATS_TYPE_TGID = 0x2 + TASKSTATS_TYPE_STATS = 0x3 + TASKSTATS_TYPE_AGGR_PID = 0x4 + TASKSTATS_TYPE_AGGR_TGID = 0x5 + TASKSTATS_TYPE_NULL = 0x6 + TASKSTATS_CMD_ATTR_UNSPEC = 0x0 + TASKSTATS_CMD_ATTR_PID = 0x1 + TASKSTATS_CMD_ATTR_TGID = 0x2 + TASKSTATS_CMD_ATTR_REGISTER_CPUMASK = 0x3 + TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK = 0x4 +) + +type CGroupStats struct { + Sleeping uint64 + Running uint64 + Stopped uint64 + Uninterruptible uint64 + Io_wait uint64 +} + +const ( + CGROUPSTATS_CMD_UNSPEC = 0x3 + CGROUPSTATS_CMD_GET = 0x4 + CGROUPSTATS_CMD_NEW = 0x5 + CGROUPSTATS_TYPE_UNSPEC = 0x0 + CGROUPSTATS_TYPE_CGROUP_STATS = 0x1 + CGROUPSTATS_CMD_ATTR_UNSPEC = 0x0 + CGROUPSTATS_CMD_ATTR_FD = 0x1 +) + +type Genlmsghdr struct { + Cmd uint8 + Version uint8 + Reserved uint16 +} + +const ( + CTRL_CMD_UNSPEC = 0x0 + CTRL_CMD_NEWFAMILY = 0x1 + CTRL_CMD_DELFAMILY = 0x2 + CTRL_CMD_GETFAMILY = 0x3 + CTRL_CMD_NEWOPS = 0x4 + CTRL_CMD_DELOPS = 0x5 + CTRL_CMD_GETOPS = 0x6 + CTRL_CMD_NEWMCAST_GRP = 0x7 + CTRL_CMD_DELMCAST_GRP = 0x8 + CTRL_CMD_GETMCAST_GRP = 0x9 + CTRL_ATTR_UNSPEC = 0x0 + CTRL_ATTR_FAMILY_ID = 0x1 + CTRL_ATTR_FAMILY_NAME = 0x2 + CTRL_ATTR_VERSION = 0x3 + CTRL_ATTR_HDRSIZE = 0x4 + CTRL_ATTR_MAXATTR = 0x5 + CTRL_ATTR_OPS = 0x6 + CTRL_ATTR_MCAST_GROUPS = 0x7 + CTRL_ATTR_OP_UNSPEC = 0x0 + CTRL_ATTR_OP_ID = 0x1 + CTRL_ATTR_OP_FLAGS = 0x2 + CTRL_ATTR_MCAST_GRP_UNSPEC = 0x0 + CTRL_ATTR_MCAST_GRP_NAME = 0x1 + CTRL_ATTR_MCAST_GRP_ID = 0x2 +) + +type cpuMask uint64 + +const ( + _CPU_SETSIZE = 0x400 + _NCPUBITS = 0x40 +) + +const ( + BDADDR_BREDR = 0x0 + BDADDR_LE_PUBLIC = 0x1 + BDADDR_LE_RANDOM = 0x2 +) + +type PerfEventAttr struct { + Type uint32 + Size uint32 + Config uint64 + Sample uint64 + Sample_type uint64 + Read_format uint64 + Bits uint64 + Wakeup uint32 + Bp_type uint32 + Ext1 uint64 + Ext2 uint64 + Branch_sample_type uint64 + Sample_regs_user uint64 + Sample_stack_user uint32 + Clockid int32 + Sample_regs_intr uint64 + Aux_watermark uint32 + _ uint32 +} + +type PerfEventMmapPage struct { + Version uint32 + Compat_version uint32 + Lock uint32 + Index uint32 + Offset int64 + Time_enabled uint64 + Time_running uint64 + Capabilities uint64 + Pmc_width uint16 + Time_shift uint16 + Time_mult uint32 + Time_offset uint64 + Time_zero uint64 + Size uint32 + _ [948]uint8 + Data_head uint64 + Data_tail uint64 + Data_offset uint64 + Data_size uint64 + Aux_head uint64 + Aux_tail uint64 + Aux_offset uint64 + Aux_size uint64 +} + +const ( + PerfBitDisabled uint64 = CBitFieldMaskBit0 + PerfBitInherit = CBitFieldMaskBit1 + PerfBitPinned = CBitFieldMaskBit2 + PerfBitExclusive = CBitFieldMaskBit3 + PerfBitExcludeUser = CBitFieldMaskBit4 + PerfBitExcludeKernel = CBitFieldMaskBit5 + PerfBitExcludeHv = CBitFieldMaskBit6 + PerfBitExcludeIdle = CBitFieldMaskBit7 + PerfBitMmap = CBitFieldMaskBit8 + PerfBitComm = CBitFieldMaskBit9 + PerfBitFreq = CBitFieldMaskBit10 + PerfBitInheritStat = CBitFieldMaskBit11 + PerfBitEnableOnExec = CBitFieldMaskBit12 + PerfBitTask = CBitFieldMaskBit13 + PerfBitWatermark = CBitFieldMaskBit14 + PerfBitPreciseIPBit1 = CBitFieldMaskBit15 + PerfBitPreciseIPBit2 = CBitFieldMaskBit16 + PerfBitMmapData = CBitFieldMaskBit17 + PerfBitSampleIDAll = CBitFieldMaskBit18 + PerfBitExcludeHost = CBitFieldMaskBit19 + PerfBitExcludeGuest = CBitFieldMaskBit20 + PerfBitExcludeCallchainKernel = CBitFieldMaskBit21 + PerfBitExcludeCallchainUser = CBitFieldMaskBit22 + PerfBitMmap2 = CBitFieldMaskBit23 + PerfBitCommExec = CBitFieldMaskBit24 + PerfBitUseClockID = CBitFieldMaskBit25 + PerfBitContextSwitch = CBitFieldMaskBit26 +) + +const ( + PERF_TYPE_HARDWARE = 0x0 + PERF_TYPE_SOFTWARE = 0x1 + PERF_TYPE_TRACEPOINT = 0x2 + PERF_TYPE_HW_CACHE = 0x3 + PERF_TYPE_RAW = 0x4 + PERF_TYPE_BREAKPOINT = 0x5 + + PERF_COUNT_HW_CPU_CYCLES = 0x0 + PERF_COUNT_HW_INSTRUCTIONS = 0x1 + PERF_COUNT_HW_CACHE_REFERENCES = 0x2 + PERF_COUNT_HW_CACHE_MISSES = 0x3 + PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 0x4 + PERF_COUNT_HW_BRANCH_MISSES = 0x5 + PERF_COUNT_HW_BUS_CYCLES = 0x6 + PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 0x7 + PERF_COUNT_HW_STALLED_CYCLES_BACKEND = 0x8 + PERF_COUNT_HW_REF_CPU_CYCLES = 0x9 + + PERF_COUNT_HW_CACHE_L1D = 0x0 + PERF_COUNT_HW_CACHE_L1I = 0x1 + PERF_COUNT_HW_CACHE_LL = 0x2 + PERF_COUNT_HW_CACHE_DTLB = 0x3 + PERF_COUNT_HW_CACHE_ITLB = 0x4 + PERF_COUNT_HW_CACHE_BPU = 0x5 + PERF_COUNT_HW_CACHE_NODE = 0x6 + + PERF_COUNT_HW_CACHE_OP_READ = 0x0 + PERF_COUNT_HW_CACHE_OP_WRITE = 0x1 + PERF_COUNT_HW_CACHE_OP_PREFETCH = 0x2 + + PERF_COUNT_HW_CACHE_RESULT_ACCESS = 0x0 + PERF_COUNT_HW_CACHE_RESULT_MISS = 0x1 + + PERF_COUNT_SW_CPU_CLOCK = 0x0 + PERF_COUNT_SW_TASK_CLOCK = 0x1 + PERF_COUNT_SW_PAGE_FAULTS = 0x2 + PERF_COUNT_SW_CONTEXT_SWITCHES = 0x3 + PERF_COUNT_SW_CPU_MIGRATIONS = 0x4 + PERF_COUNT_SW_PAGE_FAULTS_MIN = 0x5 + PERF_COUNT_SW_PAGE_FAULTS_MAJ = 0x6 + PERF_COUNT_SW_ALIGNMENT_FAULTS = 0x7 + PERF_COUNT_SW_EMULATION_FAULTS = 0x8 + PERF_COUNT_SW_DUMMY = 0x9 + + PERF_SAMPLE_IP = 0x1 + PERF_SAMPLE_TID = 0x2 + PERF_SAMPLE_TIME = 0x4 + PERF_SAMPLE_ADDR = 0x8 + PERF_SAMPLE_READ = 0x10 + PERF_SAMPLE_CALLCHAIN = 0x20 + PERF_SAMPLE_ID = 0x40 + PERF_SAMPLE_CPU = 0x80 + PERF_SAMPLE_PERIOD = 0x100 + PERF_SAMPLE_STREAM_ID = 0x200 + PERF_SAMPLE_RAW = 0x400 + PERF_SAMPLE_BRANCH_STACK = 0x800 + + PERF_SAMPLE_BRANCH_USER = 0x1 + PERF_SAMPLE_BRANCH_KERNEL = 0x2 + PERF_SAMPLE_BRANCH_HV = 0x4 + PERF_SAMPLE_BRANCH_ANY = 0x8 + PERF_SAMPLE_BRANCH_ANY_CALL = 0x10 + PERF_SAMPLE_BRANCH_ANY_RETURN = 0x20 + PERF_SAMPLE_BRANCH_IND_CALL = 0x40 + + PERF_FORMAT_TOTAL_TIME_ENABLED = 0x1 + PERF_FORMAT_TOTAL_TIME_RUNNING = 0x2 + PERF_FORMAT_ID = 0x4 + PERF_FORMAT_GROUP = 0x8 + + PERF_RECORD_MMAP = 0x1 + PERF_RECORD_LOST = 0x2 + PERF_RECORD_COMM = 0x3 + PERF_RECORD_EXIT = 0x4 + PERF_RECORD_THROTTLE = 0x5 + PERF_RECORD_UNTHROTTLE = 0x6 + PERF_RECORD_FORK = 0x7 + PERF_RECORD_READ = 0x8 + PERF_RECORD_SAMPLE = 0x9 + + PERF_CONTEXT_HV = -0x20 + PERF_CONTEXT_KERNEL = -0x80 + PERF_CONTEXT_USER = -0x200 + + PERF_CONTEXT_GUEST = -0x800 + PERF_CONTEXT_GUEST_KERNEL = -0x880 + PERF_CONTEXT_GUEST_USER = -0xa00 + + PERF_FLAG_FD_NO_GROUP = 0x1 + PERF_FLAG_FD_OUTPUT = 0x2 + PERF_FLAG_PID_CGROUP = 0x4 +) + +const ( + CBitFieldMaskBit0 = 0x1 + CBitFieldMaskBit1 = 0x2 + CBitFieldMaskBit2 = 0x4 + CBitFieldMaskBit3 = 0x8 + CBitFieldMaskBit4 = 0x10 + CBitFieldMaskBit5 = 0x20 + CBitFieldMaskBit6 = 0x40 + CBitFieldMaskBit7 = 0x80 + CBitFieldMaskBit8 = 0x100 + CBitFieldMaskBit9 = 0x200 + CBitFieldMaskBit10 = 0x400 + CBitFieldMaskBit11 = 0x800 + CBitFieldMaskBit12 = 0x1000 + CBitFieldMaskBit13 = 0x2000 + CBitFieldMaskBit14 = 0x4000 + CBitFieldMaskBit15 = 0x8000 + CBitFieldMaskBit16 = 0x10000 + CBitFieldMaskBit17 = 0x20000 + CBitFieldMaskBit18 = 0x40000 + CBitFieldMaskBit19 = 0x80000 + CBitFieldMaskBit20 = 0x100000 + CBitFieldMaskBit21 = 0x200000 + CBitFieldMaskBit22 = 0x400000 + CBitFieldMaskBit23 = 0x800000 + CBitFieldMaskBit24 = 0x1000000 + CBitFieldMaskBit25 = 0x2000000 + CBitFieldMaskBit26 = 0x4000000 + CBitFieldMaskBit27 = 0x8000000 + CBitFieldMaskBit28 = 0x10000000 + CBitFieldMaskBit29 = 0x20000000 + CBitFieldMaskBit30 = 0x40000000 + CBitFieldMaskBit31 = 0x80000000 + CBitFieldMaskBit32 = 0x100000000 + CBitFieldMaskBit33 = 0x200000000 + CBitFieldMaskBit34 = 0x400000000 + CBitFieldMaskBit35 = 0x800000000 + CBitFieldMaskBit36 = 0x1000000000 + CBitFieldMaskBit37 = 0x2000000000 + CBitFieldMaskBit38 = 0x4000000000 + CBitFieldMaskBit39 = 0x8000000000 + CBitFieldMaskBit40 = 0x10000000000 + CBitFieldMaskBit41 = 0x20000000000 + CBitFieldMaskBit42 = 0x40000000000 + CBitFieldMaskBit43 = 0x80000000000 + CBitFieldMaskBit44 = 0x100000000000 + CBitFieldMaskBit45 = 0x200000000000 + CBitFieldMaskBit46 = 0x400000000000 + CBitFieldMaskBit47 = 0x800000000000 + CBitFieldMaskBit48 = 0x1000000000000 + CBitFieldMaskBit49 = 0x2000000000000 + CBitFieldMaskBit50 = 0x4000000000000 + CBitFieldMaskBit51 = 0x8000000000000 + CBitFieldMaskBit52 = 0x10000000000000 + CBitFieldMaskBit53 = 0x20000000000000 + CBitFieldMaskBit54 = 0x40000000000000 + CBitFieldMaskBit55 = 0x80000000000000 + CBitFieldMaskBit56 = 0x100000000000000 + CBitFieldMaskBit57 = 0x200000000000000 + CBitFieldMaskBit58 = 0x400000000000000 + CBitFieldMaskBit59 = 0x800000000000000 + CBitFieldMaskBit60 = 0x1000000000000000 + CBitFieldMaskBit61 = 0x2000000000000000 + CBitFieldMaskBit62 = 0x4000000000000000 + CBitFieldMaskBit63 = 0x8000000000000000 +) + +type SockaddrStorage struct { + Family uint16 + _ [118]uint8 + _ uint64 +} + +type TCPMD5Sig struct { + Addr SockaddrStorage + Flags uint8 + Prefixlen uint8 + Keylen uint16 + _ uint32 + Key [80]uint8 +} + +type HDDriveCmdHdr struct { + Command uint8 + Number uint8 + Feature uint8 + Count uint8 +} + +type HDGeometry struct { + Heads uint8 + Sectors uint8 + Cylinders uint16 + Start uint64 +} + +type HDDriveID struct { + Config uint16 + Cyls uint16 + Reserved2 uint16 + Heads uint16 + Track_bytes uint16 + Sector_bytes uint16 + Sectors uint16 + Vendor0 uint16 + Vendor1 uint16 + Vendor2 uint16 + Serial_no [20]uint8 + Buf_type uint16 + Buf_size uint16 + Ecc_bytes uint16 + Fw_rev [8]uint8 + Model [40]uint8 + Max_multsect uint8 + Vendor3 uint8 + Dword_io uint16 + Vendor4 uint8 + Capability uint8 + Reserved50 uint16 + Vendor5 uint8 + TPIO uint8 + Vendor6 uint8 + TDMA uint8 + Field_valid uint16 + Cur_cyls uint16 + Cur_heads uint16 + Cur_sectors uint16 + Cur_capacity0 uint16 + Cur_capacity1 uint16 + Multsect uint8 + Multsect_valid uint8 + Lba_capacity uint32 + Dma_1word uint16 + Dma_mword uint16 + Eide_pio_modes uint16 + Eide_dma_min uint16 + Eide_dma_time uint16 + Eide_pio uint16 + Eide_pio_iordy uint16 + Words69_70 [2]uint16 + Words71_74 [4]uint16 + Queue_depth uint16 + Words76_79 [4]uint16 + Major_rev_num uint16 + Minor_rev_num uint16 + Command_set_1 uint16 + Command_set_2 uint16 + Cfsse uint16 + Cfs_enable_1 uint16 + Cfs_enable_2 uint16 + Csf_default uint16 + Dma_ultra uint16 + Trseuc uint16 + TrsEuc uint16 + CurAPMvalues uint16 + Mprc uint16 + Hw_config uint16 + Acoustic uint16 + Msrqs uint16 + Sxfert uint16 + Sal uint16 + Spg uint32 + Lba_capacity_2 uint64 + Words104_125 [22]uint16 + Last_lun uint16 + Word127 uint16 + Dlf uint16 + Csfo uint16 + Words130_155 [26]uint16 + Word156 uint16 + Words157_159 [3]uint16 + Cfa_power uint16 + Words161_175 [15]uint16 + Words176_205 [30]uint16 + Words206_254 [49]uint16 + Integrity_word uint16 +} + +type Statfs_t struct { + Type int64 + Bsize int64 + Blocks uint64 + Bfree uint64 + Bavail uint64 + Files uint64 + Ffree uint64 + Fsid Fsid + Namelen int64 + Frsize int64 + Flags int64 + Spare [4]int64 +} + +const ( + ST_MANDLOCK = 0x40 + ST_NOATIME = 0x400 + ST_NODEV = 0x4 + ST_NODIRATIME = 0x800 + ST_NOEXEC = 0x8 + ST_NOSUID = 0x2 + ST_RDONLY = 0x1 + ST_RELATIME = 0x1000 + ST_SYNCHRONOUS = 0x10 +) + +type TpacketHdr struct { + Status uint64 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Sec uint32 + Usec uint32 + _ [4]byte +} + +type Tpacket2Hdr struct { + Status uint32 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Sec uint32 + Nsec uint32 + Vlan_tci uint16 + Vlan_tpid uint16 + _ [4]uint8 +} + +type Tpacket3Hdr struct { + Next_offset uint32 + Sec uint32 + Nsec uint32 + Snaplen uint32 + Len uint32 + Status uint32 + Mac uint16 + Net uint16 + Hv1 TpacketHdrVariant1 + _ [8]uint8 +} + +type TpacketHdrVariant1 struct { + Rxhash uint32 + Vlan_tci uint32 + Vlan_tpid uint16 + _ uint16 +} + +type TpacketBlockDesc struct { + Version uint32 + To_priv uint32 + Hdr [40]byte +} + +type TpacketReq struct { + Block_size uint32 + Block_nr uint32 + Frame_size uint32 + Frame_nr uint32 +} + +type TpacketReq3 struct { + Block_size uint32 + Block_nr uint32 + Frame_size uint32 + Frame_nr uint32 + Retire_blk_tov uint32 + Sizeof_priv uint32 + Feature_req_word uint32 +} + +type TpacketStats struct { + Packets uint32 + Drops uint32 +} + +type TpacketStatsV3 struct { + Packets uint32 + Drops uint32 + Freeze_q_cnt uint32 +} + +type TpacketAuxdata struct { + Status uint32 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Vlan_tci uint16 + Vlan_tpid uint16 +} + +const ( + TPACKET_V1 = 0x0 + TPACKET_V2 = 0x1 + TPACKET_V3 = 0x2 +) + +const ( + SizeofTpacketHdr = 0x20 + SizeofTpacket2Hdr = 0x20 + SizeofTpacket3Hdr = 0x30 +) + +const ( + NF_INET_PRE_ROUTING = 0x0 + NF_INET_LOCAL_IN = 0x1 + NF_INET_FORWARD = 0x2 + NF_INET_LOCAL_OUT = 0x3 + NF_INET_POST_ROUTING = 0x4 + NF_INET_NUMHOOKS = 0x5 +) + +const ( + NF_NETDEV_INGRESS = 0x0 + NF_NETDEV_NUMHOOKS = 0x1 +) + +const ( + NFPROTO_UNSPEC = 0x0 + NFPROTO_INET = 0x1 + NFPROTO_IPV4 = 0x2 + NFPROTO_ARP = 0x3 + NFPROTO_NETDEV = 0x5 + NFPROTO_BRIDGE = 0x7 + NFPROTO_IPV6 = 0xa + NFPROTO_DECNET = 0xc + NFPROTO_NUMPROTO = 0xd +) + +type Nfgenmsg struct { + Nfgen_family uint8 + Version uint8 + Res_id uint16 +} + +const ( + NFNL_BATCH_UNSPEC = 0x0 + NFNL_BATCH_GENID = 0x1 +) + +const ( + NFT_REG_VERDICT = 0x0 + NFT_REG_1 = 0x1 + NFT_REG_2 = 0x2 + NFT_REG_3 = 0x3 + NFT_REG_4 = 0x4 + NFT_REG32_00 = 0x8 + NFT_REG32_01 = 0x9 + NFT_REG32_02 = 0xa + NFT_REG32_03 = 0xb + NFT_REG32_04 = 0xc + NFT_REG32_05 = 0xd + NFT_REG32_06 = 0xe + NFT_REG32_07 = 0xf + NFT_REG32_08 = 0x10 + NFT_REG32_09 = 0x11 + NFT_REG32_10 = 0x12 + NFT_REG32_11 = 0x13 + NFT_REG32_12 = 0x14 + NFT_REG32_13 = 0x15 + NFT_REG32_14 = 0x16 + NFT_REG32_15 = 0x17 + NFT_CONTINUE = -0x1 + NFT_BREAK = -0x2 + NFT_JUMP = -0x3 + NFT_GOTO = -0x4 + NFT_RETURN = -0x5 + NFT_MSG_NEWTABLE = 0x0 + NFT_MSG_GETTABLE = 0x1 + NFT_MSG_DELTABLE = 0x2 + NFT_MSG_NEWCHAIN = 0x3 + NFT_MSG_GETCHAIN = 0x4 + NFT_MSG_DELCHAIN = 0x5 + NFT_MSG_NEWRULE = 0x6 + NFT_MSG_GETRULE = 0x7 + NFT_MSG_DELRULE = 0x8 + NFT_MSG_NEWSET = 0x9 + NFT_MSG_GETSET = 0xa + NFT_MSG_DELSET = 0xb + NFT_MSG_NEWSETELEM = 0xc + NFT_MSG_GETSETELEM = 0xd + NFT_MSG_DELSETELEM = 0xe + NFT_MSG_NEWGEN = 0xf + NFT_MSG_GETGEN = 0x10 + NFT_MSG_TRACE = 0x11 + NFT_MSG_NEWOBJ = 0x12 + NFT_MSG_GETOBJ = 0x13 + NFT_MSG_DELOBJ = 0x14 + NFT_MSG_GETOBJ_RESET = 0x15 + NFT_MSG_MAX = 0x19 + NFTA_LIST_UNPEC = 0x0 + NFTA_LIST_ELEM = 0x1 + NFTA_HOOK_UNSPEC = 0x0 + NFTA_HOOK_HOOKNUM = 0x1 + NFTA_HOOK_PRIORITY = 0x2 + NFTA_HOOK_DEV = 0x3 + NFT_TABLE_F_DORMANT = 0x1 + NFTA_TABLE_UNSPEC = 0x0 + NFTA_TABLE_NAME = 0x1 + NFTA_TABLE_FLAGS = 0x2 + NFTA_TABLE_USE = 0x3 + NFTA_CHAIN_UNSPEC = 0x0 + NFTA_CHAIN_TABLE = 0x1 + NFTA_CHAIN_HANDLE = 0x2 + NFTA_CHAIN_NAME = 0x3 + NFTA_CHAIN_HOOK = 0x4 + NFTA_CHAIN_POLICY = 0x5 + NFTA_CHAIN_USE = 0x6 + NFTA_CHAIN_TYPE = 0x7 + NFTA_CHAIN_COUNTERS = 0x8 + NFTA_CHAIN_PAD = 0x9 + NFTA_RULE_UNSPEC = 0x0 + NFTA_RULE_TABLE = 0x1 + NFTA_RULE_CHAIN = 0x2 + NFTA_RULE_HANDLE = 0x3 + NFTA_RULE_EXPRESSIONS = 0x4 + NFTA_RULE_COMPAT = 0x5 + NFTA_RULE_POSITION = 0x6 + NFTA_RULE_USERDATA = 0x7 + NFTA_RULE_PAD = 0x8 + NFTA_RULE_ID = 0x9 + NFT_RULE_COMPAT_F_INV = 0x2 + NFT_RULE_COMPAT_F_MASK = 0x2 + NFTA_RULE_COMPAT_UNSPEC = 0x0 + NFTA_RULE_COMPAT_PROTO = 0x1 + NFTA_RULE_COMPAT_FLAGS = 0x2 + NFT_SET_ANONYMOUS = 0x1 + NFT_SET_CONSTANT = 0x2 + NFT_SET_INTERVAL = 0x4 + NFT_SET_MAP = 0x8 + NFT_SET_TIMEOUT = 0x10 + NFT_SET_EVAL = 0x20 + NFT_SET_OBJECT = 0x40 + NFT_SET_POL_PERFORMANCE = 0x0 + NFT_SET_POL_MEMORY = 0x1 + NFTA_SET_DESC_UNSPEC = 0x0 + NFTA_SET_DESC_SIZE = 0x1 + NFTA_SET_UNSPEC = 0x0 + NFTA_SET_TABLE = 0x1 + NFTA_SET_NAME = 0x2 + NFTA_SET_FLAGS = 0x3 + NFTA_SET_KEY_TYPE = 0x4 + NFTA_SET_KEY_LEN = 0x5 + NFTA_SET_DATA_TYPE = 0x6 + NFTA_SET_DATA_LEN = 0x7 + NFTA_SET_POLICY = 0x8 + NFTA_SET_DESC = 0x9 + NFTA_SET_ID = 0xa + NFTA_SET_TIMEOUT = 0xb + NFTA_SET_GC_INTERVAL = 0xc + NFTA_SET_USERDATA = 0xd + NFTA_SET_PAD = 0xe + NFTA_SET_OBJ_TYPE = 0xf + NFT_SET_ELEM_INTERVAL_END = 0x1 + NFTA_SET_ELEM_UNSPEC = 0x0 + NFTA_SET_ELEM_KEY = 0x1 + NFTA_SET_ELEM_DATA = 0x2 + NFTA_SET_ELEM_FLAGS = 0x3 + NFTA_SET_ELEM_TIMEOUT = 0x4 + NFTA_SET_ELEM_EXPIRATION = 0x5 + NFTA_SET_ELEM_USERDATA = 0x6 + NFTA_SET_ELEM_EXPR = 0x7 + NFTA_SET_ELEM_PAD = 0x8 + NFTA_SET_ELEM_OBJREF = 0x9 + NFTA_SET_ELEM_LIST_UNSPEC = 0x0 + NFTA_SET_ELEM_LIST_TABLE = 0x1 + NFTA_SET_ELEM_LIST_SET = 0x2 + NFTA_SET_ELEM_LIST_ELEMENTS = 0x3 + NFTA_SET_ELEM_LIST_SET_ID = 0x4 + NFT_DATA_VALUE = 0x0 + NFT_DATA_VERDICT = 0xffffff00 + NFTA_DATA_UNSPEC = 0x0 + NFTA_DATA_VALUE = 0x1 + NFTA_DATA_VERDICT = 0x2 + NFTA_VERDICT_UNSPEC = 0x0 + NFTA_VERDICT_CODE = 0x1 + NFTA_VERDICT_CHAIN = 0x2 + NFTA_EXPR_UNSPEC = 0x0 + NFTA_EXPR_NAME = 0x1 + NFTA_EXPR_DATA = 0x2 + NFTA_IMMEDIATE_UNSPEC = 0x0 + NFTA_IMMEDIATE_DREG = 0x1 + NFTA_IMMEDIATE_DATA = 0x2 + NFTA_BITWISE_UNSPEC = 0x0 + NFTA_BITWISE_SREG = 0x1 + NFTA_BITWISE_DREG = 0x2 + NFTA_BITWISE_LEN = 0x3 + NFTA_BITWISE_MASK = 0x4 + NFTA_BITWISE_XOR = 0x5 + NFT_BYTEORDER_NTOH = 0x0 + NFT_BYTEORDER_HTON = 0x1 + NFTA_BYTEORDER_UNSPEC = 0x0 + NFTA_BYTEORDER_SREG = 0x1 + NFTA_BYTEORDER_DREG = 0x2 + NFTA_BYTEORDER_OP = 0x3 + NFTA_BYTEORDER_LEN = 0x4 + NFTA_BYTEORDER_SIZE = 0x5 + NFT_CMP_EQ = 0x0 + NFT_CMP_NEQ = 0x1 + NFT_CMP_LT = 0x2 + NFT_CMP_LTE = 0x3 + NFT_CMP_GT = 0x4 + NFT_CMP_GTE = 0x5 + NFTA_CMP_UNSPEC = 0x0 + NFTA_CMP_SREG = 0x1 + NFTA_CMP_OP = 0x2 + NFTA_CMP_DATA = 0x3 + NFT_RANGE_EQ = 0x0 + NFT_RANGE_NEQ = 0x1 + NFTA_RANGE_UNSPEC = 0x0 + NFTA_RANGE_SREG = 0x1 + NFTA_RANGE_OP = 0x2 + NFTA_RANGE_FROM_DATA = 0x3 + NFTA_RANGE_TO_DATA = 0x4 + NFT_LOOKUP_F_INV = 0x1 + NFTA_LOOKUP_UNSPEC = 0x0 + NFTA_LOOKUP_SET = 0x1 + NFTA_LOOKUP_SREG = 0x2 + NFTA_LOOKUP_DREG = 0x3 + NFTA_LOOKUP_SET_ID = 0x4 + NFTA_LOOKUP_FLAGS = 0x5 + NFT_DYNSET_OP_ADD = 0x0 + NFT_DYNSET_OP_UPDATE = 0x1 + NFT_DYNSET_F_INV = 0x1 + NFTA_DYNSET_UNSPEC = 0x0 + NFTA_DYNSET_SET_NAME = 0x1 + NFTA_DYNSET_SET_ID = 0x2 + NFTA_DYNSET_OP = 0x3 + NFTA_DYNSET_SREG_KEY = 0x4 + NFTA_DYNSET_SREG_DATA = 0x5 + NFTA_DYNSET_TIMEOUT = 0x6 + NFTA_DYNSET_EXPR = 0x7 + NFTA_DYNSET_PAD = 0x8 + NFTA_DYNSET_FLAGS = 0x9 + NFT_PAYLOAD_LL_HEADER = 0x0 + NFT_PAYLOAD_NETWORK_HEADER = 0x1 + NFT_PAYLOAD_TRANSPORT_HEADER = 0x2 + NFT_PAYLOAD_CSUM_NONE = 0x0 + NFT_PAYLOAD_CSUM_INET = 0x1 + NFT_PAYLOAD_L4CSUM_PSEUDOHDR = 0x1 + NFTA_PAYLOAD_UNSPEC = 0x0 + NFTA_PAYLOAD_DREG = 0x1 + NFTA_PAYLOAD_BASE = 0x2 + NFTA_PAYLOAD_OFFSET = 0x3 + NFTA_PAYLOAD_LEN = 0x4 + NFTA_PAYLOAD_SREG = 0x5 + NFTA_PAYLOAD_CSUM_TYPE = 0x6 + NFTA_PAYLOAD_CSUM_OFFSET = 0x7 + NFTA_PAYLOAD_CSUM_FLAGS = 0x8 + NFT_EXTHDR_F_PRESENT = 0x1 + NFT_EXTHDR_OP_IPV6 = 0x0 + NFT_EXTHDR_OP_TCPOPT = 0x1 + NFTA_EXTHDR_UNSPEC = 0x0 + NFTA_EXTHDR_DREG = 0x1 + NFTA_EXTHDR_TYPE = 0x2 + NFTA_EXTHDR_OFFSET = 0x3 + NFTA_EXTHDR_LEN = 0x4 + NFTA_EXTHDR_FLAGS = 0x5 + NFTA_EXTHDR_OP = 0x6 + NFTA_EXTHDR_SREG = 0x7 + NFT_META_LEN = 0x0 + NFT_META_PROTOCOL = 0x1 + NFT_META_PRIORITY = 0x2 + NFT_META_MARK = 0x3 + NFT_META_IIF = 0x4 + NFT_META_OIF = 0x5 + NFT_META_IIFNAME = 0x6 + NFT_META_OIFNAME = 0x7 + NFT_META_IIFTYPE = 0x8 + NFT_META_OIFTYPE = 0x9 + NFT_META_SKUID = 0xa + NFT_META_SKGID = 0xb + NFT_META_NFTRACE = 0xc + NFT_META_RTCLASSID = 0xd + NFT_META_SECMARK = 0xe + NFT_META_NFPROTO = 0xf + NFT_META_L4PROTO = 0x10 + NFT_META_BRI_IIFNAME = 0x11 + NFT_META_BRI_OIFNAME = 0x12 + NFT_META_PKTTYPE = 0x13 + NFT_META_CPU = 0x14 + NFT_META_IIFGROUP = 0x15 + NFT_META_OIFGROUP = 0x16 + NFT_META_CGROUP = 0x17 + NFT_META_PRANDOM = 0x18 + NFT_RT_CLASSID = 0x0 + NFT_RT_NEXTHOP4 = 0x1 + NFT_RT_NEXTHOP6 = 0x2 + NFT_RT_TCPMSS = 0x3 + NFT_HASH_JENKINS = 0x0 + NFT_HASH_SYM = 0x1 + NFTA_HASH_UNSPEC = 0x0 + NFTA_HASH_SREG = 0x1 + NFTA_HASH_DREG = 0x2 + NFTA_HASH_LEN = 0x3 + NFTA_HASH_MODULUS = 0x4 + NFTA_HASH_SEED = 0x5 + NFTA_HASH_OFFSET = 0x6 + NFTA_HASH_TYPE = 0x7 + NFTA_META_UNSPEC = 0x0 + NFTA_META_DREG = 0x1 + NFTA_META_KEY = 0x2 + NFTA_META_SREG = 0x3 + NFTA_RT_UNSPEC = 0x0 + NFTA_RT_DREG = 0x1 + NFTA_RT_KEY = 0x2 + NFT_CT_STATE = 0x0 + NFT_CT_DIRECTION = 0x1 + NFT_CT_STATUS = 0x2 + NFT_CT_MARK = 0x3 + NFT_CT_SECMARK = 0x4 + NFT_CT_EXPIRATION = 0x5 + NFT_CT_HELPER = 0x6 + NFT_CT_L3PROTOCOL = 0x7 + NFT_CT_SRC = 0x8 + NFT_CT_DST = 0x9 + NFT_CT_PROTOCOL = 0xa + NFT_CT_PROTO_SRC = 0xb + NFT_CT_PROTO_DST = 0xc + NFT_CT_LABELS = 0xd + NFT_CT_PKTS = 0xe + NFT_CT_BYTES = 0xf + NFT_CT_AVGPKT = 0x10 + NFT_CT_ZONE = 0x11 + NFT_CT_EVENTMASK = 0x12 + NFTA_CT_UNSPEC = 0x0 + NFTA_CT_DREG = 0x1 + NFTA_CT_KEY = 0x2 + NFTA_CT_DIRECTION = 0x3 + NFTA_CT_SREG = 0x4 + NFT_LIMIT_PKTS = 0x0 + NFT_LIMIT_PKT_BYTES = 0x1 + NFT_LIMIT_F_INV = 0x1 + NFTA_LIMIT_UNSPEC = 0x0 + NFTA_LIMIT_RATE = 0x1 + NFTA_LIMIT_UNIT = 0x2 + NFTA_LIMIT_BURST = 0x3 + NFTA_LIMIT_TYPE = 0x4 + NFTA_LIMIT_FLAGS = 0x5 + NFTA_LIMIT_PAD = 0x6 + NFTA_COUNTER_UNSPEC = 0x0 + NFTA_COUNTER_BYTES = 0x1 + NFTA_COUNTER_PACKETS = 0x2 + NFTA_COUNTER_PAD = 0x3 + NFTA_LOG_UNSPEC = 0x0 + NFTA_LOG_GROUP = 0x1 + NFTA_LOG_PREFIX = 0x2 + NFTA_LOG_SNAPLEN = 0x3 + NFTA_LOG_QTHRESHOLD = 0x4 + NFTA_LOG_LEVEL = 0x5 + NFTA_LOG_FLAGS = 0x6 + NFTA_QUEUE_UNSPEC = 0x0 + NFTA_QUEUE_NUM = 0x1 + NFTA_QUEUE_TOTAL = 0x2 + NFTA_QUEUE_FLAGS = 0x3 + NFTA_QUEUE_SREG_QNUM = 0x4 + NFT_QUOTA_F_INV = 0x1 + NFT_QUOTA_F_DEPLETED = 0x2 + NFTA_QUOTA_UNSPEC = 0x0 + NFTA_QUOTA_BYTES = 0x1 + NFTA_QUOTA_FLAGS = 0x2 + NFTA_QUOTA_PAD = 0x3 + NFTA_QUOTA_CONSUMED = 0x4 + NFT_REJECT_ICMP_UNREACH = 0x0 + NFT_REJECT_TCP_RST = 0x1 + NFT_REJECT_ICMPX_UNREACH = 0x2 + NFT_REJECT_ICMPX_NO_ROUTE = 0x0 + NFT_REJECT_ICMPX_PORT_UNREACH = 0x1 + NFT_REJECT_ICMPX_HOST_UNREACH = 0x2 + NFT_REJECT_ICMPX_ADMIN_PROHIBITED = 0x3 + NFTA_REJECT_UNSPEC = 0x0 + NFTA_REJECT_TYPE = 0x1 + NFTA_REJECT_ICMP_CODE = 0x2 + NFT_NAT_SNAT = 0x0 + NFT_NAT_DNAT = 0x1 + NFTA_NAT_UNSPEC = 0x0 + NFTA_NAT_TYPE = 0x1 + NFTA_NAT_FAMILY = 0x2 + NFTA_NAT_REG_ADDR_MIN = 0x3 + NFTA_NAT_REG_ADDR_MAX = 0x4 + NFTA_NAT_REG_PROTO_MIN = 0x5 + NFTA_NAT_REG_PROTO_MAX = 0x6 + NFTA_NAT_FLAGS = 0x7 + NFTA_MASQ_UNSPEC = 0x0 + NFTA_MASQ_FLAGS = 0x1 + NFTA_MASQ_REG_PROTO_MIN = 0x2 + NFTA_MASQ_REG_PROTO_MAX = 0x3 + NFTA_REDIR_UNSPEC = 0x0 + NFTA_REDIR_REG_PROTO_MIN = 0x1 + NFTA_REDIR_REG_PROTO_MAX = 0x2 + NFTA_REDIR_FLAGS = 0x3 + NFTA_DUP_UNSPEC = 0x0 + NFTA_DUP_SREG_ADDR = 0x1 + NFTA_DUP_SREG_DEV = 0x2 + NFTA_FWD_UNSPEC = 0x0 + NFTA_FWD_SREG_DEV = 0x1 + NFTA_OBJREF_UNSPEC = 0x0 + NFTA_OBJREF_IMM_TYPE = 0x1 + NFTA_OBJREF_IMM_NAME = 0x2 + NFTA_OBJREF_SET_SREG = 0x3 + NFTA_OBJREF_SET_NAME = 0x4 + NFTA_OBJREF_SET_ID = 0x5 + NFTA_GEN_UNSPEC = 0x0 + NFTA_GEN_ID = 0x1 + NFTA_GEN_PROC_PID = 0x2 + NFTA_GEN_PROC_NAME = 0x3 + NFTA_FIB_UNSPEC = 0x0 + NFTA_FIB_DREG = 0x1 + NFTA_FIB_RESULT = 0x2 + NFTA_FIB_FLAGS = 0x3 + NFT_FIB_RESULT_UNSPEC = 0x0 + NFT_FIB_RESULT_OIF = 0x1 + NFT_FIB_RESULT_OIFNAME = 0x2 + NFT_FIB_RESULT_ADDRTYPE = 0x3 + NFTA_FIB_F_SADDR = 0x1 + NFTA_FIB_F_DADDR = 0x2 + NFTA_FIB_F_MARK = 0x4 + NFTA_FIB_F_IIF = 0x8 + NFTA_FIB_F_OIF = 0x10 + NFTA_FIB_F_PRESENT = 0x20 + NFTA_CT_HELPER_UNSPEC = 0x0 + NFTA_CT_HELPER_NAME = 0x1 + NFTA_CT_HELPER_L3PROTO = 0x2 + NFTA_CT_HELPER_L4PROTO = 0x3 + NFTA_OBJ_UNSPEC = 0x0 + NFTA_OBJ_TABLE = 0x1 + NFTA_OBJ_NAME = 0x2 + NFTA_OBJ_TYPE = 0x3 + NFTA_OBJ_DATA = 0x4 + NFTA_OBJ_USE = 0x5 + NFTA_TRACE_UNSPEC = 0x0 + NFTA_TRACE_TABLE = 0x1 + NFTA_TRACE_CHAIN = 0x2 + NFTA_TRACE_RULE_HANDLE = 0x3 + NFTA_TRACE_TYPE = 0x4 + NFTA_TRACE_VERDICT = 0x5 + NFTA_TRACE_ID = 0x6 + NFTA_TRACE_LL_HEADER = 0x7 + NFTA_TRACE_NETWORK_HEADER = 0x8 + NFTA_TRACE_TRANSPORT_HEADER = 0x9 + NFTA_TRACE_IIF = 0xa + NFTA_TRACE_IIFTYPE = 0xb + NFTA_TRACE_OIF = 0xc + NFTA_TRACE_OIFTYPE = 0xd + NFTA_TRACE_MARK = 0xe + NFTA_TRACE_NFPROTO = 0xf + NFTA_TRACE_POLICY = 0x10 + NFTA_TRACE_PAD = 0x11 + NFT_TRACETYPE_UNSPEC = 0x0 + NFT_TRACETYPE_POLICY = 0x1 + NFT_TRACETYPE_RETURN = 0x2 + NFT_TRACETYPE_RULE = 0x3 + NFTA_NG_UNSPEC = 0x0 + NFTA_NG_DREG = 0x1 + NFTA_NG_MODULUS = 0x2 + NFTA_NG_TYPE = 0x3 + NFTA_NG_OFFSET = 0x4 + NFT_NG_INCREMENTAL = 0x0 + NFT_NG_RANDOM = 0x1 +) + +type RTCTime struct { + Sec int32 + Min int32 + Hour int32 + Mday int32 + Mon int32 + Year int32 + Wday int32 + Yday int32 + Isdst int32 +} + +type RTCWkAlrm struct { + Enabled uint8 + Pending uint8 + Time RTCTime +} + +type RTCPLLInfo struct { + Ctrl int32 + Value int32 + Max int32 + Min int32 + Posmult int32 + Negmult int32 + Clock int64 +} + +type BlkpgIoctlArg struct { + Op int32 + Flags int32 + Datalen int32 + Data *byte +} + +type BlkpgPartition struct { + Start int64 + Length int64 + Pno int32 + Devname [64]uint8 + Volname [64]uint8 + _ [4]byte +} + +const ( + BLKPG = 0x1269 + BLKPG_ADD_PARTITION = 0x1 + BLKPG_DEL_PARTITION = 0x2 + BLKPG_RESIZE_PARTITION = 0x3 +) + +const ( + NETNSA_NONE = 0x0 + NETNSA_NSID = 0x1 + NETNSA_PID = 0x2 + NETNSA_FD = 0x3 +) + +type XDPRingOffset struct { + Producer uint64 + Consumer uint64 + Desc uint64 +} + +type XDPMmapOffsets struct { + Rx XDPRingOffset + Tx XDPRingOffset + Fr XDPRingOffset + Cr XDPRingOffset +} + +type XDPUmemReg struct { + Addr uint64 + Len uint64 + Size uint32 + Headroom uint32 +} + +type XDPStatistics struct { + Rx_dropped uint64 + Rx_invalid_descs uint64 + Tx_invalid_descs uint64 +} + +type XDPDesc struct { + Addr uint64 + Len uint32 + Options uint32 +} + +const ( + NCSI_CMD_UNSPEC = 0x0 + NCSI_CMD_PKG_INFO = 0x1 + NCSI_CMD_SET_INTERFACE = 0x2 + NCSI_CMD_CLEAR_INTERFACE = 0x3 + NCSI_ATTR_UNSPEC = 0x0 + NCSI_ATTR_IFINDEX = 0x1 + NCSI_ATTR_PACKAGE_LIST = 0x2 + NCSI_ATTR_PACKAGE_ID = 0x3 + NCSI_ATTR_CHANNEL_ID = 0x4 + NCSI_PKG_ATTR_UNSPEC = 0x0 + NCSI_PKG_ATTR = 0x1 + NCSI_PKG_ATTR_ID = 0x2 + NCSI_PKG_ATTR_FORCED = 0x3 + NCSI_PKG_ATTR_CHANNEL_LIST = 0x4 + NCSI_CHANNEL_ATTR_UNSPEC = 0x0 + NCSI_CHANNEL_ATTR = 0x1 + NCSI_CHANNEL_ATTR_ID = 0x2 + NCSI_CHANNEL_ATTR_VERSION_MAJOR = 0x3 + NCSI_CHANNEL_ATTR_VERSION_MINOR = 0x4 + NCSI_CHANNEL_ATTR_VERSION_STR = 0x5 + NCSI_CHANNEL_ATTR_LINK_STATE = 0x6 + NCSI_CHANNEL_ATTR_ACTIVE = 0x7 + NCSI_CHANNEL_ATTR_FORCED = 0x8 + NCSI_CHANNEL_ATTR_VLAN_LIST = 0x9 + NCSI_CHANNEL_ATTR_VLAN_ID = 0xa +) + +type ScmTimestamping struct { + Ts [3]Timespec +} + +const ( + SOF_TIMESTAMPING_TX_HARDWARE = 0x1 + SOF_TIMESTAMPING_TX_SOFTWARE = 0x2 + SOF_TIMESTAMPING_RX_HARDWARE = 0x4 + SOF_TIMESTAMPING_RX_SOFTWARE = 0x8 + SOF_TIMESTAMPING_SOFTWARE = 0x10 + SOF_TIMESTAMPING_SYS_HARDWARE = 0x20 + SOF_TIMESTAMPING_RAW_HARDWARE = 0x40 + SOF_TIMESTAMPING_OPT_ID = 0x80 + SOF_TIMESTAMPING_TX_SCHED = 0x100 + SOF_TIMESTAMPING_TX_ACK = 0x200 + SOF_TIMESTAMPING_OPT_CMSG = 0x400 + SOF_TIMESTAMPING_OPT_TSONLY = 0x800 + SOF_TIMESTAMPING_OPT_STATS = 0x1000 + SOF_TIMESTAMPING_OPT_PKTINFO = 0x2000 + SOF_TIMESTAMPING_OPT_TX_SWHW = 0x4000 + + SOF_TIMESTAMPING_LAST = 0x4000 + SOF_TIMESTAMPING_MASK = 0x7fff + + SCM_TSTAMP_SND = 0x0 + SCM_TSTAMP_SCHED = 0x1 + SCM_TSTAMP_ACK = 0x2 +) + +type SockExtendedErr struct { + Errno uint32 + Origin uint8 + Type uint8 + Code uint8 + Pad uint8 + Info uint32 + Data uint32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go b/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go index cb194f4717..d315f2c3a7 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go @@ -6,11 +6,11 @@ package unix const ( - sizeofPtr = 0x8 - sizeofShort = 0x2 - sizeofInt = 0x4 - sizeofLong = 0x8 - sizeofLongLong = 0x8 + SizeofPtr = 0x8 + SizeofShort = 0x2 + SizeofInt = 0x4 + SizeofLong = 0x8 + SizeofLongLong = 0x8 PathMax = 0x1000 ) @@ -33,13 +33,11 @@ type Timeval struct { type Timex struct { Modes uint32 - _ [4]byte Offset int64 Freq int64 Maxerror int64 Esterror int64 Status int32 - _ [4]byte Constant int64 Precision int64 Tolerance int64 @@ -48,7 +46,6 @@ type Timex struct { Ppsfreq int64 Jitter int64 Shift int32 - _ [4]byte Stabil int64 Jitcnt int64 Calcnt int64 @@ -116,20 +113,34 @@ type Stat_t struct { _ [3]int64 } -type Statfs_t struct { - Type uint32 - Bsize uint32 - Blocks uint64 - Bfree uint64 - Bavail uint64 - Files uint64 - Ffree uint64 - Fsid Fsid - Namelen uint32 - Frsize uint32 - Flags uint32 - Spare [4]uint32 - _ [4]byte +type StatxTimestamp struct { + Sec int64 + Nsec uint32 + _ int32 +} + +type Statx_t struct { + Mask uint32 + Blksize uint32 + Attributes uint64 + Nlink uint32 + Uid uint32 + Gid uint32 + Mode uint16 + _ [1]uint16 + Ino uint64 + Size uint64 + Blocks uint64 + Attributes_mask uint64 + Atime StatxTimestamp + Btime StatxTimestamp + Ctime StatxTimestamp + Mtime StatxTimestamp + Rdev_major uint32 + Rdev_minor uint32 + Dev_major uint32 + Dev_minor uint32 + _ [14]uint64 } type Dirent struct { @@ -142,13 +153,12 @@ type Dirent struct { } type Fsid struct { - _ [2]int32 + Val [2]int32 } type Flock_t struct { Type int16 Whence int16 - _ [4]byte Start int64 Len int64 Pid int32 @@ -227,9 +237,24 @@ type RawSockaddrHCI struct { Channel uint16 } +type RawSockaddrL2 struct { + Family uint16 + Psm uint16 + Bdaddr [6]uint8 + Cid uint16 + Bdaddr_type uint8 + _ [1]byte +} + +type RawSockaddrRFCOMM struct { + Family uint16 + Bdaddr [6]uint8 + Channel uint8 + _ [1]byte +} + type RawSockaddrCAN struct { Family uint16 - _ [2]byte Ifindex int32 Addr [8]byte } @@ -250,6 +275,16 @@ type RawSockaddrVM struct { Zero [4]uint8 } +type RawSockaddrXDP struct { + Family uint16 + Flags uint16 + Ifindex uint32 + Queue_id uint32 + Shared_umem_fd uint32 +} + +type RawSockaddrPPPoX [0x1e]byte + type RawSockaddr struct { Family uint16 Data [14]int8 @@ -298,7 +333,6 @@ type PacketMreq struct { type Msghdr struct { Name *byte Namelen uint32 - _ [4]byte Iov *Iovec Iovlen uint64 Control *byte @@ -346,7 +380,6 @@ type TCPInfo struct { Probes uint8 Backoff uint8 Options uint8 - _ [2]byte Rto uint32 Ato uint32 Snd_mss uint32 @@ -381,9 +414,13 @@ const ( SizeofSockaddrLinklayer = 0x14 SizeofSockaddrNetlink = 0xc SizeofSockaddrHCI = 0x6 + SizeofSockaddrL2 = 0xe + SizeofSockaddrRFCOMM = 0xa SizeofSockaddrCAN = 0x10 SizeofSockaddrALG = 0x58 SizeofSockaddrVM = 0x10 + SizeofSockaddrXDP = 0x10 + SizeofSockaddrPPPoX = 0x1e SizeofLinger = 0x8 SizeofIovec = 0x10 SizeofIPMreq = 0x8 @@ -401,97 +438,138 @@ const ( ) const ( - IFA_UNSPEC = 0x0 - IFA_ADDRESS = 0x1 - IFA_LOCAL = 0x2 - IFA_LABEL = 0x3 - IFA_BROADCAST = 0x4 - IFA_ANYCAST = 0x5 - IFA_CACHEINFO = 0x6 - IFA_MULTICAST = 0x7 - IFLA_UNSPEC = 0x0 - IFLA_ADDRESS = 0x1 - IFLA_BROADCAST = 0x2 - IFLA_IFNAME = 0x3 - IFLA_MTU = 0x4 - IFLA_LINK = 0x5 - IFLA_QDISC = 0x6 - IFLA_STATS = 0x7 - IFLA_COST = 0x8 - IFLA_PRIORITY = 0x9 - IFLA_MASTER = 0xa - IFLA_WIRELESS = 0xb - IFLA_PROTINFO = 0xc - IFLA_TXQLEN = 0xd - IFLA_MAP = 0xe - IFLA_WEIGHT = 0xf - IFLA_OPERSTATE = 0x10 - IFLA_LINKMODE = 0x11 - IFLA_LINKINFO = 0x12 - IFLA_NET_NS_PID = 0x13 - IFLA_IFALIAS = 0x14 - IFLA_MAX = 0x2c - RT_SCOPE_UNIVERSE = 0x0 - RT_SCOPE_SITE = 0xc8 - RT_SCOPE_LINK = 0xfd - RT_SCOPE_HOST = 0xfe - RT_SCOPE_NOWHERE = 0xff - RT_TABLE_UNSPEC = 0x0 - RT_TABLE_COMPAT = 0xfc - RT_TABLE_DEFAULT = 0xfd - RT_TABLE_MAIN = 0xfe - RT_TABLE_LOCAL = 0xff - RT_TABLE_MAX = 0xffffffff - RTA_UNSPEC = 0x0 - RTA_DST = 0x1 - RTA_SRC = 0x2 - RTA_IIF = 0x3 - RTA_OIF = 0x4 - RTA_GATEWAY = 0x5 - RTA_PRIORITY = 0x6 - RTA_PREFSRC = 0x7 - RTA_METRICS = 0x8 - RTA_MULTIPATH = 0x9 - RTA_FLOW = 0xb - RTA_CACHEINFO = 0xc - RTA_TABLE = 0xf - RTN_UNSPEC = 0x0 - RTN_UNICAST = 0x1 - RTN_LOCAL = 0x2 - RTN_BROADCAST = 0x3 - RTN_ANYCAST = 0x4 - RTN_MULTICAST = 0x5 - RTN_BLACKHOLE = 0x6 - RTN_UNREACHABLE = 0x7 - RTN_PROHIBIT = 0x8 - RTN_THROW = 0x9 - RTN_NAT = 0xa - RTN_XRESOLVE = 0xb - RTNLGRP_NONE = 0x0 - RTNLGRP_LINK = 0x1 - RTNLGRP_NOTIFY = 0x2 - RTNLGRP_NEIGH = 0x3 - RTNLGRP_TC = 0x4 - RTNLGRP_IPV4_IFADDR = 0x5 - RTNLGRP_IPV4_MROUTE = 0x6 - RTNLGRP_IPV4_ROUTE = 0x7 - RTNLGRP_IPV4_RULE = 0x8 - RTNLGRP_IPV6_IFADDR = 0x9 - RTNLGRP_IPV6_MROUTE = 0xa - RTNLGRP_IPV6_ROUTE = 0xb - RTNLGRP_IPV6_IFINFO = 0xc - RTNLGRP_IPV6_PREFIX = 0x12 - RTNLGRP_IPV6_RULE = 0x13 - RTNLGRP_ND_USEROPT = 0x14 - SizeofNlMsghdr = 0x10 - SizeofNlMsgerr = 0x14 - SizeofRtGenmsg = 0x1 - SizeofNlAttr = 0x4 - SizeofRtAttr = 0x4 - SizeofIfInfomsg = 0x10 - SizeofIfAddrmsg = 0x8 - SizeofRtMsg = 0xc - SizeofRtNexthop = 0x8 + IFA_UNSPEC = 0x0 + IFA_ADDRESS = 0x1 + IFA_LOCAL = 0x2 + IFA_LABEL = 0x3 + IFA_BROADCAST = 0x4 + IFA_ANYCAST = 0x5 + IFA_CACHEINFO = 0x6 + IFA_MULTICAST = 0x7 + IFLA_UNSPEC = 0x0 + IFLA_ADDRESS = 0x1 + IFLA_BROADCAST = 0x2 + IFLA_IFNAME = 0x3 + IFLA_INFO_KIND = 0x1 + IFLA_MTU = 0x4 + IFLA_LINK = 0x5 + IFLA_QDISC = 0x6 + IFLA_STATS = 0x7 + IFLA_COST = 0x8 + IFLA_PRIORITY = 0x9 + IFLA_MASTER = 0xa + IFLA_WIRELESS = 0xb + IFLA_PROTINFO = 0xc + IFLA_TXQLEN = 0xd + IFLA_MAP = 0xe + IFLA_WEIGHT = 0xf + IFLA_OPERSTATE = 0x10 + IFLA_LINKMODE = 0x11 + IFLA_LINKINFO = 0x12 + IFLA_NET_NS_PID = 0x13 + IFLA_IFALIAS = 0x14 + IFLA_NUM_VF = 0x15 + IFLA_VFINFO_LIST = 0x16 + IFLA_STATS64 = 0x17 + IFLA_VF_PORTS = 0x18 + IFLA_PORT_SELF = 0x19 + IFLA_AF_SPEC = 0x1a + IFLA_GROUP = 0x1b + IFLA_NET_NS_FD = 0x1c + IFLA_EXT_MASK = 0x1d + IFLA_PROMISCUITY = 0x1e + IFLA_NUM_TX_QUEUES = 0x1f + IFLA_NUM_RX_QUEUES = 0x20 + IFLA_CARRIER = 0x21 + IFLA_PHYS_PORT_ID = 0x22 + IFLA_CARRIER_CHANGES = 0x23 + IFLA_PHYS_SWITCH_ID = 0x24 + IFLA_LINK_NETNSID = 0x25 + IFLA_PHYS_PORT_NAME = 0x26 + IFLA_PROTO_DOWN = 0x27 + IFLA_GSO_MAX_SEGS = 0x28 + IFLA_GSO_MAX_SIZE = 0x29 + IFLA_PAD = 0x2a + IFLA_XDP = 0x2b + IFLA_EVENT = 0x2c + IFLA_NEW_NETNSID = 0x2d + IFLA_IF_NETNSID = 0x2e + IFLA_MAX = 0x33 + RT_SCOPE_UNIVERSE = 0x0 + RT_SCOPE_SITE = 0xc8 + RT_SCOPE_LINK = 0xfd + RT_SCOPE_HOST = 0xfe + RT_SCOPE_NOWHERE = 0xff + RT_TABLE_UNSPEC = 0x0 + RT_TABLE_COMPAT = 0xfc + RT_TABLE_DEFAULT = 0xfd + RT_TABLE_MAIN = 0xfe + RT_TABLE_LOCAL = 0xff + RT_TABLE_MAX = 0xffffffff + RTA_UNSPEC = 0x0 + RTA_DST = 0x1 + RTA_SRC = 0x2 + RTA_IIF = 0x3 + RTA_OIF = 0x4 + RTA_GATEWAY = 0x5 + RTA_PRIORITY = 0x6 + RTA_PREFSRC = 0x7 + RTA_METRICS = 0x8 + RTA_MULTIPATH = 0x9 + RTA_FLOW = 0xb + RTA_CACHEINFO = 0xc + RTA_TABLE = 0xf + RTA_MARK = 0x10 + RTA_MFC_STATS = 0x11 + RTA_VIA = 0x12 + RTA_NEWDST = 0x13 + RTA_PREF = 0x14 + RTA_ENCAP_TYPE = 0x15 + RTA_ENCAP = 0x16 + RTA_EXPIRES = 0x17 + RTA_PAD = 0x18 + RTA_UID = 0x19 + RTA_TTL_PROPAGATE = 0x1a + RTA_IP_PROTO = 0x1b + RTA_SPORT = 0x1c + RTA_DPORT = 0x1d + RTN_UNSPEC = 0x0 + RTN_UNICAST = 0x1 + RTN_LOCAL = 0x2 + RTN_BROADCAST = 0x3 + RTN_ANYCAST = 0x4 + RTN_MULTICAST = 0x5 + RTN_BLACKHOLE = 0x6 + RTN_UNREACHABLE = 0x7 + RTN_PROHIBIT = 0x8 + RTN_THROW = 0x9 + RTN_NAT = 0xa + RTN_XRESOLVE = 0xb + RTNLGRP_NONE = 0x0 + RTNLGRP_LINK = 0x1 + RTNLGRP_NOTIFY = 0x2 + RTNLGRP_NEIGH = 0x3 + RTNLGRP_TC = 0x4 + RTNLGRP_IPV4_IFADDR = 0x5 + RTNLGRP_IPV4_MROUTE = 0x6 + RTNLGRP_IPV4_ROUTE = 0x7 + RTNLGRP_IPV4_RULE = 0x8 + RTNLGRP_IPV6_IFADDR = 0x9 + RTNLGRP_IPV6_MROUTE = 0xa + RTNLGRP_IPV6_ROUTE = 0xb + RTNLGRP_IPV6_IFINFO = 0xc + RTNLGRP_IPV6_PREFIX = 0x12 + RTNLGRP_IPV6_RULE = 0x13 + RTNLGRP_ND_USEROPT = 0x14 + SizeofNlMsghdr = 0x10 + SizeofNlMsgerr = 0x14 + SizeofRtGenmsg = 0x1 + SizeofNlAttr = 0x4 + SizeofRtAttr = 0x4 + SizeofIfInfomsg = 0x10 + SizeofIfAddrmsg = 0x8 + SizeofRtMsg = 0xc + SizeofRtNexthop = 0x8 ) type NlMsghdr struct { @@ -571,7 +649,6 @@ type SockFilter struct { type SockFprog struct { Len uint16 - _ [6]byte Filter *SockFilter } @@ -601,18 +678,15 @@ type PtracePsw struct { type PtraceFpregs struct { Fpc uint32 - _ [4]byte Fprs [16]float64 } type PtracePer struct { _ [0]uint64 - _ [24]byte - _ [8]byte + _ [32]byte Starting_addr uint64 Ending_addr uint64 Perc_atmid uint16 - _ [6]byte Address uint64 Access_id uint8 _ [7]byte @@ -633,7 +707,6 @@ type Sysinfo_t struct { Freeswap uint64 Procs uint16 Pad uint16 - _ [4]byte Totalhigh uint64 Freehigh uint64 Unit uint32 @@ -652,7 +725,6 @@ type Utsname struct { type Ustat_t struct { Tfree int32 - _ [4]byte Tinode uint64 Fname [6]int8 Fpack [6]int8 @@ -667,10 +739,19 @@ type EpollEvent struct { } const ( - AT_FDCWD = -0x64 - AT_REMOVEDIR = 0x200 + AT_EMPTY_PATH = 0x1000 + AT_FDCWD = -0x64 + AT_NO_AUTOMOUNT = 0x800 + AT_REMOVEDIR = 0x200 + + AT_STATX_SYNC_AS_STAT = 0x0 + AT_STATX_FORCE_SYNC = 0x2000 + AT_STATX_DONT_SYNC = 0x4000 + AT_SYMLINK_FOLLOW = 0x400 AT_SYMLINK_NOFOLLOW = 0x100 + + AT_EACCESS = 0x200 ) type PollFd struct { @@ -690,10 +771,33 @@ const ( ) type Sigset_t struct { - _ [16]uint64 + Val [16]uint64 } -const RNDGETENTCNT = 0x80045200 +type SignalfdSiginfo struct { + Signo uint32 + Errno int32 + Code int32 + Pid uint32 + Uid uint32 + Fd int32 + Tid uint32 + Band uint32 + Overrun uint32 + Trapno uint32 + Status int32 + Int int32 + Ptr uint64 + Utime uint64 + Stime uint64 + Addr uint64 + Addr_lsb uint16 + _ uint16 + Syscall int32 + Call_addr uint64 + Arch uint32 + _ [28]uint8 +} const PERF_IOC_FLAG_GROUP = 0x1 @@ -717,11 +821,9 @@ type Winsize struct { type Taskstats struct { Version uint16 - _ [2]byte Ac_exitcode uint32 Ac_flag uint8 Ac_nice uint8 - _ [6]byte Cpu_count uint64 Cpu_delay_total uint64 Blkio_count uint64 @@ -739,7 +841,6 @@ type Taskstats struct { Ac_pid uint32 Ac_ppid uint32 Ac_btime uint32 - _ [4]byte Ac_etime uint64 Ac_utime uint64 Ac_stime uint64 @@ -763,6 +864,8 @@ type Taskstats struct { Cpu_scaled_run_real_total uint64 Freepages_count uint64 Freepages_delay_total uint64 + Thrashing_count uint64 + Thrashing_delay_total uint64 } const ( @@ -783,6 +886,24 @@ const ( TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK = 0x4 ) +type CGroupStats struct { + Sleeping uint64 + Running uint64 + Stopped uint64 + Uninterruptible uint64 + Io_wait uint64 +} + +const ( + CGROUPSTATS_CMD_UNSPEC = 0x3 + CGROUPSTATS_CMD_GET = 0x4 + CGROUPSTATS_CMD_NEW = 0x5 + CGROUPSTATS_TYPE_UNSPEC = 0x0 + CGROUPSTATS_TYPE_CGROUP_STATS = 0x1 + CGROUPSTATS_CMD_ATTR_UNSPEC = 0x0 + CGROUPSTATS_CMD_ATTR_FD = 0x1 +) + type Genlmsghdr struct { Cmd uint8 Version uint8 @@ -815,3 +936,1108 @@ const ( CTRL_ATTR_MCAST_GRP_NAME = 0x1 CTRL_ATTR_MCAST_GRP_ID = 0x2 ) + +type cpuMask uint64 + +const ( + _CPU_SETSIZE = 0x400 + _NCPUBITS = 0x40 +) + +const ( + BDADDR_BREDR = 0x0 + BDADDR_LE_PUBLIC = 0x1 + BDADDR_LE_RANDOM = 0x2 +) + +type PerfEventAttr struct { + Type uint32 + Size uint32 + Config uint64 + Sample uint64 + Sample_type uint64 + Read_format uint64 + Bits uint64 + Wakeup uint32 + Bp_type uint32 + Ext1 uint64 + Ext2 uint64 + Branch_sample_type uint64 + Sample_regs_user uint64 + Sample_stack_user uint32 + Clockid int32 + Sample_regs_intr uint64 + Aux_watermark uint32 + _ uint32 +} + +type PerfEventMmapPage struct { + Version uint32 + Compat_version uint32 + Lock uint32 + Index uint32 + Offset int64 + Time_enabled uint64 + Time_running uint64 + Capabilities uint64 + Pmc_width uint16 + Time_shift uint16 + Time_mult uint32 + Time_offset uint64 + Time_zero uint64 + Size uint32 + _ [948]uint8 + Data_head uint64 + Data_tail uint64 + Data_offset uint64 + Data_size uint64 + Aux_head uint64 + Aux_tail uint64 + Aux_offset uint64 + Aux_size uint64 +} + +const ( + PerfBitDisabled uint64 = CBitFieldMaskBit0 + PerfBitInherit = CBitFieldMaskBit1 + PerfBitPinned = CBitFieldMaskBit2 + PerfBitExclusive = CBitFieldMaskBit3 + PerfBitExcludeUser = CBitFieldMaskBit4 + PerfBitExcludeKernel = CBitFieldMaskBit5 + PerfBitExcludeHv = CBitFieldMaskBit6 + PerfBitExcludeIdle = CBitFieldMaskBit7 + PerfBitMmap = CBitFieldMaskBit8 + PerfBitComm = CBitFieldMaskBit9 + PerfBitFreq = CBitFieldMaskBit10 + PerfBitInheritStat = CBitFieldMaskBit11 + PerfBitEnableOnExec = CBitFieldMaskBit12 + PerfBitTask = CBitFieldMaskBit13 + PerfBitWatermark = CBitFieldMaskBit14 + PerfBitPreciseIPBit1 = CBitFieldMaskBit15 + PerfBitPreciseIPBit2 = CBitFieldMaskBit16 + PerfBitMmapData = CBitFieldMaskBit17 + PerfBitSampleIDAll = CBitFieldMaskBit18 + PerfBitExcludeHost = CBitFieldMaskBit19 + PerfBitExcludeGuest = CBitFieldMaskBit20 + PerfBitExcludeCallchainKernel = CBitFieldMaskBit21 + PerfBitExcludeCallchainUser = CBitFieldMaskBit22 + PerfBitMmap2 = CBitFieldMaskBit23 + PerfBitCommExec = CBitFieldMaskBit24 + PerfBitUseClockID = CBitFieldMaskBit25 + PerfBitContextSwitch = CBitFieldMaskBit26 +) + +const ( + PERF_TYPE_HARDWARE = 0x0 + PERF_TYPE_SOFTWARE = 0x1 + PERF_TYPE_TRACEPOINT = 0x2 + PERF_TYPE_HW_CACHE = 0x3 + PERF_TYPE_RAW = 0x4 + PERF_TYPE_BREAKPOINT = 0x5 + + PERF_COUNT_HW_CPU_CYCLES = 0x0 + PERF_COUNT_HW_INSTRUCTIONS = 0x1 + PERF_COUNT_HW_CACHE_REFERENCES = 0x2 + PERF_COUNT_HW_CACHE_MISSES = 0x3 + PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 0x4 + PERF_COUNT_HW_BRANCH_MISSES = 0x5 + PERF_COUNT_HW_BUS_CYCLES = 0x6 + PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 0x7 + PERF_COUNT_HW_STALLED_CYCLES_BACKEND = 0x8 + PERF_COUNT_HW_REF_CPU_CYCLES = 0x9 + + PERF_COUNT_HW_CACHE_L1D = 0x0 + PERF_COUNT_HW_CACHE_L1I = 0x1 + PERF_COUNT_HW_CACHE_LL = 0x2 + PERF_COUNT_HW_CACHE_DTLB = 0x3 + PERF_COUNT_HW_CACHE_ITLB = 0x4 + PERF_COUNT_HW_CACHE_BPU = 0x5 + PERF_COUNT_HW_CACHE_NODE = 0x6 + + PERF_COUNT_HW_CACHE_OP_READ = 0x0 + PERF_COUNT_HW_CACHE_OP_WRITE = 0x1 + PERF_COUNT_HW_CACHE_OP_PREFETCH = 0x2 + + PERF_COUNT_HW_CACHE_RESULT_ACCESS = 0x0 + PERF_COUNT_HW_CACHE_RESULT_MISS = 0x1 + + PERF_COUNT_SW_CPU_CLOCK = 0x0 + PERF_COUNT_SW_TASK_CLOCK = 0x1 + PERF_COUNT_SW_PAGE_FAULTS = 0x2 + PERF_COUNT_SW_CONTEXT_SWITCHES = 0x3 + PERF_COUNT_SW_CPU_MIGRATIONS = 0x4 + PERF_COUNT_SW_PAGE_FAULTS_MIN = 0x5 + PERF_COUNT_SW_PAGE_FAULTS_MAJ = 0x6 + PERF_COUNT_SW_ALIGNMENT_FAULTS = 0x7 + PERF_COUNT_SW_EMULATION_FAULTS = 0x8 + PERF_COUNT_SW_DUMMY = 0x9 + + PERF_SAMPLE_IP = 0x1 + PERF_SAMPLE_TID = 0x2 + PERF_SAMPLE_TIME = 0x4 + PERF_SAMPLE_ADDR = 0x8 + PERF_SAMPLE_READ = 0x10 + PERF_SAMPLE_CALLCHAIN = 0x20 + PERF_SAMPLE_ID = 0x40 + PERF_SAMPLE_CPU = 0x80 + PERF_SAMPLE_PERIOD = 0x100 + PERF_SAMPLE_STREAM_ID = 0x200 + PERF_SAMPLE_RAW = 0x400 + PERF_SAMPLE_BRANCH_STACK = 0x800 + + PERF_SAMPLE_BRANCH_USER = 0x1 + PERF_SAMPLE_BRANCH_KERNEL = 0x2 + PERF_SAMPLE_BRANCH_HV = 0x4 + PERF_SAMPLE_BRANCH_ANY = 0x8 + PERF_SAMPLE_BRANCH_ANY_CALL = 0x10 + PERF_SAMPLE_BRANCH_ANY_RETURN = 0x20 + PERF_SAMPLE_BRANCH_IND_CALL = 0x40 + + PERF_FORMAT_TOTAL_TIME_ENABLED = 0x1 + PERF_FORMAT_TOTAL_TIME_RUNNING = 0x2 + PERF_FORMAT_ID = 0x4 + PERF_FORMAT_GROUP = 0x8 + + PERF_RECORD_MMAP = 0x1 + PERF_RECORD_LOST = 0x2 + PERF_RECORD_COMM = 0x3 + PERF_RECORD_EXIT = 0x4 + PERF_RECORD_THROTTLE = 0x5 + PERF_RECORD_UNTHROTTLE = 0x6 + PERF_RECORD_FORK = 0x7 + PERF_RECORD_READ = 0x8 + PERF_RECORD_SAMPLE = 0x9 + + PERF_CONTEXT_HV = -0x20 + PERF_CONTEXT_KERNEL = -0x80 + PERF_CONTEXT_USER = -0x200 + + PERF_CONTEXT_GUEST = -0x800 + PERF_CONTEXT_GUEST_KERNEL = -0x880 + PERF_CONTEXT_GUEST_USER = -0xa00 + + PERF_FLAG_FD_NO_GROUP = 0x1 + PERF_FLAG_FD_OUTPUT = 0x2 + PERF_FLAG_PID_CGROUP = 0x4 +) + +const ( + CBitFieldMaskBit0 = 0x8000000000000000 + CBitFieldMaskBit1 = 0x4000000000000000 + CBitFieldMaskBit2 = 0x2000000000000000 + CBitFieldMaskBit3 = 0x1000000000000000 + CBitFieldMaskBit4 = 0x800000000000000 + CBitFieldMaskBit5 = 0x400000000000000 + CBitFieldMaskBit6 = 0x200000000000000 + CBitFieldMaskBit7 = 0x100000000000000 + CBitFieldMaskBit8 = 0x80000000000000 + CBitFieldMaskBit9 = 0x40000000000000 + CBitFieldMaskBit10 = 0x20000000000000 + CBitFieldMaskBit11 = 0x10000000000000 + CBitFieldMaskBit12 = 0x8000000000000 + CBitFieldMaskBit13 = 0x4000000000000 + CBitFieldMaskBit14 = 0x2000000000000 + CBitFieldMaskBit15 = 0x1000000000000 + CBitFieldMaskBit16 = 0x800000000000 + CBitFieldMaskBit17 = 0x400000000000 + CBitFieldMaskBit18 = 0x200000000000 + CBitFieldMaskBit19 = 0x100000000000 + CBitFieldMaskBit20 = 0x80000000000 + CBitFieldMaskBit21 = 0x40000000000 + CBitFieldMaskBit22 = 0x20000000000 + CBitFieldMaskBit23 = 0x10000000000 + CBitFieldMaskBit24 = 0x8000000000 + CBitFieldMaskBit25 = 0x4000000000 + CBitFieldMaskBit26 = 0x2000000000 + CBitFieldMaskBit27 = 0x1000000000 + CBitFieldMaskBit28 = 0x800000000 + CBitFieldMaskBit29 = 0x400000000 + CBitFieldMaskBit30 = 0x200000000 + CBitFieldMaskBit31 = 0x100000000 + CBitFieldMaskBit32 = 0x80000000 + CBitFieldMaskBit33 = 0x40000000 + CBitFieldMaskBit34 = 0x20000000 + CBitFieldMaskBit35 = 0x10000000 + CBitFieldMaskBit36 = 0x8000000 + CBitFieldMaskBit37 = 0x4000000 + CBitFieldMaskBit38 = 0x2000000 + CBitFieldMaskBit39 = 0x1000000 + CBitFieldMaskBit40 = 0x800000 + CBitFieldMaskBit41 = 0x400000 + CBitFieldMaskBit42 = 0x200000 + CBitFieldMaskBit43 = 0x100000 + CBitFieldMaskBit44 = 0x80000 + CBitFieldMaskBit45 = 0x40000 + CBitFieldMaskBit46 = 0x20000 + CBitFieldMaskBit47 = 0x10000 + CBitFieldMaskBit48 = 0x8000 + CBitFieldMaskBit49 = 0x4000 + CBitFieldMaskBit50 = 0x2000 + CBitFieldMaskBit51 = 0x1000 + CBitFieldMaskBit52 = 0x800 + CBitFieldMaskBit53 = 0x400 + CBitFieldMaskBit54 = 0x200 + CBitFieldMaskBit55 = 0x100 + CBitFieldMaskBit56 = 0x80 + CBitFieldMaskBit57 = 0x40 + CBitFieldMaskBit58 = 0x20 + CBitFieldMaskBit59 = 0x10 + CBitFieldMaskBit60 = 0x8 + CBitFieldMaskBit61 = 0x4 + CBitFieldMaskBit62 = 0x2 + CBitFieldMaskBit63 = 0x1 +) + +type SockaddrStorage struct { + Family uint16 + _ [118]int8 + _ uint64 +} + +type TCPMD5Sig struct { + Addr SockaddrStorage + Flags uint8 + Prefixlen uint8 + Keylen uint16 + _ uint32 + Key [80]uint8 +} + +type HDDriveCmdHdr struct { + Command uint8 + Number uint8 + Feature uint8 + Count uint8 +} + +type HDGeometry struct { + Heads uint8 + Sectors uint8 + Cylinders uint16 + Start uint64 +} + +type HDDriveID struct { + Config uint16 + Cyls uint16 + Reserved2 uint16 + Heads uint16 + Track_bytes uint16 + Sector_bytes uint16 + Sectors uint16 + Vendor0 uint16 + Vendor1 uint16 + Vendor2 uint16 + Serial_no [20]uint8 + Buf_type uint16 + Buf_size uint16 + Ecc_bytes uint16 + Fw_rev [8]uint8 + Model [40]uint8 + Max_multsect uint8 + Vendor3 uint8 + Dword_io uint16 + Vendor4 uint8 + Capability uint8 + Reserved50 uint16 + Vendor5 uint8 + TPIO uint8 + Vendor6 uint8 + TDMA uint8 + Field_valid uint16 + Cur_cyls uint16 + Cur_heads uint16 + Cur_sectors uint16 + Cur_capacity0 uint16 + Cur_capacity1 uint16 + Multsect uint8 + Multsect_valid uint8 + Lba_capacity uint32 + Dma_1word uint16 + Dma_mword uint16 + Eide_pio_modes uint16 + Eide_dma_min uint16 + Eide_dma_time uint16 + Eide_pio uint16 + Eide_pio_iordy uint16 + Words69_70 [2]uint16 + Words71_74 [4]uint16 + Queue_depth uint16 + Words76_79 [4]uint16 + Major_rev_num uint16 + Minor_rev_num uint16 + Command_set_1 uint16 + Command_set_2 uint16 + Cfsse uint16 + Cfs_enable_1 uint16 + Cfs_enable_2 uint16 + Csf_default uint16 + Dma_ultra uint16 + Trseuc uint16 + TrsEuc uint16 + CurAPMvalues uint16 + Mprc uint16 + Hw_config uint16 + Acoustic uint16 + Msrqs uint16 + Sxfert uint16 + Sal uint16 + Spg uint32 + Lba_capacity_2 uint64 + Words104_125 [22]uint16 + Last_lun uint16 + Word127 uint16 + Dlf uint16 + Csfo uint16 + Words130_155 [26]uint16 + Word156 uint16 + Words157_159 [3]uint16 + Cfa_power uint16 + Words161_175 [15]uint16 + Words176_205 [30]uint16 + Words206_254 [49]uint16 + Integrity_word uint16 +} + +type Statfs_t struct { + Type uint32 + Bsize uint32 + Blocks uint64 + Bfree uint64 + Bavail uint64 + Files uint64 + Ffree uint64 + Fsid Fsid + Namelen uint32 + Frsize uint32 + Flags uint32 + Spare [4]uint32 + _ [4]byte +} + +const ( + ST_MANDLOCK = 0x40 + ST_NOATIME = 0x400 + ST_NODEV = 0x4 + ST_NODIRATIME = 0x800 + ST_NOEXEC = 0x8 + ST_NOSUID = 0x2 + ST_RDONLY = 0x1 + ST_RELATIME = 0x1000 + ST_SYNCHRONOUS = 0x10 +) + +type TpacketHdr struct { + Status uint64 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Sec uint32 + Usec uint32 + _ [4]byte +} + +type Tpacket2Hdr struct { + Status uint32 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Sec uint32 + Nsec uint32 + Vlan_tci uint16 + Vlan_tpid uint16 + _ [4]uint8 +} + +type Tpacket3Hdr struct { + Next_offset uint32 + Sec uint32 + Nsec uint32 + Snaplen uint32 + Len uint32 + Status uint32 + Mac uint16 + Net uint16 + Hv1 TpacketHdrVariant1 + _ [8]uint8 +} + +type TpacketHdrVariant1 struct { + Rxhash uint32 + Vlan_tci uint32 + Vlan_tpid uint16 + _ uint16 +} + +type TpacketBlockDesc struct { + Version uint32 + To_priv uint32 + Hdr [40]byte +} + +type TpacketReq struct { + Block_size uint32 + Block_nr uint32 + Frame_size uint32 + Frame_nr uint32 +} + +type TpacketReq3 struct { + Block_size uint32 + Block_nr uint32 + Frame_size uint32 + Frame_nr uint32 + Retire_blk_tov uint32 + Sizeof_priv uint32 + Feature_req_word uint32 +} + +type TpacketStats struct { + Packets uint32 + Drops uint32 +} + +type TpacketStatsV3 struct { + Packets uint32 + Drops uint32 + Freeze_q_cnt uint32 +} + +type TpacketAuxdata struct { + Status uint32 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Vlan_tci uint16 + Vlan_tpid uint16 +} + +const ( + TPACKET_V1 = 0x0 + TPACKET_V2 = 0x1 + TPACKET_V3 = 0x2 +) + +const ( + SizeofTpacketHdr = 0x20 + SizeofTpacket2Hdr = 0x20 + SizeofTpacket3Hdr = 0x30 +) + +const ( + NF_INET_PRE_ROUTING = 0x0 + NF_INET_LOCAL_IN = 0x1 + NF_INET_FORWARD = 0x2 + NF_INET_LOCAL_OUT = 0x3 + NF_INET_POST_ROUTING = 0x4 + NF_INET_NUMHOOKS = 0x5 +) + +const ( + NF_NETDEV_INGRESS = 0x0 + NF_NETDEV_NUMHOOKS = 0x1 +) + +const ( + NFPROTO_UNSPEC = 0x0 + NFPROTO_INET = 0x1 + NFPROTO_IPV4 = 0x2 + NFPROTO_ARP = 0x3 + NFPROTO_NETDEV = 0x5 + NFPROTO_BRIDGE = 0x7 + NFPROTO_IPV6 = 0xa + NFPROTO_DECNET = 0xc + NFPROTO_NUMPROTO = 0xd +) + +type Nfgenmsg struct { + Nfgen_family uint8 + Version uint8 + Res_id uint16 +} + +const ( + NFNL_BATCH_UNSPEC = 0x0 + NFNL_BATCH_GENID = 0x1 +) + +const ( + NFT_REG_VERDICT = 0x0 + NFT_REG_1 = 0x1 + NFT_REG_2 = 0x2 + NFT_REG_3 = 0x3 + NFT_REG_4 = 0x4 + NFT_REG32_00 = 0x8 + NFT_REG32_01 = 0x9 + NFT_REG32_02 = 0xa + NFT_REG32_03 = 0xb + NFT_REG32_04 = 0xc + NFT_REG32_05 = 0xd + NFT_REG32_06 = 0xe + NFT_REG32_07 = 0xf + NFT_REG32_08 = 0x10 + NFT_REG32_09 = 0x11 + NFT_REG32_10 = 0x12 + NFT_REG32_11 = 0x13 + NFT_REG32_12 = 0x14 + NFT_REG32_13 = 0x15 + NFT_REG32_14 = 0x16 + NFT_REG32_15 = 0x17 + NFT_CONTINUE = -0x1 + NFT_BREAK = -0x2 + NFT_JUMP = -0x3 + NFT_GOTO = -0x4 + NFT_RETURN = -0x5 + NFT_MSG_NEWTABLE = 0x0 + NFT_MSG_GETTABLE = 0x1 + NFT_MSG_DELTABLE = 0x2 + NFT_MSG_NEWCHAIN = 0x3 + NFT_MSG_GETCHAIN = 0x4 + NFT_MSG_DELCHAIN = 0x5 + NFT_MSG_NEWRULE = 0x6 + NFT_MSG_GETRULE = 0x7 + NFT_MSG_DELRULE = 0x8 + NFT_MSG_NEWSET = 0x9 + NFT_MSG_GETSET = 0xa + NFT_MSG_DELSET = 0xb + NFT_MSG_NEWSETELEM = 0xc + NFT_MSG_GETSETELEM = 0xd + NFT_MSG_DELSETELEM = 0xe + NFT_MSG_NEWGEN = 0xf + NFT_MSG_GETGEN = 0x10 + NFT_MSG_TRACE = 0x11 + NFT_MSG_NEWOBJ = 0x12 + NFT_MSG_GETOBJ = 0x13 + NFT_MSG_DELOBJ = 0x14 + NFT_MSG_GETOBJ_RESET = 0x15 + NFT_MSG_MAX = 0x19 + NFTA_LIST_UNPEC = 0x0 + NFTA_LIST_ELEM = 0x1 + NFTA_HOOK_UNSPEC = 0x0 + NFTA_HOOK_HOOKNUM = 0x1 + NFTA_HOOK_PRIORITY = 0x2 + NFTA_HOOK_DEV = 0x3 + NFT_TABLE_F_DORMANT = 0x1 + NFTA_TABLE_UNSPEC = 0x0 + NFTA_TABLE_NAME = 0x1 + NFTA_TABLE_FLAGS = 0x2 + NFTA_TABLE_USE = 0x3 + NFTA_CHAIN_UNSPEC = 0x0 + NFTA_CHAIN_TABLE = 0x1 + NFTA_CHAIN_HANDLE = 0x2 + NFTA_CHAIN_NAME = 0x3 + NFTA_CHAIN_HOOK = 0x4 + NFTA_CHAIN_POLICY = 0x5 + NFTA_CHAIN_USE = 0x6 + NFTA_CHAIN_TYPE = 0x7 + NFTA_CHAIN_COUNTERS = 0x8 + NFTA_CHAIN_PAD = 0x9 + NFTA_RULE_UNSPEC = 0x0 + NFTA_RULE_TABLE = 0x1 + NFTA_RULE_CHAIN = 0x2 + NFTA_RULE_HANDLE = 0x3 + NFTA_RULE_EXPRESSIONS = 0x4 + NFTA_RULE_COMPAT = 0x5 + NFTA_RULE_POSITION = 0x6 + NFTA_RULE_USERDATA = 0x7 + NFTA_RULE_PAD = 0x8 + NFTA_RULE_ID = 0x9 + NFT_RULE_COMPAT_F_INV = 0x2 + NFT_RULE_COMPAT_F_MASK = 0x2 + NFTA_RULE_COMPAT_UNSPEC = 0x0 + NFTA_RULE_COMPAT_PROTO = 0x1 + NFTA_RULE_COMPAT_FLAGS = 0x2 + NFT_SET_ANONYMOUS = 0x1 + NFT_SET_CONSTANT = 0x2 + NFT_SET_INTERVAL = 0x4 + NFT_SET_MAP = 0x8 + NFT_SET_TIMEOUT = 0x10 + NFT_SET_EVAL = 0x20 + NFT_SET_OBJECT = 0x40 + NFT_SET_POL_PERFORMANCE = 0x0 + NFT_SET_POL_MEMORY = 0x1 + NFTA_SET_DESC_UNSPEC = 0x0 + NFTA_SET_DESC_SIZE = 0x1 + NFTA_SET_UNSPEC = 0x0 + NFTA_SET_TABLE = 0x1 + NFTA_SET_NAME = 0x2 + NFTA_SET_FLAGS = 0x3 + NFTA_SET_KEY_TYPE = 0x4 + NFTA_SET_KEY_LEN = 0x5 + NFTA_SET_DATA_TYPE = 0x6 + NFTA_SET_DATA_LEN = 0x7 + NFTA_SET_POLICY = 0x8 + NFTA_SET_DESC = 0x9 + NFTA_SET_ID = 0xa + NFTA_SET_TIMEOUT = 0xb + NFTA_SET_GC_INTERVAL = 0xc + NFTA_SET_USERDATA = 0xd + NFTA_SET_PAD = 0xe + NFTA_SET_OBJ_TYPE = 0xf + NFT_SET_ELEM_INTERVAL_END = 0x1 + NFTA_SET_ELEM_UNSPEC = 0x0 + NFTA_SET_ELEM_KEY = 0x1 + NFTA_SET_ELEM_DATA = 0x2 + NFTA_SET_ELEM_FLAGS = 0x3 + NFTA_SET_ELEM_TIMEOUT = 0x4 + NFTA_SET_ELEM_EXPIRATION = 0x5 + NFTA_SET_ELEM_USERDATA = 0x6 + NFTA_SET_ELEM_EXPR = 0x7 + NFTA_SET_ELEM_PAD = 0x8 + NFTA_SET_ELEM_OBJREF = 0x9 + NFTA_SET_ELEM_LIST_UNSPEC = 0x0 + NFTA_SET_ELEM_LIST_TABLE = 0x1 + NFTA_SET_ELEM_LIST_SET = 0x2 + NFTA_SET_ELEM_LIST_ELEMENTS = 0x3 + NFTA_SET_ELEM_LIST_SET_ID = 0x4 + NFT_DATA_VALUE = 0x0 + NFT_DATA_VERDICT = 0xffffff00 + NFTA_DATA_UNSPEC = 0x0 + NFTA_DATA_VALUE = 0x1 + NFTA_DATA_VERDICT = 0x2 + NFTA_VERDICT_UNSPEC = 0x0 + NFTA_VERDICT_CODE = 0x1 + NFTA_VERDICT_CHAIN = 0x2 + NFTA_EXPR_UNSPEC = 0x0 + NFTA_EXPR_NAME = 0x1 + NFTA_EXPR_DATA = 0x2 + NFTA_IMMEDIATE_UNSPEC = 0x0 + NFTA_IMMEDIATE_DREG = 0x1 + NFTA_IMMEDIATE_DATA = 0x2 + NFTA_BITWISE_UNSPEC = 0x0 + NFTA_BITWISE_SREG = 0x1 + NFTA_BITWISE_DREG = 0x2 + NFTA_BITWISE_LEN = 0x3 + NFTA_BITWISE_MASK = 0x4 + NFTA_BITWISE_XOR = 0x5 + NFT_BYTEORDER_NTOH = 0x0 + NFT_BYTEORDER_HTON = 0x1 + NFTA_BYTEORDER_UNSPEC = 0x0 + NFTA_BYTEORDER_SREG = 0x1 + NFTA_BYTEORDER_DREG = 0x2 + NFTA_BYTEORDER_OP = 0x3 + NFTA_BYTEORDER_LEN = 0x4 + NFTA_BYTEORDER_SIZE = 0x5 + NFT_CMP_EQ = 0x0 + NFT_CMP_NEQ = 0x1 + NFT_CMP_LT = 0x2 + NFT_CMP_LTE = 0x3 + NFT_CMP_GT = 0x4 + NFT_CMP_GTE = 0x5 + NFTA_CMP_UNSPEC = 0x0 + NFTA_CMP_SREG = 0x1 + NFTA_CMP_OP = 0x2 + NFTA_CMP_DATA = 0x3 + NFT_RANGE_EQ = 0x0 + NFT_RANGE_NEQ = 0x1 + NFTA_RANGE_UNSPEC = 0x0 + NFTA_RANGE_SREG = 0x1 + NFTA_RANGE_OP = 0x2 + NFTA_RANGE_FROM_DATA = 0x3 + NFTA_RANGE_TO_DATA = 0x4 + NFT_LOOKUP_F_INV = 0x1 + NFTA_LOOKUP_UNSPEC = 0x0 + NFTA_LOOKUP_SET = 0x1 + NFTA_LOOKUP_SREG = 0x2 + NFTA_LOOKUP_DREG = 0x3 + NFTA_LOOKUP_SET_ID = 0x4 + NFTA_LOOKUP_FLAGS = 0x5 + NFT_DYNSET_OP_ADD = 0x0 + NFT_DYNSET_OP_UPDATE = 0x1 + NFT_DYNSET_F_INV = 0x1 + NFTA_DYNSET_UNSPEC = 0x0 + NFTA_DYNSET_SET_NAME = 0x1 + NFTA_DYNSET_SET_ID = 0x2 + NFTA_DYNSET_OP = 0x3 + NFTA_DYNSET_SREG_KEY = 0x4 + NFTA_DYNSET_SREG_DATA = 0x5 + NFTA_DYNSET_TIMEOUT = 0x6 + NFTA_DYNSET_EXPR = 0x7 + NFTA_DYNSET_PAD = 0x8 + NFTA_DYNSET_FLAGS = 0x9 + NFT_PAYLOAD_LL_HEADER = 0x0 + NFT_PAYLOAD_NETWORK_HEADER = 0x1 + NFT_PAYLOAD_TRANSPORT_HEADER = 0x2 + NFT_PAYLOAD_CSUM_NONE = 0x0 + NFT_PAYLOAD_CSUM_INET = 0x1 + NFT_PAYLOAD_L4CSUM_PSEUDOHDR = 0x1 + NFTA_PAYLOAD_UNSPEC = 0x0 + NFTA_PAYLOAD_DREG = 0x1 + NFTA_PAYLOAD_BASE = 0x2 + NFTA_PAYLOAD_OFFSET = 0x3 + NFTA_PAYLOAD_LEN = 0x4 + NFTA_PAYLOAD_SREG = 0x5 + NFTA_PAYLOAD_CSUM_TYPE = 0x6 + NFTA_PAYLOAD_CSUM_OFFSET = 0x7 + NFTA_PAYLOAD_CSUM_FLAGS = 0x8 + NFT_EXTHDR_F_PRESENT = 0x1 + NFT_EXTHDR_OP_IPV6 = 0x0 + NFT_EXTHDR_OP_TCPOPT = 0x1 + NFTA_EXTHDR_UNSPEC = 0x0 + NFTA_EXTHDR_DREG = 0x1 + NFTA_EXTHDR_TYPE = 0x2 + NFTA_EXTHDR_OFFSET = 0x3 + NFTA_EXTHDR_LEN = 0x4 + NFTA_EXTHDR_FLAGS = 0x5 + NFTA_EXTHDR_OP = 0x6 + NFTA_EXTHDR_SREG = 0x7 + NFT_META_LEN = 0x0 + NFT_META_PROTOCOL = 0x1 + NFT_META_PRIORITY = 0x2 + NFT_META_MARK = 0x3 + NFT_META_IIF = 0x4 + NFT_META_OIF = 0x5 + NFT_META_IIFNAME = 0x6 + NFT_META_OIFNAME = 0x7 + NFT_META_IIFTYPE = 0x8 + NFT_META_OIFTYPE = 0x9 + NFT_META_SKUID = 0xa + NFT_META_SKGID = 0xb + NFT_META_NFTRACE = 0xc + NFT_META_RTCLASSID = 0xd + NFT_META_SECMARK = 0xe + NFT_META_NFPROTO = 0xf + NFT_META_L4PROTO = 0x10 + NFT_META_BRI_IIFNAME = 0x11 + NFT_META_BRI_OIFNAME = 0x12 + NFT_META_PKTTYPE = 0x13 + NFT_META_CPU = 0x14 + NFT_META_IIFGROUP = 0x15 + NFT_META_OIFGROUP = 0x16 + NFT_META_CGROUP = 0x17 + NFT_META_PRANDOM = 0x18 + NFT_RT_CLASSID = 0x0 + NFT_RT_NEXTHOP4 = 0x1 + NFT_RT_NEXTHOP6 = 0x2 + NFT_RT_TCPMSS = 0x3 + NFT_HASH_JENKINS = 0x0 + NFT_HASH_SYM = 0x1 + NFTA_HASH_UNSPEC = 0x0 + NFTA_HASH_SREG = 0x1 + NFTA_HASH_DREG = 0x2 + NFTA_HASH_LEN = 0x3 + NFTA_HASH_MODULUS = 0x4 + NFTA_HASH_SEED = 0x5 + NFTA_HASH_OFFSET = 0x6 + NFTA_HASH_TYPE = 0x7 + NFTA_META_UNSPEC = 0x0 + NFTA_META_DREG = 0x1 + NFTA_META_KEY = 0x2 + NFTA_META_SREG = 0x3 + NFTA_RT_UNSPEC = 0x0 + NFTA_RT_DREG = 0x1 + NFTA_RT_KEY = 0x2 + NFT_CT_STATE = 0x0 + NFT_CT_DIRECTION = 0x1 + NFT_CT_STATUS = 0x2 + NFT_CT_MARK = 0x3 + NFT_CT_SECMARK = 0x4 + NFT_CT_EXPIRATION = 0x5 + NFT_CT_HELPER = 0x6 + NFT_CT_L3PROTOCOL = 0x7 + NFT_CT_SRC = 0x8 + NFT_CT_DST = 0x9 + NFT_CT_PROTOCOL = 0xa + NFT_CT_PROTO_SRC = 0xb + NFT_CT_PROTO_DST = 0xc + NFT_CT_LABELS = 0xd + NFT_CT_PKTS = 0xe + NFT_CT_BYTES = 0xf + NFT_CT_AVGPKT = 0x10 + NFT_CT_ZONE = 0x11 + NFT_CT_EVENTMASK = 0x12 + NFTA_CT_UNSPEC = 0x0 + NFTA_CT_DREG = 0x1 + NFTA_CT_KEY = 0x2 + NFTA_CT_DIRECTION = 0x3 + NFTA_CT_SREG = 0x4 + NFT_LIMIT_PKTS = 0x0 + NFT_LIMIT_PKT_BYTES = 0x1 + NFT_LIMIT_F_INV = 0x1 + NFTA_LIMIT_UNSPEC = 0x0 + NFTA_LIMIT_RATE = 0x1 + NFTA_LIMIT_UNIT = 0x2 + NFTA_LIMIT_BURST = 0x3 + NFTA_LIMIT_TYPE = 0x4 + NFTA_LIMIT_FLAGS = 0x5 + NFTA_LIMIT_PAD = 0x6 + NFTA_COUNTER_UNSPEC = 0x0 + NFTA_COUNTER_BYTES = 0x1 + NFTA_COUNTER_PACKETS = 0x2 + NFTA_COUNTER_PAD = 0x3 + NFTA_LOG_UNSPEC = 0x0 + NFTA_LOG_GROUP = 0x1 + NFTA_LOG_PREFIX = 0x2 + NFTA_LOG_SNAPLEN = 0x3 + NFTA_LOG_QTHRESHOLD = 0x4 + NFTA_LOG_LEVEL = 0x5 + NFTA_LOG_FLAGS = 0x6 + NFTA_QUEUE_UNSPEC = 0x0 + NFTA_QUEUE_NUM = 0x1 + NFTA_QUEUE_TOTAL = 0x2 + NFTA_QUEUE_FLAGS = 0x3 + NFTA_QUEUE_SREG_QNUM = 0x4 + NFT_QUOTA_F_INV = 0x1 + NFT_QUOTA_F_DEPLETED = 0x2 + NFTA_QUOTA_UNSPEC = 0x0 + NFTA_QUOTA_BYTES = 0x1 + NFTA_QUOTA_FLAGS = 0x2 + NFTA_QUOTA_PAD = 0x3 + NFTA_QUOTA_CONSUMED = 0x4 + NFT_REJECT_ICMP_UNREACH = 0x0 + NFT_REJECT_TCP_RST = 0x1 + NFT_REJECT_ICMPX_UNREACH = 0x2 + NFT_REJECT_ICMPX_NO_ROUTE = 0x0 + NFT_REJECT_ICMPX_PORT_UNREACH = 0x1 + NFT_REJECT_ICMPX_HOST_UNREACH = 0x2 + NFT_REJECT_ICMPX_ADMIN_PROHIBITED = 0x3 + NFTA_REJECT_UNSPEC = 0x0 + NFTA_REJECT_TYPE = 0x1 + NFTA_REJECT_ICMP_CODE = 0x2 + NFT_NAT_SNAT = 0x0 + NFT_NAT_DNAT = 0x1 + NFTA_NAT_UNSPEC = 0x0 + NFTA_NAT_TYPE = 0x1 + NFTA_NAT_FAMILY = 0x2 + NFTA_NAT_REG_ADDR_MIN = 0x3 + NFTA_NAT_REG_ADDR_MAX = 0x4 + NFTA_NAT_REG_PROTO_MIN = 0x5 + NFTA_NAT_REG_PROTO_MAX = 0x6 + NFTA_NAT_FLAGS = 0x7 + NFTA_MASQ_UNSPEC = 0x0 + NFTA_MASQ_FLAGS = 0x1 + NFTA_MASQ_REG_PROTO_MIN = 0x2 + NFTA_MASQ_REG_PROTO_MAX = 0x3 + NFTA_REDIR_UNSPEC = 0x0 + NFTA_REDIR_REG_PROTO_MIN = 0x1 + NFTA_REDIR_REG_PROTO_MAX = 0x2 + NFTA_REDIR_FLAGS = 0x3 + NFTA_DUP_UNSPEC = 0x0 + NFTA_DUP_SREG_ADDR = 0x1 + NFTA_DUP_SREG_DEV = 0x2 + NFTA_FWD_UNSPEC = 0x0 + NFTA_FWD_SREG_DEV = 0x1 + NFTA_OBJREF_UNSPEC = 0x0 + NFTA_OBJREF_IMM_TYPE = 0x1 + NFTA_OBJREF_IMM_NAME = 0x2 + NFTA_OBJREF_SET_SREG = 0x3 + NFTA_OBJREF_SET_NAME = 0x4 + NFTA_OBJREF_SET_ID = 0x5 + NFTA_GEN_UNSPEC = 0x0 + NFTA_GEN_ID = 0x1 + NFTA_GEN_PROC_PID = 0x2 + NFTA_GEN_PROC_NAME = 0x3 + NFTA_FIB_UNSPEC = 0x0 + NFTA_FIB_DREG = 0x1 + NFTA_FIB_RESULT = 0x2 + NFTA_FIB_FLAGS = 0x3 + NFT_FIB_RESULT_UNSPEC = 0x0 + NFT_FIB_RESULT_OIF = 0x1 + NFT_FIB_RESULT_OIFNAME = 0x2 + NFT_FIB_RESULT_ADDRTYPE = 0x3 + NFTA_FIB_F_SADDR = 0x1 + NFTA_FIB_F_DADDR = 0x2 + NFTA_FIB_F_MARK = 0x4 + NFTA_FIB_F_IIF = 0x8 + NFTA_FIB_F_OIF = 0x10 + NFTA_FIB_F_PRESENT = 0x20 + NFTA_CT_HELPER_UNSPEC = 0x0 + NFTA_CT_HELPER_NAME = 0x1 + NFTA_CT_HELPER_L3PROTO = 0x2 + NFTA_CT_HELPER_L4PROTO = 0x3 + NFTA_OBJ_UNSPEC = 0x0 + NFTA_OBJ_TABLE = 0x1 + NFTA_OBJ_NAME = 0x2 + NFTA_OBJ_TYPE = 0x3 + NFTA_OBJ_DATA = 0x4 + NFTA_OBJ_USE = 0x5 + NFTA_TRACE_UNSPEC = 0x0 + NFTA_TRACE_TABLE = 0x1 + NFTA_TRACE_CHAIN = 0x2 + NFTA_TRACE_RULE_HANDLE = 0x3 + NFTA_TRACE_TYPE = 0x4 + NFTA_TRACE_VERDICT = 0x5 + NFTA_TRACE_ID = 0x6 + NFTA_TRACE_LL_HEADER = 0x7 + NFTA_TRACE_NETWORK_HEADER = 0x8 + NFTA_TRACE_TRANSPORT_HEADER = 0x9 + NFTA_TRACE_IIF = 0xa + NFTA_TRACE_IIFTYPE = 0xb + NFTA_TRACE_OIF = 0xc + NFTA_TRACE_OIFTYPE = 0xd + NFTA_TRACE_MARK = 0xe + NFTA_TRACE_NFPROTO = 0xf + NFTA_TRACE_POLICY = 0x10 + NFTA_TRACE_PAD = 0x11 + NFT_TRACETYPE_UNSPEC = 0x0 + NFT_TRACETYPE_POLICY = 0x1 + NFT_TRACETYPE_RETURN = 0x2 + NFT_TRACETYPE_RULE = 0x3 + NFTA_NG_UNSPEC = 0x0 + NFTA_NG_DREG = 0x1 + NFTA_NG_MODULUS = 0x2 + NFTA_NG_TYPE = 0x3 + NFTA_NG_OFFSET = 0x4 + NFT_NG_INCREMENTAL = 0x0 + NFT_NG_RANDOM = 0x1 +) + +type RTCTime struct { + Sec int32 + Min int32 + Hour int32 + Mday int32 + Mon int32 + Year int32 + Wday int32 + Yday int32 + Isdst int32 +} + +type RTCWkAlrm struct { + Enabled uint8 + Pending uint8 + Time RTCTime +} + +type RTCPLLInfo struct { + Ctrl int32 + Value int32 + Max int32 + Min int32 + Posmult int32 + Negmult int32 + Clock int64 +} + +type BlkpgIoctlArg struct { + Op int32 + Flags int32 + Datalen int32 + Data *byte +} + +type BlkpgPartition struct { + Start int64 + Length int64 + Pno int32 + Devname [64]uint8 + Volname [64]uint8 + _ [4]byte +} + +const ( + BLKPG = 0x1269 + BLKPG_ADD_PARTITION = 0x1 + BLKPG_DEL_PARTITION = 0x2 + BLKPG_RESIZE_PARTITION = 0x3 +) + +const ( + NETNSA_NONE = 0x0 + NETNSA_NSID = 0x1 + NETNSA_PID = 0x2 + NETNSA_FD = 0x3 +) + +type XDPRingOffset struct { + Producer uint64 + Consumer uint64 + Desc uint64 +} + +type XDPMmapOffsets struct { + Rx XDPRingOffset + Tx XDPRingOffset + Fr XDPRingOffset + Cr XDPRingOffset +} + +type XDPUmemReg struct { + Addr uint64 + Len uint64 + Size uint32 + Headroom uint32 +} + +type XDPStatistics struct { + Rx_dropped uint64 + Rx_invalid_descs uint64 + Tx_invalid_descs uint64 +} + +type XDPDesc struct { + Addr uint64 + Len uint32 + Options uint32 +} + +const ( + NCSI_CMD_UNSPEC = 0x0 + NCSI_CMD_PKG_INFO = 0x1 + NCSI_CMD_SET_INTERFACE = 0x2 + NCSI_CMD_CLEAR_INTERFACE = 0x3 + NCSI_ATTR_UNSPEC = 0x0 + NCSI_ATTR_IFINDEX = 0x1 + NCSI_ATTR_PACKAGE_LIST = 0x2 + NCSI_ATTR_PACKAGE_ID = 0x3 + NCSI_ATTR_CHANNEL_ID = 0x4 + NCSI_PKG_ATTR_UNSPEC = 0x0 + NCSI_PKG_ATTR = 0x1 + NCSI_PKG_ATTR_ID = 0x2 + NCSI_PKG_ATTR_FORCED = 0x3 + NCSI_PKG_ATTR_CHANNEL_LIST = 0x4 + NCSI_CHANNEL_ATTR_UNSPEC = 0x0 + NCSI_CHANNEL_ATTR = 0x1 + NCSI_CHANNEL_ATTR_ID = 0x2 + NCSI_CHANNEL_ATTR_VERSION_MAJOR = 0x3 + NCSI_CHANNEL_ATTR_VERSION_MINOR = 0x4 + NCSI_CHANNEL_ATTR_VERSION_STR = 0x5 + NCSI_CHANNEL_ATTR_LINK_STATE = 0x6 + NCSI_CHANNEL_ATTR_ACTIVE = 0x7 + NCSI_CHANNEL_ATTR_FORCED = 0x8 + NCSI_CHANNEL_ATTR_VLAN_LIST = 0x9 + NCSI_CHANNEL_ATTR_VLAN_ID = 0xa +) + +type ScmTimestamping struct { + Ts [3]Timespec +} + +const ( + SOF_TIMESTAMPING_TX_HARDWARE = 0x1 + SOF_TIMESTAMPING_TX_SOFTWARE = 0x2 + SOF_TIMESTAMPING_RX_HARDWARE = 0x4 + SOF_TIMESTAMPING_RX_SOFTWARE = 0x8 + SOF_TIMESTAMPING_SOFTWARE = 0x10 + SOF_TIMESTAMPING_SYS_HARDWARE = 0x20 + SOF_TIMESTAMPING_RAW_HARDWARE = 0x40 + SOF_TIMESTAMPING_OPT_ID = 0x80 + SOF_TIMESTAMPING_TX_SCHED = 0x100 + SOF_TIMESTAMPING_TX_ACK = 0x200 + SOF_TIMESTAMPING_OPT_CMSG = 0x400 + SOF_TIMESTAMPING_OPT_TSONLY = 0x800 + SOF_TIMESTAMPING_OPT_STATS = 0x1000 + SOF_TIMESTAMPING_OPT_PKTINFO = 0x2000 + SOF_TIMESTAMPING_OPT_TX_SWHW = 0x4000 + + SOF_TIMESTAMPING_LAST = 0x4000 + SOF_TIMESTAMPING_MASK = 0x7fff + + SCM_TSTAMP_SND = 0x0 + SCM_TSTAMP_SCHED = 0x1 + SCM_TSTAMP_ACK = 0x2 +) + +type SockExtendedErr struct { + Errno uint32 + Origin uint8 + Type uint8 + Code uint8 + Pad uint8 + Info uint32 + Data uint32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go index 9dbbb1ce52..a1a9279c22 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go @@ -1,15 +1,16 @@ +// cgo -godefs -- -Wall -Werror -static -I/tmp/include linux/types.go | go run mkpost.go +// Code generated by the command above; see README.md. DO NOT EDIT. + // +build sparc64,linux -// Created by cgo -godefs - DO NOT EDIT -// cgo -godefs types_linux.go | go run mkpost.go package unix const ( - sizeofPtr = 0x8 - sizeofShort = 0x2 - sizeofInt = 0x4 - sizeofLong = 0x8 - sizeofLongLong = 0x8 + SizeofPtr = 0x8 + SizeofShort = 0x2 + SizeofInt = 0x4 + SizeofLong = 0x8 + SizeofLongLong = 0x8 PathMax = 0x1000 ) @@ -26,20 +27,18 @@ type Timespec struct { } type Timeval struct { - Sec int64 - Usec int32 - Pad_cgo_0 [4]byte + Sec int64 + Usec int32 + _ [4]byte } type Timex struct { Modes uint32 - Pad_cgo_0 [4]byte Offset int64 Freq int64 Maxerror int64 Esterror int64 Status int32 - Pad_cgo_1 [4]byte Constant int64 Precision int64 Tolerance int64 @@ -48,14 +47,13 @@ type Timex struct { Ppsfreq int64 Jitter int64 Shift int32 - Pad_cgo_2 [4]byte Stabil int64 Jitcnt int64 Calcnt int64 Errcnt int64 Stbcnt int64 Tai int32 - Pad_cgo_3 [44]byte + _ [44]byte } type Time_t int64 @@ -99,64 +97,96 @@ type Rlimit struct { type _Gid_t uint32 type Stat_t struct { - Dev uint64 - X__pad1 uint16 - Pad_cgo_0 [6]byte - Ino uint64 - Mode uint32 - Nlink uint32 - Uid uint32 - Gid uint32 - Rdev uint64 - X__pad2 uint16 - Pad_cgo_1 [6]byte - Size int64 - Blksize int64 - Blocks int64 - Atim Timespec - Mtim Timespec - Ctim Timespec - X__glibc_reserved4 uint64 - X__glibc_reserved5 uint64 + Dev uint64 + _ uint16 + Ino uint64 + Mode uint32 + Nlink uint32 + Uid uint32 + Gid uint32 + Rdev uint64 + _ uint16 + Size int64 + Blksize int64 + Blocks int64 + Atim Timespec + Mtim Timespec + Ctim Timespec + _ uint64 + _ uint64 } -type Statfs_t struct { - Type int64 - Bsize int64 - Blocks uint64 - Bfree uint64 - Bavail uint64 - Files uint64 - Ffree uint64 - Fsid Fsid - Namelen int64 - Frsize int64 - Flags int64 - Spare [4]int64 +type StatxTimestamp struct { + Sec int64 + Nsec uint32 + _ int32 +} + +type Statx_t struct { + Mask uint32 + Blksize uint32 + Attributes uint64 + Nlink uint32 + Uid uint32 + Gid uint32 + Mode uint16 + _ [1]uint16 + Ino uint64 + Size uint64 + Blocks uint64 + Attributes_mask uint64 + Atime StatxTimestamp + Btime StatxTimestamp + Ctime StatxTimestamp + Mtime StatxTimestamp + Rdev_major uint32 + Rdev_minor uint32 + Dev_major uint32 + Dev_minor uint32 + _ [14]uint64 } type Dirent struct { - Ino uint64 - Off int64 - Reclen uint16 - Type uint8 - Name [256]int8 - Pad_cgo_0 [5]byte + Ino uint64 + Off int64 + Reclen uint16 + Type uint8 + Name [256]int8 + _ [5]byte } type Fsid struct { - X__val [2]int32 + Val [2]int32 } type Flock_t struct { - Type int16 - Whence int16 - Pad_cgo_0 [4]byte - Start int64 - Len int64 - Pid int32 - X__glibc_reserved int16 - Pad_cgo_1 [2]byte + Type int16 + Whence int16 + Start int64 + Len int64 + Pid int32 + _ int16 + _ [2]byte +} + +type FscryptPolicy struct { + Version uint8 + Contents_encryption_mode uint8 + Filenames_encryption_mode uint8 + Flags uint8 + Master_key_descriptor [8]uint8 +} + +type FscryptKey struct { + Mode uint32 + Raw [64]uint8 + Size uint32 +} + +type KeyctlDHParams struct { + Private int32 + Prime int32 + Base int32 } const ( @@ -211,11 +241,26 @@ type RawSockaddrHCI struct { Channel uint16 } +type RawSockaddrL2 struct { + Family uint16 + Psm uint16 + Bdaddr [6]uint8 + Cid uint16 + Bdaddr_type uint8 + _ [1]byte +} + +type RawSockaddrRFCOMM struct { + Family uint16 + Bdaddr [6]uint8 + Channel uint8 + _ [1]byte +} + type RawSockaddrCAN struct { - Family uint16 - Pad_cgo_0 [2]byte - Ifindex int32 - Addr [8]byte + Family uint16 + Ifindex int32 + Addr [8]byte } type RawSockaddrALG struct { @@ -234,6 +279,16 @@ type RawSockaddrVM struct { Zero [4]uint8 } +type RawSockaddrXDP struct { + Family uint16 + Flags uint16 + Ifindex uint32 + Queue_id uint32 + Shared_umem_fd uint32 +} + +type RawSockaddrPPPoX [0x1e]byte + type RawSockaddr struct { Family uint16 Data [14]int8 @@ -272,16 +327,22 @@ type IPv6Mreq struct { Interface uint32 } +type PacketMreq struct { + Ifindex int32 + Type uint16 + Alen uint16 + Address [8]uint8 +} + type Msghdr struct { Name *byte Namelen uint32 - Pad_cgo_0 [4]byte Iov *Iovec Iovlen uint64 Control *byte Controllen uint64 Flags int32 - Pad_cgo_1 [4]byte + _ [4]byte } type Cmsghdr struct { @@ -323,7 +384,6 @@ type TCPInfo struct { Probes uint8 Backoff uint8 Options uint8 - Pad_cgo_0 [2]byte Rto uint32 Ato uint32 Snd_mss uint32 @@ -358,13 +418,19 @@ const ( SizeofSockaddrLinklayer = 0x14 SizeofSockaddrNetlink = 0xc SizeofSockaddrHCI = 0x6 + SizeofSockaddrL2 = 0xe + SizeofSockaddrRFCOMM = 0xa SizeofSockaddrCAN = 0x10 SizeofSockaddrALG = 0x58 SizeofSockaddrVM = 0x10 + SizeofSockaddrXDP = 0x10 + SizeofSockaddrPPPoX = 0x1e SizeofLinger = 0x8 + SizeofIovec = 0x10 SizeofIPMreq = 0x8 SizeofIPMreqn = 0xc SizeofIPv6Mreq = 0x14 + SizeofPacketMreq = 0x10 SizeofMsghdr = 0x38 SizeofCmsghdr = 0x10 SizeofInet4Pktinfo = 0xc @@ -376,97 +442,138 @@ const ( ) const ( - IFA_UNSPEC = 0x0 - IFA_ADDRESS = 0x1 - IFA_LOCAL = 0x2 - IFA_LABEL = 0x3 - IFA_BROADCAST = 0x4 - IFA_ANYCAST = 0x5 - IFA_CACHEINFO = 0x6 - IFA_MULTICAST = 0x7 - IFLA_UNSPEC = 0x0 - IFLA_ADDRESS = 0x1 - IFLA_BROADCAST = 0x2 - IFLA_IFNAME = 0x3 - IFLA_MTU = 0x4 - IFLA_LINK = 0x5 - IFLA_QDISC = 0x6 - IFLA_STATS = 0x7 - IFLA_COST = 0x8 - IFLA_PRIORITY = 0x9 - IFLA_MASTER = 0xa - IFLA_WIRELESS = 0xb - IFLA_PROTINFO = 0xc - IFLA_TXQLEN = 0xd - IFLA_MAP = 0xe - IFLA_WEIGHT = 0xf - IFLA_OPERSTATE = 0x10 - IFLA_LINKMODE = 0x11 - IFLA_LINKINFO = 0x12 - IFLA_NET_NS_PID = 0x13 - IFLA_IFALIAS = 0x14 - IFLA_MAX = 0x2a - RT_SCOPE_UNIVERSE = 0x0 - RT_SCOPE_SITE = 0xc8 - RT_SCOPE_LINK = 0xfd - RT_SCOPE_HOST = 0xfe - RT_SCOPE_NOWHERE = 0xff - RT_TABLE_UNSPEC = 0x0 - RT_TABLE_COMPAT = 0xfc - RT_TABLE_DEFAULT = 0xfd - RT_TABLE_MAIN = 0xfe - RT_TABLE_LOCAL = 0xff - RT_TABLE_MAX = 0xffffffff - RTA_UNSPEC = 0x0 - RTA_DST = 0x1 - RTA_SRC = 0x2 - RTA_IIF = 0x3 - RTA_OIF = 0x4 - RTA_GATEWAY = 0x5 - RTA_PRIORITY = 0x6 - RTA_PREFSRC = 0x7 - RTA_METRICS = 0x8 - RTA_MULTIPATH = 0x9 - RTA_FLOW = 0xb - RTA_CACHEINFO = 0xc - RTA_TABLE = 0xf - RTN_UNSPEC = 0x0 - RTN_UNICAST = 0x1 - RTN_LOCAL = 0x2 - RTN_BROADCAST = 0x3 - RTN_ANYCAST = 0x4 - RTN_MULTICAST = 0x5 - RTN_BLACKHOLE = 0x6 - RTN_UNREACHABLE = 0x7 - RTN_PROHIBIT = 0x8 - RTN_THROW = 0x9 - RTN_NAT = 0xa - RTN_XRESOLVE = 0xb - RTNLGRP_NONE = 0x0 - RTNLGRP_LINK = 0x1 - RTNLGRP_NOTIFY = 0x2 - RTNLGRP_NEIGH = 0x3 - RTNLGRP_TC = 0x4 - RTNLGRP_IPV4_IFADDR = 0x5 - RTNLGRP_IPV4_MROUTE = 0x6 - RTNLGRP_IPV4_ROUTE = 0x7 - RTNLGRP_IPV4_RULE = 0x8 - RTNLGRP_IPV6_IFADDR = 0x9 - RTNLGRP_IPV6_MROUTE = 0xa - RTNLGRP_IPV6_ROUTE = 0xb - RTNLGRP_IPV6_IFINFO = 0xc - RTNLGRP_IPV6_PREFIX = 0x12 - RTNLGRP_IPV6_RULE = 0x13 - RTNLGRP_ND_USEROPT = 0x14 - SizeofNlMsghdr = 0x10 - SizeofNlMsgerr = 0x14 - SizeofRtGenmsg = 0x1 - SizeofNlAttr = 0x4 - SizeofRtAttr = 0x4 - SizeofIfInfomsg = 0x10 - SizeofIfAddrmsg = 0x8 - SizeofRtMsg = 0xc - SizeofRtNexthop = 0x8 + IFA_UNSPEC = 0x0 + IFA_ADDRESS = 0x1 + IFA_LOCAL = 0x2 + IFA_LABEL = 0x3 + IFA_BROADCAST = 0x4 + IFA_ANYCAST = 0x5 + IFA_CACHEINFO = 0x6 + IFA_MULTICAST = 0x7 + IFLA_UNSPEC = 0x0 + IFLA_ADDRESS = 0x1 + IFLA_BROADCAST = 0x2 + IFLA_IFNAME = 0x3 + IFLA_INFO_KIND = 0x1 + IFLA_MTU = 0x4 + IFLA_LINK = 0x5 + IFLA_QDISC = 0x6 + IFLA_STATS = 0x7 + IFLA_COST = 0x8 + IFLA_PRIORITY = 0x9 + IFLA_MASTER = 0xa + IFLA_WIRELESS = 0xb + IFLA_PROTINFO = 0xc + IFLA_TXQLEN = 0xd + IFLA_MAP = 0xe + IFLA_WEIGHT = 0xf + IFLA_OPERSTATE = 0x10 + IFLA_LINKMODE = 0x11 + IFLA_LINKINFO = 0x12 + IFLA_NET_NS_PID = 0x13 + IFLA_IFALIAS = 0x14 + IFLA_NUM_VF = 0x15 + IFLA_VFINFO_LIST = 0x16 + IFLA_STATS64 = 0x17 + IFLA_VF_PORTS = 0x18 + IFLA_PORT_SELF = 0x19 + IFLA_AF_SPEC = 0x1a + IFLA_GROUP = 0x1b + IFLA_NET_NS_FD = 0x1c + IFLA_EXT_MASK = 0x1d + IFLA_PROMISCUITY = 0x1e + IFLA_NUM_TX_QUEUES = 0x1f + IFLA_NUM_RX_QUEUES = 0x20 + IFLA_CARRIER = 0x21 + IFLA_PHYS_PORT_ID = 0x22 + IFLA_CARRIER_CHANGES = 0x23 + IFLA_PHYS_SWITCH_ID = 0x24 + IFLA_LINK_NETNSID = 0x25 + IFLA_PHYS_PORT_NAME = 0x26 + IFLA_PROTO_DOWN = 0x27 + IFLA_GSO_MAX_SEGS = 0x28 + IFLA_GSO_MAX_SIZE = 0x29 + IFLA_PAD = 0x2a + IFLA_XDP = 0x2b + IFLA_EVENT = 0x2c + IFLA_NEW_NETNSID = 0x2d + IFLA_IF_NETNSID = 0x2e + IFLA_MAX = 0x33 + RT_SCOPE_UNIVERSE = 0x0 + RT_SCOPE_SITE = 0xc8 + RT_SCOPE_LINK = 0xfd + RT_SCOPE_HOST = 0xfe + RT_SCOPE_NOWHERE = 0xff + RT_TABLE_UNSPEC = 0x0 + RT_TABLE_COMPAT = 0xfc + RT_TABLE_DEFAULT = 0xfd + RT_TABLE_MAIN = 0xfe + RT_TABLE_LOCAL = 0xff + RT_TABLE_MAX = 0xffffffff + RTA_UNSPEC = 0x0 + RTA_DST = 0x1 + RTA_SRC = 0x2 + RTA_IIF = 0x3 + RTA_OIF = 0x4 + RTA_GATEWAY = 0x5 + RTA_PRIORITY = 0x6 + RTA_PREFSRC = 0x7 + RTA_METRICS = 0x8 + RTA_MULTIPATH = 0x9 + RTA_FLOW = 0xb + RTA_CACHEINFO = 0xc + RTA_TABLE = 0xf + RTA_MARK = 0x10 + RTA_MFC_STATS = 0x11 + RTA_VIA = 0x12 + RTA_NEWDST = 0x13 + RTA_PREF = 0x14 + RTA_ENCAP_TYPE = 0x15 + RTA_ENCAP = 0x16 + RTA_EXPIRES = 0x17 + RTA_PAD = 0x18 + RTA_UID = 0x19 + RTA_TTL_PROPAGATE = 0x1a + RTA_IP_PROTO = 0x1b + RTA_SPORT = 0x1c + RTA_DPORT = 0x1d + RTN_UNSPEC = 0x0 + RTN_UNICAST = 0x1 + RTN_LOCAL = 0x2 + RTN_BROADCAST = 0x3 + RTN_ANYCAST = 0x4 + RTN_MULTICAST = 0x5 + RTN_BLACKHOLE = 0x6 + RTN_UNREACHABLE = 0x7 + RTN_PROHIBIT = 0x8 + RTN_THROW = 0x9 + RTN_NAT = 0xa + RTN_XRESOLVE = 0xb + RTNLGRP_NONE = 0x0 + RTNLGRP_LINK = 0x1 + RTNLGRP_NOTIFY = 0x2 + RTNLGRP_NEIGH = 0x3 + RTNLGRP_TC = 0x4 + RTNLGRP_IPV4_IFADDR = 0x5 + RTNLGRP_IPV4_MROUTE = 0x6 + RTNLGRP_IPV4_ROUTE = 0x7 + RTNLGRP_IPV4_RULE = 0x8 + RTNLGRP_IPV6_IFADDR = 0x9 + RTNLGRP_IPV6_MROUTE = 0xa + RTNLGRP_IPV6_ROUTE = 0xb + RTNLGRP_IPV6_IFINFO = 0xc + RTNLGRP_IPV6_PREFIX = 0x12 + RTNLGRP_IPV6_RULE = 0x13 + RTNLGRP_ND_USEROPT = 0x14 + SizeofNlMsghdr = 0x10 + SizeofNlMsgerr = 0x14 + SizeofRtGenmsg = 0x1 + SizeofNlAttr = 0x4 + SizeofRtAttr = 0x4 + SizeofIfInfomsg = 0x10 + SizeofIfAddrmsg = 0x8 + SizeofRtMsg = 0xc + SizeofRtNexthop = 0x8 ) type NlMsghdr struct { @@ -497,12 +604,12 @@ type RtAttr struct { } type IfInfomsg struct { - Family uint8 - X__ifi_pad uint8 - Type uint16 - Index int32 - Flags uint32 - Change uint32 + Family uint8 + _ uint8 + Type uint16 + Index int32 + Flags uint32 + Change uint32 } type IfAddrmsg struct { @@ -545,9 +652,8 @@ type SockFilter struct { } type SockFprog struct { - Len uint16 - Pad_cgo_0 [6]byte - Filter *SockFilter + Len uint16 + Filter *SockFilter } type InotifyEvent struct { @@ -568,15 +674,6 @@ type PtraceRegs struct { Magic uint32 } -type ptracePsw struct { -} - -type ptraceFpregs struct { -} - -type ptracePer struct { -} - type FdSet struct { Bits [16]int64 } @@ -592,12 +689,11 @@ type Sysinfo_t struct { Freeswap uint64 Procs uint16 Pad uint16 - Pad_cgo_0 [4]byte Totalhigh uint64 Freehigh uint64 Unit uint32 - X_f [0]int8 - Pad_cgo_1 [4]byte + _ [0]int8 + _ [4]byte } type Utsname struct { @@ -610,26 +706,34 @@ type Utsname struct { } type Ustat_t struct { - Tfree int32 - Pad_cgo_0 [4]byte - Tinode uint64 - Fname [6]int8 - Fpack [6]int8 - Pad_cgo_1 [4]byte + Tfree int32 + Tinode uint64 + Fname [6]int8 + Fpack [6]int8 + _ [4]byte } type EpollEvent struct { - Events uint32 - X_padFd int32 - Fd int32 - Pad int32 + Events uint32 + _ int32 + Fd int32 + Pad int32 } const ( - AT_FDCWD = -0x64 - AT_REMOVEDIR = 0x200 + AT_EMPTY_PATH = 0x1000 + AT_FDCWD = -0x64 + AT_NO_AUTOMOUNT = 0x800 + AT_REMOVEDIR = 0x200 + + AT_STATX_SYNC_AS_STAT = 0x0 + AT_STATX_FORCE_SYNC = 0x2000 + AT_STATX_DONT_SYNC = 0x4000 + AT_SYMLINK_FOLLOW = 0x400 AT_SYMLINK_NOFOLLOW = 0x100 + + AT_EACCESS = 0x200 ) type PollFd struct { @@ -649,9 +753,36 @@ const ( ) type Sigset_t struct { - X__val [16]uint64 + Val [16]uint64 } +type SignalfdSiginfo struct { + Signo uint32 + Errno int32 + Code int32 + Pid uint32 + Uid uint32 + Fd int32 + Tid uint32 + Band uint32 + Overrun uint32 + Trapno uint32 + Status int32 + Int int32 + Ptr uint64 + Utime uint64 + Stime uint64 + Addr uint64 + Addr_lsb uint16 + _ uint16 + Syscall int32 + Call_addr uint64 + Arch uint32 + _ [28]uint8 +} + +const PERF_IOC_FLAG_GROUP = 0x1 + type Termios struct { Iflag uint32 Oflag uint32 @@ -662,3 +793,1232 @@ type Termios struct { Ispeed uint32 Ospeed uint32 } + +type Winsize struct { + Row uint16 + Col uint16 + Xpixel uint16 + Ypixel uint16 +} + +type Taskstats struct { + Version uint16 + Ac_exitcode uint32 + Ac_flag uint8 + Ac_nice uint8 + Cpu_count uint64 + Cpu_delay_total uint64 + Blkio_count uint64 + Blkio_delay_total uint64 + Swapin_count uint64 + Swapin_delay_total uint64 + Cpu_run_real_total uint64 + Cpu_run_virtual_total uint64 + Ac_comm [32]int8 + Ac_sched uint8 + Ac_pad [3]uint8 + _ [4]byte + Ac_uid uint32 + Ac_gid uint32 + Ac_pid uint32 + Ac_ppid uint32 + Ac_btime uint32 + Ac_etime uint64 + Ac_utime uint64 + Ac_stime uint64 + Ac_minflt uint64 + Ac_majflt uint64 + Coremem uint64 + Virtmem uint64 + Hiwater_rss uint64 + Hiwater_vm uint64 + Read_char uint64 + Write_char uint64 + Read_syscalls uint64 + Write_syscalls uint64 + Read_bytes uint64 + Write_bytes uint64 + Cancelled_write_bytes uint64 + Nvcsw uint64 + Nivcsw uint64 + Ac_utimescaled uint64 + Ac_stimescaled uint64 + Cpu_scaled_run_real_total uint64 + Freepages_count uint64 + Freepages_delay_total uint64 + Thrashing_count uint64 + Thrashing_delay_total uint64 +} + +const ( + TASKSTATS_CMD_UNSPEC = 0x0 + TASKSTATS_CMD_GET = 0x1 + TASKSTATS_CMD_NEW = 0x2 + TASKSTATS_TYPE_UNSPEC = 0x0 + TASKSTATS_TYPE_PID = 0x1 + TASKSTATS_TYPE_TGID = 0x2 + TASKSTATS_TYPE_STATS = 0x3 + TASKSTATS_TYPE_AGGR_PID = 0x4 + TASKSTATS_TYPE_AGGR_TGID = 0x5 + TASKSTATS_TYPE_NULL = 0x6 + TASKSTATS_CMD_ATTR_UNSPEC = 0x0 + TASKSTATS_CMD_ATTR_PID = 0x1 + TASKSTATS_CMD_ATTR_TGID = 0x2 + TASKSTATS_CMD_ATTR_REGISTER_CPUMASK = 0x3 + TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK = 0x4 +) + +type CGroupStats struct { + Sleeping uint64 + Running uint64 + Stopped uint64 + Uninterruptible uint64 + Io_wait uint64 +} + +const ( + CGROUPSTATS_CMD_UNSPEC = 0x3 + CGROUPSTATS_CMD_GET = 0x4 + CGROUPSTATS_CMD_NEW = 0x5 + CGROUPSTATS_TYPE_UNSPEC = 0x0 + CGROUPSTATS_TYPE_CGROUP_STATS = 0x1 + CGROUPSTATS_CMD_ATTR_UNSPEC = 0x0 + CGROUPSTATS_CMD_ATTR_FD = 0x1 +) + +type Genlmsghdr struct { + Cmd uint8 + Version uint8 + Reserved uint16 +} + +const ( + CTRL_CMD_UNSPEC = 0x0 + CTRL_CMD_NEWFAMILY = 0x1 + CTRL_CMD_DELFAMILY = 0x2 + CTRL_CMD_GETFAMILY = 0x3 + CTRL_CMD_NEWOPS = 0x4 + CTRL_CMD_DELOPS = 0x5 + CTRL_CMD_GETOPS = 0x6 + CTRL_CMD_NEWMCAST_GRP = 0x7 + CTRL_CMD_DELMCAST_GRP = 0x8 + CTRL_CMD_GETMCAST_GRP = 0x9 + CTRL_ATTR_UNSPEC = 0x0 + CTRL_ATTR_FAMILY_ID = 0x1 + CTRL_ATTR_FAMILY_NAME = 0x2 + CTRL_ATTR_VERSION = 0x3 + CTRL_ATTR_HDRSIZE = 0x4 + CTRL_ATTR_MAXATTR = 0x5 + CTRL_ATTR_OPS = 0x6 + CTRL_ATTR_MCAST_GROUPS = 0x7 + CTRL_ATTR_OP_UNSPEC = 0x0 + CTRL_ATTR_OP_ID = 0x1 + CTRL_ATTR_OP_FLAGS = 0x2 + CTRL_ATTR_MCAST_GRP_UNSPEC = 0x0 + CTRL_ATTR_MCAST_GRP_NAME = 0x1 + CTRL_ATTR_MCAST_GRP_ID = 0x2 +) + +type cpuMask uint64 + +const ( + _CPU_SETSIZE = 0x400 + _NCPUBITS = 0x40 +) + +const ( + BDADDR_BREDR = 0x0 + BDADDR_LE_PUBLIC = 0x1 + BDADDR_LE_RANDOM = 0x2 +) + +type PerfEventAttr struct { + Type uint32 + Size uint32 + Config uint64 + Sample uint64 + Sample_type uint64 + Read_format uint64 + Bits uint64 + Wakeup uint32 + Bp_type uint32 + Ext1 uint64 + Ext2 uint64 + Branch_sample_type uint64 + Sample_regs_user uint64 + Sample_stack_user uint32 + Clockid int32 + Sample_regs_intr uint64 + Aux_watermark uint32 + _ uint32 +} + +type PerfEventMmapPage struct { + Version uint32 + Compat_version uint32 + Lock uint32 + Index uint32 + Offset int64 + Time_enabled uint64 + Time_running uint64 + Capabilities uint64 + Pmc_width uint16 + Time_shift uint16 + Time_mult uint32 + Time_offset uint64 + Time_zero uint64 + Size uint32 + _ [948]uint8 + Data_head uint64 + Data_tail uint64 + Data_offset uint64 + Data_size uint64 + Aux_head uint64 + Aux_tail uint64 + Aux_offset uint64 + Aux_size uint64 +} + +const ( + PerfBitDisabled uint64 = CBitFieldMaskBit0 + PerfBitInherit = CBitFieldMaskBit1 + PerfBitPinned = CBitFieldMaskBit2 + PerfBitExclusive = CBitFieldMaskBit3 + PerfBitExcludeUser = CBitFieldMaskBit4 + PerfBitExcludeKernel = CBitFieldMaskBit5 + PerfBitExcludeHv = CBitFieldMaskBit6 + PerfBitExcludeIdle = CBitFieldMaskBit7 + PerfBitMmap = CBitFieldMaskBit8 + PerfBitComm = CBitFieldMaskBit9 + PerfBitFreq = CBitFieldMaskBit10 + PerfBitInheritStat = CBitFieldMaskBit11 + PerfBitEnableOnExec = CBitFieldMaskBit12 + PerfBitTask = CBitFieldMaskBit13 + PerfBitWatermark = CBitFieldMaskBit14 + PerfBitPreciseIPBit1 = CBitFieldMaskBit15 + PerfBitPreciseIPBit2 = CBitFieldMaskBit16 + PerfBitMmapData = CBitFieldMaskBit17 + PerfBitSampleIDAll = CBitFieldMaskBit18 + PerfBitExcludeHost = CBitFieldMaskBit19 + PerfBitExcludeGuest = CBitFieldMaskBit20 + PerfBitExcludeCallchainKernel = CBitFieldMaskBit21 + PerfBitExcludeCallchainUser = CBitFieldMaskBit22 + PerfBitMmap2 = CBitFieldMaskBit23 + PerfBitCommExec = CBitFieldMaskBit24 + PerfBitUseClockID = CBitFieldMaskBit25 + PerfBitContextSwitch = CBitFieldMaskBit26 +) + +const ( + PERF_TYPE_HARDWARE = 0x0 + PERF_TYPE_SOFTWARE = 0x1 + PERF_TYPE_TRACEPOINT = 0x2 + PERF_TYPE_HW_CACHE = 0x3 + PERF_TYPE_RAW = 0x4 + PERF_TYPE_BREAKPOINT = 0x5 + + PERF_COUNT_HW_CPU_CYCLES = 0x0 + PERF_COUNT_HW_INSTRUCTIONS = 0x1 + PERF_COUNT_HW_CACHE_REFERENCES = 0x2 + PERF_COUNT_HW_CACHE_MISSES = 0x3 + PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 0x4 + PERF_COUNT_HW_BRANCH_MISSES = 0x5 + PERF_COUNT_HW_BUS_CYCLES = 0x6 + PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 0x7 + PERF_COUNT_HW_STALLED_CYCLES_BACKEND = 0x8 + PERF_COUNT_HW_REF_CPU_CYCLES = 0x9 + + PERF_COUNT_HW_CACHE_L1D = 0x0 + PERF_COUNT_HW_CACHE_L1I = 0x1 + PERF_COUNT_HW_CACHE_LL = 0x2 + PERF_COUNT_HW_CACHE_DTLB = 0x3 + PERF_COUNT_HW_CACHE_ITLB = 0x4 + PERF_COUNT_HW_CACHE_BPU = 0x5 + PERF_COUNT_HW_CACHE_NODE = 0x6 + + PERF_COUNT_HW_CACHE_OP_READ = 0x0 + PERF_COUNT_HW_CACHE_OP_WRITE = 0x1 + PERF_COUNT_HW_CACHE_OP_PREFETCH = 0x2 + + PERF_COUNT_HW_CACHE_RESULT_ACCESS = 0x0 + PERF_COUNT_HW_CACHE_RESULT_MISS = 0x1 + + PERF_COUNT_SW_CPU_CLOCK = 0x0 + PERF_COUNT_SW_TASK_CLOCK = 0x1 + PERF_COUNT_SW_PAGE_FAULTS = 0x2 + PERF_COUNT_SW_CONTEXT_SWITCHES = 0x3 + PERF_COUNT_SW_CPU_MIGRATIONS = 0x4 + PERF_COUNT_SW_PAGE_FAULTS_MIN = 0x5 + PERF_COUNT_SW_PAGE_FAULTS_MAJ = 0x6 + PERF_COUNT_SW_ALIGNMENT_FAULTS = 0x7 + PERF_COUNT_SW_EMULATION_FAULTS = 0x8 + PERF_COUNT_SW_DUMMY = 0x9 + + PERF_SAMPLE_IP = 0x1 + PERF_SAMPLE_TID = 0x2 + PERF_SAMPLE_TIME = 0x4 + PERF_SAMPLE_ADDR = 0x8 + PERF_SAMPLE_READ = 0x10 + PERF_SAMPLE_CALLCHAIN = 0x20 + PERF_SAMPLE_ID = 0x40 + PERF_SAMPLE_CPU = 0x80 + PERF_SAMPLE_PERIOD = 0x100 + PERF_SAMPLE_STREAM_ID = 0x200 + PERF_SAMPLE_RAW = 0x400 + PERF_SAMPLE_BRANCH_STACK = 0x800 + + PERF_SAMPLE_BRANCH_USER = 0x1 + PERF_SAMPLE_BRANCH_KERNEL = 0x2 + PERF_SAMPLE_BRANCH_HV = 0x4 + PERF_SAMPLE_BRANCH_ANY = 0x8 + PERF_SAMPLE_BRANCH_ANY_CALL = 0x10 + PERF_SAMPLE_BRANCH_ANY_RETURN = 0x20 + PERF_SAMPLE_BRANCH_IND_CALL = 0x40 + + PERF_FORMAT_TOTAL_TIME_ENABLED = 0x1 + PERF_FORMAT_TOTAL_TIME_RUNNING = 0x2 + PERF_FORMAT_ID = 0x4 + PERF_FORMAT_GROUP = 0x8 + + PERF_RECORD_MMAP = 0x1 + PERF_RECORD_LOST = 0x2 + PERF_RECORD_COMM = 0x3 + PERF_RECORD_EXIT = 0x4 + PERF_RECORD_THROTTLE = 0x5 + PERF_RECORD_UNTHROTTLE = 0x6 + PERF_RECORD_FORK = 0x7 + PERF_RECORD_READ = 0x8 + PERF_RECORD_SAMPLE = 0x9 + + PERF_CONTEXT_HV = -0x20 + PERF_CONTEXT_KERNEL = -0x80 + PERF_CONTEXT_USER = -0x200 + + PERF_CONTEXT_GUEST = -0x800 + PERF_CONTEXT_GUEST_KERNEL = -0x880 + PERF_CONTEXT_GUEST_USER = -0xa00 + + PERF_FLAG_FD_NO_GROUP = 0x1 + PERF_FLAG_FD_OUTPUT = 0x2 + PERF_FLAG_PID_CGROUP = 0x4 +) + +const ( + CBitFieldMaskBit0 = 0x8000000000000000 + CBitFieldMaskBit1 = 0x4000000000000000 + CBitFieldMaskBit2 = 0x2000000000000000 + CBitFieldMaskBit3 = 0x1000000000000000 + CBitFieldMaskBit4 = 0x800000000000000 + CBitFieldMaskBit5 = 0x400000000000000 + CBitFieldMaskBit6 = 0x200000000000000 + CBitFieldMaskBit7 = 0x100000000000000 + CBitFieldMaskBit8 = 0x80000000000000 + CBitFieldMaskBit9 = 0x40000000000000 + CBitFieldMaskBit10 = 0x20000000000000 + CBitFieldMaskBit11 = 0x10000000000000 + CBitFieldMaskBit12 = 0x8000000000000 + CBitFieldMaskBit13 = 0x4000000000000 + CBitFieldMaskBit14 = 0x2000000000000 + CBitFieldMaskBit15 = 0x1000000000000 + CBitFieldMaskBit16 = 0x800000000000 + CBitFieldMaskBit17 = 0x400000000000 + CBitFieldMaskBit18 = 0x200000000000 + CBitFieldMaskBit19 = 0x100000000000 + CBitFieldMaskBit20 = 0x80000000000 + CBitFieldMaskBit21 = 0x40000000000 + CBitFieldMaskBit22 = 0x20000000000 + CBitFieldMaskBit23 = 0x10000000000 + CBitFieldMaskBit24 = 0x8000000000 + CBitFieldMaskBit25 = 0x4000000000 + CBitFieldMaskBit26 = 0x2000000000 + CBitFieldMaskBit27 = 0x1000000000 + CBitFieldMaskBit28 = 0x800000000 + CBitFieldMaskBit29 = 0x400000000 + CBitFieldMaskBit30 = 0x200000000 + CBitFieldMaskBit31 = 0x100000000 + CBitFieldMaskBit32 = 0x80000000 + CBitFieldMaskBit33 = 0x40000000 + CBitFieldMaskBit34 = 0x20000000 + CBitFieldMaskBit35 = 0x10000000 + CBitFieldMaskBit36 = 0x8000000 + CBitFieldMaskBit37 = 0x4000000 + CBitFieldMaskBit38 = 0x2000000 + CBitFieldMaskBit39 = 0x1000000 + CBitFieldMaskBit40 = 0x800000 + CBitFieldMaskBit41 = 0x400000 + CBitFieldMaskBit42 = 0x200000 + CBitFieldMaskBit43 = 0x100000 + CBitFieldMaskBit44 = 0x80000 + CBitFieldMaskBit45 = 0x40000 + CBitFieldMaskBit46 = 0x20000 + CBitFieldMaskBit47 = 0x10000 + CBitFieldMaskBit48 = 0x8000 + CBitFieldMaskBit49 = 0x4000 + CBitFieldMaskBit50 = 0x2000 + CBitFieldMaskBit51 = 0x1000 + CBitFieldMaskBit52 = 0x800 + CBitFieldMaskBit53 = 0x400 + CBitFieldMaskBit54 = 0x200 + CBitFieldMaskBit55 = 0x100 + CBitFieldMaskBit56 = 0x80 + CBitFieldMaskBit57 = 0x40 + CBitFieldMaskBit58 = 0x20 + CBitFieldMaskBit59 = 0x10 + CBitFieldMaskBit60 = 0x8 + CBitFieldMaskBit61 = 0x4 + CBitFieldMaskBit62 = 0x2 + CBitFieldMaskBit63 = 0x1 +) + +type SockaddrStorage struct { + Family uint16 + _ [118]int8 + _ uint64 +} + +type TCPMD5Sig struct { + Addr SockaddrStorage + Flags uint8 + Prefixlen uint8 + Keylen uint16 + _ uint32 + Key [80]uint8 +} + +type HDDriveCmdHdr struct { + Command uint8 + Number uint8 + Feature uint8 + Count uint8 +} + +type HDGeometry struct { + Heads uint8 + Sectors uint8 + Cylinders uint16 + Start uint64 +} + +type HDDriveID struct { + Config uint16 + Cyls uint16 + Reserved2 uint16 + Heads uint16 + Track_bytes uint16 + Sector_bytes uint16 + Sectors uint16 + Vendor0 uint16 + Vendor1 uint16 + Vendor2 uint16 + Serial_no [20]uint8 + Buf_type uint16 + Buf_size uint16 + Ecc_bytes uint16 + Fw_rev [8]uint8 + Model [40]uint8 + Max_multsect uint8 + Vendor3 uint8 + Dword_io uint16 + Vendor4 uint8 + Capability uint8 + Reserved50 uint16 + Vendor5 uint8 + TPIO uint8 + Vendor6 uint8 + TDMA uint8 + Field_valid uint16 + Cur_cyls uint16 + Cur_heads uint16 + Cur_sectors uint16 + Cur_capacity0 uint16 + Cur_capacity1 uint16 + Multsect uint8 + Multsect_valid uint8 + Lba_capacity uint32 + Dma_1word uint16 + Dma_mword uint16 + Eide_pio_modes uint16 + Eide_dma_min uint16 + Eide_dma_time uint16 + Eide_pio uint16 + Eide_pio_iordy uint16 + Words69_70 [2]uint16 + Words71_74 [4]uint16 + Queue_depth uint16 + Words76_79 [4]uint16 + Major_rev_num uint16 + Minor_rev_num uint16 + Command_set_1 uint16 + Command_set_2 uint16 + Cfsse uint16 + Cfs_enable_1 uint16 + Cfs_enable_2 uint16 + Csf_default uint16 + Dma_ultra uint16 + Trseuc uint16 + TrsEuc uint16 + CurAPMvalues uint16 + Mprc uint16 + Hw_config uint16 + Acoustic uint16 + Msrqs uint16 + Sxfert uint16 + Sal uint16 + Spg uint32 + Lba_capacity_2 uint64 + Words104_125 [22]uint16 + Last_lun uint16 + Word127 uint16 + Dlf uint16 + Csfo uint16 + Words130_155 [26]uint16 + Word156 uint16 + Words157_159 [3]uint16 + Cfa_power uint16 + Words161_175 [15]uint16 + Words176_205 [30]uint16 + Words206_254 [49]uint16 + Integrity_word uint16 +} + +type Statfs_t struct { + Type int64 + Bsize int64 + Blocks uint64 + Bfree uint64 + Bavail uint64 + Files uint64 + Ffree uint64 + Fsid Fsid + Namelen int64 + Frsize int64 + Flags int64 + Spare [4]int64 +} + +const ( + ST_MANDLOCK = 0x40 + ST_NOATIME = 0x400 + ST_NODEV = 0x4 + ST_NODIRATIME = 0x800 + ST_NOEXEC = 0x8 + ST_NOSUID = 0x2 + ST_RDONLY = 0x1 + ST_RELATIME = 0x1000 + ST_SYNCHRONOUS = 0x10 +) + +type TpacketHdr struct { + Status uint64 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Sec uint32 + Usec uint32 + _ [4]byte +} + +type Tpacket2Hdr struct { + Status uint32 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Sec uint32 + Nsec uint32 + Vlan_tci uint16 + Vlan_tpid uint16 + _ [4]uint8 +} + +type Tpacket3Hdr struct { + Next_offset uint32 + Sec uint32 + Nsec uint32 + Snaplen uint32 + Len uint32 + Status uint32 + Mac uint16 + Net uint16 + Hv1 TpacketHdrVariant1 + _ [8]uint8 +} + +type TpacketHdrVariant1 struct { + Rxhash uint32 + Vlan_tci uint32 + Vlan_tpid uint16 + _ uint16 +} + +type TpacketBlockDesc struct { + Version uint32 + To_priv uint32 + Hdr [40]byte +} + +type TpacketReq struct { + Block_size uint32 + Block_nr uint32 + Frame_size uint32 + Frame_nr uint32 +} + +type TpacketReq3 struct { + Block_size uint32 + Block_nr uint32 + Frame_size uint32 + Frame_nr uint32 + Retire_blk_tov uint32 + Sizeof_priv uint32 + Feature_req_word uint32 +} + +type TpacketStats struct { + Packets uint32 + Drops uint32 +} + +type TpacketStatsV3 struct { + Packets uint32 + Drops uint32 + Freeze_q_cnt uint32 +} + +type TpacketAuxdata struct { + Status uint32 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Vlan_tci uint16 + Vlan_tpid uint16 +} + +const ( + TPACKET_V1 = 0x0 + TPACKET_V2 = 0x1 + TPACKET_V3 = 0x2 +) + +const ( + SizeofTpacketHdr = 0x20 + SizeofTpacket2Hdr = 0x20 + SizeofTpacket3Hdr = 0x30 +) + +const ( + NF_INET_PRE_ROUTING = 0x0 + NF_INET_LOCAL_IN = 0x1 + NF_INET_FORWARD = 0x2 + NF_INET_LOCAL_OUT = 0x3 + NF_INET_POST_ROUTING = 0x4 + NF_INET_NUMHOOKS = 0x5 +) + +const ( + NF_NETDEV_INGRESS = 0x0 + NF_NETDEV_NUMHOOKS = 0x1 +) + +const ( + NFPROTO_UNSPEC = 0x0 + NFPROTO_INET = 0x1 + NFPROTO_IPV4 = 0x2 + NFPROTO_ARP = 0x3 + NFPROTO_NETDEV = 0x5 + NFPROTO_BRIDGE = 0x7 + NFPROTO_IPV6 = 0xa + NFPROTO_DECNET = 0xc + NFPROTO_NUMPROTO = 0xd +) + +type Nfgenmsg struct { + Nfgen_family uint8 + Version uint8 + Res_id uint16 +} + +const ( + NFNL_BATCH_UNSPEC = 0x0 + NFNL_BATCH_GENID = 0x1 +) + +const ( + NFT_REG_VERDICT = 0x0 + NFT_REG_1 = 0x1 + NFT_REG_2 = 0x2 + NFT_REG_3 = 0x3 + NFT_REG_4 = 0x4 + NFT_REG32_00 = 0x8 + NFT_REG32_01 = 0x9 + NFT_REG32_02 = 0xa + NFT_REG32_03 = 0xb + NFT_REG32_04 = 0xc + NFT_REG32_05 = 0xd + NFT_REG32_06 = 0xe + NFT_REG32_07 = 0xf + NFT_REG32_08 = 0x10 + NFT_REG32_09 = 0x11 + NFT_REG32_10 = 0x12 + NFT_REG32_11 = 0x13 + NFT_REG32_12 = 0x14 + NFT_REG32_13 = 0x15 + NFT_REG32_14 = 0x16 + NFT_REG32_15 = 0x17 + NFT_CONTINUE = -0x1 + NFT_BREAK = -0x2 + NFT_JUMP = -0x3 + NFT_GOTO = -0x4 + NFT_RETURN = -0x5 + NFT_MSG_NEWTABLE = 0x0 + NFT_MSG_GETTABLE = 0x1 + NFT_MSG_DELTABLE = 0x2 + NFT_MSG_NEWCHAIN = 0x3 + NFT_MSG_GETCHAIN = 0x4 + NFT_MSG_DELCHAIN = 0x5 + NFT_MSG_NEWRULE = 0x6 + NFT_MSG_GETRULE = 0x7 + NFT_MSG_DELRULE = 0x8 + NFT_MSG_NEWSET = 0x9 + NFT_MSG_GETSET = 0xa + NFT_MSG_DELSET = 0xb + NFT_MSG_NEWSETELEM = 0xc + NFT_MSG_GETSETELEM = 0xd + NFT_MSG_DELSETELEM = 0xe + NFT_MSG_NEWGEN = 0xf + NFT_MSG_GETGEN = 0x10 + NFT_MSG_TRACE = 0x11 + NFT_MSG_NEWOBJ = 0x12 + NFT_MSG_GETOBJ = 0x13 + NFT_MSG_DELOBJ = 0x14 + NFT_MSG_GETOBJ_RESET = 0x15 + NFT_MSG_MAX = 0x19 + NFTA_LIST_UNPEC = 0x0 + NFTA_LIST_ELEM = 0x1 + NFTA_HOOK_UNSPEC = 0x0 + NFTA_HOOK_HOOKNUM = 0x1 + NFTA_HOOK_PRIORITY = 0x2 + NFTA_HOOK_DEV = 0x3 + NFT_TABLE_F_DORMANT = 0x1 + NFTA_TABLE_UNSPEC = 0x0 + NFTA_TABLE_NAME = 0x1 + NFTA_TABLE_FLAGS = 0x2 + NFTA_TABLE_USE = 0x3 + NFTA_CHAIN_UNSPEC = 0x0 + NFTA_CHAIN_TABLE = 0x1 + NFTA_CHAIN_HANDLE = 0x2 + NFTA_CHAIN_NAME = 0x3 + NFTA_CHAIN_HOOK = 0x4 + NFTA_CHAIN_POLICY = 0x5 + NFTA_CHAIN_USE = 0x6 + NFTA_CHAIN_TYPE = 0x7 + NFTA_CHAIN_COUNTERS = 0x8 + NFTA_CHAIN_PAD = 0x9 + NFTA_RULE_UNSPEC = 0x0 + NFTA_RULE_TABLE = 0x1 + NFTA_RULE_CHAIN = 0x2 + NFTA_RULE_HANDLE = 0x3 + NFTA_RULE_EXPRESSIONS = 0x4 + NFTA_RULE_COMPAT = 0x5 + NFTA_RULE_POSITION = 0x6 + NFTA_RULE_USERDATA = 0x7 + NFTA_RULE_PAD = 0x8 + NFTA_RULE_ID = 0x9 + NFT_RULE_COMPAT_F_INV = 0x2 + NFT_RULE_COMPAT_F_MASK = 0x2 + NFTA_RULE_COMPAT_UNSPEC = 0x0 + NFTA_RULE_COMPAT_PROTO = 0x1 + NFTA_RULE_COMPAT_FLAGS = 0x2 + NFT_SET_ANONYMOUS = 0x1 + NFT_SET_CONSTANT = 0x2 + NFT_SET_INTERVAL = 0x4 + NFT_SET_MAP = 0x8 + NFT_SET_TIMEOUT = 0x10 + NFT_SET_EVAL = 0x20 + NFT_SET_OBJECT = 0x40 + NFT_SET_POL_PERFORMANCE = 0x0 + NFT_SET_POL_MEMORY = 0x1 + NFTA_SET_DESC_UNSPEC = 0x0 + NFTA_SET_DESC_SIZE = 0x1 + NFTA_SET_UNSPEC = 0x0 + NFTA_SET_TABLE = 0x1 + NFTA_SET_NAME = 0x2 + NFTA_SET_FLAGS = 0x3 + NFTA_SET_KEY_TYPE = 0x4 + NFTA_SET_KEY_LEN = 0x5 + NFTA_SET_DATA_TYPE = 0x6 + NFTA_SET_DATA_LEN = 0x7 + NFTA_SET_POLICY = 0x8 + NFTA_SET_DESC = 0x9 + NFTA_SET_ID = 0xa + NFTA_SET_TIMEOUT = 0xb + NFTA_SET_GC_INTERVAL = 0xc + NFTA_SET_USERDATA = 0xd + NFTA_SET_PAD = 0xe + NFTA_SET_OBJ_TYPE = 0xf + NFT_SET_ELEM_INTERVAL_END = 0x1 + NFTA_SET_ELEM_UNSPEC = 0x0 + NFTA_SET_ELEM_KEY = 0x1 + NFTA_SET_ELEM_DATA = 0x2 + NFTA_SET_ELEM_FLAGS = 0x3 + NFTA_SET_ELEM_TIMEOUT = 0x4 + NFTA_SET_ELEM_EXPIRATION = 0x5 + NFTA_SET_ELEM_USERDATA = 0x6 + NFTA_SET_ELEM_EXPR = 0x7 + NFTA_SET_ELEM_PAD = 0x8 + NFTA_SET_ELEM_OBJREF = 0x9 + NFTA_SET_ELEM_LIST_UNSPEC = 0x0 + NFTA_SET_ELEM_LIST_TABLE = 0x1 + NFTA_SET_ELEM_LIST_SET = 0x2 + NFTA_SET_ELEM_LIST_ELEMENTS = 0x3 + NFTA_SET_ELEM_LIST_SET_ID = 0x4 + NFT_DATA_VALUE = 0x0 + NFT_DATA_VERDICT = 0xffffff00 + NFTA_DATA_UNSPEC = 0x0 + NFTA_DATA_VALUE = 0x1 + NFTA_DATA_VERDICT = 0x2 + NFTA_VERDICT_UNSPEC = 0x0 + NFTA_VERDICT_CODE = 0x1 + NFTA_VERDICT_CHAIN = 0x2 + NFTA_EXPR_UNSPEC = 0x0 + NFTA_EXPR_NAME = 0x1 + NFTA_EXPR_DATA = 0x2 + NFTA_IMMEDIATE_UNSPEC = 0x0 + NFTA_IMMEDIATE_DREG = 0x1 + NFTA_IMMEDIATE_DATA = 0x2 + NFTA_BITWISE_UNSPEC = 0x0 + NFTA_BITWISE_SREG = 0x1 + NFTA_BITWISE_DREG = 0x2 + NFTA_BITWISE_LEN = 0x3 + NFTA_BITWISE_MASK = 0x4 + NFTA_BITWISE_XOR = 0x5 + NFT_BYTEORDER_NTOH = 0x0 + NFT_BYTEORDER_HTON = 0x1 + NFTA_BYTEORDER_UNSPEC = 0x0 + NFTA_BYTEORDER_SREG = 0x1 + NFTA_BYTEORDER_DREG = 0x2 + NFTA_BYTEORDER_OP = 0x3 + NFTA_BYTEORDER_LEN = 0x4 + NFTA_BYTEORDER_SIZE = 0x5 + NFT_CMP_EQ = 0x0 + NFT_CMP_NEQ = 0x1 + NFT_CMP_LT = 0x2 + NFT_CMP_LTE = 0x3 + NFT_CMP_GT = 0x4 + NFT_CMP_GTE = 0x5 + NFTA_CMP_UNSPEC = 0x0 + NFTA_CMP_SREG = 0x1 + NFTA_CMP_OP = 0x2 + NFTA_CMP_DATA = 0x3 + NFT_RANGE_EQ = 0x0 + NFT_RANGE_NEQ = 0x1 + NFTA_RANGE_UNSPEC = 0x0 + NFTA_RANGE_SREG = 0x1 + NFTA_RANGE_OP = 0x2 + NFTA_RANGE_FROM_DATA = 0x3 + NFTA_RANGE_TO_DATA = 0x4 + NFT_LOOKUP_F_INV = 0x1 + NFTA_LOOKUP_UNSPEC = 0x0 + NFTA_LOOKUP_SET = 0x1 + NFTA_LOOKUP_SREG = 0x2 + NFTA_LOOKUP_DREG = 0x3 + NFTA_LOOKUP_SET_ID = 0x4 + NFTA_LOOKUP_FLAGS = 0x5 + NFT_DYNSET_OP_ADD = 0x0 + NFT_DYNSET_OP_UPDATE = 0x1 + NFT_DYNSET_F_INV = 0x1 + NFTA_DYNSET_UNSPEC = 0x0 + NFTA_DYNSET_SET_NAME = 0x1 + NFTA_DYNSET_SET_ID = 0x2 + NFTA_DYNSET_OP = 0x3 + NFTA_DYNSET_SREG_KEY = 0x4 + NFTA_DYNSET_SREG_DATA = 0x5 + NFTA_DYNSET_TIMEOUT = 0x6 + NFTA_DYNSET_EXPR = 0x7 + NFTA_DYNSET_PAD = 0x8 + NFTA_DYNSET_FLAGS = 0x9 + NFT_PAYLOAD_LL_HEADER = 0x0 + NFT_PAYLOAD_NETWORK_HEADER = 0x1 + NFT_PAYLOAD_TRANSPORT_HEADER = 0x2 + NFT_PAYLOAD_CSUM_NONE = 0x0 + NFT_PAYLOAD_CSUM_INET = 0x1 + NFT_PAYLOAD_L4CSUM_PSEUDOHDR = 0x1 + NFTA_PAYLOAD_UNSPEC = 0x0 + NFTA_PAYLOAD_DREG = 0x1 + NFTA_PAYLOAD_BASE = 0x2 + NFTA_PAYLOAD_OFFSET = 0x3 + NFTA_PAYLOAD_LEN = 0x4 + NFTA_PAYLOAD_SREG = 0x5 + NFTA_PAYLOAD_CSUM_TYPE = 0x6 + NFTA_PAYLOAD_CSUM_OFFSET = 0x7 + NFTA_PAYLOAD_CSUM_FLAGS = 0x8 + NFT_EXTHDR_F_PRESENT = 0x1 + NFT_EXTHDR_OP_IPV6 = 0x0 + NFT_EXTHDR_OP_TCPOPT = 0x1 + NFTA_EXTHDR_UNSPEC = 0x0 + NFTA_EXTHDR_DREG = 0x1 + NFTA_EXTHDR_TYPE = 0x2 + NFTA_EXTHDR_OFFSET = 0x3 + NFTA_EXTHDR_LEN = 0x4 + NFTA_EXTHDR_FLAGS = 0x5 + NFTA_EXTHDR_OP = 0x6 + NFTA_EXTHDR_SREG = 0x7 + NFT_META_LEN = 0x0 + NFT_META_PROTOCOL = 0x1 + NFT_META_PRIORITY = 0x2 + NFT_META_MARK = 0x3 + NFT_META_IIF = 0x4 + NFT_META_OIF = 0x5 + NFT_META_IIFNAME = 0x6 + NFT_META_OIFNAME = 0x7 + NFT_META_IIFTYPE = 0x8 + NFT_META_OIFTYPE = 0x9 + NFT_META_SKUID = 0xa + NFT_META_SKGID = 0xb + NFT_META_NFTRACE = 0xc + NFT_META_RTCLASSID = 0xd + NFT_META_SECMARK = 0xe + NFT_META_NFPROTO = 0xf + NFT_META_L4PROTO = 0x10 + NFT_META_BRI_IIFNAME = 0x11 + NFT_META_BRI_OIFNAME = 0x12 + NFT_META_PKTTYPE = 0x13 + NFT_META_CPU = 0x14 + NFT_META_IIFGROUP = 0x15 + NFT_META_OIFGROUP = 0x16 + NFT_META_CGROUP = 0x17 + NFT_META_PRANDOM = 0x18 + NFT_RT_CLASSID = 0x0 + NFT_RT_NEXTHOP4 = 0x1 + NFT_RT_NEXTHOP6 = 0x2 + NFT_RT_TCPMSS = 0x3 + NFT_HASH_JENKINS = 0x0 + NFT_HASH_SYM = 0x1 + NFTA_HASH_UNSPEC = 0x0 + NFTA_HASH_SREG = 0x1 + NFTA_HASH_DREG = 0x2 + NFTA_HASH_LEN = 0x3 + NFTA_HASH_MODULUS = 0x4 + NFTA_HASH_SEED = 0x5 + NFTA_HASH_OFFSET = 0x6 + NFTA_HASH_TYPE = 0x7 + NFTA_META_UNSPEC = 0x0 + NFTA_META_DREG = 0x1 + NFTA_META_KEY = 0x2 + NFTA_META_SREG = 0x3 + NFTA_RT_UNSPEC = 0x0 + NFTA_RT_DREG = 0x1 + NFTA_RT_KEY = 0x2 + NFT_CT_STATE = 0x0 + NFT_CT_DIRECTION = 0x1 + NFT_CT_STATUS = 0x2 + NFT_CT_MARK = 0x3 + NFT_CT_SECMARK = 0x4 + NFT_CT_EXPIRATION = 0x5 + NFT_CT_HELPER = 0x6 + NFT_CT_L3PROTOCOL = 0x7 + NFT_CT_SRC = 0x8 + NFT_CT_DST = 0x9 + NFT_CT_PROTOCOL = 0xa + NFT_CT_PROTO_SRC = 0xb + NFT_CT_PROTO_DST = 0xc + NFT_CT_LABELS = 0xd + NFT_CT_PKTS = 0xe + NFT_CT_BYTES = 0xf + NFT_CT_AVGPKT = 0x10 + NFT_CT_ZONE = 0x11 + NFT_CT_EVENTMASK = 0x12 + NFTA_CT_UNSPEC = 0x0 + NFTA_CT_DREG = 0x1 + NFTA_CT_KEY = 0x2 + NFTA_CT_DIRECTION = 0x3 + NFTA_CT_SREG = 0x4 + NFT_LIMIT_PKTS = 0x0 + NFT_LIMIT_PKT_BYTES = 0x1 + NFT_LIMIT_F_INV = 0x1 + NFTA_LIMIT_UNSPEC = 0x0 + NFTA_LIMIT_RATE = 0x1 + NFTA_LIMIT_UNIT = 0x2 + NFTA_LIMIT_BURST = 0x3 + NFTA_LIMIT_TYPE = 0x4 + NFTA_LIMIT_FLAGS = 0x5 + NFTA_LIMIT_PAD = 0x6 + NFTA_COUNTER_UNSPEC = 0x0 + NFTA_COUNTER_BYTES = 0x1 + NFTA_COUNTER_PACKETS = 0x2 + NFTA_COUNTER_PAD = 0x3 + NFTA_LOG_UNSPEC = 0x0 + NFTA_LOG_GROUP = 0x1 + NFTA_LOG_PREFIX = 0x2 + NFTA_LOG_SNAPLEN = 0x3 + NFTA_LOG_QTHRESHOLD = 0x4 + NFTA_LOG_LEVEL = 0x5 + NFTA_LOG_FLAGS = 0x6 + NFTA_QUEUE_UNSPEC = 0x0 + NFTA_QUEUE_NUM = 0x1 + NFTA_QUEUE_TOTAL = 0x2 + NFTA_QUEUE_FLAGS = 0x3 + NFTA_QUEUE_SREG_QNUM = 0x4 + NFT_QUOTA_F_INV = 0x1 + NFT_QUOTA_F_DEPLETED = 0x2 + NFTA_QUOTA_UNSPEC = 0x0 + NFTA_QUOTA_BYTES = 0x1 + NFTA_QUOTA_FLAGS = 0x2 + NFTA_QUOTA_PAD = 0x3 + NFTA_QUOTA_CONSUMED = 0x4 + NFT_REJECT_ICMP_UNREACH = 0x0 + NFT_REJECT_TCP_RST = 0x1 + NFT_REJECT_ICMPX_UNREACH = 0x2 + NFT_REJECT_ICMPX_NO_ROUTE = 0x0 + NFT_REJECT_ICMPX_PORT_UNREACH = 0x1 + NFT_REJECT_ICMPX_HOST_UNREACH = 0x2 + NFT_REJECT_ICMPX_ADMIN_PROHIBITED = 0x3 + NFTA_REJECT_UNSPEC = 0x0 + NFTA_REJECT_TYPE = 0x1 + NFTA_REJECT_ICMP_CODE = 0x2 + NFT_NAT_SNAT = 0x0 + NFT_NAT_DNAT = 0x1 + NFTA_NAT_UNSPEC = 0x0 + NFTA_NAT_TYPE = 0x1 + NFTA_NAT_FAMILY = 0x2 + NFTA_NAT_REG_ADDR_MIN = 0x3 + NFTA_NAT_REG_ADDR_MAX = 0x4 + NFTA_NAT_REG_PROTO_MIN = 0x5 + NFTA_NAT_REG_PROTO_MAX = 0x6 + NFTA_NAT_FLAGS = 0x7 + NFTA_MASQ_UNSPEC = 0x0 + NFTA_MASQ_FLAGS = 0x1 + NFTA_MASQ_REG_PROTO_MIN = 0x2 + NFTA_MASQ_REG_PROTO_MAX = 0x3 + NFTA_REDIR_UNSPEC = 0x0 + NFTA_REDIR_REG_PROTO_MIN = 0x1 + NFTA_REDIR_REG_PROTO_MAX = 0x2 + NFTA_REDIR_FLAGS = 0x3 + NFTA_DUP_UNSPEC = 0x0 + NFTA_DUP_SREG_ADDR = 0x1 + NFTA_DUP_SREG_DEV = 0x2 + NFTA_FWD_UNSPEC = 0x0 + NFTA_FWD_SREG_DEV = 0x1 + NFTA_OBJREF_UNSPEC = 0x0 + NFTA_OBJREF_IMM_TYPE = 0x1 + NFTA_OBJREF_IMM_NAME = 0x2 + NFTA_OBJREF_SET_SREG = 0x3 + NFTA_OBJREF_SET_NAME = 0x4 + NFTA_OBJREF_SET_ID = 0x5 + NFTA_GEN_UNSPEC = 0x0 + NFTA_GEN_ID = 0x1 + NFTA_GEN_PROC_PID = 0x2 + NFTA_GEN_PROC_NAME = 0x3 + NFTA_FIB_UNSPEC = 0x0 + NFTA_FIB_DREG = 0x1 + NFTA_FIB_RESULT = 0x2 + NFTA_FIB_FLAGS = 0x3 + NFT_FIB_RESULT_UNSPEC = 0x0 + NFT_FIB_RESULT_OIF = 0x1 + NFT_FIB_RESULT_OIFNAME = 0x2 + NFT_FIB_RESULT_ADDRTYPE = 0x3 + NFTA_FIB_F_SADDR = 0x1 + NFTA_FIB_F_DADDR = 0x2 + NFTA_FIB_F_MARK = 0x4 + NFTA_FIB_F_IIF = 0x8 + NFTA_FIB_F_OIF = 0x10 + NFTA_FIB_F_PRESENT = 0x20 + NFTA_CT_HELPER_UNSPEC = 0x0 + NFTA_CT_HELPER_NAME = 0x1 + NFTA_CT_HELPER_L3PROTO = 0x2 + NFTA_CT_HELPER_L4PROTO = 0x3 + NFTA_OBJ_UNSPEC = 0x0 + NFTA_OBJ_TABLE = 0x1 + NFTA_OBJ_NAME = 0x2 + NFTA_OBJ_TYPE = 0x3 + NFTA_OBJ_DATA = 0x4 + NFTA_OBJ_USE = 0x5 + NFTA_TRACE_UNSPEC = 0x0 + NFTA_TRACE_TABLE = 0x1 + NFTA_TRACE_CHAIN = 0x2 + NFTA_TRACE_RULE_HANDLE = 0x3 + NFTA_TRACE_TYPE = 0x4 + NFTA_TRACE_VERDICT = 0x5 + NFTA_TRACE_ID = 0x6 + NFTA_TRACE_LL_HEADER = 0x7 + NFTA_TRACE_NETWORK_HEADER = 0x8 + NFTA_TRACE_TRANSPORT_HEADER = 0x9 + NFTA_TRACE_IIF = 0xa + NFTA_TRACE_IIFTYPE = 0xb + NFTA_TRACE_OIF = 0xc + NFTA_TRACE_OIFTYPE = 0xd + NFTA_TRACE_MARK = 0xe + NFTA_TRACE_NFPROTO = 0xf + NFTA_TRACE_POLICY = 0x10 + NFTA_TRACE_PAD = 0x11 + NFT_TRACETYPE_UNSPEC = 0x0 + NFT_TRACETYPE_POLICY = 0x1 + NFT_TRACETYPE_RETURN = 0x2 + NFT_TRACETYPE_RULE = 0x3 + NFTA_NG_UNSPEC = 0x0 + NFTA_NG_DREG = 0x1 + NFTA_NG_MODULUS = 0x2 + NFTA_NG_TYPE = 0x3 + NFTA_NG_OFFSET = 0x4 + NFT_NG_INCREMENTAL = 0x0 + NFT_NG_RANDOM = 0x1 +) + +type RTCTime struct { + Sec int32 + Min int32 + Hour int32 + Mday int32 + Mon int32 + Year int32 + Wday int32 + Yday int32 + Isdst int32 +} + +type RTCWkAlrm struct { + Enabled uint8 + Pending uint8 + Time RTCTime +} + +type RTCPLLInfo struct { + Ctrl int32 + Value int32 + Max int32 + Min int32 + Posmult int32 + Negmult int32 + Clock int64 +} + +type BlkpgIoctlArg struct { + Op int32 + Flags int32 + Datalen int32 + Data *byte +} + +type BlkpgPartition struct { + Start int64 + Length int64 + Pno int32 + Devname [64]uint8 + Volname [64]uint8 + _ [4]byte +} + +const ( + BLKPG = 0x20001269 + BLKPG_ADD_PARTITION = 0x1 + BLKPG_DEL_PARTITION = 0x2 + BLKPG_RESIZE_PARTITION = 0x3 +) + +const ( + NETNSA_NONE = 0x0 + NETNSA_NSID = 0x1 + NETNSA_PID = 0x2 + NETNSA_FD = 0x3 +) + +type XDPRingOffset struct { + Producer uint64 + Consumer uint64 + Desc uint64 +} + +type XDPMmapOffsets struct { + Rx XDPRingOffset + Tx XDPRingOffset + Fr XDPRingOffset + Cr XDPRingOffset +} + +type XDPUmemReg struct { + Addr uint64 + Len uint64 + Size uint32 + Headroom uint32 +} + +type XDPStatistics struct { + Rx_dropped uint64 + Rx_invalid_descs uint64 + Tx_invalid_descs uint64 +} + +type XDPDesc struct { + Addr uint64 + Len uint32 + Options uint32 +} + +const ( + NCSI_CMD_UNSPEC = 0x0 + NCSI_CMD_PKG_INFO = 0x1 + NCSI_CMD_SET_INTERFACE = 0x2 + NCSI_CMD_CLEAR_INTERFACE = 0x3 + NCSI_ATTR_UNSPEC = 0x0 + NCSI_ATTR_IFINDEX = 0x1 + NCSI_ATTR_PACKAGE_LIST = 0x2 + NCSI_ATTR_PACKAGE_ID = 0x3 + NCSI_ATTR_CHANNEL_ID = 0x4 + NCSI_PKG_ATTR_UNSPEC = 0x0 + NCSI_PKG_ATTR = 0x1 + NCSI_PKG_ATTR_ID = 0x2 + NCSI_PKG_ATTR_FORCED = 0x3 + NCSI_PKG_ATTR_CHANNEL_LIST = 0x4 + NCSI_CHANNEL_ATTR_UNSPEC = 0x0 + NCSI_CHANNEL_ATTR = 0x1 + NCSI_CHANNEL_ATTR_ID = 0x2 + NCSI_CHANNEL_ATTR_VERSION_MAJOR = 0x3 + NCSI_CHANNEL_ATTR_VERSION_MINOR = 0x4 + NCSI_CHANNEL_ATTR_VERSION_STR = 0x5 + NCSI_CHANNEL_ATTR_LINK_STATE = 0x6 + NCSI_CHANNEL_ATTR_ACTIVE = 0x7 + NCSI_CHANNEL_ATTR_FORCED = 0x8 + NCSI_CHANNEL_ATTR_VLAN_LIST = 0x9 + NCSI_CHANNEL_ATTR_VLAN_ID = 0xa +) + +type ScmTimestamping struct { + Ts [3]Timespec +} + +const ( + SOF_TIMESTAMPING_TX_HARDWARE = 0x1 + SOF_TIMESTAMPING_TX_SOFTWARE = 0x2 + SOF_TIMESTAMPING_RX_HARDWARE = 0x4 + SOF_TIMESTAMPING_RX_SOFTWARE = 0x8 + SOF_TIMESTAMPING_SOFTWARE = 0x10 + SOF_TIMESTAMPING_SYS_HARDWARE = 0x20 + SOF_TIMESTAMPING_RAW_HARDWARE = 0x40 + SOF_TIMESTAMPING_OPT_ID = 0x80 + SOF_TIMESTAMPING_TX_SCHED = 0x100 + SOF_TIMESTAMPING_TX_ACK = 0x200 + SOF_TIMESTAMPING_OPT_CMSG = 0x400 + SOF_TIMESTAMPING_OPT_TSONLY = 0x800 + SOF_TIMESTAMPING_OPT_STATS = 0x1000 + SOF_TIMESTAMPING_OPT_PKTINFO = 0x2000 + SOF_TIMESTAMPING_OPT_TX_SWHW = 0x4000 + + SOF_TIMESTAMPING_LAST = 0x4000 + SOF_TIMESTAMPING_MASK = 0x7fff + + SCM_TSTAMP_SND = 0x0 + SCM_TSTAMP_SCHED = 0x1 + SCM_TSTAMP_ACK = 0x2 +) + +type SockExtendedErr struct { + Errno uint32 + Origin uint8 + Type uint8 + Code uint8 + Pad uint8 + Info uint32 + Data uint32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go b/vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go index e16c05a8a0..2dae0c17a3 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go +++ b/vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go @@ -6,11 +6,11 @@ package unix const ( - sizeofPtr = 0x4 - sizeofShort = 0x2 - sizeofInt = 0x4 - sizeofLong = 0x4 - sizeofLongLong = 0x8 + SizeofPtr = 0x4 + SizeofShort = 0x2 + SizeofInt = 0x4 + SizeofLong = 0x4 + SizeofLongLong = 0x8 ) type ( @@ -99,6 +99,19 @@ type Fsid struct { X__fsid_val [2]int32 } +const ( + PathMax = 0x400 +) + +const ( + FADV_NORMAL = 0x0 + FADV_RANDOM = 0x1 + FADV_SEQUENTIAL = 0x2 + FADV_WILLNEED = 0x3 + FADV_DONTNEED = 0x4 + FADV_NOREUSE = 0x5 +) + type RawSockaddrInet4 struct { Len uint8 Family uint8 @@ -389,6 +402,13 @@ type Winsize struct { Ypixel uint16 } +type Ptmget struct { + Cfd int32 + Sfd int32 + Cn [1024]byte + Sn [1024]byte +} + const ( AT_FDCWD = -0x64 AT_SYMLINK_NOFOLLOW = 0x200 @@ -425,3 +445,21 @@ type Sysctlnode struct { X_sysctl_parent [8]byte X_sysctl_desc [8]byte } + +type Utsname struct { + Sysname [256]byte + Nodename [256]byte + Release [256]byte + Version [256]byte + Machine [256]byte +} + +const SizeofClockinfo = 0x14 + +type Clockinfo struct { + Hz int32 + Tick int32 + Tickadj int32 + Stathz int32 + Profhz int32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go index 9c3743561f..1f0e76c0cc 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go @@ -6,11 +6,11 @@ package unix const ( - sizeofPtr = 0x8 - sizeofShort = 0x2 - sizeofInt = 0x4 - sizeofLong = 0x8 - sizeofLongLong = 0x8 + SizeofPtr = 0x8 + SizeofShort = 0x2 + SizeofInt = 0x4 + SizeofLong = 0x8 + SizeofLongLong = 0x8 ) type ( @@ -103,6 +103,19 @@ type Fsid struct { X__fsid_val [2]int32 } +const ( + PathMax = 0x400 +) + +const ( + FADV_NORMAL = 0x0 + FADV_RANDOM = 0x1 + FADV_SEQUENTIAL = 0x2 + FADV_WILLNEED = 0x3 + FADV_DONTNEED = 0x4 + FADV_NOREUSE = 0x5 +) + type RawSockaddrInet4 struct { Len uint8 Family uint8 @@ -396,6 +409,13 @@ type Winsize struct { Ypixel uint16 } +type Ptmget struct { + Cfd int32 + Sfd int32 + Cn [1024]byte + Sn [1024]byte +} + const ( AT_FDCWD = -0x64 AT_SYMLINK_NOFOLLOW = 0x200 @@ -432,3 +452,21 @@ type Sysctlnode struct { X_sysctl_parent [8]byte X_sysctl_desc [8]byte } + +type Utsname struct { + Sysname [256]byte + Nodename [256]byte + Release [256]byte + Version [256]byte + Machine [256]byte +} + +const SizeofClockinfo = 0x14 + +type Clockinfo struct { + Hz int32 + Tick int32 + Tickadj int32 + Stathz int32 + Profhz int32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go b/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go index 1329423184..53f2159c7d 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go +++ b/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go @@ -6,11 +6,11 @@ package unix const ( - sizeofPtr = 0x4 - sizeofShort = 0x2 - sizeofInt = 0x4 - sizeofLong = 0x4 - sizeofLongLong = 0x8 + SizeofPtr = 0x4 + SizeofShort = 0x2 + SizeofInt = 0x4 + SizeofLong = 0x4 + SizeofLongLong = 0x8 ) type ( @@ -104,6 +104,19 @@ type Fsid struct { X__fsid_val [2]int32 } +const ( + PathMax = 0x400 +) + +const ( + FADV_NORMAL = 0x0 + FADV_RANDOM = 0x1 + FADV_SEQUENTIAL = 0x2 + FADV_WILLNEED = 0x3 + FADV_DONTNEED = 0x4 + FADV_NOREUSE = 0x5 +) + type RawSockaddrInet4 struct { Len uint8 Family uint8 @@ -394,6 +407,13 @@ type Winsize struct { Ypixel uint16 } +type Ptmget struct { + Cfd int32 + Sfd int32 + Cn [1024]byte + Sn [1024]byte +} + const ( AT_FDCWD = -0x64 AT_SYMLINK_NOFOLLOW = 0x200 @@ -430,3 +450,21 @@ type Sysctlnode struct { X_sysctl_parent [8]byte X_sysctl_desc [8]byte } + +type Utsname struct { + Sysname [256]byte + Nodename [256]byte + Release [256]byte + Version [256]byte + Machine [256]byte +} + +const SizeofClockinfo = 0x14 + +type Clockinfo struct { + Hz int32 + Tick int32 + Tickadj int32 + Stathz int32 + Profhz int32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm64.go b/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm64.go new file mode 100644 index 0000000000..43da2c41c5 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm64.go @@ -0,0 +1,472 @@ +// cgo -godefs types_netbsd.go | go run mkpost.go +// Code generated by the command above; see README.md. DO NOT EDIT. + +// +build arm64,netbsd + +package unix + +const ( + SizeofPtr = 0x8 + SizeofShort = 0x2 + SizeofInt = 0x4 + SizeofLong = 0x8 + SizeofLongLong = 0x8 +) + +type ( + _C_short int16 + _C_int int32 + _C_long int64 + _C_long_long int64 +) + +type Timespec struct { + Sec int64 + Nsec int64 +} + +type Timeval struct { + Sec int64 + Usec int32 + Pad_cgo_0 [4]byte +} + +type Rusage struct { + Utime Timeval + Stime Timeval + Maxrss int64 + Ixrss int64 + Idrss int64 + Isrss int64 + Minflt int64 + Majflt int64 + Nswap int64 + Inblock int64 + Oublock int64 + Msgsnd int64 + Msgrcv int64 + Nsignals int64 + Nvcsw int64 + Nivcsw int64 +} + +type Rlimit struct { + Cur uint64 + Max uint64 +} + +type _Gid_t uint32 + +type Stat_t struct { + Dev uint64 + Mode uint32 + Pad_cgo_0 [4]byte + Ino uint64 + Nlink uint32 + Uid uint32 + Gid uint32 + Pad_cgo_1 [4]byte + Rdev uint64 + Atimespec Timespec + Mtimespec Timespec + Ctimespec Timespec + Birthtimespec Timespec + Size int64 + Blocks int64 + Blksize uint32 + Flags uint32 + Gen uint32 + Spare [2]uint32 + Pad_cgo_2 [4]byte +} + +type Statfs_t [0]byte + +type Flock_t struct { + Start int64 + Len int64 + Pid int32 + Type int16 + Whence int16 +} + +type Dirent struct { + Fileno uint64 + Reclen uint16 + Namlen uint16 + Type uint8 + Name [512]int8 + Pad_cgo_0 [3]byte +} + +type Fsid struct { + X__fsid_val [2]int32 +} + +const ( + PathMax = 0x400 +) + +const ( + FADV_NORMAL = 0x0 + FADV_RANDOM = 0x1 + FADV_SEQUENTIAL = 0x2 + FADV_WILLNEED = 0x3 + FADV_DONTNEED = 0x4 + FADV_NOREUSE = 0x5 +) + +type RawSockaddrInet4 struct { + Len uint8 + Family uint8 + Port uint16 + Addr [4]byte /* in_addr */ + Zero [8]int8 +} + +type RawSockaddrInet6 struct { + Len uint8 + Family uint8 + Port uint16 + Flowinfo uint32 + Addr [16]byte /* in6_addr */ + Scope_id uint32 +} + +type RawSockaddrUnix struct { + Len uint8 + Family uint8 + Path [104]int8 +} + +type RawSockaddrDatalink struct { + Len uint8 + Family uint8 + Index uint16 + Type uint8 + Nlen uint8 + Alen uint8 + Slen uint8 + Data [12]int8 +} + +type RawSockaddr struct { + Len uint8 + Family uint8 + Data [14]int8 +} + +type RawSockaddrAny struct { + Addr RawSockaddr + Pad [92]int8 +} + +type _Socklen uint32 + +type Linger struct { + Onoff int32 + Linger int32 +} + +type Iovec struct { + Base *byte + Len uint64 +} + +type IPMreq struct { + Multiaddr [4]byte /* in_addr */ + Interface [4]byte /* in_addr */ +} + +type IPv6Mreq struct { + Multiaddr [16]byte /* in6_addr */ + Interface uint32 +} + +type Msghdr struct { + Name *byte + Namelen uint32 + Pad_cgo_0 [4]byte + Iov *Iovec + Iovlen int32 + Pad_cgo_1 [4]byte + Control *byte + Controllen uint32 + Flags int32 +} + +type Cmsghdr struct { + Len uint32 + Level int32 + Type int32 +} + +type Inet6Pktinfo struct { + Addr [16]byte /* in6_addr */ + Ifindex uint32 +} + +type IPv6MTUInfo struct { + Addr RawSockaddrInet6 + Mtu uint32 +} + +type ICMPv6Filter struct { + Filt [8]uint32 +} + +const ( + SizeofSockaddrInet4 = 0x10 + SizeofSockaddrInet6 = 0x1c + SizeofSockaddrAny = 0x6c + SizeofSockaddrUnix = 0x6a + SizeofSockaddrDatalink = 0x14 + SizeofLinger = 0x8 + SizeofIPMreq = 0x8 + SizeofIPv6Mreq = 0x14 + SizeofMsghdr = 0x30 + SizeofCmsghdr = 0xc + SizeofInet6Pktinfo = 0x14 + SizeofIPv6MTUInfo = 0x20 + SizeofICMPv6Filter = 0x20 +) + +const ( + PTRACE_TRACEME = 0x0 + PTRACE_CONT = 0x7 + PTRACE_KILL = 0x8 +) + +type Kevent_t struct { + Ident uint64 + Filter uint32 + Flags uint32 + Fflags uint32 + Pad_cgo_0 [4]byte + Data int64 + Udata int64 +} + +type FdSet struct { + Bits [8]uint32 +} + +const ( + SizeofIfMsghdr = 0x98 + SizeofIfData = 0x88 + SizeofIfaMsghdr = 0x18 + SizeofIfAnnounceMsghdr = 0x18 + SizeofRtMsghdr = 0x78 + SizeofRtMetrics = 0x50 +) + +type IfMsghdr struct { + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + Pad_cgo_0 [2]byte + Data IfData +} + +type IfData struct { + Type uint8 + Addrlen uint8 + Hdrlen uint8 + Pad_cgo_0 [1]byte + Link_state int32 + Mtu uint64 + Metric uint64 + Baudrate uint64 + Ipackets uint64 + Ierrors uint64 + Opackets uint64 + Oerrors uint64 + Collisions uint64 + Ibytes uint64 + Obytes uint64 + Imcasts uint64 + Omcasts uint64 + Iqdrops uint64 + Noproto uint64 + Lastchange Timespec +} + +type IfaMsghdr struct { + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Metric int32 + Index uint16 + Pad_cgo_0 [6]byte +} + +type IfAnnounceMsghdr struct { + Msglen uint16 + Version uint8 + Type uint8 + Index uint16 + Name [16]int8 + What uint16 +} + +type RtMsghdr struct { + Msglen uint16 + Version uint8 + Type uint8 + Index uint16 + Pad_cgo_0 [2]byte + Flags int32 + Addrs int32 + Pid int32 + Seq int32 + Errno int32 + Use int32 + Inits int32 + Pad_cgo_1 [4]byte + Rmx RtMetrics +} + +type RtMetrics struct { + Locks uint64 + Mtu uint64 + Hopcount uint64 + Recvpipe uint64 + Sendpipe uint64 + Ssthresh uint64 + Rtt uint64 + Rttvar uint64 + Expire int64 + Pksent int64 +} + +type Mclpool [0]byte + +const ( + SizeofBpfVersion = 0x4 + SizeofBpfStat = 0x80 + SizeofBpfProgram = 0x10 + SizeofBpfInsn = 0x8 + SizeofBpfHdr = 0x20 +) + +type BpfVersion struct { + Major uint16 + Minor uint16 +} + +type BpfStat struct { + Recv uint64 + Drop uint64 + Capt uint64 + Padding [13]uint64 +} + +type BpfProgram struct { + Len uint32 + Pad_cgo_0 [4]byte + Insns *BpfInsn +} + +type BpfInsn struct { + Code uint16 + Jt uint8 + Jf uint8 + K uint32 +} + +type BpfHdr struct { + Tstamp BpfTimeval + Caplen uint32 + Datalen uint32 + Hdrlen uint16 + Pad_cgo_0 [6]byte +} + +type BpfTimeval struct { + Sec int64 + Usec int64 +} + +type Termios struct { + Iflag uint32 + Oflag uint32 + Cflag uint32 + Lflag uint32 + Cc [20]uint8 + Ispeed int32 + Ospeed int32 +} + +type Winsize struct { + Row uint16 + Col uint16 + Xpixel uint16 + Ypixel uint16 +} + +type Ptmget struct { + Cfd int32 + Sfd int32 + Cn [1024]byte + Sn [1024]byte +} + +const ( + AT_FDCWD = -0x64 + AT_SYMLINK_NOFOLLOW = 0x200 +) + +type PollFd struct { + Fd int32 + Events int16 + Revents int16 +} + +const ( + POLLERR = 0x8 + POLLHUP = 0x10 + POLLIN = 0x1 + POLLNVAL = 0x20 + POLLOUT = 0x4 + POLLPRI = 0x2 + POLLRDBAND = 0x80 + POLLRDNORM = 0x40 + POLLWRBAND = 0x100 + POLLWRNORM = 0x4 +) + +type Sysctlnode struct { + Flags uint32 + Num int32 + Name [32]int8 + Ver uint32 + X__rsvd uint32 + Un [16]byte + X_sysctl_size [8]byte + X_sysctl_func [8]byte + X_sysctl_parent [8]byte + X_sysctl_desc [8]byte +} + +type Utsname struct { + Sysname [256]byte + Nodename [256]byte + Release [256]byte + Version [256]byte + Machine [256]byte +} + +const SizeofClockinfo = 0x14 + +type Clockinfo struct { + Hz int32 + Tick int32 + Tickadj int32 + Stathz int32 + Profhz int32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go b/vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go index 2cf08bf495..8b37d83992 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go +++ b/vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go @@ -6,11 +6,11 @@ package unix const ( - sizeofPtr = 0x4 - sizeofShort = 0x2 - sizeofInt = 0x4 - sizeofLong = 0x4 - sizeofLongLong = 0x8 + SizeofPtr = 0x4 + SizeofShort = 0x2 + SizeofInt = 0x4 + SizeofLong = 0x4 + SizeofLongLong = 0x8 ) type ( @@ -56,23 +56,6 @@ type Rlimit struct { type _Gid_t uint32 -const ( - S_IFMT = 0xf000 - S_IFIFO = 0x1000 - S_IFCHR = 0x2000 - S_IFDIR = 0x4000 - S_IFBLK = 0x6000 - S_IFREG = 0x8000 - S_IFLNK = 0xa000 - S_IFSOCK = 0xc000 - S_ISUID = 0x800 - S_ISGID = 0x400 - S_ISVTX = 0x200 - S_IRUSR = 0x100 - S_IWUSR = 0x80 - S_IXUSR = 0x40 -) - type Stat_t struct { Mode uint32 Dev int32 @@ -140,6 +123,10 @@ type Fsid struct { Val [2]int32 } +const ( + PathMax = 0x400 +) + type RawSockaddrInet4 struct { Len uint8 Family uint8 @@ -470,3 +457,104 @@ const ( POLLWRBAND = 0x100 POLLWRNORM = 0x4 ) + +type Sigset_t uint32 + +type Utsname struct { + Sysname [256]byte + Nodename [256]byte + Release [256]byte + Version [256]byte + Machine [256]byte +} + +const SizeofUvmexp = 0x158 + +type Uvmexp struct { + Pagesize int32 + Pagemask int32 + Pageshift int32 + Npages int32 + Free int32 + Active int32 + Inactive int32 + Paging int32 + Wired int32 + Zeropages int32 + Reserve_pagedaemon int32 + Reserve_kernel int32 + Anonpages int32 + Vnodepages int32 + Vtextpages int32 + Freemin int32 + Freetarg int32 + Inactarg int32 + Wiredmax int32 + Anonmin int32 + Vtextmin int32 + Vnodemin int32 + Anonminpct int32 + Vtextminpct int32 + Vnodeminpct int32 + Nswapdev int32 + Swpages int32 + Swpginuse int32 + Swpgonly int32 + Nswget int32 + Nanon int32 + Nanonneeded int32 + Nfreeanon int32 + Faults int32 + Traps int32 + Intrs int32 + Swtch int32 + Softs int32 + Syscalls int32 + Pageins int32 + Obsolete_swapins int32 + Obsolete_swapouts int32 + Pgswapin int32 + Pgswapout int32 + Forks int32 + Forks_ppwait int32 + Forks_sharevm int32 + Pga_zerohit int32 + Pga_zeromiss int32 + Zeroaborts int32 + Fltnoram int32 + Fltnoanon int32 + Fltnoamap int32 + Fltpgwait int32 + Fltpgrele int32 + Fltrelck int32 + Fltrelckok int32 + Fltanget int32 + Fltanretry int32 + Fltamcopy int32 + Fltnamap int32 + Fltnomap int32 + Fltlget int32 + Fltget int32 + Flt_anon int32 + Flt_acow int32 + Flt_obj int32 + Flt_prcopy int32 + Flt_przero int32 + Pdwoke int32 + Pdrevs int32 + Pdswout int32 + Pdfreed int32 + Pdscans int32 + Pdanscan int32 + Pdobscan int32 + Pdreact int32 + Pdbusy int32 + Pdpageouts int32 + Pdpending int32 + Pddeact int32 + Pdreanon int32 + Pdrevnode int32 + Pdrevtext int32 + Fpswtch int32 + Kmapent int32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go index 7cfc61f661..6efea46355 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go @@ -6,11 +6,11 @@ package unix const ( - sizeofPtr = 0x8 - sizeofShort = 0x2 - sizeofInt = 0x4 - sizeofLong = 0x8 - sizeofLongLong = 0x8 + SizeofPtr = 0x8 + SizeofShort = 0x2 + SizeofInt = 0x4 + SizeofLong = 0x8 + SizeofLongLong = 0x8 ) type ( @@ -56,48 +56,31 @@ type Rlimit struct { type _Gid_t uint32 -const ( - S_IFMT = 0xf000 - S_IFIFO = 0x1000 - S_IFCHR = 0x2000 - S_IFDIR = 0x4000 - S_IFBLK = 0x6000 - S_IFREG = 0x8000 - S_IFLNK = 0xa000 - S_IFSOCK = 0xc000 - S_ISUID = 0x800 - S_ISGID = 0x400 - S_ISVTX = 0x200 - S_IRUSR = 0x100 - S_IWUSR = 0x80 - S_IXUSR = 0x40 -) - type Stat_t struct { - Mode uint32 - Dev int32 - Ino uint64 - Nlink uint32 - Uid uint32 - Gid uint32 - Rdev int32 - Atim Timespec - Mtim Timespec - Ctim Timespec - Size int64 - Blocks int64 - Blksize uint32 - Flags uint32 - Gen uint32 - Pad_cgo_0 [4]byte - X__st_birthtim Timespec + Mode uint32 + Dev int32 + Ino uint64 + Nlink uint32 + Uid uint32 + Gid uint32 + Rdev int32 + Atim Timespec + Mtim Timespec + Ctim Timespec + Size int64 + Blocks int64 + Blksize int32 + Flags uint32 + Gen uint32 + _ [4]byte + _ Timespec } type Statfs_t struct { F_flags uint32 F_bsize uint32 F_iosize uint32 - Pad_cgo_0 [4]byte + _ [4]byte F_blocks uint64 F_bfree uint64 F_bavail int64 @@ -116,7 +99,7 @@ type Statfs_t struct { F_mntonname [90]int8 F_mntfromname [90]int8 F_mntfromspec [90]int8 - Pad_cgo_1 [2]byte + _ [2]byte Mount_info [160]byte } @@ -129,19 +112,23 @@ type Flock_t struct { } type Dirent struct { - Fileno uint64 - Off int64 - Reclen uint16 - Type uint8 - Namlen uint8 - X__d_padding [4]uint8 - Name [256]int8 + Fileno uint64 + Off int64 + Reclen uint16 + Type uint8 + Namlen uint8 + _ [4]uint8 + Name [256]int8 } type Fsid struct { Val [2]int32 } +const ( + PathMax = 0x400 +) + type RawSockaddrInet4 struct { Len uint8 Family uint8 @@ -212,10 +199,10 @@ type IPv6Mreq struct { type Msghdr struct { Name *byte Namelen uint32 - Pad_cgo_0 [4]byte + _ [4]byte Iov *Iovec Iovlen uint32 - Pad_cgo_1 [4]byte + _ [4]byte Control *byte Controllen uint32 Flags int32 @@ -277,8 +264,8 @@ type FdSet struct { } const ( - SizeofIfMsghdr = 0xf8 - SizeofIfData = 0xe0 + SizeofIfMsghdr = 0xa8 + SizeofIfData = 0x90 SizeofIfaMsghdr = 0x18 SizeofIfAnnounceMsghdr = 0x1a SizeofRtMsghdr = 0x60 @@ -307,7 +294,7 @@ type IfData struct { Link_state uint8 Mtu uint32 Metric uint32 - Pad uint32 + Rdomain uint32 Baudrate uint64 Ipackets uint64 Ierrors uint64 @@ -319,12 +306,11 @@ type IfData struct { Imcasts uint64 Omcasts uint64 Iqdrops uint64 + Oqdrops uint64 Noproto uint64 Capabilities uint32 - Pad_cgo_0 [4]byte + _ [4]byte Lastchange Timeval - Mclpool [7]Mclpool - Pad_cgo_1 [4]byte } type IfaMsghdr struct { @@ -385,13 +371,7 @@ type RtMetrics struct { Pad uint32 } -type Mclpool struct { - Grown int32 - Alive uint16 - Hwm uint16 - Cwm uint16 - Lwm uint16 -} +type Mclpool struct{} const ( SizeofBpfVersion = 0x4 @@ -412,9 +392,9 @@ type BpfStat struct { } type BpfProgram struct { - Len uint32 - Pad_cgo_0 [4]byte - Insns *BpfInsn + Len uint32 + _ [4]byte + Insns *BpfInsn } type BpfInsn struct { @@ -425,11 +405,11 @@ type BpfInsn struct { } type BpfHdr struct { - Tstamp BpfTimeval - Caplen uint32 - Datalen uint32 - Hdrlen uint16 - Pad_cgo_0 [2]byte + Tstamp BpfTimeval + Caplen uint32 + Datalen uint32 + Hdrlen uint16 + _ [2]byte } type BpfTimeval struct { @@ -477,3 +457,104 @@ const ( POLLWRBAND = 0x100 POLLWRNORM = 0x4 ) + +type Sigset_t uint32 + +type Utsname struct { + Sysname [256]byte + Nodename [256]byte + Release [256]byte + Version [256]byte + Machine [256]byte +} + +const SizeofUvmexp = 0x158 + +type Uvmexp struct { + Pagesize int32 + Pagemask int32 + Pageshift int32 + Npages int32 + Free int32 + Active int32 + Inactive int32 + Paging int32 + Wired int32 + Zeropages int32 + Reserve_pagedaemon int32 + Reserve_kernel int32 + Anonpages int32 + Vnodepages int32 + Vtextpages int32 + Freemin int32 + Freetarg int32 + Inactarg int32 + Wiredmax int32 + Anonmin int32 + Vtextmin int32 + Vnodemin int32 + Anonminpct int32 + Vtextminpct int32 + Vnodeminpct int32 + Nswapdev int32 + Swpages int32 + Swpginuse int32 + Swpgonly int32 + Nswget int32 + Nanon int32 + Nanonneeded int32 + Nfreeanon int32 + Faults int32 + Traps int32 + Intrs int32 + Swtch int32 + Softs int32 + Syscalls int32 + Pageins int32 + Obsolete_swapins int32 + Obsolete_swapouts int32 + Pgswapin int32 + Pgswapout int32 + Forks int32 + Forks_ppwait int32 + Forks_sharevm int32 + Pga_zerohit int32 + Pga_zeromiss int32 + Zeroaborts int32 + Fltnoram int32 + Fltnoanon int32 + Fltnoamap int32 + Fltpgwait int32 + Fltpgrele int32 + Fltrelck int32 + Fltrelckok int32 + Fltanget int32 + Fltanretry int32 + Fltamcopy int32 + Fltnamap int32 + Fltnomap int32 + Fltlget int32 + Fltget int32 + Flt_anon int32 + Flt_acow int32 + Flt_obj int32 + Flt_prcopy int32 + Flt_przero int32 + Pdwoke int32 + Pdrevs int32 + Pdswout int32 + Pdfreed int32 + Pdscans int32 + Pdanscan int32 + Pdobscan int32 + Pdreact int32 + Pdbusy int32 + Pdpageouts int32 + Pdpending int32 + Pddeact int32 + Pdreanon int32 + Pdrevnode int32 + Pdrevtext int32 + Fpswtch int32 + Kmapent int32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go b/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go index 842c59c5c1..510efc3eaa 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go +++ b/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go @@ -1,4 +1,4 @@ -// cgo -godefs types_openbsd.go | go run mkpost.go +// cgo -godefs -- -fsigned-char types_openbsd.go | go run mkpost.go // Code generated by the command above; see README.md. DO NOT EDIT. // +build arm,openbsd @@ -6,11 +6,11 @@ package unix const ( - sizeofPtr = 0x4 - sizeofShort = 0x2 - sizeofInt = 0x4 - sizeofLong = 0x4 - sizeofLongLong = 0x8 + SizeofPtr = 0x4 + SizeofShort = 0x2 + SizeofInt = 0x4 + SizeofLong = 0x4 + SizeofLongLong = 0x8 ) type ( @@ -23,11 +23,13 @@ type ( type Timespec struct { Sec int64 Nsec int32 + _ [4]byte } type Timeval struct { Sec int64 Usec int32 + _ [4]byte } type Rusage struct { @@ -56,46 +58,31 @@ type Rlimit struct { type _Gid_t uint32 -const ( - S_IFMT = 0xf000 - S_IFIFO = 0x1000 - S_IFCHR = 0x2000 - S_IFDIR = 0x4000 - S_IFBLK = 0x6000 - S_IFREG = 0x8000 - S_IFLNK = 0xa000 - S_IFSOCK = 0xc000 - S_ISUID = 0x800 - S_ISGID = 0x400 - S_ISVTX = 0x200 - S_IRUSR = 0x100 - S_IWUSR = 0x80 - S_IXUSR = 0x40 -) - type Stat_t struct { - Mode uint32 - Dev int32 - Ino uint64 - Nlink uint32 - Uid uint32 - Gid uint32 - Rdev int32 - Atim Timespec - Mtim Timespec - Ctim Timespec - Size int64 - Blocks int64 - Blksize int32 - Flags uint32 - Gen uint32 - X__st_birthtim Timespec + Mode uint32 + Dev int32 + Ino uint64 + Nlink uint32 + Uid uint32 + Gid uint32 + Rdev int32 + Atim Timespec + Mtim Timespec + Ctim Timespec + Size int64 + Blocks int64 + Blksize int32 + Flags uint32 + Gen uint32 + _ [4]byte + _ Timespec } type Statfs_t struct { F_flags uint32 F_bsize uint32 F_iosize uint32 + _ [4]byte F_blocks uint64 F_bfree uint64 F_bavail int64 @@ -110,11 +97,11 @@ type Statfs_t struct { F_namemax uint32 F_owner uint32 F_ctime uint64 - F_fstypename [16]uint8 - F_mntonname [90]uint8 - F_mntfromname [90]uint8 - F_mntfromspec [90]uint8 - Pad_cgo_0 [2]byte + F_fstypename [16]int8 + F_mntonname [90]int8 + F_mntfromname [90]int8 + F_mntfromspec [90]int8 + _ [2]byte Mount_info [160]byte } @@ -127,19 +114,23 @@ type Flock_t struct { } type Dirent struct { - Fileno uint64 - Off int64 - Reclen uint16 - Type uint8 - Namlen uint8 - X__d_padding [4]uint8 - Name [256]uint8 + Fileno uint64 + Off int64 + Reclen uint16 + Type uint8 + Namlen uint8 + _ [4]uint8 + Name [256]int8 } type Fsid struct { Val [2]int32 } +const ( + PathMax = 0x400 +) + type RawSockaddrInet4 struct { Len uint8 Family uint8 @@ -264,8 +255,10 @@ type Kevent_t struct { Filter int16 Flags uint16 Fflags uint32 + _ [4]byte Data int64 Udata *byte + _ [4]byte } type FdSet struct { @@ -273,8 +266,8 @@ type FdSet struct { } const ( - SizeofIfMsghdr = 0x98 - SizeofIfData = 0x80 + SizeofIfMsghdr = 0xa8 + SizeofIfData = 0x90 SizeofIfaMsghdr = 0x18 SizeofIfAnnounceMsghdr = 0x1a SizeofRtMsghdr = 0x60 @@ -303,7 +296,7 @@ type IfData struct { Link_state uint8 Mtu uint32 Metric uint32 - Pad uint32 + Rdomain uint32 Baudrate uint64 Ipackets uint64 Ierrors uint64 @@ -315,8 +308,10 @@ type IfData struct { Imcasts uint64 Omcasts uint64 Iqdrops uint64 + Oqdrops uint64 Noproto uint64 Capabilities uint32 + _ [4]byte Lastchange Timeval } @@ -341,7 +336,7 @@ type IfAnnounceMsghdr struct { Hdrlen uint16 Index uint16 What uint16 - Name [16]uint8 + Name [16]int8 } type RtMsghdr struct { @@ -411,11 +406,11 @@ type BpfInsn struct { } type BpfHdr struct { - Tstamp BpfTimeval - Caplen uint32 - Datalen uint32 - Hdrlen uint16 - Pad_cgo_0 [2]byte + Tstamp BpfTimeval + Caplen uint32 + Datalen uint32 + Hdrlen uint16 + _ [2]byte } type BpfTimeval struct { @@ -463,3 +458,104 @@ const ( POLLWRBAND = 0x100 POLLWRNORM = 0x4 ) + +type Sigset_t uint32 + +type Utsname struct { + Sysname [256]byte + Nodename [256]byte + Release [256]byte + Version [256]byte + Machine [256]byte +} + +const SizeofUvmexp = 0x158 + +type Uvmexp struct { + Pagesize int32 + Pagemask int32 + Pageshift int32 + Npages int32 + Free int32 + Active int32 + Inactive int32 + Paging int32 + Wired int32 + Zeropages int32 + Reserve_pagedaemon int32 + Reserve_kernel int32 + Unused01 int32 + Vnodepages int32 + Vtextpages int32 + Freemin int32 + Freetarg int32 + Inactarg int32 + Wiredmax int32 + Anonmin int32 + Vtextmin int32 + Vnodemin int32 + Anonminpct int32 + Vtextminpct int32 + Vnodeminpct int32 + Nswapdev int32 + Swpages int32 + Swpginuse int32 + Swpgonly int32 + Nswget int32 + Nanon int32 + Unused05 int32 + Unused06 int32 + Faults int32 + Traps int32 + Intrs int32 + Swtch int32 + Softs int32 + Syscalls int32 + Pageins int32 + Unused07 int32 + Unused08 int32 + Pgswapin int32 + Pgswapout int32 + Forks int32 + Forks_ppwait int32 + Forks_sharevm int32 + Pga_zerohit int32 + Pga_zeromiss int32 + Unused09 int32 + Fltnoram int32 + Fltnoanon int32 + Fltnoamap int32 + Fltpgwait int32 + Fltpgrele int32 + Fltrelck int32 + Fltrelckok int32 + Fltanget int32 + Fltanretry int32 + Fltamcopy int32 + Fltnamap int32 + Fltnomap int32 + Fltlget int32 + Fltget int32 + Flt_anon int32 + Flt_acow int32 + Flt_obj int32 + Flt_prcopy int32 + Flt_przero int32 + Pdwoke int32 + Pdrevs int32 + Pdswout int32 + Pdfreed int32 + Pdscans int32 + Pdanscan int32 + Pdobscan int32 + Pdreact int32 + Pdbusy int32 + Pdpageouts int32 + Pdpending int32 + Pddeact int32 + Unused11 int32 + Unused12 int32 + Unused13 int32 + Fpswtch int32 + Kmapent int32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_solaris_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_solaris_amd64.go index d445452486..8531a190f2 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_solaris_amd64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_solaris_amd64.go @@ -6,11 +6,11 @@ package unix const ( - sizeofPtr = 0x8 - sizeofShort = 0x2 - sizeofInt = 0x4 - sizeofLong = 0x8 - sizeofLongLong = 0x8 + SizeofPtr = 0x8 + SizeofShort = 0x2 + SizeofInt = 0x4 + SizeofLong = 0x8 + SizeofLongLong = 0x8 PathMax = 0x400 MaxHostNameLen = 0x100 ) @@ -75,58 +75,41 @@ type Rlimit struct { type _Gid_t uint32 -const ( - S_IFMT = 0xf000 - S_IFIFO = 0x1000 - S_IFCHR = 0x2000 - S_IFDIR = 0x4000 - S_IFBLK = 0x6000 - S_IFREG = 0x8000 - S_IFLNK = 0xa000 - S_IFSOCK = 0xc000 - S_ISUID = 0x800 - S_ISGID = 0x400 - S_ISVTX = 0x200 - S_IRUSR = 0x100 - S_IWUSR = 0x80 - S_IXUSR = 0x40 -) - type Stat_t struct { - Dev uint64 - Ino uint64 - Mode uint32 - Nlink uint32 - Uid uint32 - Gid uint32 - Rdev uint64 - Size int64 - Atim Timespec - Mtim Timespec - Ctim Timespec - Blksize int32 - Pad_cgo_0 [4]byte - Blocks int64 - Fstype [16]int8 + Dev uint64 + Ino uint64 + Mode uint32 + Nlink uint32 + Uid uint32 + Gid uint32 + Rdev uint64 + Size int64 + Atim Timespec + Mtim Timespec + Ctim Timespec + Blksize int32 + _ [4]byte + Blocks int64 + Fstype [16]int8 } type Flock_t struct { - Type int16 - Whence int16 - Pad_cgo_0 [4]byte - Start int64 - Len int64 - Sysid int32 - Pid int32 - Pad [4]int64 + Type int16 + Whence int16 + _ [4]byte + Start int64 + Len int64 + Sysid int32 + Pid int32 + Pad [4]int64 } type Dirent struct { - Ino uint64 - Off int64 - Reclen uint16 - Name [1]int8 - Pad_cgo_0 [5]byte + Ino uint64 + Off int64 + Reclen uint16 + Name [1]int8 + _ [5]byte } type _Fsblkcnt_t uint64 @@ -213,13 +196,13 @@ type IPv6Mreq struct { type Msghdr struct { Name *byte Namelen uint32 - Pad_cgo_0 [4]byte + _ [4]byte Iov *Iovec Iovlen int32 - Pad_cgo_1 [4]byte + _ [4]byte Accrights *int8 Accrightslen int32 - Pad_cgo_2 [4]byte + _ [4]byte } type Cmsghdr struct { @@ -271,11 +254,11 @@ type Utsname struct { } type Ustat_t struct { - Tfree int64 - Tinode uint64 - Fname [6]int8 - Fpack [6]int8 - Pad_cgo_0 [4]byte + Tfree int64 + Tinode uint64 + Fname [6]int8 + Fpack [6]int8 + _ [4]byte } const ( @@ -295,21 +278,21 @@ const ( ) type IfMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Pad_cgo_0 [2]byte - Data IfData + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte + Data IfData } type IfData struct { Type uint8 Addrlen uint8 Hdrlen uint8 - Pad_cgo_0 [1]byte + _ [1]byte Mtu uint32 Metric uint32 Baudrate uint32 @@ -328,30 +311,30 @@ type IfData struct { } type IfaMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - Pad_cgo_0 [2]byte - Metric int32 + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte + Metric int32 } type RtMsghdr struct { - Msglen uint16 - Version uint8 - Type uint8 - Index uint16 - Pad_cgo_0 [2]byte - Flags int32 - Addrs int32 - Pid int32 - Seq int32 - Errno int32 - Use int32 - Inits uint32 - Rmx RtMetrics + Msglen uint16 + Version uint8 + Type uint8 + Index uint16 + _ [2]byte + Flags int32 + Addrs int32 + Pid int32 + Seq int32 + Errno int32 + Use int32 + Inits uint32 + Rmx RtMetrics } type RtMetrics struct { @@ -388,9 +371,9 @@ type BpfStat struct { } type BpfProgram struct { - Len uint32 - Pad_cgo_0 [4]byte - Insns *BpfInsn + Len uint32 + _ [4]byte + Insns *BpfInsn } type BpfInsn struct { @@ -406,30 +389,30 @@ type BpfTimeval struct { } type BpfHdr struct { - Tstamp BpfTimeval - Caplen uint32 - Datalen uint32 - Hdrlen uint16 - Pad_cgo_0 [2]byte + Tstamp BpfTimeval + Caplen uint32 + Datalen uint32 + Hdrlen uint16 + _ [2]byte } type Termios struct { - Iflag uint32 - Oflag uint32 - Cflag uint32 - Lflag uint32 - Cc [19]uint8 - Pad_cgo_0 [1]byte + Iflag uint32 + Oflag uint32 + Cflag uint32 + Lflag uint32 + Cc [19]uint8 + _ [1]byte } type Termio struct { - Iflag uint16 - Oflag uint16 - Cflag uint16 - Lflag uint16 - Line int8 - Cc [8]uint8 - Pad_cgo_0 [1]byte + Iflag uint16 + Oflag uint16 + Cflag uint16 + Lflag uint16 + Line int8 + Cc [8]uint8 + _ [1]byte } type Winsize struct { diff --git a/vendor/golang.org/x/sys/windows/aliases.go b/vendor/golang.org/x/sys/windows/aliases.go new file mode 100644 index 0000000000..af3af60db9 --- /dev/null +++ b/vendor/golang.org/x/sys/windows/aliases.go @@ -0,0 +1,13 @@ +// 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 windows +// +build go1.9 + +package windows + +import "syscall" + +type Errno = syscall.Errno +type SysProcAttr = syscall.SysProcAttr diff --git a/vendor/golang.org/x/sys/windows/asm_windows_386.s b/vendor/golang.org/x/sys/windows/asm_windows_386.s index 1c20dd2f89..21d994d318 100644 --- a/vendor/golang.org/x/sys/windows/asm_windows_386.s +++ b/vendor/golang.org/x/sys/windows/asm_windows_386.s @@ -6,8 +6,8 @@ // System calls for 386, Windows are implemented in runtime/syscall_windows.goc // -TEXT ·getprocaddress(SB), 7, $0-8 +TEXT ·getprocaddress(SB), 7, $0-16 JMP syscall·getprocaddress(SB) -TEXT ·loadlibrary(SB), 7, $0-4 +TEXT ·loadlibrary(SB), 7, $0-12 JMP syscall·loadlibrary(SB) diff --git a/vendor/golang.org/x/sys/windows/asm_windows_amd64.s b/vendor/golang.org/x/sys/windows/asm_windows_amd64.s index 4d025ab556..5bfdf79741 100644 --- a/vendor/golang.org/x/sys/windows/asm_windows_amd64.s +++ b/vendor/golang.org/x/sys/windows/asm_windows_amd64.s @@ -9,5 +9,5 @@ TEXT ·getprocaddress(SB), 7, $0-32 JMP syscall·getprocaddress(SB) -TEXT ·loadlibrary(SB), 7, $0-8 +TEXT ·loadlibrary(SB), 7, $0-24 JMP syscall·loadlibrary(SB) diff --git a/vendor/golang.org/x/sys/windows/asm_windows_arm.s b/vendor/golang.org/x/sys/windows/asm_windows_arm.s new file mode 100644 index 0000000000..55d8b91a28 --- /dev/null +++ b/vendor/golang.org/x/sys/windows/asm_windows_arm.s @@ -0,0 +1,11 @@ +// 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. + +#include "textflag.h" + +TEXT ·getprocaddress(SB),NOSPLIT,$0 + B syscall·getprocaddress(SB) + +TEXT ·loadlibrary(SB),NOSPLIT,$0 + B syscall·loadlibrary(SB) diff --git a/vendor/golang.org/x/sys/windows/env_unset.go b/vendor/golang.org/x/sys/windows/env_unset.go deleted file mode 100644 index b712c6604a..0000000000 --- a/vendor/golang.org/x/sys/windows/env_unset.go +++ /dev/null @@ -1,15 +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 windows -// +build go1.4 - -package windows - -import "syscall" - -func Unsetenv(key string) error { - // This was added in Go 1.4. - return syscall.Unsetenv(key) -} diff --git a/vendor/golang.org/x/sys/windows/env_windows.go b/vendor/golang.org/x/sys/windows/env_windows.go index e8292386c0..bdc71e241e 100644 --- a/vendor/golang.org/x/sys/windows/env_windows.go +++ b/vendor/golang.org/x/sys/windows/env_windows.go @@ -23,3 +23,7 @@ func Clearenv() { func Environ() []string { return syscall.Environ() } + +func Unsetenv(key string) error { + return syscall.Unsetenv(key) +} diff --git a/vendor/golang.org/x/sys/windows/security_windows.go b/vendor/golang.org/x/sys/windows/security_windows.go index d8e7ff2ec5..4f17a3331f 100644 --- a/vendor/golang.org/x/sys/windows/security_windows.go +++ b/vendor/golang.org/x/sys/windows/security_windows.go @@ -132,6 +132,36 @@ const ( SECURITY_NT_NON_UNIQUE_RID = 0x15 ) +// Predefined domain-relative RIDs for local groups. +// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa379649(v=vs.85).aspx +const ( + DOMAIN_ALIAS_RID_ADMINS = 0x220 + DOMAIN_ALIAS_RID_USERS = 0x221 + DOMAIN_ALIAS_RID_GUESTS = 0x222 + DOMAIN_ALIAS_RID_POWER_USERS = 0x223 + DOMAIN_ALIAS_RID_ACCOUNT_OPS = 0x224 + DOMAIN_ALIAS_RID_SYSTEM_OPS = 0x225 + DOMAIN_ALIAS_RID_PRINT_OPS = 0x226 + DOMAIN_ALIAS_RID_BACKUP_OPS = 0x227 + DOMAIN_ALIAS_RID_REPLICATOR = 0x228 + DOMAIN_ALIAS_RID_RAS_SERVERS = 0x229 + DOMAIN_ALIAS_RID_PREW2KCOMPACCESS = 0x22a + DOMAIN_ALIAS_RID_REMOTE_DESKTOP_USERS = 0x22b + DOMAIN_ALIAS_RID_NETWORK_CONFIGURATION_OPS = 0x22c + DOMAIN_ALIAS_RID_INCOMING_FOREST_TRUST_BUILDERS = 0x22d + DOMAIN_ALIAS_RID_MONITORING_USERS = 0X22e + DOMAIN_ALIAS_RID_LOGGING_USERS = 0x22f + DOMAIN_ALIAS_RID_AUTHORIZATIONACCESS = 0x230 + DOMAIN_ALIAS_RID_TS_LICENSE_SERVERS = 0x231 + DOMAIN_ALIAS_RID_DCOM_USERS = 0x232 + DOMAIN_ALIAS_RID_IUSERS = 0x238 + DOMAIN_ALIAS_RID_CRYPTO_OPERATORS = 0x239 + DOMAIN_ALIAS_RID_CACHEABLE_PRINCIPALS_GROUP = 0x23b + DOMAIN_ALIAS_RID_NON_CACHEABLE_PRINCIPALS_GROUP = 0x23c + DOMAIN_ALIAS_RID_EVENT_LOG_READERS_GROUP = 0x23d + DOMAIN_ALIAS_RID_CERTSVC_DCOM_ACCESS_GROUP = 0x23e +) + //sys LookupAccountSid(systemName *uint16, sid *SID, name *uint16, nameLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) = advapi32.LookupAccountSidW //sys LookupAccountName(systemName *uint16, accountName *uint16, sid *SID, sidLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) = advapi32.LookupAccountNameW //sys ConvertSidToStringSid(sid *SID, stringSid **uint16) (err error) = advapi32.ConvertSidToStringSidW @@ -266,6 +296,7 @@ const ( TOKEN_ADJUST_PRIVILEGES TOKEN_ADJUST_GROUPS TOKEN_ADJUST_DEFAULT + TOKEN_ADJUST_SESSIONID TOKEN_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY | @@ -275,7 +306,8 @@ const ( TOKEN_QUERY_SOURCE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | - TOKEN_ADJUST_DEFAULT + TOKEN_ADJUST_DEFAULT | + TOKEN_ADJUST_SESSIONID TOKEN_READ = STANDARD_RIGHTS_READ | TOKEN_QUERY TOKEN_WRITE = STANDARD_RIGHTS_WRITE | TOKEN_ADJUST_PRIVILEGES | @@ -335,6 +367,8 @@ type Tokengroups struct { Groups [1]SIDAndAttributes } +// Authorization Functions +//sys checkTokenMembership(tokenHandle Token, sidToCheck *SID, isMember *int32) (err error) = advapi32.CheckTokenMembership //sys OpenProcessToken(h Handle, access uint32, token *Token) (err error) = advapi32.OpenProcessToken //sys GetTokenInformation(t Token, infoClass uint32, info *byte, infoLen uint32, returnedLen *uint32) (err error) = advapi32.GetTokenInformation //sys GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) = userenv.GetUserProfileDirectoryW @@ -433,3 +467,12 @@ func (t Token) GetUserProfileDirectory() (string, error) { } } } + +// IsMember reports whether the access token t is a member of the provided SID. +func (t Token) IsMember(sid *SID) (bool, error) { + var b int32 + if e := checkTokenMembership(t, sid, &b); e != nil { + return false, e + } + return b != 0, nil +} diff --git a/vendor/golang.org/x/sys/windows/service.go b/vendor/golang.org/x/sys/windows/service.go index a500dd7dfc..62fc31b40b 100644 --- a/vendor/golang.org/x/sys/windows/service.go +++ b/vendor/golang.org/x/sys/windows/service.go @@ -43,6 +43,11 @@ const ( SC_STATUS_PROCESS_INFO = 0 + SC_ACTION_NONE = 0 + SC_ACTION_RESTART = 1 + SC_ACTION_REBOOT = 2 + SC_ACTION_RUN_COMMAND = 3 + SERVICE_STOPPED = 1 SERVICE_START_PENDING = 2 SERVICE_STOP_PENDING = 3 @@ -148,6 +153,19 @@ type ENUM_SERVICE_STATUS_PROCESS struct { ServiceStatusProcess SERVICE_STATUS_PROCESS } +type SERVICE_FAILURE_ACTIONS struct { + ResetPeriod uint32 + RebootMsg *uint16 + Command *uint16 + ActionsCount uint32 + Actions *SC_ACTION +} + +type SC_ACTION struct { + Type uint32 + Delay uint32 +} + //sys CloseServiceHandle(handle Handle) (err error) = advapi32.CloseServiceHandle //sys CreateService(mgr Handle, serviceName *uint16, displayName *uint16, access uint32, srvType uint32, startType uint32, errCtl uint32, pathName *uint16, loadOrderGroup *uint16, tagId *uint32, dependencies *uint16, serviceStartName *uint16, password *uint16) (handle Handle, err error) [failretval==0] = advapi32.CreateServiceW //sys OpenService(mgr Handle, serviceName *uint16, access uint32) (handle Handle, err error) [failretval==0] = advapi32.OpenServiceW @@ -162,3 +180,4 @@ type ENUM_SERVICE_STATUS_PROCESS struct { //sys ChangeServiceConfig2(service Handle, infoLevel uint32, info *byte) (err error) = advapi32.ChangeServiceConfig2W //sys QueryServiceConfig2(service Handle, infoLevel uint32, buff *byte, buffSize uint32, bytesNeeded *uint32) (err error) = advapi32.QueryServiceConfig2W //sys EnumServicesStatusEx(mgr Handle, infoLevel uint32, serviceType uint32, serviceState uint32, services *byte, bufSize uint32, bytesNeeded *uint32, servicesReturned *uint32, resumeHandle *uint32, groupName *uint16) (err error) = advapi32.EnumServicesStatusExW +//sys QueryServiceStatusEx(service Handle, infoLevel uint32, buff *byte, buffSize uint32, bytesNeeded *uint32) (err error) = advapi32.QueryServiceStatusEx diff --git a/vendor/golang.org/x/sys/windows/syscall.go b/vendor/golang.org/x/sys/windows/syscall.go index b07bc2305d..af828a91bc 100644 --- a/vendor/golang.org/x/sys/windows/syscall.go +++ b/vendor/golang.org/x/sys/windows/syscall.go @@ -11,11 +11,14 @@ // system, set $GOOS and $GOARCH to the desired system. For example, if // you want to view documentation for freebsd/arm on linux/amd64, set $GOOS // to freebsd and $GOARCH to arm. +// // The primary use of this package is inside other packages that provide a more // portable interface to the system, such as "os", "time" and "net". Use // those packages rather than this one if you can. +// // For details of the functions and data types in this package consult // the manuals for the appropriate operating system. +// // These calls return err == nil to indicate success; otherwise // err represents an operating system error describing the failure and // holds a value of type syscall.Errno. diff --git a/vendor/golang.org/x/sys/windows/syscall_windows.go b/vendor/golang.org/x/sys/windows/syscall_windows.go index f48fec60d4..f72fa55f3e 100644 --- a/vendor/golang.org/x/sys/windows/syscall_windows.go +++ b/vendor/golang.org/x/sys/windows/syscall_windows.go @@ -16,7 +16,46 @@ import ( type Handle uintptr -const InvalidHandle = ^Handle(0) +const ( + InvalidHandle = ^Handle(0) + + // Flags for DefineDosDevice. + DDD_EXACT_MATCH_ON_REMOVE = 0x00000004 + DDD_NO_BROADCAST_SYSTEM = 0x00000008 + DDD_RAW_TARGET_PATH = 0x00000001 + DDD_REMOVE_DEFINITION = 0x00000002 + + // Return values for GetDriveType. + DRIVE_UNKNOWN = 0 + DRIVE_NO_ROOT_DIR = 1 + DRIVE_REMOVABLE = 2 + DRIVE_FIXED = 3 + DRIVE_REMOTE = 4 + DRIVE_CDROM = 5 + DRIVE_RAMDISK = 6 + + // File system flags from GetVolumeInformation and GetVolumeInformationByHandle. + FILE_CASE_SENSITIVE_SEARCH = 0x00000001 + FILE_CASE_PRESERVED_NAMES = 0x00000002 + FILE_FILE_COMPRESSION = 0x00000010 + FILE_DAX_VOLUME = 0x20000000 + FILE_NAMED_STREAMS = 0x00040000 + FILE_PERSISTENT_ACLS = 0x00000008 + FILE_READ_ONLY_VOLUME = 0x00080000 + FILE_SEQUENTIAL_WRITE_ONCE = 0x00100000 + FILE_SUPPORTS_ENCRYPTION = 0x00020000 + FILE_SUPPORTS_EXTENDED_ATTRIBUTES = 0x00800000 + FILE_SUPPORTS_HARD_LINKS = 0x00400000 + FILE_SUPPORTS_OBJECT_IDS = 0x00010000 + FILE_SUPPORTS_OPEN_BY_FILE_ID = 0x01000000 + FILE_SUPPORTS_REPARSE_POINTS = 0x00000080 + FILE_SUPPORTS_SPARSE_FILES = 0x00000040 + FILE_SUPPORTS_TRANSACTIONS = 0x00200000 + FILE_SUPPORTS_USN_JOURNAL = 0x02000000 + FILE_UNICODE_ON_DISK = 0x00000004 + FILE_VOLUME_IS_COMPRESSED = 0x00008000 + FILE_VOLUME_QUOTAS = 0x00000020 +) // StringToUTF16 is deprecated. Use UTF16FromString instead. // If s contains a NUL byte this function panics instead of @@ -73,12 +112,14 @@ func Getpagesize() int { return 4096 } // NewCallback converts a Go function to a function pointer conforming to the stdcall calling convention. // This is useful when interoperating with Windows code requiring callbacks. +// The argument is expected to be a function with with one uintptr-sized result. The function must not have arguments with size larger than the size of uintptr. func NewCallback(fn interface{}) uintptr { return syscall.NewCallback(fn) } // NewCallbackCDecl converts a Go function to a function pointer conforming to the cdecl calling convention. // This is useful when interoperating with Windows code requiring callbacks. +// The argument is expected to be a function with with one uintptr-sized result. The function must not have arguments with size larger than the size of uintptr. func NewCallbackCDecl(fn interface{}) uintptr { return syscall.NewCallbackCDecl(fn) } @@ -131,6 +172,7 @@ func NewCallbackCDecl(fn interface{}) uintptr { //sys GetProcessTimes(handle Handle, creationTime *Filetime, exitTime *Filetime, kernelTime *Filetime, userTime *Filetime) (err error) //sys DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (err error) //sys WaitForSingleObject(handle Handle, waitMilliseconds uint32) (event uint32, err error) [failretval==0xffffffff] +//sys waitForMultipleObjects(count uint32, handles uintptr, waitAll bool, waitMilliseconds uint32) (event uint32, err error) [failretval==0xffffffff] = WaitForMultipleObjects //sys GetTempPath(buflen uint32, buf *uint16) (n uint32, err error) = GetTempPathW //sys CreatePipe(readhandle *Handle, writehandle *Handle, sa *SecurityAttributes, size uint32) (err error) //sys GetFileType(filehandle Handle) (n uint32, err error) @@ -200,6 +242,27 @@ func NewCallbackCDecl(fn interface{}) uintptr { //sys ResetEvent(event Handle) (err error) = kernel32.ResetEvent //sys PulseEvent(event Handle) (err error) = kernel32.PulseEvent +// Volume Management Functions +//sys DefineDosDevice(flags uint32, deviceName *uint16, targetPath *uint16) (err error) = DefineDosDeviceW +//sys DeleteVolumeMountPoint(volumeMountPoint *uint16) (err error) = DeleteVolumeMountPointW +//sys FindFirstVolume(volumeName *uint16, bufferLength uint32) (handle Handle, err error) [failretval==InvalidHandle] = FindFirstVolumeW +//sys FindFirstVolumeMountPoint(rootPathName *uint16, volumeMountPoint *uint16, bufferLength uint32) (handle Handle, err error) [failretval==InvalidHandle] = FindFirstVolumeMountPointW +//sys FindNextVolume(findVolume Handle, volumeName *uint16, bufferLength uint32) (err error) = FindNextVolumeW +//sys FindNextVolumeMountPoint(findVolumeMountPoint Handle, volumeMountPoint *uint16, bufferLength uint32) (err error) = FindNextVolumeMountPointW +//sys FindVolumeClose(findVolume Handle) (err error) +//sys FindVolumeMountPointClose(findVolumeMountPoint Handle) (err error) +//sys GetDriveType(rootPathName *uint16) (driveType uint32) = GetDriveTypeW +//sys GetLogicalDrives() (drivesBitMask uint32, err error) [failretval==0] +//sys GetLogicalDriveStrings(bufferLength uint32, buffer *uint16) (n uint32, err error) [failretval==0] = GetLogicalDriveStringsW +//sys GetVolumeInformation(rootPathName *uint16, volumeNameBuffer *uint16, volumeNameSize uint32, volumeNameSerialNumber *uint32, maximumComponentLength *uint32, fileSystemFlags *uint32, fileSystemNameBuffer *uint16, fileSystemNameSize uint32) (err error) = GetVolumeInformationW +//sys GetVolumeInformationByHandle(file Handle, volumeNameBuffer *uint16, volumeNameSize uint32, volumeNameSerialNumber *uint32, maximumComponentLength *uint32, fileSystemFlags *uint32, fileSystemNameBuffer *uint16, fileSystemNameSize uint32) (err error) = GetVolumeInformationByHandleW +//sys GetVolumeNameForVolumeMountPoint(volumeMountPoint *uint16, volumeName *uint16, bufferlength uint32) (err error) = GetVolumeNameForVolumeMountPointW +//sys GetVolumePathName(fileName *uint16, volumePathName *uint16, bufferLength uint32) (err error) = GetVolumePathNameW +//sys GetVolumePathNamesForVolumeName(volumeName *uint16, volumePathNames *uint16, bufferLength uint32, returnLength *uint32) (err error) = GetVolumePathNamesForVolumeNameW +//sys QueryDosDevice(deviceName *uint16, targetPath *uint16, max uint32) (n uint32, err error) [failretval==0] = QueryDosDeviceW +//sys SetVolumeLabel(rootPathName *uint16, volumeName *uint16) (err error) = SetVolumeLabelW +//sys SetVolumeMountPoint(volumeMountPoint *uint16, volumeName *uint16) (err error) = SetVolumeMountPointW + // syscall interface implementation for other packages // GetProcAddressByOrdinal retrieves the address of the exported @@ -527,6 +590,18 @@ func LoadSetFileCompletionNotificationModes() error { return procSetFileCompletionNotificationModes.Find() } +func WaitForMultipleObjects(handles []Handle, waitAll bool, waitMilliseconds uint32) (event uint32, err error) { + // Every other win32 array API takes arguments as "pointer, count", except for this function. So we + // can't declare it as a usual [] type, because mksyscall will use the opposite order. We therefore + // trivially stub this ourselves. + + var handlePtr *Handle + if len(handles) > 0 { + handlePtr = &handles[0] + } + return waitForMultipleObjects(uint32(len(handles)), uintptr(unsafe.Pointer(handlePtr)), waitAll, waitMilliseconds) +} + // net api calls const socket_error = uintptr(^uint32(0)) @@ -593,7 +668,7 @@ type RawSockaddr struct { type RawSockaddrAny struct { Addr RawSockaddr - Pad [96]int8 + Pad [100]int8 } type Sockaddr interface { @@ -642,19 +717,69 @@ func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, int32, error) { return unsafe.Pointer(&sa.raw), int32(unsafe.Sizeof(sa.raw)), nil } +type RawSockaddrUnix struct { + Family uint16 + Path [UNIX_PATH_MAX]int8 +} + type SockaddrUnix struct { Name string + raw RawSockaddrUnix } func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, int32, error) { - // TODO(brainman): implement SockaddrUnix.sockaddr() - return nil, 0, syscall.EWINDOWS + name := sa.Name + n := len(name) + if n > len(sa.raw.Path) { + return nil, 0, syscall.EINVAL + } + if n == len(sa.raw.Path) && name[0] != '@' { + return nil, 0, syscall.EINVAL + } + sa.raw.Family = AF_UNIX + for i := 0; i < n; i++ { + sa.raw.Path[i] = int8(name[i]) + } + // length is family (uint16), name, NUL. + sl := int32(2) + if n > 0 { + sl += int32(n) + 1 + } + if sa.raw.Path[0] == '@' { + sa.raw.Path[0] = 0 + // Don't count trailing NUL for abstract address. + sl-- + } + + return unsafe.Pointer(&sa.raw), sl, nil } func (rsa *RawSockaddrAny) Sockaddr() (Sockaddr, error) { switch rsa.Addr.Family { case AF_UNIX: - return nil, syscall.EWINDOWS + pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa)) + sa := new(SockaddrUnix) + if pp.Path[0] == 0 { + // "Abstract" Unix domain socket. + // Rewrite leading NUL as @ for textual display. + // (This is the standard convention.) + // Not friendly to overwrite in place, + // but the callers below don't care. + pp.Path[0] = '@' + } + + // Assume path ends at NUL. + // This is not technically the Linux semantics for + // abstract Unix domain sockets--they are supposed + // to be uninterpreted fixed-size binary blobs--but + // everyone uses this convention. + n := 0 + for n < len(pp.Path) && pp.Path[n] != 0 { + n++ + } + bytes := (*[10000]byte)(unsafe.Pointer(&pp.Path[0]))[0:n] + sa.Name = string(bytes) + return sa, nil case AF_INET: pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa)) diff --git a/vendor/golang.org/x/sys/windows/types_windows.go b/vendor/golang.org/x/sys/windows/types_windows.go index 78b714c0da..141ca81bd7 100644 --- a/vendor/golang.org/x/sys/windows/types_windows.go +++ b/vendor/golang.org/x/sys/windows/types_windows.go @@ -94,16 +94,29 @@ const ( FILE_APPEND_DATA = 0x00000004 FILE_WRITE_ATTRIBUTES = 0x00000100 - FILE_SHARE_READ = 0x00000001 - FILE_SHARE_WRITE = 0x00000002 - FILE_SHARE_DELETE = 0x00000004 - FILE_ATTRIBUTE_READONLY = 0x00000001 - FILE_ATTRIBUTE_HIDDEN = 0x00000002 - FILE_ATTRIBUTE_SYSTEM = 0x00000004 - FILE_ATTRIBUTE_DIRECTORY = 0x00000010 - FILE_ATTRIBUTE_ARCHIVE = 0x00000020 - FILE_ATTRIBUTE_NORMAL = 0x00000080 - FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400 + FILE_SHARE_READ = 0x00000001 + FILE_SHARE_WRITE = 0x00000002 + FILE_SHARE_DELETE = 0x00000004 + + FILE_ATTRIBUTE_READONLY = 0x00000001 + FILE_ATTRIBUTE_HIDDEN = 0x00000002 + FILE_ATTRIBUTE_SYSTEM = 0x00000004 + FILE_ATTRIBUTE_DIRECTORY = 0x00000010 + FILE_ATTRIBUTE_ARCHIVE = 0x00000020 + FILE_ATTRIBUTE_DEVICE = 0x00000040 + FILE_ATTRIBUTE_NORMAL = 0x00000080 + FILE_ATTRIBUTE_TEMPORARY = 0x00000100 + FILE_ATTRIBUTE_SPARSE_FILE = 0x00000200 + FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400 + FILE_ATTRIBUTE_COMPRESSED = 0x00000800 + FILE_ATTRIBUTE_OFFLINE = 0x00001000 + FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000 + FILE_ATTRIBUTE_ENCRYPTED = 0x00004000 + FILE_ATTRIBUTE_INTEGRITY_STREAM = 0x00008000 + FILE_ATTRIBUTE_VIRTUAL = 0x00010000 + FILE_ATTRIBUTE_NO_SCRUB_DATA = 0x00020000 + FILE_ATTRIBUTE_RECALL_ON_OPEN = 0x00040000 + FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS = 0x00400000 INVALID_FILE_ATTRIBUTES = 0xffffffff @@ -159,9 +172,6 @@ const ( WAIT_OBJECT_0 = 0x00000000 WAIT_FAILED = 0xFFFFFFFF - CREATE_NEW_PROCESS_GROUP = 0x00000200 - CREATE_UNICODE_ENVIRONMENT = 0x00000400 - PROCESS_TERMINATE = 1 PROCESS_QUERY_INFORMATION = 0x00000400 SYNCHRONIZE = 0x00100000 @@ -178,6 +188,26 @@ const ( APPLICATION_ERROR = 1 << 29 ) +const ( + // Process creation flags. + CREATE_BREAKAWAY_FROM_JOB = 0x01000000 + CREATE_DEFAULT_ERROR_MODE = 0x04000000 + CREATE_NEW_CONSOLE = 0x00000010 + CREATE_NEW_PROCESS_GROUP = 0x00000200 + CREATE_NO_WINDOW = 0x08000000 + CREATE_PROTECTED_PROCESS = 0x00040000 + CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000 + CREATE_SEPARATE_WOW_VDM = 0x00000800 + CREATE_SHARED_WOW_VDM = 0x00001000 + CREATE_SUSPENDED = 0x00000004 + CREATE_UNICODE_ENVIRONMENT = 0x00000400 + DEBUG_ONLY_THIS_PROCESS = 0x00000002 + DEBUG_PROCESS = 0x00000001 + DETACHED_PROCESS = 0x00000008 + EXTENDED_STARTUPINFO_PRESENT = 0x00080000 + INHERIT_PARENT_AFFINITY = 0x00010000 +) + const ( // flags for CreateToolhelp32Snapshot TH32CS_SNAPHEAPLIST = 0x01 @@ -240,15 +270,87 @@ const ( USAGE_MATCH_TYPE_AND = 0 USAGE_MATCH_TYPE_OR = 1 + /* msgAndCertEncodingType values for CertOpenStore function */ X509_ASN_ENCODING = 0x00000001 PKCS_7_ASN_ENCODING = 0x00010000 - CERT_STORE_PROV_MEMORY = 2 - - CERT_STORE_ADD_ALWAYS = 4 + /* storeProvider values for CertOpenStore function */ + CERT_STORE_PROV_MSG = 1 + CERT_STORE_PROV_MEMORY = 2 + CERT_STORE_PROV_FILE = 3 + CERT_STORE_PROV_REG = 4 + CERT_STORE_PROV_PKCS7 = 5 + CERT_STORE_PROV_SERIALIZED = 6 + CERT_STORE_PROV_FILENAME_A = 7 + CERT_STORE_PROV_FILENAME_W = 8 + CERT_STORE_PROV_FILENAME = CERT_STORE_PROV_FILENAME_W + CERT_STORE_PROV_SYSTEM_A = 9 + CERT_STORE_PROV_SYSTEM_W = 10 + CERT_STORE_PROV_SYSTEM = CERT_STORE_PROV_SYSTEM_W + CERT_STORE_PROV_COLLECTION = 11 + CERT_STORE_PROV_SYSTEM_REGISTRY_A = 12 + CERT_STORE_PROV_SYSTEM_REGISTRY_W = 13 + CERT_STORE_PROV_SYSTEM_REGISTRY = CERT_STORE_PROV_SYSTEM_REGISTRY_W + CERT_STORE_PROV_PHYSICAL_W = 14 + CERT_STORE_PROV_PHYSICAL = CERT_STORE_PROV_PHYSICAL_W + CERT_STORE_PROV_SMART_CARD_W = 15 + CERT_STORE_PROV_SMART_CARD = CERT_STORE_PROV_SMART_CARD_W + CERT_STORE_PROV_LDAP_W = 16 + CERT_STORE_PROV_LDAP = CERT_STORE_PROV_LDAP_W + CERT_STORE_PROV_PKCS12 = 17 + /* store characteristics (low WORD of flag) for CertOpenStore function */ + CERT_STORE_NO_CRYPT_RELEASE_FLAG = 0x00000001 + CERT_STORE_SET_LOCALIZED_NAME_FLAG = 0x00000002 CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG = 0x00000004 + CERT_STORE_DELETE_FLAG = 0x00000010 + CERT_STORE_UNSAFE_PHYSICAL_FLAG = 0x00000020 + CERT_STORE_SHARE_STORE_FLAG = 0x00000040 + CERT_STORE_SHARE_CONTEXT_FLAG = 0x00000080 + CERT_STORE_MANIFOLD_FLAG = 0x00000100 + CERT_STORE_ENUM_ARCHIVED_FLAG = 0x00000200 + CERT_STORE_UPDATE_KEYID_FLAG = 0x00000400 + CERT_STORE_BACKUP_RESTORE_FLAG = 0x00000800 + CERT_STORE_MAXIMUM_ALLOWED_FLAG = 0x00001000 + CERT_STORE_CREATE_NEW_FLAG = 0x00002000 + CERT_STORE_OPEN_EXISTING_FLAG = 0x00004000 + CERT_STORE_READONLY_FLAG = 0x00008000 + /* store locations (high WORD of flag) for CertOpenStore function */ + CERT_SYSTEM_STORE_CURRENT_USER = 0x00010000 + CERT_SYSTEM_STORE_LOCAL_MACHINE = 0x00020000 + CERT_SYSTEM_STORE_CURRENT_SERVICE = 0x00040000 + CERT_SYSTEM_STORE_SERVICES = 0x00050000 + CERT_SYSTEM_STORE_USERS = 0x00060000 + CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY = 0x00070000 + CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY = 0x00080000 + CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE = 0x00090000 + CERT_SYSTEM_STORE_UNPROTECTED_FLAG = 0x40000000 + CERT_SYSTEM_STORE_RELOCATE_FLAG = 0x80000000 + + /* Miscellaneous high-WORD flags for CertOpenStore function */ + CERT_REGISTRY_STORE_REMOTE_FLAG = 0x00010000 + CERT_REGISTRY_STORE_SERIALIZED_FLAG = 0x00020000 + CERT_REGISTRY_STORE_ROAMING_FLAG = 0x00040000 + CERT_REGISTRY_STORE_MY_IE_DIRTY_FLAG = 0x00080000 + CERT_REGISTRY_STORE_LM_GPT_FLAG = 0x01000000 + CERT_REGISTRY_STORE_CLIENT_GPT_FLAG = 0x80000000 + CERT_FILE_STORE_COMMIT_ENABLE_FLAG = 0x00010000 + CERT_LDAP_STORE_SIGN_FLAG = 0x00010000 + CERT_LDAP_STORE_AREC_EXCLUSIVE_FLAG = 0x00020000 + CERT_LDAP_STORE_OPENED_FLAG = 0x00040000 + CERT_LDAP_STORE_UNBIND_FLAG = 0x00080000 + + /* addDisposition values for CertAddCertificateContextToStore function */ + CERT_STORE_ADD_NEW = 1 + CERT_STORE_ADD_USE_EXISTING = 2 + CERT_STORE_ADD_REPLACE_EXISTING = 3 + CERT_STORE_ADD_ALWAYS = 4 + CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES = 5 + CERT_STORE_ADD_NEWER = 6 + CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES = 7 + + /* ErrorStatus values for CertTrustStatus struct */ CERT_TRUST_NO_ERROR = 0x00000000 CERT_TRUST_IS_NOT_TIME_VALID = 0x00000001 CERT_TRUST_IS_REVOKED = 0x00000004 @@ -265,11 +367,31 @@ const ( CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT = 0x00002000 CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT = 0x00004000 CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT = 0x00008000 + CERT_TRUST_IS_PARTIAL_CHAIN = 0x00010000 + CERT_TRUST_CTL_IS_NOT_TIME_VALID = 0x00020000 + CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID = 0x00040000 + CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE = 0x00080000 + CERT_TRUST_HAS_WEAK_SIGNATURE = 0x00100000 CERT_TRUST_IS_OFFLINE_REVOCATION = 0x01000000 CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY = 0x02000000 CERT_TRUST_IS_EXPLICIT_DISTRUST = 0x04000000 CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT = 0x08000000 + /* InfoStatus values for CertTrustStatus struct */ + CERT_TRUST_HAS_EXACT_MATCH_ISSUER = 0x00000001 + CERT_TRUST_HAS_KEY_MATCH_ISSUER = 0x00000002 + CERT_TRUST_HAS_NAME_MATCH_ISSUER = 0x00000004 + CERT_TRUST_IS_SELF_SIGNED = 0x00000008 + CERT_TRUST_HAS_PREFERRED_ISSUER = 0x00000100 + CERT_TRUST_HAS_ISSUANCE_CHAIN_POLICY = 0x00000400 + CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS = 0x00000400 + CERT_TRUST_IS_PEER_TRUSTED = 0x00000800 + CERT_TRUST_HAS_CRL_VALIDITY_EXTENDED = 0x00001000 + CERT_TRUST_IS_FROM_EXCLUSIVE_TRUST_STORE = 0x00002000 + CERT_TRUST_IS_CA_TRUSTED = 0x00004000 + CERT_TRUST_IS_COMPLEX_CHAIN = 0x00010000 + + /* policyOID values for CertVerifyCertificateChainPolicy function */ CERT_CHAIN_POLICY_BASE = 1 CERT_CHAIN_POLICY_AUTHENTICODE = 2 CERT_CHAIN_POLICY_AUTHENTICODE_TS = 3 @@ -278,6 +400,7 @@ const ( CERT_CHAIN_POLICY_NT_AUTH = 6 CERT_CHAIN_POLICY_MICROSOFT_ROOT = 7 CERT_CHAIN_POLICY_EV = 8 + CERT_CHAIN_POLICY_SSL_F12 = 9 CERT_E_EXPIRED = 0x800B0101 CERT_E_ROLE = 0x800B0103 @@ -285,8 +408,16 @@ const ( CERT_E_UNTRUSTEDROOT = 0x800B0109 CERT_E_CN_NO_MATCH = 0x800B010F + /* AuthType values for SSLExtraCertChainPolicyPara struct */ AUTHTYPE_CLIENT = 1 AUTHTYPE_SERVER = 2 + + /* Checks values for SSLExtraCertChainPolicyPara struct */ + SECURITY_FLAG_IGNORE_REVOCATION = 0x00000080 + SECURITY_FLAG_IGNORE_UNKNOWN_CA = 0x00000100 + SECURITY_FLAG_IGNORE_WRONG_USAGE = 0x00000200 + SECURITY_FLAG_IGNORE_CERT_CN_INVALID = 0x00001000 + SECURITY_FLAG_IGNORE_CERT_DATE_INVALID = 0x00002000 ) var ( @@ -295,6 +426,14 @@ var ( OID_SGC_NETSCAPE = []byte("2.16.840.1.113730.4.1\x00") ) +// Pointer represents a pointer to an arbitrary Windows type. +// +// Pointer-typed fields may point to one of many different types. It's +// up to the caller to provide a pointer to the appropriate type, cast +// to Pointer. The caller must obey the unsafe.Pointer rules while +// doing so. +type Pointer *struct{} + // Invented values to support what package os expects. type Timeval struct { Sec int32 @@ -863,11 +1002,15 @@ type MibIfRow struct { Descr [MAXLEN_IFDESCR]byte } +type CertInfo struct { + // Not implemented +} + type CertContext struct { EncodingType uint32 EncodedCert *byte Length uint32 - CertInfo uintptr + CertInfo *CertInfo Store Handle } @@ -882,12 +1025,16 @@ type CertChainContext struct { RevocationFreshnessTime uint32 } +type CertTrustListInfo struct { + // Not implemented +} + type CertSimpleChain struct { Size uint32 TrustStatus CertTrustStatus NumElements uint32 Elements **CertChainElement - TrustListInfo uintptr + TrustListInfo *CertTrustListInfo HasRevocationFreshnessTime uint32 RevocationFreshnessTime uint32 } @@ -902,14 +1049,18 @@ type CertChainElement struct { ExtendedErrorInfo *uint16 } +type CertRevocationCrlInfo struct { + // Not implemented +} + type CertRevocationInfo struct { Size uint32 RevocationResult uint32 RevocationOid *byte - OidSpecificInfo uintptr + OidSpecificInfo Pointer HasFreshnessTime uint32 FreshnessTime uint32 - CrlInfo uintptr // *CertRevocationCrlInfo + CrlInfo *CertRevocationCrlInfo } type CertTrustStatus struct { @@ -940,7 +1091,7 @@ type CertChainPara struct { type CertChainPolicyPara struct { Size uint32 Flags uint32 - ExtraPolicyPara uintptr + ExtraPolicyPara Pointer } type SSLExtraCertChainPolicyPara struct { @@ -955,7 +1106,7 @@ type CertChainPolicyStatus struct { Error uint32 ChainIndex uint32 ElementIndex uint32 - ExtraPolicyStatus uintptr + ExtraPolicyStatus Pointer } const ( @@ -1302,7 +1453,7 @@ type SmallRect struct { Bottom int16 } -// Used with GetConsoleScreenBuffer to retreive information about a console +// Used with GetConsoleScreenBuffer to retrieve information about a console // screen buffer. See // https://docs.microsoft.com/en-us/windows/console/console-screen-buffer-info-str // for details. @@ -1314,3 +1465,5 @@ type ConsoleScreenBufferInfo struct { Window SmallRect MaximumWindowSize Coord } + +const UNIX_PATH_MAX = 108 // defined in afunix.h diff --git a/vendor/golang.org/x/sys/windows/types_windows_arm.go b/vendor/golang.org/x/sys/windows/types_windows_arm.go new file mode 100644 index 0000000000..74571e3600 --- /dev/null +++ b/vendor/golang.org/x/sys/windows/types_windows_arm.go @@ -0,0 +1,22 @@ +// 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 windows + +type WSAData struct { + Version uint16 + HighVersion uint16 + Description [WSADESCRIPTION_LEN + 1]byte + SystemStatus [WSASYS_STATUS_LEN + 1]byte + MaxSockets uint16 + MaxUdpDg uint16 + VendorInfo *byte +} + +type Servent struct { + Name *byte + Aliases **byte + Port uint16 + Proto *byte +} diff --git a/vendor/golang.org/x/sys/windows/zsyscall_windows.go b/vendor/golang.org/x/sys/windows/zsyscall_windows.go index 2f893d2efc..e4b54e2d92 100644 --- a/vendor/golang.org/x/sys/windows/zsyscall_windows.go +++ b/vendor/golang.org/x/sys/windows/zsyscall_windows.go @@ -1,4 +1,4 @@ -// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT +// Code generated by 'go generate'; DO NOT EDIT. package windows @@ -65,6 +65,7 @@ var ( procChangeServiceConfig2W = modadvapi32.NewProc("ChangeServiceConfig2W") procQueryServiceConfig2W = modadvapi32.NewProc("QueryServiceConfig2W") procEnumServicesStatusExW = modadvapi32.NewProc("EnumServicesStatusExW") + procQueryServiceStatusEx = modadvapi32.NewProc("QueryServiceStatusEx") procGetLastError = modkernel32.NewProc("GetLastError") procLoadLibraryW = modkernel32.NewProc("LoadLibraryW") procLoadLibraryExW = modkernel32.NewProc("LoadLibraryExW") @@ -111,6 +112,7 @@ var ( procGetProcessTimes = modkernel32.NewProc("GetProcessTimes") procDuplicateHandle = modkernel32.NewProc("DuplicateHandle") procWaitForSingleObject = modkernel32.NewProc("WaitForSingleObject") + procWaitForMultipleObjects = modkernel32.NewProc("WaitForMultipleObjects") procGetTempPathW = modkernel32.NewProc("GetTempPathW") procCreatePipe = modkernel32.NewProc("CreatePipe") procGetFileType = modkernel32.NewProc("GetFileType") @@ -178,6 +180,25 @@ var ( procSetEvent = modkernel32.NewProc("SetEvent") procResetEvent = modkernel32.NewProc("ResetEvent") procPulseEvent = modkernel32.NewProc("PulseEvent") + procDefineDosDeviceW = modkernel32.NewProc("DefineDosDeviceW") + procDeleteVolumeMountPointW = modkernel32.NewProc("DeleteVolumeMountPointW") + procFindFirstVolumeW = modkernel32.NewProc("FindFirstVolumeW") + procFindFirstVolumeMountPointW = modkernel32.NewProc("FindFirstVolumeMountPointW") + procFindNextVolumeW = modkernel32.NewProc("FindNextVolumeW") + procFindNextVolumeMountPointW = modkernel32.NewProc("FindNextVolumeMountPointW") + procFindVolumeClose = modkernel32.NewProc("FindVolumeClose") + procFindVolumeMountPointClose = modkernel32.NewProc("FindVolumeMountPointClose") + procGetDriveTypeW = modkernel32.NewProc("GetDriveTypeW") + procGetLogicalDrives = modkernel32.NewProc("GetLogicalDrives") + procGetLogicalDriveStringsW = modkernel32.NewProc("GetLogicalDriveStringsW") + procGetVolumeInformationW = modkernel32.NewProc("GetVolumeInformationW") + procGetVolumeInformationByHandleW = modkernel32.NewProc("GetVolumeInformationByHandleW") + procGetVolumeNameForVolumeMountPointW = modkernel32.NewProc("GetVolumeNameForVolumeMountPointW") + procGetVolumePathNameW = modkernel32.NewProc("GetVolumePathNameW") + procGetVolumePathNamesForVolumeNameW = modkernel32.NewProc("GetVolumePathNamesForVolumeNameW") + procQueryDosDeviceW = modkernel32.NewProc("QueryDosDeviceW") + procSetVolumeLabelW = modkernel32.NewProc("SetVolumeLabelW") + procSetVolumeMountPointW = modkernel32.NewProc("SetVolumeMountPointW") procWSAStartup = modws2_32.NewProc("WSAStartup") procWSACleanup = modws2_32.NewProc("WSACleanup") procWSAIoctl = modws2_32.NewProc("WSAIoctl") @@ -227,6 +248,7 @@ var ( procAllocateAndInitializeSid = modadvapi32.NewProc("AllocateAndInitializeSid") procFreeSid = modadvapi32.NewProc("FreeSid") procEqualSid = modadvapi32.NewProc("EqualSid") + procCheckTokenMembership = modadvapi32.NewProc("CheckTokenMembership") procOpenProcessToken = modadvapi32.NewProc("OpenProcessToken") procGetTokenInformation = modadvapi32.NewProc("GetTokenInformation") procGetUserProfileDirectoryW = moduserenv.NewProc("GetUserProfileDirectoryW") @@ -452,6 +474,18 @@ func EnumServicesStatusEx(mgr Handle, infoLevel uint32, serviceType uint32, serv return } +func QueryServiceStatusEx(service Handle, infoLevel uint32, buff *byte, buffSize uint32, bytesNeeded *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procQueryServiceStatusEx.Addr(), 5, uintptr(service), uintptr(infoLevel), uintptr(unsafe.Pointer(buff)), uintptr(buffSize), uintptr(unsafe.Pointer(bytesNeeded)), 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + func GetLastError() (lasterr error) { r0, _, _ := syscall.Syscall(procGetLastError.Addr(), 0, 0, 0, 0) if r0 != 0 { @@ -1051,6 +1085,25 @@ func WaitForSingleObject(handle Handle, waitMilliseconds uint32) (event uint32, return } +func waitForMultipleObjects(count uint32, handles uintptr, waitAll bool, waitMilliseconds uint32) (event uint32, err error) { + var _p0 uint32 + if waitAll { + _p0 = 1 + } else { + _p0 = 0 + } + r0, _, e1 := syscall.Syscall6(procWaitForMultipleObjects.Addr(), 4, uintptr(count), uintptr(handles), uintptr(_p0), uintptr(waitMilliseconds), 0, 0) + event = uint32(r0) + if event == 0xffffffff { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + func GetTempPath(buflen uint32, buf *uint16) (n uint32, err error) { r0, _, e1 := syscall.Syscall(procGetTempPathW.Addr(), 2, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0) n = uint32(r0) @@ -1843,6 +1896,233 @@ func PulseEvent(event Handle) (err error) { return } +func DefineDosDevice(flags uint32, deviceName *uint16, targetPath *uint16) (err error) { + r1, _, e1 := syscall.Syscall(procDefineDosDeviceW.Addr(), 3, uintptr(flags), uintptr(unsafe.Pointer(deviceName)), uintptr(unsafe.Pointer(targetPath))) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func DeleteVolumeMountPoint(volumeMountPoint *uint16) (err error) { + r1, _, e1 := syscall.Syscall(procDeleteVolumeMountPointW.Addr(), 1, uintptr(unsafe.Pointer(volumeMountPoint)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func FindFirstVolume(volumeName *uint16, bufferLength uint32) (handle Handle, err error) { + r0, _, e1 := syscall.Syscall(procFindFirstVolumeW.Addr(), 2, uintptr(unsafe.Pointer(volumeName)), uintptr(bufferLength), 0) + handle = Handle(r0) + if handle == InvalidHandle { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func FindFirstVolumeMountPoint(rootPathName *uint16, volumeMountPoint *uint16, bufferLength uint32) (handle Handle, err error) { + r0, _, e1 := syscall.Syscall(procFindFirstVolumeMountPointW.Addr(), 3, uintptr(unsafe.Pointer(rootPathName)), uintptr(unsafe.Pointer(volumeMountPoint)), uintptr(bufferLength)) + handle = Handle(r0) + if handle == InvalidHandle { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func FindNextVolume(findVolume Handle, volumeName *uint16, bufferLength uint32) (err error) { + r1, _, e1 := syscall.Syscall(procFindNextVolumeW.Addr(), 3, uintptr(findVolume), uintptr(unsafe.Pointer(volumeName)), uintptr(bufferLength)) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func FindNextVolumeMountPoint(findVolumeMountPoint Handle, volumeMountPoint *uint16, bufferLength uint32) (err error) { + r1, _, e1 := syscall.Syscall(procFindNextVolumeMountPointW.Addr(), 3, uintptr(findVolumeMountPoint), uintptr(unsafe.Pointer(volumeMountPoint)), uintptr(bufferLength)) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func FindVolumeClose(findVolume Handle) (err error) { + r1, _, e1 := syscall.Syscall(procFindVolumeClose.Addr(), 1, uintptr(findVolume), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func FindVolumeMountPointClose(findVolumeMountPoint Handle) (err error) { + r1, _, e1 := syscall.Syscall(procFindVolumeMountPointClose.Addr(), 1, uintptr(findVolumeMountPoint), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetDriveType(rootPathName *uint16) (driveType uint32) { + r0, _, _ := syscall.Syscall(procGetDriveTypeW.Addr(), 1, uintptr(unsafe.Pointer(rootPathName)), 0, 0) + driveType = uint32(r0) + return +} + +func GetLogicalDrives() (drivesBitMask uint32, err error) { + r0, _, e1 := syscall.Syscall(procGetLogicalDrives.Addr(), 0, 0, 0, 0) + drivesBitMask = uint32(r0) + if drivesBitMask == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetLogicalDriveStrings(bufferLength uint32, buffer *uint16) (n uint32, err error) { + r0, _, e1 := syscall.Syscall(procGetLogicalDriveStringsW.Addr(), 2, uintptr(bufferLength), uintptr(unsafe.Pointer(buffer)), 0) + n = uint32(r0) + if n == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetVolumeInformation(rootPathName *uint16, volumeNameBuffer *uint16, volumeNameSize uint32, volumeNameSerialNumber *uint32, maximumComponentLength *uint32, fileSystemFlags *uint32, fileSystemNameBuffer *uint16, fileSystemNameSize uint32) (err error) { + r1, _, e1 := syscall.Syscall9(procGetVolumeInformationW.Addr(), 8, uintptr(unsafe.Pointer(rootPathName)), uintptr(unsafe.Pointer(volumeNameBuffer)), uintptr(volumeNameSize), uintptr(unsafe.Pointer(volumeNameSerialNumber)), uintptr(unsafe.Pointer(maximumComponentLength)), uintptr(unsafe.Pointer(fileSystemFlags)), uintptr(unsafe.Pointer(fileSystemNameBuffer)), uintptr(fileSystemNameSize), 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetVolumeInformationByHandle(file Handle, volumeNameBuffer *uint16, volumeNameSize uint32, volumeNameSerialNumber *uint32, maximumComponentLength *uint32, fileSystemFlags *uint32, fileSystemNameBuffer *uint16, fileSystemNameSize uint32) (err error) { + r1, _, e1 := syscall.Syscall9(procGetVolumeInformationByHandleW.Addr(), 8, uintptr(file), uintptr(unsafe.Pointer(volumeNameBuffer)), uintptr(volumeNameSize), uintptr(unsafe.Pointer(volumeNameSerialNumber)), uintptr(unsafe.Pointer(maximumComponentLength)), uintptr(unsafe.Pointer(fileSystemFlags)), uintptr(unsafe.Pointer(fileSystemNameBuffer)), uintptr(fileSystemNameSize), 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetVolumeNameForVolumeMountPoint(volumeMountPoint *uint16, volumeName *uint16, bufferlength uint32) (err error) { + r1, _, e1 := syscall.Syscall(procGetVolumeNameForVolumeMountPointW.Addr(), 3, uintptr(unsafe.Pointer(volumeMountPoint)), uintptr(unsafe.Pointer(volumeName)), uintptr(bufferlength)) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetVolumePathName(fileName *uint16, volumePathName *uint16, bufferLength uint32) (err error) { + r1, _, e1 := syscall.Syscall(procGetVolumePathNameW.Addr(), 3, uintptr(unsafe.Pointer(fileName)), uintptr(unsafe.Pointer(volumePathName)), uintptr(bufferLength)) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetVolumePathNamesForVolumeName(volumeName *uint16, volumePathNames *uint16, bufferLength uint32, returnLength *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procGetVolumePathNamesForVolumeNameW.Addr(), 4, uintptr(unsafe.Pointer(volumeName)), uintptr(unsafe.Pointer(volumePathNames)), uintptr(bufferLength), uintptr(unsafe.Pointer(returnLength)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func QueryDosDevice(deviceName *uint16, targetPath *uint16, max uint32) (n uint32, err error) { + r0, _, e1 := syscall.Syscall(procQueryDosDeviceW.Addr(), 3, uintptr(unsafe.Pointer(deviceName)), uintptr(unsafe.Pointer(targetPath)), uintptr(max)) + n = uint32(r0) + if n == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func SetVolumeLabel(rootPathName *uint16, volumeName *uint16) (err error) { + r1, _, e1 := syscall.Syscall(procSetVolumeLabelW.Addr(), 2, uintptr(unsafe.Pointer(rootPathName)), uintptr(unsafe.Pointer(volumeName)), 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func SetVolumeMountPoint(volumeMountPoint *uint16, volumeName *uint16) (err error) { + r1, _, e1 := syscall.Syscall(procSetVolumeMountPointW.Addr(), 2, uintptr(unsafe.Pointer(volumeMountPoint)), uintptr(unsafe.Pointer(volumeName)), 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + func WSAStartup(verreq uint32, data *WSAData) (sockerr error) { r0, _, _ := syscall.Syscall(procWSAStartup.Addr(), 2, uintptr(verreq), uintptr(unsafe.Pointer(data)), 0) if r0 != 0 { @@ -2391,6 +2671,18 @@ func EqualSid(sid1 *SID, sid2 *SID) (isEqual bool) { return } +func checkTokenMembership(tokenHandle Token, sidToCheck *SID, isMember *int32) (err error) { + r1, _, e1 := syscall.Syscall(procCheckTokenMembership.Addr(), 3, uintptr(tokenHandle), uintptr(unsafe.Pointer(sidToCheck)), uintptr(unsafe.Pointer(isMember))) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + func OpenProcessToken(h Handle, access uint32, token *Token) (err error) { r1, _, e1 := syscall.Syscall(procOpenProcessToken.Addr(), 3, uintptr(h), uintptr(access), uintptr(unsafe.Pointer(token))) if r1 == 0 { diff --git a/vendor/golang.org/x/text/secure/bidirule/bidirule.go b/vendor/golang.org/x/text/secure/bidirule/bidirule.go new file mode 100644 index 0000000000..e2b70f76c2 --- /dev/null +++ b/vendor/golang.org/x/text/secure/bidirule/bidirule.go @@ -0,0 +1,336 @@ +// Copyright 2016 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 bidirule implements the Bidi Rule defined by RFC 5893. +// +// This package is under development. The API may change without notice and +// without preserving backward compatibility. +package bidirule + +import ( + "errors" + "unicode/utf8" + + "golang.org/x/text/transform" + "golang.org/x/text/unicode/bidi" +) + +// This file contains an implementation of RFC 5893: Right-to-Left Scripts for +// Internationalized Domain Names for Applications (IDNA) +// +// A label is an individual component of a domain name. Labels are usually +// shown separated by dots; for example, the domain name "www.example.com" is +// composed of three labels: "www", "example", and "com". +// +// An RTL label is a label that contains at least one character of class R, AL, +// or AN. An LTR label is any label that is not an RTL label. +// +// A "Bidi domain name" is a domain name that contains at least one RTL label. +// +// The following guarantees can be made based on the above: +// +// o In a domain name consisting of only labels that satisfy the rule, +// the requirements of Section 3 are satisfied. Note that even LTR +// labels and pure ASCII labels have to be tested. +// +// o In a domain name consisting of only LDH labels (as defined in the +// Definitions document [RFC5890]) and labels that satisfy the rule, +// the requirements of Section 3 are satisfied as long as a label +// that starts with an ASCII digit does not come after a +// right-to-left label. +// +// No guarantee is given for other combinations. + +// ErrInvalid indicates a label is invalid according to the Bidi Rule. +var ErrInvalid = errors.New("bidirule: failed Bidi Rule") + +type ruleState uint8 + +const ( + ruleInitial ruleState = iota + ruleLTR + ruleLTRFinal + ruleRTL + ruleRTLFinal + ruleInvalid +) + +type ruleTransition struct { + next ruleState + mask uint16 +} + +var transitions = [...][2]ruleTransition{ + // [2.1] The first character must be a character with Bidi property L, R, or + // AL. If it has the R or AL property, it is an RTL label; if it has the L + // property, it is an LTR label. + ruleInitial: { + {ruleLTRFinal, 1 << bidi.L}, + {ruleRTLFinal, 1< 0; count-- { + p.openers.Remove(p.openers.Front()) + } + break + } + } + sort.Sort(p.pairPositions) + // if we get here, the closing bracket matched no openers + // and gets ignored + } + } +} + +// Bracket pairs within an isolating run sequence are processed as units so +// that both the opening and the closing paired bracket in a pair resolve to +// the same direction. +// +// N0. Process bracket pairs in an isolating run sequence sequentially in +// the logical order of the text positions of the opening paired brackets +// using the logic given below. Within this scope, bidirectional types EN +// and AN are treated as R. +// +// Identify the bracket pairs in the current isolating run sequence +// according to BD16. For each bracket-pair element in the list of pairs of +// text positions: +// +// a Inspect the bidirectional types of the characters enclosed within the +// bracket pair. +// +// b If any strong type (either L or R) matching the embedding direction is +// found, set the type for both brackets in the pair to match the embedding +// direction. +// +// o [ e ] o -> o e e e o +// +// o [ o e ] -> o e o e e +// +// o [ NI e ] -> o e NI e e +// +// c Otherwise, if a strong type (opposite the embedding direction) is +// found, test for adjacent strong types as follows: 1 First, check +// backwards before the opening paired bracket until the first strong type +// (L, R, or sos) is found. If that first preceding strong type is opposite +// the embedding direction, then set the type for both brackets in the pair +// to that type. 2 Otherwise, set the type for both brackets in the pair to +// the embedding direction. +// +// o [ o ] e -> o o o o e +// +// o [ o NI ] o -> o o o NI o o +// +// e [ o ] o -> e e o e o +// +// e [ o ] e -> e e o e e +// +// e ( o [ o ] NI ) e -> e e o o o o NI e e +// +// d Otherwise, do not set the type for the current bracket pair. Note that +// if the enclosed text contains no strong types the paired brackets will +// both resolve to the same level when resolved individually using rules N1 +// and N2. +// +// e ( NI ) o -> e ( NI ) o + +// getStrongTypeN0 maps character's directional code to strong type as required +// by rule N0. +// +// TODO: have separate type for "strong" directionality. +func (p *bracketPairer) getStrongTypeN0(index int) Class { + switch p.codesIsolatedRun[index] { + // in the scope of N0, number types are treated as R + case EN, AN, AL, R: + return R + case L: + return L + default: + return ON + } +} + +// classifyPairContent reports the strong types contained inside a Bracket Pair, +// assuming the given embedding direction. +// +// It returns ON if no strong type is found. If a single strong type is found, +// it returns this this type. Otherwise it returns the embedding direction. +// +// TODO: use separate type for "strong" directionality. +func (p *bracketPairer) classifyPairContent(loc bracketPair, dirEmbed Class) Class { + dirOpposite := ON + for i := loc.opener + 1; i < loc.closer; i++ { + dir := p.getStrongTypeN0(i) + if dir == ON { + continue + } + if dir == dirEmbed { + return dir // type matching embedding direction found + } + dirOpposite = dir + } + // return ON if no strong type found, or class opposite to dirEmbed + return dirOpposite +} + +// classBeforePair determines which strong types are present before a Bracket +// Pair. Return R or L if strong type found, otherwise ON. +func (p *bracketPairer) classBeforePair(loc bracketPair) Class { + for i := loc.opener - 1; i >= 0; i-- { + if dir := p.getStrongTypeN0(i); dir != ON { + return dir + } + } + // no strong types found, return sos + return p.sos +} + +// assignBracketType implements rule N0 for a single bracket pair. +func (p *bracketPairer) assignBracketType(loc bracketPair, dirEmbed Class, initialTypes []Class) { + // rule "N0, a", inspect contents of pair + dirPair := p.classifyPairContent(loc, dirEmbed) + + // dirPair is now L, R, or N (no strong type found) + + // the following logical tests are performed out of order compared to + // the statement of the rules but yield the same results + if dirPair == ON { + return // case "d" - nothing to do + } + + if dirPair != dirEmbed { + // case "c": strong type found, opposite - check before (c.1) + dirPair = p.classBeforePair(loc) + if dirPair == dirEmbed || dirPair == ON { + // no strong opposite type found before - use embedding (c.2) + dirPair = dirEmbed + } + } + // else: case "b", strong type found matching embedding, + // no explicit action needed, as dirPair is already set to embedding + // direction + + // set the bracket types to the type found + p.setBracketsToType(loc, dirPair, initialTypes) +} + +func (p *bracketPairer) setBracketsToType(loc bracketPair, dirPair Class, initialTypes []Class) { + p.codesIsolatedRun[loc.opener] = dirPair + p.codesIsolatedRun[loc.closer] = dirPair + + for i := loc.opener + 1; i < loc.closer; i++ { + index := p.indexes[i] + if initialTypes[index] != NSM { + break + } + p.codesIsolatedRun[i] = dirPair + } + + for i := loc.closer + 1; i < len(p.indexes); i++ { + index := p.indexes[i] + if initialTypes[index] != NSM { + break + } + p.codesIsolatedRun[i] = dirPair + } +} + +// resolveBrackets implements rule N0 for a list of pairs. +func (p *bracketPairer) resolveBrackets(dirEmbed Class, initialTypes []Class) { + for _, loc := range p.pairPositions { + p.assignBracketType(loc, dirEmbed, initialTypes) + } +} diff --git a/vendor/golang.org/x/text/unicode/bidi/core.go b/vendor/golang.org/x/text/unicode/bidi/core.go new file mode 100644 index 0000000000..d4c1399f0d --- /dev/null +++ b/vendor/golang.org/x/text/unicode/bidi/core.go @@ -0,0 +1,1058 @@ +// 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 bidi + +import "log" + +// This implementation is a port based on the reference implementation found at: +// http://www.unicode.org/Public/PROGRAMS/BidiReferenceJava/ +// +// described in Unicode Bidirectional Algorithm (UAX #9). +// +// Input: +// There are two levels of input to the algorithm, since clients may prefer to +// supply some information from out-of-band sources rather than relying on the +// default behavior. +// +// - Bidi class array +// - Bidi class array, with externally supplied base line direction +// +// Output: +// Output is separated into several stages: +// +// - levels array over entire paragraph +// - reordering array over entire paragraph +// - levels array over line +// - reordering array over line +// +// Note that for conformance to the Unicode Bidirectional Algorithm, +// implementations are only required to generate correct reordering and +// character directionality (odd or even levels) over a line. Generating +// identical level arrays over a line is not required. Bidi explicit format +// codes (LRE, RLE, LRO, RLO, PDF) and BN can be assigned arbitrary levels and +// positions as long as the rest of the input is properly reordered. +// +// As the algorithm is defined to operate on a single paragraph at a time, this +// implementation is written to handle single paragraphs. Thus rule P1 is +// presumed by this implementation-- the data provided to the implementation is +// assumed to be a single paragraph, and either contains no 'B' codes, or a +// single 'B' code at the end of the input. 'B' is allowed as input to +// illustrate how the algorithm assigns it a level. +// +// Also note that rules L3 and L4 depend on the rendering engine that uses the +// result of the bidi algorithm. This implementation assumes that the rendering +// engine expects combining marks in visual order (e.g. to the left of their +// base character in RTL runs) and that it adjusts the glyphs used to render +// mirrored characters that are in RTL runs so that they render appropriately. + +// level is the embedding level of a character. Even embedding levels indicate +// left-to-right order and odd levels indicate right-to-left order. The special +// level of -1 is reserved for undefined order. +type level int8 + +const implicitLevel level = -1 + +// in returns if x is equal to any of the values in set. +func (c Class) in(set ...Class) bool { + for _, s := range set { + if c == s { + return true + } + } + return false +} + +// A paragraph contains the state of a paragraph. +type paragraph struct { + initialTypes []Class + + // Arrays of properties needed for paired bracket evaluation in N0 + pairTypes []bracketType // paired Bracket types for paragraph + pairValues []rune // rune for opening bracket or pbOpen and pbClose; 0 for pbNone + + embeddingLevel level // default: = implicitLevel; + + // at the paragraph levels + resultTypes []Class + resultLevels []level + + // Index of matching PDI for isolate initiator characters. For other + // characters, the value of matchingPDI will be set to -1. For isolate + // initiators with no matching PDI, matchingPDI will be set to the length of + // the input string. + matchingPDI []int + + // Index of matching isolate initiator for PDI characters. For other + // characters, and for PDIs with no matching isolate initiator, the value of + // matchingIsolateInitiator will be set to -1. + matchingIsolateInitiator []int +} + +// newParagraph initializes a paragraph. The user needs to supply a few arrays +// corresponding to the preprocessed text input. The types correspond to the +// Unicode BiDi classes for each rune. pairTypes indicates the bracket type for +// each rune. pairValues provides a unique bracket class identifier for each +// rune (suggested is the rune of the open bracket for opening and matching +// close brackets, after normalization). The embedding levels are optional, but +// may be supplied to encode embedding levels of styled text. +// +// TODO: return an error. +func newParagraph(types []Class, pairTypes []bracketType, pairValues []rune, levels level) *paragraph { + validateTypes(types) + validatePbTypes(pairTypes) + validatePbValues(pairValues, pairTypes) + validateParagraphEmbeddingLevel(levels) + + p := ¶graph{ + initialTypes: append([]Class(nil), types...), + embeddingLevel: levels, + + pairTypes: pairTypes, + pairValues: pairValues, + + resultTypes: append([]Class(nil), types...), + } + p.run() + return p +} + +func (p *paragraph) Len() int { return len(p.initialTypes) } + +// The algorithm. Does not include line-based processing (Rules L1, L2). +// These are applied later in the line-based phase of the algorithm. +func (p *paragraph) run() { + p.determineMatchingIsolates() + + // 1) determining the paragraph level + // Rule P1 is the requirement for entering this algorithm. + // Rules P2, P3. + // If no externally supplied paragraph embedding level, use default. + if p.embeddingLevel == implicitLevel { + p.embeddingLevel = p.determineParagraphEmbeddingLevel(0, p.Len()) + } + + // Initialize result levels to paragraph embedding level. + p.resultLevels = make([]level, p.Len()) + setLevels(p.resultLevels, p.embeddingLevel) + + // 2) Explicit levels and directions + // Rules X1-X8. + p.determineExplicitEmbeddingLevels() + + // Rule X9. + // We do not remove the embeddings, the overrides, the PDFs, and the BNs + // from the string explicitly. But they are not copied into isolating run + // sequences when they are created, so they are removed for all + // practical purposes. + + // Rule X10. + // Run remainder of algorithm one isolating run sequence at a time + for _, seq := range p.determineIsolatingRunSequences() { + // 3) resolving weak types + // Rules W1-W7. + seq.resolveWeakTypes() + + // 4a) resolving paired brackets + // Rule N0 + resolvePairedBrackets(seq) + + // 4b) resolving neutral types + // Rules N1-N3. + seq.resolveNeutralTypes() + + // 5) resolving implicit embedding levels + // Rules I1, I2. + seq.resolveImplicitLevels() + + // Apply the computed levels and types + seq.applyLevelsAndTypes() + } + + // Assign appropriate levels to 'hide' LREs, RLEs, LROs, RLOs, PDFs, and + // BNs. This is for convenience, so the resulting level array will have + // a value for every character. + p.assignLevelsToCharactersRemovedByX9() +} + +// determineMatchingIsolates determines the matching PDI for each isolate +// initiator and vice versa. +// +// Definition BD9. +// +// At the end of this function: +// +// - The member variable matchingPDI is set to point to the index of the +// matching PDI character for each isolate initiator character. If there is +// no matching PDI, it is set to the length of the input text. For other +// characters, it is set to -1. +// - The member variable matchingIsolateInitiator is set to point to the +// index of the matching isolate initiator character for each PDI character. +// If there is no matching isolate initiator, or the character is not a PDI, +// it is set to -1. +func (p *paragraph) determineMatchingIsolates() { + p.matchingPDI = make([]int, p.Len()) + p.matchingIsolateInitiator = make([]int, p.Len()) + + for i := range p.matchingIsolateInitiator { + p.matchingIsolateInitiator[i] = -1 + } + + for i := range p.matchingPDI { + p.matchingPDI[i] = -1 + + if t := p.resultTypes[i]; t.in(LRI, RLI, FSI) { + depthCounter := 1 + for j := i + 1; j < p.Len(); j++ { + if u := p.resultTypes[j]; u.in(LRI, RLI, FSI) { + depthCounter++ + } else if u == PDI { + if depthCounter--; depthCounter == 0 { + p.matchingPDI[i] = j + p.matchingIsolateInitiator[j] = i + break + } + } + } + if p.matchingPDI[i] == -1 { + p.matchingPDI[i] = p.Len() + } + } + } +} + +// determineParagraphEmbeddingLevel reports the resolved paragraph direction of +// the substring limited by the given range [start, end). +// +// Determines the paragraph level based on rules P2, P3. This is also used +// in rule X5c to find if an FSI should resolve to LRI or RLI. +func (p *paragraph) determineParagraphEmbeddingLevel(start, end int) level { + var strongType Class = unknownClass + + // Rule P2. + for i := start; i < end; i++ { + if t := p.resultTypes[i]; t.in(L, AL, R) { + strongType = t + break + } else if t.in(FSI, LRI, RLI) { + i = p.matchingPDI[i] // skip over to the matching PDI + if i > end { + log.Panic("assert (i <= end)") + } + } + } + // Rule P3. + switch strongType { + case unknownClass: // none found + // default embedding level when no strong types found is 0. + return 0 + case L: + return 0 + default: // AL, R + return 1 + } +} + +const maxDepth = 125 + +// This stack will store the embedding levels and override and isolated +// statuses +type directionalStatusStack struct { + stackCounter int + embeddingLevelStack [maxDepth + 1]level + overrideStatusStack [maxDepth + 1]Class + isolateStatusStack [maxDepth + 1]bool +} + +func (s *directionalStatusStack) empty() { s.stackCounter = 0 } +func (s *directionalStatusStack) pop() { s.stackCounter-- } +func (s *directionalStatusStack) depth() int { return s.stackCounter } + +func (s *directionalStatusStack) push(level level, overrideStatus Class, isolateStatus bool) { + s.embeddingLevelStack[s.stackCounter] = level + s.overrideStatusStack[s.stackCounter] = overrideStatus + s.isolateStatusStack[s.stackCounter] = isolateStatus + s.stackCounter++ +} + +func (s *directionalStatusStack) lastEmbeddingLevel() level { + return s.embeddingLevelStack[s.stackCounter-1] +} + +func (s *directionalStatusStack) lastDirectionalOverrideStatus() Class { + return s.overrideStatusStack[s.stackCounter-1] +} + +func (s *directionalStatusStack) lastDirectionalIsolateStatus() bool { + return s.isolateStatusStack[s.stackCounter-1] +} + +// Determine explicit levels using rules X1 - X8 +func (p *paragraph) determineExplicitEmbeddingLevels() { + var stack directionalStatusStack + var overflowIsolateCount, overflowEmbeddingCount, validIsolateCount int + + // Rule X1. + stack.push(p.embeddingLevel, ON, false) + + for i, t := range p.resultTypes { + // Rules X2, X3, X4, X5, X5a, X5b, X5c + switch t { + case RLE, LRE, RLO, LRO, RLI, LRI, FSI: + isIsolate := t.in(RLI, LRI, FSI) + isRTL := t.in(RLE, RLO, RLI) + + // override if this is an FSI that resolves to RLI + if t == FSI { + isRTL = (p.determineParagraphEmbeddingLevel(i+1, p.matchingPDI[i]) == 1) + } + if isIsolate { + p.resultLevels[i] = stack.lastEmbeddingLevel() + if stack.lastDirectionalOverrideStatus() != ON { + p.resultTypes[i] = stack.lastDirectionalOverrideStatus() + } + } + + var newLevel level + if isRTL { + // least greater odd + newLevel = (stack.lastEmbeddingLevel() + 1) | 1 + } else { + // least greater even + newLevel = (stack.lastEmbeddingLevel() + 2) &^ 1 + } + + if newLevel <= maxDepth && overflowIsolateCount == 0 && overflowEmbeddingCount == 0 { + if isIsolate { + validIsolateCount++ + } + // Push new embedding level, override status, and isolated + // status. + // No check for valid stack counter, since the level check + // suffices. + switch t { + case LRO: + stack.push(newLevel, L, isIsolate) + case RLO: + stack.push(newLevel, R, isIsolate) + default: + stack.push(newLevel, ON, isIsolate) + } + // Not really part of the spec + if !isIsolate { + p.resultLevels[i] = newLevel + } + } else { + // This is an invalid explicit formatting character, + // so apply the "Otherwise" part of rules X2-X5b. + if isIsolate { + overflowIsolateCount++ + } else { // !isIsolate + if overflowIsolateCount == 0 { + overflowEmbeddingCount++ + } + } + } + + // Rule X6a + case PDI: + if overflowIsolateCount > 0 { + overflowIsolateCount-- + } else if validIsolateCount == 0 { + // do nothing + } else { + overflowEmbeddingCount = 0 + for !stack.lastDirectionalIsolateStatus() { + stack.pop() + } + stack.pop() + validIsolateCount-- + } + p.resultLevels[i] = stack.lastEmbeddingLevel() + + // Rule X7 + case PDF: + // Not really part of the spec + p.resultLevels[i] = stack.lastEmbeddingLevel() + + if overflowIsolateCount > 0 { + // do nothing + } else if overflowEmbeddingCount > 0 { + overflowEmbeddingCount-- + } else if !stack.lastDirectionalIsolateStatus() && stack.depth() >= 2 { + stack.pop() + } + + case B: // paragraph separator. + // Rule X8. + + // These values are reset for clarity, in this implementation B + // can only occur as the last code in the array. + stack.empty() + overflowIsolateCount = 0 + overflowEmbeddingCount = 0 + validIsolateCount = 0 + p.resultLevels[i] = p.embeddingLevel + + default: + p.resultLevels[i] = stack.lastEmbeddingLevel() + if stack.lastDirectionalOverrideStatus() != ON { + p.resultTypes[i] = stack.lastDirectionalOverrideStatus() + } + } + } +} + +type isolatingRunSequence struct { + p *paragraph + + indexes []int // indexes to the original string + + types []Class // type of each character using the index + resolvedLevels []level // resolved levels after application of rules + level level + sos, eos Class +} + +func (i *isolatingRunSequence) Len() int { return len(i.indexes) } + +func maxLevel(a, b level) level { + if a > b { + return a + } + return b +} + +// Rule X10, second bullet: Determine the start-of-sequence (sos) and end-of-sequence (eos) types, +// either L or R, for each isolating run sequence. +func (p *paragraph) isolatingRunSequence(indexes []int) *isolatingRunSequence { + length := len(indexes) + types := make([]Class, length) + for i, x := range indexes { + types[i] = p.resultTypes[x] + } + + // assign level, sos and eos + prevChar := indexes[0] - 1 + for prevChar >= 0 && isRemovedByX9(p.initialTypes[prevChar]) { + prevChar-- + } + prevLevel := p.embeddingLevel + if prevChar >= 0 { + prevLevel = p.resultLevels[prevChar] + } + + var succLevel level + lastType := types[length-1] + if lastType.in(LRI, RLI, FSI) { + succLevel = p.embeddingLevel + } else { + // the first character after the end of run sequence + limit := indexes[length-1] + 1 + for ; limit < p.Len() && isRemovedByX9(p.initialTypes[limit]); limit++ { + + } + succLevel = p.embeddingLevel + if limit < p.Len() { + succLevel = p.resultLevels[limit] + } + } + level := p.resultLevels[indexes[0]] + return &isolatingRunSequence{ + p: p, + indexes: indexes, + types: types, + level: level, + sos: typeForLevel(maxLevel(prevLevel, level)), + eos: typeForLevel(maxLevel(succLevel, level)), + } +} + +// Resolving weak types Rules W1-W7. +// +// Note that some weak types (EN, AN) remain after this processing is +// complete. +func (s *isolatingRunSequence) resolveWeakTypes() { + + // on entry, only these types remain + s.assertOnly(L, R, AL, EN, ES, ET, AN, CS, B, S, WS, ON, NSM, LRI, RLI, FSI, PDI) + + // Rule W1. + // Changes all NSMs. + preceedingCharacterType := s.sos + for i, t := range s.types { + if t == NSM { + s.types[i] = preceedingCharacterType + } else { + if t.in(LRI, RLI, FSI, PDI) { + preceedingCharacterType = ON + } + preceedingCharacterType = t + } + } + + // Rule W2. + // EN does not change at the start of the run, because sos != AL. + for i, t := range s.types { + if t == EN { + for j := i - 1; j >= 0; j-- { + if t := s.types[j]; t.in(L, R, AL) { + if t == AL { + s.types[i] = AN + } + break + } + } + } + } + + // Rule W3. + for i, t := range s.types { + if t == AL { + s.types[i] = R + } + } + + // Rule W4. + // Since there must be values on both sides for this rule to have an + // effect, the scan skips the first and last value. + // + // Although the scan proceeds left to right, and changes the type + // values in a way that would appear to affect the computations + // later in the scan, there is actually no problem. A change in the + // current value can only affect the value to its immediate right, + // and only affect it if it is ES or CS. But the current value can + // only change if the value to its right is not ES or CS. Thus + // either the current value will not change, or its change will have + // no effect on the remainder of the analysis. + + for i := 1; i < s.Len()-1; i++ { + t := s.types[i] + if t == ES || t == CS { + prevSepType := s.types[i-1] + succSepType := s.types[i+1] + if prevSepType == EN && succSepType == EN { + s.types[i] = EN + } else if s.types[i] == CS && prevSepType == AN && succSepType == AN { + s.types[i] = AN + } + } + } + + // Rule W5. + for i, t := range s.types { + if t == ET { + // locate end of sequence + runStart := i + runEnd := s.findRunLimit(runStart, ET) + + // check values at ends of sequence + t := s.sos + if runStart > 0 { + t = s.types[runStart-1] + } + if t != EN { + t = s.eos + if runEnd < len(s.types) { + t = s.types[runEnd] + } + } + if t == EN { + setTypes(s.types[runStart:runEnd], EN) + } + // continue at end of sequence + i = runEnd + } + } + + // Rule W6. + for i, t := range s.types { + if t.in(ES, ET, CS) { + s.types[i] = ON + } + } + + // Rule W7. + for i, t := range s.types { + if t == EN { + // set default if we reach start of run + prevStrongType := s.sos + for j := i - 1; j >= 0; j-- { + t = s.types[j] + if t == L || t == R { // AL's have been changed to R + prevStrongType = t + break + } + } + if prevStrongType == L { + s.types[i] = L + } + } + } +} + +// 6) resolving neutral types Rules N1-N2. +func (s *isolatingRunSequence) resolveNeutralTypes() { + + // on entry, only these types can be in resultTypes + s.assertOnly(L, R, EN, AN, B, S, WS, ON, RLI, LRI, FSI, PDI) + + for i, t := range s.types { + switch t { + case WS, ON, B, S, RLI, LRI, FSI, PDI: + // find bounds of run of neutrals + runStart := i + runEnd := s.findRunLimit(runStart, B, S, WS, ON, RLI, LRI, FSI, PDI) + + // determine effective types at ends of run + var leadType, trailType Class + + // Note that the character found can only be L, R, AN, or + // EN. + if runStart == 0 { + leadType = s.sos + } else { + leadType = s.types[runStart-1] + if leadType.in(AN, EN) { + leadType = R + } + } + if runEnd == len(s.types) { + trailType = s.eos + } else { + trailType = s.types[runEnd] + if trailType.in(AN, EN) { + trailType = R + } + } + + var resolvedType Class + if leadType == trailType { + // Rule N1. + resolvedType = leadType + } else { + // Rule N2. + // Notice the embedding level of the run is used, not + // the paragraph embedding level. + resolvedType = typeForLevel(s.level) + } + + setTypes(s.types[runStart:runEnd], resolvedType) + + // skip over run of (former) neutrals + i = runEnd + } + } +} + +func setLevels(levels []level, newLevel level) { + for i := range levels { + levels[i] = newLevel + } +} + +func setTypes(types []Class, newType Class) { + for i := range types { + types[i] = newType + } +} + +// 7) resolving implicit embedding levels Rules I1, I2. +func (s *isolatingRunSequence) resolveImplicitLevels() { + + // on entry, only these types can be in resultTypes + s.assertOnly(L, R, EN, AN) + + s.resolvedLevels = make([]level, len(s.types)) + setLevels(s.resolvedLevels, s.level) + + if (s.level & 1) == 0 { // even level + for i, t := range s.types { + // Rule I1. + if t == L { + // no change + } else if t == R { + s.resolvedLevels[i] += 1 + } else { // t == AN || t == EN + s.resolvedLevels[i] += 2 + } + } + } else { // odd level + for i, t := range s.types { + // Rule I2. + if t == R { + // no change + } else { // t == L || t == AN || t == EN + s.resolvedLevels[i] += 1 + } + } + } +} + +// Applies the levels and types resolved in rules W1-I2 to the +// resultLevels array. +func (s *isolatingRunSequence) applyLevelsAndTypes() { + for i, x := range s.indexes { + s.p.resultTypes[x] = s.types[i] + s.p.resultLevels[x] = s.resolvedLevels[i] + } +} + +// Return the limit of the run consisting only of the types in validSet +// starting at index. This checks the value at index, and will return +// index if that value is not in validSet. +func (s *isolatingRunSequence) findRunLimit(index int, validSet ...Class) int { +loop: + for ; index < len(s.types); index++ { + t := s.types[index] + for _, valid := range validSet { + if t == valid { + continue loop + } + } + return index // didn't find a match in validSet + } + return len(s.types) +} + +// Algorithm validation. Assert that all values in types are in the +// provided set. +func (s *isolatingRunSequence) assertOnly(codes ...Class) { +loop: + for i, t := range s.types { + for _, c := range codes { + if t == c { + continue loop + } + } + log.Panicf("invalid bidi code %v present in assertOnly at position %d", t, s.indexes[i]) + } +} + +// determineLevelRuns returns an array of level runs. Each level run is +// described as an array of indexes into the input string. +// +// Determines the level runs. Rule X9 will be applied in determining the +// runs, in the way that makes sure the characters that are supposed to be +// removed are not included in the runs. +func (p *paragraph) determineLevelRuns() [][]int { + run := []int{} + allRuns := [][]int{} + currentLevel := implicitLevel + + for i := range p.initialTypes { + if !isRemovedByX9(p.initialTypes[i]) { + if p.resultLevels[i] != currentLevel { + // we just encountered a new run; wrap up last run + if currentLevel >= 0 { // only wrap it up if there was a run + allRuns = append(allRuns, run) + run = nil + } + // Start new run + currentLevel = p.resultLevels[i] + } + run = append(run, i) + } + } + // Wrap up the final run, if any + if len(run) > 0 { + allRuns = append(allRuns, run) + } + return allRuns +} + +// Definition BD13. Determine isolating run sequences. +func (p *paragraph) determineIsolatingRunSequences() []*isolatingRunSequence { + levelRuns := p.determineLevelRuns() + + // Compute the run that each character belongs to + runForCharacter := make([]int, p.Len()) + for i, run := range levelRuns { + for _, index := range run { + runForCharacter[index] = i + } + } + + sequences := []*isolatingRunSequence{} + + var currentRunSequence []int + + for _, run := range levelRuns { + first := run[0] + if p.initialTypes[first] != PDI || p.matchingIsolateInitiator[first] == -1 { + currentRunSequence = nil + // int run = i; + for { + // Copy this level run into currentRunSequence + currentRunSequence = append(currentRunSequence, run...) + + last := currentRunSequence[len(currentRunSequence)-1] + lastT := p.initialTypes[last] + if lastT.in(LRI, RLI, FSI) && p.matchingPDI[last] != p.Len() { + run = levelRuns[runForCharacter[p.matchingPDI[last]]] + } else { + break + } + } + sequences = append(sequences, p.isolatingRunSequence(currentRunSequence)) + } + } + return sequences +} + +// Assign level information to characters removed by rule X9. This is for +// ease of relating the level information to the original input data. Note +// that the levels assigned to these codes are arbitrary, they're chosen so +// as to avoid breaking level runs. +func (p *paragraph) assignLevelsToCharactersRemovedByX9() { + for i, t := range p.initialTypes { + if t.in(LRE, RLE, LRO, RLO, PDF, BN) { + p.resultTypes[i] = t + p.resultLevels[i] = -1 + } + } + // now propagate forward the levels information (could have + // propagated backward, the main thing is not to introduce a level + // break where one doesn't already exist). + + if p.resultLevels[0] == -1 { + p.resultLevels[0] = p.embeddingLevel + } + for i := 1; i < len(p.initialTypes); i++ { + if p.resultLevels[i] == -1 { + p.resultLevels[i] = p.resultLevels[i-1] + } + } + // Embedding information is for informational purposes only so need not be + // adjusted. +} + +// +// Output +// + +// getLevels computes levels array breaking lines at offsets in linebreaks. +// Rule L1. +// +// The linebreaks array must include at least one value. The values must be +// in strictly increasing order (no duplicates) between 1 and the length of +// the text, inclusive. The last value must be the length of the text. +func (p *paragraph) getLevels(linebreaks []int) []level { + // Note that since the previous processing has removed all + // P, S, and WS values from resultTypes, the values referred to + // in these rules are the initial types, before any processing + // has been applied (including processing of overrides). + // + // This example implementation has reinserted explicit format codes + // and BN, in order that the levels array correspond to the + // initial text. Their final placement is not normative. + // These codes are treated like WS in this implementation, + // so they don't interrupt sequences of WS. + + validateLineBreaks(linebreaks, p.Len()) + + result := append([]level(nil), p.resultLevels...) + + // don't worry about linebreaks since if there is a break within + // a series of WS values preceding S, the linebreak itself + // causes the reset. + for i, t := range p.initialTypes { + if t.in(B, S) { + // Rule L1, clauses one and two. + result[i] = p.embeddingLevel + + // Rule L1, clause three. + for j := i - 1; j >= 0; j-- { + if isWhitespace(p.initialTypes[j]) { // including format codes + result[j] = p.embeddingLevel + } else { + break + } + } + } + } + + // Rule L1, clause four. + start := 0 + for _, limit := range linebreaks { + for j := limit - 1; j >= start; j-- { + if isWhitespace(p.initialTypes[j]) { // including format codes + result[j] = p.embeddingLevel + } else { + break + } + } + start = limit + } + + return result +} + +// getReordering returns the reordering of lines from a visual index to a +// logical index for line breaks at the given offsets. +// +// Lines are concatenated from left to right. So for example, the fifth +// character from the left on the third line is +// +// getReordering(linebreaks)[linebreaks[1] + 4] +// +// (linebreaks[1] is the position after the last character of the second +// line, which is also the index of the first character on the third line, +// and adding four gets the fifth character from the left). +// +// The linebreaks array must include at least one value. The values must be +// in strictly increasing order (no duplicates) between 1 and the length of +// the text, inclusive. The last value must be the length of the text. +func (p *paragraph) getReordering(linebreaks []int) []int { + validateLineBreaks(linebreaks, p.Len()) + + return computeMultilineReordering(p.getLevels(linebreaks), linebreaks) +} + +// Return multiline reordering array for a given level array. Reordering +// does not occur across a line break. +func computeMultilineReordering(levels []level, linebreaks []int) []int { + result := make([]int, len(levels)) + + start := 0 + for _, limit := range linebreaks { + tempLevels := make([]level, limit-start) + copy(tempLevels, levels[start:]) + + for j, order := range computeReordering(tempLevels) { + result[start+j] = order + start + } + start = limit + } + return result +} + +// Return reordering array for a given level array. This reorders a single +// line. The reordering is a visual to logical map. For example, the +// leftmost char is string.charAt(order[0]). Rule L2. +func computeReordering(levels []level) []int { + result := make([]int, len(levels)) + // initialize order + for i := range result { + result[i] = i + } + + // locate highest level found on line. + // Note the rules say text, but no reordering across line bounds is + // performed, so this is sufficient. + highestLevel := level(0) + lowestOddLevel := level(maxDepth + 2) + for _, level := range levels { + if level > highestLevel { + highestLevel = level + } + if level&1 != 0 && level < lowestOddLevel { + lowestOddLevel = level + } + } + + for level := highestLevel; level >= lowestOddLevel; level-- { + for i := 0; i < len(levels); i++ { + if levels[i] >= level { + // find range of text at or above this level + start := i + limit := i + 1 + for limit < len(levels) && levels[limit] >= level { + limit++ + } + + for j, k := start, limit-1; j < k; j, k = j+1, k-1 { + result[j], result[k] = result[k], result[j] + } + // skip to end of level run + i = limit + } + } + } + + return result +} + +// isWhitespace reports whether the type is considered a whitespace type for the +// line break rules. +func isWhitespace(c Class) bool { + switch c { + case LRE, RLE, LRO, RLO, PDF, LRI, RLI, FSI, PDI, BN, WS: + return true + } + return false +} + +// isRemovedByX9 reports whether the type is one of the types removed in X9. +func isRemovedByX9(c Class) bool { + switch c { + case LRE, RLE, LRO, RLO, PDF, BN: + return true + } + return false +} + +// typeForLevel reports the strong type (L or R) corresponding to the level. +func typeForLevel(level level) Class { + if (level & 0x1) == 0 { + return L + } + return R +} + +// TODO: change validation to not panic + +func validateTypes(types []Class) { + if len(types) == 0 { + log.Panic("types is null") + } + for i, t := range types[:len(types)-1] { + if t == B { + log.Panicf("B type before end of paragraph at index: %d", i) + } + } +} + +func validateParagraphEmbeddingLevel(embeddingLevel level) { + if embeddingLevel != implicitLevel && + embeddingLevel != 0 && + embeddingLevel != 1 { + log.Panicf("illegal paragraph embedding level: %d", embeddingLevel) + } +} + +func validateLineBreaks(linebreaks []int, textLength int) { + prev := 0 + for i, next := range linebreaks { + if next <= prev { + log.Panicf("bad linebreak: %d at index: %d", next, i) + } + prev = next + } + if prev != textLength { + log.Panicf("last linebreak was %d, want %d", prev, textLength) + } +} + +func validatePbTypes(pairTypes []bracketType) { + if len(pairTypes) == 0 { + log.Panic("pairTypes is null") + } + for i, pt := range pairTypes { + switch pt { + case bpNone, bpOpen, bpClose: + default: + log.Panicf("illegal pairType value at %d: %v", i, pairTypes[i]) + } + } +} + +func validatePbValues(pairValues []rune, pairTypes []bracketType) { + if pairValues == nil { + log.Panic("pairValues is null") + } + if len(pairTypes) != len(pairValues) { + log.Panic("pairTypes is different length from pairValues") + } +} diff --git a/vendor/golang.org/x/text/unicode/bidi/prop.go b/vendor/golang.org/x/text/unicode/bidi/prop.go new file mode 100644 index 0000000000..7c9484e1f5 --- /dev/null +++ b/vendor/golang.org/x/text/unicode/bidi/prop.go @@ -0,0 +1,206 @@ +// Copyright 2016 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 bidi + +import "unicode/utf8" + +// Properties provides access to BiDi properties of runes. +type Properties struct { + entry uint8 + last uint8 +} + +var trie = newBidiTrie(0) + +// TODO: using this for bidirule reduces the running time by about 5%. Consider +// if this is worth exposing or if we can find a way to speed up the Class +// method. +// +// // CompactClass is like Class, but maps all of the BiDi control classes +// // (LRO, RLO, LRE, RLE, PDF, LRI, RLI, FSI, PDI) to the class Control. +// func (p Properties) CompactClass() Class { +// return Class(p.entry & 0x0F) +// } + +// Class returns the Bidi class for p. +func (p Properties) Class() Class { + c := Class(p.entry & 0x0F) + if c == Control { + c = controlByteToClass[p.last&0xF] + } + return c +} + +// IsBracket reports whether the rune is a bracket. +func (p Properties) IsBracket() bool { return p.entry&0xF0 != 0 } + +// IsOpeningBracket reports whether the rune is an opening bracket. +// IsBracket must return true. +func (p Properties) IsOpeningBracket() bool { return p.entry&openMask != 0 } + +// TODO: find a better API and expose. +func (p Properties) reverseBracket(r rune) rune { + return xorMasks[p.entry>>xorMaskShift] ^ r +} + +var controlByteToClass = [16]Class{ + 0xD: LRO, // U+202D LeftToRightOverride, + 0xE: RLO, // U+202E RightToLeftOverride, + 0xA: LRE, // U+202A LeftToRightEmbedding, + 0xB: RLE, // U+202B RightToLeftEmbedding, + 0xC: PDF, // U+202C PopDirectionalFormat, + 0x6: LRI, // U+2066 LeftToRightIsolate, + 0x7: RLI, // U+2067 RightToLeftIsolate, + 0x8: FSI, // U+2068 FirstStrongIsolate, + 0x9: PDI, // U+2069 PopDirectionalIsolate, +} + +// LookupRune returns properties for r. +func LookupRune(r rune) (p Properties, size int) { + var buf [4]byte + n := utf8.EncodeRune(buf[:], r) + return Lookup(buf[:n]) +} + +// TODO: these lookup methods are based on the generated trie code. The returned +// sizes have slightly different semantics from the generated code, in that it +// always returns size==1 for an illegal UTF-8 byte (instead of the length +// of the maximum invalid subsequence). Most Transformers, like unicode/norm, +// leave invalid UTF-8 untouched, in which case it has performance benefits to +// do so (without changing the semantics). Bidi requires the semantics used here +// for the bidirule implementation to be compatible with the Go semantics. +// They ultimately should perhaps be adopted by all trie implementations, for +// convenience sake. +// This unrolled code also boosts performance of the secure/bidirule package by +// about 30%. +// So, to remove this code: +// - add option to trie generator to define return type. +// - always return 1 byte size for ill-formed UTF-8 runes. + +// Lookup returns properties for the first rune in s and the width in bytes of +// its encoding. The size will be 0 if s does not hold enough bytes to complete +// the encoding. +func Lookup(s []byte) (p Properties, sz int) { + c0 := s[0] + switch { + case c0 < 0x80: // is ASCII + return Properties{entry: bidiValues[c0]}, 1 + case c0 < 0xC2: + return Properties{}, 1 + case c0 < 0xE0: // 2-byte UTF-8 + if len(s) < 2 { + return Properties{}, 0 + } + i := bidiIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return Properties{}, 1 + } + return Properties{entry: trie.lookupValue(uint32(i), c1)}, 2 + case c0 < 0xF0: // 3-byte UTF-8 + if len(s) < 3 { + return Properties{}, 0 + } + i := bidiIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return Properties{}, 1 + } + o := uint32(i)<<6 + uint32(c1) + i = bidiIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return Properties{}, 1 + } + return Properties{entry: trie.lookupValue(uint32(i), c2), last: c2}, 3 + case c0 < 0xF8: // 4-byte UTF-8 + if len(s) < 4 { + return Properties{}, 0 + } + i := bidiIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return Properties{}, 1 + } + o := uint32(i)<<6 + uint32(c1) + i = bidiIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return Properties{}, 1 + } + o = uint32(i)<<6 + uint32(c2) + i = bidiIndex[o] + c3 := s[3] + if c3 < 0x80 || 0xC0 <= c3 { + return Properties{}, 1 + } + return Properties{entry: trie.lookupValue(uint32(i), c3)}, 4 + } + // Illegal rune + return Properties{}, 1 +} + +// LookupString returns properties for the first rune in s and the width in +// bytes of its encoding. The size will be 0 if s does not hold enough bytes to +// complete the encoding. +func LookupString(s string) (p Properties, sz int) { + c0 := s[0] + switch { + case c0 < 0x80: // is ASCII + return Properties{entry: bidiValues[c0]}, 1 + case c0 < 0xC2: + return Properties{}, 1 + case c0 < 0xE0: // 2-byte UTF-8 + if len(s) < 2 { + return Properties{}, 0 + } + i := bidiIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return Properties{}, 1 + } + return Properties{entry: trie.lookupValue(uint32(i), c1)}, 2 + case c0 < 0xF0: // 3-byte UTF-8 + if len(s) < 3 { + return Properties{}, 0 + } + i := bidiIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return Properties{}, 1 + } + o := uint32(i)<<6 + uint32(c1) + i = bidiIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return Properties{}, 1 + } + return Properties{entry: trie.lookupValue(uint32(i), c2), last: c2}, 3 + case c0 < 0xF8: // 4-byte UTF-8 + if len(s) < 4 { + return Properties{}, 0 + } + i := bidiIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return Properties{}, 1 + } + o := uint32(i)<<6 + uint32(c1) + i = bidiIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return Properties{}, 1 + } + o = uint32(i)<<6 + uint32(c2) + i = bidiIndex[o] + c3 := s[3] + if c3 < 0x80 || 0xC0 <= c3 { + return Properties{}, 1 + } + return Properties{entry: trie.lookupValue(uint32(i), c3)}, 4 + } + // Illegal rune + return Properties{}, 1 +} diff --git a/vendor/golang.org/x/text/unicode/bidi/tables10.0.0.go b/vendor/golang.org/x/text/unicode/bidi/tables10.0.0.go new file mode 100644 index 0000000000..2e1ff19599 --- /dev/null +++ b/vendor/golang.org/x/text/unicode/bidi/tables10.0.0.go @@ -0,0 +1,1815 @@ +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. + +// +build go1.10 + +package bidi + +// UnicodeVersion is the Unicode version from which the tables in this package are derived. +const UnicodeVersion = "10.0.0" + +// xorMasks contains masks to be xor-ed with brackets to get the reverse +// version. +var xorMasks = []int32{ // 8 elements + 0, 1, 6, 7, 3, 15, 29, 63, +} // Size: 56 bytes + +// lookup returns the trie value for the first UTF-8 encoding in s and +// the width in bytes of this encoding. The size will be 0 if s does not +// hold enough bytes to complete the encoding. len(s) must be greater than 0. +func (t *bidiTrie) lookup(s []byte) (v uint8, sz int) { + c0 := s[0] + switch { + case c0 < 0x80: // is ASCII + return bidiValues[c0], 1 + case c0 < 0xC2: + return 0, 1 // Illegal UTF-8: not a starter, not ASCII. + case c0 < 0xE0: // 2-byte UTF-8 + if len(s) < 2 { + return 0, 0 + } + i := bidiIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c1), 2 + case c0 < 0xF0: // 3-byte UTF-8 + if len(s) < 3 { + return 0, 0 + } + i := bidiIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = bidiIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c2), 3 + case c0 < 0xF8: // 4-byte UTF-8 + if len(s) < 4 { + return 0, 0 + } + i := bidiIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = bidiIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + o = uint32(i)<<6 + uint32(c2) + i = bidiIndex[o] + c3 := s[3] + if c3 < 0x80 || 0xC0 <= c3 { + return 0, 3 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c3), 4 + } + // Illegal rune + return 0, 1 +} + +// lookupUnsafe returns the trie value for the first UTF-8 encoding in s. +// s must start with a full and valid UTF-8 encoded rune. +func (t *bidiTrie) lookupUnsafe(s []byte) uint8 { + c0 := s[0] + if c0 < 0x80 { // is ASCII + return bidiValues[c0] + } + i := bidiIndex[c0] + if c0 < 0xE0 { // 2-byte UTF-8 + return t.lookupValue(uint32(i), s[1]) + } + i = bidiIndex[uint32(i)<<6+uint32(s[1])] + if c0 < 0xF0 { // 3-byte UTF-8 + return t.lookupValue(uint32(i), s[2]) + } + i = bidiIndex[uint32(i)<<6+uint32(s[2])] + if c0 < 0xF8 { // 4-byte UTF-8 + return t.lookupValue(uint32(i), s[3]) + } + return 0 +} + +// lookupString returns the trie value for the first UTF-8 encoding in s and +// the width in bytes of this encoding. The size will be 0 if s does not +// hold enough bytes to complete the encoding. len(s) must be greater than 0. +func (t *bidiTrie) lookupString(s string) (v uint8, sz int) { + c0 := s[0] + switch { + case c0 < 0x80: // is ASCII + return bidiValues[c0], 1 + case c0 < 0xC2: + return 0, 1 // Illegal UTF-8: not a starter, not ASCII. + case c0 < 0xE0: // 2-byte UTF-8 + if len(s) < 2 { + return 0, 0 + } + i := bidiIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c1), 2 + case c0 < 0xF0: // 3-byte UTF-8 + if len(s) < 3 { + return 0, 0 + } + i := bidiIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = bidiIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c2), 3 + case c0 < 0xF8: // 4-byte UTF-8 + if len(s) < 4 { + return 0, 0 + } + i := bidiIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = bidiIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + o = uint32(i)<<6 + uint32(c2) + i = bidiIndex[o] + c3 := s[3] + if c3 < 0x80 || 0xC0 <= c3 { + return 0, 3 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c3), 4 + } + // Illegal rune + return 0, 1 +} + +// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s. +// s must start with a full and valid UTF-8 encoded rune. +func (t *bidiTrie) lookupStringUnsafe(s string) uint8 { + c0 := s[0] + if c0 < 0x80 { // is ASCII + return bidiValues[c0] + } + i := bidiIndex[c0] + if c0 < 0xE0 { // 2-byte UTF-8 + return t.lookupValue(uint32(i), s[1]) + } + i = bidiIndex[uint32(i)<<6+uint32(s[1])] + if c0 < 0xF0 { // 3-byte UTF-8 + return t.lookupValue(uint32(i), s[2]) + } + i = bidiIndex[uint32(i)<<6+uint32(s[2])] + if c0 < 0xF8 { // 4-byte UTF-8 + return t.lookupValue(uint32(i), s[3]) + } + return 0 +} + +// bidiTrie. Total size: 16128 bytes (15.75 KiB). Checksum: 8122d83e461996f. +type bidiTrie struct{} + +func newBidiTrie(i int) *bidiTrie { + return &bidiTrie{} +} + +// lookupValue determines the type of block n and looks up the value for b. +func (t *bidiTrie) lookupValue(n uint32, b byte) uint8 { + switch { + default: + return uint8(bidiValues[n<<6+uint32(b)]) + } +} + +// bidiValues: 228 blocks, 14592 entries, 14592 bytes +// The third block is the zero block. +var bidiValues = [14592]uint8{ + // Block 0x0, offset 0x0 + 0x00: 0x000b, 0x01: 0x000b, 0x02: 0x000b, 0x03: 0x000b, 0x04: 0x000b, 0x05: 0x000b, + 0x06: 0x000b, 0x07: 0x000b, 0x08: 0x000b, 0x09: 0x0008, 0x0a: 0x0007, 0x0b: 0x0008, + 0x0c: 0x0009, 0x0d: 0x0007, 0x0e: 0x000b, 0x0f: 0x000b, 0x10: 0x000b, 0x11: 0x000b, + 0x12: 0x000b, 0x13: 0x000b, 0x14: 0x000b, 0x15: 0x000b, 0x16: 0x000b, 0x17: 0x000b, + 0x18: 0x000b, 0x19: 0x000b, 0x1a: 0x000b, 0x1b: 0x000b, 0x1c: 0x0007, 0x1d: 0x0007, + 0x1e: 0x0007, 0x1f: 0x0008, 0x20: 0x0009, 0x21: 0x000a, 0x22: 0x000a, 0x23: 0x0004, + 0x24: 0x0004, 0x25: 0x0004, 0x26: 0x000a, 0x27: 0x000a, 0x28: 0x003a, 0x29: 0x002a, + 0x2a: 0x000a, 0x2b: 0x0003, 0x2c: 0x0006, 0x2d: 0x0003, 0x2e: 0x0006, 0x2f: 0x0006, + 0x30: 0x0002, 0x31: 0x0002, 0x32: 0x0002, 0x33: 0x0002, 0x34: 0x0002, 0x35: 0x0002, + 0x36: 0x0002, 0x37: 0x0002, 0x38: 0x0002, 0x39: 0x0002, 0x3a: 0x0006, 0x3b: 0x000a, + 0x3c: 0x000a, 0x3d: 0x000a, 0x3e: 0x000a, 0x3f: 0x000a, + // Block 0x1, offset 0x40 + 0x40: 0x000a, + 0x5b: 0x005a, 0x5c: 0x000a, 0x5d: 0x004a, + 0x5e: 0x000a, 0x5f: 0x000a, 0x60: 0x000a, + 0x7b: 0x005a, + 0x7c: 0x000a, 0x7d: 0x004a, 0x7e: 0x000a, 0x7f: 0x000b, + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0xc0: 0x000b, 0xc1: 0x000b, 0xc2: 0x000b, 0xc3: 0x000b, 0xc4: 0x000b, 0xc5: 0x0007, + 0xc6: 0x000b, 0xc7: 0x000b, 0xc8: 0x000b, 0xc9: 0x000b, 0xca: 0x000b, 0xcb: 0x000b, + 0xcc: 0x000b, 0xcd: 0x000b, 0xce: 0x000b, 0xcf: 0x000b, 0xd0: 0x000b, 0xd1: 0x000b, + 0xd2: 0x000b, 0xd3: 0x000b, 0xd4: 0x000b, 0xd5: 0x000b, 0xd6: 0x000b, 0xd7: 0x000b, + 0xd8: 0x000b, 0xd9: 0x000b, 0xda: 0x000b, 0xdb: 0x000b, 0xdc: 0x000b, 0xdd: 0x000b, + 0xde: 0x000b, 0xdf: 0x000b, 0xe0: 0x0006, 0xe1: 0x000a, 0xe2: 0x0004, 0xe3: 0x0004, + 0xe4: 0x0004, 0xe5: 0x0004, 0xe6: 0x000a, 0xe7: 0x000a, 0xe8: 0x000a, 0xe9: 0x000a, + 0xeb: 0x000a, 0xec: 0x000a, 0xed: 0x000b, 0xee: 0x000a, 0xef: 0x000a, + 0xf0: 0x0004, 0xf1: 0x0004, 0xf2: 0x0002, 0xf3: 0x0002, 0xf4: 0x000a, + 0xf6: 0x000a, 0xf7: 0x000a, 0xf8: 0x000a, 0xf9: 0x0002, 0xfb: 0x000a, + 0xfc: 0x000a, 0xfd: 0x000a, 0xfe: 0x000a, 0xff: 0x000a, + // Block 0x4, offset 0x100 + 0x117: 0x000a, + 0x137: 0x000a, + // Block 0x5, offset 0x140 + 0x179: 0x000a, 0x17a: 0x000a, + // Block 0x6, offset 0x180 + 0x182: 0x000a, 0x183: 0x000a, 0x184: 0x000a, 0x185: 0x000a, + 0x186: 0x000a, 0x187: 0x000a, 0x188: 0x000a, 0x189: 0x000a, 0x18a: 0x000a, 0x18b: 0x000a, + 0x18c: 0x000a, 0x18d: 0x000a, 0x18e: 0x000a, 0x18f: 0x000a, + 0x192: 0x000a, 0x193: 0x000a, 0x194: 0x000a, 0x195: 0x000a, 0x196: 0x000a, 0x197: 0x000a, + 0x198: 0x000a, 0x199: 0x000a, 0x19a: 0x000a, 0x19b: 0x000a, 0x19c: 0x000a, 0x19d: 0x000a, + 0x19e: 0x000a, 0x19f: 0x000a, + 0x1a5: 0x000a, 0x1a6: 0x000a, 0x1a7: 0x000a, 0x1a8: 0x000a, 0x1a9: 0x000a, + 0x1aa: 0x000a, 0x1ab: 0x000a, 0x1ac: 0x000a, 0x1ad: 0x000a, 0x1af: 0x000a, + 0x1b0: 0x000a, 0x1b1: 0x000a, 0x1b2: 0x000a, 0x1b3: 0x000a, 0x1b4: 0x000a, 0x1b5: 0x000a, + 0x1b6: 0x000a, 0x1b7: 0x000a, 0x1b8: 0x000a, 0x1b9: 0x000a, 0x1ba: 0x000a, 0x1bb: 0x000a, + 0x1bc: 0x000a, 0x1bd: 0x000a, 0x1be: 0x000a, 0x1bf: 0x000a, + // Block 0x7, offset 0x1c0 + 0x1c0: 0x000c, 0x1c1: 0x000c, 0x1c2: 0x000c, 0x1c3: 0x000c, 0x1c4: 0x000c, 0x1c5: 0x000c, + 0x1c6: 0x000c, 0x1c7: 0x000c, 0x1c8: 0x000c, 0x1c9: 0x000c, 0x1ca: 0x000c, 0x1cb: 0x000c, + 0x1cc: 0x000c, 0x1cd: 0x000c, 0x1ce: 0x000c, 0x1cf: 0x000c, 0x1d0: 0x000c, 0x1d1: 0x000c, + 0x1d2: 0x000c, 0x1d3: 0x000c, 0x1d4: 0x000c, 0x1d5: 0x000c, 0x1d6: 0x000c, 0x1d7: 0x000c, + 0x1d8: 0x000c, 0x1d9: 0x000c, 0x1da: 0x000c, 0x1db: 0x000c, 0x1dc: 0x000c, 0x1dd: 0x000c, + 0x1de: 0x000c, 0x1df: 0x000c, 0x1e0: 0x000c, 0x1e1: 0x000c, 0x1e2: 0x000c, 0x1e3: 0x000c, + 0x1e4: 0x000c, 0x1e5: 0x000c, 0x1e6: 0x000c, 0x1e7: 0x000c, 0x1e8: 0x000c, 0x1e9: 0x000c, + 0x1ea: 0x000c, 0x1eb: 0x000c, 0x1ec: 0x000c, 0x1ed: 0x000c, 0x1ee: 0x000c, 0x1ef: 0x000c, + 0x1f0: 0x000c, 0x1f1: 0x000c, 0x1f2: 0x000c, 0x1f3: 0x000c, 0x1f4: 0x000c, 0x1f5: 0x000c, + 0x1f6: 0x000c, 0x1f7: 0x000c, 0x1f8: 0x000c, 0x1f9: 0x000c, 0x1fa: 0x000c, 0x1fb: 0x000c, + 0x1fc: 0x000c, 0x1fd: 0x000c, 0x1fe: 0x000c, 0x1ff: 0x000c, + // Block 0x8, offset 0x200 + 0x200: 0x000c, 0x201: 0x000c, 0x202: 0x000c, 0x203: 0x000c, 0x204: 0x000c, 0x205: 0x000c, + 0x206: 0x000c, 0x207: 0x000c, 0x208: 0x000c, 0x209: 0x000c, 0x20a: 0x000c, 0x20b: 0x000c, + 0x20c: 0x000c, 0x20d: 0x000c, 0x20e: 0x000c, 0x20f: 0x000c, 0x210: 0x000c, 0x211: 0x000c, + 0x212: 0x000c, 0x213: 0x000c, 0x214: 0x000c, 0x215: 0x000c, 0x216: 0x000c, 0x217: 0x000c, + 0x218: 0x000c, 0x219: 0x000c, 0x21a: 0x000c, 0x21b: 0x000c, 0x21c: 0x000c, 0x21d: 0x000c, + 0x21e: 0x000c, 0x21f: 0x000c, 0x220: 0x000c, 0x221: 0x000c, 0x222: 0x000c, 0x223: 0x000c, + 0x224: 0x000c, 0x225: 0x000c, 0x226: 0x000c, 0x227: 0x000c, 0x228: 0x000c, 0x229: 0x000c, + 0x22a: 0x000c, 0x22b: 0x000c, 0x22c: 0x000c, 0x22d: 0x000c, 0x22e: 0x000c, 0x22f: 0x000c, + 0x234: 0x000a, 0x235: 0x000a, + 0x23e: 0x000a, + // Block 0x9, offset 0x240 + 0x244: 0x000a, 0x245: 0x000a, + 0x247: 0x000a, + // Block 0xa, offset 0x280 + 0x2b6: 0x000a, + // Block 0xb, offset 0x2c0 + 0x2c3: 0x000c, 0x2c4: 0x000c, 0x2c5: 0x000c, + 0x2c6: 0x000c, 0x2c7: 0x000c, 0x2c8: 0x000c, 0x2c9: 0x000c, + // Block 0xc, offset 0x300 + 0x30a: 0x000a, + 0x30d: 0x000a, 0x30e: 0x000a, 0x30f: 0x0004, 0x310: 0x0001, 0x311: 0x000c, + 0x312: 0x000c, 0x313: 0x000c, 0x314: 0x000c, 0x315: 0x000c, 0x316: 0x000c, 0x317: 0x000c, + 0x318: 0x000c, 0x319: 0x000c, 0x31a: 0x000c, 0x31b: 0x000c, 0x31c: 0x000c, 0x31d: 0x000c, + 0x31e: 0x000c, 0x31f: 0x000c, 0x320: 0x000c, 0x321: 0x000c, 0x322: 0x000c, 0x323: 0x000c, + 0x324: 0x000c, 0x325: 0x000c, 0x326: 0x000c, 0x327: 0x000c, 0x328: 0x000c, 0x329: 0x000c, + 0x32a: 0x000c, 0x32b: 0x000c, 0x32c: 0x000c, 0x32d: 0x000c, 0x32e: 0x000c, 0x32f: 0x000c, + 0x330: 0x000c, 0x331: 0x000c, 0x332: 0x000c, 0x333: 0x000c, 0x334: 0x000c, 0x335: 0x000c, + 0x336: 0x000c, 0x337: 0x000c, 0x338: 0x000c, 0x339: 0x000c, 0x33a: 0x000c, 0x33b: 0x000c, + 0x33c: 0x000c, 0x33d: 0x000c, 0x33e: 0x0001, 0x33f: 0x000c, + // Block 0xd, offset 0x340 + 0x340: 0x0001, 0x341: 0x000c, 0x342: 0x000c, 0x343: 0x0001, 0x344: 0x000c, 0x345: 0x000c, + 0x346: 0x0001, 0x347: 0x000c, 0x348: 0x0001, 0x349: 0x0001, 0x34a: 0x0001, 0x34b: 0x0001, + 0x34c: 0x0001, 0x34d: 0x0001, 0x34e: 0x0001, 0x34f: 0x0001, 0x350: 0x0001, 0x351: 0x0001, + 0x352: 0x0001, 0x353: 0x0001, 0x354: 0x0001, 0x355: 0x0001, 0x356: 0x0001, 0x357: 0x0001, + 0x358: 0x0001, 0x359: 0x0001, 0x35a: 0x0001, 0x35b: 0x0001, 0x35c: 0x0001, 0x35d: 0x0001, + 0x35e: 0x0001, 0x35f: 0x0001, 0x360: 0x0001, 0x361: 0x0001, 0x362: 0x0001, 0x363: 0x0001, + 0x364: 0x0001, 0x365: 0x0001, 0x366: 0x0001, 0x367: 0x0001, 0x368: 0x0001, 0x369: 0x0001, + 0x36a: 0x0001, 0x36b: 0x0001, 0x36c: 0x0001, 0x36d: 0x0001, 0x36e: 0x0001, 0x36f: 0x0001, + 0x370: 0x0001, 0x371: 0x0001, 0x372: 0x0001, 0x373: 0x0001, 0x374: 0x0001, 0x375: 0x0001, + 0x376: 0x0001, 0x377: 0x0001, 0x378: 0x0001, 0x379: 0x0001, 0x37a: 0x0001, 0x37b: 0x0001, + 0x37c: 0x0001, 0x37d: 0x0001, 0x37e: 0x0001, 0x37f: 0x0001, + // Block 0xe, offset 0x380 + 0x380: 0x0005, 0x381: 0x0005, 0x382: 0x0005, 0x383: 0x0005, 0x384: 0x0005, 0x385: 0x0005, + 0x386: 0x000a, 0x387: 0x000a, 0x388: 0x000d, 0x389: 0x0004, 0x38a: 0x0004, 0x38b: 0x000d, + 0x38c: 0x0006, 0x38d: 0x000d, 0x38e: 0x000a, 0x38f: 0x000a, 0x390: 0x000c, 0x391: 0x000c, + 0x392: 0x000c, 0x393: 0x000c, 0x394: 0x000c, 0x395: 0x000c, 0x396: 0x000c, 0x397: 0x000c, + 0x398: 0x000c, 0x399: 0x000c, 0x39a: 0x000c, 0x39b: 0x000d, 0x39c: 0x000d, 0x39d: 0x000d, + 0x39e: 0x000d, 0x39f: 0x000d, 0x3a0: 0x000d, 0x3a1: 0x000d, 0x3a2: 0x000d, 0x3a3: 0x000d, + 0x3a4: 0x000d, 0x3a5: 0x000d, 0x3a6: 0x000d, 0x3a7: 0x000d, 0x3a8: 0x000d, 0x3a9: 0x000d, + 0x3aa: 0x000d, 0x3ab: 0x000d, 0x3ac: 0x000d, 0x3ad: 0x000d, 0x3ae: 0x000d, 0x3af: 0x000d, + 0x3b0: 0x000d, 0x3b1: 0x000d, 0x3b2: 0x000d, 0x3b3: 0x000d, 0x3b4: 0x000d, 0x3b5: 0x000d, + 0x3b6: 0x000d, 0x3b7: 0x000d, 0x3b8: 0x000d, 0x3b9: 0x000d, 0x3ba: 0x000d, 0x3bb: 0x000d, + 0x3bc: 0x000d, 0x3bd: 0x000d, 0x3be: 0x000d, 0x3bf: 0x000d, + // Block 0xf, offset 0x3c0 + 0x3c0: 0x000d, 0x3c1: 0x000d, 0x3c2: 0x000d, 0x3c3: 0x000d, 0x3c4: 0x000d, 0x3c5: 0x000d, + 0x3c6: 0x000d, 0x3c7: 0x000d, 0x3c8: 0x000d, 0x3c9: 0x000d, 0x3ca: 0x000d, 0x3cb: 0x000c, + 0x3cc: 0x000c, 0x3cd: 0x000c, 0x3ce: 0x000c, 0x3cf: 0x000c, 0x3d0: 0x000c, 0x3d1: 0x000c, + 0x3d2: 0x000c, 0x3d3: 0x000c, 0x3d4: 0x000c, 0x3d5: 0x000c, 0x3d6: 0x000c, 0x3d7: 0x000c, + 0x3d8: 0x000c, 0x3d9: 0x000c, 0x3da: 0x000c, 0x3db: 0x000c, 0x3dc: 0x000c, 0x3dd: 0x000c, + 0x3de: 0x000c, 0x3df: 0x000c, 0x3e0: 0x0005, 0x3e1: 0x0005, 0x3e2: 0x0005, 0x3e3: 0x0005, + 0x3e4: 0x0005, 0x3e5: 0x0005, 0x3e6: 0x0005, 0x3e7: 0x0005, 0x3e8: 0x0005, 0x3e9: 0x0005, + 0x3ea: 0x0004, 0x3eb: 0x0005, 0x3ec: 0x0005, 0x3ed: 0x000d, 0x3ee: 0x000d, 0x3ef: 0x000d, + 0x3f0: 0x000c, 0x3f1: 0x000d, 0x3f2: 0x000d, 0x3f3: 0x000d, 0x3f4: 0x000d, 0x3f5: 0x000d, + 0x3f6: 0x000d, 0x3f7: 0x000d, 0x3f8: 0x000d, 0x3f9: 0x000d, 0x3fa: 0x000d, 0x3fb: 0x000d, + 0x3fc: 0x000d, 0x3fd: 0x000d, 0x3fe: 0x000d, 0x3ff: 0x000d, + // Block 0x10, offset 0x400 + 0x400: 0x000d, 0x401: 0x000d, 0x402: 0x000d, 0x403: 0x000d, 0x404: 0x000d, 0x405: 0x000d, + 0x406: 0x000d, 0x407: 0x000d, 0x408: 0x000d, 0x409: 0x000d, 0x40a: 0x000d, 0x40b: 0x000d, + 0x40c: 0x000d, 0x40d: 0x000d, 0x40e: 0x000d, 0x40f: 0x000d, 0x410: 0x000d, 0x411: 0x000d, + 0x412: 0x000d, 0x413: 0x000d, 0x414: 0x000d, 0x415: 0x000d, 0x416: 0x000d, 0x417: 0x000d, + 0x418: 0x000d, 0x419: 0x000d, 0x41a: 0x000d, 0x41b: 0x000d, 0x41c: 0x000d, 0x41d: 0x000d, + 0x41e: 0x000d, 0x41f: 0x000d, 0x420: 0x000d, 0x421: 0x000d, 0x422: 0x000d, 0x423: 0x000d, + 0x424: 0x000d, 0x425: 0x000d, 0x426: 0x000d, 0x427: 0x000d, 0x428: 0x000d, 0x429: 0x000d, + 0x42a: 0x000d, 0x42b: 0x000d, 0x42c: 0x000d, 0x42d: 0x000d, 0x42e: 0x000d, 0x42f: 0x000d, + 0x430: 0x000d, 0x431: 0x000d, 0x432: 0x000d, 0x433: 0x000d, 0x434: 0x000d, 0x435: 0x000d, + 0x436: 0x000d, 0x437: 0x000d, 0x438: 0x000d, 0x439: 0x000d, 0x43a: 0x000d, 0x43b: 0x000d, + 0x43c: 0x000d, 0x43d: 0x000d, 0x43e: 0x000d, 0x43f: 0x000d, + // Block 0x11, offset 0x440 + 0x440: 0x000d, 0x441: 0x000d, 0x442: 0x000d, 0x443: 0x000d, 0x444: 0x000d, 0x445: 0x000d, + 0x446: 0x000d, 0x447: 0x000d, 0x448: 0x000d, 0x449: 0x000d, 0x44a: 0x000d, 0x44b: 0x000d, + 0x44c: 0x000d, 0x44d: 0x000d, 0x44e: 0x000d, 0x44f: 0x000d, 0x450: 0x000d, 0x451: 0x000d, + 0x452: 0x000d, 0x453: 0x000d, 0x454: 0x000d, 0x455: 0x000d, 0x456: 0x000c, 0x457: 0x000c, + 0x458: 0x000c, 0x459: 0x000c, 0x45a: 0x000c, 0x45b: 0x000c, 0x45c: 0x000c, 0x45d: 0x0005, + 0x45e: 0x000a, 0x45f: 0x000c, 0x460: 0x000c, 0x461: 0x000c, 0x462: 0x000c, 0x463: 0x000c, + 0x464: 0x000c, 0x465: 0x000d, 0x466: 0x000d, 0x467: 0x000c, 0x468: 0x000c, 0x469: 0x000a, + 0x46a: 0x000c, 0x46b: 0x000c, 0x46c: 0x000c, 0x46d: 0x000c, 0x46e: 0x000d, 0x46f: 0x000d, + 0x470: 0x0002, 0x471: 0x0002, 0x472: 0x0002, 0x473: 0x0002, 0x474: 0x0002, 0x475: 0x0002, + 0x476: 0x0002, 0x477: 0x0002, 0x478: 0x0002, 0x479: 0x0002, 0x47a: 0x000d, 0x47b: 0x000d, + 0x47c: 0x000d, 0x47d: 0x000d, 0x47e: 0x000d, 0x47f: 0x000d, + // Block 0x12, offset 0x480 + 0x480: 0x000d, 0x481: 0x000d, 0x482: 0x000d, 0x483: 0x000d, 0x484: 0x000d, 0x485: 0x000d, + 0x486: 0x000d, 0x487: 0x000d, 0x488: 0x000d, 0x489: 0x000d, 0x48a: 0x000d, 0x48b: 0x000d, + 0x48c: 0x000d, 0x48d: 0x000d, 0x48e: 0x000d, 0x48f: 0x000d, 0x490: 0x000d, 0x491: 0x000c, + 0x492: 0x000d, 0x493: 0x000d, 0x494: 0x000d, 0x495: 0x000d, 0x496: 0x000d, 0x497: 0x000d, + 0x498: 0x000d, 0x499: 0x000d, 0x49a: 0x000d, 0x49b: 0x000d, 0x49c: 0x000d, 0x49d: 0x000d, + 0x49e: 0x000d, 0x49f: 0x000d, 0x4a0: 0x000d, 0x4a1: 0x000d, 0x4a2: 0x000d, 0x4a3: 0x000d, + 0x4a4: 0x000d, 0x4a5: 0x000d, 0x4a6: 0x000d, 0x4a7: 0x000d, 0x4a8: 0x000d, 0x4a9: 0x000d, + 0x4aa: 0x000d, 0x4ab: 0x000d, 0x4ac: 0x000d, 0x4ad: 0x000d, 0x4ae: 0x000d, 0x4af: 0x000d, + 0x4b0: 0x000c, 0x4b1: 0x000c, 0x4b2: 0x000c, 0x4b3: 0x000c, 0x4b4: 0x000c, 0x4b5: 0x000c, + 0x4b6: 0x000c, 0x4b7: 0x000c, 0x4b8: 0x000c, 0x4b9: 0x000c, 0x4ba: 0x000c, 0x4bb: 0x000c, + 0x4bc: 0x000c, 0x4bd: 0x000c, 0x4be: 0x000c, 0x4bf: 0x000c, + // Block 0x13, offset 0x4c0 + 0x4c0: 0x000c, 0x4c1: 0x000c, 0x4c2: 0x000c, 0x4c3: 0x000c, 0x4c4: 0x000c, 0x4c5: 0x000c, + 0x4c6: 0x000c, 0x4c7: 0x000c, 0x4c8: 0x000c, 0x4c9: 0x000c, 0x4ca: 0x000c, 0x4cb: 0x000d, + 0x4cc: 0x000d, 0x4cd: 0x000d, 0x4ce: 0x000d, 0x4cf: 0x000d, 0x4d0: 0x000d, 0x4d1: 0x000d, + 0x4d2: 0x000d, 0x4d3: 0x000d, 0x4d4: 0x000d, 0x4d5: 0x000d, 0x4d6: 0x000d, 0x4d7: 0x000d, + 0x4d8: 0x000d, 0x4d9: 0x000d, 0x4da: 0x000d, 0x4db: 0x000d, 0x4dc: 0x000d, 0x4dd: 0x000d, + 0x4de: 0x000d, 0x4df: 0x000d, 0x4e0: 0x000d, 0x4e1: 0x000d, 0x4e2: 0x000d, 0x4e3: 0x000d, + 0x4e4: 0x000d, 0x4e5: 0x000d, 0x4e6: 0x000d, 0x4e7: 0x000d, 0x4e8: 0x000d, 0x4e9: 0x000d, + 0x4ea: 0x000d, 0x4eb: 0x000d, 0x4ec: 0x000d, 0x4ed: 0x000d, 0x4ee: 0x000d, 0x4ef: 0x000d, + 0x4f0: 0x000d, 0x4f1: 0x000d, 0x4f2: 0x000d, 0x4f3: 0x000d, 0x4f4: 0x000d, 0x4f5: 0x000d, + 0x4f6: 0x000d, 0x4f7: 0x000d, 0x4f8: 0x000d, 0x4f9: 0x000d, 0x4fa: 0x000d, 0x4fb: 0x000d, + 0x4fc: 0x000d, 0x4fd: 0x000d, 0x4fe: 0x000d, 0x4ff: 0x000d, + // Block 0x14, offset 0x500 + 0x500: 0x000d, 0x501: 0x000d, 0x502: 0x000d, 0x503: 0x000d, 0x504: 0x000d, 0x505: 0x000d, + 0x506: 0x000d, 0x507: 0x000d, 0x508: 0x000d, 0x509: 0x000d, 0x50a: 0x000d, 0x50b: 0x000d, + 0x50c: 0x000d, 0x50d: 0x000d, 0x50e: 0x000d, 0x50f: 0x000d, 0x510: 0x000d, 0x511: 0x000d, + 0x512: 0x000d, 0x513: 0x000d, 0x514: 0x000d, 0x515: 0x000d, 0x516: 0x000d, 0x517: 0x000d, + 0x518: 0x000d, 0x519: 0x000d, 0x51a: 0x000d, 0x51b: 0x000d, 0x51c: 0x000d, 0x51d: 0x000d, + 0x51e: 0x000d, 0x51f: 0x000d, 0x520: 0x000d, 0x521: 0x000d, 0x522: 0x000d, 0x523: 0x000d, + 0x524: 0x000d, 0x525: 0x000d, 0x526: 0x000c, 0x527: 0x000c, 0x528: 0x000c, 0x529: 0x000c, + 0x52a: 0x000c, 0x52b: 0x000c, 0x52c: 0x000c, 0x52d: 0x000c, 0x52e: 0x000c, 0x52f: 0x000c, + 0x530: 0x000c, 0x531: 0x000d, 0x532: 0x000d, 0x533: 0x000d, 0x534: 0x000d, 0x535: 0x000d, + 0x536: 0x000d, 0x537: 0x000d, 0x538: 0x000d, 0x539: 0x000d, 0x53a: 0x000d, 0x53b: 0x000d, + 0x53c: 0x000d, 0x53d: 0x000d, 0x53e: 0x000d, 0x53f: 0x000d, + // Block 0x15, offset 0x540 + 0x540: 0x0001, 0x541: 0x0001, 0x542: 0x0001, 0x543: 0x0001, 0x544: 0x0001, 0x545: 0x0001, + 0x546: 0x0001, 0x547: 0x0001, 0x548: 0x0001, 0x549: 0x0001, 0x54a: 0x0001, 0x54b: 0x0001, + 0x54c: 0x0001, 0x54d: 0x0001, 0x54e: 0x0001, 0x54f: 0x0001, 0x550: 0x0001, 0x551: 0x0001, + 0x552: 0x0001, 0x553: 0x0001, 0x554: 0x0001, 0x555: 0x0001, 0x556: 0x0001, 0x557: 0x0001, + 0x558: 0x0001, 0x559: 0x0001, 0x55a: 0x0001, 0x55b: 0x0001, 0x55c: 0x0001, 0x55d: 0x0001, + 0x55e: 0x0001, 0x55f: 0x0001, 0x560: 0x0001, 0x561: 0x0001, 0x562: 0x0001, 0x563: 0x0001, + 0x564: 0x0001, 0x565: 0x0001, 0x566: 0x0001, 0x567: 0x0001, 0x568: 0x0001, 0x569: 0x0001, + 0x56a: 0x0001, 0x56b: 0x000c, 0x56c: 0x000c, 0x56d: 0x000c, 0x56e: 0x000c, 0x56f: 0x000c, + 0x570: 0x000c, 0x571: 0x000c, 0x572: 0x000c, 0x573: 0x000c, 0x574: 0x0001, 0x575: 0x0001, + 0x576: 0x000a, 0x577: 0x000a, 0x578: 0x000a, 0x579: 0x000a, 0x57a: 0x0001, 0x57b: 0x0001, + 0x57c: 0x0001, 0x57d: 0x0001, 0x57e: 0x0001, 0x57f: 0x0001, + // Block 0x16, offset 0x580 + 0x580: 0x0001, 0x581: 0x0001, 0x582: 0x0001, 0x583: 0x0001, 0x584: 0x0001, 0x585: 0x0001, + 0x586: 0x0001, 0x587: 0x0001, 0x588: 0x0001, 0x589: 0x0001, 0x58a: 0x0001, 0x58b: 0x0001, + 0x58c: 0x0001, 0x58d: 0x0001, 0x58e: 0x0001, 0x58f: 0x0001, 0x590: 0x0001, 0x591: 0x0001, + 0x592: 0x0001, 0x593: 0x0001, 0x594: 0x0001, 0x595: 0x0001, 0x596: 0x000c, 0x597: 0x000c, + 0x598: 0x000c, 0x599: 0x000c, 0x59a: 0x0001, 0x59b: 0x000c, 0x59c: 0x000c, 0x59d: 0x000c, + 0x59e: 0x000c, 0x59f: 0x000c, 0x5a0: 0x000c, 0x5a1: 0x000c, 0x5a2: 0x000c, 0x5a3: 0x000c, + 0x5a4: 0x0001, 0x5a5: 0x000c, 0x5a6: 0x000c, 0x5a7: 0x000c, 0x5a8: 0x0001, 0x5a9: 0x000c, + 0x5aa: 0x000c, 0x5ab: 0x000c, 0x5ac: 0x000c, 0x5ad: 0x000c, 0x5ae: 0x0001, 0x5af: 0x0001, + 0x5b0: 0x0001, 0x5b1: 0x0001, 0x5b2: 0x0001, 0x5b3: 0x0001, 0x5b4: 0x0001, 0x5b5: 0x0001, + 0x5b6: 0x0001, 0x5b7: 0x0001, 0x5b8: 0x0001, 0x5b9: 0x0001, 0x5ba: 0x0001, 0x5bb: 0x0001, + 0x5bc: 0x0001, 0x5bd: 0x0001, 0x5be: 0x0001, 0x5bf: 0x0001, + // Block 0x17, offset 0x5c0 + 0x5c0: 0x0001, 0x5c1: 0x0001, 0x5c2: 0x0001, 0x5c3: 0x0001, 0x5c4: 0x0001, 0x5c5: 0x0001, + 0x5c6: 0x0001, 0x5c7: 0x0001, 0x5c8: 0x0001, 0x5c9: 0x0001, 0x5ca: 0x0001, 0x5cb: 0x0001, + 0x5cc: 0x0001, 0x5cd: 0x0001, 0x5ce: 0x0001, 0x5cf: 0x0001, 0x5d0: 0x0001, 0x5d1: 0x0001, + 0x5d2: 0x0001, 0x5d3: 0x0001, 0x5d4: 0x0001, 0x5d5: 0x0001, 0x5d6: 0x0001, 0x5d7: 0x0001, + 0x5d8: 0x0001, 0x5d9: 0x000c, 0x5da: 0x000c, 0x5db: 0x000c, 0x5dc: 0x0001, 0x5dd: 0x0001, + 0x5de: 0x0001, 0x5df: 0x0001, 0x5e0: 0x000d, 0x5e1: 0x000d, 0x5e2: 0x000d, 0x5e3: 0x000d, + 0x5e4: 0x000d, 0x5e5: 0x000d, 0x5e6: 0x000d, 0x5e7: 0x000d, 0x5e8: 0x000d, 0x5e9: 0x000d, + 0x5ea: 0x000d, 0x5eb: 0x000d, 0x5ec: 0x000d, 0x5ed: 0x000d, 0x5ee: 0x000d, 0x5ef: 0x000d, + 0x5f0: 0x0001, 0x5f1: 0x0001, 0x5f2: 0x0001, 0x5f3: 0x0001, 0x5f4: 0x0001, 0x5f5: 0x0001, + 0x5f6: 0x0001, 0x5f7: 0x0001, 0x5f8: 0x0001, 0x5f9: 0x0001, 0x5fa: 0x0001, 0x5fb: 0x0001, + 0x5fc: 0x0001, 0x5fd: 0x0001, 0x5fe: 0x0001, 0x5ff: 0x0001, + // Block 0x18, offset 0x600 + 0x600: 0x0001, 0x601: 0x0001, 0x602: 0x0001, 0x603: 0x0001, 0x604: 0x0001, 0x605: 0x0001, + 0x606: 0x0001, 0x607: 0x0001, 0x608: 0x0001, 0x609: 0x0001, 0x60a: 0x0001, 0x60b: 0x0001, + 0x60c: 0x0001, 0x60d: 0x0001, 0x60e: 0x0001, 0x60f: 0x0001, 0x610: 0x0001, 0x611: 0x0001, + 0x612: 0x0001, 0x613: 0x0001, 0x614: 0x0001, 0x615: 0x0001, 0x616: 0x0001, 0x617: 0x0001, + 0x618: 0x0001, 0x619: 0x0001, 0x61a: 0x0001, 0x61b: 0x0001, 0x61c: 0x0001, 0x61d: 0x0001, + 0x61e: 0x0001, 0x61f: 0x0001, 0x620: 0x000d, 0x621: 0x000d, 0x622: 0x000d, 0x623: 0x000d, + 0x624: 0x000d, 0x625: 0x000d, 0x626: 0x000d, 0x627: 0x000d, 0x628: 0x000d, 0x629: 0x000d, + 0x62a: 0x000d, 0x62b: 0x000d, 0x62c: 0x000d, 0x62d: 0x000d, 0x62e: 0x000d, 0x62f: 0x000d, + 0x630: 0x000d, 0x631: 0x000d, 0x632: 0x000d, 0x633: 0x000d, 0x634: 0x000d, 0x635: 0x000d, + 0x636: 0x000d, 0x637: 0x000d, 0x638: 0x000d, 0x639: 0x000d, 0x63a: 0x000d, 0x63b: 0x000d, + 0x63c: 0x000d, 0x63d: 0x000d, 0x63e: 0x000d, 0x63f: 0x000d, + // Block 0x19, offset 0x640 + 0x640: 0x000d, 0x641: 0x000d, 0x642: 0x000d, 0x643: 0x000d, 0x644: 0x000d, 0x645: 0x000d, + 0x646: 0x000d, 0x647: 0x000d, 0x648: 0x000d, 0x649: 0x000d, 0x64a: 0x000d, 0x64b: 0x000d, + 0x64c: 0x000d, 0x64d: 0x000d, 0x64e: 0x000d, 0x64f: 0x000d, 0x650: 0x000d, 0x651: 0x000d, + 0x652: 0x000d, 0x653: 0x000d, 0x654: 0x000c, 0x655: 0x000c, 0x656: 0x000c, 0x657: 0x000c, + 0x658: 0x000c, 0x659: 0x000c, 0x65a: 0x000c, 0x65b: 0x000c, 0x65c: 0x000c, 0x65d: 0x000c, + 0x65e: 0x000c, 0x65f: 0x000c, 0x660: 0x000c, 0x661: 0x000c, 0x662: 0x0005, 0x663: 0x000c, + 0x664: 0x000c, 0x665: 0x000c, 0x666: 0x000c, 0x667: 0x000c, 0x668: 0x000c, 0x669: 0x000c, + 0x66a: 0x000c, 0x66b: 0x000c, 0x66c: 0x000c, 0x66d: 0x000c, 0x66e: 0x000c, 0x66f: 0x000c, + 0x670: 0x000c, 0x671: 0x000c, 0x672: 0x000c, 0x673: 0x000c, 0x674: 0x000c, 0x675: 0x000c, + 0x676: 0x000c, 0x677: 0x000c, 0x678: 0x000c, 0x679: 0x000c, 0x67a: 0x000c, 0x67b: 0x000c, + 0x67c: 0x000c, 0x67d: 0x000c, 0x67e: 0x000c, 0x67f: 0x000c, + // Block 0x1a, offset 0x680 + 0x680: 0x000c, 0x681: 0x000c, 0x682: 0x000c, + 0x6ba: 0x000c, + 0x6bc: 0x000c, + // Block 0x1b, offset 0x6c0 + 0x6c1: 0x000c, 0x6c2: 0x000c, 0x6c3: 0x000c, 0x6c4: 0x000c, 0x6c5: 0x000c, + 0x6c6: 0x000c, 0x6c7: 0x000c, 0x6c8: 0x000c, + 0x6cd: 0x000c, 0x6d1: 0x000c, + 0x6d2: 0x000c, 0x6d3: 0x000c, 0x6d4: 0x000c, 0x6d5: 0x000c, 0x6d6: 0x000c, 0x6d7: 0x000c, + 0x6e2: 0x000c, 0x6e3: 0x000c, + // Block 0x1c, offset 0x700 + 0x701: 0x000c, + 0x73c: 0x000c, + // Block 0x1d, offset 0x740 + 0x741: 0x000c, 0x742: 0x000c, 0x743: 0x000c, 0x744: 0x000c, + 0x74d: 0x000c, + 0x762: 0x000c, 0x763: 0x000c, + 0x772: 0x0004, 0x773: 0x0004, + 0x77b: 0x0004, + // Block 0x1e, offset 0x780 + 0x781: 0x000c, 0x782: 0x000c, + 0x7bc: 0x000c, + // Block 0x1f, offset 0x7c0 + 0x7c1: 0x000c, 0x7c2: 0x000c, + 0x7c7: 0x000c, 0x7c8: 0x000c, 0x7cb: 0x000c, + 0x7cc: 0x000c, 0x7cd: 0x000c, 0x7d1: 0x000c, + 0x7f0: 0x000c, 0x7f1: 0x000c, 0x7f5: 0x000c, + // Block 0x20, offset 0x800 + 0x801: 0x000c, 0x802: 0x000c, 0x803: 0x000c, 0x804: 0x000c, 0x805: 0x000c, + 0x807: 0x000c, 0x808: 0x000c, + 0x80d: 0x000c, + 0x822: 0x000c, 0x823: 0x000c, + 0x831: 0x0004, + 0x83a: 0x000c, 0x83b: 0x000c, + 0x83c: 0x000c, 0x83d: 0x000c, 0x83e: 0x000c, 0x83f: 0x000c, + // Block 0x21, offset 0x840 + 0x841: 0x000c, + 0x87c: 0x000c, 0x87f: 0x000c, + // Block 0x22, offset 0x880 + 0x881: 0x000c, 0x882: 0x000c, 0x883: 0x000c, 0x884: 0x000c, + 0x88d: 0x000c, + 0x896: 0x000c, + 0x8a2: 0x000c, 0x8a3: 0x000c, + // Block 0x23, offset 0x8c0 + 0x8c2: 0x000c, + // Block 0x24, offset 0x900 + 0x900: 0x000c, + 0x90d: 0x000c, + 0x933: 0x000a, 0x934: 0x000a, 0x935: 0x000a, + 0x936: 0x000a, 0x937: 0x000a, 0x938: 0x000a, 0x939: 0x0004, 0x93a: 0x000a, + // Block 0x25, offset 0x940 + 0x940: 0x000c, + 0x97e: 0x000c, 0x97f: 0x000c, + // Block 0x26, offset 0x980 + 0x980: 0x000c, + 0x986: 0x000c, 0x987: 0x000c, 0x988: 0x000c, 0x98a: 0x000c, 0x98b: 0x000c, + 0x98c: 0x000c, 0x98d: 0x000c, + 0x995: 0x000c, 0x996: 0x000c, + 0x9a2: 0x000c, 0x9a3: 0x000c, + 0x9b8: 0x000a, 0x9b9: 0x000a, 0x9ba: 0x000a, 0x9bb: 0x000a, + 0x9bc: 0x000a, 0x9bd: 0x000a, 0x9be: 0x000a, + // Block 0x27, offset 0x9c0 + 0x9cc: 0x000c, 0x9cd: 0x000c, + 0x9e2: 0x000c, 0x9e3: 0x000c, + // Block 0x28, offset 0xa00 + 0xa00: 0x000c, 0xa01: 0x000c, + 0xa3b: 0x000c, + 0xa3c: 0x000c, + // Block 0x29, offset 0xa40 + 0xa41: 0x000c, 0xa42: 0x000c, 0xa43: 0x000c, 0xa44: 0x000c, + 0xa4d: 0x000c, + 0xa62: 0x000c, 0xa63: 0x000c, + // Block 0x2a, offset 0xa80 + 0xa8a: 0x000c, + 0xa92: 0x000c, 0xa93: 0x000c, 0xa94: 0x000c, 0xa96: 0x000c, + // Block 0x2b, offset 0xac0 + 0xaf1: 0x000c, 0xaf4: 0x000c, 0xaf5: 0x000c, + 0xaf6: 0x000c, 0xaf7: 0x000c, 0xaf8: 0x000c, 0xaf9: 0x000c, 0xafa: 0x000c, + 0xaff: 0x0004, + // Block 0x2c, offset 0xb00 + 0xb07: 0x000c, 0xb08: 0x000c, 0xb09: 0x000c, 0xb0a: 0x000c, 0xb0b: 0x000c, + 0xb0c: 0x000c, 0xb0d: 0x000c, 0xb0e: 0x000c, + // Block 0x2d, offset 0xb40 + 0xb71: 0x000c, 0xb74: 0x000c, 0xb75: 0x000c, + 0xb76: 0x000c, 0xb77: 0x000c, 0xb78: 0x000c, 0xb79: 0x000c, 0xb7b: 0x000c, + 0xb7c: 0x000c, + // Block 0x2e, offset 0xb80 + 0xb88: 0x000c, 0xb89: 0x000c, 0xb8a: 0x000c, 0xb8b: 0x000c, + 0xb8c: 0x000c, 0xb8d: 0x000c, + // Block 0x2f, offset 0xbc0 + 0xbd8: 0x000c, 0xbd9: 0x000c, + 0xbf5: 0x000c, + 0xbf7: 0x000c, 0xbf9: 0x000c, 0xbfa: 0x003a, 0xbfb: 0x002a, + 0xbfc: 0x003a, 0xbfd: 0x002a, + // Block 0x30, offset 0xc00 + 0xc31: 0x000c, 0xc32: 0x000c, 0xc33: 0x000c, 0xc34: 0x000c, 0xc35: 0x000c, + 0xc36: 0x000c, 0xc37: 0x000c, 0xc38: 0x000c, 0xc39: 0x000c, 0xc3a: 0x000c, 0xc3b: 0x000c, + 0xc3c: 0x000c, 0xc3d: 0x000c, 0xc3e: 0x000c, + // Block 0x31, offset 0xc40 + 0xc40: 0x000c, 0xc41: 0x000c, 0xc42: 0x000c, 0xc43: 0x000c, 0xc44: 0x000c, + 0xc46: 0x000c, 0xc47: 0x000c, + 0xc4d: 0x000c, 0xc4e: 0x000c, 0xc4f: 0x000c, 0xc50: 0x000c, 0xc51: 0x000c, + 0xc52: 0x000c, 0xc53: 0x000c, 0xc54: 0x000c, 0xc55: 0x000c, 0xc56: 0x000c, 0xc57: 0x000c, + 0xc59: 0x000c, 0xc5a: 0x000c, 0xc5b: 0x000c, 0xc5c: 0x000c, 0xc5d: 0x000c, + 0xc5e: 0x000c, 0xc5f: 0x000c, 0xc60: 0x000c, 0xc61: 0x000c, 0xc62: 0x000c, 0xc63: 0x000c, + 0xc64: 0x000c, 0xc65: 0x000c, 0xc66: 0x000c, 0xc67: 0x000c, 0xc68: 0x000c, 0xc69: 0x000c, + 0xc6a: 0x000c, 0xc6b: 0x000c, 0xc6c: 0x000c, 0xc6d: 0x000c, 0xc6e: 0x000c, 0xc6f: 0x000c, + 0xc70: 0x000c, 0xc71: 0x000c, 0xc72: 0x000c, 0xc73: 0x000c, 0xc74: 0x000c, 0xc75: 0x000c, + 0xc76: 0x000c, 0xc77: 0x000c, 0xc78: 0x000c, 0xc79: 0x000c, 0xc7a: 0x000c, 0xc7b: 0x000c, + 0xc7c: 0x000c, + // Block 0x32, offset 0xc80 + 0xc86: 0x000c, + // Block 0x33, offset 0xcc0 + 0xced: 0x000c, 0xcee: 0x000c, 0xcef: 0x000c, + 0xcf0: 0x000c, 0xcf2: 0x000c, 0xcf3: 0x000c, 0xcf4: 0x000c, 0xcf5: 0x000c, + 0xcf6: 0x000c, 0xcf7: 0x000c, 0xcf9: 0x000c, 0xcfa: 0x000c, + 0xcfd: 0x000c, 0xcfe: 0x000c, + // Block 0x34, offset 0xd00 + 0xd18: 0x000c, 0xd19: 0x000c, + 0xd1e: 0x000c, 0xd1f: 0x000c, 0xd20: 0x000c, + 0xd31: 0x000c, 0xd32: 0x000c, 0xd33: 0x000c, 0xd34: 0x000c, + // Block 0x35, offset 0xd40 + 0xd42: 0x000c, 0xd45: 0x000c, + 0xd46: 0x000c, + 0xd4d: 0x000c, + 0xd5d: 0x000c, + // Block 0x36, offset 0xd80 + 0xd9d: 0x000c, + 0xd9e: 0x000c, 0xd9f: 0x000c, + // Block 0x37, offset 0xdc0 + 0xdd0: 0x000a, 0xdd1: 0x000a, + 0xdd2: 0x000a, 0xdd3: 0x000a, 0xdd4: 0x000a, 0xdd5: 0x000a, 0xdd6: 0x000a, 0xdd7: 0x000a, + 0xdd8: 0x000a, 0xdd9: 0x000a, + // Block 0x38, offset 0xe00 + 0xe00: 0x000a, + // Block 0x39, offset 0xe40 + 0xe40: 0x0009, + 0xe5b: 0x007a, 0xe5c: 0x006a, + // Block 0x3a, offset 0xe80 + 0xe92: 0x000c, 0xe93: 0x000c, 0xe94: 0x000c, + 0xeb2: 0x000c, 0xeb3: 0x000c, 0xeb4: 0x000c, + // Block 0x3b, offset 0xec0 + 0xed2: 0x000c, 0xed3: 0x000c, + 0xef2: 0x000c, 0xef3: 0x000c, + // Block 0x3c, offset 0xf00 + 0xf34: 0x000c, 0xf35: 0x000c, + 0xf37: 0x000c, 0xf38: 0x000c, 0xf39: 0x000c, 0xf3a: 0x000c, 0xf3b: 0x000c, + 0xf3c: 0x000c, 0xf3d: 0x000c, + // Block 0x3d, offset 0xf40 + 0xf46: 0x000c, 0xf49: 0x000c, 0xf4a: 0x000c, 0xf4b: 0x000c, + 0xf4c: 0x000c, 0xf4d: 0x000c, 0xf4e: 0x000c, 0xf4f: 0x000c, 0xf50: 0x000c, 0xf51: 0x000c, + 0xf52: 0x000c, 0xf53: 0x000c, + 0xf5b: 0x0004, 0xf5d: 0x000c, + 0xf70: 0x000a, 0xf71: 0x000a, 0xf72: 0x000a, 0xf73: 0x000a, 0xf74: 0x000a, 0xf75: 0x000a, + 0xf76: 0x000a, 0xf77: 0x000a, 0xf78: 0x000a, 0xf79: 0x000a, + // Block 0x3e, offset 0xf80 + 0xf80: 0x000a, 0xf81: 0x000a, 0xf82: 0x000a, 0xf83: 0x000a, 0xf84: 0x000a, 0xf85: 0x000a, + 0xf86: 0x000a, 0xf87: 0x000a, 0xf88: 0x000a, 0xf89: 0x000a, 0xf8a: 0x000a, 0xf8b: 0x000c, + 0xf8c: 0x000c, 0xf8d: 0x000c, 0xf8e: 0x000b, + // Block 0x3f, offset 0xfc0 + 0xfc5: 0x000c, + 0xfc6: 0x000c, + 0xfe9: 0x000c, + // Block 0x40, offset 0x1000 + 0x1020: 0x000c, 0x1021: 0x000c, 0x1022: 0x000c, + 0x1027: 0x000c, 0x1028: 0x000c, + 0x1032: 0x000c, + 0x1039: 0x000c, 0x103a: 0x000c, 0x103b: 0x000c, + // Block 0x41, offset 0x1040 + 0x1040: 0x000a, 0x1044: 0x000a, 0x1045: 0x000a, + // Block 0x42, offset 0x1080 + 0x109e: 0x000a, 0x109f: 0x000a, 0x10a0: 0x000a, 0x10a1: 0x000a, 0x10a2: 0x000a, 0x10a3: 0x000a, + 0x10a4: 0x000a, 0x10a5: 0x000a, 0x10a6: 0x000a, 0x10a7: 0x000a, 0x10a8: 0x000a, 0x10a9: 0x000a, + 0x10aa: 0x000a, 0x10ab: 0x000a, 0x10ac: 0x000a, 0x10ad: 0x000a, 0x10ae: 0x000a, 0x10af: 0x000a, + 0x10b0: 0x000a, 0x10b1: 0x000a, 0x10b2: 0x000a, 0x10b3: 0x000a, 0x10b4: 0x000a, 0x10b5: 0x000a, + 0x10b6: 0x000a, 0x10b7: 0x000a, 0x10b8: 0x000a, 0x10b9: 0x000a, 0x10ba: 0x000a, 0x10bb: 0x000a, + 0x10bc: 0x000a, 0x10bd: 0x000a, 0x10be: 0x000a, 0x10bf: 0x000a, + // Block 0x43, offset 0x10c0 + 0x10d7: 0x000c, + 0x10d8: 0x000c, 0x10db: 0x000c, + // Block 0x44, offset 0x1100 + 0x1116: 0x000c, + 0x1118: 0x000c, 0x1119: 0x000c, 0x111a: 0x000c, 0x111b: 0x000c, 0x111c: 0x000c, 0x111d: 0x000c, + 0x111e: 0x000c, 0x1120: 0x000c, 0x1122: 0x000c, + 0x1125: 0x000c, 0x1126: 0x000c, 0x1127: 0x000c, 0x1128: 0x000c, 0x1129: 0x000c, + 0x112a: 0x000c, 0x112b: 0x000c, 0x112c: 0x000c, + 0x1133: 0x000c, 0x1134: 0x000c, 0x1135: 0x000c, + 0x1136: 0x000c, 0x1137: 0x000c, 0x1138: 0x000c, 0x1139: 0x000c, 0x113a: 0x000c, 0x113b: 0x000c, + 0x113c: 0x000c, 0x113f: 0x000c, + // Block 0x45, offset 0x1140 + 0x1170: 0x000c, 0x1171: 0x000c, 0x1172: 0x000c, 0x1173: 0x000c, 0x1174: 0x000c, 0x1175: 0x000c, + 0x1176: 0x000c, 0x1177: 0x000c, 0x1178: 0x000c, 0x1179: 0x000c, 0x117a: 0x000c, 0x117b: 0x000c, + 0x117c: 0x000c, 0x117d: 0x000c, 0x117e: 0x000c, + // Block 0x46, offset 0x1180 + 0x1180: 0x000c, 0x1181: 0x000c, 0x1182: 0x000c, 0x1183: 0x000c, + 0x11b4: 0x000c, + 0x11b6: 0x000c, 0x11b7: 0x000c, 0x11b8: 0x000c, 0x11b9: 0x000c, 0x11ba: 0x000c, + 0x11bc: 0x000c, + // Block 0x47, offset 0x11c0 + 0x11c2: 0x000c, + 0x11eb: 0x000c, 0x11ec: 0x000c, 0x11ed: 0x000c, 0x11ee: 0x000c, 0x11ef: 0x000c, + 0x11f0: 0x000c, 0x11f1: 0x000c, 0x11f2: 0x000c, 0x11f3: 0x000c, + // Block 0x48, offset 0x1200 + 0x1200: 0x000c, 0x1201: 0x000c, + 0x1222: 0x000c, 0x1223: 0x000c, + 0x1224: 0x000c, 0x1225: 0x000c, 0x1228: 0x000c, 0x1229: 0x000c, + 0x122b: 0x000c, 0x122c: 0x000c, 0x122d: 0x000c, + // Block 0x49, offset 0x1240 + 0x1266: 0x000c, 0x1268: 0x000c, 0x1269: 0x000c, + 0x126d: 0x000c, 0x126f: 0x000c, + 0x1270: 0x000c, 0x1271: 0x000c, + // Block 0x4a, offset 0x1280 + 0x12ac: 0x000c, 0x12ad: 0x000c, 0x12ae: 0x000c, 0x12af: 0x000c, + 0x12b0: 0x000c, 0x12b1: 0x000c, 0x12b2: 0x000c, 0x12b3: 0x000c, + 0x12b6: 0x000c, 0x12b7: 0x000c, + // Block 0x4b, offset 0x12c0 + 0x12d0: 0x000c, 0x12d1: 0x000c, + 0x12d2: 0x000c, 0x12d4: 0x000c, 0x12d5: 0x000c, 0x12d6: 0x000c, 0x12d7: 0x000c, + 0x12d8: 0x000c, 0x12d9: 0x000c, 0x12da: 0x000c, 0x12db: 0x000c, 0x12dc: 0x000c, 0x12dd: 0x000c, + 0x12de: 0x000c, 0x12df: 0x000c, 0x12e0: 0x000c, 0x12e2: 0x000c, 0x12e3: 0x000c, + 0x12e4: 0x000c, 0x12e5: 0x000c, 0x12e6: 0x000c, 0x12e7: 0x000c, 0x12e8: 0x000c, + 0x12ed: 0x000c, + 0x12f4: 0x000c, + 0x12f8: 0x000c, 0x12f9: 0x000c, + // Block 0x4c, offset 0x1300 + 0x1300: 0x000c, 0x1301: 0x000c, 0x1302: 0x000c, 0x1303: 0x000c, 0x1304: 0x000c, 0x1305: 0x000c, + 0x1306: 0x000c, 0x1307: 0x000c, 0x1308: 0x000c, 0x1309: 0x000c, 0x130a: 0x000c, 0x130b: 0x000c, + 0x130c: 0x000c, 0x130d: 0x000c, 0x130e: 0x000c, 0x130f: 0x000c, 0x1310: 0x000c, 0x1311: 0x000c, + 0x1312: 0x000c, 0x1313: 0x000c, 0x1314: 0x000c, 0x1315: 0x000c, 0x1316: 0x000c, 0x1317: 0x000c, + 0x1318: 0x000c, 0x1319: 0x000c, 0x131a: 0x000c, 0x131b: 0x000c, 0x131c: 0x000c, 0x131d: 0x000c, + 0x131e: 0x000c, 0x131f: 0x000c, 0x1320: 0x000c, 0x1321: 0x000c, 0x1322: 0x000c, 0x1323: 0x000c, + 0x1324: 0x000c, 0x1325: 0x000c, 0x1326: 0x000c, 0x1327: 0x000c, 0x1328: 0x000c, 0x1329: 0x000c, + 0x132a: 0x000c, 0x132b: 0x000c, 0x132c: 0x000c, 0x132d: 0x000c, 0x132e: 0x000c, 0x132f: 0x000c, + 0x1330: 0x000c, 0x1331: 0x000c, 0x1332: 0x000c, 0x1333: 0x000c, 0x1334: 0x000c, 0x1335: 0x000c, + 0x1336: 0x000c, 0x1337: 0x000c, 0x1338: 0x000c, 0x1339: 0x000c, 0x133b: 0x000c, + 0x133c: 0x000c, 0x133d: 0x000c, 0x133e: 0x000c, 0x133f: 0x000c, + // Block 0x4d, offset 0x1340 + 0x137d: 0x000a, 0x137f: 0x000a, + // Block 0x4e, offset 0x1380 + 0x1380: 0x000a, 0x1381: 0x000a, + 0x138d: 0x000a, 0x138e: 0x000a, 0x138f: 0x000a, + 0x139d: 0x000a, + 0x139e: 0x000a, 0x139f: 0x000a, + 0x13ad: 0x000a, 0x13ae: 0x000a, 0x13af: 0x000a, + 0x13bd: 0x000a, 0x13be: 0x000a, + // Block 0x4f, offset 0x13c0 + 0x13c0: 0x0009, 0x13c1: 0x0009, 0x13c2: 0x0009, 0x13c3: 0x0009, 0x13c4: 0x0009, 0x13c5: 0x0009, + 0x13c6: 0x0009, 0x13c7: 0x0009, 0x13c8: 0x0009, 0x13c9: 0x0009, 0x13ca: 0x0009, 0x13cb: 0x000b, + 0x13cc: 0x000b, 0x13cd: 0x000b, 0x13cf: 0x0001, 0x13d0: 0x000a, 0x13d1: 0x000a, + 0x13d2: 0x000a, 0x13d3: 0x000a, 0x13d4: 0x000a, 0x13d5: 0x000a, 0x13d6: 0x000a, 0x13d7: 0x000a, + 0x13d8: 0x000a, 0x13d9: 0x000a, 0x13da: 0x000a, 0x13db: 0x000a, 0x13dc: 0x000a, 0x13dd: 0x000a, + 0x13de: 0x000a, 0x13df: 0x000a, 0x13e0: 0x000a, 0x13e1: 0x000a, 0x13e2: 0x000a, 0x13e3: 0x000a, + 0x13e4: 0x000a, 0x13e5: 0x000a, 0x13e6: 0x000a, 0x13e7: 0x000a, 0x13e8: 0x0009, 0x13e9: 0x0007, + 0x13ea: 0x000e, 0x13eb: 0x000e, 0x13ec: 0x000e, 0x13ed: 0x000e, 0x13ee: 0x000e, 0x13ef: 0x0006, + 0x13f0: 0x0004, 0x13f1: 0x0004, 0x13f2: 0x0004, 0x13f3: 0x0004, 0x13f4: 0x0004, 0x13f5: 0x000a, + 0x13f6: 0x000a, 0x13f7: 0x000a, 0x13f8: 0x000a, 0x13f9: 0x000a, 0x13fa: 0x000a, 0x13fb: 0x000a, + 0x13fc: 0x000a, 0x13fd: 0x000a, 0x13fe: 0x000a, 0x13ff: 0x000a, + // Block 0x50, offset 0x1400 + 0x1400: 0x000a, 0x1401: 0x000a, 0x1402: 0x000a, 0x1403: 0x000a, 0x1404: 0x0006, 0x1405: 0x009a, + 0x1406: 0x008a, 0x1407: 0x000a, 0x1408: 0x000a, 0x1409: 0x000a, 0x140a: 0x000a, 0x140b: 0x000a, + 0x140c: 0x000a, 0x140d: 0x000a, 0x140e: 0x000a, 0x140f: 0x000a, 0x1410: 0x000a, 0x1411: 0x000a, + 0x1412: 0x000a, 0x1413: 0x000a, 0x1414: 0x000a, 0x1415: 0x000a, 0x1416: 0x000a, 0x1417: 0x000a, + 0x1418: 0x000a, 0x1419: 0x000a, 0x141a: 0x000a, 0x141b: 0x000a, 0x141c: 0x000a, 0x141d: 0x000a, + 0x141e: 0x000a, 0x141f: 0x0009, 0x1420: 0x000b, 0x1421: 0x000b, 0x1422: 0x000b, 0x1423: 0x000b, + 0x1424: 0x000b, 0x1425: 0x000b, 0x1426: 0x000e, 0x1427: 0x000e, 0x1428: 0x000e, 0x1429: 0x000e, + 0x142a: 0x000b, 0x142b: 0x000b, 0x142c: 0x000b, 0x142d: 0x000b, 0x142e: 0x000b, 0x142f: 0x000b, + 0x1430: 0x0002, 0x1434: 0x0002, 0x1435: 0x0002, + 0x1436: 0x0002, 0x1437: 0x0002, 0x1438: 0x0002, 0x1439: 0x0002, 0x143a: 0x0003, 0x143b: 0x0003, + 0x143c: 0x000a, 0x143d: 0x009a, 0x143e: 0x008a, + // Block 0x51, offset 0x1440 + 0x1440: 0x0002, 0x1441: 0x0002, 0x1442: 0x0002, 0x1443: 0x0002, 0x1444: 0x0002, 0x1445: 0x0002, + 0x1446: 0x0002, 0x1447: 0x0002, 0x1448: 0x0002, 0x1449: 0x0002, 0x144a: 0x0003, 0x144b: 0x0003, + 0x144c: 0x000a, 0x144d: 0x009a, 0x144e: 0x008a, + 0x1460: 0x0004, 0x1461: 0x0004, 0x1462: 0x0004, 0x1463: 0x0004, + 0x1464: 0x0004, 0x1465: 0x0004, 0x1466: 0x0004, 0x1467: 0x0004, 0x1468: 0x0004, 0x1469: 0x0004, + 0x146a: 0x0004, 0x146b: 0x0004, 0x146c: 0x0004, 0x146d: 0x0004, 0x146e: 0x0004, 0x146f: 0x0004, + 0x1470: 0x0004, 0x1471: 0x0004, 0x1472: 0x0004, 0x1473: 0x0004, 0x1474: 0x0004, 0x1475: 0x0004, + 0x1476: 0x0004, 0x1477: 0x0004, 0x1478: 0x0004, 0x1479: 0x0004, 0x147a: 0x0004, 0x147b: 0x0004, + 0x147c: 0x0004, 0x147d: 0x0004, 0x147e: 0x0004, 0x147f: 0x0004, + // Block 0x52, offset 0x1480 + 0x1480: 0x0004, 0x1481: 0x0004, 0x1482: 0x0004, 0x1483: 0x0004, 0x1484: 0x0004, 0x1485: 0x0004, + 0x1486: 0x0004, 0x1487: 0x0004, 0x1488: 0x0004, 0x1489: 0x0004, 0x148a: 0x0004, 0x148b: 0x0004, + 0x148c: 0x0004, 0x148d: 0x0004, 0x148e: 0x0004, 0x148f: 0x0004, 0x1490: 0x000c, 0x1491: 0x000c, + 0x1492: 0x000c, 0x1493: 0x000c, 0x1494: 0x000c, 0x1495: 0x000c, 0x1496: 0x000c, 0x1497: 0x000c, + 0x1498: 0x000c, 0x1499: 0x000c, 0x149a: 0x000c, 0x149b: 0x000c, 0x149c: 0x000c, 0x149d: 0x000c, + 0x149e: 0x000c, 0x149f: 0x000c, 0x14a0: 0x000c, 0x14a1: 0x000c, 0x14a2: 0x000c, 0x14a3: 0x000c, + 0x14a4: 0x000c, 0x14a5: 0x000c, 0x14a6: 0x000c, 0x14a7: 0x000c, 0x14a8: 0x000c, 0x14a9: 0x000c, + 0x14aa: 0x000c, 0x14ab: 0x000c, 0x14ac: 0x000c, 0x14ad: 0x000c, 0x14ae: 0x000c, 0x14af: 0x000c, + 0x14b0: 0x000c, + // Block 0x53, offset 0x14c0 + 0x14c0: 0x000a, 0x14c1: 0x000a, 0x14c3: 0x000a, 0x14c4: 0x000a, 0x14c5: 0x000a, + 0x14c6: 0x000a, 0x14c8: 0x000a, 0x14c9: 0x000a, + 0x14d4: 0x000a, 0x14d6: 0x000a, 0x14d7: 0x000a, + 0x14d8: 0x000a, + 0x14de: 0x000a, 0x14df: 0x000a, 0x14e0: 0x000a, 0x14e1: 0x000a, 0x14e2: 0x000a, 0x14e3: 0x000a, + 0x14e5: 0x000a, 0x14e7: 0x000a, 0x14e9: 0x000a, + 0x14ee: 0x0004, + 0x14fa: 0x000a, 0x14fb: 0x000a, + // Block 0x54, offset 0x1500 + 0x1500: 0x000a, 0x1501: 0x000a, 0x1502: 0x000a, 0x1503: 0x000a, 0x1504: 0x000a, + 0x150a: 0x000a, 0x150b: 0x000a, + 0x150c: 0x000a, 0x150d: 0x000a, 0x1510: 0x000a, 0x1511: 0x000a, + 0x1512: 0x000a, 0x1513: 0x000a, 0x1514: 0x000a, 0x1515: 0x000a, 0x1516: 0x000a, 0x1517: 0x000a, + 0x1518: 0x000a, 0x1519: 0x000a, 0x151a: 0x000a, 0x151b: 0x000a, 0x151c: 0x000a, 0x151d: 0x000a, + 0x151e: 0x000a, 0x151f: 0x000a, + // Block 0x55, offset 0x1540 + 0x1549: 0x000a, 0x154a: 0x000a, 0x154b: 0x000a, + 0x1550: 0x000a, 0x1551: 0x000a, + 0x1552: 0x000a, 0x1553: 0x000a, 0x1554: 0x000a, 0x1555: 0x000a, 0x1556: 0x000a, 0x1557: 0x000a, + 0x1558: 0x000a, 0x1559: 0x000a, 0x155a: 0x000a, 0x155b: 0x000a, 0x155c: 0x000a, 0x155d: 0x000a, + 0x155e: 0x000a, 0x155f: 0x000a, 0x1560: 0x000a, 0x1561: 0x000a, 0x1562: 0x000a, 0x1563: 0x000a, + 0x1564: 0x000a, 0x1565: 0x000a, 0x1566: 0x000a, 0x1567: 0x000a, 0x1568: 0x000a, 0x1569: 0x000a, + 0x156a: 0x000a, 0x156b: 0x000a, 0x156c: 0x000a, 0x156d: 0x000a, 0x156e: 0x000a, 0x156f: 0x000a, + 0x1570: 0x000a, 0x1571: 0x000a, 0x1572: 0x000a, 0x1573: 0x000a, 0x1574: 0x000a, 0x1575: 0x000a, + 0x1576: 0x000a, 0x1577: 0x000a, 0x1578: 0x000a, 0x1579: 0x000a, 0x157a: 0x000a, 0x157b: 0x000a, + 0x157c: 0x000a, 0x157d: 0x000a, 0x157e: 0x000a, 0x157f: 0x000a, + // Block 0x56, offset 0x1580 + 0x1580: 0x000a, 0x1581: 0x000a, 0x1582: 0x000a, 0x1583: 0x000a, 0x1584: 0x000a, 0x1585: 0x000a, + 0x1586: 0x000a, 0x1587: 0x000a, 0x1588: 0x000a, 0x1589: 0x000a, 0x158a: 0x000a, 0x158b: 0x000a, + 0x158c: 0x000a, 0x158d: 0x000a, 0x158e: 0x000a, 0x158f: 0x000a, 0x1590: 0x000a, 0x1591: 0x000a, + 0x1592: 0x000a, 0x1593: 0x000a, 0x1594: 0x000a, 0x1595: 0x000a, 0x1596: 0x000a, 0x1597: 0x000a, + 0x1598: 0x000a, 0x1599: 0x000a, 0x159a: 0x000a, 0x159b: 0x000a, 0x159c: 0x000a, 0x159d: 0x000a, + 0x159e: 0x000a, 0x159f: 0x000a, 0x15a0: 0x000a, 0x15a1: 0x000a, 0x15a2: 0x000a, 0x15a3: 0x000a, + 0x15a4: 0x000a, 0x15a5: 0x000a, 0x15a6: 0x000a, 0x15a7: 0x000a, 0x15a8: 0x000a, 0x15a9: 0x000a, + 0x15aa: 0x000a, 0x15ab: 0x000a, 0x15ac: 0x000a, 0x15ad: 0x000a, 0x15ae: 0x000a, 0x15af: 0x000a, + 0x15b0: 0x000a, 0x15b1: 0x000a, 0x15b2: 0x000a, 0x15b3: 0x000a, 0x15b4: 0x000a, 0x15b5: 0x000a, + 0x15b6: 0x000a, 0x15b7: 0x000a, 0x15b8: 0x000a, 0x15b9: 0x000a, 0x15ba: 0x000a, 0x15bb: 0x000a, + 0x15bc: 0x000a, 0x15bd: 0x000a, 0x15be: 0x000a, 0x15bf: 0x000a, + // Block 0x57, offset 0x15c0 + 0x15c0: 0x000a, 0x15c1: 0x000a, 0x15c2: 0x000a, 0x15c3: 0x000a, 0x15c4: 0x000a, 0x15c5: 0x000a, + 0x15c6: 0x000a, 0x15c7: 0x000a, 0x15c8: 0x000a, 0x15c9: 0x000a, 0x15ca: 0x000a, 0x15cb: 0x000a, + 0x15cc: 0x000a, 0x15cd: 0x000a, 0x15ce: 0x000a, 0x15cf: 0x000a, 0x15d0: 0x000a, 0x15d1: 0x000a, + 0x15d2: 0x0003, 0x15d3: 0x0004, 0x15d4: 0x000a, 0x15d5: 0x000a, 0x15d6: 0x000a, 0x15d7: 0x000a, + 0x15d8: 0x000a, 0x15d9: 0x000a, 0x15da: 0x000a, 0x15db: 0x000a, 0x15dc: 0x000a, 0x15dd: 0x000a, + 0x15de: 0x000a, 0x15df: 0x000a, 0x15e0: 0x000a, 0x15e1: 0x000a, 0x15e2: 0x000a, 0x15e3: 0x000a, + 0x15e4: 0x000a, 0x15e5: 0x000a, 0x15e6: 0x000a, 0x15e7: 0x000a, 0x15e8: 0x000a, 0x15e9: 0x000a, + 0x15ea: 0x000a, 0x15eb: 0x000a, 0x15ec: 0x000a, 0x15ed: 0x000a, 0x15ee: 0x000a, 0x15ef: 0x000a, + 0x15f0: 0x000a, 0x15f1: 0x000a, 0x15f2: 0x000a, 0x15f3: 0x000a, 0x15f4: 0x000a, 0x15f5: 0x000a, + 0x15f6: 0x000a, 0x15f7: 0x000a, 0x15f8: 0x000a, 0x15f9: 0x000a, 0x15fa: 0x000a, 0x15fb: 0x000a, + 0x15fc: 0x000a, 0x15fd: 0x000a, 0x15fe: 0x000a, 0x15ff: 0x000a, + // Block 0x58, offset 0x1600 + 0x1600: 0x000a, 0x1601: 0x000a, 0x1602: 0x000a, 0x1603: 0x000a, 0x1604: 0x000a, 0x1605: 0x000a, + 0x1606: 0x000a, 0x1607: 0x000a, 0x1608: 0x003a, 0x1609: 0x002a, 0x160a: 0x003a, 0x160b: 0x002a, + 0x160c: 0x000a, 0x160d: 0x000a, 0x160e: 0x000a, 0x160f: 0x000a, 0x1610: 0x000a, 0x1611: 0x000a, + 0x1612: 0x000a, 0x1613: 0x000a, 0x1614: 0x000a, 0x1615: 0x000a, 0x1616: 0x000a, 0x1617: 0x000a, + 0x1618: 0x000a, 0x1619: 0x000a, 0x161a: 0x000a, 0x161b: 0x000a, 0x161c: 0x000a, 0x161d: 0x000a, + 0x161e: 0x000a, 0x161f: 0x000a, 0x1620: 0x000a, 0x1621: 0x000a, 0x1622: 0x000a, 0x1623: 0x000a, + 0x1624: 0x000a, 0x1625: 0x000a, 0x1626: 0x000a, 0x1627: 0x000a, 0x1628: 0x000a, 0x1629: 0x009a, + 0x162a: 0x008a, 0x162b: 0x000a, 0x162c: 0x000a, 0x162d: 0x000a, 0x162e: 0x000a, 0x162f: 0x000a, + 0x1630: 0x000a, 0x1631: 0x000a, 0x1632: 0x000a, 0x1633: 0x000a, 0x1634: 0x000a, 0x1635: 0x000a, + // Block 0x59, offset 0x1640 + 0x167b: 0x000a, + 0x167c: 0x000a, 0x167d: 0x000a, 0x167e: 0x000a, 0x167f: 0x000a, + // Block 0x5a, offset 0x1680 + 0x1680: 0x000a, 0x1681: 0x000a, 0x1682: 0x000a, 0x1683: 0x000a, 0x1684: 0x000a, 0x1685: 0x000a, + 0x1686: 0x000a, 0x1687: 0x000a, 0x1688: 0x000a, 0x1689: 0x000a, 0x168a: 0x000a, 0x168b: 0x000a, + 0x168c: 0x000a, 0x168d: 0x000a, 0x168e: 0x000a, 0x168f: 0x000a, 0x1690: 0x000a, 0x1691: 0x000a, + 0x1692: 0x000a, 0x1693: 0x000a, 0x1694: 0x000a, 0x1696: 0x000a, 0x1697: 0x000a, + 0x1698: 0x000a, 0x1699: 0x000a, 0x169a: 0x000a, 0x169b: 0x000a, 0x169c: 0x000a, 0x169d: 0x000a, + 0x169e: 0x000a, 0x169f: 0x000a, 0x16a0: 0x000a, 0x16a1: 0x000a, 0x16a2: 0x000a, 0x16a3: 0x000a, + 0x16a4: 0x000a, 0x16a5: 0x000a, 0x16a6: 0x000a, 0x16a7: 0x000a, 0x16a8: 0x000a, 0x16a9: 0x000a, + 0x16aa: 0x000a, 0x16ab: 0x000a, 0x16ac: 0x000a, 0x16ad: 0x000a, 0x16ae: 0x000a, 0x16af: 0x000a, + 0x16b0: 0x000a, 0x16b1: 0x000a, 0x16b2: 0x000a, 0x16b3: 0x000a, 0x16b4: 0x000a, 0x16b5: 0x000a, + 0x16b6: 0x000a, 0x16b7: 0x000a, 0x16b8: 0x000a, 0x16b9: 0x000a, 0x16ba: 0x000a, 0x16bb: 0x000a, + 0x16bc: 0x000a, 0x16bd: 0x000a, 0x16be: 0x000a, 0x16bf: 0x000a, + // Block 0x5b, offset 0x16c0 + 0x16c0: 0x000a, 0x16c1: 0x000a, 0x16c2: 0x000a, 0x16c3: 0x000a, 0x16c4: 0x000a, 0x16c5: 0x000a, + 0x16c6: 0x000a, 0x16c7: 0x000a, 0x16c8: 0x000a, 0x16c9: 0x000a, 0x16ca: 0x000a, 0x16cb: 0x000a, + 0x16cc: 0x000a, 0x16cd: 0x000a, 0x16ce: 0x000a, 0x16cf: 0x000a, 0x16d0: 0x000a, 0x16d1: 0x000a, + 0x16d2: 0x000a, 0x16d3: 0x000a, 0x16d4: 0x000a, 0x16d5: 0x000a, 0x16d6: 0x000a, 0x16d7: 0x000a, + 0x16d8: 0x000a, 0x16d9: 0x000a, 0x16da: 0x000a, 0x16db: 0x000a, 0x16dc: 0x000a, 0x16dd: 0x000a, + 0x16de: 0x000a, 0x16df: 0x000a, 0x16e0: 0x000a, 0x16e1: 0x000a, 0x16e2: 0x000a, 0x16e3: 0x000a, + 0x16e4: 0x000a, 0x16e5: 0x000a, 0x16e6: 0x000a, + // Block 0x5c, offset 0x1700 + 0x1700: 0x000a, 0x1701: 0x000a, 0x1702: 0x000a, 0x1703: 0x000a, 0x1704: 0x000a, 0x1705: 0x000a, + 0x1706: 0x000a, 0x1707: 0x000a, 0x1708: 0x000a, 0x1709: 0x000a, 0x170a: 0x000a, + 0x1720: 0x000a, 0x1721: 0x000a, 0x1722: 0x000a, 0x1723: 0x000a, + 0x1724: 0x000a, 0x1725: 0x000a, 0x1726: 0x000a, 0x1727: 0x000a, 0x1728: 0x000a, 0x1729: 0x000a, + 0x172a: 0x000a, 0x172b: 0x000a, 0x172c: 0x000a, 0x172d: 0x000a, 0x172e: 0x000a, 0x172f: 0x000a, + 0x1730: 0x000a, 0x1731: 0x000a, 0x1732: 0x000a, 0x1733: 0x000a, 0x1734: 0x000a, 0x1735: 0x000a, + 0x1736: 0x000a, 0x1737: 0x000a, 0x1738: 0x000a, 0x1739: 0x000a, 0x173a: 0x000a, 0x173b: 0x000a, + 0x173c: 0x000a, 0x173d: 0x000a, 0x173e: 0x000a, 0x173f: 0x000a, + // Block 0x5d, offset 0x1740 + 0x1740: 0x000a, 0x1741: 0x000a, 0x1742: 0x000a, 0x1743: 0x000a, 0x1744: 0x000a, 0x1745: 0x000a, + 0x1746: 0x000a, 0x1747: 0x000a, 0x1748: 0x0002, 0x1749: 0x0002, 0x174a: 0x0002, 0x174b: 0x0002, + 0x174c: 0x0002, 0x174d: 0x0002, 0x174e: 0x0002, 0x174f: 0x0002, 0x1750: 0x0002, 0x1751: 0x0002, + 0x1752: 0x0002, 0x1753: 0x0002, 0x1754: 0x0002, 0x1755: 0x0002, 0x1756: 0x0002, 0x1757: 0x0002, + 0x1758: 0x0002, 0x1759: 0x0002, 0x175a: 0x0002, 0x175b: 0x0002, + // Block 0x5e, offset 0x1780 + 0x17aa: 0x000a, 0x17ab: 0x000a, 0x17ac: 0x000a, 0x17ad: 0x000a, 0x17ae: 0x000a, 0x17af: 0x000a, + 0x17b0: 0x000a, 0x17b1: 0x000a, 0x17b2: 0x000a, 0x17b3: 0x000a, 0x17b4: 0x000a, 0x17b5: 0x000a, + 0x17b6: 0x000a, 0x17b7: 0x000a, 0x17b8: 0x000a, 0x17b9: 0x000a, 0x17ba: 0x000a, 0x17bb: 0x000a, + 0x17bc: 0x000a, 0x17bd: 0x000a, 0x17be: 0x000a, 0x17bf: 0x000a, + // Block 0x5f, offset 0x17c0 + 0x17c0: 0x000a, 0x17c1: 0x000a, 0x17c2: 0x000a, 0x17c3: 0x000a, 0x17c4: 0x000a, 0x17c5: 0x000a, + 0x17c6: 0x000a, 0x17c7: 0x000a, 0x17c8: 0x000a, 0x17c9: 0x000a, 0x17ca: 0x000a, 0x17cb: 0x000a, + 0x17cc: 0x000a, 0x17cd: 0x000a, 0x17ce: 0x000a, 0x17cf: 0x000a, 0x17d0: 0x000a, 0x17d1: 0x000a, + 0x17d2: 0x000a, 0x17d3: 0x000a, 0x17d4: 0x000a, 0x17d5: 0x000a, 0x17d6: 0x000a, 0x17d7: 0x000a, + 0x17d8: 0x000a, 0x17d9: 0x000a, 0x17da: 0x000a, 0x17db: 0x000a, 0x17dc: 0x000a, 0x17dd: 0x000a, + 0x17de: 0x000a, 0x17df: 0x000a, 0x17e0: 0x000a, 0x17e1: 0x000a, 0x17e2: 0x000a, 0x17e3: 0x000a, + 0x17e4: 0x000a, 0x17e5: 0x000a, 0x17e6: 0x000a, 0x17e7: 0x000a, 0x17e8: 0x000a, 0x17e9: 0x000a, + 0x17ea: 0x000a, 0x17eb: 0x000a, 0x17ed: 0x000a, 0x17ee: 0x000a, 0x17ef: 0x000a, + 0x17f0: 0x000a, 0x17f1: 0x000a, 0x17f2: 0x000a, 0x17f3: 0x000a, 0x17f4: 0x000a, 0x17f5: 0x000a, + 0x17f6: 0x000a, 0x17f7: 0x000a, 0x17f8: 0x000a, 0x17f9: 0x000a, 0x17fa: 0x000a, 0x17fb: 0x000a, + 0x17fc: 0x000a, 0x17fd: 0x000a, 0x17fe: 0x000a, 0x17ff: 0x000a, + // Block 0x60, offset 0x1800 + 0x1800: 0x000a, 0x1801: 0x000a, 0x1802: 0x000a, 0x1803: 0x000a, 0x1804: 0x000a, 0x1805: 0x000a, + 0x1806: 0x000a, 0x1807: 0x000a, 0x1808: 0x000a, 0x1809: 0x000a, 0x180a: 0x000a, 0x180b: 0x000a, + 0x180c: 0x000a, 0x180d: 0x000a, 0x180e: 0x000a, 0x180f: 0x000a, 0x1810: 0x000a, 0x1811: 0x000a, + 0x1812: 0x000a, 0x1813: 0x000a, 0x1814: 0x000a, 0x1815: 0x000a, 0x1816: 0x000a, 0x1817: 0x000a, + 0x1818: 0x000a, 0x1819: 0x000a, 0x181a: 0x000a, 0x181b: 0x000a, 0x181c: 0x000a, 0x181d: 0x000a, + 0x181e: 0x000a, 0x181f: 0x000a, 0x1820: 0x000a, 0x1821: 0x000a, 0x1822: 0x000a, 0x1823: 0x000a, + 0x1824: 0x000a, 0x1825: 0x000a, 0x1826: 0x000a, 0x1827: 0x000a, 0x1828: 0x003a, 0x1829: 0x002a, + 0x182a: 0x003a, 0x182b: 0x002a, 0x182c: 0x003a, 0x182d: 0x002a, 0x182e: 0x003a, 0x182f: 0x002a, + 0x1830: 0x003a, 0x1831: 0x002a, 0x1832: 0x003a, 0x1833: 0x002a, 0x1834: 0x003a, 0x1835: 0x002a, + 0x1836: 0x000a, 0x1837: 0x000a, 0x1838: 0x000a, 0x1839: 0x000a, 0x183a: 0x000a, 0x183b: 0x000a, + 0x183c: 0x000a, 0x183d: 0x000a, 0x183e: 0x000a, 0x183f: 0x000a, + // Block 0x61, offset 0x1840 + 0x1840: 0x000a, 0x1841: 0x000a, 0x1842: 0x000a, 0x1843: 0x000a, 0x1844: 0x000a, 0x1845: 0x009a, + 0x1846: 0x008a, 0x1847: 0x000a, 0x1848: 0x000a, 0x1849: 0x000a, 0x184a: 0x000a, 0x184b: 0x000a, + 0x184c: 0x000a, 0x184d: 0x000a, 0x184e: 0x000a, 0x184f: 0x000a, 0x1850: 0x000a, 0x1851: 0x000a, + 0x1852: 0x000a, 0x1853: 0x000a, 0x1854: 0x000a, 0x1855: 0x000a, 0x1856: 0x000a, 0x1857: 0x000a, + 0x1858: 0x000a, 0x1859: 0x000a, 0x185a: 0x000a, 0x185b: 0x000a, 0x185c: 0x000a, 0x185d: 0x000a, + 0x185e: 0x000a, 0x185f: 0x000a, 0x1860: 0x000a, 0x1861: 0x000a, 0x1862: 0x000a, 0x1863: 0x000a, + 0x1864: 0x000a, 0x1865: 0x000a, 0x1866: 0x003a, 0x1867: 0x002a, 0x1868: 0x003a, 0x1869: 0x002a, + 0x186a: 0x003a, 0x186b: 0x002a, 0x186c: 0x003a, 0x186d: 0x002a, 0x186e: 0x003a, 0x186f: 0x002a, + 0x1870: 0x000a, 0x1871: 0x000a, 0x1872: 0x000a, 0x1873: 0x000a, 0x1874: 0x000a, 0x1875: 0x000a, + 0x1876: 0x000a, 0x1877: 0x000a, 0x1878: 0x000a, 0x1879: 0x000a, 0x187a: 0x000a, 0x187b: 0x000a, + 0x187c: 0x000a, 0x187d: 0x000a, 0x187e: 0x000a, 0x187f: 0x000a, + // Block 0x62, offset 0x1880 + 0x1880: 0x000a, 0x1881: 0x000a, 0x1882: 0x000a, 0x1883: 0x007a, 0x1884: 0x006a, 0x1885: 0x009a, + 0x1886: 0x008a, 0x1887: 0x00ba, 0x1888: 0x00aa, 0x1889: 0x009a, 0x188a: 0x008a, 0x188b: 0x007a, + 0x188c: 0x006a, 0x188d: 0x00da, 0x188e: 0x002a, 0x188f: 0x003a, 0x1890: 0x00ca, 0x1891: 0x009a, + 0x1892: 0x008a, 0x1893: 0x007a, 0x1894: 0x006a, 0x1895: 0x009a, 0x1896: 0x008a, 0x1897: 0x00ba, + 0x1898: 0x00aa, 0x1899: 0x000a, 0x189a: 0x000a, 0x189b: 0x000a, 0x189c: 0x000a, 0x189d: 0x000a, + 0x189e: 0x000a, 0x189f: 0x000a, 0x18a0: 0x000a, 0x18a1: 0x000a, 0x18a2: 0x000a, 0x18a3: 0x000a, + 0x18a4: 0x000a, 0x18a5: 0x000a, 0x18a6: 0x000a, 0x18a7: 0x000a, 0x18a8: 0x000a, 0x18a9: 0x000a, + 0x18aa: 0x000a, 0x18ab: 0x000a, 0x18ac: 0x000a, 0x18ad: 0x000a, 0x18ae: 0x000a, 0x18af: 0x000a, + 0x18b0: 0x000a, 0x18b1: 0x000a, 0x18b2: 0x000a, 0x18b3: 0x000a, 0x18b4: 0x000a, 0x18b5: 0x000a, + 0x18b6: 0x000a, 0x18b7: 0x000a, 0x18b8: 0x000a, 0x18b9: 0x000a, 0x18ba: 0x000a, 0x18bb: 0x000a, + 0x18bc: 0x000a, 0x18bd: 0x000a, 0x18be: 0x000a, 0x18bf: 0x000a, + // Block 0x63, offset 0x18c0 + 0x18c0: 0x000a, 0x18c1: 0x000a, 0x18c2: 0x000a, 0x18c3: 0x000a, 0x18c4: 0x000a, 0x18c5: 0x000a, + 0x18c6: 0x000a, 0x18c7: 0x000a, 0x18c8: 0x000a, 0x18c9: 0x000a, 0x18ca: 0x000a, 0x18cb: 0x000a, + 0x18cc: 0x000a, 0x18cd: 0x000a, 0x18ce: 0x000a, 0x18cf: 0x000a, 0x18d0: 0x000a, 0x18d1: 0x000a, + 0x18d2: 0x000a, 0x18d3: 0x000a, 0x18d4: 0x000a, 0x18d5: 0x000a, 0x18d6: 0x000a, 0x18d7: 0x000a, + 0x18d8: 0x003a, 0x18d9: 0x002a, 0x18da: 0x003a, 0x18db: 0x002a, 0x18dc: 0x000a, 0x18dd: 0x000a, + 0x18de: 0x000a, 0x18df: 0x000a, 0x18e0: 0x000a, 0x18e1: 0x000a, 0x18e2: 0x000a, 0x18e3: 0x000a, + 0x18e4: 0x000a, 0x18e5: 0x000a, 0x18e6: 0x000a, 0x18e7: 0x000a, 0x18e8: 0x000a, 0x18e9: 0x000a, + 0x18ea: 0x000a, 0x18eb: 0x000a, 0x18ec: 0x000a, 0x18ed: 0x000a, 0x18ee: 0x000a, 0x18ef: 0x000a, + 0x18f0: 0x000a, 0x18f1: 0x000a, 0x18f2: 0x000a, 0x18f3: 0x000a, 0x18f4: 0x000a, 0x18f5: 0x000a, + 0x18f6: 0x000a, 0x18f7: 0x000a, 0x18f8: 0x000a, 0x18f9: 0x000a, 0x18fa: 0x000a, 0x18fb: 0x000a, + 0x18fc: 0x003a, 0x18fd: 0x002a, 0x18fe: 0x000a, 0x18ff: 0x000a, + // Block 0x64, offset 0x1900 + 0x1900: 0x000a, 0x1901: 0x000a, 0x1902: 0x000a, 0x1903: 0x000a, 0x1904: 0x000a, 0x1905: 0x000a, + 0x1906: 0x000a, 0x1907: 0x000a, 0x1908: 0x000a, 0x1909: 0x000a, 0x190a: 0x000a, 0x190b: 0x000a, + 0x190c: 0x000a, 0x190d: 0x000a, 0x190e: 0x000a, 0x190f: 0x000a, 0x1910: 0x000a, 0x1911: 0x000a, + 0x1912: 0x000a, 0x1913: 0x000a, 0x1914: 0x000a, 0x1915: 0x000a, 0x1916: 0x000a, 0x1917: 0x000a, + 0x1918: 0x000a, 0x1919: 0x000a, 0x191a: 0x000a, 0x191b: 0x000a, 0x191c: 0x000a, 0x191d: 0x000a, + 0x191e: 0x000a, 0x191f: 0x000a, 0x1920: 0x000a, 0x1921: 0x000a, 0x1922: 0x000a, 0x1923: 0x000a, + 0x1924: 0x000a, 0x1925: 0x000a, 0x1926: 0x000a, 0x1927: 0x000a, 0x1928: 0x000a, 0x1929: 0x000a, + 0x192a: 0x000a, 0x192b: 0x000a, 0x192c: 0x000a, 0x192d: 0x000a, 0x192e: 0x000a, 0x192f: 0x000a, + 0x1930: 0x000a, 0x1931: 0x000a, 0x1932: 0x000a, 0x1933: 0x000a, + 0x1936: 0x000a, 0x1937: 0x000a, 0x1938: 0x000a, 0x1939: 0x000a, 0x193a: 0x000a, 0x193b: 0x000a, + 0x193c: 0x000a, 0x193d: 0x000a, 0x193e: 0x000a, 0x193f: 0x000a, + // Block 0x65, offset 0x1940 + 0x1940: 0x000a, 0x1941: 0x000a, 0x1942: 0x000a, 0x1943: 0x000a, 0x1944: 0x000a, 0x1945: 0x000a, + 0x1946: 0x000a, 0x1947: 0x000a, 0x1948: 0x000a, 0x1949: 0x000a, 0x194a: 0x000a, 0x194b: 0x000a, + 0x194c: 0x000a, 0x194d: 0x000a, 0x194e: 0x000a, 0x194f: 0x000a, 0x1950: 0x000a, 0x1951: 0x000a, + 0x1952: 0x000a, 0x1953: 0x000a, 0x1954: 0x000a, 0x1955: 0x000a, + 0x1958: 0x000a, 0x1959: 0x000a, 0x195a: 0x000a, 0x195b: 0x000a, 0x195c: 0x000a, 0x195d: 0x000a, + 0x195e: 0x000a, 0x195f: 0x000a, 0x1960: 0x000a, 0x1961: 0x000a, 0x1962: 0x000a, 0x1963: 0x000a, + 0x1964: 0x000a, 0x1965: 0x000a, 0x1966: 0x000a, 0x1967: 0x000a, 0x1968: 0x000a, 0x1969: 0x000a, + 0x196a: 0x000a, 0x196b: 0x000a, 0x196c: 0x000a, 0x196d: 0x000a, 0x196e: 0x000a, 0x196f: 0x000a, + 0x1970: 0x000a, 0x1971: 0x000a, 0x1972: 0x000a, 0x1973: 0x000a, 0x1974: 0x000a, 0x1975: 0x000a, + 0x1976: 0x000a, 0x1977: 0x000a, 0x1978: 0x000a, 0x1979: 0x000a, + 0x197d: 0x000a, 0x197e: 0x000a, 0x197f: 0x000a, + // Block 0x66, offset 0x1980 + 0x1980: 0x000a, 0x1981: 0x000a, 0x1982: 0x000a, 0x1983: 0x000a, 0x1984: 0x000a, 0x1985: 0x000a, + 0x1986: 0x000a, 0x1987: 0x000a, 0x1988: 0x000a, 0x198a: 0x000a, 0x198b: 0x000a, + 0x198c: 0x000a, 0x198d: 0x000a, 0x198e: 0x000a, 0x198f: 0x000a, 0x1990: 0x000a, 0x1991: 0x000a, + 0x1992: 0x000a, + 0x19ac: 0x000a, 0x19ad: 0x000a, 0x19ae: 0x000a, 0x19af: 0x000a, + // Block 0x67, offset 0x19c0 + 0x19e5: 0x000a, 0x19e6: 0x000a, 0x19e7: 0x000a, 0x19e8: 0x000a, 0x19e9: 0x000a, + 0x19ea: 0x000a, 0x19ef: 0x000c, + 0x19f0: 0x000c, 0x19f1: 0x000c, + 0x19f9: 0x000a, 0x19fa: 0x000a, 0x19fb: 0x000a, + 0x19fc: 0x000a, 0x19fd: 0x000a, 0x19fe: 0x000a, 0x19ff: 0x000a, + // Block 0x68, offset 0x1a00 + 0x1a3f: 0x000c, + // Block 0x69, offset 0x1a40 + 0x1a60: 0x000c, 0x1a61: 0x000c, 0x1a62: 0x000c, 0x1a63: 0x000c, + 0x1a64: 0x000c, 0x1a65: 0x000c, 0x1a66: 0x000c, 0x1a67: 0x000c, 0x1a68: 0x000c, 0x1a69: 0x000c, + 0x1a6a: 0x000c, 0x1a6b: 0x000c, 0x1a6c: 0x000c, 0x1a6d: 0x000c, 0x1a6e: 0x000c, 0x1a6f: 0x000c, + 0x1a70: 0x000c, 0x1a71: 0x000c, 0x1a72: 0x000c, 0x1a73: 0x000c, 0x1a74: 0x000c, 0x1a75: 0x000c, + 0x1a76: 0x000c, 0x1a77: 0x000c, 0x1a78: 0x000c, 0x1a79: 0x000c, 0x1a7a: 0x000c, 0x1a7b: 0x000c, + 0x1a7c: 0x000c, 0x1a7d: 0x000c, 0x1a7e: 0x000c, 0x1a7f: 0x000c, + // Block 0x6a, offset 0x1a80 + 0x1a80: 0x000a, 0x1a81: 0x000a, 0x1a82: 0x000a, 0x1a83: 0x000a, 0x1a84: 0x000a, 0x1a85: 0x000a, + 0x1a86: 0x000a, 0x1a87: 0x000a, 0x1a88: 0x000a, 0x1a89: 0x000a, 0x1a8a: 0x000a, 0x1a8b: 0x000a, + 0x1a8c: 0x000a, 0x1a8d: 0x000a, 0x1a8e: 0x000a, 0x1a8f: 0x000a, 0x1a90: 0x000a, 0x1a91: 0x000a, + 0x1a92: 0x000a, 0x1a93: 0x000a, 0x1a94: 0x000a, 0x1a95: 0x000a, 0x1a96: 0x000a, 0x1a97: 0x000a, + 0x1a98: 0x000a, 0x1a99: 0x000a, 0x1a9a: 0x000a, 0x1a9b: 0x000a, 0x1a9c: 0x000a, 0x1a9d: 0x000a, + 0x1a9e: 0x000a, 0x1a9f: 0x000a, 0x1aa0: 0x000a, 0x1aa1: 0x000a, 0x1aa2: 0x003a, 0x1aa3: 0x002a, + 0x1aa4: 0x003a, 0x1aa5: 0x002a, 0x1aa6: 0x003a, 0x1aa7: 0x002a, 0x1aa8: 0x003a, 0x1aa9: 0x002a, + 0x1aaa: 0x000a, 0x1aab: 0x000a, 0x1aac: 0x000a, 0x1aad: 0x000a, 0x1aae: 0x000a, 0x1aaf: 0x000a, + 0x1ab0: 0x000a, 0x1ab1: 0x000a, 0x1ab2: 0x000a, 0x1ab3: 0x000a, 0x1ab4: 0x000a, 0x1ab5: 0x000a, + 0x1ab6: 0x000a, 0x1ab7: 0x000a, 0x1ab8: 0x000a, 0x1ab9: 0x000a, 0x1aba: 0x000a, 0x1abb: 0x000a, + 0x1abc: 0x000a, 0x1abd: 0x000a, 0x1abe: 0x000a, 0x1abf: 0x000a, + // Block 0x6b, offset 0x1ac0 + 0x1ac0: 0x000a, 0x1ac1: 0x000a, 0x1ac2: 0x000a, 0x1ac3: 0x000a, 0x1ac4: 0x000a, 0x1ac5: 0x000a, + 0x1ac6: 0x000a, 0x1ac7: 0x000a, 0x1ac8: 0x000a, 0x1ac9: 0x000a, + // Block 0x6c, offset 0x1b00 + 0x1b00: 0x000a, 0x1b01: 0x000a, 0x1b02: 0x000a, 0x1b03: 0x000a, 0x1b04: 0x000a, 0x1b05: 0x000a, + 0x1b06: 0x000a, 0x1b07: 0x000a, 0x1b08: 0x000a, 0x1b09: 0x000a, 0x1b0a: 0x000a, 0x1b0b: 0x000a, + 0x1b0c: 0x000a, 0x1b0d: 0x000a, 0x1b0e: 0x000a, 0x1b0f: 0x000a, 0x1b10: 0x000a, 0x1b11: 0x000a, + 0x1b12: 0x000a, 0x1b13: 0x000a, 0x1b14: 0x000a, 0x1b15: 0x000a, 0x1b16: 0x000a, 0x1b17: 0x000a, + 0x1b18: 0x000a, 0x1b19: 0x000a, 0x1b1b: 0x000a, 0x1b1c: 0x000a, 0x1b1d: 0x000a, + 0x1b1e: 0x000a, 0x1b1f: 0x000a, 0x1b20: 0x000a, 0x1b21: 0x000a, 0x1b22: 0x000a, 0x1b23: 0x000a, + 0x1b24: 0x000a, 0x1b25: 0x000a, 0x1b26: 0x000a, 0x1b27: 0x000a, 0x1b28: 0x000a, 0x1b29: 0x000a, + 0x1b2a: 0x000a, 0x1b2b: 0x000a, 0x1b2c: 0x000a, 0x1b2d: 0x000a, 0x1b2e: 0x000a, 0x1b2f: 0x000a, + 0x1b30: 0x000a, 0x1b31: 0x000a, 0x1b32: 0x000a, 0x1b33: 0x000a, 0x1b34: 0x000a, 0x1b35: 0x000a, + 0x1b36: 0x000a, 0x1b37: 0x000a, 0x1b38: 0x000a, 0x1b39: 0x000a, 0x1b3a: 0x000a, 0x1b3b: 0x000a, + 0x1b3c: 0x000a, 0x1b3d: 0x000a, 0x1b3e: 0x000a, 0x1b3f: 0x000a, + // Block 0x6d, offset 0x1b40 + 0x1b40: 0x000a, 0x1b41: 0x000a, 0x1b42: 0x000a, 0x1b43: 0x000a, 0x1b44: 0x000a, 0x1b45: 0x000a, + 0x1b46: 0x000a, 0x1b47: 0x000a, 0x1b48: 0x000a, 0x1b49: 0x000a, 0x1b4a: 0x000a, 0x1b4b: 0x000a, + 0x1b4c: 0x000a, 0x1b4d: 0x000a, 0x1b4e: 0x000a, 0x1b4f: 0x000a, 0x1b50: 0x000a, 0x1b51: 0x000a, + 0x1b52: 0x000a, 0x1b53: 0x000a, 0x1b54: 0x000a, 0x1b55: 0x000a, 0x1b56: 0x000a, 0x1b57: 0x000a, + 0x1b58: 0x000a, 0x1b59: 0x000a, 0x1b5a: 0x000a, 0x1b5b: 0x000a, 0x1b5c: 0x000a, 0x1b5d: 0x000a, + 0x1b5e: 0x000a, 0x1b5f: 0x000a, 0x1b60: 0x000a, 0x1b61: 0x000a, 0x1b62: 0x000a, 0x1b63: 0x000a, + 0x1b64: 0x000a, 0x1b65: 0x000a, 0x1b66: 0x000a, 0x1b67: 0x000a, 0x1b68: 0x000a, 0x1b69: 0x000a, + 0x1b6a: 0x000a, 0x1b6b: 0x000a, 0x1b6c: 0x000a, 0x1b6d: 0x000a, 0x1b6e: 0x000a, 0x1b6f: 0x000a, + 0x1b70: 0x000a, 0x1b71: 0x000a, 0x1b72: 0x000a, 0x1b73: 0x000a, + // Block 0x6e, offset 0x1b80 + 0x1b80: 0x000a, 0x1b81: 0x000a, 0x1b82: 0x000a, 0x1b83: 0x000a, 0x1b84: 0x000a, 0x1b85: 0x000a, + 0x1b86: 0x000a, 0x1b87: 0x000a, 0x1b88: 0x000a, 0x1b89: 0x000a, 0x1b8a: 0x000a, 0x1b8b: 0x000a, + 0x1b8c: 0x000a, 0x1b8d: 0x000a, 0x1b8e: 0x000a, 0x1b8f: 0x000a, 0x1b90: 0x000a, 0x1b91: 0x000a, + 0x1b92: 0x000a, 0x1b93: 0x000a, 0x1b94: 0x000a, 0x1b95: 0x000a, + 0x1bb0: 0x000a, 0x1bb1: 0x000a, 0x1bb2: 0x000a, 0x1bb3: 0x000a, 0x1bb4: 0x000a, 0x1bb5: 0x000a, + 0x1bb6: 0x000a, 0x1bb7: 0x000a, 0x1bb8: 0x000a, 0x1bb9: 0x000a, 0x1bba: 0x000a, 0x1bbb: 0x000a, + // Block 0x6f, offset 0x1bc0 + 0x1bc0: 0x0009, 0x1bc1: 0x000a, 0x1bc2: 0x000a, 0x1bc3: 0x000a, 0x1bc4: 0x000a, + 0x1bc8: 0x003a, 0x1bc9: 0x002a, 0x1bca: 0x003a, 0x1bcb: 0x002a, + 0x1bcc: 0x003a, 0x1bcd: 0x002a, 0x1bce: 0x003a, 0x1bcf: 0x002a, 0x1bd0: 0x003a, 0x1bd1: 0x002a, + 0x1bd2: 0x000a, 0x1bd3: 0x000a, 0x1bd4: 0x003a, 0x1bd5: 0x002a, 0x1bd6: 0x003a, 0x1bd7: 0x002a, + 0x1bd8: 0x003a, 0x1bd9: 0x002a, 0x1bda: 0x003a, 0x1bdb: 0x002a, 0x1bdc: 0x000a, 0x1bdd: 0x000a, + 0x1bde: 0x000a, 0x1bdf: 0x000a, 0x1be0: 0x000a, + 0x1bea: 0x000c, 0x1beb: 0x000c, 0x1bec: 0x000c, 0x1bed: 0x000c, + 0x1bf0: 0x000a, + 0x1bf6: 0x000a, 0x1bf7: 0x000a, + 0x1bfd: 0x000a, 0x1bfe: 0x000a, 0x1bff: 0x000a, + // Block 0x70, offset 0x1c00 + 0x1c19: 0x000c, 0x1c1a: 0x000c, 0x1c1b: 0x000a, 0x1c1c: 0x000a, + 0x1c20: 0x000a, + // Block 0x71, offset 0x1c40 + 0x1c7b: 0x000a, + // Block 0x72, offset 0x1c80 + 0x1c80: 0x000a, 0x1c81: 0x000a, 0x1c82: 0x000a, 0x1c83: 0x000a, 0x1c84: 0x000a, 0x1c85: 0x000a, + 0x1c86: 0x000a, 0x1c87: 0x000a, 0x1c88: 0x000a, 0x1c89: 0x000a, 0x1c8a: 0x000a, 0x1c8b: 0x000a, + 0x1c8c: 0x000a, 0x1c8d: 0x000a, 0x1c8e: 0x000a, 0x1c8f: 0x000a, 0x1c90: 0x000a, 0x1c91: 0x000a, + 0x1c92: 0x000a, 0x1c93: 0x000a, 0x1c94: 0x000a, 0x1c95: 0x000a, 0x1c96: 0x000a, 0x1c97: 0x000a, + 0x1c98: 0x000a, 0x1c99: 0x000a, 0x1c9a: 0x000a, 0x1c9b: 0x000a, 0x1c9c: 0x000a, 0x1c9d: 0x000a, + 0x1c9e: 0x000a, 0x1c9f: 0x000a, 0x1ca0: 0x000a, 0x1ca1: 0x000a, 0x1ca2: 0x000a, 0x1ca3: 0x000a, + // Block 0x73, offset 0x1cc0 + 0x1cdd: 0x000a, + 0x1cde: 0x000a, + // Block 0x74, offset 0x1d00 + 0x1d10: 0x000a, 0x1d11: 0x000a, + 0x1d12: 0x000a, 0x1d13: 0x000a, 0x1d14: 0x000a, 0x1d15: 0x000a, 0x1d16: 0x000a, 0x1d17: 0x000a, + 0x1d18: 0x000a, 0x1d19: 0x000a, 0x1d1a: 0x000a, 0x1d1b: 0x000a, 0x1d1c: 0x000a, 0x1d1d: 0x000a, + 0x1d1e: 0x000a, 0x1d1f: 0x000a, + 0x1d3c: 0x000a, 0x1d3d: 0x000a, 0x1d3e: 0x000a, + // Block 0x75, offset 0x1d40 + 0x1d71: 0x000a, 0x1d72: 0x000a, 0x1d73: 0x000a, 0x1d74: 0x000a, 0x1d75: 0x000a, + 0x1d76: 0x000a, 0x1d77: 0x000a, 0x1d78: 0x000a, 0x1d79: 0x000a, 0x1d7a: 0x000a, 0x1d7b: 0x000a, + 0x1d7c: 0x000a, 0x1d7d: 0x000a, 0x1d7e: 0x000a, 0x1d7f: 0x000a, + // Block 0x76, offset 0x1d80 + 0x1d8c: 0x000a, 0x1d8d: 0x000a, 0x1d8e: 0x000a, 0x1d8f: 0x000a, + // Block 0x77, offset 0x1dc0 + 0x1df7: 0x000a, 0x1df8: 0x000a, 0x1df9: 0x000a, 0x1dfa: 0x000a, + // Block 0x78, offset 0x1e00 + 0x1e1e: 0x000a, 0x1e1f: 0x000a, + 0x1e3f: 0x000a, + // Block 0x79, offset 0x1e40 + 0x1e50: 0x000a, 0x1e51: 0x000a, + 0x1e52: 0x000a, 0x1e53: 0x000a, 0x1e54: 0x000a, 0x1e55: 0x000a, 0x1e56: 0x000a, 0x1e57: 0x000a, + 0x1e58: 0x000a, 0x1e59: 0x000a, 0x1e5a: 0x000a, 0x1e5b: 0x000a, 0x1e5c: 0x000a, 0x1e5d: 0x000a, + 0x1e5e: 0x000a, 0x1e5f: 0x000a, 0x1e60: 0x000a, 0x1e61: 0x000a, 0x1e62: 0x000a, 0x1e63: 0x000a, + 0x1e64: 0x000a, 0x1e65: 0x000a, 0x1e66: 0x000a, 0x1e67: 0x000a, 0x1e68: 0x000a, 0x1e69: 0x000a, + 0x1e6a: 0x000a, 0x1e6b: 0x000a, 0x1e6c: 0x000a, 0x1e6d: 0x000a, 0x1e6e: 0x000a, 0x1e6f: 0x000a, + 0x1e70: 0x000a, 0x1e71: 0x000a, 0x1e72: 0x000a, 0x1e73: 0x000a, 0x1e74: 0x000a, 0x1e75: 0x000a, + 0x1e76: 0x000a, 0x1e77: 0x000a, 0x1e78: 0x000a, 0x1e79: 0x000a, 0x1e7a: 0x000a, 0x1e7b: 0x000a, + 0x1e7c: 0x000a, 0x1e7d: 0x000a, 0x1e7e: 0x000a, 0x1e7f: 0x000a, + // Block 0x7a, offset 0x1e80 + 0x1e80: 0x000a, 0x1e81: 0x000a, 0x1e82: 0x000a, 0x1e83: 0x000a, 0x1e84: 0x000a, 0x1e85: 0x000a, + 0x1e86: 0x000a, + // Block 0x7b, offset 0x1ec0 + 0x1ecd: 0x000a, 0x1ece: 0x000a, 0x1ecf: 0x000a, + // Block 0x7c, offset 0x1f00 + 0x1f2f: 0x000c, + 0x1f30: 0x000c, 0x1f31: 0x000c, 0x1f32: 0x000c, 0x1f33: 0x000a, 0x1f34: 0x000c, 0x1f35: 0x000c, + 0x1f36: 0x000c, 0x1f37: 0x000c, 0x1f38: 0x000c, 0x1f39: 0x000c, 0x1f3a: 0x000c, 0x1f3b: 0x000c, + 0x1f3c: 0x000c, 0x1f3d: 0x000c, 0x1f3e: 0x000a, 0x1f3f: 0x000a, + // Block 0x7d, offset 0x1f40 + 0x1f5e: 0x000c, 0x1f5f: 0x000c, + // Block 0x7e, offset 0x1f80 + 0x1fb0: 0x000c, 0x1fb1: 0x000c, + // Block 0x7f, offset 0x1fc0 + 0x1fc0: 0x000a, 0x1fc1: 0x000a, 0x1fc2: 0x000a, 0x1fc3: 0x000a, 0x1fc4: 0x000a, 0x1fc5: 0x000a, + 0x1fc6: 0x000a, 0x1fc7: 0x000a, 0x1fc8: 0x000a, 0x1fc9: 0x000a, 0x1fca: 0x000a, 0x1fcb: 0x000a, + 0x1fcc: 0x000a, 0x1fcd: 0x000a, 0x1fce: 0x000a, 0x1fcf: 0x000a, 0x1fd0: 0x000a, 0x1fd1: 0x000a, + 0x1fd2: 0x000a, 0x1fd3: 0x000a, 0x1fd4: 0x000a, 0x1fd5: 0x000a, 0x1fd6: 0x000a, 0x1fd7: 0x000a, + 0x1fd8: 0x000a, 0x1fd9: 0x000a, 0x1fda: 0x000a, 0x1fdb: 0x000a, 0x1fdc: 0x000a, 0x1fdd: 0x000a, + 0x1fde: 0x000a, 0x1fdf: 0x000a, 0x1fe0: 0x000a, 0x1fe1: 0x000a, + // Block 0x80, offset 0x2000 + 0x2008: 0x000a, + // Block 0x81, offset 0x2040 + 0x2042: 0x000c, + 0x2046: 0x000c, 0x204b: 0x000c, + 0x2065: 0x000c, 0x2066: 0x000c, 0x2068: 0x000a, 0x2069: 0x000a, + 0x206a: 0x000a, 0x206b: 0x000a, + 0x2078: 0x0004, 0x2079: 0x0004, + // Block 0x82, offset 0x2080 + 0x20b4: 0x000a, 0x20b5: 0x000a, + 0x20b6: 0x000a, 0x20b7: 0x000a, + // Block 0x83, offset 0x20c0 + 0x20c4: 0x000c, 0x20c5: 0x000c, + 0x20e0: 0x000c, 0x20e1: 0x000c, 0x20e2: 0x000c, 0x20e3: 0x000c, + 0x20e4: 0x000c, 0x20e5: 0x000c, 0x20e6: 0x000c, 0x20e7: 0x000c, 0x20e8: 0x000c, 0x20e9: 0x000c, + 0x20ea: 0x000c, 0x20eb: 0x000c, 0x20ec: 0x000c, 0x20ed: 0x000c, 0x20ee: 0x000c, 0x20ef: 0x000c, + 0x20f0: 0x000c, 0x20f1: 0x000c, + // Block 0x84, offset 0x2100 + 0x2126: 0x000c, 0x2127: 0x000c, 0x2128: 0x000c, 0x2129: 0x000c, + 0x212a: 0x000c, 0x212b: 0x000c, 0x212c: 0x000c, 0x212d: 0x000c, + // Block 0x85, offset 0x2140 + 0x2147: 0x000c, 0x2148: 0x000c, 0x2149: 0x000c, 0x214a: 0x000c, 0x214b: 0x000c, + 0x214c: 0x000c, 0x214d: 0x000c, 0x214e: 0x000c, 0x214f: 0x000c, 0x2150: 0x000c, 0x2151: 0x000c, + // Block 0x86, offset 0x2180 + 0x2180: 0x000c, 0x2181: 0x000c, 0x2182: 0x000c, + 0x21b3: 0x000c, + 0x21b6: 0x000c, 0x21b7: 0x000c, 0x21b8: 0x000c, 0x21b9: 0x000c, + 0x21bc: 0x000c, + // Block 0x87, offset 0x21c0 + 0x21e5: 0x000c, + // Block 0x88, offset 0x2200 + 0x2229: 0x000c, + 0x222a: 0x000c, 0x222b: 0x000c, 0x222c: 0x000c, 0x222d: 0x000c, 0x222e: 0x000c, + 0x2231: 0x000c, 0x2232: 0x000c, 0x2235: 0x000c, + 0x2236: 0x000c, + // Block 0x89, offset 0x2240 + 0x2243: 0x000c, + 0x224c: 0x000c, + 0x227c: 0x000c, + // Block 0x8a, offset 0x2280 + 0x22b0: 0x000c, 0x22b2: 0x000c, 0x22b3: 0x000c, 0x22b4: 0x000c, + 0x22b7: 0x000c, 0x22b8: 0x000c, + 0x22be: 0x000c, 0x22bf: 0x000c, + // Block 0x8b, offset 0x22c0 + 0x22c1: 0x000c, + 0x22ec: 0x000c, 0x22ed: 0x000c, + 0x22f6: 0x000c, + // Block 0x8c, offset 0x2300 + 0x2325: 0x000c, 0x2328: 0x000c, + 0x232d: 0x000c, + // Block 0x8d, offset 0x2340 + 0x235d: 0x0001, + 0x235e: 0x000c, 0x235f: 0x0001, 0x2360: 0x0001, 0x2361: 0x0001, 0x2362: 0x0001, 0x2363: 0x0001, + 0x2364: 0x0001, 0x2365: 0x0001, 0x2366: 0x0001, 0x2367: 0x0001, 0x2368: 0x0001, 0x2369: 0x0003, + 0x236a: 0x0001, 0x236b: 0x0001, 0x236c: 0x0001, 0x236d: 0x0001, 0x236e: 0x0001, 0x236f: 0x0001, + 0x2370: 0x0001, 0x2371: 0x0001, 0x2372: 0x0001, 0x2373: 0x0001, 0x2374: 0x0001, 0x2375: 0x0001, + 0x2376: 0x0001, 0x2377: 0x0001, 0x2378: 0x0001, 0x2379: 0x0001, 0x237a: 0x0001, 0x237b: 0x0001, + 0x237c: 0x0001, 0x237d: 0x0001, 0x237e: 0x0001, 0x237f: 0x0001, + // Block 0x8e, offset 0x2380 + 0x2380: 0x0001, 0x2381: 0x0001, 0x2382: 0x0001, 0x2383: 0x0001, 0x2384: 0x0001, 0x2385: 0x0001, + 0x2386: 0x0001, 0x2387: 0x0001, 0x2388: 0x0001, 0x2389: 0x0001, 0x238a: 0x0001, 0x238b: 0x0001, + 0x238c: 0x0001, 0x238d: 0x0001, 0x238e: 0x0001, 0x238f: 0x0001, 0x2390: 0x000d, 0x2391: 0x000d, + 0x2392: 0x000d, 0x2393: 0x000d, 0x2394: 0x000d, 0x2395: 0x000d, 0x2396: 0x000d, 0x2397: 0x000d, + 0x2398: 0x000d, 0x2399: 0x000d, 0x239a: 0x000d, 0x239b: 0x000d, 0x239c: 0x000d, 0x239d: 0x000d, + 0x239e: 0x000d, 0x239f: 0x000d, 0x23a0: 0x000d, 0x23a1: 0x000d, 0x23a2: 0x000d, 0x23a3: 0x000d, + 0x23a4: 0x000d, 0x23a5: 0x000d, 0x23a6: 0x000d, 0x23a7: 0x000d, 0x23a8: 0x000d, 0x23a9: 0x000d, + 0x23aa: 0x000d, 0x23ab: 0x000d, 0x23ac: 0x000d, 0x23ad: 0x000d, 0x23ae: 0x000d, 0x23af: 0x000d, + 0x23b0: 0x000d, 0x23b1: 0x000d, 0x23b2: 0x000d, 0x23b3: 0x000d, 0x23b4: 0x000d, 0x23b5: 0x000d, + 0x23b6: 0x000d, 0x23b7: 0x000d, 0x23b8: 0x000d, 0x23b9: 0x000d, 0x23ba: 0x000d, 0x23bb: 0x000d, + 0x23bc: 0x000d, 0x23bd: 0x000d, 0x23be: 0x000d, 0x23bf: 0x000d, + // Block 0x8f, offset 0x23c0 + 0x23c0: 0x000d, 0x23c1: 0x000d, 0x23c2: 0x000d, 0x23c3: 0x000d, 0x23c4: 0x000d, 0x23c5: 0x000d, + 0x23c6: 0x000d, 0x23c7: 0x000d, 0x23c8: 0x000d, 0x23c9: 0x000d, 0x23ca: 0x000d, 0x23cb: 0x000d, + 0x23cc: 0x000d, 0x23cd: 0x000d, 0x23ce: 0x000d, 0x23cf: 0x000d, 0x23d0: 0x000d, 0x23d1: 0x000d, + 0x23d2: 0x000d, 0x23d3: 0x000d, 0x23d4: 0x000d, 0x23d5: 0x000d, 0x23d6: 0x000d, 0x23d7: 0x000d, + 0x23d8: 0x000d, 0x23d9: 0x000d, 0x23da: 0x000d, 0x23db: 0x000d, 0x23dc: 0x000d, 0x23dd: 0x000d, + 0x23de: 0x000d, 0x23df: 0x000d, 0x23e0: 0x000d, 0x23e1: 0x000d, 0x23e2: 0x000d, 0x23e3: 0x000d, + 0x23e4: 0x000d, 0x23e5: 0x000d, 0x23e6: 0x000d, 0x23e7: 0x000d, 0x23e8: 0x000d, 0x23e9: 0x000d, + 0x23ea: 0x000d, 0x23eb: 0x000d, 0x23ec: 0x000d, 0x23ed: 0x000d, 0x23ee: 0x000d, 0x23ef: 0x000d, + 0x23f0: 0x000d, 0x23f1: 0x000d, 0x23f2: 0x000d, 0x23f3: 0x000d, 0x23f4: 0x000d, 0x23f5: 0x000d, + 0x23f6: 0x000d, 0x23f7: 0x000d, 0x23f8: 0x000d, 0x23f9: 0x000d, 0x23fa: 0x000d, 0x23fb: 0x000d, + 0x23fc: 0x000d, 0x23fd: 0x000d, 0x23fe: 0x000a, 0x23ff: 0x000a, + // Block 0x90, offset 0x2400 + 0x2400: 0x000d, 0x2401: 0x000d, 0x2402: 0x000d, 0x2403: 0x000d, 0x2404: 0x000d, 0x2405: 0x000d, + 0x2406: 0x000d, 0x2407: 0x000d, 0x2408: 0x000d, 0x2409: 0x000d, 0x240a: 0x000d, 0x240b: 0x000d, + 0x240c: 0x000d, 0x240d: 0x000d, 0x240e: 0x000d, 0x240f: 0x000d, 0x2410: 0x000b, 0x2411: 0x000b, + 0x2412: 0x000b, 0x2413: 0x000b, 0x2414: 0x000b, 0x2415: 0x000b, 0x2416: 0x000b, 0x2417: 0x000b, + 0x2418: 0x000b, 0x2419: 0x000b, 0x241a: 0x000b, 0x241b: 0x000b, 0x241c: 0x000b, 0x241d: 0x000b, + 0x241e: 0x000b, 0x241f: 0x000b, 0x2420: 0x000b, 0x2421: 0x000b, 0x2422: 0x000b, 0x2423: 0x000b, + 0x2424: 0x000b, 0x2425: 0x000b, 0x2426: 0x000b, 0x2427: 0x000b, 0x2428: 0x000b, 0x2429: 0x000b, + 0x242a: 0x000b, 0x242b: 0x000b, 0x242c: 0x000b, 0x242d: 0x000b, 0x242e: 0x000b, 0x242f: 0x000b, + 0x2430: 0x000d, 0x2431: 0x000d, 0x2432: 0x000d, 0x2433: 0x000d, 0x2434: 0x000d, 0x2435: 0x000d, + 0x2436: 0x000d, 0x2437: 0x000d, 0x2438: 0x000d, 0x2439: 0x000d, 0x243a: 0x000d, 0x243b: 0x000d, + 0x243c: 0x000d, 0x243d: 0x000a, 0x243e: 0x000d, 0x243f: 0x000d, + // Block 0x91, offset 0x2440 + 0x2440: 0x000c, 0x2441: 0x000c, 0x2442: 0x000c, 0x2443: 0x000c, 0x2444: 0x000c, 0x2445: 0x000c, + 0x2446: 0x000c, 0x2447: 0x000c, 0x2448: 0x000c, 0x2449: 0x000c, 0x244a: 0x000c, 0x244b: 0x000c, + 0x244c: 0x000c, 0x244d: 0x000c, 0x244e: 0x000c, 0x244f: 0x000c, 0x2450: 0x000a, 0x2451: 0x000a, + 0x2452: 0x000a, 0x2453: 0x000a, 0x2454: 0x000a, 0x2455: 0x000a, 0x2456: 0x000a, 0x2457: 0x000a, + 0x2458: 0x000a, 0x2459: 0x000a, + 0x2460: 0x000c, 0x2461: 0x000c, 0x2462: 0x000c, 0x2463: 0x000c, + 0x2464: 0x000c, 0x2465: 0x000c, 0x2466: 0x000c, 0x2467: 0x000c, 0x2468: 0x000c, 0x2469: 0x000c, + 0x246a: 0x000c, 0x246b: 0x000c, 0x246c: 0x000c, 0x246d: 0x000c, 0x246e: 0x000c, 0x246f: 0x000c, + 0x2470: 0x000a, 0x2471: 0x000a, 0x2472: 0x000a, 0x2473: 0x000a, 0x2474: 0x000a, 0x2475: 0x000a, + 0x2476: 0x000a, 0x2477: 0x000a, 0x2478: 0x000a, 0x2479: 0x000a, 0x247a: 0x000a, 0x247b: 0x000a, + 0x247c: 0x000a, 0x247d: 0x000a, 0x247e: 0x000a, 0x247f: 0x000a, + // Block 0x92, offset 0x2480 + 0x2480: 0x000a, 0x2481: 0x000a, 0x2482: 0x000a, 0x2483: 0x000a, 0x2484: 0x000a, 0x2485: 0x000a, + 0x2486: 0x000a, 0x2487: 0x000a, 0x2488: 0x000a, 0x2489: 0x000a, 0x248a: 0x000a, 0x248b: 0x000a, + 0x248c: 0x000a, 0x248d: 0x000a, 0x248e: 0x000a, 0x248f: 0x000a, 0x2490: 0x0006, 0x2491: 0x000a, + 0x2492: 0x0006, 0x2494: 0x000a, 0x2495: 0x0006, 0x2496: 0x000a, 0x2497: 0x000a, + 0x2498: 0x000a, 0x2499: 0x009a, 0x249a: 0x008a, 0x249b: 0x007a, 0x249c: 0x006a, 0x249d: 0x009a, + 0x249e: 0x008a, 0x249f: 0x0004, 0x24a0: 0x000a, 0x24a1: 0x000a, 0x24a2: 0x0003, 0x24a3: 0x0003, + 0x24a4: 0x000a, 0x24a5: 0x000a, 0x24a6: 0x000a, 0x24a8: 0x000a, 0x24a9: 0x0004, + 0x24aa: 0x0004, 0x24ab: 0x000a, + 0x24b0: 0x000d, 0x24b1: 0x000d, 0x24b2: 0x000d, 0x24b3: 0x000d, 0x24b4: 0x000d, 0x24b5: 0x000d, + 0x24b6: 0x000d, 0x24b7: 0x000d, 0x24b8: 0x000d, 0x24b9: 0x000d, 0x24ba: 0x000d, 0x24bb: 0x000d, + 0x24bc: 0x000d, 0x24bd: 0x000d, 0x24be: 0x000d, 0x24bf: 0x000d, + // Block 0x93, offset 0x24c0 + 0x24c0: 0x000d, 0x24c1: 0x000d, 0x24c2: 0x000d, 0x24c3: 0x000d, 0x24c4: 0x000d, 0x24c5: 0x000d, + 0x24c6: 0x000d, 0x24c7: 0x000d, 0x24c8: 0x000d, 0x24c9: 0x000d, 0x24ca: 0x000d, 0x24cb: 0x000d, + 0x24cc: 0x000d, 0x24cd: 0x000d, 0x24ce: 0x000d, 0x24cf: 0x000d, 0x24d0: 0x000d, 0x24d1: 0x000d, + 0x24d2: 0x000d, 0x24d3: 0x000d, 0x24d4: 0x000d, 0x24d5: 0x000d, 0x24d6: 0x000d, 0x24d7: 0x000d, + 0x24d8: 0x000d, 0x24d9: 0x000d, 0x24da: 0x000d, 0x24db: 0x000d, 0x24dc: 0x000d, 0x24dd: 0x000d, + 0x24de: 0x000d, 0x24df: 0x000d, 0x24e0: 0x000d, 0x24e1: 0x000d, 0x24e2: 0x000d, 0x24e3: 0x000d, + 0x24e4: 0x000d, 0x24e5: 0x000d, 0x24e6: 0x000d, 0x24e7: 0x000d, 0x24e8: 0x000d, 0x24e9: 0x000d, + 0x24ea: 0x000d, 0x24eb: 0x000d, 0x24ec: 0x000d, 0x24ed: 0x000d, 0x24ee: 0x000d, 0x24ef: 0x000d, + 0x24f0: 0x000d, 0x24f1: 0x000d, 0x24f2: 0x000d, 0x24f3: 0x000d, 0x24f4: 0x000d, 0x24f5: 0x000d, + 0x24f6: 0x000d, 0x24f7: 0x000d, 0x24f8: 0x000d, 0x24f9: 0x000d, 0x24fa: 0x000d, 0x24fb: 0x000d, + 0x24fc: 0x000d, 0x24fd: 0x000d, 0x24fe: 0x000d, 0x24ff: 0x000b, + // Block 0x94, offset 0x2500 + 0x2501: 0x000a, 0x2502: 0x000a, 0x2503: 0x0004, 0x2504: 0x0004, 0x2505: 0x0004, + 0x2506: 0x000a, 0x2507: 0x000a, 0x2508: 0x003a, 0x2509: 0x002a, 0x250a: 0x000a, 0x250b: 0x0003, + 0x250c: 0x0006, 0x250d: 0x0003, 0x250e: 0x0006, 0x250f: 0x0006, 0x2510: 0x0002, 0x2511: 0x0002, + 0x2512: 0x0002, 0x2513: 0x0002, 0x2514: 0x0002, 0x2515: 0x0002, 0x2516: 0x0002, 0x2517: 0x0002, + 0x2518: 0x0002, 0x2519: 0x0002, 0x251a: 0x0006, 0x251b: 0x000a, 0x251c: 0x000a, 0x251d: 0x000a, + 0x251e: 0x000a, 0x251f: 0x000a, 0x2520: 0x000a, + 0x253b: 0x005a, + 0x253c: 0x000a, 0x253d: 0x004a, 0x253e: 0x000a, 0x253f: 0x000a, + // Block 0x95, offset 0x2540 + 0x2540: 0x000a, + 0x255b: 0x005a, 0x255c: 0x000a, 0x255d: 0x004a, + 0x255e: 0x000a, 0x255f: 0x00fa, 0x2560: 0x00ea, 0x2561: 0x000a, 0x2562: 0x003a, 0x2563: 0x002a, + 0x2564: 0x000a, 0x2565: 0x000a, + // Block 0x96, offset 0x2580 + 0x25a0: 0x0004, 0x25a1: 0x0004, 0x25a2: 0x000a, 0x25a3: 0x000a, + 0x25a4: 0x000a, 0x25a5: 0x0004, 0x25a6: 0x0004, 0x25a8: 0x000a, 0x25a9: 0x000a, + 0x25aa: 0x000a, 0x25ab: 0x000a, 0x25ac: 0x000a, 0x25ad: 0x000a, 0x25ae: 0x000a, + 0x25b0: 0x000b, 0x25b1: 0x000b, 0x25b2: 0x000b, 0x25b3: 0x000b, 0x25b4: 0x000b, 0x25b5: 0x000b, + 0x25b6: 0x000b, 0x25b7: 0x000b, 0x25b8: 0x000b, 0x25b9: 0x000a, 0x25ba: 0x000a, 0x25bb: 0x000a, + 0x25bc: 0x000a, 0x25bd: 0x000a, 0x25be: 0x000b, 0x25bf: 0x000b, + // Block 0x97, offset 0x25c0 + 0x25c1: 0x000a, + // Block 0x98, offset 0x2600 + 0x2600: 0x000a, 0x2601: 0x000a, 0x2602: 0x000a, 0x2603: 0x000a, 0x2604: 0x000a, 0x2605: 0x000a, + 0x2606: 0x000a, 0x2607: 0x000a, 0x2608: 0x000a, 0x2609: 0x000a, 0x260a: 0x000a, 0x260b: 0x000a, + 0x260c: 0x000a, 0x2610: 0x000a, 0x2611: 0x000a, + 0x2612: 0x000a, 0x2613: 0x000a, 0x2614: 0x000a, 0x2615: 0x000a, 0x2616: 0x000a, 0x2617: 0x000a, + 0x2618: 0x000a, 0x2619: 0x000a, 0x261a: 0x000a, 0x261b: 0x000a, + 0x2620: 0x000a, + // Block 0x99, offset 0x2640 + 0x267d: 0x000c, + // Block 0x9a, offset 0x2680 + 0x26a0: 0x000c, 0x26a1: 0x0002, 0x26a2: 0x0002, 0x26a3: 0x0002, + 0x26a4: 0x0002, 0x26a5: 0x0002, 0x26a6: 0x0002, 0x26a7: 0x0002, 0x26a8: 0x0002, 0x26a9: 0x0002, + 0x26aa: 0x0002, 0x26ab: 0x0002, 0x26ac: 0x0002, 0x26ad: 0x0002, 0x26ae: 0x0002, 0x26af: 0x0002, + 0x26b0: 0x0002, 0x26b1: 0x0002, 0x26b2: 0x0002, 0x26b3: 0x0002, 0x26b4: 0x0002, 0x26b5: 0x0002, + 0x26b6: 0x0002, 0x26b7: 0x0002, 0x26b8: 0x0002, 0x26b9: 0x0002, 0x26ba: 0x0002, 0x26bb: 0x0002, + // Block 0x9b, offset 0x26c0 + 0x26f6: 0x000c, 0x26f7: 0x000c, 0x26f8: 0x000c, 0x26f9: 0x000c, 0x26fa: 0x000c, + // Block 0x9c, offset 0x2700 + 0x2700: 0x0001, 0x2701: 0x0001, 0x2702: 0x0001, 0x2703: 0x0001, 0x2704: 0x0001, 0x2705: 0x0001, + 0x2706: 0x0001, 0x2707: 0x0001, 0x2708: 0x0001, 0x2709: 0x0001, 0x270a: 0x0001, 0x270b: 0x0001, + 0x270c: 0x0001, 0x270d: 0x0001, 0x270e: 0x0001, 0x270f: 0x0001, 0x2710: 0x0001, 0x2711: 0x0001, + 0x2712: 0x0001, 0x2713: 0x0001, 0x2714: 0x0001, 0x2715: 0x0001, 0x2716: 0x0001, 0x2717: 0x0001, + 0x2718: 0x0001, 0x2719: 0x0001, 0x271a: 0x0001, 0x271b: 0x0001, 0x271c: 0x0001, 0x271d: 0x0001, + 0x271e: 0x0001, 0x271f: 0x0001, 0x2720: 0x0001, 0x2721: 0x0001, 0x2722: 0x0001, 0x2723: 0x0001, + 0x2724: 0x0001, 0x2725: 0x0001, 0x2726: 0x0001, 0x2727: 0x0001, 0x2728: 0x0001, 0x2729: 0x0001, + 0x272a: 0x0001, 0x272b: 0x0001, 0x272c: 0x0001, 0x272d: 0x0001, 0x272e: 0x0001, 0x272f: 0x0001, + 0x2730: 0x0001, 0x2731: 0x0001, 0x2732: 0x0001, 0x2733: 0x0001, 0x2734: 0x0001, 0x2735: 0x0001, + 0x2736: 0x0001, 0x2737: 0x0001, 0x2738: 0x0001, 0x2739: 0x0001, 0x273a: 0x0001, 0x273b: 0x0001, + 0x273c: 0x0001, 0x273d: 0x0001, 0x273e: 0x0001, 0x273f: 0x0001, + // Block 0x9d, offset 0x2740 + 0x2740: 0x0001, 0x2741: 0x0001, 0x2742: 0x0001, 0x2743: 0x0001, 0x2744: 0x0001, 0x2745: 0x0001, + 0x2746: 0x0001, 0x2747: 0x0001, 0x2748: 0x0001, 0x2749: 0x0001, 0x274a: 0x0001, 0x274b: 0x0001, + 0x274c: 0x0001, 0x274d: 0x0001, 0x274e: 0x0001, 0x274f: 0x0001, 0x2750: 0x0001, 0x2751: 0x0001, + 0x2752: 0x0001, 0x2753: 0x0001, 0x2754: 0x0001, 0x2755: 0x0001, 0x2756: 0x0001, 0x2757: 0x0001, + 0x2758: 0x0001, 0x2759: 0x0001, 0x275a: 0x0001, 0x275b: 0x0001, 0x275c: 0x0001, 0x275d: 0x0001, + 0x275e: 0x0001, 0x275f: 0x000a, 0x2760: 0x0001, 0x2761: 0x0001, 0x2762: 0x0001, 0x2763: 0x0001, + 0x2764: 0x0001, 0x2765: 0x0001, 0x2766: 0x0001, 0x2767: 0x0001, 0x2768: 0x0001, 0x2769: 0x0001, + 0x276a: 0x0001, 0x276b: 0x0001, 0x276c: 0x0001, 0x276d: 0x0001, 0x276e: 0x0001, 0x276f: 0x0001, + 0x2770: 0x0001, 0x2771: 0x0001, 0x2772: 0x0001, 0x2773: 0x0001, 0x2774: 0x0001, 0x2775: 0x0001, + 0x2776: 0x0001, 0x2777: 0x0001, 0x2778: 0x0001, 0x2779: 0x0001, 0x277a: 0x0001, 0x277b: 0x0001, + 0x277c: 0x0001, 0x277d: 0x0001, 0x277e: 0x0001, 0x277f: 0x0001, + // Block 0x9e, offset 0x2780 + 0x2780: 0x0001, 0x2781: 0x000c, 0x2782: 0x000c, 0x2783: 0x000c, 0x2784: 0x0001, 0x2785: 0x000c, + 0x2786: 0x000c, 0x2787: 0x0001, 0x2788: 0x0001, 0x2789: 0x0001, 0x278a: 0x0001, 0x278b: 0x0001, + 0x278c: 0x000c, 0x278d: 0x000c, 0x278e: 0x000c, 0x278f: 0x000c, 0x2790: 0x0001, 0x2791: 0x0001, + 0x2792: 0x0001, 0x2793: 0x0001, 0x2794: 0x0001, 0x2795: 0x0001, 0x2796: 0x0001, 0x2797: 0x0001, + 0x2798: 0x0001, 0x2799: 0x0001, 0x279a: 0x0001, 0x279b: 0x0001, 0x279c: 0x0001, 0x279d: 0x0001, + 0x279e: 0x0001, 0x279f: 0x0001, 0x27a0: 0x0001, 0x27a1: 0x0001, 0x27a2: 0x0001, 0x27a3: 0x0001, + 0x27a4: 0x0001, 0x27a5: 0x0001, 0x27a6: 0x0001, 0x27a7: 0x0001, 0x27a8: 0x0001, 0x27a9: 0x0001, + 0x27aa: 0x0001, 0x27ab: 0x0001, 0x27ac: 0x0001, 0x27ad: 0x0001, 0x27ae: 0x0001, 0x27af: 0x0001, + 0x27b0: 0x0001, 0x27b1: 0x0001, 0x27b2: 0x0001, 0x27b3: 0x0001, 0x27b4: 0x0001, 0x27b5: 0x0001, + 0x27b6: 0x0001, 0x27b7: 0x0001, 0x27b8: 0x000c, 0x27b9: 0x000c, 0x27ba: 0x000c, 0x27bb: 0x0001, + 0x27bc: 0x0001, 0x27bd: 0x0001, 0x27be: 0x0001, 0x27bf: 0x000c, + // Block 0x9f, offset 0x27c0 + 0x27c0: 0x0001, 0x27c1: 0x0001, 0x27c2: 0x0001, 0x27c3: 0x0001, 0x27c4: 0x0001, 0x27c5: 0x0001, + 0x27c6: 0x0001, 0x27c7: 0x0001, 0x27c8: 0x0001, 0x27c9: 0x0001, 0x27ca: 0x0001, 0x27cb: 0x0001, + 0x27cc: 0x0001, 0x27cd: 0x0001, 0x27ce: 0x0001, 0x27cf: 0x0001, 0x27d0: 0x0001, 0x27d1: 0x0001, + 0x27d2: 0x0001, 0x27d3: 0x0001, 0x27d4: 0x0001, 0x27d5: 0x0001, 0x27d6: 0x0001, 0x27d7: 0x0001, + 0x27d8: 0x0001, 0x27d9: 0x0001, 0x27da: 0x0001, 0x27db: 0x0001, 0x27dc: 0x0001, 0x27dd: 0x0001, + 0x27de: 0x0001, 0x27df: 0x0001, 0x27e0: 0x0001, 0x27e1: 0x0001, 0x27e2: 0x0001, 0x27e3: 0x0001, + 0x27e4: 0x0001, 0x27e5: 0x000c, 0x27e6: 0x000c, 0x27e7: 0x0001, 0x27e8: 0x0001, 0x27e9: 0x0001, + 0x27ea: 0x0001, 0x27eb: 0x0001, 0x27ec: 0x0001, 0x27ed: 0x0001, 0x27ee: 0x0001, 0x27ef: 0x0001, + 0x27f0: 0x0001, 0x27f1: 0x0001, 0x27f2: 0x0001, 0x27f3: 0x0001, 0x27f4: 0x0001, 0x27f5: 0x0001, + 0x27f6: 0x0001, 0x27f7: 0x0001, 0x27f8: 0x0001, 0x27f9: 0x0001, 0x27fa: 0x0001, 0x27fb: 0x0001, + 0x27fc: 0x0001, 0x27fd: 0x0001, 0x27fe: 0x0001, 0x27ff: 0x0001, + // Block 0xa0, offset 0x2800 + 0x2800: 0x0001, 0x2801: 0x0001, 0x2802: 0x0001, 0x2803: 0x0001, 0x2804: 0x0001, 0x2805: 0x0001, + 0x2806: 0x0001, 0x2807: 0x0001, 0x2808: 0x0001, 0x2809: 0x0001, 0x280a: 0x0001, 0x280b: 0x0001, + 0x280c: 0x0001, 0x280d: 0x0001, 0x280e: 0x0001, 0x280f: 0x0001, 0x2810: 0x0001, 0x2811: 0x0001, + 0x2812: 0x0001, 0x2813: 0x0001, 0x2814: 0x0001, 0x2815: 0x0001, 0x2816: 0x0001, 0x2817: 0x0001, + 0x2818: 0x0001, 0x2819: 0x0001, 0x281a: 0x0001, 0x281b: 0x0001, 0x281c: 0x0001, 0x281d: 0x0001, + 0x281e: 0x0001, 0x281f: 0x0001, 0x2820: 0x0001, 0x2821: 0x0001, 0x2822: 0x0001, 0x2823: 0x0001, + 0x2824: 0x0001, 0x2825: 0x0001, 0x2826: 0x0001, 0x2827: 0x0001, 0x2828: 0x0001, 0x2829: 0x0001, + 0x282a: 0x0001, 0x282b: 0x0001, 0x282c: 0x0001, 0x282d: 0x0001, 0x282e: 0x0001, 0x282f: 0x0001, + 0x2830: 0x0001, 0x2831: 0x0001, 0x2832: 0x0001, 0x2833: 0x0001, 0x2834: 0x0001, 0x2835: 0x0001, + 0x2836: 0x0001, 0x2837: 0x0001, 0x2838: 0x0001, 0x2839: 0x000a, 0x283a: 0x000a, 0x283b: 0x000a, + 0x283c: 0x000a, 0x283d: 0x000a, 0x283e: 0x000a, 0x283f: 0x000a, + // Block 0xa1, offset 0x2840 + 0x2840: 0x0001, 0x2841: 0x0001, 0x2842: 0x0001, 0x2843: 0x0001, 0x2844: 0x0001, 0x2845: 0x0001, + 0x2846: 0x0001, 0x2847: 0x0001, 0x2848: 0x0001, 0x2849: 0x0001, 0x284a: 0x0001, 0x284b: 0x0001, + 0x284c: 0x0001, 0x284d: 0x0001, 0x284e: 0x0001, 0x284f: 0x0001, 0x2850: 0x0001, 0x2851: 0x0001, + 0x2852: 0x0001, 0x2853: 0x0001, 0x2854: 0x0001, 0x2855: 0x0001, 0x2856: 0x0001, 0x2857: 0x0001, + 0x2858: 0x0001, 0x2859: 0x0001, 0x285a: 0x0001, 0x285b: 0x0001, 0x285c: 0x0001, 0x285d: 0x0001, + 0x285e: 0x0001, 0x285f: 0x0001, 0x2860: 0x0005, 0x2861: 0x0005, 0x2862: 0x0005, 0x2863: 0x0005, + 0x2864: 0x0005, 0x2865: 0x0005, 0x2866: 0x0005, 0x2867: 0x0005, 0x2868: 0x0005, 0x2869: 0x0005, + 0x286a: 0x0005, 0x286b: 0x0005, 0x286c: 0x0005, 0x286d: 0x0005, 0x286e: 0x0005, 0x286f: 0x0005, + 0x2870: 0x0005, 0x2871: 0x0005, 0x2872: 0x0005, 0x2873: 0x0005, 0x2874: 0x0005, 0x2875: 0x0005, + 0x2876: 0x0005, 0x2877: 0x0005, 0x2878: 0x0005, 0x2879: 0x0005, 0x287a: 0x0005, 0x287b: 0x0005, + 0x287c: 0x0005, 0x287d: 0x0005, 0x287e: 0x0005, 0x287f: 0x0001, + // Block 0xa2, offset 0x2880 + 0x2881: 0x000c, + 0x28b8: 0x000c, 0x28b9: 0x000c, 0x28ba: 0x000c, 0x28bb: 0x000c, + 0x28bc: 0x000c, 0x28bd: 0x000c, 0x28be: 0x000c, 0x28bf: 0x000c, + // Block 0xa3, offset 0x28c0 + 0x28c0: 0x000c, 0x28c1: 0x000c, 0x28c2: 0x000c, 0x28c3: 0x000c, 0x28c4: 0x000c, 0x28c5: 0x000c, + 0x28c6: 0x000c, + 0x28d2: 0x000a, 0x28d3: 0x000a, 0x28d4: 0x000a, 0x28d5: 0x000a, 0x28d6: 0x000a, 0x28d7: 0x000a, + 0x28d8: 0x000a, 0x28d9: 0x000a, 0x28da: 0x000a, 0x28db: 0x000a, 0x28dc: 0x000a, 0x28dd: 0x000a, + 0x28de: 0x000a, 0x28df: 0x000a, 0x28e0: 0x000a, 0x28e1: 0x000a, 0x28e2: 0x000a, 0x28e3: 0x000a, + 0x28e4: 0x000a, 0x28e5: 0x000a, + 0x28ff: 0x000c, + // Block 0xa4, offset 0x2900 + 0x2900: 0x000c, 0x2901: 0x000c, + 0x2933: 0x000c, 0x2934: 0x000c, 0x2935: 0x000c, + 0x2936: 0x000c, 0x2939: 0x000c, 0x293a: 0x000c, + // Block 0xa5, offset 0x2940 + 0x2940: 0x000c, 0x2941: 0x000c, 0x2942: 0x000c, + 0x2967: 0x000c, 0x2968: 0x000c, 0x2969: 0x000c, + 0x296a: 0x000c, 0x296b: 0x000c, 0x296d: 0x000c, 0x296e: 0x000c, 0x296f: 0x000c, + 0x2970: 0x000c, 0x2971: 0x000c, 0x2972: 0x000c, 0x2973: 0x000c, 0x2974: 0x000c, + // Block 0xa6, offset 0x2980 + 0x29b3: 0x000c, + // Block 0xa7, offset 0x29c0 + 0x29c0: 0x000c, 0x29c1: 0x000c, + 0x29f6: 0x000c, 0x29f7: 0x000c, 0x29f8: 0x000c, 0x29f9: 0x000c, 0x29fa: 0x000c, 0x29fb: 0x000c, + 0x29fc: 0x000c, 0x29fd: 0x000c, 0x29fe: 0x000c, + // Block 0xa8, offset 0x2a00 + 0x2a0a: 0x000c, 0x2a0b: 0x000c, + 0x2a0c: 0x000c, + // Block 0xa9, offset 0x2a40 + 0x2a6f: 0x000c, + 0x2a70: 0x000c, 0x2a71: 0x000c, 0x2a74: 0x000c, + 0x2a76: 0x000c, 0x2a77: 0x000c, + 0x2a7e: 0x000c, + // Block 0xaa, offset 0x2a80 + 0x2a9f: 0x000c, 0x2aa3: 0x000c, + 0x2aa4: 0x000c, 0x2aa5: 0x000c, 0x2aa6: 0x000c, 0x2aa7: 0x000c, 0x2aa8: 0x000c, 0x2aa9: 0x000c, + 0x2aaa: 0x000c, + // Block 0xab, offset 0x2ac0 + 0x2ac0: 0x000c, 0x2ac1: 0x000c, + 0x2afc: 0x000c, + // Block 0xac, offset 0x2b00 + 0x2b00: 0x000c, + 0x2b26: 0x000c, 0x2b27: 0x000c, 0x2b28: 0x000c, 0x2b29: 0x000c, + 0x2b2a: 0x000c, 0x2b2b: 0x000c, 0x2b2c: 0x000c, + 0x2b30: 0x000c, 0x2b31: 0x000c, 0x2b32: 0x000c, 0x2b33: 0x000c, 0x2b34: 0x000c, + // Block 0xad, offset 0x2b40 + 0x2b78: 0x000c, 0x2b79: 0x000c, 0x2b7a: 0x000c, 0x2b7b: 0x000c, + 0x2b7c: 0x000c, 0x2b7d: 0x000c, 0x2b7e: 0x000c, 0x2b7f: 0x000c, + // Block 0xae, offset 0x2b80 + 0x2b82: 0x000c, 0x2b83: 0x000c, 0x2b84: 0x000c, + 0x2b86: 0x000c, + // Block 0xaf, offset 0x2bc0 + 0x2bf3: 0x000c, 0x2bf4: 0x000c, 0x2bf5: 0x000c, + 0x2bf6: 0x000c, 0x2bf7: 0x000c, 0x2bf8: 0x000c, 0x2bfa: 0x000c, + 0x2bff: 0x000c, + // Block 0xb0, offset 0x2c00 + 0x2c00: 0x000c, 0x2c02: 0x000c, 0x2c03: 0x000c, + // Block 0xb1, offset 0x2c40 + 0x2c72: 0x000c, 0x2c73: 0x000c, 0x2c74: 0x000c, 0x2c75: 0x000c, + 0x2c7c: 0x000c, 0x2c7d: 0x000c, 0x2c7f: 0x000c, + // Block 0xb2, offset 0x2c80 + 0x2c80: 0x000c, + 0x2c9c: 0x000c, 0x2c9d: 0x000c, + // Block 0xb3, offset 0x2cc0 + 0x2cf3: 0x000c, 0x2cf4: 0x000c, 0x2cf5: 0x000c, + 0x2cf6: 0x000c, 0x2cf7: 0x000c, 0x2cf8: 0x000c, 0x2cf9: 0x000c, 0x2cfa: 0x000c, + 0x2cfd: 0x000c, 0x2cff: 0x000c, + // Block 0xb4, offset 0x2d00 + 0x2d00: 0x000c, + 0x2d20: 0x000a, 0x2d21: 0x000a, 0x2d22: 0x000a, 0x2d23: 0x000a, + 0x2d24: 0x000a, 0x2d25: 0x000a, 0x2d26: 0x000a, 0x2d27: 0x000a, 0x2d28: 0x000a, 0x2d29: 0x000a, + 0x2d2a: 0x000a, 0x2d2b: 0x000a, 0x2d2c: 0x000a, + // Block 0xb5, offset 0x2d40 + 0x2d6b: 0x000c, 0x2d6d: 0x000c, + 0x2d70: 0x000c, 0x2d71: 0x000c, 0x2d72: 0x000c, 0x2d73: 0x000c, 0x2d74: 0x000c, 0x2d75: 0x000c, + 0x2d77: 0x000c, + // Block 0xb6, offset 0x2d80 + 0x2d9d: 0x000c, + 0x2d9e: 0x000c, 0x2d9f: 0x000c, 0x2da2: 0x000c, 0x2da3: 0x000c, + 0x2da4: 0x000c, 0x2da5: 0x000c, 0x2da7: 0x000c, 0x2da8: 0x000c, 0x2da9: 0x000c, + 0x2daa: 0x000c, 0x2dab: 0x000c, + // Block 0xb7, offset 0x2dc0 + 0x2dc1: 0x000c, 0x2dc2: 0x000c, 0x2dc3: 0x000c, 0x2dc4: 0x000c, 0x2dc5: 0x000c, + 0x2dc6: 0x000c, 0x2dc9: 0x000c, 0x2dca: 0x000c, + 0x2df3: 0x000c, 0x2df4: 0x000c, 0x2df5: 0x000c, + 0x2df6: 0x000c, 0x2df7: 0x000c, 0x2df8: 0x000c, 0x2dfb: 0x000c, + 0x2dfc: 0x000c, 0x2dfd: 0x000c, 0x2dfe: 0x000c, + // Block 0xb8, offset 0x2e00 + 0x2e07: 0x000c, + 0x2e11: 0x000c, + 0x2e12: 0x000c, 0x2e13: 0x000c, 0x2e14: 0x000c, 0x2e15: 0x000c, 0x2e16: 0x000c, + 0x2e19: 0x000c, 0x2e1a: 0x000c, 0x2e1b: 0x000c, + // Block 0xb9, offset 0x2e40 + 0x2e4a: 0x000c, 0x2e4b: 0x000c, + 0x2e4c: 0x000c, 0x2e4d: 0x000c, 0x2e4e: 0x000c, 0x2e4f: 0x000c, 0x2e50: 0x000c, 0x2e51: 0x000c, + 0x2e52: 0x000c, 0x2e53: 0x000c, 0x2e54: 0x000c, 0x2e55: 0x000c, 0x2e56: 0x000c, + 0x2e58: 0x000c, 0x2e59: 0x000c, + // Block 0xba, offset 0x2e80 + 0x2eb0: 0x000c, 0x2eb1: 0x000c, 0x2eb2: 0x000c, 0x2eb3: 0x000c, 0x2eb4: 0x000c, 0x2eb5: 0x000c, + 0x2eb6: 0x000c, 0x2eb8: 0x000c, 0x2eb9: 0x000c, 0x2eba: 0x000c, 0x2ebb: 0x000c, + 0x2ebc: 0x000c, 0x2ebd: 0x000c, + // Block 0xbb, offset 0x2ec0 + 0x2ed2: 0x000c, 0x2ed3: 0x000c, 0x2ed4: 0x000c, 0x2ed5: 0x000c, 0x2ed6: 0x000c, 0x2ed7: 0x000c, + 0x2ed8: 0x000c, 0x2ed9: 0x000c, 0x2eda: 0x000c, 0x2edb: 0x000c, 0x2edc: 0x000c, 0x2edd: 0x000c, + 0x2ede: 0x000c, 0x2edf: 0x000c, 0x2ee0: 0x000c, 0x2ee1: 0x000c, 0x2ee2: 0x000c, 0x2ee3: 0x000c, + 0x2ee4: 0x000c, 0x2ee5: 0x000c, 0x2ee6: 0x000c, 0x2ee7: 0x000c, + 0x2eea: 0x000c, 0x2eeb: 0x000c, 0x2eec: 0x000c, 0x2eed: 0x000c, 0x2eee: 0x000c, 0x2eef: 0x000c, + 0x2ef0: 0x000c, 0x2ef2: 0x000c, 0x2ef3: 0x000c, 0x2ef5: 0x000c, + 0x2ef6: 0x000c, + // Block 0xbc, offset 0x2f00 + 0x2f31: 0x000c, 0x2f32: 0x000c, 0x2f33: 0x000c, 0x2f34: 0x000c, 0x2f35: 0x000c, + 0x2f36: 0x000c, 0x2f3a: 0x000c, + 0x2f3c: 0x000c, 0x2f3d: 0x000c, 0x2f3f: 0x000c, + // Block 0xbd, offset 0x2f40 + 0x2f40: 0x000c, 0x2f41: 0x000c, 0x2f42: 0x000c, 0x2f43: 0x000c, 0x2f44: 0x000c, 0x2f45: 0x000c, + 0x2f47: 0x000c, + // Block 0xbe, offset 0x2f80 + 0x2fb0: 0x000c, 0x2fb1: 0x000c, 0x2fb2: 0x000c, 0x2fb3: 0x000c, 0x2fb4: 0x000c, + // Block 0xbf, offset 0x2fc0 + 0x2ff0: 0x000c, 0x2ff1: 0x000c, 0x2ff2: 0x000c, 0x2ff3: 0x000c, 0x2ff4: 0x000c, 0x2ff5: 0x000c, + 0x2ff6: 0x000c, + // Block 0xc0, offset 0x3000 + 0x300f: 0x000c, 0x3010: 0x000c, 0x3011: 0x000c, + 0x3012: 0x000c, + // Block 0xc1, offset 0x3040 + 0x305d: 0x000c, + 0x305e: 0x000c, 0x3060: 0x000b, 0x3061: 0x000b, 0x3062: 0x000b, 0x3063: 0x000b, + // Block 0xc2, offset 0x3080 + 0x30a7: 0x000c, 0x30a8: 0x000c, 0x30a9: 0x000c, + 0x30b3: 0x000b, 0x30b4: 0x000b, 0x30b5: 0x000b, + 0x30b6: 0x000b, 0x30b7: 0x000b, 0x30b8: 0x000b, 0x30b9: 0x000b, 0x30ba: 0x000b, 0x30bb: 0x000c, + 0x30bc: 0x000c, 0x30bd: 0x000c, 0x30be: 0x000c, 0x30bf: 0x000c, + // Block 0xc3, offset 0x30c0 + 0x30c0: 0x000c, 0x30c1: 0x000c, 0x30c2: 0x000c, 0x30c5: 0x000c, + 0x30c6: 0x000c, 0x30c7: 0x000c, 0x30c8: 0x000c, 0x30c9: 0x000c, 0x30ca: 0x000c, 0x30cb: 0x000c, + 0x30ea: 0x000c, 0x30eb: 0x000c, 0x30ec: 0x000c, 0x30ed: 0x000c, + // Block 0xc4, offset 0x3100 + 0x3100: 0x000a, 0x3101: 0x000a, 0x3102: 0x000c, 0x3103: 0x000c, 0x3104: 0x000c, 0x3105: 0x000a, + // Block 0xc5, offset 0x3140 + 0x3140: 0x000a, 0x3141: 0x000a, 0x3142: 0x000a, 0x3143: 0x000a, 0x3144: 0x000a, 0x3145: 0x000a, + 0x3146: 0x000a, 0x3147: 0x000a, 0x3148: 0x000a, 0x3149: 0x000a, 0x314a: 0x000a, 0x314b: 0x000a, + 0x314c: 0x000a, 0x314d: 0x000a, 0x314e: 0x000a, 0x314f: 0x000a, 0x3150: 0x000a, 0x3151: 0x000a, + 0x3152: 0x000a, 0x3153: 0x000a, 0x3154: 0x000a, 0x3155: 0x000a, 0x3156: 0x000a, + // Block 0xc6, offset 0x3180 + 0x319b: 0x000a, + // Block 0xc7, offset 0x31c0 + 0x31d5: 0x000a, + // Block 0xc8, offset 0x3200 + 0x320f: 0x000a, + // Block 0xc9, offset 0x3240 + 0x3249: 0x000a, + // Block 0xca, offset 0x3280 + 0x3283: 0x000a, + 0x328e: 0x0002, 0x328f: 0x0002, 0x3290: 0x0002, 0x3291: 0x0002, + 0x3292: 0x0002, 0x3293: 0x0002, 0x3294: 0x0002, 0x3295: 0x0002, 0x3296: 0x0002, 0x3297: 0x0002, + 0x3298: 0x0002, 0x3299: 0x0002, 0x329a: 0x0002, 0x329b: 0x0002, 0x329c: 0x0002, 0x329d: 0x0002, + 0x329e: 0x0002, 0x329f: 0x0002, 0x32a0: 0x0002, 0x32a1: 0x0002, 0x32a2: 0x0002, 0x32a3: 0x0002, + 0x32a4: 0x0002, 0x32a5: 0x0002, 0x32a6: 0x0002, 0x32a7: 0x0002, 0x32a8: 0x0002, 0x32a9: 0x0002, + 0x32aa: 0x0002, 0x32ab: 0x0002, 0x32ac: 0x0002, 0x32ad: 0x0002, 0x32ae: 0x0002, 0x32af: 0x0002, + 0x32b0: 0x0002, 0x32b1: 0x0002, 0x32b2: 0x0002, 0x32b3: 0x0002, 0x32b4: 0x0002, 0x32b5: 0x0002, + 0x32b6: 0x0002, 0x32b7: 0x0002, 0x32b8: 0x0002, 0x32b9: 0x0002, 0x32ba: 0x0002, 0x32bb: 0x0002, + 0x32bc: 0x0002, 0x32bd: 0x0002, 0x32be: 0x0002, 0x32bf: 0x0002, + // Block 0xcb, offset 0x32c0 + 0x32c0: 0x000c, 0x32c1: 0x000c, 0x32c2: 0x000c, 0x32c3: 0x000c, 0x32c4: 0x000c, 0x32c5: 0x000c, + 0x32c6: 0x000c, 0x32c7: 0x000c, 0x32c8: 0x000c, 0x32c9: 0x000c, 0x32ca: 0x000c, 0x32cb: 0x000c, + 0x32cc: 0x000c, 0x32cd: 0x000c, 0x32ce: 0x000c, 0x32cf: 0x000c, 0x32d0: 0x000c, 0x32d1: 0x000c, + 0x32d2: 0x000c, 0x32d3: 0x000c, 0x32d4: 0x000c, 0x32d5: 0x000c, 0x32d6: 0x000c, 0x32d7: 0x000c, + 0x32d8: 0x000c, 0x32d9: 0x000c, 0x32da: 0x000c, 0x32db: 0x000c, 0x32dc: 0x000c, 0x32dd: 0x000c, + 0x32de: 0x000c, 0x32df: 0x000c, 0x32e0: 0x000c, 0x32e1: 0x000c, 0x32e2: 0x000c, 0x32e3: 0x000c, + 0x32e4: 0x000c, 0x32e5: 0x000c, 0x32e6: 0x000c, 0x32e7: 0x000c, 0x32e8: 0x000c, 0x32e9: 0x000c, + 0x32ea: 0x000c, 0x32eb: 0x000c, 0x32ec: 0x000c, 0x32ed: 0x000c, 0x32ee: 0x000c, 0x32ef: 0x000c, + 0x32f0: 0x000c, 0x32f1: 0x000c, 0x32f2: 0x000c, 0x32f3: 0x000c, 0x32f4: 0x000c, 0x32f5: 0x000c, + 0x32f6: 0x000c, 0x32fb: 0x000c, + 0x32fc: 0x000c, 0x32fd: 0x000c, 0x32fe: 0x000c, 0x32ff: 0x000c, + // Block 0xcc, offset 0x3300 + 0x3300: 0x000c, 0x3301: 0x000c, 0x3302: 0x000c, 0x3303: 0x000c, 0x3304: 0x000c, 0x3305: 0x000c, + 0x3306: 0x000c, 0x3307: 0x000c, 0x3308: 0x000c, 0x3309: 0x000c, 0x330a: 0x000c, 0x330b: 0x000c, + 0x330c: 0x000c, 0x330d: 0x000c, 0x330e: 0x000c, 0x330f: 0x000c, 0x3310: 0x000c, 0x3311: 0x000c, + 0x3312: 0x000c, 0x3313: 0x000c, 0x3314: 0x000c, 0x3315: 0x000c, 0x3316: 0x000c, 0x3317: 0x000c, + 0x3318: 0x000c, 0x3319: 0x000c, 0x331a: 0x000c, 0x331b: 0x000c, 0x331c: 0x000c, 0x331d: 0x000c, + 0x331e: 0x000c, 0x331f: 0x000c, 0x3320: 0x000c, 0x3321: 0x000c, 0x3322: 0x000c, 0x3323: 0x000c, + 0x3324: 0x000c, 0x3325: 0x000c, 0x3326: 0x000c, 0x3327: 0x000c, 0x3328: 0x000c, 0x3329: 0x000c, + 0x332a: 0x000c, 0x332b: 0x000c, 0x332c: 0x000c, + 0x3335: 0x000c, + // Block 0xcd, offset 0x3340 + 0x3344: 0x000c, + 0x335b: 0x000c, 0x335c: 0x000c, 0x335d: 0x000c, + 0x335e: 0x000c, 0x335f: 0x000c, 0x3361: 0x000c, 0x3362: 0x000c, 0x3363: 0x000c, + 0x3364: 0x000c, 0x3365: 0x000c, 0x3366: 0x000c, 0x3367: 0x000c, 0x3368: 0x000c, 0x3369: 0x000c, + 0x336a: 0x000c, 0x336b: 0x000c, 0x336c: 0x000c, 0x336d: 0x000c, 0x336e: 0x000c, 0x336f: 0x000c, + // Block 0xce, offset 0x3380 + 0x3380: 0x000c, 0x3381: 0x000c, 0x3382: 0x000c, 0x3383: 0x000c, 0x3384: 0x000c, 0x3385: 0x000c, + 0x3386: 0x000c, 0x3388: 0x000c, 0x3389: 0x000c, 0x338a: 0x000c, 0x338b: 0x000c, + 0x338c: 0x000c, 0x338d: 0x000c, 0x338e: 0x000c, 0x338f: 0x000c, 0x3390: 0x000c, 0x3391: 0x000c, + 0x3392: 0x000c, 0x3393: 0x000c, 0x3394: 0x000c, 0x3395: 0x000c, 0x3396: 0x000c, 0x3397: 0x000c, + 0x3398: 0x000c, 0x339b: 0x000c, 0x339c: 0x000c, 0x339d: 0x000c, + 0x339e: 0x000c, 0x339f: 0x000c, 0x33a0: 0x000c, 0x33a1: 0x000c, 0x33a3: 0x000c, + 0x33a4: 0x000c, 0x33a6: 0x000c, 0x33a7: 0x000c, 0x33a8: 0x000c, 0x33a9: 0x000c, + 0x33aa: 0x000c, + // Block 0xcf, offset 0x33c0 + 0x33c0: 0x0001, 0x33c1: 0x0001, 0x33c2: 0x0001, 0x33c3: 0x0001, 0x33c4: 0x0001, 0x33c5: 0x0001, + 0x33c6: 0x0001, 0x33c7: 0x0001, 0x33c8: 0x0001, 0x33c9: 0x0001, 0x33ca: 0x0001, 0x33cb: 0x0001, + 0x33cc: 0x0001, 0x33cd: 0x0001, 0x33ce: 0x0001, 0x33cf: 0x0001, 0x33d0: 0x000c, 0x33d1: 0x000c, + 0x33d2: 0x000c, 0x33d3: 0x000c, 0x33d4: 0x000c, 0x33d5: 0x000c, 0x33d6: 0x000c, 0x33d7: 0x0001, + 0x33d8: 0x0001, 0x33d9: 0x0001, 0x33da: 0x0001, 0x33db: 0x0001, 0x33dc: 0x0001, 0x33dd: 0x0001, + 0x33de: 0x0001, 0x33df: 0x0001, 0x33e0: 0x0001, 0x33e1: 0x0001, 0x33e2: 0x0001, 0x33e3: 0x0001, + 0x33e4: 0x0001, 0x33e5: 0x0001, 0x33e6: 0x0001, 0x33e7: 0x0001, 0x33e8: 0x0001, 0x33e9: 0x0001, + 0x33ea: 0x0001, 0x33eb: 0x0001, 0x33ec: 0x0001, 0x33ed: 0x0001, 0x33ee: 0x0001, 0x33ef: 0x0001, + 0x33f0: 0x0001, 0x33f1: 0x0001, 0x33f2: 0x0001, 0x33f3: 0x0001, 0x33f4: 0x0001, 0x33f5: 0x0001, + 0x33f6: 0x0001, 0x33f7: 0x0001, 0x33f8: 0x0001, 0x33f9: 0x0001, 0x33fa: 0x0001, 0x33fb: 0x0001, + 0x33fc: 0x0001, 0x33fd: 0x0001, 0x33fe: 0x0001, 0x33ff: 0x0001, + // Block 0xd0, offset 0x3400 + 0x3400: 0x0001, 0x3401: 0x0001, 0x3402: 0x0001, 0x3403: 0x0001, 0x3404: 0x000c, 0x3405: 0x000c, + 0x3406: 0x000c, 0x3407: 0x000c, 0x3408: 0x000c, 0x3409: 0x000c, 0x340a: 0x000c, 0x340b: 0x0001, + 0x340c: 0x0001, 0x340d: 0x0001, 0x340e: 0x0001, 0x340f: 0x0001, 0x3410: 0x0001, 0x3411: 0x0001, + 0x3412: 0x0001, 0x3413: 0x0001, 0x3414: 0x0001, 0x3415: 0x0001, 0x3416: 0x0001, 0x3417: 0x0001, + 0x3418: 0x0001, 0x3419: 0x0001, 0x341a: 0x0001, 0x341b: 0x0001, 0x341c: 0x0001, 0x341d: 0x0001, + 0x341e: 0x0001, 0x341f: 0x0001, 0x3420: 0x0001, 0x3421: 0x0001, 0x3422: 0x0001, 0x3423: 0x0001, + 0x3424: 0x0001, 0x3425: 0x0001, 0x3426: 0x0001, 0x3427: 0x0001, 0x3428: 0x0001, 0x3429: 0x0001, + 0x342a: 0x0001, 0x342b: 0x0001, 0x342c: 0x0001, 0x342d: 0x0001, 0x342e: 0x0001, 0x342f: 0x0001, + 0x3430: 0x0001, 0x3431: 0x0001, 0x3432: 0x0001, 0x3433: 0x0001, 0x3434: 0x0001, 0x3435: 0x0001, + 0x3436: 0x0001, 0x3437: 0x0001, 0x3438: 0x0001, 0x3439: 0x0001, 0x343a: 0x0001, 0x343b: 0x0001, + 0x343c: 0x0001, 0x343d: 0x0001, 0x343e: 0x0001, 0x343f: 0x0001, + // Block 0xd1, offset 0x3440 + 0x3440: 0x000d, 0x3441: 0x000d, 0x3442: 0x000d, 0x3443: 0x000d, 0x3444: 0x000d, 0x3445: 0x000d, + 0x3446: 0x000d, 0x3447: 0x000d, 0x3448: 0x000d, 0x3449: 0x000d, 0x344a: 0x000d, 0x344b: 0x000d, + 0x344c: 0x000d, 0x344d: 0x000d, 0x344e: 0x000d, 0x344f: 0x000d, 0x3450: 0x000d, 0x3451: 0x000d, + 0x3452: 0x000d, 0x3453: 0x000d, 0x3454: 0x000d, 0x3455: 0x000d, 0x3456: 0x000d, 0x3457: 0x000d, + 0x3458: 0x000d, 0x3459: 0x000d, 0x345a: 0x000d, 0x345b: 0x000d, 0x345c: 0x000d, 0x345d: 0x000d, + 0x345e: 0x000d, 0x345f: 0x000d, 0x3460: 0x000d, 0x3461: 0x000d, 0x3462: 0x000d, 0x3463: 0x000d, + 0x3464: 0x000d, 0x3465: 0x000d, 0x3466: 0x000d, 0x3467: 0x000d, 0x3468: 0x000d, 0x3469: 0x000d, + 0x346a: 0x000d, 0x346b: 0x000d, 0x346c: 0x000d, 0x346d: 0x000d, 0x346e: 0x000d, 0x346f: 0x000d, + 0x3470: 0x000a, 0x3471: 0x000a, 0x3472: 0x000d, 0x3473: 0x000d, 0x3474: 0x000d, 0x3475: 0x000d, + 0x3476: 0x000d, 0x3477: 0x000d, 0x3478: 0x000d, 0x3479: 0x000d, 0x347a: 0x000d, 0x347b: 0x000d, + 0x347c: 0x000d, 0x347d: 0x000d, 0x347e: 0x000d, 0x347f: 0x000d, + // Block 0xd2, offset 0x3480 + 0x3480: 0x000a, 0x3481: 0x000a, 0x3482: 0x000a, 0x3483: 0x000a, 0x3484: 0x000a, 0x3485: 0x000a, + 0x3486: 0x000a, 0x3487: 0x000a, 0x3488: 0x000a, 0x3489: 0x000a, 0x348a: 0x000a, 0x348b: 0x000a, + 0x348c: 0x000a, 0x348d: 0x000a, 0x348e: 0x000a, 0x348f: 0x000a, 0x3490: 0x000a, 0x3491: 0x000a, + 0x3492: 0x000a, 0x3493: 0x000a, 0x3494: 0x000a, 0x3495: 0x000a, 0x3496: 0x000a, 0x3497: 0x000a, + 0x3498: 0x000a, 0x3499: 0x000a, 0x349a: 0x000a, 0x349b: 0x000a, 0x349c: 0x000a, 0x349d: 0x000a, + 0x349e: 0x000a, 0x349f: 0x000a, 0x34a0: 0x000a, 0x34a1: 0x000a, 0x34a2: 0x000a, 0x34a3: 0x000a, + 0x34a4: 0x000a, 0x34a5: 0x000a, 0x34a6: 0x000a, 0x34a7: 0x000a, 0x34a8: 0x000a, 0x34a9: 0x000a, + 0x34aa: 0x000a, 0x34ab: 0x000a, + 0x34b0: 0x000a, 0x34b1: 0x000a, 0x34b2: 0x000a, 0x34b3: 0x000a, 0x34b4: 0x000a, 0x34b5: 0x000a, + 0x34b6: 0x000a, 0x34b7: 0x000a, 0x34b8: 0x000a, 0x34b9: 0x000a, 0x34ba: 0x000a, 0x34bb: 0x000a, + 0x34bc: 0x000a, 0x34bd: 0x000a, 0x34be: 0x000a, 0x34bf: 0x000a, + // Block 0xd3, offset 0x34c0 + 0x34c0: 0x000a, 0x34c1: 0x000a, 0x34c2: 0x000a, 0x34c3: 0x000a, 0x34c4: 0x000a, 0x34c5: 0x000a, + 0x34c6: 0x000a, 0x34c7: 0x000a, 0x34c8: 0x000a, 0x34c9: 0x000a, 0x34ca: 0x000a, 0x34cb: 0x000a, + 0x34cc: 0x000a, 0x34cd: 0x000a, 0x34ce: 0x000a, 0x34cf: 0x000a, 0x34d0: 0x000a, 0x34d1: 0x000a, + 0x34d2: 0x000a, 0x34d3: 0x000a, + 0x34e0: 0x000a, 0x34e1: 0x000a, 0x34e2: 0x000a, 0x34e3: 0x000a, + 0x34e4: 0x000a, 0x34e5: 0x000a, 0x34e6: 0x000a, 0x34e7: 0x000a, 0x34e8: 0x000a, 0x34e9: 0x000a, + 0x34ea: 0x000a, 0x34eb: 0x000a, 0x34ec: 0x000a, 0x34ed: 0x000a, 0x34ee: 0x000a, + 0x34f1: 0x000a, 0x34f2: 0x000a, 0x34f3: 0x000a, 0x34f4: 0x000a, 0x34f5: 0x000a, + 0x34f6: 0x000a, 0x34f7: 0x000a, 0x34f8: 0x000a, 0x34f9: 0x000a, 0x34fa: 0x000a, 0x34fb: 0x000a, + 0x34fc: 0x000a, 0x34fd: 0x000a, 0x34fe: 0x000a, 0x34ff: 0x000a, + // Block 0xd4, offset 0x3500 + 0x3501: 0x000a, 0x3502: 0x000a, 0x3503: 0x000a, 0x3504: 0x000a, 0x3505: 0x000a, + 0x3506: 0x000a, 0x3507: 0x000a, 0x3508: 0x000a, 0x3509: 0x000a, 0x350a: 0x000a, 0x350b: 0x000a, + 0x350c: 0x000a, 0x350d: 0x000a, 0x350e: 0x000a, 0x350f: 0x000a, 0x3511: 0x000a, + 0x3512: 0x000a, 0x3513: 0x000a, 0x3514: 0x000a, 0x3515: 0x000a, 0x3516: 0x000a, 0x3517: 0x000a, + 0x3518: 0x000a, 0x3519: 0x000a, 0x351a: 0x000a, 0x351b: 0x000a, 0x351c: 0x000a, 0x351d: 0x000a, + 0x351e: 0x000a, 0x351f: 0x000a, 0x3520: 0x000a, 0x3521: 0x000a, 0x3522: 0x000a, 0x3523: 0x000a, + 0x3524: 0x000a, 0x3525: 0x000a, 0x3526: 0x000a, 0x3527: 0x000a, 0x3528: 0x000a, 0x3529: 0x000a, + 0x352a: 0x000a, 0x352b: 0x000a, 0x352c: 0x000a, 0x352d: 0x000a, 0x352e: 0x000a, 0x352f: 0x000a, + 0x3530: 0x000a, 0x3531: 0x000a, 0x3532: 0x000a, 0x3533: 0x000a, 0x3534: 0x000a, 0x3535: 0x000a, + // Block 0xd5, offset 0x3540 + 0x3540: 0x0002, 0x3541: 0x0002, 0x3542: 0x0002, 0x3543: 0x0002, 0x3544: 0x0002, 0x3545: 0x0002, + 0x3546: 0x0002, 0x3547: 0x0002, 0x3548: 0x0002, 0x3549: 0x0002, 0x354a: 0x0002, 0x354b: 0x000a, + 0x354c: 0x000a, + // Block 0xd6, offset 0x3580 + 0x35aa: 0x000a, 0x35ab: 0x000a, + // Block 0xd7, offset 0x35c0 + 0x35e0: 0x000a, 0x35e1: 0x000a, 0x35e2: 0x000a, 0x35e3: 0x000a, + 0x35e4: 0x000a, 0x35e5: 0x000a, + // Block 0xd8, offset 0x3600 + 0x3600: 0x000a, 0x3601: 0x000a, 0x3602: 0x000a, 0x3603: 0x000a, 0x3604: 0x000a, 0x3605: 0x000a, + 0x3606: 0x000a, 0x3607: 0x000a, 0x3608: 0x000a, 0x3609: 0x000a, 0x360a: 0x000a, 0x360b: 0x000a, + 0x360c: 0x000a, 0x360d: 0x000a, 0x360e: 0x000a, 0x360f: 0x000a, 0x3610: 0x000a, 0x3611: 0x000a, + 0x3612: 0x000a, 0x3613: 0x000a, 0x3614: 0x000a, + 0x3620: 0x000a, 0x3621: 0x000a, 0x3622: 0x000a, 0x3623: 0x000a, + 0x3624: 0x000a, 0x3625: 0x000a, 0x3626: 0x000a, 0x3627: 0x000a, 0x3628: 0x000a, 0x3629: 0x000a, + 0x362a: 0x000a, 0x362b: 0x000a, 0x362c: 0x000a, + 0x3630: 0x000a, 0x3631: 0x000a, 0x3632: 0x000a, 0x3633: 0x000a, 0x3634: 0x000a, 0x3635: 0x000a, + 0x3636: 0x000a, 0x3637: 0x000a, 0x3638: 0x000a, + // Block 0xd9, offset 0x3640 + 0x3640: 0x000a, 0x3641: 0x000a, 0x3642: 0x000a, 0x3643: 0x000a, 0x3644: 0x000a, 0x3645: 0x000a, + 0x3646: 0x000a, 0x3647: 0x000a, 0x3648: 0x000a, 0x3649: 0x000a, 0x364a: 0x000a, 0x364b: 0x000a, + 0x364c: 0x000a, 0x364d: 0x000a, 0x364e: 0x000a, 0x364f: 0x000a, 0x3650: 0x000a, 0x3651: 0x000a, + 0x3652: 0x000a, 0x3653: 0x000a, 0x3654: 0x000a, + // Block 0xda, offset 0x3680 + 0x3680: 0x000a, 0x3681: 0x000a, 0x3682: 0x000a, 0x3683: 0x000a, 0x3684: 0x000a, 0x3685: 0x000a, + 0x3686: 0x000a, 0x3687: 0x000a, 0x3688: 0x000a, 0x3689: 0x000a, 0x368a: 0x000a, 0x368b: 0x000a, + 0x3690: 0x000a, 0x3691: 0x000a, + 0x3692: 0x000a, 0x3693: 0x000a, 0x3694: 0x000a, 0x3695: 0x000a, 0x3696: 0x000a, 0x3697: 0x000a, + 0x3698: 0x000a, 0x3699: 0x000a, 0x369a: 0x000a, 0x369b: 0x000a, 0x369c: 0x000a, 0x369d: 0x000a, + 0x369e: 0x000a, 0x369f: 0x000a, 0x36a0: 0x000a, 0x36a1: 0x000a, 0x36a2: 0x000a, 0x36a3: 0x000a, + 0x36a4: 0x000a, 0x36a5: 0x000a, 0x36a6: 0x000a, 0x36a7: 0x000a, 0x36a8: 0x000a, 0x36a9: 0x000a, + 0x36aa: 0x000a, 0x36ab: 0x000a, 0x36ac: 0x000a, 0x36ad: 0x000a, 0x36ae: 0x000a, 0x36af: 0x000a, + 0x36b0: 0x000a, 0x36b1: 0x000a, 0x36b2: 0x000a, 0x36b3: 0x000a, 0x36b4: 0x000a, 0x36b5: 0x000a, + 0x36b6: 0x000a, 0x36b7: 0x000a, 0x36b8: 0x000a, 0x36b9: 0x000a, 0x36ba: 0x000a, 0x36bb: 0x000a, + 0x36bc: 0x000a, 0x36bd: 0x000a, 0x36be: 0x000a, 0x36bf: 0x000a, + // Block 0xdb, offset 0x36c0 + 0x36c0: 0x000a, 0x36c1: 0x000a, 0x36c2: 0x000a, 0x36c3: 0x000a, 0x36c4: 0x000a, 0x36c5: 0x000a, + 0x36c6: 0x000a, 0x36c7: 0x000a, + 0x36d0: 0x000a, 0x36d1: 0x000a, + 0x36d2: 0x000a, 0x36d3: 0x000a, 0x36d4: 0x000a, 0x36d5: 0x000a, 0x36d6: 0x000a, 0x36d7: 0x000a, + 0x36d8: 0x000a, 0x36d9: 0x000a, + 0x36e0: 0x000a, 0x36e1: 0x000a, 0x36e2: 0x000a, 0x36e3: 0x000a, + 0x36e4: 0x000a, 0x36e5: 0x000a, 0x36e6: 0x000a, 0x36e7: 0x000a, 0x36e8: 0x000a, 0x36e9: 0x000a, + 0x36ea: 0x000a, 0x36eb: 0x000a, 0x36ec: 0x000a, 0x36ed: 0x000a, 0x36ee: 0x000a, 0x36ef: 0x000a, + 0x36f0: 0x000a, 0x36f1: 0x000a, 0x36f2: 0x000a, 0x36f3: 0x000a, 0x36f4: 0x000a, 0x36f5: 0x000a, + 0x36f6: 0x000a, 0x36f7: 0x000a, 0x36f8: 0x000a, 0x36f9: 0x000a, 0x36fa: 0x000a, 0x36fb: 0x000a, + 0x36fc: 0x000a, 0x36fd: 0x000a, 0x36fe: 0x000a, 0x36ff: 0x000a, + // Block 0xdc, offset 0x3700 + 0x3700: 0x000a, 0x3701: 0x000a, 0x3702: 0x000a, 0x3703: 0x000a, 0x3704: 0x000a, 0x3705: 0x000a, + 0x3706: 0x000a, 0x3707: 0x000a, + 0x3710: 0x000a, 0x3711: 0x000a, + 0x3712: 0x000a, 0x3713: 0x000a, 0x3714: 0x000a, 0x3715: 0x000a, 0x3716: 0x000a, 0x3717: 0x000a, + 0x3718: 0x000a, 0x3719: 0x000a, 0x371a: 0x000a, 0x371b: 0x000a, 0x371c: 0x000a, 0x371d: 0x000a, + 0x371e: 0x000a, 0x371f: 0x000a, 0x3720: 0x000a, 0x3721: 0x000a, 0x3722: 0x000a, 0x3723: 0x000a, + 0x3724: 0x000a, 0x3725: 0x000a, 0x3726: 0x000a, 0x3727: 0x000a, 0x3728: 0x000a, 0x3729: 0x000a, + 0x372a: 0x000a, 0x372b: 0x000a, 0x372c: 0x000a, 0x372d: 0x000a, + // Block 0xdd, offset 0x3740 + 0x3740: 0x000a, 0x3741: 0x000a, 0x3742: 0x000a, 0x3743: 0x000a, 0x3744: 0x000a, 0x3745: 0x000a, + 0x3746: 0x000a, 0x3747: 0x000a, 0x3748: 0x000a, 0x3749: 0x000a, 0x374a: 0x000a, 0x374b: 0x000a, + 0x3750: 0x000a, 0x3751: 0x000a, + 0x3752: 0x000a, 0x3753: 0x000a, 0x3754: 0x000a, 0x3755: 0x000a, 0x3756: 0x000a, 0x3757: 0x000a, + 0x3758: 0x000a, 0x3759: 0x000a, 0x375a: 0x000a, 0x375b: 0x000a, 0x375c: 0x000a, 0x375d: 0x000a, + 0x375e: 0x000a, 0x375f: 0x000a, 0x3760: 0x000a, 0x3761: 0x000a, 0x3762: 0x000a, 0x3763: 0x000a, + 0x3764: 0x000a, 0x3765: 0x000a, 0x3766: 0x000a, 0x3767: 0x000a, 0x3768: 0x000a, 0x3769: 0x000a, + 0x376a: 0x000a, 0x376b: 0x000a, 0x376c: 0x000a, 0x376d: 0x000a, 0x376e: 0x000a, 0x376f: 0x000a, + 0x3770: 0x000a, 0x3771: 0x000a, 0x3772: 0x000a, 0x3773: 0x000a, 0x3774: 0x000a, 0x3775: 0x000a, + 0x3776: 0x000a, 0x3777: 0x000a, 0x3778: 0x000a, 0x3779: 0x000a, 0x377a: 0x000a, 0x377b: 0x000a, + 0x377c: 0x000a, 0x377d: 0x000a, 0x377e: 0x000a, + // Block 0xde, offset 0x3780 + 0x3780: 0x000a, 0x3781: 0x000a, 0x3782: 0x000a, 0x3783: 0x000a, 0x3784: 0x000a, 0x3785: 0x000a, + 0x3786: 0x000a, 0x3787: 0x000a, 0x3788: 0x000a, 0x3789: 0x000a, 0x378a: 0x000a, 0x378b: 0x000a, + 0x378c: 0x000a, 0x3790: 0x000a, 0x3791: 0x000a, + 0x3792: 0x000a, 0x3793: 0x000a, 0x3794: 0x000a, 0x3795: 0x000a, 0x3796: 0x000a, 0x3797: 0x000a, + 0x3798: 0x000a, 0x3799: 0x000a, 0x379a: 0x000a, 0x379b: 0x000a, 0x379c: 0x000a, 0x379d: 0x000a, + 0x379e: 0x000a, 0x379f: 0x000a, 0x37a0: 0x000a, 0x37a1: 0x000a, 0x37a2: 0x000a, 0x37a3: 0x000a, + 0x37a4: 0x000a, 0x37a5: 0x000a, 0x37a6: 0x000a, 0x37a7: 0x000a, 0x37a8: 0x000a, 0x37a9: 0x000a, + 0x37aa: 0x000a, 0x37ab: 0x000a, + // Block 0xdf, offset 0x37c0 + 0x37c0: 0x000a, 0x37c1: 0x000a, 0x37c2: 0x000a, 0x37c3: 0x000a, 0x37c4: 0x000a, 0x37c5: 0x000a, + 0x37c6: 0x000a, 0x37c7: 0x000a, 0x37c8: 0x000a, 0x37c9: 0x000a, 0x37ca: 0x000a, 0x37cb: 0x000a, + 0x37cc: 0x000a, 0x37cd: 0x000a, 0x37ce: 0x000a, 0x37cf: 0x000a, 0x37d0: 0x000a, 0x37d1: 0x000a, + 0x37d2: 0x000a, 0x37d3: 0x000a, 0x37d4: 0x000a, 0x37d5: 0x000a, 0x37d6: 0x000a, 0x37d7: 0x000a, + // Block 0xe0, offset 0x3800 + 0x3800: 0x000a, + 0x3810: 0x000a, 0x3811: 0x000a, + 0x3812: 0x000a, 0x3813: 0x000a, 0x3814: 0x000a, 0x3815: 0x000a, 0x3816: 0x000a, 0x3817: 0x000a, + 0x3818: 0x000a, 0x3819: 0x000a, 0x381a: 0x000a, 0x381b: 0x000a, 0x381c: 0x000a, 0x381d: 0x000a, + 0x381e: 0x000a, 0x381f: 0x000a, 0x3820: 0x000a, 0x3821: 0x000a, 0x3822: 0x000a, 0x3823: 0x000a, + 0x3824: 0x000a, 0x3825: 0x000a, 0x3826: 0x000a, + // Block 0xe1, offset 0x3840 + 0x387e: 0x000b, 0x387f: 0x000b, + // Block 0xe2, offset 0x3880 + 0x3880: 0x000b, 0x3881: 0x000b, 0x3882: 0x000b, 0x3883: 0x000b, 0x3884: 0x000b, 0x3885: 0x000b, + 0x3886: 0x000b, 0x3887: 0x000b, 0x3888: 0x000b, 0x3889: 0x000b, 0x388a: 0x000b, 0x388b: 0x000b, + 0x388c: 0x000b, 0x388d: 0x000b, 0x388e: 0x000b, 0x388f: 0x000b, 0x3890: 0x000b, 0x3891: 0x000b, + 0x3892: 0x000b, 0x3893: 0x000b, 0x3894: 0x000b, 0x3895: 0x000b, 0x3896: 0x000b, 0x3897: 0x000b, + 0x3898: 0x000b, 0x3899: 0x000b, 0x389a: 0x000b, 0x389b: 0x000b, 0x389c: 0x000b, 0x389d: 0x000b, + 0x389e: 0x000b, 0x389f: 0x000b, 0x38a0: 0x000b, 0x38a1: 0x000b, 0x38a2: 0x000b, 0x38a3: 0x000b, + 0x38a4: 0x000b, 0x38a5: 0x000b, 0x38a6: 0x000b, 0x38a7: 0x000b, 0x38a8: 0x000b, 0x38a9: 0x000b, + 0x38aa: 0x000b, 0x38ab: 0x000b, 0x38ac: 0x000b, 0x38ad: 0x000b, 0x38ae: 0x000b, 0x38af: 0x000b, + 0x38b0: 0x000b, 0x38b1: 0x000b, 0x38b2: 0x000b, 0x38b3: 0x000b, 0x38b4: 0x000b, 0x38b5: 0x000b, + 0x38b6: 0x000b, 0x38b7: 0x000b, 0x38b8: 0x000b, 0x38b9: 0x000b, 0x38ba: 0x000b, 0x38bb: 0x000b, + 0x38bc: 0x000b, 0x38bd: 0x000b, 0x38be: 0x000b, 0x38bf: 0x000b, + // Block 0xe3, offset 0x38c0 + 0x38c0: 0x000c, 0x38c1: 0x000c, 0x38c2: 0x000c, 0x38c3: 0x000c, 0x38c4: 0x000c, 0x38c5: 0x000c, + 0x38c6: 0x000c, 0x38c7: 0x000c, 0x38c8: 0x000c, 0x38c9: 0x000c, 0x38ca: 0x000c, 0x38cb: 0x000c, + 0x38cc: 0x000c, 0x38cd: 0x000c, 0x38ce: 0x000c, 0x38cf: 0x000c, 0x38d0: 0x000c, 0x38d1: 0x000c, + 0x38d2: 0x000c, 0x38d3: 0x000c, 0x38d4: 0x000c, 0x38d5: 0x000c, 0x38d6: 0x000c, 0x38d7: 0x000c, + 0x38d8: 0x000c, 0x38d9: 0x000c, 0x38da: 0x000c, 0x38db: 0x000c, 0x38dc: 0x000c, 0x38dd: 0x000c, + 0x38de: 0x000c, 0x38df: 0x000c, 0x38e0: 0x000c, 0x38e1: 0x000c, 0x38e2: 0x000c, 0x38e3: 0x000c, + 0x38e4: 0x000c, 0x38e5: 0x000c, 0x38e6: 0x000c, 0x38e7: 0x000c, 0x38e8: 0x000c, 0x38e9: 0x000c, + 0x38ea: 0x000c, 0x38eb: 0x000c, 0x38ec: 0x000c, 0x38ed: 0x000c, 0x38ee: 0x000c, 0x38ef: 0x000c, + 0x38f0: 0x000b, 0x38f1: 0x000b, 0x38f2: 0x000b, 0x38f3: 0x000b, 0x38f4: 0x000b, 0x38f5: 0x000b, + 0x38f6: 0x000b, 0x38f7: 0x000b, 0x38f8: 0x000b, 0x38f9: 0x000b, 0x38fa: 0x000b, 0x38fb: 0x000b, + 0x38fc: 0x000b, 0x38fd: 0x000b, 0x38fe: 0x000b, 0x38ff: 0x000b, +} + +// bidiIndex: 24 blocks, 1536 entries, 1536 bytes +// Block 0 is the zero block. +var bidiIndex = [1536]uint8{ + // Block 0x0, offset 0x0 + // Block 0x1, offset 0x40 + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0xc2: 0x01, 0xc3: 0x02, + 0xca: 0x03, 0xcb: 0x04, 0xcc: 0x05, 0xcd: 0x06, 0xce: 0x07, 0xcf: 0x08, + 0xd2: 0x09, 0xd6: 0x0a, 0xd7: 0x0b, + 0xd8: 0x0c, 0xd9: 0x0d, 0xda: 0x0e, 0xdb: 0x0f, 0xdc: 0x10, 0xdd: 0x11, 0xde: 0x12, 0xdf: 0x13, + 0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05, 0xe4: 0x06, + 0xea: 0x07, 0xef: 0x08, + 0xf0: 0x11, 0xf1: 0x12, 0xf2: 0x12, 0xf3: 0x14, 0xf4: 0x15, + // Block 0x4, offset 0x100 + 0x120: 0x14, 0x121: 0x15, 0x122: 0x16, 0x123: 0x17, 0x124: 0x18, 0x125: 0x19, 0x126: 0x1a, 0x127: 0x1b, + 0x128: 0x1c, 0x129: 0x1d, 0x12a: 0x1c, 0x12b: 0x1e, 0x12c: 0x1f, 0x12d: 0x20, 0x12e: 0x21, 0x12f: 0x22, + 0x130: 0x23, 0x131: 0x24, 0x132: 0x1a, 0x133: 0x25, 0x134: 0x26, 0x135: 0x27, 0x137: 0x28, + 0x138: 0x29, 0x139: 0x2a, 0x13a: 0x2b, 0x13b: 0x2c, 0x13c: 0x2d, 0x13d: 0x2e, 0x13e: 0x2f, 0x13f: 0x30, + // Block 0x5, offset 0x140 + 0x140: 0x31, 0x141: 0x32, 0x142: 0x33, + 0x14d: 0x34, 0x14e: 0x35, + 0x150: 0x36, + 0x15a: 0x37, 0x15c: 0x38, 0x15d: 0x39, 0x15e: 0x3a, 0x15f: 0x3b, + 0x160: 0x3c, 0x162: 0x3d, 0x164: 0x3e, 0x165: 0x3f, 0x167: 0x40, + 0x168: 0x41, 0x169: 0x42, 0x16a: 0x43, 0x16c: 0x44, 0x16d: 0x45, 0x16e: 0x46, 0x16f: 0x47, + 0x170: 0x48, 0x173: 0x49, 0x177: 0x4a, + 0x17e: 0x4b, 0x17f: 0x4c, + // Block 0x6, offset 0x180 + 0x180: 0x4d, 0x181: 0x4e, 0x182: 0x4f, 0x183: 0x50, 0x184: 0x51, 0x185: 0x52, 0x186: 0x53, 0x187: 0x54, + 0x188: 0x55, 0x189: 0x54, 0x18a: 0x54, 0x18b: 0x54, 0x18c: 0x56, 0x18d: 0x57, 0x18e: 0x58, 0x18f: 0x54, + 0x190: 0x59, 0x191: 0x5a, 0x192: 0x5b, 0x193: 0x5c, 0x194: 0x54, 0x195: 0x54, 0x196: 0x54, 0x197: 0x54, + 0x198: 0x54, 0x199: 0x54, 0x19a: 0x5d, 0x19b: 0x54, 0x19c: 0x54, 0x19d: 0x5e, 0x19e: 0x54, 0x19f: 0x5f, + 0x1a4: 0x54, 0x1a5: 0x54, 0x1a6: 0x60, 0x1a7: 0x61, + 0x1a8: 0x54, 0x1a9: 0x54, 0x1aa: 0x54, 0x1ab: 0x54, 0x1ac: 0x54, 0x1ad: 0x62, 0x1ae: 0x63, 0x1af: 0x64, + 0x1b3: 0x65, 0x1b5: 0x66, 0x1b7: 0x67, + 0x1b8: 0x68, 0x1b9: 0x69, 0x1ba: 0x6a, 0x1bb: 0x6b, 0x1bc: 0x54, 0x1bd: 0x54, 0x1be: 0x54, 0x1bf: 0x6c, + // Block 0x7, offset 0x1c0 + 0x1c0: 0x6d, 0x1c2: 0x6e, 0x1c3: 0x6f, 0x1c7: 0x70, + 0x1c8: 0x71, 0x1c9: 0x72, 0x1ca: 0x73, 0x1cb: 0x74, 0x1cd: 0x75, 0x1cf: 0x76, + // Block 0x8, offset 0x200 + 0x237: 0x54, + // Block 0x9, offset 0x240 + 0x252: 0x77, 0x253: 0x78, + 0x258: 0x79, 0x259: 0x7a, 0x25a: 0x7b, 0x25b: 0x7c, 0x25c: 0x7d, 0x25e: 0x7e, + 0x260: 0x7f, 0x261: 0x80, 0x263: 0x81, 0x264: 0x82, 0x265: 0x83, 0x266: 0x84, 0x267: 0x85, + 0x268: 0x86, 0x269: 0x87, 0x26a: 0x88, 0x26b: 0x89, 0x26f: 0x8a, + // Block 0xa, offset 0x280 + 0x2ac: 0x8b, 0x2ad: 0x8c, 0x2ae: 0x0e, 0x2af: 0x0e, + 0x2b0: 0x0e, 0x2b1: 0x0e, 0x2b2: 0x0e, 0x2b3: 0x0e, 0x2b4: 0x8d, 0x2b5: 0x0e, 0x2b6: 0x0e, 0x2b7: 0x8e, + 0x2b8: 0x8f, 0x2b9: 0x90, 0x2ba: 0x0e, 0x2bb: 0x91, 0x2bc: 0x92, 0x2bd: 0x93, 0x2bf: 0x94, + // Block 0xb, offset 0x2c0 + 0x2c4: 0x95, 0x2c5: 0x54, 0x2c6: 0x96, 0x2c7: 0x97, + 0x2cb: 0x98, 0x2cd: 0x99, + 0x2e0: 0x9a, 0x2e1: 0x9a, 0x2e2: 0x9a, 0x2e3: 0x9a, 0x2e4: 0x9b, 0x2e5: 0x9a, 0x2e6: 0x9a, 0x2e7: 0x9a, + 0x2e8: 0x9c, 0x2e9: 0x9a, 0x2ea: 0x9a, 0x2eb: 0x9d, 0x2ec: 0x9e, 0x2ed: 0x9a, 0x2ee: 0x9a, 0x2ef: 0x9a, + 0x2f0: 0x9a, 0x2f1: 0x9a, 0x2f2: 0x9a, 0x2f3: 0x9a, 0x2f4: 0x9a, 0x2f5: 0x9a, 0x2f6: 0x9a, 0x2f7: 0x9a, + 0x2f8: 0x9a, 0x2f9: 0x9f, 0x2fa: 0x9a, 0x2fb: 0x9a, 0x2fc: 0x9a, 0x2fd: 0x9a, 0x2fe: 0x9a, 0x2ff: 0x9a, + // Block 0xc, offset 0x300 + 0x300: 0xa0, 0x301: 0xa1, 0x302: 0xa2, 0x304: 0xa3, 0x305: 0xa4, 0x306: 0xa5, 0x307: 0xa6, + 0x308: 0xa7, 0x30b: 0xa8, 0x30c: 0xa9, 0x30d: 0xaa, + 0x310: 0xab, 0x311: 0xac, 0x312: 0xad, 0x313: 0xae, 0x316: 0xaf, 0x317: 0xb0, + 0x318: 0xb1, 0x319: 0xb2, 0x31a: 0xb3, 0x31c: 0xb4, + 0x328: 0xb5, 0x329: 0xb6, 0x32a: 0xb7, + 0x330: 0xb8, 0x332: 0xb9, 0x334: 0xba, 0x335: 0xbb, + // Block 0xd, offset 0x340 + 0x36b: 0xbc, 0x36c: 0xbd, + 0x37e: 0xbe, + // Block 0xe, offset 0x380 + 0x3b2: 0xbf, + // Block 0xf, offset 0x3c0 + 0x3c5: 0xc0, 0x3c6: 0xc1, + 0x3c8: 0x54, 0x3c9: 0xc2, 0x3cc: 0x54, 0x3cd: 0xc3, + 0x3db: 0xc4, 0x3dc: 0xc5, 0x3dd: 0xc6, 0x3de: 0xc7, 0x3df: 0xc8, + 0x3e8: 0xc9, 0x3e9: 0xca, 0x3ea: 0xcb, + // Block 0x10, offset 0x400 + 0x400: 0xcc, + 0x420: 0x9a, 0x421: 0x9a, 0x422: 0x9a, 0x423: 0xcd, 0x424: 0x9a, 0x425: 0xce, 0x426: 0x9a, 0x427: 0x9a, + 0x428: 0x9a, 0x429: 0x9a, 0x42a: 0x9a, 0x42b: 0x9a, 0x42c: 0x9a, 0x42d: 0x9a, 0x42e: 0x9a, 0x42f: 0x9a, + 0x430: 0x9a, 0x431: 0x9a, 0x432: 0x9a, 0x433: 0x9a, 0x434: 0x9a, 0x435: 0x9a, 0x436: 0x9a, 0x437: 0x9a, + 0x438: 0x0e, 0x439: 0x0e, 0x43a: 0x0e, 0x43b: 0xcf, 0x43c: 0x9a, 0x43d: 0x9a, 0x43e: 0x9a, 0x43f: 0x9a, + // Block 0x11, offset 0x440 + 0x440: 0xd0, 0x441: 0x54, 0x442: 0xd1, 0x443: 0xd2, 0x444: 0xd3, 0x445: 0xd4, + 0x449: 0xd5, 0x44c: 0x54, 0x44d: 0x54, 0x44e: 0x54, 0x44f: 0x54, + 0x450: 0x54, 0x451: 0x54, 0x452: 0x54, 0x453: 0x54, 0x454: 0x54, 0x455: 0x54, 0x456: 0x54, 0x457: 0x54, + 0x458: 0x54, 0x459: 0x54, 0x45a: 0x54, 0x45b: 0xd6, 0x45c: 0x54, 0x45d: 0x6b, 0x45e: 0x54, 0x45f: 0xd7, + 0x460: 0xd8, 0x461: 0xd9, 0x462: 0xda, 0x464: 0xdb, 0x465: 0xdc, 0x466: 0xdd, 0x467: 0xde, + 0x47f: 0xdf, + // Block 0x12, offset 0x480 + 0x4bf: 0xdf, + // Block 0x13, offset 0x4c0 + 0x4d0: 0x09, 0x4d1: 0x0a, 0x4d6: 0x0b, + 0x4db: 0x0c, 0x4dd: 0x0d, 0x4de: 0x0e, 0x4df: 0x0f, + 0x4ef: 0x10, + 0x4ff: 0x10, + // Block 0x14, offset 0x500 + 0x50f: 0x10, + 0x51f: 0x10, + 0x52f: 0x10, + 0x53f: 0x10, + // Block 0x15, offset 0x540 + 0x540: 0xe0, 0x541: 0xe0, 0x542: 0xe0, 0x543: 0xe0, 0x544: 0x05, 0x545: 0x05, 0x546: 0x05, 0x547: 0xe1, + 0x548: 0xe0, 0x549: 0xe0, 0x54a: 0xe0, 0x54b: 0xe0, 0x54c: 0xe0, 0x54d: 0xe0, 0x54e: 0xe0, 0x54f: 0xe0, + 0x550: 0xe0, 0x551: 0xe0, 0x552: 0xe0, 0x553: 0xe0, 0x554: 0xe0, 0x555: 0xe0, 0x556: 0xe0, 0x557: 0xe0, + 0x558: 0xe0, 0x559: 0xe0, 0x55a: 0xe0, 0x55b: 0xe0, 0x55c: 0xe0, 0x55d: 0xe0, 0x55e: 0xe0, 0x55f: 0xe0, + 0x560: 0xe0, 0x561: 0xe0, 0x562: 0xe0, 0x563: 0xe0, 0x564: 0xe0, 0x565: 0xe0, 0x566: 0xe0, 0x567: 0xe0, + 0x568: 0xe0, 0x569: 0xe0, 0x56a: 0xe0, 0x56b: 0xe0, 0x56c: 0xe0, 0x56d: 0xe0, 0x56e: 0xe0, 0x56f: 0xe0, + 0x570: 0xe0, 0x571: 0xe0, 0x572: 0xe0, 0x573: 0xe0, 0x574: 0xe0, 0x575: 0xe0, 0x576: 0xe0, 0x577: 0xe0, + 0x578: 0xe0, 0x579: 0xe0, 0x57a: 0xe0, 0x57b: 0xe0, 0x57c: 0xe0, 0x57d: 0xe0, 0x57e: 0xe0, 0x57f: 0xe0, + // Block 0x16, offset 0x580 + 0x58f: 0x10, + 0x59f: 0x10, + 0x5a0: 0x13, + 0x5af: 0x10, + 0x5bf: 0x10, + // Block 0x17, offset 0x5c0 + 0x5cf: 0x10, +} + +// Total table size 16184 bytes (15KiB); checksum: F50EF68C diff --git a/vendor/golang.org/x/text/unicode/bidi/tables9.0.0.go b/vendor/golang.org/x/text/unicode/bidi/tables9.0.0.go new file mode 100644 index 0000000000..0ca0193ebe --- /dev/null +++ b/vendor/golang.org/x/text/unicode/bidi/tables9.0.0.go @@ -0,0 +1,1781 @@ +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. + +// +build !go1.10 + +package bidi + +// UnicodeVersion is the Unicode version from which the tables in this package are derived. +const UnicodeVersion = "9.0.0" + +// xorMasks contains masks to be xor-ed with brackets to get the reverse +// version. +var xorMasks = []int32{ // 8 elements + 0, 1, 6, 7, 3, 15, 29, 63, +} // Size: 56 bytes + +// lookup returns the trie value for the first UTF-8 encoding in s and +// the width in bytes of this encoding. The size will be 0 if s does not +// hold enough bytes to complete the encoding. len(s) must be greater than 0. +func (t *bidiTrie) lookup(s []byte) (v uint8, sz int) { + c0 := s[0] + switch { + case c0 < 0x80: // is ASCII + return bidiValues[c0], 1 + case c0 < 0xC2: + return 0, 1 // Illegal UTF-8: not a starter, not ASCII. + case c0 < 0xE0: // 2-byte UTF-8 + if len(s) < 2 { + return 0, 0 + } + i := bidiIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c1), 2 + case c0 < 0xF0: // 3-byte UTF-8 + if len(s) < 3 { + return 0, 0 + } + i := bidiIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = bidiIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c2), 3 + case c0 < 0xF8: // 4-byte UTF-8 + if len(s) < 4 { + return 0, 0 + } + i := bidiIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = bidiIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + o = uint32(i)<<6 + uint32(c2) + i = bidiIndex[o] + c3 := s[3] + if c3 < 0x80 || 0xC0 <= c3 { + return 0, 3 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c3), 4 + } + // Illegal rune + return 0, 1 +} + +// lookupUnsafe returns the trie value for the first UTF-8 encoding in s. +// s must start with a full and valid UTF-8 encoded rune. +func (t *bidiTrie) lookupUnsafe(s []byte) uint8 { + c0 := s[0] + if c0 < 0x80 { // is ASCII + return bidiValues[c0] + } + i := bidiIndex[c0] + if c0 < 0xE0 { // 2-byte UTF-8 + return t.lookupValue(uint32(i), s[1]) + } + i = bidiIndex[uint32(i)<<6+uint32(s[1])] + if c0 < 0xF0 { // 3-byte UTF-8 + return t.lookupValue(uint32(i), s[2]) + } + i = bidiIndex[uint32(i)<<6+uint32(s[2])] + if c0 < 0xF8 { // 4-byte UTF-8 + return t.lookupValue(uint32(i), s[3]) + } + return 0 +} + +// lookupString returns the trie value for the first UTF-8 encoding in s and +// the width in bytes of this encoding. The size will be 0 if s does not +// hold enough bytes to complete the encoding. len(s) must be greater than 0. +func (t *bidiTrie) lookupString(s string) (v uint8, sz int) { + c0 := s[0] + switch { + case c0 < 0x80: // is ASCII + return bidiValues[c0], 1 + case c0 < 0xC2: + return 0, 1 // Illegal UTF-8: not a starter, not ASCII. + case c0 < 0xE0: // 2-byte UTF-8 + if len(s) < 2 { + return 0, 0 + } + i := bidiIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c1), 2 + case c0 < 0xF0: // 3-byte UTF-8 + if len(s) < 3 { + return 0, 0 + } + i := bidiIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = bidiIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c2), 3 + case c0 < 0xF8: // 4-byte UTF-8 + if len(s) < 4 { + return 0, 0 + } + i := bidiIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = bidiIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + o = uint32(i)<<6 + uint32(c2) + i = bidiIndex[o] + c3 := s[3] + if c3 < 0x80 || 0xC0 <= c3 { + return 0, 3 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c3), 4 + } + // Illegal rune + return 0, 1 +} + +// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s. +// s must start with a full and valid UTF-8 encoded rune. +func (t *bidiTrie) lookupStringUnsafe(s string) uint8 { + c0 := s[0] + if c0 < 0x80 { // is ASCII + return bidiValues[c0] + } + i := bidiIndex[c0] + if c0 < 0xE0 { // 2-byte UTF-8 + return t.lookupValue(uint32(i), s[1]) + } + i = bidiIndex[uint32(i)<<6+uint32(s[1])] + if c0 < 0xF0 { // 3-byte UTF-8 + return t.lookupValue(uint32(i), s[2]) + } + i = bidiIndex[uint32(i)<<6+uint32(s[2])] + if c0 < 0xF8 { // 4-byte UTF-8 + return t.lookupValue(uint32(i), s[3]) + } + return 0 +} + +// bidiTrie. Total size: 15744 bytes (15.38 KiB). Checksum: b4c3b70954803b86. +type bidiTrie struct{} + +func newBidiTrie(i int) *bidiTrie { + return &bidiTrie{} +} + +// lookupValue determines the type of block n and looks up the value for b. +func (t *bidiTrie) lookupValue(n uint32, b byte) uint8 { + switch { + default: + return uint8(bidiValues[n<<6+uint32(b)]) + } +} + +// bidiValues: 222 blocks, 14208 entries, 14208 bytes +// The third block is the zero block. +var bidiValues = [14208]uint8{ + // Block 0x0, offset 0x0 + 0x00: 0x000b, 0x01: 0x000b, 0x02: 0x000b, 0x03: 0x000b, 0x04: 0x000b, 0x05: 0x000b, + 0x06: 0x000b, 0x07: 0x000b, 0x08: 0x000b, 0x09: 0x0008, 0x0a: 0x0007, 0x0b: 0x0008, + 0x0c: 0x0009, 0x0d: 0x0007, 0x0e: 0x000b, 0x0f: 0x000b, 0x10: 0x000b, 0x11: 0x000b, + 0x12: 0x000b, 0x13: 0x000b, 0x14: 0x000b, 0x15: 0x000b, 0x16: 0x000b, 0x17: 0x000b, + 0x18: 0x000b, 0x19: 0x000b, 0x1a: 0x000b, 0x1b: 0x000b, 0x1c: 0x0007, 0x1d: 0x0007, + 0x1e: 0x0007, 0x1f: 0x0008, 0x20: 0x0009, 0x21: 0x000a, 0x22: 0x000a, 0x23: 0x0004, + 0x24: 0x0004, 0x25: 0x0004, 0x26: 0x000a, 0x27: 0x000a, 0x28: 0x003a, 0x29: 0x002a, + 0x2a: 0x000a, 0x2b: 0x0003, 0x2c: 0x0006, 0x2d: 0x0003, 0x2e: 0x0006, 0x2f: 0x0006, + 0x30: 0x0002, 0x31: 0x0002, 0x32: 0x0002, 0x33: 0x0002, 0x34: 0x0002, 0x35: 0x0002, + 0x36: 0x0002, 0x37: 0x0002, 0x38: 0x0002, 0x39: 0x0002, 0x3a: 0x0006, 0x3b: 0x000a, + 0x3c: 0x000a, 0x3d: 0x000a, 0x3e: 0x000a, 0x3f: 0x000a, + // Block 0x1, offset 0x40 + 0x40: 0x000a, + 0x5b: 0x005a, 0x5c: 0x000a, 0x5d: 0x004a, + 0x5e: 0x000a, 0x5f: 0x000a, 0x60: 0x000a, + 0x7b: 0x005a, + 0x7c: 0x000a, 0x7d: 0x004a, 0x7e: 0x000a, 0x7f: 0x000b, + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0xc0: 0x000b, 0xc1: 0x000b, 0xc2: 0x000b, 0xc3: 0x000b, 0xc4: 0x000b, 0xc5: 0x0007, + 0xc6: 0x000b, 0xc7: 0x000b, 0xc8: 0x000b, 0xc9: 0x000b, 0xca: 0x000b, 0xcb: 0x000b, + 0xcc: 0x000b, 0xcd: 0x000b, 0xce: 0x000b, 0xcf: 0x000b, 0xd0: 0x000b, 0xd1: 0x000b, + 0xd2: 0x000b, 0xd3: 0x000b, 0xd4: 0x000b, 0xd5: 0x000b, 0xd6: 0x000b, 0xd7: 0x000b, + 0xd8: 0x000b, 0xd9: 0x000b, 0xda: 0x000b, 0xdb: 0x000b, 0xdc: 0x000b, 0xdd: 0x000b, + 0xde: 0x000b, 0xdf: 0x000b, 0xe0: 0x0006, 0xe1: 0x000a, 0xe2: 0x0004, 0xe3: 0x0004, + 0xe4: 0x0004, 0xe5: 0x0004, 0xe6: 0x000a, 0xe7: 0x000a, 0xe8: 0x000a, 0xe9: 0x000a, + 0xeb: 0x000a, 0xec: 0x000a, 0xed: 0x000b, 0xee: 0x000a, 0xef: 0x000a, + 0xf0: 0x0004, 0xf1: 0x0004, 0xf2: 0x0002, 0xf3: 0x0002, 0xf4: 0x000a, + 0xf6: 0x000a, 0xf7: 0x000a, 0xf8: 0x000a, 0xf9: 0x0002, 0xfb: 0x000a, + 0xfc: 0x000a, 0xfd: 0x000a, 0xfe: 0x000a, 0xff: 0x000a, + // Block 0x4, offset 0x100 + 0x117: 0x000a, + 0x137: 0x000a, + // Block 0x5, offset 0x140 + 0x179: 0x000a, 0x17a: 0x000a, + // Block 0x6, offset 0x180 + 0x182: 0x000a, 0x183: 0x000a, 0x184: 0x000a, 0x185: 0x000a, + 0x186: 0x000a, 0x187: 0x000a, 0x188: 0x000a, 0x189: 0x000a, 0x18a: 0x000a, 0x18b: 0x000a, + 0x18c: 0x000a, 0x18d: 0x000a, 0x18e: 0x000a, 0x18f: 0x000a, + 0x192: 0x000a, 0x193: 0x000a, 0x194: 0x000a, 0x195: 0x000a, 0x196: 0x000a, 0x197: 0x000a, + 0x198: 0x000a, 0x199: 0x000a, 0x19a: 0x000a, 0x19b: 0x000a, 0x19c: 0x000a, 0x19d: 0x000a, + 0x19e: 0x000a, 0x19f: 0x000a, + 0x1a5: 0x000a, 0x1a6: 0x000a, 0x1a7: 0x000a, 0x1a8: 0x000a, 0x1a9: 0x000a, + 0x1aa: 0x000a, 0x1ab: 0x000a, 0x1ac: 0x000a, 0x1ad: 0x000a, 0x1af: 0x000a, + 0x1b0: 0x000a, 0x1b1: 0x000a, 0x1b2: 0x000a, 0x1b3: 0x000a, 0x1b4: 0x000a, 0x1b5: 0x000a, + 0x1b6: 0x000a, 0x1b7: 0x000a, 0x1b8: 0x000a, 0x1b9: 0x000a, 0x1ba: 0x000a, 0x1bb: 0x000a, + 0x1bc: 0x000a, 0x1bd: 0x000a, 0x1be: 0x000a, 0x1bf: 0x000a, + // Block 0x7, offset 0x1c0 + 0x1c0: 0x000c, 0x1c1: 0x000c, 0x1c2: 0x000c, 0x1c3: 0x000c, 0x1c4: 0x000c, 0x1c5: 0x000c, + 0x1c6: 0x000c, 0x1c7: 0x000c, 0x1c8: 0x000c, 0x1c9: 0x000c, 0x1ca: 0x000c, 0x1cb: 0x000c, + 0x1cc: 0x000c, 0x1cd: 0x000c, 0x1ce: 0x000c, 0x1cf: 0x000c, 0x1d0: 0x000c, 0x1d1: 0x000c, + 0x1d2: 0x000c, 0x1d3: 0x000c, 0x1d4: 0x000c, 0x1d5: 0x000c, 0x1d6: 0x000c, 0x1d7: 0x000c, + 0x1d8: 0x000c, 0x1d9: 0x000c, 0x1da: 0x000c, 0x1db: 0x000c, 0x1dc: 0x000c, 0x1dd: 0x000c, + 0x1de: 0x000c, 0x1df: 0x000c, 0x1e0: 0x000c, 0x1e1: 0x000c, 0x1e2: 0x000c, 0x1e3: 0x000c, + 0x1e4: 0x000c, 0x1e5: 0x000c, 0x1e6: 0x000c, 0x1e7: 0x000c, 0x1e8: 0x000c, 0x1e9: 0x000c, + 0x1ea: 0x000c, 0x1eb: 0x000c, 0x1ec: 0x000c, 0x1ed: 0x000c, 0x1ee: 0x000c, 0x1ef: 0x000c, + 0x1f0: 0x000c, 0x1f1: 0x000c, 0x1f2: 0x000c, 0x1f3: 0x000c, 0x1f4: 0x000c, 0x1f5: 0x000c, + 0x1f6: 0x000c, 0x1f7: 0x000c, 0x1f8: 0x000c, 0x1f9: 0x000c, 0x1fa: 0x000c, 0x1fb: 0x000c, + 0x1fc: 0x000c, 0x1fd: 0x000c, 0x1fe: 0x000c, 0x1ff: 0x000c, + // Block 0x8, offset 0x200 + 0x200: 0x000c, 0x201: 0x000c, 0x202: 0x000c, 0x203: 0x000c, 0x204: 0x000c, 0x205: 0x000c, + 0x206: 0x000c, 0x207: 0x000c, 0x208: 0x000c, 0x209: 0x000c, 0x20a: 0x000c, 0x20b: 0x000c, + 0x20c: 0x000c, 0x20d: 0x000c, 0x20e: 0x000c, 0x20f: 0x000c, 0x210: 0x000c, 0x211: 0x000c, + 0x212: 0x000c, 0x213: 0x000c, 0x214: 0x000c, 0x215: 0x000c, 0x216: 0x000c, 0x217: 0x000c, + 0x218: 0x000c, 0x219: 0x000c, 0x21a: 0x000c, 0x21b: 0x000c, 0x21c: 0x000c, 0x21d: 0x000c, + 0x21e: 0x000c, 0x21f: 0x000c, 0x220: 0x000c, 0x221: 0x000c, 0x222: 0x000c, 0x223: 0x000c, + 0x224: 0x000c, 0x225: 0x000c, 0x226: 0x000c, 0x227: 0x000c, 0x228: 0x000c, 0x229: 0x000c, + 0x22a: 0x000c, 0x22b: 0x000c, 0x22c: 0x000c, 0x22d: 0x000c, 0x22e: 0x000c, 0x22f: 0x000c, + 0x234: 0x000a, 0x235: 0x000a, + 0x23e: 0x000a, + // Block 0x9, offset 0x240 + 0x244: 0x000a, 0x245: 0x000a, + 0x247: 0x000a, + // Block 0xa, offset 0x280 + 0x2b6: 0x000a, + // Block 0xb, offset 0x2c0 + 0x2c3: 0x000c, 0x2c4: 0x000c, 0x2c5: 0x000c, + 0x2c6: 0x000c, 0x2c7: 0x000c, 0x2c8: 0x000c, 0x2c9: 0x000c, + // Block 0xc, offset 0x300 + 0x30a: 0x000a, + 0x30d: 0x000a, 0x30e: 0x000a, 0x30f: 0x0004, 0x310: 0x0001, 0x311: 0x000c, + 0x312: 0x000c, 0x313: 0x000c, 0x314: 0x000c, 0x315: 0x000c, 0x316: 0x000c, 0x317: 0x000c, + 0x318: 0x000c, 0x319: 0x000c, 0x31a: 0x000c, 0x31b: 0x000c, 0x31c: 0x000c, 0x31d: 0x000c, + 0x31e: 0x000c, 0x31f: 0x000c, 0x320: 0x000c, 0x321: 0x000c, 0x322: 0x000c, 0x323: 0x000c, + 0x324: 0x000c, 0x325: 0x000c, 0x326: 0x000c, 0x327: 0x000c, 0x328: 0x000c, 0x329: 0x000c, + 0x32a: 0x000c, 0x32b: 0x000c, 0x32c: 0x000c, 0x32d: 0x000c, 0x32e: 0x000c, 0x32f: 0x000c, + 0x330: 0x000c, 0x331: 0x000c, 0x332: 0x000c, 0x333: 0x000c, 0x334: 0x000c, 0x335: 0x000c, + 0x336: 0x000c, 0x337: 0x000c, 0x338: 0x000c, 0x339: 0x000c, 0x33a: 0x000c, 0x33b: 0x000c, + 0x33c: 0x000c, 0x33d: 0x000c, 0x33e: 0x0001, 0x33f: 0x000c, + // Block 0xd, offset 0x340 + 0x340: 0x0001, 0x341: 0x000c, 0x342: 0x000c, 0x343: 0x0001, 0x344: 0x000c, 0x345: 0x000c, + 0x346: 0x0001, 0x347: 0x000c, 0x348: 0x0001, 0x349: 0x0001, 0x34a: 0x0001, 0x34b: 0x0001, + 0x34c: 0x0001, 0x34d: 0x0001, 0x34e: 0x0001, 0x34f: 0x0001, 0x350: 0x0001, 0x351: 0x0001, + 0x352: 0x0001, 0x353: 0x0001, 0x354: 0x0001, 0x355: 0x0001, 0x356: 0x0001, 0x357: 0x0001, + 0x358: 0x0001, 0x359: 0x0001, 0x35a: 0x0001, 0x35b: 0x0001, 0x35c: 0x0001, 0x35d: 0x0001, + 0x35e: 0x0001, 0x35f: 0x0001, 0x360: 0x0001, 0x361: 0x0001, 0x362: 0x0001, 0x363: 0x0001, + 0x364: 0x0001, 0x365: 0x0001, 0x366: 0x0001, 0x367: 0x0001, 0x368: 0x0001, 0x369: 0x0001, + 0x36a: 0x0001, 0x36b: 0x0001, 0x36c: 0x0001, 0x36d: 0x0001, 0x36e: 0x0001, 0x36f: 0x0001, + 0x370: 0x0001, 0x371: 0x0001, 0x372: 0x0001, 0x373: 0x0001, 0x374: 0x0001, 0x375: 0x0001, + 0x376: 0x0001, 0x377: 0x0001, 0x378: 0x0001, 0x379: 0x0001, 0x37a: 0x0001, 0x37b: 0x0001, + 0x37c: 0x0001, 0x37d: 0x0001, 0x37e: 0x0001, 0x37f: 0x0001, + // Block 0xe, offset 0x380 + 0x380: 0x0005, 0x381: 0x0005, 0x382: 0x0005, 0x383: 0x0005, 0x384: 0x0005, 0x385: 0x0005, + 0x386: 0x000a, 0x387: 0x000a, 0x388: 0x000d, 0x389: 0x0004, 0x38a: 0x0004, 0x38b: 0x000d, + 0x38c: 0x0006, 0x38d: 0x000d, 0x38e: 0x000a, 0x38f: 0x000a, 0x390: 0x000c, 0x391: 0x000c, + 0x392: 0x000c, 0x393: 0x000c, 0x394: 0x000c, 0x395: 0x000c, 0x396: 0x000c, 0x397: 0x000c, + 0x398: 0x000c, 0x399: 0x000c, 0x39a: 0x000c, 0x39b: 0x000d, 0x39c: 0x000d, 0x39d: 0x000d, + 0x39e: 0x000d, 0x39f: 0x000d, 0x3a0: 0x000d, 0x3a1: 0x000d, 0x3a2: 0x000d, 0x3a3: 0x000d, + 0x3a4: 0x000d, 0x3a5: 0x000d, 0x3a6: 0x000d, 0x3a7: 0x000d, 0x3a8: 0x000d, 0x3a9: 0x000d, + 0x3aa: 0x000d, 0x3ab: 0x000d, 0x3ac: 0x000d, 0x3ad: 0x000d, 0x3ae: 0x000d, 0x3af: 0x000d, + 0x3b0: 0x000d, 0x3b1: 0x000d, 0x3b2: 0x000d, 0x3b3: 0x000d, 0x3b4: 0x000d, 0x3b5: 0x000d, + 0x3b6: 0x000d, 0x3b7: 0x000d, 0x3b8: 0x000d, 0x3b9: 0x000d, 0x3ba: 0x000d, 0x3bb: 0x000d, + 0x3bc: 0x000d, 0x3bd: 0x000d, 0x3be: 0x000d, 0x3bf: 0x000d, + // Block 0xf, offset 0x3c0 + 0x3c0: 0x000d, 0x3c1: 0x000d, 0x3c2: 0x000d, 0x3c3: 0x000d, 0x3c4: 0x000d, 0x3c5: 0x000d, + 0x3c6: 0x000d, 0x3c7: 0x000d, 0x3c8: 0x000d, 0x3c9: 0x000d, 0x3ca: 0x000d, 0x3cb: 0x000c, + 0x3cc: 0x000c, 0x3cd: 0x000c, 0x3ce: 0x000c, 0x3cf: 0x000c, 0x3d0: 0x000c, 0x3d1: 0x000c, + 0x3d2: 0x000c, 0x3d3: 0x000c, 0x3d4: 0x000c, 0x3d5: 0x000c, 0x3d6: 0x000c, 0x3d7: 0x000c, + 0x3d8: 0x000c, 0x3d9: 0x000c, 0x3da: 0x000c, 0x3db: 0x000c, 0x3dc: 0x000c, 0x3dd: 0x000c, + 0x3de: 0x000c, 0x3df: 0x000c, 0x3e0: 0x0005, 0x3e1: 0x0005, 0x3e2: 0x0005, 0x3e3: 0x0005, + 0x3e4: 0x0005, 0x3e5: 0x0005, 0x3e6: 0x0005, 0x3e7: 0x0005, 0x3e8: 0x0005, 0x3e9: 0x0005, + 0x3ea: 0x0004, 0x3eb: 0x0005, 0x3ec: 0x0005, 0x3ed: 0x000d, 0x3ee: 0x000d, 0x3ef: 0x000d, + 0x3f0: 0x000c, 0x3f1: 0x000d, 0x3f2: 0x000d, 0x3f3: 0x000d, 0x3f4: 0x000d, 0x3f5: 0x000d, + 0x3f6: 0x000d, 0x3f7: 0x000d, 0x3f8: 0x000d, 0x3f9: 0x000d, 0x3fa: 0x000d, 0x3fb: 0x000d, + 0x3fc: 0x000d, 0x3fd: 0x000d, 0x3fe: 0x000d, 0x3ff: 0x000d, + // Block 0x10, offset 0x400 + 0x400: 0x000d, 0x401: 0x000d, 0x402: 0x000d, 0x403: 0x000d, 0x404: 0x000d, 0x405: 0x000d, + 0x406: 0x000d, 0x407: 0x000d, 0x408: 0x000d, 0x409: 0x000d, 0x40a: 0x000d, 0x40b: 0x000d, + 0x40c: 0x000d, 0x40d: 0x000d, 0x40e: 0x000d, 0x40f: 0x000d, 0x410: 0x000d, 0x411: 0x000d, + 0x412: 0x000d, 0x413: 0x000d, 0x414: 0x000d, 0x415: 0x000d, 0x416: 0x000d, 0x417: 0x000d, + 0x418: 0x000d, 0x419: 0x000d, 0x41a: 0x000d, 0x41b: 0x000d, 0x41c: 0x000d, 0x41d: 0x000d, + 0x41e: 0x000d, 0x41f: 0x000d, 0x420: 0x000d, 0x421: 0x000d, 0x422: 0x000d, 0x423: 0x000d, + 0x424: 0x000d, 0x425: 0x000d, 0x426: 0x000d, 0x427: 0x000d, 0x428: 0x000d, 0x429: 0x000d, + 0x42a: 0x000d, 0x42b: 0x000d, 0x42c: 0x000d, 0x42d: 0x000d, 0x42e: 0x000d, 0x42f: 0x000d, + 0x430: 0x000d, 0x431: 0x000d, 0x432: 0x000d, 0x433: 0x000d, 0x434: 0x000d, 0x435: 0x000d, + 0x436: 0x000d, 0x437: 0x000d, 0x438: 0x000d, 0x439: 0x000d, 0x43a: 0x000d, 0x43b: 0x000d, + 0x43c: 0x000d, 0x43d: 0x000d, 0x43e: 0x000d, 0x43f: 0x000d, + // Block 0x11, offset 0x440 + 0x440: 0x000d, 0x441: 0x000d, 0x442: 0x000d, 0x443: 0x000d, 0x444: 0x000d, 0x445: 0x000d, + 0x446: 0x000d, 0x447: 0x000d, 0x448: 0x000d, 0x449: 0x000d, 0x44a: 0x000d, 0x44b: 0x000d, + 0x44c: 0x000d, 0x44d: 0x000d, 0x44e: 0x000d, 0x44f: 0x000d, 0x450: 0x000d, 0x451: 0x000d, + 0x452: 0x000d, 0x453: 0x000d, 0x454: 0x000d, 0x455: 0x000d, 0x456: 0x000c, 0x457: 0x000c, + 0x458: 0x000c, 0x459: 0x000c, 0x45a: 0x000c, 0x45b: 0x000c, 0x45c: 0x000c, 0x45d: 0x0005, + 0x45e: 0x000a, 0x45f: 0x000c, 0x460: 0x000c, 0x461: 0x000c, 0x462: 0x000c, 0x463: 0x000c, + 0x464: 0x000c, 0x465: 0x000d, 0x466: 0x000d, 0x467: 0x000c, 0x468: 0x000c, 0x469: 0x000a, + 0x46a: 0x000c, 0x46b: 0x000c, 0x46c: 0x000c, 0x46d: 0x000c, 0x46e: 0x000d, 0x46f: 0x000d, + 0x470: 0x0002, 0x471: 0x0002, 0x472: 0x0002, 0x473: 0x0002, 0x474: 0x0002, 0x475: 0x0002, + 0x476: 0x0002, 0x477: 0x0002, 0x478: 0x0002, 0x479: 0x0002, 0x47a: 0x000d, 0x47b: 0x000d, + 0x47c: 0x000d, 0x47d: 0x000d, 0x47e: 0x000d, 0x47f: 0x000d, + // Block 0x12, offset 0x480 + 0x480: 0x000d, 0x481: 0x000d, 0x482: 0x000d, 0x483: 0x000d, 0x484: 0x000d, 0x485: 0x000d, + 0x486: 0x000d, 0x487: 0x000d, 0x488: 0x000d, 0x489: 0x000d, 0x48a: 0x000d, 0x48b: 0x000d, + 0x48c: 0x000d, 0x48d: 0x000d, 0x48e: 0x000d, 0x48f: 0x000d, 0x490: 0x000d, 0x491: 0x000c, + 0x492: 0x000d, 0x493: 0x000d, 0x494: 0x000d, 0x495: 0x000d, 0x496: 0x000d, 0x497: 0x000d, + 0x498: 0x000d, 0x499: 0x000d, 0x49a: 0x000d, 0x49b: 0x000d, 0x49c: 0x000d, 0x49d: 0x000d, + 0x49e: 0x000d, 0x49f: 0x000d, 0x4a0: 0x000d, 0x4a1: 0x000d, 0x4a2: 0x000d, 0x4a3: 0x000d, + 0x4a4: 0x000d, 0x4a5: 0x000d, 0x4a6: 0x000d, 0x4a7: 0x000d, 0x4a8: 0x000d, 0x4a9: 0x000d, + 0x4aa: 0x000d, 0x4ab: 0x000d, 0x4ac: 0x000d, 0x4ad: 0x000d, 0x4ae: 0x000d, 0x4af: 0x000d, + 0x4b0: 0x000c, 0x4b1: 0x000c, 0x4b2: 0x000c, 0x4b3: 0x000c, 0x4b4: 0x000c, 0x4b5: 0x000c, + 0x4b6: 0x000c, 0x4b7: 0x000c, 0x4b8: 0x000c, 0x4b9: 0x000c, 0x4ba: 0x000c, 0x4bb: 0x000c, + 0x4bc: 0x000c, 0x4bd: 0x000c, 0x4be: 0x000c, 0x4bf: 0x000c, + // Block 0x13, offset 0x4c0 + 0x4c0: 0x000c, 0x4c1: 0x000c, 0x4c2: 0x000c, 0x4c3: 0x000c, 0x4c4: 0x000c, 0x4c5: 0x000c, + 0x4c6: 0x000c, 0x4c7: 0x000c, 0x4c8: 0x000c, 0x4c9: 0x000c, 0x4ca: 0x000c, 0x4cb: 0x000d, + 0x4cc: 0x000d, 0x4cd: 0x000d, 0x4ce: 0x000d, 0x4cf: 0x000d, 0x4d0: 0x000d, 0x4d1: 0x000d, + 0x4d2: 0x000d, 0x4d3: 0x000d, 0x4d4: 0x000d, 0x4d5: 0x000d, 0x4d6: 0x000d, 0x4d7: 0x000d, + 0x4d8: 0x000d, 0x4d9: 0x000d, 0x4da: 0x000d, 0x4db: 0x000d, 0x4dc: 0x000d, 0x4dd: 0x000d, + 0x4de: 0x000d, 0x4df: 0x000d, 0x4e0: 0x000d, 0x4e1: 0x000d, 0x4e2: 0x000d, 0x4e3: 0x000d, + 0x4e4: 0x000d, 0x4e5: 0x000d, 0x4e6: 0x000d, 0x4e7: 0x000d, 0x4e8: 0x000d, 0x4e9: 0x000d, + 0x4ea: 0x000d, 0x4eb: 0x000d, 0x4ec: 0x000d, 0x4ed: 0x000d, 0x4ee: 0x000d, 0x4ef: 0x000d, + 0x4f0: 0x000d, 0x4f1: 0x000d, 0x4f2: 0x000d, 0x4f3: 0x000d, 0x4f4: 0x000d, 0x4f5: 0x000d, + 0x4f6: 0x000d, 0x4f7: 0x000d, 0x4f8: 0x000d, 0x4f9: 0x000d, 0x4fa: 0x000d, 0x4fb: 0x000d, + 0x4fc: 0x000d, 0x4fd: 0x000d, 0x4fe: 0x000d, 0x4ff: 0x000d, + // Block 0x14, offset 0x500 + 0x500: 0x000d, 0x501: 0x000d, 0x502: 0x000d, 0x503: 0x000d, 0x504: 0x000d, 0x505: 0x000d, + 0x506: 0x000d, 0x507: 0x000d, 0x508: 0x000d, 0x509: 0x000d, 0x50a: 0x000d, 0x50b: 0x000d, + 0x50c: 0x000d, 0x50d: 0x000d, 0x50e: 0x000d, 0x50f: 0x000d, 0x510: 0x000d, 0x511: 0x000d, + 0x512: 0x000d, 0x513: 0x000d, 0x514: 0x000d, 0x515: 0x000d, 0x516: 0x000d, 0x517: 0x000d, + 0x518: 0x000d, 0x519: 0x000d, 0x51a: 0x000d, 0x51b: 0x000d, 0x51c: 0x000d, 0x51d: 0x000d, + 0x51e: 0x000d, 0x51f: 0x000d, 0x520: 0x000d, 0x521: 0x000d, 0x522: 0x000d, 0x523: 0x000d, + 0x524: 0x000d, 0x525: 0x000d, 0x526: 0x000c, 0x527: 0x000c, 0x528: 0x000c, 0x529: 0x000c, + 0x52a: 0x000c, 0x52b: 0x000c, 0x52c: 0x000c, 0x52d: 0x000c, 0x52e: 0x000c, 0x52f: 0x000c, + 0x530: 0x000c, 0x531: 0x000d, 0x532: 0x000d, 0x533: 0x000d, 0x534: 0x000d, 0x535: 0x000d, + 0x536: 0x000d, 0x537: 0x000d, 0x538: 0x000d, 0x539: 0x000d, 0x53a: 0x000d, 0x53b: 0x000d, + 0x53c: 0x000d, 0x53d: 0x000d, 0x53e: 0x000d, 0x53f: 0x000d, + // Block 0x15, offset 0x540 + 0x540: 0x0001, 0x541: 0x0001, 0x542: 0x0001, 0x543: 0x0001, 0x544: 0x0001, 0x545: 0x0001, + 0x546: 0x0001, 0x547: 0x0001, 0x548: 0x0001, 0x549: 0x0001, 0x54a: 0x0001, 0x54b: 0x0001, + 0x54c: 0x0001, 0x54d: 0x0001, 0x54e: 0x0001, 0x54f: 0x0001, 0x550: 0x0001, 0x551: 0x0001, + 0x552: 0x0001, 0x553: 0x0001, 0x554: 0x0001, 0x555: 0x0001, 0x556: 0x0001, 0x557: 0x0001, + 0x558: 0x0001, 0x559: 0x0001, 0x55a: 0x0001, 0x55b: 0x0001, 0x55c: 0x0001, 0x55d: 0x0001, + 0x55e: 0x0001, 0x55f: 0x0001, 0x560: 0x0001, 0x561: 0x0001, 0x562: 0x0001, 0x563: 0x0001, + 0x564: 0x0001, 0x565: 0x0001, 0x566: 0x0001, 0x567: 0x0001, 0x568: 0x0001, 0x569: 0x0001, + 0x56a: 0x0001, 0x56b: 0x000c, 0x56c: 0x000c, 0x56d: 0x000c, 0x56e: 0x000c, 0x56f: 0x000c, + 0x570: 0x000c, 0x571: 0x000c, 0x572: 0x000c, 0x573: 0x000c, 0x574: 0x0001, 0x575: 0x0001, + 0x576: 0x000a, 0x577: 0x000a, 0x578: 0x000a, 0x579: 0x000a, 0x57a: 0x0001, 0x57b: 0x0001, + 0x57c: 0x0001, 0x57d: 0x0001, 0x57e: 0x0001, 0x57f: 0x0001, + // Block 0x16, offset 0x580 + 0x580: 0x0001, 0x581: 0x0001, 0x582: 0x0001, 0x583: 0x0001, 0x584: 0x0001, 0x585: 0x0001, + 0x586: 0x0001, 0x587: 0x0001, 0x588: 0x0001, 0x589: 0x0001, 0x58a: 0x0001, 0x58b: 0x0001, + 0x58c: 0x0001, 0x58d: 0x0001, 0x58e: 0x0001, 0x58f: 0x0001, 0x590: 0x0001, 0x591: 0x0001, + 0x592: 0x0001, 0x593: 0x0001, 0x594: 0x0001, 0x595: 0x0001, 0x596: 0x000c, 0x597: 0x000c, + 0x598: 0x000c, 0x599: 0x000c, 0x59a: 0x0001, 0x59b: 0x000c, 0x59c: 0x000c, 0x59d: 0x000c, + 0x59e: 0x000c, 0x59f: 0x000c, 0x5a0: 0x000c, 0x5a1: 0x000c, 0x5a2: 0x000c, 0x5a3: 0x000c, + 0x5a4: 0x0001, 0x5a5: 0x000c, 0x5a6: 0x000c, 0x5a7: 0x000c, 0x5a8: 0x0001, 0x5a9: 0x000c, + 0x5aa: 0x000c, 0x5ab: 0x000c, 0x5ac: 0x000c, 0x5ad: 0x000c, 0x5ae: 0x0001, 0x5af: 0x0001, + 0x5b0: 0x0001, 0x5b1: 0x0001, 0x5b2: 0x0001, 0x5b3: 0x0001, 0x5b4: 0x0001, 0x5b5: 0x0001, + 0x5b6: 0x0001, 0x5b7: 0x0001, 0x5b8: 0x0001, 0x5b9: 0x0001, 0x5ba: 0x0001, 0x5bb: 0x0001, + 0x5bc: 0x0001, 0x5bd: 0x0001, 0x5be: 0x0001, 0x5bf: 0x0001, + // Block 0x17, offset 0x5c0 + 0x5c0: 0x0001, 0x5c1: 0x0001, 0x5c2: 0x0001, 0x5c3: 0x0001, 0x5c4: 0x0001, 0x5c5: 0x0001, + 0x5c6: 0x0001, 0x5c7: 0x0001, 0x5c8: 0x0001, 0x5c9: 0x0001, 0x5ca: 0x0001, 0x5cb: 0x0001, + 0x5cc: 0x0001, 0x5cd: 0x0001, 0x5ce: 0x0001, 0x5cf: 0x0001, 0x5d0: 0x0001, 0x5d1: 0x0001, + 0x5d2: 0x0001, 0x5d3: 0x0001, 0x5d4: 0x0001, 0x5d5: 0x0001, 0x5d6: 0x0001, 0x5d7: 0x0001, + 0x5d8: 0x0001, 0x5d9: 0x000c, 0x5da: 0x000c, 0x5db: 0x000c, 0x5dc: 0x0001, 0x5dd: 0x0001, + 0x5de: 0x0001, 0x5df: 0x0001, 0x5e0: 0x0001, 0x5e1: 0x0001, 0x5e2: 0x0001, 0x5e3: 0x0001, + 0x5e4: 0x0001, 0x5e5: 0x0001, 0x5e6: 0x0001, 0x5e7: 0x0001, 0x5e8: 0x0001, 0x5e9: 0x0001, + 0x5ea: 0x0001, 0x5eb: 0x0001, 0x5ec: 0x0001, 0x5ed: 0x0001, 0x5ee: 0x0001, 0x5ef: 0x0001, + 0x5f0: 0x0001, 0x5f1: 0x0001, 0x5f2: 0x0001, 0x5f3: 0x0001, 0x5f4: 0x0001, 0x5f5: 0x0001, + 0x5f6: 0x0001, 0x5f7: 0x0001, 0x5f8: 0x0001, 0x5f9: 0x0001, 0x5fa: 0x0001, 0x5fb: 0x0001, + 0x5fc: 0x0001, 0x5fd: 0x0001, 0x5fe: 0x0001, 0x5ff: 0x0001, + // Block 0x18, offset 0x600 + 0x600: 0x0001, 0x601: 0x0001, 0x602: 0x0001, 0x603: 0x0001, 0x604: 0x0001, 0x605: 0x0001, + 0x606: 0x0001, 0x607: 0x0001, 0x608: 0x0001, 0x609: 0x0001, 0x60a: 0x0001, 0x60b: 0x0001, + 0x60c: 0x0001, 0x60d: 0x0001, 0x60e: 0x0001, 0x60f: 0x0001, 0x610: 0x0001, 0x611: 0x0001, + 0x612: 0x0001, 0x613: 0x0001, 0x614: 0x0001, 0x615: 0x0001, 0x616: 0x0001, 0x617: 0x0001, + 0x618: 0x0001, 0x619: 0x0001, 0x61a: 0x0001, 0x61b: 0x0001, 0x61c: 0x0001, 0x61d: 0x0001, + 0x61e: 0x0001, 0x61f: 0x0001, 0x620: 0x000d, 0x621: 0x000d, 0x622: 0x000d, 0x623: 0x000d, + 0x624: 0x000d, 0x625: 0x000d, 0x626: 0x000d, 0x627: 0x000d, 0x628: 0x000d, 0x629: 0x000d, + 0x62a: 0x000d, 0x62b: 0x000d, 0x62c: 0x000d, 0x62d: 0x000d, 0x62e: 0x000d, 0x62f: 0x000d, + 0x630: 0x000d, 0x631: 0x000d, 0x632: 0x000d, 0x633: 0x000d, 0x634: 0x000d, 0x635: 0x000d, + 0x636: 0x000d, 0x637: 0x000d, 0x638: 0x000d, 0x639: 0x000d, 0x63a: 0x000d, 0x63b: 0x000d, + 0x63c: 0x000d, 0x63d: 0x000d, 0x63e: 0x000d, 0x63f: 0x000d, + // Block 0x19, offset 0x640 + 0x640: 0x000d, 0x641: 0x000d, 0x642: 0x000d, 0x643: 0x000d, 0x644: 0x000d, 0x645: 0x000d, + 0x646: 0x000d, 0x647: 0x000d, 0x648: 0x000d, 0x649: 0x000d, 0x64a: 0x000d, 0x64b: 0x000d, + 0x64c: 0x000d, 0x64d: 0x000d, 0x64e: 0x000d, 0x64f: 0x000d, 0x650: 0x000d, 0x651: 0x000d, + 0x652: 0x000d, 0x653: 0x000d, 0x654: 0x000c, 0x655: 0x000c, 0x656: 0x000c, 0x657: 0x000c, + 0x658: 0x000c, 0x659: 0x000c, 0x65a: 0x000c, 0x65b: 0x000c, 0x65c: 0x000c, 0x65d: 0x000c, + 0x65e: 0x000c, 0x65f: 0x000c, 0x660: 0x000c, 0x661: 0x000c, 0x662: 0x0005, 0x663: 0x000c, + 0x664: 0x000c, 0x665: 0x000c, 0x666: 0x000c, 0x667: 0x000c, 0x668: 0x000c, 0x669: 0x000c, + 0x66a: 0x000c, 0x66b: 0x000c, 0x66c: 0x000c, 0x66d: 0x000c, 0x66e: 0x000c, 0x66f: 0x000c, + 0x670: 0x000c, 0x671: 0x000c, 0x672: 0x000c, 0x673: 0x000c, 0x674: 0x000c, 0x675: 0x000c, + 0x676: 0x000c, 0x677: 0x000c, 0x678: 0x000c, 0x679: 0x000c, 0x67a: 0x000c, 0x67b: 0x000c, + 0x67c: 0x000c, 0x67d: 0x000c, 0x67e: 0x000c, 0x67f: 0x000c, + // Block 0x1a, offset 0x680 + 0x680: 0x000c, 0x681: 0x000c, 0x682: 0x000c, + 0x6ba: 0x000c, + 0x6bc: 0x000c, + // Block 0x1b, offset 0x6c0 + 0x6c1: 0x000c, 0x6c2: 0x000c, 0x6c3: 0x000c, 0x6c4: 0x000c, 0x6c5: 0x000c, + 0x6c6: 0x000c, 0x6c7: 0x000c, 0x6c8: 0x000c, + 0x6cd: 0x000c, 0x6d1: 0x000c, + 0x6d2: 0x000c, 0x6d3: 0x000c, 0x6d4: 0x000c, 0x6d5: 0x000c, 0x6d6: 0x000c, 0x6d7: 0x000c, + 0x6e2: 0x000c, 0x6e3: 0x000c, + // Block 0x1c, offset 0x700 + 0x701: 0x000c, + 0x73c: 0x000c, + // Block 0x1d, offset 0x740 + 0x741: 0x000c, 0x742: 0x000c, 0x743: 0x000c, 0x744: 0x000c, + 0x74d: 0x000c, + 0x762: 0x000c, 0x763: 0x000c, + 0x772: 0x0004, 0x773: 0x0004, + 0x77b: 0x0004, + // Block 0x1e, offset 0x780 + 0x781: 0x000c, 0x782: 0x000c, + 0x7bc: 0x000c, + // Block 0x1f, offset 0x7c0 + 0x7c1: 0x000c, 0x7c2: 0x000c, + 0x7c7: 0x000c, 0x7c8: 0x000c, 0x7cb: 0x000c, + 0x7cc: 0x000c, 0x7cd: 0x000c, 0x7d1: 0x000c, + 0x7f0: 0x000c, 0x7f1: 0x000c, 0x7f5: 0x000c, + // Block 0x20, offset 0x800 + 0x801: 0x000c, 0x802: 0x000c, 0x803: 0x000c, 0x804: 0x000c, 0x805: 0x000c, + 0x807: 0x000c, 0x808: 0x000c, + 0x80d: 0x000c, + 0x822: 0x000c, 0x823: 0x000c, + 0x831: 0x0004, + // Block 0x21, offset 0x840 + 0x841: 0x000c, + 0x87c: 0x000c, 0x87f: 0x000c, + // Block 0x22, offset 0x880 + 0x881: 0x000c, 0x882: 0x000c, 0x883: 0x000c, 0x884: 0x000c, + 0x88d: 0x000c, + 0x896: 0x000c, + 0x8a2: 0x000c, 0x8a3: 0x000c, + // Block 0x23, offset 0x8c0 + 0x8c2: 0x000c, + // Block 0x24, offset 0x900 + 0x900: 0x000c, + 0x90d: 0x000c, + 0x933: 0x000a, 0x934: 0x000a, 0x935: 0x000a, + 0x936: 0x000a, 0x937: 0x000a, 0x938: 0x000a, 0x939: 0x0004, 0x93a: 0x000a, + // Block 0x25, offset 0x940 + 0x940: 0x000c, + 0x97e: 0x000c, 0x97f: 0x000c, + // Block 0x26, offset 0x980 + 0x980: 0x000c, + 0x986: 0x000c, 0x987: 0x000c, 0x988: 0x000c, 0x98a: 0x000c, 0x98b: 0x000c, + 0x98c: 0x000c, 0x98d: 0x000c, + 0x995: 0x000c, 0x996: 0x000c, + 0x9a2: 0x000c, 0x9a3: 0x000c, + 0x9b8: 0x000a, 0x9b9: 0x000a, 0x9ba: 0x000a, 0x9bb: 0x000a, + 0x9bc: 0x000a, 0x9bd: 0x000a, 0x9be: 0x000a, + // Block 0x27, offset 0x9c0 + 0x9cc: 0x000c, 0x9cd: 0x000c, + 0x9e2: 0x000c, 0x9e3: 0x000c, + // Block 0x28, offset 0xa00 + 0xa01: 0x000c, + // Block 0x29, offset 0xa40 + 0xa41: 0x000c, 0xa42: 0x000c, 0xa43: 0x000c, 0xa44: 0x000c, + 0xa4d: 0x000c, + 0xa62: 0x000c, 0xa63: 0x000c, + // Block 0x2a, offset 0xa80 + 0xa8a: 0x000c, + 0xa92: 0x000c, 0xa93: 0x000c, 0xa94: 0x000c, 0xa96: 0x000c, + // Block 0x2b, offset 0xac0 + 0xaf1: 0x000c, 0xaf4: 0x000c, 0xaf5: 0x000c, + 0xaf6: 0x000c, 0xaf7: 0x000c, 0xaf8: 0x000c, 0xaf9: 0x000c, 0xafa: 0x000c, + 0xaff: 0x0004, + // Block 0x2c, offset 0xb00 + 0xb07: 0x000c, 0xb08: 0x000c, 0xb09: 0x000c, 0xb0a: 0x000c, 0xb0b: 0x000c, + 0xb0c: 0x000c, 0xb0d: 0x000c, 0xb0e: 0x000c, + // Block 0x2d, offset 0xb40 + 0xb71: 0x000c, 0xb74: 0x000c, 0xb75: 0x000c, + 0xb76: 0x000c, 0xb77: 0x000c, 0xb78: 0x000c, 0xb79: 0x000c, 0xb7b: 0x000c, + 0xb7c: 0x000c, + // Block 0x2e, offset 0xb80 + 0xb88: 0x000c, 0xb89: 0x000c, 0xb8a: 0x000c, 0xb8b: 0x000c, + 0xb8c: 0x000c, 0xb8d: 0x000c, + // Block 0x2f, offset 0xbc0 + 0xbd8: 0x000c, 0xbd9: 0x000c, + 0xbf5: 0x000c, + 0xbf7: 0x000c, 0xbf9: 0x000c, 0xbfa: 0x003a, 0xbfb: 0x002a, + 0xbfc: 0x003a, 0xbfd: 0x002a, + // Block 0x30, offset 0xc00 + 0xc31: 0x000c, 0xc32: 0x000c, 0xc33: 0x000c, 0xc34: 0x000c, 0xc35: 0x000c, + 0xc36: 0x000c, 0xc37: 0x000c, 0xc38: 0x000c, 0xc39: 0x000c, 0xc3a: 0x000c, 0xc3b: 0x000c, + 0xc3c: 0x000c, 0xc3d: 0x000c, 0xc3e: 0x000c, + // Block 0x31, offset 0xc40 + 0xc40: 0x000c, 0xc41: 0x000c, 0xc42: 0x000c, 0xc43: 0x000c, 0xc44: 0x000c, + 0xc46: 0x000c, 0xc47: 0x000c, + 0xc4d: 0x000c, 0xc4e: 0x000c, 0xc4f: 0x000c, 0xc50: 0x000c, 0xc51: 0x000c, + 0xc52: 0x000c, 0xc53: 0x000c, 0xc54: 0x000c, 0xc55: 0x000c, 0xc56: 0x000c, 0xc57: 0x000c, + 0xc59: 0x000c, 0xc5a: 0x000c, 0xc5b: 0x000c, 0xc5c: 0x000c, 0xc5d: 0x000c, + 0xc5e: 0x000c, 0xc5f: 0x000c, 0xc60: 0x000c, 0xc61: 0x000c, 0xc62: 0x000c, 0xc63: 0x000c, + 0xc64: 0x000c, 0xc65: 0x000c, 0xc66: 0x000c, 0xc67: 0x000c, 0xc68: 0x000c, 0xc69: 0x000c, + 0xc6a: 0x000c, 0xc6b: 0x000c, 0xc6c: 0x000c, 0xc6d: 0x000c, 0xc6e: 0x000c, 0xc6f: 0x000c, + 0xc70: 0x000c, 0xc71: 0x000c, 0xc72: 0x000c, 0xc73: 0x000c, 0xc74: 0x000c, 0xc75: 0x000c, + 0xc76: 0x000c, 0xc77: 0x000c, 0xc78: 0x000c, 0xc79: 0x000c, 0xc7a: 0x000c, 0xc7b: 0x000c, + 0xc7c: 0x000c, + // Block 0x32, offset 0xc80 + 0xc86: 0x000c, + // Block 0x33, offset 0xcc0 + 0xced: 0x000c, 0xcee: 0x000c, 0xcef: 0x000c, + 0xcf0: 0x000c, 0xcf2: 0x000c, 0xcf3: 0x000c, 0xcf4: 0x000c, 0xcf5: 0x000c, + 0xcf6: 0x000c, 0xcf7: 0x000c, 0xcf9: 0x000c, 0xcfa: 0x000c, + 0xcfd: 0x000c, 0xcfe: 0x000c, + // Block 0x34, offset 0xd00 + 0xd18: 0x000c, 0xd19: 0x000c, + 0xd1e: 0x000c, 0xd1f: 0x000c, 0xd20: 0x000c, + 0xd31: 0x000c, 0xd32: 0x000c, 0xd33: 0x000c, 0xd34: 0x000c, + // Block 0x35, offset 0xd40 + 0xd42: 0x000c, 0xd45: 0x000c, + 0xd46: 0x000c, + 0xd4d: 0x000c, + 0xd5d: 0x000c, + // Block 0x36, offset 0xd80 + 0xd9d: 0x000c, + 0xd9e: 0x000c, 0xd9f: 0x000c, + // Block 0x37, offset 0xdc0 + 0xdd0: 0x000a, 0xdd1: 0x000a, + 0xdd2: 0x000a, 0xdd3: 0x000a, 0xdd4: 0x000a, 0xdd5: 0x000a, 0xdd6: 0x000a, 0xdd7: 0x000a, + 0xdd8: 0x000a, 0xdd9: 0x000a, + // Block 0x38, offset 0xe00 + 0xe00: 0x000a, + // Block 0x39, offset 0xe40 + 0xe40: 0x0009, + 0xe5b: 0x007a, 0xe5c: 0x006a, + // Block 0x3a, offset 0xe80 + 0xe92: 0x000c, 0xe93: 0x000c, 0xe94: 0x000c, + 0xeb2: 0x000c, 0xeb3: 0x000c, 0xeb4: 0x000c, + // Block 0x3b, offset 0xec0 + 0xed2: 0x000c, 0xed3: 0x000c, + 0xef2: 0x000c, 0xef3: 0x000c, + // Block 0x3c, offset 0xf00 + 0xf34: 0x000c, 0xf35: 0x000c, + 0xf37: 0x000c, 0xf38: 0x000c, 0xf39: 0x000c, 0xf3a: 0x000c, 0xf3b: 0x000c, + 0xf3c: 0x000c, 0xf3d: 0x000c, + // Block 0x3d, offset 0xf40 + 0xf46: 0x000c, 0xf49: 0x000c, 0xf4a: 0x000c, 0xf4b: 0x000c, + 0xf4c: 0x000c, 0xf4d: 0x000c, 0xf4e: 0x000c, 0xf4f: 0x000c, 0xf50: 0x000c, 0xf51: 0x000c, + 0xf52: 0x000c, 0xf53: 0x000c, + 0xf5b: 0x0004, 0xf5d: 0x000c, + 0xf70: 0x000a, 0xf71: 0x000a, 0xf72: 0x000a, 0xf73: 0x000a, 0xf74: 0x000a, 0xf75: 0x000a, + 0xf76: 0x000a, 0xf77: 0x000a, 0xf78: 0x000a, 0xf79: 0x000a, + // Block 0x3e, offset 0xf80 + 0xf80: 0x000a, 0xf81: 0x000a, 0xf82: 0x000a, 0xf83: 0x000a, 0xf84: 0x000a, 0xf85: 0x000a, + 0xf86: 0x000a, 0xf87: 0x000a, 0xf88: 0x000a, 0xf89: 0x000a, 0xf8a: 0x000a, 0xf8b: 0x000c, + 0xf8c: 0x000c, 0xf8d: 0x000c, 0xf8e: 0x000b, + // Block 0x3f, offset 0xfc0 + 0xfc5: 0x000c, + 0xfc6: 0x000c, + 0xfe9: 0x000c, + // Block 0x40, offset 0x1000 + 0x1020: 0x000c, 0x1021: 0x000c, 0x1022: 0x000c, + 0x1027: 0x000c, 0x1028: 0x000c, + 0x1032: 0x000c, + 0x1039: 0x000c, 0x103a: 0x000c, 0x103b: 0x000c, + // Block 0x41, offset 0x1040 + 0x1040: 0x000a, 0x1044: 0x000a, 0x1045: 0x000a, + // Block 0x42, offset 0x1080 + 0x109e: 0x000a, 0x109f: 0x000a, 0x10a0: 0x000a, 0x10a1: 0x000a, 0x10a2: 0x000a, 0x10a3: 0x000a, + 0x10a4: 0x000a, 0x10a5: 0x000a, 0x10a6: 0x000a, 0x10a7: 0x000a, 0x10a8: 0x000a, 0x10a9: 0x000a, + 0x10aa: 0x000a, 0x10ab: 0x000a, 0x10ac: 0x000a, 0x10ad: 0x000a, 0x10ae: 0x000a, 0x10af: 0x000a, + 0x10b0: 0x000a, 0x10b1: 0x000a, 0x10b2: 0x000a, 0x10b3: 0x000a, 0x10b4: 0x000a, 0x10b5: 0x000a, + 0x10b6: 0x000a, 0x10b7: 0x000a, 0x10b8: 0x000a, 0x10b9: 0x000a, 0x10ba: 0x000a, 0x10bb: 0x000a, + 0x10bc: 0x000a, 0x10bd: 0x000a, 0x10be: 0x000a, 0x10bf: 0x000a, + // Block 0x43, offset 0x10c0 + 0x10d7: 0x000c, + 0x10d8: 0x000c, 0x10db: 0x000c, + // Block 0x44, offset 0x1100 + 0x1116: 0x000c, + 0x1118: 0x000c, 0x1119: 0x000c, 0x111a: 0x000c, 0x111b: 0x000c, 0x111c: 0x000c, 0x111d: 0x000c, + 0x111e: 0x000c, 0x1120: 0x000c, 0x1122: 0x000c, + 0x1125: 0x000c, 0x1126: 0x000c, 0x1127: 0x000c, 0x1128: 0x000c, 0x1129: 0x000c, + 0x112a: 0x000c, 0x112b: 0x000c, 0x112c: 0x000c, + 0x1133: 0x000c, 0x1134: 0x000c, 0x1135: 0x000c, + 0x1136: 0x000c, 0x1137: 0x000c, 0x1138: 0x000c, 0x1139: 0x000c, 0x113a: 0x000c, 0x113b: 0x000c, + 0x113c: 0x000c, 0x113f: 0x000c, + // Block 0x45, offset 0x1140 + 0x1170: 0x000c, 0x1171: 0x000c, 0x1172: 0x000c, 0x1173: 0x000c, 0x1174: 0x000c, 0x1175: 0x000c, + 0x1176: 0x000c, 0x1177: 0x000c, 0x1178: 0x000c, 0x1179: 0x000c, 0x117a: 0x000c, 0x117b: 0x000c, + 0x117c: 0x000c, 0x117d: 0x000c, 0x117e: 0x000c, + // Block 0x46, offset 0x1180 + 0x1180: 0x000c, 0x1181: 0x000c, 0x1182: 0x000c, 0x1183: 0x000c, + 0x11b4: 0x000c, + 0x11b6: 0x000c, 0x11b7: 0x000c, 0x11b8: 0x000c, 0x11b9: 0x000c, 0x11ba: 0x000c, + 0x11bc: 0x000c, + // Block 0x47, offset 0x11c0 + 0x11c2: 0x000c, + 0x11eb: 0x000c, 0x11ec: 0x000c, 0x11ed: 0x000c, 0x11ee: 0x000c, 0x11ef: 0x000c, + 0x11f0: 0x000c, 0x11f1: 0x000c, 0x11f2: 0x000c, 0x11f3: 0x000c, + // Block 0x48, offset 0x1200 + 0x1200: 0x000c, 0x1201: 0x000c, + 0x1222: 0x000c, 0x1223: 0x000c, + 0x1224: 0x000c, 0x1225: 0x000c, 0x1228: 0x000c, 0x1229: 0x000c, + 0x122b: 0x000c, 0x122c: 0x000c, 0x122d: 0x000c, + // Block 0x49, offset 0x1240 + 0x1266: 0x000c, 0x1268: 0x000c, 0x1269: 0x000c, + 0x126d: 0x000c, 0x126f: 0x000c, + 0x1270: 0x000c, 0x1271: 0x000c, + // Block 0x4a, offset 0x1280 + 0x12ac: 0x000c, 0x12ad: 0x000c, 0x12ae: 0x000c, 0x12af: 0x000c, + 0x12b0: 0x000c, 0x12b1: 0x000c, 0x12b2: 0x000c, 0x12b3: 0x000c, + 0x12b6: 0x000c, 0x12b7: 0x000c, + // Block 0x4b, offset 0x12c0 + 0x12d0: 0x000c, 0x12d1: 0x000c, + 0x12d2: 0x000c, 0x12d4: 0x000c, 0x12d5: 0x000c, 0x12d6: 0x000c, 0x12d7: 0x000c, + 0x12d8: 0x000c, 0x12d9: 0x000c, 0x12da: 0x000c, 0x12db: 0x000c, 0x12dc: 0x000c, 0x12dd: 0x000c, + 0x12de: 0x000c, 0x12df: 0x000c, 0x12e0: 0x000c, 0x12e2: 0x000c, 0x12e3: 0x000c, + 0x12e4: 0x000c, 0x12e5: 0x000c, 0x12e6: 0x000c, 0x12e7: 0x000c, 0x12e8: 0x000c, + 0x12ed: 0x000c, + 0x12f4: 0x000c, + 0x12f8: 0x000c, 0x12f9: 0x000c, + // Block 0x4c, offset 0x1300 + 0x1300: 0x000c, 0x1301: 0x000c, 0x1302: 0x000c, 0x1303: 0x000c, 0x1304: 0x000c, 0x1305: 0x000c, + 0x1306: 0x000c, 0x1307: 0x000c, 0x1308: 0x000c, 0x1309: 0x000c, 0x130a: 0x000c, 0x130b: 0x000c, + 0x130c: 0x000c, 0x130d: 0x000c, 0x130e: 0x000c, 0x130f: 0x000c, 0x1310: 0x000c, 0x1311: 0x000c, + 0x1312: 0x000c, 0x1313: 0x000c, 0x1314: 0x000c, 0x1315: 0x000c, 0x1316: 0x000c, 0x1317: 0x000c, + 0x1318: 0x000c, 0x1319: 0x000c, 0x131a: 0x000c, 0x131b: 0x000c, 0x131c: 0x000c, 0x131d: 0x000c, + 0x131e: 0x000c, 0x131f: 0x000c, 0x1320: 0x000c, 0x1321: 0x000c, 0x1322: 0x000c, 0x1323: 0x000c, + 0x1324: 0x000c, 0x1325: 0x000c, 0x1326: 0x000c, 0x1327: 0x000c, 0x1328: 0x000c, 0x1329: 0x000c, + 0x132a: 0x000c, 0x132b: 0x000c, 0x132c: 0x000c, 0x132d: 0x000c, 0x132e: 0x000c, 0x132f: 0x000c, + 0x1330: 0x000c, 0x1331: 0x000c, 0x1332: 0x000c, 0x1333: 0x000c, 0x1334: 0x000c, 0x1335: 0x000c, + 0x133b: 0x000c, + 0x133c: 0x000c, 0x133d: 0x000c, 0x133e: 0x000c, 0x133f: 0x000c, + // Block 0x4d, offset 0x1340 + 0x137d: 0x000a, 0x137f: 0x000a, + // Block 0x4e, offset 0x1380 + 0x1380: 0x000a, 0x1381: 0x000a, + 0x138d: 0x000a, 0x138e: 0x000a, 0x138f: 0x000a, + 0x139d: 0x000a, + 0x139e: 0x000a, 0x139f: 0x000a, + 0x13ad: 0x000a, 0x13ae: 0x000a, 0x13af: 0x000a, + 0x13bd: 0x000a, 0x13be: 0x000a, + // Block 0x4f, offset 0x13c0 + 0x13c0: 0x0009, 0x13c1: 0x0009, 0x13c2: 0x0009, 0x13c3: 0x0009, 0x13c4: 0x0009, 0x13c5: 0x0009, + 0x13c6: 0x0009, 0x13c7: 0x0009, 0x13c8: 0x0009, 0x13c9: 0x0009, 0x13ca: 0x0009, 0x13cb: 0x000b, + 0x13cc: 0x000b, 0x13cd: 0x000b, 0x13cf: 0x0001, 0x13d0: 0x000a, 0x13d1: 0x000a, + 0x13d2: 0x000a, 0x13d3: 0x000a, 0x13d4: 0x000a, 0x13d5: 0x000a, 0x13d6: 0x000a, 0x13d7: 0x000a, + 0x13d8: 0x000a, 0x13d9: 0x000a, 0x13da: 0x000a, 0x13db: 0x000a, 0x13dc: 0x000a, 0x13dd: 0x000a, + 0x13de: 0x000a, 0x13df: 0x000a, 0x13e0: 0x000a, 0x13e1: 0x000a, 0x13e2: 0x000a, 0x13e3: 0x000a, + 0x13e4: 0x000a, 0x13e5: 0x000a, 0x13e6: 0x000a, 0x13e7: 0x000a, 0x13e8: 0x0009, 0x13e9: 0x0007, + 0x13ea: 0x000e, 0x13eb: 0x000e, 0x13ec: 0x000e, 0x13ed: 0x000e, 0x13ee: 0x000e, 0x13ef: 0x0006, + 0x13f0: 0x0004, 0x13f1: 0x0004, 0x13f2: 0x0004, 0x13f3: 0x0004, 0x13f4: 0x0004, 0x13f5: 0x000a, + 0x13f6: 0x000a, 0x13f7: 0x000a, 0x13f8: 0x000a, 0x13f9: 0x000a, 0x13fa: 0x000a, 0x13fb: 0x000a, + 0x13fc: 0x000a, 0x13fd: 0x000a, 0x13fe: 0x000a, 0x13ff: 0x000a, + // Block 0x50, offset 0x1400 + 0x1400: 0x000a, 0x1401: 0x000a, 0x1402: 0x000a, 0x1403: 0x000a, 0x1404: 0x0006, 0x1405: 0x009a, + 0x1406: 0x008a, 0x1407: 0x000a, 0x1408: 0x000a, 0x1409: 0x000a, 0x140a: 0x000a, 0x140b: 0x000a, + 0x140c: 0x000a, 0x140d: 0x000a, 0x140e: 0x000a, 0x140f: 0x000a, 0x1410: 0x000a, 0x1411: 0x000a, + 0x1412: 0x000a, 0x1413: 0x000a, 0x1414: 0x000a, 0x1415: 0x000a, 0x1416: 0x000a, 0x1417: 0x000a, + 0x1418: 0x000a, 0x1419: 0x000a, 0x141a: 0x000a, 0x141b: 0x000a, 0x141c: 0x000a, 0x141d: 0x000a, + 0x141e: 0x000a, 0x141f: 0x0009, 0x1420: 0x000b, 0x1421: 0x000b, 0x1422: 0x000b, 0x1423: 0x000b, + 0x1424: 0x000b, 0x1425: 0x000b, 0x1426: 0x000e, 0x1427: 0x000e, 0x1428: 0x000e, 0x1429: 0x000e, + 0x142a: 0x000b, 0x142b: 0x000b, 0x142c: 0x000b, 0x142d: 0x000b, 0x142e: 0x000b, 0x142f: 0x000b, + 0x1430: 0x0002, 0x1434: 0x0002, 0x1435: 0x0002, + 0x1436: 0x0002, 0x1437: 0x0002, 0x1438: 0x0002, 0x1439: 0x0002, 0x143a: 0x0003, 0x143b: 0x0003, + 0x143c: 0x000a, 0x143d: 0x009a, 0x143e: 0x008a, + // Block 0x51, offset 0x1440 + 0x1440: 0x0002, 0x1441: 0x0002, 0x1442: 0x0002, 0x1443: 0x0002, 0x1444: 0x0002, 0x1445: 0x0002, + 0x1446: 0x0002, 0x1447: 0x0002, 0x1448: 0x0002, 0x1449: 0x0002, 0x144a: 0x0003, 0x144b: 0x0003, + 0x144c: 0x000a, 0x144d: 0x009a, 0x144e: 0x008a, + 0x1460: 0x0004, 0x1461: 0x0004, 0x1462: 0x0004, 0x1463: 0x0004, + 0x1464: 0x0004, 0x1465: 0x0004, 0x1466: 0x0004, 0x1467: 0x0004, 0x1468: 0x0004, 0x1469: 0x0004, + 0x146a: 0x0004, 0x146b: 0x0004, 0x146c: 0x0004, 0x146d: 0x0004, 0x146e: 0x0004, 0x146f: 0x0004, + 0x1470: 0x0004, 0x1471: 0x0004, 0x1472: 0x0004, 0x1473: 0x0004, 0x1474: 0x0004, 0x1475: 0x0004, + 0x1476: 0x0004, 0x1477: 0x0004, 0x1478: 0x0004, 0x1479: 0x0004, 0x147a: 0x0004, 0x147b: 0x0004, + 0x147c: 0x0004, 0x147d: 0x0004, 0x147e: 0x0004, 0x147f: 0x0004, + // Block 0x52, offset 0x1480 + 0x1480: 0x0004, 0x1481: 0x0004, 0x1482: 0x0004, 0x1483: 0x0004, 0x1484: 0x0004, 0x1485: 0x0004, + 0x1486: 0x0004, 0x1487: 0x0004, 0x1488: 0x0004, 0x1489: 0x0004, 0x148a: 0x0004, 0x148b: 0x0004, + 0x148c: 0x0004, 0x148d: 0x0004, 0x148e: 0x0004, 0x148f: 0x0004, 0x1490: 0x000c, 0x1491: 0x000c, + 0x1492: 0x000c, 0x1493: 0x000c, 0x1494: 0x000c, 0x1495: 0x000c, 0x1496: 0x000c, 0x1497: 0x000c, + 0x1498: 0x000c, 0x1499: 0x000c, 0x149a: 0x000c, 0x149b: 0x000c, 0x149c: 0x000c, 0x149d: 0x000c, + 0x149e: 0x000c, 0x149f: 0x000c, 0x14a0: 0x000c, 0x14a1: 0x000c, 0x14a2: 0x000c, 0x14a3: 0x000c, + 0x14a4: 0x000c, 0x14a5: 0x000c, 0x14a6: 0x000c, 0x14a7: 0x000c, 0x14a8: 0x000c, 0x14a9: 0x000c, + 0x14aa: 0x000c, 0x14ab: 0x000c, 0x14ac: 0x000c, 0x14ad: 0x000c, 0x14ae: 0x000c, 0x14af: 0x000c, + 0x14b0: 0x000c, + // Block 0x53, offset 0x14c0 + 0x14c0: 0x000a, 0x14c1: 0x000a, 0x14c3: 0x000a, 0x14c4: 0x000a, 0x14c5: 0x000a, + 0x14c6: 0x000a, 0x14c8: 0x000a, 0x14c9: 0x000a, + 0x14d4: 0x000a, 0x14d6: 0x000a, 0x14d7: 0x000a, + 0x14d8: 0x000a, + 0x14de: 0x000a, 0x14df: 0x000a, 0x14e0: 0x000a, 0x14e1: 0x000a, 0x14e2: 0x000a, 0x14e3: 0x000a, + 0x14e5: 0x000a, 0x14e7: 0x000a, 0x14e9: 0x000a, + 0x14ee: 0x0004, + 0x14fa: 0x000a, 0x14fb: 0x000a, + // Block 0x54, offset 0x1500 + 0x1500: 0x000a, 0x1501: 0x000a, 0x1502: 0x000a, 0x1503: 0x000a, 0x1504: 0x000a, + 0x150a: 0x000a, 0x150b: 0x000a, + 0x150c: 0x000a, 0x150d: 0x000a, 0x1510: 0x000a, 0x1511: 0x000a, + 0x1512: 0x000a, 0x1513: 0x000a, 0x1514: 0x000a, 0x1515: 0x000a, 0x1516: 0x000a, 0x1517: 0x000a, + 0x1518: 0x000a, 0x1519: 0x000a, 0x151a: 0x000a, 0x151b: 0x000a, 0x151c: 0x000a, 0x151d: 0x000a, + 0x151e: 0x000a, 0x151f: 0x000a, + // Block 0x55, offset 0x1540 + 0x1549: 0x000a, 0x154a: 0x000a, 0x154b: 0x000a, + 0x1550: 0x000a, 0x1551: 0x000a, + 0x1552: 0x000a, 0x1553: 0x000a, 0x1554: 0x000a, 0x1555: 0x000a, 0x1556: 0x000a, 0x1557: 0x000a, + 0x1558: 0x000a, 0x1559: 0x000a, 0x155a: 0x000a, 0x155b: 0x000a, 0x155c: 0x000a, 0x155d: 0x000a, + 0x155e: 0x000a, 0x155f: 0x000a, 0x1560: 0x000a, 0x1561: 0x000a, 0x1562: 0x000a, 0x1563: 0x000a, + 0x1564: 0x000a, 0x1565: 0x000a, 0x1566: 0x000a, 0x1567: 0x000a, 0x1568: 0x000a, 0x1569: 0x000a, + 0x156a: 0x000a, 0x156b: 0x000a, 0x156c: 0x000a, 0x156d: 0x000a, 0x156e: 0x000a, 0x156f: 0x000a, + 0x1570: 0x000a, 0x1571: 0x000a, 0x1572: 0x000a, 0x1573: 0x000a, 0x1574: 0x000a, 0x1575: 0x000a, + 0x1576: 0x000a, 0x1577: 0x000a, 0x1578: 0x000a, 0x1579: 0x000a, 0x157a: 0x000a, 0x157b: 0x000a, + 0x157c: 0x000a, 0x157d: 0x000a, 0x157e: 0x000a, 0x157f: 0x000a, + // Block 0x56, offset 0x1580 + 0x1580: 0x000a, 0x1581: 0x000a, 0x1582: 0x000a, 0x1583: 0x000a, 0x1584: 0x000a, 0x1585: 0x000a, + 0x1586: 0x000a, 0x1587: 0x000a, 0x1588: 0x000a, 0x1589: 0x000a, 0x158a: 0x000a, 0x158b: 0x000a, + 0x158c: 0x000a, 0x158d: 0x000a, 0x158e: 0x000a, 0x158f: 0x000a, 0x1590: 0x000a, 0x1591: 0x000a, + 0x1592: 0x000a, 0x1593: 0x000a, 0x1594: 0x000a, 0x1595: 0x000a, 0x1596: 0x000a, 0x1597: 0x000a, + 0x1598: 0x000a, 0x1599: 0x000a, 0x159a: 0x000a, 0x159b: 0x000a, 0x159c: 0x000a, 0x159d: 0x000a, + 0x159e: 0x000a, 0x159f: 0x000a, 0x15a0: 0x000a, 0x15a1: 0x000a, 0x15a2: 0x000a, 0x15a3: 0x000a, + 0x15a4: 0x000a, 0x15a5: 0x000a, 0x15a6: 0x000a, 0x15a7: 0x000a, 0x15a8: 0x000a, 0x15a9: 0x000a, + 0x15aa: 0x000a, 0x15ab: 0x000a, 0x15ac: 0x000a, 0x15ad: 0x000a, 0x15ae: 0x000a, 0x15af: 0x000a, + 0x15b0: 0x000a, 0x15b1: 0x000a, 0x15b2: 0x000a, 0x15b3: 0x000a, 0x15b4: 0x000a, 0x15b5: 0x000a, + 0x15b6: 0x000a, 0x15b7: 0x000a, 0x15b8: 0x000a, 0x15b9: 0x000a, 0x15ba: 0x000a, 0x15bb: 0x000a, + 0x15bc: 0x000a, 0x15bd: 0x000a, 0x15be: 0x000a, 0x15bf: 0x000a, + // Block 0x57, offset 0x15c0 + 0x15c0: 0x000a, 0x15c1: 0x000a, 0x15c2: 0x000a, 0x15c3: 0x000a, 0x15c4: 0x000a, 0x15c5: 0x000a, + 0x15c6: 0x000a, 0x15c7: 0x000a, 0x15c8: 0x000a, 0x15c9: 0x000a, 0x15ca: 0x000a, 0x15cb: 0x000a, + 0x15cc: 0x000a, 0x15cd: 0x000a, 0x15ce: 0x000a, 0x15cf: 0x000a, 0x15d0: 0x000a, 0x15d1: 0x000a, + 0x15d2: 0x0003, 0x15d3: 0x0004, 0x15d4: 0x000a, 0x15d5: 0x000a, 0x15d6: 0x000a, 0x15d7: 0x000a, + 0x15d8: 0x000a, 0x15d9: 0x000a, 0x15da: 0x000a, 0x15db: 0x000a, 0x15dc: 0x000a, 0x15dd: 0x000a, + 0x15de: 0x000a, 0x15df: 0x000a, 0x15e0: 0x000a, 0x15e1: 0x000a, 0x15e2: 0x000a, 0x15e3: 0x000a, + 0x15e4: 0x000a, 0x15e5: 0x000a, 0x15e6: 0x000a, 0x15e7: 0x000a, 0x15e8: 0x000a, 0x15e9: 0x000a, + 0x15ea: 0x000a, 0x15eb: 0x000a, 0x15ec: 0x000a, 0x15ed: 0x000a, 0x15ee: 0x000a, 0x15ef: 0x000a, + 0x15f0: 0x000a, 0x15f1: 0x000a, 0x15f2: 0x000a, 0x15f3: 0x000a, 0x15f4: 0x000a, 0x15f5: 0x000a, + 0x15f6: 0x000a, 0x15f7: 0x000a, 0x15f8: 0x000a, 0x15f9: 0x000a, 0x15fa: 0x000a, 0x15fb: 0x000a, + 0x15fc: 0x000a, 0x15fd: 0x000a, 0x15fe: 0x000a, 0x15ff: 0x000a, + // Block 0x58, offset 0x1600 + 0x1600: 0x000a, 0x1601: 0x000a, 0x1602: 0x000a, 0x1603: 0x000a, 0x1604: 0x000a, 0x1605: 0x000a, + 0x1606: 0x000a, 0x1607: 0x000a, 0x1608: 0x003a, 0x1609: 0x002a, 0x160a: 0x003a, 0x160b: 0x002a, + 0x160c: 0x000a, 0x160d: 0x000a, 0x160e: 0x000a, 0x160f: 0x000a, 0x1610: 0x000a, 0x1611: 0x000a, + 0x1612: 0x000a, 0x1613: 0x000a, 0x1614: 0x000a, 0x1615: 0x000a, 0x1616: 0x000a, 0x1617: 0x000a, + 0x1618: 0x000a, 0x1619: 0x000a, 0x161a: 0x000a, 0x161b: 0x000a, 0x161c: 0x000a, 0x161d: 0x000a, + 0x161e: 0x000a, 0x161f: 0x000a, 0x1620: 0x000a, 0x1621: 0x000a, 0x1622: 0x000a, 0x1623: 0x000a, + 0x1624: 0x000a, 0x1625: 0x000a, 0x1626: 0x000a, 0x1627: 0x000a, 0x1628: 0x000a, 0x1629: 0x009a, + 0x162a: 0x008a, 0x162b: 0x000a, 0x162c: 0x000a, 0x162d: 0x000a, 0x162e: 0x000a, 0x162f: 0x000a, + 0x1630: 0x000a, 0x1631: 0x000a, 0x1632: 0x000a, 0x1633: 0x000a, 0x1634: 0x000a, 0x1635: 0x000a, + // Block 0x59, offset 0x1640 + 0x167b: 0x000a, + 0x167c: 0x000a, 0x167d: 0x000a, 0x167e: 0x000a, 0x167f: 0x000a, + // Block 0x5a, offset 0x1680 + 0x1680: 0x000a, 0x1681: 0x000a, 0x1682: 0x000a, 0x1683: 0x000a, 0x1684: 0x000a, 0x1685: 0x000a, + 0x1686: 0x000a, 0x1687: 0x000a, 0x1688: 0x000a, 0x1689: 0x000a, 0x168a: 0x000a, 0x168b: 0x000a, + 0x168c: 0x000a, 0x168d: 0x000a, 0x168e: 0x000a, 0x168f: 0x000a, 0x1690: 0x000a, 0x1691: 0x000a, + 0x1692: 0x000a, 0x1693: 0x000a, 0x1694: 0x000a, 0x1696: 0x000a, 0x1697: 0x000a, + 0x1698: 0x000a, 0x1699: 0x000a, 0x169a: 0x000a, 0x169b: 0x000a, 0x169c: 0x000a, 0x169d: 0x000a, + 0x169e: 0x000a, 0x169f: 0x000a, 0x16a0: 0x000a, 0x16a1: 0x000a, 0x16a2: 0x000a, 0x16a3: 0x000a, + 0x16a4: 0x000a, 0x16a5: 0x000a, 0x16a6: 0x000a, 0x16a7: 0x000a, 0x16a8: 0x000a, 0x16a9: 0x000a, + 0x16aa: 0x000a, 0x16ab: 0x000a, 0x16ac: 0x000a, 0x16ad: 0x000a, 0x16ae: 0x000a, 0x16af: 0x000a, + 0x16b0: 0x000a, 0x16b1: 0x000a, 0x16b2: 0x000a, 0x16b3: 0x000a, 0x16b4: 0x000a, 0x16b5: 0x000a, + 0x16b6: 0x000a, 0x16b7: 0x000a, 0x16b8: 0x000a, 0x16b9: 0x000a, 0x16ba: 0x000a, 0x16bb: 0x000a, + 0x16bc: 0x000a, 0x16bd: 0x000a, 0x16be: 0x000a, 0x16bf: 0x000a, + // Block 0x5b, offset 0x16c0 + 0x16c0: 0x000a, 0x16c1: 0x000a, 0x16c2: 0x000a, 0x16c3: 0x000a, 0x16c4: 0x000a, 0x16c5: 0x000a, + 0x16c6: 0x000a, 0x16c7: 0x000a, 0x16c8: 0x000a, 0x16c9: 0x000a, 0x16ca: 0x000a, 0x16cb: 0x000a, + 0x16cc: 0x000a, 0x16cd: 0x000a, 0x16ce: 0x000a, 0x16cf: 0x000a, 0x16d0: 0x000a, 0x16d1: 0x000a, + 0x16d2: 0x000a, 0x16d3: 0x000a, 0x16d4: 0x000a, 0x16d5: 0x000a, 0x16d6: 0x000a, 0x16d7: 0x000a, + 0x16d8: 0x000a, 0x16d9: 0x000a, 0x16da: 0x000a, 0x16db: 0x000a, 0x16dc: 0x000a, 0x16dd: 0x000a, + 0x16de: 0x000a, 0x16df: 0x000a, 0x16e0: 0x000a, 0x16e1: 0x000a, 0x16e2: 0x000a, 0x16e3: 0x000a, + 0x16e4: 0x000a, 0x16e5: 0x000a, 0x16e6: 0x000a, 0x16e7: 0x000a, 0x16e8: 0x000a, 0x16e9: 0x000a, + 0x16ea: 0x000a, 0x16eb: 0x000a, 0x16ec: 0x000a, 0x16ed: 0x000a, 0x16ee: 0x000a, 0x16ef: 0x000a, + 0x16f0: 0x000a, 0x16f1: 0x000a, 0x16f2: 0x000a, 0x16f3: 0x000a, 0x16f4: 0x000a, 0x16f5: 0x000a, + 0x16f6: 0x000a, 0x16f7: 0x000a, 0x16f8: 0x000a, 0x16f9: 0x000a, 0x16fa: 0x000a, 0x16fb: 0x000a, + 0x16fc: 0x000a, 0x16fd: 0x000a, 0x16fe: 0x000a, + // Block 0x5c, offset 0x1700 + 0x1700: 0x000a, 0x1701: 0x000a, 0x1702: 0x000a, 0x1703: 0x000a, 0x1704: 0x000a, 0x1705: 0x000a, + 0x1706: 0x000a, 0x1707: 0x000a, 0x1708: 0x000a, 0x1709: 0x000a, 0x170a: 0x000a, 0x170b: 0x000a, + 0x170c: 0x000a, 0x170d: 0x000a, 0x170e: 0x000a, 0x170f: 0x000a, 0x1710: 0x000a, 0x1711: 0x000a, + 0x1712: 0x000a, 0x1713: 0x000a, 0x1714: 0x000a, 0x1715: 0x000a, 0x1716: 0x000a, 0x1717: 0x000a, + 0x1718: 0x000a, 0x1719: 0x000a, 0x171a: 0x000a, 0x171b: 0x000a, 0x171c: 0x000a, 0x171d: 0x000a, + 0x171e: 0x000a, 0x171f: 0x000a, 0x1720: 0x000a, 0x1721: 0x000a, 0x1722: 0x000a, 0x1723: 0x000a, + 0x1724: 0x000a, 0x1725: 0x000a, 0x1726: 0x000a, + // Block 0x5d, offset 0x1740 + 0x1740: 0x000a, 0x1741: 0x000a, 0x1742: 0x000a, 0x1743: 0x000a, 0x1744: 0x000a, 0x1745: 0x000a, + 0x1746: 0x000a, 0x1747: 0x000a, 0x1748: 0x000a, 0x1749: 0x000a, 0x174a: 0x000a, + 0x1760: 0x000a, 0x1761: 0x000a, 0x1762: 0x000a, 0x1763: 0x000a, + 0x1764: 0x000a, 0x1765: 0x000a, 0x1766: 0x000a, 0x1767: 0x000a, 0x1768: 0x000a, 0x1769: 0x000a, + 0x176a: 0x000a, 0x176b: 0x000a, 0x176c: 0x000a, 0x176d: 0x000a, 0x176e: 0x000a, 0x176f: 0x000a, + 0x1770: 0x000a, 0x1771: 0x000a, 0x1772: 0x000a, 0x1773: 0x000a, 0x1774: 0x000a, 0x1775: 0x000a, + 0x1776: 0x000a, 0x1777: 0x000a, 0x1778: 0x000a, 0x1779: 0x000a, 0x177a: 0x000a, 0x177b: 0x000a, + 0x177c: 0x000a, 0x177d: 0x000a, 0x177e: 0x000a, 0x177f: 0x000a, + // Block 0x5e, offset 0x1780 + 0x1780: 0x000a, 0x1781: 0x000a, 0x1782: 0x000a, 0x1783: 0x000a, 0x1784: 0x000a, 0x1785: 0x000a, + 0x1786: 0x000a, 0x1787: 0x000a, 0x1788: 0x0002, 0x1789: 0x0002, 0x178a: 0x0002, 0x178b: 0x0002, + 0x178c: 0x0002, 0x178d: 0x0002, 0x178e: 0x0002, 0x178f: 0x0002, 0x1790: 0x0002, 0x1791: 0x0002, + 0x1792: 0x0002, 0x1793: 0x0002, 0x1794: 0x0002, 0x1795: 0x0002, 0x1796: 0x0002, 0x1797: 0x0002, + 0x1798: 0x0002, 0x1799: 0x0002, 0x179a: 0x0002, 0x179b: 0x0002, + // Block 0x5f, offset 0x17c0 + 0x17ea: 0x000a, 0x17eb: 0x000a, 0x17ec: 0x000a, 0x17ed: 0x000a, 0x17ee: 0x000a, 0x17ef: 0x000a, + 0x17f0: 0x000a, 0x17f1: 0x000a, 0x17f2: 0x000a, 0x17f3: 0x000a, 0x17f4: 0x000a, 0x17f5: 0x000a, + 0x17f6: 0x000a, 0x17f7: 0x000a, 0x17f8: 0x000a, 0x17f9: 0x000a, 0x17fa: 0x000a, 0x17fb: 0x000a, + 0x17fc: 0x000a, 0x17fd: 0x000a, 0x17fe: 0x000a, 0x17ff: 0x000a, + // Block 0x60, offset 0x1800 + 0x1800: 0x000a, 0x1801: 0x000a, 0x1802: 0x000a, 0x1803: 0x000a, 0x1804: 0x000a, 0x1805: 0x000a, + 0x1806: 0x000a, 0x1807: 0x000a, 0x1808: 0x000a, 0x1809: 0x000a, 0x180a: 0x000a, 0x180b: 0x000a, + 0x180c: 0x000a, 0x180d: 0x000a, 0x180e: 0x000a, 0x180f: 0x000a, 0x1810: 0x000a, 0x1811: 0x000a, + 0x1812: 0x000a, 0x1813: 0x000a, 0x1814: 0x000a, 0x1815: 0x000a, 0x1816: 0x000a, 0x1817: 0x000a, + 0x1818: 0x000a, 0x1819: 0x000a, 0x181a: 0x000a, 0x181b: 0x000a, 0x181c: 0x000a, 0x181d: 0x000a, + 0x181e: 0x000a, 0x181f: 0x000a, 0x1820: 0x000a, 0x1821: 0x000a, 0x1822: 0x000a, 0x1823: 0x000a, + 0x1824: 0x000a, 0x1825: 0x000a, 0x1826: 0x000a, 0x1827: 0x000a, 0x1828: 0x000a, 0x1829: 0x000a, + 0x182a: 0x000a, 0x182b: 0x000a, 0x182d: 0x000a, 0x182e: 0x000a, 0x182f: 0x000a, + 0x1830: 0x000a, 0x1831: 0x000a, 0x1832: 0x000a, 0x1833: 0x000a, 0x1834: 0x000a, 0x1835: 0x000a, + 0x1836: 0x000a, 0x1837: 0x000a, 0x1838: 0x000a, 0x1839: 0x000a, 0x183a: 0x000a, 0x183b: 0x000a, + 0x183c: 0x000a, 0x183d: 0x000a, 0x183e: 0x000a, 0x183f: 0x000a, + // Block 0x61, offset 0x1840 + 0x1840: 0x000a, 0x1841: 0x000a, 0x1842: 0x000a, 0x1843: 0x000a, 0x1844: 0x000a, 0x1845: 0x000a, + 0x1846: 0x000a, 0x1847: 0x000a, 0x1848: 0x000a, 0x1849: 0x000a, 0x184a: 0x000a, 0x184b: 0x000a, + 0x184c: 0x000a, 0x184d: 0x000a, 0x184e: 0x000a, 0x184f: 0x000a, 0x1850: 0x000a, 0x1851: 0x000a, + 0x1852: 0x000a, 0x1853: 0x000a, 0x1854: 0x000a, 0x1855: 0x000a, 0x1856: 0x000a, 0x1857: 0x000a, + 0x1858: 0x000a, 0x1859: 0x000a, 0x185a: 0x000a, 0x185b: 0x000a, 0x185c: 0x000a, 0x185d: 0x000a, + 0x185e: 0x000a, 0x185f: 0x000a, 0x1860: 0x000a, 0x1861: 0x000a, 0x1862: 0x000a, 0x1863: 0x000a, + 0x1864: 0x000a, 0x1865: 0x000a, 0x1866: 0x000a, 0x1867: 0x000a, 0x1868: 0x003a, 0x1869: 0x002a, + 0x186a: 0x003a, 0x186b: 0x002a, 0x186c: 0x003a, 0x186d: 0x002a, 0x186e: 0x003a, 0x186f: 0x002a, + 0x1870: 0x003a, 0x1871: 0x002a, 0x1872: 0x003a, 0x1873: 0x002a, 0x1874: 0x003a, 0x1875: 0x002a, + 0x1876: 0x000a, 0x1877: 0x000a, 0x1878: 0x000a, 0x1879: 0x000a, 0x187a: 0x000a, 0x187b: 0x000a, + 0x187c: 0x000a, 0x187d: 0x000a, 0x187e: 0x000a, 0x187f: 0x000a, + // Block 0x62, offset 0x1880 + 0x1880: 0x000a, 0x1881: 0x000a, 0x1882: 0x000a, 0x1883: 0x000a, 0x1884: 0x000a, 0x1885: 0x009a, + 0x1886: 0x008a, 0x1887: 0x000a, 0x1888: 0x000a, 0x1889: 0x000a, 0x188a: 0x000a, 0x188b: 0x000a, + 0x188c: 0x000a, 0x188d: 0x000a, 0x188e: 0x000a, 0x188f: 0x000a, 0x1890: 0x000a, 0x1891: 0x000a, + 0x1892: 0x000a, 0x1893: 0x000a, 0x1894: 0x000a, 0x1895: 0x000a, 0x1896: 0x000a, 0x1897: 0x000a, + 0x1898: 0x000a, 0x1899: 0x000a, 0x189a: 0x000a, 0x189b: 0x000a, 0x189c: 0x000a, 0x189d: 0x000a, + 0x189e: 0x000a, 0x189f: 0x000a, 0x18a0: 0x000a, 0x18a1: 0x000a, 0x18a2: 0x000a, 0x18a3: 0x000a, + 0x18a4: 0x000a, 0x18a5: 0x000a, 0x18a6: 0x003a, 0x18a7: 0x002a, 0x18a8: 0x003a, 0x18a9: 0x002a, + 0x18aa: 0x003a, 0x18ab: 0x002a, 0x18ac: 0x003a, 0x18ad: 0x002a, 0x18ae: 0x003a, 0x18af: 0x002a, + 0x18b0: 0x000a, 0x18b1: 0x000a, 0x18b2: 0x000a, 0x18b3: 0x000a, 0x18b4: 0x000a, 0x18b5: 0x000a, + 0x18b6: 0x000a, 0x18b7: 0x000a, 0x18b8: 0x000a, 0x18b9: 0x000a, 0x18ba: 0x000a, 0x18bb: 0x000a, + 0x18bc: 0x000a, 0x18bd: 0x000a, 0x18be: 0x000a, 0x18bf: 0x000a, + // Block 0x63, offset 0x18c0 + 0x18c0: 0x000a, 0x18c1: 0x000a, 0x18c2: 0x000a, 0x18c3: 0x007a, 0x18c4: 0x006a, 0x18c5: 0x009a, + 0x18c6: 0x008a, 0x18c7: 0x00ba, 0x18c8: 0x00aa, 0x18c9: 0x009a, 0x18ca: 0x008a, 0x18cb: 0x007a, + 0x18cc: 0x006a, 0x18cd: 0x00da, 0x18ce: 0x002a, 0x18cf: 0x003a, 0x18d0: 0x00ca, 0x18d1: 0x009a, + 0x18d2: 0x008a, 0x18d3: 0x007a, 0x18d4: 0x006a, 0x18d5: 0x009a, 0x18d6: 0x008a, 0x18d7: 0x00ba, + 0x18d8: 0x00aa, 0x18d9: 0x000a, 0x18da: 0x000a, 0x18db: 0x000a, 0x18dc: 0x000a, 0x18dd: 0x000a, + 0x18de: 0x000a, 0x18df: 0x000a, 0x18e0: 0x000a, 0x18e1: 0x000a, 0x18e2: 0x000a, 0x18e3: 0x000a, + 0x18e4: 0x000a, 0x18e5: 0x000a, 0x18e6: 0x000a, 0x18e7: 0x000a, 0x18e8: 0x000a, 0x18e9: 0x000a, + 0x18ea: 0x000a, 0x18eb: 0x000a, 0x18ec: 0x000a, 0x18ed: 0x000a, 0x18ee: 0x000a, 0x18ef: 0x000a, + 0x18f0: 0x000a, 0x18f1: 0x000a, 0x18f2: 0x000a, 0x18f3: 0x000a, 0x18f4: 0x000a, 0x18f5: 0x000a, + 0x18f6: 0x000a, 0x18f7: 0x000a, 0x18f8: 0x000a, 0x18f9: 0x000a, 0x18fa: 0x000a, 0x18fb: 0x000a, + 0x18fc: 0x000a, 0x18fd: 0x000a, 0x18fe: 0x000a, 0x18ff: 0x000a, + // Block 0x64, offset 0x1900 + 0x1900: 0x000a, 0x1901: 0x000a, 0x1902: 0x000a, 0x1903: 0x000a, 0x1904: 0x000a, 0x1905: 0x000a, + 0x1906: 0x000a, 0x1907: 0x000a, 0x1908: 0x000a, 0x1909: 0x000a, 0x190a: 0x000a, 0x190b: 0x000a, + 0x190c: 0x000a, 0x190d: 0x000a, 0x190e: 0x000a, 0x190f: 0x000a, 0x1910: 0x000a, 0x1911: 0x000a, + 0x1912: 0x000a, 0x1913: 0x000a, 0x1914: 0x000a, 0x1915: 0x000a, 0x1916: 0x000a, 0x1917: 0x000a, + 0x1918: 0x003a, 0x1919: 0x002a, 0x191a: 0x003a, 0x191b: 0x002a, 0x191c: 0x000a, 0x191d: 0x000a, + 0x191e: 0x000a, 0x191f: 0x000a, 0x1920: 0x000a, 0x1921: 0x000a, 0x1922: 0x000a, 0x1923: 0x000a, + 0x1924: 0x000a, 0x1925: 0x000a, 0x1926: 0x000a, 0x1927: 0x000a, 0x1928: 0x000a, 0x1929: 0x000a, + 0x192a: 0x000a, 0x192b: 0x000a, 0x192c: 0x000a, 0x192d: 0x000a, 0x192e: 0x000a, 0x192f: 0x000a, + 0x1930: 0x000a, 0x1931: 0x000a, 0x1932: 0x000a, 0x1933: 0x000a, 0x1934: 0x000a, 0x1935: 0x000a, + 0x1936: 0x000a, 0x1937: 0x000a, 0x1938: 0x000a, 0x1939: 0x000a, 0x193a: 0x000a, 0x193b: 0x000a, + 0x193c: 0x003a, 0x193d: 0x002a, 0x193e: 0x000a, 0x193f: 0x000a, + // Block 0x65, offset 0x1940 + 0x1940: 0x000a, 0x1941: 0x000a, 0x1942: 0x000a, 0x1943: 0x000a, 0x1944: 0x000a, 0x1945: 0x000a, + 0x1946: 0x000a, 0x1947: 0x000a, 0x1948: 0x000a, 0x1949: 0x000a, 0x194a: 0x000a, 0x194b: 0x000a, + 0x194c: 0x000a, 0x194d: 0x000a, 0x194e: 0x000a, 0x194f: 0x000a, 0x1950: 0x000a, 0x1951: 0x000a, + 0x1952: 0x000a, 0x1953: 0x000a, 0x1954: 0x000a, 0x1955: 0x000a, 0x1956: 0x000a, 0x1957: 0x000a, + 0x1958: 0x000a, 0x1959: 0x000a, 0x195a: 0x000a, 0x195b: 0x000a, 0x195c: 0x000a, 0x195d: 0x000a, + 0x195e: 0x000a, 0x195f: 0x000a, 0x1960: 0x000a, 0x1961: 0x000a, 0x1962: 0x000a, 0x1963: 0x000a, + 0x1964: 0x000a, 0x1965: 0x000a, 0x1966: 0x000a, 0x1967: 0x000a, 0x1968: 0x000a, 0x1969: 0x000a, + 0x196a: 0x000a, 0x196b: 0x000a, 0x196c: 0x000a, 0x196d: 0x000a, 0x196e: 0x000a, 0x196f: 0x000a, + 0x1970: 0x000a, 0x1971: 0x000a, 0x1972: 0x000a, 0x1973: 0x000a, + 0x1976: 0x000a, 0x1977: 0x000a, 0x1978: 0x000a, 0x1979: 0x000a, 0x197a: 0x000a, 0x197b: 0x000a, + 0x197c: 0x000a, 0x197d: 0x000a, 0x197e: 0x000a, 0x197f: 0x000a, + // Block 0x66, offset 0x1980 + 0x1980: 0x000a, 0x1981: 0x000a, 0x1982: 0x000a, 0x1983: 0x000a, 0x1984: 0x000a, 0x1985: 0x000a, + 0x1986: 0x000a, 0x1987: 0x000a, 0x1988: 0x000a, 0x1989: 0x000a, 0x198a: 0x000a, 0x198b: 0x000a, + 0x198c: 0x000a, 0x198d: 0x000a, 0x198e: 0x000a, 0x198f: 0x000a, 0x1990: 0x000a, 0x1991: 0x000a, + 0x1992: 0x000a, 0x1993: 0x000a, 0x1994: 0x000a, 0x1995: 0x000a, + 0x1998: 0x000a, 0x1999: 0x000a, 0x199a: 0x000a, 0x199b: 0x000a, 0x199c: 0x000a, 0x199d: 0x000a, + 0x199e: 0x000a, 0x199f: 0x000a, 0x19a0: 0x000a, 0x19a1: 0x000a, 0x19a2: 0x000a, 0x19a3: 0x000a, + 0x19a4: 0x000a, 0x19a5: 0x000a, 0x19a6: 0x000a, 0x19a7: 0x000a, 0x19a8: 0x000a, 0x19a9: 0x000a, + 0x19aa: 0x000a, 0x19ab: 0x000a, 0x19ac: 0x000a, 0x19ad: 0x000a, 0x19ae: 0x000a, 0x19af: 0x000a, + 0x19b0: 0x000a, 0x19b1: 0x000a, 0x19b2: 0x000a, 0x19b3: 0x000a, 0x19b4: 0x000a, 0x19b5: 0x000a, + 0x19b6: 0x000a, 0x19b7: 0x000a, 0x19b8: 0x000a, 0x19b9: 0x000a, + 0x19bd: 0x000a, 0x19be: 0x000a, 0x19bf: 0x000a, + // Block 0x67, offset 0x19c0 + 0x19c0: 0x000a, 0x19c1: 0x000a, 0x19c2: 0x000a, 0x19c3: 0x000a, 0x19c4: 0x000a, 0x19c5: 0x000a, + 0x19c6: 0x000a, 0x19c7: 0x000a, 0x19c8: 0x000a, 0x19ca: 0x000a, 0x19cb: 0x000a, + 0x19cc: 0x000a, 0x19cd: 0x000a, 0x19ce: 0x000a, 0x19cf: 0x000a, 0x19d0: 0x000a, 0x19d1: 0x000a, + 0x19ec: 0x000a, 0x19ed: 0x000a, 0x19ee: 0x000a, 0x19ef: 0x000a, + // Block 0x68, offset 0x1a00 + 0x1a25: 0x000a, 0x1a26: 0x000a, 0x1a27: 0x000a, 0x1a28: 0x000a, 0x1a29: 0x000a, + 0x1a2a: 0x000a, 0x1a2f: 0x000c, + 0x1a30: 0x000c, 0x1a31: 0x000c, + 0x1a39: 0x000a, 0x1a3a: 0x000a, 0x1a3b: 0x000a, + 0x1a3c: 0x000a, 0x1a3d: 0x000a, 0x1a3e: 0x000a, 0x1a3f: 0x000a, + // Block 0x69, offset 0x1a40 + 0x1a7f: 0x000c, + // Block 0x6a, offset 0x1a80 + 0x1aa0: 0x000c, 0x1aa1: 0x000c, 0x1aa2: 0x000c, 0x1aa3: 0x000c, + 0x1aa4: 0x000c, 0x1aa5: 0x000c, 0x1aa6: 0x000c, 0x1aa7: 0x000c, 0x1aa8: 0x000c, 0x1aa9: 0x000c, + 0x1aaa: 0x000c, 0x1aab: 0x000c, 0x1aac: 0x000c, 0x1aad: 0x000c, 0x1aae: 0x000c, 0x1aaf: 0x000c, + 0x1ab0: 0x000c, 0x1ab1: 0x000c, 0x1ab2: 0x000c, 0x1ab3: 0x000c, 0x1ab4: 0x000c, 0x1ab5: 0x000c, + 0x1ab6: 0x000c, 0x1ab7: 0x000c, 0x1ab8: 0x000c, 0x1ab9: 0x000c, 0x1aba: 0x000c, 0x1abb: 0x000c, + 0x1abc: 0x000c, 0x1abd: 0x000c, 0x1abe: 0x000c, 0x1abf: 0x000c, + // Block 0x6b, offset 0x1ac0 + 0x1ac0: 0x000a, 0x1ac1: 0x000a, 0x1ac2: 0x000a, 0x1ac3: 0x000a, 0x1ac4: 0x000a, 0x1ac5: 0x000a, + 0x1ac6: 0x000a, 0x1ac7: 0x000a, 0x1ac8: 0x000a, 0x1ac9: 0x000a, 0x1aca: 0x000a, 0x1acb: 0x000a, + 0x1acc: 0x000a, 0x1acd: 0x000a, 0x1ace: 0x000a, 0x1acf: 0x000a, 0x1ad0: 0x000a, 0x1ad1: 0x000a, + 0x1ad2: 0x000a, 0x1ad3: 0x000a, 0x1ad4: 0x000a, 0x1ad5: 0x000a, 0x1ad6: 0x000a, 0x1ad7: 0x000a, + 0x1ad8: 0x000a, 0x1ad9: 0x000a, 0x1ada: 0x000a, 0x1adb: 0x000a, 0x1adc: 0x000a, 0x1add: 0x000a, + 0x1ade: 0x000a, 0x1adf: 0x000a, 0x1ae0: 0x000a, 0x1ae1: 0x000a, 0x1ae2: 0x003a, 0x1ae3: 0x002a, + 0x1ae4: 0x003a, 0x1ae5: 0x002a, 0x1ae6: 0x003a, 0x1ae7: 0x002a, 0x1ae8: 0x003a, 0x1ae9: 0x002a, + 0x1aea: 0x000a, 0x1aeb: 0x000a, 0x1aec: 0x000a, 0x1aed: 0x000a, 0x1aee: 0x000a, 0x1aef: 0x000a, + 0x1af0: 0x000a, 0x1af1: 0x000a, 0x1af2: 0x000a, 0x1af3: 0x000a, 0x1af4: 0x000a, 0x1af5: 0x000a, + 0x1af6: 0x000a, 0x1af7: 0x000a, 0x1af8: 0x000a, 0x1af9: 0x000a, 0x1afa: 0x000a, 0x1afb: 0x000a, + 0x1afc: 0x000a, 0x1afd: 0x000a, 0x1afe: 0x000a, 0x1aff: 0x000a, + // Block 0x6c, offset 0x1b00 + 0x1b00: 0x000a, 0x1b01: 0x000a, 0x1b02: 0x000a, 0x1b03: 0x000a, 0x1b04: 0x000a, + // Block 0x6d, offset 0x1b40 + 0x1b40: 0x000a, 0x1b41: 0x000a, 0x1b42: 0x000a, 0x1b43: 0x000a, 0x1b44: 0x000a, 0x1b45: 0x000a, + 0x1b46: 0x000a, 0x1b47: 0x000a, 0x1b48: 0x000a, 0x1b49: 0x000a, 0x1b4a: 0x000a, 0x1b4b: 0x000a, + 0x1b4c: 0x000a, 0x1b4d: 0x000a, 0x1b4e: 0x000a, 0x1b4f: 0x000a, 0x1b50: 0x000a, 0x1b51: 0x000a, + 0x1b52: 0x000a, 0x1b53: 0x000a, 0x1b54: 0x000a, 0x1b55: 0x000a, 0x1b56: 0x000a, 0x1b57: 0x000a, + 0x1b58: 0x000a, 0x1b59: 0x000a, 0x1b5b: 0x000a, 0x1b5c: 0x000a, 0x1b5d: 0x000a, + 0x1b5e: 0x000a, 0x1b5f: 0x000a, 0x1b60: 0x000a, 0x1b61: 0x000a, 0x1b62: 0x000a, 0x1b63: 0x000a, + 0x1b64: 0x000a, 0x1b65: 0x000a, 0x1b66: 0x000a, 0x1b67: 0x000a, 0x1b68: 0x000a, 0x1b69: 0x000a, + 0x1b6a: 0x000a, 0x1b6b: 0x000a, 0x1b6c: 0x000a, 0x1b6d: 0x000a, 0x1b6e: 0x000a, 0x1b6f: 0x000a, + 0x1b70: 0x000a, 0x1b71: 0x000a, 0x1b72: 0x000a, 0x1b73: 0x000a, 0x1b74: 0x000a, 0x1b75: 0x000a, + 0x1b76: 0x000a, 0x1b77: 0x000a, 0x1b78: 0x000a, 0x1b79: 0x000a, 0x1b7a: 0x000a, 0x1b7b: 0x000a, + 0x1b7c: 0x000a, 0x1b7d: 0x000a, 0x1b7e: 0x000a, 0x1b7f: 0x000a, + // Block 0x6e, offset 0x1b80 + 0x1b80: 0x000a, 0x1b81: 0x000a, 0x1b82: 0x000a, 0x1b83: 0x000a, 0x1b84: 0x000a, 0x1b85: 0x000a, + 0x1b86: 0x000a, 0x1b87: 0x000a, 0x1b88: 0x000a, 0x1b89: 0x000a, 0x1b8a: 0x000a, 0x1b8b: 0x000a, + 0x1b8c: 0x000a, 0x1b8d: 0x000a, 0x1b8e: 0x000a, 0x1b8f: 0x000a, 0x1b90: 0x000a, 0x1b91: 0x000a, + 0x1b92: 0x000a, 0x1b93: 0x000a, 0x1b94: 0x000a, 0x1b95: 0x000a, 0x1b96: 0x000a, 0x1b97: 0x000a, + 0x1b98: 0x000a, 0x1b99: 0x000a, 0x1b9a: 0x000a, 0x1b9b: 0x000a, 0x1b9c: 0x000a, 0x1b9d: 0x000a, + 0x1b9e: 0x000a, 0x1b9f: 0x000a, 0x1ba0: 0x000a, 0x1ba1: 0x000a, 0x1ba2: 0x000a, 0x1ba3: 0x000a, + 0x1ba4: 0x000a, 0x1ba5: 0x000a, 0x1ba6: 0x000a, 0x1ba7: 0x000a, 0x1ba8: 0x000a, 0x1ba9: 0x000a, + 0x1baa: 0x000a, 0x1bab: 0x000a, 0x1bac: 0x000a, 0x1bad: 0x000a, 0x1bae: 0x000a, 0x1baf: 0x000a, + 0x1bb0: 0x000a, 0x1bb1: 0x000a, 0x1bb2: 0x000a, 0x1bb3: 0x000a, + // Block 0x6f, offset 0x1bc0 + 0x1bc0: 0x000a, 0x1bc1: 0x000a, 0x1bc2: 0x000a, 0x1bc3: 0x000a, 0x1bc4: 0x000a, 0x1bc5: 0x000a, + 0x1bc6: 0x000a, 0x1bc7: 0x000a, 0x1bc8: 0x000a, 0x1bc9: 0x000a, 0x1bca: 0x000a, 0x1bcb: 0x000a, + 0x1bcc: 0x000a, 0x1bcd: 0x000a, 0x1bce: 0x000a, 0x1bcf: 0x000a, 0x1bd0: 0x000a, 0x1bd1: 0x000a, + 0x1bd2: 0x000a, 0x1bd3: 0x000a, 0x1bd4: 0x000a, 0x1bd5: 0x000a, + 0x1bf0: 0x000a, 0x1bf1: 0x000a, 0x1bf2: 0x000a, 0x1bf3: 0x000a, 0x1bf4: 0x000a, 0x1bf5: 0x000a, + 0x1bf6: 0x000a, 0x1bf7: 0x000a, 0x1bf8: 0x000a, 0x1bf9: 0x000a, 0x1bfa: 0x000a, 0x1bfb: 0x000a, + // Block 0x70, offset 0x1c00 + 0x1c00: 0x0009, 0x1c01: 0x000a, 0x1c02: 0x000a, 0x1c03: 0x000a, 0x1c04: 0x000a, + 0x1c08: 0x003a, 0x1c09: 0x002a, 0x1c0a: 0x003a, 0x1c0b: 0x002a, + 0x1c0c: 0x003a, 0x1c0d: 0x002a, 0x1c0e: 0x003a, 0x1c0f: 0x002a, 0x1c10: 0x003a, 0x1c11: 0x002a, + 0x1c12: 0x000a, 0x1c13: 0x000a, 0x1c14: 0x003a, 0x1c15: 0x002a, 0x1c16: 0x003a, 0x1c17: 0x002a, + 0x1c18: 0x003a, 0x1c19: 0x002a, 0x1c1a: 0x003a, 0x1c1b: 0x002a, 0x1c1c: 0x000a, 0x1c1d: 0x000a, + 0x1c1e: 0x000a, 0x1c1f: 0x000a, 0x1c20: 0x000a, + 0x1c2a: 0x000c, 0x1c2b: 0x000c, 0x1c2c: 0x000c, 0x1c2d: 0x000c, + 0x1c30: 0x000a, + 0x1c36: 0x000a, 0x1c37: 0x000a, + 0x1c3d: 0x000a, 0x1c3e: 0x000a, 0x1c3f: 0x000a, + // Block 0x71, offset 0x1c40 + 0x1c59: 0x000c, 0x1c5a: 0x000c, 0x1c5b: 0x000a, 0x1c5c: 0x000a, + 0x1c60: 0x000a, + // Block 0x72, offset 0x1c80 + 0x1cbb: 0x000a, + // Block 0x73, offset 0x1cc0 + 0x1cc0: 0x000a, 0x1cc1: 0x000a, 0x1cc2: 0x000a, 0x1cc3: 0x000a, 0x1cc4: 0x000a, 0x1cc5: 0x000a, + 0x1cc6: 0x000a, 0x1cc7: 0x000a, 0x1cc8: 0x000a, 0x1cc9: 0x000a, 0x1cca: 0x000a, 0x1ccb: 0x000a, + 0x1ccc: 0x000a, 0x1ccd: 0x000a, 0x1cce: 0x000a, 0x1ccf: 0x000a, 0x1cd0: 0x000a, 0x1cd1: 0x000a, + 0x1cd2: 0x000a, 0x1cd3: 0x000a, 0x1cd4: 0x000a, 0x1cd5: 0x000a, 0x1cd6: 0x000a, 0x1cd7: 0x000a, + 0x1cd8: 0x000a, 0x1cd9: 0x000a, 0x1cda: 0x000a, 0x1cdb: 0x000a, 0x1cdc: 0x000a, 0x1cdd: 0x000a, + 0x1cde: 0x000a, 0x1cdf: 0x000a, 0x1ce0: 0x000a, 0x1ce1: 0x000a, 0x1ce2: 0x000a, 0x1ce3: 0x000a, + // Block 0x74, offset 0x1d00 + 0x1d1d: 0x000a, + 0x1d1e: 0x000a, + // Block 0x75, offset 0x1d40 + 0x1d50: 0x000a, 0x1d51: 0x000a, + 0x1d52: 0x000a, 0x1d53: 0x000a, 0x1d54: 0x000a, 0x1d55: 0x000a, 0x1d56: 0x000a, 0x1d57: 0x000a, + 0x1d58: 0x000a, 0x1d59: 0x000a, 0x1d5a: 0x000a, 0x1d5b: 0x000a, 0x1d5c: 0x000a, 0x1d5d: 0x000a, + 0x1d5e: 0x000a, 0x1d5f: 0x000a, + 0x1d7c: 0x000a, 0x1d7d: 0x000a, 0x1d7e: 0x000a, + // Block 0x76, offset 0x1d80 + 0x1db1: 0x000a, 0x1db2: 0x000a, 0x1db3: 0x000a, 0x1db4: 0x000a, 0x1db5: 0x000a, + 0x1db6: 0x000a, 0x1db7: 0x000a, 0x1db8: 0x000a, 0x1db9: 0x000a, 0x1dba: 0x000a, 0x1dbb: 0x000a, + 0x1dbc: 0x000a, 0x1dbd: 0x000a, 0x1dbe: 0x000a, 0x1dbf: 0x000a, + // Block 0x77, offset 0x1dc0 + 0x1dcc: 0x000a, 0x1dcd: 0x000a, 0x1dce: 0x000a, 0x1dcf: 0x000a, + // Block 0x78, offset 0x1e00 + 0x1e37: 0x000a, 0x1e38: 0x000a, 0x1e39: 0x000a, 0x1e3a: 0x000a, + // Block 0x79, offset 0x1e40 + 0x1e5e: 0x000a, 0x1e5f: 0x000a, + 0x1e7f: 0x000a, + // Block 0x7a, offset 0x1e80 + 0x1e90: 0x000a, 0x1e91: 0x000a, + 0x1e92: 0x000a, 0x1e93: 0x000a, 0x1e94: 0x000a, 0x1e95: 0x000a, 0x1e96: 0x000a, 0x1e97: 0x000a, + 0x1e98: 0x000a, 0x1e99: 0x000a, 0x1e9a: 0x000a, 0x1e9b: 0x000a, 0x1e9c: 0x000a, 0x1e9d: 0x000a, + 0x1e9e: 0x000a, 0x1e9f: 0x000a, 0x1ea0: 0x000a, 0x1ea1: 0x000a, 0x1ea2: 0x000a, 0x1ea3: 0x000a, + 0x1ea4: 0x000a, 0x1ea5: 0x000a, 0x1ea6: 0x000a, 0x1ea7: 0x000a, 0x1ea8: 0x000a, 0x1ea9: 0x000a, + 0x1eaa: 0x000a, 0x1eab: 0x000a, 0x1eac: 0x000a, 0x1ead: 0x000a, 0x1eae: 0x000a, 0x1eaf: 0x000a, + 0x1eb0: 0x000a, 0x1eb1: 0x000a, 0x1eb2: 0x000a, 0x1eb3: 0x000a, 0x1eb4: 0x000a, 0x1eb5: 0x000a, + 0x1eb6: 0x000a, 0x1eb7: 0x000a, 0x1eb8: 0x000a, 0x1eb9: 0x000a, 0x1eba: 0x000a, 0x1ebb: 0x000a, + 0x1ebc: 0x000a, 0x1ebd: 0x000a, 0x1ebe: 0x000a, 0x1ebf: 0x000a, + // Block 0x7b, offset 0x1ec0 + 0x1ec0: 0x000a, 0x1ec1: 0x000a, 0x1ec2: 0x000a, 0x1ec3: 0x000a, 0x1ec4: 0x000a, 0x1ec5: 0x000a, + 0x1ec6: 0x000a, + // Block 0x7c, offset 0x1f00 + 0x1f0d: 0x000a, 0x1f0e: 0x000a, 0x1f0f: 0x000a, + // Block 0x7d, offset 0x1f40 + 0x1f6f: 0x000c, + 0x1f70: 0x000c, 0x1f71: 0x000c, 0x1f72: 0x000c, 0x1f73: 0x000a, 0x1f74: 0x000c, 0x1f75: 0x000c, + 0x1f76: 0x000c, 0x1f77: 0x000c, 0x1f78: 0x000c, 0x1f79: 0x000c, 0x1f7a: 0x000c, 0x1f7b: 0x000c, + 0x1f7c: 0x000c, 0x1f7d: 0x000c, 0x1f7e: 0x000a, 0x1f7f: 0x000a, + // Block 0x7e, offset 0x1f80 + 0x1f9e: 0x000c, 0x1f9f: 0x000c, + // Block 0x7f, offset 0x1fc0 + 0x1ff0: 0x000c, 0x1ff1: 0x000c, + // Block 0x80, offset 0x2000 + 0x2000: 0x000a, 0x2001: 0x000a, 0x2002: 0x000a, 0x2003: 0x000a, 0x2004: 0x000a, 0x2005: 0x000a, + 0x2006: 0x000a, 0x2007: 0x000a, 0x2008: 0x000a, 0x2009: 0x000a, 0x200a: 0x000a, 0x200b: 0x000a, + 0x200c: 0x000a, 0x200d: 0x000a, 0x200e: 0x000a, 0x200f: 0x000a, 0x2010: 0x000a, 0x2011: 0x000a, + 0x2012: 0x000a, 0x2013: 0x000a, 0x2014: 0x000a, 0x2015: 0x000a, 0x2016: 0x000a, 0x2017: 0x000a, + 0x2018: 0x000a, 0x2019: 0x000a, 0x201a: 0x000a, 0x201b: 0x000a, 0x201c: 0x000a, 0x201d: 0x000a, + 0x201e: 0x000a, 0x201f: 0x000a, 0x2020: 0x000a, 0x2021: 0x000a, + // Block 0x81, offset 0x2040 + 0x2048: 0x000a, + // Block 0x82, offset 0x2080 + 0x2082: 0x000c, + 0x2086: 0x000c, 0x208b: 0x000c, + 0x20a5: 0x000c, 0x20a6: 0x000c, 0x20a8: 0x000a, 0x20a9: 0x000a, + 0x20aa: 0x000a, 0x20ab: 0x000a, + 0x20b8: 0x0004, 0x20b9: 0x0004, + // Block 0x83, offset 0x20c0 + 0x20f4: 0x000a, 0x20f5: 0x000a, + 0x20f6: 0x000a, 0x20f7: 0x000a, + // Block 0x84, offset 0x2100 + 0x2104: 0x000c, 0x2105: 0x000c, + 0x2120: 0x000c, 0x2121: 0x000c, 0x2122: 0x000c, 0x2123: 0x000c, + 0x2124: 0x000c, 0x2125: 0x000c, 0x2126: 0x000c, 0x2127: 0x000c, 0x2128: 0x000c, 0x2129: 0x000c, + 0x212a: 0x000c, 0x212b: 0x000c, 0x212c: 0x000c, 0x212d: 0x000c, 0x212e: 0x000c, 0x212f: 0x000c, + 0x2130: 0x000c, 0x2131: 0x000c, + // Block 0x85, offset 0x2140 + 0x2166: 0x000c, 0x2167: 0x000c, 0x2168: 0x000c, 0x2169: 0x000c, + 0x216a: 0x000c, 0x216b: 0x000c, 0x216c: 0x000c, 0x216d: 0x000c, + // Block 0x86, offset 0x2180 + 0x2187: 0x000c, 0x2188: 0x000c, 0x2189: 0x000c, 0x218a: 0x000c, 0x218b: 0x000c, + 0x218c: 0x000c, 0x218d: 0x000c, 0x218e: 0x000c, 0x218f: 0x000c, 0x2190: 0x000c, 0x2191: 0x000c, + // Block 0x87, offset 0x21c0 + 0x21c0: 0x000c, 0x21c1: 0x000c, 0x21c2: 0x000c, + 0x21f3: 0x000c, + 0x21f6: 0x000c, 0x21f7: 0x000c, 0x21f8: 0x000c, 0x21f9: 0x000c, + 0x21fc: 0x000c, + // Block 0x88, offset 0x2200 + 0x2225: 0x000c, + // Block 0x89, offset 0x2240 + 0x2269: 0x000c, + 0x226a: 0x000c, 0x226b: 0x000c, 0x226c: 0x000c, 0x226d: 0x000c, 0x226e: 0x000c, + 0x2271: 0x000c, 0x2272: 0x000c, 0x2275: 0x000c, + 0x2276: 0x000c, + // Block 0x8a, offset 0x2280 + 0x2283: 0x000c, + 0x228c: 0x000c, + 0x22bc: 0x000c, + // Block 0x8b, offset 0x22c0 + 0x22f0: 0x000c, 0x22f2: 0x000c, 0x22f3: 0x000c, 0x22f4: 0x000c, + 0x22f7: 0x000c, 0x22f8: 0x000c, + 0x22fe: 0x000c, 0x22ff: 0x000c, + // Block 0x8c, offset 0x2300 + 0x2301: 0x000c, + 0x232c: 0x000c, 0x232d: 0x000c, + 0x2336: 0x000c, + // Block 0x8d, offset 0x2340 + 0x2365: 0x000c, 0x2368: 0x000c, + 0x236d: 0x000c, + // Block 0x8e, offset 0x2380 + 0x239d: 0x0001, + 0x239e: 0x000c, 0x239f: 0x0001, 0x23a0: 0x0001, 0x23a1: 0x0001, 0x23a2: 0x0001, 0x23a3: 0x0001, + 0x23a4: 0x0001, 0x23a5: 0x0001, 0x23a6: 0x0001, 0x23a7: 0x0001, 0x23a8: 0x0001, 0x23a9: 0x0003, + 0x23aa: 0x0001, 0x23ab: 0x0001, 0x23ac: 0x0001, 0x23ad: 0x0001, 0x23ae: 0x0001, 0x23af: 0x0001, + 0x23b0: 0x0001, 0x23b1: 0x0001, 0x23b2: 0x0001, 0x23b3: 0x0001, 0x23b4: 0x0001, 0x23b5: 0x0001, + 0x23b6: 0x0001, 0x23b7: 0x0001, 0x23b8: 0x0001, 0x23b9: 0x0001, 0x23ba: 0x0001, 0x23bb: 0x0001, + 0x23bc: 0x0001, 0x23bd: 0x0001, 0x23be: 0x0001, 0x23bf: 0x0001, + // Block 0x8f, offset 0x23c0 + 0x23c0: 0x0001, 0x23c1: 0x0001, 0x23c2: 0x0001, 0x23c3: 0x0001, 0x23c4: 0x0001, 0x23c5: 0x0001, + 0x23c6: 0x0001, 0x23c7: 0x0001, 0x23c8: 0x0001, 0x23c9: 0x0001, 0x23ca: 0x0001, 0x23cb: 0x0001, + 0x23cc: 0x0001, 0x23cd: 0x0001, 0x23ce: 0x0001, 0x23cf: 0x0001, 0x23d0: 0x000d, 0x23d1: 0x000d, + 0x23d2: 0x000d, 0x23d3: 0x000d, 0x23d4: 0x000d, 0x23d5: 0x000d, 0x23d6: 0x000d, 0x23d7: 0x000d, + 0x23d8: 0x000d, 0x23d9: 0x000d, 0x23da: 0x000d, 0x23db: 0x000d, 0x23dc: 0x000d, 0x23dd: 0x000d, + 0x23de: 0x000d, 0x23df: 0x000d, 0x23e0: 0x000d, 0x23e1: 0x000d, 0x23e2: 0x000d, 0x23e3: 0x000d, + 0x23e4: 0x000d, 0x23e5: 0x000d, 0x23e6: 0x000d, 0x23e7: 0x000d, 0x23e8: 0x000d, 0x23e9: 0x000d, + 0x23ea: 0x000d, 0x23eb: 0x000d, 0x23ec: 0x000d, 0x23ed: 0x000d, 0x23ee: 0x000d, 0x23ef: 0x000d, + 0x23f0: 0x000d, 0x23f1: 0x000d, 0x23f2: 0x000d, 0x23f3: 0x000d, 0x23f4: 0x000d, 0x23f5: 0x000d, + 0x23f6: 0x000d, 0x23f7: 0x000d, 0x23f8: 0x000d, 0x23f9: 0x000d, 0x23fa: 0x000d, 0x23fb: 0x000d, + 0x23fc: 0x000d, 0x23fd: 0x000d, 0x23fe: 0x000d, 0x23ff: 0x000d, + // Block 0x90, offset 0x2400 + 0x2400: 0x000d, 0x2401: 0x000d, 0x2402: 0x000d, 0x2403: 0x000d, 0x2404: 0x000d, 0x2405: 0x000d, + 0x2406: 0x000d, 0x2407: 0x000d, 0x2408: 0x000d, 0x2409: 0x000d, 0x240a: 0x000d, 0x240b: 0x000d, + 0x240c: 0x000d, 0x240d: 0x000d, 0x240e: 0x000d, 0x240f: 0x000d, 0x2410: 0x000d, 0x2411: 0x000d, + 0x2412: 0x000d, 0x2413: 0x000d, 0x2414: 0x000d, 0x2415: 0x000d, 0x2416: 0x000d, 0x2417: 0x000d, + 0x2418: 0x000d, 0x2419: 0x000d, 0x241a: 0x000d, 0x241b: 0x000d, 0x241c: 0x000d, 0x241d: 0x000d, + 0x241e: 0x000d, 0x241f: 0x000d, 0x2420: 0x000d, 0x2421: 0x000d, 0x2422: 0x000d, 0x2423: 0x000d, + 0x2424: 0x000d, 0x2425: 0x000d, 0x2426: 0x000d, 0x2427: 0x000d, 0x2428: 0x000d, 0x2429: 0x000d, + 0x242a: 0x000d, 0x242b: 0x000d, 0x242c: 0x000d, 0x242d: 0x000d, 0x242e: 0x000d, 0x242f: 0x000d, + 0x2430: 0x000d, 0x2431: 0x000d, 0x2432: 0x000d, 0x2433: 0x000d, 0x2434: 0x000d, 0x2435: 0x000d, + 0x2436: 0x000d, 0x2437: 0x000d, 0x2438: 0x000d, 0x2439: 0x000d, 0x243a: 0x000d, 0x243b: 0x000d, + 0x243c: 0x000d, 0x243d: 0x000d, 0x243e: 0x000a, 0x243f: 0x000a, + // Block 0x91, offset 0x2440 + 0x2440: 0x000d, 0x2441: 0x000d, 0x2442: 0x000d, 0x2443: 0x000d, 0x2444: 0x000d, 0x2445: 0x000d, + 0x2446: 0x000d, 0x2447: 0x000d, 0x2448: 0x000d, 0x2449: 0x000d, 0x244a: 0x000d, 0x244b: 0x000d, + 0x244c: 0x000d, 0x244d: 0x000d, 0x244e: 0x000d, 0x244f: 0x000d, 0x2450: 0x000b, 0x2451: 0x000b, + 0x2452: 0x000b, 0x2453: 0x000b, 0x2454: 0x000b, 0x2455: 0x000b, 0x2456: 0x000b, 0x2457: 0x000b, + 0x2458: 0x000b, 0x2459: 0x000b, 0x245a: 0x000b, 0x245b: 0x000b, 0x245c: 0x000b, 0x245d: 0x000b, + 0x245e: 0x000b, 0x245f: 0x000b, 0x2460: 0x000b, 0x2461: 0x000b, 0x2462: 0x000b, 0x2463: 0x000b, + 0x2464: 0x000b, 0x2465: 0x000b, 0x2466: 0x000b, 0x2467: 0x000b, 0x2468: 0x000b, 0x2469: 0x000b, + 0x246a: 0x000b, 0x246b: 0x000b, 0x246c: 0x000b, 0x246d: 0x000b, 0x246e: 0x000b, 0x246f: 0x000b, + 0x2470: 0x000d, 0x2471: 0x000d, 0x2472: 0x000d, 0x2473: 0x000d, 0x2474: 0x000d, 0x2475: 0x000d, + 0x2476: 0x000d, 0x2477: 0x000d, 0x2478: 0x000d, 0x2479: 0x000d, 0x247a: 0x000d, 0x247b: 0x000d, + 0x247c: 0x000d, 0x247d: 0x000a, 0x247e: 0x000d, 0x247f: 0x000d, + // Block 0x92, offset 0x2480 + 0x2480: 0x000c, 0x2481: 0x000c, 0x2482: 0x000c, 0x2483: 0x000c, 0x2484: 0x000c, 0x2485: 0x000c, + 0x2486: 0x000c, 0x2487: 0x000c, 0x2488: 0x000c, 0x2489: 0x000c, 0x248a: 0x000c, 0x248b: 0x000c, + 0x248c: 0x000c, 0x248d: 0x000c, 0x248e: 0x000c, 0x248f: 0x000c, 0x2490: 0x000a, 0x2491: 0x000a, + 0x2492: 0x000a, 0x2493: 0x000a, 0x2494: 0x000a, 0x2495: 0x000a, 0x2496: 0x000a, 0x2497: 0x000a, + 0x2498: 0x000a, 0x2499: 0x000a, + 0x24a0: 0x000c, 0x24a1: 0x000c, 0x24a2: 0x000c, 0x24a3: 0x000c, + 0x24a4: 0x000c, 0x24a5: 0x000c, 0x24a6: 0x000c, 0x24a7: 0x000c, 0x24a8: 0x000c, 0x24a9: 0x000c, + 0x24aa: 0x000c, 0x24ab: 0x000c, 0x24ac: 0x000c, 0x24ad: 0x000c, 0x24ae: 0x000c, 0x24af: 0x000c, + 0x24b0: 0x000a, 0x24b1: 0x000a, 0x24b2: 0x000a, 0x24b3: 0x000a, 0x24b4: 0x000a, 0x24b5: 0x000a, + 0x24b6: 0x000a, 0x24b7: 0x000a, 0x24b8: 0x000a, 0x24b9: 0x000a, 0x24ba: 0x000a, 0x24bb: 0x000a, + 0x24bc: 0x000a, 0x24bd: 0x000a, 0x24be: 0x000a, 0x24bf: 0x000a, + // Block 0x93, offset 0x24c0 + 0x24c0: 0x000a, 0x24c1: 0x000a, 0x24c2: 0x000a, 0x24c3: 0x000a, 0x24c4: 0x000a, 0x24c5: 0x000a, + 0x24c6: 0x000a, 0x24c7: 0x000a, 0x24c8: 0x000a, 0x24c9: 0x000a, 0x24ca: 0x000a, 0x24cb: 0x000a, + 0x24cc: 0x000a, 0x24cd: 0x000a, 0x24ce: 0x000a, 0x24cf: 0x000a, 0x24d0: 0x0006, 0x24d1: 0x000a, + 0x24d2: 0x0006, 0x24d4: 0x000a, 0x24d5: 0x0006, 0x24d6: 0x000a, 0x24d7: 0x000a, + 0x24d8: 0x000a, 0x24d9: 0x009a, 0x24da: 0x008a, 0x24db: 0x007a, 0x24dc: 0x006a, 0x24dd: 0x009a, + 0x24de: 0x008a, 0x24df: 0x0004, 0x24e0: 0x000a, 0x24e1: 0x000a, 0x24e2: 0x0003, 0x24e3: 0x0003, + 0x24e4: 0x000a, 0x24e5: 0x000a, 0x24e6: 0x000a, 0x24e8: 0x000a, 0x24e9: 0x0004, + 0x24ea: 0x0004, 0x24eb: 0x000a, + 0x24f0: 0x000d, 0x24f1: 0x000d, 0x24f2: 0x000d, 0x24f3: 0x000d, 0x24f4: 0x000d, 0x24f5: 0x000d, + 0x24f6: 0x000d, 0x24f7: 0x000d, 0x24f8: 0x000d, 0x24f9: 0x000d, 0x24fa: 0x000d, 0x24fb: 0x000d, + 0x24fc: 0x000d, 0x24fd: 0x000d, 0x24fe: 0x000d, 0x24ff: 0x000d, + // Block 0x94, offset 0x2500 + 0x2500: 0x000d, 0x2501: 0x000d, 0x2502: 0x000d, 0x2503: 0x000d, 0x2504: 0x000d, 0x2505: 0x000d, + 0x2506: 0x000d, 0x2507: 0x000d, 0x2508: 0x000d, 0x2509: 0x000d, 0x250a: 0x000d, 0x250b: 0x000d, + 0x250c: 0x000d, 0x250d: 0x000d, 0x250e: 0x000d, 0x250f: 0x000d, 0x2510: 0x000d, 0x2511: 0x000d, + 0x2512: 0x000d, 0x2513: 0x000d, 0x2514: 0x000d, 0x2515: 0x000d, 0x2516: 0x000d, 0x2517: 0x000d, + 0x2518: 0x000d, 0x2519: 0x000d, 0x251a: 0x000d, 0x251b: 0x000d, 0x251c: 0x000d, 0x251d: 0x000d, + 0x251e: 0x000d, 0x251f: 0x000d, 0x2520: 0x000d, 0x2521: 0x000d, 0x2522: 0x000d, 0x2523: 0x000d, + 0x2524: 0x000d, 0x2525: 0x000d, 0x2526: 0x000d, 0x2527: 0x000d, 0x2528: 0x000d, 0x2529: 0x000d, + 0x252a: 0x000d, 0x252b: 0x000d, 0x252c: 0x000d, 0x252d: 0x000d, 0x252e: 0x000d, 0x252f: 0x000d, + 0x2530: 0x000d, 0x2531: 0x000d, 0x2532: 0x000d, 0x2533: 0x000d, 0x2534: 0x000d, 0x2535: 0x000d, + 0x2536: 0x000d, 0x2537: 0x000d, 0x2538: 0x000d, 0x2539: 0x000d, 0x253a: 0x000d, 0x253b: 0x000d, + 0x253c: 0x000d, 0x253d: 0x000d, 0x253e: 0x000d, 0x253f: 0x000b, + // Block 0x95, offset 0x2540 + 0x2541: 0x000a, 0x2542: 0x000a, 0x2543: 0x0004, 0x2544: 0x0004, 0x2545: 0x0004, + 0x2546: 0x000a, 0x2547: 0x000a, 0x2548: 0x003a, 0x2549: 0x002a, 0x254a: 0x000a, 0x254b: 0x0003, + 0x254c: 0x0006, 0x254d: 0x0003, 0x254e: 0x0006, 0x254f: 0x0006, 0x2550: 0x0002, 0x2551: 0x0002, + 0x2552: 0x0002, 0x2553: 0x0002, 0x2554: 0x0002, 0x2555: 0x0002, 0x2556: 0x0002, 0x2557: 0x0002, + 0x2558: 0x0002, 0x2559: 0x0002, 0x255a: 0x0006, 0x255b: 0x000a, 0x255c: 0x000a, 0x255d: 0x000a, + 0x255e: 0x000a, 0x255f: 0x000a, 0x2560: 0x000a, + 0x257b: 0x005a, + 0x257c: 0x000a, 0x257d: 0x004a, 0x257e: 0x000a, 0x257f: 0x000a, + // Block 0x96, offset 0x2580 + 0x2580: 0x000a, + 0x259b: 0x005a, 0x259c: 0x000a, 0x259d: 0x004a, + 0x259e: 0x000a, 0x259f: 0x00fa, 0x25a0: 0x00ea, 0x25a1: 0x000a, 0x25a2: 0x003a, 0x25a3: 0x002a, + 0x25a4: 0x000a, 0x25a5: 0x000a, + // Block 0x97, offset 0x25c0 + 0x25e0: 0x0004, 0x25e1: 0x0004, 0x25e2: 0x000a, 0x25e3: 0x000a, + 0x25e4: 0x000a, 0x25e5: 0x0004, 0x25e6: 0x0004, 0x25e8: 0x000a, 0x25e9: 0x000a, + 0x25ea: 0x000a, 0x25eb: 0x000a, 0x25ec: 0x000a, 0x25ed: 0x000a, 0x25ee: 0x000a, + 0x25f0: 0x000b, 0x25f1: 0x000b, 0x25f2: 0x000b, 0x25f3: 0x000b, 0x25f4: 0x000b, 0x25f5: 0x000b, + 0x25f6: 0x000b, 0x25f7: 0x000b, 0x25f8: 0x000b, 0x25f9: 0x000a, 0x25fa: 0x000a, 0x25fb: 0x000a, + 0x25fc: 0x000a, 0x25fd: 0x000a, 0x25fe: 0x000b, 0x25ff: 0x000b, + // Block 0x98, offset 0x2600 + 0x2601: 0x000a, + // Block 0x99, offset 0x2640 + 0x2640: 0x000a, 0x2641: 0x000a, 0x2642: 0x000a, 0x2643: 0x000a, 0x2644: 0x000a, 0x2645: 0x000a, + 0x2646: 0x000a, 0x2647: 0x000a, 0x2648: 0x000a, 0x2649: 0x000a, 0x264a: 0x000a, 0x264b: 0x000a, + 0x264c: 0x000a, 0x2650: 0x000a, 0x2651: 0x000a, + 0x2652: 0x000a, 0x2653: 0x000a, 0x2654: 0x000a, 0x2655: 0x000a, 0x2656: 0x000a, 0x2657: 0x000a, + 0x2658: 0x000a, 0x2659: 0x000a, 0x265a: 0x000a, 0x265b: 0x000a, + 0x2660: 0x000a, + // Block 0x9a, offset 0x2680 + 0x26bd: 0x000c, + // Block 0x9b, offset 0x26c0 + 0x26e0: 0x000c, 0x26e1: 0x0002, 0x26e2: 0x0002, 0x26e3: 0x0002, + 0x26e4: 0x0002, 0x26e5: 0x0002, 0x26e6: 0x0002, 0x26e7: 0x0002, 0x26e8: 0x0002, 0x26e9: 0x0002, + 0x26ea: 0x0002, 0x26eb: 0x0002, 0x26ec: 0x0002, 0x26ed: 0x0002, 0x26ee: 0x0002, 0x26ef: 0x0002, + 0x26f0: 0x0002, 0x26f1: 0x0002, 0x26f2: 0x0002, 0x26f3: 0x0002, 0x26f4: 0x0002, 0x26f5: 0x0002, + 0x26f6: 0x0002, 0x26f7: 0x0002, 0x26f8: 0x0002, 0x26f9: 0x0002, 0x26fa: 0x0002, 0x26fb: 0x0002, + // Block 0x9c, offset 0x2700 + 0x2736: 0x000c, 0x2737: 0x000c, 0x2738: 0x000c, 0x2739: 0x000c, 0x273a: 0x000c, + // Block 0x9d, offset 0x2740 + 0x2740: 0x0001, 0x2741: 0x0001, 0x2742: 0x0001, 0x2743: 0x0001, 0x2744: 0x0001, 0x2745: 0x0001, + 0x2746: 0x0001, 0x2747: 0x0001, 0x2748: 0x0001, 0x2749: 0x0001, 0x274a: 0x0001, 0x274b: 0x0001, + 0x274c: 0x0001, 0x274d: 0x0001, 0x274e: 0x0001, 0x274f: 0x0001, 0x2750: 0x0001, 0x2751: 0x0001, + 0x2752: 0x0001, 0x2753: 0x0001, 0x2754: 0x0001, 0x2755: 0x0001, 0x2756: 0x0001, 0x2757: 0x0001, + 0x2758: 0x0001, 0x2759: 0x0001, 0x275a: 0x0001, 0x275b: 0x0001, 0x275c: 0x0001, 0x275d: 0x0001, + 0x275e: 0x0001, 0x275f: 0x0001, 0x2760: 0x0001, 0x2761: 0x0001, 0x2762: 0x0001, 0x2763: 0x0001, + 0x2764: 0x0001, 0x2765: 0x0001, 0x2766: 0x0001, 0x2767: 0x0001, 0x2768: 0x0001, 0x2769: 0x0001, + 0x276a: 0x0001, 0x276b: 0x0001, 0x276c: 0x0001, 0x276d: 0x0001, 0x276e: 0x0001, 0x276f: 0x0001, + 0x2770: 0x0001, 0x2771: 0x0001, 0x2772: 0x0001, 0x2773: 0x0001, 0x2774: 0x0001, 0x2775: 0x0001, + 0x2776: 0x0001, 0x2777: 0x0001, 0x2778: 0x0001, 0x2779: 0x0001, 0x277a: 0x0001, 0x277b: 0x0001, + 0x277c: 0x0001, 0x277d: 0x0001, 0x277e: 0x0001, 0x277f: 0x0001, + // Block 0x9e, offset 0x2780 + 0x2780: 0x0001, 0x2781: 0x0001, 0x2782: 0x0001, 0x2783: 0x0001, 0x2784: 0x0001, 0x2785: 0x0001, + 0x2786: 0x0001, 0x2787: 0x0001, 0x2788: 0x0001, 0x2789: 0x0001, 0x278a: 0x0001, 0x278b: 0x0001, + 0x278c: 0x0001, 0x278d: 0x0001, 0x278e: 0x0001, 0x278f: 0x0001, 0x2790: 0x0001, 0x2791: 0x0001, + 0x2792: 0x0001, 0x2793: 0x0001, 0x2794: 0x0001, 0x2795: 0x0001, 0x2796: 0x0001, 0x2797: 0x0001, + 0x2798: 0x0001, 0x2799: 0x0001, 0x279a: 0x0001, 0x279b: 0x0001, 0x279c: 0x0001, 0x279d: 0x0001, + 0x279e: 0x0001, 0x279f: 0x000a, 0x27a0: 0x0001, 0x27a1: 0x0001, 0x27a2: 0x0001, 0x27a3: 0x0001, + 0x27a4: 0x0001, 0x27a5: 0x0001, 0x27a6: 0x0001, 0x27a7: 0x0001, 0x27a8: 0x0001, 0x27a9: 0x0001, + 0x27aa: 0x0001, 0x27ab: 0x0001, 0x27ac: 0x0001, 0x27ad: 0x0001, 0x27ae: 0x0001, 0x27af: 0x0001, + 0x27b0: 0x0001, 0x27b1: 0x0001, 0x27b2: 0x0001, 0x27b3: 0x0001, 0x27b4: 0x0001, 0x27b5: 0x0001, + 0x27b6: 0x0001, 0x27b7: 0x0001, 0x27b8: 0x0001, 0x27b9: 0x0001, 0x27ba: 0x0001, 0x27bb: 0x0001, + 0x27bc: 0x0001, 0x27bd: 0x0001, 0x27be: 0x0001, 0x27bf: 0x0001, + // Block 0x9f, offset 0x27c0 + 0x27c0: 0x0001, 0x27c1: 0x000c, 0x27c2: 0x000c, 0x27c3: 0x000c, 0x27c4: 0x0001, 0x27c5: 0x000c, + 0x27c6: 0x000c, 0x27c7: 0x0001, 0x27c8: 0x0001, 0x27c9: 0x0001, 0x27ca: 0x0001, 0x27cb: 0x0001, + 0x27cc: 0x000c, 0x27cd: 0x000c, 0x27ce: 0x000c, 0x27cf: 0x000c, 0x27d0: 0x0001, 0x27d1: 0x0001, + 0x27d2: 0x0001, 0x27d3: 0x0001, 0x27d4: 0x0001, 0x27d5: 0x0001, 0x27d6: 0x0001, 0x27d7: 0x0001, + 0x27d8: 0x0001, 0x27d9: 0x0001, 0x27da: 0x0001, 0x27db: 0x0001, 0x27dc: 0x0001, 0x27dd: 0x0001, + 0x27de: 0x0001, 0x27df: 0x0001, 0x27e0: 0x0001, 0x27e1: 0x0001, 0x27e2: 0x0001, 0x27e3: 0x0001, + 0x27e4: 0x0001, 0x27e5: 0x0001, 0x27e6: 0x0001, 0x27e7: 0x0001, 0x27e8: 0x0001, 0x27e9: 0x0001, + 0x27ea: 0x0001, 0x27eb: 0x0001, 0x27ec: 0x0001, 0x27ed: 0x0001, 0x27ee: 0x0001, 0x27ef: 0x0001, + 0x27f0: 0x0001, 0x27f1: 0x0001, 0x27f2: 0x0001, 0x27f3: 0x0001, 0x27f4: 0x0001, 0x27f5: 0x0001, + 0x27f6: 0x0001, 0x27f7: 0x0001, 0x27f8: 0x000c, 0x27f9: 0x000c, 0x27fa: 0x000c, 0x27fb: 0x0001, + 0x27fc: 0x0001, 0x27fd: 0x0001, 0x27fe: 0x0001, 0x27ff: 0x000c, + // Block 0xa0, offset 0x2800 + 0x2800: 0x0001, 0x2801: 0x0001, 0x2802: 0x0001, 0x2803: 0x0001, 0x2804: 0x0001, 0x2805: 0x0001, + 0x2806: 0x0001, 0x2807: 0x0001, 0x2808: 0x0001, 0x2809: 0x0001, 0x280a: 0x0001, 0x280b: 0x0001, + 0x280c: 0x0001, 0x280d: 0x0001, 0x280e: 0x0001, 0x280f: 0x0001, 0x2810: 0x0001, 0x2811: 0x0001, + 0x2812: 0x0001, 0x2813: 0x0001, 0x2814: 0x0001, 0x2815: 0x0001, 0x2816: 0x0001, 0x2817: 0x0001, + 0x2818: 0x0001, 0x2819: 0x0001, 0x281a: 0x0001, 0x281b: 0x0001, 0x281c: 0x0001, 0x281d: 0x0001, + 0x281e: 0x0001, 0x281f: 0x0001, 0x2820: 0x0001, 0x2821: 0x0001, 0x2822: 0x0001, 0x2823: 0x0001, + 0x2824: 0x0001, 0x2825: 0x000c, 0x2826: 0x000c, 0x2827: 0x0001, 0x2828: 0x0001, 0x2829: 0x0001, + 0x282a: 0x0001, 0x282b: 0x0001, 0x282c: 0x0001, 0x282d: 0x0001, 0x282e: 0x0001, 0x282f: 0x0001, + 0x2830: 0x0001, 0x2831: 0x0001, 0x2832: 0x0001, 0x2833: 0x0001, 0x2834: 0x0001, 0x2835: 0x0001, + 0x2836: 0x0001, 0x2837: 0x0001, 0x2838: 0x0001, 0x2839: 0x0001, 0x283a: 0x0001, 0x283b: 0x0001, + 0x283c: 0x0001, 0x283d: 0x0001, 0x283e: 0x0001, 0x283f: 0x0001, + // Block 0xa1, offset 0x2840 + 0x2840: 0x0001, 0x2841: 0x0001, 0x2842: 0x0001, 0x2843: 0x0001, 0x2844: 0x0001, 0x2845: 0x0001, + 0x2846: 0x0001, 0x2847: 0x0001, 0x2848: 0x0001, 0x2849: 0x0001, 0x284a: 0x0001, 0x284b: 0x0001, + 0x284c: 0x0001, 0x284d: 0x0001, 0x284e: 0x0001, 0x284f: 0x0001, 0x2850: 0x0001, 0x2851: 0x0001, + 0x2852: 0x0001, 0x2853: 0x0001, 0x2854: 0x0001, 0x2855: 0x0001, 0x2856: 0x0001, 0x2857: 0x0001, + 0x2858: 0x0001, 0x2859: 0x0001, 0x285a: 0x0001, 0x285b: 0x0001, 0x285c: 0x0001, 0x285d: 0x0001, + 0x285e: 0x0001, 0x285f: 0x0001, 0x2860: 0x0001, 0x2861: 0x0001, 0x2862: 0x0001, 0x2863: 0x0001, + 0x2864: 0x0001, 0x2865: 0x0001, 0x2866: 0x0001, 0x2867: 0x0001, 0x2868: 0x0001, 0x2869: 0x0001, + 0x286a: 0x0001, 0x286b: 0x0001, 0x286c: 0x0001, 0x286d: 0x0001, 0x286e: 0x0001, 0x286f: 0x0001, + 0x2870: 0x0001, 0x2871: 0x0001, 0x2872: 0x0001, 0x2873: 0x0001, 0x2874: 0x0001, 0x2875: 0x0001, + 0x2876: 0x0001, 0x2877: 0x0001, 0x2878: 0x0001, 0x2879: 0x000a, 0x287a: 0x000a, 0x287b: 0x000a, + 0x287c: 0x000a, 0x287d: 0x000a, 0x287e: 0x000a, 0x287f: 0x000a, + // Block 0xa2, offset 0x2880 + 0x2880: 0x0001, 0x2881: 0x0001, 0x2882: 0x0001, 0x2883: 0x0001, 0x2884: 0x0001, 0x2885: 0x0001, + 0x2886: 0x0001, 0x2887: 0x0001, 0x2888: 0x0001, 0x2889: 0x0001, 0x288a: 0x0001, 0x288b: 0x0001, + 0x288c: 0x0001, 0x288d: 0x0001, 0x288e: 0x0001, 0x288f: 0x0001, 0x2890: 0x0001, 0x2891: 0x0001, + 0x2892: 0x0001, 0x2893: 0x0001, 0x2894: 0x0001, 0x2895: 0x0001, 0x2896: 0x0001, 0x2897: 0x0001, + 0x2898: 0x0001, 0x2899: 0x0001, 0x289a: 0x0001, 0x289b: 0x0001, 0x289c: 0x0001, 0x289d: 0x0001, + 0x289e: 0x0001, 0x289f: 0x0001, 0x28a0: 0x0005, 0x28a1: 0x0005, 0x28a2: 0x0005, 0x28a3: 0x0005, + 0x28a4: 0x0005, 0x28a5: 0x0005, 0x28a6: 0x0005, 0x28a7: 0x0005, 0x28a8: 0x0005, 0x28a9: 0x0005, + 0x28aa: 0x0005, 0x28ab: 0x0005, 0x28ac: 0x0005, 0x28ad: 0x0005, 0x28ae: 0x0005, 0x28af: 0x0005, + 0x28b0: 0x0005, 0x28b1: 0x0005, 0x28b2: 0x0005, 0x28b3: 0x0005, 0x28b4: 0x0005, 0x28b5: 0x0005, + 0x28b6: 0x0005, 0x28b7: 0x0005, 0x28b8: 0x0005, 0x28b9: 0x0005, 0x28ba: 0x0005, 0x28bb: 0x0005, + 0x28bc: 0x0005, 0x28bd: 0x0005, 0x28be: 0x0005, 0x28bf: 0x0001, + // Block 0xa3, offset 0x28c0 + 0x28c1: 0x000c, + 0x28f8: 0x000c, 0x28f9: 0x000c, 0x28fa: 0x000c, 0x28fb: 0x000c, + 0x28fc: 0x000c, 0x28fd: 0x000c, 0x28fe: 0x000c, 0x28ff: 0x000c, + // Block 0xa4, offset 0x2900 + 0x2900: 0x000c, 0x2901: 0x000c, 0x2902: 0x000c, 0x2903: 0x000c, 0x2904: 0x000c, 0x2905: 0x000c, + 0x2906: 0x000c, + 0x2912: 0x000a, 0x2913: 0x000a, 0x2914: 0x000a, 0x2915: 0x000a, 0x2916: 0x000a, 0x2917: 0x000a, + 0x2918: 0x000a, 0x2919: 0x000a, 0x291a: 0x000a, 0x291b: 0x000a, 0x291c: 0x000a, 0x291d: 0x000a, + 0x291e: 0x000a, 0x291f: 0x000a, 0x2920: 0x000a, 0x2921: 0x000a, 0x2922: 0x000a, 0x2923: 0x000a, + 0x2924: 0x000a, 0x2925: 0x000a, + 0x293f: 0x000c, + // Block 0xa5, offset 0x2940 + 0x2940: 0x000c, 0x2941: 0x000c, + 0x2973: 0x000c, 0x2974: 0x000c, 0x2975: 0x000c, + 0x2976: 0x000c, 0x2979: 0x000c, 0x297a: 0x000c, + // Block 0xa6, offset 0x2980 + 0x2980: 0x000c, 0x2981: 0x000c, 0x2982: 0x000c, + 0x29a7: 0x000c, 0x29a8: 0x000c, 0x29a9: 0x000c, + 0x29aa: 0x000c, 0x29ab: 0x000c, 0x29ad: 0x000c, 0x29ae: 0x000c, 0x29af: 0x000c, + 0x29b0: 0x000c, 0x29b1: 0x000c, 0x29b2: 0x000c, 0x29b3: 0x000c, 0x29b4: 0x000c, + // Block 0xa7, offset 0x29c0 + 0x29f3: 0x000c, + // Block 0xa8, offset 0x2a00 + 0x2a00: 0x000c, 0x2a01: 0x000c, + 0x2a36: 0x000c, 0x2a37: 0x000c, 0x2a38: 0x000c, 0x2a39: 0x000c, 0x2a3a: 0x000c, 0x2a3b: 0x000c, + 0x2a3c: 0x000c, 0x2a3d: 0x000c, 0x2a3e: 0x000c, + // Block 0xa9, offset 0x2a40 + 0x2a4a: 0x000c, 0x2a4b: 0x000c, + 0x2a4c: 0x000c, + // Block 0xaa, offset 0x2a80 + 0x2aaf: 0x000c, + 0x2ab0: 0x000c, 0x2ab1: 0x000c, 0x2ab4: 0x000c, + 0x2ab6: 0x000c, 0x2ab7: 0x000c, + 0x2abe: 0x000c, + // Block 0xab, offset 0x2ac0 + 0x2adf: 0x000c, 0x2ae3: 0x000c, + 0x2ae4: 0x000c, 0x2ae5: 0x000c, 0x2ae6: 0x000c, 0x2ae7: 0x000c, 0x2ae8: 0x000c, 0x2ae9: 0x000c, + 0x2aea: 0x000c, + // Block 0xac, offset 0x2b00 + 0x2b00: 0x000c, 0x2b01: 0x000c, + 0x2b3c: 0x000c, + // Block 0xad, offset 0x2b40 + 0x2b40: 0x000c, + 0x2b66: 0x000c, 0x2b67: 0x000c, 0x2b68: 0x000c, 0x2b69: 0x000c, + 0x2b6a: 0x000c, 0x2b6b: 0x000c, 0x2b6c: 0x000c, + 0x2b70: 0x000c, 0x2b71: 0x000c, 0x2b72: 0x000c, 0x2b73: 0x000c, 0x2b74: 0x000c, + // Block 0xae, offset 0x2b80 + 0x2bb8: 0x000c, 0x2bb9: 0x000c, 0x2bba: 0x000c, 0x2bbb: 0x000c, + 0x2bbc: 0x000c, 0x2bbd: 0x000c, 0x2bbe: 0x000c, 0x2bbf: 0x000c, + // Block 0xaf, offset 0x2bc0 + 0x2bc2: 0x000c, 0x2bc3: 0x000c, 0x2bc4: 0x000c, + 0x2bc6: 0x000c, + // Block 0xb0, offset 0x2c00 + 0x2c33: 0x000c, 0x2c34: 0x000c, 0x2c35: 0x000c, + 0x2c36: 0x000c, 0x2c37: 0x000c, 0x2c38: 0x000c, 0x2c3a: 0x000c, + 0x2c3f: 0x000c, + // Block 0xb1, offset 0x2c40 + 0x2c40: 0x000c, 0x2c42: 0x000c, 0x2c43: 0x000c, + // Block 0xb2, offset 0x2c80 + 0x2cb2: 0x000c, 0x2cb3: 0x000c, 0x2cb4: 0x000c, 0x2cb5: 0x000c, + 0x2cbc: 0x000c, 0x2cbd: 0x000c, 0x2cbf: 0x000c, + // Block 0xb3, offset 0x2cc0 + 0x2cc0: 0x000c, + 0x2cdc: 0x000c, 0x2cdd: 0x000c, + // Block 0xb4, offset 0x2d00 + 0x2d33: 0x000c, 0x2d34: 0x000c, 0x2d35: 0x000c, + 0x2d36: 0x000c, 0x2d37: 0x000c, 0x2d38: 0x000c, 0x2d39: 0x000c, 0x2d3a: 0x000c, + 0x2d3d: 0x000c, 0x2d3f: 0x000c, + // Block 0xb5, offset 0x2d40 + 0x2d40: 0x000c, + 0x2d60: 0x000a, 0x2d61: 0x000a, 0x2d62: 0x000a, 0x2d63: 0x000a, + 0x2d64: 0x000a, 0x2d65: 0x000a, 0x2d66: 0x000a, 0x2d67: 0x000a, 0x2d68: 0x000a, 0x2d69: 0x000a, + 0x2d6a: 0x000a, 0x2d6b: 0x000a, 0x2d6c: 0x000a, + // Block 0xb6, offset 0x2d80 + 0x2dab: 0x000c, 0x2dad: 0x000c, + 0x2db0: 0x000c, 0x2db1: 0x000c, 0x2db2: 0x000c, 0x2db3: 0x000c, 0x2db4: 0x000c, 0x2db5: 0x000c, + 0x2db7: 0x000c, + // Block 0xb7, offset 0x2dc0 + 0x2ddd: 0x000c, + 0x2dde: 0x000c, 0x2ddf: 0x000c, 0x2de2: 0x000c, 0x2de3: 0x000c, + 0x2de4: 0x000c, 0x2de5: 0x000c, 0x2de7: 0x000c, 0x2de8: 0x000c, 0x2de9: 0x000c, + 0x2dea: 0x000c, 0x2deb: 0x000c, + // Block 0xb8, offset 0x2e00 + 0x2e30: 0x000c, 0x2e31: 0x000c, 0x2e32: 0x000c, 0x2e33: 0x000c, 0x2e34: 0x000c, 0x2e35: 0x000c, + 0x2e36: 0x000c, 0x2e38: 0x000c, 0x2e39: 0x000c, 0x2e3a: 0x000c, 0x2e3b: 0x000c, + 0x2e3c: 0x000c, 0x2e3d: 0x000c, + // Block 0xb9, offset 0x2e40 + 0x2e52: 0x000c, 0x2e53: 0x000c, 0x2e54: 0x000c, 0x2e55: 0x000c, 0x2e56: 0x000c, 0x2e57: 0x000c, + 0x2e58: 0x000c, 0x2e59: 0x000c, 0x2e5a: 0x000c, 0x2e5b: 0x000c, 0x2e5c: 0x000c, 0x2e5d: 0x000c, + 0x2e5e: 0x000c, 0x2e5f: 0x000c, 0x2e60: 0x000c, 0x2e61: 0x000c, 0x2e62: 0x000c, 0x2e63: 0x000c, + 0x2e64: 0x000c, 0x2e65: 0x000c, 0x2e66: 0x000c, 0x2e67: 0x000c, + 0x2e6a: 0x000c, 0x2e6b: 0x000c, 0x2e6c: 0x000c, 0x2e6d: 0x000c, 0x2e6e: 0x000c, 0x2e6f: 0x000c, + 0x2e70: 0x000c, 0x2e72: 0x000c, 0x2e73: 0x000c, 0x2e75: 0x000c, + 0x2e76: 0x000c, + // Block 0xba, offset 0x2e80 + 0x2eb0: 0x000c, 0x2eb1: 0x000c, 0x2eb2: 0x000c, 0x2eb3: 0x000c, 0x2eb4: 0x000c, + // Block 0xbb, offset 0x2ec0 + 0x2ef0: 0x000c, 0x2ef1: 0x000c, 0x2ef2: 0x000c, 0x2ef3: 0x000c, 0x2ef4: 0x000c, 0x2ef5: 0x000c, + 0x2ef6: 0x000c, + // Block 0xbc, offset 0x2f00 + 0x2f0f: 0x000c, 0x2f10: 0x000c, 0x2f11: 0x000c, + 0x2f12: 0x000c, + // Block 0xbd, offset 0x2f40 + 0x2f5d: 0x000c, + 0x2f5e: 0x000c, 0x2f60: 0x000b, 0x2f61: 0x000b, 0x2f62: 0x000b, 0x2f63: 0x000b, + // Block 0xbe, offset 0x2f80 + 0x2fa7: 0x000c, 0x2fa8: 0x000c, 0x2fa9: 0x000c, + 0x2fb3: 0x000b, 0x2fb4: 0x000b, 0x2fb5: 0x000b, + 0x2fb6: 0x000b, 0x2fb7: 0x000b, 0x2fb8: 0x000b, 0x2fb9: 0x000b, 0x2fba: 0x000b, 0x2fbb: 0x000c, + 0x2fbc: 0x000c, 0x2fbd: 0x000c, 0x2fbe: 0x000c, 0x2fbf: 0x000c, + // Block 0xbf, offset 0x2fc0 + 0x2fc0: 0x000c, 0x2fc1: 0x000c, 0x2fc2: 0x000c, 0x2fc5: 0x000c, + 0x2fc6: 0x000c, 0x2fc7: 0x000c, 0x2fc8: 0x000c, 0x2fc9: 0x000c, 0x2fca: 0x000c, 0x2fcb: 0x000c, + 0x2fea: 0x000c, 0x2feb: 0x000c, 0x2fec: 0x000c, 0x2fed: 0x000c, + // Block 0xc0, offset 0x3000 + 0x3000: 0x000a, 0x3001: 0x000a, 0x3002: 0x000c, 0x3003: 0x000c, 0x3004: 0x000c, 0x3005: 0x000a, + // Block 0xc1, offset 0x3040 + 0x3040: 0x000a, 0x3041: 0x000a, 0x3042: 0x000a, 0x3043: 0x000a, 0x3044: 0x000a, 0x3045: 0x000a, + 0x3046: 0x000a, 0x3047: 0x000a, 0x3048: 0x000a, 0x3049: 0x000a, 0x304a: 0x000a, 0x304b: 0x000a, + 0x304c: 0x000a, 0x304d: 0x000a, 0x304e: 0x000a, 0x304f: 0x000a, 0x3050: 0x000a, 0x3051: 0x000a, + 0x3052: 0x000a, 0x3053: 0x000a, 0x3054: 0x000a, 0x3055: 0x000a, 0x3056: 0x000a, + // Block 0xc2, offset 0x3080 + 0x309b: 0x000a, + // Block 0xc3, offset 0x30c0 + 0x30d5: 0x000a, + // Block 0xc4, offset 0x3100 + 0x310f: 0x000a, + // Block 0xc5, offset 0x3140 + 0x3149: 0x000a, + // Block 0xc6, offset 0x3180 + 0x3183: 0x000a, + 0x318e: 0x0002, 0x318f: 0x0002, 0x3190: 0x0002, 0x3191: 0x0002, + 0x3192: 0x0002, 0x3193: 0x0002, 0x3194: 0x0002, 0x3195: 0x0002, 0x3196: 0x0002, 0x3197: 0x0002, + 0x3198: 0x0002, 0x3199: 0x0002, 0x319a: 0x0002, 0x319b: 0x0002, 0x319c: 0x0002, 0x319d: 0x0002, + 0x319e: 0x0002, 0x319f: 0x0002, 0x31a0: 0x0002, 0x31a1: 0x0002, 0x31a2: 0x0002, 0x31a3: 0x0002, + 0x31a4: 0x0002, 0x31a5: 0x0002, 0x31a6: 0x0002, 0x31a7: 0x0002, 0x31a8: 0x0002, 0x31a9: 0x0002, + 0x31aa: 0x0002, 0x31ab: 0x0002, 0x31ac: 0x0002, 0x31ad: 0x0002, 0x31ae: 0x0002, 0x31af: 0x0002, + 0x31b0: 0x0002, 0x31b1: 0x0002, 0x31b2: 0x0002, 0x31b3: 0x0002, 0x31b4: 0x0002, 0x31b5: 0x0002, + 0x31b6: 0x0002, 0x31b7: 0x0002, 0x31b8: 0x0002, 0x31b9: 0x0002, 0x31ba: 0x0002, 0x31bb: 0x0002, + 0x31bc: 0x0002, 0x31bd: 0x0002, 0x31be: 0x0002, 0x31bf: 0x0002, + // Block 0xc7, offset 0x31c0 + 0x31c0: 0x000c, 0x31c1: 0x000c, 0x31c2: 0x000c, 0x31c3: 0x000c, 0x31c4: 0x000c, 0x31c5: 0x000c, + 0x31c6: 0x000c, 0x31c7: 0x000c, 0x31c8: 0x000c, 0x31c9: 0x000c, 0x31ca: 0x000c, 0x31cb: 0x000c, + 0x31cc: 0x000c, 0x31cd: 0x000c, 0x31ce: 0x000c, 0x31cf: 0x000c, 0x31d0: 0x000c, 0x31d1: 0x000c, + 0x31d2: 0x000c, 0x31d3: 0x000c, 0x31d4: 0x000c, 0x31d5: 0x000c, 0x31d6: 0x000c, 0x31d7: 0x000c, + 0x31d8: 0x000c, 0x31d9: 0x000c, 0x31da: 0x000c, 0x31db: 0x000c, 0x31dc: 0x000c, 0x31dd: 0x000c, + 0x31de: 0x000c, 0x31df: 0x000c, 0x31e0: 0x000c, 0x31e1: 0x000c, 0x31e2: 0x000c, 0x31e3: 0x000c, + 0x31e4: 0x000c, 0x31e5: 0x000c, 0x31e6: 0x000c, 0x31e7: 0x000c, 0x31e8: 0x000c, 0x31e9: 0x000c, + 0x31ea: 0x000c, 0x31eb: 0x000c, 0x31ec: 0x000c, 0x31ed: 0x000c, 0x31ee: 0x000c, 0x31ef: 0x000c, + 0x31f0: 0x000c, 0x31f1: 0x000c, 0x31f2: 0x000c, 0x31f3: 0x000c, 0x31f4: 0x000c, 0x31f5: 0x000c, + 0x31f6: 0x000c, 0x31fb: 0x000c, + 0x31fc: 0x000c, 0x31fd: 0x000c, 0x31fe: 0x000c, 0x31ff: 0x000c, + // Block 0xc8, offset 0x3200 + 0x3200: 0x000c, 0x3201: 0x000c, 0x3202: 0x000c, 0x3203: 0x000c, 0x3204: 0x000c, 0x3205: 0x000c, + 0x3206: 0x000c, 0x3207: 0x000c, 0x3208: 0x000c, 0x3209: 0x000c, 0x320a: 0x000c, 0x320b: 0x000c, + 0x320c: 0x000c, 0x320d: 0x000c, 0x320e: 0x000c, 0x320f: 0x000c, 0x3210: 0x000c, 0x3211: 0x000c, + 0x3212: 0x000c, 0x3213: 0x000c, 0x3214: 0x000c, 0x3215: 0x000c, 0x3216: 0x000c, 0x3217: 0x000c, + 0x3218: 0x000c, 0x3219: 0x000c, 0x321a: 0x000c, 0x321b: 0x000c, 0x321c: 0x000c, 0x321d: 0x000c, + 0x321e: 0x000c, 0x321f: 0x000c, 0x3220: 0x000c, 0x3221: 0x000c, 0x3222: 0x000c, 0x3223: 0x000c, + 0x3224: 0x000c, 0x3225: 0x000c, 0x3226: 0x000c, 0x3227: 0x000c, 0x3228: 0x000c, 0x3229: 0x000c, + 0x322a: 0x000c, 0x322b: 0x000c, 0x322c: 0x000c, + 0x3235: 0x000c, + // Block 0xc9, offset 0x3240 + 0x3244: 0x000c, + 0x325b: 0x000c, 0x325c: 0x000c, 0x325d: 0x000c, + 0x325e: 0x000c, 0x325f: 0x000c, 0x3261: 0x000c, 0x3262: 0x000c, 0x3263: 0x000c, + 0x3264: 0x000c, 0x3265: 0x000c, 0x3266: 0x000c, 0x3267: 0x000c, 0x3268: 0x000c, 0x3269: 0x000c, + 0x326a: 0x000c, 0x326b: 0x000c, 0x326c: 0x000c, 0x326d: 0x000c, 0x326e: 0x000c, 0x326f: 0x000c, + // Block 0xca, offset 0x3280 + 0x3280: 0x000c, 0x3281: 0x000c, 0x3282: 0x000c, 0x3283: 0x000c, 0x3284: 0x000c, 0x3285: 0x000c, + 0x3286: 0x000c, 0x3288: 0x000c, 0x3289: 0x000c, 0x328a: 0x000c, 0x328b: 0x000c, + 0x328c: 0x000c, 0x328d: 0x000c, 0x328e: 0x000c, 0x328f: 0x000c, 0x3290: 0x000c, 0x3291: 0x000c, + 0x3292: 0x000c, 0x3293: 0x000c, 0x3294: 0x000c, 0x3295: 0x000c, 0x3296: 0x000c, 0x3297: 0x000c, + 0x3298: 0x000c, 0x329b: 0x000c, 0x329c: 0x000c, 0x329d: 0x000c, + 0x329e: 0x000c, 0x329f: 0x000c, 0x32a0: 0x000c, 0x32a1: 0x000c, 0x32a3: 0x000c, + 0x32a4: 0x000c, 0x32a6: 0x000c, 0x32a7: 0x000c, 0x32a8: 0x000c, 0x32a9: 0x000c, + 0x32aa: 0x000c, + // Block 0xcb, offset 0x32c0 + 0x32c0: 0x0001, 0x32c1: 0x0001, 0x32c2: 0x0001, 0x32c3: 0x0001, 0x32c4: 0x0001, 0x32c5: 0x0001, + 0x32c6: 0x0001, 0x32c7: 0x0001, 0x32c8: 0x0001, 0x32c9: 0x0001, 0x32ca: 0x0001, 0x32cb: 0x0001, + 0x32cc: 0x0001, 0x32cd: 0x0001, 0x32ce: 0x0001, 0x32cf: 0x0001, 0x32d0: 0x000c, 0x32d1: 0x000c, + 0x32d2: 0x000c, 0x32d3: 0x000c, 0x32d4: 0x000c, 0x32d5: 0x000c, 0x32d6: 0x000c, 0x32d7: 0x0001, + 0x32d8: 0x0001, 0x32d9: 0x0001, 0x32da: 0x0001, 0x32db: 0x0001, 0x32dc: 0x0001, 0x32dd: 0x0001, + 0x32de: 0x0001, 0x32df: 0x0001, 0x32e0: 0x0001, 0x32e1: 0x0001, 0x32e2: 0x0001, 0x32e3: 0x0001, + 0x32e4: 0x0001, 0x32e5: 0x0001, 0x32e6: 0x0001, 0x32e7: 0x0001, 0x32e8: 0x0001, 0x32e9: 0x0001, + 0x32ea: 0x0001, 0x32eb: 0x0001, 0x32ec: 0x0001, 0x32ed: 0x0001, 0x32ee: 0x0001, 0x32ef: 0x0001, + 0x32f0: 0x0001, 0x32f1: 0x0001, 0x32f2: 0x0001, 0x32f3: 0x0001, 0x32f4: 0x0001, 0x32f5: 0x0001, + 0x32f6: 0x0001, 0x32f7: 0x0001, 0x32f8: 0x0001, 0x32f9: 0x0001, 0x32fa: 0x0001, 0x32fb: 0x0001, + 0x32fc: 0x0001, 0x32fd: 0x0001, 0x32fe: 0x0001, 0x32ff: 0x0001, + // Block 0xcc, offset 0x3300 + 0x3300: 0x0001, 0x3301: 0x0001, 0x3302: 0x0001, 0x3303: 0x0001, 0x3304: 0x000c, 0x3305: 0x000c, + 0x3306: 0x000c, 0x3307: 0x000c, 0x3308: 0x000c, 0x3309: 0x000c, 0x330a: 0x000c, 0x330b: 0x0001, + 0x330c: 0x0001, 0x330d: 0x0001, 0x330e: 0x0001, 0x330f: 0x0001, 0x3310: 0x0001, 0x3311: 0x0001, + 0x3312: 0x0001, 0x3313: 0x0001, 0x3314: 0x0001, 0x3315: 0x0001, 0x3316: 0x0001, 0x3317: 0x0001, + 0x3318: 0x0001, 0x3319: 0x0001, 0x331a: 0x0001, 0x331b: 0x0001, 0x331c: 0x0001, 0x331d: 0x0001, + 0x331e: 0x0001, 0x331f: 0x0001, 0x3320: 0x0001, 0x3321: 0x0001, 0x3322: 0x0001, 0x3323: 0x0001, + 0x3324: 0x0001, 0x3325: 0x0001, 0x3326: 0x0001, 0x3327: 0x0001, 0x3328: 0x0001, 0x3329: 0x0001, + 0x332a: 0x0001, 0x332b: 0x0001, 0x332c: 0x0001, 0x332d: 0x0001, 0x332e: 0x0001, 0x332f: 0x0001, + 0x3330: 0x0001, 0x3331: 0x0001, 0x3332: 0x0001, 0x3333: 0x0001, 0x3334: 0x0001, 0x3335: 0x0001, + 0x3336: 0x0001, 0x3337: 0x0001, 0x3338: 0x0001, 0x3339: 0x0001, 0x333a: 0x0001, 0x333b: 0x0001, + 0x333c: 0x0001, 0x333d: 0x0001, 0x333e: 0x0001, 0x333f: 0x0001, + // Block 0xcd, offset 0x3340 + 0x3340: 0x000d, 0x3341: 0x000d, 0x3342: 0x000d, 0x3343: 0x000d, 0x3344: 0x000d, 0x3345: 0x000d, + 0x3346: 0x000d, 0x3347: 0x000d, 0x3348: 0x000d, 0x3349: 0x000d, 0x334a: 0x000d, 0x334b: 0x000d, + 0x334c: 0x000d, 0x334d: 0x000d, 0x334e: 0x000d, 0x334f: 0x000d, 0x3350: 0x000d, 0x3351: 0x000d, + 0x3352: 0x000d, 0x3353: 0x000d, 0x3354: 0x000d, 0x3355: 0x000d, 0x3356: 0x000d, 0x3357: 0x000d, + 0x3358: 0x000d, 0x3359: 0x000d, 0x335a: 0x000d, 0x335b: 0x000d, 0x335c: 0x000d, 0x335d: 0x000d, + 0x335e: 0x000d, 0x335f: 0x000d, 0x3360: 0x000d, 0x3361: 0x000d, 0x3362: 0x000d, 0x3363: 0x000d, + 0x3364: 0x000d, 0x3365: 0x000d, 0x3366: 0x000d, 0x3367: 0x000d, 0x3368: 0x000d, 0x3369: 0x000d, + 0x336a: 0x000d, 0x336b: 0x000d, 0x336c: 0x000d, 0x336d: 0x000d, 0x336e: 0x000d, 0x336f: 0x000d, + 0x3370: 0x000a, 0x3371: 0x000a, 0x3372: 0x000d, 0x3373: 0x000d, 0x3374: 0x000d, 0x3375: 0x000d, + 0x3376: 0x000d, 0x3377: 0x000d, 0x3378: 0x000d, 0x3379: 0x000d, 0x337a: 0x000d, 0x337b: 0x000d, + 0x337c: 0x000d, 0x337d: 0x000d, 0x337e: 0x000d, 0x337f: 0x000d, + // Block 0xce, offset 0x3380 + 0x3380: 0x000a, 0x3381: 0x000a, 0x3382: 0x000a, 0x3383: 0x000a, 0x3384: 0x000a, 0x3385: 0x000a, + 0x3386: 0x000a, 0x3387: 0x000a, 0x3388: 0x000a, 0x3389: 0x000a, 0x338a: 0x000a, 0x338b: 0x000a, + 0x338c: 0x000a, 0x338d: 0x000a, 0x338e: 0x000a, 0x338f: 0x000a, 0x3390: 0x000a, 0x3391: 0x000a, + 0x3392: 0x000a, 0x3393: 0x000a, 0x3394: 0x000a, 0x3395: 0x000a, 0x3396: 0x000a, 0x3397: 0x000a, + 0x3398: 0x000a, 0x3399: 0x000a, 0x339a: 0x000a, 0x339b: 0x000a, 0x339c: 0x000a, 0x339d: 0x000a, + 0x339e: 0x000a, 0x339f: 0x000a, 0x33a0: 0x000a, 0x33a1: 0x000a, 0x33a2: 0x000a, 0x33a3: 0x000a, + 0x33a4: 0x000a, 0x33a5: 0x000a, 0x33a6: 0x000a, 0x33a7: 0x000a, 0x33a8: 0x000a, 0x33a9: 0x000a, + 0x33aa: 0x000a, 0x33ab: 0x000a, + 0x33b0: 0x000a, 0x33b1: 0x000a, 0x33b2: 0x000a, 0x33b3: 0x000a, 0x33b4: 0x000a, 0x33b5: 0x000a, + 0x33b6: 0x000a, 0x33b7: 0x000a, 0x33b8: 0x000a, 0x33b9: 0x000a, 0x33ba: 0x000a, 0x33bb: 0x000a, + 0x33bc: 0x000a, 0x33bd: 0x000a, 0x33be: 0x000a, 0x33bf: 0x000a, + // Block 0xcf, offset 0x33c0 + 0x33c0: 0x000a, 0x33c1: 0x000a, 0x33c2: 0x000a, 0x33c3: 0x000a, 0x33c4: 0x000a, 0x33c5: 0x000a, + 0x33c6: 0x000a, 0x33c7: 0x000a, 0x33c8: 0x000a, 0x33c9: 0x000a, 0x33ca: 0x000a, 0x33cb: 0x000a, + 0x33cc: 0x000a, 0x33cd: 0x000a, 0x33ce: 0x000a, 0x33cf: 0x000a, 0x33d0: 0x000a, 0x33d1: 0x000a, + 0x33d2: 0x000a, 0x33d3: 0x000a, + 0x33e0: 0x000a, 0x33e1: 0x000a, 0x33e2: 0x000a, 0x33e3: 0x000a, + 0x33e4: 0x000a, 0x33e5: 0x000a, 0x33e6: 0x000a, 0x33e7: 0x000a, 0x33e8: 0x000a, 0x33e9: 0x000a, + 0x33ea: 0x000a, 0x33eb: 0x000a, 0x33ec: 0x000a, 0x33ed: 0x000a, 0x33ee: 0x000a, + 0x33f1: 0x000a, 0x33f2: 0x000a, 0x33f3: 0x000a, 0x33f4: 0x000a, 0x33f5: 0x000a, + 0x33f6: 0x000a, 0x33f7: 0x000a, 0x33f8: 0x000a, 0x33f9: 0x000a, 0x33fa: 0x000a, 0x33fb: 0x000a, + 0x33fc: 0x000a, 0x33fd: 0x000a, 0x33fe: 0x000a, 0x33ff: 0x000a, + // Block 0xd0, offset 0x3400 + 0x3401: 0x000a, 0x3402: 0x000a, 0x3403: 0x000a, 0x3404: 0x000a, 0x3405: 0x000a, + 0x3406: 0x000a, 0x3407: 0x000a, 0x3408: 0x000a, 0x3409: 0x000a, 0x340a: 0x000a, 0x340b: 0x000a, + 0x340c: 0x000a, 0x340d: 0x000a, 0x340e: 0x000a, 0x340f: 0x000a, 0x3411: 0x000a, + 0x3412: 0x000a, 0x3413: 0x000a, 0x3414: 0x000a, 0x3415: 0x000a, 0x3416: 0x000a, 0x3417: 0x000a, + 0x3418: 0x000a, 0x3419: 0x000a, 0x341a: 0x000a, 0x341b: 0x000a, 0x341c: 0x000a, 0x341d: 0x000a, + 0x341e: 0x000a, 0x341f: 0x000a, 0x3420: 0x000a, 0x3421: 0x000a, 0x3422: 0x000a, 0x3423: 0x000a, + 0x3424: 0x000a, 0x3425: 0x000a, 0x3426: 0x000a, 0x3427: 0x000a, 0x3428: 0x000a, 0x3429: 0x000a, + 0x342a: 0x000a, 0x342b: 0x000a, 0x342c: 0x000a, 0x342d: 0x000a, 0x342e: 0x000a, 0x342f: 0x000a, + 0x3430: 0x000a, 0x3431: 0x000a, 0x3432: 0x000a, 0x3433: 0x000a, 0x3434: 0x000a, 0x3435: 0x000a, + // Block 0xd1, offset 0x3440 + 0x3440: 0x0002, 0x3441: 0x0002, 0x3442: 0x0002, 0x3443: 0x0002, 0x3444: 0x0002, 0x3445: 0x0002, + 0x3446: 0x0002, 0x3447: 0x0002, 0x3448: 0x0002, 0x3449: 0x0002, 0x344a: 0x0002, 0x344b: 0x000a, + 0x344c: 0x000a, + // Block 0xd2, offset 0x3480 + 0x34aa: 0x000a, 0x34ab: 0x000a, + // Block 0xd3, offset 0x34c0 + 0x34c0: 0x000a, 0x34c1: 0x000a, 0x34c2: 0x000a, 0x34c3: 0x000a, 0x34c4: 0x000a, 0x34c5: 0x000a, + 0x34c6: 0x000a, 0x34c7: 0x000a, 0x34c8: 0x000a, 0x34c9: 0x000a, 0x34ca: 0x000a, 0x34cb: 0x000a, + 0x34cc: 0x000a, 0x34cd: 0x000a, 0x34ce: 0x000a, 0x34cf: 0x000a, 0x34d0: 0x000a, 0x34d1: 0x000a, + 0x34d2: 0x000a, + 0x34e0: 0x000a, 0x34e1: 0x000a, 0x34e2: 0x000a, 0x34e3: 0x000a, + 0x34e4: 0x000a, 0x34e5: 0x000a, 0x34e6: 0x000a, 0x34e7: 0x000a, 0x34e8: 0x000a, 0x34e9: 0x000a, + 0x34ea: 0x000a, 0x34eb: 0x000a, 0x34ec: 0x000a, + 0x34f0: 0x000a, 0x34f1: 0x000a, 0x34f2: 0x000a, 0x34f3: 0x000a, 0x34f4: 0x000a, 0x34f5: 0x000a, + 0x34f6: 0x000a, + // Block 0xd4, offset 0x3500 + 0x3500: 0x000a, 0x3501: 0x000a, 0x3502: 0x000a, 0x3503: 0x000a, 0x3504: 0x000a, 0x3505: 0x000a, + 0x3506: 0x000a, 0x3507: 0x000a, 0x3508: 0x000a, 0x3509: 0x000a, 0x350a: 0x000a, 0x350b: 0x000a, + 0x350c: 0x000a, 0x350d: 0x000a, 0x350e: 0x000a, 0x350f: 0x000a, 0x3510: 0x000a, 0x3511: 0x000a, + 0x3512: 0x000a, 0x3513: 0x000a, 0x3514: 0x000a, + // Block 0xd5, offset 0x3540 + 0x3540: 0x000a, 0x3541: 0x000a, 0x3542: 0x000a, 0x3543: 0x000a, 0x3544: 0x000a, 0x3545: 0x000a, + 0x3546: 0x000a, 0x3547: 0x000a, 0x3548: 0x000a, 0x3549: 0x000a, 0x354a: 0x000a, 0x354b: 0x000a, + 0x3550: 0x000a, 0x3551: 0x000a, + 0x3552: 0x000a, 0x3553: 0x000a, 0x3554: 0x000a, 0x3555: 0x000a, 0x3556: 0x000a, 0x3557: 0x000a, + 0x3558: 0x000a, 0x3559: 0x000a, 0x355a: 0x000a, 0x355b: 0x000a, 0x355c: 0x000a, 0x355d: 0x000a, + 0x355e: 0x000a, 0x355f: 0x000a, 0x3560: 0x000a, 0x3561: 0x000a, 0x3562: 0x000a, 0x3563: 0x000a, + 0x3564: 0x000a, 0x3565: 0x000a, 0x3566: 0x000a, 0x3567: 0x000a, 0x3568: 0x000a, 0x3569: 0x000a, + 0x356a: 0x000a, 0x356b: 0x000a, 0x356c: 0x000a, 0x356d: 0x000a, 0x356e: 0x000a, 0x356f: 0x000a, + 0x3570: 0x000a, 0x3571: 0x000a, 0x3572: 0x000a, 0x3573: 0x000a, 0x3574: 0x000a, 0x3575: 0x000a, + 0x3576: 0x000a, 0x3577: 0x000a, 0x3578: 0x000a, 0x3579: 0x000a, 0x357a: 0x000a, 0x357b: 0x000a, + 0x357c: 0x000a, 0x357d: 0x000a, 0x357e: 0x000a, 0x357f: 0x000a, + // Block 0xd6, offset 0x3580 + 0x3580: 0x000a, 0x3581: 0x000a, 0x3582: 0x000a, 0x3583: 0x000a, 0x3584: 0x000a, 0x3585: 0x000a, + 0x3586: 0x000a, 0x3587: 0x000a, + 0x3590: 0x000a, 0x3591: 0x000a, + 0x3592: 0x000a, 0x3593: 0x000a, 0x3594: 0x000a, 0x3595: 0x000a, 0x3596: 0x000a, 0x3597: 0x000a, + 0x3598: 0x000a, 0x3599: 0x000a, + 0x35a0: 0x000a, 0x35a1: 0x000a, 0x35a2: 0x000a, 0x35a3: 0x000a, + 0x35a4: 0x000a, 0x35a5: 0x000a, 0x35a6: 0x000a, 0x35a7: 0x000a, 0x35a8: 0x000a, 0x35a9: 0x000a, + 0x35aa: 0x000a, 0x35ab: 0x000a, 0x35ac: 0x000a, 0x35ad: 0x000a, 0x35ae: 0x000a, 0x35af: 0x000a, + 0x35b0: 0x000a, 0x35b1: 0x000a, 0x35b2: 0x000a, 0x35b3: 0x000a, 0x35b4: 0x000a, 0x35b5: 0x000a, + 0x35b6: 0x000a, 0x35b7: 0x000a, 0x35b8: 0x000a, 0x35b9: 0x000a, 0x35ba: 0x000a, 0x35bb: 0x000a, + 0x35bc: 0x000a, 0x35bd: 0x000a, 0x35be: 0x000a, 0x35bf: 0x000a, + // Block 0xd7, offset 0x35c0 + 0x35c0: 0x000a, 0x35c1: 0x000a, 0x35c2: 0x000a, 0x35c3: 0x000a, 0x35c4: 0x000a, 0x35c5: 0x000a, + 0x35c6: 0x000a, 0x35c7: 0x000a, + 0x35d0: 0x000a, 0x35d1: 0x000a, + 0x35d2: 0x000a, 0x35d3: 0x000a, 0x35d4: 0x000a, 0x35d5: 0x000a, 0x35d6: 0x000a, 0x35d7: 0x000a, + 0x35d8: 0x000a, 0x35d9: 0x000a, 0x35da: 0x000a, 0x35db: 0x000a, 0x35dc: 0x000a, 0x35dd: 0x000a, + 0x35de: 0x000a, 0x35df: 0x000a, 0x35e0: 0x000a, 0x35e1: 0x000a, 0x35e2: 0x000a, 0x35e3: 0x000a, + 0x35e4: 0x000a, 0x35e5: 0x000a, 0x35e6: 0x000a, 0x35e7: 0x000a, 0x35e8: 0x000a, 0x35e9: 0x000a, + 0x35ea: 0x000a, 0x35eb: 0x000a, 0x35ec: 0x000a, 0x35ed: 0x000a, + // Block 0xd8, offset 0x3600 + 0x3610: 0x000a, 0x3611: 0x000a, + 0x3612: 0x000a, 0x3613: 0x000a, 0x3614: 0x000a, 0x3615: 0x000a, 0x3616: 0x000a, 0x3617: 0x000a, + 0x3618: 0x000a, 0x3619: 0x000a, 0x361a: 0x000a, 0x361b: 0x000a, 0x361c: 0x000a, 0x361d: 0x000a, + 0x361e: 0x000a, 0x3620: 0x000a, 0x3621: 0x000a, 0x3622: 0x000a, 0x3623: 0x000a, + 0x3624: 0x000a, 0x3625: 0x000a, 0x3626: 0x000a, 0x3627: 0x000a, + 0x3630: 0x000a, 0x3633: 0x000a, 0x3634: 0x000a, 0x3635: 0x000a, + 0x3636: 0x000a, 0x3637: 0x000a, 0x3638: 0x000a, 0x3639: 0x000a, 0x363a: 0x000a, 0x363b: 0x000a, + 0x363c: 0x000a, 0x363d: 0x000a, 0x363e: 0x000a, + // Block 0xd9, offset 0x3640 + 0x3640: 0x000a, 0x3641: 0x000a, 0x3642: 0x000a, 0x3643: 0x000a, 0x3644: 0x000a, 0x3645: 0x000a, + 0x3646: 0x000a, 0x3647: 0x000a, 0x3648: 0x000a, 0x3649: 0x000a, 0x364a: 0x000a, 0x364b: 0x000a, + 0x3650: 0x000a, 0x3651: 0x000a, + 0x3652: 0x000a, 0x3653: 0x000a, 0x3654: 0x000a, 0x3655: 0x000a, 0x3656: 0x000a, 0x3657: 0x000a, + 0x3658: 0x000a, 0x3659: 0x000a, 0x365a: 0x000a, 0x365b: 0x000a, 0x365c: 0x000a, 0x365d: 0x000a, + 0x365e: 0x000a, + // Block 0xda, offset 0x3680 + 0x3680: 0x000a, 0x3681: 0x000a, 0x3682: 0x000a, 0x3683: 0x000a, 0x3684: 0x000a, 0x3685: 0x000a, + 0x3686: 0x000a, 0x3687: 0x000a, 0x3688: 0x000a, 0x3689: 0x000a, 0x368a: 0x000a, 0x368b: 0x000a, + 0x368c: 0x000a, 0x368d: 0x000a, 0x368e: 0x000a, 0x368f: 0x000a, 0x3690: 0x000a, 0x3691: 0x000a, + // Block 0xdb, offset 0x36c0 + 0x36fe: 0x000b, 0x36ff: 0x000b, + // Block 0xdc, offset 0x3700 + 0x3700: 0x000b, 0x3701: 0x000b, 0x3702: 0x000b, 0x3703: 0x000b, 0x3704: 0x000b, 0x3705: 0x000b, + 0x3706: 0x000b, 0x3707: 0x000b, 0x3708: 0x000b, 0x3709: 0x000b, 0x370a: 0x000b, 0x370b: 0x000b, + 0x370c: 0x000b, 0x370d: 0x000b, 0x370e: 0x000b, 0x370f: 0x000b, 0x3710: 0x000b, 0x3711: 0x000b, + 0x3712: 0x000b, 0x3713: 0x000b, 0x3714: 0x000b, 0x3715: 0x000b, 0x3716: 0x000b, 0x3717: 0x000b, + 0x3718: 0x000b, 0x3719: 0x000b, 0x371a: 0x000b, 0x371b: 0x000b, 0x371c: 0x000b, 0x371d: 0x000b, + 0x371e: 0x000b, 0x371f: 0x000b, 0x3720: 0x000b, 0x3721: 0x000b, 0x3722: 0x000b, 0x3723: 0x000b, + 0x3724: 0x000b, 0x3725: 0x000b, 0x3726: 0x000b, 0x3727: 0x000b, 0x3728: 0x000b, 0x3729: 0x000b, + 0x372a: 0x000b, 0x372b: 0x000b, 0x372c: 0x000b, 0x372d: 0x000b, 0x372e: 0x000b, 0x372f: 0x000b, + 0x3730: 0x000b, 0x3731: 0x000b, 0x3732: 0x000b, 0x3733: 0x000b, 0x3734: 0x000b, 0x3735: 0x000b, + 0x3736: 0x000b, 0x3737: 0x000b, 0x3738: 0x000b, 0x3739: 0x000b, 0x373a: 0x000b, 0x373b: 0x000b, + 0x373c: 0x000b, 0x373d: 0x000b, 0x373e: 0x000b, 0x373f: 0x000b, + // Block 0xdd, offset 0x3740 + 0x3740: 0x000c, 0x3741: 0x000c, 0x3742: 0x000c, 0x3743: 0x000c, 0x3744: 0x000c, 0x3745: 0x000c, + 0x3746: 0x000c, 0x3747: 0x000c, 0x3748: 0x000c, 0x3749: 0x000c, 0x374a: 0x000c, 0x374b: 0x000c, + 0x374c: 0x000c, 0x374d: 0x000c, 0x374e: 0x000c, 0x374f: 0x000c, 0x3750: 0x000c, 0x3751: 0x000c, + 0x3752: 0x000c, 0x3753: 0x000c, 0x3754: 0x000c, 0x3755: 0x000c, 0x3756: 0x000c, 0x3757: 0x000c, + 0x3758: 0x000c, 0x3759: 0x000c, 0x375a: 0x000c, 0x375b: 0x000c, 0x375c: 0x000c, 0x375d: 0x000c, + 0x375e: 0x000c, 0x375f: 0x000c, 0x3760: 0x000c, 0x3761: 0x000c, 0x3762: 0x000c, 0x3763: 0x000c, + 0x3764: 0x000c, 0x3765: 0x000c, 0x3766: 0x000c, 0x3767: 0x000c, 0x3768: 0x000c, 0x3769: 0x000c, + 0x376a: 0x000c, 0x376b: 0x000c, 0x376c: 0x000c, 0x376d: 0x000c, 0x376e: 0x000c, 0x376f: 0x000c, + 0x3770: 0x000b, 0x3771: 0x000b, 0x3772: 0x000b, 0x3773: 0x000b, 0x3774: 0x000b, 0x3775: 0x000b, + 0x3776: 0x000b, 0x3777: 0x000b, 0x3778: 0x000b, 0x3779: 0x000b, 0x377a: 0x000b, 0x377b: 0x000b, + 0x377c: 0x000b, 0x377d: 0x000b, 0x377e: 0x000b, 0x377f: 0x000b, +} + +// bidiIndex: 24 blocks, 1536 entries, 1536 bytes +// Block 0 is the zero block. +var bidiIndex = [1536]uint8{ + // Block 0x0, offset 0x0 + // Block 0x1, offset 0x40 + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0xc2: 0x01, 0xc3: 0x02, + 0xca: 0x03, 0xcb: 0x04, 0xcc: 0x05, 0xcd: 0x06, 0xce: 0x07, 0xcf: 0x08, + 0xd2: 0x09, 0xd6: 0x0a, 0xd7: 0x0b, + 0xd8: 0x0c, 0xd9: 0x0d, 0xda: 0x0e, 0xdb: 0x0f, 0xdc: 0x10, 0xdd: 0x11, 0xde: 0x12, 0xdf: 0x13, + 0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05, 0xe4: 0x06, + 0xea: 0x07, 0xef: 0x08, + 0xf0: 0x11, 0xf1: 0x12, 0xf2: 0x12, 0xf3: 0x14, 0xf4: 0x15, + // Block 0x4, offset 0x100 + 0x120: 0x14, 0x121: 0x15, 0x122: 0x16, 0x123: 0x17, 0x124: 0x18, 0x125: 0x19, 0x126: 0x1a, 0x127: 0x1b, + 0x128: 0x1c, 0x129: 0x1d, 0x12a: 0x1c, 0x12b: 0x1e, 0x12c: 0x1f, 0x12d: 0x20, 0x12e: 0x21, 0x12f: 0x22, + 0x130: 0x23, 0x131: 0x24, 0x132: 0x1a, 0x133: 0x25, 0x134: 0x26, 0x135: 0x27, 0x137: 0x28, + 0x138: 0x29, 0x139: 0x2a, 0x13a: 0x2b, 0x13b: 0x2c, 0x13c: 0x2d, 0x13d: 0x2e, 0x13e: 0x2f, 0x13f: 0x30, + // Block 0x5, offset 0x140 + 0x140: 0x31, 0x141: 0x32, 0x142: 0x33, + 0x14d: 0x34, 0x14e: 0x35, + 0x150: 0x36, + 0x15a: 0x37, 0x15c: 0x38, 0x15d: 0x39, 0x15e: 0x3a, 0x15f: 0x3b, + 0x160: 0x3c, 0x162: 0x3d, 0x164: 0x3e, 0x165: 0x3f, 0x167: 0x40, + 0x168: 0x41, 0x169: 0x42, 0x16a: 0x43, 0x16c: 0x44, 0x16d: 0x45, 0x16e: 0x46, 0x16f: 0x47, + 0x170: 0x48, 0x173: 0x49, 0x177: 0x4a, + 0x17e: 0x4b, 0x17f: 0x4c, + // Block 0x6, offset 0x180 + 0x180: 0x4d, 0x181: 0x4e, 0x182: 0x4f, 0x183: 0x50, 0x184: 0x51, 0x185: 0x52, 0x186: 0x53, 0x187: 0x54, + 0x188: 0x55, 0x189: 0x54, 0x18a: 0x54, 0x18b: 0x54, 0x18c: 0x56, 0x18d: 0x57, 0x18e: 0x58, 0x18f: 0x59, + 0x190: 0x5a, 0x191: 0x5b, 0x192: 0x5c, 0x193: 0x5d, 0x194: 0x54, 0x195: 0x54, 0x196: 0x54, 0x197: 0x54, + 0x198: 0x54, 0x199: 0x54, 0x19a: 0x5e, 0x19b: 0x54, 0x19c: 0x54, 0x19d: 0x5f, 0x19e: 0x54, 0x19f: 0x60, + 0x1a4: 0x54, 0x1a5: 0x54, 0x1a6: 0x61, 0x1a7: 0x62, + 0x1a8: 0x54, 0x1a9: 0x54, 0x1aa: 0x54, 0x1ab: 0x54, 0x1ac: 0x54, 0x1ad: 0x63, 0x1ae: 0x64, 0x1af: 0x65, + 0x1b3: 0x66, 0x1b5: 0x67, 0x1b7: 0x68, + 0x1b8: 0x69, 0x1b9: 0x6a, 0x1ba: 0x6b, 0x1bb: 0x6c, 0x1bc: 0x54, 0x1bd: 0x54, 0x1be: 0x54, 0x1bf: 0x6d, + // Block 0x7, offset 0x1c0 + 0x1c0: 0x6e, 0x1c2: 0x6f, 0x1c3: 0x70, 0x1c7: 0x71, + 0x1c8: 0x72, 0x1c9: 0x73, 0x1ca: 0x74, 0x1cb: 0x75, 0x1cd: 0x76, 0x1cf: 0x77, + // Block 0x8, offset 0x200 + 0x237: 0x54, + // Block 0x9, offset 0x240 + 0x252: 0x78, 0x253: 0x79, + 0x258: 0x7a, 0x259: 0x7b, 0x25a: 0x7c, 0x25b: 0x7d, 0x25c: 0x7e, 0x25e: 0x7f, + 0x260: 0x80, 0x261: 0x81, 0x263: 0x82, 0x264: 0x83, 0x265: 0x84, 0x266: 0x85, 0x267: 0x86, + 0x268: 0x87, 0x269: 0x88, 0x26a: 0x89, 0x26b: 0x8a, 0x26f: 0x8b, + // Block 0xa, offset 0x280 + 0x2ac: 0x8c, 0x2ad: 0x8d, 0x2ae: 0x0e, 0x2af: 0x0e, + 0x2b0: 0x0e, 0x2b1: 0x0e, 0x2b2: 0x0e, 0x2b3: 0x0e, 0x2b4: 0x8e, 0x2b5: 0x0e, 0x2b6: 0x0e, 0x2b7: 0x8f, + 0x2b8: 0x90, 0x2b9: 0x91, 0x2ba: 0x0e, 0x2bb: 0x92, 0x2bc: 0x93, 0x2bd: 0x94, 0x2bf: 0x95, + // Block 0xb, offset 0x2c0 + 0x2c4: 0x96, 0x2c5: 0x54, 0x2c6: 0x97, 0x2c7: 0x98, + 0x2cb: 0x99, 0x2cd: 0x9a, + 0x2e0: 0x9b, 0x2e1: 0x9b, 0x2e2: 0x9b, 0x2e3: 0x9b, 0x2e4: 0x9c, 0x2e5: 0x9b, 0x2e6: 0x9b, 0x2e7: 0x9b, + 0x2e8: 0x9d, 0x2e9: 0x9b, 0x2ea: 0x9b, 0x2eb: 0x9e, 0x2ec: 0x9f, 0x2ed: 0x9b, 0x2ee: 0x9b, 0x2ef: 0x9b, + 0x2f0: 0x9b, 0x2f1: 0x9b, 0x2f2: 0x9b, 0x2f3: 0x9b, 0x2f4: 0x9b, 0x2f5: 0x9b, 0x2f6: 0x9b, 0x2f7: 0x9b, + 0x2f8: 0x9b, 0x2f9: 0xa0, 0x2fa: 0x9b, 0x2fb: 0x9b, 0x2fc: 0x9b, 0x2fd: 0x9b, 0x2fe: 0x9b, 0x2ff: 0x9b, + // Block 0xc, offset 0x300 + 0x300: 0xa1, 0x301: 0xa2, 0x302: 0xa3, 0x304: 0xa4, 0x305: 0xa5, 0x306: 0xa6, 0x307: 0xa7, + 0x308: 0xa8, 0x30b: 0xa9, 0x30c: 0xaa, 0x30d: 0xab, + 0x310: 0xac, 0x311: 0xad, 0x312: 0xae, 0x313: 0xaf, 0x316: 0xb0, 0x317: 0xb1, + 0x318: 0xb2, 0x319: 0xb3, 0x31a: 0xb4, 0x31c: 0xb5, + 0x330: 0xb6, 0x332: 0xb7, + // Block 0xd, offset 0x340 + 0x36b: 0xb8, 0x36c: 0xb9, + 0x37e: 0xba, + // Block 0xe, offset 0x380 + 0x3b2: 0xbb, + // Block 0xf, offset 0x3c0 + 0x3c5: 0xbc, 0x3c6: 0xbd, + 0x3c8: 0x54, 0x3c9: 0xbe, 0x3cc: 0x54, 0x3cd: 0xbf, + 0x3db: 0xc0, 0x3dc: 0xc1, 0x3dd: 0xc2, 0x3de: 0xc3, 0x3df: 0xc4, + 0x3e8: 0xc5, 0x3e9: 0xc6, 0x3ea: 0xc7, + // Block 0x10, offset 0x400 + 0x400: 0xc8, + 0x420: 0x9b, 0x421: 0x9b, 0x422: 0x9b, 0x423: 0xc9, 0x424: 0x9b, 0x425: 0xca, 0x426: 0x9b, 0x427: 0x9b, + 0x428: 0x9b, 0x429: 0x9b, 0x42a: 0x9b, 0x42b: 0x9b, 0x42c: 0x9b, 0x42d: 0x9b, 0x42e: 0x9b, 0x42f: 0x9b, + 0x430: 0x9b, 0x431: 0x9b, 0x432: 0x9b, 0x433: 0x9b, 0x434: 0x9b, 0x435: 0x9b, 0x436: 0x9b, 0x437: 0x9b, + 0x438: 0x0e, 0x439: 0x0e, 0x43a: 0x0e, 0x43b: 0xcb, 0x43c: 0x9b, 0x43d: 0x9b, 0x43e: 0x9b, 0x43f: 0x9b, + // Block 0x11, offset 0x440 + 0x440: 0xcc, 0x441: 0x54, 0x442: 0xcd, 0x443: 0xce, 0x444: 0xcf, 0x445: 0xd0, + 0x44c: 0x54, 0x44d: 0x54, 0x44e: 0x54, 0x44f: 0x54, + 0x450: 0x54, 0x451: 0x54, 0x452: 0x54, 0x453: 0x54, 0x454: 0x54, 0x455: 0x54, 0x456: 0x54, 0x457: 0x54, + 0x458: 0x54, 0x459: 0x54, 0x45a: 0x54, 0x45b: 0xd1, 0x45c: 0x54, 0x45d: 0x6c, 0x45e: 0x54, 0x45f: 0xd2, + 0x460: 0xd3, 0x461: 0xd4, 0x462: 0xd5, 0x464: 0xd6, 0x465: 0xd7, 0x466: 0xd8, 0x467: 0x36, + 0x47f: 0xd9, + // Block 0x12, offset 0x480 + 0x4bf: 0xd9, + // Block 0x13, offset 0x4c0 + 0x4d0: 0x09, 0x4d1: 0x0a, 0x4d6: 0x0b, + 0x4db: 0x0c, 0x4dd: 0x0d, 0x4de: 0x0e, 0x4df: 0x0f, + 0x4ef: 0x10, + 0x4ff: 0x10, + // Block 0x14, offset 0x500 + 0x50f: 0x10, + 0x51f: 0x10, + 0x52f: 0x10, + 0x53f: 0x10, + // Block 0x15, offset 0x540 + 0x540: 0xda, 0x541: 0xda, 0x542: 0xda, 0x543: 0xda, 0x544: 0x05, 0x545: 0x05, 0x546: 0x05, 0x547: 0xdb, + 0x548: 0xda, 0x549: 0xda, 0x54a: 0xda, 0x54b: 0xda, 0x54c: 0xda, 0x54d: 0xda, 0x54e: 0xda, 0x54f: 0xda, + 0x550: 0xda, 0x551: 0xda, 0x552: 0xda, 0x553: 0xda, 0x554: 0xda, 0x555: 0xda, 0x556: 0xda, 0x557: 0xda, + 0x558: 0xda, 0x559: 0xda, 0x55a: 0xda, 0x55b: 0xda, 0x55c: 0xda, 0x55d: 0xda, 0x55e: 0xda, 0x55f: 0xda, + 0x560: 0xda, 0x561: 0xda, 0x562: 0xda, 0x563: 0xda, 0x564: 0xda, 0x565: 0xda, 0x566: 0xda, 0x567: 0xda, + 0x568: 0xda, 0x569: 0xda, 0x56a: 0xda, 0x56b: 0xda, 0x56c: 0xda, 0x56d: 0xda, 0x56e: 0xda, 0x56f: 0xda, + 0x570: 0xda, 0x571: 0xda, 0x572: 0xda, 0x573: 0xda, 0x574: 0xda, 0x575: 0xda, 0x576: 0xda, 0x577: 0xda, + 0x578: 0xda, 0x579: 0xda, 0x57a: 0xda, 0x57b: 0xda, 0x57c: 0xda, 0x57d: 0xda, 0x57e: 0xda, 0x57f: 0xda, + // Block 0x16, offset 0x580 + 0x58f: 0x10, + 0x59f: 0x10, + 0x5a0: 0x13, + 0x5af: 0x10, + 0x5bf: 0x10, + // Block 0x17, offset 0x5c0 + 0x5cf: 0x10, +} + +// Total table size 15800 bytes (15KiB); checksum: F50EF68C diff --git a/vendor/golang.org/x/text/unicode/bidi/trieval.go b/vendor/golang.org/x/text/unicode/bidi/trieval.go new file mode 100644 index 0000000000..4c459c4b72 --- /dev/null +++ b/vendor/golang.org/x/text/unicode/bidi/trieval.go @@ -0,0 +1,60 @@ +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. + +package bidi + +// Class is the Unicode BiDi class. Each rune has a single class. +type Class uint + +const ( + L Class = iota // LeftToRight + R // RightToLeft + EN // EuropeanNumber + ES // EuropeanSeparator + ET // EuropeanTerminator + AN // ArabicNumber + CS // CommonSeparator + B // ParagraphSeparator + S // SegmentSeparator + WS // WhiteSpace + ON // OtherNeutral + BN // BoundaryNeutral + NSM // NonspacingMark + AL // ArabicLetter + Control // Control LRO - PDI + + numClass + + LRO // LeftToRightOverride + RLO // RightToLeftOverride + LRE // LeftToRightEmbedding + RLE // RightToLeftEmbedding + PDF // PopDirectionalFormat + LRI // LeftToRightIsolate + RLI // RightToLeftIsolate + FSI // FirstStrongIsolate + PDI // PopDirectionalIsolate + + unknownClass = ^Class(0) +) + +var controlToClass = map[rune]Class{ + 0x202D: LRO, // LeftToRightOverride, + 0x202E: RLO, // RightToLeftOverride, + 0x202A: LRE, // LeftToRightEmbedding, + 0x202B: RLE, // RightToLeftEmbedding, + 0x202C: PDF, // PopDirectionalFormat, + 0x2066: LRI, // LeftToRightIsolate, + 0x2067: RLI, // RightToLeftIsolate, + 0x2068: FSI, // FirstStrongIsolate, + 0x2069: PDI, // PopDirectionalIsolate, +} + +// A trie entry has the following bits: +// 7..5 XOR mask for brackets +// 4 1: Bracket open, 0: Bracket close +// 3..0 Class type + +const ( + openMask = 0x10 + xorMaskShift = 5 +) diff --git a/vendor/golang.org/x/text/unicode/norm/composition.go b/vendor/golang.org/x/text/unicode/norm/composition.go new file mode 100644 index 0000000000..bab4c5de02 --- /dev/null +++ b/vendor/golang.org/x/text/unicode/norm/composition.go @@ -0,0 +1,508 @@ +// Copyright 2011 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 norm + +import "unicode/utf8" + +const ( + maxNonStarters = 30 + // The maximum number of characters needed for a buffer is + // maxNonStarters + 1 for the starter + 1 for the GCJ + maxBufferSize = maxNonStarters + 2 + maxNFCExpansion = 3 // NFC(0x1D160) + maxNFKCExpansion = 18 // NFKC(0xFDFA) + + maxByteBufferSize = utf8.UTFMax * maxBufferSize // 128 +) + +// ssState is used for reporting the segment state after inserting a rune. +// It is returned by streamSafe.next. +type ssState int + +const ( + // Indicates a rune was successfully added to the segment. + ssSuccess ssState = iota + // Indicates a rune starts a new segment and should not be added. + ssStarter + // Indicates a rune caused a segment overflow and a CGJ should be inserted. + ssOverflow +) + +// streamSafe implements the policy of when a CGJ should be inserted. +type streamSafe uint8 + +// first inserts the first rune of a segment. It is a faster version of next if +// it is known p represents the first rune in a segment. +func (ss *streamSafe) first(p Properties) { + *ss = streamSafe(p.nTrailingNonStarters()) +} + +// insert returns a ssState value to indicate whether a rune represented by p +// can be inserted. +func (ss *streamSafe) next(p Properties) ssState { + if *ss > maxNonStarters { + panic("streamSafe was not reset") + } + n := p.nLeadingNonStarters() + if *ss += streamSafe(n); *ss > maxNonStarters { + *ss = 0 + return ssOverflow + } + // The Stream-Safe Text Processing prescribes that the counting can stop + // as soon as a starter is encountered. However, there are some starters, + // like Jamo V and T, that can combine with other runes, leaving their + // successive non-starters appended to the previous, possibly causing an + // overflow. We will therefore consider any rune with a non-zero nLead to + // be a non-starter. Note that it always hold that if nLead > 0 then + // nLead == nTrail. + if n == 0 { + *ss = streamSafe(p.nTrailingNonStarters()) + return ssStarter + } + return ssSuccess +} + +// backwards is used for checking for overflow and segment starts +// when traversing a string backwards. Users do not need to call first +// for the first rune. The state of the streamSafe retains the count of +// the non-starters loaded. +func (ss *streamSafe) backwards(p Properties) ssState { + if *ss > maxNonStarters { + panic("streamSafe was not reset") + } + c := *ss + streamSafe(p.nTrailingNonStarters()) + if c > maxNonStarters { + return ssOverflow + } + *ss = c + if p.nLeadingNonStarters() == 0 { + return ssStarter + } + return ssSuccess +} + +func (ss streamSafe) isMax() bool { + return ss == maxNonStarters +} + +// GraphemeJoiner is inserted after maxNonStarters non-starter runes. +const GraphemeJoiner = "\u034F" + +// reorderBuffer is used to normalize a single segment. Characters inserted with +// insert are decomposed and reordered based on CCC. The compose method can +// be used to recombine characters. Note that the byte buffer does not hold +// the UTF-8 characters in order. Only the rune array is maintained in sorted +// order. flush writes the resulting segment to a byte array. +type reorderBuffer struct { + rune [maxBufferSize]Properties // Per character info. + byte [maxByteBufferSize]byte // UTF-8 buffer. Referenced by runeInfo.pos. + nbyte uint8 // Number or bytes. + ss streamSafe // For limiting length of non-starter sequence. + nrune int // Number of runeInfos. + f formInfo + + src input + nsrc int + tmpBytes input + + out []byte + flushF func(*reorderBuffer) bool +} + +func (rb *reorderBuffer) init(f Form, src []byte) { + rb.f = *formTable[f] + rb.src.setBytes(src) + rb.nsrc = len(src) + rb.ss = 0 +} + +func (rb *reorderBuffer) initString(f Form, src string) { + rb.f = *formTable[f] + rb.src.setString(src) + rb.nsrc = len(src) + rb.ss = 0 +} + +func (rb *reorderBuffer) setFlusher(out []byte, f func(*reorderBuffer) bool) { + rb.out = out + rb.flushF = f +} + +// reset discards all characters from the buffer. +func (rb *reorderBuffer) reset() { + rb.nrune = 0 + rb.nbyte = 0 +} + +func (rb *reorderBuffer) doFlush() bool { + if rb.f.composing { + rb.compose() + } + res := rb.flushF(rb) + rb.reset() + return res +} + +// appendFlush appends the normalized segment to rb.out. +func appendFlush(rb *reorderBuffer) bool { + for i := 0; i < rb.nrune; i++ { + start := rb.rune[i].pos + end := start + rb.rune[i].size + rb.out = append(rb.out, rb.byte[start:end]...) + } + return true +} + +// flush appends the normalized segment to out and resets rb. +func (rb *reorderBuffer) flush(out []byte) []byte { + for i := 0; i < rb.nrune; i++ { + start := rb.rune[i].pos + end := start + rb.rune[i].size + out = append(out, rb.byte[start:end]...) + } + rb.reset() + return out +} + +// flushCopy copies the normalized segment to buf and resets rb. +// It returns the number of bytes written to buf. +func (rb *reorderBuffer) flushCopy(buf []byte) int { + p := 0 + for i := 0; i < rb.nrune; i++ { + runep := rb.rune[i] + p += copy(buf[p:], rb.byte[runep.pos:runep.pos+runep.size]) + } + rb.reset() + return p +} + +// insertOrdered inserts a rune in the buffer, ordered by Canonical Combining Class. +// It returns false if the buffer is not large enough to hold the rune. +// It is used internally by insert and insertString only. +func (rb *reorderBuffer) insertOrdered(info Properties) { + n := rb.nrune + b := rb.rune[:] + cc := info.ccc + if cc > 0 { + // Find insertion position + move elements to make room. + for ; n > 0; n-- { + if b[n-1].ccc <= cc { + break + } + b[n] = b[n-1] + } + } + rb.nrune += 1 + pos := uint8(rb.nbyte) + rb.nbyte += utf8.UTFMax + info.pos = pos + b[n] = info +} + +// insertErr is an error code returned by insert. Using this type instead +// of error improves performance up to 20% for many of the benchmarks. +type insertErr int + +const ( + iSuccess insertErr = -iota + iShortDst + iShortSrc +) + +// insertFlush inserts the given rune in the buffer ordered by CCC. +// If a decomposition with multiple segments are encountered, they leading +// ones are flushed. +// It returns a non-zero error code if the rune was not inserted. +func (rb *reorderBuffer) insertFlush(src input, i int, info Properties) insertErr { + if rune := src.hangul(i); rune != 0 { + rb.decomposeHangul(rune) + return iSuccess + } + if info.hasDecomposition() { + return rb.insertDecomposed(info.Decomposition()) + } + rb.insertSingle(src, i, info) + return iSuccess +} + +// insertUnsafe inserts the given rune in the buffer ordered by CCC. +// It is assumed there is sufficient space to hold the runes. It is the +// responsibility of the caller to ensure this. This can be done by checking +// the state returned by the streamSafe type. +func (rb *reorderBuffer) insertUnsafe(src input, i int, info Properties) { + if rune := src.hangul(i); rune != 0 { + rb.decomposeHangul(rune) + } + if info.hasDecomposition() { + // TODO: inline. + rb.insertDecomposed(info.Decomposition()) + } else { + rb.insertSingle(src, i, info) + } +} + +// insertDecomposed inserts an entry in to the reorderBuffer for each rune +// in dcomp. dcomp must be a sequence of decomposed UTF-8-encoded runes. +// It flushes the buffer on each new segment start. +func (rb *reorderBuffer) insertDecomposed(dcomp []byte) insertErr { + rb.tmpBytes.setBytes(dcomp) + // As the streamSafe accounting already handles the counting for modifiers, + // we don't have to call next. However, we do need to keep the accounting + // intact when flushing the buffer. + for i := 0; i < len(dcomp); { + info := rb.f.info(rb.tmpBytes, i) + if info.BoundaryBefore() && rb.nrune > 0 && !rb.doFlush() { + return iShortDst + } + i += copy(rb.byte[rb.nbyte:], dcomp[i:i+int(info.size)]) + rb.insertOrdered(info) + } + return iSuccess +} + +// insertSingle inserts an entry in the reorderBuffer for the rune at +// position i. info is the runeInfo for the rune at position i. +func (rb *reorderBuffer) insertSingle(src input, i int, info Properties) { + src.copySlice(rb.byte[rb.nbyte:], i, i+int(info.size)) + rb.insertOrdered(info) +} + +// insertCGJ inserts a Combining Grapheme Joiner (0x034f) into rb. +func (rb *reorderBuffer) insertCGJ() { + rb.insertSingle(input{str: GraphemeJoiner}, 0, Properties{size: uint8(len(GraphemeJoiner))}) +} + +// appendRune inserts a rune at the end of the buffer. It is used for Hangul. +func (rb *reorderBuffer) appendRune(r rune) { + bn := rb.nbyte + sz := utf8.EncodeRune(rb.byte[bn:], rune(r)) + rb.nbyte += utf8.UTFMax + rb.rune[rb.nrune] = Properties{pos: bn, size: uint8(sz)} + rb.nrune++ +} + +// assignRune sets a rune at position pos. It is used for Hangul and recomposition. +func (rb *reorderBuffer) assignRune(pos int, r rune) { + bn := rb.rune[pos].pos + sz := utf8.EncodeRune(rb.byte[bn:], rune(r)) + rb.rune[pos] = Properties{pos: bn, size: uint8(sz)} +} + +// runeAt returns the rune at position n. It is used for Hangul and recomposition. +func (rb *reorderBuffer) runeAt(n int) rune { + inf := rb.rune[n] + r, _ := utf8.DecodeRune(rb.byte[inf.pos : inf.pos+inf.size]) + return r +} + +// bytesAt returns the UTF-8 encoding of the rune at position n. +// It is used for Hangul and recomposition. +func (rb *reorderBuffer) bytesAt(n int) []byte { + inf := rb.rune[n] + return rb.byte[inf.pos : int(inf.pos)+int(inf.size)] +} + +// For Hangul we combine algorithmically, instead of using tables. +const ( + hangulBase = 0xAC00 // UTF-8(hangulBase) -> EA B0 80 + hangulBase0 = 0xEA + hangulBase1 = 0xB0 + hangulBase2 = 0x80 + + hangulEnd = hangulBase + jamoLVTCount // UTF-8(0xD7A4) -> ED 9E A4 + hangulEnd0 = 0xED + hangulEnd1 = 0x9E + hangulEnd2 = 0xA4 + + jamoLBase = 0x1100 // UTF-8(jamoLBase) -> E1 84 00 + jamoLBase0 = 0xE1 + jamoLBase1 = 0x84 + jamoLEnd = 0x1113 + jamoVBase = 0x1161 + jamoVEnd = 0x1176 + jamoTBase = 0x11A7 + jamoTEnd = 0x11C3 + + jamoTCount = 28 + jamoVCount = 21 + jamoVTCount = 21 * 28 + jamoLVTCount = 19 * 21 * 28 +) + +const hangulUTF8Size = 3 + +func isHangul(b []byte) bool { + if len(b) < hangulUTF8Size { + return false + } + b0 := b[0] + if b0 < hangulBase0 { + return false + } + b1 := b[1] + switch { + case b0 == hangulBase0: + return b1 >= hangulBase1 + case b0 < hangulEnd0: + return true + case b0 > hangulEnd0: + return false + case b1 < hangulEnd1: + return true + } + return b1 == hangulEnd1 && b[2] < hangulEnd2 +} + +func isHangulString(b string) bool { + if len(b) < hangulUTF8Size { + return false + } + b0 := b[0] + if b0 < hangulBase0 { + return false + } + b1 := b[1] + switch { + case b0 == hangulBase0: + return b1 >= hangulBase1 + case b0 < hangulEnd0: + return true + case b0 > hangulEnd0: + return false + case b1 < hangulEnd1: + return true + } + return b1 == hangulEnd1 && b[2] < hangulEnd2 +} + +// Caller must ensure len(b) >= 2. +func isJamoVT(b []byte) bool { + // True if (rune & 0xff00) == jamoLBase + return b[0] == jamoLBase0 && (b[1]&0xFC) == jamoLBase1 +} + +func isHangulWithoutJamoT(b []byte) bool { + c, _ := utf8.DecodeRune(b) + c -= hangulBase + return c < jamoLVTCount && c%jamoTCount == 0 +} + +// decomposeHangul writes the decomposed Hangul to buf and returns the number +// of bytes written. len(buf) should be at least 9. +func decomposeHangul(buf []byte, r rune) int { + const JamoUTF8Len = 3 + r -= hangulBase + x := r % jamoTCount + r /= jamoTCount + utf8.EncodeRune(buf, jamoLBase+r/jamoVCount) + utf8.EncodeRune(buf[JamoUTF8Len:], jamoVBase+r%jamoVCount) + if x != 0 { + utf8.EncodeRune(buf[2*JamoUTF8Len:], jamoTBase+x) + return 3 * JamoUTF8Len + } + return 2 * JamoUTF8Len +} + +// decomposeHangul algorithmically decomposes a Hangul rune into +// its Jamo components. +// See http://unicode.org/reports/tr15/#Hangul for details on decomposing Hangul. +func (rb *reorderBuffer) decomposeHangul(r rune) { + r -= hangulBase + x := r % jamoTCount + r /= jamoTCount + rb.appendRune(jamoLBase + r/jamoVCount) + rb.appendRune(jamoVBase + r%jamoVCount) + if x != 0 { + rb.appendRune(jamoTBase + x) + } +} + +// combineHangul algorithmically combines Jamo character components into Hangul. +// See http://unicode.org/reports/tr15/#Hangul for details on combining Hangul. +func (rb *reorderBuffer) combineHangul(s, i, k int) { + b := rb.rune[:] + bn := rb.nrune + for ; i < bn; i++ { + cccB := b[k-1].ccc + cccC := b[i].ccc + if cccB == 0 { + s = k - 1 + } + if s != k-1 && cccB >= cccC { + // b[i] is blocked by greater-equal cccX below it + b[k] = b[i] + k++ + } else { + l := rb.runeAt(s) // also used to compare to hangulBase + v := rb.runeAt(i) // also used to compare to jamoT + switch { + case jamoLBase <= l && l < jamoLEnd && + jamoVBase <= v && v < jamoVEnd: + // 11xx plus 116x to LV + rb.assignRune(s, hangulBase+ + (l-jamoLBase)*jamoVTCount+(v-jamoVBase)*jamoTCount) + case hangulBase <= l && l < hangulEnd && + jamoTBase < v && v < jamoTEnd && + ((l-hangulBase)%jamoTCount) == 0: + // ACxx plus 11Ax to LVT + rb.assignRune(s, l+v-jamoTBase) + default: + b[k] = b[i] + k++ + } + } + } + rb.nrune = k +} + +// compose recombines the runes in the buffer. +// It should only be used to recompose a single segment, as it will not +// handle alternations between Hangul and non-Hangul characters correctly. +func (rb *reorderBuffer) compose() { + // UAX #15, section X5 , including Corrigendum #5 + // "In any character sequence beginning with starter S, a character C is + // blocked from S if and only if there is some character B between S + // and C, and either B is a starter or it has the same or higher + // combining class as C." + bn := rb.nrune + if bn == 0 { + return + } + k := 1 + b := rb.rune[:] + for s, i := 0, 1; i < bn; i++ { + if isJamoVT(rb.bytesAt(i)) { + // Redo from start in Hangul mode. Necessary to support + // U+320E..U+321E in NFKC mode. + rb.combineHangul(s, i, k) + return + } + ii := b[i] + // We can only use combineForward as a filter if we later + // get the info for the combined character. This is more + // expensive than using the filter. Using combinesBackward() + // is safe. + if ii.combinesBackward() { + cccB := b[k-1].ccc + cccC := ii.ccc + blocked := false // b[i] blocked by starter or greater or equal CCC? + if cccB == 0 { + s = k - 1 + } else { + blocked = s != k-1 && cccB >= cccC + } + if !blocked { + combined := combine(rb.runeAt(s), rb.runeAt(i)) + if combined != 0 { + rb.assignRune(s, combined) + continue + } + } + } + b[k] = b[i] + k++ + } + rb.nrune = k +} diff --git a/vendor/golang.org/x/text/unicode/norm/forminfo.go b/vendor/golang.org/x/text/unicode/norm/forminfo.go new file mode 100644 index 0000000000..e67e7655c5 --- /dev/null +++ b/vendor/golang.org/x/text/unicode/norm/forminfo.go @@ -0,0 +1,259 @@ +// Copyright 2011 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 norm + +// This file contains Form-specific logic and wrappers for data in tables.go. + +// Rune info is stored in a separate trie per composing form. A composing form +// and its corresponding decomposing form share the same trie. Each trie maps +// a rune to a uint16. The values take two forms. For v >= 0x8000: +// bits +// 15: 1 (inverse of NFD_QC bit of qcInfo) +// 13..7: qcInfo (see below). isYesD is always true (no decompostion). +// 6..0: ccc (compressed CCC value). +// For v < 0x8000, the respective rune has a decomposition and v is an index +// into a byte array of UTF-8 decomposition sequences and additional info and +// has the form: +//
* [ []] +// The header contains the number of bytes in the decomposition (excluding this +// length byte). The two most significant bits of this length byte correspond +// to bit 5 and 4 of qcInfo (see below). The byte sequence itself starts at v+1. +// The byte sequence is followed by a trailing and leading CCC if the values +// for these are not zero. The value of v determines which ccc are appended +// to the sequences. For v < firstCCC, there are none, for v >= firstCCC, +// the sequence is followed by a trailing ccc, and for v >= firstLeadingCC +// there is an additional leading ccc. The value of tccc itself is the +// trailing CCC shifted left 2 bits. The two least-significant bits of tccc +// are the number of trailing non-starters. + +const ( + qcInfoMask = 0x3F // to clear all but the relevant bits in a qcInfo + headerLenMask = 0x3F // extract the length value from the header byte + headerFlagsMask = 0xC0 // extract the qcInfo bits from the header byte +) + +// Properties provides access to normalization properties of a rune. +type Properties struct { + pos uint8 // start position in reorderBuffer; used in composition.go + size uint8 // length of UTF-8 encoding of this rune + ccc uint8 // leading canonical combining class (ccc if not decomposition) + tccc uint8 // trailing canonical combining class (ccc if not decomposition) + nLead uint8 // number of leading non-starters. + flags qcInfo // quick check flags + index uint16 +} + +// functions dispatchable per form +type lookupFunc func(b input, i int) Properties + +// formInfo holds Form-specific functions and tables. +type formInfo struct { + form Form + composing, compatibility bool // form type + info lookupFunc + nextMain iterFunc +} + +var formTable = []*formInfo{{ + form: NFC, + composing: true, + compatibility: false, + info: lookupInfoNFC, + nextMain: nextComposed, +}, { + form: NFD, + composing: false, + compatibility: false, + info: lookupInfoNFC, + nextMain: nextDecomposed, +}, { + form: NFKC, + composing: true, + compatibility: true, + info: lookupInfoNFKC, + nextMain: nextComposed, +}, { + form: NFKD, + composing: false, + compatibility: true, + info: lookupInfoNFKC, + nextMain: nextDecomposed, +}} + +// We do not distinguish between boundaries for NFC, NFD, etc. to avoid +// unexpected behavior for the user. For example, in NFD, there is a boundary +// after 'a'. However, 'a' might combine with modifiers, so from the application's +// perspective it is not a good boundary. We will therefore always use the +// boundaries for the combining variants. + +// BoundaryBefore returns true if this rune starts a new segment and +// cannot combine with any rune on the left. +func (p Properties) BoundaryBefore() bool { + if p.ccc == 0 && !p.combinesBackward() { + return true + } + // We assume that the CCC of the first character in a decomposition + // is always non-zero if different from info.ccc and that we can return + // false at this point. This is verified by maketables. + return false +} + +// BoundaryAfter returns true if runes cannot combine with or otherwise +// interact with this or previous runes. +func (p Properties) BoundaryAfter() bool { + // TODO: loosen these conditions. + return p.isInert() +} + +// We pack quick check data in 4 bits: +// 5: Combines forward (0 == false, 1 == true) +// 4..3: NFC_QC Yes(00), No (10), or Maybe (11) +// 2: NFD_QC Yes (0) or No (1). No also means there is a decomposition. +// 1..0: Number of trailing non-starters. +// +// When all 4 bits are zero, the character is inert, meaning it is never +// influenced by normalization. +type qcInfo uint8 + +func (p Properties) isYesC() bool { return p.flags&0x10 == 0 } +func (p Properties) isYesD() bool { return p.flags&0x4 == 0 } + +func (p Properties) combinesForward() bool { return p.flags&0x20 != 0 } +func (p Properties) combinesBackward() bool { return p.flags&0x8 != 0 } // == isMaybe +func (p Properties) hasDecomposition() bool { return p.flags&0x4 != 0 } // == isNoD + +func (p Properties) isInert() bool { + return p.flags&qcInfoMask == 0 && p.ccc == 0 +} + +func (p Properties) multiSegment() bool { + return p.index >= firstMulti && p.index < endMulti +} + +func (p Properties) nLeadingNonStarters() uint8 { + return p.nLead +} + +func (p Properties) nTrailingNonStarters() uint8 { + return uint8(p.flags & 0x03) +} + +// Decomposition returns the decomposition for the underlying rune +// or nil if there is none. +func (p Properties) Decomposition() []byte { + // TODO: create the decomposition for Hangul? + if p.index == 0 { + return nil + } + i := p.index + n := decomps[i] & headerLenMask + i++ + return decomps[i : i+uint16(n)] +} + +// Size returns the length of UTF-8 encoding of the rune. +func (p Properties) Size() int { + return int(p.size) +} + +// CCC returns the canonical combining class of the underlying rune. +func (p Properties) CCC() uint8 { + if p.index >= firstCCCZeroExcept { + return 0 + } + return ccc[p.ccc] +} + +// LeadCCC returns the CCC of the first rune in the decomposition. +// If there is no decomposition, LeadCCC equals CCC. +func (p Properties) LeadCCC() uint8 { + return ccc[p.ccc] +} + +// TrailCCC returns the CCC of the last rune in the decomposition. +// If there is no decomposition, TrailCCC equals CCC. +func (p Properties) TrailCCC() uint8 { + return ccc[p.tccc] +} + +// Recomposition +// We use 32-bit keys instead of 64-bit for the two codepoint keys. +// This clips off the bits of three entries, but we know this will not +// result in a collision. In the unlikely event that changes to +// UnicodeData.txt introduce collisions, the compiler will catch it. +// Note that the recomposition map for NFC and NFKC are identical. + +// combine returns the combined rune or 0 if it doesn't exist. +func combine(a, b rune) rune { + key := uint32(uint16(a))<<16 + uint32(uint16(b)) + return recompMap[key] +} + +func lookupInfoNFC(b input, i int) Properties { + v, sz := b.charinfoNFC(i) + return compInfo(v, sz) +} + +func lookupInfoNFKC(b input, i int) Properties { + v, sz := b.charinfoNFKC(i) + return compInfo(v, sz) +} + +// Properties returns properties for the first rune in s. +func (f Form) Properties(s []byte) Properties { + if f == NFC || f == NFD { + return compInfo(nfcData.lookup(s)) + } + return compInfo(nfkcData.lookup(s)) +} + +// PropertiesString returns properties for the first rune in s. +func (f Form) PropertiesString(s string) Properties { + if f == NFC || f == NFD { + return compInfo(nfcData.lookupString(s)) + } + return compInfo(nfkcData.lookupString(s)) +} + +// compInfo converts the information contained in v and sz +// to a Properties. See the comment at the top of the file +// for more information on the format. +func compInfo(v uint16, sz int) Properties { + if v == 0 { + return Properties{size: uint8(sz)} + } else if v >= 0x8000 { + p := Properties{ + size: uint8(sz), + ccc: uint8(v), + tccc: uint8(v), + flags: qcInfo(v >> 8), + } + if p.ccc > 0 || p.combinesBackward() { + p.nLead = uint8(p.flags & 0x3) + } + return p + } + // has decomposition + h := decomps[v] + f := (qcInfo(h&headerFlagsMask) >> 2) | 0x4 + p := Properties{size: uint8(sz), flags: f, index: v} + if v >= firstCCC { + v += uint16(h&headerLenMask) + 1 + c := decomps[v] + p.tccc = c >> 2 + p.flags |= qcInfo(c & 0x3) + if v >= firstLeadingCCC { + p.nLead = c & 0x3 + if v >= firstStarterWithNLead { + // We were tricked. Remove the decomposition. + p.flags &= 0x03 + p.index = 0 + return p + } + p.ccc = decomps[v+1] + } + } + return p +} diff --git a/vendor/golang.org/x/text/unicode/norm/input.go b/vendor/golang.org/x/text/unicode/norm/input.go new file mode 100644 index 0000000000..479e35bc25 --- /dev/null +++ b/vendor/golang.org/x/text/unicode/norm/input.go @@ -0,0 +1,109 @@ +// Copyright 2011 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 norm + +import "unicode/utf8" + +type input struct { + str string + bytes []byte +} + +func inputBytes(str []byte) input { + return input{bytes: str} +} + +func inputString(str string) input { + return input{str: str} +} + +func (in *input) setBytes(str []byte) { + in.str = "" + in.bytes = str +} + +func (in *input) setString(str string) { + in.str = str + in.bytes = nil +} + +func (in *input) _byte(p int) byte { + if in.bytes == nil { + return in.str[p] + } + return in.bytes[p] +} + +func (in *input) skipASCII(p, max int) int { + if in.bytes == nil { + for ; p < max && in.str[p] < utf8.RuneSelf; p++ { + } + } else { + for ; p < max && in.bytes[p] < utf8.RuneSelf; p++ { + } + } + return p +} + +func (in *input) skipContinuationBytes(p int) int { + if in.bytes == nil { + for ; p < len(in.str) && !utf8.RuneStart(in.str[p]); p++ { + } + } else { + for ; p < len(in.bytes) && !utf8.RuneStart(in.bytes[p]); p++ { + } + } + return p +} + +func (in *input) appendSlice(buf []byte, b, e int) []byte { + if in.bytes != nil { + return append(buf, in.bytes[b:e]...) + } + for i := b; i < e; i++ { + buf = append(buf, in.str[i]) + } + return buf +} + +func (in *input) copySlice(buf []byte, b, e int) int { + if in.bytes == nil { + return copy(buf, in.str[b:e]) + } + return copy(buf, in.bytes[b:e]) +} + +func (in *input) charinfoNFC(p int) (uint16, int) { + if in.bytes == nil { + return nfcData.lookupString(in.str[p:]) + } + return nfcData.lookup(in.bytes[p:]) +} + +func (in *input) charinfoNFKC(p int) (uint16, int) { + if in.bytes == nil { + return nfkcData.lookupString(in.str[p:]) + } + return nfkcData.lookup(in.bytes[p:]) +} + +func (in *input) hangul(p int) (r rune) { + var size int + if in.bytes == nil { + if !isHangulString(in.str[p:]) { + return 0 + } + r, size = utf8.DecodeRuneInString(in.str[p:]) + } else { + if !isHangul(in.bytes[p:]) { + return 0 + } + r, size = utf8.DecodeRune(in.bytes[p:]) + } + if size != hangulUTF8Size { + return 0 + } + return r +} diff --git a/vendor/golang.org/x/text/unicode/norm/iter.go b/vendor/golang.org/x/text/unicode/norm/iter.go new file mode 100644 index 0000000000..ce17f96c2e --- /dev/null +++ b/vendor/golang.org/x/text/unicode/norm/iter.go @@ -0,0 +1,457 @@ +// Copyright 2011 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 norm + +import ( + "fmt" + "unicode/utf8" +) + +// MaxSegmentSize is the maximum size of a byte buffer needed to consider any +// sequence of starter and non-starter runes for the purpose of normalization. +const MaxSegmentSize = maxByteBufferSize + +// An Iter iterates over a string or byte slice, while normalizing it +// to a given Form. +type Iter struct { + rb reorderBuffer + buf [maxByteBufferSize]byte + info Properties // first character saved from previous iteration + next iterFunc // implementation of next depends on form + asciiF iterFunc + + p int // current position in input source + multiSeg []byte // remainder of multi-segment decomposition +} + +type iterFunc func(*Iter) []byte + +// Init initializes i to iterate over src after normalizing it to Form f. +func (i *Iter) Init(f Form, src []byte) { + i.p = 0 + if len(src) == 0 { + i.setDone() + i.rb.nsrc = 0 + return + } + i.multiSeg = nil + i.rb.init(f, src) + i.next = i.rb.f.nextMain + i.asciiF = nextASCIIBytes + i.info = i.rb.f.info(i.rb.src, i.p) + i.rb.ss.first(i.info) +} + +// InitString initializes i to iterate over src after normalizing it to Form f. +func (i *Iter) InitString(f Form, src string) { + i.p = 0 + if len(src) == 0 { + i.setDone() + i.rb.nsrc = 0 + return + } + i.multiSeg = nil + i.rb.initString(f, src) + i.next = i.rb.f.nextMain + i.asciiF = nextASCIIString + i.info = i.rb.f.info(i.rb.src, i.p) + i.rb.ss.first(i.info) +} + +// Seek sets the segment to be returned by the next call to Next to start +// at position p. It is the responsibility of the caller to set p to the +// start of a segment. +func (i *Iter) Seek(offset int64, whence int) (int64, error) { + var abs int64 + switch whence { + case 0: + abs = offset + case 1: + abs = int64(i.p) + offset + case 2: + abs = int64(i.rb.nsrc) + offset + default: + return 0, fmt.Errorf("norm: invalid whence") + } + if abs < 0 { + return 0, fmt.Errorf("norm: negative position") + } + if int(abs) >= i.rb.nsrc { + i.setDone() + return int64(i.p), nil + } + i.p = int(abs) + i.multiSeg = nil + i.next = i.rb.f.nextMain + i.info = i.rb.f.info(i.rb.src, i.p) + i.rb.ss.first(i.info) + return abs, nil +} + +// returnSlice returns a slice of the underlying input type as a byte slice. +// If the underlying is of type []byte, it will simply return a slice. +// If the underlying is of type string, it will copy the slice to the buffer +// and return that. +func (i *Iter) returnSlice(a, b int) []byte { + if i.rb.src.bytes == nil { + return i.buf[:copy(i.buf[:], i.rb.src.str[a:b])] + } + return i.rb.src.bytes[a:b] +} + +// Pos returns the byte position at which the next call to Next will commence processing. +func (i *Iter) Pos() int { + return i.p +} + +func (i *Iter) setDone() { + i.next = nextDone + i.p = i.rb.nsrc +} + +// Done returns true if there is no more input to process. +func (i *Iter) Done() bool { + return i.p >= i.rb.nsrc +} + +// Next returns f(i.input[i.Pos():n]), where n is a boundary of i.input. +// For any input a and b for which f(a) == f(b), subsequent calls +// to Next will return the same segments. +// Modifying runes are grouped together with the preceding starter, if such a starter exists. +// Although not guaranteed, n will typically be the smallest possible n. +func (i *Iter) Next() []byte { + return i.next(i) +} + +func nextASCIIBytes(i *Iter) []byte { + p := i.p + 1 + if p >= i.rb.nsrc { + i.setDone() + return i.rb.src.bytes[i.p:p] + } + if i.rb.src.bytes[p] < utf8.RuneSelf { + p0 := i.p + i.p = p + return i.rb.src.bytes[p0:p] + } + i.info = i.rb.f.info(i.rb.src, i.p) + i.next = i.rb.f.nextMain + return i.next(i) +} + +func nextASCIIString(i *Iter) []byte { + p := i.p + 1 + if p >= i.rb.nsrc { + i.buf[0] = i.rb.src.str[i.p] + i.setDone() + return i.buf[:1] + } + if i.rb.src.str[p] < utf8.RuneSelf { + i.buf[0] = i.rb.src.str[i.p] + i.p = p + return i.buf[:1] + } + i.info = i.rb.f.info(i.rb.src, i.p) + i.next = i.rb.f.nextMain + return i.next(i) +} + +func nextHangul(i *Iter) []byte { + p := i.p + next := p + hangulUTF8Size + if next >= i.rb.nsrc { + i.setDone() + } else if i.rb.src.hangul(next) == 0 { + i.rb.ss.next(i.info) + i.info = i.rb.f.info(i.rb.src, i.p) + i.next = i.rb.f.nextMain + return i.next(i) + } + i.p = next + return i.buf[:decomposeHangul(i.buf[:], i.rb.src.hangul(p))] +} + +func nextDone(i *Iter) []byte { + return nil +} + +// nextMulti is used for iterating over multi-segment decompositions +// for decomposing normal forms. +func nextMulti(i *Iter) []byte { + j := 0 + d := i.multiSeg + // skip first rune + for j = 1; j < len(d) && !utf8.RuneStart(d[j]); j++ { + } + for j < len(d) { + info := i.rb.f.info(input{bytes: d}, j) + if info.BoundaryBefore() { + i.multiSeg = d[j:] + return d[:j] + } + j += int(info.size) + } + // treat last segment as normal decomposition + i.next = i.rb.f.nextMain + return i.next(i) +} + +// nextMultiNorm is used for iterating over multi-segment decompositions +// for composing normal forms. +func nextMultiNorm(i *Iter) []byte { + j := 0 + d := i.multiSeg + for j < len(d) { + info := i.rb.f.info(input{bytes: d}, j) + if info.BoundaryBefore() { + i.rb.compose() + seg := i.buf[:i.rb.flushCopy(i.buf[:])] + i.rb.insertUnsafe(input{bytes: d}, j, info) + i.multiSeg = d[j+int(info.size):] + return seg + } + i.rb.insertUnsafe(input{bytes: d}, j, info) + j += int(info.size) + } + i.multiSeg = nil + i.next = nextComposed + return doNormComposed(i) +} + +// nextDecomposed is the implementation of Next for forms NFD and NFKD. +func nextDecomposed(i *Iter) (next []byte) { + outp := 0 + inCopyStart, outCopyStart := i.p, 0 + for { + if sz := int(i.info.size); sz <= 1 { + i.rb.ss = 0 + p := i.p + i.p++ // ASCII or illegal byte. Either way, advance by 1. + if i.p >= i.rb.nsrc { + i.setDone() + return i.returnSlice(p, i.p) + } else if i.rb.src._byte(i.p) < utf8.RuneSelf { + i.next = i.asciiF + return i.returnSlice(p, i.p) + } + outp++ + } else if d := i.info.Decomposition(); d != nil { + // Note: If leading CCC != 0, then len(d) == 2 and last is also non-zero. + // Case 1: there is a leftover to copy. In this case the decomposition + // must begin with a modifier and should always be appended. + // Case 2: no leftover. Simply return d if followed by a ccc == 0 value. + p := outp + len(d) + if outp > 0 { + i.rb.src.copySlice(i.buf[outCopyStart:], inCopyStart, i.p) + // TODO: this condition should not be possible, but we leave it + // in for defensive purposes. + if p > len(i.buf) { + return i.buf[:outp] + } + } else if i.info.multiSegment() { + // outp must be 0 as multi-segment decompositions always + // start a new segment. + if i.multiSeg == nil { + i.multiSeg = d + i.next = nextMulti + return nextMulti(i) + } + // We are in the last segment. Treat as normal decomposition. + d = i.multiSeg + i.multiSeg = nil + p = len(d) + } + prevCC := i.info.tccc + if i.p += sz; i.p >= i.rb.nsrc { + i.setDone() + i.info = Properties{} // Force BoundaryBefore to succeed. + } else { + i.info = i.rb.f.info(i.rb.src, i.p) + } + switch i.rb.ss.next(i.info) { + case ssOverflow: + i.next = nextCGJDecompose + fallthrough + case ssStarter: + if outp > 0 { + copy(i.buf[outp:], d) + return i.buf[:p] + } + return d + } + copy(i.buf[outp:], d) + outp = p + inCopyStart, outCopyStart = i.p, outp + if i.info.ccc < prevCC { + goto doNorm + } + continue + } else if r := i.rb.src.hangul(i.p); r != 0 { + outp = decomposeHangul(i.buf[:], r) + i.p += hangulUTF8Size + inCopyStart, outCopyStart = i.p, outp + if i.p >= i.rb.nsrc { + i.setDone() + break + } else if i.rb.src.hangul(i.p) != 0 { + i.next = nextHangul + return i.buf[:outp] + } + } else { + p := outp + sz + if p > len(i.buf) { + break + } + outp = p + i.p += sz + } + if i.p >= i.rb.nsrc { + i.setDone() + break + } + prevCC := i.info.tccc + i.info = i.rb.f.info(i.rb.src, i.p) + if v := i.rb.ss.next(i.info); v == ssStarter { + break + } else if v == ssOverflow { + i.next = nextCGJDecompose + break + } + if i.info.ccc < prevCC { + goto doNorm + } + } + if outCopyStart == 0 { + return i.returnSlice(inCopyStart, i.p) + } else if inCopyStart < i.p { + i.rb.src.copySlice(i.buf[outCopyStart:], inCopyStart, i.p) + } + return i.buf[:outp] +doNorm: + // Insert what we have decomposed so far in the reorderBuffer. + // As we will only reorder, there will always be enough room. + i.rb.src.copySlice(i.buf[outCopyStart:], inCopyStart, i.p) + i.rb.insertDecomposed(i.buf[0:outp]) + return doNormDecomposed(i) +} + +func doNormDecomposed(i *Iter) []byte { + for { + i.rb.insertUnsafe(i.rb.src, i.p, i.info) + if i.p += int(i.info.size); i.p >= i.rb.nsrc { + i.setDone() + break + } + i.info = i.rb.f.info(i.rb.src, i.p) + if i.info.ccc == 0 { + break + } + if s := i.rb.ss.next(i.info); s == ssOverflow { + i.next = nextCGJDecompose + break + } + } + // new segment or too many combining characters: exit normalization + return i.buf[:i.rb.flushCopy(i.buf[:])] +} + +func nextCGJDecompose(i *Iter) []byte { + i.rb.ss = 0 + i.rb.insertCGJ() + i.next = nextDecomposed + i.rb.ss.first(i.info) + buf := doNormDecomposed(i) + return buf +} + +// nextComposed is the implementation of Next for forms NFC and NFKC. +func nextComposed(i *Iter) []byte { + outp, startp := 0, i.p + var prevCC uint8 + for { + if !i.info.isYesC() { + goto doNorm + } + prevCC = i.info.tccc + sz := int(i.info.size) + if sz == 0 { + sz = 1 // illegal rune: copy byte-by-byte + } + p := outp + sz + if p > len(i.buf) { + break + } + outp = p + i.p += sz + if i.p >= i.rb.nsrc { + i.setDone() + break + } else if i.rb.src._byte(i.p) < utf8.RuneSelf { + i.rb.ss = 0 + i.next = i.asciiF + break + } + i.info = i.rb.f.info(i.rb.src, i.p) + if v := i.rb.ss.next(i.info); v == ssStarter { + break + } else if v == ssOverflow { + i.next = nextCGJCompose + break + } + if i.info.ccc < prevCC { + goto doNorm + } + } + return i.returnSlice(startp, i.p) +doNorm: + // reset to start position + i.p = startp + i.info = i.rb.f.info(i.rb.src, i.p) + i.rb.ss.first(i.info) + if i.info.multiSegment() { + d := i.info.Decomposition() + info := i.rb.f.info(input{bytes: d}, 0) + i.rb.insertUnsafe(input{bytes: d}, 0, info) + i.multiSeg = d[int(info.size):] + i.next = nextMultiNorm + return nextMultiNorm(i) + } + i.rb.ss.first(i.info) + i.rb.insertUnsafe(i.rb.src, i.p, i.info) + return doNormComposed(i) +} + +func doNormComposed(i *Iter) []byte { + // First rune should already be inserted. + for { + if i.p += int(i.info.size); i.p >= i.rb.nsrc { + i.setDone() + break + } + i.info = i.rb.f.info(i.rb.src, i.p) + if s := i.rb.ss.next(i.info); s == ssStarter { + break + } else if s == ssOverflow { + i.next = nextCGJCompose + break + } + i.rb.insertUnsafe(i.rb.src, i.p, i.info) + } + i.rb.compose() + seg := i.buf[:i.rb.flushCopy(i.buf[:])] + return seg +} + +func nextCGJCompose(i *Iter) []byte { + i.rb.ss = 0 // instead of first + i.rb.insertCGJ() + i.next = nextComposed + // Note that we treat any rune with nLeadingNonStarters > 0 as a non-starter, + // even if they are not. This is particularly dubious for U+FF9E and UFF9A. + // If we ever change that, insert a check here. + i.rb.ss.first(i.info) + i.rb.insertUnsafe(i.rb.src, i.p, i.info) + return doNormComposed(i) +} diff --git a/vendor/golang.org/x/text/unicode/norm/normalize.go b/vendor/golang.org/x/text/unicode/norm/normalize.go new file mode 100644 index 0000000000..e28ac641ac --- /dev/null +++ b/vendor/golang.org/x/text/unicode/norm/normalize.go @@ -0,0 +1,609 @@ +// Copyright 2011 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. + +// Note: the file data_test.go that is generated should not be checked in. +//go:generate go run maketables.go triegen.go +//go:generate go test -tags test + +// Package norm contains types and functions for normalizing Unicode strings. +package norm // import "golang.org/x/text/unicode/norm" + +import ( + "unicode/utf8" + + "golang.org/x/text/transform" +) + +// A Form denotes a canonical representation of Unicode code points. +// The Unicode-defined normalization and equivalence forms are: +// +// NFC Unicode Normalization Form C +// NFD Unicode Normalization Form D +// NFKC Unicode Normalization Form KC +// NFKD Unicode Normalization Form KD +// +// For a Form f, this documentation uses the notation f(x) to mean +// the bytes or string x converted to the given form. +// A position n in x is called a boundary if conversion to the form can +// proceed independently on both sides: +// f(x) == append(f(x[0:n]), f(x[n:])...) +// +// References: http://unicode.org/reports/tr15/ and +// http://unicode.org/notes/tn5/. +type Form int + +const ( + NFC Form = iota + NFD + NFKC + NFKD +) + +// Bytes returns f(b). May return b if f(b) = b. +func (f Form) Bytes(b []byte) []byte { + src := inputBytes(b) + ft := formTable[f] + n, ok := ft.quickSpan(src, 0, len(b), true) + if ok { + return b + } + out := make([]byte, n, len(b)) + copy(out, b[0:n]) + rb := reorderBuffer{f: *ft, src: src, nsrc: len(b), out: out, flushF: appendFlush} + return doAppendInner(&rb, n) +} + +// String returns f(s). +func (f Form) String(s string) string { + src := inputString(s) + ft := formTable[f] + n, ok := ft.quickSpan(src, 0, len(s), true) + if ok { + return s + } + out := make([]byte, n, len(s)) + copy(out, s[0:n]) + rb := reorderBuffer{f: *ft, src: src, nsrc: len(s), out: out, flushF: appendFlush} + return string(doAppendInner(&rb, n)) +} + +// IsNormal returns true if b == f(b). +func (f Form) IsNormal(b []byte) bool { + src := inputBytes(b) + ft := formTable[f] + bp, ok := ft.quickSpan(src, 0, len(b), true) + if ok { + return true + } + rb := reorderBuffer{f: *ft, src: src, nsrc: len(b)} + rb.setFlusher(nil, cmpNormalBytes) + for bp < len(b) { + rb.out = b[bp:] + if bp = decomposeSegment(&rb, bp, true); bp < 0 { + return false + } + bp, _ = rb.f.quickSpan(rb.src, bp, len(b), true) + } + return true +} + +func cmpNormalBytes(rb *reorderBuffer) bool { + b := rb.out + for i := 0; i < rb.nrune; i++ { + info := rb.rune[i] + if int(info.size) > len(b) { + return false + } + p := info.pos + pe := p + info.size + for ; p < pe; p++ { + if b[0] != rb.byte[p] { + return false + } + b = b[1:] + } + } + return true +} + +// IsNormalString returns true if s == f(s). +func (f Form) IsNormalString(s string) bool { + src := inputString(s) + ft := formTable[f] + bp, ok := ft.quickSpan(src, 0, len(s), true) + if ok { + return true + } + rb := reorderBuffer{f: *ft, src: src, nsrc: len(s)} + rb.setFlusher(nil, func(rb *reorderBuffer) bool { + for i := 0; i < rb.nrune; i++ { + info := rb.rune[i] + if bp+int(info.size) > len(s) { + return false + } + p := info.pos + pe := p + info.size + for ; p < pe; p++ { + if s[bp] != rb.byte[p] { + return false + } + bp++ + } + } + return true + }) + for bp < len(s) { + if bp = decomposeSegment(&rb, bp, true); bp < 0 { + return false + } + bp, _ = rb.f.quickSpan(rb.src, bp, len(s), true) + } + return true +} + +// patchTail fixes a case where a rune may be incorrectly normalized +// if it is followed by illegal continuation bytes. It returns the +// patched buffer and whether the decomposition is still in progress. +func patchTail(rb *reorderBuffer) bool { + info, p := lastRuneStart(&rb.f, rb.out) + if p == -1 || info.size == 0 { + return true + } + end := p + int(info.size) + extra := len(rb.out) - end + if extra > 0 { + // Potentially allocating memory. However, this only + // happens with ill-formed UTF-8. + x := make([]byte, 0) + x = append(x, rb.out[len(rb.out)-extra:]...) + rb.out = rb.out[:end] + decomposeToLastBoundary(rb) + rb.doFlush() + rb.out = append(rb.out, x...) + return false + } + buf := rb.out[p:] + rb.out = rb.out[:p] + decomposeToLastBoundary(rb) + if s := rb.ss.next(info); s == ssStarter { + rb.doFlush() + rb.ss.first(info) + } else if s == ssOverflow { + rb.doFlush() + rb.insertCGJ() + rb.ss = 0 + } + rb.insertUnsafe(inputBytes(buf), 0, info) + return true +} + +func appendQuick(rb *reorderBuffer, i int) int { + if rb.nsrc == i { + return i + } + end, _ := rb.f.quickSpan(rb.src, i, rb.nsrc, true) + rb.out = rb.src.appendSlice(rb.out, i, end) + return end +} + +// Append returns f(append(out, b...)). +// The buffer out must be nil, empty, or equal to f(out). +func (f Form) Append(out []byte, src ...byte) []byte { + return f.doAppend(out, inputBytes(src), len(src)) +} + +func (f Form) doAppend(out []byte, src input, n int) []byte { + if n == 0 { + return out + } + ft := formTable[f] + // Attempt to do a quickSpan first so we can avoid initializing the reorderBuffer. + if len(out) == 0 { + p, _ := ft.quickSpan(src, 0, n, true) + out = src.appendSlice(out, 0, p) + if p == n { + return out + } + rb := reorderBuffer{f: *ft, src: src, nsrc: n, out: out, flushF: appendFlush} + return doAppendInner(&rb, p) + } + rb := reorderBuffer{f: *ft, src: src, nsrc: n} + return doAppend(&rb, out, 0) +} + +func doAppend(rb *reorderBuffer, out []byte, p int) []byte { + rb.setFlusher(out, appendFlush) + src, n := rb.src, rb.nsrc + doMerge := len(out) > 0 + if q := src.skipContinuationBytes(p); q > p { + // Move leading non-starters to destination. + rb.out = src.appendSlice(rb.out, p, q) + p = q + doMerge = patchTail(rb) + } + fd := &rb.f + if doMerge { + var info Properties + if p < n { + info = fd.info(src, p) + if !info.BoundaryBefore() || info.nLeadingNonStarters() > 0 { + if p == 0 { + decomposeToLastBoundary(rb) + } + p = decomposeSegment(rb, p, true) + } + } + if info.size == 0 { + rb.doFlush() + // Append incomplete UTF-8 encoding. + return src.appendSlice(rb.out, p, n) + } + if rb.nrune > 0 { + return doAppendInner(rb, p) + } + } + p = appendQuick(rb, p) + return doAppendInner(rb, p) +} + +func doAppendInner(rb *reorderBuffer, p int) []byte { + for n := rb.nsrc; p < n; { + p = decomposeSegment(rb, p, true) + p = appendQuick(rb, p) + } + return rb.out +} + +// AppendString returns f(append(out, []byte(s))). +// The buffer out must be nil, empty, or equal to f(out). +func (f Form) AppendString(out []byte, src string) []byte { + return f.doAppend(out, inputString(src), len(src)) +} + +// QuickSpan returns a boundary n such that b[0:n] == f(b[0:n]). +// It is not guaranteed to return the largest such n. +func (f Form) QuickSpan(b []byte) int { + n, _ := formTable[f].quickSpan(inputBytes(b), 0, len(b), true) + return n +} + +// Span implements transform.SpanningTransformer. It returns a boundary n such +// that b[0:n] == f(b[0:n]). It is not guaranteed to return the largest such n. +func (f Form) Span(b []byte, atEOF bool) (n int, err error) { + n, ok := formTable[f].quickSpan(inputBytes(b), 0, len(b), atEOF) + if n < len(b) { + if !ok { + err = transform.ErrEndOfSpan + } else { + err = transform.ErrShortSrc + } + } + return n, err +} + +// SpanString returns a boundary n such that s[0:n] == f(s[0:n]). +// It is not guaranteed to return the largest such n. +func (f Form) SpanString(s string, atEOF bool) (n int, err error) { + n, ok := formTable[f].quickSpan(inputString(s), 0, len(s), atEOF) + if n < len(s) { + if !ok { + err = transform.ErrEndOfSpan + } else { + err = transform.ErrShortSrc + } + } + return n, err +} + +// quickSpan returns a boundary n such that src[0:n] == f(src[0:n]) and +// whether any non-normalized parts were found. If atEOF is false, n will +// not point past the last segment if this segment might be become +// non-normalized by appending other runes. +func (f *formInfo) quickSpan(src input, i, end int, atEOF bool) (n int, ok bool) { + var lastCC uint8 + ss := streamSafe(0) + lastSegStart := i + for n = end; i < n; { + if j := src.skipASCII(i, n); i != j { + i = j + lastSegStart = i - 1 + lastCC = 0 + ss = 0 + continue + } + info := f.info(src, i) + if info.size == 0 { + if atEOF { + // include incomplete runes + return n, true + } + return lastSegStart, true + } + // This block needs to be before the next, because it is possible to + // have an overflow for runes that are starters (e.g. with U+FF9E). + switch ss.next(info) { + case ssStarter: + lastSegStart = i + case ssOverflow: + return lastSegStart, false + case ssSuccess: + if lastCC > info.ccc { + return lastSegStart, false + } + } + if f.composing { + if !info.isYesC() { + break + } + } else { + if !info.isYesD() { + break + } + } + lastCC = info.ccc + i += int(info.size) + } + if i == n { + if !atEOF { + n = lastSegStart + } + return n, true + } + return lastSegStart, false +} + +// QuickSpanString returns a boundary n such that s[0:n] == f(s[0:n]). +// It is not guaranteed to return the largest such n. +func (f Form) QuickSpanString(s string) int { + n, _ := formTable[f].quickSpan(inputString(s), 0, len(s), true) + return n +} + +// FirstBoundary returns the position i of the first boundary in b +// or -1 if b contains no boundary. +func (f Form) FirstBoundary(b []byte) int { + return f.firstBoundary(inputBytes(b), len(b)) +} + +func (f Form) firstBoundary(src input, nsrc int) int { + i := src.skipContinuationBytes(0) + if i >= nsrc { + return -1 + } + fd := formTable[f] + ss := streamSafe(0) + // We should call ss.first here, but we can't as the first rune is + // skipped already. This means FirstBoundary can't really determine + // CGJ insertion points correctly. Luckily it doesn't have to. + for { + info := fd.info(src, i) + if info.size == 0 { + return -1 + } + if s := ss.next(info); s != ssSuccess { + return i + } + i += int(info.size) + if i >= nsrc { + if !info.BoundaryAfter() && !ss.isMax() { + return -1 + } + return nsrc + } + } +} + +// FirstBoundaryInString returns the position i of the first boundary in s +// or -1 if s contains no boundary. +func (f Form) FirstBoundaryInString(s string) int { + return f.firstBoundary(inputString(s), len(s)) +} + +// NextBoundary reports the index of the boundary between the first and next +// segment in b or -1 if atEOF is false and there are not enough bytes to +// determine this boundary. +func (f Form) NextBoundary(b []byte, atEOF bool) int { + return f.nextBoundary(inputBytes(b), len(b), atEOF) +} + +// NextBoundaryInString reports the index of the boundary between the first and +// next segment in b or -1 if atEOF is false and there are not enough bytes to +// determine this boundary. +func (f Form) NextBoundaryInString(s string, atEOF bool) int { + return f.nextBoundary(inputString(s), len(s), atEOF) +} + +func (f Form) nextBoundary(src input, nsrc int, atEOF bool) int { + if nsrc == 0 { + if atEOF { + return 0 + } + return -1 + } + fd := formTable[f] + info := fd.info(src, 0) + if info.size == 0 { + if atEOF { + return 1 + } + return -1 + } + ss := streamSafe(0) + ss.first(info) + + for i := int(info.size); i < nsrc; i += int(info.size) { + info = fd.info(src, i) + if info.size == 0 { + if atEOF { + return i + } + return -1 + } + // TODO: Using streamSafe to determine the boundary isn't the same as + // using BoundaryBefore. Determine which should be used. + if s := ss.next(info); s != ssSuccess { + return i + } + } + if !atEOF && !info.BoundaryAfter() && !ss.isMax() { + return -1 + } + return nsrc +} + +// LastBoundary returns the position i of the last boundary in b +// or -1 if b contains no boundary. +func (f Form) LastBoundary(b []byte) int { + return lastBoundary(formTable[f], b) +} + +func lastBoundary(fd *formInfo, b []byte) int { + i := len(b) + info, p := lastRuneStart(fd, b) + if p == -1 { + return -1 + } + if info.size == 0 { // ends with incomplete rune + if p == 0 { // starts with incomplete rune + return -1 + } + i = p + info, p = lastRuneStart(fd, b[:i]) + if p == -1 { // incomplete UTF-8 encoding or non-starter bytes without a starter + return i + } + } + if p+int(info.size) != i { // trailing non-starter bytes: illegal UTF-8 + return i + } + if info.BoundaryAfter() { + return i + } + ss := streamSafe(0) + v := ss.backwards(info) + for i = p; i >= 0 && v != ssStarter; i = p { + info, p = lastRuneStart(fd, b[:i]) + if v = ss.backwards(info); v == ssOverflow { + break + } + if p+int(info.size) != i { + if p == -1 { // no boundary found + return -1 + } + return i // boundary after an illegal UTF-8 encoding + } + } + return i +} + +// decomposeSegment scans the first segment in src into rb. It inserts 0x034f +// (Grapheme Joiner) when it encounters a sequence of more than 30 non-starters +// and returns the number of bytes consumed from src or iShortDst or iShortSrc. +func decomposeSegment(rb *reorderBuffer, sp int, atEOF bool) int { + // Force one character to be consumed. + info := rb.f.info(rb.src, sp) + if info.size == 0 { + return 0 + } + if s := rb.ss.next(info); s == ssStarter { + // TODO: this could be removed if we don't support merging. + if rb.nrune > 0 { + goto end + } + } else if s == ssOverflow { + rb.insertCGJ() + goto end + } + if err := rb.insertFlush(rb.src, sp, info); err != iSuccess { + return int(err) + } + for { + sp += int(info.size) + if sp >= rb.nsrc { + if !atEOF && !info.BoundaryAfter() { + return int(iShortSrc) + } + break + } + info = rb.f.info(rb.src, sp) + if info.size == 0 { + if !atEOF { + return int(iShortSrc) + } + break + } + if s := rb.ss.next(info); s == ssStarter { + break + } else if s == ssOverflow { + rb.insertCGJ() + break + } + if err := rb.insertFlush(rb.src, sp, info); err != iSuccess { + return int(err) + } + } +end: + if !rb.doFlush() { + return int(iShortDst) + } + return sp +} + +// lastRuneStart returns the runeInfo and position of the last +// rune in buf or the zero runeInfo and -1 if no rune was found. +func lastRuneStart(fd *formInfo, buf []byte) (Properties, int) { + p := len(buf) - 1 + for ; p >= 0 && !utf8.RuneStart(buf[p]); p-- { + } + if p < 0 { + return Properties{}, -1 + } + return fd.info(inputBytes(buf), p), p +} + +// decomposeToLastBoundary finds an open segment at the end of the buffer +// and scans it into rb. Returns the buffer minus the last segment. +func decomposeToLastBoundary(rb *reorderBuffer) { + fd := &rb.f + info, i := lastRuneStart(fd, rb.out) + if int(info.size) != len(rb.out)-i { + // illegal trailing continuation bytes + return + } + if info.BoundaryAfter() { + return + } + var add [maxNonStarters + 1]Properties // stores runeInfo in reverse order + padd := 0 + ss := streamSafe(0) + p := len(rb.out) + for { + add[padd] = info + v := ss.backwards(info) + if v == ssOverflow { + // Note that if we have an overflow, it the string we are appending to + // is not correctly normalized. In this case the behavior is undefined. + break + } + padd++ + p -= int(info.size) + if v == ssStarter || p < 0 { + break + } + info, i = lastRuneStart(fd, rb.out[:p]) + if int(info.size) != p-i { + break + } + } + rb.ss = ss + // Copy bytes for insertion as we may need to overwrite rb.out. + var buf [maxBufferSize * utf8.UTFMax]byte + cp := buf[:copy(buf[:], rb.out[p:])] + rb.out = rb.out[:p] + for padd--; padd >= 0; padd-- { + info = add[padd] + rb.insertUnsafe(inputBytes(cp), 0, info) + cp = cp[info.size:] + } +} diff --git a/vendor/golang.org/x/text/unicode/norm/readwriter.go b/vendor/golang.org/x/text/unicode/norm/readwriter.go new file mode 100644 index 0000000000..d926ee903e --- /dev/null +++ b/vendor/golang.org/x/text/unicode/norm/readwriter.go @@ -0,0 +1,125 @@ +// Copyright 2011 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 norm + +import "io" + +type normWriter struct { + rb reorderBuffer + w io.Writer + buf []byte +} + +// Write implements the standard write interface. If the last characters are +// not at a normalization boundary, the bytes will be buffered for the next +// write. The remaining bytes will be written on close. +func (w *normWriter) Write(data []byte) (n int, err error) { + // Process data in pieces to keep w.buf size bounded. + const chunk = 4000 + + for len(data) > 0 { + // Normalize into w.buf. + m := len(data) + if m > chunk { + m = chunk + } + w.rb.src = inputBytes(data[:m]) + w.rb.nsrc = m + w.buf = doAppend(&w.rb, w.buf, 0) + data = data[m:] + n += m + + // Write out complete prefix, save remainder. + // Note that lastBoundary looks back at most 31 runes. + i := lastBoundary(&w.rb.f, w.buf) + if i == -1 { + i = 0 + } + if i > 0 { + if _, err = w.w.Write(w.buf[:i]); err != nil { + break + } + bn := copy(w.buf, w.buf[i:]) + w.buf = w.buf[:bn] + } + } + return n, err +} + +// Close forces data that remains in the buffer to be written. +func (w *normWriter) Close() error { + if len(w.buf) > 0 { + _, err := w.w.Write(w.buf) + if err != nil { + return err + } + } + return nil +} + +// Writer returns a new writer that implements Write(b) +// by writing f(b) to w. The returned writer may use an +// an internal buffer to maintain state across Write calls. +// Calling its Close method writes any buffered data to w. +func (f Form) Writer(w io.Writer) io.WriteCloser { + wr := &normWriter{rb: reorderBuffer{}, w: w} + wr.rb.init(f, nil) + return wr +} + +type normReader struct { + rb reorderBuffer + r io.Reader + inbuf []byte + outbuf []byte + bufStart int + lastBoundary int + err error +} + +// Read implements the standard read interface. +func (r *normReader) Read(p []byte) (int, error) { + for { + if r.lastBoundary-r.bufStart > 0 { + n := copy(p, r.outbuf[r.bufStart:r.lastBoundary]) + r.bufStart += n + if r.lastBoundary-r.bufStart > 0 { + return n, nil + } + return n, r.err + } + if r.err != nil { + return 0, r.err + } + outn := copy(r.outbuf, r.outbuf[r.lastBoundary:]) + r.outbuf = r.outbuf[0:outn] + r.bufStart = 0 + + n, err := r.r.Read(r.inbuf) + r.rb.src = inputBytes(r.inbuf[0:n]) + r.rb.nsrc, r.err = n, err + if n > 0 { + r.outbuf = doAppend(&r.rb, r.outbuf, 0) + } + if err == io.EOF { + r.lastBoundary = len(r.outbuf) + } else { + r.lastBoundary = lastBoundary(&r.rb.f, r.outbuf) + if r.lastBoundary == -1 { + r.lastBoundary = 0 + } + } + } +} + +// Reader returns a new reader that implements Read +// by reading data from r and returning f(data). +func (f Form) Reader(r io.Reader) io.Reader { + const chunk = 4000 + buf := make([]byte, chunk) + rr := &normReader{rb: reorderBuffer{}, r: r, inbuf: buf} + rr.rb.init(f, buf) + return rr +} diff --git a/vendor/golang.org/x/text/unicode/norm/tables10.0.0.go b/vendor/golang.org/x/text/unicode/norm/tables10.0.0.go new file mode 100644 index 0000000000..44dd3978ca --- /dev/null +++ b/vendor/golang.org/x/text/unicode/norm/tables10.0.0.go @@ -0,0 +1,7653 @@ +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. + +// +build go1.10 + +package norm + +const ( + // Version is the Unicode edition from which the tables are derived. + Version = "10.0.0" + + // MaxTransformChunkSize indicates the maximum number of bytes that Transform + // may need to write atomically for any Form. Making a destination buffer at + // least this size ensures that Transform can always make progress and that + // the user does not need to grow the buffer on an ErrShortDst. + MaxTransformChunkSize = 35 + maxNonStarters*4 +) + +var ccc = [55]uint8{ + 0, 1, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, + 84, 91, 103, 107, 118, 122, 129, 130, + 132, 202, 214, 216, 218, 220, 222, 224, + 226, 228, 230, 232, 233, 234, 240, +} + +const ( + firstMulti = 0x186D + firstCCC = 0x2C9E + endMulti = 0x2F60 + firstLeadingCCC = 0x49AE + firstCCCZeroExcept = 0x4A78 + firstStarterWithNLead = 0x4A9F + lastDecomp = 0x4AA1 + maxDecomp = 0x8000 +) + +// decomps: 19105 bytes +var decomps = [...]byte{ + // Bytes 0 - 3f + 0x00, 0x41, 0x20, 0x41, 0x21, 0x41, 0x22, 0x41, + 0x23, 0x41, 0x24, 0x41, 0x25, 0x41, 0x26, 0x41, + 0x27, 0x41, 0x28, 0x41, 0x29, 0x41, 0x2A, 0x41, + 0x2B, 0x41, 0x2C, 0x41, 0x2D, 0x41, 0x2E, 0x41, + 0x2F, 0x41, 0x30, 0x41, 0x31, 0x41, 0x32, 0x41, + 0x33, 0x41, 0x34, 0x41, 0x35, 0x41, 0x36, 0x41, + 0x37, 0x41, 0x38, 0x41, 0x39, 0x41, 0x3A, 0x41, + 0x3B, 0x41, 0x3C, 0x41, 0x3D, 0x41, 0x3E, 0x41, + // Bytes 40 - 7f + 0x3F, 0x41, 0x40, 0x41, 0x41, 0x41, 0x42, 0x41, + 0x43, 0x41, 0x44, 0x41, 0x45, 0x41, 0x46, 0x41, + 0x47, 0x41, 0x48, 0x41, 0x49, 0x41, 0x4A, 0x41, + 0x4B, 0x41, 0x4C, 0x41, 0x4D, 0x41, 0x4E, 0x41, + 0x4F, 0x41, 0x50, 0x41, 0x51, 0x41, 0x52, 0x41, + 0x53, 0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x41, + 0x57, 0x41, 0x58, 0x41, 0x59, 0x41, 0x5A, 0x41, + 0x5B, 0x41, 0x5C, 0x41, 0x5D, 0x41, 0x5E, 0x41, + // Bytes 80 - bf + 0x5F, 0x41, 0x60, 0x41, 0x61, 0x41, 0x62, 0x41, + 0x63, 0x41, 0x64, 0x41, 0x65, 0x41, 0x66, 0x41, + 0x67, 0x41, 0x68, 0x41, 0x69, 0x41, 0x6A, 0x41, + 0x6B, 0x41, 0x6C, 0x41, 0x6D, 0x41, 0x6E, 0x41, + 0x6F, 0x41, 0x70, 0x41, 0x71, 0x41, 0x72, 0x41, + 0x73, 0x41, 0x74, 0x41, 0x75, 0x41, 0x76, 0x41, + 0x77, 0x41, 0x78, 0x41, 0x79, 0x41, 0x7A, 0x41, + 0x7B, 0x41, 0x7C, 0x41, 0x7D, 0x41, 0x7E, 0x42, + // Bytes c0 - ff + 0xC2, 0xA2, 0x42, 0xC2, 0xA3, 0x42, 0xC2, 0xA5, + 0x42, 0xC2, 0xA6, 0x42, 0xC2, 0xAC, 0x42, 0xC2, + 0xB7, 0x42, 0xC3, 0x86, 0x42, 0xC3, 0xB0, 0x42, + 0xC4, 0xA6, 0x42, 0xC4, 0xA7, 0x42, 0xC4, 0xB1, + 0x42, 0xC5, 0x8B, 0x42, 0xC5, 0x93, 0x42, 0xC6, + 0x8E, 0x42, 0xC6, 0x90, 0x42, 0xC6, 0xAB, 0x42, + 0xC8, 0xA2, 0x42, 0xC8, 0xB7, 0x42, 0xC9, 0x90, + 0x42, 0xC9, 0x91, 0x42, 0xC9, 0x92, 0x42, 0xC9, + // Bytes 100 - 13f + 0x94, 0x42, 0xC9, 0x95, 0x42, 0xC9, 0x99, 0x42, + 0xC9, 0x9B, 0x42, 0xC9, 0x9C, 0x42, 0xC9, 0x9F, + 0x42, 0xC9, 0xA1, 0x42, 0xC9, 0xA3, 0x42, 0xC9, + 0xA5, 0x42, 0xC9, 0xA6, 0x42, 0xC9, 0xA8, 0x42, + 0xC9, 0xA9, 0x42, 0xC9, 0xAA, 0x42, 0xC9, 0xAB, + 0x42, 0xC9, 0xAD, 0x42, 0xC9, 0xAF, 0x42, 0xC9, + 0xB0, 0x42, 0xC9, 0xB1, 0x42, 0xC9, 0xB2, 0x42, + 0xC9, 0xB3, 0x42, 0xC9, 0xB4, 0x42, 0xC9, 0xB5, + // Bytes 140 - 17f + 0x42, 0xC9, 0xB8, 0x42, 0xC9, 0xB9, 0x42, 0xC9, + 0xBB, 0x42, 0xCA, 0x81, 0x42, 0xCA, 0x82, 0x42, + 0xCA, 0x83, 0x42, 0xCA, 0x89, 0x42, 0xCA, 0x8A, + 0x42, 0xCA, 0x8B, 0x42, 0xCA, 0x8C, 0x42, 0xCA, + 0x90, 0x42, 0xCA, 0x91, 0x42, 0xCA, 0x92, 0x42, + 0xCA, 0x95, 0x42, 0xCA, 0x9D, 0x42, 0xCA, 0x9F, + 0x42, 0xCA, 0xB9, 0x42, 0xCE, 0x91, 0x42, 0xCE, + 0x92, 0x42, 0xCE, 0x93, 0x42, 0xCE, 0x94, 0x42, + // Bytes 180 - 1bf + 0xCE, 0x95, 0x42, 0xCE, 0x96, 0x42, 0xCE, 0x97, + 0x42, 0xCE, 0x98, 0x42, 0xCE, 0x99, 0x42, 0xCE, + 0x9A, 0x42, 0xCE, 0x9B, 0x42, 0xCE, 0x9C, 0x42, + 0xCE, 0x9D, 0x42, 0xCE, 0x9E, 0x42, 0xCE, 0x9F, + 0x42, 0xCE, 0xA0, 0x42, 0xCE, 0xA1, 0x42, 0xCE, + 0xA3, 0x42, 0xCE, 0xA4, 0x42, 0xCE, 0xA5, 0x42, + 0xCE, 0xA6, 0x42, 0xCE, 0xA7, 0x42, 0xCE, 0xA8, + 0x42, 0xCE, 0xA9, 0x42, 0xCE, 0xB1, 0x42, 0xCE, + // Bytes 1c0 - 1ff + 0xB2, 0x42, 0xCE, 0xB3, 0x42, 0xCE, 0xB4, 0x42, + 0xCE, 0xB5, 0x42, 0xCE, 0xB6, 0x42, 0xCE, 0xB7, + 0x42, 0xCE, 0xB8, 0x42, 0xCE, 0xB9, 0x42, 0xCE, + 0xBA, 0x42, 0xCE, 0xBB, 0x42, 0xCE, 0xBC, 0x42, + 0xCE, 0xBD, 0x42, 0xCE, 0xBE, 0x42, 0xCE, 0xBF, + 0x42, 0xCF, 0x80, 0x42, 0xCF, 0x81, 0x42, 0xCF, + 0x82, 0x42, 0xCF, 0x83, 0x42, 0xCF, 0x84, 0x42, + 0xCF, 0x85, 0x42, 0xCF, 0x86, 0x42, 0xCF, 0x87, + // Bytes 200 - 23f + 0x42, 0xCF, 0x88, 0x42, 0xCF, 0x89, 0x42, 0xCF, + 0x9C, 0x42, 0xCF, 0x9D, 0x42, 0xD0, 0xBD, 0x42, + 0xD1, 0x8A, 0x42, 0xD1, 0x8C, 0x42, 0xD7, 0x90, + 0x42, 0xD7, 0x91, 0x42, 0xD7, 0x92, 0x42, 0xD7, + 0x93, 0x42, 0xD7, 0x94, 0x42, 0xD7, 0x9B, 0x42, + 0xD7, 0x9C, 0x42, 0xD7, 0x9D, 0x42, 0xD7, 0xA2, + 0x42, 0xD7, 0xA8, 0x42, 0xD7, 0xAA, 0x42, 0xD8, + 0xA1, 0x42, 0xD8, 0xA7, 0x42, 0xD8, 0xA8, 0x42, + // Bytes 240 - 27f + 0xD8, 0xA9, 0x42, 0xD8, 0xAA, 0x42, 0xD8, 0xAB, + 0x42, 0xD8, 0xAC, 0x42, 0xD8, 0xAD, 0x42, 0xD8, + 0xAE, 0x42, 0xD8, 0xAF, 0x42, 0xD8, 0xB0, 0x42, + 0xD8, 0xB1, 0x42, 0xD8, 0xB2, 0x42, 0xD8, 0xB3, + 0x42, 0xD8, 0xB4, 0x42, 0xD8, 0xB5, 0x42, 0xD8, + 0xB6, 0x42, 0xD8, 0xB7, 0x42, 0xD8, 0xB8, 0x42, + 0xD8, 0xB9, 0x42, 0xD8, 0xBA, 0x42, 0xD9, 0x81, + 0x42, 0xD9, 0x82, 0x42, 0xD9, 0x83, 0x42, 0xD9, + // Bytes 280 - 2bf + 0x84, 0x42, 0xD9, 0x85, 0x42, 0xD9, 0x86, 0x42, + 0xD9, 0x87, 0x42, 0xD9, 0x88, 0x42, 0xD9, 0x89, + 0x42, 0xD9, 0x8A, 0x42, 0xD9, 0xAE, 0x42, 0xD9, + 0xAF, 0x42, 0xD9, 0xB1, 0x42, 0xD9, 0xB9, 0x42, + 0xD9, 0xBA, 0x42, 0xD9, 0xBB, 0x42, 0xD9, 0xBE, + 0x42, 0xD9, 0xBF, 0x42, 0xDA, 0x80, 0x42, 0xDA, + 0x83, 0x42, 0xDA, 0x84, 0x42, 0xDA, 0x86, 0x42, + 0xDA, 0x87, 0x42, 0xDA, 0x88, 0x42, 0xDA, 0x8C, + // Bytes 2c0 - 2ff + 0x42, 0xDA, 0x8D, 0x42, 0xDA, 0x8E, 0x42, 0xDA, + 0x91, 0x42, 0xDA, 0x98, 0x42, 0xDA, 0xA1, 0x42, + 0xDA, 0xA4, 0x42, 0xDA, 0xA6, 0x42, 0xDA, 0xA9, + 0x42, 0xDA, 0xAD, 0x42, 0xDA, 0xAF, 0x42, 0xDA, + 0xB1, 0x42, 0xDA, 0xB3, 0x42, 0xDA, 0xBA, 0x42, + 0xDA, 0xBB, 0x42, 0xDA, 0xBE, 0x42, 0xDB, 0x81, + 0x42, 0xDB, 0x85, 0x42, 0xDB, 0x86, 0x42, 0xDB, + 0x87, 0x42, 0xDB, 0x88, 0x42, 0xDB, 0x89, 0x42, + // Bytes 300 - 33f + 0xDB, 0x8B, 0x42, 0xDB, 0x8C, 0x42, 0xDB, 0x90, + 0x42, 0xDB, 0x92, 0x43, 0xE0, 0xBC, 0x8B, 0x43, + 0xE1, 0x83, 0x9C, 0x43, 0xE1, 0x84, 0x80, 0x43, + 0xE1, 0x84, 0x81, 0x43, 0xE1, 0x84, 0x82, 0x43, + 0xE1, 0x84, 0x83, 0x43, 0xE1, 0x84, 0x84, 0x43, + 0xE1, 0x84, 0x85, 0x43, 0xE1, 0x84, 0x86, 0x43, + 0xE1, 0x84, 0x87, 0x43, 0xE1, 0x84, 0x88, 0x43, + 0xE1, 0x84, 0x89, 0x43, 0xE1, 0x84, 0x8A, 0x43, + // Bytes 340 - 37f + 0xE1, 0x84, 0x8B, 0x43, 0xE1, 0x84, 0x8C, 0x43, + 0xE1, 0x84, 0x8D, 0x43, 0xE1, 0x84, 0x8E, 0x43, + 0xE1, 0x84, 0x8F, 0x43, 0xE1, 0x84, 0x90, 0x43, + 0xE1, 0x84, 0x91, 0x43, 0xE1, 0x84, 0x92, 0x43, + 0xE1, 0x84, 0x94, 0x43, 0xE1, 0x84, 0x95, 0x43, + 0xE1, 0x84, 0x9A, 0x43, 0xE1, 0x84, 0x9C, 0x43, + 0xE1, 0x84, 0x9D, 0x43, 0xE1, 0x84, 0x9E, 0x43, + 0xE1, 0x84, 0xA0, 0x43, 0xE1, 0x84, 0xA1, 0x43, + // Bytes 380 - 3bf + 0xE1, 0x84, 0xA2, 0x43, 0xE1, 0x84, 0xA3, 0x43, + 0xE1, 0x84, 0xA7, 0x43, 0xE1, 0x84, 0xA9, 0x43, + 0xE1, 0x84, 0xAB, 0x43, 0xE1, 0x84, 0xAC, 0x43, + 0xE1, 0x84, 0xAD, 0x43, 0xE1, 0x84, 0xAE, 0x43, + 0xE1, 0x84, 0xAF, 0x43, 0xE1, 0x84, 0xB2, 0x43, + 0xE1, 0x84, 0xB6, 0x43, 0xE1, 0x85, 0x80, 0x43, + 0xE1, 0x85, 0x87, 0x43, 0xE1, 0x85, 0x8C, 0x43, + 0xE1, 0x85, 0x97, 0x43, 0xE1, 0x85, 0x98, 0x43, + // Bytes 3c0 - 3ff + 0xE1, 0x85, 0x99, 0x43, 0xE1, 0x85, 0xA0, 0x43, + 0xE1, 0x86, 0x84, 0x43, 0xE1, 0x86, 0x85, 0x43, + 0xE1, 0x86, 0x88, 0x43, 0xE1, 0x86, 0x91, 0x43, + 0xE1, 0x86, 0x92, 0x43, 0xE1, 0x86, 0x94, 0x43, + 0xE1, 0x86, 0x9E, 0x43, 0xE1, 0x86, 0xA1, 0x43, + 0xE1, 0x87, 0x87, 0x43, 0xE1, 0x87, 0x88, 0x43, + 0xE1, 0x87, 0x8C, 0x43, 0xE1, 0x87, 0x8E, 0x43, + 0xE1, 0x87, 0x93, 0x43, 0xE1, 0x87, 0x97, 0x43, + // Bytes 400 - 43f + 0xE1, 0x87, 0x99, 0x43, 0xE1, 0x87, 0x9D, 0x43, + 0xE1, 0x87, 0x9F, 0x43, 0xE1, 0x87, 0xB1, 0x43, + 0xE1, 0x87, 0xB2, 0x43, 0xE1, 0xB4, 0x82, 0x43, + 0xE1, 0xB4, 0x96, 0x43, 0xE1, 0xB4, 0x97, 0x43, + 0xE1, 0xB4, 0x9C, 0x43, 0xE1, 0xB4, 0x9D, 0x43, + 0xE1, 0xB4, 0xA5, 0x43, 0xE1, 0xB5, 0xBB, 0x43, + 0xE1, 0xB6, 0x85, 0x43, 0xE2, 0x80, 0x82, 0x43, + 0xE2, 0x80, 0x83, 0x43, 0xE2, 0x80, 0x90, 0x43, + // Bytes 440 - 47f + 0xE2, 0x80, 0x93, 0x43, 0xE2, 0x80, 0x94, 0x43, + 0xE2, 0x82, 0xA9, 0x43, 0xE2, 0x86, 0x90, 0x43, + 0xE2, 0x86, 0x91, 0x43, 0xE2, 0x86, 0x92, 0x43, + 0xE2, 0x86, 0x93, 0x43, 0xE2, 0x88, 0x82, 0x43, + 0xE2, 0x88, 0x87, 0x43, 0xE2, 0x88, 0x91, 0x43, + 0xE2, 0x88, 0x92, 0x43, 0xE2, 0x94, 0x82, 0x43, + 0xE2, 0x96, 0xA0, 0x43, 0xE2, 0x97, 0x8B, 0x43, + 0xE2, 0xA6, 0x85, 0x43, 0xE2, 0xA6, 0x86, 0x43, + // Bytes 480 - 4bf + 0xE2, 0xB5, 0xA1, 0x43, 0xE3, 0x80, 0x81, 0x43, + 0xE3, 0x80, 0x82, 0x43, 0xE3, 0x80, 0x88, 0x43, + 0xE3, 0x80, 0x89, 0x43, 0xE3, 0x80, 0x8A, 0x43, + 0xE3, 0x80, 0x8B, 0x43, 0xE3, 0x80, 0x8C, 0x43, + 0xE3, 0x80, 0x8D, 0x43, 0xE3, 0x80, 0x8E, 0x43, + 0xE3, 0x80, 0x8F, 0x43, 0xE3, 0x80, 0x90, 0x43, + 0xE3, 0x80, 0x91, 0x43, 0xE3, 0x80, 0x92, 0x43, + 0xE3, 0x80, 0x94, 0x43, 0xE3, 0x80, 0x95, 0x43, + // Bytes 4c0 - 4ff + 0xE3, 0x80, 0x96, 0x43, 0xE3, 0x80, 0x97, 0x43, + 0xE3, 0x82, 0xA1, 0x43, 0xE3, 0x82, 0xA2, 0x43, + 0xE3, 0x82, 0xA3, 0x43, 0xE3, 0x82, 0xA4, 0x43, + 0xE3, 0x82, 0xA5, 0x43, 0xE3, 0x82, 0xA6, 0x43, + 0xE3, 0x82, 0xA7, 0x43, 0xE3, 0x82, 0xA8, 0x43, + 0xE3, 0x82, 0xA9, 0x43, 0xE3, 0x82, 0xAA, 0x43, + 0xE3, 0x82, 0xAB, 0x43, 0xE3, 0x82, 0xAD, 0x43, + 0xE3, 0x82, 0xAF, 0x43, 0xE3, 0x82, 0xB1, 0x43, + // Bytes 500 - 53f + 0xE3, 0x82, 0xB3, 0x43, 0xE3, 0x82, 0xB5, 0x43, + 0xE3, 0x82, 0xB7, 0x43, 0xE3, 0x82, 0xB9, 0x43, + 0xE3, 0x82, 0xBB, 0x43, 0xE3, 0x82, 0xBD, 0x43, + 0xE3, 0x82, 0xBF, 0x43, 0xE3, 0x83, 0x81, 0x43, + 0xE3, 0x83, 0x83, 0x43, 0xE3, 0x83, 0x84, 0x43, + 0xE3, 0x83, 0x86, 0x43, 0xE3, 0x83, 0x88, 0x43, + 0xE3, 0x83, 0x8A, 0x43, 0xE3, 0x83, 0x8B, 0x43, + 0xE3, 0x83, 0x8C, 0x43, 0xE3, 0x83, 0x8D, 0x43, + // Bytes 540 - 57f + 0xE3, 0x83, 0x8E, 0x43, 0xE3, 0x83, 0x8F, 0x43, + 0xE3, 0x83, 0x92, 0x43, 0xE3, 0x83, 0x95, 0x43, + 0xE3, 0x83, 0x98, 0x43, 0xE3, 0x83, 0x9B, 0x43, + 0xE3, 0x83, 0x9E, 0x43, 0xE3, 0x83, 0x9F, 0x43, + 0xE3, 0x83, 0xA0, 0x43, 0xE3, 0x83, 0xA1, 0x43, + 0xE3, 0x83, 0xA2, 0x43, 0xE3, 0x83, 0xA3, 0x43, + 0xE3, 0x83, 0xA4, 0x43, 0xE3, 0x83, 0xA5, 0x43, + 0xE3, 0x83, 0xA6, 0x43, 0xE3, 0x83, 0xA7, 0x43, + // Bytes 580 - 5bf + 0xE3, 0x83, 0xA8, 0x43, 0xE3, 0x83, 0xA9, 0x43, + 0xE3, 0x83, 0xAA, 0x43, 0xE3, 0x83, 0xAB, 0x43, + 0xE3, 0x83, 0xAC, 0x43, 0xE3, 0x83, 0xAD, 0x43, + 0xE3, 0x83, 0xAF, 0x43, 0xE3, 0x83, 0xB0, 0x43, + 0xE3, 0x83, 0xB1, 0x43, 0xE3, 0x83, 0xB2, 0x43, + 0xE3, 0x83, 0xB3, 0x43, 0xE3, 0x83, 0xBB, 0x43, + 0xE3, 0x83, 0xBC, 0x43, 0xE3, 0x92, 0x9E, 0x43, + 0xE3, 0x92, 0xB9, 0x43, 0xE3, 0x92, 0xBB, 0x43, + // Bytes 5c0 - 5ff + 0xE3, 0x93, 0x9F, 0x43, 0xE3, 0x94, 0x95, 0x43, + 0xE3, 0x9B, 0xAE, 0x43, 0xE3, 0x9B, 0xBC, 0x43, + 0xE3, 0x9E, 0x81, 0x43, 0xE3, 0xA0, 0xAF, 0x43, + 0xE3, 0xA1, 0xA2, 0x43, 0xE3, 0xA1, 0xBC, 0x43, + 0xE3, 0xA3, 0x87, 0x43, 0xE3, 0xA3, 0xA3, 0x43, + 0xE3, 0xA4, 0x9C, 0x43, 0xE3, 0xA4, 0xBA, 0x43, + 0xE3, 0xA8, 0xAE, 0x43, 0xE3, 0xA9, 0xAC, 0x43, + 0xE3, 0xAB, 0xA4, 0x43, 0xE3, 0xAC, 0x88, 0x43, + // Bytes 600 - 63f + 0xE3, 0xAC, 0x99, 0x43, 0xE3, 0xAD, 0x89, 0x43, + 0xE3, 0xAE, 0x9D, 0x43, 0xE3, 0xB0, 0x98, 0x43, + 0xE3, 0xB1, 0x8E, 0x43, 0xE3, 0xB4, 0xB3, 0x43, + 0xE3, 0xB6, 0x96, 0x43, 0xE3, 0xBA, 0xAC, 0x43, + 0xE3, 0xBA, 0xB8, 0x43, 0xE3, 0xBC, 0x9B, 0x43, + 0xE3, 0xBF, 0xBC, 0x43, 0xE4, 0x80, 0x88, 0x43, + 0xE4, 0x80, 0x98, 0x43, 0xE4, 0x80, 0xB9, 0x43, + 0xE4, 0x81, 0x86, 0x43, 0xE4, 0x82, 0x96, 0x43, + // Bytes 640 - 67f + 0xE4, 0x83, 0xA3, 0x43, 0xE4, 0x84, 0xAF, 0x43, + 0xE4, 0x88, 0x82, 0x43, 0xE4, 0x88, 0xA7, 0x43, + 0xE4, 0x8A, 0xA0, 0x43, 0xE4, 0x8C, 0x81, 0x43, + 0xE4, 0x8C, 0xB4, 0x43, 0xE4, 0x8D, 0x99, 0x43, + 0xE4, 0x8F, 0x95, 0x43, 0xE4, 0x8F, 0x99, 0x43, + 0xE4, 0x90, 0x8B, 0x43, 0xE4, 0x91, 0xAB, 0x43, + 0xE4, 0x94, 0xAB, 0x43, 0xE4, 0x95, 0x9D, 0x43, + 0xE4, 0x95, 0xA1, 0x43, 0xE4, 0x95, 0xAB, 0x43, + // Bytes 680 - 6bf + 0xE4, 0x97, 0x97, 0x43, 0xE4, 0x97, 0xB9, 0x43, + 0xE4, 0x98, 0xB5, 0x43, 0xE4, 0x9A, 0xBE, 0x43, + 0xE4, 0x9B, 0x87, 0x43, 0xE4, 0xA6, 0x95, 0x43, + 0xE4, 0xA7, 0xA6, 0x43, 0xE4, 0xA9, 0xAE, 0x43, + 0xE4, 0xA9, 0xB6, 0x43, 0xE4, 0xAA, 0xB2, 0x43, + 0xE4, 0xAC, 0xB3, 0x43, 0xE4, 0xAF, 0x8E, 0x43, + 0xE4, 0xB3, 0x8E, 0x43, 0xE4, 0xB3, 0xAD, 0x43, + 0xE4, 0xB3, 0xB8, 0x43, 0xE4, 0xB5, 0x96, 0x43, + // Bytes 6c0 - 6ff + 0xE4, 0xB8, 0x80, 0x43, 0xE4, 0xB8, 0x81, 0x43, + 0xE4, 0xB8, 0x83, 0x43, 0xE4, 0xB8, 0x89, 0x43, + 0xE4, 0xB8, 0x8A, 0x43, 0xE4, 0xB8, 0x8B, 0x43, + 0xE4, 0xB8, 0x8D, 0x43, 0xE4, 0xB8, 0x99, 0x43, + 0xE4, 0xB8, 0xA6, 0x43, 0xE4, 0xB8, 0xA8, 0x43, + 0xE4, 0xB8, 0xAD, 0x43, 0xE4, 0xB8, 0xB2, 0x43, + 0xE4, 0xB8, 0xB6, 0x43, 0xE4, 0xB8, 0xB8, 0x43, + 0xE4, 0xB8, 0xB9, 0x43, 0xE4, 0xB8, 0xBD, 0x43, + // Bytes 700 - 73f + 0xE4, 0xB8, 0xBF, 0x43, 0xE4, 0xB9, 0x81, 0x43, + 0xE4, 0xB9, 0x99, 0x43, 0xE4, 0xB9, 0x9D, 0x43, + 0xE4, 0xBA, 0x82, 0x43, 0xE4, 0xBA, 0x85, 0x43, + 0xE4, 0xBA, 0x86, 0x43, 0xE4, 0xBA, 0x8C, 0x43, + 0xE4, 0xBA, 0x94, 0x43, 0xE4, 0xBA, 0xA0, 0x43, + 0xE4, 0xBA, 0xA4, 0x43, 0xE4, 0xBA, 0xAE, 0x43, + 0xE4, 0xBA, 0xBA, 0x43, 0xE4, 0xBB, 0x80, 0x43, + 0xE4, 0xBB, 0x8C, 0x43, 0xE4, 0xBB, 0xA4, 0x43, + // Bytes 740 - 77f + 0xE4, 0xBC, 0x81, 0x43, 0xE4, 0xBC, 0x91, 0x43, + 0xE4, 0xBD, 0xA0, 0x43, 0xE4, 0xBE, 0x80, 0x43, + 0xE4, 0xBE, 0x86, 0x43, 0xE4, 0xBE, 0x8B, 0x43, + 0xE4, 0xBE, 0xAE, 0x43, 0xE4, 0xBE, 0xBB, 0x43, + 0xE4, 0xBE, 0xBF, 0x43, 0xE5, 0x80, 0x82, 0x43, + 0xE5, 0x80, 0xAB, 0x43, 0xE5, 0x81, 0xBA, 0x43, + 0xE5, 0x82, 0x99, 0x43, 0xE5, 0x83, 0x8F, 0x43, + 0xE5, 0x83, 0x9A, 0x43, 0xE5, 0x83, 0xA7, 0x43, + // Bytes 780 - 7bf + 0xE5, 0x84, 0xAA, 0x43, 0xE5, 0x84, 0xBF, 0x43, + 0xE5, 0x85, 0x80, 0x43, 0xE5, 0x85, 0x85, 0x43, + 0xE5, 0x85, 0x8D, 0x43, 0xE5, 0x85, 0x94, 0x43, + 0xE5, 0x85, 0xA4, 0x43, 0xE5, 0x85, 0xA5, 0x43, + 0xE5, 0x85, 0xA7, 0x43, 0xE5, 0x85, 0xA8, 0x43, + 0xE5, 0x85, 0xA9, 0x43, 0xE5, 0x85, 0xAB, 0x43, + 0xE5, 0x85, 0xAD, 0x43, 0xE5, 0x85, 0xB7, 0x43, + 0xE5, 0x86, 0x80, 0x43, 0xE5, 0x86, 0x82, 0x43, + // Bytes 7c0 - 7ff + 0xE5, 0x86, 0x8D, 0x43, 0xE5, 0x86, 0x92, 0x43, + 0xE5, 0x86, 0x95, 0x43, 0xE5, 0x86, 0x96, 0x43, + 0xE5, 0x86, 0x97, 0x43, 0xE5, 0x86, 0x99, 0x43, + 0xE5, 0x86, 0xA4, 0x43, 0xE5, 0x86, 0xAB, 0x43, + 0xE5, 0x86, 0xAC, 0x43, 0xE5, 0x86, 0xB5, 0x43, + 0xE5, 0x86, 0xB7, 0x43, 0xE5, 0x87, 0x89, 0x43, + 0xE5, 0x87, 0x8C, 0x43, 0xE5, 0x87, 0x9C, 0x43, + 0xE5, 0x87, 0x9E, 0x43, 0xE5, 0x87, 0xA0, 0x43, + // Bytes 800 - 83f + 0xE5, 0x87, 0xB5, 0x43, 0xE5, 0x88, 0x80, 0x43, + 0xE5, 0x88, 0x83, 0x43, 0xE5, 0x88, 0x87, 0x43, + 0xE5, 0x88, 0x97, 0x43, 0xE5, 0x88, 0x9D, 0x43, + 0xE5, 0x88, 0xA9, 0x43, 0xE5, 0x88, 0xBA, 0x43, + 0xE5, 0x88, 0xBB, 0x43, 0xE5, 0x89, 0x86, 0x43, + 0xE5, 0x89, 0x8D, 0x43, 0xE5, 0x89, 0xB2, 0x43, + 0xE5, 0x89, 0xB7, 0x43, 0xE5, 0x8A, 0x89, 0x43, + 0xE5, 0x8A, 0x9B, 0x43, 0xE5, 0x8A, 0xA3, 0x43, + // Bytes 840 - 87f + 0xE5, 0x8A, 0xB3, 0x43, 0xE5, 0x8A, 0xB4, 0x43, + 0xE5, 0x8B, 0x87, 0x43, 0xE5, 0x8B, 0x89, 0x43, + 0xE5, 0x8B, 0x92, 0x43, 0xE5, 0x8B, 0x9E, 0x43, + 0xE5, 0x8B, 0xA4, 0x43, 0xE5, 0x8B, 0xB5, 0x43, + 0xE5, 0x8B, 0xB9, 0x43, 0xE5, 0x8B, 0xBA, 0x43, + 0xE5, 0x8C, 0x85, 0x43, 0xE5, 0x8C, 0x86, 0x43, + 0xE5, 0x8C, 0x95, 0x43, 0xE5, 0x8C, 0x97, 0x43, + 0xE5, 0x8C, 0x9A, 0x43, 0xE5, 0x8C, 0xB8, 0x43, + // Bytes 880 - 8bf + 0xE5, 0x8C, 0xBB, 0x43, 0xE5, 0x8C, 0xBF, 0x43, + 0xE5, 0x8D, 0x81, 0x43, 0xE5, 0x8D, 0x84, 0x43, + 0xE5, 0x8D, 0x85, 0x43, 0xE5, 0x8D, 0x89, 0x43, + 0xE5, 0x8D, 0x91, 0x43, 0xE5, 0x8D, 0x94, 0x43, + 0xE5, 0x8D, 0x9A, 0x43, 0xE5, 0x8D, 0x9C, 0x43, + 0xE5, 0x8D, 0xA9, 0x43, 0xE5, 0x8D, 0xB0, 0x43, + 0xE5, 0x8D, 0xB3, 0x43, 0xE5, 0x8D, 0xB5, 0x43, + 0xE5, 0x8D, 0xBD, 0x43, 0xE5, 0x8D, 0xBF, 0x43, + // Bytes 8c0 - 8ff + 0xE5, 0x8E, 0x82, 0x43, 0xE5, 0x8E, 0xB6, 0x43, + 0xE5, 0x8F, 0x83, 0x43, 0xE5, 0x8F, 0x88, 0x43, + 0xE5, 0x8F, 0x8A, 0x43, 0xE5, 0x8F, 0x8C, 0x43, + 0xE5, 0x8F, 0x9F, 0x43, 0xE5, 0x8F, 0xA3, 0x43, + 0xE5, 0x8F, 0xA5, 0x43, 0xE5, 0x8F, 0xAB, 0x43, + 0xE5, 0x8F, 0xAF, 0x43, 0xE5, 0x8F, 0xB1, 0x43, + 0xE5, 0x8F, 0xB3, 0x43, 0xE5, 0x90, 0x86, 0x43, + 0xE5, 0x90, 0x88, 0x43, 0xE5, 0x90, 0x8D, 0x43, + // Bytes 900 - 93f + 0xE5, 0x90, 0x8F, 0x43, 0xE5, 0x90, 0x9D, 0x43, + 0xE5, 0x90, 0xB8, 0x43, 0xE5, 0x90, 0xB9, 0x43, + 0xE5, 0x91, 0x82, 0x43, 0xE5, 0x91, 0x88, 0x43, + 0xE5, 0x91, 0xA8, 0x43, 0xE5, 0x92, 0x9E, 0x43, + 0xE5, 0x92, 0xA2, 0x43, 0xE5, 0x92, 0xBD, 0x43, + 0xE5, 0x93, 0xB6, 0x43, 0xE5, 0x94, 0x90, 0x43, + 0xE5, 0x95, 0x8F, 0x43, 0xE5, 0x95, 0x93, 0x43, + 0xE5, 0x95, 0x95, 0x43, 0xE5, 0x95, 0xA3, 0x43, + // Bytes 940 - 97f + 0xE5, 0x96, 0x84, 0x43, 0xE5, 0x96, 0x87, 0x43, + 0xE5, 0x96, 0x99, 0x43, 0xE5, 0x96, 0x9D, 0x43, + 0xE5, 0x96, 0xAB, 0x43, 0xE5, 0x96, 0xB3, 0x43, + 0xE5, 0x96, 0xB6, 0x43, 0xE5, 0x97, 0x80, 0x43, + 0xE5, 0x97, 0x82, 0x43, 0xE5, 0x97, 0xA2, 0x43, + 0xE5, 0x98, 0x86, 0x43, 0xE5, 0x99, 0x91, 0x43, + 0xE5, 0x99, 0xA8, 0x43, 0xE5, 0x99, 0xB4, 0x43, + 0xE5, 0x9B, 0x97, 0x43, 0xE5, 0x9B, 0x9B, 0x43, + // Bytes 980 - 9bf + 0xE5, 0x9B, 0xB9, 0x43, 0xE5, 0x9C, 0x96, 0x43, + 0xE5, 0x9C, 0x97, 0x43, 0xE5, 0x9C, 0x9F, 0x43, + 0xE5, 0x9C, 0xB0, 0x43, 0xE5, 0x9E, 0x8B, 0x43, + 0xE5, 0x9F, 0x8E, 0x43, 0xE5, 0x9F, 0xB4, 0x43, + 0xE5, 0xA0, 0x8D, 0x43, 0xE5, 0xA0, 0xB1, 0x43, + 0xE5, 0xA0, 0xB2, 0x43, 0xE5, 0xA1, 0x80, 0x43, + 0xE5, 0xA1, 0x9A, 0x43, 0xE5, 0xA1, 0x9E, 0x43, + 0xE5, 0xA2, 0xA8, 0x43, 0xE5, 0xA2, 0xAC, 0x43, + // Bytes 9c0 - 9ff + 0xE5, 0xA2, 0xB3, 0x43, 0xE5, 0xA3, 0x98, 0x43, + 0xE5, 0xA3, 0x9F, 0x43, 0xE5, 0xA3, 0xAB, 0x43, + 0xE5, 0xA3, 0xAE, 0x43, 0xE5, 0xA3, 0xB0, 0x43, + 0xE5, 0xA3, 0xB2, 0x43, 0xE5, 0xA3, 0xB7, 0x43, + 0xE5, 0xA4, 0x82, 0x43, 0xE5, 0xA4, 0x86, 0x43, + 0xE5, 0xA4, 0x8A, 0x43, 0xE5, 0xA4, 0x95, 0x43, + 0xE5, 0xA4, 0x9A, 0x43, 0xE5, 0xA4, 0x9C, 0x43, + 0xE5, 0xA4, 0xA2, 0x43, 0xE5, 0xA4, 0xA7, 0x43, + // Bytes a00 - a3f + 0xE5, 0xA4, 0xA9, 0x43, 0xE5, 0xA5, 0x84, 0x43, + 0xE5, 0xA5, 0x88, 0x43, 0xE5, 0xA5, 0x91, 0x43, + 0xE5, 0xA5, 0x94, 0x43, 0xE5, 0xA5, 0xA2, 0x43, + 0xE5, 0xA5, 0xB3, 0x43, 0xE5, 0xA7, 0x98, 0x43, + 0xE5, 0xA7, 0xAC, 0x43, 0xE5, 0xA8, 0x9B, 0x43, + 0xE5, 0xA8, 0xA7, 0x43, 0xE5, 0xA9, 0xA2, 0x43, + 0xE5, 0xA9, 0xA6, 0x43, 0xE5, 0xAA, 0xB5, 0x43, + 0xE5, 0xAC, 0x88, 0x43, 0xE5, 0xAC, 0xA8, 0x43, + // Bytes a40 - a7f + 0xE5, 0xAC, 0xBE, 0x43, 0xE5, 0xAD, 0x90, 0x43, + 0xE5, 0xAD, 0x97, 0x43, 0xE5, 0xAD, 0xA6, 0x43, + 0xE5, 0xAE, 0x80, 0x43, 0xE5, 0xAE, 0x85, 0x43, + 0xE5, 0xAE, 0x97, 0x43, 0xE5, 0xAF, 0x83, 0x43, + 0xE5, 0xAF, 0x98, 0x43, 0xE5, 0xAF, 0xA7, 0x43, + 0xE5, 0xAF, 0xAE, 0x43, 0xE5, 0xAF, 0xB3, 0x43, + 0xE5, 0xAF, 0xB8, 0x43, 0xE5, 0xAF, 0xBF, 0x43, + 0xE5, 0xB0, 0x86, 0x43, 0xE5, 0xB0, 0x8F, 0x43, + // Bytes a80 - abf + 0xE5, 0xB0, 0xA2, 0x43, 0xE5, 0xB0, 0xB8, 0x43, + 0xE5, 0xB0, 0xBF, 0x43, 0xE5, 0xB1, 0xA0, 0x43, + 0xE5, 0xB1, 0xA2, 0x43, 0xE5, 0xB1, 0xA4, 0x43, + 0xE5, 0xB1, 0xA5, 0x43, 0xE5, 0xB1, 0xAE, 0x43, + 0xE5, 0xB1, 0xB1, 0x43, 0xE5, 0xB2, 0x8D, 0x43, + 0xE5, 0xB3, 0x80, 0x43, 0xE5, 0xB4, 0x99, 0x43, + 0xE5, 0xB5, 0x83, 0x43, 0xE5, 0xB5, 0x90, 0x43, + 0xE5, 0xB5, 0xAB, 0x43, 0xE5, 0xB5, 0xAE, 0x43, + // Bytes ac0 - aff + 0xE5, 0xB5, 0xBC, 0x43, 0xE5, 0xB6, 0xB2, 0x43, + 0xE5, 0xB6, 0xBA, 0x43, 0xE5, 0xB7, 0x9B, 0x43, + 0xE5, 0xB7, 0xA1, 0x43, 0xE5, 0xB7, 0xA2, 0x43, + 0xE5, 0xB7, 0xA5, 0x43, 0xE5, 0xB7, 0xA6, 0x43, + 0xE5, 0xB7, 0xB1, 0x43, 0xE5, 0xB7, 0xBD, 0x43, + 0xE5, 0xB7, 0xBE, 0x43, 0xE5, 0xB8, 0xA8, 0x43, + 0xE5, 0xB8, 0xBD, 0x43, 0xE5, 0xB9, 0xA9, 0x43, + 0xE5, 0xB9, 0xB2, 0x43, 0xE5, 0xB9, 0xB4, 0x43, + // Bytes b00 - b3f + 0xE5, 0xB9, 0xBA, 0x43, 0xE5, 0xB9, 0xBC, 0x43, + 0xE5, 0xB9, 0xBF, 0x43, 0xE5, 0xBA, 0xA6, 0x43, + 0xE5, 0xBA, 0xB0, 0x43, 0xE5, 0xBA, 0xB3, 0x43, + 0xE5, 0xBA, 0xB6, 0x43, 0xE5, 0xBB, 0x89, 0x43, + 0xE5, 0xBB, 0x8A, 0x43, 0xE5, 0xBB, 0x92, 0x43, + 0xE5, 0xBB, 0x93, 0x43, 0xE5, 0xBB, 0x99, 0x43, + 0xE5, 0xBB, 0xAC, 0x43, 0xE5, 0xBB, 0xB4, 0x43, + 0xE5, 0xBB, 0xBE, 0x43, 0xE5, 0xBC, 0x84, 0x43, + // Bytes b40 - b7f + 0xE5, 0xBC, 0x8B, 0x43, 0xE5, 0xBC, 0x93, 0x43, + 0xE5, 0xBC, 0xA2, 0x43, 0xE5, 0xBD, 0x90, 0x43, + 0xE5, 0xBD, 0x93, 0x43, 0xE5, 0xBD, 0xA1, 0x43, + 0xE5, 0xBD, 0xA2, 0x43, 0xE5, 0xBD, 0xA9, 0x43, + 0xE5, 0xBD, 0xAB, 0x43, 0xE5, 0xBD, 0xB3, 0x43, + 0xE5, 0xBE, 0x8B, 0x43, 0xE5, 0xBE, 0x8C, 0x43, + 0xE5, 0xBE, 0x97, 0x43, 0xE5, 0xBE, 0x9A, 0x43, + 0xE5, 0xBE, 0xA9, 0x43, 0xE5, 0xBE, 0xAD, 0x43, + // Bytes b80 - bbf + 0xE5, 0xBF, 0x83, 0x43, 0xE5, 0xBF, 0x8D, 0x43, + 0xE5, 0xBF, 0x97, 0x43, 0xE5, 0xBF, 0xB5, 0x43, + 0xE5, 0xBF, 0xB9, 0x43, 0xE6, 0x80, 0x92, 0x43, + 0xE6, 0x80, 0x9C, 0x43, 0xE6, 0x81, 0xB5, 0x43, + 0xE6, 0x82, 0x81, 0x43, 0xE6, 0x82, 0x94, 0x43, + 0xE6, 0x83, 0x87, 0x43, 0xE6, 0x83, 0x98, 0x43, + 0xE6, 0x83, 0xA1, 0x43, 0xE6, 0x84, 0x88, 0x43, + 0xE6, 0x85, 0x84, 0x43, 0xE6, 0x85, 0x88, 0x43, + // Bytes bc0 - bff + 0xE6, 0x85, 0x8C, 0x43, 0xE6, 0x85, 0x8E, 0x43, + 0xE6, 0x85, 0xA0, 0x43, 0xE6, 0x85, 0xA8, 0x43, + 0xE6, 0x85, 0xBA, 0x43, 0xE6, 0x86, 0x8E, 0x43, + 0xE6, 0x86, 0x90, 0x43, 0xE6, 0x86, 0xA4, 0x43, + 0xE6, 0x86, 0xAF, 0x43, 0xE6, 0x86, 0xB2, 0x43, + 0xE6, 0x87, 0x9E, 0x43, 0xE6, 0x87, 0xB2, 0x43, + 0xE6, 0x87, 0xB6, 0x43, 0xE6, 0x88, 0x80, 0x43, + 0xE6, 0x88, 0x88, 0x43, 0xE6, 0x88, 0x90, 0x43, + // Bytes c00 - c3f + 0xE6, 0x88, 0x9B, 0x43, 0xE6, 0x88, 0xAE, 0x43, + 0xE6, 0x88, 0xB4, 0x43, 0xE6, 0x88, 0xB6, 0x43, + 0xE6, 0x89, 0x8B, 0x43, 0xE6, 0x89, 0x93, 0x43, + 0xE6, 0x89, 0x9D, 0x43, 0xE6, 0x8A, 0x95, 0x43, + 0xE6, 0x8A, 0xB1, 0x43, 0xE6, 0x8B, 0x89, 0x43, + 0xE6, 0x8B, 0x8F, 0x43, 0xE6, 0x8B, 0x93, 0x43, + 0xE6, 0x8B, 0x94, 0x43, 0xE6, 0x8B, 0xBC, 0x43, + 0xE6, 0x8B, 0xBE, 0x43, 0xE6, 0x8C, 0x87, 0x43, + // Bytes c40 - c7f + 0xE6, 0x8C, 0xBD, 0x43, 0xE6, 0x8D, 0x90, 0x43, + 0xE6, 0x8D, 0x95, 0x43, 0xE6, 0x8D, 0xA8, 0x43, + 0xE6, 0x8D, 0xBB, 0x43, 0xE6, 0x8E, 0x83, 0x43, + 0xE6, 0x8E, 0xA0, 0x43, 0xE6, 0x8E, 0xA9, 0x43, + 0xE6, 0x8F, 0x84, 0x43, 0xE6, 0x8F, 0x85, 0x43, + 0xE6, 0x8F, 0xA4, 0x43, 0xE6, 0x90, 0x9C, 0x43, + 0xE6, 0x90, 0xA2, 0x43, 0xE6, 0x91, 0x92, 0x43, + 0xE6, 0x91, 0xA9, 0x43, 0xE6, 0x91, 0xB7, 0x43, + // Bytes c80 - cbf + 0xE6, 0x91, 0xBE, 0x43, 0xE6, 0x92, 0x9A, 0x43, + 0xE6, 0x92, 0x9D, 0x43, 0xE6, 0x93, 0x84, 0x43, + 0xE6, 0x94, 0xAF, 0x43, 0xE6, 0x94, 0xB4, 0x43, + 0xE6, 0x95, 0x8F, 0x43, 0xE6, 0x95, 0x96, 0x43, + 0xE6, 0x95, 0xAC, 0x43, 0xE6, 0x95, 0xB8, 0x43, + 0xE6, 0x96, 0x87, 0x43, 0xE6, 0x96, 0x97, 0x43, + 0xE6, 0x96, 0x99, 0x43, 0xE6, 0x96, 0xA4, 0x43, + 0xE6, 0x96, 0xB0, 0x43, 0xE6, 0x96, 0xB9, 0x43, + // Bytes cc0 - cff + 0xE6, 0x97, 0x85, 0x43, 0xE6, 0x97, 0xA0, 0x43, + 0xE6, 0x97, 0xA2, 0x43, 0xE6, 0x97, 0xA3, 0x43, + 0xE6, 0x97, 0xA5, 0x43, 0xE6, 0x98, 0x93, 0x43, + 0xE6, 0x98, 0xA0, 0x43, 0xE6, 0x99, 0x89, 0x43, + 0xE6, 0x99, 0xB4, 0x43, 0xE6, 0x9A, 0x88, 0x43, + 0xE6, 0x9A, 0x91, 0x43, 0xE6, 0x9A, 0x9C, 0x43, + 0xE6, 0x9A, 0xB4, 0x43, 0xE6, 0x9B, 0x86, 0x43, + 0xE6, 0x9B, 0xB0, 0x43, 0xE6, 0x9B, 0xB4, 0x43, + // Bytes d00 - d3f + 0xE6, 0x9B, 0xB8, 0x43, 0xE6, 0x9C, 0x80, 0x43, + 0xE6, 0x9C, 0x88, 0x43, 0xE6, 0x9C, 0x89, 0x43, + 0xE6, 0x9C, 0x97, 0x43, 0xE6, 0x9C, 0x9B, 0x43, + 0xE6, 0x9C, 0xA1, 0x43, 0xE6, 0x9C, 0xA8, 0x43, + 0xE6, 0x9D, 0x8E, 0x43, 0xE6, 0x9D, 0x93, 0x43, + 0xE6, 0x9D, 0x96, 0x43, 0xE6, 0x9D, 0x9E, 0x43, + 0xE6, 0x9D, 0xBB, 0x43, 0xE6, 0x9E, 0x85, 0x43, + 0xE6, 0x9E, 0x97, 0x43, 0xE6, 0x9F, 0xB3, 0x43, + // Bytes d40 - d7f + 0xE6, 0x9F, 0xBA, 0x43, 0xE6, 0xA0, 0x97, 0x43, + 0xE6, 0xA0, 0x9F, 0x43, 0xE6, 0xA0, 0xAA, 0x43, + 0xE6, 0xA1, 0x92, 0x43, 0xE6, 0xA2, 0x81, 0x43, + 0xE6, 0xA2, 0x85, 0x43, 0xE6, 0xA2, 0x8E, 0x43, + 0xE6, 0xA2, 0xA8, 0x43, 0xE6, 0xA4, 0x94, 0x43, + 0xE6, 0xA5, 0x82, 0x43, 0xE6, 0xA6, 0xA3, 0x43, + 0xE6, 0xA7, 0xAA, 0x43, 0xE6, 0xA8, 0x82, 0x43, + 0xE6, 0xA8, 0x93, 0x43, 0xE6, 0xAA, 0xA8, 0x43, + // Bytes d80 - dbf + 0xE6, 0xAB, 0x93, 0x43, 0xE6, 0xAB, 0x9B, 0x43, + 0xE6, 0xAC, 0x84, 0x43, 0xE6, 0xAC, 0xA0, 0x43, + 0xE6, 0xAC, 0xA1, 0x43, 0xE6, 0xAD, 0x94, 0x43, + 0xE6, 0xAD, 0xA2, 0x43, 0xE6, 0xAD, 0xA3, 0x43, + 0xE6, 0xAD, 0xB2, 0x43, 0xE6, 0xAD, 0xB7, 0x43, + 0xE6, 0xAD, 0xB9, 0x43, 0xE6, 0xAE, 0x9F, 0x43, + 0xE6, 0xAE, 0xAE, 0x43, 0xE6, 0xAE, 0xB3, 0x43, + 0xE6, 0xAE, 0xBA, 0x43, 0xE6, 0xAE, 0xBB, 0x43, + // Bytes dc0 - dff + 0xE6, 0xAF, 0x8B, 0x43, 0xE6, 0xAF, 0x8D, 0x43, + 0xE6, 0xAF, 0x94, 0x43, 0xE6, 0xAF, 0x9B, 0x43, + 0xE6, 0xB0, 0x8F, 0x43, 0xE6, 0xB0, 0x94, 0x43, + 0xE6, 0xB0, 0xB4, 0x43, 0xE6, 0xB1, 0x8E, 0x43, + 0xE6, 0xB1, 0xA7, 0x43, 0xE6, 0xB2, 0x88, 0x43, + 0xE6, 0xB2, 0xBF, 0x43, 0xE6, 0xB3, 0x8C, 0x43, + 0xE6, 0xB3, 0x8D, 0x43, 0xE6, 0xB3, 0xA5, 0x43, + 0xE6, 0xB3, 0xA8, 0x43, 0xE6, 0xB4, 0x96, 0x43, + // Bytes e00 - e3f + 0xE6, 0xB4, 0x9B, 0x43, 0xE6, 0xB4, 0x9E, 0x43, + 0xE6, 0xB4, 0xB4, 0x43, 0xE6, 0xB4, 0xBE, 0x43, + 0xE6, 0xB5, 0x81, 0x43, 0xE6, 0xB5, 0xA9, 0x43, + 0xE6, 0xB5, 0xAA, 0x43, 0xE6, 0xB5, 0xB7, 0x43, + 0xE6, 0xB5, 0xB8, 0x43, 0xE6, 0xB6, 0x85, 0x43, + 0xE6, 0xB7, 0x8B, 0x43, 0xE6, 0xB7, 0x9A, 0x43, + 0xE6, 0xB7, 0xAA, 0x43, 0xE6, 0xB7, 0xB9, 0x43, + 0xE6, 0xB8, 0x9A, 0x43, 0xE6, 0xB8, 0xAF, 0x43, + // Bytes e40 - e7f + 0xE6, 0xB9, 0xAE, 0x43, 0xE6, 0xBA, 0x80, 0x43, + 0xE6, 0xBA, 0x9C, 0x43, 0xE6, 0xBA, 0xBA, 0x43, + 0xE6, 0xBB, 0x87, 0x43, 0xE6, 0xBB, 0x8B, 0x43, + 0xE6, 0xBB, 0x91, 0x43, 0xE6, 0xBB, 0x9B, 0x43, + 0xE6, 0xBC, 0x8F, 0x43, 0xE6, 0xBC, 0x94, 0x43, + 0xE6, 0xBC, 0xA2, 0x43, 0xE6, 0xBC, 0xA3, 0x43, + 0xE6, 0xBD, 0xAE, 0x43, 0xE6, 0xBF, 0x86, 0x43, + 0xE6, 0xBF, 0xAB, 0x43, 0xE6, 0xBF, 0xBE, 0x43, + // Bytes e80 - ebf + 0xE7, 0x80, 0x9B, 0x43, 0xE7, 0x80, 0x9E, 0x43, + 0xE7, 0x80, 0xB9, 0x43, 0xE7, 0x81, 0x8A, 0x43, + 0xE7, 0x81, 0xAB, 0x43, 0xE7, 0x81, 0xB0, 0x43, + 0xE7, 0x81, 0xB7, 0x43, 0xE7, 0x81, 0xBD, 0x43, + 0xE7, 0x82, 0x99, 0x43, 0xE7, 0x82, 0xAD, 0x43, + 0xE7, 0x83, 0x88, 0x43, 0xE7, 0x83, 0x99, 0x43, + 0xE7, 0x84, 0xA1, 0x43, 0xE7, 0x85, 0x85, 0x43, + 0xE7, 0x85, 0x89, 0x43, 0xE7, 0x85, 0xAE, 0x43, + // Bytes ec0 - eff + 0xE7, 0x86, 0x9C, 0x43, 0xE7, 0x87, 0x8E, 0x43, + 0xE7, 0x87, 0x90, 0x43, 0xE7, 0x88, 0x90, 0x43, + 0xE7, 0x88, 0x9B, 0x43, 0xE7, 0x88, 0xA8, 0x43, + 0xE7, 0x88, 0xAA, 0x43, 0xE7, 0x88, 0xAB, 0x43, + 0xE7, 0x88, 0xB5, 0x43, 0xE7, 0x88, 0xB6, 0x43, + 0xE7, 0x88, 0xBB, 0x43, 0xE7, 0x88, 0xBF, 0x43, + 0xE7, 0x89, 0x87, 0x43, 0xE7, 0x89, 0x90, 0x43, + 0xE7, 0x89, 0x99, 0x43, 0xE7, 0x89, 0x9B, 0x43, + // Bytes f00 - f3f + 0xE7, 0x89, 0xA2, 0x43, 0xE7, 0x89, 0xB9, 0x43, + 0xE7, 0x8A, 0x80, 0x43, 0xE7, 0x8A, 0x95, 0x43, + 0xE7, 0x8A, 0xAC, 0x43, 0xE7, 0x8A, 0xAF, 0x43, + 0xE7, 0x8B, 0x80, 0x43, 0xE7, 0x8B, 0xBC, 0x43, + 0xE7, 0x8C, 0xAA, 0x43, 0xE7, 0x8D, 0xB5, 0x43, + 0xE7, 0x8D, 0xBA, 0x43, 0xE7, 0x8E, 0x84, 0x43, + 0xE7, 0x8E, 0x87, 0x43, 0xE7, 0x8E, 0x89, 0x43, + 0xE7, 0x8E, 0x8B, 0x43, 0xE7, 0x8E, 0xA5, 0x43, + // Bytes f40 - f7f + 0xE7, 0x8E, 0xB2, 0x43, 0xE7, 0x8F, 0x9E, 0x43, + 0xE7, 0x90, 0x86, 0x43, 0xE7, 0x90, 0x89, 0x43, + 0xE7, 0x90, 0xA2, 0x43, 0xE7, 0x91, 0x87, 0x43, + 0xE7, 0x91, 0x9C, 0x43, 0xE7, 0x91, 0xA9, 0x43, + 0xE7, 0x91, 0xB1, 0x43, 0xE7, 0x92, 0x85, 0x43, + 0xE7, 0x92, 0x89, 0x43, 0xE7, 0x92, 0x98, 0x43, + 0xE7, 0x93, 0x8A, 0x43, 0xE7, 0x93, 0x9C, 0x43, + 0xE7, 0x93, 0xA6, 0x43, 0xE7, 0x94, 0x86, 0x43, + // Bytes f80 - fbf + 0xE7, 0x94, 0x98, 0x43, 0xE7, 0x94, 0x9F, 0x43, + 0xE7, 0x94, 0xA4, 0x43, 0xE7, 0x94, 0xA8, 0x43, + 0xE7, 0x94, 0xB0, 0x43, 0xE7, 0x94, 0xB2, 0x43, + 0xE7, 0x94, 0xB3, 0x43, 0xE7, 0x94, 0xB7, 0x43, + 0xE7, 0x94, 0xBB, 0x43, 0xE7, 0x94, 0xBE, 0x43, + 0xE7, 0x95, 0x99, 0x43, 0xE7, 0x95, 0xA5, 0x43, + 0xE7, 0x95, 0xB0, 0x43, 0xE7, 0x96, 0x8B, 0x43, + 0xE7, 0x96, 0x92, 0x43, 0xE7, 0x97, 0xA2, 0x43, + // Bytes fc0 - fff + 0xE7, 0x98, 0x90, 0x43, 0xE7, 0x98, 0x9D, 0x43, + 0xE7, 0x98, 0x9F, 0x43, 0xE7, 0x99, 0x82, 0x43, + 0xE7, 0x99, 0xA9, 0x43, 0xE7, 0x99, 0xB6, 0x43, + 0xE7, 0x99, 0xBD, 0x43, 0xE7, 0x9A, 0xAE, 0x43, + 0xE7, 0x9A, 0xBF, 0x43, 0xE7, 0x9B, 0x8A, 0x43, + 0xE7, 0x9B, 0x9B, 0x43, 0xE7, 0x9B, 0xA3, 0x43, + 0xE7, 0x9B, 0xA7, 0x43, 0xE7, 0x9B, 0xAE, 0x43, + 0xE7, 0x9B, 0xB4, 0x43, 0xE7, 0x9C, 0x81, 0x43, + // Bytes 1000 - 103f + 0xE7, 0x9C, 0x9E, 0x43, 0xE7, 0x9C, 0x9F, 0x43, + 0xE7, 0x9D, 0x80, 0x43, 0xE7, 0x9D, 0x8A, 0x43, + 0xE7, 0x9E, 0x8B, 0x43, 0xE7, 0x9E, 0xA7, 0x43, + 0xE7, 0x9F, 0x9B, 0x43, 0xE7, 0x9F, 0xA2, 0x43, + 0xE7, 0x9F, 0xB3, 0x43, 0xE7, 0xA1, 0x8E, 0x43, + 0xE7, 0xA1, 0xAB, 0x43, 0xE7, 0xA2, 0x8C, 0x43, + 0xE7, 0xA2, 0x91, 0x43, 0xE7, 0xA3, 0x8A, 0x43, + 0xE7, 0xA3, 0x8C, 0x43, 0xE7, 0xA3, 0xBB, 0x43, + // Bytes 1040 - 107f + 0xE7, 0xA4, 0xAA, 0x43, 0xE7, 0xA4, 0xBA, 0x43, + 0xE7, 0xA4, 0xBC, 0x43, 0xE7, 0xA4, 0xBE, 0x43, + 0xE7, 0xA5, 0x88, 0x43, 0xE7, 0xA5, 0x89, 0x43, + 0xE7, 0xA5, 0x90, 0x43, 0xE7, 0xA5, 0x96, 0x43, + 0xE7, 0xA5, 0x9D, 0x43, 0xE7, 0xA5, 0x9E, 0x43, + 0xE7, 0xA5, 0xA5, 0x43, 0xE7, 0xA5, 0xBF, 0x43, + 0xE7, 0xA6, 0x81, 0x43, 0xE7, 0xA6, 0x8D, 0x43, + 0xE7, 0xA6, 0x8E, 0x43, 0xE7, 0xA6, 0x8F, 0x43, + // Bytes 1080 - 10bf + 0xE7, 0xA6, 0xAE, 0x43, 0xE7, 0xA6, 0xB8, 0x43, + 0xE7, 0xA6, 0xBE, 0x43, 0xE7, 0xA7, 0x8A, 0x43, + 0xE7, 0xA7, 0x98, 0x43, 0xE7, 0xA7, 0xAB, 0x43, + 0xE7, 0xA8, 0x9C, 0x43, 0xE7, 0xA9, 0x80, 0x43, + 0xE7, 0xA9, 0x8A, 0x43, 0xE7, 0xA9, 0x8F, 0x43, + 0xE7, 0xA9, 0xB4, 0x43, 0xE7, 0xA9, 0xBA, 0x43, + 0xE7, 0xAA, 0x81, 0x43, 0xE7, 0xAA, 0xB1, 0x43, + 0xE7, 0xAB, 0x8B, 0x43, 0xE7, 0xAB, 0xAE, 0x43, + // Bytes 10c0 - 10ff + 0xE7, 0xAB, 0xB9, 0x43, 0xE7, 0xAC, 0xA0, 0x43, + 0xE7, 0xAE, 0x8F, 0x43, 0xE7, 0xAF, 0x80, 0x43, + 0xE7, 0xAF, 0x86, 0x43, 0xE7, 0xAF, 0x89, 0x43, + 0xE7, 0xB0, 0xBE, 0x43, 0xE7, 0xB1, 0xA0, 0x43, + 0xE7, 0xB1, 0xB3, 0x43, 0xE7, 0xB1, 0xBB, 0x43, + 0xE7, 0xB2, 0x92, 0x43, 0xE7, 0xB2, 0xBE, 0x43, + 0xE7, 0xB3, 0x92, 0x43, 0xE7, 0xB3, 0x96, 0x43, + 0xE7, 0xB3, 0xA3, 0x43, 0xE7, 0xB3, 0xA7, 0x43, + // Bytes 1100 - 113f + 0xE7, 0xB3, 0xA8, 0x43, 0xE7, 0xB3, 0xB8, 0x43, + 0xE7, 0xB4, 0x80, 0x43, 0xE7, 0xB4, 0x90, 0x43, + 0xE7, 0xB4, 0xA2, 0x43, 0xE7, 0xB4, 0xAF, 0x43, + 0xE7, 0xB5, 0x82, 0x43, 0xE7, 0xB5, 0x9B, 0x43, + 0xE7, 0xB5, 0xA3, 0x43, 0xE7, 0xB6, 0xA0, 0x43, + 0xE7, 0xB6, 0xBE, 0x43, 0xE7, 0xB7, 0x87, 0x43, + 0xE7, 0xB7, 0xB4, 0x43, 0xE7, 0xB8, 0x82, 0x43, + 0xE7, 0xB8, 0x89, 0x43, 0xE7, 0xB8, 0xB7, 0x43, + // Bytes 1140 - 117f + 0xE7, 0xB9, 0x81, 0x43, 0xE7, 0xB9, 0x85, 0x43, + 0xE7, 0xBC, 0xB6, 0x43, 0xE7, 0xBC, 0xBE, 0x43, + 0xE7, 0xBD, 0x91, 0x43, 0xE7, 0xBD, 0xB2, 0x43, + 0xE7, 0xBD, 0xB9, 0x43, 0xE7, 0xBD, 0xBA, 0x43, + 0xE7, 0xBE, 0x85, 0x43, 0xE7, 0xBE, 0x8A, 0x43, + 0xE7, 0xBE, 0x95, 0x43, 0xE7, 0xBE, 0x9A, 0x43, + 0xE7, 0xBE, 0xBD, 0x43, 0xE7, 0xBF, 0xBA, 0x43, + 0xE8, 0x80, 0x81, 0x43, 0xE8, 0x80, 0x85, 0x43, + // Bytes 1180 - 11bf + 0xE8, 0x80, 0x8C, 0x43, 0xE8, 0x80, 0x92, 0x43, + 0xE8, 0x80, 0xB3, 0x43, 0xE8, 0x81, 0x86, 0x43, + 0xE8, 0x81, 0xA0, 0x43, 0xE8, 0x81, 0xAF, 0x43, + 0xE8, 0x81, 0xB0, 0x43, 0xE8, 0x81, 0xBE, 0x43, + 0xE8, 0x81, 0xBF, 0x43, 0xE8, 0x82, 0x89, 0x43, + 0xE8, 0x82, 0x8B, 0x43, 0xE8, 0x82, 0xAD, 0x43, + 0xE8, 0x82, 0xB2, 0x43, 0xE8, 0x84, 0x83, 0x43, + 0xE8, 0x84, 0xBE, 0x43, 0xE8, 0x87, 0x98, 0x43, + // Bytes 11c0 - 11ff + 0xE8, 0x87, 0xA3, 0x43, 0xE8, 0x87, 0xA8, 0x43, + 0xE8, 0x87, 0xAA, 0x43, 0xE8, 0x87, 0xAD, 0x43, + 0xE8, 0x87, 0xB3, 0x43, 0xE8, 0x87, 0xBC, 0x43, + 0xE8, 0x88, 0x81, 0x43, 0xE8, 0x88, 0x84, 0x43, + 0xE8, 0x88, 0x8C, 0x43, 0xE8, 0x88, 0x98, 0x43, + 0xE8, 0x88, 0x9B, 0x43, 0xE8, 0x88, 0x9F, 0x43, + 0xE8, 0x89, 0xAE, 0x43, 0xE8, 0x89, 0xAF, 0x43, + 0xE8, 0x89, 0xB2, 0x43, 0xE8, 0x89, 0xB8, 0x43, + // Bytes 1200 - 123f + 0xE8, 0x89, 0xB9, 0x43, 0xE8, 0x8A, 0x8B, 0x43, + 0xE8, 0x8A, 0x91, 0x43, 0xE8, 0x8A, 0x9D, 0x43, + 0xE8, 0x8A, 0xB1, 0x43, 0xE8, 0x8A, 0xB3, 0x43, + 0xE8, 0x8A, 0xBD, 0x43, 0xE8, 0x8B, 0xA5, 0x43, + 0xE8, 0x8B, 0xA6, 0x43, 0xE8, 0x8C, 0x9D, 0x43, + 0xE8, 0x8C, 0xA3, 0x43, 0xE8, 0x8C, 0xB6, 0x43, + 0xE8, 0x8D, 0x92, 0x43, 0xE8, 0x8D, 0x93, 0x43, + 0xE8, 0x8D, 0xA3, 0x43, 0xE8, 0x8E, 0xAD, 0x43, + // Bytes 1240 - 127f + 0xE8, 0x8E, 0xBD, 0x43, 0xE8, 0x8F, 0x89, 0x43, + 0xE8, 0x8F, 0x8A, 0x43, 0xE8, 0x8F, 0x8C, 0x43, + 0xE8, 0x8F, 0x9C, 0x43, 0xE8, 0x8F, 0xA7, 0x43, + 0xE8, 0x8F, 0xAF, 0x43, 0xE8, 0x8F, 0xB1, 0x43, + 0xE8, 0x90, 0xBD, 0x43, 0xE8, 0x91, 0x89, 0x43, + 0xE8, 0x91, 0x97, 0x43, 0xE8, 0x93, 0xAE, 0x43, + 0xE8, 0x93, 0xB1, 0x43, 0xE8, 0x93, 0xB3, 0x43, + 0xE8, 0x93, 0xBC, 0x43, 0xE8, 0x94, 0x96, 0x43, + // Bytes 1280 - 12bf + 0xE8, 0x95, 0xA4, 0x43, 0xE8, 0x97, 0x8D, 0x43, + 0xE8, 0x97, 0xBA, 0x43, 0xE8, 0x98, 0x86, 0x43, + 0xE8, 0x98, 0x92, 0x43, 0xE8, 0x98, 0xAD, 0x43, + 0xE8, 0x98, 0xBF, 0x43, 0xE8, 0x99, 0x8D, 0x43, + 0xE8, 0x99, 0x90, 0x43, 0xE8, 0x99, 0x9C, 0x43, + 0xE8, 0x99, 0xA7, 0x43, 0xE8, 0x99, 0xA9, 0x43, + 0xE8, 0x99, 0xAB, 0x43, 0xE8, 0x9A, 0x88, 0x43, + 0xE8, 0x9A, 0xA9, 0x43, 0xE8, 0x9B, 0xA2, 0x43, + // Bytes 12c0 - 12ff + 0xE8, 0x9C, 0x8E, 0x43, 0xE8, 0x9C, 0xA8, 0x43, + 0xE8, 0x9D, 0xAB, 0x43, 0xE8, 0x9D, 0xB9, 0x43, + 0xE8, 0x9E, 0x86, 0x43, 0xE8, 0x9E, 0xBA, 0x43, + 0xE8, 0x9F, 0xA1, 0x43, 0xE8, 0xA0, 0x81, 0x43, + 0xE8, 0xA0, 0x9F, 0x43, 0xE8, 0xA1, 0x80, 0x43, + 0xE8, 0xA1, 0x8C, 0x43, 0xE8, 0xA1, 0xA0, 0x43, + 0xE8, 0xA1, 0xA3, 0x43, 0xE8, 0xA3, 0x82, 0x43, + 0xE8, 0xA3, 0x8F, 0x43, 0xE8, 0xA3, 0x97, 0x43, + // Bytes 1300 - 133f + 0xE8, 0xA3, 0x9E, 0x43, 0xE8, 0xA3, 0xA1, 0x43, + 0xE8, 0xA3, 0xB8, 0x43, 0xE8, 0xA3, 0xBA, 0x43, + 0xE8, 0xA4, 0x90, 0x43, 0xE8, 0xA5, 0x81, 0x43, + 0xE8, 0xA5, 0xA4, 0x43, 0xE8, 0xA5, 0xBE, 0x43, + 0xE8, 0xA6, 0x86, 0x43, 0xE8, 0xA6, 0x8B, 0x43, + 0xE8, 0xA6, 0x96, 0x43, 0xE8, 0xA7, 0x92, 0x43, + 0xE8, 0xA7, 0xA3, 0x43, 0xE8, 0xA8, 0x80, 0x43, + 0xE8, 0xAA, 0xA0, 0x43, 0xE8, 0xAA, 0xAA, 0x43, + // Bytes 1340 - 137f + 0xE8, 0xAA, 0xBF, 0x43, 0xE8, 0xAB, 0x8B, 0x43, + 0xE8, 0xAB, 0x92, 0x43, 0xE8, 0xAB, 0x96, 0x43, + 0xE8, 0xAB, 0xAD, 0x43, 0xE8, 0xAB, 0xB8, 0x43, + 0xE8, 0xAB, 0xBE, 0x43, 0xE8, 0xAC, 0x81, 0x43, + 0xE8, 0xAC, 0xB9, 0x43, 0xE8, 0xAD, 0x98, 0x43, + 0xE8, 0xAE, 0x80, 0x43, 0xE8, 0xAE, 0x8A, 0x43, + 0xE8, 0xB0, 0xB7, 0x43, 0xE8, 0xB1, 0x86, 0x43, + 0xE8, 0xB1, 0x88, 0x43, 0xE8, 0xB1, 0x95, 0x43, + // Bytes 1380 - 13bf + 0xE8, 0xB1, 0xB8, 0x43, 0xE8, 0xB2, 0x9D, 0x43, + 0xE8, 0xB2, 0xA1, 0x43, 0xE8, 0xB2, 0xA9, 0x43, + 0xE8, 0xB2, 0xAB, 0x43, 0xE8, 0xB3, 0x81, 0x43, + 0xE8, 0xB3, 0x82, 0x43, 0xE8, 0xB3, 0x87, 0x43, + 0xE8, 0xB3, 0x88, 0x43, 0xE8, 0xB3, 0x93, 0x43, + 0xE8, 0xB4, 0x88, 0x43, 0xE8, 0xB4, 0x9B, 0x43, + 0xE8, 0xB5, 0xA4, 0x43, 0xE8, 0xB5, 0xB0, 0x43, + 0xE8, 0xB5, 0xB7, 0x43, 0xE8, 0xB6, 0xB3, 0x43, + // Bytes 13c0 - 13ff + 0xE8, 0xB6, 0xBC, 0x43, 0xE8, 0xB7, 0x8B, 0x43, + 0xE8, 0xB7, 0xAF, 0x43, 0xE8, 0xB7, 0xB0, 0x43, + 0xE8, 0xBA, 0xAB, 0x43, 0xE8, 0xBB, 0x8A, 0x43, + 0xE8, 0xBB, 0x94, 0x43, 0xE8, 0xBC, 0xA6, 0x43, + 0xE8, 0xBC, 0xAA, 0x43, 0xE8, 0xBC, 0xB8, 0x43, + 0xE8, 0xBC, 0xBB, 0x43, 0xE8, 0xBD, 0xA2, 0x43, + 0xE8, 0xBE, 0x9B, 0x43, 0xE8, 0xBE, 0x9E, 0x43, + 0xE8, 0xBE, 0xB0, 0x43, 0xE8, 0xBE, 0xB5, 0x43, + // Bytes 1400 - 143f + 0xE8, 0xBE, 0xB6, 0x43, 0xE9, 0x80, 0xA3, 0x43, + 0xE9, 0x80, 0xB8, 0x43, 0xE9, 0x81, 0x8A, 0x43, + 0xE9, 0x81, 0xA9, 0x43, 0xE9, 0x81, 0xB2, 0x43, + 0xE9, 0x81, 0xBC, 0x43, 0xE9, 0x82, 0x8F, 0x43, + 0xE9, 0x82, 0x91, 0x43, 0xE9, 0x82, 0x94, 0x43, + 0xE9, 0x83, 0x8E, 0x43, 0xE9, 0x83, 0x9E, 0x43, + 0xE9, 0x83, 0xB1, 0x43, 0xE9, 0x83, 0xBD, 0x43, + 0xE9, 0x84, 0x91, 0x43, 0xE9, 0x84, 0x9B, 0x43, + // Bytes 1440 - 147f + 0xE9, 0x85, 0x89, 0x43, 0xE9, 0x85, 0x8D, 0x43, + 0xE9, 0x85, 0xAA, 0x43, 0xE9, 0x86, 0x99, 0x43, + 0xE9, 0x86, 0xB4, 0x43, 0xE9, 0x87, 0x86, 0x43, + 0xE9, 0x87, 0x8C, 0x43, 0xE9, 0x87, 0x8F, 0x43, + 0xE9, 0x87, 0x91, 0x43, 0xE9, 0x88, 0xB4, 0x43, + 0xE9, 0x88, 0xB8, 0x43, 0xE9, 0x89, 0xB6, 0x43, + 0xE9, 0x89, 0xBC, 0x43, 0xE9, 0x8B, 0x97, 0x43, + 0xE9, 0x8B, 0x98, 0x43, 0xE9, 0x8C, 0x84, 0x43, + // Bytes 1480 - 14bf + 0xE9, 0x8D, 0x8A, 0x43, 0xE9, 0x8F, 0xB9, 0x43, + 0xE9, 0x90, 0x95, 0x43, 0xE9, 0x95, 0xB7, 0x43, + 0xE9, 0x96, 0x80, 0x43, 0xE9, 0x96, 0x8B, 0x43, + 0xE9, 0x96, 0xAD, 0x43, 0xE9, 0x96, 0xB7, 0x43, + 0xE9, 0x98, 0x9C, 0x43, 0xE9, 0x98, 0xAE, 0x43, + 0xE9, 0x99, 0x8B, 0x43, 0xE9, 0x99, 0x8D, 0x43, + 0xE9, 0x99, 0xB5, 0x43, 0xE9, 0x99, 0xB8, 0x43, + 0xE9, 0x99, 0xBC, 0x43, 0xE9, 0x9A, 0x86, 0x43, + // Bytes 14c0 - 14ff + 0xE9, 0x9A, 0xA3, 0x43, 0xE9, 0x9A, 0xB6, 0x43, + 0xE9, 0x9A, 0xB7, 0x43, 0xE9, 0x9A, 0xB8, 0x43, + 0xE9, 0x9A, 0xB9, 0x43, 0xE9, 0x9B, 0x83, 0x43, + 0xE9, 0x9B, 0xA2, 0x43, 0xE9, 0x9B, 0xA3, 0x43, + 0xE9, 0x9B, 0xA8, 0x43, 0xE9, 0x9B, 0xB6, 0x43, + 0xE9, 0x9B, 0xB7, 0x43, 0xE9, 0x9C, 0xA3, 0x43, + 0xE9, 0x9C, 0xB2, 0x43, 0xE9, 0x9D, 0x88, 0x43, + 0xE9, 0x9D, 0x91, 0x43, 0xE9, 0x9D, 0x96, 0x43, + // Bytes 1500 - 153f + 0xE9, 0x9D, 0x9E, 0x43, 0xE9, 0x9D, 0xA2, 0x43, + 0xE9, 0x9D, 0xA9, 0x43, 0xE9, 0x9F, 0x8B, 0x43, + 0xE9, 0x9F, 0x9B, 0x43, 0xE9, 0x9F, 0xA0, 0x43, + 0xE9, 0x9F, 0xAD, 0x43, 0xE9, 0x9F, 0xB3, 0x43, + 0xE9, 0x9F, 0xBF, 0x43, 0xE9, 0xA0, 0x81, 0x43, + 0xE9, 0xA0, 0x85, 0x43, 0xE9, 0xA0, 0x8B, 0x43, + 0xE9, 0xA0, 0x98, 0x43, 0xE9, 0xA0, 0xA9, 0x43, + 0xE9, 0xA0, 0xBB, 0x43, 0xE9, 0xA1, 0x9E, 0x43, + // Bytes 1540 - 157f + 0xE9, 0xA2, 0xA8, 0x43, 0xE9, 0xA3, 0x9B, 0x43, + 0xE9, 0xA3, 0x9F, 0x43, 0xE9, 0xA3, 0xA2, 0x43, + 0xE9, 0xA3, 0xAF, 0x43, 0xE9, 0xA3, 0xBC, 0x43, + 0xE9, 0xA4, 0xA8, 0x43, 0xE9, 0xA4, 0xA9, 0x43, + 0xE9, 0xA6, 0x96, 0x43, 0xE9, 0xA6, 0x99, 0x43, + 0xE9, 0xA6, 0xA7, 0x43, 0xE9, 0xA6, 0xAC, 0x43, + 0xE9, 0xA7, 0x82, 0x43, 0xE9, 0xA7, 0xB1, 0x43, + 0xE9, 0xA7, 0xBE, 0x43, 0xE9, 0xA9, 0xAA, 0x43, + // Bytes 1580 - 15bf + 0xE9, 0xAA, 0xA8, 0x43, 0xE9, 0xAB, 0x98, 0x43, + 0xE9, 0xAB, 0x9F, 0x43, 0xE9, 0xAC, 0x92, 0x43, + 0xE9, 0xAC, 0xA5, 0x43, 0xE9, 0xAC, 0xAF, 0x43, + 0xE9, 0xAC, 0xB2, 0x43, 0xE9, 0xAC, 0xBC, 0x43, + 0xE9, 0xAD, 0x9A, 0x43, 0xE9, 0xAD, 0xAF, 0x43, + 0xE9, 0xB1, 0x80, 0x43, 0xE9, 0xB1, 0x97, 0x43, + 0xE9, 0xB3, 0xA5, 0x43, 0xE9, 0xB3, 0xBD, 0x43, + 0xE9, 0xB5, 0xA7, 0x43, 0xE9, 0xB6, 0xB4, 0x43, + // Bytes 15c0 - 15ff + 0xE9, 0xB7, 0xBA, 0x43, 0xE9, 0xB8, 0x9E, 0x43, + 0xE9, 0xB9, 0xB5, 0x43, 0xE9, 0xB9, 0xBF, 0x43, + 0xE9, 0xBA, 0x97, 0x43, 0xE9, 0xBA, 0x9F, 0x43, + 0xE9, 0xBA, 0xA5, 0x43, 0xE9, 0xBA, 0xBB, 0x43, + 0xE9, 0xBB, 0x83, 0x43, 0xE9, 0xBB, 0x8D, 0x43, + 0xE9, 0xBB, 0x8E, 0x43, 0xE9, 0xBB, 0x91, 0x43, + 0xE9, 0xBB, 0xB9, 0x43, 0xE9, 0xBB, 0xBD, 0x43, + 0xE9, 0xBB, 0xBE, 0x43, 0xE9, 0xBC, 0x85, 0x43, + // Bytes 1600 - 163f + 0xE9, 0xBC, 0x8E, 0x43, 0xE9, 0xBC, 0x8F, 0x43, + 0xE9, 0xBC, 0x93, 0x43, 0xE9, 0xBC, 0x96, 0x43, + 0xE9, 0xBC, 0xA0, 0x43, 0xE9, 0xBC, 0xBB, 0x43, + 0xE9, 0xBD, 0x83, 0x43, 0xE9, 0xBD, 0x8A, 0x43, + 0xE9, 0xBD, 0x92, 0x43, 0xE9, 0xBE, 0x8D, 0x43, + 0xE9, 0xBE, 0x8E, 0x43, 0xE9, 0xBE, 0x9C, 0x43, + 0xE9, 0xBE, 0x9F, 0x43, 0xE9, 0xBE, 0xA0, 0x43, + 0xEA, 0x9C, 0xA7, 0x43, 0xEA, 0x9D, 0xAF, 0x43, + // Bytes 1640 - 167f + 0xEA, 0xAC, 0xB7, 0x43, 0xEA, 0xAD, 0x92, 0x44, + 0xF0, 0xA0, 0x84, 0xA2, 0x44, 0xF0, 0xA0, 0x94, + 0x9C, 0x44, 0xF0, 0xA0, 0x94, 0xA5, 0x44, 0xF0, + 0xA0, 0x95, 0x8B, 0x44, 0xF0, 0xA0, 0x98, 0xBA, + 0x44, 0xF0, 0xA0, 0xA0, 0x84, 0x44, 0xF0, 0xA0, + 0xA3, 0x9E, 0x44, 0xF0, 0xA0, 0xA8, 0xAC, 0x44, + 0xF0, 0xA0, 0xAD, 0xA3, 0x44, 0xF0, 0xA1, 0x93, + 0xA4, 0x44, 0xF0, 0xA1, 0x9A, 0xA8, 0x44, 0xF0, + // Bytes 1680 - 16bf + 0xA1, 0x9B, 0xAA, 0x44, 0xF0, 0xA1, 0xA7, 0x88, + 0x44, 0xF0, 0xA1, 0xAC, 0x98, 0x44, 0xF0, 0xA1, + 0xB4, 0x8B, 0x44, 0xF0, 0xA1, 0xB7, 0xA4, 0x44, + 0xF0, 0xA1, 0xB7, 0xA6, 0x44, 0xF0, 0xA2, 0x86, + 0x83, 0x44, 0xF0, 0xA2, 0x86, 0x9F, 0x44, 0xF0, + 0xA2, 0x8C, 0xB1, 0x44, 0xF0, 0xA2, 0x9B, 0x94, + 0x44, 0xF0, 0xA2, 0xA1, 0x84, 0x44, 0xF0, 0xA2, + 0xA1, 0x8A, 0x44, 0xF0, 0xA2, 0xAC, 0x8C, 0x44, + // Bytes 16c0 - 16ff + 0xF0, 0xA2, 0xAF, 0xB1, 0x44, 0xF0, 0xA3, 0x80, + 0x8A, 0x44, 0xF0, 0xA3, 0x8A, 0xB8, 0x44, 0xF0, + 0xA3, 0x8D, 0x9F, 0x44, 0xF0, 0xA3, 0x8E, 0x93, + 0x44, 0xF0, 0xA3, 0x8E, 0x9C, 0x44, 0xF0, 0xA3, + 0x8F, 0x83, 0x44, 0xF0, 0xA3, 0x8F, 0x95, 0x44, + 0xF0, 0xA3, 0x91, 0xAD, 0x44, 0xF0, 0xA3, 0x9A, + 0xA3, 0x44, 0xF0, 0xA3, 0xA2, 0xA7, 0x44, 0xF0, + 0xA3, 0xAA, 0x8D, 0x44, 0xF0, 0xA3, 0xAB, 0xBA, + // Bytes 1700 - 173f + 0x44, 0xF0, 0xA3, 0xB2, 0xBC, 0x44, 0xF0, 0xA3, + 0xB4, 0x9E, 0x44, 0xF0, 0xA3, 0xBB, 0x91, 0x44, + 0xF0, 0xA3, 0xBD, 0x9E, 0x44, 0xF0, 0xA3, 0xBE, + 0x8E, 0x44, 0xF0, 0xA4, 0x89, 0xA3, 0x44, 0xF0, + 0xA4, 0x8B, 0xAE, 0x44, 0xF0, 0xA4, 0x8E, 0xAB, + 0x44, 0xF0, 0xA4, 0x98, 0x88, 0x44, 0xF0, 0xA4, + 0x9C, 0xB5, 0x44, 0xF0, 0xA4, 0xA0, 0x94, 0x44, + 0xF0, 0xA4, 0xB0, 0xB6, 0x44, 0xF0, 0xA4, 0xB2, + // Bytes 1740 - 177f + 0x92, 0x44, 0xF0, 0xA4, 0xBE, 0xA1, 0x44, 0xF0, + 0xA4, 0xBE, 0xB8, 0x44, 0xF0, 0xA5, 0x81, 0x84, + 0x44, 0xF0, 0xA5, 0x83, 0xB2, 0x44, 0xF0, 0xA5, + 0x83, 0xB3, 0x44, 0xF0, 0xA5, 0x84, 0x99, 0x44, + 0xF0, 0xA5, 0x84, 0xB3, 0x44, 0xF0, 0xA5, 0x89, + 0x89, 0x44, 0xF0, 0xA5, 0x90, 0x9D, 0x44, 0xF0, + 0xA5, 0x98, 0xA6, 0x44, 0xF0, 0xA5, 0x9A, 0x9A, + 0x44, 0xF0, 0xA5, 0x9B, 0x85, 0x44, 0xF0, 0xA5, + // Bytes 1780 - 17bf + 0xA5, 0xBC, 0x44, 0xF0, 0xA5, 0xAA, 0xA7, 0x44, + 0xF0, 0xA5, 0xAE, 0xAB, 0x44, 0xF0, 0xA5, 0xB2, + 0x80, 0x44, 0xF0, 0xA5, 0xB3, 0x90, 0x44, 0xF0, + 0xA5, 0xBE, 0x86, 0x44, 0xF0, 0xA6, 0x87, 0x9A, + 0x44, 0xF0, 0xA6, 0x88, 0xA8, 0x44, 0xF0, 0xA6, + 0x89, 0x87, 0x44, 0xF0, 0xA6, 0x8B, 0x99, 0x44, + 0xF0, 0xA6, 0x8C, 0xBE, 0x44, 0xF0, 0xA6, 0x93, + 0x9A, 0x44, 0xF0, 0xA6, 0x94, 0xA3, 0x44, 0xF0, + // Bytes 17c0 - 17ff + 0xA6, 0x96, 0xA8, 0x44, 0xF0, 0xA6, 0x9E, 0xA7, + 0x44, 0xF0, 0xA6, 0x9E, 0xB5, 0x44, 0xF0, 0xA6, + 0xAC, 0xBC, 0x44, 0xF0, 0xA6, 0xB0, 0xB6, 0x44, + 0xF0, 0xA6, 0xB3, 0x95, 0x44, 0xF0, 0xA6, 0xB5, + 0xAB, 0x44, 0xF0, 0xA6, 0xBC, 0xAC, 0x44, 0xF0, + 0xA6, 0xBE, 0xB1, 0x44, 0xF0, 0xA7, 0x83, 0x92, + 0x44, 0xF0, 0xA7, 0x8F, 0x8A, 0x44, 0xF0, 0xA7, + 0x99, 0xA7, 0x44, 0xF0, 0xA7, 0xA2, 0xAE, 0x44, + // Bytes 1800 - 183f + 0xF0, 0xA7, 0xA5, 0xA6, 0x44, 0xF0, 0xA7, 0xB2, + 0xA8, 0x44, 0xF0, 0xA7, 0xBB, 0x93, 0x44, 0xF0, + 0xA7, 0xBC, 0xAF, 0x44, 0xF0, 0xA8, 0x97, 0x92, + 0x44, 0xF0, 0xA8, 0x97, 0xAD, 0x44, 0xF0, 0xA8, + 0x9C, 0xAE, 0x44, 0xF0, 0xA8, 0xAF, 0xBA, 0x44, + 0xF0, 0xA8, 0xB5, 0xB7, 0x44, 0xF0, 0xA9, 0x85, + 0x85, 0x44, 0xF0, 0xA9, 0x87, 0x9F, 0x44, 0xF0, + 0xA9, 0x88, 0x9A, 0x44, 0xF0, 0xA9, 0x90, 0x8A, + // Bytes 1840 - 187f + 0x44, 0xF0, 0xA9, 0x92, 0x96, 0x44, 0xF0, 0xA9, + 0x96, 0xB6, 0x44, 0xF0, 0xA9, 0xAC, 0xB0, 0x44, + 0xF0, 0xAA, 0x83, 0x8E, 0x44, 0xF0, 0xAA, 0x84, + 0x85, 0x44, 0xF0, 0xAA, 0x88, 0x8E, 0x44, 0xF0, + 0xAA, 0x8A, 0x91, 0x44, 0xF0, 0xAA, 0x8E, 0x92, + 0x44, 0xF0, 0xAA, 0x98, 0x80, 0x42, 0x21, 0x21, + 0x42, 0x21, 0x3F, 0x42, 0x2E, 0x2E, 0x42, 0x30, + 0x2C, 0x42, 0x30, 0x2E, 0x42, 0x31, 0x2C, 0x42, + // Bytes 1880 - 18bf + 0x31, 0x2E, 0x42, 0x31, 0x30, 0x42, 0x31, 0x31, + 0x42, 0x31, 0x32, 0x42, 0x31, 0x33, 0x42, 0x31, + 0x34, 0x42, 0x31, 0x35, 0x42, 0x31, 0x36, 0x42, + 0x31, 0x37, 0x42, 0x31, 0x38, 0x42, 0x31, 0x39, + 0x42, 0x32, 0x2C, 0x42, 0x32, 0x2E, 0x42, 0x32, + 0x30, 0x42, 0x32, 0x31, 0x42, 0x32, 0x32, 0x42, + 0x32, 0x33, 0x42, 0x32, 0x34, 0x42, 0x32, 0x35, + 0x42, 0x32, 0x36, 0x42, 0x32, 0x37, 0x42, 0x32, + // Bytes 18c0 - 18ff + 0x38, 0x42, 0x32, 0x39, 0x42, 0x33, 0x2C, 0x42, + 0x33, 0x2E, 0x42, 0x33, 0x30, 0x42, 0x33, 0x31, + 0x42, 0x33, 0x32, 0x42, 0x33, 0x33, 0x42, 0x33, + 0x34, 0x42, 0x33, 0x35, 0x42, 0x33, 0x36, 0x42, + 0x33, 0x37, 0x42, 0x33, 0x38, 0x42, 0x33, 0x39, + 0x42, 0x34, 0x2C, 0x42, 0x34, 0x2E, 0x42, 0x34, + 0x30, 0x42, 0x34, 0x31, 0x42, 0x34, 0x32, 0x42, + 0x34, 0x33, 0x42, 0x34, 0x34, 0x42, 0x34, 0x35, + // Bytes 1900 - 193f + 0x42, 0x34, 0x36, 0x42, 0x34, 0x37, 0x42, 0x34, + 0x38, 0x42, 0x34, 0x39, 0x42, 0x35, 0x2C, 0x42, + 0x35, 0x2E, 0x42, 0x35, 0x30, 0x42, 0x36, 0x2C, + 0x42, 0x36, 0x2E, 0x42, 0x37, 0x2C, 0x42, 0x37, + 0x2E, 0x42, 0x38, 0x2C, 0x42, 0x38, 0x2E, 0x42, + 0x39, 0x2C, 0x42, 0x39, 0x2E, 0x42, 0x3D, 0x3D, + 0x42, 0x3F, 0x21, 0x42, 0x3F, 0x3F, 0x42, 0x41, + 0x55, 0x42, 0x42, 0x71, 0x42, 0x43, 0x44, 0x42, + // Bytes 1940 - 197f + 0x44, 0x4A, 0x42, 0x44, 0x5A, 0x42, 0x44, 0x7A, + 0x42, 0x47, 0x42, 0x42, 0x47, 0x79, 0x42, 0x48, + 0x50, 0x42, 0x48, 0x56, 0x42, 0x48, 0x67, 0x42, + 0x48, 0x7A, 0x42, 0x49, 0x49, 0x42, 0x49, 0x4A, + 0x42, 0x49, 0x55, 0x42, 0x49, 0x56, 0x42, 0x49, + 0x58, 0x42, 0x4B, 0x42, 0x42, 0x4B, 0x4B, 0x42, + 0x4B, 0x4D, 0x42, 0x4C, 0x4A, 0x42, 0x4C, 0x6A, + 0x42, 0x4D, 0x42, 0x42, 0x4D, 0x43, 0x42, 0x4D, + // Bytes 1980 - 19bf + 0x44, 0x42, 0x4D, 0x56, 0x42, 0x4D, 0x57, 0x42, + 0x4E, 0x4A, 0x42, 0x4E, 0x6A, 0x42, 0x4E, 0x6F, + 0x42, 0x50, 0x48, 0x42, 0x50, 0x52, 0x42, 0x50, + 0x61, 0x42, 0x52, 0x73, 0x42, 0x53, 0x44, 0x42, + 0x53, 0x4D, 0x42, 0x53, 0x53, 0x42, 0x53, 0x76, + 0x42, 0x54, 0x4D, 0x42, 0x56, 0x49, 0x42, 0x57, + 0x43, 0x42, 0x57, 0x5A, 0x42, 0x57, 0x62, 0x42, + 0x58, 0x49, 0x42, 0x63, 0x63, 0x42, 0x63, 0x64, + // Bytes 19c0 - 19ff + 0x42, 0x63, 0x6D, 0x42, 0x64, 0x42, 0x42, 0x64, + 0x61, 0x42, 0x64, 0x6C, 0x42, 0x64, 0x6D, 0x42, + 0x64, 0x7A, 0x42, 0x65, 0x56, 0x42, 0x66, 0x66, + 0x42, 0x66, 0x69, 0x42, 0x66, 0x6C, 0x42, 0x66, + 0x6D, 0x42, 0x68, 0x61, 0x42, 0x69, 0x69, 0x42, + 0x69, 0x6A, 0x42, 0x69, 0x6E, 0x42, 0x69, 0x76, + 0x42, 0x69, 0x78, 0x42, 0x6B, 0x41, 0x42, 0x6B, + 0x56, 0x42, 0x6B, 0x57, 0x42, 0x6B, 0x67, 0x42, + // Bytes 1a00 - 1a3f + 0x6B, 0x6C, 0x42, 0x6B, 0x6D, 0x42, 0x6B, 0x74, + 0x42, 0x6C, 0x6A, 0x42, 0x6C, 0x6D, 0x42, 0x6C, + 0x6E, 0x42, 0x6C, 0x78, 0x42, 0x6D, 0x32, 0x42, + 0x6D, 0x33, 0x42, 0x6D, 0x41, 0x42, 0x6D, 0x56, + 0x42, 0x6D, 0x57, 0x42, 0x6D, 0x62, 0x42, 0x6D, + 0x67, 0x42, 0x6D, 0x6C, 0x42, 0x6D, 0x6D, 0x42, + 0x6D, 0x73, 0x42, 0x6E, 0x41, 0x42, 0x6E, 0x46, + 0x42, 0x6E, 0x56, 0x42, 0x6E, 0x57, 0x42, 0x6E, + // Bytes 1a40 - 1a7f + 0x6A, 0x42, 0x6E, 0x6D, 0x42, 0x6E, 0x73, 0x42, + 0x6F, 0x56, 0x42, 0x70, 0x41, 0x42, 0x70, 0x46, + 0x42, 0x70, 0x56, 0x42, 0x70, 0x57, 0x42, 0x70, + 0x63, 0x42, 0x70, 0x73, 0x42, 0x73, 0x72, 0x42, + 0x73, 0x74, 0x42, 0x76, 0x69, 0x42, 0x78, 0x69, + 0x43, 0x28, 0x31, 0x29, 0x43, 0x28, 0x32, 0x29, + 0x43, 0x28, 0x33, 0x29, 0x43, 0x28, 0x34, 0x29, + 0x43, 0x28, 0x35, 0x29, 0x43, 0x28, 0x36, 0x29, + // Bytes 1a80 - 1abf + 0x43, 0x28, 0x37, 0x29, 0x43, 0x28, 0x38, 0x29, + 0x43, 0x28, 0x39, 0x29, 0x43, 0x28, 0x41, 0x29, + 0x43, 0x28, 0x42, 0x29, 0x43, 0x28, 0x43, 0x29, + 0x43, 0x28, 0x44, 0x29, 0x43, 0x28, 0x45, 0x29, + 0x43, 0x28, 0x46, 0x29, 0x43, 0x28, 0x47, 0x29, + 0x43, 0x28, 0x48, 0x29, 0x43, 0x28, 0x49, 0x29, + 0x43, 0x28, 0x4A, 0x29, 0x43, 0x28, 0x4B, 0x29, + 0x43, 0x28, 0x4C, 0x29, 0x43, 0x28, 0x4D, 0x29, + // Bytes 1ac0 - 1aff + 0x43, 0x28, 0x4E, 0x29, 0x43, 0x28, 0x4F, 0x29, + 0x43, 0x28, 0x50, 0x29, 0x43, 0x28, 0x51, 0x29, + 0x43, 0x28, 0x52, 0x29, 0x43, 0x28, 0x53, 0x29, + 0x43, 0x28, 0x54, 0x29, 0x43, 0x28, 0x55, 0x29, + 0x43, 0x28, 0x56, 0x29, 0x43, 0x28, 0x57, 0x29, + 0x43, 0x28, 0x58, 0x29, 0x43, 0x28, 0x59, 0x29, + 0x43, 0x28, 0x5A, 0x29, 0x43, 0x28, 0x61, 0x29, + 0x43, 0x28, 0x62, 0x29, 0x43, 0x28, 0x63, 0x29, + // Bytes 1b00 - 1b3f + 0x43, 0x28, 0x64, 0x29, 0x43, 0x28, 0x65, 0x29, + 0x43, 0x28, 0x66, 0x29, 0x43, 0x28, 0x67, 0x29, + 0x43, 0x28, 0x68, 0x29, 0x43, 0x28, 0x69, 0x29, + 0x43, 0x28, 0x6A, 0x29, 0x43, 0x28, 0x6B, 0x29, + 0x43, 0x28, 0x6C, 0x29, 0x43, 0x28, 0x6D, 0x29, + 0x43, 0x28, 0x6E, 0x29, 0x43, 0x28, 0x6F, 0x29, + 0x43, 0x28, 0x70, 0x29, 0x43, 0x28, 0x71, 0x29, + 0x43, 0x28, 0x72, 0x29, 0x43, 0x28, 0x73, 0x29, + // Bytes 1b40 - 1b7f + 0x43, 0x28, 0x74, 0x29, 0x43, 0x28, 0x75, 0x29, + 0x43, 0x28, 0x76, 0x29, 0x43, 0x28, 0x77, 0x29, + 0x43, 0x28, 0x78, 0x29, 0x43, 0x28, 0x79, 0x29, + 0x43, 0x28, 0x7A, 0x29, 0x43, 0x2E, 0x2E, 0x2E, + 0x43, 0x31, 0x30, 0x2E, 0x43, 0x31, 0x31, 0x2E, + 0x43, 0x31, 0x32, 0x2E, 0x43, 0x31, 0x33, 0x2E, + 0x43, 0x31, 0x34, 0x2E, 0x43, 0x31, 0x35, 0x2E, + 0x43, 0x31, 0x36, 0x2E, 0x43, 0x31, 0x37, 0x2E, + // Bytes 1b80 - 1bbf + 0x43, 0x31, 0x38, 0x2E, 0x43, 0x31, 0x39, 0x2E, + 0x43, 0x32, 0x30, 0x2E, 0x43, 0x3A, 0x3A, 0x3D, + 0x43, 0x3D, 0x3D, 0x3D, 0x43, 0x43, 0x6F, 0x2E, + 0x43, 0x46, 0x41, 0x58, 0x43, 0x47, 0x48, 0x7A, + 0x43, 0x47, 0x50, 0x61, 0x43, 0x49, 0x49, 0x49, + 0x43, 0x4C, 0x54, 0x44, 0x43, 0x4C, 0xC2, 0xB7, + 0x43, 0x4D, 0x48, 0x7A, 0x43, 0x4D, 0x50, 0x61, + 0x43, 0x4D, 0xCE, 0xA9, 0x43, 0x50, 0x50, 0x4D, + // Bytes 1bc0 - 1bff + 0x43, 0x50, 0x50, 0x56, 0x43, 0x50, 0x54, 0x45, + 0x43, 0x54, 0x45, 0x4C, 0x43, 0x54, 0x48, 0x7A, + 0x43, 0x56, 0x49, 0x49, 0x43, 0x58, 0x49, 0x49, + 0x43, 0x61, 0x2F, 0x63, 0x43, 0x61, 0x2F, 0x73, + 0x43, 0x61, 0xCA, 0xBE, 0x43, 0x62, 0x61, 0x72, + 0x43, 0x63, 0x2F, 0x6F, 0x43, 0x63, 0x2F, 0x75, + 0x43, 0x63, 0x61, 0x6C, 0x43, 0x63, 0x6D, 0x32, + 0x43, 0x63, 0x6D, 0x33, 0x43, 0x64, 0x6D, 0x32, + // Bytes 1c00 - 1c3f + 0x43, 0x64, 0x6D, 0x33, 0x43, 0x65, 0x72, 0x67, + 0x43, 0x66, 0x66, 0x69, 0x43, 0x66, 0x66, 0x6C, + 0x43, 0x67, 0x61, 0x6C, 0x43, 0x68, 0x50, 0x61, + 0x43, 0x69, 0x69, 0x69, 0x43, 0x6B, 0x48, 0x7A, + 0x43, 0x6B, 0x50, 0x61, 0x43, 0x6B, 0x6D, 0x32, + 0x43, 0x6B, 0x6D, 0x33, 0x43, 0x6B, 0xCE, 0xA9, + 0x43, 0x6C, 0x6F, 0x67, 0x43, 0x6C, 0xC2, 0xB7, + 0x43, 0x6D, 0x69, 0x6C, 0x43, 0x6D, 0x6D, 0x32, + // Bytes 1c40 - 1c7f + 0x43, 0x6D, 0x6D, 0x33, 0x43, 0x6D, 0x6F, 0x6C, + 0x43, 0x72, 0x61, 0x64, 0x43, 0x76, 0x69, 0x69, + 0x43, 0x78, 0x69, 0x69, 0x43, 0xC2, 0xB0, 0x43, + 0x43, 0xC2, 0xB0, 0x46, 0x43, 0xCA, 0xBC, 0x6E, + 0x43, 0xCE, 0xBC, 0x41, 0x43, 0xCE, 0xBC, 0x46, + 0x43, 0xCE, 0xBC, 0x56, 0x43, 0xCE, 0xBC, 0x57, + 0x43, 0xCE, 0xBC, 0x67, 0x43, 0xCE, 0xBC, 0x6C, + 0x43, 0xCE, 0xBC, 0x6D, 0x43, 0xCE, 0xBC, 0x73, + // Bytes 1c80 - 1cbf + 0x44, 0x28, 0x31, 0x30, 0x29, 0x44, 0x28, 0x31, + 0x31, 0x29, 0x44, 0x28, 0x31, 0x32, 0x29, 0x44, + 0x28, 0x31, 0x33, 0x29, 0x44, 0x28, 0x31, 0x34, + 0x29, 0x44, 0x28, 0x31, 0x35, 0x29, 0x44, 0x28, + 0x31, 0x36, 0x29, 0x44, 0x28, 0x31, 0x37, 0x29, + 0x44, 0x28, 0x31, 0x38, 0x29, 0x44, 0x28, 0x31, + 0x39, 0x29, 0x44, 0x28, 0x32, 0x30, 0x29, 0x44, + 0x30, 0xE7, 0x82, 0xB9, 0x44, 0x31, 0xE2, 0x81, + // Bytes 1cc0 - 1cff + 0x84, 0x44, 0x31, 0xE6, 0x97, 0xA5, 0x44, 0x31, + 0xE6, 0x9C, 0x88, 0x44, 0x31, 0xE7, 0x82, 0xB9, + 0x44, 0x32, 0xE6, 0x97, 0xA5, 0x44, 0x32, 0xE6, + 0x9C, 0x88, 0x44, 0x32, 0xE7, 0x82, 0xB9, 0x44, + 0x33, 0xE6, 0x97, 0xA5, 0x44, 0x33, 0xE6, 0x9C, + 0x88, 0x44, 0x33, 0xE7, 0x82, 0xB9, 0x44, 0x34, + 0xE6, 0x97, 0xA5, 0x44, 0x34, 0xE6, 0x9C, 0x88, + 0x44, 0x34, 0xE7, 0x82, 0xB9, 0x44, 0x35, 0xE6, + // Bytes 1d00 - 1d3f + 0x97, 0xA5, 0x44, 0x35, 0xE6, 0x9C, 0x88, 0x44, + 0x35, 0xE7, 0x82, 0xB9, 0x44, 0x36, 0xE6, 0x97, + 0xA5, 0x44, 0x36, 0xE6, 0x9C, 0x88, 0x44, 0x36, + 0xE7, 0x82, 0xB9, 0x44, 0x37, 0xE6, 0x97, 0xA5, + 0x44, 0x37, 0xE6, 0x9C, 0x88, 0x44, 0x37, 0xE7, + 0x82, 0xB9, 0x44, 0x38, 0xE6, 0x97, 0xA5, 0x44, + 0x38, 0xE6, 0x9C, 0x88, 0x44, 0x38, 0xE7, 0x82, + 0xB9, 0x44, 0x39, 0xE6, 0x97, 0xA5, 0x44, 0x39, + // Bytes 1d40 - 1d7f + 0xE6, 0x9C, 0x88, 0x44, 0x39, 0xE7, 0x82, 0xB9, + 0x44, 0x56, 0x49, 0x49, 0x49, 0x44, 0x61, 0x2E, + 0x6D, 0x2E, 0x44, 0x6B, 0x63, 0x61, 0x6C, 0x44, + 0x70, 0x2E, 0x6D, 0x2E, 0x44, 0x76, 0x69, 0x69, + 0x69, 0x44, 0xD5, 0xA5, 0xD6, 0x82, 0x44, 0xD5, + 0xB4, 0xD5, 0xA5, 0x44, 0xD5, 0xB4, 0xD5, 0xAB, + 0x44, 0xD5, 0xB4, 0xD5, 0xAD, 0x44, 0xD5, 0xB4, + 0xD5, 0xB6, 0x44, 0xD5, 0xBE, 0xD5, 0xB6, 0x44, + // Bytes 1d80 - 1dbf + 0xD7, 0x90, 0xD7, 0x9C, 0x44, 0xD8, 0xA7, 0xD9, + 0xB4, 0x44, 0xD8, 0xA8, 0xD8, 0xAC, 0x44, 0xD8, + 0xA8, 0xD8, 0xAD, 0x44, 0xD8, 0xA8, 0xD8, 0xAE, + 0x44, 0xD8, 0xA8, 0xD8, 0xB1, 0x44, 0xD8, 0xA8, + 0xD8, 0xB2, 0x44, 0xD8, 0xA8, 0xD9, 0x85, 0x44, + 0xD8, 0xA8, 0xD9, 0x86, 0x44, 0xD8, 0xA8, 0xD9, + 0x87, 0x44, 0xD8, 0xA8, 0xD9, 0x89, 0x44, 0xD8, + 0xA8, 0xD9, 0x8A, 0x44, 0xD8, 0xAA, 0xD8, 0xAC, + // Bytes 1dc0 - 1dff + 0x44, 0xD8, 0xAA, 0xD8, 0xAD, 0x44, 0xD8, 0xAA, + 0xD8, 0xAE, 0x44, 0xD8, 0xAA, 0xD8, 0xB1, 0x44, + 0xD8, 0xAA, 0xD8, 0xB2, 0x44, 0xD8, 0xAA, 0xD9, + 0x85, 0x44, 0xD8, 0xAA, 0xD9, 0x86, 0x44, 0xD8, + 0xAA, 0xD9, 0x87, 0x44, 0xD8, 0xAA, 0xD9, 0x89, + 0x44, 0xD8, 0xAA, 0xD9, 0x8A, 0x44, 0xD8, 0xAB, + 0xD8, 0xAC, 0x44, 0xD8, 0xAB, 0xD8, 0xB1, 0x44, + 0xD8, 0xAB, 0xD8, 0xB2, 0x44, 0xD8, 0xAB, 0xD9, + // Bytes 1e00 - 1e3f + 0x85, 0x44, 0xD8, 0xAB, 0xD9, 0x86, 0x44, 0xD8, + 0xAB, 0xD9, 0x87, 0x44, 0xD8, 0xAB, 0xD9, 0x89, + 0x44, 0xD8, 0xAB, 0xD9, 0x8A, 0x44, 0xD8, 0xAC, + 0xD8, 0xAD, 0x44, 0xD8, 0xAC, 0xD9, 0x85, 0x44, + 0xD8, 0xAC, 0xD9, 0x89, 0x44, 0xD8, 0xAC, 0xD9, + 0x8A, 0x44, 0xD8, 0xAD, 0xD8, 0xAC, 0x44, 0xD8, + 0xAD, 0xD9, 0x85, 0x44, 0xD8, 0xAD, 0xD9, 0x89, + 0x44, 0xD8, 0xAD, 0xD9, 0x8A, 0x44, 0xD8, 0xAE, + // Bytes 1e40 - 1e7f + 0xD8, 0xAC, 0x44, 0xD8, 0xAE, 0xD8, 0xAD, 0x44, + 0xD8, 0xAE, 0xD9, 0x85, 0x44, 0xD8, 0xAE, 0xD9, + 0x89, 0x44, 0xD8, 0xAE, 0xD9, 0x8A, 0x44, 0xD8, + 0xB3, 0xD8, 0xAC, 0x44, 0xD8, 0xB3, 0xD8, 0xAD, + 0x44, 0xD8, 0xB3, 0xD8, 0xAE, 0x44, 0xD8, 0xB3, + 0xD8, 0xB1, 0x44, 0xD8, 0xB3, 0xD9, 0x85, 0x44, + 0xD8, 0xB3, 0xD9, 0x87, 0x44, 0xD8, 0xB3, 0xD9, + 0x89, 0x44, 0xD8, 0xB3, 0xD9, 0x8A, 0x44, 0xD8, + // Bytes 1e80 - 1ebf + 0xB4, 0xD8, 0xAC, 0x44, 0xD8, 0xB4, 0xD8, 0xAD, + 0x44, 0xD8, 0xB4, 0xD8, 0xAE, 0x44, 0xD8, 0xB4, + 0xD8, 0xB1, 0x44, 0xD8, 0xB4, 0xD9, 0x85, 0x44, + 0xD8, 0xB4, 0xD9, 0x87, 0x44, 0xD8, 0xB4, 0xD9, + 0x89, 0x44, 0xD8, 0xB4, 0xD9, 0x8A, 0x44, 0xD8, + 0xB5, 0xD8, 0xAD, 0x44, 0xD8, 0xB5, 0xD8, 0xAE, + 0x44, 0xD8, 0xB5, 0xD8, 0xB1, 0x44, 0xD8, 0xB5, + 0xD9, 0x85, 0x44, 0xD8, 0xB5, 0xD9, 0x89, 0x44, + // Bytes 1ec0 - 1eff + 0xD8, 0xB5, 0xD9, 0x8A, 0x44, 0xD8, 0xB6, 0xD8, + 0xAC, 0x44, 0xD8, 0xB6, 0xD8, 0xAD, 0x44, 0xD8, + 0xB6, 0xD8, 0xAE, 0x44, 0xD8, 0xB6, 0xD8, 0xB1, + 0x44, 0xD8, 0xB6, 0xD9, 0x85, 0x44, 0xD8, 0xB6, + 0xD9, 0x89, 0x44, 0xD8, 0xB6, 0xD9, 0x8A, 0x44, + 0xD8, 0xB7, 0xD8, 0xAD, 0x44, 0xD8, 0xB7, 0xD9, + 0x85, 0x44, 0xD8, 0xB7, 0xD9, 0x89, 0x44, 0xD8, + 0xB7, 0xD9, 0x8A, 0x44, 0xD8, 0xB8, 0xD9, 0x85, + // Bytes 1f00 - 1f3f + 0x44, 0xD8, 0xB9, 0xD8, 0xAC, 0x44, 0xD8, 0xB9, + 0xD9, 0x85, 0x44, 0xD8, 0xB9, 0xD9, 0x89, 0x44, + 0xD8, 0xB9, 0xD9, 0x8A, 0x44, 0xD8, 0xBA, 0xD8, + 0xAC, 0x44, 0xD8, 0xBA, 0xD9, 0x85, 0x44, 0xD8, + 0xBA, 0xD9, 0x89, 0x44, 0xD8, 0xBA, 0xD9, 0x8A, + 0x44, 0xD9, 0x81, 0xD8, 0xAC, 0x44, 0xD9, 0x81, + 0xD8, 0xAD, 0x44, 0xD9, 0x81, 0xD8, 0xAE, 0x44, + 0xD9, 0x81, 0xD9, 0x85, 0x44, 0xD9, 0x81, 0xD9, + // Bytes 1f40 - 1f7f + 0x89, 0x44, 0xD9, 0x81, 0xD9, 0x8A, 0x44, 0xD9, + 0x82, 0xD8, 0xAD, 0x44, 0xD9, 0x82, 0xD9, 0x85, + 0x44, 0xD9, 0x82, 0xD9, 0x89, 0x44, 0xD9, 0x82, + 0xD9, 0x8A, 0x44, 0xD9, 0x83, 0xD8, 0xA7, 0x44, + 0xD9, 0x83, 0xD8, 0xAC, 0x44, 0xD9, 0x83, 0xD8, + 0xAD, 0x44, 0xD9, 0x83, 0xD8, 0xAE, 0x44, 0xD9, + 0x83, 0xD9, 0x84, 0x44, 0xD9, 0x83, 0xD9, 0x85, + 0x44, 0xD9, 0x83, 0xD9, 0x89, 0x44, 0xD9, 0x83, + // Bytes 1f80 - 1fbf + 0xD9, 0x8A, 0x44, 0xD9, 0x84, 0xD8, 0xA7, 0x44, + 0xD9, 0x84, 0xD8, 0xAC, 0x44, 0xD9, 0x84, 0xD8, + 0xAD, 0x44, 0xD9, 0x84, 0xD8, 0xAE, 0x44, 0xD9, + 0x84, 0xD9, 0x85, 0x44, 0xD9, 0x84, 0xD9, 0x87, + 0x44, 0xD9, 0x84, 0xD9, 0x89, 0x44, 0xD9, 0x84, + 0xD9, 0x8A, 0x44, 0xD9, 0x85, 0xD8, 0xA7, 0x44, + 0xD9, 0x85, 0xD8, 0xAC, 0x44, 0xD9, 0x85, 0xD8, + 0xAD, 0x44, 0xD9, 0x85, 0xD8, 0xAE, 0x44, 0xD9, + // Bytes 1fc0 - 1fff + 0x85, 0xD9, 0x85, 0x44, 0xD9, 0x85, 0xD9, 0x89, + 0x44, 0xD9, 0x85, 0xD9, 0x8A, 0x44, 0xD9, 0x86, + 0xD8, 0xAC, 0x44, 0xD9, 0x86, 0xD8, 0xAD, 0x44, + 0xD9, 0x86, 0xD8, 0xAE, 0x44, 0xD9, 0x86, 0xD8, + 0xB1, 0x44, 0xD9, 0x86, 0xD8, 0xB2, 0x44, 0xD9, + 0x86, 0xD9, 0x85, 0x44, 0xD9, 0x86, 0xD9, 0x86, + 0x44, 0xD9, 0x86, 0xD9, 0x87, 0x44, 0xD9, 0x86, + 0xD9, 0x89, 0x44, 0xD9, 0x86, 0xD9, 0x8A, 0x44, + // Bytes 2000 - 203f + 0xD9, 0x87, 0xD8, 0xAC, 0x44, 0xD9, 0x87, 0xD9, + 0x85, 0x44, 0xD9, 0x87, 0xD9, 0x89, 0x44, 0xD9, + 0x87, 0xD9, 0x8A, 0x44, 0xD9, 0x88, 0xD9, 0xB4, + 0x44, 0xD9, 0x8A, 0xD8, 0xAC, 0x44, 0xD9, 0x8A, + 0xD8, 0xAD, 0x44, 0xD9, 0x8A, 0xD8, 0xAE, 0x44, + 0xD9, 0x8A, 0xD8, 0xB1, 0x44, 0xD9, 0x8A, 0xD8, + 0xB2, 0x44, 0xD9, 0x8A, 0xD9, 0x85, 0x44, 0xD9, + 0x8A, 0xD9, 0x86, 0x44, 0xD9, 0x8A, 0xD9, 0x87, + // Bytes 2040 - 207f + 0x44, 0xD9, 0x8A, 0xD9, 0x89, 0x44, 0xD9, 0x8A, + 0xD9, 0x8A, 0x44, 0xD9, 0x8A, 0xD9, 0xB4, 0x44, + 0xDB, 0x87, 0xD9, 0xB4, 0x45, 0x28, 0xE1, 0x84, + 0x80, 0x29, 0x45, 0x28, 0xE1, 0x84, 0x82, 0x29, + 0x45, 0x28, 0xE1, 0x84, 0x83, 0x29, 0x45, 0x28, + 0xE1, 0x84, 0x85, 0x29, 0x45, 0x28, 0xE1, 0x84, + 0x86, 0x29, 0x45, 0x28, 0xE1, 0x84, 0x87, 0x29, + 0x45, 0x28, 0xE1, 0x84, 0x89, 0x29, 0x45, 0x28, + // Bytes 2080 - 20bf + 0xE1, 0x84, 0x8B, 0x29, 0x45, 0x28, 0xE1, 0x84, + 0x8C, 0x29, 0x45, 0x28, 0xE1, 0x84, 0x8E, 0x29, + 0x45, 0x28, 0xE1, 0x84, 0x8F, 0x29, 0x45, 0x28, + 0xE1, 0x84, 0x90, 0x29, 0x45, 0x28, 0xE1, 0x84, + 0x91, 0x29, 0x45, 0x28, 0xE1, 0x84, 0x92, 0x29, + 0x45, 0x28, 0xE4, 0xB8, 0x80, 0x29, 0x45, 0x28, + 0xE4, 0xB8, 0x83, 0x29, 0x45, 0x28, 0xE4, 0xB8, + 0x89, 0x29, 0x45, 0x28, 0xE4, 0xB9, 0x9D, 0x29, + // Bytes 20c0 - 20ff + 0x45, 0x28, 0xE4, 0xBA, 0x8C, 0x29, 0x45, 0x28, + 0xE4, 0xBA, 0x94, 0x29, 0x45, 0x28, 0xE4, 0xBB, + 0xA3, 0x29, 0x45, 0x28, 0xE4, 0xBC, 0x81, 0x29, + 0x45, 0x28, 0xE4, 0xBC, 0x91, 0x29, 0x45, 0x28, + 0xE5, 0x85, 0xAB, 0x29, 0x45, 0x28, 0xE5, 0x85, + 0xAD, 0x29, 0x45, 0x28, 0xE5, 0x8A, 0xB4, 0x29, + 0x45, 0x28, 0xE5, 0x8D, 0x81, 0x29, 0x45, 0x28, + 0xE5, 0x8D, 0x94, 0x29, 0x45, 0x28, 0xE5, 0x90, + // Bytes 2100 - 213f + 0x8D, 0x29, 0x45, 0x28, 0xE5, 0x91, 0xBC, 0x29, + 0x45, 0x28, 0xE5, 0x9B, 0x9B, 0x29, 0x45, 0x28, + 0xE5, 0x9C, 0x9F, 0x29, 0x45, 0x28, 0xE5, 0xAD, + 0xA6, 0x29, 0x45, 0x28, 0xE6, 0x97, 0xA5, 0x29, + 0x45, 0x28, 0xE6, 0x9C, 0x88, 0x29, 0x45, 0x28, + 0xE6, 0x9C, 0x89, 0x29, 0x45, 0x28, 0xE6, 0x9C, + 0xA8, 0x29, 0x45, 0x28, 0xE6, 0xA0, 0xAA, 0x29, + 0x45, 0x28, 0xE6, 0xB0, 0xB4, 0x29, 0x45, 0x28, + // Bytes 2140 - 217f + 0xE7, 0x81, 0xAB, 0x29, 0x45, 0x28, 0xE7, 0x89, + 0xB9, 0x29, 0x45, 0x28, 0xE7, 0x9B, 0xA3, 0x29, + 0x45, 0x28, 0xE7, 0xA4, 0xBE, 0x29, 0x45, 0x28, + 0xE7, 0xA5, 0x9D, 0x29, 0x45, 0x28, 0xE7, 0xA5, + 0xAD, 0x29, 0x45, 0x28, 0xE8, 0x87, 0xAA, 0x29, + 0x45, 0x28, 0xE8, 0x87, 0xB3, 0x29, 0x45, 0x28, + 0xE8, 0xB2, 0xA1, 0x29, 0x45, 0x28, 0xE8, 0xB3, + 0x87, 0x29, 0x45, 0x28, 0xE9, 0x87, 0x91, 0x29, + // Bytes 2180 - 21bf + 0x45, 0x30, 0xE2, 0x81, 0x84, 0x33, 0x45, 0x31, + 0x30, 0xE6, 0x97, 0xA5, 0x45, 0x31, 0x30, 0xE6, + 0x9C, 0x88, 0x45, 0x31, 0x30, 0xE7, 0x82, 0xB9, + 0x45, 0x31, 0x31, 0xE6, 0x97, 0xA5, 0x45, 0x31, + 0x31, 0xE6, 0x9C, 0x88, 0x45, 0x31, 0x31, 0xE7, + 0x82, 0xB9, 0x45, 0x31, 0x32, 0xE6, 0x97, 0xA5, + 0x45, 0x31, 0x32, 0xE6, 0x9C, 0x88, 0x45, 0x31, + 0x32, 0xE7, 0x82, 0xB9, 0x45, 0x31, 0x33, 0xE6, + // Bytes 21c0 - 21ff + 0x97, 0xA5, 0x45, 0x31, 0x33, 0xE7, 0x82, 0xB9, + 0x45, 0x31, 0x34, 0xE6, 0x97, 0xA5, 0x45, 0x31, + 0x34, 0xE7, 0x82, 0xB9, 0x45, 0x31, 0x35, 0xE6, + 0x97, 0xA5, 0x45, 0x31, 0x35, 0xE7, 0x82, 0xB9, + 0x45, 0x31, 0x36, 0xE6, 0x97, 0xA5, 0x45, 0x31, + 0x36, 0xE7, 0x82, 0xB9, 0x45, 0x31, 0x37, 0xE6, + 0x97, 0xA5, 0x45, 0x31, 0x37, 0xE7, 0x82, 0xB9, + 0x45, 0x31, 0x38, 0xE6, 0x97, 0xA5, 0x45, 0x31, + // Bytes 2200 - 223f + 0x38, 0xE7, 0x82, 0xB9, 0x45, 0x31, 0x39, 0xE6, + 0x97, 0xA5, 0x45, 0x31, 0x39, 0xE7, 0x82, 0xB9, + 0x45, 0x31, 0xE2, 0x81, 0x84, 0x32, 0x45, 0x31, + 0xE2, 0x81, 0x84, 0x33, 0x45, 0x31, 0xE2, 0x81, + 0x84, 0x34, 0x45, 0x31, 0xE2, 0x81, 0x84, 0x35, + 0x45, 0x31, 0xE2, 0x81, 0x84, 0x36, 0x45, 0x31, + 0xE2, 0x81, 0x84, 0x37, 0x45, 0x31, 0xE2, 0x81, + 0x84, 0x38, 0x45, 0x31, 0xE2, 0x81, 0x84, 0x39, + // Bytes 2240 - 227f + 0x45, 0x32, 0x30, 0xE6, 0x97, 0xA5, 0x45, 0x32, + 0x30, 0xE7, 0x82, 0xB9, 0x45, 0x32, 0x31, 0xE6, + 0x97, 0xA5, 0x45, 0x32, 0x31, 0xE7, 0x82, 0xB9, + 0x45, 0x32, 0x32, 0xE6, 0x97, 0xA5, 0x45, 0x32, + 0x32, 0xE7, 0x82, 0xB9, 0x45, 0x32, 0x33, 0xE6, + 0x97, 0xA5, 0x45, 0x32, 0x33, 0xE7, 0x82, 0xB9, + 0x45, 0x32, 0x34, 0xE6, 0x97, 0xA5, 0x45, 0x32, + 0x34, 0xE7, 0x82, 0xB9, 0x45, 0x32, 0x35, 0xE6, + // Bytes 2280 - 22bf + 0x97, 0xA5, 0x45, 0x32, 0x36, 0xE6, 0x97, 0xA5, + 0x45, 0x32, 0x37, 0xE6, 0x97, 0xA5, 0x45, 0x32, + 0x38, 0xE6, 0x97, 0xA5, 0x45, 0x32, 0x39, 0xE6, + 0x97, 0xA5, 0x45, 0x32, 0xE2, 0x81, 0x84, 0x33, + 0x45, 0x32, 0xE2, 0x81, 0x84, 0x35, 0x45, 0x33, + 0x30, 0xE6, 0x97, 0xA5, 0x45, 0x33, 0x31, 0xE6, + 0x97, 0xA5, 0x45, 0x33, 0xE2, 0x81, 0x84, 0x34, + 0x45, 0x33, 0xE2, 0x81, 0x84, 0x35, 0x45, 0x33, + // Bytes 22c0 - 22ff + 0xE2, 0x81, 0x84, 0x38, 0x45, 0x34, 0xE2, 0x81, + 0x84, 0x35, 0x45, 0x35, 0xE2, 0x81, 0x84, 0x36, + 0x45, 0x35, 0xE2, 0x81, 0x84, 0x38, 0x45, 0x37, + 0xE2, 0x81, 0x84, 0x38, 0x45, 0x41, 0xE2, 0x88, + 0x95, 0x6D, 0x45, 0x56, 0xE2, 0x88, 0x95, 0x6D, + 0x45, 0x6D, 0xE2, 0x88, 0x95, 0x73, 0x46, 0x31, + 0xE2, 0x81, 0x84, 0x31, 0x30, 0x46, 0x43, 0xE2, + 0x88, 0x95, 0x6B, 0x67, 0x46, 0x6D, 0xE2, 0x88, + // Bytes 2300 - 233f + 0x95, 0x73, 0x32, 0x46, 0xD8, 0xA8, 0xD8, 0xAD, + 0xD9, 0x8A, 0x46, 0xD8, 0xA8, 0xD8, 0xAE, 0xD9, + 0x8A, 0x46, 0xD8, 0xAA, 0xD8, 0xAC, 0xD9, 0x85, + 0x46, 0xD8, 0xAA, 0xD8, 0xAC, 0xD9, 0x89, 0x46, + 0xD8, 0xAA, 0xD8, 0xAC, 0xD9, 0x8A, 0x46, 0xD8, + 0xAA, 0xD8, 0xAD, 0xD8, 0xAC, 0x46, 0xD8, 0xAA, + 0xD8, 0xAD, 0xD9, 0x85, 0x46, 0xD8, 0xAA, 0xD8, + 0xAE, 0xD9, 0x85, 0x46, 0xD8, 0xAA, 0xD8, 0xAE, + // Bytes 2340 - 237f + 0xD9, 0x89, 0x46, 0xD8, 0xAA, 0xD8, 0xAE, 0xD9, + 0x8A, 0x46, 0xD8, 0xAA, 0xD9, 0x85, 0xD8, 0xAC, + 0x46, 0xD8, 0xAA, 0xD9, 0x85, 0xD8, 0xAD, 0x46, + 0xD8, 0xAA, 0xD9, 0x85, 0xD8, 0xAE, 0x46, 0xD8, + 0xAA, 0xD9, 0x85, 0xD9, 0x89, 0x46, 0xD8, 0xAA, + 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD8, 0xAC, 0xD8, + 0xAD, 0xD9, 0x89, 0x46, 0xD8, 0xAC, 0xD8, 0xAD, + 0xD9, 0x8A, 0x46, 0xD8, 0xAC, 0xD9, 0x85, 0xD8, + // Bytes 2380 - 23bf + 0xAD, 0x46, 0xD8, 0xAC, 0xD9, 0x85, 0xD9, 0x89, + 0x46, 0xD8, 0xAC, 0xD9, 0x85, 0xD9, 0x8A, 0x46, + 0xD8, 0xAD, 0xD8, 0xAC, 0xD9, 0x8A, 0x46, 0xD8, + 0xAD, 0xD9, 0x85, 0xD9, 0x89, 0x46, 0xD8, 0xAD, + 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD8, 0xB3, 0xD8, + 0xAC, 0xD8, 0xAD, 0x46, 0xD8, 0xB3, 0xD8, 0xAC, + 0xD9, 0x89, 0x46, 0xD8, 0xB3, 0xD8, 0xAD, 0xD8, + 0xAC, 0x46, 0xD8, 0xB3, 0xD8, 0xAE, 0xD9, 0x89, + // Bytes 23c0 - 23ff + 0x46, 0xD8, 0xB3, 0xD8, 0xAE, 0xD9, 0x8A, 0x46, + 0xD8, 0xB3, 0xD9, 0x85, 0xD8, 0xAC, 0x46, 0xD8, + 0xB3, 0xD9, 0x85, 0xD8, 0xAD, 0x46, 0xD8, 0xB3, + 0xD9, 0x85, 0xD9, 0x85, 0x46, 0xD8, 0xB4, 0xD8, + 0xAC, 0xD9, 0x8A, 0x46, 0xD8, 0xB4, 0xD8, 0xAD, + 0xD9, 0x85, 0x46, 0xD8, 0xB4, 0xD8, 0xAD, 0xD9, + 0x8A, 0x46, 0xD8, 0xB4, 0xD9, 0x85, 0xD8, 0xAE, + 0x46, 0xD8, 0xB4, 0xD9, 0x85, 0xD9, 0x85, 0x46, + // Bytes 2400 - 243f + 0xD8, 0xB5, 0xD8, 0xAD, 0xD8, 0xAD, 0x46, 0xD8, + 0xB5, 0xD8, 0xAD, 0xD9, 0x8A, 0x46, 0xD8, 0xB5, + 0xD9, 0x84, 0xD9, 0x89, 0x46, 0xD8, 0xB5, 0xD9, + 0x84, 0xDB, 0x92, 0x46, 0xD8, 0xB5, 0xD9, 0x85, + 0xD9, 0x85, 0x46, 0xD8, 0xB6, 0xD8, 0xAD, 0xD9, + 0x89, 0x46, 0xD8, 0xB6, 0xD8, 0xAD, 0xD9, 0x8A, + 0x46, 0xD8, 0xB6, 0xD8, 0xAE, 0xD9, 0x85, 0x46, + 0xD8, 0xB7, 0xD9, 0x85, 0xD8, 0xAD, 0x46, 0xD8, + // Bytes 2440 - 247f + 0xB7, 0xD9, 0x85, 0xD9, 0x85, 0x46, 0xD8, 0xB7, + 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD8, 0xB9, 0xD8, + 0xAC, 0xD9, 0x85, 0x46, 0xD8, 0xB9, 0xD9, 0x85, + 0xD9, 0x85, 0x46, 0xD8, 0xB9, 0xD9, 0x85, 0xD9, + 0x89, 0x46, 0xD8, 0xB9, 0xD9, 0x85, 0xD9, 0x8A, + 0x46, 0xD8, 0xBA, 0xD9, 0x85, 0xD9, 0x85, 0x46, + 0xD8, 0xBA, 0xD9, 0x85, 0xD9, 0x89, 0x46, 0xD8, + 0xBA, 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD9, 0x81, + // Bytes 2480 - 24bf + 0xD8, 0xAE, 0xD9, 0x85, 0x46, 0xD9, 0x81, 0xD9, + 0x85, 0xD9, 0x8A, 0x46, 0xD9, 0x82, 0xD9, 0x84, + 0xDB, 0x92, 0x46, 0xD9, 0x82, 0xD9, 0x85, 0xD8, + 0xAD, 0x46, 0xD9, 0x82, 0xD9, 0x85, 0xD9, 0x85, + 0x46, 0xD9, 0x82, 0xD9, 0x85, 0xD9, 0x8A, 0x46, + 0xD9, 0x83, 0xD9, 0x85, 0xD9, 0x85, 0x46, 0xD9, + 0x83, 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD9, 0x84, + 0xD8, 0xAC, 0xD8, 0xAC, 0x46, 0xD9, 0x84, 0xD8, + // Bytes 24c0 - 24ff + 0xAC, 0xD9, 0x85, 0x46, 0xD9, 0x84, 0xD8, 0xAC, + 0xD9, 0x8A, 0x46, 0xD9, 0x84, 0xD8, 0xAD, 0xD9, + 0x85, 0x46, 0xD9, 0x84, 0xD8, 0xAD, 0xD9, 0x89, + 0x46, 0xD9, 0x84, 0xD8, 0xAD, 0xD9, 0x8A, 0x46, + 0xD9, 0x84, 0xD8, 0xAE, 0xD9, 0x85, 0x46, 0xD9, + 0x84, 0xD9, 0x85, 0xD8, 0xAD, 0x46, 0xD9, 0x84, + 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD9, 0x85, 0xD8, + 0xAC, 0xD8, 0xAD, 0x46, 0xD9, 0x85, 0xD8, 0xAC, + // Bytes 2500 - 253f + 0xD8, 0xAE, 0x46, 0xD9, 0x85, 0xD8, 0xAC, 0xD9, + 0x85, 0x46, 0xD9, 0x85, 0xD8, 0xAC, 0xD9, 0x8A, + 0x46, 0xD9, 0x85, 0xD8, 0xAD, 0xD8, 0xAC, 0x46, + 0xD9, 0x85, 0xD8, 0xAD, 0xD9, 0x85, 0x46, 0xD9, + 0x85, 0xD8, 0xAD, 0xD9, 0x8A, 0x46, 0xD9, 0x85, + 0xD8, 0xAE, 0xD8, 0xAC, 0x46, 0xD9, 0x85, 0xD8, + 0xAE, 0xD9, 0x85, 0x46, 0xD9, 0x85, 0xD8, 0xAE, + 0xD9, 0x8A, 0x46, 0xD9, 0x85, 0xD9, 0x85, 0xD9, + // Bytes 2540 - 257f + 0x8A, 0x46, 0xD9, 0x86, 0xD8, 0xAC, 0xD8, 0xAD, + 0x46, 0xD9, 0x86, 0xD8, 0xAC, 0xD9, 0x85, 0x46, + 0xD9, 0x86, 0xD8, 0xAC, 0xD9, 0x89, 0x46, 0xD9, + 0x86, 0xD8, 0xAC, 0xD9, 0x8A, 0x46, 0xD9, 0x86, + 0xD8, 0xAD, 0xD9, 0x85, 0x46, 0xD9, 0x86, 0xD8, + 0xAD, 0xD9, 0x89, 0x46, 0xD9, 0x86, 0xD8, 0xAD, + 0xD9, 0x8A, 0x46, 0xD9, 0x86, 0xD9, 0x85, 0xD9, + 0x89, 0x46, 0xD9, 0x86, 0xD9, 0x85, 0xD9, 0x8A, + // Bytes 2580 - 25bf + 0x46, 0xD9, 0x87, 0xD9, 0x85, 0xD8, 0xAC, 0x46, + 0xD9, 0x87, 0xD9, 0x85, 0xD9, 0x85, 0x46, 0xD9, + 0x8A, 0xD8, 0xAC, 0xD9, 0x8A, 0x46, 0xD9, 0x8A, + 0xD8, 0xAD, 0xD9, 0x8A, 0x46, 0xD9, 0x8A, 0xD9, + 0x85, 0xD9, 0x85, 0x46, 0xD9, 0x8A, 0xD9, 0x85, + 0xD9, 0x8A, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD8, + 0xA7, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xAC, + 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xAD, 0x46, + // Bytes 25c0 - 25ff + 0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xAE, 0x46, 0xD9, + 0x8A, 0xD9, 0x94, 0xD8, 0xB1, 0x46, 0xD9, 0x8A, + 0xD9, 0x94, 0xD8, 0xB2, 0x46, 0xD9, 0x8A, 0xD9, + 0x94, 0xD9, 0x85, 0x46, 0xD9, 0x8A, 0xD9, 0x94, + 0xD9, 0x86, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD9, + 0x87, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x88, + 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x89, 0x46, + 0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x8A, 0x46, 0xD9, + // Bytes 2600 - 263f + 0x8A, 0xD9, 0x94, 0xDB, 0x86, 0x46, 0xD9, 0x8A, + 0xD9, 0x94, 0xDB, 0x87, 0x46, 0xD9, 0x8A, 0xD9, + 0x94, 0xDB, 0x88, 0x46, 0xD9, 0x8A, 0xD9, 0x94, + 0xDB, 0x90, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xDB, + 0x95, 0x46, 0xE0, 0xB9, 0x8D, 0xE0, 0xB8, 0xB2, + 0x46, 0xE0, 0xBA, 0xAB, 0xE0, 0xBA, 0x99, 0x46, + 0xE0, 0xBA, 0xAB, 0xE0, 0xBA, 0xA1, 0x46, 0xE0, + 0xBB, 0x8D, 0xE0, 0xBA, 0xB2, 0x46, 0xE0, 0xBD, + // Bytes 2640 - 267f + 0x80, 0xE0, 0xBE, 0xB5, 0x46, 0xE0, 0xBD, 0x82, + 0xE0, 0xBE, 0xB7, 0x46, 0xE0, 0xBD, 0x8C, 0xE0, + 0xBE, 0xB7, 0x46, 0xE0, 0xBD, 0x91, 0xE0, 0xBE, + 0xB7, 0x46, 0xE0, 0xBD, 0x96, 0xE0, 0xBE, 0xB7, + 0x46, 0xE0, 0xBD, 0x9B, 0xE0, 0xBE, 0xB7, 0x46, + 0xE0, 0xBE, 0x90, 0xE0, 0xBE, 0xB5, 0x46, 0xE0, + 0xBE, 0x92, 0xE0, 0xBE, 0xB7, 0x46, 0xE0, 0xBE, + 0x9C, 0xE0, 0xBE, 0xB7, 0x46, 0xE0, 0xBE, 0xA1, + // Bytes 2680 - 26bf + 0xE0, 0xBE, 0xB7, 0x46, 0xE0, 0xBE, 0xA6, 0xE0, + 0xBE, 0xB7, 0x46, 0xE0, 0xBE, 0xAB, 0xE0, 0xBE, + 0xB7, 0x46, 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2, + 0x46, 0xE2, 0x80, 0xB5, 0xE2, 0x80, 0xB5, 0x46, + 0xE2, 0x88, 0xAB, 0xE2, 0x88, 0xAB, 0x46, 0xE2, + 0x88, 0xAE, 0xE2, 0x88, 0xAE, 0x46, 0xE3, 0x81, + 0xBB, 0xE3, 0x81, 0x8B, 0x46, 0xE3, 0x82, 0x88, + 0xE3, 0x82, 0x8A, 0x46, 0xE3, 0x82, 0xAD, 0xE3, + // Bytes 26c0 - 26ff + 0x83, 0xAD, 0x46, 0xE3, 0x82, 0xB3, 0xE3, 0x82, + 0xB3, 0x46, 0xE3, 0x82, 0xB3, 0xE3, 0x83, 0x88, + 0x46, 0xE3, 0x83, 0x88, 0xE3, 0x83, 0xB3, 0x46, + 0xE3, 0x83, 0x8A, 0xE3, 0x83, 0x8E, 0x46, 0xE3, + 0x83, 0x9B, 0xE3, 0x83, 0xB3, 0x46, 0xE3, 0x83, + 0x9F, 0xE3, 0x83, 0xAA, 0x46, 0xE3, 0x83, 0xAA, + 0xE3, 0x83, 0xA9, 0x46, 0xE3, 0x83, 0xAC, 0xE3, + 0x83, 0xA0, 0x46, 0xE5, 0xA4, 0xA7, 0xE6, 0xAD, + // Bytes 2700 - 273f + 0xA3, 0x46, 0xE5, 0xB9, 0xB3, 0xE6, 0x88, 0x90, + 0x46, 0xE6, 0x98, 0x8E, 0xE6, 0xB2, 0xBB, 0x46, + 0xE6, 0x98, 0xAD, 0xE5, 0x92, 0x8C, 0x47, 0x72, + 0x61, 0x64, 0xE2, 0x88, 0x95, 0x73, 0x47, 0xE3, + 0x80, 0x94, 0x53, 0xE3, 0x80, 0x95, 0x48, 0x28, + 0xE1, 0x84, 0x80, 0xE1, 0x85, 0xA1, 0x29, 0x48, + 0x28, 0xE1, 0x84, 0x82, 0xE1, 0x85, 0xA1, 0x29, + 0x48, 0x28, 0xE1, 0x84, 0x83, 0xE1, 0x85, 0xA1, + // Bytes 2740 - 277f + 0x29, 0x48, 0x28, 0xE1, 0x84, 0x85, 0xE1, 0x85, + 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, 0x86, 0xE1, + 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, 0x87, + 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, + 0x89, 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, + 0x84, 0x8B, 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28, + 0xE1, 0x84, 0x8C, 0xE1, 0x85, 0xA1, 0x29, 0x48, + 0x28, 0xE1, 0x84, 0x8C, 0xE1, 0x85, 0xAE, 0x29, + // Bytes 2780 - 27bf + 0x48, 0x28, 0xE1, 0x84, 0x8E, 0xE1, 0x85, 0xA1, + 0x29, 0x48, 0x28, 0xE1, 0x84, 0x8F, 0xE1, 0x85, + 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, 0x90, 0xE1, + 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, 0x91, + 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, + 0x92, 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x72, 0x61, + 0x64, 0xE2, 0x88, 0x95, 0x73, 0x32, 0x48, 0xD8, + 0xA7, 0xD9, 0x83, 0xD8, 0xA8, 0xD8, 0xB1, 0x48, + // Bytes 27c0 - 27ff + 0xD8, 0xA7, 0xD9, 0x84, 0xD9, 0x84, 0xD9, 0x87, + 0x48, 0xD8, 0xB1, 0xD8, 0xB3, 0xD9, 0x88, 0xD9, + 0x84, 0x48, 0xD8, 0xB1, 0xDB, 0x8C, 0xD8, 0xA7, + 0xD9, 0x84, 0x48, 0xD8, 0xB5, 0xD9, 0x84, 0xD8, + 0xB9, 0xD9, 0x85, 0x48, 0xD8, 0xB9, 0xD9, 0x84, + 0xD9, 0x8A, 0xD9, 0x87, 0x48, 0xD9, 0x85, 0xD8, + 0xAD, 0xD9, 0x85, 0xD8, 0xAF, 0x48, 0xD9, 0x88, + 0xD8, 0xB3, 0xD9, 0x84, 0xD9, 0x85, 0x49, 0xE2, + // Bytes 2800 - 283f + 0x80, 0xB2, 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2, + 0x49, 0xE2, 0x80, 0xB5, 0xE2, 0x80, 0xB5, 0xE2, + 0x80, 0xB5, 0x49, 0xE2, 0x88, 0xAB, 0xE2, 0x88, + 0xAB, 0xE2, 0x88, 0xAB, 0x49, 0xE2, 0x88, 0xAE, + 0xE2, 0x88, 0xAE, 0xE2, 0x88, 0xAE, 0x49, 0xE3, + 0x80, 0x94, 0xE4, 0xB8, 0x89, 0xE3, 0x80, 0x95, + 0x49, 0xE3, 0x80, 0x94, 0xE4, 0xBA, 0x8C, 0xE3, + 0x80, 0x95, 0x49, 0xE3, 0x80, 0x94, 0xE5, 0x8B, + // Bytes 2840 - 287f + 0x9D, 0xE3, 0x80, 0x95, 0x49, 0xE3, 0x80, 0x94, + 0xE5, 0xAE, 0x89, 0xE3, 0x80, 0x95, 0x49, 0xE3, + 0x80, 0x94, 0xE6, 0x89, 0x93, 0xE3, 0x80, 0x95, + 0x49, 0xE3, 0x80, 0x94, 0xE6, 0x95, 0x97, 0xE3, + 0x80, 0x95, 0x49, 0xE3, 0x80, 0x94, 0xE6, 0x9C, + 0xAC, 0xE3, 0x80, 0x95, 0x49, 0xE3, 0x80, 0x94, + 0xE7, 0x82, 0xB9, 0xE3, 0x80, 0x95, 0x49, 0xE3, + 0x80, 0x94, 0xE7, 0x9B, 0x97, 0xE3, 0x80, 0x95, + // Bytes 2880 - 28bf + 0x49, 0xE3, 0x82, 0xA2, 0xE3, 0x83, 0xBC, 0xE3, + 0x83, 0xAB, 0x49, 0xE3, 0x82, 0xA4, 0xE3, 0x83, + 0xB3, 0xE3, 0x83, 0x81, 0x49, 0xE3, 0x82, 0xA6, + 0xE3, 0x82, 0xA9, 0xE3, 0x83, 0xB3, 0x49, 0xE3, + 0x82, 0xAA, 0xE3, 0x83, 0xB3, 0xE3, 0x82, 0xB9, + 0x49, 0xE3, 0x82, 0xAA, 0xE3, 0x83, 0xBC, 0xE3, + 0x83, 0xA0, 0x49, 0xE3, 0x82, 0xAB, 0xE3, 0x82, + 0xA4, 0xE3, 0x83, 0xAA, 0x49, 0xE3, 0x82, 0xB1, + // Bytes 28c0 - 28ff + 0xE3, 0x83, 0xBC, 0xE3, 0x82, 0xB9, 0x49, 0xE3, + 0x82, 0xB3, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x8A, + 0x49, 0xE3, 0x82, 0xBB, 0xE3, 0x83, 0xB3, 0xE3, + 0x83, 0x81, 0x49, 0xE3, 0x82, 0xBB, 0xE3, 0x83, + 0xB3, 0xE3, 0x83, 0x88, 0x49, 0xE3, 0x83, 0x86, + 0xE3, 0x82, 0x99, 0xE3, 0x82, 0xB7, 0x49, 0xE3, + 0x83, 0x88, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xAB, + 0x49, 0xE3, 0x83, 0x8E, 0xE3, 0x83, 0x83, 0xE3, + // Bytes 2900 - 293f + 0x83, 0x88, 0x49, 0xE3, 0x83, 0x8F, 0xE3, 0x82, + 0xA4, 0xE3, 0x83, 0x84, 0x49, 0xE3, 0x83, 0x92, + 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xAB, 0x49, 0xE3, + 0x83, 0x92, 0xE3, 0x82, 0x9A, 0xE3, 0x82, 0xB3, + 0x49, 0xE3, 0x83, 0x95, 0xE3, 0x83, 0xA9, 0xE3, + 0x83, 0xB3, 0x49, 0xE3, 0x83, 0x98, 0xE3, 0x82, + 0x9A, 0xE3, 0x82, 0xBD, 0x49, 0xE3, 0x83, 0x98, + 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x84, 0x49, 0xE3, + // Bytes 2940 - 297f + 0x83, 0x9B, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0xAB, + 0x49, 0xE3, 0x83, 0x9B, 0xE3, 0x83, 0xBC, 0xE3, + 0x83, 0xB3, 0x49, 0xE3, 0x83, 0x9E, 0xE3, 0x82, + 0xA4, 0xE3, 0x83, 0xAB, 0x49, 0xE3, 0x83, 0x9E, + 0xE3, 0x83, 0x83, 0xE3, 0x83, 0x8F, 0x49, 0xE3, + 0x83, 0x9E, 0xE3, 0x83, 0xAB, 0xE3, 0x82, 0xAF, + 0x49, 0xE3, 0x83, 0xA4, 0xE3, 0x83, 0xBC, 0xE3, + 0x83, 0xAB, 0x49, 0xE3, 0x83, 0xA6, 0xE3, 0x82, + // Bytes 2980 - 29bf + 0xA2, 0xE3, 0x83, 0xB3, 0x49, 0xE3, 0x83, 0xAF, + 0xE3, 0x83, 0x83, 0xE3, 0x83, 0x88, 0x4C, 0xE2, + 0x80, 0xB2, 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2, + 0xE2, 0x80, 0xB2, 0x4C, 0xE2, 0x88, 0xAB, 0xE2, + 0x88, 0xAB, 0xE2, 0x88, 0xAB, 0xE2, 0x88, 0xAB, + 0x4C, 0xE3, 0x82, 0xA2, 0xE3, 0x83, 0xAB, 0xE3, + 0x83, 0x95, 0xE3, 0x82, 0xA1, 0x4C, 0xE3, 0x82, + 0xA8, 0xE3, 0x83, 0xBC, 0xE3, 0x82, 0xAB, 0xE3, + // Bytes 29c0 - 29ff + 0x83, 0xBC, 0x4C, 0xE3, 0x82, 0xAB, 0xE3, 0x82, + 0x99, 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xB3, 0x4C, + 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0xE3, 0x83, + 0xB3, 0xE3, 0x83, 0x9E, 0x4C, 0xE3, 0x82, 0xAB, + 0xE3, 0x83, 0xA9, 0xE3, 0x83, 0x83, 0xE3, 0x83, + 0x88, 0x4C, 0xE3, 0x82, 0xAB, 0xE3, 0x83, 0xAD, + 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0xBC, 0x4C, 0xE3, + 0x82, 0xAD, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0x8B, + // Bytes 2a00 - 2a3f + 0xE3, 0x83, 0xBC, 0x4C, 0xE3, 0x82, 0xAD, 0xE3, + 0x83, 0xA5, 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0xBC, + 0x4C, 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, 0xE3, + 0x83, 0xA9, 0xE3, 0x83, 0xA0, 0x4C, 0xE3, 0x82, + 0xAF, 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xBC, 0xE3, + 0x83, 0x8D, 0x4C, 0xE3, 0x82, 0xB5, 0xE3, 0x82, + 0xA4, 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAB, 0x4C, + 0xE3, 0x82, 0xBF, 0xE3, 0x82, 0x99, 0xE3, 0x83, + // Bytes 2a40 - 2a7f + 0xBC, 0xE3, 0x82, 0xB9, 0x4C, 0xE3, 0x83, 0x8F, + 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC, 0xE3, 0x83, + 0x84, 0x4C, 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x9A, + 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAB, 0x4C, 0xE3, + 0x83, 0x95, 0xE3, 0x82, 0xA3, 0xE3, 0x83, 0xBC, + 0xE3, 0x83, 0x88, 0x4C, 0xE3, 0x83, 0x98, 0xE3, + 0x82, 0x99, 0xE3, 0x83, 0xBC, 0xE3, 0x82, 0xBF, + 0x4C, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x9A, 0xE3, + // Bytes 2a80 - 2abf + 0x83, 0x8B, 0xE3, 0x83, 0x92, 0x4C, 0xE3, 0x83, + 0x98, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xB3, 0xE3, + 0x82, 0xB9, 0x4C, 0xE3, 0x83, 0x9B, 0xE3, 0x82, + 0x99, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x88, 0x4C, + 0xE3, 0x83, 0x9E, 0xE3, 0x82, 0xA4, 0xE3, 0x82, + 0xAF, 0xE3, 0x83, 0xAD, 0x4C, 0xE3, 0x83, 0x9F, + 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAD, 0xE3, 0x83, + 0xB3, 0x4C, 0xE3, 0x83, 0xA1, 0xE3, 0x83, 0xBC, + // Bytes 2ac0 - 2aff + 0xE3, 0x83, 0x88, 0xE3, 0x83, 0xAB, 0x4C, 0xE3, + 0x83, 0xAA, 0xE3, 0x83, 0x83, 0xE3, 0x83, 0x88, + 0xE3, 0x83, 0xAB, 0x4C, 0xE3, 0x83, 0xAB, 0xE3, + 0x83, 0x92, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC, + 0x4C, 0xE6, 0xA0, 0xAA, 0xE5, 0xBC, 0x8F, 0xE4, + 0xBC, 0x9A, 0xE7, 0xA4, 0xBE, 0x4E, 0x28, 0xE1, + 0x84, 0x8B, 0xE1, 0x85, 0xA9, 0xE1, 0x84, 0x92, + 0xE1, 0x85, 0xAE, 0x29, 0x4F, 0xD8, 0xAC, 0xD9, + // Bytes 2b00 - 2b3f + 0x84, 0x20, 0xD8, 0xAC, 0xD9, 0x84, 0xD8, 0xA7, + 0xD9, 0x84, 0xD9, 0x87, 0x4F, 0xE3, 0x82, 0xA2, + 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x9A, 0xE3, 0x83, + 0xBC, 0xE3, 0x83, 0x88, 0x4F, 0xE3, 0x82, 0xA2, + 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x98, 0xE3, 0x82, + 0x9A, 0xE3, 0x82, 0xA2, 0x4F, 0xE3, 0x82, 0xAD, + 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xAF, 0xE3, 0x83, + 0x83, 0xE3, 0x83, 0x88, 0x4F, 0xE3, 0x82, 0xB5, + // Bytes 2b40 - 2b7f + 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x81, 0xE3, 0x83, + 0xBC, 0xE3, 0x83, 0xA0, 0x4F, 0xE3, 0x83, 0x8F, + 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xBC, 0xE3, 0x83, + 0xAC, 0xE3, 0x83, 0xAB, 0x4F, 0xE3, 0x83, 0x98, + 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0xBF, 0xE3, 0x83, + 0xBC, 0xE3, 0x83, 0xAB, 0x4F, 0xE3, 0x83, 0x9B, + 0xE3, 0x82, 0x9A, 0xE3, 0x82, 0xA4, 0xE3, 0x83, + 0xB3, 0xE3, 0x83, 0x88, 0x4F, 0xE3, 0x83, 0x9E, + // Bytes 2b80 - 2bbf + 0xE3, 0x83, 0xB3, 0xE3, 0x82, 0xB7, 0xE3, 0x83, + 0xA7, 0xE3, 0x83, 0xB3, 0x4F, 0xE3, 0x83, 0xA1, + 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0xE3, 0x83, + 0x88, 0xE3, 0x83, 0xB3, 0x4F, 0xE3, 0x83, 0xAB, + 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x95, 0xE3, 0x82, + 0x99, 0xE3, 0x83, 0xAB, 0x51, 0x28, 0xE1, 0x84, + 0x8B, 0xE1, 0x85, 0xA9, 0xE1, 0x84, 0x8C, 0xE1, + 0x85, 0xA5, 0xE1, 0x86, 0xAB, 0x29, 0x52, 0xE3, + // Bytes 2bc0 - 2bff + 0x82, 0xAD, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xAB, + 0xE3, 0x82, 0xBF, 0xE3, 0x82, 0x99, 0xE3, 0x83, + 0xBC, 0x52, 0xE3, 0x82, 0xAD, 0xE3, 0x83, 0xAD, + 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, 0xE3, 0x83, + 0xA9, 0xE3, 0x83, 0xA0, 0x52, 0xE3, 0x82, 0xAD, + 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xA1, 0xE3, 0x83, + 0xBC, 0xE3, 0x83, 0x88, 0xE3, 0x83, 0xAB, 0x52, + 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, 0xE3, 0x83, + // Bytes 2c00 - 2c3f + 0xA9, 0xE3, 0x83, 0xA0, 0xE3, 0x83, 0x88, 0xE3, + 0x83, 0xB3, 0x52, 0xE3, 0x82, 0xAF, 0xE3, 0x83, + 0xAB, 0xE3, 0x82, 0xBB, 0xE3, 0x82, 0x99, 0xE3, + 0x82, 0xA4, 0xE3, 0x83, 0xAD, 0x52, 0xE3, 0x83, + 0x8F, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC, 0xE3, + 0x82, 0xBB, 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x88, + 0x52, 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x9A, 0xE3, + 0x82, 0xA2, 0xE3, 0x82, 0xB9, 0xE3, 0x83, 0x88, + // Bytes 2c40 - 2c7f + 0xE3, 0x83, 0xAB, 0x52, 0xE3, 0x83, 0x95, 0xE3, + 0x82, 0x99, 0xE3, 0x83, 0x83, 0xE3, 0x82, 0xB7, + 0xE3, 0x82, 0xA7, 0xE3, 0x83, 0xAB, 0x52, 0xE3, + 0x83, 0x9F, 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0x8F, + 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xBC, 0xE3, 0x83, + 0xAB, 0x52, 0xE3, 0x83, 0xAC, 0xE3, 0x83, 0xB3, + 0xE3, 0x83, 0x88, 0xE3, 0x82, 0xB1, 0xE3, 0x82, + 0x99, 0xE3, 0x83, 0xB3, 0x61, 0xD8, 0xB5, 0xD9, + // Bytes 2c80 - 2cbf + 0x84, 0xD9, 0x89, 0x20, 0xD8, 0xA7, 0xD9, 0x84, + 0xD9, 0x84, 0xD9, 0x87, 0x20, 0xD8, 0xB9, 0xD9, + 0x84, 0xD9, 0x8A, 0xD9, 0x87, 0x20, 0xD9, 0x88, + 0xD8, 0xB3, 0xD9, 0x84, 0xD9, 0x85, 0x06, 0xE0, + 0xA7, 0x87, 0xE0, 0xA6, 0xBE, 0x01, 0x06, 0xE0, + 0xA7, 0x87, 0xE0, 0xA7, 0x97, 0x01, 0x06, 0xE0, + 0xAD, 0x87, 0xE0, 0xAC, 0xBE, 0x01, 0x06, 0xE0, + 0xAD, 0x87, 0xE0, 0xAD, 0x96, 0x01, 0x06, 0xE0, + // Bytes 2cc0 - 2cff + 0xAD, 0x87, 0xE0, 0xAD, 0x97, 0x01, 0x06, 0xE0, + 0xAE, 0x92, 0xE0, 0xAF, 0x97, 0x01, 0x06, 0xE0, + 0xAF, 0x86, 0xE0, 0xAE, 0xBE, 0x01, 0x06, 0xE0, + 0xAF, 0x86, 0xE0, 0xAF, 0x97, 0x01, 0x06, 0xE0, + 0xAF, 0x87, 0xE0, 0xAE, 0xBE, 0x01, 0x06, 0xE0, + 0xB2, 0xBF, 0xE0, 0xB3, 0x95, 0x01, 0x06, 0xE0, + 0xB3, 0x86, 0xE0, 0xB3, 0x95, 0x01, 0x06, 0xE0, + 0xB3, 0x86, 0xE0, 0xB3, 0x96, 0x01, 0x06, 0xE0, + // Bytes 2d00 - 2d3f + 0xB5, 0x86, 0xE0, 0xB4, 0xBE, 0x01, 0x06, 0xE0, + 0xB5, 0x86, 0xE0, 0xB5, 0x97, 0x01, 0x06, 0xE0, + 0xB5, 0x87, 0xE0, 0xB4, 0xBE, 0x01, 0x06, 0xE0, + 0xB7, 0x99, 0xE0, 0xB7, 0x9F, 0x01, 0x06, 0xE1, + 0x80, 0xA5, 0xE1, 0x80, 0xAE, 0x01, 0x06, 0xE1, + 0xAC, 0x85, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1, + 0xAC, 0x87, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1, + 0xAC, 0x89, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1, + // Bytes 2d40 - 2d7f + 0xAC, 0x8B, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1, + 0xAC, 0x8D, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1, + 0xAC, 0x91, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1, + 0xAC, 0xBA, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1, + 0xAC, 0xBC, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1, + 0xAC, 0xBE, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1, + 0xAC, 0xBF, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1, + 0xAD, 0x82, 0xE1, 0xAC, 0xB5, 0x01, 0x08, 0xF0, + // Bytes 2d80 - 2dbf + 0x91, 0x84, 0xB1, 0xF0, 0x91, 0x84, 0xA7, 0x01, + 0x08, 0xF0, 0x91, 0x84, 0xB2, 0xF0, 0x91, 0x84, + 0xA7, 0x01, 0x08, 0xF0, 0x91, 0x8D, 0x87, 0xF0, + 0x91, 0x8C, 0xBE, 0x01, 0x08, 0xF0, 0x91, 0x8D, + 0x87, 0xF0, 0x91, 0x8D, 0x97, 0x01, 0x08, 0xF0, + 0x91, 0x92, 0xB9, 0xF0, 0x91, 0x92, 0xB0, 0x01, + 0x08, 0xF0, 0x91, 0x92, 0xB9, 0xF0, 0x91, 0x92, + 0xBA, 0x01, 0x08, 0xF0, 0x91, 0x92, 0xB9, 0xF0, + // Bytes 2dc0 - 2dff + 0x91, 0x92, 0xBD, 0x01, 0x08, 0xF0, 0x91, 0x96, + 0xB8, 0xF0, 0x91, 0x96, 0xAF, 0x01, 0x08, 0xF0, + 0x91, 0x96, 0xB9, 0xF0, 0x91, 0x96, 0xAF, 0x01, + 0x09, 0xE0, 0xB3, 0x86, 0xE0, 0xB3, 0x82, 0xE0, + 0xB3, 0x95, 0x02, 0x09, 0xE0, 0xB7, 0x99, 0xE0, + 0xB7, 0x8F, 0xE0, 0xB7, 0x8A, 0x12, 0x44, 0x44, + 0x5A, 0xCC, 0x8C, 0xC9, 0x44, 0x44, 0x7A, 0xCC, + 0x8C, 0xC9, 0x44, 0x64, 0x7A, 0xCC, 0x8C, 0xC9, + // Bytes 2e00 - 2e3f + 0x46, 0xD9, 0x84, 0xD8, 0xA7, 0xD9, 0x93, 0xC9, + 0x46, 0xD9, 0x84, 0xD8, 0xA7, 0xD9, 0x94, 0xC9, + 0x46, 0xD9, 0x84, 0xD8, 0xA7, 0xD9, 0x95, 0xB5, + 0x46, 0xE1, 0x84, 0x80, 0xE1, 0x85, 0xA1, 0x01, + 0x46, 0xE1, 0x84, 0x82, 0xE1, 0x85, 0xA1, 0x01, + 0x46, 0xE1, 0x84, 0x83, 0xE1, 0x85, 0xA1, 0x01, + 0x46, 0xE1, 0x84, 0x85, 0xE1, 0x85, 0xA1, 0x01, + 0x46, 0xE1, 0x84, 0x86, 0xE1, 0x85, 0xA1, 0x01, + // Bytes 2e40 - 2e7f + 0x46, 0xE1, 0x84, 0x87, 0xE1, 0x85, 0xA1, 0x01, + 0x46, 0xE1, 0x84, 0x89, 0xE1, 0x85, 0xA1, 0x01, + 0x46, 0xE1, 0x84, 0x8B, 0xE1, 0x85, 0xA1, 0x01, + 0x46, 0xE1, 0x84, 0x8B, 0xE1, 0x85, 0xAE, 0x01, + 0x46, 0xE1, 0x84, 0x8C, 0xE1, 0x85, 0xA1, 0x01, + 0x46, 0xE1, 0x84, 0x8E, 0xE1, 0x85, 0xA1, 0x01, + 0x46, 0xE1, 0x84, 0x8F, 0xE1, 0x85, 0xA1, 0x01, + 0x46, 0xE1, 0x84, 0x90, 0xE1, 0x85, 0xA1, 0x01, + // Bytes 2e80 - 2ebf + 0x46, 0xE1, 0x84, 0x91, 0xE1, 0x85, 0xA1, 0x01, + 0x46, 0xE1, 0x84, 0x92, 0xE1, 0x85, 0xA1, 0x01, + 0x49, 0xE3, 0x83, 0xA1, 0xE3, 0x82, 0xAB, 0xE3, + 0x82, 0x99, 0x0D, 0x4C, 0xE1, 0x84, 0x8C, 0xE1, + 0x85, 0xAE, 0xE1, 0x84, 0x8B, 0xE1, 0x85, 0xB4, + 0x01, 0x4C, 0xE3, 0x82, 0xAD, 0xE3, 0x82, 0x99, + 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0x0D, 0x4C, + 0xE3, 0x82, 0xB3, 0xE3, 0x83, 0xBC, 0xE3, 0x83, + // Bytes 2ec0 - 2eff + 0x9B, 0xE3, 0x82, 0x9A, 0x0D, 0x4C, 0xE3, 0x83, + 0xA4, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x88, 0xE3, + 0x82, 0x99, 0x0D, 0x4F, 0xE1, 0x84, 0x8E, 0xE1, + 0x85, 0xA1, 0xE1, 0x86, 0xB7, 0xE1, 0x84, 0x80, + 0xE1, 0x85, 0xA9, 0x01, 0x4F, 0xE3, 0x82, 0xA4, + 0xE3, 0x83, 0x8B, 0xE3, 0x83, 0xB3, 0xE3, 0x82, + 0xAF, 0xE3, 0x82, 0x99, 0x0D, 0x4F, 0xE3, 0x82, + 0xB7, 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0xB3, 0xE3, + // Bytes 2f00 - 2f3f + 0x82, 0xAF, 0xE3, 0x82, 0x99, 0x0D, 0x4F, 0xE3, + 0x83, 0x98, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC, + 0xE3, 0x82, 0xB7, 0xE3, 0x82, 0x99, 0x0D, 0x4F, + 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x9A, 0xE3, 0x83, + 0xB3, 0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99, 0x0D, + 0x52, 0xE3, 0x82, 0xA8, 0xE3, 0x82, 0xB9, 0xE3, + 0x82, 0xAF, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x88, + 0xE3, 0x82, 0x99, 0x0D, 0x52, 0xE3, 0x83, 0x95, + // Bytes 2f40 - 2f7f + 0xE3, 0x82, 0xA1, 0xE3, 0x83, 0xA9, 0xE3, 0x83, + 0x83, 0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99, 0x0D, + 0x86, 0xE0, 0xB3, 0x86, 0xE0, 0xB3, 0x82, 0x01, + 0x86, 0xE0, 0xB7, 0x99, 0xE0, 0xB7, 0x8F, 0x01, + 0x03, 0x3C, 0xCC, 0xB8, 0x05, 0x03, 0x3D, 0xCC, + 0xB8, 0x05, 0x03, 0x3E, 0xCC, 0xB8, 0x05, 0x03, + 0x41, 0xCC, 0x80, 0xC9, 0x03, 0x41, 0xCC, 0x81, + 0xC9, 0x03, 0x41, 0xCC, 0x83, 0xC9, 0x03, 0x41, + // Bytes 2f80 - 2fbf + 0xCC, 0x84, 0xC9, 0x03, 0x41, 0xCC, 0x89, 0xC9, + 0x03, 0x41, 0xCC, 0x8C, 0xC9, 0x03, 0x41, 0xCC, + 0x8F, 0xC9, 0x03, 0x41, 0xCC, 0x91, 0xC9, 0x03, + 0x41, 0xCC, 0xA5, 0xB5, 0x03, 0x41, 0xCC, 0xA8, + 0xA5, 0x03, 0x42, 0xCC, 0x87, 0xC9, 0x03, 0x42, + 0xCC, 0xA3, 0xB5, 0x03, 0x42, 0xCC, 0xB1, 0xB5, + 0x03, 0x43, 0xCC, 0x81, 0xC9, 0x03, 0x43, 0xCC, + 0x82, 0xC9, 0x03, 0x43, 0xCC, 0x87, 0xC9, 0x03, + // Bytes 2fc0 - 2fff + 0x43, 0xCC, 0x8C, 0xC9, 0x03, 0x44, 0xCC, 0x87, + 0xC9, 0x03, 0x44, 0xCC, 0x8C, 0xC9, 0x03, 0x44, + 0xCC, 0xA3, 0xB5, 0x03, 0x44, 0xCC, 0xA7, 0xA5, + 0x03, 0x44, 0xCC, 0xAD, 0xB5, 0x03, 0x44, 0xCC, + 0xB1, 0xB5, 0x03, 0x45, 0xCC, 0x80, 0xC9, 0x03, + 0x45, 0xCC, 0x81, 0xC9, 0x03, 0x45, 0xCC, 0x83, + 0xC9, 0x03, 0x45, 0xCC, 0x86, 0xC9, 0x03, 0x45, + 0xCC, 0x87, 0xC9, 0x03, 0x45, 0xCC, 0x88, 0xC9, + // Bytes 3000 - 303f + 0x03, 0x45, 0xCC, 0x89, 0xC9, 0x03, 0x45, 0xCC, + 0x8C, 0xC9, 0x03, 0x45, 0xCC, 0x8F, 0xC9, 0x03, + 0x45, 0xCC, 0x91, 0xC9, 0x03, 0x45, 0xCC, 0xA8, + 0xA5, 0x03, 0x45, 0xCC, 0xAD, 0xB5, 0x03, 0x45, + 0xCC, 0xB0, 0xB5, 0x03, 0x46, 0xCC, 0x87, 0xC9, + 0x03, 0x47, 0xCC, 0x81, 0xC9, 0x03, 0x47, 0xCC, + 0x82, 0xC9, 0x03, 0x47, 0xCC, 0x84, 0xC9, 0x03, + 0x47, 0xCC, 0x86, 0xC9, 0x03, 0x47, 0xCC, 0x87, + // Bytes 3040 - 307f + 0xC9, 0x03, 0x47, 0xCC, 0x8C, 0xC9, 0x03, 0x47, + 0xCC, 0xA7, 0xA5, 0x03, 0x48, 0xCC, 0x82, 0xC9, + 0x03, 0x48, 0xCC, 0x87, 0xC9, 0x03, 0x48, 0xCC, + 0x88, 0xC9, 0x03, 0x48, 0xCC, 0x8C, 0xC9, 0x03, + 0x48, 0xCC, 0xA3, 0xB5, 0x03, 0x48, 0xCC, 0xA7, + 0xA5, 0x03, 0x48, 0xCC, 0xAE, 0xB5, 0x03, 0x49, + 0xCC, 0x80, 0xC9, 0x03, 0x49, 0xCC, 0x81, 0xC9, + 0x03, 0x49, 0xCC, 0x82, 0xC9, 0x03, 0x49, 0xCC, + // Bytes 3080 - 30bf + 0x83, 0xC9, 0x03, 0x49, 0xCC, 0x84, 0xC9, 0x03, + 0x49, 0xCC, 0x86, 0xC9, 0x03, 0x49, 0xCC, 0x87, + 0xC9, 0x03, 0x49, 0xCC, 0x89, 0xC9, 0x03, 0x49, + 0xCC, 0x8C, 0xC9, 0x03, 0x49, 0xCC, 0x8F, 0xC9, + 0x03, 0x49, 0xCC, 0x91, 0xC9, 0x03, 0x49, 0xCC, + 0xA3, 0xB5, 0x03, 0x49, 0xCC, 0xA8, 0xA5, 0x03, + 0x49, 0xCC, 0xB0, 0xB5, 0x03, 0x4A, 0xCC, 0x82, + 0xC9, 0x03, 0x4B, 0xCC, 0x81, 0xC9, 0x03, 0x4B, + // Bytes 30c0 - 30ff + 0xCC, 0x8C, 0xC9, 0x03, 0x4B, 0xCC, 0xA3, 0xB5, + 0x03, 0x4B, 0xCC, 0xA7, 0xA5, 0x03, 0x4B, 0xCC, + 0xB1, 0xB5, 0x03, 0x4C, 0xCC, 0x81, 0xC9, 0x03, + 0x4C, 0xCC, 0x8C, 0xC9, 0x03, 0x4C, 0xCC, 0xA7, + 0xA5, 0x03, 0x4C, 0xCC, 0xAD, 0xB5, 0x03, 0x4C, + 0xCC, 0xB1, 0xB5, 0x03, 0x4D, 0xCC, 0x81, 0xC9, + 0x03, 0x4D, 0xCC, 0x87, 0xC9, 0x03, 0x4D, 0xCC, + 0xA3, 0xB5, 0x03, 0x4E, 0xCC, 0x80, 0xC9, 0x03, + // Bytes 3100 - 313f + 0x4E, 0xCC, 0x81, 0xC9, 0x03, 0x4E, 0xCC, 0x83, + 0xC9, 0x03, 0x4E, 0xCC, 0x87, 0xC9, 0x03, 0x4E, + 0xCC, 0x8C, 0xC9, 0x03, 0x4E, 0xCC, 0xA3, 0xB5, + 0x03, 0x4E, 0xCC, 0xA7, 0xA5, 0x03, 0x4E, 0xCC, + 0xAD, 0xB5, 0x03, 0x4E, 0xCC, 0xB1, 0xB5, 0x03, + 0x4F, 0xCC, 0x80, 0xC9, 0x03, 0x4F, 0xCC, 0x81, + 0xC9, 0x03, 0x4F, 0xCC, 0x86, 0xC9, 0x03, 0x4F, + 0xCC, 0x89, 0xC9, 0x03, 0x4F, 0xCC, 0x8B, 0xC9, + // Bytes 3140 - 317f + 0x03, 0x4F, 0xCC, 0x8C, 0xC9, 0x03, 0x4F, 0xCC, + 0x8F, 0xC9, 0x03, 0x4F, 0xCC, 0x91, 0xC9, 0x03, + 0x50, 0xCC, 0x81, 0xC9, 0x03, 0x50, 0xCC, 0x87, + 0xC9, 0x03, 0x52, 0xCC, 0x81, 0xC9, 0x03, 0x52, + 0xCC, 0x87, 0xC9, 0x03, 0x52, 0xCC, 0x8C, 0xC9, + 0x03, 0x52, 0xCC, 0x8F, 0xC9, 0x03, 0x52, 0xCC, + 0x91, 0xC9, 0x03, 0x52, 0xCC, 0xA7, 0xA5, 0x03, + 0x52, 0xCC, 0xB1, 0xB5, 0x03, 0x53, 0xCC, 0x82, + // Bytes 3180 - 31bf + 0xC9, 0x03, 0x53, 0xCC, 0x87, 0xC9, 0x03, 0x53, + 0xCC, 0xA6, 0xB5, 0x03, 0x53, 0xCC, 0xA7, 0xA5, + 0x03, 0x54, 0xCC, 0x87, 0xC9, 0x03, 0x54, 0xCC, + 0x8C, 0xC9, 0x03, 0x54, 0xCC, 0xA3, 0xB5, 0x03, + 0x54, 0xCC, 0xA6, 0xB5, 0x03, 0x54, 0xCC, 0xA7, + 0xA5, 0x03, 0x54, 0xCC, 0xAD, 0xB5, 0x03, 0x54, + 0xCC, 0xB1, 0xB5, 0x03, 0x55, 0xCC, 0x80, 0xC9, + 0x03, 0x55, 0xCC, 0x81, 0xC9, 0x03, 0x55, 0xCC, + // Bytes 31c0 - 31ff + 0x82, 0xC9, 0x03, 0x55, 0xCC, 0x86, 0xC9, 0x03, + 0x55, 0xCC, 0x89, 0xC9, 0x03, 0x55, 0xCC, 0x8A, + 0xC9, 0x03, 0x55, 0xCC, 0x8B, 0xC9, 0x03, 0x55, + 0xCC, 0x8C, 0xC9, 0x03, 0x55, 0xCC, 0x8F, 0xC9, + 0x03, 0x55, 0xCC, 0x91, 0xC9, 0x03, 0x55, 0xCC, + 0xA3, 0xB5, 0x03, 0x55, 0xCC, 0xA4, 0xB5, 0x03, + 0x55, 0xCC, 0xA8, 0xA5, 0x03, 0x55, 0xCC, 0xAD, + 0xB5, 0x03, 0x55, 0xCC, 0xB0, 0xB5, 0x03, 0x56, + // Bytes 3200 - 323f + 0xCC, 0x83, 0xC9, 0x03, 0x56, 0xCC, 0xA3, 0xB5, + 0x03, 0x57, 0xCC, 0x80, 0xC9, 0x03, 0x57, 0xCC, + 0x81, 0xC9, 0x03, 0x57, 0xCC, 0x82, 0xC9, 0x03, + 0x57, 0xCC, 0x87, 0xC9, 0x03, 0x57, 0xCC, 0x88, + 0xC9, 0x03, 0x57, 0xCC, 0xA3, 0xB5, 0x03, 0x58, + 0xCC, 0x87, 0xC9, 0x03, 0x58, 0xCC, 0x88, 0xC9, + 0x03, 0x59, 0xCC, 0x80, 0xC9, 0x03, 0x59, 0xCC, + 0x81, 0xC9, 0x03, 0x59, 0xCC, 0x82, 0xC9, 0x03, + // Bytes 3240 - 327f + 0x59, 0xCC, 0x83, 0xC9, 0x03, 0x59, 0xCC, 0x84, + 0xC9, 0x03, 0x59, 0xCC, 0x87, 0xC9, 0x03, 0x59, + 0xCC, 0x88, 0xC9, 0x03, 0x59, 0xCC, 0x89, 0xC9, + 0x03, 0x59, 0xCC, 0xA3, 0xB5, 0x03, 0x5A, 0xCC, + 0x81, 0xC9, 0x03, 0x5A, 0xCC, 0x82, 0xC9, 0x03, + 0x5A, 0xCC, 0x87, 0xC9, 0x03, 0x5A, 0xCC, 0x8C, + 0xC9, 0x03, 0x5A, 0xCC, 0xA3, 0xB5, 0x03, 0x5A, + 0xCC, 0xB1, 0xB5, 0x03, 0x61, 0xCC, 0x80, 0xC9, + // Bytes 3280 - 32bf + 0x03, 0x61, 0xCC, 0x81, 0xC9, 0x03, 0x61, 0xCC, + 0x83, 0xC9, 0x03, 0x61, 0xCC, 0x84, 0xC9, 0x03, + 0x61, 0xCC, 0x89, 0xC9, 0x03, 0x61, 0xCC, 0x8C, + 0xC9, 0x03, 0x61, 0xCC, 0x8F, 0xC9, 0x03, 0x61, + 0xCC, 0x91, 0xC9, 0x03, 0x61, 0xCC, 0xA5, 0xB5, + 0x03, 0x61, 0xCC, 0xA8, 0xA5, 0x03, 0x62, 0xCC, + 0x87, 0xC9, 0x03, 0x62, 0xCC, 0xA3, 0xB5, 0x03, + 0x62, 0xCC, 0xB1, 0xB5, 0x03, 0x63, 0xCC, 0x81, + // Bytes 32c0 - 32ff + 0xC9, 0x03, 0x63, 0xCC, 0x82, 0xC9, 0x03, 0x63, + 0xCC, 0x87, 0xC9, 0x03, 0x63, 0xCC, 0x8C, 0xC9, + 0x03, 0x64, 0xCC, 0x87, 0xC9, 0x03, 0x64, 0xCC, + 0x8C, 0xC9, 0x03, 0x64, 0xCC, 0xA3, 0xB5, 0x03, + 0x64, 0xCC, 0xA7, 0xA5, 0x03, 0x64, 0xCC, 0xAD, + 0xB5, 0x03, 0x64, 0xCC, 0xB1, 0xB5, 0x03, 0x65, + 0xCC, 0x80, 0xC9, 0x03, 0x65, 0xCC, 0x81, 0xC9, + 0x03, 0x65, 0xCC, 0x83, 0xC9, 0x03, 0x65, 0xCC, + // Bytes 3300 - 333f + 0x86, 0xC9, 0x03, 0x65, 0xCC, 0x87, 0xC9, 0x03, + 0x65, 0xCC, 0x88, 0xC9, 0x03, 0x65, 0xCC, 0x89, + 0xC9, 0x03, 0x65, 0xCC, 0x8C, 0xC9, 0x03, 0x65, + 0xCC, 0x8F, 0xC9, 0x03, 0x65, 0xCC, 0x91, 0xC9, + 0x03, 0x65, 0xCC, 0xA8, 0xA5, 0x03, 0x65, 0xCC, + 0xAD, 0xB5, 0x03, 0x65, 0xCC, 0xB0, 0xB5, 0x03, + 0x66, 0xCC, 0x87, 0xC9, 0x03, 0x67, 0xCC, 0x81, + 0xC9, 0x03, 0x67, 0xCC, 0x82, 0xC9, 0x03, 0x67, + // Bytes 3340 - 337f + 0xCC, 0x84, 0xC9, 0x03, 0x67, 0xCC, 0x86, 0xC9, + 0x03, 0x67, 0xCC, 0x87, 0xC9, 0x03, 0x67, 0xCC, + 0x8C, 0xC9, 0x03, 0x67, 0xCC, 0xA7, 0xA5, 0x03, + 0x68, 0xCC, 0x82, 0xC9, 0x03, 0x68, 0xCC, 0x87, + 0xC9, 0x03, 0x68, 0xCC, 0x88, 0xC9, 0x03, 0x68, + 0xCC, 0x8C, 0xC9, 0x03, 0x68, 0xCC, 0xA3, 0xB5, + 0x03, 0x68, 0xCC, 0xA7, 0xA5, 0x03, 0x68, 0xCC, + 0xAE, 0xB5, 0x03, 0x68, 0xCC, 0xB1, 0xB5, 0x03, + // Bytes 3380 - 33bf + 0x69, 0xCC, 0x80, 0xC9, 0x03, 0x69, 0xCC, 0x81, + 0xC9, 0x03, 0x69, 0xCC, 0x82, 0xC9, 0x03, 0x69, + 0xCC, 0x83, 0xC9, 0x03, 0x69, 0xCC, 0x84, 0xC9, + 0x03, 0x69, 0xCC, 0x86, 0xC9, 0x03, 0x69, 0xCC, + 0x89, 0xC9, 0x03, 0x69, 0xCC, 0x8C, 0xC9, 0x03, + 0x69, 0xCC, 0x8F, 0xC9, 0x03, 0x69, 0xCC, 0x91, + 0xC9, 0x03, 0x69, 0xCC, 0xA3, 0xB5, 0x03, 0x69, + 0xCC, 0xA8, 0xA5, 0x03, 0x69, 0xCC, 0xB0, 0xB5, + // Bytes 33c0 - 33ff + 0x03, 0x6A, 0xCC, 0x82, 0xC9, 0x03, 0x6A, 0xCC, + 0x8C, 0xC9, 0x03, 0x6B, 0xCC, 0x81, 0xC9, 0x03, + 0x6B, 0xCC, 0x8C, 0xC9, 0x03, 0x6B, 0xCC, 0xA3, + 0xB5, 0x03, 0x6B, 0xCC, 0xA7, 0xA5, 0x03, 0x6B, + 0xCC, 0xB1, 0xB5, 0x03, 0x6C, 0xCC, 0x81, 0xC9, + 0x03, 0x6C, 0xCC, 0x8C, 0xC9, 0x03, 0x6C, 0xCC, + 0xA7, 0xA5, 0x03, 0x6C, 0xCC, 0xAD, 0xB5, 0x03, + 0x6C, 0xCC, 0xB1, 0xB5, 0x03, 0x6D, 0xCC, 0x81, + // Bytes 3400 - 343f + 0xC9, 0x03, 0x6D, 0xCC, 0x87, 0xC9, 0x03, 0x6D, + 0xCC, 0xA3, 0xB5, 0x03, 0x6E, 0xCC, 0x80, 0xC9, + 0x03, 0x6E, 0xCC, 0x81, 0xC9, 0x03, 0x6E, 0xCC, + 0x83, 0xC9, 0x03, 0x6E, 0xCC, 0x87, 0xC9, 0x03, + 0x6E, 0xCC, 0x8C, 0xC9, 0x03, 0x6E, 0xCC, 0xA3, + 0xB5, 0x03, 0x6E, 0xCC, 0xA7, 0xA5, 0x03, 0x6E, + 0xCC, 0xAD, 0xB5, 0x03, 0x6E, 0xCC, 0xB1, 0xB5, + 0x03, 0x6F, 0xCC, 0x80, 0xC9, 0x03, 0x6F, 0xCC, + // Bytes 3440 - 347f + 0x81, 0xC9, 0x03, 0x6F, 0xCC, 0x86, 0xC9, 0x03, + 0x6F, 0xCC, 0x89, 0xC9, 0x03, 0x6F, 0xCC, 0x8B, + 0xC9, 0x03, 0x6F, 0xCC, 0x8C, 0xC9, 0x03, 0x6F, + 0xCC, 0x8F, 0xC9, 0x03, 0x6F, 0xCC, 0x91, 0xC9, + 0x03, 0x70, 0xCC, 0x81, 0xC9, 0x03, 0x70, 0xCC, + 0x87, 0xC9, 0x03, 0x72, 0xCC, 0x81, 0xC9, 0x03, + 0x72, 0xCC, 0x87, 0xC9, 0x03, 0x72, 0xCC, 0x8C, + 0xC9, 0x03, 0x72, 0xCC, 0x8F, 0xC9, 0x03, 0x72, + // Bytes 3480 - 34bf + 0xCC, 0x91, 0xC9, 0x03, 0x72, 0xCC, 0xA7, 0xA5, + 0x03, 0x72, 0xCC, 0xB1, 0xB5, 0x03, 0x73, 0xCC, + 0x82, 0xC9, 0x03, 0x73, 0xCC, 0x87, 0xC9, 0x03, + 0x73, 0xCC, 0xA6, 0xB5, 0x03, 0x73, 0xCC, 0xA7, + 0xA5, 0x03, 0x74, 0xCC, 0x87, 0xC9, 0x03, 0x74, + 0xCC, 0x88, 0xC9, 0x03, 0x74, 0xCC, 0x8C, 0xC9, + 0x03, 0x74, 0xCC, 0xA3, 0xB5, 0x03, 0x74, 0xCC, + 0xA6, 0xB5, 0x03, 0x74, 0xCC, 0xA7, 0xA5, 0x03, + // Bytes 34c0 - 34ff + 0x74, 0xCC, 0xAD, 0xB5, 0x03, 0x74, 0xCC, 0xB1, + 0xB5, 0x03, 0x75, 0xCC, 0x80, 0xC9, 0x03, 0x75, + 0xCC, 0x81, 0xC9, 0x03, 0x75, 0xCC, 0x82, 0xC9, + 0x03, 0x75, 0xCC, 0x86, 0xC9, 0x03, 0x75, 0xCC, + 0x89, 0xC9, 0x03, 0x75, 0xCC, 0x8A, 0xC9, 0x03, + 0x75, 0xCC, 0x8B, 0xC9, 0x03, 0x75, 0xCC, 0x8C, + 0xC9, 0x03, 0x75, 0xCC, 0x8F, 0xC9, 0x03, 0x75, + 0xCC, 0x91, 0xC9, 0x03, 0x75, 0xCC, 0xA3, 0xB5, + // Bytes 3500 - 353f + 0x03, 0x75, 0xCC, 0xA4, 0xB5, 0x03, 0x75, 0xCC, + 0xA8, 0xA5, 0x03, 0x75, 0xCC, 0xAD, 0xB5, 0x03, + 0x75, 0xCC, 0xB0, 0xB5, 0x03, 0x76, 0xCC, 0x83, + 0xC9, 0x03, 0x76, 0xCC, 0xA3, 0xB5, 0x03, 0x77, + 0xCC, 0x80, 0xC9, 0x03, 0x77, 0xCC, 0x81, 0xC9, + 0x03, 0x77, 0xCC, 0x82, 0xC9, 0x03, 0x77, 0xCC, + 0x87, 0xC9, 0x03, 0x77, 0xCC, 0x88, 0xC9, 0x03, + 0x77, 0xCC, 0x8A, 0xC9, 0x03, 0x77, 0xCC, 0xA3, + // Bytes 3540 - 357f + 0xB5, 0x03, 0x78, 0xCC, 0x87, 0xC9, 0x03, 0x78, + 0xCC, 0x88, 0xC9, 0x03, 0x79, 0xCC, 0x80, 0xC9, + 0x03, 0x79, 0xCC, 0x81, 0xC9, 0x03, 0x79, 0xCC, + 0x82, 0xC9, 0x03, 0x79, 0xCC, 0x83, 0xC9, 0x03, + 0x79, 0xCC, 0x84, 0xC9, 0x03, 0x79, 0xCC, 0x87, + 0xC9, 0x03, 0x79, 0xCC, 0x88, 0xC9, 0x03, 0x79, + 0xCC, 0x89, 0xC9, 0x03, 0x79, 0xCC, 0x8A, 0xC9, + 0x03, 0x79, 0xCC, 0xA3, 0xB5, 0x03, 0x7A, 0xCC, + // Bytes 3580 - 35bf + 0x81, 0xC9, 0x03, 0x7A, 0xCC, 0x82, 0xC9, 0x03, + 0x7A, 0xCC, 0x87, 0xC9, 0x03, 0x7A, 0xCC, 0x8C, + 0xC9, 0x03, 0x7A, 0xCC, 0xA3, 0xB5, 0x03, 0x7A, + 0xCC, 0xB1, 0xB5, 0x04, 0xC2, 0xA8, 0xCC, 0x80, + 0xCA, 0x04, 0xC2, 0xA8, 0xCC, 0x81, 0xCA, 0x04, + 0xC2, 0xA8, 0xCD, 0x82, 0xCA, 0x04, 0xC3, 0x86, + 0xCC, 0x81, 0xC9, 0x04, 0xC3, 0x86, 0xCC, 0x84, + 0xC9, 0x04, 0xC3, 0x98, 0xCC, 0x81, 0xC9, 0x04, + // Bytes 35c0 - 35ff + 0xC3, 0xA6, 0xCC, 0x81, 0xC9, 0x04, 0xC3, 0xA6, + 0xCC, 0x84, 0xC9, 0x04, 0xC3, 0xB8, 0xCC, 0x81, + 0xC9, 0x04, 0xC5, 0xBF, 0xCC, 0x87, 0xC9, 0x04, + 0xC6, 0xB7, 0xCC, 0x8C, 0xC9, 0x04, 0xCA, 0x92, + 0xCC, 0x8C, 0xC9, 0x04, 0xCE, 0x91, 0xCC, 0x80, + 0xC9, 0x04, 0xCE, 0x91, 0xCC, 0x81, 0xC9, 0x04, + 0xCE, 0x91, 0xCC, 0x84, 0xC9, 0x04, 0xCE, 0x91, + 0xCC, 0x86, 0xC9, 0x04, 0xCE, 0x91, 0xCD, 0x85, + // Bytes 3600 - 363f + 0xD9, 0x04, 0xCE, 0x95, 0xCC, 0x80, 0xC9, 0x04, + 0xCE, 0x95, 0xCC, 0x81, 0xC9, 0x04, 0xCE, 0x97, + 0xCC, 0x80, 0xC9, 0x04, 0xCE, 0x97, 0xCC, 0x81, + 0xC9, 0x04, 0xCE, 0x97, 0xCD, 0x85, 0xD9, 0x04, + 0xCE, 0x99, 0xCC, 0x80, 0xC9, 0x04, 0xCE, 0x99, + 0xCC, 0x81, 0xC9, 0x04, 0xCE, 0x99, 0xCC, 0x84, + 0xC9, 0x04, 0xCE, 0x99, 0xCC, 0x86, 0xC9, 0x04, + 0xCE, 0x99, 0xCC, 0x88, 0xC9, 0x04, 0xCE, 0x9F, + // Bytes 3640 - 367f + 0xCC, 0x80, 0xC9, 0x04, 0xCE, 0x9F, 0xCC, 0x81, + 0xC9, 0x04, 0xCE, 0xA1, 0xCC, 0x94, 0xC9, 0x04, + 0xCE, 0xA5, 0xCC, 0x80, 0xC9, 0x04, 0xCE, 0xA5, + 0xCC, 0x81, 0xC9, 0x04, 0xCE, 0xA5, 0xCC, 0x84, + 0xC9, 0x04, 0xCE, 0xA5, 0xCC, 0x86, 0xC9, 0x04, + 0xCE, 0xA5, 0xCC, 0x88, 0xC9, 0x04, 0xCE, 0xA9, + 0xCC, 0x80, 0xC9, 0x04, 0xCE, 0xA9, 0xCC, 0x81, + 0xC9, 0x04, 0xCE, 0xA9, 0xCD, 0x85, 0xD9, 0x04, + // Bytes 3680 - 36bf + 0xCE, 0xB1, 0xCC, 0x84, 0xC9, 0x04, 0xCE, 0xB1, + 0xCC, 0x86, 0xC9, 0x04, 0xCE, 0xB1, 0xCD, 0x85, + 0xD9, 0x04, 0xCE, 0xB5, 0xCC, 0x80, 0xC9, 0x04, + 0xCE, 0xB5, 0xCC, 0x81, 0xC9, 0x04, 0xCE, 0xB7, + 0xCD, 0x85, 0xD9, 0x04, 0xCE, 0xB9, 0xCC, 0x80, + 0xC9, 0x04, 0xCE, 0xB9, 0xCC, 0x81, 0xC9, 0x04, + 0xCE, 0xB9, 0xCC, 0x84, 0xC9, 0x04, 0xCE, 0xB9, + 0xCC, 0x86, 0xC9, 0x04, 0xCE, 0xB9, 0xCD, 0x82, + // Bytes 36c0 - 36ff + 0xC9, 0x04, 0xCE, 0xBF, 0xCC, 0x80, 0xC9, 0x04, + 0xCE, 0xBF, 0xCC, 0x81, 0xC9, 0x04, 0xCF, 0x81, + 0xCC, 0x93, 0xC9, 0x04, 0xCF, 0x81, 0xCC, 0x94, + 0xC9, 0x04, 0xCF, 0x85, 0xCC, 0x80, 0xC9, 0x04, + 0xCF, 0x85, 0xCC, 0x81, 0xC9, 0x04, 0xCF, 0x85, + 0xCC, 0x84, 0xC9, 0x04, 0xCF, 0x85, 0xCC, 0x86, + 0xC9, 0x04, 0xCF, 0x85, 0xCD, 0x82, 0xC9, 0x04, + 0xCF, 0x89, 0xCD, 0x85, 0xD9, 0x04, 0xCF, 0x92, + // Bytes 3700 - 373f + 0xCC, 0x81, 0xC9, 0x04, 0xCF, 0x92, 0xCC, 0x88, + 0xC9, 0x04, 0xD0, 0x86, 0xCC, 0x88, 0xC9, 0x04, + 0xD0, 0x90, 0xCC, 0x86, 0xC9, 0x04, 0xD0, 0x90, + 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0x93, 0xCC, 0x81, + 0xC9, 0x04, 0xD0, 0x95, 0xCC, 0x80, 0xC9, 0x04, + 0xD0, 0x95, 0xCC, 0x86, 0xC9, 0x04, 0xD0, 0x95, + 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0x96, 0xCC, 0x86, + 0xC9, 0x04, 0xD0, 0x96, 0xCC, 0x88, 0xC9, 0x04, + // Bytes 3740 - 377f + 0xD0, 0x97, 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0x98, + 0xCC, 0x80, 0xC9, 0x04, 0xD0, 0x98, 0xCC, 0x84, + 0xC9, 0x04, 0xD0, 0x98, 0xCC, 0x86, 0xC9, 0x04, + 0xD0, 0x98, 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0x9A, + 0xCC, 0x81, 0xC9, 0x04, 0xD0, 0x9E, 0xCC, 0x88, + 0xC9, 0x04, 0xD0, 0xA3, 0xCC, 0x84, 0xC9, 0x04, + 0xD0, 0xA3, 0xCC, 0x86, 0xC9, 0x04, 0xD0, 0xA3, + 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0xA3, 0xCC, 0x8B, + // Bytes 3780 - 37bf + 0xC9, 0x04, 0xD0, 0xA7, 0xCC, 0x88, 0xC9, 0x04, + 0xD0, 0xAB, 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0xAD, + 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0xB0, 0xCC, 0x86, + 0xC9, 0x04, 0xD0, 0xB0, 0xCC, 0x88, 0xC9, 0x04, + 0xD0, 0xB3, 0xCC, 0x81, 0xC9, 0x04, 0xD0, 0xB5, + 0xCC, 0x80, 0xC9, 0x04, 0xD0, 0xB5, 0xCC, 0x86, + 0xC9, 0x04, 0xD0, 0xB5, 0xCC, 0x88, 0xC9, 0x04, + 0xD0, 0xB6, 0xCC, 0x86, 0xC9, 0x04, 0xD0, 0xB6, + // Bytes 37c0 - 37ff + 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0xB7, 0xCC, 0x88, + 0xC9, 0x04, 0xD0, 0xB8, 0xCC, 0x80, 0xC9, 0x04, + 0xD0, 0xB8, 0xCC, 0x84, 0xC9, 0x04, 0xD0, 0xB8, + 0xCC, 0x86, 0xC9, 0x04, 0xD0, 0xB8, 0xCC, 0x88, + 0xC9, 0x04, 0xD0, 0xBA, 0xCC, 0x81, 0xC9, 0x04, + 0xD0, 0xBE, 0xCC, 0x88, 0xC9, 0x04, 0xD1, 0x83, + 0xCC, 0x84, 0xC9, 0x04, 0xD1, 0x83, 0xCC, 0x86, + 0xC9, 0x04, 0xD1, 0x83, 0xCC, 0x88, 0xC9, 0x04, + // Bytes 3800 - 383f + 0xD1, 0x83, 0xCC, 0x8B, 0xC9, 0x04, 0xD1, 0x87, + 0xCC, 0x88, 0xC9, 0x04, 0xD1, 0x8B, 0xCC, 0x88, + 0xC9, 0x04, 0xD1, 0x8D, 0xCC, 0x88, 0xC9, 0x04, + 0xD1, 0x96, 0xCC, 0x88, 0xC9, 0x04, 0xD1, 0xB4, + 0xCC, 0x8F, 0xC9, 0x04, 0xD1, 0xB5, 0xCC, 0x8F, + 0xC9, 0x04, 0xD3, 0x98, 0xCC, 0x88, 0xC9, 0x04, + 0xD3, 0x99, 0xCC, 0x88, 0xC9, 0x04, 0xD3, 0xA8, + 0xCC, 0x88, 0xC9, 0x04, 0xD3, 0xA9, 0xCC, 0x88, + // Bytes 3840 - 387f + 0xC9, 0x04, 0xD8, 0xA7, 0xD9, 0x93, 0xC9, 0x04, + 0xD8, 0xA7, 0xD9, 0x94, 0xC9, 0x04, 0xD8, 0xA7, + 0xD9, 0x95, 0xB5, 0x04, 0xD9, 0x88, 0xD9, 0x94, + 0xC9, 0x04, 0xD9, 0x8A, 0xD9, 0x94, 0xC9, 0x04, + 0xDB, 0x81, 0xD9, 0x94, 0xC9, 0x04, 0xDB, 0x92, + 0xD9, 0x94, 0xC9, 0x04, 0xDB, 0x95, 0xD9, 0x94, + 0xC9, 0x05, 0x41, 0xCC, 0x82, 0xCC, 0x80, 0xCA, + 0x05, 0x41, 0xCC, 0x82, 0xCC, 0x81, 0xCA, 0x05, + // Bytes 3880 - 38bf + 0x41, 0xCC, 0x82, 0xCC, 0x83, 0xCA, 0x05, 0x41, + 0xCC, 0x82, 0xCC, 0x89, 0xCA, 0x05, 0x41, 0xCC, + 0x86, 0xCC, 0x80, 0xCA, 0x05, 0x41, 0xCC, 0x86, + 0xCC, 0x81, 0xCA, 0x05, 0x41, 0xCC, 0x86, 0xCC, + 0x83, 0xCA, 0x05, 0x41, 0xCC, 0x86, 0xCC, 0x89, + 0xCA, 0x05, 0x41, 0xCC, 0x87, 0xCC, 0x84, 0xCA, + 0x05, 0x41, 0xCC, 0x88, 0xCC, 0x84, 0xCA, 0x05, + 0x41, 0xCC, 0x8A, 0xCC, 0x81, 0xCA, 0x05, 0x41, + // Bytes 38c0 - 38ff + 0xCC, 0xA3, 0xCC, 0x82, 0xCA, 0x05, 0x41, 0xCC, + 0xA3, 0xCC, 0x86, 0xCA, 0x05, 0x43, 0xCC, 0xA7, + 0xCC, 0x81, 0xCA, 0x05, 0x45, 0xCC, 0x82, 0xCC, + 0x80, 0xCA, 0x05, 0x45, 0xCC, 0x82, 0xCC, 0x81, + 0xCA, 0x05, 0x45, 0xCC, 0x82, 0xCC, 0x83, 0xCA, + 0x05, 0x45, 0xCC, 0x82, 0xCC, 0x89, 0xCA, 0x05, + 0x45, 0xCC, 0x84, 0xCC, 0x80, 0xCA, 0x05, 0x45, + 0xCC, 0x84, 0xCC, 0x81, 0xCA, 0x05, 0x45, 0xCC, + // Bytes 3900 - 393f + 0xA3, 0xCC, 0x82, 0xCA, 0x05, 0x45, 0xCC, 0xA7, + 0xCC, 0x86, 0xCA, 0x05, 0x49, 0xCC, 0x88, 0xCC, + 0x81, 0xCA, 0x05, 0x4C, 0xCC, 0xA3, 0xCC, 0x84, + 0xCA, 0x05, 0x4F, 0xCC, 0x82, 0xCC, 0x80, 0xCA, + 0x05, 0x4F, 0xCC, 0x82, 0xCC, 0x81, 0xCA, 0x05, + 0x4F, 0xCC, 0x82, 0xCC, 0x83, 0xCA, 0x05, 0x4F, + 0xCC, 0x82, 0xCC, 0x89, 0xCA, 0x05, 0x4F, 0xCC, + 0x83, 0xCC, 0x81, 0xCA, 0x05, 0x4F, 0xCC, 0x83, + // Bytes 3940 - 397f + 0xCC, 0x84, 0xCA, 0x05, 0x4F, 0xCC, 0x83, 0xCC, + 0x88, 0xCA, 0x05, 0x4F, 0xCC, 0x84, 0xCC, 0x80, + 0xCA, 0x05, 0x4F, 0xCC, 0x84, 0xCC, 0x81, 0xCA, + 0x05, 0x4F, 0xCC, 0x87, 0xCC, 0x84, 0xCA, 0x05, + 0x4F, 0xCC, 0x88, 0xCC, 0x84, 0xCA, 0x05, 0x4F, + 0xCC, 0x9B, 0xCC, 0x80, 0xCA, 0x05, 0x4F, 0xCC, + 0x9B, 0xCC, 0x81, 0xCA, 0x05, 0x4F, 0xCC, 0x9B, + 0xCC, 0x83, 0xCA, 0x05, 0x4F, 0xCC, 0x9B, 0xCC, + // Bytes 3980 - 39bf + 0x89, 0xCA, 0x05, 0x4F, 0xCC, 0x9B, 0xCC, 0xA3, + 0xB6, 0x05, 0x4F, 0xCC, 0xA3, 0xCC, 0x82, 0xCA, + 0x05, 0x4F, 0xCC, 0xA8, 0xCC, 0x84, 0xCA, 0x05, + 0x52, 0xCC, 0xA3, 0xCC, 0x84, 0xCA, 0x05, 0x53, + 0xCC, 0x81, 0xCC, 0x87, 0xCA, 0x05, 0x53, 0xCC, + 0x8C, 0xCC, 0x87, 0xCA, 0x05, 0x53, 0xCC, 0xA3, + 0xCC, 0x87, 0xCA, 0x05, 0x55, 0xCC, 0x83, 0xCC, + 0x81, 0xCA, 0x05, 0x55, 0xCC, 0x84, 0xCC, 0x88, + // Bytes 39c0 - 39ff + 0xCA, 0x05, 0x55, 0xCC, 0x88, 0xCC, 0x80, 0xCA, + 0x05, 0x55, 0xCC, 0x88, 0xCC, 0x81, 0xCA, 0x05, + 0x55, 0xCC, 0x88, 0xCC, 0x84, 0xCA, 0x05, 0x55, + 0xCC, 0x88, 0xCC, 0x8C, 0xCA, 0x05, 0x55, 0xCC, + 0x9B, 0xCC, 0x80, 0xCA, 0x05, 0x55, 0xCC, 0x9B, + 0xCC, 0x81, 0xCA, 0x05, 0x55, 0xCC, 0x9B, 0xCC, + 0x83, 0xCA, 0x05, 0x55, 0xCC, 0x9B, 0xCC, 0x89, + 0xCA, 0x05, 0x55, 0xCC, 0x9B, 0xCC, 0xA3, 0xB6, + // Bytes 3a00 - 3a3f + 0x05, 0x61, 0xCC, 0x82, 0xCC, 0x80, 0xCA, 0x05, + 0x61, 0xCC, 0x82, 0xCC, 0x81, 0xCA, 0x05, 0x61, + 0xCC, 0x82, 0xCC, 0x83, 0xCA, 0x05, 0x61, 0xCC, + 0x82, 0xCC, 0x89, 0xCA, 0x05, 0x61, 0xCC, 0x86, + 0xCC, 0x80, 0xCA, 0x05, 0x61, 0xCC, 0x86, 0xCC, + 0x81, 0xCA, 0x05, 0x61, 0xCC, 0x86, 0xCC, 0x83, + 0xCA, 0x05, 0x61, 0xCC, 0x86, 0xCC, 0x89, 0xCA, + 0x05, 0x61, 0xCC, 0x87, 0xCC, 0x84, 0xCA, 0x05, + // Bytes 3a40 - 3a7f + 0x61, 0xCC, 0x88, 0xCC, 0x84, 0xCA, 0x05, 0x61, + 0xCC, 0x8A, 0xCC, 0x81, 0xCA, 0x05, 0x61, 0xCC, + 0xA3, 0xCC, 0x82, 0xCA, 0x05, 0x61, 0xCC, 0xA3, + 0xCC, 0x86, 0xCA, 0x05, 0x63, 0xCC, 0xA7, 0xCC, + 0x81, 0xCA, 0x05, 0x65, 0xCC, 0x82, 0xCC, 0x80, + 0xCA, 0x05, 0x65, 0xCC, 0x82, 0xCC, 0x81, 0xCA, + 0x05, 0x65, 0xCC, 0x82, 0xCC, 0x83, 0xCA, 0x05, + 0x65, 0xCC, 0x82, 0xCC, 0x89, 0xCA, 0x05, 0x65, + // Bytes 3a80 - 3abf + 0xCC, 0x84, 0xCC, 0x80, 0xCA, 0x05, 0x65, 0xCC, + 0x84, 0xCC, 0x81, 0xCA, 0x05, 0x65, 0xCC, 0xA3, + 0xCC, 0x82, 0xCA, 0x05, 0x65, 0xCC, 0xA7, 0xCC, + 0x86, 0xCA, 0x05, 0x69, 0xCC, 0x88, 0xCC, 0x81, + 0xCA, 0x05, 0x6C, 0xCC, 0xA3, 0xCC, 0x84, 0xCA, + 0x05, 0x6F, 0xCC, 0x82, 0xCC, 0x80, 0xCA, 0x05, + 0x6F, 0xCC, 0x82, 0xCC, 0x81, 0xCA, 0x05, 0x6F, + 0xCC, 0x82, 0xCC, 0x83, 0xCA, 0x05, 0x6F, 0xCC, + // Bytes 3ac0 - 3aff + 0x82, 0xCC, 0x89, 0xCA, 0x05, 0x6F, 0xCC, 0x83, + 0xCC, 0x81, 0xCA, 0x05, 0x6F, 0xCC, 0x83, 0xCC, + 0x84, 0xCA, 0x05, 0x6F, 0xCC, 0x83, 0xCC, 0x88, + 0xCA, 0x05, 0x6F, 0xCC, 0x84, 0xCC, 0x80, 0xCA, + 0x05, 0x6F, 0xCC, 0x84, 0xCC, 0x81, 0xCA, 0x05, + 0x6F, 0xCC, 0x87, 0xCC, 0x84, 0xCA, 0x05, 0x6F, + 0xCC, 0x88, 0xCC, 0x84, 0xCA, 0x05, 0x6F, 0xCC, + 0x9B, 0xCC, 0x80, 0xCA, 0x05, 0x6F, 0xCC, 0x9B, + // Bytes 3b00 - 3b3f + 0xCC, 0x81, 0xCA, 0x05, 0x6F, 0xCC, 0x9B, 0xCC, + 0x83, 0xCA, 0x05, 0x6F, 0xCC, 0x9B, 0xCC, 0x89, + 0xCA, 0x05, 0x6F, 0xCC, 0x9B, 0xCC, 0xA3, 0xB6, + 0x05, 0x6F, 0xCC, 0xA3, 0xCC, 0x82, 0xCA, 0x05, + 0x6F, 0xCC, 0xA8, 0xCC, 0x84, 0xCA, 0x05, 0x72, + 0xCC, 0xA3, 0xCC, 0x84, 0xCA, 0x05, 0x73, 0xCC, + 0x81, 0xCC, 0x87, 0xCA, 0x05, 0x73, 0xCC, 0x8C, + 0xCC, 0x87, 0xCA, 0x05, 0x73, 0xCC, 0xA3, 0xCC, + // Bytes 3b40 - 3b7f + 0x87, 0xCA, 0x05, 0x75, 0xCC, 0x83, 0xCC, 0x81, + 0xCA, 0x05, 0x75, 0xCC, 0x84, 0xCC, 0x88, 0xCA, + 0x05, 0x75, 0xCC, 0x88, 0xCC, 0x80, 0xCA, 0x05, + 0x75, 0xCC, 0x88, 0xCC, 0x81, 0xCA, 0x05, 0x75, + 0xCC, 0x88, 0xCC, 0x84, 0xCA, 0x05, 0x75, 0xCC, + 0x88, 0xCC, 0x8C, 0xCA, 0x05, 0x75, 0xCC, 0x9B, + 0xCC, 0x80, 0xCA, 0x05, 0x75, 0xCC, 0x9B, 0xCC, + 0x81, 0xCA, 0x05, 0x75, 0xCC, 0x9B, 0xCC, 0x83, + // Bytes 3b80 - 3bbf + 0xCA, 0x05, 0x75, 0xCC, 0x9B, 0xCC, 0x89, 0xCA, + 0x05, 0x75, 0xCC, 0x9B, 0xCC, 0xA3, 0xB6, 0x05, + 0xE1, 0xBE, 0xBF, 0xCC, 0x80, 0xCA, 0x05, 0xE1, + 0xBE, 0xBF, 0xCC, 0x81, 0xCA, 0x05, 0xE1, 0xBE, + 0xBF, 0xCD, 0x82, 0xCA, 0x05, 0xE1, 0xBF, 0xBE, + 0xCC, 0x80, 0xCA, 0x05, 0xE1, 0xBF, 0xBE, 0xCC, + 0x81, 0xCA, 0x05, 0xE1, 0xBF, 0xBE, 0xCD, 0x82, + 0xCA, 0x05, 0xE2, 0x86, 0x90, 0xCC, 0xB8, 0x05, + // Bytes 3bc0 - 3bff + 0x05, 0xE2, 0x86, 0x92, 0xCC, 0xB8, 0x05, 0x05, + 0xE2, 0x86, 0x94, 0xCC, 0xB8, 0x05, 0x05, 0xE2, + 0x87, 0x90, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x87, + 0x92, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x87, 0x94, + 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x88, 0x83, 0xCC, + 0xB8, 0x05, 0x05, 0xE2, 0x88, 0x88, 0xCC, 0xB8, + 0x05, 0x05, 0xE2, 0x88, 0x8B, 0xCC, 0xB8, 0x05, + 0x05, 0xE2, 0x88, 0xA3, 0xCC, 0xB8, 0x05, 0x05, + // Bytes 3c00 - 3c3f + 0xE2, 0x88, 0xA5, 0xCC, 0xB8, 0x05, 0x05, 0xE2, + 0x88, 0xBC, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, + 0x83, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, 0x85, + 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, 0x88, 0xCC, + 0xB8, 0x05, 0x05, 0xE2, 0x89, 0x8D, 0xCC, 0xB8, + 0x05, 0x05, 0xE2, 0x89, 0xA1, 0xCC, 0xB8, 0x05, + 0x05, 0xE2, 0x89, 0xA4, 0xCC, 0xB8, 0x05, 0x05, + 0xE2, 0x89, 0xA5, 0xCC, 0xB8, 0x05, 0x05, 0xE2, + // Bytes 3c40 - 3c7f + 0x89, 0xB2, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, + 0xB3, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, 0xB6, + 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, 0xB7, 0xCC, + 0xB8, 0x05, 0x05, 0xE2, 0x89, 0xBA, 0xCC, 0xB8, + 0x05, 0x05, 0xE2, 0x89, 0xBB, 0xCC, 0xB8, 0x05, + 0x05, 0xE2, 0x89, 0xBC, 0xCC, 0xB8, 0x05, 0x05, + 0xE2, 0x89, 0xBD, 0xCC, 0xB8, 0x05, 0x05, 0xE2, + 0x8A, 0x82, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, + // Bytes 3c80 - 3cbf + 0x83, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0x86, + 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0x87, 0xCC, + 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0x91, 0xCC, 0xB8, + 0x05, 0x05, 0xE2, 0x8A, 0x92, 0xCC, 0xB8, 0x05, + 0x05, 0xE2, 0x8A, 0xA2, 0xCC, 0xB8, 0x05, 0x05, + 0xE2, 0x8A, 0xA8, 0xCC, 0xB8, 0x05, 0x05, 0xE2, + 0x8A, 0xA9, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, + 0xAB, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0xB2, + // Bytes 3cc0 - 3cff + 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0xB3, 0xCC, + 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0xB4, 0xCC, 0xB8, + 0x05, 0x05, 0xE2, 0x8A, 0xB5, 0xCC, 0xB8, 0x05, + 0x06, 0xCE, 0x91, 0xCC, 0x93, 0xCD, 0x85, 0xDA, + 0x06, 0xCE, 0x91, 0xCC, 0x94, 0xCD, 0x85, 0xDA, + 0x06, 0xCE, 0x95, 0xCC, 0x93, 0xCC, 0x80, 0xCA, + 0x06, 0xCE, 0x95, 0xCC, 0x93, 0xCC, 0x81, 0xCA, + 0x06, 0xCE, 0x95, 0xCC, 0x94, 0xCC, 0x80, 0xCA, + // Bytes 3d00 - 3d3f + 0x06, 0xCE, 0x95, 0xCC, 0x94, 0xCC, 0x81, 0xCA, + 0x06, 0xCE, 0x97, 0xCC, 0x93, 0xCD, 0x85, 0xDA, + 0x06, 0xCE, 0x97, 0xCC, 0x94, 0xCD, 0x85, 0xDA, + 0x06, 0xCE, 0x99, 0xCC, 0x93, 0xCC, 0x80, 0xCA, + 0x06, 0xCE, 0x99, 0xCC, 0x93, 0xCC, 0x81, 0xCA, + 0x06, 0xCE, 0x99, 0xCC, 0x93, 0xCD, 0x82, 0xCA, + 0x06, 0xCE, 0x99, 0xCC, 0x94, 0xCC, 0x80, 0xCA, + 0x06, 0xCE, 0x99, 0xCC, 0x94, 0xCC, 0x81, 0xCA, + // Bytes 3d40 - 3d7f + 0x06, 0xCE, 0x99, 0xCC, 0x94, 0xCD, 0x82, 0xCA, + 0x06, 0xCE, 0x9F, 0xCC, 0x93, 0xCC, 0x80, 0xCA, + 0x06, 0xCE, 0x9F, 0xCC, 0x93, 0xCC, 0x81, 0xCA, + 0x06, 0xCE, 0x9F, 0xCC, 0x94, 0xCC, 0x80, 0xCA, + 0x06, 0xCE, 0x9F, 0xCC, 0x94, 0xCC, 0x81, 0xCA, + 0x06, 0xCE, 0xA5, 0xCC, 0x94, 0xCC, 0x80, 0xCA, + 0x06, 0xCE, 0xA5, 0xCC, 0x94, 0xCC, 0x81, 0xCA, + 0x06, 0xCE, 0xA5, 0xCC, 0x94, 0xCD, 0x82, 0xCA, + // Bytes 3d80 - 3dbf + 0x06, 0xCE, 0xA9, 0xCC, 0x93, 0xCD, 0x85, 0xDA, + 0x06, 0xCE, 0xA9, 0xCC, 0x94, 0xCD, 0x85, 0xDA, + 0x06, 0xCE, 0xB1, 0xCC, 0x80, 0xCD, 0x85, 0xDA, + 0x06, 0xCE, 0xB1, 0xCC, 0x81, 0xCD, 0x85, 0xDA, + 0x06, 0xCE, 0xB1, 0xCC, 0x93, 0xCD, 0x85, 0xDA, + 0x06, 0xCE, 0xB1, 0xCC, 0x94, 0xCD, 0x85, 0xDA, + 0x06, 0xCE, 0xB1, 0xCD, 0x82, 0xCD, 0x85, 0xDA, + 0x06, 0xCE, 0xB5, 0xCC, 0x93, 0xCC, 0x80, 0xCA, + // Bytes 3dc0 - 3dff + 0x06, 0xCE, 0xB5, 0xCC, 0x93, 0xCC, 0x81, 0xCA, + 0x06, 0xCE, 0xB5, 0xCC, 0x94, 0xCC, 0x80, 0xCA, + 0x06, 0xCE, 0xB5, 0xCC, 0x94, 0xCC, 0x81, 0xCA, + 0x06, 0xCE, 0xB7, 0xCC, 0x80, 0xCD, 0x85, 0xDA, + 0x06, 0xCE, 0xB7, 0xCC, 0x81, 0xCD, 0x85, 0xDA, + 0x06, 0xCE, 0xB7, 0xCC, 0x93, 0xCD, 0x85, 0xDA, + 0x06, 0xCE, 0xB7, 0xCC, 0x94, 0xCD, 0x85, 0xDA, + 0x06, 0xCE, 0xB7, 0xCD, 0x82, 0xCD, 0x85, 0xDA, + // Bytes 3e00 - 3e3f + 0x06, 0xCE, 0xB9, 0xCC, 0x88, 0xCC, 0x80, 0xCA, + 0x06, 0xCE, 0xB9, 0xCC, 0x88, 0xCC, 0x81, 0xCA, + 0x06, 0xCE, 0xB9, 0xCC, 0x88, 0xCD, 0x82, 0xCA, + 0x06, 0xCE, 0xB9, 0xCC, 0x93, 0xCC, 0x80, 0xCA, + 0x06, 0xCE, 0xB9, 0xCC, 0x93, 0xCC, 0x81, 0xCA, + 0x06, 0xCE, 0xB9, 0xCC, 0x93, 0xCD, 0x82, 0xCA, + 0x06, 0xCE, 0xB9, 0xCC, 0x94, 0xCC, 0x80, 0xCA, + 0x06, 0xCE, 0xB9, 0xCC, 0x94, 0xCC, 0x81, 0xCA, + // Bytes 3e40 - 3e7f + 0x06, 0xCE, 0xB9, 0xCC, 0x94, 0xCD, 0x82, 0xCA, + 0x06, 0xCE, 0xBF, 0xCC, 0x93, 0xCC, 0x80, 0xCA, + 0x06, 0xCE, 0xBF, 0xCC, 0x93, 0xCC, 0x81, 0xCA, + 0x06, 0xCE, 0xBF, 0xCC, 0x94, 0xCC, 0x80, 0xCA, + 0x06, 0xCE, 0xBF, 0xCC, 0x94, 0xCC, 0x81, 0xCA, + 0x06, 0xCF, 0x85, 0xCC, 0x88, 0xCC, 0x80, 0xCA, + 0x06, 0xCF, 0x85, 0xCC, 0x88, 0xCC, 0x81, 0xCA, + 0x06, 0xCF, 0x85, 0xCC, 0x88, 0xCD, 0x82, 0xCA, + // Bytes 3e80 - 3ebf + 0x06, 0xCF, 0x85, 0xCC, 0x93, 0xCC, 0x80, 0xCA, + 0x06, 0xCF, 0x85, 0xCC, 0x93, 0xCC, 0x81, 0xCA, + 0x06, 0xCF, 0x85, 0xCC, 0x93, 0xCD, 0x82, 0xCA, + 0x06, 0xCF, 0x85, 0xCC, 0x94, 0xCC, 0x80, 0xCA, + 0x06, 0xCF, 0x85, 0xCC, 0x94, 0xCC, 0x81, 0xCA, + 0x06, 0xCF, 0x85, 0xCC, 0x94, 0xCD, 0x82, 0xCA, + 0x06, 0xCF, 0x89, 0xCC, 0x80, 0xCD, 0x85, 0xDA, + 0x06, 0xCF, 0x89, 0xCC, 0x81, 0xCD, 0x85, 0xDA, + // Bytes 3ec0 - 3eff + 0x06, 0xCF, 0x89, 0xCC, 0x93, 0xCD, 0x85, 0xDA, + 0x06, 0xCF, 0x89, 0xCC, 0x94, 0xCD, 0x85, 0xDA, + 0x06, 0xCF, 0x89, 0xCD, 0x82, 0xCD, 0x85, 0xDA, + 0x06, 0xE0, 0xA4, 0xA8, 0xE0, 0xA4, 0xBC, 0x09, + 0x06, 0xE0, 0xA4, 0xB0, 0xE0, 0xA4, 0xBC, 0x09, + 0x06, 0xE0, 0xA4, 0xB3, 0xE0, 0xA4, 0xBC, 0x09, + 0x06, 0xE0, 0xB1, 0x86, 0xE0, 0xB1, 0x96, 0x85, + 0x06, 0xE0, 0xB7, 0x99, 0xE0, 0xB7, 0x8A, 0x11, + // Bytes 3f00 - 3f3f + 0x06, 0xE3, 0x81, 0x86, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0x8B, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0x8D, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0x8F, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0x91, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0x93, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0x95, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0x97, 0xE3, 0x82, 0x99, 0x0D, + // Bytes 3f40 - 3f7f + 0x06, 0xE3, 0x81, 0x99, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0x9B, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0x9D, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0x9F, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0xA1, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0xA4, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0xA6, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0xA8, 0xE3, 0x82, 0x99, 0x0D, + // Bytes 3f80 - 3fbf + 0x06, 0xE3, 0x81, 0xAF, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0xAF, 0xE3, 0x82, 0x9A, 0x0D, + 0x06, 0xE3, 0x81, 0xB2, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0xB2, 0xE3, 0x82, 0x9A, 0x0D, + 0x06, 0xE3, 0x81, 0xB5, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0xB5, 0xE3, 0x82, 0x9A, 0x0D, + 0x06, 0xE3, 0x81, 0xB8, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0xB8, 0xE3, 0x82, 0x9A, 0x0D, + // Bytes 3fc0 - 3fff + 0x06, 0xE3, 0x81, 0xBB, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0xBB, 0xE3, 0x82, 0x9A, 0x0D, + 0x06, 0xE3, 0x82, 0x9D, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x82, 0xA6, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x82, 0xAD, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x82, 0xB1, 0xE3, 0x82, 0x99, 0x0D, + // Bytes 4000 - 403f + 0x06, 0xE3, 0x82, 0xB3, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x82, 0xB5, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x82, 0xB7, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x82, 0xB9, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x82, 0xBB, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x82, 0xBD, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x82, 0xBF, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x83, 0x81, 0xE3, 0x82, 0x99, 0x0D, + // Bytes 4040 - 407f + 0x06, 0xE3, 0x83, 0x84, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x83, 0x86, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x9A, 0x0D, + 0x06, 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x9A, 0x0D, + 0x06, 0xE3, 0x83, 0x95, 0xE3, 0x82, 0x99, 0x0D, + // Bytes 4080 - 40bf + 0x06, 0xE3, 0x83, 0x95, 0xE3, 0x82, 0x9A, 0x0D, + 0x06, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x9A, 0x0D, + 0x06, 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x9A, 0x0D, + 0x06, 0xE3, 0x83, 0xAF, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x83, 0xB0, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x83, 0xB1, 0xE3, 0x82, 0x99, 0x0D, + // Bytes 40c0 - 40ff + 0x06, 0xE3, 0x83, 0xB2, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x83, 0xBD, 0xE3, 0x82, 0x99, 0x0D, + 0x08, 0xCE, 0x91, 0xCC, 0x93, 0xCC, 0x80, 0xCD, + 0x85, 0xDB, 0x08, 0xCE, 0x91, 0xCC, 0x93, 0xCC, + 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0x91, 0xCC, + 0x93, 0xCD, 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCE, + 0x91, 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85, 0xDB, + 0x08, 0xCE, 0x91, 0xCC, 0x94, 0xCC, 0x81, 0xCD, + // Bytes 4100 - 413f + 0x85, 0xDB, 0x08, 0xCE, 0x91, 0xCC, 0x94, 0xCD, + 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0x97, 0xCC, + 0x93, 0xCC, 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCE, + 0x97, 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, 0xDB, + 0x08, 0xCE, 0x97, 0xCC, 0x93, 0xCD, 0x82, 0xCD, + 0x85, 0xDB, 0x08, 0xCE, 0x97, 0xCC, 0x94, 0xCC, + 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0x97, 0xCC, + 0x94, 0xCC, 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCE, + // Bytes 4140 - 417f + 0x97, 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, 0xDB, + 0x08, 0xCE, 0xA9, 0xCC, 0x93, 0xCC, 0x80, 0xCD, + 0x85, 0xDB, 0x08, 0xCE, 0xA9, 0xCC, 0x93, 0xCC, + 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xA9, 0xCC, + 0x93, 0xCD, 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCE, + 0xA9, 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85, 0xDB, + 0x08, 0xCE, 0xA9, 0xCC, 0x94, 0xCC, 0x81, 0xCD, + 0x85, 0xDB, 0x08, 0xCE, 0xA9, 0xCC, 0x94, 0xCD, + // Bytes 4180 - 41bf + 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xB1, 0xCC, + 0x93, 0xCC, 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCE, + 0xB1, 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, 0xDB, + 0x08, 0xCE, 0xB1, 0xCC, 0x93, 0xCD, 0x82, 0xCD, + 0x85, 0xDB, 0x08, 0xCE, 0xB1, 0xCC, 0x94, 0xCC, + 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xB1, 0xCC, + 0x94, 0xCC, 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCE, + 0xB1, 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, 0xDB, + // Bytes 41c0 - 41ff + 0x08, 0xCE, 0xB7, 0xCC, 0x93, 0xCC, 0x80, 0xCD, + 0x85, 0xDB, 0x08, 0xCE, 0xB7, 0xCC, 0x93, 0xCC, + 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xB7, 0xCC, + 0x93, 0xCD, 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCE, + 0xB7, 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85, 0xDB, + 0x08, 0xCE, 0xB7, 0xCC, 0x94, 0xCC, 0x81, 0xCD, + 0x85, 0xDB, 0x08, 0xCE, 0xB7, 0xCC, 0x94, 0xCD, + 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCF, 0x89, 0xCC, + // Bytes 4200 - 423f + 0x93, 0xCC, 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCF, + 0x89, 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, 0xDB, + 0x08, 0xCF, 0x89, 0xCC, 0x93, 0xCD, 0x82, 0xCD, + 0x85, 0xDB, 0x08, 0xCF, 0x89, 0xCC, 0x94, 0xCC, + 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCF, 0x89, 0xCC, + 0x94, 0xCC, 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCF, + 0x89, 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, 0xDB, + 0x08, 0xF0, 0x91, 0x82, 0x99, 0xF0, 0x91, 0x82, + // Bytes 4240 - 427f + 0xBA, 0x09, 0x08, 0xF0, 0x91, 0x82, 0x9B, 0xF0, + 0x91, 0x82, 0xBA, 0x09, 0x08, 0xF0, 0x91, 0x82, + 0xA5, 0xF0, 0x91, 0x82, 0xBA, 0x09, 0x42, 0xC2, + 0xB4, 0x01, 0x43, 0x20, 0xCC, 0x81, 0xC9, 0x43, + 0x20, 0xCC, 0x83, 0xC9, 0x43, 0x20, 0xCC, 0x84, + 0xC9, 0x43, 0x20, 0xCC, 0x85, 0xC9, 0x43, 0x20, + 0xCC, 0x86, 0xC9, 0x43, 0x20, 0xCC, 0x87, 0xC9, + 0x43, 0x20, 0xCC, 0x88, 0xC9, 0x43, 0x20, 0xCC, + // Bytes 4280 - 42bf + 0x8A, 0xC9, 0x43, 0x20, 0xCC, 0x8B, 0xC9, 0x43, + 0x20, 0xCC, 0x93, 0xC9, 0x43, 0x20, 0xCC, 0x94, + 0xC9, 0x43, 0x20, 0xCC, 0xA7, 0xA5, 0x43, 0x20, + 0xCC, 0xA8, 0xA5, 0x43, 0x20, 0xCC, 0xB3, 0xB5, + 0x43, 0x20, 0xCD, 0x82, 0xC9, 0x43, 0x20, 0xCD, + 0x85, 0xD9, 0x43, 0x20, 0xD9, 0x8B, 0x59, 0x43, + 0x20, 0xD9, 0x8C, 0x5D, 0x43, 0x20, 0xD9, 0x8D, + 0x61, 0x43, 0x20, 0xD9, 0x8E, 0x65, 0x43, 0x20, + // Bytes 42c0 - 42ff + 0xD9, 0x8F, 0x69, 0x43, 0x20, 0xD9, 0x90, 0x6D, + 0x43, 0x20, 0xD9, 0x91, 0x71, 0x43, 0x20, 0xD9, + 0x92, 0x75, 0x43, 0x41, 0xCC, 0x8A, 0xC9, 0x43, + 0x73, 0xCC, 0x87, 0xC9, 0x44, 0x20, 0xE3, 0x82, + 0x99, 0x0D, 0x44, 0x20, 0xE3, 0x82, 0x9A, 0x0D, + 0x44, 0xC2, 0xA8, 0xCC, 0x81, 0xCA, 0x44, 0xCE, + 0x91, 0xCC, 0x81, 0xC9, 0x44, 0xCE, 0x95, 0xCC, + 0x81, 0xC9, 0x44, 0xCE, 0x97, 0xCC, 0x81, 0xC9, + // Bytes 4300 - 433f + 0x44, 0xCE, 0x99, 0xCC, 0x81, 0xC9, 0x44, 0xCE, + 0x9F, 0xCC, 0x81, 0xC9, 0x44, 0xCE, 0xA5, 0xCC, + 0x81, 0xC9, 0x44, 0xCE, 0xA5, 0xCC, 0x88, 0xC9, + 0x44, 0xCE, 0xA9, 0xCC, 0x81, 0xC9, 0x44, 0xCE, + 0xB1, 0xCC, 0x81, 0xC9, 0x44, 0xCE, 0xB5, 0xCC, + 0x81, 0xC9, 0x44, 0xCE, 0xB7, 0xCC, 0x81, 0xC9, + 0x44, 0xCE, 0xB9, 0xCC, 0x81, 0xC9, 0x44, 0xCE, + 0xBF, 0xCC, 0x81, 0xC9, 0x44, 0xCF, 0x85, 0xCC, + // Bytes 4340 - 437f + 0x81, 0xC9, 0x44, 0xCF, 0x89, 0xCC, 0x81, 0xC9, + 0x44, 0xD7, 0x90, 0xD6, 0xB7, 0x31, 0x44, 0xD7, + 0x90, 0xD6, 0xB8, 0x35, 0x44, 0xD7, 0x90, 0xD6, + 0xBC, 0x41, 0x44, 0xD7, 0x91, 0xD6, 0xBC, 0x41, + 0x44, 0xD7, 0x91, 0xD6, 0xBF, 0x49, 0x44, 0xD7, + 0x92, 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0x93, 0xD6, + 0xBC, 0x41, 0x44, 0xD7, 0x94, 0xD6, 0xBC, 0x41, + 0x44, 0xD7, 0x95, 0xD6, 0xB9, 0x39, 0x44, 0xD7, + // Bytes 4380 - 43bf + 0x95, 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0x96, 0xD6, + 0xBC, 0x41, 0x44, 0xD7, 0x98, 0xD6, 0xBC, 0x41, + 0x44, 0xD7, 0x99, 0xD6, 0xB4, 0x25, 0x44, 0xD7, + 0x99, 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0x9A, 0xD6, + 0xBC, 0x41, 0x44, 0xD7, 0x9B, 0xD6, 0xBC, 0x41, + 0x44, 0xD7, 0x9B, 0xD6, 0xBF, 0x49, 0x44, 0xD7, + 0x9C, 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0x9E, 0xD6, + 0xBC, 0x41, 0x44, 0xD7, 0xA0, 0xD6, 0xBC, 0x41, + // Bytes 43c0 - 43ff + 0x44, 0xD7, 0xA1, 0xD6, 0xBC, 0x41, 0x44, 0xD7, + 0xA3, 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0xA4, 0xD6, + 0xBC, 0x41, 0x44, 0xD7, 0xA4, 0xD6, 0xBF, 0x49, + 0x44, 0xD7, 0xA6, 0xD6, 0xBC, 0x41, 0x44, 0xD7, + 0xA7, 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0xA8, 0xD6, + 0xBC, 0x41, 0x44, 0xD7, 0xA9, 0xD6, 0xBC, 0x41, + 0x44, 0xD7, 0xA9, 0xD7, 0x81, 0x4D, 0x44, 0xD7, + 0xA9, 0xD7, 0x82, 0x51, 0x44, 0xD7, 0xAA, 0xD6, + // Bytes 4400 - 443f + 0xBC, 0x41, 0x44, 0xD7, 0xB2, 0xD6, 0xB7, 0x31, + 0x44, 0xD8, 0xA7, 0xD9, 0x8B, 0x59, 0x44, 0xD8, + 0xA7, 0xD9, 0x93, 0xC9, 0x44, 0xD8, 0xA7, 0xD9, + 0x94, 0xC9, 0x44, 0xD8, 0xA7, 0xD9, 0x95, 0xB5, + 0x44, 0xD8, 0xB0, 0xD9, 0xB0, 0x79, 0x44, 0xD8, + 0xB1, 0xD9, 0xB0, 0x79, 0x44, 0xD9, 0x80, 0xD9, + 0x8B, 0x59, 0x44, 0xD9, 0x80, 0xD9, 0x8E, 0x65, + 0x44, 0xD9, 0x80, 0xD9, 0x8F, 0x69, 0x44, 0xD9, + // Bytes 4440 - 447f + 0x80, 0xD9, 0x90, 0x6D, 0x44, 0xD9, 0x80, 0xD9, + 0x91, 0x71, 0x44, 0xD9, 0x80, 0xD9, 0x92, 0x75, + 0x44, 0xD9, 0x87, 0xD9, 0xB0, 0x79, 0x44, 0xD9, + 0x88, 0xD9, 0x94, 0xC9, 0x44, 0xD9, 0x89, 0xD9, + 0xB0, 0x79, 0x44, 0xD9, 0x8A, 0xD9, 0x94, 0xC9, + 0x44, 0xDB, 0x92, 0xD9, 0x94, 0xC9, 0x44, 0xDB, + 0x95, 0xD9, 0x94, 0xC9, 0x45, 0x20, 0xCC, 0x88, + 0xCC, 0x80, 0xCA, 0x45, 0x20, 0xCC, 0x88, 0xCC, + // Bytes 4480 - 44bf + 0x81, 0xCA, 0x45, 0x20, 0xCC, 0x88, 0xCD, 0x82, + 0xCA, 0x45, 0x20, 0xCC, 0x93, 0xCC, 0x80, 0xCA, + 0x45, 0x20, 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x45, + 0x20, 0xCC, 0x93, 0xCD, 0x82, 0xCA, 0x45, 0x20, + 0xCC, 0x94, 0xCC, 0x80, 0xCA, 0x45, 0x20, 0xCC, + 0x94, 0xCC, 0x81, 0xCA, 0x45, 0x20, 0xCC, 0x94, + 0xCD, 0x82, 0xCA, 0x45, 0x20, 0xD9, 0x8C, 0xD9, + 0x91, 0x72, 0x45, 0x20, 0xD9, 0x8D, 0xD9, 0x91, + // Bytes 44c0 - 44ff + 0x72, 0x45, 0x20, 0xD9, 0x8E, 0xD9, 0x91, 0x72, + 0x45, 0x20, 0xD9, 0x8F, 0xD9, 0x91, 0x72, 0x45, + 0x20, 0xD9, 0x90, 0xD9, 0x91, 0x72, 0x45, 0x20, + 0xD9, 0x91, 0xD9, 0xB0, 0x7A, 0x45, 0xE2, 0xAB, + 0x9D, 0xCC, 0xB8, 0x05, 0x46, 0xCE, 0xB9, 0xCC, + 0x88, 0xCC, 0x81, 0xCA, 0x46, 0xCF, 0x85, 0xCC, + 0x88, 0xCC, 0x81, 0xCA, 0x46, 0xD7, 0xA9, 0xD6, + 0xBC, 0xD7, 0x81, 0x4E, 0x46, 0xD7, 0xA9, 0xD6, + // Bytes 4500 - 453f + 0xBC, 0xD7, 0x82, 0x52, 0x46, 0xD9, 0x80, 0xD9, + 0x8E, 0xD9, 0x91, 0x72, 0x46, 0xD9, 0x80, 0xD9, + 0x8F, 0xD9, 0x91, 0x72, 0x46, 0xD9, 0x80, 0xD9, + 0x90, 0xD9, 0x91, 0x72, 0x46, 0xE0, 0xA4, 0x95, + 0xE0, 0xA4, 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0x96, + 0xE0, 0xA4, 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0x97, + 0xE0, 0xA4, 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0x9C, + 0xE0, 0xA4, 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0xA1, + // Bytes 4540 - 457f + 0xE0, 0xA4, 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0xA2, + 0xE0, 0xA4, 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0xAB, + 0xE0, 0xA4, 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0xAF, + 0xE0, 0xA4, 0xBC, 0x09, 0x46, 0xE0, 0xA6, 0xA1, + 0xE0, 0xA6, 0xBC, 0x09, 0x46, 0xE0, 0xA6, 0xA2, + 0xE0, 0xA6, 0xBC, 0x09, 0x46, 0xE0, 0xA6, 0xAF, + 0xE0, 0xA6, 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0x96, + 0xE0, 0xA8, 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0x97, + // Bytes 4580 - 45bf + 0xE0, 0xA8, 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0x9C, + 0xE0, 0xA8, 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0xAB, + 0xE0, 0xA8, 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0xB2, + 0xE0, 0xA8, 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0xB8, + 0xE0, 0xA8, 0xBC, 0x09, 0x46, 0xE0, 0xAC, 0xA1, + 0xE0, 0xAC, 0xBC, 0x09, 0x46, 0xE0, 0xAC, 0xA2, + 0xE0, 0xAC, 0xBC, 0x09, 0x46, 0xE0, 0xBE, 0xB2, + 0xE0, 0xBE, 0x80, 0x9D, 0x46, 0xE0, 0xBE, 0xB3, + // Bytes 45c0 - 45ff + 0xE0, 0xBE, 0x80, 0x9D, 0x46, 0xE3, 0x83, 0x86, + 0xE3, 0x82, 0x99, 0x0D, 0x48, 0xF0, 0x9D, 0x85, + 0x97, 0xF0, 0x9D, 0x85, 0xA5, 0xAD, 0x48, 0xF0, + 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xAD, + 0x48, 0xF0, 0x9D, 0x86, 0xB9, 0xF0, 0x9D, 0x85, + 0xA5, 0xAD, 0x48, 0xF0, 0x9D, 0x86, 0xBA, 0xF0, + 0x9D, 0x85, 0xA5, 0xAD, 0x49, 0xE0, 0xBE, 0xB2, + 0xE0, 0xBD, 0xB1, 0xE0, 0xBE, 0x80, 0x9E, 0x49, + // Bytes 4600 - 463f + 0xE0, 0xBE, 0xB3, 0xE0, 0xBD, 0xB1, 0xE0, 0xBE, + 0x80, 0x9E, 0x4C, 0xF0, 0x9D, 0x85, 0x98, 0xF0, + 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAE, 0xAE, + 0x4C, 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85, + 0xA5, 0xF0, 0x9D, 0x85, 0xAF, 0xAE, 0x4C, 0xF0, + 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, + 0x9D, 0x85, 0xB0, 0xAE, 0x4C, 0xF0, 0x9D, 0x85, + 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, + // Bytes 4640 - 467f + 0xB1, 0xAE, 0x4C, 0xF0, 0x9D, 0x85, 0x98, 0xF0, + 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xB2, 0xAE, + 0x4C, 0xF0, 0x9D, 0x86, 0xB9, 0xF0, 0x9D, 0x85, + 0xA5, 0xF0, 0x9D, 0x85, 0xAE, 0xAE, 0x4C, 0xF0, + 0x9D, 0x86, 0xB9, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, + 0x9D, 0x85, 0xAF, 0xAE, 0x4C, 0xF0, 0x9D, 0x86, + 0xBA, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, + 0xAE, 0xAE, 0x4C, 0xF0, 0x9D, 0x86, 0xBA, 0xF0, + // Bytes 4680 - 46bf + 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAF, 0xAE, + 0x83, 0x41, 0xCC, 0x82, 0xC9, 0x83, 0x41, 0xCC, + 0x86, 0xC9, 0x83, 0x41, 0xCC, 0x87, 0xC9, 0x83, + 0x41, 0xCC, 0x88, 0xC9, 0x83, 0x41, 0xCC, 0x8A, + 0xC9, 0x83, 0x41, 0xCC, 0xA3, 0xB5, 0x83, 0x43, + 0xCC, 0xA7, 0xA5, 0x83, 0x45, 0xCC, 0x82, 0xC9, + 0x83, 0x45, 0xCC, 0x84, 0xC9, 0x83, 0x45, 0xCC, + 0xA3, 0xB5, 0x83, 0x45, 0xCC, 0xA7, 0xA5, 0x83, + // Bytes 46c0 - 46ff + 0x49, 0xCC, 0x88, 0xC9, 0x83, 0x4C, 0xCC, 0xA3, + 0xB5, 0x83, 0x4F, 0xCC, 0x82, 0xC9, 0x83, 0x4F, + 0xCC, 0x83, 0xC9, 0x83, 0x4F, 0xCC, 0x84, 0xC9, + 0x83, 0x4F, 0xCC, 0x87, 0xC9, 0x83, 0x4F, 0xCC, + 0x88, 0xC9, 0x83, 0x4F, 0xCC, 0x9B, 0xAD, 0x83, + 0x4F, 0xCC, 0xA3, 0xB5, 0x83, 0x4F, 0xCC, 0xA8, + 0xA5, 0x83, 0x52, 0xCC, 0xA3, 0xB5, 0x83, 0x53, + 0xCC, 0x81, 0xC9, 0x83, 0x53, 0xCC, 0x8C, 0xC9, + // Bytes 4700 - 473f + 0x83, 0x53, 0xCC, 0xA3, 0xB5, 0x83, 0x55, 0xCC, + 0x83, 0xC9, 0x83, 0x55, 0xCC, 0x84, 0xC9, 0x83, + 0x55, 0xCC, 0x88, 0xC9, 0x83, 0x55, 0xCC, 0x9B, + 0xAD, 0x83, 0x61, 0xCC, 0x82, 0xC9, 0x83, 0x61, + 0xCC, 0x86, 0xC9, 0x83, 0x61, 0xCC, 0x87, 0xC9, + 0x83, 0x61, 0xCC, 0x88, 0xC9, 0x83, 0x61, 0xCC, + 0x8A, 0xC9, 0x83, 0x61, 0xCC, 0xA3, 0xB5, 0x83, + 0x63, 0xCC, 0xA7, 0xA5, 0x83, 0x65, 0xCC, 0x82, + // Bytes 4740 - 477f + 0xC9, 0x83, 0x65, 0xCC, 0x84, 0xC9, 0x83, 0x65, + 0xCC, 0xA3, 0xB5, 0x83, 0x65, 0xCC, 0xA7, 0xA5, + 0x83, 0x69, 0xCC, 0x88, 0xC9, 0x83, 0x6C, 0xCC, + 0xA3, 0xB5, 0x83, 0x6F, 0xCC, 0x82, 0xC9, 0x83, + 0x6F, 0xCC, 0x83, 0xC9, 0x83, 0x6F, 0xCC, 0x84, + 0xC9, 0x83, 0x6F, 0xCC, 0x87, 0xC9, 0x83, 0x6F, + 0xCC, 0x88, 0xC9, 0x83, 0x6F, 0xCC, 0x9B, 0xAD, + 0x83, 0x6F, 0xCC, 0xA3, 0xB5, 0x83, 0x6F, 0xCC, + // Bytes 4780 - 47bf + 0xA8, 0xA5, 0x83, 0x72, 0xCC, 0xA3, 0xB5, 0x83, + 0x73, 0xCC, 0x81, 0xC9, 0x83, 0x73, 0xCC, 0x8C, + 0xC9, 0x83, 0x73, 0xCC, 0xA3, 0xB5, 0x83, 0x75, + 0xCC, 0x83, 0xC9, 0x83, 0x75, 0xCC, 0x84, 0xC9, + 0x83, 0x75, 0xCC, 0x88, 0xC9, 0x83, 0x75, 0xCC, + 0x9B, 0xAD, 0x84, 0xCE, 0x91, 0xCC, 0x93, 0xC9, + 0x84, 0xCE, 0x91, 0xCC, 0x94, 0xC9, 0x84, 0xCE, + 0x95, 0xCC, 0x93, 0xC9, 0x84, 0xCE, 0x95, 0xCC, + // Bytes 47c0 - 47ff + 0x94, 0xC9, 0x84, 0xCE, 0x97, 0xCC, 0x93, 0xC9, + 0x84, 0xCE, 0x97, 0xCC, 0x94, 0xC9, 0x84, 0xCE, + 0x99, 0xCC, 0x93, 0xC9, 0x84, 0xCE, 0x99, 0xCC, + 0x94, 0xC9, 0x84, 0xCE, 0x9F, 0xCC, 0x93, 0xC9, + 0x84, 0xCE, 0x9F, 0xCC, 0x94, 0xC9, 0x84, 0xCE, + 0xA5, 0xCC, 0x94, 0xC9, 0x84, 0xCE, 0xA9, 0xCC, + 0x93, 0xC9, 0x84, 0xCE, 0xA9, 0xCC, 0x94, 0xC9, + 0x84, 0xCE, 0xB1, 0xCC, 0x80, 0xC9, 0x84, 0xCE, + // Bytes 4800 - 483f + 0xB1, 0xCC, 0x81, 0xC9, 0x84, 0xCE, 0xB1, 0xCC, + 0x93, 0xC9, 0x84, 0xCE, 0xB1, 0xCC, 0x94, 0xC9, + 0x84, 0xCE, 0xB1, 0xCD, 0x82, 0xC9, 0x84, 0xCE, + 0xB5, 0xCC, 0x93, 0xC9, 0x84, 0xCE, 0xB5, 0xCC, + 0x94, 0xC9, 0x84, 0xCE, 0xB7, 0xCC, 0x80, 0xC9, + 0x84, 0xCE, 0xB7, 0xCC, 0x81, 0xC9, 0x84, 0xCE, + 0xB7, 0xCC, 0x93, 0xC9, 0x84, 0xCE, 0xB7, 0xCC, + 0x94, 0xC9, 0x84, 0xCE, 0xB7, 0xCD, 0x82, 0xC9, + // Bytes 4840 - 487f + 0x84, 0xCE, 0xB9, 0xCC, 0x88, 0xC9, 0x84, 0xCE, + 0xB9, 0xCC, 0x93, 0xC9, 0x84, 0xCE, 0xB9, 0xCC, + 0x94, 0xC9, 0x84, 0xCE, 0xBF, 0xCC, 0x93, 0xC9, + 0x84, 0xCE, 0xBF, 0xCC, 0x94, 0xC9, 0x84, 0xCF, + 0x85, 0xCC, 0x88, 0xC9, 0x84, 0xCF, 0x85, 0xCC, + 0x93, 0xC9, 0x84, 0xCF, 0x85, 0xCC, 0x94, 0xC9, + 0x84, 0xCF, 0x89, 0xCC, 0x80, 0xC9, 0x84, 0xCF, + 0x89, 0xCC, 0x81, 0xC9, 0x84, 0xCF, 0x89, 0xCC, + // Bytes 4880 - 48bf + 0x93, 0xC9, 0x84, 0xCF, 0x89, 0xCC, 0x94, 0xC9, + 0x84, 0xCF, 0x89, 0xCD, 0x82, 0xC9, 0x86, 0xCE, + 0x91, 0xCC, 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCE, + 0x91, 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCE, + 0x91, 0xCC, 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCE, + 0x91, 0xCC, 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCE, + 0x91, 0xCC, 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCE, + 0x91, 0xCC, 0x94, 0xCD, 0x82, 0xCA, 0x86, 0xCE, + // Bytes 48c0 - 48ff + 0x97, 0xCC, 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCE, + 0x97, 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCE, + 0x97, 0xCC, 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCE, + 0x97, 0xCC, 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCE, + 0x97, 0xCC, 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCE, + 0x97, 0xCC, 0x94, 0xCD, 0x82, 0xCA, 0x86, 0xCE, + 0xA9, 0xCC, 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCE, + 0xA9, 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCE, + // Bytes 4900 - 493f + 0xA9, 0xCC, 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCE, + 0xA9, 0xCC, 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCE, + 0xA9, 0xCC, 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCE, + 0xA9, 0xCC, 0x94, 0xCD, 0x82, 0xCA, 0x86, 0xCE, + 0xB1, 0xCC, 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCE, + 0xB1, 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCE, + 0xB1, 0xCC, 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCE, + 0xB1, 0xCC, 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCE, + // Bytes 4940 - 497f + 0xB1, 0xCC, 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCE, + 0xB1, 0xCC, 0x94, 0xCD, 0x82, 0xCA, 0x86, 0xCE, + 0xB7, 0xCC, 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCE, + 0xB7, 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCE, + 0xB7, 0xCC, 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCE, + 0xB7, 0xCC, 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCE, + 0xB7, 0xCC, 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCE, + 0xB7, 0xCC, 0x94, 0xCD, 0x82, 0xCA, 0x86, 0xCF, + // Bytes 4980 - 49bf + 0x89, 0xCC, 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCF, + 0x89, 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCF, + 0x89, 0xCC, 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCF, + 0x89, 0xCC, 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCF, + 0x89, 0xCC, 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCF, + 0x89, 0xCC, 0x94, 0xCD, 0x82, 0xCA, 0x42, 0xCC, + 0x80, 0xC9, 0x32, 0x42, 0xCC, 0x81, 0xC9, 0x32, + 0x42, 0xCC, 0x93, 0xC9, 0x32, 0x43, 0xE1, 0x85, + // Bytes 49c0 - 49ff + 0xA1, 0x01, 0x00, 0x43, 0xE1, 0x85, 0xA2, 0x01, + 0x00, 0x43, 0xE1, 0x85, 0xA3, 0x01, 0x00, 0x43, + 0xE1, 0x85, 0xA4, 0x01, 0x00, 0x43, 0xE1, 0x85, + 0xA5, 0x01, 0x00, 0x43, 0xE1, 0x85, 0xA6, 0x01, + 0x00, 0x43, 0xE1, 0x85, 0xA7, 0x01, 0x00, 0x43, + 0xE1, 0x85, 0xA8, 0x01, 0x00, 0x43, 0xE1, 0x85, + 0xA9, 0x01, 0x00, 0x43, 0xE1, 0x85, 0xAA, 0x01, + 0x00, 0x43, 0xE1, 0x85, 0xAB, 0x01, 0x00, 0x43, + // Bytes 4a00 - 4a3f + 0xE1, 0x85, 0xAC, 0x01, 0x00, 0x43, 0xE1, 0x85, + 0xAD, 0x01, 0x00, 0x43, 0xE1, 0x85, 0xAE, 0x01, + 0x00, 0x43, 0xE1, 0x85, 0xAF, 0x01, 0x00, 0x43, + 0xE1, 0x85, 0xB0, 0x01, 0x00, 0x43, 0xE1, 0x85, + 0xB1, 0x01, 0x00, 0x43, 0xE1, 0x85, 0xB2, 0x01, + 0x00, 0x43, 0xE1, 0x85, 0xB3, 0x01, 0x00, 0x43, + 0xE1, 0x85, 0xB4, 0x01, 0x00, 0x43, 0xE1, 0x85, + 0xB5, 0x01, 0x00, 0x43, 0xE1, 0x86, 0xAA, 0x01, + // Bytes 4a40 - 4a7f + 0x00, 0x43, 0xE1, 0x86, 0xAC, 0x01, 0x00, 0x43, + 0xE1, 0x86, 0xAD, 0x01, 0x00, 0x43, 0xE1, 0x86, + 0xB0, 0x01, 0x00, 0x43, 0xE1, 0x86, 0xB1, 0x01, + 0x00, 0x43, 0xE1, 0x86, 0xB2, 0x01, 0x00, 0x43, + 0xE1, 0x86, 0xB3, 0x01, 0x00, 0x43, 0xE1, 0x86, + 0xB4, 0x01, 0x00, 0x43, 0xE1, 0x86, 0xB5, 0x01, + 0x00, 0x44, 0xCC, 0x88, 0xCC, 0x81, 0xCA, 0x32, + 0x43, 0xE3, 0x82, 0x99, 0x0D, 0x03, 0x43, 0xE3, + // Bytes 4a80 - 4abf + 0x82, 0x9A, 0x0D, 0x03, 0x46, 0xE0, 0xBD, 0xB1, + 0xE0, 0xBD, 0xB2, 0x9E, 0x26, 0x46, 0xE0, 0xBD, + 0xB1, 0xE0, 0xBD, 0xB4, 0xA2, 0x26, 0x46, 0xE0, + 0xBD, 0xB1, 0xE0, 0xBE, 0x80, 0x9E, 0x26, 0x00, + 0x01, +} + +// lookup returns the trie value for the first UTF-8 encoding in s and +// the width in bytes of this encoding. The size will be 0 if s does not +// hold enough bytes to complete the encoding. len(s) must be greater than 0. +func (t *nfcTrie) lookup(s []byte) (v uint16, sz int) { + c0 := s[0] + switch { + case c0 < 0x80: // is ASCII + return nfcValues[c0], 1 + case c0 < 0xC2: + return 0, 1 // Illegal UTF-8: not a starter, not ASCII. + case c0 < 0xE0: // 2-byte UTF-8 + if len(s) < 2 { + return 0, 0 + } + i := nfcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c1), 2 + case c0 < 0xF0: // 3-byte UTF-8 + if len(s) < 3 { + return 0, 0 + } + i := nfcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = nfcIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c2), 3 + case c0 < 0xF8: // 4-byte UTF-8 + if len(s) < 4 { + return 0, 0 + } + i := nfcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = nfcIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + o = uint32(i)<<6 + uint32(c2) + i = nfcIndex[o] + c3 := s[3] + if c3 < 0x80 || 0xC0 <= c3 { + return 0, 3 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c3), 4 + } + // Illegal rune + return 0, 1 +} + +// lookupUnsafe returns the trie value for the first UTF-8 encoding in s. +// s must start with a full and valid UTF-8 encoded rune. +func (t *nfcTrie) lookupUnsafe(s []byte) uint16 { + c0 := s[0] + if c0 < 0x80 { // is ASCII + return nfcValues[c0] + } + i := nfcIndex[c0] + if c0 < 0xE0 { // 2-byte UTF-8 + return t.lookupValue(uint32(i), s[1]) + } + i = nfcIndex[uint32(i)<<6+uint32(s[1])] + if c0 < 0xF0 { // 3-byte UTF-8 + return t.lookupValue(uint32(i), s[2]) + } + i = nfcIndex[uint32(i)<<6+uint32(s[2])] + if c0 < 0xF8 { // 4-byte UTF-8 + return t.lookupValue(uint32(i), s[3]) + } + return 0 +} + +// lookupString returns the trie value for the first UTF-8 encoding in s and +// the width in bytes of this encoding. The size will be 0 if s does not +// hold enough bytes to complete the encoding. len(s) must be greater than 0. +func (t *nfcTrie) lookupString(s string) (v uint16, sz int) { + c0 := s[0] + switch { + case c0 < 0x80: // is ASCII + return nfcValues[c0], 1 + case c0 < 0xC2: + return 0, 1 // Illegal UTF-8: not a starter, not ASCII. + case c0 < 0xE0: // 2-byte UTF-8 + if len(s) < 2 { + return 0, 0 + } + i := nfcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c1), 2 + case c0 < 0xF0: // 3-byte UTF-8 + if len(s) < 3 { + return 0, 0 + } + i := nfcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = nfcIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c2), 3 + case c0 < 0xF8: // 4-byte UTF-8 + if len(s) < 4 { + return 0, 0 + } + i := nfcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = nfcIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + o = uint32(i)<<6 + uint32(c2) + i = nfcIndex[o] + c3 := s[3] + if c3 < 0x80 || 0xC0 <= c3 { + return 0, 3 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c3), 4 + } + // Illegal rune + return 0, 1 +} + +// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s. +// s must start with a full and valid UTF-8 encoded rune. +func (t *nfcTrie) lookupStringUnsafe(s string) uint16 { + c0 := s[0] + if c0 < 0x80 { // is ASCII + return nfcValues[c0] + } + i := nfcIndex[c0] + if c0 < 0xE0 { // 2-byte UTF-8 + return t.lookupValue(uint32(i), s[1]) + } + i = nfcIndex[uint32(i)<<6+uint32(s[1])] + if c0 < 0xF0 { // 3-byte UTF-8 + return t.lookupValue(uint32(i), s[2]) + } + i = nfcIndex[uint32(i)<<6+uint32(s[2])] + if c0 < 0xF8 { // 4-byte UTF-8 + return t.lookupValue(uint32(i), s[3]) + } + return 0 +} + +// nfcTrie. Total size: 10442 bytes (10.20 KiB). Checksum: 4ba400a9d8208e03. +type nfcTrie struct{} + +func newNfcTrie(i int) *nfcTrie { + return &nfcTrie{} +} + +// lookupValue determines the type of block n and looks up the value for b. +func (t *nfcTrie) lookupValue(n uint32, b byte) uint16 { + switch { + case n < 45: + return uint16(nfcValues[n<<6+uint32(b)]) + default: + n -= 45 + return uint16(nfcSparse.lookup(n, b)) + } +} + +// nfcValues: 47 blocks, 3008 entries, 6016 bytes +// The third block is the zero block. +var nfcValues = [3008]uint16{ + // Block 0x0, offset 0x0 + 0x3c: 0xa000, 0x3d: 0xa000, 0x3e: 0xa000, + // Block 0x1, offset 0x40 + 0x41: 0xa000, 0x42: 0xa000, 0x43: 0xa000, 0x44: 0xa000, 0x45: 0xa000, + 0x46: 0xa000, 0x47: 0xa000, 0x48: 0xa000, 0x49: 0xa000, 0x4a: 0xa000, 0x4b: 0xa000, + 0x4c: 0xa000, 0x4d: 0xa000, 0x4e: 0xa000, 0x4f: 0xa000, 0x50: 0xa000, + 0x52: 0xa000, 0x53: 0xa000, 0x54: 0xa000, 0x55: 0xa000, 0x56: 0xa000, 0x57: 0xa000, + 0x58: 0xa000, 0x59: 0xa000, 0x5a: 0xa000, + 0x61: 0xa000, 0x62: 0xa000, 0x63: 0xa000, + 0x64: 0xa000, 0x65: 0xa000, 0x66: 0xa000, 0x67: 0xa000, 0x68: 0xa000, 0x69: 0xa000, + 0x6a: 0xa000, 0x6b: 0xa000, 0x6c: 0xa000, 0x6d: 0xa000, 0x6e: 0xa000, 0x6f: 0xa000, + 0x70: 0xa000, 0x72: 0xa000, 0x73: 0xa000, 0x74: 0xa000, 0x75: 0xa000, + 0x76: 0xa000, 0x77: 0xa000, 0x78: 0xa000, 0x79: 0xa000, 0x7a: 0xa000, + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0xc0: 0x2f6f, 0xc1: 0x2f74, 0xc2: 0x4688, 0xc3: 0x2f79, 0xc4: 0x4697, 0xc5: 0x469c, + 0xc6: 0xa000, 0xc7: 0x46a6, 0xc8: 0x2fe2, 0xc9: 0x2fe7, 0xca: 0x46ab, 0xcb: 0x2ffb, + 0xcc: 0x306e, 0xcd: 0x3073, 0xce: 0x3078, 0xcf: 0x46bf, 0xd1: 0x3104, + 0xd2: 0x3127, 0xd3: 0x312c, 0xd4: 0x46c9, 0xd5: 0x46ce, 0xd6: 0x46dd, + 0xd8: 0xa000, 0xd9: 0x31b3, 0xda: 0x31b8, 0xdb: 0x31bd, 0xdc: 0x470f, 0xdd: 0x3235, + 0xe0: 0x327b, 0xe1: 0x3280, 0xe2: 0x4719, 0xe3: 0x3285, + 0xe4: 0x4728, 0xe5: 0x472d, 0xe6: 0xa000, 0xe7: 0x4737, 0xe8: 0x32ee, 0xe9: 0x32f3, + 0xea: 0x473c, 0xeb: 0x3307, 0xec: 0x337f, 0xed: 0x3384, 0xee: 0x3389, 0xef: 0x4750, + 0xf1: 0x3415, 0xf2: 0x3438, 0xf3: 0x343d, 0xf4: 0x475a, 0xf5: 0x475f, + 0xf6: 0x476e, 0xf8: 0xa000, 0xf9: 0x34c9, 0xfa: 0x34ce, 0xfb: 0x34d3, + 0xfc: 0x47a0, 0xfd: 0x3550, 0xff: 0x3569, + // Block 0x4, offset 0x100 + 0x100: 0x2f7e, 0x101: 0x328a, 0x102: 0x468d, 0x103: 0x471e, 0x104: 0x2f9c, 0x105: 0x32a8, + 0x106: 0x2fb0, 0x107: 0x32bc, 0x108: 0x2fb5, 0x109: 0x32c1, 0x10a: 0x2fba, 0x10b: 0x32c6, + 0x10c: 0x2fbf, 0x10d: 0x32cb, 0x10e: 0x2fc9, 0x10f: 0x32d5, + 0x112: 0x46b0, 0x113: 0x4741, 0x114: 0x2ff1, 0x115: 0x32fd, 0x116: 0x2ff6, 0x117: 0x3302, + 0x118: 0x3014, 0x119: 0x3320, 0x11a: 0x3005, 0x11b: 0x3311, 0x11c: 0x302d, 0x11d: 0x3339, + 0x11e: 0x3037, 0x11f: 0x3343, 0x120: 0x303c, 0x121: 0x3348, 0x122: 0x3046, 0x123: 0x3352, + 0x124: 0x304b, 0x125: 0x3357, 0x128: 0x307d, 0x129: 0x338e, + 0x12a: 0x3082, 0x12b: 0x3393, 0x12c: 0x3087, 0x12d: 0x3398, 0x12e: 0x30aa, 0x12f: 0x33b6, + 0x130: 0x308c, 0x134: 0x30b4, 0x135: 0x33c0, + 0x136: 0x30c8, 0x137: 0x33d9, 0x139: 0x30d2, 0x13a: 0x33e3, 0x13b: 0x30dc, + 0x13c: 0x33ed, 0x13d: 0x30d7, 0x13e: 0x33e8, + // Block 0x5, offset 0x140 + 0x143: 0x30ff, 0x144: 0x3410, 0x145: 0x3118, + 0x146: 0x3429, 0x147: 0x310e, 0x148: 0x341f, + 0x14c: 0x46d3, 0x14d: 0x4764, 0x14e: 0x3131, 0x14f: 0x3442, 0x150: 0x313b, 0x151: 0x344c, + 0x154: 0x3159, 0x155: 0x346a, 0x156: 0x3172, 0x157: 0x3483, + 0x158: 0x3163, 0x159: 0x3474, 0x15a: 0x46f6, 0x15b: 0x4787, 0x15c: 0x317c, 0x15d: 0x348d, + 0x15e: 0x318b, 0x15f: 0x349c, 0x160: 0x46fb, 0x161: 0x478c, 0x162: 0x31a4, 0x163: 0x34ba, + 0x164: 0x3195, 0x165: 0x34ab, 0x168: 0x4705, 0x169: 0x4796, + 0x16a: 0x470a, 0x16b: 0x479b, 0x16c: 0x31c2, 0x16d: 0x34d8, 0x16e: 0x31cc, 0x16f: 0x34e2, + 0x170: 0x31d1, 0x171: 0x34e7, 0x172: 0x31ef, 0x173: 0x3505, 0x174: 0x3212, 0x175: 0x3528, + 0x176: 0x323a, 0x177: 0x3555, 0x178: 0x324e, 0x179: 0x325d, 0x17a: 0x357d, 0x17b: 0x3267, + 0x17c: 0x3587, 0x17d: 0x326c, 0x17e: 0x358c, 0x17f: 0xa000, + // Block 0x6, offset 0x180 + 0x184: 0x8100, 0x185: 0x8100, + 0x186: 0x8100, + 0x18d: 0x2f88, 0x18e: 0x3294, 0x18f: 0x3096, 0x190: 0x33a2, 0x191: 0x3140, + 0x192: 0x3451, 0x193: 0x31d6, 0x194: 0x34ec, 0x195: 0x39cf, 0x196: 0x3b5e, 0x197: 0x39c8, + 0x198: 0x3b57, 0x199: 0x39d6, 0x19a: 0x3b65, 0x19b: 0x39c1, 0x19c: 0x3b50, + 0x19e: 0x38b0, 0x19f: 0x3a3f, 0x1a0: 0x38a9, 0x1a1: 0x3a38, 0x1a2: 0x35b3, 0x1a3: 0x35c5, + 0x1a6: 0x3041, 0x1a7: 0x334d, 0x1a8: 0x30be, 0x1a9: 0x33cf, + 0x1aa: 0x46ec, 0x1ab: 0x477d, 0x1ac: 0x3990, 0x1ad: 0x3b1f, 0x1ae: 0x35d7, 0x1af: 0x35dd, + 0x1b0: 0x33c5, 0x1b4: 0x3028, 0x1b5: 0x3334, + 0x1b8: 0x30fa, 0x1b9: 0x340b, 0x1ba: 0x38b7, 0x1bb: 0x3a46, + 0x1bc: 0x35ad, 0x1bd: 0x35bf, 0x1be: 0x35b9, 0x1bf: 0x35cb, + // Block 0x7, offset 0x1c0 + 0x1c0: 0x2f8d, 0x1c1: 0x3299, 0x1c2: 0x2f92, 0x1c3: 0x329e, 0x1c4: 0x300a, 0x1c5: 0x3316, + 0x1c6: 0x300f, 0x1c7: 0x331b, 0x1c8: 0x309b, 0x1c9: 0x33a7, 0x1ca: 0x30a0, 0x1cb: 0x33ac, + 0x1cc: 0x3145, 0x1cd: 0x3456, 0x1ce: 0x314a, 0x1cf: 0x345b, 0x1d0: 0x3168, 0x1d1: 0x3479, + 0x1d2: 0x316d, 0x1d3: 0x347e, 0x1d4: 0x31db, 0x1d5: 0x34f1, 0x1d6: 0x31e0, 0x1d7: 0x34f6, + 0x1d8: 0x3186, 0x1d9: 0x3497, 0x1da: 0x319f, 0x1db: 0x34b5, + 0x1de: 0x305a, 0x1df: 0x3366, + 0x1e6: 0x4692, 0x1e7: 0x4723, 0x1e8: 0x46ba, 0x1e9: 0x474b, + 0x1ea: 0x395f, 0x1eb: 0x3aee, 0x1ec: 0x393c, 0x1ed: 0x3acb, 0x1ee: 0x46d8, 0x1ef: 0x4769, + 0x1f0: 0x3958, 0x1f1: 0x3ae7, 0x1f2: 0x3244, 0x1f3: 0x355f, + // Block 0x8, offset 0x200 + 0x200: 0x9932, 0x201: 0x9932, 0x202: 0x9932, 0x203: 0x9932, 0x204: 0x9932, 0x205: 0x8132, + 0x206: 0x9932, 0x207: 0x9932, 0x208: 0x9932, 0x209: 0x9932, 0x20a: 0x9932, 0x20b: 0x9932, + 0x20c: 0x9932, 0x20d: 0x8132, 0x20e: 0x8132, 0x20f: 0x9932, 0x210: 0x8132, 0x211: 0x9932, + 0x212: 0x8132, 0x213: 0x9932, 0x214: 0x9932, 0x215: 0x8133, 0x216: 0x812d, 0x217: 0x812d, + 0x218: 0x812d, 0x219: 0x812d, 0x21a: 0x8133, 0x21b: 0x992b, 0x21c: 0x812d, 0x21d: 0x812d, + 0x21e: 0x812d, 0x21f: 0x812d, 0x220: 0x812d, 0x221: 0x8129, 0x222: 0x8129, 0x223: 0x992d, + 0x224: 0x992d, 0x225: 0x992d, 0x226: 0x992d, 0x227: 0x9929, 0x228: 0x9929, 0x229: 0x812d, + 0x22a: 0x812d, 0x22b: 0x812d, 0x22c: 0x812d, 0x22d: 0x992d, 0x22e: 0x992d, 0x22f: 0x812d, + 0x230: 0x992d, 0x231: 0x992d, 0x232: 0x812d, 0x233: 0x812d, 0x234: 0x8101, 0x235: 0x8101, + 0x236: 0x8101, 0x237: 0x8101, 0x238: 0x9901, 0x239: 0x812d, 0x23a: 0x812d, 0x23b: 0x812d, + 0x23c: 0x812d, 0x23d: 0x8132, 0x23e: 0x8132, 0x23f: 0x8132, + // Block 0x9, offset 0x240 + 0x240: 0x49ae, 0x241: 0x49b3, 0x242: 0x9932, 0x243: 0x49b8, 0x244: 0x4a71, 0x245: 0x9936, + 0x246: 0x8132, 0x247: 0x812d, 0x248: 0x812d, 0x249: 0x812d, 0x24a: 0x8132, 0x24b: 0x8132, + 0x24c: 0x8132, 0x24d: 0x812d, 0x24e: 0x812d, 0x250: 0x8132, 0x251: 0x8132, + 0x252: 0x8132, 0x253: 0x812d, 0x254: 0x812d, 0x255: 0x812d, 0x256: 0x812d, 0x257: 0x8132, + 0x258: 0x8133, 0x259: 0x812d, 0x25a: 0x812d, 0x25b: 0x8132, 0x25c: 0x8134, 0x25d: 0x8135, + 0x25e: 0x8135, 0x25f: 0x8134, 0x260: 0x8135, 0x261: 0x8135, 0x262: 0x8134, 0x263: 0x8132, + 0x264: 0x8132, 0x265: 0x8132, 0x266: 0x8132, 0x267: 0x8132, 0x268: 0x8132, 0x269: 0x8132, + 0x26a: 0x8132, 0x26b: 0x8132, 0x26c: 0x8132, 0x26d: 0x8132, 0x26e: 0x8132, 0x26f: 0x8132, + 0x274: 0x0170, + 0x27a: 0x8100, + 0x27e: 0x0037, + // Block 0xa, offset 0x280 + 0x284: 0x8100, 0x285: 0x35a1, + 0x286: 0x35e9, 0x287: 0x00ce, 0x288: 0x3607, 0x289: 0x3613, 0x28a: 0x3625, + 0x28c: 0x3643, 0x28e: 0x3655, 0x28f: 0x3673, 0x290: 0x3e08, 0x291: 0xa000, + 0x295: 0xa000, 0x297: 0xa000, + 0x299: 0xa000, + 0x29f: 0xa000, 0x2a1: 0xa000, + 0x2a5: 0xa000, 0x2a9: 0xa000, + 0x2aa: 0x3637, 0x2ab: 0x3667, 0x2ac: 0x47fe, 0x2ad: 0x3697, 0x2ae: 0x4828, 0x2af: 0x36a9, + 0x2b0: 0x3e70, 0x2b1: 0xa000, 0x2b5: 0xa000, + 0x2b7: 0xa000, 0x2b9: 0xa000, + 0x2bf: 0xa000, + // Block 0xb, offset 0x2c0 + 0x2c0: 0x3721, 0x2c1: 0x372d, 0x2c3: 0x371b, + 0x2c6: 0xa000, 0x2c7: 0x3709, + 0x2cc: 0x375d, 0x2cd: 0x3745, 0x2ce: 0x376f, 0x2d0: 0xa000, + 0x2d3: 0xa000, 0x2d5: 0xa000, 0x2d6: 0xa000, 0x2d7: 0xa000, + 0x2d8: 0xa000, 0x2d9: 0x3751, 0x2da: 0xa000, + 0x2de: 0xa000, 0x2e3: 0xa000, + 0x2e7: 0xa000, + 0x2eb: 0xa000, 0x2ed: 0xa000, + 0x2f0: 0xa000, 0x2f3: 0xa000, 0x2f5: 0xa000, + 0x2f6: 0xa000, 0x2f7: 0xa000, 0x2f8: 0xa000, 0x2f9: 0x37d5, 0x2fa: 0xa000, + 0x2fe: 0xa000, + // Block 0xc, offset 0x300 + 0x301: 0x3733, 0x302: 0x37b7, + 0x310: 0x370f, 0x311: 0x3793, + 0x312: 0x3715, 0x313: 0x3799, 0x316: 0x3727, 0x317: 0x37ab, + 0x318: 0xa000, 0x319: 0xa000, 0x31a: 0x3829, 0x31b: 0x382f, 0x31c: 0x3739, 0x31d: 0x37bd, + 0x31e: 0x373f, 0x31f: 0x37c3, 0x322: 0x374b, 0x323: 0x37cf, + 0x324: 0x3757, 0x325: 0x37db, 0x326: 0x3763, 0x327: 0x37e7, 0x328: 0xa000, 0x329: 0xa000, + 0x32a: 0x3835, 0x32b: 0x383b, 0x32c: 0x378d, 0x32d: 0x3811, 0x32e: 0x3769, 0x32f: 0x37ed, + 0x330: 0x3775, 0x331: 0x37f9, 0x332: 0x377b, 0x333: 0x37ff, 0x334: 0x3781, 0x335: 0x3805, + 0x338: 0x3787, 0x339: 0x380b, + // Block 0xd, offset 0x340 + 0x351: 0x812d, + 0x352: 0x8132, 0x353: 0x8132, 0x354: 0x8132, 0x355: 0x8132, 0x356: 0x812d, 0x357: 0x8132, + 0x358: 0x8132, 0x359: 0x8132, 0x35a: 0x812e, 0x35b: 0x812d, 0x35c: 0x8132, 0x35d: 0x8132, + 0x35e: 0x8132, 0x35f: 0x8132, 0x360: 0x8132, 0x361: 0x8132, 0x362: 0x812d, 0x363: 0x812d, + 0x364: 0x812d, 0x365: 0x812d, 0x366: 0x812d, 0x367: 0x812d, 0x368: 0x8132, 0x369: 0x8132, + 0x36a: 0x812d, 0x36b: 0x8132, 0x36c: 0x8132, 0x36d: 0x812e, 0x36e: 0x8131, 0x36f: 0x8132, + 0x370: 0x8105, 0x371: 0x8106, 0x372: 0x8107, 0x373: 0x8108, 0x374: 0x8109, 0x375: 0x810a, + 0x376: 0x810b, 0x377: 0x810c, 0x378: 0x810d, 0x379: 0x810e, 0x37a: 0x810e, 0x37b: 0x810f, + 0x37c: 0x8110, 0x37d: 0x8111, 0x37f: 0x8112, + // Block 0xe, offset 0x380 + 0x388: 0xa000, 0x38a: 0xa000, 0x38b: 0x8116, + 0x38c: 0x8117, 0x38d: 0x8118, 0x38e: 0x8119, 0x38f: 0x811a, 0x390: 0x811b, 0x391: 0x811c, + 0x392: 0x811d, 0x393: 0x9932, 0x394: 0x9932, 0x395: 0x992d, 0x396: 0x812d, 0x397: 0x8132, + 0x398: 0x8132, 0x399: 0x8132, 0x39a: 0x8132, 0x39b: 0x8132, 0x39c: 0x812d, 0x39d: 0x8132, + 0x39e: 0x8132, 0x39f: 0x812d, + 0x3b0: 0x811e, + // Block 0xf, offset 0x3c0 + 0x3c5: 0xa000, + 0x3c6: 0x2d26, 0x3c7: 0xa000, 0x3c8: 0x2d2e, 0x3c9: 0xa000, 0x3ca: 0x2d36, 0x3cb: 0xa000, + 0x3cc: 0x2d3e, 0x3cd: 0xa000, 0x3ce: 0x2d46, 0x3d1: 0xa000, + 0x3d2: 0x2d4e, + 0x3f4: 0x8102, 0x3f5: 0x9900, + 0x3fa: 0xa000, 0x3fb: 0x2d56, + 0x3fc: 0xa000, 0x3fd: 0x2d5e, 0x3fe: 0xa000, 0x3ff: 0xa000, + // Block 0x10, offset 0x400 + 0x400: 0x8132, 0x401: 0x8132, 0x402: 0x812d, 0x403: 0x8132, 0x404: 0x8132, 0x405: 0x8132, + 0x406: 0x8132, 0x407: 0x8132, 0x408: 0x8132, 0x409: 0x8132, 0x40a: 0x812d, 0x40b: 0x8132, + 0x40c: 0x8132, 0x40d: 0x8135, 0x40e: 0x812a, 0x40f: 0x812d, 0x410: 0x8129, 0x411: 0x8132, + 0x412: 0x8132, 0x413: 0x8132, 0x414: 0x8132, 0x415: 0x8132, 0x416: 0x8132, 0x417: 0x8132, + 0x418: 0x8132, 0x419: 0x8132, 0x41a: 0x8132, 0x41b: 0x8132, 0x41c: 0x8132, 0x41d: 0x8132, + 0x41e: 0x8132, 0x41f: 0x8132, 0x420: 0x8132, 0x421: 0x8132, 0x422: 0x8132, 0x423: 0x8132, + 0x424: 0x8132, 0x425: 0x8132, 0x426: 0x8132, 0x427: 0x8132, 0x428: 0x8132, 0x429: 0x8132, + 0x42a: 0x8132, 0x42b: 0x8132, 0x42c: 0x8132, 0x42d: 0x8132, 0x42e: 0x8132, 0x42f: 0x8132, + 0x430: 0x8132, 0x431: 0x8132, 0x432: 0x8132, 0x433: 0x8132, 0x434: 0x8132, 0x435: 0x8132, + 0x436: 0x8133, 0x437: 0x8131, 0x438: 0x8131, 0x439: 0x812d, 0x43b: 0x8132, + 0x43c: 0x8134, 0x43d: 0x812d, 0x43e: 0x8132, 0x43f: 0x812d, + // Block 0x11, offset 0x440 + 0x440: 0x2f97, 0x441: 0x32a3, 0x442: 0x2fa1, 0x443: 0x32ad, 0x444: 0x2fa6, 0x445: 0x32b2, + 0x446: 0x2fab, 0x447: 0x32b7, 0x448: 0x38cc, 0x449: 0x3a5b, 0x44a: 0x2fc4, 0x44b: 0x32d0, + 0x44c: 0x2fce, 0x44d: 0x32da, 0x44e: 0x2fdd, 0x44f: 0x32e9, 0x450: 0x2fd3, 0x451: 0x32df, + 0x452: 0x2fd8, 0x453: 0x32e4, 0x454: 0x38ef, 0x455: 0x3a7e, 0x456: 0x38f6, 0x457: 0x3a85, + 0x458: 0x3019, 0x459: 0x3325, 0x45a: 0x301e, 0x45b: 0x332a, 0x45c: 0x3904, 0x45d: 0x3a93, + 0x45e: 0x3023, 0x45f: 0x332f, 0x460: 0x3032, 0x461: 0x333e, 0x462: 0x3050, 0x463: 0x335c, + 0x464: 0x305f, 0x465: 0x336b, 0x466: 0x3055, 0x467: 0x3361, 0x468: 0x3064, 0x469: 0x3370, + 0x46a: 0x3069, 0x46b: 0x3375, 0x46c: 0x30af, 0x46d: 0x33bb, 0x46e: 0x390b, 0x46f: 0x3a9a, + 0x470: 0x30b9, 0x471: 0x33ca, 0x472: 0x30c3, 0x473: 0x33d4, 0x474: 0x30cd, 0x475: 0x33de, + 0x476: 0x46c4, 0x477: 0x4755, 0x478: 0x3912, 0x479: 0x3aa1, 0x47a: 0x30e6, 0x47b: 0x33f7, + 0x47c: 0x30e1, 0x47d: 0x33f2, 0x47e: 0x30eb, 0x47f: 0x33fc, + // Block 0x12, offset 0x480 + 0x480: 0x30f0, 0x481: 0x3401, 0x482: 0x30f5, 0x483: 0x3406, 0x484: 0x3109, 0x485: 0x341a, + 0x486: 0x3113, 0x487: 0x3424, 0x488: 0x3122, 0x489: 0x3433, 0x48a: 0x311d, 0x48b: 0x342e, + 0x48c: 0x3935, 0x48d: 0x3ac4, 0x48e: 0x3943, 0x48f: 0x3ad2, 0x490: 0x394a, 0x491: 0x3ad9, + 0x492: 0x3951, 0x493: 0x3ae0, 0x494: 0x314f, 0x495: 0x3460, 0x496: 0x3154, 0x497: 0x3465, + 0x498: 0x315e, 0x499: 0x346f, 0x49a: 0x46f1, 0x49b: 0x4782, 0x49c: 0x3997, 0x49d: 0x3b26, + 0x49e: 0x3177, 0x49f: 0x3488, 0x4a0: 0x3181, 0x4a1: 0x3492, 0x4a2: 0x4700, 0x4a3: 0x4791, + 0x4a4: 0x399e, 0x4a5: 0x3b2d, 0x4a6: 0x39a5, 0x4a7: 0x3b34, 0x4a8: 0x39ac, 0x4a9: 0x3b3b, + 0x4aa: 0x3190, 0x4ab: 0x34a1, 0x4ac: 0x319a, 0x4ad: 0x34b0, 0x4ae: 0x31ae, 0x4af: 0x34c4, + 0x4b0: 0x31a9, 0x4b1: 0x34bf, 0x4b2: 0x31ea, 0x4b3: 0x3500, 0x4b4: 0x31f9, 0x4b5: 0x350f, + 0x4b6: 0x31f4, 0x4b7: 0x350a, 0x4b8: 0x39b3, 0x4b9: 0x3b42, 0x4ba: 0x39ba, 0x4bb: 0x3b49, + 0x4bc: 0x31fe, 0x4bd: 0x3514, 0x4be: 0x3203, 0x4bf: 0x3519, + // Block 0x13, offset 0x4c0 + 0x4c0: 0x3208, 0x4c1: 0x351e, 0x4c2: 0x320d, 0x4c3: 0x3523, 0x4c4: 0x321c, 0x4c5: 0x3532, + 0x4c6: 0x3217, 0x4c7: 0x352d, 0x4c8: 0x3221, 0x4c9: 0x353c, 0x4ca: 0x3226, 0x4cb: 0x3541, + 0x4cc: 0x322b, 0x4cd: 0x3546, 0x4ce: 0x3249, 0x4cf: 0x3564, 0x4d0: 0x3262, 0x4d1: 0x3582, + 0x4d2: 0x3271, 0x4d3: 0x3591, 0x4d4: 0x3276, 0x4d5: 0x3596, 0x4d6: 0x337a, 0x4d7: 0x34a6, + 0x4d8: 0x3537, 0x4d9: 0x3573, 0x4db: 0x35d1, + 0x4e0: 0x46a1, 0x4e1: 0x4732, 0x4e2: 0x2f83, 0x4e3: 0x328f, + 0x4e4: 0x3878, 0x4e5: 0x3a07, 0x4e6: 0x3871, 0x4e7: 0x3a00, 0x4e8: 0x3886, 0x4e9: 0x3a15, + 0x4ea: 0x387f, 0x4eb: 0x3a0e, 0x4ec: 0x38be, 0x4ed: 0x3a4d, 0x4ee: 0x3894, 0x4ef: 0x3a23, + 0x4f0: 0x388d, 0x4f1: 0x3a1c, 0x4f2: 0x38a2, 0x4f3: 0x3a31, 0x4f4: 0x389b, 0x4f5: 0x3a2a, + 0x4f6: 0x38c5, 0x4f7: 0x3a54, 0x4f8: 0x46b5, 0x4f9: 0x4746, 0x4fa: 0x3000, 0x4fb: 0x330c, + 0x4fc: 0x2fec, 0x4fd: 0x32f8, 0x4fe: 0x38da, 0x4ff: 0x3a69, + // Block 0x14, offset 0x500 + 0x500: 0x38d3, 0x501: 0x3a62, 0x502: 0x38e8, 0x503: 0x3a77, 0x504: 0x38e1, 0x505: 0x3a70, + 0x506: 0x38fd, 0x507: 0x3a8c, 0x508: 0x3091, 0x509: 0x339d, 0x50a: 0x30a5, 0x50b: 0x33b1, + 0x50c: 0x46e7, 0x50d: 0x4778, 0x50e: 0x3136, 0x50f: 0x3447, 0x510: 0x3920, 0x511: 0x3aaf, + 0x512: 0x3919, 0x513: 0x3aa8, 0x514: 0x392e, 0x515: 0x3abd, 0x516: 0x3927, 0x517: 0x3ab6, + 0x518: 0x3989, 0x519: 0x3b18, 0x51a: 0x396d, 0x51b: 0x3afc, 0x51c: 0x3966, 0x51d: 0x3af5, + 0x51e: 0x397b, 0x51f: 0x3b0a, 0x520: 0x3974, 0x521: 0x3b03, 0x522: 0x3982, 0x523: 0x3b11, + 0x524: 0x31e5, 0x525: 0x34fb, 0x526: 0x31c7, 0x527: 0x34dd, 0x528: 0x39e4, 0x529: 0x3b73, + 0x52a: 0x39dd, 0x52b: 0x3b6c, 0x52c: 0x39f2, 0x52d: 0x3b81, 0x52e: 0x39eb, 0x52f: 0x3b7a, + 0x530: 0x39f9, 0x531: 0x3b88, 0x532: 0x3230, 0x533: 0x354b, 0x534: 0x3258, 0x535: 0x3578, + 0x536: 0x3253, 0x537: 0x356e, 0x538: 0x323f, 0x539: 0x355a, + // Block 0x15, offset 0x540 + 0x540: 0x4804, 0x541: 0x480a, 0x542: 0x491e, 0x543: 0x4936, 0x544: 0x4926, 0x545: 0x493e, + 0x546: 0x492e, 0x547: 0x4946, 0x548: 0x47aa, 0x549: 0x47b0, 0x54a: 0x488e, 0x54b: 0x48a6, + 0x54c: 0x4896, 0x54d: 0x48ae, 0x54e: 0x489e, 0x54f: 0x48b6, 0x550: 0x4816, 0x551: 0x481c, + 0x552: 0x3db8, 0x553: 0x3dc8, 0x554: 0x3dc0, 0x555: 0x3dd0, + 0x558: 0x47b6, 0x559: 0x47bc, 0x55a: 0x3ce8, 0x55b: 0x3cf8, 0x55c: 0x3cf0, 0x55d: 0x3d00, + 0x560: 0x482e, 0x561: 0x4834, 0x562: 0x494e, 0x563: 0x4966, + 0x564: 0x4956, 0x565: 0x496e, 0x566: 0x495e, 0x567: 0x4976, 0x568: 0x47c2, 0x569: 0x47c8, + 0x56a: 0x48be, 0x56b: 0x48d6, 0x56c: 0x48c6, 0x56d: 0x48de, 0x56e: 0x48ce, 0x56f: 0x48e6, + 0x570: 0x4846, 0x571: 0x484c, 0x572: 0x3e18, 0x573: 0x3e30, 0x574: 0x3e20, 0x575: 0x3e38, + 0x576: 0x3e28, 0x577: 0x3e40, 0x578: 0x47ce, 0x579: 0x47d4, 0x57a: 0x3d18, 0x57b: 0x3d30, + 0x57c: 0x3d20, 0x57d: 0x3d38, 0x57e: 0x3d28, 0x57f: 0x3d40, + // Block 0x16, offset 0x580 + 0x580: 0x4852, 0x581: 0x4858, 0x582: 0x3e48, 0x583: 0x3e58, 0x584: 0x3e50, 0x585: 0x3e60, + 0x588: 0x47da, 0x589: 0x47e0, 0x58a: 0x3d48, 0x58b: 0x3d58, + 0x58c: 0x3d50, 0x58d: 0x3d60, 0x590: 0x4864, 0x591: 0x486a, + 0x592: 0x3e80, 0x593: 0x3e98, 0x594: 0x3e88, 0x595: 0x3ea0, 0x596: 0x3e90, 0x597: 0x3ea8, + 0x599: 0x47e6, 0x59b: 0x3d68, 0x59d: 0x3d70, + 0x59f: 0x3d78, 0x5a0: 0x487c, 0x5a1: 0x4882, 0x5a2: 0x497e, 0x5a3: 0x4996, + 0x5a4: 0x4986, 0x5a5: 0x499e, 0x5a6: 0x498e, 0x5a7: 0x49a6, 0x5a8: 0x47ec, 0x5a9: 0x47f2, + 0x5aa: 0x48ee, 0x5ab: 0x4906, 0x5ac: 0x48f6, 0x5ad: 0x490e, 0x5ae: 0x48fe, 0x5af: 0x4916, + 0x5b0: 0x47f8, 0x5b1: 0x431e, 0x5b2: 0x3691, 0x5b3: 0x4324, 0x5b4: 0x4822, 0x5b5: 0x432a, + 0x5b6: 0x36a3, 0x5b7: 0x4330, 0x5b8: 0x36c1, 0x5b9: 0x4336, 0x5ba: 0x36d9, 0x5bb: 0x433c, + 0x5bc: 0x4870, 0x5bd: 0x4342, + // Block 0x17, offset 0x5c0 + 0x5c0: 0x3da0, 0x5c1: 0x3da8, 0x5c2: 0x4184, 0x5c3: 0x41a2, 0x5c4: 0x418e, 0x5c5: 0x41ac, + 0x5c6: 0x4198, 0x5c7: 0x41b6, 0x5c8: 0x3cd8, 0x5c9: 0x3ce0, 0x5ca: 0x40d0, 0x5cb: 0x40ee, + 0x5cc: 0x40da, 0x5cd: 0x40f8, 0x5ce: 0x40e4, 0x5cf: 0x4102, 0x5d0: 0x3de8, 0x5d1: 0x3df0, + 0x5d2: 0x41c0, 0x5d3: 0x41de, 0x5d4: 0x41ca, 0x5d5: 0x41e8, 0x5d6: 0x41d4, 0x5d7: 0x41f2, + 0x5d8: 0x3d08, 0x5d9: 0x3d10, 0x5da: 0x410c, 0x5db: 0x412a, 0x5dc: 0x4116, 0x5dd: 0x4134, + 0x5de: 0x4120, 0x5df: 0x413e, 0x5e0: 0x3ec0, 0x5e1: 0x3ec8, 0x5e2: 0x41fc, 0x5e3: 0x421a, + 0x5e4: 0x4206, 0x5e5: 0x4224, 0x5e6: 0x4210, 0x5e7: 0x422e, 0x5e8: 0x3d80, 0x5e9: 0x3d88, + 0x5ea: 0x4148, 0x5eb: 0x4166, 0x5ec: 0x4152, 0x5ed: 0x4170, 0x5ee: 0x415c, 0x5ef: 0x417a, + 0x5f0: 0x3685, 0x5f1: 0x367f, 0x5f2: 0x3d90, 0x5f3: 0x368b, 0x5f4: 0x3d98, + 0x5f6: 0x4810, 0x5f7: 0x3db0, 0x5f8: 0x35f5, 0x5f9: 0x35ef, 0x5fa: 0x35e3, 0x5fb: 0x42ee, + 0x5fc: 0x35fb, 0x5fd: 0x8100, 0x5fe: 0x01d3, 0x5ff: 0xa100, + // Block 0x18, offset 0x600 + 0x600: 0x8100, 0x601: 0x35a7, 0x602: 0x3dd8, 0x603: 0x369d, 0x604: 0x3de0, + 0x606: 0x483a, 0x607: 0x3df8, 0x608: 0x3601, 0x609: 0x42f4, 0x60a: 0x360d, 0x60b: 0x42fa, + 0x60c: 0x3619, 0x60d: 0x3b8f, 0x60e: 0x3b96, 0x60f: 0x3b9d, 0x610: 0x36b5, 0x611: 0x36af, + 0x612: 0x3e00, 0x613: 0x44e4, 0x616: 0x36bb, 0x617: 0x3e10, + 0x618: 0x3631, 0x619: 0x362b, 0x61a: 0x361f, 0x61b: 0x4300, 0x61d: 0x3ba4, + 0x61e: 0x3bab, 0x61f: 0x3bb2, 0x620: 0x36eb, 0x621: 0x36e5, 0x622: 0x3e68, 0x623: 0x44ec, + 0x624: 0x36cd, 0x625: 0x36d3, 0x626: 0x36f1, 0x627: 0x3e78, 0x628: 0x3661, 0x629: 0x365b, + 0x62a: 0x364f, 0x62b: 0x430c, 0x62c: 0x3649, 0x62d: 0x359b, 0x62e: 0x42e8, 0x62f: 0x0081, + 0x632: 0x3eb0, 0x633: 0x36f7, 0x634: 0x3eb8, + 0x636: 0x4888, 0x637: 0x3ed0, 0x638: 0x363d, 0x639: 0x4306, 0x63a: 0x366d, 0x63b: 0x4318, + 0x63c: 0x3679, 0x63d: 0x4256, 0x63e: 0xa100, + // Block 0x19, offset 0x640 + 0x641: 0x3c06, 0x643: 0xa000, 0x644: 0x3c0d, 0x645: 0xa000, + 0x647: 0x3c14, 0x648: 0xa000, 0x649: 0x3c1b, + 0x64d: 0xa000, + 0x660: 0x2f65, 0x661: 0xa000, 0x662: 0x3c29, + 0x664: 0xa000, 0x665: 0xa000, + 0x66d: 0x3c22, 0x66e: 0x2f60, 0x66f: 0x2f6a, + 0x670: 0x3c30, 0x671: 0x3c37, 0x672: 0xa000, 0x673: 0xa000, 0x674: 0x3c3e, 0x675: 0x3c45, + 0x676: 0xa000, 0x677: 0xa000, 0x678: 0x3c4c, 0x679: 0x3c53, 0x67a: 0xa000, 0x67b: 0xa000, + 0x67c: 0xa000, 0x67d: 0xa000, + // Block 0x1a, offset 0x680 + 0x680: 0x3c5a, 0x681: 0x3c61, 0x682: 0xa000, 0x683: 0xa000, 0x684: 0x3c76, 0x685: 0x3c7d, + 0x686: 0xa000, 0x687: 0xa000, 0x688: 0x3c84, 0x689: 0x3c8b, + 0x691: 0xa000, + 0x692: 0xa000, + 0x6a2: 0xa000, + 0x6a8: 0xa000, 0x6a9: 0xa000, + 0x6ab: 0xa000, 0x6ac: 0x3ca0, 0x6ad: 0x3ca7, 0x6ae: 0x3cae, 0x6af: 0x3cb5, + 0x6b2: 0xa000, 0x6b3: 0xa000, 0x6b4: 0xa000, 0x6b5: 0xa000, + // Block 0x1b, offset 0x6c0 + 0x6c6: 0xa000, 0x6cb: 0xa000, + 0x6cc: 0x3f08, 0x6cd: 0xa000, 0x6ce: 0x3f10, 0x6cf: 0xa000, 0x6d0: 0x3f18, 0x6d1: 0xa000, + 0x6d2: 0x3f20, 0x6d3: 0xa000, 0x6d4: 0x3f28, 0x6d5: 0xa000, 0x6d6: 0x3f30, 0x6d7: 0xa000, + 0x6d8: 0x3f38, 0x6d9: 0xa000, 0x6da: 0x3f40, 0x6db: 0xa000, 0x6dc: 0x3f48, 0x6dd: 0xa000, + 0x6de: 0x3f50, 0x6df: 0xa000, 0x6e0: 0x3f58, 0x6e1: 0xa000, 0x6e2: 0x3f60, + 0x6e4: 0xa000, 0x6e5: 0x3f68, 0x6e6: 0xa000, 0x6e7: 0x3f70, 0x6e8: 0xa000, 0x6e9: 0x3f78, + 0x6ef: 0xa000, + 0x6f0: 0x3f80, 0x6f1: 0x3f88, 0x6f2: 0xa000, 0x6f3: 0x3f90, 0x6f4: 0x3f98, 0x6f5: 0xa000, + 0x6f6: 0x3fa0, 0x6f7: 0x3fa8, 0x6f8: 0xa000, 0x6f9: 0x3fb0, 0x6fa: 0x3fb8, 0x6fb: 0xa000, + 0x6fc: 0x3fc0, 0x6fd: 0x3fc8, + // Block 0x1c, offset 0x700 + 0x714: 0x3f00, + 0x719: 0x9903, 0x71a: 0x9903, 0x71b: 0x8100, 0x71c: 0x8100, 0x71d: 0xa000, + 0x71e: 0x3fd0, + 0x726: 0xa000, + 0x72b: 0xa000, 0x72c: 0x3fe0, 0x72d: 0xa000, 0x72e: 0x3fe8, 0x72f: 0xa000, + 0x730: 0x3ff0, 0x731: 0xa000, 0x732: 0x3ff8, 0x733: 0xa000, 0x734: 0x4000, 0x735: 0xa000, + 0x736: 0x4008, 0x737: 0xa000, 0x738: 0x4010, 0x739: 0xa000, 0x73a: 0x4018, 0x73b: 0xa000, + 0x73c: 0x4020, 0x73d: 0xa000, 0x73e: 0x4028, 0x73f: 0xa000, + // Block 0x1d, offset 0x740 + 0x740: 0x4030, 0x741: 0xa000, 0x742: 0x4038, 0x744: 0xa000, 0x745: 0x4040, + 0x746: 0xa000, 0x747: 0x4048, 0x748: 0xa000, 0x749: 0x4050, + 0x74f: 0xa000, 0x750: 0x4058, 0x751: 0x4060, + 0x752: 0xa000, 0x753: 0x4068, 0x754: 0x4070, 0x755: 0xa000, 0x756: 0x4078, 0x757: 0x4080, + 0x758: 0xa000, 0x759: 0x4088, 0x75a: 0x4090, 0x75b: 0xa000, 0x75c: 0x4098, 0x75d: 0x40a0, + 0x76f: 0xa000, + 0x770: 0xa000, 0x771: 0xa000, 0x772: 0xa000, 0x774: 0x3fd8, + 0x777: 0x40a8, 0x778: 0x40b0, 0x779: 0x40b8, 0x77a: 0x40c0, + 0x77d: 0xa000, 0x77e: 0x40c8, + // Block 0x1e, offset 0x780 + 0x780: 0x1377, 0x781: 0x0cfb, 0x782: 0x13d3, 0x783: 0x139f, 0x784: 0x0e57, 0x785: 0x06eb, + 0x786: 0x08df, 0x787: 0x162b, 0x788: 0x162b, 0x789: 0x0a0b, 0x78a: 0x145f, 0x78b: 0x0943, + 0x78c: 0x0a07, 0x78d: 0x0bef, 0x78e: 0x0fcf, 0x78f: 0x115f, 0x790: 0x1297, 0x791: 0x12d3, + 0x792: 0x1307, 0x793: 0x141b, 0x794: 0x0d73, 0x795: 0x0dff, 0x796: 0x0eab, 0x797: 0x0f43, + 0x798: 0x125f, 0x799: 0x1447, 0x79a: 0x1573, 0x79b: 0x070f, 0x79c: 0x08b3, 0x79d: 0x0d87, + 0x79e: 0x0ecf, 0x79f: 0x1293, 0x7a0: 0x15c3, 0x7a1: 0x0ab3, 0x7a2: 0x0e77, 0x7a3: 0x1283, + 0x7a4: 0x1317, 0x7a5: 0x0c23, 0x7a6: 0x11bb, 0x7a7: 0x12df, 0x7a8: 0x0b1f, 0x7a9: 0x0d0f, + 0x7aa: 0x0e17, 0x7ab: 0x0f1b, 0x7ac: 0x1427, 0x7ad: 0x074f, 0x7ae: 0x07e7, 0x7af: 0x0853, + 0x7b0: 0x0c8b, 0x7b1: 0x0d7f, 0x7b2: 0x0ecb, 0x7b3: 0x0fef, 0x7b4: 0x1177, 0x7b5: 0x128b, + 0x7b6: 0x12a3, 0x7b7: 0x13c7, 0x7b8: 0x14ef, 0x7b9: 0x15a3, 0x7ba: 0x15bf, 0x7bb: 0x102b, + 0x7bc: 0x106b, 0x7bd: 0x1123, 0x7be: 0x1243, 0x7bf: 0x147b, + // Block 0x1f, offset 0x7c0 + 0x7c0: 0x15cb, 0x7c1: 0x134b, 0x7c2: 0x09c7, 0x7c3: 0x0b3b, 0x7c4: 0x10db, 0x7c5: 0x119b, + 0x7c6: 0x0eff, 0x7c7: 0x1033, 0x7c8: 0x1397, 0x7c9: 0x14e7, 0x7ca: 0x09c3, 0x7cb: 0x0a8f, + 0x7cc: 0x0d77, 0x7cd: 0x0e2b, 0x7ce: 0x0e5f, 0x7cf: 0x1113, 0x7d0: 0x113b, 0x7d1: 0x14a7, + 0x7d2: 0x084f, 0x7d3: 0x11a7, 0x7d4: 0x07f3, 0x7d5: 0x07ef, 0x7d6: 0x1097, 0x7d7: 0x1127, + 0x7d8: 0x125b, 0x7d9: 0x14af, 0x7da: 0x1367, 0x7db: 0x0c27, 0x7dc: 0x0d73, 0x7dd: 0x1357, + 0x7de: 0x06f7, 0x7df: 0x0a63, 0x7e0: 0x0b93, 0x7e1: 0x0f2f, 0x7e2: 0x0faf, 0x7e3: 0x0873, + 0x7e4: 0x103b, 0x7e5: 0x075f, 0x7e6: 0x0b77, 0x7e7: 0x06d7, 0x7e8: 0x0deb, 0x7e9: 0x0ca3, + 0x7ea: 0x110f, 0x7eb: 0x08c7, 0x7ec: 0x09b3, 0x7ed: 0x0ffb, 0x7ee: 0x1263, 0x7ef: 0x133b, + 0x7f0: 0x0db7, 0x7f1: 0x13f7, 0x7f2: 0x0de3, 0x7f3: 0x0c37, 0x7f4: 0x121b, 0x7f5: 0x0c57, + 0x7f6: 0x0fab, 0x7f7: 0x072b, 0x7f8: 0x07a7, 0x7f9: 0x07eb, 0x7fa: 0x0d53, 0x7fb: 0x10fb, + 0x7fc: 0x11f3, 0x7fd: 0x1347, 0x7fe: 0x145b, 0x7ff: 0x085b, + // Block 0x20, offset 0x800 + 0x800: 0x090f, 0x801: 0x0a17, 0x802: 0x0b2f, 0x803: 0x0cbf, 0x804: 0x0e7b, 0x805: 0x103f, + 0x806: 0x1497, 0x807: 0x157b, 0x808: 0x15cf, 0x809: 0x15e7, 0x80a: 0x0837, 0x80b: 0x0cf3, + 0x80c: 0x0da3, 0x80d: 0x13eb, 0x80e: 0x0afb, 0x80f: 0x0bd7, 0x810: 0x0bf3, 0x811: 0x0c83, + 0x812: 0x0e6b, 0x813: 0x0eb7, 0x814: 0x0f67, 0x815: 0x108b, 0x816: 0x112f, 0x817: 0x1193, + 0x818: 0x13db, 0x819: 0x126b, 0x81a: 0x1403, 0x81b: 0x147f, 0x81c: 0x080f, 0x81d: 0x083b, + 0x81e: 0x0923, 0x81f: 0x0ea7, 0x820: 0x12f3, 0x821: 0x133b, 0x822: 0x0b1b, 0x823: 0x0b8b, + 0x824: 0x0c4f, 0x825: 0x0daf, 0x826: 0x10d7, 0x827: 0x0f23, 0x828: 0x073b, 0x829: 0x097f, + 0x82a: 0x0a63, 0x82b: 0x0ac7, 0x82c: 0x0b97, 0x82d: 0x0f3f, 0x82e: 0x0f5b, 0x82f: 0x116b, + 0x830: 0x118b, 0x831: 0x1463, 0x832: 0x14e3, 0x833: 0x14f3, 0x834: 0x152f, 0x835: 0x0753, + 0x836: 0x107f, 0x837: 0x144f, 0x838: 0x14cb, 0x839: 0x0baf, 0x83a: 0x0717, 0x83b: 0x0777, + 0x83c: 0x0a67, 0x83d: 0x0a87, 0x83e: 0x0caf, 0x83f: 0x0d73, + // Block 0x21, offset 0x840 + 0x840: 0x0ec3, 0x841: 0x0fcb, 0x842: 0x1277, 0x843: 0x1417, 0x844: 0x1623, 0x845: 0x0ce3, + 0x846: 0x14a3, 0x847: 0x0833, 0x848: 0x0d2f, 0x849: 0x0d3b, 0x84a: 0x0e0f, 0x84b: 0x0e47, + 0x84c: 0x0f4b, 0x84d: 0x0fa7, 0x84e: 0x1027, 0x84f: 0x110b, 0x850: 0x153b, 0x851: 0x07af, + 0x852: 0x0c03, 0x853: 0x14b3, 0x854: 0x0767, 0x855: 0x0aab, 0x856: 0x0e2f, 0x857: 0x13df, + 0x858: 0x0b67, 0x859: 0x0bb7, 0x85a: 0x0d43, 0x85b: 0x0f2f, 0x85c: 0x14bb, 0x85d: 0x0817, + 0x85e: 0x08ff, 0x85f: 0x0a97, 0x860: 0x0cd3, 0x861: 0x0d1f, 0x862: 0x0d5f, 0x863: 0x0df3, + 0x864: 0x0f47, 0x865: 0x0fbb, 0x866: 0x1157, 0x867: 0x12f7, 0x868: 0x1303, 0x869: 0x1457, + 0x86a: 0x14d7, 0x86b: 0x0883, 0x86c: 0x0e4b, 0x86d: 0x0903, 0x86e: 0x0ec7, 0x86f: 0x0f6b, + 0x870: 0x1287, 0x871: 0x14bf, 0x872: 0x15ab, 0x873: 0x15d3, 0x874: 0x0d37, 0x875: 0x0e27, + 0x876: 0x11c3, 0x877: 0x10b7, 0x878: 0x10c3, 0x879: 0x10e7, 0x87a: 0x0f17, 0x87b: 0x0e9f, + 0x87c: 0x1363, 0x87d: 0x0733, 0x87e: 0x122b, 0x87f: 0x081b, + // Block 0x22, offset 0x880 + 0x880: 0x080b, 0x881: 0x0b0b, 0x882: 0x0c2b, 0x883: 0x10f3, 0x884: 0x0a53, 0x885: 0x0e03, + 0x886: 0x0cef, 0x887: 0x13e7, 0x888: 0x12e7, 0x889: 0x14ab, 0x88a: 0x1323, 0x88b: 0x0b27, + 0x88c: 0x0787, 0x88d: 0x095b, 0x890: 0x09af, + 0x892: 0x0cdf, 0x895: 0x07f7, 0x896: 0x0f1f, 0x897: 0x0fe3, + 0x898: 0x1047, 0x899: 0x1063, 0x89a: 0x1067, 0x89b: 0x107b, 0x89c: 0x14fb, 0x89d: 0x10eb, + 0x89e: 0x116f, 0x8a0: 0x128f, 0x8a2: 0x1353, + 0x8a5: 0x1407, 0x8a6: 0x1433, + 0x8aa: 0x154f, 0x8ab: 0x1553, 0x8ac: 0x1557, 0x8ad: 0x15bb, 0x8ae: 0x142b, 0x8af: 0x14c7, + 0x8b0: 0x0757, 0x8b1: 0x077b, 0x8b2: 0x078f, 0x8b3: 0x084b, 0x8b4: 0x0857, 0x8b5: 0x0897, + 0x8b6: 0x094b, 0x8b7: 0x0967, 0x8b8: 0x096f, 0x8b9: 0x09ab, 0x8ba: 0x09b7, 0x8bb: 0x0a93, + 0x8bc: 0x0a9b, 0x8bd: 0x0ba3, 0x8be: 0x0bcb, 0x8bf: 0x0bd3, + // Block 0x23, offset 0x8c0 + 0x8c0: 0x0beb, 0x8c1: 0x0c97, 0x8c2: 0x0cc7, 0x8c3: 0x0ce7, 0x8c4: 0x0d57, 0x8c5: 0x0e1b, + 0x8c6: 0x0e37, 0x8c7: 0x0e67, 0x8c8: 0x0ebb, 0x8c9: 0x0edb, 0x8ca: 0x0f4f, 0x8cb: 0x102f, + 0x8cc: 0x104b, 0x8cd: 0x1053, 0x8ce: 0x104f, 0x8cf: 0x1057, 0x8d0: 0x105b, 0x8d1: 0x105f, + 0x8d2: 0x1073, 0x8d3: 0x1077, 0x8d4: 0x109b, 0x8d5: 0x10af, 0x8d6: 0x10cb, 0x8d7: 0x112f, + 0x8d8: 0x1137, 0x8d9: 0x113f, 0x8da: 0x1153, 0x8db: 0x117b, 0x8dc: 0x11cb, 0x8dd: 0x11ff, + 0x8de: 0x11ff, 0x8df: 0x1267, 0x8e0: 0x130f, 0x8e1: 0x1327, 0x8e2: 0x135b, 0x8e3: 0x135f, + 0x8e4: 0x13a3, 0x8e5: 0x13a7, 0x8e6: 0x13ff, 0x8e7: 0x1407, 0x8e8: 0x14db, 0x8e9: 0x151f, + 0x8ea: 0x1537, 0x8eb: 0x0b9b, 0x8ec: 0x171e, 0x8ed: 0x11e3, + 0x8f0: 0x06df, 0x8f1: 0x07e3, 0x8f2: 0x07a3, 0x8f3: 0x074b, 0x8f4: 0x078b, 0x8f5: 0x07b7, + 0x8f6: 0x0847, 0x8f7: 0x0863, 0x8f8: 0x094b, 0x8f9: 0x0937, 0x8fa: 0x0947, 0x8fb: 0x0963, + 0x8fc: 0x09af, 0x8fd: 0x09bf, 0x8fe: 0x0a03, 0x8ff: 0x0a0f, + // Block 0x24, offset 0x900 + 0x900: 0x0a2b, 0x901: 0x0a3b, 0x902: 0x0b23, 0x903: 0x0b2b, 0x904: 0x0b5b, 0x905: 0x0b7b, + 0x906: 0x0bab, 0x907: 0x0bc3, 0x908: 0x0bb3, 0x909: 0x0bd3, 0x90a: 0x0bc7, 0x90b: 0x0beb, + 0x90c: 0x0c07, 0x90d: 0x0c5f, 0x90e: 0x0c6b, 0x90f: 0x0c73, 0x910: 0x0c9b, 0x911: 0x0cdf, + 0x912: 0x0d0f, 0x913: 0x0d13, 0x914: 0x0d27, 0x915: 0x0da7, 0x916: 0x0db7, 0x917: 0x0e0f, + 0x918: 0x0e5b, 0x919: 0x0e53, 0x91a: 0x0e67, 0x91b: 0x0e83, 0x91c: 0x0ebb, 0x91d: 0x1013, + 0x91e: 0x0edf, 0x91f: 0x0f13, 0x920: 0x0f1f, 0x921: 0x0f5f, 0x922: 0x0f7b, 0x923: 0x0f9f, + 0x924: 0x0fc3, 0x925: 0x0fc7, 0x926: 0x0fe3, 0x927: 0x0fe7, 0x928: 0x0ff7, 0x929: 0x100b, + 0x92a: 0x1007, 0x92b: 0x1037, 0x92c: 0x10b3, 0x92d: 0x10cb, 0x92e: 0x10e3, 0x92f: 0x111b, + 0x930: 0x112f, 0x931: 0x114b, 0x932: 0x117b, 0x933: 0x122f, 0x934: 0x1257, 0x935: 0x12cb, + 0x936: 0x1313, 0x937: 0x131f, 0x938: 0x1327, 0x939: 0x133f, 0x93a: 0x1353, 0x93b: 0x1343, + 0x93c: 0x135b, 0x93d: 0x1357, 0x93e: 0x134f, 0x93f: 0x135f, + // Block 0x25, offset 0x940 + 0x940: 0x136b, 0x941: 0x13a7, 0x942: 0x13e3, 0x943: 0x1413, 0x944: 0x144b, 0x945: 0x146b, + 0x946: 0x14b7, 0x947: 0x14db, 0x948: 0x14fb, 0x949: 0x150f, 0x94a: 0x151f, 0x94b: 0x152b, + 0x94c: 0x1537, 0x94d: 0x158b, 0x94e: 0x162b, 0x94f: 0x16b5, 0x950: 0x16b0, 0x951: 0x16e2, + 0x952: 0x0607, 0x953: 0x062f, 0x954: 0x0633, 0x955: 0x1764, 0x956: 0x1791, 0x957: 0x1809, + 0x958: 0x1617, 0x959: 0x1627, + // Block 0x26, offset 0x980 + 0x980: 0x06fb, 0x981: 0x06f3, 0x982: 0x0703, 0x983: 0x1647, 0x984: 0x0747, 0x985: 0x0757, + 0x986: 0x075b, 0x987: 0x0763, 0x988: 0x076b, 0x989: 0x076f, 0x98a: 0x077b, 0x98b: 0x0773, + 0x98c: 0x05b3, 0x98d: 0x165b, 0x98e: 0x078f, 0x98f: 0x0793, 0x990: 0x0797, 0x991: 0x07b3, + 0x992: 0x164c, 0x993: 0x05b7, 0x994: 0x079f, 0x995: 0x07bf, 0x996: 0x1656, 0x997: 0x07cf, + 0x998: 0x07d7, 0x999: 0x0737, 0x99a: 0x07df, 0x99b: 0x07e3, 0x99c: 0x1831, 0x99d: 0x07ff, + 0x99e: 0x0807, 0x99f: 0x05bf, 0x9a0: 0x081f, 0x9a1: 0x0823, 0x9a2: 0x082b, 0x9a3: 0x082f, + 0x9a4: 0x05c3, 0x9a5: 0x0847, 0x9a6: 0x084b, 0x9a7: 0x0857, 0x9a8: 0x0863, 0x9a9: 0x0867, + 0x9aa: 0x086b, 0x9ab: 0x0873, 0x9ac: 0x0893, 0x9ad: 0x0897, 0x9ae: 0x089f, 0x9af: 0x08af, + 0x9b0: 0x08b7, 0x9b1: 0x08bb, 0x9b2: 0x08bb, 0x9b3: 0x08bb, 0x9b4: 0x166a, 0x9b5: 0x0e93, + 0x9b6: 0x08cf, 0x9b7: 0x08d7, 0x9b8: 0x166f, 0x9b9: 0x08e3, 0x9ba: 0x08eb, 0x9bb: 0x08f3, + 0x9bc: 0x091b, 0x9bd: 0x0907, 0x9be: 0x0913, 0x9bf: 0x0917, + // Block 0x27, offset 0x9c0 + 0x9c0: 0x091f, 0x9c1: 0x0927, 0x9c2: 0x092b, 0x9c3: 0x0933, 0x9c4: 0x093b, 0x9c5: 0x093f, + 0x9c6: 0x093f, 0x9c7: 0x0947, 0x9c8: 0x094f, 0x9c9: 0x0953, 0x9ca: 0x095f, 0x9cb: 0x0983, + 0x9cc: 0x0967, 0x9cd: 0x0987, 0x9ce: 0x096b, 0x9cf: 0x0973, 0x9d0: 0x080b, 0x9d1: 0x09cf, + 0x9d2: 0x0997, 0x9d3: 0x099b, 0x9d4: 0x099f, 0x9d5: 0x0993, 0x9d6: 0x09a7, 0x9d7: 0x09a3, + 0x9d8: 0x09bb, 0x9d9: 0x1674, 0x9da: 0x09d7, 0x9db: 0x09db, 0x9dc: 0x09e3, 0x9dd: 0x09ef, + 0x9de: 0x09f7, 0x9df: 0x0a13, 0x9e0: 0x1679, 0x9e1: 0x167e, 0x9e2: 0x0a1f, 0x9e3: 0x0a23, + 0x9e4: 0x0a27, 0x9e5: 0x0a1b, 0x9e6: 0x0a2f, 0x9e7: 0x05c7, 0x9e8: 0x05cb, 0x9e9: 0x0a37, + 0x9ea: 0x0a3f, 0x9eb: 0x0a3f, 0x9ec: 0x1683, 0x9ed: 0x0a5b, 0x9ee: 0x0a5f, 0x9ef: 0x0a63, + 0x9f0: 0x0a6b, 0x9f1: 0x1688, 0x9f2: 0x0a73, 0x9f3: 0x0a77, 0x9f4: 0x0b4f, 0x9f5: 0x0a7f, + 0x9f6: 0x05cf, 0x9f7: 0x0a8b, 0x9f8: 0x0a9b, 0x9f9: 0x0aa7, 0x9fa: 0x0aa3, 0x9fb: 0x1692, + 0x9fc: 0x0aaf, 0x9fd: 0x1697, 0x9fe: 0x0abb, 0x9ff: 0x0ab7, + // Block 0x28, offset 0xa00 + 0xa00: 0x0abf, 0xa01: 0x0acf, 0xa02: 0x0ad3, 0xa03: 0x05d3, 0xa04: 0x0ae3, 0xa05: 0x0aeb, + 0xa06: 0x0aef, 0xa07: 0x0af3, 0xa08: 0x05d7, 0xa09: 0x169c, 0xa0a: 0x05db, 0xa0b: 0x0b0f, + 0xa0c: 0x0b13, 0xa0d: 0x0b17, 0xa0e: 0x0b1f, 0xa0f: 0x1863, 0xa10: 0x0b37, 0xa11: 0x16a6, + 0xa12: 0x16a6, 0xa13: 0x11d7, 0xa14: 0x0b47, 0xa15: 0x0b47, 0xa16: 0x05df, 0xa17: 0x16c9, + 0xa18: 0x179b, 0xa19: 0x0b57, 0xa1a: 0x0b5f, 0xa1b: 0x05e3, 0xa1c: 0x0b73, 0xa1d: 0x0b83, + 0xa1e: 0x0b87, 0xa1f: 0x0b8f, 0xa20: 0x0b9f, 0xa21: 0x05eb, 0xa22: 0x05e7, 0xa23: 0x0ba3, + 0xa24: 0x16ab, 0xa25: 0x0ba7, 0xa26: 0x0bbb, 0xa27: 0x0bbf, 0xa28: 0x0bc3, 0xa29: 0x0bbf, + 0xa2a: 0x0bcf, 0xa2b: 0x0bd3, 0xa2c: 0x0be3, 0xa2d: 0x0bdb, 0xa2e: 0x0bdf, 0xa2f: 0x0be7, + 0xa30: 0x0beb, 0xa31: 0x0bef, 0xa32: 0x0bfb, 0xa33: 0x0bff, 0xa34: 0x0c17, 0xa35: 0x0c1f, + 0xa36: 0x0c2f, 0xa37: 0x0c43, 0xa38: 0x16ba, 0xa39: 0x0c3f, 0xa3a: 0x0c33, 0xa3b: 0x0c4b, + 0xa3c: 0x0c53, 0xa3d: 0x0c67, 0xa3e: 0x16bf, 0xa3f: 0x0c6f, + // Block 0x29, offset 0xa40 + 0xa40: 0x0c63, 0xa41: 0x0c5b, 0xa42: 0x05ef, 0xa43: 0x0c77, 0xa44: 0x0c7f, 0xa45: 0x0c87, + 0xa46: 0x0c7b, 0xa47: 0x05f3, 0xa48: 0x0c97, 0xa49: 0x0c9f, 0xa4a: 0x16c4, 0xa4b: 0x0ccb, + 0xa4c: 0x0cff, 0xa4d: 0x0cdb, 0xa4e: 0x05ff, 0xa4f: 0x0ce7, 0xa50: 0x05fb, 0xa51: 0x05f7, + 0xa52: 0x07c3, 0xa53: 0x07c7, 0xa54: 0x0d03, 0xa55: 0x0ceb, 0xa56: 0x11ab, 0xa57: 0x0663, + 0xa58: 0x0d0f, 0xa59: 0x0d13, 0xa5a: 0x0d17, 0xa5b: 0x0d2b, 0xa5c: 0x0d23, 0xa5d: 0x16dd, + 0xa5e: 0x0603, 0xa5f: 0x0d3f, 0xa60: 0x0d33, 0xa61: 0x0d4f, 0xa62: 0x0d57, 0xa63: 0x16e7, + 0xa64: 0x0d5b, 0xa65: 0x0d47, 0xa66: 0x0d63, 0xa67: 0x0607, 0xa68: 0x0d67, 0xa69: 0x0d6b, + 0xa6a: 0x0d6f, 0xa6b: 0x0d7b, 0xa6c: 0x16ec, 0xa6d: 0x0d83, 0xa6e: 0x060b, 0xa6f: 0x0d8f, + 0xa70: 0x16f1, 0xa71: 0x0d93, 0xa72: 0x060f, 0xa73: 0x0d9f, 0xa74: 0x0dab, 0xa75: 0x0db7, + 0xa76: 0x0dbb, 0xa77: 0x16f6, 0xa78: 0x168d, 0xa79: 0x16fb, 0xa7a: 0x0ddb, 0xa7b: 0x1700, + 0xa7c: 0x0de7, 0xa7d: 0x0def, 0xa7e: 0x0ddf, 0xa7f: 0x0dfb, + // Block 0x2a, offset 0xa80 + 0xa80: 0x0e0b, 0xa81: 0x0e1b, 0xa82: 0x0e0f, 0xa83: 0x0e13, 0xa84: 0x0e1f, 0xa85: 0x0e23, + 0xa86: 0x1705, 0xa87: 0x0e07, 0xa88: 0x0e3b, 0xa89: 0x0e3f, 0xa8a: 0x0613, 0xa8b: 0x0e53, + 0xa8c: 0x0e4f, 0xa8d: 0x170a, 0xa8e: 0x0e33, 0xa8f: 0x0e6f, 0xa90: 0x170f, 0xa91: 0x1714, + 0xa92: 0x0e73, 0xa93: 0x0e87, 0xa94: 0x0e83, 0xa95: 0x0e7f, 0xa96: 0x0617, 0xa97: 0x0e8b, + 0xa98: 0x0e9b, 0xa99: 0x0e97, 0xa9a: 0x0ea3, 0xa9b: 0x1651, 0xa9c: 0x0eb3, 0xa9d: 0x1719, + 0xa9e: 0x0ebf, 0xa9f: 0x1723, 0xaa0: 0x0ed3, 0xaa1: 0x0edf, 0xaa2: 0x0ef3, 0xaa3: 0x1728, + 0xaa4: 0x0f07, 0xaa5: 0x0f0b, 0xaa6: 0x172d, 0xaa7: 0x1732, 0xaa8: 0x0f27, 0xaa9: 0x0f37, + 0xaaa: 0x061b, 0xaab: 0x0f3b, 0xaac: 0x061f, 0xaad: 0x061f, 0xaae: 0x0f53, 0xaaf: 0x0f57, + 0xab0: 0x0f5f, 0xab1: 0x0f63, 0xab2: 0x0f6f, 0xab3: 0x0623, 0xab4: 0x0f87, 0xab5: 0x1737, + 0xab6: 0x0fa3, 0xab7: 0x173c, 0xab8: 0x0faf, 0xab9: 0x16a1, 0xaba: 0x0fbf, 0xabb: 0x1741, + 0xabc: 0x1746, 0xabd: 0x174b, 0xabe: 0x0627, 0xabf: 0x062b, + // Block 0x2b, offset 0xac0 + 0xac0: 0x0ff7, 0xac1: 0x1755, 0xac2: 0x1750, 0xac3: 0x175a, 0xac4: 0x175f, 0xac5: 0x0fff, + 0xac6: 0x1003, 0xac7: 0x1003, 0xac8: 0x100b, 0xac9: 0x0633, 0xaca: 0x100f, 0xacb: 0x0637, + 0xacc: 0x063b, 0xacd: 0x1769, 0xace: 0x1023, 0xacf: 0x102b, 0xad0: 0x1037, 0xad1: 0x063f, + 0xad2: 0x176e, 0xad3: 0x105b, 0xad4: 0x1773, 0xad5: 0x1778, 0xad6: 0x107b, 0xad7: 0x1093, + 0xad8: 0x0643, 0xad9: 0x109b, 0xada: 0x109f, 0xadb: 0x10a3, 0xadc: 0x177d, 0xadd: 0x1782, + 0xade: 0x1782, 0xadf: 0x10bb, 0xae0: 0x0647, 0xae1: 0x1787, 0xae2: 0x10cf, 0xae3: 0x10d3, + 0xae4: 0x064b, 0xae5: 0x178c, 0xae6: 0x10ef, 0xae7: 0x064f, 0xae8: 0x10ff, 0xae9: 0x10f7, + 0xaea: 0x1107, 0xaeb: 0x1796, 0xaec: 0x111f, 0xaed: 0x0653, 0xaee: 0x112b, 0xaef: 0x1133, + 0xaf0: 0x1143, 0xaf1: 0x0657, 0xaf2: 0x17a0, 0xaf3: 0x17a5, 0xaf4: 0x065b, 0xaf5: 0x17aa, + 0xaf6: 0x115b, 0xaf7: 0x17af, 0xaf8: 0x1167, 0xaf9: 0x1173, 0xafa: 0x117b, 0xafb: 0x17b4, + 0xafc: 0x17b9, 0xafd: 0x118f, 0xafe: 0x17be, 0xaff: 0x1197, + // Block 0x2c, offset 0xb00 + 0xb00: 0x16ce, 0xb01: 0x065f, 0xb02: 0x11af, 0xb03: 0x11b3, 0xb04: 0x0667, 0xb05: 0x11b7, + 0xb06: 0x0a33, 0xb07: 0x17c3, 0xb08: 0x17c8, 0xb09: 0x16d3, 0xb0a: 0x16d8, 0xb0b: 0x11d7, + 0xb0c: 0x11db, 0xb0d: 0x13f3, 0xb0e: 0x066b, 0xb0f: 0x1207, 0xb10: 0x1203, 0xb11: 0x120b, + 0xb12: 0x083f, 0xb13: 0x120f, 0xb14: 0x1213, 0xb15: 0x1217, 0xb16: 0x121f, 0xb17: 0x17cd, + 0xb18: 0x121b, 0xb19: 0x1223, 0xb1a: 0x1237, 0xb1b: 0x123b, 0xb1c: 0x1227, 0xb1d: 0x123f, + 0xb1e: 0x1253, 0xb1f: 0x1267, 0xb20: 0x1233, 0xb21: 0x1247, 0xb22: 0x124b, 0xb23: 0x124f, + 0xb24: 0x17d2, 0xb25: 0x17dc, 0xb26: 0x17d7, 0xb27: 0x066f, 0xb28: 0x126f, 0xb29: 0x1273, + 0xb2a: 0x127b, 0xb2b: 0x17f0, 0xb2c: 0x127f, 0xb2d: 0x17e1, 0xb2e: 0x0673, 0xb2f: 0x0677, + 0xb30: 0x17e6, 0xb31: 0x17eb, 0xb32: 0x067b, 0xb33: 0x129f, 0xb34: 0x12a3, 0xb35: 0x12a7, + 0xb36: 0x12ab, 0xb37: 0x12b7, 0xb38: 0x12b3, 0xb39: 0x12bf, 0xb3a: 0x12bb, 0xb3b: 0x12cb, + 0xb3c: 0x12c3, 0xb3d: 0x12c7, 0xb3e: 0x12cf, 0xb3f: 0x067f, + // Block 0x2d, offset 0xb40 + 0xb40: 0x12d7, 0xb41: 0x12db, 0xb42: 0x0683, 0xb43: 0x12eb, 0xb44: 0x12ef, 0xb45: 0x17f5, + 0xb46: 0x12fb, 0xb47: 0x12ff, 0xb48: 0x0687, 0xb49: 0x130b, 0xb4a: 0x05bb, 0xb4b: 0x17fa, + 0xb4c: 0x17ff, 0xb4d: 0x068b, 0xb4e: 0x068f, 0xb4f: 0x1337, 0xb50: 0x134f, 0xb51: 0x136b, + 0xb52: 0x137b, 0xb53: 0x1804, 0xb54: 0x138f, 0xb55: 0x1393, 0xb56: 0x13ab, 0xb57: 0x13b7, + 0xb58: 0x180e, 0xb59: 0x1660, 0xb5a: 0x13c3, 0xb5b: 0x13bf, 0xb5c: 0x13cb, 0xb5d: 0x1665, + 0xb5e: 0x13d7, 0xb5f: 0x13e3, 0xb60: 0x1813, 0xb61: 0x1818, 0xb62: 0x1423, 0xb63: 0x142f, + 0xb64: 0x1437, 0xb65: 0x181d, 0xb66: 0x143b, 0xb67: 0x1467, 0xb68: 0x1473, 0xb69: 0x1477, + 0xb6a: 0x146f, 0xb6b: 0x1483, 0xb6c: 0x1487, 0xb6d: 0x1822, 0xb6e: 0x1493, 0xb6f: 0x0693, + 0xb70: 0x149b, 0xb71: 0x1827, 0xb72: 0x0697, 0xb73: 0x14d3, 0xb74: 0x0ac3, 0xb75: 0x14eb, + 0xb76: 0x182c, 0xb77: 0x1836, 0xb78: 0x069b, 0xb79: 0x069f, 0xb7a: 0x1513, 0xb7b: 0x183b, + 0xb7c: 0x06a3, 0xb7d: 0x1840, 0xb7e: 0x152b, 0xb7f: 0x152b, + // Block 0x2e, offset 0xb80 + 0xb80: 0x1533, 0xb81: 0x1845, 0xb82: 0x154b, 0xb83: 0x06a7, 0xb84: 0x155b, 0xb85: 0x1567, + 0xb86: 0x156f, 0xb87: 0x1577, 0xb88: 0x06ab, 0xb89: 0x184a, 0xb8a: 0x158b, 0xb8b: 0x15a7, + 0xb8c: 0x15b3, 0xb8d: 0x06af, 0xb8e: 0x06b3, 0xb8f: 0x15b7, 0xb90: 0x184f, 0xb91: 0x06b7, + 0xb92: 0x1854, 0xb93: 0x1859, 0xb94: 0x185e, 0xb95: 0x15db, 0xb96: 0x06bb, 0xb97: 0x15ef, + 0xb98: 0x15f7, 0xb99: 0x15fb, 0xb9a: 0x1603, 0xb9b: 0x160b, 0xb9c: 0x1613, 0xb9d: 0x1868, +} + +// nfcIndex: 22 blocks, 1408 entries, 1408 bytes +// Block 0 is the zero block. +var nfcIndex = [1408]uint8{ + // Block 0x0, offset 0x0 + // Block 0x1, offset 0x40 + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0xc2: 0x2d, 0xc3: 0x01, 0xc4: 0x02, 0xc5: 0x03, 0xc6: 0x2e, 0xc7: 0x04, + 0xc8: 0x05, 0xca: 0x2f, 0xcb: 0x30, 0xcc: 0x06, 0xcd: 0x07, 0xce: 0x08, 0xcf: 0x31, + 0xd0: 0x09, 0xd1: 0x32, 0xd2: 0x33, 0xd3: 0x0a, 0xd6: 0x0b, 0xd7: 0x34, + 0xd8: 0x35, 0xd9: 0x0c, 0xdb: 0x36, 0xdc: 0x37, 0xdd: 0x38, 0xdf: 0x39, + 0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05, + 0xea: 0x06, 0xeb: 0x07, 0xec: 0x08, 0xed: 0x09, 0xef: 0x0a, + 0xf0: 0x13, + // Block 0x4, offset 0x100 + 0x120: 0x3a, 0x121: 0x3b, 0x123: 0x3c, 0x124: 0x3d, 0x125: 0x3e, 0x126: 0x3f, 0x127: 0x40, + 0x128: 0x41, 0x129: 0x42, 0x12a: 0x43, 0x12b: 0x44, 0x12c: 0x3f, 0x12d: 0x45, 0x12e: 0x46, 0x12f: 0x47, + 0x131: 0x48, 0x132: 0x49, 0x133: 0x4a, 0x134: 0x4b, 0x135: 0x4c, 0x137: 0x4d, + 0x138: 0x4e, 0x139: 0x4f, 0x13a: 0x50, 0x13b: 0x51, 0x13c: 0x52, 0x13d: 0x53, 0x13e: 0x54, 0x13f: 0x55, + // Block 0x5, offset 0x140 + 0x140: 0x56, 0x142: 0x57, 0x144: 0x58, 0x145: 0x59, 0x146: 0x5a, 0x147: 0x5b, + 0x14d: 0x5c, + 0x15c: 0x5d, 0x15f: 0x5e, + 0x162: 0x5f, 0x164: 0x60, + 0x168: 0x61, 0x169: 0x62, 0x16a: 0x63, 0x16c: 0x0d, 0x16d: 0x64, 0x16e: 0x65, 0x16f: 0x66, + 0x170: 0x67, 0x173: 0x68, 0x177: 0x0e, + 0x178: 0x0f, 0x179: 0x10, 0x17a: 0x11, 0x17b: 0x12, 0x17c: 0x13, 0x17d: 0x14, 0x17e: 0x15, 0x17f: 0x16, + // Block 0x6, offset 0x180 + 0x180: 0x69, 0x183: 0x6a, 0x184: 0x6b, 0x186: 0x6c, 0x187: 0x6d, + 0x188: 0x6e, 0x189: 0x17, 0x18a: 0x18, 0x18b: 0x6f, 0x18c: 0x70, + 0x1ab: 0x71, + 0x1b3: 0x72, 0x1b5: 0x73, 0x1b7: 0x74, + // Block 0x7, offset 0x1c0 + 0x1c0: 0x75, 0x1c1: 0x19, 0x1c2: 0x1a, 0x1c3: 0x1b, 0x1c4: 0x76, 0x1c5: 0x77, + 0x1c9: 0x78, 0x1cc: 0x79, 0x1cd: 0x7a, + // Block 0x8, offset 0x200 + 0x219: 0x7b, 0x21a: 0x7c, 0x21b: 0x7d, + 0x220: 0x7e, 0x223: 0x7f, 0x224: 0x80, 0x225: 0x81, 0x226: 0x82, 0x227: 0x83, + 0x22a: 0x84, 0x22b: 0x85, 0x22f: 0x86, + 0x230: 0x87, 0x231: 0x88, 0x232: 0x89, 0x233: 0x8a, 0x234: 0x8b, 0x235: 0x8c, 0x236: 0x8d, 0x237: 0x87, + 0x238: 0x88, 0x239: 0x89, 0x23a: 0x8a, 0x23b: 0x8b, 0x23c: 0x8c, 0x23d: 0x8d, 0x23e: 0x87, 0x23f: 0x88, + // Block 0x9, offset 0x240 + 0x240: 0x89, 0x241: 0x8a, 0x242: 0x8b, 0x243: 0x8c, 0x244: 0x8d, 0x245: 0x87, 0x246: 0x88, 0x247: 0x89, + 0x248: 0x8a, 0x249: 0x8b, 0x24a: 0x8c, 0x24b: 0x8d, 0x24c: 0x87, 0x24d: 0x88, 0x24e: 0x89, 0x24f: 0x8a, + 0x250: 0x8b, 0x251: 0x8c, 0x252: 0x8d, 0x253: 0x87, 0x254: 0x88, 0x255: 0x89, 0x256: 0x8a, 0x257: 0x8b, + 0x258: 0x8c, 0x259: 0x8d, 0x25a: 0x87, 0x25b: 0x88, 0x25c: 0x89, 0x25d: 0x8a, 0x25e: 0x8b, 0x25f: 0x8c, + 0x260: 0x8d, 0x261: 0x87, 0x262: 0x88, 0x263: 0x89, 0x264: 0x8a, 0x265: 0x8b, 0x266: 0x8c, 0x267: 0x8d, + 0x268: 0x87, 0x269: 0x88, 0x26a: 0x89, 0x26b: 0x8a, 0x26c: 0x8b, 0x26d: 0x8c, 0x26e: 0x8d, 0x26f: 0x87, + 0x270: 0x88, 0x271: 0x89, 0x272: 0x8a, 0x273: 0x8b, 0x274: 0x8c, 0x275: 0x8d, 0x276: 0x87, 0x277: 0x88, + 0x278: 0x89, 0x279: 0x8a, 0x27a: 0x8b, 0x27b: 0x8c, 0x27c: 0x8d, 0x27d: 0x87, 0x27e: 0x88, 0x27f: 0x89, + // Block 0xa, offset 0x280 + 0x280: 0x8a, 0x281: 0x8b, 0x282: 0x8c, 0x283: 0x8d, 0x284: 0x87, 0x285: 0x88, 0x286: 0x89, 0x287: 0x8a, + 0x288: 0x8b, 0x289: 0x8c, 0x28a: 0x8d, 0x28b: 0x87, 0x28c: 0x88, 0x28d: 0x89, 0x28e: 0x8a, 0x28f: 0x8b, + 0x290: 0x8c, 0x291: 0x8d, 0x292: 0x87, 0x293: 0x88, 0x294: 0x89, 0x295: 0x8a, 0x296: 0x8b, 0x297: 0x8c, + 0x298: 0x8d, 0x299: 0x87, 0x29a: 0x88, 0x29b: 0x89, 0x29c: 0x8a, 0x29d: 0x8b, 0x29e: 0x8c, 0x29f: 0x8d, + 0x2a0: 0x87, 0x2a1: 0x88, 0x2a2: 0x89, 0x2a3: 0x8a, 0x2a4: 0x8b, 0x2a5: 0x8c, 0x2a6: 0x8d, 0x2a7: 0x87, + 0x2a8: 0x88, 0x2a9: 0x89, 0x2aa: 0x8a, 0x2ab: 0x8b, 0x2ac: 0x8c, 0x2ad: 0x8d, 0x2ae: 0x87, 0x2af: 0x88, + 0x2b0: 0x89, 0x2b1: 0x8a, 0x2b2: 0x8b, 0x2b3: 0x8c, 0x2b4: 0x8d, 0x2b5: 0x87, 0x2b6: 0x88, 0x2b7: 0x89, + 0x2b8: 0x8a, 0x2b9: 0x8b, 0x2ba: 0x8c, 0x2bb: 0x8d, 0x2bc: 0x87, 0x2bd: 0x88, 0x2be: 0x89, 0x2bf: 0x8a, + // Block 0xb, offset 0x2c0 + 0x2c0: 0x8b, 0x2c1: 0x8c, 0x2c2: 0x8d, 0x2c3: 0x87, 0x2c4: 0x88, 0x2c5: 0x89, 0x2c6: 0x8a, 0x2c7: 0x8b, + 0x2c8: 0x8c, 0x2c9: 0x8d, 0x2ca: 0x87, 0x2cb: 0x88, 0x2cc: 0x89, 0x2cd: 0x8a, 0x2ce: 0x8b, 0x2cf: 0x8c, + 0x2d0: 0x8d, 0x2d1: 0x87, 0x2d2: 0x88, 0x2d3: 0x89, 0x2d4: 0x8a, 0x2d5: 0x8b, 0x2d6: 0x8c, 0x2d7: 0x8d, + 0x2d8: 0x87, 0x2d9: 0x88, 0x2da: 0x89, 0x2db: 0x8a, 0x2dc: 0x8b, 0x2dd: 0x8c, 0x2de: 0x8e, + // Block 0xc, offset 0x300 + 0x324: 0x1c, 0x325: 0x1d, 0x326: 0x1e, 0x327: 0x1f, + 0x328: 0x20, 0x329: 0x21, 0x32a: 0x22, 0x32b: 0x23, 0x32c: 0x8f, 0x32d: 0x90, 0x32e: 0x91, + 0x331: 0x92, 0x332: 0x93, 0x333: 0x94, 0x334: 0x95, + 0x338: 0x96, 0x339: 0x97, 0x33a: 0x98, 0x33b: 0x99, 0x33e: 0x9a, 0x33f: 0x9b, + // Block 0xd, offset 0x340 + 0x347: 0x9c, + 0x34b: 0x9d, 0x34d: 0x9e, + 0x368: 0x9f, 0x36b: 0xa0, + // Block 0xe, offset 0x380 + 0x381: 0xa1, 0x382: 0xa2, 0x384: 0xa3, 0x385: 0x82, 0x387: 0xa4, + 0x388: 0xa5, 0x38b: 0xa6, 0x38c: 0x3f, 0x38d: 0xa7, + 0x391: 0xa8, 0x392: 0xa9, 0x393: 0xaa, 0x396: 0xab, 0x397: 0xac, + 0x398: 0x73, 0x39a: 0xad, 0x39c: 0xae, + 0x3a8: 0xaf, 0x3a9: 0xb0, 0x3aa: 0xb1, + 0x3b0: 0x73, 0x3b5: 0xb2, + // Block 0xf, offset 0x3c0 + 0x3eb: 0xb3, 0x3ec: 0xb4, + // Block 0x10, offset 0x400 + 0x432: 0xb5, + // Block 0x11, offset 0x440 + 0x445: 0xb6, 0x446: 0xb7, 0x447: 0xb8, + 0x449: 0xb9, + // Block 0x12, offset 0x480 + 0x480: 0xba, + 0x4a3: 0xbb, 0x4a5: 0xbc, + // Block 0x13, offset 0x4c0 + 0x4c8: 0xbd, + // Block 0x14, offset 0x500 + 0x520: 0x24, 0x521: 0x25, 0x522: 0x26, 0x523: 0x27, 0x524: 0x28, 0x525: 0x29, 0x526: 0x2a, 0x527: 0x2b, + 0x528: 0x2c, + // Block 0x15, offset 0x540 + 0x550: 0x0b, 0x551: 0x0c, 0x556: 0x0d, + 0x55b: 0x0e, 0x55d: 0x0f, 0x55e: 0x10, 0x55f: 0x11, + 0x56f: 0x12, +} + +// nfcSparseOffset: 145 entries, 290 bytes +var nfcSparseOffset = []uint16{0x0, 0x5, 0x9, 0xb, 0xd, 0x18, 0x28, 0x2a, 0x2f, 0x3a, 0x49, 0x56, 0x5e, 0x62, 0x67, 0x69, 0x7a, 0x82, 0x89, 0x8c, 0x93, 0x97, 0x9b, 0x9d, 0x9f, 0xa8, 0xac, 0xb3, 0xb8, 0xbb, 0xc5, 0xc8, 0xcf, 0xd7, 0xda, 0xdc, 0xde, 0xe0, 0xe5, 0xf6, 0x102, 0x104, 0x10a, 0x10c, 0x10e, 0x110, 0x112, 0x114, 0x116, 0x119, 0x11c, 0x11e, 0x121, 0x124, 0x128, 0x12d, 0x136, 0x138, 0x13b, 0x13d, 0x148, 0x14c, 0x15a, 0x15d, 0x163, 0x169, 0x174, 0x178, 0x17a, 0x17c, 0x17e, 0x180, 0x182, 0x188, 0x18c, 0x18e, 0x190, 0x198, 0x19c, 0x19f, 0x1a1, 0x1a3, 0x1a5, 0x1a8, 0x1aa, 0x1ac, 0x1ae, 0x1b0, 0x1b6, 0x1b9, 0x1bb, 0x1c2, 0x1c8, 0x1ce, 0x1d6, 0x1dc, 0x1e2, 0x1e8, 0x1ec, 0x1fa, 0x203, 0x206, 0x209, 0x20b, 0x20e, 0x210, 0x214, 0x219, 0x21b, 0x21d, 0x222, 0x228, 0x22a, 0x22c, 0x22e, 0x234, 0x237, 0x23a, 0x242, 0x249, 0x24c, 0x24f, 0x251, 0x259, 0x25c, 0x263, 0x266, 0x26c, 0x26e, 0x271, 0x273, 0x275, 0x277, 0x279, 0x27c, 0x27e, 0x280, 0x282, 0x28f, 0x299, 0x29b, 0x29d, 0x2a3, 0x2a5, 0x2a8} + +// nfcSparseValues: 682 entries, 2728 bytes +var nfcSparseValues = [682]valueRange{ + // Block 0x0, offset 0x0 + {value: 0x0000, lo: 0x04}, + {value: 0xa100, lo: 0xa8, hi: 0xa8}, + {value: 0x8100, lo: 0xaf, hi: 0xaf}, + {value: 0x8100, lo: 0xb4, hi: 0xb4}, + {value: 0x8100, lo: 0xb8, hi: 0xb8}, + // Block 0x1, offset 0x5 + {value: 0x0091, lo: 0x03}, + {value: 0x46e2, lo: 0xa0, hi: 0xa1}, + {value: 0x4714, lo: 0xaf, hi: 0xb0}, + {value: 0xa000, lo: 0xb7, hi: 0xb7}, + // Block 0x2, offset 0x9 + {value: 0x0000, lo: 0x01}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + // Block 0x3, offset 0xb + {value: 0x0000, lo: 0x01}, + {value: 0x8100, lo: 0x98, hi: 0x9d}, + // Block 0x4, offset 0xd + {value: 0x0006, lo: 0x0a}, + {value: 0xa000, lo: 0x81, hi: 0x81}, + {value: 0xa000, lo: 0x85, hi: 0x85}, + {value: 0xa000, lo: 0x89, hi: 0x89}, + {value: 0x4840, lo: 0x8a, hi: 0x8a}, + {value: 0x485e, lo: 0x8b, hi: 0x8b}, + {value: 0x36c7, lo: 0x8c, hi: 0x8c}, + {value: 0x36df, lo: 0x8d, hi: 0x8d}, + {value: 0x4876, lo: 0x8e, hi: 0x8e}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0x36fd, lo: 0x93, hi: 0x94}, + // Block 0x5, offset 0x18 + {value: 0x0000, lo: 0x0f}, + {value: 0xa000, lo: 0x83, hi: 0x83}, + {value: 0xa000, lo: 0x87, hi: 0x87}, + {value: 0xa000, lo: 0x8b, hi: 0x8b}, + {value: 0xa000, lo: 0x8d, hi: 0x8d}, + {value: 0x37a5, lo: 0x90, hi: 0x90}, + {value: 0x37b1, lo: 0x91, hi: 0x91}, + {value: 0x379f, lo: 0x93, hi: 0x93}, + {value: 0xa000, lo: 0x96, hi: 0x96}, + {value: 0x3817, lo: 0x97, hi: 0x97}, + {value: 0x37e1, lo: 0x9c, hi: 0x9c}, + {value: 0x37c9, lo: 0x9d, hi: 0x9d}, + {value: 0x37f3, lo: 0x9e, hi: 0x9e}, + {value: 0xa000, lo: 0xb4, hi: 0xb5}, + {value: 0x381d, lo: 0xb6, hi: 0xb6}, + {value: 0x3823, lo: 0xb7, hi: 0xb7}, + // Block 0x6, offset 0x28 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0x83, hi: 0x87}, + // Block 0x7, offset 0x2a + {value: 0x0001, lo: 0x04}, + {value: 0x8113, lo: 0x81, hi: 0x82}, + {value: 0x8132, lo: 0x84, hi: 0x84}, + {value: 0x812d, lo: 0x85, hi: 0x85}, + {value: 0x810d, lo: 0x87, hi: 0x87}, + // Block 0x8, offset 0x2f + {value: 0x0000, lo: 0x0a}, + {value: 0x8132, lo: 0x90, hi: 0x97}, + {value: 0x8119, lo: 0x98, hi: 0x98}, + {value: 0x811a, lo: 0x99, hi: 0x99}, + {value: 0x811b, lo: 0x9a, hi: 0x9a}, + {value: 0x3841, lo: 0xa2, hi: 0xa2}, + {value: 0x3847, lo: 0xa3, hi: 0xa3}, + {value: 0x3853, lo: 0xa4, hi: 0xa4}, + {value: 0x384d, lo: 0xa5, hi: 0xa5}, + {value: 0x3859, lo: 0xa6, hi: 0xa6}, + {value: 0xa000, lo: 0xa7, hi: 0xa7}, + // Block 0x9, offset 0x3a + {value: 0x0000, lo: 0x0e}, + {value: 0x386b, lo: 0x80, hi: 0x80}, + {value: 0xa000, lo: 0x81, hi: 0x81}, + {value: 0x385f, lo: 0x82, hi: 0x82}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0x3865, lo: 0x93, hi: 0x93}, + {value: 0xa000, lo: 0x95, hi: 0x95}, + {value: 0x8132, lo: 0x96, hi: 0x9c}, + {value: 0x8132, lo: 0x9f, hi: 0xa2}, + {value: 0x812d, lo: 0xa3, hi: 0xa3}, + {value: 0x8132, lo: 0xa4, hi: 0xa4}, + {value: 0x8132, lo: 0xa7, hi: 0xa8}, + {value: 0x812d, lo: 0xaa, hi: 0xaa}, + {value: 0x8132, lo: 0xab, hi: 0xac}, + {value: 0x812d, lo: 0xad, hi: 0xad}, + // Block 0xa, offset 0x49 + {value: 0x0000, lo: 0x0c}, + {value: 0x811f, lo: 0x91, hi: 0x91}, + {value: 0x8132, lo: 0xb0, hi: 0xb0}, + {value: 0x812d, lo: 0xb1, hi: 0xb1}, + {value: 0x8132, lo: 0xb2, hi: 0xb3}, + {value: 0x812d, lo: 0xb4, hi: 0xb4}, + {value: 0x8132, lo: 0xb5, hi: 0xb6}, + {value: 0x812d, lo: 0xb7, hi: 0xb9}, + {value: 0x8132, lo: 0xba, hi: 0xba}, + {value: 0x812d, lo: 0xbb, hi: 0xbc}, + {value: 0x8132, lo: 0xbd, hi: 0xbd}, + {value: 0x812d, lo: 0xbe, hi: 0xbe}, + {value: 0x8132, lo: 0xbf, hi: 0xbf}, + // Block 0xb, offset 0x56 + {value: 0x0005, lo: 0x07}, + {value: 0x8132, lo: 0x80, hi: 0x80}, + {value: 0x8132, lo: 0x81, hi: 0x81}, + {value: 0x812d, lo: 0x82, hi: 0x83}, + {value: 0x812d, lo: 0x84, hi: 0x85}, + {value: 0x812d, lo: 0x86, hi: 0x87}, + {value: 0x812d, lo: 0x88, hi: 0x89}, + {value: 0x8132, lo: 0x8a, hi: 0x8a}, + // Block 0xc, offset 0x5e + {value: 0x0000, lo: 0x03}, + {value: 0x8132, lo: 0xab, hi: 0xb1}, + {value: 0x812d, lo: 0xb2, hi: 0xb2}, + {value: 0x8132, lo: 0xb3, hi: 0xb3}, + // Block 0xd, offset 0x62 + {value: 0x0000, lo: 0x04}, + {value: 0x8132, lo: 0x96, hi: 0x99}, + {value: 0x8132, lo: 0x9b, hi: 0xa3}, + {value: 0x8132, lo: 0xa5, hi: 0xa7}, + {value: 0x8132, lo: 0xa9, hi: 0xad}, + // Block 0xe, offset 0x67 + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0x99, hi: 0x9b}, + // Block 0xf, offset 0x69 + {value: 0x0000, lo: 0x10}, + {value: 0x8132, lo: 0x94, hi: 0xa1}, + {value: 0x812d, lo: 0xa3, hi: 0xa3}, + {value: 0x8132, lo: 0xa4, hi: 0xa5}, + {value: 0x812d, lo: 0xa6, hi: 0xa6}, + {value: 0x8132, lo: 0xa7, hi: 0xa8}, + {value: 0x812d, lo: 0xa9, hi: 0xa9}, + {value: 0x8132, lo: 0xaa, hi: 0xac}, + {value: 0x812d, lo: 0xad, hi: 0xaf}, + {value: 0x8116, lo: 0xb0, hi: 0xb0}, + {value: 0x8117, lo: 0xb1, hi: 0xb1}, + {value: 0x8118, lo: 0xb2, hi: 0xb2}, + {value: 0x8132, lo: 0xb3, hi: 0xb5}, + {value: 0x812d, lo: 0xb6, hi: 0xb6}, + {value: 0x8132, lo: 0xb7, hi: 0xb8}, + {value: 0x812d, lo: 0xb9, hi: 0xba}, + {value: 0x8132, lo: 0xbb, hi: 0xbf}, + // Block 0x10, offset 0x7a + {value: 0x0000, lo: 0x07}, + {value: 0xa000, lo: 0xa8, hi: 0xa8}, + {value: 0x3ed8, lo: 0xa9, hi: 0xa9}, + {value: 0xa000, lo: 0xb0, hi: 0xb0}, + {value: 0x3ee0, lo: 0xb1, hi: 0xb1}, + {value: 0xa000, lo: 0xb3, hi: 0xb3}, + {value: 0x3ee8, lo: 0xb4, hi: 0xb4}, + {value: 0x9902, lo: 0xbc, hi: 0xbc}, + // Block 0x11, offset 0x82 + {value: 0x0008, lo: 0x06}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x8132, lo: 0x91, hi: 0x91}, + {value: 0x812d, lo: 0x92, hi: 0x92}, + {value: 0x8132, lo: 0x93, hi: 0x93}, + {value: 0x8132, lo: 0x94, hi: 0x94}, + {value: 0x451c, lo: 0x98, hi: 0x9f}, + // Block 0x12, offset 0x89 + {value: 0x0000, lo: 0x02}, + {value: 0x8102, lo: 0xbc, hi: 0xbc}, + {value: 0x9900, lo: 0xbe, hi: 0xbe}, + // Block 0x13, offset 0x8c + {value: 0x0008, lo: 0x06}, + {value: 0xa000, lo: 0x87, hi: 0x87}, + {value: 0x2c9e, lo: 0x8b, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x97, hi: 0x97}, + {value: 0x455c, lo: 0x9c, hi: 0x9d}, + {value: 0x456c, lo: 0x9f, hi: 0x9f}, + // Block 0x14, offset 0x93 + {value: 0x0000, lo: 0x03}, + {value: 0x4594, lo: 0xb3, hi: 0xb3}, + {value: 0x459c, lo: 0xb6, hi: 0xb6}, + {value: 0x8102, lo: 0xbc, hi: 0xbc}, + // Block 0x15, offset 0x97 + {value: 0x0008, lo: 0x03}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x4574, lo: 0x99, hi: 0x9b}, + {value: 0x458c, lo: 0x9e, hi: 0x9e}, + // Block 0x16, offset 0x9b + {value: 0x0000, lo: 0x01}, + {value: 0x8102, lo: 0xbc, hi: 0xbc}, + // Block 0x17, offset 0x9d + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + // Block 0x18, offset 0x9f + {value: 0x0000, lo: 0x08}, + {value: 0xa000, lo: 0x87, hi: 0x87}, + {value: 0x2cb6, lo: 0x88, hi: 0x88}, + {value: 0x2cae, lo: 0x8b, hi: 0x8b}, + {value: 0x2cbe, lo: 0x8c, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x96, hi: 0x97}, + {value: 0x45a4, lo: 0x9c, hi: 0x9c}, + {value: 0x45ac, lo: 0x9d, hi: 0x9d}, + // Block 0x19, offset 0xa8 + {value: 0x0000, lo: 0x03}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0x2cc6, lo: 0x94, hi: 0x94}, + {value: 0x9900, lo: 0xbe, hi: 0xbe}, + // Block 0x1a, offset 0xac + {value: 0x0000, lo: 0x06}, + {value: 0xa000, lo: 0x86, hi: 0x87}, + {value: 0x2cce, lo: 0x8a, hi: 0x8a}, + {value: 0x2cde, lo: 0x8b, hi: 0x8b}, + {value: 0x2cd6, lo: 0x8c, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x97, hi: 0x97}, + // Block 0x1b, offset 0xb3 + {value: 0x1801, lo: 0x04}, + {value: 0xa000, lo: 0x86, hi: 0x86}, + {value: 0x3ef0, lo: 0x88, hi: 0x88}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x8120, lo: 0x95, hi: 0x96}, + // Block 0x1c, offset 0xb8 + {value: 0x0000, lo: 0x02}, + {value: 0x8102, lo: 0xbc, hi: 0xbc}, + {value: 0xa000, lo: 0xbf, hi: 0xbf}, + // Block 0x1d, offset 0xbb + {value: 0x0000, lo: 0x09}, + {value: 0x2ce6, lo: 0x80, hi: 0x80}, + {value: 0x9900, lo: 0x82, hi: 0x82}, + {value: 0xa000, lo: 0x86, hi: 0x86}, + {value: 0x2cee, lo: 0x87, hi: 0x87}, + {value: 0x2cf6, lo: 0x88, hi: 0x88}, + {value: 0x2f50, lo: 0x8a, hi: 0x8a}, + {value: 0x2dd8, lo: 0x8b, hi: 0x8b}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x95, hi: 0x96}, + // Block 0x1e, offset 0xc5 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0xbb, hi: 0xbc}, + {value: 0x9900, lo: 0xbe, hi: 0xbe}, + // Block 0x1f, offset 0xc8 + {value: 0x0000, lo: 0x06}, + {value: 0xa000, lo: 0x86, hi: 0x87}, + {value: 0x2cfe, lo: 0x8a, hi: 0x8a}, + {value: 0x2d0e, lo: 0x8b, hi: 0x8b}, + {value: 0x2d06, lo: 0x8c, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x97, hi: 0x97}, + // Block 0x20, offset 0xcf + {value: 0x6bea, lo: 0x07}, + {value: 0x9904, lo: 0x8a, hi: 0x8a}, + {value: 0x9900, lo: 0x8f, hi: 0x8f}, + {value: 0xa000, lo: 0x99, hi: 0x99}, + {value: 0x3ef8, lo: 0x9a, hi: 0x9a}, + {value: 0x2f58, lo: 0x9c, hi: 0x9c}, + {value: 0x2de3, lo: 0x9d, hi: 0x9d}, + {value: 0x2d16, lo: 0x9e, hi: 0x9f}, + // Block 0x21, offset 0xd7 + {value: 0x0000, lo: 0x02}, + {value: 0x8122, lo: 0xb8, hi: 0xb9}, + {value: 0x8104, lo: 0xba, hi: 0xba}, + // Block 0x22, offset 0xda + {value: 0x0000, lo: 0x01}, + {value: 0x8123, lo: 0x88, hi: 0x8b}, + // Block 0x23, offset 0xdc + {value: 0x0000, lo: 0x01}, + {value: 0x8124, lo: 0xb8, hi: 0xb9}, + // Block 0x24, offset 0xde + {value: 0x0000, lo: 0x01}, + {value: 0x8125, lo: 0x88, hi: 0x8b}, + // Block 0x25, offset 0xe0 + {value: 0x0000, lo: 0x04}, + {value: 0x812d, lo: 0x98, hi: 0x99}, + {value: 0x812d, lo: 0xb5, hi: 0xb5}, + {value: 0x812d, lo: 0xb7, hi: 0xb7}, + {value: 0x812b, lo: 0xb9, hi: 0xb9}, + // Block 0x26, offset 0xe5 + {value: 0x0000, lo: 0x10}, + {value: 0x2644, lo: 0x83, hi: 0x83}, + {value: 0x264b, lo: 0x8d, hi: 0x8d}, + {value: 0x2652, lo: 0x92, hi: 0x92}, + {value: 0x2659, lo: 0x97, hi: 0x97}, + {value: 0x2660, lo: 0x9c, hi: 0x9c}, + {value: 0x263d, lo: 0xa9, hi: 0xa9}, + {value: 0x8126, lo: 0xb1, hi: 0xb1}, + {value: 0x8127, lo: 0xb2, hi: 0xb2}, + {value: 0x4a84, lo: 0xb3, hi: 0xb3}, + {value: 0x8128, lo: 0xb4, hi: 0xb4}, + {value: 0x4a8d, lo: 0xb5, hi: 0xb5}, + {value: 0x45b4, lo: 0xb6, hi: 0xb6}, + {value: 0x8200, lo: 0xb7, hi: 0xb7}, + {value: 0x45bc, lo: 0xb8, hi: 0xb8}, + {value: 0x8200, lo: 0xb9, hi: 0xb9}, + {value: 0x8127, lo: 0xba, hi: 0xbd}, + // Block 0x27, offset 0xf6 + {value: 0x0000, lo: 0x0b}, + {value: 0x8127, lo: 0x80, hi: 0x80}, + {value: 0x4a96, lo: 0x81, hi: 0x81}, + {value: 0x8132, lo: 0x82, hi: 0x83}, + {value: 0x8104, lo: 0x84, hi: 0x84}, + {value: 0x8132, lo: 0x86, hi: 0x87}, + {value: 0x266e, lo: 0x93, hi: 0x93}, + {value: 0x2675, lo: 0x9d, hi: 0x9d}, + {value: 0x267c, lo: 0xa2, hi: 0xa2}, + {value: 0x2683, lo: 0xa7, hi: 0xa7}, + {value: 0x268a, lo: 0xac, hi: 0xac}, + {value: 0x2667, lo: 0xb9, hi: 0xb9}, + // Block 0x28, offset 0x102 + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0x86, hi: 0x86}, + // Block 0x29, offset 0x104 + {value: 0x0000, lo: 0x05}, + {value: 0xa000, lo: 0xa5, hi: 0xa5}, + {value: 0x2d1e, lo: 0xa6, hi: 0xa6}, + {value: 0x9900, lo: 0xae, hi: 0xae}, + {value: 0x8102, lo: 0xb7, hi: 0xb7}, + {value: 0x8104, lo: 0xb9, hi: 0xba}, + // Block 0x2a, offset 0x10a + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0x8d, hi: 0x8d}, + // Block 0x2b, offset 0x10c + {value: 0x0000, lo: 0x01}, + {value: 0xa000, lo: 0x80, hi: 0x92}, + // Block 0x2c, offset 0x10e + {value: 0x0000, lo: 0x01}, + {value: 0xb900, lo: 0xa1, hi: 0xb5}, + // Block 0x2d, offset 0x110 + {value: 0x0000, lo: 0x01}, + {value: 0x9900, lo: 0xa8, hi: 0xbf}, + // Block 0x2e, offset 0x112 + {value: 0x0000, lo: 0x01}, + {value: 0x9900, lo: 0x80, hi: 0x82}, + // Block 0x2f, offset 0x114 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0x9d, hi: 0x9f}, + // Block 0x30, offset 0x116 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x94, hi: 0x94}, + {value: 0x8104, lo: 0xb4, hi: 0xb4}, + // Block 0x31, offset 0x119 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x92, hi: 0x92}, + {value: 0x8132, lo: 0x9d, hi: 0x9d}, + // Block 0x32, offset 0x11c + {value: 0x0000, lo: 0x01}, + {value: 0x8131, lo: 0xa9, hi: 0xa9}, + // Block 0x33, offset 0x11e + {value: 0x0004, lo: 0x02}, + {value: 0x812e, lo: 0xb9, hi: 0xba}, + {value: 0x812d, lo: 0xbb, hi: 0xbb}, + // Block 0x34, offset 0x121 + {value: 0x0000, lo: 0x02}, + {value: 0x8132, lo: 0x97, hi: 0x97}, + {value: 0x812d, lo: 0x98, hi: 0x98}, + // Block 0x35, offset 0x124 + {value: 0x0000, lo: 0x03}, + {value: 0x8104, lo: 0xa0, hi: 0xa0}, + {value: 0x8132, lo: 0xb5, hi: 0xbc}, + {value: 0x812d, lo: 0xbf, hi: 0xbf}, + // Block 0x36, offset 0x128 + {value: 0x0000, lo: 0x04}, + {value: 0x8132, lo: 0xb0, hi: 0xb4}, + {value: 0x812d, lo: 0xb5, hi: 0xba}, + {value: 0x8132, lo: 0xbb, hi: 0xbc}, + {value: 0x812d, lo: 0xbd, hi: 0xbd}, + // Block 0x37, offset 0x12d + {value: 0x0000, lo: 0x08}, + {value: 0x2d66, lo: 0x80, hi: 0x80}, + {value: 0x2d6e, lo: 0x81, hi: 0x81}, + {value: 0xa000, lo: 0x82, hi: 0x82}, + {value: 0x2d76, lo: 0x83, hi: 0x83}, + {value: 0x8104, lo: 0x84, hi: 0x84}, + {value: 0x8132, lo: 0xab, hi: 0xab}, + {value: 0x812d, lo: 0xac, hi: 0xac}, + {value: 0x8132, lo: 0xad, hi: 0xb3}, + // Block 0x38, offset 0x136 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0xaa, hi: 0xab}, + // Block 0x39, offset 0x138 + {value: 0x0000, lo: 0x02}, + {value: 0x8102, lo: 0xa6, hi: 0xa6}, + {value: 0x8104, lo: 0xb2, hi: 0xb3}, + // Block 0x3a, offset 0x13b + {value: 0x0000, lo: 0x01}, + {value: 0x8102, lo: 0xb7, hi: 0xb7}, + // Block 0x3b, offset 0x13d + {value: 0x0000, lo: 0x0a}, + {value: 0x8132, lo: 0x90, hi: 0x92}, + {value: 0x8101, lo: 0x94, hi: 0x94}, + {value: 0x812d, lo: 0x95, hi: 0x99}, + {value: 0x8132, lo: 0x9a, hi: 0x9b}, + {value: 0x812d, lo: 0x9c, hi: 0x9f}, + {value: 0x8132, lo: 0xa0, hi: 0xa0}, + {value: 0x8101, lo: 0xa2, hi: 0xa8}, + {value: 0x812d, lo: 0xad, hi: 0xad}, + {value: 0x8132, lo: 0xb4, hi: 0xb4}, + {value: 0x8132, lo: 0xb8, hi: 0xb9}, + // Block 0x3c, offset 0x148 + {value: 0x0004, lo: 0x03}, + {value: 0x0433, lo: 0x80, hi: 0x81}, + {value: 0x8100, lo: 0x97, hi: 0x97}, + {value: 0x8100, lo: 0xbe, hi: 0xbe}, + // Block 0x3d, offset 0x14c + {value: 0x0000, lo: 0x0d}, + {value: 0x8132, lo: 0x90, hi: 0x91}, + {value: 0x8101, lo: 0x92, hi: 0x93}, + {value: 0x8132, lo: 0x94, hi: 0x97}, + {value: 0x8101, lo: 0x98, hi: 0x9a}, + {value: 0x8132, lo: 0x9b, hi: 0x9c}, + {value: 0x8132, lo: 0xa1, hi: 0xa1}, + {value: 0x8101, lo: 0xa5, hi: 0xa6}, + {value: 0x8132, lo: 0xa7, hi: 0xa7}, + {value: 0x812d, lo: 0xa8, hi: 0xa8}, + {value: 0x8132, lo: 0xa9, hi: 0xa9}, + {value: 0x8101, lo: 0xaa, hi: 0xab}, + {value: 0x812d, lo: 0xac, hi: 0xaf}, + {value: 0x8132, lo: 0xb0, hi: 0xb0}, + // Block 0x3e, offset 0x15a + {value: 0x427b, lo: 0x02}, + {value: 0x01b8, lo: 0xa6, hi: 0xa6}, + {value: 0x0057, lo: 0xaa, hi: 0xab}, + // Block 0x3f, offset 0x15d + {value: 0x0007, lo: 0x05}, + {value: 0xa000, lo: 0x90, hi: 0x90}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0xa000, lo: 0x94, hi: 0x94}, + {value: 0x3bb9, lo: 0x9a, hi: 0x9b}, + {value: 0x3bc7, lo: 0xae, hi: 0xae}, + // Block 0x40, offset 0x163 + {value: 0x000e, lo: 0x05}, + {value: 0x3bce, lo: 0x8d, hi: 0x8e}, + {value: 0x3bd5, lo: 0x8f, hi: 0x8f}, + {value: 0xa000, lo: 0x90, hi: 0x90}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0xa000, lo: 0x94, hi: 0x94}, + // Block 0x41, offset 0x169 + {value: 0x6408, lo: 0x0a}, + {value: 0xa000, lo: 0x83, hi: 0x83}, + {value: 0x3be3, lo: 0x84, hi: 0x84}, + {value: 0xa000, lo: 0x88, hi: 0x88}, + {value: 0x3bea, lo: 0x89, hi: 0x89}, + {value: 0xa000, lo: 0x8b, hi: 0x8b}, + {value: 0x3bf1, lo: 0x8c, hi: 0x8c}, + {value: 0xa000, lo: 0xa3, hi: 0xa3}, + {value: 0x3bf8, lo: 0xa4, hi: 0xa5}, + {value: 0x3bff, lo: 0xa6, hi: 0xa6}, + {value: 0xa000, lo: 0xbc, hi: 0xbc}, + // Block 0x42, offset 0x174 + {value: 0x0007, lo: 0x03}, + {value: 0x3c68, lo: 0xa0, hi: 0xa1}, + {value: 0x3c92, lo: 0xa2, hi: 0xa3}, + {value: 0x3cbc, lo: 0xaa, hi: 0xad}, + // Block 0x43, offset 0x178 + {value: 0x0004, lo: 0x01}, + {value: 0x048b, lo: 0xa9, hi: 0xaa}, + // Block 0x44, offset 0x17a + {value: 0x0000, lo: 0x01}, + {value: 0x44dd, lo: 0x9c, hi: 0x9c}, + // Block 0x45, offset 0x17c + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xaf, hi: 0xb1}, + // Block 0x46, offset 0x17e + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0xbf, hi: 0xbf}, + // Block 0x47, offset 0x180 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xa0, hi: 0xbf}, + // Block 0x48, offset 0x182 + {value: 0x0000, lo: 0x05}, + {value: 0x812c, lo: 0xaa, hi: 0xaa}, + {value: 0x8131, lo: 0xab, hi: 0xab}, + {value: 0x8133, lo: 0xac, hi: 0xac}, + {value: 0x812e, lo: 0xad, hi: 0xad}, + {value: 0x812f, lo: 0xae, hi: 0xaf}, + // Block 0x49, offset 0x188 + {value: 0x0000, lo: 0x03}, + {value: 0x4a9f, lo: 0xb3, hi: 0xb3}, + {value: 0x4a9f, lo: 0xb5, hi: 0xb6}, + {value: 0x4a9f, lo: 0xba, hi: 0xbf}, + // Block 0x4a, offset 0x18c + {value: 0x0000, lo: 0x01}, + {value: 0x4a9f, lo: 0x8f, hi: 0xa3}, + // Block 0x4b, offset 0x18e + {value: 0x0000, lo: 0x01}, + {value: 0x8100, lo: 0xae, hi: 0xbe}, + // Block 0x4c, offset 0x190 + {value: 0x0000, lo: 0x07}, + {value: 0x8100, lo: 0x84, hi: 0x84}, + {value: 0x8100, lo: 0x87, hi: 0x87}, + {value: 0x8100, lo: 0x90, hi: 0x90}, + {value: 0x8100, lo: 0x9e, hi: 0x9e}, + {value: 0x8100, lo: 0xa1, hi: 0xa1}, + {value: 0x8100, lo: 0xb2, hi: 0xb2}, + {value: 0x8100, lo: 0xbb, hi: 0xbb}, + // Block 0x4d, offset 0x198 + {value: 0x0000, lo: 0x03}, + {value: 0x8100, lo: 0x80, hi: 0x80}, + {value: 0x8100, lo: 0x8b, hi: 0x8b}, + {value: 0x8100, lo: 0x8e, hi: 0x8e}, + // Block 0x4e, offset 0x19c + {value: 0x0000, lo: 0x02}, + {value: 0x8132, lo: 0xaf, hi: 0xaf}, + {value: 0x8132, lo: 0xb4, hi: 0xbd}, + // Block 0x4f, offset 0x19f + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0x9e, hi: 0x9f}, + // Block 0x50, offset 0x1a1 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xb0, hi: 0xb1}, + // Block 0x51, offset 0x1a3 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x86, hi: 0x86}, + // Block 0x52, offset 0x1a5 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x84, hi: 0x84}, + {value: 0x8132, lo: 0xa0, hi: 0xb1}, + // Block 0x53, offset 0x1a8 + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0xab, hi: 0xad}, + // Block 0x54, offset 0x1aa + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x93, hi: 0x93}, + // Block 0x55, offset 0x1ac + {value: 0x0000, lo: 0x01}, + {value: 0x8102, lo: 0xb3, hi: 0xb3}, + // Block 0x56, offset 0x1ae + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x80, hi: 0x80}, + // Block 0x57, offset 0x1b0 + {value: 0x0000, lo: 0x05}, + {value: 0x8132, lo: 0xb0, hi: 0xb0}, + {value: 0x8132, lo: 0xb2, hi: 0xb3}, + {value: 0x812d, lo: 0xb4, hi: 0xb4}, + {value: 0x8132, lo: 0xb7, hi: 0xb8}, + {value: 0x8132, lo: 0xbe, hi: 0xbf}, + // Block 0x58, offset 0x1b6 + {value: 0x0000, lo: 0x02}, + {value: 0x8132, lo: 0x81, hi: 0x81}, + {value: 0x8104, lo: 0xb6, hi: 0xb6}, + // Block 0x59, offset 0x1b9 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0xad, hi: 0xad}, + // Block 0x5a, offset 0x1bb + {value: 0x0000, lo: 0x06}, + {value: 0xe500, lo: 0x80, hi: 0x80}, + {value: 0xc600, lo: 0x81, hi: 0x9b}, + {value: 0xe500, lo: 0x9c, hi: 0x9c}, + {value: 0xc600, lo: 0x9d, hi: 0xb7}, + {value: 0xe500, lo: 0xb8, hi: 0xb8}, + {value: 0xc600, lo: 0xb9, hi: 0xbf}, + // Block 0x5b, offset 0x1c2 + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x93}, + {value: 0xe500, lo: 0x94, hi: 0x94}, + {value: 0xc600, lo: 0x95, hi: 0xaf}, + {value: 0xe500, lo: 0xb0, hi: 0xb0}, + {value: 0xc600, lo: 0xb1, hi: 0xbf}, + // Block 0x5c, offset 0x1c8 + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x8b}, + {value: 0xe500, lo: 0x8c, hi: 0x8c}, + {value: 0xc600, lo: 0x8d, hi: 0xa7}, + {value: 0xe500, lo: 0xa8, hi: 0xa8}, + {value: 0xc600, lo: 0xa9, hi: 0xbf}, + // Block 0x5d, offset 0x1ce + {value: 0x0000, lo: 0x07}, + {value: 0xc600, lo: 0x80, hi: 0x83}, + {value: 0xe500, lo: 0x84, hi: 0x84}, + {value: 0xc600, lo: 0x85, hi: 0x9f}, + {value: 0xe500, lo: 0xa0, hi: 0xa0}, + {value: 0xc600, lo: 0xa1, hi: 0xbb}, + {value: 0xe500, lo: 0xbc, hi: 0xbc}, + {value: 0xc600, lo: 0xbd, hi: 0xbf}, + // Block 0x5e, offset 0x1d6 + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x97}, + {value: 0xe500, lo: 0x98, hi: 0x98}, + {value: 0xc600, lo: 0x99, hi: 0xb3}, + {value: 0xe500, lo: 0xb4, hi: 0xb4}, + {value: 0xc600, lo: 0xb5, hi: 0xbf}, + // Block 0x5f, offset 0x1dc + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x8f}, + {value: 0xe500, lo: 0x90, hi: 0x90}, + {value: 0xc600, lo: 0x91, hi: 0xab}, + {value: 0xe500, lo: 0xac, hi: 0xac}, + {value: 0xc600, lo: 0xad, hi: 0xbf}, + // Block 0x60, offset 0x1e2 + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x87}, + {value: 0xe500, lo: 0x88, hi: 0x88}, + {value: 0xc600, lo: 0x89, hi: 0xa3}, + {value: 0xe500, lo: 0xa4, hi: 0xa4}, + {value: 0xc600, lo: 0xa5, hi: 0xbf}, + // Block 0x61, offset 0x1e8 + {value: 0x0000, lo: 0x03}, + {value: 0xc600, lo: 0x80, hi: 0x87}, + {value: 0xe500, lo: 0x88, hi: 0x88}, + {value: 0xc600, lo: 0x89, hi: 0xa3}, + // Block 0x62, offset 0x1ec + {value: 0x0006, lo: 0x0d}, + {value: 0x4390, lo: 0x9d, hi: 0x9d}, + {value: 0x8115, lo: 0x9e, hi: 0x9e}, + {value: 0x4402, lo: 0x9f, hi: 0x9f}, + {value: 0x43f0, lo: 0xaa, hi: 0xab}, + {value: 0x44f4, lo: 0xac, hi: 0xac}, + {value: 0x44fc, lo: 0xad, hi: 0xad}, + {value: 0x4348, lo: 0xae, hi: 0xb1}, + {value: 0x4366, lo: 0xb2, hi: 0xb4}, + {value: 0x437e, lo: 0xb5, hi: 0xb6}, + {value: 0x438a, lo: 0xb8, hi: 0xb8}, + {value: 0x4396, lo: 0xb9, hi: 0xbb}, + {value: 0x43ae, lo: 0xbc, hi: 0xbc}, + {value: 0x43b4, lo: 0xbe, hi: 0xbe}, + // Block 0x63, offset 0x1fa + {value: 0x0006, lo: 0x08}, + {value: 0x43ba, lo: 0x80, hi: 0x81}, + {value: 0x43c6, lo: 0x83, hi: 0x84}, + {value: 0x43d8, lo: 0x86, hi: 0x89}, + {value: 0x43fc, lo: 0x8a, hi: 0x8a}, + {value: 0x4378, lo: 0x8b, hi: 0x8b}, + {value: 0x4360, lo: 0x8c, hi: 0x8c}, + {value: 0x43a8, lo: 0x8d, hi: 0x8d}, + {value: 0x43d2, lo: 0x8e, hi: 0x8e}, + // Block 0x64, offset 0x203 + {value: 0x0000, lo: 0x02}, + {value: 0x8100, lo: 0xa4, hi: 0xa5}, + {value: 0x8100, lo: 0xb0, hi: 0xb1}, + // Block 0x65, offset 0x206 + {value: 0x0000, lo: 0x02}, + {value: 0x8100, lo: 0x9b, hi: 0x9d}, + {value: 0x8200, lo: 0x9e, hi: 0xa3}, + // Block 0x66, offset 0x209 + {value: 0x0000, lo: 0x01}, + {value: 0x8100, lo: 0x90, hi: 0x90}, + // Block 0x67, offset 0x20b + {value: 0x0000, lo: 0x02}, + {value: 0x8100, lo: 0x99, hi: 0x99}, + {value: 0x8200, lo: 0xb2, hi: 0xb4}, + // Block 0x68, offset 0x20e + {value: 0x0000, lo: 0x01}, + {value: 0x8100, lo: 0xbc, hi: 0xbd}, + // Block 0x69, offset 0x210 + {value: 0x0000, lo: 0x03}, + {value: 0x8132, lo: 0xa0, hi: 0xa6}, + {value: 0x812d, lo: 0xa7, hi: 0xad}, + {value: 0x8132, lo: 0xae, hi: 0xaf}, + // Block 0x6a, offset 0x214 + {value: 0x0000, lo: 0x04}, + {value: 0x8100, lo: 0x89, hi: 0x8c}, + {value: 0x8100, lo: 0xb0, hi: 0xb2}, + {value: 0x8100, lo: 0xb4, hi: 0xb4}, + {value: 0x8100, lo: 0xb6, hi: 0xbf}, + // Block 0x6b, offset 0x219 + {value: 0x0000, lo: 0x01}, + {value: 0x8100, lo: 0x81, hi: 0x8c}, + // Block 0x6c, offset 0x21b + {value: 0x0000, lo: 0x01}, + {value: 0x8100, lo: 0xb5, hi: 0xba}, + // Block 0x6d, offset 0x21d + {value: 0x0000, lo: 0x04}, + {value: 0x4a9f, lo: 0x9e, hi: 0x9f}, + {value: 0x4a9f, lo: 0xa3, hi: 0xa3}, + {value: 0x4a9f, lo: 0xa5, hi: 0xa6}, + {value: 0x4a9f, lo: 0xaa, hi: 0xaf}, + // Block 0x6e, offset 0x222 + {value: 0x0000, lo: 0x05}, + {value: 0x4a9f, lo: 0x82, hi: 0x87}, + {value: 0x4a9f, lo: 0x8a, hi: 0x8f}, + {value: 0x4a9f, lo: 0x92, hi: 0x97}, + {value: 0x4a9f, lo: 0x9a, hi: 0x9c}, + {value: 0x8100, lo: 0xa3, hi: 0xa3}, + // Block 0x6f, offset 0x228 + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0xbd, hi: 0xbd}, + // Block 0x70, offset 0x22a + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0xa0, hi: 0xa0}, + // Block 0x71, offset 0x22c + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xb6, hi: 0xba}, + // Block 0x72, offset 0x22e + {value: 0x002c, lo: 0x05}, + {value: 0x812d, lo: 0x8d, hi: 0x8d}, + {value: 0x8132, lo: 0x8f, hi: 0x8f}, + {value: 0x8132, lo: 0xb8, hi: 0xb8}, + {value: 0x8101, lo: 0xb9, hi: 0xba}, + {value: 0x8104, lo: 0xbf, hi: 0xbf}, + // Block 0x73, offset 0x234 + {value: 0x0000, lo: 0x02}, + {value: 0x8132, lo: 0xa5, hi: 0xa5}, + {value: 0x812d, lo: 0xa6, hi: 0xa6}, + // Block 0x74, offset 0x237 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x86, hi: 0x86}, + {value: 0x8104, lo: 0xbf, hi: 0xbf}, + // Block 0x75, offset 0x23a + {value: 0x17fe, lo: 0x07}, + {value: 0xa000, lo: 0x99, hi: 0x99}, + {value: 0x4238, lo: 0x9a, hi: 0x9a}, + {value: 0xa000, lo: 0x9b, hi: 0x9b}, + {value: 0x4242, lo: 0x9c, hi: 0x9c}, + {value: 0xa000, lo: 0xa5, hi: 0xa5}, + {value: 0x424c, lo: 0xab, hi: 0xab}, + {value: 0x8104, lo: 0xb9, hi: 0xba}, + // Block 0x76, offset 0x242 + {value: 0x0000, lo: 0x06}, + {value: 0x8132, lo: 0x80, hi: 0x82}, + {value: 0x9900, lo: 0xa7, hi: 0xa7}, + {value: 0x2d7e, lo: 0xae, hi: 0xae}, + {value: 0x2d88, lo: 0xaf, hi: 0xaf}, + {value: 0xa000, lo: 0xb1, hi: 0xb2}, + {value: 0x8104, lo: 0xb3, hi: 0xb4}, + // Block 0x77, offset 0x249 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x80, hi: 0x80}, + {value: 0x8102, lo: 0x8a, hi: 0x8a}, + // Block 0x78, offset 0x24c + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0xb5, hi: 0xb5}, + {value: 0x8102, lo: 0xb6, hi: 0xb6}, + // Block 0x79, offset 0x24f + {value: 0x0002, lo: 0x01}, + {value: 0x8102, lo: 0xa9, hi: 0xaa}, + // Block 0x7a, offset 0x251 + {value: 0x0000, lo: 0x07}, + {value: 0xa000, lo: 0x87, hi: 0x87}, + {value: 0x2d92, lo: 0x8b, hi: 0x8b}, + {value: 0x2d9c, lo: 0x8c, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x97, hi: 0x97}, + {value: 0x8132, lo: 0xa6, hi: 0xac}, + {value: 0x8132, lo: 0xb0, hi: 0xb4}, + // Block 0x7b, offset 0x259 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x82, hi: 0x82}, + {value: 0x8102, lo: 0x86, hi: 0x86}, + // Block 0x7c, offset 0x25c + {value: 0x6b5a, lo: 0x06}, + {value: 0x9900, lo: 0xb0, hi: 0xb0}, + {value: 0xa000, lo: 0xb9, hi: 0xb9}, + {value: 0x9900, lo: 0xba, hi: 0xba}, + {value: 0x2db0, lo: 0xbb, hi: 0xbb}, + {value: 0x2da6, lo: 0xbc, hi: 0xbd}, + {value: 0x2dba, lo: 0xbe, hi: 0xbe}, + // Block 0x7d, offset 0x263 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x82, hi: 0x82}, + {value: 0x8102, lo: 0x83, hi: 0x83}, + // Block 0x7e, offset 0x266 + {value: 0x0000, lo: 0x05}, + {value: 0x9900, lo: 0xaf, hi: 0xaf}, + {value: 0xa000, lo: 0xb8, hi: 0xb9}, + {value: 0x2dc4, lo: 0xba, hi: 0xba}, + {value: 0x2dce, lo: 0xbb, hi: 0xbb}, + {value: 0x8104, lo: 0xbf, hi: 0xbf}, + // Block 0x7f, offset 0x26c + {value: 0x0000, lo: 0x01}, + {value: 0x8102, lo: 0x80, hi: 0x80}, + // Block 0x80, offset 0x26e + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0xb6, hi: 0xb6}, + {value: 0x8102, lo: 0xb7, hi: 0xb7}, + // Block 0x81, offset 0x271 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0xab, hi: 0xab}, + // Block 0x82, offset 0x273 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0xb4, hi: 0xb4}, + // Block 0x83, offset 0x275 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x87, hi: 0x87}, + // Block 0x84, offset 0x277 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x99, hi: 0x99}, + // Block 0x85, offset 0x279 + {value: 0x0000, lo: 0x02}, + {value: 0x8102, lo: 0x82, hi: 0x82}, + {value: 0x8104, lo: 0x84, hi: 0x85}, + // Block 0x86, offset 0x27c + {value: 0x0000, lo: 0x01}, + {value: 0x8101, lo: 0xb0, hi: 0xb4}, + // Block 0x87, offset 0x27e + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xb0, hi: 0xb6}, + // Block 0x88, offset 0x280 + {value: 0x0000, lo: 0x01}, + {value: 0x8101, lo: 0x9e, hi: 0x9e}, + // Block 0x89, offset 0x282 + {value: 0x0000, lo: 0x0c}, + {value: 0x45cc, lo: 0x9e, hi: 0x9e}, + {value: 0x45d6, lo: 0x9f, hi: 0x9f}, + {value: 0x460a, lo: 0xa0, hi: 0xa0}, + {value: 0x4618, lo: 0xa1, hi: 0xa1}, + {value: 0x4626, lo: 0xa2, hi: 0xa2}, + {value: 0x4634, lo: 0xa3, hi: 0xa3}, + {value: 0x4642, lo: 0xa4, hi: 0xa4}, + {value: 0x812b, lo: 0xa5, hi: 0xa6}, + {value: 0x8101, lo: 0xa7, hi: 0xa9}, + {value: 0x8130, lo: 0xad, hi: 0xad}, + {value: 0x812b, lo: 0xae, hi: 0xb2}, + {value: 0x812d, lo: 0xbb, hi: 0xbf}, + // Block 0x8a, offset 0x28f + {value: 0x0000, lo: 0x09}, + {value: 0x812d, lo: 0x80, hi: 0x82}, + {value: 0x8132, lo: 0x85, hi: 0x89}, + {value: 0x812d, lo: 0x8a, hi: 0x8b}, + {value: 0x8132, lo: 0xaa, hi: 0xad}, + {value: 0x45e0, lo: 0xbb, hi: 0xbb}, + {value: 0x45ea, lo: 0xbc, hi: 0xbc}, + {value: 0x4650, lo: 0xbd, hi: 0xbd}, + {value: 0x466c, lo: 0xbe, hi: 0xbe}, + {value: 0x465e, lo: 0xbf, hi: 0xbf}, + // Block 0x8b, offset 0x299 + {value: 0x0000, lo: 0x01}, + {value: 0x467a, lo: 0x80, hi: 0x80}, + // Block 0x8c, offset 0x29b + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0x82, hi: 0x84}, + // Block 0x8d, offset 0x29d + {value: 0x0000, lo: 0x05}, + {value: 0x8132, lo: 0x80, hi: 0x86}, + {value: 0x8132, lo: 0x88, hi: 0x98}, + {value: 0x8132, lo: 0x9b, hi: 0xa1}, + {value: 0x8132, lo: 0xa3, hi: 0xa4}, + {value: 0x8132, lo: 0xa6, hi: 0xaa}, + // Block 0x8e, offset 0x2a3 + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0x90, hi: 0x96}, + // Block 0x8f, offset 0x2a5 + {value: 0x0000, lo: 0x02}, + {value: 0x8132, lo: 0x84, hi: 0x89}, + {value: 0x8102, lo: 0x8a, hi: 0x8a}, + // Block 0x90, offset 0x2a8 + {value: 0x0000, lo: 0x01}, + {value: 0x8100, lo: 0x93, hi: 0x93}, +} + +// lookup returns the trie value for the first UTF-8 encoding in s and +// the width in bytes of this encoding. The size will be 0 if s does not +// hold enough bytes to complete the encoding. len(s) must be greater than 0. +func (t *nfkcTrie) lookup(s []byte) (v uint16, sz int) { + c0 := s[0] + switch { + case c0 < 0x80: // is ASCII + return nfkcValues[c0], 1 + case c0 < 0xC2: + return 0, 1 // Illegal UTF-8: not a starter, not ASCII. + case c0 < 0xE0: // 2-byte UTF-8 + if len(s) < 2 { + return 0, 0 + } + i := nfkcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c1), 2 + case c0 < 0xF0: // 3-byte UTF-8 + if len(s) < 3 { + return 0, 0 + } + i := nfkcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = nfkcIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c2), 3 + case c0 < 0xF8: // 4-byte UTF-8 + if len(s) < 4 { + return 0, 0 + } + i := nfkcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = nfkcIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + o = uint32(i)<<6 + uint32(c2) + i = nfkcIndex[o] + c3 := s[3] + if c3 < 0x80 || 0xC0 <= c3 { + return 0, 3 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c3), 4 + } + // Illegal rune + return 0, 1 +} + +// lookupUnsafe returns the trie value for the first UTF-8 encoding in s. +// s must start with a full and valid UTF-8 encoded rune. +func (t *nfkcTrie) lookupUnsafe(s []byte) uint16 { + c0 := s[0] + if c0 < 0x80 { // is ASCII + return nfkcValues[c0] + } + i := nfkcIndex[c0] + if c0 < 0xE0 { // 2-byte UTF-8 + return t.lookupValue(uint32(i), s[1]) + } + i = nfkcIndex[uint32(i)<<6+uint32(s[1])] + if c0 < 0xF0 { // 3-byte UTF-8 + return t.lookupValue(uint32(i), s[2]) + } + i = nfkcIndex[uint32(i)<<6+uint32(s[2])] + if c0 < 0xF8 { // 4-byte UTF-8 + return t.lookupValue(uint32(i), s[3]) + } + return 0 +} + +// lookupString returns the trie value for the first UTF-8 encoding in s and +// the width in bytes of this encoding. The size will be 0 if s does not +// hold enough bytes to complete the encoding. len(s) must be greater than 0. +func (t *nfkcTrie) lookupString(s string) (v uint16, sz int) { + c0 := s[0] + switch { + case c0 < 0x80: // is ASCII + return nfkcValues[c0], 1 + case c0 < 0xC2: + return 0, 1 // Illegal UTF-8: not a starter, not ASCII. + case c0 < 0xE0: // 2-byte UTF-8 + if len(s) < 2 { + return 0, 0 + } + i := nfkcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c1), 2 + case c0 < 0xF0: // 3-byte UTF-8 + if len(s) < 3 { + return 0, 0 + } + i := nfkcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = nfkcIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c2), 3 + case c0 < 0xF8: // 4-byte UTF-8 + if len(s) < 4 { + return 0, 0 + } + i := nfkcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = nfkcIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + o = uint32(i)<<6 + uint32(c2) + i = nfkcIndex[o] + c3 := s[3] + if c3 < 0x80 || 0xC0 <= c3 { + return 0, 3 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c3), 4 + } + // Illegal rune + return 0, 1 +} + +// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s. +// s must start with a full and valid UTF-8 encoded rune. +func (t *nfkcTrie) lookupStringUnsafe(s string) uint16 { + c0 := s[0] + if c0 < 0x80 { // is ASCII + return nfkcValues[c0] + } + i := nfkcIndex[c0] + if c0 < 0xE0 { // 2-byte UTF-8 + return t.lookupValue(uint32(i), s[1]) + } + i = nfkcIndex[uint32(i)<<6+uint32(s[1])] + if c0 < 0xF0 { // 3-byte UTF-8 + return t.lookupValue(uint32(i), s[2]) + } + i = nfkcIndex[uint32(i)<<6+uint32(s[2])] + if c0 < 0xF8 { // 4-byte UTF-8 + return t.lookupValue(uint32(i), s[3]) + } + return 0 +} + +// nfkcTrie. Total size: 17104 bytes (16.70 KiB). Checksum: d985061cf5307b35. +type nfkcTrie struct{} + +func newNfkcTrie(i int) *nfkcTrie { + return &nfkcTrie{} +} + +// lookupValue determines the type of block n and looks up the value for b. +func (t *nfkcTrie) lookupValue(n uint32, b byte) uint16 { + switch { + case n < 91: + return uint16(nfkcValues[n<<6+uint32(b)]) + default: + n -= 91 + return uint16(nfkcSparse.lookup(n, b)) + } +} + +// nfkcValues: 93 blocks, 5952 entries, 11904 bytes +// The third block is the zero block. +var nfkcValues = [5952]uint16{ + // Block 0x0, offset 0x0 + 0x3c: 0xa000, 0x3d: 0xa000, 0x3e: 0xa000, + // Block 0x1, offset 0x40 + 0x41: 0xa000, 0x42: 0xa000, 0x43: 0xa000, 0x44: 0xa000, 0x45: 0xa000, + 0x46: 0xa000, 0x47: 0xa000, 0x48: 0xa000, 0x49: 0xa000, 0x4a: 0xa000, 0x4b: 0xa000, + 0x4c: 0xa000, 0x4d: 0xa000, 0x4e: 0xa000, 0x4f: 0xa000, 0x50: 0xa000, + 0x52: 0xa000, 0x53: 0xa000, 0x54: 0xa000, 0x55: 0xa000, 0x56: 0xa000, 0x57: 0xa000, + 0x58: 0xa000, 0x59: 0xa000, 0x5a: 0xa000, + 0x61: 0xa000, 0x62: 0xa000, 0x63: 0xa000, + 0x64: 0xa000, 0x65: 0xa000, 0x66: 0xa000, 0x67: 0xa000, 0x68: 0xa000, 0x69: 0xa000, + 0x6a: 0xa000, 0x6b: 0xa000, 0x6c: 0xa000, 0x6d: 0xa000, 0x6e: 0xa000, 0x6f: 0xa000, + 0x70: 0xa000, 0x72: 0xa000, 0x73: 0xa000, 0x74: 0xa000, 0x75: 0xa000, + 0x76: 0xa000, 0x77: 0xa000, 0x78: 0xa000, 0x79: 0xa000, 0x7a: 0xa000, + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0xc0: 0x2f6f, 0xc1: 0x2f74, 0xc2: 0x4688, 0xc3: 0x2f79, 0xc4: 0x4697, 0xc5: 0x469c, + 0xc6: 0xa000, 0xc7: 0x46a6, 0xc8: 0x2fe2, 0xc9: 0x2fe7, 0xca: 0x46ab, 0xcb: 0x2ffb, + 0xcc: 0x306e, 0xcd: 0x3073, 0xce: 0x3078, 0xcf: 0x46bf, 0xd1: 0x3104, + 0xd2: 0x3127, 0xd3: 0x312c, 0xd4: 0x46c9, 0xd5: 0x46ce, 0xd6: 0x46dd, + 0xd8: 0xa000, 0xd9: 0x31b3, 0xda: 0x31b8, 0xdb: 0x31bd, 0xdc: 0x470f, 0xdd: 0x3235, + 0xe0: 0x327b, 0xe1: 0x3280, 0xe2: 0x4719, 0xe3: 0x3285, + 0xe4: 0x4728, 0xe5: 0x472d, 0xe6: 0xa000, 0xe7: 0x4737, 0xe8: 0x32ee, 0xe9: 0x32f3, + 0xea: 0x473c, 0xeb: 0x3307, 0xec: 0x337f, 0xed: 0x3384, 0xee: 0x3389, 0xef: 0x4750, + 0xf1: 0x3415, 0xf2: 0x3438, 0xf3: 0x343d, 0xf4: 0x475a, 0xf5: 0x475f, + 0xf6: 0x476e, 0xf8: 0xa000, 0xf9: 0x34c9, 0xfa: 0x34ce, 0xfb: 0x34d3, + 0xfc: 0x47a0, 0xfd: 0x3550, 0xff: 0x3569, + // Block 0x4, offset 0x100 + 0x100: 0x2f7e, 0x101: 0x328a, 0x102: 0x468d, 0x103: 0x471e, 0x104: 0x2f9c, 0x105: 0x32a8, + 0x106: 0x2fb0, 0x107: 0x32bc, 0x108: 0x2fb5, 0x109: 0x32c1, 0x10a: 0x2fba, 0x10b: 0x32c6, + 0x10c: 0x2fbf, 0x10d: 0x32cb, 0x10e: 0x2fc9, 0x10f: 0x32d5, + 0x112: 0x46b0, 0x113: 0x4741, 0x114: 0x2ff1, 0x115: 0x32fd, 0x116: 0x2ff6, 0x117: 0x3302, + 0x118: 0x3014, 0x119: 0x3320, 0x11a: 0x3005, 0x11b: 0x3311, 0x11c: 0x302d, 0x11d: 0x3339, + 0x11e: 0x3037, 0x11f: 0x3343, 0x120: 0x303c, 0x121: 0x3348, 0x122: 0x3046, 0x123: 0x3352, + 0x124: 0x304b, 0x125: 0x3357, 0x128: 0x307d, 0x129: 0x338e, + 0x12a: 0x3082, 0x12b: 0x3393, 0x12c: 0x3087, 0x12d: 0x3398, 0x12e: 0x30aa, 0x12f: 0x33b6, + 0x130: 0x308c, 0x132: 0x195d, 0x133: 0x19e7, 0x134: 0x30b4, 0x135: 0x33c0, + 0x136: 0x30c8, 0x137: 0x33d9, 0x139: 0x30d2, 0x13a: 0x33e3, 0x13b: 0x30dc, + 0x13c: 0x33ed, 0x13d: 0x30d7, 0x13e: 0x33e8, 0x13f: 0x1bac, + // Block 0x5, offset 0x140 + 0x140: 0x1c34, 0x143: 0x30ff, 0x144: 0x3410, 0x145: 0x3118, + 0x146: 0x3429, 0x147: 0x310e, 0x148: 0x341f, 0x149: 0x1c5c, + 0x14c: 0x46d3, 0x14d: 0x4764, 0x14e: 0x3131, 0x14f: 0x3442, 0x150: 0x313b, 0x151: 0x344c, + 0x154: 0x3159, 0x155: 0x346a, 0x156: 0x3172, 0x157: 0x3483, + 0x158: 0x3163, 0x159: 0x3474, 0x15a: 0x46f6, 0x15b: 0x4787, 0x15c: 0x317c, 0x15d: 0x348d, + 0x15e: 0x318b, 0x15f: 0x349c, 0x160: 0x46fb, 0x161: 0x478c, 0x162: 0x31a4, 0x163: 0x34ba, + 0x164: 0x3195, 0x165: 0x34ab, 0x168: 0x4705, 0x169: 0x4796, + 0x16a: 0x470a, 0x16b: 0x479b, 0x16c: 0x31c2, 0x16d: 0x34d8, 0x16e: 0x31cc, 0x16f: 0x34e2, + 0x170: 0x31d1, 0x171: 0x34e7, 0x172: 0x31ef, 0x173: 0x3505, 0x174: 0x3212, 0x175: 0x3528, + 0x176: 0x323a, 0x177: 0x3555, 0x178: 0x324e, 0x179: 0x325d, 0x17a: 0x357d, 0x17b: 0x3267, + 0x17c: 0x3587, 0x17d: 0x326c, 0x17e: 0x358c, 0x17f: 0x00a7, + // Block 0x6, offset 0x180 + 0x184: 0x2dee, 0x185: 0x2df4, + 0x186: 0x2dfa, 0x187: 0x1972, 0x188: 0x1975, 0x189: 0x1a08, 0x18a: 0x1987, 0x18b: 0x198a, + 0x18c: 0x1a3e, 0x18d: 0x2f88, 0x18e: 0x3294, 0x18f: 0x3096, 0x190: 0x33a2, 0x191: 0x3140, + 0x192: 0x3451, 0x193: 0x31d6, 0x194: 0x34ec, 0x195: 0x39cf, 0x196: 0x3b5e, 0x197: 0x39c8, + 0x198: 0x3b57, 0x199: 0x39d6, 0x19a: 0x3b65, 0x19b: 0x39c1, 0x19c: 0x3b50, + 0x19e: 0x38b0, 0x19f: 0x3a3f, 0x1a0: 0x38a9, 0x1a1: 0x3a38, 0x1a2: 0x35b3, 0x1a3: 0x35c5, + 0x1a6: 0x3041, 0x1a7: 0x334d, 0x1a8: 0x30be, 0x1a9: 0x33cf, + 0x1aa: 0x46ec, 0x1ab: 0x477d, 0x1ac: 0x3990, 0x1ad: 0x3b1f, 0x1ae: 0x35d7, 0x1af: 0x35dd, + 0x1b0: 0x33c5, 0x1b1: 0x1942, 0x1b2: 0x1945, 0x1b3: 0x19cf, 0x1b4: 0x3028, 0x1b5: 0x3334, + 0x1b8: 0x30fa, 0x1b9: 0x340b, 0x1ba: 0x38b7, 0x1bb: 0x3a46, + 0x1bc: 0x35ad, 0x1bd: 0x35bf, 0x1be: 0x35b9, 0x1bf: 0x35cb, + // Block 0x7, offset 0x1c0 + 0x1c0: 0x2f8d, 0x1c1: 0x3299, 0x1c2: 0x2f92, 0x1c3: 0x329e, 0x1c4: 0x300a, 0x1c5: 0x3316, + 0x1c6: 0x300f, 0x1c7: 0x331b, 0x1c8: 0x309b, 0x1c9: 0x33a7, 0x1ca: 0x30a0, 0x1cb: 0x33ac, + 0x1cc: 0x3145, 0x1cd: 0x3456, 0x1ce: 0x314a, 0x1cf: 0x345b, 0x1d0: 0x3168, 0x1d1: 0x3479, + 0x1d2: 0x316d, 0x1d3: 0x347e, 0x1d4: 0x31db, 0x1d5: 0x34f1, 0x1d6: 0x31e0, 0x1d7: 0x34f6, + 0x1d8: 0x3186, 0x1d9: 0x3497, 0x1da: 0x319f, 0x1db: 0x34b5, + 0x1de: 0x305a, 0x1df: 0x3366, + 0x1e6: 0x4692, 0x1e7: 0x4723, 0x1e8: 0x46ba, 0x1e9: 0x474b, + 0x1ea: 0x395f, 0x1eb: 0x3aee, 0x1ec: 0x393c, 0x1ed: 0x3acb, 0x1ee: 0x46d8, 0x1ef: 0x4769, + 0x1f0: 0x3958, 0x1f1: 0x3ae7, 0x1f2: 0x3244, 0x1f3: 0x355f, + // Block 0x8, offset 0x200 + 0x200: 0x9932, 0x201: 0x9932, 0x202: 0x9932, 0x203: 0x9932, 0x204: 0x9932, 0x205: 0x8132, + 0x206: 0x9932, 0x207: 0x9932, 0x208: 0x9932, 0x209: 0x9932, 0x20a: 0x9932, 0x20b: 0x9932, + 0x20c: 0x9932, 0x20d: 0x8132, 0x20e: 0x8132, 0x20f: 0x9932, 0x210: 0x8132, 0x211: 0x9932, + 0x212: 0x8132, 0x213: 0x9932, 0x214: 0x9932, 0x215: 0x8133, 0x216: 0x812d, 0x217: 0x812d, + 0x218: 0x812d, 0x219: 0x812d, 0x21a: 0x8133, 0x21b: 0x992b, 0x21c: 0x812d, 0x21d: 0x812d, + 0x21e: 0x812d, 0x21f: 0x812d, 0x220: 0x812d, 0x221: 0x8129, 0x222: 0x8129, 0x223: 0x992d, + 0x224: 0x992d, 0x225: 0x992d, 0x226: 0x992d, 0x227: 0x9929, 0x228: 0x9929, 0x229: 0x812d, + 0x22a: 0x812d, 0x22b: 0x812d, 0x22c: 0x812d, 0x22d: 0x992d, 0x22e: 0x992d, 0x22f: 0x812d, + 0x230: 0x992d, 0x231: 0x992d, 0x232: 0x812d, 0x233: 0x812d, 0x234: 0x8101, 0x235: 0x8101, + 0x236: 0x8101, 0x237: 0x8101, 0x238: 0x9901, 0x239: 0x812d, 0x23a: 0x812d, 0x23b: 0x812d, + 0x23c: 0x812d, 0x23d: 0x8132, 0x23e: 0x8132, 0x23f: 0x8132, + // Block 0x9, offset 0x240 + 0x240: 0x49ae, 0x241: 0x49b3, 0x242: 0x9932, 0x243: 0x49b8, 0x244: 0x4a71, 0x245: 0x9936, + 0x246: 0x8132, 0x247: 0x812d, 0x248: 0x812d, 0x249: 0x812d, 0x24a: 0x8132, 0x24b: 0x8132, + 0x24c: 0x8132, 0x24d: 0x812d, 0x24e: 0x812d, 0x250: 0x8132, 0x251: 0x8132, + 0x252: 0x8132, 0x253: 0x812d, 0x254: 0x812d, 0x255: 0x812d, 0x256: 0x812d, 0x257: 0x8132, + 0x258: 0x8133, 0x259: 0x812d, 0x25a: 0x812d, 0x25b: 0x8132, 0x25c: 0x8134, 0x25d: 0x8135, + 0x25e: 0x8135, 0x25f: 0x8134, 0x260: 0x8135, 0x261: 0x8135, 0x262: 0x8134, 0x263: 0x8132, + 0x264: 0x8132, 0x265: 0x8132, 0x266: 0x8132, 0x267: 0x8132, 0x268: 0x8132, 0x269: 0x8132, + 0x26a: 0x8132, 0x26b: 0x8132, 0x26c: 0x8132, 0x26d: 0x8132, 0x26e: 0x8132, 0x26f: 0x8132, + 0x274: 0x0170, + 0x27a: 0x42a5, + 0x27e: 0x0037, + // Block 0xa, offset 0x280 + 0x284: 0x425a, 0x285: 0x447b, + 0x286: 0x35e9, 0x287: 0x00ce, 0x288: 0x3607, 0x289: 0x3613, 0x28a: 0x3625, + 0x28c: 0x3643, 0x28e: 0x3655, 0x28f: 0x3673, 0x290: 0x3e08, 0x291: 0xa000, + 0x295: 0xa000, 0x297: 0xa000, + 0x299: 0xa000, + 0x29f: 0xa000, 0x2a1: 0xa000, + 0x2a5: 0xa000, 0x2a9: 0xa000, + 0x2aa: 0x3637, 0x2ab: 0x3667, 0x2ac: 0x47fe, 0x2ad: 0x3697, 0x2ae: 0x4828, 0x2af: 0x36a9, + 0x2b0: 0x3e70, 0x2b1: 0xa000, 0x2b5: 0xa000, + 0x2b7: 0xa000, 0x2b9: 0xa000, + 0x2bf: 0xa000, + // Block 0xb, offset 0x2c0 + 0x2c1: 0xa000, 0x2c5: 0xa000, + 0x2c9: 0xa000, 0x2ca: 0x4840, 0x2cb: 0x485e, + 0x2cc: 0x36c7, 0x2cd: 0x36df, 0x2ce: 0x4876, 0x2d0: 0x01be, 0x2d1: 0x01d0, + 0x2d2: 0x01ac, 0x2d3: 0x430c, 0x2d4: 0x4312, 0x2d5: 0x01fa, 0x2d6: 0x01e8, + 0x2f0: 0x01d6, 0x2f1: 0x01eb, 0x2f2: 0x01ee, 0x2f4: 0x0188, 0x2f5: 0x01c7, + 0x2f9: 0x01a6, + // Block 0xc, offset 0x300 + 0x300: 0x3721, 0x301: 0x372d, 0x303: 0x371b, + 0x306: 0xa000, 0x307: 0x3709, + 0x30c: 0x375d, 0x30d: 0x3745, 0x30e: 0x376f, 0x310: 0xa000, + 0x313: 0xa000, 0x315: 0xa000, 0x316: 0xa000, 0x317: 0xa000, + 0x318: 0xa000, 0x319: 0x3751, 0x31a: 0xa000, + 0x31e: 0xa000, 0x323: 0xa000, + 0x327: 0xa000, + 0x32b: 0xa000, 0x32d: 0xa000, + 0x330: 0xa000, 0x333: 0xa000, 0x335: 0xa000, + 0x336: 0xa000, 0x337: 0xa000, 0x338: 0xa000, 0x339: 0x37d5, 0x33a: 0xa000, + 0x33e: 0xa000, + // Block 0xd, offset 0x340 + 0x341: 0x3733, 0x342: 0x37b7, + 0x350: 0x370f, 0x351: 0x3793, + 0x352: 0x3715, 0x353: 0x3799, 0x356: 0x3727, 0x357: 0x37ab, + 0x358: 0xa000, 0x359: 0xa000, 0x35a: 0x3829, 0x35b: 0x382f, 0x35c: 0x3739, 0x35d: 0x37bd, + 0x35e: 0x373f, 0x35f: 0x37c3, 0x362: 0x374b, 0x363: 0x37cf, + 0x364: 0x3757, 0x365: 0x37db, 0x366: 0x3763, 0x367: 0x37e7, 0x368: 0xa000, 0x369: 0xa000, + 0x36a: 0x3835, 0x36b: 0x383b, 0x36c: 0x378d, 0x36d: 0x3811, 0x36e: 0x3769, 0x36f: 0x37ed, + 0x370: 0x3775, 0x371: 0x37f9, 0x372: 0x377b, 0x373: 0x37ff, 0x374: 0x3781, 0x375: 0x3805, + 0x378: 0x3787, 0x379: 0x380b, + // Block 0xe, offset 0x380 + 0x387: 0x1d61, + 0x391: 0x812d, + 0x392: 0x8132, 0x393: 0x8132, 0x394: 0x8132, 0x395: 0x8132, 0x396: 0x812d, 0x397: 0x8132, + 0x398: 0x8132, 0x399: 0x8132, 0x39a: 0x812e, 0x39b: 0x812d, 0x39c: 0x8132, 0x39d: 0x8132, + 0x39e: 0x8132, 0x39f: 0x8132, 0x3a0: 0x8132, 0x3a1: 0x8132, 0x3a2: 0x812d, 0x3a3: 0x812d, + 0x3a4: 0x812d, 0x3a5: 0x812d, 0x3a6: 0x812d, 0x3a7: 0x812d, 0x3a8: 0x8132, 0x3a9: 0x8132, + 0x3aa: 0x812d, 0x3ab: 0x8132, 0x3ac: 0x8132, 0x3ad: 0x812e, 0x3ae: 0x8131, 0x3af: 0x8132, + 0x3b0: 0x8105, 0x3b1: 0x8106, 0x3b2: 0x8107, 0x3b3: 0x8108, 0x3b4: 0x8109, 0x3b5: 0x810a, + 0x3b6: 0x810b, 0x3b7: 0x810c, 0x3b8: 0x810d, 0x3b9: 0x810e, 0x3ba: 0x810e, 0x3bb: 0x810f, + 0x3bc: 0x8110, 0x3bd: 0x8111, 0x3bf: 0x8112, + // Block 0xf, offset 0x3c0 + 0x3c8: 0xa000, 0x3ca: 0xa000, 0x3cb: 0x8116, + 0x3cc: 0x8117, 0x3cd: 0x8118, 0x3ce: 0x8119, 0x3cf: 0x811a, 0x3d0: 0x811b, 0x3d1: 0x811c, + 0x3d2: 0x811d, 0x3d3: 0x9932, 0x3d4: 0x9932, 0x3d5: 0x992d, 0x3d6: 0x812d, 0x3d7: 0x8132, + 0x3d8: 0x8132, 0x3d9: 0x8132, 0x3da: 0x8132, 0x3db: 0x8132, 0x3dc: 0x812d, 0x3dd: 0x8132, + 0x3de: 0x8132, 0x3df: 0x812d, + 0x3f0: 0x811e, 0x3f5: 0x1d84, + 0x3f6: 0x2013, 0x3f7: 0x204f, 0x3f8: 0x204a, + // Block 0x10, offset 0x400 + 0x405: 0xa000, + 0x406: 0x2d26, 0x407: 0xa000, 0x408: 0x2d2e, 0x409: 0xa000, 0x40a: 0x2d36, 0x40b: 0xa000, + 0x40c: 0x2d3e, 0x40d: 0xa000, 0x40e: 0x2d46, 0x411: 0xa000, + 0x412: 0x2d4e, + 0x434: 0x8102, 0x435: 0x9900, + 0x43a: 0xa000, 0x43b: 0x2d56, + 0x43c: 0xa000, 0x43d: 0x2d5e, 0x43e: 0xa000, 0x43f: 0xa000, + // Block 0x11, offset 0x440 + 0x440: 0x0069, 0x441: 0x006b, 0x442: 0x006f, 0x443: 0x0083, 0x444: 0x00f5, 0x445: 0x00f8, + 0x446: 0x0413, 0x447: 0x0085, 0x448: 0x0089, 0x449: 0x008b, 0x44a: 0x0104, 0x44b: 0x0107, + 0x44c: 0x010a, 0x44d: 0x008f, 0x44f: 0x0097, 0x450: 0x009b, 0x451: 0x00e0, + 0x452: 0x009f, 0x453: 0x00fe, 0x454: 0x0417, 0x455: 0x041b, 0x456: 0x00a1, 0x457: 0x00a9, + 0x458: 0x00ab, 0x459: 0x0423, 0x45a: 0x012b, 0x45b: 0x00ad, 0x45c: 0x0427, 0x45d: 0x01be, + 0x45e: 0x01c1, 0x45f: 0x01c4, 0x460: 0x01fa, 0x461: 0x01fd, 0x462: 0x0093, 0x463: 0x00a5, + 0x464: 0x00ab, 0x465: 0x00ad, 0x466: 0x01be, 0x467: 0x01c1, 0x468: 0x01eb, 0x469: 0x01fa, + 0x46a: 0x01fd, + 0x478: 0x020c, + // Block 0x12, offset 0x480 + 0x49b: 0x00fb, 0x49c: 0x0087, 0x49d: 0x0101, + 0x49e: 0x00d4, 0x49f: 0x010a, 0x4a0: 0x008d, 0x4a1: 0x010d, 0x4a2: 0x0110, 0x4a3: 0x0116, + 0x4a4: 0x011c, 0x4a5: 0x011f, 0x4a6: 0x0122, 0x4a7: 0x042b, 0x4a8: 0x016a, 0x4a9: 0x0128, + 0x4aa: 0x042f, 0x4ab: 0x016d, 0x4ac: 0x0131, 0x4ad: 0x012e, 0x4ae: 0x0134, 0x4af: 0x0137, + 0x4b0: 0x013a, 0x4b1: 0x013d, 0x4b2: 0x0140, 0x4b3: 0x014c, 0x4b4: 0x014f, 0x4b5: 0x00ec, + 0x4b6: 0x0152, 0x4b7: 0x0155, 0x4b8: 0x041f, 0x4b9: 0x0158, 0x4ba: 0x015b, 0x4bb: 0x00b5, + 0x4bc: 0x015e, 0x4bd: 0x0161, 0x4be: 0x0164, 0x4bf: 0x01d0, + // Block 0x13, offset 0x4c0 + 0x4c0: 0x8132, 0x4c1: 0x8132, 0x4c2: 0x812d, 0x4c3: 0x8132, 0x4c4: 0x8132, 0x4c5: 0x8132, + 0x4c6: 0x8132, 0x4c7: 0x8132, 0x4c8: 0x8132, 0x4c9: 0x8132, 0x4ca: 0x812d, 0x4cb: 0x8132, + 0x4cc: 0x8132, 0x4cd: 0x8135, 0x4ce: 0x812a, 0x4cf: 0x812d, 0x4d0: 0x8129, 0x4d1: 0x8132, + 0x4d2: 0x8132, 0x4d3: 0x8132, 0x4d4: 0x8132, 0x4d5: 0x8132, 0x4d6: 0x8132, 0x4d7: 0x8132, + 0x4d8: 0x8132, 0x4d9: 0x8132, 0x4da: 0x8132, 0x4db: 0x8132, 0x4dc: 0x8132, 0x4dd: 0x8132, + 0x4de: 0x8132, 0x4df: 0x8132, 0x4e0: 0x8132, 0x4e1: 0x8132, 0x4e2: 0x8132, 0x4e3: 0x8132, + 0x4e4: 0x8132, 0x4e5: 0x8132, 0x4e6: 0x8132, 0x4e7: 0x8132, 0x4e8: 0x8132, 0x4e9: 0x8132, + 0x4ea: 0x8132, 0x4eb: 0x8132, 0x4ec: 0x8132, 0x4ed: 0x8132, 0x4ee: 0x8132, 0x4ef: 0x8132, + 0x4f0: 0x8132, 0x4f1: 0x8132, 0x4f2: 0x8132, 0x4f3: 0x8132, 0x4f4: 0x8132, 0x4f5: 0x8132, + 0x4f6: 0x8133, 0x4f7: 0x8131, 0x4f8: 0x8131, 0x4f9: 0x812d, 0x4fb: 0x8132, + 0x4fc: 0x8134, 0x4fd: 0x812d, 0x4fe: 0x8132, 0x4ff: 0x812d, + // Block 0x14, offset 0x500 + 0x500: 0x2f97, 0x501: 0x32a3, 0x502: 0x2fa1, 0x503: 0x32ad, 0x504: 0x2fa6, 0x505: 0x32b2, + 0x506: 0x2fab, 0x507: 0x32b7, 0x508: 0x38cc, 0x509: 0x3a5b, 0x50a: 0x2fc4, 0x50b: 0x32d0, + 0x50c: 0x2fce, 0x50d: 0x32da, 0x50e: 0x2fdd, 0x50f: 0x32e9, 0x510: 0x2fd3, 0x511: 0x32df, + 0x512: 0x2fd8, 0x513: 0x32e4, 0x514: 0x38ef, 0x515: 0x3a7e, 0x516: 0x38f6, 0x517: 0x3a85, + 0x518: 0x3019, 0x519: 0x3325, 0x51a: 0x301e, 0x51b: 0x332a, 0x51c: 0x3904, 0x51d: 0x3a93, + 0x51e: 0x3023, 0x51f: 0x332f, 0x520: 0x3032, 0x521: 0x333e, 0x522: 0x3050, 0x523: 0x335c, + 0x524: 0x305f, 0x525: 0x336b, 0x526: 0x3055, 0x527: 0x3361, 0x528: 0x3064, 0x529: 0x3370, + 0x52a: 0x3069, 0x52b: 0x3375, 0x52c: 0x30af, 0x52d: 0x33bb, 0x52e: 0x390b, 0x52f: 0x3a9a, + 0x530: 0x30b9, 0x531: 0x33ca, 0x532: 0x30c3, 0x533: 0x33d4, 0x534: 0x30cd, 0x535: 0x33de, + 0x536: 0x46c4, 0x537: 0x4755, 0x538: 0x3912, 0x539: 0x3aa1, 0x53a: 0x30e6, 0x53b: 0x33f7, + 0x53c: 0x30e1, 0x53d: 0x33f2, 0x53e: 0x30eb, 0x53f: 0x33fc, + // Block 0x15, offset 0x540 + 0x540: 0x30f0, 0x541: 0x3401, 0x542: 0x30f5, 0x543: 0x3406, 0x544: 0x3109, 0x545: 0x341a, + 0x546: 0x3113, 0x547: 0x3424, 0x548: 0x3122, 0x549: 0x3433, 0x54a: 0x311d, 0x54b: 0x342e, + 0x54c: 0x3935, 0x54d: 0x3ac4, 0x54e: 0x3943, 0x54f: 0x3ad2, 0x550: 0x394a, 0x551: 0x3ad9, + 0x552: 0x3951, 0x553: 0x3ae0, 0x554: 0x314f, 0x555: 0x3460, 0x556: 0x3154, 0x557: 0x3465, + 0x558: 0x315e, 0x559: 0x346f, 0x55a: 0x46f1, 0x55b: 0x4782, 0x55c: 0x3997, 0x55d: 0x3b26, + 0x55e: 0x3177, 0x55f: 0x3488, 0x560: 0x3181, 0x561: 0x3492, 0x562: 0x4700, 0x563: 0x4791, + 0x564: 0x399e, 0x565: 0x3b2d, 0x566: 0x39a5, 0x567: 0x3b34, 0x568: 0x39ac, 0x569: 0x3b3b, + 0x56a: 0x3190, 0x56b: 0x34a1, 0x56c: 0x319a, 0x56d: 0x34b0, 0x56e: 0x31ae, 0x56f: 0x34c4, + 0x570: 0x31a9, 0x571: 0x34bf, 0x572: 0x31ea, 0x573: 0x3500, 0x574: 0x31f9, 0x575: 0x350f, + 0x576: 0x31f4, 0x577: 0x350a, 0x578: 0x39b3, 0x579: 0x3b42, 0x57a: 0x39ba, 0x57b: 0x3b49, + 0x57c: 0x31fe, 0x57d: 0x3514, 0x57e: 0x3203, 0x57f: 0x3519, + // Block 0x16, offset 0x580 + 0x580: 0x3208, 0x581: 0x351e, 0x582: 0x320d, 0x583: 0x3523, 0x584: 0x321c, 0x585: 0x3532, + 0x586: 0x3217, 0x587: 0x352d, 0x588: 0x3221, 0x589: 0x353c, 0x58a: 0x3226, 0x58b: 0x3541, + 0x58c: 0x322b, 0x58d: 0x3546, 0x58e: 0x3249, 0x58f: 0x3564, 0x590: 0x3262, 0x591: 0x3582, + 0x592: 0x3271, 0x593: 0x3591, 0x594: 0x3276, 0x595: 0x3596, 0x596: 0x337a, 0x597: 0x34a6, + 0x598: 0x3537, 0x599: 0x3573, 0x59a: 0x1be0, 0x59b: 0x42d7, + 0x5a0: 0x46a1, 0x5a1: 0x4732, 0x5a2: 0x2f83, 0x5a3: 0x328f, + 0x5a4: 0x3878, 0x5a5: 0x3a07, 0x5a6: 0x3871, 0x5a7: 0x3a00, 0x5a8: 0x3886, 0x5a9: 0x3a15, + 0x5aa: 0x387f, 0x5ab: 0x3a0e, 0x5ac: 0x38be, 0x5ad: 0x3a4d, 0x5ae: 0x3894, 0x5af: 0x3a23, + 0x5b0: 0x388d, 0x5b1: 0x3a1c, 0x5b2: 0x38a2, 0x5b3: 0x3a31, 0x5b4: 0x389b, 0x5b5: 0x3a2a, + 0x5b6: 0x38c5, 0x5b7: 0x3a54, 0x5b8: 0x46b5, 0x5b9: 0x4746, 0x5ba: 0x3000, 0x5bb: 0x330c, + 0x5bc: 0x2fec, 0x5bd: 0x32f8, 0x5be: 0x38da, 0x5bf: 0x3a69, + // Block 0x17, offset 0x5c0 + 0x5c0: 0x38d3, 0x5c1: 0x3a62, 0x5c2: 0x38e8, 0x5c3: 0x3a77, 0x5c4: 0x38e1, 0x5c5: 0x3a70, + 0x5c6: 0x38fd, 0x5c7: 0x3a8c, 0x5c8: 0x3091, 0x5c9: 0x339d, 0x5ca: 0x30a5, 0x5cb: 0x33b1, + 0x5cc: 0x46e7, 0x5cd: 0x4778, 0x5ce: 0x3136, 0x5cf: 0x3447, 0x5d0: 0x3920, 0x5d1: 0x3aaf, + 0x5d2: 0x3919, 0x5d3: 0x3aa8, 0x5d4: 0x392e, 0x5d5: 0x3abd, 0x5d6: 0x3927, 0x5d7: 0x3ab6, + 0x5d8: 0x3989, 0x5d9: 0x3b18, 0x5da: 0x396d, 0x5db: 0x3afc, 0x5dc: 0x3966, 0x5dd: 0x3af5, + 0x5de: 0x397b, 0x5df: 0x3b0a, 0x5e0: 0x3974, 0x5e1: 0x3b03, 0x5e2: 0x3982, 0x5e3: 0x3b11, + 0x5e4: 0x31e5, 0x5e5: 0x34fb, 0x5e6: 0x31c7, 0x5e7: 0x34dd, 0x5e8: 0x39e4, 0x5e9: 0x3b73, + 0x5ea: 0x39dd, 0x5eb: 0x3b6c, 0x5ec: 0x39f2, 0x5ed: 0x3b81, 0x5ee: 0x39eb, 0x5ef: 0x3b7a, + 0x5f0: 0x39f9, 0x5f1: 0x3b88, 0x5f2: 0x3230, 0x5f3: 0x354b, 0x5f4: 0x3258, 0x5f5: 0x3578, + 0x5f6: 0x3253, 0x5f7: 0x356e, 0x5f8: 0x323f, 0x5f9: 0x355a, + // Block 0x18, offset 0x600 + 0x600: 0x4804, 0x601: 0x480a, 0x602: 0x491e, 0x603: 0x4936, 0x604: 0x4926, 0x605: 0x493e, + 0x606: 0x492e, 0x607: 0x4946, 0x608: 0x47aa, 0x609: 0x47b0, 0x60a: 0x488e, 0x60b: 0x48a6, + 0x60c: 0x4896, 0x60d: 0x48ae, 0x60e: 0x489e, 0x60f: 0x48b6, 0x610: 0x4816, 0x611: 0x481c, + 0x612: 0x3db8, 0x613: 0x3dc8, 0x614: 0x3dc0, 0x615: 0x3dd0, + 0x618: 0x47b6, 0x619: 0x47bc, 0x61a: 0x3ce8, 0x61b: 0x3cf8, 0x61c: 0x3cf0, 0x61d: 0x3d00, + 0x620: 0x482e, 0x621: 0x4834, 0x622: 0x494e, 0x623: 0x4966, + 0x624: 0x4956, 0x625: 0x496e, 0x626: 0x495e, 0x627: 0x4976, 0x628: 0x47c2, 0x629: 0x47c8, + 0x62a: 0x48be, 0x62b: 0x48d6, 0x62c: 0x48c6, 0x62d: 0x48de, 0x62e: 0x48ce, 0x62f: 0x48e6, + 0x630: 0x4846, 0x631: 0x484c, 0x632: 0x3e18, 0x633: 0x3e30, 0x634: 0x3e20, 0x635: 0x3e38, + 0x636: 0x3e28, 0x637: 0x3e40, 0x638: 0x47ce, 0x639: 0x47d4, 0x63a: 0x3d18, 0x63b: 0x3d30, + 0x63c: 0x3d20, 0x63d: 0x3d38, 0x63e: 0x3d28, 0x63f: 0x3d40, + // Block 0x19, offset 0x640 + 0x640: 0x4852, 0x641: 0x4858, 0x642: 0x3e48, 0x643: 0x3e58, 0x644: 0x3e50, 0x645: 0x3e60, + 0x648: 0x47da, 0x649: 0x47e0, 0x64a: 0x3d48, 0x64b: 0x3d58, + 0x64c: 0x3d50, 0x64d: 0x3d60, 0x650: 0x4864, 0x651: 0x486a, + 0x652: 0x3e80, 0x653: 0x3e98, 0x654: 0x3e88, 0x655: 0x3ea0, 0x656: 0x3e90, 0x657: 0x3ea8, + 0x659: 0x47e6, 0x65b: 0x3d68, 0x65d: 0x3d70, + 0x65f: 0x3d78, 0x660: 0x487c, 0x661: 0x4882, 0x662: 0x497e, 0x663: 0x4996, + 0x664: 0x4986, 0x665: 0x499e, 0x666: 0x498e, 0x667: 0x49a6, 0x668: 0x47ec, 0x669: 0x47f2, + 0x66a: 0x48ee, 0x66b: 0x4906, 0x66c: 0x48f6, 0x66d: 0x490e, 0x66e: 0x48fe, 0x66f: 0x4916, + 0x670: 0x47f8, 0x671: 0x431e, 0x672: 0x3691, 0x673: 0x4324, 0x674: 0x4822, 0x675: 0x432a, + 0x676: 0x36a3, 0x677: 0x4330, 0x678: 0x36c1, 0x679: 0x4336, 0x67a: 0x36d9, 0x67b: 0x433c, + 0x67c: 0x4870, 0x67d: 0x4342, + // Block 0x1a, offset 0x680 + 0x680: 0x3da0, 0x681: 0x3da8, 0x682: 0x4184, 0x683: 0x41a2, 0x684: 0x418e, 0x685: 0x41ac, + 0x686: 0x4198, 0x687: 0x41b6, 0x688: 0x3cd8, 0x689: 0x3ce0, 0x68a: 0x40d0, 0x68b: 0x40ee, + 0x68c: 0x40da, 0x68d: 0x40f8, 0x68e: 0x40e4, 0x68f: 0x4102, 0x690: 0x3de8, 0x691: 0x3df0, + 0x692: 0x41c0, 0x693: 0x41de, 0x694: 0x41ca, 0x695: 0x41e8, 0x696: 0x41d4, 0x697: 0x41f2, + 0x698: 0x3d08, 0x699: 0x3d10, 0x69a: 0x410c, 0x69b: 0x412a, 0x69c: 0x4116, 0x69d: 0x4134, + 0x69e: 0x4120, 0x69f: 0x413e, 0x6a0: 0x3ec0, 0x6a1: 0x3ec8, 0x6a2: 0x41fc, 0x6a3: 0x421a, + 0x6a4: 0x4206, 0x6a5: 0x4224, 0x6a6: 0x4210, 0x6a7: 0x422e, 0x6a8: 0x3d80, 0x6a9: 0x3d88, + 0x6aa: 0x4148, 0x6ab: 0x4166, 0x6ac: 0x4152, 0x6ad: 0x4170, 0x6ae: 0x415c, 0x6af: 0x417a, + 0x6b0: 0x3685, 0x6b1: 0x367f, 0x6b2: 0x3d90, 0x6b3: 0x368b, 0x6b4: 0x3d98, + 0x6b6: 0x4810, 0x6b7: 0x3db0, 0x6b8: 0x35f5, 0x6b9: 0x35ef, 0x6ba: 0x35e3, 0x6bb: 0x42ee, + 0x6bc: 0x35fb, 0x6bd: 0x4287, 0x6be: 0x01d3, 0x6bf: 0x4287, + // Block 0x1b, offset 0x6c0 + 0x6c0: 0x42a0, 0x6c1: 0x4482, 0x6c2: 0x3dd8, 0x6c3: 0x369d, 0x6c4: 0x3de0, + 0x6c6: 0x483a, 0x6c7: 0x3df8, 0x6c8: 0x3601, 0x6c9: 0x42f4, 0x6ca: 0x360d, 0x6cb: 0x42fa, + 0x6cc: 0x3619, 0x6cd: 0x4489, 0x6ce: 0x4490, 0x6cf: 0x4497, 0x6d0: 0x36b5, 0x6d1: 0x36af, + 0x6d2: 0x3e00, 0x6d3: 0x44e4, 0x6d6: 0x36bb, 0x6d7: 0x3e10, + 0x6d8: 0x3631, 0x6d9: 0x362b, 0x6da: 0x361f, 0x6db: 0x4300, 0x6dd: 0x449e, + 0x6de: 0x44a5, 0x6df: 0x44ac, 0x6e0: 0x36eb, 0x6e1: 0x36e5, 0x6e2: 0x3e68, 0x6e3: 0x44ec, + 0x6e4: 0x36cd, 0x6e5: 0x36d3, 0x6e6: 0x36f1, 0x6e7: 0x3e78, 0x6e8: 0x3661, 0x6e9: 0x365b, + 0x6ea: 0x364f, 0x6eb: 0x430c, 0x6ec: 0x3649, 0x6ed: 0x4474, 0x6ee: 0x447b, 0x6ef: 0x0081, + 0x6f2: 0x3eb0, 0x6f3: 0x36f7, 0x6f4: 0x3eb8, + 0x6f6: 0x4888, 0x6f7: 0x3ed0, 0x6f8: 0x363d, 0x6f9: 0x4306, 0x6fa: 0x366d, 0x6fb: 0x4318, + 0x6fc: 0x3679, 0x6fd: 0x425a, 0x6fe: 0x428c, + // Block 0x1c, offset 0x700 + 0x700: 0x1bd8, 0x701: 0x1bdc, 0x702: 0x0047, 0x703: 0x1c54, 0x705: 0x1be8, + 0x706: 0x1bec, 0x707: 0x00e9, 0x709: 0x1c58, 0x70a: 0x008f, 0x70b: 0x0051, + 0x70c: 0x0051, 0x70d: 0x0051, 0x70e: 0x0091, 0x70f: 0x00da, 0x710: 0x0053, 0x711: 0x0053, + 0x712: 0x0059, 0x713: 0x0099, 0x715: 0x005d, 0x716: 0x198d, + 0x719: 0x0061, 0x71a: 0x0063, 0x71b: 0x0065, 0x71c: 0x0065, 0x71d: 0x0065, + 0x720: 0x199f, 0x721: 0x1bc8, 0x722: 0x19a8, + 0x724: 0x0075, 0x726: 0x01b8, 0x728: 0x0075, + 0x72a: 0x0057, 0x72b: 0x42d2, 0x72c: 0x0045, 0x72d: 0x0047, 0x72f: 0x008b, + 0x730: 0x004b, 0x731: 0x004d, 0x733: 0x005b, 0x734: 0x009f, 0x735: 0x0215, + 0x736: 0x0218, 0x737: 0x021b, 0x738: 0x021e, 0x739: 0x0093, 0x73b: 0x1b98, + 0x73c: 0x01e8, 0x73d: 0x01c1, 0x73e: 0x0179, 0x73f: 0x01a0, + // Block 0x1d, offset 0x740 + 0x740: 0x0463, 0x745: 0x0049, + 0x746: 0x0089, 0x747: 0x008b, 0x748: 0x0093, 0x749: 0x0095, + 0x750: 0x222e, 0x751: 0x223a, + 0x752: 0x22ee, 0x753: 0x2216, 0x754: 0x229a, 0x755: 0x2222, 0x756: 0x22a0, 0x757: 0x22b8, + 0x758: 0x22c4, 0x759: 0x2228, 0x75a: 0x22ca, 0x75b: 0x2234, 0x75c: 0x22be, 0x75d: 0x22d0, + 0x75e: 0x22d6, 0x75f: 0x1cbc, 0x760: 0x0053, 0x761: 0x195a, 0x762: 0x1ba4, 0x763: 0x1963, + 0x764: 0x006d, 0x765: 0x19ab, 0x766: 0x1bd0, 0x767: 0x1d48, 0x768: 0x1966, 0x769: 0x0071, + 0x76a: 0x19b7, 0x76b: 0x1bd4, 0x76c: 0x0059, 0x76d: 0x0047, 0x76e: 0x0049, 0x76f: 0x005b, + 0x770: 0x0093, 0x771: 0x19e4, 0x772: 0x1c18, 0x773: 0x19ed, 0x774: 0x00ad, 0x775: 0x1a62, + 0x776: 0x1c4c, 0x777: 0x1d5c, 0x778: 0x19f0, 0x779: 0x00b1, 0x77a: 0x1a65, 0x77b: 0x1c50, + 0x77c: 0x0099, 0x77d: 0x0087, 0x77e: 0x0089, 0x77f: 0x009b, + // Block 0x1e, offset 0x780 + 0x781: 0x3c06, 0x783: 0xa000, 0x784: 0x3c0d, 0x785: 0xa000, + 0x787: 0x3c14, 0x788: 0xa000, 0x789: 0x3c1b, + 0x78d: 0xa000, + 0x7a0: 0x2f65, 0x7a1: 0xa000, 0x7a2: 0x3c29, + 0x7a4: 0xa000, 0x7a5: 0xa000, + 0x7ad: 0x3c22, 0x7ae: 0x2f60, 0x7af: 0x2f6a, + 0x7b0: 0x3c30, 0x7b1: 0x3c37, 0x7b2: 0xa000, 0x7b3: 0xa000, 0x7b4: 0x3c3e, 0x7b5: 0x3c45, + 0x7b6: 0xa000, 0x7b7: 0xa000, 0x7b8: 0x3c4c, 0x7b9: 0x3c53, 0x7ba: 0xa000, 0x7bb: 0xa000, + 0x7bc: 0xa000, 0x7bd: 0xa000, + // Block 0x1f, offset 0x7c0 + 0x7c0: 0x3c5a, 0x7c1: 0x3c61, 0x7c2: 0xa000, 0x7c3: 0xa000, 0x7c4: 0x3c76, 0x7c5: 0x3c7d, + 0x7c6: 0xa000, 0x7c7: 0xa000, 0x7c8: 0x3c84, 0x7c9: 0x3c8b, + 0x7d1: 0xa000, + 0x7d2: 0xa000, + 0x7e2: 0xa000, + 0x7e8: 0xa000, 0x7e9: 0xa000, + 0x7eb: 0xa000, 0x7ec: 0x3ca0, 0x7ed: 0x3ca7, 0x7ee: 0x3cae, 0x7ef: 0x3cb5, + 0x7f2: 0xa000, 0x7f3: 0xa000, 0x7f4: 0xa000, 0x7f5: 0xa000, + // Block 0x20, offset 0x800 + 0x820: 0x0023, 0x821: 0x0025, 0x822: 0x0027, 0x823: 0x0029, + 0x824: 0x002b, 0x825: 0x002d, 0x826: 0x002f, 0x827: 0x0031, 0x828: 0x0033, 0x829: 0x1882, + 0x82a: 0x1885, 0x82b: 0x1888, 0x82c: 0x188b, 0x82d: 0x188e, 0x82e: 0x1891, 0x82f: 0x1894, + 0x830: 0x1897, 0x831: 0x189a, 0x832: 0x189d, 0x833: 0x18a6, 0x834: 0x1a68, 0x835: 0x1a6c, + 0x836: 0x1a70, 0x837: 0x1a74, 0x838: 0x1a78, 0x839: 0x1a7c, 0x83a: 0x1a80, 0x83b: 0x1a84, + 0x83c: 0x1a88, 0x83d: 0x1c80, 0x83e: 0x1c85, 0x83f: 0x1c8a, + // Block 0x21, offset 0x840 + 0x840: 0x1c8f, 0x841: 0x1c94, 0x842: 0x1c99, 0x843: 0x1c9e, 0x844: 0x1ca3, 0x845: 0x1ca8, + 0x846: 0x1cad, 0x847: 0x1cb2, 0x848: 0x187f, 0x849: 0x18a3, 0x84a: 0x18c7, 0x84b: 0x18eb, + 0x84c: 0x190f, 0x84d: 0x1918, 0x84e: 0x191e, 0x84f: 0x1924, 0x850: 0x192a, 0x851: 0x1b60, + 0x852: 0x1b64, 0x853: 0x1b68, 0x854: 0x1b6c, 0x855: 0x1b70, 0x856: 0x1b74, 0x857: 0x1b78, + 0x858: 0x1b7c, 0x859: 0x1b80, 0x85a: 0x1b84, 0x85b: 0x1b88, 0x85c: 0x1af4, 0x85d: 0x1af8, + 0x85e: 0x1afc, 0x85f: 0x1b00, 0x860: 0x1b04, 0x861: 0x1b08, 0x862: 0x1b0c, 0x863: 0x1b10, + 0x864: 0x1b14, 0x865: 0x1b18, 0x866: 0x1b1c, 0x867: 0x1b20, 0x868: 0x1b24, 0x869: 0x1b28, + 0x86a: 0x1b2c, 0x86b: 0x1b30, 0x86c: 0x1b34, 0x86d: 0x1b38, 0x86e: 0x1b3c, 0x86f: 0x1b40, + 0x870: 0x1b44, 0x871: 0x1b48, 0x872: 0x1b4c, 0x873: 0x1b50, 0x874: 0x1b54, 0x875: 0x1b58, + 0x876: 0x0043, 0x877: 0x0045, 0x878: 0x0047, 0x879: 0x0049, 0x87a: 0x004b, 0x87b: 0x004d, + 0x87c: 0x004f, 0x87d: 0x0051, 0x87e: 0x0053, 0x87f: 0x0055, + // Block 0x22, offset 0x880 + 0x880: 0x06bf, 0x881: 0x06e3, 0x882: 0x06ef, 0x883: 0x06ff, 0x884: 0x0707, 0x885: 0x0713, + 0x886: 0x071b, 0x887: 0x0723, 0x888: 0x072f, 0x889: 0x0783, 0x88a: 0x079b, 0x88b: 0x07ab, + 0x88c: 0x07bb, 0x88d: 0x07cb, 0x88e: 0x07db, 0x88f: 0x07fb, 0x890: 0x07ff, 0x891: 0x0803, + 0x892: 0x0837, 0x893: 0x085f, 0x894: 0x086f, 0x895: 0x0877, 0x896: 0x087b, 0x897: 0x0887, + 0x898: 0x08a3, 0x899: 0x08a7, 0x89a: 0x08bf, 0x89b: 0x08c3, 0x89c: 0x08cb, 0x89d: 0x08db, + 0x89e: 0x0977, 0x89f: 0x098b, 0x8a0: 0x09cb, 0x8a1: 0x09df, 0x8a2: 0x09e7, 0x8a3: 0x09eb, + 0x8a4: 0x09fb, 0x8a5: 0x0a17, 0x8a6: 0x0a43, 0x8a7: 0x0a4f, 0x8a8: 0x0a6f, 0x8a9: 0x0a7b, + 0x8aa: 0x0a7f, 0x8ab: 0x0a83, 0x8ac: 0x0a9b, 0x8ad: 0x0a9f, 0x8ae: 0x0acb, 0x8af: 0x0ad7, + 0x8b0: 0x0adf, 0x8b1: 0x0ae7, 0x8b2: 0x0af7, 0x8b3: 0x0aff, 0x8b4: 0x0b07, 0x8b5: 0x0b33, + 0x8b6: 0x0b37, 0x8b7: 0x0b3f, 0x8b8: 0x0b43, 0x8b9: 0x0b4b, 0x8ba: 0x0b53, 0x8bb: 0x0b63, + 0x8bc: 0x0b7f, 0x8bd: 0x0bf7, 0x8be: 0x0c0b, 0x8bf: 0x0c0f, + // Block 0x23, offset 0x8c0 + 0x8c0: 0x0c8f, 0x8c1: 0x0c93, 0x8c2: 0x0ca7, 0x8c3: 0x0cab, 0x8c4: 0x0cb3, 0x8c5: 0x0cbb, + 0x8c6: 0x0cc3, 0x8c7: 0x0ccf, 0x8c8: 0x0cf7, 0x8c9: 0x0d07, 0x8ca: 0x0d1b, 0x8cb: 0x0d8b, + 0x8cc: 0x0d97, 0x8cd: 0x0da7, 0x8ce: 0x0db3, 0x8cf: 0x0dbf, 0x8d0: 0x0dc7, 0x8d1: 0x0dcb, + 0x8d2: 0x0dcf, 0x8d3: 0x0dd3, 0x8d4: 0x0dd7, 0x8d5: 0x0e8f, 0x8d6: 0x0ed7, 0x8d7: 0x0ee3, + 0x8d8: 0x0ee7, 0x8d9: 0x0eeb, 0x8da: 0x0eef, 0x8db: 0x0ef7, 0x8dc: 0x0efb, 0x8dd: 0x0f0f, + 0x8de: 0x0f2b, 0x8df: 0x0f33, 0x8e0: 0x0f73, 0x8e1: 0x0f77, 0x8e2: 0x0f7f, 0x8e3: 0x0f83, + 0x8e4: 0x0f8b, 0x8e5: 0x0f8f, 0x8e6: 0x0fb3, 0x8e7: 0x0fb7, 0x8e8: 0x0fd3, 0x8e9: 0x0fd7, + 0x8ea: 0x0fdb, 0x8eb: 0x0fdf, 0x8ec: 0x0ff3, 0x8ed: 0x1017, 0x8ee: 0x101b, 0x8ef: 0x101f, + 0x8f0: 0x1043, 0x8f1: 0x1083, 0x8f2: 0x1087, 0x8f3: 0x10a7, 0x8f4: 0x10b7, 0x8f5: 0x10bf, + 0x8f6: 0x10df, 0x8f7: 0x1103, 0x8f8: 0x1147, 0x8f9: 0x114f, 0x8fa: 0x1163, 0x8fb: 0x116f, + 0x8fc: 0x1177, 0x8fd: 0x117f, 0x8fe: 0x1183, 0x8ff: 0x1187, + // Block 0x24, offset 0x900 + 0x900: 0x119f, 0x901: 0x11a3, 0x902: 0x11bf, 0x903: 0x11c7, 0x904: 0x11cf, 0x905: 0x11d3, + 0x906: 0x11df, 0x907: 0x11e7, 0x908: 0x11eb, 0x909: 0x11ef, 0x90a: 0x11f7, 0x90b: 0x11fb, + 0x90c: 0x129b, 0x90d: 0x12af, 0x90e: 0x12e3, 0x90f: 0x12e7, 0x910: 0x12ef, 0x911: 0x131b, + 0x912: 0x1323, 0x913: 0x132b, 0x914: 0x1333, 0x915: 0x136f, 0x916: 0x1373, 0x917: 0x137b, + 0x918: 0x137f, 0x919: 0x1383, 0x91a: 0x13af, 0x91b: 0x13b3, 0x91c: 0x13bb, 0x91d: 0x13cf, + 0x91e: 0x13d3, 0x91f: 0x13ef, 0x920: 0x13f7, 0x921: 0x13fb, 0x922: 0x141f, 0x923: 0x143f, + 0x924: 0x1453, 0x925: 0x1457, 0x926: 0x145f, 0x927: 0x148b, 0x928: 0x148f, 0x929: 0x149f, + 0x92a: 0x14c3, 0x92b: 0x14cf, 0x92c: 0x14df, 0x92d: 0x14f7, 0x92e: 0x14ff, 0x92f: 0x1503, + 0x930: 0x1507, 0x931: 0x150b, 0x932: 0x1517, 0x933: 0x151b, 0x934: 0x1523, 0x935: 0x153f, + 0x936: 0x1543, 0x937: 0x1547, 0x938: 0x155f, 0x939: 0x1563, 0x93a: 0x156b, 0x93b: 0x157f, + 0x93c: 0x1583, 0x93d: 0x1587, 0x93e: 0x158f, 0x93f: 0x1593, + // Block 0x25, offset 0x940 + 0x946: 0xa000, 0x94b: 0xa000, + 0x94c: 0x3f08, 0x94d: 0xa000, 0x94e: 0x3f10, 0x94f: 0xa000, 0x950: 0x3f18, 0x951: 0xa000, + 0x952: 0x3f20, 0x953: 0xa000, 0x954: 0x3f28, 0x955: 0xa000, 0x956: 0x3f30, 0x957: 0xa000, + 0x958: 0x3f38, 0x959: 0xa000, 0x95a: 0x3f40, 0x95b: 0xa000, 0x95c: 0x3f48, 0x95d: 0xa000, + 0x95e: 0x3f50, 0x95f: 0xa000, 0x960: 0x3f58, 0x961: 0xa000, 0x962: 0x3f60, + 0x964: 0xa000, 0x965: 0x3f68, 0x966: 0xa000, 0x967: 0x3f70, 0x968: 0xa000, 0x969: 0x3f78, + 0x96f: 0xa000, + 0x970: 0x3f80, 0x971: 0x3f88, 0x972: 0xa000, 0x973: 0x3f90, 0x974: 0x3f98, 0x975: 0xa000, + 0x976: 0x3fa0, 0x977: 0x3fa8, 0x978: 0xa000, 0x979: 0x3fb0, 0x97a: 0x3fb8, 0x97b: 0xa000, + 0x97c: 0x3fc0, 0x97d: 0x3fc8, + // Block 0x26, offset 0x980 + 0x994: 0x3f00, + 0x999: 0x9903, 0x99a: 0x9903, 0x99b: 0x42dc, 0x99c: 0x42e2, 0x99d: 0xa000, + 0x99e: 0x3fd0, 0x99f: 0x26b4, + 0x9a6: 0xa000, + 0x9ab: 0xa000, 0x9ac: 0x3fe0, 0x9ad: 0xa000, 0x9ae: 0x3fe8, 0x9af: 0xa000, + 0x9b0: 0x3ff0, 0x9b1: 0xa000, 0x9b2: 0x3ff8, 0x9b3: 0xa000, 0x9b4: 0x4000, 0x9b5: 0xa000, + 0x9b6: 0x4008, 0x9b7: 0xa000, 0x9b8: 0x4010, 0x9b9: 0xa000, 0x9ba: 0x4018, 0x9bb: 0xa000, + 0x9bc: 0x4020, 0x9bd: 0xa000, 0x9be: 0x4028, 0x9bf: 0xa000, + // Block 0x27, offset 0x9c0 + 0x9c0: 0x4030, 0x9c1: 0xa000, 0x9c2: 0x4038, 0x9c4: 0xa000, 0x9c5: 0x4040, + 0x9c6: 0xa000, 0x9c7: 0x4048, 0x9c8: 0xa000, 0x9c9: 0x4050, + 0x9cf: 0xa000, 0x9d0: 0x4058, 0x9d1: 0x4060, + 0x9d2: 0xa000, 0x9d3: 0x4068, 0x9d4: 0x4070, 0x9d5: 0xa000, 0x9d6: 0x4078, 0x9d7: 0x4080, + 0x9d8: 0xa000, 0x9d9: 0x4088, 0x9da: 0x4090, 0x9db: 0xa000, 0x9dc: 0x4098, 0x9dd: 0x40a0, + 0x9ef: 0xa000, + 0x9f0: 0xa000, 0x9f1: 0xa000, 0x9f2: 0xa000, 0x9f4: 0x3fd8, + 0x9f7: 0x40a8, 0x9f8: 0x40b0, 0x9f9: 0x40b8, 0x9fa: 0x40c0, + 0x9fd: 0xa000, 0x9fe: 0x40c8, 0x9ff: 0x26c9, + // Block 0x28, offset 0xa00 + 0xa00: 0x0367, 0xa01: 0x032b, 0xa02: 0x032f, 0xa03: 0x0333, 0xa04: 0x037b, 0xa05: 0x0337, + 0xa06: 0x033b, 0xa07: 0x033f, 0xa08: 0x0343, 0xa09: 0x0347, 0xa0a: 0x034b, 0xa0b: 0x034f, + 0xa0c: 0x0353, 0xa0d: 0x0357, 0xa0e: 0x035b, 0xa0f: 0x49bd, 0xa10: 0x49c3, 0xa11: 0x49c9, + 0xa12: 0x49cf, 0xa13: 0x49d5, 0xa14: 0x49db, 0xa15: 0x49e1, 0xa16: 0x49e7, 0xa17: 0x49ed, + 0xa18: 0x49f3, 0xa19: 0x49f9, 0xa1a: 0x49ff, 0xa1b: 0x4a05, 0xa1c: 0x4a0b, 0xa1d: 0x4a11, + 0xa1e: 0x4a17, 0xa1f: 0x4a1d, 0xa20: 0x4a23, 0xa21: 0x4a29, 0xa22: 0x4a2f, 0xa23: 0x4a35, + 0xa24: 0x03c3, 0xa25: 0x035f, 0xa26: 0x0363, 0xa27: 0x03e7, 0xa28: 0x03eb, 0xa29: 0x03ef, + 0xa2a: 0x03f3, 0xa2b: 0x03f7, 0xa2c: 0x03fb, 0xa2d: 0x03ff, 0xa2e: 0x036b, 0xa2f: 0x0403, + 0xa30: 0x0407, 0xa31: 0x036f, 0xa32: 0x0373, 0xa33: 0x0377, 0xa34: 0x037f, 0xa35: 0x0383, + 0xa36: 0x0387, 0xa37: 0x038b, 0xa38: 0x038f, 0xa39: 0x0393, 0xa3a: 0x0397, 0xa3b: 0x039b, + 0xa3c: 0x039f, 0xa3d: 0x03a3, 0xa3e: 0x03a7, 0xa3f: 0x03ab, + // Block 0x29, offset 0xa40 + 0xa40: 0x03af, 0xa41: 0x03b3, 0xa42: 0x040b, 0xa43: 0x040f, 0xa44: 0x03b7, 0xa45: 0x03bb, + 0xa46: 0x03bf, 0xa47: 0x03c7, 0xa48: 0x03cb, 0xa49: 0x03cf, 0xa4a: 0x03d3, 0xa4b: 0x03d7, + 0xa4c: 0x03db, 0xa4d: 0x03df, 0xa4e: 0x03e3, + 0xa52: 0x06bf, 0xa53: 0x071b, 0xa54: 0x06cb, 0xa55: 0x097b, 0xa56: 0x06cf, 0xa57: 0x06e7, + 0xa58: 0x06d3, 0xa59: 0x0f93, 0xa5a: 0x0707, 0xa5b: 0x06db, 0xa5c: 0x06c3, 0xa5d: 0x09ff, + 0xa5e: 0x098f, 0xa5f: 0x072f, + // Block 0x2a, offset 0xa80 + 0xa80: 0x2054, 0xa81: 0x205a, 0xa82: 0x2060, 0xa83: 0x2066, 0xa84: 0x206c, 0xa85: 0x2072, + 0xa86: 0x2078, 0xa87: 0x207e, 0xa88: 0x2084, 0xa89: 0x208a, 0xa8a: 0x2090, 0xa8b: 0x2096, + 0xa8c: 0x209c, 0xa8d: 0x20a2, 0xa8e: 0x2726, 0xa8f: 0x272f, 0xa90: 0x2738, 0xa91: 0x2741, + 0xa92: 0x274a, 0xa93: 0x2753, 0xa94: 0x275c, 0xa95: 0x2765, 0xa96: 0x276e, 0xa97: 0x2780, + 0xa98: 0x2789, 0xa99: 0x2792, 0xa9a: 0x279b, 0xa9b: 0x27a4, 0xa9c: 0x2777, 0xa9d: 0x2bac, + 0xa9e: 0x2aed, 0xaa0: 0x20a8, 0xaa1: 0x20c0, 0xaa2: 0x20b4, 0xaa3: 0x2108, + 0xaa4: 0x20c6, 0xaa5: 0x20e4, 0xaa6: 0x20ae, 0xaa7: 0x20de, 0xaa8: 0x20ba, 0xaa9: 0x20f0, + 0xaaa: 0x2120, 0xaab: 0x213e, 0xaac: 0x2138, 0xaad: 0x212c, 0xaae: 0x217a, 0xaaf: 0x210e, + 0xab0: 0x211a, 0xab1: 0x2132, 0xab2: 0x2126, 0xab3: 0x2150, 0xab4: 0x20fc, 0xab5: 0x2144, + 0xab6: 0x216e, 0xab7: 0x2156, 0xab8: 0x20ea, 0xab9: 0x20cc, 0xaba: 0x2102, 0xabb: 0x2114, + 0xabc: 0x214a, 0xabd: 0x20d2, 0xabe: 0x2174, 0xabf: 0x20f6, + // Block 0x2b, offset 0xac0 + 0xac0: 0x215c, 0xac1: 0x20d8, 0xac2: 0x2162, 0xac3: 0x2168, 0xac4: 0x092f, 0xac5: 0x0b03, + 0xac6: 0x0ca7, 0xac7: 0x10c7, + 0xad0: 0x1bc4, 0xad1: 0x18a9, + 0xad2: 0x18ac, 0xad3: 0x18af, 0xad4: 0x18b2, 0xad5: 0x18b5, 0xad6: 0x18b8, 0xad7: 0x18bb, + 0xad8: 0x18be, 0xad9: 0x18c1, 0xada: 0x18ca, 0xadb: 0x18cd, 0xadc: 0x18d0, 0xadd: 0x18d3, + 0xade: 0x18d6, 0xadf: 0x18d9, 0xae0: 0x0313, 0xae1: 0x031b, 0xae2: 0x031f, 0xae3: 0x0327, + 0xae4: 0x032b, 0xae5: 0x032f, 0xae6: 0x0337, 0xae7: 0x033f, 0xae8: 0x0343, 0xae9: 0x034b, + 0xaea: 0x034f, 0xaeb: 0x0353, 0xaec: 0x0357, 0xaed: 0x035b, 0xaee: 0x2e18, 0xaef: 0x2e20, + 0xaf0: 0x2e28, 0xaf1: 0x2e30, 0xaf2: 0x2e38, 0xaf3: 0x2e40, 0xaf4: 0x2e48, 0xaf5: 0x2e50, + 0xaf6: 0x2e60, 0xaf7: 0x2e68, 0xaf8: 0x2e70, 0xaf9: 0x2e78, 0xafa: 0x2e80, 0xafb: 0x2e88, + 0xafc: 0x2ed3, 0xafd: 0x2e9b, 0xafe: 0x2e58, + // Block 0x2c, offset 0xb00 + 0xb00: 0x06bf, 0xb01: 0x071b, 0xb02: 0x06cb, 0xb03: 0x097b, 0xb04: 0x071f, 0xb05: 0x07af, + 0xb06: 0x06c7, 0xb07: 0x07ab, 0xb08: 0x070b, 0xb09: 0x0887, 0xb0a: 0x0d07, 0xb0b: 0x0e8f, + 0xb0c: 0x0dd7, 0xb0d: 0x0d1b, 0xb0e: 0x145f, 0xb0f: 0x098b, 0xb10: 0x0ccf, 0xb11: 0x0d4b, + 0xb12: 0x0d0b, 0xb13: 0x104b, 0xb14: 0x08fb, 0xb15: 0x0f03, 0xb16: 0x1387, 0xb17: 0x105f, + 0xb18: 0x0843, 0xb19: 0x108f, 0xb1a: 0x0f9b, 0xb1b: 0x0a17, 0xb1c: 0x140f, 0xb1d: 0x077f, + 0xb1e: 0x08ab, 0xb1f: 0x0df7, 0xb20: 0x1527, 0xb21: 0x0743, 0xb22: 0x07d3, 0xb23: 0x0d9b, + 0xb24: 0x06cf, 0xb25: 0x06e7, 0xb26: 0x06d3, 0xb27: 0x0adb, 0xb28: 0x08ef, 0xb29: 0x087f, + 0xb2a: 0x0a57, 0xb2b: 0x0a4b, 0xb2c: 0x0feb, 0xb2d: 0x073f, 0xb2e: 0x139b, 0xb2f: 0x089b, + 0xb30: 0x09f3, 0xb31: 0x18dc, 0xb32: 0x18df, 0xb33: 0x18e2, 0xb34: 0x18e5, 0xb35: 0x18ee, + 0xb36: 0x18f1, 0xb37: 0x18f4, 0xb38: 0x18f7, 0xb39: 0x18fa, 0xb3a: 0x18fd, 0xb3b: 0x1900, + 0xb3c: 0x1903, 0xb3d: 0x1906, 0xb3e: 0x1909, 0xb3f: 0x1912, + // Block 0x2d, offset 0xb40 + 0xb40: 0x1cc6, 0xb41: 0x1cd5, 0xb42: 0x1ce4, 0xb43: 0x1cf3, 0xb44: 0x1d02, 0xb45: 0x1d11, + 0xb46: 0x1d20, 0xb47: 0x1d2f, 0xb48: 0x1d3e, 0xb49: 0x218c, 0xb4a: 0x219e, 0xb4b: 0x21b0, + 0xb4c: 0x1954, 0xb4d: 0x1c04, 0xb4e: 0x19d2, 0xb4f: 0x1ba8, 0xb50: 0x04cb, 0xb51: 0x04d3, + 0xb52: 0x04db, 0xb53: 0x04e3, 0xb54: 0x04eb, 0xb55: 0x04ef, 0xb56: 0x04f3, 0xb57: 0x04f7, + 0xb58: 0x04fb, 0xb59: 0x04ff, 0xb5a: 0x0503, 0xb5b: 0x0507, 0xb5c: 0x050b, 0xb5d: 0x050f, + 0xb5e: 0x0513, 0xb5f: 0x0517, 0xb60: 0x051b, 0xb61: 0x0523, 0xb62: 0x0527, 0xb63: 0x052b, + 0xb64: 0x052f, 0xb65: 0x0533, 0xb66: 0x0537, 0xb67: 0x053b, 0xb68: 0x053f, 0xb69: 0x0543, + 0xb6a: 0x0547, 0xb6b: 0x054b, 0xb6c: 0x054f, 0xb6d: 0x0553, 0xb6e: 0x0557, 0xb6f: 0x055b, + 0xb70: 0x055f, 0xb71: 0x0563, 0xb72: 0x0567, 0xb73: 0x056f, 0xb74: 0x0577, 0xb75: 0x057f, + 0xb76: 0x0583, 0xb77: 0x0587, 0xb78: 0x058b, 0xb79: 0x058f, 0xb7a: 0x0593, 0xb7b: 0x0597, + 0xb7c: 0x059b, 0xb7d: 0x059f, 0xb7e: 0x05a3, + // Block 0x2e, offset 0xb80 + 0xb80: 0x2b0c, 0xb81: 0x29a8, 0xb82: 0x2b1c, 0xb83: 0x2880, 0xb84: 0x2ee4, 0xb85: 0x288a, + 0xb86: 0x2894, 0xb87: 0x2f28, 0xb88: 0x29b5, 0xb89: 0x289e, 0xb8a: 0x28a8, 0xb8b: 0x28b2, + 0xb8c: 0x29dc, 0xb8d: 0x29e9, 0xb8e: 0x29c2, 0xb8f: 0x29cf, 0xb90: 0x2ea9, 0xb91: 0x29f6, + 0xb92: 0x2a03, 0xb93: 0x2bbe, 0xb94: 0x26bb, 0xb95: 0x2bd1, 0xb96: 0x2be4, 0xb97: 0x2b2c, + 0xb98: 0x2a10, 0xb99: 0x2bf7, 0xb9a: 0x2c0a, 0xb9b: 0x2a1d, 0xb9c: 0x28bc, 0xb9d: 0x28c6, + 0xb9e: 0x2eb7, 0xb9f: 0x2a2a, 0xba0: 0x2b3c, 0xba1: 0x2ef5, 0xba2: 0x28d0, 0xba3: 0x28da, + 0xba4: 0x2a37, 0xba5: 0x28e4, 0xba6: 0x28ee, 0xba7: 0x26d0, 0xba8: 0x26d7, 0xba9: 0x28f8, + 0xbaa: 0x2902, 0xbab: 0x2c1d, 0xbac: 0x2a44, 0xbad: 0x2b4c, 0xbae: 0x2c30, 0xbaf: 0x2a51, + 0xbb0: 0x2916, 0xbb1: 0x290c, 0xbb2: 0x2f3c, 0xbb3: 0x2a5e, 0xbb4: 0x2c43, 0xbb5: 0x2920, + 0xbb6: 0x2b5c, 0xbb7: 0x292a, 0xbb8: 0x2a78, 0xbb9: 0x2934, 0xbba: 0x2a85, 0xbbb: 0x2f06, + 0xbbc: 0x2a6b, 0xbbd: 0x2b6c, 0xbbe: 0x2a92, 0xbbf: 0x26de, + // Block 0x2f, offset 0xbc0 + 0xbc0: 0x2f17, 0xbc1: 0x293e, 0xbc2: 0x2948, 0xbc3: 0x2a9f, 0xbc4: 0x2952, 0xbc5: 0x295c, + 0xbc6: 0x2966, 0xbc7: 0x2b7c, 0xbc8: 0x2aac, 0xbc9: 0x26e5, 0xbca: 0x2c56, 0xbcb: 0x2e90, + 0xbcc: 0x2b8c, 0xbcd: 0x2ab9, 0xbce: 0x2ec5, 0xbcf: 0x2970, 0xbd0: 0x297a, 0xbd1: 0x2ac6, + 0xbd2: 0x26ec, 0xbd3: 0x2ad3, 0xbd4: 0x2b9c, 0xbd5: 0x26f3, 0xbd6: 0x2c69, 0xbd7: 0x2984, + 0xbd8: 0x1cb7, 0xbd9: 0x1ccb, 0xbda: 0x1cda, 0xbdb: 0x1ce9, 0xbdc: 0x1cf8, 0xbdd: 0x1d07, + 0xbde: 0x1d16, 0xbdf: 0x1d25, 0xbe0: 0x1d34, 0xbe1: 0x1d43, 0xbe2: 0x2192, 0xbe3: 0x21a4, + 0xbe4: 0x21b6, 0xbe5: 0x21c2, 0xbe6: 0x21ce, 0xbe7: 0x21da, 0xbe8: 0x21e6, 0xbe9: 0x21f2, + 0xbea: 0x21fe, 0xbeb: 0x220a, 0xbec: 0x2246, 0xbed: 0x2252, 0xbee: 0x225e, 0xbef: 0x226a, + 0xbf0: 0x2276, 0xbf1: 0x1c14, 0xbf2: 0x19c6, 0xbf3: 0x1936, 0xbf4: 0x1be4, 0xbf5: 0x1a47, + 0xbf6: 0x1a56, 0xbf7: 0x19cc, 0xbf8: 0x1bfc, 0xbf9: 0x1c00, 0xbfa: 0x1960, 0xbfb: 0x2701, + 0xbfc: 0x270f, 0xbfd: 0x26fa, 0xbfe: 0x2708, 0xbff: 0x2ae0, + // Block 0x30, offset 0xc00 + 0xc00: 0x1a4a, 0xc01: 0x1a32, 0xc02: 0x1c60, 0xc03: 0x1a1a, 0xc04: 0x19f3, 0xc05: 0x1969, + 0xc06: 0x1978, 0xc07: 0x1948, 0xc08: 0x1bf0, 0xc09: 0x1d52, 0xc0a: 0x1a4d, 0xc0b: 0x1a35, + 0xc0c: 0x1c64, 0xc0d: 0x1c70, 0xc0e: 0x1a26, 0xc0f: 0x19fc, 0xc10: 0x1957, 0xc11: 0x1c1c, + 0xc12: 0x1bb0, 0xc13: 0x1b9c, 0xc14: 0x1bcc, 0xc15: 0x1c74, 0xc16: 0x1a29, 0xc17: 0x19c9, + 0xc18: 0x19ff, 0xc19: 0x19de, 0xc1a: 0x1a41, 0xc1b: 0x1c78, 0xc1c: 0x1a2c, 0xc1d: 0x19c0, + 0xc1e: 0x1a02, 0xc1f: 0x1c3c, 0xc20: 0x1bf4, 0xc21: 0x1a14, 0xc22: 0x1c24, 0xc23: 0x1c40, + 0xc24: 0x1bf8, 0xc25: 0x1a17, 0xc26: 0x1c28, 0xc27: 0x22e8, 0xc28: 0x22fc, 0xc29: 0x1996, + 0xc2a: 0x1c20, 0xc2b: 0x1bb4, 0xc2c: 0x1ba0, 0xc2d: 0x1c48, 0xc2e: 0x2716, 0xc2f: 0x27ad, + 0xc30: 0x1a59, 0xc31: 0x1a44, 0xc32: 0x1c7c, 0xc33: 0x1a2f, 0xc34: 0x1a50, 0xc35: 0x1a38, + 0xc36: 0x1c68, 0xc37: 0x1a1d, 0xc38: 0x19f6, 0xc39: 0x1981, 0xc3a: 0x1a53, 0xc3b: 0x1a3b, + 0xc3c: 0x1c6c, 0xc3d: 0x1a20, 0xc3e: 0x19f9, 0xc3f: 0x1984, + // Block 0x31, offset 0xc40 + 0xc40: 0x1c2c, 0xc41: 0x1bb8, 0xc42: 0x1d4d, 0xc43: 0x1939, 0xc44: 0x19ba, 0xc45: 0x19bd, + 0xc46: 0x22f5, 0xc47: 0x1b94, 0xc48: 0x19c3, 0xc49: 0x194b, 0xc4a: 0x19e1, 0xc4b: 0x194e, + 0xc4c: 0x19ea, 0xc4d: 0x196c, 0xc4e: 0x196f, 0xc4f: 0x1a05, 0xc50: 0x1a0b, 0xc51: 0x1a0e, + 0xc52: 0x1c30, 0xc53: 0x1a11, 0xc54: 0x1a23, 0xc55: 0x1c38, 0xc56: 0x1c44, 0xc57: 0x1990, + 0xc58: 0x1d57, 0xc59: 0x1bbc, 0xc5a: 0x1993, 0xc5b: 0x1a5c, 0xc5c: 0x19a5, 0xc5d: 0x19b4, + 0xc5e: 0x22e2, 0xc5f: 0x22dc, 0xc60: 0x1cc1, 0xc61: 0x1cd0, 0xc62: 0x1cdf, 0xc63: 0x1cee, + 0xc64: 0x1cfd, 0xc65: 0x1d0c, 0xc66: 0x1d1b, 0xc67: 0x1d2a, 0xc68: 0x1d39, 0xc69: 0x2186, + 0xc6a: 0x2198, 0xc6b: 0x21aa, 0xc6c: 0x21bc, 0xc6d: 0x21c8, 0xc6e: 0x21d4, 0xc6f: 0x21e0, + 0xc70: 0x21ec, 0xc71: 0x21f8, 0xc72: 0x2204, 0xc73: 0x2240, 0xc74: 0x224c, 0xc75: 0x2258, + 0xc76: 0x2264, 0xc77: 0x2270, 0xc78: 0x227c, 0xc79: 0x2282, 0xc7a: 0x2288, 0xc7b: 0x228e, + 0xc7c: 0x2294, 0xc7d: 0x22a6, 0xc7e: 0x22ac, 0xc7f: 0x1c10, + // Block 0x32, offset 0xc80 + 0xc80: 0x1377, 0xc81: 0x0cfb, 0xc82: 0x13d3, 0xc83: 0x139f, 0xc84: 0x0e57, 0xc85: 0x06eb, + 0xc86: 0x08df, 0xc87: 0x162b, 0xc88: 0x162b, 0xc89: 0x0a0b, 0xc8a: 0x145f, 0xc8b: 0x0943, + 0xc8c: 0x0a07, 0xc8d: 0x0bef, 0xc8e: 0x0fcf, 0xc8f: 0x115f, 0xc90: 0x1297, 0xc91: 0x12d3, + 0xc92: 0x1307, 0xc93: 0x141b, 0xc94: 0x0d73, 0xc95: 0x0dff, 0xc96: 0x0eab, 0xc97: 0x0f43, + 0xc98: 0x125f, 0xc99: 0x1447, 0xc9a: 0x1573, 0xc9b: 0x070f, 0xc9c: 0x08b3, 0xc9d: 0x0d87, + 0xc9e: 0x0ecf, 0xc9f: 0x1293, 0xca0: 0x15c3, 0xca1: 0x0ab3, 0xca2: 0x0e77, 0xca3: 0x1283, + 0xca4: 0x1317, 0xca5: 0x0c23, 0xca6: 0x11bb, 0xca7: 0x12df, 0xca8: 0x0b1f, 0xca9: 0x0d0f, + 0xcaa: 0x0e17, 0xcab: 0x0f1b, 0xcac: 0x1427, 0xcad: 0x074f, 0xcae: 0x07e7, 0xcaf: 0x0853, + 0xcb0: 0x0c8b, 0xcb1: 0x0d7f, 0xcb2: 0x0ecb, 0xcb3: 0x0fef, 0xcb4: 0x1177, 0xcb5: 0x128b, + 0xcb6: 0x12a3, 0xcb7: 0x13c7, 0xcb8: 0x14ef, 0xcb9: 0x15a3, 0xcba: 0x15bf, 0xcbb: 0x102b, + 0xcbc: 0x106b, 0xcbd: 0x1123, 0xcbe: 0x1243, 0xcbf: 0x147b, + // Block 0x33, offset 0xcc0 + 0xcc0: 0x15cb, 0xcc1: 0x134b, 0xcc2: 0x09c7, 0xcc3: 0x0b3b, 0xcc4: 0x10db, 0xcc5: 0x119b, + 0xcc6: 0x0eff, 0xcc7: 0x1033, 0xcc8: 0x1397, 0xcc9: 0x14e7, 0xcca: 0x09c3, 0xccb: 0x0a8f, + 0xccc: 0x0d77, 0xccd: 0x0e2b, 0xcce: 0x0e5f, 0xccf: 0x1113, 0xcd0: 0x113b, 0xcd1: 0x14a7, + 0xcd2: 0x084f, 0xcd3: 0x11a7, 0xcd4: 0x07f3, 0xcd5: 0x07ef, 0xcd6: 0x1097, 0xcd7: 0x1127, + 0xcd8: 0x125b, 0xcd9: 0x14af, 0xcda: 0x1367, 0xcdb: 0x0c27, 0xcdc: 0x0d73, 0xcdd: 0x1357, + 0xcde: 0x06f7, 0xcdf: 0x0a63, 0xce0: 0x0b93, 0xce1: 0x0f2f, 0xce2: 0x0faf, 0xce3: 0x0873, + 0xce4: 0x103b, 0xce5: 0x075f, 0xce6: 0x0b77, 0xce7: 0x06d7, 0xce8: 0x0deb, 0xce9: 0x0ca3, + 0xcea: 0x110f, 0xceb: 0x08c7, 0xcec: 0x09b3, 0xced: 0x0ffb, 0xcee: 0x1263, 0xcef: 0x133b, + 0xcf0: 0x0db7, 0xcf1: 0x13f7, 0xcf2: 0x0de3, 0xcf3: 0x0c37, 0xcf4: 0x121b, 0xcf5: 0x0c57, + 0xcf6: 0x0fab, 0xcf7: 0x072b, 0xcf8: 0x07a7, 0xcf9: 0x07eb, 0xcfa: 0x0d53, 0xcfb: 0x10fb, + 0xcfc: 0x11f3, 0xcfd: 0x1347, 0xcfe: 0x145b, 0xcff: 0x085b, + // Block 0x34, offset 0xd00 + 0xd00: 0x090f, 0xd01: 0x0a17, 0xd02: 0x0b2f, 0xd03: 0x0cbf, 0xd04: 0x0e7b, 0xd05: 0x103f, + 0xd06: 0x1497, 0xd07: 0x157b, 0xd08: 0x15cf, 0xd09: 0x15e7, 0xd0a: 0x0837, 0xd0b: 0x0cf3, + 0xd0c: 0x0da3, 0xd0d: 0x13eb, 0xd0e: 0x0afb, 0xd0f: 0x0bd7, 0xd10: 0x0bf3, 0xd11: 0x0c83, + 0xd12: 0x0e6b, 0xd13: 0x0eb7, 0xd14: 0x0f67, 0xd15: 0x108b, 0xd16: 0x112f, 0xd17: 0x1193, + 0xd18: 0x13db, 0xd19: 0x126b, 0xd1a: 0x1403, 0xd1b: 0x147f, 0xd1c: 0x080f, 0xd1d: 0x083b, + 0xd1e: 0x0923, 0xd1f: 0x0ea7, 0xd20: 0x12f3, 0xd21: 0x133b, 0xd22: 0x0b1b, 0xd23: 0x0b8b, + 0xd24: 0x0c4f, 0xd25: 0x0daf, 0xd26: 0x10d7, 0xd27: 0x0f23, 0xd28: 0x073b, 0xd29: 0x097f, + 0xd2a: 0x0a63, 0xd2b: 0x0ac7, 0xd2c: 0x0b97, 0xd2d: 0x0f3f, 0xd2e: 0x0f5b, 0xd2f: 0x116b, + 0xd30: 0x118b, 0xd31: 0x1463, 0xd32: 0x14e3, 0xd33: 0x14f3, 0xd34: 0x152f, 0xd35: 0x0753, + 0xd36: 0x107f, 0xd37: 0x144f, 0xd38: 0x14cb, 0xd39: 0x0baf, 0xd3a: 0x0717, 0xd3b: 0x0777, + 0xd3c: 0x0a67, 0xd3d: 0x0a87, 0xd3e: 0x0caf, 0xd3f: 0x0d73, + // Block 0x35, offset 0xd40 + 0xd40: 0x0ec3, 0xd41: 0x0fcb, 0xd42: 0x1277, 0xd43: 0x1417, 0xd44: 0x1623, 0xd45: 0x0ce3, + 0xd46: 0x14a3, 0xd47: 0x0833, 0xd48: 0x0d2f, 0xd49: 0x0d3b, 0xd4a: 0x0e0f, 0xd4b: 0x0e47, + 0xd4c: 0x0f4b, 0xd4d: 0x0fa7, 0xd4e: 0x1027, 0xd4f: 0x110b, 0xd50: 0x153b, 0xd51: 0x07af, + 0xd52: 0x0c03, 0xd53: 0x14b3, 0xd54: 0x0767, 0xd55: 0x0aab, 0xd56: 0x0e2f, 0xd57: 0x13df, + 0xd58: 0x0b67, 0xd59: 0x0bb7, 0xd5a: 0x0d43, 0xd5b: 0x0f2f, 0xd5c: 0x14bb, 0xd5d: 0x0817, + 0xd5e: 0x08ff, 0xd5f: 0x0a97, 0xd60: 0x0cd3, 0xd61: 0x0d1f, 0xd62: 0x0d5f, 0xd63: 0x0df3, + 0xd64: 0x0f47, 0xd65: 0x0fbb, 0xd66: 0x1157, 0xd67: 0x12f7, 0xd68: 0x1303, 0xd69: 0x1457, + 0xd6a: 0x14d7, 0xd6b: 0x0883, 0xd6c: 0x0e4b, 0xd6d: 0x0903, 0xd6e: 0x0ec7, 0xd6f: 0x0f6b, + 0xd70: 0x1287, 0xd71: 0x14bf, 0xd72: 0x15ab, 0xd73: 0x15d3, 0xd74: 0x0d37, 0xd75: 0x0e27, + 0xd76: 0x11c3, 0xd77: 0x10b7, 0xd78: 0x10c3, 0xd79: 0x10e7, 0xd7a: 0x0f17, 0xd7b: 0x0e9f, + 0xd7c: 0x1363, 0xd7d: 0x0733, 0xd7e: 0x122b, 0xd7f: 0x081b, + // Block 0x36, offset 0xd80 + 0xd80: 0x080b, 0xd81: 0x0b0b, 0xd82: 0x0c2b, 0xd83: 0x10f3, 0xd84: 0x0a53, 0xd85: 0x0e03, + 0xd86: 0x0cef, 0xd87: 0x13e7, 0xd88: 0x12e7, 0xd89: 0x14ab, 0xd8a: 0x1323, 0xd8b: 0x0b27, + 0xd8c: 0x0787, 0xd8d: 0x095b, 0xd90: 0x09af, + 0xd92: 0x0cdf, 0xd95: 0x07f7, 0xd96: 0x0f1f, 0xd97: 0x0fe3, + 0xd98: 0x1047, 0xd99: 0x1063, 0xd9a: 0x1067, 0xd9b: 0x107b, 0xd9c: 0x14fb, 0xd9d: 0x10eb, + 0xd9e: 0x116f, 0xda0: 0x128f, 0xda2: 0x1353, + 0xda5: 0x1407, 0xda6: 0x1433, + 0xdaa: 0x154f, 0xdab: 0x1553, 0xdac: 0x1557, 0xdad: 0x15bb, 0xdae: 0x142b, 0xdaf: 0x14c7, + 0xdb0: 0x0757, 0xdb1: 0x077b, 0xdb2: 0x078f, 0xdb3: 0x084b, 0xdb4: 0x0857, 0xdb5: 0x0897, + 0xdb6: 0x094b, 0xdb7: 0x0967, 0xdb8: 0x096f, 0xdb9: 0x09ab, 0xdba: 0x09b7, 0xdbb: 0x0a93, + 0xdbc: 0x0a9b, 0xdbd: 0x0ba3, 0xdbe: 0x0bcb, 0xdbf: 0x0bd3, + // Block 0x37, offset 0xdc0 + 0xdc0: 0x0beb, 0xdc1: 0x0c97, 0xdc2: 0x0cc7, 0xdc3: 0x0ce7, 0xdc4: 0x0d57, 0xdc5: 0x0e1b, + 0xdc6: 0x0e37, 0xdc7: 0x0e67, 0xdc8: 0x0ebb, 0xdc9: 0x0edb, 0xdca: 0x0f4f, 0xdcb: 0x102f, + 0xdcc: 0x104b, 0xdcd: 0x1053, 0xdce: 0x104f, 0xdcf: 0x1057, 0xdd0: 0x105b, 0xdd1: 0x105f, + 0xdd2: 0x1073, 0xdd3: 0x1077, 0xdd4: 0x109b, 0xdd5: 0x10af, 0xdd6: 0x10cb, 0xdd7: 0x112f, + 0xdd8: 0x1137, 0xdd9: 0x113f, 0xdda: 0x1153, 0xddb: 0x117b, 0xddc: 0x11cb, 0xddd: 0x11ff, + 0xdde: 0x11ff, 0xddf: 0x1267, 0xde0: 0x130f, 0xde1: 0x1327, 0xde2: 0x135b, 0xde3: 0x135f, + 0xde4: 0x13a3, 0xde5: 0x13a7, 0xde6: 0x13ff, 0xde7: 0x1407, 0xde8: 0x14db, 0xde9: 0x151f, + 0xdea: 0x1537, 0xdeb: 0x0b9b, 0xdec: 0x171e, 0xded: 0x11e3, + 0xdf0: 0x06df, 0xdf1: 0x07e3, 0xdf2: 0x07a3, 0xdf3: 0x074b, 0xdf4: 0x078b, 0xdf5: 0x07b7, + 0xdf6: 0x0847, 0xdf7: 0x0863, 0xdf8: 0x094b, 0xdf9: 0x0937, 0xdfa: 0x0947, 0xdfb: 0x0963, + 0xdfc: 0x09af, 0xdfd: 0x09bf, 0xdfe: 0x0a03, 0xdff: 0x0a0f, + // Block 0x38, offset 0xe00 + 0xe00: 0x0a2b, 0xe01: 0x0a3b, 0xe02: 0x0b23, 0xe03: 0x0b2b, 0xe04: 0x0b5b, 0xe05: 0x0b7b, + 0xe06: 0x0bab, 0xe07: 0x0bc3, 0xe08: 0x0bb3, 0xe09: 0x0bd3, 0xe0a: 0x0bc7, 0xe0b: 0x0beb, + 0xe0c: 0x0c07, 0xe0d: 0x0c5f, 0xe0e: 0x0c6b, 0xe0f: 0x0c73, 0xe10: 0x0c9b, 0xe11: 0x0cdf, + 0xe12: 0x0d0f, 0xe13: 0x0d13, 0xe14: 0x0d27, 0xe15: 0x0da7, 0xe16: 0x0db7, 0xe17: 0x0e0f, + 0xe18: 0x0e5b, 0xe19: 0x0e53, 0xe1a: 0x0e67, 0xe1b: 0x0e83, 0xe1c: 0x0ebb, 0xe1d: 0x1013, + 0xe1e: 0x0edf, 0xe1f: 0x0f13, 0xe20: 0x0f1f, 0xe21: 0x0f5f, 0xe22: 0x0f7b, 0xe23: 0x0f9f, + 0xe24: 0x0fc3, 0xe25: 0x0fc7, 0xe26: 0x0fe3, 0xe27: 0x0fe7, 0xe28: 0x0ff7, 0xe29: 0x100b, + 0xe2a: 0x1007, 0xe2b: 0x1037, 0xe2c: 0x10b3, 0xe2d: 0x10cb, 0xe2e: 0x10e3, 0xe2f: 0x111b, + 0xe30: 0x112f, 0xe31: 0x114b, 0xe32: 0x117b, 0xe33: 0x122f, 0xe34: 0x1257, 0xe35: 0x12cb, + 0xe36: 0x1313, 0xe37: 0x131f, 0xe38: 0x1327, 0xe39: 0x133f, 0xe3a: 0x1353, 0xe3b: 0x1343, + 0xe3c: 0x135b, 0xe3d: 0x1357, 0xe3e: 0x134f, 0xe3f: 0x135f, + // Block 0x39, offset 0xe40 + 0xe40: 0x136b, 0xe41: 0x13a7, 0xe42: 0x13e3, 0xe43: 0x1413, 0xe44: 0x144b, 0xe45: 0x146b, + 0xe46: 0x14b7, 0xe47: 0x14db, 0xe48: 0x14fb, 0xe49: 0x150f, 0xe4a: 0x151f, 0xe4b: 0x152b, + 0xe4c: 0x1537, 0xe4d: 0x158b, 0xe4e: 0x162b, 0xe4f: 0x16b5, 0xe50: 0x16b0, 0xe51: 0x16e2, + 0xe52: 0x0607, 0xe53: 0x062f, 0xe54: 0x0633, 0xe55: 0x1764, 0xe56: 0x1791, 0xe57: 0x1809, + 0xe58: 0x1617, 0xe59: 0x1627, + // Block 0x3a, offset 0xe80 + 0xe80: 0x19d5, 0xe81: 0x19d8, 0xe82: 0x19db, 0xe83: 0x1c08, 0xe84: 0x1c0c, 0xe85: 0x1a5f, + 0xe86: 0x1a5f, + 0xe93: 0x1d75, 0xe94: 0x1d66, 0xe95: 0x1d6b, 0xe96: 0x1d7a, 0xe97: 0x1d70, + 0xe9d: 0x4390, + 0xe9e: 0x8115, 0xe9f: 0x4402, 0xea0: 0x022d, 0xea1: 0x0215, 0xea2: 0x021e, 0xea3: 0x0221, + 0xea4: 0x0224, 0xea5: 0x0227, 0xea6: 0x022a, 0xea7: 0x0230, 0xea8: 0x0233, 0xea9: 0x0017, + 0xeaa: 0x43f0, 0xeab: 0x43f6, 0xeac: 0x44f4, 0xead: 0x44fc, 0xeae: 0x4348, 0xeaf: 0x434e, + 0xeb0: 0x4354, 0xeb1: 0x435a, 0xeb2: 0x4366, 0xeb3: 0x436c, 0xeb4: 0x4372, 0xeb5: 0x437e, + 0xeb6: 0x4384, 0xeb8: 0x438a, 0xeb9: 0x4396, 0xeba: 0x439c, 0xebb: 0x43a2, + 0xebc: 0x43ae, 0xebe: 0x43b4, + // Block 0x3b, offset 0xec0 + 0xec0: 0x43ba, 0xec1: 0x43c0, 0xec3: 0x43c6, 0xec4: 0x43cc, + 0xec6: 0x43d8, 0xec7: 0x43de, 0xec8: 0x43e4, 0xec9: 0x43ea, 0xeca: 0x43fc, 0xecb: 0x4378, + 0xecc: 0x4360, 0xecd: 0x43a8, 0xece: 0x43d2, 0xecf: 0x1d7f, 0xed0: 0x0299, 0xed1: 0x0299, + 0xed2: 0x02a2, 0xed3: 0x02a2, 0xed4: 0x02a2, 0xed5: 0x02a2, 0xed6: 0x02a5, 0xed7: 0x02a5, + 0xed8: 0x02a5, 0xed9: 0x02a5, 0xeda: 0x02ab, 0xedb: 0x02ab, 0xedc: 0x02ab, 0xedd: 0x02ab, + 0xede: 0x029f, 0xedf: 0x029f, 0xee0: 0x029f, 0xee1: 0x029f, 0xee2: 0x02a8, 0xee3: 0x02a8, + 0xee4: 0x02a8, 0xee5: 0x02a8, 0xee6: 0x029c, 0xee7: 0x029c, 0xee8: 0x029c, 0xee9: 0x029c, + 0xeea: 0x02cf, 0xeeb: 0x02cf, 0xeec: 0x02cf, 0xeed: 0x02cf, 0xeee: 0x02d2, 0xeef: 0x02d2, + 0xef0: 0x02d2, 0xef1: 0x02d2, 0xef2: 0x02b1, 0xef3: 0x02b1, 0xef4: 0x02b1, 0xef5: 0x02b1, + 0xef6: 0x02ae, 0xef7: 0x02ae, 0xef8: 0x02ae, 0xef9: 0x02ae, 0xefa: 0x02b4, 0xefb: 0x02b4, + 0xefc: 0x02b4, 0xefd: 0x02b4, 0xefe: 0x02b7, 0xeff: 0x02b7, + // Block 0x3c, offset 0xf00 + 0xf00: 0x02b7, 0xf01: 0x02b7, 0xf02: 0x02c0, 0xf03: 0x02c0, 0xf04: 0x02bd, 0xf05: 0x02bd, + 0xf06: 0x02c3, 0xf07: 0x02c3, 0xf08: 0x02ba, 0xf09: 0x02ba, 0xf0a: 0x02c9, 0xf0b: 0x02c9, + 0xf0c: 0x02c6, 0xf0d: 0x02c6, 0xf0e: 0x02d5, 0xf0f: 0x02d5, 0xf10: 0x02d5, 0xf11: 0x02d5, + 0xf12: 0x02db, 0xf13: 0x02db, 0xf14: 0x02db, 0xf15: 0x02db, 0xf16: 0x02e1, 0xf17: 0x02e1, + 0xf18: 0x02e1, 0xf19: 0x02e1, 0xf1a: 0x02de, 0xf1b: 0x02de, 0xf1c: 0x02de, 0xf1d: 0x02de, + 0xf1e: 0x02e4, 0xf1f: 0x02e4, 0xf20: 0x02e7, 0xf21: 0x02e7, 0xf22: 0x02e7, 0xf23: 0x02e7, + 0xf24: 0x446e, 0xf25: 0x446e, 0xf26: 0x02ed, 0xf27: 0x02ed, 0xf28: 0x02ed, 0xf29: 0x02ed, + 0xf2a: 0x02ea, 0xf2b: 0x02ea, 0xf2c: 0x02ea, 0xf2d: 0x02ea, 0xf2e: 0x0308, 0xf2f: 0x0308, + 0xf30: 0x4468, 0xf31: 0x4468, + // Block 0x3d, offset 0xf40 + 0xf53: 0x02d8, 0xf54: 0x02d8, 0xf55: 0x02d8, 0xf56: 0x02d8, 0xf57: 0x02f6, + 0xf58: 0x02f6, 0xf59: 0x02f3, 0xf5a: 0x02f3, 0xf5b: 0x02f9, 0xf5c: 0x02f9, 0xf5d: 0x204f, + 0xf5e: 0x02ff, 0xf5f: 0x02ff, 0xf60: 0x02f0, 0xf61: 0x02f0, 0xf62: 0x02fc, 0xf63: 0x02fc, + 0xf64: 0x0305, 0xf65: 0x0305, 0xf66: 0x0305, 0xf67: 0x0305, 0xf68: 0x028d, 0xf69: 0x028d, + 0xf6a: 0x25aa, 0xf6b: 0x25aa, 0xf6c: 0x261a, 0xf6d: 0x261a, 0xf6e: 0x25e9, 0xf6f: 0x25e9, + 0xf70: 0x2605, 0xf71: 0x2605, 0xf72: 0x25fe, 0xf73: 0x25fe, 0xf74: 0x260c, 0xf75: 0x260c, + 0xf76: 0x2613, 0xf77: 0x2613, 0xf78: 0x2613, 0xf79: 0x25f0, 0xf7a: 0x25f0, 0xf7b: 0x25f0, + 0xf7c: 0x0302, 0xf7d: 0x0302, 0xf7e: 0x0302, 0xf7f: 0x0302, + // Block 0x3e, offset 0xf80 + 0xf80: 0x25b1, 0xf81: 0x25b8, 0xf82: 0x25d4, 0xf83: 0x25f0, 0xf84: 0x25f7, 0xf85: 0x1d89, + 0xf86: 0x1d8e, 0xf87: 0x1d93, 0xf88: 0x1da2, 0xf89: 0x1db1, 0xf8a: 0x1db6, 0xf8b: 0x1dbb, + 0xf8c: 0x1dc0, 0xf8d: 0x1dc5, 0xf8e: 0x1dd4, 0xf8f: 0x1de3, 0xf90: 0x1de8, 0xf91: 0x1ded, + 0xf92: 0x1dfc, 0xf93: 0x1e0b, 0xf94: 0x1e10, 0xf95: 0x1e15, 0xf96: 0x1e1a, 0xf97: 0x1e29, + 0xf98: 0x1e2e, 0xf99: 0x1e3d, 0xf9a: 0x1e42, 0xf9b: 0x1e47, 0xf9c: 0x1e56, 0xf9d: 0x1e5b, + 0xf9e: 0x1e60, 0xf9f: 0x1e6a, 0xfa0: 0x1ea6, 0xfa1: 0x1eb5, 0xfa2: 0x1ec4, 0xfa3: 0x1ec9, + 0xfa4: 0x1ece, 0xfa5: 0x1ed8, 0xfa6: 0x1ee7, 0xfa7: 0x1eec, 0xfa8: 0x1efb, 0xfa9: 0x1f00, + 0xfaa: 0x1f05, 0xfab: 0x1f14, 0xfac: 0x1f19, 0xfad: 0x1f28, 0xfae: 0x1f2d, 0xfaf: 0x1f32, + 0xfb0: 0x1f37, 0xfb1: 0x1f3c, 0xfb2: 0x1f41, 0xfb3: 0x1f46, 0xfb4: 0x1f4b, 0xfb5: 0x1f50, + 0xfb6: 0x1f55, 0xfb7: 0x1f5a, 0xfb8: 0x1f5f, 0xfb9: 0x1f64, 0xfba: 0x1f69, 0xfbb: 0x1f6e, + 0xfbc: 0x1f73, 0xfbd: 0x1f78, 0xfbe: 0x1f7d, 0xfbf: 0x1f87, + // Block 0x3f, offset 0xfc0 + 0xfc0: 0x1f8c, 0xfc1: 0x1f91, 0xfc2: 0x1f96, 0xfc3: 0x1fa0, 0xfc4: 0x1fa5, 0xfc5: 0x1faf, + 0xfc6: 0x1fb4, 0xfc7: 0x1fb9, 0xfc8: 0x1fbe, 0xfc9: 0x1fc3, 0xfca: 0x1fc8, 0xfcb: 0x1fcd, + 0xfcc: 0x1fd2, 0xfcd: 0x1fd7, 0xfce: 0x1fe6, 0xfcf: 0x1ff5, 0xfd0: 0x1ffa, 0xfd1: 0x1fff, + 0xfd2: 0x2004, 0xfd3: 0x2009, 0xfd4: 0x200e, 0xfd5: 0x2018, 0xfd6: 0x201d, 0xfd7: 0x2022, + 0xfd8: 0x2031, 0xfd9: 0x2040, 0xfda: 0x2045, 0xfdb: 0x4420, 0xfdc: 0x4426, 0xfdd: 0x445c, + 0xfde: 0x44b3, 0xfdf: 0x44ba, 0xfe0: 0x44c1, 0xfe1: 0x44c8, 0xfe2: 0x44cf, 0xfe3: 0x44d6, + 0xfe4: 0x25c6, 0xfe5: 0x25cd, 0xfe6: 0x25d4, 0xfe7: 0x25db, 0xfe8: 0x25f0, 0xfe9: 0x25f7, + 0xfea: 0x1d98, 0xfeb: 0x1d9d, 0xfec: 0x1da2, 0xfed: 0x1da7, 0xfee: 0x1db1, 0xfef: 0x1db6, + 0xff0: 0x1dca, 0xff1: 0x1dcf, 0xff2: 0x1dd4, 0xff3: 0x1dd9, 0xff4: 0x1de3, 0xff5: 0x1de8, + 0xff6: 0x1df2, 0xff7: 0x1df7, 0xff8: 0x1dfc, 0xff9: 0x1e01, 0xffa: 0x1e0b, 0xffb: 0x1e10, + 0xffc: 0x1f3c, 0xffd: 0x1f41, 0xffe: 0x1f50, 0xfff: 0x1f55, + // Block 0x40, offset 0x1000 + 0x1000: 0x1f5a, 0x1001: 0x1f6e, 0x1002: 0x1f73, 0x1003: 0x1f78, 0x1004: 0x1f7d, 0x1005: 0x1f96, + 0x1006: 0x1fa0, 0x1007: 0x1fa5, 0x1008: 0x1faa, 0x1009: 0x1fbe, 0x100a: 0x1fdc, 0x100b: 0x1fe1, + 0x100c: 0x1fe6, 0x100d: 0x1feb, 0x100e: 0x1ff5, 0x100f: 0x1ffa, 0x1010: 0x445c, 0x1011: 0x2027, + 0x1012: 0x202c, 0x1013: 0x2031, 0x1014: 0x2036, 0x1015: 0x2040, 0x1016: 0x2045, 0x1017: 0x25b1, + 0x1018: 0x25b8, 0x1019: 0x25bf, 0x101a: 0x25d4, 0x101b: 0x25e2, 0x101c: 0x1d89, 0x101d: 0x1d8e, + 0x101e: 0x1d93, 0x101f: 0x1da2, 0x1020: 0x1dac, 0x1021: 0x1dbb, 0x1022: 0x1dc0, 0x1023: 0x1dc5, + 0x1024: 0x1dd4, 0x1025: 0x1dde, 0x1026: 0x1dfc, 0x1027: 0x1e15, 0x1028: 0x1e1a, 0x1029: 0x1e29, + 0x102a: 0x1e2e, 0x102b: 0x1e3d, 0x102c: 0x1e47, 0x102d: 0x1e56, 0x102e: 0x1e5b, 0x102f: 0x1e60, + 0x1030: 0x1e6a, 0x1031: 0x1ea6, 0x1032: 0x1eab, 0x1033: 0x1eb5, 0x1034: 0x1ec4, 0x1035: 0x1ec9, + 0x1036: 0x1ece, 0x1037: 0x1ed8, 0x1038: 0x1ee7, 0x1039: 0x1efb, 0x103a: 0x1f00, 0x103b: 0x1f05, + 0x103c: 0x1f14, 0x103d: 0x1f19, 0x103e: 0x1f28, 0x103f: 0x1f2d, + // Block 0x41, offset 0x1040 + 0x1040: 0x1f32, 0x1041: 0x1f37, 0x1042: 0x1f46, 0x1043: 0x1f4b, 0x1044: 0x1f5f, 0x1045: 0x1f64, + 0x1046: 0x1f69, 0x1047: 0x1f6e, 0x1048: 0x1f73, 0x1049: 0x1f87, 0x104a: 0x1f8c, 0x104b: 0x1f91, + 0x104c: 0x1f96, 0x104d: 0x1f9b, 0x104e: 0x1faf, 0x104f: 0x1fb4, 0x1050: 0x1fb9, 0x1051: 0x1fbe, + 0x1052: 0x1fcd, 0x1053: 0x1fd2, 0x1054: 0x1fd7, 0x1055: 0x1fe6, 0x1056: 0x1ff0, 0x1057: 0x1fff, + 0x1058: 0x2004, 0x1059: 0x4450, 0x105a: 0x2018, 0x105b: 0x201d, 0x105c: 0x2022, 0x105d: 0x2031, + 0x105e: 0x203b, 0x105f: 0x25d4, 0x1060: 0x25e2, 0x1061: 0x1da2, 0x1062: 0x1dac, 0x1063: 0x1dd4, + 0x1064: 0x1dde, 0x1065: 0x1dfc, 0x1066: 0x1e06, 0x1067: 0x1e6a, 0x1068: 0x1e6f, 0x1069: 0x1e92, + 0x106a: 0x1e97, 0x106b: 0x1f6e, 0x106c: 0x1f73, 0x106d: 0x1f96, 0x106e: 0x1fe6, 0x106f: 0x1ff0, + 0x1070: 0x2031, 0x1071: 0x203b, 0x1072: 0x4504, 0x1073: 0x450c, 0x1074: 0x4514, 0x1075: 0x1ef1, + 0x1076: 0x1ef6, 0x1077: 0x1f0a, 0x1078: 0x1f0f, 0x1079: 0x1f1e, 0x107a: 0x1f23, 0x107b: 0x1e74, + 0x107c: 0x1e79, 0x107d: 0x1e9c, 0x107e: 0x1ea1, 0x107f: 0x1e33, + // Block 0x42, offset 0x1080 + 0x1080: 0x1e38, 0x1081: 0x1e1f, 0x1082: 0x1e24, 0x1083: 0x1e4c, 0x1084: 0x1e51, 0x1085: 0x1eba, + 0x1086: 0x1ebf, 0x1087: 0x1edd, 0x1088: 0x1ee2, 0x1089: 0x1e7e, 0x108a: 0x1e83, 0x108b: 0x1e88, + 0x108c: 0x1e92, 0x108d: 0x1e8d, 0x108e: 0x1e65, 0x108f: 0x1eb0, 0x1090: 0x1ed3, 0x1091: 0x1ef1, + 0x1092: 0x1ef6, 0x1093: 0x1f0a, 0x1094: 0x1f0f, 0x1095: 0x1f1e, 0x1096: 0x1f23, 0x1097: 0x1e74, + 0x1098: 0x1e79, 0x1099: 0x1e9c, 0x109a: 0x1ea1, 0x109b: 0x1e33, 0x109c: 0x1e38, 0x109d: 0x1e1f, + 0x109e: 0x1e24, 0x109f: 0x1e4c, 0x10a0: 0x1e51, 0x10a1: 0x1eba, 0x10a2: 0x1ebf, 0x10a3: 0x1edd, + 0x10a4: 0x1ee2, 0x10a5: 0x1e7e, 0x10a6: 0x1e83, 0x10a7: 0x1e88, 0x10a8: 0x1e92, 0x10a9: 0x1e8d, + 0x10aa: 0x1e65, 0x10ab: 0x1eb0, 0x10ac: 0x1ed3, 0x10ad: 0x1e7e, 0x10ae: 0x1e83, 0x10af: 0x1e88, + 0x10b0: 0x1e92, 0x10b1: 0x1e6f, 0x10b2: 0x1e97, 0x10b3: 0x1eec, 0x10b4: 0x1e56, 0x10b5: 0x1e5b, + 0x10b6: 0x1e60, 0x10b7: 0x1e7e, 0x10b8: 0x1e83, 0x10b9: 0x1e88, 0x10ba: 0x1eec, 0x10bb: 0x1efb, + 0x10bc: 0x4408, 0x10bd: 0x4408, + // Block 0x43, offset 0x10c0 + 0x10d0: 0x2311, 0x10d1: 0x2326, + 0x10d2: 0x2326, 0x10d3: 0x232d, 0x10d4: 0x2334, 0x10d5: 0x2349, 0x10d6: 0x2350, 0x10d7: 0x2357, + 0x10d8: 0x237a, 0x10d9: 0x237a, 0x10da: 0x239d, 0x10db: 0x2396, 0x10dc: 0x23b2, 0x10dd: 0x23a4, + 0x10de: 0x23ab, 0x10df: 0x23ce, 0x10e0: 0x23ce, 0x10e1: 0x23c7, 0x10e2: 0x23d5, 0x10e3: 0x23d5, + 0x10e4: 0x23ff, 0x10e5: 0x23ff, 0x10e6: 0x241b, 0x10e7: 0x23e3, 0x10e8: 0x23e3, 0x10e9: 0x23dc, + 0x10ea: 0x23f1, 0x10eb: 0x23f1, 0x10ec: 0x23f8, 0x10ed: 0x23f8, 0x10ee: 0x2422, 0x10ef: 0x2430, + 0x10f0: 0x2430, 0x10f1: 0x2437, 0x10f2: 0x2437, 0x10f3: 0x243e, 0x10f4: 0x2445, 0x10f5: 0x244c, + 0x10f6: 0x2453, 0x10f7: 0x2453, 0x10f8: 0x245a, 0x10f9: 0x2468, 0x10fa: 0x2476, 0x10fb: 0x246f, + 0x10fc: 0x247d, 0x10fd: 0x247d, 0x10fe: 0x2492, 0x10ff: 0x2499, + // Block 0x44, offset 0x1100 + 0x1100: 0x24ca, 0x1101: 0x24d8, 0x1102: 0x24d1, 0x1103: 0x24b5, 0x1104: 0x24b5, 0x1105: 0x24df, + 0x1106: 0x24df, 0x1107: 0x24e6, 0x1108: 0x24e6, 0x1109: 0x2510, 0x110a: 0x2517, 0x110b: 0x251e, + 0x110c: 0x24f4, 0x110d: 0x2502, 0x110e: 0x2525, 0x110f: 0x252c, + 0x1112: 0x24fb, 0x1113: 0x2580, 0x1114: 0x2587, 0x1115: 0x255d, 0x1116: 0x2564, 0x1117: 0x2548, + 0x1118: 0x2548, 0x1119: 0x254f, 0x111a: 0x2579, 0x111b: 0x2572, 0x111c: 0x259c, 0x111d: 0x259c, + 0x111e: 0x230a, 0x111f: 0x231f, 0x1120: 0x2318, 0x1121: 0x2342, 0x1122: 0x233b, 0x1123: 0x2365, + 0x1124: 0x235e, 0x1125: 0x2388, 0x1126: 0x236c, 0x1127: 0x2381, 0x1128: 0x23b9, 0x1129: 0x2406, + 0x112a: 0x23ea, 0x112b: 0x2429, 0x112c: 0x24c3, 0x112d: 0x24ed, 0x112e: 0x2595, 0x112f: 0x258e, + 0x1130: 0x25a3, 0x1131: 0x253a, 0x1132: 0x24a0, 0x1133: 0x256b, 0x1134: 0x2492, 0x1135: 0x24ca, + 0x1136: 0x2461, 0x1137: 0x24ae, 0x1138: 0x2541, 0x1139: 0x2533, 0x113a: 0x24bc, 0x113b: 0x24a7, + 0x113c: 0x24bc, 0x113d: 0x2541, 0x113e: 0x2373, 0x113f: 0x238f, + // Block 0x45, offset 0x1140 + 0x1140: 0x2509, 0x1141: 0x2484, 0x1142: 0x2303, 0x1143: 0x24a7, 0x1144: 0x244c, 0x1145: 0x241b, + 0x1146: 0x23c0, 0x1147: 0x2556, + 0x1170: 0x2414, 0x1171: 0x248b, 0x1172: 0x27bf, 0x1173: 0x27b6, 0x1174: 0x27ec, 0x1175: 0x27da, + 0x1176: 0x27c8, 0x1177: 0x27e3, 0x1178: 0x27f5, 0x1179: 0x240d, 0x117a: 0x2c7c, 0x117b: 0x2afc, + 0x117c: 0x27d1, + // Block 0x46, offset 0x1180 + 0x1190: 0x0019, 0x1191: 0x0483, + 0x1192: 0x0487, 0x1193: 0x0035, 0x1194: 0x0037, 0x1195: 0x0003, 0x1196: 0x003f, 0x1197: 0x04bf, + 0x1198: 0x04c3, 0x1199: 0x1b5c, + 0x11a0: 0x8132, 0x11a1: 0x8132, 0x11a2: 0x8132, 0x11a3: 0x8132, + 0x11a4: 0x8132, 0x11a5: 0x8132, 0x11a6: 0x8132, 0x11a7: 0x812d, 0x11a8: 0x812d, 0x11a9: 0x812d, + 0x11aa: 0x812d, 0x11ab: 0x812d, 0x11ac: 0x812d, 0x11ad: 0x812d, 0x11ae: 0x8132, 0x11af: 0x8132, + 0x11b0: 0x1873, 0x11b1: 0x0443, 0x11b2: 0x043f, 0x11b3: 0x007f, 0x11b4: 0x007f, 0x11b5: 0x0011, + 0x11b6: 0x0013, 0x11b7: 0x00b7, 0x11b8: 0x00bb, 0x11b9: 0x04b7, 0x11ba: 0x04bb, 0x11bb: 0x04ab, + 0x11bc: 0x04af, 0x11bd: 0x0493, 0x11be: 0x0497, 0x11bf: 0x048b, + // Block 0x47, offset 0x11c0 + 0x11c0: 0x048f, 0x11c1: 0x049b, 0x11c2: 0x049f, 0x11c3: 0x04a3, 0x11c4: 0x04a7, + 0x11c7: 0x0077, 0x11c8: 0x007b, 0x11c9: 0x4269, 0x11ca: 0x4269, 0x11cb: 0x4269, + 0x11cc: 0x4269, 0x11cd: 0x007f, 0x11ce: 0x007f, 0x11cf: 0x007f, 0x11d0: 0x0019, 0x11d1: 0x0483, + 0x11d2: 0x001d, 0x11d4: 0x0037, 0x11d5: 0x0035, 0x11d6: 0x003f, 0x11d7: 0x0003, + 0x11d8: 0x0443, 0x11d9: 0x0011, 0x11da: 0x0013, 0x11db: 0x00b7, 0x11dc: 0x00bb, 0x11dd: 0x04b7, + 0x11de: 0x04bb, 0x11df: 0x0007, 0x11e0: 0x000d, 0x11e1: 0x0015, 0x11e2: 0x0017, 0x11e3: 0x001b, + 0x11e4: 0x0039, 0x11e5: 0x003d, 0x11e6: 0x003b, 0x11e8: 0x0079, 0x11e9: 0x0009, + 0x11ea: 0x000b, 0x11eb: 0x0041, + 0x11f0: 0x42aa, 0x11f1: 0x442c, 0x11f2: 0x42af, 0x11f4: 0x42b4, + 0x11f6: 0x42b9, 0x11f7: 0x4432, 0x11f8: 0x42be, 0x11f9: 0x4438, 0x11fa: 0x42c3, 0x11fb: 0x443e, + 0x11fc: 0x42c8, 0x11fd: 0x4444, 0x11fe: 0x42cd, 0x11ff: 0x444a, + // Block 0x48, offset 0x1200 + 0x1200: 0x0236, 0x1201: 0x440e, 0x1202: 0x440e, 0x1203: 0x4414, 0x1204: 0x4414, 0x1205: 0x4456, + 0x1206: 0x4456, 0x1207: 0x441a, 0x1208: 0x441a, 0x1209: 0x4462, 0x120a: 0x4462, 0x120b: 0x4462, + 0x120c: 0x4462, 0x120d: 0x0239, 0x120e: 0x0239, 0x120f: 0x023c, 0x1210: 0x023c, 0x1211: 0x023c, + 0x1212: 0x023c, 0x1213: 0x023f, 0x1214: 0x023f, 0x1215: 0x0242, 0x1216: 0x0242, 0x1217: 0x0242, + 0x1218: 0x0242, 0x1219: 0x0245, 0x121a: 0x0245, 0x121b: 0x0245, 0x121c: 0x0245, 0x121d: 0x0248, + 0x121e: 0x0248, 0x121f: 0x0248, 0x1220: 0x0248, 0x1221: 0x024b, 0x1222: 0x024b, 0x1223: 0x024b, + 0x1224: 0x024b, 0x1225: 0x024e, 0x1226: 0x024e, 0x1227: 0x024e, 0x1228: 0x024e, 0x1229: 0x0251, + 0x122a: 0x0251, 0x122b: 0x0254, 0x122c: 0x0254, 0x122d: 0x0257, 0x122e: 0x0257, 0x122f: 0x025a, + 0x1230: 0x025a, 0x1231: 0x025d, 0x1232: 0x025d, 0x1233: 0x025d, 0x1234: 0x025d, 0x1235: 0x0260, + 0x1236: 0x0260, 0x1237: 0x0260, 0x1238: 0x0260, 0x1239: 0x0263, 0x123a: 0x0263, 0x123b: 0x0263, + 0x123c: 0x0263, 0x123d: 0x0266, 0x123e: 0x0266, 0x123f: 0x0266, + // Block 0x49, offset 0x1240 + 0x1240: 0x0266, 0x1241: 0x0269, 0x1242: 0x0269, 0x1243: 0x0269, 0x1244: 0x0269, 0x1245: 0x026c, + 0x1246: 0x026c, 0x1247: 0x026c, 0x1248: 0x026c, 0x1249: 0x026f, 0x124a: 0x026f, 0x124b: 0x026f, + 0x124c: 0x026f, 0x124d: 0x0272, 0x124e: 0x0272, 0x124f: 0x0272, 0x1250: 0x0272, 0x1251: 0x0275, + 0x1252: 0x0275, 0x1253: 0x0275, 0x1254: 0x0275, 0x1255: 0x0278, 0x1256: 0x0278, 0x1257: 0x0278, + 0x1258: 0x0278, 0x1259: 0x027b, 0x125a: 0x027b, 0x125b: 0x027b, 0x125c: 0x027b, 0x125d: 0x027e, + 0x125e: 0x027e, 0x125f: 0x027e, 0x1260: 0x027e, 0x1261: 0x0281, 0x1262: 0x0281, 0x1263: 0x0281, + 0x1264: 0x0281, 0x1265: 0x0284, 0x1266: 0x0284, 0x1267: 0x0284, 0x1268: 0x0284, 0x1269: 0x0287, + 0x126a: 0x0287, 0x126b: 0x0287, 0x126c: 0x0287, 0x126d: 0x028a, 0x126e: 0x028a, 0x126f: 0x028d, + 0x1270: 0x028d, 0x1271: 0x0290, 0x1272: 0x0290, 0x1273: 0x0290, 0x1274: 0x0290, 0x1275: 0x2e00, + 0x1276: 0x2e00, 0x1277: 0x2e08, 0x1278: 0x2e08, 0x1279: 0x2e10, 0x127a: 0x2e10, 0x127b: 0x1f82, + 0x127c: 0x1f82, + // Block 0x4a, offset 0x1280 + 0x1280: 0x0081, 0x1281: 0x0083, 0x1282: 0x0085, 0x1283: 0x0087, 0x1284: 0x0089, 0x1285: 0x008b, + 0x1286: 0x008d, 0x1287: 0x008f, 0x1288: 0x0091, 0x1289: 0x0093, 0x128a: 0x0095, 0x128b: 0x0097, + 0x128c: 0x0099, 0x128d: 0x009b, 0x128e: 0x009d, 0x128f: 0x009f, 0x1290: 0x00a1, 0x1291: 0x00a3, + 0x1292: 0x00a5, 0x1293: 0x00a7, 0x1294: 0x00a9, 0x1295: 0x00ab, 0x1296: 0x00ad, 0x1297: 0x00af, + 0x1298: 0x00b1, 0x1299: 0x00b3, 0x129a: 0x00b5, 0x129b: 0x00b7, 0x129c: 0x00b9, 0x129d: 0x00bb, + 0x129e: 0x00bd, 0x129f: 0x0477, 0x12a0: 0x047b, 0x12a1: 0x0487, 0x12a2: 0x049b, 0x12a3: 0x049f, + 0x12a4: 0x0483, 0x12a5: 0x05ab, 0x12a6: 0x05a3, 0x12a7: 0x04c7, 0x12a8: 0x04cf, 0x12a9: 0x04d7, + 0x12aa: 0x04df, 0x12ab: 0x04e7, 0x12ac: 0x056b, 0x12ad: 0x0573, 0x12ae: 0x057b, 0x12af: 0x051f, + 0x12b0: 0x05af, 0x12b1: 0x04cb, 0x12b2: 0x04d3, 0x12b3: 0x04db, 0x12b4: 0x04e3, 0x12b5: 0x04eb, + 0x12b6: 0x04ef, 0x12b7: 0x04f3, 0x12b8: 0x04f7, 0x12b9: 0x04fb, 0x12ba: 0x04ff, 0x12bb: 0x0503, + 0x12bc: 0x0507, 0x12bd: 0x050b, 0x12be: 0x050f, 0x12bf: 0x0513, + // Block 0x4b, offset 0x12c0 + 0x12c0: 0x0517, 0x12c1: 0x051b, 0x12c2: 0x0523, 0x12c3: 0x0527, 0x12c4: 0x052b, 0x12c5: 0x052f, + 0x12c6: 0x0533, 0x12c7: 0x0537, 0x12c8: 0x053b, 0x12c9: 0x053f, 0x12ca: 0x0543, 0x12cb: 0x0547, + 0x12cc: 0x054b, 0x12cd: 0x054f, 0x12ce: 0x0553, 0x12cf: 0x0557, 0x12d0: 0x055b, 0x12d1: 0x055f, + 0x12d2: 0x0563, 0x12d3: 0x0567, 0x12d4: 0x056f, 0x12d5: 0x0577, 0x12d6: 0x057f, 0x12d7: 0x0583, + 0x12d8: 0x0587, 0x12d9: 0x058b, 0x12da: 0x058f, 0x12db: 0x0593, 0x12dc: 0x0597, 0x12dd: 0x05a7, + 0x12de: 0x4a78, 0x12df: 0x4a7e, 0x12e0: 0x03c3, 0x12e1: 0x0313, 0x12e2: 0x0317, 0x12e3: 0x4a3b, + 0x12e4: 0x031b, 0x12e5: 0x4a41, 0x12e6: 0x4a47, 0x12e7: 0x031f, 0x12e8: 0x0323, 0x12e9: 0x0327, + 0x12ea: 0x4a4d, 0x12eb: 0x4a53, 0x12ec: 0x4a59, 0x12ed: 0x4a5f, 0x12ee: 0x4a65, 0x12ef: 0x4a6b, + 0x12f0: 0x0367, 0x12f1: 0x032b, 0x12f2: 0x032f, 0x12f3: 0x0333, 0x12f4: 0x037b, 0x12f5: 0x0337, + 0x12f6: 0x033b, 0x12f7: 0x033f, 0x12f8: 0x0343, 0x12f9: 0x0347, 0x12fa: 0x034b, 0x12fb: 0x034f, + 0x12fc: 0x0353, 0x12fd: 0x0357, 0x12fe: 0x035b, + // Block 0x4c, offset 0x1300 + 0x1302: 0x49bd, 0x1303: 0x49c3, 0x1304: 0x49c9, 0x1305: 0x49cf, + 0x1306: 0x49d5, 0x1307: 0x49db, 0x130a: 0x49e1, 0x130b: 0x49e7, + 0x130c: 0x49ed, 0x130d: 0x49f3, 0x130e: 0x49f9, 0x130f: 0x49ff, + 0x1312: 0x4a05, 0x1313: 0x4a0b, 0x1314: 0x4a11, 0x1315: 0x4a17, 0x1316: 0x4a1d, 0x1317: 0x4a23, + 0x131a: 0x4a29, 0x131b: 0x4a2f, 0x131c: 0x4a35, + 0x1320: 0x00bf, 0x1321: 0x00c2, 0x1322: 0x00cb, 0x1323: 0x4264, + 0x1324: 0x00c8, 0x1325: 0x00c5, 0x1326: 0x0447, 0x1328: 0x046b, 0x1329: 0x044b, + 0x132a: 0x044f, 0x132b: 0x0453, 0x132c: 0x0457, 0x132d: 0x046f, 0x132e: 0x0473, + // Block 0x4d, offset 0x1340 + 0x1340: 0x0063, 0x1341: 0x0065, 0x1342: 0x0067, 0x1343: 0x0069, 0x1344: 0x006b, 0x1345: 0x006d, + 0x1346: 0x006f, 0x1347: 0x0071, 0x1348: 0x0073, 0x1349: 0x0075, 0x134a: 0x0083, 0x134b: 0x0085, + 0x134c: 0x0087, 0x134d: 0x0089, 0x134e: 0x008b, 0x134f: 0x008d, 0x1350: 0x008f, 0x1351: 0x0091, + 0x1352: 0x0093, 0x1353: 0x0095, 0x1354: 0x0097, 0x1355: 0x0099, 0x1356: 0x009b, 0x1357: 0x009d, + 0x1358: 0x009f, 0x1359: 0x00a1, 0x135a: 0x00a3, 0x135b: 0x00a5, 0x135c: 0x00a7, 0x135d: 0x00a9, + 0x135e: 0x00ab, 0x135f: 0x00ad, 0x1360: 0x00af, 0x1361: 0x00b1, 0x1362: 0x00b3, 0x1363: 0x00b5, + 0x1364: 0x00dd, 0x1365: 0x00f2, 0x1368: 0x0173, 0x1369: 0x0176, + 0x136a: 0x0179, 0x136b: 0x017c, 0x136c: 0x017f, 0x136d: 0x0182, 0x136e: 0x0185, 0x136f: 0x0188, + 0x1370: 0x018b, 0x1371: 0x018e, 0x1372: 0x0191, 0x1373: 0x0194, 0x1374: 0x0197, 0x1375: 0x019a, + 0x1376: 0x019d, 0x1377: 0x01a0, 0x1378: 0x01a3, 0x1379: 0x0188, 0x137a: 0x01a6, 0x137b: 0x01a9, + 0x137c: 0x01ac, 0x137d: 0x01af, 0x137e: 0x01b2, 0x137f: 0x01b5, + // Block 0x4e, offset 0x1380 + 0x1380: 0x01fd, 0x1381: 0x0200, 0x1382: 0x0203, 0x1383: 0x045b, 0x1384: 0x01c7, 0x1385: 0x01d0, + 0x1386: 0x01d6, 0x1387: 0x01fa, 0x1388: 0x01eb, 0x1389: 0x01e8, 0x138a: 0x0206, 0x138b: 0x0209, + 0x138e: 0x0021, 0x138f: 0x0023, 0x1390: 0x0025, 0x1391: 0x0027, + 0x1392: 0x0029, 0x1393: 0x002b, 0x1394: 0x002d, 0x1395: 0x002f, 0x1396: 0x0031, 0x1397: 0x0033, + 0x1398: 0x0021, 0x1399: 0x0023, 0x139a: 0x0025, 0x139b: 0x0027, 0x139c: 0x0029, 0x139d: 0x002b, + 0x139e: 0x002d, 0x139f: 0x002f, 0x13a0: 0x0031, 0x13a1: 0x0033, 0x13a2: 0x0021, 0x13a3: 0x0023, + 0x13a4: 0x0025, 0x13a5: 0x0027, 0x13a6: 0x0029, 0x13a7: 0x002b, 0x13a8: 0x002d, 0x13a9: 0x002f, + 0x13aa: 0x0031, 0x13ab: 0x0033, 0x13ac: 0x0021, 0x13ad: 0x0023, 0x13ae: 0x0025, 0x13af: 0x0027, + 0x13b0: 0x0029, 0x13b1: 0x002b, 0x13b2: 0x002d, 0x13b3: 0x002f, 0x13b4: 0x0031, 0x13b5: 0x0033, + 0x13b6: 0x0021, 0x13b7: 0x0023, 0x13b8: 0x0025, 0x13b9: 0x0027, 0x13ba: 0x0029, 0x13bb: 0x002b, + 0x13bc: 0x002d, 0x13bd: 0x002f, 0x13be: 0x0031, 0x13bf: 0x0033, + // Block 0x4f, offset 0x13c0 + 0x13c0: 0x0239, 0x13c1: 0x023c, 0x13c2: 0x0248, 0x13c3: 0x0251, 0x13c5: 0x028a, + 0x13c6: 0x025a, 0x13c7: 0x024b, 0x13c8: 0x0269, 0x13c9: 0x0290, 0x13ca: 0x027b, 0x13cb: 0x027e, + 0x13cc: 0x0281, 0x13cd: 0x0284, 0x13ce: 0x025d, 0x13cf: 0x026f, 0x13d0: 0x0275, 0x13d1: 0x0263, + 0x13d2: 0x0278, 0x13d3: 0x0257, 0x13d4: 0x0260, 0x13d5: 0x0242, 0x13d6: 0x0245, 0x13d7: 0x024e, + 0x13d8: 0x0254, 0x13d9: 0x0266, 0x13da: 0x026c, 0x13db: 0x0272, 0x13dc: 0x0293, 0x13dd: 0x02e4, + 0x13de: 0x02cc, 0x13df: 0x0296, 0x13e1: 0x023c, 0x13e2: 0x0248, + 0x13e4: 0x0287, 0x13e7: 0x024b, 0x13e9: 0x0290, + 0x13ea: 0x027b, 0x13eb: 0x027e, 0x13ec: 0x0281, 0x13ed: 0x0284, 0x13ee: 0x025d, 0x13ef: 0x026f, + 0x13f0: 0x0275, 0x13f1: 0x0263, 0x13f2: 0x0278, 0x13f4: 0x0260, 0x13f5: 0x0242, + 0x13f6: 0x0245, 0x13f7: 0x024e, 0x13f9: 0x0266, 0x13fb: 0x0272, + // Block 0x50, offset 0x1400 + 0x1402: 0x0248, + 0x1407: 0x024b, 0x1409: 0x0290, 0x140b: 0x027e, + 0x140d: 0x0284, 0x140e: 0x025d, 0x140f: 0x026f, 0x1411: 0x0263, + 0x1412: 0x0278, 0x1414: 0x0260, 0x1417: 0x024e, + 0x1419: 0x0266, 0x141b: 0x0272, 0x141d: 0x02e4, + 0x141f: 0x0296, 0x1421: 0x023c, 0x1422: 0x0248, + 0x1424: 0x0287, 0x1427: 0x024b, 0x1428: 0x0269, 0x1429: 0x0290, + 0x142a: 0x027b, 0x142c: 0x0281, 0x142d: 0x0284, 0x142e: 0x025d, 0x142f: 0x026f, + 0x1430: 0x0275, 0x1431: 0x0263, 0x1432: 0x0278, 0x1434: 0x0260, 0x1435: 0x0242, + 0x1436: 0x0245, 0x1437: 0x024e, 0x1439: 0x0266, 0x143a: 0x026c, 0x143b: 0x0272, + 0x143c: 0x0293, 0x143e: 0x02cc, + // Block 0x51, offset 0x1440 + 0x1440: 0x0239, 0x1441: 0x023c, 0x1442: 0x0248, 0x1443: 0x0251, 0x1444: 0x0287, 0x1445: 0x028a, + 0x1446: 0x025a, 0x1447: 0x024b, 0x1448: 0x0269, 0x1449: 0x0290, 0x144b: 0x027e, + 0x144c: 0x0281, 0x144d: 0x0284, 0x144e: 0x025d, 0x144f: 0x026f, 0x1450: 0x0275, 0x1451: 0x0263, + 0x1452: 0x0278, 0x1453: 0x0257, 0x1454: 0x0260, 0x1455: 0x0242, 0x1456: 0x0245, 0x1457: 0x024e, + 0x1458: 0x0254, 0x1459: 0x0266, 0x145a: 0x026c, 0x145b: 0x0272, + 0x1461: 0x023c, 0x1462: 0x0248, 0x1463: 0x0251, + 0x1465: 0x028a, 0x1466: 0x025a, 0x1467: 0x024b, 0x1468: 0x0269, 0x1469: 0x0290, + 0x146b: 0x027e, 0x146c: 0x0281, 0x146d: 0x0284, 0x146e: 0x025d, 0x146f: 0x026f, + 0x1470: 0x0275, 0x1471: 0x0263, 0x1472: 0x0278, 0x1473: 0x0257, 0x1474: 0x0260, 0x1475: 0x0242, + 0x1476: 0x0245, 0x1477: 0x024e, 0x1478: 0x0254, 0x1479: 0x0266, 0x147a: 0x026c, 0x147b: 0x0272, + // Block 0x52, offset 0x1480 + 0x1480: 0x1879, 0x1481: 0x1876, 0x1482: 0x187c, 0x1483: 0x18a0, 0x1484: 0x18c4, 0x1485: 0x18e8, + 0x1486: 0x190c, 0x1487: 0x1915, 0x1488: 0x191b, 0x1489: 0x1921, 0x148a: 0x1927, + 0x1490: 0x1a8c, 0x1491: 0x1a90, + 0x1492: 0x1a94, 0x1493: 0x1a98, 0x1494: 0x1a9c, 0x1495: 0x1aa0, 0x1496: 0x1aa4, 0x1497: 0x1aa8, + 0x1498: 0x1aac, 0x1499: 0x1ab0, 0x149a: 0x1ab4, 0x149b: 0x1ab8, 0x149c: 0x1abc, 0x149d: 0x1ac0, + 0x149e: 0x1ac4, 0x149f: 0x1ac8, 0x14a0: 0x1acc, 0x14a1: 0x1ad0, 0x14a2: 0x1ad4, 0x14a3: 0x1ad8, + 0x14a4: 0x1adc, 0x14a5: 0x1ae0, 0x14a6: 0x1ae4, 0x14a7: 0x1ae8, 0x14a8: 0x1aec, 0x14a9: 0x1af0, + 0x14aa: 0x271e, 0x14ab: 0x0047, 0x14ac: 0x0065, 0x14ad: 0x193c, 0x14ae: 0x19b1, + 0x14b0: 0x0043, 0x14b1: 0x0045, 0x14b2: 0x0047, 0x14b3: 0x0049, 0x14b4: 0x004b, 0x14b5: 0x004d, + 0x14b6: 0x004f, 0x14b7: 0x0051, 0x14b8: 0x0053, 0x14b9: 0x0055, 0x14ba: 0x0057, 0x14bb: 0x0059, + 0x14bc: 0x005b, 0x14bd: 0x005d, 0x14be: 0x005f, 0x14bf: 0x0061, + // Block 0x53, offset 0x14c0 + 0x14c0: 0x26ad, 0x14c1: 0x26c2, 0x14c2: 0x0503, + 0x14d0: 0x0c0f, 0x14d1: 0x0a47, + 0x14d2: 0x08d3, 0x14d3: 0x45c4, 0x14d4: 0x071b, 0x14d5: 0x09ef, 0x14d6: 0x132f, 0x14d7: 0x09ff, + 0x14d8: 0x0727, 0x14d9: 0x0cd7, 0x14da: 0x0eaf, 0x14db: 0x0caf, 0x14dc: 0x0827, 0x14dd: 0x0b6b, + 0x14de: 0x07bf, 0x14df: 0x0cb7, 0x14e0: 0x0813, 0x14e1: 0x1117, 0x14e2: 0x0f83, 0x14e3: 0x138b, + 0x14e4: 0x09d3, 0x14e5: 0x090b, 0x14e6: 0x0e63, 0x14e7: 0x0c1b, 0x14e8: 0x0c47, 0x14e9: 0x06bf, + 0x14ea: 0x06cb, 0x14eb: 0x140b, 0x14ec: 0x0adb, 0x14ed: 0x06e7, 0x14ee: 0x08ef, 0x14ef: 0x0c3b, + 0x14f0: 0x13b3, 0x14f1: 0x0c13, 0x14f2: 0x106f, 0x14f3: 0x10ab, 0x14f4: 0x08f7, 0x14f5: 0x0e43, + 0x14f6: 0x0d0b, 0x14f7: 0x0d07, 0x14f8: 0x0f97, 0x14f9: 0x082b, 0x14fa: 0x0957, 0x14fb: 0x1443, + // Block 0x54, offset 0x1500 + 0x1500: 0x06fb, 0x1501: 0x06f3, 0x1502: 0x0703, 0x1503: 0x1647, 0x1504: 0x0747, 0x1505: 0x0757, + 0x1506: 0x075b, 0x1507: 0x0763, 0x1508: 0x076b, 0x1509: 0x076f, 0x150a: 0x077b, 0x150b: 0x0773, + 0x150c: 0x05b3, 0x150d: 0x165b, 0x150e: 0x078f, 0x150f: 0x0793, 0x1510: 0x0797, 0x1511: 0x07b3, + 0x1512: 0x164c, 0x1513: 0x05b7, 0x1514: 0x079f, 0x1515: 0x07bf, 0x1516: 0x1656, 0x1517: 0x07cf, + 0x1518: 0x07d7, 0x1519: 0x0737, 0x151a: 0x07df, 0x151b: 0x07e3, 0x151c: 0x1831, 0x151d: 0x07ff, + 0x151e: 0x0807, 0x151f: 0x05bf, 0x1520: 0x081f, 0x1521: 0x0823, 0x1522: 0x082b, 0x1523: 0x082f, + 0x1524: 0x05c3, 0x1525: 0x0847, 0x1526: 0x084b, 0x1527: 0x0857, 0x1528: 0x0863, 0x1529: 0x0867, + 0x152a: 0x086b, 0x152b: 0x0873, 0x152c: 0x0893, 0x152d: 0x0897, 0x152e: 0x089f, 0x152f: 0x08af, + 0x1530: 0x08b7, 0x1531: 0x08bb, 0x1532: 0x08bb, 0x1533: 0x08bb, 0x1534: 0x166a, 0x1535: 0x0e93, + 0x1536: 0x08cf, 0x1537: 0x08d7, 0x1538: 0x166f, 0x1539: 0x08e3, 0x153a: 0x08eb, 0x153b: 0x08f3, + 0x153c: 0x091b, 0x153d: 0x0907, 0x153e: 0x0913, 0x153f: 0x0917, + // Block 0x55, offset 0x1540 + 0x1540: 0x091f, 0x1541: 0x0927, 0x1542: 0x092b, 0x1543: 0x0933, 0x1544: 0x093b, 0x1545: 0x093f, + 0x1546: 0x093f, 0x1547: 0x0947, 0x1548: 0x094f, 0x1549: 0x0953, 0x154a: 0x095f, 0x154b: 0x0983, + 0x154c: 0x0967, 0x154d: 0x0987, 0x154e: 0x096b, 0x154f: 0x0973, 0x1550: 0x080b, 0x1551: 0x09cf, + 0x1552: 0x0997, 0x1553: 0x099b, 0x1554: 0x099f, 0x1555: 0x0993, 0x1556: 0x09a7, 0x1557: 0x09a3, + 0x1558: 0x09bb, 0x1559: 0x1674, 0x155a: 0x09d7, 0x155b: 0x09db, 0x155c: 0x09e3, 0x155d: 0x09ef, + 0x155e: 0x09f7, 0x155f: 0x0a13, 0x1560: 0x1679, 0x1561: 0x167e, 0x1562: 0x0a1f, 0x1563: 0x0a23, + 0x1564: 0x0a27, 0x1565: 0x0a1b, 0x1566: 0x0a2f, 0x1567: 0x05c7, 0x1568: 0x05cb, 0x1569: 0x0a37, + 0x156a: 0x0a3f, 0x156b: 0x0a3f, 0x156c: 0x1683, 0x156d: 0x0a5b, 0x156e: 0x0a5f, 0x156f: 0x0a63, + 0x1570: 0x0a6b, 0x1571: 0x1688, 0x1572: 0x0a73, 0x1573: 0x0a77, 0x1574: 0x0b4f, 0x1575: 0x0a7f, + 0x1576: 0x05cf, 0x1577: 0x0a8b, 0x1578: 0x0a9b, 0x1579: 0x0aa7, 0x157a: 0x0aa3, 0x157b: 0x1692, + 0x157c: 0x0aaf, 0x157d: 0x1697, 0x157e: 0x0abb, 0x157f: 0x0ab7, + // Block 0x56, offset 0x1580 + 0x1580: 0x0abf, 0x1581: 0x0acf, 0x1582: 0x0ad3, 0x1583: 0x05d3, 0x1584: 0x0ae3, 0x1585: 0x0aeb, + 0x1586: 0x0aef, 0x1587: 0x0af3, 0x1588: 0x05d7, 0x1589: 0x169c, 0x158a: 0x05db, 0x158b: 0x0b0f, + 0x158c: 0x0b13, 0x158d: 0x0b17, 0x158e: 0x0b1f, 0x158f: 0x1863, 0x1590: 0x0b37, 0x1591: 0x16a6, + 0x1592: 0x16a6, 0x1593: 0x11d7, 0x1594: 0x0b47, 0x1595: 0x0b47, 0x1596: 0x05df, 0x1597: 0x16c9, + 0x1598: 0x179b, 0x1599: 0x0b57, 0x159a: 0x0b5f, 0x159b: 0x05e3, 0x159c: 0x0b73, 0x159d: 0x0b83, + 0x159e: 0x0b87, 0x159f: 0x0b8f, 0x15a0: 0x0b9f, 0x15a1: 0x05eb, 0x15a2: 0x05e7, 0x15a3: 0x0ba3, + 0x15a4: 0x16ab, 0x15a5: 0x0ba7, 0x15a6: 0x0bbb, 0x15a7: 0x0bbf, 0x15a8: 0x0bc3, 0x15a9: 0x0bbf, + 0x15aa: 0x0bcf, 0x15ab: 0x0bd3, 0x15ac: 0x0be3, 0x15ad: 0x0bdb, 0x15ae: 0x0bdf, 0x15af: 0x0be7, + 0x15b0: 0x0beb, 0x15b1: 0x0bef, 0x15b2: 0x0bfb, 0x15b3: 0x0bff, 0x15b4: 0x0c17, 0x15b5: 0x0c1f, + 0x15b6: 0x0c2f, 0x15b7: 0x0c43, 0x15b8: 0x16ba, 0x15b9: 0x0c3f, 0x15ba: 0x0c33, 0x15bb: 0x0c4b, + 0x15bc: 0x0c53, 0x15bd: 0x0c67, 0x15be: 0x16bf, 0x15bf: 0x0c6f, + // Block 0x57, offset 0x15c0 + 0x15c0: 0x0c63, 0x15c1: 0x0c5b, 0x15c2: 0x05ef, 0x15c3: 0x0c77, 0x15c4: 0x0c7f, 0x15c5: 0x0c87, + 0x15c6: 0x0c7b, 0x15c7: 0x05f3, 0x15c8: 0x0c97, 0x15c9: 0x0c9f, 0x15ca: 0x16c4, 0x15cb: 0x0ccb, + 0x15cc: 0x0cff, 0x15cd: 0x0cdb, 0x15ce: 0x05ff, 0x15cf: 0x0ce7, 0x15d0: 0x05fb, 0x15d1: 0x05f7, + 0x15d2: 0x07c3, 0x15d3: 0x07c7, 0x15d4: 0x0d03, 0x15d5: 0x0ceb, 0x15d6: 0x11ab, 0x15d7: 0x0663, + 0x15d8: 0x0d0f, 0x15d9: 0x0d13, 0x15da: 0x0d17, 0x15db: 0x0d2b, 0x15dc: 0x0d23, 0x15dd: 0x16dd, + 0x15de: 0x0603, 0x15df: 0x0d3f, 0x15e0: 0x0d33, 0x15e1: 0x0d4f, 0x15e2: 0x0d57, 0x15e3: 0x16e7, + 0x15e4: 0x0d5b, 0x15e5: 0x0d47, 0x15e6: 0x0d63, 0x15e7: 0x0607, 0x15e8: 0x0d67, 0x15e9: 0x0d6b, + 0x15ea: 0x0d6f, 0x15eb: 0x0d7b, 0x15ec: 0x16ec, 0x15ed: 0x0d83, 0x15ee: 0x060b, 0x15ef: 0x0d8f, + 0x15f0: 0x16f1, 0x15f1: 0x0d93, 0x15f2: 0x060f, 0x15f3: 0x0d9f, 0x15f4: 0x0dab, 0x15f5: 0x0db7, + 0x15f6: 0x0dbb, 0x15f7: 0x16f6, 0x15f8: 0x168d, 0x15f9: 0x16fb, 0x15fa: 0x0ddb, 0x15fb: 0x1700, + 0x15fc: 0x0de7, 0x15fd: 0x0def, 0x15fe: 0x0ddf, 0x15ff: 0x0dfb, + // Block 0x58, offset 0x1600 + 0x1600: 0x0e0b, 0x1601: 0x0e1b, 0x1602: 0x0e0f, 0x1603: 0x0e13, 0x1604: 0x0e1f, 0x1605: 0x0e23, + 0x1606: 0x1705, 0x1607: 0x0e07, 0x1608: 0x0e3b, 0x1609: 0x0e3f, 0x160a: 0x0613, 0x160b: 0x0e53, + 0x160c: 0x0e4f, 0x160d: 0x170a, 0x160e: 0x0e33, 0x160f: 0x0e6f, 0x1610: 0x170f, 0x1611: 0x1714, + 0x1612: 0x0e73, 0x1613: 0x0e87, 0x1614: 0x0e83, 0x1615: 0x0e7f, 0x1616: 0x0617, 0x1617: 0x0e8b, + 0x1618: 0x0e9b, 0x1619: 0x0e97, 0x161a: 0x0ea3, 0x161b: 0x1651, 0x161c: 0x0eb3, 0x161d: 0x1719, + 0x161e: 0x0ebf, 0x161f: 0x1723, 0x1620: 0x0ed3, 0x1621: 0x0edf, 0x1622: 0x0ef3, 0x1623: 0x1728, + 0x1624: 0x0f07, 0x1625: 0x0f0b, 0x1626: 0x172d, 0x1627: 0x1732, 0x1628: 0x0f27, 0x1629: 0x0f37, + 0x162a: 0x061b, 0x162b: 0x0f3b, 0x162c: 0x061f, 0x162d: 0x061f, 0x162e: 0x0f53, 0x162f: 0x0f57, + 0x1630: 0x0f5f, 0x1631: 0x0f63, 0x1632: 0x0f6f, 0x1633: 0x0623, 0x1634: 0x0f87, 0x1635: 0x1737, + 0x1636: 0x0fa3, 0x1637: 0x173c, 0x1638: 0x0faf, 0x1639: 0x16a1, 0x163a: 0x0fbf, 0x163b: 0x1741, + 0x163c: 0x1746, 0x163d: 0x174b, 0x163e: 0x0627, 0x163f: 0x062b, + // Block 0x59, offset 0x1640 + 0x1640: 0x0ff7, 0x1641: 0x1755, 0x1642: 0x1750, 0x1643: 0x175a, 0x1644: 0x175f, 0x1645: 0x0fff, + 0x1646: 0x1003, 0x1647: 0x1003, 0x1648: 0x100b, 0x1649: 0x0633, 0x164a: 0x100f, 0x164b: 0x0637, + 0x164c: 0x063b, 0x164d: 0x1769, 0x164e: 0x1023, 0x164f: 0x102b, 0x1650: 0x1037, 0x1651: 0x063f, + 0x1652: 0x176e, 0x1653: 0x105b, 0x1654: 0x1773, 0x1655: 0x1778, 0x1656: 0x107b, 0x1657: 0x1093, + 0x1658: 0x0643, 0x1659: 0x109b, 0x165a: 0x109f, 0x165b: 0x10a3, 0x165c: 0x177d, 0x165d: 0x1782, + 0x165e: 0x1782, 0x165f: 0x10bb, 0x1660: 0x0647, 0x1661: 0x1787, 0x1662: 0x10cf, 0x1663: 0x10d3, + 0x1664: 0x064b, 0x1665: 0x178c, 0x1666: 0x10ef, 0x1667: 0x064f, 0x1668: 0x10ff, 0x1669: 0x10f7, + 0x166a: 0x1107, 0x166b: 0x1796, 0x166c: 0x111f, 0x166d: 0x0653, 0x166e: 0x112b, 0x166f: 0x1133, + 0x1670: 0x1143, 0x1671: 0x0657, 0x1672: 0x17a0, 0x1673: 0x17a5, 0x1674: 0x065b, 0x1675: 0x17aa, + 0x1676: 0x115b, 0x1677: 0x17af, 0x1678: 0x1167, 0x1679: 0x1173, 0x167a: 0x117b, 0x167b: 0x17b4, + 0x167c: 0x17b9, 0x167d: 0x118f, 0x167e: 0x17be, 0x167f: 0x1197, + // Block 0x5a, offset 0x1680 + 0x1680: 0x16ce, 0x1681: 0x065f, 0x1682: 0x11af, 0x1683: 0x11b3, 0x1684: 0x0667, 0x1685: 0x11b7, + 0x1686: 0x0a33, 0x1687: 0x17c3, 0x1688: 0x17c8, 0x1689: 0x16d3, 0x168a: 0x16d8, 0x168b: 0x11d7, + 0x168c: 0x11db, 0x168d: 0x13f3, 0x168e: 0x066b, 0x168f: 0x1207, 0x1690: 0x1203, 0x1691: 0x120b, + 0x1692: 0x083f, 0x1693: 0x120f, 0x1694: 0x1213, 0x1695: 0x1217, 0x1696: 0x121f, 0x1697: 0x17cd, + 0x1698: 0x121b, 0x1699: 0x1223, 0x169a: 0x1237, 0x169b: 0x123b, 0x169c: 0x1227, 0x169d: 0x123f, + 0x169e: 0x1253, 0x169f: 0x1267, 0x16a0: 0x1233, 0x16a1: 0x1247, 0x16a2: 0x124b, 0x16a3: 0x124f, + 0x16a4: 0x17d2, 0x16a5: 0x17dc, 0x16a6: 0x17d7, 0x16a7: 0x066f, 0x16a8: 0x126f, 0x16a9: 0x1273, + 0x16aa: 0x127b, 0x16ab: 0x17f0, 0x16ac: 0x127f, 0x16ad: 0x17e1, 0x16ae: 0x0673, 0x16af: 0x0677, + 0x16b0: 0x17e6, 0x16b1: 0x17eb, 0x16b2: 0x067b, 0x16b3: 0x129f, 0x16b4: 0x12a3, 0x16b5: 0x12a7, + 0x16b6: 0x12ab, 0x16b7: 0x12b7, 0x16b8: 0x12b3, 0x16b9: 0x12bf, 0x16ba: 0x12bb, 0x16bb: 0x12cb, + 0x16bc: 0x12c3, 0x16bd: 0x12c7, 0x16be: 0x12cf, 0x16bf: 0x067f, + // Block 0x5b, offset 0x16c0 + 0x16c0: 0x12d7, 0x16c1: 0x12db, 0x16c2: 0x0683, 0x16c3: 0x12eb, 0x16c4: 0x12ef, 0x16c5: 0x17f5, + 0x16c6: 0x12fb, 0x16c7: 0x12ff, 0x16c8: 0x0687, 0x16c9: 0x130b, 0x16ca: 0x05bb, 0x16cb: 0x17fa, + 0x16cc: 0x17ff, 0x16cd: 0x068b, 0x16ce: 0x068f, 0x16cf: 0x1337, 0x16d0: 0x134f, 0x16d1: 0x136b, + 0x16d2: 0x137b, 0x16d3: 0x1804, 0x16d4: 0x138f, 0x16d5: 0x1393, 0x16d6: 0x13ab, 0x16d7: 0x13b7, + 0x16d8: 0x180e, 0x16d9: 0x1660, 0x16da: 0x13c3, 0x16db: 0x13bf, 0x16dc: 0x13cb, 0x16dd: 0x1665, + 0x16de: 0x13d7, 0x16df: 0x13e3, 0x16e0: 0x1813, 0x16e1: 0x1818, 0x16e2: 0x1423, 0x16e3: 0x142f, + 0x16e4: 0x1437, 0x16e5: 0x181d, 0x16e6: 0x143b, 0x16e7: 0x1467, 0x16e8: 0x1473, 0x16e9: 0x1477, + 0x16ea: 0x146f, 0x16eb: 0x1483, 0x16ec: 0x1487, 0x16ed: 0x1822, 0x16ee: 0x1493, 0x16ef: 0x0693, + 0x16f0: 0x149b, 0x16f1: 0x1827, 0x16f2: 0x0697, 0x16f3: 0x14d3, 0x16f4: 0x0ac3, 0x16f5: 0x14eb, + 0x16f6: 0x182c, 0x16f7: 0x1836, 0x16f8: 0x069b, 0x16f9: 0x069f, 0x16fa: 0x1513, 0x16fb: 0x183b, + 0x16fc: 0x06a3, 0x16fd: 0x1840, 0x16fe: 0x152b, 0x16ff: 0x152b, + // Block 0x5c, offset 0x1700 + 0x1700: 0x1533, 0x1701: 0x1845, 0x1702: 0x154b, 0x1703: 0x06a7, 0x1704: 0x155b, 0x1705: 0x1567, + 0x1706: 0x156f, 0x1707: 0x1577, 0x1708: 0x06ab, 0x1709: 0x184a, 0x170a: 0x158b, 0x170b: 0x15a7, + 0x170c: 0x15b3, 0x170d: 0x06af, 0x170e: 0x06b3, 0x170f: 0x15b7, 0x1710: 0x184f, 0x1711: 0x06b7, + 0x1712: 0x1854, 0x1713: 0x1859, 0x1714: 0x185e, 0x1715: 0x15db, 0x1716: 0x06bb, 0x1717: 0x15ef, + 0x1718: 0x15f7, 0x1719: 0x15fb, 0x171a: 0x1603, 0x171b: 0x160b, 0x171c: 0x1613, 0x171d: 0x1868, +} + +// nfkcIndex: 22 blocks, 1408 entries, 1408 bytes +// Block 0 is the zero block. +var nfkcIndex = [1408]uint8{ + // Block 0x0, offset 0x0 + // Block 0x1, offset 0x40 + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0xc2: 0x5b, 0xc3: 0x01, 0xc4: 0x02, 0xc5: 0x03, 0xc6: 0x5c, 0xc7: 0x04, + 0xc8: 0x05, 0xca: 0x5d, 0xcb: 0x5e, 0xcc: 0x06, 0xcd: 0x07, 0xce: 0x08, 0xcf: 0x09, + 0xd0: 0x0a, 0xd1: 0x5f, 0xd2: 0x60, 0xd3: 0x0b, 0xd6: 0x0c, 0xd7: 0x61, + 0xd8: 0x62, 0xd9: 0x0d, 0xdb: 0x63, 0xdc: 0x64, 0xdd: 0x65, 0xdf: 0x66, + 0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05, + 0xea: 0x06, 0xeb: 0x07, 0xec: 0x08, 0xed: 0x09, 0xef: 0x0a, + 0xf0: 0x13, + // Block 0x4, offset 0x100 + 0x120: 0x67, 0x121: 0x68, 0x123: 0x69, 0x124: 0x6a, 0x125: 0x6b, 0x126: 0x6c, 0x127: 0x6d, + 0x128: 0x6e, 0x129: 0x6f, 0x12a: 0x70, 0x12b: 0x71, 0x12c: 0x6c, 0x12d: 0x72, 0x12e: 0x73, 0x12f: 0x74, + 0x131: 0x75, 0x132: 0x76, 0x133: 0x77, 0x134: 0x78, 0x135: 0x79, 0x137: 0x7a, + 0x138: 0x7b, 0x139: 0x7c, 0x13a: 0x7d, 0x13b: 0x7e, 0x13c: 0x7f, 0x13d: 0x80, 0x13e: 0x81, 0x13f: 0x82, + // Block 0x5, offset 0x140 + 0x140: 0x83, 0x142: 0x84, 0x143: 0x85, 0x144: 0x86, 0x145: 0x87, 0x146: 0x88, 0x147: 0x89, + 0x14d: 0x8a, + 0x15c: 0x8b, 0x15f: 0x8c, + 0x162: 0x8d, 0x164: 0x8e, + 0x168: 0x8f, 0x169: 0x90, 0x16a: 0x91, 0x16c: 0x0e, 0x16d: 0x92, 0x16e: 0x93, 0x16f: 0x94, + 0x170: 0x95, 0x173: 0x96, 0x174: 0x97, 0x175: 0x0f, 0x176: 0x10, 0x177: 0x11, + 0x178: 0x12, 0x179: 0x13, 0x17a: 0x14, 0x17b: 0x15, 0x17c: 0x16, 0x17d: 0x17, 0x17e: 0x18, 0x17f: 0x19, + // Block 0x6, offset 0x180 + 0x180: 0x98, 0x181: 0x99, 0x182: 0x9a, 0x183: 0x9b, 0x184: 0x1a, 0x185: 0x1b, 0x186: 0x9c, 0x187: 0x9d, + 0x188: 0x9e, 0x189: 0x1c, 0x18a: 0x1d, 0x18b: 0x9f, 0x18c: 0xa0, + 0x191: 0x1e, 0x192: 0x1f, 0x193: 0xa1, + 0x1a8: 0xa2, 0x1a9: 0xa3, 0x1ab: 0xa4, + 0x1b1: 0xa5, 0x1b3: 0xa6, 0x1b5: 0xa7, 0x1b7: 0xa8, + 0x1ba: 0xa9, 0x1bb: 0xaa, 0x1bc: 0x20, 0x1bd: 0x21, 0x1be: 0x22, 0x1bf: 0xab, + // Block 0x7, offset 0x1c0 + 0x1c0: 0xac, 0x1c1: 0x23, 0x1c2: 0x24, 0x1c3: 0x25, 0x1c4: 0xad, 0x1c5: 0x26, 0x1c6: 0x27, + 0x1c8: 0x28, 0x1c9: 0x29, 0x1ca: 0x2a, 0x1cb: 0x2b, 0x1cc: 0x2c, 0x1cd: 0x2d, 0x1ce: 0x2e, 0x1cf: 0x2f, + // Block 0x8, offset 0x200 + 0x219: 0xae, 0x21a: 0xaf, 0x21b: 0xb0, 0x21d: 0xb1, 0x21f: 0xb2, + 0x220: 0xb3, 0x223: 0xb4, 0x224: 0xb5, 0x225: 0xb6, 0x226: 0xb7, 0x227: 0xb8, + 0x22a: 0xb9, 0x22b: 0xba, 0x22d: 0xbb, 0x22f: 0xbc, + 0x230: 0xbd, 0x231: 0xbe, 0x232: 0xbf, 0x233: 0xc0, 0x234: 0xc1, 0x235: 0xc2, 0x236: 0xc3, 0x237: 0xbd, + 0x238: 0xbe, 0x239: 0xbf, 0x23a: 0xc0, 0x23b: 0xc1, 0x23c: 0xc2, 0x23d: 0xc3, 0x23e: 0xbd, 0x23f: 0xbe, + // Block 0x9, offset 0x240 + 0x240: 0xbf, 0x241: 0xc0, 0x242: 0xc1, 0x243: 0xc2, 0x244: 0xc3, 0x245: 0xbd, 0x246: 0xbe, 0x247: 0xbf, + 0x248: 0xc0, 0x249: 0xc1, 0x24a: 0xc2, 0x24b: 0xc3, 0x24c: 0xbd, 0x24d: 0xbe, 0x24e: 0xbf, 0x24f: 0xc0, + 0x250: 0xc1, 0x251: 0xc2, 0x252: 0xc3, 0x253: 0xbd, 0x254: 0xbe, 0x255: 0xbf, 0x256: 0xc0, 0x257: 0xc1, + 0x258: 0xc2, 0x259: 0xc3, 0x25a: 0xbd, 0x25b: 0xbe, 0x25c: 0xbf, 0x25d: 0xc0, 0x25e: 0xc1, 0x25f: 0xc2, + 0x260: 0xc3, 0x261: 0xbd, 0x262: 0xbe, 0x263: 0xbf, 0x264: 0xc0, 0x265: 0xc1, 0x266: 0xc2, 0x267: 0xc3, + 0x268: 0xbd, 0x269: 0xbe, 0x26a: 0xbf, 0x26b: 0xc0, 0x26c: 0xc1, 0x26d: 0xc2, 0x26e: 0xc3, 0x26f: 0xbd, + 0x270: 0xbe, 0x271: 0xbf, 0x272: 0xc0, 0x273: 0xc1, 0x274: 0xc2, 0x275: 0xc3, 0x276: 0xbd, 0x277: 0xbe, + 0x278: 0xbf, 0x279: 0xc0, 0x27a: 0xc1, 0x27b: 0xc2, 0x27c: 0xc3, 0x27d: 0xbd, 0x27e: 0xbe, 0x27f: 0xbf, + // Block 0xa, offset 0x280 + 0x280: 0xc0, 0x281: 0xc1, 0x282: 0xc2, 0x283: 0xc3, 0x284: 0xbd, 0x285: 0xbe, 0x286: 0xbf, 0x287: 0xc0, + 0x288: 0xc1, 0x289: 0xc2, 0x28a: 0xc3, 0x28b: 0xbd, 0x28c: 0xbe, 0x28d: 0xbf, 0x28e: 0xc0, 0x28f: 0xc1, + 0x290: 0xc2, 0x291: 0xc3, 0x292: 0xbd, 0x293: 0xbe, 0x294: 0xbf, 0x295: 0xc0, 0x296: 0xc1, 0x297: 0xc2, + 0x298: 0xc3, 0x299: 0xbd, 0x29a: 0xbe, 0x29b: 0xbf, 0x29c: 0xc0, 0x29d: 0xc1, 0x29e: 0xc2, 0x29f: 0xc3, + 0x2a0: 0xbd, 0x2a1: 0xbe, 0x2a2: 0xbf, 0x2a3: 0xc0, 0x2a4: 0xc1, 0x2a5: 0xc2, 0x2a6: 0xc3, 0x2a7: 0xbd, + 0x2a8: 0xbe, 0x2a9: 0xbf, 0x2aa: 0xc0, 0x2ab: 0xc1, 0x2ac: 0xc2, 0x2ad: 0xc3, 0x2ae: 0xbd, 0x2af: 0xbe, + 0x2b0: 0xbf, 0x2b1: 0xc0, 0x2b2: 0xc1, 0x2b3: 0xc2, 0x2b4: 0xc3, 0x2b5: 0xbd, 0x2b6: 0xbe, 0x2b7: 0xbf, + 0x2b8: 0xc0, 0x2b9: 0xc1, 0x2ba: 0xc2, 0x2bb: 0xc3, 0x2bc: 0xbd, 0x2bd: 0xbe, 0x2be: 0xbf, 0x2bf: 0xc0, + // Block 0xb, offset 0x2c0 + 0x2c0: 0xc1, 0x2c1: 0xc2, 0x2c2: 0xc3, 0x2c3: 0xbd, 0x2c4: 0xbe, 0x2c5: 0xbf, 0x2c6: 0xc0, 0x2c7: 0xc1, + 0x2c8: 0xc2, 0x2c9: 0xc3, 0x2ca: 0xbd, 0x2cb: 0xbe, 0x2cc: 0xbf, 0x2cd: 0xc0, 0x2ce: 0xc1, 0x2cf: 0xc2, + 0x2d0: 0xc3, 0x2d1: 0xbd, 0x2d2: 0xbe, 0x2d3: 0xbf, 0x2d4: 0xc0, 0x2d5: 0xc1, 0x2d6: 0xc2, 0x2d7: 0xc3, + 0x2d8: 0xbd, 0x2d9: 0xbe, 0x2da: 0xbf, 0x2db: 0xc0, 0x2dc: 0xc1, 0x2dd: 0xc2, 0x2de: 0xc4, + // Block 0xc, offset 0x300 + 0x324: 0x30, 0x325: 0x31, 0x326: 0x32, 0x327: 0x33, + 0x328: 0x34, 0x329: 0x35, 0x32a: 0x36, 0x32b: 0x37, 0x32c: 0x38, 0x32d: 0x39, 0x32e: 0x3a, 0x32f: 0x3b, + 0x330: 0x3c, 0x331: 0x3d, 0x332: 0x3e, 0x333: 0x3f, 0x334: 0x40, 0x335: 0x41, 0x336: 0x42, 0x337: 0x43, + 0x338: 0x44, 0x339: 0x45, 0x33a: 0x46, 0x33b: 0x47, 0x33c: 0xc5, 0x33d: 0x48, 0x33e: 0x49, 0x33f: 0x4a, + // Block 0xd, offset 0x340 + 0x347: 0xc6, + 0x34b: 0xc7, 0x34d: 0xc8, + 0x368: 0xc9, 0x36b: 0xca, + // Block 0xe, offset 0x380 + 0x381: 0xcb, 0x382: 0xcc, 0x384: 0xcd, 0x385: 0xb7, 0x387: 0xce, + 0x388: 0xcf, 0x38b: 0xd0, 0x38c: 0x6c, 0x38d: 0xd1, + 0x391: 0xd2, 0x392: 0xd3, 0x393: 0xd4, 0x396: 0xd5, 0x397: 0xd6, + 0x398: 0xd7, 0x39a: 0xd8, 0x39c: 0xd9, + 0x3a8: 0xda, 0x3a9: 0xdb, 0x3aa: 0xdc, + 0x3b0: 0xd7, 0x3b5: 0xdd, + // Block 0xf, offset 0x3c0 + 0x3eb: 0xde, 0x3ec: 0xdf, + // Block 0x10, offset 0x400 + 0x432: 0xe0, + // Block 0x11, offset 0x440 + 0x445: 0xe1, 0x446: 0xe2, 0x447: 0xe3, + 0x449: 0xe4, + 0x450: 0xe5, 0x451: 0xe6, 0x452: 0xe7, 0x453: 0xe8, 0x454: 0xe9, 0x455: 0xea, 0x456: 0xeb, 0x457: 0xec, + 0x458: 0xed, 0x459: 0xee, 0x45a: 0x4b, 0x45b: 0xef, 0x45c: 0xf0, 0x45d: 0xf1, 0x45e: 0xf2, 0x45f: 0x4c, + // Block 0x12, offset 0x480 + 0x480: 0xf3, + 0x4a3: 0xf4, 0x4a5: 0xf5, + 0x4b8: 0x4d, 0x4b9: 0x4e, 0x4ba: 0x4f, + // Block 0x13, offset 0x4c0 + 0x4c4: 0x50, 0x4c5: 0xf6, 0x4c6: 0xf7, + 0x4c8: 0x51, 0x4c9: 0xf8, + // Block 0x14, offset 0x500 + 0x520: 0x52, 0x521: 0x53, 0x522: 0x54, 0x523: 0x55, 0x524: 0x56, 0x525: 0x57, 0x526: 0x58, 0x527: 0x59, + 0x528: 0x5a, + // Block 0x15, offset 0x540 + 0x550: 0x0b, 0x551: 0x0c, 0x556: 0x0d, + 0x55b: 0x0e, 0x55d: 0x0f, 0x55e: 0x10, 0x55f: 0x11, + 0x56f: 0x12, +} + +// nfkcSparseOffset: 158 entries, 316 bytes +var nfkcSparseOffset = []uint16{0x0, 0xe, 0x12, 0x1b, 0x25, 0x35, 0x37, 0x3c, 0x47, 0x56, 0x63, 0x6b, 0x6f, 0x74, 0x76, 0x87, 0x8f, 0x96, 0x99, 0xa0, 0xa4, 0xa8, 0xaa, 0xac, 0xb5, 0xb9, 0xc0, 0xc5, 0xc8, 0xd2, 0xd5, 0xdc, 0xe4, 0xe8, 0xea, 0xed, 0xf1, 0xf7, 0x108, 0x114, 0x116, 0x11c, 0x11e, 0x120, 0x122, 0x124, 0x126, 0x128, 0x12a, 0x12d, 0x130, 0x132, 0x135, 0x138, 0x13c, 0x141, 0x14a, 0x14c, 0x14f, 0x151, 0x15c, 0x167, 0x175, 0x183, 0x193, 0x1a1, 0x1a8, 0x1ae, 0x1bd, 0x1c1, 0x1c3, 0x1c7, 0x1c9, 0x1cc, 0x1ce, 0x1d1, 0x1d3, 0x1d6, 0x1d8, 0x1da, 0x1dc, 0x1e8, 0x1f2, 0x1fc, 0x1ff, 0x203, 0x205, 0x207, 0x209, 0x20b, 0x20e, 0x210, 0x212, 0x214, 0x216, 0x21c, 0x21f, 0x223, 0x225, 0x22c, 0x232, 0x238, 0x240, 0x246, 0x24c, 0x252, 0x256, 0x258, 0x25a, 0x25c, 0x25e, 0x264, 0x267, 0x26a, 0x272, 0x279, 0x27c, 0x27f, 0x281, 0x289, 0x28c, 0x293, 0x296, 0x29c, 0x29e, 0x2a0, 0x2a3, 0x2a5, 0x2a7, 0x2a9, 0x2ab, 0x2ae, 0x2b0, 0x2b2, 0x2b4, 0x2c1, 0x2cb, 0x2cd, 0x2cf, 0x2d3, 0x2d8, 0x2e4, 0x2e9, 0x2f2, 0x2f8, 0x2fd, 0x301, 0x306, 0x30a, 0x31a, 0x328, 0x336, 0x344, 0x34a, 0x34c, 0x34f, 0x359, 0x35b} + +// nfkcSparseValues: 869 entries, 3476 bytes +var nfkcSparseValues = [869]valueRange{ + // Block 0x0, offset 0x0 + {value: 0x0002, lo: 0x0d}, + {value: 0x0001, lo: 0xa0, hi: 0xa0}, + {value: 0x4278, lo: 0xa8, hi: 0xa8}, + {value: 0x0083, lo: 0xaa, hi: 0xaa}, + {value: 0x4264, lo: 0xaf, hi: 0xaf}, + {value: 0x0025, lo: 0xb2, hi: 0xb3}, + {value: 0x425a, lo: 0xb4, hi: 0xb4}, + {value: 0x01dc, lo: 0xb5, hi: 0xb5}, + {value: 0x4291, lo: 0xb8, hi: 0xb8}, + {value: 0x0023, lo: 0xb9, hi: 0xb9}, + {value: 0x009f, lo: 0xba, hi: 0xba}, + {value: 0x221c, lo: 0xbc, hi: 0xbc}, + {value: 0x2210, lo: 0xbd, hi: 0xbd}, + {value: 0x22b2, lo: 0xbe, hi: 0xbe}, + // Block 0x1, offset 0xe + {value: 0x0091, lo: 0x03}, + {value: 0x46e2, lo: 0xa0, hi: 0xa1}, + {value: 0x4714, lo: 0xaf, hi: 0xb0}, + {value: 0xa000, lo: 0xb7, hi: 0xb7}, + // Block 0x2, offset 0x12 + {value: 0x0003, lo: 0x08}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0x0091, lo: 0xb0, hi: 0xb0}, + {value: 0x0119, lo: 0xb1, hi: 0xb1}, + {value: 0x0095, lo: 0xb2, hi: 0xb2}, + {value: 0x00a5, lo: 0xb3, hi: 0xb3}, + {value: 0x0143, lo: 0xb4, hi: 0xb6}, + {value: 0x00af, lo: 0xb7, hi: 0xb7}, + {value: 0x00b3, lo: 0xb8, hi: 0xb8}, + // Block 0x3, offset 0x1b + {value: 0x000a, lo: 0x09}, + {value: 0x426e, lo: 0x98, hi: 0x98}, + {value: 0x4273, lo: 0x99, hi: 0x9a}, + {value: 0x4296, lo: 0x9b, hi: 0x9b}, + {value: 0x425f, lo: 0x9c, hi: 0x9c}, + {value: 0x4282, lo: 0x9d, hi: 0x9d}, + {value: 0x0113, lo: 0xa0, hi: 0xa0}, + {value: 0x0099, lo: 0xa1, hi: 0xa1}, + {value: 0x00a7, lo: 0xa2, hi: 0xa3}, + {value: 0x0167, lo: 0xa4, hi: 0xa4}, + // Block 0x4, offset 0x25 + {value: 0x0000, lo: 0x0f}, + {value: 0xa000, lo: 0x83, hi: 0x83}, + {value: 0xa000, lo: 0x87, hi: 0x87}, + {value: 0xa000, lo: 0x8b, hi: 0x8b}, + {value: 0xa000, lo: 0x8d, hi: 0x8d}, + {value: 0x37a5, lo: 0x90, hi: 0x90}, + {value: 0x37b1, lo: 0x91, hi: 0x91}, + {value: 0x379f, lo: 0x93, hi: 0x93}, + {value: 0xa000, lo: 0x96, hi: 0x96}, + {value: 0x3817, lo: 0x97, hi: 0x97}, + {value: 0x37e1, lo: 0x9c, hi: 0x9c}, + {value: 0x37c9, lo: 0x9d, hi: 0x9d}, + {value: 0x37f3, lo: 0x9e, hi: 0x9e}, + {value: 0xa000, lo: 0xb4, hi: 0xb5}, + {value: 0x381d, lo: 0xb6, hi: 0xb6}, + {value: 0x3823, lo: 0xb7, hi: 0xb7}, + // Block 0x5, offset 0x35 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0x83, hi: 0x87}, + // Block 0x6, offset 0x37 + {value: 0x0001, lo: 0x04}, + {value: 0x8113, lo: 0x81, hi: 0x82}, + {value: 0x8132, lo: 0x84, hi: 0x84}, + {value: 0x812d, lo: 0x85, hi: 0x85}, + {value: 0x810d, lo: 0x87, hi: 0x87}, + // Block 0x7, offset 0x3c + {value: 0x0000, lo: 0x0a}, + {value: 0x8132, lo: 0x90, hi: 0x97}, + {value: 0x8119, lo: 0x98, hi: 0x98}, + {value: 0x811a, lo: 0x99, hi: 0x99}, + {value: 0x811b, lo: 0x9a, hi: 0x9a}, + {value: 0x3841, lo: 0xa2, hi: 0xa2}, + {value: 0x3847, lo: 0xa3, hi: 0xa3}, + {value: 0x3853, lo: 0xa4, hi: 0xa4}, + {value: 0x384d, lo: 0xa5, hi: 0xa5}, + {value: 0x3859, lo: 0xa6, hi: 0xa6}, + {value: 0xa000, lo: 0xa7, hi: 0xa7}, + // Block 0x8, offset 0x47 + {value: 0x0000, lo: 0x0e}, + {value: 0x386b, lo: 0x80, hi: 0x80}, + {value: 0xa000, lo: 0x81, hi: 0x81}, + {value: 0x385f, lo: 0x82, hi: 0x82}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0x3865, lo: 0x93, hi: 0x93}, + {value: 0xa000, lo: 0x95, hi: 0x95}, + {value: 0x8132, lo: 0x96, hi: 0x9c}, + {value: 0x8132, lo: 0x9f, hi: 0xa2}, + {value: 0x812d, lo: 0xa3, hi: 0xa3}, + {value: 0x8132, lo: 0xa4, hi: 0xa4}, + {value: 0x8132, lo: 0xa7, hi: 0xa8}, + {value: 0x812d, lo: 0xaa, hi: 0xaa}, + {value: 0x8132, lo: 0xab, hi: 0xac}, + {value: 0x812d, lo: 0xad, hi: 0xad}, + // Block 0x9, offset 0x56 + {value: 0x0000, lo: 0x0c}, + {value: 0x811f, lo: 0x91, hi: 0x91}, + {value: 0x8132, lo: 0xb0, hi: 0xb0}, + {value: 0x812d, lo: 0xb1, hi: 0xb1}, + {value: 0x8132, lo: 0xb2, hi: 0xb3}, + {value: 0x812d, lo: 0xb4, hi: 0xb4}, + {value: 0x8132, lo: 0xb5, hi: 0xb6}, + {value: 0x812d, lo: 0xb7, hi: 0xb9}, + {value: 0x8132, lo: 0xba, hi: 0xba}, + {value: 0x812d, lo: 0xbb, hi: 0xbc}, + {value: 0x8132, lo: 0xbd, hi: 0xbd}, + {value: 0x812d, lo: 0xbe, hi: 0xbe}, + {value: 0x8132, lo: 0xbf, hi: 0xbf}, + // Block 0xa, offset 0x63 + {value: 0x0005, lo: 0x07}, + {value: 0x8132, lo: 0x80, hi: 0x80}, + {value: 0x8132, lo: 0x81, hi: 0x81}, + {value: 0x812d, lo: 0x82, hi: 0x83}, + {value: 0x812d, lo: 0x84, hi: 0x85}, + {value: 0x812d, lo: 0x86, hi: 0x87}, + {value: 0x812d, lo: 0x88, hi: 0x89}, + {value: 0x8132, lo: 0x8a, hi: 0x8a}, + // Block 0xb, offset 0x6b + {value: 0x0000, lo: 0x03}, + {value: 0x8132, lo: 0xab, hi: 0xb1}, + {value: 0x812d, lo: 0xb2, hi: 0xb2}, + {value: 0x8132, lo: 0xb3, hi: 0xb3}, + // Block 0xc, offset 0x6f + {value: 0x0000, lo: 0x04}, + {value: 0x8132, lo: 0x96, hi: 0x99}, + {value: 0x8132, lo: 0x9b, hi: 0xa3}, + {value: 0x8132, lo: 0xa5, hi: 0xa7}, + {value: 0x8132, lo: 0xa9, hi: 0xad}, + // Block 0xd, offset 0x74 + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0x99, hi: 0x9b}, + // Block 0xe, offset 0x76 + {value: 0x0000, lo: 0x10}, + {value: 0x8132, lo: 0x94, hi: 0xa1}, + {value: 0x812d, lo: 0xa3, hi: 0xa3}, + {value: 0x8132, lo: 0xa4, hi: 0xa5}, + {value: 0x812d, lo: 0xa6, hi: 0xa6}, + {value: 0x8132, lo: 0xa7, hi: 0xa8}, + {value: 0x812d, lo: 0xa9, hi: 0xa9}, + {value: 0x8132, lo: 0xaa, hi: 0xac}, + {value: 0x812d, lo: 0xad, hi: 0xaf}, + {value: 0x8116, lo: 0xb0, hi: 0xb0}, + {value: 0x8117, lo: 0xb1, hi: 0xb1}, + {value: 0x8118, lo: 0xb2, hi: 0xb2}, + {value: 0x8132, lo: 0xb3, hi: 0xb5}, + {value: 0x812d, lo: 0xb6, hi: 0xb6}, + {value: 0x8132, lo: 0xb7, hi: 0xb8}, + {value: 0x812d, lo: 0xb9, hi: 0xba}, + {value: 0x8132, lo: 0xbb, hi: 0xbf}, + // Block 0xf, offset 0x87 + {value: 0x0000, lo: 0x07}, + {value: 0xa000, lo: 0xa8, hi: 0xa8}, + {value: 0x3ed8, lo: 0xa9, hi: 0xa9}, + {value: 0xa000, lo: 0xb0, hi: 0xb0}, + {value: 0x3ee0, lo: 0xb1, hi: 0xb1}, + {value: 0xa000, lo: 0xb3, hi: 0xb3}, + {value: 0x3ee8, lo: 0xb4, hi: 0xb4}, + {value: 0x9902, lo: 0xbc, hi: 0xbc}, + // Block 0x10, offset 0x8f + {value: 0x0008, lo: 0x06}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x8132, lo: 0x91, hi: 0x91}, + {value: 0x812d, lo: 0x92, hi: 0x92}, + {value: 0x8132, lo: 0x93, hi: 0x93}, + {value: 0x8132, lo: 0x94, hi: 0x94}, + {value: 0x451c, lo: 0x98, hi: 0x9f}, + // Block 0x11, offset 0x96 + {value: 0x0000, lo: 0x02}, + {value: 0x8102, lo: 0xbc, hi: 0xbc}, + {value: 0x9900, lo: 0xbe, hi: 0xbe}, + // Block 0x12, offset 0x99 + {value: 0x0008, lo: 0x06}, + {value: 0xa000, lo: 0x87, hi: 0x87}, + {value: 0x2c9e, lo: 0x8b, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x97, hi: 0x97}, + {value: 0x455c, lo: 0x9c, hi: 0x9d}, + {value: 0x456c, lo: 0x9f, hi: 0x9f}, + // Block 0x13, offset 0xa0 + {value: 0x0000, lo: 0x03}, + {value: 0x4594, lo: 0xb3, hi: 0xb3}, + {value: 0x459c, lo: 0xb6, hi: 0xb6}, + {value: 0x8102, lo: 0xbc, hi: 0xbc}, + // Block 0x14, offset 0xa4 + {value: 0x0008, lo: 0x03}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x4574, lo: 0x99, hi: 0x9b}, + {value: 0x458c, lo: 0x9e, hi: 0x9e}, + // Block 0x15, offset 0xa8 + {value: 0x0000, lo: 0x01}, + {value: 0x8102, lo: 0xbc, hi: 0xbc}, + // Block 0x16, offset 0xaa + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + // Block 0x17, offset 0xac + {value: 0x0000, lo: 0x08}, + {value: 0xa000, lo: 0x87, hi: 0x87}, + {value: 0x2cb6, lo: 0x88, hi: 0x88}, + {value: 0x2cae, lo: 0x8b, hi: 0x8b}, + {value: 0x2cbe, lo: 0x8c, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x96, hi: 0x97}, + {value: 0x45a4, lo: 0x9c, hi: 0x9c}, + {value: 0x45ac, lo: 0x9d, hi: 0x9d}, + // Block 0x18, offset 0xb5 + {value: 0x0000, lo: 0x03}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0x2cc6, lo: 0x94, hi: 0x94}, + {value: 0x9900, lo: 0xbe, hi: 0xbe}, + // Block 0x19, offset 0xb9 + {value: 0x0000, lo: 0x06}, + {value: 0xa000, lo: 0x86, hi: 0x87}, + {value: 0x2cce, lo: 0x8a, hi: 0x8a}, + {value: 0x2cde, lo: 0x8b, hi: 0x8b}, + {value: 0x2cd6, lo: 0x8c, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x97, hi: 0x97}, + // Block 0x1a, offset 0xc0 + {value: 0x1801, lo: 0x04}, + {value: 0xa000, lo: 0x86, hi: 0x86}, + {value: 0x3ef0, lo: 0x88, hi: 0x88}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x8120, lo: 0x95, hi: 0x96}, + // Block 0x1b, offset 0xc5 + {value: 0x0000, lo: 0x02}, + {value: 0x8102, lo: 0xbc, hi: 0xbc}, + {value: 0xa000, lo: 0xbf, hi: 0xbf}, + // Block 0x1c, offset 0xc8 + {value: 0x0000, lo: 0x09}, + {value: 0x2ce6, lo: 0x80, hi: 0x80}, + {value: 0x9900, lo: 0x82, hi: 0x82}, + {value: 0xa000, lo: 0x86, hi: 0x86}, + {value: 0x2cee, lo: 0x87, hi: 0x87}, + {value: 0x2cf6, lo: 0x88, hi: 0x88}, + {value: 0x2f50, lo: 0x8a, hi: 0x8a}, + {value: 0x2dd8, lo: 0x8b, hi: 0x8b}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x95, hi: 0x96}, + // Block 0x1d, offset 0xd2 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0xbb, hi: 0xbc}, + {value: 0x9900, lo: 0xbe, hi: 0xbe}, + // Block 0x1e, offset 0xd5 + {value: 0x0000, lo: 0x06}, + {value: 0xa000, lo: 0x86, hi: 0x87}, + {value: 0x2cfe, lo: 0x8a, hi: 0x8a}, + {value: 0x2d0e, lo: 0x8b, hi: 0x8b}, + {value: 0x2d06, lo: 0x8c, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x97, hi: 0x97}, + // Block 0x1f, offset 0xdc + {value: 0x6bea, lo: 0x07}, + {value: 0x9904, lo: 0x8a, hi: 0x8a}, + {value: 0x9900, lo: 0x8f, hi: 0x8f}, + {value: 0xa000, lo: 0x99, hi: 0x99}, + {value: 0x3ef8, lo: 0x9a, hi: 0x9a}, + {value: 0x2f58, lo: 0x9c, hi: 0x9c}, + {value: 0x2de3, lo: 0x9d, hi: 0x9d}, + {value: 0x2d16, lo: 0x9e, hi: 0x9f}, + // Block 0x20, offset 0xe4 + {value: 0x0000, lo: 0x03}, + {value: 0x2621, lo: 0xb3, hi: 0xb3}, + {value: 0x8122, lo: 0xb8, hi: 0xb9}, + {value: 0x8104, lo: 0xba, hi: 0xba}, + // Block 0x21, offset 0xe8 + {value: 0x0000, lo: 0x01}, + {value: 0x8123, lo: 0x88, hi: 0x8b}, + // Block 0x22, offset 0xea + {value: 0x0000, lo: 0x02}, + {value: 0x2636, lo: 0xb3, hi: 0xb3}, + {value: 0x8124, lo: 0xb8, hi: 0xb9}, + // Block 0x23, offset 0xed + {value: 0x0000, lo: 0x03}, + {value: 0x8125, lo: 0x88, hi: 0x8b}, + {value: 0x2628, lo: 0x9c, hi: 0x9c}, + {value: 0x262f, lo: 0x9d, hi: 0x9d}, + // Block 0x24, offset 0xf1 + {value: 0x0000, lo: 0x05}, + {value: 0x030b, lo: 0x8c, hi: 0x8c}, + {value: 0x812d, lo: 0x98, hi: 0x99}, + {value: 0x812d, lo: 0xb5, hi: 0xb5}, + {value: 0x812d, lo: 0xb7, hi: 0xb7}, + {value: 0x812b, lo: 0xb9, hi: 0xb9}, + // Block 0x25, offset 0xf7 + {value: 0x0000, lo: 0x10}, + {value: 0x2644, lo: 0x83, hi: 0x83}, + {value: 0x264b, lo: 0x8d, hi: 0x8d}, + {value: 0x2652, lo: 0x92, hi: 0x92}, + {value: 0x2659, lo: 0x97, hi: 0x97}, + {value: 0x2660, lo: 0x9c, hi: 0x9c}, + {value: 0x263d, lo: 0xa9, hi: 0xa9}, + {value: 0x8126, lo: 0xb1, hi: 0xb1}, + {value: 0x8127, lo: 0xb2, hi: 0xb2}, + {value: 0x4a84, lo: 0xb3, hi: 0xb3}, + {value: 0x8128, lo: 0xb4, hi: 0xb4}, + {value: 0x4a8d, lo: 0xb5, hi: 0xb5}, + {value: 0x45b4, lo: 0xb6, hi: 0xb6}, + {value: 0x45f4, lo: 0xb7, hi: 0xb7}, + {value: 0x45bc, lo: 0xb8, hi: 0xb8}, + {value: 0x45ff, lo: 0xb9, hi: 0xb9}, + {value: 0x8127, lo: 0xba, hi: 0xbd}, + // Block 0x26, offset 0x108 + {value: 0x0000, lo: 0x0b}, + {value: 0x8127, lo: 0x80, hi: 0x80}, + {value: 0x4a96, lo: 0x81, hi: 0x81}, + {value: 0x8132, lo: 0x82, hi: 0x83}, + {value: 0x8104, lo: 0x84, hi: 0x84}, + {value: 0x8132, lo: 0x86, hi: 0x87}, + {value: 0x266e, lo: 0x93, hi: 0x93}, + {value: 0x2675, lo: 0x9d, hi: 0x9d}, + {value: 0x267c, lo: 0xa2, hi: 0xa2}, + {value: 0x2683, lo: 0xa7, hi: 0xa7}, + {value: 0x268a, lo: 0xac, hi: 0xac}, + {value: 0x2667, lo: 0xb9, hi: 0xb9}, + // Block 0x27, offset 0x114 + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0x86, hi: 0x86}, + // Block 0x28, offset 0x116 + {value: 0x0000, lo: 0x05}, + {value: 0xa000, lo: 0xa5, hi: 0xa5}, + {value: 0x2d1e, lo: 0xa6, hi: 0xa6}, + {value: 0x9900, lo: 0xae, hi: 0xae}, + {value: 0x8102, lo: 0xb7, hi: 0xb7}, + {value: 0x8104, lo: 0xb9, hi: 0xba}, + // Block 0x29, offset 0x11c + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0x8d, hi: 0x8d}, + // Block 0x2a, offset 0x11e + {value: 0x0000, lo: 0x01}, + {value: 0x030f, lo: 0xbc, hi: 0xbc}, + // Block 0x2b, offset 0x120 + {value: 0x0000, lo: 0x01}, + {value: 0xa000, lo: 0x80, hi: 0x92}, + // Block 0x2c, offset 0x122 + {value: 0x0000, lo: 0x01}, + {value: 0xb900, lo: 0xa1, hi: 0xb5}, + // Block 0x2d, offset 0x124 + {value: 0x0000, lo: 0x01}, + {value: 0x9900, lo: 0xa8, hi: 0xbf}, + // Block 0x2e, offset 0x126 + {value: 0x0000, lo: 0x01}, + {value: 0x9900, lo: 0x80, hi: 0x82}, + // Block 0x2f, offset 0x128 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0x9d, hi: 0x9f}, + // Block 0x30, offset 0x12a + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x94, hi: 0x94}, + {value: 0x8104, lo: 0xb4, hi: 0xb4}, + // Block 0x31, offset 0x12d + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x92, hi: 0x92}, + {value: 0x8132, lo: 0x9d, hi: 0x9d}, + // Block 0x32, offset 0x130 + {value: 0x0000, lo: 0x01}, + {value: 0x8131, lo: 0xa9, hi: 0xa9}, + // Block 0x33, offset 0x132 + {value: 0x0004, lo: 0x02}, + {value: 0x812e, lo: 0xb9, hi: 0xba}, + {value: 0x812d, lo: 0xbb, hi: 0xbb}, + // Block 0x34, offset 0x135 + {value: 0x0000, lo: 0x02}, + {value: 0x8132, lo: 0x97, hi: 0x97}, + {value: 0x812d, lo: 0x98, hi: 0x98}, + // Block 0x35, offset 0x138 + {value: 0x0000, lo: 0x03}, + {value: 0x8104, lo: 0xa0, hi: 0xa0}, + {value: 0x8132, lo: 0xb5, hi: 0xbc}, + {value: 0x812d, lo: 0xbf, hi: 0xbf}, + // Block 0x36, offset 0x13c + {value: 0x0000, lo: 0x04}, + {value: 0x8132, lo: 0xb0, hi: 0xb4}, + {value: 0x812d, lo: 0xb5, hi: 0xba}, + {value: 0x8132, lo: 0xbb, hi: 0xbc}, + {value: 0x812d, lo: 0xbd, hi: 0xbd}, + // Block 0x37, offset 0x141 + {value: 0x0000, lo: 0x08}, + {value: 0x2d66, lo: 0x80, hi: 0x80}, + {value: 0x2d6e, lo: 0x81, hi: 0x81}, + {value: 0xa000, lo: 0x82, hi: 0x82}, + {value: 0x2d76, lo: 0x83, hi: 0x83}, + {value: 0x8104, lo: 0x84, hi: 0x84}, + {value: 0x8132, lo: 0xab, hi: 0xab}, + {value: 0x812d, lo: 0xac, hi: 0xac}, + {value: 0x8132, lo: 0xad, hi: 0xb3}, + // Block 0x38, offset 0x14a + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0xaa, hi: 0xab}, + // Block 0x39, offset 0x14c + {value: 0x0000, lo: 0x02}, + {value: 0x8102, lo: 0xa6, hi: 0xa6}, + {value: 0x8104, lo: 0xb2, hi: 0xb3}, + // Block 0x3a, offset 0x14f + {value: 0x0000, lo: 0x01}, + {value: 0x8102, lo: 0xb7, hi: 0xb7}, + // Block 0x3b, offset 0x151 + {value: 0x0000, lo: 0x0a}, + {value: 0x8132, lo: 0x90, hi: 0x92}, + {value: 0x8101, lo: 0x94, hi: 0x94}, + {value: 0x812d, lo: 0x95, hi: 0x99}, + {value: 0x8132, lo: 0x9a, hi: 0x9b}, + {value: 0x812d, lo: 0x9c, hi: 0x9f}, + {value: 0x8132, lo: 0xa0, hi: 0xa0}, + {value: 0x8101, lo: 0xa2, hi: 0xa8}, + {value: 0x812d, lo: 0xad, hi: 0xad}, + {value: 0x8132, lo: 0xb4, hi: 0xb4}, + {value: 0x8132, lo: 0xb8, hi: 0xb9}, + // Block 0x3c, offset 0x15c + {value: 0x0002, lo: 0x0a}, + {value: 0x0043, lo: 0xac, hi: 0xac}, + {value: 0x00d1, lo: 0xad, hi: 0xad}, + {value: 0x0045, lo: 0xae, hi: 0xae}, + {value: 0x0049, lo: 0xb0, hi: 0xb1}, + {value: 0x00e6, lo: 0xb2, hi: 0xb2}, + {value: 0x004f, lo: 0xb3, hi: 0xba}, + {value: 0x005f, lo: 0xbc, hi: 0xbc}, + {value: 0x00ef, lo: 0xbd, hi: 0xbd}, + {value: 0x0061, lo: 0xbe, hi: 0xbe}, + {value: 0x0065, lo: 0xbf, hi: 0xbf}, + // Block 0x3d, offset 0x167 + {value: 0x0000, lo: 0x0d}, + {value: 0x0001, lo: 0x80, hi: 0x8a}, + {value: 0x043b, lo: 0x91, hi: 0x91}, + {value: 0x429b, lo: 0x97, hi: 0x97}, + {value: 0x001d, lo: 0xa4, hi: 0xa4}, + {value: 0x1873, lo: 0xa5, hi: 0xa5}, + {value: 0x1b5c, lo: 0xa6, hi: 0xa6}, + {value: 0x0001, lo: 0xaf, hi: 0xaf}, + {value: 0x2691, lo: 0xb3, hi: 0xb3}, + {value: 0x27fe, lo: 0xb4, hi: 0xb4}, + {value: 0x2698, lo: 0xb6, hi: 0xb6}, + {value: 0x2808, lo: 0xb7, hi: 0xb7}, + {value: 0x186d, lo: 0xbc, hi: 0xbc}, + {value: 0x4269, lo: 0xbe, hi: 0xbe}, + // Block 0x3e, offset 0x175 + {value: 0x0002, lo: 0x0d}, + {value: 0x1933, lo: 0x87, hi: 0x87}, + {value: 0x1930, lo: 0x88, hi: 0x88}, + {value: 0x1870, lo: 0x89, hi: 0x89}, + {value: 0x298e, lo: 0x97, hi: 0x97}, + {value: 0x0001, lo: 0x9f, hi: 0x9f}, + {value: 0x0021, lo: 0xb0, hi: 0xb0}, + {value: 0x0093, lo: 0xb1, hi: 0xb1}, + {value: 0x0029, lo: 0xb4, hi: 0xb9}, + {value: 0x0017, lo: 0xba, hi: 0xba}, + {value: 0x0467, lo: 0xbb, hi: 0xbb}, + {value: 0x003b, lo: 0xbc, hi: 0xbc}, + {value: 0x0011, lo: 0xbd, hi: 0xbe}, + {value: 0x009d, lo: 0xbf, hi: 0xbf}, + // Block 0x3f, offset 0x183 + {value: 0x0002, lo: 0x0f}, + {value: 0x0021, lo: 0x80, hi: 0x89}, + {value: 0x0017, lo: 0x8a, hi: 0x8a}, + {value: 0x0467, lo: 0x8b, hi: 0x8b}, + {value: 0x003b, lo: 0x8c, hi: 0x8c}, + {value: 0x0011, lo: 0x8d, hi: 0x8e}, + {value: 0x0083, lo: 0x90, hi: 0x90}, + {value: 0x008b, lo: 0x91, hi: 0x91}, + {value: 0x009f, lo: 0x92, hi: 0x92}, + {value: 0x00b1, lo: 0x93, hi: 0x93}, + {value: 0x0104, lo: 0x94, hi: 0x94}, + {value: 0x0091, lo: 0x95, hi: 0x95}, + {value: 0x0097, lo: 0x96, hi: 0x99}, + {value: 0x00a1, lo: 0x9a, hi: 0x9a}, + {value: 0x00a7, lo: 0x9b, hi: 0x9c}, + {value: 0x1999, lo: 0xa8, hi: 0xa8}, + // Block 0x40, offset 0x193 + {value: 0x0000, lo: 0x0d}, + {value: 0x8132, lo: 0x90, hi: 0x91}, + {value: 0x8101, lo: 0x92, hi: 0x93}, + {value: 0x8132, lo: 0x94, hi: 0x97}, + {value: 0x8101, lo: 0x98, hi: 0x9a}, + {value: 0x8132, lo: 0x9b, hi: 0x9c}, + {value: 0x8132, lo: 0xa1, hi: 0xa1}, + {value: 0x8101, lo: 0xa5, hi: 0xa6}, + {value: 0x8132, lo: 0xa7, hi: 0xa7}, + {value: 0x812d, lo: 0xa8, hi: 0xa8}, + {value: 0x8132, lo: 0xa9, hi: 0xa9}, + {value: 0x8101, lo: 0xaa, hi: 0xab}, + {value: 0x812d, lo: 0xac, hi: 0xaf}, + {value: 0x8132, lo: 0xb0, hi: 0xb0}, + // Block 0x41, offset 0x1a1 + {value: 0x0007, lo: 0x06}, + {value: 0x2180, lo: 0x89, hi: 0x89}, + {value: 0xa000, lo: 0x90, hi: 0x90}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0xa000, lo: 0x94, hi: 0x94}, + {value: 0x3bb9, lo: 0x9a, hi: 0x9b}, + {value: 0x3bc7, lo: 0xae, hi: 0xae}, + // Block 0x42, offset 0x1a8 + {value: 0x000e, lo: 0x05}, + {value: 0x3bce, lo: 0x8d, hi: 0x8e}, + {value: 0x3bd5, lo: 0x8f, hi: 0x8f}, + {value: 0xa000, lo: 0x90, hi: 0x90}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0xa000, lo: 0x94, hi: 0x94}, + // Block 0x43, offset 0x1ae + {value: 0x0173, lo: 0x0e}, + {value: 0xa000, lo: 0x83, hi: 0x83}, + {value: 0x3be3, lo: 0x84, hi: 0x84}, + {value: 0xa000, lo: 0x88, hi: 0x88}, + {value: 0x3bea, lo: 0x89, hi: 0x89}, + {value: 0xa000, lo: 0x8b, hi: 0x8b}, + {value: 0x3bf1, lo: 0x8c, hi: 0x8c}, + {value: 0xa000, lo: 0xa3, hi: 0xa3}, + {value: 0x3bf8, lo: 0xa4, hi: 0xa4}, + {value: 0xa000, lo: 0xa5, hi: 0xa5}, + {value: 0x3bff, lo: 0xa6, hi: 0xa6}, + {value: 0x269f, lo: 0xac, hi: 0xad}, + {value: 0x26a6, lo: 0xaf, hi: 0xaf}, + {value: 0x281c, lo: 0xb0, hi: 0xb0}, + {value: 0xa000, lo: 0xbc, hi: 0xbc}, + // Block 0x44, offset 0x1bd + {value: 0x0007, lo: 0x03}, + {value: 0x3c68, lo: 0xa0, hi: 0xa1}, + {value: 0x3c92, lo: 0xa2, hi: 0xa3}, + {value: 0x3cbc, lo: 0xaa, hi: 0xad}, + // Block 0x45, offset 0x1c1 + {value: 0x0004, lo: 0x01}, + {value: 0x048b, lo: 0xa9, hi: 0xaa}, + // Block 0x46, offset 0x1c3 + {value: 0x0002, lo: 0x03}, + {value: 0x0057, lo: 0x80, hi: 0x8f}, + {value: 0x0083, lo: 0x90, hi: 0xa9}, + {value: 0x0021, lo: 0xaa, hi: 0xaa}, + // Block 0x47, offset 0x1c7 + {value: 0x0000, lo: 0x01}, + {value: 0x299b, lo: 0x8c, hi: 0x8c}, + // Block 0x48, offset 0x1c9 + {value: 0x0263, lo: 0x02}, + {value: 0x1b8c, lo: 0xb4, hi: 0xb4}, + {value: 0x192d, lo: 0xb5, hi: 0xb6}, + // Block 0x49, offset 0x1cc + {value: 0x0000, lo: 0x01}, + {value: 0x44dd, lo: 0x9c, hi: 0x9c}, + // Block 0x4a, offset 0x1ce + {value: 0x0000, lo: 0x02}, + {value: 0x0095, lo: 0xbc, hi: 0xbc}, + {value: 0x006d, lo: 0xbd, hi: 0xbd}, + // Block 0x4b, offset 0x1d1 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xaf, hi: 0xb1}, + // Block 0x4c, offset 0x1d3 + {value: 0x0000, lo: 0x02}, + {value: 0x047f, lo: 0xaf, hi: 0xaf}, + {value: 0x8104, lo: 0xbf, hi: 0xbf}, + // Block 0x4d, offset 0x1d6 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xa0, hi: 0xbf}, + // Block 0x4e, offset 0x1d8 + {value: 0x0000, lo: 0x01}, + {value: 0x0dc3, lo: 0x9f, hi: 0x9f}, + // Block 0x4f, offset 0x1da + {value: 0x0000, lo: 0x01}, + {value: 0x162f, lo: 0xb3, hi: 0xb3}, + // Block 0x50, offset 0x1dc + {value: 0x0004, lo: 0x0b}, + {value: 0x1597, lo: 0x80, hi: 0x82}, + {value: 0x15af, lo: 0x83, hi: 0x83}, + {value: 0x15c7, lo: 0x84, hi: 0x85}, + {value: 0x15d7, lo: 0x86, hi: 0x89}, + {value: 0x15eb, lo: 0x8a, hi: 0x8c}, + {value: 0x15ff, lo: 0x8d, hi: 0x8d}, + {value: 0x1607, lo: 0x8e, hi: 0x8e}, + {value: 0x160f, lo: 0x8f, hi: 0x90}, + {value: 0x161b, lo: 0x91, hi: 0x93}, + {value: 0x162b, lo: 0x94, hi: 0x94}, + {value: 0x1633, lo: 0x95, hi: 0x95}, + // Block 0x51, offset 0x1e8 + {value: 0x0004, lo: 0x09}, + {value: 0x0001, lo: 0x80, hi: 0x80}, + {value: 0x812c, lo: 0xaa, hi: 0xaa}, + {value: 0x8131, lo: 0xab, hi: 0xab}, + {value: 0x8133, lo: 0xac, hi: 0xac}, + {value: 0x812e, lo: 0xad, hi: 0xad}, + {value: 0x812f, lo: 0xae, hi: 0xae}, + {value: 0x812f, lo: 0xaf, hi: 0xaf}, + {value: 0x04b3, lo: 0xb6, hi: 0xb6}, + {value: 0x0887, lo: 0xb8, hi: 0xba}, + // Block 0x52, offset 0x1f2 + {value: 0x0006, lo: 0x09}, + {value: 0x0313, lo: 0xb1, hi: 0xb1}, + {value: 0x0317, lo: 0xb2, hi: 0xb2}, + {value: 0x4a3b, lo: 0xb3, hi: 0xb3}, + {value: 0x031b, lo: 0xb4, hi: 0xb4}, + {value: 0x4a41, lo: 0xb5, hi: 0xb6}, + {value: 0x031f, lo: 0xb7, hi: 0xb7}, + {value: 0x0323, lo: 0xb8, hi: 0xb8}, + {value: 0x0327, lo: 0xb9, hi: 0xb9}, + {value: 0x4a4d, lo: 0xba, hi: 0xbf}, + // Block 0x53, offset 0x1fc + {value: 0x0000, lo: 0x02}, + {value: 0x8132, lo: 0xaf, hi: 0xaf}, + {value: 0x8132, lo: 0xb4, hi: 0xbd}, + // Block 0x54, offset 0x1ff + {value: 0x0000, lo: 0x03}, + {value: 0x020f, lo: 0x9c, hi: 0x9c}, + {value: 0x0212, lo: 0x9d, hi: 0x9d}, + {value: 0x8132, lo: 0x9e, hi: 0x9f}, + // Block 0x55, offset 0x203 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xb0, hi: 0xb1}, + // Block 0x56, offset 0x205 + {value: 0x0000, lo: 0x01}, + {value: 0x163b, lo: 0xb0, hi: 0xb0}, + // Block 0x57, offset 0x207 + {value: 0x000c, lo: 0x01}, + {value: 0x00d7, lo: 0xb8, hi: 0xb9}, + // Block 0x58, offset 0x209 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x86, hi: 0x86}, + // Block 0x59, offset 0x20b + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x84, hi: 0x84}, + {value: 0x8132, lo: 0xa0, hi: 0xb1}, + // Block 0x5a, offset 0x20e + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0xab, hi: 0xad}, + // Block 0x5b, offset 0x210 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x93, hi: 0x93}, + // Block 0x5c, offset 0x212 + {value: 0x0000, lo: 0x01}, + {value: 0x8102, lo: 0xb3, hi: 0xb3}, + // Block 0x5d, offset 0x214 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x80, hi: 0x80}, + // Block 0x5e, offset 0x216 + {value: 0x0000, lo: 0x05}, + {value: 0x8132, lo: 0xb0, hi: 0xb0}, + {value: 0x8132, lo: 0xb2, hi: 0xb3}, + {value: 0x812d, lo: 0xb4, hi: 0xb4}, + {value: 0x8132, lo: 0xb7, hi: 0xb8}, + {value: 0x8132, lo: 0xbe, hi: 0xbf}, + // Block 0x5f, offset 0x21c + {value: 0x0000, lo: 0x02}, + {value: 0x8132, lo: 0x81, hi: 0x81}, + {value: 0x8104, lo: 0xb6, hi: 0xb6}, + // Block 0x60, offset 0x21f + {value: 0x0008, lo: 0x03}, + {value: 0x1637, lo: 0x9c, hi: 0x9d}, + {value: 0x0125, lo: 0x9e, hi: 0x9e}, + {value: 0x1643, lo: 0x9f, hi: 0x9f}, + // Block 0x61, offset 0x223 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0xad, hi: 0xad}, + // Block 0x62, offset 0x225 + {value: 0x0000, lo: 0x06}, + {value: 0xe500, lo: 0x80, hi: 0x80}, + {value: 0xc600, lo: 0x81, hi: 0x9b}, + {value: 0xe500, lo: 0x9c, hi: 0x9c}, + {value: 0xc600, lo: 0x9d, hi: 0xb7}, + {value: 0xe500, lo: 0xb8, hi: 0xb8}, + {value: 0xc600, lo: 0xb9, hi: 0xbf}, + // Block 0x63, offset 0x22c + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x93}, + {value: 0xe500, lo: 0x94, hi: 0x94}, + {value: 0xc600, lo: 0x95, hi: 0xaf}, + {value: 0xe500, lo: 0xb0, hi: 0xb0}, + {value: 0xc600, lo: 0xb1, hi: 0xbf}, + // Block 0x64, offset 0x232 + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x8b}, + {value: 0xe500, lo: 0x8c, hi: 0x8c}, + {value: 0xc600, lo: 0x8d, hi: 0xa7}, + {value: 0xe500, lo: 0xa8, hi: 0xa8}, + {value: 0xc600, lo: 0xa9, hi: 0xbf}, + // Block 0x65, offset 0x238 + {value: 0x0000, lo: 0x07}, + {value: 0xc600, lo: 0x80, hi: 0x83}, + {value: 0xe500, lo: 0x84, hi: 0x84}, + {value: 0xc600, lo: 0x85, hi: 0x9f}, + {value: 0xe500, lo: 0xa0, hi: 0xa0}, + {value: 0xc600, lo: 0xa1, hi: 0xbb}, + {value: 0xe500, lo: 0xbc, hi: 0xbc}, + {value: 0xc600, lo: 0xbd, hi: 0xbf}, + // Block 0x66, offset 0x240 + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x97}, + {value: 0xe500, lo: 0x98, hi: 0x98}, + {value: 0xc600, lo: 0x99, hi: 0xb3}, + {value: 0xe500, lo: 0xb4, hi: 0xb4}, + {value: 0xc600, lo: 0xb5, hi: 0xbf}, + // Block 0x67, offset 0x246 + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x8f}, + {value: 0xe500, lo: 0x90, hi: 0x90}, + {value: 0xc600, lo: 0x91, hi: 0xab}, + {value: 0xe500, lo: 0xac, hi: 0xac}, + {value: 0xc600, lo: 0xad, hi: 0xbf}, + // Block 0x68, offset 0x24c + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x87}, + {value: 0xe500, lo: 0x88, hi: 0x88}, + {value: 0xc600, lo: 0x89, hi: 0xa3}, + {value: 0xe500, lo: 0xa4, hi: 0xa4}, + {value: 0xc600, lo: 0xa5, hi: 0xbf}, + // Block 0x69, offset 0x252 + {value: 0x0000, lo: 0x03}, + {value: 0xc600, lo: 0x80, hi: 0x87}, + {value: 0xe500, lo: 0x88, hi: 0x88}, + {value: 0xc600, lo: 0x89, hi: 0xa3}, + // Block 0x6a, offset 0x256 + {value: 0x0002, lo: 0x01}, + {value: 0x0003, lo: 0x81, hi: 0xbf}, + // Block 0x6b, offset 0x258 + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0xbd, hi: 0xbd}, + // Block 0x6c, offset 0x25a + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0xa0, hi: 0xa0}, + // Block 0x6d, offset 0x25c + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xb6, hi: 0xba}, + // Block 0x6e, offset 0x25e + {value: 0x002c, lo: 0x05}, + {value: 0x812d, lo: 0x8d, hi: 0x8d}, + {value: 0x8132, lo: 0x8f, hi: 0x8f}, + {value: 0x8132, lo: 0xb8, hi: 0xb8}, + {value: 0x8101, lo: 0xb9, hi: 0xba}, + {value: 0x8104, lo: 0xbf, hi: 0xbf}, + // Block 0x6f, offset 0x264 + {value: 0x0000, lo: 0x02}, + {value: 0x8132, lo: 0xa5, hi: 0xa5}, + {value: 0x812d, lo: 0xa6, hi: 0xa6}, + // Block 0x70, offset 0x267 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x86, hi: 0x86}, + {value: 0x8104, lo: 0xbf, hi: 0xbf}, + // Block 0x71, offset 0x26a + {value: 0x17fe, lo: 0x07}, + {value: 0xa000, lo: 0x99, hi: 0x99}, + {value: 0x4238, lo: 0x9a, hi: 0x9a}, + {value: 0xa000, lo: 0x9b, hi: 0x9b}, + {value: 0x4242, lo: 0x9c, hi: 0x9c}, + {value: 0xa000, lo: 0xa5, hi: 0xa5}, + {value: 0x424c, lo: 0xab, hi: 0xab}, + {value: 0x8104, lo: 0xb9, hi: 0xba}, + // Block 0x72, offset 0x272 + {value: 0x0000, lo: 0x06}, + {value: 0x8132, lo: 0x80, hi: 0x82}, + {value: 0x9900, lo: 0xa7, hi: 0xa7}, + {value: 0x2d7e, lo: 0xae, hi: 0xae}, + {value: 0x2d88, lo: 0xaf, hi: 0xaf}, + {value: 0xa000, lo: 0xb1, hi: 0xb2}, + {value: 0x8104, lo: 0xb3, hi: 0xb4}, + // Block 0x73, offset 0x279 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x80, hi: 0x80}, + {value: 0x8102, lo: 0x8a, hi: 0x8a}, + // Block 0x74, offset 0x27c + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0xb5, hi: 0xb5}, + {value: 0x8102, lo: 0xb6, hi: 0xb6}, + // Block 0x75, offset 0x27f + {value: 0x0002, lo: 0x01}, + {value: 0x8102, lo: 0xa9, hi: 0xaa}, + // Block 0x76, offset 0x281 + {value: 0x0000, lo: 0x07}, + {value: 0xa000, lo: 0x87, hi: 0x87}, + {value: 0x2d92, lo: 0x8b, hi: 0x8b}, + {value: 0x2d9c, lo: 0x8c, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x97, hi: 0x97}, + {value: 0x8132, lo: 0xa6, hi: 0xac}, + {value: 0x8132, lo: 0xb0, hi: 0xb4}, + // Block 0x77, offset 0x289 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x82, hi: 0x82}, + {value: 0x8102, lo: 0x86, hi: 0x86}, + // Block 0x78, offset 0x28c + {value: 0x6b5a, lo: 0x06}, + {value: 0x9900, lo: 0xb0, hi: 0xb0}, + {value: 0xa000, lo: 0xb9, hi: 0xb9}, + {value: 0x9900, lo: 0xba, hi: 0xba}, + {value: 0x2db0, lo: 0xbb, hi: 0xbb}, + {value: 0x2da6, lo: 0xbc, hi: 0xbd}, + {value: 0x2dba, lo: 0xbe, hi: 0xbe}, + // Block 0x79, offset 0x293 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x82, hi: 0x82}, + {value: 0x8102, lo: 0x83, hi: 0x83}, + // Block 0x7a, offset 0x296 + {value: 0x0000, lo: 0x05}, + {value: 0x9900, lo: 0xaf, hi: 0xaf}, + {value: 0xa000, lo: 0xb8, hi: 0xb9}, + {value: 0x2dc4, lo: 0xba, hi: 0xba}, + {value: 0x2dce, lo: 0xbb, hi: 0xbb}, + {value: 0x8104, lo: 0xbf, hi: 0xbf}, + // Block 0x7b, offset 0x29c + {value: 0x0000, lo: 0x01}, + {value: 0x8102, lo: 0x80, hi: 0x80}, + // Block 0x7c, offset 0x29e + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0xbf, hi: 0xbf}, + // Block 0x7d, offset 0x2a0 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0xb6, hi: 0xb6}, + {value: 0x8102, lo: 0xb7, hi: 0xb7}, + // Block 0x7e, offset 0x2a3 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0xab, hi: 0xab}, + // Block 0x7f, offset 0x2a5 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0xb4, hi: 0xb4}, + // Block 0x80, offset 0x2a7 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x87, hi: 0x87}, + // Block 0x81, offset 0x2a9 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x99, hi: 0x99}, + // Block 0x82, offset 0x2ab + {value: 0x0000, lo: 0x02}, + {value: 0x8102, lo: 0x82, hi: 0x82}, + {value: 0x8104, lo: 0x84, hi: 0x85}, + // Block 0x83, offset 0x2ae + {value: 0x0000, lo: 0x01}, + {value: 0x8101, lo: 0xb0, hi: 0xb4}, + // Block 0x84, offset 0x2b0 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xb0, hi: 0xb6}, + // Block 0x85, offset 0x2b2 + {value: 0x0000, lo: 0x01}, + {value: 0x8101, lo: 0x9e, hi: 0x9e}, + // Block 0x86, offset 0x2b4 + {value: 0x0000, lo: 0x0c}, + {value: 0x45cc, lo: 0x9e, hi: 0x9e}, + {value: 0x45d6, lo: 0x9f, hi: 0x9f}, + {value: 0x460a, lo: 0xa0, hi: 0xa0}, + {value: 0x4618, lo: 0xa1, hi: 0xa1}, + {value: 0x4626, lo: 0xa2, hi: 0xa2}, + {value: 0x4634, lo: 0xa3, hi: 0xa3}, + {value: 0x4642, lo: 0xa4, hi: 0xa4}, + {value: 0x812b, lo: 0xa5, hi: 0xa6}, + {value: 0x8101, lo: 0xa7, hi: 0xa9}, + {value: 0x8130, lo: 0xad, hi: 0xad}, + {value: 0x812b, lo: 0xae, hi: 0xb2}, + {value: 0x812d, lo: 0xbb, hi: 0xbf}, + // Block 0x87, offset 0x2c1 + {value: 0x0000, lo: 0x09}, + {value: 0x812d, lo: 0x80, hi: 0x82}, + {value: 0x8132, lo: 0x85, hi: 0x89}, + {value: 0x812d, lo: 0x8a, hi: 0x8b}, + {value: 0x8132, lo: 0xaa, hi: 0xad}, + {value: 0x45e0, lo: 0xbb, hi: 0xbb}, + {value: 0x45ea, lo: 0xbc, hi: 0xbc}, + {value: 0x4650, lo: 0xbd, hi: 0xbd}, + {value: 0x466c, lo: 0xbe, hi: 0xbe}, + {value: 0x465e, lo: 0xbf, hi: 0xbf}, + // Block 0x88, offset 0x2cb + {value: 0x0000, lo: 0x01}, + {value: 0x467a, lo: 0x80, hi: 0x80}, + // Block 0x89, offset 0x2cd + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0x82, hi: 0x84}, + // Block 0x8a, offset 0x2cf + {value: 0x0002, lo: 0x03}, + {value: 0x0043, lo: 0x80, hi: 0x99}, + {value: 0x0083, lo: 0x9a, hi: 0xb3}, + {value: 0x0043, lo: 0xb4, hi: 0xbf}, + // Block 0x8b, offset 0x2d3 + {value: 0x0002, lo: 0x04}, + {value: 0x005b, lo: 0x80, hi: 0x8d}, + {value: 0x0083, lo: 0x8e, hi: 0x94}, + {value: 0x0093, lo: 0x96, hi: 0xa7}, + {value: 0x0043, lo: 0xa8, hi: 0xbf}, + // Block 0x8c, offset 0x2d8 + {value: 0x0002, lo: 0x0b}, + {value: 0x0073, lo: 0x80, hi: 0x81}, + {value: 0x0083, lo: 0x82, hi: 0x9b}, + {value: 0x0043, lo: 0x9c, hi: 0x9c}, + {value: 0x0047, lo: 0x9e, hi: 0x9f}, + {value: 0x004f, lo: 0xa2, hi: 0xa2}, + {value: 0x0055, lo: 0xa5, hi: 0xa6}, + {value: 0x005d, lo: 0xa9, hi: 0xac}, + {value: 0x0067, lo: 0xae, hi: 0xb5}, + {value: 0x0083, lo: 0xb6, hi: 0xb9}, + {value: 0x008d, lo: 0xbb, hi: 0xbb}, + {value: 0x0091, lo: 0xbd, hi: 0xbf}, + // Block 0x8d, offset 0x2e4 + {value: 0x0002, lo: 0x04}, + {value: 0x0097, lo: 0x80, hi: 0x83}, + {value: 0x00a1, lo: 0x85, hi: 0x8f}, + {value: 0x0043, lo: 0x90, hi: 0xa9}, + {value: 0x0083, lo: 0xaa, hi: 0xbf}, + // Block 0x8e, offset 0x2e9 + {value: 0x0002, lo: 0x08}, + {value: 0x00af, lo: 0x80, hi: 0x83}, + {value: 0x0043, lo: 0x84, hi: 0x85}, + {value: 0x0049, lo: 0x87, hi: 0x8a}, + {value: 0x0055, lo: 0x8d, hi: 0x94}, + {value: 0x0067, lo: 0x96, hi: 0x9c}, + {value: 0x0083, lo: 0x9e, hi: 0xb7}, + {value: 0x0043, lo: 0xb8, hi: 0xb9}, + {value: 0x0049, lo: 0xbb, hi: 0xbe}, + // Block 0x8f, offset 0x2f2 + {value: 0x0002, lo: 0x05}, + {value: 0x0053, lo: 0x80, hi: 0x84}, + {value: 0x005f, lo: 0x86, hi: 0x86}, + {value: 0x0067, lo: 0x8a, hi: 0x90}, + {value: 0x0083, lo: 0x92, hi: 0xab}, + {value: 0x0043, lo: 0xac, hi: 0xbf}, + // Block 0x90, offset 0x2f8 + {value: 0x0002, lo: 0x04}, + {value: 0x006b, lo: 0x80, hi: 0x85}, + {value: 0x0083, lo: 0x86, hi: 0x9f}, + {value: 0x0043, lo: 0xa0, hi: 0xb9}, + {value: 0x0083, lo: 0xba, hi: 0xbf}, + // Block 0x91, offset 0x2fd + {value: 0x0002, lo: 0x03}, + {value: 0x008f, lo: 0x80, hi: 0x93}, + {value: 0x0043, lo: 0x94, hi: 0xad}, + {value: 0x0083, lo: 0xae, hi: 0xbf}, + // Block 0x92, offset 0x301 + {value: 0x0002, lo: 0x04}, + {value: 0x00a7, lo: 0x80, hi: 0x87}, + {value: 0x0043, lo: 0x88, hi: 0xa1}, + {value: 0x0083, lo: 0xa2, hi: 0xbb}, + {value: 0x0043, lo: 0xbc, hi: 0xbf}, + // Block 0x93, offset 0x306 + {value: 0x0002, lo: 0x03}, + {value: 0x004b, lo: 0x80, hi: 0x95}, + {value: 0x0083, lo: 0x96, hi: 0xaf}, + {value: 0x0043, lo: 0xb0, hi: 0xbf}, + // Block 0x94, offset 0x30a + {value: 0x0003, lo: 0x0f}, + {value: 0x01b8, lo: 0x80, hi: 0x80}, + {value: 0x045f, lo: 0x81, hi: 0x81}, + {value: 0x01bb, lo: 0x82, hi: 0x9a}, + {value: 0x045b, lo: 0x9b, hi: 0x9b}, + {value: 0x01c7, lo: 0x9c, hi: 0x9c}, + {value: 0x01d0, lo: 0x9d, hi: 0x9d}, + {value: 0x01d6, lo: 0x9e, hi: 0x9e}, + {value: 0x01fa, lo: 0x9f, hi: 0x9f}, + {value: 0x01eb, lo: 0xa0, hi: 0xa0}, + {value: 0x01e8, lo: 0xa1, hi: 0xa1}, + {value: 0x0173, lo: 0xa2, hi: 0xb2}, + {value: 0x0188, lo: 0xb3, hi: 0xb3}, + {value: 0x01a6, lo: 0xb4, hi: 0xba}, + {value: 0x045f, lo: 0xbb, hi: 0xbb}, + {value: 0x01bb, lo: 0xbc, hi: 0xbf}, + // Block 0x95, offset 0x31a + {value: 0x0003, lo: 0x0d}, + {value: 0x01c7, lo: 0x80, hi: 0x94}, + {value: 0x045b, lo: 0x95, hi: 0x95}, + {value: 0x01c7, lo: 0x96, hi: 0x96}, + {value: 0x01d0, lo: 0x97, hi: 0x97}, + {value: 0x01d6, lo: 0x98, hi: 0x98}, + {value: 0x01fa, lo: 0x99, hi: 0x99}, + {value: 0x01eb, lo: 0x9a, hi: 0x9a}, + {value: 0x01e8, lo: 0x9b, hi: 0x9b}, + {value: 0x0173, lo: 0x9c, hi: 0xac}, + {value: 0x0188, lo: 0xad, hi: 0xad}, + {value: 0x01a6, lo: 0xae, hi: 0xb4}, + {value: 0x045f, lo: 0xb5, hi: 0xb5}, + {value: 0x01bb, lo: 0xb6, hi: 0xbf}, + // Block 0x96, offset 0x328 + {value: 0x0003, lo: 0x0d}, + {value: 0x01d9, lo: 0x80, hi: 0x8e}, + {value: 0x045b, lo: 0x8f, hi: 0x8f}, + {value: 0x01c7, lo: 0x90, hi: 0x90}, + {value: 0x01d0, lo: 0x91, hi: 0x91}, + {value: 0x01d6, lo: 0x92, hi: 0x92}, + {value: 0x01fa, lo: 0x93, hi: 0x93}, + {value: 0x01eb, lo: 0x94, hi: 0x94}, + {value: 0x01e8, lo: 0x95, hi: 0x95}, + {value: 0x0173, lo: 0x96, hi: 0xa6}, + {value: 0x0188, lo: 0xa7, hi: 0xa7}, + {value: 0x01a6, lo: 0xa8, hi: 0xae}, + {value: 0x045f, lo: 0xaf, hi: 0xaf}, + {value: 0x01bb, lo: 0xb0, hi: 0xbf}, + // Block 0x97, offset 0x336 + {value: 0x0003, lo: 0x0d}, + {value: 0x01eb, lo: 0x80, hi: 0x88}, + {value: 0x045b, lo: 0x89, hi: 0x89}, + {value: 0x01c7, lo: 0x8a, hi: 0x8a}, + {value: 0x01d0, lo: 0x8b, hi: 0x8b}, + {value: 0x01d6, lo: 0x8c, hi: 0x8c}, + {value: 0x01fa, lo: 0x8d, hi: 0x8d}, + {value: 0x01eb, lo: 0x8e, hi: 0x8e}, + {value: 0x01e8, lo: 0x8f, hi: 0x8f}, + {value: 0x0173, lo: 0x90, hi: 0xa0}, + {value: 0x0188, lo: 0xa1, hi: 0xa1}, + {value: 0x01a6, lo: 0xa2, hi: 0xa8}, + {value: 0x045f, lo: 0xa9, hi: 0xa9}, + {value: 0x01bb, lo: 0xaa, hi: 0xbf}, + // Block 0x98, offset 0x344 + {value: 0x0000, lo: 0x05}, + {value: 0x8132, lo: 0x80, hi: 0x86}, + {value: 0x8132, lo: 0x88, hi: 0x98}, + {value: 0x8132, lo: 0x9b, hi: 0xa1}, + {value: 0x8132, lo: 0xa3, hi: 0xa4}, + {value: 0x8132, lo: 0xa6, hi: 0xaa}, + // Block 0x99, offset 0x34a + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0x90, hi: 0x96}, + // Block 0x9a, offset 0x34c + {value: 0x0000, lo: 0x02}, + {value: 0x8132, lo: 0x84, hi: 0x89}, + {value: 0x8102, lo: 0x8a, hi: 0x8a}, + // Block 0x9b, offset 0x34f + {value: 0x0002, lo: 0x09}, + {value: 0x0063, lo: 0x80, hi: 0x89}, + {value: 0x1951, lo: 0x8a, hi: 0x8a}, + {value: 0x1981, lo: 0x8b, hi: 0x8b}, + {value: 0x199c, lo: 0x8c, hi: 0x8c}, + {value: 0x19a2, lo: 0x8d, hi: 0x8d}, + {value: 0x1bc0, lo: 0x8e, hi: 0x8e}, + {value: 0x19ae, lo: 0x8f, hi: 0x8f}, + {value: 0x197b, lo: 0xaa, hi: 0xaa}, + {value: 0x197e, lo: 0xab, hi: 0xab}, + // Block 0x9c, offset 0x359 + {value: 0x0000, lo: 0x01}, + {value: 0x193f, lo: 0x90, hi: 0x90}, + // Block 0x9d, offset 0x35b + {value: 0x0028, lo: 0x09}, + {value: 0x2862, lo: 0x80, hi: 0x80}, + {value: 0x2826, lo: 0x81, hi: 0x81}, + {value: 0x2830, lo: 0x82, hi: 0x82}, + {value: 0x2844, lo: 0x83, hi: 0x84}, + {value: 0x284e, lo: 0x85, hi: 0x86}, + {value: 0x283a, lo: 0x87, hi: 0x87}, + {value: 0x2858, lo: 0x88, hi: 0x88}, + {value: 0x0b6f, lo: 0x90, hi: 0x90}, + {value: 0x08e7, lo: 0x91, hi: 0x91}, +} + +// recompMap: 7520 bytes (entries only) +var recompMap = map[uint32]rune{ + 0x00410300: 0x00C0, + 0x00410301: 0x00C1, + 0x00410302: 0x00C2, + 0x00410303: 0x00C3, + 0x00410308: 0x00C4, + 0x0041030A: 0x00C5, + 0x00430327: 0x00C7, + 0x00450300: 0x00C8, + 0x00450301: 0x00C9, + 0x00450302: 0x00CA, + 0x00450308: 0x00CB, + 0x00490300: 0x00CC, + 0x00490301: 0x00CD, + 0x00490302: 0x00CE, + 0x00490308: 0x00CF, + 0x004E0303: 0x00D1, + 0x004F0300: 0x00D2, + 0x004F0301: 0x00D3, + 0x004F0302: 0x00D4, + 0x004F0303: 0x00D5, + 0x004F0308: 0x00D6, + 0x00550300: 0x00D9, + 0x00550301: 0x00DA, + 0x00550302: 0x00DB, + 0x00550308: 0x00DC, + 0x00590301: 0x00DD, + 0x00610300: 0x00E0, + 0x00610301: 0x00E1, + 0x00610302: 0x00E2, + 0x00610303: 0x00E3, + 0x00610308: 0x00E4, + 0x0061030A: 0x00E5, + 0x00630327: 0x00E7, + 0x00650300: 0x00E8, + 0x00650301: 0x00E9, + 0x00650302: 0x00EA, + 0x00650308: 0x00EB, + 0x00690300: 0x00EC, + 0x00690301: 0x00ED, + 0x00690302: 0x00EE, + 0x00690308: 0x00EF, + 0x006E0303: 0x00F1, + 0x006F0300: 0x00F2, + 0x006F0301: 0x00F3, + 0x006F0302: 0x00F4, + 0x006F0303: 0x00F5, + 0x006F0308: 0x00F6, + 0x00750300: 0x00F9, + 0x00750301: 0x00FA, + 0x00750302: 0x00FB, + 0x00750308: 0x00FC, + 0x00790301: 0x00FD, + 0x00790308: 0x00FF, + 0x00410304: 0x0100, + 0x00610304: 0x0101, + 0x00410306: 0x0102, + 0x00610306: 0x0103, + 0x00410328: 0x0104, + 0x00610328: 0x0105, + 0x00430301: 0x0106, + 0x00630301: 0x0107, + 0x00430302: 0x0108, + 0x00630302: 0x0109, + 0x00430307: 0x010A, + 0x00630307: 0x010B, + 0x0043030C: 0x010C, + 0x0063030C: 0x010D, + 0x0044030C: 0x010E, + 0x0064030C: 0x010F, + 0x00450304: 0x0112, + 0x00650304: 0x0113, + 0x00450306: 0x0114, + 0x00650306: 0x0115, + 0x00450307: 0x0116, + 0x00650307: 0x0117, + 0x00450328: 0x0118, + 0x00650328: 0x0119, + 0x0045030C: 0x011A, + 0x0065030C: 0x011B, + 0x00470302: 0x011C, + 0x00670302: 0x011D, + 0x00470306: 0x011E, + 0x00670306: 0x011F, + 0x00470307: 0x0120, + 0x00670307: 0x0121, + 0x00470327: 0x0122, + 0x00670327: 0x0123, + 0x00480302: 0x0124, + 0x00680302: 0x0125, + 0x00490303: 0x0128, + 0x00690303: 0x0129, + 0x00490304: 0x012A, + 0x00690304: 0x012B, + 0x00490306: 0x012C, + 0x00690306: 0x012D, + 0x00490328: 0x012E, + 0x00690328: 0x012F, + 0x00490307: 0x0130, + 0x004A0302: 0x0134, + 0x006A0302: 0x0135, + 0x004B0327: 0x0136, + 0x006B0327: 0x0137, + 0x004C0301: 0x0139, + 0x006C0301: 0x013A, + 0x004C0327: 0x013B, + 0x006C0327: 0x013C, + 0x004C030C: 0x013D, + 0x006C030C: 0x013E, + 0x004E0301: 0x0143, + 0x006E0301: 0x0144, + 0x004E0327: 0x0145, + 0x006E0327: 0x0146, + 0x004E030C: 0x0147, + 0x006E030C: 0x0148, + 0x004F0304: 0x014C, + 0x006F0304: 0x014D, + 0x004F0306: 0x014E, + 0x006F0306: 0x014F, + 0x004F030B: 0x0150, + 0x006F030B: 0x0151, + 0x00520301: 0x0154, + 0x00720301: 0x0155, + 0x00520327: 0x0156, + 0x00720327: 0x0157, + 0x0052030C: 0x0158, + 0x0072030C: 0x0159, + 0x00530301: 0x015A, + 0x00730301: 0x015B, + 0x00530302: 0x015C, + 0x00730302: 0x015D, + 0x00530327: 0x015E, + 0x00730327: 0x015F, + 0x0053030C: 0x0160, + 0x0073030C: 0x0161, + 0x00540327: 0x0162, + 0x00740327: 0x0163, + 0x0054030C: 0x0164, + 0x0074030C: 0x0165, + 0x00550303: 0x0168, + 0x00750303: 0x0169, + 0x00550304: 0x016A, + 0x00750304: 0x016B, + 0x00550306: 0x016C, + 0x00750306: 0x016D, + 0x0055030A: 0x016E, + 0x0075030A: 0x016F, + 0x0055030B: 0x0170, + 0x0075030B: 0x0171, + 0x00550328: 0x0172, + 0x00750328: 0x0173, + 0x00570302: 0x0174, + 0x00770302: 0x0175, + 0x00590302: 0x0176, + 0x00790302: 0x0177, + 0x00590308: 0x0178, + 0x005A0301: 0x0179, + 0x007A0301: 0x017A, + 0x005A0307: 0x017B, + 0x007A0307: 0x017C, + 0x005A030C: 0x017D, + 0x007A030C: 0x017E, + 0x004F031B: 0x01A0, + 0x006F031B: 0x01A1, + 0x0055031B: 0x01AF, + 0x0075031B: 0x01B0, + 0x0041030C: 0x01CD, + 0x0061030C: 0x01CE, + 0x0049030C: 0x01CF, + 0x0069030C: 0x01D0, + 0x004F030C: 0x01D1, + 0x006F030C: 0x01D2, + 0x0055030C: 0x01D3, + 0x0075030C: 0x01D4, + 0x00DC0304: 0x01D5, + 0x00FC0304: 0x01D6, + 0x00DC0301: 0x01D7, + 0x00FC0301: 0x01D8, + 0x00DC030C: 0x01D9, + 0x00FC030C: 0x01DA, + 0x00DC0300: 0x01DB, + 0x00FC0300: 0x01DC, + 0x00C40304: 0x01DE, + 0x00E40304: 0x01DF, + 0x02260304: 0x01E0, + 0x02270304: 0x01E1, + 0x00C60304: 0x01E2, + 0x00E60304: 0x01E3, + 0x0047030C: 0x01E6, + 0x0067030C: 0x01E7, + 0x004B030C: 0x01E8, + 0x006B030C: 0x01E9, + 0x004F0328: 0x01EA, + 0x006F0328: 0x01EB, + 0x01EA0304: 0x01EC, + 0x01EB0304: 0x01ED, + 0x01B7030C: 0x01EE, + 0x0292030C: 0x01EF, + 0x006A030C: 0x01F0, + 0x00470301: 0x01F4, + 0x00670301: 0x01F5, + 0x004E0300: 0x01F8, + 0x006E0300: 0x01F9, + 0x00C50301: 0x01FA, + 0x00E50301: 0x01FB, + 0x00C60301: 0x01FC, + 0x00E60301: 0x01FD, + 0x00D80301: 0x01FE, + 0x00F80301: 0x01FF, + 0x0041030F: 0x0200, + 0x0061030F: 0x0201, + 0x00410311: 0x0202, + 0x00610311: 0x0203, + 0x0045030F: 0x0204, + 0x0065030F: 0x0205, + 0x00450311: 0x0206, + 0x00650311: 0x0207, + 0x0049030F: 0x0208, + 0x0069030F: 0x0209, + 0x00490311: 0x020A, + 0x00690311: 0x020B, + 0x004F030F: 0x020C, + 0x006F030F: 0x020D, + 0x004F0311: 0x020E, + 0x006F0311: 0x020F, + 0x0052030F: 0x0210, + 0x0072030F: 0x0211, + 0x00520311: 0x0212, + 0x00720311: 0x0213, + 0x0055030F: 0x0214, + 0x0075030F: 0x0215, + 0x00550311: 0x0216, + 0x00750311: 0x0217, + 0x00530326: 0x0218, + 0x00730326: 0x0219, + 0x00540326: 0x021A, + 0x00740326: 0x021B, + 0x0048030C: 0x021E, + 0x0068030C: 0x021F, + 0x00410307: 0x0226, + 0x00610307: 0x0227, + 0x00450327: 0x0228, + 0x00650327: 0x0229, + 0x00D60304: 0x022A, + 0x00F60304: 0x022B, + 0x00D50304: 0x022C, + 0x00F50304: 0x022D, + 0x004F0307: 0x022E, + 0x006F0307: 0x022F, + 0x022E0304: 0x0230, + 0x022F0304: 0x0231, + 0x00590304: 0x0232, + 0x00790304: 0x0233, + 0x00A80301: 0x0385, + 0x03910301: 0x0386, + 0x03950301: 0x0388, + 0x03970301: 0x0389, + 0x03990301: 0x038A, + 0x039F0301: 0x038C, + 0x03A50301: 0x038E, + 0x03A90301: 0x038F, + 0x03CA0301: 0x0390, + 0x03990308: 0x03AA, + 0x03A50308: 0x03AB, + 0x03B10301: 0x03AC, + 0x03B50301: 0x03AD, + 0x03B70301: 0x03AE, + 0x03B90301: 0x03AF, + 0x03CB0301: 0x03B0, + 0x03B90308: 0x03CA, + 0x03C50308: 0x03CB, + 0x03BF0301: 0x03CC, + 0x03C50301: 0x03CD, + 0x03C90301: 0x03CE, + 0x03D20301: 0x03D3, + 0x03D20308: 0x03D4, + 0x04150300: 0x0400, + 0x04150308: 0x0401, + 0x04130301: 0x0403, + 0x04060308: 0x0407, + 0x041A0301: 0x040C, + 0x04180300: 0x040D, + 0x04230306: 0x040E, + 0x04180306: 0x0419, + 0x04380306: 0x0439, + 0x04350300: 0x0450, + 0x04350308: 0x0451, + 0x04330301: 0x0453, + 0x04560308: 0x0457, + 0x043A0301: 0x045C, + 0x04380300: 0x045D, + 0x04430306: 0x045E, + 0x0474030F: 0x0476, + 0x0475030F: 0x0477, + 0x04160306: 0x04C1, + 0x04360306: 0x04C2, + 0x04100306: 0x04D0, + 0x04300306: 0x04D1, + 0x04100308: 0x04D2, + 0x04300308: 0x04D3, + 0x04150306: 0x04D6, + 0x04350306: 0x04D7, + 0x04D80308: 0x04DA, + 0x04D90308: 0x04DB, + 0x04160308: 0x04DC, + 0x04360308: 0x04DD, + 0x04170308: 0x04DE, + 0x04370308: 0x04DF, + 0x04180304: 0x04E2, + 0x04380304: 0x04E3, + 0x04180308: 0x04E4, + 0x04380308: 0x04E5, + 0x041E0308: 0x04E6, + 0x043E0308: 0x04E7, + 0x04E80308: 0x04EA, + 0x04E90308: 0x04EB, + 0x042D0308: 0x04EC, + 0x044D0308: 0x04ED, + 0x04230304: 0x04EE, + 0x04430304: 0x04EF, + 0x04230308: 0x04F0, + 0x04430308: 0x04F1, + 0x0423030B: 0x04F2, + 0x0443030B: 0x04F3, + 0x04270308: 0x04F4, + 0x04470308: 0x04F5, + 0x042B0308: 0x04F8, + 0x044B0308: 0x04F9, + 0x06270653: 0x0622, + 0x06270654: 0x0623, + 0x06480654: 0x0624, + 0x06270655: 0x0625, + 0x064A0654: 0x0626, + 0x06D50654: 0x06C0, + 0x06C10654: 0x06C2, + 0x06D20654: 0x06D3, + 0x0928093C: 0x0929, + 0x0930093C: 0x0931, + 0x0933093C: 0x0934, + 0x09C709BE: 0x09CB, + 0x09C709D7: 0x09CC, + 0x0B470B56: 0x0B48, + 0x0B470B3E: 0x0B4B, + 0x0B470B57: 0x0B4C, + 0x0B920BD7: 0x0B94, + 0x0BC60BBE: 0x0BCA, + 0x0BC70BBE: 0x0BCB, + 0x0BC60BD7: 0x0BCC, + 0x0C460C56: 0x0C48, + 0x0CBF0CD5: 0x0CC0, + 0x0CC60CD5: 0x0CC7, + 0x0CC60CD6: 0x0CC8, + 0x0CC60CC2: 0x0CCA, + 0x0CCA0CD5: 0x0CCB, + 0x0D460D3E: 0x0D4A, + 0x0D470D3E: 0x0D4B, + 0x0D460D57: 0x0D4C, + 0x0DD90DCA: 0x0DDA, + 0x0DD90DCF: 0x0DDC, + 0x0DDC0DCA: 0x0DDD, + 0x0DD90DDF: 0x0DDE, + 0x1025102E: 0x1026, + 0x1B051B35: 0x1B06, + 0x1B071B35: 0x1B08, + 0x1B091B35: 0x1B0A, + 0x1B0B1B35: 0x1B0C, + 0x1B0D1B35: 0x1B0E, + 0x1B111B35: 0x1B12, + 0x1B3A1B35: 0x1B3B, + 0x1B3C1B35: 0x1B3D, + 0x1B3E1B35: 0x1B40, + 0x1B3F1B35: 0x1B41, + 0x1B421B35: 0x1B43, + 0x00410325: 0x1E00, + 0x00610325: 0x1E01, + 0x00420307: 0x1E02, + 0x00620307: 0x1E03, + 0x00420323: 0x1E04, + 0x00620323: 0x1E05, + 0x00420331: 0x1E06, + 0x00620331: 0x1E07, + 0x00C70301: 0x1E08, + 0x00E70301: 0x1E09, + 0x00440307: 0x1E0A, + 0x00640307: 0x1E0B, + 0x00440323: 0x1E0C, + 0x00640323: 0x1E0D, + 0x00440331: 0x1E0E, + 0x00640331: 0x1E0F, + 0x00440327: 0x1E10, + 0x00640327: 0x1E11, + 0x0044032D: 0x1E12, + 0x0064032D: 0x1E13, + 0x01120300: 0x1E14, + 0x01130300: 0x1E15, + 0x01120301: 0x1E16, + 0x01130301: 0x1E17, + 0x0045032D: 0x1E18, + 0x0065032D: 0x1E19, + 0x00450330: 0x1E1A, + 0x00650330: 0x1E1B, + 0x02280306: 0x1E1C, + 0x02290306: 0x1E1D, + 0x00460307: 0x1E1E, + 0x00660307: 0x1E1F, + 0x00470304: 0x1E20, + 0x00670304: 0x1E21, + 0x00480307: 0x1E22, + 0x00680307: 0x1E23, + 0x00480323: 0x1E24, + 0x00680323: 0x1E25, + 0x00480308: 0x1E26, + 0x00680308: 0x1E27, + 0x00480327: 0x1E28, + 0x00680327: 0x1E29, + 0x0048032E: 0x1E2A, + 0x0068032E: 0x1E2B, + 0x00490330: 0x1E2C, + 0x00690330: 0x1E2D, + 0x00CF0301: 0x1E2E, + 0x00EF0301: 0x1E2F, + 0x004B0301: 0x1E30, + 0x006B0301: 0x1E31, + 0x004B0323: 0x1E32, + 0x006B0323: 0x1E33, + 0x004B0331: 0x1E34, + 0x006B0331: 0x1E35, + 0x004C0323: 0x1E36, + 0x006C0323: 0x1E37, + 0x1E360304: 0x1E38, + 0x1E370304: 0x1E39, + 0x004C0331: 0x1E3A, + 0x006C0331: 0x1E3B, + 0x004C032D: 0x1E3C, + 0x006C032D: 0x1E3D, + 0x004D0301: 0x1E3E, + 0x006D0301: 0x1E3F, + 0x004D0307: 0x1E40, + 0x006D0307: 0x1E41, + 0x004D0323: 0x1E42, + 0x006D0323: 0x1E43, + 0x004E0307: 0x1E44, + 0x006E0307: 0x1E45, + 0x004E0323: 0x1E46, + 0x006E0323: 0x1E47, + 0x004E0331: 0x1E48, + 0x006E0331: 0x1E49, + 0x004E032D: 0x1E4A, + 0x006E032D: 0x1E4B, + 0x00D50301: 0x1E4C, + 0x00F50301: 0x1E4D, + 0x00D50308: 0x1E4E, + 0x00F50308: 0x1E4F, + 0x014C0300: 0x1E50, + 0x014D0300: 0x1E51, + 0x014C0301: 0x1E52, + 0x014D0301: 0x1E53, + 0x00500301: 0x1E54, + 0x00700301: 0x1E55, + 0x00500307: 0x1E56, + 0x00700307: 0x1E57, + 0x00520307: 0x1E58, + 0x00720307: 0x1E59, + 0x00520323: 0x1E5A, + 0x00720323: 0x1E5B, + 0x1E5A0304: 0x1E5C, + 0x1E5B0304: 0x1E5D, + 0x00520331: 0x1E5E, + 0x00720331: 0x1E5F, + 0x00530307: 0x1E60, + 0x00730307: 0x1E61, + 0x00530323: 0x1E62, + 0x00730323: 0x1E63, + 0x015A0307: 0x1E64, + 0x015B0307: 0x1E65, + 0x01600307: 0x1E66, + 0x01610307: 0x1E67, + 0x1E620307: 0x1E68, + 0x1E630307: 0x1E69, + 0x00540307: 0x1E6A, + 0x00740307: 0x1E6B, + 0x00540323: 0x1E6C, + 0x00740323: 0x1E6D, + 0x00540331: 0x1E6E, + 0x00740331: 0x1E6F, + 0x0054032D: 0x1E70, + 0x0074032D: 0x1E71, + 0x00550324: 0x1E72, + 0x00750324: 0x1E73, + 0x00550330: 0x1E74, + 0x00750330: 0x1E75, + 0x0055032D: 0x1E76, + 0x0075032D: 0x1E77, + 0x01680301: 0x1E78, + 0x01690301: 0x1E79, + 0x016A0308: 0x1E7A, + 0x016B0308: 0x1E7B, + 0x00560303: 0x1E7C, + 0x00760303: 0x1E7D, + 0x00560323: 0x1E7E, + 0x00760323: 0x1E7F, + 0x00570300: 0x1E80, + 0x00770300: 0x1E81, + 0x00570301: 0x1E82, + 0x00770301: 0x1E83, + 0x00570308: 0x1E84, + 0x00770308: 0x1E85, + 0x00570307: 0x1E86, + 0x00770307: 0x1E87, + 0x00570323: 0x1E88, + 0x00770323: 0x1E89, + 0x00580307: 0x1E8A, + 0x00780307: 0x1E8B, + 0x00580308: 0x1E8C, + 0x00780308: 0x1E8D, + 0x00590307: 0x1E8E, + 0x00790307: 0x1E8F, + 0x005A0302: 0x1E90, + 0x007A0302: 0x1E91, + 0x005A0323: 0x1E92, + 0x007A0323: 0x1E93, + 0x005A0331: 0x1E94, + 0x007A0331: 0x1E95, + 0x00680331: 0x1E96, + 0x00740308: 0x1E97, + 0x0077030A: 0x1E98, + 0x0079030A: 0x1E99, + 0x017F0307: 0x1E9B, + 0x00410323: 0x1EA0, + 0x00610323: 0x1EA1, + 0x00410309: 0x1EA2, + 0x00610309: 0x1EA3, + 0x00C20301: 0x1EA4, + 0x00E20301: 0x1EA5, + 0x00C20300: 0x1EA6, + 0x00E20300: 0x1EA7, + 0x00C20309: 0x1EA8, + 0x00E20309: 0x1EA9, + 0x00C20303: 0x1EAA, + 0x00E20303: 0x1EAB, + 0x1EA00302: 0x1EAC, + 0x1EA10302: 0x1EAD, + 0x01020301: 0x1EAE, + 0x01030301: 0x1EAF, + 0x01020300: 0x1EB0, + 0x01030300: 0x1EB1, + 0x01020309: 0x1EB2, + 0x01030309: 0x1EB3, + 0x01020303: 0x1EB4, + 0x01030303: 0x1EB5, + 0x1EA00306: 0x1EB6, + 0x1EA10306: 0x1EB7, + 0x00450323: 0x1EB8, + 0x00650323: 0x1EB9, + 0x00450309: 0x1EBA, + 0x00650309: 0x1EBB, + 0x00450303: 0x1EBC, + 0x00650303: 0x1EBD, + 0x00CA0301: 0x1EBE, + 0x00EA0301: 0x1EBF, + 0x00CA0300: 0x1EC0, + 0x00EA0300: 0x1EC1, + 0x00CA0309: 0x1EC2, + 0x00EA0309: 0x1EC3, + 0x00CA0303: 0x1EC4, + 0x00EA0303: 0x1EC5, + 0x1EB80302: 0x1EC6, + 0x1EB90302: 0x1EC7, + 0x00490309: 0x1EC8, + 0x00690309: 0x1EC9, + 0x00490323: 0x1ECA, + 0x00690323: 0x1ECB, + 0x004F0323: 0x1ECC, + 0x006F0323: 0x1ECD, + 0x004F0309: 0x1ECE, + 0x006F0309: 0x1ECF, + 0x00D40301: 0x1ED0, + 0x00F40301: 0x1ED1, + 0x00D40300: 0x1ED2, + 0x00F40300: 0x1ED3, + 0x00D40309: 0x1ED4, + 0x00F40309: 0x1ED5, + 0x00D40303: 0x1ED6, + 0x00F40303: 0x1ED7, + 0x1ECC0302: 0x1ED8, + 0x1ECD0302: 0x1ED9, + 0x01A00301: 0x1EDA, + 0x01A10301: 0x1EDB, + 0x01A00300: 0x1EDC, + 0x01A10300: 0x1EDD, + 0x01A00309: 0x1EDE, + 0x01A10309: 0x1EDF, + 0x01A00303: 0x1EE0, + 0x01A10303: 0x1EE1, + 0x01A00323: 0x1EE2, + 0x01A10323: 0x1EE3, + 0x00550323: 0x1EE4, + 0x00750323: 0x1EE5, + 0x00550309: 0x1EE6, + 0x00750309: 0x1EE7, + 0x01AF0301: 0x1EE8, + 0x01B00301: 0x1EE9, + 0x01AF0300: 0x1EEA, + 0x01B00300: 0x1EEB, + 0x01AF0309: 0x1EEC, + 0x01B00309: 0x1EED, + 0x01AF0303: 0x1EEE, + 0x01B00303: 0x1EEF, + 0x01AF0323: 0x1EF0, + 0x01B00323: 0x1EF1, + 0x00590300: 0x1EF2, + 0x00790300: 0x1EF3, + 0x00590323: 0x1EF4, + 0x00790323: 0x1EF5, + 0x00590309: 0x1EF6, + 0x00790309: 0x1EF7, + 0x00590303: 0x1EF8, + 0x00790303: 0x1EF9, + 0x03B10313: 0x1F00, + 0x03B10314: 0x1F01, + 0x1F000300: 0x1F02, + 0x1F010300: 0x1F03, + 0x1F000301: 0x1F04, + 0x1F010301: 0x1F05, + 0x1F000342: 0x1F06, + 0x1F010342: 0x1F07, + 0x03910313: 0x1F08, + 0x03910314: 0x1F09, + 0x1F080300: 0x1F0A, + 0x1F090300: 0x1F0B, + 0x1F080301: 0x1F0C, + 0x1F090301: 0x1F0D, + 0x1F080342: 0x1F0E, + 0x1F090342: 0x1F0F, + 0x03B50313: 0x1F10, + 0x03B50314: 0x1F11, + 0x1F100300: 0x1F12, + 0x1F110300: 0x1F13, + 0x1F100301: 0x1F14, + 0x1F110301: 0x1F15, + 0x03950313: 0x1F18, + 0x03950314: 0x1F19, + 0x1F180300: 0x1F1A, + 0x1F190300: 0x1F1B, + 0x1F180301: 0x1F1C, + 0x1F190301: 0x1F1D, + 0x03B70313: 0x1F20, + 0x03B70314: 0x1F21, + 0x1F200300: 0x1F22, + 0x1F210300: 0x1F23, + 0x1F200301: 0x1F24, + 0x1F210301: 0x1F25, + 0x1F200342: 0x1F26, + 0x1F210342: 0x1F27, + 0x03970313: 0x1F28, + 0x03970314: 0x1F29, + 0x1F280300: 0x1F2A, + 0x1F290300: 0x1F2B, + 0x1F280301: 0x1F2C, + 0x1F290301: 0x1F2D, + 0x1F280342: 0x1F2E, + 0x1F290342: 0x1F2F, + 0x03B90313: 0x1F30, + 0x03B90314: 0x1F31, + 0x1F300300: 0x1F32, + 0x1F310300: 0x1F33, + 0x1F300301: 0x1F34, + 0x1F310301: 0x1F35, + 0x1F300342: 0x1F36, + 0x1F310342: 0x1F37, + 0x03990313: 0x1F38, + 0x03990314: 0x1F39, + 0x1F380300: 0x1F3A, + 0x1F390300: 0x1F3B, + 0x1F380301: 0x1F3C, + 0x1F390301: 0x1F3D, + 0x1F380342: 0x1F3E, + 0x1F390342: 0x1F3F, + 0x03BF0313: 0x1F40, + 0x03BF0314: 0x1F41, + 0x1F400300: 0x1F42, + 0x1F410300: 0x1F43, + 0x1F400301: 0x1F44, + 0x1F410301: 0x1F45, + 0x039F0313: 0x1F48, + 0x039F0314: 0x1F49, + 0x1F480300: 0x1F4A, + 0x1F490300: 0x1F4B, + 0x1F480301: 0x1F4C, + 0x1F490301: 0x1F4D, + 0x03C50313: 0x1F50, + 0x03C50314: 0x1F51, + 0x1F500300: 0x1F52, + 0x1F510300: 0x1F53, + 0x1F500301: 0x1F54, + 0x1F510301: 0x1F55, + 0x1F500342: 0x1F56, + 0x1F510342: 0x1F57, + 0x03A50314: 0x1F59, + 0x1F590300: 0x1F5B, + 0x1F590301: 0x1F5D, + 0x1F590342: 0x1F5F, + 0x03C90313: 0x1F60, + 0x03C90314: 0x1F61, + 0x1F600300: 0x1F62, + 0x1F610300: 0x1F63, + 0x1F600301: 0x1F64, + 0x1F610301: 0x1F65, + 0x1F600342: 0x1F66, + 0x1F610342: 0x1F67, + 0x03A90313: 0x1F68, + 0x03A90314: 0x1F69, + 0x1F680300: 0x1F6A, + 0x1F690300: 0x1F6B, + 0x1F680301: 0x1F6C, + 0x1F690301: 0x1F6D, + 0x1F680342: 0x1F6E, + 0x1F690342: 0x1F6F, + 0x03B10300: 0x1F70, + 0x03B50300: 0x1F72, + 0x03B70300: 0x1F74, + 0x03B90300: 0x1F76, + 0x03BF0300: 0x1F78, + 0x03C50300: 0x1F7A, + 0x03C90300: 0x1F7C, + 0x1F000345: 0x1F80, + 0x1F010345: 0x1F81, + 0x1F020345: 0x1F82, + 0x1F030345: 0x1F83, + 0x1F040345: 0x1F84, + 0x1F050345: 0x1F85, + 0x1F060345: 0x1F86, + 0x1F070345: 0x1F87, + 0x1F080345: 0x1F88, + 0x1F090345: 0x1F89, + 0x1F0A0345: 0x1F8A, + 0x1F0B0345: 0x1F8B, + 0x1F0C0345: 0x1F8C, + 0x1F0D0345: 0x1F8D, + 0x1F0E0345: 0x1F8E, + 0x1F0F0345: 0x1F8F, + 0x1F200345: 0x1F90, + 0x1F210345: 0x1F91, + 0x1F220345: 0x1F92, + 0x1F230345: 0x1F93, + 0x1F240345: 0x1F94, + 0x1F250345: 0x1F95, + 0x1F260345: 0x1F96, + 0x1F270345: 0x1F97, + 0x1F280345: 0x1F98, + 0x1F290345: 0x1F99, + 0x1F2A0345: 0x1F9A, + 0x1F2B0345: 0x1F9B, + 0x1F2C0345: 0x1F9C, + 0x1F2D0345: 0x1F9D, + 0x1F2E0345: 0x1F9E, + 0x1F2F0345: 0x1F9F, + 0x1F600345: 0x1FA0, + 0x1F610345: 0x1FA1, + 0x1F620345: 0x1FA2, + 0x1F630345: 0x1FA3, + 0x1F640345: 0x1FA4, + 0x1F650345: 0x1FA5, + 0x1F660345: 0x1FA6, + 0x1F670345: 0x1FA7, + 0x1F680345: 0x1FA8, + 0x1F690345: 0x1FA9, + 0x1F6A0345: 0x1FAA, + 0x1F6B0345: 0x1FAB, + 0x1F6C0345: 0x1FAC, + 0x1F6D0345: 0x1FAD, + 0x1F6E0345: 0x1FAE, + 0x1F6F0345: 0x1FAF, + 0x03B10306: 0x1FB0, + 0x03B10304: 0x1FB1, + 0x1F700345: 0x1FB2, + 0x03B10345: 0x1FB3, + 0x03AC0345: 0x1FB4, + 0x03B10342: 0x1FB6, + 0x1FB60345: 0x1FB7, + 0x03910306: 0x1FB8, + 0x03910304: 0x1FB9, + 0x03910300: 0x1FBA, + 0x03910345: 0x1FBC, + 0x00A80342: 0x1FC1, + 0x1F740345: 0x1FC2, + 0x03B70345: 0x1FC3, + 0x03AE0345: 0x1FC4, + 0x03B70342: 0x1FC6, + 0x1FC60345: 0x1FC7, + 0x03950300: 0x1FC8, + 0x03970300: 0x1FCA, + 0x03970345: 0x1FCC, + 0x1FBF0300: 0x1FCD, + 0x1FBF0301: 0x1FCE, + 0x1FBF0342: 0x1FCF, + 0x03B90306: 0x1FD0, + 0x03B90304: 0x1FD1, + 0x03CA0300: 0x1FD2, + 0x03B90342: 0x1FD6, + 0x03CA0342: 0x1FD7, + 0x03990306: 0x1FD8, + 0x03990304: 0x1FD9, + 0x03990300: 0x1FDA, + 0x1FFE0300: 0x1FDD, + 0x1FFE0301: 0x1FDE, + 0x1FFE0342: 0x1FDF, + 0x03C50306: 0x1FE0, + 0x03C50304: 0x1FE1, + 0x03CB0300: 0x1FE2, + 0x03C10313: 0x1FE4, + 0x03C10314: 0x1FE5, + 0x03C50342: 0x1FE6, + 0x03CB0342: 0x1FE7, + 0x03A50306: 0x1FE8, + 0x03A50304: 0x1FE9, + 0x03A50300: 0x1FEA, + 0x03A10314: 0x1FEC, + 0x00A80300: 0x1FED, + 0x1F7C0345: 0x1FF2, + 0x03C90345: 0x1FF3, + 0x03CE0345: 0x1FF4, + 0x03C90342: 0x1FF6, + 0x1FF60345: 0x1FF7, + 0x039F0300: 0x1FF8, + 0x03A90300: 0x1FFA, + 0x03A90345: 0x1FFC, + 0x21900338: 0x219A, + 0x21920338: 0x219B, + 0x21940338: 0x21AE, + 0x21D00338: 0x21CD, + 0x21D40338: 0x21CE, + 0x21D20338: 0x21CF, + 0x22030338: 0x2204, + 0x22080338: 0x2209, + 0x220B0338: 0x220C, + 0x22230338: 0x2224, + 0x22250338: 0x2226, + 0x223C0338: 0x2241, + 0x22430338: 0x2244, + 0x22450338: 0x2247, + 0x22480338: 0x2249, + 0x003D0338: 0x2260, + 0x22610338: 0x2262, + 0x224D0338: 0x226D, + 0x003C0338: 0x226E, + 0x003E0338: 0x226F, + 0x22640338: 0x2270, + 0x22650338: 0x2271, + 0x22720338: 0x2274, + 0x22730338: 0x2275, + 0x22760338: 0x2278, + 0x22770338: 0x2279, + 0x227A0338: 0x2280, + 0x227B0338: 0x2281, + 0x22820338: 0x2284, + 0x22830338: 0x2285, + 0x22860338: 0x2288, + 0x22870338: 0x2289, + 0x22A20338: 0x22AC, + 0x22A80338: 0x22AD, + 0x22A90338: 0x22AE, + 0x22AB0338: 0x22AF, + 0x227C0338: 0x22E0, + 0x227D0338: 0x22E1, + 0x22910338: 0x22E2, + 0x22920338: 0x22E3, + 0x22B20338: 0x22EA, + 0x22B30338: 0x22EB, + 0x22B40338: 0x22EC, + 0x22B50338: 0x22ED, + 0x304B3099: 0x304C, + 0x304D3099: 0x304E, + 0x304F3099: 0x3050, + 0x30513099: 0x3052, + 0x30533099: 0x3054, + 0x30553099: 0x3056, + 0x30573099: 0x3058, + 0x30593099: 0x305A, + 0x305B3099: 0x305C, + 0x305D3099: 0x305E, + 0x305F3099: 0x3060, + 0x30613099: 0x3062, + 0x30643099: 0x3065, + 0x30663099: 0x3067, + 0x30683099: 0x3069, + 0x306F3099: 0x3070, + 0x306F309A: 0x3071, + 0x30723099: 0x3073, + 0x3072309A: 0x3074, + 0x30753099: 0x3076, + 0x3075309A: 0x3077, + 0x30783099: 0x3079, + 0x3078309A: 0x307A, + 0x307B3099: 0x307C, + 0x307B309A: 0x307D, + 0x30463099: 0x3094, + 0x309D3099: 0x309E, + 0x30AB3099: 0x30AC, + 0x30AD3099: 0x30AE, + 0x30AF3099: 0x30B0, + 0x30B13099: 0x30B2, + 0x30B33099: 0x30B4, + 0x30B53099: 0x30B6, + 0x30B73099: 0x30B8, + 0x30B93099: 0x30BA, + 0x30BB3099: 0x30BC, + 0x30BD3099: 0x30BE, + 0x30BF3099: 0x30C0, + 0x30C13099: 0x30C2, + 0x30C43099: 0x30C5, + 0x30C63099: 0x30C7, + 0x30C83099: 0x30C9, + 0x30CF3099: 0x30D0, + 0x30CF309A: 0x30D1, + 0x30D23099: 0x30D3, + 0x30D2309A: 0x30D4, + 0x30D53099: 0x30D6, + 0x30D5309A: 0x30D7, + 0x30D83099: 0x30D9, + 0x30D8309A: 0x30DA, + 0x30DB3099: 0x30DC, + 0x30DB309A: 0x30DD, + 0x30A63099: 0x30F4, + 0x30EF3099: 0x30F7, + 0x30F03099: 0x30F8, + 0x30F13099: 0x30F9, + 0x30F23099: 0x30FA, + 0x30FD3099: 0x30FE, + 0x109910BA: 0x1109A, + 0x109B10BA: 0x1109C, + 0x10A510BA: 0x110AB, + 0x11311127: 0x1112E, + 0x11321127: 0x1112F, + 0x1347133E: 0x1134B, + 0x13471357: 0x1134C, + 0x14B914BA: 0x114BB, + 0x14B914B0: 0x114BC, + 0x14B914BD: 0x114BE, + 0x15B815AF: 0x115BA, + 0x15B915AF: 0x115BB, +} + +// Total size of tables: 53KB (54226 bytes) diff --git a/vendor/golang.org/x/text/unicode/norm/tables9.0.0.go b/vendor/golang.org/x/text/unicode/norm/tables9.0.0.go new file mode 100644 index 0000000000..a01274a8e8 --- /dev/null +++ b/vendor/golang.org/x/text/unicode/norm/tables9.0.0.go @@ -0,0 +1,7633 @@ +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. + +// +build !go1.10 + +package norm + +const ( + // Version is the Unicode edition from which the tables are derived. + Version = "9.0.0" + + // MaxTransformChunkSize indicates the maximum number of bytes that Transform + // may need to write atomically for any Form. Making a destination buffer at + // least this size ensures that Transform can always make progress and that + // the user does not need to grow the buffer on an ErrShortDst. + MaxTransformChunkSize = 35 + maxNonStarters*4 +) + +var ccc = [55]uint8{ + 0, 1, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, + 84, 91, 103, 107, 118, 122, 129, 130, + 132, 202, 214, 216, 218, 220, 222, 224, + 226, 228, 230, 232, 233, 234, 240, +} + +const ( + firstMulti = 0x186D + firstCCC = 0x2C9E + endMulti = 0x2F60 + firstLeadingCCC = 0x49AE + firstCCCZeroExcept = 0x4A78 + firstStarterWithNLead = 0x4A9F + lastDecomp = 0x4AA1 + maxDecomp = 0x8000 +) + +// decomps: 19105 bytes +var decomps = [...]byte{ + // Bytes 0 - 3f + 0x00, 0x41, 0x20, 0x41, 0x21, 0x41, 0x22, 0x41, + 0x23, 0x41, 0x24, 0x41, 0x25, 0x41, 0x26, 0x41, + 0x27, 0x41, 0x28, 0x41, 0x29, 0x41, 0x2A, 0x41, + 0x2B, 0x41, 0x2C, 0x41, 0x2D, 0x41, 0x2E, 0x41, + 0x2F, 0x41, 0x30, 0x41, 0x31, 0x41, 0x32, 0x41, + 0x33, 0x41, 0x34, 0x41, 0x35, 0x41, 0x36, 0x41, + 0x37, 0x41, 0x38, 0x41, 0x39, 0x41, 0x3A, 0x41, + 0x3B, 0x41, 0x3C, 0x41, 0x3D, 0x41, 0x3E, 0x41, + // Bytes 40 - 7f + 0x3F, 0x41, 0x40, 0x41, 0x41, 0x41, 0x42, 0x41, + 0x43, 0x41, 0x44, 0x41, 0x45, 0x41, 0x46, 0x41, + 0x47, 0x41, 0x48, 0x41, 0x49, 0x41, 0x4A, 0x41, + 0x4B, 0x41, 0x4C, 0x41, 0x4D, 0x41, 0x4E, 0x41, + 0x4F, 0x41, 0x50, 0x41, 0x51, 0x41, 0x52, 0x41, + 0x53, 0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x41, + 0x57, 0x41, 0x58, 0x41, 0x59, 0x41, 0x5A, 0x41, + 0x5B, 0x41, 0x5C, 0x41, 0x5D, 0x41, 0x5E, 0x41, + // Bytes 80 - bf + 0x5F, 0x41, 0x60, 0x41, 0x61, 0x41, 0x62, 0x41, + 0x63, 0x41, 0x64, 0x41, 0x65, 0x41, 0x66, 0x41, + 0x67, 0x41, 0x68, 0x41, 0x69, 0x41, 0x6A, 0x41, + 0x6B, 0x41, 0x6C, 0x41, 0x6D, 0x41, 0x6E, 0x41, + 0x6F, 0x41, 0x70, 0x41, 0x71, 0x41, 0x72, 0x41, + 0x73, 0x41, 0x74, 0x41, 0x75, 0x41, 0x76, 0x41, + 0x77, 0x41, 0x78, 0x41, 0x79, 0x41, 0x7A, 0x41, + 0x7B, 0x41, 0x7C, 0x41, 0x7D, 0x41, 0x7E, 0x42, + // Bytes c0 - ff + 0xC2, 0xA2, 0x42, 0xC2, 0xA3, 0x42, 0xC2, 0xA5, + 0x42, 0xC2, 0xA6, 0x42, 0xC2, 0xAC, 0x42, 0xC2, + 0xB7, 0x42, 0xC3, 0x86, 0x42, 0xC3, 0xB0, 0x42, + 0xC4, 0xA6, 0x42, 0xC4, 0xA7, 0x42, 0xC4, 0xB1, + 0x42, 0xC5, 0x8B, 0x42, 0xC5, 0x93, 0x42, 0xC6, + 0x8E, 0x42, 0xC6, 0x90, 0x42, 0xC6, 0xAB, 0x42, + 0xC8, 0xA2, 0x42, 0xC8, 0xB7, 0x42, 0xC9, 0x90, + 0x42, 0xC9, 0x91, 0x42, 0xC9, 0x92, 0x42, 0xC9, + // Bytes 100 - 13f + 0x94, 0x42, 0xC9, 0x95, 0x42, 0xC9, 0x99, 0x42, + 0xC9, 0x9B, 0x42, 0xC9, 0x9C, 0x42, 0xC9, 0x9F, + 0x42, 0xC9, 0xA1, 0x42, 0xC9, 0xA3, 0x42, 0xC9, + 0xA5, 0x42, 0xC9, 0xA6, 0x42, 0xC9, 0xA8, 0x42, + 0xC9, 0xA9, 0x42, 0xC9, 0xAA, 0x42, 0xC9, 0xAB, + 0x42, 0xC9, 0xAD, 0x42, 0xC9, 0xAF, 0x42, 0xC9, + 0xB0, 0x42, 0xC9, 0xB1, 0x42, 0xC9, 0xB2, 0x42, + 0xC9, 0xB3, 0x42, 0xC9, 0xB4, 0x42, 0xC9, 0xB5, + // Bytes 140 - 17f + 0x42, 0xC9, 0xB8, 0x42, 0xC9, 0xB9, 0x42, 0xC9, + 0xBB, 0x42, 0xCA, 0x81, 0x42, 0xCA, 0x82, 0x42, + 0xCA, 0x83, 0x42, 0xCA, 0x89, 0x42, 0xCA, 0x8A, + 0x42, 0xCA, 0x8B, 0x42, 0xCA, 0x8C, 0x42, 0xCA, + 0x90, 0x42, 0xCA, 0x91, 0x42, 0xCA, 0x92, 0x42, + 0xCA, 0x95, 0x42, 0xCA, 0x9D, 0x42, 0xCA, 0x9F, + 0x42, 0xCA, 0xB9, 0x42, 0xCE, 0x91, 0x42, 0xCE, + 0x92, 0x42, 0xCE, 0x93, 0x42, 0xCE, 0x94, 0x42, + // Bytes 180 - 1bf + 0xCE, 0x95, 0x42, 0xCE, 0x96, 0x42, 0xCE, 0x97, + 0x42, 0xCE, 0x98, 0x42, 0xCE, 0x99, 0x42, 0xCE, + 0x9A, 0x42, 0xCE, 0x9B, 0x42, 0xCE, 0x9C, 0x42, + 0xCE, 0x9D, 0x42, 0xCE, 0x9E, 0x42, 0xCE, 0x9F, + 0x42, 0xCE, 0xA0, 0x42, 0xCE, 0xA1, 0x42, 0xCE, + 0xA3, 0x42, 0xCE, 0xA4, 0x42, 0xCE, 0xA5, 0x42, + 0xCE, 0xA6, 0x42, 0xCE, 0xA7, 0x42, 0xCE, 0xA8, + 0x42, 0xCE, 0xA9, 0x42, 0xCE, 0xB1, 0x42, 0xCE, + // Bytes 1c0 - 1ff + 0xB2, 0x42, 0xCE, 0xB3, 0x42, 0xCE, 0xB4, 0x42, + 0xCE, 0xB5, 0x42, 0xCE, 0xB6, 0x42, 0xCE, 0xB7, + 0x42, 0xCE, 0xB8, 0x42, 0xCE, 0xB9, 0x42, 0xCE, + 0xBA, 0x42, 0xCE, 0xBB, 0x42, 0xCE, 0xBC, 0x42, + 0xCE, 0xBD, 0x42, 0xCE, 0xBE, 0x42, 0xCE, 0xBF, + 0x42, 0xCF, 0x80, 0x42, 0xCF, 0x81, 0x42, 0xCF, + 0x82, 0x42, 0xCF, 0x83, 0x42, 0xCF, 0x84, 0x42, + 0xCF, 0x85, 0x42, 0xCF, 0x86, 0x42, 0xCF, 0x87, + // Bytes 200 - 23f + 0x42, 0xCF, 0x88, 0x42, 0xCF, 0x89, 0x42, 0xCF, + 0x9C, 0x42, 0xCF, 0x9D, 0x42, 0xD0, 0xBD, 0x42, + 0xD1, 0x8A, 0x42, 0xD1, 0x8C, 0x42, 0xD7, 0x90, + 0x42, 0xD7, 0x91, 0x42, 0xD7, 0x92, 0x42, 0xD7, + 0x93, 0x42, 0xD7, 0x94, 0x42, 0xD7, 0x9B, 0x42, + 0xD7, 0x9C, 0x42, 0xD7, 0x9D, 0x42, 0xD7, 0xA2, + 0x42, 0xD7, 0xA8, 0x42, 0xD7, 0xAA, 0x42, 0xD8, + 0xA1, 0x42, 0xD8, 0xA7, 0x42, 0xD8, 0xA8, 0x42, + // Bytes 240 - 27f + 0xD8, 0xA9, 0x42, 0xD8, 0xAA, 0x42, 0xD8, 0xAB, + 0x42, 0xD8, 0xAC, 0x42, 0xD8, 0xAD, 0x42, 0xD8, + 0xAE, 0x42, 0xD8, 0xAF, 0x42, 0xD8, 0xB0, 0x42, + 0xD8, 0xB1, 0x42, 0xD8, 0xB2, 0x42, 0xD8, 0xB3, + 0x42, 0xD8, 0xB4, 0x42, 0xD8, 0xB5, 0x42, 0xD8, + 0xB6, 0x42, 0xD8, 0xB7, 0x42, 0xD8, 0xB8, 0x42, + 0xD8, 0xB9, 0x42, 0xD8, 0xBA, 0x42, 0xD9, 0x81, + 0x42, 0xD9, 0x82, 0x42, 0xD9, 0x83, 0x42, 0xD9, + // Bytes 280 - 2bf + 0x84, 0x42, 0xD9, 0x85, 0x42, 0xD9, 0x86, 0x42, + 0xD9, 0x87, 0x42, 0xD9, 0x88, 0x42, 0xD9, 0x89, + 0x42, 0xD9, 0x8A, 0x42, 0xD9, 0xAE, 0x42, 0xD9, + 0xAF, 0x42, 0xD9, 0xB1, 0x42, 0xD9, 0xB9, 0x42, + 0xD9, 0xBA, 0x42, 0xD9, 0xBB, 0x42, 0xD9, 0xBE, + 0x42, 0xD9, 0xBF, 0x42, 0xDA, 0x80, 0x42, 0xDA, + 0x83, 0x42, 0xDA, 0x84, 0x42, 0xDA, 0x86, 0x42, + 0xDA, 0x87, 0x42, 0xDA, 0x88, 0x42, 0xDA, 0x8C, + // Bytes 2c0 - 2ff + 0x42, 0xDA, 0x8D, 0x42, 0xDA, 0x8E, 0x42, 0xDA, + 0x91, 0x42, 0xDA, 0x98, 0x42, 0xDA, 0xA1, 0x42, + 0xDA, 0xA4, 0x42, 0xDA, 0xA6, 0x42, 0xDA, 0xA9, + 0x42, 0xDA, 0xAD, 0x42, 0xDA, 0xAF, 0x42, 0xDA, + 0xB1, 0x42, 0xDA, 0xB3, 0x42, 0xDA, 0xBA, 0x42, + 0xDA, 0xBB, 0x42, 0xDA, 0xBE, 0x42, 0xDB, 0x81, + 0x42, 0xDB, 0x85, 0x42, 0xDB, 0x86, 0x42, 0xDB, + 0x87, 0x42, 0xDB, 0x88, 0x42, 0xDB, 0x89, 0x42, + // Bytes 300 - 33f + 0xDB, 0x8B, 0x42, 0xDB, 0x8C, 0x42, 0xDB, 0x90, + 0x42, 0xDB, 0x92, 0x43, 0xE0, 0xBC, 0x8B, 0x43, + 0xE1, 0x83, 0x9C, 0x43, 0xE1, 0x84, 0x80, 0x43, + 0xE1, 0x84, 0x81, 0x43, 0xE1, 0x84, 0x82, 0x43, + 0xE1, 0x84, 0x83, 0x43, 0xE1, 0x84, 0x84, 0x43, + 0xE1, 0x84, 0x85, 0x43, 0xE1, 0x84, 0x86, 0x43, + 0xE1, 0x84, 0x87, 0x43, 0xE1, 0x84, 0x88, 0x43, + 0xE1, 0x84, 0x89, 0x43, 0xE1, 0x84, 0x8A, 0x43, + // Bytes 340 - 37f + 0xE1, 0x84, 0x8B, 0x43, 0xE1, 0x84, 0x8C, 0x43, + 0xE1, 0x84, 0x8D, 0x43, 0xE1, 0x84, 0x8E, 0x43, + 0xE1, 0x84, 0x8F, 0x43, 0xE1, 0x84, 0x90, 0x43, + 0xE1, 0x84, 0x91, 0x43, 0xE1, 0x84, 0x92, 0x43, + 0xE1, 0x84, 0x94, 0x43, 0xE1, 0x84, 0x95, 0x43, + 0xE1, 0x84, 0x9A, 0x43, 0xE1, 0x84, 0x9C, 0x43, + 0xE1, 0x84, 0x9D, 0x43, 0xE1, 0x84, 0x9E, 0x43, + 0xE1, 0x84, 0xA0, 0x43, 0xE1, 0x84, 0xA1, 0x43, + // Bytes 380 - 3bf + 0xE1, 0x84, 0xA2, 0x43, 0xE1, 0x84, 0xA3, 0x43, + 0xE1, 0x84, 0xA7, 0x43, 0xE1, 0x84, 0xA9, 0x43, + 0xE1, 0x84, 0xAB, 0x43, 0xE1, 0x84, 0xAC, 0x43, + 0xE1, 0x84, 0xAD, 0x43, 0xE1, 0x84, 0xAE, 0x43, + 0xE1, 0x84, 0xAF, 0x43, 0xE1, 0x84, 0xB2, 0x43, + 0xE1, 0x84, 0xB6, 0x43, 0xE1, 0x85, 0x80, 0x43, + 0xE1, 0x85, 0x87, 0x43, 0xE1, 0x85, 0x8C, 0x43, + 0xE1, 0x85, 0x97, 0x43, 0xE1, 0x85, 0x98, 0x43, + // Bytes 3c0 - 3ff + 0xE1, 0x85, 0x99, 0x43, 0xE1, 0x85, 0xA0, 0x43, + 0xE1, 0x86, 0x84, 0x43, 0xE1, 0x86, 0x85, 0x43, + 0xE1, 0x86, 0x88, 0x43, 0xE1, 0x86, 0x91, 0x43, + 0xE1, 0x86, 0x92, 0x43, 0xE1, 0x86, 0x94, 0x43, + 0xE1, 0x86, 0x9E, 0x43, 0xE1, 0x86, 0xA1, 0x43, + 0xE1, 0x87, 0x87, 0x43, 0xE1, 0x87, 0x88, 0x43, + 0xE1, 0x87, 0x8C, 0x43, 0xE1, 0x87, 0x8E, 0x43, + 0xE1, 0x87, 0x93, 0x43, 0xE1, 0x87, 0x97, 0x43, + // Bytes 400 - 43f + 0xE1, 0x87, 0x99, 0x43, 0xE1, 0x87, 0x9D, 0x43, + 0xE1, 0x87, 0x9F, 0x43, 0xE1, 0x87, 0xB1, 0x43, + 0xE1, 0x87, 0xB2, 0x43, 0xE1, 0xB4, 0x82, 0x43, + 0xE1, 0xB4, 0x96, 0x43, 0xE1, 0xB4, 0x97, 0x43, + 0xE1, 0xB4, 0x9C, 0x43, 0xE1, 0xB4, 0x9D, 0x43, + 0xE1, 0xB4, 0xA5, 0x43, 0xE1, 0xB5, 0xBB, 0x43, + 0xE1, 0xB6, 0x85, 0x43, 0xE2, 0x80, 0x82, 0x43, + 0xE2, 0x80, 0x83, 0x43, 0xE2, 0x80, 0x90, 0x43, + // Bytes 440 - 47f + 0xE2, 0x80, 0x93, 0x43, 0xE2, 0x80, 0x94, 0x43, + 0xE2, 0x82, 0xA9, 0x43, 0xE2, 0x86, 0x90, 0x43, + 0xE2, 0x86, 0x91, 0x43, 0xE2, 0x86, 0x92, 0x43, + 0xE2, 0x86, 0x93, 0x43, 0xE2, 0x88, 0x82, 0x43, + 0xE2, 0x88, 0x87, 0x43, 0xE2, 0x88, 0x91, 0x43, + 0xE2, 0x88, 0x92, 0x43, 0xE2, 0x94, 0x82, 0x43, + 0xE2, 0x96, 0xA0, 0x43, 0xE2, 0x97, 0x8B, 0x43, + 0xE2, 0xA6, 0x85, 0x43, 0xE2, 0xA6, 0x86, 0x43, + // Bytes 480 - 4bf + 0xE2, 0xB5, 0xA1, 0x43, 0xE3, 0x80, 0x81, 0x43, + 0xE3, 0x80, 0x82, 0x43, 0xE3, 0x80, 0x88, 0x43, + 0xE3, 0x80, 0x89, 0x43, 0xE3, 0x80, 0x8A, 0x43, + 0xE3, 0x80, 0x8B, 0x43, 0xE3, 0x80, 0x8C, 0x43, + 0xE3, 0x80, 0x8D, 0x43, 0xE3, 0x80, 0x8E, 0x43, + 0xE3, 0x80, 0x8F, 0x43, 0xE3, 0x80, 0x90, 0x43, + 0xE3, 0x80, 0x91, 0x43, 0xE3, 0x80, 0x92, 0x43, + 0xE3, 0x80, 0x94, 0x43, 0xE3, 0x80, 0x95, 0x43, + // Bytes 4c0 - 4ff + 0xE3, 0x80, 0x96, 0x43, 0xE3, 0x80, 0x97, 0x43, + 0xE3, 0x82, 0xA1, 0x43, 0xE3, 0x82, 0xA2, 0x43, + 0xE3, 0x82, 0xA3, 0x43, 0xE3, 0x82, 0xA4, 0x43, + 0xE3, 0x82, 0xA5, 0x43, 0xE3, 0x82, 0xA6, 0x43, + 0xE3, 0x82, 0xA7, 0x43, 0xE3, 0x82, 0xA8, 0x43, + 0xE3, 0x82, 0xA9, 0x43, 0xE3, 0x82, 0xAA, 0x43, + 0xE3, 0x82, 0xAB, 0x43, 0xE3, 0x82, 0xAD, 0x43, + 0xE3, 0x82, 0xAF, 0x43, 0xE3, 0x82, 0xB1, 0x43, + // Bytes 500 - 53f + 0xE3, 0x82, 0xB3, 0x43, 0xE3, 0x82, 0xB5, 0x43, + 0xE3, 0x82, 0xB7, 0x43, 0xE3, 0x82, 0xB9, 0x43, + 0xE3, 0x82, 0xBB, 0x43, 0xE3, 0x82, 0xBD, 0x43, + 0xE3, 0x82, 0xBF, 0x43, 0xE3, 0x83, 0x81, 0x43, + 0xE3, 0x83, 0x83, 0x43, 0xE3, 0x83, 0x84, 0x43, + 0xE3, 0x83, 0x86, 0x43, 0xE3, 0x83, 0x88, 0x43, + 0xE3, 0x83, 0x8A, 0x43, 0xE3, 0x83, 0x8B, 0x43, + 0xE3, 0x83, 0x8C, 0x43, 0xE3, 0x83, 0x8D, 0x43, + // Bytes 540 - 57f + 0xE3, 0x83, 0x8E, 0x43, 0xE3, 0x83, 0x8F, 0x43, + 0xE3, 0x83, 0x92, 0x43, 0xE3, 0x83, 0x95, 0x43, + 0xE3, 0x83, 0x98, 0x43, 0xE3, 0x83, 0x9B, 0x43, + 0xE3, 0x83, 0x9E, 0x43, 0xE3, 0x83, 0x9F, 0x43, + 0xE3, 0x83, 0xA0, 0x43, 0xE3, 0x83, 0xA1, 0x43, + 0xE3, 0x83, 0xA2, 0x43, 0xE3, 0x83, 0xA3, 0x43, + 0xE3, 0x83, 0xA4, 0x43, 0xE3, 0x83, 0xA5, 0x43, + 0xE3, 0x83, 0xA6, 0x43, 0xE3, 0x83, 0xA7, 0x43, + // Bytes 580 - 5bf + 0xE3, 0x83, 0xA8, 0x43, 0xE3, 0x83, 0xA9, 0x43, + 0xE3, 0x83, 0xAA, 0x43, 0xE3, 0x83, 0xAB, 0x43, + 0xE3, 0x83, 0xAC, 0x43, 0xE3, 0x83, 0xAD, 0x43, + 0xE3, 0x83, 0xAF, 0x43, 0xE3, 0x83, 0xB0, 0x43, + 0xE3, 0x83, 0xB1, 0x43, 0xE3, 0x83, 0xB2, 0x43, + 0xE3, 0x83, 0xB3, 0x43, 0xE3, 0x83, 0xBB, 0x43, + 0xE3, 0x83, 0xBC, 0x43, 0xE3, 0x92, 0x9E, 0x43, + 0xE3, 0x92, 0xB9, 0x43, 0xE3, 0x92, 0xBB, 0x43, + // Bytes 5c0 - 5ff + 0xE3, 0x93, 0x9F, 0x43, 0xE3, 0x94, 0x95, 0x43, + 0xE3, 0x9B, 0xAE, 0x43, 0xE3, 0x9B, 0xBC, 0x43, + 0xE3, 0x9E, 0x81, 0x43, 0xE3, 0xA0, 0xAF, 0x43, + 0xE3, 0xA1, 0xA2, 0x43, 0xE3, 0xA1, 0xBC, 0x43, + 0xE3, 0xA3, 0x87, 0x43, 0xE3, 0xA3, 0xA3, 0x43, + 0xE3, 0xA4, 0x9C, 0x43, 0xE3, 0xA4, 0xBA, 0x43, + 0xE3, 0xA8, 0xAE, 0x43, 0xE3, 0xA9, 0xAC, 0x43, + 0xE3, 0xAB, 0xA4, 0x43, 0xE3, 0xAC, 0x88, 0x43, + // Bytes 600 - 63f + 0xE3, 0xAC, 0x99, 0x43, 0xE3, 0xAD, 0x89, 0x43, + 0xE3, 0xAE, 0x9D, 0x43, 0xE3, 0xB0, 0x98, 0x43, + 0xE3, 0xB1, 0x8E, 0x43, 0xE3, 0xB4, 0xB3, 0x43, + 0xE3, 0xB6, 0x96, 0x43, 0xE3, 0xBA, 0xAC, 0x43, + 0xE3, 0xBA, 0xB8, 0x43, 0xE3, 0xBC, 0x9B, 0x43, + 0xE3, 0xBF, 0xBC, 0x43, 0xE4, 0x80, 0x88, 0x43, + 0xE4, 0x80, 0x98, 0x43, 0xE4, 0x80, 0xB9, 0x43, + 0xE4, 0x81, 0x86, 0x43, 0xE4, 0x82, 0x96, 0x43, + // Bytes 640 - 67f + 0xE4, 0x83, 0xA3, 0x43, 0xE4, 0x84, 0xAF, 0x43, + 0xE4, 0x88, 0x82, 0x43, 0xE4, 0x88, 0xA7, 0x43, + 0xE4, 0x8A, 0xA0, 0x43, 0xE4, 0x8C, 0x81, 0x43, + 0xE4, 0x8C, 0xB4, 0x43, 0xE4, 0x8D, 0x99, 0x43, + 0xE4, 0x8F, 0x95, 0x43, 0xE4, 0x8F, 0x99, 0x43, + 0xE4, 0x90, 0x8B, 0x43, 0xE4, 0x91, 0xAB, 0x43, + 0xE4, 0x94, 0xAB, 0x43, 0xE4, 0x95, 0x9D, 0x43, + 0xE4, 0x95, 0xA1, 0x43, 0xE4, 0x95, 0xAB, 0x43, + // Bytes 680 - 6bf + 0xE4, 0x97, 0x97, 0x43, 0xE4, 0x97, 0xB9, 0x43, + 0xE4, 0x98, 0xB5, 0x43, 0xE4, 0x9A, 0xBE, 0x43, + 0xE4, 0x9B, 0x87, 0x43, 0xE4, 0xA6, 0x95, 0x43, + 0xE4, 0xA7, 0xA6, 0x43, 0xE4, 0xA9, 0xAE, 0x43, + 0xE4, 0xA9, 0xB6, 0x43, 0xE4, 0xAA, 0xB2, 0x43, + 0xE4, 0xAC, 0xB3, 0x43, 0xE4, 0xAF, 0x8E, 0x43, + 0xE4, 0xB3, 0x8E, 0x43, 0xE4, 0xB3, 0xAD, 0x43, + 0xE4, 0xB3, 0xB8, 0x43, 0xE4, 0xB5, 0x96, 0x43, + // Bytes 6c0 - 6ff + 0xE4, 0xB8, 0x80, 0x43, 0xE4, 0xB8, 0x81, 0x43, + 0xE4, 0xB8, 0x83, 0x43, 0xE4, 0xB8, 0x89, 0x43, + 0xE4, 0xB8, 0x8A, 0x43, 0xE4, 0xB8, 0x8B, 0x43, + 0xE4, 0xB8, 0x8D, 0x43, 0xE4, 0xB8, 0x99, 0x43, + 0xE4, 0xB8, 0xA6, 0x43, 0xE4, 0xB8, 0xA8, 0x43, + 0xE4, 0xB8, 0xAD, 0x43, 0xE4, 0xB8, 0xB2, 0x43, + 0xE4, 0xB8, 0xB6, 0x43, 0xE4, 0xB8, 0xB8, 0x43, + 0xE4, 0xB8, 0xB9, 0x43, 0xE4, 0xB8, 0xBD, 0x43, + // Bytes 700 - 73f + 0xE4, 0xB8, 0xBF, 0x43, 0xE4, 0xB9, 0x81, 0x43, + 0xE4, 0xB9, 0x99, 0x43, 0xE4, 0xB9, 0x9D, 0x43, + 0xE4, 0xBA, 0x82, 0x43, 0xE4, 0xBA, 0x85, 0x43, + 0xE4, 0xBA, 0x86, 0x43, 0xE4, 0xBA, 0x8C, 0x43, + 0xE4, 0xBA, 0x94, 0x43, 0xE4, 0xBA, 0xA0, 0x43, + 0xE4, 0xBA, 0xA4, 0x43, 0xE4, 0xBA, 0xAE, 0x43, + 0xE4, 0xBA, 0xBA, 0x43, 0xE4, 0xBB, 0x80, 0x43, + 0xE4, 0xBB, 0x8C, 0x43, 0xE4, 0xBB, 0xA4, 0x43, + // Bytes 740 - 77f + 0xE4, 0xBC, 0x81, 0x43, 0xE4, 0xBC, 0x91, 0x43, + 0xE4, 0xBD, 0xA0, 0x43, 0xE4, 0xBE, 0x80, 0x43, + 0xE4, 0xBE, 0x86, 0x43, 0xE4, 0xBE, 0x8B, 0x43, + 0xE4, 0xBE, 0xAE, 0x43, 0xE4, 0xBE, 0xBB, 0x43, + 0xE4, 0xBE, 0xBF, 0x43, 0xE5, 0x80, 0x82, 0x43, + 0xE5, 0x80, 0xAB, 0x43, 0xE5, 0x81, 0xBA, 0x43, + 0xE5, 0x82, 0x99, 0x43, 0xE5, 0x83, 0x8F, 0x43, + 0xE5, 0x83, 0x9A, 0x43, 0xE5, 0x83, 0xA7, 0x43, + // Bytes 780 - 7bf + 0xE5, 0x84, 0xAA, 0x43, 0xE5, 0x84, 0xBF, 0x43, + 0xE5, 0x85, 0x80, 0x43, 0xE5, 0x85, 0x85, 0x43, + 0xE5, 0x85, 0x8D, 0x43, 0xE5, 0x85, 0x94, 0x43, + 0xE5, 0x85, 0xA4, 0x43, 0xE5, 0x85, 0xA5, 0x43, + 0xE5, 0x85, 0xA7, 0x43, 0xE5, 0x85, 0xA8, 0x43, + 0xE5, 0x85, 0xA9, 0x43, 0xE5, 0x85, 0xAB, 0x43, + 0xE5, 0x85, 0xAD, 0x43, 0xE5, 0x85, 0xB7, 0x43, + 0xE5, 0x86, 0x80, 0x43, 0xE5, 0x86, 0x82, 0x43, + // Bytes 7c0 - 7ff + 0xE5, 0x86, 0x8D, 0x43, 0xE5, 0x86, 0x92, 0x43, + 0xE5, 0x86, 0x95, 0x43, 0xE5, 0x86, 0x96, 0x43, + 0xE5, 0x86, 0x97, 0x43, 0xE5, 0x86, 0x99, 0x43, + 0xE5, 0x86, 0xA4, 0x43, 0xE5, 0x86, 0xAB, 0x43, + 0xE5, 0x86, 0xAC, 0x43, 0xE5, 0x86, 0xB5, 0x43, + 0xE5, 0x86, 0xB7, 0x43, 0xE5, 0x87, 0x89, 0x43, + 0xE5, 0x87, 0x8C, 0x43, 0xE5, 0x87, 0x9C, 0x43, + 0xE5, 0x87, 0x9E, 0x43, 0xE5, 0x87, 0xA0, 0x43, + // Bytes 800 - 83f + 0xE5, 0x87, 0xB5, 0x43, 0xE5, 0x88, 0x80, 0x43, + 0xE5, 0x88, 0x83, 0x43, 0xE5, 0x88, 0x87, 0x43, + 0xE5, 0x88, 0x97, 0x43, 0xE5, 0x88, 0x9D, 0x43, + 0xE5, 0x88, 0xA9, 0x43, 0xE5, 0x88, 0xBA, 0x43, + 0xE5, 0x88, 0xBB, 0x43, 0xE5, 0x89, 0x86, 0x43, + 0xE5, 0x89, 0x8D, 0x43, 0xE5, 0x89, 0xB2, 0x43, + 0xE5, 0x89, 0xB7, 0x43, 0xE5, 0x8A, 0x89, 0x43, + 0xE5, 0x8A, 0x9B, 0x43, 0xE5, 0x8A, 0xA3, 0x43, + // Bytes 840 - 87f + 0xE5, 0x8A, 0xB3, 0x43, 0xE5, 0x8A, 0xB4, 0x43, + 0xE5, 0x8B, 0x87, 0x43, 0xE5, 0x8B, 0x89, 0x43, + 0xE5, 0x8B, 0x92, 0x43, 0xE5, 0x8B, 0x9E, 0x43, + 0xE5, 0x8B, 0xA4, 0x43, 0xE5, 0x8B, 0xB5, 0x43, + 0xE5, 0x8B, 0xB9, 0x43, 0xE5, 0x8B, 0xBA, 0x43, + 0xE5, 0x8C, 0x85, 0x43, 0xE5, 0x8C, 0x86, 0x43, + 0xE5, 0x8C, 0x95, 0x43, 0xE5, 0x8C, 0x97, 0x43, + 0xE5, 0x8C, 0x9A, 0x43, 0xE5, 0x8C, 0xB8, 0x43, + // Bytes 880 - 8bf + 0xE5, 0x8C, 0xBB, 0x43, 0xE5, 0x8C, 0xBF, 0x43, + 0xE5, 0x8D, 0x81, 0x43, 0xE5, 0x8D, 0x84, 0x43, + 0xE5, 0x8D, 0x85, 0x43, 0xE5, 0x8D, 0x89, 0x43, + 0xE5, 0x8D, 0x91, 0x43, 0xE5, 0x8D, 0x94, 0x43, + 0xE5, 0x8D, 0x9A, 0x43, 0xE5, 0x8D, 0x9C, 0x43, + 0xE5, 0x8D, 0xA9, 0x43, 0xE5, 0x8D, 0xB0, 0x43, + 0xE5, 0x8D, 0xB3, 0x43, 0xE5, 0x8D, 0xB5, 0x43, + 0xE5, 0x8D, 0xBD, 0x43, 0xE5, 0x8D, 0xBF, 0x43, + // Bytes 8c0 - 8ff + 0xE5, 0x8E, 0x82, 0x43, 0xE5, 0x8E, 0xB6, 0x43, + 0xE5, 0x8F, 0x83, 0x43, 0xE5, 0x8F, 0x88, 0x43, + 0xE5, 0x8F, 0x8A, 0x43, 0xE5, 0x8F, 0x8C, 0x43, + 0xE5, 0x8F, 0x9F, 0x43, 0xE5, 0x8F, 0xA3, 0x43, + 0xE5, 0x8F, 0xA5, 0x43, 0xE5, 0x8F, 0xAB, 0x43, + 0xE5, 0x8F, 0xAF, 0x43, 0xE5, 0x8F, 0xB1, 0x43, + 0xE5, 0x8F, 0xB3, 0x43, 0xE5, 0x90, 0x86, 0x43, + 0xE5, 0x90, 0x88, 0x43, 0xE5, 0x90, 0x8D, 0x43, + // Bytes 900 - 93f + 0xE5, 0x90, 0x8F, 0x43, 0xE5, 0x90, 0x9D, 0x43, + 0xE5, 0x90, 0xB8, 0x43, 0xE5, 0x90, 0xB9, 0x43, + 0xE5, 0x91, 0x82, 0x43, 0xE5, 0x91, 0x88, 0x43, + 0xE5, 0x91, 0xA8, 0x43, 0xE5, 0x92, 0x9E, 0x43, + 0xE5, 0x92, 0xA2, 0x43, 0xE5, 0x92, 0xBD, 0x43, + 0xE5, 0x93, 0xB6, 0x43, 0xE5, 0x94, 0x90, 0x43, + 0xE5, 0x95, 0x8F, 0x43, 0xE5, 0x95, 0x93, 0x43, + 0xE5, 0x95, 0x95, 0x43, 0xE5, 0x95, 0xA3, 0x43, + // Bytes 940 - 97f + 0xE5, 0x96, 0x84, 0x43, 0xE5, 0x96, 0x87, 0x43, + 0xE5, 0x96, 0x99, 0x43, 0xE5, 0x96, 0x9D, 0x43, + 0xE5, 0x96, 0xAB, 0x43, 0xE5, 0x96, 0xB3, 0x43, + 0xE5, 0x96, 0xB6, 0x43, 0xE5, 0x97, 0x80, 0x43, + 0xE5, 0x97, 0x82, 0x43, 0xE5, 0x97, 0xA2, 0x43, + 0xE5, 0x98, 0x86, 0x43, 0xE5, 0x99, 0x91, 0x43, + 0xE5, 0x99, 0xA8, 0x43, 0xE5, 0x99, 0xB4, 0x43, + 0xE5, 0x9B, 0x97, 0x43, 0xE5, 0x9B, 0x9B, 0x43, + // Bytes 980 - 9bf + 0xE5, 0x9B, 0xB9, 0x43, 0xE5, 0x9C, 0x96, 0x43, + 0xE5, 0x9C, 0x97, 0x43, 0xE5, 0x9C, 0x9F, 0x43, + 0xE5, 0x9C, 0xB0, 0x43, 0xE5, 0x9E, 0x8B, 0x43, + 0xE5, 0x9F, 0x8E, 0x43, 0xE5, 0x9F, 0xB4, 0x43, + 0xE5, 0xA0, 0x8D, 0x43, 0xE5, 0xA0, 0xB1, 0x43, + 0xE5, 0xA0, 0xB2, 0x43, 0xE5, 0xA1, 0x80, 0x43, + 0xE5, 0xA1, 0x9A, 0x43, 0xE5, 0xA1, 0x9E, 0x43, + 0xE5, 0xA2, 0xA8, 0x43, 0xE5, 0xA2, 0xAC, 0x43, + // Bytes 9c0 - 9ff + 0xE5, 0xA2, 0xB3, 0x43, 0xE5, 0xA3, 0x98, 0x43, + 0xE5, 0xA3, 0x9F, 0x43, 0xE5, 0xA3, 0xAB, 0x43, + 0xE5, 0xA3, 0xAE, 0x43, 0xE5, 0xA3, 0xB0, 0x43, + 0xE5, 0xA3, 0xB2, 0x43, 0xE5, 0xA3, 0xB7, 0x43, + 0xE5, 0xA4, 0x82, 0x43, 0xE5, 0xA4, 0x86, 0x43, + 0xE5, 0xA4, 0x8A, 0x43, 0xE5, 0xA4, 0x95, 0x43, + 0xE5, 0xA4, 0x9A, 0x43, 0xE5, 0xA4, 0x9C, 0x43, + 0xE5, 0xA4, 0xA2, 0x43, 0xE5, 0xA4, 0xA7, 0x43, + // Bytes a00 - a3f + 0xE5, 0xA4, 0xA9, 0x43, 0xE5, 0xA5, 0x84, 0x43, + 0xE5, 0xA5, 0x88, 0x43, 0xE5, 0xA5, 0x91, 0x43, + 0xE5, 0xA5, 0x94, 0x43, 0xE5, 0xA5, 0xA2, 0x43, + 0xE5, 0xA5, 0xB3, 0x43, 0xE5, 0xA7, 0x98, 0x43, + 0xE5, 0xA7, 0xAC, 0x43, 0xE5, 0xA8, 0x9B, 0x43, + 0xE5, 0xA8, 0xA7, 0x43, 0xE5, 0xA9, 0xA2, 0x43, + 0xE5, 0xA9, 0xA6, 0x43, 0xE5, 0xAA, 0xB5, 0x43, + 0xE5, 0xAC, 0x88, 0x43, 0xE5, 0xAC, 0xA8, 0x43, + // Bytes a40 - a7f + 0xE5, 0xAC, 0xBE, 0x43, 0xE5, 0xAD, 0x90, 0x43, + 0xE5, 0xAD, 0x97, 0x43, 0xE5, 0xAD, 0xA6, 0x43, + 0xE5, 0xAE, 0x80, 0x43, 0xE5, 0xAE, 0x85, 0x43, + 0xE5, 0xAE, 0x97, 0x43, 0xE5, 0xAF, 0x83, 0x43, + 0xE5, 0xAF, 0x98, 0x43, 0xE5, 0xAF, 0xA7, 0x43, + 0xE5, 0xAF, 0xAE, 0x43, 0xE5, 0xAF, 0xB3, 0x43, + 0xE5, 0xAF, 0xB8, 0x43, 0xE5, 0xAF, 0xBF, 0x43, + 0xE5, 0xB0, 0x86, 0x43, 0xE5, 0xB0, 0x8F, 0x43, + // Bytes a80 - abf + 0xE5, 0xB0, 0xA2, 0x43, 0xE5, 0xB0, 0xB8, 0x43, + 0xE5, 0xB0, 0xBF, 0x43, 0xE5, 0xB1, 0xA0, 0x43, + 0xE5, 0xB1, 0xA2, 0x43, 0xE5, 0xB1, 0xA4, 0x43, + 0xE5, 0xB1, 0xA5, 0x43, 0xE5, 0xB1, 0xAE, 0x43, + 0xE5, 0xB1, 0xB1, 0x43, 0xE5, 0xB2, 0x8D, 0x43, + 0xE5, 0xB3, 0x80, 0x43, 0xE5, 0xB4, 0x99, 0x43, + 0xE5, 0xB5, 0x83, 0x43, 0xE5, 0xB5, 0x90, 0x43, + 0xE5, 0xB5, 0xAB, 0x43, 0xE5, 0xB5, 0xAE, 0x43, + // Bytes ac0 - aff + 0xE5, 0xB5, 0xBC, 0x43, 0xE5, 0xB6, 0xB2, 0x43, + 0xE5, 0xB6, 0xBA, 0x43, 0xE5, 0xB7, 0x9B, 0x43, + 0xE5, 0xB7, 0xA1, 0x43, 0xE5, 0xB7, 0xA2, 0x43, + 0xE5, 0xB7, 0xA5, 0x43, 0xE5, 0xB7, 0xA6, 0x43, + 0xE5, 0xB7, 0xB1, 0x43, 0xE5, 0xB7, 0xBD, 0x43, + 0xE5, 0xB7, 0xBE, 0x43, 0xE5, 0xB8, 0xA8, 0x43, + 0xE5, 0xB8, 0xBD, 0x43, 0xE5, 0xB9, 0xA9, 0x43, + 0xE5, 0xB9, 0xB2, 0x43, 0xE5, 0xB9, 0xB4, 0x43, + // Bytes b00 - b3f + 0xE5, 0xB9, 0xBA, 0x43, 0xE5, 0xB9, 0xBC, 0x43, + 0xE5, 0xB9, 0xBF, 0x43, 0xE5, 0xBA, 0xA6, 0x43, + 0xE5, 0xBA, 0xB0, 0x43, 0xE5, 0xBA, 0xB3, 0x43, + 0xE5, 0xBA, 0xB6, 0x43, 0xE5, 0xBB, 0x89, 0x43, + 0xE5, 0xBB, 0x8A, 0x43, 0xE5, 0xBB, 0x92, 0x43, + 0xE5, 0xBB, 0x93, 0x43, 0xE5, 0xBB, 0x99, 0x43, + 0xE5, 0xBB, 0xAC, 0x43, 0xE5, 0xBB, 0xB4, 0x43, + 0xE5, 0xBB, 0xBE, 0x43, 0xE5, 0xBC, 0x84, 0x43, + // Bytes b40 - b7f + 0xE5, 0xBC, 0x8B, 0x43, 0xE5, 0xBC, 0x93, 0x43, + 0xE5, 0xBC, 0xA2, 0x43, 0xE5, 0xBD, 0x90, 0x43, + 0xE5, 0xBD, 0x93, 0x43, 0xE5, 0xBD, 0xA1, 0x43, + 0xE5, 0xBD, 0xA2, 0x43, 0xE5, 0xBD, 0xA9, 0x43, + 0xE5, 0xBD, 0xAB, 0x43, 0xE5, 0xBD, 0xB3, 0x43, + 0xE5, 0xBE, 0x8B, 0x43, 0xE5, 0xBE, 0x8C, 0x43, + 0xE5, 0xBE, 0x97, 0x43, 0xE5, 0xBE, 0x9A, 0x43, + 0xE5, 0xBE, 0xA9, 0x43, 0xE5, 0xBE, 0xAD, 0x43, + // Bytes b80 - bbf + 0xE5, 0xBF, 0x83, 0x43, 0xE5, 0xBF, 0x8D, 0x43, + 0xE5, 0xBF, 0x97, 0x43, 0xE5, 0xBF, 0xB5, 0x43, + 0xE5, 0xBF, 0xB9, 0x43, 0xE6, 0x80, 0x92, 0x43, + 0xE6, 0x80, 0x9C, 0x43, 0xE6, 0x81, 0xB5, 0x43, + 0xE6, 0x82, 0x81, 0x43, 0xE6, 0x82, 0x94, 0x43, + 0xE6, 0x83, 0x87, 0x43, 0xE6, 0x83, 0x98, 0x43, + 0xE6, 0x83, 0xA1, 0x43, 0xE6, 0x84, 0x88, 0x43, + 0xE6, 0x85, 0x84, 0x43, 0xE6, 0x85, 0x88, 0x43, + // Bytes bc0 - bff + 0xE6, 0x85, 0x8C, 0x43, 0xE6, 0x85, 0x8E, 0x43, + 0xE6, 0x85, 0xA0, 0x43, 0xE6, 0x85, 0xA8, 0x43, + 0xE6, 0x85, 0xBA, 0x43, 0xE6, 0x86, 0x8E, 0x43, + 0xE6, 0x86, 0x90, 0x43, 0xE6, 0x86, 0xA4, 0x43, + 0xE6, 0x86, 0xAF, 0x43, 0xE6, 0x86, 0xB2, 0x43, + 0xE6, 0x87, 0x9E, 0x43, 0xE6, 0x87, 0xB2, 0x43, + 0xE6, 0x87, 0xB6, 0x43, 0xE6, 0x88, 0x80, 0x43, + 0xE6, 0x88, 0x88, 0x43, 0xE6, 0x88, 0x90, 0x43, + // Bytes c00 - c3f + 0xE6, 0x88, 0x9B, 0x43, 0xE6, 0x88, 0xAE, 0x43, + 0xE6, 0x88, 0xB4, 0x43, 0xE6, 0x88, 0xB6, 0x43, + 0xE6, 0x89, 0x8B, 0x43, 0xE6, 0x89, 0x93, 0x43, + 0xE6, 0x89, 0x9D, 0x43, 0xE6, 0x8A, 0x95, 0x43, + 0xE6, 0x8A, 0xB1, 0x43, 0xE6, 0x8B, 0x89, 0x43, + 0xE6, 0x8B, 0x8F, 0x43, 0xE6, 0x8B, 0x93, 0x43, + 0xE6, 0x8B, 0x94, 0x43, 0xE6, 0x8B, 0xBC, 0x43, + 0xE6, 0x8B, 0xBE, 0x43, 0xE6, 0x8C, 0x87, 0x43, + // Bytes c40 - c7f + 0xE6, 0x8C, 0xBD, 0x43, 0xE6, 0x8D, 0x90, 0x43, + 0xE6, 0x8D, 0x95, 0x43, 0xE6, 0x8D, 0xA8, 0x43, + 0xE6, 0x8D, 0xBB, 0x43, 0xE6, 0x8E, 0x83, 0x43, + 0xE6, 0x8E, 0xA0, 0x43, 0xE6, 0x8E, 0xA9, 0x43, + 0xE6, 0x8F, 0x84, 0x43, 0xE6, 0x8F, 0x85, 0x43, + 0xE6, 0x8F, 0xA4, 0x43, 0xE6, 0x90, 0x9C, 0x43, + 0xE6, 0x90, 0xA2, 0x43, 0xE6, 0x91, 0x92, 0x43, + 0xE6, 0x91, 0xA9, 0x43, 0xE6, 0x91, 0xB7, 0x43, + // Bytes c80 - cbf + 0xE6, 0x91, 0xBE, 0x43, 0xE6, 0x92, 0x9A, 0x43, + 0xE6, 0x92, 0x9D, 0x43, 0xE6, 0x93, 0x84, 0x43, + 0xE6, 0x94, 0xAF, 0x43, 0xE6, 0x94, 0xB4, 0x43, + 0xE6, 0x95, 0x8F, 0x43, 0xE6, 0x95, 0x96, 0x43, + 0xE6, 0x95, 0xAC, 0x43, 0xE6, 0x95, 0xB8, 0x43, + 0xE6, 0x96, 0x87, 0x43, 0xE6, 0x96, 0x97, 0x43, + 0xE6, 0x96, 0x99, 0x43, 0xE6, 0x96, 0xA4, 0x43, + 0xE6, 0x96, 0xB0, 0x43, 0xE6, 0x96, 0xB9, 0x43, + // Bytes cc0 - cff + 0xE6, 0x97, 0x85, 0x43, 0xE6, 0x97, 0xA0, 0x43, + 0xE6, 0x97, 0xA2, 0x43, 0xE6, 0x97, 0xA3, 0x43, + 0xE6, 0x97, 0xA5, 0x43, 0xE6, 0x98, 0x93, 0x43, + 0xE6, 0x98, 0xA0, 0x43, 0xE6, 0x99, 0x89, 0x43, + 0xE6, 0x99, 0xB4, 0x43, 0xE6, 0x9A, 0x88, 0x43, + 0xE6, 0x9A, 0x91, 0x43, 0xE6, 0x9A, 0x9C, 0x43, + 0xE6, 0x9A, 0xB4, 0x43, 0xE6, 0x9B, 0x86, 0x43, + 0xE6, 0x9B, 0xB0, 0x43, 0xE6, 0x9B, 0xB4, 0x43, + // Bytes d00 - d3f + 0xE6, 0x9B, 0xB8, 0x43, 0xE6, 0x9C, 0x80, 0x43, + 0xE6, 0x9C, 0x88, 0x43, 0xE6, 0x9C, 0x89, 0x43, + 0xE6, 0x9C, 0x97, 0x43, 0xE6, 0x9C, 0x9B, 0x43, + 0xE6, 0x9C, 0xA1, 0x43, 0xE6, 0x9C, 0xA8, 0x43, + 0xE6, 0x9D, 0x8E, 0x43, 0xE6, 0x9D, 0x93, 0x43, + 0xE6, 0x9D, 0x96, 0x43, 0xE6, 0x9D, 0x9E, 0x43, + 0xE6, 0x9D, 0xBB, 0x43, 0xE6, 0x9E, 0x85, 0x43, + 0xE6, 0x9E, 0x97, 0x43, 0xE6, 0x9F, 0xB3, 0x43, + // Bytes d40 - d7f + 0xE6, 0x9F, 0xBA, 0x43, 0xE6, 0xA0, 0x97, 0x43, + 0xE6, 0xA0, 0x9F, 0x43, 0xE6, 0xA0, 0xAA, 0x43, + 0xE6, 0xA1, 0x92, 0x43, 0xE6, 0xA2, 0x81, 0x43, + 0xE6, 0xA2, 0x85, 0x43, 0xE6, 0xA2, 0x8E, 0x43, + 0xE6, 0xA2, 0xA8, 0x43, 0xE6, 0xA4, 0x94, 0x43, + 0xE6, 0xA5, 0x82, 0x43, 0xE6, 0xA6, 0xA3, 0x43, + 0xE6, 0xA7, 0xAA, 0x43, 0xE6, 0xA8, 0x82, 0x43, + 0xE6, 0xA8, 0x93, 0x43, 0xE6, 0xAA, 0xA8, 0x43, + // Bytes d80 - dbf + 0xE6, 0xAB, 0x93, 0x43, 0xE6, 0xAB, 0x9B, 0x43, + 0xE6, 0xAC, 0x84, 0x43, 0xE6, 0xAC, 0xA0, 0x43, + 0xE6, 0xAC, 0xA1, 0x43, 0xE6, 0xAD, 0x94, 0x43, + 0xE6, 0xAD, 0xA2, 0x43, 0xE6, 0xAD, 0xA3, 0x43, + 0xE6, 0xAD, 0xB2, 0x43, 0xE6, 0xAD, 0xB7, 0x43, + 0xE6, 0xAD, 0xB9, 0x43, 0xE6, 0xAE, 0x9F, 0x43, + 0xE6, 0xAE, 0xAE, 0x43, 0xE6, 0xAE, 0xB3, 0x43, + 0xE6, 0xAE, 0xBA, 0x43, 0xE6, 0xAE, 0xBB, 0x43, + // Bytes dc0 - dff + 0xE6, 0xAF, 0x8B, 0x43, 0xE6, 0xAF, 0x8D, 0x43, + 0xE6, 0xAF, 0x94, 0x43, 0xE6, 0xAF, 0x9B, 0x43, + 0xE6, 0xB0, 0x8F, 0x43, 0xE6, 0xB0, 0x94, 0x43, + 0xE6, 0xB0, 0xB4, 0x43, 0xE6, 0xB1, 0x8E, 0x43, + 0xE6, 0xB1, 0xA7, 0x43, 0xE6, 0xB2, 0x88, 0x43, + 0xE6, 0xB2, 0xBF, 0x43, 0xE6, 0xB3, 0x8C, 0x43, + 0xE6, 0xB3, 0x8D, 0x43, 0xE6, 0xB3, 0xA5, 0x43, + 0xE6, 0xB3, 0xA8, 0x43, 0xE6, 0xB4, 0x96, 0x43, + // Bytes e00 - e3f + 0xE6, 0xB4, 0x9B, 0x43, 0xE6, 0xB4, 0x9E, 0x43, + 0xE6, 0xB4, 0xB4, 0x43, 0xE6, 0xB4, 0xBE, 0x43, + 0xE6, 0xB5, 0x81, 0x43, 0xE6, 0xB5, 0xA9, 0x43, + 0xE6, 0xB5, 0xAA, 0x43, 0xE6, 0xB5, 0xB7, 0x43, + 0xE6, 0xB5, 0xB8, 0x43, 0xE6, 0xB6, 0x85, 0x43, + 0xE6, 0xB7, 0x8B, 0x43, 0xE6, 0xB7, 0x9A, 0x43, + 0xE6, 0xB7, 0xAA, 0x43, 0xE6, 0xB7, 0xB9, 0x43, + 0xE6, 0xB8, 0x9A, 0x43, 0xE6, 0xB8, 0xAF, 0x43, + // Bytes e40 - e7f + 0xE6, 0xB9, 0xAE, 0x43, 0xE6, 0xBA, 0x80, 0x43, + 0xE6, 0xBA, 0x9C, 0x43, 0xE6, 0xBA, 0xBA, 0x43, + 0xE6, 0xBB, 0x87, 0x43, 0xE6, 0xBB, 0x8B, 0x43, + 0xE6, 0xBB, 0x91, 0x43, 0xE6, 0xBB, 0x9B, 0x43, + 0xE6, 0xBC, 0x8F, 0x43, 0xE6, 0xBC, 0x94, 0x43, + 0xE6, 0xBC, 0xA2, 0x43, 0xE6, 0xBC, 0xA3, 0x43, + 0xE6, 0xBD, 0xAE, 0x43, 0xE6, 0xBF, 0x86, 0x43, + 0xE6, 0xBF, 0xAB, 0x43, 0xE6, 0xBF, 0xBE, 0x43, + // Bytes e80 - ebf + 0xE7, 0x80, 0x9B, 0x43, 0xE7, 0x80, 0x9E, 0x43, + 0xE7, 0x80, 0xB9, 0x43, 0xE7, 0x81, 0x8A, 0x43, + 0xE7, 0x81, 0xAB, 0x43, 0xE7, 0x81, 0xB0, 0x43, + 0xE7, 0x81, 0xB7, 0x43, 0xE7, 0x81, 0xBD, 0x43, + 0xE7, 0x82, 0x99, 0x43, 0xE7, 0x82, 0xAD, 0x43, + 0xE7, 0x83, 0x88, 0x43, 0xE7, 0x83, 0x99, 0x43, + 0xE7, 0x84, 0xA1, 0x43, 0xE7, 0x85, 0x85, 0x43, + 0xE7, 0x85, 0x89, 0x43, 0xE7, 0x85, 0xAE, 0x43, + // Bytes ec0 - eff + 0xE7, 0x86, 0x9C, 0x43, 0xE7, 0x87, 0x8E, 0x43, + 0xE7, 0x87, 0x90, 0x43, 0xE7, 0x88, 0x90, 0x43, + 0xE7, 0x88, 0x9B, 0x43, 0xE7, 0x88, 0xA8, 0x43, + 0xE7, 0x88, 0xAA, 0x43, 0xE7, 0x88, 0xAB, 0x43, + 0xE7, 0x88, 0xB5, 0x43, 0xE7, 0x88, 0xB6, 0x43, + 0xE7, 0x88, 0xBB, 0x43, 0xE7, 0x88, 0xBF, 0x43, + 0xE7, 0x89, 0x87, 0x43, 0xE7, 0x89, 0x90, 0x43, + 0xE7, 0x89, 0x99, 0x43, 0xE7, 0x89, 0x9B, 0x43, + // Bytes f00 - f3f + 0xE7, 0x89, 0xA2, 0x43, 0xE7, 0x89, 0xB9, 0x43, + 0xE7, 0x8A, 0x80, 0x43, 0xE7, 0x8A, 0x95, 0x43, + 0xE7, 0x8A, 0xAC, 0x43, 0xE7, 0x8A, 0xAF, 0x43, + 0xE7, 0x8B, 0x80, 0x43, 0xE7, 0x8B, 0xBC, 0x43, + 0xE7, 0x8C, 0xAA, 0x43, 0xE7, 0x8D, 0xB5, 0x43, + 0xE7, 0x8D, 0xBA, 0x43, 0xE7, 0x8E, 0x84, 0x43, + 0xE7, 0x8E, 0x87, 0x43, 0xE7, 0x8E, 0x89, 0x43, + 0xE7, 0x8E, 0x8B, 0x43, 0xE7, 0x8E, 0xA5, 0x43, + // Bytes f40 - f7f + 0xE7, 0x8E, 0xB2, 0x43, 0xE7, 0x8F, 0x9E, 0x43, + 0xE7, 0x90, 0x86, 0x43, 0xE7, 0x90, 0x89, 0x43, + 0xE7, 0x90, 0xA2, 0x43, 0xE7, 0x91, 0x87, 0x43, + 0xE7, 0x91, 0x9C, 0x43, 0xE7, 0x91, 0xA9, 0x43, + 0xE7, 0x91, 0xB1, 0x43, 0xE7, 0x92, 0x85, 0x43, + 0xE7, 0x92, 0x89, 0x43, 0xE7, 0x92, 0x98, 0x43, + 0xE7, 0x93, 0x8A, 0x43, 0xE7, 0x93, 0x9C, 0x43, + 0xE7, 0x93, 0xA6, 0x43, 0xE7, 0x94, 0x86, 0x43, + // Bytes f80 - fbf + 0xE7, 0x94, 0x98, 0x43, 0xE7, 0x94, 0x9F, 0x43, + 0xE7, 0x94, 0xA4, 0x43, 0xE7, 0x94, 0xA8, 0x43, + 0xE7, 0x94, 0xB0, 0x43, 0xE7, 0x94, 0xB2, 0x43, + 0xE7, 0x94, 0xB3, 0x43, 0xE7, 0x94, 0xB7, 0x43, + 0xE7, 0x94, 0xBB, 0x43, 0xE7, 0x94, 0xBE, 0x43, + 0xE7, 0x95, 0x99, 0x43, 0xE7, 0x95, 0xA5, 0x43, + 0xE7, 0x95, 0xB0, 0x43, 0xE7, 0x96, 0x8B, 0x43, + 0xE7, 0x96, 0x92, 0x43, 0xE7, 0x97, 0xA2, 0x43, + // Bytes fc0 - fff + 0xE7, 0x98, 0x90, 0x43, 0xE7, 0x98, 0x9D, 0x43, + 0xE7, 0x98, 0x9F, 0x43, 0xE7, 0x99, 0x82, 0x43, + 0xE7, 0x99, 0xA9, 0x43, 0xE7, 0x99, 0xB6, 0x43, + 0xE7, 0x99, 0xBD, 0x43, 0xE7, 0x9A, 0xAE, 0x43, + 0xE7, 0x9A, 0xBF, 0x43, 0xE7, 0x9B, 0x8A, 0x43, + 0xE7, 0x9B, 0x9B, 0x43, 0xE7, 0x9B, 0xA3, 0x43, + 0xE7, 0x9B, 0xA7, 0x43, 0xE7, 0x9B, 0xAE, 0x43, + 0xE7, 0x9B, 0xB4, 0x43, 0xE7, 0x9C, 0x81, 0x43, + // Bytes 1000 - 103f + 0xE7, 0x9C, 0x9E, 0x43, 0xE7, 0x9C, 0x9F, 0x43, + 0xE7, 0x9D, 0x80, 0x43, 0xE7, 0x9D, 0x8A, 0x43, + 0xE7, 0x9E, 0x8B, 0x43, 0xE7, 0x9E, 0xA7, 0x43, + 0xE7, 0x9F, 0x9B, 0x43, 0xE7, 0x9F, 0xA2, 0x43, + 0xE7, 0x9F, 0xB3, 0x43, 0xE7, 0xA1, 0x8E, 0x43, + 0xE7, 0xA1, 0xAB, 0x43, 0xE7, 0xA2, 0x8C, 0x43, + 0xE7, 0xA2, 0x91, 0x43, 0xE7, 0xA3, 0x8A, 0x43, + 0xE7, 0xA3, 0x8C, 0x43, 0xE7, 0xA3, 0xBB, 0x43, + // Bytes 1040 - 107f + 0xE7, 0xA4, 0xAA, 0x43, 0xE7, 0xA4, 0xBA, 0x43, + 0xE7, 0xA4, 0xBC, 0x43, 0xE7, 0xA4, 0xBE, 0x43, + 0xE7, 0xA5, 0x88, 0x43, 0xE7, 0xA5, 0x89, 0x43, + 0xE7, 0xA5, 0x90, 0x43, 0xE7, 0xA5, 0x96, 0x43, + 0xE7, 0xA5, 0x9D, 0x43, 0xE7, 0xA5, 0x9E, 0x43, + 0xE7, 0xA5, 0xA5, 0x43, 0xE7, 0xA5, 0xBF, 0x43, + 0xE7, 0xA6, 0x81, 0x43, 0xE7, 0xA6, 0x8D, 0x43, + 0xE7, 0xA6, 0x8E, 0x43, 0xE7, 0xA6, 0x8F, 0x43, + // Bytes 1080 - 10bf + 0xE7, 0xA6, 0xAE, 0x43, 0xE7, 0xA6, 0xB8, 0x43, + 0xE7, 0xA6, 0xBE, 0x43, 0xE7, 0xA7, 0x8A, 0x43, + 0xE7, 0xA7, 0x98, 0x43, 0xE7, 0xA7, 0xAB, 0x43, + 0xE7, 0xA8, 0x9C, 0x43, 0xE7, 0xA9, 0x80, 0x43, + 0xE7, 0xA9, 0x8A, 0x43, 0xE7, 0xA9, 0x8F, 0x43, + 0xE7, 0xA9, 0xB4, 0x43, 0xE7, 0xA9, 0xBA, 0x43, + 0xE7, 0xAA, 0x81, 0x43, 0xE7, 0xAA, 0xB1, 0x43, + 0xE7, 0xAB, 0x8B, 0x43, 0xE7, 0xAB, 0xAE, 0x43, + // Bytes 10c0 - 10ff + 0xE7, 0xAB, 0xB9, 0x43, 0xE7, 0xAC, 0xA0, 0x43, + 0xE7, 0xAE, 0x8F, 0x43, 0xE7, 0xAF, 0x80, 0x43, + 0xE7, 0xAF, 0x86, 0x43, 0xE7, 0xAF, 0x89, 0x43, + 0xE7, 0xB0, 0xBE, 0x43, 0xE7, 0xB1, 0xA0, 0x43, + 0xE7, 0xB1, 0xB3, 0x43, 0xE7, 0xB1, 0xBB, 0x43, + 0xE7, 0xB2, 0x92, 0x43, 0xE7, 0xB2, 0xBE, 0x43, + 0xE7, 0xB3, 0x92, 0x43, 0xE7, 0xB3, 0x96, 0x43, + 0xE7, 0xB3, 0xA3, 0x43, 0xE7, 0xB3, 0xA7, 0x43, + // Bytes 1100 - 113f + 0xE7, 0xB3, 0xA8, 0x43, 0xE7, 0xB3, 0xB8, 0x43, + 0xE7, 0xB4, 0x80, 0x43, 0xE7, 0xB4, 0x90, 0x43, + 0xE7, 0xB4, 0xA2, 0x43, 0xE7, 0xB4, 0xAF, 0x43, + 0xE7, 0xB5, 0x82, 0x43, 0xE7, 0xB5, 0x9B, 0x43, + 0xE7, 0xB5, 0xA3, 0x43, 0xE7, 0xB6, 0xA0, 0x43, + 0xE7, 0xB6, 0xBE, 0x43, 0xE7, 0xB7, 0x87, 0x43, + 0xE7, 0xB7, 0xB4, 0x43, 0xE7, 0xB8, 0x82, 0x43, + 0xE7, 0xB8, 0x89, 0x43, 0xE7, 0xB8, 0xB7, 0x43, + // Bytes 1140 - 117f + 0xE7, 0xB9, 0x81, 0x43, 0xE7, 0xB9, 0x85, 0x43, + 0xE7, 0xBC, 0xB6, 0x43, 0xE7, 0xBC, 0xBE, 0x43, + 0xE7, 0xBD, 0x91, 0x43, 0xE7, 0xBD, 0xB2, 0x43, + 0xE7, 0xBD, 0xB9, 0x43, 0xE7, 0xBD, 0xBA, 0x43, + 0xE7, 0xBE, 0x85, 0x43, 0xE7, 0xBE, 0x8A, 0x43, + 0xE7, 0xBE, 0x95, 0x43, 0xE7, 0xBE, 0x9A, 0x43, + 0xE7, 0xBE, 0xBD, 0x43, 0xE7, 0xBF, 0xBA, 0x43, + 0xE8, 0x80, 0x81, 0x43, 0xE8, 0x80, 0x85, 0x43, + // Bytes 1180 - 11bf + 0xE8, 0x80, 0x8C, 0x43, 0xE8, 0x80, 0x92, 0x43, + 0xE8, 0x80, 0xB3, 0x43, 0xE8, 0x81, 0x86, 0x43, + 0xE8, 0x81, 0xA0, 0x43, 0xE8, 0x81, 0xAF, 0x43, + 0xE8, 0x81, 0xB0, 0x43, 0xE8, 0x81, 0xBE, 0x43, + 0xE8, 0x81, 0xBF, 0x43, 0xE8, 0x82, 0x89, 0x43, + 0xE8, 0x82, 0x8B, 0x43, 0xE8, 0x82, 0xAD, 0x43, + 0xE8, 0x82, 0xB2, 0x43, 0xE8, 0x84, 0x83, 0x43, + 0xE8, 0x84, 0xBE, 0x43, 0xE8, 0x87, 0x98, 0x43, + // Bytes 11c0 - 11ff + 0xE8, 0x87, 0xA3, 0x43, 0xE8, 0x87, 0xA8, 0x43, + 0xE8, 0x87, 0xAA, 0x43, 0xE8, 0x87, 0xAD, 0x43, + 0xE8, 0x87, 0xB3, 0x43, 0xE8, 0x87, 0xBC, 0x43, + 0xE8, 0x88, 0x81, 0x43, 0xE8, 0x88, 0x84, 0x43, + 0xE8, 0x88, 0x8C, 0x43, 0xE8, 0x88, 0x98, 0x43, + 0xE8, 0x88, 0x9B, 0x43, 0xE8, 0x88, 0x9F, 0x43, + 0xE8, 0x89, 0xAE, 0x43, 0xE8, 0x89, 0xAF, 0x43, + 0xE8, 0x89, 0xB2, 0x43, 0xE8, 0x89, 0xB8, 0x43, + // Bytes 1200 - 123f + 0xE8, 0x89, 0xB9, 0x43, 0xE8, 0x8A, 0x8B, 0x43, + 0xE8, 0x8A, 0x91, 0x43, 0xE8, 0x8A, 0x9D, 0x43, + 0xE8, 0x8A, 0xB1, 0x43, 0xE8, 0x8A, 0xB3, 0x43, + 0xE8, 0x8A, 0xBD, 0x43, 0xE8, 0x8B, 0xA5, 0x43, + 0xE8, 0x8B, 0xA6, 0x43, 0xE8, 0x8C, 0x9D, 0x43, + 0xE8, 0x8C, 0xA3, 0x43, 0xE8, 0x8C, 0xB6, 0x43, + 0xE8, 0x8D, 0x92, 0x43, 0xE8, 0x8D, 0x93, 0x43, + 0xE8, 0x8D, 0xA3, 0x43, 0xE8, 0x8E, 0xAD, 0x43, + // Bytes 1240 - 127f + 0xE8, 0x8E, 0xBD, 0x43, 0xE8, 0x8F, 0x89, 0x43, + 0xE8, 0x8F, 0x8A, 0x43, 0xE8, 0x8F, 0x8C, 0x43, + 0xE8, 0x8F, 0x9C, 0x43, 0xE8, 0x8F, 0xA7, 0x43, + 0xE8, 0x8F, 0xAF, 0x43, 0xE8, 0x8F, 0xB1, 0x43, + 0xE8, 0x90, 0xBD, 0x43, 0xE8, 0x91, 0x89, 0x43, + 0xE8, 0x91, 0x97, 0x43, 0xE8, 0x93, 0xAE, 0x43, + 0xE8, 0x93, 0xB1, 0x43, 0xE8, 0x93, 0xB3, 0x43, + 0xE8, 0x93, 0xBC, 0x43, 0xE8, 0x94, 0x96, 0x43, + // Bytes 1280 - 12bf + 0xE8, 0x95, 0xA4, 0x43, 0xE8, 0x97, 0x8D, 0x43, + 0xE8, 0x97, 0xBA, 0x43, 0xE8, 0x98, 0x86, 0x43, + 0xE8, 0x98, 0x92, 0x43, 0xE8, 0x98, 0xAD, 0x43, + 0xE8, 0x98, 0xBF, 0x43, 0xE8, 0x99, 0x8D, 0x43, + 0xE8, 0x99, 0x90, 0x43, 0xE8, 0x99, 0x9C, 0x43, + 0xE8, 0x99, 0xA7, 0x43, 0xE8, 0x99, 0xA9, 0x43, + 0xE8, 0x99, 0xAB, 0x43, 0xE8, 0x9A, 0x88, 0x43, + 0xE8, 0x9A, 0xA9, 0x43, 0xE8, 0x9B, 0xA2, 0x43, + // Bytes 12c0 - 12ff + 0xE8, 0x9C, 0x8E, 0x43, 0xE8, 0x9C, 0xA8, 0x43, + 0xE8, 0x9D, 0xAB, 0x43, 0xE8, 0x9D, 0xB9, 0x43, + 0xE8, 0x9E, 0x86, 0x43, 0xE8, 0x9E, 0xBA, 0x43, + 0xE8, 0x9F, 0xA1, 0x43, 0xE8, 0xA0, 0x81, 0x43, + 0xE8, 0xA0, 0x9F, 0x43, 0xE8, 0xA1, 0x80, 0x43, + 0xE8, 0xA1, 0x8C, 0x43, 0xE8, 0xA1, 0xA0, 0x43, + 0xE8, 0xA1, 0xA3, 0x43, 0xE8, 0xA3, 0x82, 0x43, + 0xE8, 0xA3, 0x8F, 0x43, 0xE8, 0xA3, 0x97, 0x43, + // Bytes 1300 - 133f + 0xE8, 0xA3, 0x9E, 0x43, 0xE8, 0xA3, 0xA1, 0x43, + 0xE8, 0xA3, 0xB8, 0x43, 0xE8, 0xA3, 0xBA, 0x43, + 0xE8, 0xA4, 0x90, 0x43, 0xE8, 0xA5, 0x81, 0x43, + 0xE8, 0xA5, 0xA4, 0x43, 0xE8, 0xA5, 0xBE, 0x43, + 0xE8, 0xA6, 0x86, 0x43, 0xE8, 0xA6, 0x8B, 0x43, + 0xE8, 0xA6, 0x96, 0x43, 0xE8, 0xA7, 0x92, 0x43, + 0xE8, 0xA7, 0xA3, 0x43, 0xE8, 0xA8, 0x80, 0x43, + 0xE8, 0xAA, 0xA0, 0x43, 0xE8, 0xAA, 0xAA, 0x43, + // Bytes 1340 - 137f + 0xE8, 0xAA, 0xBF, 0x43, 0xE8, 0xAB, 0x8B, 0x43, + 0xE8, 0xAB, 0x92, 0x43, 0xE8, 0xAB, 0x96, 0x43, + 0xE8, 0xAB, 0xAD, 0x43, 0xE8, 0xAB, 0xB8, 0x43, + 0xE8, 0xAB, 0xBE, 0x43, 0xE8, 0xAC, 0x81, 0x43, + 0xE8, 0xAC, 0xB9, 0x43, 0xE8, 0xAD, 0x98, 0x43, + 0xE8, 0xAE, 0x80, 0x43, 0xE8, 0xAE, 0x8A, 0x43, + 0xE8, 0xB0, 0xB7, 0x43, 0xE8, 0xB1, 0x86, 0x43, + 0xE8, 0xB1, 0x88, 0x43, 0xE8, 0xB1, 0x95, 0x43, + // Bytes 1380 - 13bf + 0xE8, 0xB1, 0xB8, 0x43, 0xE8, 0xB2, 0x9D, 0x43, + 0xE8, 0xB2, 0xA1, 0x43, 0xE8, 0xB2, 0xA9, 0x43, + 0xE8, 0xB2, 0xAB, 0x43, 0xE8, 0xB3, 0x81, 0x43, + 0xE8, 0xB3, 0x82, 0x43, 0xE8, 0xB3, 0x87, 0x43, + 0xE8, 0xB3, 0x88, 0x43, 0xE8, 0xB3, 0x93, 0x43, + 0xE8, 0xB4, 0x88, 0x43, 0xE8, 0xB4, 0x9B, 0x43, + 0xE8, 0xB5, 0xA4, 0x43, 0xE8, 0xB5, 0xB0, 0x43, + 0xE8, 0xB5, 0xB7, 0x43, 0xE8, 0xB6, 0xB3, 0x43, + // Bytes 13c0 - 13ff + 0xE8, 0xB6, 0xBC, 0x43, 0xE8, 0xB7, 0x8B, 0x43, + 0xE8, 0xB7, 0xAF, 0x43, 0xE8, 0xB7, 0xB0, 0x43, + 0xE8, 0xBA, 0xAB, 0x43, 0xE8, 0xBB, 0x8A, 0x43, + 0xE8, 0xBB, 0x94, 0x43, 0xE8, 0xBC, 0xA6, 0x43, + 0xE8, 0xBC, 0xAA, 0x43, 0xE8, 0xBC, 0xB8, 0x43, + 0xE8, 0xBC, 0xBB, 0x43, 0xE8, 0xBD, 0xA2, 0x43, + 0xE8, 0xBE, 0x9B, 0x43, 0xE8, 0xBE, 0x9E, 0x43, + 0xE8, 0xBE, 0xB0, 0x43, 0xE8, 0xBE, 0xB5, 0x43, + // Bytes 1400 - 143f + 0xE8, 0xBE, 0xB6, 0x43, 0xE9, 0x80, 0xA3, 0x43, + 0xE9, 0x80, 0xB8, 0x43, 0xE9, 0x81, 0x8A, 0x43, + 0xE9, 0x81, 0xA9, 0x43, 0xE9, 0x81, 0xB2, 0x43, + 0xE9, 0x81, 0xBC, 0x43, 0xE9, 0x82, 0x8F, 0x43, + 0xE9, 0x82, 0x91, 0x43, 0xE9, 0x82, 0x94, 0x43, + 0xE9, 0x83, 0x8E, 0x43, 0xE9, 0x83, 0x9E, 0x43, + 0xE9, 0x83, 0xB1, 0x43, 0xE9, 0x83, 0xBD, 0x43, + 0xE9, 0x84, 0x91, 0x43, 0xE9, 0x84, 0x9B, 0x43, + // Bytes 1440 - 147f + 0xE9, 0x85, 0x89, 0x43, 0xE9, 0x85, 0x8D, 0x43, + 0xE9, 0x85, 0xAA, 0x43, 0xE9, 0x86, 0x99, 0x43, + 0xE9, 0x86, 0xB4, 0x43, 0xE9, 0x87, 0x86, 0x43, + 0xE9, 0x87, 0x8C, 0x43, 0xE9, 0x87, 0x8F, 0x43, + 0xE9, 0x87, 0x91, 0x43, 0xE9, 0x88, 0xB4, 0x43, + 0xE9, 0x88, 0xB8, 0x43, 0xE9, 0x89, 0xB6, 0x43, + 0xE9, 0x89, 0xBC, 0x43, 0xE9, 0x8B, 0x97, 0x43, + 0xE9, 0x8B, 0x98, 0x43, 0xE9, 0x8C, 0x84, 0x43, + // Bytes 1480 - 14bf + 0xE9, 0x8D, 0x8A, 0x43, 0xE9, 0x8F, 0xB9, 0x43, + 0xE9, 0x90, 0x95, 0x43, 0xE9, 0x95, 0xB7, 0x43, + 0xE9, 0x96, 0x80, 0x43, 0xE9, 0x96, 0x8B, 0x43, + 0xE9, 0x96, 0xAD, 0x43, 0xE9, 0x96, 0xB7, 0x43, + 0xE9, 0x98, 0x9C, 0x43, 0xE9, 0x98, 0xAE, 0x43, + 0xE9, 0x99, 0x8B, 0x43, 0xE9, 0x99, 0x8D, 0x43, + 0xE9, 0x99, 0xB5, 0x43, 0xE9, 0x99, 0xB8, 0x43, + 0xE9, 0x99, 0xBC, 0x43, 0xE9, 0x9A, 0x86, 0x43, + // Bytes 14c0 - 14ff + 0xE9, 0x9A, 0xA3, 0x43, 0xE9, 0x9A, 0xB6, 0x43, + 0xE9, 0x9A, 0xB7, 0x43, 0xE9, 0x9A, 0xB8, 0x43, + 0xE9, 0x9A, 0xB9, 0x43, 0xE9, 0x9B, 0x83, 0x43, + 0xE9, 0x9B, 0xA2, 0x43, 0xE9, 0x9B, 0xA3, 0x43, + 0xE9, 0x9B, 0xA8, 0x43, 0xE9, 0x9B, 0xB6, 0x43, + 0xE9, 0x9B, 0xB7, 0x43, 0xE9, 0x9C, 0xA3, 0x43, + 0xE9, 0x9C, 0xB2, 0x43, 0xE9, 0x9D, 0x88, 0x43, + 0xE9, 0x9D, 0x91, 0x43, 0xE9, 0x9D, 0x96, 0x43, + // Bytes 1500 - 153f + 0xE9, 0x9D, 0x9E, 0x43, 0xE9, 0x9D, 0xA2, 0x43, + 0xE9, 0x9D, 0xA9, 0x43, 0xE9, 0x9F, 0x8B, 0x43, + 0xE9, 0x9F, 0x9B, 0x43, 0xE9, 0x9F, 0xA0, 0x43, + 0xE9, 0x9F, 0xAD, 0x43, 0xE9, 0x9F, 0xB3, 0x43, + 0xE9, 0x9F, 0xBF, 0x43, 0xE9, 0xA0, 0x81, 0x43, + 0xE9, 0xA0, 0x85, 0x43, 0xE9, 0xA0, 0x8B, 0x43, + 0xE9, 0xA0, 0x98, 0x43, 0xE9, 0xA0, 0xA9, 0x43, + 0xE9, 0xA0, 0xBB, 0x43, 0xE9, 0xA1, 0x9E, 0x43, + // Bytes 1540 - 157f + 0xE9, 0xA2, 0xA8, 0x43, 0xE9, 0xA3, 0x9B, 0x43, + 0xE9, 0xA3, 0x9F, 0x43, 0xE9, 0xA3, 0xA2, 0x43, + 0xE9, 0xA3, 0xAF, 0x43, 0xE9, 0xA3, 0xBC, 0x43, + 0xE9, 0xA4, 0xA8, 0x43, 0xE9, 0xA4, 0xA9, 0x43, + 0xE9, 0xA6, 0x96, 0x43, 0xE9, 0xA6, 0x99, 0x43, + 0xE9, 0xA6, 0xA7, 0x43, 0xE9, 0xA6, 0xAC, 0x43, + 0xE9, 0xA7, 0x82, 0x43, 0xE9, 0xA7, 0xB1, 0x43, + 0xE9, 0xA7, 0xBE, 0x43, 0xE9, 0xA9, 0xAA, 0x43, + // Bytes 1580 - 15bf + 0xE9, 0xAA, 0xA8, 0x43, 0xE9, 0xAB, 0x98, 0x43, + 0xE9, 0xAB, 0x9F, 0x43, 0xE9, 0xAC, 0x92, 0x43, + 0xE9, 0xAC, 0xA5, 0x43, 0xE9, 0xAC, 0xAF, 0x43, + 0xE9, 0xAC, 0xB2, 0x43, 0xE9, 0xAC, 0xBC, 0x43, + 0xE9, 0xAD, 0x9A, 0x43, 0xE9, 0xAD, 0xAF, 0x43, + 0xE9, 0xB1, 0x80, 0x43, 0xE9, 0xB1, 0x97, 0x43, + 0xE9, 0xB3, 0xA5, 0x43, 0xE9, 0xB3, 0xBD, 0x43, + 0xE9, 0xB5, 0xA7, 0x43, 0xE9, 0xB6, 0xB4, 0x43, + // Bytes 15c0 - 15ff + 0xE9, 0xB7, 0xBA, 0x43, 0xE9, 0xB8, 0x9E, 0x43, + 0xE9, 0xB9, 0xB5, 0x43, 0xE9, 0xB9, 0xBF, 0x43, + 0xE9, 0xBA, 0x97, 0x43, 0xE9, 0xBA, 0x9F, 0x43, + 0xE9, 0xBA, 0xA5, 0x43, 0xE9, 0xBA, 0xBB, 0x43, + 0xE9, 0xBB, 0x83, 0x43, 0xE9, 0xBB, 0x8D, 0x43, + 0xE9, 0xBB, 0x8E, 0x43, 0xE9, 0xBB, 0x91, 0x43, + 0xE9, 0xBB, 0xB9, 0x43, 0xE9, 0xBB, 0xBD, 0x43, + 0xE9, 0xBB, 0xBE, 0x43, 0xE9, 0xBC, 0x85, 0x43, + // Bytes 1600 - 163f + 0xE9, 0xBC, 0x8E, 0x43, 0xE9, 0xBC, 0x8F, 0x43, + 0xE9, 0xBC, 0x93, 0x43, 0xE9, 0xBC, 0x96, 0x43, + 0xE9, 0xBC, 0xA0, 0x43, 0xE9, 0xBC, 0xBB, 0x43, + 0xE9, 0xBD, 0x83, 0x43, 0xE9, 0xBD, 0x8A, 0x43, + 0xE9, 0xBD, 0x92, 0x43, 0xE9, 0xBE, 0x8D, 0x43, + 0xE9, 0xBE, 0x8E, 0x43, 0xE9, 0xBE, 0x9C, 0x43, + 0xE9, 0xBE, 0x9F, 0x43, 0xE9, 0xBE, 0xA0, 0x43, + 0xEA, 0x9C, 0xA7, 0x43, 0xEA, 0x9D, 0xAF, 0x43, + // Bytes 1640 - 167f + 0xEA, 0xAC, 0xB7, 0x43, 0xEA, 0xAD, 0x92, 0x44, + 0xF0, 0xA0, 0x84, 0xA2, 0x44, 0xF0, 0xA0, 0x94, + 0x9C, 0x44, 0xF0, 0xA0, 0x94, 0xA5, 0x44, 0xF0, + 0xA0, 0x95, 0x8B, 0x44, 0xF0, 0xA0, 0x98, 0xBA, + 0x44, 0xF0, 0xA0, 0xA0, 0x84, 0x44, 0xF0, 0xA0, + 0xA3, 0x9E, 0x44, 0xF0, 0xA0, 0xA8, 0xAC, 0x44, + 0xF0, 0xA0, 0xAD, 0xA3, 0x44, 0xF0, 0xA1, 0x93, + 0xA4, 0x44, 0xF0, 0xA1, 0x9A, 0xA8, 0x44, 0xF0, + // Bytes 1680 - 16bf + 0xA1, 0x9B, 0xAA, 0x44, 0xF0, 0xA1, 0xA7, 0x88, + 0x44, 0xF0, 0xA1, 0xAC, 0x98, 0x44, 0xF0, 0xA1, + 0xB4, 0x8B, 0x44, 0xF0, 0xA1, 0xB7, 0xA4, 0x44, + 0xF0, 0xA1, 0xB7, 0xA6, 0x44, 0xF0, 0xA2, 0x86, + 0x83, 0x44, 0xF0, 0xA2, 0x86, 0x9F, 0x44, 0xF0, + 0xA2, 0x8C, 0xB1, 0x44, 0xF0, 0xA2, 0x9B, 0x94, + 0x44, 0xF0, 0xA2, 0xA1, 0x84, 0x44, 0xF0, 0xA2, + 0xA1, 0x8A, 0x44, 0xF0, 0xA2, 0xAC, 0x8C, 0x44, + // Bytes 16c0 - 16ff + 0xF0, 0xA2, 0xAF, 0xB1, 0x44, 0xF0, 0xA3, 0x80, + 0x8A, 0x44, 0xF0, 0xA3, 0x8A, 0xB8, 0x44, 0xF0, + 0xA3, 0x8D, 0x9F, 0x44, 0xF0, 0xA3, 0x8E, 0x93, + 0x44, 0xF0, 0xA3, 0x8E, 0x9C, 0x44, 0xF0, 0xA3, + 0x8F, 0x83, 0x44, 0xF0, 0xA3, 0x8F, 0x95, 0x44, + 0xF0, 0xA3, 0x91, 0xAD, 0x44, 0xF0, 0xA3, 0x9A, + 0xA3, 0x44, 0xF0, 0xA3, 0xA2, 0xA7, 0x44, 0xF0, + 0xA3, 0xAA, 0x8D, 0x44, 0xF0, 0xA3, 0xAB, 0xBA, + // Bytes 1700 - 173f + 0x44, 0xF0, 0xA3, 0xB2, 0xBC, 0x44, 0xF0, 0xA3, + 0xB4, 0x9E, 0x44, 0xF0, 0xA3, 0xBB, 0x91, 0x44, + 0xF0, 0xA3, 0xBD, 0x9E, 0x44, 0xF0, 0xA3, 0xBE, + 0x8E, 0x44, 0xF0, 0xA4, 0x89, 0xA3, 0x44, 0xF0, + 0xA4, 0x8B, 0xAE, 0x44, 0xF0, 0xA4, 0x8E, 0xAB, + 0x44, 0xF0, 0xA4, 0x98, 0x88, 0x44, 0xF0, 0xA4, + 0x9C, 0xB5, 0x44, 0xF0, 0xA4, 0xA0, 0x94, 0x44, + 0xF0, 0xA4, 0xB0, 0xB6, 0x44, 0xF0, 0xA4, 0xB2, + // Bytes 1740 - 177f + 0x92, 0x44, 0xF0, 0xA4, 0xBE, 0xA1, 0x44, 0xF0, + 0xA4, 0xBE, 0xB8, 0x44, 0xF0, 0xA5, 0x81, 0x84, + 0x44, 0xF0, 0xA5, 0x83, 0xB2, 0x44, 0xF0, 0xA5, + 0x83, 0xB3, 0x44, 0xF0, 0xA5, 0x84, 0x99, 0x44, + 0xF0, 0xA5, 0x84, 0xB3, 0x44, 0xF0, 0xA5, 0x89, + 0x89, 0x44, 0xF0, 0xA5, 0x90, 0x9D, 0x44, 0xF0, + 0xA5, 0x98, 0xA6, 0x44, 0xF0, 0xA5, 0x9A, 0x9A, + 0x44, 0xF0, 0xA5, 0x9B, 0x85, 0x44, 0xF0, 0xA5, + // Bytes 1780 - 17bf + 0xA5, 0xBC, 0x44, 0xF0, 0xA5, 0xAA, 0xA7, 0x44, + 0xF0, 0xA5, 0xAE, 0xAB, 0x44, 0xF0, 0xA5, 0xB2, + 0x80, 0x44, 0xF0, 0xA5, 0xB3, 0x90, 0x44, 0xF0, + 0xA5, 0xBE, 0x86, 0x44, 0xF0, 0xA6, 0x87, 0x9A, + 0x44, 0xF0, 0xA6, 0x88, 0xA8, 0x44, 0xF0, 0xA6, + 0x89, 0x87, 0x44, 0xF0, 0xA6, 0x8B, 0x99, 0x44, + 0xF0, 0xA6, 0x8C, 0xBE, 0x44, 0xF0, 0xA6, 0x93, + 0x9A, 0x44, 0xF0, 0xA6, 0x94, 0xA3, 0x44, 0xF0, + // Bytes 17c0 - 17ff + 0xA6, 0x96, 0xA8, 0x44, 0xF0, 0xA6, 0x9E, 0xA7, + 0x44, 0xF0, 0xA6, 0x9E, 0xB5, 0x44, 0xF0, 0xA6, + 0xAC, 0xBC, 0x44, 0xF0, 0xA6, 0xB0, 0xB6, 0x44, + 0xF0, 0xA6, 0xB3, 0x95, 0x44, 0xF0, 0xA6, 0xB5, + 0xAB, 0x44, 0xF0, 0xA6, 0xBC, 0xAC, 0x44, 0xF0, + 0xA6, 0xBE, 0xB1, 0x44, 0xF0, 0xA7, 0x83, 0x92, + 0x44, 0xF0, 0xA7, 0x8F, 0x8A, 0x44, 0xF0, 0xA7, + 0x99, 0xA7, 0x44, 0xF0, 0xA7, 0xA2, 0xAE, 0x44, + // Bytes 1800 - 183f + 0xF0, 0xA7, 0xA5, 0xA6, 0x44, 0xF0, 0xA7, 0xB2, + 0xA8, 0x44, 0xF0, 0xA7, 0xBB, 0x93, 0x44, 0xF0, + 0xA7, 0xBC, 0xAF, 0x44, 0xF0, 0xA8, 0x97, 0x92, + 0x44, 0xF0, 0xA8, 0x97, 0xAD, 0x44, 0xF0, 0xA8, + 0x9C, 0xAE, 0x44, 0xF0, 0xA8, 0xAF, 0xBA, 0x44, + 0xF0, 0xA8, 0xB5, 0xB7, 0x44, 0xF0, 0xA9, 0x85, + 0x85, 0x44, 0xF0, 0xA9, 0x87, 0x9F, 0x44, 0xF0, + 0xA9, 0x88, 0x9A, 0x44, 0xF0, 0xA9, 0x90, 0x8A, + // Bytes 1840 - 187f + 0x44, 0xF0, 0xA9, 0x92, 0x96, 0x44, 0xF0, 0xA9, + 0x96, 0xB6, 0x44, 0xF0, 0xA9, 0xAC, 0xB0, 0x44, + 0xF0, 0xAA, 0x83, 0x8E, 0x44, 0xF0, 0xAA, 0x84, + 0x85, 0x44, 0xF0, 0xAA, 0x88, 0x8E, 0x44, 0xF0, + 0xAA, 0x8A, 0x91, 0x44, 0xF0, 0xAA, 0x8E, 0x92, + 0x44, 0xF0, 0xAA, 0x98, 0x80, 0x42, 0x21, 0x21, + 0x42, 0x21, 0x3F, 0x42, 0x2E, 0x2E, 0x42, 0x30, + 0x2C, 0x42, 0x30, 0x2E, 0x42, 0x31, 0x2C, 0x42, + // Bytes 1880 - 18bf + 0x31, 0x2E, 0x42, 0x31, 0x30, 0x42, 0x31, 0x31, + 0x42, 0x31, 0x32, 0x42, 0x31, 0x33, 0x42, 0x31, + 0x34, 0x42, 0x31, 0x35, 0x42, 0x31, 0x36, 0x42, + 0x31, 0x37, 0x42, 0x31, 0x38, 0x42, 0x31, 0x39, + 0x42, 0x32, 0x2C, 0x42, 0x32, 0x2E, 0x42, 0x32, + 0x30, 0x42, 0x32, 0x31, 0x42, 0x32, 0x32, 0x42, + 0x32, 0x33, 0x42, 0x32, 0x34, 0x42, 0x32, 0x35, + 0x42, 0x32, 0x36, 0x42, 0x32, 0x37, 0x42, 0x32, + // Bytes 18c0 - 18ff + 0x38, 0x42, 0x32, 0x39, 0x42, 0x33, 0x2C, 0x42, + 0x33, 0x2E, 0x42, 0x33, 0x30, 0x42, 0x33, 0x31, + 0x42, 0x33, 0x32, 0x42, 0x33, 0x33, 0x42, 0x33, + 0x34, 0x42, 0x33, 0x35, 0x42, 0x33, 0x36, 0x42, + 0x33, 0x37, 0x42, 0x33, 0x38, 0x42, 0x33, 0x39, + 0x42, 0x34, 0x2C, 0x42, 0x34, 0x2E, 0x42, 0x34, + 0x30, 0x42, 0x34, 0x31, 0x42, 0x34, 0x32, 0x42, + 0x34, 0x33, 0x42, 0x34, 0x34, 0x42, 0x34, 0x35, + // Bytes 1900 - 193f + 0x42, 0x34, 0x36, 0x42, 0x34, 0x37, 0x42, 0x34, + 0x38, 0x42, 0x34, 0x39, 0x42, 0x35, 0x2C, 0x42, + 0x35, 0x2E, 0x42, 0x35, 0x30, 0x42, 0x36, 0x2C, + 0x42, 0x36, 0x2E, 0x42, 0x37, 0x2C, 0x42, 0x37, + 0x2E, 0x42, 0x38, 0x2C, 0x42, 0x38, 0x2E, 0x42, + 0x39, 0x2C, 0x42, 0x39, 0x2E, 0x42, 0x3D, 0x3D, + 0x42, 0x3F, 0x21, 0x42, 0x3F, 0x3F, 0x42, 0x41, + 0x55, 0x42, 0x42, 0x71, 0x42, 0x43, 0x44, 0x42, + // Bytes 1940 - 197f + 0x44, 0x4A, 0x42, 0x44, 0x5A, 0x42, 0x44, 0x7A, + 0x42, 0x47, 0x42, 0x42, 0x47, 0x79, 0x42, 0x48, + 0x50, 0x42, 0x48, 0x56, 0x42, 0x48, 0x67, 0x42, + 0x48, 0x7A, 0x42, 0x49, 0x49, 0x42, 0x49, 0x4A, + 0x42, 0x49, 0x55, 0x42, 0x49, 0x56, 0x42, 0x49, + 0x58, 0x42, 0x4B, 0x42, 0x42, 0x4B, 0x4B, 0x42, + 0x4B, 0x4D, 0x42, 0x4C, 0x4A, 0x42, 0x4C, 0x6A, + 0x42, 0x4D, 0x42, 0x42, 0x4D, 0x43, 0x42, 0x4D, + // Bytes 1980 - 19bf + 0x44, 0x42, 0x4D, 0x56, 0x42, 0x4D, 0x57, 0x42, + 0x4E, 0x4A, 0x42, 0x4E, 0x6A, 0x42, 0x4E, 0x6F, + 0x42, 0x50, 0x48, 0x42, 0x50, 0x52, 0x42, 0x50, + 0x61, 0x42, 0x52, 0x73, 0x42, 0x53, 0x44, 0x42, + 0x53, 0x4D, 0x42, 0x53, 0x53, 0x42, 0x53, 0x76, + 0x42, 0x54, 0x4D, 0x42, 0x56, 0x49, 0x42, 0x57, + 0x43, 0x42, 0x57, 0x5A, 0x42, 0x57, 0x62, 0x42, + 0x58, 0x49, 0x42, 0x63, 0x63, 0x42, 0x63, 0x64, + // Bytes 19c0 - 19ff + 0x42, 0x63, 0x6D, 0x42, 0x64, 0x42, 0x42, 0x64, + 0x61, 0x42, 0x64, 0x6C, 0x42, 0x64, 0x6D, 0x42, + 0x64, 0x7A, 0x42, 0x65, 0x56, 0x42, 0x66, 0x66, + 0x42, 0x66, 0x69, 0x42, 0x66, 0x6C, 0x42, 0x66, + 0x6D, 0x42, 0x68, 0x61, 0x42, 0x69, 0x69, 0x42, + 0x69, 0x6A, 0x42, 0x69, 0x6E, 0x42, 0x69, 0x76, + 0x42, 0x69, 0x78, 0x42, 0x6B, 0x41, 0x42, 0x6B, + 0x56, 0x42, 0x6B, 0x57, 0x42, 0x6B, 0x67, 0x42, + // Bytes 1a00 - 1a3f + 0x6B, 0x6C, 0x42, 0x6B, 0x6D, 0x42, 0x6B, 0x74, + 0x42, 0x6C, 0x6A, 0x42, 0x6C, 0x6D, 0x42, 0x6C, + 0x6E, 0x42, 0x6C, 0x78, 0x42, 0x6D, 0x32, 0x42, + 0x6D, 0x33, 0x42, 0x6D, 0x41, 0x42, 0x6D, 0x56, + 0x42, 0x6D, 0x57, 0x42, 0x6D, 0x62, 0x42, 0x6D, + 0x67, 0x42, 0x6D, 0x6C, 0x42, 0x6D, 0x6D, 0x42, + 0x6D, 0x73, 0x42, 0x6E, 0x41, 0x42, 0x6E, 0x46, + 0x42, 0x6E, 0x56, 0x42, 0x6E, 0x57, 0x42, 0x6E, + // Bytes 1a40 - 1a7f + 0x6A, 0x42, 0x6E, 0x6D, 0x42, 0x6E, 0x73, 0x42, + 0x6F, 0x56, 0x42, 0x70, 0x41, 0x42, 0x70, 0x46, + 0x42, 0x70, 0x56, 0x42, 0x70, 0x57, 0x42, 0x70, + 0x63, 0x42, 0x70, 0x73, 0x42, 0x73, 0x72, 0x42, + 0x73, 0x74, 0x42, 0x76, 0x69, 0x42, 0x78, 0x69, + 0x43, 0x28, 0x31, 0x29, 0x43, 0x28, 0x32, 0x29, + 0x43, 0x28, 0x33, 0x29, 0x43, 0x28, 0x34, 0x29, + 0x43, 0x28, 0x35, 0x29, 0x43, 0x28, 0x36, 0x29, + // Bytes 1a80 - 1abf + 0x43, 0x28, 0x37, 0x29, 0x43, 0x28, 0x38, 0x29, + 0x43, 0x28, 0x39, 0x29, 0x43, 0x28, 0x41, 0x29, + 0x43, 0x28, 0x42, 0x29, 0x43, 0x28, 0x43, 0x29, + 0x43, 0x28, 0x44, 0x29, 0x43, 0x28, 0x45, 0x29, + 0x43, 0x28, 0x46, 0x29, 0x43, 0x28, 0x47, 0x29, + 0x43, 0x28, 0x48, 0x29, 0x43, 0x28, 0x49, 0x29, + 0x43, 0x28, 0x4A, 0x29, 0x43, 0x28, 0x4B, 0x29, + 0x43, 0x28, 0x4C, 0x29, 0x43, 0x28, 0x4D, 0x29, + // Bytes 1ac0 - 1aff + 0x43, 0x28, 0x4E, 0x29, 0x43, 0x28, 0x4F, 0x29, + 0x43, 0x28, 0x50, 0x29, 0x43, 0x28, 0x51, 0x29, + 0x43, 0x28, 0x52, 0x29, 0x43, 0x28, 0x53, 0x29, + 0x43, 0x28, 0x54, 0x29, 0x43, 0x28, 0x55, 0x29, + 0x43, 0x28, 0x56, 0x29, 0x43, 0x28, 0x57, 0x29, + 0x43, 0x28, 0x58, 0x29, 0x43, 0x28, 0x59, 0x29, + 0x43, 0x28, 0x5A, 0x29, 0x43, 0x28, 0x61, 0x29, + 0x43, 0x28, 0x62, 0x29, 0x43, 0x28, 0x63, 0x29, + // Bytes 1b00 - 1b3f + 0x43, 0x28, 0x64, 0x29, 0x43, 0x28, 0x65, 0x29, + 0x43, 0x28, 0x66, 0x29, 0x43, 0x28, 0x67, 0x29, + 0x43, 0x28, 0x68, 0x29, 0x43, 0x28, 0x69, 0x29, + 0x43, 0x28, 0x6A, 0x29, 0x43, 0x28, 0x6B, 0x29, + 0x43, 0x28, 0x6C, 0x29, 0x43, 0x28, 0x6D, 0x29, + 0x43, 0x28, 0x6E, 0x29, 0x43, 0x28, 0x6F, 0x29, + 0x43, 0x28, 0x70, 0x29, 0x43, 0x28, 0x71, 0x29, + 0x43, 0x28, 0x72, 0x29, 0x43, 0x28, 0x73, 0x29, + // Bytes 1b40 - 1b7f + 0x43, 0x28, 0x74, 0x29, 0x43, 0x28, 0x75, 0x29, + 0x43, 0x28, 0x76, 0x29, 0x43, 0x28, 0x77, 0x29, + 0x43, 0x28, 0x78, 0x29, 0x43, 0x28, 0x79, 0x29, + 0x43, 0x28, 0x7A, 0x29, 0x43, 0x2E, 0x2E, 0x2E, + 0x43, 0x31, 0x30, 0x2E, 0x43, 0x31, 0x31, 0x2E, + 0x43, 0x31, 0x32, 0x2E, 0x43, 0x31, 0x33, 0x2E, + 0x43, 0x31, 0x34, 0x2E, 0x43, 0x31, 0x35, 0x2E, + 0x43, 0x31, 0x36, 0x2E, 0x43, 0x31, 0x37, 0x2E, + // Bytes 1b80 - 1bbf + 0x43, 0x31, 0x38, 0x2E, 0x43, 0x31, 0x39, 0x2E, + 0x43, 0x32, 0x30, 0x2E, 0x43, 0x3A, 0x3A, 0x3D, + 0x43, 0x3D, 0x3D, 0x3D, 0x43, 0x43, 0x6F, 0x2E, + 0x43, 0x46, 0x41, 0x58, 0x43, 0x47, 0x48, 0x7A, + 0x43, 0x47, 0x50, 0x61, 0x43, 0x49, 0x49, 0x49, + 0x43, 0x4C, 0x54, 0x44, 0x43, 0x4C, 0xC2, 0xB7, + 0x43, 0x4D, 0x48, 0x7A, 0x43, 0x4D, 0x50, 0x61, + 0x43, 0x4D, 0xCE, 0xA9, 0x43, 0x50, 0x50, 0x4D, + // Bytes 1bc0 - 1bff + 0x43, 0x50, 0x50, 0x56, 0x43, 0x50, 0x54, 0x45, + 0x43, 0x54, 0x45, 0x4C, 0x43, 0x54, 0x48, 0x7A, + 0x43, 0x56, 0x49, 0x49, 0x43, 0x58, 0x49, 0x49, + 0x43, 0x61, 0x2F, 0x63, 0x43, 0x61, 0x2F, 0x73, + 0x43, 0x61, 0xCA, 0xBE, 0x43, 0x62, 0x61, 0x72, + 0x43, 0x63, 0x2F, 0x6F, 0x43, 0x63, 0x2F, 0x75, + 0x43, 0x63, 0x61, 0x6C, 0x43, 0x63, 0x6D, 0x32, + 0x43, 0x63, 0x6D, 0x33, 0x43, 0x64, 0x6D, 0x32, + // Bytes 1c00 - 1c3f + 0x43, 0x64, 0x6D, 0x33, 0x43, 0x65, 0x72, 0x67, + 0x43, 0x66, 0x66, 0x69, 0x43, 0x66, 0x66, 0x6C, + 0x43, 0x67, 0x61, 0x6C, 0x43, 0x68, 0x50, 0x61, + 0x43, 0x69, 0x69, 0x69, 0x43, 0x6B, 0x48, 0x7A, + 0x43, 0x6B, 0x50, 0x61, 0x43, 0x6B, 0x6D, 0x32, + 0x43, 0x6B, 0x6D, 0x33, 0x43, 0x6B, 0xCE, 0xA9, + 0x43, 0x6C, 0x6F, 0x67, 0x43, 0x6C, 0xC2, 0xB7, + 0x43, 0x6D, 0x69, 0x6C, 0x43, 0x6D, 0x6D, 0x32, + // Bytes 1c40 - 1c7f + 0x43, 0x6D, 0x6D, 0x33, 0x43, 0x6D, 0x6F, 0x6C, + 0x43, 0x72, 0x61, 0x64, 0x43, 0x76, 0x69, 0x69, + 0x43, 0x78, 0x69, 0x69, 0x43, 0xC2, 0xB0, 0x43, + 0x43, 0xC2, 0xB0, 0x46, 0x43, 0xCA, 0xBC, 0x6E, + 0x43, 0xCE, 0xBC, 0x41, 0x43, 0xCE, 0xBC, 0x46, + 0x43, 0xCE, 0xBC, 0x56, 0x43, 0xCE, 0xBC, 0x57, + 0x43, 0xCE, 0xBC, 0x67, 0x43, 0xCE, 0xBC, 0x6C, + 0x43, 0xCE, 0xBC, 0x6D, 0x43, 0xCE, 0xBC, 0x73, + // Bytes 1c80 - 1cbf + 0x44, 0x28, 0x31, 0x30, 0x29, 0x44, 0x28, 0x31, + 0x31, 0x29, 0x44, 0x28, 0x31, 0x32, 0x29, 0x44, + 0x28, 0x31, 0x33, 0x29, 0x44, 0x28, 0x31, 0x34, + 0x29, 0x44, 0x28, 0x31, 0x35, 0x29, 0x44, 0x28, + 0x31, 0x36, 0x29, 0x44, 0x28, 0x31, 0x37, 0x29, + 0x44, 0x28, 0x31, 0x38, 0x29, 0x44, 0x28, 0x31, + 0x39, 0x29, 0x44, 0x28, 0x32, 0x30, 0x29, 0x44, + 0x30, 0xE7, 0x82, 0xB9, 0x44, 0x31, 0xE2, 0x81, + // Bytes 1cc0 - 1cff + 0x84, 0x44, 0x31, 0xE6, 0x97, 0xA5, 0x44, 0x31, + 0xE6, 0x9C, 0x88, 0x44, 0x31, 0xE7, 0x82, 0xB9, + 0x44, 0x32, 0xE6, 0x97, 0xA5, 0x44, 0x32, 0xE6, + 0x9C, 0x88, 0x44, 0x32, 0xE7, 0x82, 0xB9, 0x44, + 0x33, 0xE6, 0x97, 0xA5, 0x44, 0x33, 0xE6, 0x9C, + 0x88, 0x44, 0x33, 0xE7, 0x82, 0xB9, 0x44, 0x34, + 0xE6, 0x97, 0xA5, 0x44, 0x34, 0xE6, 0x9C, 0x88, + 0x44, 0x34, 0xE7, 0x82, 0xB9, 0x44, 0x35, 0xE6, + // Bytes 1d00 - 1d3f + 0x97, 0xA5, 0x44, 0x35, 0xE6, 0x9C, 0x88, 0x44, + 0x35, 0xE7, 0x82, 0xB9, 0x44, 0x36, 0xE6, 0x97, + 0xA5, 0x44, 0x36, 0xE6, 0x9C, 0x88, 0x44, 0x36, + 0xE7, 0x82, 0xB9, 0x44, 0x37, 0xE6, 0x97, 0xA5, + 0x44, 0x37, 0xE6, 0x9C, 0x88, 0x44, 0x37, 0xE7, + 0x82, 0xB9, 0x44, 0x38, 0xE6, 0x97, 0xA5, 0x44, + 0x38, 0xE6, 0x9C, 0x88, 0x44, 0x38, 0xE7, 0x82, + 0xB9, 0x44, 0x39, 0xE6, 0x97, 0xA5, 0x44, 0x39, + // Bytes 1d40 - 1d7f + 0xE6, 0x9C, 0x88, 0x44, 0x39, 0xE7, 0x82, 0xB9, + 0x44, 0x56, 0x49, 0x49, 0x49, 0x44, 0x61, 0x2E, + 0x6D, 0x2E, 0x44, 0x6B, 0x63, 0x61, 0x6C, 0x44, + 0x70, 0x2E, 0x6D, 0x2E, 0x44, 0x76, 0x69, 0x69, + 0x69, 0x44, 0xD5, 0xA5, 0xD6, 0x82, 0x44, 0xD5, + 0xB4, 0xD5, 0xA5, 0x44, 0xD5, 0xB4, 0xD5, 0xAB, + 0x44, 0xD5, 0xB4, 0xD5, 0xAD, 0x44, 0xD5, 0xB4, + 0xD5, 0xB6, 0x44, 0xD5, 0xBE, 0xD5, 0xB6, 0x44, + // Bytes 1d80 - 1dbf + 0xD7, 0x90, 0xD7, 0x9C, 0x44, 0xD8, 0xA7, 0xD9, + 0xB4, 0x44, 0xD8, 0xA8, 0xD8, 0xAC, 0x44, 0xD8, + 0xA8, 0xD8, 0xAD, 0x44, 0xD8, 0xA8, 0xD8, 0xAE, + 0x44, 0xD8, 0xA8, 0xD8, 0xB1, 0x44, 0xD8, 0xA8, + 0xD8, 0xB2, 0x44, 0xD8, 0xA8, 0xD9, 0x85, 0x44, + 0xD8, 0xA8, 0xD9, 0x86, 0x44, 0xD8, 0xA8, 0xD9, + 0x87, 0x44, 0xD8, 0xA8, 0xD9, 0x89, 0x44, 0xD8, + 0xA8, 0xD9, 0x8A, 0x44, 0xD8, 0xAA, 0xD8, 0xAC, + // Bytes 1dc0 - 1dff + 0x44, 0xD8, 0xAA, 0xD8, 0xAD, 0x44, 0xD8, 0xAA, + 0xD8, 0xAE, 0x44, 0xD8, 0xAA, 0xD8, 0xB1, 0x44, + 0xD8, 0xAA, 0xD8, 0xB2, 0x44, 0xD8, 0xAA, 0xD9, + 0x85, 0x44, 0xD8, 0xAA, 0xD9, 0x86, 0x44, 0xD8, + 0xAA, 0xD9, 0x87, 0x44, 0xD8, 0xAA, 0xD9, 0x89, + 0x44, 0xD8, 0xAA, 0xD9, 0x8A, 0x44, 0xD8, 0xAB, + 0xD8, 0xAC, 0x44, 0xD8, 0xAB, 0xD8, 0xB1, 0x44, + 0xD8, 0xAB, 0xD8, 0xB2, 0x44, 0xD8, 0xAB, 0xD9, + // Bytes 1e00 - 1e3f + 0x85, 0x44, 0xD8, 0xAB, 0xD9, 0x86, 0x44, 0xD8, + 0xAB, 0xD9, 0x87, 0x44, 0xD8, 0xAB, 0xD9, 0x89, + 0x44, 0xD8, 0xAB, 0xD9, 0x8A, 0x44, 0xD8, 0xAC, + 0xD8, 0xAD, 0x44, 0xD8, 0xAC, 0xD9, 0x85, 0x44, + 0xD8, 0xAC, 0xD9, 0x89, 0x44, 0xD8, 0xAC, 0xD9, + 0x8A, 0x44, 0xD8, 0xAD, 0xD8, 0xAC, 0x44, 0xD8, + 0xAD, 0xD9, 0x85, 0x44, 0xD8, 0xAD, 0xD9, 0x89, + 0x44, 0xD8, 0xAD, 0xD9, 0x8A, 0x44, 0xD8, 0xAE, + // Bytes 1e40 - 1e7f + 0xD8, 0xAC, 0x44, 0xD8, 0xAE, 0xD8, 0xAD, 0x44, + 0xD8, 0xAE, 0xD9, 0x85, 0x44, 0xD8, 0xAE, 0xD9, + 0x89, 0x44, 0xD8, 0xAE, 0xD9, 0x8A, 0x44, 0xD8, + 0xB3, 0xD8, 0xAC, 0x44, 0xD8, 0xB3, 0xD8, 0xAD, + 0x44, 0xD8, 0xB3, 0xD8, 0xAE, 0x44, 0xD8, 0xB3, + 0xD8, 0xB1, 0x44, 0xD8, 0xB3, 0xD9, 0x85, 0x44, + 0xD8, 0xB3, 0xD9, 0x87, 0x44, 0xD8, 0xB3, 0xD9, + 0x89, 0x44, 0xD8, 0xB3, 0xD9, 0x8A, 0x44, 0xD8, + // Bytes 1e80 - 1ebf + 0xB4, 0xD8, 0xAC, 0x44, 0xD8, 0xB4, 0xD8, 0xAD, + 0x44, 0xD8, 0xB4, 0xD8, 0xAE, 0x44, 0xD8, 0xB4, + 0xD8, 0xB1, 0x44, 0xD8, 0xB4, 0xD9, 0x85, 0x44, + 0xD8, 0xB4, 0xD9, 0x87, 0x44, 0xD8, 0xB4, 0xD9, + 0x89, 0x44, 0xD8, 0xB4, 0xD9, 0x8A, 0x44, 0xD8, + 0xB5, 0xD8, 0xAD, 0x44, 0xD8, 0xB5, 0xD8, 0xAE, + 0x44, 0xD8, 0xB5, 0xD8, 0xB1, 0x44, 0xD8, 0xB5, + 0xD9, 0x85, 0x44, 0xD8, 0xB5, 0xD9, 0x89, 0x44, + // Bytes 1ec0 - 1eff + 0xD8, 0xB5, 0xD9, 0x8A, 0x44, 0xD8, 0xB6, 0xD8, + 0xAC, 0x44, 0xD8, 0xB6, 0xD8, 0xAD, 0x44, 0xD8, + 0xB6, 0xD8, 0xAE, 0x44, 0xD8, 0xB6, 0xD8, 0xB1, + 0x44, 0xD8, 0xB6, 0xD9, 0x85, 0x44, 0xD8, 0xB6, + 0xD9, 0x89, 0x44, 0xD8, 0xB6, 0xD9, 0x8A, 0x44, + 0xD8, 0xB7, 0xD8, 0xAD, 0x44, 0xD8, 0xB7, 0xD9, + 0x85, 0x44, 0xD8, 0xB7, 0xD9, 0x89, 0x44, 0xD8, + 0xB7, 0xD9, 0x8A, 0x44, 0xD8, 0xB8, 0xD9, 0x85, + // Bytes 1f00 - 1f3f + 0x44, 0xD8, 0xB9, 0xD8, 0xAC, 0x44, 0xD8, 0xB9, + 0xD9, 0x85, 0x44, 0xD8, 0xB9, 0xD9, 0x89, 0x44, + 0xD8, 0xB9, 0xD9, 0x8A, 0x44, 0xD8, 0xBA, 0xD8, + 0xAC, 0x44, 0xD8, 0xBA, 0xD9, 0x85, 0x44, 0xD8, + 0xBA, 0xD9, 0x89, 0x44, 0xD8, 0xBA, 0xD9, 0x8A, + 0x44, 0xD9, 0x81, 0xD8, 0xAC, 0x44, 0xD9, 0x81, + 0xD8, 0xAD, 0x44, 0xD9, 0x81, 0xD8, 0xAE, 0x44, + 0xD9, 0x81, 0xD9, 0x85, 0x44, 0xD9, 0x81, 0xD9, + // Bytes 1f40 - 1f7f + 0x89, 0x44, 0xD9, 0x81, 0xD9, 0x8A, 0x44, 0xD9, + 0x82, 0xD8, 0xAD, 0x44, 0xD9, 0x82, 0xD9, 0x85, + 0x44, 0xD9, 0x82, 0xD9, 0x89, 0x44, 0xD9, 0x82, + 0xD9, 0x8A, 0x44, 0xD9, 0x83, 0xD8, 0xA7, 0x44, + 0xD9, 0x83, 0xD8, 0xAC, 0x44, 0xD9, 0x83, 0xD8, + 0xAD, 0x44, 0xD9, 0x83, 0xD8, 0xAE, 0x44, 0xD9, + 0x83, 0xD9, 0x84, 0x44, 0xD9, 0x83, 0xD9, 0x85, + 0x44, 0xD9, 0x83, 0xD9, 0x89, 0x44, 0xD9, 0x83, + // Bytes 1f80 - 1fbf + 0xD9, 0x8A, 0x44, 0xD9, 0x84, 0xD8, 0xA7, 0x44, + 0xD9, 0x84, 0xD8, 0xAC, 0x44, 0xD9, 0x84, 0xD8, + 0xAD, 0x44, 0xD9, 0x84, 0xD8, 0xAE, 0x44, 0xD9, + 0x84, 0xD9, 0x85, 0x44, 0xD9, 0x84, 0xD9, 0x87, + 0x44, 0xD9, 0x84, 0xD9, 0x89, 0x44, 0xD9, 0x84, + 0xD9, 0x8A, 0x44, 0xD9, 0x85, 0xD8, 0xA7, 0x44, + 0xD9, 0x85, 0xD8, 0xAC, 0x44, 0xD9, 0x85, 0xD8, + 0xAD, 0x44, 0xD9, 0x85, 0xD8, 0xAE, 0x44, 0xD9, + // Bytes 1fc0 - 1fff + 0x85, 0xD9, 0x85, 0x44, 0xD9, 0x85, 0xD9, 0x89, + 0x44, 0xD9, 0x85, 0xD9, 0x8A, 0x44, 0xD9, 0x86, + 0xD8, 0xAC, 0x44, 0xD9, 0x86, 0xD8, 0xAD, 0x44, + 0xD9, 0x86, 0xD8, 0xAE, 0x44, 0xD9, 0x86, 0xD8, + 0xB1, 0x44, 0xD9, 0x86, 0xD8, 0xB2, 0x44, 0xD9, + 0x86, 0xD9, 0x85, 0x44, 0xD9, 0x86, 0xD9, 0x86, + 0x44, 0xD9, 0x86, 0xD9, 0x87, 0x44, 0xD9, 0x86, + 0xD9, 0x89, 0x44, 0xD9, 0x86, 0xD9, 0x8A, 0x44, + // Bytes 2000 - 203f + 0xD9, 0x87, 0xD8, 0xAC, 0x44, 0xD9, 0x87, 0xD9, + 0x85, 0x44, 0xD9, 0x87, 0xD9, 0x89, 0x44, 0xD9, + 0x87, 0xD9, 0x8A, 0x44, 0xD9, 0x88, 0xD9, 0xB4, + 0x44, 0xD9, 0x8A, 0xD8, 0xAC, 0x44, 0xD9, 0x8A, + 0xD8, 0xAD, 0x44, 0xD9, 0x8A, 0xD8, 0xAE, 0x44, + 0xD9, 0x8A, 0xD8, 0xB1, 0x44, 0xD9, 0x8A, 0xD8, + 0xB2, 0x44, 0xD9, 0x8A, 0xD9, 0x85, 0x44, 0xD9, + 0x8A, 0xD9, 0x86, 0x44, 0xD9, 0x8A, 0xD9, 0x87, + // Bytes 2040 - 207f + 0x44, 0xD9, 0x8A, 0xD9, 0x89, 0x44, 0xD9, 0x8A, + 0xD9, 0x8A, 0x44, 0xD9, 0x8A, 0xD9, 0xB4, 0x44, + 0xDB, 0x87, 0xD9, 0xB4, 0x45, 0x28, 0xE1, 0x84, + 0x80, 0x29, 0x45, 0x28, 0xE1, 0x84, 0x82, 0x29, + 0x45, 0x28, 0xE1, 0x84, 0x83, 0x29, 0x45, 0x28, + 0xE1, 0x84, 0x85, 0x29, 0x45, 0x28, 0xE1, 0x84, + 0x86, 0x29, 0x45, 0x28, 0xE1, 0x84, 0x87, 0x29, + 0x45, 0x28, 0xE1, 0x84, 0x89, 0x29, 0x45, 0x28, + // Bytes 2080 - 20bf + 0xE1, 0x84, 0x8B, 0x29, 0x45, 0x28, 0xE1, 0x84, + 0x8C, 0x29, 0x45, 0x28, 0xE1, 0x84, 0x8E, 0x29, + 0x45, 0x28, 0xE1, 0x84, 0x8F, 0x29, 0x45, 0x28, + 0xE1, 0x84, 0x90, 0x29, 0x45, 0x28, 0xE1, 0x84, + 0x91, 0x29, 0x45, 0x28, 0xE1, 0x84, 0x92, 0x29, + 0x45, 0x28, 0xE4, 0xB8, 0x80, 0x29, 0x45, 0x28, + 0xE4, 0xB8, 0x83, 0x29, 0x45, 0x28, 0xE4, 0xB8, + 0x89, 0x29, 0x45, 0x28, 0xE4, 0xB9, 0x9D, 0x29, + // Bytes 20c0 - 20ff + 0x45, 0x28, 0xE4, 0xBA, 0x8C, 0x29, 0x45, 0x28, + 0xE4, 0xBA, 0x94, 0x29, 0x45, 0x28, 0xE4, 0xBB, + 0xA3, 0x29, 0x45, 0x28, 0xE4, 0xBC, 0x81, 0x29, + 0x45, 0x28, 0xE4, 0xBC, 0x91, 0x29, 0x45, 0x28, + 0xE5, 0x85, 0xAB, 0x29, 0x45, 0x28, 0xE5, 0x85, + 0xAD, 0x29, 0x45, 0x28, 0xE5, 0x8A, 0xB4, 0x29, + 0x45, 0x28, 0xE5, 0x8D, 0x81, 0x29, 0x45, 0x28, + 0xE5, 0x8D, 0x94, 0x29, 0x45, 0x28, 0xE5, 0x90, + // Bytes 2100 - 213f + 0x8D, 0x29, 0x45, 0x28, 0xE5, 0x91, 0xBC, 0x29, + 0x45, 0x28, 0xE5, 0x9B, 0x9B, 0x29, 0x45, 0x28, + 0xE5, 0x9C, 0x9F, 0x29, 0x45, 0x28, 0xE5, 0xAD, + 0xA6, 0x29, 0x45, 0x28, 0xE6, 0x97, 0xA5, 0x29, + 0x45, 0x28, 0xE6, 0x9C, 0x88, 0x29, 0x45, 0x28, + 0xE6, 0x9C, 0x89, 0x29, 0x45, 0x28, 0xE6, 0x9C, + 0xA8, 0x29, 0x45, 0x28, 0xE6, 0xA0, 0xAA, 0x29, + 0x45, 0x28, 0xE6, 0xB0, 0xB4, 0x29, 0x45, 0x28, + // Bytes 2140 - 217f + 0xE7, 0x81, 0xAB, 0x29, 0x45, 0x28, 0xE7, 0x89, + 0xB9, 0x29, 0x45, 0x28, 0xE7, 0x9B, 0xA3, 0x29, + 0x45, 0x28, 0xE7, 0xA4, 0xBE, 0x29, 0x45, 0x28, + 0xE7, 0xA5, 0x9D, 0x29, 0x45, 0x28, 0xE7, 0xA5, + 0xAD, 0x29, 0x45, 0x28, 0xE8, 0x87, 0xAA, 0x29, + 0x45, 0x28, 0xE8, 0x87, 0xB3, 0x29, 0x45, 0x28, + 0xE8, 0xB2, 0xA1, 0x29, 0x45, 0x28, 0xE8, 0xB3, + 0x87, 0x29, 0x45, 0x28, 0xE9, 0x87, 0x91, 0x29, + // Bytes 2180 - 21bf + 0x45, 0x30, 0xE2, 0x81, 0x84, 0x33, 0x45, 0x31, + 0x30, 0xE6, 0x97, 0xA5, 0x45, 0x31, 0x30, 0xE6, + 0x9C, 0x88, 0x45, 0x31, 0x30, 0xE7, 0x82, 0xB9, + 0x45, 0x31, 0x31, 0xE6, 0x97, 0xA5, 0x45, 0x31, + 0x31, 0xE6, 0x9C, 0x88, 0x45, 0x31, 0x31, 0xE7, + 0x82, 0xB9, 0x45, 0x31, 0x32, 0xE6, 0x97, 0xA5, + 0x45, 0x31, 0x32, 0xE6, 0x9C, 0x88, 0x45, 0x31, + 0x32, 0xE7, 0x82, 0xB9, 0x45, 0x31, 0x33, 0xE6, + // Bytes 21c0 - 21ff + 0x97, 0xA5, 0x45, 0x31, 0x33, 0xE7, 0x82, 0xB9, + 0x45, 0x31, 0x34, 0xE6, 0x97, 0xA5, 0x45, 0x31, + 0x34, 0xE7, 0x82, 0xB9, 0x45, 0x31, 0x35, 0xE6, + 0x97, 0xA5, 0x45, 0x31, 0x35, 0xE7, 0x82, 0xB9, + 0x45, 0x31, 0x36, 0xE6, 0x97, 0xA5, 0x45, 0x31, + 0x36, 0xE7, 0x82, 0xB9, 0x45, 0x31, 0x37, 0xE6, + 0x97, 0xA5, 0x45, 0x31, 0x37, 0xE7, 0x82, 0xB9, + 0x45, 0x31, 0x38, 0xE6, 0x97, 0xA5, 0x45, 0x31, + // Bytes 2200 - 223f + 0x38, 0xE7, 0x82, 0xB9, 0x45, 0x31, 0x39, 0xE6, + 0x97, 0xA5, 0x45, 0x31, 0x39, 0xE7, 0x82, 0xB9, + 0x45, 0x31, 0xE2, 0x81, 0x84, 0x32, 0x45, 0x31, + 0xE2, 0x81, 0x84, 0x33, 0x45, 0x31, 0xE2, 0x81, + 0x84, 0x34, 0x45, 0x31, 0xE2, 0x81, 0x84, 0x35, + 0x45, 0x31, 0xE2, 0x81, 0x84, 0x36, 0x45, 0x31, + 0xE2, 0x81, 0x84, 0x37, 0x45, 0x31, 0xE2, 0x81, + 0x84, 0x38, 0x45, 0x31, 0xE2, 0x81, 0x84, 0x39, + // Bytes 2240 - 227f + 0x45, 0x32, 0x30, 0xE6, 0x97, 0xA5, 0x45, 0x32, + 0x30, 0xE7, 0x82, 0xB9, 0x45, 0x32, 0x31, 0xE6, + 0x97, 0xA5, 0x45, 0x32, 0x31, 0xE7, 0x82, 0xB9, + 0x45, 0x32, 0x32, 0xE6, 0x97, 0xA5, 0x45, 0x32, + 0x32, 0xE7, 0x82, 0xB9, 0x45, 0x32, 0x33, 0xE6, + 0x97, 0xA5, 0x45, 0x32, 0x33, 0xE7, 0x82, 0xB9, + 0x45, 0x32, 0x34, 0xE6, 0x97, 0xA5, 0x45, 0x32, + 0x34, 0xE7, 0x82, 0xB9, 0x45, 0x32, 0x35, 0xE6, + // Bytes 2280 - 22bf + 0x97, 0xA5, 0x45, 0x32, 0x36, 0xE6, 0x97, 0xA5, + 0x45, 0x32, 0x37, 0xE6, 0x97, 0xA5, 0x45, 0x32, + 0x38, 0xE6, 0x97, 0xA5, 0x45, 0x32, 0x39, 0xE6, + 0x97, 0xA5, 0x45, 0x32, 0xE2, 0x81, 0x84, 0x33, + 0x45, 0x32, 0xE2, 0x81, 0x84, 0x35, 0x45, 0x33, + 0x30, 0xE6, 0x97, 0xA5, 0x45, 0x33, 0x31, 0xE6, + 0x97, 0xA5, 0x45, 0x33, 0xE2, 0x81, 0x84, 0x34, + 0x45, 0x33, 0xE2, 0x81, 0x84, 0x35, 0x45, 0x33, + // Bytes 22c0 - 22ff + 0xE2, 0x81, 0x84, 0x38, 0x45, 0x34, 0xE2, 0x81, + 0x84, 0x35, 0x45, 0x35, 0xE2, 0x81, 0x84, 0x36, + 0x45, 0x35, 0xE2, 0x81, 0x84, 0x38, 0x45, 0x37, + 0xE2, 0x81, 0x84, 0x38, 0x45, 0x41, 0xE2, 0x88, + 0x95, 0x6D, 0x45, 0x56, 0xE2, 0x88, 0x95, 0x6D, + 0x45, 0x6D, 0xE2, 0x88, 0x95, 0x73, 0x46, 0x31, + 0xE2, 0x81, 0x84, 0x31, 0x30, 0x46, 0x43, 0xE2, + 0x88, 0x95, 0x6B, 0x67, 0x46, 0x6D, 0xE2, 0x88, + // Bytes 2300 - 233f + 0x95, 0x73, 0x32, 0x46, 0xD8, 0xA8, 0xD8, 0xAD, + 0xD9, 0x8A, 0x46, 0xD8, 0xA8, 0xD8, 0xAE, 0xD9, + 0x8A, 0x46, 0xD8, 0xAA, 0xD8, 0xAC, 0xD9, 0x85, + 0x46, 0xD8, 0xAA, 0xD8, 0xAC, 0xD9, 0x89, 0x46, + 0xD8, 0xAA, 0xD8, 0xAC, 0xD9, 0x8A, 0x46, 0xD8, + 0xAA, 0xD8, 0xAD, 0xD8, 0xAC, 0x46, 0xD8, 0xAA, + 0xD8, 0xAD, 0xD9, 0x85, 0x46, 0xD8, 0xAA, 0xD8, + 0xAE, 0xD9, 0x85, 0x46, 0xD8, 0xAA, 0xD8, 0xAE, + // Bytes 2340 - 237f + 0xD9, 0x89, 0x46, 0xD8, 0xAA, 0xD8, 0xAE, 0xD9, + 0x8A, 0x46, 0xD8, 0xAA, 0xD9, 0x85, 0xD8, 0xAC, + 0x46, 0xD8, 0xAA, 0xD9, 0x85, 0xD8, 0xAD, 0x46, + 0xD8, 0xAA, 0xD9, 0x85, 0xD8, 0xAE, 0x46, 0xD8, + 0xAA, 0xD9, 0x85, 0xD9, 0x89, 0x46, 0xD8, 0xAA, + 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD8, 0xAC, 0xD8, + 0xAD, 0xD9, 0x89, 0x46, 0xD8, 0xAC, 0xD8, 0xAD, + 0xD9, 0x8A, 0x46, 0xD8, 0xAC, 0xD9, 0x85, 0xD8, + // Bytes 2380 - 23bf + 0xAD, 0x46, 0xD8, 0xAC, 0xD9, 0x85, 0xD9, 0x89, + 0x46, 0xD8, 0xAC, 0xD9, 0x85, 0xD9, 0x8A, 0x46, + 0xD8, 0xAD, 0xD8, 0xAC, 0xD9, 0x8A, 0x46, 0xD8, + 0xAD, 0xD9, 0x85, 0xD9, 0x89, 0x46, 0xD8, 0xAD, + 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD8, 0xB3, 0xD8, + 0xAC, 0xD8, 0xAD, 0x46, 0xD8, 0xB3, 0xD8, 0xAC, + 0xD9, 0x89, 0x46, 0xD8, 0xB3, 0xD8, 0xAD, 0xD8, + 0xAC, 0x46, 0xD8, 0xB3, 0xD8, 0xAE, 0xD9, 0x89, + // Bytes 23c0 - 23ff + 0x46, 0xD8, 0xB3, 0xD8, 0xAE, 0xD9, 0x8A, 0x46, + 0xD8, 0xB3, 0xD9, 0x85, 0xD8, 0xAC, 0x46, 0xD8, + 0xB3, 0xD9, 0x85, 0xD8, 0xAD, 0x46, 0xD8, 0xB3, + 0xD9, 0x85, 0xD9, 0x85, 0x46, 0xD8, 0xB4, 0xD8, + 0xAC, 0xD9, 0x8A, 0x46, 0xD8, 0xB4, 0xD8, 0xAD, + 0xD9, 0x85, 0x46, 0xD8, 0xB4, 0xD8, 0xAD, 0xD9, + 0x8A, 0x46, 0xD8, 0xB4, 0xD9, 0x85, 0xD8, 0xAE, + 0x46, 0xD8, 0xB4, 0xD9, 0x85, 0xD9, 0x85, 0x46, + // Bytes 2400 - 243f + 0xD8, 0xB5, 0xD8, 0xAD, 0xD8, 0xAD, 0x46, 0xD8, + 0xB5, 0xD8, 0xAD, 0xD9, 0x8A, 0x46, 0xD8, 0xB5, + 0xD9, 0x84, 0xD9, 0x89, 0x46, 0xD8, 0xB5, 0xD9, + 0x84, 0xDB, 0x92, 0x46, 0xD8, 0xB5, 0xD9, 0x85, + 0xD9, 0x85, 0x46, 0xD8, 0xB6, 0xD8, 0xAD, 0xD9, + 0x89, 0x46, 0xD8, 0xB6, 0xD8, 0xAD, 0xD9, 0x8A, + 0x46, 0xD8, 0xB6, 0xD8, 0xAE, 0xD9, 0x85, 0x46, + 0xD8, 0xB7, 0xD9, 0x85, 0xD8, 0xAD, 0x46, 0xD8, + // Bytes 2440 - 247f + 0xB7, 0xD9, 0x85, 0xD9, 0x85, 0x46, 0xD8, 0xB7, + 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD8, 0xB9, 0xD8, + 0xAC, 0xD9, 0x85, 0x46, 0xD8, 0xB9, 0xD9, 0x85, + 0xD9, 0x85, 0x46, 0xD8, 0xB9, 0xD9, 0x85, 0xD9, + 0x89, 0x46, 0xD8, 0xB9, 0xD9, 0x85, 0xD9, 0x8A, + 0x46, 0xD8, 0xBA, 0xD9, 0x85, 0xD9, 0x85, 0x46, + 0xD8, 0xBA, 0xD9, 0x85, 0xD9, 0x89, 0x46, 0xD8, + 0xBA, 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD9, 0x81, + // Bytes 2480 - 24bf + 0xD8, 0xAE, 0xD9, 0x85, 0x46, 0xD9, 0x81, 0xD9, + 0x85, 0xD9, 0x8A, 0x46, 0xD9, 0x82, 0xD9, 0x84, + 0xDB, 0x92, 0x46, 0xD9, 0x82, 0xD9, 0x85, 0xD8, + 0xAD, 0x46, 0xD9, 0x82, 0xD9, 0x85, 0xD9, 0x85, + 0x46, 0xD9, 0x82, 0xD9, 0x85, 0xD9, 0x8A, 0x46, + 0xD9, 0x83, 0xD9, 0x85, 0xD9, 0x85, 0x46, 0xD9, + 0x83, 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD9, 0x84, + 0xD8, 0xAC, 0xD8, 0xAC, 0x46, 0xD9, 0x84, 0xD8, + // Bytes 24c0 - 24ff + 0xAC, 0xD9, 0x85, 0x46, 0xD9, 0x84, 0xD8, 0xAC, + 0xD9, 0x8A, 0x46, 0xD9, 0x84, 0xD8, 0xAD, 0xD9, + 0x85, 0x46, 0xD9, 0x84, 0xD8, 0xAD, 0xD9, 0x89, + 0x46, 0xD9, 0x84, 0xD8, 0xAD, 0xD9, 0x8A, 0x46, + 0xD9, 0x84, 0xD8, 0xAE, 0xD9, 0x85, 0x46, 0xD9, + 0x84, 0xD9, 0x85, 0xD8, 0xAD, 0x46, 0xD9, 0x84, + 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD9, 0x85, 0xD8, + 0xAC, 0xD8, 0xAD, 0x46, 0xD9, 0x85, 0xD8, 0xAC, + // Bytes 2500 - 253f + 0xD8, 0xAE, 0x46, 0xD9, 0x85, 0xD8, 0xAC, 0xD9, + 0x85, 0x46, 0xD9, 0x85, 0xD8, 0xAC, 0xD9, 0x8A, + 0x46, 0xD9, 0x85, 0xD8, 0xAD, 0xD8, 0xAC, 0x46, + 0xD9, 0x85, 0xD8, 0xAD, 0xD9, 0x85, 0x46, 0xD9, + 0x85, 0xD8, 0xAD, 0xD9, 0x8A, 0x46, 0xD9, 0x85, + 0xD8, 0xAE, 0xD8, 0xAC, 0x46, 0xD9, 0x85, 0xD8, + 0xAE, 0xD9, 0x85, 0x46, 0xD9, 0x85, 0xD8, 0xAE, + 0xD9, 0x8A, 0x46, 0xD9, 0x85, 0xD9, 0x85, 0xD9, + // Bytes 2540 - 257f + 0x8A, 0x46, 0xD9, 0x86, 0xD8, 0xAC, 0xD8, 0xAD, + 0x46, 0xD9, 0x86, 0xD8, 0xAC, 0xD9, 0x85, 0x46, + 0xD9, 0x86, 0xD8, 0xAC, 0xD9, 0x89, 0x46, 0xD9, + 0x86, 0xD8, 0xAC, 0xD9, 0x8A, 0x46, 0xD9, 0x86, + 0xD8, 0xAD, 0xD9, 0x85, 0x46, 0xD9, 0x86, 0xD8, + 0xAD, 0xD9, 0x89, 0x46, 0xD9, 0x86, 0xD8, 0xAD, + 0xD9, 0x8A, 0x46, 0xD9, 0x86, 0xD9, 0x85, 0xD9, + 0x89, 0x46, 0xD9, 0x86, 0xD9, 0x85, 0xD9, 0x8A, + // Bytes 2580 - 25bf + 0x46, 0xD9, 0x87, 0xD9, 0x85, 0xD8, 0xAC, 0x46, + 0xD9, 0x87, 0xD9, 0x85, 0xD9, 0x85, 0x46, 0xD9, + 0x8A, 0xD8, 0xAC, 0xD9, 0x8A, 0x46, 0xD9, 0x8A, + 0xD8, 0xAD, 0xD9, 0x8A, 0x46, 0xD9, 0x8A, 0xD9, + 0x85, 0xD9, 0x85, 0x46, 0xD9, 0x8A, 0xD9, 0x85, + 0xD9, 0x8A, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD8, + 0xA7, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xAC, + 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xAD, 0x46, + // Bytes 25c0 - 25ff + 0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xAE, 0x46, 0xD9, + 0x8A, 0xD9, 0x94, 0xD8, 0xB1, 0x46, 0xD9, 0x8A, + 0xD9, 0x94, 0xD8, 0xB2, 0x46, 0xD9, 0x8A, 0xD9, + 0x94, 0xD9, 0x85, 0x46, 0xD9, 0x8A, 0xD9, 0x94, + 0xD9, 0x86, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD9, + 0x87, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x88, + 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x89, 0x46, + 0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x8A, 0x46, 0xD9, + // Bytes 2600 - 263f + 0x8A, 0xD9, 0x94, 0xDB, 0x86, 0x46, 0xD9, 0x8A, + 0xD9, 0x94, 0xDB, 0x87, 0x46, 0xD9, 0x8A, 0xD9, + 0x94, 0xDB, 0x88, 0x46, 0xD9, 0x8A, 0xD9, 0x94, + 0xDB, 0x90, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xDB, + 0x95, 0x46, 0xE0, 0xB9, 0x8D, 0xE0, 0xB8, 0xB2, + 0x46, 0xE0, 0xBA, 0xAB, 0xE0, 0xBA, 0x99, 0x46, + 0xE0, 0xBA, 0xAB, 0xE0, 0xBA, 0xA1, 0x46, 0xE0, + 0xBB, 0x8D, 0xE0, 0xBA, 0xB2, 0x46, 0xE0, 0xBD, + // Bytes 2640 - 267f + 0x80, 0xE0, 0xBE, 0xB5, 0x46, 0xE0, 0xBD, 0x82, + 0xE0, 0xBE, 0xB7, 0x46, 0xE0, 0xBD, 0x8C, 0xE0, + 0xBE, 0xB7, 0x46, 0xE0, 0xBD, 0x91, 0xE0, 0xBE, + 0xB7, 0x46, 0xE0, 0xBD, 0x96, 0xE0, 0xBE, 0xB7, + 0x46, 0xE0, 0xBD, 0x9B, 0xE0, 0xBE, 0xB7, 0x46, + 0xE0, 0xBE, 0x90, 0xE0, 0xBE, 0xB5, 0x46, 0xE0, + 0xBE, 0x92, 0xE0, 0xBE, 0xB7, 0x46, 0xE0, 0xBE, + 0x9C, 0xE0, 0xBE, 0xB7, 0x46, 0xE0, 0xBE, 0xA1, + // Bytes 2680 - 26bf + 0xE0, 0xBE, 0xB7, 0x46, 0xE0, 0xBE, 0xA6, 0xE0, + 0xBE, 0xB7, 0x46, 0xE0, 0xBE, 0xAB, 0xE0, 0xBE, + 0xB7, 0x46, 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2, + 0x46, 0xE2, 0x80, 0xB5, 0xE2, 0x80, 0xB5, 0x46, + 0xE2, 0x88, 0xAB, 0xE2, 0x88, 0xAB, 0x46, 0xE2, + 0x88, 0xAE, 0xE2, 0x88, 0xAE, 0x46, 0xE3, 0x81, + 0xBB, 0xE3, 0x81, 0x8B, 0x46, 0xE3, 0x82, 0x88, + 0xE3, 0x82, 0x8A, 0x46, 0xE3, 0x82, 0xAD, 0xE3, + // Bytes 26c0 - 26ff + 0x83, 0xAD, 0x46, 0xE3, 0x82, 0xB3, 0xE3, 0x82, + 0xB3, 0x46, 0xE3, 0x82, 0xB3, 0xE3, 0x83, 0x88, + 0x46, 0xE3, 0x83, 0x88, 0xE3, 0x83, 0xB3, 0x46, + 0xE3, 0x83, 0x8A, 0xE3, 0x83, 0x8E, 0x46, 0xE3, + 0x83, 0x9B, 0xE3, 0x83, 0xB3, 0x46, 0xE3, 0x83, + 0x9F, 0xE3, 0x83, 0xAA, 0x46, 0xE3, 0x83, 0xAA, + 0xE3, 0x83, 0xA9, 0x46, 0xE3, 0x83, 0xAC, 0xE3, + 0x83, 0xA0, 0x46, 0xE5, 0xA4, 0xA7, 0xE6, 0xAD, + // Bytes 2700 - 273f + 0xA3, 0x46, 0xE5, 0xB9, 0xB3, 0xE6, 0x88, 0x90, + 0x46, 0xE6, 0x98, 0x8E, 0xE6, 0xB2, 0xBB, 0x46, + 0xE6, 0x98, 0xAD, 0xE5, 0x92, 0x8C, 0x47, 0x72, + 0x61, 0x64, 0xE2, 0x88, 0x95, 0x73, 0x47, 0xE3, + 0x80, 0x94, 0x53, 0xE3, 0x80, 0x95, 0x48, 0x28, + 0xE1, 0x84, 0x80, 0xE1, 0x85, 0xA1, 0x29, 0x48, + 0x28, 0xE1, 0x84, 0x82, 0xE1, 0x85, 0xA1, 0x29, + 0x48, 0x28, 0xE1, 0x84, 0x83, 0xE1, 0x85, 0xA1, + // Bytes 2740 - 277f + 0x29, 0x48, 0x28, 0xE1, 0x84, 0x85, 0xE1, 0x85, + 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, 0x86, 0xE1, + 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, 0x87, + 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, + 0x89, 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, + 0x84, 0x8B, 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28, + 0xE1, 0x84, 0x8C, 0xE1, 0x85, 0xA1, 0x29, 0x48, + 0x28, 0xE1, 0x84, 0x8C, 0xE1, 0x85, 0xAE, 0x29, + // Bytes 2780 - 27bf + 0x48, 0x28, 0xE1, 0x84, 0x8E, 0xE1, 0x85, 0xA1, + 0x29, 0x48, 0x28, 0xE1, 0x84, 0x8F, 0xE1, 0x85, + 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, 0x90, 0xE1, + 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, 0x91, + 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, + 0x92, 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x72, 0x61, + 0x64, 0xE2, 0x88, 0x95, 0x73, 0x32, 0x48, 0xD8, + 0xA7, 0xD9, 0x83, 0xD8, 0xA8, 0xD8, 0xB1, 0x48, + // Bytes 27c0 - 27ff + 0xD8, 0xA7, 0xD9, 0x84, 0xD9, 0x84, 0xD9, 0x87, + 0x48, 0xD8, 0xB1, 0xD8, 0xB3, 0xD9, 0x88, 0xD9, + 0x84, 0x48, 0xD8, 0xB1, 0xDB, 0x8C, 0xD8, 0xA7, + 0xD9, 0x84, 0x48, 0xD8, 0xB5, 0xD9, 0x84, 0xD8, + 0xB9, 0xD9, 0x85, 0x48, 0xD8, 0xB9, 0xD9, 0x84, + 0xD9, 0x8A, 0xD9, 0x87, 0x48, 0xD9, 0x85, 0xD8, + 0xAD, 0xD9, 0x85, 0xD8, 0xAF, 0x48, 0xD9, 0x88, + 0xD8, 0xB3, 0xD9, 0x84, 0xD9, 0x85, 0x49, 0xE2, + // Bytes 2800 - 283f + 0x80, 0xB2, 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2, + 0x49, 0xE2, 0x80, 0xB5, 0xE2, 0x80, 0xB5, 0xE2, + 0x80, 0xB5, 0x49, 0xE2, 0x88, 0xAB, 0xE2, 0x88, + 0xAB, 0xE2, 0x88, 0xAB, 0x49, 0xE2, 0x88, 0xAE, + 0xE2, 0x88, 0xAE, 0xE2, 0x88, 0xAE, 0x49, 0xE3, + 0x80, 0x94, 0xE4, 0xB8, 0x89, 0xE3, 0x80, 0x95, + 0x49, 0xE3, 0x80, 0x94, 0xE4, 0xBA, 0x8C, 0xE3, + 0x80, 0x95, 0x49, 0xE3, 0x80, 0x94, 0xE5, 0x8B, + // Bytes 2840 - 287f + 0x9D, 0xE3, 0x80, 0x95, 0x49, 0xE3, 0x80, 0x94, + 0xE5, 0xAE, 0x89, 0xE3, 0x80, 0x95, 0x49, 0xE3, + 0x80, 0x94, 0xE6, 0x89, 0x93, 0xE3, 0x80, 0x95, + 0x49, 0xE3, 0x80, 0x94, 0xE6, 0x95, 0x97, 0xE3, + 0x80, 0x95, 0x49, 0xE3, 0x80, 0x94, 0xE6, 0x9C, + 0xAC, 0xE3, 0x80, 0x95, 0x49, 0xE3, 0x80, 0x94, + 0xE7, 0x82, 0xB9, 0xE3, 0x80, 0x95, 0x49, 0xE3, + 0x80, 0x94, 0xE7, 0x9B, 0x97, 0xE3, 0x80, 0x95, + // Bytes 2880 - 28bf + 0x49, 0xE3, 0x82, 0xA2, 0xE3, 0x83, 0xBC, 0xE3, + 0x83, 0xAB, 0x49, 0xE3, 0x82, 0xA4, 0xE3, 0x83, + 0xB3, 0xE3, 0x83, 0x81, 0x49, 0xE3, 0x82, 0xA6, + 0xE3, 0x82, 0xA9, 0xE3, 0x83, 0xB3, 0x49, 0xE3, + 0x82, 0xAA, 0xE3, 0x83, 0xB3, 0xE3, 0x82, 0xB9, + 0x49, 0xE3, 0x82, 0xAA, 0xE3, 0x83, 0xBC, 0xE3, + 0x83, 0xA0, 0x49, 0xE3, 0x82, 0xAB, 0xE3, 0x82, + 0xA4, 0xE3, 0x83, 0xAA, 0x49, 0xE3, 0x82, 0xB1, + // Bytes 28c0 - 28ff + 0xE3, 0x83, 0xBC, 0xE3, 0x82, 0xB9, 0x49, 0xE3, + 0x82, 0xB3, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x8A, + 0x49, 0xE3, 0x82, 0xBB, 0xE3, 0x83, 0xB3, 0xE3, + 0x83, 0x81, 0x49, 0xE3, 0x82, 0xBB, 0xE3, 0x83, + 0xB3, 0xE3, 0x83, 0x88, 0x49, 0xE3, 0x83, 0x86, + 0xE3, 0x82, 0x99, 0xE3, 0x82, 0xB7, 0x49, 0xE3, + 0x83, 0x88, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xAB, + 0x49, 0xE3, 0x83, 0x8E, 0xE3, 0x83, 0x83, 0xE3, + // Bytes 2900 - 293f + 0x83, 0x88, 0x49, 0xE3, 0x83, 0x8F, 0xE3, 0x82, + 0xA4, 0xE3, 0x83, 0x84, 0x49, 0xE3, 0x83, 0x92, + 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xAB, 0x49, 0xE3, + 0x83, 0x92, 0xE3, 0x82, 0x9A, 0xE3, 0x82, 0xB3, + 0x49, 0xE3, 0x83, 0x95, 0xE3, 0x83, 0xA9, 0xE3, + 0x83, 0xB3, 0x49, 0xE3, 0x83, 0x98, 0xE3, 0x82, + 0x9A, 0xE3, 0x82, 0xBD, 0x49, 0xE3, 0x83, 0x98, + 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x84, 0x49, 0xE3, + // Bytes 2940 - 297f + 0x83, 0x9B, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0xAB, + 0x49, 0xE3, 0x83, 0x9B, 0xE3, 0x83, 0xBC, 0xE3, + 0x83, 0xB3, 0x49, 0xE3, 0x83, 0x9E, 0xE3, 0x82, + 0xA4, 0xE3, 0x83, 0xAB, 0x49, 0xE3, 0x83, 0x9E, + 0xE3, 0x83, 0x83, 0xE3, 0x83, 0x8F, 0x49, 0xE3, + 0x83, 0x9E, 0xE3, 0x83, 0xAB, 0xE3, 0x82, 0xAF, + 0x49, 0xE3, 0x83, 0xA4, 0xE3, 0x83, 0xBC, 0xE3, + 0x83, 0xAB, 0x49, 0xE3, 0x83, 0xA6, 0xE3, 0x82, + // Bytes 2980 - 29bf + 0xA2, 0xE3, 0x83, 0xB3, 0x49, 0xE3, 0x83, 0xAF, + 0xE3, 0x83, 0x83, 0xE3, 0x83, 0x88, 0x4C, 0xE2, + 0x80, 0xB2, 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2, + 0xE2, 0x80, 0xB2, 0x4C, 0xE2, 0x88, 0xAB, 0xE2, + 0x88, 0xAB, 0xE2, 0x88, 0xAB, 0xE2, 0x88, 0xAB, + 0x4C, 0xE3, 0x82, 0xA2, 0xE3, 0x83, 0xAB, 0xE3, + 0x83, 0x95, 0xE3, 0x82, 0xA1, 0x4C, 0xE3, 0x82, + 0xA8, 0xE3, 0x83, 0xBC, 0xE3, 0x82, 0xAB, 0xE3, + // Bytes 29c0 - 29ff + 0x83, 0xBC, 0x4C, 0xE3, 0x82, 0xAB, 0xE3, 0x82, + 0x99, 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xB3, 0x4C, + 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0xE3, 0x83, + 0xB3, 0xE3, 0x83, 0x9E, 0x4C, 0xE3, 0x82, 0xAB, + 0xE3, 0x83, 0xA9, 0xE3, 0x83, 0x83, 0xE3, 0x83, + 0x88, 0x4C, 0xE3, 0x82, 0xAB, 0xE3, 0x83, 0xAD, + 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0xBC, 0x4C, 0xE3, + 0x82, 0xAD, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0x8B, + // Bytes 2a00 - 2a3f + 0xE3, 0x83, 0xBC, 0x4C, 0xE3, 0x82, 0xAD, 0xE3, + 0x83, 0xA5, 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0xBC, + 0x4C, 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, 0xE3, + 0x83, 0xA9, 0xE3, 0x83, 0xA0, 0x4C, 0xE3, 0x82, + 0xAF, 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xBC, 0xE3, + 0x83, 0x8D, 0x4C, 0xE3, 0x82, 0xB5, 0xE3, 0x82, + 0xA4, 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAB, 0x4C, + 0xE3, 0x82, 0xBF, 0xE3, 0x82, 0x99, 0xE3, 0x83, + // Bytes 2a40 - 2a7f + 0xBC, 0xE3, 0x82, 0xB9, 0x4C, 0xE3, 0x83, 0x8F, + 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC, 0xE3, 0x83, + 0x84, 0x4C, 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x9A, + 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAB, 0x4C, 0xE3, + 0x83, 0x95, 0xE3, 0x82, 0xA3, 0xE3, 0x83, 0xBC, + 0xE3, 0x83, 0x88, 0x4C, 0xE3, 0x83, 0x98, 0xE3, + 0x82, 0x99, 0xE3, 0x83, 0xBC, 0xE3, 0x82, 0xBF, + 0x4C, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x9A, 0xE3, + // Bytes 2a80 - 2abf + 0x83, 0x8B, 0xE3, 0x83, 0x92, 0x4C, 0xE3, 0x83, + 0x98, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xB3, 0xE3, + 0x82, 0xB9, 0x4C, 0xE3, 0x83, 0x9B, 0xE3, 0x82, + 0x99, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x88, 0x4C, + 0xE3, 0x83, 0x9E, 0xE3, 0x82, 0xA4, 0xE3, 0x82, + 0xAF, 0xE3, 0x83, 0xAD, 0x4C, 0xE3, 0x83, 0x9F, + 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAD, 0xE3, 0x83, + 0xB3, 0x4C, 0xE3, 0x83, 0xA1, 0xE3, 0x83, 0xBC, + // Bytes 2ac0 - 2aff + 0xE3, 0x83, 0x88, 0xE3, 0x83, 0xAB, 0x4C, 0xE3, + 0x83, 0xAA, 0xE3, 0x83, 0x83, 0xE3, 0x83, 0x88, + 0xE3, 0x83, 0xAB, 0x4C, 0xE3, 0x83, 0xAB, 0xE3, + 0x83, 0x92, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC, + 0x4C, 0xE6, 0xA0, 0xAA, 0xE5, 0xBC, 0x8F, 0xE4, + 0xBC, 0x9A, 0xE7, 0xA4, 0xBE, 0x4E, 0x28, 0xE1, + 0x84, 0x8B, 0xE1, 0x85, 0xA9, 0xE1, 0x84, 0x92, + 0xE1, 0x85, 0xAE, 0x29, 0x4F, 0xD8, 0xAC, 0xD9, + // Bytes 2b00 - 2b3f + 0x84, 0x20, 0xD8, 0xAC, 0xD9, 0x84, 0xD8, 0xA7, + 0xD9, 0x84, 0xD9, 0x87, 0x4F, 0xE3, 0x82, 0xA2, + 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x9A, 0xE3, 0x83, + 0xBC, 0xE3, 0x83, 0x88, 0x4F, 0xE3, 0x82, 0xA2, + 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x98, 0xE3, 0x82, + 0x9A, 0xE3, 0x82, 0xA2, 0x4F, 0xE3, 0x82, 0xAD, + 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xAF, 0xE3, 0x83, + 0x83, 0xE3, 0x83, 0x88, 0x4F, 0xE3, 0x82, 0xB5, + // Bytes 2b40 - 2b7f + 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x81, 0xE3, 0x83, + 0xBC, 0xE3, 0x83, 0xA0, 0x4F, 0xE3, 0x83, 0x8F, + 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xBC, 0xE3, 0x83, + 0xAC, 0xE3, 0x83, 0xAB, 0x4F, 0xE3, 0x83, 0x98, + 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0xBF, 0xE3, 0x83, + 0xBC, 0xE3, 0x83, 0xAB, 0x4F, 0xE3, 0x83, 0x9B, + 0xE3, 0x82, 0x9A, 0xE3, 0x82, 0xA4, 0xE3, 0x83, + 0xB3, 0xE3, 0x83, 0x88, 0x4F, 0xE3, 0x83, 0x9E, + // Bytes 2b80 - 2bbf + 0xE3, 0x83, 0xB3, 0xE3, 0x82, 0xB7, 0xE3, 0x83, + 0xA7, 0xE3, 0x83, 0xB3, 0x4F, 0xE3, 0x83, 0xA1, + 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0xE3, 0x83, + 0x88, 0xE3, 0x83, 0xB3, 0x4F, 0xE3, 0x83, 0xAB, + 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x95, 0xE3, 0x82, + 0x99, 0xE3, 0x83, 0xAB, 0x51, 0x28, 0xE1, 0x84, + 0x8B, 0xE1, 0x85, 0xA9, 0xE1, 0x84, 0x8C, 0xE1, + 0x85, 0xA5, 0xE1, 0x86, 0xAB, 0x29, 0x52, 0xE3, + // Bytes 2bc0 - 2bff + 0x82, 0xAD, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xAB, + 0xE3, 0x82, 0xBF, 0xE3, 0x82, 0x99, 0xE3, 0x83, + 0xBC, 0x52, 0xE3, 0x82, 0xAD, 0xE3, 0x83, 0xAD, + 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, 0xE3, 0x83, + 0xA9, 0xE3, 0x83, 0xA0, 0x52, 0xE3, 0x82, 0xAD, + 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xA1, 0xE3, 0x83, + 0xBC, 0xE3, 0x83, 0x88, 0xE3, 0x83, 0xAB, 0x52, + 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, 0xE3, 0x83, + // Bytes 2c00 - 2c3f + 0xA9, 0xE3, 0x83, 0xA0, 0xE3, 0x83, 0x88, 0xE3, + 0x83, 0xB3, 0x52, 0xE3, 0x82, 0xAF, 0xE3, 0x83, + 0xAB, 0xE3, 0x82, 0xBB, 0xE3, 0x82, 0x99, 0xE3, + 0x82, 0xA4, 0xE3, 0x83, 0xAD, 0x52, 0xE3, 0x83, + 0x8F, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC, 0xE3, + 0x82, 0xBB, 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x88, + 0x52, 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x9A, 0xE3, + 0x82, 0xA2, 0xE3, 0x82, 0xB9, 0xE3, 0x83, 0x88, + // Bytes 2c40 - 2c7f + 0xE3, 0x83, 0xAB, 0x52, 0xE3, 0x83, 0x95, 0xE3, + 0x82, 0x99, 0xE3, 0x83, 0x83, 0xE3, 0x82, 0xB7, + 0xE3, 0x82, 0xA7, 0xE3, 0x83, 0xAB, 0x52, 0xE3, + 0x83, 0x9F, 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0x8F, + 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xBC, 0xE3, 0x83, + 0xAB, 0x52, 0xE3, 0x83, 0xAC, 0xE3, 0x83, 0xB3, + 0xE3, 0x83, 0x88, 0xE3, 0x82, 0xB1, 0xE3, 0x82, + 0x99, 0xE3, 0x83, 0xB3, 0x61, 0xD8, 0xB5, 0xD9, + // Bytes 2c80 - 2cbf + 0x84, 0xD9, 0x89, 0x20, 0xD8, 0xA7, 0xD9, 0x84, + 0xD9, 0x84, 0xD9, 0x87, 0x20, 0xD8, 0xB9, 0xD9, + 0x84, 0xD9, 0x8A, 0xD9, 0x87, 0x20, 0xD9, 0x88, + 0xD8, 0xB3, 0xD9, 0x84, 0xD9, 0x85, 0x06, 0xE0, + 0xA7, 0x87, 0xE0, 0xA6, 0xBE, 0x01, 0x06, 0xE0, + 0xA7, 0x87, 0xE0, 0xA7, 0x97, 0x01, 0x06, 0xE0, + 0xAD, 0x87, 0xE0, 0xAC, 0xBE, 0x01, 0x06, 0xE0, + 0xAD, 0x87, 0xE0, 0xAD, 0x96, 0x01, 0x06, 0xE0, + // Bytes 2cc0 - 2cff + 0xAD, 0x87, 0xE0, 0xAD, 0x97, 0x01, 0x06, 0xE0, + 0xAE, 0x92, 0xE0, 0xAF, 0x97, 0x01, 0x06, 0xE0, + 0xAF, 0x86, 0xE0, 0xAE, 0xBE, 0x01, 0x06, 0xE0, + 0xAF, 0x86, 0xE0, 0xAF, 0x97, 0x01, 0x06, 0xE0, + 0xAF, 0x87, 0xE0, 0xAE, 0xBE, 0x01, 0x06, 0xE0, + 0xB2, 0xBF, 0xE0, 0xB3, 0x95, 0x01, 0x06, 0xE0, + 0xB3, 0x86, 0xE0, 0xB3, 0x95, 0x01, 0x06, 0xE0, + 0xB3, 0x86, 0xE0, 0xB3, 0x96, 0x01, 0x06, 0xE0, + // Bytes 2d00 - 2d3f + 0xB5, 0x86, 0xE0, 0xB4, 0xBE, 0x01, 0x06, 0xE0, + 0xB5, 0x86, 0xE0, 0xB5, 0x97, 0x01, 0x06, 0xE0, + 0xB5, 0x87, 0xE0, 0xB4, 0xBE, 0x01, 0x06, 0xE0, + 0xB7, 0x99, 0xE0, 0xB7, 0x9F, 0x01, 0x06, 0xE1, + 0x80, 0xA5, 0xE1, 0x80, 0xAE, 0x01, 0x06, 0xE1, + 0xAC, 0x85, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1, + 0xAC, 0x87, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1, + 0xAC, 0x89, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1, + // Bytes 2d40 - 2d7f + 0xAC, 0x8B, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1, + 0xAC, 0x8D, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1, + 0xAC, 0x91, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1, + 0xAC, 0xBA, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1, + 0xAC, 0xBC, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1, + 0xAC, 0xBE, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1, + 0xAC, 0xBF, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1, + 0xAD, 0x82, 0xE1, 0xAC, 0xB5, 0x01, 0x08, 0xF0, + // Bytes 2d80 - 2dbf + 0x91, 0x84, 0xB1, 0xF0, 0x91, 0x84, 0xA7, 0x01, + 0x08, 0xF0, 0x91, 0x84, 0xB2, 0xF0, 0x91, 0x84, + 0xA7, 0x01, 0x08, 0xF0, 0x91, 0x8D, 0x87, 0xF0, + 0x91, 0x8C, 0xBE, 0x01, 0x08, 0xF0, 0x91, 0x8D, + 0x87, 0xF0, 0x91, 0x8D, 0x97, 0x01, 0x08, 0xF0, + 0x91, 0x92, 0xB9, 0xF0, 0x91, 0x92, 0xB0, 0x01, + 0x08, 0xF0, 0x91, 0x92, 0xB9, 0xF0, 0x91, 0x92, + 0xBA, 0x01, 0x08, 0xF0, 0x91, 0x92, 0xB9, 0xF0, + // Bytes 2dc0 - 2dff + 0x91, 0x92, 0xBD, 0x01, 0x08, 0xF0, 0x91, 0x96, + 0xB8, 0xF0, 0x91, 0x96, 0xAF, 0x01, 0x08, 0xF0, + 0x91, 0x96, 0xB9, 0xF0, 0x91, 0x96, 0xAF, 0x01, + 0x09, 0xE0, 0xB3, 0x86, 0xE0, 0xB3, 0x82, 0xE0, + 0xB3, 0x95, 0x02, 0x09, 0xE0, 0xB7, 0x99, 0xE0, + 0xB7, 0x8F, 0xE0, 0xB7, 0x8A, 0x12, 0x44, 0x44, + 0x5A, 0xCC, 0x8C, 0xC9, 0x44, 0x44, 0x7A, 0xCC, + 0x8C, 0xC9, 0x44, 0x64, 0x7A, 0xCC, 0x8C, 0xC9, + // Bytes 2e00 - 2e3f + 0x46, 0xD9, 0x84, 0xD8, 0xA7, 0xD9, 0x93, 0xC9, + 0x46, 0xD9, 0x84, 0xD8, 0xA7, 0xD9, 0x94, 0xC9, + 0x46, 0xD9, 0x84, 0xD8, 0xA7, 0xD9, 0x95, 0xB5, + 0x46, 0xE1, 0x84, 0x80, 0xE1, 0x85, 0xA1, 0x01, + 0x46, 0xE1, 0x84, 0x82, 0xE1, 0x85, 0xA1, 0x01, + 0x46, 0xE1, 0x84, 0x83, 0xE1, 0x85, 0xA1, 0x01, + 0x46, 0xE1, 0x84, 0x85, 0xE1, 0x85, 0xA1, 0x01, + 0x46, 0xE1, 0x84, 0x86, 0xE1, 0x85, 0xA1, 0x01, + // Bytes 2e40 - 2e7f + 0x46, 0xE1, 0x84, 0x87, 0xE1, 0x85, 0xA1, 0x01, + 0x46, 0xE1, 0x84, 0x89, 0xE1, 0x85, 0xA1, 0x01, + 0x46, 0xE1, 0x84, 0x8B, 0xE1, 0x85, 0xA1, 0x01, + 0x46, 0xE1, 0x84, 0x8B, 0xE1, 0x85, 0xAE, 0x01, + 0x46, 0xE1, 0x84, 0x8C, 0xE1, 0x85, 0xA1, 0x01, + 0x46, 0xE1, 0x84, 0x8E, 0xE1, 0x85, 0xA1, 0x01, + 0x46, 0xE1, 0x84, 0x8F, 0xE1, 0x85, 0xA1, 0x01, + 0x46, 0xE1, 0x84, 0x90, 0xE1, 0x85, 0xA1, 0x01, + // Bytes 2e80 - 2ebf + 0x46, 0xE1, 0x84, 0x91, 0xE1, 0x85, 0xA1, 0x01, + 0x46, 0xE1, 0x84, 0x92, 0xE1, 0x85, 0xA1, 0x01, + 0x49, 0xE3, 0x83, 0xA1, 0xE3, 0x82, 0xAB, 0xE3, + 0x82, 0x99, 0x0D, 0x4C, 0xE1, 0x84, 0x8C, 0xE1, + 0x85, 0xAE, 0xE1, 0x84, 0x8B, 0xE1, 0x85, 0xB4, + 0x01, 0x4C, 0xE3, 0x82, 0xAD, 0xE3, 0x82, 0x99, + 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0x0D, 0x4C, + 0xE3, 0x82, 0xB3, 0xE3, 0x83, 0xBC, 0xE3, 0x83, + // Bytes 2ec0 - 2eff + 0x9B, 0xE3, 0x82, 0x9A, 0x0D, 0x4C, 0xE3, 0x83, + 0xA4, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x88, 0xE3, + 0x82, 0x99, 0x0D, 0x4F, 0xE1, 0x84, 0x8E, 0xE1, + 0x85, 0xA1, 0xE1, 0x86, 0xB7, 0xE1, 0x84, 0x80, + 0xE1, 0x85, 0xA9, 0x01, 0x4F, 0xE3, 0x82, 0xA4, + 0xE3, 0x83, 0x8B, 0xE3, 0x83, 0xB3, 0xE3, 0x82, + 0xAF, 0xE3, 0x82, 0x99, 0x0D, 0x4F, 0xE3, 0x82, + 0xB7, 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0xB3, 0xE3, + // Bytes 2f00 - 2f3f + 0x82, 0xAF, 0xE3, 0x82, 0x99, 0x0D, 0x4F, 0xE3, + 0x83, 0x98, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC, + 0xE3, 0x82, 0xB7, 0xE3, 0x82, 0x99, 0x0D, 0x4F, + 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x9A, 0xE3, 0x83, + 0xB3, 0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99, 0x0D, + 0x52, 0xE3, 0x82, 0xA8, 0xE3, 0x82, 0xB9, 0xE3, + 0x82, 0xAF, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x88, + 0xE3, 0x82, 0x99, 0x0D, 0x52, 0xE3, 0x83, 0x95, + // Bytes 2f40 - 2f7f + 0xE3, 0x82, 0xA1, 0xE3, 0x83, 0xA9, 0xE3, 0x83, + 0x83, 0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99, 0x0D, + 0x86, 0xE0, 0xB3, 0x86, 0xE0, 0xB3, 0x82, 0x01, + 0x86, 0xE0, 0xB7, 0x99, 0xE0, 0xB7, 0x8F, 0x01, + 0x03, 0x3C, 0xCC, 0xB8, 0x05, 0x03, 0x3D, 0xCC, + 0xB8, 0x05, 0x03, 0x3E, 0xCC, 0xB8, 0x05, 0x03, + 0x41, 0xCC, 0x80, 0xC9, 0x03, 0x41, 0xCC, 0x81, + 0xC9, 0x03, 0x41, 0xCC, 0x83, 0xC9, 0x03, 0x41, + // Bytes 2f80 - 2fbf + 0xCC, 0x84, 0xC9, 0x03, 0x41, 0xCC, 0x89, 0xC9, + 0x03, 0x41, 0xCC, 0x8C, 0xC9, 0x03, 0x41, 0xCC, + 0x8F, 0xC9, 0x03, 0x41, 0xCC, 0x91, 0xC9, 0x03, + 0x41, 0xCC, 0xA5, 0xB5, 0x03, 0x41, 0xCC, 0xA8, + 0xA5, 0x03, 0x42, 0xCC, 0x87, 0xC9, 0x03, 0x42, + 0xCC, 0xA3, 0xB5, 0x03, 0x42, 0xCC, 0xB1, 0xB5, + 0x03, 0x43, 0xCC, 0x81, 0xC9, 0x03, 0x43, 0xCC, + 0x82, 0xC9, 0x03, 0x43, 0xCC, 0x87, 0xC9, 0x03, + // Bytes 2fc0 - 2fff + 0x43, 0xCC, 0x8C, 0xC9, 0x03, 0x44, 0xCC, 0x87, + 0xC9, 0x03, 0x44, 0xCC, 0x8C, 0xC9, 0x03, 0x44, + 0xCC, 0xA3, 0xB5, 0x03, 0x44, 0xCC, 0xA7, 0xA5, + 0x03, 0x44, 0xCC, 0xAD, 0xB5, 0x03, 0x44, 0xCC, + 0xB1, 0xB5, 0x03, 0x45, 0xCC, 0x80, 0xC9, 0x03, + 0x45, 0xCC, 0x81, 0xC9, 0x03, 0x45, 0xCC, 0x83, + 0xC9, 0x03, 0x45, 0xCC, 0x86, 0xC9, 0x03, 0x45, + 0xCC, 0x87, 0xC9, 0x03, 0x45, 0xCC, 0x88, 0xC9, + // Bytes 3000 - 303f + 0x03, 0x45, 0xCC, 0x89, 0xC9, 0x03, 0x45, 0xCC, + 0x8C, 0xC9, 0x03, 0x45, 0xCC, 0x8F, 0xC9, 0x03, + 0x45, 0xCC, 0x91, 0xC9, 0x03, 0x45, 0xCC, 0xA8, + 0xA5, 0x03, 0x45, 0xCC, 0xAD, 0xB5, 0x03, 0x45, + 0xCC, 0xB0, 0xB5, 0x03, 0x46, 0xCC, 0x87, 0xC9, + 0x03, 0x47, 0xCC, 0x81, 0xC9, 0x03, 0x47, 0xCC, + 0x82, 0xC9, 0x03, 0x47, 0xCC, 0x84, 0xC9, 0x03, + 0x47, 0xCC, 0x86, 0xC9, 0x03, 0x47, 0xCC, 0x87, + // Bytes 3040 - 307f + 0xC9, 0x03, 0x47, 0xCC, 0x8C, 0xC9, 0x03, 0x47, + 0xCC, 0xA7, 0xA5, 0x03, 0x48, 0xCC, 0x82, 0xC9, + 0x03, 0x48, 0xCC, 0x87, 0xC9, 0x03, 0x48, 0xCC, + 0x88, 0xC9, 0x03, 0x48, 0xCC, 0x8C, 0xC9, 0x03, + 0x48, 0xCC, 0xA3, 0xB5, 0x03, 0x48, 0xCC, 0xA7, + 0xA5, 0x03, 0x48, 0xCC, 0xAE, 0xB5, 0x03, 0x49, + 0xCC, 0x80, 0xC9, 0x03, 0x49, 0xCC, 0x81, 0xC9, + 0x03, 0x49, 0xCC, 0x82, 0xC9, 0x03, 0x49, 0xCC, + // Bytes 3080 - 30bf + 0x83, 0xC9, 0x03, 0x49, 0xCC, 0x84, 0xC9, 0x03, + 0x49, 0xCC, 0x86, 0xC9, 0x03, 0x49, 0xCC, 0x87, + 0xC9, 0x03, 0x49, 0xCC, 0x89, 0xC9, 0x03, 0x49, + 0xCC, 0x8C, 0xC9, 0x03, 0x49, 0xCC, 0x8F, 0xC9, + 0x03, 0x49, 0xCC, 0x91, 0xC9, 0x03, 0x49, 0xCC, + 0xA3, 0xB5, 0x03, 0x49, 0xCC, 0xA8, 0xA5, 0x03, + 0x49, 0xCC, 0xB0, 0xB5, 0x03, 0x4A, 0xCC, 0x82, + 0xC9, 0x03, 0x4B, 0xCC, 0x81, 0xC9, 0x03, 0x4B, + // Bytes 30c0 - 30ff + 0xCC, 0x8C, 0xC9, 0x03, 0x4B, 0xCC, 0xA3, 0xB5, + 0x03, 0x4B, 0xCC, 0xA7, 0xA5, 0x03, 0x4B, 0xCC, + 0xB1, 0xB5, 0x03, 0x4C, 0xCC, 0x81, 0xC9, 0x03, + 0x4C, 0xCC, 0x8C, 0xC9, 0x03, 0x4C, 0xCC, 0xA7, + 0xA5, 0x03, 0x4C, 0xCC, 0xAD, 0xB5, 0x03, 0x4C, + 0xCC, 0xB1, 0xB5, 0x03, 0x4D, 0xCC, 0x81, 0xC9, + 0x03, 0x4D, 0xCC, 0x87, 0xC9, 0x03, 0x4D, 0xCC, + 0xA3, 0xB5, 0x03, 0x4E, 0xCC, 0x80, 0xC9, 0x03, + // Bytes 3100 - 313f + 0x4E, 0xCC, 0x81, 0xC9, 0x03, 0x4E, 0xCC, 0x83, + 0xC9, 0x03, 0x4E, 0xCC, 0x87, 0xC9, 0x03, 0x4E, + 0xCC, 0x8C, 0xC9, 0x03, 0x4E, 0xCC, 0xA3, 0xB5, + 0x03, 0x4E, 0xCC, 0xA7, 0xA5, 0x03, 0x4E, 0xCC, + 0xAD, 0xB5, 0x03, 0x4E, 0xCC, 0xB1, 0xB5, 0x03, + 0x4F, 0xCC, 0x80, 0xC9, 0x03, 0x4F, 0xCC, 0x81, + 0xC9, 0x03, 0x4F, 0xCC, 0x86, 0xC9, 0x03, 0x4F, + 0xCC, 0x89, 0xC9, 0x03, 0x4F, 0xCC, 0x8B, 0xC9, + // Bytes 3140 - 317f + 0x03, 0x4F, 0xCC, 0x8C, 0xC9, 0x03, 0x4F, 0xCC, + 0x8F, 0xC9, 0x03, 0x4F, 0xCC, 0x91, 0xC9, 0x03, + 0x50, 0xCC, 0x81, 0xC9, 0x03, 0x50, 0xCC, 0x87, + 0xC9, 0x03, 0x52, 0xCC, 0x81, 0xC9, 0x03, 0x52, + 0xCC, 0x87, 0xC9, 0x03, 0x52, 0xCC, 0x8C, 0xC9, + 0x03, 0x52, 0xCC, 0x8F, 0xC9, 0x03, 0x52, 0xCC, + 0x91, 0xC9, 0x03, 0x52, 0xCC, 0xA7, 0xA5, 0x03, + 0x52, 0xCC, 0xB1, 0xB5, 0x03, 0x53, 0xCC, 0x82, + // Bytes 3180 - 31bf + 0xC9, 0x03, 0x53, 0xCC, 0x87, 0xC9, 0x03, 0x53, + 0xCC, 0xA6, 0xB5, 0x03, 0x53, 0xCC, 0xA7, 0xA5, + 0x03, 0x54, 0xCC, 0x87, 0xC9, 0x03, 0x54, 0xCC, + 0x8C, 0xC9, 0x03, 0x54, 0xCC, 0xA3, 0xB5, 0x03, + 0x54, 0xCC, 0xA6, 0xB5, 0x03, 0x54, 0xCC, 0xA7, + 0xA5, 0x03, 0x54, 0xCC, 0xAD, 0xB5, 0x03, 0x54, + 0xCC, 0xB1, 0xB5, 0x03, 0x55, 0xCC, 0x80, 0xC9, + 0x03, 0x55, 0xCC, 0x81, 0xC9, 0x03, 0x55, 0xCC, + // Bytes 31c0 - 31ff + 0x82, 0xC9, 0x03, 0x55, 0xCC, 0x86, 0xC9, 0x03, + 0x55, 0xCC, 0x89, 0xC9, 0x03, 0x55, 0xCC, 0x8A, + 0xC9, 0x03, 0x55, 0xCC, 0x8B, 0xC9, 0x03, 0x55, + 0xCC, 0x8C, 0xC9, 0x03, 0x55, 0xCC, 0x8F, 0xC9, + 0x03, 0x55, 0xCC, 0x91, 0xC9, 0x03, 0x55, 0xCC, + 0xA3, 0xB5, 0x03, 0x55, 0xCC, 0xA4, 0xB5, 0x03, + 0x55, 0xCC, 0xA8, 0xA5, 0x03, 0x55, 0xCC, 0xAD, + 0xB5, 0x03, 0x55, 0xCC, 0xB0, 0xB5, 0x03, 0x56, + // Bytes 3200 - 323f + 0xCC, 0x83, 0xC9, 0x03, 0x56, 0xCC, 0xA3, 0xB5, + 0x03, 0x57, 0xCC, 0x80, 0xC9, 0x03, 0x57, 0xCC, + 0x81, 0xC9, 0x03, 0x57, 0xCC, 0x82, 0xC9, 0x03, + 0x57, 0xCC, 0x87, 0xC9, 0x03, 0x57, 0xCC, 0x88, + 0xC9, 0x03, 0x57, 0xCC, 0xA3, 0xB5, 0x03, 0x58, + 0xCC, 0x87, 0xC9, 0x03, 0x58, 0xCC, 0x88, 0xC9, + 0x03, 0x59, 0xCC, 0x80, 0xC9, 0x03, 0x59, 0xCC, + 0x81, 0xC9, 0x03, 0x59, 0xCC, 0x82, 0xC9, 0x03, + // Bytes 3240 - 327f + 0x59, 0xCC, 0x83, 0xC9, 0x03, 0x59, 0xCC, 0x84, + 0xC9, 0x03, 0x59, 0xCC, 0x87, 0xC9, 0x03, 0x59, + 0xCC, 0x88, 0xC9, 0x03, 0x59, 0xCC, 0x89, 0xC9, + 0x03, 0x59, 0xCC, 0xA3, 0xB5, 0x03, 0x5A, 0xCC, + 0x81, 0xC9, 0x03, 0x5A, 0xCC, 0x82, 0xC9, 0x03, + 0x5A, 0xCC, 0x87, 0xC9, 0x03, 0x5A, 0xCC, 0x8C, + 0xC9, 0x03, 0x5A, 0xCC, 0xA3, 0xB5, 0x03, 0x5A, + 0xCC, 0xB1, 0xB5, 0x03, 0x61, 0xCC, 0x80, 0xC9, + // Bytes 3280 - 32bf + 0x03, 0x61, 0xCC, 0x81, 0xC9, 0x03, 0x61, 0xCC, + 0x83, 0xC9, 0x03, 0x61, 0xCC, 0x84, 0xC9, 0x03, + 0x61, 0xCC, 0x89, 0xC9, 0x03, 0x61, 0xCC, 0x8C, + 0xC9, 0x03, 0x61, 0xCC, 0x8F, 0xC9, 0x03, 0x61, + 0xCC, 0x91, 0xC9, 0x03, 0x61, 0xCC, 0xA5, 0xB5, + 0x03, 0x61, 0xCC, 0xA8, 0xA5, 0x03, 0x62, 0xCC, + 0x87, 0xC9, 0x03, 0x62, 0xCC, 0xA3, 0xB5, 0x03, + 0x62, 0xCC, 0xB1, 0xB5, 0x03, 0x63, 0xCC, 0x81, + // Bytes 32c0 - 32ff + 0xC9, 0x03, 0x63, 0xCC, 0x82, 0xC9, 0x03, 0x63, + 0xCC, 0x87, 0xC9, 0x03, 0x63, 0xCC, 0x8C, 0xC9, + 0x03, 0x64, 0xCC, 0x87, 0xC9, 0x03, 0x64, 0xCC, + 0x8C, 0xC9, 0x03, 0x64, 0xCC, 0xA3, 0xB5, 0x03, + 0x64, 0xCC, 0xA7, 0xA5, 0x03, 0x64, 0xCC, 0xAD, + 0xB5, 0x03, 0x64, 0xCC, 0xB1, 0xB5, 0x03, 0x65, + 0xCC, 0x80, 0xC9, 0x03, 0x65, 0xCC, 0x81, 0xC9, + 0x03, 0x65, 0xCC, 0x83, 0xC9, 0x03, 0x65, 0xCC, + // Bytes 3300 - 333f + 0x86, 0xC9, 0x03, 0x65, 0xCC, 0x87, 0xC9, 0x03, + 0x65, 0xCC, 0x88, 0xC9, 0x03, 0x65, 0xCC, 0x89, + 0xC9, 0x03, 0x65, 0xCC, 0x8C, 0xC9, 0x03, 0x65, + 0xCC, 0x8F, 0xC9, 0x03, 0x65, 0xCC, 0x91, 0xC9, + 0x03, 0x65, 0xCC, 0xA8, 0xA5, 0x03, 0x65, 0xCC, + 0xAD, 0xB5, 0x03, 0x65, 0xCC, 0xB0, 0xB5, 0x03, + 0x66, 0xCC, 0x87, 0xC9, 0x03, 0x67, 0xCC, 0x81, + 0xC9, 0x03, 0x67, 0xCC, 0x82, 0xC9, 0x03, 0x67, + // Bytes 3340 - 337f + 0xCC, 0x84, 0xC9, 0x03, 0x67, 0xCC, 0x86, 0xC9, + 0x03, 0x67, 0xCC, 0x87, 0xC9, 0x03, 0x67, 0xCC, + 0x8C, 0xC9, 0x03, 0x67, 0xCC, 0xA7, 0xA5, 0x03, + 0x68, 0xCC, 0x82, 0xC9, 0x03, 0x68, 0xCC, 0x87, + 0xC9, 0x03, 0x68, 0xCC, 0x88, 0xC9, 0x03, 0x68, + 0xCC, 0x8C, 0xC9, 0x03, 0x68, 0xCC, 0xA3, 0xB5, + 0x03, 0x68, 0xCC, 0xA7, 0xA5, 0x03, 0x68, 0xCC, + 0xAE, 0xB5, 0x03, 0x68, 0xCC, 0xB1, 0xB5, 0x03, + // Bytes 3380 - 33bf + 0x69, 0xCC, 0x80, 0xC9, 0x03, 0x69, 0xCC, 0x81, + 0xC9, 0x03, 0x69, 0xCC, 0x82, 0xC9, 0x03, 0x69, + 0xCC, 0x83, 0xC9, 0x03, 0x69, 0xCC, 0x84, 0xC9, + 0x03, 0x69, 0xCC, 0x86, 0xC9, 0x03, 0x69, 0xCC, + 0x89, 0xC9, 0x03, 0x69, 0xCC, 0x8C, 0xC9, 0x03, + 0x69, 0xCC, 0x8F, 0xC9, 0x03, 0x69, 0xCC, 0x91, + 0xC9, 0x03, 0x69, 0xCC, 0xA3, 0xB5, 0x03, 0x69, + 0xCC, 0xA8, 0xA5, 0x03, 0x69, 0xCC, 0xB0, 0xB5, + // Bytes 33c0 - 33ff + 0x03, 0x6A, 0xCC, 0x82, 0xC9, 0x03, 0x6A, 0xCC, + 0x8C, 0xC9, 0x03, 0x6B, 0xCC, 0x81, 0xC9, 0x03, + 0x6B, 0xCC, 0x8C, 0xC9, 0x03, 0x6B, 0xCC, 0xA3, + 0xB5, 0x03, 0x6B, 0xCC, 0xA7, 0xA5, 0x03, 0x6B, + 0xCC, 0xB1, 0xB5, 0x03, 0x6C, 0xCC, 0x81, 0xC9, + 0x03, 0x6C, 0xCC, 0x8C, 0xC9, 0x03, 0x6C, 0xCC, + 0xA7, 0xA5, 0x03, 0x6C, 0xCC, 0xAD, 0xB5, 0x03, + 0x6C, 0xCC, 0xB1, 0xB5, 0x03, 0x6D, 0xCC, 0x81, + // Bytes 3400 - 343f + 0xC9, 0x03, 0x6D, 0xCC, 0x87, 0xC9, 0x03, 0x6D, + 0xCC, 0xA3, 0xB5, 0x03, 0x6E, 0xCC, 0x80, 0xC9, + 0x03, 0x6E, 0xCC, 0x81, 0xC9, 0x03, 0x6E, 0xCC, + 0x83, 0xC9, 0x03, 0x6E, 0xCC, 0x87, 0xC9, 0x03, + 0x6E, 0xCC, 0x8C, 0xC9, 0x03, 0x6E, 0xCC, 0xA3, + 0xB5, 0x03, 0x6E, 0xCC, 0xA7, 0xA5, 0x03, 0x6E, + 0xCC, 0xAD, 0xB5, 0x03, 0x6E, 0xCC, 0xB1, 0xB5, + 0x03, 0x6F, 0xCC, 0x80, 0xC9, 0x03, 0x6F, 0xCC, + // Bytes 3440 - 347f + 0x81, 0xC9, 0x03, 0x6F, 0xCC, 0x86, 0xC9, 0x03, + 0x6F, 0xCC, 0x89, 0xC9, 0x03, 0x6F, 0xCC, 0x8B, + 0xC9, 0x03, 0x6F, 0xCC, 0x8C, 0xC9, 0x03, 0x6F, + 0xCC, 0x8F, 0xC9, 0x03, 0x6F, 0xCC, 0x91, 0xC9, + 0x03, 0x70, 0xCC, 0x81, 0xC9, 0x03, 0x70, 0xCC, + 0x87, 0xC9, 0x03, 0x72, 0xCC, 0x81, 0xC9, 0x03, + 0x72, 0xCC, 0x87, 0xC9, 0x03, 0x72, 0xCC, 0x8C, + 0xC9, 0x03, 0x72, 0xCC, 0x8F, 0xC9, 0x03, 0x72, + // Bytes 3480 - 34bf + 0xCC, 0x91, 0xC9, 0x03, 0x72, 0xCC, 0xA7, 0xA5, + 0x03, 0x72, 0xCC, 0xB1, 0xB5, 0x03, 0x73, 0xCC, + 0x82, 0xC9, 0x03, 0x73, 0xCC, 0x87, 0xC9, 0x03, + 0x73, 0xCC, 0xA6, 0xB5, 0x03, 0x73, 0xCC, 0xA7, + 0xA5, 0x03, 0x74, 0xCC, 0x87, 0xC9, 0x03, 0x74, + 0xCC, 0x88, 0xC9, 0x03, 0x74, 0xCC, 0x8C, 0xC9, + 0x03, 0x74, 0xCC, 0xA3, 0xB5, 0x03, 0x74, 0xCC, + 0xA6, 0xB5, 0x03, 0x74, 0xCC, 0xA7, 0xA5, 0x03, + // Bytes 34c0 - 34ff + 0x74, 0xCC, 0xAD, 0xB5, 0x03, 0x74, 0xCC, 0xB1, + 0xB5, 0x03, 0x75, 0xCC, 0x80, 0xC9, 0x03, 0x75, + 0xCC, 0x81, 0xC9, 0x03, 0x75, 0xCC, 0x82, 0xC9, + 0x03, 0x75, 0xCC, 0x86, 0xC9, 0x03, 0x75, 0xCC, + 0x89, 0xC9, 0x03, 0x75, 0xCC, 0x8A, 0xC9, 0x03, + 0x75, 0xCC, 0x8B, 0xC9, 0x03, 0x75, 0xCC, 0x8C, + 0xC9, 0x03, 0x75, 0xCC, 0x8F, 0xC9, 0x03, 0x75, + 0xCC, 0x91, 0xC9, 0x03, 0x75, 0xCC, 0xA3, 0xB5, + // Bytes 3500 - 353f + 0x03, 0x75, 0xCC, 0xA4, 0xB5, 0x03, 0x75, 0xCC, + 0xA8, 0xA5, 0x03, 0x75, 0xCC, 0xAD, 0xB5, 0x03, + 0x75, 0xCC, 0xB0, 0xB5, 0x03, 0x76, 0xCC, 0x83, + 0xC9, 0x03, 0x76, 0xCC, 0xA3, 0xB5, 0x03, 0x77, + 0xCC, 0x80, 0xC9, 0x03, 0x77, 0xCC, 0x81, 0xC9, + 0x03, 0x77, 0xCC, 0x82, 0xC9, 0x03, 0x77, 0xCC, + 0x87, 0xC9, 0x03, 0x77, 0xCC, 0x88, 0xC9, 0x03, + 0x77, 0xCC, 0x8A, 0xC9, 0x03, 0x77, 0xCC, 0xA3, + // Bytes 3540 - 357f + 0xB5, 0x03, 0x78, 0xCC, 0x87, 0xC9, 0x03, 0x78, + 0xCC, 0x88, 0xC9, 0x03, 0x79, 0xCC, 0x80, 0xC9, + 0x03, 0x79, 0xCC, 0x81, 0xC9, 0x03, 0x79, 0xCC, + 0x82, 0xC9, 0x03, 0x79, 0xCC, 0x83, 0xC9, 0x03, + 0x79, 0xCC, 0x84, 0xC9, 0x03, 0x79, 0xCC, 0x87, + 0xC9, 0x03, 0x79, 0xCC, 0x88, 0xC9, 0x03, 0x79, + 0xCC, 0x89, 0xC9, 0x03, 0x79, 0xCC, 0x8A, 0xC9, + 0x03, 0x79, 0xCC, 0xA3, 0xB5, 0x03, 0x7A, 0xCC, + // Bytes 3580 - 35bf + 0x81, 0xC9, 0x03, 0x7A, 0xCC, 0x82, 0xC9, 0x03, + 0x7A, 0xCC, 0x87, 0xC9, 0x03, 0x7A, 0xCC, 0x8C, + 0xC9, 0x03, 0x7A, 0xCC, 0xA3, 0xB5, 0x03, 0x7A, + 0xCC, 0xB1, 0xB5, 0x04, 0xC2, 0xA8, 0xCC, 0x80, + 0xCA, 0x04, 0xC2, 0xA8, 0xCC, 0x81, 0xCA, 0x04, + 0xC2, 0xA8, 0xCD, 0x82, 0xCA, 0x04, 0xC3, 0x86, + 0xCC, 0x81, 0xC9, 0x04, 0xC3, 0x86, 0xCC, 0x84, + 0xC9, 0x04, 0xC3, 0x98, 0xCC, 0x81, 0xC9, 0x04, + // Bytes 35c0 - 35ff + 0xC3, 0xA6, 0xCC, 0x81, 0xC9, 0x04, 0xC3, 0xA6, + 0xCC, 0x84, 0xC9, 0x04, 0xC3, 0xB8, 0xCC, 0x81, + 0xC9, 0x04, 0xC5, 0xBF, 0xCC, 0x87, 0xC9, 0x04, + 0xC6, 0xB7, 0xCC, 0x8C, 0xC9, 0x04, 0xCA, 0x92, + 0xCC, 0x8C, 0xC9, 0x04, 0xCE, 0x91, 0xCC, 0x80, + 0xC9, 0x04, 0xCE, 0x91, 0xCC, 0x81, 0xC9, 0x04, + 0xCE, 0x91, 0xCC, 0x84, 0xC9, 0x04, 0xCE, 0x91, + 0xCC, 0x86, 0xC9, 0x04, 0xCE, 0x91, 0xCD, 0x85, + // Bytes 3600 - 363f + 0xD9, 0x04, 0xCE, 0x95, 0xCC, 0x80, 0xC9, 0x04, + 0xCE, 0x95, 0xCC, 0x81, 0xC9, 0x04, 0xCE, 0x97, + 0xCC, 0x80, 0xC9, 0x04, 0xCE, 0x97, 0xCC, 0x81, + 0xC9, 0x04, 0xCE, 0x97, 0xCD, 0x85, 0xD9, 0x04, + 0xCE, 0x99, 0xCC, 0x80, 0xC9, 0x04, 0xCE, 0x99, + 0xCC, 0x81, 0xC9, 0x04, 0xCE, 0x99, 0xCC, 0x84, + 0xC9, 0x04, 0xCE, 0x99, 0xCC, 0x86, 0xC9, 0x04, + 0xCE, 0x99, 0xCC, 0x88, 0xC9, 0x04, 0xCE, 0x9F, + // Bytes 3640 - 367f + 0xCC, 0x80, 0xC9, 0x04, 0xCE, 0x9F, 0xCC, 0x81, + 0xC9, 0x04, 0xCE, 0xA1, 0xCC, 0x94, 0xC9, 0x04, + 0xCE, 0xA5, 0xCC, 0x80, 0xC9, 0x04, 0xCE, 0xA5, + 0xCC, 0x81, 0xC9, 0x04, 0xCE, 0xA5, 0xCC, 0x84, + 0xC9, 0x04, 0xCE, 0xA5, 0xCC, 0x86, 0xC9, 0x04, + 0xCE, 0xA5, 0xCC, 0x88, 0xC9, 0x04, 0xCE, 0xA9, + 0xCC, 0x80, 0xC9, 0x04, 0xCE, 0xA9, 0xCC, 0x81, + 0xC9, 0x04, 0xCE, 0xA9, 0xCD, 0x85, 0xD9, 0x04, + // Bytes 3680 - 36bf + 0xCE, 0xB1, 0xCC, 0x84, 0xC9, 0x04, 0xCE, 0xB1, + 0xCC, 0x86, 0xC9, 0x04, 0xCE, 0xB1, 0xCD, 0x85, + 0xD9, 0x04, 0xCE, 0xB5, 0xCC, 0x80, 0xC9, 0x04, + 0xCE, 0xB5, 0xCC, 0x81, 0xC9, 0x04, 0xCE, 0xB7, + 0xCD, 0x85, 0xD9, 0x04, 0xCE, 0xB9, 0xCC, 0x80, + 0xC9, 0x04, 0xCE, 0xB9, 0xCC, 0x81, 0xC9, 0x04, + 0xCE, 0xB9, 0xCC, 0x84, 0xC9, 0x04, 0xCE, 0xB9, + 0xCC, 0x86, 0xC9, 0x04, 0xCE, 0xB9, 0xCD, 0x82, + // Bytes 36c0 - 36ff + 0xC9, 0x04, 0xCE, 0xBF, 0xCC, 0x80, 0xC9, 0x04, + 0xCE, 0xBF, 0xCC, 0x81, 0xC9, 0x04, 0xCF, 0x81, + 0xCC, 0x93, 0xC9, 0x04, 0xCF, 0x81, 0xCC, 0x94, + 0xC9, 0x04, 0xCF, 0x85, 0xCC, 0x80, 0xC9, 0x04, + 0xCF, 0x85, 0xCC, 0x81, 0xC9, 0x04, 0xCF, 0x85, + 0xCC, 0x84, 0xC9, 0x04, 0xCF, 0x85, 0xCC, 0x86, + 0xC9, 0x04, 0xCF, 0x85, 0xCD, 0x82, 0xC9, 0x04, + 0xCF, 0x89, 0xCD, 0x85, 0xD9, 0x04, 0xCF, 0x92, + // Bytes 3700 - 373f + 0xCC, 0x81, 0xC9, 0x04, 0xCF, 0x92, 0xCC, 0x88, + 0xC9, 0x04, 0xD0, 0x86, 0xCC, 0x88, 0xC9, 0x04, + 0xD0, 0x90, 0xCC, 0x86, 0xC9, 0x04, 0xD0, 0x90, + 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0x93, 0xCC, 0x81, + 0xC9, 0x04, 0xD0, 0x95, 0xCC, 0x80, 0xC9, 0x04, + 0xD0, 0x95, 0xCC, 0x86, 0xC9, 0x04, 0xD0, 0x95, + 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0x96, 0xCC, 0x86, + 0xC9, 0x04, 0xD0, 0x96, 0xCC, 0x88, 0xC9, 0x04, + // Bytes 3740 - 377f + 0xD0, 0x97, 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0x98, + 0xCC, 0x80, 0xC9, 0x04, 0xD0, 0x98, 0xCC, 0x84, + 0xC9, 0x04, 0xD0, 0x98, 0xCC, 0x86, 0xC9, 0x04, + 0xD0, 0x98, 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0x9A, + 0xCC, 0x81, 0xC9, 0x04, 0xD0, 0x9E, 0xCC, 0x88, + 0xC9, 0x04, 0xD0, 0xA3, 0xCC, 0x84, 0xC9, 0x04, + 0xD0, 0xA3, 0xCC, 0x86, 0xC9, 0x04, 0xD0, 0xA3, + 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0xA3, 0xCC, 0x8B, + // Bytes 3780 - 37bf + 0xC9, 0x04, 0xD0, 0xA7, 0xCC, 0x88, 0xC9, 0x04, + 0xD0, 0xAB, 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0xAD, + 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0xB0, 0xCC, 0x86, + 0xC9, 0x04, 0xD0, 0xB0, 0xCC, 0x88, 0xC9, 0x04, + 0xD0, 0xB3, 0xCC, 0x81, 0xC9, 0x04, 0xD0, 0xB5, + 0xCC, 0x80, 0xC9, 0x04, 0xD0, 0xB5, 0xCC, 0x86, + 0xC9, 0x04, 0xD0, 0xB5, 0xCC, 0x88, 0xC9, 0x04, + 0xD0, 0xB6, 0xCC, 0x86, 0xC9, 0x04, 0xD0, 0xB6, + // Bytes 37c0 - 37ff + 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0xB7, 0xCC, 0x88, + 0xC9, 0x04, 0xD0, 0xB8, 0xCC, 0x80, 0xC9, 0x04, + 0xD0, 0xB8, 0xCC, 0x84, 0xC9, 0x04, 0xD0, 0xB8, + 0xCC, 0x86, 0xC9, 0x04, 0xD0, 0xB8, 0xCC, 0x88, + 0xC9, 0x04, 0xD0, 0xBA, 0xCC, 0x81, 0xC9, 0x04, + 0xD0, 0xBE, 0xCC, 0x88, 0xC9, 0x04, 0xD1, 0x83, + 0xCC, 0x84, 0xC9, 0x04, 0xD1, 0x83, 0xCC, 0x86, + 0xC9, 0x04, 0xD1, 0x83, 0xCC, 0x88, 0xC9, 0x04, + // Bytes 3800 - 383f + 0xD1, 0x83, 0xCC, 0x8B, 0xC9, 0x04, 0xD1, 0x87, + 0xCC, 0x88, 0xC9, 0x04, 0xD1, 0x8B, 0xCC, 0x88, + 0xC9, 0x04, 0xD1, 0x8D, 0xCC, 0x88, 0xC9, 0x04, + 0xD1, 0x96, 0xCC, 0x88, 0xC9, 0x04, 0xD1, 0xB4, + 0xCC, 0x8F, 0xC9, 0x04, 0xD1, 0xB5, 0xCC, 0x8F, + 0xC9, 0x04, 0xD3, 0x98, 0xCC, 0x88, 0xC9, 0x04, + 0xD3, 0x99, 0xCC, 0x88, 0xC9, 0x04, 0xD3, 0xA8, + 0xCC, 0x88, 0xC9, 0x04, 0xD3, 0xA9, 0xCC, 0x88, + // Bytes 3840 - 387f + 0xC9, 0x04, 0xD8, 0xA7, 0xD9, 0x93, 0xC9, 0x04, + 0xD8, 0xA7, 0xD9, 0x94, 0xC9, 0x04, 0xD8, 0xA7, + 0xD9, 0x95, 0xB5, 0x04, 0xD9, 0x88, 0xD9, 0x94, + 0xC9, 0x04, 0xD9, 0x8A, 0xD9, 0x94, 0xC9, 0x04, + 0xDB, 0x81, 0xD9, 0x94, 0xC9, 0x04, 0xDB, 0x92, + 0xD9, 0x94, 0xC9, 0x04, 0xDB, 0x95, 0xD9, 0x94, + 0xC9, 0x05, 0x41, 0xCC, 0x82, 0xCC, 0x80, 0xCA, + 0x05, 0x41, 0xCC, 0x82, 0xCC, 0x81, 0xCA, 0x05, + // Bytes 3880 - 38bf + 0x41, 0xCC, 0x82, 0xCC, 0x83, 0xCA, 0x05, 0x41, + 0xCC, 0x82, 0xCC, 0x89, 0xCA, 0x05, 0x41, 0xCC, + 0x86, 0xCC, 0x80, 0xCA, 0x05, 0x41, 0xCC, 0x86, + 0xCC, 0x81, 0xCA, 0x05, 0x41, 0xCC, 0x86, 0xCC, + 0x83, 0xCA, 0x05, 0x41, 0xCC, 0x86, 0xCC, 0x89, + 0xCA, 0x05, 0x41, 0xCC, 0x87, 0xCC, 0x84, 0xCA, + 0x05, 0x41, 0xCC, 0x88, 0xCC, 0x84, 0xCA, 0x05, + 0x41, 0xCC, 0x8A, 0xCC, 0x81, 0xCA, 0x05, 0x41, + // Bytes 38c0 - 38ff + 0xCC, 0xA3, 0xCC, 0x82, 0xCA, 0x05, 0x41, 0xCC, + 0xA3, 0xCC, 0x86, 0xCA, 0x05, 0x43, 0xCC, 0xA7, + 0xCC, 0x81, 0xCA, 0x05, 0x45, 0xCC, 0x82, 0xCC, + 0x80, 0xCA, 0x05, 0x45, 0xCC, 0x82, 0xCC, 0x81, + 0xCA, 0x05, 0x45, 0xCC, 0x82, 0xCC, 0x83, 0xCA, + 0x05, 0x45, 0xCC, 0x82, 0xCC, 0x89, 0xCA, 0x05, + 0x45, 0xCC, 0x84, 0xCC, 0x80, 0xCA, 0x05, 0x45, + 0xCC, 0x84, 0xCC, 0x81, 0xCA, 0x05, 0x45, 0xCC, + // Bytes 3900 - 393f + 0xA3, 0xCC, 0x82, 0xCA, 0x05, 0x45, 0xCC, 0xA7, + 0xCC, 0x86, 0xCA, 0x05, 0x49, 0xCC, 0x88, 0xCC, + 0x81, 0xCA, 0x05, 0x4C, 0xCC, 0xA3, 0xCC, 0x84, + 0xCA, 0x05, 0x4F, 0xCC, 0x82, 0xCC, 0x80, 0xCA, + 0x05, 0x4F, 0xCC, 0x82, 0xCC, 0x81, 0xCA, 0x05, + 0x4F, 0xCC, 0x82, 0xCC, 0x83, 0xCA, 0x05, 0x4F, + 0xCC, 0x82, 0xCC, 0x89, 0xCA, 0x05, 0x4F, 0xCC, + 0x83, 0xCC, 0x81, 0xCA, 0x05, 0x4F, 0xCC, 0x83, + // Bytes 3940 - 397f + 0xCC, 0x84, 0xCA, 0x05, 0x4F, 0xCC, 0x83, 0xCC, + 0x88, 0xCA, 0x05, 0x4F, 0xCC, 0x84, 0xCC, 0x80, + 0xCA, 0x05, 0x4F, 0xCC, 0x84, 0xCC, 0x81, 0xCA, + 0x05, 0x4F, 0xCC, 0x87, 0xCC, 0x84, 0xCA, 0x05, + 0x4F, 0xCC, 0x88, 0xCC, 0x84, 0xCA, 0x05, 0x4F, + 0xCC, 0x9B, 0xCC, 0x80, 0xCA, 0x05, 0x4F, 0xCC, + 0x9B, 0xCC, 0x81, 0xCA, 0x05, 0x4F, 0xCC, 0x9B, + 0xCC, 0x83, 0xCA, 0x05, 0x4F, 0xCC, 0x9B, 0xCC, + // Bytes 3980 - 39bf + 0x89, 0xCA, 0x05, 0x4F, 0xCC, 0x9B, 0xCC, 0xA3, + 0xB6, 0x05, 0x4F, 0xCC, 0xA3, 0xCC, 0x82, 0xCA, + 0x05, 0x4F, 0xCC, 0xA8, 0xCC, 0x84, 0xCA, 0x05, + 0x52, 0xCC, 0xA3, 0xCC, 0x84, 0xCA, 0x05, 0x53, + 0xCC, 0x81, 0xCC, 0x87, 0xCA, 0x05, 0x53, 0xCC, + 0x8C, 0xCC, 0x87, 0xCA, 0x05, 0x53, 0xCC, 0xA3, + 0xCC, 0x87, 0xCA, 0x05, 0x55, 0xCC, 0x83, 0xCC, + 0x81, 0xCA, 0x05, 0x55, 0xCC, 0x84, 0xCC, 0x88, + // Bytes 39c0 - 39ff + 0xCA, 0x05, 0x55, 0xCC, 0x88, 0xCC, 0x80, 0xCA, + 0x05, 0x55, 0xCC, 0x88, 0xCC, 0x81, 0xCA, 0x05, + 0x55, 0xCC, 0x88, 0xCC, 0x84, 0xCA, 0x05, 0x55, + 0xCC, 0x88, 0xCC, 0x8C, 0xCA, 0x05, 0x55, 0xCC, + 0x9B, 0xCC, 0x80, 0xCA, 0x05, 0x55, 0xCC, 0x9B, + 0xCC, 0x81, 0xCA, 0x05, 0x55, 0xCC, 0x9B, 0xCC, + 0x83, 0xCA, 0x05, 0x55, 0xCC, 0x9B, 0xCC, 0x89, + 0xCA, 0x05, 0x55, 0xCC, 0x9B, 0xCC, 0xA3, 0xB6, + // Bytes 3a00 - 3a3f + 0x05, 0x61, 0xCC, 0x82, 0xCC, 0x80, 0xCA, 0x05, + 0x61, 0xCC, 0x82, 0xCC, 0x81, 0xCA, 0x05, 0x61, + 0xCC, 0x82, 0xCC, 0x83, 0xCA, 0x05, 0x61, 0xCC, + 0x82, 0xCC, 0x89, 0xCA, 0x05, 0x61, 0xCC, 0x86, + 0xCC, 0x80, 0xCA, 0x05, 0x61, 0xCC, 0x86, 0xCC, + 0x81, 0xCA, 0x05, 0x61, 0xCC, 0x86, 0xCC, 0x83, + 0xCA, 0x05, 0x61, 0xCC, 0x86, 0xCC, 0x89, 0xCA, + 0x05, 0x61, 0xCC, 0x87, 0xCC, 0x84, 0xCA, 0x05, + // Bytes 3a40 - 3a7f + 0x61, 0xCC, 0x88, 0xCC, 0x84, 0xCA, 0x05, 0x61, + 0xCC, 0x8A, 0xCC, 0x81, 0xCA, 0x05, 0x61, 0xCC, + 0xA3, 0xCC, 0x82, 0xCA, 0x05, 0x61, 0xCC, 0xA3, + 0xCC, 0x86, 0xCA, 0x05, 0x63, 0xCC, 0xA7, 0xCC, + 0x81, 0xCA, 0x05, 0x65, 0xCC, 0x82, 0xCC, 0x80, + 0xCA, 0x05, 0x65, 0xCC, 0x82, 0xCC, 0x81, 0xCA, + 0x05, 0x65, 0xCC, 0x82, 0xCC, 0x83, 0xCA, 0x05, + 0x65, 0xCC, 0x82, 0xCC, 0x89, 0xCA, 0x05, 0x65, + // Bytes 3a80 - 3abf + 0xCC, 0x84, 0xCC, 0x80, 0xCA, 0x05, 0x65, 0xCC, + 0x84, 0xCC, 0x81, 0xCA, 0x05, 0x65, 0xCC, 0xA3, + 0xCC, 0x82, 0xCA, 0x05, 0x65, 0xCC, 0xA7, 0xCC, + 0x86, 0xCA, 0x05, 0x69, 0xCC, 0x88, 0xCC, 0x81, + 0xCA, 0x05, 0x6C, 0xCC, 0xA3, 0xCC, 0x84, 0xCA, + 0x05, 0x6F, 0xCC, 0x82, 0xCC, 0x80, 0xCA, 0x05, + 0x6F, 0xCC, 0x82, 0xCC, 0x81, 0xCA, 0x05, 0x6F, + 0xCC, 0x82, 0xCC, 0x83, 0xCA, 0x05, 0x6F, 0xCC, + // Bytes 3ac0 - 3aff + 0x82, 0xCC, 0x89, 0xCA, 0x05, 0x6F, 0xCC, 0x83, + 0xCC, 0x81, 0xCA, 0x05, 0x6F, 0xCC, 0x83, 0xCC, + 0x84, 0xCA, 0x05, 0x6F, 0xCC, 0x83, 0xCC, 0x88, + 0xCA, 0x05, 0x6F, 0xCC, 0x84, 0xCC, 0x80, 0xCA, + 0x05, 0x6F, 0xCC, 0x84, 0xCC, 0x81, 0xCA, 0x05, + 0x6F, 0xCC, 0x87, 0xCC, 0x84, 0xCA, 0x05, 0x6F, + 0xCC, 0x88, 0xCC, 0x84, 0xCA, 0x05, 0x6F, 0xCC, + 0x9B, 0xCC, 0x80, 0xCA, 0x05, 0x6F, 0xCC, 0x9B, + // Bytes 3b00 - 3b3f + 0xCC, 0x81, 0xCA, 0x05, 0x6F, 0xCC, 0x9B, 0xCC, + 0x83, 0xCA, 0x05, 0x6F, 0xCC, 0x9B, 0xCC, 0x89, + 0xCA, 0x05, 0x6F, 0xCC, 0x9B, 0xCC, 0xA3, 0xB6, + 0x05, 0x6F, 0xCC, 0xA3, 0xCC, 0x82, 0xCA, 0x05, + 0x6F, 0xCC, 0xA8, 0xCC, 0x84, 0xCA, 0x05, 0x72, + 0xCC, 0xA3, 0xCC, 0x84, 0xCA, 0x05, 0x73, 0xCC, + 0x81, 0xCC, 0x87, 0xCA, 0x05, 0x73, 0xCC, 0x8C, + 0xCC, 0x87, 0xCA, 0x05, 0x73, 0xCC, 0xA3, 0xCC, + // Bytes 3b40 - 3b7f + 0x87, 0xCA, 0x05, 0x75, 0xCC, 0x83, 0xCC, 0x81, + 0xCA, 0x05, 0x75, 0xCC, 0x84, 0xCC, 0x88, 0xCA, + 0x05, 0x75, 0xCC, 0x88, 0xCC, 0x80, 0xCA, 0x05, + 0x75, 0xCC, 0x88, 0xCC, 0x81, 0xCA, 0x05, 0x75, + 0xCC, 0x88, 0xCC, 0x84, 0xCA, 0x05, 0x75, 0xCC, + 0x88, 0xCC, 0x8C, 0xCA, 0x05, 0x75, 0xCC, 0x9B, + 0xCC, 0x80, 0xCA, 0x05, 0x75, 0xCC, 0x9B, 0xCC, + 0x81, 0xCA, 0x05, 0x75, 0xCC, 0x9B, 0xCC, 0x83, + // Bytes 3b80 - 3bbf + 0xCA, 0x05, 0x75, 0xCC, 0x9B, 0xCC, 0x89, 0xCA, + 0x05, 0x75, 0xCC, 0x9B, 0xCC, 0xA3, 0xB6, 0x05, + 0xE1, 0xBE, 0xBF, 0xCC, 0x80, 0xCA, 0x05, 0xE1, + 0xBE, 0xBF, 0xCC, 0x81, 0xCA, 0x05, 0xE1, 0xBE, + 0xBF, 0xCD, 0x82, 0xCA, 0x05, 0xE1, 0xBF, 0xBE, + 0xCC, 0x80, 0xCA, 0x05, 0xE1, 0xBF, 0xBE, 0xCC, + 0x81, 0xCA, 0x05, 0xE1, 0xBF, 0xBE, 0xCD, 0x82, + 0xCA, 0x05, 0xE2, 0x86, 0x90, 0xCC, 0xB8, 0x05, + // Bytes 3bc0 - 3bff + 0x05, 0xE2, 0x86, 0x92, 0xCC, 0xB8, 0x05, 0x05, + 0xE2, 0x86, 0x94, 0xCC, 0xB8, 0x05, 0x05, 0xE2, + 0x87, 0x90, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x87, + 0x92, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x87, 0x94, + 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x88, 0x83, 0xCC, + 0xB8, 0x05, 0x05, 0xE2, 0x88, 0x88, 0xCC, 0xB8, + 0x05, 0x05, 0xE2, 0x88, 0x8B, 0xCC, 0xB8, 0x05, + 0x05, 0xE2, 0x88, 0xA3, 0xCC, 0xB8, 0x05, 0x05, + // Bytes 3c00 - 3c3f + 0xE2, 0x88, 0xA5, 0xCC, 0xB8, 0x05, 0x05, 0xE2, + 0x88, 0xBC, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, + 0x83, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, 0x85, + 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, 0x88, 0xCC, + 0xB8, 0x05, 0x05, 0xE2, 0x89, 0x8D, 0xCC, 0xB8, + 0x05, 0x05, 0xE2, 0x89, 0xA1, 0xCC, 0xB8, 0x05, + 0x05, 0xE2, 0x89, 0xA4, 0xCC, 0xB8, 0x05, 0x05, + 0xE2, 0x89, 0xA5, 0xCC, 0xB8, 0x05, 0x05, 0xE2, + // Bytes 3c40 - 3c7f + 0x89, 0xB2, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, + 0xB3, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, 0xB6, + 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, 0xB7, 0xCC, + 0xB8, 0x05, 0x05, 0xE2, 0x89, 0xBA, 0xCC, 0xB8, + 0x05, 0x05, 0xE2, 0x89, 0xBB, 0xCC, 0xB8, 0x05, + 0x05, 0xE2, 0x89, 0xBC, 0xCC, 0xB8, 0x05, 0x05, + 0xE2, 0x89, 0xBD, 0xCC, 0xB8, 0x05, 0x05, 0xE2, + 0x8A, 0x82, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, + // Bytes 3c80 - 3cbf + 0x83, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0x86, + 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0x87, 0xCC, + 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0x91, 0xCC, 0xB8, + 0x05, 0x05, 0xE2, 0x8A, 0x92, 0xCC, 0xB8, 0x05, + 0x05, 0xE2, 0x8A, 0xA2, 0xCC, 0xB8, 0x05, 0x05, + 0xE2, 0x8A, 0xA8, 0xCC, 0xB8, 0x05, 0x05, 0xE2, + 0x8A, 0xA9, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, + 0xAB, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0xB2, + // Bytes 3cc0 - 3cff + 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0xB3, 0xCC, + 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0xB4, 0xCC, 0xB8, + 0x05, 0x05, 0xE2, 0x8A, 0xB5, 0xCC, 0xB8, 0x05, + 0x06, 0xCE, 0x91, 0xCC, 0x93, 0xCD, 0x85, 0xDA, + 0x06, 0xCE, 0x91, 0xCC, 0x94, 0xCD, 0x85, 0xDA, + 0x06, 0xCE, 0x95, 0xCC, 0x93, 0xCC, 0x80, 0xCA, + 0x06, 0xCE, 0x95, 0xCC, 0x93, 0xCC, 0x81, 0xCA, + 0x06, 0xCE, 0x95, 0xCC, 0x94, 0xCC, 0x80, 0xCA, + // Bytes 3d00 - 3d3f + 0x06, 0xCE, 0x95, 0xCC, 0x94, 0xCC, 0x81, 0xCA, + 0x06, 0xCE, 0x97, 0xCC, 0x93, 0xCD, 0x85, 0xDA, + 0x06, 0xCE, 0x97, 0xCC, 0x94, 0xCD, 0x85, 0xDA, + 0x06, 0xCE, 0x99, 0xCC, 0x93, 0xCC, 0x80, 0xCA, + 0x06, 0xCE, 0x99, 0xCC, 0x93, 0xCC, 0x81, 0xCA, + 0x06, 0xCE, 0x99, 0xCC, 0x93, 0xCD, 0x82, 0xCA, + 0x06, 0xCE, 0x99, 0xCC, 0x94, 0xCC, 0x80, 0xCA, + 0x06, 0xCE, 0x99, 0xCC, 0x94, 0xCC, 0x81, 0xCA, + // Bytes 3d40 - 3d7f + 0x06, 0xCE, 0x99, 0xCC, 0x94, 0xCD, 0x82, 0xCA, + 0x06, 0xCE, 0x9F, 0xCC, 0x93, 0xCC, 0x80, 0xCA, + 0x06, 0xCE, 0x9F, 0xCC, 0x93, 0xCC, 0x81, 0xCA, + 0x06, 0xCE, 0x9F, 0xCC, 0x94, 0xCC, 0x80, 0xCA, + 0x06, 0xCE, 0x9F, 0xCC, 0x94, 0xCC, 0x81, 0xCA, + 0x06, 0xCE, 0xA5, 0xCC, 0x94, 0xCC, 0x80, 0xCA, + 0x06, 0xCE, 0xA5, 0xCC, 0x94, 0xCC, 0x81, 0xCA, + 0x06, 0xCE, 0xA5, 0xCC, 0x94, 0xCD, 0x82, 0xCA, + // Bytes 3d80 - 3dbf + 0x06, 0xCE, 0xA9, 0xCC, 0x93, 0xCD, 0x85, 0xDA, + 0x06, 0xCE, 0xA9, 0xCC, 0x94, 0xCD, 0x85, 0xDA, + 0x06, 0xCE, 0xB1, 0xCC, 0x80, 0xCD, 0x85, 0xDA, + 0x06, 0xCE, 0xB1, 0xCC, 0x81, 0xCD, 0x85, 0xDA, + 0x06, 0xCE, 0xB1, 0xCC, 0x93, 0xCD, 0x85, 0xDA, + 0x06, 0xCE, 0xB1, 0xCC, 0x94, 0xCD, 0x85, 0xDA, + 0x06, 0xCE, 0xB1, 0xCD, 0x82, 0xCD, 0x85, 0xDA, + 0x06, 0xCE, 0xB5, 0xCC, 0x93, 0xCC, 0x80, 0xCA, + // Bytes 3dc0 - 3dff + 0x06, 0xCE, 0xB5, 0xCC, 0x93, 0xCC, 0x81, 0xCA, + 0x06, 0xCE, 0xB5, 0xCC, 0x94, 0xCC, 0x80, 0xCA, + 0x06, 0xCE, 0xB5, 0xCC, 0x94, 0xCC, 0x81, 0xCA, + 0x06, 0xCE, 0xB7, 0xCC, 0x80, 0xCD, 0x85, 0xDA, + 0x06, 0xCE, 0xB7, 0xCC, 0x81, 0xCD, 0x85, 0xDA, + 0x06, 0xCE, 0xB7, 0xCC, 0x93, 0xCD, 0x85, 0xDA, + 0x06, 0xCE, 0xB7, 0xCC, 0x94, 0xCD, 0x85, 0xDA, + 0x06, 0xCE, 0xB7, 0xCD, 0x82, 0xCD, 0x85, 0xDA, + // Bytes 3e00 - 3e3f + 0x06, 0xCE, 0xB9, 0xCC, 0x88, 0xCC, 0x80, 0xCA, + 0x06, 0xCE, 0xB9, 0xCC, 0x88, 0xCC, 0x81, 0xCA, + 0x06, 0xCE, 0xB9, 0xCC, 0x88, 0xCD, 0x82, 0xCA, + 0x06, 0xCE, 0xB9, 0xCC, 0x93, 0xCC, 0x80, 0xCA, + 0x06, 0xCE, 0xB9, 0xCC, 0x93, 0xCC, 0x81, 0xCA, + 0x06, 0xCE, 0xB9, 0xCC, 0x93, 0xCD, 0x82, 0xCA, + 0x06, 0xCE, 0xB9, 0xCC, 0x94, 0xCC, 0x80, 0xCA, + 0x06, 0xCE, 0xB9, 0xCC, 0x94, 0xCC, 0x81, 0xCA, + // Bytes 3e40 - 3e7f + 0x06, 0xCE, 0xB9, 0xCC, 0x94, 0xCD, 0x82, 0xCA, + 0x06, 0xCE, 0xBF, 0xCC, 0x93, 0xCC, 0x80, 0xCA, + 0x06, 0xCE, 0xBF, 0xCC, 0x93, 0xCC, 0x81, 0xCA, + 0x06, 0xCE, 0xBF, 0xCC, 0x94, 0xCC, 0x80, 0xCA, + 0x06, 0xCE, 0xBF, 0xCC, 0x94, 0xCC, 0x81, 0xCA, + 0x06, 0xCF, 0x85, 0xCC, 0x88, 0xCC, 0x80, 0xCA, + 0x06, 0xCF, 0x85, 0xCC, 0x88, 0xCC, 0x81, 0xCA, + 0x06, 0xCF, 0x85, 0xCC, 0x88, 0xCD, 0x82, 0xCA, + // Bytes 3e80 - 3ebf + 0x06, 0xCF, 0x85, 0xCC, 0x93, 0xCC, 0x80, 0xCA, + 0x06, 0xCF, 0x85, 0xCC, 0x93, 0xCC, 0x81, 0xCA, + 0x06, 0xCF, 0x85, 0xCC, 0x93, 0xCD, 0x82, 0xCA, + 0x06, 0xCF, 0x85, 0xCC, 0x94, 0xCC, 0x80, 0xCA, + 0x06, 0xCF, 0x85, 0xCC, 0x94, 0xCC, 0x81, 0xCA, + 0x06, 0xCF, 0x85, 0xCC, 0x94, 0xCD, 0x82, 0xCA, + 0x06, 0xCF, 0x89, 0xCC, 0x80, 0xCD, 0x85, 0xDA, + 0x06, 0xCF, 0x89, 0xCC, 0x81, 0xCD, 0x85, 0xDA, + // Bytes 3ec0 - 3eff + 0x06, 0xCF, 0x89, 0xCC, 0x93, 0xCD, 0x85, 0xDA, + 0x06, 0xCF, 0x89, 0xCC, 0x94, 0xCD, 0x85, 0xDA, + 0x06, 0xCF, 0x89, 0xCD, 0x82, 0xCD, 0x85, 0xDA, + 0x06, 0xE0, 0xA4, 0xA8, 0xE0, 0xA4, 0xBC, 0x09, + 0x06, 0xE0, 0xA4, 0xB0, 0xE0, 0xA4, 0xBC, 0x09, + 0x06, 0xE0, 0xA4, 0xB3, 0xE0, 0xA4, 0xBC, 0x09, + 0x06, 0xE0, 0xB1, 0x86, 0xE0, 0xB1, 0x96, 0x85, + 0x06, 0xE0, 0xB7, 0x99, 0xE0, 0xB7, 0x8A, 0x11, + // Bytes 3f00 - 3f3f + 0x06, 0xE3, 0x81, 0x86, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0x8B, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0x8D, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0x8F, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0x91, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0x93, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0x95, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0x97, 0xE3, 0x82, 0x99, 0x0D, + // Bytes 3f40 - 3f7f + 0x06, 0xE3, 0x81, 0x99, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0x9B, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0x9D, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0x9F, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0xA1, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0xA4, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0xA6, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0xA8, 0xE3, 0x82, 0x99, 0x0D, + // Bytes 3f80 - 3fbf + 0x06, 0xE3, 0x81, 0xAF, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0xAF, 0xE3, 0x82, 0x9A, 0x0D, + 0x06, 0xE3, 0x81, 0xB2, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0xB2, 0xE3, 0x82, 0x9A, 0x0D, + 0x06, 0xE3, 0x81, 0xB5, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0xB5, 0xE3, 0x82, 0x9A, 0x0D, + 0x06, 0xE3, 0x81, 0xB8, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0xB8, 0xE3, 0x82, 0x9A, 0x0D, + // Bytes 3fc0 - 3fff + 0x06, 0xE3, 0x81, 0xBB, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x81, 0xBB, 0xE3, 0x82, 0x9A, 0x0D, + 0x06, 0xE3, 0x82, 0x9D, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x82, 0xA6, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x82, 0xAD, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x82, 0xB1, 0xE3, 0x82, 0x99, 0x0D, + // Bytes 4000 - 403f + 0x06, 0xE3, 0x82, 0xB3, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x82, 0xB5, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x82, 0xB7, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x82, 0xB9, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x82, 0xBB, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x82, 0xBD, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x82, 0xBF, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x83, 0x81, 0xE3, 0x82, 0x99, 0x0D, + // Bytes 4040 - 407f + 0x06, 0xE3, 0x83, 0x84, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x83, 0x86, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x9A, 0x0D, + 0x06, 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x9A, 0x0D, + 0x06, 0xE3, 0x83, 0x95, 0xE3, 0x82, 0x99, 0x0D, + // Bytes 4080 - 40bf + 0x06, 0xE3, 0x83, 0x95, 0xE3, 0x82, 0x9A, 0x0D, + 0x06, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x9A, 0x0D, + 0x06, 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x9A, 0x0D, + 0x06, 0xE3, 0x83, 0xAF, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x83, 0xB0, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x83, 0xB1, 0xE3, 0x82, 0x99, 0x0D, + // Bytes 40c0 - 40ff + 0x06, 0xE3, 0x83, 0xB2, 0xE3, 0x82, 0x99, 0x0D, + 0x06, 0xE3, 0x83, 0xBD, 0xE3, 0x82, 0x99, 0x0D, + 0x08, 0xCE, 0x91, 0xCC, 0x93, 0xCC, 0x80, 0xCD, + 0x85, 0xDB, 0x08, 0xCE, 0x91, 0xCC, 0x93, 0xCC, + 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0x91, 0xCC, + 0x93, 0xCD, 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCE, + 0x91, 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85, 0xDB, + 0x08, 0xCE, 0x91, 0xCC, 0x94, 0xCC, 0x81, 0xCD, + // Bytes 4100 - 413f + 0x85, 0xDB, 0x08, 0xCE, 0x91, 0xCC, 0x94, 0xCD, + 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0x97, 0xCC, + 0x93, 0xCC, 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCE, + 0x97, 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, 0xDB, + 0x08, 0xCE, 0x97, 0xCC, 0x93, 0xCD, 0x82, 0xCD, + 0x85, 0xDB, 0x08, 0xCE, 0x97, 0xCC, 0x94, 0xCC, + 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0x97, 0xCC, + 0x94, 0xCC, 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCE, + // Bytes 4140 - 417f + 0x97, 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, 0xDB, + 0x08, 0xCE, 0xA9, 0xCC, 0x93, 0xCC, 0x80, 0xCD, + 0x85, 0xDB, 0x08, 0xCE, 0xA9, 0xCC, 0x93, 0xCC, + 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xA9, 0xCC, + 0x93, 0xCD, 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCE, + 0xA9, 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85, 0xDB, + 0x08, 0xCE, 0xA9, 0xCC, 0x94, 0xCC, 0x81, 0xCD, + 0x85, 0xDB, 0x08, 0xCE, 0xA9, 0xCC, 0x94, 0xCD, + // Bytes 4180 - 41bf + 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xB1, 0xCC, + 0x93, 0xCC, 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCE, + 0xB1, 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, 0xDB, + 0x08, 0xCE, 0xB1, 0xCC, 0x93, 0xCD, 0x82, 0xCD, + 0x85, 0xDB, 0x08, 0xCE, 0xB1, 0xCC, 0x94, 0xCC, + 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xB1, 0xCC, + 0x94, 0xCC, 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCE, + 0xB1, 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, 0xDB, + // Bytes 41c0 - 41ff + 0x08, 0xCE, 0xB7, 0xCC, 0x93, 0xCC, 0x80, 0xCD, + 0x85, 0xDB, 0x08, 0xCE, 0xB7, 0xCC, 0x93, 0xCC, + 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xB7, 0xCC, + 0x93, 0xCD, 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCE, + 0xB7, 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85, 0xDB, + 0x08, 0xCE, 0xB7, 0xCC, 0x94, 0xCC, 0x81, 0xCD, + 0x85, 0xDB, 0x08, 0xCE, 0xB7, 0xCC, 0x94, 0xCD, + 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCF, 0x89, 0xCC, + // Bytes 4200 - 423f + 0x93, 0xCC, 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCF, + 0x89, 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, 0xDB, + 0x08, 0xCF, 0x89, 0xCC, 0x93, 0xCD, 0x82, 0xCD, + 0x85, 0xDB, 0x08, 0xCF, 0x89, 0xCC, 0x94, 0xCC, + 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCF, 0x89, 0xCC, + 0x94, 0xCC, 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCF, + 0x89, 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, 0xDB, + 0x08, 0xF0, 0x91, 0x82, 0x99, 0xF0, 0x91, 0x82, + // Bytes 4240 - 427f + 0xBA, 0x09, 0x08, 0xF0, 0x91, 0x82, 0x9B, 0xF0, + 0x91, 0x82, 0xBA, 0x09, 0x08, 0xF0, 0x91, 0x82, + 0xA5, 0xF0, 0x91, 0x82, 0xBA, 0x09, 0x42, 0xC2, + 0xB4, 0x01, 0x43, 0x20, 0xCC, 0x81, 0xC9, 0x43, + 0x20, 0xCC, 0x83, 0xC9, 0x43, 0x20, 0xCC, 0x84, + 0xC9, 0x43, 0x20, 0xCC, 0x85, 0xC9, 0x43, 0x20, + 0xCC, 0x86, 0xC9, 0x43, 0x20, 0xCC, 0x87, 0xC9, + 0x43, 0x20, 0xCC, 0x88, 0xC9, 0x43, 0x20, 0xCC, + // Bytes 4280 - 42bf + 0x8A, 0xC9, 0x43, 0x20, 0xCC, 0x8B, 0xC9, 0x43, + 0x20, 0xCC, 0x93, 0xC9, 0x43, 0x20, 0xCC, 0x94, + 0xC9, 0x43, 0x20, 0xCC, 0xA7, 0xA5, 0x43, 0x20, + 0xCC, 0xA8, 0xA5, 0x43, 0x20, 0xCC, 0xB3, 0xB5, + 0x43, 0x20, 0xCD, 0x82, 0xC9, 0x43, 0x20, 0xCD, + 0x85, 0xD9, 0x43, 0x20, 0xD9, 0x8B, 0x59, 0x43, + 0x20, 0xD9, 0x8C, 0x5D, 0x43, 0x20, 0xD9, 0x8D, + 0x61, 0x43, 0x20, 0xD9, 0x8E, 0x65, 0x43, 0x20, + // Bytes 42c0 - 42ff + 0xD9, 0x8F, 0x69, 0x43, 0x20, 0xD9, 0x90, 0x6D, + 0x43, 0x20, 0xD9, 0x91, 0x71, 0x43, 0x20, 0xD9, + 0x92, 0x75, 0x43, 0x41, 0xCC, 0x8A, 0xC9, 0x43, + 0x73, 0xCC, 0x87, 0xC9, 0x44, 0x20, 0xE3, 0x82, + 0x99, 0x0D, 0x44, 0x20, 0xE3, 0x82, 0x9A, 0x0D, + 0x44, 0xC2, 0xA8, 0xCC, 0x81, 0xCA, 0x44, 0xCE, + 0x91, 0xCC, 0x81, 0xC9, 0x44, 0xCE, 0x95, 0xCC, + 0x81, 0xC9, 0x44, 0xCE, 0x97, 0xCC, 0x81, 0xC9, + // Bytes 4300 - 433f + 0x44, 0xCE, 0x99, 0xCC, 0x81, 0xC9, 0x44, 0xCE, + 0x9F, 0xCC, 0x81, 0xC9, 0x44, 0xCE, 0xA5, 0xCC, + 0x81, 0xC9, 0x44, 0xCE, 0xA5, 0xCC, 0x88, 0xC9, + 0x44, 0xCE, 0xA9, 0xCC, 0x81, 0xC9, 0x44, 0xCE, + 0xB1, 0xCC, 0x81, 0xC9, 0x44, 0xCE, 0xB5, 0xCC, + 0x81, 0xC9, 0x44, 0xCE, 0xB7, 0xCC, 0x81, 0xC9, + 0x44, 0xCE, 0xB9, 0xCC, 0x81, 0xC9, 0x44, 0xCE, + 0xBF, 0xCC, 0x81, 0xC9, 0x44, 0xCF, 0x85, 0xCC, + // Bytes 4340 - 437f + 0x81, 0xC9, 0x44, 0xCF, 0x89, 0xCC, 0x81, 0xC9, + 0x44, 0xD7, 0x90, 0xD6, 0xB7, 0x31, 0x44, 0xD7, + 0x90, 0xD6, 0xB8, 0x35, 0x44, 0xD7, 0x90, 0xD6, + 0xBC, 0x41, 0x44, 0xD7, 0x91, 0xD6, 0xBC, 0x41, + 0x44, 0xD7, 0x91, 0xD6, 0xBF, 0x49, 0x44, 0xD7, + 0x92, 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0x93, 0xD6, + 0xBC, 0x41, 0x44, 0xD7, 0x94, 0xD6, 0xBC, 0x41, + 0x44, 0xD7, 0x95, 0xD6, 0xB9, 0x39, 0x44, 0xD7, + // Bytes 4380 - 43bf + 0x95, 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0x96, 0xD6, + 0xBC, 0x41, 0x44, 0xD7, 0x98, 0xD6, 0xBC, 0x41, + 0x44, 0xD7, 0x99, 0xD6, 0xB4, 0x25, 0x44, 0xD7, + 0x99, 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0x9A, 0xD6, + 0xBC, 0x41, 0x44, 0xD7, 0x9B, 0xD6, 0xBC, 0x41, + 0x44, 0xD7, 0x9B, 0xD6, 0xBF, 0x49, 0x44, 0xD7, + 0x9C, 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0x9E, 0xD6, + 0xBC, 0x41, 0x44, 0xD7, 0xA0, 0xD6, 0xBC, 0x41, + // Bytes 43c0 - 43ff + 0x44, 0xD7, 0xA1, 0xD6, 0xBC, 0x41, 0x44, 0xD7, + 0xA3, 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0xA4, 0xD6, + 0xBC, 0x41, 0x44, 0xD7, 0xA4, 0xD6, 0xBF, 0x49, + 0x44, 0xD7, 0xA6, 0xD6, 0xBC, 0x41, 0x44, 0xD7, + 0xA7, 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0xA8, 0xD6, + 0xBC, 0x41, 0x44, 0xD7, 0xA9, 0xD6, 0xBC, 0x41, + 0x44, 0xD7, 0xA9, 0xD7, 0x81, 0x4D, 0x44, 0xD7, + 0xA9, 0xD7, 0x82, 0x51, 0x44, 0xD7, 0xAA, 0xD6, + // Bytes 4400 - 443f + 0xBC, 0x41, 0x44, 0xD7, 0xB2, 0xD6, 0xB7, 0x31, + 0x44, 0xD8, 0xA7, 0xD9, 0x8B, 0x59, 0x44, 0xD8, + 0xA7, 0xD9, 0x93, 0xC9, 0x44, 0xD8, 0xA7, 0xD9, + 0x94, 0xC9, 0x44, 0xD8, 0xA7, 0xD9, 0x95, 0xB5, + 0x44, 0xD8, 0xB0, 0xD9, 0xB0, 0x79, 0x44, 0xD8, + 0xB1, 0xD9, 0xB0, 0x79, 0x44, 0xD9, 0x80, 0xD9, + 0x8B, 0x59, 0x44, 0xD9, 0x80, 0xD9, 0x8E, 0x65, + 0x44, 0xD9, 0x80, 0xD9, 0x8F, 0x69, 0x44, 0xD9, + // Bytes 4440 - 447f + 0x80, 0xD9, 0x90, 0x6D, 0x44, 0xD9, 0x80, 0xD9, + 0x91, 0x71, 0x44, 0xD9, 0x80, 0xD9, 0x92, 0x75, + 0x44, 0xD9, 0x87, 0xD9, 0xB0, 0x79, 0x44, 0xD9, + 0x88, 0xD9, 0x94, 0xC9, 0x44, 0xD9, 0x89, 0xD9, + 0xB0, 0x79, 0x44, 0xD9, 0x8A, 0xD9, 0x94, 0xC9, + 0x44, 0xDB, 0x92, 0xD9, 0x94, 0xC9, 0x44, 0xDB, + 0x95, 0xD9, 0x94, 0xC9, 0x45, 0x20, 0xCC, 0x88, + 0xCC, 0x80, 0xCA, 0x45, 0x20, 0xCC, 0x88, 0xCC, + // Bytes 4480 - 44bf + 0x81, 0xCA, 0x45, 0x20, 0xCC, 0x88, 0xCD, 0x82, + 0xCA, 0x45, 0x20, 0xCC, 0x93, 0xCC, 0x80, 0xCA, + 0x45, 0x20, 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x45, + 0x20, 0xCC, 0x93, 0xCD, 0x82, 0xCA, 0x45, 0x20, + 0xCC, 0x94, 0xCC, 0x80, 0xCA, 0x45, 0x20, 0xCC, + 0x94, 0xCC, 0x81, 0xCA, 0x45, 0x20, 0xCC, 0x94, + 0xCD, 0x82, 0xCA, 0x45, 0x20, 0xD9, 0x8C, 0xD9, + 0x91, 0x72, 0x45, 0x20, 0xD9, 0x8D, 0xD9, 0x91, + // Bytes 44c0 - 44ff + 0x72, 0x45, 0x20, 0xD9, 0x8E, 0xD9, 0x91, 0x72, + 0x45, 0x20, 0xD9, 0x8F, 0xD9, 0x91, 0x72, 0x45, + 0x20, 0xD9, 0x90, 0xD9, 0x91, 0x72, 0x45, 0x20, + 0xD9, 0x91, 0xD9, 0xB0, 0x7A, 0x45, 0xE2, 0xAB, + 0x9D, 0xCC, 0xB8, 0x05, 0x46, 0xCE, 0xB9, 0xCC, + 0x88, 0xCC, 0x81, 0xCA, 0x46, 0xCF, 0x85, 0xCC, + 0x88, 0xCC, 0x81, 0xCA, 0x46, 0xD7, 0xA9, 0xD6, + 0xBC, 0xD7, 0x81, 0x4E, 0x46, 0xD7, 0xA9, 0xD6, + // Bytes 4500 - 453f + 0xBC, 0xD7, 0x82, 0x52, 0x46, 0xD9, 0x80, 0xD9, + 0x8E, 0xD9, 0x91, 0x72, 0x46, 0xD9, 0x80, 0xD9, + 0x8F, 0xD9, 0x91, 0x72, 0x46, 0xD9, 0x80, 0xD9, + 0x90, 0xD9, 0x91, 0x72, 0x46, 0xE0, 0xA4, 0x95, + 0xE0, 0xA4, 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0x96, + 0xE0, 0xA4, 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0x97, + 0xE0, 0xA4, 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0x9C, + 0xE0, 0xA4, 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0xA1, + // Bytes 4540 - 457f + 0xE0, 0xA4, 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0xA2, + 0xE0, 0xA4, 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0xAB, + 0xE0, 0xA4, 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0xAF, + 0xE0, 0xA4, 0xBC, 0x09, 0x46, 0xE0, 0xA6, 0xA1, + 0xE0, 0xA6, 0xBC, 0x09, 0x46, 0xE0, 0xA6, 0xA2, + 0xE0, 0xA6, 0xBC, 0x09, 0x46, 0xE0, 0xA6, 0xAF, + 0xE0, 0xA6, 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0x96, + 0xE0, 0xA8, 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0x97, + // Bytes 4580 - 45bf + 0xE0, 0xA8, 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0x9C, + 0xE0, 0xA8, 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0xAB, + 0xE0, 0xA8, 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0xB2, + 0xE0, 0xA8, 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0xB8, + 0xE0, 0xA8, 0xBC, 0x09, 0x46, 0xE0, 0xAC, 0xA1, + 0xE0, 0xAC, 0xBC, 0x09, 0x46, 0xE0, 0xAC, 0xA2, + 0xE0, 0xAC, 0xBC, 0x09, 0x46, 0xE0, 0xBE, 0xB2, + 0xE0, 0xBE, 0x80, 0x9D, 0x46, 0xE0, 0xBE, 0xB3, + // Bytes 45c0 - 45ff + 0xE0, 0xBE, 0x80, 0x9D, 0x46, 0xE3, 0x83, 0x86, + 0xE3, 0x82, 0x99, 0x0D, 0x48, 0xF0, 0x9D, 0x85, + 0x97, 0xF0, 0x9D, 0x85, 0xA5, 0xAD, 0x48, 0xF0, + 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xAD, + 0x48, 0xF0, 0x9D, 0x86, 0xB9, 0xF0, 0x9D, 0x85, + 0xA5, 0xAD, 0x48, 0xF0, 0x9D, 0x86, 0xBA, 0xF0, + 0x9D, 0x85, 0xA5, 0xAD, 0x49, 0xE0, 0xBE, 0xB2, + 0xE0, 0xBD, 0xB1, 0xE0, 0xBE, 0x80, 0x9E, 0x49, + // Bytes 4600 - 463f + 0xE0, 0xBE, 0xB3, 0xE0, 0xBD, 0xB1, 0xE0, 0xBE, + 0x80, 0x9E, 0x4C, 0xF0, 0x9D, 0x85, 0x98, 0xF0, + 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAE, 0xAE, + 0x4C, 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85, + 0xA5, 0xF0, 0x9D, 0x85, 0xAF, 0xAE, 0x4C, 0xF0, + 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, + 0x9D, 0x85, 0xB0, 0xAE, 0x4C, 0xF0, 0x9D, 0x85, + 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, + // Bytes 4640 - 467f + 0xB1, 0xAE, 0x4C, 0xF0, 0x9D, 0x85, 0x98, 0xF0, + 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xB2, 0xAE, + 0x4C, 0xF0, 0x9D, 0x86, 0xB9, 0xF0, 0x9D, 0x85, + 0xA5, 0xF0, 0x9D, 0x85, 0xAE, 0xAE, 0x4C, 0xF0, + 0x9D, 0x86, 0xB9, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, + 0x9D, 0x85, 0xAF, 0xAE, 0x4C, 0xF0, 0x9D, 0x86, + 0xBA, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, + 0xAE, 0xAE, 0x4C, 0xF0, 0x9D, 0x86, 0xBA, 0xF0, + // Bytes 4680 - 46bf + 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAF, 0xAE, + 0x83, 0x41, 0xCC, 0x82, 0xC9, 0x83, 0x41, 0xCC, + 0x86, 0xC9, 0x83, 0x41, 0xCC, 0x87, 0xC9, 0x83, + 0x41, 0xCC, 0x88, 0xC9, 0x83, 0x41, 0xCC, 0x8A, + 0xC9, 0x83, 0x41, 0xCC, 0xA3, 0xB5, 0x83, 0x43, + 0xCC, 0xA7, 0xA5, 0x83, 0x45, 0xCC, 0x82, 0xC9, + 0x83, 0x45, 0xCC, 0x84, 0xC9, 0x83, 0x45, 0xCC, + 0xA3, 0xB5, 0x83, 0x45, 0xCC, 0xA7, 0xA5, 0x83, + // Bytes 46c0 - 46ff + 0x49, 0xCC, 0x88, 0xC9, 0x83, 0x4C, 0xCC, 0xA3, + 0xB5, 0x83, 0x4F, 0xCC, 0x82, 0xC9, 0x83, 0x4F, + 0xCC, 0x83, 0xC9, 0x83, 0x4F, 0xCC, 0x84, 0xC9, + 0x83, 0x4F, 0xCC, 0x87, 0xC9, 0x83, 0x4F, 0xCC, + 0x88, 0xC9, 0x83, 0x4F, 0xCC, 0x9B, 0xAD, 0x83, + 0x4F, 0xCC, 0xA3, 0xB5, 0x83, 0x4F, 0xCC, 0xA8, + 0xA5, 0x83, 0x52, 0xCC, 0xA3, 0xB5, 0x83, 0x53, + 0xCC, 0x81, 0xC9, 0x83, 0x53, 0xCC, 0x8C, 0xC9, + // Bytes 4700 - 473f + 0x83, 0x53, 0xCC, 0xA3, 0xB5, 0x83, 0x55, 0xCC, + 0x83, 0xC9, 0x83, 0x55, 0xCC, 0x84, 0xC9, 0x83, + 0x55, 0xCC, 0x88, 0xC9, 0x83, 0x55, 0xCC, 0x9B, + 0xAD, 0x83, 0x61, 0xCC, 0x82, 0xC9, 0x83, 0x61, + 0xCC, 0x86, 0xC9, 0x83, 0x61, 0xCC, 0x87, 0xC9, + 0x83, 0x61, 0xCC, 0x88, 0xC9, 0x83, 0x61, 0xCC, + 0x8A, 0xC9, 0x83, 0x61, 0xCC, 0xA3, 0xB5, 0x83, + 0x63, 0xCC, 0xA7, 0xA5, 0x83, 0x65, 0xCC, 0x82, + // Bytes 4740 - 477f + 0xC9, 0x83, 0x65, 0xCC, 0x84, 0xC9, 0x83, 0x65, + 0xCC, 0xA3, 0xB5, 0x83, 0x65, 0xCC, 0xA7, 0xA5, + 0x83, 0x69, 0xCC, 0x88, 0xC9, 0x83, 0x6C, 0xCC, + 0xA3, 0xB5, 0x83, 0x6F, 0xCC, 0x82, 0xC9, 0x83, + 0x6F, 0xCC, 0x83, 0xC9, 0x83, 0x6F, 0xCC, 0x84, + 0xC9, 0x83, 0x6F, 0xCC, 0x87, 0xC9, 0x83, 0x6F, + 0xCC, 0x88, 0xC9, 0x83, 0x6F, 0xCC, 0x9B, 0xAD, + 0x83, 0x6F, 0xCC, 0xA3, 0xB5, 0x83, 0x6F, 0xCC, + // Bytes 4780 - 47bf + 0xA8, 0xA5, 0x83, 0x72, 0xCC, 0xA3, 0xB5, 0x83, + 0x73, 0xCC, 0x81, 0xC9, 0x83, 0x73, 0xCC, 0x8C, + 0xC9, 0x83, 0x73, 0xCC, 0xA3, 0xB5, 0x83, 0x75, + 0xCC, 0x83, 0xC9, 0x83, 0x75, 0xCC, 0x84, 0xC9, + 0x83, 0x75, 0xCC, 0x88, 0xC9, 0x83, 0x75, 0xCC, + 0x9B, 0xAD, 0x84, 0xCE, 0x91, 0xCC, 0x93, 0xC9, + 0x84, 0xCE, 0x91, 0xCC, 0x94, 0xC9, 0x84, 0xCE, + 0x95, 0xCC, 0x93, 0xC9, 0x84, 0xCE, 0x95, 0xCC, + // Bytes 47c0 - 47ff + 0x94, 0xC9, 0x84, 0xCE, 0x97, 0xCC, 0x93, 0xC9, + 0x84, 0xCE, 0x97, 0xCC, 0x94, 0xC9, 0x84, 0xCE, + 0x99, 0xCC, 0x93, 0xC9, 0x84, 0xCE, 0x99, 0xCC, + 0x94, 0xC9, 0x84, 0xCE, 0x9F, 0xCC, 0x93, 0xC9, + 0x84, 0xCE, 0x9F, 0xCC, 0x94, 0xC9, 0x84, 0xCE, + 0xA5, 0xCC, 0x94, 0xC9, 0x84, 0xCE, 0xA9, 0xCC, + 0x93, 0xC9, 0x84, 0xCE, 0xA9, 0xCC, 0x94, 0xC9, + 0x84, 0xCE, 0xB1, 0xCC, 0x80, 0xC9, 0x84, 0xCE, + // Bytes 4800 - 483f + 0xB1, 0xCC, 0x81, 0xC9, 0x84, 0xCE, 0xB1, 0xCC, + 0x93, 0xC9, 0x84, 0xCE, 0xB1, 0xCC, 0x94, 0xC9, + 0x84, 0xCE, 0xB1, 0xCD, 0x82, 0xC9, 0x84, 0xCE, + 0xB5, 0xCC, 0x93, 0xC9, 0x84, 0xCE, 0xB5, 0xCC, + 0x94, 0xC9, 0x84, 0xCE, 0xB7, 0xCC, 0x80, 0xC9, + 0x84, 0xCE, 0xB7, 0xCC, 0x81, 0xC9, 0x84, 0xCE, + 0xB7, 0xCC, 0x93, 0xC9, 0x84, 0xCE, 0xB7, 0xCC, + 0x94, 0xC9, 0x84, 0xCE, 0xB7, 0xCD, 0x82, 0xC9, + // Bytes 4840 - 487f + 0x84, 0xCE, 0xB9, 0xCC, 0x88, 0xC9, 0x84, 0xCE, + 0xB9, 0xCC, 0x93, 0xC9, 0x84, 0xCE, 0xB9, 0xCC, + 0x94, 0xC9, 0x84, 0xCE, 0xBF, 0xCC, 0x93, 0xC9, + 0x84, 0xCE, 0xBF, 0xCC, 0x94, 0xC9, 0x84, 0xCF, + 0x85, 0xCC, 0x88, 0xC9, 0x84, 0xCF, 0x85, 0xCC, + 0x93, 0xC9, 0x84, 0xCF, 0x85, 0xCC, 0x94, 0xC9, + 0x84, 0xCF, 0x89, 0xCC, 0x80, 0xC9, 0x84, 0xCF, + 0x89, 0xCC, 0x81, 0xC9, 0x84, 0xCF, 0x89, 0xCC, + // Bytes 4880 - 48bf + 0x93, 0xC9, 0x84, 0xCF, 0x89, 0xCC, 0x94, 0xC9, + 0x84, 0xCF, 0x89, 0xCD, 0x82, 0xC9, 0x86, 0xCE, + 0x91, 0xCC, 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCE, + 0x91, 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCE, + 0x91, 0xCC, 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCE, + 0x91, 0xCC, 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCE, + 0x91, 0xCC, 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCE, + 0x91, 0xCC, 0x94, 0xCD, 0x82, 0xCA, 0x86, 0xCE, + // Bytes 48c0 - 48ff + 0x97, 0xCC, 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCE, + 0x97, 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCE, + 0x97, 0xCC, 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCE, + 0x97, 0xCC, 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCE, + 0x97, 0xCC, 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCE, + 0x97, 0xCC, 0x94, 0xCD, 0x82, 0xCA, 0x86, 0xCE, + 0xA9, 0xCC, 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCE, + 0xA9, 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCE, + // Bytes 4900 - 493f + 0xA9, 0xCC, 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCE, + 0xA9, 0xCC, 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCE, + 0xA9, 0xCC, 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCE, + 0xA9, 0xCC, 0x94, 0xCD, 0x82, 0xCA, 0x86, 0xCE, + 0xB1, 0xCC, 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCE, + 0xB1, 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCE, + 0xB1, 0xCC, 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCE, + 0xB1, 0xCC, 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCE, + // Bytes 4940 - 497f + 0xB1, 0xCC, 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCE, + 0xB1, 0xCC, 0x94, 0xCD, 0x82, 0xCA, 0x86, 0xCE, + 0xB7, 0xCC, 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCE, + 0xB7, 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCE, + 0xB7, 0xCC, 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCE, + 0xB7, 0xCC, 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCE, + 0xB7, 0xCC, 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCE, + 0xB7, 0xCC, 0x94, 0xCD, 0x82, 0xCA, 0x86, 0xCF, + // Bytes 4980 - 49bf + 0x89, 0xCC, 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCF, + 0x89, 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCF, + 0x89, 0xCC, 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCF, + 0x89, 0xCC, 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCF, + 0x89, 0xCC, 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCF, + 0x89, 0xCC, 0x94, 0xCD, 0x82, 0xCA, 0x42, 0xCC, + 0x80, 0xC9, 0x32, 0x42, 0xCC, 0x81, 0xC9, 0x32, + 0x42, 0xCC, 0x93, 0xC9, 0x32, 0x43, 0xE1, 0x85, + // Bytes 49c0 - 49ff + 0xA1, 0x01, 0x00, 0x43, 0xE1, 0x85, 0xA2, 0x01, + 0x00, 0x43, 0xE1, 0x85, 0xA3, 0x01, 0x00, 0x43, + 0xE1, 0x85, 0xA4, 0x01, 0x00, 0x43, 0xE1, 0x85, + 0xA5, 0x01, 0x00, 0x43, 0xE1, 0x85, 0xA6, 0x01, + 0x00, 0x43, 0xE1, 0x85, 0xA7, 0x01, 0x00, 0x43, + 0xE1, 0x85, 0xA8, 0x01, 0x00, 0x43, 0xE1, 0x85, + 0xA9, 0x01, 0x00, 0x43, 0xE1, 0x85, 0xAA, 0x01, + 0x00, 0x43, 0xE1, 0x85, 0xAB, 0x01, 0x00, 0x43, + // Bytes 4a00 - 4a3f + 0xE1, 0x85, 0xAC, 0x01, 0x00, 0x43, 0xE1, 0x85, + 0xAD, 0x01, 0x00, 0x43, 0xE1, 0x85, 0xAE, 0x01, + 0x00, 0x43, 0xE1, 0x85, 0xAF, 0x01, 0x00, 0x43, + 0xE1, 0x85, 0xB0, 0x01, 0x00, 0x43, 0xE1, 0x85, + 0xB1, 0x01, 0x00, 0x43, 0xE1, 0x85, 0xB2, 0x01, + 0x00, 0x43, 0xE1, 0x85, 0xB3, 0x01, 0x00, 0x43, + 0xE1, 0x85, 0xB4, 0x01, 0x00, 0x43, 0xE1, 0x85, + 0xB5, 0x01, 0x00, 0x43, 0xE1, 0x86, 0xAA, 0x01, + // Bytes 4a40 - 4a7f + 0x00, 0x43, 0xE1, 0x86, 0xAC, 0x01, 0x00, 0x43, + 0xE1, 0x86, 0xAD, 0x01, 0x00, 0x43, 0xE1, 0x86, + 0xB0, 0x01, 0x00, 0x43, 0xE1, 0x86, 0xB1, 0x01, + 0x00, 0x43, 0xE1, 0x86, 0xB2, 0x01, 0x00, 0x43, + 0xE1, 0x86, 0xB3, 0x01, 0x00, 0x43, 0xE1, 0x86, + 0xB4, 0x01, 0x00, 0x43, 0xE1, 0x86, 0xB5, 0x01, + 0x00, 0x44, 0xCC, 0x88, 0xCC, 0x81, 0xCA, 0x32, + 0x43, 0xE3, 0x82, 0x99, 0x0D, 0x03, 0x43, 0xE3, + // Bytes 4a80 - 4abf + 0x82, 0x9A, 0x0D, 0x03, 0x46, 0xE0, 0xBD, 0xB1, + 0xE0, 0xBD, 0xB2, 0x9E, 0x26, 0x46, 0xE0, 0xBD, + 0xB1, 0xE0, 0xBD, 0xB4, 0xA2, 0x26, 0x46, 0xE0, + 0xBD, 0xB1, 0xE0, 0xBE, 0x80, 0x9E, 0x26, 0x00, + 0x01, +} + +// lookup returns the trie value for the first UTF-8 encoding in s and +// the width in bytes of this encoding. The size will be 0 if s does not +// hold enough bytes to complete the encoding. len(s) must be greater than 0. +func (t *nfcTrie) lookup(s []byte) (v uint16, sz int) { + c0 := s[0] + switch { + case c0 < 0x80: // is ASCII + return nfcValues[c0], 1 + case c0 < 0xC2: + return 0, 1 // Illegal UTF-8: not a starter, not ASCII. + case c0 < 0xE0: // 2-byte UTF-8 + if len(s) < 2 { + return 0, 0 + } + i := nfcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c1), 2 + case c0 < 0xF0: // 3-byte UTF-8 + if len(s) < 3 { + return 0, 0 + } + i := nfcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = nfcIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c2), 3 + case c0 < 0xF8: // 4-byte UTF-8 + if len(s) < 4 { + return 0, 0 + } + i := nfcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = nfcIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + o = uint32(i)<<6 + uint32(c2) + i = nfcIndex[o] + c3 := s[3] + if c3 < 0x80 || 0xC0 <= c3 { + return 0, 3 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c3), 4 + } + // Illegal rune + return 0, 1 +} + +// lookupUnsafe returns the trie value for the first UTF-8 encoding in s. +// s must start with a full and valid UTF-8 encoded rune. +func (t *nfcTrie) lookupUnsafe(s []byte) uint16 { + c0 := s[0] + if c0 < 0x80 { // is ASCII + return nfcValues[c0] + } + i := nfcIndex[c0] + if c0 < 0xE0 { // 2-byte UTF-8 + return t.lookupValue(uint32(i), s[1]) + } + i = nfcIndex[uint32(i)<<6+uint32(s[1])] + if c0 < 0xF0 { // 3-byte UTF-8 + return t.lookupValue(uint32(i), s[2]) + } + i = nfcIndex[uint32(i)<<6+uint32(s[2])] + if c0 < 0xF8 { // 4-byte UTF-8 + return t.lookupValue(uint32(i), s[3]) + } + return 0 +} + +// lookupString returns the trie value for the first UTF-8 encoding in s and +// the width in bytes of this encoding. The size will be 0 if s does not +// hold enough bytes to complete the encoding. len(s) must be greater than 0. +func (t *nfcTrie) lookupString(s string) (v uint16, sz int) { + c0 := s[0] + switch { + case c0 < 0x80: // is ASCII + return nfcValues[c0], 1 + case c0 < 0xC2: + return 0, 1 // Illegal UTF-8: not a starter, not ASCII. + case c0 < 0xE0: // 2-byte UTF-8 + if len(s) < 2 { + return 0, 0 + } + i := nfcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c1), 2 + case c0 < 0xF0: // 3-byte UTF-8 + if len(s) < 3 { + return 0, 0 + } + i := nfcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = nfcIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c2), 3 + case c0 < 0xF8: // 4-byte UTF-8 + if len(s) < 4 { + return 0, 0 + } + i := nfcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = nfcIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + o = uint32(i)<<6 + uint32(c2) + i = nfcIndex[o] + c3 := s[3] + if c3 < 0x80 || 0xC0 <= c3 { + return 0, 3 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c3), 4 + } + // Illegal rune + return 0, 1 +} + +// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s. +// s must start with a full and valid UTF-8 encoded rune. +func (t *nfcTrie) lookupStringUnsafe(s string) uint16 { + c0 := s[0] + if c0 < 0x80 { // is ASCII + return nfcValues[c0] + } + i := nfcIndex[c0] + if c0 < 0xE0 { // 2-byte UTF-8 + return t.lookupValue(uint32(i), s[1]) + } + i = nfcIndex[uint32(i)<<6+uint32(s[1])] + if c0 < 0xF0 { // 3-byte UTF-8 + return t.lookupValue(uint32(i), s[2]) + } + i = nfcIndex[uint32(i)<<6+uint32(s[2])] + if c0 < 0xF8 { // 4-byte UTF-8 + return t.lookupValue(uint32(i), s[3]) + } + return 0 +} + +// nfcTrie. Total size: 10332 bytes (10.09 KiB). Checksum: 51cc525b297fc970. +type nfcTrie struct{} + +func newNfcTrie(i int) *nfcTrie { + return &nfcTrie{} +} + +// lookupValue determines the type of block n and looks up the value for b. +func (t *nfcTrie) lookupValue(n uint32, b byte) uint16 { + switch { + case n < 44: + return uint16(nfcValues[n<<6+uint32(b)]) + default: + n -= 44 + return uint16(nfcSparse.lookup(n, b)) + } +} + +// nfcValues: 46 blocks, 2944 entries, 5888 bytes +// The third block is the zero block. +var nfcValues = [2944]uint16{ + // Block 0x0, offset 0x0 + 0x3c: 0xa000, 0x3d: 0xa000, 0x3e: 0xa000, + // Block 0x1, offset 0x40 + 0x41: 0xa000, 0x42: 0xa000, 0x43: 0xa000, 0x44: 0xa000, 0x45: 0xa000, + 0x46: 0xa000, 0x47: 0xa000, 0x48: 0xa000, 0x49: 0xa000, 0x4a: 0xa000, 0x4b: 0xa000, + 0x4c: 0xa000, 0x4d: 0xa000, 0x4e: 0xa000, 0x4f: 0xa000, 0x50: 0xa000, + 0x52: 0xa000, 0x53: 0xa000, 0x54: 0xa000, 0x55: 0xa000, 0x56: 0xa000, 0x57: 0xa000, + 0x58: 0xa000, 0x59: 0xa000, 0x5a: 0xa000, + 0x61: 0xa000, 0x62: 0xa000, 0x63: 0xa000, + 0x64: 0xa000, 0x65: 0xa000, 0x66: 0xa000, 0x67: 0xa000, 0x68: 0xa000, 0x69: 0xa000, + 0x6a: 0xa000, 0x6b: 0xa000, 0x6c: 0xa000, 0x6d: 0xa000, 0x6e: 0xa000, 0x6f: 0xa000, + 0x70: 0xa000, 0x72: 0xa000, 0x73: 0xa000, 0x74: 0xa000, 0x75: 0xa000, + 0x76: 0xa000, 0x77: 0xa000, 0x78: 0xa000, 0x79: 0xa000, 0x7a: 0xa000, + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0xc0: 0x2f6f, 0xc1: 0x2f74, 0xc2: 0x4688, 0xc3: 0x2f79, 0xc4: 0x4697, 0xc5: 0x469c, + 0xc6: 0xa000, 0xc7: 0x46a6, 0xc8: 0x2fe2, 0xc9: 0x2fe7, 0xca: 0x46ab, 0xcb: 0x2ffb, + 0xcc: 0x306e, 0xcd: 0x3073, 0xce: 0x3078, 0xcf: 0x46bf, 0xd1: 0x3104, + 0xd2: 0x3127, 0xd3: 0x312c, 0xd4: 0x46c9, 0xd5: 0x46ce, 0xd6: 0x46dd, + 0xd8: 0xa000, 0xd9: 0x31b3, 0xda: 0x31b8, 0xdb: 0x31bd, 0xdc: 0x470f, 0xdd: 0x3235, + 0xe0: 0x327b, 0xe1: 0x3280, 0xe2: 0x4719, 0xe3: 0x3285, + 0xe4: 0x4728, 0xe5: 0x472d, 0xe6: 0xa000, 0xe7: 0x4737, 0xe8: 0x32ee, 0xe9: 0x32f3, + 0xea: 0x473c, 0xeb: 0x3307, 0xec: 0x337f, 0xed: 0x3384, 0xee: 0x3389, 0xef: 0x4750, + 0xf1: 0x3415, 0xf2: 0x3438, 0xf3: 0x343d, 0xf4: 0x475a, 0xf5: 0x475f, + 0xf6: 0x476e, 0xf8: 0xa000, 0xf9: 0x34c9, 0xfa: 0x34ce, 0xfb: 0x34d3, + 0xfc: 0x47a0, 0xfd: 0x3550, 0xff: 0x3569, + // Block 0x4, offset 0x100 + 0x100: 0x2f7e, 0x101: 0x328a, 0x102: 0x468d, 0x103: 0x471e, 0x104: 0x2f9c, 0x105: 0x32a8, + 0x106: 0x2fb0, 0x107: 0x32bc, 0x108: 0x2fb5, 0x109: 0x32c1, 0x10a: 0x2fba, 0x10b: 0x32c6, + 0x10c: 0x2fbf, 0x10d: 0x32cb, 0x10e: 0x2fc9, 0x10f: 0x32d5, + 0x112: 0x46b0, 0x113: 0x4741, 0x114: 0x2ff1, 0x115: 0x32fd, 0x116: 0x2ff6, 0x117: 0x3302, + 0x118: 0x3014, 0x119: 0x3320, 0x11a: 0x3005, 0x11b: 0x3311, 0x11c: 0x302d, 0x11d: 0x3339, + 0x11e: 0x3037, 0x11f: 0x3343, 0x120: 0x303c, 0x121: 0x3348, 0x122: 0x3046, 0x123: 0x3352, + 0x124: 0x304b, 0x125: 0x3357, 0x128: 0x307d, 0x129: 0x338e, + 0x12a: 0x3082, 0x12b: 0x3393, 0x12c: 0x3087, 0x12d: 0x3398, 0x12e: 0x30aa, 0x12f: 0x33b6, + 0x130: 0x308c, 0x134: 0x30b4, 0x135: 0x33c0, + 0x136: 0x30c8, 0x137: 0x33d9, 0x139: 0x30d2, 0x13a: 0x33e3, 0x13b: 0x30dc, + 0x13c: 0x33ed, 0x13d: 0x30d7, 0x13e: 0x33e8, + // Block 0x5, offset 0x140 + 0x143: 0x30ff, 0x144: 0x3410, 0x145: 0x3118, + 0x146: 0x3429, 0x147: 0x310e, 0x148: 0x341f, + 0x14c: 0x46d3, 0x14d: 0x4764, 0x14e: 0x3131, 0x14f: 0x3442, 0x150: 0x313b, 0x151: 0x344c, + 0x154: 0x3159, 0x155: 0x346a, 0x156: 0x3172, 0x157: 0x3483, + 0x158: 0x3163, 0x159: 0x3474, 0x15a: 0x46f6, 0x15b: 0x4787, 0x15c: 0x317c, 0x15d: 0x348d, + 0x15e: 0x318b, 0x15f: 0x349c, 0x160: 0x46fb, 0x161: 0x478c, 0x162: 0x31a4, 0x163: 0x34ba, + 0x164: 0x3195, 0x165: 0x34ab, 0x168: 0x4705, 0x169: 0x4796, + 0x16a: 0x470a, 0x16b: 0x479b, 0x16c: 0x31c2, 0x16d: 0x34d8, 0x16e: 0x31cc, 0x16f: 0x34e2, + 0x170: 0x31d1, 0x171: 0x34e7, 0x172: 0x31ef, 0x173: 0x3505, 0x174: 0x3212, 0x175: 0x3528, + 0x176: 0x323a, 0x177: 0x3555, 0x178: 0x324e, 0x179: 0x325d, 0x17a: 0x357d, 0x17b: 0x3267, + 0x17c: 0x3587, 0x17d: 0x326c, 0x17e: 0x358c, 0x17f: 0xa000, + // Block 0x6, offset 0x180 + 0x184: 0x8100, 0x185: 0x8100, + 0x186: 0x8100, + 0x18d: 0x2f88, 0x18e: 0x3294, 0x18f: 0x3096, 0x190: 0x33a2, 0x191: 0x3140, + 0x192: 0x3451, 0x193: 0x31d6, 0x194: 0x34ec, 0x195: 0x39cf, 0x196: 0x3b5e, 0x197: 0x39c8, + 0x198: 0x3b57, 0x199: 0x39d6, 0x19a: 0x3b65, 0x19b: 0x39c1, 0x19c: 0x3b50, + 0x19e: 0x38b0, 0x19f: 0x3a3f, 0x1a0: 0x38a9, 0x1a1: 0x3a38, 0x1a2: 0x35b3, 0x1a3: 0x35c5, + 0x1a6: 0x3041, 0x1a7: 0x334d, 0x1a8: 0x30be, 0x1a9: 0x33cf, + 0x1aa: 0x46ec, 0x1ab: 0x477d, 0x1ac: 0x3990, 0x1ad: 0x3b1f, 0x1ae: 0x35d7, 0x1af: 0x35dd, + 0x1b0: 0x33c5, 0x1b4: 0x3028, 0x1b5: 0x3334, + 0x1b8: 0x30fa, 0x1b9: 0x340b, 0x1ba: 0x38b7, 0x1bb: 0x3a46, + 0x1bc: 0x35ad, 0x1bd: 0x35bf, 0x1be: 0x35b9, 0x1bf: 0x35cb, + // Block 0x7, offset 0x1c0 + 0x1c0: 0x2f8d, 0x1c1: 0x3299, 0x1c2: 0x2f92, 0x1c3: 0x329e, 0x1c4: 0x300a, 0x1c5: 0x3316, + 0x1c6: 0x300f, 0x1c7: 0x331b, 0x1c8: 0x309b, 0x1c9: 0x33a7, 0x1ca: 0x30a0, 0x1cb: 0x33ac, + 0x1cc: 0x3145, 0x1cd: 0x3456, 0x1ce: 0x314a, 0x1cf: 0x345b, 0x1d0: 0x3168, 0x1d1: 0x3479, + 0x1d2: 0x316d, 0x1d3: 0x347e, 0x1d4: 0x31db, 0x1d5: 0x34f1, 0x1d6: 0x31e0, 0x1d7: 0x34f6, + 0x1d8: 0x3186, 0x1d9: 0x3497, 0x1da: 0x319f, 0x1db: 0x34b5, + 0x1de: 0x305a, 0x1df: 0x3366, + 0x1e6: 0x4692, 0x1e7: 0x4723, 0x1e8: 0x46ba, 0x1e9: 0x474b, + 0x1ea: 0x395f, 0x1eb: 0x3aee, 0x1ec: 0x393c, 0x1ed: 0x3acb, 0x1ee: 0x46d8, 0x1ef: 0x4769, + 0x1f0: 0x3958, 0x1f1: 0x3ae7, 0x1f2: 0x3244, 0x1f3: 0x355f, + // Block 0x8, offset 0x200 + 0x200: 0x9932, 0x201: 0x9932, 0x202: 0x9932, 0x203: 0x9932, 0x204: 0x9932, 0x205: 0x8132, + 0x206: 0x9932, 0x207: 0x9932, 0x208: 0x9932, 0x209: 0x9932, 0x20a: 0x9932, 0x20b: 0x9932, + 0x20c: 0x9932, 0x20d: 0x8132, 0x20e: 0x8132, 0x20f: 0x9932, 0x210: 0x8132, 0x211: 0x9932, + 0x212: 0x8132, 0x213: 0x9932, 0x214: 0x9932, 0x215: 0x8133, 0x216: 0x812d, 0x217: 0x812d, + 0x218: 0x812d, 0x219: 0x812d, 0x21a: 0x8133, 0x21b: 0x992b, 0x21c: 0x812d, 0x21d: 0x812d, + 0x21e: 0x812d, 0x21f: 0x812d, 0x220: 0x812d, 0x221: 0x8129, 0x222: 0x8129, 0x223: 0x992d, + 0x224: 0x992d, 0x225: 0x992d, 0x226: 0x992d, 0x227: 0x9929, 0x228: 0x9929, 0x229: 0x812d, + 0x22a: 0x812d, 0x22b: 0x812d, 0x22c: 0x812d, 0x22d: 0x992d, 0x22e: 0x992d, 0x22f: 0x812d, + 0x230: 0x992d, 0x231: 0x992d, 0x232: 0x812d, 0x233: 0x812d, 0x234: 0x8101, 0x235: 0x8101, + 0x236: 0x8101, 0x237: 0x8101, 0x238: 0x9901, 0x239: 0x812d, 0x23a: 0x812d, 0x23b: 0x812d, + 0x23c: 0x812d, 0x23d: 0x8132, 0x23e: 0x8132, 0x23f: 0x8132, + // Block 0x9, offset 0x240 + 0x240: 0x49ae, 0x241: 0x49b3, 0x242: 0x9932, 0x243: 0x49b8, 0x244: 0x4a71, 0x245: 0x9936, + 0x246: 0x8132, 0x247: 0x812d, 0x248: 0x812d, 0x249: 0x812d, 0x24a: 0x8132, 0x24b: 0x8132, + 0x24c: 0x8132, 0x24d: 0x812d, 0x24e: 0x812d, 0x250: 0x8132, 0x251: 0x8132, + 0x252: 0x8132, 0x253: 0x812d, 0x254: 0x812d, 0x255: 0x812d, 0x256: 0x812d, 0x257: 0x8132, + 0x258: 0x8133, 0x259: 0x812d, 0x25a: 0x812d, 0x25b: 0x8132, 0x25c: 0x8134, 0x25d: 0x8135, + 0x25e: 0x8135, 0x25f: 0x8134, 0x260: 0x8135, 0x261: 0x8135, 0x262: 0x8134, 0x263: 0x8132, + 0x264: 0x8132, 0x265: 0x8132, 0x266: 0x8132, 0x267: 0x8132, 0x268: 0x8132, 0x269: 0x8132, + 0x26a: 0x8132, 0x26b: 0x8132, 0x26c: 0x8132, 0x26d: 0x8132, 0x26e: 0x8132, 0x26f: 0x8132, + 0x274: 0x0170, + 0x27a: 0x8100, + 0x27e: 0x0037, + // Block 0xa, offset 0x280 + 0x284: 0x8100, 0x285: 0x35a1, + 0x286: 0x35e9, 0x287: 0x00ce, 0x288: 0x3607, 0x289: 0x3613, 0x28a: 0x3625, + 0x28c: 0x3643, 0x28e: 0x3655, 0x28f: 0x3673, 0x290: 0x3e08, 0x291: 0xa000, + 0x295: 0xa000, 0x297: 0xa000, + 0x299: 0xa000, + 0x29f: 0xa000, 0x2a1: 0xa000, + 0x2a5: 0xa000, 0x2a9: 0xa000, + 0x2aa: 0x3637, 0x2ab: 0x3667, 0x2ac: 0x47fe, 0x2ad: 0x3697, 0x2ae: 0x4828, 0x2af: 0x36a9, + 0x2b0: 0x3e70, 0x2b1: 0xa000, 0x2b5: 0xa000, + 0x2b7: 0xa000, 0x2b9: 0xa000, + 0x2bf: 0xa000, + // Block 0xb, offset 0x2c0 + 0x2c0: 0x3721, 0x2c1: 0x372d, 0x2c3: 0x371b, + 0x2c6: 0xa000, 0x2c7: 0x3709, + 0x2cc: 0x375d, 0x2cd: 0x3745, 0x2ce: 0x376f, 0x2d0: 0xa000, + 0x2d3: 0xa000, 0x2d5: 0xa000, 0x2d6: 0xa000, 0x2d7: 0xa000, + 0x2d8: 0xa000, 0x2d9: 0x3751, 0x2da: 0xa000, + 0x2de: 0xa000, 0x2e3: 0xa000, + 0x2e7: 0xa000, + 0x2eb: 0xa000, 0x2ed: 0xa000, + 0x2f0: 0xa000, 0x2f3: 0xa000, 0x2f5: 0xa000, + 0x2f6: 0xa000, 0x2f7: 0xa000, 0x2f8: 0xa000, 0x2f9: 0x37d5, 0x2fa: 0xa000, + 0x2fe: 0xa000, + // Block 0xc, offset 0x300 + 0x301: 0x3733, 0x302: 0x37b7, + 0x310: 0x370f, 0x311: 0x3793, + 0x312: 0x3715, 0x313: 0x3799, 0x316: 0x3727, 0x317: 0x37ab, + 0x318: 0xa000, 0x319: 0xa000, 0x31a: 0x3829, 0x31b: 0x382f, 0x31c: 0x3739, 0x31d: 0x37bd, + 0x31e: 0x373f, 0x31f: 0x37c3, 0x322: 0x374b, 0x323: 0x37cf, + 0x324: 0x3757, 0x325: 0x37db, 0x326: 0x3763, 0x327: 0x37e7, 0x328: 0xa000, 0x329: 0xa000, + 0x32a: 0x3835, 0x32b: 0x383b, 0x32c: 0x378d, 0x32d: 0x3811, 0x32e: 0x3769, 0x32f: 0x37ed, + 0x330: 0x3775, 0x331: 0x37f9, 0x332: 0x377b, 0x333: 0x37ff, 0x334: 0x3781, 0x335: 0x3805, + 0x338: 0x3787, 0x339: 0x380b, + // Block 0xd, offset 0x340 + 0x351: 0x812d, + 0x352: 0x8132, 0x353: 0x8132, 0x354: 0x8132, 0x355: 0x8132, 0x356: 0x812d, 0x357: 0x8132, + 0x358: 0x8132, 0x359: 0x8132, 0x35a: 0x812e, 0x35b: 0x812d, 0x35c: 0x8132, 0x35d: 0x8132, + 0x35e: 0x8132, 0x35f: 0x8132, 0x360: 0x8132, 0x361: 0x8132, 0x362: 0x812d, 0x363: 0x812d, + 0x364: 0x812d, 0x365: 0x812d, 0x366: 0x812d, 0x367: 0x812d, 0x368: 0x8132, 0x369: 0x8132, + 0x36a: 0x812d, 0x36b: 0x8132, 0x36c: 0x8132, 0x36d: 0x812e, 0x36e: 0x8131, 0x36f: 0x8132, + 0x370: 0x8105, 0x371: 0x8106, 0x372: 0x8107, 0x373: 0x8108, 0x374: 0x8109, 0x375: 0x810a, + 0x376: 0x810b, 0x377: 0x810c, 0x378: 0x810d, 0x379: 0x810e, 0x37a: 0x810e, 0x37b: 0x810f, + 0x37c: 0x8110, 0x37d: 0x8111, 0x37f: 0x8112, + // Block 0xe, offset 0x380 + 0x388: 0xa000, 0x38a: 0xa000, 0x38b: 0x8116, + 0x38c: 0x8117, 0x38d: 0x8118, 0x38e: 0x8119, 0x38f: 0x811a, 0x390: 0x811b, 0x391: 0x811c, + 0x392: 0x811d, 0x393: 0x9932, 0x394: 0x9932, 0x395: 0x992d, 0x396: 0x812d, 0x397: 0x8132, + 0x398: 0x8132, 0x399: 0x8132, 0x39a: 0x8132, 0x39b: 0x8132, 0x39c: 0x812d, 0x39d: 0x8132, + 0x39e: 0x8132, 0x39f: 0x812d, + 0x3b0: 0x811e, + // Block 0xf, offset 0x3c0 + 0x3c5: 0xa000, + 0x3c6: 0x2d26, 0x3c7: 0xa000, 0x3c8: 0x2d2e, 0x3c9: 0xa000, 0x3ca: 0x2d36, 0x3cb: 0xa000, + 0x3cc: 0x2d3e, 0x3cd: 0xa000, 0x3ce: 0x2d46, 0x3d1: 0xa000, + 0x3d2: 0x2d4e, + 0x3f4: 0x8102, 0x3f5: 0x9900, + 0x3fa: 0xa000, 0x3fb: 0x2d56, + 0x3fc: 0xa000, 0x3fd: 0x2d5e, 0x3fe: 0xa000, 0x3ff: 0xa000, + // Block 0x10, offset 0x400 + 0x400: 0x2f97, 0x401: 0x32a3, 0x402: 0x2fa1, 0x403: 0x32ad, 0x404: 0x2fa6, 0x405: 0x32b2, + 0x406: 0x2fab, 0x407: 0x32b7, 0x408: 0x38cc, 0x409: 0x3a5b, 0x40a: 0x2fc4, 0x40b: 0x32d0, + 0x40c: 0x2fce, 0x40d: 0x32da, 0x40e: 0x2fdd, 0x40f: 0x32e9, 0x410: 0x2fd3, 0x411: 0x32df, + 0x412: 0x2fd8, 0x413: 0x32e4, 0x414: 0x38ef, 0x415: 0x3a7e, 0x416: 0x38f6, 0x417: 0x3a85, + 0x418: 0x3019, 0x419: 0x3325, 0x41a: 0x301e, 0x41b: 0x332a, 0x41c: 0x3904, 0x41d: 0x3a93, + 0x41e: 0x3023, 0x41f: 0x332f, 0x420: 0x3032, 0x421: 0x333e, 0x422: 0x3050, 0x423: 0x335c, + 0x424: 0x305f, 0x425: 0x336b, 0x426: 0x3055, 0x427: 0x3361, 0x428: 0x3064, 0x429: 0x3370, + 0x42a: 0x3069, 0x42b: 0x3375, 0x42c: 0x30af, 0x42d: 0x33bb, 0x42e: 0x390b, 0x42f: 0x3a9a, + 0x430: 0x30b9, 0x431: 0x33ca, 0x432: 0x30c3, 0x433: 0x33d4, 0x434: 0x30cd, 0x435: 0x33de, + 0x436: 0x46c4, 0x437: 0x4755, 0x438: 0x3912, 0x439: 0x3aa1, 0x43a: 0x30e6, 0x43b: 0x33f7, + 0x43c: 0x30e1, 0x43d: 0x33f2, 0x43e: 0x30eb, 0x43f: 0x33fc, + // Block 0x11, offset 0x440 + 0x440: 0x30f0, 0x441: 0x3401, 0x442: 0x30f5, 0x443: 0x3406, 0x444: 0x3109, 0x445: 0x341a, + 0x446: 0x3113, 0x447: 0x3424, 0x448: 0x3122, 0x449: 0x3433, 0x44a: 0x311d, 0x44b: 0x342e, + 0x44c: 0x3935, 0x44d: 0x3ac4, 0x44e: 0x3943, 0x44f: 0x3ad2, 0x450: 0x394a, 0x451: 0x3ad9, + 0x452: 0x3951, 0x453: 0x3ae0, 0x454: 0x314f, 0x455: 0x3460, 0x456: 0x3154, 0x457: 0x3465, + 0x458: 0x315e, 0x459: 0x346f, 0x45a: 0x46f1, 0x45b: 0x4782, 0x45c: 0x3997, 0x45d: 0x3b26, + 0x45e: 0x3177, 0x45f: 0x3488, 0x460: 0x3181, 0x461: 0x3492, 0x462: 0x4700, 0x463: 0x4791, + 0x464: 0x399e, 0x465: 0x3b2d, 0x466: 0x39a5, 0x467: 0x3b34, 0x468: 0x39ac, 0x469: 0x3b3b, + 0x46a: 0x3190, 0x46b: 0x34a1, 0x46c: 0x319a, 0x46d: 0x34b0, 0x46e: 0x31ae, 0x46f: 0x34c4, + 0x470: 0x31a9, 0x471: 0x34bf, 0x472: 0x31ea, 0x473: 0x3500, 0x474: 0x31f9, 0x475: 0x350f, + 0x476: 0x31f4, 0x477: 0x350a, 0x478: 0x39b3, 0x479: 0x3b42, 0x47a: 0x39ba, 0x47b: 0x3b49, + 0x47c: 0x31fe, 0x47d: 0x3514, 0x47e: 0x3203, 0x47f: 0x3519, + // Block 0x12, offset 0x480 + 0x480: 0x3208, 0x481: 0x351e, 0x482: 0x320d, 0x483: 0x3523, 0x484: 0x321c, 0x485: 0x3532, + 0x486: 0x3217, 0x487: 0x352d, 0x488: 0x3221, 0x489: 0x353c, 0x48a: 0x3226, 0x48b: 0x3541, + 0x48c: 0x322b, 0x48d: 0x3546, 0x48e: 0x3249, 0x48f: 0x3564, 0x490: 0x3262, 0x491: 0x3582, + 0x492: 0x3271, 0x493: 0x3591, 0x494: 0x3276, 0x495: 0x3596, 0x496: 0x337a, 0x497: 0x34a6, + 0x498: 0x3537, 0x499: 0x3573, 0x49b: 0x35d1, + 0x4a0: 0x46a1, 0x4a1: 0x4732, 0x4a2: 0x2f83, 0x4a3: 0x328f, + 0x4a4: 0x3878, 0x4a5: 0x3a07, 0x4a6: 0x3871, 0x4a7: 0x3a00, 0x4a8: 0x3886, 0x4a9: 0x3a15, + 0x4aa: 0x387f, 0x4ab: 0x3a0e, 0x4ac: 0x38be, 0x4ad: 0x3a4d, 0x4ae: 0x3894, 0x4af: 0x3a23, + 0x4b0: 0x388d, 0x4b1: 0x3a1c, 0x4b2: 0x38a2, 0x4b3: 0x3a31, 0x4b4: 0x389b, 0x4b5: 0x3a2a, + 0x4b6: 0x38c5, 0x4b7: 0x3a54, 0x4b8: 0x46b5, 0x4b9: 0x4746, 0x4ba: 0x3000, 0x4bb: 0x330c, + 0x4bc: 0x2fec, 0x4bd: 0x32f8, 0x4be: 0x38da, 0x4bf: 0x3a69, + // Block 0x13, offset 0x4c0 + 0x4c0: 0x38d3, 0x4c1: 0x3a62, 0x4c2: 0x38e8, 0x4c3: 0x3a77, 0x4c4: 0x38e1, 0x4c5: 0x3a70, + 0x4c6: 0x38fd, 0x4c7: 0x3a8c, 0x4c8: 0x3091, 0x4c9: 0x339d, 0x4ca: 0x30a5, 0x4cb: 0x33b1, + 0x4cc: 0x46e7, 0x4cd: 0x4778, 0x4ce: 0x3136, 0x4cf: 0x3447, 0x4d0: 0x3920, 0x4d1: 0x3aaf, + 0x4d2: 0x3919, 0x4d3: 0x3aa8, 0x4d4: 0x392e, 0x4d5: 0x3abd, 0x4d6: 0x3927, 0x4d7: 0x3ab6, + 0x4d8: 0x3989, 0x4d9: 0x3b18, 0x4da: 0x396d, 0x4db: 0x3afc, 0x4dc: 0x3966, 0x4dd: 0x3af5, + 0x4de: 0x397b, 0x4df: 0x3b0a, 0x4e0: 0x3974, 0x4e1: 0x3b03, 0x4e2: 0x3982, 0x4e3: 0x3b11, + 0x4e4: 0x31e5, 0x4e5: 0x34fb, 0x4e6: 0x31c7, 0x4e7: 0x34dd, 0x4e8: 0x39e4, 0x4e9: 0x3b73, + 0x4ea: 0x39dd, 0x4eb: 0x3b6c, 0x4ec: 0x39f2, 0x4ed: 0x3b81, 0x4ee: 0x39eb, 0x4ef: 0x3b7a, + 0x4f0: 0x39f9, 0x4f1: 0x3b88, 0x4f2: 0x3230, 0x4f3: 0x354b, 0x4f4: 0x3258, 0x4f5: 0x3578, + 0x4f6: 0x3253, 0x4f7: 0x356e, 0x4f8: 0x323f, 0x4f9: 0x355a, + // Block 0x14, offset 0x500 + 0x500: 0x4804, 0x501: 0x480a, 0x502: 0x491e, 0x503: 0x4936, 0x504: 0x4926, 0x505: 0x493e, + 0x506: 0x492e, 0x507: 0x4946, 0x508: 0x47aa, 0x509: 0x47b0, 0x50a: 0x488e, 0x50b: 0x48a6, + 0x50c: 0x4896, 0x50d: 0x48ae, 0x50e: 0x489e, 0x50f: 0x48b6, 0x510: 0x4816, 0x511: 0x481c, + 0x512: 0x3db8, 0x513: 0x3dc8, 0x514: 0x3dc0, 0x515: 0x3dd0, + 0x518: 0x47b6, 0x519: 0x47bc, 0x51a: 0x3ce8, 0x51b: 0x3cf8, 0x51c: 0x3cf0, 0x51d: 0x3d00, + 0x520: 0x482e, 0x521: 0x4834, 0x522: 0x494e, 0x523: 0x4966, + 0x524: 0x4956, 0x525: 0x496e, 0x526: 0x495e, 0x527: 0x4976, 0x528: 0x47c2, 0x529: 0x47c8, + 0x52a: 0x48be, 0x52b: 0x48d6, 0x52c: 0x48c6, 0x52d: 0x48de, 0x52e: 0x48ce, 0x52f: 0x48e6, + 0x530: 0x4846, 0x531: 0x484c, 0x532: 0x3e18, 0x533: 0x3e30, 0x534: 0x3e20, 0x535: 0x3e38, + 0x536: 0x3e28, 0x537: 0x3e40, 0x538: 0x47ce, 0x539: 0x47d4, 0x53a: 0x3d18, 0x53b: 0x3d30, + 0x53c: 0x3d20, 0x53d: 0x3d38, 0x53e: 0x3d28, 0x53f: 0x3d40, + // Block 0x15, offset 0x540 + 0x540: 0x4852, 0x541: 0x4858, 0x542: 0x3e48, 0x543: 0x3e58, 0x544: 0x3e50, 0x545: 0x3e60, + 0x548: 0x47da, 0x549: 0x47e0, 0x54a: 0x3d48, 0x54b: 0x3d58, + 0x54c: 0x3d50, 0x54d: 0x3d60, 0x550: 0x4864, 0x551: 0x486a, + 0x552: 0x3e80, 0x553: 0x3e98, 0x554: 0x3e88, 0x555: 0x3ea0, 0x556: 0x3e90, 0x557: 0x3ea8, + 0x559: 0x47e6, 0x55b: 0x3d68, 0x55d: 0x3d70, + 0x55f: 0x3d78, 0x560: 0x487c, 0x561: 0x4882, 0x562: 0x497e, 0x563: 0x4996, + 0x564: 0x4986, 0x565: 0x499e, 0x566: 0x498e, 0x567: 0x49a6, 0x568: 0x47ec, 0x569: 0x47f2, + 0x56a: 0x48ee, 0x56b: 0x4906, 0x56c: 0x48f6, 0x56d: 0x490e, 0x56e: 0x48fe, 0x56f: 0x4916, + 0x570: 0x47f8, 0x571: 0x431e, 0x572: 0x3691, 0x573: 0x4324, 0x574: 0x4822, 0x575: 0x432a, + 0x576: 0x36a3, 0x577: 0x4330, 0x578: 0x36c1, 0x579: 0x4336, 0x57a: 0x36d9, 0x57b: 0x433c, + 0x57c: 0x4870, 0x57d: 0x4342, + // Block 0x16, offset 0x580 + 0x580: 0x3da0, 0x581: 0x3da8, 0x582: 0x4184, 0x583: 0x41a2, 0x584: 0x418e, 0x585: 0x41ac, + 0x586: 0x4198, 0x587: 0x41b6, 0x588: 0x3cd8, 0x589: 0x3ce0, 0x58a: 0x40d0, 0x58b: 0x40ee, + 0x58c: 0x40da, 0x58d: 0x40f8, 0x58e: 0x40e4, 0x58f: 0x4102, 0x590: 0x3de8, 0x591: 0x3df0, + 0x592: 0x41c0, 0x593: 0x41de, 0x594: 0x41ca, 0x595: 0x41e8, 0x596: 0x41d4, 0x597: 0x41f2, + 0x598: 0x3d08, 0x599: 0x3d10, 0x59a: 0x410c, 0x59b: 0x412a, 0x59c: 0x4116, 0x59d: 0x4134, + 0x59e: 0x4120, 0x59f: 0x413e, 0x5a0: 0x3ec0, 0x5a1: 0x3ec8, 0x5a2: 0x41fc, 0x5a3: 0x421a, + 0x5a4: 0x4206, 0x5a5: 0x4224, 0x5a6: 0x4210, 0x5a7: 0x422e, 0x5a8: 0x3d80, 0x5a9: 0x3d88, + 0x5aa: 0x4148, 0x5ab: 0x4166, 0x5ac: 0x4152, 0x5ad: 0x4170, 0x5ae: 0x415c, 0x5af: 0x417a, + 0x5b0: 0x3685, 0x5b1: 0x367f, 0x5b2: 0x3d90, 0x5b3: 0x368b, 0x5b4: 0x3d98, + 0x5b6: 0x4810, 0x5b7: 0x3db0, 0x5b8: 0x35f5, 0x5b9: 0x35ef, 0x5ba: 0x35e3, 0x5bb: 0x42ee, + 0x5bc: 0x35fb, 0x5bd: 0x8100, 0x5be: 0x01d3, 0x5bf: 0xa100, + // Block 0x17, offset 0x5c0 + 0x5c0: 0x8100, 0x5c1: 0x35a7, 0x5c2: 0x3dd8, 0x5c3: 0x369d, 0x5c4: 0x3de0, + 0x5c6: 0x483a, 0x5c7: 0x3df8, 0x5c8: 0x3601, 0x5c9: 0x42f4, 0x5ca: 0x360d, 0x5cb: 0x42fa, + 0x5cc: 0x3619, 0x5cd: 0x3b8f, 0x5ce: 0x3b96, 0x5cf: 0x3b9d, 0x5d0: 0x36b5, 0x5d1: 0x36af, + 0x5d2: 0x3e00, 0x5d3: 0x44e4, 0x5d6: 0x36bb, 0x5d7: 0x3e10, + 0x5d8: 0x3631, 0x5d9: 0x362b, 0x5da: 0x361f, 0x5db: 0x4300, 0x5dd: 0x3ba4, + 0x5de: 0x3bab, 0x5df: 0x3bb2, 0x5e0: 0x36eb, 0x5e1: 0x36e5, 0x5e2: 0x3e68, 0x5e3: 0x44ec, + 0x5e4: 0x36cd, 0x5e5: 0x36d3, 0x5e6: 0x36f1, 0x5e7: 0x3e78, 0x5e8: 0x3661, 0x5e9: 0x365b, + 0x5ea: 0x364f, 0x5eb: 0x430c, 0x5ec: 0x3649, 0x5ed: 0x359b, 0x5ee: 0x42e8, 0x5ef: 0x0081, + 0x5f2: 0x3eb0, 0x5f3: 0x36f7, 0x5f4: 0x3eb8, + 0x5f6: 0x4888, 0x5f7: 0x3ed0, 0x5f8: 0x363d, 0x5f9: 0x4306, 0x5fa: 0x366d, 0x5fb: 0x4318, + 0x5fc: 0x3679, 0x5fd: 0x4256, 0x5fe: 0xa100, + // Block 0x18, offset 0x600 + 0x601: 0x3c06, 0x603: 0xa000, 0x604: 0x3c0d, 0x605: 0xa000, + 0x607: 0x3c14, 0x608: 0xa000, 0x609: 0x3c1b, + 0x60d: 0xa000, + 0x620: 0x2f65, 0x621: 0xa000, 0x622: 0x3c29, + 0x624: 0xa000, 0x625: 0xa000, + 0x62d: 0x3c22, 0x62e: 0x2f60, 0x62f: 0x2f6a, + 0x630: 0x3c30, 0x631: 0x3c37, 0x632: 0xa000, 0x633: 0xa000, 0x634: 0x3c3e, 0x635: 0x3c45, + 0x636: 0xa000, 0x637: 0xa000, 0x638: 0x3c4c, 0x639: 0x3c53, 0x63a: 0xa000, 0x63b: 0xa000, + 0x63c: 0xa000, 0x63d: 0xa000, + // Block 0x19, offset 0x640 + 0x640: 0x3c5a, 0x641: 0x3c61, 0x642: 0xa000, 0x643: 0xa000, 0x644: 0x3c76, 0x645: 0x3c7d, + 0x646: 0xa000, 0x647: 0xa000, 0x648: 0x3c84, 0x649: 0x3c8b, + 0x651: 0xa000, + 0x652: 0xa000, + 0x662: 0xa000, + 0x668: 0xa000, 0x669: 0xa000, + 0x66b: 0xa000, 0x66c: 0x3ca0, 0x66d: 0x3ca7, 0x66e: 0x3cae, 0x66f: 0x3cb5, + 0x672: 0xa000, 0x673: 0xa000, 0x674: 0xa000, 0x675: 0xa000, + // Block 0x1a, offset 0x680 + 0x686: 0xa000, 0x68b: 0xa000, + 0x68c: 0x3f08, 0x68d: 0xa000, 0x68e: 0x3f10, 0x68f: 0xa000, 0x690: 0x3f18, 0x691: 0xa000, + 0x692: 0x3f20, 0x693: 0xa000, 0x694: 0x3f28, 0x695: 0xa000, 0x696: 0x3f30, 0x697: 0xa000, + 0x698: 0x3f38, 0x699: 0xa000, 0x69a: 0x3f40, 0x69b: 0xa000, 0x69c: 0x3f48, 0x69d: 0xa000, + 0x69e: 0x3f50, 0x69f: 0xa000, 0x6a0: 0x3f58, 0x6a1: 0xa000, 0x6a2: 0x3f60, + 0x6a4: 0xa000, 0x6a5: 0x3f68, 0x6a6: 0xa000, 0x6a7: 0x3f70, 0x6a8: 0xa000, 0x6a9: 0x3f78, + 0x6af: 0xa000, + 0x6b0: 0x3f80, 0x6b1: 0x3f88, 0x6b2: 0xa000, 0x6b3: 0x3f90, 0x6b4: 0x3f98, 0x6b5: 0xa000, + 0x6b6: 0x3fa0, 0x6b7: 0x3fa8, 0x6b8: 0xa000, 0x6b9: 0x3fb0, 0x6ba: 0x3fb8, 0x6bb: 0xa000, + 0x6bc: 0x3fc0, 0x6bd: 0x3fc8, + // Block 0x1b, offset 0x6c0 + 0x6d4: 0x3f00, + 0x6d9: 0x9903, 0x6da: 0x9903, 0x6db: 0x8100, 0x6dc: 0x8100, 0x6dd: 0xa000, + 0x6de: 0x3fd0, + 0x6e6: 0xa000, + 0x6eb: 0xa000, 0x6ec: 0x3fe0, 0x6ed: 0xa000, 0x6ee: 0x3fe8, 0x6ef: 0xa000, + 0x6f0: 0x3ff0, 0x6f1: 0xa000, 0x6f2: 0x3ff8, 0x6f3: 0xa000, 0x6f4: 0x4000, 0x6f5: 0xa000, + 0x6f6: 0x4008, 0x6f7: 0xa000, 0x6f8: 0x4010, 0x6f9: 0xa000, 0x6fa: 0x4018, 0x6fb: 0xa000, + 0x6fc: 0x4020, 0x6fd: 0xa000, 0x6fe: 0x4028, 0x6ff: 0xa000, + // Block 0x1c, offset 0x700 + 0x700: 0x4030, 0x701: 0xa000, 0x702: 0x4038, 0x704: 0xa000, 0x705: 0x4040, + 0x706: 0xa000, 0x707: 0x4048, 0x708: 0xa000, 0x709: 0x4050, + 0x70f: 0xa000, 0x710: 0x4058, 0x711: 0x4060, + 0x712: 0xa000, 0x713: 0x4068, 0x714: 0x4070, 0x715: 0xa000, 0x716: 0x4078, 0x717: 0x4080, + 0x718: 0xa000, 0x719: 0x4088, 0x71a: 0x4090, 0x71b: 0xa000, 0x71c: 0x4098, 0x71d: 0x40a0, + 0x72f: 0xa000, + 0x730: 0xa000, 0x731: 0xa000, 0x732: 0xa000, 0x734: 0x3fd8, + 0x737: 0x40a8, 0x738: 0x40b0, 0x739: 0x40b8, 0x73a: 0x40c0, + 0x73d: 0xa000, 0x73e: 0x40c8, + // Block 0x1d, offset 0x740 + 0x740: 0x1377, 0x741: 0x0cfb, 0x742: 0x13d3, 0x743: 0x139f, 0x744: 0x0e57, 0x745: 0x06eb, + 0x746: 0x08df, 0x747: 0x162b, 0x748: 0x162b, 0x749: 0x0a0b, 0x74a: 0x145f, 0x74b: 0x0943, + 0x74c: 0x0a07, 0x74d: 0x0bef, 0x74e: 0x0fcf, 0x74f: 0x115f, 0x750: 0x1297, 0x751: 0x12d3, + 0x752: 0x1307, 0x753: 0x141b, 0x754: 0x0d73, 0x755: 0x0dff, 0x756: 0x0eab, 0x757: 0x0f43, + 0x758: 0x125f, 0x759: 0x1447, 0x75a: 0x1573, 0x75b: 0x070f, 0x75c: 0x08b3, 0x75d: 0x0d87, + 0x75e: 0x0ecf, 0x75f: 0x1293, 0x760: 0x15c3, 0x761: 0x0ab3, 0x762: 0x0e77, 0x763: 0x1283, + 0x764: 0x1317, 0x765: 0x0c23, 0x766: 0x11bb, 0x767: 0x12df, 0x768: 0x0b1f, 0x769: 0x0d0f, + 0x76a: 0x0e17, 0x76b: 0x0f1b, 0x76c: 0x1427, 0x76d: 0x074f, 0x76e: 0x07e7, 0x76f: 0x0853, + 0x770: 0x0c8b, 0x771: 0x0d7f, 0x772: 0x0ecb, 0x773: 0x0fef, 0x774: 0x1177, 0x775: 0x128b, + 0x776: 0x12a3, 0x777: 0x13c7, 0x778: 0x14ef, 0x779: 0x15a3, 0x77a: 0x15bf, 0x77b: 0x102b, + 0x77c: 0x106b, 0x77d: 0x1123, 0x77e: 0x1243, 0x77f: 0x147b, + // Block 0x1e, offset 0x780 + 0x780: 0x15cb, 0x781: 0x134b, 0x782: 0x09c7, 0x783: 0x0b3b, 0x784: 0x10db, 0x785: 0x119b, + 0x786: 0x0eff, 0x787: 0x1033, 0x788: 0x1397, 0x789: 0x14e7, 0x78a: 0x09c3, 0x78b: 0x0a8f, + 0x78c: 0x0d77, 0x78d: 0x0e2b, 0x78e: 0x0e5f, 0x78f: 0x1113, 0x790: 0x113b, 0x791: 0x14a7, + 0x792: 0x084f, 0x793: 0x11a7, 0x794: 0x07f3, 0x795: 0x07ef, 0x796: 0x1097, 0x797: 0x1127, + 0x798: 0x125b, 0x799: 0x14af, 0x79a: 0x1367, 0x79b: 0x0c27, 0x79c: 0x0d73, 0x79d: 0x1357, + 0x79e: 0x06f7, 0x79f: 0x0a63, 0x7a0: 0x0b93, 0x7a1: 0x0f2f, 0x7a2: 0x0faf, 0x7a3: 0x0873, + 0x7a4: 0x103b, 0x7a5: 0x075f, 0x7a6: 0x0b77, 0x7a7: 0x06d7, 0x7a8: 0x0deb, 0x7a9: 0x0ca3, + 0x7aa: 0x110f, 0x7ab: 0x08c7, 0x7ac: 0x09b3, 0x7ad: 0x0ffb, 0x7ae: 0x1263, 0x7af: 0x133b, + 0x7b0: 0x0db7, 0x7b1: 0x13f7, 0x7b2: 0x0de3, 0x7b3: 0x0c37, 0x7b4: 0x121b, 0x7b5: 0x0c57, + 0x7b6: 0x0fab, 0x7b7: 0x072b, 0x7b8: 0x07a7, 0x7b9: 0x07eb, 0x7ba: 0x0d53, 0x7bb: 0x10fb, + 0x7bc: 0x11f3, 0x7bd: 0x1347, 0x7be: 0x145b, 0x7bf: 0x085b, + // Block 0x1f, offset 0x7c0 + 0x7c0: 0x090f, 0x7c1: 0x0a17, 0x7c2: 0x0b2f, 0x7c3: 0x0cbf, 0x7c4: 0x0e7b, 0x7c5: 0x103f, + 0x7c6: 0x1497, 0x7c7: 0x157b, 0x7c8: 0x15cf, 0x7c9: 0x15e7, 0x7ca: 0x0837, 0x7cb: 0x0cf3, + 0x7cc: 0x0da3, 0x7cd: 0x13eb, 0x7ce: 0x0afb, 0x7cf: 0x0bd7, 0x7d0: 0x0bf3, 0x7d1: 0x0c83, + 0x7d2: 0x0e6b, 0x7d3: 0x0eb7, 0x7d4: 0x0f67, 0x7d5: 0x108b, 0x7d6: 0x112f, 0x7d7: 0x1193, + 0x7d8: 0x13db, 0x7d9: 0x126b, 0x7da: 0x1403, 0x7db: 0x147f, 0x7dc: 0x080f, 0x7dd: 0x083b, + 0x7de: 0x0923, 0x7df: 0x0ea7, 0x7e0: 0x12f3, 0x7e1: 0x133b, 0x7e2: 0x0b1b, 0x7e3: 0x0b8b, + 0x7e4: 0x0c4f, 0x7e5: 0x0daf, 0x7e6: 0x10d7, 0x7e7: 0x0f23, 0x7e8: 0x073b, 0x7e9: 0x097f, + 0x7ea: 0x0a63, 0x7eb: 0x0ac7, 0x7ec: 0x0b97, 0x7ed: 0x0f3f, 0x7ee: 0x0f5b, 0x7ef: 0x116b, + 0x7f0: 0x118b, 0x7f1: 0x1463, 0x7f2: 0x14e3, 0x7f3: 0x14f3, 0x7f4: 0x152f, 0x7f5: 0x0753, + 0x7f6: 0x107f, 0x7f7: 0x144f, 0x7f8: 0x14cb, 0x7f9: 0x0baf, 0x7fa: 0x0717, 0x7fb: 0x0777, + 0x7fc: 0x0a67, 0x7fd: 0x0a87, 0x7fe: 0x0caf, 0x7ff: 0x0d73, + // Block 0x20, offset 0x800 + 0x800: 0x0ec3, 0x801: 0x0fcb, 0x802: 0x1277, 0x803: 0x1417, 0x804: 0x1623, 0x805: 0x0ce3, + 0x806: 0x14a3, 0x807: 0x0833, 0x808: 0x0d2f, 0x809: 0x0d3b, 0x80a: 0x0e0f, 0x80b: 0x0e47, + 0x80c: 0x0f4b, 0x80d: 0x0fa7, 0x80e: 0x1027, 0x80f: 0x110b, 0x810: 0x153b, 0x811: 0x07af, + 0x812: 0x0c03, 0x813: 0x14b3, 0x814: 0x0767, 0x815: 0x0aab, 0x816: 0x0e2f, 0x817: 0x13df, + 0x818: 0x0b67, 0x819: 0x0bb7, 0x81a: 0x0d43, 0x81b: 0x0f2f, 0x81c: 0x14bb, 0x81d: 0x0817, + 0x81e: 0x08ff, 0x81f: 0x0a97, 0x820: 0x0cd3, 0x821: 0x0d1f, 0x822: 0x0d5f, 0x823: 0x0df3, + 0x824: 0x0f47, 0x825: 0x0fbb, 0x826: 0x1157, 0x827: 0x12f7, 0x828: 0x1303, 0x829: 0x1457, + 0x82a: 0x14d7, 0x82b: 0x0883, 0x82c: 0x0e4b, 0x82d: 0x0903, 0x82e: 0x0ec7, 0x82f: 0x0f6b, + 0x830: 0x1287, 0x831: 0x14bf, 0x832: 0x15ab, 0x833: 0x15d3, 0x834: 0x0d37, 0x835: 0x0e27, + 0x836: 0x11c3, 0x837: 0x10b7, 0x838: 0x10c3, 0x839: 0x10e7, 0x83a: 0x0f17, 0x83b: 0x0e9f, + 0x83c: 0x1363, 0x83d: 0x0733, 0x83e: 0x122b, 0x83f: 0x081b, + // Block 0x21, offset 0x840 + 0x840: 0x080b, 0x841: 0x0b0b, 0x842: 0x0c2b, 0x843: 0x10f3, 0x844: 0x0a53, 0x845: 0x0e03, + 0x846: 0x0cef, 0x847: 0x13e7, 0x848: 0x12e7, 0x849: 0x14ab, 0x84a: 0x1323, 0x84b: 0x0b27, + 0x84c: 0x0787, 0x84d: 0x095b, 0x850: 0x09af, + 0x852: 0x0cdf, 0x855: 0x07f7, 0x856: 0x0f1f, 0x857: 0x0fe3, + 0x858: 0x1047, 0x859: 0x1063, 0x85a: 0x1067, 0x85b: 0x107b, 0x85c: 0x14fb, 0x85d: 0x10eb, + 0x85e: 0x116f, 0x860: 0x128f, 0x862: 0x1353, + 0x865: 0x1407, 0x866: 0x1433, + 0x86a: 0x154f, 0x86b: 0x1553, 0x86c: 0x1557, 0x86d: 0x15bb, 0x86e: 0x142b, 0x86f: 0x14c7, + 0x870: 0x0757, 0x871: 0x077b, 0x872: 0x078f, 0x873: 0x084b, 0x874: 0x0857, 0x875: 0x0897, + 0x876: 0x094b, 0x877: 0x0967, 0x878: 0x096f, 0x879: 0x09ab, 0x87a: 0x09b7, 0x87b: 0x0a93, + 0x87c: 0x0a9b, 0x87d: 0x0ba3, 0x87e: 0x0bcb, 0x87f: 0x0bd3, + // Block 0x22, offset 0x880 + 0x880: 0x0beb, 0x881: 0x0c97, 0x882: 0x0cc7, 0x883: 0x0ce7, 0x884: 0x0d57, 0x885: 0x0e1b, + 0x886: 0x0e37, 0x887: 0x0e67, 0x888: 0x0ebb, 0x889: 0x0edb, 0x88a: 0x0f4f, 0x88b: 0x102f, + 0x88c: 0x104b, 0x88d: 0x1053, 0x88e: 0x104f, 0x88f: 0x1057, 0x890: 0x105b, 0x891: 0x105f, + 0x892: 0x1073, 0x893: 0x1077, 0x894: 0x109b, 0x895: 0x10af, 0x896: 0x10cb, 0x897: 0x112f, + 0x898: 0x1137, 0x899: 0x113f, 0x89a: 0x1153, 0x89b: 0x117b, 0x89c: 0x11cb, 0x89d: 0x11ff, + 0x89e: 0x11ff, 0x89f: 0x1267, 0x8a0: 0x130f, 0x8a1: 0x1327, 0x8a2: 0x135b, 0x8a3: 0x135f, + 0x8a4: 0x13a3, 0x8a5: 0x13a7, 0x8a6: 0x13ff, 0x8a7: 0x1407, 0x8a8: 0x14db, 0x8a9: 0x151f, + 0x8aa: 0x1537, 0x8ab: 0x0b9b, 0x8ac: 0x171e, 0x8ad: 0x11e3, + 0x8b0: 0x06df, 0x8b1: 0x07e3, 0x8b2: 0x07a3, 0x8b3: 0x074b, 0x8b4: 0x078b, 0x8b5: 0x07b7, + 0x8b6: 0x0847, 0x8b7: 0x0863, 0x8b8: 0x094b, 0x8b9: 0x0937, 0x8ba: 0x0947, 0x8bb: 0x0963, + 0x8bc: 0x09af, 0x8bd: 0x09bf, 0x8be: 0x0a03, 0x8bf: 0x0a0f, + // Block 0x23, offset 0x8c0 + 0x8c0: 0x0a2b, 0x8c1: 0x0a3b, 0x8c2: 0x0b23, 0x8c3: 0x0b2b, 0x8c4: 0x0b5b, 0x8c5: 0x0b7b, + 0x8c6: 0x0bab, 0x8c7: 0x0bc3, 0x8c8: 0x0bb3, 0x8c9: 0x0bd3, 0x8ca: 0x0bc7, 0x8cb: 0x0beb, + 0x8cc: 0x0c07, 0x8cd: 0x0c5f, 0x8ce: 0x0c6b, 0x8cf: 0x0c73, 0x8d0: 0x0c9b, 0x8d1: 0x0cdf, + 0x8d2: 0x0d0f, 0x8d3: 0x0d13, 0x8d4: 0x0d27, 0x8d5: 0x0da7, 0x8d6: 0x0db7, 0x8d7: 0x0e0f, + 0x8d8: 0x0e5b, 0x8d9: 0x0e53, 0x8da: 0x0e67, 0x8db: 0x0e83, 0x8dc: 0x0ebb, 0x8dd: 0x1013, + 0x8de: 0x0edf, 0x8df: 0x0f13, 0x8e0: 0x0f1f, 0x8e1: 0x0f5f, 0x8e2: 0x0f7b, 0x8e3: 0x0f9f, + 0x8e4: 0x0fc3, 0x8e5: 0x0fc7, 0x8e6: 0x0fe3, 0x8e7: 0x0fe7, 0x8e8: 0x0ff7, 0x8e9: 0x100b, + 0x8ea: 0x1007, 0x8eb: 0x1037, 0x8ec: 0x10b3, 0x8ed: 0x10cb, 0x8ee: 0x10e3, 0x8ef: 0x111b, + 0x8f0: 0x112f, 0x8f1: 0x114b, 0x8f2: 0x117b, 0x8f3: 0x122f, 0x8f4: 0x1257, 0x8f5: 0x12cb, + 0x8f6: 0x1313, 0x8f7: 0x131f, 0x8f8: 0x1327, 0x8f9: 0x133f, 0x8fa: 0x1353, 0x8fb: 0x1343, + 0x8fc: 0x135b, 0x8fd: 0x1357, 0x8fe: 0x134f, 0x8ff: 0x135f, + // Block 0x24, offset 0x900 + 0x900: 0x136b, 0x901: 0x13a7, 0x902: 0x13e3, 0x903: 0x1413, 0x904: 0x144b, 0x905: 0x146b, + 0x906: 0x14b7, 0x907: 0x14db, 0x908: 0x14fb, 0x909: 0x150f, 0x90a: 0x151f, 0x90b: 0x152b, + 0x90c: 0x1537, 0x90d: 0x158b, 0x90e: 0x162b, 0x90f: 0x16b5, 0x910: 0x16b0, 0x911: 0x16e2, + 0x912: 0x0607, 0x913: 0x062f, 0x914: 0x0633, 0x915: 0x1764, 0x916: 0x1791, 0x917: 0x1809, + 0x918: 0x1617, 0x919: 0x1627, + // Block 0x25, offset 0x940 + 0x940: 0x06fb, 0x941: 0x06f3, 0x942: 0x0703, 0x943: 0x1647, 0x944: 0x0747, 0x945: 0x0757, + 0x946: 0x075b, 0x947: 0x0763, 0x948: 0x076b, 0x949: 0x076f, 0x94a: 0x077b, 0x94b: 0x0773, + 0x94c: 0x05b3, 0x94d: 0x165b, 0x94e: 0x078f, 0x94f: 0x0793, 0x950: 0x0797, 0x951: 0x07b3, + 0x952: 0x164c, 0x953: 0x05b7, 0x954: 0x079f, 0x955: 0x07bf, 0x956: 0x1656, 0x957: 0x07cf, + 0x958: 0x07d7, 0x959: 0x0737, 0x95a: 0x07df, 0x95b: 0x07e3, 0x95c: 0x1831, 0x95d: 0x07ff, + 0x95e: 0x0807, 0x95f: 0x05bf, 0x960: 0x081f, 0x961: 0x0823, 0x962: 0x082b, 0x963: 0x082f, + 0x964: 0x05c3, 0x965: 0x0847, 0x966: 0x084b, 0x967: 0x0857, 0x968: 0x0863, 0x969: 0x0867, + 0x96a: 0x086b, 0x96b: 0x0873, 0x96c: 0x0893, 0x96d: 0x0897, 0x96e: 0x089f, 0x96f: 0x08af, + 0x970: 0x08b7, 0x971: 0x08bb, 0x972: 0x08bb, 0x973: 0x08bb, 0x974: 0x166a, 0x975: 0x0e93, + 0x976: 0x08cf, 0x977: 0x08d7, 0x978: 0x166f, 0x979: 0x08e3, 0x97a: 0x08eb, 0x97b: 0x08f3, + 0x97c: 0x091b, 0x97d: 0x0907, 0x97e: 0x0913, 0x97f: 0x0917, + // Block 0x26, offset 0x980 + 0x980: 0x091f, 0x981: 0x0927, 0x982: 0x092b, 0x983: 0x0933, 0x984: 0x093b, 0x985: 0x093f, + 0x986: 0x093f, 0x987: 0x0947, 0x988: 0x094f, 0x989: 0x0953, 0x98a: 0x095f, 0x98b: 0x0983, + 0x98c: 0x0967, 0x98d: 0x0987, 0x98e: 0x096b, 0x98f: 0x0973, 0x990: 0x080b, 0x991: 0x09cf, + 0x992: 0x0997, 0x993: 0x099b, 0x994: 0x099f, 0x995: 0x0993, 0x996: 0x09a7, 0x997: 0x09a3, + 0x998: 0x09bb, 0x999: 0x1674, 0x99a: 0x09d7, 0x99b: 0x09db, 0x99c: 0x09e3, 0x99d: 0x09ef, + 0x99e: 0x09f7, 0x99f: 0x0a13, 0x9a0: 0x1679, 0x9a1: 0x167e, 0x9a2: 0x0a1f, 0x9a3: 0x0a23, + 0x9a4: 0x0a27, 0x9a5: 0x0a1b, 0x9a6: 0x0a2f, 0x9a7: 0x05c7, 0x9a8: 0x05cb, 0x9a9: 0x0a37, + 0x9aa: 0x0a3f, 0x9ab: 0x0a3f, 0x9ac: 0x1683, 0x9ad: 0x0a5b, 0x9ae: 0x0a5f, 0x9af: 0x0a63, + 0x9b0: 0x0a6b, 0x9b1: 0x1688, 0x9b2: 0x0a73, 0x9b3: 0x0a77, 0x9b4: 0x0b4f, 0x9b5: 0x0a7f, + 0x9b6: 0x05cf, 0x9b7: 0x0a8b, 0x9b8: 0x0a9b, 0x9b9: 0x0aa7, 0x9ba: 0x0aa3, 0x9bb: 0x1692, + 0x9bc: 0x0aaf, 0x9bd: 0x1697, 0x9be: 0x0abb, 0x9bf: 0x0ab7, + // Block 0x27, offset 0x9c0 + 0x9c0: 0x0abf, 0x9c1: 0x0acf, 0x9c2: 0x0ad3, 0x9c3: 0x05d3, 0x9c4: 0x0ae3, 0x9c5: 0x0aeb, + 0x9c6: 0x0aef, 0x9c7: 0x0af3, 0x9c8: 0x05d7, 0x9c9: 0x169c, 0x9ca: 0x05db, 0x9cb: 0x0b0f, + 0x9cc: 0x0b13, 0x9cd: 0x0b17, 0x9ce: 0x0b1f, 0x9cf: 0x1863, 0x9d0: 0x0b37, 0x9d1: 0x16a6, + 0x9d2: 0x16a6, 0x9d3: 0x11d7, 0x9d4: 0x0b47, 0x9d5: 0x0b47, 0x9d6: 0x05df, 0x9d7: 0x16c9, + 0x9d8: 0x179b, 0x9d9: 0x0b57, 0x9da: 0x0b5f, 0x9db: 0x05e3, 0x9dc: 0x0b73, 0x9dd: 0x0b83, + 0x9de: 0x0b87, 0x9df: 0x0b8f, 0x9e0: 0x0b9f, 0x9e1: 0x05eb, 0x9e2: 0x05e7, 0x9e3: 0x0ba3, + 0x9e4: 0x16ab, 0x9e5: 0x0ba7, 0x9e6: 0x0bbb, 0x9e7: 0x0bbf, 0x9e8: 0x0bc3, 0x9e9: 0x0bbf, + 0x9ea: 0x0bcf, 0x9eb: 0x0bd3, 0x9ec: 0x0be3, 0x9ed: 0x0bdb, 0x9ee: 0x0bdf, 0x9ef: 0x0be7, + 0x9f0: 0x0beb, 0x9f1: 0x0bef, 0x9f2: 0x0bfb, 0x9f3: 0x0bff, 0x9f4: 0x0c17, 0x9f5: 0x0c1f, + 0x9f6: 0x0c2f, 0x9f7: 0x0c43, 0x9f8: 0x16ba, 0x9f9: 0x0c3f, 0x9fa: 0x0c33, 0x9fb: 0x0c4b, + 0x9fc: 0x0c53, 0x9fd: 0x0c67, 0x9fe: 0x16bf, 0x9ff: 0x0c6f, + // Block 0x28, offset 0xa00 + 0xa00: 0x0c63, 0xa01: 0x0c5b, 0xa02: 0x05ef, 0xa03: 0x0c77, 0xa04: 0x0c7f, 0xa05: 0x0c87, + 0xa06: 0x0c7b, 0xa07: 0x05f3, 0xa08: 0x0c97, 0xa09: 0x0c9f, 0xa0a: 0x16c4, 0xa0b: 0x0ccb, + 0xa0c: 0x0cff, 0xa0d: 0x0cdb, 0xa0e: 0x05ff, 0xa0f: 0x0ce7, 0xa10: 0x05fb, 0xa11: 0x05f7, + 0xa12: 0x07c3, 0xa13: 0x07c7, 0xa14: 0x0d03, 0xa15: 0x0ceb, 0xa16: 0x11ab, 0xa17: 0x0663, + 0xa18: 0x0d0f, 0xa19: 0x0d13, 0xa1a: 0x0d17, 0xa1b: 0x0d2b, 0xa1c: 0x0d23, 0xa1d: 0x16dd, + 0xa1e: 0x0603, 0xa1f: 0x0d3f, 0xa20: 0x0d33, 0xa21: 0x0d4f, 0xa22: 0x0d57, 0xa23: 0x16e7, + 0xa24: 0x0d5b, 0xa25: 0x0d47, 0xa26: 0x0d63, 0xa27: 0x0607, 0xa28: 0x0d67, 0xa29: 0x0d6b, + 0xa2a: 0x0d6f, 0xa2b: 0x0d7b, 0xa2c: 0x16ec, 0xa2d: 0x0d83, 0xa2e: 0x060b, 0xa2f: 0x0d8f, + 0xa30: 0x16f1, 0xa31: 0x0d93, 0xa32: 0x060f, 0xa33: 0x0d9f, 0xa34: 0x0dab, 0xa35: 0x0db7, + 0xa36: 0x0dbb, 0xa37: 0x16f6, 0xa38: 0x168d, 0xa39: 0x16fb, 0xa3a: 0x0ddb, 0xa3b: 0x1700, + 0xa3c: 0x0de7, 0xa3d: 0x0def, 0xa3e: 0x0ddf, 0xa3f: 0x0dfb, + // Block 0x29, offset 0xa40 + 0xa40: 0x0e0b, 0xa41: 0x0e1b, 0xa42: 0x0e0f, 0xa43: 0x0e13, 0xa44: 0x0e1f, 0xa45: 0x0e23, + 0xa46: 0x1705, 0xa47: 0x0e07, 0xa48: 0x0e3b, 0xa49: 0x0e3f, 0xa4a: 0x0613, 0xa4b: 0x0e53, + 0xa4c: 0x0e4f, 0xa4d: 0x170a, 0xa4e: 0x0e33, 0xa4f: 0x0e6f, 0xa50: 0x170f, 0xa51: 0x1714, + 0xa52: 0x0e73, 0xa53: 0x0e87, 0xa54: 0x0e83, 0xa55: 0x0e7f, 0xa56: 0x0617, 0xa57: 0x0e8b, + 0xa58: 0x0e9b, 0xa59: 0x0e97, 0xa5a: 0x0ea3, 0xa5b: 0x1651, 0xa5c: 0x0eb3, 0xa5d: 0x1719, + 0xa5e: 0x0ebf, 0xa5f: 0x1723, 0xa60: 0x0ed3, 0xa61: 0x0edf, 0xa62: 0x0ef3, 0xa63: 0x1728, + 0xa64: 0x0f07, 0xa65: 0x0f0b, 0xa66: 0x172d, 0xa67: 0x1732, 0xa68: 0x0f27, 0xa69: 0x0f37, + 0xa6a: 0x061b, 0xa6b: 0x0f3b, 0xa6c: 0x061f, 0xa6d: 0x061f, 0xa6e: 0x0f53, 0xa6f: 0x0f57, + 0xa70: 0x0f5f, 0xa71: 0x0f63, 0xa72: 0x0f6f, 0xa73: 0x0623, 0xa74: 0x0f87, 0xa75: 0x1737, + 0xa76: 0x0fa3, 0xa77: 0x173c, 0xa78: 0x0faf, 0xa79: 0x16a1, 0xa7a: 0x0fbf, 0xa7b: 0x1741, + 0xa7c: 0x1746, 0xa7d: 0x174b, 0xa7e: 0x0627, 0xa7f: 0x062b, + // Block 0x2a, offset 0xa80 + 0xa80: 0x0ff7, 0xa81: 0x1755, 0xa82: 0x1750, 0xa83: 0x175a, 0xa84: 0x175f, 0xa85: 0x0fff, + 0xa86: 0x1003, 0xa87: 0x1003, 0xa88: 0x100b, 0xa89: 0x0633, 0xa8a: 0x100f, 0xa8b: 0x0637, + 0xa8c: 0x063b, 0xa8d: 0x1769, 0xa8e: 0x1023, 0xa8f: 0x102b, 0xa90: 0x1037, 0xa91: 0x063f, + 0xa92: 0x176e, 0xa93: 0x105b, 0xa94: 0x1773, 0xa95: 0x1778, 0xa96: 0x107b, 0xa97: 0x1093, + 0xa98: 0x0643, 0xa99: 0x109b, 0xa9a: 0x109f, 0xa9b: 0x10a3, 0xa9c: 0x177d, 0xa9d: 0x1782, + 0xa9e: 0x1782, 0xa9f: 0x10bb, 0xaa0: 0x0647, 0xaa1: 0x1787, 0xaa2: 0x10cf, 0xaa3: 0x10d3, + 0xaa4: 0x064b, 0xaa5: 0x178c, 0xaa6: 0x10ef, 0xaa7: 0x064f, 0xaa8: 0x10ff, 0xaa9: 0x10f7, + 0xaaa: 0x1107, 0xaab: 0x1796, 0xaac: 0x111f, 0xaad: 0x0653, 0xaae: 0x112b, 0xaaf: 0x1133, + 0xab0: 0x1143, 0xab1: 0x0657, 0xab2: 0x17a0, 0xab3: 0x17a5, 0xab4: 0x065b, 0xab5: 0x17aa, + 0xab6: 0x115b, 0xab7: 0x17af, 0xab8: 0x1167, 0xab9: 0x1173, 0xaba: 0x117b, 0xabb: 0x17b4, + 0xabc: 0x17b9, 0xabd: 0x118f, 0xabe: 0x17be, 0xabf: 0x1197, + // Block 0x2b, offset 0xac0 + 0xac0: 0x16ce, 0xac1: 0x065f, 0xac2: 0x11af, 0xac3: 0x11b3, 0xac4: 0x0667, 0xac5: 0x11b7, + 0xac6: 0x0a33, 0xac7: 0x17c3, 0xac8: 0x17c8, 0xac9: 0x16d3, 0xaca: 0x16d8, 0xacb: 0x11d7, + 0xacc: 0x11db, 0xacd: 0x13f3, 0xace: 0x066b, 0xacf: 0x1207, 0xad0: 0x1203, 0xad1: 0x120b, + 0xad2: 0x083f, 0xad3: 0x120f, 0xad4: 0x1213, 0xad5: 0x1217, 0xad6: 0x121f, 0xad7: 0x17cd, + 0xad8: 0x121b, 0xad9: 0x1223, 0xada: 0x1237, 0xadb: 0x123b, 0xadc: 0x1227, 0xadd: 0x123f, + 0xade: 0x1253, 0xadf: 0x1267, 0xae0: 0x1233, 0xae1: 0x1247, 0xae2: 0x124b, 0xae3: 0x124f, + 0xae4: 0x17d2, 0xae5: 0x17dc, 0xae6: 0x17d7, 0xae7: 0x066f, 0xae8: 0x126f, 0xae9: 0x1273, + 0xaea: 0x127b, 0xaeb: 0x17f0, 0xaec: 0x127f, 0xaed: 0x17e1, 0xaee: 0x0673, 0xaef: 0x0677, + 0xaf0: 0x17e6, 0xaf1: 0x17eb, 0xaf2: 0x067b, 0xaf3: 0x129f, 0xaf4: 0x12a3, 0xaf5: 0x12a7, + 0xaf6: 0x12ab, 0xaf7: 0x12b7, 0xaf8: 0x12b3, 0xaf9: 0x12bf, 0xafa: 0x12bb, 0xafb: 0x12cb, + 0xafc: 0x12c3, 0xafd: 0x12c7, 0xafe: 0x12cf, 0xaff: 0x067f, + // Block 0x2c, offset 0xb00 + 0xb00: 0x12d7, 0xb01: 0x12db, 0xb02: 0x0683, 0xb03: 0x12eb, 0xb04: 0x12ef, 0xb05: 0x17f5, + 0xb06: 0x12fb, 0xb07: 0x12ff, 0xb08: 0x0687, 0xb09: 0x130b, 0xb0a: 0x05bb, 0xb0b: 0x17fa, + 0xb0c: 0x17ff, 0xb0d: 0x068b, 0xb0e: 0x068f, 0xb0f: 0x1337, 0xb10: 0x134f, 0xb11: 0x136b, + 0xb12: 0x137b, 0xb13: 0x1804, 0xb14: 0x138f, 0xb15: 0x1393, 0xb16: 0x13ab, 0xb17: 0x13b7, + 0xb18: 0x180e, 0xb19: 0x1660, 0xb1a: 0x13c3, 0xb1b: 0x13bf, 0xb1c: 0x13cb, 0xb1d: 0x1665, + 0xb1e: 0x13d7, 0xb1f: 0x13e3, 0xb20: 0x1813, 0xb21: 0x1818, 0xb22: 0x1423, 0xb23: 0x142f, + 0xb24: 0x1437, 0xb25: 0x181d, 0xb26: 0x143b, 0xb27: 0x1467, 0xb28: 0x1473, 0xb29: 0x1477, + 0xb2a: 0x146f, 0xb2b: 0x1483, 0xb2c: 0x1487, 0xb2d: 0x1822, 0xb2e: 0x1493, 0xb2f: 0x0693, + 0xb30: 0x149b, 0xb31: 0x1827, 0xb32: 0x0697, 0xb33: 0x14d3, 0xb34: 0x0ac3, 0xb35: 0x14eb, + 0xb36: 0x182c, 0xb37: 0x1836, 0xb38: 0x069b, 0xb39: 0x069f, 0xb3a: 0x1513, 0xb3b: 0x183b, + 0xb3c: 0x06a3, 0xb3d: 0x1840, 0xb3e: 0x152b, 0xb3f: 0x152b, + // Block 0x2d, offset 0xb40 + 0xb40: 0x1533, 0xb41: 0x1845, 0xb42: 0x154b, 0xb43: 0x06a7, 0xb44: 0x155b, 0xb45: 0x1567, + 0xb46: 0x156f, 0xb47: 0x1577, 0xb48: 0x06ab, 0xb49: 0x184a, 0xb4a: 0x158b, 0xb4b: 0x15a7, + 0xb4c: 0x15b3, 0xb4d: 0x06af, 0xb4e: 0x06b3, 0xb4f: 0x15b7, 0xb50: 0x184f, 0xb51: 0x06b7, + 0xb52: 0x1854, 0xb53: 0x1859, 0xb54: 0x185e, 0xb55: 0x15db, 0xb56: 0x06bb, 0xb57: 0x15ef, + 0xb58: 0x15f7, 0xb59: 0x15fb, 0xb5a: 0x1603, 0xb5b: 0x160b, 0xb5c: 0x1613, 0xb5d: 0x1868, +} + +// nfcIndex: 22 blocks, 1408 entries, 1408 bytes +// Block 0 is the zero block. +var nfcIndex = [1408]uint8{ + // Block 0x0, offset 0x0 + // Block 0x1, offset 0x40 + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0xc2: 0x2c, 0xc3: 0x01, 0xc4: 0x02, 0xc5: 0x03, 0xc6: 0x2d, 0xc7: 0x04, + 0xc8: 0x05, 0xca: 0x2e, 0xcb: 0x2f, 0xcc: 0x06, 0xcd: 0x07, 0xce: 0x08, 0xcf: 0x30, + 0xd0: 0x09, 0xd1: 0x31, 0xd2: 0x32, 0xd3: 0x0a, 0xd6: 0x0b, 0xd7: 0x33, + 0xd8: 0x34, 0xd9: 0x0c, 0xdb: 0x35, 0xdc: 0x36, 0xdd: 0x37, 0xdf: 0x38, + 0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05, + 0xea: 0x06, 0xeb: 0x07, 0xec: 0x08, 0xed: 0x09, 0xef: 0x0a, + 0xf0: 0x13, + // Block 0x4, offset 0x100 + 0x120: 0x39, 0x121: 0x3a, 0x123: 0x3b, 0x124: 0x3c, 0x125: 0x3d, 0x126: 0x3e, 0x127: 0x3f, + 0x128: 0x40, 0x129: 0x41, 0x12a: 0x42, 0x12b: 0x43, 0x12c: 0x3e, 0x12d: 0x44, 0x12e: 0x45, 0x12f: 0x46, + 0x131: 0x47, 0x132: 0x48, 0x133: 0x49, 0x134: 0x4a, 0x135: 0x4b, 0x137: 0x4c, + 0x138: 0x4d, 0x139: 0x4e, 0x13a: 0x4f, 0x13b: 0x50, 0x13c: 0x51, 0x13d: 0x52, 0x13e: 0x53, 0x13f: 0x54, + // Block 0x5, offset 0x140 + 0x140: 0x55, 0x142: 0x56, 0x144: 0x57, 0x145: 0x58, 0x146: 0x59, 0x147: 0x5a, + 0x14d: 0x5b, + 0x15c: 0x5c, 0x15f: 0x5d, + 0x162: 0x5e, 0x164: 0x5f, + 0x168: 0x60, 0x169: 0x61, 0x16a: 0x62, 0x16c: 0x0d, 0x16d: 0x63, 0x16e: 0x64, 0x16f: 0x65, + 0x170: 0x66, 0x173: 0x67, 0x177: 0x68, + 0x178: 0x0e, 0x179: 0x0f, 0x17a: 0x10, 0x17b: 0x11, 0x17c: 0x12, 0x17d: 0x13, 0x17e: 0x14, 0x17f: 0x15, + // Block 0x6, offset 0x180 + 0x180: 0x69, 0x183: 0x6a, 0x184: 0x6b, 0x186: 0x6c, 0x187: 0x6d, + 0x188: 0x6e, 0x189: 0x16, 0x18a: 0x17, 0x18b: 0x6f, 0x18c: 0x70, + 0x1ab: 0x71, + 0x1b3: 0x72, 0x1b5: 0x73, 0x1b7: 0x74, + // Block 0x7, offset 0x1c0 + 0x1c0: 0x75, 0x1c1: 0x18, 0x1c2: 0x19, 0x1c3: 0x1a, 0x1c4: 0x76, 0x1c5: 0x77, + 0x1c9: 0x78, 0x1cc: 0x79, 0x1cd: 0x7a, + // Block 0x8, offset 0x200 + 0x219: 0x7b, 0x21a: 0x7c, 0x21b: 0x7d, + 0x220: 0x7e, 0x223: 0x7f, 0x224: 0x80, 0x225: 0x81, 0x226: 0x82, 0x227: 0x83, + 0x22a: 0x84, 0x22b: 0x85, 0x22f: 0x86, + 0x230: 0x87, 0x231: 0x88, 0x232: 0x89, 0x233: 0x8a, 0x234: 0x8b, 0x235: 0x8c, 0x236: 0x8d, 0x237: 0x87, + 0x238: 0x88, 0x239: 0x89, 0x23a: 0x8a, 0x23b: 0x8b, 0x23c: 0x8c, 0x23d: 0x8d, 0x23e: 0x87, 0x23f: 0x88, + // Block 0x9, offset 0x240 + 0x240: 0x89, 0x241: 0x8a, 0x242: 0x8b, 0x243: 0x8c, 0x244: 0x8d, 0x245: 0x87, 0x246: 0x88, 0x247: 0x89, + 0x248: 0x8a, 0x249: 0x8b, 0x24a: 0x8c, 0x24b: 0x8d, 0x24c: 0x87, 0x24d: 0x88, 0x24e: 0x89, 0x24f: 0x8a, + 0x250: 0x8b, 0x251: 0x8c, 0x252: 0x8d, 0x253: 0x87, 0x254: 0x88, 0x255: 0x89, 0x256: 0x8a, 0x257: 0x8b, + 0x258: 0x8c, 0x259: 0x8d, 0x25a: 0x87, 0x25b: 0x88, 0x25c: 0x89, 0x25d: 0x8a, 0x25e: 0x8b, 0x25f: 0x8c, + 0x260: 0x8d, 0x261: 0x87, 0x262: 0x88, 0x263: 0x89, 0x264: 0x8a, 0x265: 0x8b, 0x266: 0x8c, 0x267: 0x8d, + 0x268: 0x87, 0x269: 0x88, 0x26a: 0x89, 0x26b: 0x8a, 0x26c: 0x8b, 0x26d: 0x8c, 0x26e: 0x8d, 0x26f: 0x87, + 0x270: 0x88, 0x271: 0x89, 0x272: 0x8a, 0x273: 0x8b, 0x274: 0x8c, 0x275: 0x8d, 0x276: 0x87, 0x277: 0x88, + 0x278: 0x89, 0x279: 0x8a, 0x27a: 0x8b, 0x27b: 0x8c, 0x27c: 0x8d, 0x27d: 0x87, 0x27e: 0x88, 0x27f: 0x89, + // Block 0xa, offset 0x280 + 0x280: 0x8a, 0x281: 0x8b, 0x282: 0x8c, 0x283: 0x8d, 0x284: 0x87, 0x285: 0x88, 0x286: 0x89, 0x287: 0x8a, + 0x288: 0x8b, 0x289: 0x8c, 0x28a: 0x8d, 0x28b: 0x87, 0x28c: 0x88, 0x28d: 0x89, 0x28e: 0x8a, 0x28f: 0x8b, + 0x290: 0x8c, 0x291: 0x8d, 0x292: 0x87, 0x293: 0x88, 0x294: 0x89, 0x295: 0x8a, 0x296: 0x8b, 0x297: 0x8c, + 0x298: 0x8d, 0x299: 0x87, 0x29a: 0x88, 0x29b: 0x89, 0x29c: 0x8a, 0x29d: 0x8b, 0x29e: 0x8c, 0x29f: 0x8d, + 0x2a0: 0x87, 0x2a1: 0x88, 0x2a2: 0x89, 0x2a3: 0x8a, 0x2a4: 0x8b, 0x2a5: 0x8c, 0x2a6: 0x8d, 0x2a7: 0x87, + 0x2a8: 0x88, 0x2a9: 0x89, 0x2aa: 0x8a, 0x2ab: 0x8b, 0x2ac: 0x8c, 0x2ad: 0x8d, 0x2ae: 0x87, 0x2af: 0x88, + 0x2b0: 0x89, 0x2b1: 0x8a, 0x2b2: 0x8b, 0x2b3: 0x8c, 0x2b4: 0x8d, 0x2b5: 0x87, 0x2b6: 0x88, 0x2b7: 0x89, + 0x2b8: 0x8a, 0x2b9: 0x8b, 0x2ba: 0x8c, 0x2bb: 0x8d, 0x2bc: 0x87, 0x2bd: 0x88, 0x2be: 0x89, 0x2bf: 0x8a, + // Block 0xb, offset 0x2c0 + 0x2c0: 0x8b, 0x2c1: 0x8c, 0x2c2: 0x8d, 0x2c3: 0x87, 0x2c4: 0x88, 0x2c5: 0x89, 0x2c6: 0x8a, 0x2c7: 0x8b, + 0x2c8: 0x8c, 0x2c9: 0x8d, 0x2ca: 0x87, 0x2cb: 0x88, 0x2cc: 0x89, 0x2cd: 0x8a, 0x2ce: 0x8b, 0x2cf: 0x8c, + 0x2d0: 0x8d, 0x2d1: 0x87, 0x2d2: 0x88, 0x2d3: 0x89, 0x2d4: 0x8a, 0x2d5: 0x8b, 0x2d6: 0x8c, 0x2d7: 0x8d, + 0x2d8: 0x87, 0x2d9: 0x88, 0x2da: 0x89, 0x2db: 0x8a, 0x2dc: 0x8b, 0x2dd: 0x8c, 0x2de: 0x8e, + // Block 0xc, offset 0x300 + 0x324: 0x1b, 0x325: 0x1c, 0x326: 0x1d, 0x327: 0x1e, + 0x328: 0x1f, 0x329: 0x20, 0x32a: 0x21, 0x32b: 0x22, 0x32c: 0x8f, 0x32d: 0x90, 0x32e: 0x91, + 0x331: 0x92, 0x332: 0x93, 0x333: 0x94, 0x334: 0x95, + 0x338: 0x96, 0x339: 0x97, 0x33a: 0x98, 0x33b: 0x99, 0x33e: 0x9a, 0x33f: 0x9b, + // Block 0xd, offset 0x340 + 0x347: 0x9c, + 0x34b: 0x9d, 0x34d: 0x9e, + 0x368: 0x9f, 0x36b: 0xa0, + // Block 0xe, offset 0x380 + 0x381: 0xa1, 0x382: 0xa2, 0x384: 0xa3, 0x385: 0x82, 0x387: 0xa4, + 0x388: 0xa5, 0x38b: 0xa6, 0x38c: 0x3e, 0x38d: 0xa7, + 0x391: 0xa8, 0x392: 0xa9, 0x393: 0xaa, 0x396: 0xab, 0x397: 0xac, + 0x398: 0x73, 0x39a: 0xad, 0x39c: 0xae, + 0x3b0: 0x73, + // Block 0xf, offset 0x3c0 + 0x3eb: 0xaf, 0x3ec: 0xb0, + // Block 0x10, offset 0x400 + 0x432: 0xb1, + // Block 0x11, offset 0x440 + 0x445: 0xb2, 0x446: 0xb3, 0x447: 0xb4, + 0x449: 0xb5, + // Block 0x12, offset 0x480 + 0x480: 0xb6, + 0x4a3: 0xb7, 0x4a5: 0xb8, + // Block 0x13, offset 0x4c0 + 0x4c8: 0xb9, + // Block 0x14, offset 0x500 + 0x520: 0x23, 0x521: 0x24, 0x522: 0x25, 0x523: 0x26, 0x524: 0x27, 0x525: 0x28, 0x526: 0x29, 0x527: 0x2a, + 0x528: 0x2b, + // Block 0x15, offset 0x540 + 0x550: 0x0b, 0x551: 0x0c, 0x556: 0x0d, + 0x55b: 0x0e, 0x55d: 0x0f, 0x55e: 0x10, 0x55f: 0x11, + 0x56f: 0x12, +} + +// nfcSparseOffset: 142 entries, 284 bytes +var nfcSparseOffset = []uint16{0x0, 0x5, 0x9, 0xb, 0xd, 0x18, 0x28, 0x2a, 0x2f, 0x3a, 0x49, 0x56, 0x5e, 0x62, 0x67, 0x69, 0x7a, 0x82, 0x89, 0x8c, 0x93, 0x97, 0x9b, 0x9d, 0x9f, 0xa8, 0xac, 0xb3, 0xb8, 0xbb, 0xc5, 0xc7, 0xce, 0xd6, 0xd9, 0xdb, 0xdd, 0xdf, 0xe4, 0xf5, 0x101, 0x103, 0x109, 0x10b, 0x10d, 0x10f, 0x111, 0x113, 0x115, 0x118, 0x11b, 0x11d, 0x120, 0x123, 0x127, 0x12c, 0x135, 0x137, 0x13a, 0x13c, 0x147, 0x157, 0x15b, 0x169, 0x16c, 0x172, 0x178, 0x183, 0x187, 0x189, 0x18b, 0x18d, 0x18f, 0x191, 0x197, 0x19b, 0x19d, 0x19f, 0x1a7, 0x1ab, 0x1ae, 0x1b0, 0x1b2, 0x1b4, 0x1b7, 0x1b9, 0x1bb, 0x1bd, 0x1bf, 0x1c5, 0x1c8, 0x1ca, 0x1d1, 0x1d7, 0x1dd, 0x1e5, 0x1eb, 0x1f1, 0x1f7, 0x1fb, 0x209, 0x212, 0x215, 0x218, 0x21a, 0x21d, 0x21f, 0x223, 0x228, 0x22a, 0x22c, 0x231, 0x237, 0x239, 0x23b, 0x23d, 0x243, 0x246, 0x249, 0x251, 0x258, 0x25b, 0x25e, 0x260, 0x268, 0x26b, 0x272, 0x275, 0x27b, 0x27d, 0x280, 0x282, 0x284, 0x286, 0x288, 0x295, 0x29f, 0x2a1, 0x2a3, 0x2a9, 0x2ab, 0x2ae} + +// nfcSparseValues: 688 entries, 2752 bytes +var nfcSparseValues = [688]valueRange{ + // Block 0x0, offset 0x0 + {value: 0x0000, lo: 0x04}, + {value: 0xa100, lo: 0xa8, hi: 0xa8}, + {value: 0x8100, lo: 0xaf, hi: 0xaf}, + {value: 0x8100, lo: 0xb4, hi: 0xb4}, + {value: 0x8100, lo: 0xb8, hi: 0xb8}, + // Block 0x1, offset 0x5 + {value: 0x0091, lo: 0x03}, + {value: 0x46e2, lo: 0xa0, hi: 0xa1}, + {value: 0x4714, lo: 0xaf, hi: 0xb0}, + {value: 0xa000, lo: 0xb7, hi: 0xb7}, + // Block 0x2, offset 0x9 + {value: 0x0000, lo: 0x01}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + // Block 0x3, offset 0xb + {value: 0x0000, lo: 0x01}, + {value: 0x8100, lo: 0x98, hi: 0x9d}, + // Block 0x4, offset 0xd + {value: 0x0006, lo: 0x0a}, + {value: 0xa000, lo: 0x81, hi: 0x81}, + {value: 0xa000, lo: 0x85, hi: 0x85}, + {value: 0xa000, lo: 0x89, hi: 0x89}, + {value: 0x4840, lo: 0x8a, hi: 0x8a}, + {value: 0x485e, lo: 0x8b, hi: 0x8b}, + {value: 0x36c7, lo: 0x8c, hi: 0x8c}, + {value: 0x36df, lo: 0x8d, hi: 0x8d}, + {value: 0x4876, lo: 0x8e, hi: 0x8e}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0x36fd, lo: 0x93, hi: 0x94}, + // Block 0x5, offset 0x18 + {value: 0x0000, lo: 0x0f}, + {value: 0xa000, lo: 0x83, hi: 0x83}, + {value: 0xa000, lo: 0x87, hi: 0x87}, + {value: 0xa000, lo: 0x8b, hi: 0x8b}, + {value: 0xa000, lo: 0x8d, hi: 0x8d}, + {value: 0x37a5, lo: 0x90, hi: 0x90}, + {value: 0x37b1, lo: 0x91, hi: 0x91}, + {value: 0x379f, lo: 0x93, hi: 0x93}, + {value: 0xa000, lo: 0x96, hi: 0x96}, + {value: 0x3817, lo: 0x97, hi: 0x97}, + {value: 0x37e1, lo: 0x9c, hi: 0x9c}, + {value: 0x37c9, lo: 0x9d, hi: 0x9d}, + {value: 0x37f3, lo: 0x9e, hi: 0x9e}, + {value: 0xa000, lo: 0xb4, hi: 0xb5}, + {value: 0x381d, lo: 0xb6, hi: 0xb6}, + {value: 0x3823, lo: 0xb7, hi: 0xb7}, + // Block 0x6, offset 0x28 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0x83, hi: 0x87}, + // Block 0x7, offset 0x2a + {value: 0x0001, lo: 0x04}, + {value: 0x8113, lo: 0x81, hi: 0x82}, + {value: 0x8132, lo: 0x84, hi: 0x84}, + {value: 0x812d, lo: 0x85, hi: 0x85}, + {value: 0x810d, lo: 0x87, hi: 0x87}, + // Block 0x8, offset 0x2f + {value: 0x0000, lo: 0x0a}, + {value: 0x8132, lo: 0x90, hi: 0x97}, + {value: 0x8119, lo: 0x98, hi: 0x98}, + {value: 0x811a, lo: 0x99, hi: 0x99}, + {value: 0x811b, lo: 0x9a, hi: 0x9a}, + {value: 0x3841, lo: 0xa2, hi: 0xa2}, + {value: 0x3847, lo: 0xa3, hi: 0xa3}, + {value: 0x3853, lo: 0xa4, hi: 0xa4}, + {value: 0x384d, lo: 0xa5, hi: 0xa5}, + {value: 0x3859, lo: 0xa6, hi: 0xa6}, + {value: 0xa000, lo: 0xa7, hi: 0xa7}, + // Block 0x9, offset 0x3a + {value: 0x0000, lo: 0x0e}, + {value: 0x386b, lo: 0x80, hi: 0x80}, + {value: 0xa000, lo: 0x81, hi: 0x81}, + {value: 0x385f, lo: 0x82, hi: 0x82}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0x3865, lo: 0x93, hi: 0x93}, + {value: 0xa000, lo: 0x95, hi: 0x95}, + {value: 0x8132, lo: 0x96, hi: 0x9c}, + {value: 0x8132, lo: 0x9f, hi: 0xa2}, + {value: 0x812d, lo: 0xa3, hi: 0xa3}, + {value: 0x8132, lo: 0xa4, hi: 0xa4}, + {value: 0x8132, lo: 0xa7, hi: 0xa8}, + {value: 0x812d, lo: 0xaa, hi: 0xaa}, + {value: 0x8132, lo: 0xab, hi: 0xac}, + {value: 0x812d, lo: 0xad, hi: 0xad}, + // Block 0xa, offset 0x49 + {value: 0x0000, lo: 0x0c}, + {value: 0x811f, lo: 0x91, hi: 0x91}, + {value: 0x8132, lo: 0xb0, hi: 0xb0}, + {value: 0x812d, lo: 0xb1, hi: 0xb1}, + {value: 0x8132, lo: 0xb2, hi: 0xb3}, + {value: 0x812d, lo: 0xb4, hi: 0xb4}, + {value: 0x8132, lo: 0xb5, hi: 0xb6}, + {value: 0x812d, lo: 0xb7, hi: 0xb9}, + {value: 0x8132, lo: 0xba, hi: 0xba}, + {value: 0x812d, lo: 0xbb, hi: 0xbc}, + {value: 0x8132, lo: 0xbd, hi: 0xbd}, + {value: 0x812d, lo: 0xbe, hi: 0xbe}, + {value: 0x8132, lo: 0xbf, hi: 0xbf}, + // Block 0xb, offset 0x56 + {value: 0x0005, lo: 0x07}, + {value: 0x8132, lo: 0x80, hi: 0x80}, + {value: 0x8132, lo: 0x81, hi: 0x81}, + {value: 0x812d, lo: 0x82, hi: 0x83}, + {value: 0x812d, lo: 0x84, hi: 0x85}, + {value: 0x812d, lo: 0x86, hi: 0x87}, + {value: 0x812d, lo: 0x88, hi: 0x89}, + {value: 0x8132, lo: 0x8a, hi: 0x8a}, + // Block 0xc, offset 0x5e + {value: 0x0000, lo: 0x03}, + {value: 0x8132, lo: 0xab, hi: 0xb1}, + {value: 0x812d, lo: 0xb2, hi: 0xb2}, + {value: 0x8132, lo: 0xb3, hi: 0xb3}, + // Block 0xd, offset 0x62 + {value: 0x0000, lo: 0x04}, + {value: 0x8132, lo: 0x96, hi: 0x99}, + {value: 0x8132, lo: 0x9b, hi: 0xa3}, + {value: 0x8132, lo: 0xa5, hi: 0xa7}, + {value: 0x8132, lo: 0xa9, hi: 0xad}, + // Block 0xe, offset 0x67 + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0x99, hi: 0x9b}, + // Block 0xf, offset 0x69 + {value: 0x0000, lo: 0x10}, + {value: 0x8132, lo: 0x94, hi: 0xa1}, + {value: 0x812d, lo: 0xa3, hi: 0xa3}, + {value: 0x8132, lo: 0xa4, hi: 0xa5}, + {value: 0x812d, lo: 0xa6, hi: 0xa6}, + {value: 0x8132, lo: 0xa7, hi: 0xa8}, + {value: 0x812d, lo: 0xa9, hi: 0xa9}, + {value: 0x8132, lo: 0xaa, hi: 0xac}, + {value: 0x812d, lo: 0xad, hi: 0xaf}, + {value: 0x8116, lo: 0xb0, hi: 0xb0}, + {value: 0x8117, lo: 0xb1, hi: 0xb1}, + {value: 0x8118, lo: 0xb2, hi: 0xb2}, + {value: 0x8132, lo: 0xb3, hi: 0xb5}, + {value: 0x812d, lo: 0xb6, hi: 0xb6}, + {value: 0x8132, lo: 0xb7, hi: 0xb8}, + {value: 0x812d, lo: 0xb9, hi: 0xba}, + {value: 0x8132, lo: 0xbb, hi: 0xbf}, + // Block 0x10, offset 0x7a + {value: 0x0000, lo: 0x07}, + {value: 0xa000, lo: 0xa8, hi: 0xa8}, + {value: 0x3ed8, lo: 0xa9, hi: 0xa9}, + {value: 0xa000, lo: 0xb0, hi: 0xb0}, + {value: 0x3ee0, lo: 0xb1, hi: 0xb1}, + {value: 0xa000, lo: 0xb3, hi: 0xb3}, + {value: 0x3ee8, lo: 0xb4, hi: 0xb4}, + {value: 0x9902, lo: 0xbc, hi: 0xbc}, + // Block 0x11, offset 0x82 + {value: 0x0008, lo: 0x06}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x8132, lo: 0x91, hi: 0x91}, + {value: 0x812d, lo: 0x92, hi: 0x92}, + {value: 0x8132, lo: 0x93, hi: 0x93}, + {value: 0x8132, lo: 0x94, hi: 0x94}, + {value: 0x451c, lo: 0x98, hi: 0x9f}, + // Block 0x12, offset 0x89 + {value: 0x0000, lo: 0x02}, + {value: 0x8102, lo: 0xbc, hi: 0xbc}, + {value: 0x9900, lo: 0xbe, hi: 0xbe}, + // Block 0x13, offset 0x8c + {value: 0x0008, lo: 0x06}, + {value: 0xa000, lo: 0x87, hi: 0x87}, + {value: 0x2c9e, lo: 0x8b, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x97, hi: 0x97}, + {value: 0x455c, lo: 0x9c, hi: 0x9d}, + {value: 0x456c, lo: 0x9f, hi: 0x9f}, + // Block 0x14, offset 0x93 + {value: 0x0000, lo: 0x03}, + {value: 0x4594, lo: 0xb3, hi: 0xb3}, + {value: 0x459c, lo: 0xb6, hi: 0xb6}, + {value: 0x8102, lo: 0xbc, hi: 0xbc}, + // Block 0x15, offset 0x97 + {value: 0x0008, lo: 0x03}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x4574, lo: 0x99, hi: 0x9b}, + {value: 0x458c, lo: 0x9e, hi: 0x9e}, + // Block 0x16, offset 0x9b + {value: 0x0000, lo: 0x01}, + {value: 0x8102, lo: 0xbc, hi: 0xbc}, + // Block 0x17, offset 0x9d + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + // Block 0x18, offset 0x9f + {value: 0x0000, lo: 0x08}, + {value: 0xa000, lo: 0x87, hi: 0x87}, + {value: 0x2cb6, lo: 0x88, hi: 0x88}, + {value: 0x2cae, lo: 0x8b, hi: 0x8b}, + {value: 0x2cbe, lo: 0x8c, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x96, hi: 0x97}, + {value: 0x45a4, lo: 0x9c, hi: 0x9c}, + {value: 0x45ac, lo: 0x9d, hi: 0x9d}, + // Block 0x19, offset 0xa8 + {value: 0x0000, lo: 0x03}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0x2cc6, lo: 0x94, hi: 0x94}, + {value: 0x9900, lo: 0xbe, hi: 0xbe}, + // Block 0x1a, offset 0xac + {value: 0x0000, lo: 0x06}, + {value: 0xa000, lo: 0x86, hi: 0x87}, + {value: 0x2cce, lo: 0x8a, hi: 0x8a}, + {value: 0x2cde, lo: 0x8b, hi: 0x8b}, + {value: 0x2cd6, lo: 0x8c, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x97, hi: 0x97}, + // Block 0x1b, offset 0xb3 + {value: 0x1801, lo: 0x04}, + {value: 0xa000, lo: 0x86, hi: 0x86}, + {value: 0x3ef0, lo: 0x88, hi: 0x88}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x8120, lo: 0x95, hi: 0x96}, + // Block 0x1c, offset 0xb8 + {value: 0x0000, lo: 0x02}, + {value: 0x8102, lo: 0xbc, hi: 0xbc}, + {value: 0xa000, lo: 0xbf, hi: 0xbf}, + // Block 0x1d, offset 0xbb + {value: 0x0000, lo: 0x09}, + {value: 0x2ce6, lo: 0x80, hi: 0x80}, + {value: 0x9900, lo: 0x82, hi: 0x82}, + {value: 0xa000, lo: 0x86, hi: 0x86}, + {value: 0x2cee, lo: 0x87, hi: 0x87}, + {value: 0x2cf6, lo: 0x88, hi: 0x88}, + {value: 0x2f50, lo: 0x8a, hi: 0x8a}, + {value: 0x2dd8, lo: 0x8b, hi: 0x8b}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x95, hi: 0x96}, + // Block 0x1e, offset 0xc5 + {value: 0x0000, lo: 0x01}, + {value: 0x9900, lo: 0xbe, hi: 0xbe}, + // Block 0x1f, offset 0xc7 + {value: 0x0000, lo: 0x06}, + {value: 0xa000, lo: 0x86, hi: 0x87}, + {value: 0x2cfe, lo: 0x8a, hi: 0x8a}, + {value: 0x2d0e, lo: 0x8b, hi: 0x8b}, + {value: 0x2d06, lo: 0x8c, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x97, hi: 0x97}, + // Block 0x20, offset 0xce + {value: 0x6bea, lo: 0x07}, + {value: 0x9904, lo: 0x8a, hi: 0x8a}, + {value: 0x9900, lo: 0x8f, hi: 0x8f}, + {value: 0xa000, lo: 0x99, hi: 0x99}, + {value: 0x3ef8, lo: 0x9a, hi: 0x9a}, + {value: 0x2f58, lo: 0x9c, hi: 0x9c}, + {value: 0x2de3, lo: 0x9d, hi: 0x9d}, + {value: 0x2d16, lo: 0x9e, hi: 0x9f}, + // Block 0x21, offset 0xd6 + {value: 0x0000, lo: 0x02}, + {value: 0x8122, lo: 0xb8, hi: 0xb9}, + {value: 0x8104, lo: 0xba, hi: 0xba}, + // Block 0x22, offset 0xd9 + {value: 0x0000, lo: 0x01}, + {value: 0x8123, lo: 0x88, hi: 0x8b}, + // Block 0x23, offset 0xdb + {value: 0x0000, lo: 0x01}, + {value: 0x8124, lo: 0xb8, hi: 0xb9}, + // Block 0x24, offset 0xdd + {value: 0x0000, lo: 0x01}, + {value: 0x8125, lo: 0x88, hi: 0x8b}, + // Block 0x25, offset 0xdf + {value: 0x0000, lo: 0x04}, + {value: 0x812d, lo: 0x98, hi: 0x99}, + {value: 0x812d, lo: 0xb5, hi: 0xb5}, + {value: 0x812d, lo: 0xb7, hi: 0xb7}, + {value: 0x812b, lo: 0xb9, hi: 0xb9}, + // Block 0x26, offset 0xe4 + {value: 0x0000, lo: 0x10}, + {value: 0x2644, lo: 0x83, hi: 0x83}, + {value: 0x264b, lo: 0x8d, hi: 0x8d}, + {value: 0x2652, lo: 0x92, hi: 0x92}, + {value: 0x2659, lo: 0x97, hi: 0x97}, + {value: 0x2660, lo: 0x9c, hi: 0x9c}, + {value: 0x263d, lo: 0xa9, hi: 0xa9}, + {value: 0x8126, lo: 0xb1, hi: 0xb1}, + {value: 0x8127, lo: 0xb2, hi: 0xb2}, + {value: 0x4a84, lo: 0xb3, hi: 0xb3}, + {value: 0x8128, lo: 0xb4, hi: 0xb4}, + {value: 0x4a8d, lo: 0xb5, hi: 0xb5}, + {value: 0x45b4, lo: 0xb6, hi: 0xb6}, + {value: 0x8200, lo: 0xb7, hi: 0xb7}, + {value: 0x45bc, lo: 0xb8, hi: 0xb8}, + {value: 0x8200, lo: 0xb9, hi: 0xb9}, + {value: 0x8127, lo: 0xba, hi: 0xbd}, + // Block 0x27, offset 0xf5 + {value: 0x0000, lo: 0x0b}, + {value: 0x8127, lo: 0x80, hi: 0x80}, + {value: 0x4a96, lo: 0x81, hi: 0x81}, + {value: 0x8132, lo: 0x82, hi: 0x83}, + {value: 0x8104, lo: 0x84, hi: 0x84}, + {value: 0x8132, lo: 0x86, hi: 0x87}, + {value: 0x266e, lo: 0x93, hi: 0x93}, + {value: 0x2675, lo: 0x9d, hi: 0x9d}, + {value: 0x267c, lo: 0xa2, hi: 0xa2}, + {value: 0x2683, lo: 0xa7, hi: 0xa7}, + {value: 0x268a, lo: 0xac, hi: 0xac}, + {value: 0x2667, lo: 0xb9, hi: 0xb9}, + // Block 0x28, offset 0x101 + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0x86, hi: 0x86}, + // Block 0x29, offset 0x103 + {value: 0x0000, lo: 0x05}, + {value: 0xa000, lo: 0xa5, hi: 0xa5}, + {value: 0x2d1e, lo: 0xa6, hi: 0xa6}, + {value: 0x9900, lo: 0xae, hi: 0xae}, + {value: 0x8102, lo: 0xb7, hi: 0xb7}, + {value: 0x8104, lo: 0xb9, hi: 0xba}, + // Block 0x2a, offset 0x109 + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0x8d, hi: 0x8d}, + // Block 0x2b, offset 0x10b + {value: 0x0000, lo: 0x01}, + {value: 0xa000, lo: 0x80, hi: 0x92}, + // Block 0x2c, offset 0x10d + {value: 0x0000, lo: 0x01}, + {value: 0xb900, lo: 0xa1, hi: 0xb5}, + // Block 0x2d, offset 0x10f + {value: 0x0000, lo: 0x01}, + {value: 0x9900, lo: 0xa8, hi: 0xbf}, + // Block 0x2e, offset 0x111 + {value: 0x0000, lo: 0x01}, + {value: 0x9900, lo: 0x80, hi: 0x82}, + // Block 0x2f, offset 0x113 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0x9d, hi: 0x9f}, + // Block 0x30, offset 0x115 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x94, hi: 0x94}, + {value: 0x8104, lo: 0xb4, hi: 0xb4}, + // Block 0x31, offset 0x118 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x92, hi: 0x92}, + {value: 0x8132, lo: 0x9d, hi: 0x9d}, + // Block 0x32, offset 0x11b + {value: 0x0000, lo: 0x01}, + {value: 0x8131, lo: 0xa9, hi: 0xa9}, + // Block 0x33, offset 0x11d + {value: 0x0004, lo: 0x02}, + {value: 0x812e, lo: 0xb9, hi: 0xba}, + {value: 0x812d, lo: 0xbb, hi: 0xbb}, + // Block 0x34, offset 0x120 + {value: 0x0000, lo: 0x02}, + {value: 0x8132, lo: 0x97, hi: 0x97}, + {value: 0x812d, lo: 0x98, hi: 0x98}, + // Block 0x35, offset 0x123 + {value: 0x0000, lo: 0x03}, + {value: 0x8104, lo: 0xa0, hi: 0xa0}, + {value: 0x8132, lo: 0xb5, hi: 0xbc}, + {value: 0x812d, lo: 0xbf, hi: 0xbf}, + // Block 0x36, offset 0x127 + {value: 0x0000, lo: 0x04}, + {value: 0x8132, lo: 0xb0, hi: 0xb4}, + {value: 0x812d, lo: 0xb5, hi: 0xba}, + {value: 0x8132, lo: 0xbb, hi: 0xbc}, + {value: 0x812d, lo: 0xbd, hi: 0xbd}, + // Block 0x37, offset 0x12c + {value: 0x0000, lo: 0x08}, + {value: 0x2d66, lo: 0x80, hi: 0x80}, + {value: 0x2d6e, lo: 0x81, hi: 0x81}, + {value: 0xa000, lo: 0x82, hi: 0x82}, + {value: 0x2d76, lo: 0x83, hi: 0x83}, + {value: 0x8104, lo: 0x84, hi: 0x84}, + {value: 0x8132, lo: 0xab, hi: 0xab}, + {value: 0x812d, lo: 0xac, hi: 0xac}, + {value: 0x8132, lo: 0xad, hi: 0xb3}, + // Block 0x38, offset 0x135 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0xaa, hi: 0xab}, + // Block 0x39, offset 0x137 + {value: 0x0000, lo: 0x02}, + {value: 0x8102, lo: 0xa6, hi: 0xa6}, + {value: 0x8104, lo: 0xb2, hi: 0xb3}, + // Block 0x3a, offset 0x13a + {value: 0x0000, lo: 0x01}, + {value: 0x8102, lo: 0xb7, hi: 0xb7}, + // Block 0x3b, offset 0x13c + {value: 0x0000, lo: 0x0a}, + {value: 0x8132, lo: 0x90, hi: 0x92}, + {value: 0x8101, lo: 0x94, hi: 0x94}, + {value: 0x812d, lo: 0x95, hi: 0x99}, + {value: 0x8132, lo: 0x9a, hi: 0x9b}, + {value: 0x812d, lo: 0x9c, hi: 0x9f}, + {value: 0x8132, lo: 0xa0, hi: 0xa0}, + {value: 0x8101, lo: 0xa2, hi: 0xa8}, + {value: 0x812d, lo: 0xad, hi: 0xad}, + {value: 0x8132, lo: 0xb4, hi: 0xb4}, + {value: 0x8132, lo: 0xb8, hi: 0xb9}, + // Block 0x3c, offset 0x147 + {value: 0x0000, lo: 0x0f}, + {value: 0x8132, lo: 0x80, hi: 0x81}, + {value: 0x812d, lo: 0x82, hi: 0x82}, + {value: 0x8132, lo: 0x83, hi: 0x89}, + {value: 0x812d, lo: 0x8a, hi: 0x8a}, + {value: 0x8132, lo: 0x8b, hi: 0x8c}, + {value: 0x8135, lo: 0x8d, hi: 0x8d}, + {value: 0x812a, lo: 0x8e, hi: 0x8e}, + {value: 0x812d, lo: 0x8f, hi: 0x8f}, + {value: 0x8129, lo: 0x90, hi: 0x90}, + {value: 0x8132, lo: 0x91, hi: 0xb5}, + {value: 0x8132, lo: 0xbb, hi: 0xbb}, + {value: 0x8134, lo: 0xbc, hi: 0xbc}, + {value: 0x812d, lo: 0xbd, hi: 0xbd}, + {value: 0x8132, lo: 0xbe, hi: 0xbe}, + {value: 0x812d, lo: 0xbf, hi: 0xbf}, + // Block 0x3d, offset 0x157 + {value: 0x0004, lo: 0x03}, + {value: 0x0433, lo: 0x80, hi: 0x81}, + {value: 0x8100, lo: 0x97, hi: 0x97}, + {value: 0x8100, lo: 0xbe, hi: 0xbe}, + // Block 0x3e, offset 0x15b + {value: 0x0000, lo: 0x0d}, + {value: 0x8132, lo: 0x90, hi: 0x91}, + {value: 0x8101, lo: 0x92, hi: 0x93}, + {value: 0x8132, lo: 0x94, hi: 0x97}, + {value: 0x8101, lo: 0x98, hi: 0x9a}, + {value: 0x8132, lo: 0x9b, hi: 0x9c}, + {value: 0x8132, lo: 0xa1, hi: 0xa1}, + {value: 0x8101, lo: 0xa5, hi: 0xa6}, + {value: 0x8132, lo: 0xa7, hi: 0xa7}, + {value: 0x812d, lo: 0xa8, hi: 0xa8}, + {value: 0x8132, lo: 0xa9, hi: 0xa9}, + {value: 0x8101, lo: 0xaa, hi: 0xab}, + {value: 0x812d, lo: 0xac, hi: 0xaf}, + {value: 0x8132, lo: 0xb0, hi: 0xb0}, + // Block 0x3f, offset 0x169 + {value: 0x427b, lo: 0x02}, + {value: 0x01b8, lo: 0xa6, hi: 0xa6}, + {value: 0x0057, lo: 0xaa, hi: 0xab}, + // Block 0x40, offset 0x16c + {value: 0x0007, lo: 0x05}, + {value: 0xa000, lo: 0x90, hi: 0x90}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0xa000, lo: 0x94, hi: 0x94}, + {value: 0x3bb9, lo: 0x9a, hi: 0x9b}, + {value: 0x3bc7, lo: 0xae, hi: 0xae}, + // Block 0x41, offset 0x172 + {value: 0x000e, lo: 0x05}, + {value: 0x3bce, lo: 0x8d, hi: 0x8e}, + {value: 0x3bd5, lo: 0x8f, hi: 0x8f}, + {value: 0xa000, lo: 0x90, hi: 0x90}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0xa000, lo: 0x94, hi: 0x94}, + // Block 0x42, offset 0x178 + {value: 0x6408, lo: 0x0a}, + {value: 0xa000, lo: 0x83, hi: 0x83}, + {value: 0x3be3, lo: 0x84, hi: 0x84}, + {value: 0xa000, lo: 0x88, hi: 0x88}, + {value: 0x3bea, lo: 0x89, hi: 0x89}, + {value: 0xa000, lo: 0x8b, hi: 0x8b}, + {value: 0x3bf1, lo: 0x8c, hi: 0x8c}, + {value: 0xa000, lo: 0xa3, hi: 0xa3}, + {value: 0x3bf8, lo: 0xa4, hi: 0xa5}, + {value: 0x3bff, lo: 0xa6, hi: 0xa6}, + {value: 0xa000, lo: 0xbc, hi: 0xbc}, + // Block 0x43, offset 0x183 + {value: 0x0007, lo: 0x03}, + {value: 0x3c68, lo: 0xa0, hi: 0xa1}, + {value: 0x3c92, lo: 0xa2, hi: 0xa3}, + {value: 0x3cbc, lo: 0xaa, hi: 0xad}, + // Block 0x44, offset 0x187 + {value: 0x0004, lo: 0x01}, + {value: 0x048b, lo: 0xa9, hi: 0xaa}, + // Block 0x45, offset 0x189 + {value: 0x0000, lo: 0x01}, + {value: 0x44dd, lo: 0x9c, hi: 0x9c}, + // Block 0x46, offset 0x18b + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xaf, hi: 0xb1}, + // Block 0x47, offset 0x18d + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0xbf, hi: 0xbf}, + // Block 0x48, offset 0x18f + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xa0, hi: 0xbf}, + // Block 0x49, offset 0x191 + {value: 0x0000, lo: 0x05}, + {value: 0x812c, lo: 0xaa, hi: 0xaa}, + {value: 0x8131, lo: 0xab, hi: 0xab}, + {value: 0x8133, lo: 0xac, hi: 0xac}, + {value: 0x812e, lo: 0xad, hi: 0xad}, + {value: 0x812f, lo: 0xae, hi: 0xaf}, + // Block 0x4a, offset 0x197 + {value: 0x0000, lo: 0x03}, + {value: 0x4a9f, lo: 0xb3, hi: 0xb3}, + {value: 0x4a9f, lo: 0xb5, hi: 0xb6}, + {value: 0x4a9f, lo: 0xba, hi: 0xbf}, + // Block 0x4b, offset 0x19b + {value: 0x0000, lo: 0x01}, + {value: 0x4a9f, lo: 0x8f, hi: 0xa3}, + // Block 0x4c, offset 0x19d + {value: 0x0000, lo: 0x01}, + {value: 0x8100, lo: 0xae, hi: 0xbe}, + // Block 0x4d, offset 0x19f + {value: 0x0000, lo: 0x07}, + {value: 0x8100, lo: 0x84, hi: 0x84}, + {value: 0x8100, lo: 0x87, hi: 0x87}, + {value: 0x8100, lo: 0x90, hi: 0x90}, + {value: 0x8100, lo: 0x9e, hi: 0x9e}, + {value: 0x8100, lo: 0xa1, hi: 0xa1}, + {value: 0x8100, lo: 0xb2, hi: 0xb2}, + {value: 0x8100, lo: 0xbb, hi: 0xbb}, + // Block 0x4e, offset 0x1a7 + {value: 0x0000, lo: 0x03}, + {value: 0x8100, lo: 0x80, hi: 0x80}, + {value: 0x8100, lo: 0x8b, hi: 0x8b}, + {value: 0x8100, lo: 0x8e, hi: 0x8e}, + // Block 0x4f, offset 0x1ab + {value: 0x0000, lo: 0x02}, + {value: 0x8132, lo: 0xaf, hi: 0xaf}, + {value: 0x8132, lo: 0xb4, hi: 0xbd}, + // Block 0x50, offset 0x1ae + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0x9e, hi: 0x9f}, + // Block 0x51, offset 0x1b0 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xb0, hi: 0xb1}, + // Block 0x52, offset 0x1b2 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x86, hi: 0x86}, + // Block 0x53, offset 0x1b4 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x84, hi: 0x84}, + {value: 0x8132, lo: 0xa0, hi: 0xb1}, + // Block 0x54, offset 0x1b7 + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0xab, hi: 0xad}, + // Block 0x55, offset 0x1b9 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x93, hi: 0x93}, + // Block 0x56, offset 0x1bb + {value: 0x0000, lo: 0x01}, + {value: 0x8102, lo: 0xb3, hi: 0xb3}, + // Block 0x57, offset 0x1bd + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x80, hi: 0x80}, + // Block 0x58, offset 0x1bf + {value: 0x0000, lo: 0x05}, + {value: 0x8132, lo: 0xb0, hi: 0xb0}, + {value: 0x8132, lo: 0xb2, hi: 0xb3}, + {value: 0x812d, lo: 0xb4, hi: 0xb4}, + {value: 0x8132, lo: 0xb7, hi: 0xb8}, + {value: 0x8132, lo: 0xbe, hi: 0xbf}, + // Block 0x59, offset 0x1c5 + {value: 0x0000, lo: 0x02}, + {value: 0x8132, lo: 0x81, hi: 0x81}, + {value: 0x8104, lo: 0xb6, hi: 0xb6}, + // Block 0x5a, offset 0x1c8 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0xad, hi: 0xad}, + // Block 0x5b, offset 0x1ca + {value: 0x0000, lo: 0x06}, + {value: 0xe500, lo: 0x80, hi: 0x80}, + {value: 0xc600, lo: 0x81, hi: 0x9b}, + {value: 0xe500, lo: 0x9c, hi: 0x9c}, + {value: 0xc600, lo: 0x9d, hi: 0xb7}, + {value: 0xe500, lo: 0xb8, hi: 0xb8}, + {value: 0xc600, lo: 0xb9, hi: 0xbf}, + // Block 0x5c, offset 0x1d1 + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x93}, + {value: 0xe500, lo: 0x94, hi: 0x94}, + {value: 0xc600, lo: 0x95, hi: 0xaf}, + {value: 0xe500, lo: 0xb0, hi: 0xb0}, + {value: 0xc600, lo: 0xb1, hi: 0xbf}, + // Block 0x5d, offset 0x1d7 + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x8b}, + {value: 0xe500, lo: 0x8c, hi: 0x8c}, + {value: 0xc600, lo: 0x8d, hi: 0xa7}, + {value: 0xe500, lo: 0xa8, hi: 0xa8}, + {value: 0xc600, lo: 0xa9, hi: 0xbf}, + // Block 0x5e, offset 0x1dd + {value: 0x0000, lo: 0x07}, + {value: 0xc600, lo: 0x80, hi: 0x83}, + {value: 0xe500, lo: 0x84, hi: 0x84}, + {value: 0xc600, lo: 0x85, hi: 0x9f}, + {value: 0xe500, lo: 0xa0, hi: 0xa0}, + {value: 0xc600, lo: 0xa1, hi: 0xbb}, + {value: 0xe500, lo: 0xbc, hi: 0xbc}, + {value: 0xc600, lo: 0xbd, hi: 0xbf}, + // Block 0x5f, offset 0x1e5 + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x97}, + {value: 0xe500, lo: 0x98, hi: 0x98}, + {value: 0xc600, lo: 0x99, hi: 0xb3}, + {value: 0xe500, lo: 0xb4, hi: 0xb4}, + {value: 0xc600, lo: 0xb5, hi: 0xbf}, + // Block 0x60, offset 0x1eb + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x8f}, + {value: 0xe500, lo: 0x90, hi: 0x90}, + {value: 0xc600, lo: 0x91, hi: 0xab}, + {value: 0xe500, lo: 0xac, hi: 0xac}, + {value: 0xc600, lo: 0xad, hi: 0xbf}, + // Block 0x61, offset 0x1f1 + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x87}, + {value: 0xe500, lo: 0x88, hi: 0x88}, + {value: 0xc600, lo: 0x89, hi: 0xa3}, + {value: 0xe500, lo: 0xa4, hi: 0xa4}, + {value: 0xc600, lo: 0xa5, hi: 0xbf}, + // Block 0x62, offset 0x1f7 + {value: 0x0000, lo: 0x03}, + {value: 0xc600, lo: 0x80, hi: 0x87}, + {value: 0xe500, lo: 0x88, hi: 0x88}, + {value: 0xc600, lo: 0x89, hi: 0xa3}, + // Block 0x63, offset 0x1fb + {value: 0x0006, lo: 0x0d}, + {value: 0x4390, lo: 0x9d, hi: 0x9d}, + {value: 0x8115, lo: 0x9e, hi: 0x9e}, + {value: 0x4402, lo: 0x9f, hi: 0x9f}, + {value: 0x43f0, lo: 0xaa, hi: 0xab}, + {value: 0x44f4, lo: 0xac, hi: 0xac}, + {value: 0x44fc, lo: 0xad, hi: 0xad}, + {value: 0x4348, lo: 0xae, hi: 0xb1}, + {value: 0x4366, lo: 0xb2, hi: 0xb4}, + {value: 0x437e, lo: 0xb5, hi: 0xb6}, + {value: 0x438a, lo: 0xb8, hi: 0xb8}, + {value: 0x4396, lo: 0xb9, hi: 0xbb}, + {value: 0x43ae, lo: 0xbc, hi: 0xbc}, + {value: 0x43b4, lo: 0xbe, hi: 0xbe}, + // Block 0x64, offset 0x209 + {value: 0x0006, lo: 0x08}, + {value: 0x43ba, lo: 0x80, hi: 0x81}, + {value: 0x43c6, lo: 0x83, hi: 0x84}, + {value: 0x43d8, lo: 0x86, hi: 0x89}, + {value: 0x43fc, lo: 0x8a, hi: 0x8a}, + {value: 0x4378, lo: 0x8b, hi: 0x8b}, + {value: 0x4360, lo: 0x8c, hi: 0x8c}, + {value: 0x43a8, lo: 0x8d, hi: 0x8d}, + {value: 0x43d2, lo: 0x8e, hi: 0x8e}, + // Block 0x65, offset 0x212 + {value: 0x0000, lo: 0x02}, + {value: 0x8100, lo: 0xa4, hi: 0xa5}, + {value: 0x8100, lo: 0xb0, hi: 0xb1}, + // Block 0x66, offset 0x215 + {value: 0x0000, lo: 0x02}, + {value: 0x8100, lo: 0x9b, hi: 0x9d}, + {value: 0x8200, lo: 0x9e, hi: 0xa3}, + // Block 0x67, offset 0x218 + {value: 0x0000, lo: 0x01}, + {value: 0x8100, lo: 0x90, hi: 0x90}, + // Block 0x68, offset 0x21a + {value: 0x0000, lo: 0x02}, + {value: 0x8100, lo: 0x99, hi: 0x99}, + {value: 0x8200, lo: 0xb2, hi: 0xb4}, + // Block 0x69, offset 0x21d + {value: 0x0000, lo: 0x01}, + {value: 0x8100, lo: 0xbc, hi: 0xbd}, + // Block 0x6a, offset 0x21f + {value: 0x0000, lo: 0x03}, + {value: 0x8132, lo: 0xa0, hi: 0xa6}, + {value: 0x812d, lo: 0xa7, hi: 0xad}, + {value: 0x8132, lo: 0xae, hi: 0xaf}, + // Block 0x6b, offset 0x223 + {value: 0x0000, lo: 0x04}, + {value: 0x8100, lo: 0x89, hi: 0x8c}, + {value: 0x8100, lo: 0xb0, hi: 0xb2}, + {value: 0x8100, lo: 0xb4, hi: 0xb4}, + {value: 0x8100, lo: 0xb6, hi: 0xbf}, + // Block 0x6c, offset 0x228 + {value: 0x0000, lo: 0x01}, + {value: 0x8100, lo: 0x81, hi: 0x8c}, + // Block 0x6d, offset 0x22a + {value: 0x0000, lo: 0x01}, + {value: 0x8100, lo: 0xb5, hi: 0xba}, + // Block 0x6e, offset 0x22c + {value: 0x0000, lo: 0x04}, + {value: 0x4a9f, lo: 0x9e, hi: 0x9f}, + {value: 0x4a9f, lo: 0xa3, hi: 0xa3}, + {value: 0x4a9f, lo: 0xa5, hi: 0xa6}, + {value: 0x4a9f, lo: 0xaa, hi: 0xaf}, + // Block 0x6f, offset 0x231 + {value: 0x0000, lo: 0x05}, + {value: 0x4a9f, lo: 0x82, hi: 0x87}, + {value: 0x4a9f, lo: 0x8a, hi: 0x8f}, + {value: 0x4a9f, lo: 0x92, hi: 0x97}, + {value: 0x4a9f, lo: 0x9a, hi: 0x9c}, + {value: 0x8100, lo: 0xa3, hi: 0xa3}, + // Block 0x70, offset 0x237 + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0xbd, hi: 0xbd}, + // Block 0x71, offset 0x239 + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0xa0, hi: 0xa0}, + // Block 0x72, offset 0x23b + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xb6, hi: 0xba}, + // Block 0x73, offset 0x23d + {value: 0x002c, lo: 0x05}, + {value: 0x812d, lo: 0x8d, hi: 0x8d}, + {value: 0x8132, lo: 0x8f, hi: 0x8f}, + {value: 0x8132, lo: 0xb8, hi: 0xb8}, + {value: 0x8101, lo: 0xb9, hi: 0xba}, + {value: 0x8104, lo: 0xbf, hi: 0xbf}, + // Block 0x74, offset 0x243 + {value: 0x0000, lo: 0x02}, + {value: 0x8132, lo: 0xa5, hi: 0xa5}, + {value: 0x812d, lo: 0xa6, hi: 0xa6}, + // Block 0x75, offset 0x246 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x86, hi: 0x86}, + {value: 0x8104, lo: 0xbf, hi: 0xbf}, + // Block 0x76, offset 0x249 + {value: 0x17fe, lo: 0x07}, + {value: 0xa000, lo: 0x99, hi: 0x99}, + {value: 0x4238, lo: 0x9a, hi: 0x9a}, + {value: 0xa000, lo: 0x9b, hi: 0x9b}, + {value: 0x4242, lo: 0x9c, hi: 0x9c}, + {value: 0xa000, lo: 0xa5, hi: 0xa5}, + {value: 0x424c, lo: 0xab, hi: 0xab}, + {value: 0x8104, lo: 0xb9, hi: 0xba}, + // Block 0x77, offset 0x251 + {value: 0x0000, lo: 0x06}, + {value: 0x8132, lo: 0x80, hi: 0x82}, + {value: 0x9900, lo: 0xa7, hi: 0xa7}, + {value: 0x2d7e, lo: 0xae, hi: 0xae}, + {value: 0x2d88, lo: 0xaf, hi: 0xaf}, + {value: 0xa000, lo: 0xb1, hi: 0xb2}, + {value: 0x8104, lo: 0xb3, hi: 0xb4}, + // Block 0x78, offset 0x258 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x80, hi: 0x80}, + {value: 0x8102, lo: 0x8a, hi: 0x8a}, + // Block 0x79, offset 0x25b + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0xb5, hi: 0xb5}, + {value: 0x8102, lo: 0xb6, hi: 0xb6}, + // Block 0x7a, offset 0x25e + {value: 0x0002, lo: 0x01}, + {value: 0x8102, lo: 0xa9, hi: 0xaa}, + // Block 0x7b, offset 0x260 + {value: 0x0000, lo: 0x07}, + {value: 0xa000, lo: 0x87, hi: 0x87}, + {value: 0x2d92, lo: 0x8b, hi: 0x8b}, + {value: 0x2d9c, lo: 0x8c, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x97, hi: 0x97}, + {value: 0x8132, lo: 0xa6, hi: 0xac}, + {value: 0x8132, lo: 0xb0, hi: 0xb4}, + // Block 0x7c, offset 0x268 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x82, hi: 0x82}, + {value: 0x8102, lo: 0x86, hi: 0x86}, + // Block 0x7d, offset 0x26b + {value: 0x6b5a, lo: 0x06}, + {value: 0x9900, lo: 0xb0, hi: 0xb0}, + {value: 0xa000, lo: 0xb9, hi: 0xb9}, + {value: 0x9900, lo: 0xba, hi: 0xba}, + {value: 0x2db0, lo: 0xbb, hi: 0xbb}, + {value: 0x2da6, lo: 0xbc, hi: 0xbd}, + {value: 0x2dba, lo: 0xbe, hi: 0xbe}, + // Block 0x7e, offset 0x272 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x82, hi: 0x82}, + {value: 0x8102, lo: 0x83, hi: 0x83}, + // Block 0x7f, offset 0x275 + {value: 0x0000, lo: 0x05}, + {value: 0x9900, lo: 0xaf, hi: 0xaf}, + {value: 0xa000, lo: 0xb8, hi: 0xb9}, + {value: 0x2dc4, lo: 0xba, hi: 0xba}, + {value: 0x2dce, lo: 0xbb, hi: 0xbb}, + {value: 0x8104, lo: 0xbf, hi: 0xbf}, + // Block 0x80, offset 0x27b + {value: 0x0000, lo: 0x01}, + {value: 0x8102, lo: 0x80, hi: 0x80}, + // Block 0x81, offset 0x27d + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0xb6, hi: 0xb6}, + {value: 0x8102, lo: 0xb7, hi: 0xb7}, + // Block 0x82, offset 0x280 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0xab, hi: 0xab}, + // Block 0x83, offset 0x282 + {value: 0x0000, lo: 0x01}, + {value: 0x8101, lo: 0xb0, hi: 0xb4}, + // Block 0x84, offset 0x284 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xb0, hi: 0xb6}, + // Block 0x85, offset 0x286 + {value: 0x0000, lo: 0x01}, + {value: 0x8101, lo: 0x9e, hi: 0x9e}, + // Block 0x86, offset 0x288 + {value: 0x0000, lo: 0x0c}, + {value: 0x45cc, lo: 0x9e, hi: 0x9e}, + {value: 0x45d6, lo: 0x9f, hi: 0x9f}, + {value: 0x460a, lo: 0xa0, hi: 0xa0}, + {value: 0x4618, lo: 0xa1, hi: 0xa1}, + {value: 0x4626, lo: 0xa2, hi: 0xa2}, + {value: 0x4634, lo: 0xa3, hi: 0xa3}, + {value: 0x4642, lo: 0xa4, hi: 0xa4}, + {value: 0x812b, lo: 0xa5, hi: 0xa6}, + {value: 0x8101, lo: 0xa7, hi: 0xa9}, + {value: 0x8130, lo: 0xad, hi: 0xad}, + {value: 0x812b, lo: 0xae, hi: 0xb2}, + {value: 0x812d, lo: 0xbb, hi: 0xbf}, + // Block 0x87, offset 0x295 + {value: 0x0000, lo: 0x09}, + {value: 0x812d, lo: 0x80, hi: 0x82}, + {value: 0x8132, lo: 0x85, hi: 0x89}, + {value: 0x812d, lo: 0x8a, hi: 0x8b}, + {value: 0x8132, lo: 0xaa, hi: 0xad}, + {value: 0x45e0, lo: 0xbb, hi: 0xbb}, + {value: 0x45ea, lo: 0xbc, hi: 0xbc}, + {value: 0x4650, lo: 0xbd, hi: 0xbd}, + {value: 0x466c, lo: 0xbe, hi: 0xbe}, + {value: 0x465e, lo: 0xbf, hi: 0xbf}, + // Block 0x88, offset 0x29f + {value: 0x0000, lo: 0x01}, + {value: 0x467a, lo: 0x80, hi: 0x80}, + // Block 0x89, offset 0x2a1 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0x82, hi: 0x84}, + // Block 0x8a, offset 0x2a3 + {value: 0x0000, lo: 0x05}, + {value: 0x8132, lo: 0x80, hi: 0x86}, + {value: 0x8132, lo: 0x88, hi: 0x98}, + {value: 0x8132, lo: 0x9b, hi: 0xa1}, + {value: 0x8132, lo: 0xa3, hi: 0xa4}, + {value: 0x8132, lo: 0xa6, hi: 0xaa}, + // Block 0x8b, offset 0x2a9 + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0x90, hi: 0x96}, + // Block 0x8c, offset 0x2ab + {value: 0x0000, lo: 0x02}, + {value: 0x8132, lo: 0x84, hi: 0x89}, + {value: 0x8102, lo: 0x8a, hi: 0x8a}, + // Block 0x8d, offset 0x2ae + {value: 0x0000, lo: 0x01}, + {value: 0x8100, lo: 0x93, hi: 0x93}, +} + +// lookup returns the trie value for the first UTF-8 encoding in s and +// the width in bytes of this encoding. The size will be 0 if s does not +// hold enough bytes to complete the encoding. len(s) must be greater than 0. +func (t *nfkcTrie) lookup(s []byte) (v uint16, sz int) { + c0 := s[0] + switch { + case c0 < 0x80: // is ASCII + return nfkcValues[c0], 1 + case c0 < 0xC2: + return 0, 1 // Illegal UTF-8: not a starter, not ASCII. + case c0 < 0xE0: // 2-byte UTF-8 + if len(s) < 2 { + return 0, 0 + } + i := nfkcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c1), 2 + case c0 < 0xF0: // 3-byte UTF-8 + if len(s) < 3 { + return 0, 0 + } + i := nfkcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = nfkcIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c2), 3 + case c0 < 0xF8: // 4-byte UTF-8 + if len(s) < 4 { + return 0, 0 + } + i := nfkcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = nfkcIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + o = uint32(i)<<6 + uint32(c2) + i = nfkcIndex[o] + c3 := s[3] + if c3 < 0x80 || 0xC0 <= c3 { + return 0, 3 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c3), 4 + } + // Illegal rune + return 0, 1 +} + +// lookupUnsafe returns the trie value for the first UTF-8 encoding in s. +// s must start with a full and valid UTF-8 encoded rune. +func (t *nfkcTrie) lookupUnsafe(s []byte) uint16 { + c0 := s[0] + if c0 < 0x80 { // is ASCII + return nfkcValues[c0] + } + i := nfkcIndex[c0] + if c0 < 0xE0 { // 2-byte UTF-8 + return t.lookupValue(uint32(i), s[1]) + } + i = nfkcIndex[uint32(i)<<6+uint32(s[1])] + if c0 < 0xF0 { // 3-byte UTF-8 + return t.lookupValue(uint32(i), s[2]) + } + i = nfkcIndex[uint32(i)<<6+uint32(s[2])] + if c0 < 0xF8 { // 4-byte UTF-8 + return t.lookupValue(uint32(i), s[3]) + } + return 0 +} + +// lookupString returns the trie value for the first UTF-8 encoding in s and +// the width in bytes of this encoding. The size will be 0 if s does not +// hold enough bytes to complete the encoding. len(s) must be greater than 0. +func (t *nfkcTrie) lookupString(s string) (v uint16, sz int) { + c0 := s[0] + switch { + case c0 < 0x80: // is ASCII + return nfkcValues[c0], 1 + case c0 < 0xC2: + return 0, 1 // Illegal UTF-8: not a starter, not ASCII. + case c0 < 0xE0: // 2-byte UTF-8 + if len(s) < 2 { + return 0, 0 + } + i := nfkcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c1), 2 + case c0 < 0xF0: // 3-byte UTF-8 + if len(s) < 3 { + return 0, 0 + } + i := nfkcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = nfkcIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c2), 3 + case c0 < 0xF8: // 4-byte UTF-8 + if len(s) < 4 { + return 0, 0 + } + i := nfkcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = nfkcIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + o = uint32(i)<<6 + uint32(c2) + i = nfkcIndex[o] + c3 := s[3] + if c3 < 0x80 || 0xC0 <= c3 { + return 0, 3 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c3), 4 + } + // Illegal rune + return 0, 1 +} + +// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s. +// s must start with a full and valid UTF-8 encoded rune. +func (t *nfkcTrie) lookupStringUnsafe(s string) uint16 { + c0 := s[0] + if c0 < 0x80 { // is ASCII + return nfkcValues[c0] + } + i := nfkcIndex[c0] + if c0 < 0xE0 { // 2-byte UTF-8 + return t.lookupValue(uint32(i), s[1]) + } + i = nfkcIndex[uint32(i)<<6+uint32(s[1])] + if c0 < 0xF0 { // 3-byte UTF-8 + return t.lookupValue(uint32(i), s[2]) + } + i = nfkcIndex[uint32(i)<<6+uint32(s[2])] + if c0 < 0xF8 { // 4-byte UTF-8 + return t.lookupValue(uint32(i), s[3]) + } + return 0 +} + +// nfkcTrie. Total size: 16994 bytes (16.60 KiB). Checksum: c3ed54ee046f3c46. +type nfkcTrie struct{} + +func newNfkcTrie(i int) *nfkcTrie { + return &nfkcTrie{} +} + +// lookupValue determines the type of block n and looks up the value for b. +func (t *nfkcTrie) lookupValue(n uint32, b byte) uint16 { + switch { + case n < 90: + return uint16(nfkcValues[n<<6+uint32(b)]) + default: + n -= 90 + return uint16(nfkcSparse.lookup(n, b)) + } +} + +// nfkcValues: 92 blocks, 5888 entries, 11776 bytes +// The third block is the zero block. +var nfkcValues = [5888]uint16{ + // Block 0x0, offset 0x0 + 0x3c: 0xa000, 0x3d: 0xa000, 0x3e: 0xa000, + // Block 0x1, offset 0x40 + 0x41: 0xa000, 0x42: 0xa000, 0x43: 0xa000, 0x44: 0xa000, 0x45: 0xa000, + 0x46: 0xa000, 0x47: 0xa000, 0x48: 0xa000, 0x49: 0xa000, 0x4a: 0xa000, 0x4b: 0xa000, + 0x4c: 0xa000, 0x4d: 0xa000, 0x4e: 0xa000, 0x4f: 0xa000, 0x50: 0xa000, + 0x52: 0xa000, 0x53: 0xa000, 0x54: 0xa000, 0x55: 0xa000, 0x56: 0xa000, 0x57: 0xa000, + 0x58: 0xa000, 0x59: 0xa000, 0x5a: 0xa000, + 0x61: 0xa000, 0x62: 0xa000, 0x63: 0xa000, + 0x64: 0xa000, 0x65: 0xa000, 0x66: 0xa000, 0x67: 0xa000, 0x68: 0xa000, 0x69: 0xa000, + 0x6a: 0xa000, 0x6b: 0xa000, 0x6c: 0xa000, 0x6d: 0xa000, 0x6e: 0xa000, 0x6f: 0xa000, + 0x70: 0xa000, 0x72: 0xa000, 0x73: 0xa000, 0x74: 0xa000, 0x75: 0xa000, + 0x76: 0xa000, 0x77: 0xa000, 0x78: 0xa000, 0x79: 0xa000, 0x7a: 0xa000, + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0xc0: 0x2f6f, 0xc1: 0x2f74, 0xc2: 0x4688, 0xc3: 0x2f79, 0xc4: 0x4697, 0xc5: 0x469c, + 0xc6: 0xa000, 0xc7: 0x46a6, 0xc8: 0x2fe2, 0xc9: 0x2fe7, 0xca: 0x46ab, 0xcb: 0x2ffb, + 0xcc: 0x306e, 0xcd: 0x3073, 0xce: 0x3078, 0xcf: 0x46bf, 0xd1: 0x3104, + 0xd2: 0x3127, 0xd3: 0x312c, 0xd4: 0x46c9, 0xd5: 0x46ce, 0xd6: 0x46dd, + 0xd8: 0xa000, 0xd9: 0x31b3, 0xda: 0x31b8, 0xdb: 0x31bd, 0xdc: 0x470f, 0xdd: 0x3235, + 0xe0: 0x327b, 0xe1: 0x3280, 0xe2: 0x4719, 0xe3: 0x3285, + 0xe4: 0x4728, 0xe5: 0x472d, 0xe6: 0xa000, 0xe7: 0x4737, 0xe8: 0x32ee, 0xe9: 0x32f3, + 0xea: 0x473c, 0xeb: 0x3307, 0xec: 0x337f, 0xed: 0x3384, 0xee: 0x3389, 0xef: 0x4750, + 0xf1: 0x3415, 0xf2: 0x3438, 0xf3: 0x343d, 0xf4: 0x475a, 0xf5: 0x475f, + 0xf6: 0x476e, 0xf8: 0xa000, 0xf9: 0x34c9, 0xfa: 0x34ce, 0xfb: 0x34d3, + 0xfc: 0x47a0, 0xfd: 0x3550, 0xff: 0x3569, + // Block 0x4, offset 0x100 + 0x100: 0x2f7e, 0x101: 0x328a, 0x102: 0x468d, 0x103: 0x471e, 0x104: 0x2f9c, 0x105: 0x32a8, + 0x106: 0x2fb0, 0x107: 0x32bc, 0x108: 0x2fb5, 0x109: 0x32c1, 0x10a: 0x2fba, 0x10b: 0x32c6, + 0x10c: 0x2fbf, 0x10d: 0x32cb, 0x10e: 0x2fc9, 0x10f: 0x32d5, + 0x112: 0x46b0, 0x113: 0x4741, 0x114: 0x2ff1, 0x115: 0x32fd, 0x116: 0x2ff6, 0x117: 0x3302, + 0x118: 0x3014, 0x119: 0x3320, 0x11a: 0x3005, 0x11b: 0x3311, 0x11c: 0x302d, 0x11d: 0x3339, + 0x11e: 0x3037, 0x11f: 0x3343, 0x120: 0x303c, 0x121: 0x3348, 0x122: 0x3046, 0x123: 0x3352, + 0x124: 0x304b, 0x125: 0x3357, 0x128: 0x307d, 0x129: 0x338e, + 0x12a: 0x3082, 0x12b: 0x3393, 0x12c: 0x3087, 0x12d: 0x3398, 0x12e: 0x30aa, 0x12f: 0x33b6, + 0x130: 0x308c, 0x132: 0x195d, 0x133: 0x19e7, 0x134: 0x30b4, 0x135: 0x33c0, + 0x136: 0x30c8, 0x137: 0x33d9, 0x139: 0x30d2, 0x13a: 0x33e3, 0x13b: 0x30dc, + 0x13c: 0x33ed, 0x13d: 0x30d7, 0x13e: 0x33e8, 0x13f: 0x1bac, + // Block 0x5, offset 0x140 + 0x140: 0x1c34, 0x143: 0x30ff, 0x144: 0x3410, 0x145: 0x3118, + 0x146: 0x3429, 0x147: 0x310e, 0x148: 0x341f, 0x149: 0x1c5c, + 0x14c: 0x46d3, 0x14d: 0x4764, 0x14e: 0x3131, 0x14f: 0x3442, 0x150: 0x313b, 0x151: 0x344c, + 0x154: 0x3159, 0x155: 0x346a, 0x156: 0x3172, 0x157: 0x3483, + 0x158: 0x3163, 0x159: 0x3474, 0x15a: 0x46f6, 0x15b: 0x4787, 0x15c: 0x317c, 0x15d: 0x348d, + 0x15e: 0x318b, 0x15f: 0x349c, 0x160: 0x46fb, 0x161: 0x478c, 0x162: 0x31a4, 0x163: 0x34ba, + 0x164: 0x3195, 0x165: 0x34ab, 0x168: 0x4705, 0x169: 0x4796, + 0x16a: 0x470a, 0x16b: 0x479b, 0x16c: 0x31c2, 0x16d: 0x34d8, 0x16e: 0x31cc, 0x16f: 0x34e2, + 0x170: 0x31d1, 0x171: 0x34e7, 0x172: 0x31ef, 0x173: 0x3505, 0x174: 0x3212, 0x175: 0x3528, + 0x176: 0x323a, 0x177: 0x3555, 0x178: 0x324e, 0x179: 0x325d, 0x17a: 0x357d, 0x17b: 0x3267, + 0x17c: 0x3587, 0x17d: 0x326c, 0x17e: 0x358c, 0x17f: 0x00a7, + // Block 0x6, offset 0x180 + 0x184: 0x2dee, 0x185: 0x2df4, + 0x186: 0x2dfa, 0x187: 0x1972, 0x188: 0x1975, 0x189: 0x1a08, 0x18a: 0x1987, 0x18b: 0x198a, + 0x18c: 0x1a3e, 0x18d: 0x2f88, 0x18e: 0x3294, 0x18f: 0x3096, 0x190: 0x33a2, 0x191: 0x3140, + 0x192: 0x3451, 0x193: 0x31d6, 0x194: 0x34ec, 0x195: 0x39cf, 0x196: 0x3b5e, 0x197: 0x39c8, + 0x198: 0x3b57, 0x199: 0x39d6, 0x19a: 0x3b65, 0x19b: 0x39c1, 0x19c: 0x3b50, + 0x19e: 0x38b0, 0x19f: 0x3a3f, 0x1a0: 0x38a9, 0x1a1: 0x3a38, 0x1a2: 0x35b3, 0x1a3: 0x35c5, + 0x1a6: 0x3041, 0x1a7: 0x334d, 0x1a8: 0x30be, 0x1a9: 0x33cf, + 0x1aa: 0x46ec, 0x1ab: 0x477d, 0x1ac: 0x3990, 0x1ad: 0x3b1f, 0x1ae: 0x35d7, 0x1af: 0x35dd, + 0x1b0: 0x33c5, 0x1b1: 0x1942, 0x1b2: 0x1945, 0x1b3: 0x19cf, 0x1b4: 0x3028, 0x1b5: 0x3334, + 0x1b8: 0x30fa, 0x1b9: 0x340b, 0x1ba: 0x38b7, 0x1bb: 0x3a46, + 0x1bc: 0x35ad, 0x1bd: 0x35bf, 0x1be: 0x35b9, 0x1bf: 0x35cb, + // Block 0x7, offset 0x1c0 + 0x1c0: 0x2f8d, 0x1c1: 0x3299, 0x1c2: 0x2f92, 0x1c3: 0x329e, 0x1c4: 0x300a, 0x1c5: 0x3316, + 0x1c6: 0x300f, 0x1c7: 0x331b, 0x1c8: 0x309b, 0x1c9: 0x33a7, 0x1ca: 0x30a0, 0x1cb: 0x33ac, + 0x1cc: 0x3145, 0x1cd: 0x3456, 0x1ce: 0x314a, 0x1cf: 0x345b, 0x1d0: 0x3168, 0x1d1: 0x3479, + 0x1d2: 0x316d, 0x1d3: 0x347e, 0x1d4: 0x31db, 0x1d5: 0x34f1, 0x1d6: 0x31e0, 0x1d7: 0x34f6, + 0x1d8: 0x3186, 0x1d9: 0x3497, 0x1da: 0x319f, 0x1db: 0x34b5, + 0x1de: 0x305a, 0x1df: 0x3366, + 0x1e6: 0x4692, 0x1e7: 0x4723, 0x1e8: 0x46ba, 0x1e9: 0x474b, + 0x1ea: 0x395f, 0x1eb: 0x3aee, 0x1ec: 0x393c, 0x1ed: 0x3acb, 0x1ee: 0x46d8, 0x1ef: 0x4769, + 0x1f0: 0x3958, 0x1f1: 0x3ae7, 0x1f2: 0x3244, 0x1f3: 0x355f, + // Block 0x8, offset 0x200 + 0x200: 0x9932, 0x201: 0x9932, 0x202: 0x9932, 0x203: 0x9932, 0x204: 0x9932, 0x205: 0x8132, + 0x206: 0x9932, 0x207: 0x9932, 0x208: 0x9932, 0x209: 0x9932, 0x20a: 0x9932, 0x20b: 0x9932, + 0x20c: 0x9932, 0x20d: 0x8132, 0x20e: 0x8132, 0x20f: 0x9932, 0x210: 0x8132, 0x211: 0x9932, + 0x212: 0x8132, 0x213: 0x9932, 0x214: 0x9932, 0x215: 0x8133, 0x216: 0x812d, 0x217: 0x812d, + 0x218: 0x812d, 0x219: 0x812d, 0x21a: 0x8133, 0x21b: 0x992b, 0x21c: 0x812d, 0x21d: 0x812d, + 0x21e: 0x812d, 0x21f: 0x812d, 0x220: 0x812d, 0x221: 0x8129, 0x222: 0x8129, 0x223: 0x992d, + 0x224: 0x992d, 0x225: 0x992d, 0x226: 0x992d, 0x227: 0x9929, 0x228: 0x9929, 0x229: 0x812d, + 0x22a: 0x812d, 0x22b: 0x812d, 0x22c: 0x812d, 0x22d: 0x992d, 0x22e: 0x992d, 0x22f: 0x812d, + 0x230: 0x992d, 0x231: 0x992d, 0x232: 0x812d, 0x233: 0x812d, 0x234: 0x8101, 0x235: 0x8101, + 0x236: 0x8101, 0x237: 0x8101, 0x238: 0x9901, 0x239: 0x812d, 0x23a: 0x812d, 0x23b: 0x812d, + 0x23c: 0x812d, 0x23d: 0x8132, 0x23e: 0x8132, 0x23f: 0x8132, + // Block 0x9, offset 0x240 + 0x240: 0x49ae, 0x241: 0x49b3, 0x242: 0x9932, 0x243: 0x49b8, 0x244: 0x4a71, 0x245: 0x9936, + 0x246: 0x8132, 0x247: 0x812d, 0x248: 0x812d, 0x249: 0x812d, 0x24a: 0x8132, 0x24b: 0x8132, + 0x24c: 0x8132, 0x24d: 0x812d, 0x24e: 0x812d, 0x250: 0x8132, 0x251: 0x8132, + 0x252: 0x8132, 0x253: 0x812d, 0x254: 0x812d, 0x255: 0x812d, 0x256: 0x812d, 0x257: 0x8132, + 0x258: 0x8133, 0x259: 0x812d, 0x25a: 0x812d, 0x25b: 0x8132, 0x25c: 0x8134, 0x25d: 0x8135, + 0x25e: 0x8135, 0x25f: 0x8134, 0x260: 0x8135, 0x261: 0x8135, 0x262: 0x8134, 0x263: 0x8132, + 0x264: 0x8132, 0x265: 0x8132, 0x266: 0x8132, 0x267: 0x8132, 0x268: 0x8132, 0x269: 0x8132, + 0x26a: 0x8132, 0x26b: 0x8132, 0x26c: 0x8132, 0x26d: 0x8132, 0x26e: 0x8132, 0x26f: 0x8132, + 0x274: 0x0170, + 0x27a: 0x42a5, + 0x27e: 0x0037, + // Block 0xa, offset 0x280 + 0x284: 0x425a, 0x285: 0x447b, + 0x286: 0x35e9, 0x287: 0x00ce, 0x288: 0x3607, 0x289: 0x3613, 0x28a: 0x3625, + 0x28c: 0x3643, 0x28e: 0x3655, 0x28f: 0x3673, 0x290: 0x3e08, 0x291: 0xa000, + 0x295: 0xa000, 0x297: 0xa000, + 0x299: 0xa000, + 0x29f: 0xa000, 0x2a1: 0xa000, + 0x2a5: 0xa000, 0x2a9: 0xa000, + 0x2aa: 0x3637, 0x2ab: 0x3667, 0x2ac: 0x47fe, 0x2ad: 0x3697, 0x2ae: 0x4828, 0x2af: 0x36a9, + 0x2b0: 0x3e70, 0x2b1: 0xa000, 0x2b5: 0xa000, + 0x2b7: 0xa000, 0x2b9: 0xa000, + 0x2bf: 0xa000, + // Block 0xb, offset 0x2c0 + 0x2c1: 0xa000, 0x2c5: 0xa000, + 0x2c9: 0xa000, 0x2ca: 0x4840, 0x2cb: 0x485e, + 0x2cc: 0x36c7, 0x2cd: 0x36df, 0x2ce: 0x4876, 0x2d0: 0x01be, 0x2d1: 0x01d0, + 0x2d2: 0x01ac, 0x2d3: 0x430c, 0x2d4: 0x4312, 0x2d5: 0x01fa, 0x2d6: 0x01e8, + 0x2f0: 0x01d6, 0x2f1: 0x01eb, 0x2f2: 0x01ee, 0x2f4: 0x0188, 0x2f5: 0x01c7, + 0x2f9: 0x01a6, + // Block 0xc, offset 0x300 + 0x300: 0x3721, 0x301: 0x372d, 0x303: 0x371b, + 0x306: 0xa000, 0x307: 0x3709, + 0x30c: 0x375d, 0x30d: 0x3745, 0x30e: 0x376f, 0x310: 0xa000, + 0x313: 0xa000, 0x315: 0xa000, 0x316: 0xa000, 0x317: 0xa000, + 0x318: 0xa000, 0x319: 0x3751, 0x31a: 0xa000, + 0x31e: 0xa000, 0x323: 0xa000, + 0x327: 0xa000, + 0x32b: 0xa000, 0x32d: 0xa000, + 0x330: 0xa000, 0x333: 0xa000, 0x335: 0xa000, + 0x336: 0xa000, 0x337: 0xa000, 0x338: 0xa000, 0x339: 0x37d5, 0x33a: 0xa000, + 0x33e: 0xa000, + // Block 0xd, offset 0x340 + 0x341: 0x3733, 0x342: 0x37b7, + 0x350: 0x370f, 0x351: 0x3793, + 0x352: 0x3715, 0x353: 0x3799, 0x356: 0x3727, 0x357: 0x37ab, + 0x358: 0xa000, 0x359: 0xa000, 0x35a: 0x3829, 0x35b: 0x382f, 0x35c: 0x3739, 0x35d: 0x37bd, + 0x35e: 0x373f, 0x35f: 0x37c3, 0x362: 0x374b, 0x363: 0x37cf, + 0x364: 0x3757, 0x365: 0x37db, 0x366: 0x3763, 0x367: 0x37e7, 0x368: 0xa000, 0x369: 0xa000, + 0x36a: 0x3835, 0x36b: 0x383b, 0x36c: 0x378d, 0x36d: 0x3811, 0x36e: 0x3769, 0x36f: 0x37ed, + 0x370: 0x3775, 0x371: 0x37f9, 0x372: 0x377b, 0x373: 0x37ff, 0x374: 0x3781, 0x375: 0x3805, + 0x378: 0x3787, 0x379: 0x380b, + // Block 0xe, offset 0x380 + 0x387: 0x1d61, + 0x391: 0x812d, + 0x392: 0x8132, 0x393: 0x8132, 0x394: 0x8132, 0x395: 0x8132, 0x396: 0x812d, 0x397: 0x8132, + 0x398: 0x8132, 0x399: 0x8132, 0x39a: 0x812e, 0x39b: 0x812d, 0x39c: 0x8132, 0x39d: 0x8132, + 0x39e: 0x8132, 0x39f: 0x8132, 0x3a0: 0x8132, 0x3a1: 0x8132, 0x3a2: 0x812d, 0x3a3: 0x812d, + 0x3a4: 0x812d, 0x3a5: 0x812d, 0x3a6: 0x812d, 0x3a7: 0x812d, 0x3a8: 0x8132, 0x3a9: 0x8132, + 0x3aa: 0x812d, 0x3ab: 0x8132, 0x3ac: 0x8132, 0x3ad: 0x812e, 0x3ae: 0x8131, 0x3af: 0x8132, + 0x3b0: 0x8105, 0x3b1: 0x8106, 0x3b2: 0x8107, 0x3b3: 0x8108, 0x3b4: 0x8109, 0x3b5: 0x810a, + 0x3b6: 0x810b, 0x3b7: 0x810c, 0x3b8: 0x810d, 0x3b9: 0x810e, 0x3ba: 0x810e, 0x3bb: 0x810f, + 0x3bc: 0x8110, 0x3bd: 0x8111, 0x3bf: 0x8112, + // Block 0xf, offset 0x3c0 + 0x3c8: 0xa000, 0x3ca: 0xa000, 0x3cb: 0x8116, + 0x3cc: 0x8117, 0x3cd: 0x8118, 0x3ce: 0x8119, 0x3cf: 0x811a, 0x3d0: 0x811b, 0x3d1: 0x811c, + 0x3d2: 0x811d, 0x3d3: 0x9932, 0x3d4: 0x9932, 0x3d5: 0x992d, 0x3d6: 0x812d, 0x3d7: 0x8132, + 0x3d8: 0x8132, 0x3d9: 0x8132, 0x3da: 0x8132, 0x3db: 0x8132, 0x3dc: 0x812d, 0x3dd: 0x8132, + 0x3de: 0x8132, 0x3df: 0x812d, + 0x3f0: 0x811e, 0x3f5: 0x1d84, + 0x3f6: 0x2013, 0x3f7: 0x204f, 0x3f8: 0x204a, + // Block 0x10, offset 0x400 + 0x405: 0xa000, + 0x406: 0x2d26, 0x407: 0xa000, 0x408: 0x2d2e, 0x409: 0xa000, 0x40a: 0x2d36, 0x40b: 0xa000, + 0x40c: 0x2d3e, 0x40d: 0xa000, 0x40e: 0x2d46, 0x411: 0xa000, + 0x412: 0x2d4e, + 0x434: 0x8102, 0x435: 0x9900, + 0x43a: 0xa000, 0x43b: 0x2d56, + 0x43c: 0xa000, 0x43d: 0x2d5e, 0x43e: 0xa000, 0x43f: 0xa000, + // Block 0x11, offset 0x440 + 0x440: 0x0069, 0x441: 0x006b, 0x442: 0x006f, 0x443: 0x0083, 0x444: 0x00f5, 0x445: 0x00f8, + 0x446: 0x0413, 0x447: 0x0085, 0x448: 0x0089, 0x449: 0x008b, 0x44a: 0x0104, 0x44b: 0x0107, + 0x44c: 0x010a, 0x44d: 0x008f, 0x44f: 0x0097, 0x450: 0x009b, 0x451: 0x00e0, + 0x452: 0x009f, 0x453: 0x00fe, 0x454: 0x0417, 0x455: 0x041b, 0x456: 0x00a1, 0x457: 0x00a9, + 0x458: 0x00ab, 0x459: 0x0423, 0x45a: 0x012b, 0x45b: 0x00ad, 0x45c: 0x0427, 0x45d: 0x01be, + 0x45e: 0x01c1, 0x45f: 0x01c4, 0x460: 0x01fa, 0x461: 0x01fd, 0x462: 0x0093, 0x463: 0x00a5, + 0x464: 0x00ab, 0x465: 0x00ad, 0x466: 0x01be, 0x467: 0x01c1, 0x468: 0x01eb, 0x469: 0x01fa, + 0x46a: 0x01fd, + 0x478: 0x020c, + // Block 0x12, offset 0x480 + 0x49b: 0x00fb, 0x49c: 0x0087, 0x49d: 0x0101, + 0x49e: 0x00d4, 0x49f: 0x010a, 0x4a0: 0x008d, 0x4a1: 0x010d, 0x4a2: 0x0110, 0x4a3: 0x0116, + 0x4a4: 0x011c, 0x4a5: 0x011f, 0x4a6: 0x0122, 0x4a7: 0x042b, 0x4a8: 0x016a, 0x4a9: 0x0128, + 0x4aa: 0x042f, 0x4ab: 0x016d, 0x4ac: 0x0131, 0x4ad: 0x012e, 0x4ae: 0x0134, 0x4af: 0x0137, + 0x4b0: 0x013a, 0x4b1: 0x013d, 0x4b2: 0x0140, 0x4b3: 0x014c, 0x4b4: 0x014f, 0x4b5: 0x00ec, + 0x4b6: 0x0152, 0x4b7: 0x0155, 0x4b8: 0x041f, 0x4b9: 0x0158, 0x4ba: 0x015b, 0x4bb: 0x00b5, + 0x4bc: 0x015e, 0x4bd: 0x0161, 0x4be: 0x0164, 0x4bf: 0x01d0, + // Block 0x13, offset 0x4c0 + 0x4c0: 0x2f97, 0x4c1: 0x32a3, 0x4c2: 0x2fa1, 0x4c3: 0x32ad, 0x4c4: 0x2fa6, 0x4c5: 0x32b2, + 0x4c6: 0x2fab, 0x4c7: 0x32b7, 0x4c8: 0x38cc, 0x4c9: 0x3a5b, 0x4ca: 0x2fc4, 0x4cb: 0x32d0, + 0x4cc: 0x2fce, 0x4cd: 0x32da, 0x4ce: 0x2fdd, 0x4cf: 0x32e9, 0x4d0: 0x2fd3, 0x4d1: 0x32df, + 0x4d2: 0x2fd8, 0x4d3: 0x32e4, 0x4d4: 0x38ef, 0x4d5: 0x3a7e, 0x4d6: 0x38f6, 0x4d7: 0x3a85, + 0x4d8: 0x3019, 0x4d9: 0x3325, 0x4da: 0x301e, 0x4db: 0x332a, 0x4dc: 0x3904, 0x4dd: 0x3a93, + 0x4de: 0x3023, 0x4df: 0x332f, 0x4e0: 0x3032, 0x4e1: 0x333e, 0x4e2: 0x3050, 0x4e3: 0x335c, + 0x4e4: 0x305f, 0x4e5: 0x336b, 0x4e6: 0x3055, 0x4e7: 0x3361, 0x4e8: 0x3064, 0x4e9: 0x3370, + 0x4ea: 0x3069, 0x4eb: 0x3375, 0x4ec: 0x30af, 0x4ed: 0x33bb, 0x4ee: 0x390b, 0x4ef: 0x3a9a, + 0x4f0: 0x30b9, 0x4f1: 0x33ca, 0x4f2: 0x30c3, 0x4f3: 0x33d4, 0x4f4: 0x30cd, 0x4f5: 0x33de, + 0x4f6: 0x46c4, 0x4f7: 0x4755, 0x4f8: 0x3912, 0x4f9: 0x3aa1, 0x4fa: 0x30e6, 0x4fb: 0x33f7, + 0x4fc: 0x30e1, 0x4fd: 0x33f2, 0x4fe: 0x30eb, 0x4ff: 0x33fc, + // Block 0x14, offset 0x500 + 0x500: 0x30f0, 0x501: 0x3401, 0x502: 0x30f5, 0x503: 0x3406, 0x504: 0x3109, 0x505: 0x341a, + 0x506: 0x3113, 0x507: 0x3424, 0x508: 0x3122, 0x509: 0x3433, 0x50a: 0x311d, 0x50b: 0x342e, + 0x50c: 0x3935, 0x50d: 0x3ac4, 0x50e: 0x3943, 0x50f: 0x3ad2, 0x510: 0x394a, 0x511: 0x3ad9, + 0x512: 0x3951, 0x513: 0x3ae0, 0x514: 0x314f, 0x515: 0x3460, 0x516: 0x3154, 0x517: 0x3465, + 0x518: 0x315e, 0x519: 0x346f, 0x51a: 0x46f1, 0x51b: 0x4782, 0x51c: 0x3997, 0x51d: 0x3b26, + 0x51e: 0x3177, 0x51f: 0x3488, 0x520: 0x3181, 0x521: 0x3492, 0x522: 0x4700, 0x523: 0x4791, + 0x524: 0x399e, 0x525: 0x3b2d, 0x526: 0x39a5, 0x527: 0x3b34, 0x528: 0x39ac, 0x529: 0x3b3b, + 0x52a: 0x3190, 0x52b: 0x34a1, 0x52c: 0x319a, 0x52d: 0x34b0, 0x52e: 0x31ae, 0x52f: 0x34c4, + 0x530: 0x31a9, 0x531: 0x34bf, 0x532: 0x31ea, 0x533: 0x3500, 0x534: 0x31f9, 0x535: 0x350f, + 0x536: 0x31f4, 0x537: 0x350a, 0x538: 0x39b3, 0x539: 0x3b42, 0x53a: 0x39ba, 0x53b: 0x3b49, + 0x53c: 0x31fe, 0x53d: 0x3514, 0x53e: 0x3203, 0x53f: 0x3519, + // Block 0x15, offset 0x540 + 0x540: 0x3208, 0x541: 0x351e, 0x542: 0x320d, 0x543: 0x3523, 0x544: 0x321c, 0x545: 0x3532, + 0x546: 0x3217, 0x547: 0x352d, 0x548: 0x3221, 0x549: 0x353c, 0x54a: 0x3226, 0x54b: 0x3541, + 0x54c: 0x322b, 0x54d: 0x3546, 0x54e: 0x3249, 0x54f: 0x3564, 0x550: 0x3262, 0x551: 0x3582, + 0x552: 0x3271, 0x553: 0x3591, 0x554: 0x3276, 0x555: 0x3596, 0x556: 0x337a, 0x557: 0x34a6, + 0x558: 0x3537, 0x559: 0x3573, 0x55a: 0x1be0, 0x55b: 0x42d7, + 0x560: 0x46a1, 0x561: 0x4732, 0x562: 0x2f83, 0x563: 0x328f, + 0x564: 0x3878, 0x565: 0x3a07, 0x566: 0x3871, 0x567: 0x3a00, 0x568: 0x3886, 0x569: 0x3a15, + 0x56a: 0x387f, 0x56b: 0x3a0e, 0x56c: 0x38be, 0x56d: 0x3a4d, 0x56e: 0x3894, 0x56f: 0x3a23, + 0x570: 0x388d, 0x571: 0x3a1c, 0x572: 0x38a2, 0x573: 0x3a31, 0x574: 0x389b, 0x575: 0x3a2a, + 0x576: 0x38c5, 0x577: 0x3a54, 0x578: 0x46b5, 0x579: 0x4746, 0x57a: 0x3000, 0x57b: 0x330c, + 0x57c: 0x2fec, 0x57d: 0x32f8, 0x57e: 0x38da, 0x57f: 0x3a69, + // Block 0x16, offset 0x580 + 0x580: 0x38d3, 0x581: 0x3a62, 0x582: 0x38e8, 0x583: 0x3a77, 0x584: 0x38e1, 0x585: 0x3a70, + 0x586: 0x38fd, 0x587: 0x3a8c, 0x588: 0x3091, 0x589: 0x339d, 0x58a: 0x30a5, 0x58b: 0x33b1, + 0x58c: 0x46e7, 0x58d: 0x4778, 0x58e: 0x3136, 0x58f: 0x3447, 0x590: 0x3920, 0x591: 0x3aaf, + 0x592: 0x3919, 0x593: 0x3aa8, 0x594: 0x392e, 0x595: 0x3abd, 0x596: 0x3927, 0x597: 0x3ab6, + 0x598: 0x3989, 0x599: 0x3b18, 0x59a: 0x396d, 0x59b: 0x3afc, 0x59c: 0x3966, 0x59d: 0x3af5, + 0x59e: 0x397b, 0x59f: 0x3b0a, 0x5a0: 0x3974, 0x5a1: 0x3b03, 0x5a2: 0x3982, 0x5a3: 0x3b11, + 0x5a4: 0x31e5, 0x5a5: 0x34fb, 0x5a6: 0x31c7, 0x5a7: 0x34dd, 0x5a8: 0x39e4, 0x5a9: 0x3b73, + 0x5aa: 0x39dd, 0x5ab: 0x3b6c, 0x5ac: 0x39f2, 0x5ad: 0x3b81, 0x5ae: 0x39eb, 0x5af: 0x3b7a, + 0x5b0: 0x39f9, 0x5b1: 0x3b88, 0x5b2: 0x3230, 0x5b3: 0x354b, 0x5b4: 0x3258, 0x5b5: 0x3578, + 0x5b6: 0x3253, 0x5b7: 0x356e, 0x5b8: 0x323f, 0x5b9: 0x355a, + // Block 0x17, offset 0x5c0 + 0x5c0: 0x4804, 0x5c1: 0x480a, 0x5c2: 0x491e, 0x5c3: 0x4936, 0x5c4: 0x4926, 0x5c5: 0x493e, + 0x5c6: 0x492e, 0x5c7: 0x4946, 0x5c8: 0x47aa, 0x5c9: 0x47b0, 0x5ca: 0x488e, 0x5cb: 0x48a6, + 0x5cc: 0x4896, 0x5cd: 0x48ae, 0x5ce: 0x489e, 0x5cf: 0x48b6, 0x5d0: 0x4816, 0x5d1: 0x481c, + 0x5d2: 0x3db8, 0x5d3: 0x3dc8, 0x5d4: 0x3dc0, 0x5d5: 0x3dd0, + 0x5d8: 0x47b6, 0x5d9: 0x47bc, 0x5da: 0x3ce8, 0x5db: 0x3cf8, 0x5dc: 0x3cf0, 0x5dd: 0x3d00, + 0x5e0: 0x482e, 0x5e1: 0x4834, 0x5e2: 0x494e, 0x5e3: 0x4966, + 0x5e4: 0x4956, 0x5e5: 0x496e, 0x5e6: 0x495e, 0x5e7: 0x4976, 0x5e8: 0x47c2, 0x5e9: 0x47c8, + 0x5ea: 0x48be, 0x5eb: 0x48d6, 0x5ec: 0x48c6, 0x5ed: 0x48de, 0x5ee: 0x48ce, 0x5ef: 0x48e6, + 0x5f0: 0x4846, 0x5f1: 0x484c, 0x5f2: 0x3e18, 0x5f3: 0x3e30, 0x5f4: 0x3e20, 0x5f5: 0x3e38, + 0x5f6: 0x3e28, 0x5f7: 0x3e40, 0x5f8: 0x47ce, 0x5f9: 0x47d4, 0x5fa: 0x3d18, 0x5fb: 0x3d30, + 0x5fc: 0x3d20, 0x5fd: 0x3d38, 0x5fe: 0x3d28, 0x5ff: 0x3d40, + // Block 0x18, offset 0x600 + 0x600: 0x4852, 0x601: 0x4858, 0x602: 0x3e48, 0x603: 0x3e58, 0x604: 0x3e50, 0x605: 0x3e60, + 0x608: 0x47da, 0x609: 0x47e0, 0x60a: 0x3d48, 0x60b: 0x3d58, + 0x60c: 0x3d50, 0x60d: 0x3d60, 0x610: 0x4864, 0x611: 0x486a, + 0x612: 0x3e80, 0x613: 0x3e98, 0x614: 0x3e88, 0x615: 0x3ea0, 0x616: 0x3e90, 0x617: 0x3ea8, + 0x619: 0x47e6, 0x61b: 0x3d68, 0x61d: 0x3d70, + 0x61f: 0x3d78, 0x620: 0x487c, 0x621: 0x4882, 0x622: 0x497e, 0x623: 0x4996, + 0x624: 0x4986, 0x625: 0x499e, 0x626: 0x498e, 0x627: 0x49a6, 0x628: 0x47ec, 0x629: 0x47f2, + 0x62a: 0x48ee, 0x62b: 0x4906, 0x62c: 0x48f6, 0x62d: 0x490e, 0x62e: 0x48fe, 0x62f: 0x4916, + 0x630: 0x47f8, 0x631: 0x431e, 0x632: 0x3691, 0x633: 0x4324, 0x634: 0x4822, 0x635: 0x432a, + 0x636: 0x36a3, 0x637: 0x4330, 0x638: 0x36c1, 0x639: 0x4336, 0x63a: 0x36d9, 0x63b: 0x433c, + 0x63c: 0x4870, 0x63d: 0x4342, + // Block 0x19, offset 0x640 + 0x640: 0x3da0, 0x641: 0x3da8, 0x642: 0x4184, 0x643: 0x41a2, 0x644: 0x418e, 0x645: 0x41ac, + 0x646: 0x4198, 0x647: 0x41b6, 0x648: 0x3cd8, 0x649: 0x3ce0, 0x64a: 0x40d0, 0x64b: 0x40ee, + 0x64c: 0x40da, 0x64d: 0x40f8, 0x64e: 0x40e4, 0x64f: 0x4102, 0x650: 0x3de8, 0x651: 0x3df0, + 0x652: 0x41c0, 0x653: 0x41de, 0x654: 0x41ca, 0x655: 0x41e8, 0x656: 0x41d4, 0x657: 0x41f2, + 0x658: 0x3d08, 0x659: 0x3d10, 0x65a: 0x410c, 0x65b: 0x412a, 0x65c: 0x4116, 0x65d: 0x4134, + 0x65e: 0x4120, 0x65f: 0x413e, 0x660: 0x3ec0, 0x661: 0x3ec8, 0x662: 0x41fc, 0x663: 0x421a, + 0x664: 0x4206, 0x665: 0x4224, 0x666: 0x4210, 0x667: 0x422e, 0x668: 0x3d80, 0x669: 0x3d88, + 0x66a: 0x4148, 0x66b: 0x4166, 0x66c: 0x4152, 0x66d: 0x4170, 0x66e: 0x415c, 0x66f: 0x417a, + 0x670: 0x3685, 0x671: 0x367f, 0x672: 0x3d90, 0x673: 0x368b, 0x674: 0x3d98, + 0x676: 0x4810, 0x677: 0x3db0, 0x678: 0x35f5, 0x679: 0x35ef, 0x67a: 0x35e3, 0x67b: 0x42ee, + 0x67c: 0x35fb, 0x67d: 0x4287, 0x67e: 0x01d3, 0x67f: 0x4287, + // Block 0x1a, offset 0x680 + 0x680: 0x42a0, 0x681: 0x4482, 0x682: 0x3dd8, 0x683: 0x369d, 0x684: 0x3de0, + 0x686: 0x483a, 0x687: 0x3df8, 0x688: 0x3601, 0x689: 0x42f4, 0x68a: 0x360d, 0x68b: 0x42fa, + 0x68c: 0x3619, 0x68d: 0x4489, 0x68e: 0x4490, 0x68f: 0x4497, 0x690: 0x36b5, 0x691: 0x36af, + 0x692: 0x3e00, 0x693: 0x44e4, 0x696: 0x36bb, 0x697: 0x3e10, + 0x698: 0x3631, 0x699: 0x362b, 0x69a: 0x361f, 0x69b: 0x4300, 0x69d: 0x449e, + 0x69e: 0x44a5, 0x69f: 0x44ac, 0x6a0: 0x36eb, 0x6a1: 0x36e5, 0x6a2: 0x3e68, 0x6a3: 0x44ec, + 0x6a4: 0x36cd, 0x6a5: 0x36d3, 0x6a6: 0x36f1, 0x6a7: 0x3e78, 0x6a8: 0x3661, 0x6a9: 0x365b, + 0x6aa: 0x364f, 0x6ab: 0x430c, 0x6ac: 0x3649, 0x6ad: 0x4474, 0x6ae: 0x447b, 0x6af: 0x0081, + 0x6b2: 0x3eb0, 0x6b3: 0x36f7, 0x6b4: 0x3eb8, + 0x6b6: 0x4888, 0x6b7: 0x3ed0, 0x6b8: 0x363d, 0x6b9: 0x4306, 0x6ba: 0x366d, 0x6bb: 0x4318, + 0x6bc: 0x3679, 0x6bd: 0x425a, 0x6be: 0x428c, + // Block 0x1b, offset 0x6c0 + 0x6c0: 0x1bd8, 0x6c1: 0x1bdc, 0x6c2: 0x0047, 0x6c3: 0x1c54, 0x6c5: 0x1be8, + 0x6c6: 0x1bec, 0x6c7: 0x00e9, 0x6c9: 0x1c58, 0x6ca: 0x008f, 0x6cb: 0x0051, + 0x6cc: 0x0051, 0x6cd: 0x0051, 0x6ce: 0x0091, 0x6cf: 0x00da, 0x6d0: 0x0053, 0x6d1: 0x0053, + 0x6d2: 0x0059, 0x6d3: 0x0099, 0x6d5: 0x005d, 0x6d6: 0x198d, + 0x6d9: 0x0061, 0x6da: 0x0063, 0x6db: 0x0065, 0x6dc: 0x0065, 0x6dd: 0x0065, + 0x6e0: 0x199f, 0x6e1: 0x1bc8, 0x6e2: 0x19a8, + 0x6e4: 0x0075, 0x6e6: 0x01b8, 0x6e8: 0x0075, + 0x6ea: 0x0057, 0x6eb: 0x42d2, 0x6ec: 0x0045, 0x6ed: 0x0047, 0x6ef: 0x008b, + 0x6f0: 0x004b, 0x6f1: 0x004d, 0x6f3: 0x005b, 0x6f4: 0x009f, 0x6f5: 0x0215, + 0x6f6: 0x0218, 0x6f7: 0x021b, 0x6f8: 0x021e, 0x6f9: 0x0093, 0x6fb: 0x1b98, + 0x6fc: 0x01e8, 0x6fd: 0x01c1, 0x6fe: 0x0179, 0x6ff: 0x01a0, + // Block 0x1c, offset 0x700 + 0x700: 0x0463, 0x705: 0x0049, + 0x706: 0x0089, 0x707: 0x008b, 0x708: 0x0093, 0x709: 0x0095, + 0x710: 0x222e, 0x711: 0x223a, + 0x712: 0x22ee, 0x713: 0x2216, 0x714: 0x229a, 0x715: 0x2222, 0x716: 0x22a0, 0x717: 0x22b8, + 0x718: 0x22c4, 0x719: 0x2228, 0x71a: 0x22ca, 0x71b: 0x2234, 0x71c: 0x22be, 0x71d: 0x22d0, + 0x71e: 0x22d6, 0x71f: 0x1cbc, 0x720: 0x0053, 0x721: 0x195a, 0x722: 0x1ba4, 0x723: 0x1963, + 0x724: 0x006d, 0x725: 0x19ab, 0x726: 0x1bd0, 0x727: 0x1d48, 0x728: 0x1966, 0x729: 0x0071, + 0x72a: 0x19b7, 0x72b: 0x1bd4, 0x72c: 0x0059, 0x72d: 0x0047, 0x72e: 0x0049, 0x72f: 0x005b, + 0x730: 0x0093, 0x731: 0x19e4, 0x732: 0x1c18, 0x733: 0x19ed, 0x734: 0x00ad, 0x735: 0x1a62, + 0x736: 0x1c4c, 0x737: 0x1d5c, 0x738: 0x19f0, 0x739: 0x00b1, 0x73a: 0x1a65, 0x73b: 0x1c50, + 0x73c: 0x0099, 0x73d: 0x0087, 0x73e: 0x0089, 0x73f: 0x009b, + // Block 0x1d, offset 0x740 + 0x741: 0x3c06, 0x743: 0xa000, 0x744: 0x3c0d, 0x745: 0xa000, + 0x747: 0x3c14, 0x748: 0xa000, 0x749: 0x3c1b, + 0x74d: 0xa000, + 0x760: 0x2f65, 0x761: 0xa000, 0x762: 0x3c29, + 0x764: 0xa000, 0x765: 0xa000, + 0x76d: 0x3c22, 0x76e: 0x2f60, 0x76f: 0x2f6a, + 0x770: 0x3c30, 0x771: 0x3c37, 0x772: 0xa000, 0x773: 0xa000, 0x774: 0x3c3e, 0x775: 0x3c45, + 0x776: 0xa000, 0x777: 0xa000, 0x778: 0x3c4c, 0x779: 0x3c53, 0x77a: 0xa000, 0x77b: 0xa000, + 0x77c: 0xa000, 0x77d: 0xa000, + // Block 0x1e, offset 0x780 + 0x780: 0x3c5a, 0x781: 0x3c61, 0x782: 0xa000, 0x783: 0xa000, 0x784: 0x3c76, 0x785: 0x3c7d, + 0x786: 0xa000, 0x787: 0xa000, 0x788: 0x3c84, 0x789: 0x3c8b, + 0x791: 0xa000, + 0x792: 0xa000, + 0x7a2: 0xa000, + 0x7a8: 0xa000, 0x7a9: 0xa000, + 0x7ab: 0xa000, 0x7ac: 0x3ca0, 0x7ad: 0x3ca7, 0x7ae: 0x3cae, 0x7af: 0x3cb5, + 0x7b2: 0xa000, 0x7b3: 0xa000, 0x7b4: 0xa000, 0x7b5: 0xa000, + // Block 0x1f, offset 0x7c0 + 0x7e0: 0x0023, 0x7e1: 0x0025, 0x7e2: 0x0027, 0x7e3: 0x0029, + 0x7e4: 0x002b, 0x7e5: 0x002d, 0x7e6: 0x002f, 0x7e7: 0x0031, 0x7e8: 0x0033, 0x7e9: 0x1882, + 0x7ea: 0x1885, 0x7eb: 0x1888, 0x7ec: 0x188b, 0x7ed: 0x188e, 0x7ee: 0x1891, 0x7ef: 0x1894, + 0x7f0: 0x1897, 0x7f1: 0x189a, 0x7f2: 0x189d, 0x7f3: 0x18a6, 0x7f4: 0x1a68, 0x7f5: 0x1a6c, + 0x7f6: 0x1a70, 0x7f7: 0x1a74, 0x7f8: 0x1a78, 0x7f9: 0x1a7c, 0x7fa: 0x1a80, 0x7fb: 0x1a84, + 0x7fc: 0x1a88, 0x7fd: 0x1c80, 0x7fe: 0x1c85, 0x7ff: 0x1c8a, + // Block 0x20, offset 0x800 + 0x800: 0x1c8f, 0x801: 0x1c94, 0x802: 0x1c99, 0x803: 0x1c9e, 0x804: 0x1ca3, 0x805: 0x1ca8, + 0x806: 0x1cad, 0x807: 0x1cb2, 0x808: 0x187f, 0x809: 0x18a3, 0x80a: 0x18c7, 0x80b: 0x18eb, + 0x80c: 0x190f, 0x80d: 0x1918, 0x80e: 0x191e, 0x80f: 0x1924, 0x810: 0x192a, 0x811: 0x1b60, + 0x812: 0x1b64, 0x813: 0x1b68, 0x814: 0x1b6c, 0x815: 0x1b70, 0x816: 0x1b74, 0x817: 0x1b78, + 0x818: 0x1b7c, 0x819: 0x1b80, 0x81a: 0x1b84, 0x81b: 0x1b88, 0x81c: 0x1af4, 0x81d: 0x1af8, + 0x81e: 0x1afc, 0x81f: 0x1b00, 0x820: 0x1b04, 0x821: 0x1b08, 0x822: 0x1b0c, 0x823: 0x1b10, + 0x824: 0x1b14, 0x825: 0x1b18, 0x826: 0x1b1c, 0x827: 0x1b20, 0x828: 0x1b24, 0x829: 0x1b28, + 0x82a: 0x1b2c, 0x82b: 0x1b30, 0x82c: 0x1b34, 0x82d: 0x1b38, 0x82e: 0x1b3c, 0x82f: 0x1b40, + 0x830: 0x1b44, 0x831: 0x1b48, 0x832: 0x1b4c, 0x833: 0x1b50, 0x834: 0x1b54, 0x835: 0x1b58, + 0x836: 0x0043, 0x837: 0x0045, 0x838: 0x0047, 0x839: 0x0049, 0x83a: 0x004b, 0x83b: 0x004d, + 0x83c: 0x004f, 0x83d: 0x0051, 0x83e: 0x0053, 0x83f: 0x0055, + // Block 0x21, offset 0x840 + 0x840: 0x06bf, 0x841: 0x06e3, 0x842: 0x06ef, 0x843: 0x06ff, 0x844: 0x0707, 0x845: 0x0713, + 0x846: 0x071b, 0x847: 0x0723, 0x848: 0x072f, 0x849: 0x0783, 0x84a: 0x079b, 0x84b: 0x07ab, + 0x84c: 0x07bb, 0x84d: 0x07cb, 0x84e: 0x07db, 0x84f: 0x07fb, 0x850: 0x07ff, 0x851: 0x0803, + 0x852: 0x0837, 0x853: 0x085f, 0x854: 0x086f, 0x855: 0x0877, 0x856: 0x087b, 0x857: 0x0887, + 0x858: 0x08a3, 0x859: 0x08a7, 0x85a: 0x08bf, 0x85b: 0x08c3, 0x85c: 0x08cb, 0x85d: 0x08db, + 0x85e: 0x0977, 0x85f: 0x098b, 0x860: 0x09cb, 0x861: 0x09df, 0x862: 0x09e7, 0x863: 0x09eb, + 0x864: 0x09fb, 0x865: 0x0a17, 0x866: 0x0a43, 0x867: 0x0a4f, 0x868: 0x0a6f, 0x869: 0x0a7b, + 0x86a: 0x0a7f, 0x86b: 0x0a83, 0x86c: 0x0a9b, 0x86d: 0x0a9f, 0x86e: 0x0acb, 0x86f: 0x0ad7, + 0x870: 0x0adf, 0x871: 0x0ae7, 0x872: 0x0af7, 0x873: 0x0aff, 0x874: 0x0b07, 0x875: 0x0b33, + 0x876: 0x0b37, 0x877: 0x0b3f, 0x878: 0x0b43, 0x879: 0x0b4b, 0x87a: 0x0b53, 0x87b: 0x0b63, + 0x87c: 0x0b7f, 0x87d: 0x0bf7, 0x87e: 0x0c0b, 0x87f: 0x0c0f, + // Block 0x22, offset 0x880 + 0x880: 0x0c8f, 0x881: 0x0c93, 0x882: 0x0ca7, 0x883: 0x0cab, 0x884: 0x0cb3, 0x885: 0x0cbb, + 0x886: 0x0cc3, 0x887: 0x0ccf, 0x888: 0x0cf7, 0x889: 0x0d07, 0x88a: 0x0d1b, 0x88b: 0x0d8b, + 0x88c: 0x0d97, 0x88d: 0x0da7, 0x88e: 0x0db3, 0x88f: 0x0dbf, 0x890: 0x0dc7, 0x891: 0x0dcb, + 0x892: 0x0dcf, 0x893: 0x0dd3, 0x894: 0x0dd7, 0x895: 0x0e8f, 0x896: 0x0ed7, 0x897: 0x0ee3, + 0x898: 0x0ee7, 0x899: 0x0eeb, 0x89a: 0x0eef, 0x89b: 0x0ef7, 0x89c: 0x0efb, 0x89d: 0x0f0f, + 0x89e: 0x0f2b, 0x89f: 0x0f33, 0x8a0: 0x0f73, 0x8a1: 0x0f77, 0x8a2: 0x0f7f, 0x8a3: 0x0f83, + 0x8a4: 0x0f8b, 0x8a5: 0x0f8f, 0x8a6: 0x0fb3, 0x8a7: 0x0fb7, 0x8a8: 0x0fd3, 0x8a9: 0x0fd7, + 0x8aa: 0x0fdb, 0x8ab: 0x0fdf, 0x8ac: 0x0ff3, 0x8ad: 0x1017, 0x8ae: 0x101b, 0x8af: 0x101f, + 0x8b0: 0x1043, 0x8b1: 0x1083, 0x8b2: 0x1087, 0x8b3: 0x10a7, 0x8b4: 0x10b7, 0x8b5: 0x10bf, + 0x8b6: 0x10df, 0x8b7: 0x1103, 0x8b8: 0x1147, 0x8b9: 0x114f, 0x8ba: 0x1163, 0x8bb: 0x116f, + 0x8bc: 0x1177, 0x8bd: 0x117f, 0x8be: 0x1183, 0x8bf: 0x1187, + // Block 0x23, offset 0x8c0 + 0x8c0: 0x119f, 0x8c1: 0x11a3, 0x8c2: 0x11bf, 0x8c3: 0x11c7, 0x8c4: 0x11cf, 0x8c5: 0x11d3, + 0x8c6: 0x11df, 0x8c7: 0x11e7, 0x8c8: 0x11eb, 0x8c9: 0x11ef, 0x8ca: 0x11f7, 0x8cb: 0x11fb, + 0x8cc: 0x129b, 0x8cd: 0x12af, 0x8ce: 0x12e3, 0x8cf: 0x12e7, 0x8d0: 0x12ef, 0x8d1: 0x131b, + 0x8d2: 0x1323, 0x8d3: 0x132b, 0x8d4: 0x1333, 0x8d5: 0x136f, 0x8d6: 0x1373, 0x8d7: 0x137b, + 0x8d8: 0x137f, 0x8d9: 0x1383, 0x8da: 0x13af, 0x8db: 0x13b3, 0x8dc: 0x13bb, 0x8dd: 0x13cf, + 0x8de: 0x13d3, 0x8df: 0x13ef, 0x8e0: 0x13f7, 0x8e1: 0x13fb, 0x8e2: 0x141f, 0x8e3: 0x143f, + 0x8e4: 0x1453, 0x8e5: 0x1457, 0x8e6: 0x145f, 0x8e7: 0x148b, 0x8e8: 0x148f, 0x8e9: 0x149f, + 0x8ea: 0x14c3, 0x8eb: 0x14cf, 0x8ec: 0x14df, 0x8ed: 0x14f7, 0x8ee: 0x14ff, 0x8ef: 0x1503, + 0x8f0: 0x1507, 0x8f1: 0x150b, 0x8f2: 0x1517, 0x8f3: 0x151b, 0x8f4: 0x1523, 0x8f5: 0x153f, + 0x8f6: 0x1543, 0x8f7: 0x1547, 0x8f8: 0x155f, 0x8f9: 0x1563, 0x8fa: 0x156b, 0x8fb: 0x157f, + 0x8fc: 0x1583, 0x8fd: 0x1587, 0x8fe: 0x158f, 0x8ff: 0x1593, + // Block 0x24, offset 0x900 + 0x906: 0xa000, 0x90b: 0xa000, + 0x90c: 0x3f08, 0x90d: 0xa000, 0x90e: 0x3f10, 0x90f: 0xa000, 0x910: 0x3f18, 0x911: 0xa000, + 0x912: 0x3f20, 0x913: 0xa000, 0x914: 0x3f28, 0x915: 0xa000, 0x916: 0x3f30, 0x917: 0xa000, + 0x918: 0x3f38, 0x919: 0xa000, 0x91a: 0x3f40, 0x91b: 0xa000, 0x91c: 0x3f48, 0x91d: 0xa000, + 0x91e: 0x3f50, 0x91f: 0xa000, 0x920: 0x3f58, 0x921: 0xa000, 0x922: 0x3f60, + 0x924: 0xa000, 0x925: 0x3f68, 0x926: 0xa000, 0x927: 0x3f70, 0x928: 0xa000, 0x929: 0x3f78, + 0x92f: 0xa000, + 0x930: 0x3f80, 0x931: 0x3f88, 0x932: 0xa000, 0x933: 0x3f90, 0x934: 0x3f98, 0x935: 0xa000, + 0x936: 0x3fa0, 0x937: 0x3fa8, 0x938: 0xa000, 0x939: 0x3fb0, 0x93a: 0x3fb8, 0x93b: 0xa000, + 0x93c: 0x3fc0, 0x93d: 0x3fc8, + // Block 0x25, offset 0x940 + 0x954: 0x3f00, + 0x959: 0x9903, 0x95a: 0x9903, 0x95b: 0x42dc, 0x95c: 0x42e2, 0x95d: 0xa000, + 0x95e: 0x3fd0, 0x95f: 0x26b4, + 0x966: 0xa000, + 0x96b: 0xa000, 0x96c: 0x3fe0, 0x96d: 0xa000, 0x96e: 0x3fe8, 0x96f: 0xa000, + 0x970: 0x3ff0, 0x971: 0xa000, 0x972: 0x3ff8, 0x973: 0xa000, 0x974: 0x4000, 0x975: 0xa000, + 0x976: 0x4008, 0x977: 0xa000, 0x978: 0x4010, 0x979: 0xa000, 0x97a: 0x4018, 0x97b: 0xa000, + 0x97c: 0x4020, 0x97d: 0xa000, 0x97e: 0x4028, 0x97f: 0xa000, + // Block 0x26, offset 0x980 + 0x980: 0x4030, 0x981: 0xa000, 0x982: 0x4038, 0x984: 0xa000, 0x985: 0x4040, + 0x986: 0xa000, 0x987: 0x4048, 0x988: 0xa000, 0x989: 0x4050, + 0x98f: 0xa000, 0x990: 0x4058, 0x991: 0x4060, + 0x992: 0xa000, 0x993: 0x4068, 0x994: 0x4070, 0x995: 0xa000, 0x996: 0x4078, 0x997: 0x4080, + 0x998: 0xa000, 0x999: 0x4088, 0x99a: 0x4090, 0x99b: 0xa000, 0x99c: 0x4098, 0x99d: 0x40a0, + 0x9af: 0xa000, + 0x9b0: 0xa000, 0x9b1: 0xa000, 0x9b2: 0xa000, 0x9b4: 0x3fd8, + 0x9b7: 0x40a8, 0x9b8: 0x40b0, 0x9b9: 0x40b8, 0x9ba: 0x40c0, + 0x9bd: 0xa000, 0x9be: 0x40c8, 0x9bf: 0x26c9, + // Block 0x27, offset 0x9c0 + 0x9c0: 0x0367, 0x9c1: 0x032b, 0x9c2: 0x032f, 0x9c3: 0x0333, 0x9c4: 0x037b, 0x9c5: 0x0337, + 0x9c6: 0x033b, 0x9c7: 0x033f, 0x9c8: 0x0343, 0x9c9: 0x0347, 0x9ca: 0x034b, 0x9cb: 0x034f, + 0x9cc: 0x0353, 0x9cd: 0x0357, 0x9ce: 0x035b, 0x9cf: 0x49bd, 0x9d0: 0x49c3, 0x9d1: 0x49c9, + 0x9d2: 0x49cf, 0x9d3: 0x49d5, 0x9d4: 0x49db, 0x9d5: 0x49e1, 0x9d6: 0x49e7, 0x9d7: 0x49ed, + 0x9d8: 0x49f3, 0x9d9: 0x49f9, 0x9da: 0x49ff, 0x9db: 0x4a05, 0x9dc: 0x4a0b, 0x9dd: 0x4a11, + 0x9de: 0x4a17, 0x9df: 0x4a1d, 0x9e0: 0x4a23, 0x9e1: 0x4a29, 0x9e2: 0x4a2f, 0x9e3: 0x4a35, + 0x9e4: 0x03c3, 0x9e5: 0x035f, 0x9e6: 0x0363, 0x9e7: 0x03e7, 0x9e8: 0x03eb, 0x9e9: 0x03ef, + 0x9ea: 0x03f3, 0x9eb: 0x03f7, 0x9ec: 0x03fb, 0x9ed: 0x03ff, 0x9ee: 0x036b, 0x9ef: 0x0403, + 0x9f0: 0x0407, 0x9f1: 0x036f, 0x9f2: 0x0373, 0x9f3: 0x0377, 0x9f4: 0x037f, 0x9f5: 0x0383, + 0x9f6: 0x0387, 0x9f7: 0x038b, 0x9f8: 0x038f, 0x9f9: 0x0393, 0x9fa: 0x0397, 0x9fb: 0x039b, + 0x9fc: 0x039f, 0x9fd: 0x03a3, 0x9fe: 0x03a7, 0x9ff: 0x03ab, + // Block 0x28, offset 0xa00 + 0xa00: 0x03af, 0xa01: 0x03b3, 0xa02: 0x040b, 0xa03: 0x040f, 0xa04: 0x03b7, 0xa05: 0x03bb, + 0xa06: 0x03bf, 0xa07: 0x03c7, 0xa08: 0x03cb, 0xa09: 0x03cf, 0xa0a: 0x03d3, 0xa0b: 0x03d7, + 0xa0c: 0x03db, 0xa0d: 0x03df, 0xa0e: 0x03e3, + 0xa12: 0x06bf, 0xa13: 0x071b, 0xa14: 0x06cb, 0xa15: 0x097b, 0xa16: 0x06cf, 0xa17: 0x06e7, + 0xa18: 0x06d3, 0xa19: 0x0f93, 0xa1a: 0x0707, 0xa1b: 0x06db, 0xa1c: 0x06c3, 0xa1d: 0x09ff, + 0xa1e: 0x098f, 0xa1f: 0x072f, + // Block 0x29, offset 0xa40 + 0xa40: 0x2054, 0xa41: 0x205a, 0xa42: 0x2060, 0xa43: 0x2066, 0xa44: 0x206c, 0xa45: 0x2072, + 0xa46: 0x2078, 0xa47: 0x207e, 0xa48: 0x2084, 0xa49: 0x208a, 0xa4a: 0x2090, 0xa4b: 0x2096, + 0xa4c: 0x209c, 0xa4d: 0x20a2, 0xa4e: 0x2726, 0xa4f: 0x272f, 0xa50: 0x2738, 0xa51: 0x2741, + 0xa52: 0x274a, 0xa53: 0x2753, 0xa54: 0x275c, 0xa55: 0x2765, 0xa56: 0x276e, 0xa57: 0x2780, + 0xa58: 0x2789, 0xa59: 0x2792, 0xa5a: 0x279b, 0xa5b: 0x27a4, 0xa5c: 0x2777, 0xa5d: 0x2bac, + 0xa5e: 0x2aed, 0xa60: 0x20a8, 0xa61: 0x20c0, 0xa62: 0x20b4, 0xa63: 0x2108, + 0xa64: 0x20c6, 0xa65: 0x20e4, 0xa66: 0x20ae, 0xa67: 0x20de, 0xa68: 0x20ba, 0xa69: 0x20f0, + 0xa6a: 0x2120, 0xa6b: 0x213e, 0xa6c: 0x2138, 0xa6d: 0x212c, 0xa6e: 0x217a, 0xa6f: 0x210e, + 0xa70: 0x211a, 0xa71: 0x2132, 0xa72: 0x2126, 0xa73: 0x2150, 0xa74: 0x20fc, 0xa75: 0x2144, + 0xa76: 0x216e, 0xa77: 0x2156, 0xa78: 0x20ea, 0xa79: 0x20cc, 0xa7a: 0x2102, 0xa7b: 0x2114, + 0xa7c: 0x214a, 0xa7d: 0x20d2, 0xa7e: 0x2174, 0xa7f: 0x20f6, + // Block 0x2a, offset 0xa80 + 0xa80: 0x215c, 0xa81: 0x20d8, 0xa82: 0x2162, 0xa83: 0x2168, 0xa84: 0x092f, 0xa85: 0x0b03, + 0xa86: 0x0ca7, 0xa87: 0x10c7, + 0xa90: 0x1bc4, 0xa91: 0x18a9, + 0xa92: 0x18ac, 0xa93: 0x18af, 0xa94: 0x18b2, 0xa95: 0x18b5, 0xa96: 0x18b8, 0xa97: 0x18bb, + 0xa98: 0x18be, 0xa99: 0x18c1, 0xa9a: 0x18ca, 0xa9b: 0x18cd, 0xa9c: 0x18d0, 0xa9d: 0x18d3, + 0xa9e: 0x18d6, 0xa9f: 0x18d9, 0xaa0: 0x0313, 0xaa1: 0x031b, 0xaa2: 0x031f, 0xaa3: 0x0327, + 0xaa4: 0x032b, 0xaa5: 0x032f, 0xaa6: 0x0337, 0xaa7: 0x033f, 0xaa8: 0x0343, 0xaa9: 0x034b, + 0xaaa: 0x034f, 0xaab: 0x0353, 0xaac: 0x0357, 0xaad: 0x035b, 0xaae: 0x2e18, 0xaaf: 0x2e20, + 0xab0: 0x2e28, 0xab1: 0x2e30, 0xab2: 0x2e38, 0xab3: 0x2e40, 0xab4: 0x2e48, 0xab5: 0x2e50, + 0xab6: 0x2e60, 0xab7: 0x2e68, 0xab8: 0x2e70, 0xab9: 0x2e78, 0xaba: 0x2e80, 0xabb: 0x2e88, + 0xabc: 0x2ed3, 0xabd: 0x2e9b, 0xabe: 0x2e58, + // Block 0x2b, offset 0xac0 + 0xac0: 0x06bf, 0xac1: 0x071b, 0xac2: 0x06cb, 0xac3: 0x097b, 0xac4: 0x071f, 0xac5: 0x07af, + 0xac6: 0x06c7, 0xac7: 0x07ab, 0xac8: 0x070b, 0xac9: 0x0887, 0xaca: 0x0d07, 0xacb: 0x0e8f, + 0xacc: 0x0dd7, 0xacd: 0x0d1b, 0xace: 0x145f, 0xacf: 0x098b, 0xad0: 0x0ccf, 0xad1: 0x0d4b, + 0xad2: 0x0d0b, 0xad3: 0x104b, 0xad4: 0x08fb, 0xad5: 0x0f03, 0xad6: 0x1387, 0xad7: 0x105f, + 0xad8: 0x0843, 0xad9: 0x108f, 0xada: 0x0f9b, 0xadb: 0x0a17, 0xadc: 0x140f, 0xadd: 0x077f, + 0xade: 0x08ab, 0xadf: 0x0df7, 0xae0: 0x1527, 0xae1: 0x0743, 0xae2: 0x07d3, 0xae3: 0x0d9b, + 0xae4: 0x06cf, 0xae5: 0x06e7, 0xae6: 0x06d3, 0xae7: 0x0adb, 0xae8: 0x08ef, 0xae9: 0x087f, + 0xaea: 0x0a57, 0xaeb: 0x0a4b, 0xaec: 0x0feb, 0xaed: 0x073f, 0xaee: 0x139b, 0xaef: 0x089b, + 0xaf0: 0x09f3, 0xaf1: 0x18dc, 0xaf2: 0x18df, 0xaf3: 0x18e2, 0xaf4: 0x18e5, 0xaf5: 0x18ee, + 0xaf6: 0x18f1, 0xaf7: 0x18f4, 0xaf8: 0x18f7, 0xaf9: 0x18fa, 0xafa: 0x18fd, 0xafb: 0x1900, + 0xafc: 0x1903, 0xafd: 0x1906, 0xafe: 0x1909, 0xaff: 0x1912, + // Block 0x2c, offset 0xb00 + 0xb00: 0x1cc6, 0xb01: 0x1cd5, 0xb02: 0x1ce4, 0xb03: 0x1cf3, 0xb04: 0x1d02, 0xb05: 0x1d11, + 0xb06: 0x1d20, 0xb07: 0x1d2f, 0xb08: 0x1d3e, 0xb09: 0x218c, 0xb0a: 0x219e, 0xb0b: 0x21b0, + 0xb0c: 0x1954, 0xb0d: 0x1c04, 0xb0e: 0x19d2, 0xb0f: 0x1ba8, 0xb10: 0x04cb, 0xb11: 0x04d3, + 0xb12: 0x04db, 0xb13: 0x04e3, 0xb14: 0x04eb, 0xb15: 0x04ef, 0xb16: 0x04f3, 0xb17: 0x04f7, + 0xb18: 0x04fb, 0xb19: 0x04ff, 0xb1a: 0x0503, 0xb1b: 0x0507, 0xb1c: 0x050b, 0xb1d: 0x050f, + 0xb1e: 0x0513, 0xb1f: 0x0517, 0xb20: 0x051b, 0xb21: 0x0523, 0xb22: 0x0527, 0xb23: 0x052b, + 0xb24: 0x052f, 0xb25: 0x0533, 0xb26: 0x0537, 0xb27: 0x053b, 0xb28: 0x053f, 0xb29: 0x0543, + 0xb2a: 0x0547, 0xb2b: 0x054b, 0xb2c: 0x054f, 0xb2d: 0x0553, 0xb2e: 0x0557, 0xb2f: 0x055b, + 0xb30: 0x055f, 0xb31: 0x0563, 0xb32: 0x0567, 0xb33: 0x056f, 0xb34: 0x0577, 0xb35: 0x057f, + 0xb36: 0x0583, 0xb37: 0x0587, 0xb38: 0x058b, 0xb39: 0x058f, 0xb3a: 0x0593, 0xb3b: 0x0597, + 0xb3c: 0x059b, 0xb3d: 0x059f, 0xb3e: 0x05a3, + // Block 0x2d, offset 0xb40 + 0xb40: 0x2b0c, 0xb41: 0x29a8, 0xb42: 0x2b1c, 0xb43: 0x2880, 0xb44: 0x2ee4, 0xb45: 0x288a, + 0xb46: 0x2894, 0xb47: 0x2f28, 0xb48: 0x29b5, 0xb49: 0x289e, 0xb4a: 0x28a8, 0xb4b: 0x28b2, + 0xb4c: 0x29dc, 0xb4d: 0x29e9, 0xb4e: 0x29c2, 0xb4f: 0x29cf, 0xb50: 0x2ea9, 0xb51: 0x29f6, + 0xb52: 0x2a03, 0xb53: 0x2bbe, 0xb54: 0x26bb, 0xb55: 0x2bd1, 0xb56: 0x2be4, 0xb57: 0x2b2c, + 0xb58: 0x2a10, 0xb59: 0x2bf7, 0xb5a: 0x2c0a, 0xb5b: 0x2a1d, 0xb5c: 0x28bc, 0xb5d: 0x28c6, + 0xb5e: 0x2eb7, 0xb5f: 0x2a2a, 0xb60: 0x2b3c, 0xb61: 0x2ef5, 0xb62: 0x28d0, 0xb63: 0x28da, + 0xb64: 0x2a37, 0xb65: 0x28e4, 0xb66: 0x28ee, 0xb67: 0x26d0, 0xb68: 0x26d7, 0xb69: 0x28f8, + 0xb6a: 0x2902, 0xb6b: 0x2c1d, 0xb6c: 0x2a44, 0xb6d: 0x2b4c, 0xb6e: 0x2c30, 0xb6f: 0x2a51, + 0xb70: 0x2916, 0xb71: 0x290c, 0xb72: 0x2f3c, 0xb73: 0x2a5e, 0xb74: 0x2c43, 0xb75: 0x2920, + 0xb76: 0x2b5c, 0xb77: 0x292a, 0xb78: 0x2a78, 0xb79: 0x2934, 0xb7a: 0x2a85, 0xb7b: 0x2f06, + 0xb7c: 0x2a6b, 0xb7d: 0x2b6c, 0xb7e: 0x2a92, 0xb7f: 0x26de, + // Block 0x2e, offset 0xb80 + 0xb80: 0x2f17, 0xb81: 0x293e, 0xb82: 0x2948, 0xb83: 0x2a9f, 0xb84: 0x2952, 0xb85: 0x295c, + 0xb86: 0x2966, 0xb87: 0x2b7c, 0xb88: 0x2aac, 0xb89: 0x26e5, 0xb8a: 0x2c56, 0xb8b: 0x2e90, + 0xb8c: 0x2b8c, 0xb8d: 0x2ab9, 0xb8e: 0x2ec5, 0xb8f: 0x2970, 0xb90: 0x297a, 0xb91: 0x2ac6, + 0xb92: 0x26ec, 0xb93: 0x2ad3, 0xb94: 0x2b9c, 0xb95: 0x26f3, 0xb96: 0x2c69, 0xb97: 0x2984, + 0xb98: 0x1cb7, 0xb99: 0x1ccb, 0xb9a: 0x1cda, 0xb9b: 0x1ce9, 0xb9c: 0x1cf8, 0xb9d: 0x1d07, + 0xb9e: 0x1d16, 0xb9f: 0x1d25, 0xba0: 0x1d34, 0xba1: 0x1d43, 0xba2: 0x2192, 0xba3: 0x21a4, + 0xba4: 0x21b6, 0xba5: 0x21c2, 0xba6: 0x21ce, 0xba7: 0x21da, 0xba8: 0x21e6, 0xba9: 0x21f2, + 0xbaa: 0x21fe, 0xbab: 0x220a, 0xbac: 0x2246, 0xbad: 0x2252, 0xbae: 0x225e, 0xbaf: 0x226a, + 0xbb0: 0x2276, 0xbb1: 0x1c14, 0xbb2: 0x19c6, 0xbb3: 0x1936, 0xbb4: 0x1be4, 0xbb5: 0x1a47, + 0xbb6: 0x1a56, 0xbb7: 0x19cc, 0xbb8: 0x1bfc, 0xbb9: 0x1c00, 0xbba: 0x1960, 0xbbb: 0x2701, + 0xbbc: 0x270f, 0xbbd: 0x26fa, 0xbbe: 0x2708, 0xbbf: 0x2ae0, + // Block 0x2f, offset 0xbc0 + 0xbc0: 0x1a4a, 0xbc1: 0x1a32, 0xbc2: 0x1c60, 0xbc3: 0x1a1a, 0xbc4: 0x19f3, 0xbc5: 0x1969, + 0xbc6: 0x1978, 0xbc7: 0x1948, 0xbc8: 0x1bf0, 0xbc9: 0x1d52, 0xbca: 0x1a4d, 0xbcb: 0x1a35, + 0xbcc: 0x1c64, 0xbcd: 0x1c70, 0xbce: 0x1a26, 0xbcf: 0x19fc, 0xbd0: 0x1957, 0xbd1: 0x1c1c, + 0xbd2: 0x1bb0, 0xbd3: 0x1b9c, 0xbd4: 0x1bcc, 0xbd5: 0x1c74, 0xbd6: 0x1a29, 0xbd7: 0x19c9, + 0xbd8: 0x19ff, 0xbd9: 0x19de, 0xbda: 0x1a41, 0xbdb: 0x1c78, 0xbdc: 0x1a2c, 0xbdd: 0x19c0, + 0xbde: 0x1a02, 0xbdf: 0x1c3c, 0xbe0: 0x1bf4, 0xbe1: 0x1a14, 0xbe2: 0x1c24, 0xbe3: 0x1c40, + 0xbe4: 0x1bf8, 0xbe5: 0x1a17, 0xbe6: 0x1c28, 0xbe7: 0x22e8, 0xbe8: 0x22fc, 0xbe9: 0x1996, + 0xbea: 0x1c20, 0xbeb: 0x1bb4, 0xbec: 0x1ba0, 0xbed: 0x1c48, 0xbee: 0x2716, 0xbef: 0x27ad, + 0xbf0: 0x1a59, 0xbf1: 0x1a44, 0xbf2: 0x1c7c, 0xbf3: 0x1a2f, 0xbf4: 0x1a50, 0xbf5: 0x1a38, + 0xbf6: 0x1c68, 0xbf7: 0x1a1d, 0xbf8: 0x19f6, 0xbf9: 0x1981, 0xbfa: 0x1a53, 0xbfb: 0x1a3b, + 0xbfc: 0x1c6c, 0xbfd: 0x1a20, 0xbfe: 0x19f9, 0xbff: 0x1984, + // Block 0x30, offset 0xc00 + 0xc00: 0x1c2c, 0xc01: 0x1bb8, 0xc02: 0x1d4d, 0xc03: 0x1939, 0xc04: 0x19ba, 0xc05: 0x19bd, + 0xc06: 0x22f5, 0xc07: 0x1b94, 0xc08: 0x19c3, 0xc09: 0x194b, 0xc0a: 0x19e1, 0xc0b: 0x194e, + 0xc0c: 0x19ea, 0xc0d: 0x196c, 0xc0e: 0x196f, 0xc0f: 0x1a05, 0xc10: 0x1a0b, 0xc11: 0x1a0e, + 0xc12: 0x1c30, 0xc13: 0x1a11, 0xc14: 0x1a23, 0xc15: 0x1c38, 0xc16: 0x1c44, 0xc17: 0x1990, + 0xc18: 0x1d57, 0xc19: 0x1bbc, 0xc1a: 0x1993, 0xc1b: 0x1a5c, 0xc1c: 0x19a5, 0xc1d: 0x19b4, + 0xc1e: 0x22e2, 0xc1f: 0x22dc, 0xc20: 0x1cc1, 0xc21: 0x1cd0, 0xc22: 0x1cdf, 0xc23: 0x1cee, + 0xc24: 0x1cfd, 0xc25: 0x1d0c, 0xc26: 0x1d1b, 0xc27: 0x1d2a, 0xc28: 0x1d39, 0xc29: 0x2186, + 0xc2a: 0x2198, 0xc2b: 0x21aa, 0xc2c: 0x21bc, 0xc2d: 0x21c8, 0xc2e: 0x21d4, 0xc2f: 0x21e0, + 0xc30: 0x21ec, 0xc31: 0x21f8, 0xc32: 0x2204, 0xc33: 0x2240, 0xc34: 0x224c, 0xc35: 0x2258, + 0xc36: 0x2264, 0xc37: 0x2270, 0xc38: 0x227c, 0xc39: 0x2282, 0xc3a: 0x2288, 0xc3b: 0x228e, + 0xc3c: 0x2294, 0xc3d: 0x22a6, 0xc3e: 0x22ac, 0xc3f: 0x1c10, + // Block 0x31, offset 0xc40 + 0xc40: 0x1377, 0xc41: 0x0cfb, 0xc42: 0x13d3, 0xc43: 0x139f, 0xc44: 0x0e57, 0xc45: 0x06eb, + 0xc46: 0x08df, 0xc47: 0x162b, 0xc48: 0x162b, 0xc49: 0x0a0b, 0xc4a: 0x145f, 0xc4b: 0x0943, + 0xc4c: 0x0a07, 0xc4d: 0x0bef, 0xc4e: 0x0fcf, 0xc4f: 0x115f, 0xc50: 0x1297, 0xc51: 0x12d3, + 0xc52: 0x1307, 0xc53: 0x141b, 0xc54: 0x0d73, 0xc55: 0x0dff, 0xc56: 0x0eab, 0xc57: 0x0f43, + 0xc58: 0x125f, 0xc59: 0x1447, 0xc5a: 0x1573, 0xc5b: 0x070f, 0xc5c: 0x08b3, 0xc5d: 0x0d87, + 0xc5e: 0x0ecf, 0xc5f: 0x1293, 0xc60: 0x15c3, 0xc61: 0x0ab3, 0xc62: 0x0e77, 0xc63: 0x1283, + 0xc64: 0x1317, 0xc65: 0x0c23, 0xc66: 0x11bb, 0xc67: 0x12df, 0xc68: 0x0b1f, 0xc69: 0x0d0f, + 0xc6a: 0x0e17, 0xc6b: 0x0f1b, 0xc6c: 0x1427, 0xc6d: 0x074f, 0xc6e: 0x07e7, 0xc6f: 0x0853, + 0xc70: 0x0c8b, 0xc71: 0x0d7f, 0xc72: 0x0ecb, 0xc73: 0x0fef, 0xc74: 0x1177, 0xc75: 0x128b, + 0xc76: 0x12a3, 0xc77: 0x13c7, 0xc78: 0x14ef, 0xc79: 0x15a3, 0xc7a: 0x15bf, 0xc7b: 0x102b, + 0xc7c: 0x106b, 0xc7d: 0x1123, 0xc7e: 0x1243, 0xc7f: 0x147b, + // Block 0x32, offset 0xc80 + 0xc80: 0x15cb, 0xc81: 0x134b, 0xc82: 0x09c7, 0xc83: 0x0b3b, 0xc84: 0x10db, 0xc85: 0x119b, + 0xc86: 0x0eff, 0xc87: 0x1033, 0xc88: 0x1397, 0xc89: 0x14e7, 0xc8a: 0x09c3, 0xc8b: 0x0a8f, + 0xc8c: 0x0d77, 0xc8d: 0x0e2b, 0xc8e: 0x0e5f, 0xc8f: 0x1113, 0xc90: 0x113b, 0xc91: 0x14a7, + 0xc92: 0x084f, 0xc93: 0x11a7, 0xc94: 0x07f3, 0xc95: 0x07ef, 0xc96: 0x1097, 0xc97: 0x1127, + 0xc98: 0x125b, 0xc99: 0x14af, 0xc9a: 0x1367, 0xc9b: 0x0c27, 0xc9c: 0x0d73, 0xc9d: 0x1357, + 0xc9e: 0x06f7, 0xc9f: 0x0a63, 0xca0: 0x0b93, 0xca1: 0x0f2f, 0xca2: 0x0faf, 0xca3: 0x0873, + 0xca4: 0x103b, 0xca5: 0x075f, 0xca6: 0x0b77, 0xca7: 0x06d7, 0xca8: 0x0deb, 0xca9: 0x0ca3, + 0xcaa: 0x110f, 0xcab: 0x08c7, 0xcac: 0x09b3, 0xcad: 0x0ffb, 0xcae: 0x1263, 0xcaf: 0x133b, + 0xcb0: 0x0db7, 0xcb1: 0x13f7, 0xcb2: 0x0de3, 0xcb3: 0x0c37, 0xcb4: 0x121b, 0xcb5: 0x0c57, + 0xcb6: 0x0fab, 0xcb7: 0x072b, 0xcb8: 0x07a7, 0xcb9: 0x07eb, 0xcba: 0x0d53, 0xcbb: 0x10fb, + 0xcbc: 0x11f3, 0xcbd: 0x1347, 0xcbe: 0x145b, 0xcbf: 0x085b, + // Block 0x33, offset 0xcc0 + 0xcc0: 0x090f, 0xcc1: 0x0a17, 0xcc2: 0x0b2f, 0xcc3: 0x0cbf, 0xcc4: 0x0e7b, 0xcc5: 0x103f, + 0xcc6: 0x1497, 0xcc7: 0x157b, 0xcc8: 0x15cf, 0xcc9: 0x15e7, 0xcca: 0x0837, 0xccb: 0x0cf3, + 0xccc: 0x0da3, 0xccd: 0x13eb, 0xcce: 0x0afb, 0xccf: 0x0bd7, 0xcd0: 0x0bf3, 0xcd1: 0x0c83, + 0xcd2: 0x0e6b, 0xcd3: 0x0eb7, 0xcd4: 0x0f67, 0xcd5: 0x108b, 0xcd6: 0x112f, 0xcd7: 0x1193, + 0xcd8: 0x13db, 0xcd9: 0x126b, 0xcda: 0x1403, 0xcdb: 0x147f, 0xcdc: 0x080f, 0xcdd: 0x083b, + 0xcde: 0x0923, 0xcdf: 0x0ea7, 0xce0: 0x12f3, 0xce1: 0x133b, 0xce2: 0x0b1b, 0xce3: 0x0b8b, + 0xce4: 0x0c4f, 0xce5: 0x0daf, 0xce6: 0x10d7, 0xce7: 0x0f23, 0xce8: 0x073b, 0xce9: 0x097f, + 0xcea: 0x0a63, 0xceb: 0x0ac7, 0xcec: 0x0b97, 0xced: 0x0f3f, 0xcee: 0x0f5b, 0xcef: 0x116b, + 0xcf0: 0x118b, 0xcf1: 0x1463, 0xcf2: 0x14e3, 0xcf3: 0x14f3, 0xcf4: 0x152f, 0xcf5: 0x0753, + 0xcf6: 0x107f, 0xcf7: 0x144f, 0xcf8: 0x14cb, 0xcf9: 0x0baf, 0xcfa: 0x0717, 0xcfb: 0x0777, + 0xcfc: 0x0a67, 0xcfd: 0x0a87, 0xcfe: 0x0caf, 0xcff: 0x0d73, + // Block 0x34, offset 0xd00 + 0xd00: 0x0ec3, 0xd01: 0x0fcb, 0xd02: 0x1277, 0xd03: 0x1417, 0xd04: 0x1623, 0xd05: 0x0ce3, + 0xd06: 0x14a3, 0xd07: 0x0833, 0xd08: 0x0d2f, 0xd09: 0x0d3b, 0xd0a: 0x0e0f, 0xd0b: 0x0e47, + 0xd0c: 0x0f4b, 0xd0d: 0x0fa7, 0xd0e: 0x1027, 0xd0f: 0x110b, 0xd10: 0x153b, 0xd11: 0x07af, + 0xd12: 0x0c03, 0xd13: 0x14b3, 0xd14: 0x0767, 0xd15: 0x0aab, 0xd16: 0x0e2f, 0xd17: 0x13df, + 0xd18: 0x0b67, 0xd19: 0x0bb7, 0xd1a: 0x0d43, 0xd1b: 0x0f2f, 0xd1c: 0x14bb, 0xd1d: 0x0817, + 0xd1e: 0x08ff, 0xd1f: 0x0a97, 0xd20: 0x0cd3, 0xd21: 0x0d1f, 0xd22: 0x0d5f, 0xd23: 0x0df3, + 0xd24: 0x0f47, 0xd25: 0x0fbb, 0xd26: 0x1157, 0xd27: 0x12f7, 0xd28: 0x1303, 0xd29: 0x1457, + 0xd2a: 0x14d7, 0xd2b: 0x0883, 0xd2c: 0x0e4b, 0xd2d: 0x0903, 0xd2e: 0x0ec7, 0xd2f: 0x0f6b, + 0xd30: 0x1287, 0xd31: 0x14bf, 0xd32: 0x15ab, 0xd33: 0x15d3, 0xd34: 0x0d37, 0xd35: 0x0e27, + 0xd36: 0x11c3, 0xd37: 0x10b7, 0xd38: 0x10c3, 0xd39: 0x10e7, 0xd3a: 0x0f17, 0xd3b: 0x0e9f, + 0xd3c: 0x1363, 0xd3d: 0x0733, 0xd3e: 0x122b, 0xd3f: 0x081b, + // Block 0x35, offset 0xd40 + 0xd40: 0x080b, 0xd41: 0x0b0b, 0xd42: 0x0c2b, 0xd43: 0x10f3, 0xd44: 0x0a53, 0xd45: 0x0e03, + 0xd46: 0x0cef, 0xd47: 0x13e7, 0xd48: 0x12e7, 0xd49: 0x14ab, 0xd4a: 0x1323, 0xd4b: 0x0b27, + 0xd4c: 0x0787, 0xd4d: 0x095b, 0xd50: 0x09af, + 0xd52: 0x0cdf, 0xd55: 0x07f7, 0xd56: 0x0f1f, 0xd57: 0x0fe3, + 0xd58: 0x1047, 0xd59: 0x1063, 0xd5a: 0x1067, 0xd5b: 0x107b, 0xd5c: 0x14fb, 0xd5d: 0x10eb, + 0xd5e: 0x116f, 0xd60: 0x128f, 0xd62: 0x1353, + 0xd65: 0x1407, 0xd66: 0x1433, + 0xd6a: 0x154f, 0xd6b: 0x1553, 0xd6c: 0x1557, 0xd6d: 0x15bb, 0xd6e: 0x142b, 0xd6f: 0x14c7, + 0xd70: 0x0757, 0xd71: 0x077b, 0xd72: 0x078f, 0xd73: 0x084b, 0xd74: 0x0857, 0xd75: 0x0897, + 0xd76: 0x094b, 0xd77: 0x0967, 0xd78: 0x096f, 0xd79: 0x09ab, 0xd7a: 0x09b7, 0xd7b: 0x0a93, + 0xd7c: 0x0a9b, 0xd7d: 0x0ba3, 0xd7e: 0x0bcb, 0xd7f: 0x0bd3, + // Block 0x36, offset 0xd80 + 0xd80: 0x0beb, 0xd81: 0x0c97, 0xd82: 0x0cc7, 0xd83: 0x0ce7, 0xd84: 0x0d57, 0xd85: 0x0e1b, + 0xd86: 0x0e37, 0xd87: 0x0e67, 0xd88: 0x0ebb, 0xd89: 0x0edb, 0xd8a: 0x0f4f, 0xd8b: 0x102f, + 0xd8c: 0x104b, 0xd8d: 0x1053, 0xd8e: 0x104f, 0xd8f: 0x1057, 0xd90: 0x105b, 0xd91: 0x105f, + 0xd92: 0x1073, 0xd93: 0x1077, 0xd94: 0x109b, 0xd95: 0x10af, 0xd96: 0x10cb, 0xd97: 0x112f, + 0xd98: 0x1137, 0xd99: 0x113f, 0xd9a: 0x1153, 0xd9b: 0x117b, 0xd9c: 0x11cb, 0xd9d: 0x11ff, + 0xd9e: 0x11ff, 0xd9f: 0x1267, 0xda0: 0x130f, 0xda1: 0x1327, 0xda2: 0x135b, 0xda3: 0x135f, + 0xda4: 0x13a3, 0xda5: 0x13a7, 0xda6: 0x13ff, 0xda7: 0x1407, 0xda8: 0x14db, 0xda9: 0x151f, + 0xdaa: 0x1537, 0xdab: 0x0b9b, 0xdac: 0x171e, 0xdad: 0x11e3, + 0xdb0: 0x06df, 0xdb1: 0x07e3, 0xdb2: 0x07a3, 0xdb3: 0x074b, 0xdb4: 0x078b, 0xdb5: 0x07b7, + 0xdb6: 0x0847, 0xdb7: 0x0863, 0xdb8: 0x094b, 0xdb9: 0x0937, 0xdba: 0x0947, 0xdbb: 0x0963, + 0xdbc: 0x09af, 0xdbd: 0x09bf, 0xdbe: 0x0a03, 0xdbf: 0x0a0f, + // Block 0x37, offset 0xdc0 + 0xdc0: 0x0a2b, 0xdc1: 0x0a3b, 0xdc2: 0x0b23, 0xdc3: 0x0b2b, 0xdc4: 0x0b5b, 0xdc5: 0x0b7b, + 0xdc6: 0x0bab, 0xdc7: 0x0bc3, 0xdc8: 0x0bb3, 0xdc9: 0x0bd3, 0xdca: 0x0bc7, 0xdcb: 0x0beb, + 0xdcc: 0x0c07, 0xdcd: 0x0c5f, 0xdce: 0x0c6b, 0xdcf: 0x0c73, 0xdd0: 0x0c9b, 0xdd1: 0x0cdf, + 0xdd2: 0x0d0f, 0xdd3: 0x0d13, 0xdd4: 0x0d27, 0xdd5: 0x0da7, 0xdd6: 0x0db7, 0xdd7: 0x0e0f, + 0xdd8: 0x0e5b, 0xdd9: 0x0e53, 0xdda: 0x0e67, 0xddb: 0x0e83, 0xddc: 0x0ebb, 0xddd: 0x1013, + 0xdde: 0x0edf, 0xddf: 0x0f13, 0xde0: 0x0f1f, 0xde1: 0x0f5f, 0xde2: 0x0f7b, 0xde3: 0x0f9f, + 0xde4: 0x0fc3, 0xde5: 0x0fc7, 0xde6: 0x0fe3, 0xde7: 0x0fe7, 0xde8: 0x0ff7, 0xde9: 0x100b, + 0xdea: 0x1007, 0xdeb: 0x1037, 0xdec: 0x10b3, 0xded: 0x10cb, 0xdee: 0x10e3, 0xdef: 0x111b, + 0xdf0: 0x112f, 0xdf1: 0x114b, 0xdf2: 0x117b, 0xdf3: 0x122f, 0xdf4: 0x1257, 0xdf5: 0x12cb, + 0xdf6: 0x1313, 0xdf7: 0x131f, 0xdf8: 0x1327, 0xdf9: 0x133f, 0xdfa: 0x1353, 0xdfb: 0x1343, + 0xdfc: 0x135b, 0xdfd: 0x1357, 0xdfe: 0x134f, 0xdff: 0x135f, + // Block 0x38, offset 0xe00 + 0xe00: 0x136b, 0xe01: 0x13a7, 0xe02: 0x13e3, 0xe03: 0x1413, 0xe04: 0x144b, 0xe05: 0x146b, + 0xe06: 0x14b7, 0xe07: 0x14db, 0xe08: 0x14fb, 0xe09: 0x150f, 0xe0a: 0x151f, 0xe0b: 0x152b, + 0xe0c: 0x1537, 0xe0d: 0x158b, 0xe0e: 0x162b, 0xe0f: 0x16b5, 0xe10: 0x16b0, 0xe11: 0x16e2, + 0xe12: 0x0607, 0xe13: 0x062f, 0xe14: 0x0633, 0xe15: 0x1764, 0xe16: 0x1791, 0xe17: 0x1809, + 0xe18: 0x1617, 0xe19: 0x1627, + // Block 0x39, offset 0xe40 + 0xe40: 0x19d5, 0xe41: 0x19d8, 0xe42: 0x19db, 0xe43: 0x1c08, 0xe44: 0x1c0c, 0xe45: 0x1a5f, + 0xe46: 0x1a5f, + 0xe53: 0x1d75, 0xe54: 0x1d66, 0xe55: 0x1d6b, 0xe56: 0x1d7a, 0xe57: 0x1d70, + 0xe5d: 0x4390, + 0xe5e: 0x8115, 0xe5f: 0x4402, 0xe60: 0x022d, 0xe61: 0x0215, 0xe62: 0x021e, 0xe63: 0x0221, + 0xe64: 0x0224, 0xe65: 0x0227, 0xe66: 0x022a, 0xe67: 0x0230, 0xe68: 0x0233, 0xe69: 0x0017, + 0xe6a: 0x43f0, 0xe6b: 0x43f6, 0xe6c: 0x44f4, 0xe6d: 0x44fc, 0xe6e: 0x4348, 0xe6f: 0x434e, + 0xe70: 0x4354, 0xe71: 0x435a, 0xe72: 0x4366, 0xe73: 0x436c, 0xe74: 0x4372, 0xe75: 0x437e, + 0xe76: 0x4384, 0xe78: 0x438a, 0xe79: 0x4396, 0xe7a: 0x439c, 0xe7b: 0x43a2, + 0xe7c: 0x43ae, 0xe7e: 0x43b4, + // Block 0x3a, offset 0xe80 + 0xe80: 0x43ba, 0xe81: 0x43c0, 0xe83: 0x43c6, 0xe84: 0x43cc, + 0xe86: 0x43d8, 0xe87: 0x43de, 0xe88: 0x43e4, 0xe89: 0x43ea, 0xe8a: 0x43fc, 0xe8b: 0x4378, + 0xe8c: 0x4360, 0xe8d: 0x43a8, 0xe8e: 0x43d2, 0xe8f: 0x1d7f, 0xe90: 0x0299, 0xe91: 0x0299, + 0xe92: 0x02a2, 0xe93: 0x02a2, 0xe94: 0x02a2, 0xe95: 0x02a2, 0xe96: 0x02a5, 0xe97: 0x02a5, + 0xe98: 0x02a5, 0xe99: 0x02a5, 0xe9a: 0x02ab, 0xe9b: 0x02ab, 0xe9c: 0x02ab, 0xe9d: 0x02ab, + 0xe9e: 0x029f, 0xe9f: 0x029f, 0xea0: 0x029f, 0xea1: 0x029f, 0xea2: 0x02a8, 0xea3: 0x02a8, + 0xea4: 0x02a8, 0xea5: 0x02a8, 0xea6: 0x029c, 0xea7: 0x029c, 0xea8: 0x029c, 0xea9: 0x029c, + 0xeaa: 0x02cf, 0xeab: 0x02cf, 0xeac: 0x02cf, 0xead: 0x02cf, 0xeae: 0x02d2, 0xeaf: 0x02d2, + 0xeb0: 0x02d2, 0xeb1: 0x02d2, 0xeb2: 0x02b1, 0xeb3: 0x02b1, 0xeb4: 0x02b1, 0xeb5: 0x02b1, + 0xeb6: 0x02ae, 0xeb7: 0x02ae, 0xeb8: 0x02ae, 0xeb9: 0x02ae, 0xeba: 0x02b4, 0xebb: 0x02b4, + 0xebc: 0x02b4, 0xebd: 0x02b4, 0xebe: 0x02b7, 0xebf: 0x02b7, + // Block 0x3b, offset 0xec0 + 0xec0: 0x02b7, 0xec1: 0x02b7, 0xec2: 0x02c0, 0xec3: 0x02c0, 0xec4: 0x02bd, 0xec5: 0x02bd, + 0xec6: 0x02c3, 0xec7: 0x02c3, 0xec8: 0x02ba, 0xec9: 0x02ba, 0xeca: 0x02c9, 0xecb: 0x02c9, + 0xecc: 0x02c6, 0xecd: 0x02c6, 0xece: 0x02d5, 0xecf: 0x02d5, 0xed0: 0x02d5, 0xed1: 0x02d5, + 0xed2: 0x02db, 0xed3: 0x02db, 0xed4: 0x02db, 0xed5: 0x02db, 0xed6: 0x02e1, 0xed7: 0x02e1, + 0xed8: 0x02e1, 0xed9: 0x02e1, 0xeda: 0x02de, 0xedb: 0x02de, 0xedc: 0x02de, 0xedd: 0x02de, + 0xede: 0x02e4, 0xedf: 0x02e4, 0xee0: 0x02e7, 0xee1: 0x02e7, 0xee2: 0x02e7, 0xee3: 0x02e7, + 0xee4: 0x446e, 0xee5: 0x446e, 0xee6: 0x02ed, 0xee7: 0x02ed, 0xee8: 0x02ed, 0xee9: 0x02ed, + 0xeea: 0x02ea, 0xeeb: 0x02ea, 0xeec: 0x02ea, 0xeed: 0x02ea, 0xeee: 0x0308, 0xeef: 0x0308, + 0xef0: 0x4468, 0xef1: 0x4468, + // Block 0x3c, offset 0xf00 + 0xf13: 0x02d8, 0xf14: 0x02d8, 0xf15: 0x02d8, 0xf16: 0x02d8, 0xf17: 0x02f6, + 0xf18: 0x02f6, 0xf19: 0x02f3, 0xf1a: 0x02f3, 0xf1b: 0x02f9, 0xf1c: 0x02f9, 0xf1d: 0x204f, + 0xf1e: 0x02ff, 0xf1f: 0x02ff, 0xf20: 0x02f0, 0xf21: 0x02f0, 0xf22: 0x02fc, 0xf23: 0x02fc, + 0xf24: 0x0305, 0xf25: 0x0305, 0xf26: 0x0305, 0xf27: 0x0305, 0xf28: 0x028d, 0xf29: 0x028d, + 0xf2a: 0x25aa, 0xf2b: 0x25aa, 0xf2c: 0x261a, 0xf2d: 0x261a, 0xf2e: 0x25e9, 0xf2f: 0x25e9, + 0xf30: 0x2605, 0xf31: 0x2605, 0xf32: 0x25fe, 0xf33: 0x25fe, 0xf34: 0x260c, 0xf35: 0x260c, + 0xf36: 0x2613, 0xf37: 0x2613, 0xf38: 0x2613, 0xf39: 0x25f0, 0xf3a: 0x25f0, 0xf3b: 0x25f0, + 0xf3c: 0x0302, 0xf3d: 0x0302, 0xf3e: 0x0302, 0xf3f: 0x0302, + // Block 0x3d, offset 0xf40 + 0xf40: 0x25b1, 0xf41: 0x25b8, 0xf42: 0x25d4, 0xf43: 0x25f0, 0xf44: 0x25f7, 0xf45: 0x1d89, + 0xf46: 0x1d8e, 0xf47: 0x1d93, 0xf48: 0x1da2, 0xf49: 0x1db1, 0xf4a: 0x1db6, 0xf4b: 0x1dbb, + 0xf4c: 0x1dc0, 0xf4d: 0x1dc5, 0xf4e: 0x1dd4, 0xf4f: 0x1de3, 0xf50: 0x1de8, 0xf51: 0x1ded, + 0xf52: 0x1dfc, 0xf53: 0x1e0b, 0xf54: 0x1e10, 0xf55: 0x1e15, 0xf56: 0x1e1a, 0xf57: 0x1e29, + 0xf58: 0x1e2e, 0xf59: 0x1e3d, 0xf5a: 0x1e42, 0xf5b: 0x1e47, 0xf5c: 0x1e56, 0xf5d: 0x1e5b, + 0xf5e: 0x1e60, 0xf5f: 0x1e6a, 0xf60: 0x1ea6, 0xf61: 0x1eb5, 0xf62: 0x1ec4, 0xf63: 0x1ec9, + 0xf64: 0x1ece, 0xf65: 0x1ed8, 0xf66: 0x1ee7, 0xf67: 0x1eec, 0xf68: 0x1efb, 0xf69: 0x1f00, + 0xf6a: 0x1f05, 0xf6b: 0x1f14, 0xf6c: 0x1f19, 0xf6d: 0x1f28, 0xf6e: 0x1f2d, 0xf6f: 0x1f32, + 0xf70: 0x1f37, 0xf71: 0x1f3c, 0xf72: 0x1f41, 0xf73: 0x1f46, 0xf74: 0x1f4b, 0xf75: 0x1f50, + 0xf76: 0x1f55, 0xf77: 0x1f5a, 0xf78: 0x1f5f, 0xf79: 0x1f64, 0xf7a: 0x1f69, 0xf7b: 0x1f6e, + 0xf7c: 0x1f73, 0xf7d: 0x1f78, 0xf7e: 0x1f7d, 0xf7f: 0x1f87, + // Block 0x3e, offset 0xf80 + 0xf80: 0x1f8c, 0xf81: 0x1f91, 0xf82: 0x1f96, 0xf83: 0x1fa0, 0xf84: 0x1fa5, 0xf85: 0x1faf, + 0xf86: 0x1fb4, 0xf87: 0x1fb9, 0xf88: 0x1fbe, 0xf89: 0x1fc3, 0xf8a: 0x1fc8, 0xf8b: 0x1fcd, + 0xf8c: 0x1fd2, 0xf8d: 0x1fd7, 0xf8e: 0x1fe6, 0xf8f: 0x1ff5, 0xf90: 0x1ffa, 0xf91: 0x1fff, + 0xf92: 0x2004, 0xf93: 0x2009, 0xf94: 0x200e, 0xf95: 0x2018, 0xf96: 0x201d, 0xf97: 0x2022, + 0xf98: 0x2031, 0xf99: 0x2040, 0xf9a: 0x2045, 0xf9b: 0x4420, 0xf9c: 0x4426, 0xf9d: 0x445c, + 0xf9e: 0x44b3, 0xf9f: 0x44ba, 0xfa0: 0x44c1, 0xfa1: 0x44c8, 0xfa2: 0x44cf, 0xfa3: 0x44d6, + 0xfa4: 0x25c6, 0xfa5: 0x25cd, 0xfa6: 0x25d4, 0xfa7: 0x25db, 0xfa8: 0x25f0, 0xfa9: 0x25f7, + 0xfaa: 0x1d98, 0xfab: 0x1d9d, 0xfac: 0x1da2, 0xfad: 0x1da7, 0xfae: 0x1db1, 0xfaf: 0x1db6, + 0xfb0: 0x1dca, 0xfb1: 0x1dcf, 0xfb2: 0x1dd4, 0xfb3: 0x1dd9, 0xfb4: 0x1de3, 0xfb5: 0x1de8, + 0xfb6: 0x1df2, 0xfb7: 0x1df7, 0xfb8: 0x1dfc, 0xfb9: 0x1e01, 0xfba: 0x1e0b, 0xfbb: 0x1e10, + 0xfbc: 0x1f3c, 0xfbd: 0x1f41, 0xfbe: 0x1f50, 0xfbf: 0x1f55, + // Block 0x3f, offset 0xfc0 + 0xfc0: 0x1f5a, 0xfc1: 0x1f6e, 0xfc2: 0x1f73, 0xfc3: 0x1f78, 0xfc4: 0x1f7d, 0xfc5: 0x1f96, + 0xfc6: 0x1fa0, 0xfc7: 0x1fa5, 0xfc8: 0x1faa, 0xfc9: 0x1fbe, 0xfca: 0x1fdc, 0xfcb: 0x1fe1, + 0xfcc: 0x1fe6, 0xfcd: 0x1feb, 0xfce: 0x1ff5, 0xfcf: 0x1ffa, 0xfd0: 0x445c, 0xfd1: 0x2027, + 0xfd2: 0x202c, 0xfd3: 0x2031, 0xfd4: 0x2036, 0xfd5: 0x2040, 0xfd6: 0x2045, 0xfd7: 0x25b1, + 0xfd8: 0x25b8, 0xfd9: 0x25bf, 0xfda: 0x25d4, 0xfdb: 0x25e2, 0xfdc: 0x1d89, 0xfdd: 0x1d8e, + 0xfde: 0x1d93, 0xfdf: 0x1da2, 0xfe0: 0x1dac, 0xfe1: 0x1dbb, 0xfe2: 0x1dc0, 0xfe3: 0x1dc5, + 0xfe4: 0x1dd4, 0xfe5: 0x1dde, 0xfe6: 0x1dfc, 0xfe7: 0x1e15, 0xfe8: 0x1e1a, 0xfe9: 0x1e29, + 0xfea: 0x1e2e, 0xfeb: 0x1e3d, 0xfec: 0x1e47, 0xfed: 0x1e56, 0xfee: 0x1e5b, 0xfef: 0x1e60, + 0xff0: 0x1e6a, 0xff1: 0x1ea6, 0xff2: 0x1eab, 0xff3: 0x1eb5, 0xff4: 0x1ec4, 0xff5: 0x1ec9, + 0xff6: 0x1ece, 0xff7: 0x1ed8, 0xff8: 0x1ee7, 0xff9: 0x1efb, 0xffa: 0x1f00, 0xffb: 0x1f05, + 0xffc: 0x1f14, 0xffd: 0x1f19, 0xffe: 0x1f28, 0xfff: 0x1f2d, + // Block 0x40, offset 0x1000 + 0x1000: 0x1f32, 0x1001: 0x1f37, 0x1002: 0x1f46, 0x1003: 0x1f4b, 0x1004: 0x1f5f, 0x1005: 0x1f64, + 0x1006: 0x1f69, 0x1007: 0x1f6e, 0x1008: 0x1f73, 0x1009: 0x1f87, 0x100a: 0x1f8c, 0x100b: 0x1f91, + 0x100c: 0x1f96, 0x100d: 0x1f9b, 0x100e: 0x1faf, 0x100f: 0x1fb4, 0x1010: 0x1fb9, 0x1011: 0x1fbe, + 0x1012: 0x1fcd, 0x1013: 0x1fd2, 0x1014: 0x1fd7, 0x1015: 0x1fe6, 0x1016: 0x1ff0, 0x1017: 0x1fff, + 0x1018: 0x2004, 0x1019: 0x4450, 0x101a: 0x2018, 0x101b: 0x201d, 0x101c: 0x2022, 0x101d: 0x2031, + 0x101e: 0x203b, 0x101f: 0x25d4, 0x1020: 0x25e2, 0x1021: 0x1da2, 0x1022: 0x1dac, 0x1023: 0x1dd4, + 0x1024: 0x1dde, 0x1025: 0x1dfc, 0x1026: 0x1e06, 0x1027: 0x1e6a, 0x1028: 0x1e6f, 0x1029: 0x1e92, + 0x102a: 0x1e97, 0x102b: 0x1f6e, 0x102c: 0x1f73, 0x102d: 0x1f96, 0x102e: 0x1fe6, 0x102f: 0x1ff0, + 0x1030: 0x2031, 0x1031: 0x203b, 0x1032: 0x4504, 0x1033: 0x450c, 0x1034: 0x4514, 0x1035: 0x1ef1, + 0x1036: 0x1ef6, 0x1037: 0x1f0a, 0x1038: 0x1f0f, 0x1039: 0x1f1e, 0x103a: 0x1f23, 0x103b: 0x1e74, + 0x103c: 0x1e79, 0x103d: 0x1e9c, 0x103e: 0x1ea1, 0x103f: 0x1e33, + // Block 0x41, offset 0x1040 + 0x1040: 0x1e38, 0x1041: 0x1e1f, 0x1042: 0x1e24, 0x1043: 0x1e4c, 0x1044: 0x1e51, 0x1045: 0x1eba, + 0x1046: 0x1ebf, 0x1047: 0x1edd, 0x1048: 0x1ee2, 0x1049: 0x1e7e, 0x104a: 0x1e83, 0x104b: 0x1e88, + 0x104c: 0x1e92, 0x104d: 0x1e8d, 0x104e: 0x1e65, 0x104f: 0x1eb0, 0x1050: 0x1ed3, 0x1051: 0x1ef1, + 0x1052: 0x1ef6, 0x1053: 0x1f0a, 0x1054: 0x1f0f, 0x1055: 0x1f1e, 0x1056: 0x1f23, 0x1057: 0x1e74, + 0x1058: 0x1e79, 0x1059: 0x1e9c, 0x105a: 0x1ea1, 0x105b: 0x1e33, 0x105c: 0x1e38, 0x105d: 0x1e1f, + 0x105e: 0x1e24, 0x105f: 0x1e4c, 0x1060: 0x1e51, 0x1061: 0x1eba, 0x1062: 0x1ebf, 0x1063: 0x1edd, + 0x1064: 0x1ee2, 0x1065: 0x1e7e, 0x1066: 0x1e83, 0x1067: 0x1e88, 0x1068: 0x1e92, 0x1069: 0x1e8d, + 0x106a: 0x1e65, 0x106b: 0x1eb0, 0x106c: 0x1ed3, 0x106d: 0x1e7e, 0x106e: 0x1e83, 0x106f: 0x1e88, + 0x1070: 0x1e92, 0x1071: 0x1e6f, 0x1072: 0x1e97, 0x1073: 0x1eec, 0x1074: 0x1e56, 0x1075: 0x1e5b, + 0x1076: 0x1e60, 0x1077: 0x1e7e, 0x1078: 0x1e83, 0x1079: 0x1e88, 0x107a: 0x1eec, 0x107b: 0x1efb, + 0x107c: 0x4408, 0x107d: 0x4408, + // Block 0x42, offset 0x1080 + 0x1090: 0x2311, 0x1091: 0x2326, + 0x1092: 0x2326, 0x1093: 0x232d, 0x1094: 0x2334, 0x1095: 0x2349, 0x1096: 0x2350, 0x1097: 0x2357, + 0x1098: 0x237a, 0x1099: 0x237a, 0x109a: 0x239d, 0x109b: 0x2396, 0x109c: 0x23b2, 0x109d: 0x23a4, + 0x109e: 0x23ab, 0x109f: 0x23ce, 0x10a0: 0x23ce, 0x10a1: 0x23c7, 0x10a2: 0x23d5, 0x10a3: 0x23d5, + 0x10a4: 0x23ff, 0x10a5: 0x23ff, 0x10a6: 0x241b, 0x10a7: 0x23e3, 0x10a8: 0x23e3, 0x10a9: 0x23dc, + 0x10aa: 0x23f1, 0x10ab: 0x23f1, 0x10ac: 0x23f8, 0x10ad: 0x23f8, 0x10ae: 0x2422, 0x10af: 0x2430, + 0x10b0: 0x2430, 0x10b1: 0x2437, 0x10b2: 0x2437, 0x10b3: 0x243e, 0x10b4: 0x2445, 0x10b5: 0x244c, + 0x10b6: 0x2453, 0x10b7: 0x2453, 0x10b8: 0x245a, 0x10b9: 0x2468, 0x10ba: 0x2476, 0x10bb: 0x246f, + 0x10bc: 0x247d, 0x10bd: 0x247d, 0x10be: 0x2492, 0x10bf: 0x2499, + // Block 0x43, offset 0x10c0 + 0x10c0: 0x24ca, 0x10c1: 0x24d8, 0x10c2: 0x24d1, 0x10c3: 0x24b5, 0x10c4: 0x24b5, 0x10c5: 0x24df, + 0x10c6: 0x24df, 0x10c7: 0x24e6, 0x10c8: 0x24e6, 0x10c9: 0x2510, 0x10ca: 0x2517, 0x10cb: 0x251e, + 0x10cc: 0x24f4, 0x10cd: 0x2502, 0x10ce: 0x2525, 0x10cf: 0x252c, + 0x10d2: 0x24fb, 0x10d3: 0x2580, 0x10d4: 0x2587, 0x10d5: 0x255d, 0x10d6: 0x2564, 0x10d7: 0x2548, + 0x10d8: 0x2548, 0x10d9: 0x254f, 0x10da: 0x2579, 0x10db: 0x2572, 0x10dc: 0x259c, 0x10dd: 0x259c, + 0x10de: 0x230a, 0x10df: 0x231f, 0x10e0: 0x2318, 0x10e1: 0x2342, 0x10e2: 0x233b, 0x10e3: 0x2365, + 0x10e4: 0x235e, 0x10e5: 0x2388, 0x10e6: 0x236c, 0x10e7: 0x2381, 0x10e8: 0x23b9, 0x10e9: 0x2406, + 0x10ea: 0x23ea, 0x10eb: 0x2429, 0x10ec: 0x24c3, 0x10ed: 0x24ed, 0x10ee: 0x2595, 0x10ef: 0x258e, + 0x10f0: 0x25a3, 0x10f1: 0x253a, 0x10f2: 0x24a0, 0x10f3: 0x256b, 0x10f4: 0x2492, 0x10f5: 0x24ca, + 0x10f6: 0x2461, 0x10f7: 0x24ae, 0x10f8: 0x2541, 0x10f9: 0x2533, 0x10fa: 0x24bc, 0x10fb: 0x24a7, + 0x10fc: 0x24bc, 0x10fd: 0x2541, 0x10fe: 0x2373, 0x10ff: 0x238f, + // Block 0x44, offset 0x1100 + 0x1100: 0x2509, 0x1101: 0x2484, 0x1102: 0x2303, 0x1103: 0x24a7, 0x1104: 0x244c, 0x1105: 0x241b, + 0x1106: 0x23c0, 0x1107: 0x2556, + 0x1130: 0x2414, 0x1131: 0x248b, 0x1132: 0x27bf, 0x1133: 0x27b6, 0x1134: 0x27ec, 0x1135: 0x27da, + 0x1136: 0x27c8, 0x1137: 0x27e3, 0x1138: 0x27f5, 0x1139: 0x240d, 0x113a: 0x2c7c, 0x113b: 0x2afc, + 0x113c: 0x27d1, + // Block 0x45, offset 0x1140 + 0x1150: 0x0019, 0x1151: 0x0483, + 0x1152: 0x0487, 0x1153: 0x0035, 0x1154: 0x0037, 0x1155: 0x0003, 0x1156: 0x003f, 0x1157: 0x04bf, + 0x1158: 0x04c3, 0x1159: 0x1b5c, + 0x1160: 0x8132, 0x1161: 0x8132, 0x1162: 0x8132, 0x1163: 0x8132, + 0x1164: 0x8132, 0x1165: 0x8132, 0x1166: 0x8132, 0x1167: 0x812d, 0x1168: 0x812d, 0x1169: 0x812d, + 0x116a: 0x812d, 0x116b: 0x812d, 0x116c: 0x812d, 0x116d: 0x812d, 0x116e: 0x8132, 0x116f: 0x8132, + 0x1170: 0x1873, 0x1171: 0x0443, 0x1172: 0x043f, 0x1173: 0x007f, 0x1174: 0x007f, 0x1175: 0x0011, + 0x1176: 0x0013, 0x1177: 0x00b7, 0x1178: 0x00bb, 0x1179: 0x04b7, 0x117a: 0x04bb, 0x117b: 0x04ab, + 0x117c: 0x04af, 0x117d: 0x0493, 0x117e: 0x0497, 0x117f: 0x048b, + // Block 0x46, offset 0x1180 + 0x1180: 0x048f, 0x1181: 0x049b, 0x1182: 0x049f, 0x1183: 0x04a3, 0x1184: 0x04a7, + 0x1187: 0x0077, 0x1188: 0x007b, 0x1189: 0x4269, 0x118a: 0x4269, 0x118b: 0x4269, + 0x118c: 0x4269, 0x118d: 0x007f, 0x118e: 0x007f, 0x118f: 0x007f, 0x1190: 0x0019, 0x1191: 0x0483, + 0x1192: 0x001d, 0x1194: 0x0037, 0x1195: 0x0035, 0x1196: 0x003f, 0x1197: 0x0003, + 0x1198: 0x0443, 0x1199: 0x0011, 0x119a: 0x0013, 0x119b: 0x00b7, 0x119c: 0x00bb, 0x119d: 0x04b7, + 0x119e: 0x04bb, 0x119f: 0x0007, 0x11a0: 0x000d, 0x11a1: 0x0015, 0x11a2: 0x0017, 0x11a3: 0x001b, + 0x11a4: 0x0039, 0x11a5: 0x003d, 0x11a6: 0x003b, 0x11a8: 0x0079, 0x11a9: 0x0009, + 0x11aa: 0x000b, 0x11ab: 0x0041, + 0x11b0: 0x42aa, 0x11b1: 0x442c, 0x11b2: 0x42af, 0x11b4: 0x42b4, + 0x11b6: 0x42b9, 0x11b7: 0x4432, 0x11b8: 0x42be, 0x11b9: 0x4438, 0x11ba: 0x42c3, 0x11bb: 0x443e, + 0x11bc: 0x42c8, 0x11bd: 0x4444, 0x11be: 0x42cd, 0x11bf: 0x444a, + // Block 0x47, offset 0x11c0 + 0x11c0: 0x0236, 0x11c1: 0x440e, 0x11c2: 0x440e, 0x11c3: 0x4414, 0x11c4: 0x4414, 0x11c5: 0x4456, + 0x11c6: 0x4456, 0x11c7: 0x441a, 0x11c8: 0x441a, 0x11c9: 0x4462, 0x11ca: 0x4462, 0x11cb: 0x4462, + 0x11cc: 0x4462, 0x11cd: 0x0239, 0x11ce: 0x0239, 0x11cf: 0x023c, 0x11d0: 0x023c, 0x11d1: 0x023c, + 0x11d2: 0x023c, 0x11d3: 0x023f, 0x11d4: 0x023f, 0x11d5: 0x0242, 0x11d6: 0x0242, 0x11d7: 0x0242, + 0x11d8: 0x0242, 0x11d9: 0x0245, 0x11da: 0x0245, 0x11db: 0x0245, 0x11dc: 0x0245, 0x11dd: 0x0248, + 0x11de: 0x0248, 0x11df: 0x0248, 0x11e0: 0x0248, 0x11e1: 0x024b, 0x11e2: 0x024b, 0x11e3: 0x024b, + 0x11e4: 0x024b, 0x11e5: 0x024e, 0x11e6: 0x024e, 0x11e7: 0x024e, 0x11e8: 0x024e, 0x11e9: 0x0251, + 0x11ea: 0x0251, 0x11eb: 0x0254, 0x11ec: 0x0254, 0x11ed: 0x0257, 0x11ee: 0x0257, 0x11ef: 0x025a, + 0x11f0: 0x025a, 0x11f1: 0x025d, 0x11f2: 0x025d, 0x11f3: 0x025d, 0x11f4: 0x025d, 0x11f5: 0x0260, + 0x11f6: 0x0260, 0x11f7: 0x0260, 0x11f8: 0x0260, 0x11f9: 0x0263, 0x11fa: 0x0263, 0x11fb: 0x0263, + 0x11fc: 0x0263, 0x11fd: 0x0266, 0x11fe: 0x0266, 0x11ff: 0x0266, + // Block 0x48, offset 0x1200 + 0x1200: 0x0266, 0x1201: 0x0269, 0x1202: 0x0269, 0x1203: 0x0269, 0x1204: 0x0269, 0x1205: 0x026c, + 0x1206: 0x026c, 0x1207: 0x026c, 0x1208: 0x026c, 0x1209: 0x026f, 0x120a: 0x026f, 0x120b: 0x026f, + 0x120c: 0x026f, 0x120d: 0x0272, 0x120e: 0x0272, 0x120f: 0x0272, 0x1210: 0x0272, 0x1211: 0x0275, + 0x1212: 0x0275, 0x1213: 0x0275, 0x1214: 0x0275, 0x1215: 0x0278, 0x1216: 0x0278, 0x1217: 0x0278, + 0x1218: 0x0278, 0x1219: 0x027b, 0x121a: 0x027b, 0x121b: 0x027b, 0x121c: 0x027b, 0x121d: 0x027e, + 0x121e: 0x027e, 0x121f: 0x027e, 0x1220: 0x027e, 0x1221: 0x0281, 0x1222: 0x0281, 0x1223: 0x0281, + 0x1224: 0x0281, 0x1225: 0x0284, 0x1226: 0x0284, 0x1227: 0x0284, 0x1228: 0x0284, 0x1229: 0x0287, + 0x122a: 0x0287, 0x122b: 0x0287, 0x122c: 0x0287, 0x122d: 0x028a, 0x122e: 0x028a, 0x122f: 0x028d, + 0x1230: 0x028d, 0x1231: 0x0290, 0x1232: 0x0290, 0x1233: 0x0290, 0x1234: 0x0290, 0x1235: 0x2e00, + 0x1236: 0x2e00, 0x1237: 0x2e08, 0x1238: 0x2e08, 0x1239: 0x2e10, 0x123a: 0x2e10, 0x123b: 0x1f82, + 0x123c: 0x1f82, + // Block 0x49, offset 0x1240 + 0x1240: 0x0081, 0x1241: 0x0083, 0x1242: 0x0085, 0x1243: 0x0087, 0x1244: 0x0089, 0x1245: 0x008b, + 0x1246: 0x008d, 0x1247: 0x008f, 0x1248: 0x0091, 0x1249: 0x0093, 0x124a: 0x0095, 0x124b: 0x0097, + 0x124c: 0x0099, 0x124d: 0x009b, 0x124e: 0x009d, 0x124f: 0x009f, 0x1250: 0x00a1, 0x1251: 0x00a3, + 0x1252: 0x00a5, 0x1253: 0x00a7, 0x1254: 0x00a9, 0x1255: 0x00ab, 0x1256: 0x00ad, 0x1257: 0x00af, + 0x1258: 0x00b1, 0x1259: 0x00b3, 0x125a: 0x00b5, 0x125b: 0x00b7, 0x125c: 0x00b9, 0x125d: 0x00bb, + 0x125e: 0x00bd, 0x125f: 0x0477, 0x1260: 0x047b, 0x1261: 0x0487, 0x1262: 0x049b, 0x1263: 0x049f, + 0x1264: 0x0483, 0x1265: 0x05ab, 0x1266: 0x05a3, 0x1267: 0x04c7, 0x1268: 0x04cf, 0x1269: 0x04d7, + 0x126a: 0x04df, 0x126b: 0x04e7, 0x126c: 0x056b, 0x126d: 0x0573, 0x126e: 0x057b, 0x126f: 0x051f, + 0x1270: 0x05af, 0x1271: 0x04cb, 0x1272: 0x04d3, 0x1273: 0x04db, 0x1274: 0x04e3, 0x1275: 0x04eb, + 0x1276: 0x04ef, 0x1277: 0x04f3, 0x1278: 0x04f7, 0x1279: 0x04fb, 0x127a: 0x04ff, 0x127b: 0x0503, + 0x127c: 0x0507, 0x127d: 0x050b, 0x127e: 0x050f, 0x127f: 0x0513, + // Block 0x4a, offset 0x1280 + 0x1280: 0x0517, 0x1281: 0x051b, 0x1282: 0x0523, 0x1283: 0x0527, 0x1284: 0x052b, 0x1285: 0x052f, + 0x1286: 0x0533, 0x1287: 0x0537, 0x1288: 0x053b, 0x1289: 0x053f, 0x128a: 0x0543, 0x128b: 0x0547, + 0x128c: 0x054b, 0x128d: 0x054f, 0x128e: 0x0553, 0x128f: 0x0557, 0x1290: 0x055b, 0x1291: 0x055f, + 0x1292: 0x0563, 0x1293: 0x0567, 0x1294: 0x056f, 0x1295: 0x0577, 0x1296: 0x057f, 0x1297: 0x0583, + 0x1298: 0x0587, 0x1299: 0x058b, 0x129a: 0x058f, 0x129b: 0x0593, 0x129c: 0x0597, 0x129d: 0x05a7, + 0x129e: 0x4a78, 0x129f: 0x4a7e, 0x12a0: 0x03c3, 0x12a1: 0x0313, 0x12a2: 0x0317, 0x12a3: 0x4a3b, + 0x12a4: 0x031b, 0x12a5: 0x4a41, 0x12a6: 0x4a47, 0x12a7: 0x031f, 0x12a8: 0x0323, 0x12a9: 0x0327, + 0x12aa: 0x4a4d, 0x12ab: 0x4a53, 0x12ac: 0x4a59, 0x12ad: 0x4a5f, 0x12ae: 0x4a65, 0x12af: 0x4a6b, + 0x12b0: 0x0367, 0x12b1: 0x032b, 0x12b2: 0x032f, 0x12b3: 0x0333, 0x12b4: 0x037b, 0x12b5: 0x0337, + 0x12b6: 0x033b, 0x12b7: 0x033f, 0x12b8: 0x0343, 0x12b9: 0x0347, 0x12ba: 0x034b, 0x12bb: 0x034f, + 0x12bc: 0x0353, 0x12bd: 0x0357, 0x12be: 0x035b, + // Block 0x4b, offset 0x12c0 + 0x12c2: 0x49bd, 0x12c3: 0x49c3, 0x12c4: 0x49c9, 0x12c5: 0x49cf, + 0x12c6: 0x49d5, 0x12c7: 0x49db, 0x12ca: 0x49e1, 0x12cb: 0x49e7, + 0x12cc: 0x49ed, 0x12cd: 0x49f3, 0x12ce: 0x49f9, 0x12cf: 0x49ff, + 0x12d2: 0x4a05, 0x12d3: 0x4a0b, 0x12d4: 0x4a11, 0x12d5: 0x4a17, 0x12d6: 0x4a1d, 0x12d7: 0x4a23, + 0x12da: 0x4a29, 0x12db: 0x4a2f, 0x12dc: 0x4a35, + 0x12e0: 0x00bf, 0x12e1: 0x00c2, 0x12e2: 0x00cb, 0x12e3: 0x4264, + 0x12e4: 0x00c8, 0x12e5: 0x00c5, 0x12e6: 0x0447, 0x12e8: 0x046b, 0x12e9: 0x044b, + 0x12ea: 0x044f, 0x12eb: 0x0453, 0x12ec: 0x0457, 0x12ed: 0x046f, 0x12ee: 0x0473, + // Block 0x4c, offset 0x1300 + 0x1300: 0x0063, 0x1301: 0x0065, 0x1302: 0x0067, 0x1303: 0x0069, 0x1304: 0x006b, 0x1305: 0x006d, + 0x1306: 0x006f, 0x1307: 0x0071, 0x1308: 0x0073, 0x1309: 0x0075, 0x130a: 0x0083, 0x130b: 0x0085, + 0x130c: 0x0087, 0x130d: 0x0089, 0x130e: 0x008b, 0x130f: 0x008d, 0x1310: 0x008f, 0x1311: 0x0091, + 0x1312: 0x0093, 0x1313: 0x0095, 0x1314: 0x0097, 0x1315: 0x0099, 0x1316: 0x009b, 0x1317: 0x009d, + 0x1318: 0x009f, 0x1319: 0x00a1, 0x131a: 0x00a3, 0x131b: 0x00a5, 0x131c: 0x00a7, 0x131d: 0x00a9, + 0x131e: 0x00ab, 0x131f: 0x00ad, 0x1320: 0x00af, 0x1321: 0x00b1, 0x1322: 0x00b3, 0x1323: 0x00b5, + 0x1324: 0x00dd, 0x1325: 0x00f2, 0x1328: 0x0173, 0x1329: 0x0176, + 0x132a: 0x0179, 0x132b: 0x017c, 0x132c: 0x017f, 0x132d: 0x0182, 0x132e: 0x0185, 0x132f: 0x0188, + 0x1330: 0x018b, 0x1331: 0x018e, 0x1332: 0x0191, 0x1333: 0x0194, 0x1334: 0x0197, 0x1335: 0x019a, + 0x1336: 0x019d, 0x1337: 0x01a0, 0x1338: 0x01a3, 0x1339: 0x0188, 0x133a: 0x01a6, 0x133b: 0x01a9, + 0x133c: 0x01ac, 0x133d: 0x01af, 0x133e: 0x01b2, 0x133f: 0x01b5, + // Block 0x4d, offset 0x1340 + 0x1340: 0x01fd, 0x1341: 0x0200, 0x1342: 0x0203, 0x1343: 0x045b, 0x1344: 0x01c7, 0x1345: 0x01d0, + 0x1346: 0x01d6, 0x1347: 0x01fa, 0x1348: 0x01eb, 0x1349: 0x01e8, 0x134a: 0x0206, 0x134b: 0x0209, + 0x134e: 0x0021, 0x134f: 0x0023, 0x1350: 0x0025, 0x1351: 0x0027, + 0x1352: 0x0029, 0x1353: 0x002b, 0x1354: 0x002d, 0x1355: 0x002f, 0x1356: 0x0031, 0x1357: 0x0033, + 0x1358: 0x0021, 0x1359: 0x0023, 0x135a: 0x0025, 0x135b: 0x0027, 0x135c: 0x0029, 0x135d: 0x002b, + 0x135e: 0x002d, 0x135f: 0x002f, 0x1360: 0x0031, 0x1361: 0x0033, 0x1362: 0x0021, 0x1363: 0x0023, + 0x1364: 0x0025, 0x1365: 0x0027, 0x1366: 0x0029, 0x1367: 0x002b, 0x1368: 0x002d, 0x1369: 0x002f, + 0x136a: 0x0031, 0x136b: 0x0033, 0x136c: 0x0021, 0x136d: 0x0023, 0x136e: 0x0025, 0x136f: 0x0027, + 0x1370: 0x0029, 0x1371: 0x002b, 0x1372: 0x002d, 0x1373: 0x002f, 0x1374: 0x0031, 0x1375: 0x0033, + 0x1376: 0x0021, 0x1377: 0x0023, 0x1378: 0x0025, 0x1379: 0x0027, 0x137a: 0x0029, 0x137b: 0x002b, + 0x137c: 0x002d, 0x137d: 0x002f, 0x137e: 0x0031, 0x137f: 0x0033, + // Block 0x4e, offset 0x1380 + 0x1380: 0x0239, 0x1381: 0x023c, 0x1382: 0x0248, 0x1383: 0x0251, 0x1385: 0x028a, + 0x1386: 0x025a, 0x1387: 0x024b, 0x1388: 0x0269, 0x1389: 0x0290, 0x138a: 0x027b, 0x138b: 0x027e, + 0x138c: 0x0281, 0x138d: 0x0284, 0x138e: 0x025d, 0x138f: 0x026f, 0x1390: 0x0275, 0x1391: 0x0263, + 0x1392: 0x0278, 0x1393: 0x0257, 0x1394: 0x0260, 0x1395: 0x0242, 0x1396: 0x0245, 0x1397: 0x024e, + 0x1398: 0x0254, 0x1399: 0x0266, 0x139a: 0x026c, 0x139b: 0x0272, 0x139c: 0x0293, 0x139d: 0x02e4, + 0x139e: 0x02cc, 0x139f: 0x0296, 0x13a1: 0x023c, 0x13a2: 0x0248, + 0x13a4: 0x0287, 0x13a7: 0x024b, 0x13a9: 0x0290, + 0x13aa: 0x027b, 0x13ab: 0x027e, 0x13ac: 0x0281, 0x13ad: 0x0284, 0x13ae: 0x025d, 0x13af: 0x026f, + 0x13b0: 0x0275, 0x13b1: 0x0263, 0x13b2: 0x0278, 0x13b4: 0x0260, 0x13b5: 0x0242, + 0x13b6: 0x0245, 0x13b7: 0x024e, 0x13b9: 0x0266, 0x13bb: 0x0272, + // Block 0x4f, offset 0x13c0 + 0x13c2: 0x0248, + 0x13c7: 0x024b, 0x13c9: 0x0290, 0x13cb: 0x027e, + 0x13cd: 0x0284, 0x13ce: 0x025d, 0x13cf: 0x026f, 0x13d1: 0x0263, + 0x13d2: 0x0278, 0x13d4: 0x0260, 0x13d7: 0x024e, + 0x13d9: 0x0266, 0x13db: 0x0272, 0x13dd: 0x02e4, + 0x13df: 0x0296, 0x13e1: 0x023c, 0x13e2: 0x0248, + 0x13e4: 0x0287, 0x13e7: 0x024b, 0x13e8: 0x0269, 0x13e9: 0x0290, + 0x13ea: 0x027b, 0x13ec: 0x0281, 0x13ed: 0x0284, 0x13ee: 0x025d, 0x13ef: 0x026f, + 0x13f0: 0x0275, 0x13f1: 0x0263, 0x13f2: 0x0278, 0x13f4: 0x0260, 0x13f5: 0x0242, + 0x13f6: 0x0245, 0x13f7: 0x024e, 0x13f9: 0x0266, 0x13fa: 0x026c, 0x13fb: 0x0272, + 0x13fc: 0x0293, 0x13fe: 0x02cc, + // Block 0x50, offset 0x1400 + 0x1400: 0x0239, 0x1401: 0x023c, 0x1402: 0x0248, 0x1403: 0x0251, 0x1404: 0x0287, 0x1405: 0x028a, + 0x1406: 0x025a, 0x1407: 0x024b, 0x1408: 0x0269, 0x1409: 0x0290, 0x140b: 0x027e, + 0x140c: 0x0281, 0x140d: 0x0284, 0x140e: 0x025d, 0x140f: 0x026f, 0x1410: 0x0275, 0x1411: 0x0263, + 0x1412: 0x0278, 0x1413: 0x0257, 0x1414: 0x0260, 0x1415: 0x0242, 0x1416: 0x0245, 0x1417: 0x024e, + 0x1418: 0x0254, 0x1419: 0x0266, 0x141a: 0x026c, 0x141b: 0x0272, + 0x1421: 0x023c, 0x1422: 0x0248, 0x1423: 0x0251, + 0x1425: 0x028a, 0x1426: 0x025a, 0x1427: 0x024b, 0x1428: 0x0269, 0x1429: 0x0290, + 0x142b: 0x027e, 0x142c: 0x0281, 0x142d: 0x0284, 0x142e: 0x025d, 0x142f: 0x026f, + 0x1430: 0x0275, 0x1431: 0x0263, 0x1432: 0x0278, 0x1433: 0x0257, 0x1434: 0x0260, 0x1435: 0x0242, + 0x1436: 0x0245, 0x1437: 0x024e, 0x1438: 0x0254, 0x1439: 0x0266, 0x143a: 0x026c, 0x143b: 0x0272, + // Block 0x51, offset 0x1440 + 0x1440: 0x1879, 0x1441: 0x1876, 0x1442: 0x187c, 0x1443: 0x18a0, 0x1444: 0x18c4, 0x1445: 0x18e8, + 0x1446: 0x190c, 0x1447: 0x1915, 0x1448: 0x191b, 0x1449: 0x1921, 0x144a: 0x1927, + 0x1450: 0x1a8c, 0x1451: 0x1a90, + 0x1452: 0x1a94, 0x1453: 0x1a98, 0x1454: 0x1a9c, 0x1455: 0x1aa0, 0x1456: 0x1aa4, 0x1457: 0x1aa8, + 0x1458: 0x1aac, 0x1459: 0x1ab0, 0x145a: 0x1ab4, 0x145b: 0x1ab8, 0x145c: 0x1abc, 0x145d: 0x1ac0, + 0x145e: 0x1ac4, 0x145f: 0x1ac8, 0x1460: 0x1acc, 0x1461: 0x1ad0, 0x1462: 0x1ad4, 0x1463: 0x1ad8, + 0x1464: 0x1adc, 0x1465: 0x1ae0, 0x1466: 0x1ae4, 0x1467: 0x1ae8, 0x1468: 0x1aec, 0x1469: 0x1af0, + 0x146a: 0x271e, 0x146b: 0x0047, 0x146c: 0x0065, 0x146d: 0x193c, 0x146e: 0x19b1, + 0x1470: 0x0043, 0x1471: 0x0045, 0x1472: 0x0047, 0x1473: 0x0049, 0x1474: 0x004b, 0x1475: 0x004d, + 0x1476: 0x004f, 0x1477: 0x0051, 0x1478: 0x0053, 0x1479: 0x0055, 0x147a: 0x0057, 0x147b: 0x0059, + 0x147c: 0x005b, 0x147d: 0x005d, 0x147e: 0x005f, 0x147f: 0x0061, + // Block 0x52, offset 0x1480 + 0x1480: 0x26ad, 0x1481: 0x26c2, 0x1482: 0x0503, + 0x1490: 0x0c0f, 0x1491: 0x0a47, + 0x1492: 0x08d3, 0x1493: 0x45c4, 0x1494: 0x071b, 0x1495: 0x09ef, 0x1496: 0x132f, 0x1497: 0x09ff, + 0x1498: 0x0727, 0x1499: 0x0cd7, 0x149a: 0x0eaf, 0x149b: 0x0caf, 0x149c: 0x0827, 0x149d: 0x0b6b, + 0x149e: 0x07bf, 0x149f: 0x0cb7, 0x14a0: 0x0813, 0x14a1: 0x1117, 0x14a2: 0x0f83, 0x14a3: 0x138b, + 0x14a4: 0x09d3, 0x14a5: 0x090b, 0x14a6: 0x0e63, 0x14a7: 0x0c1b, 0x14a8: 0x0c47, 0x14a9: 0x06bf, + 0x14aa: 0x06cb, 0x14ab: 0x140b, 0x14ac: 0x0adb, 0x14ad: 0x06e7, 0x14ae: 0x08ef, 0x14af: 0x0c3b, + 0x14b0: 0x13b3, 0x14b1: 0x0c13, 0x14b2: 0x106f, 0x14b3: 0x10ab, 0x14b4: 0x08f7, 0x14b5: 0x0e43, + 0x14b6: 0x0d0b, 0x14b7: 0x0d07, 0x14b8: 0x0f97, 0x14b9: 0x082b, 0x14ba: 0x0957, 0x14bb: 0x1443, + // Block 0x53, offset 0x14c0 + 0x14c0: 0x06fb, 0x14c1: 0x06f3, 0x14c2: 0x0703, 0x14c3: 0x1647, 0x14c4: 0x0747, 0x14c5: 0x0757, + 0x14c6: 0x075b, 0x14c7: 0x0763, 0x14c8: 0x076b, 0x14c9: 0x076f, 0x14ca: 0x077b, 0x14cb: 0x0773, + 0x14cc: 0x05b3, 0x14cd: 0x165b, 0x14ce: 0x078f, 0x14cf: 0x0793, 0x14d0: 0x0797, 0x14d1: 0x07b3, + 0x14d2: 0x164c, 0x14d3: 0x05b7, 0x14d4: 0x079f, 0x14d5: 0x07bf, 0x14d6: 0x1656, 0x14d7: 0x07cf, + 0x14d8: 0x07d7, 0x14d9: 0x0737, 0x14da: 0x07df, 0x14db: 0x07e3, 0x14dc: 0x1831, 0x14dd: 0x07ff, + 0x14de: 0x0807, 0x14df: 0x05bf, 0x14e0: 0x081f, 0x14e1: 0x0823, 0x14e2: 0x082b, 0x14e3: 0x082f, + 0x14e4: 0x05c3, 0x14e5: 0x0847, 0x14e6: 0x084b, 0x14e7: 0x0857, 0x14e8: 0x0863, 0x14e9: 0x0867, + 0x14ea: 0x086b, 0x14eb: 0x0873, 0x14ec: 0x0893, 0x14ed: 0x0897, 0x14ee: 0x089f, 0x14ef: 0x08af, + 0x14f0: 0x08b7, 0x14f1: 0x08bb, 0x14f2: 0x08bb, 0x14f3: 0x08bb, 0x14f4: 0x166a, 0x14f5: 0x0e93, + 0x14f6: 0x08cf, 0x14f7: 0x08d7, 0x14f8: 0x166f, 0x14f9: 0x08e3, 0x14fa: 0x08eb, 0x14fb: 0x08f3, + 0x14fc: 0x091b, 0x14fd: 0x0907, 0x14fe: 0x0913, 0x14ff: 0x0917, + // Block 0x54, offset 0x1500 + 0x1500: 0x091f, 0x1501: 0x0927, 0x1502: 0x092b, 0x1503: 0x0933, 0x1504: 0x093b, 0x1505: 0x093f, + 0x1506: 0x093f, 0x1507: 0x0947, 0x1508: 0x094f, 0x1509: 0x0953, 0x150a: 0x095f, 0x150b: 0x0983, + 0x150c: 0x0967, 0x150d: 0x0987, 0x150e: 0x096b, 0x150f: 0x0973, 0x1510: 0x080b, 0x1511: 0x09cf, + 0x1512: 0x0997, 0x1513: 0x099b, 0x1514: 0x099f, 0x1515: 0x0993, 0x1516: 0x09a7, 0x1517: 0x09a3, + 0x1518: 0x09bb, 0x1519: 0x1674, 0x151a: 0x09d7, 0x151b: 0x09db, 0x151c: 0x09e3, 0x151d: 0x09ef, + 0x151e: 0x09f7, 0x151f: 0x0a13, 0x1520: 0x1679, 0x1521: 0x167e, 0x1522: 0x0a1f, 0x1523: 0x0a23, + 0x1524: 0x0a27, 0x1525: 0x0a1b, 0x1526: 0x0a2f, 0x1527: 0x05c7, 0x1528: 0x05cb, 0x1529: 0x0a37, + 0x152a: 0x0a3f, 0x152b: 0x0a3f, 0x152c: 0x1683, 0x152d: 0x0a5b, 0x152e: 0x0a5f, 0x152f: 0x0a63, + 0x1530: 0x0a6b, 0x1531: 0x1688, 0x1532: 0x0a73, 0x1533: 0x0a77, 0x1534: 0x0b4f, 0x1535: 0x0a7f, + 0x1536: 0x05cf, 0x1537: 0x0a8b, 0x1538: 0x0a9b, 0x1539: 0x0aa7, 0x153a: 0x0aa3, 0x153b: 0x1692, + 0x153c: 0x0aaf, 0x153d: 0x1697, 0x153e: 0x0abb, 0x153f: 0x0ab7, + // Block 0x55, offset 0x1540 + 0x1540: 0x0abf, 0x1541: 0x0acf, 0x1542: 0x0ad3, 0x1543: 0x05d3, 0x1544: 0x0ae3, 0x1545: 0x0aeb, + 0x1546: 0x0aef, 0x1547: 0x0af3, 0x1548: 0x05d7, 0x1549: 0x169c, 0x154a: 0x05db, 0x154b: 0x0b0f, + 0x154c: 0x0b13, 0x154d: 0x0b17, 0x154e: 0x0b1f, 0x154f: 0x1863, 0x1550: 0x0b37, 0x1551: 0x16a6, + 0x1552: 0x16a6, 0x1553: 0x11d7, 0x1554: 0x0b47, 0x1555: 0x0b47, 0x1556: 0x05df, 0x1557: 0x16c9, + 0x1558: 0x179b, 0x1559: 0x0b57, 0x155a: 0x0b5f, 0x155b: 0x05e3, 0x155c: 0x0b73, 0x155d: 0x0b83, + 0x155e: 0x0b87, 0x155f: 0x0b8f, 0x1560: 0x0b9f, 0x1561: 0x05eb, 0x1562: 0x05e7, 0x1563: 0x0ba3, + 0x1564: 0x16ab, 0x1565: 0x0ba7, 0x1566: 0x0bbb, 0x1567: 0x0bbf, 0x1568: 0x0bc3, 0x1569: 0x0bbf, + 0x156a: 0x0bcf, 0x156b: 0x0bd3, 0x156c: 0x0be3, 0x156d: 0x0bdb, 0x156e: 0x0bdf, 0x156f: 0x0be7, + 0x1570: 0x0beb, 0x1571: 0x0bef, 0x1572: 0x0bfb, 0x1573: 0x0bff, 0x1574: 0x0c17, 0x1575: 0x0c1f, + 0x1576: 0x0c2f, 0x1577: 0x0c43, 0x1578: 0x16ba, 0x1579: 0x0c3f, 0x157a: 0x0c33, 0x157b: 0x0c4b, + 0x157c: 0x0c53, 0x157d: 0x0c67, 0x157e: 0x16bf, 0x157f: 0x0c6f, + // Block 0x56, offset 0x1580 + 0x1580: 0x0c63, 0x1581: 0x0c5b, 0x1582: 0x05ef, 0x1583: 0x0c77, 0x1584: 0x0c7f, 0x1585: 0x0c87, + 0x1586: 0x0c7b, 0x1587: 0x05f3, 0x1588: 0x0c97, 0x1589: 0x0c9f, 0x158a: 0x16c4, 0x158b: 0x0ccb, + 0x158c: 0x0cff, 0x158d: 0x0cdb, 0x158e: 0x05ff, 0x158f: 0x0ce7, 0x1590: 0x05fb, 0x1591: 0x05f7, + 0x1592: 0x07c3, 0x1593: 0x07c7, 0x1594: 0x0d03, 0x1595: 0x0ceb, 0x1596: 0x11ab, 0x1597: 0x0663, + 0x1598: 0x0d0f, 0x1599: 0x0d13, 0x159a: 0x0d17, 0x159b: 0x0d2b, 0x159c: 0x0d23, 0x159d: 0x16dd, + 0x159e: 0x0603, 0x159f: 0x0d3f, 0x15a0: 0x0d33, 0x15a1: 0x0d4f, 0x15a2: 0x0d57, 0x15a3: 0x16e7, + 0x15a4: 0x0d5b, 0x15a5: 0x0d47, 0x15a6: 0x0d63, 0x15a7: 0x0607, 0x15a8: 0x0d67, 0x15a9: 0x0d6b, + 0x15aa: 0x0d6f, 0x15ab: 0x0d7b, 0x15ac: 0x16ec, 0x15ad: 0x0d83, 0x15ae: 0x060b, 0x15af: 0x0d8f, + 0x15b0: 0x16f1, 0x15b1: 0x0d93, 0x15b2: 0x060f, 0x15b3: 0x0d9f, 0x15b4: 0x0dab, 0x15b5: 0x0db7, + 0x15b6: 0x0dbb, 0x15b7: 0x16f6, 0x15b8: 0x168d, 0x15b9: 0x16fb, 0x15ba: 0x0ddb, 0x15bb: 0x1700, + 0x15bc: 0x0de7, 0x15bd: 0x0def, 0x15be: 0x0ddf, 0x15bf: 0x0dfb, + // Block 0x57, offset 0x15c0 + 0x15c0: 0x0e0b, 0x15c1: 0x0e1b, 0x15c2: 0x0e0f, 0x15c3: 0x0e13, 0x15c4: 0x0e1f, 0x15c5: 0x0e23, + 0x15c6: 0x1705, 0x15c7: 0x0e07, 0x15c8: 0x0e3b, 0x15c9: 0x0e3f, 0x15ca: 0x0613, 0x15cb: 0x0e53, + 0x15cc: 0x0e4f, 0x15cd: 0x170a, 0x15ce: 0x0e33, 0x15cf: 0x0e6f, 0x15d0: 0x170f, 0x15d1: 0x1714, + 0x15d2: 0x0e73, 0x15d3: 0x0e87, 0x15d4: 0x0e83, 0x15d5: 0x0e7f, 0x15d6: 0x0617, 0x15d7: 0x0e8b, + 0x15d8: 0x0e9b, 0x15d9: 0x0e97, 0x15da: 0x0ea3, 0x15db: 0x1651, 0x15dc: 0x0eb3, 0x15dd: 0x1719, + 0x15de: 0x0ebf, 0x15df: 0x1723, 0x15e0: 0x0ed3, 0x15e1: 0x0edf, 0x15e2: 0x0ef3, 0x15e3: 0x1728, + 0x15e4: 0x0f07, 0x15e5: 0x0f0b, 0x15e6: 0x172d, 0x15e7: 0x1732, 0x15e8: 0x0f27, 0x15e9: 0x0f37, + 0x15ea: 0x061b, 0x15eb: 0x0f3b, 0x15ec: 0x061f, 0x15ed: 0x061f, 0x15ee: 0x0f53, 0x15ef: 0x0f57, + 0x15f0: 0x0f5f, 0x15f1: 0x0f63, 0x15f2: 0x0f6f, 0x15f3: 0x0623, 0x15f4: 0x0f87, 0x15f5: 0x1737, + 0x15f6: 0x0fa3, 0x15f7: 0x173c, 0x15f8: 0x0faf, 0x15f9: 0x16a1, 0x15fa: 0x0fbf, 0x15fb: 0x1741, + 0x15fc: 0x1746, 0x15fd: 0x174b, 0x15fe: 0x0627, 0x15ff: 0x062b, + // Block 0x58, offset 0x1600 + 0x1600: 0x0ff7, 0x1601: 0x1755, 0x1602: 0x1750, 0x1603: 0x175a, 0x1604: 0x175f, 0x1605: 0x0fff, + 0x1606: 0x1003, 0x1607: 0x1003, 0x1608: 0x100b, 0x1609: 0x0633, 0x160a: 0x100f, 0x160b: 0x0637, + 0x160c: 0x063b, 0x160d: 0x1769, 0x160e: 0x1023, 0x160f: 0x102b, 0x1610: 0x1037, 0x1611: 0x063f, + 0x1612: 0x176e, 0x1613: 0x105b, 0x1614: 0x1773, 0x1615: 0x1778, 0x1616: 0x107b, 0x1617: 0x1093, + 0x1618: 0x0643, 0x1619: 0x109b, 0x161a: 0x109f, 0x161b: 0x10a3, 0x161c: 0x177d, 0x161d: 0x1782, + 0x161e: 0x1782, 0x161f: 0x10bb, 0x1620: 0x0647, 0x1621: 0x1787, 0x1622: 0x10cf, 0x1623: 0x10d3, + 0x1624: 0x064b, 0x1625: 0x178c, 0x1626: 0x10ef, 0x1627: 0x064f, 0x1628: 0x10ff, 0x1629: 0x10f7, + 0x162a: 0x1107, 0x162b: 0x1796, 0x162c: 0x111f, 0x162d: 0x0653, 0x162e: 0x112b, 0x162f: 0x1133, + 0x1630: 0x1143, 0x1631: 0x0657, 0x1632: 0x17a0, 0x1633: 0x17a5, 0x1634: 0x065b, 0x1635: 0x17aa, + 0x1636: 0x115b, 0x1637: 0x17af, 0x1638: 0x1167, 0x1639: 0x1173, 0x163a: 0x117b, 0x163b: 0x17b4, + 0x163c: 0x17b9, 0x163d: 0x118f, 0x163e: 0x17be, 0x163f: 0x1197, + // Block 0x59, offset 0x1640 + 0x1640: 0x16ce, 0x1641: 0x065f, 0x1642: 0x11af, 0x1643: 0x11b3, 0x1644: 0x0667, 0x1645: 0x11b7, + 0x1646: 0x0a33, 0x1647: 0x17c3, 0x1648: 0x17c8, 0x1649: 0x16d3, 0x164a: 0x16d8, 0x164b: 0x11d7, + 0x164c: 0x11db, 0x164d: 0x13f3, 0x164e: 0x066b, 0x164f: 0x1207, 0x1650: 0x1203, 0x1651: 0x120b, + 0x1652: 0x083f, 0x1653: 0x120f, 0x1654: 0x1213, 0x1655: 0x1217, 0x1656: 0x121f, 0x1657: 0x17cd, + 0x1658: 0x121b, 0x1659: 0x1223, 0x165a: 0x1237, 0x165b: 0x123b, 0x165c: 0x1227, 0x165d: 0x123f, + 0x165e: 0x1253, 0x165f: 0x1267, 0x1660: 0x1233, 0x1661: 0x1247, 0x1662: 0x124b, 0x1663: 0x124f, + 0x1664: 0x17d2, 0x1665: 0x17dc, 0x1666: 0x17d7, 0x1667: 0x066f, 0x1668: 0x126f, 0x1669: 0x1273, + 0x166a: 0x127b, 0x166b: 0x17f0, 0x166c: 0x127f, 0x166d: 0x17e1, 0x166e: 0x0673, 0x166f: 0x0677, + 0x1670: 0x17e6, 0x1671: 0x17eb, 0x1672: 0x067b, 0x1673: 0x129f, 0x1674: 0x12a3, 0x1675: 0x12a7, + 0x1676: 0x12ab, 0x1677: 0x12b7, 0x1678: 0x12b3, 0x1679: 0x12bf, 0x167a: 0x12bb, 0x167b: 0x12cb, + 0x167c: 0x12c3, 0x167d: 0x12c7, 0x167e: 0x12cf, 0x167f: 0x067f, + // Block 0x5a, offset 0x1680 + 0x1680: 0x12d7, 0x1681: 0x12db, 0x1682: 0x0683, 0x1683: 0x12eb, 0x1684: 0x12ef, 0x1685: 0x17f5, + 0x1686: 0x12fb, 0x1687: 0x12ff, 0x1688: 0x0687, 0x1689: 0x130b, 0x168a: 0x05bb, 0x168b: 0x17fa, + 0x168c: 0x17ff, 0x168d: 0x068b, 0x168e: 0x068f, 0x168f: 0x1337, 0x1690: 0x134f, 0x1691: 0x136b, + 0x1692: 0x137b, 0x1693: 0x1804, 0x1694: 0x138f, 0x1695: 0x1393, 0x1696: 0x13ab, 0x1697: 0x13b7, + 0x1698: 0x180e, 0x1699: 0x1660, 0x169a: 0x13c3, 0x169b: 0x13bf, 0x169c: 0x13cb, 0x169d: 0x1665, + 0x169e: 0x13d7, 0x169f: 0x13e3, 0x16a0: 0x1813, 0x16a1: 0x1818, 0x16a2: 0x1423, 0x16a3: 0x142f, + 0x16a4: 0x1437, 0x16a5: 0x181d, 0x16a6: 0x143b, 0x16a7: 0x1467, 0x16a8: 0x1473, 0x16a9: 0x1477, + 0x16aa: 0x146f, 0x16ab: 0x1483, 0x16ac: 0x1487, 0x16ad: 0x1822, 0x16ae: 0x1493, 0x16af: 0x0693, + 0x16b0: 0x149b, 0x16b1: 0x1827, 0x16b2: 0x0697, 0x16b3: 0x14d3, 0x16b4: 0x0ac3, 0x16b5: 0x14eb, + 0x16b6: 0x182c, 0x16b7: 0x1836, 0x16b8: 0x069b, 0x16b9: 0x069f, 0x16ba: 0x1513, 0x16bb: 0x183b, + 0x16bc: 0x06a3, 0x16bd: 0x1840, 0x16be: 0x152b, 0x16bf: 0x152b, + // Block 0x5b, offset 0x16c0 + 0x16c0: 0x1533, 0x16c1: 0x1845, 0x16c2: 0x154b, 0x16c3: 0x06a7, 0x16c4: 0x155b, 0x16c5: 0x1567, + 0x16c6: 0x156f, 0x16c7: 0x1577, 0x16c8: 0x06ab, 0x16c9: 0x184a, 0x16ca: 0x158b, 0x16cb: 0x15a7, + 0x16cc: 0x15b3, 0x16cd: 0x06af, 0x16ce: 0x06b3, 0x16cf: 0x15b7, 0x16d0: 0x184f, 0x16d1: 0x06b7, + 0x16d2: 0x1854, 0x16d3: 0x1859, 0x16d4: 0x185e, 0x16d5: 0x15db, 0x16d6: 0x06bb, 0x16d7: 0x15ef, + 0x16d8: 0x15f7, 0x16d9: 0x15fb, 0x16da: 0x1603, 0x16db: 0x160b, 0x16dc: 0x1613, 0x16dd: 0x1868, +} + +// nfkcIndex: 22 blocks, 1408 entries, 1408 bytes +// Block 0 is the zero block. +var nfkcIndex = [1408]uint8{ + // Block 0x0, offset 0x0 + // Block 0x1, offset 0x40 + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0xc2: 0x5a, 0xc3: 0x01, 0xc4: 0x02, 0xc5: 0x03, 0xc6: 0x5b, 0xc7: 0x04, + 0xc8: 0x05, 0xca: 0x5c, 0xcb: 0x5d, 0xcc: 0x06, 0xcd: 0x07, 0xce: 0x08, 0xcf: 0x09, + 0xd0: 0x0a, 0xd1: 0x5e, 0xd2: 0x5f, 0xd3: 0x0b, 0xd6: 0x0c, 0xd7: 0x60, + 0xd8: 0x61, 0xd9: 0x0d, 0xdb: 0x62, 0xdc: 0x63, 0xdd: 0x64, 0xdf: 0x65, + 0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05, + 0xea: 0x06, 0xeb: 0x07, 0xec: 0x08, 0xed: 0x09, 0xef: 0x0a, + 0xf0: 0x13, + // Block 0x4, offset 0x100 + 0x120: 0x66, 0x121: 0x67, 0x123: 0x68, 0x124: 0x69, 0x125: 0x6a, 0x126: 0x6b, 0x127: 0x6c, + 0x128: 0x6d, 0x129: 0x6e, 0x12a: 0x6f, 0x12b: 0x70, 0x12c: 0x6b, 0x12d: 0x71, 0x12e: 0x72, 0x12f: 0x73, + 0x131: 0x74, 0x132: 0x75, 0x133: 0x76, 0x134: 0x77, 0x135: 0x78, 0x137: 0x79, + 0x138: 0x7a, 0x139: 0x7b, 0x13a: 0x7c, 0x13b: 0x7d, 0x13c: 0x7e, 0x13d: 0x7f, 0x13e: 0x80, 0x13f: 0x81, + // Block 0x5, offset 0x140 + 0x140: 0x82, 0x142: 0x83, 0x143: 0x84, 0x144: 0x85, 0x145: 0x86, 0x146: 0x87, 0x147: 0x88, + 0x14d: 0x89, + 0x15c: 0x8a, 0x15f: 0x8b, + 0x162: 0x8c, 0x164: 0x8d, + 0x168: 0x8e, 0x169: 0x8f, 0x16a: 0x90, 0x16c: 0x0e, 0x16d: 0x91, 0x16e: 0x92, 0x16f: 0x93, + 0x170: 0x94, 0x173: 0x95, 0x174: 0x96, 0x175: 0x0f, 0x176: 0x10, 0x177: 0x97, + 0x178: 0x11, 0x179: 0x12, 0x17a: 0x13, 0x17b: 0x14, 0x17c: 0x15, 0x17d: 0x16, 0x17e: 0x17, 0x17f: 0x18, + // Block 0x6, offset 0x180 + 0x180: 0x98, 0x181: 0x99, 0x182: 0x9a, 0x183: 0x9b, 0x184: 0x19, 0x185: 0x1a, 0x186: 0x9c, 0x187: 0x9d, + 0x188: 0x9e, 0x189: 0x1b, 0x18a: 0x1c, 0x18b: 0x9f, 0x18c: 0xa0, + 0x191: 0x1d, 0x192: 0x1e, 0x193: 0xa1, + 0x1a8: 0xa2, 0x1a9: 0xa3, 0x1ab: 0xa4, + 0x1b1: 0xa5, 0x1b3: 0xa6, 0x1b5: 0xa7, 0x1b7: 0xa8, + 0x1ba: 0xa9, 0x1bb: 0xaa, 0x1bc: 0x1f, 0x1bd: 0x20, 0x1be: 0x21, 0x1bf: 0xab, + // Block 0x7, offset 0x1c0 + 0x1c0: 0xac, 0x1c1: 0x22, 0x1c2: 0x23, 0x1c3: 0x24, 0x1c4: 0xad, 0x1c5: 0x25, 0x1c6: 0x26, + 0x1c8: 0x27, 0x1c9: 0x28, 0x1ca: 0x29, 0x1cb: 0x2a, 0x1cc: 0x2b, 0x1cd: 0x2c, 0x1ce: 0x2d, 0x1cf: 0x2e, + // Block 0x8, offset 0x200 + 0x219: 0xae, 0x21a: 0xaf, 0x21b: 0xb0, 0x21d: 0xb1, 0x21f: 0xb2, + 0x220: 0xb3, 0x223: 0xb4, 0x224: 0xb5, 0x225: 0xb6, 0x226: 0xb7, 0x227: 0xb8, + 0x22a: 0xb9, 0x22b: 0xba, 0x22d: 0xbb, 0x22f: 0xbc, + 0x230: 0xbd, 0x231: 0xbe, 0x232: 0xbf, 0x233: 0xc0, 0x234: 0xc1, 0x235: 0xc2, 0x236: 0xc3, 0x237: 0xbd, + 0x238: 0xbe, 0x239: 0xbf, 0x23a: 0xc0, 0x23b: 0xc1, 0x23c: 0xc2, 0x23d: 0xc3, 0x23e: 0xbd, 0x23f: 0xbe, + // Block 0x9, offset 0x240 + 0x240: 0xbf, 0x241: 0xc0, 0x242: 0xc1, 0x243: 0xc2, 0x244: 0xc3, 0x245: 0xbd, 0x246: 0xbe, 0x247: 0xbf, + 0x248: 0xc0, 0x249: 0xc1, 0x24a: 0xc2, 0x24b: 0xc3, 0x24c: 0xbd, 0x24d: 0xbe, 0x24e: 0xbf, 0x24f: 0xc0, + 0x250: 0xc1, 0x251: 0xc2, 0x252: 0xc3, 0x253: 0xbd, 0x254: 0xbe, 0x255: 0xbf, 0x256: 0xc0, 0x257: 0xc1, + 0x258: 0xc2, 0x259: 0xc3, 0x25a: 0xbd, 0x25b: 0xbe, 0x25c: 0xbf, 0x25d: 0xc0, 0x25e: 0xc1, 0x25f: 0xc2, + 0x260: 0xc3, 0x261: 0xbd, 0x262: 0xbe, 0x263: 0xbf, 0x264: 0xc0, 0x265: 0xc1, 0x266: 0xc2, 0x267: 0xc3, + 0x268: 0xbd, 0x269: 0xbe, 0x26a: 0xbf, 0x26b: 0xc0, 0x26c: 0xc1, 0x26d: 0xc2, 0x26e: 0xc3, 0x26f: 0xbd, + 0x270: 0xbe, 0x271: 0xbf, 0x272: 0xc0, 0x273: 0xc1, 0x274: 0xc2, 0x275: 0xc3, 0x276: 0xbd, 0x277: 0xbe, + 0x278: 0xbf, 0x279: 0xc0, 0x27a: 0xc1, 0x27b: 0xc2, 0x27c: 0xc3, 0x27d: 0xbd, 0x27e: 0xbe, 0x27f: 0xbf, + // Block 0xa, offset 0x280 + 0x280: 0xc0, 0x281: 0xc1, 0x282: 0xc2, 0x283: 0xc3, 0x284: 0xbd, 0x285: 0xbe, 0x286: 0xbf, 0x287: 0xc0, + 0x288: 0xc1, 0x289: 0xc2, 0x28a: 0xc3, 0x28b: 0xbd, 0x28c: 0xbe, 0x28d: 0xbf, 0x28e: 0xc0, 0x28f: 0xc1, + 0x290: 0xc2, 0x291: 0xc3, 0x292: 0xbd, 0x293: 0xbe, 0x294: 0xbf, 0x295: 0xc0, 0x296: 0xc1, 0x297: 0xc2, + 0x298: 0xc3, 0x299: 0xbd, 0x29a: 0xbe, 0x29b: 0xbf, 0x29c: 0xc0, 0x29d: 0xc1, 0x29e: 0xc2, 0x29f: 0xc3, + 0x2a0: 0xbd, 0x2a1: 0xbe, 0x2a2: 0xbf, 0x2a3: 0xc0, 0x2a4: 0xc1, 0x2a5: 0xc2, 0x2a6: 0xc3, 0x2a7: 0xbd, + 0x2a8: 0xbe, 0x2a9: 0xbf, 0x2aa: 0xc0, 0x2ab: 0xc1, 0x2ac: 0xc2, 0x2ad: 0xc3, 0x2ae: 0xbd, 0x2af: 0xbe, + 0x2b0: 0xbf, 0x2b1: 0xc0, 0x2b2: 0xc1, 0x2b3: 0xc2, 0x2b4: 0xc3, 0x2b5: 0xbd, 0x2b6: 0xbe, 0x2b7: 0xbf, + 0x2b8: 0xc0, 0x2b9: 0xc1, 0x2ba: 0xc2, 0x2bb: 0xc3, 0x2bc: 0xbd, 0x2bd: 0xbe, 0x2be: 0xbf, 0x2bf: 0xc0, + // Block 0xb, offset 0x2c0 + 0x2c0: 0xc1, 0x2c1: 0xc2, 0x2c2: 0xc3, 0x2c3: 0xbd, 0x2c4: 0xbe, 0x2c5: 0xbf, 0x2c6: 0xc0, 0x2c7: 0xc1, + 0x2c8: 0xc2, 0x2c9: 0xc3, 0x2ca: 0xbd, 0x2cb: 0xbe, 0x2cc: 0xbf, 0x2cd: 0xc0, 0x2ce: 0xc1, 0x2cf: 0xc2, + 0x2d0: 0xc3, 0x2d1: 0xbd, 0x2d2: 0xbe, 0x2d3: 0xbf, 0x2d4: 0xc0, 0x2d5: 0xc1, 0x2d6: 0xc2, 0x2d7: 0xc3, + 0x2d8: 0xbd, 0x2d9: 0xbe, 0x2da: 0xbf, 0x2db: 0xc0, 0x2dc: 0xc1, 0x2dd: 0xc2, 0x2de: 0xc4, + // Block 0xc, offset 0x300 + 0x324: 0x2f, 0x325: 0x30, 0x326: 0x31, 0x327: 0x32, + 0x328: 0x33, 0x329: 0x34, 0x32a: 0x35, 0x32b: 0x36, 0x32c: 0x37, 0x32d: 0x38, 0x32e: 0x39, 0x32f: 0x3a, + 0x330: 0x3b, 0x331: 0x3c, 0x332: 0x3d, 0x333: 0x3e, 0x334: 0x3f, 0x335: 0x40, 0x336: 0x41, 0x337: 0x42, + 0x338: 0x43, 0x339: 0x44, 0x33a: 0x45, 0x33b: 0x46, 0x33c: 0xc5, 0x33d: 0x47, 0x33e: 0x48, 0x33f: 0x49, + // Block 0xd, offset 0x340 + 0x347: 0xc6, + 0x34b: 0xc7, 0x34d: 0xc8, + 0x368: 0xc9, 0x36b: 0xca, + // Block 0xe, offset 0x380 + 0x381: 0xcb, 0x382: 0xcc, 0x384: 0xcd, 0x385: 0xb7, 0x387: 0xce, + 0x388: 0xcf, 0x38b: 0xd0, 0x38c: 0x6b, 0x38d: 0xd1, + 0x391: 0xd2, 0x392: 0xd3, 0x393: 0xd4, 0x396: 0xd5, 0x397: 0xd6, + 0x398: 0xd7, 0x39a: 0xd8, 0x39c: 0xd9, + 0x3b0: 0xd7, + // Block 0xf, offset 0x3c0 + 0x3eb: 0xda, 0x3ec: 0xdb, + // Block 0x10, offset 0x400 + 0x432: 0xdc, + // Block 0x11, offset 0x440 + 0x445: 0xdd, 0x446: 0xde, 0x447: 0xdf, + 0x449: 0xe0, + 0x450: 0xe1, 0x451: 0xe2, 0x452: 0xe3, 0x453: 0xe4, 0x454: 0xe5, 0x455: 0xe6, 0x456: 0xe7, 0x457: 0xe8, + 0x458: 0xe9, 0x459: 0xea, 0x45a: 0x4a, 0x45b: 0xeb, 0x45c: 0xec, 0x45d: 0xed, 0x45e: 0xee, 0x45f: 0x4b, + // Block 0x12, offset 0x480 + 0x480: 0xef, + 0x4a3: 0xf0, 0x4a5: 0xf1, + 0x4b8: 0x4c, 0x4b9: 0x4d, 0x4ba: 0x4e, + // Block 0x13, offset 0x4c0 + 0x4c4: 0x4f, 0x4c5: 0xf2, 0x4c6: 0xf3, + 0x4c8: 0x50, 0x4c9: 0xf4, + // Block 0x14, offset 0x500 + 0x520: 0x51, 0x521: 0x52, 0x522: 0x53, 0x523: 0x54, 0x524: 0x55, 0x525: 0x56, 0x526: 0x57, 0x527: 0x58, + 0x528: 0x59, + // Block 0x15, offset 0x540 + 0x550: 0x0b, 0x551: 0x0c, 0x556: 0x0d, + 0x55b: 0x0e, 0x55d: 0x0f, 0x55e: 0x10, 0x55f: 0x11, + 0x56f: 0x12, +} + +// nfkcSparseOffset: 155 entries, 310 bytes +var nfkcSparseOffset = []uint16{0x0, 0xe, 0x12, 0x1b, 0x25, 0x35, 0x37, 0x3c, 0x47, 0x56, 0x63, 0x6b, 0x6f, 0x74, 0x76, 0x87, 0x8f, 0x96, 0x99, 0xa0, 0xa4, 0xa8, 0xaa, 0xac, 0xb5, 0xb9, 0xc0, 0xc5, 0xc8, 0xd2, 0xd4, 0xdb, 0xe3, 0xe7, 0xe9, 0xec, 0xf0, 0xf6, 0x107, 0x113, 0x115, 0x11b, 0x11d, 0x11f, 0x121, 0x123, 0x125, 0x127, 0x129, 0x12c, 0x12f, 0x131, 0x134, 0x137, 0x13b, 0x140, 0x149, 0x14b, 0x14e, 0x150, 0x15b, 0x166, 0x176, 0x184, 0x192, 0x1a2, 0x1b0, 0x1b7, 0x1bd, 0x1cc, 0x1d0, 0x1d2, 0x1d6, 0x1d8, 0x1db, 0x1dd, 0x1e0, 0x1e2, 0x1e5, 0x1e7, 0x1e9, 0x1eb, 0x1f7, 0x201, 0x20b, 0x20e, 0x212, 0x214, 0x216, 0x218, 0x21a, 0x21d, 0x21f, 0x221, 0x223, 0x225, 0x22b, 0x22e, 0x232, 0x234, 0x23b, 0x241, 0x247, 0x24f, 0x255, 0x25b, 0x261, 0x265, 0x267, 0x269, 0x26b, 0x26d, 0x273, 0x276, 0x279, 0x281, 0x288, 0x28b, 0x28e, 0x290, 0x298, 0x29b, 0x2a2, 0x2a5, 0x2ab, 0x2ad, 0x2af, 0x2b2, 0x2b4, 0x2b6, 0x2b8, 0x2ba, 0x2c7, 0x2d1, 0x2d3, 0x2d5, 0x2d9, 0x2de, 0x2ea, 0x2ef, 0x2f8, 0x2fe, 0x303, 0x307, 0x30c, 0x310, 0x320, 0x32e, 0x33c, 0x34a, 0x350, 0x352, 0x355, 0x35f, 0x361} + +// nfkcSparseValues: 875 entries, 3500 bytes +var nfkcSparseValues = [875]valueRange{ + // Block 0x0, offset 0x0 + {value: 0x0002, lo: 0x0d}, + {value: 0x0001, lo: 0xa0, hi: 0xa0}, + {value: 0x4278, lo: 0xa8, hi: 0xa8}, + {value: 0x0083, lo: 0xaa, hi: 0xaa}, + {value: 0x4264, lo: 0xaf, hi: 0xaf}, + {value: 0x0025, lo: 0xb2, hi: 0xb3}, + {value: 0x425a, lo: 0xb4, hi: 0xb4}, + {value: 0x01dc, lo: 0xb5, hi: 0xb5}, + {value: 0x4291, lo: 0xb8, hi: 0xb8}, + {value: 0x0023, lo: 0xb9, hi: 0xb9}, + {value: 0x009f, lo: 0xba, hi: 0xba}, + {value: 0x221c, lo: 0xbc, hi: 0xbc}, + {value: 0x2210, lo: 0xbd, hi: 0xbd}, + {value: 0x22b2, lo: 0xbe, hi: 0xbe}, + // Block 0x1, offset 0xe + {value: 0x0091, lo: 0x03}, + {value: 0x46e2, lo: 0xa0, hi: 0xa1}, + {value: 0x4714, lo: 0xaf, hi: 0xb0}, + {value: 0xa000, lo: 0xb7, hi: 0xb7}, + // Block 0x2, offset 0x12 + {value: 0x0003, lo: 0x08}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0x0091, lo: 0xb0, hi: 0xb0}, + {value: 0x0119, lo: 0xb1, hi: 0xb1}, + {value: 0x0095, lo: 0xb2, hi: 0xb2}, + {value: 0x00a5, lo: 0xb3, hi: 0xb3}, + {value: 0x0143, lo: 0xb4, hi: 0xb6}, + {value: 0x00af, lo: 0xb7, hi: 0xb7}, + {value: 0x00b3, lo: 0xb8, hi: 0xb8}, + // Block 0x3, offset 0x1b + {value: 0x000a, lo: 0x09}, + {value: 0x426e, lo: 0x98, hi: 0x98}, + {value: 0x4273, lo: 0x99, hi: 0x9a}, + {value: 0x4296, lo: 0x9b, hi: 0x9b}, + {value: 0x425f, lo: 0x9c, hi: 0x9c}, + {value: 0x4282, lo: 0x9d, hi: 0x9d}, + {value: 0x0113, lo: 0xa0, hi: 0xa0}, + {value: 0x0099, lo: 0xa1, hi: 0xa1}, + {value: 0x00a7, lo: 0xa2, hi: 0xa3}, + {value: 0x0167, lo: 0xa4, hi: 0xa4}, + // Block 0x4, offset 0x25 + {value: 0x0000, lo: 0x0f}, + {value: 0xa000, lo: 0x83, hi: 0x83}, + {value: 0xa000, lo: 0x87, hi: 0x87}, + {value: 0xa000, lo: 0x8b, hi: 0x8b}, + {value: 0xa000, lo: 0x8d, hi: 0x8d}, + {value: 0x37a5, lo: 0x90, hi: 0x90}, + {value: 0x37b1, lo: 0x91, hi: 0x91}, + {value: 0x379f, lo: 0x93, hi: 0x93}, + {value: 0xa000, lo: 0x96, hi: 0x96}, + {value: 0x3817, lo: 0x97, hi: 0x97}, + {value: 0x37e1, lo: 0x9c, hi: 0x9c}, + {value: 0x37c9, lo: 0x9d, hi: 0x9d}, + {value: 0x37f3, lo: 0x9e, hi: 0x9e}, + {value: 0xa000, lo: 0xb4, hi: 0xb5}, + {value: 0x381d, lo: 0xb6, hi: 0xb6}, + {value: 0x3823, lo: 0xb7, hi: 0xb7}, + // Block 0x5, offset 0x35 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0x83, hi: 0x87}, + // Block 0x6, offset 0x37 + {value: 0x0001, lo: 0x04}, + {value: 0x8113, lo: 0x81, hi: 0x82}, + {value: 0x8132, lo: 0x84, hi: 0x84}, + {value: 0x812d, lo: 0x85, hi: 0x85}, + {value: 0x810d, lo: 0x87, hi: 0x87}, + // Block 0x7, offset 0x3c + {value: 0x0000, lo: 0x0a}, + {value: 0x8132, lo: 0x90, hi: 0x97}, + {value: 0x8119, lo: 0x98, hi: 0x98}, + {value: 0x811a, lo: 0x99, hi: 0x99}, + {value: 0x811b, lo: 0x9a, hi: 0x9a}, + {value: 0x3841, lo: 0xa2, hi: 0xa2}, + {value: 0x3847, lo: 0xa3, hi: 0xa3}, + {value: 0x3853, lo: 0xa4, hi: 0xa4}, + {value: 0x384d, lo: 0xa5, hi: 0xa5}, + {value: 0x3859, lo: 0xa6, hi: 0xa6}, + {value: 0xa000, lo: 0xa7, hi: 0xa7}, + // Block 0x8, offset 0x47 + {value: 0x0000, lo: 0x0e}, + {value: 0x386b, lo: 0x80, hi: 0x80}, + {value: 0xa000, lo: 0x81, hi: 0x81}, + {value: 0x385f, lo: 0x82, hi: 0x82}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0x3865, lo: 0x93, hi: 0x93}, + {value: 0xa000, lo: 0x95, hi: 0x95}, + {value: 0x8132, lo: 0x96, hi: 0x9c}, + {value: 0x8132, lo: 0x9f, hi: 0xa2}, + {value: 0x812d, lo: 0xa3, hi: 0xa3}, + {value: 0x8132, lo: 0xa4, hi: 0xa4}, + {value: 0x8132, lo: 0xa7, hi: 0xa8}, + {value: 0x812d, lo: 0xaa, hi: 0xaa}, + {value: 0x8132, lo: 0xab, hi: 0xac}, + {value: 0x812d, lo: 0xad, hi: 0xad}, + // Block 0x9, offset 0x56 + {value: 0x0000, lo: 0x0c}, + {value: 0x811f, lo: 0x91, hi: 0x91}, + {value: 0x8132, lo: 0xb0, hi: 0xb0}, + {value: 0x812d, lo: 0xb1, hi: 0xb1}, + {value: 0x8132, lo: 0xb2, hi: 0xb3}, + {value: 0x812d, lo: 0xb4, hi: 0xb4}, + {value: 0x8132, lo: 0xb5, hi: 0xb6}, + {value: 0x812d, lo: 0xb7, hi: 0xb9}, + {value: 0x8132, lo: 0xba, hi: 0xba}, + {value: 0x812d, lo: 0xbb, hi: 0xbc}, + {value: 0x8132, lo: 0xbd, hi: 0xbd}, + {value: 0x812d, lo: 0xbe, hi: 0xbe}, + {value: 0x8132, lo: 0xbf, hi: 0xbf}, + // Block 0xa, offset 0x63 + {value: 0x0005, lo: 0x07}, + {value: 0x8132, lo: 0x80, hi: 0x80}, + {value: 0x8132, lo: 0x81, hi: 0x81}, + {value: 0x812d, lo: 0x82, hi: 0x83}, + {value: 0x812d, lo: 0x84, hi: 0x85}, + {value: 0x812d, lo: 0x86, hi: 0x87}, + {value: 0x812d, lo: 0x88, hi: 0x89}, + {value: 0x8132, lo: 0x8a, hi: 0x8a}, + // Block 0xb, offset 0x6b + {value: 0x0000, lo: 0x03}, + {value: 0x8132, lo: 0xab, hi: 0xb1}, + {value: 0x812d, lo: 0xb2, hi: 0xb2}, + {value: 0x8132, lo: 0xb3, hi: 0xb3}, + // Block 0xc, offset 0x6f + {value: 0x0000, lo: 0x04}, + {value: 0x8132, lo: 0x96, hi: 0x99}, + {value: 0x8132, lo: 0x9b, hi: 0xa3}, + {value: 0x8132, lo: 0xa5, hi: 0xa7}, + {value: 0x8132, lo: 0xa9, hi: 0xad}, + // Block 0xd, offset 0x74 + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0x99, hi: 0x9b}, + // Block 0xe, offset 0x76 + {value: 0x0000, lo: 0x10}, + {value: 0x8132, lo: 0x94, hi: 0xa1}, + {value: 0x812d, lo: 0xa3, hi: 0xa3}, + {value: 0x8132, lo: 0xa4, hi: 0xa5}, + {value: 0x812d, lo: 0xa6, hi: 0xa6}, + {value: 0x8132, lo: 0xa7, hi: 0xa8}, + {value: 0x812d, lo: 0xa9, hi: 0xa9}, + {value: 0x8132, lo: 0xaa, hi: 0xac}, + {value: 0x812d, lo: 0xad, hi: 0xaf}, + {value: 0x8116, lo: 0xb0, hi: 0xb0}, + {value: 0x8117, lo: 0xb1, hi: 0xb1}, + {value: 0x8118, lo: 0xb2, hi: 0xb2}, + {value: 0x8132, lo: 0xb3, hi: 0xb5}, + {value: 0x812d, lo: 0xb6, hi: 0xb6}, + {value: 0x8132, lo: 0xb7, hi: 0xb8}, + {value: 0x812d, lo: 0xb9, hi: 0xba}, + {value: 0x8132, lo: 0xbb, hi: 0xbf}, + // Block 0xf, offset 0x87 + {value: 0x0000, lo: 0x07}, + {value: 0xa000, lo: 0xa8, hi: 0xa8}, + {value: 0x3ed8, lo: 0xa9, hi: 0xa9}, + {value: 0xa000, lo: 0xb0, hi: 0xb0}, + {value: 0x3ee0, lo: 0xb1, hi: 0xb1}, + {value: 0xa000, lo: 0xb3, hi: 0xb3}, + {value: 0x3ee8, lo: 0xb4, hi: 0xb4}, + {value: 0x9902, lo: 0xbc, hi: 0xbc}, + // Block 0x10, offset 0x8f + {value: 0x0008, lo: 0x06}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x8132, lo: 0x91, hi: 0x91}, + {value: 0x812d, lo: 0x92, hi: 0x92}, + {value: 0x8132, lo: 0x93, hi: 0x93}, + {value: 0x8132, lo: 0x94, hi: 0x94}, + {value: 0x451c, lo: 0x98, hi: 0x9f}, + // Block 0x11, offset 0x96 + {value: 0x0000, lo: 0x02}, + {value: 0x8102, lo: 0xbc, hi: 0xbc}, + {value: 0x9900, lo: 0xbe, hi: 0xbe}, + // Block 0x12, offset 0x99 + {value: 0x0008, lo: 0x06}, + {value: 0xa000, lo: 0x87, hi: 0x87}, + {value: 0x2c9e, lo: 0x8b, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x97, hi: 0x97}, + {value: 0x455c, lo: 0x9c, hi: 0x9d}, + {value: 0x456c, lo: 0x9f, hi: 0x9f}, + // Block 0x13, offset 0xa0 + {value: 0x0000, lo: 0x03}, + {value: 0x4594, lo: 0xb3, hi: 0xb3}, + {value: 0x459c, lo: 0xb6, hi: 0xb6}, + {value: 0x8102, lo: 0xbc, hi: 0xbc}, + // Block 0x14, offset 0xa4 + {value: 0x0008, lo: 0x03}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x4574, lo: 0x99, hi: 0x9b}, + {value: 0x458c, lo: 0x9e, hi: 0x9e}, + // Block 0x15, offset 0xa8 + {value: 0x0000, lo: 0x01}, + {value: 0x8102, lo: 0xbc, hi: 0xbc}, + // Block 0x16, offset 0xaa + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + // Block 0x17, offset 0xac + {value: 0x0000, lo: 0x08}, + {value: 0xa000, lo: 0x87, hi: 0x87}, + {value: 0x2cb6, lo: 0x88, hi: 0x88}, + {value: 0x2cae, lo: 0x8b, hi: 0x8b}, + {value: 0x2cbe, lo: 0x8c, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x96, hi: 0x97}, + {value: 0x45a4, lo: 0x9c, hi: 0x9c}, + {value: 0x45ac, lo: 0x9d, hi: 0x9d}, + // Block 0x18, offset 0xb5 + {value: 0x0000, lo: 0x03}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0x2cc6, lo: 0x94, hi: 0x94}, + {value: 0x9900, lo: 0xbe, hi: 0xbe}, + // Block 0x19, offset 0xb9 + {value: 0x0000, lo: 0x06}, + {value: 0xa000, lo: 0x86, hi: 0x87}, + {value: 0x2cce, lo: 0x8a, hi: 0x8a}, + {value: 0x2cde, lo: 0x8b, hi: 0x8b}, + {value: 0x2cd6, lo: 0x8c, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x97, hi: 0x97}, + // Block 0x1a, offset 0xc0 + {value: 0x1801, lo: 0x04}, + {value: 0xa000, lo: 0x86, hi: 0x86}, + {value: 0x3ef0, lo: 0x88, hi: 0x88}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x8120, lo: 0x95, hi: 0x96}, + // Block 0x1b, offset 0xc5 + {value: 0x0000, lo: 0x02}, + {value: 0x8102, lo: 0xbc, hi: 0xbc}, + {value: 0xa000, lo: 0xbf, hi: 0xbf}, + // Block 0x1c, offset 0xc8 + {value: 0x0000, lo: 0x09}, + {value: 0x2ce6, lo: 0x80, hi: 0x80}, + {value: 0x9900, lo: 0x82, hi: 0x82}, + {value: 0xa000, lo: 0x86, hi: 0x86}, + {value: 0x2cee, lo: 0x87, hi: 0x87}, + {value: 0x2cf6, lo: 0x88, hi: 0x88}, + {value: 0x2f50, lo: 0x8a, hi: 0x8a}, + {value: 0x2dd8, lo: 0x8b, hi: 0x8b}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x95, hi: 0x96}, + // Block 0x1d, offset 0xd2 + {value: 0x0000, lo: 0x01}, + {value: 0x9900, lo: 0xbe, hi: 0xbe}, + // Block 0x1e, offset 0xd4 + {value: 0x0000, lo: 0x06}, + {value: 0xa000, lo: 0x86, hi: 0x87}, + {value: 0x2cfe, lo: 0x8a, hi: 0x8a}, + {value: 0x2d0e, lo: 0x8b, hi: 0x8b}, + {value: 0x2d06, lo: 0x8c, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x97, hi: 0x97}, + // Block 0x1f, offset 0xdb + {value: 0x6bea, lo: 0x07}, + {value: 0x9904, lo: 0x8a, hi: 0x8a}, + {value: 0x9900, lo: 0x8f, hi: 0x8f}, + {value: 0xa000, lo: 0x99, hi: 0x99}, + {value: 0x3ef8, lo: 0x9a, hi: 0x9a}, + {value: 0x2f58, lo: 0x9c, hi: 0x9c}, + {value: 0x2de3, lo: 0x9d, hi: 0x9d}, + {value: 0x2d16, lo: 0x9e, hi: 0x9f}, + // Block 0x20, offset 0xe3 + {value: 0x0000, lo: 0x03}, + {value: 0x2621, lo: 0xb3, hi: 0xb3}, + {value: 0x8122, lo: 0xb8, hi: 0xb9}, + {value: 0x8104, lo: 0xba, hi: 0xba}, + // Block 0x21, offset 0xe7 + {value: 0x0000, lo: 0x01}, + {value: 0x8123, lo: 0x88, hi: 0x8b}, + // Block 0x22, offset 0xe9 + {value: 0x0000, lo: 0x02}, + {value: 0x2636, lo: 0xb3, hi: 0xb3}, + {value: 0x8124, lo: 0xb8, hi: 0xb9}, + // Block 0x23, offset 0xec + {value: 0x0000, lo: 0x03}, + {value: 0x8125, lo: 0x88, hi: 0x8b}, + {value: 0x2628, lo: 0x9c, hi: 0x9c}, + {value: 0x262f, lo: 0x9d, hi: 0x9d}, + // Block 0x24, offset 0xf0 + {value: 0x0000, lo: 0x05}, + {value: 0x030b, lo: 0x8c, hi: 0x8c}, + {value: 0x812d, lo: 0x98, hi: 0x99}, + {value: 0x812d, lo: 0xb5, hi: 0xb5}, + {value: 0x812d, lo: 0xb7, hi: 0xb7}, + {value: 0x812b, lo: 0xb9, hi: 0xb9}, + // Block 0x25, offset 0xf6 + {value: 0x0000, lo: 0x10}, + {value: 0x2644, lo: 0x83, hi: 0x83}, + {value: 0x264b, lo: 0x8d, hi: 0x8d}, + {value: 0x2652, lo: 0x92, hi: 0x92}, + {value: 0x2659, lo: 0x97, hi: 0x97}, + {value: 0x2660, lo: 0x9c, hi: 0x9c}, + {value: 0x263d, lo: 0xa9, hi: 0xa9}, + {value: 0x8126, lo: 0xb1, hi: 0xb1}, + {value: 0x8127, lo: 0xb2, hi: 0xb2}, + {value: 0x4a84, lo: 0xb3, hi: 0xb3}, + {value: 0x8128, lo: 0xb4, hi: 0xb4}, + {value: 0x4a8d, lo: 0xb5, hi: 0xb5}, + {value: 0x45b4, lo: 0xb6, hi: 0xb6}, + {value: 0x45f4, lo: 0xb7, hi: 0xb7}, + {value: 0x45bc, lo: 0xb8, hi: 0xb8}, + {value: 0x45ff, lo: 0xb9, hi: 0xb9}, + {value: 0x8127, lo: 0xba, hi: 0xbd}, + // Block 0x26, offset 0x107 + {value: 0x0000, lo: 0x0b}, + {value: 0x8127, lo: 0x80, hi: 0x80}, + {value: 0x4a96, lo: 0x81, hi: 0x81}, + {value: 0x8132, lo: 0x82, hi: 0x83}, + {value: 0x8104, lo: 0x84, hi: 0x84}, + {value: 0x8132, lo: 0x86, hi: 0x87}, + {value: 0x266e, lo: 0x93, hi: 0x93}, + {value: 0x2675, lo: 0x9d, hi: 0x9d}, + {value: 0x267c, lo: 0xa2, hi: 0xa2}, + {value: 0x2683, lo: 0xa7, hi: 0xa7}, + {value: 0x268a, lo: 0xac, hi: 0xac}, + {value: 0x2667, lo: 0xb9, hi: 0xb9}, + // Block 0x27, offset 0x113 + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0x86, hi: 0x86}, + // Block 0x28, offset 0x115 + {value: 0x0000, lo: 0x05}, + {value: 0xa000, lo: 0xa5, hi: 0xa5}, + {value: 0x2d1e, lo: 0xa6, hi: 0xa6}, + {value: 0x9900, lo: 0xae, hi: 0xae}, + {value: 0x8102, lo: 0xb7, hi: 0xb7}, + {value: 0x8104, lo: 0xb9, hi: 0xba}, + // Block 0x29, offset 0x11b + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0x8d, hi: 0x8d}, + // Block 0x2a, offset 0x11d + {value: 0x0000, lo: 0x01}, + {value: 0x030f, lo: 0xbc, hi: 0xbc}, + // Block 0x2b, offset 0x11f + {value: 0x0000, lo: 0x01}, + {value: 0xa000, lo: 0x80, hi: 0x92}, + // Block 0x2c, offset 0x121 + {value: 0x0000, lo: 0x01}, + {value: 0xb900, lo: 0xa1, hi: 0xb5}, + // Block 0x2d, offset 0x123 + {value: 0x0000, lo: 0x01}, + {value: 0x9900, lo: 0xa8, hi: 0xbf}, + // Block 0x2e, offset 0x125 + {value: 0x0000, lo: 0x01}, + {value: 0x9900, lo: 0x80, hi: 0x82}, + // Block 0x2f, offset 0x127 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0x9d, hi: 0x9f}, + // Block 0x30, offset 0x129 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x94, hi: 0x94}, + {value: 0x8104, lo: 0xb4, hi: 0xb4}, + // Block 0x31, offset 0x12c + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x92, hi: 0x92}, + {value: 0x8132, lo: 0x9d, hi: 0x9d}, + // Block 0x32, offset 0x12f + {value: 0x0000, lo: 0x01}, + {value: 0x8131, lo: 0xa9, hi: 0xa9}, + // Block 0x33, offset 0x131 + {value: 0x0004, lo: 0x02}, + {value: 0x812e, lo: 0xb9, hi: 0xba}, + {value: 0x812d, lo: 0xbb, hi: 0xbb}, + // Block 0x34, offset 0x134 + {value: 0x0000, lo: 0x02}, + {value: 0x8132, lo: 0x97, hi: 0x97}, + {value: 0x812d, lo: 0x98, hi: 0x98}, + // Block 0x35, offset 0x137 + {value: 0x0000, lo: 0x03}, + {value: 0x8104, lo: 0xa0, hi: 0xa0}, + {value: 0x8132, lo: 0xb5, hi: 0xbc}, + {value: 0x812d, lo: 0xbf, hi: 0xbf}, + // Block 0x36, offset 0x13b + {value: 0x0000, lo: 0x04}, + {value: 0x8132, lo: 0xb0, hi: 0xb4}, + {value: 0x812d, lo: 0xb5, hi: 0xba}, + {value: 0x8132, lo: 0xbb, hi: 0xbc}, + {value: 0x812d, lo: 0xbd, hi: 0xbd}, + // Block 0x37, offset 0x140 + {value: 0x0000, lo: 0x08}, + {value: 0x2d66, lo: 0x80, hi: 0x80}, + {value: 0x2d6e, lo: 0x81, hi: 0x81}, + {value: 0xa000, lo: 0x82, hi: 0x82}, + {value: 0x2d76, lo: 0x83, hi: 0x83}, + {value: 0x8104, lo: 0x84, hi: 0x84}, + {value: 0x8132, lo: 0xab, hi: 0xab}, + {value: 0x812d, lo: 0xac, hi: 0xac}, + {value: 0x8132, lo: 0xad, hi: 0xb3}, + // Block 0x38, offset 0x149 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0xaa, hi: 0xab}, + // Block 0x39, offset 0x14b + {value: 0x0000, lo: 0x02}, + {value: 0x8102, lo: 0xa6, hi: 0xa6}, + {value: 0x8104, lo: 0xb2, hi: 0xb3}, + // Block 0x3a, offset 0x14e + {value: 0x0000, lo: 0x01}, + {value: 0x8102, lo: 0xb7, hi: 0xb7}, + // Block 0x3b, offset 0x150 + {value: 0x0000, lo: 0x0a}, + {value: 0x8132, lo: 0x90, hi: 0x92}, + {value: 0x8101, lo: 0x94, hi: 0x94}, + {value: 0x812d, lo: 0x95, hi: 0x99}, + {value: 0x8132, lo: 0x9a, hi: 0x9b}, + {value: 0x812d, lo: 0x9c, hi: 0x9f}, + {value: 0x8132, lo: 0xa0, hi: 0xa0}, + {value: 0x8101, lo: 0xa2, hi: 0xa8}, + {value: 0x812d, lo: 0xad, hi: 0xad}, + {value: 0x8132, lo: 0xb4, hi: 0xb4}, + {value: 0x8132, lo: 0xb8, hi: 0xb9}, + // Block 0x3c, offset 0x15b + {value: 0x0002, lo: 0x0a}, + {value: 0x0043, lo: 0xac, hi: 0xac}, + {value: 0x00d1, lo: 0xad, hi: 0xad}, + {value: 0x0045, lo: 0xae, hi: 0xae}, + {value: 0x0049, lo: 0xb0, hi: 0xb1}, + {value: 0x00e6, lo: 0xb2, hi: 0xb2}, + {value: 0x004f, lo: 0xb3, hi: 0xba}, + {value: 0x005f, lo: 0xbc, hi: 0xbc}, + {value: 0x00ef, lo: 0xbd, hi: 0xbd}, + {value: 0x0061, lo: 0xbe, hi: 0xbe}, + {value: 0x0065, lo: 0xbf, hi: 0xbf}, + // Block 0x3d, offset 0x166 + {value: 0x0000, lo: 0x0f}, + {value: 0x8132, lo: 0x80, hi: 0x81}, + {value: 0x812d, lo: 0x82, hi: 0x82}, + {value: 0x8132, lo: 0x83, hi: 0x89}, + {value: 0x812d, lo: 0x8a, hi: 0x8a}, + {value: 0x8132, lo: 0x8b, hi: 0x8c}, + {value: 0x8135, lo: 0x8d, hi: 0x8d}, + {value: 0x812a, lo: 0x8e, hi: 0x8e}, + {value: 0x812d, lo: 0x8f, hi: 0x8f}, + {value: 0x8129, lo: 0x90, hi: 0x90}, + {value: 0x8132, lo: 0x91, hi: 0xb5}, + {value: 0x8132, lo: 0xbb, hi: 0xbb}, + {value: 0x8134, lo: 0xbc, hi: 0xbc}, + {value: 0x812d, lo: 0xbd, hi: 0xbd}, + {value: 0x8132, lo: 0xbe, hi: 0xbe}, + {value: 0x812d, lo: 0xbf, hi: 0xbf}, + // Block 0x3e, offset 0x176 + {value: 0x0000, lo: 0x0d}, + {value: 0x0001, lo: 0x80, hi: 0x8a}, + {value: 0x043b, lo: 0x91, hi: 0x91}, + {value: 0x429b, lo: 0x97, hi: 0x97}, + {value: 0x001d, lo: 0xa4, hi: 0xa4}, + {value: 0x1873, lo: 0xa5, hi: 0xa5}, + {value: 0x1b5c, lo: 0xa6, hi: 0xa6}, + {value: 0x0001, lo: 0xaf, hi: 0xaf}, + {value: 0x2691, lo: 0xb3, hi: 0xb3}, + {value: 0x27fe, lo: 0xb4, hi: 0xb4}, + {value: 0x2698, lo: 0xb6, hi: 0xb6}, + {value: 0x2808, lo: 0xb7, hi: 0xb7}, + {value: 0x186d, lo: 0xbc, hi: 0xbc}, + {value: 0x4269, lo: 0xbe, hi: 0xbe}, + // Block 0x3f, offset 0x184 + {value: 0x0002, lo: 0x0d}, + {value: 0x1933, lo: 0x87, hi: 0x87}, + {value: 0x1930, lo: 0x88, hi: 0x88}, + {value: 0x1870, lo: 0x89, hi: 0x89}, + {value: 0x298e, lo: 0x97, hi: 0x97}, + {value: 0x0001, lo: 0x9f, hi: 0x9f}, + {value: 0x0021, lo: 0xb0, hi: 0xb0}, + {value: 0x0093, lo: 0xb1, hi: 0xb1}, + {value: 0x0029, lo: 0xb4, hi: 0xb9}, + {value: 0x0017, lo: 0xba, hi: 0xba}, + {value: 0x0467, lo: 0xbb, hi: 0xbb}, + {value: 0x003b, lo: 0xbc, hi: 0xbc}, + {value: 0x0011, lo: 0xbd, hi: 0xbe}, + {value: 0x009d, lo: 0xbf, hi: 0xbf}, + // Block 0x40, offset 0x192 + {value: 0x0002, lo: 0x0f}, + {value: 0x0021, lo: 0x80, hi: 0x89}, + {value: 0x0017, lo: 0x8a, hi: 0x8a}, + {value: 0x0467, lo: 0x8b, hi: 0x8b}, + {value: 0x003b, lo: 0x8c, hi: 0x8c}, + {value: 0x0011, lo: 0x8d, hi: 0x8e}, + {value: 0x0083, lo: 0x90, hi: 0x90}, + {value: 0x008b, lo: 0x91, hi: 0x91}, + {value: 0x009f, lo: 0x92, hi: 0x92}, + {value: 0x00b1, lo: 0x93, hi: 0x93}, + {value: 0x0104, lo: 0x94, hi: 0x94}, + {value: 0x0091, lo: 0x95, hi: 0x95}, + {value: 0x0097, lo: 0x96, hi: 0x99}, + {value: 0x00a1, lo: 0x9a, hi: 0x9a}, + {value: 0x00a7, lo: 0x9b, hi: 0x9c}, + {value: 0x1999, lo: 0xa8, hi: 0xa8}, + // Block 0x41, offset 0x1a2 + {value: 0x0000, lo: 0x0d}, + {value: 0x8132, lo: 0x90, hi: 0x91}, + {value: 0x8101, lo: 0x92, hi: 0x93}, + {value: 0x8132, lo: 0x94, hi: 0x97}, + {value: 0x8101, lo: 0x98, hi: 0x9a}, + {value: 0x8132, lo: 0x9b, hi: 0x9c}, + {value: 0x8132, lo: 0xa1, hi: 0xa1}, + {value: 0x8101, lo: 0xa5, hi: 0xa6}, + {value: 0x8132, lo: 0xa7, hi: 0xa7}, + {value: 0x812d, lo: 0xa8, hi: 0xa8}, + {value: 0x8132, lo: 0xa9, hi: 0xa9}, + {value: 0x8101, lo: 0xaa, hi: 0xab}, + {value: 0x812d, lo: 0xac, hi: 0xaf}, + {value: 0x8132, lo: 0xb0, hi: 0xb0}, + // Block 0x42, offset 0x1b0 + {value: 0x0007, lo: 0x06}, + {value: 0x2180, lo: 0x89, hi: 0x89}, + {value: 0xa000, lo: 0x90, hi: 0x90}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0xa000, lo: 0x94, hi: 0x94}, + {value: 0x3bb9, lo: 0x9a, hi: 0x9b}, + {value: 0x3bc7, lo: 0xae, hi: 0xae}, + // Block 0x43, offset 0x1b7 + {value: 0x000e, lo: 0x05}, + {value: 0x3bce, lo: 0x8d, hi: 0x8e}, + {value: 0x3bd5, lo: 0x8f, hi: 0x8f}, + {value: 0xa000, lo: 0x90, hi: 0x90}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0xa000, lo: 0x94, hi: 0x94}, + // Block 0x44, offset 0x1bd + {value: 0x0173, lo: 0x0e}, + {value: 0xa000, lo: 0x83, hi: 0x83}, + {value: 0x3be3, lo: 0x84, hi: 0x84}, + {value: 0xa000, lo: 0x88, hi: 0x88}, + {value: 0x3bea, lo: 0x89, hi: 0x89}, + {value: 0xa000, lo: 0x8b, hi: 0x8b}, + {value: 0x3bf1, lo: 0x8c, hi: 0x8c}, + {value: 0xa000, lo: 0xa3, hi: 0xa3}, + {value: 0x3bf8, lo: 0xa4, hi: 0xa4}, + {value: 0xa000, lo: 0xa5, hi: 0xa5}, + {value: 0x3bff, lo: 0xa6, hi: 0xa6}, + {value: 0x269f, lo: 0xac, hi: 0xad}, + {value: 0x26a6, lo: 0xaf, hi: 0xaf}, + {value: 0x281c, lo: 0xb0, hi: 0xb0}, + {value: 0xa000, lo: 0xbc, hi: 0xbc}, + // Block 0x45, offset 0x1cc + {value: 0x0007, lo: 0x03}, + {value: 0x3c68, lo: 0xa0, hi: 0xa1}, + {value: 0x3c92, lo: 0xa2, hi: 0xa3}, + {value: 0x3cbc, lo: 0xaa, hi: 0xad}, + // Block 0x46, offset 0x1d0 + {value: 0x0004, lo: 0x01}, + {value: 0x048b, lo: 0xa9, hi: 0xaa}, + // Block 0x47, offset 0x1d2 + {value: 0x0002, lo: 0x03}, + {value: 0x0057, lo: 0x80, hi: 0x8f}, + {value: 0x0083, lo: 0x90, hi: 0xa9}, + {value: 0x0021, lo: 0xaa, hi: 0xaa}, + // Block 0x48, offset 0x1d6 + {value: 0x0000, lo: 0x01}, + {value: 0x299b, lo: 0x8c, hi: 0x8c}, + // Block 0x49, offset 0x1d8 + {value: 0x0263, lo: 0x02}, + {value: 0x1b8c, lo: 0xb4, hi: 0xb4}, + {value: 0x192d, lo: 0xb5, hi: 0xb6}, + // Block 0x4a, offset 0x1db + {value: 0x0000, lo: 0x01}, + {value: 0x44dd, lo: 0x9c, hi: 0x9c}, + // Block 0x4b, offset 0x1dd + {value: 0x0000, lo: 0x02}, + {value: 0x0095, lo: 0xbc, hi: 0xbc}, + {value: 0x006d, lo: 0xbd, hi: 0xbd}, + // Block 0x4c, offset 0x1e0 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xaf, hi: 0xb1}, + // Block 0x4d, offset 0x1e2 + {value: 0x0000, lo: 0x02}, + {value: 0x047f, lo: 0xaf, hi: 0xaf}, + {value: 0x8104, lo: 0xbf, hi: 0xbf}, + // Block 0x4e, offset 0x1e5 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xa0, hi: 0xbf}, + // Block 0x4f, offset 0x1e7 + {value: 0x0000, lo: 0x01}, + {value: 0x0dc3, lo: 0x9f, hi: 0x9f}, + // Block 0x50, offset 0x1e9 + {value: 0x0000, lo: 0x01}, + {value: 0x162f, lo: 0xb3, hi: 0xb3}, + // Block 0x51, offset 0x1eb + {value: 0x0004, lo: 0x0b}, + {value: 0x1597, lo: 0x80, hi: 0x82}, + {value: 0x15af, lo: 0x83, hi: 0x83}, + {value: 0x15c7, lo: 0x84, hi: 0x85}, + {value: 0x15d7, lo: 0x86, hi: 0x89}, + {value: 0x15eb, lo: 0x8a, hi: 0x8c}, + {value: 0x15ff, lo: 0x8d, hi: 0x8d}, + {value: 0x1607, lo: 0x8e, hi: 0x8e}, + {value: 0x160f, lo: 0x8f, hi: 0x90}, + {value: 0x161b, lo: 0x91, hi: 0x93}, + {value: 0x162b, lo: 0x94, hi: 0x94}, + {value: 0x1633, lo: 0x95, hi: 0x95}, + // Block 0x52, offset 0x1f7 + {value: 0x0004, lo: 0x09}, + {value: 0x0001, lo: 0x80, hi: 0x80}, + {value: 0x812c, lo: 0xaa, hi: 0xaa}, + {value: 0x8131, lo: 0xab, hi: 0xab}, + {value: 0x8133, lo: 0xac, hi: 0xac}, + {value: 0x812e, lo: 0xad, hi: 0xad}, + {value: 0x812f, lo: 0xae, hi: 0xae}, + {value: 0x812f, lo: 0xaf, hi: 0xaf}, + {value: 0x04b3, lo: 0xb6, hi: 0xb6}, + {value: 0x0887, lo: 0xb8, hi: 0xba}, + // Block 0x53, offset 0x201 + {value: 0x0006, lo: 0x09}, + {value: 0x0313, lo: 0xb1, hi: 0xb1}, + {value: 0x0317, lo: 0xb2, hi: 0xb2}, + {value: 0x4a3b, lo: 0xb3, hi: 0xb3}, + {value: 0x031b, lo: 0xb4, hi: 0xb4}, + {value: 0x4a41, lo: 0xb5, hi: 0xb6}, + {value: 0x031f, lo: 0xb7, hi: 0xb7}, + {value: 0x0323, lo: 0xb8, hi: 0xb8}, + {value: 0x0327, lo: 0xb9, hi: 0xb9}, + {value: 0x4a4d, lo: 0xba, hi: 0xbf}, + // Block 0x54, offset 0x20b + {value: 0x0000, lo: 0x02}, + {value: 0x8132, lo: 0xaf, hi: 0xaf}, + {value: 0x8132, lo: 0xb4, hi: 0xbd}, + // Block 0x55, offset 0x20e + {value: 0x0000, lo: 0x03}, + {value: 0x020f, lo: 0x9c, hi: 0x9c}, + {value: 0x0212, lo: 0x9d, hi: 0x9d}, + {value: 0x8132, lo: 0x9e, hi: 0x9f}, + // Block 0x56, offset 0x212 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xb0, hi: 0xb1}, + // Block 0x57, offset 0x214 + {value: 0x0000, lo: 0x01}, + {value: 0x163b, lo: 0xb0, hi: 0xb0}, + // Block 0x58, offset 0x216 + {value: 0x000c, lo: 0x01}, + {value: 0x00d7, lo: 0xb8, hi: 0xb9}, + // Block 0x59, offset 0x218 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x86, hi: 0x86}, + // Block 0x5a, offset 0x21a + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x84, hi: 0x84}, + {value: 0x8132, lo: 0xa0, hi: 0xb1}, + // Block 0x5b, offset 0x21d + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0xab, hi: 0xad}, + // Block 0x5c, offset 0x21f + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x93, hi: 0x93}, + // Block 0x5d, offset 0x221 + {value: 0x0000, lo: 0x01}, + {value: 0x8102, lo: 0xb3, hi: 0xb3}, + // Block 0x5e, offset 0x223 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x80, hi: 0x80}, + // Block 0x5f, offset 0x225 + {value: 0x0000, lo: 0x05}, + {value: 0x8132, lo: 0xb0, hi: 0xb0}, + {value: 0x8132, lo: 0xb2, hi: 0xb3}, + {value: 0x812d, lo: 0xb4, hi: 0xb4}, + {value: 0x8132, lo: 0xb7, hi: 0xb8}, + {value: 0x8132, lo: 0xbe, hi: 0xbf}, + // Block 0x60, offset 0x22b + {value: 0x0000, lo: 0x02}, + {value: 0x8132, lo: 0x81, hi: 0x81}, + {value: 0x8104, lo: 0xb6, hi: 0xb6}, + // Block 0x61, offset 0x22e + {value: 0x0008, lo: 0x03}, + {value: 0x1637, lo: 0x9c, hi: 0x9d}, + {value: 0x0125, lo: 0x9e, hi: 0x9e}, + {value: 0x1643, lo: 0x9f, hi: 0x9f}, + // Block 0x62, offset 0x232 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0xad, hi: 0xad}, + // Block 0x63, offset 0x234 + {value: 0x0000, lo: 0x06}, + {value: 0xe500, lo: 0x80, hi: 0x80}, + {value: 0xc600, lo: 0x81, hi: 0x9b}, + {value: 0xe500, lo: 0x9c, hi: 0x9c}, + {value: 0xc600, lo: 0x9d, hi: 0xb7}, + {value: 0xe500, lo: 0xb8, hi: 0xb8}, + {value: 0xc600, lo: 0xb9, hi: 0xbf}, + // Block 0x64, offset 0x23b + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x93}, + {value: 0xe500, lo: 0x94, hi: 0x94}, + {value: 0xc600, lo: 0x95, hi: 0xaf}, + {value: 0xe500, lo: 0xb0, hi: 0xb0}, + {value: 0xc600, lo: 0xb1, hi: 0xbf}, + // Block 0x65, offset 0x241 + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x8b}, + {value: 0xe500, lo: 0x8c, hi: 0x8c}, + {value: 0xc600, lo: 0x8d, hi: 0xa7}, + {value: 0xe500, lo: 0xa8, hi: 0xa8}, + {value: 0xc600, lo: 0xa9, hi: 0xbf}, + // Block 0x66, offset 0x247 + {value: 0x0000, lo: 0x07}, + {value: 0xc600, lo: 0x80, hi: 0x83}, + {value: 0xe500, lo: 0x84, hi: 0x84}, + {value: 0xc600, lo: 0x85, hi: 0x9f}, + {value: 0xe500, lo: 0xa0, hi: 0xa0}, + {value: 0xc600, lo: 0xa1, hi: 0xbb}, + {value: 0xe500, lo: 0xbc, hi: 0xbc}, + {value: 0xc600, lo: 0xbd, hi: 0xbf}, + // Block 0x67, offset 0x24f + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x97}, + {value: 0xe500, lo: 0x98, hi: 0x98}, + {value: 0xc600, lo: 0x99, hi: 0xb3}, + {value: 0xe500, lo: 0xb4, hi: 0xb4}, + {value: 0xc600, lo: 0xb5, hi: 0xbf}, + // Block 0x68, offset 0x255 + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x8f}, + {value: 0xe500, lo: 0x90, hi: 0x90}, + {value: 0xc600, lo: 0x91, hi: 0xab}, + {value: 0xe500, lo: 0xac, hi: 0xac}, + {value: 0xc600, lo: 0xad, hi: 0xbf}, + // Block 0x69, offset 0x25b + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x87}, + {value: 0xe500, lo: 0x88, hi: 0x88}, + {value: 0xc600, lo: 0x89, hi: 0xa3}, + {value: 0xe500, lo: 0xa4, hi: 0xa4}, + {value: 0xc600, lo: 0xa5, hi: 0xbf}, + // Block 0x6a, offset 0x261 + {value: 0x0000, lo: 0x03}, + {value: 0xc600, lo: 0x80, hi: 0x87}, + {value: 0xe500, lo: 0x88, hi: 0x88}, + {value: 0xc600, lo: 0x89, hi: 0xa3}, + // Block 0x6b, offset 0x265 + {value: 0x0002, lo: 0x01}, + {value: 0x0003, lo: 0x81, hi: 0xbf}, + // Block 0x6c, offset 0x267 + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0xbd, hi: 0xbd}, + // Block 0x6d, offset 0x269 + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0xa0, hi: 0xa0}, + // Block 0x6e, offset 0x26b + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xb6, hi: 0xba}, + // Block 0x6f, offset 0x26d + {value: 0x002c, lo: 0x05}, + {value: 0x812d, lo: 0x8d, hi: 0x8d}, + {value: 0x8132, lo: 0x8f, hi: 0x8f}, + {value: 0x8132, lo: 0xb8, hi: 0xb8}, + {value: 0x8101, lo: 0xb9, hi: 0xba}, + {value: 0x8104, lo: 0xbf, hi: 0xbf}, + // Block 0x70, offset 0x273 + {value: 0x0000, lo: 0x02}, + {value: 0x8132, lo: 0xa5, hi: 0xa5}, + {value: 0x812d, lo: 0xa6, hi: 0xa6}, + // Block 0x71, offset 0x276 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x86, hi: 0x86}, + {value: 0x8104, lo: 0xbf, hi: 0xbf}, + // Block 0x72, offset 0x279 + {value: 0x17fe, lo: 0x07}, + {value: 0xa000, lo: 0x99, hi: 0x99}, + {value: 0x4238, lo: 0x9a, hi: 0x9a}, + {value: 0xa000, lo: 0x9b, hi: 0x9b}, + {value: 0x4242, lo: 0x9c, hi: 0x9c}, + {value: 0xa000, lo: 0xa5, hi: 0xa5}, + {value: 0x424c, lo: 0xab, hi: 0xab}, + {value: 0x8104, lo: 0xb9, hi: 0xba}, + // Block 0x73, offset 0x281 + {value: 0x0000, lo: 0x06}, + {value: 0x8132, lo: 0x80, hi: 0x82}, + {value: 0x9900, lo: 0xa7, hi: 0xa7}, + {value: 0x2d7e, lo: 0xae, hi: 0xae}, + {value: 0x2d88, lo: 0xaf, hi: 0xaf}, + {value: 0xa000, lo: 0xb1, hi: 0xb2}, + {value: 0x8104, lo: 0xb3, hi: 0xb4}, + // Block 0x74, offset 0x288 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x80, hi: 0x80}, + {value: 0x8102, lo: 0x8a, hi: 0x8a}, + // Block 0x75, offset 0x28b + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0xb5, hi: 0xb5}, + {value: 0x8102, lo: 0xb6, hi: 0xb6}, + // Block 0x76, offset 0x28e + {value: 0x0002, lo: 0x01}, + {value: 0x8102, lo: 0xa9, hi: 0xaa}, + // Block 0x77, offset 0x290 + {value: 0x0000, lo: 0x07}, + {value: 0xa000, lo: 0x87, hi: 0x87}, + {value: 0x2d92, lo: 0x8b, hi: 0x8b}, + {value: 0x2d9c, lo: 0x8c, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x97, hi: 0x97}, + {value: 0x8132, lo: 0xa6, hi: 0xac}, + {value: 0x8132, lo: 0xb0, hi: 0xb4}, + // Block 0x78, offset 0x298 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x82, hi: 0x82}, + {value: 0x8102, lo: 0x86, hi: 0x86}, + // Block 0x79, offset 0x29b + {value: 0x6b5a, lo: 0x06}, + {value: 0x9900, lo: 0xb0, hi: 0xb0}, + {value: 0xa000, lo: 0xb9, hi: 0xb9}, + {value: 0x9900, lo: 0xba, hi: 0xba}, + {value: 0x2db0, lo: 0xbb, hi: 0xbb}, + {value: 0x2da6, lo: 0xbc, hi: 0xbd}, + {value: 0x2dba, lo: 0xbe, hi: 0xbe}, + // Block 0x7a, offset 0x2a2 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x82, hi: 0x82}, + {value: 0x8102, lo: 0x83, hi: 0x83}, + // Block 0x7b, offset 0x2a5 + {value: 0x0000, lo: 0x05}, + {value: 0x9900, lo: 0xaf, hi: 0xaf}, + {value: 0xa000, lo: 0xb8, hi: 0xb9}, + {value: 0x2dc4, lo: 0xba, hi: 0xba}, + {value: 0x2dce, lo: 0xbb, hi: 0xbb}, + {value: 0x8104, lo: 0xbf, hi: 0xbf}, + // Block 0x7c, offset 0x2ab + {value: 0x0000, lo: 0x01}, + {value: 0x8102, lo: 0x80, hi: 0x80}, + // Block 0x7d, offset 0x2ad + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0xbf, hi: 0xbf}, + // Block 0x7e, offset 0x2af + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0xb6, hi: 0xb6}, + {value: 0x8102, lo: 0xb7, hi: 0xb7}, + // Block 0x7f, offset 0x2b2 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0xab, hi: 0xab}, + // Block 0x80, offset 0x2b4 + {value: 0x0000, lo: 0x01}, + {value: 0x8101, lo: 0xb0, hi: 0xb4}, + // Block 0x81, offset 0x2b6 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xb0, hi: 0xb6}, + // Block 0x82, offset 0x2b8 + {value: 0x0000, lo: 0x01}, + {value: 0x8101, lo: 0x9e, hi: 0x9e}, + // Block 0x83, offset 0x2ba + {value: 0x0000, lo: 0x0c}, + {value: 0x45cc, lo: 0x9e, hi: 0x9e}, + {value: 0x45d6, lo: 0x9f, hi: 0x9f}, + {value: 0x460a, lo: 0xa0, hi: 0xa0}, + {value: 0x4618, lo: 0xa1, hi: 0xa1}, + {value: 0x4626, lo: 0xa2, hi: 0xa2}, + {value: 0x4634, lo: 0xa3, hi: 0xa3}, + {value: 0x4642, lo: 0xa4, hi: 0xa4}, + {value: 0x812b, lo: 0xa5, hi: 0xa6}, + {value: 0x8101, lo: 0xa7, hi: 0xa9}, + {value: 0x8130, lo: 0xad, hi: 0xad}, + {value: 0x812b, lo: 0xae, hi: 0xb2}, + {value: 0x812d, lo: 0xbb, hi: 0xbf}, + // Block 0x84, offset 0x2c7 + {value: 0x0000, lo: 0x09}, + {value: 0x812d, lo: 0x80, hi: 0x82}, + {value: 0x8132, lo: 0x85, hi: 0x89}, + {value: 0x812d, lo: 0x8a, hi: 0x8b}, + {value: 0x8132, lo: 0xaa, hi: 0xad}, + {value: 0x45e0, lo: 0xbb, hi: 0xbb}, + {value: 0x45ea, lo: 0xbc, hi: 0xbc}, + {value: 0x4650, lo: 0xbd, hi: 0xbd}, + {value: 0x466c, lo: 0xbe, hi: 0xbe}, + {value: 0x465e, lo: 0xbf, hi: 0xbf}, + // Block 0x85, offset 0x2d1 + {value: 0x0000, lo: 0x01}, + {value: 0x467a, lo: 0x80, hi: 0x80}, + // Block 0x86, offset 0x2d3 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0x82, hi: 0x84}, + // Block 0x87, offset 0x2d5 + {value: 0x0002, lo: 0x03}, + {value: 0x0043, lo: 0x80, hi: 0x99}, + {value: 0x0083, lo: 0x9a, hi: 0xb3}, + {value: 0x0043, lo: 0xb4, hi: 0xbf}, + // Block 0x88, offset 0x2d9 + {value: 0x0002, lo: 0x04}, + {value: 0x005b, lo: 0x80, hi: 0x8d}, + {value: 0x0083, lo: 0x8e, hi: 0x94}, + {value: 0x0093, lo: 0x96, hi: 0xa7}, + {value: 0x0043, lo: 0xa8, hi: 0xbf}, + // Block 0x89, offset 0x2de + {value: 0x0002, lo: 0x0b}, + {value: 0x0073, lo: 0x80, hi: 0x81}, + {value: 0x0083, lo: 0x82, hi: 0x9b}, + {value: 0x0043, lo: 0x9c, hi: 0x9c}, + {value: 0x0047, lo: 0x9e, hi: 0x9f}, + {value: 0x004f, lo: 0xa2, hi: 0xa2}, + {value: 0x0055, lo: 0xa5, hi: 0xa6}, + {value: 0x005d, lo: 0xa9, hi: 0xac}, + {value: 0x0067, lo: 0xae, hi: 0xb5}, + {value: 0x0083, lo: 0xb6, hi: 0xb9}, + {value: 0x008d, lo: 0xbb, hi: 0xbb}, + {value: 0x0091, lo: 0xbd, hi: 0xbf}, + // Block 0x8a, offset 0x2ea + {value: 0x0002, lo: 0x04}, + {value: 0x0097, lo: 0x80, hi: 0x83}, + {value: 0x00a1, lo: 0x85, hi: 0x8f}, + {value: 0x0043, lo: 0x90, hi: 0xa9}, + {value: 0x0083, lo: 0xaa, hi: 0xbf}, + // Block 0x8b, offset 0x2ef + {value: 0x0002, lo: 0x08}, + {value: 0x00af, lo: 0x80, hi: 0x83}, + {value: 0x0043, lo: 0x84, hi: 0x85}, + {value: 0x0049, lo: 0x87, hi: 0x8a}, + {value: 0x0055, lo: 0x8d, hi: 0x94}, + {value: 0x0067, lo: 0x96, hi: 0x9c}, + {value: 0x0083, lo: 0x9e, hi: 0xb7}, + {value: 0x0043, lo: 0xb8, hi: 0xb9}, + {value: 0x0049, lo: 0xbb, hi: 0xbe}, + // Block 0x8c, offset 0x2f8 + {value: 0x0002, lo: 0x05}, + {value: 0x0053, lo: 0x80, hi: 0x84}, + {value: 0x005f, lo: 0x86, hi: 0x86}, + {value: 0x0067, lo: 0x8a, hi: 0x90}, + {value: 0x0083, lo: 0x92, hi: 0xab}, + {value: 0x0043, lo: 0xac, hi: 0xbf}, + // Block 0x8d, offset 0x2fe + {value: 0x0002, lo: 0x04}, + {value: 0x006b, lo: 0x80, hi: 0x85}, + {value: 0x0083, lo: 0x86, hi: 0x9f}, + {value: 0x0043, lo: 0xa0, hi: 0xb9}, + {value: 0x0083, lo: 0xba, hi: 0xbf}, + // Block 0x8e, offset 0x303 + {value: 0x0002, lo: 0x03}, + {value: 0x008f, lo: 0x80, hi: 0x93}, + {value: 0x0043, lo: 0x94, hi: 0xad}, + {value: 0x0083, lo: 0xae, hi: 0xbf}, + // Block 0x8f, offset 0x307 + {value: 0x0002, lo: 0x04}, + {value: 0x00a7, lo: 0x80, hi: 0x87}, + {value: 0x0043, lo: 0x88, hi: 0xa1}, + {value: 0x0083, lo: 0xa2, hi: 0xbb}, + {value: 0x0043, lo: 0xbc, hi: 0xbf}, + // Block 0x90, offset 0x30c + {value: 0x0002, lo: 0x03}, + {value: 0x004b, lo: 0x80, hi: 0x95}, + {value: 0x0083, lo: 0x96, hi: 0xaf}, + {value: 0x0043, lo: 0xb0, hi: 0xbf}, + // Block 0x91, offset 0x310 + {value: 0x0003, lo: 0x0f}, + {value: 0x01b8, lo: 0x80, hi: 0x80}, + {value: 0x045f, lo: 0x81, hi: 0x81}, + {value: 0x01bb, lo: 0x82, hi: 0x9a}, + {value: 0x045b, lo: 0x9b, hi: 0x9b}, + {value: 0x01c7, lo: 0x9c, hi: 0x9c}, + {value: 0x01d0, lo: 0x9d, hi: 0x9d}, + {value: 0x01d6, lo: 0x9e, hi: 0x9e}, + {value: 0x01fa, lo: 0x9f, hi: 0x9f}, + {value: 0x01eb, lo: 0xa0, hi: 0xa0}, + {value: 0x01e8, lo: 0xa1, hi: 0xa1}, + {value: 0x0173, lo: 0xa2, hi: 0xb2}, + {value: 0x0188, lo: 0xb3, hi: 0xb3}, + {value: 0x01a6, lo: 0xb4, hi: 0xba}, + {value: 0x045f, lo: 0xbb, hi: 0xbb}, + {value: 0x01bb, lo: 0xbc, hi: 0xbf}, + // Block 0x92, offset 0x320 + {value: 0x0003, lo: 0x0d}, + {value: 0x01c7, lo: 0x80, hi: 0x94}, + {value: 0x045b, lo: 0x95, hi: 0x95}, + {value: 0x01c7, lo: 0x96, hi: 0x96}, + {value: 0x01d0, lo: 0x97, hi: 0x97}, + {value: 0x01d6, lo: 0x98, hi: 0x98}, + {value: 0x01fa, lo: 0x99, hi: 0x99}, + {value: 0x01eb, lo: 0x9a, hi: 0x9a}, + {value: 0x01e8, lo: 0x9b, hi: 0x9b}, + {value: 0x0173, lo: 0x9c, hi: 0xac}, + {value: 0x0188, lo: 0xad, hi: 0xad}, + {value: 0x01a6, lo: 0xae, hi: 0xb4}, + {value: 0x045f, lo: 0xb5, hi: 0xb5}, + {value: 0x01bb, lo: 0xb6, hi: 0xbf}, + // Block 0x93, offset 0x32e + {value: 0x0003, lo: 0x0d}, + {value: 0x01d9, lo: 0x80, hi: 0x8e}, + {value: 0x045b, lo: 0x8f, hi: 0x8f}, + {value: 0x01c7, lo: 0x90, hi: 0x90}, + {value: 0x01d0, lo: 0x91, hi: 0x91}, + {value: 0x01d6, lo: 0x92, hi: 0x92}, + {value: 0x01fa, lo: 0x93, hi: 0x93}, + {value: 0x01eb, lo: 0x94, hi: 0x94}, + {value: 0x01e8, lo: 0x95, hi: 0x95}, + {value: 0x0173, lo: 0x96, hi: 0xa6}, + {value: 0x0188, lo: 0xa7, hi: 0xa7}, + {value: 0x01a6, lo: 0xa8, hi: 0xae}, + {value: 0x045f, lo: 0xaf, hi: 0xaf}, + {value: 0x01bb, lo: 0xb0, hi: 0xbf}, + // Block 0x94, offset 0x33c + {value: 0x0003, lo: 0x0d}, + {value: 0x01eb, lo: 0x80, hi: 0x88}, + {value: 0x045b, lo: 0x89, hi: 0x89}, + {value: 0x01c7, lo: 0x8a, hi: 0x8a}, + {value: 0x01d0, lo: 0x8b, hi: 0x8b}, + {value: 0x01d6, lo: 0x8c, hi: 0x8c}, + {value: 0x01fa, lo: 0x8d, hi: 0x8d}, + {value: 0x01eb, lo: 0x8e, hi: 0x8e}, + {value: 0x01e8, lo: 0x8f, hi: 0x8f}, + {value: 0x0173, lo: 0x90, hi: 0xa0}, + {value: 0x0188, lo: 0xa1, hi: 0xa1}, + {value: 0x01a6, lo: 0xa2, hi: 0xa8}, + {value: 0x045f, lo: 0xa9, hi: 0xa9}, + {value: 0x01bb, lo: 0xaa, hi: 0xbf}, + // Block 0x95, offset 0x34a + {value: 0x0000, lo: 0x05}, + {value: 0x8132, lo: 0x80, hi: 0x86}, + {value: 0x8132, lo: 0x88, hi: 0x98}, + {value: 0x8132, lo: 0x9b, hi: 0xa1}, + {value: 0x8132, lo: 0xa3, hi: 0xa4}, + {value: 0x8132, lo: 0xa6, hi: 0xaa}, + // Block 0x96, offset 0x350 + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0x90, hi: 0x96}, + // Block 0x97, offset 0x352 + {value: 0x0000, lo: 0x02}, + {value: 0x8132, lo: 0x84, hi: 0x89}, + {value: 0x8102, lo: 0x8a, hi: 0x8a}, + // Block 0x98, offset 0x355 + {value: 0x0002, lo: 0x09}, + {value: 0x0063, lo: 0x80, hi: 0x89}, + {value: 0x1951, lo: 0x8a, hi: 0x8a}, + {value: 0x1981, lo: 0x8b, hi: 0x8b}, + {value: 0x199c, lo: 0x8c, hi: 0x8c}, + {value: 0x19a2, lo: 0x8d, hi: 0x8d}, + {value: 0x1bc0, lo: 0x8e, hi: 0x8e}, + {value: 0x19ae, lo: 0x8f, hi: 0x8f}, + {value: 0x197b, lo: 0xaa, hi: 0xaa}, + {value: 0x197e, lo: 0xab, hi: 0xab}, + // Block 0x99, offset 0x35f + {value: 0x0000, lo: 0x01}, + {value: 0x193f, lo: 0x90, hi: 0x90}, + // Block 0x9a, offset 0x361 + {value: 0x0028, lo: 0x09}, + {value: 0x2862, lo: 0x80, hi: 0x80}, + {value: 0x2826, lo: 0x81, hi: 0x81}, + {value: 0x2830, lo: 0x82, hi: 0x82}, + {value: 0x2844, lo: 0x83, hi: 0x84}, + {value: 0x284e, lo: 0x85, hi: 0x86}, + {value: 0x283a, lo: 0x87, hi: 0x87}, + {value: 0x2858, lo: 0x88, hi: 0x88}, + {value: 0x0b6f, lo: 0x90, hi: 0x90}, + {value: 0x08e7, lo: 0x91, hi: 0x91}, +} + +// recompMap: 7520 bytes (entries only) +var recompMap = map[uint32]rune{ + 0x00410300: 0x00C0, + 0x00410301: 0x00C1, + 0x00410302: 0x00C2, + 0x00410303: 0x00C3, + 0x00410308: 0x00C4, + 0x0041030A: 0x00C5, + 0x00430327: 0x00C7, + 0x00450300: 0x00C8, + 0x00450301: 0x00C9, + 0x00450302: 0x00CA, + 0x00450308: 0x00CB, + 0x00490300: 0x00CC, + 0x00490301: 0x00CD, + 0x00490302: 0x00CE, + 0x00490308: 0x00CF, + 0x004E0303: 0x00D1, + 0x004F0300: 0x00D2, + 0x004F0301: 0x00D3, + 0x004F0302: 0x00D4, + 0x004F0303: 0x00D5, + 0x004F0308: 0x00D6, + 0x00550300: 0x00D9, + 0x00550301: 0x00DA, + 0x00550302: 0x00DB, + 0x00550308: 0x00DC, + 0x00590301: 0x00DD, + 0x00610300: 0x00E0, + 0x00610301: 0x00E1, + 0x00610302: 0x00E2, + 0x00610303: 0x00E3, + 0x00610308: 0x00E4, + 0x0061030A: 0x00E5, + 0x00630327: 0x00E7, + 0x00650300: 0x00E8, + 0x00650301: 0x00E9, + 0x00650302: 0x00EA, + 0x00650308: 0x00EB, + 0x00690300: 0x00EC, + 0x00690301: 0x00ED, + 0x00690302: 0x00EE, + 0x00690308: 0x00EF, + 0x006E0303: 0x00F1, + 0x006F0300: 0x00F2, + 0x006F0301: 0x00F3, + 0x006F0302: 0x00F4, + 0x006F0303: 0x00F5, + 0x006F0308: 0x00F6, + 0x00750300: 0x00F9, + 0x00750301: 0x00FA, + 0x00750302: 0x00FB, + 0x00750308: 0x00FC, + 0x00790301: 0x00FD, + 0x00790308: 0x00FF, + 0x00410304: 0x0100, + 0x00610304: 0x0101, + 0x00410306: 0x0102, + 0x00610306: 0x0103, + 0x00410328: 0x0104, + 0x00610328: 0x0105, + 0x00430301: 0x0106, + 0x00630301: 0x0107, + 0x00430302: 0x0108, + 0x00630302: 0x0109, + 0x00430307: 0x010A, + 0x00630307: 0x010B, + 0x0043030C: 0x010C, + 0x0063030C: 0x010D, + 0x0044030C: 0x010E, + 0x0064030C: 0x010F, + 0x00450304: 0x0112, + 0x00650304: 0x0113, + 0x00450306: 0x0114, + 0x00650306: 0x0115, + 0x00450307: 0x0116, + 0x00650307: 0x0117, + 0x00450328: 0x0118, + 0x00650328: 0x0119, + 0x0045030C: 0x011A, + 0x0065030C: 0x011B, + 0x00470302: 0x011C, + 0x00670302: 0x011D, + 0x00470306: 0x011E, + 0x00670306: 0x011F, + 0x00470307: 0x0120, + 0x00670307: 0x0121, + 0x00470327: 0x0122, + 0x00670327: 0x0123, + 0x00480302: 0x0124, + 0x00680302: 0x0125, + 0x00490303: 0x0128, + 0x00690303: 0x0129, + 0x00490304: 0x012A, + 0x00690304: 0x012B, + 0x00490306: 0x012C, + 0x00690306: 0x012D, + 0x00490328: 0x012E, + 0x00690328: 0x012F, + 0x00490307: 0x0130, + 0x004A0302: 0x0134, + 0x006A0302: 0x0135, + 0x004B0327: 0x0136, + 0x006B0327: 0x0137, + 0x004C0301: 0x0139, + 0x006C0301: 0x013A, + 0x004C0327: 0x013B, + 0x006C0327: 0x013C, + 0x004C030C: 0x013D, + 0x006C030C: 0x013E, + 0x004E0301: 0x0143, + 0x006E0301: 0x0144, + 0x004E0327: 0x0145, + 0x006E0327: 0x0146, + 0x004E030C: 0x0147, + 0x006E030C: 0x0148, + 0x004F0304: 0x014C, + 0x006F0304: 0x014D, + 0x004F0306: 0x014E, + 0x006F0306: 0x014F, + 0x004F030B: 0x0150, + 0x006F030B: 0x0151, + 0x00520301: 0x0154, + 0x00720301: 0x0155, + 0x00520327: 0x0156, + 0x00720327: 0x0157, + 0x0052030C: 0x0158, + 0x0072030C: 0x0159, + 0x00530301: 0x015A, + 0x00730301: 0x015B, + 0x00530302: 0x015C, + 0x00730302: 0x015D, + 0x00530327: 0x015E, + 0x00730327: 0x015F, + 0x0053030C: 0x0160, + 0x0073030C: 0x0161, + 0x00540327: 0x0162, + 0x00740327: 0x0163, + 0x0054030C: 0x0164, + 0x0074030C: 0x0165, + 0x00550303: 0x0168, + 0x00750303: 0x0169, + 0x00550304: 0x016A, + 0x00750304: 0x016B, + 0x00550306: 0x016C, + 0x00750306: 0x016D, + 0x0055030A: 0x016E, + 0x0075030A: 0x016F, + 0x0055030B: 0x0170, + 0x0075030B: 0x0171, + 0x00550328: 0x0172, + 0x00750328: 0x0173, + 0x00570302: 0x0174, + 0x00770302: 0x0175, + 0x00590302: 0x0176, + 0x00790302: 0x0177, + 0x00590308: 0x0178, + 0x005A0301: 0x0179, + 0x007A0301: 0x017A, + 0x005A0307: 0x017B, + 0x007A0307: 0x017C, + 0x005A030C: 0x017D, + 0x007A030C: 0x017E, + 0x004F031B: 0x01A0, + 0x006F031B: 0x01A1, + 0x0055031B: 0x01AF, + 0x0075031B: 0x01B0, + 0x0041030C: 0x01CD, + 0x0061030C: 0x01CE, + 0x0049030C: 0x01CF, + 0x0069030C: 0x01D0, + 0x004F030C: 0x01D1, + 0x006F030C: 0x01D2, + 0x0055030C: 0x01D3, + 0x0075030C: 0x01D4, + 0x00DC0304: 0x01D5, + 0x00FC0304: 0x01D6, + 0x00DC0301: 0x01D7, + 0x00FC0301: 0x01D8, + 0x00DC030C: 0x01D9, + 0x00FC030C: 0x01DA, + 0x00DC0300: 0x01DB, + 0x00FC0300: 0x01DC, + 0x00C40304: 0x01DE, + 0x00E40304: 0x01DF, + 0x02260304: 0x01E0, + 0x02270304: 0x01E1, + 0x00C60304: 0x01E2, + 0x00E60304: 0x01E3, + 0x0047030C: 0x01E6, + 0x0067030C: 0x01E7, + 0x004B030C: 0x01E8, + 0x006B030C: 0x01E9, + 0x004F0328: 0x01EA, + 0x006F0328: 0x01EB, + 0x01EA0304: 0x01EC, + 0x01EB0304: 0x01ED, + 0x01B7030C: 0x01EE, + 0x0292030C: 0x01EF, + 0x006A030C: 0x01F0, + 0x00470301: 0x01F4, + 0x00670301: 0x01F5, + 0x004E0300: 0x01F8, + 0x006E0300: 0x01F9, + 0x00C50301: 0x01FA, + 0x00E50301: 0x01FB, + 0x00C60301: 0x01FC, + 0x00E60301: 0x01FD, + 0x00D80301: 0x01FE, + 0x00F80301: 0x01FF, + 0x0041030F: 0x0200, + 0x0061030F: 0x0201, + 0x00410311: 0x0202, + 0x00610311: 0x0203, + 0x0045030F: 0x0204, + 0x0065030F: 0x0205, + 0x00450311: 0x0206, + 0x00650311: 0x0207, + 0x0049030F: 0x0208, + 0x0069030F: 0x0209, + 0x00490311: 0x020A, + 0x00690311: 0x020B, + 0x004F030F: 0x020C, + 0x006F030F: 0x020D, + 0x004F0311: 0x020E, + 0x006F0311: 0x020F, + 0x0052030F: 0x0210, + 0x0072030F: 0x0211, + 0x00520311: 0x0212, + 0x00720311: 0x0213, + 0x0055030F: 0x0214, + 0x0075030F: 0x0215, + 0x00550311: 0x0216, + 0x00750311: 0x0217, + 0x00530326: 0x0218, + 0x00730326: 0x0219, + 0x00540326: 0x021A, + 0x00740326: 0x021B, + 0x0048030C: 0x021E, + 0x0068030C: 0x021F, + 0x00410307: 0x0226, + 0x00610307: 0x0227, + 0x00450327: 0x0228, + 0x00650327: 0x0229, + 0x00D60304: 0x022A, + 0x00F60304: 0x022B, + 0x00D50304: 0x022C, + 0x00F50304: 0x022D, + 0x004F0307: 0x022E, + 0x006F0307: 0x022F, + 0x022E0304: 0x0230, + 0x022F0304: 0x0231, + 0x00590304: 0x0232, + 0x00790304: 0x0233, + 0x00A80301: 0x0385, + 0x03910301: 0x0386, + 0x03950301: 0x0388, + 0x03970301: 0x0389, + 0x03990301: 0x038A, + 0x039F0301: 0x038C, + 0x03A50301: 0x038E, + 0x03A90301: 0x038F, + 0x03CA0301: 0x0390, + 0x03990308: 0x03AA, + 0x03A50308: 0x03AB, + 0x03B10301: 0x03AC, + 0x03B50301: 0x03AD, + 0x03B70301: 0x03AE, + 0x03B90301: 0x03AF, + 0x03CB0301: 0x03B0, + 0x03B90308: 0x03CA, + 0x03C50308: 0x03CB, + 0x03BF0301: 0x03CC, + 0x03C50301: 0x03CD, + 0x03C90301: 0x03CE, + 0x03D20301: 0x03D3, + 0x03D20308: 0x03D4, + 0x04150300: 0x0400, + 0x04150308: 0x0401, + 0x04130301: 0x0403, + 0x04060308: 0x0407, + 0x041A0301: 0x040C, + 0x04180300: 0x040D, + 0x04230306: 0x040E, + 0x04180306: 0x0419, + 0x04380306: 0x0439, + 0x04350300: 0x0450, + 0x04350308: 0x0451, + 0x04330301: 0x0453, + 0x04560308: 0x0457, + 0x043A0301: 0x045C, + 0x04380300: 0x045D, + 0x04430306: 0x045E, + 0x0474030F: 0x0476, + 0x0475030F: 0x0477, + 0x04160306: 0x04C1, + 0x04360306: 0x04C2, + 0x04100306: 0x04D0, + 0x04300306: 0x04D1, + 0x04100308: 0x04D2, + 0x04300308: 0x04D3, + 0x04150306: 0x04D6, + 0x04350306: 0x04D7, + 0x04D80308: 0x04DA, + 0x04D90308: 0x04DB, + 0x04160308: 0x04DC, + 0x04360308: 0x04DD, + 0x04170308: 0x04DE, + 0x04370308: 0x04DF, + 0x04180304: 0x04E2, + 0x04380304: 0x04E3, + 0x04180308: 0x04E4, + 0x04380308: 0x04E5, + 0x041E0308: 0x04E6, + 0x043E0308: 0x04E7, + 0x04E80308: 0x04EA, + 0x04E90308: 0x04EB, + 0x042D0308: 0x04EC, + 0x044D0308: 0x04ED, + 0x04230304: 0x04EE, + 0x04430304: 0x04EF, + 0x04230308: 0x04F0, + 0x04430308: 0x04F1, + 0x0423030B: 0x04F2, + 0x0443030B: 0x04F3, + 0x04270308: 0x04F4, + 0x04470308: 0x04F5, + 0x042B0308: 0x04F8, + 0x044B0308: 0x04F9, + 0x06270653: 0x0622, + 0x06270654: 0x0623, + 0x06480654: 0x0624, + 0x06270655: 0x0625, + 0x064A0654: 0x0626, + 0x06D50654: 0x06C0, + 0x06C10654: 0x06C2, + 0x06D20654: 0x06D3, + 0x0928093C: 0x0929, + 0x0930093C: 0x0931, + 0x0933093C: 0x0934, + 0x09C709BE: 0x09CB, + 0x09C709D7: 0x09CC, + 0x0B470B56: 0x0B48, + 0x0B470B3E: 0x0B4B, + 0x0B470B57: 0x0B4C, + 0x0B920BD7: 0x0B94, + 0x0BC60BBE: 0x0BCA, + 0x0BC70BBE: 0x0BCB, + 0x0BC60BD7: 0x0BCC, + 0x0C460C56: 0x0C48, + 0x0CBF0CD5: 0x0CC0, + 0x0CC60CD5: 0x0CC7, + 0x0CC60CD6: 0x0CC8, + 0x0CC60CC2: 0x0CCA, + 0x0CCA0CD5: 0x0CCB, + 0x0D460D3E: 0x0D4A, + 0x0D470D3E: 0x0D4B, + 0x0D460D57: 0x0D4C, + 0x0DD90DCA: 0x0DDA, + 0x0DD90DCF: 0x0DDC, + 0x0DDC0DCA: 0x0DDD, + 0x0DD90DDF: 0x0DDE, + 0x1025102E: 0x1026, + 0x1B051B35: 0x1B06, + 0x1B071B35: 0x1B08, + 0x1B091B35: 0x1B0A, + 0x1B0B1B35: 0x1B0C, + 0x1B0D1B35: 0x1B0E, + 0x1B111B35: 0x1B12, + 0x1B3A1B35: 0x1B3B, + 0x1B3C1B35: 0x1B3D, + 0x1B3E1B35: 0x1B40, + 0x1B3F1B35: 0x1B41, + 0x1B421B35: 0x1B43, + 0x00410325: 0x1E00, + 0x00610325: 0x1E01, + 0x00420307: 0x1E02, + 0x00620307: 0x1E03, + 0x00420323: 0x1E04, + 0x00620323: 0x1E05, + 0x00420331: 0x1E06, + 0x00620331: 0x1E07, + 0x00C70301: 0x1E08, + 0x00E70301: 0x1E09, + 0x00440307: 0x1E0A, + 0x00640307: 0x1E0B, + 0x00440323: 0x1E0C, + 0x00640323: 0x1E0D, + 0x00440331: 0x1E0E, + 0x00640331: 0x1E0F, + 0x00440327: 0x1E10, + 0x00640327: 0x1E11, + 0x0044032D: 0x1E12, + 0x0064032D: 0x1E13, + 0x01120300: 0x1E14, + 0x01130300: 0x1E15, + 0x01120301: 0x1E16, + 0x01130301: 0x1E17, + 0x0045032D: 0x1E18, + 0x0065032D: 0x1E19, + 0x00450330: 0x1E1A, + 0x00650330: 0x1E1B, + 0x02280306: 0x1E1C, + 0x02290306: 0x1E1D, + 0x00460307: 0x1E1E, + 0x00660307: 0x1E1F, + 0x00470304: 0x1E20, + 0x00670304: 0x1E21, + 0x00480307: 0x1E22, + 0x00680307: 0x1E23, + 0x00480323: 0x1E24, + 0x00680323: 0x1E25, + 0x00480308: 0x1E26, + 0x00680308: 0x1E27, + 0x00480327: 0x1E28, + 0x00680327: 0x1E29, + 0x0048032E: 0x1E2A, + 0x0068032E: 0x1E2B, + 0x00490330: 0x1E2C, + 0x00690330: 0x1E2D, + 0x00CF0301: 0x1E2E, + 0x00EF0301: 0x1E2F, + 0x004B0301: 0x1E30, + 0x006B0301: 0x1E31, + 0x004B0323: 0x1E32, + 0x006B0323: 0x1E33, + 0x004B0331: 0x1E34, + 0x006B0331: 0x1E35, + 0x004C0323: 0x1E36, + 0x006C0323: 0x1E37, + 0x1E360304: 0x1E38, + 0x1E370304: 0x1E39, + 0x004C0331: 0x1E3A, + 0x006C0331: 0x1E3B, + 0x004C032D: 0x1E3C, + 0x006C032D: 0x1E3D, + 0x004D0301: 0x1E3E, + 0x006D0301: 0x1E3F, + 0x004D0307: 0x1E40, + 0x006D0307: 0x1E41, + 0x004D0323: 0x1E42, + 0x006D0323: 0x1E43, + 0x004E0307: 0x1E44, + 0x006E0307: 0x1E45, + 0x004E0323: 0x1E46, + 0x006E0323: 0x1E47, + 0x004E0331: 0x1E48, + 0x006E0331: 0x1E49, + 0x004E032D: 0x1E4A, + 0x006E032D: 0x1E4B, + 0x00D50301: 0x1E4C, + 0x00F50301: 0x1E4D, + 0x00D50308: 0x1E4E, + 0x00F50308: 0x1E4F, + 0x014C0300: 0x1E50, + 0x014D0300: 0x1E51, + 0x014C0301: 0x1E52, + 0x014D0301: 0x1E53, + 0x00500301: 0x1E54, + 0x00700301: 0x1E55, + 0x00500307: 0x1E56, + 0x00700307: 0x1E57, + 0x00520307: 0x1E58, + 0x00720307: 0x1E59, + 0x00520323: 0x1E5A, + 0x00720323: 0x1E5B, + 0x1E5A0304: 0x1E5C, + 0x1E5B0304: 0x1E5D, + 0x00520331: 0x1E5E, + 0x00720331: 0x1E5F, + 0x00530307: 0x1E60, + 0x00730307: 0x1E61, + 0x00530323: 0x1E62, + 0x00730323: 0x1E63, + 0x015A0307: 0x1E64, + 0x015B0307: 0x1E65, + 0x01600307: 0x1E66, + 0x01610307: 0x1E67, + 0x1E620307: 0x1E68, + 0x1E630307: 0x1E69, + 0x00540307: 0x1E6A, + 0x00740307: 0x1E6B, + 0x00540323: 0x1E6C, + 0x00740323: 0x1E6D, + 0x00540331: 0x1E6E, + 0x00740331: 0x1E6F, + 0x0054032D: 0x1E70, + 0x0074032D: 0x1E71, + 0x00550324: 0x1E72, + 0x00750324: 0x1E73, + 0x00550330: 0x1E74, + 0x00750330: 0x1E75, + 0x0055032D: 0x1E76, + 0x0075032D: 0x1E77, + 0x01680301: 0x1E78, + 0x01690301: 0x1E79, + 0x016A0308: 0x1E7A, + 0x016B0308: 0x1E7B, + 0x00560303: 0x1E7C, + 0x00760303: 0x1E7D, + 0x00560323: 0x1E7E, + 0x00760323: 0x1E7F, + 0x00570300: 0x1E80, + 0x00770300: 0x1E81, + 0x00570301: 0x1E82, + 0x00770301: 0x1E83, + 0x00570308: 0x1E84, + 0x00770308: 0x1E85, + 0x00570307: 0x1E86, + 0x00770307: 0x1E87, + 0x00570323: 0x1E88, + 0x00770323: 0x1E89, + 0x00580307: 0x1E8A, + 0x00780307: 0x1E8B, + 0x00580308: 0x1E8C, + 0x00780308: 0x1E8D, + 0x00590307: 0x1E8E, + 0x00790307: 0x1E8F, + 0x005A0302: 0x1E90, + 0x007A0302: 0x1E91, + 0x005A0323: 0x1E92, + 0x007A0323: 0x1E93, + 0x005A0331: 0x1E94, + 0x007A0331: 0x1E95, + 0x00680331: 0x1E96, + 0x00740308: 0x1E97, + 0x0077030A: 0x1E98, + 0x0079030A: 0x1E99, + 0x017F0307: 0x1E9B, + 0x00410323: 0x1EA0, + 0x00610323: 0x1EA1, + 0x00410309: 0x1EA2, + 0x00610309: 0x1EA3, + 0x00C20301: 0x1EA4, + 0x00E20301: 0x1EA5, + 0x00C20300: 0x1EA6, + 0x00E20300: 0x1EA7, + 0x00C20309: 0x1EA8, + 0x00E20309: 0x1EA9, + 0x00C20303: 0x1EAA, + 0x00E20303: 0x1EAB, + 0x1EA00302: 0x1EAC, + 0x1EA10302: 0x1EAD, + 0x01020301: 0x1EAE, + 0x01030301: 0x1EAF, + 0x01020300: 0x1EB0, + 0x01030300: 0x1EB1, + 0x01020309: 0x1EB2, + 0x01030309: 0x1EB3, + 0x01020303: 0x1EB4, + 0x01030303: 0x1EB5, + 0x1EA00306: 0x1EB6, + 0x1EA10306: 0x1EB7, + 0x00450323: 0x1EB8, + 0x00650323: 0x1EB9, + 0x00450309: 0x1EBA, + 0x00650309: 0x1EBB, + 0x00450303: 0x1EBC, + 0x00650303: 0x1EBD, + 0x00CA0301: 0x1EBE, + 0x00EA0301: 0x1EBF, + 0x00CA0300: 0x1EC0, + 0x00EA0300: 0x1EC1, + 0x00CA0309: 0x1EC2, + 0x00EA0309: 0x1EC3, + 0x00CA0303: 0x1EC4, + 0x00EA0303: 0x1EC5, + 0x1EB80302: 0x1EC6, + 0x1EB90302: 0x1EC7, + 0x00490309: 0x1EC8, + 0x00690309: 0x1EC9, + 0x00490323: 0x1ECA, + 0x00690323: 0x1ECB, + 0x004F0323: 0x1ECC, + 0x006F0323: 0x1ECD, + 0x004F0309: 0x1ECE, + 0x006F0309: 0x1ECF, + 0x00D40301: 0x1ED0, + 0x00F40301: 0x1ED1, + 0x00D40300: 0x1ED2, + 0x00F40300: 0x1ED3, + 0x00D40309: 0x1ED4, + 0x00F40309: 0x1ED5, + 0x00D40303: 0x1ED6, + 0x00F40303: 0x1ED7, + 0x1ECC0302: 0x1ED8, + 0x1ECD0302: 0x1ED9, + 0x01A00301: 0x1EDA, + 0x01A10301: 0x1EDB, + 0x01A00300: 0x1EDC, + 0x01A10300: 0x1EDD, + 0x01A00309: 0x1EDE, + 0x01A10309: 0x1EDF, + 0x01A00303: 0x1EE0, + 0x01A10303: 0x1EE1, + 0x01A00323: 0x1EE2, + 0x01A10323: 0x1EE3, + 0x00550323: 0x1EE4, + 0x00750323: 0x1EE5, + 0x00550309: 0x1EE6, + 0x00750309: 0x1EE7, + 0x01AF0301: 0x1EE8, + 0x01B00301: 0x1EE9, + 0x01AF0300: 0x1EEA, + 0x01B00300: 0x1EEB, + 0x01AF0309: 0x1EEC, + 0x01B00309: 0x1EED, + 0x01AF0303: 0x1EEE, + 0x01B00303: 0x1EEF, + 0x01AF0323: 0x1EF0, + 0x01B00323: 0x1EF1, + 0x00590300: 0x1EF2, + 0x00790300: 0x1EF3, + 0x00590323: 0x1EF4, + 0x00790323: 0x1EF5, + 0x00590309: 0x1EF6, + 0x00790309: 0x1EF7, + 0x00590303: 0x1EF8, + 0x00790303: 0x1EF9, + 0x03B10313: 0x1F00, + 0x03B10314: 0x1F01, + 0x1F000300: 0x1F02, + 0x1F010300: 0x1F03, + 0x1F000301: 0x1F04, + 0x1F010301: 0x1F05, + 0x1F000342: 0x1F06, + 0x1F010342: 0x1F07, + 0x03910313: 0x1F08, + 0x03910314: 0x1F09, + 0x1F080300: 0x1F0A, + 0x1F090300: 0x1F0B, + 0x1F080301: 0x1F0C, + 0x1F090301: 0x1F0D, + 0x1F080342: 0x1F0E, + 0x1F090342: 0x1F0F, + 0x03B50313: 0x1F10, + 0x03B50314: 0x1F11, + 0x1F100300: 0x1F12, + 0x1F110300: 0x1F13, + 0x1F100301: 0x1F14, + 0x1F110301: 0x1F15, + 0x03950313: 0x1F18, + 0x03950314: 0x1F19, + 0x1F180300: 0x1F1A, + 0x1F190300: 0x1F1B, + 0x1F180301: 0x1F1C, + 0x1F190301: 0x1F1D, + 0x03B70313: 0x1F20, + 0x03B70314: 0x1F21, + 0x1F200300: 0x1F22, + 0x1F210300: 0x1F23, + 0x1F200301: 0x1F24, + 0x1F210301: 0x1F25, + 0x1F200342: 0x1F26, + 0x1F210342: 0x1F27, + 0x03970313: 0x1F28, + 0x03970314: 0x1F29, + 0x1F280300: 0x1F2A, + 0x1F290300: 0x1F2B, + 0x1F280301: 0x1F2C, + 0x1F290301: 0x1F2D, + 0x1F280342: 0x1F2E, + 0x1F290342: 0x1F2F, + 0x03B90313: 0x1F30, + 0x03B90314: 0x1F31, + 0x1F300300: 0x1F32, + 0x1F310300: 0x1F33, + 0x1F300301: 0x1F34, + 0x1F310301: 0x1F35, + 0x1F300342: 0x1F36, + 0x1F310342: 0x1F37, + 0x03990313: 0x1F38, + 0x03990314: 0x1F39, + 0x1F380300: 0x1F3A, + 0x1F390300: 0x1F3B, + 0x1F380301: 0x1F3C, + 0x1F390301: 0x1F3D, + 0x1F380342: 0x1F3E, + 0x1F390342: 0x1F3F, + 0x03BF0313: 0x1F40, + 0x03BF0314: 0x1F41, + 0x1F400300: 0x1F42, + 0x1F410300: 0x1F43, + 0x1F400301: 0x1F44, + 0x1F410301: 0x1F45, + 0x039F0313: 0x1F48, + 0x039F0314: 0x1F49, + 0x1F480300: 0x1F4A, + 0x1F490300: 0x1F4B, + 0x1F480301: 0x1F4C, + 0x1F490301: 0x1F4D, + 0x03C50313: 0x1F50, + 0x03C50314: 0x1F51, + 0x1F500300: 0x1F52, + 0x1F510300: 0x1F53, + 0x1F500301: 0x1F54, + 0x1F510301: 0x1F55, + 0x1F500342: 0x1F56, + 0x1F510342: 0x1F57, + 0x03A50314: 0x1F59, + 0x1F590300: 0x1F5B, + 0x1F590301: 0x1F5D, + 0x1F590342: 0x1F5F, + 0x03C90313: 0x1F60, + 0x03C90314: 0x1F61, + 0x1F600300: 0x1F62, + 0x1F610300: 0x1F63, + 0x1F600301: 0x1F64, + 0x1F610301: 0x1F65, + 0x1F600342: 0x1F66, + 0x1F610342: 0x1F67, + 0x03A90313: 0x1F68, + 0x03A90314: 0x1F69, + 0x1F680300: 0x1F6A, + 0x1F690300: 0x1F6B, + 0x1F680301: 0x1F6C, + 0x1F690301: 0x1F6D, + 0x1F680342: 0x1F6E, + 0x1F690342: 0x1F6F, + 0x03B10300: 0x1F70, + 0x03B50300: 0x1F72, + 0x03B70300: 0x1F74, + 0x03B90300: 0x1F76, + 0x03BF0300: 0x1F78, + 0x03C50300: 0x1F7A, + 0x03C90300: 0x1F7C, + 0x1F000345: 0x1F80, + 0x1F010345: 0x1F81, + 0x1F020345: 0x1F82, + 0x1F030345: 0x1F83, + 0x1F040345: 0x1F84, + 0x1F050345: 0x1F85, + 0x1F060345: 0x1F86, + 0x1F070345: 0x1F87, + 0x1F080345: 0x1F88, + 0x1F090345: 0x1F89, + 0x1F0A0345: 0x1F8A, + 0x1F0B0345: 0x1F8B, + 0x1F0C0345: 0x1F8C, + 0x1F0D0345: 0x1F8D, + 0x1F0E0345: 0x1F8E, + 0x1F0F0345: 0x1F8F, + 0x1F200345: 0x1F90, + 0x1F210345: 0x1F91, + 0x1F220345: 0x1F92, + 0x1F230345: 0x1F93, + 0x1F240345: 0x1F94, + 0x1F250345: 0x1F95, + 0x1F260345: 0x1F96, + 0x1F270345: 0x1F97, + 0x1F280345: 0x1F98, + 0x1F290345: 0x1F99, + 0x1F2A0345: 0x1F9A, + 0x1F2B0345: 0x1F9B, + 0x1F2C0345: 0x1F9C, + 0x1F2D0345: 0x1F9D, + 0x1F2E0345: 0x1F9E, + 0x1F2F0345: 0x1F9F, + 0x1F600345: 0x1FA0, + 0x1F610345: 0x1FA1, + 0x1F620345: 0x1FA2, + 0x1F630345: 0x1FA3, + 0x1F640345: 0x1FA4, + 0x1F650345: 0x1FA5, + 0x1F660345: 0x1FA6, + 0x1F670345: 0x1FA7, + 0x1F680345: 0x1FA8, + 0x1F690345: 0x1FA9, + 0x1F6A0345: 0x1FAA, + 0x1F6B0345: 0x1FAB, + 0x1F6C0345: 0x1FAC, + 0x1F6D0345: 0x1FAD, + 0x1F6E0345: 0x1FAE, + 0x1F6F0345: 0x1FAF, + 0x03B10306: 0x1FB0, + 0x03B10304: 0x1FB1, + 0x1F700345: 0x1FB2, + 0x03B10345: 0x1FB3, + 0x03AC0345: 0x1FB4, + 0x03B10342: 0x1FB6, + 0x1FB60345: 0x1FB7, + 0x03910306: 0x1FB8, + 0x03910304: 0x1FB9, + 0x03910300: 0x1FBA, + 0x03910345: 0x1FBC, + 0x00A80342: 0x1FC1, + 0x1F740345: 0x1FC2, + 0x03B70345: 0x1FC3, + 0x03AE0345: 0x1FC4, + 0x03B70342: 0x1FC6, + 0x1FC60345: 0x1FC7, + 0x03950300: 0x1FC8, + 0x03970300: 0x1FCA, + 0x03970345: 0x1FCC, + 0x1FBF0300: 0x1FCD, + 0x1FBF0301: 0x1FCE, + 0x1FBF0342: 0x1FCF, + 0x03B90306: 0x1FD0, + 0x03B90304: 0x1FD1, + 0x03CA0300: 0x1FD2, + 0x03B90342: 0x1FD6, + 0x03CA0342: 0x1FD7, + 0x03990306: 0x1FD8, + 0x03990304: 0x1FD9, + 0x03990300: 0x1FDA, + 0x1FFE0300: 0x1FDD, + 0x1FFE0301: 0x1FDE, + 0x1FFE0342: 0x1FDF, + 0x03C50306: 0x1FE0, + 0x03C50304: 0x1FE1, + 0x03CB0300: 0x1FE2, + 0x03C10313: 0x1FE4, + 0x03C10314: 0x1FE5, + 0x03C50342: 0x1FE6, + 0x03CB0342: 0x1FE7, + 0x03A50306: 0x1FE8, + 0x03A50304: 0x1FE9, + 0x03A50300: 0x1FEA, + 0x03A10314: 0x1FEC, + 0x00A80300: 0x1FED, + 0x1F7C0345: 0x1FF2, + 0x03C90345: 0x1FF3, + 0x03CE0345: 0x1FF4, + 0x03C90342: 0x1FF6, + 0x1FF60345: 0x1FF7, + 0x039F0300: 0x1FF8, + 0x03A90300: 0x1FFA, + 0x03A90345: 0x1FFC, + 0x21900338: 0x219A, + 0x21920338: 0x219B, + 0x21940338: 0x21AE, + 0x21D00338: 0x21CD, + 0x21D40338: 0x21CE, + 0x21D20338: 0x21CF, + 0x22030338: 0x2204, + 0x22080338: 0x2209, + 0x220B0338: 0x220C, + 0x22230338: 0x2224, + 0x22250338: 0x2226, + 0x223C0338: 0x2241, + 0x22430338: 0x2244, + 0x22450338: 0x2247, + 0x22480338: 0x2249, + 0x003D0338: 0x2260, + 0x22610338: 0x2262, + 0x224D0338: 0x226D, + 0x003C0338: 0x226E, + 0x003E0338: 0x226F, + 0x22640338: 0x2270, + 0x22650338: 0x2271, + 0x22720338: 0x2274, + 0x22730338: 0x2275, + 0x22760338: 0x2278, + 0x22770338: 0x2279, + 0x227A0338: 0x2280, + 0x227B0338: 0x2281, + 0x22820338: 0x2284, + 0x22830338: 0x2285, + 0x22860338: 0x2288, + 0x22870338: 0x2289, + 0x22A20338: 0x22AC, + 0x22A80338: 0x22AD, + 0x22A90338: 0x22AE, + 0x22AB0338: 0x22AF, + 0x227C0338: 0x22E0, + 0x227D0338: 0x22E1, + 0x22910338: 0x22E2, + 0x22920338: 0x22E3, + 0x22B20338: 0x22EA, + 0x22B30338: 0x22EB, + 0x22B40338: 0x22EC, + 0x22B50338: 0x22ED, + 0x304B3099: 0x304C, + 0x304D3099: 0x304E, + 0x304F3099: 0x3050, + 0x30513099: 0x3052, + 0x30533099: 0x3054, + 0x30553099: 0x3056, + 0x30573099: 0x3058, + 0x30593099: 0x305A, + 0x305B3099: 0x305C, + 0x305D3099: 0x305E, + 0x305F3099: 0x3060, + 0x30613099: 0x3062, + 0x30643099: 0x3065, + 0x30663099: 0x3067, + 0x30683099: 0x3069, + 0x306F3099: 0x3070, + 0x306F309A: 0x3071, + 0x30723099: 0x3073, + 0x3072309A: 0x3074, + 0x30753099: 0x3076, + 0x3075309A: 0x3077, + 0x30783099: 0x3079, + 0x3078309A: 0x307A, + 0x307B3099: 0x307C, + 0x307B309A: 0x307D, + 0x30463099: 0x3094, + 0x309D3099: 0x309E, + 0x30AB3099: 0x30AC, + 0x30AD3099: 0x30AE, + 0x30AF3099: 0x30B0, + 0x30B13099: 0x30B2, + 0x30B33099: 0x30B4, + 0x30B53099: 0x30B6, + 0x30B73099: 0x30B8, + 0x30B93099: 0x30BA, + 0x30BB3099: 0x30BC, + 0x30BD3099: 0x30BE, + 0x30BF3099: 0x30C0, + 0x30C13099: 0x30C2, + 0x30C43099: 0x30C5, + 0x30C63099: 0x30C7, + 0x30C83099: 0x30C9, + 0x30CF3099: 0x30D0, + 0x30CF309A: 0x30D1, + 0x30D23099: 0x30D3, + 0x30D2309A: 0x30D4, + 0x30D53099: 0x30D6, + 0x30D5309A: 0x30D7, + 0x30D83099: 0x30D9, + 0x30D8309A: 0x30DA, + 0x30DB3099: 0x30DC, + 0x30DB309A: 0x30DD, + 0x30A63099: 0x30F4, + 0x30EF3099: 0x30F7, + 0x30F03099: 0x30F8, + 0x30F13099: 0x30F9, + 0x30F23099: 0x30FA, + 0x30FD3099: 0x30FE, + 0x109910BA: 0x1109A, + 0x109B10BA: 0x1109C, + 0x10A510BA: 0x110AB, + 0x11311127: 0x1112E, + 0x11321127: 0x1112F, + 0x1347133E: 0x1134B, + 0x13471357: 0x1134C, + 0x14B914BA: 0x114BB, + 0x14B914B0: 0x114BC, + 0x14B914BD: 0x114BE, + 0x15B815AF: 0x115BA, + 0x15B915AF: 0x115BB, +} + +// Total size of tables: 53KB (54006 bytes) diff --git a/vendor/golang.org/x/text/unicode/norm/transform.go b/vendor/golang.org/x/text/unicode/norm/transform.go new file mode 100644 index 0000000000..9f47efbaf6 --- /dev/null +++ b/vendor/golang.org/x/text/unicode/norm/transform.go @@ -0,0 +1,88 @@ +// Copyright 2013 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 norm + +import ( + "unicode/utf8" + + "golang.org/x/text/transform" +) + +// Reset implements the Reset method of the transform.Transformer interface. +func (Form) Reset() {} + +// Transform implements the Transform method of the transform.Transformer +// interface. It may need to write segments of up to MaxSegmentSize at once. +// Users should either catch ErrShortDst and allow dst to grow or have dst be at +// least of size MaxTransformChunkSize to be guaranteed of progress. +func (f Form) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + n := 0 + // Cap the maximum number of src bytes to check. + b := src + eof := atEOF + if ns := len(dst); ns < len(b) { + err = transform.ErrShortDst + eof = false + b = b[:ns] + } + i, ok := formTable[f].quickSpan(inputBytes(b), n, len(b), eof) + n += copy(dst[n:], b[n:i]) + if !ok { + nDst, nSrc, err = f.transform(dst[n:], src[n:], atEOF) + return nDst + n, nSrc + n, err + } + if n < len(src) && !atEOF { + err = transform.ErrShortSrc + } + return n, n, err +} + +func flushTransform(rb *reorderBuffer) bool { + // Write out (must fully fit in dst, or else it is an ErrShortDst). + if len(rb.out) < rb.nrune*utf8.UTFMax { + return false + } + rb.out = rb.out[rb.flushCopy(rb.out):] + return true +} + +var errs = []error{nil, transform.ErrShortDst, transform.ErrShortSrc} + +// transform implements the transform.Transformer interface. It is only called +// when quickSpan does not pass for a given string. +func (f Form) transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + // TODO: get rid of reorderBuffer. See CL 23460044. + rb := reorderBuffer{} + rb.init(f, src) + for { + // Load segment into reorder buffer. + rb.setFlusher(dst[nDst:], flushTransform) + end := decomposeSegment(&rb, nSrc, atEOF) + if end < 0 { + return nDst, nSrc, errs[-end] + } + nDst = len(dst) - len(rb.out) + nSrc = end + + // Next quickSpan. + end = rb.nsrc + eof := atEOF + if n := nSrc + len(dst) - nDst; n < end { + err = transform.ErrShortDst + end = n + eof = false + } + end, ok := rb.f.quickSpan(rb.src, nSrc, end, eof) + n := copy(dst[nDst:], rb.src.bytes[nSrc:end]) + nSrc += n + nDst += n + if ok { + if n < rb.nsrc && !atEOF { + err = transform.ErrShortSrc + } + return nDst, nSrc, err + } + } +} diff --git a/vendor/golang.org/x/text/unicode/norm/trie.go b/vendor/golang.org/x/text/unicode/norm/trie.go new file mode 100644 index 0000000000..423386bf43 --- /dev/null +++ b/vendor/golang.org/x/text/unicode/norm/trie.go @@ -0,0 +1,54 @@ +// Copyright 2011 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 norm + +type valueRange struct { + value uint16 // header: value:stride + lo, hi byte // header: lo:n +} + +type sparseBlocks struct { + values []valueRange + offset []uint16 +} + +var nfcSparse = sparseBlocks{ + values: nfcSparseValues[:], + offset: nfcSparseOffset[:], +} + +var nfkcSparse = sparseBlocks{ + values: nfkcSparseValues[:], + offset: nfkcSparseOffset[:], +} + +var ( + nfcData = newNfcTrie(0) + nfkcData = newNfkcTrie(0) +) + +// lookupValue determines the type of block n and looks up the value for b. +// For n < t.cutoff, the block is a simple lookup table. Otherwise, the block +// is a list of ranges with an accompanying value. Given a matching range r, +// the value for b is by r.value + (b - r.lo) * stride. +func (t *sparseBlocks) lookup(n uint32, b byte) uint16 { + offset := t.offset[n] + header := t.values[offset] + lo := offset + 1 + hi := lo + uint16(header.lo) + for lo < hi { + m := lo + (hi-lo)/2 + r := t.values[m] + if r.lo <= b && b <= r.hi { + return r.value + uint16(b-r.lo)*header.value + } + if b < r.lo { + hi = m + } else { + lo = m + 1 + } + } + return 0 +} diff --git a/vendor/golang.org/x/tools/imports/fastwalk.go b/vendor/golang.org/x/tools/imports/fastwalk.go deleted file mode 100644 index 157c79225b..0000000000 --- a/vendor/golang.org/x/tools/imports/fastwalk.go +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright 2016 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. - -// A faster implementation of filepath.Walk. -// -// filepath.Walk's design necessarily calls os.Lstat on each file, -// even if the caller needs less info. And goimports only need to know -// the type of each file. The kernel interface provides the type in -// the Readdir call but the standard library ignored it. -// fastwalk_unix.go contains a fork of the syscall routines. -// -// See golang.org/issue/16399 - -package imports - -import ( - "errors" - "os" - "path/filepath" - "runtime" -) - -// traverseLink is a sentinel error for fastWalk, similar to filepath.SkipDir. -var traverseLink = errors.New("traverse symlink, assuming target is a directory") - -// fastWalk walks the file tree rooted at root, calling walkFn for -// each file or directory in the tree, including root. -// -// If fastWalk returns filepath.SkipDir, the directory is skipped. -// -// Unlike filepath.Walk: -// * file stat calls must be done by the user. -// The only provided metadata is the file type, which does not include -// any permission bits. -// * multiple goroutines stat the filesystem concurrently. The provided -// walkFn must be safe for concurrent use. -// * fastWalk can follow symlinks if walkFn returns the traverseLink -// sentinel error. It is the walkFn's responsibility to prevent -// fastWalk from going into symlink cycles. -func fastWalk(root string, walkFn func(path string, typ os.FileMode) error) error { - // TODO(bradfitz): make numWorkers configurable? We used a - // minimum of 4 to give the kernel more info about multiple - // things we want, in hopes its I/O scheduling can take - // advantage of that. Hopefully most are in cache. Maybe 4 is - // even too low of a minimum. Profile more. - numWorkers := 4 - if n := runtime.NumCPU(); n > numWorkers { - numWorkers = n - } - w := &walker{ - fn: walkFn, - enqueuec: make(chan walkItem, numWorkers), // buffered for performance - workc: make(chan walkItem, numWorkers), // buffered for performance - donec: make(chan struct{}), - - // buffered for correctness & not leaking goroutines: - resc: make(chan error, numWorkers), - } - defer close(w.donec) - // TODO(bradfitz): start the workers as needed? maybe not worth it. - for i := 0; i < numWorkers; i++ { - go w.doWork() - } - todo := []walkItem{{dir: root}} - out := 0 - for { - workc := w.workc - var workItem walkItem - if len(todo) == 0 { - workc = nil - } else { - workItem = todo[len(todo)-1] - } - select { - case workc <- workItem: - todo = todo[:len(todo)-1] - out++ - case it := <-w.enqueuec: - todo = append(todo, it) - case err := <-w.resc: - out-- - if err != nil { - return err - } - if out == 0 && len(todo) == 0 { - // It's safe to quit here, as long as the buffered - // enqueue channel isn't also readable, which might - // happen if the worker sends both another unit of - // work and its result before the other select was - // scheduled and both w.resc and w.enqueuec were - // readable. - select { - case it := <-w.enqueuec: - todo = append(todo, it) - default: - return nil - } - } - } - } -} - -// doWork reads directories as instructed (via workc) and runs the -// user's callback function. -func (w *walker) doWork() { - for { - select { - case <-w.donec: - return - case it := <-w.workc: - w.resc <- w.walk(it.dir, !it.callbackDone) - } - } -} - -type walker struct { - fn func(path string, typ os.FileMode) error - - donec chan struct{} // closed on fastWalk's return - workc chan walkItem // to workers - enqueuec chan walkItem // from workers - resc chan error // from workers -} - -type walkItem struct { - dir string - callbackDone bool // callback already called; don't do it again -} - -func (w *walker) enqueue(it walkItem) { - select { - case w.enqueuec <- it: - case <-w.donec: - } -} - -func (w *walker) onDirEnt(dirName, baseName string, typ os.FileMode) error { - joined := dirName + string(os.PathSeparator) + baseName - if typ == os.ModeDir { - w.enqueue(walkItem{dir: joined}) - return nil - } - - err := w.fn(joined, typ) - if typ == os.ModeSymlink { - if err == traverseLink { - // Set callbackDone so we don't call it twice for both the - // symlink-as-symlink and the symlink-as-directory later: - w.enqueue(walkItem{dir: joined, callbackDone: true}) - return nil - } - if err == filepath.SkipDir { - // Permit SkipDir on symlinks too. - return nil - } - } - return err -} -func (w *walker) walk(root string, runUserCallback bool) error { - if runUserCallback { - err := w.fn(root, os.ModeDir) - if err == filepath.SkipDir { - return nil - } - if err != nil { - return err - } - } - - return readDir(root, w.onDirEnt) -} diff --git a/vendor/golang.org/x/tools/imports/fastwalk_dirent_fileno.go b/vendor/golang.org/x/tools/imports/fastwalk_dirent_fileno.go deleted file mode 100644 index f1fd64949d..0000000000 --- a/vendor/golang.org/x/tools/imports/fastwalk_dirent_fileno.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2016 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 freebsd openbsd netbsd - -package imports - -import "syscall" - -func direntInode(dirent *syscall.Dirent) uint64 { - return uint64(dirent.Fileno) -} diff --git a/vendor/golang.org/x/tools/imports/fastwalk_portable.go b/vendor/golang.org/x/tools/imports/fastwalk_portable.go deleted file mode 100644 index 6c2658347d..0000000000 --- a/vendor/golang.org/x/tools/imports/fastwalk_portable.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2016 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 !linux,!darwin,!freebsd,!openbsd,!netbsd - -package imports - -import ( - "io/ioutil" - "os" -) - -// readDir calls fn for each directory entry in dirName. -// It does not descend into directories or follow symlinks. -// If fn returns a non-nil error, readDir returns with that error -// immediately. -func readDir(dirName string, fn func(dirName, entName string, typ os.FileMode) error) error { - fis, err := ioutil.ReadDir(dirName) - if err != nil { - return err - } - for _, fi := range fis { - if err := fn(dirName, fi.Name(), fi.Mode()&os.ModeType); err != nil { - return err - } - } - return nil -} diff --git a/vendor/golang.org/x/tools/imports/fastwalk_unix.go b/vendor/golang.org/x/tools/imports/fastwalk_unix.go deleted file mode 100644 index 5854233db9..0000000000 --- a/vendor/golang.org/x/tools/imports/fastwalk_unix.go +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2016 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 linux,!appengine darwin freebsd openbsd netbsd - -package imports - -import ( - "bytes" - "fmt" - "os" - "syscall" - "unsafe" -) - -const blockSize = 8 << 10 - -// unknownFileMode is a sentinel (and bogus) os.FileMode -// value used to represent a syscall.DT_UNKNOWN Dirent.Type. -const unknownFileMode os.FileMode = os.ModeNamedPipe | os.ModeSocket | os.ModeDevice - -func readDir(dirName string, fn func(dirName, entName string, typ os.FileMode) error) error { - fd, err := syscall.Open(dirName, 0, 0) - if err != nil { - return err - } - defer syscall.Close(fd) - - // The buffer must be at least a block long. - buf := make([]byte, blockSize) // stack-allocated; doesn't escape - bufp := 0 // starting read position in buf - nbuf := 0 // end valid data in buf - for { - if bufp >= nbuf { - bufp = 0 - nbuf, err = syscall.ReadDirent(fd, buf) - if err != nil { - return os.NewSyscallError("readdirent", err) - } - if nbuf <= 0 { - return nil - } - } - consumed, name, typ := parseDirEnt(buf[bufp:nbuf]) - bufp += consumed - if name == "" || name == "." || name == ".." { - continue - } - // Fallback for filesystems (like old XFS) that don't - // support Dirent.Type and have DT_UNKNOWN (0) there - // instead. - if typ == unknownFileMode { - fi, err := os.Lstat(dirName + "/" + name) - if err != nil { - // It got deleted in the meantime. - if os.IsNotExist(err) { - continue - } - return err - } - typ = fi.Mode() & os.ModeType - } - if err := fn(dirName, name, typ); err != nil { - return err - } - } -} - -func parseDirEnt(buf []byte) (consumed int, name string, typ os.FileMode) { - // golang.org/issue/15653 - dirent := (*syscall.Dirent)(unsafe.Pointer(&buf[0])) - if v := unsafe.Offsetof(dirent.Reclen) + unsafe.Sizeof(dirent.Reclen); uintptr(len(buf)) < v { - panic(fmt.Sprintf("buf size of %d smaller than dirent header size %d", len(buf), v)) - } - if len(buf) < int(dirent.Reclen) { - panic(fmt.Sprintf("buf size %d < record length %d", len(buf), dirent.Reclen)) - } - consumed = int(dirent.Reclen) - if direntInode(dirent) == 0 { // File absent in directory. - return - } - switch dirent.Type { - case syscall.DT_REG: - typ = 0 - case syscall.DT_DIR: - typ = os.ModeDir - case syscall.DT_LNK: - typ = os.ModeSymlink - case syscall.DT_BLK: - typ = os.ModeDevice - case syscall.DT_FIFO: - typ = os.ModeNamedPipe - case syscall.DT_SOCK: - typ = os.ModeSocket - case syscall.DT_UNKNOWN: - typ = unknownFileMode - default: - // Skip weird things. - // It's probably a DT_WHT (http://lwn.net/Articles/325369/) - // or something. Revisit if/when this package is moved outside - // of goimports. goimports only cares about regular files, - // symlinks, and directories. - return - } - - nameBuf := (*[unsafe.Sizeof(dirent.Name)]byte)(unsafe.Pointer(&dirent.Name[0])) - nameLen := bytes.IndexByte(nameBuf[:], 0) - if nameLen < 0 { - panic("failed to find terminating 0 byte in dirent") - } - - // Special cases for common things: - if nameLen == 1 && nameBuf[0] == '.' { - name = "." - } else if nameLen == 2 && nameBuf[0] == '.' && nameBuf[1] == '.' { - name = ".." - } else { - name = string(nameBuf[:nameLen]) - } - return -} diff --git a/vendor/golang.org/x/tools/imports/fix.go b/vendor/golang.org/x/tools/imports/fix.go deleted file mode 100644 index c74bdd2c02..0000000000 --- a/vendor/golang.org/x/tools/imports/fix.go +++ /dev/null @@ -1,978 +0,0 @@ -// Copyright 2013 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 imports - -import ( - "bufio" - "bytes" - "fmt" - "go/ast" - "go/build" - "go/parser" - "go/token" - "io/ioutil" - "log" - "os" - "path" - "path/filepath" - "sort" - "strings" - "sync" - - "golang.org/x/tools/go/ast/astutil" -) - -// Debug controls verbose logging. -var Debug = false - -var ( - inTests = false // set true by fix_test.go; if false, no need to use testMu - testMu sync.RWMutex // guards globals reset by tests; used only if inTests -) - -// If set, LocalPrefix instructs Process to sort import paths with the given -// prefix into another group after 3rd-party packages. -var LocalPrefix string - -// importToGroup is a list of functions which map from an import path to -// a group number. -var importToGroup = []func(importPath string) (num int, ok bool){ - func(importPath string) (num int, ok bool) { - if LocalPrefix != "" && strings.HasPrefix(importPath, LocalPrefix) { - return 3, true - } - return - }, - func(importPath string) (num int, ok bool) { - if strings.HasPrefix(importPath, "appengine") { - return 2, true - } - return - }, - func(importPath string) (num int, ok bool) { - if strings.Contains(importPath, ".") { - return 1, true - } - return - }, -} - -func importGroup(importPath string) int { - for _, fn := range importToGroup { - if n, ok := fn(importPath); ok { - return n - } - } - return 0 -} - -// packageInfo is a summary of features found in a package. -type packageInfo struct { - Globals map[string]bool // symbol => true -} - -// dirPackageInfo gets information from other files in the package. -func dirPackageInfo(srcDir, filename string) (*packageInfo, error) { - considerTests := strings.HasSuffix(filename, "_test.go") - - // Handle file from stdin - if _, err := os.Stat(filename); err != nil { - if os.IsNotExist(err) { - return &packageInfo{}, nil - } - return nil, err - } - - fileBase := filepath.Base(filename) - packageFileInfos, err := ioutil.ReadDir(srcDir) - if err != nil { - return nil, err - } - - info := &packageInfo{Globals: make(map[string]bool)} - for _, fi := range packageFileInfos { - if fi.Name() == fileBase || !strings.HasSuffix(fi.Name(), ".go") { - continue - } - if !considerTests && strings.HasSuffix(fi.Name(), "_test.go") { - continue - } - - fileSet := token.NewFileSet() - root, err := parser.ParseFile(fileSet, filepath.Join(srcDir, fi.Name()), nil, 0) - if err != nil { - continue - } - - for _, decl := range root.Decls { - genDecl, ok := decl.(*ast.GenDecl) - if !ok { - continue - } - - for _, spec := range genDecl.Specs { - valueSpec, ok := spec.(*ast.ValueSpec) - if !ok { - continue - } - info.Globals[valueSpec.Names[0].Name] = true - } - } - } - return info, nil -} - -func fixImports(fset *token.FileSet, f *ast.File, filename string) (added []string, err error) { - // refs are a set of possible package references currently unsatisfied by imports. - // first key: either base package (e.g. "fmt") or renamed package - // second key: referenced package symbol (e.g. "Println") - refs := make(map[string]map[string]bool) - - // decls are the current package imports. key is base package or renamed package. - decls := make(map[string]*ast.ImportSpec) - - abs, err := filepath.Abs(filename) - if err != nil { - return nil, err - } - srcDir := filepath.Dir(abs) - if Debug { - log.Printf("fixImports(filename=%q), abs=%q, srcDir=%q ...", filename, abs, srcDir) - } - - var packageInfo *packageInfo - var loadedPackageInfo bool - - // collect potential uses of packages. - var visitor visitFn - visitor = visitFn(func(node ast.Node) ast.Visitor { - if node == nil { - return visitor - } - switch v := node.(type) { - case *ast.ImportSpec: - if v.Name != nil { - decls[v.Name.Name] = v - break - } - ipath := strings.Trim(v.Path.Value, `"`) - if ipath == "C" { - break - } - local := importPathToName(ipath, srcDir) - decls[local] = v - case *ast.SelectorExpr: - xident, ok := v.X.(*ast.Ident) - if !ok { - break - } - if xident.Obj != nil { - // if the parser can resolve it, it's not a package ref - break - } - pkgName := xident.Name - if refs[pkgName] == nil { - refs[pkgName] = make(map[string]bool) - } - if !loadedPackageInfo { - loadedPackageInfo = true - packageInfo, _ = dirPackageInfo(srcDir, filename) - } - if decls[pkgName] == nil && (packageInfo == nil || !packageInfo.Globals[pkgName]) { - refs[pkgName][v.Sel.Name] = true - } - } - return visitor - }) - ast.Walk(visitor, f) - - // Nil out any unused ImportSpecs, to be removed in following passes - unusedImport := map[string]string{} - for pkg, is := range decls { - if refs[pkg] == nil && pkg != "_" && pkg != "." { - name := "" - if is.Name != nil { - name = is.Name.Name - } - unusedImport[strings.Trim(is.Path.Value, `"`)] = name - } - } - for ipath, name := range unusedImport { - if ipath == "C" { - // Don't remove cgo stuff. - continue - } - astutil.DeleteNamedImport(fset, f, name, ipath) - } - - for pkgName, symbols := range refs { - if len(symbols) == 0 { - // skip over packages already imported - delete(refs, pkgName) - } - } - - // Search for imports matching potential package references. - searches := 0 - type result struct { - ipath string // import path (if err == nil) - name string // optional name to rename import as - err error - } - results := make(chan result) - for pkgName, symbols := range refs { - go func(pkgName string, symbols map[string]bool) { - ipath, rename, err := findImport(pkgName, symbols, filename) - r := result{ipath: ipath, err: err} - if rename { - r.name = pkgName - } - results <- r - }(pkgName, symbols) - searches++ - } - for i := 0; i < searches; i++ { - result := <-results - if result.err != nil { - return nil, result.err - } - if result.ipath != "" { - if result.name != "" { - astutil.AddNamedImport(fset, f, result.name, result.ipath) - } else { - astutil.AddImport(fset, f, result.ipath) - } - added = append(added, result.ipath) - } - } - - return added, nil -} - -// importPathToName returns the package name for the given import path. -var importPathToName func(importPath, srcDir string) (packageName string) = importPathToNameGoPath - -// importPathToNameBasic assumes the package name is the base of import path. -func importPathToNameBasic(importPath, srcDir string) (packageName string) { - return path.Base(importPath) -} - -// importPathToNameGoPath finds out the actual package name, as declared in its .go files. -// If there's a problem, it falls back to using importPathToNameBasic. -func importPathToNameGoPath(importPath, srcDir string) (packageName string) { - // Fast path for standard library without going to disk. - if pkg, ok := stdImportPackage[importPath]; ok { - return pkg - } - - pkgName, err := importPathToNameGoPathParse(importPath, srcDir) - if Debug { - log.Printf("importPathToNameGoPathParse(%q, srcDir=%q) = %q, %v", importPath, srcDir, pkgName, err) - } - if err == nil { - return pkgName - } - return importPathToNameBasic(importPath, srcDir) -} - -// importPathToNameGoPathParse is a faster version of build.Import if -// the only thing desired is the package name. It uses build.FindOnly -// to find the directory and then only parses one file in the package, -// trusting that the files in the directory are consistent. -func importPathToNameGoPathParse(importPath, srcDir string) (packageName string, err error) { - buildPkg, err := build.Import(importPath, srcDir, build.FindOnly) - if err != nil { - return "", err - } - d, err := os.Open(buildPkg.Dir) - if err != nil { - return "", err - } - names, err := d.Readdirnames(-1) - d.Close() - if err != nil { - return "", err - } - sort.Strings(names) // to have predictable behavior - var lastErr error - var nfile int - for _, name := range names { - if !strings.HasSuffix(name, ".go") { - continue - } - if strings.HasSuffix(name, "_test.go") { - continue - } - nfile++ - fullFile := filepath.Join(buildPkg.Dir, name) - - fset := token.NewFileSet() - f, err := parser.ParseFile(fset, fullFile, nil, parser.PackageClauseOnly) - if err != nil { - lastErr = err - continue - } - pkgName := f.Name.Name - if pkgName == "documentation" { - // Special case from go/build.ImportDir, not - // handled by ctx.MatchFile. - continue - } - if pkgName == "main" { - // Also skip package main, assuming it's a +build ignore generator or example. - // Since you can't import a package main anyway, there's no harm here. - continue - } - return pkgName, nil - } - if lastErr != nil { - return "", lastErr - } - return "", fmt.Errorf("no importable package found in %d Go files", nfile) -} - -var stdImportPackage = map[string]string{} // "net/http" => "http" - -func init() { - // Nothing in the standard library has a package name not - // matching its import base name. - for _, pkg := range stdlib { - if _, ok := stdImportPackage[pkg]; !ok { - stdImportPackage[pkg] = path.Base(pkg) - } - } -} - -// Directory-scanning state. -var ( - // scanGoRootOnce guards calling scanGoRoot (for $GOROOT) - scanGoRootOnce sync.Once - // scanGoPathOnce guards calling scanGoPath (for $GOPATH) - scanGoPathOnce sync.Once - - // populateIgnoreOnce guards calling populateIgnore - populateIgnoreOnce sync.Once - ignoredDirs []os.FileInfo - - dirScanMu sync.RWMutex - dirScan map[string]*pkg // abs dir path => *pkg -) - -type pkg struct { - dir string // absolute file path to pkg directory ("/usr/lib/go/src/net/http") - importPath string // full pkg import path ("net/http", "foo/bar/vendor/a/b") - importPathShort string // vendorless import path ("net/http", "a/b") -} - -// byImportPathShortLength sorts by the short import path length, breaking ties on the -// import string itself. -type byImportPathShortLength []*pkg - -func (s byImportPathShortLength) Len() int { return len(s) } -func (s byImportPathShortLength) Less(i, j int) bool { - vi, vj := s[i].importPathShort, s[j].importPathShort - return len(vi) < len(vj) || (len(vi) == len(vj) && vi < vj) - -} -func (s byImportPathShortLength) Swap(i, j int) { s[i], s[j] = s[j], s[i] } - -// gate is a semaphore for limiting concurrency. -type gate chan struct{} - -func (g gate) enter() { g <- struct{}{} } -func (g gate) leave() { <-g } - -var visitedSymlinks struct { - sync.Mutex - m map[string]struct{} -} - -// guarded by populateIgnoreOnce; populates ignoredDirs. -func populateIgnore() { - for _, srcDir := range build.Default.SrcDirs() { - if srcDir == filepath.Join(build.Default.GOROOT, "src") { - continue - } - populateIgnoredDirs(srcDir) - } -} - -// populateIgnoredDirs reads an optional config file at /.goimportsignore -// of relative directories to ignore when scanning for go files. -// The provided path is one of the $GOPATH entries with "src" appended. -func populateIgnoredDirs(path string) { - file := filepath.Join(path, ".goimportsignore") - slurp, err := ioutil.ReadFile(file) - if Debug { - if err != nil { - log.Print(err) - } else { - log.Printf("Read %s", file) - } - } - if err != nil { - return - } - bs := bufio.NewScanner(bytes.NewReader(slurp)) - for bs.Scan() { - line := strings.TrimSpace(bs.Text()) - if line == "" || strings.HasPrefix(line, "#") { - continue - } - full := filepath.Join(path, line) - if fi, err := os.Stat(full); err == nil { - ignoredDirs = append(ignoredDirs, fi) - if Debug { - log.Printf("Directory added to ignore list: %s", full) - } - } else if Debug { - log.Printf("Error statting entry in .goimportsignore: %v", err) - } - } -} - -func skipDir(fi os.FileInfo) bool { - for _, ignoredDir := range ignoredDirs { - if os.SameFile(fi, ignoredDir) { - return true - } - } - return false -} - -// shouldTraverse reports whether the symlink fi should, found in dir, -// should be followed. It makes sure symlinks were never visited -// before to avoid symlink loops. -func shouldTraverse(dir string, fi os.FileInfo) bool { - path := filepath.Join(dir, fi.Name()) - target, err := filepath.EvalSymlinks(path) - if err != nil { - if !os.IsNotExist(err) { - fmt.Fprintln(os.Stderr, err) - } - return false - } - ts, err := os.Stat(target) - if err != nil { - fmt.Fprintln(os.Stderr, err) - return false - } - if !ts.IsDir() { - return false - } - if skipDir(ts) { - return false - } - - realParent, err := filepath.EvalSymlinks(dir) - if err != nil { - fmt.Fprint(os.Stderr, err) - return false - } - realPath := filepath.Join(realParent, fi.Name()) - visitedSymlinks.Lock() - defer visitedSymlinks.Unlock() - if visitedSymlinks.m == nil { - visitedSymlinks.m = make(map[string]struct{}) - } - if _, ok := visitedSymlinks.m[realPath]; ok { - return false - } - visitedSymlinks.m[realPath] = struct{}{} - return true -} - -var testHookScanDir = func(dir string) {} - -var scanGoRootDone = make(chan struct{}) // closed when scanGoRoot is done - -func scanGoRoot() { - go func() { - scanGoDirs(true) - close(scanGoRootDone) - }() -} - -func scanGoPath() { scanGoDirs(false) } - -func scanGoDirs(goRoot bool) { - if Debug { - which := "$GOROOT" - if !goRoot { - which = "$GOPATH" - } - log.Printf("scanning " + which) - defer log.Printf("scanned " + which) - } - dirScanMu.Lock() - if dirScan == nil { - dirScan = make(map[string]*pkg) - } - dirScanMu.Unlock() - - for _, srcDir := range build.Default.SrcDirs() { - isGoroot := srcDir == filepath.Join(build.Default.GOROOT, "src") - if isGoroot != goRoot { - continue - } - testHookScanDir(srcDir) - walkFn := func(path string, typ os.FileMode) error { - dir := filepath.Dir(path) - if typ.IsRegular() { - if dir == srcDir { - // Doesn't make sense to have regular files - // directly in your $GOPATH/src or $GOROOT/src. - return nil - } - if !strings.HasSuffix(path, ".go") { - return nil - } - dirScanMu.Lock() - if _, dup := dirScan[dir]; !dup { - importpath := filepath.ToSlash(dir[len(srcDir)+len("/"):]) - dirScan[dir] = &pkg{ - importPath: importpath, - importPathShort: vendorlessImportPath(importpath), - dir: dir, - } - } - dirScanMu.Unlock() - return nil - } - if typ == os.ModeDir { - base := filepath.Base(path) - if base == "" || base[0] == '.' || base[0] == '_' || - base == "testdata" || base == "node_modules" { - return filepath.SkipDir - } - fi, err := os.Lstat(path) - if err == nil && skipDir(fi) { - if Debug { - log.Printf("skipping directory %q under %s", fi.Name(), dir) - } - return filepath.SkipDir - } - return nil - } - if typ == os.ModeSymlink { - base := filepath.Base(path) - if strings.HasPrefix(base, ".#") { - // Emacs noise. - return nil - } - fi, err := os.Lstat(path) - if err != nil { - // Just ignore it. - return nil - } - if shouldTraverse(dir, fi) { - return traverseLink - } - } - return nil - } - if err := fastWalk(srcDir, walkFn); err != nil { - log.Printf("goimports: scanning directory %v: %v", srcDir, err) - } - } -} - -// vendorlessImportPath returns the devendorized version of the provided import path. -// e.g. "foo/bar/vendor/a/b" => "a/b" -func vendorlessImportPath(ipath string) string { - // Devendorize for use in import statement. - if i := strings.LastIndex(ipath, "/vendor/"); i >= 0 { - return ipath[i+len("/vendor/"):] - } - if strings.HasPrefix(ipath, "vendor/") { - return ipath[len("vendor/"):] - } - return ipath -} - -// loadExports returns the set of exported symbols in the package at dir. -// It returns nil on error or if the package name in dir does not match expectPackage. -var loadExports func(expectPackage, dir string) map[string]bool = loadExportsGoPath - -func loadExportsGoPath(expectPackage, dir string) map[string]bool { - if Debug { - log.Printf("loading exports in dir %s (seeking package %s)", dir, expectPackage) - } - exports := make(map[string]bool) - - ctx := build.Default - - // ReadDir is like ioutil.ReadDir, but only returns *.go files - // and filters out _test.go files since they're not relevant - // and only slow things down. - ctx.ReadDir = func(dir string) (notTests []os.FileInfo, err error) { - all, err := ioutil.ReadDir(dir) - if err != nil { - return nil, err - } - notTests = all[:0] - for _, fi := range all { - name := fi.Name() - if strings.HasSuffix(name, ".go") && !strings.HasSuffix(name, "_test.go") { - notTests = append(notTests, fi) - } - } - return notTests, nil - } - - files, err := ctx.ReadDir(dir) - if err != nil { - log.Print(err) - return nil - } - - fset := token.NewFileSet() - - for _, fi := range files { - match, err := ctx.MatchFile(dir, fi.Name()) - if err != nil || !match { - continue - } - fullFile := filepath.Join(dir, fi.Name()) - f, err := parser.ParseFile(fset, fullFile, nil, 0) - if err != nil { - if Debug { - log.Printf("Parsing %s: %v", fullFile, err) - } - return nil - } - pkgName := f.Name.Name - if pkgName == "documentation" { - // Special case from go/build.ImportDir, not - // handled by ctx.MatchFile. - continue - } - if pkgName != expectPackage { - if Debug { - log.Printf("scan of dir %v is not expected package %v (actually %v)", dir, expectPackage, pkgName) - } - return nil - } - for name := range f.Scope.Objects { - if ast.IsExported(name) { - exports[name] = true - } - } - } - - if Debug { - exportList := make([]string, 0, len(exports)) - for k := range exports { - exportList = append(exportList, k) - } - sort.Strings(exportList) - log.Printf("loaded exports in dir %v (package %v): %v", dir, expectPackage, strings.Join(exportList, ", ")) - } - return exports -} - -// findImport searches for a package with the given symbols. -// If no package is found, findImport returns ("", false, nil) -// -// This is declared as a variable rather than a function so goimports -// can be easily extended by adding a file with an init function. -// -// The rename value tells goimports whether to use the package name as -// a local qualifier in an import. For example, if findImports("pkg", -// "X") returns ("foo/bar", rename=true), then goimports adds the -// import line: -// import pkg "foo/bar" -// to satisfy uses of pkg.X in the file. -var findImport func(pkgName string, symbols map[string]bool, filename string) (foundPkg string, rename bool, err error) = findImportGoPath - -// findImportGoPath is the normal implementation of findImport. -// (Some companies have their own internally.) -func findImportGoPath(pkgName string, symbols map[string]bool, filename string) (foundPkg string, rename bool, err error) { - if inTests { - testMu.RLock() - defer testMu.RUnlock() - } - - // Fast path for the standard library. - // In the common case we hopefully never have to scan the GOPATH, which can - // be slow with moving disks. - if pkg, rename, ok := findImportStdlib(pkgName, symbols); ok { - return pkg, rename, nil - } - if pkgName == "rand" && symbols["Read"] { - // Special-case rand.Read. - // - // If findImportStdlib didn't find it above, don't go - // searching for it, lest it find and pick math/rand - // in GOROOT (new as of Go 1.6) - // - // crypto/rand is the safer choice. - return "", false, nil - } - - // TODO(sameer): look at the import lines for other Go files in the - // local directory, since the user is likely to import the same packages - // in the current Go file. Return rename=true when the other Go files - // use a renamed package that's also used in the current file. - - // Read all the $GOPATH/src/.goimportsignore files before scanning directories. - populateIgnoreOnce.Do(populateIgnore) - - // Start scanning the $GOROOT asynchronously, then run the - // GOPATH scan synchronously if needed, and then wait for the - // $GOROOT to finish. - // - // TODO(bradfitz): run each $GOPATH entry async. But nobody - // really has more than one anyway, so low priority. - scanGoRootOnce.Do(scanGoRoot) // async - if !fileInDir(filename, build.Default.GOROOT) { - scanGoPathOnce.Do(scanGoPath) // blocking - } - <-scanGoRootDone - - // Find candidate packages, looking only at their directory names first. - var candidates []*pkg - for _, pkg := range dirScan { - if pkgIsCandidate(filename, pkgName, pkg) { - candidates = append(candidates, pkg) - } - } - - // Sort the candidates by their import package length, - // assuming that shorter package names are better than long - // ones. Note that this sorts by the de-vendored name, so - // there's no "penalty" for vendoring. - sort.Sort(byImportPathShortLength(candidates)) - if Debug { - for i, pkg := range candidates { - log.Printf("%s candidate %d/%d: %v", pkgName, i+1, len(candidates), pkg.importPathShort) - } - } - - // Collect exports for packages with matching names. - - done := make(chan struct{}) // closed when we find the answer - defer close(done) - - rescv := make([]chan *pkg, len(candidates)) - for i := range candidates { - rescv[i] = make(chan *pkg) - } - const maxConcurrentPackageImport = 4 - loadExportsSem := make(chan struct{}, maxConcurrentPackageImport) - - go func() { - for i, pkg := range candidates { - select { - case loadExportsSem <- struct{}{}: - select { - case <-done: - default: - } - case <-done: - return - } - pkg := pkg - resc := rescv[i] - go func() { - if inTests { - testMu.RLock() - defer testMu.RUnlock() - } - defer func() { <-loadExportsSem }() - exports := loadExports(pkgName, pkg.dir) - - // If it doesn't have the right - // symbols, send nil to mean no match. - for symbol := range symbols { - if !exports[symbol] { - pkg = nil - break - } - } - select { - case resc <- pkg: - case <-done: - } - }() - } - }() - for _, resc := range rescv { - pkg := <-resc - if pkg == nil { - continue - } - // If the package name in the source doesn't match the import path's base, - // return true so the rewriter adds a name (import foo "github.com/bar/go-foo") - needsRename := path.Base(pkg.importPath) != pkgName - return pkg.importPathShort, needsRename, nil - } - return "", false, nil -} - -// pkgIsCandidate reports whether pkg is a candidate for satisfying the -// finding which package pkgIdent in the file named by filename is trying -// to refer to. -// -// This check is purely lexical and is meant to be as fast as possible -// because it's run over all $GOPATH directories to filter out poor -// candidates in order to limit the CPU and I/O later parsing the -// exports in candidate packages. -// -// filename is the file being formatted. -// pkgIdent is the package being searched for, like "client" (if -// searching for "client.New") -func pkgIsCandidate(filename, pkgIdent string, pkg *pkg) bool { - // Check "internal" and "vendor" visibility: - if !canUse(filename, pkg.dir) { - return false - } - - // Speed optimization to minimize disk I/O: - // the last two components on disk must contain the - // package name somewhere. - // - // This permits mismatch naming like directory - // "go-foo" being package "foo", or "pkg.v3" being "pkg", - // or directory "google.golang.org/api/cloudbilling/v1" - // being package "cloudbilling", but doesn't - // permit a directory "foo" to be package - // "bar", which is strongly discouraged - // anyway. There's no reason goimports needs - // to be slow just to accomodate that. - lastTwo := lastTwoComponents(pkg.importPathShort) - if strings.Contains(lastTwo, pkgIdent) { - return true - } - if hasHyphenOrUpperASCII(lastTwo) && !hasHyphenOrUpperASCII(pkgIdent) { - lastTwo = lowerASCIIAndRemoveHyphen(lastTwo) - if strings.Contains(lastTwo, pkgIdent) { - return true - } - } - - return false -} - -func hasHyphenOrUpperASCII(s string) bool { - for i := 0; i < len(s); i++ { - b := s[i] - if b == '-' || ('A' <= b && b <= 'Z') { - return true - } - } - return false -} - -func lowerASCIIAndRemoveHyphen(s string) (ret string) { - buf := make([]byte, 0, len(s)) - for i := 0; i < len(s); i++ { - b := s[i] - switch { - case b == '-': - continue - case 'A' <= b && b <= 'Z': - buf = append(buf, b+('a'-'A')) - default: - buf = append(buf, b) - } - } - return string(buf) -} - -// canUse reports whether the package in dir is usable from filename, -// respecting the Go "internal" and "vendor" visibility rules. -func canUse(filename, dir string) bool { - // Fast path check, before any allocations. If it doesn't contain vendor - // or internal, it's not tricky: - // Note that this can false-negative on directories like "notinternal", - // but we check it correctly below. This is just a fast path. - if !strings.Contains(dir, "vendor") && !strings.Contains(dir, "internal") { - return true - } - - dirSlash := filepath.ToSlash(dir) - if !strings.Contains(dirSlash, "/vendor/") && !strings.Contains(dirSlash, "/internal/") && !strings.HasSuffix(dirSlash, "/internal") { - return true - } - // Vendor or internal directory only visible from children of parent. - // That means the path from the current directory to the target directory - // can contain ../vendor or ../internal but not ../foo/vendor or ../foo/internal - // or bar/vendor or bar/internal. - // After stripping all the leading ../, the only okay place to see vendor or internal - // is at the very beginning of the path. - absfile, err := filepath.Abs(filename) - if err != nil { - return false - } - absdir, err := filepath.Abs(dir) - if err != nil { - return false - } - rel, err := filepath.Rel(absfile, absdir) - if err != nil { - return false - } - relSlash := filepath.ToSlash(rel) - if i := strings.LastIndex(relSlash, "../"); i >= 0 { - relSlash = relSlash[i+len("../"):] - } - return !strings.Contains(relSlash, "/vendor/") && !strings.Contains(relSlash, "/internal/") && !strings.HasSuffix(relSlash, "/internal") -} - -// lastTwoComponents returns at most the last two path components -// of v, using either / or \ as the path separator. -func lastTwoComponents(v string) string { - nslash := 0 - for i := len(v) - 1; i >= 0; i-- { - if v[i] == '/' || v[i] == '\\' { - nslash++ - if nslash == 2 { - return v[i:] - } - } - } - return v -} - -type visitFn func(node ast.Node) ast.Visitor - -func (fn visitFn) Visit(node ast.Node) ast.Visitor { - return fn(node) -} - -func findImportStdlib(shortPkg string, symbols map[string]bool) (importPath string, rename, ok bool) { - for symbol := range symbols { - key := shortPkg + "." + symbol - path := stdlib[key] - if path == "" { - if key == "rand.Read" { - continue - } - return "", false, false - } - if importPath != "" && importPath != path { - // Ambiguous. Symbols pointed to different things. - return "", false, false - } - importPath = path - } - if importPath == "" && shortPkg == "rand" && symbols["Read"] { - return "crypto/rand", false, true - } - return importPath, false, importPath != "" -} - -// fileInDir reports whether the provided file path looks like -// it's in dir. (without hitting the filesystem) -func fileInDir(file, dir string) bool { - rest := strings.TrimPrefix(file, dir) - if len(rest) == len(file) { - // dir is not a prefix of file. - return false - } - // Check for boundary: either nothing (file == dir), or a slash. - return len(rest) == 0 || rest[0] == '/' || rest[0] == '\\' -} diff --git a/vendor/golang.org/x/tools/imports/imports.go b/vendor/golang.org/x/tools/imports/imports.go deleted file mode 100644 index 67573f497e..0000000000 --- a/vendor/golang.org/x/tools/imports/imports.go +++ /dev/null @@ -1,289 +0,0 @@ -// Copyright 2013 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. - -//go:generate go run mkstdlib.go - -// Package imports implements a Go pretty-printer (like package "go/format") -// that also adds or removes import statements as necessary. -package imports // import "golang.org/x/tools/imports" - -import ( - "bufio" - "bytes" - "fmt" - "go/ast" - "go/format" - "go/parser" - "go/printer" - "go/token" - "io" - "regexp" - "strconv" - "strings" - - "golang.org/x/tools/go/ast/astutil" -) - -// Options specifies options for processing files. -type Options struct { - Fragment bool // Accept fragment of a source file (no package statement) - AllErrors bool // Report all errors (not just the first 10 on different lines) - - Comments bool // Print comments (true if nil *Options provided) - TabIndent bool // Use tabs for indent (true if nil *Options provided) - TabWidth int // Tab width (8 if nil *Options provided) - - FormatOnly bool // Disable the insertion and deletion of imports -} - -// Process formats and adjusts imports for the provided file. -// If opt is nil the defaults are used. -// -// Note that filename's directory influences which imports can be chosen, -// so it is important that filename be accurate. -// To process data ``as if'' it were in filename, pass the data as a non-nil src. -func Process(filename string, src []byte, opt *Options) ([]byte, error) { - if opt == nil { - opt = &Options{Comments: true, TabIndent: true, TabWidth: 8} - } - - fileSet := token.NewFileSet() - file, adjust, err := parse(fileSet, filename, src, opt) - if err != nil { - return nil, err - } - - if !opt.FormatOnly { - _, err = fixImports(fileSet, file, filename) - if err != nil { - return nil, err - } - } - - sortImports(fileSet, file) - imps := astutil.Imports(fileSet, file) - - var spacesBefore []string // import paths we need spaces before - for _, impSection := range imps { - // Within each block of contiguous imports, see if any - // import lines are in different group numbers. If so, - // we'll need to put a space between them so it's - // compatible with gofmt. - lastGroup := -1 - for _, importSpec := range impSection { - importPath, _ := strconv.Unquote(importSpec.Path.Value) - groupNum := importGroup(importPath) - if groupNum != lastGroup && lastGroup != -1 { - spacesBefore = append(spacesBefore, importPath) - } - lastGroup = groupNum - } - - } - - printerMode := printer.UseSpaces - if opt.TabIndent { - printerMode |= printer.TabIndent - } - printConfig := &printer.Config{Mode: printerMode, Tabwidth: opt.TabWidth} - - var buf bytes.Buffer - err = printConfig.Fprint(&buf, fileSet, file) - if err != nil { - return nil, err - } - out := buf.Bytes() - if adjust != nil { - out = adjust(src, out) - } - if len(spacesBefore) > 0 { - out = addImportSpaces(bytes.NewReader(out), spacesBefore) - } - - out, err = format.Source(out) - if err != nil { - return nil, err - } - return out, nil -} - -// parse parses src, which was read from filename, -// as a Go source file or statement list. -func parse(fset *token.FileSet, filename string, src []byte, opt *Options) (*ast.File, func(orig, src []byte) []byte, error) { - parserMode := parser.Mode(0) - if opt.Comments { - parserMode |= parser.ParseComments - } - if opt.AllErrors { - parserMode |= parser.AllErrors - } - - // Try as whole source file. - file, err := parser.ParseFile(fset, filename, src, parserMode) - if err == nil { - return file, nil, nil - } - // If the error is that the source file didn't begin with a - // package line and we accept fragmented input, fall through to - // try as a source fragment. Stop and return on any other error. - if !opt.Fragment || !strings.Contains(err.Error(), "expected 'package'") { - return nil, nil, err - } - - // If this is a declaration list, make it a source file - // by inserting a package clause. - // Insert using a ;, not a newline, so that the line numbers - // in psrc match the ones in src. - psrc := append([]byte("package main;"), src...) - file, err = parser.ParseFile(fset, filename, psrc, parserMode) - if err == nil { - // If a main function exists, we will assume this is a main - // package and leave the file. - if containsMainFunc(file) { - return file, nil, nil - } - - adjust := func(orig, src []byte) []byte { - // Remove the package clause. - // Gofmt has turned the ; into a \n. - src = src[len("package main\n"):] - return matchSpace(orig, src) - } - return file, adjust, nil - } - // If the error is that the source file didn't begin with a - // declaration, fall through to try as a statement list. - // Stop and return on any other error. - if !strings.Contains(err.Error(), "expected declaration") { - return nil, nil, err - } - - // If this is a statement list, make it a source file - // by inserting a package clause and turning the list - // into a function body. This handles expressions too. - // Insert using a ;, not a newline, so that the line numbers - // in fsrc match the ones in src. - fsrc := append(append([]byte("package p; func _() {"), src...), '}') - file, err = parser.ParseFile(fset, filename, fsrc, parserMode) - if err == nil { - adjust := func(orig, src []byte) []byte { - // Remove the wrapping. - // Gofmt has turned the ; into a \n\n. - src = src[len("package p\n\nfunc _() {"):] - src = src[:len(src)-len("}\n")] - // Gofmt has also indented the function body one level. - // Remove that indent. - src = bytes.Replace(src, []byte("\n\t"), []byte("\n"), -1) - return matchSpace(orig, src) - } - return file, adjust, nil - } - - // Failed, and out of options. - return nil, nil, err -} - -// containsMainFunc checks if a file contains a function declaration with the -// function signature 'func main()' -func containsMainFunc(file *ast.File) bool { - for _, decl := range file.Decls { - if f, ok := decl.(*ast.FuncDecl); ok { - if f.Name.Name != "main" { - continue - } - - if len(f.Type.Params.List) != 0 { - continue - } - - if f.Type.Results != nil && len(f.Type.Results.List) != 0 { - continue - } - - return true - } - } - - return false -} - -func cutSpace(b []byte) (before, middle, after []byte) { - i := 0 - for i < len(b) && (b[i] == ' ' || b[i] == '\t' || b[i] == '\n') { - i++ - } - j := len(b) - for j > 0 && (b[j-1] == ' ' || b[j-1] == '\t' || b[j-1] == '\n') { - j-- - } - if i <= j { - return b[:i], b[i:j], b[j:] - } - return nil, nil, b[j:] -} - -// matchSpace reformats src to use the same space context as orig. -// 1) If orig begins with blank lines, matchSpace inserts them at the beginning of src. -// 2) matchSpace copies the indentation of the first non-blank line in orig -// to every non-blank line in src. -// 3) matchSpace copies the trailing space from orig and uses it in place -// of src's trailing space. -func matchSpace(orig []byte, src []byte) []byte { - before, _, after := cutSpace(orig) - i := bytes.LastIndex(before, []byte{'\n'}) - before, indent := before[:i+1], before[i+1:] - - _, src, _ = cutSpace(src) - - var b bytes.Buffer - b.Write(before) - for len(src) > 0 { - line := src - if i := bytes.IndexByte(line, '\n'); i >= 0 { - line, src = line[:i+1], line[i+1:] - } else { - src = nil - } - if len(line) > 0 && line[0] != '\n' { // not blank - b.Write(indent) - } - b.Write(line) - } - b.Write(after) - return b.Bytes() -} - -var impLine = regexp.MustCompile(`^\s+(?:[\w\.]+\s+)?"(.+)"`) - -func addImportSpaces(r io.Reader, breaks []string) []byte { - var out bytes.Buffer - sc := bufio.NewScanner(r) - inImports := false - done := false - for sc.Scan() { - s := sc.Text() - - if !inImports && !done && strings.HasPrefix(s, "import") { - inImports = true - } - if inImports && (strings.HasPrefix(s, "var") || - strings.HasPrefix(s, "func") || - strings.HasPrefix(s, "const") || - strings.HasPrefix(s, "type")) { - done = true - inImports = false - } - if inImports && len(breaks) > 0 { - if m := impLine.FindStringSubmatch(s); m != nil { - if m[1] == breaks[0] { - out.WriteByte('\n') - breaks = breaks[1:] - } - } - } - - fmt.Fprintln(&out, s) - } - return out.Bytes() -} diff --git a/vendor/golang.org/x/tools/imports/mkindex.go b/vendor/golang.org/x/tools/imports/mkindex.go deleted file mode 100644 index 755e2394f2..0000000000 --- a/vendor/golang.org/x/tools/imports/mkindex.go +++ /dev/null @@ -1,173 +0,0 @@ -// +build ignore - -// Copyright 2013 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. - -// Command mkindex creates the file "pkgindex.go" containing an index of the Go -// standard library. The file is intended to be built as part of the imports -// package, so that the package may be used in environments where a GOROOT is -// not available (such as App Engine). -package main - -import ( - "bytes" - "fmt" - "go/ast" - "go/build" - "go/format" - "go/parser" - "go/token" - "io/ioutil" - "log" - "os" - "path" - "path/filepath" - "strings" -) - -var ( - pkgIndex = make(map[string][]pkg) - exports = make(map[string]map[string]bool) -) - -func main() { - // Don't use GOPATH. - ctx := build.Default - ctx.GOPATH = "" - - // Populate pkgIndex global from GOROOT. - for _, path := range ctx.SrcDirs() { - f, err := os.Open(path) - if err != nil { - log.Print(err) - continue - } - children, err := f.Readdir(-1) - f.Close() - if err != nil { - log.Print(err) - continue - } - for _, child := range children { - if child.IsDir() { - loadPkg(path, child.Name()) - } - } - } - // Populate exports global. - for _, ps := range pkgIndex { - for _, p := range ps { - e := loadExports(p.dir) - if e != nil { - exports[p.dir] = e - } - } - } - - // Construct source file. - var buf bytes.Buffer - fmt.Fprint(&buf, pkgIndexHead) - fmt.Fprintf(&buf, "var pkgIndexMaster = %#v\n", pkgIndex) - fmt.Fprintf(&buf, "var exportsMaster = %#v\n", exports) - src := buf.Bytes() - - // Replace main.pkg type name with pkg. - src = bytes.Replace(src, []byte("main.pkg"), []byte("pkg"), -1) - // Replace actual GOROOT with "/go". - src = bytes.Replace(src, []byte(ctx.GOROOT), []byte("/go"), -1) - // Add some line wrapping. - src = bytes.Replace(src, []byte("}, "), []byte("},\n"), -1) - src = bytes.Replace(src, []byte("true, "), []byte("true,\n"), -1) - - var err error - src, err = format.Source(src) - if err != nil { - log.Fatal(err) - } - - // Write out source file. - err = ioutil.WriteFile("pkgindex.go", src, 0644) - if err != nil { - log.Fatal(err) - } -} - -const pkgIndexHead = `package imports - -func init() { - pkgIndexOnce.Do(func() { - pkgIndex.m = pkgIndexMaster - }) - loadExports = func(dir string) map[string]bool { - return exportsMaster[dir] - } -} -` - -type pkg struct { - importpath string // full pkg import path, e.g. "net/http" - dir string // absolute file path to pkg directory e.g. "/usr/lib/go/src/fmt" -} - -var fset = token.NewFileSet() - -func loadPkg(root, importpath string) { - shortName := path.Base(importpath) - if shortName == "testdata" { - return - } - - dir := filepath.Join(root, importpath) - pkgIndex[shortName] = append(pkgIndex[shortName], pkg{ - importpath: importpath, - dir: dir, - }) - - pkgDir, err := os.Open(dir) - if err != nil { - return - } - children, err := pkgDir.Readdir(-1) - pkgDir.Close() - if err != nil { - return - } - for _, child := range children { - name := child.Name() - if name == "" { - continue - } - if c := name[0]; c == '.' || ('0' <= c && c <= '9') { - continue - } - if child.IsDir() { - loadPkg(root, filepath.Join(importpath, name)) - } - } -} - -func loadExports(dir string) map[string]bool { - exports := make(map[string]bool) - buildPkg, err := build.ImportDir(dir, 0) - if err != nil { - if strings.Contains(err.Error(), "no buildable Go source files in") { - return nil - } - log.Printf("could not import %q: %v", dir, err) - return nil - } - for _, file := range buildPkg.GoFiles { - f, err := parser.ParseFile(fset, filepath.Join(dir, file), nil, 0) - if err != nil { - log.Printf("could not parse %q: %v", file, err) - continue - } - for name := range f.Scope.Objects { - if ast.IsExported(name) { - exports[name] = true - } - } - } - return exports -} diff --git a/vendor/golang.org/x/tools/imports/mkstdlib.go b/vendor/golang.org/x/tools/imports/mkstdlib.go deleted file mode 100644 index 1e559e9f50..0000000000 --- a/vendor/golang.org/x/tools/imports/mkstdlib.go +++ /dev/null @@ -1,103 +0,0 @@ -// +build ignore - -// mkstdlib generates the zstdlib.go file, containing the Go standard -// library API symbols. It's baked into the binary to avoid scanning -// GOPATH in the common case. -package main - -import ( - "bufio" - "bytes" - "fmt" - "go/format" - "io" - "io/ioutil" - "log" - "os" - "path" - "path/filepath" - "regexp" - "sort" - "strings" -) - -func mustOpen(name string) io.Reader { - f, err := os.Open(name) - if err != nil { - log.Fatal(err) - } - return f -} - -func api(base string) string { - return filepath.Join(os.Getenv("GOROOT"), "api", base) -} - -var sym = regexp.MustCompile(`^pkg (\S+).*?, (?:var|func|type|const) ([A-Z]\w*)`) - -func main() { - var buf bytes.Buffer - outf := func(format string, args ...interface{}) { - fmt.Fprintf(&buf, format, args...) - } - outf("// AUTO-GENERATED BY mkstdlib.go\n\n") - outf("package imports\n") - outf("var stdlib = map[string]string{\n") - f := io.MultiReader( - mustOpen(api("go1.txt")), - mustOpen(api("go1.1.txt")), - mustOpen(api("go1.2.txt")), - mustOpen(api("go1.3.txt")), - mustOpen(api("go1.4.txt")), - mustOpen(api("go1.5.txt")), - mustOpen(api("go1.6.txt")), - mustOpen(api("go1.7.txt")), - ) - sc := bufio.NewScanner(f) - fullImport := map[string]string{} // "zip.NewReader" => "archive/zip" - ambiguous := map[string]bool{} - var keys []string - for sc.Scan() { - l := sc.Text() - has := func(v string) bool { return strings.Contains(l, v) } - if has("struct, ") || has("interface, ") || has(", method (") { - continue - } - if m := sym.FindStringSubmatch(l); m != nil { - full := m[1] - key := path.Base(full) + "." + m[2] - if exist, ok := fullImport[key]; ok { - if exist != full { - ambiguous[key] = true - } - } else { - fullImport[key] = full - keys = append(keys, key) - } - } - } - if err := sc.Err(); err != nil { - log.Fatal(err) - } - sort.Strings(keys) - for _, key := range keys { - if ambiguous[key] { - outf("\t// %q is ambiguous\n", key) - } else { - outf("\t%q: %q,\n", key, fullImport[key]) - } - } - outf("\n") - for _, sym := range [...]string{"Alignof", "ArbitraryType", "Offsetof", "Pointer", "Sizeof"} { - outf("\t%q: %q,\n", "unsafe."+sym, "unsafe") - } - outf("}\n") - fmtbuf, err := format.Source(buf.Bytes()) - if err != nil { - log.Fatal(err) - } - err = ioutil.WriteFile("zstdlib.go", fmtbuf, 0666) - if err != nil { - log.Fatal(err) - } -} diff --git a/vendor/golang.org/x/tools/imports/sortimports.go b/vendor/golang.org/x/tools/imports/sortimports.go deleted file mode 100644 index 653afc5177..0000000000 --- a/vendor/golang.org/x/tools/imports/sortimports.go +++ /dev/null @@ -1,212 +0,0 @@ -// Copyright 2013 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. - -// Hacked up copy of go/ast/import.go - -package imports - -import ( - "go/ast" - "go/token" - "sort" - "strconv" -) - -// sortImports sorts runs of consecutive import lines in import blocks in f. -// It also removes duplicate imports when it is possible to do so without data loss. -func sortImports(fset *token.FileSet, f *ast.File) { - for i, d := range f.Decls { - d, ok := d.(*ast.GenDecl) - if !ok || d.Tok != token.IMPORT { - // Not an import declaration, so we're done. - // Imports are always first. - break - } - - if len(d.Specs) == 0 { - // Empty import block, remove it. - f.Decls = append(f.Decls[:i], f.Decls[i+1:]...) - } - - if !d.Lparen.IsValid() { - // Not a block: sorted by default. - continue - } - - // Identify and sort runs of specs on successive lines. - i := 0 - specs := d.Specs[:0] - for j, s := range d.Specs { - if j > i && fset.Position(s.Pos()).Line > 1+fset.Position(d.Specs[j-1].End()).Line { - // j begins a new run. End this one. - specs = append(specs, sortSpecs(fset, f, d.Specs[i:j])...) - i = j - } - } - specs = append(specs, sortSpecs(fset, f, d.Specs[i:])...) - d.Specs = specs - - // Deduping can leave a blank line before the rparen; clean that up. - if len(d.Specs) > 0 { - lastSpec := d.Specs[len(d.Specs)-1] - lastLine := fset.Position(lastSpec.Pos()).Line - if rParenLine := fset.Position(d.Rparen).Line; rParenLine > lastLine+1 { - fset.File(d.Rparen).MergeLine(rParenLine - 1) - } - } - } -} - -func importPath(s ast.Spec) string { - t, err := strconv.Unquote(s.(*ast.ImportSpec).Path.Value) - if err == nil { - return t - } - return "" -} - -func importName(s ast.Spec) string { - n := s.(*ast.ImportSpec).Name - if n == nil { - return "" - } - return n.Name -} - -func importComment(s ast.Spec) string { - c := s.(*ast.ImportSpec).Comment - if c == nil { - return "" - } - return c.Text() -} - -// collapse indicates whether prev may be removed, leaving only next. -func collapse(prev, next ast.Spec) bool { - if importPath(next) != importPath(prev) || importName(next) != importName(prev) { - return false - } - return prev.(*ast.ImportSpec).Comment == nil -} - -type posSpan struct { - Start token.Pos - End token.Pos -} - -func sortSpecs(fset *token.FileSet, f *ast.File, specs []ast.Spec) []ast.Spec { - // Can't short-circuit here even if specs are already sorted, - // since they might yet need deduplication. - // A lone import, however, may be safely ignored. - if len(specs) <= 1 { - return specs - } - - // Record positions for specs. - pos := make([]posSpan, len(specs)) - for i, s := range specs { - pos[i] = posSpan{s.Pos(), s.End()} - } - - // Identify comments in this range. - // Any comment from pos[0].Start to the final line counts. - lastLine := fset.Position(pos[len(pos)-1].End).Line - cstart := len(f.Comments) - cend := len(f.Comments) - for i, g := range f.Comments { - if g.Pos() < pos[0].Start { - continue - } - if i < cstart { - cstart = i - } - if fset.Position(g.End()).Line > lastLine { - cend = i - break - } - } - comments := f.Comments[cstart:cend] - - // Assign each comment to the import spec preceding it. - importComment := map[*ast.ImportSpec][]*ast.CommentGroup{} - specIndex := 0 - for _, g := range comments { - for specIndex+1 < len(specs) && pos[specIndex+1].Start <= g.Pos() { - specIndex++ - } - s := specs[specIndex].(*ast.ImportSpec) - importComment[s] = append(importComment[s], g) - } - - // Sort the import specs by import path. - // Remove duplicates, when possible without data loss. - // Reassign the import paths to have the same position sequence. - // Reassign each comment to abut the end of its spec. - // Sort the comments by new position. - sort.Sort(byImportSpec(specs)) - - // Dedup. Thanks to our sorting, we can just consider - // adjacent pairs of imports. - deduped := specs[:0] - for i, s := range specs { - if i == len(specs)-1 || !collapse(s, specs[i+1]) { - deduped = append(deduped, s) - } else { - p := s.Pos() - fset.File(p).MergeLine(fset.Position(p).Line) - } - } - specs = deduped - - // Fix up comment positions - for i, s := range specs { - s := s.(*ast.ImportSpec) - if s.Name != nil { - s.Name.NamePos = pos[i].Start - } - s.Path.ValuePos = pos[i].Start - s.EndPos = pos[i].End - for _, g := range importComment[s] { - for _, c := range g.List { - c.Slash = pos[i].End - } - } - } - - sort.Sort(byCommentPos(comments)) - - return specs -} - -type byImportSpec []ast.Spec // slice of *ast.ImportSpec - -func (x byImportSpec) Len() int { return len(x) } -func (x byImportSpec) Swap(i, j int) { x[i], x[j] = x[j], x[i] } -func (x byImportSpec) Less(i, j int) bool { - ipath := importPath(x[i]) - jpath := importPath(x[j]) - - igroup := importGroup(ipath) - jgroup := importGroup(jpath) - if igroup != jgroup { - return igroup < jgroup - } - - if ipath != jpath { - return ipath < jpath - } - iname := importName(x[i]) - jname := importName(x[j]) - - if iname != jname { - return iname < jname - } - return importComment(x[i]) < importComment(x[j]) -} - -type byCommentPos []*ast.CommentGroup - -func (x byCommentPos) Len() int { return len(x) } -func (x byCommentPos) Swap(i, j int) { x[i], x[j] = x[j], x[i] } -func (x byCommentPos) Less(i, j int) bool { return x[i].Pos() < x[j].Pos() } diff --git a/vendor/golang.org/x/tools/imports/zstdlib.go b/vendor/golang.org/x/tools/imports/zstdlib.go deleted file mode 100644 index 28835da031..0000000000 --- a/vendor/golang.org/x/tools/imports/zstdlib.go +++ /dev/null @@ -1,9289 +0,0 @@ -// AUTO-GENERATED BY mkstdlib.go - -package imports - -var stdlib = map[string]string{ - "adler32.Checksum": "hash/adler32", - "adler32.New": "hash/adler32", - "adler32.Size": "hash/adler32", - "aes.BlockSize": "crypto/aes", - "aes.KeySizeError": "crypto/aes", - "aes.NewCipher": "crypto/aes", - "ascii85.CorruptInputError": "encoding/ascii85", - "ascii85.Decode": "encoding/ascii85", - "ascii85.Encode": "encoding/ascii85", - "ascii85.MaxEncodedLen": "encoding/ascii85", - "ascii85.NewDecoder": "encoding/ascii85", - "ascii85.NewEncoder": "encoding/ascii85", - "asn1.BitString": "encoding/asn1", - "asn1.ClassApplication": "encoding/asn1", - "asn1.ClassContextSpecific": "encoding/asn1", - "asn1.ClassPrivate": "encoding/asn1", - "asn1.ClassUniversal": "encoding/asn1", - "asn1.Enumerated": "encoding/asn1", - "asn1.Flag": "encoding/asn1", - "asn1.Marshal": "encoding/asn1", - "asn1.ObjectIdentifier": "encoding/asn1", - "asn1.RawContent": "encoding/asn1", - "asn1.RawValue": "encoding/asn1", - "asn1.StructuralError": "encoding/asn1", - "asn1.SyntaxError": "encoding/asn1", - "asn1.TagBitString": "encoding/asn1", - "asn1.TagBoolean": "encoding/asn1", - "asn1.TagEnum": "encoding/asn1", - "asn1.TagGeneralString": "encoding/asn1", - "asn1.TagGeneralizedTime": "encoding/asn1", - "asn1.TagIA5String": "encoding/asn1", - "asn1.TagInteger": "encoding/asn1", - "asn1.TagOID": "encoding/asn1", - "asn1.TagOctetString": "encoding/asn1", - "asn1.TagPrintableString": "encoding/asn1", - "asn1.TagSequence": "encoding/asn1", - "asn1.TagSet": "encoding/asn1", - "asn1.TagT61String": "encoding/asn1", - "asn1.TagUTCTime": "encoding/asn1", - "asn1.TagUTF8String": "encoding/asn1", - "asn1.Unmarshal": "encoding/asn1", - "asn1.UnmarshalWithParams": "encoding/asn1", - "ast.ArrayType": "go/ast", - "ast.AssignStmt": "go/ast", - "ast.Bad": "go/ast", - "ast.BadDecl": "go/ast", - "ast.BadExpr": "go/ast", - "ast.BadStmt": "go/ast", - "ast.BasicLit": "go/ast", - "ast.BinaryExpr": "go/ast", - "ast.BlockStmt": "go/ast", - "ast.BranchStmt": "go/ast", - "ast.CallExpr": "go/ast", - "ast.CaseClause": "go/ast", - "ast.ChanDir": "go/ast", - "ast.ChanType": "go/ast", - "ast.CommClause": "go/ast", - "ast.Comment": "go/ast", - "ast.CommentGroup": "go/ast", - "ast.CommentMap": "go/ast", - "ast.CompositeLit": "go/ast", - "ast.Con": "go/ast", - "ast.DeclStmt": "go/ast", - "ast.DeferStmt": "go/ast", - "ast.Ellipsis": "go/ast", - "ast.EmptyStmt": "go/ast", - "ast.ExprStmt": "go/ast", - "ast.Field": "go/ast", - "ast.FieldFilter": "go/ast", - "ast.FieldList": "go/ast", - "ast.File": "go/ast", - "ast.FileExports": "go/ast", - "ast.Filter": "go/ast", - "ast.FilterDecl": "go/ast", - "ast.FilterFile": "go/ast", - "ast.FilterFuncDuplicates": "go/ast", - "ast.FilterImportDuplicates": "go/ast", - "ast.FilterPackage": "go/ast", - "ast.FilterUnassociatedComments": "go/ast", - "ast.ForStmt": "go/ast", - "ast.Fprint": "go/ast", - "ast.Fun": "go/ast", - "ast.FuncDecl": "go/ast", - "ast.FuncLit": "go/ast", - "ast.FuncType": "go/ast", - "ast.GenDecl": "go/ast", - "ast.GoStmt": "go/ast", - "ast.Ident": "go/ast", - "ast.IfStmt": "go/ast", - "ast.ImportSpec": "go/ast", - "ast.Importer": "go/ast", - "ast.IncDecStmt": "go/ast", - "ast.IndexExpr": "go/ast", - "ast.Inspect": "go/ast", - "ast.InterfaceType": "go/ast", - "ast.IsExported": "go/ast", - "ast.KeyValueExpr": "go/ast", - "ast.LabeledStmt": "go/ast", - "ast.Lbl": "go/ast", - "ast.MapType": "go/ast", - "ast.MergeMode": "go/ast", - "ast.MergePackageFiles": "go/ast", - "ast.NewCommentMap": "go/ast", - "ast.NewIdent": "go/ast", - "ast.NewObj": "go/ast", - "ast.NewPackage": "go/ast", - "ast.NewScope": "go/ast", - "ast.Node": "go/ast", - "ast.NotNilFilter": "go/ast", - "ast.ObjKind": "go/ast", - "ast.Object": "go/ast", - "ast.Package": "go/ast", - "ast.PackageExports": "go/ast", - "ast.ParenExpr": "go/ast", - "ast.Pkg": "go/ast", - "ast.Print": "go/ast", - "ast.RECV": "go/ast", - "ast.RangeStmt": "go/ast", - "ast.ReturnStmt": "go/ast", - "ast.SEND": "go/ast", - "ast.Scope": "go/ast", - "ast.SelectStmt": "go/ast", - "ast.SelectorExpr": "go/ast", - "ast.SendStmt": "go/ast", - "ast.SliceExpr": "go/ast", - "ast.SortImports": "go/ast", - "ast.StarExpr": "go/ast", - "ast.StructType": "go/ast", - "ast.SwitchStmt": "go/ast", - "ast.Typ": "go/ast", - "ast.TypeAssertExpr": "go/ast", - "ast.TypeSpec": "go/ast", - "ast.TypeSwitchStmt": "go/ast", - "ast.UnaryExpr": "go/ast", - "ast.ValueSpec": "go/ast", - "ast.Var": "go/ast", - "ast.Visitor": "go/ast", - "ast.Walk": "go/ast", - "atomic.AddInt32": "sync/atomic", - "atomic.AddInt64": "sync/atomic", - "atomic.AddUint32": "sync/atomic", - "atomic.AddUint64": "sync/atomic", - "atomic.AddUintptr": "sync/atomic", - "atomic.CompareAndSwapInt32": "sync/atomic", - "atomic.CompareAndSwapInt64": "sync/atomic", - "atomic.CompareAndSwapPointer": "sync/atomic", - "atomic.CompareAndSwapUint32": "sync/atomic", - "atomic.CompareAndSwapUint64": "sync/atomic", - "atomic.CompareAndSwapUintptr": "sync/atomic", - "atomic.LoadInt32": "sync/atomic", - "atomic.LoadInt64": "sync/atomic", - "atomic.LoadPointer": "sync/atomic", - "atomic.LoadUint32": "sync/atomic", - "atomic.LoadUint64": "sync/atomic", - "atomic.LoadUintptr": "sync/atomic", - "atomic.StoreInt32": "sync/atomic", - "atomic.StoreInt64": "sync/atomic", - "atomic.StorePointer": "sync/atomic", - "atomic.StoreUint32": "sync/atomic", - "atomic.StoreUint64": "sync/atomic", - "atomic.StoreUintptr": "sync/atomic", - "atomic.SwapInt32": "sync/atomic", - "atomic.SwapInt64": "sync/atomic", - "atomic.SwapPointer": "sync/atomic", - "atomic.SwapUint32": "sync/atomic", - "atomic.SwapUint64": "sync/atomic", - "atomic.SwapUintptr": "sync/atomic", - "atomic.Value": "sync/atomic", - "base32.CorruptInputError": "encoding/base32", - "base32.Encoding": "encoding/base32", - "base32.HexEncoding": "encoding/base32", - "base32.NewDecoder": "encoding/base32", - "base32.NewEncoder": "encoding/base32", - "base32.NewEncoding": "encoding/base32", - "base32.StdEncoding": "encoding/base32", - "base64.CorruptInputError": "encoding/base64", - "base64.Encoding": "encoding/base64", - "base64.NewDecoder": "encoding/base64", - "base64.NewEncoder": "encoding/base64", - "base64.NewEncoding": "encoding/base64", - "base64.NoPadding": "encoding/base64", - "base64.RawStdEncoding": "encoding/base64", - "base64.RawURLEncoding": "encoding/base64", - "base64.StdEncoding": "encoding/base64", - "base64.StdPadding": "encoding/base64", - "base64.URLEncoding": "encoding/base64", - "big.Above": "math/big", - "big.Accuracy": "math/big", - "big.AwayFromZero": "math/big", - "big.Below": "math/big", - "big.ErrNaN": "math/big", - "big.Exact": "math/big", - "big.Float": "math/big", - "big.Int": "math/big", - "big.Jacobi": "math/big", - "big.MaxBase": "math/big", - "big.MaxExp": "math/big", - "big.MaxPrec": "math/big", - "big.MinExp": "math/big", - "big.NewFloat": "math/big", - "big.NewInt": "math/big", - "big.NewRat": "math/big", - "big.ParseFloat": "math/big", - "big.Rat": "math/big", - "big.RoundingMode": "math/big", - "big.ToNearestAway": "math/big", - "big.ToNearestEven": "math/big", - "big.ToNegativeInf": "math/big", - "big.ToPositiveInf": "math/big", - "big.ToZero": "math/big", - "big.Word": "math/big", - "binary.BigEndian": "encoding/binary", - "binary.ByteOrder": "encoding/binary", - "binary.LittleEndian": "encoding/binary", - "binary.MaxVarintLen16": "encoding/binary", - "binary.MaxVarintLen32": "encoding/binary", - "binary.MaxVarintLen64": "encoding/binary", - "binary.PutUvarint": "encoding/binary", - "binary.PutVarint": "encoding/binary", - "binary.Read": "encoding/binary", - "binary.ReadUvarint": "encoding/binary", - "binary.ReadVarint": "encoding/binary", - "binary.Size": "encoding/binary", - "binary.Uvarint": "encoding/binary", - "binary.Varint": "encoding/binary", - "binary.Write": "encoding/binary", - "bufio.ErrAdvanceTooFar": "bufio", - "bufio.ErrBufferFull": "bufio", - "bufio.ErrFinalToken": "bufio", - "bufio.ErrInvalidUnreadByte": "bufio", - "bufio.ErrInvalidUnreadRune": "bufio", - "bufio.ErrNegativeAdvance": "bufio", - "bufio.ErrNegativeCount": "bufio", - "bufio.ErrTooLong": "bufio", - "bufio.MaxScanTokenSize": "bufio", - "bufio.NewReadWriter": "bufio", - "bufio.NewReader": "bufio", - "bufio.NewReaderSize": "bufio", - "bufio.NewScanner": "bufio", - "bufio.NewWriter": "bufio", - "bufio.NewWriterSize": "bufio", - "bufio.ReadWriter": "bufio", - "bufio.Reader": "bufio", - "bufio.ScanBytes": "bufio", - "bufio.ScanLines": "bufio", - "bufio.ScanRunes": "bufio", - "bufio.ScanWords": "bufio", - "bufio.Scanner": "bufio", - "bufio.SplitFunc": "bufio", - "bufio.Writer": "bufio", - "build.AllowBinary": "go/build", - "build.ArchChar": "go/build", - "build.Context": "go/build", - "build.Default": "go/build", - "build.FindOnly": "go/build", - "build.IgnoreVendor": "go/build", - "build.Import": "go/build", - "build.ImportComment": "go/build", - "build.ImportDir": "go/build", - "build.ImportMode": "go/build", - "build.IsLocalImport": "go/build", - "build.MultiplePackageError": "go/build", - "build.NoGoError": "go/build", - "build.Package": "go/build", - "build.ToolDir": "go/build", - "bytes.Buffer": "bytes", - "bytes.Compare": "bytes", - "bytes.Contains": "bytes", - "bytes.ContainsAny": "bytes", - "bytes.ContainsRune": "bytes", - "bytes.Count": "bytes", - "bytes.Equal": "bytes", - "bytes.EqualFold": "bytes", - "bytes.ErrTooLarge": "bytes", - "bytes.Fields": "bytes", - "bytes.FieldsFunc": "bytes", - "bytes.HasPrefix": "bytes", - "bytes.HasSuffix": "bytes", - "bytes.Index": "bytes", - "bytes.IndexAny": "bytes", - "bytes.IndexByte": "bytes", - "bytes.IndexFunc": "bytes", - "bytes.IndexRune": "bytes", - "bytes.Join": "bytes", - "bytes.LastIndex": "bytes", - "bytes.LastIndexAny": "bytes", - "bytes.LastIndexByte": "bytes", - "bytes.LastIndexFunc": "bytes", - "bytes.Map": "bytes", - "bytes.MinRead": "bytes", - "bytes.NewBuffer": "bytes", - "bytes.NewBufferString": "bytes", - "bytes.NewReader": "bytes", - "bytes.Reader": "bytes", - "bytes.Repeat": "bytes", - "bytes.Replace": "bytes", - "bytes.Runes": "bytes", - "bytes.Split": "bytes", - "bytes.SplitAfter": "bytes", - "bytes.SplitAfterN": "bytes", - "bytes.SplitN": "bytes", - "bytes.Title": "bytes", - "bytes.ToLower": "bytes", - "bytes.ToLowerSpecial": "bytes", - "bytes.ToTitle": "bytes", - "bytes.ToTitleSpecial": "bytes", - "bytes.ToUpper": "bytes", - "bytes.ToUpperSpecial": "bytes", - "bytes.Trim": "bytes", - "bytes.TrimFunc": "bytes", - "bytes.TrimLeft": "bytes", - "bytes.TrimLeftFunc": "bytes", - "bytes.TrimPrefix": "bytes", - "bytes.TrimRight": "bytes", - "bytes.TrimRightFunc": "bytes", - "bytes.TrimSpace": "bytes", - "bytes.TrimSuffix": "bytes", - "bzip2.NewReader": "compress/bzip2", - "bzip2.StructuralError": "compress/bzip2", - "cgi.Handler": "net/http/cgi", - "cgi.Request": "net/http/cgi", - "cgi.RequestFromMap": "net/http/cgi", - "cgi.Serve": "net/http/cgi", - "cipher.AEAD": "crypto/cipher", - "cipher.Block": "crypto/cipher", - "cipher.BlockMode": "crypto/cipher", - "cipher.NewCBCDecrypter": "crypto/cipher", - "cipher.NewCBCEncrypter": "crypto/cipher", - "cipher.NewCFBDecrypter": "crypto/cipher", - "cipher.NewCFBEncrypter": "crypto/cipher", - "cipher.NewCTR": "crypto/cipher", - "cipher.NewGCM": "crypto/cipher", - "cipher.NewGCMWithNonceSize": "crypto/cipher", - "cipher.NewOFB": "crypto/cipher", - "cipher.Stream": "crypto/cipher", - "cipher.StreamReader": "crypto/cipher", - "cipher.StreamWriter": "crypto/cipher", - "cmplx.Abs": "math/cmplx", - "cmplx.Acos": "math/cmplx", - "cmplx.Acosh": "math/cmplx", - "cmplx.Asin": "math/cmplx", - "cmplx.Asinh": "math/cmplx", - "cmplx.Atan": "math/cmplx", - "cmplx.Atanh": "math/cmplx", - "cmplx.Conj": "math/cmplx", - "cmplx.Cos": "math/cmplx", - "cmplx.Cosh": "math/cmplx", - "cmplx.Cot": "math/cmplx", - "cmplx.Exp": "math/cmplx", - "cmplx.Inf": "math/cmplx", - "cmplx.IsInf": "math/cmplx", - "cmplx.IsNaN": "math/cmplx", - "cmplx.Log": "math/cmplx", - "cmplx.Log10": "math/cmplx", - "cmplx.NaN": "math/cmplx", - "cmplx.Phase": "math/cmplx", - "cmplx.Polar": "math/cmplx", - "cmplx.Pow": "math/cmplx", - "cmplx.Rect": "math/cmplx", - "cmplx.Sin": "math/cmplx", - "cmplx.Sinh": "math/cmplx", - "cmplx.Sqrt": "math/cmplx", - "cmplx.Tan": "math/cmplx", - "cmplx.Tanh": "math/cmplx", - "color.Alpha": "image/color", - "color.Alpha16": "image/color", - "color.Alpha16Model": "image/color", - "color.AlphaModel": "image/color", - "color.Black": "image/color", - "color.CMYK": "image/color", - "color.CMYKModel": "image/color", - "color.CMYKToRGB": "image/color", - "color.Color": "image/color", - "color.Gray": "image/color", - "color.Gray16": "image/color", - "color.Gray16Model": "image/color", - "color.GrayModel": "image/color", - "color.Model": "image/color", - "color.ModelFunc": "image/color", - "color.NRGBA": "image/color", - "color.NRGBA64": "image/color", - "color.NRGBA64Model": "image/color", - "color.NRGBAModel": "image/color", - "color.NYCbCrA": "image/color", - "color.NYCbCrAModel": "image/color", - "color.Opaque": "image/color", - "color.Palette": "image/color", - "color.RGBA": "image/color", - "color.RGBA64": "image/color", - "color.RGBA64Model": "image/color", - "color.RGBAModel": "image/color", - "color.RGBToCMYK": "image/color", - "color.RGBToYCbCr": "image/color", - "color.Transparent": "image/color", - "color.White": "image/color", - "color.YCbCr": "image/color", - "color.YCbCrModel": "image/color", - "color.YCbCrToRGB": "image/color", - "constant.BinaryOp": "go/constant", - "constant.BitLen": "go/constant", - "constant.Bool": "go/constant", - "constant.BoolVal": "go/constant", - "constant.Bytes": "go/constant", - "constant.Compare": "go/constant", - "constant.Complex": "go/constant", - "constant.Denom": "go/constant", - "constant.Float": "go/constant", - "constant.Float32Val": "go/constant", - "constant.Float64Val": "go/constant", - "constant.Imag": "go/constant", - "constant.Int": "go/constant", - "constant.Int64Val": "go/constant", - "constant.Kind": "go/constant", - "constant.MakeBool": "go/constant", - "constant.MakeFloat64": "go/constant", - "constant.MakeFromBytes": "go/constant", - "constant.MakeFromLiteral": "go/constant", - "constant.MakeImag": "go/constant", - "constant.MakeInt64": "go/constant", - "constant.MakeString": "go/constant", - "constant.MakeUint64": "go/constant", - "constant.MakeUnknown": "go/constant", - "constant.Num": "go/constant", - "constant.Real": "go/constant", - "constant.Shift": "go/constant", - "constant.Sign": "go/constant", - "constant.String": "go/constant", - "constant.StringVal": "go/constant", - "constant.ToComplex": "go/constant", - "constant.ToFloat": "go/constant", - "constant.ToInt": "go/constant", - "constant.Uint64Val": "go/constant", - "constant.UnaryOp": "go/constant", - "constant.Unknown": "go/constant", - "context.Background": "context", - "context.CancelFunc": "context", - "context.Canceled": "context", - "context.Context": "context", - "context.DeadlineExceeded": "context", - "context.TODO": "context", - "context.WithCancel": "context", - "context.WithDeadline": "context", - "context.WithTimeout": "context", - "context.WithValue": "context", - "cookiejar.Jar": "net/http/cookiejar", - "cookiejar.New": "net/http/cookiejar", - "cookiejar.Options": "net/http/cookiejar", - "cookiejar.PublicSuffixList": "net/http/cookiejar", - "crc32.Castagnoli": "hash/crc32", - "crc32.Checksum": "hash/crc32", - "crc32.ChecksumIEEE": "hash/crc32", - "crc32.IEEE": "hash/crc32", - "crc32.IEEETable": "hash/crc32", - "crc32.Koopman": "hash/crc32", - "crc32.MakeTable": "hash/crc32", - "crc32.New": "hash/crc32", - "crc32.NewIEEE": "hash/crc32", - "crc32.Size": "hash/crc32", - "crc32.Table": "hash/crc32", - "crc32.Update": "hash/crc32", - "crc64.Checksum": "hash/crc64", - "crc64.ECMA": "hash/crc64", - "crc64.ISO": "hash/crc64", - "crc64.MakeTable": "hash/crc64", - "crc64.New": "hash/crc64", - "crc64.Size": "hash/crc64", - "crc64.Table": "hash/crc64", - "crc64.Update": "hash/crc64", - "crypto.Decrypter": "crypto", - "crypto.DecrypterOpts": "crypto", - "crypto.Hash": "crypto", - "crypto.MD4": "crypto", - "crypto.MD5": "crypto", - "crypto.MD5SHA1": "crypto", - "crypto.PrivateKey": "crypto", - "crypto.PublicKey": "crypto", - "crypto.RIPEMD160": "crypto", - "crypto.RegisterHash": "crypto", - "crypto.SHA1": "crypto", - "crypto.SHA224": "crypto", - "crypto.SHA256": "crypto", - "crypto.SHA384": "crypto", - "crypto.SHA3_224": "crypto", - "crypto.SHA3_256": "crypto", - "crypto.SHA3_384": "crypto", - "crypto.SHA3_512": "crypto", - "crypto.SHA512": "crypto", - "crypto.SHA512_224": "crypto", - "crypto.SHA512_256": "crypto", - "crypto.Signer": "crypto", - "crypto.SignerOpts": "crypto", - "csv.ErrBareQuote": "encoding/csv", - "csv.ErrFieldCount": "encoding/csv", - "csv.ErrQuote": "encoding/csv", - "csv.ErrTrailingComma": "encoding/csv", - "csv.NewReader": "encoding/csv", - "csv.NewWriter": "encoding/csv", - "csv.ParseError": "encoding/csv", - "csv.Reader": "encoding/csv", - "csv.Writer": "encoding/csv", - "debug.FreeOSMemory": "runtime/debug", - "debug.GCStats": "runtime/debug", - "debug.PrintStack": "runtime/debug", - "debug.ReadGCStats": "runtime/debug", - "debug.SetGCPercent": "runtime/debug", - "debug.SetMaxStack": "runtime/debug", - "debug.SetMaxThreads": "runtime/debug", - "debug.SetPanicOnFault": "runtime/debug", - "debug.SetTraceback": "runtime/debug", - "debug.Stack": "runtime/debug", - "debug.WriteHeapDump": "runtime/debug", - "des.BlockSize": "crypto/des", - "des.KeySizeError": "crypto/des", - "des.NewCipher": "crypto/des", - "des.NewTripleDESCipher": "crypto/des", - "doc.AllDecls": "go/doc", - "doc.AllMethods": "go/doc", - "doc.Example": "go/doc", - "doc.Examples": "go/doc", - "doc.Filter": "go/doc", - "doc.Func": "go/doc", - "doc.IllegalPrefixes": "go/doc", - "doc.Mode": "go/doc", - "doc.New": "go/doc", - "doc.Note": "go/doc", - "doc.Package": "go/doc", - "doc.Synopsis": "go/doc", - "doc.ToHTML": "go/doc", - "doc.ToText": "go/doc", - "doc.Type": "go/doc", - "doc.Value": "go/doc", - "draw.Draw": "image/draw", - "draw.DrawMask": "image/draw", - "draw.Drawer": "image/draw", - "draw.FloydSteinberg": "image/draw", - "draw.Image": "image/draw", - "draw.Op": "image/draw", - "draw.Over": "image/draw", - "draw.Quantizer": "image/draw", - "draw.Src": "image/draw", - "driver.Bool": "database/sql/driver", - "driver.ColumnConverter": "database/sql/driver", - "driver.Conn": "database/sql/driver", - "driver.DefaultParameterConverter": "database/sql/driver", - "driver.Driver": "database/sql/driver", - "driver.ErrBadConn": "database/sql/driver", - "driver.ErrSkip": "database/sql/driver", - "driver.Execer": "database/sql/driver", - "driver.Int32": "database/sql/driver", - "driver.IsScanValue": "database/sql/driver", - "driver.IsValue": "database/sql/driver", - "driver.NotNull": "database/sql/driver", - "driver.Null": "database/sql/driver", - "driver.Queryer": "database/sql/driver", - "driver.Result": "database/sql/driver", - "driver.ResultNoRows": "database/sql/driver", - "driver.Rows": "database/sql/driver", - "driver.RowsAffected": "database/sql/driver", - "driver.Stmt": "database/sql/driver", - "driver.String": "database/sql/driver", - "driver.Tx": "database/sql/driver", - "driver.Value": "database/sql/driver", - "driver.ValueConverter": "database/sql/driver", - "driver.Valuer": "database/sql/driver", - "dsa.ErrInvalidPublicKey": "crypto/dsa", - "dsa.GenerateKey": "crypto/dsa", - "dsa.GenerateParameters": "crypto/dsa", - "dsa.L1024N160": "crypto/dsa", - "dsa.L2048N224": "crypto/dsa", - "dsa.L2048N256": "crypto/dsa", - "dsa.L3072N256": "crypto/dsa", - "dsa.ParameterSizes": "crypto/dsa", - "dsa.Parameters": "crypto/dsa", - "dsa.PrivateKey": "crypto/dsa", - "dsa.PublicKey": "crypto/dsa", - "dsa.Sign": "crypto/dsa", - "dsa.Verify": "crypto/dsa", - "dwarf.AddrType": "debug/dwarf", - "dwarf.ArrayType": "debug/dwarf", - "dwarf.Attr": "debug/dwarf", - "dwarf.AttrAbstractOrigin": "debug/dwarf", - "dwarf.AttrAccessibility": "debug/dwarf", - "dwarf.AttrAddrClass": "debug/dwarf", - "dwarf.AttrAllocated": "debug/dwarf", - "dwarf.AttrArtificial": "debug/dwarf", - "dwarf.AttrAssociated": "debug/dwarf", - "dwarf.AttrBaseTypes": "debug/dwarf", - "dwarf.AttrBitOffset": "debug/dwarf", - "dwarf.AttrBitSize": "debug/dwarf", - "dwarf.AttrByteSize": "debug/dwarf", - "dwarf.AttrCallColumn": "debug/dwarf", - "dwarf.AttrCallFile": "debug/dwarf", - "dwarf.AttrCallLine": "debug/dwarf", - "dwarf.AttrCalling": "debug/dwarf", - "dwarf.AttrCommonRef": "debug/dwarf", - "dwarf.AttrCompDir": "debug/dwarf", - "dwarf.AttrConstValue": "debug/dwarf", - "dwarf.AttrContainingType": "debug/dwarf", - "dwarf.AttrCount": "debug/dwarf", - "dwarf.AttrDataLocation": "debug/dwarf", - "dwarf.AttrDataMemberLoc": "debug/dwarf", - "dwarf.AttrDeclColumn": "debug/dwarf", - "dwarf.AttrDeclFile": "debug/dwarf", - "dwarf.AttrDeclLine": "debug/dwarf", - "dwarf.AttrDeclaration": "debug/dwarf", - "dwarf.AttrDefaultValue": "debug/dwarf", - "dwarf.AttrDescription": "debug/dwarf", - "dwarf.AttrDiscr": "debug/dwarf", - "dwarf.AttrDiscrList": "debug/dwarf", - "dwarf.AttrDiscrValue": "debug/dwarf", - "dwarf.AttrEncoding": "debug/dwarf", - "dwarf.AttrEntrypc": "debug/dwarf", - "dwarf.AttrExtension": "debug/dwarf", - "dwarf.AttrExternal": "debug/dwarf", - "dwarf.AttrFrameBase": "debug/dwarf", - "dwarf.AttrFriend": "debug/dwarf", - "dwarf.AttrHighpc": "debug/dwarf", - "dwarf.AttrIdentifierCase": "debug/dwarf", - "dwarf.AttrImport": "debug/dwarf", - "dwarf.AttrInline": "debug/dwarf", - "dwarf.AttrIsOptional": "debug/dwarf", - "dwarf.AttrLanguage": "debug/dwarf", - "dwarf.AttrLocation": "debug/dwarf", - "dwarf.AttrLowerBound": "debug/dwarf", - "dwarf.AttrLowpc": "debug/dwarf", - "dwarf.AttrMacroInfo": "debug/dwarf", - "dwarf.AttrName": "debug/dwarf", - "dwarf.AttrNamelistItem": "debug/dwarf", - "dwarf.AttrOrdering": "debug/dwarf", - "dwarf.AttrPriority": "debug/dwarf", - "dwarf.AttrProducer": "debug/dwarf", - "dwarf.AttrPrototyped": "debug/dwarf", - "dwarf.AttrRanges": "debug/dwarf", - "dwarf.AttrReturnAddr": "debug/dwarf", - "dwarf.AttrSegment": "debug/dwarf", - "dwarf.AttrSibling": "debug/dwarf", - "dwarf.AttrSpecification": "debug/dwarf", - "dwarf.AttrStartScope": "debug/dwarf", - "dwarf.AttrStaticLink": "debug/dwarf", - "dwarf.AttrStmtList": "debug/dwarf", - "dwarf.AttrStride": "debug/dwarf", - "dwarf.AttrStrideSize": "debug/dwarf", - "dwarf.AttrStringLength": "debug/dwarf", - "dwarf.AttrTrampoline": "debug/dwarf", - "dwarf.AttrType": "debug/dwarf", - "dwarf.AttrUpperBound": "debug/dwarf", - "dwarf.AttrUseLocation": "debug/dwarf", - "dwarf.AttrUseUTF8": "debug/dwarf", - "dwarf.AttrVarParam": "debug/dwarf", - "dwarf.AttrVirtuality": "debug/dwarf", - "dwarf.AttrVisibility": "debug/dwarf", - "dwarf.AttrVtableElemLoc": "debug/dwarf", - "dwarf.BasicType": "debug/dwarf", - "dwarf.BoolType": "debug/dwarf", - "dwarf.CharType": "debug/dwarf", - "dwarf.Class": "debug/dwarf", - "dwarf.ClassAddress": "debug/dwarf", - "dwarf.ClassBlock": "debug/dwarf", - "dwarf.ClassConstant": "debug/dwarf", - "dwarf.ClassExprLoc": "debug/dwarf", - "dwarf.ClassFlag": "debug/dwarf", - "dwarf.ClassLinePtr": "debug/dwarf", - "dwarf.ClassLocListPtr": "debug/dwarf", - "dwarf.ClassMacPtr": "debug/dwarf", - "dwarf.ClassRangeListPtr": "debug/dwarf", - "dwarf.ClassReference": "debug/dwarf", - "dwarf.ClassReferenceAlt": "debug/dwarf", - "dwarf.ClassReferenceSig": "debug/dwarf", - "dwarf.ClassString": "debug/dwarf", - "dwarf.ClassStringAlt": "debug/dwarf", - "dwarf.ClassUnknown": "debug/dwarf", - "dwarf.CommonType": "debug/dwarf", - "dwarf.ComplexType": "debug/dwarf", - "dwarf.Data": "debug/dwarf", - "dwarf.DecodeError": "debug/dwarf", - "dwarf.DotDotDotType": "debug/dwarf", - "dwarf.Entry": "debug/dwarf", - "dwarf.EnumType": "debug/dwarf", - "dwarf.EnumValue": "debug/dwarf", - "dwarf.ErrUnknownPC": "debug/dwarf", - "dwarf.Field": "debug/dwarf", - "dwarf.FloatType": "debug/dwarf", - "dwarf.FuncType": "debug/dwarf", - "dwarf.IntType": "debug/dwarf", - "dwarf.LineEntry": "debug/dwarf", - "dwarf.LineFile": "debug/dwarf", - "dwarf.LineReader": "debug/dwarf", - "dwarf.LineReaderPos": "debug/dwarf", - "dwarf.New": "debug/dwarf", - "dwarf.Offset": "debug/dwarf", - "dwarf.PtrType": "debug/dwarf", - "dwarf.QualType": "debug/dwarf", - "dwarf.Reader": "debug/dwarf", - "dwarf.StructField": "debug/dwarf", - "dwarf.StructType": "debug/dwarf", - "dwarf.Tag": "debug/dwarf", - "dwarf.TagAccessDeclaration": "debug/dwarf", - "dwarf.TagArrayType": "debug/dwarf", - "dwarf.TagBaseType": "debug/dwarf", - "dwarf.TagCatchDwarfBlock": "debug/dwarf", - "dwarf.TagClassType": "debug/dwarf", - "dwarf.TagCommonDwarfBlock": "debug/dwarf", - "dwarf.TagCommonInclusion": "debug/dwarf", - "dwarf.TagCompileUnit": "debug/dwarf", - "dwarf.TagCondition": "debug/dwarf", - "dwarf.TagConstType": "debug/dwarf", - "dwarf.TagConstant": "debug/dwarf", - "dwarf.TagDwarfProcedure": "debug/dwarf", - "dwarf.TagEntryPoint": "debug/dwarf", - "dwarf.TagEnumerationType": "debug/dwarf", - "dwarf.TagEnumerator": "debug/dwarf", - "dwarf.TagFileType": "debug/dwarf", - "dwarf.TagFormalParameter": "debug/dwarf", - "dwarf.TagFriend": "debug/dwarf", - "dwarf.TagImportedDeclaration": "debug/dwarf", - "dwarf.TagImportedModule": "debug/dwarf", - "dwarf.TagImportedUnit": "debug/dwarf", - "dwarf.TagInheritance": "debug/dwarf", - "dwarf.TagInlinedSubroutine": "debug/dwarf", - "dwarf.TagInterfaceType": "debug/dwarf", - "dwarf.TagLabel": "debug/dwarf", - "dwarf.TagLexDwarfBlock": "debug/dwarf", - "dwarf.TagMember": "debug/dwarf", - "dwarf.TagModule": "debug/dwarf", - "dwarf.TagMutableType": "debug/dwarf", - "dwarf.TagNamelist": "debug/dwarf", - "dwarf.TagNamelistItem": "debug/dwarf", - "dwarf.TagNamespace": "debug/dwarf", - "dwarf.TagPackedType": "debug/dwarf", - "dwarf.TagPartialUnit": "debug/dwarf", - "dwarf.TagPointerType": "debug/dwarf", - "dwarf.TagPtrToMemberType": "debug/dwarf", - "dwarf.TagReferenceType": "debug/dwarf", - "dwarf.TagRestrictType": "debug/dwarf", - "dwarf.TagRvalueReferenceType": "debug/dwarf", - "dwarf.TagSetType": "debug/dwarf", - "dwarf.TagSharedType": "debug/dwarf", - "dwarf.TagStringType": "debug/dwarf", - "dwarf.TagStructType": "debug/dwarf", - "dwarf.TagSubprogram": "debug/dwarf", - "dwarf.TagSubrangeType": "debug/dwarf", - "dwarf.TagSubroutineType": "debug/dwarf", - "dwarf.TagTemplateAlias": "debug/dwarf", - "dwarf.TagTemplateTypeParameter": "debug/dwarf", - "dwarf.TagTemplateValueParameter": "debug/dwarf", - "dwarf.TagThrownType": "debug/dwarf", - "dwarf.TagTryDwarfBlock": "debug/dwarf", - "dwarf.TagTypeUnit": "debug/dwarf", - "dwarf.TagTypedef": "debug/dwarf", - "dwarf.TagUnionType": "debug/dwarf", - "dwarf.TagUnspecifiedParameters": "debug/dwarf", - "dwarf.TagUnspecifiedType": "debug/dwarf", - "dwarf.TagVariable": "debug/dwarf", - "dwarf.TagVariant": "debug/dwarf", - "dwarf.TagVariantPart": "debug/dwarf", - "dwarf.TagVolatileType": "debug/dwarf", - "dwarf.TagWithStmt": "debug/dwarf", - "dwarf.Type": "debug/dwarf", - "dwarf.TypedefType": "debug/dwarf", - "dwarf.UcharType": "debug/dwarf", - "dwarf.UintType": "debug/dwarf", - "dwarf.UnspecifiedType": "debug/dwarf", - "dwarf.VoidType": "debug/dwarf", - "ecdsa.GenerateKey": "crypto/ecdsa", - "ecdsa.PrivateKey": "crypto/ecdsa", - "ecdsa.PublicKey": "crypto/ecdsa", - "ecdsa.Sign": "crypto/ecdsa", - "ecdsa.Verify": "crypto/ecdsa", - "elf.ARM_MAGIC_TRAMP_NUMBER": "debug/elf", - "elf.COMPRESS_HIOS": "debug/elf", - "elf.COMPRESS_HIPROC": "debug/elf", - "elf.COMPRESS_LOOS": "debug/elf", - "elf.COMPRESS_LOPROC": "debug/elf", - "elf.COMPRESS_ZLIB": "debug/elf", - "elf.Chdr32": "debug/elf", - "elf.Chdr64": "debug/elf", - "elf.Class": "debug/elf", - "elf.CompressionType": "debug/elf", - "elf.DF_BIND_NOW": "debug/elf", - "elf.DF_ORIGIN": "debug/elf", - "elf.DF_STATIC_TLS": "debug/elf", - "elf.DF_SYMBOLIC": "debug/elf", - "elf.DF_TEXTREL": "debug/elf", - "elf.DT_BIND_NOW": "debug/elf", - "elf.DT_DEBUG": "debug/elf", - "elf.DT_ENCODING": "debug/elf", - "elf.DT_FINI": "debug/elf", - "elf.DT_FINI_ARRAY": "debug/elf", - "elf.DT_FINI_ARRAYSZ": "debug/elf", - "elf.DT_FLAGS": "debug/elf", - "elf.DT_HASH": "debug/elf", - "elf.DT_HIOS": "debug/elf", - "elf.DT_HIPROC": "debug/elf", - "elf.DT_INIT": "debug/elf", - "elf.DT_INIT_ARRAY": "debug/elf", - "elf.DT_INIT_ARRAYSZ": "debug/elf", - "elf.DT_JMPREL": "debug/elf", - "elf.DT_LOOS": "debug/elf", - "elf.DT_LOPROC": "debug/elf", - "elf.DT_NEEDED": "debug/elf", - "elf.DT_NULL": "debug/elf", - "elf.DT_PLTGOT": "debug/elf", - "elf.DT_PLTREL": "debug/elf", - "elf.DT_PLTRELSZ": "debug/elf", - "elf.DT_PREINIT_ARRAY": "debug/elf", - "elf.DT_PREINIT_ARRAYSZ": "debug/elf", - "elf.DT_REL": "debug/elf", - "elf.DT_RELA": "debug/elf", - "elf.DT_RELAENT": "debug/elf", - "elf.DT_RELASZ": "debug/elf", - "elf.DT_RELENT": "debug/elf", - "elf.DT_RELSZ": "debug/elf", - "elf.DT_RPATH": "debug/elf", - "elf.DT_RUNPATH": "debug/elf", - "elf.DT_SONAME": "debug/elf", - "elf.DT_STRSZ": "debug/elf", - "elf.DT_STRTAB": "debug/elf", - "elf.DT_SYMBOLIC": "debug/elf", - "elf.DT_SYMENT": "debug/elf", - "elf.DT_SYMTAB": "debug/elf", - "elf.DT_TEXTREL": "debug/elf", - "elf.DT_VERNEED": "debug/elf", - "elf.DT_VERNEEDNUM": "debug/elf", - "elf.DT_VERSYM": "debug/elf", - "elf.Data": "debug/elf", - "elf.Dyn32": "debug/elf", - "elf.Dyn64": "debug/elf", - "elf.DynFlag": "debug/elf", - "elf.DynTag": "debug/elf", - "elf.EI_ABIVERSION": "debug/elf", - "elf.EI_CLASS": "debug/elf", - "elf.EI_DATA": "debug/elf", - "elf.EI_NIDENT": "debug/elf", - "elf.EI_OSABI": "debug/elf", - "elf.EI_PAD": "debug/elf", - "elf.EI_VERSION": "debug/elf", - "elf.ELFCLASS32": "debug/elf", - "elf.ELFCLASS64": "debug/elf", - "elf.ELFCLASSNONE": "debug/elf", - "elf.ELFDATA2LSB": "debug/elf", - "elf.ELFDATA2MSB": "debug/elf", - "elf.ELFDATANONE": "debug/elf", - "elf.ELFMAG": "debug/elf", - "elf.ELFOSABI_86OPEN": "debug/elf", - "elf.ELFOSABI_AIX": "debug/elf", - "elf.ELFOSABI_ARM": "debug/elf", - "elf.ELFOSABI_FREEBSD": "debug/elf", - "elf.ELFOSABI_HPUX": "debug/elf", - "elf.ELFOSABI_HURD": "debug/elf", - "elf.ELFOSABI_IRIX": "debug/elf", - "elf.ELFOSABI_LINUX": "debug/elf", - "elf.ELFOSABI_MODESTO": "debug/elf", - "elf.ELFOSABI_NETBSD": "debug/elf", - "elf.ELFOSABI_NONE": "debug/elf", - "elf.ELFOSABI_NSK": "debug/elf", - "elf.ELFOSABI_OPENBSD": "debug/elf", - "elf.ELFOSABI_OPENVMS": "debug/elf", - "elf.ELFOSABI_SOLARIS": "debug/elf", - "elf.ELFOSABI_STANDALONE": "debug/elf", - "elf.ELFOSABI_TRU64": "debug/elf", - "elf.EM_386": "debug/elf", - "elf.EM_486": "debug/elf", - "elf.EM_68HC12": "debug/elf", - "elf.EM_68K": "debug/elf", - "elf.EM_860": "debug/elf", - "elf.EM_88K": "debug/elf", - "elf.EM_960": "debug/elf", - "elf.EM_AARCH64": "debug/elf", - "elf.EM_ALPHA": "debug/elf", - "elf.EM_ALPHA_STD": "debug/elf", - "elf.EM_ARC": "debug/elf", - "elf.EM_ARM": "debug/elf", - "elf.EM_COLDFIRE": "debug/elf", - "elf.EM_FR20": "debug/elf", - "elf.EM_H8S": "debug/elf", - "elf.EM_H8_300": "debug/elf", - "elf.EM_H8_300H": "debug/elf", - "elf.EM_H8_500": "debug/elf", - "elf.EM_IA_64": "debug/elf", - "elf.EM_M32": "debug/elf", - "elf.EM_ME16": "debug/elf", - "elf.EM_MIPS": "debug/elf", - "elf.EM_MIPS_RS3_LE": "debug/elf", - "elf.EM_MIPS_RS4_BE": "debug/elf", - "elf.EM_MIPS_X": "debug/elf", - "elf.EM_MMA": "debug/elf", - "elf.EM_NCPU": "debug/elf", - "elf.EM_NDR1": "debug/elf", - "elf.EM_NONE": "debug/elf", - "elf.EM_PARISC": "debug/elf", - "elf.EM_PCP": "debug/elf", - "elf.EM_PPC": "debug/elf", - "elf.EM_PPC64": "debug/elf", - "elf.EM_RCE": "debug/elf", - "elf.EM_RH32": "debug/elf", - "elf.EM_S370": "debug/elf", - "elf.EM_S390": "debug/elf", - "elf.EM_SH": "debug/elf", - "elf.EM_SPARC": "debug/elf", - "elf.EM_SPARC32PLUS": "debug/elf", - "elf.EM_SPARCV9": "debug/elf", - "elf.EM_ST100": "debug/elf", - "elf.EM_STARCORE": "debug/elf", - "elf.EM_TINYJ": "debug/elf", - "elf.EM_TRICORE": "debug/elf", - "elf.EM_V800": "debug/elf", - "elf.EM_VPP500": "debug/elf", - "elf.EM_X86_64": "debug/elf", - "elf.ET_CORE": "debug/elf", - "elf.ET_DYN": "debug/elf", - "elf.ET_EXEC": "debug/elf", - "elf.ET_HIOS": "debug/elf", - "elf.ET_HIPROC": "debug/elf", - "elf.ET_LOOS": "debug/elf", - "elf.ET_LOPROC": "debug/elf", - "elf.ET_NONE": "debug/elf", - "elf.ET_REL": "debug/elf", - "elf.EV_CURRENT": "debug/elf", - "elf.EV_NONE": "debug/elf", - "elf.ErrNoSymbols": "debug/elf", - "elf.File": "debug/elf", - "elf.FileHeader": "debug/elf", - "elf.FormatError": "debug/elf", - "elf.Header32": "debug/elf", - "elf.Header64": "debug/elf", - "elf.ImportedSymbol": "debug/elf", - "elf.Machine": "debug/elf", - "elf.NT_FPREGSET": "debug/elf", - "elf.NT_PRPSINFO": "debug/elf", - "elf.NT_PRSTATUS": "debug/elf", - "elf.NType": "debug/elf", - "elf.NewFile": "debug/elf", - "elf.OSABI": "debug/elf", - "elf.Open": "debug/elf", - "elf.PF_MASKOS": "debug/elf", - "elf.PF_MASKPROC": "debug/elf", - "elf.PF_R": "debug/elf", - "elf.PF_W": "debug/elf", - "elf.PF_X": "debug/elf", - "elf.PT_DYNAMIC": "debug/elf", - "elf.PT_HIOS": "debug/elf", - "elf.PT_HIPROC": "debug/elf", - "elf.PT_INTERP": "debug/elf", - "elf.PT_LOAD": "debug/elf", - "elf.PT_LOOS": "debug/elf", - "elf.PT_LOPROC": "debug/elf", - "elf.PT_NOTE": "debug/elf", - "elf.PT_NULL": "debug/elf", - "elf.PT_PHDR": "debug/elf", - "elf.PT_SHLIB": "debug/elf", - "elf.PT_TLS": "debug/elf", - "elf.Prog": "debug/elf", - "elf.Prog32": "debug/elf", - "elf.Prog64": "debug/elf", - "elf.ProgFlag": "debug/elf", - "elf.ProgHeader": "debug/elf", - "elf.ProgType": "debug/elf", - "elf.R_386": "debug/elf", - "elf.R_386_32": "debug/elf", - "elf.R_386_COPY": "debug/elf", - "elf.R_386_GLOB_DAT": "debug/elf", - "elf.R_386_GOT32": "debug/elf", - "elf.R_386_GOTOFF": "debug/elf", - "elf.R_386_GOTPC": "debug/elf", - "elf.R_386_JMP_SLOT": "debug/elf", - "elf.R_386_NONE": "debug/elf", - "elf.R_386_PC32": "debug/elf", - "elf.R_386_PLT32": "debug/elf", - "elf.R_386_RELATIVE": "debug/elf", - "elf.R_386_TLS_DTPMOD32": "debug/elf", - "elf.R_386_TLS_DTPOFF32": "debug/elf", - "elf.R_386_TLS_GD": "debug/elf", - "elf.R_386_TLS_GD_32": "debug/elf", - "elf.R_386_TLS_GD_CALL": "debug/elf", - "elf.R_386_TLS_GD_POP": "debug/elf", - "elf.R_386_TLS_GD_PUSH": "debug/elf", - "elf.R_386_TLS_GOTIE": "debug/elf", - "elf.R_386_TLS_IE": "debug/elf", - "elf.R_386_TLS_IE_32": "debug/elf", - "elf.R_386_TLS_LDM": "debug/elf", - "elf.R_386_TLS_LDM_32": "debug/elf", - "elf.R_386_TLS_LDM_CALL": "debug/elf", - "elf.R_386_TLS_LDM_POP": "debug/elf", - "elf.R_386_TLS_LDM_PUSH": "debug/elf", - "elf.R_386_TLS_LDO_32": "debug/elf", - "elf.R_386_TLS_LE": "debug/elf", - "elf.R_386_TLS_LE_32": "debug/elf", - "elf.R_386_TLS_TPOFF": "debug/elf", - "elf.R_386_TLS_TPOFF32": "debug/elf", - "elf.R_390": "debug/elf", - "elf.R_390_12": "debug/elf", - "elf.R_390_16": "debug/elf", - "elf.R_390_20": "debug/elf", - "elf.R_390_32": "debug/elf", - "elf.R_390_64": "debug/elf", - "elf.R_390_8": "debug/elf", - "elf.R_390_COPY": "debug/elf", - "elf.R_390_GLOB_DAT": "debug/elf", - "elf.R_390_GOT12": "debug/elf", - "elf.R_390_GOT16": "debug/elf", - "elf.R_390_GOT20": "debug/elf", - "elf.R_390_GOT32": "debug/elf", - "elf.R_390_GOT64": "debug/elf", - "elf.R_390_GOTENT": "debug/elf", - "elf.R_390_GOTOFF": "debug/elf", - "elf.R_390_GOTOFF16": "debug/elf", - "elf.R_390_GOTOFF64": "debug/elf", - "elf.R_390_GOTPC": "debug/elf", - "elf.R_390_GOTPCDBL": "debug/elf", - "elf.R_390_GOTPLT12": "debug/elf", - "elf.R_390_GOTPLT16": "debug/elf", - "elf.R_390_GOTPLT20": "debug/elf", - "elf.R_390_GOTPLT32": "debug/elf", - "elf.R_390_GOTPLT64": "debug/elf", - "elf.R_390_GOTPLTENT": "debug/elf", - "elf.R_390_GOTPLTOFF16": "debug/elf", - "elf.R_390_GOTPLTOFF32": "debug/elf", - "elf.R_390_GOTPLTOFF64": "debug/elf", - "elf.R_390_JMP_SLOT": "debug/elf", - "elf.R_390_NONE": "debug/elf", - "elf.R_390_PC16": "debug/elf", - "elf.R_390_PC16DBL": "debug/elf", - "elf.R_390_PC32": "debug/elf", - "elf.R_390_PC32DBL": "debug/elf", - "elf.R_390_PC64": "debug/elf", - "elf.R_390_PLT16DBL": "debug/elf", - "elf.R_390_PLT32": "debug/elf", - "elf.R_390_PLT32DBL": "debug/elf", - "elf.R_390_PLT64": "debug/elf", - "elf.R_390_RELATIVE": "debug/elf", - "elf.R_390_TLS_DTPMOD": "debug/elf", - "elf.R_390_TLS_DTPOFF": "debug/elf", - "elf.R_390_TLS_GD32": "debug/elf", - "elf.R_390_TLS_GD64": "debug/elf", - "elf.R_390_TLS_GDCALL": "debug/elf", - "elf.R_390_TLS_GOTIE12": "debug/elf", - "elf.R_390_TLS_GOTIE20": "debug/elf", - "elf.R_390_TLS_GOTIE32": "debug/elf", - "elf.R_390_TLS_GOTIE64": "debug/elf", - "elf.R_390_TLS_IE32": "debug/elf", - "elf.R_390_TLS_IE64": "debug/elf", - "elf.R_390_TLS_IEENT": "debug/elf", - "elf.R_390_TLS_LDCALL": "debug/elf", - "elf.R_390_TLS_LDM32": "debug/elf", - "elf.R_390_TLS_LDM64": "debug/elf", - "elf.R_390_TLS_LDO32": "debug/elf", - "elf.R_390_TLS_LDO64": "debug/elf", - "elf.R_390_TLS_LE32": "debug/elf", - "elf.R_390_TLS_LE64": "debug/elf", - "elf.R_390_TLS_LOAD": "debug/elf", - "elf.R_390_TLS_TPOFF": "debug/elf", - "elf.R_AARCH64": "debug/elf", - "elf.R_AARCH64_ABS16": "debug/elf", - "elf.R_AARCH64_ABS32": "debug/elf", - "elf.R_AARCH64_ABS64": "debug/elf", - "elf.R_AARCH64_ADD_ABS_LO12_NC": "debug/elf", - "elf.R_AARCH64_ADR_GOT_PAGE": "debug/elf", - "elf.R_AARCH64_ADR_PREL_LO21": "debug/elf", - "elf.R_AARCH64_ADR_PREL_PG_HI21": "debug/elf", - "elf.R_AARCH64_ADR_PREL_PG_HI21_NC": "debug/elf", - "elf.R_AARCH64_CALL26": "debug/elf", - "elf.R_AARCH64_CONDBR19": "debug/elf", - "elf.R_AARCH64_COPY": "debug/elf", - "elf.R_AARCH64_GLOB_DAT": "debug/elf", - "elf.R_AARCH64_GOT_LD_PREL19": "debug/elf", - "elf.R_AARCH64_IRELATIVE": "debug/elf", - "elf.R_AARCH64_JUMP26": "debug/elf", - "elf.R_AARCH64_JUMP_SLOT": "debug/elf", - "elf.R_AARCH64_LD64_GOT_LO12_NC": "debug/elf", - "elf.R_AARCH64_LDST128_ABS_LO12_NC": "debug/elf", - "elf.R_AARCH64_LDST16_ABS_LO12_NC": "debug/elf", - "elf.R_AARCH64_LDST32_ABS_LO12_NC": "debug/elf", - "elf.R_AARCH64_LDST64_ABS_LO12_NC": "debug/elf", - "elf.R_AARCH64_LDST8_ABS_LO12_NC": "debug/elf", - "elf.R_AARCH64_LD_PREL_LO19": "debug/elf", - "elf.R_AARCH64_MOVW_SABS_G0": "debug/elf", - "elf.R_AARCH64_MOVW_SABS_G1": "debug/elf", - "elf.R_AARCH64_MOVW_SABS_G2": "debug/elf", - "elf.R_AARCH64_MOVW_UABS_G0": "debug/elf", - "elf.R_AARCH64_MOVW_UABS_G0_NC": "debug/elf", - "elf.R_AARCH64_MOVW_UABS_G1": "debug/elf", - "elf.R_AARCH64_MOVW_UABS_G1_NC": "debug/elf", - "elf.R_AARCH64_MOVW_UABS_G2": "debug/elf", - "elf.R_AARCH64_MOVW_UABS_G2_NC": "debug/elf", - "elf.R_AARCH64_MOVW_UABS_G3": "debug/elf", - "elf.R_AARCH64_NONE": "debug/elf", - "elf.R_AARCH64_NULL": "debug/elf", - "elf.R_AARCH64_P32_ABS16": "debug/elf", - "elf.R_AARCH64_P32_ABS32": "debug/elf", - "elf.R_AARCH64_P32_ADD_ABS_LO12_NC": "debug/elf", - "elf.R_AARCH64_P32_ADR_GOT_PAGE": "debug/elf", - "elf.R_AARCH64_P32_ADR_PREL_LO21": "debug/elf", - "elf.R_AARCH64_P32_ADR_PREL_PG_HI21": "debug/elf", - "elf.R_AARCH64_P32_CALL26": "debug/elf", - "elf.R_AARCH64_P32_CONDBR19": "debug/elf", - "elf.R_AARCH64_P32_COPY": "debug/elf", - "elf.R_AARCH64_P32_GLOB_DAT": "debug/elf", - "elf.R_AARCH64_P32_GOT_LD_PREL19": "debug/elf", - "elf.R_AARCH64_P32_IRELATIVE": "debug/elf", - "elf.R_AARCH64_P32_JUMP26": "debug/elf", - "elf.R_AARCH64_P32_JUMP_SLOT": "debug/elf", - "elf.R_AARCH64_P32_LD32_GOT_LO12_NC": "debug/elf", - "elf.R_AARCH64_P32_LDST128_ABS_LO12_NC": "debug/elf", - "elf.R_AARCH64_P32_LDST16_ABS_LO12_NC": "debug/elf", - "elf.R_AARCH64_P32_LDST32_ABS_LO12_NC": "debug/elf", - "elf.R_AARCH64_P32_LDST64_ABS_LO12_NC": "debug/elf", - "elf.R_AARCH64_P32_LDST8_ABS_LO12_NC": "debug/elf", - "elf.R_AARCH64_P32_LD_PREL_LO19": "debug/elf", - "elf.R_AARCH64_P32_MOVW_SABS_G0": "debug/elf", - "elf.R_AARCH64_P32_MOVW_UABS_G0": "debug/elf", - "elf.R_AARCH64_P32_MOVW_UABS_G0_NC": "debug/elf", - "elf.R_AARCH64_P32_MOVW_UABS_G1": "debug/elf", - "elf.R_AARCH64_P32_PREL16": "debug/elf", - "elf.R_AARCH64_P32_PREL32": "debug/elf", - "elf.R_AARCH64_P32_RELATIVE": "debug/elf", - "elf.R_AARCH64_P32_TLSDESC": "debug/elf", - "elf.R_AARCH64_P32_TLSDESC_ADD_LO12_NC": "debug/elf", - "elf.R_AARCH64_P32_TLSDESC_ADR_PAGE21": "debug/elf", - "elf.R_AARCH64_P32_TLSDESC_ADR_PREL21": "debug/elf", - "elf.R_AARCH64_P32_TLSDESC_CALL": "debug/elf", - "elf.R_AARCH64_P32_TLSDESC_LD32_LO12_NC": "debug/elf", - "elf.R_AARCH64_P32_TLSDESC_LD_PREL19": "debug/elf", - "elf.R_AARCH64_P32_TLSGD_ADD_LO12_NC": "debug/elf", - "elf.R_AARCH64_P32_TLSGD_ADR_PAGE21": "debug/elf", - "elf.R_AARCH64_P32_TLSIE_ADR_GOTTPREL_PAGE21": "debug/elf", - "elf.R_AARCH64_P32_TLSIE_LD32_GOTTPREL_LO12_NC": "debug/elf", - "elf.R_AARCH64_P32_TLSIE_LD_GOTTPREL_PREL19": "debug/elf", - "elf.R_AARCH64_P32_TLSLE_ADD_TPREL_HI12": "debug/elf", - "elf.R_AARCH64_P32_TLSLE_ADD_TPREL_LO12": "debug/elf", - "elf.R_AARCH64_P32_TLSLE_ADD_TPREL_LO12_NC": "debug/elf", - "elf.R_AARCH64_P32_TLSLE_MOVW_TPREL_G0": "debug/elf", - "elf.R_AARCH64_P32_TLSLE_MOVW_TPREL_G0_NC": "debug/elf", - "elf.R_AARCH64_P32_TLSLE_MOVW_TPREL_G1": "debug/elf", - "elf.R_AARCH64_P32_TLS_DTPMOD": "debug/elf", - "elf.R_AARCH64_P32_TLS_DTPREL": "debug/elf", - "elf.R_AARCH64_P32_TLS_TPREL": "debug/elf", - "elf.R_AARCH64_P32_TSTBR14": "debug/elf", - "elf.R_AARCH64_PREL16": "debug/elf", - "elf.R_AARCH64_PREL32": "debug/elf", - "elf.R_AARCH64_PREL64": "debug/elf", - "elf.R_AARCH64_RELATIVE": "debug/elf", - "elf.R_AARCH64_TLSDESC": "debug/elf", - "elf.R_AARCH64_TLSDESC_ADD": "debug/elf", - "elf.R_AARCH64_TLSDESC_ADD_LO12_NC": "debug/elf", - "elf.R_AARCH64_TLSDESC_ADR_PAGE21": "debug/elf", - "elf.R_AARCH64_TLSDESC_ADR_PREL21": "debug/elf", - "elf.R_AARCH64_TLSDESC_CALL": "debug/elf", - "elf.R_AARCH64_TLSDESC_LD64_LO12_NC": "debug/elf", - "elf.R_AARCH64_TLSDESC_LDR": "debug/elf", - "elf.R_AARCH64_TLSDESC_LD_PREL19": "debug/elf", - "elf.R_AARCH64_TLSDESC_OFF_G0_NC": "debug/elf", - "elf.R_AARCH64_TLSDESC_OFF_G1": "debug/elf", - "elf.R_AARCH64_TLSGD_ADD_LO12_NC": "debug/elf", - "elf.R_AARCH64_TLSGD_ADR_PAGE21": "debug/elf", - "elf.R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21": "debug/elf", - "elf.R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC": "debug/elf", - "elf.R_AARCH64_TLSIE_LD_GOTTPREL_PREL19": "debug/elf", - "elf.R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC": "debug/elf", - "elf.R_AARCH64_TLSIE_MOVW_GOTTPREL_G1": "debug/elf", - "elf.R_AARCH64_TLSLE_ADD_TPREL_HI12": "debug/elf", - "elf.R_AARCH64_TLSLE_ADD_TPREL_LO12": "debug/elf", - "elf.R_AARCH64_TLSLE_ADD_TPREL_LO12_NC": "debug/elf", - "elf.R_AARCH64_TLSLE_MOVW_TPREL_G0": "debug/elf", - "elf.R_AARCH64_TLSLE_MOVW_TPREL_G0_NC": "debug/elf", - "elf.R_AARCH64_TLSLE_MOVW_TPREL_G1": "debug/elf", - "elf.R_AARCH64_TLSLE_MOVW_TPREL_G1_NC": "debug/elf", - "elf.R_AARCH64_TLSLE_MOVW_TPREL_G2": "debug/elf", - "elf.R_AARCH64_TLS_DTPMOD64": "debug/elf", - "elf.R_AARCH64_TLS_DTPREL64": "debug/elf", - "elf.R_AARCH64_TLS_TPREL64": "debug/elf", - "elf.R_AARCH64_TSTBR14": "debug/elf", - "elf.R_ALPHA": "debug/elf", - "elf.R_ALPHA_BRADDR": "debug/elf", - "elf.R_ALPHA_COPY": "debug/elf", - "elf.R_ALPHA_GLOB_DAT": "debug/elf", - "elf.R_ALPHA_GPDISP": "debug/elf", - "elf.R_ALPHA_GPREL32": "debug/elf", - "elf.R_ALPHA_GPRELHIGH": "debug/elf", - "elf.R_ALPHA_GPRELLOW": "debug/elf", - "elf.R_ALPHA_GPVALUE": "debug/elf", - "elf.R_ALPHA_HINT": "debug/elf", - "elf.R_ALPHA_IMMED_BR_HI32": "debug/elf", - "elf.R_ALPHA_IMMED_GP_16": "debug/elf", - "elf.R_ALPHA_IMMED_GP_HI32": "debug/elf", - "elf.R_ALPHA_IMMED_LO32": "debug/elf", - "elf.R_ALPHA_IMMED_SCN_HI32": "debug/elf", - "elf.R_ALPHA_JMP_SLOT": "debug/elf", - "elf.R_ALPHA_LITERAL": "debug/elf", - "elf.R_ALPHA_LITUSE": "debug/elf", - "elf.R_ALPHA_NONE": "debug/elf", - "elf.R_ALPHA_OP_PRSHIFT": "debug/elf", - "elf.R_ALPHA_OP_PSUB": "debug/elf", - "elf.R_ALPHA_OP_PUSH": "debug/elf", - "elf.R_ALPHA_OP_STORE": "debug/elf", - "elf.R_ALPHA_REFLONG": "debug/elf", - "elf.R_ALPHA_REFQUAD": "debug/elf", - "elf.R_ALPHA_RELATIVE": "debug/elf", - "elf.R_ALPHA_SREL16": "debug/elf", - "elf.R_ALPHA_SREL32": "debug/elf", - "elf.R_ALPHA_SREL64": "debug/elf", - "elf.R_ARM": "debug/elf", - "elf.R_ARM_ABS12": "debug/elf", - "elf.R_ARM_ABS16": "debug/elf", - "elf.R_ARM_ABS32": "debug/elf", - "elf.R_ARM_ABS8": "debug/elf", - "elf.R_ARM_AMP_VCALL9": "debug/elf", - "elf.R_ARM_COPY": "debug/elf", - "elf.R_ARM_GLOB_DAT": "debug/elf", - "elf.R_ARM_GNU_VTENTRY": "debug/elf", - "elf.R_ARM_GNU_VTINHERIT": "debug/elf", - "elf.R_ARM_GOT32": "debug/elf", - "elf.R_ARM_GOTOFF": "debug/elf", - "elf.R_ARM_GOTPC": "debug/elf", - "elf.R_ARM_JUMP_SLOT": "debug/elf", - "elf.R_ARM_NONE": "debug/elf", - "elf.R_ARM_PC13": "debug/elf", - "elf.R_ARM_PC24": "debug/elf", - "elf.R_ARM_PLT32": "debug/elf", - "elf.R_ARM_RABS32": "debug/elf", - "elf.R_ARM_RBASE": "debug/elf", - "elf.R_ARM_REL32": "debug/elf", - "elf.R_ARM_RELATIVE": "debug/elf", - "elf.R_ARM_RPC24": "debug/elf", - "elf.R_ARM_RREL32": "debug/elf", - "elf.R_ARM_RSBREL32": "debug/elf", - "elf.R_ARM_SBREL32": "debug/elf", - "elf.R_ARM_SWI24": "debug/elf", - "elf.R_ARM_THM_ABS5": "debug/elf", - "elf.R_ARM_THM_PC22": "debug/elf", - "elf.R_ARM_THM_PC8": "debug/elf", - "elf.R_ARM_THM_RPC22": "debug/elf", - "elf.R_ARM_THM_SWI8": "debug/elf", - "elf.R_ARM_THM_XPC22": "debug/elf", - "elf.R_ARM_XPC25": "debug/elf", - "elf.R_INFO": "debug/elf", - "elf.R_INFO32": "debug/elf", - "elf.R_MIPS": "debug/elf", - "elf.R_MIPS_16": "debug/elf", - "elf.R_MIPS_26": "debug/elf", - "elf.R_MIPS_32": "debug/elf", - "elf.R_MIPS_64": "debug/elf", - "elf.R_MIPS_ADD_IMMEDIATE": "debug/elf", - "elf.R_MIPS_CALL16": "debug/elf", - "elf.R_MIPS_CALL_HI16": "debug/elf", - "elf.R_MIPS_CALL_LO16": "debug/elf", - "elf.R_MIPS_DELETE": "debug/elf", - "elf.R_MIPS_GOT16": "debug/elf", - "elf.R_MIPS_GOT_DISP": "debug/elf", - "elf.R_MIPS_GOT_HI16": "debug/elf", - "elf.R_MIPS_GOT_LO16": "debug/elf", - "elf.R_MIPS_GOT_OFST": "debug/elf", - "elf.R_MIPS_GOT_PAGE": "debug/elf", - "elf.R_MIPS_GPREL16": "debug/elf", - "elf.R_MIPS_GPREL32": "debug/elf", - "elf.R_MIPS_HI16": "debug/elf", - "elf.R_MIPS_HIGHER": "debug/elf", - "elf.R_MIPS_HIGHEST": "debug/elf", - "elf.R_MIPS_INSERT_A": "debug/elf", - "elf.R_MIPS_INSERT_B": "debug/elf", - "elf.R_MIPS_JALR": "debug/elf", - "elf.R_MIPS_LITERAL": "debug/elf", - "elf.R_MIPS_LO16": "debug/elf", - "elf.R_MIPS_NONE": "debug/elf", - "elf.R_MIPS_PC16": "debug/elf", - "elf.R_MIPS_PJUMP": "debug/elf", - "elf.R_MIPS_REL16": "debug/elf", - "elf.R_MIPS_REL32": "debug/elf", - "elf.R_MIPS_RELGOT": "debug/elf", - "elf.R_MIPS_SCN_DISP": "debug/elf", - "elf.R_MIPS_SHIFT5": "debug/elf", - "elf.R_MIPS_SHIFT6": "debug/elf", - "elf.R_MIPS_SUB": "debug/elf", - "elf.R_MIPS_TLS_DTPMOD32": "debug/elf", - "elf.R_MIPS_TLS_DTPMOD64": "debug/elf", - "elf.R_MIPS_TLS_DTPREL32": "debug/elf", - "elf.R_MIPS_TLS_DTPREL64": "debug/elf", - "elf.R_MIPS_TLS_DTPREL_HI16": "debug/elf", - "elf.R_MIPS_TLS_DTPREL_LO16": "debug/elf", - "elf.R_MIPS_TLS_GD": "debug/elf", - "elf.R_MIPS_TLS_GOTTPREL": "debug/elf", - "elf.R_MIPS_TLS_LDM": "debug/elf", - "elf.R_MIPS_TLS_TPREL32": "debug/elf", - "elf.R_MIPS_TLS_TPREL64": "debug/elf", - "elf.R_MIPS_TLS_TPREL_HI16": "debug/elf", - "elf.R_MIPS_TLS_TPREL_LO16": "debug/elf", - "elf.R_PPC": "debug/elf", - "elf.R_PPC64": "debug/elf", - "elf.R_PPC64_ADDR14": "debug/elf", - "elf.R_PPC64_ADDR14_BRNTAKEN": "debug/elf", - "elf.R_PPC64_ADDR14_BRTAKEN": "debug/elf", - "elf.R_PPC64_ADDR16": "debug/elf", - "elf.R_PPC64_ADDR16_DS": "debug/elf", - "elf.R_PPC64_ADDR16_HA": "debug/elf", - "elf.R_PPC64_ADDR16_HI": "debug/elf", - "elf.R_PPC64_ADDR16_HIGHER": "debug/elf", - "elf.R_PPC64_ADDR16_HIGHERA": "debug/elf", - "elf.R_PPC64_ADDR16_HIGHEST": "debug/elf", - "elf.R_PPC64_ADDR16_HIGHESTA": "debug/elf", - "elf.R_PPC64_ADDR16_LO": "debug/elf", - "elf.R_PPC64_ADDR16_LO_DS": "debug/elf", - "elf.R_PPC64_ADDR24": "debug/elf", - "elf.R_PPC64_ADDR32": "debug/elf", - "elf.R_PPC64_ADDR64": "debug/elf", - "elf.R_PPC64_DTPMOD64": "debug/elf", - "elf.R_PPC64_DTPREL16": "debug/elf", - "elf.R_PPC64_DTPREL16_DS": "debug/elf", - "elf.R_PPC64_DTPREL16_HA": "debug/elf", - "elf.R_PPC64_DTPREL16_HI": "debug/elf", - "elf.R_PPC64_DTPREL16_HIGHER": "debug/elf", - "elf.R_PPC64_DTPREL16_HIGHERA": "debug/elf", - "elf.R_PPC64_DTPREL16_HIGHEST": "debug/elf", - "elf.R_PPC64_DTPREL16_HIGHESTA": "debug/elf", - "elf.R_PPC64_DTPREL16_LO": "debug/elf", - "elf.R_PPC64_DTPREL16_LO_DS": "debug/elf", - "elf.R_PPC64_DTPREL64": "debug/elf", - "elf.R_PPC64_GOT16": "debug/elf", - "elf.R_PPC64_GOT16_DS": "debug/elf", - "elf.R_PPC64_GOT16_HA": "debug/elf", - "elf.R_PPC64_GOT16_HI": "debug/elf", - "elf.R_PPC64_GOT16_LO": "debug/elf", - "elf.R_PPC64_GOT16_LO_DS": "debug/elf", - "elf.R_PPC64_GOT_DTPREL16_DS": "debug/elf", - "elf.R_PPC64_GOT_DTPREL16_HA": "debug/elf", - "elf.R_PPC64_GOT_DTPREL16_HI": "debug/elf", - "elf.R_PPC64_GOT_DTPREL16_LO_DS": "debug/elf", - "elf.R_PPC64_GOT_TLSGD16": "debug/elf", - "elf.R_PPC64_GOT_TLSGD16_HA": "debug/elf", - "elf.R_PPC64_GOT_TLSGD16_HI": "debug/elf", - "elf.R_PPC64_GOT_TLSGD16_LO": "debug/elf", - "elf.R_PPC64_GOT_TLSLD16": "debug/elf", - "elf.R_PPC64_GOT_TLSLD16_HA": "debug/elf", - "elf.R_PPC64_GOT_TLSLD16_HI": "debug/elf", - "elf.R_PPC64_GOT_TLSLD16_LO": "debug/elf", - "elf.R_PPC64_GOT_TPREL16_DS": "debug/elf", - "elf.R_PPC64_GOT_TPREL16_HA": "debug/elf", - "elf.R_PPC64_GOT_TPREL16_HI": "debug/elf", - "elf.R_PPC64_GOT_TPREL16_LO_DS": "debug/elf", - "elf.R_PPC64_JMP_SLOT": "debug/elf", - "elf.R_PPC64_NONE": "debug/elf", - "elf.R_PPC64_REL14": "debug/elf", - "elf.R_PPC64_REL14_BRNTAKEN": "debug/elf", - "elf.R_PPC64_REL14_BRTAKEN": "debug/elf", - "elf.R_PPC64_REL16": "debug/elf", - "elf.R_PPC64_REL16_HA": "debug/elf", - "elf.R_PPC64_REL16_HI": "debug/elf", - "elf.R_PPC64_REL16_LO": "debug/elf", - "elf.R_PPC64_REL24": "debug/elf", - "elf.R_PPC64_REL32": "debug/elf", - "elf.R_PPC64_REL64": "debug/elf", - "elf.R_PPC64_TLS": "debug/elf", - "elf.R_PPC64_TLSGD": "debug/elf", - "elf.R_PPC64_TLSLD": "debug/elf", - "elf.R_PPC64_TOC": "debug/elf", - "elf.R_PPC64_TOC16": "debug/elf", - "elf.R_PPC64_TOC16_DS": "debug/elf", - "elf.R_PPC64_TOC16_HA": "debug/elf", - "elf.R_PPC64_TOC16_HI": "debug/elf", - "elf.R_PPC64_TOC16_LO": "debug/elf", - "elf.R_PPC64_TOC16_LO_DS": "debug/elf", - "elf.R_PPC64_TPREL16": "debug/elf", - "elf.R_PPC64_TPREL16_DS": "debug/elf", - "elf.R_PPC64_TPREL16_HA": "debug/elf", - "elf.R_PPC64_TPREL16_HI": "debug/elf", - "elf.R_PPC64_TPREL16_HIGHER": "debug/elf", - "elf.R_PPC64_TPREL16_HIGHERA": "debug/elf", - "elf.R_PPC64_TPREL16_HIGHEST": "debug/elf", - "elf.R_PPC64_TPREL16_HIGHESTA": "debug/elf", - "elf.R_PPC64_TPREL16_LO": "debug/elf", - "elf.R_PPC64_TPREL16_LO_DS": "debug/elf", - "elf.R_PPC64_TPREL64": "debug/elf", - "elf.R_PPC_ADDR14": "debug/elf", - "elf.R_PPC_ADDR14_BRNTAKEN": "debug/elf", - "elf.R_PPC_ADDR14_BRTAKEN": "debug/elf", - "elf.R_PPC_ADDR16": "debug/elf", - "elf.R_PPC_ADDR16_HA": "debug/elf", - "elf.R_PPC_ADDR16_HI": "debug/elf", - "elf.R_PPC_ADDR16_LO": "debug/elf", - "elf.R_PPC_ADDR24": "debug/elf", - "elf.R_PPC_ADDR32": "debug/elf", - "elf.R_PPC_COPY": "debug/elf", - "elf.R_PPC_DTPMOD32": "debug/elf", - "elf.R_PPC_DTPREL16": "debug/elf", - "elf.R_PPC_DTPREL16_HA": "debug/elf", - "elf.R_PPC_DTPREL16_HI": "debug/elf", - "elf.R_PPC_DTPREL16_LO": "debug/elf", - "elf.R_PPC_DTPREL32": "debug/elf", - "elf.R_PPC_EMB_BIT_FLD": "debug/elf", - "elf.R_PPC_EMB_MRKREF": "debug/elf", - "elf.R_PPC_EMB_NADDR16": "debug/elf", - "elf.R_PPC_EMB_NADDR16_HA": "debug/elf", - "elf.R_PPC_EMB_NADDR16_HI": "debug/elf", - "elf.R_PPC_EMB_NADDR16_LO": "debug/elf", - "elf.R_PPC_EMB_NADDR32": "debug/elf", - "elf.R_PPC_EMB_RELSDA": "debug/elf", - "elf.R_PPC_EMB_RELSEC16": "debug/elf", - "elf.R_PPC_EMB_RELST_HA": "debug/elf", - "elf.R_PPC_EMB_RELST_HI": "debug/elf", - "elf.R_PPC_EMB_RELST_LO": "debug/elf", - "elf.R_PPC_EMB_SDA21": "debug/elf", - "elf.R_PPC_EMB_SDA2I16": "debug/elf", - "elf.R_PPC_EMB_SDA2REL": "debug/elf", - "elf.R_PPC_EMB_SDAI16": "debug/elf", - "elf.R_PPC_GLOB_DAT": "debug/elf", - "elf.R_PPC_GOT16": "debug/elf", - "elf.R_PPC_GOT16_HA": "debug/elf", - "elf.R_PPC_GOT16_HI": "debug/elf", - "elf.R_PPC_GOT16_LO": "debug/elf", - "elf.R_PPC_GOT_TLSGD16": "debug/elf", - "elf.R_PPC_GOT_TLSGD16_HA": "debug/elf", - "elf.R_PPC_GOT_TLSGD16_HI": "debug/elf", - "elf.R_PPC_GOT_TLSGD16_LO": "debug/elf", - "elf.R_PPC_GOT_TLSLD16": "debug/elf", - "elf.R_PPC_GOT_TLSLD16_HA": "debug/elf", - "elf.R_PPC_GOT_TLSLD16_HI": "debug/elf", - "elf.R_PPC_GOT_TLSLD16_LO": "debug/elf", - "elf.R_PPC_GOT_TPREL16": "debug/elf", - "elf.R_PPC_GOT_TPREL16_HA": "debug/elf", - "elf.R_PPC_GOT_TPREL16_HI": "debug/elf", - "elf.R_PPC_GOT_TPREL16_LO": "debug/elf", - "elf.R_PPC_JMP_SLOT": "debug/elf", - "elf.R_PPC_LOCAL24PC": "debug/elf", - "elf.R_PPC_NONE": "debug/elf", - "elf.R_PPC_PLT16_HA": "debug/elf", - "elf.R_PPC_PLT16_HI": "debug/elf", - "elf.R_PPC_PLT16_LO": "debug/elf", - "elf.R_PPC_PLT32": "debug/elf", - "elf.R_PPC_PLTREL24": "debug/elf", - "elf.R_PPC_PLTREL32": "debug/elf", - "elf.R_PPC_REL14": "debug/elf", - "elf.R_PPC_REL14_BRNTAKEN": "debug/elf", - "elf.R_PPC_REL14_BRTAKEN": "debug/elf", - "elf.R_PPC_REL24": "debug/elf", - "elf.R_PPC_REL32": "debug/elf", - "elf.R_PPC_RELATIVE": "debug/elf", - "elf.R_PPC_SDAREL16": "debug/elf", - "elf.R_PPC_SECTOFF": "debug/elf", - "elf.R_PPC_SECTOFF_HA": "debug/elf", - "elf.R_PPC_SECTOFF_HI": "debug/elf", - "elf.R_PPC_SECTOFF_LO": "debug/elf", - "elf.R_PPC_TLS": "debug/elf", - "elf.R_PPC_TPREL16": "debug/elf", - "elf.R_PPC_TPREL16_HA": "debug/elf", - "elf.R_PPC_TPREL16_HI": "debug/elf", - "elf.R_PPC_TPREL16_LO": "debug/elf", - "elf.R_PPC_TPREL32": "debug/elf", - "elf.R_PPC_UADDR16": "debug/elf", - "elf.R_PPC_UADDR32": "debug/elf", - "elf.R_SPARC": "debug/elf", - "elf.R_SPARC_10": "debug/elf", - "elf.R_SPARC_11": "debug/elf", - "elf.R_SPARC_13": "debug/elf", - "elf.R_SPARC_16": "debug/elf", - "elf.R_SPARC_22": "debug/elf", - "elf.R_SPARC_32": "debug/elf", - "elf.R_SPARC_5": "debug/elf", - "elf.R_SPARC_6": "debug/elf", - "elf.R_SPARC_64": "debug/elf", - "elf.R_SPARC_7": "debug/elf", - "elf.R_SPARC_8": "debug/elf", - "elf.R_SPARC_COPY": "debug/elf", - "elf.R_SPARC_DISP16": "debug/elf", - "elf.R_SPARC_DISP32": "debug/elf", - "elf.R_SPARC_DISP64": "debug/elf", - "elf.R_SPARC_DISP8": "debug/elf", - "elf.R_SPARC_GLOB_DAT": "debug/elf", - "elf.R_SPARC_GLOB_JMP": "debug/elf", - "elf.R_SPARC_GOT10": "debug/elf", - "elf.R_SPARC_GOT13": "debug/elf", - "elf.R_SPARC_GOT22": "debug/elf", - "elf.R_SPARC_H44": "debug/elf", - "elf.R_SPARC_HH22": "debug/elf", - "elf.R_SPARC_HI22": "debug/elf", - "elf.R_SPARC_HIPLT22": "debug/elf", - "elf.R_SPARC_HIX22": "debug/elf", - "elf.R_SPARC_HM10": "debug/elf", - "elf.R_SPARC_JMP_SLOT": "debug/elf", - "elf.R_SPARC_L44": "debug/elf", - "elf.R_SPARC_LM22": "debug/elf", - "elf.R_SPARC_LO10": "debug/elf", - "elf.R_SPARC_LOPLT10": "debug/elf", - "elf.R_SPARC_LOX10": "debug/elf", - "elf.R_SPARC_M44": "debug/elf", - "elf.R_SPARC_NONE": "debug/elf", - "elf.R_SPARC_OLO10": "debug/elf", - "elf.R_SPARC_PC10": "debug/elf", - "elf.R_SPARC_PC22": "debug/elf", - "elf.R_SPARC_PCPLT10": "debug/elf", - "elf.R_SPARC_PCPLT22": "debug/elf", - "elf.R_SPARC_PCPLT32": "debug/elf", - "elf.R_SPARC_PC_HH22": "debug/elf", - "elf.R_SPARC_PC_HM10": "debug/elf", - "elf.R_SPARC_PC_LM22": "debug/elf", - "elf.R_SPARC_PLT32": "debug/elf", - "elf.R_SPARC_PLT64": "debug/elf", - "elf.R_SPARC_REGISTER": "debug/elf", - "elf.R_SPARC_RELATIVE": "debug/elf", - "elf.R_SPARC_UA16": "debug/elf", - "elf.R_SPARC_UA32": "debug/elf", - "elf.R_SPARC_UA64": "debug/elf", - "elf.R_SPARC_WDISP16": "debug/elf", - "elf.R_SPARC_WDISP19": "debug/elf", - "elf.R_SPARC_WDISP22": "debug/elf", - "elf.R_SPARC_WDISP30": "debug/elf", - "elf.R_SPARC_WPLT30": "debug/elf", - "elf.R_SYM32": "debug/elf", - "elf.R_SYM64": "debug/elf", - "elf.R_TYPE32": "debug/elf", - "elf.R_TYPE64": "debug/elf", - "elf.R_X86_64": "debug/elf", - "elf.R_X86_64_16": "debug/elf", - "elf.R_X86_64_32": "debug/elf", - "elf.R_X86_64_32S": "debug/elf", - "elf.R_X86_64_64": "debug/elf", - "elf.R_X86_64_8": "debug/elf", - "elf.R_X86_64_COPY": "debug/elf", - "elf.R_X86_64_DTPMOD64": "debug/elf", - "elf.R_X86_64_DTPOFF32": "debug/elf", - "elf.R_X86_64_DTPOFF64": "debug/elf", - "elf.R_X86_64_GLOB_DAT": "debug/elf", - "elf.R_X86_64_GOT32": "debug/elf", - "elf.R_X86_64_GOTPCREL": "debug/elf", - "elf.R_X86_64_GOTTPOFF": "debug/elf", - "elf.R_X86_64_JMP_SLOT": "debug/elf", - "elf.R_X86_64_NONE": "debug/elf", - "elf.R_X86_64_PC16": "debug/elf", - "elf.R_X86_64_PC32": "debug/elf", - "elf.R_X86_64_PC8": "debug/elf", - "elf.R_X86_64_PLT32": "debug/elf", - "elf.R_X86_64_RELATIVE": "debug/elf", - "elf.R_X86_64_TLSGD": "debug/elf", - "elf.R_X86_64_TLSLD": "debug/elf", - "elf.R_X86_64_TPOFF32": "debug/elf", - "elf.R_X86_64_TPOFF64": "debug/elf", - "elf.Rel32": "debug/elf", - "elf.Rel64": "debug/elf", - "elf.Rela32": "debug/elf", - "elf.Rela64": "debug/elf", - "elf.SHF_ALLOC": "debug/elf", - "elf.SHF_COMPRESSED": "debug/elf", - "elf.SHF_EXECINSTR": "debug/elf", - "elf.SHF_GROUP": "debug/elf", - "elf.SHF_INFO_LINK": "debug/elf", - "elf.SHF_LINK_ORDER": "debug/elf", - "elf.SHF_MASKOS": "debug/elf", - "elf.SHF_MASKPROC": "debug/elf", - "elf.SHF_MERGE": "debug/elf", - "elf.SHF_OS_NONCONFORMING": "debug/elf", - "elf.SHF_STRINGS": "debug/elf", - "elf.SHF_TLS": "debug/elf", - "elf.SHF_WRITE": "debug/elf", - "elf.SHN_ABS": "debug/elf", - "elf.SHN_COMMON": "debug/elf", - "elf.SHN_HIOS": "debug/elf", - "elf.SHN_HIPROC": "debug/elf", - "elf.SHN_HIRESERVE": "debug/elf", - "elf.SHN_LOOS": "debug/elf", - "elf.SHN_LOPROC": "debug/elf", - "elf.SHN_LORESERVE": "debug/elf", - "elf.SHN_UNDEF": "debug/elf", - "elf.SHN_XINDEX": "debug/elf", - "elf.SHT_DYNAMIC": "debug/elf", - "elf.SHT_DYNSYM": "debug/elf", - "elf.SHT_FINI_ARRAY": "debug/elf", - "elf.SHT_GNU_ATTRIBUTES": "debug/elf", - "elf.SHT_GNU_HASH": "debug/elf", - "elf.SHT_GNU_LIBLIST": "debug/elf", - "elf.SHT_GNU_VERDEF": "debug/elf", - "elf.SHT_GNU_VERNEED": "debug/elf", - "elf.SHT_GNU_VERSYM": "debug/elf", - "elf.SHT_GROUP": "debug/elf", - "elf.SHT_HASH": "debug/elf", - "elf.SHT_HIOS": "debug/elf", - "elf.SHT_HIPROC": "debug/elf", - "elf.SHT_HIUSER": "debug/elf", - "elf.SHT_INIT_ARRAY": "debug/elf", - "elf.SHT_LOOS": "debug/elf", - "elf.SHT_LOPROC": "debug/elf", - "elf.SHT_LOUSER": "debug/elf", - "elf.SHT_NOBITS": "debug/elf", - "elf.SHT_NOTE": "debug/elf", - "elf.SHT_NULL": "debug/elf", - "elf.SHT_PREINIT_ARRAY": "debug/elf", - "elf.SHT_PROGBITS": "debug/elf", - "elf.SHT_REL": "debug/elf", - "elf.SHT_RELA": "debug/elf", - "elf.SHT_SHLIB": "debug/elf", - "elf.SHT_STRTAB": "debug/elf", - "elf.SHT_SYMTAB": "debug/elf", - "elf.SHT_SYMTAB_SHNDX": "debug/elf", - "elf.STB_GLOBAL": "debug/elf", - "elf.STB_HIOS": "debug/elf", - "elf.STB_HIPROC": "debug/elf", - "elf.STB_LOCAL": "debug/elf", - "elf.STB_LOOS": "debug/elf", - "elf.STB_LOPROC": "debug/elf", - "elf.STB_WEAK": "debug/elf", - "elf.STT_COMMON": "debug/elf", - "elf.STT_FILE": "debug/elf", - "elf.STT_FUNC": "debug/elf", - "elf.STT_HIOS": "debug/elf", - "elf.STT_HIPROC": "debug/elf", - "elf.STT_LOOS": "debug/elf", - "elf.STT_LOPROC": "debug/elf", - "elf.STT_NOTYPE": "debug/elf", - "elf.STT_OBJECT": "debug/elf", - "elf.STT_SECTION": "debug/elf", - "elf.STT_TLS": "debug/elf", - "elf.STV_DEFAULT": "debug/elf", - "elf.STV_HIDDEN": "debug/elf", - "elf.STV_INTERNAL": "debug/elf", - "elf.STV_PROTECTED": "debug/elf", - "elf.ST_BIND": "debug/elf", - "elf.ST_INFO": "debug/elf", - "elf.ST_TYPE": "debug/elf", - "elf.ST_VISIBILITY": "debug/elf", - "elf.Section": "debug/elf", - "elf.Section32": "debug/elf", - "elf.Section64": "debug/elf", - "elf.SectionFlag": "debug/elf", - "elf.SectionHeader": "debug/elf", - "elf.SectionIndex": "debug/elf", - "elf.SectionType": "debug/elf", - "elf.Sym32": "debug/elf", - "elf.Sym32Size": "debug/elf", - "elf.Sym64": "debug/elf", - "elf.Sym64Size": "debug/elf", - "elf.SymBind": "debug/elf", - "elf.SymType": "debug/elf", - "elf.SymVis": "debug/elf", - "elf.Symbol": "debug/elf", - "elf.Type": "debug/elf", - "elf.Version": "debug/elf", - "elliptic.Curve": "crypto/elliptic", - "elliptic.CurveParams": "crypto/elliptic", - "elliptic.GenerateKey": "crypto/elliptic", - "elliptic.Marshal": "crypto/elliptic", - "elliptic.P224": "crypto/elliptic", - "elliptic.P256": "crypto/elliptic", - "elliptic.P384": "crypto/elliptic", - "elliptic.P521": "crypto/elliptic", - "elliptic.Unmarshal": "crypto/elliptic", - "encoding.BinaryMarshaler": "encoding", - "encoding.BinaryUnmarshaler": "encoding", - "encoding.TextMarshaler": "encoding", - "encoding.TextUnmarshaler": "encoding", - "errors.New": "errors", - "exec.Cmd": "os/exec", - "exec.Command": "os/exec", - "exec.CommandContext": "os/exec", - "exec.ErrNotFound": "os/exec", - "exec.Error": "os/exec", - "exec.ExitError": "os/exec", - "exec.LookPath": "os/exec", - "expvar.Do": "expvar", - "expvar.Float": "expvar", - "expvar.Func": "expvar", - "expvar.Get": "expvar", - "expvar.Int": "expvar", - "expvar.KeyValue": "expvar", - "expvar.Map": "expvar", - "expvar.NewFloat": "expvar", - "expvar.NewInt": "expvar", - "expvar.NewMap": "expvar", - "expvar.NewString": "expvar", - "expvar.Publish": "expvar", - "expvar.String": "expvar", - "expvar.Var": "expvar", - "fcgi.ErrConnClosed": "net/http/fcgi", - "fcgi.ErrRequestAborted": "net/http/fcgi", - "fcgi.Serve": "net/http/fcgi", - "filepath.Abs": "path/filepath", - "filepath.Base": "path/filepath", - "filepath.Clean": "path/filepath", - "filepath.Dir": "path/filepath", - "filepath.ErrBadPattern": "path/filepath", - "filepath.EvalSymlinks": "path/filepath", - "filepath.Ext": "path/filepath", - "filepath.FromSlash": "path/filepath", - "filepath.Glob": "path/filepath", - "filepath.HasPrefix": "path/filepath", - "filepath.IsAbs": "path/filepath", - "filepath.Join": "path/filepath", - "filepath.ListSeparator": "path/filepath", - "filepath.Match": "path/filepath", - "filepath.Rel": "path/filepath", - "filepath.Separator": "path/filepath", - "filepath.SkipDir": "path/filepath", - "filepath.Split": "path/filepath", - "filepath.SplitList": "path/filepath", - "filepath.ToSlash": "path/filepath", - "filepath.VolumeName": "path/filepath", - "filepath.Walk": "path/filepath", - "filepath.WalkFunc": "path/filepath", - "flag.Arg": "flag", - "flag.Args": "flag", - "flag.Bool": "flag", - "flag.BoolVar": "flag", - "flag.CommandLine": "flag", - "flag.ContinueOnError": "flag", - "flag.Duration": "flag", - "flag.DurationVar": "flag", - "flag.ErrHelp": "flag", - "flag.ErrorHandling": "flag", - "flag.ExitOnError": "flag", - "flag.Flag": "flag", - "flag.FlagSet": "flag", - "flag.Float64": "flag", - "flag.Float64Var": "flag", - "flag.Getter": "flag", - "flag.Int": "flag", - "flag.Int64": "flag", - "flag.Int64Var": "flag", - "flag.IntVar": "flag", - "flag.Lookup": "flag", - "flag.NArg": "flag", - "flag.NFlag": "flag", - "flag.NewFlagSet": "flag", - "flag.PanicOnError": "flag", - "flag.Parse": "flag", - "flag.Parsed": "flag", - "flag.PrintDefaults": "flag", - "flag.Set": "flag", - "flag.String": "flag", - "flag.StringVar": "flag", - "flag.Uint": "flag", - "flag.Uint64": "flag", - "flag.Uint64Var": "flag", - "flag.UintVar": "flag", - "flag.UnquoteUsage": "flag", - "flag.Usage": "flag", - "flag.Value": "flag", - "flag.Var": "flag", - "flag.Visit": "flag", - "flag.VisitAll": "flag", - "flate.BestCompression": "compress/flate", - "flate.BestSpeed": "compress/flate", - "flate.CorruptInputError": "compress/flate", - "flate.DefaultCompression": "compress/flate", - "flate.HuffmanOnly": "compress/flate", - "flate.InternalError": "compress/flate", - "flate.NewReader": "compress/flate", - "flate.NewReaderDict": "compress/flate", - "flate.NewWriter": "compress/flate", - "flate.NewWriterDict": "compress/flate", - "flate.NoCompression": "compress/flate", - "flate.ReadError": "compress/flate", - "flate.Reader": "compress/flate", - "flate.Resetter": "compress/flate", - "flate.WriteError": "compress/flate", - "flate.Writer": "compress/flate", - "fmt.Errorf": "fmt", - "fmt.Formatter": "fmt", - "fmt.Fprint": "fmt", - "fmt.Fprintf": "fmt", - "fmt.Fprintln": "fmt", - "fmt.Fscan": "fmt", - "fmt.Fscanf": "fmt", - "fmt.Fscanln": "fmt", - "fmt.GoStringer": "fmt", - "fmt.Print": "fmt", - "fmt.Printf": "fmt", - "fmt.Println": "fmt", - "fmt.Scan": "fmt", - "fmt.ScanState": "fmt", - "fmt.Scanf": "fmt", - "fmt.Scanln": "fmt", - "fmt.Scanner": "fmt", - "fmt.Sprint": "fmt", - "fmt.Sprintf": "fmt", - "fmt.Sprintln": "fmt", - "fmt.Sscan": "fmt", - "fmt.Sscanf": "fmt", - "fmt.Sscanln": "fmt", - "fmt.State": "fmt", - "fmt.Stringer": "fmt", - "fnv.New32": "hash/fnv", - "fnv.New32a": "hash/fnv", - "fnv.New64": "hash/fnv", - "fnv.New64a": "hash/fnv", - "format.Node": "go/format", - "format.Source": "go/format", - "gif.Decode": "image/gif", - "gif.DecodeAll": "image/gif", - "gif.DecodeConfig": "image/gif", - "gif.DisposalBackground": "image/gif", - "gif.DisposalNone": "image/gif", - "gif.DisposalPrevious": "image/gif", - "gif.Encode": "image/gif", - "gif.EncodeAll": "image/gif", - "gif.GIF": "image/gif", - "gif.Options": "image/gif", - "gob.CommonType": "encoding/gob", - "gob.Decoder": "encoding/gob", - "gob.Encoder": "encoding/gob", - "gob.GobDecoder": "encoding/gob", - "gob.GobEncoder": "encoding/gob", - "gob.NewDecoder": "encoding/gob", - "gob.NewEncoder": "encoding/gob", - "gob.Register": "encoding/gob", - "gob.RegisterName": "encoding/gob", - "gosym.DecodingError": "debug/gosym", - "gosym.Func": "debug/gosym", - "gosym.LineTable": "debug/gosym", - "gosym.NewLineTable": "debug/gosym", - "gosym.NewTable": "debug/gosym", - "gosym.Obj": "debug/gosym", - "gosym.Sym": "debug/gosym", - "gosym.Table": "debug/gosym", - "gosym.UnknownFileError": "debug/gosym", - "gosym.UnknownLineError": "debug/gosym", - "gzip.BestCompression": "compress/gzip", - "gzip.BestSpeed": "compress/gzip", - "gzip.DefaultCompression": "compress/gzip", - "gzip.ErrChecksum": "compress/gzip", - "gzip.ErrHeader": "compress/gzip", - "gzip.Header": "compress/gzip", - "gzip.NewReader": "compress/gzip", - "gzip.NewWriter": "compress/gzip", - "gzip.NewWriterLevel": "compress/gzip", - "gzip.NoCompression": "compress/gzip", - "gzip.Reader": "compress/gzip", - "gzip.Writer": "compress/gzip", - "hash.Hash": "hash", - "hash.Hash32": "hash", - "hash.Hash64": "hash", - "heap.Fix": "container/heap", - "heap.Init": "container/heap", - "heap.Interface": "container/heap", - "heap.Pop": "container/heap", - "heap.Push": "container/heap", - "heap.Remove": "container/heap", - "hex.Decode": "encoding/hex", - "hex.DecodeString": "encoding/hex", - "hex.DecodedLen": "encoding/hex", - "hex.Dump": "encoding/hex", - "hex.Dumper": "encoding/hex", - "hex.Encode": "encoding/hex", - "hex.EncodeToString": "encoding/hex", - "hex.EncodedLen": "encoding/hex", - "hex.ErrLength": "encoding/hex", - "hex.InvalidByteError": "encoding/hex", - "hmac.Equal": "crypto/hmac", - "hmac.New": "crypto/hmac", - "html.EscapeString": "html", - "html.UnescapeString": "html", - "http.CanonicalHeaderKey": "net/http", - "http.Client": "net/http", - "http.CloseNotifier": "net/http", - "http.ConnState": "net/http", - "http.Cookie": "net/http", - "http.CookieJar": "net/http", - "http.DefaultClient": "net/http", - "http.DefaultMaxHeaderBytes": "net/http", - "http.DefaultMaxIdleConnsPerHost": "net/http", - "http.DefaultServeMux": "net/http", - "http.DefaultTransport": "net/http", - "http.DetectContentType": "net/http", - "http.Dir": "net/http", - "http.ErrBodyNotAllowed": "net/http", - "http.ErrBodyReadAfterClose": "net/http", - "http.ErrContentLength": "net/http", - "http.ErrHandlerTimeout": "net/http", - "http.ErrHeaderTooLong": "net/http", - "http.ErrHijacked": "net/http", - "http.ErrLineTooLong": "net/http", - "http.ErrMissingBoundary": "net/http", - "http.ErrMissingContentLength": "net/http", - "http.ErrMissingFile": "net/http", - "http.ErrNoCookie": "net/http", - "http.ErrNoLocation": "net/http", - "http.ErrNotMultipart": "net/http", - "http.ErrNotSupported": "net/http", - "http.ErrShortBody": "net/http", - "http.ErrSkipAltProtocol": "net/http", - "http.ErrUnexpectedTrailer": "net/http", - "http.ErrUseLastResponse": "net/http", - "http.ErrWriteAfterFlush": "net/http", - "http.Error": "net/http", - "http.File": "net/http", - "http.FileServer": "net/http", - "http.FileSystem": "net/http", - "http.Flusher": "net/http", - "http.Get": "net/http", - "http.Handle": "net/http", - "http.HandleFunc": "net/http", - "http.Handler": "net/http", - "http.HandlerFunc": "net/http", - "http.Head": "net/http", - "http.Header": "net/http", - "http.Hijacker": "net/http", - "http.ListenAndServe": "net/http", - "http.ListenAndServeTLS": "net/http", - "http.LocalAddrContextKey": "net/http", - "http.MaxBytesReader": "net/http", - "http.MethodConnect": "net/http", - "http.MethodDelete": "net/http", - "http.MethodGet": "net/http", - "http.MethodHead": "net/http", - "http.MethodOptions": "net/http", - "http.MethodPatch": "net/http", - "http.MethodPost": "net/http", - "http.MethodPut": "net/http", - "http.MethodTrace": "net/http", - "http.NewFileTransport": "net/http", - "http.NewRequest": "net/http", - "http.NewServeMux": "net/http", - "http.NotFound": "net/http", - "http.NotFoundHandler": "net/http", - "http.ParseHTTPVersion": "net/http", - "http.ParseTime": "net/http", - "http.Post": "net/http", - "http.PostForm": "net/http", - "http.ProtocolError": "net/http", - "http.ProxyFromEnvironment": "net/http", - "http.ProxyURL": "net/http", - "http.ReadRequest": "net/http", - "http.ReadResponse": "net/http", - "http.Redirect": "net/http", - "http.RedirectHandler": "net/http", - "http.Request": "net/http", - "http.Response": "net/http", - "http.ResponseWriter": "net/http", - "http.RoundTripper": "net/http", - "http.Serve": "net/http", - "http.ServeContent": "net/http", - "http.ServeFile": "net/http", - "http.ServeMux": "net/http", - "http.Server": "net/http", - "http.ServerContextKey": "net/http", - "http.SetCookie": "net/http", - "http.StateActive": "net/http", - "http.StateClosed": "net/http", - "http.StateHijacked": "net/http", - "http.StateIdle": "net/http", - "http.StateNew": "net/http", - "http.StatusAccepted": "net/http", - "http.StatusAlreadyReported": "net/http", - "http.StatusBadGateway": "net/http", - "http.StatusBadRequest": "net/http", - "http.StatusConflict": "net/http", - "http.StatusContinue": "net/http", - "http.StatusCreated": "net/http", - "http.StatusExpectationFailed": "net/http", - "http.StatusFailedDependency": "net/http", - "http.StatusForbidden": "net/http", - "http.StatusFound": "net/http", - "http.StatusGatewayTimeout": "net/http", - "http.StatusGone": "net/http", - "http.StatusHTTPVersionNotSupported": "net/http", - "http.StatusIMUsed": "net/http", - "http.StatusInsufficientStorage": "net/http", - "http.StatusInternalServerError": "net/http", - "http.StatusLengthRequired": "net/http", - "http.StatusLocked": "net/http", - "http.StatusLoopDetected": "net/http", - "http.StatusMethodNotAllowed": "net/http", - "http.StatusMovedPermanently": "net/http", - "http.StatusMultiStatus": "net/http", - "http.StatusMultipleChoices": "net/http", - "http.StatusNetworkAuthenticationRequired": "net/http", - "http.StatusNoContent": "net/http", - "http.StatusNonAuthoritativeInfo": "net/http", - "http.StatusNotAcceptable": "net/http", - "http.StatusNotExtended": "net/http", - "http.StatusNotFound": "net/http", - "http.StatusNotImplemented": "net/http", - "http.StatusNotModified": "net/http", - "http.StatusOK": "net/http", - "http.StatusPartialContent": "net/http", - "http.StatusPaymentRequired": "net/http", - "http.StatusPermanentRedirect": "net/http", - "http.StatusPreconditionFailed": "net/http", - "http.StatusPreconditionRequired": "net/http", - "http.StatusProcessing": "net/http", - "http.StatusProxyAuthRequired": "net/http", - "http.StatusRequestEntityTooLarge": "net/http", - "http.StatusRequestHeaderFieldsTooLarge": "net/http", - "http.StatusRequestTimeout": "net/http", - "http.StatusRequestURITooLong": "net/http", - "http.StatusRequestedRangeNotSatisfiable": "net/http", - "http.StatusResetContent": "net/http", - "http.StatusSeeOther": "net/http", - "http.StatusServiceUnavailable": "net/http", - "http.StatusSwitchingProtocols": "net/http", - "http.StatusTeapot": "net/http", - "http.StatusTemporaryRedirect": "net/http", - "http.StatusText": "net/http", - "http.StatusTooManyRequests": "net/http", - "http.StatusUnauthorized": "net/http", - "http.StatusUnavailableForLegalReasons": "net/http", - "http.StatusUnprocessableEntity": "net/http", - "http.StatusUnsupportedMediaType": "net/http", - "http.StatusUpgradeRequired": "net/http", - "http.StatusUseProxy": "net/http", - "http.StatusVariantAlsoNegotiates": "net/http", - "http.StripPrefix": "net/http", - "http.TimeFormat": "net/http", - "http.TimeoutHandler": "net/http", - "http.Transport": "net/http", - "httptest.DefaultRemoteAddr": "net/http/httptest", - "httptest.NewRecorder": "net/http/httptest", - "httptest.NewRequest": "net/http/httptest", - "httptest.NewServer": "net/http/httptest", - "httptest.NewTLSServer": "net/http/httptest", - "httptest.NewUnstartedServer": "net/http/httptest", - "httptest.ResponseRecorder": "net/http/httptest", - "httptest.Server": "net/http/httptest", - "httptrace.ClientTrace": "net/http/httptrace", - "httptrace.ContextClientTrace": "net/http/httptrace", - "httptrace.DNSDoneInfo": "net/http/httptrace", - "httptrace.DNSStartInfo": "net/http/httptrace", - "httptrace.GotConnInfo": "net/http/httptrace", - "httptrace.WithClientTrace": "net/http/httptrace", - "httptrace.WroteRequestInfo": "net/http/httptrace", - "httputil.BufferPool": "net/http/httputil", - "httputil.ClientConn": "net/http/httputil", - "httputil.DumpRequest": "net/http/httputil", - "httputil.DumpRequestOut": "net/http/httputil", - "httputil.DumpResponse": "net/http/httputil", - "httputil.ErrClosed": "net/http/httputil", - "httputil.ErrLineTooLong": "net/http/httputil", - "httputil.ErrPersistEOF": "net/http/httputil", - "httputil.ErrPipeline": "net/http/httputil", - "httputil.NewChunkedReader": "net/http/httputil", - "httputil.NewChunkedWriter": "net/http/httputil", - "httputil.NewClientConn": "net/http/httputil", - "httputil.NewProxyClientConn": "net/http/httputil", - "httputil.NewServerConn": "net/http/httputil", - "httputil.NewSingleHostReverseProxy": "net/http/httputil", - "httputil.ReverseProxy": "net/http/httputil", - "httputil.ServerConn": "net/http/httputil", - "image.Alpha": "image", - "image.Alpha16": "image", - "image.Black": "image", - "image.CMYK": "image", - "image.Config": "image", - "image.Decode": "image", - "image.DecodeConfig": "image", - "image.ErrFormat": "image", - "image.Gray": "image", - "image.Gray16": "image", - "image.Image": "image", - "image.NRGBA": "image", - "image.NRGBA64": "image", - "image.NYCbCrA": "image", - "image.NewAlpha": "image", - "image.NewAlpha16": "image", - "image.NewCMYK": "image", - "image.NewGray": "image", - "image.NewGray16": "image", - "image.NewNRGBA": "image", - "image.NewNRGBA64": "image", - "image.NewNYCbCrA": "image", - "image.NewPaletted": "image", - "image.NewRGBA": "image", - "image.NewRGBA64": "image", - "image.NewUniform": "image", - "image.NewYCbCr": "image", - "image.Opaque": "image", - "image.Paletted": "image", - "image.PalettedImage": "image", - "image.Point": "image", - "image.Pt": "image", - "image.RGBA": "image", - "image.RGBA64": "image", - "image.Rect": "image", - "image.Rectangle": "image", - "image.RegisterFormat": "image", - "image.Transparent": "image", - "image.Uniform": "image", - "image.White": "image", - "image.YCbCr": "image", - "image.YCbCrSubsampleRatio": "image", - "image.YCbCrSubsampleRatio410": "image", - "image.YCbCrSubsampleRatio411": "image", - "image.YCbCrSubsampleRatio420": "image", - "image.YCbCrSubsampleRatio422": "image", - "image.YCbCrSubsampleRatio440": "image", - "image.YCbCrSubsampleRatio444": "image", - "image.ZP": "image", - "image.ZR": "image", - "importer.Default": "go/importer", - "importer.For": "go/importer", - "importer.Lookup": "go/importer", - "io.ByteReader": "io", - "io.ByteScanner": "io", - "io.ByteWriter": "io", - "io.Closer": "io", - "io.Copy": "io", - "io.CopyBuffer": "io", - "io.CopyN": "io", - "io.EOF": "io", - "io.ErrClosedPipe": "io", - "io.ErrNoProgress": "io", - "io.ErrShortBuffer": "io", - "io.ErrShortWrite": "io", - "io.ErrUnexpectedEOF": "io", - "io.LimitReader": "io", - "io.LimitedReader": "io", - "io.MultiReader": "io", - "io.MultiWriter": "io", - "io.NewSectionReader": "io", - "io.Pipe": "io", - "io.PipeReader": "io", - "io.PipeWriter": "io", - "io.ReadAtLeast": "io", - "io.ReadCloser": "io", - "io.ReadFull": "io", - "io.ReadSeeker": "io", - "io.ReadWriteCloser": "io", - "io.ReadWriteSeeker": "io", - "io.ReadWriter": "io", - "io.Reader": "io", - "io.ReaderAt": "io", - "io.ReaderFrom": "io", - "io.RuneReader": "io", - "io.RuneScanner": "io", - "io.SectionReader": "io", - "io.SeekCurrent": "io", - "io.SeekEnd": "io", - "io.SeekStart": "io", - "io.Seeker": "io", - "io.TeeReader": "io", - "io.WriteCloser": "io", - "io.WriteSeeker": "io", - "io.WriteString": "io", - "io.Writer": "io", - "io.WriterAt": "io", - "io.WriterTo": "io", - "iotest.DataErrReader": "testing/iotest", - "iotest.ErrTimeout": "testing/iotest", - "iotest.HalfReader": "testing/iotest", - "iotest.NewReadLogger": "testing/iotest", - "iotest.NewWriteLogger": "testing/iotest", - "iotest.OneByteReader": "testing/iotest", - "iotest.TimeoutReader": "testing/iotest", - "iotest.TruncateWriter": "testing/iotest", - "ioutil.Discard": "io/ioutil", - "ioutil.NopCloser": "io/ioutil", - "ioutil.ReadAll": "io/ioutil", - "ioutil.ReadDir": "io/ioutil", - "ioutil.ReadFile": "io/ioutil", - "ioutil.TempDir": "io/ioutil", - "ioutil.TempFile": "io/ioutil", - "ioutil.WriteFile": "io/ioutil", - "jpeg.Decode": "image/jpeg", - "jpeg.DecodeConfig": "image/jpeg", - "jpeg.DefaultQuality": "image/jpeg", - "jpeg.Encode": "image/jpeg", - "jpeg.FormatError": "image/jpeg", - "jpeg.Options": "image/jpeg", - "jpeg.Reader": "image/jpeg", - "jpeg.UnsupportedError": "image/jpeg", - "json.Compact": "encoding/json", - "json.Decoder": "encoding/json", - "json.Delim": "encoding/json", - "json.Encoder": "encoding/json", - "json.HTMLEscape": "encoding/json", - "json.Indent": "encoding/json", - "json.InvalidUTF8Error": "encoding/json", - "json.InvalidUnmarshalError": "encoding/json", - "json.Marshal": "encoding/json", - "json.MarshalIndent": "encoding/json", - "json.Marshaler": "encoding/json", - "json.MarshalerError": "encoding/json", - "json.NewDecoder": "encoding/json", - "json.NewEncoder": "encoding/json", - "json.Number": "encoding/json", - "json.RawMessage": "encoding/json", - "json.SyntaxError": "encoding/json", - "json.Token": "encoding/json", - "json.Unmarshal": "encoding/json", - "json.UnmarshalFieldError": "encoding/json", - "json.UnmarshalTypeError": "encoding/json", - "json.Unmarshaler": "encoding/json", - "json.UnsupportedTypeError": "encoding/json", - "json.UnsupportedValueError": "encoding/json", - "jsonrpc.Dial": "net/rpc/jsonrpc", - "jsonrpc.NewClient": "net/rpc/jsonrpc", - "jsonrpc.NewClientCodec": "net/rpc/jsonrpc", - "jsonrpc.NewServerCodec": "net/rpc/jsonrpc", - "jsonrpc.ServeConn": "net/rpc/jsonrpc", - "list.Element": "container/list", - "list.List": "container/list", - "list.New": "container/list", - "log.Fatal": "log", - "log.Fatalf": "log", - "log.Fatalln": "log", - "log.Flags": "log", - "log.LUTC": "log", - "log.Ldate": "log", - "log.Llongfile": "log", - "log.Lmicroseconds": "log", - "log.Logger": "log", - "log.Lshortfile": "log", - "log.LstdFlags": "log", - "log.Ltime": "log", - "log.New": "log", - "log.Output": "log", - "log.Panic": "log", - "log.Panicf": "log", - "log.Panicln": "log", - "log.Prefix": "log", - "log.Print": "log", - "log.Printf": "log", - "log.Println": "log", - "log.SetFlags": "log", - "log.SetOutput": "log", - "log.SetPrefix": "log", - "lzw.LSB": "compress/lzw", - "lzw.MSB": "compress/lzw", - "lzw.NewReader": "compress/lzw", - "lzw.NewWriter": "compress/lzw", - "lzw.Order": "compress/lzw", - "macho.Cpu": "debug/macho", - "macho.Cpu386": "debug/macho", - "macho.CpuAmd64": "debug/macho", - "macho.CpuArm": "debug/macho", - "macho.CpuPpc": "debug/macho", - "macho.CpuPpc64": "debug/macho", - "macho.Dylib": "debug/macho", - "macho.DylibCmd": "debug/macho", - "macho.Dysymtab": "debug/macho", - "macho.DysymtabCmd": "debug/macho", - "macho.ErrNotFat": "debug/macho", - "macho.FatArch": "debug/macho", - "macho.FatArchHeader": "debug/macho", - "macho.FatFile": "debug/macho", - "macho.File": "debug/macho", - "macho.FileHeader": "debug/macho", - "macho.FormatError": "debug/macho", - "macho.Load": "debug/macho", - "macho.LoadBytes": "debug/macho", - "macho.LoadCmd": "debug/macho", - "macho.LoadCmdDylib": "debug/macho", - "macho.LoadCmdDylinker": "debug/macho", - "macho.LoadCmdDysymtab": "debug/macho", - "macho.LoadCmdSegment": "debug/macho", - "macho.LoadCmdSegment64": "debug/macho", - "macho.LoadCmdSymtab": "debug/macho", - "macho.LoadCmdThread": "debug/macho", - "macho.LoadCmdUnixThread": "debug/macho", - "macho.Magic32": "debug/macho", - "macho.Magic64": "debug/macho", - "macho.MagicFat": "debug/macho", - "macho.NewFatFile": "debug/macho", - "macho.NewFile": "debug/macho", - "macho.Nlist32": "debug/macho", - "macho.Nlist64": "debug/macho", - "macho.Open": "debug/macho", - "macho.OpenFat": "debug/macho", - "macho.Regs386": "debug/macho", - "macho.RegsAMD64": "debug/macho", - "macho.Section": "debug/macho", - "macho.Section32": "debug/macho", - "macho.Section64": "debug/macho", - "macho.SectionHeader": "debug/macho", - "macho.Segment": "debug/macho", - "macho.Segment32": "debug/macho", - "macho.Segment64": "debug/macho", - "macho.SegmentHeader": "debug/macho", - "macho.Symbol": "debug/macho", - "macho.Symtab": "debug/macho", - "macho.SymtabCmd": "debug/macho", - "macho.Thread": "debug/macho", - "macho.Type": "debug/macho", - "macho.TypeBundle": "debug/macho", - "macho.TypeDylib": "debug/macho", - "macho.TypeExec": "debug/macho", - "macho.TypeObj": "debug/macho", - "mail.Address": "net/mail", - "mail.AddressParser": "net/mail", - "mail.ErrHeaderNotPresent": "net/mail", - "mail.Header": "net/mail", - "mail.Message": "net/mail", - "mail.ParseAddress": "net/mail", - "mail.ParseAddressList": "net/mail", - "mail.ReadMessage": "net/mail", - "math.Abs": "math", - "math.Acos": "math", - "math.Acosh": "math", - "math.Asin": "math", - "math.Asinh": "math", - "math.Atan": "math", - "math.Atan2": "math", - "math.Atanh": "math", - "math.Cbrt": "math", - "math.Ceil": "math", - "math.Copysign": "math", - "math.Cos": "math", - "math.Cosh": "math", - "math.Dim": "math", - "math.E": "math", - "math.Erf": "math", - "math.Erfc": "math", - "math.Exp": "math", - "math.Exp2": "math", - "math.Expm1": "math", - "math.Float32bits": "math", - "math.Float32frombits": "math", - "math.Float64bits": "math", - "math.Float64frombits": "math", - "math.Floor": "math", - "math.Frexp": "math", - "math.Gamma": "math", - "math.Hypot": "math", - "math.Ilogb": "math", - "math.Inf": "math", - "math.IsInf": "math", - "math.IsNaN": "math", - "math.J0": "math", - "math.J1": "math", - "math.Jn": "math", - "math.Ldexp": "math", - "math.Lgamma": "math", - "math.Ln10": "math", - "math.Ln2": "math", - "math.Log": "math", - "math.Log10": "math", - "math.Log10E": "math", - "math.Log1p": "math", - "math.Log2": "math", - "math.Log2E": "math", - "math.Logb": "math", - "math.Max": "math", - "math.MaxFloat32": "math", - "math.MaxFloat64": "math", - "math.MaxInt16": "math", - "math.MaxInt32": "math", - "math.MaxInt64": "math", - "math.MaxInt8": "math", - "math.MaxUint16": "math", - "math.MaxUint32": "math", - "math.MaxUint64": "math", - "math.MaxUint8": "math", - "math.Min": "math", - "math.MinInt16": "math", - "math.MinInt32": "math", - "math.MinInt64": "math", - "math.MinInt8": "math", - "math.Mod": "math", - "math.Modf": "math", - "math.NaN": "math", - "math.Nextafter": "math", - "math.Nextafter32": "math", - "math.Phi": "math", - "math.Pi": "math", - "math.Pow": "math", - "math.Pow10": "math", - "math.Remainder": "math", - "math.Signbit": "math", - "math.Sin": "math", - "math.Sincos": "math", - "math.Sinh": "math", - "math.SmallestNonzeroFloat32": "math", - "math.SmallestNonzeroFloat64": "math", - "math.Sqrt": "math", - "math.Sqrt2": "math", - "math.SqrtE": "math", - "math.SqrtPhi": "math", - "math.SqrtPi": "math", - "math.Tan": "math", - "math.Tanh": "math", - "math.Trunc": "math", - "math.Y0": "math", - "math.Y1": "math", - "math.Yn": "math", - "md5.BlockSize": "crypto/md5", - "md5.New": "crypto/md5", - "md5.Size": "crypto/md5", - "md5.Sum": "crypto/md5", - "mime.AddExtensionType": "mime", - "mime.BEncoding": "mime", - "mime.ExtensionsByType": "mime", - "mime.FormatMediaType": "mime", - "mime.ParseMediaType": "mime", - "mime.QEncoding": "mime", - "mime.TypeByExtension": "mime", - "mime.WordDecoder": "mime", - "mime.WordEncoder": "mime", - "multipart.File": "mime/multipart", - "multipart.FileHeader": "mime/multipart", - "multipart.Form": "mime/multipart", - "multipart.NewReader": "mime/multipart", - "multipart.NewWriter": "mime/multipart", - "multipart.Part": "mime/multipart", - "multipart.Reader": "mime/multipart", - "multipart.Writer": "mime/multipart", - "net.Addr": "net", - "net.AddrError": "net", - "net.CIDRMask": "net", - "net.Conn": "net", - "net.DNSConfigError": "net", - "net.DNSError": "net", - "net.Dial": "net", - "net.DialIP": "net", - "net.DialTCP": "net", - "net.DialTimeout": "net", - "net.DialUDP": "net", - "net.DialUnix": "net", - "net.Dialer": "net", - "net.ErrWriteToConnected": "net", - "net.Error": "net", - "net.FileConn": "net", - "net.FileListener": "net", - "net.FilePacketConn": "net", - "net.FlagBroadcast": "net", - "net.FlagLoopback": "net", - "net.FlagMulticast": "net", - "net.FlagPointToPoint": "net", - "net.FlagUp": "net", - "net.Flags": "net", - "net.HardwareAddr": "net", - "net.IP": "net", - "net.IPAddr": "net", - "net.IPConn": "net", - "net.IPMask": "net", - "net.IPNet": "net", - "net.IPv4": "net", - "net.IPv4Mask": "net", - "net.IPv4allrouter": "net", - "net.IPv4allsys": "net", - "net.IPv4bcast": "net", - "net.IPv4len": "net", - "net.IPv4zero": "net", - "net.IPv6interfacelocalallnodes": "net", - "net.IPv6len": "net", - "net.IPv6linklocalallnodes": "net", - "net.IPv6linklocalallrouters": "net", - "net.IPv6loopback": "net", - "net.IPv6unspecified": "net", - "net.IPv6zero": "net", - "net.Interface": "net", - "net.InterfaceAddrs": "net", - "net.InterfaceByIndex": "net", - "net.InterfaceByName": "net", - "net.Interfaces": "net", - "net.InvalidAddrError": "net", - "net.JoinHostPort": "net", - "net.Listen": "net", - "net.ListenIP": "net", - "net.ListenMulticastUDP": "net", - "net.ListenPacket": "net", - "net.ListenTCP": "net", - "net.ListenUDP": "net", - "net.ListenUnix": "net", - "net.ListenUnixgram": "net", - "net.Listener": "net", - "net.LookupAddr": "net", - "net.LookupCNAME": "net", - "net.LookupHost": "net", - "net.LookupIP": "net", - "net.LookupMX": "net", - "net.LookupNS": "net", - "net.LookupPort": "net", - "net.LookupSRV": "net", - "net.LookupTXT": "net", - "net.MX": "net", - "net.NS": "net", - "net.OpError": "net", - "net.PacketConn": "net", - "net.ParseCIDR": "net", - "net.ParseError": "net", - "net.ParseIP": "net", - "net.ParseMAC": "net", - "net.Pipe": "net", - "net.ResolveIPAddr": "net", - "net.ResolveTCPAddr": "net", - "net.ResolveUDPAddr": "net", - "net.ResolveUnixAddr": "net", - "net.SRV": "net", - "net.SplitHostPort": "net", - "net.TCPAddr": "net", - "net.TCPConn": "net", - "net.TCPListener": "net", - "net.UDPAddr": "net", - "net.UDPConn": "net", - "net.UnixAddr": "net", - "net.UnixConn": "net", - "net.UnixListener": "net", - "net.UnknownNetworkError": "net", - "os.Args": "os", - "os.Chdir": "os", - "os.Chmod": "os", - "os.Chown": "os", - "os.Chtimes": "os", - "os.Clearenv": "os", - "os.Create": "os", - "os.DevNull": "os", - "os.Environ": "os", - "os.ErrExist": "os", - "os.ErrInvalid": "os", - "os.ErrNotExist": "os", - "os.ErrPermission": "os", - "os.Exit": "os", - "os.Expand": "os", - "os.ExpandEnv": "os", - "os.File": "os", - "os.FileInfo": "os", - "os.FileMode": "os", - "os.FindProcess": "os", - "os.Getegid": "os", - "os.Getenv": "os", - "os.Geteuid": "os", - "os.Getgid": "os", - "os.Getgroups": "os", - "os.Getpagesize": "os", - "os.Getpid": "os", - "os.Getppid": "os", - "os.Getuid": "os", - "os.Getwd": "os", - "os.Hostname": "os", - "os.Interrupt": "os", - "os.IsExist": "os", - "os.IsNotExist": "os", - "os.IsPathSeparator": "os", - "os.IsPermission": "os", - "os.Kill": "os", - "os.Lchown": "os", - "os.Link": "os", - "os.LinkError": "os", - "os.LookupEnv": "os", - "os.Lstat": "os", - "os.Mkdir": "os", - "os.MkdirAll": "os", - "os.ModeAppend": "os", - "os.ModeCharDevice": "os", - "os.ModeDevice": "os", - "os.ModeDir": "os", - "os.ModeExclusive": "os", - "os.ModeNamedPipe": "os", - "os.ModePerm": "os", - "os.ModeSetgid": "os", - "os.ModeSetuid": "os", - "os.ModeSocket": "os", - "os.ModeSticky": "os", - "os.ModeSymlink": "os", - "os.ModeTemporary": "os", - "os.ModeType": "os", - "os.NewFile": "os", - "os.NewSyscallError": "os", - "os.O_APPEND": "os", - "os.O_CREATE": "os", - "os.O_EXCL": "os", - "os.O_RDONLY": "os", - "os.O_RDWR": "os", - "os.O_SYNC": "os", - "os.O_TRUNC": "os", - "os.O_WRONLY": "os", - "os.Open": "os", - "os.OpenFile": "os", - "os.PathError": "os", - "os.PathListSeparator": "os", - "os.PathSeparator": "os", - "os.Pipe": "os", - "os.ProcAttr": "os", - "os.Process": "os", - "os.ProcessState": "os", - "os.Readlink": "os", - "os.Remove": "os", - "os.RemoveAll": "os", - "os.Rename": "os", - "os.SEEK_CUR": "os", - "os.SEEK_END": "os", - "os.SEEK_SET": "os", - "os.SameFile": "os", - "os.Setenv": "os", - "os.Signal": "os", - "os.StartProcess": "os", - "os.Stat": "os", - "os.Stderr": "os", - "os.Stdin": "os", - "os.Stdout": "os", - "os.Symlink": "os", - "os.SyscallError": "os", - "os.TempDir": "os", - "os.Truncate": "os", - "os.Unsetenv": "os", - "palette.Plan9": "image/color/palette", - "palette.WebSafe": "image/color/palette", - "parse.ActionNode": "text/template/parse", - "parse.BoolNode": "text/template/parse", - "parse.BranchNode": "text/template/parse", - "parse.ChainNode": "text/template/parse", - "parse.CommandNode": "text/template/parse", - "parse.DotNode": "text/template/parse", - "parse.FieldNode": "text/template/parse", - "parse.IdentifierNode": "text/template/parse", - "parse.IfNode": "text/template/parse", - "parse.IsEmptyTree": "text/template/parse", - "parse.ListNode": "text/template/parse", - "parse.New": "text/template/parse", - "parse.NewIdentifier": "text/template/parse", - "parse.NilNode": "text/template/parse", - "parse.Node": "text/template/parse", - "parse.NodeAction": "text/template/parse", - "parse.NodeBool": "text/template/parse", - "parse.NodeChain": "text/template/parse", - "parse.NodeCommand": "text/template/parse", - "parse.NodeDot": "text/template/parse", - "parse.NodeField": "text/template/parse", - "parse.NodeIdentifier": "text/template/parse", - "parse.NodeIf": "text/template/parse", - "parse.NodeList": "text/template/parse", - "parse.NodeNil": "text/template/parse", - "parse.NodeNumber": "text/template/parse", - "parse.NodePipe": "text/template/parse", - "parse.NodeRange": "text/template/parse", - "parse.NodeString": "text/template/parse", - "parse.NodeTemplate": "text/template/parse", - "parse.NodeText": "text/template/parse", - "parse.NodeType": "text/template/parse", - "parse.NodeVariable": "text/template/parse", - "parse.NodeWith": "text/template/parse", - "parse.NumberNode": "text/template/parse", - "parse.Parse": "text/template/parse", - "parse.PipeNode": "text/template/parse", - "parse.Pos": "text/template/parse", - "parse.RangeNode": "text/template/parse", - "parse.StringNode": "text/template/parse", - "parse.TemplateNode": "text/template/parse", - "parse.TextNode": "text/template/parse", - "parse.Tree": "text/template/parse", - "parse.VariableNode": "text/template/parse", - "parse.WithNode": "text/template/parse", - "parser.AllErrors": "go/parser", - "parser.DeclarationErrors": "go/parser", - "parser.ImportsOnly": "go/parser", - "parser.Mode": "go/parser", - "parser.PackageClauseOnly": "go/parser", - "parser.ParseComments": "go/parser", - "parser.ParseDir": "go/parser", - "parser.ParseExpr": "go/parser", - "parser.ParseExprFrom": "go/parser", - "parser.ParseFile": "go/parser", - "parser.SpuriousErrors": "go/parser", - "parser.Trace": "go/parser", - "path.Base": "path", - "path.Clean": "path", - "path.Dir": "path", - "path.ErrBadPattern": "path", - "path.Ext": "path", - "path.IsAbs": "path", - "path.Join": "path", - "path.Match": "path", - "path.Split": "path", - "pe.COFFSymbol": "debug/pe", - "pe.COFFSymbolSize": "debug/pe", - "pe.DataDirectory": "debug/pe", - "pe.File": "debug/pe", - "pe.FileHeader": "debug/pe", - "pe.FormatError": "debug/pe", - "pe.IMAGE_FILE_MACHINE_AM33": "debug/pe", - "pe.IMAGE_FILE_MACHINE_AMD64": "debug/pe", - "pe.IMAGE_FILE_MACHINE_ARM": "debug/pe", - "pe.IMAGE_FILE_MACHINE_EBC": "debug/pe", - "pe.IMAGE_FILE_MACHINE_I386": "debug/pe", - "pe.IMAGE_FILE_MACHINE_IA64": "debug/pe", - "pe.IMAGE_FILE_MACHINE_M32R": "debug/pe", - "pe.IMAGE_FILE_MACHINE_MIPS16": "debug/pe", - "pe.IMAGE_FILE_MACHINE_MIPSFPU": "debug/pe", - "pe.IMAGE_FILE_MACHINE_MIPSFPU16": "debug/pe", - "pe.IMAGE_FILE_MACHINE_POWERPC": "debug/pe", - "pe.IMAGE_FILE_MACHINE_POWERPCFP": "debug/pe", - "pe.IMAGE_FILE_MACHINE_R4000": "debug/pe", - "pe.IMAGE_FILE_MACHINE_SH3": "debug/pe", - "pe.IMAGE_FILE_MACHINE_SH3DSP": "debug/pe", - "pe.IMAGE_FILE_MACHINE_SH4": "debug/pe", - "pe.IMAGE_FILE_MACHINE_SH5": "debug/pe", - "pe.IMAGE_FILE_MACHINE_THUMB": "debug/pe", - "pe.IMAGE_FILE_MACHINE_UNKNOWN": "debug/pe", - "pe.IMAGE_FILE_MACHINE_WCEMIPSV2": "debug/pe", - "pe.ImportDirectory": "debug/pe", - "pe.NewFile": "debug/pe", - "pe.Open": "debug/pe", - "pe.OptionalHeader32": "debug/pe", - "pe.OptionalHeader64": "debug/pe", - "pe.Section": "debug/pe", - "pe.SectionHeader": "debug/pe", - "pe.SectionHeader32": "debug/pe", - "pe.Symbol": "debug/pe", - "pem.Block": "encoding/pem", - "pem.Decode": "encoding/pem", - "pem.Encode": "encoding/pem", - "pem.EncodeToMemory": "encoding/pem", - "pkix.AlgorithmIdentifier": "crypto/x509/pkix", - "pkix.AttributeTypeAndValue": "crypto/x509/pkix", - "pkix.AttributeTypeAndValueSET": "crypto/x509/pkix", - "pkix.CertificateList": "crypto/x509/pkix", - "pkix.Extension": "crypto/x509/pkix", - "pkix.Name": "crypto/x509/pkix", - "pkix.RDNSequence": "crypto/x509/pkix", - "pkix.RelativeDistinguishedNameSET": "crypto/x509/pkix", - "pkix.RevokedCertificate": "crypto/x509/pkix", - "pkix.TBSCertificateList": "crypto/x509/pkix", - "plan9obj.File": "debug/plan9obj", - "plan9obj.FileHeader": "debug/plan9obj", - "plan9obj.Magic386": "debug/plan9obj", - "plan9obj.Magic64": "debug/plan9obj", - "plan9obj.MagicAMD64": "debug/plan9obj", - "plan9obj.MagicARM": "debug/plan9obj", - "plan9obj.NewFile": "debug/plan9obj", - "plan9obj.Open": "debug/plan9obj", - "plan9obj.Section": "debug/plan9obj", - "plan9obj.SectionHeader": "debug/plan9obj", - "plan9obj.Sym": "debug/plan9obj", - "png.BestCompression": "image/png", - "png.BestSpeed": "image/png", - "png.CompressionLevel": "image/png", - "png.Decode": "image/png", - "png.DecodeConfig": "image/png", - "png.DefaultCompression": "image/png", - "png.Encode": "image/png", - "png.Encoder": "image/png", - "png.FormatError": "image/png", - "png.NoCompression": "image/png", - "png.UnsupportedError": "image/png", - "pprof.Cmdline": "net/http/pprof", - "pprof.Handler": "net/http/pprof", - "pprof.Index": "net/http/pprof", - "pprof.Lookup": "runtime/pprof", - "pprof.NewProfile": "runtime/pprof", - // "pprof.Profile" is ambiguous - "pprof.Profiles": "runtime/pprof", - "pprof.StartCPUProfile": "runtime/pprof", - "pprof.StopCPUProfile": "runtime/pprof", - "pprof.Symbol": "net/http/pprof", - "pprof.Trace": "net/http/pprof", - "pprof.WriteHeapProfile": "runtime/pprof", - "printer.CommentedNode": "go/printer", - "printer.Config": "go/printer", - "printer.Fprint": "go/printer", - "printer.Mode": "go/printer", - "printer.RawFormat": "go/printer", - "printer.SourcePos": "go/printer", - "printer.TabIndent": "go/printer", - "printer.UseSpaces": "go/printer", - "quick.Check": "testing/quick", - "quick.CheckEqual": "testing/quick", - "quick.CheckEqualError": "testing/quick", - "quick.CheckError": "testing/quick", - "quick.Config": "testing/quick", - "quick.Generator": "testing/quick", - "quick.SetupError": "testing/quick", - "quick.Value": "testing/quick", - "quotedprintable.NewReader": "mime/quotedprintable", - "quotedprintable.NewWriter": "mime/quotedprintable", - "quotedprintable.Reader": "mime/quotedprintable", - "quotedprintable.Writer": "mime/quotedprintable", - "rand.ExpFloat64": "math/rand", - "rand.Float32": "math/rand", - "rand.Float64": "math/rand", - // "rand.Int" is ambiguous - "rand.Int31": "math/rand", - "rand.Int31n": "math/rand", - "rand.Int63": "math/rand", - "rand.Int63n": "math/rand", - "rand.Intn": "math/rand", - "rand.New": "math/rand", - "rand.NewSource": "math/rand", - "rand.NewZipf": "math/rand", - "rand.NormFloat64": "math/rand", - "rand.Perm": "math/rand", - "rand.Prime": "crypto/rand", - "rand.Rand": "math/rand", - // "rand.Read" is ambiguous - "rand.Reader": "crypto/rand", - "rand.Seed": "math/rand", - "rand.Source": "math/rand", - "rand.Uint32": "math/rand", - "rand.Zipf": "math/rand", - "rc4.Cipher": "crypto/rc4", - "rc4.KeySizeError": "crypto/rc4", - "rc4.NewCipher": "crypto/rc4", - "reflect.Append": "reflect", - "reflect.AppendSlice": "reflect", - "reflect.Array": "reflect", - "reflect.ArrayOf": "reflect", - "reflect.Bool": "reflect", - "reflect.BothDir": "reflect", - "reflect.Chan": "reflect", - "reflect.ChanDir": "reflect", - "reflect.ChanOf": "reflect", - "reflect.Complex128": "reflect", - "reflect.Complex64": "reflect", - "reflect.Copy": "reflect", - "reflect.DeepEqual": "reflect", - "reflect.Float32": "reflect", - "reflect.Float64": "reflect", - "reflect.Func": "reflect", - "reflect.FuncOf": "reflect", - "reflect.Indirect": "reflect", - "reflect.Int": "reflect", - "reflect.Int16": "reflect", - "reflect.Int32": "reflect", - "reflect.Int64": "reflect", - "reflect.Int8": "reflect", - "reflect.Interface": "reflect", - "reflect.Invalid": "reflect", - "reflect.Kind": "reflect", - "reflect.MakeChan": "reflect", - "reflect.MakeFunc": "reflect", - "reflect.MakeMap": "reflect", - "reflect.MakeSlice": "reflect", - "reflect.Map": "reflect", - "reflect.MapOf": "reflect", - "reflect.Method": "reflect", - "reflect.New": "reflect", - "reflect.NewAt": "reflect", - "reflect.Ptr": "reflect", - "reflect.PtrTo": "reflect", - "reflect.RecvDir": "reflect", - "reflect.Select": "reflect", - "reflect.SelectCase": "reflect", - "reflect.SelectDefault": "reflect", - "reflect.SelectDir": "reflect", - "reflect.SelectRecv": "reflect", - "reflect.SelectSend": "reflect", - "reflect.SendDir": "reflect", - "reflect.Slice": "reflect", - "reflect.SliceHeader": "reflect", - "reflect.SliceOf": "reflect", - "reflect.String": "reflect", - "reflect.StringHeader": "reflect", - "reflect.Struct": "reflect", - "reflect.StructField": "reflect", - "reflect.StructOf": "reflect", - "reflect.StructTag": "reflect", - "reflect.TypeOf": "reflect", - "reflect.Uint": "reflect", - "reflect.Uint16": "reflect", - "reflect.Uint32": "reflect", - "reflect.Uint64": "reflect", - "reflect.Uint8": "reflect", - "reflect.Uintptr": "reflect", - "reflect.UnsafePointer": "reflect", - "reflect.Value": "reflect", - "reflect.ValueError": "reflect", - "reflect.ValueOf": "reflect", - "reflect.Zero": "reflect", - "regexp.Compile": "regexp", - "regexp.CompilePOSIX": "regexp", - "regexp.Match": "regexp", - "regexp.MatchReader": "regexp", - "regexp.MatchString": "regexp", - "regexp.MustCompile": "regexp", - "regexp.MustCompilePOSIX": "regexp", - "regexp.QuoteMeta": "regexp", - "regexp.Regexp": "regexp", - "ring.New": "container/ring", - "ring.Ring": "container/ring", - "rpc.Accept": "net/rpc", - "rpc.Call": "net/rpc", - "rpc.Client": "net/rpc", - "rpc.ClientCodec": "net/rpc", - "rpc.DefaultDebugPath": "net/rpc", - "rpc.DefaultRPCPath": "net/rpc", - "rpc.DefaultServer": "net/rpc", - "rpc.Dial": "net/rpc", - "rpc.DialHTTP": "net/rpc", - "rpc.DialHTTPPath": "net/rpc", - "rpc.ErrShutdown": "net/rpc", - "rpc.HandleHTTP": "net/rpc", - "rpc.NewClient": "net/rpc", - "rpc.NewClientWithCodec": "net/rpc", - "rpc.NewServer": "net/rpc", - "rpc.Register": "net/rpc", - "rpc.RegisterName": "net/rpc", - "rpc.Request": "net/rpc", - "rpc.Response": "net/rpc", - "rpc.ServeCodec": "net/rpc", - "rpc.ServeConn": "net/rpc", - "rpc.ServeRequest": "net/rpc", - "rpc.Server": "net/rpc", - "rpc.ServerCodec": "net/rpc", - "rpc.ServerError": "net/rpc", - "rsa.CRTValue": "crypto/rsa", - "rsa.DecryptOAEP": "crypto/rsa", - "rsa.DecryptPKCS1v15": "crypto/rsa", - "rsa.DecryptPKCS1v15SessionKey": "crypto/rsa", - "rsa.EncryptOAEP": "crypto/rsa", - "rsa.EncryptPKCS1v15": "crypto/rsa", - "rsa.ErrDecryption": "crypto/rsa", - "rsa.ErrMessageTooLong": "crypto/rsa", - "rsa.ErrVerification": "crypto/rsa", - "rsa.GenerateKey": "crypto/rsa", - "rsa.GenerateMultiPrimeKey": "crypto/rsa", - "rsa.OAEPOptions": "crypto/rsa", - "rsa.PKCS1v15DecryptOptions": "crypto/rsa", - "rsa.PSSOptions": "crypto/rsa", - "rsa.PSSSaltLengthAuto": "crypto/rsa", - "rsa.PSSSaltLengthEqualsHash": "crypto/rsa", - "rsa.PrecomputedValues": "crypto/rsa", - "rsa.PrivateKey": "crypto/rsa", - "rsa.PublicKey": "crypto/rsa", - "rsa.SignPKCS1v15": "crypto/rsa", - "rsa.SignPSS": "crypto/rsa", - "rsa.VerifyPKCS1v15": "crypto/rsa", - "rsa.VerifyPSS": "crypto/rsa", - "runtime.BlockProfile": "runtime", - "runtime.BlockProfileRecord": "runtime", - "runtime.Breakpoint": "runtime", - "runtime.CPUProfile": "runtime", - "runtime.Caller": "runtime", - "runtime.Callers": "runtime", - "runtime.CallersFrames": "runtime", - "runtime.Compiler": "runtime", - "runtime.Error": "runtime", - "runtime.Frame": "runtime", - "runtime.Frames": "runtime", - "runtime.Func": "runtime", - "runtime.FuncForPC": "runtime", - "runtime.GC": "runtime", - "runtime.GOARCH": "runtime", - "runtime.GOMAXPROCS": "runtime", - "runtime.GOOS": "runtime", - "runtime.GOROOT": "runtime", - "runtime.Goexit": "runtime", - "runtime.GoroutineProfile": "runtime", - "runtime.Gosched": "runtime", - "runtime.KeepAlive": "runtime", - "runtime.LockOSThread": "runtime", - "runtime.MemProfile": "runtime", - "runtime.MemProfileRate": "runtime", - "runtime.MemProfileRecord": "runtime", - "runtime.MemStats": "runtime", - "runtime.NumCPU": "runtime", - "runtime.NumCgoCall": "runtime", - "runtime.NumGoroutine": "runtime", - "runtime.ReadMemStats": "runtime", - "runtime.ReadTrace": "runtime", - "runtime.SetBlockProfileRate": "runtime", - "runtime.SetCPUProfileRate": "runtime", - "runtime.SetCgoTraceback": "runtime", - "runtime.SetFinalizer": "runtime", - "runtime.Stack": "runtime", - "runtime.StackRecord": "runtime", - "runtime.StartTrace": "runtime", - "runtime.StopTrace": "runtime", - "runtime.ThreadCreateProfile": "runtime", - "runtime.TypeAssertionError": "runtime", - "runtime.UnlockOSThread": "runtime", - "runtime.Version": "runtime", - "scanner.Char": "text/scanner", - "scanner.Comment": "text/scanner", - "scanner.EOF": "text/scanner", - "scanner.Error": "go/scanner", - "scanner.ErrorHandler": "go/scanner", - "scanner.ErrorList": "go/scanner", - "scanner.Float": "text/scanner", - "scanner.GoTokens": "text/scanner", - "scanner.GoWhitespace": "text/scanner", - "scanner.Ident": "text/scanner", - "scanner.Int": "text/scanner", - "scanner.Mode": "go/scanner", - "scanner.Position": "text/scanner", - "scanner.PrintError": "go/scanner", - "scanner.RawString": "text/scanner", - "scanner.ScanChars": "text/scanner", - // "scanner.ScanComments" is ambiguous - "scanner.ScanFloats": "text/scanner", - "scanner.ScanIdents": "text/scanner", - "scanner.ScanInts": "text/scanner", - "scanner.ScanRawStrings": "text/scanner", - "scanner.ScanStrings": "text/scanner", - // "scanner.Scanner" is ambiguous - "scanner.SkipComments": "text/scanner", - "scanner.String": "text/scanner", - "scanner.TokenString": "text/scanner", - "sha1.BlockSize": "crypto/sha1", - "sha1.New": "crypto/sha1", - "sha1.Size": "crypto/sha1", - "sha1.Sum": "crypto/sha1", - "sha256.BlockSize": "crypto/sha256", - "sha256.New": "crypto/sha256", - "sha256.New224": "crypto/sha256", - "sha256.Size": "crypto/sha256", - "sha256.Size224": "crypto/sha256", - "sha256.Sum224": "crypto/sha256", - "sha256.Sum256": "crypto/sha256", - "sha512.BlockSize": "crypto/sha512", - "sha512.New": "crypto/sha512", - "sha512.New384": "crypto/sha512", - "sha512.New512_224": "crypto/sha512", - "sha512.New512_256": "crypto/sha512", - "sha512.Size": "crypto/sha512", - "sha512.Size224": "crypto/sha512", - "sha512.Size256": "crypto/sha512", - "sha512.Size384": "crypto/sha512", - "sha512.Sum384": "crypto/sha512", - "sha512.Sum512": "crypto/sha512", - "sha512.Sum512_224": "crypto/sha512", - "sha512.Sum512_256": "crypto/sha512", - "signal.Ignore": "os/signal", - "signal.Notify": "os/signal", - "signal.Reset": "os/signal", - "signal.Stop": "os/signal", - "smtp.Auth": "net/smtp", - "smtp.CRAMMD5Auth": "net/smtp", - "smtp.Client": "net/smtp", - "smtp.Dial": "net/smtp", - "smtp.NewClient": "net/smtp", - "smtp.PlainAuth": "net/smtp", - "smtp.SendMail": "net/smtp", - "smtp.ServerInfo": "net/smtp", - "sort.Float64Slice": "sort", - "sort.Float64s": "sort", - "sort.Float64sAreSorted": "sort", - "sort.IntSlice": "sort", - "sort.Interface": "sort", - "sort.Ints": "sort", - "sort.IntsAreSorted": "sort", - "sort.IsSorted": "sort", - "sort.Reverse": "sort", - "sort.Search": "sort", - "sort.SearchFloat64s": "sort", - "sort.SearchInts": "sort", - "sort.SearchStrings": "sort", - "sort.Sort": "sort", - "sort.Stable": "sort", - "sort.StringSlice": "sort", - "sort.Strings": "sort", - "sort.StringsAreSorted": "sort", - "sql.DB": "database/sql", - "sql.DBStats": "database/sql", - "sql.Drivers": "database/sql", - "sql.ErrNoRows": "database/sql", - "sql.ErrTxDone": "database/sql", - "sql.NullBool": "database/sql", - "sql.NullFloat64": "database/sql", - "sql.NullInt64": "database/sql", - "sql.NullString": "database/sql", - "sql.Open": "database/sql", - "sql.RawBytes": "database/sql", - "sql.Register": "database/sql", - "sql.Result": "database/sql", - "sql.Row": "database/sql", - "sql.Rows": "database/sql", - "sql.Scanner": "database/sql", - "sql.Stmt": "database/sql", - "sql.Tx": "database/sql", - "strconv.AppendBool": "strconv", - "strconv.AppendFloat": "strconv", - "strconv.AppendInt": "strconv", - "strconv.AppendQuote": "strconv", - "strconv.AppendQuoteRune": "strconv", - "strconv.AppendQuoteRuneToASCII": "strconv", - "strconv.AppendQuoteRuneToGraphic": "strconv", - "strconv.AppendQuoteToASCII": "strconv", - "strconv.AppendQuoteToGraphic": "strconv", - "strconv.AppendUint": "strconv", - "strconv.Atoi": "strconv", - "strconv.CanBackquote": "strconv", - "strconv.ErrRange": "strconv", - "strconv.ErrSyntax": "strconv", - "strconv.FormatBool": "strconv", - "strconv.FormatFloat": "strconv", - "strconv.FormatInt": "strconv", - "strconv.FormatUint": "strconv", - "strconv.IntSize": "strconv", - "strconv.IsGraphic": "strconv", - "strconv.IsPrint": "strconv", - "strconv.Itoa": "strconv", - "strconv.NumError": "strconv", - "strconv.ParseBool": "strconv", - "strconv.ParseFloat": "strconv", - "strconv.ParseInt": "strconv", - "strconv.ParseUint": "strconv", - "strconv.Quote": "strconv", - "strconv.QuoteRune": "strconv", - "strconv.QuoteRuneToASCII": "strconv", - "strconv.QuoteRuneToGraphic": "strconv", - "strconv.QuoteToASCII": "strconv", - "strconv.QuoteToGraphic": "strconv", - "strconv.Unquote": "strconv", - "strconv.UnquoteChar": "strconv", - "strings.Compare": "strings", - "strings.Contains": "strings", - "strings.ContainsAny": "strings", - "strings.ContainsRune": "strings", - "strings.Count": "strings", - "strings.EqualFold": "strings", - "strings.Fields": "strings", - "strings.FieldsFunc": "strings", - "strings.HasPrefix": "strings", - "strings.HasSuffix": "strings", - "strings.Index": "strings", - "strings.IndexAny": "strings", - "strings.IndexByte": "strings", - "strings.IndexFunc": "strings", - "strings.IndexRune": "strings", - "strings.Join": "strings", - "strings.LastIndex": "strings", - "strings.LastIndexAny": "strings", - "strings.LastIndexByte": "strings", - "strings.LastIndexFunc": "strings", - "strings.Map": "strings", - "strings.NewReader": "strings", - "strings.NewReplacer": "strings", - "strings.Reader": "strings", - "strings.Repeat": "strings", - "strings.Replace": "strings", - "strings.Replacer": "strings", - "strings.Split": "strings", - "strings.SplitAfter": "strings", - "strings.SplitAfterN": "strings", - "strings.SplitN": "strings", - "strings.Title": "strings", - "strings.ToLower": "strings", - "strings.ToLowerSpecial": "strings", - "strings.ToTitle": "strings", - "strings.ToTitleSpecial": "strings", - "strings.ToUpper": "strings", - "strings.ToUpperSpecial": "strings", - "strings.Trim": "strings", - "strings.TrimFunc": "strings", - "strings.TrimLeft": "strings", - "strings.TrimLeftFunc": "strings", - "strings.TrimPrefix": "strings", - "strings.TrimRight": "strings", - "strings.TrimRightFunc": "strings", - "strings.TrimSpace": "strings", - "strings.TrimSuffix": "strings", - "subtle.ConstantTimeByteEq": "crypto/subtle", - "subtle.ConstantTimeCompare": "crypto/subtle", - "subtle.ConstantTimeCopy": "crypto/subtle", - "subtle.ConstantTimeEq": "crypto/subtle", - "subtle.ConstantTimeLessOrEq": "crypto/subtle", - "subtle.ConstantTimeSelect": "crypto/subtle", - "suffixarray.Index": "index/suffixarray", - "suffixarray.New": "index/suffixarray", - "sync.Cond": "sync", - "sync.Locker": "sync", - "sync.Mutex": "sync", - "sync.NewCond": "sync", - "sync.Once": "sync", - "sync.Pool": "sync", - "sync.RWMutex": "sync", - "sync.WaitGroup": "sync", - "syntax.ClassNL": "regexp/syntax", - "syntax.Compile": "regexp/syntax", - "syntax.DotNL": "regexp/syntax", - "syntax.EmptyBeginLine": "regexp/syntax", - "syntax.EmptyBeginText": "regexp/syntax", - "syntax.EmptyEndLine": "regexp/syntax", - "syntax.EmptyEndText": "regexp/syntax", - "syntax.EmptyNoWordBoundary": "regexp/syntax", - "syntax.EmptyOp": "regexp/syntax", - "syntax.EmptyOpContext": "regexp/syntax", - "syntax.EmptyWordBoundary": "regexp/syntax", - "syntax.ErrInternalError": "regexp/syntax", - "syntax.ErrInvalidCharClass": "regexp/syntax", - "syntax.ErrInvalidCharRange": "regexp/syntax", - "syntax.ErrInvalidEscape": "regexp/syntax", - "syntax.ErrInvalidNamedCapture": "regexp/syntax", - "syntax.ErrInvalidPerlOp": "regexp/syntax", - "syntax.ErrInvalidRepeatOp": "regexp/syntax", - "syntax.ErrInvalidRepeatSize": "regexp/syntax", - "syntax.ErrInvalidUTF8": "regexp/syntax", - "syntax.ErrMissingBracket": "regexp/syntax", - "syntax.ErrMissingParen": "regexp/syntax", - "syntax.ErrMissingRepeatArgument": "regexp/syntax", - "syntax.ErrTrailingBackslash": "regexp/syntax", - "syntax.ErrUnexpectedParen": "regexp/syntax", - "syntax.Error": "regexp/syntax", - "syntax.ErrorCode": "regexp/syntax", - "syntax.Flags": "regexp/syntax", - "syntax.FoldCase": "regexp/syntax", - "syntax.Inst": "regexp/syntax", - "syntax.InstAlt": "regexp/syntax", - "syntax.InstAltMatch": "regexp/syntax", - "syntax.InstCapture": "regexp/syntax", - "syntax.InstEmptyWidth": "regexp/syntax", - "syntax.InstFail": "regexp/syntax", - "syntax.InstMatch": "regexp/syntax", - "syntax.InstNop": "regexp/syntax", - "syntax.InstOp": "regexp/syntax", - "syntax.InstRune": "regexp/syntax", - "syntax.InstRune1": "regexp/syntax", - "syntax.InstRuneAny": "regexp/syntax", - "syntax.InstRuneAnyNotNL": "regexp/syntax", - "syntax.IsWordChar": "regexp/syntax", - "syntax.Literal": "regexp/syntax", - "syntax.MatchNL": "regexp/syntax", - "syntax.NonGreedy": "regexp/syntax", - "syntax.OneLine": "regexp/syntax", - "syntax.Op": "regexp/syntax", - "syntax.OpAlternate": "regexp/syntax", - "syntax.OpAnyChar": "regexp/syntax", - "syntax.OpAnyCharNotNL": "regexp/syntax", - "syntax.OpBeginLine": "regexp/syntax", - "syntax.OpBeginText": "regexp/syntax", - "syntax.OpCapture": "regexp/syntax", - "syntax.OpCharClass": "regexp/syntax", - "syntax.OpConcat": "regexp/syntax", - "syntax.OpEmptyMatch": "regexp/syntax", - "syntax.OpEndLine": "regexp/syntax", - "syntax.OpEndText": "regexp/syntax", - "syntax.OpLiteral": "regexp/syntax", - "syntax.OpNoMatch": "regexp/syntax", - "syntax.OpNoWordBoundary": "regexp/syntax", - "syntax.OpPlus": "regexp/syntax", - "syntax.OpQuest": "regexp/syntax", - "syntax.OpRepeat": "regexp/syntax", - "syntax.OpStar": "regexp/syntax", - "syntax.OpWordBoundary": "regexp/syntax", - "syntax.POSIX": "regexp/syntax", - "syntax.Parse": "regexp/syntax", - "syntax.Perl": "regexp/syntax", - "syntax.PerlX": "regexp/syntax", - "syntax.Prog": "regexp/syntax", - "syntax.Regexp": "regexp/syntax", - "syntax.Simple": "regexp/syntax", - "syntax.UnicodeGroups": "regexp/syntax", - "syntax.WasDollar": "regexp/syntax", - "syscall.AF_ALG": "syscall", - "syscall.AF_APPLETALK": "syscall", - "syscall.AF_ARP": "syscall", - "syscall.AF_ASH": "syscall", - "syscall.AF_ATM": "syscall", - "syscall.AF_ATMPVC": "syscall", - "syscall.AF_ATMSVC": "syscall", - "syscall.AF_AX25": "syscall", - "syscall.AF_BLUETOOTH": "syscall", - "syscall.AF_BRIDGE": "syscall", - "syscall.AF_CAIF": "syscall", - "syscall.AF_CAN": "syscall", - "syscall.AF_CCITT": "syscall", - "syscall.AF_CHAOS": "syscall", - "syscall.AF_CNT": "syscall", - "syscall.AF_COIP": "syscall", - "syscall.AF_DATAKIT": "syscall", - "syscall.AF_DECnet": "syscall", - "syscall.AF_DLI": "syscall", - "syscall.AF_E164": "syscall", - "syscall.AF_ECMA": "syscall", - "syscall.AF_ECONET": "syscall", - "syscall.AF_ENCAP": "syscall", - "syscall.AF_FILE": "syscall", - "syscall.AF_HYLINK": "syscall", - "syscall.AF_IEEE80211": "syscall", - "syscall.AF_IEEE802154": "syscall", - "syscall.AF_IMPLINK": "syscall", - "syscall.AF_INET": "syscall", - "syscall.AF_INET6": "syscall", - "syscall.AF_INET6_SDP": "syscall", - "syscall.AF_INET_SDP": "syscall", - "syscall.AF_IPX": "syscall", - "syscall.AF_IRDA": "syscall", - "syscall.AF_ISDN": "syscall", - "syscall.AF_ISO": "syscall", - "syscall.AF_IUCV": "syscall", - "syscall.AF_KEY": "syscall", - "syscall.AF_LAT": "syscall", - "syscall.AF_LINK": "syscall", - "syscall.AF_LLC": "syscall", - "syscall.AF_LOCAL": "syscall", - "syscall.AF_MAX": "syscall", - "syscall.AF_MPLS": "syscall", - "syscall.AF_NATM": "syscall", - "syscall.AF_NDRV": "syscall", - "syscall.AF_NETBEUI": "syscall", - "syscall.AF_NETBIOS": "syscall", - "syscall.AF_NETGRAPH": "syscall", - "syscall.AF_NETLINK": "syscall", - "syscall.AF_NETROM": "syscall", - "syscall.AF_NS": "syscall", - "syscall.AF_OROUTE": "syscall", - "syscall.AF_OSI": "syscall", - "syscall.AF_PACKET": "syscall", - "syscall.AF_PHONET": "syscall", - "syscall.AF_PPP": "syscall", - "syscall.AF_PPPOX": "syscall", - "syscall.AF_PUP": "syscall", - "syscall.AF_RDS": "syscall", - "syscall.AF_RESERVED_36": "syscall", - "syscall.AF_ROSE": "syscall", - "syscall.AF_ROUTE": "syscall", - "syscall.AF_RXRPC": "syscall", - "syscall.AF_SCLUSTER": "syscall", - "syscall.AF_SECURITY": "syscall", - "syscall.AF_SIP": "syscall", - "syscall.AF_SLOW": "syscall", - "syscall.AF_SNA": "syscall", - "syscall.AF_SYSTEM": "syscall", - "syscall.AF_TIPC": "syscall", - "syscall.AF_UNIX": "syscall", - "syscall.AF_UNSPEC": "syscall", - "syscall.AF_VENDOR00": "syscall", - "syscall.AF_VENDOR01": "syscall", - "syscall.AF_VENDOR02": "syscall", - "syscall.AF_VENDOR03": "syscall", - "syscall.AF_VENDOR04": "syscall", - "syscall.AF_VENDOR05": "syscall", - "syscall.AF_VENDOR06": "syscall", - "syscall.AF_VENDOR07": "syscall", - "syscall.AF_VENDOR08": "syscall", - "syscall.AF_VENDOR09": "syscall", - "syscall.AF_VENDOR10": "syscall", - "syscall.AF_VENDOR11": "syscall", - "syscall.AF_VENDOR12": "syscall", - "syscall.AF_VENDOR13": "syscall", - "syscall.AF_VENDOR14": "syscall", - "syscall.AF_VENDOR15": "syscall", - "syscall.AF_VENDOR16": "syscall", - "syscall.AF_VENDOR17": "syscall", - "syscall.AF_VENDOR18": "syscall", - "syscall.AF_VENDOR19": "syscall", - "syscall.AF_VENDOR20": "syscall", - "syscall.AF_VENDOR21": "syscall", - "syscall.AF_VENDOR22": "syscall", - "syscall.AF_VENDOR23": "syscall", - "syscall.AF_VENDOR24": "syscall", - "syscall.AF_VENDOR25": "syscall", - "syscall.AF_VENDOR26": "syscall", - "syscall.AF_VENDOR27": "syscall", - "syscall.AF_VENDOR28": "syscall", - "syscall.AF_VENDOR29": "syscall", - "syscall.AF_VENDOR30": "syscall", - "syscall.AF_VENDOR31": "syscall", - "syscall.AF_VENDOR32": "syscall", - "syscall.AF_VENDOR33": "syscall", - "syscall.AF_VENDOR34": "syscall", - "syscall.AF_VENDOR35": "syscall", - "syscall.AF_VENDOR36": "syscall", - "syscall.AF_VENDOR37": "syscall", - "syscall.AF_VENDOR38": "syscall", - "syscall.AF_VENDOR39": "syscall", - "syscall.AF_VENDOR40": "syscall", - "syscall.AF_VENDOR41": "syscall", - "syscall.AF_VENDOR42": "syscall", - "syscall.AF_VENDOR43": "syscall", - "syscall.AF_VENDOR44": "syscall", - "syscall.AF_VENDOR45": "syscall", - "syscall.AF_VENDOR46": "syscall", - "syscall.AF_VENDOR47": "syscall", - "syscall.AF_WANPIPE": "syscall", - "syscall.AF_X25": "syscall", - "syscall.AI_CANONNAME": "syscall", - "syscall.AI_NUMERICHOST": "syscall", - "syscall.AI_PASSIVE": "syscall", - "syscall.APPLICATION_ERROR": "syscall", - "syscall.ARPHRD_ADAPT": "syscall", - "syscall.ARPHRD_APPLETLK": "syscall", - "syscall.ARPHRD_ARCNET": "syscall", - "syscall.ARPHRD_ASH": "syscall", - "syscall.ARPHRD_ATM": "syscall", - "syscall.ARPHRD_AX25": "syscall", - "syscall.ARPHRD_BIF": "syscall", - "syscall.ARPHRD_CHAOS": "syscall", - "syscall.ARPHRD_CISCO": "syscall", - "syscall.ARPHRD_CSLIP": "syscall", - "syscall.ARPHRD_CSLIP6": "syscall", - "syscall.ARPHRD_DDCMP": "syscall", - "syscall.ARPHRD_DLCI": "syscall", - "syscall.ARPHRD_ECONET": "syscall", - "syscall.ARPHRD_EETHER": "syscall", - "syscall.ARPHRD_ETHER": "syscall", - "syscall.ARPHRD_EUI64": "syscall", - "syscall.ARPHRD_FCAL": "syscall", - "syscall.ARPHRD_FCFABRIC": "syscall", - "syscall.ARPHRD_FCPL": "syscall", - "syscall.ARPHRD_FCPP": "syscall", - "syscall.ARPHRD_FDDI": "syscall", - "syscall.ARPHRD_FRAD": "syscall", - "syscall.ARPHRD_FRELAY": "syscall", - "syscall.ARPHRD_HDLC": "syscall", - "syscall.ARPHRD_HIPPI": "syscall", - "syscall.ARPHRD_HWX25": "syscall", - "syscall.ARPHRD_IEEE1394": "syscall", - "syscall.ARPHRD_IEEE802": "syscall", - "syscall.ARPHRD_IEEE80211": "syscall", - "syscall.ARPHRD_IEEE80211_PRISM": "syscall", - "syscall.ARPHRD_IEEE80211_RADIOTAP": "syscall", - "syscall.ARPHRD_IEEE802154": "syscall", - "syscall.ARPHRD_IEEE802154_PHY": "syscall", - "syscall.ARPHRD_IEEE802_TR": "syscall", - "syscall.ARPHRD_INFINIBAND": "syscall", - "syscall.ARPHRD_IPDDP": "syscall", - "syscall.ARPHRD_IPGRE": "syscall", - "syscall.ARPHRD_IRDA": "syscall", - "syscall.ARPHRD_LAPB": "syscall", - "syscall.ARPHRD_LOCALTLK": "syscall", - "syscall.ARPHRD_LOOPBACK": "syscall", - "syscall.ARPHRD_METRICOM": "syscall", - "syscall.ARPHRD_NETROM": "syscall", - "syscall.ARPHRD_NONE": "syscall", - "syscall.ARPHRD_PIMREG": "syscall", - "syscall.ARPHRD_PPP": "syscall", - "syscall.ARPHRD_PRONET": "syscall", - "syscall.ARPHRD_RAWHDLC": "syscall", - "syscall.ARPHRD_ROSE": "syscall", - "syscall.ARPHRD_RSRVD": "syscall", - "syscall.ARPHRD_SIT": "syscall", - "syscall.ARPHRD_SKIP": "syscall", - "syscall.ARPHRD_SLIP": "syscall", - "syscall.ARPHRD_SLIP6": "syscall", - "syscall.ARPHRD_STRIP": "syscall", - "syscall.ARPHRD_TUNNEL": "syscall", - "syscall.ARPHRD_TUNNEL6": "syscall", - "syscall.ARPHRD_VOID": "syscall", - "syscall.ARPHRD_X25": "syscall", - "syscall.AUTHTYPE_CLIENT": "syscall", - "syscall.AUTHTYPE_SERVER": "syscall", - "syscall.Accept": "syscall", - "syscall.Accept4": "syscall", - "syscall.AcceptEx": "syscall", - "syscall.Access": "syscall", - "syscall.Acct": "syscall", - "syscall.AddrinfoW": "syscall", - "syscall.Adjtime": "syscall", - "syscall.Adjtimex": "syscall", - "syscall.AttachLsf": "syscall", - "syscall.B0": "syscall", - "syscall.B1000000": "syscall", - "syscall.B110": "syscall", - "syscall.B115200": "syscall", - "syscall.B1152000": "syscall", - "syscall.B1200": "syscall", - "syscall.B134": "syscall", - "syscall.B14400": "syscall", - "syscall.B150": "syscall", - "syscall.B1500000": "syscall", - "syscall.B1800": "syscall", - "syscall.B19200": "syscall", - "syscall.B200": "syscall", - "syscall.B2000000": "syscall", - "syscall.B230400": "syscall", - "syscall.B2400": "syscall", - "syscall.B2500000": "syscall", - "syscall.B28800": "syscall", - "syscall.B300": "syscall", - "syscall.B3000000": "syscall", - "syscall.B3500000": "syscall", - "syscall.B38400": "syscall", - "syscall.B4000000": "syscall", - "syscall.B460800": "syscall", - "syscall.B4800": "syscall", - "syscall.B50": "syscall", - "syscall.B500000": "syscall", - "syscall.B57600": "syscall", - "syscall.B576000": "syscall", - "syscall.B600": "syscall", - "syscall.B7200": "syscall", - "syscall.B75": "syscall", - "syscall.B76800": "syscall", - "syscall.B921600": "syscall", - "syscall.B9600": "syscall", - "syscall.BASE_PROTOCOL": "syscall", - "syscall.BIOCFEEDBACK": "syscall", - "syscall.BIOCFLUSH": "syscall", - "syscall.BIOCGBLEN": "syscall", - "syscall.BIOCGDIRECTION": "syscall", - "syscall.BIOCGDIRFILT": "syscall", - "syscall.BIOCGDLT": "syscall", - "syscall.BIOCGDLTLIST": "syscall", - "syscall.BIOCGETBUFMODE": "syscall", - "syscall.BIOCGETIF": "syscall", - "syscall.BIOCGETZMAX": "syscall", - "syscall.BIOCGFEEDBACK": "syscall", - "syscall.BIOCGFILDROP": "syscall", - "syscall.BIOCGHDRCMPLT": "syscall", - "syscall.BIOCGRSIG": "syscall", - "syscall.BIOCGRTIMEOUT": "syscall", - "syscall.BIOCGSEESENT": "syscall", - "syscall.BIOCGSTATS": "syscall", - "syscall.BIOCGSTATSOLD": "syscall", - "syscall.BIOCGTSTAMP": "syscall", - "syscall.BIOCIMMEDIATE": "syscall", - "syscall.BIOCLOCK": "syscall", - "syscall.BIOCPROMISC": "syscall", - "syscall.BIOCROTZBUF": "syscall", - "syscall.BIOCSBLEN": "syscall", - "syscall.BIOCSDIRECTION": "syscall", - "syscall.BIOCSDIRFILT": "syscall", - "syscall.BIOCSDLT": "syscall", - "syscall.BIOCSETBUFMODE": "syscall", - "syscall.BIOCSETF": "syscall", - "syscall.BIOCSETFNR": "syscall", - "syscall.BIOCSETIF": "syscall", - "syscall.BIOCSETWF": "syscall", - "syscall.BIOCSETZBUF": "syscall", - "syscall.BIOCSFEEDBACK": "syscall", - "syscall.BIOCSFILDROP": "syscall", - "syscall.BIOCSHDRCMPLT": "syscall", - "syscall.BIOCSRSIG": "syscall", - "syscall.BIOCSRTIMEOUT": "syscall", - "syscall.BIOCSSEESENT": "syscall", - "syscall.BIOCSTCPF": "syscall", - "syscall.BIOCSTSTAMP": "syscall", - "syscall.BIOCSUDPF": "syscall", - "syscall.BIOCVERSION": "syscall", - "syscall.BPF_A": "syscall", - "syscall.BPF_ABS": "syscall", - "syscall.BPF_ADD": "syscall", - "syscall.BPF_ALIGNMENT": "syscall", - "syscall.BPF_ALIGNMENT32": "syscall", - "syscall.BPF_ALU": "syscall", - "syscall.BPF_AND": "syscall", - "syscall.BPF_B": "syscall", - "syscall.BPF_BUFMODE_BUFFER": "syscall", - "syscall.BPF_BUFMODE_ZBUF": "syscall", - "syscall.BPF_DFLTBUFSIZE": "syscall", - "syscall.BPF_DIRECTION_IN": "syscall", - "syscall.BPF_DIRECTION_OUT": "syscall", - "syscall.BPF_DIV": "syscall", - "syscall.BPF_H": "syscall", - "syscall.BPF_IMM": "syscall", - "syscall.BPF_IND": "syscall", - "syscall.BPF_JA": "syscall", - "syscall.BPF_JEQ": "syscall", - "syscall.BPF_JGE": "syscall", - "syscall.BPF_JGT": "syscall", - "syscall.BPF_JMP": "syscall", - "syscall.BPF_JSET": "syscall", - "syscall.BPF_K": "syscall", - "syscall.BPF_LD": "syscall", - "syscall.BPF_LDX": "syscall", - "syscall.BPF_LEN": "syscall", - "syscall.BPF_LSH": "syscall", - "syscall.BPF_MAJOR_VERSION": "syscall", - "syscall.BPF_MAXBUFSIZE": "syscall", - "syscall.BPF_MAXINSNS": "syscall", - "syscall.BPF_MEM": "syscall", - "syscall.BPF_MEMWORDS": "syscall", - "syscall.BPF_MINBUFSIZE": "syscall", - "syscall.BPF_MINOR_VERSION": "syscall", - "syscall.BPF_MISC": "syscall", - "syscall.BPF_MSH": "syscall", - "syscall.BPF_MUL": "syscall", - "syscall.BPF_NEG": "syscall", - "syscall.BPF_OR": "syscall", - "syscall.BPF_RELEASE": "syscall", - "syscall.BPF_RET": "syscall", - "syscall.BPF_RSH": "syscall", - "syscall.BPF_ST": "syscall", - "syscall.BPF_STX": "syscall", - "syscall.BPF_SUB": "syscall", - "syscall.BPF_TAX": "syscall", - "syscall.BPF_TXA": "syscall", - "syscall.BPF_T_BINTIME": "syscall", - "syscall.BPF_T_BINTIME_FAST": "syscall", - "syscall.BPF_T_BINTIME_MONOTONIC": "syscall", - "syscall.BPF_T_BINTIME_MONOTONIC_FAST": "syscall", - "syscall.BPF_T_FAST": "syscall", - "syscall.BPF_T_FLAG_MASK": "syscall", - "syscall.BPF_T_FORMAT_MASK": "syscall", - "syscall.BPF_T_MICROTIME": "syscall", - "syscall.BPF_T_MICROTIME_FAST": "syscall", - "syscall.BPF_T_MICROTIME_MONOTONIC": "syscall", - "syscall.BPF_T_MICROTIME_MONOTONIC_FAST": "syscall", - "syscall.BPF_T_MONOTONIC": "syscall", - "syscall.BPF_T_MONOTONIC_FAST": "syscall", - "syscall.BPF_T_NANOTIME": "syscall", - "syscall.BPF_T_NANOTIME_FAST": "syscall", - "syscall.BPF_T_NANOTIME_MONOTONIC": "syscall", - "syscall.BPF_T_NANOTIME_MONOTONIC_FAST": "syscall", - "syscall.BPF_T_NONE": "syscall", - "syscall.BPF_T_NORMAL": "syscall", - "syscall.BPF_W": "syscall", - "syscall.BPF_X": "syscall", - "syscall.BRKINT": "syscall", - "syscall.Bind": "syscall", - "syscall.BindToDevice": "syscall", - "syscall.BpfBuflen": "syscall", - "syscall.BpfDatalink": "syscall", - "syscall.BpfHdr": "syscall", - "syscall.BpfHeadercmpl": "syscall", - "syscall.BpfInsn": "syscall", - "syscall.BpfInterface": "syscall", - "syscall.BpfJump": "syscall", - "syscall.BpfProgram": "syscall", - "syscall.BpfStat": "syscall", - "syscall.BpfStats": "syscall", - "syscall.BpfStmt": "syscall", - "syscall.BpfTimeout": "syscall", - "syscall.BpfTimeval": "syscall", - "syscall.BpfVersion": "syscall", - "syscall.BpfZbuf": "syscall", - "syscall.BpfZbufHeader": "syscall", - "syscall.ByHandleFileInformation": "syscall", - "syscall.BytePtrFromString": "syscall", - "syscall.ByteSliceFromString": "syscall", - "syscall.CCR0_FLUSH": "syscall", - "syscall.CERT_CHAIN_POLICY_AUTHENTICODE": "syscall", - "syscall.CERT_CHAIN_POLICY_AUTHENTICODE_TS": "syscall", - "syscall.CERT_CHAIN_POLICY_BASE": "syscall", - "syscall.CERT_CHAIN_POLICY_BASIC_CONSTRAINTS": "syscall", - "syscall.CERT_CHAIN_POLICY_EV": "syscall", - "syscall.CERT_CHAIN_POLICY_MICROSOFT_ROOT": "syscall", - "syscall.CERT_CHAIN_POLICY_NT_AUTH": "syscall", - "syscall.CERT_CHAIN_POLICY_SSL": "syscall", - "syscall.CERT_E_CN_NO_MATCH": "syscall", - "syscall.CERT_E_EXPIRED": "syscall", - "syscall.CERT_E_PURPOSE": "syscall", - "syscall.CERT_E_ROLE": "syscall", - "syscall.CERT_E_UNTRUSTEDROOT": "syscall", - "syscall.CERT_STORE_ADD_ALWAYS": "syscall", - "syscall.CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG": "syscall", - "syscall.CERT_STORE_PROV_MEMORY": "syscall", - "syscall.CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT": "syscall", - "syscall.CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT": "syscall", - "syscall.CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT": "syscall", - "syscall.CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT": "syscall", - "syscall.CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT": "syscall", - "syscall.CERT_TRUST_INVALID_BASIC_CONSTRAINTS": "syscall", - "syscall.CERT_TRUST_INVALID_EXTENSION": "syscall", - "syscall.CERT_TRUST_INVALID_NAME_CONSTRAINTS": "syscall", - "syscall.CERT_TRUST_INVALID_POLICY_CONSTRAINTS": "syscall", - "syscall.CERT_TRUST_IS_CYCLIC": "syscall", - "syscall.CERT_TRUST_IS_EXPLICIT_DISTRUST": "syscall", - "syscall.CERT_TRUST_IS_NOT_SIGNATURE_VALID": "syscall", - "syscall.CERT_TRUST_IS_NOT_TIME_VALID": "syscall", - "syscall.CERT_TRUST_IS_NOT_VALID_FOR_USAGE": "syscall", - "syscall.CERT_TRUST_IS_OFFLINE_REVOCATION": "syscall", - "syscall.CERT_TRUST_IS_REVOKED": "syscall", - "syscall.CERT_TRUST_IS_UNTRUSTED_ROOT": "syscall", - "syscall.CERT_TRUST_NO_ERROR": "syscall", - "syscall.CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY": "syscall", - "syscall.CERT_TRUST_REVOCATION_STATUS_UNKNOWN": "syscall", - "syscall.CFLUSH": "syscall", - "syscall.CLOCAL": "syscall", - "syscall.CLONE_CHILD_CLEARTID": "syscall", - "syscall.CLONE_CHILD_SETTID": "syscall", - "syscall.CLONE_CSIGNAL": "syscall", - "syscall.CLONE_DETACHED": "syscall", - "syscall.CLONE_FILES": "syscall", - "syscall.CLONE_FS": "syscall", - "syscall.CLONE_IO": "syscall", - "syscall.CLONE_NEWIPC": "syscall", - "syscall.CLONE_NEWNET": "syscall", - "syscall.CLONE_NEWNS": "syscall", - "syscall.CLONE_NEWPID": "syscall", - "syscall.CLONE_NEWUSER": "syscall", - "syscall.CLONE_NEWUTS": "syscall", - "syscall.CLONE_PARENT": "syscall", - "syscall.CLONE_PARENT_SETTID": "syscall", - "syscall.CLONE_PID": "syscall", - "syscall.CLONE_PTRACE": "syscall", - "syscall.CLONE_SETTLS": "syscall", - "syscall.CLONE_SIGHAND": "syscall", - "syscall.CLONE_SYSVSEM": "syscall", - "syscall.CLONE_THREAD": "syscall", - "syscall.CLONE_UNTRACED": "syscall", - "syscall.CLONE_VFORK": "syscall", - "syscall.CLONE_VM": "syscall", - "syscall.CPUID_CFLUSH": "syscall", - "syscall.CREAD": "syscall", - "syscall.CREATE_ALWAYS": "syscall", - "syscall.CREATE_NEW": "syscall", - "syscall.CREATE_NEW_PROCESS_GROUP": "syscall", - "syscall.CREATE_UNICODE_ENVIRONMENT": "syscall", - "syscall.CRYPT_DEFAULT_CONTAINER_OPTIONAL": "syscall", - "syscall.CRYPT_DELETEKEYSET": "syscall", - "syscall.CRYPT_MACHINE_KEYSET": "syscall", - "syscall.CRYPT_NEWKEYSET": "syscall", - "syscall.CRYPT_SILENT": "syscall", - "syscall.CRYPT_VERIFYCONTEXT": "syscall", - "syscall.CS5": "syscall", - "syscall.CS6": "syscall", - "syscall.CS7": "syscall", - "syscall.CS8": "syscall", - "syscall.CSIZE": "syscall", - "syscall.CSTART": "syscall", - "syscall.CSTATUS": "syscall", - "syscall.CSTOP": "syscall", - "syscall.CSTOPB": "syscall", - "syscall.CSUSP": "syscall", - "syscall.CTL_MAXNAME": "syscall", - "syscall.CTL_NET": "syscall", - "syscall.CTL_QUERY": "syscall", - "syscall.CTRL_BREAK_EVENT": "syscall", - "syscall.CTRL_C_EVENT": "syscall", - "syscall.CancelIo": "syscall", - "syscall.CancelIoEx": "syscall", - "syscall.CertAddCertificateContextToStore": "syscall", - "syscall.CertChainContext": "syscall", - "syscall.CertChainElement": "syscall", - "syscall.CertChainPara": "syscall", - "syscall.CertChainPolicyPara": "syscall", - "syscall.CertChainPolicyStatus": "syscall", - "syscall.CertCloseStore": "syscall", - "syscall.CertContext": "syscall", - "syscall.CertCreateCertificateContext": "syscall", - "syscall.CertEnhKeyUsage": "syscall", - "syscall.CertEnumCertificatesInStore": "syscall", - "syscall.CertFreeCertificateChain": "syscall", - "syscall.CertFreeCertificateContext": "syscall", - "syscall.CertGetCertificateChain": "syscall", - "syscall.CertOpenStore": "syscall", - "syscall.CertOpenSystemStore": "syscall", - "syscall.CertRevocationInfo": "syscall", - "syscall.CertSimpleChain": "syscall", - "syscall.CertTrustStatus": "syscall", - "syscall.CertUsageMatch": "syscall", - "syscall.CertVerifyCertificateChainPolicy": "syscall", - "syscall.Chdir": "syscall", - "syscall.CheckBpfVersion": "syscall", - "syscall.Chflags": "syscall", - "syscall.Chmod": "syscall", - "syscall.Chown": "syscall", - "syscall.Chroot": "syscall", - "syscall.Clearenv": "syscall", - "syscall.Close": "syscall", - "syscall.CloseHandle": "syscall", - "syscall.CloseOnExec": "syscall", - "syscall.Closesocket": "syscall", - "syscall.CmsgLen": "syscall", - "syscall.CmsgSpace": "syscall", - "syscall.Cmsghdr": "syscall", - "syscall.CommandLineToArgv": "syscall", - "syscall.ComputerName": "syscall", - "syscall.Connect": "syscall", - "syscall.ConnectEx": "syscall", - "syscall.ConvertSidToStringSid": "syscall", - "syscall.ConvertStringSidToSid": "syscall", - "syscall.CopySid": "syscall", - "syscall.Creat": "syscall", - "syscall.CreateDirectory": "syscall", - "syscall.CreateFile": "syscall", - "syscall.CreateFileMapping": "syscall", - "syscall.CreateHardLink": "syscall", - "syscall.CreateIoCompletionPort": "syscall", - "syscall.CreatePipe": "syscall", - "syscall.CreateProcess": "syscall", - "syscall.CreateSymbolicLink": "syscall", - "syscall.CreateToolhelp32Snapshot": "syscall", - "syscall.Credential": "syscall", - "syscall.CryptAcquireContext": "syscall", - "syscall.CryptGenRandom": "syscall", - "syscall.CryptReleaseContext": "syscall", - "syscall.DIOCBSFLUSH": "syscall", - "syscall.DIOCOSFPFLUSH": "syscall", - "syscall.DLL": "syscall", - "syscall.DLLError": "syscall", - "syscall.DLT_A429": "syscall", - "syscall.DLT_A653_ICM": "syscall", - "syscall.DLT_AIRONET_HEADER": "syscall", - "syscall.DLT_AOS": "syscall", - "syscall.DLT_APPLE_IP_OVER_IEEE1394": "syscall", - "syscall.DLT_ARCNET": "syscall", - "syscall.DLT_ARCNET_LINUX": "syscall", - "syscall.DLT_ATM_CLIP": "syscall", - "syscall.DLT_ATM_RFC1483": "syscall", - "syscall.DLT_AURORA": "syscall", - "syscall.DLT_AX25": "syscall", - "syscall.DLT_AX25_KISS": "syscall", - "syscall.DLT_BACNET_MS_TP": "syscall", - "syscall.DLT_BLUETOOTH_HCI_H4": "syscall", - "syscall.DLT_BLUETOOTH_HCI_H4_WITH_PHDR": "syscall", - "syscall.DLT_CAN20B": "syscall", - "syscall.DLT_CAN_SOCKETCAN": "syscall", - "syscall.DLT_CHAOS": "syscall", - "syscall.DLT_CHDLC": "syscall", - "syscall.DLT_CISCO_IOS": "syscall", - "syscall.DLT_C_HDLC": "syscall", - "syscall.DLT_C_HDLC_WITH_DIR": "syscall", - "syscall.DLT_DBUS": "syscall", - "syscall.DLT_DECT": "syscall", - "syscall.DLT_DOCSIS": "syscall", - "syscall.DLT_DVB_CI": "syscall", - "syscall.DLT_ECONET": "syscall", - "syscall.DLT_EN10MB": "syscall", - "syscall.DLT_EN3MB": "syscall", - "syscall.DLT_ENC": "syscall", - "syscall.DLT_ERF": "syscall", - "syscall.DLT_ERF_ETH": "syscall", - "syscall.DLT_ERF_POS": "syscall", - "syscall.DLT_FC_2": "syscall", - "syscall.DLT_FC_2_WITH_FRAME_DELIMS": "syscall", - "syscall.DLT_FDDI": "syscall", - "syscall.DLT_FLEXRAY": "syscall", - "syscall.DLT_FRELAY": "syscall", - "syscall.DLT_FRELAY_WITH_DIR": "syscall", - "syscall.DLT_GCOM_SERIAL": "syscall", - "syscall.DLT_GCOM_T1E1": "syscall", - "syscall.DLT_GPF_F": "syscall", - "syscall.DLT_GPF_T": "syscall", - "syscall.DLT_GPRS_LLC": "syscall", - "syscall.DLT_GSMTAP_ABIS": "syscall", - "syscall.DLT_GSMTAP_UM": "syscall", - "syscall.DLT_HDLC": "syscall", - "syscall.DLT_HHDLC": "syscall", - "syscall.DLT_HIPPI": "syscall", - "syscall.DLT_IBM_SN": "syscall", - "syscall.DLT_IBM_SP": "syscall", - "syscall.DLT_IEEE802": "syscall", - "syscall.DLT_IEEE802_11": "syscall", - "syscall.DLT_IEEE802_11_RADIO": "syscall", - "syscall.DLT_IEEE802_11_RADIO_AVS": "syscall", - "syscall.DLT_IEEE802_15_4": "syscall", - "syscall.DLT_IEEE802_15_4_LINUX": "syscall", - "syscall.DLT_IEEE802_15_4_NOFCS": "syscall", - "syscall.DLT_IEEE802_15_4_NONASK_PHY": "syscall", - "syscall.DLT_IEEE802_16_MAC_CPS": "syscall", - "syscall.DLT_IEEE802_16_MAC_CPS_RADIO": "syscall", - "syscall.DLT_IPFILTER": "syscall", - "syscall.DLT_IPMB": "syscall", - "syscall.DLT_IPMB_LINUX": "syscall", - "syscall.DLT_IPNET": "syscall", - "syscall.DLT_IPOIB": "syscall", - "syscall.DLT_IPV4": "syscall", - "syscall.DLT_IPV6": "syscall", - "syscall.DLT_IP_OVER_FC": "syscall", - "syscall.DLT_JUNIPER_ATM1": "syscall", - "syscall.DLT_JUNIPER_ATM2": "syscall", - "syscall.DLT_JUNIPER_ATM_CEMIC": "syscall", - "syscall.DLT_JUNIPER_CHDLC": "syscall", - "syscall.DLT_JUNIPER_ES": "syscall", - "syscall.DLT_JUNIPER_ETHER": "syscall", - "syscall.DLT_JUNIPER_FIBRECHANNEL": "syscall", - "syscall.DLT_JUNIPER_FRELAY": "syscall", - "syscall.DLT_JUNIPER_GGSN": "syscall", - "syscall.DLT_JUNIPER_ISM": "syscall", - "syscall.DLT_JUNIPER_MFR": "syscall", - "syscall.DLT_JUNIPER_MLFR": "syscall", - "syscall.DLT_JUNIPER_MLPPP": "syscall", - "syscall.DLT_JUNIPER_MONITOR": "syscall", - "syscall.DLT_JUNIPER_PIC_PEER": "syscall", - "syscall.DLT_JUNIPER_PPP": "syscall", - "syscall.DLT_JUNIPER_PPPOE": "syscall", - "syscall.DLT_JUNIPER_PPPOE_ATM": "syscall", - "syscall.DLT_JUNIPER_SERVICES": "syscall", - "syscall.DLT_JUNIPER_SRX_E2E": "syscall", - "syscall.DLT_JUNIPER_ST": "syscall", - "syscall.DLT_JUNIPER_VP": "syscall", - "syscall.DLT_JUNIPER_VS": "syscall", - "syscall.DLT_LAPB_WITH_DIR": "syscall", - "syscall.DLT_LAPD": "syscall", - "syscall.DLT_LIN": "syscall", - "syscall.DLT_LINUX_EVDEV": "syscall", - "syscall.DLT_LINUX_IRDA": "syscall", - "syscall.DLT_LINUX_LAPD": "syscall", - "syscall.DLT_LINUX_PPP_WITHDIRECTION": "syscall", - "syscall.DLT_LINUX_SLL": "syscall", - "syscall.DLT_LOOP": "syscall", - "syscall.DLT_LTALK": "syscall", - "syscall.DLT_MATCHING_MAX": "syscall", - "syscall.DLT_MATCHING_MIN": "syscall", - "syscall.DLT_MFR": "syscall", - "syscall.DLT_MOST": "syscall", - "syscall.DLT_MPEG_2_TS": "syscall", - "syscall.DLT_MPLS": "syscall", - "syscall.DLT_MTP2": "syscall", - "syscall.DLT_MTP2_WITH_PHDR": "syscall", - "syscall.DLT_MTP3": "syscall", - "syscall.DLT_MUX27010": "syscall", - "syscall.DLT_NETANALYZER": "syscall", - "syscall.DLT_NETANALYZER_TRANSPARENT": "syscall", - "syscall.DLT_NFC_LLCP": "syscall", - "syscall.DLT_NFLOG": "syscall", - "syscall.DLT_NG40": "syscall", - "syscall.DLT_NULL": "syscall", - "syscall.DLT_PCI_EXP": "syscall", - "syscall.DLT_PFLOG": "syscall", - "syscall.DLT_PFSYNC": "syscall", - "syscall.DLT_PPI": "syscall", - "syscall.DLT_PPP": "syscall", - "syscall.DLT_PPP_BSDOS": "syscall", - "syscall.DLT_PPP_ETHER": "syscall", - "syscall.DLT_PPP_PPPD": "syscall", - "syscall.DLT_PPP_SERIAL": "syscall", - "syscall.DLT_PPP_WITH_DIR": "syscall", - "syscall.DLT_PPP_WITH_DIRECTION": "syscall", - "syscall.DLT_PRISM_HEADER": "syscall", - "syscall.DLT_PRONET": "syscall", - "syscall.DLT_RAIF1": "syscall", - "syscall.DLT_RAW": "syscall", - "syscall.DLT_RAWAF_MASK": "syscall", - "syscall.DLT_RIO": "syscall", - "syscall.DLT_SCCP": "syscall", - "syscall.DLT_SITA": "syscall", - "syscall.DLT_SLIP": "syscall", - "syscall.DLT_SLIP_BSDOS": "syscall", - "syscall.DLT_STANAG_5066_D_PDU": "syscall", - "syscall.DLT_SUNATM": "syscall", - "syscall.DLT_SYMANTEC_FIREWALL": "syscall", - "syscall.DLT_TZSP": "syscall", - "syscall.DLT_USB": "syscall", - "syscall.DLT_USB_LINUX": "syscall", - "syscall.DLT_USB_LINUX_MMAPPED": "syscall", - "syscall.DLT_USER0": "syscall", - "syscall.DLT_USER1": "syscall", - "syscall.DLT_USER10": "syscall", - "syscall.DLT_USER11": "syscall", - "syscall.DLT_USER12": "syscall", - "syscall.DLT_USER13": "syscall", - "syscall.DLT_USER14": "syscall", - "syscall.DLT_USER15": "syscall", - "syscall.DLT_USER2": "syscall", - "syscall.DLT_USER3": "syscall", - "syscall.DLT_USER4": "syscall", - "syscall.DLT_USER5": "syscall", - "syscall.DLT_USER6": "syscall", - "syscall.DLT_USER7": "syscall", - "syscall.DLT_USER8": "syscall", - "syscall.DLT_USER9": "syscall", - "syscall.DLT_WIHART": "syscall", - "syscall.DLT_X2E_SERIAL": "syscall", - "syscall.DLT_X2E_XORAYA": "syscall", - "syscall.DNSMXData": "syscall", - "syscall.DNSPTRData": "syscall", - "syscall.DNSRecord": "syscall", - "syscall.DNSSRVData": "syscall", - "syscall.DNSTXTData": "syscall", - "syscall.DNS_INFO_NO_RECORDS": "syscall", - "syscall.DNS_TYPE_A": "syscall", - "syscall.DNS_TYPE_A6": "syscall", - "syscall.DNS_TYPE_AAAA": "syscall", - "syscall.DNS_TYPE_ADDRS": "syscall", - "syscall.DNS_TYPE_AFSDB": "syscall", - "syscall.DNS_TYPE_ALL": "syscall", - "syscall.DNS_TYPE_ANY": "syscall", - "syscall.DNS_TYPE_ATMA": "syscall", - "syscall.DNS_TYPE_AXFR": "syscall", - "syscall.DNS_TYPE_CERT": "syscall", - "syscall.DNS_TYPE_CNAME": "syscall", - "syscall.DNS_TYPE_DHCID": "syscall", - "syscall.DNS_TYPE_DNAME": "syscall", - "syscall.DNS_TYPE_DNSKEY": "syscall", - "syscall.DNS_TYPE_DS": "syscall", - "syscall.DNS_TYPE_EID": "syscall", - "syscall.DNS_TYPE_GID": "syscall", - "syscall.DNS_TYPE_GPOS": "syscall", - "syscall.DNS_TYPE_HINFO": "syscall", - "syscall.DNS_TYPE_ISDN": "syscall", - "syscall.DNS_TYPE_IXFR": "syscall", - "syscall.DNS_TYPE_KEY": "syscall", - "syscall.DNS_TYPE_KX": "syscall", - "syscall.DNS_TYPE_LOC": "syscall", - "syscall.DNS_TYPE_MAILA": "syscall", - "syscall.DNS_TYPE_MAILB": "syscall", - "syscall.DNS_TYPE_MB": "syscall", - "syscall.DNS_TYPE_MD": "syscall", - "syscall.DNS_TYPE_MF": "syscall", - "syscall.DNS_TYPE_MG": "syscall", - "syscall.DNS_TYPE_MINFO": "syscall", - "syscall.DNS_TYPE_MR": "syscall", - "syscall.DNS_TYPE_MX": "syscall", - "syscall.DNS_TYPE_NAPTR": "syscall", - "syscall.DNS_TYPE_NBSTAT": "syscall", - "syscall.DNS_TYPE_NIMLOC": "syscall", - "syscall.DNS_TYPE_NS": "syscall", - "syscall.DNS_TYPE_NSAP": "syscall", - "syscall.DNS_TYPE_NSAPPTR": "syscall", - "syscall.DNS_TYPE_NSEC": "syscall", - "syscall.DNS_TYPE_NULL": "syscall", - "syscall.DNS_TYPE_NXT": "syscall", - "syscall.DNS_TYPE_OPT": "syscall", - "syscall.DNS_TYPE_PTR": "syscall", - "syscall.DNS_TYPE_PX": "syscall", - "syscall.DNS_TYPE_RP": "syscall", - "syscall.DNS_TYPE_RRSIG": "syscall", - "syscall.DNS_TYPE_RT": "syscall", - "syscall.DNS_TYPE_SIG": "syscall", - "syscall.DNS_TYPE_SINK": "syscall", - "syscall.DNS_TYPE_SOA": "syscall", - "syscall.DNS_TYPE_SRV": "syscall", - "syscall.DNS_TYPE_TEXT": "syscall", - "syscall.DNS_TYPE_TKEY": "syscall", - "syscall.DNS_TYPE_TSIG": "syscall", - "syscall.DNS_TYPE_UID": "syscall", - "syscall.DNS_TYPE_UINFO": "syscall", - "syscall.DNS_TYPE_UNSPEC": "syscall", - "syscall.DNS_TYPE_WINS": "syscall", - "syscall.DNS_TYPE_WINSR": "syscall", - "syscall.DNS_TYPE_WKS": "syscall", - "syscall.DNS_TYPE_X25": "syscall", - "syscall.DT_BLK": "syscall", - "syscall.DT_CHR": "syscall", - "syscall.DT_DIR": "syscall", - "syscall.DT_FIFO": "syscall", - "syscall.DT_LNK": "syscall", - "syscall.DT_REG": "syscall", - "syscall.DT_SOCK": "syscall", - "syscall.DT_UNKNOWN": "syscall", - "syscall.DT_WHT": "syscall", - "syscall.DUPLICATE_CLOSE_SOURCE": "syscall", - "syscall.DUPLICATE_SAME_ACCESS": "syscall", - "syscall.DeleteFile": "syscall", - "syscall.DetachLsf": "syscall", - "syscall.DeviceIoControl": "syscall", - "syscall.Dirent": "syscall", - "syscall.DnsNameCompare": "syscall", - "syscall.DnsQuery": "syscall", - "syscall.DnsRecordListFree": "syscall", - "syscall.DnsSectionAdditional": "syscall", - "syscall.DnsSectionAnswer": "syscall", - "syscall.DnsSectionAuthority": "syscall", - "syscall.DnsSectionQuestion": "syscall", - "syscall.Dup": "syscall", - "syscall.Dup2": "syscall", - "syscall.Dup3": "syscall", - "syscall.DuplicateHandle": "syscall", - "syscall.E2BIG": "syscall", - "syscall.EACCES": "syscall", - "syscall.EADDRINUSE": "syscall", - "syscall.EADDRNOTAVAIL": "syscall", - "syscall.EADV": "syscall", - "syscall.EAFNOSUPPORT": "syscall", - "syscall.EAGAIN": "syscall", - "syscall.EALREADY": "syscall", - "syscall.EAUTH": "syscall", - "syscall.EBADARCH": "syscall", - "syscall.EBADE": "syscall", - "syscall.EBADEXEC": "syscall", - "syscall.EBADF": "syscall", - "syscall.EBADFD": "syscall", - "syscall.EBADMACHO": "syscall", - "syscall.EBADMSG": "syscall", - "syscall.EBADR": "syscall", - "syscall.EBADRPC": "syscall", - "syscall.EBADRQC": "syscall", - "syscall.EBADSLT": "syscall", - "syscall.EBFONT": "syscall", - "syscall.EBUSY": "syscall", - "syscall.ECANCELED": "syscall", - "syscall.ECAPMODE": "syscall", - "syscall.ECHILD": "syscall", - "syscall.ECHO": "syscall", - "syscall.ECHOCTL": "syscall", - "syscall.ECHOE": "syscall", - "syscall.ECHOK": "syscall", - "syscall.ECHOKE": "syscall", - "syscall.ECHONL": "syscall", - "syscall.ECHOPRT": "syscall", - "syscall.ECHRNG": "syscall", - "syscall.ECOMM": "syscall", - "syscall.ECONNABORTED": "syscall", - "syscall.ECONNREFUSED": "syscall", - "syscall.ECONNRESET": "syscall", - "syscall.EDEADLK": "syscall", - "syscall.EDEADLOCK": "syscall", - "syscall.EDESTADDRREQ": "syscall", - "syscall.EDEVERR": "syscall", - "syscall.EDOM": "syscall", - "syscall.EDOOFUS": "syscall", - "syscall.EDOTDOT": "syscall", - "syscall.EDQUOT": "syscall", - "syscall.EEXIST": "syscall", - "syscall.EFAULT": "syscall", - "syscall.EFBIG": "syscall", - "syscall.EFER_LMA": "syscall", - "syscall.EFER_LME": "syscall", - "syscall.EFER_NXE": "syscall", - "syscall.EFER_SCE": "syscall", - "syscall.EFTYPE": "syscall", - "syscall.EHOSTDOWN": "syscall", - "syscall.EHOSTUNREACH": "syscall", - "syscall.EHWPOISON": "syscall", - "syscall.EIDRM": "syscall", - "syscall.EILSEQ": "syscall", - "syscall.EINPROGRESS": "syscall", - "syscall.EINTR": "syscall", - "syscall.EINVAL": "syscall", - "syscall.EIO": "syscall", - "syscall.EIPSEC": "syscall", - "syscall.EISCONN": "syscall", - "syscall.EISDIR": "syscall", - "syscall.EISNAM": "syscall", - "syscall.EKEYEXPIRED": "syscall", - "syscall.EKEYREJECTED": "syscall", - "syscall.EKEYREVOKED": "syscall", - "syscall.EL2HLT": "syscall", - "syscall.EL2NSYNC": "syscall", - "syscall.EL3HLT": "syscall", - "syscall.EL3RST": "syscall", - "syscall.ELAST": "syscall", - "syscall.ELF_NGREG": "syscall", - "syscall.ELF_PRARGSZ": "syscall", - "syscall.ELIBACC": "syscall", - "syscall.ELIBBAD": "syscall", - "syscall.ELIBEXEC": "syscall", - "syscall.ELIBMAX": "syscall", - "syscall.ELIBSCN": "syscall", - "syscall.ELNRNG": "syscall", - "syscall.ELOOP": "syscall", - "syscall.EMEDIUMTYPE": "syscall", - "syscall.EMFILE": "syscall", - "syscall.EMLINK": "syscall", - "syscall.EMSGSIZE": "syscall", - "syscall.EMT_TAGOVF": "syscall", - "syscall.EMULTIHOP": "syscall", - "syscall.EMUL_ENABLED": "syscall", - "syscall.EMUL_LINUX": "syscall", - "syscall.EMUL_LINUX32": "syscall", - "syscall.EMUL_MAXID": "syscall", - "syscall.EMUL_NATIVE": "syscall", - "syscall.ENAMETOOLONG": "syscall", - "syscall.ENAVAIL": "syscall", - "syscall.ENDRUNDISC": "syscall", - "syscall.ENEEDAUTH": "syscall", - "syscall.ENETDOWN": "syscall", - "syscall.ENETRESET": "syscall", - "syscall.ENETUNREACH": "syscall", - "syscall.ENFILE": "syscall", - "syscall.ENOANO": "syscall", - "syscall.ENOATTR": "syscall", - "syscall.ENOBUFS": "syscall", - "syscall.ENOCSI": "syscall", - "syscall.ENODATA": "syscall", - "syscall.ENODEV": "syscall", - "syscall.ENOENT": "syscall", - "syscall.ENOEXEC": "syscall", - "syscall.ENOKEY": "syscall", - "syscall.ENOLCK": "syscall", - "syscall.ENOLINK": "syscall", - "syscall.ENOMEDIUM": "syscall", - "syscall.ENOMEM": "syscall", - "syscall.ENOMSG": "syscall", - "syscall.ENONET": "syscall", - "syscall.ENOPKG": "syscall", - "syscall.ENOPOLICY": "syscall", - "syscall.ENOPROTOOPT": "syscall", - "syscall.ENOSPC": "syscall", - "syscall.ENOSR": "syscall", - "syscall.ENOSTR": "syscall", - "syscall.ENOSYS": "syscall", - "syscall.ENOTBLK": "syscall", - "syscall.ENOTCAPABLE": "syscall", - "syscall.ENOTCONN": "syscall", - "syscall.ENOTDIR": "syscall", - "syscall.ENOTEMPTY": "syscall", - "syscall.ENOTNAM": "syscall", - "syscall.ENOTRECOVERABLE": "syscall", - "syscall.ENOTSOCK": "syscall", - "syscall.ENOTSUP": "syscall", - "syscall.ENOTTY": "syscall", - "syscall.ENOTUNIQ": "syscall", - "syscall.ENXIO": "syscall", - "syscall.EN_SW_CTL_INF": "syscall", - "syscall.EN_SW_CTL_PREC": "syscall", - "syscall.EN_SW_CTL_ROUND": "syscall", - "syscall.EN_SW_DATACHAIN": "syscall", - "syscall.EN_SW_DENORM": "syscall", - "syscall.EN_SW_INVOP": "syscall", - "syscall.EN_SW_OVERFLOW": "syscall", - "syscall.EN_SW_PRECLOSS": "syscall", - "syscall.EN_SW_UNDERFLOW": "syscall", - "syscall.EN_SW_ZERODIV": "syscall", - "syscall.EOPNOTSUPP": "syscall", - "syscall.EOVERFLOW": "syscall", - "syscall.EOWNERDEAD": "syscall", - "syscall.EPERM": "syscall", - "syscall.EPFNOSUPPORT": "syscall", - "syscall.EPIPE": "syscall", - "syscall.EPOLLERR": "syscall", - "syscall.EPOLLET": "syscall", - "syscall.EPOLLHUP": "syscall", - "syscall.EPOLLIN": "syscall", - "syscall.EPOLLMSG": "syscall", - "syscall.EPOLLONESHOT": "syscall", - "syscall.EPOLLOUT": "syscall", - "syscall.EPOLLPRI": "syscall", - "syscall.EPOLLRDBAND": "syscall", - "syscall.EPOLLRDHUP": "syscall", - "syscall.EPOLLRDNORM": "syscall", - "syscall.EPOLLWRBAND": "syscall", - "syscall.EPOLLWRNORM": "syscall", - "syscall.EPOLL_CLOEXEC": "syscall", - "syscall.EPOLL_CTL_ADD": "syscall", - "syscall.EPOLL_CTL_DEL": "syscall", - "syscall.EPOLL_CTL_MOD": "syscall", - "syscall.EPOLL_NONBLOCK": "syscall", - "syscall.EPROCLIM": "syscall", - "syscall.EPROCUNAVAIL": "syscall", - "syscall.EPROGMISMATCH": "syscall", - "syscall.EPROGUNAVAIL": "syscall", - "syscall.EPROTO": "syscall", - "syscall.EPROTONOSUPPORT": "syscall", - "syscall.EPROTOTYPE": "syscall", - "syscall.EPWROFF": "syscall", - "syscall.ERANGE": "syscall", - "syscall.EREMCHG": "syscall", - "syscall.EREMOTE": "syscall", - "syscall.EREMOTEIO": "syscall", - "syscall.ERESTART": "syscall", - "syscall.ERFKILL": "syscall", - "syscall.EROFS": "syscall", - "syscall.ERPCMISMATCH": "syscall", - "syscall.ERROR_ACCESS_DENIED": "syscall", - "syscall.ERROR_ALREADY_EXISTS": "syscall", - "syscall.ERROR_BROKEN_PIPE": "syscall", - "syscall.ERROR_BUFFER_OVERFLOW": "syscall", - "syscall.ERROR_ENVVAR_NOT_FOUND": "syscall", - "syscall.ERROR_FILE_EXISTS": "syscall", - "syscall.ERROR_FILE_NOT_FOUND": "syscall", - "syscall.ERROR_HANDLE_EOF": "syscall", - "syscall.ERROR_INSUFFICIENT_BUFFER": "syscall", - "syscall.ERROR_IO_PENDING": "syscall", - "syscall.ERROR_MOD_NOT_FOUND": "syscall", - "syscall.ERROR_MORE_DATA": "syscall", - "syscall.ERROR_NETNAME_DELETED": "syscall", - "syscall.ERROR_NOT_FOUND": "syscall", - "syscall.ERROR_NO_MORE_FILES": "syscall", - "syscall.ERROR_OPERATION_ABORTED": "syscall", - "syscall.ERROR_PATH_NOT_FOUND": "syscall", - "syscall.ERROR_PRIVILEGE_NOT_HELD": "syscall", - "syscall.ERROR_PROC_NOT_FOUND": "syscall", - "syscall.ESHLIBVERS": "syscall", - "syscall.ESHUTDOWN": "syscall", - "syscall.ESOCKTNOSUPPORT": "syscall", - "syscall.ESPIPE": "syscall", - "syscall.ESRCH": "syscall", - "syscall.ESRMNT": "syscall", - "syscall.ESTALE": "syscall", - "syscall.ESTRPIPE": "syscall", - "syscall.ETHERCAP_JUMBO_MTU": "syscall", - "syscall.ETHERCAP_VLAN_HWTAGGING": "syscall", - "syscall.ETHERCAP_VLAN_MTU": "syscall", - "syscall.ETHERMIN": "syscall", - "syscall.ETHERMTU": "syscall", - "syscall.ETHERMTU_JUMBO": "syscall", - "syscall.ETHERTYPE_8023": "syscall", - "syscall.ETHERTYPE_AARP": "syscall", - "syscall.ETHERTYPE_ACCTON": "syscall", - "syscall.ETHERTYPE_AEONIC": "syscall", - "syscall.ETHERTYPE_ALPHA": "syscall", - "syscall.ETHERTYPE_AMBER": "syscall", - "syscall.ETHERTYPE_AMOEBA": "syscall", - "syscall.ETHERTYPE_AOE": "syscall", - "syscall.ETHERTYPE_APOLLO": "syscall", - "syscall.ETHERTYPE_APOLLODOMAIN": "syscall", - "syscall.ETHERTYPE_APPLETALK": "syscall", - "syscall.ETHERTYPE_APPLITEK": "syscall", - "syscall.ETHERTYPE_ARGONAUT": "syscall", - "syscall.ETHERTYPE_ARP": "syscall", - "syscall.ETHERTYPE_AT": "syscall", - "syscall.ETHERTYPE_ATALK": "syscall", - "syscall.ETHERTYPE_ATOMIC": "syscall", - "syscall.ETHERTYPE_ATT": "syscall", - "syscall.ETHERTYPE_ATTSTANFORD": "syscall", - "syscall.ETHERTYPE_AUTOPHON": "syscall", - "syscall.ETHERTYPE_AXIS": "syscall", - "syscall.ETHERTYPE_BCLOOP": "syscall", - "syscall.ETHERTYPE_BOFL": "syscall", - "syscall.ETHERTYPE_CABLETRON": "syscall", - "syscall.ETHERTYPE_CHAOS": "syscall", - "syscall.ETHERTYPE_COMDESIGN": "syscall", - "syscall.ETHERTYPE_COMPUGRAPHIC": "syscall", - "syscall.ETHERTYPE_COUNTERPOINT": "syscall", - "syscall.ETHERTYPE_CRONUS": "syscall", - "syscall.ETHERTYPE_CRONUSVLN": "syscall", - "syscall.ETHERTYPE_DCA": "syscall", - "syscall.ETHERTYPE_DDE": "syscall", - "syscall.ETHERTYPE_DEBNI": "syscall", - "syscall.ETHERTYPE_DECAM": "syscall", - "syscall.ETHERTYPE_DECCUST": "syscall", - "syscall.ETHERTYPE_DECDIAG": "syscall", - "syscall.ETHERTYPE_DECDNS": "syscall", - "syscall.ETHERTYPE_DECDTS": "syscall", - "syscall.ETHERTYPE_DECEXPER": "syscall", - "syscall.ETHERTYPE_DECLAST": "syscall", - "syscall.ETHERTYPE_DECLTM": "syscall", - "syscall.ETHERTYPE_DECMUMPS": "syscall", - "syscall.ETHERTYPE_DECNETBIOS": "syscall", - "syscall.ETHERTYPE_DELTACON": "syscall", - "syscall.ETHERTYPE_DIDDLE": "syscall", - "syscall.ETHERTYPE_DLOG1": "syscall", - "syscall.ETHERTYPE_DLOG2": "syscall", - "syscall.ETHERTYPE_DN": "syscall", - "syscall.ETHERTYPE_DOGFIGHT": "syscall", - "syscall.ETHERTYPE_DSMD": "syscall", - "syscall.ETHERTYPE_ECMA": "syscall", - "syscall.ETHERTYPE_ENCRYPT": "syscall", - "syscall.ETHERTYPE_ES": "syscall", - "syscall.ETHERTYPE_EXCELAN": "syscall", - "syscall.ETHERTYPE_EXPERDATA": "syscall", - "syscall.ETHERTYPE_FLIP": "syscall", - "syscall.ETHERTYPE_FLOWCONTROL": "syscall", - "syscall.ETHERTYPE_FRARP": "syscall", - "syscall.ETHERTYPE_GENDYN": "syscall", - "syscall.ETHERTYPE_HAYES": "syscall", - "syscall.ETHERTYPE_HIPPI_FP": "syscall", - "syscall.ETHERTYPE_HITACHI": "syscall", - "syscall.ETHERTYPE_HP": "syscall", - "syscall.ETHERTYPE_IEEEPUP": "syscall", - "syscall.ETHERTYPE_IEEEPUPAT": "syscall", - "syscall.ETHERTYPE_IMLBL": "syscall", - "syscall.ETHERTYPE_IMLBLDIAG": "syscall", - "syscall.ETHERTYPE_IP": "syscall", - "syscall.ETHERTYPE_IPAS": "syscall", - "syscall.ETHERTYPE_IPV6": "syscall", - "syscall.ETHERTYPE_IPX": "syscall", - "syscall.ETHERTYPE_IPXNEW": "syscall", - "syscall.ETHERTYPE_KALPANA": "syscall", - "syscall.ETHERTYPE_LANBRIDGE": "syscall", - "syscall.ETHERTYPE_LANPROBE": "syscall", - "syscall.ETHERTYPE_LAT": "syscall", - "syscall.ETHERTYPE_LBACK": "syscall", - "syscall.ETHERTYPE_LITTLE": "syscall", - "syscall.ETHERTYPE_LLDP": "syscall", - "syscall.ETHERTYPE_LOGICRAFT": "syscall", - "syscall.ETHERTYPE_LOOPBACK": "syscall", - "syscall.ETHERTYPE_MATRA": "syscall", - "syscall.ETHERTYPE_MAX": "syscall", - "syscall.ETHERTYPE_MERIT": "syscall", - "syscall.ETHERTYPE_MICP": "syscall", - "syscall.ETHERTYPE_MOPDL": "syscall", - "syscall.ETHERTYPE_MOPRC": "syscall", - "syscall.ETHERTYPE_MOTOROLA": "syscall", - "syscall.ETHERTYPE_MPLS": "syscall", - "syscall.ETHERTYPE_MPLS_MCAST": "syscall", - "syscall.ETHERTYPE_MUMPS": "syscall", - "syscall.ETHERTYPE_NBPCC": "syscall", - "syscall.ETHERTYPE_NBPCLAIM": "syscall", - "syscall.ETHERTYPE_NBPCLREQ": "syscall", - "syscall.ETHERTYPE_NBPCLRSP": "syscall", - "syscall.ETHERTYPE_NBPCREQ": "syscall", - "syscall.ETHERTYPE_NBPCRSP": "syscall", - "syscall.ETHERTYPE_NBPDG": "syscall", - "syscall.ETHERTYPE_NBPDGB": "syscall", - "syscall.ETHERTYPE_NBPDLTE": "syscall", - "syscall.ETHERTYPE_NBPRAR": "syscall", - "syscall.ETHERTYPE_NBPRAS": "syscall", - "syscall.ETHERTYPE_NBPRST": "syscall", - "syscall.ETHERTYPE_NBPSCD": "syscall", - "syscall.ETHERTYPE_NBPVCD": "syscall", - "syscall.ETHERTYPE_NBS": "syscall", - "syscall.ETHERTYPE_NCD": "syscall", - "syscall.ETHERTYPE_NESTAR": "syscall", - "syscall.ETHERTYPE_NETBEUI": "syscall", - "syscall.ETHERTYPE_NOVELL": "syscall", - "syscall.ETHERTYPE_NS": "syscall", - "syscall.ETHERTYPE_NSAT": "syscall", - "syscall.ETHERTYPE_NSCOMPAT": "syscall", - "syscall.ETHERTYPE_NTRAILER": "syscall", - "syscall.ETHERTYPE_OS9": "syscall", - "syscall.ETHERTYPE_OS9NET": "syscall", - "syscall.ETHERTYPE_PACER": "syscall", - "syscall.ETHERTYPE_PAE": "syscall", - "syscall.ETHERTYPE_PCS": "syscall", - "syscall.ETHERTYPE_PLANNING": "syscall", - "syscall.ETHERTYPE_PPP": "syscall", - "syscall.ETHERTYPE_PPPOE": "syscall", - "syscall.ETHERTYPE_PPPOEDISC": "syscall", - "syscall.ETHERTYPE_PRIMENTS": "syscall", - "syscall.ETHERTYPE_PUP": "syscall", - "syscall.ETHERTYPE_PUPAT": "syscall", - "syscall.ETHERTYPE_QINQ": "syscall", - "syscall.ETHERTYPE_RACAL": "syscall", - "syscall.ETHERTYPE_RATIONAL": "syscall", - "syscall.ETHERTYPE_RAWFR": "syscall", - "syscall.ETHERTYPE_RCL": "syscall", - "syscall.ETHERTYPE_RDP": "syscall", - "syscall.ETHERTYPE_RETIX": "syscall", - "syscall.ETHERTYPE_REVARP": "syscall", - "syscall.ETHERTYPE_SCA": "syscall", - "syscall.ETHERTYPE_SECTRA": "syscall", - "syscall.ETHERTYPE_SECUREDATA": "syscall", - "syscall.ETHERTYPE_SGITW": "syscall", - "syscall.ETHERTYPE_SG_BOUNCE": "syscall", - "syscall.ETHERTYPE_SG_DIAG": "syscall", - "syscall.ETHERTYPE_SG_NETGAMES": "syscall", - "syscall.ETHERTYPE_SG_RESV": "syscall", - "syscall.ETHERTYPE_SIMNET": "syscall", - "syscall.ETHERTYPE_SLOW": "syscall", - "syscall.ETHERTYPE_SLOWPROTOCOLS": "syscall", - "syscall.ETHERTYPE_SNA": "syscall", - "syscall.ETHERTYPE_SNMP": "syscall", - "syscall.ETHERTYPE_SONIX": "syscall", - "syscall.ETHERTYPE_SPIDER": "syscall", - "syscall.ETHERTYPE_SPRITE": "syscall", - "syscall.ETHERTYPE_STP": "syscall", - "syscall.ETHERTYPE_TALARIS": "syscall", - "syscall.ETHERTYPE_TALARISMC": "syscall", - "syscall.ETHERTYPE_TCPCOMP": "syscall", - "syscall.ETHERTYPE_TCPSM": "syscall", - "syscall.ETHERTYPE_TEC": "syscall", - "syscall.ETHERTYPE_TIGAN": "syscall", - "syscall.ETHERTYPE_TRAIL": "syscall", - "syscall.ETHERTYPE_TRANSETHER": "syscall", - "syscall.ETHERTYPE_TYMSHARE": "syscall", - "syscall.ETHERTYPE_UBBST": "syscall", - "syscall.ETHERTYPE_UBDEBUG": "syscall", - "syscall.ETHERTYPE_UBDIAGLOOP": "syscall", - "syscall.ETHERTYPE_UBDL": "syscall", - "syscall.ETHERTYPE_UBNIU": "syscall", - "syscall.ETHERTYPE_UBNMC": "syscall", - "syscall.ETHERTYPE_VALID": "syscall", - "syscall.ETHERTYPE_VARIAN": "syscall", - "syscall.ETHERTYPE_VAXELN": "syscall", - "syscall.ETHERTYPE_VEECO": "syscall", - "syscall.ETHERTYPE_VEXP": "syscall", - "syscall.ETHERTYPE_VGLAB": "syscall", - "syscall.ETHERTYPE_VINES": "syscall", - "syscall.ETHERTYPE_VINESECHO": "syscall", - "syscall.ETHERTYPE_VINESLOOP": "syscall", - "syscall.ETHERTYPE_VITAL": "syscall", - "syscall.ETHERTYPE_VLAN": "syscall", - "syscall.ETHERTYPE_VLTLMAN": "syscall", - "syscall.ETHERTYPE_VPROD": "syscall", - "syscall.ETHERTYPE_VURESERVED": "syscall", - "syscall.ETHERTYPE_WATERLOO": "syscall", - "syscall.ETHERTYPE_WELLFLEET": "syscall", - "syscall.ETHERTYPE_X25": "syscall", - "syscall.ETHERTYPE_X75": "syscall", - "syscall.ETHERTYPE_XNSSM": "syscall", - "syscall.ETHERTYPE_XTP": "syscall", - "syscall.ETHER_ADDR_LEN": "syscall", - "syscall.ETHER_ALIGN": "syscall", - "syscall.ETHER_CRC_LEN": "syscall", - "syscall.ETHER_CRC_POLY_BE": "syscall", - "syscall.ETHER_CRC_POLY_LE": "syscall", - "syscall.ETHER_HDR_LEN": "syscall", - "syscall.ETHER_MAX_DIX_LEN": "syscall", - "syscall.ETHER_MAX_LEN": "syscall", - "syscall.ETHER_MAX_LEN_JUMBO": "syscall", - "syscall.ETHER_MIN_LEN": "syscall", - "syscall.ETHER_PPPOE_ENCAP_LEN": "syscall", - "syscall.ETHER_TYPE_LEN": "syscall", - "syscall.ETHER_VLAN_ENCAP_LEN": "syscall", - "syscall.ETH_P_1588": "syscall", - "syscall.ETH_P_8021Q": "syscall", - "syscall.ETH_P_802_2": "syscall", - "syscall.ETH_P_802_3": "syscall", - "syscall.ETH_P_AARP": "syscall", - "syscall.ETH_P_ALL": "syscall", - "syscall.ETH_P_AOE": "syscall", - "syscall.ETH_P_ARCNET": "syscall", - "syscall.ETH_P_ARP": "syscall", - "syscall.ETH_P_ATALK": "syscall", - "syscall.ETH_P_ATMFATE": "syscall", - "syscall.ETH_P_ATMMPOA": "syscall", - "syscall.ETH_P_AX25": "syscall", - "syscall.ETH_P_BPQ": "syscall", - "syscall.ETH_P_CAIF": "syscall", - "syscall.ETH_P_CAN": "syscall", - "syscall.ETH_P_CONTROL": "syscall", - "syscall.ETH_P_CUST": "syscall", - "syscall.ETH_P_DDCMP": "syscall", - "syscall.ETH_P_DEC": "syscall", - "syscall.ETH_P_DIAG": "syscall", - "syscall.ETH_P_DNA_DL": "syscall", - "syscall.ETH_P_DNA_RC": "syscall", - "syscall.ETH_P_DNA_RT": "syscall", - "syscall.ETH_P_DSA": "syscall", - "syscall.ETH_P_ECONET": "syscall", - "syscall.ETH_P_EDSA": "syscall", - "syscall.ETH_P_FCOE": "syscall", - "syscall.ETH_P_FIP": "syscall", - "syscall.ETH_P_HDLC": "syscall", - "syscall.ETH_P_IEEE802154": "syscall", - "syscall.ETH_P_IEEEPUP": "syscall", - "syscall.ETH_P_IEEEPUPAT": "syscall", - "syscall.ETH_P_IP": "syscall", - "syscall.ETH_P_IPV6": "syscall", - "syscall.ETH_P_IPX": "syscall", - "syscall.ETH_P_IRDA": "syscall", - "syscall.ETH_P_LAT": "syscall", - "syscall.ETH_P_LINK_CTL": "syscall", - "syscall.ETH_P_LOCALTALK": "syscall", - "syscall.ETH_P_LOOP": "syscall", - "syscall.ETH_P_MOBITEX": "syscall", - "syscall.ETH_P_MPLS_MC": "syscall", - "syscall.ETH_P_MPLS_UC": "syscall", - "syscall.ETH_P_PAE": "syscall", - "syscall.ETH_P_PAUSE": "syscall", - "syscall.ETH_P_PHONET": "syscall", - "syscall.ETH_P_PPPTALK": "syscall", - "syscall.ETH_P_PPP_DISC": "syscall", - "syscall.ETH_P_PPP_MP": "syscall", - "syscall.ETH_P_PPP_SES": "syscall", - "syscall.ETH_P_PUP": "syscall", - "syscall.ETH_P_PUPAT": "syscall", - "syscall.ETH_P_RARP": "syscall", - "syscall.ETH_P_SCA": "syscall", - "syscall.ETH_P_SLOW": "syscall", - "syscall.ETH_P_SNAP": "syscall", - "syscall.ETH_P_TEB": "syscall", - "syscall.ETH_P_TIPC": "syscall", - "syscall.ETH_P_TRAILER": "syscall", - "syscall.ETH_P_TR_802_2": "syscall", - "syscall.ETH_P_WAN_PPP": "syscall", - "syscall.ETH_P_WCCP": "syscall", - "syscall.ETH_P_X25": "syscall", - "syscall.ETIME": "syscall", - "syscall.ETIMEDOUT": "syscall", - "syscall.ETOOMANYREFS": "syscall", - "syscall.ETXTBSY": "syscall", - "syscall.EUCLEAN": "syscall", - "syscall.EUNATCH": "syscall", - "syscall.EUSERS": "syscall", - "syscall.EVFILT_AIO": "syscall", - "syscall.EVFILT_FS": "syscall", - "syscall.EVFILT_LIO": "syscall", - "syscall.EVFILT_MACHPORT": "syscall", - "syscall.EVFILT_PROC": "syscall", - "syscall.EVFILT_READ": "syscall", - "syscall.EVFILT_SIGNAL": "syscall", - "syscall.EVFILT_SYSCOUNT": "syscall", - "syscall.EVFILT_THREADMARKER": "syscall", - "syscall.EVFILT_TIMER": "syscall", - "syscall.EVFILT_USER": "syscall", - "syscall.EVFILT_VM": "syscall", - "syscall.EVFILT_VNODE": "syscall", - "syscall.EVFILT_WRITE": "syscall", - "syscall.EV_ADD": "syscall", - "syscall.EV_CLEAR": "syscall", - "syscall.EV_DELETE": "syscall", - "syscall.EV_DISABLE": "syscall", - "syscall.EV_DISPATCH": "syscall", - "syscall.EV_DROP": "syscall", - "syscall.EV_ENABLE": "syscall", - "syscall.EV_EOF": "syscall", - "syscall.EV_ERROR": "syscall", - "syscall.EV_FLAG0": "syscall", - "syscall.EV_FLAG1": "syscall", - "syscall.EV_ONESHOT": "syscall", - "syscall.EV_OOBAND": "syscall", - "syscall.EV_POLL": "syscall", - "syscall.EV_RECEIPT": "syscall", - "syscall.EV_SYSFLAGS": "syscall", - "syscall.EWINDOWS": "syscall", - "syscall.EWOULDBLOCK": "syscall", - "syscall.EXDEV": "syscall", - "syscall.EXFULL": "syscall", - "syscall.EXTA": "syscall", - "syscall.EXTB": "syscall", - "syscall.EXTPROC": "syscall", - "syscall.Environ": "syscall", - "syscall.EpollCreate": "syscall", - "syscall.EpollCreate1": "syscall", - "syscall.EpollCtl": "syscall", - "syscall.EpollEvent": "syscall", - "syscall.EpollWait": "syscall", - "syscall.Errno": "syscall", - "syscall.EscapeArg": "syscall", - "syscall.Exchangedata": "syscall", - "syscall.Exec": "syscall", - "syscall.Exit": "syscall", - "syscall.ExitProcess": "syscall", - "syscall.FD_CLOEXEC": "syscall", - "syscall.FD_SETSIZE": "syscall", - "syscall.FILE_ACTION_ADDED": "syscall", - "syscall.FILE_ACTION_MODIFIED": "syscall", - "syscall.FILE_ACTION_REMOVED": "syscall", - "syscall.FILE_ACTION_RENAMED_NEW_NAME": "syscall", - "syscall.FILE_ACTION_RENAMED_OLD_NAME": "syscall", - "syscall.FILE_APPEND_DATA": "syscall", - "syscall.FILE_ATTRIBUTE_ARCHIVE": "syscall", - "syscall.FILE_ATTRIBUTE_DIRECTORY": "syscall", - "syscall.FILE_ATTRIBUTE_HIDDEN": "syscall", - "syscall.FILE_ATTRIBUTE_NORMAL": "syscall", - "syscall.FILE_ATTRIBUTE_READONLY": "syscall", - "syscall.FILE_ATTRIBUTE_REPARSE_POINT": "syscall", - "syscall.FILE_ATTRIBUTE_SYSTEM": "syscall", - "syscall.FILE_BEGIN": "syscall", - "syscall.FILE_CURRENT": "syscall", - "syscall.FILE_END": "syscall", - "syscall.FILE_FLAG_BACKUP_SEMANTICS": "syscall", - "syscall.FILE_FLAG_OPEN_REPARSE_POINT": "syscall", - "syscall.FILE_FLAG_OVERLAPPED": "syscall", - "syscall.FILE_LIST_DIRECTORY": "syscall", - "syscall.FILE_MAP_COPY": "syscall", - "syscall.FILE_MAP_EXECUTE": "syscall", - "syscall.FILE_MAP_READ": "syscall", - "syscall.FILE_MAP_WRITE": "syscall", - "syscall.FILE_NOTIFY_CHANGE_ATTRIBUTES": "syscall", - "syscall.FILE_NOTIFY_CHANGE_CREATION": "syscall", - "syscall.FILE_NOTIFY_CHANGE_DIR_NAME": "syscall", - "syscall.FILE_NOTIFY_CHANGE_FILE_NAME": "syscall", - "syscall.FILE_NOTIFY_CHANGE_LAST_ACCESS": "syscall", - "syscall.FILE_NOTIFY_CHANGE_LAST_WRITE": "syscall", - "syscall.FILE_NOTIFY_CHANGE_SIZE": "syscall", - "syscall.FILE_SHARE_DELETE": "syscall", - "syscall.FILE_SHARE_READ": "syscall", - "syscall.FILE_SHARE_WRITE": "syscall", - "syscall.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS": "syscall", - "syscall.FILE_SKIP_SET_EVENT_ON_HANDLE": "syscall", - "syscall.FILE_TYPE_CHAR": "syscall", - "syscall.FILE_TYPE_DISK": "syscall", - "syscall.FILE_TYPE_PIPE": "syscall", - "syscall.FILE_TYPE_REMOTE": "syscall", - "syscall.FILE_TYPE_UNKNOWN": "syscall", - "syscall.FILE_WRITE_ATTRIBUTES": "syscall", - "syscall.FLUSHO": "syscall", - "syscall.FORMAT_MESSAGE_ALLOCATE_BUFFER": "syscall", - "syscall.FORMAT_MESSAGE_ARGUMENT_ARRAY": "syscall", - "syscall.FORMAT_MESSAGE_FROM_HMODULE": "syscall", - "syscall.FORMAT_MESSAGE_FROM_STRING": "syscall", - "syscall.FORMAT_MESSAGE_FROM_SYSTEM": "syscall", - "syscall.FORMAT_MESSAGE_IGNORE_INSERTS": "syscall", - "syscall.FORMAT_MESSAGE_MAX_WIDTH_MASK": "syscall", - "syscall.FSCTL_GET_REPARSE_POINT": "syscall", - "syscall.F_ADDFILESIGS": "syscall", - "syscall.F_ADDSIGS": "syscall", - "syscall.F_ALLOCATEALL": "syscall", - "syscall.F_ALLOCATECONTIG": "syscall", - "syscall.F_CANCEL": "syscall", - "syscall.F_CHKCLEAN": "syscall", - "syscall.F_CLOSEM": "syscall", - "syscall.F_DUP2FD": "syscall", - "syscall.F_DUP2FD_CLOEXEC": "syscall", - "syscall.F_DUPFD": "syscall", - "syscall.F_DUPFD_CLOEXEC": "syscall", - "syscall.F_EXLCK": "syscall", - "syscall.F_FLUSH_DATA": "syscall", - "syscall.F_FREEZE_FS": "syscall", - "syscall.F_FSCTL": "syscall", - "syscall.F_FSDIRMASK": "syscall", - "syscall.F_FSIN": "syscall", - "syscall.F_FSINOUT": "syscall", - "syscall.F_FSOUT": "syscall", - "syscall.F_FSPRIV": "syscall", - "syscall.F_FSVOID": "syscall", - "syscall.F_FULLFSYNC": "syscall", - "syscall.F_GETFD": "syscall", - "syscall.F_GETFL": "syscall", - "syscall.F_GETLEASE": "syscall", - "syscall.F_GETLK": "syscall", - "syscall.F_GETLK64": "syscall", - "syscall.F_GETLKPID": "syscall", - "syscall.F_GETNOSIGPIPE": "syscall", - "syscall.F_GETOWN": "syscall", - "syscall.F_GETOWN_EX": "syscall", - "syscall.F_GETPATH": "syscall", - "syscall.F_GETPATH_MTMINFO": "syscall", - "syscall.F_GETPIPE_SZ": "syscall", - "syscall.F_GETPROTECTIONCLASS": "syscall", - "syscall.F_GETSIG": "syscall", - "syscall.F_GLOBAL_NOCACHE": "syscall", - "syscall.F_LOCK": "syscall", - "syscall.F_LOG2PHYS": "syscall", - "syscall.F_LOG2PHYS_EXT": "syscall", - "syscall.F_MARKDEPENDENCY": "syscall", - "syscall.F_MAXFD": "syscall", - "syscall.F_NOCACHE": "syscall", - "syscall.F_NODIRECT": "syscall", - "syscall.F_NOTIFY": "syscall", - "syscall.F_OGETLK": "syscall", - "syscall.F_OK": "syscall", - "syscall.F_OSETLK": "syscall", - "syscall.F_OSETLKW": "syscall", - "syscall.F_PARAM_MASK": "syscall", - "syscall.F_PARAM_MAX": "syscall", - "syscall.F_PATHPKG_CHECK": "syscall", - "syscall.F_PEOFPOSMODE": "syscall", - "syscall.F_PREALLOCATE": "syscall", - "syscall.F_RDADVISE": "syscall", - "syscall.F_RDAHEAD": "syscall", - "syscall.F_RDLCK": "syscall", - "syscall.F_READAHEAD": "syscall", - "syscall.F_READBOOTSTRAP": "syscall", - "syscall.F_SETBACKINGSTORE": "syscall", - "syscall.F_SETFD": "syscall", - "syscall.F_SETFL": "syscall", - "syscall.F_SETLEASE": "syscall", - "syscall.F_SETLK": "syscall", - "syscall.F_SETLK64": "syscall", - "syscall.F_SETLKW": "syscall", - "syscall.F_SETLKW64": "syscall", - "syscall.F_SETLK_REMOTE": "syscall", - "syscall.F_SETNOSIGPIPE": "syscall", - "syscall.F_SETOWN": "syscall", - "syscall.F_SETOWN_EX": "syscall", - "syscall.F_SETPIPE_SZ": "syscall", - "syscall.F_SETPROTECTIONCLASS": "syscall", - "syscall.F_SETSIG": "syscall", - "syscall.F_SETSIZE": "syscall", - "syscall.F_SHLCK": "syscall", - "syscall.F_TEST": "syscall", - "syscall.F_THAW_FS": "syscall", - "syscall.F_TLOCK": "syscall", - "syscall.F_ULOCK": "syscall", - "syscall.F_UNLCK": "syscall", - "syscall.F_UNLCKSYS": "syscall", - "syscall.F_VOLPOSMODE": "syscall", - "syscall.F_WRITEBOOTSTRAP": "syscall", - "syscall.F_WRLCK": "syscall", - "syscall.Faccessat": "syscall", - "syscall.Fallocate": "syscall", - "syscall.Fbootstraptransfer_t": "syscall", - "syscall.Fchdir": "syscall", - "syscall.Fchflags": "syscall", - "syscall.Fchmod": "syscall", - "syscall.Fchmodat": "syscall", - "syscall.Fchown": "syscall", - "syscall.Fchownat": "syscall", - "syscall.FcntlFlock": "syscall", - "syscall.FdSet": "syscall", - "syscall.Fdatasync": "syscall", - "syscall.FileNotifyInformation": "syscall", - "syscall.Filetime": "syscall", - "syscall.FindClose": "syscall", - "syscall.FindFirstFile": "syscall", - "syscall.FindNextFile": "syscall", - "syscall.Flock": "syscall", - "syscall.Flock_t": "syscall", - "syscall.FlushBpf": "syscall", - "syscall.FlushFileBuffers": "syscall", - "syscall.FlushViewOfFile": "syscall", - "syscall.ForkExec": "syscall", - "syscall.ForkLock": "syscall", - "syscall.FormatMessage": "syscall", - "syscall.Fpathconf": "syscall", - "syscall.FreeAddrInfoW": "syscall", - "syscall.FreeEnvironmentStrings": "syscall", - "syscall.FreeLibrary": "syscall", - "syscall.Fsid": "syscall", - "syscall.Fstat": "syscall", - "syscall.Fstatfs": "syscall", - "syscall.Fstore_t": "syscall", - "syscall.Fsync": "syscall", - "syscall.Ftruncate": "syscall", - "syscall.FullPath": "syscall", - "syscall.Futimes": "syscall", - "syscall.Futimesat": "syscall", - "syscall.GENERIC_ALL": "syscall", - "syscall.GENERIC_EXECUTE": "syscall", - "syscall.GENERIC_READ": "syscall", - "syscall.GENERIC_WRITE": "syscall", - "syscall.GUID": "syscall", - "syscall.GetAcceptExSockaddrs": "syscall", - "syscall.GetAdaptersInfo": "syscall", - "syscall.GetAddrInfoW": "syscall", - "syscall.GetCommandLine": "syscall", - "syscall.GetComputerName": "syscall", - "syscall.GetConsoleMode": "syscall", - "syscall.GetCurrentDirectory": "syscall", - "syscall.GetCurrentProcess": "syscall", - "syscall.GetEnvironmentStrings": "syscall", - "syscall.GetEnvironmentVariable": "syscall", - "syscall.GetExitCodeProcess": "syscall", - "syscall.GetFileAttributes": "syscall", - "syscall.GetFileAttributesEx": "syscall", - "syscall.GetFileExInfoStandard": "syscall", - "syscall.GetFileExMaxInfoLevel": "syscall", - "syscall.GetFileInformationByHandle": "syscall", - "syscall.GetFileType": "syscall", - "syscall.GetFullPathName": "syscall", - "syscall.GetHostByName": "syscall", - "syscall.GetIfEntry": "syscall", - "syscall.GetLastError": "syscall", - "syscall.GetLengthSid": "syscall", - "syscall.GetLongPathName": "syscall", - "syscall.GetProcAddress": "syscall", - "syscall.GetProcessTimes": "syscall", - "syscall.GetProtoByName": "syscall", - "syscall.GetQueuedCompletionStatus": "syscall", - "syscall.GetServByName": "syscall", - "syscall.GetShortPathName": "syscall", - "syscall.GetStartupInfo": "syscall", - "syscall.GetStdHandle": "syscall", - "syscall.GetSystemTimeAsFileTime": "syscall", - "syscall.GetTempPath": "syscall", - "syscall.GetTimeZoneInformation": "syscall", - "syscall.GetTokenInformation": "syscall", - "syscall.GetUserNameEx": "syscall", - "syscall.GetUserProfileDirectory": "syscall", - "syscall.GetVersion": "syscall", - "syscall.Getcwd": "syscall", - "syscall.Getdents": "syscall", - "syscall.Getdirentries": "syscall", - "syscall.Getdtablesize": "syscall", - "syscall.Getegid": "syscall", - "syscall.Getenv": "syscall", - "syscall.Geteuid": "syscall", - "syscall.Getfsstat": "syscall", - "syscall.Getgid": "syscall", - "syscall.Getgroups": "syscall", - "syscall.Getpagesize": "syscall", - "syscall.Getpeername": "syscall", - "syscall.Getpgid": "syscall", - "syscall.Getpgrp": "syscall", - "syscall.Getpid": "syscall", - "syscall.Getppid": "syscall", - "syscall.Getpriority": "syscall", - "syscall.Getrlimit": "syscall", - "syscall.Getrusage": "syscall", - "syscall.Getsid": "syscall", - "syscall.Getsockname": "syscall", - "syscall.Getsockopt": "syscall", - "syscall.GetsockoptByte": "syscall", - "syscall.GetsockoptICMPv6Filter": "syscall", - "syscall.GetsockoptIPMreq": "syscall", - "syscall.GetsockoptIPMreqn": "syscall", - "syscall.GetsockoptIPv6MTUInfo": "syscall", - "syscall.GetsockoptIPv6Mreq": "syscall", - "syscall.GetsockoptInet4Addr": "syscall", - "syscall.GetsockoptInt": "syscall", - "syscall.GetsockoptUcred": "syscall", - "syscall.Gettid": "syscall", - "syscall.Gettimeofday": "syscall", - "syscall.Getuid": "syscall", - "syscall.Getwd": "syscall", - "syscall.Getxattr": "syscall", - "syscall.HANDLE_FLAG_INHERIT": "syscall", - "syscall.HKEY_CLASSES_ROOT": "syscall", - "syscall.HKEY_CURRENT_CONFIG": "syscall", - "syscall.HKEY_CURRENT_USER": "syscall", - "syscall.HKEY_DYN_DATA": "syscall", - "syscall.HKEY_LOCAL_MACHINE": "syscall", - "syscall.HKEY_PERFORMANCE_DATA": "syscall", - "syscall.HKEY_USERS": "syscall", - "syscall.HUPCL": "syscall", - "syscall.Handle": "syscall", - "syscall.Hostent": "syscall", - "syscall.ICANON": "syscall", - "syscall.ICMP6_FILTER": "syscall", - "syscall.ICMPV6_FILTER": "syscall", - "syscall.ICMPv6Filter": "syscall", - "syscall.ICRNL": "syscall", - "syscall.IEXTEN": "syscall", - "syscall.IFAN_ARRIVAL": "syscall", - "syscall.IFAN_DEPARTURE": "syscall", - "syscall.IFA_ADDRESS": "syscall", - "syscall.IFA_ANYCAST": "syscall", - "syscall.IFA_BROADCAST": "syscall", - "syscall.IFA_CACHEINFO": "syscall", - "syscall.IFA_F_DADFAILED": "syscall", - "syscall.IFA_F_DEPRECATED": "syscall", - "syscall.IFA_F_HOMEADDRESS": "syscall", - "syscall.IFA_F_NODAD": "syscall", - "syscall.IFA_F_OPTIMISTIC": "syscall", - "syscall.IFA_F_PERMANENT": "syscall", - "syscall.IFA_F_SECONDARY": "syscall", - "syscall.IFA_F_TEMPORARY": "syscall", - "syscall.IFA_F_TENTATIVE": "syscall", - "syscall.IFA_LABEL": "syscall", - "syscall.IFA_LOCAL": "syscall", - "syscall.IFA_MAX": "syscall", - "syscall.IFA_MULTICAST": "syscall", - "syscall.IFA_ROUTE": "syscall", - "syscall.IFA_UNSPEC": "syscall", - "syscall.IFF_ALLMULTI": "syscall", - "syscall.IFF_ALTPHYS": "syscall", - "syscall.IFF_AUTOMEDIA": "syscall", - "syscall.IFF_BROADCAST": "syscall", - "syscall.IFF_CANTCHANGE": "syscall", - "syscall.IFF_CANTCONFIG": "syscall", - "syscall.IFF_DEBUG": "syscall", - "syscall.IFF_DRV_OACTIVE": "syscall", - "syscall.IFF_DRV_RUNNING": "syscall", - "syscall.IFF_DYING": "syscall", - "syscall.IFF_DYNAMIC": "syscall", - "syscall.IFF_LINK0": "syscall", - "syscall.IFF_LINK1": "syscall", - "syscall.IFF_LINK2": "syscall", - "syscall.IFF_LOOPBACK": "syscall", - "syscall.IFF_MASTER": "syscall", - "syscall.IFF_MONITOR": "syscall", - "syscall.IFF_MULTICAST": "syscall", - "syscall.IFF_NOARP": "syscall", - "syscall.IFF_NOTRAILERS": "syscall", - "syscall.IFF_NO_PI": "syscall", - "syscall.IFF_OACTIVE": "syscall", - "syscall.IFF_ONE_QUEUE": "syscall", - "syscall.IFF_POINTOPOINT": "syscall", - "syscall.IFF_POINTTOPOINT": "syscall", - "syscall.IFF_PORTSEL": "syscall", - "syscall.IFF_PPROMISC": "syscall", - "syscall.IFF_PROMISC": "syscall", - "syscall.IFF_RENAMING": "syscall", - "syscall.IFF_RUNNING": "syscall", - "syscall.IFF_SIMPLEX": "syscall", - "syscall.IFF_SLAVE": "syscall", - "syscall.IFF_SMART": "syscall", - "syscall.IFF_STATICARP": "syscall", - "syscall.IFF_TAP": "syscall", - "syscall.IFF_TUN": "syscall", - "syscall.IFF_TUN_EXCL": "syscall", - "syscall.IFF_UP": "syscall", - "syscall.IFF_VNET_HDR": "syscall", - "syscall.IFLA_ADDRESS": "syscall", - "syscall.IFLA_BROADCAST": "syscall", - "syscall.IFLA_COST": "syscall", - "syscall.IFLA_IFALIAS": "syscall", - "syscall.IFLA_IFNAME": "syscall", - "syscall.IFLA_LINK": "syscall", - "syscall.IFLA_LINKINFO": "syscall", - "syscall.IFLA_LINKMODE": "syscall", - "syscall.IFLA_MAP": "syscall", - "syscall.IFLA_MASTER": "syscall", - "syscall.IFLA_MAX": "syscall", - "syscall.IFLA_MTU": "syscall", - "syscall.IFLA_NET_NS_PID": "syscall", - "syscall.IFLA_OPERSTATE": "syscall", - "syscall.IFLA_PRIORITY": "syscall", - "syscall.IFLA_PROTINFO": "syscall", - "syscall.IFLA_QDISC": "syscall", - "syscall.IFLA_STATS": "syscall", - "syscall.IFLA_TXQLEN": "syscall", - "syscall.IFLA_UNSPEC": "syscall", - "syscall.IFLA_WEIGHT": "syscall", - "syscall.IFLA_WIRELESS": "syscall", - "syscall.IFNAMSIZ": "syscall", - "syscall.IFT_1822": "syscall", - "syscall.IFT_A12MPPSWITCH": "syscall", - "syscall.IFT_AAL2": "syscall", - "syscall.IFT_AAL5": "syscall", - "syscall.IFT_ADSL": "syscall", - "syscall.IFT_AFLANE8023": "syscall", - "syscall.IFT_AFLANE8025": "syscall", - "syscall.IFT_ARAP": "syscall", - "syscall.IFT_ARCNET": "syscall", - "syscall.IFT_ARCNETPLUS": "syscall", - "syscall.IFT_ASYNC": "syscall", - "syscall.IFT_ATM": "syscall", - "syscall.IFT_ATMDXI": "syscall", - "syscall.IFT_ATMFUNI": "syscall", - "syscall.IFT_ATMIMA": "syscall", - "syscall.IFT_ATMLOGICAL": "syscall", - "syscall.IFT_ATMRADIO": "syscall", - "syscall.IFT_ATMSUBINTERFACE": "syscall", - "syscall.IFT_ATMVCIENDPT": "syscall", - "syscall.IFT_ATMVIRTUAL": "syscall", - "syscall.IFT_BGPPOLICYACCOUNTING": "syscall", - "syscall.IFT_BLUETOOTH": "syscall", - "syscall.IFT_BRIDGE": "syscall", - "syscall.IFT_BSC": "syscall", - "syscall.IFT_CARP": "syscall", - "syscall.IFT_CCTEMUL": "syscall", - "syscall.IFT_CELLULAR": "syscall", - "syscall.IFT_CEPT": "syscall", - "syscall.IFT_CES": "syscall", - "syscall.IFT_CHANNEL": "syscall", - "syscall.IFT_CNR": "syscall", - "syscall.IFT_COFFEE": "syscall", - "syscall.IFT_COMPOSITELINK": "syscall", - "syscall.IFT_DCN": "syscall", - "syscall.IFT_DIGITALPOWERLINE": "syscall", - "syscall.IFT_DIGITALWRAPPEROVERHEADCHANNEL": "syscall", - "syscall.IFT_DLSW": "syscall", - "syscall.IFT_DOCSCABLEDOWNSTREAM": "syscall", - "syscall.IFT_DOCSCABLEMACLAYER": "syscall", - "syscall.IFT_DOCSCABLEUPSTREAM": "syscall", - "syscall.IFT_DOCSCABLEUPSTREAMCHANNEL": "syscall", - "syscall.IFT_DS0": "syscall", - "syscall.IFT_DS0BUNDLE": "syscall", - "syscall.IFT_DS1FDL": "syscall", - "syscall.IFT_DS3": "syscall", - "syscall.IFT_DTM": "syscall", - "syscall.IFT_DUMMY": "syscall", - "syscall.IFT_DVBASILN": "syscall", - "syscall.IFT_DVBASIOUT": "syscall", - "syscall.IFT_DVBRCCDOWNSTREAM": "syscall", - "syscall.IFT_DVBRCCMACLAYER": "syscall", - "syscall.IFT_DVBRCCUPSTREAM": "syscall", - "syscall.IFT_ECONET": "syscall", - "syscall.IFT_ENC": "syscall", - "syscall.IFT_EON": "syscall", - "syscall.IFT_EPLRS": "syscall", - "syscall.IFT_ESCON": "syscall", - "syscall.IFT_ETHER": "syscall", - "syscall.IFT_FAITH": "syscall", - "syscall.IFT_FAST": "syscall", - "syscall.IFT_FASTETHER": "syscall", - "syscall.IFT_FASTETHERFX": "syscall", - "syscall.IFT_FDDI": "syscall", - "syscall.IFT_FIBRECHANNEL": "syscall", - "syscall.IFT_FRAMERELAYINTERCONNECT": "syscall", - "syscall.IFT_FRAMERELAYMPI": "syscall", - "syscall.IFT_FRDLCIENDPT": "syscall", - "syscall.IFT_FRELAY": "syscall", - "syscall.IFT_FRELAYDCE": "syscall", - "syscall.IFT_FRF16MFRBUNDLE": "syscall", - "syscall.IFT_FRFORWARD": "syscall", - "syscall.IFT_G703AT2MB": "syscall", - "syscall.IFT_G703AT64K": "syscall", - "syscall.IFT_GIF": "syscall", - "syscall.IFT_GIGABITETHERNET": "syscall", - "syscall.IFT_GR303IDT": "syscall", - "syscall.IFT_GR303RDT": "syscall", - "syscall.IFT_H323GATEKEEPER": "syscall", - "syscall.IFT_H323PROXY": "syscall", - "syscall.IFT_HDH1822": "syscall", - "syscall.IFT_HDLC": "syscall", - "syscall.IFT_HDSL2": "syscall", - "syscall.IFT_HIPERLAN2": "syscall", - "syscall.IFT_HIPPI": "syscall", - "syscall.IFT_HIPPIINTERFACE": "syscall", - "syscall.IFT_HOSTPAD": "syscall", - "syscall.IFT_HSSI": "syscall", - "syscall.IFT_HY": "syscall", - "syscall.IFT_IBM370PARCHAN": "syscall", - "syscall.IFT_IDSL": "syscall", - "syscall.IFT_IEEE1394": "syscall", - "syscall.IFT_IEEE80211": "syscall", - "syscall.IFT_IEEE80212": "syscall", - "syscall.IFT_IEEE8023ADLAG": "syscall", - "syscall.IFT_IFGSN": "syscall", - "syscall.IFT_IMT": "syscall", - "syscall.IFT_INFINIBAND": "syscall", - "syscall.IFT_INTERLEAVE": "syscall", - "syscall.IFT_IP": "syscall", - "syscall.IFT_IPFORWARD": "syscall", - "syscall.IFT_IPOVERATM": "syscall", - "syscall.IFT_IPOVERCDLC": "syscall", - "syscall.IFT_IPOVERCLAW": "syscall", - "syscall.IFT_IPSWITCH": "syscall", - "syscall.IFT_IPXIP": "syscall", - "syscall.IFT_ISDN": "syscall", - "syscall.IFT_ISDNBASIC": "syscall", - "syscall.IFT_ISDNPRIMARY": "syscall", - "syscall.IFT_ISDNS": "syscall", - "syscall.IFT_ISDNU": "syscall", - "syscall.IFT_ISO88022LLC": "syscall", - "syscall.IFT_ISO88023": "syscall", - "syscall.IFT_ISO88024": "syscall", - "syscall.IFT_ISO88025": "syscall", - "syscall.IFT_ISO88025CRFPINT": "syscall", - "syscall.IFT_ISO88025DTR": "syscall", - "syscall.IFT_ISO88025FIBER": "syscall", - "syscall.IFT_ISO88026": "syscall", - "syscall.IFT_ISUP": "syscall", - "syscall.IFT_L2VLAN": "syscall", - "syscall.IFT_L3IPVLAN": "syscall", - "syscall.IFT_L3IPXVLAN": "syscall", - "syscall.IFT_LAPB": "syscall", - "syscall.IFT_LAPD": "syscall", - "syscall.IFT_LAPF": "syscall", - "syscall.IFT_LINEGROUP": "syscall", - "syscall.IFT_LOCALTALK": "syscall", - "syscall.IFT_LOOP": "syscall", - "syscall.IFT_MEDIAMAILOVERIP": "syscall", - "syscall.IFT_MFSIGLINK": "syscall", - "syscall.IFT_MIOX25": "syscall", - "syscall.IFT_MODEM": "syscall", - "syscall.IFT_MPC": "syscall", - "syscall.IFT_MPLS": "syscall", - "syscall.IFT_MPLSTUNNEL": "syscall", - "syscall.IFT_MSDSL": "syscall", - "syscall.IFT_MVL": "syscall", - "syscall.IFT_MYRINET": "syscall", - "syscall.IFT_NFAS": "syscall", - "syscall.IFT_NSIP": "syscall", - "syscall.IFT_OPTICALCHANNEL": "syscall", - "syscall.IFT_OPTICALTRANSPORT": "syscall", - "syscall.IFT_OTHER": "syscall", - "syscall.IFT_P10": "syscall", - "syscall.IFT_P80": "syscall", - "syscall.IFT_PARA": "syscall", - "syscall.IFT_PDP": "syscall", - "syscall.IFT_PFLOG": "syscall", - "syscall.IFT_PFLOW": "syscall", - "syscall.IFT_PFSYNC": "syscall", - "syscall.IFT_PLC": "syscall", - "syscall.IFT_PON155": "syscall", - "syscall.IFT_PON622": "syscall", - "syscall.IFT_POS": "syscall", - "syscall.IFT_PPP": "syscall", - "syscall.IFT_PPPMULTILINKBUNDLE": "syscall", - "syscall.IFT_PROPATM": "syscall", - "syscall.IFT_PROPBWAP2MP": "syscall", - "syscall.IFT_PROPCNLS": "syscall", - "syscall.IFT_PROPDOCSWIRELESSDOWNSTREAM": "syscall", - "syscall.IFT_PROPDOCSWIRELESSMACLAYER": "syscall", - "syscall.IFT_PROPDOCSWIRELESSUPSTREAM": "syscall", - "syscall.IFT_PROPMUX": "syscall", - "syscall.IFT_PROPVIRTUAL": "syscall", - "syscall.IFT_PROPWIRELESSP2P": "syscall", - "syscall.IFT_PTPSERIAL": "syscall", - "syscall.IFT_PVC": "syscall", - "syscall.IFT_Q2931": "syscall", - "syscall.IFT_QLLC": "syscall", - "syscall.IFT_RADIOMAC": "syscall", - "syscall.IFT_RADSL": "syscall", - "syscall.IFT_REACHDSL": "syscall", - "syscall.IFT_RFC1483": "syscall", - "syscall.IFT_RS232": "syscall", - "syscall.IFT_RSRB": "syscall", - "syscall.IFT_SDLC": "syscall", - "syscall.IFT_SDSL": "syscall", - "syscall.IFT_SHDSL": "syscall", - "syscall.IFT_SIP": "syscall", - "syscall.IFT_SIPSIG": "syscall", - "syscall.IFT_SIPTG": "syscall", - "syscall.IFT_SLIP": "syscall", - "syscall.IFT_SMDSDXI": "syscall", - "syscall.IFT_SMDSICIP": "syscall", - "syscall.IFT_SONET": "syscall", - "syscall.IFT_SONETOVERHEADCHANNEL": "syscall", - "syscall.IFT_SONETPATH": "syscall", - "syscall.IFT_SONETVT": "syscall", - "syscall.IFT_SRP": "syscall", - "syscall.IFT_SS7SIGLINK": "syscall", - "syscall.IFT_STACKTOSTACK": "syscall", - "syscall.IFT_STARLAN": "syscall", - "syscall.IFT_STF": "syscall", - "syscall.IFT_T1": "syscall", - "syscall.IFT_TDLC": "syscall", - "syscall.IFT_TELINK": "syscall", - "syscall.IFT_TERMPAD": "syscall", - "syscall.IFT_TR008": "syscall", - "syscall.IFT_TRANSPHDLC": "syscall", - "syscall.IFT_TUNNEL": "syscall", - "syscall.IFT_ULTRA": "syscall", - "syscall.IFT_USB": "syscall", - "syscall.IFT_V11": "syscall", - "syscall.IFT_V35": "syscall", - "syscall.IFT_V36": "syscall", - "syscall.IFT_V37": "syscall", - "syscall.IFT_VDSL": "syscall", - "syscall.IFT_VIRTUALIPADDRESS": "syscall", - "syscall.IFT_VIRTUALTG": "syscall", - "syscall.IFT_VOICEDID": "syscall", - "syscall.IFT_VOICEEM": "syscall", - "syscall.IFT_VOICEEMFGD": "syscall", - "syscall.IFT_VOICEENCAP": "syscall", - "syscall.IFT_VOICEFGDEANA": "syscall", - "syscall.IFT_VOICEFXO": "syscall", - "syscall.IFT_VOICEFXS": "syscall", - "syscall.IFT_VOICEOVERATM": "syscall", - "syscall.IFT_VOICEOVERCABLE": "syscall", - "syscall.IFT_VOICEOVERFRAMERELAY": "syscall", - "syscall.IFT_VOICEOVERIP": "syscall", - "syscall.IFT_X213": "syscall", - "syscall.IFT_X25": "syscall", - "syscall.IFT_X25DDN": "syscall", - "syscall.IFT_X25HUNTGROUP": "syscall", - "syscall.IFT_X25MLP": "syscall", - "syscall.IFT_X25PLE": "syscall", - "syscall.IFT_XETHER": "syscall", - "syscall.IGNBRK": "syscall", - "syscall.IGNCR": "syscall", - "syscall.IGNORE": "syscall", - "syscall.IGNPAR": "syscall", - "syscall.IMAXBEL": "syscall", - "syscall.INFINITE": "syscall", - "syscall.INLCR": "syscall", - "syscall.INPCK": "syscall", - "syscall.INVALID_FILE_ATTRIBUTES": "syscall", - "syscall.IN_ACCESS": "syscall", - "syscall.IN_ALL_EVENTS": "syscall", - "syscall.IN_ATTRIB": "syscall", - "syscall.IN_CLASSA_HOST": "syscall", - "syscall.IN_CLASSA_MAX": "syscall", - "syscall.IN_CLASSA_NET": "syscall", - "syscall.IN_CLASSA_NSHIFT": "syscall", - "syscall.IN_CLASSB_HOST": "syscall", - "syscall.IN_CLASSB_MAX": "syscall", - "syscall.IN_CLASSB_NET": "syscall", - "syscall.IN_CLASSB_NSHIFT": "syscall", - "syscall.IN_CLASSC_HOST": "syscall", - "syscall.IN_CLASSC_NET": "syscall", - "syscall.IN_CLASSC_NSHIFT": "syscall", - "syscall.IN_CLASSD_HOST": "syscall", - "syscall.IN_CLASSD_NET": "syscall", - "syscall.IN_CLASSD_NSHIFT": "syscall", - "syscall.IN_CLOEXEC": "syscall", - "syscall.IN_CLOSE": "syscall", - "syscall.IN_CLOSE_NOWRITE": "syscall", - "syscall.IN_CLOSE_WRITE": "syscall", - "syscall.IN_CREATE": "syscall", - "syscall.IN_DELETE": "syscall", - "syscall.IN_DELETE_SELF": "syscall", - "syscall.IN_DONT_FOLLOW": "syscall", - "syscall.IN_EXCL_UNLINK": "syscall", - "syscall.IN_IGNORED": "syscall", - "syscall.IN_ISDIR": "syscall", - "syscall.IN_LINKLOCALNETNUM": "syscall", - "syscall.IN_LOOPBACKNET": "syscall", - "syscall.IN_MASK_ADD": "syscall", - "syscall.IN_MODIFY": "syscall", - "syscall.IN_MOVE": "syscall", - "syscall.IN_MOVED_FROM": "syscall", - "syscall.IN_MOVED_TO": "syscall", - "syscall.IN_MOVE_SELF": "syscall", - "syscall.IN_NONBLOCK": "syscall", - "syscall.IN_ONESHOT": "syscall", - "syscall.IN_ONLYDIR": "syscall", - "syscall.IN_OPEN": "syscall", - "syscall.IN_Q_OVERFLOW": "syscall", - "syscall.IN_RFC3021_HOST": "syscall", - "syscall.IN_RFC3021_MASK": "syscall", - "syscall.IN_RFC3021_NET": "syscall", - "syscall.IN_RFC3021_NSHIFT": "syscall", - "syscall.IN_UNMOUNT": "syscall", - "syscall.IOC_IN": "syscall", - "syscall.IOC_INOUT": "syscall", - "syscall.IOC_OUT": "syscall", - "syscall.IOC_VENDOR": "syscall", - "syscall.IOC_WS2": "syscall", - "syscall.IO_REPARSE_TAG_SYMLINK": "syscall", - "syscall.IPMreq": "syscall", - "syscall.IPMreqn": "syscall", - "syscall.IPPROTO_3PC": "syscall", - "syscall.IPPROTO_ADFS": "syscall", - "syscall.IPPROTO_AH": "syscall", - "syscall.IPPROTO_AHIP": "syscall", - "syscall.IPPROTO_APES": "syscall", - "syscall.IPPROTO_ARGUS": "syscall", - "syscall.IPPROTO_AX25": "syscall", - "syscall.IPPROTO_BHA": "syscall", - "syscall.IPPROTO_BLT": "syscall", - "syscall.IPPROTO_BRSATMON": "syscall", - "syscall.IPPROTO_CARP": "syscall", - "syscall.IPPROTO_CFTP": "syscall", - "syscall.IPPROTO_CHAOS": "syscall", - "syscall.IPPROTO_CMTP": "syscall", - "syscall.IPPROTO_COMP": "syscall", - "syscall.IPPROTO_CPHB": "syscall", - "syscall.IPPROTO_CPNX": "syscall", - "syscall.IPPROTO_DCCP": "syscall", - "syscall.IPPROTO_DDP": "syscall", - "syscall.IPPROTO_DGP": "syscall", - "syscall.IPPROTO_DIVERT": "syscall", - "syscall.IPPROTO_DIVERT_INIT": "syscall", - "syscall.IPPROTO_DIVERT_RESP": "syscall", - "syscall.IPPROTO_DONE": "syscall", - "syscall.IPPROTO_DSTOPTS": "syscall", - "syscall.IPPROTO_EGP": "syscall", - "syscall.IPPROTO_EMCON": "syscall", - "syscall.IPPROTO_ENCAP": "syscall", - "syscall.IPPROTO_EON": "syscall", - "syscall.IPPROTO_ESP": "syscall", - "syscall.IPPROTO_ETHERIP": "syscall", - "syscall.IPPROTO_FRAGMENT": "syscall", - "syscall.IPPROTO_GGP": "syscall", - "syscall.IPPROTO_GMTP": "syscall", - "syscall.IPPROTO_GRE": "syscall", - "syscall.IPPROTO_HELLO": "syscall", - "syscall.IPPROTO_HMP": "syscall", - "syscall.IPPROTO_HOPOPTS": "syscall", - "syscall.IPPROTO_ICMP": "syscall", - "syscall.IPPROTO_ICMPV6": "syscall", - "syscall.IPPROTO_IDP": "syscall", - "syscall.IPPROTO_IDPR": "syscall", - "syscall.IPPROTO_IDRP": "syscall", - "syscall.IPPROTO_IGMP": "syscall", - "syscall.IPPROTO_IGP": "syscall", - "syscall.IPPROTO_IGRP": "syscall", - "syscall.IPPROTO_IL": "syscall", - "syscall.IPPROTO_INLSP": "syscall", - "syscall.IPPROTO_INP": "syscall", - "syscall.IPPROTO_IP": "syscall", - "syscall.IPPROTO_IPCOMP": "syscall", - "syscall.IPPROTO_IPCV": "syscall", - "syscall.IPPROTO_IPEIP": "syscall", - "syscall.IPPROTO_IPIP": "syscall", - "syscall.IPPROTO_IPPC": "syscall", - "syscall.IPPROTO_IPV4": "syscall", - "syscall.IPPROTO_IPV6": "syscall", - "syscall.IPPROTO_IPV6_ICMP": "syscall", - "syscall.IPPROTO_IRTP": "syscall", - "syscall.IPPROTO_KRYPTOLAN": "syscall", - "syscall.IPPROTO_LARP": "syscall", - "syscall.IPPROTO_LEAF1": "syscall", - "syscall.IPPROTO_LEAF2": "syscall", - "syscall.IPPROTO_MAX": "syscall", - "syscall.IPPROTO_MAXID": "syscall", - "syscall.IPPROTO_MEAS": "syscall", - "syscall.IPPROTO_MH": "syscall", - "syscall.IPPROTO_MHRP": "syscall", - "syscall.IPPROTO_MICP": "syscall", - "syscall.IPPROTO_MOBILE": "syscall", - "syscall.IPPROTO_MPLS": "syscall", - "syscall.IPPROTO_MTP": "syscall", - "syscall.IPPROTO_MUX": "syscall", - "syscall.IPPROTO_ND": "syscall", - "syscall.IPPROTO_NHRP": "syscall", - "syscall.IPPROTO_NONE": "syscall", - "syscall.IPPROTO_NSP": "syscall", - "syscall.IPPROTO_NVPII": "syscall", - "syscall.IPPROTO_OLD_DIVERT": "syscall", - "syscall.IPPROTO_OSPFIGP": "syscall", - "syscall.IPPROTO_PFSYNC": "syscall", - "syscall.IPPROTO_PGM": "syscall", - "syscall.IPPROTO_PIGP": "syscall", - "syscall.IPPROTO_PIM": "syscall", - "syscall.IPPROTO_PRM": "syscall", - "syscall.IPPROTO_PUP": "syscall", - "syscall.IPPROTO_PVP": "syscall", - "syscall.IPPROTO_RAW": "syscall", - "syscall.IPPROTO_RCCMON": "syscall", - "syscall.IPPROTO_RDP": "syscall", - "syscall.IPPROTO_ROUTING": "syscall", - "syscall.IPPROTO_RSVP": "syscall", - "syscall.IPPROTO_RVD": "syscall", - "syscall.IPPROTO_SATEXPAK": "syscall", - "syscall.IPPROTO_SATMON": "syscall", - "syscall.IPPROTO_SCCSP": "syscall", - "syscall.IPPROTO_SCTP": "syscall", - "syscall.IPPROTO_SDRP": "syscall", - "syscall.IPPROTO_SEND": "syscall", - "syscall.IPPROTO_SEP": "syscall", - "syscall.IPPROTO_SKIP": "syscall", - "syscall.IPPROTO_SPACER": "syscall", - "syscall.IPPROTO_SRPC": "syscall", - "syscall.IPPROTO_ST": "syscall", - "syscall.IPPROTO_SVMTP": "syscall", - "syscall.IPPROTO_SWIPE": "syscall", - "syscall.IPPROTO_TCF": "syscall", - "syscall.IPPROTO_TCP": "syscall", - "syscall.IPPROTO_TLSP": "syscall", - "syscall.IPPROTO_TP": "syscall", - "syscall.IPPROTO_TPXX": "syscall", - "syscall.IPPROTO_TRUNK1": "syscall", - "syscall.IPPROTO_TRUNK2": "syscall", - "syscall.IPPROTO_TTP": "syscall", - "syscall.IPPROTO_UDP": "syscall", - "syscall.IPPROTO_UDPLITE": "syscall", - "syscall.IPPROTO_VINES": "syscall", - "syscall.IPPROTO_VISA": "syscall", - "syscall.IPPROTO_VMTP": "syscall", - "syscall.IPPROTO_VRRP": "syscall", - "syscall.IPPROTO_WBEXPAK": "syscall", - "syscall.IPPROTO_WBMON": "syscall", - "syscall.IPPROTO_WSN": "syscall", - "syscall.IPPROTO_XNET": "syscall", - "syscall.IPPROTO_XTP": "syscall", - "syscall.IPV6_2292DSTOPTS": "syscall", - "syscall.IPV6_2292HOPLIMIT": "syscall", - "syscall.IPV6_2292HOPOPTS": "syscall", - "syscall.IPV6_2292NEXTHOP": "syscall", - "syscall.IPV6_2292PKTINFO": "syscall", - "syscall.IPV6_2292PKTOPTIONS": "syscall", - "syscall.IPV6_2292RTHDR": "syscall", - "syscall.IPV6_ADDRFORM": "syscall", - "syscall.IPV6_ADD_MEMBERSHIP": "syscall", - "syscall.IPV6_AUTHHDR": "syscall", - "syscall.IPV6_AUTH_LEVEL": "syscall", - "syscall.IPV6_AUTOFLOWLABEL": "syscall", - "syscall.IPV6_BINDANY": "syscall", - "syscall.IPV6_BINDV6ONLY": "syscall", - "syscall.IPV6_BOUND_IF": "syscall", - "syscall.IPV6_CHECKSUM": "syscall", - "syscall.IPV6_DEFAULT_MULTICAST_HOPS": "syscall", - "syscall.IPV6_DEFAULT_MULTICAST_LOOP": "syscall", - "syscall.IPV6_DEFHLIM": "syscall", - "syscall.IPV6_DONTFRAG": "syscall", - "syscall.IPV6_DROP_MEMBERSHIP": "syscall", - "syscall.IPV6_DSTOPTS": "syscall", - "syscall.IPV6_ESP_NETWORK_LEVEL": "syscall", - "syscall.IPV6_ESP_TRANS_LEVEL": "syscall", - "syscall.IPV6_FAITH": "syscall", - "syscall.IPV6_FLOWINFO_MASK": "syscall", - "syscall.IPV6_FLOWLABEL_MASK": "syscall", - "syscall.IPV6_FRAGTTL": "syscall", - "syscall.IPV6_FW_ADD": "syscall", - "syscall.IPV6_FW_DEL": "syscall", - "syscall.IPV6_FW_FLUSH": "syscall", - "syscall.IPV6_FW_GET": "syscall", - "syscall.IPV6_FW_ZERO": "syscall", - "syscall.IPV6_HLIMDEC": "syscall", - "syscall.IPV6_HOPLIMIT": "syscall", - "syscall.IPV6_HOPOPTS": "syscall", - "syscall.IPV6_IPCOMP_LEVEL": "syscall", - "syscall.IPV6_IPSEC_POLICY": "syscall", - "syscall.IPV6_JOIN_ANYCAST": "syscall", - "syscall.IPV6_JOIN_GROUP": "syscall", - "syscall.IPV6_LEAVE_ANYCAST": "syscall", - "syscall.IPV6_LEAVE_GROUP": "syscall", - "syscall.IPV6_MAXHLIM": "syscall", - "syscall.IPV6_MAXOPTHDR": "syscall", - "syscall.IPV6_MAXPACKET": "syscall", - "syscall.IPV6_MAX_GROUP_SRC_FILTER": "syscall", - "syscall.IPV6_MAX_MEMBERSHIPS": "syscall", - "syscall.IPV6_MAX_SOCK_SRC_FILTER": "syscall", - "syscall.IPV6_MIN_MEMBERSHIPS": "syscall", - "syscall.IPV6_MMTU": "syscall", - "syscall.IPV6_MSFILTER": "syscall", - "syscall.IPV6_MTU": "syscall", - "syscall.IPV6_MTU_DISCOVER": "syscall", - "syscall.IPV6_MULTICAST_HOPS": "syscall", - "syscall.IPV6_MULTICAST_IF": "syscall", - "syscall.IPV6_MULTICAST_LOOP": "syscall", - "syscall.IPV6_NEXTHOP": "syscall", - "syscall.IPV6_OPTIONS": "syscall", - "syscall.IPV6_PATHMTU": "syscall", - "syscall.IPV6_PIPEX": "syscall", - "syscall.IPV6_PKTINFO": "syscall", - "syscall.IPV6_PMTUDISC_DO": "syscall", - "syscall.IPV6_PMTUDISC_DONT": "syscall", - "syscall.IPV6_PMTUDISC_PROBE": "syscall", - "syscall.IPV6_PMTUDISC_WANT": "syscall", - "syscall.IPV6_PORTRANGE": "syscall", - "syscall.IPV6_PORTRANGE_DEFAULT": "syscall", - "syscall.IPV6_PORTRANGE_HIGH": "syscall", - "syscall.IPV6_PORTRANGE_LOW": "syscall", - "syscall.IPV6_PREFER_TEMPADDR": "syscall", - "syscall.IPV6_RECVDSTOPTS": "syscall", - "syscall.IPV6_RECVDSTPORT": "syscall", - "syscall.IPV6_RECVERR": "syscall", - "syscall.IPV6_RECVHOPLIMIT": "syscall", - "syscall.IPV6_RECVHOPOPTS": "syscall", - "syscall.IPV6_RECVPATHMTU": "syscall", - "syscall.IPV6_RECVPKTINFO": "syscall", - "syscall.IPV6_RECVRTHDR": "syscall", - "syscall.IPV6_RECVTCLASS": "syscall", - "syscall.IPV6_ROUTER_ALERT": "syscall", - "syscall.IPV6_RTABLE": "syscall", - "syscall.IPV6_RTHDR": "syscall", - "syscall.IPV6_RTHDRDSTOPTS": "syscall", - "syscall.IPV6_RTHDR_LOOSE": "syscall", - "syscall.IPV6_RTHDR_STRICT": "syscall", - "syscall.IPV6_RTHDR_TYPE_0": "syscall", - "syscall.IPV6_RXDSTOPTS": "syscall", - "syscall.IPV6_RXHOPOPTS": "syscall", - "syscall.IPV6_SOCKOPT_RESERVED1": "syscall", - "syscall.IPV6_TCLASS": "syscall", - "syscall.IPV6_UNICAST_HOPS": "syscall", - "syscall.IPV6_USE_MIN_MTU": "syscall", - "syscall.IPV6_V6ONLY": "syscall", - "syscall.IPV6_VERSION": "syscall", - "syscall.IPV6_VERSION_MASK": "syscall", - "syscall.IPV6_XFRM_POLICY": "syscall", - "syscall.IP_ADD_MEMBERSHIP": "syscall", - "syscall.IP_ADD_SOURCE_MEMBERSHIP": "syscall", - "syscall.IP_AUTH_LEVEL": "syscall", - "syscall.IP_BINDANY": "syscall", - "syscall.IP_BLOCK_SOURCE": "syscall", - "syscall.IP_BOUND_IF": "syscall", - "syscall.IP_DEFAULT_MULTICAST_LOOP": "syscall", - "syscall.IP_DEFAULT_MULTICAST_TTL": "syscall", - "syscall.IP_DF": "syscall", - "syscall.IP_DIVERTFL": "syscall", - "syscall.IP_DONTFRAG": "syscall", - "syscall.IP_DROP_MEMBERSHIP": "syscall", - "syscall.IP_DROP_SOURCE_MEMBERSHIP": "syscall", - "syscall.IP_DUMMYNET3": "syscall", - "syscall.IP_DUMMYNET_CONFIGURE": "syscall", - "syscall.IP_DUMMYNET_DEL": "syscall", - "syscall.IP_DUMMYNET_FLUSH": "syscall", - "syscall.IP_DUMMYNET_GET": "syscall", - "syscall.IP_EF": "syscall", - "syscall.IP_ERRORMTU": "syscall", - "syscall.IP_ESP_NETWORK_LEVEL": "syscall", - "syscall.IP_ESP_TRANS_LEVEL": "syscall", - "syscall.IP_FAITH": "syscall", - "syscall.IP_FREEBIND": "syscall", - "syscall.IP_FW3": "syscall", - "syscall.IP_FW_ADD": "syscall", - "syscall.IP_FW_DEL": "syscall", - "syscall.IP_FW_FLUSH": "syscall", - "syscall.IP_FW_GET": "syscall", - "syscall.IP_FW_NAT_CFG": "syscall", - "syscall.IP_FW_NAT_DEL": "syscall", - "syscall.IP_FW_NAT_GET_CONFIG": "syscall", - "syscall.IP_FW_NAT_GET_LOG": "syscall", - "syscall.IP_FW_RESETLOG": "syscall", - "syscall.IP_FW_TABLE_ADD": "syscall", - "syscall.IP_FW_TABLE_DEL": "syscall", - "syscall.IP_FW_TABLE_FLUSH": "syscall", - "syscall.IP_FW_TABLE_GETSIZE": "syscall", - "syscall.IP_FW_TABLE_LIST": "syscall", - "syscall.IP_FW_ZERO": "syscall", - "syscall.IP_HDRINCL": "syscall", - "syscall.IP_IPCOMP_LEVEL": "syscall", - "syscall.IP_IPSECFLOWINFO": "syscall", - "syscall.IP_IPSEC_LOCAL_AUTH": "syscall", - "syscall.IP_IPSEC_LOCAL_CRED": "syscall", - "syscall.IP_IPSEC_LOCAL_ID": "syscall", - "syscall.IP_IPSEC_POLICY": "syscall", - "syscall.IP_IPSEC_REMOTE_AUTH": "syscall", - "syscall.IP_IPSEC_REMOTE_CRED": "syscall", - "syscall.IP_IPSEC_REMOTE_ID": "syscall", - "syscall.IP_MAXPACKET": "syscall", - "syscall.IP_MAX_GROUP_SRC_FILTER": "syscall", - "syscall.IP_MAX_MEMBERSHIPS": "syscall", - "syscall.IP_MAX_SOCK_MUTE_FILTER": "syscall", - "syscall.IP_MAX_SOCK_SRC_FILTER": "syscall", - "syscall.IP_MAX_SOURCE_FILTER": "syscall", - "syscall.IP_MF": "syscall", - "syscall.IP_MINFRAGSIZE": "syscall", - "syscall.IP_MINTTL": "syscall", - "syscall.IP_MIN_MEMBERSHIPS": "syscall", - "syscall.IP_MSFILTER": "syscall", - "syscall.IP_MSS": "syscall", - "syscall.IP_MTU": "syscall", - "syscall.IP_MTU_DISCOVER": "syscall", - "syscall.IP_MULTICAST_IF": "syscall", - "syscall.IP_MULTICAST_IFINDEX": "syscall", - "syscall.IP_MULTICAST_LOOP": "syscall", - "syscall.IP_MULTICAST_TTL": "syscall", - "syscall.IP_MULTICAST_VIF": "syscall", - "syscall.IP_NAT__XXX": "syscall", - "syscall.IP_OFFMASK": "syscall", - "syscall.IP_OLD_FW_ADD": "syscall", - "syscall.IP_OLD_FW_DEL": "syscall", - "syscall.IP_OLD_FW_FLUSH": "syscall", - "syscall.IP_OLD_FW_GET": "syscall", - "syscall.IP_OLD_FW_RESETLOG": "syscall", - "syscall.IP_OLD_FW_ZERO": "syscall", - "syscall.IP_ONESBCAST": "syscall", - "syscall.IP_OPTIONS": "syscall", - "syscall.IP_ORIGDSTADDR": "syscall", - "syscall.IP_PASSSEC": "syscall", - "syscall.IP_PIPEX": "syscall", - "syscall.IP_PKTINFO": "syscall", - "syscall.IP_PKTOPTIONS": "syscall", - "syscall.IP_PMTUDISC": "syscall", - "syscall.IP_PMTUDISC_DO": "syscall", - "syscall.IP_PMTUDISC_DONT": "syscall", - "syscall.IP_PMTUDISC_PROBE": "syscall", - "syscall.IP_PMTUDISC_WANT": "syscall", - "syscall.IP_PORTRANGE": "syscall", - "syscall.IP_PORTRANGE_DEFAULT": "syscall", - "syscall.IP_PORTRANGE_HIGH": "syscall", - "syscall.IP_PORTRANGE_LOW": "syscall", - "syscall.IP_RECVDSTADDR": "syscall", - "syscall.IP_RECVDSTPORT": "syscall", - "syscall.IP_RECVERR": "syscall", - "syscall.IP_RECVIF": "syscall", - "syscall.IP_RECVOPTS": "syscall", - "syscall.IP_RECVORIGDSTADDR": "syscall", - "syscall.IP_RECVPKTINFO": "syscall", - "syscall.IP_RECVRETOPTS": "syscall", - "syscall.IP_RECVRTABLE": "syscall", - "syscall.IP_RECVTOS": "syscall", - "syscall.IP_RECVTTL": "syscall", - "syscall.IP_RETOPTS": "syscall", - "syscall.IP_RF": "syscall", - "syscall.IP_ROUTER_ALERT": "syscall", - "syscall.IP_RSVP_OFF": "syscall", - "syscall.IP_RSVP_ON": "syscall", - "syscall.IP_RSVP_VIF_OFF": "syscall", - "syscall.IP_RSVP_VIF_ON": "syscall", - "syscall.IP_RTABLE": "syscall", - "syscall.IP_SENDSRCADDR": "syscall", - "syscall.IP_STRIPHDR": "syscall", - "syscall.IP_TOS": "syscall", - "syscall.IP_TRAFFIC_MGT_BACKGROUND": "syscall", - "syscall.IP_TRANSPARENT": "syscall", - "syscall.IP_TTL": "syscall", - "syscall.IP_UNBLOCK_SOURCE": "syscall", - "syscall.IP_XFRM_POLICY": "syscall", - "syscall.IPv6MTUInfo": "syscall", - "syscall.IPv6Mreq": "syscall", - "syscall.ISIG": "syscall", - "syscall.ISTRIP": "syscall", - "syscall.IUCLC": "syscall", - "syscall.IUTF8": "syscall", - "syscall.IXANY": "syscall", - "syscall.IXOFF": "syscall", - "syscall.IXON": "syscall", - "syscall.IfAddrmsg": "syscall", - "syscall.IfAnnounceMsghdr": "syscall", - "syscall.IfData": "syscall", - "syscall.IfInfomsg": "syscall", - "syscall.IfMsghdr": "syscall", - "syscall.IfaMsghdr": "syscall", - "syscall.IfmaMsghdr": "syscall", - "syscall.IfmaMsghdr2": "syscall", - "syscall.ImplementsGetwd": "syscall", - "syscall.Inet4Pktinfo": "syscall", - "syscall.Inet6Pktinfo": "syscall", - "syscall.InotifyAddWatch": "syscall", - "syscall.InotifyEvent": "syscall", - "syscall.InotifyInit": "syscall", - "syscall.InotifyInit1": "syscall", - "syscall.InotifyRmWatch": "syscall", - "syscall.InterfaceAddrMessage": "syscall", - "syscall.InterfaceAnnounceMessage": "syscall", - "syscall.InterfaceInfo": "syscall", - "syscall.InterfaceMessage": "syscall", - "syscall.InterfaceMulticastAddrMessage": "syscall", - "syscall.InvalidHandle": "syscall", - "syscall.Ioperm": "syscall", - "syscall.Iopl": "syscall", - "syscall.Iovec": "syscall", - "syscall.IpAdapterInfo": "syscall", - "syscall.IpAddrString": "syscall", - "syscall.IpAddressString": "syscall", - "syscall.IpMaskString": "syscall", - "syscall.Issetugid": "syscall", - "syscall.KEY_ALL_ACCESS": "syscall", - "syscall.KEY_CREATE_LINK": "syscall", - "syscall.KEY_CREATE_SUB_KEY": "syscall", - "syscall.KEY_ENUMERATE_SUB_KEYS": "syscall", - "syscall.KEY_EXECUTE": "syscall", - "syscall.KEY_NOTIFY": "syscall", - "syscall.KEY_QUERY_VALUE": "syscall", - "syscall.KEY_READ": "syscall", - "syscall.KEY_SET_VALUE": "syscall", - "syscall.KEY_WOW64_32KEY": "syscall", - "syscall.KEY_WOW64_64KEY": "syscall", - "syscall.KEY_WRITE": "syscall", - "syscall.Kevent": "syscall", - "syscall.Kevent_t": "syscall", - "syscall.Kill": "syscall", - "syscall.Klogctl": "syscall", - "syscall.Kqueue": "syscall", - "syscall.LANG_ENGLISH": "syscall", - "syscall.LAYERED_PROTOCOL": "syscall", - "syscall.LCNT_OVERLOAD_FLUSH": "syscall", - "syscall.LINUX_REBOOT_CMD_CAD_OFF": "syscall", - "syscall.LINUX_REBOOT_CMD_CAD_ON": "syscall", - "syscall.LINUX_REBOOT_CMD_HALT": "syscall", - "syscall.LINUX_REBOOT_CMD_KEXEC": "syscall", - "syscall.LINUX_REBOOT_CMD_POWER_OFF": "syscall", - "syscall.LINUX_REBOOT_CMD_RESTART": "syscall", - "syscall.LINUX_REBOOT_CMD_RESTART2": "syscall", - "syscall.LINUX_REBOOT_CMD_SW_SUSPEND": "syscall", - "syscall.LINUX_REBOOT_MAGIC1": "syscall", - "syscall.LINUX_REBOOT_MAGIC2": "syscall", - "syscall.LOCK_EX": "syscall", - "syscall.LOCK_NB": "syscall", - "syscall.LOCK_SH": "syscall", - "syscall.LOCK_UN": "syscall", - "syscall.LazyDLL": "syscall", - "syscall.LazyProc": "syscall", - "syscall.Lchown": "syscall", - "syscall.Linger": "syscall", - "syscall.Link": "syscall", - "syscall.Listen": "syscall", - "syscall.Listxattr": "syscall", - "syscall.LoadCancelIoEx": "syscall", - "syscall.LoadConnectEx": "syscall", - "syscall.LoadCreateSymbolicLink": "syscall", - "syscall.LoadDLL": "syscall", - "syscall.LoadGetAddrInfo": "syscall", - "syscall.LoadLibrary": "syscall", - "syscall.LoadSetFileCompletionNotificationModes": "syscall", - "syscall.LocalFree": "syscall", - "syscall.Log2phys_t": "syscall", - "syscall.LookupAccountName": "syscall", - "syscall.LookupAccountSid": "syscall", - "syscall.LookupSID": "syscall", - "syscall.LsfJump": "syscall", - "syscall.LsfSocket": "syscall", - "syscall.LsfStmt": "syscall", - "syscall.Lstat": "syscall", - "syscall.MADV_AUTOSYNC": "syscall", - "syscall.MADV_CAN_REUSE": "syscall", - "syscall.MADV_CORE": "syscall", - "syscall.MADV_DOFORK": "syscall", - "syscall.MADV_DONTFORK": "syscall", - "syscall.MADV_DONTNEED": "syscall", - "syscall.MADV_FREE": "syscall", - "syscall.MADV_FREE_REUSABLE": "syscall", - "syscall.MADV_FREE_REUSE": "syscall", - "syscall.MADV_HUGEPAGE": "syscall", - "syscall.MADV_HWPOISON": "syscall", - "syscall.MADV_MERGEABLE": "syscall", - "syscall.MADV_NOCORE": "syscall", - "syscall.MADV_NOHUGEPAGE": "syscall", - "syscall.MADV_NORMAL": "syscall", - "syscall.MADV_NOSYNC": "syscall", - "syscall.MADV_PROTECT": "syscall", - "syscall.MADV_RANDOM": "syscall", - "syscall.MADV_REMOVE": "syscall", - "syscall.MADV_SEQUENTIAL": "syscall", - "syscall.MADV_SPACEAVAIL": "syscall", - "syscall.MADV_UNMERGEABLE": "syscall", - "syscall.MADV_WILLNEED": "syscall", - "syscall.MADV_ZERO_WIRED_PAGES": "syscall", - "syscall.MAP_32BIT": "syscall", - "syscall.MAP_ALIGNED_SUPER": "syscall", - "syscall.MAP_ALIGNMENT_16MB": "syscall", - "syscall.MAP_ALIGNMENT_1TB": "syscall", - "syscall.MAP_ALIGNMENT_256TB": "syscall", - "syscall.MAP_ALIGNMENT_4GB": "syscall", - "syscall.MAP_ALIGNMENT_64KB": "syscall", - "syscall.MAP_ALIGNMENT_64PB": "syscall", - "syscall.MAP_ALIGNMENT_MASK": "syscall", - "syscall.MAP_ALIGNMENT_SHIFT": "syscall", - "syscall.MAP_ANON": "syscall", - "syscall.MAP_ANONYMOUS": "syscall", - "syscall.MAP_COPY": "syscall", - "syscall.MAP_DENYWRITE": "syscall", - "syscall.MAP_EXECUTABLE": "syscall", - "syscall.MAP_FILE": "syscall", - "syscall.MAP_FIXED": "syscall", - "syscall.MAP_FLAGMASK": "syscall", - "syscall.MAP_GROWSDOWN": "syscall", - "syscall.MAP_HASSEMAPHORE": "syscall", - "syscall.MAP_HUGETLB": "syscall", - "syscall.MAP_INHERIT": "syscall", - "syscall.MAP_INHERIT_COPY": "syscall", - "syscall.MAP_INHERIT_DEFAULT": "syscall", - "syscall.MAP_INHERIT_DONATE_COPY": "syscall", - "syscall.MAP_INHERIT_NONE": "syscall", - "syscall.MAP_INHERIT_SHARE": "syscall", - "syscall.MAP_JIT": "syscall", - "syscall.MAP_LOCKED": "syscall", - "syscall.MAP_NOCACHE": "syscall", - "syscall.MAP_NOCORE": "syscall", - "syscall.MAP_NOEXTEND": "syscall", - "syscall.MAP_NONBLOCK": "syscall", - "syscall.MAP_NORESERVE": "syscall", - "syscall.MAP_NOSYNC": "syscall", - "syscall.MAP_POPULATE": "syscall", - "syscall.MAP_PREFAULT_READ": "syscall", - "syscall.MAP_PRIVATE": "syscall", - "syscall.MAP_RENAME": "syscall", - "syscall.MAP_RESERVED0080": "syscall", - "syscall.MAP_RESERVED0100": "syscall", - "syscall.MAP_SHARED": "syscall", - "syscall.MAP_STACK": "syscall", - "syscall.MAP_TRYFIXED": "syscall", - "syscall.MAP_TYPE": "syscall", - "syscall.MAP_WIRED": "syscall", - "syscall.MAXIMUM_REPARSE_DATA_BUFFER_SIZE": "syscall", - "syscall.MAXLEN_IFDESCR": "syscall", - "syscall.MAXLEN_PHYSADDR": "syscall", - "syscall.MAX_ADAPTER_ADDRESS_LENGTH": "syscall", - "syscall.MAX_ADAPTER_DESCRIPTION_LENGTH": "syscall", - "syscall.MAX_ADAPTER_NAME_LENGTH": "syscall", - "syscall.MAX_COMPUTERNAME_LENGTH": "syscall", - "syscall.MAX_INTERFACE_NAME_LEN": "syscall", - "syscall.MAX_LONG_PATH": "syscall", - "syscall.MAX_PATH": "syscall", - "syscall.MAX_PROTOCOL_CHAIN": "syscall", - "syscall.MCL_CURRENT": "syscall", - "syscall.MCL_FUTURE": "syscall", - "syscall.MNT_DETACH": "syscall", - "syscall.MNT_EXPIRE": "syscall", - "syscall.MNT_FORCE": "syscall", - "syscall.MSG_BCAST": "syscall", - "syscall.MSG_CMSG_CLOEXEC": "syscall", - "syscall.MSG_COMPAT": "syscall", - "syscall.MSG_CONFIRM": "syscall", - "syscall.MSG_CONTROLMBUF": "syscall", - "syscall.MSG_CTRUNC": "syscall", - "syscall.MSG_DONTROUTE": "syscall", - "syscall.MSG_DONTWAIT": "syscall", - "syscall.MSG_EOF": "syscall", - "syscall.MSG_EOR": "syscall", - "syscall.MSG_ERRQUEUE": "syscall", - "syscall.MSG_FASTOPEN": "syscall", - "syscall.MSG_FIN": "syscall", - "syscall.MSG_FLUSH": "syscall", - "syscall.MSG_HAVEMORE": "syscall", - "syscall.MSG_HOLD": "syscall", - "syscall.MSG_IOVUSRSPACE": "syscall", - "syscall.MSG_LENUSRSPACE": "syscall", - "syscall.MSG_MCAST": "syscall", - "syscall.MSG_MORE": "syscall", - "syscall.MSG_NAMEMBUF": "syscall", - "syscall.MSG_NBIO": "syscall", - "syscall.MSG_NEEDSA": "syscall", - "syscall.MSG_NOSIGNAL": "syscall", - "syscall.MSG_NOTIFICATION": "syscall", - "syscall.MSG_OOB": "syscall", - "syscall.MSG_PEEK": "syscall", - "syscall.MSG_PROXY": "syscall", - "syscall.MSG_RCVMORE": "syscall", - "syscall.MSG_RST": "syscall", - "syscall.MSG_SEND": "syscall", - "syscall.MSG_SYN": "syscall", - "syscall.MSG_TRUNC": "syscall", - "syscall.MSG_TRYHARD": "syscall", - "syscall.MSG_USERFLAGS": "syscall", - "syscall.MSG_WAITALL": "syscall", - "syscall.MSG_WAITFORONE": "syscall", - "syscall.MSG_WAITSTREAM": "syscall", - "syscall.MS_ACTIVE": "syscall", - "syscall.MS_ASYNC": "syscall", - "syscall.MS_BIND": "syscall", - "syscall.MS_DEACTIVATE": "syscall", - "syscall.MS_DIRSYNC": "syscall", - "syscall.MS_INVALIDATE": "syscall", - "syscall.MS_I_VERSION": "syscall", - "syscall.MS_KERNMOUNT": "syscall", - "syscall.MS_KILLPAGES": "syscall", - "syscall.MS_MANDLOCK": "syscall", - "syscall.MS_MGC_MSK": "syscall", - "syscall.MS_MGC_VAL": "syscall", - "syscall.MS_MOVE": "syscall", - "syscall.MS_NOATIME": "syscall", - "syscall.MS_NODEV": "syscall", - "syscall.MS_NODIRATIME": "syscall", - "syscall.MS_NOEXEC": "syscall", - "syscall.MS_NOSUID": "syscall", - "syscall.MS_NOUSER": "syscall", - "syscall.MS_POSIXACL": "syscall", - "syscall.MS_PRIVATE": "syscall", - "syscall.MS_RDONLY": "syscall", - "syscall.MS_REC": "syscall", - "syscall.MS_RELATIME": "syscall", - "syscall.MS_REMOUNT": "syscall", - "syscall.MS_RMT_MASK": "syscall", - "syscall.MS_SHARED": "syscall", - "syscall.MS_SILENT": "syscall", - "syscall.MS_SLAVE": "syscall", - "syscall.MS_STRICTATIME": "syscall", - "syscall.MS_SYNC": "syscall", - "syscall.MS_SYNCHRONOUS": "syscall", - "syscall.MS_UNBINDABLE": "syscall", - "syscall.Madvise": "syscall", - "syscall.MapViewOfFile": "syscall", - "syscall.MaxTokenInfoClass": "syscall", - "syscall.Mclpool": "syscall", - "syscall.MibIfRow": "syscall", - "syscall.Mkdir": "syscall", - "syscall.Mkdirat": "syscall", - "syscall.Mkfifo": "syscall", - "syscall.Mknod": "syscall", - "syscall.Mknodat": "syscall", - "syscall.Mlock": "syscall", - "syscall.Mlockall": "syscall", - "syscall.Mmap": "syscall", - "syscall.Mount": "syscall", - "syscall.MoveFile": "syscall", - "syscall.Mprotect": "syscall", - "syscall.Msghdr": "syscall", - "syscall.Munlock": "syscall", - "syscall.Munlockall": "syscall", - "syscall.Munmap": "syscall", - "syscall.MustLoadDLL": "syscall", - "syscall.NAME_MAX": "syscall", - "syscall.NETLINK_ADD_MEMBERSHIP": "syscall", - "syscall.NETLINK_AUDIT": "syscall", - "syscall.NETLINK_BROADCAST_ERROR": "syscall", - "syscall.NETLINK_CONNECTOR": "syscall", - "syscall.NETLINK_DNRTMSG": "syscall", - "syscall.NETLINK_DROP_MEMBERSHIP": "syscall", - "syscall.NETLINK_ECRYPTFS": "syscall", - "syscall.NETLINK_FIB_LOOKUP": "syscall", - "syscall.NETLINK_FIREWALL": "syscall", - "syscall.NETLINK_GENERIC": "syscall", - "syscall.NETLINK_INET_DIAG": "syscall", - "syscall.NETLINK_IP6_FW": "syscall", - "syscall.NETLINK_ISCSI": "syscall", - "syscall.NETLINK_KOBJECT_UEVENT": "syscall", - "syscall.NETLINK_NETFILTER": "syscall", - "syscall.NETLINK_NFLOG": "syscall", - "syscall.NETLINK_NO_ENOBUFS": "syscall", - "syscall.NETLINK_PKTINFO": "syscall", - "syscall.NETLINK_RDMA": "syscall", - "syscall.NETLINK_ROUTE": "syscall", - "syscall.NETLINK_SCSITRANSPORT": "syscall", - "syscall.NETLINK_SELINUX": "syscall", - "syscall.NETLINK_UNUSED": "syscall", - "syscall.NETLINK_USERSOCK": "syscall", - "syscall.NETLINK_XFRM": "syscall", - "syscall.NET_RT_DUMP": "syscall", - "syscall.NET_RT_DUMP2": "syscall", - "syscall.NET_RT_FLAGS": "syscall", - "syscall.NET_RT_IFLIST": "syscall", - "syscall.NET_RT_IFLIST2": "syscall", - "syscall.NET_RT_IFLISTL": "syscall", - "syscall.NET_RT_IFMALIST": "syscall", - "syscall.NET_RT_MAXID": "syscall", - "syscall.NET_RT_OIFLIST": "syscall", - "syscall.NET_RT_OOIFLIST": "syscall", - "syscall.NET_RT_STAT": "syscall", - "syscall.NET_RT_STATS": "syscall", - "syscall.NET_RT_TABLE": "syscall", - "syscall.NET_RT_TRASH": "syscall", - "syscall.NLA_ALIGNTO": "syscall", - "syscall.NLA_F_NESTED": "syscall", - "syscall.NLA_F_NET_BYTEORDER": "syscall", - "syscall.NLA_HDRLEN": "syscall", - "syscall.NLMSG_ALIGNTO": "syscall", - "syscall.NLMSG_DONE": "syscall", - "syscall.NLMSG_ERROR": "syscall", - "syscall.NLMSG_HDRLEN": "syscall", - "syscall.NLMSG_MIN_TYPE": "syscall", - "syscall.NLMSG_NOOP": "syscall", - "syscall.NLMSG_OVERRUN": "syscall", - "syscall.NLM_F_ACK": "syscall", - "syscall.NLM_F_APPEND": "syscall", - "syscall.NLM_F_ATOMIC": "syscall", - "syscall.NLM_F_CREATE": "syscall", - "syscall.NLM_F_DUMP": "syscall", - "syscall.NLM_F_ECHO": "syscall", - "syscall.NLM_F_EXCL": "syscall", - "syscall.NLM_F_MATCH": "syscall", - "syscall.NLM_F_MULTI": "syscall", - "syscall.NLM_F_REPLACE": "syscall", - "syscall.NLM_F_REQUEST": "syscall", - "syscall.NLM_F_ROOT": "syscall", - "syscall.NOFLSH": "syscall", - "syscall.NOTE_ABSOLUTE": "syscall", - "syscall.NOTE_ATTRIB": "syscall", - "syscall.NOTE_CHILD": "syscall", - "syscall.NOTE_DELETE": "syscall", - "syscall.NOTE_EOF": "syscall", - "syscall.NOTE_EXEC": "syscall", - "syscall.NOTE_EXIT": "syscall", - "syscall.NOTE_EXITSTATUS": "syscall", - "syscall.NOTE_EXTEND": "syscall", - "syscall.NOTE_FFAND": "syscall", - "syscall.NOTE_FFCOPY": "syscall", - "syscall.NOTE_FFCTRLMASK": "syscall", - "syscall.NOTE_FFLAGSMASK": "syscall", - "syscall.NOTE_FFNOP": "syscall", - "syscall.NOTE_FFOR": "syscall", - "syscall.NOTE_FORK": "syscall", - "syscall.NOTE_LINK": "syscall", - "syscall.NOTE_LOWAT": "syscall", - "syscall.NOTE_NONE": "syscall", - "syscall.NOTE_NSECONDS": "syscall", - "syscall.NOTE_PCTRLMASK": "syscall", - "syscall.NOTE_PDATAMASK": "syscall", - "syscall.NOTE_REAP": "syscall", - "syscall.NOTE_RENAME": "syscall", - "syscall.NOTE_RESOURCEEND": "syscall", - "syscall.NOTE_REVOKE": "syscall", - "syscall.NOTE_SECONDS": "syscall", - "syscall.NOTE_SIGNAL": "syscall", - "syscall.NOTE_TRACK": "syscall", - "syscall.NOTE_TRACKERR": "syscall", - "syscall.NOTE_TRIGGER": "syscall", - "syscall.NOTE_TRUNCATE": "syscall", - "syscall.NOTE_USECONDS": "syscall", - "syscall.NOTE_VM_ERROR": "syscall", - "syscall.NOTE_VM_PRESSURE": "syscall", - "syscall.NOTE_VM_PRESSURE_SUDDEN_TERMINATE": "syscall", - "syscall.NOTE_VM_PRESSURE_TERMINATE": "syscall", - "syscall.NOTE_WRITE": "syscall", - "syscall.NameCanonical": "syscall", - "syscall.NameCanonicalEx": "syscall", - "syscall.NameDisplay": "syscall", - "syscall.NameDnsDomain": "syscall", - "syscall.NameFullyQualifiedDN": "syscall", - "syscall.NameSamCompatible": "syscall", - "syscall.NameServicePrincipal": "syscall", - "syscall.NameUniqueId": "syscall", - "syscall.NameUnknown": "syscall", - "syscall.NameUserPrincipal": "syscall", - "syscall.Nanosleep": "syscall", - "syscall.NetApiBufferFree": "syscall", - "syscall.NetGetJoinInformation": "syscall", - "syscall.NetSetupDomainName": "syscall", - "syscall.NetSetupUnjoined": "syscall", - "syscall.NetSetupUnknownStatus": "syscall", - "syscall.NetSetupWorkgroupName": "syscall", - "syscall.NetUserGetInfo": "syscall", - "syscall.NetlinkMessage": "syscall", - "syscall.NetlinkRIB": "syscall", - "syscall.NetlinkRouteAttr": "syscall", - "syscall.NetlinkRouteRequest": "syscall", - "syscall.NewCallback": "syscall", - "syscall.NewCallbackCDecl": "syscall", - "syscall.NewLazyDLL": "syscall", - "syscall.NlAttr": "syscall", - "syscall.NlMsgerr": "syscall", - "syscall.NlMsghdr": "syscall", - "syscall.NsecToFiletime": "syscall", - "syscall.NsecToTimespec": "syscall", - "syscall.NsecToTimeval": "syscall", - "syscall.Ntohs": "syscall", - "syscall.OCRNL": "syscall", - "syscall.OFDEL": "syscall", - "syscall.OFILL": "syscall", - "syscall.OFIOGETBMAP": "syscall", - "syscall.OID_PKIX_KP_SERVER_AUTH": "syscall", - "syscall.OID_SERVER_GATED_CRYPTO": "syscall", - "syscall.OID_SGC_NETSCAPE": "syscall", - "syscall.OLCUC": "syscall", - "syscall.ONLCR": "syscall", - "syscall.ONLRET": "syscall", - "syscall.ONOCR": "syscall", - "syscall.ONOEOT": "syscall", - "syscall.OPEN_ALWAYS": "syscall", - "syscall.OPEN_EXISTING": "syscall", - "syscall.OPOST": "syscall", - "syscall.O_ACCMODE": "syscall", - "syscall.O_ALERT": "syscall", - "syscall.O_ALT_IO": "syscall", - "syscall.O_APPEND": "syscall", - "syscall.O_ASYNC": "syscall", - "syscall.O_CLOEXEC": "syscall", - "syscall.O_CREAT": "syscall", - "syscall.O_DIRECT": "syscall", - "syscall.O_DIRECTORY": "syscall", - "syscall.O_DSYNC": "syscall", - "syscall.O_EVTONLY": "syscall", - "syscall.O_EXCL": "syscall", - "syscall.O_EXEC": "syscall", - "syscall.O_EXLOCK": "syscall", - "syscall.O_FSYNC": "syscall", - "syscall.O_LARGEFILE": "syscall", - "syscall.O_NDELAY": "syscall", - "syscall.O_NOATIME": "syscall", - "syscall.O_NOCTTY": "syscall", - "syscall.O_NOFOLLOW": "syscall", - "syscall.O_NONBLOCK": "syscall", - "syscall.O_NOSIGPIPE": "syscall", - "syscall.O_POPUP": "syscall", - "syscall.O_RDONLY": "syscall", - "syscall.O_RDWR": "syscall", - "syscall.O_RSYNC": "syscall", - "syscall.O_SHLOCK": "syscall", - "syscall.O_SYMLINK": "syscall", - "syscall.O_SYNC": "syscall", - "syscall.O_TRUNC": "syscall", - "syscall.O_TTY_INIT": "syscall", - "syscall.O_WRONLY": "syscall", - "syscall.Open": "syscall", - "syscall.OpenCurrentProcessToken": "syscall", - "syscall.OpenProcess": "syscall", - "syscall.OpenProcessToken": "syscall", - "syscall.Openat": "syscall", - "syscall.Overlapped": "syscall", - "syscall.PACKET_ADD_MEMBERSHIP": "syscall", - "syscall.PACKET_BROADCAST": "syscall", - "syscall.PACKET_DROP_MEMBERSHIP": "syscall", - "syscall.PACKET_FASTROUTE": "syscall", - "syscall.PACKET_HOST": "syscall", - "syscall.PACKET_LOOPBACK": "syscall", - "syscall.PACKET_MR_ALLMULTI": "syscall", - "syscall.PACKET_MR_MULTICAST": "syscall", - "syscall.PACKET_MR_PROMISC": "syscall", - "syscall.PACKET_MULTICAST": "syscall", - "syscall.PACKET_OTHERHOST": "syscall", - "syscall.PACKET_OUTGOING": "syscall", - "syscall.PACKET_RECV_OUTPUT": "syscall", - "syscall.PACKET_RX_RING": "syscall", - "syscall.PACKET_STATISTICS": "syscall", - "syscall.PAGE_EXECUTE_READ": "syscall", - "syscall.PAGE_EXECUTE_READWRITE": "syscall", - "syscall.PAGE_EXECUTE_WRITECOPY": "syscall", - "syscall.PAGE_READONLY": "syscall", - "syscall.PAGE_READWRITE": "syscall", - "syscall.PAGE_WRITECOPY": "syscall", - "syscall.PARENB": "syscall", - "syscall.PARMRK": "syscall", - "syscall.PARODD": "syscall", - "syscall.PENDIN": "syscall", - "syscall.PFL_HIDDEN": "syscall", - "syscall.PFL_MATCHES_PROTOCOL_ZERO": "syscall", - "syscall.PFL_MULTIPLE_PROTO_ENTRIES": "syscall", - "syscall.PFL_NETWORKDIRECT_PROVIDER": "syscall", - "syscall.PFL_RECOMMENDED_PROTO_ENTRY": "syscall", - "syscall.PF_FLUSH": "syscall", - "syscall.PKCS_7_ASN_ENCODING": "syscall", - "syscall.PMC5_PIPELINE_FLUSH": "syscall", - "syscall.PRIO_PGRP": "syscall", - "syscall.PRIO_PROCESS": "syscall", - "syscall.PRIO_USER": "syscall", - "syscall.PRI_IOFLUSH": "syscall", - "syscall.PROCESS_QUERY_INFORMATION": "syscall", - "syscall.PROCESS_TERMINATE": "syscall", - "syscall.PROT_EXEC": "syscall", - "syscall.PROT_GROWSDOWN": "syscall", - "syscall.PROT_GROWSUP": "syscall", - "syscall.PROT_NONE": "syscall", - "syscall.PROT_READ": "syscall", - "syscall.PROT_WRITE": "syscall", - "syscall.PROV_DH_SCHANNEL": "syscall", - "syscall.PROV_DSS": "syscall", - "syscall.PROV_DSS_DH": "syscall", - "syscall.PROV_EC_ECDSA_FULL": "syscall", - "syscall.PROV_EC_ECDSA_SIG": "syscall", - "syscall.PROV_EC_ECNRA_FULL": "syscall", - "syscall.PROV_EC_ECNRA_SIG": "syscall", - "syscall.PROV_FORTEZZA": "syscall", - "syscall.PROV_INTEL_SEC": "syscall", - "syscall.PROV_MS_EXCHANGE": "syscall", - "syscall.PROV_REPLACE_OWF": "syscall", - "syscall.PROV_RNG": "syscall", - "syscall.PROV_RSA_AES": "syscall", - "syscall.PROV_RSA_FULL": "syscall", - "syscall.PROV_RSA_SCHANNEL": "syscall", - "syscall.PROV_RSA_SIG": "syscall", - "syscall.PROV_SPYRUS_LYNKS": "syscall", - "syscall.PROV_SSL": "syscall", - "syscall.PR_CAPBSET_DROP": "syscall", - "syscall.PR_CAPBSET_READ": "syscall", - "syscall.PR_CLEAR_SECCOMP_FILTER": "syscall", - "syscall.PR_ENDIAN_BIG": "syscall", - "syscall.PR_ENDIAN_LITTLE": "syscall", - "syscall.PR_ENDIAN_PPC_LITTLE": "syscall", - "syscall.PR_FPEMU_NOPRINT": "syscall", - "syscall.PR_FPEMU_SIGFPE": "syscall", - "syscall.PR_FP_EXC_ASYNC": "syscall", - "syscall.PR_FP_EXC_DISABLED": "syscall", - "syscall.PR_FP_EXC_DIV": "syscall", - "syscall.PR_FP_EXC_INV": "syscall", - "syscall.PR_FP_EXC_NONRECOV": "syscall", - "syscall.PR_FP_EXC_OVF": "syscall", - "syscall.PR_FP_EXC_PRECISE": "syscall", - "syscall.PR_FP_EXC_RES": "syscall", - "syscall.PR_FP_EXC_SW_ENABLE": "syscall", - "syscall.PR_FP_EXC_UND": "syscall", - "syscall.PR_GET_DUMPABLE": "syscall", - "syscall.PR_GET_ENDIAN": "syscall", - "syscall.PR_GET_FPEMU": "syscall", - "syscall.PR_GET_FPEXC": "syscall", - "syscall.PR_GET_KEEPCAPS": "syscall", - "syscall.PR_GET_NAME": "syscall", - "syscall.PR_GET_PDEATHSIG": "syscall", - "syscall.PR_GET_SECCOMP": "syscall", - "syscall.PR_GET_SECCOMP_FILTER": "syscall", - "syscall.PR_GET_SECUREBITS": "syscall", - "syscall.PR_GET_TIMERSLACK": "syscall", - "syscall.PR_GET_TIMING": "syscall", - "syscall.PR_GET_TSC": "syscall", - "syscall.PR_GET_UNALIGN": "syscall", - "syscall.PR_MCE_KILL": "syscall", - "syscall.PR_MCE_KILL_CLEAR": "syscall", - "syscall.PR_MCE_KILL_DEFAULT": "syscall", - "syscall.PR_MCE_KILL_EARLY": "syscall", - "syscall.PR_MCE_KILL_GET": "syscall", - "syscall.PR_MCE_KILL_LATE": "syscall", - "syscall.PR_MCE_KILL_SET": "syscall", - "syscall.PR_SECCOMP_FILTER_EVENT": "syscall", - "syscall.PR_SECCOMP_FILTER_SYSCALL": "syscall", - "syscall.PR_SET_DUMPABLE": "syscall", - "syscall.PR_SET_ENDIAN": "syscall", - "syscall.PR_SET_FPEMU": "syscall", - "syscall.PR_SET_FPEXC": "syscall", - "syscall.PR_SET_KEEPCAPS": "syscall", - "syscall.PR_SET_NAME": "syscall", - "syscall.PR_SET_PDEATHSIG": "syscall", - "syscall.PR_SET_PTRACER": "syscall", - "syscall.PR_SET_SECCOMP": "syscall", - "syscall.PR_SET_SECCOMP_FILTER": "syscall", - "syscall.PR_SET_SECUREBITS": "syscall", - "syscall.PR_SET_TIMERSLACK": "syscall", - "syscall.PR_SET_TIMING": "syscall", - "syscall.PR_SET_TSC": "syscall", - "syscall.PR_SET_UNALIGN": "syscall", - "syscall.PR_TASK_PERF_EVENTS_DISABLE": "syscall", - "syscall.PR_TASK_PERF_EVENTS_ENABLE": "syscall", - "syscall.PR_TIMING_STATISTICAL": "syscall", - "syscall.PR_TIMING_TIMESTAMP": "syscall", - "syscall.PR_TSC_ENABLE": "syscall", - "syscall.PR_TSC_SIGSEGV": "syscall", - "syscall.PR_UNALIGN_NOPRINT": "syscall", - "syscall.PR_UNALIGN_SIGBUS": "syscall", - "syscall.PTRACE_ARCH_PRCTL": "syscall", - "syscall.PTRACE_ATTACH": "syscall", - "syscall.PTRACE_CONT": "syscall", - "syscall.PTRACE_DETACH": "syscall", - "syscall.PTRACE_EVENT_CLONE": "syscall", - "syscall.PTRACE_EVENT_EXEC": "syscall", - "syscall.PTRACE_EVENT_EXIT": "syscall", - "syscall.PTRACE_EVENT_FORK": "syscall", - "syscall.PTRACE_EVENT_VFORK": "syscall", - "syscall.PTRACE_EVENT_VFORK_DONE": "syscall", - "syscall.PTRACE_GETCRUNCHREGS": "syscall", - "syscall.PTRACE_GETEVENTMSG": "syscall", - "syscall.PTRACE_GETFPREGS": "syscall", - "syscall.PTRACE_GETFPXREGS": "syscall", - "syscall.PTRACE_GETHBPREGS": "syscall", - "syscall.PTRACE_GETREGS": "syscall", - "syscall.PTRACE_GETREGSET": "syscall", - "syscall.PTRACE_GETSIGINFO": "syscall", - "syscall.PTRACE_GETVFPREGS": "syscall", - "syscall.PTRACE_GETWMMXREGS": "syscall", - "syscall.PTRACE_GET_THREAD_AREA": "syscall", - "syscall.PTRACE_KILL": "syscall", - "syscall.PTRACE_OLDSETOPTIONS": "syscall", - "syscall.PTRACE_O_MASK": "syscall", - "syscall.PTRACE_O_TRACECLONE": "syscall", - "syscall.PTRACE_O_TRACEEXEC": "syscall", - "syscall.PTRACE_O_TRACEEXIT": "syscall", - "syscall.PTRACE_O_TRACEFORK": "syscall", - "syscall.PTRACE_O_TRACESYSGOOD": "syscall", - "syscall.PTRACE_O_TRACEVFORK": "syscall", - "syscall.PTRACE_O_TRACEVFORKDONE": "syscall", - "syscall.PTRACE_PEEKDATA": "syscall", - "syscall.PTRACE_PEEKTEXT": "syscall", - "syscall.PTRACE_PEEKUSR": "syscall", - "syscall.PTRACE_POKEDATA": "syscall", - "syscall.PTRACE_POKETEXT": "syscall", - "syscall.PTRACE_POKEUSR": "syscall", - "syscall.PTRACE_SETCRUNCHREGS": "syscall", - "syscall.PTRACE_SETFPREGS": "syscall", - "syscall.PTRACE_SETFPXREGS": "syscall", - "syscall.PTRACE_SETHBPREGS": "syscall", - "syscall.PTRACE_SETOPTIONS": "syscall", - "syscall.PTRACE_SETREGS": "syscall", - "syscall.PTRACE_SETREGSET": "syscall", - "syscall.PTRACE_SETSIGINFO": "syscall", - "syscall.PTRACE_SETVFPREGS": "syscall", - "syscall.PTRACE_SETWMMXREGS": "syscall", - "syscall.PTRACE_SET_SYSCALL": "syscall", - "syscall.PTRACE_SET_THREAD_AREA": "syscall", - "syscall.PTRACE_SINGLEBLOCK": "syscall", - "syscall.PTRACE_SINGLESTEP": "syscall", - "syscall.PTRACE_SYSCALL": "syscall", - "syscall.PTRACE_SYSEMU": "syscall", - "syscall.PTRACE_SYSEMU_SINGLESTEP": "syscall", - "syscall.PTRACE_TRACEME": "syscall", - "syscall.PT_ATTACH": "syscall", - "syscall.PT_ATTACHEXC": "syscall", - "syscall.PT_CONTINUE": "syscall", - "syscall.PT_DATA_ADDR": "syscall", - "syscall.PT_DENY_ATTACH": "syscall", - "syscall.PT_DETACH": "syscall", - "syscall.PT_FIRSTMACH": "syscall", - "syscall.PT_FORCEQUOTA": "syscall", - "syscall.PT_KILL": "syscall", - "syscall.PT_MASK": "syscall", - "syscall.PT_READ_D": "syscall", - "syscall.PT_READ_I": "syscall", - "syscall.PT_READ_U": "syscall", - "syscall.PT_SIGEXC": "syscall", - "syscall.PT_STEP": "syscall", - "syscall.PT_TEXT_ADDR": "syscall", - "syscall.PT_TEXT_END_ADDR": "syscall", - "syscall.PT_THUPDATE": "syscall", - "syscall.PT_TRACE_ME": "syscall", - "syscall.PT_WRITE_D": "syscall", - "syscall.PT_WRITE_I": "syscall", - "syscall.PT_WRITE_U": "syscall", - "syscall.ParseDirent": "syscall", - "syscall.ParseNetlinkMessage": "syscall", - "syscall.ParseNetlinkRouteAttr": "syscall", - "syscall.ParseRoutingMessage": "syscall", - "syscall.ParseRoutingSockaddr": "syscall", - "syscall.ParseSocketControlMessage": "syscall", - "syscall.ParseUnixCredentials": "syscall", - "syscall.ParseUnixRights": "syscall", - "syscall.PathMax": "syscall", - "syscall.Pathconf": "syscall", - "syscall.Pause": "syscall", - "syscall.Pipe": "syscall", - "syscall.Pipe2": "syscall", - "syscall.PivotRoot": "syscall", - "syscall.PostQueuedCompletionStatus": "syscall", - "syscall.Pread": "syscall", - "syscall.Proc": "syscall", - "syscall.ProcAttr": "syscall", - "syscall.Process32First": "syscall", - "syscall.Process32Next": "syscall", - "syscall.ProcessEntry32": "syscall", - "syscall.ProcessInformation": "syscall", - "syscall.Protoent": "syscall", - "syscall.PtraceAttach": "syscall", - "syscall.PtraceCont": "syscall", - "syscall.PtraceDetach": "syscall", - "syscall.PtraceGetEventMsg": "syscall", - "syscall.PtraceGetRegs": "syscall", - "syscall.PtracePeekData": "syscall", - "syscall.PtracePeekText": "syscall", - "syscall.PtracePokeData": "syscall", - "syscall.PtracePokeText": "syscall", - "syscall.PtraceRegs": "syscall", - "syscall.PtraceSetOptions": "syscall", - "syscall.PtraceSetRegs": "syscall", - "syscall.PtraceSingleStep": "syscall", - "syscall.PtraceSyscall": "syscall", - "syscall.Pwrite": "syscall", - "syscall.REG_BINARY": "syscall", - "syscall.REG_DWORD": "syscall", - "syscall.REG_DWORD_BIG_ENDIAN": "syscall", - "syscall.REG_DWORD_LITTLE_ENDIAN": "syscall", - "syscall.REG_EXPAND_SZ": "syscall", - "syscall.REG_FULL_RESOURCE_DESCRIPTOR": "syscall", - "syscall.REG_LINK": "syscall", - "syscall.REG_MULTI_SZ": "syscall", - "syscall.REG_NONE": "syscall", - "syscall.REG_QWORD": "syscall", - "syscall.REG_QWORD_LITTLE_ENDIAN": "syscall", - "syscall.REG_RESOURCE_LIST": "syscall", - "syscall.REG_RESOURCE_REQUIREMENTS_LIST": "syscall", - "syscall.REG_SZ": "syscall", - "syscall.RLIMIT_AS": "syscall", - "syscall.RLIMIT_CORE": "syscall", - "syscall.RLIMIT_CPU": "syscall", - "syscall.RLIMIT_DATA": "syscall", - "syscall.RLIMIT_FSIZE": "syscall", - "syscall.RLIMIT_NOFILE": "syscall", - "syscall.RLIMIT_STACK": "syscall", - "syscall.RLIM_INFINITY": "syscall", - "syscall.RTAX_ADVMSS": "syscall", - "syscall.RTAX_AUTHOR": "syscall", - "syscall.RTAX_BRD": "syscall", - "syscall.RTAX_CWND": "syscall", - "syscall.RTAX_DST": "syscall", - "syscall.RTAX_FEATURES": "syscall", - "syscall.RTAX_FEATURE_ALLFRAG": "syscall", - "syscall.RTAX_FEATURE_ECN": "syscall", - "syscall.RTAX_FEATURE_SACK": "syscall", - "syscall.RTAX_FEATURE_TIMESTAMP": "syscall", - "syscall.RTAX_GATEWAY": "syscall", - "syscall.RTAX_GENMASK": "syscall", - "syscall.RTAX_HOPLIMIT": "syscall", - "syscall.RTAX_IFA": "syscall", - "syscall.RTAX_IFP": "syscall", - "syscall.RTAX_INITCWND": "syscall", - "syscall.RTAX_INITRWND": "syscall", - "syscall.RTAX_LABEL": "syscall", - "syscall.RTAX_LOCK": "syscall", - "syscall.RTAX_MAX": "syscall", - "syscall.RTAX_MTU": "syscall", - "syscall.RTAX_NETMASK": "syscall", - "syscall.RTAX_REORDERING": "syscall", - "syscall.RTAX_RTO_MIN": "syscall", - "syscall.RTAX_RTT": "syscall", - "syscall.RTAX_RTTVAR": "syscall", - "syscall.RTAX_SRC": "syscall", - "syscall.RTAX_SRCMASK": "syscall", - "syscall.RTAX_SSTHRESH": "syscall", - "syscall.RTAX_TAG": "syscall", - "syscall.RTAX_UNSPEC": "syscall", - "syscall.RTAX_WINDOW": "syscall", - "syscall.RTA_ALIGNTO": "syscall", - "syscall.RTA_AUTHOR": "syscall", - "syscall.RTA_BRD": "syscall", - "syscall.RTA_CACHEINFO": "syscall", - "syscall.RTA_DST": "syscall", - "syscall.RTA_FLOW": "syscall", - "syscall.RTA_GATEWAY": "syscall", - "syscall.RTA_GENMASK": "syscall", - "syscall.RTA_IFA": "syscall", - "syscall.RTA_IFP": "syscall", - "syscall.RTA_IIF": "syscall", - "syscall.RTA_LABEL": "syscall", - "syscall.RTA_MAX": "syscall", - "syscall.RTA_METRICS": "syscall", - "syscall.RTA_MULTIPATH": "syscall", - "syscall.RTA_NETMASK": "syscall", - "syscall.RTA_OIF": "syscall", - "syscall.RTA_PREFSRC": "syscall", - "syscall.RTA_PRIORITY": "syscall", - "syscall.RTA_SRC": "syscall", - "syscall.RTA_SRCMASK": "syscall", - "syscall.RTA_TABLE": "syscall", - "syscall.RTA_TAG": "syscall", - "syscall.RTA_UNSPEC": "syscall", - "syscall.RTCF_DIRECTSRC": "syscall", - "syscall.RTCF_DOREDIRECT": "syscall", - "syscall.RTCF_LOG": "syscall", - "syscall.RTCF_MASQ": "syscall", - "syscall.RTCF_NAT": "syscall", - "syscall.RTCF_VALVE": "syscall", - "syscall.RTF_ADDRCLASSMASK": "syscall", - "syscall.RTF_ADDRCONF": "syscall", - "syscall.RTF_ALLONLINK": "syscall", - "syscall.RTF_ANNOUNCE": "syscall", - "syscall.RTF_BLACKHOLE": "syscall", - "syscall.RTF_BROADCAST": "syscall", - "syscall.RTF_CACHE": "syscall", - "syscall.RTF_CLONED": "syscall", - "syscall.RTF_CLONING": "syscall", - "syscall.RTF_CONDEMNED": "syscall", - "syscall.RTF_DEFAULT": "syscall", - "syscall.RTF_DELCLONE": "syscall", - "syscall.RTF_DONE": "syscall", - "syscall.RTF_DYNAMIC": "syscall", - "syscall.RTF_FLOW": "syscall", - "syscall.RTF_FMASK": "syscall", - "syscall.RTF_GATEWAY": "syscall", - "syscall.RTF_GWFLAG_COMPAT": "syscall", - "syscall.RTF_HOST": "syscall", - "syscall.RTF_IFREF": "syscall", - "syscall.RTF_IFSCOPE": "syscall", - "syscall.RTF_INTERFACE": "syscall", - "syscall.RTF_IRTT": "syscall", - "syscall.RTF_LINKRT": "syscall", - "syscall.RTF_LLDATA": "syscall", - "syscall.RTF_LLINFO": "syscall", - "syscall.RTF_LOCAL": "syscall", - "syscall.RTF_MASK": "syscall", - "syscall.RTF_MODIFIED": "syscall", - "syscall.RTF_MPATH": "syscall", - "syscall.RTF_MPLS": "syscall", - "syscall.RTF_MSS": "syscall", - "syscall.RTF_MTU": "syscall", - "syscall.RTF_MULTICAST": "syscall", - "syscall.RTF_NAT": "syscall", - "syscall.RTF_NOFORWARD": "syscall", - "syscall.RTF_NONEXTHOP": "syscall", - "syscall.RTF_NOPMTUDISC": "syscall", - "syscall.RTF_PERMANENT_ARP": "syscall", - "syscall.RTF_PINNED": "syscall", - "syscall.RTF_POLICY": "syscall", - "syscall.RTF_PRCLONING": "syscall", - "syscall.RTF_PROTO1": "syscall", - "syscall.RTF_PROTO2": "syscall", - "syscall.RTF_PROTO3": "syscall", - "syscall.RTF_REINSTATE": "syscall", - "syscall.RTF_REJECT": "syscall", - "syscall.RTF_RNH_LOCKED": "syscall", - "syscall.RTF_SOURCE": "syscall", - "syscall.RTF_SRC": "syscall", - "syscall.RTF_STATIC": "syscall", - "syscall.RTF_STICKY": "syscall", - "syscall.RTF_THROW": "syscall", - "syscall.RTF_TUNNEL": "syscall", - "syscall.RTF_UP": "syscall", - "syscall.RTF_USETRAILERS": "syscall", - "syscall.RTF_WASCLONED": "syscall", - "syscall.RTF_WINDOW": "syscall", - "syscall.RTF_XRESOLVE": "syscall", - "syscall.RTM_ADD": "syscall", - "syscall.RTM_BASE": "syscall", - "syscall.RTM_CHANGE": "syscall", - "syscall.RTM_CHGADDR": "syscall", - "syscall.RTM_DELACTION": "syscall", - "syscall.RTM_DELADDR": "syscall", - "syscall.RTM_DELADDRLABEL": "syscall", - "syscall.RTM_DELETE": "syscall", - "syscall.RTM_DELLINK": "syscall", - "syscall.RTM_DELMADDR": "syscall", - "syscall.RTM_DELNEIGH": "syscall", - "syscall.RTM_DELQDISC": "syscall", - "syscall.RTM_DELROUTE": "syscall", - "syscall.RTM_DELRULE": "syscall", - "syscall.RTM_DELTCLASS": "syscall", - "syscall.RTM_DELTFILTER": "syscall", - "syscall.RTM_DESYNC": "syscall", - "syscall.RTM_F_CLONED": "syscall", - "syscall.RTM_F_EQUALIZE": "syscall", - "syscall.RTM_F_NOTIFY": "syscall", - "syscall.RTM_F_PREFIX": "syscall", - "syscall.RTM_GET": "syscall", - "syscall.RTM_GET2": "syscall", - "syscall.RTM_GETACTION": "syscall", - "syscall.RTM_GETADDR": "syscall", - "syscall.RTM_GETADDRLABEL": "syscall", - "syscall.RTM_GETANYCAST": "syscall", - "syscall.RTM_GETDCB": "syscall", - "syscall.RTM_GETLINK": "syscall", - "syscall.RTM_GETMULTICAST": "syscall", - "syscall.RTM_GETNEIGH": "syscall", - "syscall.RTM_GETNEIGHTBL": "syscall", - "syscall.RTM_GETQDISC": "syscall", - "syscall.RTM_GETROUTE": "syscall", - "syscall.RTM_GETRULE": "syscall", - "syscall.RTM_GETTCLASS": "syscall", - "syscall.RTM_GETTFILTER": "syscall", - "syscall.RTM_IEEE80211": "syscall", - "syscall.RTM_IFANNOUNCE": "syscall", - "syscall.RTM_IFINFO": "syscall", - "syscall.RTM_IFINFO2": "syscall", - "syscall.RTM_LLINFO_UPD": "syscall", - "syscall.RTM_LOCK": "syscall", - "syscall.RTM_LOSING": "syscall", - "syscall.RTM_MAX": "syscall", - "syscall.RTM_MAXSIZE": "syscall", - "syscall.RTM_MISS": "syscall", - "syscall.RTM_NEWACTION": "syscall", - "syscall.RTM_NEWADDR": "syscall", - "syscall.RTM_NEWADDRLABEL": "syscall", - "syscall.RTM_NEWLINK": "syscall", - "syscall.RTM_NEWMADDR": "syscall", - "syscall.RTM_NEWMADDR2": "syscall", - "syscall.RTM_NEWNDUSEROPT": "syscall", - "syscall.RTM_NEWNEIGH": "syscall", - "syscall.RTM_NEWNEIGHTBL": "syscall", - "syscall.RTM_NEWPREFIX": "syscall", - "syscall.RTM_NEWQDISC": "syscall", - "syscall.RTM_NEWROUTE": "syscall", - "syscall.RTM_NEWRULE": "syscall", - "syscall.RTM_NEWTCLASS": "syscall", - "syscall.RTM_NEWTFILTER": "syscall", - "syscall.RTM_NR_FAMILIES": "syscall", - "syscall.RTM_NR_MSGTYPES": "syscall", - "syscall.RTM_OIFINFO": "syscall", - "syscall.RTM_OLDADD": "syscall", - "syscall.RTM_OLDDEL": "syscall", - "syscall.RTM_OOIFINFO": "syscall", - "syscall.RTM_REDIRECT": "syscall", - "syscall.RTM_RESOLVE": "syscall", - "syscall.RTM_RTTUNIT": "syscall", - "syscall.RTM_SETDCB": "syscall", - "syscall.RTM_SETGATE": "syscall", - "syscall.RTM_SETLINK": "syscall", - "syscall.RTM_SETNEIGHTBL": "syscall", - "syscall.RTM_VERSION": "syscall", - "syscall.RTNH_ALIGNTO": "syscall", - "syscall.RTNH_F_DEAD": "syscall", - "syscall.RTNH_F_ONLINK": "syscall", - "syscall.RTNH_F_PERVASIVE": "syscall", - "syscall.RTNLGRP_IPV4_IFADDR": "syscall", - "syscall.RTNLGRP_IPV4_MROUTE": "syscall", - "syscall.RTNLGRP_IPV4_ROUTE": "syscall", - "syscall.RTNLGRP_IPV4_RULE": "syscall", - "syscall.RTNLGRP_IPV6_IFADDR": "syscall", - "syscall.RTNLGRP_IPV6_IFINFO": "syscall", - "syscall.RTNLGRP_IPV6_MROUTE": "syscall", - "syscall.RTNLGRP_IPV6_PREFIX": "syscall", - "syscall.RTNLGRP_IPV6_ROUTE": "syscall", - "syscall.RTNLGRP_IPV6_RULE": "syscall", - "syscall.RTNLGRP_LINK": "syscall", - "syscall.RTNLGRP_ND_USEROPT": "syscall", - "syscall.RTNLGRP_NEIGH": "syscall", - "syscall.RTNLGRP_NONE": "syscall", - "syscall.RTNLGRP_NOTIFY": "syscall", - "syscall.RTNLGRP_TC": "syscall", - "syscall.RTN_ANYCAST": "syscall", - "syscall.RTN_BLACKHOLE": "syscall", - "syscall.RTN_BROADCAST": "syscall", - "syscall.RTN_LOCAL": "syscall", - "syscall.RTN_MAX": "syscall", - "syscall.RTN_MULTICAST": "syscall", - "syscall.RTN_NAT": "syscall", - "syscall.RTN_PROHIBIT": "syscall", - "syscall.RTN_THROW": "syscall", - "syscall.RTN_UNICAST": "syscall", - "syscall.RTN_UNREACHABLE": "syscall", - "syscall.RTN_UNSPEC": "syscall", - "syscall.RTN_XRESOLVE": "syscall", - "syscall.RTPROT_BIRD": "syscall", - "syscall.RTPROT_BOOT": "syscall", - "syscall.RTPROT_DHCP": "syscall", - "syscall.RTPROT_DNROUTED": "syscall", - "syscall.RTPROT_GATED": "syscall", - "syscall.RTPROT_KERNEL": "syscall", - "syscall.RTPROT_MRT": "syscall", - "syscall.RTPROT_NTK": "syscall", - "syscall.RTPROT_RA": "syscall", - "syscall.RTPROT_REDIRECT": "syscall", - "syscall.RTPROT_STATIC": "syscall", - "syscall.RTPROT_UNSPEC": "syscall", - "syscall.RTPROT_XORP": "syscall", - "syscall.RTPROT_ZEBRA": "syscall", - "syscall.RTV_EXPIRE": "syscall", - "syscall.RTV_HOPCOUNT": "syscall", - "syscall.RTV_MTU": "syscall", - "syscall.RTV_RPIPE": "syscall", - "syscall.RTV_RTT": "syscall", - "syscall.RTV_RTTVAR": "syscall", - "syscall.RTV_SPIPE": "syscall", - "syscall.RTV_SSTHRESH": "syscall", - "syscall.RTV_WEIGHT": "syscall", - "syscall.RT_CACHING_CONTEXT": "syscall", - "syscall.RT_CLASS_DEFAULT": "syscall", - "syscall.RT_CLASS_LOCAL": "syscall", - "syscall.RT_CLASS_MAIN": "syscall", - "syscall.RT_CLASS_MAX": "syscall", - "syscall.RT_CLASS_UNSPEC": "syscall", - "syscall.RT_DEFAULT_FIB": "syscall", - "syscall.RT_NORTREF": "syscall", - "syscall.RT_SCOPE_HOST": "syscall", - "syscall.RT_SCOPE_LINK": "syscall", - "syscall.RT_SCOPE_NOWHERE": "syscall", - "syscall.RT_SCOPE_SITE": "syscall", - "syscall.RT_SCOPE_UNIVERSE": "syscall", - "syscall.RT_TABLEID_MAX": "syscall", - "syscall.RT_TABLE_COMPAT": "syscall", - "syscall.RT_TABLE_DEFAULT": "syscall", - "syscall.RT_TABLE_LOCAL": "syscall", - "syscall.RT_TABLE_MAIN": "syscall", - "syscall.RT_TABLE_MAX": "syscall", - "syscall.RT_TABLE_UNSPEC": "syscall", - "syscall.RUSAGE_CHILDREN": "syscall", - "syscall.RUSAGE_SELF": "syscall", - "syscall.RUSAGE_THREAD": "syscall", - "syscall.Radvisory_t": "syscall", - "syscall.RawSockaddr": "syscall", - "syscall.RawSockaddrAny": "syscall", - "syscall.RawSockaddrDatalink": "syscall", - "syscall.RawSockaddrInet4": "syscall", - "syscall.RawSockaddrInet6": "syscall", - "syscall.RawSockaddrLinklayer": "syscall", - "syscall.RawSockaddrNetlink": "syscall", - "syscall.RawSockaddrUnix": "syscall", - "syscall.RawSyscall": "syscall", - "syscall.RawSyscall6": "syscall", - "syscall.Read": "syscall", - "syscall.ReadConsole": "syscall", - "syscall.ReadDirectoryChanges": "syscall", - "syscall.ReadDirent": "syscall", - "syscall.ReadFile": "syscall", - "syscall.Readlink": "syscall", - "syscall.Reboot": "syscall", - "syscall.Recvfrom": "syscall", - "syscall.Recvmsg": "syscall", - "syscall.RegCloseKey": "syscall", - "syscall.RegEnumKeyEx": "syscall", - "syscall.RegOpenKeyEx": "syscall", - "syscall.RegQueryInfoKey": "syscall", - "syscall.RegQueryValueEx": "syscall", - "syscall.RemoveDirectory": "syscall", - "syscall.Removexattr": "syscall", - "syscall.Rename": "syscall", - "syscall.Renameat": "syscall", - "syscall.Revoke": "syscall", - "syscall.Rlimit": "syscall", - "syscall.Rmdir": "syscall", - "syscall.RouteMessage": "syscall", - "syscall.RouteRIB": "syscall", - "syscall.RtAttr": "syscall", - "syscall.RtGenmsg": "syscall", - "syscall.RtMetrics": "syscall", - "syscall.RtMsg": "syscall", - "syscall.RtMsghdr": "syscall", - "syscall.RtNexthop": "syscall", - "syscall.Rusage": "syscall", - "syscall.SCM_BINTIME": "syscall", - "syscall.SCM_CREDENTIALS": "syscall", - "syscall.SCM_CREDS": "syscall", - "syscall.SCM_RIGHTS": "syscall", - "syscall.SCM_TIMESTAMP": "syscall", - "syscall.SCM_TIMESTAMPING": "syscall", - "syscall.SCM_TIMESTAMPNS": "syscall", - "syscall.SCM_TIMESTAMP_MONOTONIC": "syscall", - "syscall.SHUT_RD": "syscall", - "syscall.SHUT_RDWR": "syscall", - "syscall.SHUT_WR": "syscall", - "syscall.SID": "syscall", - "syscall.SIDAndAttributes": "syscall", - "syscall.SIGABRT": "syscall", - "syscall.SIGALRM": "syscall", - "syscall.SIGBUS": "syscall", - "syscall.SIGCHLD": "syscall", - "syscall.SIGCLD": "syscall", - "syscall.SIGCONT": "syscall", - "syscall.SIGEMT": "syscall", - "syscall.SIGFPE": "syscall", - "syscall.SIGHUP": "syscall", - "syscall.SIGILL": "syscall", - "syscall.SIGINFO": "syscall", - "syscall.SIGINT": "syscall", - "syscall.SIGIO": "syscall", - "syscall.SIGIOT": "syscall", - "syscall.SIGKILL": "syscall", - "syscall.SIGLIBRT": "syscall", - "syscall.SIGLWP": "syscall", - "syscall.SIGPIPE": "syscall", - "syscall.SIGPOLL": "syscall", - "syscall.SIGPROF": "syscall", - "syscall.SIGPWR": "syscall", - "syscall.SIGQUIT": "syscall", - "syscall.SIGSEGV": "syscall", - "syscall.SIGSTKFLT": "syscall", - "syscall.SIGSTOP": "syscall", - "syscall.SIGSYS": "syscall", - "syscall.SIGTERM": "syscall", - "syscall.SIGTHR": "syscall", - "syscall.SIGTRAP": "syscall", - "syscall.SIGTSTP": "syscall", - "syscall.SIGTTIN": "syscall", - "syscall.SIGTTOU": "syscall", - "syscall.SIGUNUSED": "syscall", - "syscall.SIGURG": "syscall", - "syscall.SIGUSR1": "syscall", - "syscall.SIGUSR2": "syscall", - "syscall.SIGVTALRM": "syscall", - "syscall.SIGWINCH": "syscall", - "syscall.SIGXCPU": "syscall", - "syscall.SIGXFSZ": "syscall", - "syscall.SIOCADDDLCI": "syscall", - "syscall.SIOCADDMULTI": "syscall", - "syscall.SIOCADDRT": "syscall", - "syscall.SIOCAIFADDR": "syscall", - "syscall.SIOCAIFGROUP": "syscall", - "syscall.SIOCALIFADDR": "syscall", - "syscall.SIOCARPIPLL": "syscall", - "syscall.SIOCATMARK": "syscall", - "syscall.SIOCAUTOADDR": "syscall", - "syscall.SIOCAUTONETMASK": "syscall", - "syscall.SIOCBRDGADD": "syscall", - "syscall.SIOCBRDGADDS": "syscall", - "syscall.SIOCBRDGARL": "syscall", - "syscall.SIOCBRDGDADDR": "syscall", - "syscall.SIOCBRDGDEL": "syscall", - "syscall.SIOCBRDGDELS": "syscall", - "syscall.SIOCBRDGFLUSH": "syscall", - "syscall.SIOCBRDGFRL": "syscall", - "syscall.SIOCBRDGGCACHE": "syscall", - "syscall.SIOCBRDGGFD": "syscall", - "syscall.SIOCBRDGGHT": "syscall", - "syscall.SIOCBRDGGIFFLGS": "syscall", - "syscall.SIOCBRDGGMA": "syscall", - "syscall.SIOCBRDGGPARAM": "syscall", - "syscall.SIOCBRDGGPRI": "syscall", - "syscall.SIOCBRDGGRL": "syscall", - "syscall.SIOCBRDGGSIFS": "syscall", - "syscall.SIOCBRDGGTO": "syscall", - "syscall.SIOCBRDGIFS": "syscall", - "syscall.SIOCBRDGRTS": "syscall", - "syscall.SIOCBRDGSADDR": "syscall", - "syscall.SIOCBRDGSCACHE": "syscall", - "syscall.SIOCBRDGSFD": "syscall", - "syscall.SIOCBRDGSHT": "syscall", - "syscall.SIOCBRDGSIFCOST": "syscall", - "syscall.SIOCBRDGSIFFLGS": "syscall", - "syscall.SIOCBRDGSIFPRIO": "syscall", - "syscall.SIOCBRDGSMA": "syscall", - "syscall.SIOCBRDGSPRI": "syscall", - "syscall.SIOCBRDGSPROTO": "syscall", - "syscall.SIOCBRDGSTO": "syscall", - "syscall.SIOCBRDGSTXHC": "syscall", - "syscall.SIOCDARP": "syscall", - "syscall.SIOCDELDLCI": "syscall", - "syscall.SIOCDELMULTI": "syscall", - "syscall.SIOCDELRT": "syscall", - "syscall.SIOCDEVPRIVATE": "syscall", - "syscall.SIOCDIFADDR": "syscall", - "syscall.SIOCDIFGROUP": "syscall", - "syscall.SIOCDIFPHYADDR": "syscall", - "syscall.SIOCDLIFADDR": "syscall", - "syscall.SIOCDRARP": "syscall", - "syscall.SIOCGARP": "syscall", - "syscall.SIOCGDRVSPEC": "syscall", - "syscall.SIOCGETKALIVE": "syscall", - "syscall.SIOCGETLABEL": "syscall", - "syscall.SIOCGETPFLOW": "syscall", - "syscall.SIOCGETPFSYNC": "syscall", - "syscall.SIOCGETSGCNT": "syscall", - "syscall.SIOCGETVIFCNT": "syscall", - "syscall.SIOCGETVLAN": "syscall", - "syscall.SIOCGHIWAT": "syscall", - "syscall.SIOCGIFADDR": "syscall", - "syscall.SIOCGIFADDRPREF": "syscall", - "syscall.SIOCGIFALIAS": "syscall", - "syscall.SIOCGIFALTMTU": "syscall", - "syscall.SIOCGIFASYNCMAP": "syscall", - "syscall.SIOCGIFBOND": "syscall", - "syscall.SIOCGIFBR": "syscall", - "syscall.SIOCGIFBRDADDR": "syscall", - "syscall.SIOCGIFCAP": "syscall", - "syscall.SIOCGIFCONF": "syscall", - "syscall.SIOCGIFCOUNT": "syscall", - "syscall.SIOCGIFDATA": "syscall", - "syscall.SIOCGIFDESCR": "syscall", - "syscall.SIOCGIFDEVMTU": "syscall", - "syscall.SIOCGIFDLT": "syscall", - "syscall.SIOCGIFDSTADDR": "syscall", - "syscall.SIOCGIFENCAP": "syscall", - "syscall.SIOCGIFFIB": "syscall", - "syscall.SIOCGIFFLAGS": "syscall", - "syscall.SIOCGIFGATTR": "syscall", - "syscall.SIOCGIFGENERIC": "syscall", - "syscall.SIOCGIFGMEMB": "syscall", - "syscall.SIOCGIFGROUP": "syscall", - "syscall.SIOCGIFHARDMTU": "syscall", - "syscall.SIOCGIFHWADDR": "syscall", - "syscall.SIOCGIFINDEX": "syscall", - "syscall.SIOCGIFKPI": "syscall", - "syscall.SIOCGIFMAC": "syscall", - "syscall.SIOCGIFMAP": "syscall", - "syscall.SIOCGIFMEDIA": "syscall", - "syscall.SIOCGIFMEM": "syscall", - "syscall.SIOCGIFMETRIC": "syscall", - "syscall.SIOCGIFMTU": "syscall", - "syscall.SIOCGIFNAME": "syscall", - "syscall.SIOCGIFNETMASK": "syscall", - "syscall.SIOCGIFPDSTADDR": "syscall", - "syscall.SIOCGIFPFLAGS": "syscall", - "syscall.SIOCGIFPHYS": "syscall", - "syscall.SIOCGIFPRIORITY": "syscall", - "syscall.SIOCGIFPSRCADDR": "syscall", - "syscall.SIOCGIFRDOMAIN": "syscall", - "syscall.SIOCGIFRTLABEL": "syscall", - "syscall.SIOCGIFSLAVE": "syscall", - "syscall.SIOCGIFSTATUS": "syscall", - "syscall.SIOCGIFTIMESLOT": "syscall", - "syscall.SIOCGIFTXQLEN": "syscall", - "syscall.SIOCGIFVLAN": "syscall", - "syscall.SIOCGIFWAKEFLAGS": "syscall", - "syscall.SIOCGIFXFLAGS": "syscall", - "syscall.SIOCGLIFADDR": "syscall", - "syscall.SIOCGLIFPHYADDR": "syscall", - "syscall.SIOCGLIFPHYRTABLE": "syscall", - "syscall.SIOCGLIFPHYTTL": "syscall", - "syscall.SIOCGLINKSTR": "syscall", - "syscall.SIOCGLOWAT": "syscall", - "syscall.SIOCGPGRP": "syscall", - "syscall.SIOCGPRIVATE_0": "syscall", - "syscall.SIOCGPRIVATE_1": "syscall", - "syscall.SIOCGRARP": "syscall", - "syscall.SIOCGSPPPPARAMS": "syscall", - "syscall.SIOCGSTAMP": "syscall", - "syscall.SIOCGSTAMPNS": "syscall", - "syscall.SIOCGVH": "syscall", - "syscall.SIOCGVNETID": "syscall", - "syscall.SIOCIFCREATE": "syscall", - "syscall.SIOCIFCREATE2": "syscall", - "syscall.SIOCIFDESTROY": "syscall", - "syscall.SIOCIFGCLONERS": "syscall", - "syscall.SIOCINITIFADDR": "syscall", - "syscall.SIOCPROTOPRIVATE": "syscall", - "syscall.SIOCRSLVMULTI": "syscall", - "syscall.SIOCRTMSG": "syscall", - "syscall.SIOCSARP": "syscall", - "syscall.SIOCSDRVSPEC": "syscall", - "syscall.SIOCSETKALIVE": "syscall", - "syscall.SIOCSETLABEL": "syscall", - "syscall.SIOCSETPFLOW": "syscall", - "syscall.SIOCSETPFSYNC": "syscall", - "syscall.SIOCSETVLAN": "syscall", - "syscall.SIOCSHIWAT": "syscall", - "syscall.SIOCSIFADDR": "syscall", - "syscall.SIOCSIFADDRPREF": "syscall", - "syscall.SIOCSIFALTMTU": "syscall", - "syscall.SIOCSIFASYNCMAP": "syscall", - "syscall.SIOCSIFBOND": "syscall", - "syscall.SIOCSIFBR": "syscall", - "syscall.SIOCSIFBRDADDR": "syscall", - "syscall.SIOCSIFCAP": "syscall", - "syscall.SIOCSIFDESCR": "syscall", - "syscall.SIOCSIFDSTADDR": "syscall", - "syscall.SIOCSIFENCAP": "syscall", - "syscall.SIOCSIFFIB": "syscall", - "syscall.SIOCSIFFLAGS": "syscall", - "syscall.SIOCSIFGATTR": "syscall", - "syscall.SIOCSIFGENERIC": "syscall", - "syscall.SIOCSIFHWADDR": "syscall", - "syscall.SIOCSIFHWBROADCAST": "syscall", - "syscall.SIOCSIFKPI": "syscall", - "syscall.SIOCSIFLINK": "syscall", - "syscall.SIOCSIFLLADDR": "syscall", - "syscall.SIOCSIFMAC": "syscall", - "syscall.SIOCSIFMAP": "syscall", - "syscall.SIOCSIFMEDIA": "syscall", - "syscall.SIOCSIFMEM": "syscall", - "syscall.SIOCSIFMETRIC": "syscall", - "syscall.SIOCSIFMTU": "syscall", - "syscall.SIOCSIFNAME": "syscall", - "syscall.SIOCSIFNETMASK": "syscall", - "syscall.SIOCSIFPFLAGS": "syscall", - "syscall.SIOCSIFPHYADDR": "syscall", - "syscall.SIOCSIFPHYS": "syscall", - "syscall.SIOCSIFPRIORITY": "syscall", - "syscall.SIOCSIFRDOMAIN": "syscall", - "syscall.SIOCSIFRTLABEL": "syscall", - "syscall.SIOCSIFRVNET": "syscall", - "syscall.SIOCSIFSLAVE": "syscall", - "syscall.SIOCSIFTIMESLOT": "syscall", - "syscall.SIOCSIFTXQLEN": "syscall", - "syscall.SIOCSIFVLAN": "syscall", - "syscall.SIOCSIFVNET": "syscall", - "syscall.SIOCSIFXFLAGS": "syscall", - "syscall.SIOCSLIFPHYADDR": "syscall", - "syscall.SIOCSLIFPHYRTABLE": "syscall", - "syscall.SIOCSLIFPHYTTL": "syscall", - "syscall.SIOCSLINKSTR": "syscall", - "syscall.SIOCSLOWAT": "syscall", - "syscall.SIOCSPGRP": "syscall", - "syscall.SIOCSRARP": "syscall", - "syscall.SIOCSSPPPPARAMS": "syscall", - "syscall.SIOCSVH": "syscall", - "syscall.SIOCSVNETID": "syscall", - "syscall.SIOCZIFDATA": "syscall", - "syscall.SIO_GET_EXTENSION_FUNCTION_POINTER": "syscall", - "syscall.SIO_GET_INTERFACE_LIST": "syscall", - "syscall.SIO_KEEPALIVE_VALS": "syscall", - "syscall.SIO_UDP_CONNRESET": "syscall", - "syscall.SOCK_CLOEXEC": "syscall", - "syscall.SOCK_DCCP": "syscall", - "syscall.SOCK_DGRAM": "syscall", - "syscall.SOCK_FLAGS_MASK": "syscall", - "syscall.SOCK_MAXADDRLEN": "syscall", - "syscall.SOCK_NONBLOCK": "syscall", - "syscall.SOCK_NOSIGPIPE": "syscall", - "syscall.SOCK_PACKET": "syscall", - "syscall.SOCK_RAW": "syscall", - "syscall.SOCK_RDM": "syscall", - "syscall.SOCK_SEQPACKET": "syscall", - "syscall.SOCK_STREAM": "syscall", - "syscall.SOL_AAL": "syscall", - "syscall.SOL_ATM": "syscall", - "syscall.SOL_DECNET": "syscall", - "syscall.SOL_ICMPV6": "syscall", - "syscall.SOL_IP": "syscall", - "syscall.SOL_IPV6": "syscall", - "syscall.SOL_IRDA": "syscall", - "syscall.SOL_PACKET": "syscall", - "syscall.SOL_RAW": "syscall", - "syscall.SOL_SOCKET": "syscall", - "syscall.SOL_TCP": "syscall", - "syscall.SOL_X25": "syscall", - "syscall.SOMAXCONN": "syscall", - "syscall.SO_ACCEPTCONN": "syscall", - "syscall.SO_ACCEPTFILTER": "syscall", - "syscall.SO_ATTACH_FILTER": "syscall", - "syscall.SO_BINDANY": "syscall", - "syscall.SO_BINDTODEVICE": "syscall", - "syscall.SO_BINTIME": "syscall", - "syscall.SO_BROADCAST": "syscall", - "syscall.SO_BSDCOMPAT": "syscall", - "syscall.SO_DEBUG": "syscall", - "syscall.SO_DETACH_FILTER": "syscall", - "syscall.SO_DOMAIN": "syscall", - "syscall.SO_DONTROUTE": "syscall", - "syscall.SO_DONTTRUNC": "syscall", - "syscall.SO_ERROR": "syscall", - "syscall.SO_KEEPALIVE": "syscall", - "syscall.SO_LABEL": "syscall", - "syscall.SO_LINGER": "syscall", - "syscall.SO_LINGER_SEC": "syscall", - "syscall.SO_LISTENINCQLEN": "syscall", - "syscall.SO_LISTENQLEN": "syscall", - "syscall.SO_LISTENQLIMIT": "syscall", - "syscall.SO_MARK": "syscall", - "syscall.SO_NETPROC": "syscall", - "syscall.SO_NKE": "syscall", - "syscall.SO_NOADDRERR": "syscall", - "syscall.SO_NOHEADER": "syscall", - "syscall.SO_NOSIGPIPE": "syscall", - "syscall.SO_NOTIFYCONFLICT": "syscall", - "syscall.SO_NO_CHECK": "syscall", - "syscall.SO_NO_DDP": "syscall", - "syscall.SO_NO_OFFLOAD": "syscall", - "syscall.SO_NP_EXTENSIONS": "syscall", - "syscall.SO_NREAD": "syscall", - "syscall.SO_NWRITE": "syscall", - "syscall.SO_OOBINLINE": "syscall", - "syscall.SO_OVERFLOWED": "syscall", - "syscall.SO_PASSCRED": "syscall", - "syscall.SO_PASSSEC": "syscall", - "syscall.SO_PEERCRED": "syscall", - "syscall.SO_PEERLABEL": "syscall", - "syscall.SO_PEERNAME": "syscall", - "syscall.SO_PEERSEC": "syscall", - "syscall.SO_PRIORITY": "syscall", - "syscall.SO_PROTOCOL": "syscall", - "syscall.SO_PROTOTYPE": "syscall", - "syscall.SO_RANDOMPORT": "syscall", - "syscall.SO_RCVBUF": "syscall", - "syscall.SO_RCVBUFFORCE": "syscall", - "syscall.SO_RCVLOWAT": "syscall", - "syscall.SO_RCVTIMEO": "syscall", - "syscall.SO_RESTRICTIONS": "syscall", - "syscall.SO_RESTRICT_DENYIN": "syscall", - "syscall.SO_RESTRICT_DENYOUT": "syscall", - "syscall.SO_RESTRICT_DENYSET": "syscall", - "syscall.SO_REUSEADDR": "syscall", - "syscall.SO_REUSEPORT": "syscall", - "syscall.SO_REUSESHAREUID": "syscall", - "syscall.SO_RTABLE": "syscall", - "syscall.SO_RXQ_OVFL": "syscall", - "syscall.SO_SECURITY_AUTHENTICATION": "syscall", - "syscall.SO_SECURITY_ENCRYPTION_NETWORK": "syscall", - "syscall.SO_SECURITY_ENCRYPTION_TRANSPORT": "syscall", - "syscall.SO_SETFIB": "syscall", - "syscall.SO_SNDBUF": "syscall", - "syscall.SO_SNDBUFFORCE": "syscall", - "syscall.SO_SNDLOWAT": "syscall", - "syscall.SO_SNDTIMEO": "syscall", - "syscall.SO_SPLICE": "syscall", - "syscall.SO_TIMESTAMP": "syscall", - "syscall.SO_TIMESTAMPING": "syscall", - "syscall.SO_TIMESTAMPNS": "syscall", - "syscall.SO_TIMESTAMP_MONOTONIC": "syscall", - "syscall.SO_TYPE": "syscall", - "syscall.SO_UPCALLCLOSEWAIT": "syscall", - "syscall.SO_UPDATE_ACCEPT_CONTEXT": "syscall", - "syscall.SO_UPDATE_CONNECT_CONTEXT": "syscall", - "syscall.SO_USELOOPBACK": "syscall", - "syscall.SO_USER_COOKIE": "syscall", - "syscall.SO_VENDOR": "syscall", - "syscall.SO_WANTMORE": "syscall", - "syscall.SO_WANTOOBFLAG": "syscall", - "syscall.SSLExtraCertChainPolicyPara": "syscall", - "syscall.STANDARD_RIGHTS_ALL": "syscall", - "syscall.STANDARD_RIGHTS_EXECUTE": "syscall", - "syscall.STANDARD_RIGHTS_READ": "syscall", - "syscall.STANDARD_RIGHTS_REQUIRED": "syscall", - "syscall.STANDARD_RIGHTS_WRITE": "syscall", - "syscall.STARTF_USESHOWWINDOW": "syscall", - "syscall.STARTF_USESTDHANDLES": "syscall", - "syscall.STD_ERROR_HANDLE": "syscall", - "syscall.STD_INPUT_HANDLE": "syscall", - "syscall.STD_OUTPUT_HANDLE": "syscall", - "syscall.SUBLANG_ENGLISH_US": "syscall", - "syscall.SW_FORCEMINIMIZE": "syscall", - "syscall.SW_HIDE": "syscall", - "syscall.SW_MAXIMIZE": "syscall", - "syscall.SW_MINIMIZE": "syscall", - "syscall.SW_NORMAL": "syscall", - "syscall.SW_RESTORE": "syscall", - "syscall.SW_SHOW": "syscall", - "syscall.SW_SHOWDEFAULT": "syscall", - "syscall.SW_SHOWMAXIMIZED": "syscall", - "syscall.SW_SHOWMINIMIZED": "syscall", - "syscall.SW_SHOWMINNOACTIVE": "syscall", - "syscall.SW_SHOWNA": "syscall", - "syscall.SW_SHOWNOACTIVATE": "syscall", - "syscall.SW_SHOWNORMAL": "syscall", - "syscall.SYMBOLIC_LINK_FLAG_DIRECTORY": "syscall", - "syscall.SYNCHRONIZE": "syscall", - "syscall.SYSCTL_VERSION": "syscall", - "syscall.SYSCTL_VERS_0": "syscall", - "syscall.SYSCTL_VERS_1": "syscall", - "syscall.SYSCTL_VERS_MASK": "syscall", - "syscall.SYS_ABORT2": "syscall", - "syscall.SYS_ACCEPT": "syscall", - "syscall.SYS_ACCEPT4": "syscall", - "syscall.SYS_ACCEPT_NOCANCEL": "syscall", - "syscall.SYS_ACCESS": "syscall", - "syscall.SYS_ACCESS_EXTENDED": "syscall", - "syscall.SYS_ACCT": "syscall", - "syscall.SYS_ADD_KEY": "syscall", - "syscall.SYS_ADD_PROFIL": "syscall", - "syscall.SYS_ADJFREQ": "syscall", - "syscall.SYS_ADJTIME": "syscall", - "syscall.SYS_ADJTIMEX": "syscall", - "syscall.SYS_AFS_SYSCALL": "syscall", - "syscall.SYS_AIO_CANCEL": "syscall", - "syscall.SYS_AIO_ERROR": "syscall", - "syscall.SYS_AIO_FSYNC": "syscall", - "syscall.SYS_AIO_READ": "syscall", - "syscall.SYS_AIO_RETURN": "syscall", - "syscall.SYS_AIO_SUSPEND": "syscall", - "syscall.SYS_AIO_SUSPEND_NOCANCEL": "syscall", - "syscall.SYS_AIO_WRITE": "syscall", - "syscall.SYS_ALARM": "syscall", - "syscall.SYS_ARCH_PRCTL": "syscall", - "syscall.SYS_ARM_FADVISE64_64": "syscall", - "syscall.SYS_ARM_SYNC_FILE_RANGE": "syscall", - "syscall.SYS_ATGETMSG": "syscall", - "syscall.SYS_ATPGETREQ": "syscall", - "syscall.SYS_ATPGETRSP": "syscall", - "syscall.SYS_ATPSNDREQ": "syscall", - "syscall.SYS_ATPSNDRSP": "syscall", - "syscall.SYS_ATPUTMSG": "syscall", - "syscall.SYS_ATSOCKET": "syscall", - "syscall.SYS_AUDIT": "syscall", - "syscall.SYS_AUDITCTL": "syscall", - "syscall.SYS_AUDITON": "syscall", - "syscall.SYS_AUDIT_SESSION_JOIN": "syscall", - "syscall.SYS_AUDIT_SESSION_PORT": "syscall", - "syscall.SYS_AUDIT_SESSION_SELF": "syscall", - "syscall.SYS_BDFLUSH": "syscall", - "syscall.SYS_BIND": "syscall", - "syscall.SYS_BINDAT": "syscall", - "syscall.SYS_BREAK": "syscall", - "syscall.SYS_BRK": "syscall", - "syscall.SYS_BSDTHREAD_CREATE": "syscall", - "syscall.SYS_BSDTHREAD_REGISTER": "syscall", - "syscall.SYS_BSDTHREAD_TERMINATE": "syscall", - "syscall.SYS_CAPGET": "syscall", - "syscall.SYS_CAPSET": "syscall", - "syscall.SYS_CAP_ENTER": "syscall", - "syscall.SYS_CAP_FCNTLS_GET": "syscall", - "syscall.SYS_CAP_FCNTLS_LIMIT": "syscall", - "syscall.SYS_CAP_GETMODE": "syscall", - "syscall.SYS_CAP_GETRIGHTS": "syscall", - "syscall.SYS_CAP_IOCTLS_GET": "syscall", - "syscall.SYS_CAP_IOCTLS_LIMIT": "syscall", - "syscall.SYS_CAP_NEW": "syscall", - "syscall.SYS_CAP_RIGHTS_GET": "syscall", - "syscall.SYS_CAP_RIGHTS_LIMIT": "syscall", - "syscall.SYS_CHDIR": "syscall", - "syscall.SYS_CHFLAGS": "syscall", - "syscall.SYS_CHFLAGSAT": "syscall", - "syscall.SYS_CHMOD": "syscall", - "syscall.SYS_CHMOD_EXTENDED": "syscall", - "syscall.SYS_CHOWN": "syscall", - "syscall.SYS_CHOWN32": "syscall", - "syscall.SYS_CHROOT": "syscall", - "syscall.SYS_CHUD": "syscall", - "syscall.SYS_CLOCK_ADJTIME": "syscall", - "syscall.SYS_CLOCK_GETCPUCLOCKID2": "syscall", - "syscall.SYS_CLOCK_GETRES": "syscall", - "syscall.SYS_CLOCK_GETTIME": "syscall", - "syscall.SYS_CLOCK_NANOSLEEP": "syscall", - "syscall.SYS_CLOCK_SETTIME": "syscall", - "syscall.SYS_CLONE": "syscall", - "syscall.SYS_CLOSE": "syscall", - "syscall.SYS_CLOSEFROM": "syscall", - "syscall.SYS_CLOSE_NOCANCEL": "syscall", - "syscall.SYS_CONNECT": "syscall", - "syscall.SYS_CONNECTAT": "syscall", - "syscall.SYS_CONNECT_NOCANCEL": "syscall", - "syscall.SYS_COPYFILE": "syscall", - "syscall.SYS_CPUSET": "syscall", - "syscall.SYS_CPUSET_GETAFFINITY": "syscall", - "syscall.SYS_CPUSET_GETID": "syscall", - "syscall.SYS_CPUSET_SETAFFINITY": "syscall", - "syscall.SYS_CPUSET_SETID": "syscall", - "syscall.SYS_CREAT": "syscall", - "syscall.SYS_CREATE_MODULE": "syscall", - "syscall.SYS_CSOPS": "syscall", - "syscall.SYS_DELETE": "syscall", - "syscall.SYS_DELETE_MODULE": "syscall", - "syscall.SYS_DUP": "syscall", - "syscall.SYS_DUP2": "syscall", - "syscall.SYS_DUP3": "syscall", - "syscall.SYS_EACCESS": "syscall", - "syscall.SYS_EPOLL_CREATE": "syscall", - "syscall.SYS_EPOLL_CREATE1": "syscall", - "syscall.SYS_EPOLL_CTL": "syscall", - "syscall.SYS_EPOLL_CTL_OLD": "syscall", - "syscall.SYS_EPOLL_PWAIT": "syscall", - "syscall.SYS_EPOLL_WAIT": "syscall", - "syscall.SYS_EPOLL_WAIT_OLD": "syscall", - "syscall.SYS_EVENTFD": "syscall", - "syscall.SYS_EVENTFD2": "syscall", - "syscall.SYS_EXCHANGEDATA": "syscall", - "syscall.SYS_EXECVE": "syscall", - "syscall.SYS_EXIT": "syscall", - "syscall.SYS_EXIT_GROUP": "syscall", - "syscall.SYS_EXTATTRCTL": "syscall", - "syscall.SYS_EXTATTR_DELETE_FD": "syscall", - "syscall.SYS_EXTATTR_DELETE_FILE": "syscall", - "syscall.SYS_EXTATTR_DELETE_LINK": "syscall", - "syscall.SYS_EXTATTR_GET_FD": "syscall", - "syscall.SYS_EXTATTR_GET_FILE": "syscall", - "syscall.SYS_EXTATTR_GET_LINK": "syscall", - "syscall.SYS_EXTATTR_LIST_FD": "syscall", - "syscall.SYS_EXTATTR_LIST_FILE": "syscall", - "syscall.SYS_EXTATTR_LIST_LINK": "syscall", - "syscall.SYS_EXTATTR_SET_FD": "syscall", - "syscall.SYS_EXTATTR_SET_FILE": "syscall", - "syscall.SYS_EXTATTR_SET_LINK": "syscall", - "syscall.SYS_FACCESSAT": "syscall", - "syscall.SYS_FADVISE64": "syscall", - "syscall.SYS_FADVISE64_64": "syscall", - "syscall.SYS_FALLOCATE": "syscall", - "syscall.SYS_FANOTIFY_INIT": "syscall", - "syscall.SYS_FANOTIFY_MARK": "syscall", - "syscall.SYS_FCHDIR": "syscall", - "syscall.SYS_FCHFLAGS": "syscall", - "syscall.SYS_FCHMOD": "syscall", - "syscall.SYS_FCHMODAT": "syscall", - "syscall.SYS_FCHMOD_EXTENDED": "syscall", - "syscall.SYS_FCHOWN": "syscall", - "syscall.SYS_FCHOWN32": "syscall", - "syscall.SYS_FCHOWNAT": "syscall", - "syscall.SYS_FCHROOT": "syscall", - "syscall.SYS_FCNTL": "syscall", - "syscall.SYS_FCNTL64": "syscall", - "syscall.SYS_FCNTL_NOCANCEL": "syscall", - "syscall.SYS_FDATASYNC": "syscall", - "syscall.SYS_FEXECVE": "syscall", - "syscall.SYS_FFCLOCK_GETCOUNTER": "syscall", - "syscall.SYS_FFCLOCK_GETESTIMATE": "syscall", - "syscall.SYS_FFCLOCK_SETESTIMATE": "syscall", - "syscall.SYS_FFSCTL": "syscall", - "syscall.SYS_FGETATTRLIST": "syscall", - "syscall.SYS_FGETXATTR": "syscall", - "syscall.SYS_FHOPEN": "syscall", - "syscall.SYS_FHSTAT": "syscall", - "syscall.SYS_FHSTATFS": "syscall", - "syscall.SYS_FILEPORT_MAKEFD": "syscall", - "syscall.SYS_FILEPORT_MAKEPORT": "syscall", - "syscall.SYS_FKTRACE": "syscall", - "syscall.SYS_FLISTXATTR": "syscall", - "syscall.SYS_FLOCK": "syscall", - "syscall.SYS_FORK": "syscall", - "syscall.SYS_FPATHCONF": "syscall", - "syscall.SYS_FREEBSD6_FTRUNCATE": "syscall", - "syscall.SYS_FREEBSD6_LSEEK": "syscall", - "syscall.SYS_FREEBSD6_MMAP": "syscall", - "syscall.SYS_FREEBSD6_PREAD": "syscall", - "syscall.SYS_FREEBSD6_PWRITE": "syscall", - "syscall.SYS_FREEBSD6_TRUNCATE": "syscall", - "syscall.SYS_FREMOVEXATTR": "syscall", - "syscall.SYS_FSCTL": "syscall", - "syscall.SYS_FSETATTRLIST": "syscall", - "syscall.SYS_FSETXATTR": "syscall", - "syscall.SYS_FSGETPATH": "syscall", - "syscall.SYS_FSTAT": "syscall", - "syscall.SYS_FSTAT64": "syscall", - "syscall.SYS_FSTAT64_EXTENDED": "syscall", - "syscall.SYS_FSTATAT": "syscall", - "syscall.SYS_FSTATAT64": "syscall", - "syscall.SYS_FSTATFS": "syscall", - "syscall.SYS_FSTATFS64": "syscall", - "syscall.SYS_FSTATV": "syscall", - "syscall.SYS_FSTATVFS1": "syscall", - "syscall.SYS_FSTAT_EXTENDED": "syscall", - "syscall.SYS_FSYNC": "syscall", - "syscall.SYS_FSYNC_NOCANCEL": "syscall", - "syscall.SYS_FSYNC_RANGE": "syscall", - "syscall.SYS_FTIME": "syscall", - "syscall.SYS_FTRUNCATE": "syscall", - "syscall.SYS_FTRUNCATE64": "syscall", - "syscall.SYS_FUTEX": "syscall", - "syscall.SYS_FUTIMENS": "syscall", - "syscall.SYS_FUTIMES": "syscall", - "syscall.SYS_FUTIMESAT": "syscall", - "syscall.SYS_GETATTRLIST": "syscall", - "syscall.SYS_GETAUDIT": "syscall", - "syscall.SYS_GETAUDIT_ADDR": "syscall", - "syscall.SYS_GETAUID": "syscall", - "syscall.SYS_GETCONTEXT": "syscall", - "syscall.SYS_GETCPU": "syscall", - "syscall.SYS_GETCWD": "syscall", - "syscall.SYS_GETDENTS": "syscall", - "syscall.SYS_GETDENTS64": "syscall", - "syscall.SYS_GETDIRENTRIES": "syscall", - "syscall.SYS_GETDIRENTRIES64": "syscall", - "syscall.SYS_GETDIRENTRIESATTR": "syscall", - "syscall.SYS_GETDTABLECOUNT": "syscall", - "syscall.SYS_GETDTABLESIZE": "syscall", - "syscall.SYS_GETEGID": "syscall", - "syscall.SYS_GETEGID32": "syscall", - "syscall.SYS_GETEUID": "syscall", - "syscall.SYS_GETEUID32": "syscall", - "syscall.SYS_GETFH": "syscall", - "syscall.SYS_GETFSSTAT": "syscall", - "syscall.SYS_GETFSSTAT64": "syscall", - "syscall.SYS_GETGID": "syscall", - "syscall.SYS_GETGID32": "syscall", - "syscall.SYS_GETGROUPS": "syscall", - "syscall.SYS_GETGROUPS32": "syscall", - "syscall.SYS_GETHOSTUUID": "syscall", - "syscall.SYS_GETITIMER": "syscall", - "syscall.SYS_GETLCID": "syscall", - "syscall.SYS_GETLOGIN": "syscall", - "syscall.SYS_GETLOGINCLASS": "syscall", - "syscall.SYS_GETPEERNAME": "syscall", - "syscall.SYS_GETPGID": "syscall", - "syscall.SYS_GETPGRP": "syscall", - "syscall.SYS_GETPID": "syscall", - "syscall.SYS_GETPMSG": "syscall", - "syscall.SYS_GETPPID": "syscall", - "syscall.SYS_GETPRIORITY": "syscall", - "syscall.SYS_GETRESGID": "syscall", - "syscall.SYS_GETRESGID32": "syscall", - "syscall.SYS_GETRESUID": "syscall", - "syscall.SYS_GETRESUID32": "syscall", - "syscall.SYS_GETRLIMIT": "syscall", - "syscall.SYS_GETRTABLE": "syscall", - "syscall.SYS_GETRUSAGE": "syscall", - "syscall.SYS_GETSGROUPS": "syscall", - "syscall.SYS_GETSID": "syscall", - "syscall.SYS_GETSOCKNAME": "syscall", - "syscall.SYS_GETSOCKOPT": "syscall", - "syscall.SYS_GETTHRID": "syscall", - "syscall.SYS_GETTID": "syscall", - "syscall.SYS_GETTIMEOFDAY": "syscall", - "syscall.SYS_GETUID": "syscall", - "syscall.SYS_GETUID32": "syscall", - "syscall.SYS_GETVFSSTAT": "syscall", - "syscall.SYS_GETWGROUPS": "syscall", - "syscall.SYS_GETXATTR": "syscall", - "syscall.SYS_GET_KERNEL_SYMS": "syscall", - "syscall.SYS_GET_MEMPOLICY": "syscall", - "syscall.SYS_GET_ROBUST_LIST": "syscall", - "syscall.SYS_GET_THREAD_AREA": "syscall", - "syscall.SYS_GTTY": "syscall", - "syscall.SYS_IDENTITYSVC": "syscall", - "syscall.SYS_IDLE": "syscall", - "syscall.SYS_INITGROUPS": "syscall", - "syscall.SYS_INIT_MODULE": "syscall", - "syscall.SYS_INOTIFY_ADD_WATCH": "syscall", - "syscall.SYS_INOTIFY_INIT": "syscall", - "syscall.SYS_INOTIFY_INIT1": "syscall", - "syscall.SYS_INOTIFY_RM_WATCH": "syscall", - "syscall.SYS_IOCTL": "syscall", - "syscall.SYS_IOPERM": "syscall", - "syscall.SYS_IOPL": "syscall", - "syscall.SYS_IOPOLICYSYS": "syscall", - "syscall.SYS_IOPRIO_GET": "syscall", - "syscall.SYS_IOPRIO_SET": "syscall", - "syscall.SYS_IO_CANCEL": "syscall", - "syscall.SYS_IO_DESTROY": "syscall", - "syscall.SYS_IO_GETEVENTS": "syscall", - "syscall.SYS_IO_SETUP": "syscall", - "syscall.SYS_IO_SUBMIT": "syscall", - "syscall.SYS_IPC": "syscall", - "syscall.SYS_ISSETUGID": "syscall", - "syscall.SYS_JAIL": "syscall", - "syscall.SYS_JAIL_ATTACH": "syscall", - "syscall.SYS_JAIL_GET": "syscall", - "syscall.SYS_JAIL_REMOVE": "syscall", - "syscall.SYS_JAIL_SET": "syscall", - "syscall.SYS_KDEBUG_TRACE": "syscall", - "syscall.SYS_KENV": "syscall", - "syscall.SYS_KEVENT": "syscall", - "syscall.SYS_KEVENT64": "syscall", - "syscall.SYS_KEXEC_LOAD": "syscall", - "syscall.SYS_KEYCTL": "syscall", - "syscall.SYS_KILL": "syscall", - "syscall.SYS_KLDFIND": "syscall", - "syscall.SYS_KLDFIRSTMOD": "syscall", - "syscall.SYS_KLDLOAD": "syscall", - "syscall.SYS_KLDNEXT": "syscall", - "syscall.SYS_KLDSTAT": "syscall", - "syscall.SYS_KLDSYM": "syscall", - "syscall.SYS_KLDUNLOAD": "syscall", - "syscall.SYS_KLDUNLOADF": "syscall", - "syscall.SYS_KQUEUE": "syscall", - "syscall.SYS_KQUEUE1": "syscall", - "syscall.SYS_KTIMER_CREATE": "syscall", - "syscall.SYS_KTIMER_DELETE": "syscall", - "syscall.SYS_KTIMER_GETOVERRUN": "syscall", - "syscall.SYS_KTIMER_GETTIME": "syscall", - "syscall.SYS_KTIMER_SETTIME": "syscall", - "syscall.SYS_KTRACE": "syscall", - "syscall.SYS_LCHFLAGS": "syscall", - "syscall.SYS_LCHMOD": "syscall", - "syscall.SYS_LCHOWN": "syscall", - "syscall.SYS_LCHOWN32": "syscall", - "syscall.SYS_LGETFH": "syscall", - "syscall.SYS_LGETXATTR": "syscall", - "syscall.SYS_LINK": "syscall", - "syscall.SYS_LINKAT": "syscall", - "syscall.SYS_LIO_LISTIO": "syscall", - "syscall.SYS_LISTEN": "syscall", - "syscall.SYS_LISTXATTR": "syscall", - "syscall.SYS_LLISTXATTR": "syscall", - "syscall.SYS_LOCK": "syscall", - "syscall.SYS_LOOKUP_DCOOKIE": "syscall", - "syscall.SYS_LPATHCONF": "syscall", - "syscall.SYS_LREMOVEXATTR": "syscall", - "syscall.SYS_LSEEK": "syscall", - "syscall.SYS_LSETXATTR": "syscall", - "syscall.SYS_LSTAT": "syscall", - "syscall.SYS_LSTAT64": "syscall", - "syscall.SYS_LSTAT64_EXTENDED": "syscall", - "syscall.SYS_LSTATV": "syscall", - "syscall.SYS_LSTAT_EXTENDED": "syscall", - "syscall.SYS_LUTIMES": "syscall", - "syscall.SYS_MAC_SYSCALL": "syscall", - "syscall.SYS_MADVISE": "syscall", - "syscall.SYS_MADVISE1": "syscall", - "syscall.SYS_MAXSYSCALL": "syscall", - "syscall.SYS_MBIND": "syscall", - "syscall.SYS_MIGRATE_PAGES": "syscall", - "syscall.SYS_MINCORE": "syscall", - "syscall.SYS_MINHERIT": "syscall", - "syscall.SYS_MKCOMPLEX": "syscall", - "syscall.SYS_MKDIR": "syscall", - "syscall.SYS_MKDIRAT": "syscall", - "syscall.SYS_MKDIR_EXTENDED": "syscall", - "syscall.SYS_MKFIFO": "syscall", - "syscall.SYS_MKFIFOAT": "syscall", - "syscall.SYS_MKFIFO_EXTENDED": "syscall", - "syscall.SYS_MKNOD": "syscall", - "syscall.SYS_MKNODAT": "syscall", - "syscall.SYS_MLOCK": "syscall", - "syscall.SYS_MLOCKALL": "syscall", - "syscall.SYS_MMAP": "syscall", - "syscall.SYS_MMAP2": "syscall", - "syscall.SYS_MODCTL": "syscall", - "syscall.SYS_MODFIND": "syscall", - "syscall.SYS_MODFNEXT": "syscall", - "syscall.SYS_MODIFY_LDT": "syscall", - "syscall.SYS_MODNEXT": "syscall", - "syscall.SYS_MODSTAT": "syscall", - "syscall.SYS_MODWATCH": "syscall", - "syscall.SYS_MOUNT": "syscall", - "syscall.SYS_MOVE_PAGES": "syscall", - "syscall.SYS_MPROTECT": "syscall", - "syscall.SYS_MPX": "syscall", - "syscall.SYS_MQUERY": "syscall", - "syscall.SYS_MQ_GETSETATTR": "syscall", - "syscall.SYS_MQ_NOTIFY": "syscall", - "syscall.SYS_MQ_OPEN": "syscall", - "syscall.SYS_MQ_TIMEDRECEIVE": "syscall", - "syscall.SYS_MQ_TIMEDSEND": "syscall", - "syscall.SYS_MQ_UNLINK": "syscall", - "syscall.SYS_MREMAP": "syscall", - "syscall.SYS_MSGCTL": "syscall", - "syscall.SYS_MSGGET": "syscall", - "syscall.SYS_MSGRCV": "syscall", - "syscall.SYS_MSGRCV_NOCANCEL": "syscall", - "syscall.SYS_MSGSND": "syscall", - "syscall.SYS_MSGSND_NOCANCEL": "syscall", - "syscall.SYS_MSGSYS": "syscall", - "syscall.SYS_MSYNC": "syscall", - "syscall.SYS_MSYNC_NOCANCEL": "syscall", - "syscall.SYS_MUNLOCK": "syscall", - "syscall.SYS_MUNLOCKALL": "syscall", - "syscall.SYS_MUNMAP": "syscall", - "syscall.SYS_NAME_TO_HANDLE_AT": "syscall", - "syscall.SYS_NANOSLEEP": "syscall", - "syscall.SYS_NEWFSTATAT": "syscall", - "syscall.SYS_NFSCLNT": "syscall", - "syscall.SYS_NFSSERVCTL": "syscall", - "syscall.SYS_NFSSVC": "syscall", - "syscall.SYS_NFSTAT": "syscall", - "syscall.SYS_NICE": "syscall", - "syscall.SYS_NLSTAT": "syscall", - "syscall.SYS_NMOUNT": "syscall", - "syscall.SYS_NSTAT": "syscall", - "syscall.SYS_NTP_ADJTIME": "syscall", - "syscall.SYS_NTP_GETTIME": "syscall", - "syscall.SYS_OABI_SYSCALL_BASE": "syscall", - "syscall.SYS_OBREAK": "syscall", - "syscall.SYS_OLDFSTAT": "syscall", - "syscall.SYS_OLDLSTAT": "syscall", - "syscall.SYS_OLDOLDUNAME": "syscall", - "syscall.SYS_OLDSTAT": "syscall", - "syscall.SYS_OLDUNAME": "syscall", - "syscall.SYS_OPEN": "syscall", - "syscall.SYS_OPENAT": "syscall", - "syscall.SYS_OPENBSD_POLL": "syscall", - "syscall.SYS_OPEN_BY_HANDLE_AT": "syscall", - "syscall.SYS_OPEN_EXTENDED": "syscall", - "syscall.SYS_OPEN_NOCANCEL": "syscall", - "syscall.SYS_OVADVISE": "syscall", - "syscall.SYS_PACCEPT": "syscall", - "syscall.SYS_PATHCONF": "syscall", - "syscall.SYS_PAUSE": "syscall", - "syscall.SYS_PCICONFIG_IOBASE": "syscall", - "syscall.SYS_PCICONFIG_READ": "syscall", - "syscall.SYS_PCICONFIG_WRITE": "syscall", - "syscall.SYS_PDFORK": "syscall", - "syscall.SYS_PDGETPID": "syscall", - "syscall.SYS_PDKILL": "syscall", - "syscall.SYS_PERF_EVENT_OPEN": "syscall", - "syscall.SYS_PERSONALITY": "syscall", - "syscall.SYS_PID_HIBERNATE": "syscall", - "syscall.SYS_PID_RESUME": "syscall", - "syscall.SYS_PID_SHUTDOWN_SOCKETS": "syscall", - "syscall.SYS_PID_SUSPEND": "syscall", - "syscall.SYS_PIPE": "syscall", - "syscall.SYS_PIPE2": "syscall", - "syscall.SYS_PIVOT_ROOT": "syscall", - "syscall.SYS_PMC_CONTROL": "syscall", - "syscall.SYS_PMC_GET_INFO": "syscall", - "syscall.SYS_POLL": "syscall", - "syscall.SYS_POLLTS": "syscall", - "syscall.SYS_POLL_NOCANCEL": "syscall", - "syscall.SYS_POSIX_FADVISE": "syscall", - "syscall.SYS_POSIX_FALLOCATE": "syscall", - "syscall.SYS_POSIX_OPENPT": "syscall", - "syscall.SYS_POSIX_SPAWN": "syscall", - "syscall.SYS_PPOLL": "syscall", - "syscall.SYS_PRCTL": "syscall", - "syscall.SYS_PREAD": "syscall", - "syscall.SYS_PREAD64": "syscall", - "syscall.SYS_PREADV": "syscall", - "syscall.SYS_PREAD_NOCANCEL": "syscall", - "syscall.SYS_PRLIMIT64": "syscall", - "syscall.SYS_PROCCTL": "syscall", - "syscall.SYS_PROCESS_POLICY": "syscall", - "syscall.SYS_PROCESS_VM_READV": "syscall", - "syscall.SYS_PROCESS_VM_WRITEV": "syscall", - "syscall.SYS_PROC_INFO": "syscall", - "syscall.SYS_PROF": "syscall", - "syscall.SYS_PROFIL": "syscall", - "syscall.SYS_PSELECT": "syscall", - "syscall.SYS_PSELECT6": "syscall", - "syscall.SYS_PSET_ASSIGN": "syscall", - "syscall.SYS_PSET_CREATE": "syscall", - "syscall.SYS_PSET_DESTROY": "syscall", - "syscall.SYS_PSYNCH_CVBROAD": "syscall", - "syscall.SYS_PSYNCH_CVCLRPREPOST": "syscall", - "syscall.SYS_PSYNCH_CVSIGNAL": "syscall", - "syscall.SYS_PSYNCH_CVWAIT": "syscall", - "syscall.SYS_PSYNCH_MUTEXDROP": "syscall", - "syscall.SYS_PSYNCH_MUTEXWAIT": "syscall", - "syscall.SYS_PSYNCH_RW_DOWNGRADE": "syscall", - "syscall.SYS_PSYNCH_RW_LONGRDLOCK": "syscall", - "syscall.SYS_PSYNCH_RW_RDLOCK": "syscall", - "syscall.SYS_PSYNCH_RW_UNLOCK": "syscall", - "syscall.SYS_PSYNCH_RW_UNLOCK2": "syscall", - "syscall.SYS_PSYNCH_RW_UPGRADE": "syscall", - "syscall.SYS_PSYNCH_RW_WRLOCK": "syscall", - "syscall.SYS_PSYNCH_RW_YIELDWRLOCK": "syscall", - "syscall.SYS_PTRACE": "syscall", - "syscall.SYS_PUTPMSG": "syscall", - "syscall.SYS_PWRITE": "syscall", - "syscall.SYS_PWRITE64": "syscall", - "syscall.SYS_PWRITEV": "syscall", - "syscall.SYS_PWRITE_NOCANCEL": "syscall", - "syscall.SYS_QUERY_MODULE": "syscall", - "syscall.SYS_QUOTACTL": "syscall", - "syscall.SYS_RASCTL": "syscall", - "syscall.SYS_RCTL_ADD_RULE": "syscall", - "syscall.SYS_RCTL_GET_LIMITS": "syscall", - "syscall.SYS_RCTL_GET_RACCT": "syscall", - "syscall.SYS_RCTL_GET_RULES": "syscall", - "syscall.SYS_RCTL_REMOVE_RULE": "syscall", - "syscall.SYS_READ": "syscall", - "syscall.SYS_READAHEAD": "syscall", - "syscall.SYS_READDIR": "syscall", - "syscall.SYS_READLINK": "syscall", - "syscall.SYS_READLINKAT": "syscall", - "syscall.SYS_READV": "syscall", - "syscall.SYS_READV_NOCANCEL": "syscall", - "syscall.SYS_READ_NOCANCEL": "syscall", - "syscall.SYS_REBOOT": "syscall", - "syscall.SYS_RECV": "syscall", - "syscall.SYS_RECVFROM": "syscall", - "syscall.SYS_RECVFROM_NOCANCEL": "syscall", - "syscall.SYS_RECVMMSG": "syscall", - "syscall.SYS_RECVMSG": "syscall", - "syscall.SYS_RECVMSG_NOCANCEL": "syscall", - "syscall.SYS_REMAP_FILE_PAGES": "syscall", - "syscall.SYS_REMOVEXATTR": "syscall", - "syscall.SYS_RENAME": "syscall", - "syscall.SYS_RENAMEAT": "syscall", - "syscall.SYS_REQUEST_KEY": "syscall", - "syscall.SYS_RESTART_SYSCALL": "syscall", - "syscall.SYS_REVOKE": "syscall", - "syscall.SYS_RFORK": "syscall", - "syscall.SYS_RMDIR": "syscall", - "syscall.SYS_RTPRIO": "syscall", - "syscall.SYS_RTPRIO_THREAD": "syscall", - "syscall.SYS_RT_SIGACTION": "syscall", - "syscall.SYS_RT_SIGPENDING": "syscall", - "syscall.SYS_RT_SIGPROCMASK": "syscall", - "syscall.SYS_RT_SIGQUEUEINFO": "syscall", - "syscall.SYS_RT_SIGRETURN": "syscall", - "syscall.SYS_RT_SIGSUSPEND": "syscall", - "syscall.SYS_RT_SIGTIMEDWAIT": "syscall", - "syscall.SYS_RT_TGSIGQUEUEINFO": "syscall", - "syscall.SYS_SBRK": "syscall", - "syscall.SYS_SCHED_GETAFFINITY": "syscall", - "syscall.SYS_SCHED_GETPARAM": "syscall", - "syscall.SYS_SCHED_GETSCHEDULER": "syscall", - "syscall.SYS_SCHED_GET_PRIORITY_MAX": "syscall", - "syscall.SYS_SCHED_GET_PRIORITY_MIN": "syscall", - "syscall.SYS_SCHED_RR_GET_INTERVAL": "syscall", - "syscall.SYS_SCHED_SETAFFINITY": "syscall", - "syscall.SYS_SCHED_SETPARAM": "syscall", - "syscall.SYS_SCHED_SETSCHEDULER": "syscall", - "syscall.SYS_SCHED_YIELD": "syscall", - "syscall.SYS_SCTP_GENERIC_RECVMSG": "syscall", - "syscall.SYS_SCTP_GENERIC_SENDMSG": "syscall", - "syscall.SYS_SCTP_GENERIC_SENDMSG_IOV": "syscall", - "syscall.SYS_SCTP_PEELOFF": "syscall", - "syscall.SYS_SEARCHFS": "syscall", - "syscall.SYS_SECURITY": "syscall", - "syscall.SYS_SELECT": "syscall", - "syscall.SYS_SELECT_NOCANCEL": "syscall", - "syscall.SYS_SEMCONFIG": "syscall", - "syscall.SYS_SEMCTL": "syscall", - "syscall.SYS_SEMGET": "syscall", - "syscall.SYS_SEMOP": "syscall", - "syscall.SYS_SEMSYS": "syscall", - "syscall.SYS_SEMTIMEDOP": "syscall", - "syscall.SYS_SEM_CLOSE": "syscall", - "syscall.SYS_SEM_DESTROY": "syscall", - "syscall.SYS_SEM_GETVALUE": "syscall", - "syscall.SYS_SEM_INIT": "syscall", - "syscall.SYS_SEM_OPEN": "syscall", - "syscall.SYS_SEM_POST": "syscall", - "syscall.SYS_SEM_TRYWAIT": "syscall", - "syscall.SYS_SEM_UNLINK": "syscall", - "syscall.SYS_SEM_WAIT": "syscall", - "syscall.SYS_SEM_WAIT_NOCANCEL": "syscall", - "syscall.SYS_SEND": "syscall", - "syscall.SYS_SENDFILE": "syscall", - "syscall.SYS_SENDFILE64": "syscall", - "syscall.SYS_SENDMMSG": "syscall", - "syscall.SYS_SENDMSG": "syscall", - "syscall.SYS_SENDMSG_NOCANCEL": "syscall", - "syscall.SYS_SENDTO": "syscall", - "syscall.SYS_SENDTO_NOCANCEL": "syscall", - "syscall.SYS_SETATTRLIST": "syscall", - "syscall.SYS_SETAUDIT": "syscall", - "syscall.SYS_SETAUDIT_ADDR": "syscall", - "syscall.SYS_SETAUID": "syscall", - "syscall.SYS_SETCONTEXT": "syscall", - "syscall.SYS_SETDOMAINNAME": "syscall", - "syscall.SYS_SETEGID": "syscall", - "syscall.SYS_SETEUID": "syscall", - "syscall.SYS_SETFIB": "syscall", - "syscall.SYS_SETFSGID": "syscall", - "syscall.SYS_SETFSGID32": "syscall", - "syscall.SYS_SETFSUID": "syscall", - "syscall.SYS_SETFSUID32": "syscall", - "syscall.SYS_SETGID": "syscall", - "syscall.SYS_SETGID32": "syscall", - "syscall.SYS_SETGROUPS": "syscall", - "syscall.SYS_SETGROUPS32": "syscall", - "syscall.SYS_SETHOSTNAME": "syscall", - "syscall.SYS_SETITIMER": "syscall", - "syscall.SYS_SETLCID": "syscall", - "syscall.SYS_SETLOGIN": "syscall", - "syscall.SYS_SETLOGINCLASS": "syscall", - "syscall.SYS_SETNS": "syscall", - "syscall.SYS_SETPGID": "syscall", - "syscall.SYS_SETPRIORITY": "syscall", - "syscall.SYS_SETPRIVEXEC": "syscall", - "syscall.SYS_SETREGID": "syscall", - "syscall.SYS_SETREGID32": "syscall", - "syscall.SYS_SETRESGID": "syscall", - "syscall.SYS_SETRESGID32": "syscall", - "syscall.SYS_SETRESUID": "syscall", - "syscall.SYS_SETRESUID32": "syscall", - "syscall.SYS_SETREUID": "syscall", - "syscall.SYS_SETREUID32": "syscall", - "syscall.SYS_SETRLIMIT": "syscall", - "syscall.SYS_SETRTABLE": "syscall", - "syscall.SYS_SETSGROUPS": "syscall", - "syscall.SYS_SETSID": "syscall", - "syscall.SYS_SETSOCKOPT": "syscall", - "syscall.SYS_SETTID": "syscall", - "syscall.SYS_SETTID_WITH_PID": "syscall", - "syscall.SYS_SETTIMEOFDAY": "syscall", - "syscall.SYS_SETUID": "syscall", - "syscall.SYS_SETUID32": "syscall", - "syscall.SYS_SETWGROUPS": "syscall", - "syscall.SYS_SETXATTR": "syscall", - "syscall.SYS_SET_MEMPOLICY": "syscall", - "syscall.SYS_SET_ROBUST_LIST": "syscall", - "syscall.SYS_SET_THREAD_AREA": "syscall", - "syscall.SYS_SET_TID_ADDRESS": "syscall", - "syscall.SYS_SGETMASK": "syscall", - "syscall.SYS_SHARED_REGION_CHECK_NP": "syscall", - "syscall.SYS_SHARED_REGION_MAP_AND_SLIDE_NP": "syscall", - "syscall.SYS_SHMAT": "syscall", - "syscall.SYS_SHMCTL": "syscall", - "syscall.SYS_SHMDT": "syscall", - "syscall.SYS_SHMGET": "syscall", - "syscall.SYS_SHMSYS": "syscall", - "syscall.SYS_SHM_OPEN": "syscall", - "syscall.SYS_SHM_UNLINK": "syscall", - "syscall.SYS_SHUTDOWN": "syscall", - "syscall.SYS_SIGACTION": "syscall", - "syscall.SYS_SIGALTSTACK": "syscall", - "syscall.SYS_SIGNAL": "syscall", - "syscall.SYS_SIGNALFD": "syscall", - "syscall.SYS_SIGNALFD4": "syscall", - "syscall.SYS_SIGPENDING": "syscall", - "syscall.SYS_SIGPROCMASK": "syscall", - "syscall.SYS_SIGQUEUE": "syscall", - "syscall.SYS_SIGQUEUEINFO": "syscall", - "syscall.SYS_SIGRETURN": "syscall", - "syscall.SYS_SIGSUSPEND": "syscall", - "syscall.SYS_SIGSUSPEND_NOCANCEL": "syscall", - "syscall.SYS_SIGTIMEDWAIT": "syscall", - "syscall.SYS_SIGWAIT": "syscall", - "syscall.SYS_SIGWAITINFO": "syscall", - "syscall.SYS_SOCKET": "syscall", - "syscall.SYS_SOCKETCALL": "syscall", - "syscall.SYS_SOCKETPAIR": "syscall", - "syscall.SYS_SPLICE": "syscall", - "syscall.SYS_SSETMASK": "syscall", - "syscall.SYS_SSTK": "syscall", - "syscall.SYS_STACK_SNAPSHOT": "syscall", - "syscall.SYS_STAT": "syscall", - "syscall.SYS_STAT64": "syscall", - "syscall.SYS_STAT64_EXTENDED": "syscall", - "syscall.SYS_STATFS": "syscall", - "syscall.SYS_STATFS64": "syscall", - "syscall.SYS_STATV": "syscall", - "syscall.SYS_STATVFS1": "syscall", - "syscall.SYS_STAT_EXTENDED": "syscall", - "syscall.SYS_STIME": "syscall", - "syscall.SYS_STTY": "syscall", - "syscall.SYS_SWAPCONTEXT": "syscall", - "syscall.SYS_SWAPCTL": "syscall", - "syscall.SYS_SWAPOFF": "syscall", - "syscall.SYS_SWAPON": "syscall", - "syscall.SYS_SYMLINK": "syscall", - "syscall.SYS_SYMLINKAT": "syscall", - "syscall.SYS_SYNC": "syscall", - "syscall.SYS_SYNCFS": "syscall", - "syscall.SYS_SYNC_FILE_RANGE": "syscall", - "syscall.SYS_SYSARCH": "syscall", - "syscall.SYS_SYSCALL": "syscall", - "syscall.SYS_SYSCALL_BASE": "syscall", - "syscall.SYS_SYSFS": "syscall", - "syscall.SYS_SYSINFO": "syscall", - "syscall.SYS_SYSLOG": "syscall", - "syscall.SYS_TEE": "syscall", - "syscall.SYS_TGKILL": "syscall", - "syscall.SYS_THREAD_SELFID": "syscall", - "syscall.SYS_THR_CREATE": "syscall", - "syscall.SYS_THR_EXIT": "syscall", - "syscall.SYS_THR_KILL": "syscall", - "syscall.SYS_THR_KILL2": "syscall", - "syscall.SYS_THR_NEW": "syscall", - "syscall.SYS_THR_SELF": "syscall", - "syscall.SYS_THR_SET_NAME": "syscall", - "syscall.SYS_THR_SUSPEND": "syscall", - "syscall.SYS_THR_WAKE": "syscall", - "syscall.SYS_TIME": "syscall", - "syscall.SYS_TIMERFD_CREATE": "syscall", - "syscall.SYS_TIMERFD_GETTIME": "syscall", - "syscall.SYS_TIMERFD_SETTIME": "syscall", - "syscall.SYS_TIMER_CREATE": "syscall", - "syscall.SYS_TIMER_DELETE": "syscall", - "syscall.SYS_TIMER_GETOVERRUN": "syscall", - "syscall.SYS_TIMER_GETTIME": "syscall", - "syscall.SYS_TIMER_SETTIME": "syscall", - "syscall.SYS_TIMES": "syscall", - "syscall.SYS_TKILL": "syscall", - "syscall.SYS_TRUNCATE": "syscall", - "syscall.SYS_TRUNCATE64": "syscall", - "syscall.SYS_TUXCALL": "syscall", - "syscall.SYS_UGETRLIMIT": "syscall", - "syscall.SYS_ULIMIT": "syscall", - "syscall.SYS_UMASK": "syscall", - "syscall.SYS_UMASK_EXTENDED": "syscall", - "syscall.SYS_UMOUNT": "syscall", - "syscall.SYS_UMOUNT2": "syscall", - "syscall.SYS_UNAME": "syscall", - "syscall.SYS_UNDELETE": "syscall", - "syscall.SYS_UNLINK": "syscall", - "syscall.SYS_UNLINKAT": "syscall", - "syscall.SYS_UNMOUNT": "syscall", - "syscall.SYS_UNSHARE": "syscall", - "syscall.SYS_USELIB": "syscall", - "syscall.SYS_USTAT": "syscall", - "syscall.SYS_UTIME": "syscall", - "syscall.SYS_UTIMENSAT": "syscall", - "syscall.SYS_UTIMES": "syscall", - "syscall.SYS_UTRACE": "syscall", - "syscall.SYS_UUIDGEN": "syscall", - "syscall.SYS_VADVISE": "syscall", - "syscall.SYS_VFORK": "syscall", - "syscall.SYS_VHANGUP": "syscall", - "syscall.SYS_VM86": "syscall", - "syscall.SYS_VM86OLD": "syscall", - "syscall.SYS_VMSPLICE": "syscall", - "syscall.SYS_VM_PRESSURE_MONITOR": "syscall", - "syscall.SYS_VSERVER": "syscall", - "syscall.SYS_WAIT4": "syscall", - "syscall.SYS_WAIT4_NOCANCEL": "syscall", - "syscall.SYS_WAIT6": "syscall", - "syscall.SYS_WAITEVENT": "syscall", - "syscall.SYS_WAITID": "syscall", - "syscall.SYS_WAITID_NOCANCEL": "syscall", - "syscall.SYS_WAITPID": "syscall", - "syscall.SYS_WATCHEVENT": "syscall", - "syscall.SYS_WORKQ_KERNRETURN": "syscall", - "syscall.SYS_WORKQ_OPEN": "syscall", - "syscall.SYS_WRITE": "syscall", - "syscall.SYS_WRITEV": "syscall", - "syscall.SYS_WRITEV_NOCANCEL": "syscall", - "syscall.SYS_WRITE_NOCANCEL": "syscall", - "syscall.SYS_YIELD": "syscall", - "syscall.SYS__LLSEEK": "syscall", - "syscall.SYS__LWP_CONTINUE": "syscall", - "syscall.SYS__LWP_CREATE": "syscall", - "syscall.SYS__LWP_CTL": "syscall", - "syscall.SYS__LWP_DETACH": "syscall", - "syscall.SYS__LWP_EXIT": "syscall", - "syscall.SYS__LWP_GETNAME": "syscall", - "syscall.SYS__LWP_GETPRIVATE": "syscall", - "syscall.SYS__LWP_KILL": "syscall", - "syscall.SYS__LWP_PARK": "syscall", - "syscall.SYS__LWP_SELF": "syscall", - "syscall.SYS__LWP_SETNAME": "syscall", - "syscall.SYS__LWP_SETPRIVATE": "syscall", - "syscall.SYS__LWP_SUSPEND": "syscall", - "syscall.SYS__LWP_UNPARK": "syscall", - "syscall.SYS__LWP_UNPARK_ALL": "syscall", - "syscall.SYS__LWP_WAIT": "syscall", - "syscall.SYS__LWP_WAKEUP": "syscall", - "syscall.SYS__NEWSELECT": "syscall", - "syscall.SYS__PSET_BIND": "syscall", - "syscall.SYS__SCHED_GETAFFINITY": "syscall", - "syscall.SYS__SCHED_GETPARAM": "syscall", - "syscall.SYS__SCHED_SETAFFINITY": "syscall", - "syscall.SYS__SCHED_SETPARAM": "syscall", - "syscall.SYS__SYSCTL": "syscall", - "syscall.SYS__UMTX_LOCK": "syscall", - "syscall.SYS__UMTX_OP": "syscall", - "syscall.SYS__UMTX_UNLOCK": "syscall", - "syscall.SYS___ACL_ACLCHECK_FD": "syscall", - "syscall.SYS___ACL_ACLCHECK_FILE": "syscall", - "syscall.SYS___ACL_ACLCHECK_LINK": "syscall", - "syscall.SYS___ACL_DELETE_FD": "syscall", - "syscall.SYS___ACL_DELETE_FILE": "syscall", - "syscall.SYS___ACL_DELETE_LINK": "syscall", - "syscall.SYS___ACL_GET_FD": "syscall", - "syscall.SYS___ACL_GET_FILE": "syscall", - "syscall.SYS___ACL_GET_LINK": "syscall", - "syscall.SYS___ACL_SET_FD": "syscall", - "syscall.SYS___ACL_SET_FILE": "syscall", - "syscall.SYS___ACL_SET_LINK": "syscall", - "syscall.SYS___CLONE": "syscall", - "syscall.SYS___DISABLE_THREADSIGNAL": "syscall", - "syscall.SYS___GETCWD": "syscall", - "syscall.SYS___GETLOGIN": "syscall", - "syscall.SYS___GET_TCB": "syscall", - "syscall.SYS___MAC_EXECVE": "syscall", - "syscall.SYS___MAC_GETFSSTAT": "syscall", - "syscall.SYS___MAC_GET_FD": "syscall", - "syscall.SYS___MAC_GET_FILE": "syscall", - "syscall.SYS___MAC_GET_LCID": "syscall", - "syscall.SYS___MAC_GET_LCTX": "syscall", - "syscall.SYS___MAC_GET_LINK": "syscall", - "syscall.SYS___MAC_GET_MOUNT": "syscall", - "syscall.SYS___MAC_GET_PID": "syscall", - "syscall.SYS___MAC_GET_PROC": "syscall", - "syscall.SYS___MAC_MOUNT": "syscall", - "syscall.SYS___MAC_SET_FD": "syscall", - "syscall.SYS___MAC_SET_FILE": "syscall", - "syscall.SYS___MAC_SET_LCTX": "syscall", - "syscall.SYS___MAC_SET_LINK": "syscall", - "syscall.SYS___MAC_SET_PROC": "syscall", - "syscall.SYS___MAC_SYSCALL": "syscall", - "syscall.SYS___OLD_SEMWAIT_SIGNAL": "syscall", - "syscall.SYS___OLD_SEMWAIT_SIGNAL_NOCANCEL": "syscall", - "syscall.SYS___POSIX_CHOWN": "syscall", - "syscall.SYS___POSIX_FCHOWN": "syscall", - "syscall.SYS___POSIX_LCHOWN": "syscall", - "syscall.SYS___POSIX_RENAME": "syscall", - "syscall.SYS___PTHREAD_CANCELED": "syscall", - "syscall.SYS___PTHREAD_CHDIR": "syscall", - "syscall.SYS___PTHREAD_FCHDIR": "syscall", - "syscall.SYS___PTHREAD_KILL": "syscall", - "syscall.SYS___PTHREAD_MARKCANCEL": "syscall", - "syscall.SYS___PTHREAD_SIGMASK": "syscall", - "syscall.SYS___QUOTACTL": "syscall", - "syscall.SYS___SEMCTL": "syscall", - "syscall.SYS___SEMWAIT_SIGNAL": "syscall", - "syscall.SYS___SEMWAIT_SIGNAL_NOCANCEL": "syscall", - "syscall.SYS___SETLOGIN": "syscall", - "syscall.SYS___SETUGID": "syscall", - "syscall.SYS___SET_TCB": "syscall", - "syscall.SYS___SIGACTION_SIGTRAMP": "syscall", - "syscall.SYS___SIGTIMEDWAIT": "syscall", - "syscall.SYS___SIGWAIT": "syscall", - "syscall.SYS___SIGWAIT_NOCANCEL": "syscall", - "syscall.SYS___SYSCTL": "syscall", - "syscall.SYS___TFORK": "syscall", - "syscall.SYS___THREXIT": "syscall", - "syscall.SYS___THRSIGDIVERT": "syscall", - "syscall.SYS___THRSLEEP": "syscall", - "syscall.SYS___THRWAKEUP": "syscall", - "syscall.S_ARCH1": "syscall", - "syscall.S_ARCH2": "syscall", - "syscall.S_BLKSIZE": "syscall", - "syscall.S_IEXEC": "syscall", - "syscall.S_IFBLK": "syscall", - "syscall.S_IFCHR": "syscall", - "syscall.S_IFDIR": "syscall", - "syscall.S_IFIFO": "syscall", - "syscall.S_IFLNK": "syscall", - "syscall.S_IFMT": "syscall", - "syscall.S_IFREG": "syscall", - "syscall.S_IFSOCK": "syscall", - "syscall.S_IFWHT": "syscall", - "syscall.S_IREAD": "syscall", - "syscall.S_IRGRP": "syscall", - "syscall.S_IROTH": "syscall", - "syscall.S_IRUSR": "syscall", - "syscall.S_IRWXG": "syscall", - "syscall.S_IRWXO": "syscall", - "syscall.S_IRWXU": "syscall", - "syscall.S_ISGID": "syscall", - "syscall.S_ISTXT": "syscall", - "syscall.S_ISUID": "syscall", - "syscall.S_ISVTX": "syscall", - "syscall.S_IWGRP": "syscall", - "syscall.S_IWOTH": "syscall", - "syscall.S_IWRITE": "syscall", - "syscall.S_IWUSR": "syscall", - "syscall.S_IXGRP": "syscall", - "syscall.S_IXOTH": "syscall", - "syscall.S_IXUSR": "syscall", - "syscall.S_LOGIN_SET": "syscall", - "syscall.SecurityAttributes": "syscall", - "syscall.Seek": "syscall", - "syscall.Select": "syscall", - "syscall.Sendfile": "syscall", - "syscall.Sendmsg": "syscall", - "syscall.SendmsgN": "syscall", - "syscall.Sendto": "syscall", - "syscall.Servent": "syscall", - "syscall.SetBpf": "syscall", - "syscall.SetBpfBuflen": "syscall", - "syscall.SetBpfDatalink": "syscall", - "syscall.SetBpfHeadercmpl": "syscall", - "syscall.SetBpfImmediate": "syscall", - "syscall.SetBpfInterface": "syscall", - "syscall.SetBpfPromisc": "syscall", - "syscall.SetBpfTimeout": "syscall", - "syscall.SetCurrentDirectory": "syscall", - "syscall.SetEndOfFile": "syscall", - "syscall.SetEnvironmentVariable": "syscall", - "syscall.SetFileAttributes": "syscall", - "syscall.SetFileCompletionNotificationModes": "syscall", - "syscall.SetFilePointer": "syscall", - "syscall.SetFileTime": "syscall", - "syscall.SetHandleInformation": "syscall", - "syscall.SetKevent": "syscall", - "syscall.SetLsfPromisc": "syscall", - "syscall.SetNonblock": "syscall", - "syscall.Setdomainname": "syscall", - "syscall.Setegid": "syscall", - "syscall.Setenv": "syscall", - "syscall.Seteuid": "syscall", - "syscall.Setfsgid": "syscall", - "syscall.Setfsuid": "syscall", - "syscall.Setgid": "syscall", - "syscall.Setgroups": "syscall", - "syscall.Sethostname": "syscall", - "syscall.Setlogin": "syscall", - "syscall.Setpgid": "syscall", - "syscall.Setpriority": "syscall", - "syscall.Setprivexec": "syscall", - "syscall.Setregid": "syscall", - "syscall.Setresgid": "syscall", - "syscall.Setresuid": "syscall", - "syscall.Setreuid": "syscall", - "syscall.Setrlimit": "syscall", - "syscall.Setsid": "syscall", - "syscall.Setsockopt": "syscall", - "syscall.SetsockoptByte": "syscall", - "syscall.SetsockoptICMPv6Filter": "syscall", - "syscall.SetsockoptIPMreq": "syscall", - "syscall.SetsockoptIPMreqn": "syscall", - "syscall.SetsockoptIPv6Mreq": "syscall", - "syscall.SetsockoptInet4Addr": "syscall", - "syscall.SetsockoptInt": "syscall", - "syscall.SetsockoptLinger": "syscall", - "syscall.SetsockoptString": "syscall", - "syscall.SetsockoptTimeval": "syscall", - "syscall.Settimeofday": "syscall", - "syscall.Setuid": "syscall", - "syscall.Setxattr": "syscall", - "syscall.Shutdown": "syscall", - "syscall.SidTypeAlias": "syscall", - "syscall.SidTypeComputer": "syscall", - "syscall.SidTypeDeletedAccount": "syscall", - "syscall.SidTypeDomain": "syscall", - "syscall.SidTypeGroup": "syscall", - "syscall.SidTypeInvalid": "syscall", - "syscall.SidTypeLabel": "syscall", - "syscall.SidTypeUnknown": "syscall", - "syscall.SidTypeUser": "syscall", - "syscall.SidTypeWellKnownGroup": "syscall", - "syscall.Signal": "syscall", - "syscall.SizeofBpfHdr": "syscall", - "syscall.SizeofBpfInsn": "syscall", - "syscall.SizeofBpfProgram": "syscall", - "syscall.SizeofBpfStat": "syscall", - "syscall.SizeofBpfVersion": "syscall", - "syscall.SizeofBpfZbuf": "syscall", - "syscall.SizeofBpfZbufHeader": "syscall", - "syscall.SizeofCmsghdr": "syscall", - "syscall.SizeofICMPv6Filter": "syscall", - "syscall.SizeofIPMreq": "syscall", - "syscall.SizeofIPMreqn": "syscall", - "syscall.SizeofIPv6MTUInfo": "syscall", - "syscall.SizeofIPv6Mreq": "syscall", - "syscall.SizeofIfAddrmsg": "syscall", - "syscall.SizeofIfAnnounceMsghdr": "syscall", - "syscall.SizeofIfData": "syscall", - "syscall.SizeofIfInfomsg": "syscall", - "syscall.SizeofIfMsghdr": "syscall", - "syscall.SizeofIfaMsghdr": "syscall", - "syscall.SizeofIfmaMsghdr": "syscall", - "syscall.SizeofIfmaMsghdr2": "syscall", - "syscall.SizeofInet4Pktinfo": "syscall", - "syscall.SizeofInet6Pktinfo": "syscall", - "syscall.SizeofInotifyEvent": "syscall", - "syscall.SizeofLinger": "syscall", - "syscall.SizeofMsghdr": "syscall", - "syscall.SizeofNlAttr": "syscall", - "syscall.SizeofNlMsgerr": "syscall", - "syscall.SizeofNlMsghdr": "syscall", - "syscall.SizeofRtAttr": "syscall", - "syscall.SizeofRtGenmsg": "syscall", - "syscall.SizeofRtMetrics": "syscall", - "syscall.SizeofRtMsg": "syscall", - "syscall.SizeofRtMsghdr": "syscall", - "syscall.SizeofRtNexthop": "syscall", - "syscall.SizeofSockFilter": "syscall", - "syscall.SizeofSockFprog": "syscall", - "syscall.SizeofSockaddrAny": "syscall", - "syscall.SizeofSockaddrDatalink": "syscall", - "syscall.SizeofSockaddrInet4": "syscall", - "syscall.SizeofSockaddrInet6": "syscall", - "syscall.SizeofSockaddrLinklayer": "syscall", - "syscall.SizeofSockaddrNetlink": "syscall", - "syscall.SizeofSockaddrUnix": "syscall", - "syscall.SizeofTCPInfo": "syscall", - "syscall.SizeofUcred": "syscall", - "syscall.SlicePtrFromStrings": "syscall", - "syscall.SockFilter": "syscall", - "syscall.SockFprog": "syscall", - "syscall.SockaddrDatalink": "syscall", - "syscall.SockaddrGen": "syscall", - "syscall.SockaddrInet4": "syscall", - "syscall.SockaddrInet6": "syscall", - "syscall.SockaddrLinklayer": "syscall", - "syscall.SockaddrNetlink": "syscall", - "syscall.SockaddrUnix": "syscall", - "syscall.Socket": "syscall", - "syscall.SocketControlMessage": "syscall", - "syscall.SocketDisableIPv6": "syscall", - "syscall.Socketpair": "syscall", - "syscall.Splice": "syscall", - "syscall.StartProcess": "syscall", - "syscall.StartupInfo": "syscall", - "syscall.Stat": "syscall", - "syscall.Stat_t": "syscall", - "syscall.Statfs": "syscall", - "syscall.Statfs_t": "syscall", - "syscall.Stderr": "syscall", - "syscall.Stdin": "syscall", - "syscall.Stdout": "syscall", - "syscall.StringBytePtr": "syscall", - "syscall.StringByteSlice": "syscall", - "syscall.StringSlicePtr": "syscall", - "syscall.StringToSid": "syscall", - "syscall.StringToUTF16": "syscall", - "syscall.StringToUTF16Ptr": "syscall", - "syscall.Symlink": "syscall", - "syscall.Sync": "syscall", - "syscall.SyncFileRange": "syscall", - "syscall.SysProcAttr": "syscall", - "syscall.SysProcIDMap": "syscall", - "syscall.Syscall": "syscall", - "syscall.Syscall12": "syscall", - "syscall.Syscall15": "syscall", - "syscall.Syscall6": "syscall", - "syscall.Syscall9": "syscall", - "syscall.Sysctl": "syscall", - "syscall.SysctlUint32": "syscall", - "syscall.Sysctlnode": "syscall", - "syscall.Sysinfo": "syscall", - "syscall.Sysinfo_t": "syscall", - "syscall.Systemtime": "syscall", - "syscall.TCGETS": "syscall", - "syscall.TCIFLUSH": "syscall", - "syscall.TCIOFLUSH": "syscall", - "syscall.TCOFLUSH": "syscall", - "syscall.TCPInfo": "syscall", - "syscall.TCPKeepalive": "syscall", - "syscall.TCP_CA_NAME_MAX": "syscall", - "syscall.TCP_CONGCTL": "syscall", - "syscall.TCP_CONGESTION": "syscall", - "syscall.TCP_CONNECTIONTIMEOUT": "syscall", - "syscall.TCP_CORK": "syscall", - "syscall.TCP_DEFER_ACCEPT": "syscall", - "syscall.TCP_INFO": "syscall", - "syscall.TCP_KEEPALIVE": "syscall", - "syscall.TCP_KEEPCNT": "syscall", - "syscall.TCP_KEEPIDLE": "syscall", - "syscall.TCP_KEEPINIT": "syscall", - "syscall.TCP_KEEPINTVL": "syscall", - "syscall.TCP_LINGER2": "syscall", - "syscall.TCP_MAXBURST": "syscall", - "syscall.TCP_MAXHLEN": "syscall", - "syscall.TCP_MAXOLEN": "syscall", - "syscall.TCP_MAXSEG": "syscall", - "syscall.TCP_MAXWIN": "syscall", - "syscall.TCP_MAX_SACK": "syscall", - "syscall.TCP_MAX_WINSHIFT": "syscall", - "syscall.TCP_MD5SIG": "syscall", - "syscall.TCP_MD5SIG_MAXKEYLEN": "syscall", - "syscall.TCP_MINMSS": "syscall", - "syscall.TCP_MINMSSOVERLOAD": "syscall", - "syscall.TCP_MSS": "syscall", - "syscall.TCP_NODELAY": "syscall", - "syscall.TCP_NOOPT": "syscall", - "syscall.TCP_NOPUSH": "syscall", - "syscall.TCP_NSTATES": "syscall", - "syscall.TCP_QUICKACK": "syscall", - "syscall.TCP_RXT_CONNDROPTIME": "syscall", - "syscall.TCP_RXT_FINDROP": "syscall", - "syscall.TCP_SACK_ENABLE": "syscall", - "syscall.TCP_SYNCNT": "syscall", - "syscall.TCP_VENDOR": "syscall", - "syscall.TCP_WINDOW_CLAMP": "syscall", - "syscall.TCSAFLUSH": "syscall", - "syscall.TCSETS": "syscall", - "syscall.TF_DISCONNECT": "syscall", - "syscall.TF_REUSE_SOCKET": "syscall", - "syscall.TF_USE_DEFAULT_WORKER": "syscall", - "syscall.TF_USE_KERNEL_APC": "syscall", - "syscall.TF_USE_SYSTEM_THREAD": "syscall", - "syscall.TF_WRITE_BEHIND": "syscall", - "syscall.TH32CS_INHERIT": "syscall", - "syscall.TH32CS_SNAPALL": "syscall", - "syscall.TH32CS_SNAPHEAPLIST": "syscall", - "syscall.TH32CS_SNAPMODULE": "syscall", - "syscall.TH32CS_SNAPMODULE32": "syscall", - "syscall.TH32CS_SNAPPROCESS": "syscall", - "syscall.TH32CS_SNAPTHREAD": "syscall", - "syscall.TIME_ZONE_ID_DAYLIGHT": "syscall", - "syscall.TIME_ZONE_ID_STANDARD": "syscall", - "syscall.TIME_ZONE_ID_UNKNOWN": "syscall", - "syscall.TIOCCBRK": "syscall", - "syscall.TIOCCDTR": "syscall", - "syscall.TIOCCONS": "syscall", - "syscall.TIOCDCDTIMESTAMP": "syscall", - "syscall.TIOCDRAIN": "syscall", - "syscall.TIOCDSIMICROCODE": "syscall", - "syscall.TIOCEXCL": "syscall", - "syscall.TIOCEXT": "syscall", - "syscall.TIOCFLAG_CDTRCTS": "syscall", - "syscall.TIOCFLAG_CLOCAL": "syscall", - "syscall.TIOCFLAG_CRTSCTS": "syscall", - "syscall.TIOCFLAG_MDMBUF": "syscall", - "syscall.TIOCFLAG_PPS": "syscall", - "syscall.TIOCFLAG_SOFTCAR": "syscall", - "syscall.TIOCFLUSH": "syscall", - "syscall.TIOCGDEV": "syscall", - "syscall.TIOCGDRAINWAIT": "syscall", - "syscall.TIOCGETA": "syscall", - "syscall.TIOCGETD": "syscall", - "syscall.TIOCGFLAGS": "syscall", - "syscall.TIOCGICOUNT": "syscall", - "syscall.TIOCGLCKTRMIOS": "syscall", - "syscall.TIOCGLINED": "syscall", - "syscall.TIOCGPGRP": "syscall", - "syscall.TIOCGPTN": "syscall", - "syscall.TIOCGQSIZE": "syscall", - "syscall.TIOCGRANTPT": "syscall", - "syscall.TIOCGRS485": "syscall", - "syscall.TIOCGSERIAL": "syscall", - "syscall.TIOCGSID": "syscall", - "syscall.TIOCGSIZE": "syscall", - "syscall.TIOCGSOFTCAR": "syscall", - "syscall.TIOCGTSTAMP": "syscall", - "syscall.TIOCGWINSZ": "syscall", - "syscall.TIOCINQ": "syscall", - "syscall.TIOCIXOFF": "syscall", - "syscall.TIOCIXON": "syscall", - "syscall.TIOCLINUX": "syscall", - "syscall.TIOCMBIC": "syscall", - "syscall.TIOCMBIS": "syscall", - "syscall.TIOCMGDTRWAIT": "syscall", - "syscall.TIOCMGET": "syscall", - "syscall.TIOCMIWAIT": "syscall", - "syscall.TIOCMODG": "syscall", - "syscall.TIOCMODS": "syscall", - "syscall.TIOCMSDTRWAIT": "syscall", - "syscall.TIOCMSET": "syscall", - "syscall.TIOCM_CAR": "syscall", - "syscall.TIOCM_CD": "syscall", - "syscall.TIOCM_CTS": "syscall", - "syscall.TIOCM_DCD": "syscall", - "syscall.TIOCM_DSR": "syscall", - "syscall.TIOCM_DTR": "syscall", - "syscall.TIOCM_LE": "syscall", - "syscall.TIOCM_RI": "syscall", - "syscall.TIOCM_RNG": "syscall", - "syscall.TIOCM_RTS": "syscall", - "syscall.TIOCM_SR": "syscall", - "syscall.TIOCM_ST": "syscall", - "syscall.TIOCNOTTY": "syscall", - "syscall.TIOCNXCL": "syscall", - "syscall.TIOCOUTQ": "syscall", - "syscall.TIOCPKT": "syscall", - "syscall.TIOCPKT_DATA": "syscall", - "syscall.TIOCPKT_DOSTOP": "syscall", - "syscall.TIOCPKT_FLUSHREAD": "syscall", - "syscall.TIOCPKT_FLUSHWRITE": "syscall", - "syscall.TIOCPKT_IOCTL": "syscall", - "syscall.TIOCPKT_NOSTOP": "syscall", - "syscall.TIOCPKT_START": "syscall", - "syscall.TIOCPKT_STOP": "syscall", - "syscall.TIOCPTMASTER": "syscall", - "syscall.TIOCPTMGET": "syscall", - "syscall.TIOCPTSNAME": "syscall", - "syscall.TIOCPTYGNAME": "syscall", - "syscall.TIOCPTYGRANT": "syscall", - "syscall.TIOCPTYUNLK": "syscall", - "syscall.TIOCRCVFRAME": "syscall", - "syscall.TIOCREMOTE": "syscall", - "syscall.TIOCSBRK": "syscall", - "syscall.TIOCSCONS": "syscall", - "syscall.TIOCSCTTY": "syscall", - "syscall.TIOCSDRAINWAIT": "syscall", - "syscall.TIOCSDTR": "syscall", - "syscall.TIOCSERCONFIG": "syscall", - "syscall.TIOCSERGETLSR": "syscall", - "syscall.TIOCSERGETMULTI": "syscall", - "syscall.TIOCSERGSTRUCT": "syscall", - "syscall.TIOCSERGWILD": "syscall", - "syscall.TIOCSERSETMULTI": "syscall", - "syscall.TIOCSERSWILD": "syscall", - "syscall.TIOCSER_TEMT": "syscall", - "syscall.TIOCSETA": "syscall", - "syscall.TIOCSETAF": "syscall", - "syscall.TIOCSETAW": "syscall", - "syscall.TIOCSETD": "syscall", - "syscall.TIOCSFLAGS": "syscall", - "syscall.TIOCSIG": "syscall", - "syscall.TIOCSLCKTRMIOS": "syscall", - "syscall.TIOCSLINED": "syscall", - "syscall.TIOCSPGRP": "syscall", - "syscall.TIOCSPTLCK": "syscall", - "syscall.TIOCSQSIZE": "syscall", - "syscall.TIOCSRS485": "syscall", - "syscall.TIOCSSERIAL": "syscall", - "syscall.TIOCSSIZE": "syscall", - "syscall.TIOCSSOFTCAR": "syscall", - "syscall.TIOCSTART": "syscall", - "syscall.TIOCSTAT": "syscall", - "syscall.TIOCSTI": "syscall", - "syscall.TIOCSTOP": "syscall", - "syscall.TIOCSTSTAMP": "syscall", - "syscall.TIOCSWINSZ": "syscall", - "syscall.TIOCTIMESTAMP": "syscall", - "syscall.TIOCUCNTL": "syscall", - "syscall.TIOCVHANGUP": "syscall", - "syscall.TIOCXMTFRAME": "syscall", - "syscall.TOKEN_ADJUST_DEFAULT": "syscall", - "syscall.TOKEN_ADJUST_GROUPS": "syscall", - "syscall.TOKEN_ADJUST_PRIVILEGES": "syscall", - "syscall.TOKEN_ALL_ACCESS": "syscall", - "syscall.TOKEN_ASSIGN_PRIMARY": "syscall", - "syscall.TOKEN_DUPLICATE": "syscall", - "syscall.TOKEN_EXECUTE": "syscall", - "syscall.TOKEN_IMPERSONATE": "syscall", - "syscall.TOKEN_QUERY": "syscall", - "syscall.TOKEN_QUERY_SOURCE": "syscall", - "syscall.TOKEN_READ": "syscall", - "syscall.TOKEN_WRITE": "syscall", - "syscall.TOSTOP": "syscall", - "syscall.TRUNCATE_EXISTING": "syscall", - "syscall.TUNATTACHFILTER": "syscall", - "syscall.TUNDETACHFILTER": "syscall", - "syscall.TUNGETFEATURES": "syscall", - "syscall.TUNGETIFF": "syscall", - "syscall.TUNGETSNDBUF": "syscall", - "syscall.TUNGETVNETHDRSZ": "syscall", - "syscall.TUNSETDEBUG": "syscall", - "syscall.TUNSETGROUP": "syscall", - "syscall.TUNSETIFF": "syscall", - "syscall.TUNSETLINK": "syscall", - "syscall.TUNSETNOCSUM": "syscall", - "syscall.TUNSETOFFLOAD": "syscall", - "syscall.TUNSETOWNER": "syscall", - "syscall.TUNSETPERSIST": "syscall", - "syscall.TUNSETSNDBUF": "syscall", - "syscall.TUNSETTXFILTER": "syscall", - "syscall.TUNSETVNETHDRSZ": "syscall", - "syscall.Tee": "syscall", - "syscall.TerminateProcess": "syscall", - "syscall.Termios": "syscall", - "syscall.Tgkill": "syscall", - "syscall.Time": "syscall", - "syscall.Time_t": "syscall", - "syscall.Times": "syscall", - "syscall.Timespec": "syscall", - "syscall.TimespecToNsec": "syscall", - "syscall.Timeval": "syscall", - "syscall.Timeval32": "syscall", - "syscall.TimevalToNsec": "syscall", - "syscall.Timex": "syscall", - "syscall.Timezoneinformation": "syscall", - "syscall.Tms": "syscall", - "syscall.Token": "syscall", - "syscall.TokenAccessInformation": "syscall", - "syscall.TokenAuditPolicy": "syscall", - "syscall.TokenDefaultDacl": "syscall", - "syscall.TokenElevation": "syscall", - "syscall.TokenElevationType": "syscall", - "syscall.TokenGroups": "syscall", - "syscall.TokenGroupsAndPrivileges": "syscall", - "syscall.TokenHasRestrictions": "syscall", - "syscall.TokenImpersonationLevel": "syscall", - "syscall.TokenIntegrityLevel": "syscall", - "syscall.TokenLinkedToken": "syscall", - "syscall.TokenLogonSid": "syscall", - "syscall.TokenMandatoryPolicy": "syscall", - "syscall.TokenOrigin": "syscall", - "syscall.TokenOwner": "syscall", - "syscall.TokenPrimaryGroup": "syscall", - "syscall.TokenPrivileges": "syscall", - "syscall.TokenRestrictedSids": "syscall", - "syscall.TokenSandBoxInert": "syscall", - "syscall.TokenSessionId": "syscall", - "syscall.TokenSessionReference": "syscall", - "syscall.TokenSource": "syscall", - "syscall.TokenStatistics": "syscall", - "syscall.TokenType": "syscall", - "syscall.TokenUIAccess": "syscall", - "syscall.TokenUser": "syscall", - "syscall.TokenVirtualizationAllowed": "syscall", - "syscall.TokenVirtualizationEnabled": "syscall", - "syscall.Tokenprimarygroup": "syscall", - "syscall.Tokenuser": "syscall", - "syscall.TranslateAccountName": "syscall", - "syscall.TranslateName": "syscall", - "syscall.TransmitFile": "syscall", - "syscall.TransmitFileBuffers": "syscall", - "syscall.Truncate": "syscall", - "syscall.USAGE_MATCH_TYPE_AND": "syscall", - "syscall.USAGE_MATCH_TYPE_OR": "syscall", - "syscall.UTF16FromString": "syscall", - "syscall.UTF16PtrFromString": "syscall", - "syscall.UTF16ToString": "syscall", - "syscall.Ucred": "syscall", - "syscall.Umask": "syscall", - "syscall.Uname": "syscall", - "syscall.Undelete": "syscall", - "syscall.UnixCredentials": "syscall", - "syscall.UnixRights": "syscall", - "syscall.Unlink": "syscall", - "syscall.Unlinkat": "syscall", - "syscall.UnmapViewOfFile": "syscall", - "syscall.Unmount": "syscall", - "syscall.Unsetenv": "syscall", - "syscall.Unshare": "syscall", - "syscall.UserInfo10": "syscall", - "syscall.Ustat": "syscall", - "syscall.Ustat_t": "syscall", - "syscall.Utimbuf": "syscall", - "syscall.Utime": "syscall", - "syscall.Utimes": "syscall", - "syscall.UtimesNano": "syscall", - "syscall.Utsname": "syscall", - "syscall.VDISCARD": "syscall", - "syscall.VDSUSP": "syscall", - "syscall.VEOF": "syscall", - "syscall.VEOL": "syscall", - "syscall.VEOL2": "syscall", - "syscall.VERASE": "syscall", - "syscall.VERASE2": "syscall", - "syscall.VINTR": "syscall", - "syscall.VKILL": "syscall", - "syscall.VLNEXT": "syscall", - "syscall.VMIN": "syscall", - "syscall.VQUIT": "syscall", - "syscall.VREPRINT": "syscall", - "syscall.VSTART": "syscall", - "syscall.VSTATUS": "syscall", - "syscall.VSTOP": "syscall", - "syscall.VSUSP": "syscall", - "syscall.VSWTC": "syscall", - "syscall.VT0": "syscall", - "syscall.VT1": "syscall", - "syscall.VTDLY": "syscall", - "syscall.VTIME": "syscall", - "syscall.VWERASE": "syscall", - "syscall.VirtualLock": "syscall", - "syscall.VirtualUnlock": "syscall", - "syscall.WAIT_ABANDONED": "syscall", - "syscall.WAIT_FAILED": "syscall", - "syscall.WAIT_OBJECT_0": "syscall", - "syscall.WAIT_TIMEOUT": "syscall", - "syscall.WALL": "syscall", - "syscall.WALLSIG": "syscall", - "syscall.WALTSIG": "syscall", - "syscall.WCLONE": "syscall", - "syscall.WCONTINUED": "syscall", - "syscall.WCOREFLAG": "syscall", - "syscall.WEXITED": "syscall", - "syscall.WLINUXCLONE": "syscall", - "syscall.WNOHANG": "syscall", - "syscall.WNOTHREAD": "syscall", - "syscall.WNOWAIT": "syscall", - "syscall.WNOZOMBIE": "syscall", - "syscall.WOPTSCHECKED": "syscall", - "syscall.WORDSIZE": "syscall", - "syscall.WSABuf": "syscall", - "syscall.WSACleanup": "syscall", - "syscall.WSADESCRIPTION_LEN": "syscall", - "syscall.WSAData": "syscall", - "syscall.WSAEACCES": "syscall", - "syscall.WSAECONNRESET": "syscall", - "syscall.WSAEnumProtocols": "syscall", - "syscall.WSAID_CONNECTEX": "syscall", - "syscall.WSAIoctl": "syscall", - "syscall.WSAPROTOCOL_LEN": "syscall", - "syscall.WSAProtocolChain": "syscall", - "syscall.WSAProtocolInfo": "syscall", - "syscall.WSARecv": "syscall", - "syscall.WSARecvFrom": "syscall", - "syscall.WSASYS_STATUS_LEN": "syscall", - "syscall.WSASend": "syscall", - "syscall.WSASendTo": "syscall", - "syscall.WSASendto": "syscall", - "syscall.WSAStartup": "syscall", - "syscall.WSTOPPED": "syscall", - "syscall.WTRAPPED": "syscall", - "syscall.WUNTRACED": "syscall", - "syscall.Wait4": "syscall", - "syscall.WaitForSingleObject": "syscall", - "syscall.WaitStatus": "syscall", - "syscall.Win32FileAttributeData": "syscall", - "syscall.Win32finddata": "syscall", - "syscall.Write": "syscall", - "syscall.WriteConsole": "syscall", - "syscall.WriteFile": "syscall", - "syscall.X509_ASN_ENCODING": "syscall", - "syscall.XCASE": "syscall", - "syscall.XP1_CONNECTIONLESS": "syscall", - "syscall.XP1_CONNECT_DATA": "syscall", - "syscall.XP1_DISCONNECT_DATA": "syscall", - "syscall.XP1_EXPEDITED_DATA": "syscall", - "syscall.XP1_GRACEFUL_CLOSE": "syscall", - "syscall.XP1_GUARANTEED_DELIVERY": "syscall", - "syscall.XP1_GUARANTEED_ORDER": "syscall", - "syscall.XP1_IFS_HANDLES": "syscall", - "syscall.XP1_MESSAGE_ORIENTED": "syscall", - "syscall.XP1_MULTIPOINT_CONTROL_PLANE": "syscall", - "syscall.XP1_MULTIPOINT_DATA_PLANE": "syscall", - "syscall.XP1_PARTIAL_MESSAGE": "syscall", - "syscall.XP1_PSEUDO_STREAM": "syscall", - "syscall.XP1_QOS_SUPPORTED": "syscall", - "syscall.XP1_SAN_SUPPORT_SDP": "syscall", - "syscall.XP1_SUPPORT_BROADCAST": "syscall", - "syscall.XP1_SUPPORT_MULTIPOINT": "syscall", - "syscall.XP1_UNI_RECV": "syscall", - "syscall.XP1_UNI_SEND": "syscall", - "syslog.Dial": "log/syslog", - "syslog.LOG_ALERT": "log/syslog", - "syslog.LOG_AUTH": "log/syslog", - "syslog.LOG_AUTHPRIV": "log/syslog", - "syslog.LOG_CRIT": "log/syslog", - "syslog.LOG_CRON": "log/syslog", - "syslog.LOG_DAEMON": "log/syslog", - "syslog.LOG_DEBUG": "log/syslog", - "syslog.LOG_EMERG": "log/syslog", - "syslog.LOG_ERR": "log/syslog", - "syslog.LOG_FTP": "log/syslog", - "syslog.LOG_INFO": "log/syslog", - "syslog.LOG_KERN": "log/syslog", - "syslog.LOG_LOCAL0": "log/syslog", - "syslog.LOG_LOCAL1": "log/syslog", - "syslog.LOG_LOCAL2": "log/syslog", - "syslog.LOG_LOCAL3": "log/syslog", - "syslog.LOG_LOCAL4": "log/syslog", - "syslog.LOG_LOCAL5": "log/syslog", - "syslog.LOG_LOCAL6": "log/syslog", - "syslog.LOG_LOCAL7": "log/syslog", - "syslog.LOG_LPR": "log/syslog", - "syslog.LOG_MAIL": "log/syslog", - "syslog.LOG_NEWS": "log/syslog", - "syslog.LOG_NOTICE": "log/syslog", - "syslog.LOG_SYSLOG": "log/syslog", - "syslog.LOG_USER": "log/syslog", - "syslog.LOG_UUCP": "log/syslog", - "syslog.LOG_WARNING": "log/syslog", - "syslog.New": "log/syslog", - "syslog.NewLogger": "log/syslog", - "syslog.Priority": "log/syslog", - "syslog.Writer": "log/syslog", - "tabwriter.AlignRight": "text/tabwriter", - "tabwriter.Debug": "text/tabwriter", - "tabwriter.DiscardEmptyColumns": "text/tabwriter", - "tabwriter.Escape": "text/tabwriter", - "tabwriter.FilterHTML": "text/tabwriter", - "tabwriter.NewWriter": "text/tabwriter", - "tabwriter.StripEscape": "text/tabwriter", - "tabwriter.TabIndent": "text/tabwriter", - "tabwriter.Writer": "text/tabwriter", - "tar.ErrFieldTooLong": "archive/tar", - "tar.ErrHeader": "archive/tar", - "tar.ErrWriteAfterClose": "archive/tar", - "tar.ErrWriteTooLong": "archive/tar", - "tar.FileInfoHeader": "archive/tar", - "tar.Header": "archive/tar", - "tar.NewReader": "archive/tar", - "tar.NewWriter": "archive/tar", - "tar.Reader": "archive/tar", - "tar.TypeBlock": "archive/tar", - "tar.TypeChar": "archive/tar", - "tar.TypeCont": "archive/tar", - "tar.TypeDir": "archive/tar", - "tar.TypeFifo": "archive/tar", - "tar.TypeGNULongLink": "archive/tar", - "tar.TypeGNULongName": "archive/tar", - "tar.TypeGNUSparse": "archive/tar", - "tar.TypeLink": "archive/tar", - "tar.TypeReg": "archive/tar", - "tar.TypeRegA": "archive/tar", - "tar.TypeSymlink": "archive/tar", - "tar.TypeXGlobalHeader": "archive/tar", - "tar.TypeXHeader": "archive/tar", - "tar.Writer": "archive/tar", - "template.CSS": "html/template", - "template.ErrAmbigContext": "html/template", - "template.ErrBadHTML": "html/template", - "template.ErrBranchEnd": "html/template", - "template.ErrEndContext": "html/template", - "template.ErrNoSuchTemplate": "html/template", - "template.ErrOutputContext": "html/template", - "template.ErrPartialCharset": "html/template", - "template.ErrPartialEscape": "html/template", - "template.ErrRangeLoopReentry": "html/template", - "template.ErrSlashAmbig": "html/template", - "template.Error": "html/template", - "template.ErrorCode": "html/template", - "template.ExecError": "text/template", - // "template.FuncMap" is ambiguous - "template.HTML": "html/template", - "template.HTMLAttr": "html/template", - // "template.HTMLEscape" is ambiguous - // "template.HTMLEscapeString" is ambiguous - // "template.HTMLEscaper" is ambiguous - // "template.IsTrue" is ambiguous - "template.JS": "html/template", - // "template.JSEscape" is ambiguous - // "template.JSEscapeString" is ambiguous - // "template.JSEscaper" is ambiguous - "template.JSStr": "html/template", - // "template.Must" is ambiguous - // "template.New" is ambiguous - "template.OK": "html/template", - // "template.ParseFiles" is ambiguous - // "template.ParseGlob" is ambiguous - // "template.Template" is ambiguous - "template.URL": "html/template", - // "template.URLQueryEscaper" is ambiguous - "testing.AllocsPerRun": "testing", - "testing.B": "testing", - "testing.Benchmark": "testing", - "testing.BenchmarkResult": "testing", - "testing.Cover": "testing", - "testing.CoverBlock": "testing", - "testing.Coverage": "testing", - "testing.InternalBenchmark": "testing", - "testing.InternalExample": "testing", - "testing.InternalTest": "testing", - "testing.M": "testing", - "testing.Main": "testing", - "testing.MainStart": "testing", - "testing.PB": "testing", - "testing.RegisterCover": "testing", - "testing.RunBenchmarks": "testing", - "testing.RunExamples": "testing", - "testing.RunTests": "testing", - "testing.Short": "testing", - "testing.T": "testing", - "testing.Verbose": "testing", - "textproto.CanonicalMIMEHeaderKey": "net/textproto", - "textproto.Conn": "net/textproto", - "textproto.Dial": "net/textproto", - "textproto.Error": "net/textproto", - "textproto.MIMEHeader": "net/textproto", - "textproto.NewConn": "net/textproto", - "textproto.NewReader": "net/textproto", - "textproto.NewWriter": "net/textproto", - "textproto.Pipeline": "net/textproto", - "textproto.ProtocolError": "net/textproto", - "textproto.Reader": "net/textproto", - "textproto.TrimBytes": "net/textproto", - "textproto.TrimString": "net/textproto", - "textproto.Writer": "net/textproto", - "time.ANSIC": "time", - "time.After": "time", - "time.AfterFunc": "time", - "time.April": "time", - "time.August": "time", - "time.Date": "time", - "time.December": "time", - "time.Duration": "time", - "time.February": "time", - "time.FixedZone": "time", - "time.Friday": "time", - "time.Hour": "time", - "time.January": "time", - "time.July": "time", - "time.June": "time", - "time.Kitchen": "time", - "time.LoadLocation": "time", - "time.Local": "time", - "time.Location": "time", - "time.March": "time", - "time.May": "time", - "time.Microsecond": "time", - "time.Millisecond": "time", - "time.Minute": "time", - "time.Monday": "time", - "time.Month": "time", - "time.Nanosecond": "time", - "time.NewTicker": "time", - "time.NewTimer": "time", - "time.November": "time", - "time.Now": "time", - "time.October": "time", - "time.Parse": "time", - "time.ParseDuration": "time", - "time.ParseError": "time", - "time.ParseInLocation": "time", - "time.RFC1123": "time", - "time.RFC1123Z": "time", - "time.RFC3339": "time", - "time.RFC3339Nano": "time", - "time.RFC822": "time", - "time.RFC822Z": "time", - "time.RFC850": "time", - "time.RubyDate": "time", - "time.Saturday": "time", - "time.Second": "time", - "time.September": "time", - "time.Since": "time", - "time.Sleep": "time", - "time.Stamp": "time", - "time.StampMicro": "time", - "time.StampMilli": "time", - "time.StampNano": "time", - "time.Sunday": "time", - "time.Thursday": "time", - "time.Tick": "time", - "time.Ticker": "time", - "time.Time": "time", - "time.Timer": "time", - "time.Tuesday": "time", - "time.UTC": "time", - "time.Unix": "time", - "time.UnixDate": "time", - "time.Wednesday": "time", - "time.Weekday": "time", - "tls.Certificate": "crypto/tls", - "tls.Client": "crypto/tls", - "tls.ClientAuthType": "crypto/tls", - "tls.ClientHelloInfo": "crypto/tls", - "tls.ClientSessionCache": "crypto/tls", - "tls.ClientSessionState": "crypto/tls", - "tls.Config": "crypto/tls", - "tls.Conn": "crypto/tls", - "tls.ConnectionState": "crypto/tls", - "tls.CurveID": "crypto/tls", - "tls.CurveP256": "crypto/tls", - "tls.CurveP384": "crypto/tls", - "tls.CurveP521": "crypto/tls", - "tls.Dial": "crypto/tls", - "tls.DialWithDialer": "crypto/tls", - "tls.Listen": "crypto/tls", - "tls.LoadX509KeyPair": "crypto/tls", - "tls.NewLRUClientSessionCache": "crypto/tls", - "tls.NewListener": "crypto/tls", - "tls.NoClientCert": "crypto/tls", - "tls.RecordHeaderError": "crypto/tls", - "tls.RenegotiateFreelyAsClient": "crypto/tls", - "tls.RenegotiateNever": "crypto/tls", - "tls.RenegotiateOnceAsClient": "crypto/tls", - "tls.RenegotiationSupport": "crypto/tls", - "tls.RequestClientCert": "crypto/tls", - "tls.RequireAndVerifyClientCert": "crypto/tls", - "tls.RequireAnyClientCert": "crypto/tls", - "tls.Server": "crypto/tls", - "tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA": "crypto/tls", - "tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": "crypto/tls", - "tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA": "crypto/tls", - "tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": "crypto/tls", - "tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA": "crypto/tls", - "tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA": "crypto/tls", - "tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA": "crypto/tls", - "tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256": "crypto/tls", - "tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA": "crypto/tls", - "tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384": "crypto/tls", - "tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA": "crypto/tls", - "tls.TLS_FALLBACK_SCSV": "crypto/tls", - "tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA": "crypto/tls", - "tls.TLS_RSA_WITH_AES_128_CBC_SHA": "crypto/tls", - "tls.TLS_RSA_WITH_AES_128_GCM_SHA256": "crypto/tls", - "tls.TLS_RSA_WITH_AES_256_CBC_SHA": "crypto/tls", - "tls.TLS_RSA_WITH_AES_256_GCM_SHA384": "crypto/tls", - "tls.TLS_RSA_WITH_RC4_128_SHA": "crypto/tls", - "tls.VerifyClientCertIfGiven": "crypto/tls", - "tls.VersionSSL30": "crypto/tls", - "tls.VersionTLS10": "crypto/tls", - "tls.VersionTLS11": "crypto/tls", - "tls.VersionTLS12": "crypto/tls", - "tls.X509KeyPair": "crypto/tls", - "token.ADD": "go/token", - "token.ADD_ASSIGN": "go/token", - "token.AND": "go/token", - "token.AND_ASSIGN": "go/token", - "token.AND_NOT": "go/token", - "token.AND_NOT_ASSIGN": "go/token", - "token.ARROW": "go/token", - "token.ASSIGN": "go/token", - "token.BREAK": "go/token", - "token.CASE": "go/token", - "token.CHAN": "go/token", - "token.CHAR": "go/token", - "token.COLON": "go/token", - "token.COMMA": "go/token", - "token.COMMENT": "go/token", - "token.CONST": "go/token", - "token.CONTINUE": "go/token", - "token.DEC": "go/token", - "token.DEFAULT": "go/token", - "token.DEFER": "go/token", - "token.DEFINE": "go/token", - "token.ELLIPSIS": "go/token", - "token.ELSE": "go/token", - "token.EOF": "go/token", - "token.EQL": "go/token", - "token.FALLTHROUGH": "go/token", - "token.FLOAT": "go/token", - "token.FOR": "go/token", - "token.FUNC": "go/token", - "token.File": "go/token", - "token.FileSet": "go/token", - "token.GEQ": "go/token", - "token.GO": "go/token", - "token.GOTO": "go/token", - "token.GTR": "go/token", - "token.HighestPrec": "go/token", - "token.IDENT": "go/token", - "token.IF": "go/token", - "token.ILLEGAL": "go/token", - "token.IMAG": "go/token", - "token.IMPORT": "go/token", - "token.INC": "go/token", - "token.INT": "go/token", - "token.INTERFACE": "go/token", - "token.LAND": "go/token", - "token.LBRACE": "go/token", - "token.LBRACK": "go/token", - "token.LEQ": "go/token", - "token.LOR": "go/token", - "token.LPAREN": "go/token", - "token.LSS": "go/token", - "token.Lookup": "go/token", - "token.LowestPrec": "go/token", - "token.MAP": "go/token", - "token.MUL": "go/token", - "token.MUL_ASSIGN": "go/token", - "token.NEQ": "go/token", - "token.NOT": "go/token", - "token.NewFileSet": "go/token", - "token.NoPos": "go/token", - "token.OR": "go/token", - "token.OR_ASSIGN": "go/token", - "token.PACKAGE": "go/token", - "token.PERIOD": "go/token", - "token.Pos": "go/token", - "token.Position": "go/token", - "token.QUO": "go/token", - "token.QUO_ASSIGN": "go/token", - "token.RANGE": "go/token", - "token.RBRACE": "go/token", - "token.RBRACK": "go/token", - "token.REM": "go/token", - "token.REM_ASSIGN": "go/token", - "token.RETURN": "go/token", - "token.RPAREN": "go/token", - "token.SELECT": "go/token", - "token.SEMICOLON": "go/token", - "token.SHL": "go/token", - "token.SHL_ASSIGN": "go/token", - "token.SHR": "go/token", - "token.SHR_ASSIGN": "go/token", - "token.STRING": "go/token", - "token.STRUCT": "go/token", - "token.SUB": "go/token", - "token.SUB_ASSIGN": "go/token", - "token.SWITCH": "go/token", - "token.TYPE": "go/token", - "token.Token": "go/token", - "token.UnaryPrec": "go/token", - "token.VAR": "go/token", - "token.XOR": "go/token", - "token.XOR_ASSIGN": "go/token", - "trace.Start": "runtime/trace", - "trace.Stop": "runtime/trace", - "types.Array": "go/types", - "types.AssertableTo": "go/types", - "types.AssignableTo": "go/types", - "types.Basic": "go/types", - "types.BasicInfo": "go/types", - "types.BasicKind": "go/types", - "types.Bool": "go/types", - "types.Builtin": "go/types", - "types.Byte": "go/types", - "types.Chan": "go/types", - "types.ChanDir": "go/types", - "types.Checker": "go/types", - "types.Comparable": "go/types", - "types.Complex128": "go/types", - "types.Complex64": "go/types", - "types.Config": "go/types", - "types.Const": "go/types", - "types.ConvertibleTo": "go/types", - "types.DefPredeclaredTestFuncs": "go/types", - "types.Error": "go/types", - "types.Eval": "go/types", - "types.ExprString": "go/types", - "types.FieldVal": "go/types", - "types.Float32": "go/types", - "types.Float64": "go/types", - "types.Func": "go/types", - "types.Id": "go/types", - "types.Identical": "go/types", - "types.Implements": "go/types", - "types.ImportMode": "go/types", - "types.Importer": "go/types", - "types.ImporterFrom": "go/types", - "types.Info": "go/types", - "types.Initializer": "go/types", - "types.Int": "go/types", - "types.Int16": "go/types", - "types.Int32": "go/types", - "types.Int64": "go/types", - "types.Int8": "go/types", - "types.Interface": "go/types", - "types.Invalid": "go/types", - "types.IsBoolean": "go/types", - "types.IsComplex": "go/types", - "types.IsConstType": "go/types", - "types.IsFloat": "go/types", - "types.IsInteger": "go/types", - "types.IsInterface": "go/types", - "types.IsNumeric": "go/types", - "types.IsOrdered": "go/types", - "types.IsString": "go/types", - "types.IsUnsigned": "go/types", - "types.IsUntyped": "go/types", - "types.Label": "go/types", - "types.LookupFieldOrMethod": "go/types", - "types.Map": "go/types", - "types.MethodExpr": "go/types", - "types.MethodSet": "go/types", - "types.MethodVal": "go/types", - "types.MissingMethod": "go/types", - "types.Named": "go/types", - "types.NewArray": "go/types", - "types.NewChan": "go/types", - "types.NewChecker": "go/types", - "types.NewConst": "go/types", - "types.NewField": "go/types", - "types.NewFunc": "go/types", - "types.NewInterface": "go/types", - "types.NewLabel": "go/types", - "types.NewMap": "go/types", - "types.NewMethodSet": "go/types", - "types.NewNamed": "go/types", - "types.NewPackage": "go/types", - "types.NewParam": "go/types", - "types.NewPkgName": "go/types", - "types.NewPointer": "go/types", - "types.NewScope": "go/types", - "types.NewSignature": "go/types", - "types.NewSlice": "go/types", - "types.NewStruct": "go/types", - "types.NewTuple": "go/types", - "types.NewTypeName": "go/types", - "types.NewVar": "go/types", - "types.Nil": "go/types", - "types.ObjectString": "go/types", - "types.Package": "go/types", - "types.PkgName": "go/types", - "types.Pointer": "go/types", - "types.Qualifier": "go/types", - "types.RecvOnly": "go/types", - "types.RelativeTo": "go/types", - "types.Rune": "go/types", - "types.Scope": "go/types", - "types.Selection": "go/types", - "types.SelectionKind": "go/types", - "types.SelectionString": "go/types", - "types.SendOnly": "go/types", - "types.SendRecv": "go/types", - "types.Signature": "go/types", - "types.Sizes": "go/types", - "types.Slice": "go/types", - "types.StdSizes": "go/types", - "types.String": "go/types", - "types.Struct": "go/types", - "types.Tuple": "go/types", - "types.Typ": "go/types", - "types.Type": "go/types", - "types.TypeAndValue": "go/types", - "types.TypeName": "go/types", - "types.TypeString": "go/types", - "types.Uint": "go/types", - "types.Uint16": "go/types", - "types.Uint32": "go/types", - "types.Uint64": "go/types", - "types.Uint8": "go/types", - "types.Uintptr": "go/types", - "types.Universe": "go/types", - "types.Unsafe": "go/types", - "types.UnsafePointer": "go/types", - "types.UntypedBool": "go/types", - "types.UntypedComplex": "go/types", - "types.UntypedFloat": "go/types", - "types.UntypedInt": "go/types", - "types.UntypedNil": "go/types", - "types.UntypedRune": "go/types", - "types.UntypedString": "go/types", - "types.Var": "go/types", - "types.WriteExpr": "go/types", - "types.WriteSignature": "go/types", - "types.WriteType": "go/types", - "unicode.ASCII_Hex_Digit": "unicode", - "unicode.Adlam": "unicode", - "unicode.Ahom": "unicode", - "unicode.Anatolian_Hieroglyphs": "unicode", - "unicode.Arabic": "unicode", - "unicode.Armenian": "unicode", - "unicode.Avestan": "unicode", - "unicode.AzeriCase": "unicode", - "unicode.Balinese": "unicode", - "unicode.Bamum": "unicode", - "unicode.Bassa_Vah": "unicode", - "unicode.Batak": "unicode", - "unicode.Bengali": "unicode", - "unicode.Bhaiksuki": "unicode", - "unicode.Bidi_Control": "unicode", - "unicode.Bopomofo": "unicode", - "unicode.Brahmi": "unicode", - "unicode.Braille": "unicode", - "unicode.Buginese": "unicode", - "unicode.Buhid": "unicode", - "unicode.C": "unicode", - "unicode.Canadian_Aboriginal": "unicode", - "unicode.Carian": "unicode", - "unicode.CaseRange": "unicode", - "unicode.CaseRanges": "unicode", - "unicode.Categories": "unicode", - "unicode.Caucasian_Albanian": "unicode", - "unicode.Cc": "unicode", - "unicode.Cf": "unicode", - "unicode.Chakma": "unicode", - "unicode.Cham": "unicode", - "unicode.Cherokee": "unicode", - "unicode.Co": "unicode", - "unicode.Common": "unicode", - "unicode.Coptic": "unicode", - "unicode.Cs": "unicode", - "unicode.Cuneiform": "unicode", - "unicode.Cypriot": "unicode", - "unicode.Cyrillic": "unicode", - "unicode.Dash": "unicode", - "unicode.Deprecated": "unicode", - "unicode.Deseret": "unicode", - "unicode.Devanagari": "unicode", - "unicode.Diacritic": "unicode", - "unicode.Digit": "unicode", - "unicode.Duployan": "unicode", - "unicode.Egyptian_Hieroglyphs": "unicode", - "unicode.Elbasan": "unicode", - "unicode.Ethiopic": "unicode", - "unicode.Extender": "unicode", - "unicode.FoldCategory": "unicode", - "unicode.FoldScript": "unicode", - "unicode.Georgian": "unicode", - "unicode.Glagolitic": "unicode", - "unicode.Gothic": "unicode", - "unicode.Grantha": "unicode", - "unicode.GraphicRanges": "unicode", - "unicode.Greek": "unicode", - "unicode.Gujarati": "unicode", - "unicode.Gurmukhi": "unicode", - "unicode.Han": "unicode", - "unicode.Hangul": "unicode", - "unicode.Hanunoo": "unicode", - "unicode.Hatran": "unicode", - "unicode.Hebrew": "unicode", - "unicode.Hex_Digit": "unicode", - "unicode.Hiragana": "unicode", - "unicode.Hyphen": "unicode", - "unicode.IDS_Binary_Operator": "unicode", - "unicode.IDS_Trinary_Operator": "unicode", - "unicode.Ideographic": "unicode", - "unicode.Imperial_Aramaic": "unicode", - "unicode.In": "unicode", - "unicode.Inherited": "unicode", - "unicode.Inscriptional_Pahlavi": "unicode", - "unicode.Inscriptional_Parthian": "unicode", - "unicode.Is": "unicode", - "unicode.IsControl": "unicode", - "unicode.IsDigit": "unicode", - "unicode.IsGraphic": "unicode", - "unicode.IsLetter": "unicode", - "unicode.IsLower": "unicode", - "unicode.IsMark": "unicode", - "unicode.IsNumber": "unicode", - "unicode.IsOneOf": "unicode", - "unicode.IsPrint": "unicode", - "unicode.IsPunct": "unicode", - "unicode.IsSpace": "unicode", - "unicode.IsSymbol": "unicode", - "unicode.IsTitle": "unicode", - "unicode.IsUpper": "unicode", - "unicode.Javanese": "unicode", - "unicode.Join_Control": "unicode", - "unicode.Kaithi": "unicode", - "unicode.Kannada": "unicode", - "unicode.Katakana": "unicode", - "unicode.Kayah_Li": "unicode", - "unicode.Kharoshthi": "unicode", - "unicode.Khmer": "unicode", - "unicode.Khojki": "unicode", - "unicode.Khudawadi": "unicode", - "unicode.L": "unicode", - "unicode.Lao": "unicode", - "unicode.Latin": "unicode", - "unicode.Lepcha": "unicode", - "unicode.Letter": "unicode", - "unicode.Limbu": "unicode", - "unicode.Linear_A": "unicode", - "unicode.Linear_B": "unicode", - "unicode.Lisu": "unicode", - "unicode.Ll": "unicode", - "unicode.Lm": "unicode", - "unicode.Lo": "unicode", - "unicode.Logical_Order_Exception": "unicode", - "unicode.Lower": "unicode", - "unicode.LowerCase": "unicode", - "unicode.Lt": "unicode", - "unicode.Lu": "unicode", - "unicode.Lycian": "unicode", - "unicode.Lydian": "unicode", - "unicode.M": "unicode", - "unicode.Mahajani": "unicode", - "unicode.Malayalam": "unicode", - "unicode.Mandaic": "unicode", - "unicode.Manichaean": "unicode", - "unicode.Marchen": "unicode", - "unicode.Mark": "unicode", - "unicode.MaxASCII": "unicode", - "unicode.MaxCase": "unicode", - "unicode.MaxLatin1": "unicode", - "unicode.MaxRune": "unicode", - "unicode.Mc": "unicode", - "unicode.Me": "unicode", - "unicode.Meetei_Mayek": "unicode", - "unicode.Mende_Kikakui": "unicode", - "unicode.Meroitic_Cursive": "unicode", - "unicode.Meroitic_Hieroglyphs": "unicode", - "unicode.Miao": "unicode", - "unicode.Mn": "unicode", - "unicode.Modi": "unicode", - "unicode.Mongolian": "unicode", - "unicode.Mro": "unicode", - "unicode.Multani": "unicode", - "unicode.Myanmar": "unicode", - "unicode.N": "unicode", - "unicode.Nabataean": "unicode", - "unicode.Nd": "unicode", - "unicode.New_Tai_Lue": "unicode", - "unicode.Newa": "unicode", - "unicode.Nko": "unicode", - "unicode.Nl": "unicode", - "unicode.No": "unicode", - "unicode.Noncharacter_Code_Point": "unicode", - "unicode.Number": "unicode", - "unicode.Ogham": "unicode", - "unicode.Ol_Chiki": "unicode", - "unicode.Old_Hungarian": "unicode", - "unicode.Old_Italic": "unicode", - "unicode.Old_North_Arabian": "unicode", - "unicode.Old_Permic": "unicode", - "unicode.Old_Persian": "unicode", - "unicode.Old_South_Arabian": "unicode", - "unicode.Old_Turkic": "unicode", - "unicode.Oriya": "unicode", - "unicode.Osage": "unicode", - "unicode.Osmanya": "unicode", - "unicode.Other": "unicode", - "unicode.Other_Alphabetic": "unicode", - "unicode.Other_Default_Ignorable_Code_Point": "unicode", - "unicode.Other_Grapheme_Extend": "unicode", - "unicode.Other_ID_Continue": "unicode", - "unicode.Other_ID_Start": "unicode", - "unicode.Other_Lowercase": "unicode", - "unicode.Other_Math": "unicode", - "unicode.Other_Uppercase": "unicode", - "unicode.P": "unicode", - "unicode.Pahawh_Hmong": "unicode", - "unicode.Palmyrene": "unicode", - "unicode.Pattern_Syntax": "unicode", - "unicode.Pattern_White_Space": "unicode", - "unicode.Pau_Cin_Hau": "unicode", - "unicode.Pc": "unicode", - "unicode.Pd": "unicode", - "unicode.Pe": "unicode", - "unicode.Pf": "unicode", - "unicode.Phags_Pa": "unicode", - "unicode.Phoenician": "unicode", - "unicode.Pi": "unicode", - "unicode.Po": "unicode", - "unicode.Prepended_Concatenation_Mark": "unicode", - "unicode.PrintRanges": "unicode", - "unicode.Properties": "unicode", - "unicode.Ps": "unicode", - "unicode.Psalter_Pahlavi": "unicode", - "unicode.Punct": "unicode", - "unicode.Quotation_Mark": "unicode", - "unicode.Radical": "unicode", - "unicode.Range16": "unicode", - "unicode.Range32": "unicode", - "unicode.RangeTable": "unicode", - "unicode.Rejang": "unicode", - "unicode.ReplacementChar": "unicode", - "unicode.Runic": "unicode", - "unicode.S": "unicode", - "unicode.STerm": "unicode", - "unicode.Samaritan": "unicode", - "unicode.Saurashtra": "unicode", - "unicode.Sc": "unicode", - "unicode.Scripts": "unicode", - "unicode.Sentence_Terminal": "unicode", - "unicode.Sharada": "unicode", - "unicode.Shavian": "unicode", - "unicode.Siddham": "unicode", - "unicode.SignWriting": "unicode", - "unicode.SimpleFold": "unicode", - "unicode.Sinhala": "unicode", - "unicode.Sk": "unicode", - "unicode.Sm": "unicode", - "unicode.So": "unicode", - "unicode.Soft_Dotted": "unicode", - "unicode.Sora_Sompeng": "unicode", - "unicode.Space": "unicode", - "unicode.SpecialCase": "unicode", - "unicode.Sundanese": "unicode", - "unicode.Syloti_Nagri": "unicode", - "unicode.Symbol": "unicode", - "unicode.Syriac": "unicode", - "unicode.Tagalog": "unicode", - "unicode.Tagbanwa": "unicode", - "unicode.Tai_Le": "unicode", - "unicode.Tai_Tham": "unicode", - "unicode.Tai_Viet": "unicode", - "unicode.Takri": "unicode", - "unicode.Tamil": "unicode", - "unicode.Tangut": "unicode", - "unicode.Telugu": "unicode", - "unicode.Terminal_Punctuation": "unicode", - "unicode.Thaana": "unicode", - "unicode.Thai": "unicode", - "unicode.Tibetan": "unicode", - "unicode.Tifinagh": "unicode", - "unicode.Tirhuta": "unicode", - "unicode.Title": "unicode", - "unicode.TitleCase": "unicode", - "unicode.To": "unicode", - "unicode.ToLower": "unicode", - "unicode.ToTitle": "unicode", - "unicode.ToUpper": "unicode", - "unicode.TurkishCase": "unicode", - "unicode.Ugaritic": "unicode", - "unicode.Unified_Ideograph": "unicode", - "unicode.Upper": "unicode", - "unicode.UpperCase": "unicode", - "unicode.UpperLower": "unicode", - "unicode.Vai": "unicode", - "unicode.Variation_Selector": "unicode", - "unicode.Version": "unicode", - "unicode.Warang_Citi": "unicode", - "unicode.White_Space": "unicode", - "unicode.Yi": "unicode", - "unicode.Z": "unicode", - "unicode.Zl": "unicode", - "unicode.Zp": "unicode", - "unicode.Zs": "unicode", - "url.Error": "net/url", - "url.EscapeError": "net/url", - "url.InvalidHostError": "net/url", - "url.Parse": "net/url", - "url.ParseQuery": "net/url", - "url.ParseRequestURI": "net/url", - "url.QueryEscape": "net/url", - "url.QueryUnescape": "net/url", - "url.URL": "net/url", - "url.User": "net/url", - "url.UserPassword": "net/url", - "url.Userinfo": "net/url", - "url.Values": "net/url", - "user.Current": "os/user", - "user.Group": "os/user", - "user.Lookup": "os/user", - "user.LookupGroup": "os/user", - "user.LookupGroupId": "os/user", - "user.LookupId": "os/user", - "user.UnknownGroupError": "os/user", - "user.UnknownGroupIdError": "os/user", - "user.UnknownUserError": "os/user", - "user.UnknownUserIdError": "os/user", - "user.User": "os/user", - "utf16.Decode": "unicode/utf16", - "utf16.DecodeRune": "unicode/utf16", - "utf16.Encode": "unicode/utf16", - "utf16.EncodeRune": "unicode/utf16", - "utf16.IsSurrogate": "unicode/utf16", - "utf8.DecodeLastRune": "unicode/utf8", - "utf8.DecodeLastRuneInString": "unicode/utf8", - "utf8.DecodeRune": "unicode/utf8", - "utf8.DecodeRuneInString": "unicode/utf8", - "utf8.EncodeRune": "unicode/utf8", - "utf8.FullRune": "unicode/utf8", - "utf8.FullRuneInString": "unicode/utf8", - "utf8.MaxRune": "unicode/utf8", - "utf8.RuneCount": "unicode/utf8", - "utf8.RuneCountInString": "unicode/utf8", - "utf8.RuneError": "unicode/utf8", - "utf8.RuneLen": "unicode/utf8", - "utf8.RuneSelf": "unicode/utf8", - "utf8.RuneStart": "unicode/utf8", - "utf8.UTFMax": "unicode/utf8", - "utf8.Valid": "unicode/utf8", - "utf8.ValidRune": "unicode/utf8", - "utf8.ValidString": "unicode/utf8", - "x509.CANotAuthorizedForThisName": "crypto/x509", - "x509.CertPool": "crypto/x509", - "x509.Certificate": "crypto/x509", - "x509.CertificateInvalidError": "crypto/x509", - "x509.CertificateRequest": "crypto/x509", - "x509.ConstraintViolationError": "crypto/x509", - "x509.CreateCertificate": "crypto/x509", - "x509.CreateCertificateRequest": "crypto/x509", - "x509.DSA": "crypto/x509", - "x509.DSAWithSHA1": "crypto/x509", - "x509.DSAWithSHA256": "crypto/x509", - "x509.DecryptPEMBlock": "crypto/x509", - "x509.ECDSA": "crypto/x509", - "x509.ECDSAWithSHA1": "crypto/x509", - "x509.ECDSAWithSHA256": "crypto/x509", - "x509.ECDSAWithSHA384": "crypto/x509", - "x509.ECDSAWithSHA512": "crypto/x509", - "x509.EncryptPEMBlock": "crypto/x509", - "x509.ErrUnsupportedAlgorithm": "crypto/x509", - "x509.Expired": "crypto/x509", - "x509.ExtKeyUsage": "crypto/x509", - "x509.ExtKeyUsageAny": "crypto/x509", - "x509.ExtKeyUsageClientAuth": "crypto/x509", - "x509.ExtKeyUsageCodeSigning": "crypto/x509", - "x509.ExtKeyUsageEmailProtection": "crypto/x509", - "x509.ExtKeyUsageIPSECEndSystem": "crypto/x509", - "x509.ExtKeyUsageIPSECTunnel": "crypto/x509", - "x509.ExtKeyUsageIPSECUser": "crypto/x509", - "x509.ExtKeyUsageMicrosoftServerGatedCrypto": "crypto/x509", - "x509.ExtKeyUsageNetscapeServerGatedCrypto": "crypto/x509", - "x509.ExtKeyUsageOCSPSigning": "crypto/x509", - "x509.ExtKeyUsageServerAuth": "crypto/x509", - "x509.ExtKeyUsageTimeStamping": "crypto/x509", - "x509.HostnameError": "crypto/x509", - "x509.IncompatibleUsage": "crypto/x509", - "x509.IncorrectPasswordError": "crypto/x509", - "x509.InsecureAlgorithmError": "crypto/x509", - "x509.InvalidReason": "crypto/x509", - "x509.IsEncryptedPEMBlock": "crypto/x509", - "x509.KeyUsage": "crypto/x509", - "x509.KeyUsageCRLSign": "crypto/x509", - "x509.KeyUsageCertSign": "crypto/x509", - "x509.KeyUsageContentCommitment": "crypto/x509", - "x509.KeyUsageDataEncipherment": "crypto/x509", - "x509.KeyUsageDecipherOnly": "crypto/x509", - "x509.KeyUsageDigitalSignature": "crypto/x509", - "x509.KeyUsageEncipherOnly": "crypto/x509", - "x509.KeyUsageKeyAgreement": "crypto/x509", - "x509.KeyUsageKeyEncipherment": "crypto/x509", - "x509.MD2WithRSA": "crypto/x509", - "x509.MD5WithRSA": "crypto/x509", - "x509.MarshalECPrivateKey": "crypto/x509", - "x509.MarshalPKCS1PrivateKey": "crypto/x509", - "x509.MarshalPKIXPublicKey": "crypto/x509", - "x509.NewCertPool": "crypto/x509", - "x509.NotAuthorizedToSign": "crypto/x509", - "x509.PEMCipher": "crypto/x509", - "x509.PEMCipher3DES": "crypto/x509", - "x509.PEMCipherAES128": "crypto/x509", - "x509.PEMCipherAES192": "crypto/x509", - "x509.PEMCipherAES256": "crypto/x509", - "x509.PEMCipherDES": "crypto/x509", - "x509.ParseCRL": "crypto/x509", - "x509.ParseCertificate": "crypto/x509", - "x509.ParseCertificateRequest": "crypto/x509", - "x509.ParseCertificates": "crypto/x509", - "x509.ParseDERCRL": "crypto/x509", - "x509.ParseECPrivateKey": "crypto/x509", - "x509.ParsePKCS1PrivateKey": "crypto/x509", - "x509.ParsePKCS8PrivateKey": "crypto/x509", - "x509.ParsePKIXPublicKey": "crypto/x509", - "x509.PublicKeyAlgorithm": "crypto/x509", - "x509.RSA": "crypto/x509", - "x509.SHA1WithRSA": "crypto/x509", - "x509.SHA256WithRSA": "crypto/x509", - "x509.SHA384WithRSA": "crypto/x509", - "x509.SHA512WithRSA": "crypto/x509", - "x509.SignatureAlgorithm": "crypto/x509", - "x509.SystemCertPool": "crypto/x509", - "x509.SystemRootsError": "crypto/x509", - "x509.TooManyIntermediates": "crypto/x509", - "x509.UnhandledCriticalExtension": "crypto/x509", - "x509.UnknownAuthorityError": "crypto/x509", - "x509.UnknownPublicKeyAlgorithm": "crypto/x509", - "x509.UnknownSignatureAlgorithm": "crypto/x509", - "x509.VerifyOptions": "crypto/x509", - "xml.Attr": "encoding/xml", - "xml.CharData": "encoding/xml", - "xml.Comment": "encoding/xml", - "xml.CopyToken": "encoding/xml", - "xml.Decoder": "encoding/xml", - "xml.Directive": "encoding/xml", - "xml.Encoder": "encoding/xml", - "xml.EndElement": "encoding/xml", - "xml.Escape": "encoding/xml", - "xml.EscapeText": "encoding/xml", - "xml.HTMLAutoClose": "encoding/xml", - "xml.HTMLEntity": "encoding/xml", - "xml.Header": "encoding/xml", - "xml.Marshal": "encoding/xml", - "xml.MarshalIndent": "encoding/xml", - "xml.Marshaler": "encoding/xml", - "xml.MarshalerAttr": "encoding/xml", - "xml.Name": "encoding/xml", - "xml.NewDecoder": "encoding/xml", - "xml.NewEncoder": "encoding/xml", - "xml.ProcInst": "encoding/xml", - "xml.StartElement": "encoding/xml", - "xml.SyntaxError": "encoding/xml", - "xml.TagPathError": "encoding/xml", - "xml.Token": "encoding/xml", - "xml.Unmarshal": "encoding/xml", - "xml.UnmarshalError": "encoding/xml", - "xml.Unmarshaler": "encoding/xml", - "xml.UnmarshalerAttr": "encoding/xml", - "xml.UnsupportedTypeError": "encoding/xml", - "zip.Compressor": "archive/zip", - "zip.Decompressor": "archive/zip", - "zip.Deflate": "archive/zip", - "zip.ErrAlgorithm": "archive/zip", - "zip.ErrChecksum": "archive/zip", - "zip.ErrFormat": "archive/zip", - "zip.File": "archive/zip", - "zip.FileHeader": "archive/zip", - "zip.FileInfoHeader": "archive/zip", - "zip.NewReader": "archive/zip", - "zip.NewWriter": "archive/zip", - "zip.OpenReader": "archive/zip", - "zip.ReadCloser": "archive/zip", - "zip.Reader": "archive/zip", - "zip.RegisterCompressor": "archive/zip", - "zip.RegisterDecompressor": "archive/zip", - "zip.Store": "archive/zip", - "zip.Writer": "archive/zip", - "zlib.BestCompression": "compress/zlib", - "zlib.BestSpeed": "compress/zlib", - "zlib.DefaultCompression": "compress/zlib", - "zlib.ErrChecksum": "compress/zlib", - "zlib.ErrDictionary": "compress/zlib", - "zlib.ErrHeader": "compress/zlib", - "zlib.NewReader": "compress/zlib", - "zlib.NewReaderDict": "compress/zlib", - "zlib.NewWriter": "compress/zlib", - "zlib.NewWriterLevel": "compress/zlib", - "zlib.NewWriterLevelDict": "compress/zlib", - "zlib.NoCompression": "compress/zlib", - "zlib.Resetter": "compress/zlib", - "zlib.Writer": "compress/zlib", - - "unsafe.Alignof": "unsafe", - "unsafe.ArbitraryType": "unsafe", - "unsafe.Offsetof": "unsafe", - "unsafe.Pointer": "unsafe", - "unsafe.Sizeof": "unsafe", -} diff --git a/vendor/gopkg.in/fatih/set.v0/README.md b/vendor/gopkg.in/fatih/set.v0/README.md deleted file mode 100644 index 23afdd98d3..0000000000 --- a/vendor/gopkg.in/fatih/set.v0/README.md +++ /dev/null @@ -1,245 +0,0 @@ -# Set [![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](https://godoc.org/gopkg.in/fatih/set.v0) [![Build Status](http://img.shields.io/travis/fatih/set.svg?style=flat-square)](https://travis-ci.org/fatih/set) - -Set is a basic and simple, hash-based, **Set** data structure implementation -in Go (Golang). - -Set provides both threadsafe and non-threadsafe implementations of a generic -set data structure. The thread safety encompasses all operations on one set. -Operations on multiple sets are consistent in that the elements of each set -used was valid at exactly one point in time between the start and the end of -the operation. Because it's thread safe, you can use it concurrently with your -goroutines. - -For usage see examples below or click on the godoc badge. - -## Install and Usage - -Install the package with: - -```bash -go get gopkg.in/fatih/set.v0 -``` - -Import it with: - -```go -import "gopkg.in/fatih/set.v0" -``` - -and use `set` as the package name inside the code. - -## Examples - -#### Initialization of a new Set - -```go - -// create a set with zero items -s := set.New() -s := set.NewNonTS() // non thread-safe version - -// ... or with some initial values -s := set.New("istanbul", "frankfurt", 30.123, "san francisco", 1234) -s := set.NewNonTS("kenya", "ethiopia", "sumatra") - -``` - -#### Basic Operations - -```go -// add items -s.Add("istanbul") -s.Add("istanbul") // nothing happens if you add duplicate item - -// add multiple items -s.Add("ankara", "san francisco", 3.14) - -// remove item -s.Remove("frankfurt") -s.Remove("frankfurt") // nothing happes if you remove a nonexisting item - -// remove multiple items -s.Remove("barcelona", 3.14, "ankara") - -// removes an arbitary item and return it -item := s.Pop() - -// create a new copy -other := s.Copy() - -// remove all items -s.Clear() - -// number of items in the set -len := s.Size() - -// return a list of items -items := s.List() - -// string representation of set -fmt.Printf("set is %s", s.String()) - -``` - -#### Check Operations - -```go -// check for set emptiness, returns true if set is empty -s.IsEmpty() - -// check for a single item exist -s.Has("istanbul") - -// ... or for multiple items. This will return true if all of the items exist. -s.Has("istanbul", "san francisco", 3.14) - -// create two sets for the following checks... -s := s.New("1", "2", "3", "4", "5") -t := s.New("1", "2", "3") - - -// check if they are the same -if !s.IsEqual(t) { - fmt.Println("s is not equal to t") -} - -// if s contains all elements of t -if s.IsSubset(t) { - fmt.Println("t is a subset of s") -} - -// ... or if s is a superset of t -if t.IsSuperset(s) { - fmt.Println("s is a superset of t") -} - - -``` - -#### Set Operations - - -```go -// let us initialize two sets with some values -a := set.New("ankara", "berlin", "san francisco") -b := set.New("frankfurt", "berlin") - -// creates a new set with the items in a and b combined. -// [frankfurt, berlin, ankara, san francisco] -c := set.Union(a, b) - -// contains items which is in both a and b -// [berlin] -c := set.Intersection(a, b) - -// contains items which are in a but not in b -// [ankara, san francisco] -c := set.Difference(a, b) - -// contains items which are in one of either, but not in both. -// [frankfurt, ankara, san francisco] -c := set.SymmetricDifference(a, b) - -``` - -```go -// like Union but saves the result back into a. -a.Merge(b) - -// removes the set items which are in b from a and saves the result back into a. -a.Separate(b) - -``` - -#### Multiple Set Operations - -```go -a := set.New("1", "3", "4", "5") -b := set.New("2", "3", "4", "5") -c := set.New("4", "5", "6", "7") - -// creates a new set with items in a, b and c -// [1 2 3 4 5 6 7] -u := set.Union(a, b, c) - -// creates a new set with items in a but not in b and c -// [1] -u := set.Difference(a, b, c) - -// creates a new set with items that are common to a, b and c -// [5] -u := set.Intersection(a, b, c) -``` - -#### Helper methods - -The Slice functions below are a convenient way to extract or convert your Set data -into basic data types. - - -```go -// create a set of mixed types -s := set.New("ankara", "5", "8", "san francisco", 13, 21) - - -// convert s into a slice of strings (type is []string) -// [ankara 5 8 san francisco] -t := set.StringSlice(s) - - -// u contains a slice of ints (type is []int) -// [13, 21] -u := set.IntSlice(s) - -``` - -#### Concurrent safe usage - -Below is an example of a concurrent way that uses set. We call ten functions -concurrently and wait until they are finished. It basically creates a new -string for each goroutine and adds it to our set. - -```go -package main - -import ( - "fmt" - "github.com/fatih/set" - "strconv" - "sync" -) - -func main() { - var wg sync.WaitGroup // this is just for waiting until all goroutines finish - - // Initialize our thread safe Set - s := set.New() - - // Add items concurrently (item1, item2, and so on) - for i := 0; i < 10; i++ { - wg.Add(1) - go func(i int) { - item := "item" + strconv.Itoa(i) - fmt.Println("adding", item) - s.Add(item) - wg.Done() - }(i) - } - - // Wait until all concurrent calls finished and print our set - wg.Wait() - fmt.Println(s) -} -``` - -## Credits - - * [Fatih Arslan](https://github.com/fatih) - * [Arne Hormann](https://github.com/arnehormann) - * [Sam Boyer](https://github.com/sdboyer) - * [Ralph Loizzo](https://github.com/friartech) - -## License - -The MIT License (MIT) - see LICENSE.md for more details - diff --git a/vendor/gopkg.in/fatih/set.v0/set.go b/vendor/gopkg.in/fatih/set.v0/set.go deleted file mode 100644 index ac0240ce70..0000000000 --- a/vendor/gopkg.in/fatih/set.v0/set.go +++ /dev/null @@ -1,121 +0,0 @@ -// Package set provides both threadsafe and non-threadsafe implementations of -// a generic set data structure. In the threadsafe set, safety encompasses all -// operations on one set. Operations on multiple sets are consistent in that -// the elements of each set used was valid at exactly one point in time -// between the start and the end of the operation. -package set - -// Interface is describing a Set. Sets are an unordered, unique list of values. -type Interface interface { - New(items ...interface{}) Interface - Add(items ...interface{}) - Remove(items ...interface{}) - Pop() interface{} - Has(items ...interface{}) bool - Size() int - Clear() - IsEmpty() bool - IsEqual(s Interface) bool - IsSubset(s Interface) bool - IsSuperset(s Interface) bool - Each(func(interface{}) bool) - String() string - List() []interface{} - Copy() Interface - Merge(s Interface) - Separate(s Interface) -} - -// helpful to not write everywhere struct{}{} -var keyExists = struct{}{} - -// Union is the merger of multiple sets. It returns a new set with all the -// elements present in all the sets that are passed. -// -// The dynamic type of the returned set is determined by the first passed set's -// implementation of the New() method. -func Union(set1, set2 Interface, sets ...Interface) Interface { - u := set1.Copy() - set2.Each(func(item interface{}) bool { - u.Add(item) - return true - }) - for _, set := range sets { - set.Each(func(item interface{}) bool { - u.Add(item) - return true - }) - } - - return u -} - -// Difference returns a new set which contains items which are in in the first -// set but not in the others. Unlike the Difference() method you can use this -// function separately with multiple sets. -func Difference(set1, set2 Interface, sets ...Interface) Interface { - s := set1.Copy() - s.Separate(set2) - for _, set := range sets { - s.Separate(set) // seperate is thread safe - } - return s -} - -// Intersection returns a new set which contains items that only exist in all given sets. -func Intersection(set1, set2 Interface, sets ...Interface) Interface { - all := Union(set1, set2, sets...) - result := Union(set1, set2, sets...) - - all.Each(func(item interface{}) bool { - if !set1.Has(item) || !set2.Has(item) { - result.Remove(item) - } - - for _, set := range sets { - if !set.Has(item) { - result.Remove(item) - } - } - return true - }) - return result -} - -// SymmetricDifference returns a new set which s is the difference of items which are in -// one of either, but not in both. -func SymmetricDifference(s Interface, t Interface) Interface { - u := Difference(s, t) - v := Difference(t, s) - return Union(u, v) -} - -// StringSlice is a helper function that returns a slice of strings of s. If -// the set contains mixed types of items only items of type string are returned. -func StringSlice(s Interface) []string { - slice := make([]string, 0) - for _, item := range s.List() { - v, ok := item.(string) - if !ok { - continue - } - - slice = append(slice, v) - } - return slice -} - -// IntSlice is a helper function that returns a slice of ints of s. If -// the set contains mixed types of items only items of type int are returned. -func IntSlice(s Interface) []int { - slice := make([]int, 0) - for _, item := range s.List() { - v, ok := item.(int) - if !ok { - continue - } - - slice = append(slice, v) - } - return slice -} diff --git a/vendor/gopkg.in/fatih/set.v0/set_nots.go b/vendor/gopkg.in/fatih/set.v0/set_nots.go deleted file mode 100644 index ec1ab2285f..0000000000 --- a/vendor/gopkg.in/fatih/set.v0/set_nots.go +++ /dev/null @@ -1,195 +0,0 @@ -package set - -import ( - "fmt" - "strings" -) - -// Provides a common set baseline for both threadsafe and non-ts Sets. -type set struct { - m map[interface{}]struct{} // struct{} doesn't take up space -} - -// SetNonTS defines a non-thread safe set data structure. -type SetNonTS struct { - set -} - -// NewNonTS creates and initialize a new non-threadsafe Set. -// It accepts a variable number of arguments to populate the initial set. -// If nothing is passed a SetNonTS with zero size is created. -func NewNonTS(items ...interface{}) *SetNonTS { - s := &SetNonTS{} - s.m = make(map[interface{}]struct{}) - - // Ensure interface compliance - var _ Interface = s - - s.Add(items...) - return s -} - -// New creates and initalizes a new Set interface. It accepts a variable -// number of arguments to populate the initial set. If nothing is passed a -// zero size Set based on the struct is created. -func (s *set) New(items ...interface{}) Interface { - return NewNonTS(items...) -} - -// Add includes the specified items (one or more) to the set. The underlying -// Set s is modified. If passed nothing it silently returns. -func (s *set) Add(items ...interface{}) { - if len(items) == 0 { - return - } - - for _, item := range items { - s.m[item] = keyExists - } -} - -// Remove deletes the specified items from the set. The underlying Set s is -// modified. If passed nothing it silently returns. -func (s *set) Remove(items ...interface{}) { - if len(items) == 0 { - return - } - - for _, item := range items { - delete(s.m, item) - } -} - -// Pop deletes and return an item from the set. The underlying Set s is -// modified. If set is empty, nil is returned. -func (s *set) Pop() interface{} { - for item := range s.m { - delete(s.m, item) - return item - } - return nil -} - -// Has looks for the existence of items passed. It returns false if nothing is -// passed. For multiple items it returns true only if all of the items exist. -func (s *set) Has(items ...interface{}) bool { - // assume checked for empty item, which not exist - if len(items) == 0 { - return false - } - - has := true - for _, item := range items { - if _, has = s.m[item]; !has { - break - } - } - return has -} - -// Size returns the number of items in a set. -func (s *set) Size() int { - return len(s.m) -} - -// Clear removes all items from the set. -func (s *set) Clear() { - s.m = make(map[interface{}]struct{}) -} - -// IsEmpty reports whether the Set is empty. -func (s *set) IsEmpty() bool { - return s.Size() == 0 -} - -// IsEqual test whether s and t are the same in size and have the same items. -func (s *set) IsEqual(t Interface) bool { - // Force locking only if given set is threadsafe. - if conv, ok := t.(*Set); ok { - conv.l.RLock() - defer conv.l.RUnlock() - } - - // return false if they are no the same size - if sameSize := len(s.m) == t.Size(); !sameSize { - return false - } - - equal := true - t.Each(func(item interface{}) bool { - _, equal = s.m[item] - return equal // if false, Each() will end - }) - - return equal -} - -// IsSubset tests whether t is a subset of s. -func (s *set) IsSubset(t Interface) (subset bool) { - subset = true - - t.Each(func(item interface{}) bool { - _, subset = s.m[item] - return subset - }) - - return -} - -// IsSuperset tests whether t is a superset of s. -func (s *set) IsSuperset(t Interface) bool { - return t.IsSubset(s) -} - -// Each traverses the items in the Set, calling the provided function for each -// set member. Traversal will continue until all items in the Set have been -// visited, or if the closure returns false. -func (s *set) Each(f func(item interface{}) bool) { - for item := range s.m { - if !f(item) { - break - } - } -} - -// String returns a string representation of s -func (s *set) String() string { - t := make([]string, 0, len(s.List())) - for _, item := range s.List() { - t = append(t, fmt.Sprintf("%v", item)) - } - - return fmt.Sprintf("[%s]", strings.Join(t, ", ")) -} - -// List returns a slice of all items. There is also StringSlice() and -// IntSlice() methods for returning slices of type string or int. -func (s *set) List() []interface{} { - list := make([]interface{}, 0, len(s.m)) - - for item := range s.m { - list = append(list, item) - } - - return list -} - -// Copy returns a new Set with a copy of s. -func (s *set) Copy() Interface { - return NewNonTS(s.List()...) -} - -// Merge is like Union, however it modifies the current set it's applied on -// with the given t set. -func (s *set) Merge(t Interface) { - t.Each(func(item interface{}) bool { - s.m[item] = keyExists - return true - }) -} - -// it's not the opposite of Merge. -// Separate removes the set items containing in t from set s. Please aware that -func (s *set) Separate(t Interface) { - s.Remove(t.List()...) -} diff --git a/vendor/gopkg.in/fatih/set.v0/set_ts.go b/vendor/gopkg.in/fatih/set.v0/set_ts.go deleted file mode 100644 index 50f532565b..0000000000 --- a/vendor/gopkg.in/fatih/set.v0/set_ts.go +++ /dev/null @@ -1,200 +0,0 @@ -package set - -import ( - "sync" -) - -// Set defines a thread safe set data structure. -type Set struct { - set - l sync.RWMutex // we name it because we don't want to expose it -} - -// New creates and initialize a new Set. It's accept a variable number of -// arguments to populate the initial set. If nothing passed a Set with zero -// size is created. -func New(items ...interface{}) *Set { - s := &Set{} - s.m = make(map[interface{}]struct{}) - - // Ensure interface compliance - var _ Interface = s - - s.Add(items...) - return s -} - -// New creates and initalizes a new Set interface. It accepts a variable -// number of arguments to populate the initial set. If nothing is passed a -// zero size Set based on the struct is created. -func (s *Set) New(items ...interface{}) Interface { - return New(items...) -} - -// Add includes the specified items (one or more) to the set. The underlying -// Set s is modified. If passed nothing it silently returns. -func (s *Set) Add(items ...interface{}) { - if len(items) == 0 { - return - } - - s.l.Lock() - defer s.l.Unlock() - - for _, item := range items { - s.m[item] = keyExists - } -} - -// Remove deletes the specified items from the set. The underlying Set s is -// modified. If passed nothing it silently returns. -func (s *Set) Remove(items ...interface{}) { - if len(items) == 0 { - return - } - - s.l.Lock() - defer s.l.Unlock() - - for _, item := range items { - delete(s.m, item) - } -} - -// Pop deletes and return an item from the set. The underlying Set s is -// modified. If set is empty, nil is returned. -func (s *Set) Pop() interface{} { - s.l.RLock() - for item := range s.m { - s.l.RUnlock() - s.l.Lock() - delete(s.m, item) - s.l.Unlock() - return item - } - s.l.RUnlock() - return nil -} - -// Has looks for the existence of items passed. It returns false if nothing is -// passed. For multiple items it returns true only if all of the items exist. -func (s *Set) Has(items ...interface{}) bool { - // assume checked for empty item, which not exist - if len(items) == 0 { - return false - } - - s.l.RLock() - defer s.l.RUnlock() - - has := true - for _, item := range items { - if _, has = s.m[item]; !has { - break - } - } - return has -} - -// Size returns the number of items in a set. -func (s *Set) Size() int { - s.l.RLock() - defer s.l.RUnlock() - - l := len(s.m) - return l -} - -// Clear removes all items from the set. -func (s *Set) Clear() { - s.l.Lock() - defer s.l.Unlock() - - s.m = make(map[interface{}]struct{}) -} - -// IsEqual test whether s and t are the same in size and have the same items. -func (s *Set) IsEqual(t Interface) bool { - s.l.RLock() - defer s.l.RUnlock() - - // Force locking only if given set is threadsafe. - if conv, ok := t.(*Set); ok { - conv.l.RLock() - defer conv.l.RUnlock() - } - - // return false if they are no the same size - if sameSize := len(s.m) == t.Size(); !sameSize { - return false - } - - equal := true - t.Each(func(item interface{}) bool { - _, equal = s.m[item] - return equal // if false, Each() will end - }) - - return equal -} - -// IsSubset tests whether t is a subset of s. -func (s *Set) IsSubset(t Interface) (subset bool) { - s.l.RLock() - defer s.l.RUnlock() - - subset = true - - t.Each(func(item interface{}) bool { - _, subset = s.m[item] - return subset - }) - - return -} - -// Each traverses the items in the Set, calling the provided function for each -// set member. Traversal will continue until all items in the Set have been -// visited, or if the closure returns false. -func (s *Set) Each(f func(item interface{}) bool) { - s.l.RLock() - defer s.l.RUnlock() - - for item := range s.m { - if !f(item) { - break - } - } -} - -// List returns a slice of all items. There is also StringSlice() and -// IntSlice() methods for returning slices of type string or int. -func (s *Set) List() []interface{} { - s.l.RLock() - defer s.l.RUnlock() - - list := make([]interface{}, 0, len(s.m)) - - for item := range s.m { - list = append(list, item) - } - - return list -} - -// Copy returns a new Set with a copy of s. -func (s *Set) Copy() Interface { - return New(s.List()...) -} - -// Merge is like Union, however it modifies the current set it's applied on -// with the given t set. -func (s *Set) Merge(t Interface) { - s.l.Lock() - defer s.l.Unlock() - - t.Each(func(item interface{}) bool { - s.m[item] = keyExists - return true - }) -} diff --git a/vendor/gopkg.in/karalabe/cookiejar.v2/LICENSE b/vendor/gopkg.in/karalabe/cookiejar.v2/LICENSE deleted file mode 100755 index 467d60878d..0000000000 --- a/vendor/gopkg.in/karalabe/cookiejar.v2/LICENSE +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2014 Péter Szilágyi. All rights reserved. - -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. - -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 HOLDER 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. - -Alternatively, the CookieJar toolbox may be used in accordance with the terms -and conditions contained in a signed written agreement between you and the -author(s). diff --git a/vendor/gopkg.in/karalabe/cookiejar.v2/README.md b/vendor/gopkg.in/karalabe/cookiejar.v2/README.md deleted file mode 100755 index 44c420b60e..0000000000 --- a/vendor/gopkg.in/karalabe/cookiejar.v2/README.md +++ /dev/null @@ -1,109 +0,0 @@ - CookieJar - A contestant's toolbox -====================================== - -CookieJar is a small collection of common algorithms, data structures and library extensions that were deemed handy for computing competitions at one point or another. - -This toolbox is a work in progress for the time being. It may be lacking, and it may change drastically between commits (although every effort is made not to). You're welcome to use it, but it's your head on the line :) - - Installation ----------------- - -To get the package, execute: - - go get gopkg.in/karalabe/cookiejar.v2 - -To import this package, add the following line to your code: - - import "gopkg.in/karalabe/cookiejar.v2" - -For more details, see the [package documentation](http://godoc.org/gopkg.in/karalabe/cookiejar.v2). - - Contents ------------- - -Algorithms: - - Graph - - [Breadth First Search](http://godoc.org/gopkg.in/karalabe/cookiejar.v2/graph/bfs) - - [Depth First Search](http://godoc.org/gopkg.in/karalabe/cookiejar.v2/graph/dfs) - -Data structures: - - [Bag](http://godoc.org/gopkg.in/karalabe/cookiejar.v2/collections/bag) - - [Deque](http://godoc.org/gopkg.in/karalabe/cookiejar.v2/collections/deque) - - [Graph](http://godoc.org/gopkg.in/karalabe/cookiejar.v2/graph) - - [Priority Queue](http://godoc.org/gopkg.in/karalabe/cookiejar.v2/collections/prque) - - [Queue](http://godoc.org/gopkg.in/karalabe/cookiejar.v2/collections/queue) - - [Set](http://godoc.org/gopkg.in/karalabe/cookiejar.v2/collections/set) - - [Stack](http://godoc.org/gopkg.in/karalabe/cookiejar.v2/collections/stack) - -Extensions: - - [fmt](http://godoc.org/gopkg.in/karalabe/cookiejar.v2/exts/fmtext) - - `Scan` and `Fscan` for `int`, `float64`, `string` and lines - - [math](http://godoc.org/gopkg.in/karalabe/cookiejar.v2/exts/mathext) - - `Abs` for `int` - - `Min` and `Max` for `int`, `big.Int` and `big.Rat` - - `Sign` for `int` and `float64` - - [os](http://godoc.org/gopkg.in/karalabe/cookiejar.v2/exts/osext) - - `Open` and `Create` without error codes - - [sort](http://godoc.org/gopkg.in/karalabe/cookiejar.v2/exts/sortext) - - `Sort` and `Search` for `big.Int` and `big.Rat` - - `Unique` for any `sort.Interface` - -Below are the performance results for the data structures and the complexity analysis for the algorithms. - - Performance ---------------- - -Intel(R) Core(TM) i7-2600 CPU @ 3.40GHz: -``` -- bag - - BenchmarkInsert 309 ns/op - - BenchmarkRemove 197 ns/op - - BenchmarkDo 28.1 ns/op -- deque - - BenchmarkPush 25.4 ns/op - - BenchmarkPop 6.72 ns/op -- prque - - BenchmarkPush 171 ns/op - - BenchmarkPop 947 ns/op -- queue - - BenchmarkPush 23.0 ns/op - - BenchmarkPop 5.92 ns/op -- set - - BenchmarkInsert 259 ns/op - - BenchmarkRemove 115 ns/op - - BenchmarkDo 20.9 ns/op -- stack - - BenchmarkPush 16.4 ns/op - - BenchmarkPop 6.45 ns/op -``` - - Complexity --------------- - -| Algorithm | Time complexity | Space complexity | -|:---------:|:---------------:|:----------------:| -| graph/bfs | O(E) | O(V) | -| graph/dfs | O(E) | O(E) | - - Here be dragons :) ----------------------- - -``` - . _///_, - . / ` ' '> - ) o' __/_'> - ( / _/ )_\'> - ' "__/ /_/\_> - ____/_/_/_/ - /,---, _/ / - "" /_/_/_/ - /_(_(_(_ \ - ( \_\_\\_ )\ - \'__\_\_\_\__ ).\ - //____|___\__) )_/ - | _ \'___'_( /' - \_ (-'\'___'_\ __,'_' - __) \ \\___(_ __/.__,' - ,((,-,__\ '", __\_/. __,' - '"./_._._-' -``` diff --git a/vendor/gopkg.in/karalabe/cookiejar.v2/collections/prque/prque.go b/vendor/gopkg.in/karalabe/cookiejar.v2/collections/prque/prque.go deleted file mode 100755 index 5c1967c658..0000000000 --- a/vendor/gopkg.in/karalabe/cookiejar.v2/collections/prque/prque.go +++ /dev/null @@ -1,66 +0,0 @@ -// CookieJar - A contestant's algorithm toolbox -// Copyright (c) 2013 Peter Szilagyi. All rights reserved. -// -// CookieJar is dual licensed: use of this source code is governed by a BSD -// license that can be found in the LICENSE file. Alternatively, the CookieJar -// toolbox may be used in accordance with the terms and conditions contained -// in a signed written agreement between you and the author(s). - -// Package prque implements a priority queue data structure supporting arbitrary -// value types and float priorities. -// -// The reasoning behind using floats for the priorities vs. ints or interfaces -// was larger flexibility without sacrificing too much performance or code -// complexity. -// -// If you would like to use a min-priority queue, simply negate the priorities. -// -// Internally the queue is based on the standard heap package working on a -// sortable version of the block based stack. -package prque - -import ( - "container/heap" -) - -// Priority queue data structure. -type Prque struct { - cont *sstack -} - -// Creates a new priority queue. -func New() *Prque { - return &Prque{newSstack()} -} - -// Pushes a value with a given priority into the queue, expanding if necessary. -func (p *Prque) Push(data interface{}, priority float32) { - heap.Push(p.cont, &item{data, priority}) -} - -// Pops the value with the greates priority off the stack and returns it. -// Currently no shrinking is done. -func (p *Prque) Pop() (interface{}, float32) { - item := heap.Pop(p.cont).(*item) - return item.value, item.priority -} - -// Pops only the item from the queue, dropping the associated priority value. -func (p *Prque) PopItem() interface{} { - return heap.Pop(p.cont).(*item).value -} - -// Checks whether the priority queue is empty. -func (p *Prque) Empty() bool { - return p.cont.Len() == 0 -} - -// Returns the number of element in the priority queue. -func (p *Prque) Size() int { - return p.cont.Len() -} - -// Clears the contents of the priority queue. -func (p *Prque) Reset() { - *p = *New() -} diff --git a/vendor/gopkg.in/olebedev/go-duktape.v3/api.go b/vendor/gopkg.in/olebedev/go-duktape.v3/api.go index 6617ec23db..924b5c32fc 100644 --- a/vendor/gopkg.in/olebedev/go-duktape.v3/api.go +++ b/vendor/gopkg.in/olebedev/go-duktape.v3/api.go @@ -1,8 +1,8 @@ package duktape /* -#cgo !windows CFLAGS: -std=c99 -O3 -Wall -fomit-frame-pointer -fstrict-aliasing -#cgo windows CFLAGS: -O3 -Wall -fomit-frame-pointer -fstrict-aliasing +#cgo !windows CFLAGS: -std=c99 -O3 -Wall -Wno-unused-value -fomit-frame-pointer -fstrict-aliasing +#cgo windows CFLAGS: -O3 -Wall -Wno-unused-value -fomit-frame-pointer -fstrict-aliasing #include "duktape.h" #include "duk_logging.h" diff --git a/vendor/gopkg.in/olebedev/go-duktape.v3/duktape.go b/vendor/gopkg.in/olebedev/go-duktape.v3/duktape.go index f0806fcae1..83a7a80872 100644 --- a/vendor/gopkg.in/olebedev/go-duktape.v3/duktape.go +++ b/vendor/gopkg.in/olebedev/go-duktape.v3/duktape.go @@ -5,6 +5,7 @@ package duktape #cgo windows CFLAGS: -O3 -Wall -fomit-frame-pointer -fstrict-aliasing #cgo linux LDFLAGS: -lm #cgo freebsd LDFLAGS: -lm +#cgo openbsd LDFLAGS: -lm #include "duktape.h" #include "duk_logging.h" diff --git a/vendor/vendor.json b/vendor/vendor.json index 4360223298..a7cd0821e5 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -21,28 +21,16 @@ "revisionTime": "2016-08-11T21:22:31Z" }, { - "checksumSHA1": "24EW3PGLGVSy/5joAOZdHzN/S2E=", - "path": "github.com/Azure/azure-storage-go", - "revision": "12ccaadb081cdd217702067d28da9a7ff4305239", - "revisionTime": "2017-03-02T22:15:08Z" + "checksumSHA1": "z+M6FYl9EKsoZZMLcT0Ktwfk8pI=", + "path": "github.com/Azure/azure-pipeline-go/pipeline", + "revision": "7571e8eb0876932ab505918ff7ed5107773e5ee2", + "revisionTime": "2018-06-07T21:19:23Z" }, { - "checksumSHA1": "+sxS3YEvxf1VxlRskIdXFRWq9rY=", - "path": "github.com/Azure/go-autorest/autorest", - "revision": "ec5f4903f77ed9927ac95b19ab8e44ada64c1356", - "revisionTime": "2017-02-15T19:58:14Z" - }, - { - "checksumSHA1": "ghrnc4vZv6q8zzeakZnrS8CGFhE=", - "path": "github.com/Azure/go-autorest/autorest/azure", - "revision": "ec5f4903f77ed9927ac95b19ab8e44ada64c1356", - "revisionTime": "2017-02-15T19:58:14Z" - }, - { - "checksumSHA1": "q9Qz8PAxK5FTOZwgYKe5Lj38u4c=", - "path": "github.com/Azure/go-autorest/autorest/date", - "revision": "ec5f4903f77ed9927ac95b19ab8e44ada64c1356", - "revisionTime": "2017-02-15T19:58:14Z" + "checksumSHA1": "5nsGu77r69lloEWbFhMof2UA9rY=", + "path": "github.com/Azure/azure-storage-blob-go/2018-03-28/azblob", + "revision": "eaae161d9d5e07363f04ddb19d84d57efc66d1a1", + "revisionTime": "2018-07-12T00:56:34Z" }, { "checksumSHA1": "QC55lHNOv1+UAL2xtIHw17MJ8J8=", @@ -50,6 +38,18 @@ "revision": "5d049714c4a64225c3c79a7cf7d02f7fb5b96338", "revisionTime": "2018-01-16T20:38:02Z" }, + { + "checksumSHA1": "8skJYOdQytXjimcDPLRW4tonX3A=", + "path": "github.com/allegro/bigcache", + "revision": "e24eb225f15679bbe54f91bfa7da3b00e59b9768", + "revisionTime": "2019-02-18T06:46:05Z" + }, + { + "checksumSHA1": "vtT7NcYLatJmxVQQEeSESyrgVg0=", + "path": "github.com/allegro/bigcache/queue", + "revision": "e24eb225f15679bbe54f91bfa7da3b00e59b9768", + "revisionTime": "2019-02-18T06:46:05Z" + }, { "checksumSHA1": "USkefO0g1U9mr+8hagv3fpSkrxg=", "path": "github.com/aristanetworks/goarista/monotime", @@ -68,12 +68,24 @@ "revision": "165db2f241fd235aec29ba6d9b1ccd5f1c14637c", "revisionTime": "2015-01-22T07:26:53Z" }, + { + "checksumSHA1": "7gK+lSShSu1NRw83/A95BcgMqsI=", + "path": "github.com/codahale/hdrhistogram", + "revision": "3a0bb77429bd3a61596f5e8a3172445844342120", + "revisionTime": "2016-10-10T02:54:55Z" + }, { "checksumSHA1": "dvabztWVQX8f6oMLRyv4dLH+TGY=", "path": "github.com/davecgh/go-spew/spew", "revision": "346938d642f2ec3594ed81d874461961cd0faa76", "revisionTime": "2016-10-29T20:57:26Z" }, + { + "checksumSHA1": "1xK7ycc1ICRInk/S9iiyB9Rpv50=", + "path": "github.com/deckarep/golang-set", + "revision": "504e848d77ea4752b3057b8fb46da0e7f746ccf3", + "revisionTime": "2018-06-03T19:32:48Z" + }, { "checksumSHA1": "2Fy1Y6Z3lRRX1891WF/+HT4XS2I=", "path": "github.com/dgrijalva/jwt-go", @@ -81,10 +93,10 @@ "revisionTime": "2017-02-01T22:58:49Z" }, { - "checksumSHA1": "lutCa+IVM60R1OYBm9RtDAW50Ys=", + "checksumSHA1": "Ad8LPSCP9HctFrmskh+S5HpHXcs=", "path": "github.com/docker/docker/pkg/reexec", - "revision": "83ee902ecc3790c33c1e2d87334074436056bb49", - "revisionTime": "2017-04-22T21:51:12Z" + "revision": "8e610b2b55bfd1bfa9436ab110d311f5e8a74dcb", + "revisionTime": "2018-06-25T18:44:42Z" }, { "checksumSHA1": "zYnPsNAVm1/ViwCkN++dX2JQhBo=", @@ -93,10 +105,10 @@ "revisionTime": "2016-05-12T03:30:02Z" }, { - "checksumSHA1": "Fc8BCxCoQ7ZmghDT6X1cASR10Ec=", + "checksumSHA1": "jElNoLEe7m/iaoF1vYIHyNaS2SE=", "path": "github.com/elastic/gosigar", - "revision": "a3814ce5008e612a0c6d027608b54e1d0d9a5613", - "revisionTime": "2018-01-22T22:25:45Z" + "revision": "37f05ff46ffa7a825d1b24cf2b62d4a4c1a9d2e8", + "revisionTime": "2018-03-30T10:04:40Z" }, { "checksumSHA1": "qDsgp2kAeI9nhj565HUScaUyjU4=", @@ -110,6 +122,18 @@ "revision": "5ec5d9d3c2cf82e9688b34e9bc27a94d616a7193", "revisionTime": "2017-02-09T08:00:14Z" }, + { + "checksumSHA1": "Jq1rrHSGPfh689nA2hL1QVb62zE=", + "path": "github.com/fjl/memsize", + "revision": "ca190fb6ffbc076ff49197b7168a760f30182d2e", + "revisionTime": "2018-04-18T12:24:29Z" + }, + { + "checksumSHA1": "Z13QAYTqeW4cTiglkc2F05gWLu4=", + "path": "github.com/fjl/memsize/memsizeui", + "revision": "ca190fb6ffbc076ff49197b7168a760f30182d2e", + "revisionTime": "2018-04-18T12:24:29Z" + }, { "checksumSHA1": "0orwvPL96wFckVJyPl39fz2QsgA=", "path": "github.com/gizak/termui", @@ -206,6 +230,30 @@ "revision": "679507af18f3c7ba2bcc7905392ce23e148661c3", "revisionTime": "2016-12-24T10:41:01Z" }, + { + "checksumSHA1": "6tNwbL5tUS0dxYzADKVZtI2d/lE=", + "path": "github.com/influxdata/influxdb/client", + "revision": "a55dd0f50edd14c9c798d3564189eb4f53914309", + "revisionTime": "2017-10-09T17:24:46Z" + }, + { + "checksumSHA1": "O4XpbSNeUhSIMD2FWtQximJiFIs=", + "path": "github.com/influxdata/influxdb/client/v2", + "revision": "b36b9f109f2da91c8941679caf5356e08eee0b2b", + "revisionTime": "2018-01-17T01:42:09Z" + }, + { + "checksumSHA1": "cfumoC9gHEUROd+fA8qK3WLFAZQ=", + "path": "github.com/influxdata/influxdb/models", + "revision": "b36b9f109f2da91c8941679caf5356e08eee0b2b", + "revisionTime": "2018-01-17T01:42:09Z" + }, + { + "checksumSHA1": "Z0Bb5PWa5WL/j5Dm2KJCLGn1l7U=", + "path": "github.com/influxdata/influxdb/pkg/escape", + "revision": "01288bdb0883a01cac999326bd34421b29acaec8", + "revisionTime": "2018-02-21T22:33:40Z" + }, { "checksumSHA1": "vTGKMIfiMwz43y5bsgx9PrL+AVw=", "path": "github.com/jackpal/go-nat-pmp", @@ -219,10 +267,10 @@ "revisionTime": "2017-04-30T22:20:11Z" }, { - "checksumSHA1": "UpjhOUZ1+0zNt+iIvdtECSHXmTs=", + "checksumSHA1": "6XsjAARQFvlW6dS15al0ibTFPOQ=", "path": "github.com/karalabe/hid", - "revision": "f00545f9f3748e591590be3732d913c77525b10f", - "revisionTime": "2017-08-21T10:38:37Z", + "revision": "d815e0c1a2e2082a287a2806bc90bc8fc7b276a9", + "revisionTime": "2018-11-28T19:21:57Z", "tree": true }, { @@ -232,22 +280,23 @@ "revisionTime": "2016-07-20T14:16:34Z" }, { - "checksumSHA1": "I4njd26dG5hxFT2nawuByM4pxzY=", + "checksumSHA1": "SEnjvwVyfuU2xBaOfXfwPD5MZqk=", "path": "github.com/mattn/go-colorable", - "revision": "5411d3eea5978e6cdc258b30de592b60df6aba96", - "revisionTime": "2017-02-10T17:28:01Z" + "revision": "efa589957cd060542a26d2dd7832fd6a6c6c3ade", + "revisionTime": "2018-03-10T13:32:14Z", + "version": "efa589957cd060542a26d2dd7832fd6a6c6c3ade" }, { - "checksumSHA1": "EkT5JmFvz3zOPWappEFyYWUaeY0=", + "checksumSHA1": "GiVgQkx5acnq+JZtYiuHPlhHoso=", "path": "github.com/mattn/go-isatty", - "revision": "281032e84ae07510239465db46bf442aa44b953a", - "revisionTime": "2017-02-09T17:56:15Z" + "revision": "3fb116b820352b7f0c281308a4d6250c22d94e27", + "revisionTime": "2018-08-30T10:17:45Z" }, { "checksumSHA1": "MNkKJyk2TazKMJYbal5wFHybpyA=", "path": "github.com/mattn/go-runewidth", - "revision": "14207d285c6c197daabb5c9793d63e7af9ab2d50", - "revisionTime": "2017-02-01T02:35:40Z" + "revision": "ce7b0b5c7b45a81508558cd1dba6bb1e4ddb51bb", + "revisionTime": "2018-04-08T05:53:51Z" }, { "checksumSHA1": "L3leymg2RT8hFl5uL+5KP/LpBkg=", @@ -256,10 +305,16 @@ "revisionTime": "2015-03-14T17:03:34Z" }, { - "checksumSHA1": "2gmvVTDCks8cPhpmyDlvm0sbrXE=", + "checksumSHA1": "2jsbDTvwxafPp7FJjJ8IIFlTLjs=", + "path": "github.com/mohae/deepcopy", + "revision": "c48cc78d482608239f6c4c92a4abd87eb8761c90", + "revisionTime": "2017-09-29T03:49:55Z" + }, + { + "checksumSHA1": "FYM/8R2CqS6PSNAoKl6X5gNJ20A=", "path": "github.com/naoina/toml", - "revision": "ac014c6b6502388d89a85552b7208b8da7cfe104", - "revisionTime": "2017-04-10T21:57:17Z" + "revision": "9fafd69674167c06933b1787ae235618431ce87f", + "revisionTime": "2017-09-18T21:04:37Z" }, { "checksumSHA1": "xZBlSMT5o/A+EDOro6KbfHZwSNc=", @@ -279,6 +334,24 @@ "revision": "febf2d34b54a69ce7530036c7503b1c9fbfdf0bb", "revisionTime": "2017-01-28T05:05:32Z" }, + { + "checksumSHA1": "wIcN7tZiF441h08RHAm4NV8cYO4=", + "path": "github.com/opentracing/opentracing-go", + "revision": "bd9c3193394760d98b2fa6ebb2291f0cd1d06a7d", + "revisionTime": "2018-06-06T20:41:48Z" + }, + { + "checksumSHA1": "uhDxBvLEqRAMZKgpTZ8MFuLIIM8=", + "path": "github.com/opentracing/opentracing-go/ext", + "revision": "bd9c3193394760d98b2fa6ebb2291f0cd1d06a7d", + "revisionTime": "2018-06-06T20:41:48Z" + }, + { + "checksumSHA1": "tnkdNJbJxNKuPZMWapP1xhKIIGw=", + "path": "github.com/opentracing/opentracing-go/log", + "revision": "bd9c3193394760d98b2fa6ebb2291f0cd1d06a7d", + "revisionTime": "2018-06-06T20:41:48Z" + }, { "checksumSHA1": "Se195FlZ160eaEk/uVx4KdTPSxU=", "path": "github.com/pborman/uuid", @@ -286,10 +359,10 @@ "revisionTime": "2017-01-12T15:04:04Z" }, { - "checksumSHA1": "lSRg5clrIZUxq4aaExbpnpAgtWA=", + "checksumSHA1": "fGwQlTsml12gzgbWjOyyKPzbMD8=", "path": "github.com/peterh/liner", - "revision": "a37ad39843113264dae84a5d89fcee28f50b35c6", - "revisionTime": "2017-09-02T20:46:57Z" + "revision": "a2c9a5303de792c7581a3b80a8f10258319bb20e", + "revisionTime": "2019-01-23T17:38:45Z" }, { "checksumSHA1": "xCv4GBFyw07vZkVtKF/XrUnkHRk=", @@ -310,22 +383,10 @@ "revisionTime": "2017-08-14T17:01:13Z" }, { - "checksumSHA1": "KAzbLjI9MzW2tjfcAsK75lVRp6I=", - "path": "github.com/rcrowley/go-metrics", - "revision": "1f30fe9094a513ce4c700b9a54458bbb0c96996c", - "revisionTime": "2016-11-28T21:05:44Z" - }, - { - "checksumSHA1": "q/d9nXRQYKEJ/EWn+5y6jL8rPGs=", - "path": "github.com/rcrowley/go-metrics/exp", - "revision": "1f30fe9094a513ce4c700b9a54458bbb0c96996c", - "revisionTime": "2016-11-28T21:05:44Z" - }, - { - "checksumSHA1": "1ESHllhZOIBg7MnlGHUdhz047bI=", + "checksumSHA1": "lU41NL1TEDtsrr0yUdp3SMB4Y9o=", "path": "github.com/rjeczalik/notify", - "revision": "27b537f07230b3f917421af6dcf044038dbe57e2", - "revisionTime": "2018-01-03T13:19:05Z" + "revision": "0f065fa99b48b842c3fd3e2c8b194c6f2b69f6b8", + "revisionTime": "2018-08-27T19:31:19Z" }, { "checksumSHA1": "5uqO4ITTDMklKi3uNaE/D9LQ5nM=", @@ -394,166 +455,292 @@ "revisionTime": "2017-07-05T02:17:15Z" }, { - "checksumSHA1": "rpu5ZHjXlV13UKA7L1d5MTOyQwA=", + "checksumSHA1": "4vxle8JfbPDO0ndiBUjMmRXGBQM=", "path": "github.com/syndtr/goleveldb/leveldb", - "revision": "211f780988068502fe874c44dae530528ebd840f", - "revisionTime": "2018-01-28T14:04:16Z" + "revision": "3a907f965fc16db5f7787e18d4434bbe46d47f6e", + "revisionTime": "2019-03-04T06:08:05Z" }, { - "checksumSHA1": "EKIow7XkgNdWvR/982ffIZxKG8Y=", + "checksumSHA1": "mPNraL2edpk/2FYq26rSXfMHbJg=", "path": "github.com/syndtr/goleveldb/leveldb/cache", - "revision": "b89cc31ef7977104127d34c1bd31ebd1a9db2199", - "revisionTime": "2017-07-25T06:48:36Z" + "revision": "b001fa50d6b27f3f0bb175a87d0cb55426d0a0ae", + "revisionTime": "2018-11-28T10:09:59Z" }, { - "checksumSHA1": "5KPgnvCPlR0ysDAqo6jApzRQ3tw=", + "checksumSHA1": "UA+PKDKWlDnE2OZblh23W6wZwbY=", "path": "github.com/syndtr/goleveldb/leveldb/comparer", - "revision": "b89cc31ef7977104127d34c1bd31ebd1a9db2199", - "revisionTime": "2017-07-25T06:48:36Z" + "revision": "b001fa50d6b27f3f0bb175a87d0cb55426d0a0ae", + "revisionTime": "2018-11-28T10:09:59Z" }, { "checksumSHA1": "1DRAxdlWzS4U0xKN/yQ/fdNN7f0=", "path": "github.com/syndtr/goleveldb/leveldb/errors", - "revision": "b89cc31ef7977104127d34c1bd31ebd1a9db2199", - "revisionTime": "2017-07-25T06:48:36Z" + "revision": "b001fa50d6b27f3f0bb175a87d0cb55426d0a0ae", + "revisionTime": "2018-11-28T10:09:59Z" }, { "checksumSHA1": "eqKeD6DS7eNCtxVYZEHHRKkyZrw=", "path": "github.com/syndtr/goleveldb/leveldb/filter", - "revision": "b89cc31ef7977104127d34c1bd31ebd1a9db2199", - "revisionTime": "2017-07-25T06:48:36Z" + "revision": "b001fa50d6b27f3f0bb175a87d0cb55426d0a0ae", + "revisionTime": "2018-11-28T10:09:59Z" }, { - "checksumSHA1": "8dXuAVIsbtaMiGGuHjzGR6Ny/5c=", + "checksumSHA1": "hPyFsMiqZ1OB7MX+6wIAA6nsdtc=", "path": "github.com/syndtr/goleveldb/leveldb/iterator", - "revision": "b89cc31ef7977104127d34c1bd31ebd1a9db2199", - "revisionTime": "2017-07-25T06:48:36Z" + "revision": "b001fa50d6b27f3f0bb175a87d0cb55426d0a0ae", + "revisionTime": "2018-11-28T10:09:59Z" }, { "checksumSHA1": "gJY7bRpELtO0PJpZXgPQ2BYFJ88=", "path": "github.com/syndtr/goleveldb/leveldb/journal", - "revision": "b89cc31ef7977104127d34c1bd31ebd1a9db2199", - "revisionTime": "2017-07-25T06:48:36Z" + "revision": "b001fa50d6b27f3f0bb175a87d0cb55426d0a0ae", + "revisionTime": "2018-11-28T10:09:59Z" }, { - "checksumSHA1": "j+uaQ6DwJ50dkIdfMQu1TXdlQcY=", + "checksumSHA1": "MtYY1b2234y/MlS+djL8tXVAcQs=", "path": "github.com/syndtr/goleveldb/leveldb/memdb", - "revision": "b89cc31ef7977104127d34c1bd31ebd1a9db2199", - "revisionTime": "2017-07-25T06:48:36Z" + "revision": "b001fa50d6b27f3f0bb175a87d0cb55426d0a0ae", + "revisionTime": "2018-11-28T10:09:59Z" }, { - "checksumSHA1": "UmQeotV+m8/FduKEfLOhjdp18rs=", + "checksumSHA1": "o2TorI3z+vc+EBMJ8XeFoUmXBtU=", "path": "github.com/syndtr/goleveldb/leveldb/opt", - "revision": "b89cc31ef7977104127d34c1bd31ebd1a9db2199", - "revisionTime": "2017-07-25T06:48:36Z" + "revision": "b001fa50d6b27f3f0bb175a87d0cb55426d0a0ae", + "revisionTime": "2018-11-28T10:09:59Z" }, { - "checksumSHA1": "tQ2AqXXAEy9icbZI9dLVdZGvWMw=", + "checksumSHA1": "ZnyuciM+R19NG8L5YS3TIJdo1e8=", "path": "github.com/syndtr/goleveldb/leveldb/storage", - "revision": "b89cc31ef7977104127d34c1bd31ebd1a9db2199", - "revisionTime": "2017-07-25T06:48:36Z" + "revision": "b001fa50d6b27f3f0bb175a87d0cb55426d0a0ae", + "revisionTime": "2018-11-28T10:09:59Z" }, { "checksumSHA1": "gWFPMz8OQeul0t54RM66yMTX49g=", "path": "github.com/syndtr/goleveldb/leveldb/table", - "revision": "b89cc31ef7977104127d34c1bd31ebd1a9db2199", - "revisionTime": "2017-07-25T06:48:36Z" + "revision": "b001fa50d6b27f3f0bb175a87d0cb55426d0a0ae", + "revisionTime": "2018-11-28T10:09:59Z" }, { - "checksumSHA1": "4zil8Gwg8VPkDn1YzlgCvtukJFU=", + "checksumSHA1": "V/Dh7NV0/fy/5jX1KaAjmGcNbzI=", "path": "github.com/syndtr/goleveldb/leveldb/util", - "revision": "b89cc31ef7977104127d34c1bd31ebd1a9db2199", - "revisionTime": "2017-07-25T06:48:36Z" + "revision": "b001fa50d6b27f3f0bb175a87d0cb55426d0a0ae", + "revisionTime": "2018-11-28T10:09:59Z" + }, + { + "checksumSHA1": "nD6S4KB0S+YHxVMDDE+w3PyXaMk=", + "path": "github.com/uber/jaeger-client-go", + "revision": "f7e0d4744fa6d5287c53b8ac8d4f83089ce07ce8", + "revisionTime": "2018-06-07T15:18:42Z" + }, + { + "checksumSHA1": "cjhPfiQbTqfkHmZM3Bi+Bm8qgN4=", + "path": "github.com/uber/jaeger-client-go/config", + "revision": "f7e0d4744fa6d5287c53b8ac8d4f83089ce07ce8", + "revisionTime": "2018-06-07T15:18:42Z" + }, + { + "checksumSHA1": "KM5UXTWkHULmw0dDRNuk8ogWyGs=", + "path": "github.com/uber/jaeger-client-go/internal/baggage", + "revision": "f7e0d4744fa6d5287c53b8ac8d4f83089ce07ce8", + "revisionTime": "2018-06-07T15:18:42Z" + }, + { + "checksumSHA1": "tZqlcHV1XoLdZp9jfnydzsZAvYo=", + "path": "github.com/uber/jaeger-client-go/internal/baggage/remote", + "revision": "f7e0d4744fa6d5287c53b8ac8d4f83089ce07ce8", + "revisionTime": "2018-06-07T15:18:42Z" + }, + { + "checksumSHA1": "QB0L0GrzyMGQp6ivkkxp7a1DPsE=", + "path": "github.com/uber/jaeger-client-go/internal/spanlog", + "revision": "f7e0d4744fa6d5287c53b8ac8d4f83089ce07ce8", + "revisionTime": "2018-06-07T15:18:42Z" + }, + { + "checksumSHA1": "79HRO/+ekkpwqDB/OMiW+AHJtlE=", + "path": "github.com/uber/jaeger-client-go/internal/throttler", + "revision": "f7e0d4744fa6d5287c53b8ac8d4f83089ce07ce8", + "revisionTime": "2018-06-07T15:18:42Z" + }, + { + "checksumSHA1": "OVQDWFtFMs+NODe0F/S5kYViQco=", + "path": "github.com/uber/jaeger-client-go/internal/throttler/remote", + "revision": "f7e0d4744fa6d5287c53b8ac8d4f83089ce07ce8", + "revisionTime": "2018-06-07T15:18:42Z" + }, + { + "checksumSHA1": "tMP/vxbHwNAbOEaUhic5/meKfac=", + "path": "github.com/uber/jaeger-client-go/log", + "revision": "f7e0d4744fa6d5287c53b8ac8d4f83089ce07ce8", + "revisionTime": "2018-06-07T15:18:42Z" + }, + { + "checksumSHA1": "j4WrA/B2SJCqHxttCQ+TYbmtQqE=", + "path": "github.com/uber/jaeger-client-go/rpcmetrics", + "revision": "f7e0d4744fa6d5287c53b8ac8d4f83089ce07ce8", + "revisionTime": "2018-06-07T15:18:42Z" + }, + { + "checksumSHA1": "+ffspyTBQLql2UiU6muvfWR/m1o=", + "path": "github.com/uber/jaeger-client-go/thrift", + "revision": "f7e0d4744fa6d5287c53b8ac8d4f83089ce07ce8", + "revisionTime": "2018-06-07T15:18:42Z" + }, + { + "checksumSHA1": "fMIQ4sJFCkqFYhXvvLKIlofqxvY=", + "path": "github.com/uber/jaeger-client-go/thrift-gen/agent", + "revision": "f7e0d4744fa6d5287c53b8ac8d4f83089ce07ce8", + "revisionTime": "2018-06-07T15:18:42Z" + }, + { + "checksumSHA1": "fRR2p+JAp7paApf32YuQuWU7yzY=", + "path": "github.com/uber/jaeger-client-go/thrift-gen/baggage", + "revision": "f7e0d4744fa6d5287c53b8ac8d4f83089ce07ce8", + "revisionTime": "2018-06-07T15:18:42Z" + }, + { + "checksumSHA1": "JZkMEOmiOFFEuGCsDOVLK5RzvMM=", + "path": "github.com/uber/jaeger-client-go/thrift-gen/jaeger", + "revision": "f7e0d4744fa6d5287c53b8ac8d4f83089ce07ce8", + "revisionTime": "2018-06-07T15:18:42Z" + }, + { + "checksumSHA1": "0teQUhTqTE1fLs+vbnTTzWOqdEQ=", + "path": "github.com/uber/jaeger-client-go/thrift-gen/sampling", + "revision": "f7e0d4744fa6d5287c53b8ac8d4f83089ce07ce8", + "revisionTime": "2018-06-07T15:18:42Z" + }, + { + "checksumSHA1": "Nx5witfz05BSO2YlFzh2Gno6bA0=", + "path": "github.com/uber/jaeger-client-go/thrift-gen/zipkincore", + "revision": "f7e0d4744fa6d5287c53b8ac8d4f83089ce07ce8", + "revisionTime": "2018-06-07T15:18:42Z" + }, + { + "checksumSHA1": "DKwwIk9vq53IKO7RKccat9cnqeo=", + "path": "github.com/uber/jaeger-client-go/utils", + "revision": "f7e0d4744fa6d5287c53b8ac8d4f83089ce07ce8", + "revisionTime": "2018-06-07T15:18:42Z" + }, + { + "checksumSHA1": "k1iaOSBmLp3TpGvHNnRQXyJfwyI=", + "path": "github.com/uber/jaeger-lib/metrics", + "revision": "a51202d6f4a7e5a219e3841a43614ff7187ae7f1", + "revisionTime": "2018-06-15T20:27:29Z" }, { "checksumSHA1": "TT1rac6kpQp2vz24m5yDGUNQ/QQ=", "path": "golang.org/x/crypto/cast5", - "revision": "6a293f2d4b14b8e6d3f0539e383f6d0d30fce3fd", - "revisionTime": "2017-09-25T11:22:06Z" + "revision": "ff983b9c42bc9fbf91556e191cc8efb585c16908", + "revisionTime": "2018-07-25T11:53:45Z" }, { "checksumSHA1": "IQkUIOnvlf0tYloFx9mLaXSvXWQ=", "path": "golang.org/x/crypto/curve25519", - "revision": "6a293f2d4b14b8e6d3f0539e383f6d0d30fce3fd", - "revisionTime": "2017-09-25T11:22:06Z" + "revision": "ff983b9c42bc9fbf91556e191cc8efb585c16908", + "revisionTime": "2018-07-25T11:53:45Z" }, { - "checksumSHA1": "1hwn8cgg4EVXhCpJIqmMbzqnUo0=", + "checksumSHA1": "2LpxYGSf068307b7bhAuVjvzLLc=", "path": "golang.org/x/crypto/ed25519", - "revision": "6a293f2d4b14b8e6d3f0539e383f6d0d30fce3fd", - "revisionTime": "2017-09-25T11:22:06Z" + "revision": "ff983b9c42bc9fbf91556e191cc8efb585c16908", + "revisionTime": "2018-07-25T11:53:45Z" }, { - "checksumSHA1": "LXFcVx8I587SnWmKycSDEq9yvK8=", + "checksumSHA1": "0JTAFXPkankmWcZGQJGScLDiaN8=", "path": "golang.org/x/crypto/ed25519/internal/edwards25519", - "revision": "6a293f2d4b14b8e6d3f0539e383f6d0d30fce3fd", - "revisionTime": "2017-09-25T11:22:06Z" + "revision": "ff983b9c42bc9fbf91556e191cc8efb585c16908", + "revisionTime": "2018-07-25T11:53:45Z" }, { - "checksumSHA1": "IIhFTrLlmlc6lEFSitqi4aw2lw0=", + "checksumSHA1": "fhxj9uzosD3dQefNF5JuGJzGZwg=", + "path": "golang.org/x/crypto/internal/chacha20", + "revision": "ff983b9c42bc9fbf91556e191cc8efb585c16908", + "revisionTime": "2018-07-25T11:53:45Z" + }, + { + "checksumSHA1": "/U7f2gaH6DnEmLguVLDbipU6kXU=", + "path": "golang.org/x/crypto/internal/subtle", + "revision": "ff983b9c42bc9fbf91556e191cc8efb585c16908", + "revisionTime": "2018-07-25T11:53:45Z" + }, + { + "checksumSHA1": "M7MQqB1xKzwQh5aEjckVsVCxpoY=", "path": "golang.org/x/crypto/openpgp", - "revision": "6a293f2d4b14b8e6d3f0539e383f6d0d30fce3fd", - "revisionTime": "2017-09-25T11:22:06Z" + "revision": "ff983b9c42bc9fbf91556e191cc8efb585c16908", + "revisionTime": "2018-07-25T11:53:45Z" }, { "checksumSHA1": "olOKkhrdkYQHZ0lf1orrFQPQrv4=", "path": "golang.org/x/crypto/openpgp/armor", - "revision": "6a293f2d4b14b8e6d3f0539e383f6d0d30fce3fd", - "revisionTime": "2017-09-25T11:22:06Z" + "revision": "ff983b9c42bc9fbf91556e191cc8efb585c16908", + "revisionTime": "2018-07-25T11:53:45Z" }, { "checksumSHA1": "eo/KtdjieJQXH7Qy+faXFcF70ME=", "path": "golang.org/x/crypto/openpgp/elgamal", - "revision": "6a293f2d4b14b8e6d3f0539e383f6d0d30fce3fd", - "revisionTime": "2017-09-25T11:22:06Z" + "revision": "ff983b9c42bc9fbf91556e191cc8efb585c16908", + "revisionTime": "2018-07-25T11:53:45Z" }, { "checksumSHA1": "rlxVSaGgqdAgwblsErxTxIfuGfg=", "path": "golang.org/x/crypto/openpgp/errors", - "revision": "6a293f2d4b14b8e6d3f0539e383f6d0d30fce3fd", - "revisionTime": "2017-09-25T11:22:06Z" + "revision": "ff983b9c42bc9fbf91556e191cc8efb585c16908", + "revisionTime": "2018-07-25T11:53:45Z" }, { - "checksumSHA1": "Pq88+Dgh04UdXWZN6P+bLgYnbRc=", + "checksumSHA1": "DwKua4mYaqKBGxCrwgLP2JqkPA0=", "path": "golang.org/x/crypto/openpgp/packet", - "revision": "6a293f2d4b14b8e6d3f0539e383f6d0d30fce3fd", - "revisionTime": "2017-09-25T11:22:06Z" + "revision": "ff983b9c42bc9fbf91556e191cc8efb585c16908", + "revisionTime": "2018-07-25T11:53:45Z" }, { "checksumSHA1": "s2qT4UwvzBSkzXuiuMkowif1Olw=", "path": "golang.org/x/crypto/openpgp/s2k", - "revision": "6a293f2d4b14b8e6d3f0539e383f6d0d30fce3fd", - "revisionTime": "2017-09-25T11:22:06Z" + "revision": "ff983b9c42bc9fbf91556e191cc8efb585c16908", + "revisionTime": "2018-07-25T11:53:45Z" }, { "checksumSHA1": "1MGpGDQqnUoRpv7VEcQrXOBydXE=", "path": "golang.org/x/crypto/pbkdf2", - "revision": "6a293f2d4b14b8e6d3f0539e383f6d0d30fce3fd", - "revisionTime": "2017-09-25T11:22:06Z" + "revision": "ff983b9c42bc9fbf91556e191cc8efb585c16908", + "revisionTime": "2018-07-25T11:53:45Z" }, { - "checksumSHA1": "y/oIaxq2d3WPizRZfVjo8RCRYTU=", + "checksumSHA1": "vKbPb9fpjCdzuoOvajOJnYfHG2g=", + "path": "golang.org/x/crypto/poly1305", + "revision": "ff983b9c42bc9fbf91556e191cc8efb585c16908", + "revisionTime": "2018-07-25T11:53:45Z" + }, + { + "checksumSHA1": "GP0QdBhWPoH4hsHedU7935MjGWo=", "path": "golang.org/x/crypto/ripemd160", - "revision": "6a293f2d4b14b8e6d3f0539e383f6d0d30fce3fd", - "revisionTime": "2017-09-25T11:22:06Z" + "revision": "ff983b9c42bc9fbf91556e191cc8efb585c16908", + "revisionTime": "2018-07-25T11:53:45Z" }, { - "checksumSHA1": "dHh6VeHcbNg11miGjGEl8LbPe7w=", + "checksumSHA1": "q+Rqy6Spw6qDSj75TGEZF7nzoFM=", "path": "golang.org/x/crypto/scrypt", - "revision": "6a293f2d4b14b8e6d3f0539e383f6d0d30fce3fd", - "revisionTime": "2017-09-25T11:22:06Z" + "revision": "ff983b9c42bc9fbf91556e191cc8efb585c16908", + "revisionTime": "2018-07-25T11:53:45Z" }, { - "checksumSHA1": "Wi44TcpIOXdojyVWkvyOBnBKIS4=", + "checksumSHA1": "hUsBzxJ8KTL4v0vpPT/mqvdJ46s=", + "path": "golang.org/x/crypto/sha3", + "revision": "ff983b9c42bc9fbf91556e191cc8efb585c16908", + "revisionTime": "2018-07-25T11:53:45Z" + }, + { + "checksumSHA1": "eMiE+YWT0hJF4B9/hrKHaRp39aU=", "path": "golang.org/x/crypto/ssh", - "revision": "6a293f2d4b14b8e6d3f0539e383f6d0d30fce3fd", - "revisionTime": "2017-09-25T11:22:06Z" + "revision": "ff983b9c42bc9fbf91556e191cc8efb585c16908", + "revisionTime": "2018-07-25T11:53:45Z" }, { - "checksumSHA1": "5Yb2z6UO+Arm/TEd+OEtdnwOt1A=", + "checksumSHA1": "BSPDVKviqHQaG2phOFN690zAKB8=", "path": "golang.org/x/crypto/ssh/terminal", - "revision": "6a293f2d4b14b8e6d3f0539e383f6d0d30fce3fd", - "revisionTime": "2017-09-25T11:22:06Z" + "revision": "ff983b9c42bc9fbf91556e191cc8efb585c16908", + "revisionTime": "2018-07-25T11:53:45Z" }, { "checksumSHA1": "Y+HGqEkYM15ir+J93MEaHdyFy0c=", @@ -579,6 +766,12 @@ "revision": "b4690f45fa1cafc47b1c280c2e75116efe40cc13", "revisionTime": "2017-02-15T08:41:58Z" }, + { + "checksumSHA1": "RcrB7tgYS/GMW4QrwVdMOTNqIU8=", + "path": "golang.org/x/net/idna", + "revision": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec", + "revisionTime": "2018-01-12T01:53:59Z" + }, { "checksumSHA1": "7EZyXN0EmZLgGxZxK01IJua4c8o=", "path": "golang.org/x/net/websocket", @@ -592,16 +785,22 @@ "revisionTime": "2017-05-17T20:25:26Z" }, { - "checksumSHA1": "r1jWq0V3AI5DLN0aCnXXMH/is9Q=", - "path": "golang.org/x/sys/unix", - "revision": "1e2299c37cc91a509f1b12369872d27be0ce98a6", - "revisionTime": "2017-11-09T13:50:42Z" + "checksumSHA1": "2HmF5lkH5eTCChFqqUPKGyZq46o=", + "path": "golang.org/x/sys/cpu", + "revision": "e77772198cdc3dbfcf7f2de96630204df9fd3a0b", + "revisionTime": "2019-02-14T21:28:15Z" }, { - "checksumSHA1": "ck5uxoEeMDUL/QqPvGvBmcbsJzg=", + "checksumSHA1": "k8nyiVwbKd7N/Lo9z85y6v/03NE=", + "path": "golang.org/x/sys/unix", + "revision": "e77772198cdc3dbfcf7f2de96630204df9fd3a0b", + "revisionTime": "2019-02-14T21:28:15Z" + }, + { + "checksumSHA1": "IwB9A6UjgGYrHIBFJEamnrXPeNo=", "path": "golang.org/x/sys/windows", - "revision": "1e2299c37cc91a509f1b12369872d27be0ce98a6", - "revisionTime": "2017-11-09T13:50:42Z" + "revision": "e77772198cdc3dbfcf7f2de96630204df9fd3a0b", + "revisionTime": "2019-02-14T21:28:15Z" }, { "checksumSHA1": "Mr4ur60bgQJnQFfJY0dGtwWwMPE=", @@ -687,6 +886,12 @@ "revision": "85c29909967d7f171f821e7a42e7b7af76fb9598", "revisionTime": "2017-02-11T12:01:23Z" }, + { + "checksumSHA1": "CbpjEkkOeh0fdM/V8xKDdI0AA88=", + "path": "golang.org/x/text/secure/bidirule", + "revision": "e19ae1496984b1c655b8044a65c0300a3c878dd3", + "revisionTime": "2017-12-24T20:31:28Z" + }, { "checksumSHA1": "ziMb9+ANGRJSSIuxYdRbA+cDRBQ=", "path": "golang.org/x/text/transform", @@ -694,14 +899,20 @@ "revisionTime": "2017-02-11T12:01:23Z" }, { - "checksumSHA1": "ikor+YKJu2eKwyFteBWhsb8IGy8=", - "path": "golang.org/x/tools/go/ast/astutil", - "revision": "be0fcc31ae2332374e800dfff29b721c585b35df", - "revisionTime": "2016-11-04T18:56:24Z" + "checksumSHA1": "w8kDfZ1Ug+qAcVU0v8obbu3aDOY=", + "path": "golang.org/x/text/unicode/bidi", + "revision": "e19ae1496984b1c655b8044a65c0300a3c878dd3", + "revisionTime": "2017-12-24T20:31:28Z" }, { - "checksumSHA1": "2ko3hvt1vrfwG+p7SLW+zqDEeV4=", - "path": "golang.org/x/tools/imports", + "checksumSHA1": "BCNYmf4Ek93G4lk5x3ucNi/lTwA=", + "path": "golang.org/x/text/unicode/norm", + "revision": "e19ae1496984b1c655b8044a65c0300a3c878dd3", + "revisionTime": "2017-12-24T20:31:28Z" + }, + { + "checksumSHA1": "ikor+YKJu2eKwyFteBWhsb8IGy8=", + "path": "golang.org/x/tools/go/ast/astutil", "revision": "be0fcc31ae2332374e800dfff29b721c585b35df", "revisionTime": "2016-11-04T18:56:24Z" }, @@ -711,18 +922,6 @@ "revision": "20d25e2804050c1cd24a7eea1e7a6447dd0e74ec", "revisionTime": "2016-12-08T18:13:25Z" }, - { - "checksumSHA1": "NGg7/qIJVUfXi7xnEyyDLocdi6Y=", - "path": "gopkg.in/fatih/set.v0", - "revision": "27c40922c40b43fe04554d8223a402af3ea333f3", - "revisionTime": "2014-12-10T08:48:24Z" - }, - { - "checksumSHA1": "DQXNV0EivoHm4q+bkdahYXrjjfE=", - "path": "gopkg.in/karalabe/cookiejar.v2/collections/prque", - "revision": "8dcd6a7f4951f6ff3ee9cbb919a06d8925822e57", - "revisionTime": "2015-07-24T13:16:13Z" - }, { "checksumSHA1": "0xgs8lwcWLUffemlj+SsgKlxvDU=", "path": "gopkg.in/natefinch/npipe.v2", @@ -730,10 +929,10 @@ "revisionTime": "2016-06-21T03:49:01Z" }, { - "checksumSHA1": "YvuEbc0a032zr+BTp/YbBQojiuY=", + "checksumSHA1": "vndxs5Tv09/8S+Dr2PBAiM557lI=", "path": "gopkg.in/olebedev/go-duktape.v3", - "revision": "9af39127cb024b355a6a0221769f6ddfe3f542e7", - "revisionTime": "2017-12-20T12:19:14Z" + "revision": "abf0ba0be5d5d36b1f9266463cc320b9a5ab224e", + "revisionTime": "2018-03-02T12:15:09Z" }, { "checksumSHA1": "4BwmmgQUhWtizsR2soXND0nqZ1I=", diff --git a/whisper/mailserver/mailserver.go b/whisper/mailserver/mailserver.go index 0ec6ec570c..d7af4baae3 100644 --- a/whisper/mailserver/mailserver.go +++ b/whisper/mailserver/mailserver.go @@ -14,23 +14,24 @@ // 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 ( - "bytes" "encoding/binary" "fmt" - "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" - whisper "github.com/ethereum/go-ethereum/whisper/whisperv5" + 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 @@ -44,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 @@ -55,19 +58,20 @@ func NewDbKey(t uint32, h common.Hash) *DBKey { return &k } -func (s *WMailServer) Init(shh *whisper.Whisper, path string, password string, pow float64) { +// 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 { - utils.Fatalf("DB file is not specified") + return fmt.Errorf("DB file is not specified") } if len(password) == 0 { - utils.Fatalf("Password is not specified for MailServer") + 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 { - utils.Fatalf("Failed to open DB file: %s", err) + return fmt.Errorf("open DB file: %s", err) } s.w = shh @@ -75,20 +79,23 @@ func (s *WMailServer) Init(shh *whisper.Whisper, path string, password string, p MailServerKeyID, err := s.w.AddSymKeyFromPassword(password) if err != nil { - utils.Fatalf("Failed to create symmetric key for MailServer: %s", err) + return fmt.Errorf("create symmetric key: %s", err) } s.key, err = s.w.GetSymKey(MailServerKeyID) if err != nil { - utils.Fatalf("Failed to save symmetric key for MailServer") + return fmt.Errorf("save symmetric key: %s", err) } + 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) @@ -102,25 +109,26 @@ 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") return } - ok, lower, upper, topic := s.validateRequest(peer.ID(), request) + ok, lower, upper, bloom := s.validateRequest(peer.ID(), request) if ok { - s.processRequest(peer, lower, upper, topic) + s.processRequest(peer, lower, upper, bloom) } } -func (s *WMailServer) processRequest(peer *whisper.Peer, lower, upper uint32, topic whisper.TopicType) []*whisper.Envelope { +func (s *WMailServer) processRequest(peer *whisper.Peer, lower, upper uint32, bloom []byte) []*whisper.Envelope { ret := make([]*whisper.Envelope, 0) var err error var zero common.Hash - var empty whisper.TopicType kl := NewDbKey(lower, zero) - ku := NewDbKey(upper, zero) + ku := NewDbKey(upper+1, zero) // LevelDB is exclusive, while the Whisper API is inclusive i := s.db.NewIterator(&util.Range{Start: kl.raw, Limit: ku.raw}, nil) defer i.Release() @@ -131,7 +139,7 @@ func (s *WMailServer) processRequest(peer *whisper.Peer, lower, upper uint32, to log.Error(fmt.Sprintf("RLP decoding failed: %s", err)) } - if topic == empty || envelope.Topic == topic { + if whisper.BloomFilterMatch(bloom, envelope.Bloom()) { if peer == nil { // used for test purposes ret = append(ret, &envelope) @@ -153,39 +161,45 @@ func (s *WMailServer) processRequest(peer *whisper.Peer, lower, upper uint32, to return ret } -func (s *WMailServer) validateRequest(peerID []byte, request *whisper.Envelope) (bool, uint32, uint32, whisper.TopicType) { - var topic whisper.TopicType +func (s *WMailServer) validateRequest(peerID []byte, request *whisper.Envelope) (bool, uint32, uint32, []byte) { if s.pow > 0.0 && request.PoW() < s.pow { - return false, 0, 0, topic + return false, 0, 0, nil } f := whisper.Filter{KeySym: s.key} decrypted := request.Open(&f) if decrypted == nil { log.Warn(fmt.Sprintf("Failed to decrypt p2p request")) - return false, 0, 0, topic - } - - if len(decrypted.Payload) < 8 { - log.Warn(fmt.Sprintf("Undersized p2p request")) - return false, 0, 0, topic + return false, 0, 0, nil } src := crypto.FromECDSAPub(decrypted.Src) if len(src)-len(peerID) == 1 { src = src[1:] } - if !bytes.Equal(peerID, src) { + + // if you want to check the signature, you can do it here. e.g.: + // if !bytes.Equal(peerID, src) { + if src == nil { log.Warn(fmt.Sprintf("Wrong signature of p2p request")) - return false, 0, 0, topic + return false, 0, 0, nil + } + + var bloom []byte + payloadSize := len(decrypted.Payload) + if payloadSize < 8 { + log.Warn(fmt.Sprintf("Undersized p2p request")) + return false, 0, 0, nil + } else if payloadSize == 8 { + bloom = whisper.MakeFullNodeBloom() + } else if payloadSize < 8+whisper.BloomFilterSize { + log.Warn(fmt.Sprintf("Undersized bloom filter in p2p request")) + return false, 0, 0, nil + } else { + bloom = decrypted.Payload[8 : 8+whisper.BloomFilterSize] } lower := binary.BigEndian.Uint32(decrypted.Payload[:4]) upper := binary.BigEndian.Uint32(decrypted.Payload[4:8]) - - if len(decrypted.Payload) >= 8+whisper.TopicLength { - topic = whisper.BytesToTopic(decrypted.Payload[8:]) - } - - return true, lower, upper, topic + return true, lower, upper, bloom } diff --git a/whisper/mailserver/server_test.go b/whisper/mailserver/server_test.go index 9155ee85a6..edb817cc75 100644 --- a/whisper/mailserver/server_test.go +++ b/whisper/mailserver/server_test.go @@ -17,6 +17,7 @@ package mailserver import ( + "bytes" "crypto/ecdsa" "encoding/binary" "io/ioutil" @@ -26,7 +27,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" - whisper "github.com/ethereum/go-ethereum/whisper/whisperv5" + whisper "github.com/ethereum/go-ethereum/whisper/whisperv6" ) const powRequirement = 0.00001 @@ -61,7 +62,7 @@ func generateEnvelope(t *testing.T) *whisper.Envelope { h := crypto.Keccak256Hash([]byte("test sample data")) params := &whisper.MessageParams{ KeySym: h[:], - Topic: whisper.TopicType{}, + Topic: whisper.TopicType{0x1F, 0x7E, 0xA1, 0x7F}, Payload: []byte("test payload"), PoW: powRequirement, WorkTime: 2, @@ -91,7 +92,10 @@ func TestMailServer(t *testing.T) { shh = whisper.New(&whisper.DefaultConfig) shh.RegisterServer(&server) - server.Init(shh, dir, password, powRequirement) + err = server.Init(shh, dir, password, powRequirement) + if err != nil { + t.Fatal(err) + } defer server.Close() keyID, err = shh.AddSymKeyFromPassword(password) @@ -121,6 +125,7 @@ func deliverTest(t *testing.T, server *WMailServer, env *whisper.Envelope) { upp: birth + 1, key: testPeerID, } + singleRequest(t, server, env, p, true) p.low, p.upp = birth+1, 0xffffffff @@ -131,14 +136,14 @@ func deliverTest(t *testing.T, server *WMailServer, env *whisper.Envelope) { p.low = birth - 1 p.upp = birth + 1 - p.topic[0]++ + p.topic[0] = 0xFF singleRequest(t, server, env, p, false) } func singleRequest(t *testing.T, server *WMailServer, env *whisper.Envelope, p *ServerTestParams, expect bool) { request := createRequest(t, p) src := crypto.FromECDSAPub(&p.key.PublicKey) - ok, lower, upper, topic := server.validateRequest(src, request) + ok, lower, upper, bloom := server.validateRequest(src, request) if !ok { t.Fatalf("request validation failed, seed: %d.", seed) } @@ -148,12 +153,13 @@ func singleRequest(t *testing.T, server *WMailServer, env *whisper.Envelope, p * if upper != p.upp { t.Fatalf("request validation failed (upper bound), seed: %d.", seed) } - if topic != p.topic { + expectedBloom := whisper.TopicToBloom(p.topic) + if !bytes.Equal(bloom, expectedBloom) { t.Fatalf("request validation failed (topic), seed: %d.", seed) } var exist bool - mail := server.processRequest(nil, p.low, p.upp, p.topic) + mail := server.processRequest(nil, p.low, p.upp, bloom) for _, msg := range mail { if msg.Hash() == env.Hash() { exist = true @@ -166,17 +172,19 @@ func singleRequest(t *testing.T, server *WMailServer, env *whisper.Envelope, p * } src[0]++ - ok, lower, upper, topic = server.validateRequest(src, request) - if ok { - t.Fatalf("request validation false positive, seed: %d (lower: %d, upper: %d).", seed, lower, upper) + ok, lower, upper, bloom = server.validateRequest(src, request) + if !ok { + // request should be valid regardless of signature + t.Fatalf("request validation false negative, seed: %d (lower: %d, upper: %d).", seed, lower, upper) } } func createRequest(t *testing.T, p *ServerTestParams) *whisper.Envelope { - data := make([]byte, 8+whisper.TopicLength) + bloom := whisper.TopicToBloom(p.topic) + data := make([]byte, 8) binary.BigEndian.PutUint32(data, p.low) binary.BigEndian.PutUint32(data[4:], p.upp) - copy(data[8:], p.topic[:]) + data = append(data, bloom...) key, err := shh.GetSymKey(keyID) if err != nil { diff --git a/whisper/shhclient/client.go b/whisper/shhclient/client.go index 61b4775d95..a814154e47 100644 --- a/whisper/shhclient/client.go +++ b/whisper/shhclient/client.go @@ -22,10 +22,10 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/rpc" - whisper "github.com/ethereum/go-ethereum/whisper/whisperv5" + whisper "github.com/ethereum/go-ethereum/whisper/whisperv6" ) -// Client defines typed wrappers for the Whisper v5 RPC API. +// Client defines typed wrappers for the Whisper v6 RPC API. type Client struct { c *rpc.Client } @@ -67,7 +67,6 @@ func (sc *Client) SetMaxMessageSize(ctx context.Context, size uint32) error { } // SetMinimumPoW (experimental) sets the minimal PoW required by this node. - // This experimental function was introduced for the future dynamic adjustment of // PoW requirement. If the node is overwhelmed with messages, it should raise the // PoW requirement and notify the peers. The new value should be set relative to @@ -77,7 +76,7 @@ func (sc *Client) SetMinimumPoW(ctx context.Context, pow float64) error { return sc.c.CallContext(ctx, &ignored, "shh_setMinPoW", pow) } -// Marks specific peer trusted, which will allow it to send historic (expired) messages. +// MarkTrustedPeer marks specific 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 (sc *Client) MarkTrustedPeer(ctx context.Context, enode string) error { var ignored bool @@ -136,9 +135,9 @@ func (sc *Client) AddSymmetricKey(ctx context.Context, key []byte) (string, erro } // GenerateSymmetricKeyFromPassword generates the key from password, stores it, and returns its identifier. -func (sc *Client) GenerateSymmetricKeyFromPassword(ctx context.Context, passwd []byte) (string, error) { +func (sc *Client) GenerateSymmetricKeyFromPassword(ctx context.Context, passwd string) (string, error) { var id string - return id, sc.c.CallContext(ctx, &id, "shh_generateSymKeyFromPassword", hexutil.Bytes(passwd)) + return id, sc.c.CallContext(ctx, &id, "shh_generateSymKeyFromPassword", passwd) } // HasSymmetricKey returns an indication if the key associated with the given id is stored in the node. @@ -160,35 +159,35 @@ func (sc *Client) DeleteSymmetricKey(ctx context.Context, id string) error { } // Post a message onto the network. -func (sc *Client) Post(ctx context.Context, message whisper.NewMessage) error { - var ignored bool - return sc.c.CallContext(ctx, &ignored, "shh_post", message) +func (sc *Client) Post(ctx context.Context, message whisper.NewMessage) (string, error) { + var hash string + return hash, sc.c.CallContext(ctx, &hash, "shh_post", message) } // SubscribeMessages subscribes to messages that match the given criteria. This method // is only supported on bi-directional connections such as websockets and IPC. // NewMessageFilter uses polling and is supported over HTTP. -func (ec *Client) SubscribeMessages(ctx context.Context, criteria whisper.Criteria, ch chan<- *whisper.Message) (ethereum.Subscription, error) { - return ec.c.ShhSubscribe(ctx, ch, "messages", criteria) +func (sc *Client) SubscribeMessages(ctx context.Context, criteria whisper.Criteria, ch chan<- *whisper.Message) (ethereum.Subscription, error) { + return sc.c.ShhSubscribe(ctx, ch, "messages", criteria) } // NewMessageFilter creates a filter within the node. This filter can be used to poll // for new messages (see FilterMessages) that satisfy the given criteria. A filter can // timeout when it was polled for in whisper.filterTimeout. -func (ec *Client) NewMessageFilter(ctx context.Context, criteria whisper.Criteria) (string, error) { +func (sc *Client) NewMessageFilter(ctx context.Context, criteria whisper.Criteria) (string, error) { var id string - return id, ec.c.CallContext(ctx, &id, "shh_newMessageFilter", criteria) + return id, sc.c.CallContext(ctx, &id, "shh_newMessageFilter", criteria) } // DeleteMessageFilter removes the filter associated with the given id. -func (ec *Client) DeleteMessageFilter(ctx context.Context, id string) error { +func (sc *Client) DeleteMessageFilter(ctx context.Context, id string) error { var ignored bool - return ec.c.CallContext(ctx, &ignored, "shh_deleteMessageFilter", id) + return sc.c.CallContext(ctx, &ignored, "shh_deleteMessageFilter", id) } // FilterMessages retrieves all messages that are received between the last call to // this function and match the criteria that where given when the filter was created. -func (ec *Client) FilterMessages(ctx context.Context, id string) ([]*whisper.Message, error) { +func (sc *Client) FilterMessages(ctx context.Context, id string) ([]*whisper.Message, error) { var messages []*whisper.Message - return messages, ec.c.CallContext(ctx, &messages, "shh_getFilterMessages", id) + return messages, sc.c.CallContext(ctx, &messages, "shh_getFilterMessages", id) } diff --git a/whisper/whisperv2/api.go b/whisper/whisperv2/api.go deleted file mode 100644 index 5c6d170959..0000000000 --- a/whisper/whisperv2/api.go +++ /dev/null @@ -1,402 +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 whisperv2 - -import ( - "encoding/json" - "fmt" - "sync" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/crypto" -) - -// PublicWhisperAPI provides the whisper RPC service. -type PublicWhisperAPI struct { - w *Whisper - - messagesMu sync.RWMutex - messages map[hexutil.Uint]*whisperFilter -} - -type whisperOfflineError struct{} - -func (e *whisperOfflineError) Error() string { - return "whisper is offline" -} - -// whisperOffLineErr is returned when the node doesn't offer the shh service. -var whisperOffLineErr = new(whisperOfflineError) - -// NewPublicWhisperAPI create a new RPC whisper service. -func NewPublicWhisperAPI(w *Whisper) *PublicWhisperAPI { - return &PublicWhisperAPI{w: w, messages: make(map[hexutil.Uint]*whisperFilter)} -} - -// Version returns the Whisper version this node offers. -func (s *PublicWhisperAPI) Version() (hexutil.Uint, error) { - if s.w == nil { - return 0, whisperOffLineErr - } - return hexutil.Uint(s.w.Version()), nil -} - -// HasIdentity checks if the the whisper node is configured with the private key -// of the specified public pair. -func (s *PublicWhisperAPI) HasIdentity(identity string) (bool, error) { - if s.w == nil { - return false, whisperOffLineErr - } - return s.w.HasIdentity(crypto.ToECDSAPub(common.FromHex(identity))), nil -} - -// NewIdentity generates a new cryptographic identity for the client, and injects -// it into the known identities for message decryption. -func (s *PublicWhisperAPI) NewIdentity() (string, error) { - if s.w == nil { - return "", whisperOffLineErr - } - - identity := s.w.NewIdentity() - return common.ToHex(crypto.FromECDSAPub(&identity.PublicKey)), nil -} - -type NewFilterArgs struct { - To string - From string - Topics [][][]byte -} - -// NewWhisperFilter creates and registers a new message filter to watch for inbound whisper messages. -func (s *PublicWhisperAPI) NewFilter(args NewFilterArgs) (hexutil.Uint, error) { - if s.w == nil { - return 0, whisperOffLineErr - } - - var id hexutil.Uint - filter := Filter{ - To: crypto.ToECDSAPub(common.FromHex(args.To)), - From: crypto.ToECDSAPub(common.FromHex(args.From)), - Topics: NewFilterTopics(args.Topics...), - Fn: func(message *Message) { - wmsg := NewWhisperMessage(message) - s.messagesMu.RLock() // Only read lock to the filter pool - defer s.messagesMu.RUnlock() - if s.messages[id] != nil { - s.messages[id].insert(wmsg) - } - }, - } - id = hexutil.Uint(s.w.Watch(filter)) - - s.messagesMu.Lock() - s.messages[id] = newWhisperFilter(id, s.w) - s.messagesMu.Unlock() - - return id, nil -} - -// GetFilterChanges retrieves all the new messages matched by a filter since the last retrieval. -func (s *PublicWhisperAPI) GetFilterChanges(filterId hexutil.Uint) []WhisperMessage { - s.messagesMu.RLock() - defer s.messagesMu.RUnlock() - - if s.messages[filterId] != nil { - if changes := s.messages[filterId].retrieve(); changes != nil { - return changes - } - } - return returnWhisperMessages(nil) -} - -// UninstallFilter disables and removes an existing filter. -func (s *PublicWhisperAPI) UninstallFilter(filterId hexutil.Uint) bool { - s.messagesMu.Lock() - defer s.messagesMu.Unlock() - - if _, ok := s.messages[filterId]; ok { - delete(s.messages, filterId) - return true - } - return false -} - -// GetMessages retrieves all the known messages that match a specific filter. -func (s *PublicWhisperAPI) GetMessages(filterId hexutil.Uint) []WhisperMessage { - // Retrieve all the cached messages matching a specific, existing filter - s.messagesMu.RLock() - defer s.messagesMu.RUnlock() - - var messages []*Message - if s.messages[filterId] != nil { - messages = s.messages[filterId].messages() - } - - return returnWhisperMessages(messages) -} - -// returnWhisperMessages converts aNhisper message to a RPC whisper message. -func returnWhisperMessages(messages []*Message) []WhisperMessage { - msgs := make([]WhisperMessage, len(messages)) - for i, msg := range messages { - msgs[i] = NewWhisperMessage(msg) - } - return msgs -} - -type PostArgs struct { - From string `json:"from"` - To string `json:"to"` - Topics [][]byte `json:"topics"` - Payload string `json:"payload"` - Priority int64 `json:"priority"` - TTL int64 `json:"ttl"` -} - -// Post injects a message into the whisper network for distribution. -func (s *PublicWhisperAPI) Post(args PostArgs) (bool, error) { - if s.w == nil { - return false, whisperOffLineErr - } - - // construct whisper message with transmission options - message := NewMessage(common.FromHex(args.Payload)) - options := Options{ - To: crypto.ToECDSAPub(common.FromHex(args.To)), - TTL: time.Duration(args.TTL) * time.Second, - Topics: NewTopics(args.Topics...), - } - - // set sender identity - if len(args.From) > 0 { - if key := s.w.GetIdentity(crypto.ToECDSAPub(common.FromHex(args.From))); key != nil { - options.From = key - } else { - return false, fmt.Errorf("unknown identity to send from: %s", args.From) - } - } - - // Wrap and send the message - pow := time.Duration(args.Priority) * time.Millisecond - envelope, err := message.Wrap(pow, options) - if err != nil { - return false, err - } - - return true, s.w.Send(envelope) -} - -// WhisperMessage is the RPC representation of a whisper message. -type WhisperMessage struct { - ref *Message - - Payload string `json:"payload"` - To string `json:"to"` - From string `json:"from"` - Sent int64 `json:"sent"` - TTL int64 `json:"ttl"` - Hash string `json:"hash"` -} - -func (args *PostArgs) UnmarshalJSON(data []byte) (err error) { - var obj struct { - From string `json:"from"` - To string `json:"to"` - Topics []string `json:"topics"` - Payload string `json:"payload"` - Priority hexutil.Uint64 `json:"priority"` - TTL hexutil.Uint64 `json:"ttl"` - } - - if err := json.Unmarshal(data, &obj); err != nil { - return err - } - - args.From = obj.From - args.To = obj.To - args.Payload = obj.Payload - args.Priority = int64(obj.Priority) // TODO(gluk256): handle overflow - args.TTL = int64(obj.TTL) // ... here too ... - - // decode topic strings - args.Topics = make([][]byte, len(obj.Topics)) - for i, topic := range obj.Topics { - args.Topics[i] = common.FromHex(topic) - } - - return nil -} - -// UnmarshalJSON implements the json.Unmarshaler interface, invoked to convert a -// JSON message blob into a WhisperFilterArgs structure. -func (args *NewFilterArgs) UnmarshalJSON(b []byte) (err error) { - // Unmarshal the JSON message and sanity check - var obj struct { - To interface{} `json:"to"` - From interface{} `json:"from"` - Topics interface{} `json:"topics"` - } - if err := json.Unmarshal(b, &obj); err != nil { - return err - } - - // Retrieve the simple data contents of the filter arguments - if obj.To == nil { - args.To = "" - } else { - argstr, ok := obj.To.(string) - if !ok { - return fmt.Errorf("to is not a string") - } - args.To = argstr - } - if obj.From == nil { - args.From = "" - } else { - argstr, ok := obj.From.(string) - if !ok { - return fmt.Errorf("from is not a string") - } - args.From = argstr - } - // Construct the nested topic array - if obj.Topics != nil { - // Make sure we have an actual topic array - list, ok := obj.Topics.([]interface{}) - if !ok { - return fmt.Errorf("topics is not an array") - } - // Iterate over each topic and handle nil, string or array - topics := make([][]string, len(list)) - for idx, field := range list { - switch value := field.(type) { - case nil: - topics[idx] = []string{} - - case string: - topics[idx] = []string{value} - - case []interface{}: - topics[idx] = make([]string, len(value)) - for i, nested := range value { - switch value := nested.(type) { - case nil: - topics[idx][i] = "" - - case string: - topics[idx][i] = value - - default: - return fmt.Errorf("topic[%d][%d] is not a string", idx, i) - } - } - default: - return fmt.Errorf("topic[%d] not a string or array", idx) - } - } - - topicsDecoded := make([][][]byte, len(topics)) - for i, condition := range topics { - topicsDecoded[i] = make([][]byte, len(condition)) - for j, topic := range condition { - topicsDecoded[i][j] = common.FromHex(topic) - } - } - - args.Topics = topicsDecoded - } - return nil -} - -// whisperFilter is the message cache matching a specific filter, accumulating -// inbound messages until the are requested by the client. -type whisperFilter struct { - id hexutil.Uint // Filter identifier for old message retrieval - ref *Whisper // Whisper reference for old message retrieval - - cache []WhisperMessage // Cache of messages not yet polled - skip map[common.Hash]struct{} // List of retrieved messages to avoid duplication - update time.Time // Time of the last message query - - lock sync.RWMutex // Lock protecting the filter internals -} - -// messages retrieves all the cached messages from the entire pool matching the -// filter, resetting the filter's change buffer. -func (w *whisperFilter) messages() []*Message { - w.lock.Lock() - defer w.lock.Unlock() - - w.cache = nil - w.update = time.Now() - - w.skip = make(map[common.Hash]struct{}) - messages := w.ref.Messages(int(w.id)) - for _, message := range messages { - w.skip[message.Hash] = struct{}{} - } - return messages -} - -// insert injects a new batch of messages into the filter cache. -func (w *whisperFilter) insert(messages ...WhisperMessage) { - w.lock.Lock() - defer w.lock.Unlock() - - for _, message := range messages { - if _, ok := w.skip[message.ref.Hash]; !ok { - w.cache = append(w.cache, messages...) - } - } -} - -// retrieve fetches all the cached messages from the filter. -func (w *whisperFilter) retrieve() (messages []WhisperMessage) { - w.lock.Lock() - defer w.lock.Unlock() - - messages, w.cache = w.cache, nil - w.update = time.Now() - - return -} - -// newWhisperFilter creates a new serialized, poll based whisper topic filter. -func newWhisperFilter(id hexutil.Uint, ref *Whisper) *whisperFilter { - return &whisperFilter{ - id: id, - ref: ref, - update: time.Now(), - skip: make(map[common.Hash]struct{}), - } -} - -// NewWhisperMessage converts an internal message into an API version. -func NewWhisperMessage(message *Message) WhisperMessage { - return WhisperMessage{ - ref: message, - - Payload: common.ToHex(message.Payload), - From: common.ToHex(crypto.FromECDSAPub(message.Recover())), - To: common.ToHex(crypto.FromECDSAPub(message.To)), - Sent: message.Sent.Unix(), - TTL: int64(message.TTL / time.Second), - Hash: common.ToHex(message.Hash.Bytes()), - } -} diff --git a/whisper/whisperv2/envelope.go b/whisper/whisperv2/envelope.go deleted file mode 100644 index 9f1c682040..0000000000 --- a/whisper/whisperv2/envelope.go +++ /dev/null @@ -1,150 +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 . - -// Contains the Whisper protocol Envelope element. For formal details please see -// the specs at https://github.com/ethereum/wiki/wiki/Whisper-PoC-1-Protocol-Spec#envelopes. - -package whisperv2 - -import ( - "crypto/ecdsa" - "encoding/binary" - "fmt" - "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 { - Expiry uint32 // Whisper protocol specifies int32, really should be int64 - TTL uint32 // ^^^^^^ - Topics []Topic - Data []byte - Nonce uint32 - - hash common.Hash // Cached hash of the envelope to avoid rehashing every time -} - -// NewEnvelope wraps a Whisper message with expiration and destination data -// included into an envelope for network forwarding. -func NewEnvelope(ttl time.Duration, topics []Topic, msg *Message) *Envelope { - return &Envelope{ - Expiry: uint32(time.Now().Add(ttl).Unix()), - TTL: uint32(ttl.Seconds()), - Topics: topics, - Data: msg.bytes(), - Nonce: 0, - } -} - -// Seal closes the envelope by spending the requested amount of time as a proof -// of work on hashing the data. -func (self *Envelope) Seal(pow time.Duration) { - d := make([]byte, 64) - copy(d[:32], self.rlpWithoutNonce()) - - finish, bestBit := time.Now().Add(pow).UnixNano(), 0 - for nonce := uint32(0); time.Now().UnixNano() < finish; { - for i := 0; i < 1024; i++ { - binary.BigEndian.PutUint32(d[60:], nonce) - - d := new(big.Int).SetBytes(crypto.Keccak256(d)) - firstBit := math.FirstBitSet(d) - if firstBit > bestBit { - self.Nonce, bestBit = nonce, firstBit - } - nonce++ - } - } -} - -// rlpWithoutNonce returns the RLP encoded envelope contents, except the nonce. -func (self *Envelope) rlpWithoutNonce() []byte { - enc, _ := rlp.EncodeToBytes([]interface{}{self.Expiry, self.TTL, self.Topics, self.Data}) - return enc -} - -// Open extracts the message contained within a potentially encrypted envelope. -func (self *Envelope) Open(key *ecdsa.PrivateKey) (msg *Message, err error) { - // Split open the payload into a message construct - data := self.Data - - message := &Message{ - Flags: data[0], - Sent: time.Unix(int64(self.Expiry-self.TTL), 0), - TTL: time.Duration(self.TTL) * time.Second, - Hash: self.Hash(), - } - data = data[1:] - - if message.Flags&signatureFlag == signatureFlag { - if len(data) < signatureLength { - return nil, fmt.Errorf("unable to open envelope. First bit set but len(data) < len(signature)") - } - message.Signature, data = data[:signatureLength], data[signatureLength:] - } - message.Payload = data - - // Decrypt the message, if requested - if key == nil { - return message, nil - } - err = message.decrypt(key) - switch err { - case nil: - return message, nil - - case ecies.ErrInvalidPublicKey: // Payload isn't encrypted - return message, err - - default: - return nil, fmt.Errorf("unable to open envelope, decrypt failed: %v", err) - } -} - -// Hash returns the SHA3 hash of the envelope, calculating it if not yet done. -func (self *Envelope) Hash() common.Hash { - if (self.hash == common.Hash{}) { - enc, _ := rlp.EncodeToBytes(self) - self.hash = crypto.Keccak256Hash(enc) - } - return self.hash -} - -// DecodeRLP decodes an Envelope from an RLP data stream. -func (self *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 so we can reuse the Envelope struct definition. - type rlpenv Envelope - if err := rlp.DecodeBytes(raw, (*rlpenv)(self)); err != nil { - return err - } - self.hash = crypto.Keccak256Hash(raw) - return nil -} diff --git a/whisper/whisperv2/envelope_test.go b/whisper/whisperv2/envelope_test.go deleted file mode 100644 index 490ed9f6f8..0000000000 --- a/whisper/whisperv2/envelope_test.go +++ /dev/null @@ -1,158 +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 whisperv2 - -import ( - "bytes" - "testing" - "time" - - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/crypto/ecies" -) - -func TestEnvelopeOpen(t *testing.T) { - payload := []byte("hello world") - message := NewMessage(payload) - - envelope, err := message.Wrap(DefaultPoW, Options{}) - if err != nil { - t.Fatalf("failed to wrap message: %v", err) - } - opened, err := envelope.Open(nil) - if err != nil { - t.Fatalf("failed to open envelope: %v", err) - } - if opened.Flags != message.Flags { - t.Fatalf("flags mismatch: have %d, want %d", opened.Flags, message.Flags) - } - if !bytes.Equal(opened.Signature, message.Signature) { - t.Fatalf("signature mismatch: have 0x%x, want 0x%x", opened.Signature, message.Signature) - } - if !bytes.Equal(opened.Payload, message.Payload) { - t.Fatalf("payload mismatch: have 0x%x, want 0x%x", opened.Payload, message.Payload) - } - if opened.Sent.Unix() != message.Sent.Unix() { - t.Fatalf("send time mismatch: have %v, want %v", opened.Sent, message.Sent) - } - if opened.TTL/time.Second != DefaultTTL/time.Second { - t.Fatalf("message TTL mismatch: have %v, want %v", opened.TTL, DefaultTTL) - } - - if opened.Hash != envelope.Hash() { - t.Fatalf("message hash mismatch: have 0x%x, want 0x%x", opened.Hash, envelope.Hash()) - } -} - -func TestEnvelopeAnonymousOpenUntargeted(t *testing.T) { - payload := []byte("hello envelope") - envelope, err := NewMessage(payload).Wrap(DefaultPoW, Options{}) - if err != nil { - t.Fatalf("failed to wrap message: %v", err) - } - opened, err := envelope.Open(nil) - if err != nil { - t.Fatalf("failed to open envelope: %v", err) - } - if opened.To != nil { - t.Fatalf("recipient mismatch: have 0x%x, want nil", opened.To) - } - if !bytes.Equal(opened.Payload, payload) { - t.Fatalf("payload mismatch: have 0x%x, want 0x%x", opened.Payload, payload) - } -} - -func TestEnvelopeAnonymousOpenTargeted(t *testing.T) { - key, err := crypto.GenerateKey() - if err != nil { - t.Fatalf("failed to generate test identity: %v", err) - } - - payload := []byte("hello envelope") - envelope, err := NewMessage(payload).Wrap(DefaultPoW, Options{ - To: &key.PublicKey, - }) - if err != nil { - t.Fatalf("failed to wrap message: %v", err) - } - opened, err := envelope.Open(nil) - if err != nil { - t.Fatalf("failed to open envelope: %v", err) - } - if opened.To != nil { - t.Fatalf("recipient mismatch: have 0x%x, want nil", opened.To) - } - if bytes.Equal(opened.Payload, payload) { - t.Fatalf("payload match, should have been encrypted: 0x%x", opened.Payload) - } -} - -func TestEnvelopeIdentifiedOpenUntargeted(t *testing.T) { - key, err := crypto.GenerateKey() - if err != nil { - t.Fatalf("failed to generate test identity: %v", err) - } - - payload := []byte("hello envelope") - envelope, err := NewMessage(payload).Wrap(DefaultPoW, Options{}) - if err != nil { - t.Fatalf("failed to wrap message: %v", err) - } - opened, err := envelope.Open(key) - switch err { - case nil: - t.Fatalf("envelope opened with bad key: %v", opened) - - case ecies.ErrInvalidPublicKey: - // Ok, key mismatch but opened - - default: - t.Fatalf("failed to open envelope: %v", err) - } - - if opened.To != nil { - t.Fatalf("recipient mismatch: have 0x%x, want nil", opened.To) - } - if !bytes.Equal(opened.Payload, payload) { - t.Fatalf("payload mismatch: have 0x%x, want 0x%x", opened.Payload, payload) - } -} - -func TestEnvelopeIdentifiedOpenTargeted(t *testing.T) { - key, err := crypto.GenerateKey() - if err != nil { - t.Fatalf("failed to generate test identity: %v", err) - } - - payload := []byte("hello envelope") - envelope, err := NewMessage(payload).Wrap(DefaultPoW, Options{ - To: &key.PublicKey, - }) - if err != nil { - t.Fatalf("failed to wrap message: %v", err) - } - opened, err := envelope.Open(key) - if err != nil { - t.Fatalf("failed to open envelope: %v", err) - } - if opened.To != nil { - t.Fatalf("recipient mismatch: have 0x%x, want nil", opened.To) - } - if !bytes.Equal(opened.Payload, payload) { - t.Fatalf("payload mismatch: have 0x%x, want 0x%x", opened.Payload, payload) - } -} diff --git a/whisper/whisperv2/filter.go b/whisper/whisperv2/filter.go deleted file mode 100644 index 7404859b78..0000000000 --- a/whisper/whisperv2/filter.go +++ /dev/null @@ -1,129 +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 . - -// Contains the message filter for fine grained subscriptions. - -package whisperv2 - -import ( - "crypto/ecdsa" - - "github.com/ethereum/go-ethereum/event/filter" -) - -// Filter is used to subscribe to specific types of whisper messages. -type Filter struct { - To *ecdsa.PublicKey // Recipient of the message - From *ecdsa.PublicKey // Sender of the message - Topics [][]Topic // Topics to filter messages with - Fn func(msg *Message) // Handler in case of a match -} - -// NewFilterTopics creates a 2D topic array used by whisper.Filter from binary -// data elements. -func NewFilterTopics(data ...[][]byte) [][]Topic { - filter := make([][]Topic, len(data)) - for i, condition := range data { - // Handle the special case of condition == [[]byte{}] - if len(condition) == 1 && len(condition[0]) == 0 { - filter[i] = []Topic{} - continue - } - // Otherwise flatten normally - filter[i] = NewTopics(condition...) - } - return filter -} - -// NewFilterTopicsFlat creates a 2D topic array used by whisper.Filter from flat -// binary data elements. -func NewFilterTopicsFlat(data ...[]byte) [][]Topic { - filter := make([][]Topic, len(data)) - for i, element := range data { - // Only add non-wildcard topics - filter[i] = make([]Topic, 0, 1) - if len(element) > 0 { - filter[i] = append(filter[i], NewTopic(element)) - } - } - return filter -} - -// NewFilterTopicsFromStrings creates a 2D topic array used by whisper.Filter -// from textual data elements. -func NewFilterTopicsFromStrings(data ...[]string) [][]Topic { - filter := make([][]Topic, len(data)) - for i, condition := range data { - // Handle the special case of condition == [""] - if len(condition) == 1 && condition[0] == "" { - filter[i] = []Topic{} - continue - } - // Otherwise flatten normally - filter[i] = NewTopicsFromStrings(condition...) - } - return filter -} - -// NewFilterTopicsFromStringsFlat creates a 2D topic array used by whisper.Filter from flat -// binary data elements. -func NewFilterTopicsFromStringsFlat(data ...string) [][]Topic { - filter := make([][]Topic, len(data)) - for i, element := range data { - // Only add non-wildcard topics - filter[i] = make([]Topic, 0, 1) - if element != "" { - filter[i] = append(filter[i], NewTopicFromString(element)) - } - } - return filter -} - -// filterer is the internal, fully initialized filter ready to match inbound -// messages to a variety of criteria. -type filterer struct { - to string // Recipient of the message - from string // Sender of the message - matcher *topicMatcher // Topics to filter messages with - fn func(data interface{}) // Handler in case of a match -} - -// Compare checks if the specified filter matches the current one. -func (self filterer) Compare(f filter.Filter) bool { - filter := f.(filterer) - - // Check the message sender and recipient - if len(self.to) > 0 && self.to != filter.to { - return false - } - if len(self.from) > 0 && self.from != filter.from { - return false - } - // Check the topic filtering - topics := make([]Topic, len(filter.matcher.conditions)) - for i, group := range filter.matcher.conditions { - // Message should contain a single topic entry, extract - for topics[i] = range group { - break - } - } - return self.matcher.Matches(topics) -} - -// Trigger is called when a filter successfully matches an inbound message. -func (self filterer) Trigger(data interface{}) { - self.fn(data) -} diff --git a/whisper/whisperv2/filter_test.go b/whisper/whisperv2/filter_test.go deleted file mode 100644 index ffdfd7b349..0000000000 --- a/whisper/whisperv2/filter_test.go +++ /dev/null @@ -1,215 +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 whisperv2 - -import ( - "bytes" - - "testing" -) - -var filterTopicsCreationTests = []struct { - topics [][]string - filter [][][4]byte -}{ - { // Simple topic filter - topics: [][]string{ - {"abc", "def", "ghi"}, - {"def"}, - {"ghi", "abc"}, - }, - filter: [][][4]byte{ - {{0x4e, 0x03, 0x65, 0x7a}, {0x34, 0x60, 0x7c, 0x9b}, {0x21, 0x41, 0x7d, 0xf9}}, - {{0x34, 0x60, 0x7c, 0x9b}}, - {{0x21, 0x41, 0x7d, 0xf9}, {0x4e, 0x03, 0x65, 0x7a}}, - }, - }, - { // Wild-carded topic filter - topics: [][]string{ - {"abc", "def", "ghi"}, - {}, - {""}, - {"def"}, - }, - filter: [][][4]byte{ - {{0x4e, 0x03, 0x65, 0x7a}, {0x34, 0x60, 0x7c, 0x9b}, {0x21, 0x41, 0x7d, 0xf9}}, - {}, - {}, - {{0x34, 0x60, 0x7c, 0x9b}}, - }, - }, -} - -var filterTopicsCreationFlatTests = []struct { - topics []string - filter [][][4]byte -}{ - { // Simple topic list - topics: []string{"abc", "def", "ghi"}, - filter: [][][4]byte{ - {{0x4e, 0x03, 0x65, 0x7a}}, - {{0x34, 0x60, 0x7c, 0x9b}}, - {{0x21, 0x41, 0x7d, 0xf9}}, - }, - }, - { // Wild-carded topic list - topics: []string{"abc", "", "ghi"}, - filter: [][][4]byte{ - {{0x4e, 0x03, 0x65, 0x7a}}, - {}, - {{0x21, 0x41, 0x7d, 0xf9}}, - }, - }, -} - -func TestFilterTopicsCreation(t *testing.T) { - // Check full filter creation - for i, tt := range filterTopicsCreationTests { - // Check the textual creation - filter := NewFilterTopicsFromStrings(tt.topics...) - if len(filter) != len(tt.topics) { - t.Errorf("test %d: condition count mismatch: have %v, want %v", i, len(filter), len(tt.topics)) - continue - } - for j, condition := range filter { - if len(condition) != len(tt.filter[j]) { - t.Errorf("test %d, condition %d: size mismatch: have %v, want %v", i, j, len(condition), len(tt.filter[j])) - continue - } - for k := 0; k < len(condition); k++ { - if !bytes.Equal(condition[k][:], tt.filter[j][k][:]) { - t.Errorf("test %d, condition %d, segment %d: filter mismatch: have 0x%x, want 0x%x", i, j, k, condition[k], tt.filter[j][k]) - } - } - } - // Check the binary creation - binary := make([][][]byte, len(tt.topics)) - for j, condition := range tt.topics { - binary[j] = make([][]byte, len(condition)) - for k, segment := range condition { - binary[j][k] = []byte(segment) - } - } - filter = NewFilterTopics(binary...) - if len(filter) != len(tt.topics) { - t.Errorf("test %d: condition count mismatch: have %v, want %v", i, len(filter), len(tt.topics)) - continue - } - for j, condition := range filter { - if len(condition) != len(tt.filter[j]) { - t.Errorf("test %d, condition %d: size mismatch: have %v, want %v", i, j, len(condition), len(tt.filter[j])) - continue - } - for k := 0; k < len(condition); k++ { - if !bytes.Equal(condition[k][:], tt.filter[j][k][:]) { - t.Errorf("test %d, condition %d, segment %d: filter mismatch: have 0x%x, want 0x%x", i, j, k, condition[k], tt.filter[j][k]) - } - } - } - } - // Check flat filter creation - for i, tt := range filterTopicsCreationFlatTests { - // Check the textual creation - filter := NewFilterTopicsFromStringsFlat(tt.topics...) - if len(filter) != len(tt.topics) { - t.Errorf("test %d: condition count mismatch: have %v, want %v", i, len(filter), len(tt.topics)) - continue - } - for j, condition := range filter { - if len(condition) != len(tt.filter[j]) { - t.Errorf("test %d, condition %d: size mismatch: have %v, want %v", i, j, len(condition), len(tt.filter[j])) - continue - } - for k := 0; k < len(condition); k++ { - if !bytes.Equal(condition[k][:], tt.filter[j][k][:]) { - t.Errorf("test %d, condition %d, segment %d: filter mismatch: have 0x%x, want 0x%x", i, j, k, condition[k], tt.filter[j][k]) - } - } - } - // Check the binary creation - binary := make([][]byte, len(tt.topics)) - for j, topic := range tt.topics { - binary[j] = []byte(topic) - } - filter = NewFilterTopicsFlat(binary...) - if len(filter) != len(tt.topics) { - t.Errorf("test %d: condition count mismatch: have %v, want %v", i, len(filter), len(tt.topics)) - continue - } - for j, condition := range filter { - if len(condition) != len(tt.filter[j]) { - t.Errorf("test %d, condition %d: size mismatch: have %v, want %v", i, j, len(condition), len(tt.filter[j])) - continue - } - for k := 0; k < len(condition); k++ { - if !bytes.Equal(condition[k][:], tt.filter[j][k][:]) { - t.Errorf("test %d, condition %d, segment %d: filter mismatch: have 0x%x, want 0x%x", i, j, k, condition[k], tt.filter[j][k]) - } - } - } - } -} - -var filterCompareTests = []struct { - matcher filterer - message filterer - match bool -}{ - { // Wild-card filter matching anything - matcher: filterer{to: "", from: "", matcher: newTopicMatcher()}, - message: filterer{to: "to", from: "from", matcher: newTopicMatcher(NewFilterTopicsFromStringsFlat("topic")...)}, - match: true, - }, - { // Filter matching the to field - matcher: filterer{to: "to", from: "", matcher: newTopicMatcher()}, - message: filterer{to: "to", from: "from", matcher: newTopicMatcher(NewFilterTopicsFromStringsFlat("topic")...)}, - match: true, - }, - { // Filter rejecting the to field - matcher: filterer{to: "to", from: "", matcher: newTopicMatcher()}, - message: filterer{to: "", from: "from", matcher: newTopicMatcher(NewFilterTopicsFromStringsFlat("topic")...)}, - match: false, - }, - { // Filter matching the from field - matcher: filterer{to: "", from: "from", matcher: newTopicMatcher()}, - message: filterer{to: "to", from: "from", matcher: newTopicMatcher(NewFilterTopicsFromStringsFlat("topic")...)}, - match: true, - }, - { // Filter rejecting the from field - matcher: filterer{to: "", from: "from", matcher: newTopicMatcher()}, - message: filterer{to: "to", from: "", matcher: newTopicMatcher(NewFilterTopicsFromStringsFlat("topic")...)}, - match: false, - }, - { // Filter matching the topic field - matcher: filterer{to: "", from: "from", matcher: newTopicMatcher(NewFilterTopicsFromStringsFlat("topic")...)}, - message: filterer{to: "to", from: "from", matcher: newTopicMatcher(NewFilterTopicsFromStringsFlat("topic")...)}, - match: true, - }, - { // Filter rejecting the topic field - matcher: filterer{to: "", from: "", matcher: newTopicMatcher(NewFilterTopicsFromStringsFlat("topic")...)}, - message: filterer{to: "to", from: "from", matcher: newTopicMatcher()}, - match: false, - }, -} - -func TestFilterCompare(t *testing.T) { - for i, tt := range filterCompareTests { - if match := tt.matcher.Compare(tt.message); match != tt.match { - t.Errorf("test %d: match mismatch: have %v, want %v", i, match, tt.match) - } - } -} diff --git a/whisper/whisperv2/main.go b/whisper/whisperv2/main.go deleted file mode 100644 index be41604890..0000000000 --- a/whisper/whisperv2/main.go +++ /dev/null @@ -1,106 +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 none - -// Contains a simple whisper peer setup and self messaging to allow playing -// around with the protocol and API without a fancy client implementation. - -package main - -import ( - "fmt" - "log" - "os" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/logger" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/nat" - "github.com/ethereum/go-ethereum/whisper" -) - -func main() { - logger.AddLogSystem(logger.NewStdLogSystem(os.Stdout, log.LstdFlags, logger.InfoLevel)) - - // Generate the peer identity - key, err := crypto.GenerateKey() - if err != nil { - fmt.Printf("Failed to generate peer key: %v.\n", err) - os.Exit(-1) - } - name := common.MakeName("whisper-go", "1.0") - shh := whisper.New() - - // Create an Ethereum peer to communicate through - server := p2p.Server{ - PrivateKey: key, - MaxPeers: 10, - Name: name, - Protocols: []p2p.Protocol{shh.Protocol()}, - ListenAddr: ":30300", - NAT: nat.Any(), - } - fmt.Println("Starting Ethereum peer...") - if err := server.Start(); err != nil { - fmt.Printf("Failed to start Ethereum peer: %v.\n", err) - os.Exit(1) - } - - // Send a message to self to check that something works - payload := fmt.Sprintf("Hello world, this is %v. In case you're wondering, the time is %v", name, time.Now()) - if err := selfSend(shh, []byte(payload)); err != nil { - fmt.Printf("Failed to self message: %v.\n", err) - os.Exit(-1) - } -} - -// SendSelf wraps a payload into a Whisper envelope and forwards it to itself. -func selfSend(shh *whisper.Whisper, payload []byte) error { - ok := make(chan struct{}) - - // Start watching for self messages, output any arrivals - id := shh.NewIdentity() - shh.Watch(whisper.Filter{ - To: &id.PublicKey, - Fn: func(msg *whisper.Message) { - fmt.Printf("Message received: %s, signed with 0x%x.\n", string(msg.Payload), msg.Signature) - close(ok) - }, - }) - // Wrap the payload and encrypt it - msg := whisper.NewMessage(payload) - envelope, err := msg.Wrap(whisper.DefaultPoW, whisper.Options{ - From: id, - To: &id.PublicKey, - TTL: whisper.DefaultTTL, - }) - if err != nil { - return fmt.Errorf("failed to seal message: %v", err) - } - // Dump the message into the system and wait for it to pop back out - if err := shh.Send(envelope); err != nil { - return fmt.Errorf("failed to send self-message: %v", err) - } - select { - case <-ok: - case <-time.After(time.Second): - return fmt.Errorf("failed to receive message in time") - } - return nil -} diff --git a/whisper/whisperv2/message.go b/whisper/whisperv2/message.go deleted file mode 100644 index 66648c3be8..0000000000 --- a/whisper/whisperv2/message.go +++ /dev/null @@ -1,158 +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 . - -// Contains the Whisper protocol Message element. For formal details please see -// the specs at https://github.com/ethereum/wiki/wiki/Whisper-PoC-1-Protocol-Spec#messages. - -package whisperv2 - -import ( - "crypto/ecdsa" - crand "crypto/rand" - "fmt" - "math/rand" - "time" - - "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" -) - -// Message 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 Message struct { - Flags byte // First bit is signature presence, rest reserved and should be random - Signature []byte - Payload []byte - - Sent time.Time // Time when the message was posted into the network - TTL time.Duration // Maximum time to live allowed for the message - - To *ecdsa.PublicKey // Message recipient (identity used to decode the message) - Hash common.Hash // Message envelope hash to act as a unique id -} - -// Options specifies the exact way a message should be wrapped into an Envelope. -type Options struct { - From *ecdsa.PrivateKey - To *ecdsa.PublicKey - TTL time.Duration - Topics []Topic -} - -// NewMessage creates and initializes a non-signed, non-encrypted Whisper message. -func NewMessage(payload []byte) *Message { - // Construct an initial flag set: no signature, rest random - flags := byte(rand.Intn(256)) - flags &= ^signatureFlag - - // Assemble and return the message - return &Message{ - Flags: flags, - Payload: payload, - Sent: time.Now(), - } -} - -// Wrap bundles the message into an Envelope to transmit over the network. -// -// pow (Proof Of Work) controls how much time to spend on hashing the message, -// inherently controlling its priority through the network (smaller hash, bigger -// priority). -// -// The user can control the amount of identity, privacy and encryption through -// the options parameter as follows: -// - options.From == nil && options.To == nil: anonymous broadcast -// - options.From != nil && options.To == nil: signed broadcast (known sender) -// - options.From == nil && options.To != nil: encrypted anonymous message -// - options.From != nil && options.To != nil: encrypted signed message -func (self *Message) Wrap(pow time.Duration, options Options) (*Envelope, error) { - // Use the default TTL if non was specified - if options.TTL == 0 { - options.TTL = DefaultTTL - } - self.TTL = options.TTL - - // Sign and encrypt the message if requested - if options.From != nil { - if err := self.sign(options.From); err != nil { - return nil, err - } - } - if options.To != nil { - if err := self.encrypt(options.To); err != nil { - return nil, err - } - } - // Wrap the processed message, seal it and return - envelope := NewEnvelope(options.TTL, options.Topics, self) - envelope.Seal(pow) - - return envelope, nil -} - -// sign calculates and sets the cryptographic signature for the message , also -// setting the sign flag. -func (self *Message) sign(key *ecdsa.PrivateKey) (err error) { - self.Flags |= signatureFlag - self.Signature, err = crypto.Sign(self.hash(), key) - return -} - -// Recover retrieves the public key of the message signer. -func (self *Message) Recover() *ecdsa.PublicKey { - defer func() { recover() }() // in case of invalid signature - - // Short circuit if no signature is present - if self.Signature == nil { - return nil - } - // Otherwise try and recover the signature - pub, err := crypto.SigToPub(self.hash(), self.Signature) - if err != nil { - log.Error(fmt.Sprintf("Could not get public key from signature: %v", err)) - return nil - } - return pub -} - -// encrypt encrypts a message payload with a public key. -func (self *Message) encrypt(key *ecdsa.PublicKey) (err error) { - self.Payload, err = ecies.Encrypt(crand.Reader, ecies.ImportECDSAPublic(key), self.Payload, nil, nil) - return -} - -// decrypt decrypts an encrypted payload with a private key. -func (self *Message) decrypt(key *ecdsa.PrivateKey) error { - cleartext, err := ecies.ImportECDSA(key).Decrypt(crand.Reader, self.Payload, nil, nil) - if err == nil { - self.Payload = cleartext - } - return err -} - -// hash calculates the SHA3 checksum of the message flags and payload. -func (self *Message) hash() []byte { - return crypto.Keccak256(append([]byte{self.Flags}, self.Payload...)) -} - -// bytes flattens the message contents (flags, signature and payload) into a -// single binary blob. -func (self *Message) bytes() []byte { - return append([]byte{self.Flags}, append(self.Signature, self.Payload...)...) -} diff --git a/whisper/whisperv2/message_test.go b/whisper/whisperv2/message_test.go deleted file mode 100644 index c760ac54c4..0000000000 --- a/whisper/whisperv2/message_test.go +++ /dev/null @@ -1,158 +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 whisperv2 - -import ( - "bytes" - "crypto/elliptic" - "testing" - "time" - - "github.com/ethereum/go-ethereum/crypto" -) - -// Tests whether a message can be wrapped without any identity or encryption. -func TestMessageSimpleWrap(t *testing.T) { - payload := []byte("hello world") - - msg := NewMessage(payload) - if _, err := msg.Wrap(DefaultPoW, Options{}); err != nil { - t.Fatalf("failed to wrap message: %v", err) - } - if msg.Flags&signatureFlag != 0 { - t.Fatalf("signature flag mismatch: have %d, want %d", msg.Flags&signatureFlag, 0) - } - if len(msg.Signature) != 0 { - t.Fatalf("signature found for simple wrapping: 0x%x", msg.Signature) - } - if !bytes.Equal(msg.Payload, payload) { - t.Fatalf("payload mismatch after wrapping: have 0x%x, want 0x%x", msg.Payload, payload) - } - if msg.TTL/time.Second != DefaultTTL/time.Second { - t.Fatalf("message TTL mismatch: have %v, want %v", msg.TTL, DefaultTTL) - } -} - -// Tests whether a message can be signed, and wrapped in plain-text. -func TestMessageCleartextSignRecover(t *testing.T) { - key, err := crypto.GenerateKey() - if err != nil { - t.Fatalf("failed to create crypto key: %v", err) - } - payload := []byte("hello world") - - msg := NewMessage(payload) - if _, err := msg.Wrap(DefaultPoW, Options{ - From: key, - }); err != nil { - t.Fatalf("failed to sign message: %v", err) - } - if msg.Flags&signatureFlag != signatureFlag { - t.Fatalf("signature flag mismatch: have %d, want %d", msg.Flags&signatureFlag, signatureFlag) - } - if !bytes.Equal(msg.Payload, payload) { - t.Fatalf("payload mismatch after signing: have 0x%x, want 0x%x", msg.Payload, payload) - } - - pubKey := msg.Recover() - if pubKey == nil { - t.Fatalf("failed to recover public key") - } - p1 := elliptic.Marshal(crypto.S256(), key.PublicKey.X, key.PublicKey.Y) - p2 := elliptic.Marshal(crypto.S256(), pubKey.X, pubKey.Y) - if !bytes.Equal(p1, p2) { - t.Fatalf("public key mismatch: have 0x%x, want 0x%x", p2, p1) - } -} - -// Tests whether a message can be encrypted and decrypted using an anonymous -// sender (i.e. no signature). -func TestMessageAnonymousEncryptDecrypt(t *testing.T) { - key, err := crypto.GenerateKey() - if err != nil { - t.Fatalf("failed to create recipient crypto key: %v", err) - } - payload := []byte("hello world") - - msg := NewMessage(payload) - envelope, err := msg.Wrap(DefaultPoW, Options{ - To: &key.PublicKey, - }) - if err != nil { - t.Fatalf("failed to encrypt message: %v", err) - } - if msg.Flags&signatureFlag != 0 { - t.Fatalf("signature flag mismatch: have %d, want %d", msg.Flags&signatureFlag, 0) - } - if len(msg.Signature) != 0 { - t.Fatalf("signature found for anonymous message: 0x%x", msg.Signature) - } - - out, err := envelope.Open(key) - if err != nil { - t.Fatalf("failed to open encrypted message: %v", err) - } - if !bytes.Equal(out.Payload, payload) { - t.Errorf("payload mismatch: have 0x%x, want 0x%x", out.Payload, payload) - } -} - -// Tests whether a message can be properly signed and encrypted. -func TestMessageFullCrypto(t *testing.T) { - fromKey, err := crypto.GenerateKey() - if err != nil { - t.Fatalf("failed to create sender crypto key: %v", err) - } - toKey, err := crypto.GenerateKey() - if err != nil { - t.Fatalf("failed to create recipient crypto key: %v", err) - } - - payload := []byte("hello world") - msg := NewMessage(payload) - envelope, err := msg.Wrap(DefaultPoW, Options{ - From: fromKey, - To: &toKey.PublicKey, - }) - if err != nil { - t.Fatalf("failed to encrypt message: %v", err) - } - if msg.Flags&signatureFlag != signatureFlag { - t.Fatalf("signature flag mismatch: have %d, want %d", msg.Flags&signatureFlag, signatureFlag) - } - if len(msg.Signature) == 0 { - t.Fatalf("no signature found for signed message") - } - - out, err := envelope.Open(toKey) - if err != nil { - t.Fatalf("failed to open encrypted message: %v", err) - } - if !bytes.Equal(out.Payload, payload) { - t.Errorf("payload mismatch: have 0x%x, want 0x%x", out.Payload, payload) - } - - pubKey := out.Recover() - if pubKey == nil { - t.Fatalf("failed to recover public key") - } - p1 := elliptic.Marshal(crypto.S256(), fromKey.PublicKey.X, fromKey.PublicKey.Y) - p2 := elliptic.Marshal(crypto.S256(), pubKey.X, pubKey.Y) - if !bytes.Equal(p1, p2) { - t.Fatalf("public key mismatch: have 0x%x, want 0x%x", p2, p1) - } -} diff --git a/whisper/whisperv2/peer.go b/whisper/whisperv2/peer.go deleted file mode 100644 index 71798408b9..0000000000 --- a/whisper/whisperv2/peer.go +++ /dev/null @@ -1,174 +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 whisperv2 - -import ( - "fmt" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/rlp" - "gopkg.in/fatih/set.v0" -) - -// peer represents a whisper protocol peer connection. -type peer struct { - host *Whisper - peer *p2p.Peer - ws p2p.MsgReadWriter - - known *set.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, - known: set.New(), - quit: make(chan struct{}), - } -} - -// start initiates the peer updater, periodically broadcasting the whisper packets -// into the network. -func (self *peer) start() { - go self.update() - log.Debug(fmt.Sprintf("%v: whisper started", self.peer)) -} - -// stop terminates the peer updater, stopping message forwarding to it. -func (self *peer) stop() { - close(self.quit) - log.Debug(fmt.Sprintf("%v: whisper stopped", self.peer)) -} - -// handshake sends the protocol initiation status message to the remote peer and -// verifies the remote status too. -func (self *peer) handshake() error { - // Send the handshake status message asynchronously - errc := make(chan error, 1) - go func() { - errc <- p2p.SendItems(self.ws, statusCode, protocolVersion) - }() - // Fetch the remote status packet and verify protocol match - packet, err := self.ws.ReadMsg() - if err != nil { - return err - } - if packet.Code != statusCode { - return fmt.Errorf("peer sent %x before status packet", packet.Code) - } - s := rlp.NewStream(packet.Payload, uint64(packet.Size)) - if _, err := s.List(); err != nil { - return fmt.Errorf("bad status message: %v", err) - } - peerVersion, err := s.Uint() - if err != nil { - return fmt.Errorf("bad status message: %v", err) - } - if peerVersion != protocolVersion { - return fmt.Errorf("protocol version mismatch %d != %d", peerVersion, protocolVersion) - } - // Wait until out own status is consumed too - if err := <-errc; err != nil { - return fmt.Errorf("failed to send status packet: %v", err) - } - return nil -} - -// update executes periodic operations on the peer, including message transmission -// and expiration. -func (self *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: - self.expire() - - case <-transmit.C: - if err := self.broadcast(); err != nil { - log.Info(fmt.Sprintf("%v: broadcast failed: %v", self.peer, err)) - return - } - - case <-self.quit: - return - } - } -} - -// mark marks an envelope known to the peer so that it won't be sent back. -func (self *peer) mark(envelope *Envelope) { - self.known.Add(envelope.Hash()) -} - -// marked checks if an envelope is already known to the remote peer. -func (self *peer) marked(envelope *Envelope) bool { - return self.known.Has(envelope.Hash()) -} - -// expire iterates over all the known envelopes in the host and removes all -// expired (unknown) ones from the known list. -func (self *peer) expire() { - // Assemble the list of available envelopes - available := set.NewNonTS() - for _, envelope := range self.host.envelopes() { - available.Add(envelope.Hash()) - } - // Cross reference availability with known status - unmark := make(map[common.Hash]struct{}) - self.known.Each(func(v interface{}) bool { - if !available.Has(v.(common.Hash)) { - unmark[v.(common.Hash)] = struct{}{} - } - return true - }) - // Dump all known but unavailable - for hash := range unmark { - self.known.Remove(hash) - } -} - -// broadcast iterates over the collection of envelopes and transmits yet unknown -// ones over the network. -func (self *peer) broadcast() error { - // Fetch the envelopes and collect the unknown ones - envelopes := self.host.envelopes() - transmit := make([]*Envelope, 0, len(envelopes)) - for _, envelope := range envelopes { - if !self.marked(envelope) { - transmit = append(transmit, envelope) - self.mark(envelope) - } - } - // Transmit the unknown batch (potentially empty) - if err := p2p.Send(self.ws, messagesCode, transmit); err != nil { - return err - } - log.Trace(fmt.Sprint(self.peer, "broadcasted", len(transmit), "message(s)")) - return nil -} diff --git a/whisper/whisperv2/peer_test.go b/whisper/whisperv2/peer_test.go deleted file mode 100644 index 87ca5063df..0000000000 --- a/whisper/whisperv2/peer_test.go +++ /dev/null @@ -1,261 +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 whisperv2 - -import ( - "testing" - "time" - - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/discover" -) - -type testPeer struct { - client *Whisper - stream *p2p.MsgPipeRW - termed chan struct{} -} - -func startTestPeer() *testPeer { - // Create a simulated P2P remote peer and data streams to it - remote := p2p.NewPeer(discover.NodeID{}, "", nil) - tester, tested := p2p.MsgPipe() - - // Create a whisper client and connect with it to the tester peer - client := New() - client.Start(nil) - - termed := make(chan struct{}) - go func() { - defer client.Stop() - defer close(termed) - defer tested.Close() - - client.handlePeer(remote, tested) - }() - - return &testPeer{ - client: client, - stream: tester, - termed: termed, - } -} - -func startTestPeerInited() (*testPeer, error) { - peer := startTestPeer() - - if err := p2p.ExpectMsg(peer.stream, statusCode, []uint64{protocolVersion}); err != nil { - peer.stream.Close() - return nil, err - } - if err := p2p.SendItems(peer.stream, statusCode, protocolVersion); err != nil { - peer.stream.Close() - return nil, err - } - return peer, nil -} - -func TestPeerStatusMessage(t *testing.T) { - tester := startTestPeer() - - // Wait for the handshake status message and check it - if err := p2p.ExpectMsg(tester.stream, statusCode, []uint64{protocolVersion}); err != nil { - t.Fatalf("status message mismatch: %v", err) - } - // Terminate the node - tester.stream.Close() - - select { - case <-tester.termed: - case <-time.After(time.Second): - t.Fatalf("local close timed out") - } -} - -func TestPeerHandshakeFail(t *testing.T) { - tester := startTestPeer() - - // Wait for and check the handshake - if err := p2p.ExpectMsg(tester.stream, statusCode, []uint64{protocolVersion}); err != nil { - t.Fatalf("status message mismatch: %v", err) - } - // Send an invalid handshake status and verify disconnect - if err := p2p.SendItems(tester.stream, messagesCode); err != nil { - t.Fatalf("failed to send malformed status: %v", err) - } - select { - case <-tester.termed: - case <-time.After(time.Second): - t.Fatalf("remote close timed out") - } -} - -func TestPeerHandshakeSuccess(t *testing.T) { - tester := startTestPeer() - - // Wait for and check the handshake - if err := p2p.ExpectMsg(tester.stream, statusCode, []uint64{protocolVersion}); err != nil { - t.Fatalf("status message mismatch: %v", err) - } - // Send a valid handshake status and make sure connection stays live - if err := p2p.SendItems(tester.stream, statusCode, protocolVersion); err != nil { - t.Fatalf("failed to send status: %v", err) - } - select { - case <-tester.termed: - t.Fatalf("valid handshake disconnected") - - case <-time.After(100 * time.Millisecond): - } - // Clean up the test - tester.stream.Close() - - select { - case <-tester.termed: - case <-time.After(time.Second): - t.Fatalf("local close timed out") - } -} - -func TestPeerSend(t *testing.T) { - // Start a tester and execute the handshake - tester, err := startTestPeerInited() - if err != nil { - t.Fatalf("failed to start initialized peer: %v", err) - } - defer tester.stream.Close() - - // Construct a message and inject into the tester - message := NewMessage([]byte("peer broadcast test message")) - envelope, err := message.Wrap(DefaultPoW, Options{ - TTL: DefaultTTL, - }) - if err != nil { - t.Fatalf("failed to wrap message: %v", err) - } - if err := tester.client.Send(envelope); err != nil { - t.Fatalf("failed to send message: %v", err) - } - // Check that the message is eventually forwarded - payload := []interface{}{envelope} - if err := p2p.ExpectMsg(tester.stream, messagesCode, payload); err != nil { - t.Fatalf("message mismatch: %v", err) - } - // Make sure that even with a re-insert, an empty batch is received - if err := tester.client.Send(envelope); err != nil { - t.Fatalf("failed to send message: %v", err) - } - if err := p2p.ExpectMsg(tester.stream, messagesCode, []interface{}{}); err != nil { - t.Fatalf("message mismatch: %v", err) - } -} - -func TestPeerDeliver(t *testing.T) { - // Start a tester and execute the handshake - tester, err := startTestPeerInited() - if err != nil { - t.Fatalf("failed to start initialized peer: %v", err) - } - defer tester.stream.Close() - - // Watch for all inbound messages - arrived := make(chan struct{}, 1) - tester.client.Watch(Filter{ - Fn: func(message *Message) { - arrived <- struct{}{} - }, - }) - // Construct a message and deliver it to the tester peer - message := NewMessage([]byte("peer broadcast test message")) - envelope, err := message.Wrap(DefaultPoW, Options{ - TTL: DefaultTTL, - }) - if err != nil { - t.Fatalf("failed to wrap message: %v", err) - } - if err := p2p.Send(tester.stream, messagesCode, []*Envelope{envelope}); err != nil { - t.Fatalf("failed to transfer message: %v", err) - } - // Check that the message is delivered upstream - select { - case <-arrived: - case <-time.After(time.Second): - t.Fatalf("message delivery timeout") - } - // Check that a resend is not delivered - if err := p2p.Send(tester.stream, messagesCode, []*Envelope{envelope}); err != nil { - t.Fatalf("failed to transfer message: %v", err) - } - select { - case <-time.After(2 * transmissionCycle): - case <-arrived: - t.Fatalf("repeating message arrived") - } -} - -func TestPeerMessageExpiration(t *testing.T) { - // Start a tester and execute the handshake - tester, err := startTestPeerInited() - if err != nil { - t.Fatalf("failed to start initialized peer: %v", err) - } - defer tester.stream.Close() - - // Fetch the peer instance for later inspection - tester.client.peerMu.RLock() - if peers := len(tester.client.peers); peers != 1 { - t.Fatalf("peer pool size mismatch: have %v, want %v", peers, 1) - } - var peer *peer - for peer = range tester.client.peers { - break - } - tester.client.peerMu.RUnlock() - - // Construct a message and pass it through the tester - message := NewMessage([]byte("peer test message")) - envelope, err := message.Wrap(DefaultPoW, Options{ - TTL: time.Second, - }) - if err != nil { - t.Fatalf("failed to wrap message: %v", err) - } - if err := tester.client.Send(envelope); err != nil { - t.Fatalf("failed to send message: %v", err) - } - payload := []interface{}{envelope} - if err := p2p.ExpectMsg(tester.stream, messagesCode, payload); err != nil { - // A premature empty message may have been broadcast, check the next too - if err := p2p.ExpectMsg(tester.stream, messagesCode, payload); err != nil { - t.Fatalf("message mismatch: %v", err) - } - } - // Check that the message is inside the cache - if !peer.known.Has(envelope.Hash()) { - t.Fatalf("message not found in cache") - } - // Discard messages until expiration and check cache again - exp := time.Now().Add(time.Second + 2*expirationCycle + 100*time.Millisecond) - for time.Now().Before(exp) { - if err := p2p.ExpectMsg(tester.stream, messagesCode, []interface{}{}); err != nil { - t.Fatalf("message mismatch: %v", err) - } - } - if peer.known.Has(envelope.Hash()) { - t.Fatalf("message not expired from cache") - } -} diff --git a/whisper/whisperv2/topic.go b/whisper/whisperv2/topic.go deleted file mode 100644 index 3e2b47bd3f..0000000000 --- a/whisper/whisperv2/topic.go +++ /dev/null @@ -1,140 +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 . - -// Contains the Whisper protocol Topic element. For formal details please see -// the specs at https://github.com/ethereum/wiki/wiki/Whisper-PoC-1-Protocol-Spec#topics. - -package whisperv2 - -import "github.com/ethereum/go-ethereum/crypto" - -// Topic 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 Topic [4]byte - -// NewTopic creates a topic from the 4 byte prefix of the SHA3 hash of the data. -// -// Note, empty topics are considered the wildcard, and cannot be used in messages. -func NewTopic(data []byte) Topic { - prefix := [4]byte{} - copy(prefix[:], crypto.Keccak256(data)[:4]) - return Topic(prefix) -} - -// NewTopics creates a list of topics from a list of binary data elements, by -// iteratively calling NewTopic on each of them. -func NewTopics(data ...[]byte) []Topic { - topics := make([]Topic, len(data)) - for i, element := range data { - topics[i] = NewTopic(element) - } - return topics -} - -// NewTopicFromString creates a topic using the binary data contents of the -// specified string. -func NewTopicFromString(data string) Topic { - return NewTopic([]byte(data)) -} - -// NewTopicsFromStrings creates a list of topics from a list of textual data -// elements, by iteratively calling NewTopicFromString on each of them. -func NewTopicsFromStrings(data ...string) []Topic { - topics := make([]Topic, len(data)) - for i, element := range data { - topics[i] = NewTopicFromString(element) - } - return topics -} - -// String converts a topic byte array to a string representation. -func (self *Topic) String() string { - return string(self[:]) -} - -// topicMatcher is a filter expression to verify if a list of topics contained -// in an arriving message matches some topic conditions. The topic matcher is -// built up of a list of conditions, each of which must be satisfied by the -// corresponding topic in the message. Each condition may require: a) an exact -// topic match; b) a match from a set of topics; or c) a wild-card matching all. -// -// If a message contains more topics than required by the matcher, those beyond -// the condition count are ignored and assumed to match. -// -// Consider the following sample topic matcher: -// sample := { -// {TopicA1, TopicA2, TopicA3}, -// {TopicB}, -// nil, -// {TopicD1, TopicD2} -// } -// In order for a message to pass this filter, it should enumerate at least 4 -// topics, the first any of [TopicA1, TopicA2, TopicA3], the second mandatory -// "TopicB", the third is ignored by the filter and the fourth either "TopicD1" -// or "TopicD2". If the message contains further topics, the filter will match -// them too. -type topicMatcher struct { - conditions []map[Topic]struct{} -} - -// newTopicMatcher create a topic matcher from a list of topic conditions. -func newTopicMatcher(topics ...[]Topic) *topicMatcher { - matcher := make([]map[Topic]struct{}, len(topics)) - for i, condition := range topics { - matcher[i] = make(map[Topic]struct{}) - for _, topic := range condition { - matcher[i][topic] = struct{}{} - } - } - return &topicMatcher{conditions: matcher} -} - -// newTopicMatcherFromBinary create a topic matcher from a list of binary conditions. -func newTopicMatcherFromBinary(data ...[][]byte) *topicMatcher { - topics := make([][]Topic, len(data)) - for i, condition := range data { - topics[i] = NewTopics(condition...) - } - return newTopicMatcher(topics...) -} - -// newTopicMatcherFromStrings creates a topic matcher from a list of textual -// conditions. -func newTopicMatcherFromStrings(data ...[]string) *topicMatcher { - topics := make([][]Topic, len(data)) - for i, condition := range data { - topics[i] = NewTopicsFromStrings(condition...) - } - return newTopicMatcher(topics...) -} - -// Matches checks if a list of topics matches this particular condition set. -func (self *topicMatcher) Matches(topics []Topic) bool { - // Mismatch if there aren't enough topics - if len(self.conditions) > len(topics) { - return false - } - // Check each topic condition for existence (skip wild-cards) - for i := 0; i < len(topics) && i < len(self.conditions); i++ { - if len(self.conditions[i]) > 0 { - if _, ok := self.conditions[i][topics[i]]; !ok { - return false - } - } - } - return true -} diff --git a/whisper/whisperv2/topic_test.go b/whisper/whisperv2/topic_test.go deleted file mode 100644 index bb65689963..0000000000 --- a/whisper/whisperv2/topic_test.go +++ /dev/null @@ -1,215 +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 whisperv2 - -import ( - "bytes" - "testing" -) - -var topicCreationTests = []struct { - data []byte - hash [4]byte -}{ - {hash: [4]byte{0x8f, 0x9a, 0x2b, 0x7d}, data: []byte("test name")}, - {hash: [4]byte{0xf2, 0x6e, 0x77, 0x79}, data: []byte("some other test")}, -} - -func TestTopicCreation(t *testing.T) { - // Create the topics individually - for i, tt := range topicCreationTests { - topic := NewTopic(tt.data) - if !bytes.Equal(topic[:], tt.hash[:]) { - t.Errorf("binary test %d: hash mismatch: have %v, want %v.", i, topic, tt.hash) - } - } - for i, tt := range topicCreationTests { - topic := NewTopicFromString(string(tt.data)) - if !bytes.Equal(topic[:], tt.hash[:]) { - t.Errorf("textual test %d: hash mismatch: have %v, want %v.", i, topic, tt.hash) - } - } - // Create the topics in batches - binaryData := make([][]byte, len(topicCreationTests)) - for i, tt := range topicCreationTests { - binaryData[i] = tt.data - } - textualData := make([]string, len(topicCreationTests)) - for i, tt := range topicCreationTests { - textualData[i] = string(tt.data) - } - - topics := NewTopics(binaryData...) - for i, tt := range topicCreationTests { - if !bytes.Equal(topics[i][:], tt.hash[:]) { - t.Errorf("binary batch test %d: hash mismatch: have %v, want %v.", i, topics[i], tt.hash) - } - } - topics = NewTopicsFromStrings(textualData...) - for i, tt := range topicCreationTests { - if !bytes.Equal(topics[i][:], tt.hash[:]) { - t.Errorf("textual batch test %d: hash mismatch: have %v, want %v.", i, topics[i], tt.hash) - } - } -} - -var topicMatcherCreationTest = struct { - binary [][][]byte - textual [][]string - matcher []map[[4]byte]struct{} -}{ - binary: [][][]byte{ - {}, - { - []byte("Topic A"), - }, - { - []byte("Topic B1"), - []byte("Topic B2"), - []byte("Topic B3"), - }, - }, - textual: [][]string{ - {}, - {"Topic A"}, - {"Topic B1", "Topic B2", "Topic B3"}, - }, - matcher: []map[[4]byte]struct{}{ - {}, - { - {0x25, 0xfc, 0x95, 0x66}: {}, - }, - { - {0x93, 0x6d, 0xec, 0x09}: {}, - {0x25, 0x23, 0x34, 0xd3}: {}, - {0x6b, 0xc2, 0x73, 0xd1}: {}, - }, - }, -} - -func TestTopicMatcherCreation(t *testing.T) { - test := topicMatcherCreationTest - - matcher := newTopicMatcherFromBinary(test.binary...) - for i, cond := range matcher.conditions { - for topic := range cond { - if _, ok := test.matcher[i][topic]; !ok { - t.Errorf("condition %d; extra topic found: 0x%x", i, topic[:]) - } - } - } - for i, cond := range test.matcher { - for topic := range cond { - if _, ok := matcher.conditions[i][topic]; !ok { - t.Errorf("condition %d; topic not found: 0x%x", i, topic[:]) - } - } - } - - matcher = newTopicMatcherFromStrings(test.textual...) - for i, cond := range matcher.conditions { - for topic := range cond { - if _, ok := test.matcher[i][topic]; !ok { - t.Errorf("condition %d; extra topic found: 0x%x", i, topic[:]) - } - } - } - for i, cond := range test.matcher { - for topic := range cond { - if _, ok := matcher.conditions[i][topic]; !ok { - t.Errorf("condition %d; topic not found: 0x%x", i, topic[:]) - } - } - } -} - -var topicMatcherTests = []struct { - filter [][]string - topics []string - match bool -}{ - // Empty topic matcher should match everything - { - filter: [][]string{}, - topics: []string{}, - match: true, - }, - { - filter: [][]string{}, - topics: []string{"a", "b", "c"}, - match: true, - }, - // Fixed topic matcher should match strictly, but only prefix - { - filter: [][]string{{"a"}, {"b"}}, - topics: []string{"a"}, - match: false, - }, - { - filter: [][]string{{"a"}, {"b"}}, - topics: []string{"a", "b"}, - match: true, - }, - { - filter: [][]string{{"a"}, {"b"}}, - topics: []string{"a", "b", "c"}, - match: true, - }, - // Multi-matcher should match any from a sub-group - { - filter: [][]string{{"a1", "a2"}}, - topics: []string{"a"}, - match: false, - }, - { - filter: [][]string{{"a1", "a2"}}, - topics: []string{"a1"}, - match: true, - }, - { - filter: [][]string{{"a1", "a2"}}, - topics: []string{"a2"}, - match: true, - }, - // Wild-card condition should match anything - { - filter: [][]string{{}, {"b"}}, - topics: []string{"a"}, - match: false, - }, - { - filter: [][]string{{}, {"b"}}, - topics: []string{"a", "b"}, - match: true, - }, - { - filter: [][]string{{}, {"b"}}, - topics: []string{"b", "b"}, - match: true, - }, -} - -func TestTopicMatcher(t *testing.T) { - for i, tt := range topicMatcherTests { - topics := NewTopicsFromStrings(tt.topics...) - - matcher := newTopicMatcherFromStrings(tt.filter...) - if match := matcher.Matches(topics); match != tt.match { - t.Errorf("test %d: match mismatch: have %v, want %v", i, match, tt.match) - } - } -} diff --git a/whisper/whisperv2/whisper.go b/whisper/whisperv2/whisper.go deleted file mode 100644 index e111a34146..0000000000 --- a/whisper/whisperv2/whisper.go +++ /dev/null @@ -1,378 +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 whisperv2 - -import ( - "crypto/ecdsa" - "fmt" - "sync" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/crypto/ecies" - "github.com/ethereum/go-ethereum/event/filter" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/rpc" - - "gopkg.in/fatih/set.v0" -) - -const ( - statusCode = 0x00 - messagesCode = 0x01 - - protocolVersion uint64 = 0x02 - protocolName = "shh" - - signatureFlag = byte(1 << 7) - signatureLength = 65 - - expirationCycle = 800 * time.Millisecond - transmissionCycle = 300 * time.Millisecond -) - -const ( - DefaultTTL = 50 * time.Second - DefaultPoW = 50 * time.Millisecond -) - -type MessageEvent struct { - To *ecdsa.PrivateKey - From *ecdsa.PublicKey - Message *Message -} - -// Whisper represents a dark communication interface through the Ethereum -// network, using its very own P2P communication layer. -type Whisper struct { - protocol p2p.Protocol - filters *filter.Filters - - keys map[string]*ecdsa.PrivateKey - - messages map[common.Hash]*Envelope // Pool of messages currently tracked by this node - expirations map[uint32]*set.SetNonTS // Message expiration pool (TODO: something lighter) - poolMu sync.RWMutex // Mutex to sync the message and expiration pools - - peers map[*peer]struct{} // Set of currently active peers - peerMu sync.RWMutex // Mutex to sync the active peer set - - quit chan struct{} -} - -// New creates a Whisper client ready to communicate through the Ethereum P2P -// network. -func New() *Whisper { - whisper := &Whisper{ - filters: filter.New(), - keys: make(map[string]*ecdsa.PrivateKey), - messages: make(map[common.Hash]*Envelope), - expirations: make(map[uint32]*set.SetNonTS), - peers: make(map[*peer]struct{}), - quit: make(chan struct{}), - } - whisper.filters.Start() - - // p2p whisper sub protocol handler - whisper.protocol = p2p.Protocol{ - Name: protocolName, - Version: uint(protocolVersion), - Length: 2, - Run: whisper.handlePeer, - } - - return whisper -} - -// APIs returns the RPC descriptors the Whisper implementation offers -func (s *Whisper) APIs() []rpc.API { - return []rpc.API{ - { - Namespace: "shh", - Version: "1.0", - Service: NewPublicWhisperAPI(s), - Public: true, - }, - } -} - -// Protocols returns the whisper sub-protocols ran by this particular client. -func (self *Whisper) Protocols() []p2p.Protocol { - return []p2p.Protocol{self.protocol} -} - -// Version returns the whisper sub-protocols version number. -func (self *Whisper) Version() uint { - return self.protocol.Version -} - -// NewIdentity generates a new cryptographic identity for the client, and injects -// it into the known identities for message decryption. -func (self *Whisper) NewIdentity() *ecdsa.PrivateKey { - key, err := crypto.GenerateKey() - if err != nil { - panic(err) - } - self.keys[string(crypto.FromECDSAPub(&key.PublicKey))] = key - - return key -} - -// HasIdentity checks if the the whisper node is configured with the private key -// of the specified public pair. -func (self *Whisper) HasIdentity(key *ecdsa.PublicKey) bool { - return self.keys[string(crypto.FromECDSAPub(key))] != nil -} - -// GetIdentity retrieves the private key of the specified public identity. -func (self *Whisper) GetIdentity(key *ecdsa.PublicKey) *ecdsa.PrivateKey { - return self.keys[string(crypto.FromECDSAPub(key))] -} - -// Watch installs a new message handler to run in case a matching packet arrives -// from the whisper network. -func (self *Whisper) Watch(options Filter) int { - filter := filterer{ - to: string(crypto.FromECDSAPub(options.To)), - from: string(crypto.FromECDSAPub(options.From)), - matcher: newTopicMatcher(options.Topics...), - fn: func(data interface{}) { - options.Fn(data.(*Message)) - }, - } - return self.filters.Install(filter) -} - -// Unwatch removes an installed message handler. -func (self *Whisper) Unwatch(id int) { - self.filters.Uninstall(id) -} - -// Send injects a message into the whisper send queue, to be distributed in the -// network in the coming cycles. -func (self *Whisper) Send(envelope *Envelope) error { - return self.add(envelope) -} - -// Start implements node.Service, starting the background data propagation thread -// of the Whisper protocol. -func (self *Whisper) Start(*p2p.Server) error { - log.Info("Whisper started") - go self.update() - return nil -} - -// Stop implements node.Service, stopping the background data propagation thread -// of the Whisper protocol. -func (self *Whisper) Stop() error { - close(self.quit) - log.Info("Whisper stopped") - return nil -} - -// Messages retrieves all the currently pooled messages matching a filter id. -func (self *Whisper) Messages(id int) []*Message { - messages := make([]*Message, 0) - if filter := self.filters.Get(id); filter != nil { - for _, envelope := range self.messages { - if message := self.open(envelope); message != nil { - if self.filters.Match(filter, createFilter(message, envelope.Topics)) { - messages = append(messages, message) - } - } - } - } - return messages -} - -// handlePeer is called by the underlying P2P layer when the whisper sub-protocol -// connection is negotiated. -func (self *Whisper) handlePeer(peer *p2p.Peer, rw p2p.MsgReadWriter) error { - // Create the new peer and start tracking it - whisperPeer := newPeer(self, peer, rw) - - self.peerMu.Lock() - self.peers[whisperPeer] = struct{}{} - self.peerMu.Unlock() - - defer func() { - self.peerMu.Lock() - delete(self.peers, whisperPeer) - self.peerMu.Unlock() - }() - - // Run the peer handshake and state updates - if err := whisperPeer.handshake(); err != nil { - return err - } - whisperPeer.start() - defer whisperPeer.stop() - - // Read and process inbound messages directly to merge into client-global state - for { - // Fetch the next packet and decode the contained envelopes - packet, err := rw.ReadMsg() - if err != nil { - return err - } - var envelopes []*Envelope - if err := packet.Decode(&envelopes); err != nil { - log.Info(fmt.Sprintf("%v: failed to decode envelope: %v", peer, err)) - continue - } - // Inject all envelopes into the internal pool - for _, envelope := range envelopes { - if err := self.add(envelope); err != nil { - // TODO Punish peer here. Invalid envelope. - log.Debug(fmt.Sprintf("%v: failed to pool envelope: %v", peer, err)) - } - whisperPeer.mark(envelope) - } - } -} - -// 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. -func (self *Whisper) add(envelope *Envelope) error { - self.poolMu.Lock() - defer self.poolMu.Unlock() - - // short circuit when a received envelope has already expired - if envelope.Expiry < uint32(time.Now().Unix()) { - return nil - } - - // Insert the message into the tracked pool - hash := envelope.Hash() - if _, ok := self.messages[hash]; ok { - log.Trace(fmt.Sprintf("whisper envelope already cached: %x\n", hash)) - return nil - } - self.messages[hash] = envelope - - // Insert the message into the expiration pool for later removal - if self.expirations[envelope.Expiry] == nil { - self.expirations[envelope.Expiry] = set.NewNonTS() - } - if !self.expirations[envelope.Expiry].Has(hash) { - self.expirations[envelope.Expiry].Add(hash) - - // Notify the local node of a message arrival - go self.postEvent(envelope) - } - log.Trace(fmt.Sprintf("cached whisper envelope %x\n", hash)) - return nil -} - -// postEvent opens an envelope with the configured identities and delivers the -// message upstream from application processing. -func (self *Whisper) postEvent(envelope *Envelope) { - if message := self.open(envelope); message != nil { - self.filters.Notify(createFilter(message, envelope.Topics), message) - } -} - -// open tries to decrypt a whisper envelope with all the configured identities, -// returning the decrypted message and the key used to achieve it. If not keys -// are configured, open will return the payload as if non encrypted. -func (self *Whisper) open(envelope *Envelope) *Message { - // Short circuit if no identity is set, and assume clear-text - if len(self.keys) == 0 { - if message, err := envelope.Open(nil); err == nil { - return message - } - } - // Iterate over the keys and try to decrypt the message - for _, key := range self.keys { - message, err := envelope.Open(key) - if err == nil { - message.To = &key.PublicKey - return message - } else if err == ecies.ErrInvalidPublicKey { - return message - } - } - // Failed to decrypt, don't return anything - return nil -} - -// createFilter creates a message filter to check against installed handlers. -func createFilter(message *Message, topics []Topic) filter.Filter { - matcher := make([][]Topic, len(topics)) - for i, topic := range topics { - matcher[i] = []Topic{topic} - } - return filterer{ - to: string(crypto.FromECDSAPub(message.To)), - from: string(crypto.FromECDSAPub(message.Recover())), - matcher: newTopicMatcher(matcher...), - } -} - -// update loops until the lifetime of the whisper node, updating its internal -// state by expiring stale messages from the pool. -func (self *Whisper) update() { - // Start a ticker to check for expirations - expire := time.NewTicker(expirationCycle) - - // Repeat updates until termination is requested - for { - select { - case <-expire.C: - self.expire() - - case <-self.quit: - return - } - } -} - -// expire iterates over all the expiration timestamps, removing all stale -// messages from the pools. -func (self *Whisper) expire() { - self.poolMu.Lock() - defer self.poolMu.Unlock() - - now := uint32(time.Now().Unix()) - for then, hashSet := range self.expirations { - // Short circuit if a future time - if then > now { - continue - } - // Dump all expired messages and remove timestamp - hashSet.Each(func(v interface{}) bool { - delete(self.messages, v.(common.Hash)) - return true - }) - self.expirations[then].Clear() - } -} - -// envelopes retrieves all the messages currently pooled by the node. -func (self *Whisper) envelopes() []*Envelope { - self.poolMu.RLock() - defer self.poolMu.RUnlock() - - envelopes := make([]*Envelope, 0, len(self.messages)) - for _, envelope := range self.messages { - envelopes = append(envelopes, envelope) - } - return envelopes -} diff --git a/whisper/whisperv2/whisper_test.go b/whisper/whisperv2/whisper_test.go deleted file mode 100644 index 1e0d3f85d4..0000000000 --- a/whisper/whisperv2/whisper_test.go +++ /dev/null @@ -1,216 +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 whisperv2 - -import ( - "testing" - "time" - - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/discover" -) - -func startTestCluster(n int) []*Whisper { - // Create the batch of simulated peers - nodes := make([]*p2p.Peer, n) - for i := 0; i < n; i++ { - nodes[i] = p2p.NewPeer(discover.NodeID{}, "", nil) - } - whispers := make([]*Whisper, n) - for i := 0; i < n; i++ { - whispers[i] = New() - whispers[i].Start(nil) - } - // Wire all the peers to the root one - for i := 1; i < n; i++ { - src, dst := p2p.MsgPipe() - - go whispers[0].handlePeer(nodes[i], src) - go whispers[i].handlePeer(nodes[0], dst) - } - return whispers -} - -func TestSelfMessage(t *testing.T) { - // Start the single node cluster - client := startTestCluster(1)[0] - - // Start watching for self messages, signal any arrivals - self := client.NewIdentity() - done := make(chan struct{}) - - client.Watch(Filter{ - To: &self.PublicKey, - Fn: func(msg *Message) { - close(done) - }, - }) - // Send a dummy message to oneself - msg := NewMessage([]byte("self whisper")) - envelope, err := msg.Wrap(DefaultPoW, Options{ - From: self, - To: &self.PublicKey, - TTL: DefaultTTL, - }) - if err != nil { - t.Fatalf("failed to wrap message: %v", err) - } - // Dump the message into the system and wait for it to pop back out - if err := client.Send(envelope); err != nil { - t.Fatalf("failed to send self-message: %v", err) - } - select { - case <-done: - case <-time.After(time.Second): - t.Fatalf("self-message receive timeout") - } -} - -func TestDirectMessage(t *testing.T) { - // Start the sender-recipient cluster - cluster := startTestCluster(2) - - sender := cluster[0] - senderId := sender.NewIdentity() - - recipient := cluster[1] - recipientId := recipient.NewIdentity() - - // Watch for arriving messages on the recipient - done := make(chan struct{}) - recipient.Watch(Filter{ - To: &recipientId.PublicKey, - Fn: func(msg *Message) { - close(done) - }, - }) - // Send a dummy message from the sender - msg := NewMessage([]byte("direct whisper")) - envelope, err := msg.Wrap(DefaultPoW, Options{ - From: senderId, - To: &recipientId.PublicKey, - TTL: DefaultTTL, - }) - if err != nil { - t.Fatalf("failed to wrap message: %v", err) - } - if err := sender.Send(envelope); err != nil { - t.Fatalf("failed to send direct message: %v", err) - } - // Wait for an arrival or a timeout - select { - case <-done: - case <-time.After(time.Second): - t.Fatalf("direct message receive timeout") - } -} - -func TestAnonymousBroadcast(t *testing.T) { - testBroadcast(true, t) -} - -func TestIdentifiedBroadcast(t *testing.T) { - testBroadcast(false, t) -} - -func testBroadcast(anonymous bool, t *testing.T) { - // Start the single sender multi recipient cluster - cluster := startTestCluster(3) - - sender := cluster[1] - targets := cluster[1:] - for _, target := range targets { - if !anonymous { - target.NewIdentity() - } - } - // Watch for arriving messages on the recipients - dones := make([]chan struct{}, len(targets)) - for i := 0; i < len(targets); i++ { - done := make(chan struct{}) // need for the closure - dones[i] = done - - targets[i].Watch(Filter{ - Topics: NewFilterTopicsFromStringsFlat("broadcast topic"), - Fn: func(msg *Message) { - close(done) - }, - }) - } - // Send a dummy message from the sender - msg := NewMessage([]byte("broadcast whisper")) - envelope, err := msg.Wrap(DefaultPoW, Options{ - Topics: NewTopicsFromStrings("broadcast topic"), - TTL: DefaultTTL, - }) - if err != nil { - t.Fatalf("failed to wrap message: %v", err) - } - if err := sender.Send(envelope); err != nil { - t.Fatalf("failed to send broadcast message: %v", err) - } - // Wait for an arrival on each recipient, or timeouts - timeout := time.After(time.Second) - for _, done := range dones { - select { - case <-done: - case <-timeout: - t.Fatalf("broadcast message receive timeout") - } - } -} - -func TestMessageExpiration(t *testing.T) { - // Start the single node cluster and inject a dummy message - node := startTestCluster(1)[0] - - message := NewMessage([]byte("expiring message")) - envelope, err := message.Wrap(DefaultPoW, Options{TTL: time.Second}) - if err != nil { - t.Fatalf("failed to wrap message: %v", err) - } - if err := node.Send(envelope); err != nil { - t.Fatalf("failed to inject message: %v", err) - } - // Check that the message is inside the cache - node.poolMu.RLock() - _, found := node.messages[envelope.Hash()] - node.poolMu.RUnlock() - - if !found { - t.Fatalf("message not found in cache") - } - // Wait for expiration and check cache again - time.Sleep(time.Second) // wait for expiration - time.Sleep(2 * expirationCycle) // wait for cleanup cycle - - node.poolMu.RLock() - _, found = node.messages[envelope.Hash()] - node.poolMu.RUnlock() - if found { - t.Fatalf("message not expired from cache") - } - - // Check that adding an expired envelope doesn't do anything. - node.add(envelope) - node.poolMu.RLock() - _, found = node.messages[envelope.Hash()] - node.poolMu.RUnlock() - if found { - t.Fatalf("message was added to cache") - } -} diff --git a/whisper/whisperv5/api.go b/whisper/whisperv5/api.go deleted file mode 100644 index b4494d0d61..0000000000 --- a/whisper/whisperv5/api.go +++ /dev/null @@ -1,591 +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/discover" - "github.com/ethereum/go-ethereum/rpc" -) - -const ( - filterTimeout = 300 // filters are considered timeout out after filterTimeout seconds -) - -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), - } - - go api.run() - return api -} - -// run the api event loop. -// this loop deletes filter that have not been used within filterTimeout -func (api *PublicWhisperAPI) run() { - timeout := time.NewTicker(2 * time.Minute) - for { - <-timeout.C - - api.mu.Lock() - for id, lastUsed := range api.lastUsed { - if time.Since(lastUsed).Seconds() >= filterTimeout { - delete(api.lastUsed, id) - if err := api.w.Unsubscribe(id); err != nil { - log.Error("could not unsubscribe whisper filter", "error", err) - } - log.Debug("delete whisper filter (timeout)", "id", id) - } - } - api.mu.Unlock() - } -} - -// 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, enode string) (bool, error) { - n, err := discover.ParseNode(enode) - if err != nil { - return false, err - } - return true, api.w.AllowP2PMessagesFromPeer(n.ID[:]) -} - -// 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 -} - -// GetPublicKey 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 { - params.Dst = crypto.ToECDSAPub(req.PublicKey) - if !ValidatePublicKey(params.Dst) { - 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 := discover.ParseNode(req.TargetPeer) - if err != nil { - return false, fmt.Errorf("failed to parse target peer: %s", err) - } - return true, api.w.SendP2PMessage(n.ID[:], 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 { - filter.Src = crypto.ToECDSAPub(crit.Sig) - if !ValidatePublicKey(filter.Src) { - 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 { - src = crypto.ToECDSAPub(req.Sig) - if !ValidatePublicKey(src) { - 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/whisper/whisperv5/benchmarks_test.go b/whisper/whisperv5/benchmarks_test.go deleted file mode 100644 index dcfbcb56d8..0000000000 --- a/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/whisper/whisperv5/doc.go b/whisper/whisperv5/doc.go deleted file mode 100644 index 7a57488bd7..0000000000 --- a/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 whisper 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/whisper/whisperv5/envelope.go b/whisper/whisperv5/envelope.go deleted file mode 100644 index 169cbba9dd..0000000000 --- a/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/whisper/whisperv5/filter.go b/whisper/whisperv5/filter.go deleted file mode 100644 index 3190334ebb..0000000000 --- a/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) < TopicLength { - 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/whisper/whisperv5/filter_test.go b/whisper/whisperv5/filter_test.go deleted file mode 100644 index 01034a3513..0000000000 --- a/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_NotEquals_ReturnFalse(t *testing.T) { - bt := []byte("tes") - topic := BytesToTopic(bt) - - if matchSingleTopic(topic, bt) { - t.FailNow() - } -} - -func TestMatchSingleTopic_InsufficientLength_ReturnFalse(t *testing.T) { - bt := []byte("test") - topic := BytesToTopic([]byte("not_equal")) - - if matchSingleTopic(topic, bt) { - t.FailNow() - } -} diff --git a/whisper/whisperv5/gen_criteria_json.go b/whisper/whisperv5/gen_criteria_json.go deleted file mode 100644 index 1c0e389ad9..0000000000 --- a/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/whisper/whisperv5/gen_message_json.go b/whisper/whisperv5/gen_message_json.go deleted file mode 100644 index b4c4274d07..0000000000 --- a/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/whisper/whisperv5/gen_newmessage_json.go b/whisper/whisperv5/gen_newmessage_json.go deleted file mode 100644 index 97ffb64ad3..0000000000 --- a/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/whisper/whisperv5/message.go b/whisper/whisperv5/message.go deleted file mode 100644 index c27535cd1a..0000000000 --- a/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" -) - -// Options 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 -} - -// NewMessage 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(crand.Reader, 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 -} - -// Recover 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/whisper/whisperv5/message_test.go b/whisper/whisperv5/message_test.go deleted file mode 100644 index 2edf945df0..0000000000 --- a/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/whisper/whisperv5/peer.go b/whisper/whisperv5/peer.go deleted file mode 100644 index 179c931795..0000000000 --- a/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" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/rlp" - set "gopkg.in/fatih/set.v0" -) - -// peer represents a whisper protocol peer connection. -type Peer struct { - host *Whisper - peer *p2p.Peer - ws p2p.MsgReadWriter - trusted bool - - known *set.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: set.New(), - quit: make(chan struct{}), - } -} - -// start initiates the peer updater, periodically broadcasting the whisper packets -// into the network. -func (p *Peer) start() { - go p.update() - log.Trace("start", "peer", p.ID()) -} - -// stop terminates the peer updater, stopping message forwarding to it. -func (p *Peer) stop() { - close(p.quit) - log.Trace("stop", "peer", p.ID()) -} - -// handshake sends the protocol initiation status message to the remote peer and -// verifies the remote status too. -func (p *Peer) handshake() error { - // Send the handshake status message asynchronously - errc := make(chan error, 1) - go func() { - errc <- p2p.Send(p.ws, statusCode, ProtocolVersion) - }() - // Fetch the remote status packet and verify protocol match - packet, err := p.ws.ReadMsg() - if err != nil { - return err - } - if packet.Code != statusCode { - return fmt.Errorf("peer [%x] sent packet %x before status packet", p.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", p.ID(), err) - } - if peerVersion != ProtocolVersion { - return fmt.Errorf("peer [%x]: protocol version mismatch %d != %d", p.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", p.ID(), err) - } - return nil -} - -// update executes periodic operations on the peer, including message transmission -// and expiration. -func (p *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: - p.expire() - - case <-transmit.C: - if err := p.broadcast(); err != nil { - log.Trace("broadcast failed", "reason", err, "peer", p.ID()) - return - } - - case <-p.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.Has(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 (p *Peer) broadcast() error { - var cnt int - envelopes := p.host.Envelopes() - for _, envelope := range envelopes { - if !p.marked(envelope) { - err := p2p.Send(p.ws, messagesCode, envelope) - if err != nil { - return err - } else { - p.mark(envelope) - cnt++ - } - } - } - if cnt > 0 { - log.Trace("broadcast", "num. messages", cnt) - } - return nil -} - -func (p *Peer) ID() []byte { - id := p.peer.ID() - return id[:] -} diff --git a/whisper/whisperv5/peer_test.go b/whisper/whisperv5/peer_test.go deleted file mode 100644 index bae2adb6f5..0000000000 --- a/whisper/whisperv5/peer_test.go +++ /dev/null @@ -1,306 +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" - "fmt" - "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/discover" - "github.com/ethereum/go-ethereum/p2p/nat" -) - -var keys []string = []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 = []byte("some arbitrary data here") -var sharedTopic TopicType = TopicType{0xF, 0x1, 0x2, 0} -var expectedMessage []byte = []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 - ip := net.IPv4(127, 0, 0, 1) - port0 := 30303 - - 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]) - } - port := port0 + i - addr := fmt.Sprintf(":%d", port) // e.g. ":30303" - name := common.MakeName("whisper-go", "2.0") - var peers []*discover.Node - if i > 0 { - peerNodeId := nodes[i-1].id - peerPort := uint16(port - 1) - peerNode := discover.PubkeyID(&peerNodeId.PublicKey) - peer := discover.NewNode(peerNode, ip, peerPort, peerPort) - peers = append(peers, peer) - } - - node.server = &p2p.Server{ - Config: p2p.Config{ - PrivateKey: node.id, - MaxPeers: NumNodes/2 + 1, - Name: name, - Protocols: node.shh.Protocols(), - ListenAddr: addr, - NAT: nat.Any(), - BootstrapNodes: peers, - StaticNodes: peers, - TrustedNodes: peers, - }, - } - - err = node.server.Start() - if err != nil { - t.Fatalf("failed to start server %d.", i) - } - - 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/whisper/whisperv5/topic.go b/whisper/whisperv5/topic.go deleted file mode 100644 index c4ea67eefa..0000000000 --- a/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" -) - -// Topic 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/whisper/whisperv5/topic_test.go b/whisper/whisperv5/topic_test.go deleted file mode 100644 index 54bbeaf85e..0000000000 --- a/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/whisper/whisperv5/whisper.go b/whisper/whisperv5/whisper.go deleted file mode 100644 index 85849ccce4..0000000000 --- a/whisper/whisperv5/whisper.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" - crand "crypto/rand" - "crypto/sha256" - "fmt" - "runtime" - "sync" - "time" - - "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" - set "gopkg.in/fatih/set.v0" -) - -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]*set.SetNonTS // 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]*set.SetNonTS), - 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 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 (wh *Whisper) HandlePeer(peer *p2p.Peer, rw p2p.MsgReadWriter) error { - // Create the new peer and start tracking it - whisperPeer := newPeer(wh, peer, rw) - - wh.peerMu.Lock() - wh.peers[whisperPeer] = struct{}{} - wh.peerMu.Unlock() - - defer func() { - wh.peerMu.Lock() - delete(wh.peers, whisperPeer) - wh.peerMu.Unlock() - }() - - // Run the peer handshake and state updates - if err := whisperPeer.handshake(); err != nil { - return err - } - whisperPeer.start() - defer whisperPeer.stop() - - return wh.runMessageLoop(whisperPeer, rw) -} - -// runMessageLoop reads and processes inbound messages directly to merge into client-global state. -func (wh *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error { - for { - // fetch the next packet - packet, err := rw.ReadMsg() - if err != nil { - log.Warn("message loop", "peer", p.peer.ID(), "err", err) - return err - } - if packet.Size > wh.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 := wh.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") - } - wh.postEvent(&envelope, true) - } - case p2pRequestCode: - // Must be processed if mail server is implemented. Otherwise ignore. - if wh.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") - } - wh.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 (wh *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()) - } else { - // 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") - } else { - log.Debug("expired envelope dropped", "hash", envelope.Hash().Hex()) - return false, nil // drop envelope without error - } - } - - if uint32(envelope.size()) > wh.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() < wh.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() - - wh.poolMu.Lock() - _, alreadyCached := wh.envelopes[hash] - if !alreadyCached { - wh.envelopes[hash] = envelope - if wh.expirations[envelope.Expiry] == nil { - wh.expirations[envelope.Expiry] = set.NewNonTS() - } - if !wh.expirations[envelope.Expiry].Has(hash) { - wh.expirations[envelope.Expiry].Add(hash) - } - } - wh.poolMu.Unlock() - - if alreadyCached { - log.Trace("whisper envelope already cached", "hash", envelope.Hash().Hex()) - } else { - log.Trace("cached whisper envelope", "hash", envelope.Hash().Hex()) - wh.statsMu.Lock() - wh.stats.memoryUsed += envelope.size() - wh.statsMu.Unlock() - wh.postEvent(envelope, false) // notify the local node about the new message - if wh.mailServer != nil { - wh.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 true - }) - 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 - } else { - 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/whisper/whisperv5/whisper_test.go b/whisper/whisperv5/whisper_test.go deleted file mode 100644 index 8af085292a..0000000000 --- a/whisper/whisperv5/whisper_test.go +++ /dev/null @@ -1,851 +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 - 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()) > 0 { - 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/whisper/whisperv6/api.go b/whisper/whisperv6/api.go index 8ae2882e1f..7609a03c28 100644 --- a/whisper/whisperv6/api.go +++ b/whisper/whisperv6/api.go @@ -28,14 +28,10 @@ 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/p2p/discover" + "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/rpc" ) -const ( - filterTimeout = 300 // filters are considered timeout out after filterTimeout seconds -) - // List of errors var ( ErrSymAsym = errors.New("specify either a symmetric or an asymmetric key") @@ -61,32 +57,9 @@ func NewPublicWhisperAPI(w *Whisper) *PublicWhisperAPI { w: w, lastUsed: make(map[string]time.Time), } - - go api.run() return api } -// run the api event loop. -// this loop deletes filter that have not been used within filterTimeout -func (api *PublicWhisperAPI) run() { - timeout := time.NewTicker(2 * time.Minute) - for { - <-timeout.C - - api.mu.Lock() - for id, lastUsed := range api.lastUsed { - if time.Since(lastUsed).Seconds() >= filterTimeout { - delete(api.lastUsed, id) - if err := api.w.Unsubscribe(id); err != nil { - log.Error("could not unsubscribe whisper filter", "error", err) - } - log.Debug("delete whisper filter (timeout)", "id", id) - } - } - api.mu.Unlock() - } -} - // Version returns the Whisper sub-protocol version. func (api *PublicWhisperAPI) Version(ctx context.Context) string { return ProtocolVersionStr @@ -129,12 +102,12 @@ func (api *PublicWhisperAPI) SetBloomFilter(ctx context.Context, bloom hexutil.B // 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, enode string) (bool, error) { - n, err := discover.ParseNode(enode) +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[:]) + return true, api.w.AllowP2PMessagesFromPeer(n.ID().Bytes()) } // NewKeyPair generates a new public and private key pair for message decryption and encryption. @@ -219,6 +192,19 @@ func (api *PublicWhisperAPI) DeleteSymKey(ctx context.Context, id string) bool { return api.w.DeleteSymKey(id) } +// MakeLightClient turns the node into light client, which does not forward +// any incoming messages, and sends only messages originated in this node. +func (api *PublicWhisperAPI) MakeLightClient(ctx context.Context) bool { + api.w.SetLightClientMode(true) + return api.w.LightClientMode() +} + +// CancelLightClient cancels light client mode. +func (api *PublicWhisperAPI) CancelLightClient(ctx context.Context) bool { + api.w.SetLightClientMode(false) + return !api.w.LightClientMode() +} + //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. @@ -241,8 +227,9 @@ type newMessageOverride struct { Padding hexutil.Bytes } -// Post a message on the Whisper network. -func (api *PublicWhisperAPI) Post(ctx context.Context, req NewMessage) (bool, error) { +// Post posts a message on the Whisper network. +// returns the hash of the message in case of success. +func (api *PublicWhisperAPI) Post(ctx context.Context, req NewMessage) (hexutil.Bytes, error) { var ( symKeyGiven = len(req.SymKeyID) > 0 pubKeyGiven = len(req.PublicKey) > 0 @@ -251,7 +238,7 @@ func (api *PublicWhisperAPI) Post(ctx context.Context, req NewMessage) (bool, er // user must specify either a symmetric or an asymmetric key if (symKeyGiven && pubKeyGiven) || (!symKeyGiven && !pubKeyGiven) { - return false, ErrSymAsym + return nil, ErrSymAsym } params := &MessageParams{ @@ -266,57 +253,67 @@ func (api *PublicWhisperAPI) Post(ctx context.Context, req NewMessage) (bool, er // 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 + return nil, 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 + return nil, ErrNoTopics } if params.KeySym, err = api.w.GetSymKey(req.SymKeyID); err != nil { - return false, err + return nil, err } if !validateDataIntegrity(params.KeySym, aesKeyLength) { - return false, ErrInvalidSymmetricKey + return nil, ErrInvalidSymmetricKey } } // Set asymmetric key that is used to encrypt the message if pubKeyGiven { - params.Dst = crypto.ToECDSAPub(req.PublicKey) - if !ValidatePublicKey(params.Dst) { - return false, ErrInvalidPublicKey + if params.Dst, err = crypto.UnmarshalPubkey(req.PublicKey); err != nil { + return nil, ErrInvalidPublicKey } } // encrypt and sent message - whisperMsg, err := newSentMessage(params) + whisperMsg, err := NewSentMessage(params) if err != nil { - return false, err + return nil, err } + var result []byte env, err := whisperMsg.Wrap(params) if err != nil { - return false, err + return nil, err } // send to specific node (skip PoW check) if len(req.TargetPeer) > 0 { - n, err := discover.ParseNode(req.TargetPeer) + n, err := enode.ParseV4(req.TargetPeer) if err != nil { - return false, fmt.Errorf("failed to parse target peer: %s", err) + return nil, fmt.Errorf("failed to parse target peer: %s", err) } - return true, api.w.SendP2PMessage(n.ID[:], env) + err = api.w.SendP2PMessage(n.ID().Bytes(), env) + if err == nil { + hash := env.Hash() + result = hash[:] + } + return result, err } // ensure that the message PoW meets the node's minimum accepted PoW if req.PowTarget < api.w.MinPow() { - return false, ErrTooLowPoW + return nil, ErrTooLowPoW } - return true, api.w.Send(env) + err = api.w.Send(env) + if err == nil { + hash := env.Hash() + result = hash[:] + } + return result, err } //go:generate gencodec -type Criteria -field-override criteriaOverride -out gen_criteria_json.go @@ -362,8 +359,7 @@ func (api *PublicWhisperAPI) Messages(ctx context.Context, crit Criteria) (*rpc. } if len(crit.Sig) > 0 { - filter.Src = crypto.ToECDSAPub(crit.Sig) - if !ValidatePublicKey(filter.Src) { + if filter.Src, err = crypto.UnmarshalPubkey(crit.Sig); err != nil { return nil, ErrInvalidSigningPubKey } } @@ -546,8 +542,7 @@ func (api *PublicWhisperAPI) NewMessageFilter(req Criteria) (string, error) { } if len(req.Sig) > 0 { - src = crypto.ToECDSAPub(req.Sig) - if !ValidatePublicKey(src) { + if src, err = crypto.UnmarshalPubkey(req.Sig); err != nil { return "", ErrInvalidSigningPubKey } } @@ -568,9 +563,10 @@ func (api *PublicWhisperAPI) NewMessageFilter(req Criteria) (string, error) { } if len(req.Topics) > 0 { - topics = make([][]byte, 0, len(req.Topics)) - for _, topic := range req.Topics { - topics = append(topics, topic[:]) + topics = make([][]byte, len(req.Topics)) + for i, topic := range req.Topics { + topics[i] = make([]byte, TopicLength) + copy(topics[i], topic[:]) } } diff --git a/whisper/whisperv6/api_test.go b/whisper/whisperv6/api_test.go new file mode 100644 index 0000000000..6d7157f57f --- /dev/null +++ b/whisper/whisperv6/api_test.go @@ -0,0 +1,63 @@ +// 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 whisperv6 + +import ( + "bytes" + "testing" + "time" +) + +func TestMultipleTopicCopyInNewMessageFilter(t *testing.T) { + w := New(nil) + + keyID, err := w.GenerateSymKey() + if err != nil { + t.Fatalf("Error generating symmetric key: %v", err) + } + api := PublicWhisperAPI{ + w: w, + lastUsed: make(map[string]time.Time), + } + + t1 := [4]byte{0xde, 0xea, 0xbe, 0xef} + t2 := [4]byte{0xca, 0xfe, 0xde, 0xca} + + crit := Criteria{ + SymKeyID: keyID, + Topics: []TopicType{TopicType(t1), TopicType(t2)}, + } + + _, err = api.NewMessageFilter(crit) + if err != nil { + t.Fatalf("Error creating the filter: %v", err) + } + + found := false + candidates := w.filters.getWatchersByTopic(TopicType(t1)) + for _, f := range candidates { + if len(f.Topics) == 2 { + if bytes.Equal(f.Topics[0], t1[:]) && bytes.Equal(f.Topics[1], t2[:]) { + found = true + } + } + } + + if !found { + t.Fatalf("Could not find filter with both topics") + } +} diff --git a/whisper/whisperv6/benchmarks_test.go b/whisper/whisperv6/benchmarks_test.go index 52c8f95ea6..0473179da5 100644 --- a/whisper/whisperv6/benchmarks_test.go +++ b/whisper/whisperv6/benchmarks_test.go @@ -39,7 +39,7 @@ func BenchmarkEncryptionSym(b *testing.B) { } for i := 0; i < b.N; i++ { - msg, _ := newSentMessage(params) + msg, _ := NewSentMessage(params) _, err := msg.Wrap(params) if err != nil { b.Errorf("failed Wrap with seed %d: %s.", seed, err) @@ -64,7 +64,7 @@ func BenchmarkEncryptionAsym(b *testing.B) { params.Dst = &key.PublicKey for i := 0; i < b.N; i++ { - msg, _ := newSentMessage(params) + msg, _ := NewSentMessage(params) _, err := msg.Wrap(params) if err != nil { b.Fatalf("failed Wrap with seed %d: %s.", seed, err) @@ -79,7 +79,7 @@ func BenchmarkDecryptionSymValid(b *testing.B) { if err != nil { b.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) } - msg, _ := newSentMessage(params) + msg, _ := NewSentMessage(params) env, err := msg.Wrap(params) if err != nil { b.Fatalf("failed Wrap with seed %d: %s.", seed, err) @@ -101,7 +101,7 @@ func BenchmarkDecryptionSymInvalid(b *testing.B) { if err != nil { b.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) } - msg, _ := newSentMessage(params) + msg, _ := NewSentMessage(params) env, err := msg.Wrap(params) if err != nil { b.Fatalf("failed Wrap with seed %d: %s.", seed, err) @@ -130,7 +130,7 @@ func BenchmarkDecryptionAsymValid(b *testing.B) { f := Filter{KeyAsym: key} params.KeySym = nil params.Dst = &key.PublicKey - msg, _ := newSentMessage(params) + msg, _ := NewSentMessage(params) env, err := msg.Wrap(params) if err != nil { b.Fatalf("failed Wrap with seed %d: %s.", seed, err) @@ -157,7 +157,7 @@ func BenchmarkDecryptionAsymInvalid(b *testing.B) { } params.KeySym = nil params.Dst = &key.PublicKey - msg, _ := newSentMessage(params) + msg, _ := NewSentMessage(params) env, err := msg.Wrap(params) if err != nil { b.Fatalf("failed Wrap with seed %d: %s.", seed, err) @@ -199,7 +199,7 @@ func BenchmarkPoW(b *testing.B) { for i := 0; i < b.N; i++ { increment(params.Payload) - msg, _ := newSentMessage(params) + msg, _ := NewSentMessage(params) _, err := msg.Wrap(params) if err != nil { b.Fatalf("failed Wrap with seed %d: %s.", seed, err) diff --git a/whisper/whisperv6/config.go b/whisper/whisperv6/config.go index 61419de007..38eb9551cc 100644 --- a/whisper/whisperv6/config.go +++ b/whisper/whisperv6/config.go @@ -18,12 +18,14 @@ package whisperv6 // Config represents the configuration state of a whisper node. type Config struct { - MaxMessageSize uint32 `toml:",omitempty"` - MinimumAcceptedPOW float64 `toml:",omitempty"` + MaxMessageSize uint32 `toml:",omitempty"` + MinimumAcceptedPOW float64 `toml:",omitempty"` + RestrictConnectionBetweenLightClients bool `toml:",omitempty"` } // DefaultConfig represents (shocker!) the default configuration. var DefaultConfig = Config{ - MaxMessageSize: DefaultMaxMessageSize, - MinimumAcceptedPOW: DefaultMinimumPoW, + MaxMessageSize: DefaultMaxMessageSize, + MinimumAcceptedPOW: DefaultMinimumPoW, + RestrictConnectionBetweenLightClients: true, } diff --git a/whisper/whisperv6/doc.go b/whisper/whisperv6/doc.go index d5d7fed609..529bf3d2de 100644 --- a/whisper/whisperv6/doc.go +++ b/whisper/whisperv6/doc.go @@ -33,7 +33,6 @@ particularly the notion of singular endpoints. package whisperv6 import ( - "fmt" "time" ) @@ -60,7 +59,7 @@ const ( aesKeyLength = 32 // in bytes aesNonceLength = 12 // in bytes; for more info please see cipher.gcmStandardNonceSize & aesgcm.NonceSize() keyIDSize = 32 // in bytes - bloomFilterSize = 64 // in bytes + BloomFilterSize = 64 // in bytes flagsLength = 1 EnvelopeHeaderLength = 20 @@ -79,12 +78,6 @@ const ( DefaultSyncAllowance = 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 diff --git a/whisper/whisperv6/envelope.go b/whisper/whisperv6/envelope.go index 881945e9a8..c42d1fa8ac 100644 --- a/whisper/whisperv6/envelope.go +++ b/whisper/whisperv6/envelope.go @@ -77,15 +77,19 @@ func NewEnvelope(ttl uint32, topic TopicType, msg *sentMessage) *Envelope { // 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 + // PoW is not required + return nil + } + + var target, bestBit 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 + // the execution time, we can also adjust Expiry. e.Expiry += options.WorkTime } else { target = e.powToFirstBit(options.PoW) - if target < 1 { - target = 1 - } } buf := make([]byte, 64) @@ -143,7 +147,11 @@ func (e *Envelope) powToFirstBit(pow float64) int { x *= float64(e.TTL) bits := gmath.Log2(x) bits = gmath.Ceil(bits) - return int(bits) + res := int(bits) + if res < 1 { + res = 1 + } + return res } // Hash returns the SHA3 hash of the envelope, calculating it if not yet done. @@ -200,6 +208,10 @@ func (e *Envelope) OpenSymmetric(key []byte) (msg *ReceivedMessage, err error) { // Open tries to decrypt an envelope, and populates the message fields in case of success. func (e *Envelope) Open(watcher *Filter) (msg *ReceivedMessage) { + if watcher == nil { + return nil + } + // The API interface forbids filters doing both symmetric and asymmetric encryption. if watcher.expectsAsymmetricEncryption() && watcher.expectsSymmetricEncryption() { return nil @@ -241,7 +253,7 @@ func (e *Envelope) Bloom() []byte { // TopicToBloom converts the topic (4 bytes) to the bloom filter (64 bytes) func TopicToBloom(topic TopicType) []byte { - b := make([]byte, bloomFilterSize) + b := make([]byte, BloomFilterSize) var index [3]int for j := 0; j < 3; j++ { index[j] = int(topic[j]) @@ -257,3 +269,11 @@ func TopicToBloom(topic TopicType) []byte { } return b } + +// GetEnvelope retrieves an envelope from the message queue by its hash. +// It returns nil if the envelope can not be found. +func (w *Whisper) GetEnvelope(hash common.Hash) *Envelope { + w.poolMu.RLock() + defer w.poolMu.RUnlock() + return w.envelopes[hash] +} diff --git a/whisper/whisperv6/envelope_test.go b/whisper/whisperv6/envelope_test.go index 1ee1bec41b..410b250a3f 100644 --- a/whisper/whisperv6/envelope_test.go +++ b/whisper/whisperv6/envelope_test.go @@ -45,7 +45,7 @@ func TestEnvelopeOpenAcceptsOnlyOneKeyTypeInFilter(t *testing.T) { mrand.Read(params.Payload) - msg, err := newSentMessage(¶ms) + msg, err := NewSentMessage(¶ms) if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } diff --git a/whisper/whisperv6/filter.go b/whisper/whisperv6/filter.go index eb0c65fa3b..6a5b79674b 100644 --- a/whisper/whisperv6/filter.go +++ b/whisper/whisperv6/filter.go @@ -35,6 +35,7 @@ type Filter struct { 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 + id string // unique identifier Messages map[common.Hash]*ReceivedMessage mutex sync.RWMutex @@ -43,15 +44,21 @@ type Filter struct { // Filters represents a collection of filters type Filters struct { watchers map[string]*Filter - whisper *Whisper - mutex sync.RWMutex + + topicMatcher map[TopicType]map[*Filter]struct{} // map a topic to the filters that are interested in being notified when a message matches that topic + allTopicsMatcher map[*Filter]struct{} // list all the filters that will be notified of a new message, no matter what its topic is + + whisper *Whisper + mutex sync.RWMutex } // NewFilters returns a newly created filter collection func NewFilters(w *Whisper) *Filters { return &Filters{ - watchers: make(map[string]*Filter), - whisper: w, + watchers: make(map[string]*Filter), + topicMatcher: make(map[TopicType]map[*Filter]struct{}), + allTopicsMatcher: make(map[*Filter]struct{}), + whisper: w, } } @@ -81,7 +88,9 @@ func (fs *Filters) Install(watcher *Filter) (string, error) { watcher.SymKeyHash = crypto.Keccak256Hash(watcher.KeySym) } + watcher.id = id fs.watchers[id] = watcher + fs.addTopicMatcher(watcher) return id, err } @@ -91,12 +100,51 @@ func (fs *Filters) Uninstall(id string) bool { fs.mutex.Lock() defer fs.mutex.Unlock() if fs.watchers[id] != nil { + fs.removeFromTopicMatchers(fs.watchers[id]) delete(fs.watchers, id) return true } return false } +// addTopicMatcher adds a filter to the topic matchers. +// If the filter's Topics array is empty, it will be tried on every topic. +// Otherwise, it will be tried on the topics specified. +func (fs *Filters) addTopicMatcher(watcher *Filter) { + if len(watcher.Topics) == 0 { + fs.allTopicsMatcher[watcher] = struct{}{} + } else { + for _, t := range watcher.Topics { + topic := BytesToTopic(t) + if fs.topicMatcher[topic] == nil { + fs.topicMatcher[topic] = make(map[*Filter]struct{}) + } + fs.topicMatcher[topic][watcher] = struct{}{} + } + } +} + +// removeFromTopicMatchers removes a filter from the topic matchers +func (fs *Filters) removeFromTopicMatchers(watcher *Filter) { + delete(fs.allTopicsMatcher, watcher) + for _, topic := range watcher.Topics { + delete(fs.topicMatcher[BytesToTopic(topic)], watcher) + } +} + +// getWatchersByTopic returns a slice containing the filters that +// match a specific topic +func (fs *Filters) getWatchersByTopic(topic TopicType) []*Filter { + res := make([]*Filter, 0, len(fs.allTopicsMatcher)) + for watcher := range fs.allTopicsMatcher { + res = append(res, watcher) + } + for watcher := range fs.topicMatcher[topic] { + res = append(res, watcher) + } + return res +} + // Get returns a filter from the collection with a specific ID func (fs *Filters) Get(id string) *Filter { fs.mutex.RLock() @@ -112,11 +160,10 @@ func (fs *Filters) NotifyWatchers(env *Envelope, p2pMessage bool) { fs.mutex.RLock() defer fs.mutex.RUnlock() - i := -1 // only used for logging info - for _, watcher := range fs.watchers { - i++ + candidates := fs.getWatchersByTopic(env.Topic) + for _, watcher := range candidates { if p2pMessage && !watcher.AllowP2P { - log.Trace(fmt.Sprintf("msg [%x], filter [%d]: p2p messages are not allowed", env.Hash(), i)) + log.Trace(fmt.Sprintf("msg [%x], filter [%s]: p2p messages are not allowed", env.Hash(), watcher.id)) continue } @@ -128,10 +175,10 @@ func (fs *Filters) NotifyWatchers(env *Envelope, p2pMessage bool) { if match { msg = env.Open(watcher) if msg == nil { - log.Trace("processing message: failed to open", "message", env.Hash().Hex(), "filter", i) + log.Trace("processing message: failed to open", "message", env.Hash().Hex(), "filter", watcher.id) } } else { - log.Trace("processing message: does not match", "message", env.Hash().Hex(), "filter", i) + log.Trace("processing message: does not match", "message", env.Hash().Hex(), "filter", watcher.id) } } @@ -144,20 +191,6 @@ func (fs *Filters) NotifyWatchers(env *Envelope, p2pMessage bool) { } } -func (f *Filter) processEnvelope(env *Envelope) *ReceivedMessage { - if f.MatchEnvelope(env) { - msg := env.Open(f) - if msg != nil { - return msg - } - - 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 } @@ -194,16 +227,17 @@ func (f *Filter) Retrieve() (all []*ReceivedMessage) { // MatchMessage checks if the filter matches an already decrypted // message (i.e. a Message that has already been handled by -// MatchEnvelope when checked by a previous filter) +// MatchEnvelope when checked by a previous filter). +// Topics are not checked here, since this is done by topic matchers. 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) + return IsPubKeyEqual(&f.KeyAsym.PublicKey, msg.Dst) } else if f.expectsSymmetricEncryption() && msg.isSymmetricEncryption() { - return f.SymKeyHash == msg.SymKeyHash && f.MatchTopic(msg.Topic) + return f.SymKeyHash == msg.SymKeyHash } return false } @@ -211,44 +245,9 @@ func (f *Filter) MatchMessage(msg *ReceivedMessage) bool { // MatchEnvelope checks if it's worth decrypting the message. If // it returns `true`, client code is expected to attempt decrypting // the message and subsequently call MatchMessage. +// Topics are not checked here, since this is done by topic matchers. func (f *Filter) MatchEnvelope(envelope *Envelope) bool { - if f.PoW > 0 && envelope.pow < f.PoW { - return false - } - - return f.MatchTopic(envelope.Topic) -} - -// MatchTopic checks that the filter captures a given topic. -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) < TopicLength { - return false - } - - for j, b := range bt { - if topic[j] != b { - return false - } - } - return true + return f.PoW <= 0 || envelope.pow >= f.PoW } // IsPubKeyEqual checks that two public keys are equal diff --git a/whisper/whisperv6/filter_test.go b/whisper/whisperv6/filter_test.go index fc7db76712..5ce99d9f6c 100644 --- a/whisper/whisperv6/filter_test.go +++ b/whisper/whisperv6/filter_test.go @@ -56,7 +56,7 @@ func generateFilter(t *testing.T, symmetric bool) (*Filter, error) { f.Topics = make([][]byte, topicNum) for i := 0; i < topicNum; i++ { f.Topics[i] = make([]byte, 4) - mrand.Read(f.Topics[i][:]) + mrand.Read(f.Topics[i]) f.Topics[i][0] = 0x01 } @@ -199,7 +199,7 @@ func TestInstallIdenticalFilters(t *testing.T) { filter1.Src = ¶ms.Src.PublicKey filter2.Src = ¶ms.Src.PublicKey - sentMessage, err := newSentMessage(params) + sentMessage, err := NewSentMessage(params) if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } @@ -303,10 +303,9 @@ func TestMatchEnvelope(t *testing.T) { t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) } - params.Topic[0] = 0xFF // ensure mismatch + params.Topic[0] = 0xFF // topic mismatch - // mismatch with pseudo-random data - msg, err := newSentMessage(params) + msg, err := NewSentMessage(params) if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } @@ -314,20 +313,12 @@ func TestMatchEnvelope(t *testing.T) { 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) + msg, err = NewSentMessage(params) if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } @@ -337,7 +328,7 @@ func TestMatchEnvelope(t *testing.T) { } // symmetric + matching topic: match - match = fsym.MatchEnvelope(env) + match := fsym.MatchEnvelope(env) if !match { t.Fatalf("failed MatchEnvelope() symmetric with seed %d.", seed) } @@ -372,7 +363,7 @@ func TestMatchEnvelope(t *testing.T) { } params.KeySym = nil params.Dst = &key.PublicKey - msg, err = newSentMessage(params) + msg, err = NewSentMessage(params) if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } @@ -396,7 +387,7 @@ func TestMatchEnvelope(t *testing.T) { // asymmetric + matching topic: match fasym.Topics[i] = fasym.Topics[i+1] match = fasym.MatchEnvelope(env) - if match { + if !match { t.Fatalf("failed MatchEnvelope(asymmetric + matching topic) with seed %d.", seed) } @@ -431,7 +422,8 @@ func TestMatchEnvelope(t *testing.T) { // filter with topic + envelope without topic: mismatch fasym.Topics = fsym.Topics match = fasym.MatchEnvelope(env) - if match { + if !match { + // topic mismatch should have no affect, as topics are handled by topic matchers t.Fatalf("failed MatchEnvelope(filter without topic + envelope without topic) with seed %d.", seed) } } @@ -453,7 +445,7 @@ func TestMatchMessageSym(t *testing.T) { params.KeySym = f.KeySym params.Topic = BytesToTopic(f.Topics[index]) - sentMessage, err := newSentMessage(params) + sentMessage, err := NewSentMessage(params) if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } @@ -487,7 +479,8 @@ func TestMatchMessageSym(t *testing.T) { // topic mismatch f.Topics[index][0]++ - if f.MatchMessage(msg) { + if !f.MatchMessage(msg) { + // topic mismatch should have no affect, as topics are handled by topic matchers t.Fatalf("failed MatchEnvelope(topic mismatch) with seed %d.", seed) } f.Topics[index][0]-- @@ -546,7 +539,7 @@ func TestMatchMessageAsym(t *testing.T) { keySymOrig := params.KeySym params.KeySym = nil - sentMessage, err := newSentMessage(params) + sentMessage, err := NewSentMessage(params) if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } @@ -580,7 +573,8 @@ func TestMatchMessageAsym(t *testing.T) { // topic mismatch f.Topics[index][0]++ - if f.MatchMessage(msg) { + if !f.MatchMessage(msg) { + // topic mismatch should have no affect, as topics are handled by topic matchers t.Fatalf("failed MatchEnvelope(topic mismatch) with seed %d.", seed) } f.Topics[index][0]-- @@ -630,7 +624,7 @@ func generateCompatibeEnvelope(t *testing.T, f *Filter) *Envelope { params.KeySym = f.KeySym params.Topic = BytesToTopic(f.Topics[2]) - sentMessage, err := newSentMessage(params) + sentMessage, err := NewSentMessage(params) if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } @@ -806,7 +800,7 @@ func TestVariableTopics(t *testing.T) { if err != nil { t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) } - msg, err := newSentMessage(params) + msg, err := NewSentMessage(params) if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } @@ -829,44 +823,9 @@ func TestVariableTopics(t *testing.T) { f.Topics[i][lastTopicByte]++ match = f.MatchEnvelope(env) - if match { - t.Fatalf("MatchEnvelope symmetric with seed %d, step %d: false positive.", seed, i) + if !match { + // topic mismatch should have no affect, as topics are handled by topic matchers + t.Fatalf("MatchEnvelope symmetric with seed %d, step %d.", 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_NotEquals_ReturnFalse(t *testing.T) { - bt := []byte("tes") - topic := BytesToTopic(bt) - - if matchSingleTopic(topic, bt) { - t.FailNow() - } -} - -func TestMatchSingleTopic_InsufficientLength_ReturnFalse(t *testing.T) { - bt := []byte("test") - topic := BytesToTopic([]byte("not_equal")) - - if matchSingleTopic(topic, bt) { - t.FailNow() - } -} diff --git a/whisper/whisperv6/message.go b/whisper/whisperv6/message.go index 7def35f14f..2d4e862441 100644 --- a/whisper/whisperv6/message.go +++ b/whisper/whisperv6/message.go @@ -89,7 +89,7 @@ func (msg *ReceivedMessage) isAsymmetricEncryption() bool { } // NewSentMessage creates and initializes a non-signed, non-encrypted Whisper message. -func newSentMessage(params *MessageParams) (*sentMessage, error) { +func NewSentMessage(params *MessageParams) (*sentMessage, error) { const payloadSizeFieldMaxSize = 4 msg := sentMessage{} msg.Raw = make([]byte, 1, @@ -289,7 +289,7 @@ func (msg *ReceivedMessage) decryptSymmetric(key []byte) error { // decryptAsymmetric decrypts an encrypted payload with a private key. func (msg *ReceivedMessage) decryptAsymmetric(key *ecdsa.PrivateKey) error { - decrypted, err := ecies.ImportECDSA(key).Decrypt(crand.Reader, msg.Raw, nil, nil) + decrypted, err := ecies.ImportECDSA(key).Decrypt(msg.Raw, nil, nil) if err == nil { msg.Raw = decrypted } diff --git a/whisper/whisperv6/message_test.go b/whisper/whisperv6/message_test.go index 12a269f5db..0a5c1c8533 100644 --- a/whisper/whisperv6/message_test.go +++ b/whisper/whisperv6/message_test.go @@ -73,7 +73,7 @@ func singleMessageTest(t *testing.T, symmetric bool) { text := make([]byte, 0, 512) text = append(text, params.Payload...) - msg, err := newSentMessage(params) + msg, err := NewSentMessage(params) if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } @@ -131,7 +131,7 @@ func TestMessageWrap(t *testing.T) { t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) } - msg, err := newSentMessage(params) + msg, err := NewSentMessage(params) if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } @@ -149,7 +149,7 @@ func TestMessageWrap(t *testing.T) { } // set PoW target too high, expect error - msg2, err := newSentMessage(params) + msg2, err := NewSentMessage(params) if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } @@ -172,7 +172,7 @@ func TestMessageSeal(t *testing.T) { t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) } - msg, err := newSentMessage(params) + msg, err := NewSentMessage(params) if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } @@ -234,7 +234,7 @@ func singleEnvelopeOpenTest(t *testing.T, symmetric bool) { text := make([]byte, 0, 512) text = append(text, params.Payload...) - msg, err := newSentMessage(params) + msg, err := NewSentMessage(params) if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } @@ -289,7 +289,7 @@ func TestEncryptWithZeroKey(t *testing.T) { if err != nil { t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) } - msg, err := newSentMessage(params) + msg, err := NewSentMessage(params) if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } @@ -303,7 +303,7 @@ func TestEncryptWithZeroKey(t *testing.T) { if err != nil { t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) } - msg, err = newSentMessage(params) + msg, err = NewSentMessage(params) if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } @@ -317,7 +317,7 @@ func TestEncryptWithZeroKey(t *testing.T) { if err != nil { t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) } - msg, err = newSentMessage(params) + msg, err = NewSentMessage(params) if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } @@ -335,7 +335,7 @@ func TestRlpEncode(t *testing.T) { if err != nil { t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) } - msg, err := newSentMessage(params) + msg, err := NewSentMessage(params) if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } @@ -379,7 +379,7 @@ func singlePaddingTest(t *testing.T, padSize int) { if n != padSize { t.Fatalf("padding is not copied (seed %d): %s", seed, err) } - msg, err := newSentMessage(params) + msg, err := NewSentMessage(params) if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } diff --git a/whisper/whisperv6/peer.go b/whisper/whisperv6/peer.go index 4f9a7c3780..621d512081 100644 --- a/whisper/whisperv6/peer.go +++ b/whisper/whisperv6/peer.go @@ -19,13 +19,14 @@ package whisperv6 import ( "fmt" "math" + "sync" "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" - set "gopkg.in/fatih/set.v0" ) // Peer represents a whisper protocol peer connection. @@ -36,9 +37,11 @@ type Peer struct { trusted bool powRequirement float64 - bloomFilter []byte // may contain nil in case of full node + bloomMu sync.Mutex + bloomFilter []byte + fullNode bool - known *set.Set // Messages already known by the peer to avoid wasting bandwidth + known mapset.Set // Messages already known by the peer to avoid wasting bandwidth quit chan struct{} } @@ -51,8 +54,10 @@ func newPeer(host *Whisper, remote *p2p.Peer, rw p2p.MsgReadWriter) *Peer { ws: rw, trusted: false, powRequirement: 0.0, - known: set.New(), + known: mapset.NewSet(), quit: make(chan struct{}), + bloomFilter: MakeFullNodeBloom(), + fullNode: true, } } @@ -74,11 +79,14 @@ func (peer *Peer) stop() { func (peer *Peer) handshake() error { // Send the handshake status message asynchronously errc := make(chan error, 1) + isLightNode := peer.host.LightClientMode() + isRestrictedLightNodeConnection := peer.host.LightClientModeConnectionRestricted() go func() { pow := peer.host.MinPow() powConverted := math.Float64bits(pow) bloom := peer.host.BloomFilter() - errc <- p2p.SendItems(peer.ws, statusCode, ProtocolVersion, powConverted, bloom) + + errc <- p2p.SendItems(peer.ws, statusCode, ProtocolVersion, powConverted, bloom, isLightNode) }() // Fetch the remote status packet and verify protocol match @@ -115,17 +123,18 @@ func (peer *Peer) handshake() error { err = s.Decode(&bloom) if err == nil { sz := len(bloom) - if sz != bloomFilterSize && sz != 0 { + if sz != BloomFilterSize && sz != 0 { return fmt.Errorf("peer [%x] sent bad status message: wrong bloom filter size %d", peer.ID(), sz) } - if isFullNode(bloom) { - peer.bloomFilter = nil - } else { - peer.bloomFilter = bloom - } + peer.setBloomFilter(bloom) } } + isRemotePeerLightNode, err := s.Bool() + if isRemotePeerLightNode && isLightNode && isRestrictedLightNodeConnection { + return fmt.Errorf("peer [%x] is useless: two light client communication restricted", peer.ID()) + } + if err := <-errc; err != nil { return fmt.Errorf("peer [%x] failed to send status packet: %v", peer.ID(), err) } @@ -164,7 +173,7 @@ func (peer *Peer) mark(envelope *Envelope) { // marked checks if an envelope is already known to the remote peer. func (peer *Peer) marked(envelope *Envelope) bool { - return peer.known.Has(envelope.Hash()) + return peer.known.Contains(envelope.Hash()) } // expire iterates over all the known envelopes in the host and removes all @@ -226,10 +235,25 @@ func (peer *Peer) notifyAboutBloomFilterChange(bloom []byte) error { } func (peer *Peer) bloomMatch(env *Envelope) bool { - if peer.bloomFilter == nil { - // no filter - full node, accepts all envelops - return true - } - - return bloomFilterMatch(peer.bloomFilter, env.Bloom()) + peer.bloomMu.Lock() + defer peer.bloomMu.Unlock() + return peer.fullNode || BloomFilterMatch(peer.bloomFilter, env.Bloom()) +} + +func (peer *Peer) setBloomFilter(bloom []byte) { + peer.bloomMu.Lock() + defer peer.bloomMu.Unlock() + peer.bloomFilter = bloom + peer.fullNode = isFullNode(bloom) + if peer.fullNode && peer.bloomFilter == nil { + peer.bloomFilter = MakeFullNodeBloom() + } +} + +func MakeFullNodeBloom() []byte { + bloom := make([]byte, BloomFilterSize) + for i := 0; i < BloomFilterSize; i++ { + bloom[i] = 0xFF + } + return bloom } diff --git a/whisper/whisperv6/peer_test.go b/whisper/whisperv6/peer_test.go index 17f70129b5..c5b044e1a6 100644 --- a/whisper/whisperv6/peer_test.go +++ b/whisper/whisperv6/peer_test.go @@ -21,17 +21,20 @@ import ( "crypto/ecdsa" "fmt" mrand "math/rand" - "net" "sync" + "sync/atomic" "testing" "time" + "net" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/discover" + "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/nat" + "github.com/ethereum/go-ethereum/rlp" ) var keys = []string{ @@ -70,9 +73,8 @@ var keys = []string{ "7184c1701569e3a4c4d2ddce691edd983b81e42e09196d332e1ae2f1e062cff4", } -const NumNodes = 16 // must not exceed the number of keys (32) - type TestData struct { + started int64 counter [NumNodes]int mutex sync.RWMutex } @@ -84,21 +86,29 @@ type TestNode struct { filerID string } +const NumNodes = 8 // must not exceed the number of keys (32) + var result TestData var nodes [NumNodes]*TestNode var sharedKey = hexutil.MustDecode("0x03ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd31") +var wrongKey = hexutil.MustDecode("0xf91156714d7ec88d3edc1c652c2181dbb3044e8771c683f3b30d33c12b986b11") var sharedTopic = TopicType{0xF, 0x1, 0x2, 0} -var expectedMessage = []byte("per rectum ad astra") +var wrongTopic = TopicType{0, 0, 0, 0} +var expectedMessage = []byte("per aspera ad astra") +var unexpectedMessage = []byte("per rectum ad astra") var masterBloomFilter []byte var masterPow = 0.00000001 var round = 1 +var debugMode = false +var prevTime time.Time +var cntPrev int func TestSimulation(t *testing.T) { // create a chain of whisper nodes, // installs the filters with shared (predefined) parameters initialize(t) - // each node sends a number of random (undecryptable) messages + // each node sends one random (not decryptable) message for i := 0; i < NumNodes; i++ { sendMsg(t, false, i) } @@ -115,7 +125,6 @@ func TestSimulation(t *testing.T) { // send new pow and bloom exchange messages resetParams(t) - round++ // node #1 sends one expected (decryptable) message sendMsg(t, true, 1) @@ -140,10 +149,12 @@ func resetParams(t *testing.T) { for i := 0; i < NumNodes; i++ { nodes[i].shh.SetBloomFilter(masterBloomFilter) } + + round++ } func initBloom(t *testing.T) { - masterBloomFilter = make([]byte, bloomFilterSize) + masterBloomFilter = make([]byte, BloomFilterSize) _, err := mrand.Read(masterBloomFilter) if err != nil { t.Fatalf("rand failed: %s.", err) @@ -155,7 +166,7 @@ func initBloom(t *testing.T) { masterBloomFilter[i] = 0xFF } - if !bloomFilterMatch(masterBloomFilter, msgBloom) { + if !BloomFilterMatch(masterBloomFilter, msgBloom) { t.Fatalf("bloom mismatch on initBloom.") } } @@ -164,12 +175,10 @@ func initialize(t *testing.T) { initBloom(t) var err error - ip := net.IPv4(127, 0, 0, 1) - port0 := 30303 for i := 0; i < NumNodes; i++ { var node TestNode - b := make([]byte, bloomFilterSize) + b := make([]byte, BloomFilterSize) copy(b, masterBloomFilter) node.shh = New(&DefaultConfig) node.shh.SetMinimumPoW(masterPow) @@ -190,44 +199,43 @@ func initialize(t *testing.T) { if err != nil { t.Fatalf("failed convert the key: %s.", keys[i]) } - port := port0 + i - addr := fmt.Sprintf(":%d", port) // e.g. ":30303" name := common.MakeName("whisper-go", "2.0") - var peers []*discover.Node - if i > 0 { - peerNodeID := nodes[i-1].id - peerPort := uint16(port - 1) - peerNode := discover.PubkeyID(&peerNodeID.PublicKey) - peer := discover.NewNode(peerNode, ip, peerPort, peerPort) - peers = append(peers, peer) - } node.server = &p2p.Server{ Config: p2p.Config{ - PrivateKey: node.id, - MaxPeers: NumNodes/2 + 1, - Name: name, - Protocols: node.shh.Protocols(), - ListenAddr: addr, - NAT: nat.Any(), - BootstrapNodes: peers, - StaticNodes: peers, - TrustedNodes: peers, + PrivateKey: node.id, + MaxPeers: NumNodes/2 + 1, + Name: name, + Protocols: node.shh.Protocols(), + ListenAddr: "127.0.0.1:0", + NAT: nat.Any(), }, } + go startServer(t, node.server) + nodes[i] = &node } - for i := 1; i < NumNodes; i++ { - go nodes[i].server.Start() + waitForServersToStart(t) + + for i := 0; i < NumNodes; i++ { + for j := 0; j < i; j++ { + peerNodeId := nodes[j].id + address, _ := net.ResolveTCPAddr("tcp", nodes[j].server.ListenAddr) + peer := enode.NewV4(&peerNodeId.PublicKey, address.IP, address.Port, address.Port) + nodes[i].server.AddPeer(peer) + } + } +} + +func startServer(t *testing.T, s *p2p.Server) { + err := s.Start() + if err != nil { + t.Fatalf("failed to start the first server. err: %v", err) } - // we need to wait until the first node actually starts - err = nodes[0].server.Start() - if err != nil { - t.Fatalf("failed to start the fisrt server.") - } + atomic.AddInt64(&result.started, 1) } func stopServers() { @@ -246,8 +254,10 @@ func checkPropagation(t *testing.T, includingNodeZero bool) { return } - const cycle = 50 - const iterations = 200 + prevTime = time.Now() + // (cycle * iterations) should not exceed 50 seconds, since TTL=50 + const cycle = 200 // time in milliseconds + const iterations = 250 first := 0 if !includingNodeZero { @@ -262,29 +272,29 @@ func checkPropagation(t *testing.T, includingNodeZero bool) { } mail := f.Retrieve() - if !validateMail(t, i, mail) { - return - } + validateMail(t, i, mail) if isTestComplete() { + checkTestStatus() return } } + checkTestStatus() time.Sleep(cycle * time.Millisecond) } - t.Fatalf("Test was not complete: timeout %d seconds.", iterations*cycle/1000) - if !includingNodeZero { f := nodes[0].shh.GetFilter(nodes[0].filerID) if f != nil { t.Fatalf("node zero received a message with low PoW.") } } + + t.Fatalf("Test was not complete (%d round): timeout %d seconds. nodes=%v", round, iterations*cycle/1000, nodes) } -func validateMail(t *testing.T, index int, mail []*ReceivedMessage) bool { +func validateMail(t *testing.T, index int, mail []*ReceivedMessage) { var cnt int for _, m := range mail { if bytes.Equal(m.Payload, expectedMessage) { @@ -294,14 +304,13 @@ func validateMail(t *testing.T, index int, mail []*ReceivedMessage) bool { if cnt == 0 { // no messages received yet: nothing is wrong - return true + return } if cnt > 1 { t.Fatalf("node %d received %d.", index, cnt) - return false } - if cnt > 0 { + if cnt == 1 { result.mutex.Lock() defer result.mutex.Unlock() result.counter[index] += cnt @@ -309,7 +318,28 @@ func validateMail(t *testing.T, index int, mail []*ReceivedMessage) bool { t.Fatalf("node %d accumulated %d.", index, result.counter[index]) } } - return true +} + +func checkTestStatus() { + var cnt int + var arr [NumNodes]int + + for i := 0; i < NumNodes; i++ { + arr[i] = nodes[i].server.PeerCount() + envelopes := nodes[i].shh.Envelopes() + if len(envelopes) >= NumNodes { + cnt++ + } + } + + if debugMode { + if cntPrev != cnt { + fmt.Printf(" %v \t number of nodes that have received all msgs: %d, number of peers per node: %v \n", + time.Since(prevTime), cnt, arr) + prevTime = time.Now() + cntPrev = cnt + } + } } func isTestComplete() bool { @@ -324,7 +354,7 @@ func isTestComplete() bool { for i := 0; i < NumNodes; i++ { envelopes := nodes[i].shh.Envelopes() - if len(envelopes) < 2 { + if len(envelopes) < NumNodes+1 { return false } } @@ -339,12 +369,13 @@ func sendMsg(t *testing.T, expected bool, id int) { 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:] + opt.KeySym = wrongKey + opt.Topic = wrongTopic + opt.Payload = unexpectedMessage + opt.Payload[0] = byte(id) } - msg, err := newSentMessage(&opt) + msg, err := NewSentMessage(&opt) if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } @@ -368,7 +399,7 @@ func TestPeerBasic(t *testing.T) { } params.PoW = 0.001 - msg, err := newSentMessage(params) + msg, err := NewSentMessage(params) if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } @@ -400,7 +431,7 @@ func checkPowExchangeForNodeZeroOnce(t *testing.T, mustPass bool) bool { cnt := 0 for i, node := range nodes { for peer := range node.shh.peers { - if peer.peer.ID() == discover.PubkeyID(&nodes[0].id.PublicKey) { + if peer.peer.ID() == nodes[0].server.Self().ID() { cnt++ if peer.powRequirement != masterPow { if mustPass { @@ -421,7 +452,7 @@ func checkPowExchangeForNodeZeroOnce(t *testing.T, mustPass bool) bool { func checkPowExchange(t *testing.T) { for i, node := range nodes { for peer := range node.shh.peers { - if peer.peer.ID() != discover.PubkeyID(&nodes[0].id.PublicKey) { + if peer.peer.ID() != nodes[0].server.Self().ID() { if peer.powRequirement != masterPow { t.Fatalf("node %d: failed to exchange pow requirement in round %d; expected %f, got %f", i, round, masterPow, peer.powRequirement) @@ -434,7 +465,10 @@ func checkPowExchange(t *testing.T) { func checkBloomFilterExchangeOnce(t *testing.T, mustPass bool) bool { for i, node := range nodes { for peer := range node.shh.peers { - if !bytes.Equal(peer.bloomFilter, masterBloomFilter) { + peer.bloomMu.Lock() + equals := bytes.Equal(peer.bloomFilter, masterBloomFilter) + peer.bloomMu.Unlock() + if !equals { if mustPass { t.Fatalf("node %d: failed to exchange bloom filter requirement in round %d. \n%x expected \n%x got", i, round, masterBloomFilter, peer.bloomFilter) @@ -459,3 +493,76 @@ func checkBloomFilterExchange(t *testing.T) { time.Sleep(50 * time.Millisecond) } } + +func waitForServersToStart(t *testing.T) { + const iterations = 200 + var started int64 + for j := 0; j < iterations; j++ { + time.Sleep(50 * time.Millisecond) + started = atomic.LoadInt64(&result.started) + if started == NumNodes { + return + } + } + t.Fatalf("Failed to start all the servers, running: %d", started) +} + +//two generic whisper node handshake +func TestPeerHandshakeWithTwoFullNode(t *testing.T) { + w1 := Whisper{} + p1 := newPeer(&w1, p2p.NewPeer(enode.ID{}, "test", []p2p.Cap{}), &rwStub{[]interface{}{ProtocolVersion, uint64(123), make([]byte, BloomFilterSize), false}}) + err := p1.handshake() + if err != nil { + t.Fatal() + } +} + +//two generic whisper node handshake. one don't send light flag +func TestHandshakeWithOldVersionWithoutLightModeFlag(t *testing.T) { + w1 := Whisper{} + p1 := newPeer(&w1, p2p.NewPeer(enode.ID{}, "test", []p2p.Cap{}), &rwStub{[]interface{}{ProtocolVersion, uint64(123), make([]byte, BloomFilterSize)}}) + err := p1.handshake() + if err != nil { + t.Fatal() + } +} + +//two light nodes handshake. restriction disabled +func TestTwoLightPeerHandshakeRestrictionOff(t *testing.T) { + w1 := Whisper{} + w1.settings.Store(restrictConnectionBetweenLightClientsIdx, false) + w1.SetLightClientMode(true) + p1 := newPeer(&w1, p2p.NewPeer(enode.ID{}, "test", []p2p.Cap{}), &rwStub{[]interface{}{ProtocolVersion, uint64(123), make([]byte, BloomFilterSize), true}}) + err := p1.handshake() + if err != nil { + t.FailNow() + } +} + +//two light nodes handshake. restriction enabled +func TestTwoLightPeerHandshakeError(t *testing.T) { + w1 := Whisper{} + w1.settings.Store(restrictConnectionBetweenLightClientsIdx, true) + w1.SetLightClientMode(true) + p1 := newPeer(&w1, p2p.NewPeer(enode.ID{}, "test", []p2p.Cap{}), &rwStub{[]interface{}{ProtocolVersion, uint64(123), make([]byte, BloomFilterSize), true}}) + err := p1.handshake() + if err == nil { + t.FailNow() + } +} + +type rwStub struct { + payload []interface{} +} + +func (stub *rwStub) ReadMsg() (p2p.Msg, error) { + size, r, err := rlp.EncodeToReader(stub.payload) + if err != nil { + return p2p.Msg{}, err + } + return p2p.Msg{Code: statusCode, Size: uint32(size), Payload: r}, nil +} + +func (stub *rwStub) WriteMsg(m p2p.Msg) error { + return nil +} diff --git a/whisper/whisperv6/whisper.go b/whisper/whisperv6/whisper.go index d75ad04ac3..eb713f84ee 100644 --- a/whisper/whisperv6/whisper.go +++ b/whisper/whisperv6/whisper.go @@ -26,6 +26,7 @@ import ( "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" @@ -35,7 +36,6 @@ import ( "github.com/syndtr/goleveldb/leveldb/errors" "golang.org/x/crypto/pbkdf2" "golang.org/x/sync/syncmap" - set "gopkg.in/fatih/set.v0" ) // Statistics holds several message-related counter for analytics @@ -49,12 +49,14 @@ type Statistics struct { } const ( - maxMsgSizeIdx = iota // Maximal message length allowed by the whisper node - overflowIdx // Indicator of message queue overflow - minPowIdx // Minimal PoW required by the whisper node - minPowToleranceIdx // Minimal PoW tolerated by the whisper node for a limited time - bloomFilterIdx // Bloom filter for topics of interest for this node - bloomFilterToleranceIdx // Bloom filter tolerated by the whisper node for a limited time + maxMsgSizeIdx = iota // Maximal message length allowed by the whisper node + overflowIdx // Indicator of message queue overflow + minPowIdx // Minimal PoW required by the whisper node + minPowToleranceIdx // Minimal PoW tolerated by the whisper node for a limited time + bloomFilterIdx // Bloom filter for topics of interest for this node + bloomFilterToleranceIdx // Bloom filter tolerated by the whisper node for a limited time + lightClientModeIdx // Light client mode. (does not forward any messages) + restrictConnectionBetweenLightClientsIdx // Restrict connection between two light clients ) // Whisper represents a dark communication interface through the Ethereum @@ -69,7 +71,7 @@ type Whisper struct { 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]*set.SetNonTS // Message expiration pool + 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 @@ -98,7 +100,7 @@ func New(cfg *Config) *Whisper { privateKeys: make(map[string]*ecdsa.PrivateKey), symKeys: make(map[string][]byte), envelopes: make(map[common.Hash]*Envelope), - expirations: make(map[uint32]*set.SetNonTS), + expirations: make(map[uint32]mapset.Set), peers: make(map[*Peer]struct{}), messageQueue: make(chan *Envelope, messageQueueLimit), p2pMsgQueue: make(chan *Envelope, messageQueueLimit), @@ -111,6 +113,7 @@ func New(cfg *Config) *Whisper { whisper.settings.Store(minPowIdx, cfg.MinimumAcceptedPOW) whisper.settings.Store(maxMsgSizeIdx, cfg.MaxMessageSize) whisper.settings.Store(overflowIdx, false) + whisper.settings.Store(restrictConnectionBetweenLightClientsIdx, cfg.RestrictConnectionBetweenLightClients) // p2p whisper sub protocol handler whisper.protocol = p2p.Protocol{ @@ -230,11 +233,11 @@ func (whisper *Whisper) SetMaxMessageSize(size uint32) error { // SetBloomFilter sets the new bloom filter func (whisper *Whisper) SetBloomFilter(bloom []byte) error { - if len(bloom) != bloomFilterSize { + if len(bloom) != BloomFilterSize { return fmt.Errorf("invalid bloom filter size: %d", len(bloom)) } - b := make([]byte, bloomFilterSize) + b := make([]byte, BloomFilterSize) copy(b, bloom) whisper.settings.Store(bloomFilterIdx, b) @@ -274,6 +277,31 @@ func (whisper *Whisper) SetMinimumPowTest(val float64) { whisper.settings.Store(minPowToleranceIdx, val) } +//SetLightClientMode makes node light client (does not forward any messages) +func (whisper *Whisper) SetLightClientMode(v bool) { + whisper.settings.Store(lightClientModeIdx, v) +} + +//LightClientMode indicates is this node is light client (does not forward any messages) +func (whisper *Whisper) LightClientMode() bool { + val, exist := whisper.settings.Load(lightClientModeIdx) + if !exist || val == nil { + return false + } + v, ok := val.(bool) + return v && ok +} + +//LightClientModeConnectionRestricted indicates that connection to light client in light client mode not allowed +func (whisper *Whisper) LightClientModeConnectionRestricted() bool { + val, exist := whisper.settings.Load(restrictConnectionBetweenLightClientsIdx) + if !exist || val == nil { + return false + } + v, ok := val.(bool) + return v && ok +} + func (whisper *Whisper) notifyPeersAboutPowRequirementChange(pow float64) { arr := whisper.getPeers() for _, p := range arr { @@ -421,7 +449,7 @@ func (whisper *Whisper) AddKeyPair(key *ecdsa.PrivateKey) (string, error) { return id, nil } -// HasKeyPair checks if the the whisper node is configured with the private key +// HasKeyPair checks if the whisper node is configured with the private key // of the specified public pair. func (whisper *Whisper) HasKeyPair(id string) bool { whisper.keyMu.RLock() @@ -556,14 +584,14 @@ func (whisper *Whisper) Subscribe(f *Filter) (string, error) { // updateBloomFilter recalculates the new value of bloom filter, // and informs the peers if necessary. func (whisper *Whisper) updateBloomFilter(f *Filter) { - aggregate := make([]byte, bloomFilterSize) + aggregate := make([]byte, BloomFilterSize) for _, t := range f.Topics { top := BytesToTopic(t) b := TopicToBloom(top) aggregate = addBloom(aggregate, b) } - if !bloomFilterMatch(whisper.BloomFilter(), aggregate) { + if !BloomFilterMatch(whisper.BloomFilter(), aggregate) { // existing bloom filter must be updated aggregate = addBloom(whisper.BloomFilter(), aggregate) whisper.SetBloomFilter(aggregate) @@ -587,11 +615,8 @@ func (whisper *Whisper) Unsubscribe(id string) error { // Send injects a message into the whisper send queue, to be distributed in the // network in the coming cycles. func (whisper *Whisper) Send(envelope *Envelope) error { - ok, err := whisper.add(envelope) - if err != nil { - return err - } - if !ok { + ok, err := whisper.add(envelope, false) + if err == nil && !ok { return fmt.Errorf("failed to add envelope") } return err @@ -651,7 +676,7 @@ func (whisper *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error { // fetch the next packet packet, err := rw.ReadMsg() if err != nil { - log.Warn("message loop", "peer", p.peer.ID(), "err", err) + log.Info("message loop", "peer", p.peer.ID(), "err", err) return err } if packet.Size > whisper.MaxMessageSize() { @@ -673,7 +698,7 @@ func (whisper *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error { trouble := false for _, env := range envelopes { - cached, err := whisper.add(env) + cached, err := whisper.add(env, whisper.LightClientMode()) if err != nil { trouble = true log.Error("bad envelope received, peer will be disconnected", "peer", p.peer.ID(), "err", err) @@ -702,7 +727,7 @@ func (whisper *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error { case bloomFilterExCode: var bloom []byte err := packet.Decode(&bloom) - if err == nil && len(bloom) != bloomFilterSize { + if err == nil && len(bloom) != BloomFilterSize { err = fmt.Errorf("wrong bloom filter size %d", len(bloom)) } @@ -710,11 +735,7 @@ func (whisper *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error { log.Warn("failed to decode bloom filter exchange message, peer will be disconnected", "peer", p.peer.ID(), "err", err) return errors.New("invalid bloom filter exchange message") } - if isFullNode(bloom) { - p.bloomFilter = nil - } else { - p.bloomFilter = bloom - } + p.setBloomFilter(bloom) case p2pMessageCode: // peer-to-peer message, sent directly to peer bypassing PoW checks, etc. // this message is not supposed to be forwarded to other peers, and @@ -750,7 +771,8 @@ func (whisper *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error { // 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 (whisper *Whisper) add(envelope *Envelope) (bool, error) { +// param isP2P indicates whether the message is peer-to-peer (should not be forwarded). +func (whisper *Whisper) add(envelope *Envelope, isP2P bool) (bool, error) { now := uint32(time.Now().Unix()) sent := envelope.Expiry - envelope.TTL @@ -783,11 +805,11 @@ func (whisper *Whisper) add(envelope *Envelope) (bool, error) { } } - if !bloomFilterMatch(whisper.BloomFilter(), envelope.Bloom()) { + if !BloomFilterMatch(whisper.BloomFilter(), envelope.Bloom()) { // maybe the value was recently changed, and the peers did not adjust yet. // in this case the previous value is retrieved by BloomFilterTolerance() // for a short period of peer synchronization. - if !bloomFilterMatch(whisper.BloomFilterTolerance(), envelope.Bloom()) { + if !BloomFilterMatch(whisper.BloomFilterTolerance(), envelope.Bloom()) { return false, fmt.Errorf("envelope does not match bloom filter, hash=[%v], bloom: \n%x \n%x \n%x", envelope.Hash().Hex(), whisper.BloomFilter(), envelope.Bloom(), envelope.Topic) } @@ -800,9 +822,9 @@ func (whisper *Whisper) add(envelope *Envelope) (bool, error) { if !alreadyCached { whisper.envelopes[hash] = envelope if whisper.expirations[envelope.Expiry] == nil { - whisper.expirations[envelope.Expiry] = set.NewNonTS() + whisper.expirations[envelope.Expiry] = mapset.NewThreadUnsafeSet() } - if !whisper.expirations[envelope.Expiry].Has(hash) { + if !whisper.expirations[envelope.Expiry].Contains(hash) { whisper.expirations[envelope.Expiry].Add(hash) } } @@ -815,7 +837,7 @@ func (whisper *Whisper) add(envelope *Envelope) (bool, error) { whisper.statsMu.Lock() whisper.stats.memoryUsed += envelope.size() whisper.statsMu.Unlock() - whisper.postEvent(envelope, false) // notify the local node about the new message + whisper.postEvent(envelope, isP2P) // notify the local node about the new message if whisper.mailServer != nil { whisper.mailServer.Archive(envelope) } @@ -904,7 +926,7 @@ func (whisper *Whisper) expire() { whisper.stats.messagesCleared++ whisper.stats.memoryCleared += sz whisper.stats.memoryUsed -= sz - return true + return false }) whisper.expirations[expiry].Clear() delete(whisper.expirations, expiry) @@ -932,24 +954,6 @@ func (whisper *Whisper) Envelopes() []*Envelope { return all } -// Messages iterates through all currently floating envelopes -// and retrieves all the messages, that this filter could decrypt. -func (whisper *Whisper) Messages(id string) []*ReceivedMessage { - result := make([]*ReceivedMessage, 0) - whisper.poolMu.RLock() - defer whisper.poolMu.RUnlock() - - if filter := whisper.filters.Get(id); filter != nil { - for _, env := range whisper.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 (whisper *Whisper) isEnvelopeCached(hash common.Hash) bool { whisper.poolMu.Lock() @@ -1047,13 +1051,12 @@ func isFullNode(bloom []byte) bool { return true } -func bloomFilterMatch(filter, sample []byte) bool { +func BloomFilterMatch(filter, sample []byte) bool { if filter == nil { - // full node, accepts all messages return true } - for i := 0; i < bloomFilterSize; i++ { + for i := 0; i < BloomFilterSize; i++ { f := filter[i] s := sample[i] if (f | s) != f { @@ -1065,8 +1068,8 @@ func bloomFilterMatch(filter, sample []byte) bool { } func addBloom(a, b []byte) []byte { - c := make([]byte, bloomFilterSize) - for i := 0; i < bloomFilterSize; i++ { + c := make([]byte, BloomFilterSize) + for i := 0; i < BloomFilterSize; i++ { c[i] = a[i] | b[i] } return c diff --git a/whisper/whisperv6/whisper_test.go b/whisper/whisperv6/whisper_test.go index 838cb7b851..895bb2b969 100644 --- a/whisper/whisperv6/whisper_test.go +++ b/whisper/whisperv6/whisper_test.go @@ -75,10 +75,6 @@ func TestWhisperBasic(t *testing.T) { if len(mail) != 0 { t.Fatalf("failed w.Envelopes().") } - m := w.Messages("non-existent") - if len(m) != 0 { - t.Fatalf("failed w.Messages.") - } derived := pbkdf2.Key([]byte(peerID), nil, 65356, aesKeyLength, sha256.New) if !validateDataIntegrity(derived, aesKeyLength) { @@ -469,27 +465,34 @@ func TestExpiry(t *testing.T) { if err != nil { t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) } - params.TTL = 1 - 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) + 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()) > 0 { + if len(w.Envelopes()) == messagesCount { received = true break } @@ -537,7 +540,7 @@ func TestCustomization(t *testing.T) { params.Topic = BytesToTopic(f.Topics[2]) params.PoW = smallPoW params.TTL = 3600 * 24 // one day - msg, err := newSentMessage(params) + msg, err := NewSentMessage(params) if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } @@ -558,7 +561,7 @@ func TestCustomization(t *testing.T) { } params.TTL++ - msg, err = newSentMessage(params) + msg, err = NewSentMessage(params) if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } @@ -593,7 +596,7 @@ func TestCustomization(t *testing.T) { } // check w.messages() - id, err := w.Subscribe(f) + _, err = w.Subscribe(f) if err != nil { t.Fatalf("failed subscribe with seed %d: %s.", seed, err) } @@ -602,11 +605,6 @@ func TestCustomization(t *testing.T) { 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) { @@ -647,7 +645,7 @@ func TestSymmetricSendCycle(t *testing.T) { params.PoW = filter1.PoW params.WorkTime = 10 params.TTL = 50 - msg, err := newSentMessage(params) + msg, err := NewSentMessage(params) if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } @@ -725,7 +723,7 @@ func TestSymmetricSendWithoutAKey(t *testing.T) { params.PoW = filter.PoW params.WorkTime = 10 params.TTL = 50 - msg, err := newSentMessage(params) + msg, err := NewSentMessage(params) if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } @@ -791,7 +789,7 @@ func TestSymmetricSendKeyMismatch(t *testing.T) { params.PoW = filter.PoW params.WorkTime = 10 params.TTL = 50 - msg, err := newSentMessage(params) + msg, err := NewSentMessage(params) if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } @@ -835,11 +833,11 @@ func TestSymmetricSendKeyMismatch(t *testing.T) { func TestBloom(t *testing.T) { topic := TopicType{0, 0, 255, 6} b := TopicToBloom(topic) - x := make([]byte, bloomFilterSize) + x := make([]byte, BloomFilterSize) x[0] = byte(1) x[32] = byte(1) - x[bloomFilterSize-1] = byte(128) - if !bloomFilterMatch(x, b) || !bloomFilterMatch(b, x) { + x[BloomFilterSize-1] = byte(128) + if !BloomFilterMatch(x, b) || !BloomFilterMatch(b, x) { t.Fatalf("bloom filter does not match the mask") } @@ -851,11 +849,11 @@ func TestBloom(t *testing.T) { if err != nil { t.Fatalf("math rand error") } - if !bloomFilterMatch(b, b) { + if !BloomFilterMatch(b, b) { t.Fatalf("bloom filter does not match self") } x = addBloom(x, b) - if !bloomFilterMatch(x, b) { + if !BloomFilterMatch(x, b) { t.Fatalf("bloom filter does not match combined bloom") } if !isFullNode(nil) { @@ -865,16 +863,16 @@ func TestBloom(t *testing.T) { if isFullNode(x) { t.Fatalf("isFullNode false positive") } - for i := 0; i < bloomFilterSize; i++ { + for i := 0; i < BloomFilterSize; i++ { b[i] = byte(255) } if !isFullNode(b) { t.Fatalf("isFullNode false negative") } - if bloomFilterMatch(x, b) { + if BloomFilterMatch(x, b) { t.Fatalf("bloomFilterMatch false positive") } - if !bloomFilterMatch(b, x) { + if !BloomFilterMatch(b, x) { t.Fatalf("bloomFilterMatch false negative") } @@ -888,7 +886,7 @@ func TestBloom(t *testing.T) { t.Fatalf("failed to set bloom filter: %s", err) } f = w.BloomFilter() - if !bloomFilterMatch(f, x) || !bloomFilterMatch(x, f) { + if !BloomFilterMatch(f, x) || !BloomFilterMatch(x, f) { t.Fatalf("retireved wrong bloom filter") } }